From 0aaf6853a4cb7e16a3a5755c6a3b97344e59c3c5 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Tue, 27 Oct 2026 16:53:04 -0400 Subject: [PATCH 1/9] deps: update V8 to 15.8.62 --- deps/v8/AUTHORS | 11 + deps/v8/BUILD.bazel | 196 +- deps/v8/BUILD.gn | 480 +- deps/v8/DEPS | 342 +- deps/v8/PRESUBMIT.py | 19 +- deps/v8/agents/PRESUBMIT.py | 17 +- deps/v8/agents/rules/execution-constraints.md | 13 +- deps/v8/agents/rules/git-cl.md | 151 +- deps/v8/agents/rules/git-commit.md | 29 +- deps/v8/agents/rules/v8-best-practices.md | 15 + deps/v8/agents/rules/writing-skills.md | 12 +- deps/v8/agents/scripts/create_worktree.sh | 6 +- deps/v8/agents/scripts/edit_cl_description.sh | 81 - deps/v8/agents/scripts/upload_cl.sh | 176 - .../agents/scripts/validate_cl_description.py | 120 - deps/v8/agents/skills/clusterfuzz/SKILL.md | 137 + .../clusterfuzz/scripts/fetch_testcase.py | 398 ++ .../scripts/fetch_testcase_test.py | 140 + deps/v8/agents/skills/v8-features/SKILL.md | 88 + .../assets/launch-review-template.md | 170 + .../v8-features/references/coverage-report.md | 93 + .../v8-features/references/launch-reviews.md | 234 + .../v8-features/references/shipping-steps.md | 124 + .../v8-features/scripts/extract_coverage.py | 79 + .../v8-features/scripts/fetch_chromestatus.py | 258 + .../scripts/find_affected_blocks.py | 535 ++ .../scripts/generate_coverage_report.py | 791 +++ .../v8-features/scripts/get_v8_revision.py | 38 + .../v8-features/scripts/read_finch_config.py | 332 ++ .../skills/v8-poc-classification/SKILL.md | 40 +- .../skills/v8-regression-testing/SKILL.md | 14 +- deps/v8/agents/skills/v8-review/OWNERS | 2 + deps/v8/agents/skills/v8-review/SKILL.md | 233 + .../skills/v8-security-triaging/SKILL.md | 249 +- deps/v8/agents/skills/v8-testing/SKILL.md | 19 +- deps/v8/agents/skills/v8-turboshaft/SKILL.md | 73 + deps/v8/agents/skills/v8-workflow/SKILL.md | 16 +- .../agents/skills/workflow-debugging/SKILL.md | 5 +- .../skills/workflow-gerrit-fix/SKILL.md | 8 +- .../scripts/upload_and_pinpoint.py | 18 +- deps/v8/bazel/defs.bzl | 215 +- deps/v8/bazel/v8-generators.bzl | 170 + deps/v8/bazel/v8-non-pointer-compression.bzl | 44 +- deps/v8/docs/committer-responsibility.md | 5 +- deps/v8/docs/heap/roots.md | 2 +- .../parsing/hole-check-elimination-parser.md | 8 +- deps/v8/docs/security/reproducing-bugs.md | 1 + deps/v8/docs/security/triaging.md | 17 +- deps/v8/experimental/redline/.clang-tidy | 72 + deps/v8/experimental/redline/.gitignore | 1 + deps/v8/experimental/redline/BUILD.gn | 172 + deps/v8/experimental/redline/CONTRIBUTE.md | 968 ++++ deps/v8/experimental/redline/CPPLINT.cfg | 7 + deps/v8/experimental/redline/DEPS | 10 + deps/v8/experimental/redline/DESIGN.md | 482 ++ deps/v8/experimental/redline/GEMINI.md | 17 + deps/v8/experimental/redline/README.md | 152 + deps/v8/experimental/redline/TUTORIAL.md | 784 +++ .../v8/experimental/redline/base/file_util.cc | 193 + deps/v8/experimental/redline/base/file_util.h | 45 + deps/v8/experimental/redline/base/flags.cc | 181 + deps/v8/experimental/redline/base/flags.h | 61 + deps/v8/experimental/redline/base/json.cc | 302 ++ deps/v8/experimental/redline/base/json.h | 77 + .../experimental/redline/base/json_parser.cc | 428 ++ .../experimental/redline/base/json_parser.h | 83 + deps/v8/experimental/redline/base/log.cc | 118 + deps/v8/experimental/redline/base/log.h | 47 + .../experimental/redline/base/subprocess.cc | 215 + .../v8/experimental/redline/base/subprocess.h | 44 + deps/v8/experimental/redline/base/time_util.h | 46 + .../experimental/redline/base/v8_runtime.cc | 170 + .../v8/experimental/redline/base/v8_runtime.h | 46 + .../redline/commands/amplify_command.cc | 237 + .../experimental/redline/commands/command.h | 43 + .../redline/commands/exec_command.cc | 182 + .../redline/commands/fuzz_command.cc | 228 + .../redline/commands/minimize_command.cc | 352 ++ .../redline/commands/mutate_command.cc | 664 +++ .../redline/commands/parse_command.cc | 247 + .../redline/commands/replay_command.cc | 319 ++ .../redline/commands/roundtrip_command.cc | 997 ++++ .../redline/commands/selftest_checker.h | 45 + .../redline/commands/selftest_command.cc | 425 ++ .../redline/commands/selftest_selection.cc | 1088 ++++ .../redline/commands/selftest_selection.h | 42 + .../redline/commands/shell_command.cc | 1133 ++++ .../redline/core/adaptive_selector.h | 298 + .../experimental/redline/core/ast_builder.cc | 551 ++ .../experimental/redline/core/ast_builder.h | 219 + deps/v8/experimental/redline/core/builder.cc | 1013 ++++ deps/v8/experimental/redline/core/builder.h | 213 + .../v8/experimental/redline/core/component.cc | 42 + deps/v8/experimental/redline/core/component.h | 83 + .../experimental/redline/core/environment.cc | 823 +++ .../experimental/redline/core/environment.h | 132 + deps/v8/experimental/redline/core/program.cc | 66 + deps/v8/experimental/redline/core/program.h | 109 + deps/v8/experimental/redline/core/random.h | 155 + .../v8/experimental/redline/core/selection.cc | 126 + deps/v8/experimental/redline/core/selection.h | 305 ++ deps/v8/experimental/redline/core/tunable.cc | 149 + deps/v8/experimental/redline/core/tunable.h | 107 + .../redline/core/weighted_selector.h | 123 + deps/v8/experimental/redline/corpus/corpus.cc | 704 +++ deps/v8/experimental/redline/corpus/corpus.h | 88 + .../experimental/redline/engine/amplifier.cc | 411 ++ .../experimental/redline/engine/amplifier.h | 103 + deps/v8/experimental/redline/engine/config.cc | 1390 +++++ deps/v8/experimental/redline/engine/config.h | 227 + deps/v8/experimental/redline/engine/crash.cc | 402 ++ deps/v8/experimental/redline/engine/crash.h | 76 + deps/v8/experimental/redline/engine/fuzzer.cc | 2055 +++++++ deps/v8/experimental/redline/engine/fuzzer.h | 201 + .../experimental/redline/engine/importer.cc | 167 + .../v8/experimental/redline/engine/importer.h | 43 + .../v8/experimental/redline/engine/prelude.cc | 81 + deps/v8/experimental/redline/engine/prelude.h | 21 + .../redline/engine/shared_coverage.cc | 179 + .../redline/engine/shared_coverage.h | 84 + deps/v8/experimental/redline/engine/stages.cc | 355 ++ deps/v8/experimental/redline/engine/stages.h | 136 + deps/v8/experimental/redline/exec/coverage.cc | 262 + deps/v8/experimental/redline/exec/coverage.h | 130 + .../v8/experimental/redline/exec/execution.cc | 81 + deps/v8/experimental/redline/exec/execution.h | 58 + .../experimental/redline/exec/process_run.cc | 140 + .../experimental/redline/exec/process_run.h | 39 + deps/v8/experimental/redline/exec/reprl.cc | 570 ++ deps/v8/experimental/redline/exec/reprl.h | 111 + deps/v8/experimental/redline/exec/runner.cc | 148 + deps/v8/experimental/redline/exec/runner.h | 94 + .../redline/exec/target_options.cc | 158 + .../redline/exec/target_options.h | 65 + deps/v8/experimental/redline/fast/arena.cc | 105 + deps/v8/experimental/redline/fast/arena.h | 80 + deps/v8/experimental/redline/fast/ast.cc | 201 + deps/v8/experimental/redline/fast/ast.h | 769 +++ deps/v8/experimental/redline/fast/ast_visit.h | 336 ++ deps/v8/experimental/redline/fast/lexer.cc | 1170 ++++ deps/v8/experimental/redline/fast/lexer.h | 234 + deps/v8/experimental/redline/fast/parser.cc | 2891 ++++++++++ deps/v8/experimental/redline/fast/parser.h | 216 + deps/v8/experimental/redline/fast/printer.cc | 1550 ++++++ deps/v8/experimental/redline/fast/printer.h | 48 + deps/v8/experimental/redline/fast/scope.cc | 1416 +++++ deps/v8/experimental/redline/fast/scope.h | 303 ++ deps/v8/experimental/redline/fast/tree.cc | 122 + deps/v8/experimental/redline/fast/tree.h | 84 + .../redline/generators/codegen.cc | 1436 +++++ .../experimental/redline/generators/codegen.h | 125 + .../redline/generators/generator.h | 158 + .../redline/generators/generators.cc | 4776 +++++++++++++++++ .../redline/generators/wasm_module.cc | 680 +++ .../redline/generators/wasm_module.h | 54 + deps/v8/experimental/redline/main.cc | 154 + .../redline/minimizer/minimizer.cc | 1153 ++++ .../redline/minimizer/minimizer.h | 148 + .../experimental/redline/mutators/explore.cc | 872 +++ .../experimental/redline/mutators/explore.h | 115 + .../experimental/redline/mutators/mutator.h | 143 + .../experimental/redline/mutators/mutators.cc | 2057 +++++++ .../experimental/redline/mutators/probing.cc | 384 ++ .../experimental/redline/mutators/probing.h | 52 + .../experimental/redline/presets/.gitignore | 4 + .../redline/presets/builtins.json | 6 + .../experimental/redline/presets/default.json | 3 + .../experimental/redline/presets/maglev.json | 6 + .../experimental/redline/presets/parser.json | 7 + .../experimental/redline/presets/runtime.json | 8 + .../redline/presets/turbolev.json | 6 + .../v8/experimental/redline/presets/wasm.json | 5 + .../redline/skills/redline-presubmit/SKILL.md | 148 + .../redline-presubmit/scripts/ab_compare.py | 88 + .../redline-presubmit/scripts/ab_run.sh | 139 + .../skills/redline-presubmit/scripts/check.sh | 115 + .../redline-presubmit/scripts/ste_check.py | 243 + .../scripts/ste_lint.vpython3 | 9 + .../experimental/redline/testdata/README.md | 35 + .../redline/testdata/selection/codegen.trace | 1000 ++++ .../selection/generator_outputs.trace | 470 ++ .../testdata/selection/generators.trace | 2000 +++++++ .../testdata/selection/mutator_outputs.trace | 75 + .../redline/testdata/selection/mutators.trace | 2000 +++++++ .../selection/scheduler_productive.trace | 1000 ++++ .../selection/scheduler_recency.trace | 1000 ++++ .../selection/scheduler_tournament.trace | 1000 ++++ .../selection/scheduler_uniform.trace | 1000 ++++ deps/v8/gni/v8.gni | 20 +- deps/v8/include/cppgc/allocation.h | 18 +- deps/v8/include/cppgc/common.h | 28 + deps/v8/include/cppgc/explicit-management.h | 7 + deps/v8/include/cppgc/heap-consistency.h | 4 +- deps/v8/include/cppgc/heap.h | 7 + deps/v8/include/cppgc/platform.h | 54 + deps/v8/include/js_protocol.pdl | 15 +- deps/v8/include/v8-array-buffer.h | 227 +- deps/v8/include/v8-callbacks.h | 10 + deps/v8/include/v8-context.h | 29 +- deps/v8/include/v8-cppgc.h | 7 + deps/v8/include/v8-fast-api-calls.h | 2 +- deps/v8/include/v8-forward.h | 1 + deps/v8/include/v8-function-callback.h | 11 +- deps/v8/include/v8-internal.h | 92 +- deps/v8/include/v8-isolate.h | 26 + deps/v8/include/v8-local-handle.h | 16 +- deps/v8/include/v8-object.h | 21 +- deps/v8/include/v8-platform.h | 19 +- deps/v8/include/v8-primitive.h | 6 + deps/v8/include/v8-profiler.h | 77 +- deps/v8/include/v8-regexp.h | 3 + deps/v8/include/v8-template.h | 18 +- deps/v8/include/v8-typed-array.h | 49 +- deps/v8/include/v8-value.h | 5 + deps/v8/include/v8-version.h | 6 +- deps/v8/include/v8-wasm.h | 43 +- deps/v8/include/v8config.h | 4 - deps/v8/infra/mb/gn_isolate_map.pyl | 4 + deps/v8/infra/mb/mb_config.pyl | 53 +- deps/v8/infra/testing/builders.pyl | 40 +- deps/v8/src/DEPS | 26 + deps/v8/src/api/api-arguments-inl.h | 2 +- deps/v8/src/api/api-natives.cc | 22 +- deps/v8/src/api/api.cc | 347 +- deps/v8/src/api/api.h | 119 +- deps/v8/src/ast/ast.h | 11 +- deps/v8/src/ast/prettyprinter.cc | 112 +- deps/v8/src/ast/scopes.cc | 164 +- deps/v8/src/ast/scopes.h | 20 +- deps/v8/src/ast/variables.h | 3 - deps/v8/src/base/bits.h | 58 - deps/v8/src/base/cpu/cpu-arm.cc | 17 + deps/v8/src/base/cpu/cpu-riscv.cc | 38 + deps/v8/src/base/cpu/cpu.h | 4 + deps/v8/src/base/flags.h | 5 +- deps/v8/src/base/fpu.cc | 101 - deps/v8/src/base/fpu.h | 29 - deps/v8/src/base/growing-circular-queue.h | 165 + deps/v8/src/base/hashing.h | 6 + deps/v8/src/base/logging.cc | 2 +- deps/v8/src/base/logging.h | 8 + deps/v8/src/base/macros.h | 10 - deps/v8/src/base/numbers/bignum-dtoa.cc | 15 +- deps/v8/src/base/numbers/bignum-dtoa.h | 6 +- deps/v8/src/base/numbers/bignum.cc | 20 +- deps/v8/src/base/numbers/bignum.h | 24 +- deps/v8/src/base/numbers/dtoa.cc | 3 +- deps/v8/src/base/numbers/dtoa.h | 8 +- deps/v8/src/base/numbers/fast-dtoa.cc | 15 +- deps/v8/src/base/numbers/fast-dtoa.h | 6 +- deps/v8/src/base/numbers/fixed-dtoa.cc | 18 +- deps/v8/src/base/numbers/fixed-dtoa.h | 6 +- deps/v8/src/base/numbers/strtod.cc | 80 +- deps/v8/src/base/numbers/strtod.h | 6 +- deps/v8/src/base/platform/mutex.h | 14 + deps/v8/src/base/platform/platform-linux.cc | 20 + deps/v8/src/base/platform/platform-posix.cc | 19 +- .../src/base/platform/platform-starboard.cc | 9 +- deps/v8/src/base/platform/platform-win32.cc | 16 +- deps/v8/src/base/platform/platform.cc | 72 +- deps/v8/src/base/platform/platform.h | 40 +- deps/v8/src/base/small-vector.h | 14 +- deps/v8/src/base/strings.cc | 11 +- deps/v8/src/base/strings.h | 9 +- deps/v8/src/base/unique-array.h | 196 + deps/v8/src/base/vector.h | 333 +- .../arm64/baseline-assembler-arm64-inl.h | 91 + deps/v8/src/baseline/baseline-assembler.h | 12 + .../src/baseline/baseline-batch-compiler.cc | 3 - deps/v8/src/baseline/baseline-compiler.cc | 218 +- deps/v8/src/baseline/baseline-compiler.h | 28 +- .../loong64/baseline-assembler-loong64-inl.h | 98 + .../baseline/x64/baseline-assembler-x64-inl.h | 104 + .../baseline/x64/baseline-compiler-x64-inl.h | 13 +- deps/v8/src/builtins/accessors.cc | 94 +- deps/v8/src/builtins/accessors.h | 9 +- deps/v8/src/builtins/arm/builtins-arm.cc | 164 +- deps/v8/src/builtins/arm64/builtins-arm64.cc | 187 +- deps/v8/src/builtins/array-reduce-right.tq | 6 +- deps/v8/src/builtins/array-reduce.tq | 6 +- deps/v8/src/builtins/array-slice.tq | 2 +- deps/v8/src/builtins/array-splice.tq | 2 +- deps/v8/src/builtins/array-to-sorted.tq | 2 +- deps/v8/src/builtins/array-to-spliced.tq | 2 +- deps/v8/src/builtins/array.tq | 2 +- deps/v8/src/builtins/base.tq | 25 +- deps/v8/src/builtins/builtins-array-gen.cc | 12 + deps/v8/src/builtins/builtins-arraybuffer.cc | 6 +- .../builtins-async-disposable-stack.cc | 7 + .../builtins/builtins-async-function-gen.cc | 3 +- deps/v8/src/builtins/builtins-async-gen.cc | 8 +- .../builtins-atomics-synchronization.cc | 260 - deps/v8/src/builtins/builtins-bigint.cc | 1 + deps/v8/src/builtins/builtins-call-gen.cc | 2 +- .../src/builtins/builtins-collections-gen.cc | 16 +- deps/v8/src/builtins/builtins-console.cc | 12 +- .../src/builtins/builtins-constructor-gen.cc | 28 +- deps/v8/src/builtins/builtins-dataview.cc | 3 +- deps/v8/src/builtins/builtins-date.cc | 24 +- deps/v8/src/builtins/builtins-definitions.h | 53 +- deps/v8/src/builtins/builtins-error.cc | 2 +- deps/v8/src/builtins/builtins-function.cc | 9 +- deps/v8/src/builtins/builtins-inl.h | 6 +- deps/v8/src/builtins/builtins-internal-gen.cc | 34 +- deps/v8/src/builtins/builtins-intl-gen.cc | 24 +- deps/v8/src/builtins/builtins-intl.cc | 13 +- deps/v8/src/builtins/builtins-iterator-inl.h | 227 +- deps/v8/src/builtins/builtins-proxy-gen.cc | 25 +- deps/v8/src/builtins/builtins-regexp-gen.cc | 10 +- deps/v8/src/builtins/builtins-regexp.cc | 11 +- deps/v8/src/builtins/builtins-shadow-realm.cc | 10 +- .../builtins-sharedarraybuffer-gen.cc | 2 +- .../builtins/builtins-sharedarraybuffer.cc | 2 +- .../v8/src/builtins/builtins-string-tsa-inl.h | 12 +- deps/v8/src/builtins/builtins-string.cc | 9 +- deps/v8/src/builtins/builtins-struct.cc | 14 +- .../src/builtins/builtins-typed-array-gen.cc | 4 +- deps/v8/src/builtins/builtins-typed-array.cc | 54 +- deps/v8/src/builtins/builtins-utils.h | 10 +- deps/v8/src/builtins/builtins-wasm-gen.cc | 19 +- deps/v8/src/builtins/builtins.cc | 22 +- deps/v8/src/builtins/builtins.h | 3 +- .../v8/src/builtins/bytecodes-builtins-list.h | 18 + deps/v8/src/builtins/cast.tq | 9 +- deps/v8/src/builtins/console.tq | 2 +- deps/v8/src/builtins/conversion.tq | 2 +- deps/v8/src/builtins/convert.tq | 10 +- deps/v8/src/builtins/function.tq | 2 +- .../generate-bytecodes-builtins-list.cc | 8 +- deps/v8/src/builtins/ia32/builtins-ia32.cc | 176 +- deps/v8/src/builtins/internal.tq | 44 +- deps/v8/src/builtins/iterator-helpers.tq | 3 +- deps/v8/src/builtins/js-to-wasm.tq | 13 +- .../src/builtins/loong64/builtins-loong64.cc | 171 +- .../v8/src/builtins/mips64/builtins-mips64.cc | 35 +- deps/v8/src/builtins/object-fromentries.tq | 2 +- deps/v8/src/builtins/ppc/builtins-ppc.cc | 419 +- .../builtins/promise-abstract-operations.tq | 20 +- deps/v8/src/builtins/promise-misc.tq | 8 +- deps/v8/src/builtins/proxy-revocable.tq | 2 +- deps/v8/src/builtins/proxy-set-property.tq | 2 +- .../v8/src/builtins/proxy-set-prototype-of.tq | 3 +- deps/v8/src/builtins/riscv/builtins-riscv.cc | 205 +- deps/v8/src/builtins/s390/builtins-s390.cc | 161 +- .../src/builtins/setup-builtins-internal.cc | 4 +- deps/v8/src/builtins/superspread.h | 3 +- .../builtins/typed-array-createtypedarray.tq | 4 + deps/v8/src/builtins/typed-array-entries.tq | 2 +- deps/v8/src/builtins/typed-array-every.tq | 2 +- deps/v8/src/builtins/typed-array-filter.tq | 3 +- deps/v8/src/builtins/typed-array-find.tq | 2 +- deps/v8/src/builtins/typed-array-findindex.tq | 2 +- deps/v8/src/builtins/typed-array-findlast.tq | 2 +- .../src/builtins/typed-array-findlastindex.tq | 2 +- deps/v8/src/builtins/typed-array-foreach.tq | 2 +- deps/v8/src/builtins/typed-array-keys.tq | 2 +- deps/v8/src/builtins/typed-array-reduce.tq | 4 +- .../src/builtins/typed-array-reduceright.tq | 5 +- deps/v8/src/builtins/typed-array-set.tq | 2 +- deps/v8/src/builtins/typed-array-some.tq | 2 +- deps/v8/src/builtins/typed-array-values.tq | 2 +- deps/v8/src/builtins/typed-array-with.tq | 2 +- .../src/builtins/wasm-interpreter-wrappers.tq | 7 + deps/v8/src/builtins/wasm.tq | 106 +- deps/v8/src/builtins/x64/builtins-x64.cc | 247 +- .../v8/src/codegen/arm/macro-assembler-arm.cc | 2 +- deps/v8/src/codegen/arm/macro-assembler-arm.h | 3 +- deps/v8/src/codegen/arm64/assembler-arm64.cc | 96 +- deps/v8/src/codegen/arm64/assembler-arm64.h | 32 + .../src/codegen/arm64/constant-pool-arm64.cc | 48 +- .../src/codegen/arm64/constant-pool-arm64.h | 5 +- deps/v8/src/codegen/arm64/constants-arm64.h | 42 + deps/v8/src/codegen/arm64/decoder-arm64-inl.h | 13 + deps/v8/src/codegen/arm64/decoder-arm64.h | 2 + .../codegen/arm64/macro-assembler-arm64-inl.h | 8 + .../codegen/arm64/macro-assembler-arm64.cc | 249 +- .../src/codegen/arm64/macro-assembler-arm64.h | 116 +- deps/v8/src/codegen/assembler.cc | 6 +- deps/v8/src/codegen/assembler.h | 33 +- deps/v8/src/codegen/bailout-reason.h | 237 +- deps/v8/src/codegen/code-factory.cc | 8 +- deps/v8/src/codegen/code-stub-assembler-inl.h | 6 +- deps/v8/src/codegen/code-stub-assembler.cc | 425 +- deps/v8/src/codegen/code-stub-assembler.h | 81 +- deps/v8/src/codegen/compiler.cc | 200 +- deps/v8/src/codegen/compiler.h | 22 +- deps/v8/src/codegen/cpu-features.h | 7 + deps/v8/src/codegen/external-reference.cc | 85 +- deps/v8/src/codegen/external-reference.h | 33 +- .../src/codegen/ia32/macro-assembler-ia32.cc | 9 +- .../src/codegen/ia32/macro-assembler-ia32.h | 3 +- .../src/codegen/interface-descriptors-inl.h | 26 +- deps/v8/src/codegen/interface-descriptors.cc | 2 +- deps/v8/src/codegen/interface-descriptors.h | 61 +- .../loong64/macro-assembler-loong64.cc | 176 +- .../codegen/loong64/macro-assembler-loong64.h | 44 +- deps/v8/src/codegen/machine-type.cc | 4 +- deps/v8/src/codegen/machine-type.h | 24 +- deps/v8/src/codegen/macro-assembler-base.cc | 1 + deps/v8/src/codegen/maglev-safepoint-table.cc | 10 +- deps/v8/src/codegen/maglev-safepoint-table.h | 20 +- .../codegen/mips64/macro-assembler-mips64.cc | 28 +- .../codegen/mips64/macro-assembler-mips64.h | 3 +- .../src/codegen/optimized-compilation-info.cc | 11 +- .../src/codegen/optimized-compilation-info.h | 6 +- .../src/codegen/pending-optimization-table.cc | 40 + .../src/codegen/pending-optimization-table.h | 9 + .../v8/src/codegen/ppc/macro-assembler-ppc.cc | 2 +- deps/v8/src/codegen/ppc/macro-assembler-ppc.h | 3 +- .../src/codegen/riscv/assembler-riscv-inl.h | 14 +- deps/v8/src/codegen/riscv/assembler-riscv.cc | 6 +- deps/v8/src/codegen/riscv/assembler-riscv.h | 6 +- .../src/codegen/riscv/base-assembler-riscv.h | 7 +- deps/v8/src/codegen/riscv/constants-riscv.h | 1 + .../codegen/riscv/macro-assembler-riscv.cc | 150 +- .../src/codegen/riscv/macro-assembler-riscv.h | 38 +- deps/v8/src/codegen/riscv/register-riscv.h | 7 +- .../src/codegen/s390/macro-assembler-s390.cc | 3 +- .../src/codegen/s390/macro-assembler-s390.h | 4 +- deps/v8/src/codegen/safepoint-table.cc | 9 +- deps/v8/src/codegen/safepoint-table.h | 11 +- deps/v8/src/codegen/source-position-table.cc | 9 +- deps/v8/src/codegen/source-position-table.h | 3 +- deps/v8/src/codegen/tnode.h | 7 +- .../turboshaft-builtins-assembler-inl.h | 9 +- deps/v8/src/codegen/x64/assembler-x64.cc | 9 + deps/v8/src/codegen/x64/assembler-x64.h | 63 +- .../x64/interface-descriptors-x64-inl.h | 3 +- .../v8/src/codegen/x64/macro-assembler-x64.cc | 365 +- deps/v8/src/codegen/x64/macro-assembler-x64.h | 65 +- deps/v8/src/codegen/x64/register-x64.h | 3 +- deps/v8/src/common/code-memory-access.cc | 120 +- deps/v8/src/common/code-memory-access.h | 18 +- deps/v8/src/common/globals.h | 100 +- deps/v8/src/common/message-template.h | 6 +- deps/v8/src/common/operation.h | 12 + .../common/synchronization-point-support.cc | 2 +- .../lazy-compile-dispatcher.cc | 3 - .../optimizing-compile-dispatcher.cc | 8 +- .../optimizing-compile-dispatcher.h | 4 +- deps/v8/src/compiler/OWNERS | 6 +- deps/v8/src/compiler/access-builder.cc | 37 +- deps/v8/src/compiler/access-builder.h | 9 +- deps/v8/src/compiler/access-info.cc | 27 +- deps/v8/src/compiler/allocation-builder.h | 2 +- .../backend/arm/code-generator-arm.cc | 255 +- .../backend/arm/instruction-selector-arm.cc | 4 +- .../backend/arm64/code-generator-arm64.cc | 639 ++- .../backend/arm64/instruction-codes-arm64.h | 18 +- .../arm64/instruction-scheduler-arm64.cc | 46 +- .../arm64/instruction-selector-arm64.cc | 458 +- .../v8/src/compiler/backend/code-generator.cc | 116 +- deps/v8/src/compiler/backend/code-generator.h | 21 +- .../backend/ia32/code-generator-ia32.cc | 257 +- .../backend/ia32/instruction-selector-ia32.cc | 4 +- .../src/compiler/backend/instruction-codes.h | 17 +- .../compiler/backend/instruction-scheduler.cc | 4 +- .../compiler/backend/instruction-selector.cc | 90 +- .../compiler/backend/instruction-selector.h | 7 +- deps/v8/src/compiler/backend/instruction.cc | 4 +- deps/v8/src/compiler/backend/instruction.h | 16 +- .../backend/loong64/code-generator-loong64.cc | 376 +- .../loong64/instruction-codes-loong64.h | 2 +- .../loong64/instruction-selector-loong64.cc | 41 +- .../backend/mips64/code-generator-mips64.cc | 122 +- .../mips64/instruction-selector-mips64.cc | 8 +- .../v8/src/compiler/backend/move-optimizer.cc | 21 + .../backend/ppc/code-generator-ppc.cc | 285 +- .../backend/ppc/instruction-selector-ppc.cc | 8 +- .../compiler/backend/register-allocation.h | 2 +- .../backend/register-allocator-verifier.cc | 15 +- .../backend/register-allocator-verifier.h | 8 +- .../compiler/backend/register-allocator.cc | 195 +- .../src/compiler/backend/register-allocator.h | 103 +- .../backend/riscv/code-generator-riscv.cc | 315 +- .../backend/riscv/instruction-codes-riscv.h | 2 +- .../riscv/instruction-scheduler-riscv.cc | 4 +- .../riscv/instruction-selector-riscv32.cc | 14 +- .../riscv/instruction-selector-riscv64.cc | 25 +- .../backend/s390/code-generator-s390.cc | 255 +- .../backend/s390/instruction-selector-s390.cc | 8 +- deps/v8/src/compiler/backend/simd-shuffle.cc | 202 +- deps/v8/src/compiler/backend/simd-shuffle.h | 6 +- deps/v8/src/compiler/backend/spill-placer.cc | 4 +- deps/v8/src/compiler/backend/spill-placer.h | 1 - .../backend/x64/code-generator-x64.cc | 490 +- .../backend/x64/instruction-codes-x64.h | 2 +- .../backend/x64/instruction-scheduler-x64.cc | 2 +- .../backend/x64/instruction-selector-x64.cc | 127 +- deps/v8/src/compiler/bytecode-analysis.cc | 67 +- .../v8/src/compiler/bytecode-graph-builder.cc | 10 +- deps/v8/src/compiler/bytecode-liveness-map.h | 21 + deps/v8/src/compiler/code-assembler.cc | 48 +- deps/v8/src/compiler/code-assembler.h | 25 +- deps/v8/src/compiler/common-operator.cc | 4 +- deps/v8/src/compiler/common-operator.h | 4 +- .../src/compiler/compilation-dependencies.cc | 5 +- deps/v8/src/compiler/graph-assembler.cc | 31 +- deps/v8/src/compiler/heap-refs.cc | 50 +- deps/v8/src/compiler/heap-refs.h | 23 +- deps/v8/src/compiler/js-call-reducer.cc | 86 +- .../src/compiler/js-context-specialization.cc | 1 - deps/v8/src/compiler/js-create-lowering.cc | 34 +- deps/v8/src/compiler/js-generic-lowering.cc | 13 +- deps/v8/src/compiler/js-heap-broker.cc | 24 +- deps/v8/src/compiler/js-heap-broker.h | 8 + deps/v8/src/compiler/js-inlining-heuristic.cc | 2 +- deps/v8/src/compiler/js-inlining.cc | 11 +- .../js-native-context-specialization.cc | 173 +- .../js-native-context-specialization.h | 5 - deps/v8/src/compiler/js-operator.cc | 46 +- deps/v8/src/compiler/js-operator.h | 41 +- deps/v8/src/compiler/js-typed-lowering.cc | 47 +- deps/v8/src/compiler/linkage.cc | 37 +- deps/v8/src/compiler/linkage.h | 63 +- deps/v8/src/compiler/load-elimination.cc | 8 +- .../v8/src/compiler/machine-graph-verifier.cc | 10 +- deps/v8/src/compiler/machine-operator.cc | 58 +- deps/v8/src/compiler/machine-operator.h | 2 +- deps/v8/src/compiler/memory-lowering.cc | 764 --- deps/v8/src/compiler/memory-lowering.h | 150 - deps/v8/src/compiler/memory-optimizer.cc | 536 -- deps/v8/src/compiler/memory-optimizer.h | 128 - deps/v8/src/compiler/opcodes.h | 2 +- deps/v8/src/compiler/operator.h | 2 +- deps/v8/src/compiler/pipeline.cc | 101 +- deps/v8/src/compiler/raw-machine-assembler.h | 14 +- deps/v8/src/compiler/representation-change.cc | 2 +- .../compiler/simplified-lowering-verifier.cc | 2 +- deps/v8/src/compiler/simplified-lowering.cc | 11 +- deps/v8/src/compiler/simplified-operator.cc | 5 +- deps/v8/src/compiler/simplified-operator.h | 29 +- .../src/compiler/turbofan-graph-visualizer.cc | 45 +- deps/v8/src/compiler/turbofan-typer.cc | 5 +- deps/v8/src/compiler/turbofan-types.cc | 4 +- deps/v8/src/compiler/turboshaft/assembler.h | 148 +- .../turboshaft/branch-elimination-reducer.h | 16 +- .../turboshaft/builtin-call-descriptors.h | 2 +- .../compiler/turboshaft/builtin-compiler.cc | 3 +- .../turboshaft/define-assembler-macros.inc | 9 +- .../duplication-optimization-reducer.h | 59 +- .../fast-api-call-lowering-reducer.h | 3 +- deps/v8/src/compiler/turboshaft/fast-hash.h | 8 + .../src/compiler/turboshaft/graph-builder.cc | 6 +- deps/v8/src/compiler/turboshaft/graph.h | 24 +- .../turboshaft/growable-stacks-reducer.h | 85 +- deps/v8/src/compiler/turboshaft/index.h | 7 +- ...truction-selection-normalization-reducer.h | 228 + .../turboshaft/int64-lowering-reducer.h | 17 +- .../late-load-elimination-reducer.cc | 30 +- .../late-load-elimination-reducer.h | 69 +- .../compiler/turboshaft/layered-hash-map.h | 3 +- .../load-store-simplification-reducer.h | 4 +- .../load-store-verification-reducer.h | 4 +- .../turboshaft/loop-peeling-reducer.h | 2 +- .../turboshaft/loop-unrolling-reducer.h | 4 +- .../turboshaft/machine-optimization-reducer.h | 154 +- .../turboshaft/memory-optimization-reducer.cc | 4 +- .../turboshaft/memory-optimization-reducer.h | 58 +- deps/v8/src/compiler/turboshaft/operations.cc | 13 +- deps/v8/src/compiler/turboshaft/operations.h | 230 +- deps/v8/src/compiler/turboshaft/opmasks.h | 1 + deps/v8/src/compiler/turboshaft/phase.h | 7 +- deps/v8/src/compiler/turboshaft/pipelines.cc | 17 +- deps/v8/src/compiler/turboshaft/pipelines.h | 12 + .../turboshaft/register-allocation-phase.h | 3 + .../compiler/turboshaft/representations.cc | 2 - .../src/compiler/turboshaft/representations.h | 45 +- .../required-optimization-reducer.h | 2 +- .../turboshaft/runtime-call-descriptors.h | 27 +- .../src/compiler/turboshaft/snapshot-table.h | 2 +- .../turboshaft/stack-check-lowering-reducer.h | 42 +- .../turboshaft/turbolev-frontend-pipeline.cc | 2 + .../turboshaft/turbolev-graph-builder.cc | 107 +- deps/v8/src/compiler/turboshaft/typer.h | 9 +- deps/v8/src/compiler/turboshaft/types.cc | 75 +- .../turboshaft/undef-assembler-macros.inc | 1 + deps/v8/src/compiler/turboshaft/use-map.cc | 6 + deps/v8/src/compiler/turboshaft/use-map.h | 11 +- .../turboshaft/value-numbering-reducer.h | 5 +- .../wasm-gc-typed-optimization-reducer.cc | 69 +- .../wasm-gc-typed-optimization-reducer.h | 4 +- .../wasm-in-js-inlining-reducer-inl.h | 12 +- .../wasm-load-elimination-reducer.cc | 11 +- .../wasm-load-elimination-reducer.h | 53 +- .../turboshaft/wasm-lowering-reducer.h | 520 +- .../compiler/turboshaft/wasm-revec-reducer.cc | 46 +- .../compiler/turboshaft/wasm-revec-reducer.h | 17 +- .../turboshaft/wasm-shuffle-reducer.cc | 110 + .../turboshaft/wasm-shuffle-reducer.h | 35 +- .../compiler/turboshaft/wasm-wrappers-inl.h | 218 +- .../src/compiler/turboshaft/wasm-wrappers.h | 62 +- deps/v8/src/compiler/verifier.cc | 2 +- .../compiler/wasm-address-reassociation.cc | 192 - .../src/compiler/wasm-address-reassociation.h | 86 - .../src/compiler/wasm-compiler-definitions.cc | 18 +- .../src/compiler/wasm-compiler-definitions.h | 9 +- deps/v8/src/compiler/wasm-compiler.cc | 586 +- deps/v8/src/compiler/wasm-compiler.h | 164 +- deps/v8/src/compiler/wasm-gc-lowering.cc | 49 +- deps/v8/src/compiler/wasm-graph-assembler.cc | 39 +- deps/v8/src/compiler/wasm-graph-assembler.h | 8 +- deps/v8/src/compiler/write-barrier-kind.h | 6 +- deps/v8/src/d8/d8-platforms.cc | 23 +- deps/v8/src/d8/d8-posix.cc | 25 +- deps/v8/src/d8/d8-test.cc | 9 +- deps/v8/src/d8/d8-windows.cc | 6 +- deps/v8/src/d8/d8.cc | 582 +- deps/v8/src/d8/d8.h | 37 +- deps/v8/src/debug/debug-block-list.cc | 6 +- deps/v8/src/debug/debug-coverage.cc | 4 +- deps/v8/src/debug/debug-evaluate.cc | 30 +- deps/v8/src/debug/debug-interface.cc | 26 +- deps/v8/src/debug/debug-interface.h | 38 +- deps/v8/src/debug/debug-property-iterator.cc | 15 +- deps/v8/src/debug/debug-scope-info.cc | 32 + deps/v8/src/debug/debug-scope-info.h | 14 + deps/v8/src/debug/debug-scope-iterator.cc | 12 +- deps/v8/src/debug/debug-scope-iterator.h | 2 +- deps/v8/src/debug/debug-scopes.cc | 243 +- deps/v8/src/debug/debug-scopes.h | 32 +- deps/v8/src/debug/debug-wasm-objects.cc | 84 +- deps/v8/src/debug/debug.cc | 184 +- deps/v8/src/debug/debug.h | 30 +- deps/v8/src/deoptimizer/deoptimizer.cc | 74 +- deps/v8/src/deoptimizer/deoptimizer.h | 2 +- .../deoptimizer/frame-translation-builder.cc | 14 + .../deoptimizer/frame-translation-builder.h | 2 + deps/v8/src/deoptimizer/translated-state.cc | 160 +- deps/v8/src/deoptimizer/translated-state.h | 10 + deps/v8/src/deoptimizer/translation-opcode.h | 2 + deps/v8/src/diagnostics/arm/disasm-arm.cc | 18 +- deps/v8/src/diagnostics/arm64/disasm-arm64.cc | 56 +- deps/v8/src/diagnostics/code-tracer.h | 10 +- deps/v8/src/diagnostics/disasm.h | 4 +- deps/v8/src/diagnostics/disassembler.cc | 63 +- deps/v8/src/diagnostics/gdb-jit.cc | 14 +- deps/v8/src/diagnostics/ia32/disasm-ia32.cc | 15 +- .../src/diagnostics/loong64/disasm-loong64.cc | 8 +- .../src/diagnostics/mips64/disasm-mips64.cc | 10 +- deps/v8/src/diagnostics/objects-debug.cc | 179 +- deps/v8/src/diagnostics/objects-printer.cc | 136 +- deps/v8/src/diagnostics/perf-jit.cc | 7 +- deps/v8/src/diagnostics/ppc/disasm-ppc.cc | 10 +- deps/v8/src/diagnostics/riscv/disasm-riscv.cc | 9 +- deps/v8/src/diagnostics/s390/disasm-s390.cc | 10 +- deps/v8/src/diagnostics/x64/disasm-x64.cc | 41 +- deps/v8/src/dumpling/object-dumping.cc | 20 +- deps/v8/src/execution/arguments.h | 23 +- deps/v8/src/execution/arm/simulator-arm.cc | 16 +- .../v8/src/execution/arm64/simulator-arm64.cc | 60 +- deps/v8/src/execution/arm64/simulator-arm64.h | 45 +- .../execution/arm64/simulator-logic-arm64.cc | 14 +- deps/v8/src/execution/frame-constants.h | 8 +- deps/v8/src/execution/frames-inl.h | 5 - deps/v8/src/execution/frames.cc | 86 +- deps/v8/src/execution/frames.h | 37 +- deps/v8/src/execution/isolate-data-fields.h | 8 + deps/v8/src/execution/isolate-data.h | 7 + deps/v8/src/execution/isolate.cc | 91 +- deps/v8/src/execution/isolate.h | 73 +- deps/v8/src/execution/local-isolate.cc | 9 +- deps/v8/src/execution/local-isolate.h | 7 +- .../execution/loong64/simulator-loong64.cc | 18 +- .../src/execution/loong64/simulator-loong64.h | 4 +- deps/v8/src/execution/messages.cc | 111 +- .../src/execution/mips64/simulator-mips64.cc | 18 +- .../src/execution/mips64/simulator-mips64.h | 6 +- deps/v8/src/execution/ppc/simulator-ppc.cc | 18 +- .../v8/src/execution/riscv/simulator-riscv.cc | 481 +- deps/v8/src/execution/riscv/simulator-riscv.h | 25 +- deps/v8/src/execution/s390/simulator-s390.cc | 21 +- deps/v8/src/execution/stack-guard.cc | 3 + .../src/execution/x64/frame-constants-x64.cc | 9 +- .../src/extensions/cputracemark-extension.h | 3 +- deps/v8/src/extensions/gc-extension.h | 3 +- deps/v8/src/flags/feature-flags.h | 36 +- deps/v8/src/flags/flag-definitions.h | 514 +- deps/v8/src/flags/flags-impl.h | 1 + deps/v8/src/flags/flags.cc | 201 +- deps/v8/src/flags/flags.h | 8 +- deps/v8/src/fuzzilli/cov.cc | 333 +- deps/v8/src/fuzzilli/cov.h | 20 + deps/v8/src/fuzzilli/fuzzilli.h | 3 +- deps/v8/src/gen/.clang-format | 2 + deps/v8/src/gen/OWNERS | 1 + deps/v8/src/gen/README.md | 28 + .../intl-nowasm/static-roots.h} | 41 +- .../src/gen/intl-wasm/builtin-definitions.h | 773 +++ .../gen/intl-wasm/bytecodes-builtins-list.h | 555 ++ .../intl-wasm/class-forward-declarations.h | 313 ++ deps/v8/src/gen/intl-wasm/instance-types.h | 1838 +++++++ .../gen/intl-wasm/interface-descriptors.inc | 3492 ++++++++++++ .../intl-wasm/static-roots.h} | 82 +- .../nointl-nowasm/static-roots.h} | 41 +- .../nointl-wasm/static-roots.h} | 82 +- deps/v8/src/handles/global-handles-inl.h | 19 +- deps/v8/src/handles/global-handles.h | 20 + deps/v8/src/handles/handles-inl.h | 9 +- deps/v8/src/handles/handles.h | 4 +- deps/v8/src/heap/WRITE_BARRIER.md | 2 +- deps/v8/src/heap/array-buffer-sweeper.cc | 2 - deps/v8/src/heap/base/stack.cc | 4 +- deps/v8/src/heap/base/stack.h | 14 +- deps/v8/src/heap/cppgc-internal/allocation.cc | 40 +- deps/v8/src/heap/cppgc-internal/caged-heap.cc | 8 +- .../cppgc-internal/explicit-management.cc | 15 +- deps/v8/src/heap/cppgc-internal/free-list.cc | 4 +- deps/v8/src/heap/cppgc-internal/heap-base.cc | 100 +- deps/v8/src/heap/cppgc-internal/heap-base.h | 36 +- deps/v8/src/heap/cppgc-internal/heap-page.cc | 3 +- deps/v8/src/heap/cppgc-internal/heap-page.h | 10 +- deps/v8/src/heap/cppgc-internal/heap.cc | 4 +- deps/v8/src/heap/cppgc-internal/marker.h | 43 +- .../heap/cppgc-internal/object-allocator.cc | 67 +- .../heap/cppgc-internal/object-allocator.h | 119 +- .../heap/cppgc-internal/object-start-bitmap.h | 74 +- deps/v8/src/heap/cppgc-internal/platform.cc | 15 + deps/v8/src/heap/cppgc-internal/sweeper.cc | 4 +- deps/v8/src/heap/cppgc-js/cpp-heap.cc | 36 +- deps/v8/src/heap/cppgc-js/cpp-heap.h | 3 +- deps/v8/src/heap/factory-base-inl.h | 130 +- deps/v8/src/heap/factory-base.cc | 248 +- deps/v8/src/heap/factory-base.h | 54 +- deps/v8/src/heap/factory-inl.h | 3 +- deps/v8/src/heap/factory.cc | 609 +-- deps/v8/src/heap/factory.h | 82 +- deps/v8/src/heap/gc-tracer.h | 2 + deps/v8/src/heap/heap-inl.h | 25 +- deps/v8/src/heap/heap-layout-inl.h | 5 + deps/v8/src/heap/heap-visitor-inl.h | 18 +- deps/v8/src/heap/heap-visitor.h | 2 +- deps/v8/src/heap/heap-write-barrier-inl.h | 22 +- deps/v8/src/heap/heap-write-barrier.cc | 14 +- deps/v8/src/heap/heap-write-barrier.h | 22 +- deps/v8/src/heap/heap.cc | 90 +- deps/v8/src/heap/heap.h | 39 +- deps/v8/src/heap/local-heap.cc | 15 +- deps/v8/src/heap/local-heap.h | 11 +- deps/v8/src/heap/mark-compact.cc | 47 +- deps/v8/src/heap/marking-barrier.cc | 2 +- deps/v8/src/heap/marking-barrier.h | 2 +- deps/v8/src/heap/marking-visitor-inl.h | 28 +- deps/v8/src/heap/marking-visitor.h | 10 +- deps/v8/src/heap/memory-measurement-inl.h | 16 +- deps/v8/src/heap/memory-measurement.cc | 1 - deps/v8/src/heap/memory-pool.cc | 25 +- deps/v8/src/heap/memory-pool.h | 4 +- deps/v8/src/heap/memory-reducer.cc | 134 +- deps/v8/src/heap/memory-reducer.h | 97 +- deps/v8/src/heap/mutable-page.cc | 4 +- deps/v8/src/heap/mutable-page.h | 2 +- deps/v8/src/heap/normal-page-inl.h | 2 +- deps/v8/src/heap/normal-page.cc | 22 +- deps/v8/src/heap/normal-page.h | 2 +- deps/v8/src/heap/object-stats.cc | 8 +- deps/v8/src/heap/read-only-heap.cc | 55 +- deps/v8/src/heap/read-only-heap.h | 9 +- deps/v8/src/heap/read-only-promotion.cc | 84 +- deps/v8/src/heap/read-only-spaces.h | 4 +- deps/v8/src/heap/reference-summarizer.cc | 4 +- deps/v8/src/heap/scavenger.cc | 7 +- deps/v8/src/heap/setup-heap-internal.cc | 213 +- deps/v8/src/heap/sweeper.cc | 1 - deps/v8/src/heap/visit-object.cc | 8 +- .../young-generation-marking-visitor-inl.h | 1 - deps/v8/src/ic/accessor-assembler.cc | 66 +- deps/v8/src/ic/accessor-assembler.h | 7 +- deps/v8/src/ic/handler-configuration.cc | 24 + deps/v8/src/ic/ic.cc | 67 +- deps/v8/src/init/bootstrapper.cc | 270 +- deps/v8/src/init/bootstrapper.h | 4 +- deps/v8/src/init/heap-symbols.h | 3 - deps/v8/src/init/icu_util.cc | 29 +- deps/v8/src/init/isolate-group.cc | 57 +- deps/v8/src/inspector/custom-preview.cc | 152 +- deps/v8/src/inspector/custom-preview.h | 15 +- deps/v8/src/inspector/injected-script.cc | 158 +- deps/v8/src/inspector/injected-script.h | 6 +- .../v8/src/inspector/v8-console-agent-impl.cc | 3 + deps/v8/src/inspector/v8-console-message.cc | 31 +- deps/v8/src/inspector/v8-console-message.h | 1 + deps/v8/src/inspector/v8-console.cc | 259 +- deps/v8/src/inspector/v8-console.h | 116 +- .../src/inspector/v8-debugger-agent-impl.cc | 106 +- .../v8/src/inspector/v8-debugger-agent-impl.h | 15 +- deps/v8/src/inspector/v8-debugger.cc | 44 +- deps/v8/src/inspector/v8-debugger.h | 5 +- deps/v8/src/inspector/v8-deep-serializer.cc | 78 +- .../inspector/v8-inspector-session-impl.cc | 23 +- .../src/inspector/v8-inspector-session-impl.h | 3 +- .../src/inspector/v8-profiler-agent-impl.cc | 3 + .../v8/src/inspector/v8-runtime-agent-impl.cc | 8 + .../v8-serialization-duplicate-tracker.cc | 68 +- .../v8-serialization-duplicate-tracker.h | 50 +- deps/v8/src/inspector/value-mirror.cc | 287 +- deps/v8/src/inspector/value-mirror.h | 2 + .../src/interpreter/bytecode-array-builder.cc | 4 +- .../src/interpreter/bytecode-array-iterator.h | 16 + .../src/interpreter/bytecode-array-writer.cc | 2 +- .../interpreter/bytecode-flags-and-tokens.cc | 8 +- .../interpreter/bytecode-flags-and-tokens.h | 24 +- deps/v8/src/interpreter/bytecode-generator.cc | 87 +- deps/v8/src/interpreter/bytecode-generator.h | 2 + deps/v8/src/interpreter/bytecode-jump-table.h | 5 +- deps/v8/src/interpreter/bytecode-node.cc | 3 +- deps/v8/src/interpreter/bytecodes.h | 6 +- .../src/interpreter/interpreter-assembler.cc | 36 +- .../src/interpreter/interpreter-generator.cc | 135 +- deps/v8/src/interpreter/interpreter.cc | 5 +- deps/v8/src/json/json-parser.cc | 170 +- deps/v8/src/json/json-parser.h | 92 +- deps/v8/src/json/json-stringifier.cc | 350 +- deps/v8/src/libsampler/DEPS | 8 +- deps/v8/src/libsampler/sampler.cc | 29 +- deps/v8/src/logging/counters-definitions.h | 42 +- deps/v8/src/logging/counters-scopes.h | 4 +- deps/v8/src/logging/log.cc | 30 +- deps/v8/src/logging/runtime-call-stats.h | 7 +- .../maglev/arm64/maglev-assembler-arm64-inl.h | 42 +- .../loong64/maglev-assembler-loong64-inl.h | 26 +- .../loong64/maglev-assembler-loong64.cc | 12 +- deps/v8/src/maglev/maglev-assembler-inl.h | 9 +- deps/v8/src/maglev/maglev-assembler.cc | 39 +- deps/v8/src/maglev/maglev-assembler.h | 30 +- deps/v8/src/maglev/maglev-basic-block.cc | 48 + deps/v8/src/maglev/maglev-basic-block.h | 20 +- deps/v8/src/maglev/maglev-code-generator.cc | 121 +- deps/v8/src/maglev/maglev-code-generator.h | 8 +- deps/v8/src/maglev/maglev-compilation-info.cc | 38 - deps/v8/src/maglev/maglev-compilation-info.h | 17 - deps/v8/src/maglev/maglev-compilation-unit.cc | 157 +- deps/v8/src/maglev/maglev-compilation-unit.h | 117 +- deps/v8/src/maglev/maglev-compiler.cc | 55 + .../maglev/maglev-concurrent-dispatcher.cc | 34 +- .../src/maglev/maglev-concurrent-dispatcher.h | 2 - deps/v8/src/maglev/maglev-graph-builder.cc | 684 +-- deps/v8/src/maglev/maglev-graph-builder.h | 24 +- deps/v8/src/maglev/maglev-graph-labeller.h | 9 +- deps/v8/src/maglev/maglev-graph-optimizer.cc | 87 +- deps/v8/src/maglev/maglev-graph-optimizer.h | 3 +- deps/v8/src/maglev/maglev-graph-processor.h | 38 +- deps/v8/src/maglev/maglev-graph-serializer.cc | 27 +- deps/v8/src/maglev/maglev-graph.cc | 2 +- deps/v8/src/maglev/maglev-graph.h | 2 +- deps/v8/src/maglev/maglev-inlining.cc | 46 +- .../maglev/maglev-interpreter-frame-state.h | 81 - deps/v8/src/maglev/maglev-ir.cc | 73 +- deps/v8/src/maglev/maglev-ir.h | 159 +- deps/v8/src/maglev/maglev-kna-map.h | 230 + deps/v8/src/maglev/maglev-kna-processor.h | 16 +- .../src/maglev/maglev-known-node-aspects.cc | 353 +- .../v8/src/maglev/maglev-known-node-aspects.h | 85 +- deps/v8/src/maglev/maglev-node-type.cc | 2 +- deps/v8/src/maglev/maglev-node-type.h | 22 +- ...maglev-post-hoc-optimizations-processors.h | 6 +- .../maglev-pre-regalloc-codegen-processors.h | 10 +- deps/v8/src/maglev/maglev-reducer-inl.h | 307 +- deps/v8/src/maglev/maglev-reducer.h | 33 +- deps/v8/src/maglev/maglev-regalloc.cc | 3 + deps/v8/src/maglev/maglev-truncation.h | 10 +- .../src/maglev/ppc/maglev-assembler-ppc-inl.h | 6 +- .../maglev/riscv/maglev-assembler-riscv-inl.h | 2 +- .../v8/src/maglev/turbolev-escape-analysis.cc | 50 +- .../src/maglev/x64/maglev-assembler-x64-inl.h | 5 +- deps/v8/src/maglev/x64/maglev-ir-x64.cc | 10 +- deps/v8/src/numbers/conversions.cc | 56 +- deps/v8/src/numbers/ieee754.cc | 7 + deps/v8/src/objects/DEPS | 3 +- deps/v8/src/objects/all-objects-inl.h | 1 - deps/v8/src/objects/all-objects.h | 1 - deps/v8/src/objects/allocation-site-inl.h | 7 +- deps/v8/src/objects/api-callbacks-inl.h | 50 +- deps/v8/src/objects/api-callbacks.h | 86 +- deps/v8/src/objects/api-callbacks.tq | 6 +- deps/v8/src/objects/arguments-inl.h | 9 +- deps/v8/src/objects/arguments.h | 10 +- deps/v8/src/objects/arguments.tq | 8 +- deps/v8/src/objects/backing-store.cc | 76 +- deps/v8/src/objects/backing-store.h | 6 + deps/v8/src/objects/bigint.cc | 30 +- deps/v8/src/objects/bigint.h | 14 +- deps/v8/src/objects/bit-field-group.h | 81 + deps/v8/src/objects/bytecode-array-inl.h | 6 +- deps/v8/src/objects/bytecode-array.h | 9 +- deps/v8/src/objects/call-site-info-inl.h | 34 +- deps/v8/src/objects/call-site-info.cc | 3 +- deps/v8/src/objects/call-site-info.h | 29 +- deps/v8/src/objects/casting.h | 158 +- deps/v8/src/objects/cell-inl.h | 12 + deps/v8/src/objects/cell.h | 4 + deps/v8/src/objects/code-inl.h | 12 +- deps/v8/src/objects/code.cc | 7 +- deps/v8/src/objects/code.h | 6 +- deps/v8/src/objects/compressed-slots.h | 2 +- deps/v8/src/objects/contexts.cc | 32 +- deps/v8/src/objects/contexts.h | 30 +- deps/v8/src/objects/contexts.tq | 5 +- deps/v8/src/objects/data-handler.h | 7 + deps/v8/src/objects/debug-objects-inl.h | 102 +- deps/v8/src/objects/debug-objects.cc | 15 +- deps/v8/src/objects/debug-objects.h | 98 +- deps/v8/src/objects/deoptimization-data.cc | 20 +- deps/v8/src/objects/deoptimization-data.h | 12 +- deps/v8/src/objects/descriptor-array-inl.h | 23 +- deps/v8/src/objects/descriptor-array.h | 25 +- deps/v8/src/objects/descriptor-array.tq | 8 +- deps/v8/src/objects/elements-kind.h | 5 +- deps/v8/src/objects/elements.cc | 3 +- deps/v8/src/objects/embedder-data-array.h | 1 + deps/v8/src/objects/feedback-cell-inl.h | 16 +- deps/v8/src/objects/feedback-cell.h | 10 +- deps/v8/src/objects/feedback-vector-inl.h | 94 +- deps/v8/src/objects/feedback-vector.cc | 18 +- deps/v8/src/objects/feedback-vector.h | 109 +- deps/v8/src/objects/feedback-vector.tq | 8 +- deps/v8/src/objects/field-index.h | 8 + deps/v8/src/objects/fixed-array-base.h | 4 +- deps/v8/src/objects/fixed-array.h | 13 +- deps/v8/src/objects/fixed-array.tq | 6 +- .../src/objects/fixed-primitive-array-inl.h | 14 +- deps/v8/src/objects/fixed-primitive-array.h | 8 +- deps/v8/src/objects/function-kind.h | 2 +- deps/v8/src/objects/hash-table-inl.h | 4 +- deps/v8/src/objects/hash-table.h | 4 +- deps/v8/src/objects/heap-number-inl.h | 16 +- deps/v8/src/objects/heap-number.h | 37 +- deps/v8/src/objects/heap-number.tq | 9 + deps/v8/src/objects/heap-object-field-inl.h | 8 +- deps/v8/src/objects/heap-object-set-map-inl.h | 43 + deps/v8/src/objects/heap-object.h | 56 +- deps/v8/src/objects/hole.h | 2 +- deps/v8/src/objects/instance-type-checker.h | 1 + deps/v8/src/objects/instance-type-inl.h | 9 + deps/v8/src/objects/instance-type.h | 24 +- deps/v8/src/objects/instance-types-gen.h | 18 +- deps/v8/src/objects/intl-objects.cc | 22 +- deps/v8/src/objects/intl-objects.h | 7 +- deps/v8/src/objects/js-array-buffer-inl.h | 75 +- deps/v8/src/objects/js-array-buffer.cc | 6 +- deps/v8/src/objects/js-array-buffer.h | 117 +- deps/v8/src/objects/js-array-buffer.tq | 12 +- deps/v8/src/objects/js-array.h | 2 +- .../objects/js-atomics-synchronization-inl.h | 266 - .../src/objects/js-atomics-synchronization.cc | 532 -- .../src/objects/js-atomics-synchronization.h | 379 -- .../src/objects/js-atomics-synchronization.tq | 20 - .../src/objects/js-data-object-builder-inl.h | 53 +- deps/v8/src/objects/js-date-time-format.cc | 16 +- deps/v8/src/objects/js-date-time-format.h | 2 +- deps/v8/src/objects/js-display-names.h | 2 +- deps/v8/src/objects/js-disposable-stack.cc | 4 + deps/v8/src/objects/js-disposable-stack.h | 2 +- deps/v8/src/objects/js-duration-format.h | 6 +- deps/v8/src/objects/js-function-inl.h | 10 +- deps/v8/src/objects/js-function.cc | 3 +- deps/v8/src/objects/js-function.h | 9 +- deps/v8/src/objects/js-function.tq | 2 +- deps/v8/src/objects/js-generator.tq | 2 +- deps/v8/src/objects/js-iterator-helpers-inl.h | 28 +- deps/v8/src/objects/js-iterator-helpers.h | 35 +- deps/v8/src/objects/js-list-format.h | 2 +- deps/v8/src/objects/js-locale.cc | 28 +- deps/v8/src/objects/js-number-format.cc | 23 +- deps/v8/src/objects/js-objects-inl.h | 35 +- deps/v8/src/objects/js-objects.cc | 129 +- deps/v8/src/objects/js-objects.h | 52 +- deps/v8/src/objects/js-plural-rules-inl.h | 22 +- .../src/objects/js-plural-rules-internal.cc | 293 + .../v8/src/objects/js-plural-rules-internal.h | 51 + deps/v8/src/objects/js-plural-rules.cc | 248 +- deps/v8/src/objects/js-plural-rules.h | 28 +- deps/v8/src/objects/js-plural-rules.tq | 4 +- deps/v8/src/objects/js-promise-inl.h | 20 +- deps/v8/src/objects/js-promise.h | 40 +- deps/v8/src/objects/js-promise.tq | 14 +- deps/v8/src/objects/js-proxy.h | 2 +- deps/v8/src/objects/js-regexp-inl.h | 9 +- .../src/objects/js-regexp-string-iterator.h | 2 +- deps/v8/src/objects/js-regexp.h | 17 +- deps/v8/src/objects/js-regexp.tq | 4 +- deps/v8/src/objects/js-relative-time-format.h | 2 +- deps/v8/src/objects/js-segment-iterator.h | 2 +- deps/v8/src/objects/js-segmenter.h | 2 +- deps/v8/src/objects/js-segments.h | 2 +- deps/v8/src/objects/js-temporal-objects-inl.h | 11 + deps/v8/src/objects/js-temporal-objects.cc | 6 + deps/v8/src/objects/js-temporal-objects.h | 15 + deps/v8/src/objects/js-temporal-zoneinfo64.cc | 5 + deps/v8/src/objects/js-temporal-zoneinfo64.h | 9 + deps/v8/src/objects/js-weak-refs-inl.h | 4 +- deps/v8/src/objects/js-weak-refs.h | 8 +- deps/v8/src/objects/keys.cc | 31 +- deps/v8/src/objects/keys.h | 6 +- deps/v8/src/objects/literal-objects-inl.h | 101 +- deps/v8/src/objects/literal-objects.cc | 24 +- deps/v8/src/objects/literal-objects.h | 99 +- deps/v8/src/objects/literal-objects.tq | 2 +- deps/v8/src/objects/lookup-inl.h | 2 +- deps/v8/src/objects/lookup.cc | 23 +- deps/v8/src/objects/managed-type-id.h | 2 + deps/v8/src/objects/managed.h | 17 +- deps/v8/src/objects/map-inl.h | 131 +- deps/v8/src/objects/map.cc | 166 +- deps/v8/src/objects/map.h | 151 +- deps/v8/src/objects/map.tq | 26 +- deps/v8/src/objects/microtask-inl.h | 68 +- deps/v8/src/objects/microtask.h | 45 +- deps/v8/src/objects/microtask.tq | 2 +- deps/v8/src/objects/module-inl.h | 191 +- deps/v8/src/objects/module.cc | 507 +- deps/v8/src/objects/module.h | 339 +- deps/v8/src/objects/module.tq | 2 +- deps/v8/src/objects/name-inl.h | 27 +- deps/v8/src/objects/name.h | 126 +- deps/v8/src/objects/name.tq | 26 +- deps/v8/src/objects/number-string-cache-inl.h | 8 +- deps/v8/src/objects/object-list-macros.h | 9 +- deps/v8/src/objects/object-macros-undef.h | 14 +- deps/v8/src/objects/object-macros.h | 79 +- .../objects/objects-body-descriptors-inl.h | 147 +- .../v8/src/objects/objects-body-descriptors.h | 30 +- deps/v8/src/objects/objects-definitions.h | 5 +- deps/v8/src/objects/objects-inl.h | 53 +- deps/v8/src/objects/objects.cc | 100 +- deps/v8/src/objects/objects.h | 19 +- deps/v8/src/objects/oddball-inl.h | 40 +- deps/v8/src/objects/oddball-predicates-inl.h | 2 + deps/v8/src/objects/oddball.h | 28 +- deps/v8/src/objects/off-heap-hash-table-inl.h | 4 +- deps/v8/src/objects/ordered-hash-table.cc | 5 +- deps/v8/src/objects/ordered-hash-table.h | 21 +- deps/v8/src/objects/ordered-hash-table.tq | 74 +- deps/v8/src/objects/primitive-heap-object.h | 2 + deps/v8/src/objects/promise-inl.h | 62 +- deps/v8/src/objects/promise.h | 57 +- deps/v8/src/objects/promise.tq | 2 +- deps/v8/src/objects/property-array.h | 1 + deps/v8/src/objects/property-cell.tq | 2 +- .../objects/property-descriptor-object-inl.h | 35 +- .../src/objects/property-descriptor-object.h | 28 +- deps/v8/src/objects/property.cc | 7 +- deps/v8/src/objects/prototype-info-inl.h | 14 + deps/v8/src/objects/prototype-info.h | 7 +- deps/v8/src/objects/regexp-match-info.h | 1 + deps/v8/src/objects/scope-info-inl.h | 89 +- deps/v8/src/objects/scope-info.cc | 246 +- deps/v8/src/objects/scope-info.h | 153 +- deps/v8/src/objects/scope-info.tq | 125 +- deps/v8/src/objects/script-inl.h | 69 +- deps/v8/src/objects/script.h | 23 +- .../v8/src/objects/shared-function-info-inl.h | 151 +- deps/v8/src/objects/shared-function-info.cc | 63 +- deps/v8/src/objects/shared-function-info.h | 209 +- deps/v8/src/objects/shared-function-info.tq | 6 +- deps/v8/src/objects/simd.cc | 14 +- deps/v8/src/objects/slots-inl.h | 72 +- deps/v8/src/objects/slots.h | 51 +- deps/v8/src/objects/smi.h | 5 - deps/v8/src/objects/sort-state.h | 2 +- deps/v8/src/objects/source-text-module-inl.h | 96 +- deps/v8/src/objects/source-text-module.cc | 1422 ++--- deps/v8/src/objects/source-text-module.h | 222 +- deps/v8/src/objects/string-inl.h | 17 +- deps/v8/src/objects/string-table.cc | 10 +- deps/v8/src/objects/string.cc | 30 +- deps/v8/src/objects/string.h | 16 +- deps/v8/src/objects/string.tq | 4 +- deps/v8/src/objects/struct-inl.h | 57 +- deps/v8/src/objects/struct.h | 58 +- deps/v8/src/objects/struct.tq | 7 + .../src/objects/swiss-name-dictionary-inl.h | 216 +- deps/v8/src/objects/swiss-name-dictionary.cc | 73 +- deps/v8/src/objects/swiss-name-dictionary.h | 133 +- deps/v8/src/objects/swiss-name-dictionary.tq | 14 +- deps/v8/src/objects/synthetic-module.cc | 45 +- deps/v8/src/objects/synthetic-module.h | 14 +- deps/v8/src/objects/tagged-field-inl.h | 76 +- deps/v8/src/objects/tagged-field.h | 61 +- deps/v8/src/objects/tagged.h | 114 +- deps/v8/src/objects/template-objects-inl.h | 16 +- deps/v8/src/objects/template-objects.h | 13 +- deps/v8/src/objects/templates-inl.h | 86 +- deps/v8/src/objects/templates.cc | 12 +- deps/v8/src/objects/templates.h | 68 +- deps/v8/src/objects/templates.tq | 2 +- deps/v8/src/objects/transitions.cc | 1 - deps/v8/src/objects/trusted-object-inl.h | 60 +- deps/v8/src/objects/trusted-object.h | 8 +- deps/v8/src/objects/trusted-object.tq | 2 +- deps/v8/src/objects/trusted-pointer-inl.h | 235 - deps/v8/src/objects/turbofan-types-inl.h | 14 +- deps/v8/src/objects/turbofan-types.h | 37 +- deps/v8/src/objects/turbofan-types.tq | 29 +- deps/v8/src/objects/turboshaft-types-inl.h | 5 +- deps/v8/src/objects/turboshaft-types.h | 27 +- deps/v8/src/objects/turboshaft-types.tq | 8 +- deps/v8/src/objects/value-serializer.cc | 50 +- deps/v8/src/objects/visitors.h | 8 +- deps/v8/src/objects/waiter-queue-node.cc | 196 - deps/v8/src/objects/waiter-queue-node.h | 88 - deps/v8/src/parsing/expression-scope.h | 114 +- deps/v8/src/parsing/literal-buffer.cc | 50 +- deps/v8/src/parsing/literal-buffer.h | 8 +- deps/v8/src/parsing/parser-base.h | 436 +- deps/v8/src/parsing/parser.cc | 152 +- deps/v8/src/parsing/parser.h | 40 +- .../pending-compilation-error-handler.cc | 3 +- deps/v8/src/parsing/preparse-data.cc | 2 +- deps/v8/src/parsing/preparse-data.h | 1 - deps/v8/src/parsing/preparser.cc | 66 +- deps/v8/src/parsing/preparser.h | 39 +- deps/v8/src/parsing/rewriter.cc | 52 +- deps/v8/src/parsing/scanner.cc | 131 +- deps/v8/src/parsing/scanner.h | 34 +- deps/v8/src/profiler/cpu-profiler.cc | 42 +- deps/v8/src/profiler/cpu-profiler.h | 16 +- deps/v8/src/profiler/heap-profiler.cc | 12 +- deps/v8/src/profiler/heap-profiler.h | 6 +- .../src/profiler/heap-snapshot-generator.cc | 99 +- .../v8/src/profiler/heap-snapshot-generator.h | 2 + deps/v8/src/profiler/output-stream-writer.h | 6 +- deps/v8/src/profiler/profile-generator.cc | 9 +- deps/v8/src/profiler/profile-generator.h | 7 +- deps/v8/src/profiler/profiler-listener.cc | 5 +- .../v8/src/profiler/sampling-heap-profiler.cc | 18 +- deps/v8/src/profiler/sampling-heap-profiler.h | 10 +- deps/v8/src/profiler/strings-storage.cc | 26 +- deps/v8/src/profiler/tick-sample.cc | 13 +- deps/v8/src/profiler/tick-sample.h | 5 +- .../regexp/arm/regexp-macro-assembler-arm.cc | 57 +- .../regexp/arm/regexp-macro-assembler-arm.h | 7 +- .../arm64/regexp-macro-assembler-arm64.cc | 98 +- .../arm64/regexp-macro-assembler-arm64.h | 10 +- .../experimental/experimental-bytecode.cc | 2 +- deps/v8/src/regexp/gen-regexp-special-case.cc | 19 + .../ia32/regexp-macro-assembler-ia32.cc | 53 +- .../regexp/ia32/regexp-macro-assembler-ia32.h | 5 +- .../loong64/regexp-macro-assembler-loong64.cc | 68 +- .../loong64/regexp-macro-assembler-loong64.h | 7 +- .../mips64/regexp-macro-assembler-mips64.cc | 72 +- .../mips64/regexp-macro-assembler-mips64.h | 7 +- .../regexp/ppc/regexp-macro-assembler-ppc.cc | 61 +- .../regexp/ppc/regexp-macro-assembler-ppc.h | 11 +- deps/v8/src/regexp/regexp-ast.h | 8 +- .../regexp/regexp-bytecode-generator-inl.h | 4 +- deps/v8/src/regexp/regexp-compiler-tonode.cc | 16 +- deps/v8/src/regexp/regexp-compiler.cc | 169 +- deps/v8/src/regexp/regexp-compiler.h | 11 +- deps/v8/src/regexp/regexp-flags.h | 2 +- deps/v8/src/regexp/regexp-interpreter.cc | 3 +- deps/v8/src/regexp/regexp-nodes.h | 11 +- deps/v8/src/regexp/regexp-parser.cc | 204 +- deps/v8/src/regexp/regexp-stack.h | 45 +- deps/v8/src/regexp/regexp.cc | 8 +- .../riscv/regexp-macro-assembler-riscv.cc | 68 +- .../riscv/regexp-macro-assembler-riscv.h | 7 +- .../s390/regexp-macro-assembler-s390.cc | 47 +- .../regexp/s390/regexp-macro-assembler-s390.h | 6 + deps/v8/src/regexp/special-case.h | 28 +- .../regexp/x64/regexp-macro-assembler-x64.cc | 72 +- .../regexp/x64/regexp-macro-assembler-x64.h | 11 +- deps/v8/src/roots/roots-inl.h | 37 +- deps/v8/src/roots/roots.cc | 6 +- deps/v8/src/roots/roots.h | 33 +- deps/v8/src/roots/static-roots.h | 8 +- deps/v8/src/runtime/runtime-array.cc | 21 +- deps/v8/src/runtime/runtime-classes.cc | 6 +- deps/v8/src/runtime/runtime-compiler.cc | 80 +- deps/v8/src/runtime/runtime-debug.cc | 62 +- deps/v8/src/runtime/runtime-forin.cc | 75 +- deps/v8/src/runtime/runtime-internal.cc | 10 +- deps/v8/src/runtime/runtime-literals.cc | 9 +- deps/v8/src/runtime/runtime-object.cc | 34 +- deps/v8/src/runtime/runtime-promise.cc | 14 +- deps/v8/src/runtime/runtime-regexp.cc | 54 +- deps/v8/src/runtime/runtime-scopes.cc | 20 +- deps/v8/src/runtime/runtime-test-wasm.cc | 21 +- deps/v8/src/runtime/runtime-test.cc | 47 +- deps/v8/src/runtime/runtime-typedarray.cc | 6 +- deps/v8/src/runtime/runtime-wasm.cc | 277 +- deps/v8/src/runtime/runtime.cc | 10 +- deps/v8/src/runtime/runtime.h | 28 +- deps/v8/src/sandbox/bytecode-verifier.cc | 29 +- deps/v8/src/sandbox/bytecode-verifier.h | 11 + deps/v8/src/sandbox/code-entrypoint-tag.h | 17 +- .../src/sandbox/cppheap-pointer-table-inl.h | 5 +- deps/v8/src/sandbox/cppheap-pointer-table.h | 4 + deps/v8/src/sandbox/cppheap-pointer-tag.h | 6 +- .../src/sandbox/external-entity-table-inl.h | 2 + deps/v8/src/sandbox/external-entity-table.h | 2 + .../src/sandbox/external-pointer-table-inl.h | 39 +- deps/v8/src/sandbox/external-pointer-table.h | 4 + .../sandbox/generated-code-validator-arm64.cc | 342 +- .../sandbox/generated-code-validator-x64.cc | 222 +- .../src/sandbox/generated-code-validator.cc | 166 +- .../v8/src/sandbox/generated-code-validator.h | 148 +- deps/v8/src/sandbox/indirect-pointer-inl.h | 95 - deps/v8/src/sandbox/indirect-pointer.h | 65 - deps/v8/src/sandbox/isolate-inl.h | 6 +- deps/v8/src/sandbox/isolate.h | 6 +- deps/v8/src/sandbox/js-dispatch-table-inl.h | 45 +- deps/v8/src/sandbox/js-dispatch-table.cc | 5 + deps/v8/src/sandbox/js-dispatch-table.h | 70 +- deps/v8/src/sandbox/sandbox-malloc.h | 32 +- deps/v8/src/sandbox/sandbox-zero-segment.h | 65 + deps/v8/src/sandbox/sandbox.cc | 23 +- deps/v8/src/sandbox/sandbox.h | 25 +- deps/v8/src/sandbox/tagged-payload.h | 3 +- deps/v8/src/sandbox/testing.cc | 85 +- deps/v8/src/sandbox/trusted-pointer-inl.h | 337 ++ .../src/sandbox/trusted-pointer-table-inl.h | 46 +- deps/v8/src/sandbox/trusted-pointer-table.cc | 16 +- deps/v8/src/sandbox/trusted-pointer-table.h | 44 +- ...ct-pointer-tag.h => trusted-pointer-tag.h} | 243 +- .../{objects => sandbox}/trusted-pointer.h | 111 +- deps/v8/src/snapshot/code-serializer.cc | 321 +- deps/v8/src/snapshot/code-serializer.h | 193 +- deps/v8/src/snapshot/context-deserializer.h | 5 +- deps/v8/src/snapshot/context-serializer.cc | 4 +- deps/v8/src/snapshot/deserializer.cc | 341 +- deps/v8/src/snapshot/deserializer.h | 91 +- .../snapshot/embedded/embedded-file-writer.cc | 21 +- .../snapshot/embedded/embedded-file-writer.h | 11 +- .../platform-embedded-file-writer-win.cc | 7 +- deps/v8/src/snapshot/object-deserializer.cc | 18 +- .../v8/src/snapshot/read-only-deserializer.cc | 32 +- deps/v8/src/snapshot/read-only-serializer.cc | 10 +- .../v8/src/snapshot/serializer-deserializer.h | 136 +- deps/v8/src/snapshot/serializer.cc | 366 +- deps/v8/src/snapshot/serializer.h | 75 +- .../src/snapshot/shared-heap-deserializer.cc | 12 + .../src/snapshot/shared-heap-deserializer.h | 4 +- .../v8/src/snapshot/shared-heap-serializer.cc | 2 +- deps/v8/src/snapshot/snapshot-compression.cc | 11 +- deps/v8/src/snapshot/snapshot-data.cc | 6 +- deps/v8/src/snapshot/snapshot-source-sink.h | 14 +- deps/v8/src/snapshot/snapshot.cc | 62 +- deps/v8/src/snapshot/startup-deserializer.cc | 15 +- deps/v8/src/snapshot/startup-deserializer.h | 3 +- deps/v8/src/snapshot/startup-serializer.cc | 5 +- deps/v8/src/snapshot/static-roots-gen.cc | 33 +- .../snapshot/trusted-section-serializer.cc | 113 + .../src/snapshot/trusted-section-serializer.h | 56 + deps/v8/src/strings/string-hasher.cc | 2 +- deps/v8/src/strings/string-search.h | 33 +- deps/v8/src/strings/string-stream.cc | 32 +- deps/v8/src/strings/string-stream.h | 18 +- deps/v8/src/strings/uri.cc | 8 +- deps/v8/src/torque/ast.h | 1 + deps/v8/src/torque/cpp-builder.cc | 23 +- deps/v8/src/torque/cpp-builder.h | 4 + deps/v8/src/torque/declaration-visitor.cc | 10 + deps/v8/src/torque/earley-parser.cc | 13 +- deps/v8/src/torque/earley-parser.h | 9 + deps/v8/src/torque/global-context.cc | 2 + deps/v8/src/torque/global-context.h | 41 + deps/v8/src/torque/implementation-visitor.cc | 283 +- deps/v8/src/torque/instance-type-generator.cc | 12 +- deps/v8/src/torque/kythe-data.cc | 3 +- deps/v8/src/torque/kythe-data.h | 9 +- deps/v8/src/torque/layout-loader.cc | 1831 +++++++ deps/v8/src/torque/layout-loader.h | 44 + deps/v8/src/torque/source-positions.cc | 8 +- deps/v8/src/torque/source-positions.h | 4 + deps/v8/src/torque/torque-compiler.cc | 19 + deps/v8/src/torque/torque-compiler.h | 25 + deps/v8/src/torque/torque-parser.cc | 52 +- deps/v8/src/torque/torque-parser.h | 5 + deps/v8/src/torque/torque.cc | 10 + deps/v8/src/torque/type-visitor.cc | 10 +- deps/v8/src/torque/types.cc | 28 +- deps/v8/src/torque/utils.cc | 6 +- deps/v8/src/tracing/code-data-source.cc | 5 +- deps/v8/src/tracing/perfetto-logger.cc | 19 +- deps/v8/src/tracing/traced-value.cc | 6 +- deps/v8/src/utils/bit-vector.h | 71 +- deps/v8/src/utils/memcopy.h | 19 +- deps/v8/src/utils/scoped-list.h | 15 +- deps/v8/src/utils/sparse-bit-vector.h | 18 +- deps/v8/src/utils/utils.cc | 3 +- deps/v8/src/utils/utils.h | 110 +- .../baseline/arm/liftoff-assembler-arm-inl.h | 103 +- .../arm64/liftoff-assembler-arm64-inl.h | 148 +- .../ia32/liftoff-assembler-ia32-inl.h | 88 +- .../src/wasm/baseline/liftoff-assembler-inl.h | 2 +- .../v8/src/wasm/baseline/liftoff-assembler.cc | 7 +- deps/v8/src/wasm/baseline/liftoff-assembler.h | 32 +- deps/v8/src/wasm/baseline/liftoff-compiler.cc | 406 +- deps/v8/src/wasm/baseline/liftoff-compiler.h | 2 +- deps/v8/src/wasm/baseline/liftoff-varstate.h | 22 +- .../loong64/liftoff-assembler-loong64-inl.h | 137 +- .../mips64/liftoff-assembler-mips64-inl.h | 63 +- deps/v8/src/wasm/baseline/parallel-move.cc | 5 +- deps/v8/src/wasm/baseline/parallel-move.h | 2 +- .../baseline/ppc/liftoff-assembler-ppc-inl.h | 108 +- .../riscv/liftoff-assembler-riscv-inl.h | 71 +- .../riscv/liftoff-assembler-riscv32-inl.h | 5 +- .../riscv/liftoff-assembler-riscv64-inl.h | 28 +- .../s390/liftoff-assembler-s390-inl.h | 107 +- .../baseline/x64/liftoff-assembler-x64-inl.h | 250 +- deps/v8/src/wasm/c-api.cc | 18 +- deps/v8/src/wasm/canonical-types.cc | 8 +- deps/v8/src/wasm/canonical-types.h | 4 +- .../src/wasm/compilation-hints-generation.cc | 19 +- .../src/wasm/constant-expression-interface.cc | 77 +- deps/v8/src/wasm/decoder.h | 5 +- deps/v8/src/wasm/function-body-decoder-impl.h | 109 +- deps/v8/src/wasm/function-compiler.cc | 5 - deps/v8/src/wasm/function-compiler.h | 11 +- .../wasm/fuzzing/random-module-generation.cc | 48 +- deps/v8/src/wasm/inlining-tree.h | 2 +- .../arm64/interpreter-builtins-arm64.cc | 3 +- .../riscv/interpreter-builtins-riscv.cc | 2 +- .../wasm/interpreter/wasm-interpreter-inl.h | 3 +- .../wasm-interpreter-runtime-inl.h | 2 +- .../interpreter/wasm-interpreter-runtime.cc | 143 +- .../interpreter/wasm-interpreter-runtime.h | 30 +- .../src/wasm/interpreter/wasm-interpreter.cc | 66 +- .../src/wasm/interpreter/wasm-interpreter.h | 50 +- .../x64/interpreter-builtins-x64.cc | 2 +- deps/v8/src/wasm/jump-table-assembler.cc | 15 +- deps/v8/src/wasm/module-compiler.cc | 138 +- deps/v8/src/wasm/module-compiler.h | 7 +- deps/v8/src/wasm/module-decoder-impl.h | 59 +- deps/v8/src/wasm/module-decoder.cc | 13 +- deps/v8/src/wasm/module-decoder.h | 5 +- deps/v8/src/wasm/module-instantiate.cc | 28 +- deps/v8/src/wasm/names-provider.cc | 27 +- deps/v8/src/wasm/names-provider.h | 3 +- deps/v8/src/wasm/pgo.cc | 40 +- deps/v8/src/wasm/stacks.cc | 21 +- deps/v8/src/wasm/stacks.h | 9 +- deps/v8/src/wasm/std-object-sizes.h | 4 +- deps/v8/src/wasm/streaming-decoder.cc | 21 +- deps/v8/src/wasm/streaming-decoder.h | 10 +- deps/v8/src/wasm/struct-types.h | 43 +- .../src/wasm/turboshaft-graph-interface-inl.h | 90 +- .../v8/src/wasm/turboshaft-graph-interface.cc | 585 +- deps/v8/src/wasm/turboshaft-graph-interface.h | 3 +- deps/v8/src/wasm/wasm-builtin-list.h | 7 +- deps/v8/src/wasm/wasm-code-coverage.h | 13 +- deps/v8/src/wasm/wasm-code-manager.cc | 177 +- deps/v8/src/wasm/wasm-code-manager.h | 20 +- deps/v8/src/wasm/wasm-debug.cc | 323 +- deps/v8/src/wasm/wasm-deopt-data.cc | 7 +- deps/v8/src/wasm/wasm-deopt-data.h | 3 +- deps/v8/src/wasm/wasm-engine.cc | 307 +- deps/v8/src/wasm/wasm-engine.h | 28 +- deps/v8/src/wasm/wasm-export-wrapper-cache.h | 3 +- deps/v8/src/wasm/wasm-external-refs.cc | 129 +- deps/v8/src/wasm/wasm-external-refs.h | 5 +- deps/v8/src/wasm/wasm-features.h | 7 +- deps/v8/src/wasm/wasm-js.cc | 123 +- deps/v8/src/wasm/wasm-js.h | 3 +- deps/v8/src/wasm/wasm-module-builder.cc | 24 +- deps/v8/src/wasm/wasm-module-builder.h | 37 +- deps/v8/src/wasm/wasm-module-sourcemap.cc | 8 +- deps/v8/src/wasm/wasm-module.cc | 5 +- deps/v8/src/wasm/wasm-module.h | 5 +- deps/v8/src/wasm/wasm-objects-inl.h | 137 +- deps/v8/src/wasm/wasm-objects.cc | 213 +- deps/v8/src/wasm/wasm-objects.h | 179 +- deps/v8/src/wasm/wasm-objects.tq | 2 +- deps/v8/src/wasm/wasm-result.cc | 8 +- deps/v8/src/wasm/wasm-serialization.cc | 51 +- deps/v8/src/wasm/wasm-serialization.h | 11 +- deps/v8/src/wasm/wasm-subtyping.cc | 15 +- deps/v8/src/wasm/wasm-subtyping.h | 4 + deps/v8/src/wasm/wasm-value.h | 1 + deps/v8/src/wasm/wasm-wrapper-cache-inl.h | 8 +- deps/v8/src/zone/zone-chunk-list.h | 536 -- deps/v8/test/benchmarks/cpp/BUILD.gn | 45 +- deps/v8/test/benchmarks/cpp/DEPS | 2 +- deps/v8/test/benchmarks/cpp/benchmark-main.cc | 2 +- deps/v8/test/benchmarks/cpp/benchmark-utils.h | 2 +- deps/v8/test/benchmarks/cpp/bindings.cc | 6 +- deps/v8/test/benchmarks/cpp/cppgc/BUILD.gn | 9 +- deps/v8/test/benchmarks/cpp/cppgc/DEPS | 2 +- .../benchmarks/cpp/cppgc/allocation_perf.cc | 2 +- .../benchmarks/cpp/cppgc/benchmark_main.cc | 2 +- .../benchmarks/cpp/cppgc/benchmark_utils.h | 2 +- .../benchmarks/cpp/cppgc/binary-trees_perf.cc | 2 +- .../test/benchmarks/cpp/cppgc/trace_perf.cc | 2 +- deps/v8/test/benchmarks/cpp/dtoa.cc | 10 +- deps/v8/test/benchmarks/cpp/empty.cc | 2 +- deps/v8/test/benchmarks/cpp/fast-api.cc | 8 +- deps/v8/test/cctest/BUILD.gn | 55 - deps/v8/test/cctest/cctest.cc | 6 +- deps/v8/test/cctest/cctest.h | 4 +- deps/v8/test/cctest/cctest.status | 292 - deps/v8/test/cctest/collector.h | 76 +- deps/v8/test/cctest/compiler/codegen-tester.h | 3 +- .../cctest/compiler/test-code-generator.cc | 21 +- .../test-concurrent-shared-function-info.cc | 1 - .../cctest/compiler/test-multiple-return.cc | 11 +- .../cctest/compiler/test-run-native-calls.cc | 18 +- .../compiler/turboshaft-codegen-tester.h | 4 +- deps/v8/test/cctest/heap/heap-tester.h | 81 +- deps/v8/test/cctest/heap/heap-utils.cc | 79 +- deps/v8/test/cctest/heap/heap-utils.h | 29 - deps/v8/test/cctest/heap/test-alloc.cc | 181 - deps/v8/test/cctest/heap/test-compaction.cc | 440 -- .../cctest/heap/test-concurrent-marking.cc | 65 - deps/v8/test/cctest/heap/test-heap.cc | 2784 ---------- .../cctest/heap/test-incremental-marking.cc | 70 - deps/v8/test/cctest/heap/test-mark-compact.cc | 382 -- .../cctest/heap/test-memory-measurement.cc | 236 - deps/v8/test/cctest/heap/test-pool.cc | 66 - deps/v8/test/cctest/heap/test-spaces.cc | 826 --- .../v8/test/cctest/heap/test-write-barrier.cc | 94 - .../v8/test/cctest/test-accessor-assembler.cc | 3 +- deps/v8/test/cctest/test-api-array-buffer.cc | 62 +- deps/v8/test/cctest/test-api-incumbent.cc | 25 +- deps/v8/test/cctest/test-api-interceptors.cc | 148 +- deps/v8/test/cctest/test-api-stack-traces.cc | 164 +- deps/v8/test/cctest/test-api-typed-array.cc | 49 +- deps/v8/test/cctest/test-api.cc | 975 +++- .../test/cctest/test-code-stub-assembler.cc | 77 - deps/v8/test/cctest/test-cpu-profiler.cc | 265 +- deps/v8/test/cctest/test-debug-helper.cc | 45 +- deps/v8/test/cctest/test-debug.cc | 162 +- .../test/cctest/test-field-type-tracking.cc | 9 +- .../test/cctest/test-func-name-inference.cc | 1 - deps/v8/test/cctest/test-heap-profiler.cc | 320 +- deps/v8/test/cctest/test-js-to-wasm.cc | 14 +- deps/v8/test/cctest/test-log-stack-tracer.cc | 6 +- deps/v8/test/cctest/test-profile-generator.cc | 14 +- deps/v8/test/cctest/test-regexp.cc | 2 +- deps/v8/test/cctest/test-sampler-api.cc | 11 +- deps/v8/test/cctest/test-serialize.cc | 944 +++- deps/v8/test/cctest/test-shared-strings.cc | 2147 +------- deps/v8/test/cctest/test-strings.cc | 30 +- .../cctest/test-swiss-name-dictionary-csa.cc | 19 +- .../cctest/test-swiss-name-dictionary-infra.h | 38 +- .../test-swiss-name-dictionary-shared-tests.h | 158 +- .../test/cctest/test-swiss-name-dictionary.cc | 93 +- deps/v8/test/cctest/test-transitions.cc | 19 +- deps/v8/test/cctest/test-usecounters.cc | 50 +- deps/v8/test/cctest/test-utils.cc | 23 +- deps/v8/test/cctest/wasm/test-run-wasm-f16.cc | 453 -- deps/v8/test/common/code-assembler-tester.h | 2 +- deps/v8/test/common/wasm/fuzzer-common.cc | 101 +- .../v8/test/common/wasm/wasm-module-runner.cc | 3 +- deps/v8/test/common/wasm/wasm-run-utils.cc | 75 +- deps/v8/test/common/wasm/wasm-run-utils.h | 55 +- .../test/debugger/debug/debug-eval-scope.js | 2 + .../debug-evaluate-shadowed-context-reuse.js | 9 +- .../debug/debug-evaluate-shadowed-context.js | 9 +- .../debugger/debug/debug-function-scopes.js | 16 +- .../debug-modules-set-variable-value.mjs | 4 +- .../debug-scopes-suspended-generators.js | 2 +- deps/v8/test/debugger/debug/debug-scopes.js | 40 +- ...regress-nested-arrow-default-param-this.js | 35 + .../debug/harmony/modules-debug-scopes1.mjs | 18 +- .../regress-debug-scopes-context-blocklist.js | 5 +- deps/v8/test/debugger/debugger.status | 6 + .../debugger/regress/regress-510925423.js | 17 - .../debugger/regress/regress-571155503.js | 132 + .../regress/wasm/regress-532625490.js | 25 - .../regress/wasm/regress-570547314.js | 68 + .../regress/wasm/regress-576981470.js | 45 + deps/v8/test/debugger/test-api.js | 10 +- deps/v8/test/filecheck/deopt-now-fuzzing.js | 43 + deps/v8/test/filecheck/filecheck.status | 1 + ...ad-rest-parameter-late-inlined-mutation.js | 42 + .../wasm-turbolev-inlined-wrapper.js | 13 +- .../turbofan-extern-convert-any-static.js | 7 +- deps/v8/test/fuzzer/multi-return.cc | 5 +- deps/v8/test/fuzzer/wasm/async.cc | 3 +- deps/v8/test/fuzzer/wasm/code.cc | 2 +- deps/v8/test/fuzzer/wasm/deopt.cc | 15 +- deps/v8/test/fuzzer/wasm/init-expr.cc | 3 +- .../wasm/interpreter/fast-interpreter.cc | 3 +- .../wasm/interpreter/interpreter-code.cc | 2 +- .../wasm/interpreter/interpreter-diff.cc | 3 +- .../interpreter/interpreter-fuzzer-common.cc | 9 +- .../wasm/interpreter/interpreter-init-expr.cc | 3 +- deps/v8/test/fuzzer/wasm/module.cc | 3 +- deps/v8/test/fuzzer/wasm/streaming.cc | 7 +- .../enable-with-stored-exception-expected.txt | 9 + .../console/enable-with-stored-exception.js | 35 + .../debugger/class-fields-scopes-expected.txt | 216 +- .../class-private-fields-scopes-expected.txt | 42 +- ...luate-on-call-frame-in-module-expected.txt | 35 +- ...-frame-in-throwing-with-scope-expected.txt | 16 + ...te-on-call-frame-in-throwing-with-scope.js | 53 + ...private-class-member-conflict-expected.txt | 34 + ...ll-frame-private-class-member-expected.txt | 38 + ...e-private-class-member-static-expected.txt | 38 + ...-constructor-anonymous-scopes-expected.txt | 1 + ...es-import-meta-debug-evaluate-expected.txt | 19 + .../modules-import-meta-debug-evaluate.js | 38 + .../debugger/osr-debug-break-expected.txt | 3 + .../inspector/debugger/osr-debug-break.js | 53 + .../osr-step-in-blackboxed-expected.txt | 5 + .../debugger/osr-step-in-blackboxed.js | 61 + .../osr-step-on-throw-blackboxed-expected.txt | 5 + .../debugger/osr-step-on-throw-blackboxed.js | 59 + .../debugger/osr-step-on-throw-expected.txt | 5 + .../inspector/debugger/osr-step-on-throw.js | 55 + .../debugger/osr-step-out-expected.txt | 4 + .../test/inspector/debugger/osr-step-out.js | 51 + ...-on-oom-all-frames-blackboxed-expected.txt | 3 + .../pause-on-oom-all-frames-blackboxed.js | 45 + .../pause-on-oom-in-blackboxed-expected.txt | 3 + .../debugger/pause-on-oom-in-blackboxed.js | 46 + .../regress-blackbox-exact-start-expected.txt | 3 + .../debugger/regress-blackbox-exact-start.js | 43 + ...over-enter-ranges-exact-start-expected.txt | 2 + ...ress-step-over-enter-ranges-exact-start.js | 44 + ...t-frame-during-embedder-pause-expected.txt | 3 + .../restart-frame-during-embedder-pause.js | 63 + ...pe-chain-eval-unique-id-clash-expected.txt | 18 + .../scope-chain-eval-unique-id-clash.js | 61 + .../scope-chain-outer-scopes-expected.txt | 269 + .../debugger/scope-chain-outer-scopes.js | 278 + .../scope-chain-return-position-expected.txt | 77 + .../debugger/scope-chain-return-position.js | 88 + .../debugger/scope-empty-reason-expected.txt | 15 + .../inspector/debugger/scope-empty-reason.js | 70 + ...pt-parsed-long-magic-comments-expected.txt | 13 + .../script-parsed-long-magic-comments.js | 36 + ...after-last-breakable-position-expected.txt | 31 + ...reakpoint-after-last-breakable-position.js | 66 + ...akpoint-no-breakable-position-expected.txt | 3 + .../set-breakpoint-no-breakable-position.js | 29 + ...et-variable-value-unallocated-expected.txt | 19 + .../set-variable-value-unallocated.js | 57 + ...-variable-value-varblock-eval-expected.txt | 10 + .../set-variable-value-varblock-eval.js | 46 + ...luate-with-pause-on-next-call-expected.txt | 11 + ...t-free-evaluate-with-pause-on-next-call.js | 40 + .../step-over-enter-ranges-expected.txt | 106 + .../debugger/step-over-enter-ranges.js | 185 + ...ing-with-skip-list-and-assert-expected.txt | 25 + .../stepping-with-skip-list-and-assert.js | 82 + ...ith-skip-list-and-breakpoints-expected.txt | 114 + ...stepping-with-skip-list-and-breakpoints.js | 122 + ...stepping-with-stale-skip-list-expected.txt | 63 + .../debugger/stepping-with-stale-skip-list.js | 84 + .../debugger/tdz-modules-scopes-expected.txt | 8 + .../debugger/tdz-scopes-expected.txt | 4 + ...untrusted-terminate-on-resume-expected.txt | 26 + .../debugger/untrusted-terminate-on-resume.js | 29 + .../wasm-inspect-inline-trap-expected.txt | 8 +- .../debugger/wasm-inspect-inline-trap.js | 25 +- .../wasm-set-breakpoint-on-entry-expected.txt | 8 + .../debugger/wasm-set-breakpoint-on-entry.js | 24 + deps/v8/test/inspector/inspector-test.cc | 45 +- deps/v8/test/inspector/inspector.status | 36 + deps/v8/test/inspector/isolate-data.cc | 6 +- .../private-class-member-inspector-test.js | 12 + .../regress/regress-502287689-expected.txt | 12 + .../inspector/regress/regress-502287689.js | 104 + .../regress/regress-502337304-expected.txt | 1 + .../inspector/regress/regress-502337304.js | 58 + .../regress/regress-507490539-expected.txt | 1 + .../regress}/regress-507490539.js | 54 +- .../regress/regress-513048538-expected.txt | 9 + .../regress}/regress-513048538.js | 18 +- .../regress/regress-513413942-expected.txt | 12 + .../inspector/regress/regress-513413942.js | 77 + .../regress/regress-514561070-expected.txt | 9 + .../inspector/regress/regress-514561070.js | 20 + .../regress/regress-516022777-expected.txt | 9 + .../inspector/regress/regress-516022777.js | 22 + .../regress/regress-519715438-expected.txt | 1 + .../inspector/regress/regress-519715438.js | 75 + .../regress/regress-521715545-expected.txt | 12 + .../inspector/regress/regress-521715545.js | 57 + .../regress/regress-526163463-expected.txt | 1 + .../inspector/regress/regress-526163463.js | 52 + .../regress/regress-527985808-expected.txt | 1 + .../inspector/regress/regress-527985808.js | 53 + .../regress/regress-529880019-expected.txt | 1 + .../regress}/regress-529880019.js | 48 +- .../regress/regress-530658019-expected.txt | 2 + .../regress}/regress-530658019.js | 73 +- .../regress/regress-531297707-expected.txt | 4 + .../inspector/regress/regress-531297707.js | 51 + .../regress/regress-532720981-expected.txt | 1 + .../inspector/regress/regress-532720981.js | 25 + .../regress/regress-534275413-expected.txt | 7 + .../regress}/regress-534275413.js | 71 +- .../regress/regress-534579660-expected.txt | 5 + .../inspector/regress/regress-534579660.js | 85 + .../regress/regress-537219980-expected.txt | 5 + .../inspector/regress/regress-537219980.js | 87 + .../regress/regress-568338771-expected.txt | 1 + .../inspector/regress/regress-568338771.js | 56 + .../regress/regress-569886678-expected.txt | 2 + .../inspector/regress/regress-569886678.js | 50 + .../regress/regress-570538338-expected.txt | 6 + .../inspector/regress/regress-570538338.js | 94 + .../regress/regress-570547313-expected.txt | 6 + .../inspector/regress/regress-570547313.js | 54 + .../regress/regress-570558888-expected.txt | 1 + .../inspector/regress/regress-570558888.js | 45 + .../regress/regress-571965281-expected.txt | 5 + .../inspector/regress/regress-571965281.js | 78 + .../regress/regress-572276045-expected.txt | 8 + .../inspector/regress/regress-572276045.js | 43 + .../regress/regress-572276137-expected.txt | 3 + .../inspector/regress/regress-572276137.js | 77 + .../regress/regress-572401025-expected.txt | 39 + .../inspector/regress/regress-572401025.js | 47 + .../regress/regress-572403047-expected.txt | 2 + .../inspector/regress/regress-572403047.js | 34 + .../regress/regress-572834323-expected.txt | 27 + .../inspector/regress/regress-572834323.js | 26 + .../regress/regress-574453614-expected.txt | 31 + .../inspector/regress/regress-574453614.js | 38 + .../regress/regress-574454550-expected.txt | 5 + .../inspector/regress/regress-574454550.js | 17 + .../regress/regress-574597225-expected.txt | 15 + .../inspector/regress/regress-574597225.js | 65 + .../regress/regress-574597313-expected.txt | 3 + .../inspector/regress/regress-574597313.js | 62 + .../regress/regress-575321664-expected.txt | 6 + .../inspector/regress/regress-575321664.js | 56 + .../regress/regress-575325461-expected.txt | 21 + .../inspector/regress/regress-575325461.js | 74 + .../regress/regress-575735741-expected.txt | 3 + .../inspector/regress/regress-575735741.js | 66 + .../regress/regress-575737154-expected.txt | 3 + .../inspector/regress/regress-575737154.js | 60 + .../regress/regress-575762332-expected.txt | 25 + .../inspector/regress/regress-575762332.js | 34 + .../regress/regress-575806232-expected.txt | 6 + .../inspector/regress/regress-575806232.js | 45 + .../regress/regress-575834150-expected.txt | 12 + .../inspector/regress/regress-575834150.js | 72 + .../regress/regress-575834938-expected.txt | 6 + .../inspector/regress/regress-575834938.js | 48 + .../regress/regress-575835333-expected.txt | 6 + .../inspector/regress/regress-575835333.js | 37 + .../regress/regress-575838270-expected.txt | 11 + .../inspector/regress/regress-575838270.js | 60 + .../regress/regress-575863785-expected.txt | 47 + .../inspector/regress/regress-575863785.js | 46 + .../regress/regress-575876559-expected.txt | 3 + .../inspector/regress/regress-575876559.js | 86 + .../regress/regress-575876890-expected.txt | 7 + .../inspector/regress/regress-575876890.js | 53 + .../regress/regress-575892969-expected.txt | 11 + .../inspector/regress/regress-575892969.js | 61 + .../regress/regress-575895942-expected.txt | 6 + .../inspector/regress/regress-575895942.js | 48 + .../regress/regress-575910950-expected.txt | 5 + .../inspector/regress/regress-575910950.js | 23 + .../regress/regress-576260517-expected.txt | 7 + .../inspector/regress/regress-576260517.js | 66 + .../regress/regress-576261017-expected.txt | 3 + .../inspector/regress/regress-576261017.js | 53 + .../regress/regress-576534261-expected.txt | 8 + .../inspector/regress/regress-576534261.js | 24 + .../regress/regress-576631304-expected.txt | 6 + .../inspector/regress/regress-576631304.js | 54 + ...ss-console-assert-termination-expected.txt | 3 + .../regress-console-assert-termination.js | 38 + ...le-table-column-getter-throws-expected.txt | 3 + ...ress-console-table-column-getter-throws.js | 42 + .../regress-crbug-383029265-expected.txt | 46 +- .../regress-crbug-568986689-expected.txt | 2 + .../regress/regress-crbug-568986689.js | 164 + .../regress-crbug-570558711-expected.txt | 17 + .../regress/regress-crbug-570558711.js | 18 + .../regress-crbug-571211187-expected.txt | 7 + .../regress/regress-crbug-571211187.js | 80 + .../regress-crbug-571845147-expected.txt | 4 + .../regress/regress-crbug-571845147.js | 117 + .../regress-crbug-571979576-expected.txt | 4 + .../regress/regress-crbug-571979576.js | 118 + .../regress-crbug-571984048-expected.txt | 8 + .../regress/regress-crbug-571984048.js | 38 + .../regress-crbug-572821841-expected.txt | 4 + .../regress/regress-crbug-572821841.js | 142 + ...ector-custom-preview-bypasses-expected.txt | 12 + ...gress-inspector-custom-preview-bypasses.js | 74 + ...-serialization-stack-overflow-expected.txt | 8 + ...ector-deep-serialization-stack-overflow.js | 27 + ...ess-nested-stack-switch-catch-expected.txt | 38 + .../regress-nested-stack-switch-catch.js | 77 + ...ss-proxy-has-command-line-api-expected.txt | 24 + .../regress-proxy-has-command-line-api.js | 35 + ...nate-on-resume-double-install-expected.txt | 2 + ...ress-terminate-on-resume-double-install.js | 23 + .../runtime/console-context-expected.txt | 13 + .../test/inspector/runtime/console-context.js | 22 + ...sole-label-conversion-failure-expected.txt | 21 + .../console-label-conversion-failure.js | 80 + .../custom-preview-body-too-long-expected.txt | 5 + .../runtime/custom-preview-body-too-long.js | 51 + ...om-preview-long-error-message-expected.txt | 2 + .../custom-preview-long-error-message.js | 32 + .../deep-serialization-errors-expected.txt | 21 + .../runtime/deep-serialization-errors.js | 3 + ...private-class-member-conflict-expected.txt | 34 + ...evaluate-private-class-member-expected.txt | 38 + ...e-private-class-member-static-expected.txt | 38 + ...-throw-on-side-effect-preview-expected.txt | 9 + .../evaluate-throw-on-side-effect-preview.js | 63 + ...ow-on-side-effect-wrap-result-expected.txt | 40 + ...aluate-throw-on-side-effect-wrap-result.js | 288 + ...evaluate-without-side-effects-expected.txt | 9 + .../runtime/evaluate-without-side-effects.js | 5 + .../runtime/get-heap-usage-expected.txt | 8 + .../test/inspector/runtime/get-heap-usage.js | 7 + .../runtime/get-isolate-id-expected.txt | 8 + .../test/inspector/runtime/get-isolate-id.js | 7 + ...t-defer-exception-stack-trace-expected.txt | 325 ++ .../import-defer-exception-stack-trace.js | 87 + ...fer-side-effect-free-evaluate-expected.txt | 25 + ...fect-free-evaluate-with-scope-expected.txt | 12 + ...er-side-effect-free-evaluate-with-scope.js | 67 + .../import-defer-side-effect-free-evaluate.js | 99 + .../runtime/internal-entry-cycle-expected.txt | 13 + .../inspector/runtime/internal-entry-cycle.js | 59 + ...olate-id-leaked-via-object-id-expected.txt | 4 + .../isolate-id-leaked-via-object-id.js | 43 + .../private-methods-description-expected.txt | 26 + .../runtime/private-methods-description.js | 44 + .../runtime/regression-736302-expected.txt | 26 +- .../inspector/runtime/regression-736302.js | 19 +- .../runtime/remote-object-expected.txt | 6 + .../test/inspector/runtime/remote-object.js | 4 + .../shutdown-pending-evaluate-expected.txt | 1 + .../runtime/shutdown-pending-evaluate.js | 13 + deps/v8/test/intl/regexp-case-equivalence.js | 63 +- deps/v8/test/intl/regress-110086.js | 13 + deps/v8/test/memory/Memory.json | 30 +- .../message/fail/bundle-duplicate-module.js | 14 + .../message/fail/bundle-duplicate-module.out | 1 + .../wasm-compilation-hints-inlining.js | 2 +- .../array-index-undefined-optimized.js | 56 + ...rray-literal-transitions-no-pretenuring.js | 246 + .../baseline/embedded-feedback-monotonic.js | 39 + .../call-lhs-web-compat-early-errors.js | 10 + deps/v8/test/mjsunit/code-cache-sha256.js | 11 + .../mjsunit/compiler/regress-531297707.js | 44 - .../test/mjsunit/d8/d8-flag-normalization.js | 9 + .../d8-inspector-shutdown-pending-evaluate.js | 16 - .../mjsunit/d8/d8-module-tree-rollback.js | 31 + .../mjsunit/d8/d8-realm-shared-templates.js | 44 + .../mjsunit/d8/d8-test-fast-api-realms.js | 59 + .../test/mjsunit/d8/flush-denormals-flag.js | 8 - .../test/mjsunit/d8/flush-denormals-helper.js | 10 - .../test/mjsunit/d8/flush-denormals-worker.js | 43 - deps/v8/test/mjsunit/d8/regress-564550564.js | 28 + deps/v8/test/mjsunit/debug-osr-debug-break.js | 44 - .../mjsunit/debug-osr-step-in-blackboxed.js | 64 - .../debug-osr-step-on-throw-blackboxed.js | 62 - .../test/mjsunit/debug-osr-step-on-throw.js | 58 - deps/v8/test/mjsunit/debug-osr-step-out.js | 52 - .../destructuring-default-maybe-assigned.js | 108 + .../disable-eager-inlining-no-non-eager.js | 67 + .../v8/test/mjsunit/disable-eager-inlining.js | 63 + .../mjsunit/es6/classes-subclass-builtins.js | 14 +- ...gress-analyze-partially-arrow-head-lazy.js | 53 + .../es6/regress-arrow-cover-grammar-scope.js | 38 + .../regress-arrow-head-pattern-error-order.js | 61 + .../es6/regress-arrow-reparse-strict-param.js | 24 + .../regress-class-member-init-reparse-eos.js | 102 + ...regress-class-member-init-reparse-super.js | 128 + ...ess-comma-expression-arrow-initializers.js | 15 + ...ess-conditional-chain-non-short-circuit.js | 34 + .../regress-dynamic-local-param-hole-check.js | 70 + .../regress-escaped-contextual-keywords.js | 72 + ...egress-eval-var-arguments-default-param.js | 107 + .../es6/regress-for-of-async-property.js | 36 + ...regress-invalid-lhs-validate-expression.js | 35 + ...egress-member-template-expression-scope.js | 39 + ...regress-object-rest-property-validation.js | 40 + ...egress-preparser-optional-chain-private.js | 26 + ...reparser-validate-formals-on-body-error.js | 28 + .../regress-private-name-heritage-recalc.js | 90 + .../es6/regress-rewriter-completion-values.js | 31 + .../regress-static-field-await-identifier.js | 56 + ...ss-strict-eval-destructuring-subpattern.js | 34 + .../es6/regress-strict-octal-after-rbrace.js | 57 + .../es6/regress-strict-param-error-order.js | 32 + .../regress-subpattern-validate-expression.js | 44 + .../es6/regress-super-optional-chain.js | 18 + .../es6/regress-yield-expression-scope.js | 19 + .../es8/regress-async-arrow-scope-and-new.js | 70 + ...lazy-arrow-formal-params-function-state.js | 67 + .../modules-import-defer-stack-trace.js | 171 + .../modules-import-defer-terminate.mjs | 15 + .../mjsunit/harmony/modules-using-export.mjs | 97 + .../harmony/optional-chaining-this-private.js | 12 + ...p-unicode-sets-class-string-disjunction.js | 94 + .../harmony/regress-auto-accessor-tostring.js | 69 + ...ass-reparse-no-lazy-and-brand-check-pos.js | 70 + .../regress-for-using-closure-assignment.js | 72 + ...egress-private-name-heritage-catch-eval.js | 131 + .../harmony/regress/regress-511329274.js | 43 +- .../harmony/regress/regress-520728938.js | 16 - .../mjsunit/harmony/shadowrealm-evaluate.js | 2 +- deps/v8/test/mjsunit/iterable-foreach.js | 101 + .../mjsunit/loadic-transition-elements.js | 104 + .../regress/regress-571759664.js | 33 + .../branch-if-int32-bitwise-and-nonzero.js | 66 + .../maglev/create-closure-top-level.js | 31 + .../define-const-data-field-spread-literal.js | 81 - .../mjsunit/maglev/int32-div-const-fold.js | 162 + .../mjsunit/maglev/new-closure-tenured.js | 23 - .../maglev/read-only-constant-compare.js | 55 + .../test/mjsunit/maglev/regress-563882510.js | 49 + .../test/mjsunit/maglev/regress-569212098.js | 13 + .../mjsunit/maglev/regress-569376794-1.js | 34 + .../mjsunit/maglev/regress-569376794-2.js | 16 + .../test/mjsunit/maglev/regress-569947577.js | 24 + .../test/mjsunit/maglev/regress-570091260.js | 50 + .../test/mjsunit/maglev/regress-573856023.js | 38 + .../test/mjsunit/maglev/regress-574021176.js | 44 + .../test/mjsunit/maglev/regress-574412712.js | 47 + .../test/mjsunit/maglev/regress-577954376.js | 19 + .../maglev/script-context-specialization.js | 466 ++ .../spread-rest-parameter-element-mutation.js | 103 + .../test/mjsunit/math-sum-precise/closing.js | 44 +- .../iterator-clear-on-error.js | 24 - .../iterator-not-exhausted-on-error.js | 50 + .../regress-sumPrecise-iterator.js | 34 + .../set-iterator-clear-on-error.js | 26 - .../set-iterator-not-exhausted-on-error.js | 27 + .../uncaught-error-message.js | 78 + deps/v8/test/mjsunit/mjsunit.js | 20 +- deps/v8/test/mjsunit/mjsunit.status | 236 +- .../mjsunit/parser/array-literal-fast-path.js | 89 + .../mjsunit/regexp-boyer-moore-backtrack.js | 9 + deps/v8/test/mjsunit/regexp-unicode-sets.js | 27 + deps/v8/test/mjsunit/regexp/drain.js | 17 + .../regress/fast-proxy-load-ic-bailouts.js | 18 +- .../v8/test/mjsunit/regress/regress-108296.js | 2 +- .../test/mjsunit/regress/regress-1494681.js | 2 +- .../test/mjsunit/regress/regress-440528038.js | 7 - .../test/mjsunit/regress/regress-461969023.js | 2 +- .../test/mjsunit/regress/regress-498904299.js | 2 +- .../test/mjsunit/regress/regress-505481956.js | 8 +- .../test/mjsunit/regress/regress-514561070.js | 14 - .../test/mjsunit/regress/regress-516022777.js | 16 - .../test/mjsunit/regress/regress-521520188.js | 44 + .../test/mjsunit/regress/regress-523431532.js | 34 + .../test/mjsunit/regress/regress-532288251.js | 60 - .../test/mjsunit/regress/regress-532720981.js | 20 - .../test/mjsunit/regress/regress-533311268.js | 3 +- .../test/mjsunit/regress/regress-535071448.js | 259 + .../test/mjsunit/regress/regress-539212794.js | 1 + .../test/mjsunit/regress/regress-544787343.js | 25 + .../test/mjsunit/regress/regress-546370272.js | 20 + .../test/mjsunit/regress/regress-557076207.js | 25 + .../test/mjsunit/regress/regress-561116894.js | 16 + .../test/mjsunit/regress/regress-561672123.js | 48 + .../mjsunit/regress/regress-561799397.mjs | 55 + .../test/mjsunit/regress/regress-564012076.js | 40 + .../test/mjsunit/regress/regress-564879562.js | 75 + .../mjsunit/regress/regress-564880275-2.js | 42 + .../mjsunit/regress/regress-564880275-3.js | 72 + .../mjsunit/regress/regress-564880275-4.js | 65 + .../mjsunit/regress/regress-564880275-5.js | 10 + .../mjsunit/regress/regress-564880275-6.js | 51 + .../mjsunit/regress/regress-564880275-7.js | 45 + .../mjsunit/regress/regress-564880275-8.js | 49 + .../test/mjsunit/regress/regress-564880275.js | 28 + .../test/mjsunit/regress/regress-566415771.js | 23 + .../mjsunit/regress/regress-567222737-2.js | 42 + .../mjsunit/regress/regress-567222737-3.js | 37 + .../mjsunit/regress/regress-567222737-4.js | 21 + .../mjsunit/regress/regress-567222737-5.js | 30 + .../mjsunit/regress/regress-567222737-6.js | 59 + .../test/mjsunit/regress/regress-567222737.js | 52 + .../test/mjsunit/regress/regress-567574900.js | 19 + .../test/mjsunit/regress/regress-567576220.js | 49 + .../test/mjsunit/regress/regress-567827593.js | 26 + .../test/mjsunit/regress/regress-568341998.js | 10 + .../test/mjsunit/regress/regress-568633429.js | 25 + .../test/mjsunit/regress/regress-568654095.js | 11 + .../test/mjsunit/regress/regress-568794851.js | 132 + .../mjsunit/regress/regress-568893995-1.js | 29 + .../mjsunit/regress/regress-568893995-2.js | 27 + .../mjsunit/regress/regress-568893995-3.js | 28 + .../test/mjsunit/regress/regress-569056575.js | 44 + .../test/mjsunit/regress/regress-571397035.js | 93 + .../regress/regress-571565364-empty.txt | 0 .../test/mjsunit/regress/regress-571565364.js | 8 + .../test/mjsunit/regress/regress-571811885.js | 19 + .../test/mjsunit/regress/regress-571853016.js | 43 + .../test/mjsunit/regress/regress-571871980.js | 45 + .../test/mjsunit/regress/regress-571944332.js | 45 + .../test/mjsunit/regress/regress-571975489.js | 21 + .../test/mjsunit/regress/regress-572400584.js | 80 + .../test/mjsunit/regress/regress-572988453.js | 34 + .../test/mjsunit/regress/regress-573037572.js | 118 + .../test/mjsunit/regress/regress-573038326.js | 50 + .../test/mjsunit/regress/regress-573048357.js | 72 + .../test/mjsunit/regress/regress-573048572.js | 9 + .../test/mjsunit/regress/regress-573263262.js | 17 + .../test/mjsunit/regress/regress-573471186.js | 80 + .../test/mjsunit/regress/regress-573777594.js | 8 + .../test/mjsunit/regress/regress-573962535.js | 44 + .../test/mjsunit/regress/regress-574038247.js | 68 + .../test/mjsunit/regress/regress-575750485.js | 34 + .../test/mjsunit/regress/regress-575820656.js | 48 + .../test/mjsunit/regress/regress-576225189.js | 37 + .../regress/regress-crbug-540324230.js | 28 + .../regress/regress-crbug-572331419.js | 37 + .../mjsunit/regress/regress-crbug-917076.js | 2 +- ...egress-declare-arguments-maybe-assigned.js | 51 + .../regress-fast-proxy-deprecated-map.js | 79 + .../regress/regress-fast-proxy-keyed-miss.js | 189 + .../regress-fast-proxy-target-toctou.js | 331 ++ .../regress/regress-homomorphic-maglev.js | 4 + .../regress/regress-homomorphic-turbofan.js | 4 + .../regress-homomorphic-unoptimized.js | 5 +- .../regress-memory-pool-release-task.js | 24 + .../regress-preparser-eval-default-params.js | 30 + .../mjsunit/regress/wasm/regress-1189454.js | 1590 +++++- .../mjsunit/regress/wasm/regress-12866.js | 5 +- .../mjsunit/regress/wasm/regress-355493919.js | 5 +- .../mjsunit/regress/wasm/regress-358393368.js | 91 +- .../mjsunit/regress/wasm/regress-399402814.js | 5 +- .../mjsunit/regress/wasm/regress-449010912.js | 2 +- .../mjsunit/regress/wasm/regress-502287689.js | 107 - .../mjsunit/regress/wasm/regress-502300817.js | 122 +- .../mjsunit/regress/wasm/regress-513413942.js | 71 - .../mjsunit/regress/wasm/regress-519715438.js | 62 - .../mjsunit/regress/wasm/regress-526163463.js | 39 - .../mjsunit/regress/wasm/regress-527985808.js | 41 - .../mjsunit/regress/wasm/regress-531302064.js | 9 +- .../mjsunit/regress/wasm/regress-533578412.js | 32 + .../mjsunit/regress/wasm/regress-563068683.js | 22 + .../mjsunit/regress/wasm/regress-565341967.js | 36 + .../mjsunit/regress/wasm/regress-565847635.js | 72 +- .../mjsunit/regress/wasm/regress-566359200.js | 65 + .../mjsunit/regress/wasm/regress-566727937.js | 21 + .../mjsunit/regress/wasm/regress-567126756.js | 13 + .../mjsunit/regress/wasm/regress-567171844.js | 153 + .../mjsunit/regress/wasm/regress-567481597.js | 25 + .../mjsunit/regress/wasm/regress-567624365.js | 22 + .../mjsunit/regress/wasm/regress-567911985.js | 77 + .../mjsunit/regress/wasm/regress-568629618.js | 84 + .../mjsunit/regress/wasm/regress-568806936.js | 36 + .../mjsunit/regress/wasm/regress-569071532.js | 36 + .../mjsunit/regress/wasm/regress-570433240.js | 72 + .../mjsunit/regress/wasm/regress-570433264.js | 80 + .../mjsunit/regress/wasm/regress-571155505.js | 7 + .../mjsunit/regress/wasm/regress-571348848.js | 46 + .../mjsunit/regress/wasm/regress-571700025.js | 40 + .../mjsunit/regress/wasm/regress-571812798.js | 43 + .../mjsunit/regress/wasm/regress-572399938.js | 48 + .../mjsunit/regress/wasm/regress-572627851.js | 46 + .../mjsunit/regress/wasm/regress-573042748.js | 75 + .../mjsunit/regress/wasm/regress-573260377.js | 55 + .../mjsunit/regress/wasm/regress-573446890.js | 20 + .../mjsunit/regress/wasm/regress-573498301.js | 45 + .../mjsunit/regress/wasm/regress-573612775.js | 34 + .../mjsunit/regress/wasm/regress-573816513.js | 59 + .../mjsunit/regress/wasm/regress-573866983.js | 156 + .../mjsunit/regress/wasm/regress-573974793.js | 138 + .../mjsunit/regress/wasm/regress-574223268.js | 10 +- .../mjsunit/regress/wasm/regress-574681855.js | 94 + .../mjsunit/regress/wasm/regress-574704749.js | 63 + .../mjsunit/regress/wasm/regress-574824670.js | 30 + .../mjsunit/regress/wasm/regress-575514140.js | 71 + .../mjsunit/regress/wasm/regress-575829159.js | 19 + .../mjsunit/regress/wasm/regress-575926503.js | 30 + .../mjsunit/regress/wasm/regress-576112595.js | 64 + .../mjsunit/regress/wasm/regress-577305505.js | 120 + .../mjsunit/regress/wasm/regress-670683.js | 44 +- .../mjsunit/regress/wasm/regress-734108.js | 44 +- .../regress/wasm/regress-crbug-1340488.js | 93 +- .../regress-drumbrake-array-segment-args.js | 94 + .../wasm/regress-drumbrake-cast-nofunc.js | 38 + .../wasm/regress-drumbrake-exception-null.js | 133 + .../regress/wasm/regress-drumbrake-exnref.js | 21 + .../wasm/regress-drumbrake-import-context.js | 41 + .../wasm/regress-drumbrake-import-null.js | 122 + .../regress-drumbrake-return-call-subtype.js | 38 + .../regress-drumbrake-v128-js-boundary.js | 52 + .../regress/wasm/regress-simd-570497964.js | 155 + .../regress/wasm/regress-simd-573671130.js | 49 + .../regress/wasm/regress-simd-573671231.js | 101 + .../mjsunit/regress/wasm/regress-v8-9106.js | 103 +- .../sandbox/fixed-double-array-field-count.js | 38 + .../test/mjsunit/sandbox/regress-443772809.js | 64 +- .../test/mjsunit/sandbox/regress-524290062.js | 45 +- .../test/mjsunit/sandbox/regress-558640961.js | 101 + .../test/mjsunit/sandbox/regress-560980980.js | 52 + .../test/mjsunit/sandbox/regress-561387542.js | 32 +- .../test/mjsunit/sandbox/regress-564835629.js | 16 + .../test/mjsunit/sandbox/regress-564835816.js | 21 + .../test/mjsunit/sandbox/regress-566142291.js | 75 + .../test/mjsunit/sandbox/regress-567222739.js | 37 + .../test/mjsunit/sandbox/regress-569548220.js | 21 + .../test/mjsunit/sandbox/regress-571126471.js | 69 + .../test/mjsunit/sandbox/regress-571127829.js | 125 + .../regress/regress-435630464-disabled.js | 8 +- .../sandbox/regress/regress-462217236.js | 64 +- .../sandbox/regress/regress-502337304.js | 76 - .../sandbox/regress/regress-502997649.js | 33 +- .../sandbox/regress/regress-514163419.js | 9 +- .../sandbox/regress/regress-543557673.js | 213 +- .../sandbox/regress/regress-555304822.js | 110 + .../sandbox/regress/regress-560536734.js | 78 + .../sandbox/regress/regress-567526351.js | 50 + .../sandbox/regress/regress-572826713.js | 89 + .../sandbox/regress/regress-574792351.js | 55 + ...asm-interpreter-reentrant-throw-overlap.js | 180 + .../sandbox/wasm-suspender-stack-reference.js | 95 + .../test/mjsunit/sandbox/wasmfx-jspi-uaf.js | 69 + .../mjsunit/shared-memory/brand-checks.js | 34 +- .../cannot-redefine-properties.js | 2 - .../test/mjsunit/shared-memory/client-gc.js | 2 +- .../shared-memory/condition-workers.js | 43 - .../test/mjsunit/shared-memory/condition.js | 43 - .../mjsunit/shared-memory/mutex-lock-twice.js | 19 - .../mjsunit/shared-memory/mutex-workers.js | 175 - deps/v8/test/mjsunit/shared-memory/mutex.js | 76 - .../shared-memory/optimize-non-instance.js | 14 - .../mjsunit/shared-memory/private-brand.js | 2 - .../mjsunit/shared-memory/private-field.js | 2 - .../mjsunit/shared-memory/private-name.js | 2 - .../shared-memory/regress-524783017.js | 30 - .../shared-memory/regress-crbug-1441241.js | 2 +- .../shared-memory/regress-crbug-1449611.js | 13 - .../shared-memory/regress-crbug-333007256.js | 27 - .../regress/regress-528397177.js | 2 +- .../shared-object-has-instance.js | 24 - .../shared-string-in-code-object.js | 4 +- .../shared-string-in-weak-map.js | 4 +- .../string-index-undefined-optimized.js | 79 + .../test/mjsunit/transition-elements-kind.js | 2 +- .../test/mjsunit/turbolev/convert-receiver.js | 4 + .../turbolev/create-closure-top-level.js | 31 + .../escape-analysis-regress-561781465.js | 27 + ...ape-analysis-regress-564543692-array-at.js | 25 + .../escape-analysis-regress-564543692.js | 25 + .../for-in-enumerator-holder-holey.js | 180 + .../turbolev/for-in-enumerator-holder.js | 294 + .../loop-in-maglev-but-not-turboshaft.js | 27 + .../mjsunit/turbolev/new-closure-tenured.js | 23 - .../mjsunit/turbolev/regress-505610970.js | 3 +- .../mjsunit/turbolev/regress-564329221.js | 22 + .../mjsunit/turbolev/regress-567993838.js | 32 + .../mjsunit/turbolev/regress-568010379.js | 48 + .../mjsunit/turbolev/regress-571002038.js | 65 + .../turbolev/regress-forin-type-confusion.js | 44 + .../turbolev/store-const-heap-number.js | 21 + .../turboshaft/couldhavesamemap-poly-poly.js | 49 + .../turboshaft/reduce-strictly-less-than.js | 35 + .../mjsunit/turboshaft/regress-574660146.js | 41 + .../compilation-hints/hints-and-deopts.js | 181 + .../wasm/compiled-module-serialization.js | 10 + .../wasm/custom-descriptors-validity.js | 12 + .../wasm/debug-set-breakpoint-on-entry.js | 34 - deps/v8/test/mjsunit/wasm/denormals.js | 34 - .../mjsunit/wasm/esm/module-import-source.mjs | 12 + deps/v8/test/mjsunit/wasm/gc-casts-branch.js | 223 + .../test/mjsunit/wasm/growable-stacks-simd.js | 155 + deps/v8/test/mjsunit/wasm/growable-stacks.js | 264 +- .../v8/test/mjsunit/wasm/imported-dataview.js | 90 +- deps/v8/test/mjsunit/wasm/instance-gc.js | 4 +- .../mjsunit/wasm/instantiate-module-basic.js | 16 +- deps/v8/test/mjsunit/wasm/lazy-compilation.js | 24 +- deps/v8/test/mjsunit/wasm/load-shift32.js | 9 +- .../v8/test/mjsunit/wasm/reference-globals.js | 22 + .../v8/test/mjsunit/wasm/regress-534579660.js | 93 - .../test/mjsunit/wasm/regress-535877252-2.js | 92 + .../v8/test/mjsunit/wasm/regress-535877252.js | 92 + .../v8/test/mjsunit/wasm/regress-569014241.js | 107 + .../v8/test/mjsunit/wasm/regress-576453351.js | 99 + .../wasm/regress-nested-stack-switch-catch.js | 75 - .../test/mjsunit/wasm/regression-521715545.js | 53 - .../gc-casts-subtypes-shared.js | 19 +- .../wasm/shared-everything/wait-queue.js | 25 + .../shared-everything/wrapper-type-checks.js | 80 +- .../wasm/shared-memory-grow-bounds-check.js | 67 + .../mjsunit/wasm/shared-memory-size-atomic.js | 88 + .../mjsunit/wasm/simd-add-sub-high-narrow.js | 93 + .../mjsunit/wasm/simd-i64x2-mul-mixed-sign.js | 74 + .../mjsunit/wasm/simd-narrow-interleave.js | 259 + .../mjsunit/wasm/simd-replace-lane-zero.js | 32 +- .../test/mjsunit/wasm/simd-shift-left-long.js | 100 + .../mjsunit/wasm/stack-switching-profiler.js | 55 + deps/v8/test/mjsunit/wasm/stack-switching.js | 19 + .../wasm/test-growable-tail-call-matrix.js | 248 + .../test-growable-tail-call-stack-params.js | 99 + deps/v8/test/test262/test262.status | 156 +- deps/v8/test/torque/test-torque.tq | 24 + deps/v8/test/unittests/BUILD.gn | 58 +- .../v8/test/unittests/api/api-icu-unittest.cc | 28 + .../test/unittests/api/api-wasm-unittest.cc | 154 +- .../unittests/api/deserialize-unittest.cc | 210 + .../api/dictionary-template-unittest.cc | 2 - .../unittests/api/interceptor-unittest.cc | 64 + .../unittests/api/v8-array-buffer-unittest.cc | 14 + .../test/unittests/api/v8-object-unittest.cc | 397 ++ .../test/unittests/api/v8-script-unittest.cc | 334 ++ .../test/unittests/api/v8-value-unittest.cc | 26 + .../assembler/assembler-arm64-unittest.cc | 131 + .../assembler/assembler-riscv64-unittest.cc | 135 + .../assembler/assembler-x64-unittest.cc | 211 + .../assembler/disasm-arm-unittest.cc | 5 +- .../assembler/disasm-arm64-unittest.cc | 38 + .../assembler/disasm-loong64-unittest.cc | 8 +- .../assembler/disasm-mips64-unittest.cc | 8 +- .../assembler/disasm-ppc-unittest.cc | 8 +- .../assembler/disasm-riscv-unittest.cc | 8 +- .../assembler/disasm-s390-unittest.cc | 8 +- .../assembler/disasm-x64-unittest.cc | 200 +- .../macro-assembler-arm64-unittest.cc | 70 + .../unittests/assembler/test-helper-riscv32.h | 2 +- .../unittests/assembler/test-helper-riscv64.h | 2 +- .../v8/test/unittests/base/bignum-unittest.cc | 4 +- deps/v8/test/unittests/base/bits-unittest.cc | 43 - .../base/growing-circular-queue-unittest.cc | 187 + .../test/unittests/base/hashing-unittest.cc | 54 + .../unittests/base/platform/mutex-unittest.cc | 10 + .../unittests/base/small-vector-unittest.cc | 1 + .../unittests/base/unique-array-unittest.cc | 92 + .../v8/test/unittests/base/vector-unittest.cc | 170 +- .../aligned-slot-allocator-unittest.cc | 6 +- .../codegen/safepoint-table-unittest.cc | 10 +- .../common/thread-isolation-unittest.cc | 57 + ...shaft-instruction-selector-arm-unittest.cc | 52 +- ...aft-instruction-selector-arm64-unittest.cc | 508 +- .../backend/instruction-selector-unittest.cc | 3 +- .../backend/instruction-selector-unittest.h | 2 +- ...urboshaft-instruction-selector-unittest.cc | 14 +- ...turboshaft-instruction-selector-unittest.h | 11 +- .../compiler/bytecode-analysis-unittest.cc | 35 + .../test/unittests/compiler/codegen-tester.h | 2 +- .../unittests/compiler/compiler-unittest.cc | 30 +- ...haft-instruction-selector-ia32-unittest.cc | 28 +- .../unittests/compiler/linkage-unittest.cc | 12 +- .../unittests/compiler/node-test-utils.cc | 2 - .../regalloc/register-allocator-unittest.cc | 4 +- .../run-bytecode-graph-builder-unittest.cc | 486 +- .../compiler/run-variables-unittest.cc | 8 +- .../compiler/simplified-lowering-unittest.cc | 2 +- ...plication-optimization-reducer-unittest.cc | 254 + ...election-normalization-reducer-unittest.cc | 200 +- .../machine-optimization-reducer-unittest.cc | 236 + .../compiler/turboshaft/reducer-test.h | 8 +- .../turboshaft/turboshaft-typer-unittest.cc | 49 + .../turboshaft/turboshaft-types-unittest.cc | 123 + .../wasm-shuffle-reducer-unittest.cc | 110 + .../compiler/turboshaft/wasm-simd-unittest.cc | 7 +- .../wasm-address-reassociation-unittest.cc | 264 - ...shaft-instruction-selector-x64-unittest.cc | 259 + .../debug/debug-property-iterator-unittest.cc | 38 - .../debug/debug-scope-info-unittest.cc | 206 +- .../deoptimizer/deoptimization-unittest.cc | 7 +- .../flags/flag-definitions-unittest.cc | 161 +- .../heap/array-buffer-sweeper-unittest.cc} | 333 +- .../heap/concurrent-allocation-unittest.cc} | 692 ++- .../cpp-heap-stack-start-marker-unittest.cc | 25 + .../unified-heap-snapshot-unittest.cc | 2 +- .../heap/cppgc/allocation-unittest.cc | 243 + .../heap/cppgc/concurrent-marking-unittest.cc | 124 + .../heap/cppgc/stack-start-marker-unittest.cc | 35 + .../unittests/heap/cppgc/stack-unittest.cc | 3 +- .../heap/cppgc/workloads-unittest.cc | 9 +- .../heap/cppgc/write-barrier-unittest.cc | 4 +- .../heap/external-string-tracker-unittest.cc} | 140 +- .../test/unittests/heap/gc-tracer-unittest.cc | 39 + deps/v8/test/unittests/heap/heap-unittest.cc | 3980 ++++++++++++-- deps/v8/test/unittests/heap/heap-utils.cc | 109 +- deps/v8/test/unittests/heap/heap-utils.h | 98 +- .../unittests/heap/local-factory-unittest.cc | 20 +- .../unittests/heap/mark-compact-unittest.cc | 707 +++ .../heap/memory-measurement-unittest.cc | 282 + .../unittests/heap/memory-reducer-unittest.cc | 292 +- deps/v8/test/unittests/heap/pool-unittest.cc | 405 -- .../v8/test/unittests/heap/spaces-unittest.cc | 1413 ++++- .../heap/weak-references-unittest.cc} | 471 +- .../unittests/heap/write-barrier-unittest.cc | 71 +- .../unittests/inspector/inspector-unittest.cc | 235 + .../bytecode-array-builder-unittest.cc | 12 +- .../bytecode-expectations-printer.cc | 8 +- .../bytecode_expectations/BasicLoops.golden | 2 +- .../BreakableBlocks.golden | 4 +- .../CallLookupSlot.golden | 2 +- .../bytecode_expectations/CallNew.golden | 2 +- .../ClassDeclarations.golden | 22 +- .../CompoundExpressions.golden | 2 +- .../ContextParameters.golden | 8 +- .../ContextVariables.golden | 10 +- .../CountOperators.golden | 4 +- .../bytecode_expectations/Delete.golden | 2 +- .../bytecode_expectations/ForOfLoop.golden | 2 +- .../FunctionLiterals.golden | 6 +- .../bytecode_expectations/NewAndSpread.golden | 6 +- .../ObjectLiterals.golden | 40 +- .../PrivateAccessorAccess.golden | 8 +- .../PrivateAccessorDeclaration.golden | 42 +- .../PrivateClassFields.golden | 28 +- .../PrivateMethodAccess.golden | 6 +- .../PrivateMethodDeclaration.golden | 20 +- .../PublicClassFields.golden | 26 +- .../SetPrototypePropertiesOptimization.golden | 2 +- .../StandardForLoop.golden | 2 +- .../StaticClassFields.golden | 36 +- .../StaticPrivateMethodAccess.golden | 30 +- .../StaticPrivateMethodDeclaration.golden | 24 +- .../bytecode_expectations/StringConcat.golden | 2 +- .../TemplateLiterals.golden | 2 +- .../interpreter/bytecodes-unittest.cc | 8 +- .../interpreter/interpreter-unittest.cc | 131 + ...mics-synchronization-primitive-unittest.cc | 292 - .../unittests/libplatform/tracing-unittest.cc | 4 +- .../unittests/libsampler/sampler-unittest.cc | 25 + .../v8/test/unittests/logging/log-unittest.cc | 33 +- .../maglev/maglev-assembler-unittest.cc | 99 + .../maglev/maglev-graph-builder-unittest.cc | 12 +- .../maglev/maglev-graph-processor-unittest.cc | 4 +- .../test/unittests/numbers/strtod-unittest.cc | 34 +- .../unittests/objects/casting-unittest.cc | 215 + .../unittests/objects/managed-unittest.cc | 34 + .../unittests/objects/modules-unittest.cc | 87 + .../test/unittests/objects/object-unittest.cc | 43 +- .../objects/string-table-unittest.cc | 8 +- .../objects/value-serializer-unittest.cc | 48 +- .../objects/weakarraylist-unittest.cc | 13 + .../test/unittests/parser/parsing-unittest.cc | 133 +- .../unittests/parser/preparser-unittest.cc | 69 +- .../test/unittests/parser/scanner-unittest.cc | 42 + .../profiler/heap-snapshot-scopes-unittest.cc | 19 +- .../profiler/heap-snapshot-unittest.cc | 138 + .../v8/test/unittests/regexp/regexp-fuzzer.cc | 2 +- .../test/unittests/regexp/regexp-unittest.cc | 40 +- .../regress/regress-536954139-unittest.cc | 6 +- deps/v8/test/unittests/run-all-unittests.cc | 213 + .../sandbox/bytecode-verifier-unittest.cc | 152 +- .../unittests/sandbox/code-cache-unittest.cc | 296 + .../generated-code-validator-unittest.cc | 432 +- deps/v8/test/unittests/test-utils.h | 9 +- deps/v8/test/unittests/testcfg.py | 13 + .../test/unittests/torque/torque-unittest.cc | 970 ++++ deps/v8/test/unittests/unittests.status | 272 +- .../unittests/utils/bit-vector-unittest.cc | 46 + .../utils/sparse-bit-vector-unittest.cc | 37 + .../v8/test/unittests/utils/utils-unittest.cc | 66 +- .../test/unittests/utils/version-unittest.cc | 14 +- deps/v8/test/{cctest => unittests}/wasm/DEPS | 2 +- .../wasm/backing-store-unittest.cc} | 29 +- .../wasm/basic-block-calculator-unittest.cc | 19 +- .../wasm/c-wasm-entry-unittest.cc} | 17 +- .../wasm/compilation-cache-unittest.cc} | 73 +- .../wasm/compilation-hints-unittest.cc | 2 +- .../wasm/function-body-decoder-unittest.cc | 97 +- .../wasm/fuzzer-steps-unittest.cc} | 9 +- .../wasm/gc-unittest.cc} | 24 +- .../wasm/grow-memory-unittest.cc} | 22 +- .../wasm/jump-table-assembler-unittest.cc} | 48 +- .../wasm/liftoff-for-fuzzing-unittest.cc} | 7 +- .../wasm/liftoff-inspection-unittest.cc} | 35 +- .../wasm/liftoff-register-unittests.cc | 142 +- .../wasm}/manually-externalized-buffer.h | 10 +- .../wasm/memory-protection-unittest.cc | 8 +- .../unittests/wasm/module-decoder-unittest.cc | 7 + .../wasm/run-wasm-64-unittest.cc} | 8 +- .../wasm/run-wasm-atomics-unittest.cc} | 7 +- .../wasm/run-wasm-atomics64-unittest.cc} | 7 +- .../wasm/run-wasm-bulk-memory-unittest.cc} | 14 +- .../wasm/run-wasm-exceptions-unittest.cc} | 43 +- .../unittests/wasm/run-wasm-f16-unittest.cc | 855 +++ .../wasm/run-wasm-js-unittest.cc} | 98 +- .../wasm/run-wasm-memory64-unittest.cc} | 10 +- .../wasm/run-wasm-module-unittest.cc} | 140 +- .../wasm/run-wasm-relaxed-simd-unittest.cc} | 44 +- .../wasm/run-wasm-sign-extension-unittest.cc} | 8 +- .../wasm/run-wasm-simd-liftoff-unittest.cc} | 21 +- .../wasm/run-wasm-simd-unittest.cc} | 578 +- .../wasm/run-wasm-unittest.cc} | 112 +- .../wasm/run-wasm-wrappers-unittest.cc} | 39 +- ...imd-cross-compiler-determinism-fuzztest.cc | 219 + .../wasm/streaming-compilation-unittest.cc} | 252 +- .../wasm/streaming-decoder-unittest.cc | 9 +- .../unittests/wasm/struct-types-unittest.cc | 17 +- .../test/unittests/wasm/subtyping-unittest.cc | 7 +- .../wasm/type-canonicalization-fuzztest.cc | 486 +- .../wasm/wasm-atomics-utils.h | 9 +- .../wasm/wasm-breakpoints-unittest.cc} | 102 +- .../wasm/wasm-codegen-unittest.cc} | 20 +- .../test/unittests/wasm/wasm-compile-module.h | 5 +- .../wasm-import-wrapper-cache-unittest.cc} | 23 +- .../wasm/wasm-metrics-unittest.cc} | 155 +- deps/v8/test/unittests/wasm/wasm-runner.h | 149 + .../wasm/wasm-serialization-unittest.cc} | 306 +- .../wasm/wasm-shared-engine-unittest.cc} | 97 +- .../wasm/wasm-simd-utils.cc | 4 +- .../wasm/wasm-simd-utils.h | 10 +- .../wasm/wasm-stack-unittest.cc} | 16 +- .../wasm/wasm-strings-unittest.cc} | 6 +- .../unittests/wasm/wasm-tracing-unittest.cc | 2 +- .../wasm/wasm-trap-position-unittest.cc} | 12 +- .../test/unittests/wasm/wasm-usecounters.cc | 6 +- .../zone/zone-chunk-list-unittest.cc | 436 -- deps/v8/test/wasm-api-tests/callbacks.cc | 29 +- deps/v8/test/wasm-api-tests/finalize.cc | 8 +- deps/v8/test/wasm-api-tests/globals.cc | 68 +- deps/v8/test/wasm-api-tests/hostref.cc | 26 +- deps/v8/test/wasm-api-tests/memory.cc | 10 +- deps/v8/test/wasm-api-tests/multi-return.cc | 4 +- deps/v8/test/wasm-api-tests/reflect.cc | 9 +- deps/v8/test/wasm-api-tests/regressions.cc | 2 +- deps/v8/test/wasm-api-tests/serialize.cc | 8 +- deps/v8/test/wasm-api-tests/startup-errors.cc | 2 +- deps/v8/test/wasm-api-tests/table.cc | 11 +- deps/v8/test/wasm-api-tests/threads.cc | 9 +- deps/v8/test/wasm-api-tests/traps.cc | 11 +- deps/v8/test/wasm-api-tests/wasm-api-test.h | 2 +- deps/v8/testing/gtest-support.h | 1 - deps/v8/third_party/abseil-cpp/.bazelrc | 122 + deps/v8/third_party/abseil-cpp/BUILD.gn | 31 +- .../abseil-cpp/CMake/AbseilDll.cmake | 263 +- .../abseil-cpp/CMake/AbseilHelpers.cmake | 52 +- .../CMake/install_test_project/test.sh | 17 +- deps/v8/third_party/abseil-cpp/MODULE.bazel | 6 + .../v8/third_party/abseil-cpp/README.chromium | 2 +- .../third_party/abseil-cpp/absl/BUILD.bazel | 12 + .../abseil-cpp/absl/algorithm/container.h | 16 +- .../absl/algorithm/container_test.cc | 30 + .../abseil-cpp/absl/base/BUILD.bazel | 5 + .../third_party/abseil-cpp/absl/base/BUILD.gn | 1 + .../abseil-cpp/absl/base/CMakeLists.txt | 3 + .../abseil-cpp/absl/base/attributes.h | 167 +- .../abseil-cpp/absl/base/attributes_test.cc | 52 +- .../third_party/abseil-cpp/absl/base/config.h | 15 +- .../absl/base/dynamic_annotations.h | 2 - .../base/exception_safety_testing_test.cc | 2 +- .../absl/base/internal/cpu_detect.cc | 8 + .../absl/base/internal/cpu_detect.h | 4 + .../base/internal/exception_safety_testing.h | 27 +- .../base/internal/low_level_alloc_test.cc | 2 +- .../absl/base/internal/raw_logging.cc | 15 +- .../absl/base/internal/raw_logging.h | 3 +- .../abseil-cpp/absl/base/internal/spinlock.cc | 10 +- .../abseil-cpp/absl/base/internal/spinlock.h | 4 +- .../abseil-cpp/absl/base/internal/sysinfo.cc | 10 + .../absl/base/internal/thread_identity.h | 9 +- .../abseil-cpp/absl/base/raw_logging_test.cc | 50 +- .../abseil-cpp/absl/base/thread_annotations.h | 4 +- .../abseil-cpp/absl/container/BUILD.bazel | 33 +- .../abseil-cpp/absl/container/BUILD.gn | 15 + .../abseil-cpp/absl/container/CMakeLists.txt | 31 +- .../absl/container/btree_instantiate_test.cc | 731 +++ .../abseil-cpp/absl/container/btree_test.cc | 683 +-- .../abseil-cpp/absl/container/chunked_queue.h | 132 +- .../absl/container/chunked_queue_benchmark.cc | 36 + .../absl/container/chunked_queue_test.cc | 226 +- .../abseil-cpp/absl/container/flat_hash_map.h | 40 +- .../absl/container/flat_hash_set_test.cc | 10 + .../container/internal/container_memory.h | 72 +- .../internal/container_memory_test.cc | 23 +- .../internal/hash_function_defaults.h | 17 + .../internal/hashtable_control_bytes.h | 2 +- .../absl/container/internal/raw_hash_map.h | 82 +- .../absl/container/internal/raw_hash_set.cc | 888 +-- .../absl/container/internal/raw_hash_set.h | 1032 ++-- .../internal/raw_hash_set_allocator_test.cc | 11 + .../container/internal/raw_hash_set_test.cc | 365 +- .../absl/container/linked_hash_map.h | 69 +- .../absl/container/linked_hash_map_test.cc | 131 + .../absl/container/linked_hash_set.h | 52 +- .../absl/container/linked_hash_set_test.cc | 129 + .../abseil-cpp/absl/crc/BUILD.bazel | 3 + .../third_party/abseil-cpp/absl/crc/BUILD.gn | 3 + .../abseil-cpp/absl/crc/CMakeLists.txt | 5 + .../third_party/abseil-cpp/absl/crc/crc32c.cc | 1 - .../abseil-cpp/absl/crc/internal/crc.cc | 23 +- .../abseil-cpp/absl/crc/internal/crc.h | 11 + .../internal/crc32_x86_arm_combined_simd.h | 166 +- .../abseil-cpp/absl/crc/internal/crc_memcpy.h | 10 +- .../absl/crc/internal/crc_memcpy_test.cc | 184 + .../absl/crc/internal/crc_x86_arm_combined.cc | 906 ++-- .../abseil-cpp/absl/debugging/BUILD.bazel | 4 + .../absl/debugging/internal/elf_mem_image.h | 14 +- .../internal/stacktrace_emscripten-inl.inc | 2 +- .../absl/debugging/internal/symbolize.h | 3 +- .../abseil-cpp/absl/debugging/stacktrace.cc | 10 +- .../absl/debugging/stacktrace_test.cc | 4 +- .../absl/debugging/symbolize_elf.inc | 55 +- .../absl/debugging/symbolize_test.cc | 134 +- .../abseil-cpp/absl/flags/BUILD.bazel | 1 + .../abseil-cpp/absl/flags/BUILD.gn | 1 + .../abseil-cpp/absl/flags/CMakeLists.txt | 3 + .../third_party/abseil-cpp/absl/flags/flag.h | 10 + .../abseil-cpp/absl/flags/flag_benchmark.cc | 4 +- .../abseil-cpp/absl/flags/flag_test.cc | 81 +- .../abseil-cpp/absl/flags/reflection.cc | 10 +- .../abseil-cpp/absl/flags/reflection.h | 13 +- .../abseil-cpp/absl/functional/BUILD.bazel | 1 + .../abseil-cpp/absl/functional/BUILD.gn | 1 + .../abseil-cpp/absl/functional/CMakeLists.txt | 1 + .../abseil-cpp/absl/functional/bind_front.h | 55 +- .../absl/functional/bind_front_test.cc | 226 +- .../functional/function_type_benchmark.cc | 2 +- .../absl/functional/internal/front_binder.h | 29 + .../abseil-cpp/absl/hash/BUILD.bazel | 4 +- .../third_party/abseil-cpp/absl/hash/BUILD.gn | 3 +- .../abseil-cpp/absl/hash/CMakeLists.txt | 5 +- .../third_party/abseil-cpp/absl/hash/hash.h | 2 +- .../abseil-cpp/absl/hash/hash_test.cc | 90 +- .../abseil-cpp/absl/hash/internal/hash.cc | 33 +- .../abseil-cpp/absl/hash/internal/hash.h | 141 +- .../abseil-cpp/absl/log/BUILD.bazel | 2 + .../abseil-cpp/absl/log/CMakeLists.txt | 4 + .../abseil-cpp/absl/log/check_test_impl.inc | 2 +- .../abseil-cpp/absl/log/internal/check_op.h | 13 +- .../absl/log/internal/log_message.cc | 12 +- .../absl/log/internal/log_message.h | 59 +- .../abseil-cpp/absl/numeric/int128.cc | 2 +- .../absl/profiling/internal/sample_recorder.h | 36 +- .../abseil-cpp/absl/random/BUILD.bazel | 3 + .../abseil-cpp/absl/random/CMakeLists.txt | 7 + .../absl/random/internal/BUILD.bazel | 2 + .../abseil-cpp/absl/random/internal/BUILD.gn | 1 + .../absl/random/internal/nanobenchmark.cc | 13 +- .../absl/random/internal/randen_detect.cc | 4 +- .../absl/random/internal/randen_hwaes.cc | 47 +- .../absl/random/internal/randen_slow.cc | 38 +- .../random/log_uniform_int_distribution.h | 25 +- .../log_uniform_int_distribution_test.cc | 20 + .../absl/status/internal/status_internal.h | 18 +- .../abseil-cpp/absl/status/status.cc | 4 + .../abseil-cpp/absl/status/status_macros.h | 49 +- .../abseil-cpp/absl/status/statusor.h | 4 +- .../absl/status/statusor_benchmark.cc | 12 +- .../abseil-cpp/absl/strings/BUILD.bazel | 7 +- .../abseil-cpp/absl/strings/BUILD.gn | 4 +- .../abseil-cpp/absl/strings/CMakeLists.txt | 8 + .../abseil-cpp/absl/strings/cord.cc | 294 +- .../abseil-cpp/absl/strings/cord.h | 3 +- .../abseil-cpp/absl/strings/cord_test.cc | 486 ++ .../internal/append_and_overwrite_test.cc | 2 +- .../absl/strings/internal/cordz_info.h | 6 +- .../strings/internal/generic_printer_test.cc | 6 +- .../absl/strings/internal/str_format/bind.h | 13 +- .../internal/str_format/convert_test.cc | 41 +- .../internal/str_format/float_conversion.cc | 2 + .../absl/strings/internal/str_join_internal.h | 18 +- .../abseil-cpp/absl/strings/match.h | 3 +- .../abseil-cpp/absl/strings/numbers.cc | 6 +- .../abseil-cpp/absl/strings/str_cat.h | 7 +- .../abseil-cpp/absl/strings/str_join_test.cc | 10 + .../abseil-cpp/absl/strings/str_split.h | 8 +- .../abseil-cpp/absl/strings/str_split_test.cc | 32 + .../abseil-cpp/absl/strings/string_view.h | 1 - .../absl/synchronization/BUILD.bazel | 2 + .../absl/synchronization/CMakeLists.txt | 4 + .../synchronization/internal/graphcycles.cc | 330 +- .../synchronization/internal/graphcycles.h | 6 + .../internal/graphcycles_benchmark.cc | 61 + .../internal/graphcycles_test.cc | 161 + .../abseil-cpp/absl/synchronization/mutex.cc | 215 +- .../abseil-cpp/absl/synchronization/mutex.h | 7 +- .../absl/synchronization/mutex_test.cc | 282 + .../abseil-cpp/absl/time/BUILD.bazel | 1 + .../abseil-cpp/absl/time/CMakeLists.txt | 2 + .../abseil-cpp/absl/time/civil_time.cc | 11 +- .../abseil-cpp/absl/time/civil_time_test.cc | 13 + .../third_party/abseil-cpp/absl/time/clock.cc | 6 +- .../abseil-cpp/absl/time/clock_interface.h | 2 +- .../abseil-cpp/absl/time/duration.cc | 18 +- .../abseil-cpp/absl/time/duration_test.cc | 11 + .../internal/cctz/include/cctz/time_zone.h | 92 +- .../time/internal/cctz/src/cctz_benchmark.cc | 4 +- .../internal/cctz/src/time_zone_format.cc | 13 +- .../cctz/src/time_zone_format_test.cc | 281 +- .../time/internal/cctz/src/time_zone_info.cc | 7 +- .../time/internal/cctz/src/time_zone_libc.cc | 46 +- .../cctz/src/time_zone_lookup_test.cc | 43 +- .../absl/time/internal/cctz/testdata/version | 2 +- .../cctz/testdata/zoneinfo/America/Bogota | Bin 179 -> 179 bytes .../cctz/testdata/zoneinfo/America/Inuvik | Bin 817 -> 1160 bytes .../testdata/zoneinfo/America/Rainy_River | Bin 1294 -> 1637 bytes .../cctz/testdata/zoneinfo/America/Winnipeg | Bin 1294 -> 1637 bytes .../cctz/testdata/zoneinfo/Asia/Tehran | Bin 812 -> 812 bytes .../internal/cctz/testdata/zoneinfo/CST6CDT | Bin 1754 -> 922 bytes .../cctz/testdata/zoneinfo/Canada/Central | Bin 1294 -> 1637 bytes .../internal/cctz/testdata/zoneinfo/EST5EDT | Bin 1744 -> 922 bytes .../time/internal/cctz/testdata/zoneinfo/Eire | Bin 1496 -> 1496 bytes .../cctz/testdata/zoneinfo/Europe/Dublin | Bin 1496 -> 1496 bytes .../time/internal/cctz/testdata/zoneinfo/Iran | Bin 812 -> 812 bytes .../internal/cctz/testdata/zoneinfo/MST7MDT | Bin 1042 -> 922 bytes .../internal/cctz/testdata/zoneinfo/PST8PDT | Bin 1294 -> 922 bytes .../cctz/testdata/zoneinfo/zone1970.tab | 4 +- .../cctz/testdata/zoneinfo/zonenow.tab | 9 +- .../abseil-cpp/convert_bazel_to_gn.py | 33 +- .../patches/0001-Undeprecate-deprecated.patch | 40 + ...ete-static-initializer-in-stacktrace.patch | 8 +- .../0004-string-view-transitive-includes | 13 - deps/v8/third_party/abseil-cpp/roll_abseil.py | 1 + .../abseil-cpp/symbols_arm64_dbg.def | 339 +- .../abseil-cpp/symbols_arm64_dbg_cxx23.def | 339 +- .../abseil-cpp/symbols_arm64_rel.def | 49 +- .../abseil-cpp/symbols_arm64_rel_cxx23.def | 49 +- .../abseil-cpp/symbols_x64_dbg.def | 336 +- .../abseil-cpp/symbols_x64_dbg_cxx23.def | 336 +- .../abseil-cpp/symbols_x64_rel.def | 52 +- .../abseil-cpp/symbols_x64_rel_asan.def | 48 +- .../abseil-cpp/symbols_x64_rel_asan_cxx23.def | 48 +- .../abseil-cpp/symbols_x64_rel_cxx23.def | 52 +- .../abseil-cpp/symbols_x86_dbg.def | 334 +- .../abseil-cpp/symbols_x86_dbg_cxx23.def | 334 +- .../abseil-cpp/symbols_x86_rel.def | 47 +- .../abseil-cpp/symbols_x86_rel_cxx23.def | 48 +- .../src/include/fast_float/ascii_number.h | 56 +- .../include/fast_float/decimal_to_binary.h | 38 +- .../src/include/fast_float/digit_comparison.h | 4 - .../src/include/fast_float/float_common.h | 222 +- .../src/include/fast_float/parse_number.h | 110 +- .../inspector_protocol/crdtp/error_support.cc | 3 +- .../crdtp/json_platform_v8.cc | 8 +- .../llvm-libc/src/hdr/CMakeLists.txt | 39 + .../llvm-libc/src/hdr/poll_macros.h | 27 + .../llvm-libc/src/hdr/poll_overlay.h | 69 + .../llvm-libc/src/hdr/sys_eventfd_macros.h | 27 + .../llvm-libc/src/hdr/sys_inotify_macros.h | 27 + .../llvm-libc/src/hdr/sys_socket_macros.h | 2 +- .../llvm-libc/src/hdr/sys_socket_overlay.h | 69 + .../llvm-libc/src/hdr/sys_xattr_macros.h | 27 + .../llvm-libc/src/hdr/types/CMakeLists.txt | 55 +- .../llvm-libc/src/hdr/types/fpos_t.h | 27 + .../llvm-libc/src/hdr/types/idtype_t.h | 27 + .../llvm-libc/src/hdr/types/nfds_t.h | 2 +- .../llvm-libc/src/hdr/types/sa_family_t.h | 2 +- .../llvm-libc/src/hdr/types/socklen_t.h | 2 +- .../types/struct___pthread_cleanup_frame.h | 27 + .../llvm-libc/src/hdr/types/struct_cmsghdr.h | 2 +- .../src/hdr/types/struct_ether_addr.h | 27 + .../llvm-libc/src/hdr/types/struct_linger.h | 2 +- .../llvm-libc/src/hdr/types/struct_mmsghdr.h | 2 +- .../llvm-libc/src/hdr/types/struct_msghdr.h | 2 +- .../llvm-libc/src/hdr/types/struct_pollfd.h | 2 +- .../llvm-libc/src/hdr/types/struct_sockaddr.h | 2 +- .../src/hdr/types/struct_sockaddr_storage.h | 2 +- .../llvm-libc/src/hdr/unistd_macros.h | 1 + .../llvm-libc/src/include/CMakeLists.txt | 56 + .../llvm-libc/src/include/arpa/inet.yaml | 8 + .../llvm-libc/src/include/dirent.yaml | 9 + .../llvm-libc/src/include/fcntl.yaml | 86 +- .../llvm-libc/src/include/grp.yaml | 35 + .../llvm-libc/src/include/libintl.yaml | 131 + .../include/llvm-libc-macros/CMakeLists.txt | 34 + .../llvm-libc-macros/common-threads-macros.h | 19 + .../generic-error-number-macros.h | 1 + .../include/llvm-libc-macros/limits-macros.h | 4 +- .../llvm-libc-macros/linux/CMakeLists.txt | 36 +- .../llvm-libc-macros/linux/fcntl-macros.h | 8 + .../llvm-libc-macros/linux/net-if-macros.h | 4 + .../linux/sys-eventfd-macros.h | 23 + .../linux/sys-inotify-macros.h | 54 + .../linux/sys-socket-macros.h | 3 + .../llvm-libc-macros/linux/sys-xattr-macros.h | 20 + .../llvm-libc-macros/linux/unistd-macros.h | 7 + .../include/llvm-libc-macros/pthread-macros.h | 10 + .../include/llvm-libc-macros/stdbit-macros.h | 85 +- .../include/llvm-libc-macros/stdio-macros.h | 29 + .../llvm-libc-macros/sys-eventfd-macros.h | 21 + .../llvm-libc-macros/sys-inotify-macros.h | 21 + .../llvm-libc-macros/sys-xattr-macros.h | 21 + .../include/llvm-libc-macros/threads-macros.h | 22 + .../include/llvm-libc-types/CMakeLists.txt | 16 +- .../llvm-libc-types/EFI_ALLOCATE_TYPE.h | 7 +- .../llvm-libc-types/EFI_BOOT_SERVICES.h | 7 +- .../src/include/llvm-libc-types/EFI_CAPSULE.h | 7 +- .../llvm-libc-types/EFI_CONFIGURATION_TABLE.h | 9 +- .../EFI_DEVICE_PATH_PROTOCOL.h | 7 +- .../src/include/llvm-libc-types/EFI_EVENT.h | 7 +- .../src/include/llvm-libc-types/EFI_GUID.h | 9 +- .../src/include/llvm-libc-types/EFI_HANDLE.h | 9 +- .../llvm-libc-types/EFI_INTERFACE_TYPE.h | 7 +- .../llvm-libc-types/EFI_LOCATE_SEARCH_TYPE.h | 7 +- .../llvm-libc-types/EFI_MEMORY_DESCRIPTOR.h | 7 +- .../include/llvm-libc-types/EFI_MEMORY_TYPE.h | 7 +- .../EFI_OPEN_PROTOCOL_INFORMATION_ENTRY.h | 7 +- .../llvm-libc-types/EFI_PHYSICAL_ADDRESS.h | 7 +- .../llvm-libc-types/EFI_RUNTIME_SERVICES.h | 7 +- .../EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h | 7 +- .../EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h | 7 +- .../src/include/llvm-libc-types/EFI_STATUS.h | 9 +- .../llvm-libc-types/EFI_SYSTEM_TABLE.h | 9 +- .../llvm-libc-types/EFI_TABLE_HEADER.h | 9 +- .../src/include/llvm-libc-types/EFI_TIME.h | 7 +- .../include/llvm-libc-types/EFI_TIMER_DELAY.h | 7 +- .../src/include/llvm-libc-types/EFI_TPL.h | 7 +- .../llvm-libc-types/EFI_VIRTUAL_ADDRESS.h | 7 +- .../src/include/llvm-libc-types/__jmp_buf.h | 6 + .../src/include/llvm-libc-types/fenv_t.h | 2 + .../src/include/llvm-libc-types/fpos_t.h | 25 + .../src/include/llvm-libc-types/idtype_t.h | 19 + .../llvm-libc-types/linux/CMakeLists.txt | 16 + .../llvm-libc-types/linux/struct_ifmap.h | 29 + .../llvm-libc-types/linux/struct_ifreq.h | 62 + .../include/llvm-libc-types/sighandler_t.h | 3 - .../struct___pthread_cleanup_frame.h | 23 + .../llvm-libc-types/struct_ether_addr.h | 23 + .../include/llvm-libc-types/struct_ifreq.h | 25 +- .../llvm-libc-types/struct_inotify_event.h | 27 + .../llvm-libc/src/include/net/ethernet.yaml | 10 + .../llvm-libc/src/include/net/if.yaml | 4 + .../llvm-libc/src/include/netinet/ether.yaml | 21 + .../llvm-libc/src/include/poll.yaml | 11 + .../llvm-libc/src/include/pthread.yaml | 21 + .../llvm-libc/src/include/pwd.yaml | 9 + .../llvm-libc/src/include/sched.yaml | 11 + .../llvm-libc/src/include/signal.yaml | 18 +- .../llvm-libc/src/include/stdio.yaml | 51 + .../llvm-libc/src/include/stdlib.yaml | 22 + .../llvm-libc/src/include/sys/eventfd.yaml | 19 + .../llvm-libc/src/include/sys/inotify.yaml | 82 + .../llvm-libc/src/include/sys/mman.yaml | 6 +- .../llvm-libc/src/include/sys/random.yaml | 2 +- .../llvm-libc/src/include/sys/select.yaml | 11 + .../llvm-libc/src/include/sys/stat.yaml | 26 + .../llvm-libc/src/include/sys/wait.yaml | 11 + .../llvm-libc/src/include/sys/xattr.yaml | 63 +- .../llvm-libc/src/include/termios.yaml | 15 + .../llvm-libc/src/include/threads.yaml | 2 + .../llvm-libc/src/include/time.yaml | 13 + .../llvm-libc/src/include/unistd.yaml | 119 + .../v8/third_party/llvm-libc/src/shared/bit.h | 23 + .../llvm-libc/src/shared/builtins.h | 6 + .../src/shared/builtins/extendhfdf2.h | 29 + .../src/shared/builtins/extendhfsf2.h | 29 + .../src/shared/builtins/extendhftf2.h | 36 + .../src/shared/builtins/truncdfhf2.h | 29 + .../src/shared/builtins/truncsfhf2.h | 29 + .../src/shared/builtins/trunctfhf2.h | 36 + .../third_party/llvm-libc/src/shared/math.h | 1 + .../llvm-libc/src/shared/math/exp2bf16.h | 28 + .../src/shared/math/getpayloadf128.h | 13 +- .../llvm-libc/src/shared/math/nanf128.h | 13 +- .../src/shared/math/setpayloadf128.h | 13 +- .../src/shared/math/setpayloadsigf128.h | 13 +- .../src/shared/math/static_rounding/exp2f.h | 30 + .../src/shared/math/static_rounding/expf.h | 2 + .../src/shared/static_rounding_math.h | 1 + .../src/src/__support/CMakeLists.txt | 7 +- .../src/src/__support/CPP/CMakeLists.txt | 37 +- .../llvm-libc/src/src/__support/CPP/bitset.h | 4 + .../llvm-libc/src/src/__support/CPP/cstddef.h | 2 +- .../src/src/__support/CPP/expected.h | 81 +- .../llvm-libc/src/src/__support/CPP/new.cpp | 10 +- .../llvm-libc/src/src/__support/CPP/new.h | 2 + .../src/src/__support/CPP/optional.h | 43 +- .../src/src/__support/CPP/type_traits.h | 8 +- .../src/src/__support/CPP/unique_ptr.h | 208 + .../llvm-libc/src/src/__support/CPP/vector.h | 309 -- .../src/src/__support/FPUtil/CMakeLists.txt | 25 + .../src/src/__support/FPUtil/FEnvImpl.h | 9 +- .../llvm-libc/src/src/__support/FPUtil/FMA.h | 23 + .../src/src/__support/FPUtil/FPBits.h | 5 +- .../src/src/__support/FPUtil/PolyEval.h | 13 +- .../FPUtil/aarch64/nearest_integer.h | 13 + .../src/src/__support/FPUtil/aarch64/sqrt.h | 13 + .../llvm-libc/src/src/__support/FPUtil/cast.h | 8 +- .../src/src/__support/FPUtil/double_double.h | 16 +- .../src/src/__support/FPUtil/dyadic_float.h | 73 +- .../src/src/__support/FPUtil/float80.h | 2 +- .../src/src/__support/FPUtil/fp_bitwise.h | 250 + .../src/__support/FPUtil/hexagon/FEnvImpl.h | 215 + .../src/src/__support/FPUtil/is_integer.h | 62 + .../src/src/__support/FPUtil/multiply_add.h | 34 +- .../src/__support/FPUtil/nearest_integer.h | 23 +- .../llvm-libc/src/src/__support/FPUtil/sqrt.h | 2 +- .../__support/FPUtil/x86_64/nearest_integer.h | 31 +- .../src/src/__support/FPUtil/x86_64/sqrt.h | 19 + .../src/src/__support/File/CMakeLists.txt | 36 +- .../llvm-libc/src/src/__support/File/dir.cpp | 8 + .../llvm-libc/src/src/__support/File/dir.h | 9 +- .../src/src/__support/File/dir_scan_impl.h | 133 + .../llvm-libc/src/src/__support/File/file.cpp | 99 +- .../llvm-libc/src/src/__support/File/file.h | 155 +- .../src/src/__support/File/file_io_result.h | 37 + .../src/src/__support/File/file_mode.h | 18 +- .../src/__support/File/linux/CMakeLists.txt | 19 + .../src/src/__support/File/linux/file.cpp | 102 +- .../src/src/__support/File/linux/file.h | 62 +- .../src/src/__support/File/linux/file_flags.h | 2 + .../src/__support/File/linux/popen_file.cpp | 60 + .../src/src/__support/File/linux/popen_file.h | 66 + .../src/src/__support/GPU/CMakeLists.txt | 5 + .../src/src/__support/GPU/fixedbuffer.h | 3 +- .../src/__support/OSUtil/linux/CMakeLists.txt | 35 + .../src/src/__support/OSUtil/linux/exit.cpp | 8 +- .../src/__support/OSUtil/linux/shell_fork.h | 81 + .../src/src/__support/OSUtil/linux/sigmask.h | 133 + .../linux/syscall_wrappers/CMakeLists.txt | 511 +- .../linux/syscall_wrappers/aarch64/clone.h | 60 + .../OSUtil/linux/syscall_wrappers/access.h | 9 +- .../OSUtil/linux/syscall_wrappers/chdir.h | 7 +- .../OSUtil/linux/syscall_wrappers/chmod.h | 16 +- .../OSUtil/linux/syscall_wrappers/clone.h | 72 + .../OSUtil/linux/syscall_wrappers/close.h | 14 +- .../OSUtil/linux/syscall_wrappers/dup.h | 7 +- .../OSUtil/linux/syscall_wrappers/dup2.h | 9 +- .../OSUtil/linux/syscall_wrappers/dup3.h | 7 +- .../OSUtil/linux/syscall_wrappers/epoll_ctl.h | 36 + .../OSUtil/linux/syscall_wrappers/eventfd.h | 33 + .../OSUtil/linux/syscall_wrappers/execveat.h | 35 + .../OSUtil/linux/syscall_wrappers/exit.h | 33 + .../linux/syscall_wrappers/exit_group.h | 33 + .../OSUtil/linux/syscall_wrappers/faccessat.h | 9 +- .../OSUtil/linux/syscall_wrappers/fchdir.h | 7 +- .../OSUtil/linux/syscall_wrappers/fchmod.h | 7 +- .../OSUtil/linux/syscall_wrappers/fchownat.h | 37 + .../OSUtil/linux/syscall_wrappers/fcntl.h | 24 +- .../OSUtil/linux/syscall_wrappers/fdatasync.h | 33 + .../OSUtil/linux/syscall_wrappers/fgetxattr.h | 36 + .../OSUtil/linux/syscall_wrappers/fsetxattr.h | 35 + .../OSUtil/linux/syscall_wrappers/fsync.h | 7 +- .../OSUtil/linux/syscall_wrappers/ftruncate.h | 16 +- .../OSUtil/linux/syscall_wrappers/getcpu.h | 38 + .../OSUtil/linux/syscall_wrappers/getcwd.h | 13 +- .../OSUtil/linux/syscall_wrappers/getegid.h | 6 + .../OSUtil/linux/syscall_wrappers/getxattr.h | 36 + .../syscall_wrappers/inotify_add_watch.h | 35 + .../linux/syscall_wrappers/inotify_init.h | 40 + .../linux/syscall_wrappers/inotify_init1.h | 33 + .../linux/syscall_wrappers/inotify_rm_watch.h | 33 + .../OSUtil/linux/syscall_wrappers/lchown.h | 45 + .../OSUtil/linux/syscall_wrappers/lgetxattr.h | 36 + .../OSUtil/linux/syscall_wrappers/link.h | 20 +- .../OSUtil/linux/syscall_wrappers/lseek.h | 20 +- .../OSUtil/linux/syscall_wrappers/lsetxattr.h | 35 + .../linux/syscall_wrappers/memfd_create.h | 7 +- .../OSUtil/linux/syscall_wrappers/mkdir.h | 9 +- .../OSUtil/linux/syscall_wrappers/mkdirat.h | 7 +- .../OSUtil/linux/syscall_wrappers/pause.h | 33 + .../OSUtil/linux/syscall_wrappers/pipe2.h | 38 + .../OSUtil/linux/syscall_wrappers/ppoll.h | 63 + .../OSUtil/linux/syscall_wrappers/pselect6.h | 71 + .../OSUtil/linux/syscall_wrappers/read.h | 14 +- .../OSUtil/linux/syscall_wrappers/readlink.h | 10 +- .../linux/syscall_wrappers/readlinkat.h | 7 +- .../OSUtil/linux/syscall_wrappers/rename.h | 15 +- .../OSUtil/linux/syscall_wrappers/renameat.h | 42 + .../linux/syscall_wrappers/riscv/clone.h | 68 + .../OSUtil/linux/syscall_wrappers/rmdir.h | 9 +- .../syscall_wrappers/sched_get_priority_max.h | 34 + .../syscall_wrappers/sched_get_priority_min.h | 34 + .../syscall_wrappers/sched_rr_get_interval.h | 52 + .../syscall_wrappers/sched_setaffinity.h | 38 + .../linux/syscall_wrappers/sched_setparam.h | 37 + .../linux/syscall_wrappers/sched_yield.h | 33 + .../OSUtil/linux/syscall_wrappers/setgid.h | 6 + .../OSUtil/linux/syscall_wrappers/setgroups.h | 43 + .../OSUtil/linux/syscall_wrappers/setregid.h | 6 + .../OSUtil/linux/syscall_wrappers/setresgid.h | 40 + .../OSUtil/linux/syscall_wrappers/setresuid.h | 40 + .../OSUtil/linux/syscall_wrappers/setreuid.h | 6 + .../OSUtil/linux/syscall_wrappers/setuid.h | 6 + .../OSUtil/linux/syscall_wrappers/setxattr.h | 35 + .../OSUtil/linux/syscall_wrappers/statx.h | 7 +- .../OSUtil/linux/syscall_wrappers/sync.h | 30 + .../OSUtil/linux/syscall_wrappers/syncfs.h | 33 + .../linux/syscall_wrappers/timer_getoverrun.h | 34 + .../OSUtil/linux/syscall_wrappers/unlink.h | 18 +- .../OSUtil/linux/syscall_wrappers/unlinkat.h | 7 +- .../OSUtil/linux/syscall_wrappers/utimensat.h | 20 +- .../OSUtil/linux/syscall_wrappers/waitid.h | 38 + .../OSUtil/linux/syscall_wrappers/write.h | 14 +- .../linux/syscall_wrappers/x86_64/clone.h | 60 + .../src/src/__support/OSUtil/uefi/error.h | 7 +- .../src/src/__support/OSUtil/uefi/exit.cpp | 20 +- .../src/src/__support/OSUtil/uefi/io.cpp | 9 +- .../src/src/__support/OSUtil/uefi/io.h | 9 +- .../src/src/__support/RPC/CMakeLists.txt | 1 + .../llvm-libc/src/src/__support/big_int.h | 58 +- .../llvm-libc/src/src/__support/block.h | 63 +- .../src/src/__support/builtins/CMakeLists.txt | 68 + .../src/src/__support/builtins/extendhfdf2.h | 34 + .../src/src/__support/builtins/extendhfsf2.h | 34 + .../src/src/__support/builtins/extendhftf2.h | 41 + .../src/__support/builtins/fpconvert_helper.h | 94 +- .../src/src/__support/builtins/truncdfhf2.h | 34 + .../src/src/__support/builtins/truncsfhf2.h | 34 + .../src/src/__support/builtins/trunctfhf2.h | 41 + .../llvm-libc/src/src/__support/frac64.h | 28 +- .../src/src/__support/freelist_heap.h | 145 +- .../llvm-libc/src/src/__support/freestore.h | 42 +- .../llvm-libc/src/src/__support/freetrie.cpp | 8 + .../llvm-libc/src/src/__support/freetrie.h | 4 + .../src/src/__support/integer_to_string.h | 121 +- .../src/src/__support/macros/CMakeLists.txt | 1 - .../src/src/__support/macros/attributes.h | 50 +- .../src/src/__support/macros/optimization.h | 18 +- .../macros/properties/architectures.h | 4 + .../__support/macros/properties/compiler.h | 2 +- .../macros/properties/cpu_features.h | 25 +- .../src/src/__support/macros/sanitizer.h | 6 +- .../src/src/__support/math/CMakeLists.txt | 364 +- .../src/src/__support/math/acosbf16.h | 21 +- .../src/src/__support/math/asin_utils.h | 16 + .../src/src/__support/math/asinbf16.h | 6 +- .../src/src/__support/math/bf16sub.h | 2 +- .../src/src/__support/math/bf16subf.h | 2 +- .../src/src/__support/math/bf16subf128.h | 2 +- .../llvm-libc/src/src/__support/math/cbrtf.h | 132 +- .../llvm-libc/src/src/__support/math/cosf.h | 169 +- .../src/src/__support/math/cosf_double_eval.h | 162 + .../src/src/__support/math/cosf_float_eval.h | 33 + .../llvm-libc/src/src/__support/math/erff.h | 214 +- .../llvm-libc/src/src/__support/math/exp.h | 446 +- .../src/__support/math/exp10f_double_eval.h | 148 +- .../llvm-libc/src/src/__support/math/exp2.h | 437 +- .../src/__support/math/exp2_accurate_128.h | 265 + .../src/src/__support/math/exp2_double_eval.h | 133 + .../src/src/__support/math/exp2bf16.h | 211 + .../llvm-libc/src/src/__support/math/exp2f.h | 13 +- .../src/__support/math/exp2f_double_eval.h | 96 +- .../src/__support/math/exp2f_float_utils.h | 25 +- .../src/__support/math/exp2f_integer_eval.h | 131 + .../src/__support/math/exp2f_integer_utils.h | 182 + .../src/src/__support/math/exp_double_eval.h | 153 + .../src/src/__support/math/exp_double_utils.h | 178 + .../src/src/__support/math/exp_utils.h | 519 +- .../llvm-libc/src/src/__support/math/expf.h | 23 +- .../src/src/__support/math/expf_double_eval.h | 11 +- .../src/src/__support/math/expf_float_eval.h | 91 +- .../src/src/__support/math/expf_float_utils.h | 149 + .../src/__support/math/expf_integer_eval.h | 300 +- .../src/src/__support/math/gamma_util.h | 14 - .../src/src/__support/math/getpayloadf128.h | 18 +- .../src/src/__support/math/lgammaf.h | 11 +- .../src/src/__support/math/lgammaf16.h | 3 +- .../llvm-libc/src/src/__support/math/log10f.h | 111 +- .../llvm-libc/src/src/__support/math/log1p.h | 12 +- .../llvm-libc/src/src/__support/math/log2f.h | 8 +- .../src/src/__support/math/nanf128.h | 20 +- .../llvm-libc/src/src/__support/math/pow.h | 3 +- .../src/src/__support/math/pow_fast.h | 8 +- .../src/src/__support/math/pow_utils.h | 211 +- .../llvm-libc/src/src/__support/math/powf.h | 1047 +--- .../src/src/__support/math/powf_double_eval.h | 558 ++ .../src/src/__support/math/powf_float_eval.h | 236 + .../src/__support/math/powf_small_tables.h | 120 - .../src/src/__support/math/powf_utils.h | 721 +++ .../src/src/__support/math/setpayloadf128.h | 18 +- .../src/__support/math/setpayloadsigf128.h | 18 +- .../src/__support/math/sincosf_float_eval.h | 83 +- .../llvm-libc/src/src/__support/math/sinf.h | 191 +- .../src/src/__support/math/sinf_double_eval.h | 182 + .../src/src/__support/math/sinf_float_eval.h | 33 + .../llvm-libc/src/src/__support/math/tanf.h | 167 +- .../src/src/__support/math/tanf_double_eval.h | 172 + .../src/src/__support/math/tanf_float_eval.h | 106 + .../llvm-libc/src/src/__support/math/tanpif.h | 57 +- .../src/src/__support/math/tanpif16.h | 53 +- .../src/src/__support/mathvec/CMakeLists.txt | 3 +- .../src/src/__support/mathvec/acosf.h | 2 +- .../src/src/__support/mathvec/acoshf.h | 2 +- .../src/src/__support/mathvec/acospif.h | 2 +- .../src/src/__support/mathvec/asinf.h | 2 +- .../src/src/__support/mathvec/asinhf.h | 2 +- .../src/src/__support/mathvec/asinpif.h | 2 +- .../src/src/__support/mathvec/atanf.h | 2 +- .../src/src/__support/mathvec/atanhf.h | 2 +- .../src/src/__support/mathvec/cbrtf.h | 2 +- .../src/__support/mathvec/common_constants.h | 60 + .../src/src/__support/mathvec/cosf.h | 126 +- .../src/src/__support/mathvec/coshf.h | 2 +- .../src/src/__support/mathvec/cospif.h | 2 +- .../src/src/__support/mathvec/erff.h | 2 +- .../src/src/__support/mathvec/exp10f.h | 2 +- .../src/src/__support/mathvec/exp10m1f.h | 2 +- .../src/src/__support/mathvec/exp2f.h | 2 +- .../src/src/__support/mathvec/exp2m1f.h | 2 +- .../src/src/__support/mathvec/expf.h | 2 +- .../src/src/__support/mathvec/expm1f.h | 2 +- .../src/src/__support/mathvec/log10f.h | 2 +- .../src/src/__support/mathvec/log1pf.h | 2 +- .../src/src/__support/mathvec/log2f.h | 2 +- .../src/src/__support/mathvec/logf.h | 103 +- .../src/src/__support/mathvec/rsqrtf.h | 2 +- .../src/src/__support/mathvec/sinf.h | 2 +- .../src/src/__support/mathvec/sinhf.h | 2 +- .../src/src/__support/mathvec/sinpif.h | 2 +- .../src/src/__support/mathvec/sqrtf.h | 2 +- .../src/src/__support/mathvec/tanf.h | 2 +- .../src/src/__support/mathvec/tanhf.h | 2 +- .../src/src/__support/mathvec/tanpif.h | 2 +- .../src/__support/mathvec/trig_reductionf.h | 30 +- .../__support/mathvec/trig_reductionf_nofma.h | 34 +- .../llvm-libc/src/src/__support/memory_size.h | 7 +- .../src/src/__support/net/CMakeLists.txt | 3 + .../src/src/__support/net/address.cpp | 131 + .../llvm-libc/src/src/__support/net/address.h | 2 + .../src/__support/printf_core/CMakeLists.txt | 23 +- .../__support/printf_core/char_converter.h | 65 +- .../src/src/__support/printf_core/converter.h | 112 +- .../src/__support/printf_core/core_structs.h | 29 +- .../__support/printf_core/fixed_converter.h | 57 +- .../printf_core/float_dec_converter.h | 273 +- .../printf_core/float_dec_converter_limited.h | 171 +- .../printf_core/float_hex_converter.h | 213 +- .../printf_core/float_inf_nan_converter.h | 84 +- .../src/__support/printf_core/int_converter.h | 106 +- .../src/src/__support/printf_core/parser.h | 165 +- .../src/__support/printf_core/printf_main.h | 2 +- .../src/__support/printf_core/ptr_converter.h | 24 +- .../printf_core/strerror_converter.h | 23 +- .../__support/printf_core/string_converter.h | 148 +- .../printf_core/write_int_converter.h | 31 +- .../src/src/__support/pwd/flat_file_db.h | 17 +- .../src/src/__support/regex/CMakeLists.txt | 58 +- .../src/src/__support/regex/regex_ast.h | 111 +- .../src/__support/regex/regex_expr_pool.cpp | 361 +- .../src/src/__support/regex/regex_expr_pool.h | 171 +- .../src/src/__support/regex/regex_internal.h | 41 + .../src/src/__support/regex/regex_matcher.cpp | 142 + .../src/src/__support/regex/regex_matcher.h | 60 + .../src/src/__support/regex/regex_parser.cpp | 276 + .../src/src/__support/regex/regex_parser.h | 32 + .../src/src/__support/str_to_float.h | 126 +- .../src/src/__support/str_to_integer.h | 4 +- .../src/src/__support/threads/CMakeLists.txt | 18 +- .../src/src/__support/threads/cleanup_stack.h | 45 + .../__support/threads/linux/CMakeLists.txt | 25 +- .../threads/linux/aarch64/CMakeLists.txt | 20 + .../__support/threads/linux/aarch64/tls.cpp | 82 + .../threads/linux/riscv/CMakeLists.txt | 20 + .../src/__support/threads/linux/riscv/tls.cpp | 58 + .../src/__support/threads/linux/thread.cpp | 132 +- .../threads/linux/x86_64/CMakeLists.txt | 21 + .../__support/threads/linux/x86_64/tls.cpp | 76 + .../src/src/__support/threads/raw_mutex.h | 2 - .../src/src/__support/threads/thread.cpp | 45 +- .../src/src/__support/threads/thread.h | 15 +- .../src/__support/threads/thread_attributes.h | 2 + .../src/src/__support/time/gpu/CMakeLists.txt | 1 + .../llvm-libc/src/src/__support/tlsf_table.h | 7 + deps/v8/third_party/zlib/chromeconf.h | 1 + .../contrib/optimizations/inffast_chunk.c | 35 +- deps/v8/tools/clusterfuzz/foozzie/BUILD.gn | 2 + .../foozzie/testdata/failure_output_arch.txt | 2 +- .../testdata/failure_output_second.txt | 2 +- .../tools/clusterfuzz/foozzie/v8_commands.py | 2 + .../tools/clusterfuzz/foozzie/v8_foozzie.py | 16 +- .../clusterfuzz/foozzie/v8_foozzie_test.py | 65 +- .../foozzie/v8_fuzz_experiments_regexp.json | 6 + .../clusterfuzz/foozzie/v8_fuzz_flags.json | 1 - .../foozzie/v8_fuzz_flags_regexp.json | 11 + .../tools/clusterfuzz/js_fuzzer/exceptions.js | 1 + .../trials/clusterfuzz_trials_config.json | 2 - deps/v8/tools/compare-checked-in-headers.py | 112 + deps/v8/tools/debug_helper/BUILD.gn | 4 +- .../debug_helper/get-object-properties.cc | 90 +- deps/v8/tools/debug_helper/plugins/Makefile | 7 +- deps/v8/tools/debug_helper/plugins/README.md | 45 +- .../tools/debug_helper/plugins/gdb_plugin.py | 10 +- .../tools/debug_helper/plugins/lldb_plugin.py | 10 +- .../plugins/test/fixtures/args-mismatch.js | 13 + .../debug_helper/plugins/test/helpers/args.py | 155 + .../plugins/test/helpers/backtrace.py | 41 +- .../plugins/test/helpers/corruptions.py | 14 +- .../plugins/test/helpers/session.py | 18 +- .../plugins/test/helpers/source.py | 20 +- .../plugins/test/test_gdb_core.py | 34 + .../plugins/test/test_gdb_live.py | 41 + .../plugins/test/test_lldb_core.py | 34 + .../plugins/test/test_lldb_live.py | 41 + .../debug_helper/plugins/v8dbg/commands.py | 165 +- .../debug_helper/plugins/v8dbg/format.py | 18 +- .../debug_helper/plugins/v8dbg/inspect.py | 46 +- .../plugins/v8dbg/shared_bridge.py | 63 +- deps/v8/tools/dev/gen-checked-in-headers.py | 90 + deps/v8/tools/dev/gen-static-roots.py | 51 +- deps/v8/tools/dev/gm.py | 22 + deps/v8/tools/dev/setup_worktree_build.py | 238 +- deps/v8/tools/dev/update-compile-commands.py | 6 +- deps/v8/tools/gcmole/bootstrap.sh | 8 + deps/v8/tools/gcmole/gcmole-test.cc | 101 +- deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 | 2 +- deps/v8/tools/gcmole/gcmole.cc | 601 ++- deps/v8/tools/gcmole/package.sh | 2 +- deps/v8/tools/gcmole/test-expectations.txt | 181 +- deps/v8/tools/jj/README.md | 52 + deps/v8/tools/jj/config.toml | 64 + deps/v8/tools/metagen/PRESUBMIT.py | 32 + deps/v8/tools/metagen/clang_bootstrap.py | 2 +- deps/v8/tools/metagen/compile_flags.py | 149 +- deps/v8/tools/metagen/compile_flags_test.py | 90 - deps/v8/tools/metagen/cpp_hier.py | 278 +- deps/v8/tools/metagen/extract.py | 52 +- deps/v8/tools/metagen/layout_extract.py | 826 +++ deps/v8/tools/metagen/layout_ir.py | 716 +++ deps/v8/tools/metagen/metagen.py | 190 +- .../tools/metagen/test/compile_flags_test.py | 287 + .../tools/metagen/test/instance_types_test.py | 392 ++ deps/v8/tools/metagen/test/metagen_test.py | 130 + .../metagen/tests/layout_extract_test.py | 1078 ++++ deps/v8/tools/metagen/tests/layout_ir_test.py | 535 ++ .../tools/regexp/correctness_fuzzer/README.md | 113 +- .../correctness_fuzzer/correctness_fuzzer.py | 102 +- .../correctness_fuzzer/grammar/__init__.py | 4 + .../correctness_fuzzer/grammar/cases.py | 11 +- .../correctness_fuzzer/grammar/menus.py | 8 + .../correctness_fuzzer/grammar/profiles.py | 14 + .../correctness_fuzzer/grammar/registry.py | 5 + .../correctness_fuzzer/grammar/rules.py | 84 +- .../regexp/correctness_fuzzer/grammar_test.py | 524 +- .../regexp/correctness_fuzzer/harness.js | 43 +- .../regexp/correctness_fuzzer/harness.py | 82 + .../regexp/correctness_fuzzer/package.sh | 49 + .../v8/tools/regexp/correctness_fuzzer/run.py | 150 + .../run_locally_against_foozzie.py | 115 + deps/v8/tools/release/common_includes.py | 12 +- deps/v8/tools/release/git_recipes.py | 5 +- deps/v8/tools/testrunner/base_runner.py | 6 + deps/v8/tools/testrunner/local/command.py | 212 +- .../v8/tools/testrunner/local/command_test.py | 260 + deps/v8/tools/testrunner/local/variants.py | 2 +- deps/v8/tools/testrunner/objects/testcase.py | 1 + deps/v8/tools/testrunner/outproc/base.py | 21 +- deps/v8/tools/testrunner/test_config.py | 4 +- deps/v8/tools/testrunner/testproc/fuzzer.py | 1 - deps/v8/tools/turbolizer/README.md | 9 +- deps/v8/tools/turbolizer/cli.js | 128 + deps/v8/tools/turbolizer/package-lock.json | 3 + deps/v8/tools/turbolizer/package.json | 3 + .../turboshaft-graph-operation.ts | 6 +- .../tools/turbolizer/src/turbo-visualizer.ts | 20 +- deps/v8/tools/v8_presubmit.py | 13 +- .../tools/v8windbg/src/object-inspection.cc | 4 +- deps/v8/tools/wasm/module-inspector.cc | 28 +- 3031 files changed, 190107 insertions(+), 57043 deletions(-) delete mode 100755 deps/v8/agents/scripts/edit_cl_description.sh delete mode 100755 deps/v8/agents/scripts/upload_cl.sh delete mode 100755 deps/v8/agents/scripts/validate_cl_description.py create mode 100644 deps/v8/agents/skills/clusterfuzz/SKILL.md create mode 100755 deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase.py create mode 100644 deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase_test.py create mode 100644 deps/v8/agents/skills/v8-features/SKILL.md create mode 100644 deps/v8/agents/skills/v8-features/assets/launch-review-template.md create mode 100644 deps/v8/agents/skills/v8-features/references/coverage-report.md create mode 100644 deps/v8/agents/skills/v8-features/references/launch-reviews.md create mode 100644 deps/v8/agents/skills/v8-features/references/shipping-steps.md create mode 100755 deps/v8/agents/skills/v8-features/scripts/extract_coverage.py create mode 100755 deps/v8/agents/skills/v8-features/scripts/fetch_chromestatus.py create mode 100755 deps/v8/agents/skills/v8-features/scripts/find_affected_blocks.py create mode 100755 deps/v8/agents/skills/v8-features/scripts/generate_coverage_report.py create mode 100755 deps/v8/agents/skills/v8-features/scripts/get_v8_revision.py create mode 100755 deps/v8/agents/skills/v8-features/scripts/read_finch_config.py create mode 100644 deps/v8/agents/skills/v8-review/OWNERS create mode 100644 deps/v8/agents/skills/v8-review/SKILL.md create mode 100644 deps/v8/agents/skills/v8-turboshaft/SKILL.md create mode 100644 deps/v8/bazel/v8-generators.bzl create mode 100644 deps/v8/experimental/redline/.clang-tidy create mode 100644 deps/v8/experimental/redline/.gitignore create mode 100644 deps/v8/experimental/redline/BUILD.gn create mode 100644 deps/v8/experimental/redline/CONTRIBUTE.md create mode 100644 deps/v8/experimental/redline/CPPLINT.cfg create mode 100644 deps/v8/experimental/redline/DEPS create mode 100644 deps/v8/experimental/redline/DESIGN.md create mode 100644 deps/v8/experimental/redline/GEMINI.md create mode 100644 deps/v8/experimental/redline/README.md create mode 100644 deps/v8/experimental/redline/TUTORIAL.md create mode 100644 deps/v8/experimental/redline/base/file_util.cc create mode 100644 deps/v8/experimental/redline/base/file_util.h create mode 100644 deps/v8/experimental/redline/base/flags.cc create mode 100644 deps/v8/experimental/redline/base/flags.h create mode 100644 deps/v8/experimental/redline/base/json.cc create mode 100644 deps/v8/experimental/redline/base/json.h create mode 100644 deps/v8/experimental/redline/base/json_parser.cc create mode 100644 deps/v8/experimental/redline/base/json_parser.h create mode 100644 deps/v8/experimental/redline/base/log.cc create mode 100644 deps/v8/experimental/redline/base/log.h create mode 100644 deps/v8/experimental/redline/base/subprocess.cc create mode 100644 deps/v8/experimental/redline/base/subprocess.h create mode 100644 deps/v8/experimental/redline/base/time_util.h create mode 100644 deps/v8/experimental/redline/base/v8_runtime.cc create mode 100644 deps/v8/experimental/redline/base/v8_runtime.h create mode 100644 deps/v8/experimental/redline/commands/amplify_command.cc create mode 100644 deps/v8/experimental/redline/commands/command.h create mode 100644 deps/v8/experimental/redline/commands/exec_command.cc create mode 100644 deps/v8/experimental/redline/commands/fuzz_command.cc create mode 100644 deps/v8/experimental/redline/commands/minimize_command.cc create mode 100644 deps/v8/experimental/redline/commands/mutate_command.cc create mode 100644 deps/v8/experimental/redline/commands/parse_command.cc create mode 100644 deps/v8/experimental/redline/commands/replay_command.cc create mode 100644 deps/v8/experimental/redline/commands/roundtrip_command.cc create mode 100644 deps/v8/experimental/redline/commands/selftest_checker.h create mode 100644 deps/v8/experimental/redline/commands/selftest_command.cc create mode 100644 deps/v8/experimental/redline/commands/selftest_selection.cc create mode 100644 deps/v8/experimental/redline/commands/selftest_selection.h create mode 100644 deps/v8/experimental/redline/commands/shell_command.cc create mode 100644 deps/v8/experimental/redline/core/adaptive_selector.h create mode 100644 deps/v8/experimental/redline/core/ast_builder.cc create mode 100644 deps/v8/experimental/redline/core/ast_builder.h create mode 100644 deps/v8/experimental/redline/core/builder.cc create mode 100644 deps/v8/experimental/redline/core/builder.h create mode 100644 deps/v8/experimental/redline/core/component.cc create mode 100644 deps/v8/experimental/redline/core/component.h create mode 100644 deps/v8/experimental/redline/core/environment.cc create mode 100644 deps/v8/experimental/redline/core/environment.h create mode 100644 deps/v8/experimental/redline/core/program.cc create mode 100644 deps/v8/experimental/redline/core/program.h create mode 100644 deps/v8/experimental/redline/core/random.h create mode 100644 deps/v8/experimental/redline/core/selection.cc create mode 100644 deps/v8/experimental/redline/core/selection.h create mode 100644 deps/v8/experimental/redline/core/tunable.cc create mode 100644 deps/v8/experimental/redline/core/tunable.h create mode 100644 deps/v8/experimental/redline/core/weighted_selector.h create mode 100644 deps/v8/experimental/redline/corpus/corpus.cc create mode 100644 deps/v8/experimental/redline/corpus/corpus.h create mode 100644 deps/v8/experimental/redline/engine/amplifier.cc create mode 100644 deps/v8/experimental/redline/engine/amplifier.h create mode 100644 deps/v8/experimental/redline/engine/config.cc create mode 100644 deps/v8/experimental/redline/engine/config.h create mode 100644 deps/v8/experimental/redline/engine/crash.cc create mode 100644 deps/v8/experimental/redline/engine/crash.h create mode 100644 deps/v8/experimental/redline/engine/fuzzer.cc create mode 100644 deps/v8/experimental/redline/engine/fuzzer.h create mode 100644 deps/v8/experimental/redline/engine/importer.cc create mode 100644 deps/v8/experimental/redline/engine/importer.h create mode 100644 deps/v8/experimental/redline/engine/prelude.cc create mode 100644 deps/v8/experimental/redline/engine/prelude.h create mode 100644 deps/v8/experimental/redline/engine/shared_coverage.cc create mode 100644 deps/v8/experimental/redline/engine/shared_coverage.h create mode 100644 deps/v8/experimental/redline/engine/stages.cc create mode 100644 deps/v8/experimental/redline/engine/stages.h create mode 100644 deps/v8/experimental/redline/exec/coverage.cc create mode 100644 deps/v8/experimental/redline/exec/coverage.h create mode 100644 deps/v8/experimental/redline/exec/execution.cc create mode 100644 deps/v8/experimental/redline/exec/execution.h create mode 100644 deps/v8/experimental/redline/exec/process_run.cc create mode 100644 deps/v8/experimental/redline/exec/process_run.h create mode 100644 deps/v8/experimental/redline/exec/reprl.cc create mode 100644 deps/v8/experimental/redline/exec/reprl.h create mode 100644 deps/v8/experimental/redline/exec/runner.cc create mode 100644 deps/v8/experimental/redline/exec/runner.h create mode 100644 deps/v8/experimental/redline/exec/target_options.cc create mode 100644 deps/v8/experimental/redline/exec/target_options.h create mode 100644 deps/v8/experimental/redline/fast/arena.cc create mode 100644 deps/v8/experimental/redline/fast/arena.h create mode 100644 deps/v8/experimental/redline/fast/ast.cc create mode 100644 deps/v8/experimental/redline/fast/ast.h create mode 100644 deps/v8/experimental/redline/fast/ast_visit.h create mode 100644 deps/v8/experimental/redline/fast/lexer.cc create mode 100644 deps/v8/experimental/redline/fast/lexer.h create mode 100644 deps/v8/experimental/redline/fast/parser.cc create mode 100644 deps/v8/experimental/redline/fast/parser.h create mode 100644 deps/v8/experimental/redline/fast/printer.cc create mode 100644 deps/v8/experimental/redline/fast/printer.h create mode 100644 deps/v8/experimental/redline/fast/scope.cc create mode 100644 deps/v8/experimental/redline/fast/scope.h create mode 100644 deps/v8/experimental/redline/fast/tree.cc create mode 100644 deps/v8/experimental/redline/fast/tree.h create mode 100644 deps/v8/experimental/redline/generators/codegen.cc create mode 100644 deps/v8/experimental/redline/generators/codegen.h create mode 100644 deps/v8/experimental/redline/generators/generator.h create mode 100644 deps/v8/experimental/redline/generators/generators.cc create mode 100644 deps/v8/experimental/redline/generators/wasm_module.cc create mode 100644 deps/v8/experimental/redline/generators/wasm_module.h create mode 100644 deps/v8/experimental/redline/main.cc create mode 100644 deps/v8/experimental/redline/minimizer/minimizer.cc create mode 100644 deps/v8/experimental/redline/minimizer/minimizer.h create mode 100644 deps/v8/experimental/redline/mutators/explore.cc create mode 100644 deps/v8/experimental/redline/mutators/explore.h create mode 100644 deps/v8/experimental/redline/mutators/mutator.h create mode 100644 deps/v8/experimental/redline/mutators/mutators.cc create mode 100644 deps/v8/experimental/redline/mutators/probing.cc create mode 100644 deps/v8/experimental/redline/mutators/probing.h create mode 100644 deps/v8/experimental/redline/presets/.gitignore create mode 100644 deps/v8/experimental/redline/presets/builtins.json create mode 100644 deps/v8/experimental/redline/presets/default.json create mode 100644 deps/v8/experimental/redline/presets/maglev.json create mode 100644 deps/v8/experimental/redline/presets/parser.json create mode 100644 deps/v8/experimental/redline/presets/runtime.json create mode 100644 deps/v8/experimental/redline/presets/turbolev.json create mode 100644 deps/v8/experimental/redline/presets/wasm.json create mode 100644 deps/v8/experimental/redline/skills/redline-presubmit/SKILL.md create mode 100755 deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_compare.py create mode 100755 deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_run.sh create mode 100755 deps/v8/experimental/redline/skills/redline-presubmit/scripts/check.sh create mode 100755 deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_check.py create mode 100644 deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_lint.vpython3 create mode 100644 deps/v8/experimental/redline/testdata/README.md create mode 100644 deps/v8/experimental/redline/testdata/selection/codegen.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/generator_outputs.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/generators.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/mutator_outputs.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/mutators.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/scheduler_productive.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/scheduler_recency.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/scheduler_tournament.trace create mode 100644 deps/v8/experimental/redline/testdata/selection/scheduler_uniform.trace delete mode 100644 deps/v8/src/base/fpu.cc delete mode 100644 deps/v8/src/base/fpu.h create mode 100644 deps/v8/src/base/growing-circular-queue.h create mode 100644 deps/v8/src/base/unique-array.h delete mode 100644 deps/v8/src/builtins/builtins-atomics-synchronization.cc create mode 100644 deps/v8/src/builtins/bytecodes-builtins-list.h delete mode 100644 deps/v8/src/compiler/memory-lowering.cc delete mode 100644 deps/v8/src/compiler/memory-lowering.h delete mode 100644 deps/v8/src/compiler/memory-optimizer.cc delete mode 100644 deps/v8/src/compiler/memory-optimizer.h delete mode 100644 deps/v8/src/compiler/wasm-address-reassociation.cc delete mode 100644 deps/v8/src/compiler/wasm-address-reassociation.h create mode 100644 deps/v8/src/gen/.clang-format create mode 100644 deps/v8/src/gen/OWNERS create mode 100644 deps/v8/src/gen/README.md rename deps/v8/src/{roots/static-roots-intl-nowasm.h => gen/intl-nowasm/static-roots.h} (99%) create mode 100644 deps/v8/src/gen/intl-wasm/builtin-definitions.h create mode 100644 deps/v8/src/gen/intl-wasm/bytecodes-builtins-list.h create mode 100644 deps/v8/src/gen/intl-wasm/class-forward-declarations.h create mode 100644 deps/v8/src/gen/intl-wasm/instance-types.h create mode 100644 deps/v8/src/gen/intl-wasm/interface-descriptors.inc rename deps/v8/src/{roots/static-roots-intl-wasm.h => gen/intl-wasm/static-roots.h} (98%) rename deps/v8/src/{roots/static-roots-nointl-nowasm.h => gen/nointl-nowasm/static-roots.h} (98%) rename deps/v8/src/{roots/static-roots-nointl-wasm.h => gen/nointl-wasm/static-roots.h} (97%) create mode 100644 deps/v8/src/maglev/maglev-basic-block.cc create mode 100644 deps/v8/src/maglev/maglev-kna-map.h create mode 100644 deps/v8/src/objects/bit-field-group.h delete mode 100644 deps/v8/src/objects/js-atomics-synchronization-inl.h delete mode 100644 deps/v8/src/objects/js-atomics-synchronization.cc delete mode 100644 deps/v8/src/objects/js-atomics-synchronization.h delete mode 100644 deps/v8/src/objects/js-atomics-synchronization.tq create mode 100644 deps/v8/src/objects/js-plural-rules-internal.cc create mode 100644 deps/v8/src/objects/js-plural-rules-internal.h delete mode 100644 deps/v8/src/objects/trusted-pointer-inl.h delete mode 100644 deps/v8/src/objects/waiter-queue-node.cc delete mode 100644 deps/v8/src/objects/waiter-queue-node.h delete mode 100644 deps/v8/src/sandbox/indirect-pointer-inl.h delete mode 100644 deps/v8/src/sandbox/indirect-pointer.h create mode 100644 deps/v8/src/sandbox/sandbox-zero-segment.h create mode 100644 deps/v8/src/sandbox/trusted-pointer-inl.h rename deps/v8/src/sandbox/{indirect-pointer-tag.h => trusted-pointer-tag.h} (50%) rename deps/v8/src/{objects => sandbox}/trusted-pointer.h (57%) create mode 100644 deps/v8/src/snapshot/trusted-section-serializer.cc create mode 100644 deps/v8/src/snapshot/trusted-section-serializer.h create mode 100644 deps/v8/src/torque/layout-loader.cc create mode 100644 deps/v8/src/torque/layout-loader.h delete mode 100644 deps/v8/src/zone/zone-chunk-list.h delete mode 100644 deps/v8/test/cctest/heap/test-alloc.cc delete mode 100644 deps/v8/test/cctest/heap/test-compaction.cc delete mode 100644 deps/v8/test/cctest/heap/test-concurrent-marking.cc delete mode 100644 deps/v8/test/cctest/heap/test-heap.cc delete mode 100644 deps/v8/test/cctest/heap/test-incremental-marking.cc delete mode 100644 deps/v8/test/cctest/heap/test-mark-compact.cc delete mode 100644 deps/v8/test/cctest/heap/test-memory-measurement.cc delete mode 100644 deps/v8/test/cctest/heap/test-pool.cc delete mode 100644 deps/v8/test/cctest/heap/test-spaces.cc delete mode 100644 deps/v8/test/cctest/heap/test-write-barrier.cc delete mode 100644 deps/v8/test/cctest/wasm/test-run-wasm-f16.cc create mode 100644 deps/v8/test/debugger/debug/es6/regress-nested-arrow-default-param-this.js delete mode 100644 deps/v8/test/debugger/regress/regress-510925423.js create mode 100644 deps/v8/test/debugger/regress/regress-571155503.js delete mode 100644 deps/v8/test/debugger/regress/wasm/regress-532625490.js create mode 100644 deps/v8/test/debugger/regress/wasm/regress-570547314.js create mode 100644 deps/v8/test/debugger/regress/wasm/regress-576981470.js create mode 100644 deps/v8/test/filecheck/deopt-now-fuzzing.js create mode 100644 deps/v8/test/filecheck/turbolev-spread-rest-parameter-late-inlined-mutation.js create mode 100644 deps/v8/test/inspector/console/enable-with-stored-exception-expected.txt create mode 100644 deps/v8/test/inspector/console/enable-with-stored-exception.js create mode 100644 deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope-expected.txt create mode 100644 deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope.js create mode 100644 deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate-expected.txt create mode 100644 deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate.js create mode 100644 deps/v8/test/inspector/debugger/osr-debug-break-expected.txt create mode 100644 deps/v8/test/inspector/debugger/osr-debug-break.js create mode 100644 deps/v8/test/inspector/debugger/osr-step-in-blackboxed-expected.txt create mode 100644 deps/v8/test/inspector/debugger/osr-step-in-blackboxed.js create mode 100644 deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed-expected.txt create mode 100644 deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed.js create mode 100644 deps/v8/test/inspector/debugger/osr-step-on-throw-expected.txt create mode 100644 deps/v8/test/inspector/debugger/osr-step-on-throw.js create mode 100644 deps/v8/test/inspector/debugger/osr-step-out-expected.txt create mode 100644 deps/v8/test/inspector/debugger/osr-step-out.js create mode 100644 deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed-expected.txt create mode 100644 deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed.js create mode 100644 deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed-expected.txt create mode 100644 deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed.js create mode 100644 deps/v8/test/inspector/debugger/regress-blackbox-exact-start-expected.txt create mode 100644 deps/v8/test/inspector/debugger/regress-blackbox-exact-start.js create mode 100644 deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start-expected.txt create mode 100644 deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start.js create mode 100644 deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause-expected.txt create mode 100644 deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause.js create mode 100644 deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash-expected.txt create mode 100644 deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash.js create mode 100644 deps/v8/test/inspector/debugger/scope-chain-outer-scopes-expected.txt create mode 100644 deps/v8/test/inspector/debugger/scope-chain-outer-scopes.js create mode 100644 deps/v8/test/inspector/debugger/scope-chain-return-position-expected.txt create mode 100644 deps/v8/test/inspector/debugger/scope-chain-return-position.js create mode 100644 deps/v8/test/inspector/debugger/scope-empty-reason-expected.txt create mode 100644 deps/v8/test/inspector/debugger/scope-empty-reason.js create mode 100644 deps/v8/test/inspector/debugger/script-parsed-long-magic-comments-expected.txt create mode 100644 deps/v8/test/inspector/debugger/script-parsed-long-magic-comments.js create mode 100644 deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position-expected.txt create mode 100644 deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position.js create mode 100644 deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position-expected.txt create mode 100644 deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position.js create mode 100644 deps/v8/test/inspector/debugger/set-variable-value-unallocated-expected.txt create mode 100644 deps/v8/test/inspector/debugger/set-variable-value-unallocated.js create mode 100644 deps/v8/test/inspector/debugger/set-variable-value-varblock-eval-expected.txt create mode 100644 deps/v8/test/inspector/debugger/set-variable-value-varblock-eval.js create mode 100644 deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call-expected.txt create mode 100644 deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call.js create mode 100644 deps/v8/test/inspector/debugger/step-over-enter-ranges-expected.txt create mode 100644 deps/v8/test/inspector/debugger/step-over-enter-ranges.js create mode 100644 deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert-expected.txt create mode 100644 deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert.js create mode 100644 deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints-expected.txt create mode 100644 deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints.js create mode 100644 deps/v8/test/inspector/debugger/stepping-with-stale-skip-list-expected.txt create mode 100644 deps/v8/test/inspector/debugger/stepping-with-stale-skip-list.js create mode 100644 deps/v8/test/inspector/debugger/untrusted-terminate-on-resume-expected.txt create mode 100644 deps/v8/test/inspector/debugger/untrusted-terminate-on-resume.js create mode 100644 deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry-expected.txt create mode 100644 deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry.js create mode 100644 deps/v8/test/inspector/regress/regress-502287689-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-502287689.js create mode 100644 deps/v8/test/inspector/regress/regress-502337304-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-502337304.js create mode 100644 deps/v8/test/inspector/regress/regress-507490539-expected.txt rename deps/v8/test/{mjsunit/sandbox => inspector/regress}/regress-507490539.js (77%) create mode 100644 deps/v8/test/inspector/regress/regress-513048538-expected.txt rename deps/v8/test/{mjsunit/sandbox => inspector/regress}/regress-513048538.js (94%) create mode 100644 deps/v8/test/inspector/regress/regress-513413942-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-513413942.js create mode 100644 deps/v8/test/inspector/regress/regress-514561070-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-514561070.js create mode 100644 deps/v8/test/inspector/regress/regress-516022777-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-516022777.js create mode 100644 deps/v8/test/inspector/regress/regress-519715438-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-519715438.js create mode 100644 deps/v8/test/inspector/regress/regress-521715545-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-521715545.js create mode 100644 deps/v8/test/inspector/regress/regress-526163463-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-526163463.js create mode 100644 deps/v8/test/inspector/regress/regress-527985808-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-527985808.js create mode 100644 deps/v8/test/inspector/regress/regress-529880019-expected.txt rename deps/v8/test/{mjsunit/regress/wasm => inspector/regress}/regress-529880019.js (52%) create mode 100644 deps/v8/test/inspector/regress/regress-530658019-expected.txt rename deps/v8/test/{mjsunit/regress/wasm => inspector/regress}/regress-530658019.js (52%) create mode 100644 deps/v8/test/inspector/regress/regress-531297707-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-531297707.js create mode 100644 deps/v8/test/inspector/regress/regress-532720981-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-532720981.js create mode 100644 deps/v8/test/inspector/regress/regress-534275413-expected.txt rename deps/v8/test/{mjsunit/regress/wasm => inspector/regress}/regress-534275413.js (53%) create mode 100644 deps/v8/test/inspector/regress/regress-534579660-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-534579660.js create mode 100644 deps/v8/test/inspector/regress/regress-537219980-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-537219980.js create mode 100644 deps/v8/test/inspector/regress/regress-568338771-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-568338771.js create mode 100644 deps/v8/test/inspector/regress/regress-569886678-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-569886678.js create mode 100644 deps/v8/test/inspector/regress/regress-570538338-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-570538338.js create mode 100644 deps/v8/test/inspector/regress/regress-570547313-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-570547313.js create mode 100644 deps/v8/test/inspector/regress/regress-570558888-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-570558888.js create mode 100644 deps/v8/test/inspector/regress/regress-571965281-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-571965281.js create mode 100644 deps/v8/test/inspector/regress/regress-572276045-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-572276045.js create mode 100644 deps/v8/test/inspector/regress/regress-572276137-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-572276137.js create mode 100644 deps/v8/test/inspector/regress/regress-572401025-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-572401025.js create mode 100644 deps/v8/test/inspector/regress/regress-572403047-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-572403047.js create mode 100644 deps/v8/test/inspector/regress/regress-572834323-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-572834323.js create mode 100644 deps/v8/test/inspector/regress/regress-574453614-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-574453614.js create mode 100644 deps/v8/test/inspector/regress/regress-574454550-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-574454550.js create mode 100644 deps/v8/test/inspector/regress/regress-574597225-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-574597225.js create mode 100644 deps/v8/test/inspector/regress/regress-574597313-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-574597313.js create mode 100644 deps/v8/test/inspector/regress/regress-575321664-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575321664.js create mode 100644 deps/v8/test/inspector/regress/regress-575325461-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575325461.js create mode 100644 deps/v8/test/inspector/regress/regress-575735741-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575735741.js create mode 100644 deps/v8/test/inspector/regress/regress-575737154-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575737154.js create mode 100644 deps/v8/test/inspector/regress/regress-575762332-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575762332.js create mode 100644 deps/v8/test/inspector/regress/regress-575806232-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575806232.js create mode 100644 deps/v8/test/inspector/regress/regress-575834150-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575834150.js create mode 100644 deps/v8/test/inspector/regress/regress-575834938-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575834938.js create mode 100644 deps/v8/test/inspector/regress/regress-575835333-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575835333.js create mode 100644 deps/v8/test/inspector/regress/regress-575838270-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575838270.js create mode 100644 deps/v8/test/inspector/regress/regress-575863785-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575863785.js create mode 100644 deps/v8/test/inspector/regress/regress-575876559-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575876559.js create mode 100644 deps/v8/test/inspector/regress/regress-575876890-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575876890.js create mode 100644 deps/v8/test/inspector/regress/regress-575892969-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575892969.js create mode 100644 deps/v8/test/inspector/regress/regress-575895942-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575895942.js create mode 100644 deps/v8/test/inspector/regress/regress-575910950-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-575910950.js create mode 100644 deps/v8/test/inspector/regress/regress-576260517-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-576260517.js create mode 100644 deps/v8/test/inspector/regress/regress-576261017-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-576261017.js create mode 100644 deps/v8/test/inspector/regress/regress-576534261-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-576534261.js create mode 100644 deps/v8/test/inspector/regress/regress-576631304-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-576631304.js create mode 100644 deps/v8/test/inspector/regress/regress-console-assert-termination-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-console-assert-termination.js create mode 100644 deps/v8/test/inspector/regress/regress-console-table-column-getter-throws-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-console-table-column-getter-throws.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-568986689-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-568986689.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-570558711-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-570558711.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571211187-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571211187.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571845147-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571845147.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571979576-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571979576.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571984048-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-571984048.js create mode 100644 deps/v8/test/inspector/regress/regress-crbug-572821841-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-crbug-572821841.js create mode 100644 deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses.js create mode 100644 deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow.js create mode 100644 deps/v8/test/inspector/regress/regress-nested-stack-switch-catch-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-nested-stack-switch-catch.js create mode 100644 deps/v8/test/inspector/regress/regress-proxy-has-command-line-api-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-proxy-has-command-line-api.js create mode 100644 deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install-expected.txt create mode 100644 deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install.js create mode 100644 deps/v8/test/inspector/runtime/console-label-conversion-failure-expected.txt create mode 100644 deps/v8/test/inspector/runtime/console-label-conversion-failure.js create mode 100644 deps/v8/test/inspector/runtime/custom-preview-body-too-long-expected.txt create mode 100644 deps/v8/test/inspector/runtime/custom-preview-body-too-long.js create mode 100644 deps/v8/test/inspector/runtime/custom-preview-long-error-message-expected.txt create mode 100644 deps/v8/test/inspector/runtime/custom-preview-long-error-message.js create mode 100644 deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview-expected.txt create mode 100644 deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview.js create mode 100644 deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result-expected.txt create mode 100644 deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result.js create mode 100644 deps/v8/test/inspector/runtime/import-defer-exception-stack-trace-expected.txt create mode 100644 deps/v8/test/inspector/runtime/import-defer-exception-stack-trace.js create mode 100644 deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-expected.txt create mode 100644 deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope-expected.txt create mode 100644 deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope.js create mode 100644 deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate.js create mode 100644 deps/v8/test/inspector/runtime/internal-entry-cycle-expected.txt create mode 100644 deps/v8/test/inspector/runtime/internal-entry-cycle.js create mode 100644 deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id-expected.txt create mode 100644 deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id.js create mode 100644 deps/v8/test/inspector/runtime/private-methods-description-expected.txt create mode 100644 deps/v8/test/inspector/runtime/private-methods-description.js create mode 100644 deps/v8/test/inspector/runtime/shutdown-pending-evaluate-expected.txt create mode 100644 deps/v8/test/inspector/runtime/shutdown-pending-evaluate.js create mode 100644 deps/v8/test/intl/regress-110086.js create mode 100644 deps/v8/test/message/fail/bundle-duplicate-module.js create mode 100644 deps/v8/test/message/fail/bundle-duplicate-module.out create mode 100644 deps/v8/test/mjsunit/array-index-undefined-optimized.js create mode 100644 deps/v8/test/mjsunit/array-literal-transitions-no-pretenuring.js create mode 100644 deps/v8/test/mjsunit/baseline/embedded-feedback-monotonic.js create mode 100644 deps/v8/test/mjsunit/code-cache-sha256.js delete mode 100644 deps/v8/test/mjsunit/compiler/regress-531297707.js create mode 100644 deps/v8/test/mjsunit/d8/d8-flag-normalization.js delete mode 100644 deps/v8/test/mjsunit/d8/d8-inspector-shutdown-pending-evaluate.js create mode 100644 deps/v8/test/mjsunit/d8/d8-module-tree-rollback.js create mode 100644 deps/v8/test/mjsunit/d8/d8-realm-shared-templates.js create mode 100644 deps/v8/test/mjsunit/d8/d8-test-fast-api-realms.js delete mode 100644 deps/v8/test/mjsunit/d8/flush-denormals-flag.js delete mode 100644 deps/v8/test/mjsunit/d8/flush-denormals-helper.js delete mode 100644 deps/v8/test/mjsunit/d8/flush-denormals-worker.js create mode 100644 deps/v8/test/mjsunit/d8/regress-564550564.js delete mode 100644 deps/v8/test/mjsunit/debug-osr-debug-break.js delete mode 100644 deps/v8/test/mjsunit/debug-osr-step-in-blackboxed.js delete mode 100644 deps/v8/test/mjsunit/debug-osr-step-on-throw-blackboxed.js delete mode 100644 deps/v8/test/mjsunit/debug-osr-step-on-throw.js delete mode 100644 deps/v8/test/mjsunit/debug-osr-step-out.js create mode 100644 deps/v8/test/mjsunit/destructuring-default-maybe-assigned.js create mode 100644 deps/v8/test/mjsunit/disable-eager-inlining-no-non-eager.js create mode 100644 deps/v8/test/mjsunit/disable-eager-inlining.js create mode 100644 deps/v8/test/mjsunit/es6/regress-analyze-partially-arrow-head-lazy.js create mode 100644 deps/v8/test/mjsunit/es6/regress-arrow-cover-grammar-scope.js create mode 100644 deps/v8/test/mjsunit/es6/regress-arrow-head-pattern-error-order.js create mode 100644 deps/v8/test/mjsunit/es6/regress-arrow-reparse-strict-param.js create mode 100644 deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-eos.js create mode 100644 deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-super.js create mode 100644 deps/v8/test/mjsunit/es6/regress-comma-expression-arrow-initializers.js create mode 100644 deps/v8/test/mjsunit/es6/regress-conditional-chain-non-short-circuit.js create mode 100644 deps/v8/test/mjsunit/es6/regress-dynamic-local-param-hole-check.js create mode 100644 deps/v8/test/mjsunit/es6/regress-escaped-contextual-keywords.js create mode 100644 deps/v8/test/mjsunit/es6/regress-eval-var-arguments-default-param.js create mode 100644 deps/v8/test/mjsunit/es6/regress-for-of-async-property.js create mode 100644 deps/v8/test/mjsunit/es6/regress-invalid-lhs-validate-expression.js create mode 100644 deps/v8/test/mjsunit/es6/regress-member-template-expression-scope.js create mode 100644 deps/v8/test/mjsunit/es6/regress-object-rest-property-validation.js create mode 100644 deps/v8/test/mjsunit/es6/regress-preparser-optional-chain-private.js create mode 100644 deps/v8/test/mjsunit/es6/regress-preparser-validate-formals-on-body-error.js create mode 100644 deps/v8/test/mjsunit/es6/regress-private-name-heritage-recalc.js create mode 100644 deps/v8/test/mjsunit/es6/regress-rewriter-completion-values.js create mode 100644 deps/v8/test/mjsunit/es6/regress-static-field-await-identifier.js create mode 100644 deps/v8/test/mjsunit/es6/regress-strict-eval-destructuring-subpattern.js create mode 100644 deps/v8/test/mjsunit/es6/regress-strict-octal-after-rbrace.js create mode 100644 deps/v8/test/mjsunit/es6/regress-strict-param-error-order.js create mode 100644 deps/v8/test/mjsunit/es6/regress-subpattern-validate-expression.js create mode 100644 deps/v8/test/mjsunit/es6/regress-super-optional-chain.js create mode 100644 deps/v8/test/mjsunit/es6/regress-yield-expression-scope.js create mode 100644 deps/v8/test/mjsunit/es8/regress-async-arrow-scope-and-new.js create mode 100644 deps/v8/test/mjsunit/es8/regress-lazy-arrow-formal-params-function-state.js create mode 100644 deps/v8/test/mjsunit/harmony/modules-import-defer-stack-trace.js create mode 100644 deps/v8/test/mjsunit/harmony/modules-import-defer-terminate.mjs create mode 100644 deps/v8/test/mjsunit/harmony/modules-using-export.mjs create mode 100644 deps/v8/test/mjsunit/harmony/regexp-unicode-sets-class-string-disjunction.js create mode 100644 deps/v8/test/mjsunit/harmony/regress-auto-accessor-tostring.js create mode 100644 deps/v8/test/mjsunit/harmony/regress-class-reparse-no-lazy-and-brand-check-pos.js create mode 100644 deps/v8/test/mjsunit/harmony/regress-for-using-closure-assignment.js create mode 100644 deps/v8/test/mjsunit/harmony/regress-private-name-heritage-catch-eval.js delete mode 100644 deps/v8/test/mjsunit/harmony/regress/regress-520728938.js create mode 100644 deps/v8/test/mjsunit/lower_limits_mode/regress/regress-571759664.js create mode 100644 deps/v8/test/mjsunit/maglev/branch-if-int32-bitwise-and-nonzero.js create mode 100644 deps/v8/test/mjsunit/maglev/create-closure-top-level.js delete mode 100644 deps/v8/test/mjsunit/maglev/define-const-data-field-spread-literal.js create mode 100644 deps/v8/test/mjsunit/maglev/int32-div-const-fold.js delete mode 100644 deps/v8/test/mjsunit/maglev/new-closure-tenured.js create mode 100644 deps/v8/test/mjsunit/maglev/read-only-constant-compare.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-563882510.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569212098.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569376794-1.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569376794-2.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-569947577.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-570091260.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-573856023.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-574021176.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-574412712.js create mode 100644 deps/v8/test/mjsunit/maglev/regress-577954376.js create mode 100644 deps/v8/test/mjsunit/maglev/spread-rest-parameter-element-mutation.js delete mode 100644 deps/v8/test/mjsunit/math-sum-precise/iterator-clear-on-error.js create mode 100644 deps/v8/test/mjsunit/math-sum-precise/iterator-not-exhausted-on-error.js delete mode 100644 deps/v8/test/mjsunit/math-sum-precise/set-iterator-clear-on-error.js create mode 100644 deps/v8/test/mjsunit/math-sum-precise/set-iterator-not-exhausted-on-error.js create mode 100644 deps/v8/test/mjsunit/math-sum-precise/uncaught-error-message.js create mode 100644 deps/v8/test/mjsunit/parser/array-literal-fast-path.js create mode 100644 deps/v8/test/mjsunit/regexp-boyer-moore-backtrack.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-440528038.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-514561070.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-516022777.js create mode 100644 deps/v8/test/mjsunit/regress/regress-521520188.js create mode 100644 deps/v8/test/mjsunit/regress/regress-523431532.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-532288251.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-532720981.js create mode 100644 deps/v8/test/mjsunit/regress/regress-535071448.js create mode 100644 deps/v8/test/mjsunit/regress/regress-544787343.js create mode 100644 deps/v8/test/mjsunit/regress/regress-546370272.js create mode 100644 deps/v8/test/mjsunit/regress/regress-557076207.js create mode 100644 deps/v8/test/mjsunit/regress/regress-561116894.js create mode 100644 deps/v8/test/mjsunit/regress/regress-561672123.js create mode 100644 deps/v8/test/mjsunit/regress/regress-561799397.mjs create mode 100644 deps/v8/test/mjsunit/regress/regress-564012076.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564879562.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-3.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-4.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-5.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-6.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-7.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275-8.js create mode 100644 deps/v8/test/mjsunit/regress/regress-564880275.js create mode 100644 deps/v8/test/mjsunit/regress/regress-566415771.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567222737-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567222737-3.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567222737-4.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567222737-5.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567222737-6.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567222737.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567574900.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567576220.js create mode 100644 deps/v8/test/mjsunit/regress/regress-567827593.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568341998.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568633429.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568654095.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568794851.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568893995-1.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568893995-2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-568893995-3.js create mode 100644 deps/v8/test/mjsunit/regress/regress-569056575.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571397035.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571565364-empty.txt create mode 100644 deps/v8/test/mjsunit/regress/regress-571565364.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571811885.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571853016.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571871980.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571944332.js create mode 100644 deps/v8/test/mjsunit/regress/regress-571975489.js create mode 100644 deps/v8/test/mjsunit/regress/regress-572400584.js create mode 100644 deps/v8/test/mjsunit/regress/regress-572988453.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573037572.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573038326.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573048357.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573048572.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573263262.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573471186.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573777594.js create mode 100644 deps/v8/test/mjsunit/regress/regress-573962535.js create mode 100644 deps/v8/test/mjsunit/regress/regress-574038247.js create mode 100644 deps/v8/test/mjsunit/regress/regress-575750485.js create mode 100644 deps/v8/test/mjsunit/regress/regress-575820656.js create mode 100644 deps/v8/test/mjsunit/regress/regress-576225189.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-540324230.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-572331419.js create mode 100644 deps/v8/test/mjsunit/regress/regress-declare-arguments-maybe-assigned.js create mode 100644 deps/v8/test/mjsunit/regress/regress-fast-proxy-deprecated-map.js create mode 100644 deps/v8/test/mjsunit/regress/regress-fast-proxy-keyed-miss.js create mode 100644 deps/v8/test/mjsunit/regress/regress-fast-proxy-target-toctou.js create mode 100644 deps/v8/test/mjsunit/regress/regress-memory-pool-release-task.js create mode 100644 deps/v8/test/mjsunit/regress/regress-preparser-eval-default-params.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-502287689.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-513413942.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-519715438.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-526163463.js delete mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-527985808.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-533578412.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-563068683.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-565341967.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-566359200.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-566727937.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-567126756.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-567171844.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-567481597.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-567624365.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-567911985.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-568629618.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-568806936.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-569071532.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-570433240.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-570433264.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-571155505.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-571348848.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-571700025.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-571812798.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-572399938.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-572627851.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573042748.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573260377.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573446890.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573498301.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573612775.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573816513.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573866983.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-573974793.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-574681855.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-574704749.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-574824670.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-575514140.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-575829159.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-575926503.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-576112595.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-577305505.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-array-segment-args.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-cast-nofunc.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exception-null.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exnref.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-context.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-null.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-return-call-subtype.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-v128-js-boundary.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-simd-570497964.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-simd-573671130.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-simd-573671231.js create mode 100644 deps/v8/test/mjsunit/sandbox/fixed-double-array-field-count.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-558640961.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-560980980.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-564835629.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-564835816.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-566142291.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-567222739.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-569548220.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-571126471.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress-571127829.js delete mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-502337304.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-555304822.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-560536734.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-567526351.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-572826713.js create mode 100644 deps/v8/test/mjsunit/sandbox/regress/regress-574792351.js create mode 100644 deps/v8/test/mjsunit/sandbox/wasm-interpreter-reentrant-throw-overlap.js create mode 100644 deps/v8/test/mjsunit/sandbox/wasm-suspender-stack-reference.js create mode 100644 deps/v8/test/mjsunit/sandbox/wasmfx-jspi-uaf.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/condition-workers.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/condition.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/mutex-lock-twice.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/mutex-workers.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/mutex.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/regress-524783017.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/regress-crbug-1449611.js delete mode 100644 deps/v8/test/mjsunit/shared-memory/regress-crbug-333007256.js create mode 100644 deps/v8/test/mjsunit/string-index-undefined-optimized.js create mode 100644 deps/v8/test/mjsunit/turbolev/create-closure-top-level.js create mode 100644 deps/v8/test/mjsunit/turbolev/escape-analysis-regress-561781465.js create mode 100644 deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692-array-at.js create mode 100644 deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692.js create mode 100644 deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder-holey.js create mode 100644 deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder.js create mode 100644 deps/v8/test/mjsunit/turbolev/loop-in-maglev-but-not-turboshaft.js delete mode 100644 deps/v8/test/mjsunit/turbolev/new-closure-tenured.js create mode 100644 deps/v8/test/mjsunit/turbolev/regress-564329221.js create mode 100644 deps/v8/test/mjsunit/turbolev/regress-567993838.js create mode 100644 deps/v8/test/mjsunit/turbolev/regress-568010379.js create mode 100644 deps/v8/test/mjsunit/turbolev/regress-571002038.js create mode 100644 deps/v8/test/mjsunit/turbolev/regress-forin-type-confusion.js create mode 100644 deps/v8/test/mjsunit/turbolev/store-const-heap-number.js create mode 100644 deps/v8/test/mjsunit/turboshaft/couldhavesamemap-poly-poly.js create mode 100644 deps/v8/test/mjsunit/turboshaft/reduce-strictly-less-than.js create mode 100644 deps/v8/test/mjsunit/turboshaft/regress-574660146.js create mode 100644 deps/v8/test/mjsunit/wasm/compilation-hints/hints-and-deopts.js delete mode 100644 deps/v8/test/mjsunit/wasm/debug-set-breakpoint-on-entry.js delete mode 100644 deps/v8/test/mjsunit/wasm/denormals.js create mode 100644 deps/v8/test/mjsunit/wasm/gc-casts-branch.js create mode 100644 deps/v8/test/mjsunit/wasm/growable-stacks-simd.js delete mode 100644 deps/v8/test/mjsunit/wasm/regress-534579660.js create mode 100644 deps/v8/test/mjsunit/wasm/regress-535877252-2.js create mode 100644 deps/v8/test/mjsunit/wasm/regress-535877252.js create mode 100644 deps/v8/test/mjsunit/wasm/regress-569014241.js create mode 100644 deps/v8/test/mjsunit/wasm/regress-576453351.js delete mode 100644 deps/v8/test/mjsunit/wasm/regress-nested-stack-switch-catch.js delete mode 100644 deps/v8/test/mjsunit/wasm/regression-521715545.js create mode 100644 deps/v8/test/mjsunit/wasm/shared-memory-grow-bounds-check.js create mode 100644 deps/v8/test/mjsunit/wasm/shared-memory-size-atomic.js create mode 100644 deps/v8/test/mjsunit/wasm/simd-add-sub-high-narrow.js create mode 100644 deps/v8/test/mjsunit/wasm/simd-i64x2-mul-mixed-sign.js create mode 100644 deps/v8/test/mjsunit/wasm/simd-narrow-interleave.js create mode 100644 deps/v8/test/mjsunit/wasm/simd-shift-left-long.js create mode 100644 deps/v8/test/mjsunit/wasm/stack-switching-profiler.js create mode 100644 deps/v8/test/mjsunit/wasm/test-growable-tail-call-matrix.js create mode 100644 deps/v8/test/mjsunit/wasm/test-growable-tail-call-stack-params.js create mode 100644 deps/v8/test/unittests/base/growing-circular-queue-unittest.cc create mode 100644 deps/v8/test/unittests/base/unique-array-unittest.cc create mode 100644 deps/v8/test/unittests/compiler/turboshaft/duplication-optimization-reducer-unittest.cc delete mode 100644 deps/v8/test/unittests/compiler/wasm-address-reassociation-unittest.cc rename deps/v8/test/{cctest/heap/test-array-buffer-sweeper.cc => unittests/heap/array-buffer-sweeper-unittest.cc} (55%) rename deps/v8/test/{cctest/heap/test-concurrent-allocation.cc => unittests/heap/concurrent-allocation-unittest.cc} (53%) rename deps/v8/test/{cctest/heap/test-external-string-tracker.cc => unittests/heap/external-string-tracker-unittest.cc} (53%) create mode 100644 deps/v8/test/unittests/heap/mark-compact-unittest.cc create mode 100644 deps/v8/test/unittests/heap/memory-measurement-unittest.cc delete mode 100644 deps/v8/test/unittests/heap/pool-unittest.cc rename deps/v8/test/{cctest/heap/test-weak-references.cc => unittests/heap/weak-references-unittest.cc} (58%) delete mode 100644 deps/v8/test/unittests/js-atomics/js-atomics-synchronization-primitive-unittest.cc create mode 100644 deps/v8/test/unittests/objects/casting-unittest.cc create mode 100644 deps/v8/test/unittests/sandbox/code-cache-unittest.cc rename deps/v8/test/{cctest => unittests}/wasm/DEPS (67%) rename deps/v8/test/{cctest/wasm/test-backing-store.cc => unittests/wasm/backing-store-unittest.cc} (78%) rename deps/v8/test/{cctest/wasm/test-c-wasm-entry.cc => unittests/wasm/c-wasm-entry-unittest.cc} (93%) rename deps/v8/test/{cctest/wasm/test-compilation-cache.cc => unittests/wasm/compilation-cache-unittest.cc} (79%) rename deps/v8/test/{cctest/wasm/test-fuzzer-steps.cc => unittests/wasm/fuzzer-steps-unittest.cc} (85%) rename deps/v8/test/{cctest/wasm/test-gc.cc => unittests/wasm/gc-unittest.cc} (99%) rename deps/v8/test/{cctest/wasm/test-grow-memory.cc => unittests/wasm/grow-memory-unittest.cc} (86%) rename deps/v8/test/{cctest/wasm/test-jump-table-assembler.cc => unittests/wasm/jump-table-assembler-unittest.cc} (89%) rename deps/v8/test/{cctest/wasm/test-liftoff-for-fuzzing.cc => unittests/wasm/liftoff-for-fuzzing-unittest.cc} (78%) rename deps/v8/test/{cctest/wasm/test-liftoff-inspection.cc => unittests/wasm/liftoff-inspection-unittest.cc} (94%) rename deps/v8/test/{cctest => unittests/wasm}/manually-externalized-buffer.h (76%) rename deps/v8/test/{cctest/wasm/test-run-wasm-64.cc => unittests/wasm/run-wasm-64-unittest.cc} (99%) rename deps/v8/test/{cctest/wasm/test-run-wasm-atomics.cc => unittests/wasm/run-wasm-atomics-unittest.cc} (99%) rename deps/v8/test/{cctest/wasm/test-run-wasm-atomics64.cc => unittests/wasm/run-wasm-atomics64-unittest.cc} (99%) rename deps/v8/test/{cctest/wasm/test-run-wasm-bulk-memory.cc => unittests/wasm/run-wasm-bulk-memory-unittest.cc} (98%) rename deps/v8/test/{cctest/wasm/test-run-wasm-exceptions.cc => unittests/wasm/run-wasm-exceptions-unittest.cc} (95%) create mode 100644 deps/v8/test/unittests/wasm/run-wasm-f16-unittest.cc rename deps/v8/test/{cctest/wasm/test-run-wasm-js.cc => unittests/wasm/run-wasm-js-unittest.cc} (87%) rename deps/v8/test/{cctest/wasm/test-run-wasm-memory64.cc => unittests/wasm/run-wasm-memory64-unittest.cc} (93%) rename deps/v8/test/{cctest/wasm/test-run-wasm-module.cc => unittests/wasm/run-wasm-module-unittest.cc} (80%) rename deps/v8/test/{cctest/wasm/test-run-wasm-relaxed-simd.cc => unittests/wasm/run-wasm-relaxed-simd-unittest.cc} (96%) rename deps/v8/test/{cctest/wasm/test-run-wasm-sign-extension.cc => unittests/wasm/run-wasm-sign-extension-unittest.cc} (90%) rename deps/v8/test/{cctest/wasm/test-run-wasm-simd-liftoff.cc => unittests/wasm/run-wasm-simd-liftoff-unittest.cc} (94%) rename deps/v8/test/{cctest/wasm/test-run-wasm-simd.cc => unittests/wasm/run-wasm-simd-unittest.cc} (96%) rename deps/v8/test/{cctest/wasm/test-run-wasm.cc => unittests/wasm/run-wasm-unittest.cc} (98%) rename deps/v8/test/{cctest/wasm/test-run-wasm-wrappers.cc => unittests/wasm/run-wasm-wrappers-unittest.cc} (94%) rename deps/v8/test/{cctest/wasm/test-streaming-compilation.cc => unittests/wasm/streaming-compilation-unittest.cc} (88%) rename deps/v8/test/{cctest => unittests}/wasm/wasm-atomics-utils.h (86%) rename deps/v8/test/{cctest/wasm/test-wasm-breakpoints.cc => unittests/wasm/wasm-breakpoints-unittest.cc} (86%) rename deps/v8/test/{cctest/wasm/test-wasm-codegen.cc => unittests/wasm/wasm-codegen-unittest.cc} (89%) rename deps/v8/test/{cctest/wasm/test-wasm-import-wrapper-cache.cc => unittests/wasm/wasm-import-wrapper-cache-unittest.cc} (92%) rename deps/v8/test/{cctest/wasm/test-wasm-metrics.cc => unittests/wasm/wasm-metrics-unittest.cc} (74%) create mode 100644 deps/v8/test/unittests/wasm/wasm-runner.h rename deps/v8/test/{cctest/wasm/test-wasm-serialization.cc => unittests/wasm/wasm-serialization-unittest.cc} (74%) rename deps/v8/test/{cctest/wasm/test-wasm-shared-engine.cc => unittests/wasm/wasm-shared-engine-unittest.cc} (77%) rename deps/v8/test/{cctest => unittests}/wasm/wasm-simd-utils.cc (99%) rename deps/v8/test/{cctest => unittests}/wasm/wasm-simd-utils.h (98%) rename deps/v8/test/{cctest/wasm/test-wasm-stack.cc => unittests/wasm/wasm-stack-unittest.cc} (96%) rename deps/v8/test/{cctest/wasm/test-wasm-strings.cc => unittests/wasm/wasm-strings-unittest.cc} (98%) rename deps/v8/test/{cctest/wasm/test-wasm-trap-position.cc => unittests/wasm/wasm-trap-position-unittest.cc} (94%) delete mode 100644 deps/v8/test/unittests/zone/zone-chunk-list-unittest.cc create mode 100644 deps/v8/third_party/abseil-cpp/.bazelrc create mode 100644 deps/v8/third_party/abseil-cpp/absl/container/btree_instantiate_test.cc delete mode 100644 deps/v8/third_party/abseil-cpp/patches/0004-string-view-transitive-includes create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/poll_macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/poll_overlay.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/sys_eventfd_macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/sys_inotify_macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/sys_socket_overlay.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/sys_xattr_macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/types/fpos_t.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/types/idtype_t.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/types/struct___pthread_cleanup_frame.h create mode 100644 deps/v8/third_party/llvm-libc/src/hdr/types/struct_ether_addr.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/libintl.yaml create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/common-threads-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-eventfd-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-inotify-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-xattr-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-eventfd-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-inotify-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-xattr-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/threads-macros.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fpos_t.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/idtype_t.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifmap.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifreq.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct___pthread_cleanup_frame.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ether_addr.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_inotify_event.h create mode 100644 deps/v8/third_party/llvm-libc/src/include/net/ethernet.yaml create mode 100644 deps/v8/third_party/llvm-libc/src/include/netinet/ether.yaml create mode 100644 deps/v8/third_party/llvm-libc/src/include/sys/eventfd.yaml create mode 100644 deps/v8/third_party/llvm-libc/src/include/sys/inotify.yaml create mode 100644 deps/v8/third_party/llvm-libc/src/shared/bit.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfdf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfsf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/builtins/extendhftf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/builtins/truncdfhf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/builtins/truncsfhf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/builtins/trunctfhf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/math/exp2bf16.h create mode 100644 deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/exp2f.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/CPP/unique_ptr.h delete mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/CPP/vector.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/fp_bitwise.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/hexagon/FEnvImpl.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/is_integer.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/File/dir_scan_impl.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/File/file_io_result.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.cpp create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/shell_fork.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/sigmask.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/aarch64/clone.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/clone.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/epoll_ctl.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/eventfd.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/execveat.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchownat.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fdatasync.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcpu.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_add_watch.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init1.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_rm_watch.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lchown.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pause.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pipe2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ppoll.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/renameat.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/riscv/clone.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_max.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_min.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_rr_get_interval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setaffinity.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setparam.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_yield.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgroups.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresgid.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresuid.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sync.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/syncfs.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/timer_getoverrun.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/waitid.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/x86_64/clone.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfdf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfsf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhftf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncdfhf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncsfhf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/builtins/trunctfhf2.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_double_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_float_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_accurate_128.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_double_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp2bf16.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_utils.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_utils.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_utils.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/powf_double_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/powf_float_eval.h delete mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/powf_small_tables.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/powf_utils.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_double_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_float_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_double_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_float_eval.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_internal.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.cpp create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.cpp create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/cleanup_stack.h create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/CMakeLists.txt create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/tls.cpp create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/CMakeLists.txt create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/tls.cpp create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/CMakeLists.txt create mode 100644 deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/tls.cpp create mode 100644 deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_experiments_regexp.json create mode 100644 deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags_regexp.json create mode 100644 deps/v8/tools/compare-checked-in-headers.py create mode 100644 deps/v8/tools/debug_helper/plugins/test/fixtures/args-mismatch.js create mode 100644 deps/v8/tools/debug_helper/plugins/test/helpers/args.py create mode 100644 deps/v8/tools/dev/gen-checked-in-headers.py create mode 100644 deps/v8/tools/jj/README.md create mode 100644 deps/v8/tools/jj/config.toml create mode 100644 deps/v8/tools/metagen/PRESUBMIT.py delete mode 100644 deps/v8/tools/metagen/compile_flags_test.py create mode 100644 deps/v8/tools/metagen/layout_extract.py create mode 100644 deps/v8/tools/metagen/layout_ir.py create mode 100644 deps/v8/tools/metagen/test/compile_flags_test.py create mode 100644 deps/v8/tools/metagen/test/instance_types_test.py create mode 100644 deps/v8/tools/metagen/test/metagen_test.py create mode 100644 deps/v8/tools/metagen/tests/layout_extract_test.py create mode 100644 deps/v8/tools/metagen/tests/layout_ir_test.py create mode 100644 deps/v8/tools/regexp/correctness_fuzzer/harness.py create mode 100755 deps/v8/tools/regexp/correctness_fuzzer/package.sh create mode 100755 deps/v8/tools/regexp/correctness_fuzzer/run.py create mode 100755 deps/v8/tools/regexp/correctness_fuzzer/run_locally_against_foozzie.py create mode 100644 deps/v8/tools/testrunner/local/command_test.py create mode 100755 deps/v8/tools/turbolizer/cli.js diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 31ac08aa8ddb..4e43ea3d7e14 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -46,6 +46,7 @@ Alibaba, Inc. <*@alibaba-inc.com> SiFive, Inc. <*@sifive.com> Island Technology, Inc. <*@island.io> Xperi Corporation <*@xperi.com> +Datadog, Inc. <*@datadoghq.com> Aapo Alasuutari Aaron Bieber @@ -80,6 +81,7 @@ Artem Kobzar Arthur Islamov Asuka Shikina Aurèle Barrière +Austin Burdine Aviv Keller Ayako Hayasaka Bala Avulapati @@ -103,6 +105,7 @@ Cheng Zhao Chengzhong Wu Choongwoo Han Chris Nardi +Christian Aurich Zanettini Martins Christopher A. Taylor Christopher Nady Colin Ihrig @@ -229,6 +232,7 @@ Marcin Cieślak Marcin Wiącek Marisa Kirisame Martin Bidlingmaier +Mateusz Burzyński Mateusz Czeladka Matheus Marchini Matheus Marchini @@ -263,6 +267,7 @@ Oliver Dunk Paolo Giarrusso Patrick Gansterer Paul Lind +Pavel Atamanov Pavel Medvedev Pedro Falcato Peng Fei @@ -291,6 +296,7 @@ Robert O'Callahan Rong Wang Ross Kirsling Ruben Bridgewater +Rudolf Meijering Ryan Dahl Sahil Shaikh Sakthipriyan Vairamani (thefourtheye) @@ -318,6 +324,7 @@ Steven R. Loomis Sylvestre Ledru Takeshi Yoneda Taketoshi Aono +Tamir Duberstein Tao Liqiang Tao Wang Teddy Katz @@ -330,6 +337,7 @@ Tobias Burnus Tobias Nießen Tomasz Malinowski Ujjwal Sharma +V8 AIRC Bot Vadim Gorbachev Varun Varada Victor Costan @@ -352,6 +360,7 @@ Wouter Vermeiren Xiaofang Zou Xiaoyin Liu Yagiz Nizipli +Yaksh Bariya Yanbo Li Yannic Bonenberger Yi Wang @@ -364,6 +373,7 @@ Yuri Iozzelli Yuri Gaevsky Yusif Khudhur Yuxiang Cao +Yuya Inoue Zac Hansen Zeynep Cankara Zhao Jiazhong @@ -381,6 +391,7 @@ magic-akari Ryuhei Shima Domagoj Stolfa Zhijin Zeng +Zhiyan Deng 王家睿 Julian Gremminger Liam Wachter diff --git a/deps/v8/BUILD.bazel b/deps/v8/BUILD.bazel index 914fe144311e..2168c198c783 100644 --- a/deps/v8/BUILD.bazel +++ b/deps/v8/BUILD.bazel @@ -9,7 +9,7 @@ load("@rules_python//python:defs.bzl", "py_binary", "py_test") load("@v8_python_deps//:requirements.bzl", "requirement") load( "@v8//:bazel/defs.bzl", - "metagen_instance_types", + "run_metagen", "v8_binary", "v8_build_config", "v8_config", @@ -19,9 +19,8 @@ load( "v8_library", "v8_mksnapshot", "v8_string", - "v8_torque_files", ) -load(":bazel/v8-non-pointer-compression.bzl", "v8_binary_non_pointer_compression") +load(":bazel/v8-generators.bzl", "v8_torque_files") # ================================================= # Flags @@ -178,14 +177,17 @@ v8_flag( v8_flag(name = "v8_enable_experimental_tq_to_tsa") -# Mirrors the GN arg of the same name: selects which instance-type -# generator's output V8 compiles in, metagen or Torque's emission. When -# off, the metagen action is not part of the build graph. +# Mirrors the GN arg of the same name: selects metagen's instance types and +# object layouts. When off, the metagen action is not part of the build graph. v8_flag( - name = "v8_use_metagen_instance_types", + name = "v8_use_metagen", default = True, ) +# Empty selects the default for the target OS. Set to "gcc" or "cl" when +# the C++ toolchain uses a different driver mode. +v8_string(name = "v8_metagen_driver_mode") + v8_flag( name = "v8_use_host_cpu_arm_features", default = True, @@ -266,6 +268,21 @@ v8_flag( default = False, ) +v8_flag( + name = "v8_x64_16byte_stack_alignment", + default = False, +) + +v8_flag( + name = "v8_support_la57", + default = True, +) + +v8_flag( + name = "v8_enable_ecma402_icu4x", + default = False, +) + selects.config_setting_group( name = "enable_drumbrake_x64", match_all = [ @@ -315,6 +332,14 @@ selects.config_setting_group( ], ) +selects.config_setting_group( + name = "webassembly_on_arm64_simulator", + match_all = [ + "@v8//bazel/config:v8_arm64_simulator", + ":is_v8_enable_webassembly", + ], +) + v8_flag( name = "v8_jitless", default = False, @@ -325,6 +350,11 @@ v8_int( default = 64, ) +v8_int( + name = "v8_embedder_data_array_size", + default = 5, +) + # We use a string flag to create a 3 value-logic. # If no explicit value for v8_enable_pointer_compression, we set it to 'none'. v8_string( @@ -410,12 +440,12 @@ v8_flag( default = True, ) -# Enable support for external code range if enable_pointer_compression_shared_cage and +# Enable support for external code range if v8_enable_pointer_compression and # v8_enable_external_code_space. selects.config_setting_group( name = "enable_external_code_space", match_all = [ - ":enable_pointer_compression_shared_cage", + ":is_v8_enable_pointer_compression", ":is_v8_enable_external_code_space", ], ) @@ -545,18 +575,22 @@ v8_config( "v8_enable_vtunejit": "ENABLE_VTUNE_JIT_INTERFACE", "v8_enable_undefined_double": "V8_ENABLE_UNDEFINED_DOUBLE", "v8_use_host_cpu_arm_features": "V8_USE_HOST_CPU_ARM_FEATURES", + "v8_x64_16byte_stack_alignment": "V8_X64_16BYTE_STACK_ALIGNMENT", + "v8_support_la57": "V8_SUPPORT_LA57", + "v8_enable_ecma402_icu4x": "V8_ENABLE_ECMA402_ICU4X", }, defines = [ "GOOGLE3", "V8_ADVANCED_BIGINT_ALGORITHMS", + "V8_ALLOCATION_SITE_TRACKING", "V8_CONCURRENT_MARKING", "V8_ENABLE_SPARKPLUG", "V8_ENABLE_EXTENSIBLE_RO_SNAPSHOT", "V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA", "V8_TLS_USED_IN_LIBRARY", ] + select({ - ":is_not_v8_use_metagen_instance_types": [ - "V8_USE_METAGEN_INSTANCE_TYPES=0", + ":is_not_v8_use_metagen": [ + "V8_USE_METAGEN=0", ], "//conditions:default": [], }) + select({ @@ -889,11 +923,10 @@ filegroup( "src/base/file-utils.h", "src/base/flags.h", "src/base/float16.h", - "src/base/fpu.cc", - "src/base/fpu.h", "src/base/functional/bind-internal.h", "src/base/functional/function-ref.h", "src/base/free_deleter.h", + "src/base/growing-circular-queue.h", "src/base/hashing.h", "src/base/hashmap.h", "src/base/hashmap-entry.h", @@ -986,6 +1019,7 @@ filegroup( "src/base/threaded-list.h", "src/base/timezone-cache.h", "src/base/types/is-instantiation.h", + "src/base/unique-array.h", "src/base/utils/random-number-generator.cc", "src/base/utils/random-number-generator.h", "src/base/vector.h", @@ -1278,7 +1312,6 @@ filegroup( "src/objects/heap-object.tq", "src/objects/js-array.tq", "src/objects/js-array-buffer.tq", - "src/objects/js-atomics-synchronization.tq", "src/objects/js-collection.tq", "src/objects/js-collection-iterator.tq", "src/objects/js-disposable-stack.tq", @@ -1402,6 +1435,12 @@ filegroup( "src/torque/instructions.h", "src/torque/kythe-data.cc", "src/torque/kythe-data.h", + "src/torque/layout-loader.cc", + "src/torque/layout-loader.h", + "src/torque/ls/json.cc", + "src/torque/ls/json.h", + "src/torque/ls/json-parser.cc", + "src/torque/ls/json-parser.h", "src/torque/parameter-difference.h", "src/torque/server-data.cc", "src/torque/server-data.h", @@ -1491,13 +1530,13 @@ filegroup( "src/builtins/builtins.cc", "src/builtins/builtins-inl.h", "src/builtins/builtins.h", + "src/builtins/bytecodes-builtins-list.h", "src/builtins/builtins-abstract-module-source.cc", "src/builtins/builtins-api.cc", "src/builtins/builtins-array.cc", "src/builtins/builtins-arraybuffer.cc", "src/builtins/builtins-async-disposable-stack.cc", "src/builtins/builtins-async-module.cc", - "src/builtins/builtins-atomics-synchronization.cc", "src/builtins/builtins-bigint.cc", "src/builtins/builtins-callsite.cc", "src/builtins/builtins-collections.cc", @@ -2124,6 +2163,7 @@ filegroup( "src/objects/backing-store.h", "src/objects/bigint.cc", "src/objects/bigint.h", + "src/objects/bit-field-group.h", "src/objects/bytecode-array.cc", "src/objects/bytecode-array.h", "src/objects/bytecode-array-inl.h", @@ -2221,9 +2261,6 @@ filegroup( "src/objects/js-array-buffer.h", "src/objects/js-array-buffer-inl.h", "src/objects/js-array-inl.h", - "src/objects/js-atomics-synchronization.cc", - "src/objects/js-atomics-synchronization.h", - "src/objects/js-atomics-synchronization-inl.h", "src/objects/js-collection.h", "src/objects/js-collection-inl.h", "src/objects/js-collection-iterator.h", @@ -2331,8 +2368,6 @@ filegroup( "src/objects/hole.h", "src/objects/trusted-object.h", "src/objects/trusted-object-inl.h", - "src/objects/trusted-pointer.h", - "src/objects/trusted-pointer-inl.h", "src/objects/option-utils.cc", "src/objects/option-utils.h", "src/objects/ordered-hash-table.cc", @@ -2435,8 +2470,6 @@ filegroup( "src/objects/visitors.cc", "src/objects/visitors.h", "src/objects/visitors-inl.h", - "src/objects/waiter-queue-node.cc", - "src/objects/waiter-queue-node.h", "src/parsing/expression-scope.h", "src/parsing/func-name-inferrer.cc", "src/parsing/func-name-inferrer.h", @@ -2564,10 +2597,10 @@ filegroup( "src/roots/roots.h", "src/roots/roots-inl.h", "src/roots/static-roots.h", - "src/roots/static-roots-intl-nowasm.h", - "src/roots/static-roots-intl-wasm.h", - "src/roots/static-roots-nointl-nowasm.h", - "src/roots/static-roots-nointl-wasm.h", + "src/gen/intl-nowasm/static-roots.h", + "src/gen/intl-wasm/static-roots.h", + "src/gen/nointl-nowasm/static-roots.h", + "src/gen/nointl-wasm/static-roots.h", "src/runtime/runtime.cc", "src/runtime/runtime.h", "src/runtime/runtime-array.cc", @@ -2631,9 +2664,9 @@ filegroup( "src/sandbox/external-strings-cage.h", "src/sandbox/isolate.h", "src/sandbox/isolate-inl.h", - "src/sandbox/indirect-pointer.h", - "src/sandbox/indirect-pointer-tag.h", - "src/sandbox/indirect-pointer-inl.h", + "src/sandbox/trusted-pointer.h", + "src/sandbox/trusted-pointer-tag.h", + "src/sandbox/trusted-pointer-inl.h", "src/sandbox/code-entrypoint-tag.h", "src/sandbox/external-entity-table.h", "src/sandbox/external-entity-table-inl.h", @@ -2644,6 +2677,7 @@ filegroup( "src/sandbox/sandboxable-thread.cc", "src/sandbox/sandboxable-thread.h", "src/sandbox/sandbox-malloc.h", + "src/sandbox/sandbox-zero-segment.h", "src/sandbox/sandboxed-pointer.h", "src/sandbox/sandboxed-pointer-inl.h", "src/sandbox/segmented-table.cc", @@ -2702,6 +2736,8 @@ filegroup( "src/snapshot/startup-deserializer.h", "src/snapshot/startup-serializer.cc", "src/snapshot/startup-serializer.h", + "src/snapshot/trusted-section-serializer.cc", + "src/snapshot/trusted-section-serializer.h", "src/strings/char-predicates.h", "src/strings/char-predicates-inl.h", "src/strings/owning-external-string-resource.h", @@ -2776,7 +2812,6 @@ filegroup( "src/zone/zone.cc", "src/zone/zone.h", "src/zone/zone-allocator.h", - "src/zone/zone-chunk-list.h", "src/zone/zone-compact-set.h", "src/zone/zone-containers.h", "src/zone/zone-hashmap.h", @@ -3034,7 +3069,7 @@ filegroup( ], "//conditions:default": [], }) + select({ - "@v8//bazel/config:v8_arm64_simulator": [ + ":webassembly_on_arm64_simulator": [ "src/trap-handler/handler-outside-simulator.cc", "src/trap-handler/trap-handler-simulator.h", ], @@ -3072,6 +3107,7 @@ filegroup( "src/maglev/maglev-interpreter-frame-state.h", "src/maglev/maglev-ir-inl.h", "src/maglev/maglev-ir.h", + "src/maglev/maglev-kna-map.h", "src/maglev/maglev-kna-processor.h", "src/maglev/maglev-map-inference.h", "src/maglev/maglev-node-type.h", @@ -3092,6 +3128,7 @@ filegroup( "src/maglev/maglev-register-frame-array.h", "src/maglev/maglev.h", "src/maglev/maglev-assembler.cc", + "src/maglev/maglev-basic-block.cc", "src/maglev/maglev-code-generator.cc", "src/maglev/maglev-compilation-info.cc", "src/maglev/maglev-compilation-unit.cc", @@ -3350,6 +3387,8 @@ filegroup( "src/objects/js-plural-rules.cc", "src/objects/js-plural-rules.h", "src/objects/js-plural-rules-inl.h", + "src/objects/js-plural-rules-internal.cc", + "src/objects/js-plural-rules-internal.h", "src/objects/js-relative-time-format.cc", "src/objects/js-relative-time-format.h", "src/objects/js-relative-time-format-inl.h", @@ -3524,10 +3563,6 @@ filegroup( "src/compiler/machine-operator-reducer.h", "src/compiler/map-inference.cc", "src/compiler/map-inference.h", - "src/compiler/memory-lowering.cc", - "src/compiler/memory-lowering.h", - "src/compiler/memory-optimizer.cc", - "src/compiler/memory-optimizer.h", "src/compiler/node.cc", "src/compiler/node.h", "src/compiler/node-aux-data.h", @@ -3850,8 +3885,6 @@ filegroup( "src/compiler/turboshaft/wasm-shuffle-reducer.h", "src/compiler/turboshaft/wasm-simd-phase.cc", "src/compiler/turboshaft/wasm-simd-phase.h", - "src/compiler/wasm-address-reassociation.cc", - "src/compiler/wasm-address-reassociation.h", "src/compiler/wasm-call-descriptors.cc", "src/compiler/wasm-call-descriptors.h", "src/compiler/wasm-compiler.cc", @@ -3880,6 +3913,7 @@ filegroup( ":enable_maglev": [], "//conditions:default": [ "src/maglev/hamt.h", + "src/maglev/maglev-basic-block.cc", "src/maglev/maglev-basic-block.h", "src/maglev/maglev-code-gen-state.h", "src/maglev/maglev-code-gen-state-inl.h", @@ -3916,6 +3950,7 @@ filegroup( "src/maglev/maglev-ir-inl.h", "src/maglev/maglev-kna-processor.h", "src/maglev/maglev-kna-processor.cc", + "src/maglev/maglev-map-inference.h", "src/maglev/maglev-node-type.cc", "src/maglev/maglev-node-type.h", "src/maglev/maglev-range.h", @@ -3924,6 +3959,7 @@ filegroup( "src/maglev/maglev-range-verification.h", "src/maglev/maglev-reducer-inl.h", "src/maglev/maglev-reducer.h", + "src/maglev/maglev-regalloc-node-info.h", "src/maglev/maglev-register-frame-array.h", "src/maglev/maglev-phase.h", "src/maglev/maglev-phi-representation-selector.cc", @@ -4444,6 +4480,18 @@ filegroup( output_group = "initializers", ) +filegroup( + name = "icu/metagen_layouts_json", + srcs = [":icu/run_metagen"], + output_group = "layouts", +) + +filegroup( + name = "noicu/metagen_layouts_json", + srcs = [":noicu/run_metagen"], + output_group = "layouts", +) + # TODO(victorgomes): Add support to tools/debug_helper, # which needs class-debug-readers and debug-macros. v8_torque_files( @@ -4475,13 +4523,20 @@ v8_torque_files( "interface-descriptors.inc", ], icu_srcs = [":icu/torque_files"], + icu_layout_json = select({ + ":is_v8_use_metagen": ":icu/metagen_layouts_json", + "//conditions:default": None, + }), noicu_srcs = [":noicu/torque_files"], + noicu_layout_json = select({ + ":is_v8_use_metagen": ":noicu/metagen_layouts_json", + "//conditions:default": None, + }), ) -# Metagen: libclang-driven IT generator. Produces gen/metagen/instance-types.h -# which `src/objects/instance-types-gen.h` includes when -# V8_USE_METAGEN_INSTANCE_TYPES is on. :v8_libshared reaches the targets -# below only under that flag. +# Metagen: libclang-driven metadata generator. Produces +# gen/metagen/instance-types.h for src/objects/instance-types-gen.h and +# gen/metagen/layouts.json for Torque. filegroup( name = "metagen_python_sources", srcs = [ @@ -4491,6 +4546,8 @@ filegroup( "tools/metagen/cpp_hier.py", "tools/metagen/extract.py", "tools/metagen/instance_types.py", + "tools/metagen/layout_extract.py", + "tools/metagen/layout_ir.py", "tools/metagen/metagen.py", ], ) @@ -4543,11 +4600,10 @@ filegroup( # Clang's builtin headers (stddef.h, stdarg.h, the arch intrinsics). # Kept separate from the libclang files above because they are a -# different input to the rule: metagen takes their directory explicitly -# and passes it as -isystem. The llvm-libclang package ships the library -# and the C API headers but no builtin headers, so these come from the -# clang toolchain, which rolls from the same LLVM revision and therefore -# matches the parsing library. +# different input to the rule: metagen passes their directory as +# -resource-dir=. The llvm-libclang package ships the library and C API +# headers but no builtin headers, so these come from the matching clang +# toolchain. filegroup( name = "metagen_clang_builtin_headers", srcs = glob([ @@ -4555,7 +4611,7 @@ filegroup( ]), ) -# The harvest's checked-in C++ driver, shared with GN and metagen.py. It +# Metagen's checked-in C++ driver, shared with GN and metagen.py. It # includes src/objects/all-objects.h, whose feature-conditional groups # are selected by the normal V8 feature defines. Bazel always defines # V8_ENABLE_WEBASSEMBLY via :define_flags; V8_INTL_SUPPORT is added only by @@ -4578,6 +4634,8 @@ py_binary( "tools/metagen/cpp_hier.py", "tools/metagen/extract.py", "tools/metagen/instance_types.py", + "tools/metagen/layout_extract.py", + "tools/metagen/layout_ir.py", "tools/metagen/metagen.py", ], # tools/metagen/ is a Python package, so the scripts import each @@ -4589,9 +4647,14 @@ py_binary( main = "tools/metagen/metagen.py", ) -metagen_instance_types( - name = "metagen_instance_types_h", +run_metagen( + name = "run_metagen", driver = ":metagen_driver", + default_driver_mode = select({ + "@v8//bazel/config:is_windows": "cl", + "//conditions:default": "gcc", + }), + driver_mode_flag = ":v8_metagen_driver_mode", clang_builtin_headers = [":metagen_clang_builtin_headers"], libclang_files = [":metagen_libclang_files"], python_srcs = [":metagen_python_sources"], @@ -4630,7 +4693,7 @@ metagen_instance_types( # The icu variant of v8_library compiles with V8_INTL_SUPPORT (via # ENABLE_I18N_SUPPORT_DEFINES copts, invisible to CcInfo) and the # intl object sources, so its IT enum must include the intl types: - # the icu-prefixed harvest additionally parses the intl headers, + # the icu-prefixed run additionally parses the intl headers, # with the same defines and with ICU's headers + include paths. icu_cc_compilation_context_from = ["//external:icu"], icu_extra_defines = [ @@ -4644,15 +4707,15 @@ metagen_instance_types( # rewrites the include path so `#include "metagen/instance-types.h"` # resolves against the gen dir. cc_library( - name = "icu/metagen_instance_types_headers", - hdrs = [":icu/metagen_instance_types_h"], + name = "icu/run_metagen_headers", + hdrs = [":icu/run_metagen"], copts = ["-Wno-implicit-fallthrough"], strip_include_prefix = "icu", ) cc_library( - name = "noicu/metagen_instance_types_headers", - hdrs = [":noicu/metagen_instance_types_h"], + name = "noicu/run_metagen_headers", + hdrs = [":noicu/run_metagen"], copts = ["-Wno-implicit-fallthrough"], strip_include_prefix = "noicu", ) @@ -4858,6 +4921,7 @@ cc_library( }), features = ["-use_header_modules"], deps = [ + ":simdutf", ":torque_base_headers", ":v8_libbase", "@abseil-cpp//absl/container:node_hash_map", @@ -4894,8 +4958,8 @@ v8_library( ":icu/generated_torque_definitions_headers", "//external:icu", ] + select({ - ":is_v8_use_metagen_instance_types": [ - ":icu/metagen_instance_types_headers", + ":is_v8_use_metagen": [ + ":icu/run_metagen_headers", ], "//conditions:default": [], }), @@ -4904,21 +4968,21 @@ v8_library( ":icu/generated_torque_definitions", ":icu/v8_base_without_compiler_files", ] + select({ - ":is_v8_use_metagen_instance_types": [":icu/metagen_instance_types_h"], + ":is_v8_use_metagen": [":icu/run_metagen"], "//conditions:default": [], }), noicu_deps = [ ":noicu/generated_torque_definitions_headers", ] + select({ - ":is_v8_use_metagen_instance_types": [ - ":noicu/metagen_instance_types_headers", + ":is_v8_use_metagen": [ + ":noicu/run_metagen_headers", ], "//conditions:default": [], }), noicu_srcs = [ ":noicu/generated_torque_definitions", ] + select({ - ":is_v8_use_metagen_instance_types": [":noicu/metagen_instance_types_h"], + ":is_v8_use_metagen": [":noicu/run_metagen"], "//conditions:default": [], }), deps = [ @@ -5051,6 +5115,7 @@ v8_binary( "//conditions:default": [], }), deps = [ + ":simdutf", "v8_libbase", "@abseil-cpp//absl/container:node_hash_map", "@abseil-cpp//absl/container:node_hash_set", @@ -5093,17 +5158,6 @@ v8_binary( noicu_deps = [":noicu/v8"], ) -# This target forces torque to be compiled without pointer compression. -v8_binary_non_pointer_compression( - name = "noicu/torque_non_pointer_compression", - binary = "noicu/torque", -) - -v8_binary_non_pointer_compression( - name = "icu/torque_non_pointer_compression", - binary = "icu/torque", -) - alias( name = "v8ci", actual = "noicu/v8", diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index 1df3d4e31bcc..d0531ca88958 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -14,6 +14,7 @@ import("//build/config/host_byteorder.gni") import("//build/config/mips.gni") import("//build/config/riscv.gni") import("//build/config/sanitizers/sanitizers.gni") +import("//build/toolchain/kythe.gni") import("//build_overrides/build.gni") import("//third_party/icu/config.gni") @@ -25,12 +26,12 @@ if (is_clang) { import("//build/config/clang/clang.gni") } -if (is_win && v8_use_metagen_instance_types) { - # For the SDK include flags, see `metagen_instance_types_h`. +if (is_win && v8_use_metagen) { + # For the SDK include flags, see `run_metagen`. import("//build/toolchain/win/win_toolchain_data.gni") } -if (v8_enable_temporal_support) { +if (v8_enable_temporal_support || v8_enable_ecma402_icu4x) { import("//build/config/rust.gni") } @@ -45,7 +46,7 @@ declare_args() { # Print to stdout on Android. v8_android_log_stdout = false - # Native libclang for the metagen instance-type harvest, for platforms + # Native libclang for Metagen, for platforms # that have no prebuilt llvm-libclang package (currently ppc64 and s390x). # Both are absolute paths, and both must be set or both left empty. # v8_metagen_libclang_so: the native libclang shared library. @@ -114,6 +115,9 @@ declare_args() { # Sets the number of internal fields on array buffer view objects. v8_array_buffer_view_internal_field_count = 0 + # Sets the size of the EmbedderDataArray on context objects. + v8_embedder_data_array_size = 5 + # Sets -DENABLE_VTUNE_JIT_INTERFACE. v8_enable_vtunejit = false @@ -536,9 +540,6 @@ declare_args() { # usages. The plugin is not exhaustive but covers most common known pitfalls. use_cppgc_clang_plugin = true - # Expose F.p.caller and .arguments as own properties. - v8_function_arguments_caller_are_own_props = false - # Use a hard-coded secret value when hashing. v8_use_default_hasher_secret = true @@ -557,6 +558,13 @@ declare_args() { # 1: Message but no file or line. # 2: Everything (file, line, message). v8_logging_level = "" + + # Use 16 byte stack alignment for x64. + v8_x64_16byte_stack_alignment = false + + # Support 57-bit virtual addresses (LA57) on x64. + # Sets -DV8_SUPPORT_LA57. + v8_support_la57 = true } # The native-libclang args are a matched pair: a .so with no bindings (or @@ -566,6 +574,25 @@ assert(v8_metagen_libclang_so == "" == (v8_metagen_libclang_bindings_dir == ""), "v8_metagen_libclang_so and v8_metagen_libclang_bindings_dir must be " + "set together or left empty together.") +# The generation-invariance comparison runs torque twice for a 32-bit target, +# from a 32-bit and a 64-bit host, and diffs the output: it tests the Torque +# generator, so it belongs on the path where Torque owns the layouts. +assert(!v8_verify_torque_generation_invariance || !v8_use_metagen, + "v8_verify_torque_generation_invariance requires " + + "v8_use_metagen=false.") + +declare_args() { + # Checked-in headers let compilation start before the generators finish. + # Enable them only for the configuration they match; the build verifies + # their contents. See src/gen/README.md for configuration and regeneration. + v8_use_checked_in_generated_headers = + v8_enable_i18n_support && v8_enable_webassembly && + v8_enable_temporal_support && !v8_enable_drumbrake && + !v8_enable_experimental_tsa_builtins && + !v8_enable_experimental_tq_to_tsa && v8_use_metagen && + (v8_current_cpu == "x64" || v8_current_cpu == "arm64") +} + # Derived defaults. if (v8_logging_level == "") { if (v8_enable_verification_features || v8_dcheck_always_on) { @@ -809,9 +836,12 @@ if (v8_builtins_profiling_log_file == "default") { # * `v8_enable_sandbox && v8_enable_external_code_space` because they affect # the way how external pointer values are accessed, # * `v8_enable_webassembly` because it changes the set of opcodes which - # affects graphs hashes. + # affects graphs hashes, + # * `!v8_x64_16byte_stack_alignment` because frame layout changes graph + # hashes. if (v8_enable_builtins_optimization && !v8_enable_builtins_profiling && - !is_debug && !v8_dcheck_always_on && v8_enable_webassembly) { + !is_debug && !v8_dcheck_always_on && v8_enable_webassembly && + !v8_x64_16byte_stack_alignment) { # This is about function arguments evaluation order on the machine building # mksnapshot, which makes node IDs not predictable for subgraphs like # Op1(Op2(), Op3()) and as a result different graph hashes. @@ -866,6 +896,9 @@ assert(!v8_enable_map_packing || !v8_enable_pointer_compression, assert(!v8_enable_map_packing || v8_current_cpu == "x64", "Map packing is only supported on x64") +assert(!v8_x64_16byte_stack_alignment || v8_current_cpu == "x64", + "v8_x64_16byte_stack_alignment is only supported on x64") + assert(!v8_enable_external_code_space || v8_enable_pointer_compression, "External code space feature requires pointer compression") @@ -1090,6 +1123,7 @@ external_v8_defines = [ "V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT=${v8_array_buffer_internal_field_count}", "V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT=${v8_array_buffer_view_internal_field_count}", "V8_PROMISE_INTERNAL_FIELD_COUNT=${v8_promise_internal_field_count}", + "V8_EMBEDDER_DATA_ARRAY_SIZE=${v8_embedder_data_array_size}", "V8_USE_DEFAULT_HASHER_SECRET=${v8_use_default_hasher_secret}", "V8_ENABLE_CHECKS", "V8_ENABLE_MEMORY_ACCOUNTING_CHECKS", @@ -1108,6 +1142,7 @@ external_v8_defines = [ "V8_IS_TSAN", "V8_ENABLE_DIRECT_HANDLE", "V8_MINORMS_STRING_SHORTCUTTING", + "V8_SUPPORT_LA57", "V8_HAVE_TARGET_OS", "V8_TARGET_OS_ANDROID", "V8_TARGET_OS_FUCHSIA", @@ -1126,6 +1161,7 @@ enabled_external_v8_defines = [ "V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT=${v8_array_buffer_internal_field_count}", "V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT=${v8_array_buffer_view_internal_field_count}", "V8_PROMISE_INTERNAL_FIELD_COUNT=${v8_promise_internal_field_count}", + "V8_EMBEDDER_DATA_ARRAY_SIZE=${v8_embedder_data_array_size}", "V8_USE_DEFAULT_HASHER_SECRET=${v8_use_default_hasher_secret}", ] @@ -1179,6 +1215,9 @@ if (v8_enable_direct_handle) { if (v8_shortcut_strings_in_minor_ms) { enabled_external_v8_defines += [ "V8_MINORMS_STRING_SHORTCUTTING" ] } +if (v8_support_la57) { + enabled_external_v8_defines += [ "V8_SUPPORT_LA57" ] +} # V8_TARGET_OS_ defines. The target OS may differ from host OS e.g. in # mksnapshot. We additionally set V8_HAVE_TARGET_OS to determine that a @@ -1322,8 +1361,14 @@ config("features") { # Selects metagen vs Torque instance-type output (see # src/objects/instance-types-gen.h). The header defaults to metagen # when this is undefined, so only the off case needs a define. - if (!v8_use_metagen_instance_types) { - defines += [ "V8_USE_METAGEN_INSTANCE_TYPES=0" ] + if (!v8_use_metagen) { + defines += [ "V8_USE_METAGEN=0" ] + } + + # Makes the hand-written headers listed in src/gen/README.md include + # the checked-in copies under src/gen/ instead of the generated headers. + if (v8_use_checked_in_generated_headers) { + defines += [ "V8_USE_CHECKED_IN_GENERATED_HEADERS" ] } configs = [ @@ -1446,6 +1491,9 @@ config("features") { if (v8_enable_temporal_systemicu) { defines += [ "V8_ENABLE_TEMPORAL_SYSTEMICU" ] } + if (v8_enable_ecma402_icu4x) { + defines += [ "V8_ENABLE_ECMA402_ICU4X" ] + } if (v8_enable_local_handle_zapping) { defines += [ "ENABLE_LOCAL_HANDLE_ZAPPING" ] } @@ -1681,8 +1729,8 @@ config("features") { if (v8_target_is_simulator) { defines += [ "USE_SIMULATOR" ] } - if (v8_function_arguments_caller_are_own_props) { - defines += [ "V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS" ] + if (v8_x64_16byte_stack_alignment) { + defines += [ "V8_X64_16BYTE_STACK_ALIGNMENT" ] } } @@ -2062,7 +2110,7 @@ if (v8_postmortem_support) { script = "tools/gen-postmortem-metadata.py" - if (v8_use_metagen_instance_types) { + if (v8_use_metagen) { _instance_types_header = "$target_gen_dir/metagen/instance-types.h" } else { _instance_types_header = @@ -2178,8 +2226,8 @@ if (v8_postmortem_support) { rebase_path(inputs, root_build_dir) deps = [ ":run_torque" ] - if (v8_use_metagen_instance_types) { - deps += [ ":metagen_instance_types_h" ] + if (v8_use_metagen) { + deps += [ ":run_metagen" ] } } } @@ -2362,7 +2410,6 @@ torque_files = [ "src/objects/heap-object.tq", "src/objects/js-array-buffer.tq", "src/objects/js-array.tq", - "src/objects/js-atomics-synchronization.tq", "src/objects/js-collection-iterator.tq", "src/objects/js-collection.tq", "src/objects/js-disposable-stack.tq", @@ -2453,7 +2500,7 @@ if (v8_enable_webassembly) { } } -if (v8_use_metagen_instance_types) { +if (v8_use_metagen) { # The checked-in translation unit metagen parses. It includes # src/objects/all-objects.h, whose feature-specific groups use the same # defines as their V8 sources. @@ -2461,7 +2508,7 @@ if (v8_use_metagen_instance_types) { _metagen_out_dir = "$target_gen_dir/metagen" # metagen's libclang Python bindings and native library, declared as - # inputs so a package roll re-runs the harvest. + # inputs so a package roll re-runs Metagen. # # The `//` prefix is load-bearing: llvm-libclang lives in the checkout # root's third_party in both layouts (v8/ standalone, src/ under @@ -2490,12 +2537,23 @@ if (v8_use_metagen_instance_types) { # The clang toolchain's resource dir contains builting headers # include/{stddef.h,stdarg.h,...}. _metagen_clang_resource_dir = "$clang_base_path/lib/clang/$clang_version" + + # The headers are parsed with v8_base_without_compiler's flags. _metagen_flags_target = ":v8_base_without_compiler" + _metagen_flags_target_name = get_label_info(_metagen_flags_target, "name") + + # This lets us add a dependency on "changed flags" to the depfile: _metagen_flags_target_ninja = get_label_info(_metagen_flags_target, "target_out_dir") + - "/v8_base_without_compiler.ninja" - - action("metagen_instance_types_h") { + "/$_metagen_flags_target_name.ninja" + + # Runs in every toolchain that builds V8. Each toolchain harvests with its + # own compile flags (see --flags-toolchain below): secondary toolchains may + # build a different V8 configuration than the default one, e.g. 32-bit + # x86/arm in v8_verify_builtins_compatibility and v8_multi_arch_build, or + # flipped pointer compression in clang_x64_fuzzer_experiments. Torque + # rejects a layouts.json whose pointer/tagged sizes do not match its target. + action("run_metagen") { visibility = [ ":*", "tools/debug_helper/:*", @@ -2504,8 +2562,9 @@ if (v8_use_metagen_instance_types) { script = "tools/metagen/metagen.py" # The script obtains the parse flags through `gn desc`, so make the build - # configuration an explicit input. In particular, changing a feature define - # must re-run the driver even though the action command is unchanged. + # configuration an explicit input. In particular, changing a feature + # define must re-run the driver even though the action command is + # unchanged. deps = [ ":v8_dump_build_config" ] if (v8_generate_external_defines_header) { @@ -2513,44 +2572,46 @@ if (v8_use_metagen_instance_types) { deps += [ ":gen_v8_gn" ] } - # No deps on V8's own generators: every generated header the harvested set - # reaches short-circuits to empty under V8_METAGEN_GENERATION_PASS - # (see builtins-definitions.h and factory-base.h), so the harvest runs - # independently of Torque and the bytecode-builtins-list generator. - # Perfetto's generated headers are kept out of the parse the same way, by - # undefining V8_USE_PERFETTO for it (see metagen.py). + # We don't depend on other generators (torque, bytecode-builtins-list, + # perfetto), since their outputs are explicitly excluded during the + # metagen parse. See V8_METAGEN_GENERATION_PASS and undefining + # V8_USE_PERFETTO. - # `inputs`, not `sources`: these headers belong to the V8 targets that - # compile them; this action only reads them. inputs = [ "tools/metagen/clang_bootstrap.py", "tools/metagen/compile_flags.py", "tools/metagen/cpp_hier.py", "tools/metagen/extract.py", "tools/metagen/instance_types.py", + "tools/metagen/layout_extract.py", + "tools/metagen/layout_ir.py", "tools/metagen/metagen.py", _metagen_driver_file, - # The driver's aggregate header. It declares no classes, so - # metagen records no fact from it and it is absent from the - # depfile, but its include list determines which headers the - # harvest parses. PRESUBMIT.py checks that the list is complete. + # The driver's aggregate header. It includes every header that + # declares a class that's part of the v8 hierarchy. It's + # included here to generate proper build deps when a new header + # file is added (ie adding a new header must trigger a + # rebuild). PRESUBMIT.py checks that the list is complete. "src/objects/all-objects.h", "$root_out_dir/v8_build_config.json", # Proxy for the whole builtin-header directory, which has no # GN glob: a toolchain roll rewrites stddef.h along with the - # rest, and the harvest cannot parse without it. + # rest, and Metagen cannot parse without it. "$_metagen_clang_resource_dir/include/stddef.h", ] + _metagen_libclang_files - outputs = [ "$_metagen_out_dir/instance-types.h" ] + # Write-if-changed on each output. Dependents only re-run if needed. + # TODO(jgruber): Add a non-critical diagnostics target that requests + # --enable-layout-positions when C++ source positions are consumed. + outputs = [ + "$_metagen_out_dir/instance-types.h", + "$_metagen_out_dir/layouts.json", + ] - # The files the harvest read a fact out of, reported by the script. - # `inputs` above declares only the driver, so this is what re-runs the - # harvest when a class declaration or a marker changes. - # - # Binds to the first output, so output order matters if one is added. + # Metagen generates its own depfile. + # TODO(jgruber): Could be renamed to run-metagen.d. depfile = "$_metagen_out_dir/instance-types.h.d" args = [ @@ -2563,20 +2624,15 @@ if (v8_use_metagen_instance_types) { "--build-dir", ".", # The action runs with cwd=root_build_dir. - # metagen cannot find this by walking up from the build dir: on - # ChromeOS the build dir sits outside the checkout entirely. + # metagen cannot find this by walking up from the build dir. On + # ChromeOS the build dir is outside the checkout. "--source-root", rebase_path("//", root_build_dir), "--out", rebase_path(_metagen_out_dir, root_build_dir), - # Representative compiled target whose flags metagen harvests via - # `gn desc`: its TUs include the headers metagen parses, so its - # config is the right one. Passed as a string, not a dep, to avoid a - # cycle with the targets that consume instance-types.h. - # Pass the current_toolchain so cross-compiles are handled correctly. - # It travels in its own argument because GN would not quote the - # parentheses of a qualified label on a Windows command line. + # Metagen reads the compile flags from this target. Passed as a string, + # not a dep, to avoid a cycle. "--flags-from-target", get_label_info(_metagen_flags_target, "label_no_toolchain"), "--flags-toolchain", @@ -2587,13 +2643,20 @@ if (v8_use_metagen_instance_types) { "--flags-dependency", rebase_path(_metagen_flags_target_ninja, root_build_dir), - # We pass a resource dir, not an include dir, so the driver decides where - # the builtin headers sit: behind libc++, ahead of the Windows SDK's - # copies of stddef.h and the intrinsics. See tools/metagen/metagen.py. + # We pass a resource dir, not an include dir, so the driver decides + # where to put builtin headers: behind libc++, ahead of the Windows + # SDK's copies of stddef.h and the intrinsics. See + # tools/metagen/metagen.py. "--clang-resource-dir", rebase_path(_metagen_clang_resource_dir, root_build_dir), ] + if (is_win) { + args += [ "--driver-mode=cl" ] + } else { + args += [ "--driver-mode=gcc" ] + } + if (v8_metagen_libclang_so != "") { # No prebuilt llvm-libclang for this platform: point metagen at the # system libclang and the separately-staged cindex bindings. The two @@ -2605,12 +2668,11 @@ if (v8_use_metagen_instance_types) { v8_metagen_libclang_bindings_dir, # The toolchain major, so metagen can warn if the loaded libclang is - # out of step with the clang whose builtin headers it parses against. + # out of step with clang. "--expect-libclang-major", clang_version, ] } else { - # Package root, so metagen need not guess the checkout layout. args += [ "--libclang-dir", rebase_path("//third_party/llvm-libclang", root_build_dir), @@ -2621,7 +2683,7 @@ if (v8_use_metagen_instance_types) { # The SDK/UCRT include dirs never show up in `gn desc`: the toolchain # interpolates them into its tool command template instead of into # cflags. Pass the build's own resolved flags, the way - # build/modules/BUILD.gn does, so an SDK roll reruns the harvest. + # build/modules/BUILD.gn does, so an SDK roll reruns Metagen. # `--extra-flag=` attaches the value because the flags start with a # dash (-imsvc) and argparse would take them for options. foreach(flag, current_win_toolchain_data.include_flags_imsvc_list) { @@ -2771,12 +2833,31 @@ template("run_torque") { "-v8-root", rebase_path(".", root_build_dir), ] + + if (v8_use_metagen) { + deps += [ ":run_metagen" ] + layout_json = get_label_info(":run_metagen", "target_gen_dir") + + "/metagen/layouts.json" + inputs = [ layout_json ] + args += [ + "-layout-json", + rebase_path(layout_json, root_build_dir), + "-use-cpp-layouts", + ] + } if (v8_annotate_torque_ir) { args += [ "-annotate-ir" ] } if (v8_enable_torque_dwarf) { args += [ "-torque-dwarf" ] } + if (enable_kythe_annotations) { + args += [ + "-kythe-inline-metadata", + "-kythe-default-corpus", + kythe_corpus, + ] + } if (defined(invoker.args)) { args += invoker.args } @@ -2827,6 +2908,12 @@ group("v8_maybe_temporal") { } } +group("v8_maybe_ecma402_icu4x") { + if (v8_enable_ecma402_icu4x) { + public_deps = [ "//third_party/rust/icu_capi" ] + } +} + group("v8_abseil") { public_deps = [ "//third_party/abseil-cpp:absl" ] @@ -2865,6 +2952,47 @@ v8_header_set("torque_runtime_support") { configs = [ ":internal_config" ] } +if (v8_use_checked_in_generated_headers) { + # This target has no generator dependencies, so dependents can compile + # immediately. :verify_checked_in_generated_headers checks the copies. + v8_header_set("checked_in_generated_headers") { + visibility = [ ":generated_headers" ] + + # For src/common/globals.h, included from the bytecodes list. + deps = [ ":v8_shared_internal_headers" ] + + sources = [ + "src/gen/intl-wasm/builtin-definitions.h", + "src/gen/intl-wasm/bytecodes-builtins-list.h", + "src/gen/intl-wasm/class-forward-declarations.h", + "src/gen/intl-wasm/instance-types.h", + "src/gen/intl-wasm/interface-descriptors.inc", + ] + + configs = [ ":internal_config" ] + } +} + +# Targets that need only the headers listed in src/gen/README.md depend on +# this group. Other generator outputs still require their generator actions. +group("generated_headers") { + visibility = [ ":*" ] + + if (v8_use_checked_in_generated_headers) { + public_deps = [ ":checked_in_generated_headers" ] + } else { + public_deps = [ + ":generate_bytecode_builtins_list", + ":run_torque", + ] + + # :run_metagen only exists when metagen is enabled. + if (v8_use_metagen) { + public_deps += [ ":run_metagen" ] + } + } +} + # Build lists of torque-generated .cc and .h files for clustering torque_csa_cc_files = [] torque_csa_h_files = [] @@ -2892,6 +3020,7 @@ v8_cluster_source_set("torque_generated_initializers") { ":run_torque", ":v8_base_without_compiler", ":v8_internal_headers", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_tracing", ] @@ -2957,6 +3086,7 @@ v8_cluster_source_set("torque_generated_definitions") { ":run_torque", ":v8_internal_headers", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_tracing", ] @@ -2990,6 +3120,84 @@ action("generate_bytecode_builtins_list") { ] } +# The checked-in generated headers, as [generated, checked-in] pairs. +# Both actions below use this list. See src/gen/README.md. +_checked_in_generated_headers = [ + [ + "$target_gen_dir/torque-generated/builtin-definitions.h", + "src/gen/intl-wasm/builtin-definitions.h", + ], + [ + "$target_gen_dir/torque-generated/class-forward-declarations.h", + "src/gen/intl-wasm/class-forward-declarations.h", + ], + [ + "$target_gen_dir/torque-generated/interface-descriptors.inc", + "src/gen/intl-wasm/interface-descriptors.inc", + ], + [ + "$target_gen_dir/builtins-generated/bytecodes-builtins-list.h", + "src/gen/intl-wasm/bytecodes-builtins-list.h", + ], +] +if (v8_use_metagen) { + _checked_in_generated_headers += [ [ + "$target_gen_dir/metagen/instance-types.h", + "src/gen/intl-wasm/instance-types.h", + ] ] +} + +# The generators do not depend on checked-in headers, so verification and +# regeneration can use the same build directory even when copies are stale. +template("checked_in_generated_headers_action") { + action(target_name) { + visibility = [ ":*" ] + script = "tools/compare-checked-in-headers.py" + deps = [ + ":generate_bytecode_builtins_list", + ":run_torque", + ] + if (v8_use_metagen) { + deps += [ ":run_metagen" ] + } + outputs = [ "$target_gen_dir/$target_name.stamp" ] + inputs = [] + args = [ + "--" + invoker.mode, + "--stamp", + rebase_path(outputs[0], root_build_dir), + ] + foreach(pair, _checked_in_generated_headers) { + inputs += [ pair[0] ] + if (invoker.mode == "verify") { + # So that the check re-runs when a checked-in copy is edited. + # Not in update mode, which must also run when a copy is missing. + inputs += [ pair[1] ] + } + args += [ + "--pair", + rebase_path(pair[0], root_build_dir) + "=" + + rebase_path(pair[1], root_build_dir), + ] + } + } +} + +if (v8_use_checked_in_generated_headers) { + # Verify before linking or running code compiled from checked-in headers. + # :v8_base covers library users; mksnapshot bypasses it and depends on this + # action explicitly. The CPU condition above excludes 32-bit toolchains. + checked_in_generated_headers_action("verify_checked_in_generated_headers") { + mode = "verify" + } + + # Only the matching configuration may regenerate checked-in headers. + # Nothing depends on this target; gm.py gen-checked-in-headers builds it. + checked_in_generated_headers_action("regen_checked_in_generated_headers") { + mode = "update" + } +} + # Template to generate different V8 snapshots based on different runtime flags. # Can be invoked with run_mksnapshot(). The target will resolve to # run_mksnapshot_. If is "default", no file suffixes will be used. @@ -3417,6 +3625,7 @@ action("v8_dump_build_config") { "has_wasm_interpreter=$v8_enable_drumbrake", "i18n=$v8_enable_i18n_support", "temporal=$v8_enable_temporal_support", + "ecma402_icu4x=$v8_enable_ecma402_icu4x", "is_android=$is_android", "is_ios=$is_ios", "is_linux=$is_linux", @@ -3481,6 +3690,7 @@ generated_file("v8_generate_features_json") { v8_enable_i18n_support = v8_enable_i18n_support v8_enable_temporal_support = v8_enable_temporal_support v8_enable_temporal_systemicu = v8_enable_temporal_systemicu + v8_enable_ecma402_icu4x = v8_enable_ecma402_icu4x v8_enable_javascript_promise_hooks = v8_enable_javascript_promise_hooks v8_enable_lite_mode = v8_enable_lite_mode v8_enable_map_packing = v8_enable_map_packing @@ -3496,6 +3706,7 @@ generated_file("v8_generate_features_json") { v8_imminent_deprecation_warnings = v8_imminent_deprecation_warnings v8_optimized_debug = v8_optimized_debug v8_random_seed = v8_random_seed + v8_support_la57 = v8_support_la57 v8_use_perfetto = v8_use_perfetto v8_use_siphash = v8_use_siphash v8_use_default_hasher_secret = v8_use_default_hasher_secret @@ -3515,6 +3726,7 @@ v8_source_set("v8_snapshot") { deps = [ ":v8_internal_headers", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_tracing", ] @@ -3753,6 +3965,7 @@ v8_source_set("v8_init") { ":v8_base_without_compiler", ":v8_initializers", ":v8_internal_headers", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_tracing", ] @@ -3970,9 +4183,16 @@ v8_header_set("v8_internal_headers") { public_configs = [ "src/inspector:inspector_config" ] - sources = [ + sources = [] + if (!v8_use_checked_in_generated_headers) { + # With v8_use_checked_in_generated_headers the checked-in copy is + # listed by :checked_in_generated_headers instead. + sources += + [ "$target_gen_dir/builtins-generated/bytecodes-builtins-list.h" ] + } + + sources += [ ### gcmole(all) ### - "$target_gen_dir/builtins-generated/bytecodes-builtins-list.h", "include/cppgc/common.h", "include/v8-inspector-protocol.h", "include/v8-inspector.h", @@ -4009,6 +4229,7 @@ v8_header_set("v8_internal_headers") { "src/builtins/builtins-utils-inl.h", "src/builtins/builtins-utils.h", "src/builtins/builtins.h", + "src/builtins/bytecodes-builtins-list.h", "src/builtins/constants-table-builder.h", "src/builtins/data-view-ops.h", "src/builtins/profile-data-reader.h", @@ -4163,8 +4384,6 @@ v8_header_set("v8_internal_headers") { "src/compiler/machine-operator-reducer.h", "src/compiler/machine-operator.h", "src/compiler/map-inference.h", - "src/compiler/memory-lowering.h", - "src/compiler/memory-optimizer.h", "src/compiler/node-aux-data.h", "src/compiler/node-cache.h", "src/compiler/node-marker.h", @@ -4385,6 +4604,10 @@ v8_header_set("v8_internal_headers") { "src/extensions/statistics-extension.h", "src/extensions/trigger-failure-extension.h", "src/flags/save-flags.h", + "src/gen/intl-nowasm/static-roots.h", + "src/gen/intl-wasm/static-roots.h", + "src/gen/nointl-nowasm/static-roots.h", + "src/gen/nointl-wasm/static-roots.h", "src/handles/global-handles-inl.h", "src/handles/global-handles.h", "src/handles/handle-scope-implementer-inl.h", @@ -4601,6 +4824,7 @@ v8_header_set("v8_internal_headers") { "src/objects/arguments.h", "src/objects/backing-store.h", "src/objects/bigint.h", + "src/objects/bit-field-group.h", "src/objects/call-site-info-inl.h", "src/objects/call-site-info.h", "src/objects/casting.h", @@ -4671,8 +4895,6 @@ v8_header_set("v8_internal_headers") { "src/objects/js-array-buffer.h", "src/objects/js-array-inl.h", "src/objects/js-array.h", - "src/objects/js-atomics-synchronization-inl.h", - "src/objects/js-atomics-synchronization.h", "src/objects/js-collection-inl.h", "src/objects/js-collection-iterator-inl.h", "src/objects/js-collection-iterator.h", @@ -4823,8 +5045,6 @@ v8_header_set("v8_internal_headers") { "src/objects/transitions.h", "src/objects/trusted-object-inl.h", "src/objects/trusted-object.h", - "src/objects/trusted-pointer-inl.h", - "src/objects/trusted-pointer.h", "src/objects/turbofan-types-inl.h", "src/objects/turbofan-types.h", "src/objects/turboshaft-types-inl.h", @@ -4834,7 +5054,6 @@ v8_header_set("v8_internal_headers") { "src/objects/value-serializer.h", "src/objects/visitors-inl.h", "src/objects/visitors.h", - "src/objects/waiter-queue-node.h", "src/parsing/expression-scope.h", "src/parsing/func-name-inferrer.h", "src/parsing/import-attributes.h", @@ -4901,10 +5120,6 @@ v8_header_set("v8_internal_headers") { "src/regexp/special-case.h", "src/roots/roots-inl.h", "src/roots/roots.h", - "src/roots/static-roots-intl-nowasm.h", - "src/roots/static-roots-intl-wasm.h", - "src/roots/static-roots-nointl-nowasm.h", - "src/roots/static-roots-nointl-wasm.h", "src/roots/static-roots.h", "src/runtime/runtime-utils.h", "src/runtime/runtime.h", @@ -4929,14 +5144,12 @@ v8_header_set("v8_internal_headers") { "src/sandbox/external-pointer.h", "src/sandbox/external-strings-cage.h", "src/sandbox/hardware-support.h", - "src/sandbox/indirect-pointer-inl.h", - "src/sandbox/indirect-pointer-tag.h", - "src/sandbox/indirect-pointer.h", "src/sandbox/isolate-inl.h", "src/sandbox/isolate.h", "src/sandbox/js-dispatch-table-inl.h", "src/sandbox/js-dispatch-table.h", "src/sandbox/sandbox-malloc.h", + "src/sandbox/sandbox-zero-segment.h", "src/sandbox/sandbox.h", "src/sandbox/sandboxable-thread.h", "src/sandbox/sandboxed-pointer-inl.h", @@ -4945,9 +5158,12 @@ v8_header_set("v8_internal_headers") { "src/sandbox/segmented-table.h", "src/sandbox/tagged-payload.h", "src/sandbox/testing.h", + "src/sandbox/trusted-pointer-inl.h", "src/sandbox/trusted-pointer-scope.h", "src/sandbox/trusted-pointer-table-inl.h", "src/sandbox/trusted-pointer-table.h", + "src/sandbox/trusted-pointer-tag.h", + "src/sandbox/trusted-pointer.h", "src/snapshot/code-serializer.h", "src/snapshot/context-deserializer.h", "src/snapshot/context-serializer.h", @@ -4973,6 +5189,7 @@ v8_header_set("v8_internal_headers") { "src/snapshot/sort-builtins.h", "src/snapshot/startup-deserializer.h", "src/snapshot/startup-serializer.h", + "src/snapshot/trusted-section-serializer.h", "src/strings/char-predicates-inl.h", "src/strings/char-predicates.h", "src/strings/owning-external-string-resource.h", @@ -5017,7 +5234,6 @@ v8_header_set("v8_internal_headers") { "src/zone/accounting-allocator.h", "src/zone/type-stats.h", "src/zone/zone-allocator.h", - "src/zone/zone-chunk-list.h", "src/zone/zone-compact-set.h", "src/zone/zone-containers.h", "src/zone/zone-hashmap.h", @@ -5103,6 +5319,7 @@ v8_header_set("v8_internal_headers") { "src/maglev/maglev-interpreter-frame-state.h", "src/maglev/maglev-ir-inl.h", "src/maglev/maglev-ir.h", + "src/maglev/maglev-kna-map.h", "src/maglev/maglev-kna-processor.h", "src/maglev/maglev-known-node-aspects.h", "src/maglev/maglev-loop-peeler.h", @@ -5119,6 +5336,7 @@ v8_header_set("v8_internal_headers") { "src/maglev/maglev-reducer-inl.h", "src/maglev/maglev-reducer.h", "src/maglev/maglev-regalloc-data.h", + "src/maglev/maglev-regalloc-node-info.h", "src/maglev/maglev-regalloc.h", "src/maglev/maglev-register-frame-array.h", "src/maglev/maglev-tracer.h", @@ -5165,7 +5383,6 @@ v8_header_set("v8_internal_headers") { "src/compiler/turboshaft/wasm-turboshaft-compiler.h", "src/compiler/turboshaft/wasm-wrappers-inl.h", "src/compiler/turboshaft/wasm-wrappers.h", - "src/compiler/wasm-address-reassociation.h", "src/compiler/wasm-call-descriptors.h", "src/compiler/wasm-compiler-definitions.h", "src/compiler/wasm-compiler.h", @@ -5306,6 +5523,7 @@ v8_header_set("v8_internal_headers") { "src/objects/js-number-format-inl.h", "src/objects/js-number-format.h", "src/objects/js-plural-rules-inl.h", + "src/objects/js-plural-rules-internal.h", "src/objects/js-plural-rules.h", "src/objects/js-relative-time-format-inl.h", "src/objects/js-relative-time-format.h", @@ -5754,19 +5972,16 @@ v8_header_set("v8_internal_headers") { deps = [ ":cppgc_headers", - ":generate_bytecode_builtins_list", - ":run_torque", + ":generated_headers", ":v8_abseil", ":v8_heap_base_headers", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ] if (v8_enable_experimental_tq_to_tsa) { deps += [ ":run_torque_to_tsa" ] } - if (v8_use_metagen_instance_types) { - deps += [ ":metagen_instance_types_h" ] - } } v8_compiler_sources = [ @@ -5840,8 +6055,6 @@ v8_compiler_sources = [ "src/compiler/machine-operator-reducer.cc", "src/compiler/machine-operator.cc", "src/compiler/map-inference.cc", - "src/compiler/memory-lowering.cc", - "src/compiler/memory-optimizer.cc", "src/compiler/node-marker.cc", "src/compiler/node-matchers.cc", "src/compiler/node-observer.cc", @@ -5933,6 +6146,7 @@ v8_compiler_sources = [ if (!v8_enable_maglev) { # When Maglev is not enabled, Turboshaft still needs Maglev's graph builder. v8_compiler_sources += [ + "src/maglev/maglev-basic-block.cc", "src/maglev/maglev-compilation-info.cc", "src/maglev/maglev-compilation-unit.cc", "src/maglev/maglev-graph-builder.cc", @@ -6048,7 +6262,6 @@ if (v8_enable_webassembly) { "src/compiler/turboshaft/wasm-simd-phase.cc", "src/compiler/turboshaft/wasm-turboshaft-compiler.cc", "src/compiler/turboshaft/wasm-wrappers.cc", - "src/compiler/wasm-address-reassociation.cc", "src/compiler/wasm-call-descriptors.cc", "src/compiler/wasm-compiler.cc", "src/compiler/wasm-escape-analysis.cc", @@ -6095,8 +6308,7 @@ v8_cluster_source_set("v8_compiler_for_mksnapshot_source_set") { exclude_from_cluster = exclude_from_compiler_cluster public_deps = [ - ":generate_bytecode_builtins_list", - ":run_torque", + ":generated_headers", ":v8_abseil", ":v8_maybe_icu", ":v8_tracing", @@ -6109,6 +6321,7 @@ v8_cluster_source_set("v8_compiler_for_mksnapshot_source_set") { ":v8_base_without_compiler", ":v8_internal_headers", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_shared_internal_headers", ] @@ -6142,8 +6355,7 @@ v8_cluster_source_set("v8_compiler") { exclude_from_cluster = exclude_from_compiler_cluster public_deps = [ - ":generate_bytecode_builtins_list", - ":run_torque", + ":generated_headers", ":v8_abseil", ":v8_internal_headers", ":v8_maybe_icu", @@ -6156,6 +6368,7 @@ v8_cluster_source_set("v8_compiler") { deps = [ ":v8_base_without_compiler", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_shared_internal_headers", ] @@ -6242,7 +6455,6 @@ v8_cluster_source_set("v8_base_without_compiler") { "src/builtins/builtins-arraybuffer.cc", "src/builtins/builtins-async-disposable-stack.cc", "src/builtins/builtins-async-module.cc", - "src/builtins/builtins-atomics-synchronization.cc", "src/builtins/builtins-bigint.cc", "src/builtins/builtins-callsite.cc", "src/builtins/builtins-collections.cc", @@ -6509,7 +6721,6 @@ v8_cluster_source_set("v8_base_without_compiler") { "src/objects/instruction-stream.cc", "src/objects/intl-objects.cc", "src/objects/js-array-buffer.cc", - "src/objects/js-atomics-synchronization.cc", "src/objects/js-break-iterator.cc", "src/objects/js-collator.cc", "src/objects/js-data-object-builder.cc", @@ -6522,6 +6733,7 @@ v8_cluster_source_set("v8_base_without_compiler") { "src/objects/js-locale.cc", "src/objects/js-number-format.cc", "src/objects/js-objects.cc", + "src/objects/js-plural-rules-internal.cc", "src/objects/js-plural-rules.cc", "src/objects/js-raw-json.cc", "src/objects/js-regexp.cc", @@ -6567,7 +6779,6 @@ v8_cluster_source_set("v8_base_without_compiler") { "src/objects/type-hints.cc", "src/objects/value-serializer.cc", "src/objects/visitors.cc", - "src/objects/waiter-queue-node.cc", "src/parsing/func-name-inferrer.cc", "src/parsing/import-attributes.cc", "src/parsing/literal-buffer.cc", @@ -6680,6 +6891,7 @@ v8_cluster_source_set("v8_base_without_compiler") { "src/snapshot/sort-builtins.cc", "src/snapshot/startup-deserializer.cc", "src/snapshot/startup-serializer.cc", + "src/snapshot/trusted-section-serializer.cc", "src/strings/char-predicates.cc", "src/strings/string-builder.cc", "src/strings/string-case.cc", @@ -6745,6 +6957,7 @@ v8_cluster_source_set("v8_base_without_compiler") { if (v8_enable_maglev) { sources += [ "src/maglev/maglev-assembler.cc", + "src/maglev/maglev-basic-block.cc", "src/maglev/maglev-code-generator.cc", "src/maglev/maglev-compilation-info.cc", "src/maglev/maglev-compilation-unit.cc", @@ -7184,11 +7397,11 @@ v8_cluster_source_set("v8_base_without_compiler") { ] deps = [ - ":torque_generated_definitions", ":v8_bigint", ":v8_headers", ":v8_heap_base", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_shared_internal_headers", ":v8_tracing", @@ -7199,6 +7412,12 @@ v8_cluster_source_set("v8_base_without_compiler") { "//third_party/highway:libhwy", ] + # With checked-in headers, link generated definitions through :v8_base. + # A dependency here would make every compile wait for run_torque. + if (!v8_use_checked_in_generated_headers) { + deps += [ ":torque_generated_definitions" ] + } + if (v8_enable_generated_code_validator) { sources += [ "src/sandbox/generated-code-validator.cc" ] if (v8_current_cpu == "x64") { @@ -7212,8 +7431,7 @@ v8_cluster_source_set("v8_base_without_compiler") { public_deps = [ ":cppgc_base", - ":generate_bytecode_builtins_list", - ":run_torque", + ":generated_headers", ":v8_abseil", ":v8_headers", ":v8_internal_headers", @@ -7254,6 +7472,7 @@ v8_cluster_source_set("v8_base_without_compiler") { "src/objects/js-list-format.cc", "src/objects/js-locale.cc", "src/objects/js-number-format.cc", + "src/objects/js-plural-rules-internal.cc", "src/objects/js-plural-rules.cc", "src/objects/js-relative-time-format.cc", "src/objects/js-segment-iterator.cc", @@ -7308,6 +7527,12 @@ group("v8_base") { ":v8_base_without_compiler", ":v8_compiler", ] + + # Keep generator dependencies out of v8_base_without_compiler's compiles. + if (v8_use_checked_in_generated_headers) { + public_deps += [ ":torque_generated_definitions" ] + deps = [ ":verify_checked_in_generated_headers" ] + } } v8_source_set("torque_base") { @@ -7344,6 +7569,16 @@ v8_source_set("torque_base") { "src/torque/instructions.h", "src/torque/kythe-data.cc", "src/torque/kythe-data.h", + "src/torque/layout-loader.cc", + "src/torque/layout-loader.h", + + # The JSON reader/writer predates the layout loader in the language + # server; the loader reuses it, so it lives here and torque_ls_base + # reaches it via its public_dep on this target. + "src/torque/ls/json-parser.cc", + "src/torque/ls/json-parser.h", + "src/torque/ls/json.cc", + "src/torque/ls/json.h", "src/torque/parameter-difference.h", "src/torque/server-data.cc", "src/torque/server-data.h", @@ -7375,7 +7610,10 @@ v8_source_set("torque_base") { ] } - deps = [ ":v8_shared_internal_headers" ] + deps = [ + ":v8_shared_internal_headers", + ":v8_simdutf", + ] public_deps = [ ":v8_config_headers", @@ -7406,10 +7644,6 @@ v8_source_set("torque_base") { v8_source_set("torque_ls_base") { sources = [ "src/torque/ls/globals.h", - "src/torque/ls/json-parser.cc", - "src/torque/ls/json-parser.h", - "src/torque/ls/json.cc", - "src/torque/ls/json.h", "src/torque/ls/message-handler.cc", "src/torque/ls/message-handler.h", "src/torque/ls/message-macros.h", @@ -7470,11 +7704,10 @@ v8_component("v8_libbase") { "src/base/file-utils.h", "src/base/flags.h", "src/base/float16.h", - "src/base/fpu.cc", - "src/base/fpu.h", "src/base/free_deleter.h", "src/base/functional/bind-internal.h", "src/base/functional/function-ref.h", + "src/base/growing-circular-queue.h", "src/base/hashing.h", "src/base/hashmap-entry.h", "src/base/hashmap.h", @@ -7575,6 +7808,7 @@ v8_component("v8_libbase") { "src/base/threaded-list.h", "src/base/timezone-cache.h", "src/base/types/is-instantiation.h", + "src/base/unique-array.h", "src/base/utils/random-number-generator.cc", "src/base/utils/random-number-generator.h", "src/base/vector.h", @@ -7889,7 +8123,10 @@ v8_source_set("fuzzer_support") { ":v8_libplatform", ":v8_maybe_icu", ] - deps = [ ":v8_maybe_temporal" ] + deps = [ + ":v8_maybe_ecma402_icu4x", + ":v8_maybe_temporal", + ] # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and # enable the diagnostic by removing this line. @@ -8223,6 +8460,7 @@ if (v8_check_header_includes) { ":v8_initializers", ":v8_internal_headers", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_icu", ":v8_maybe_temporal", ":v8_version", @@ -8346,18 +8584,26 @@ if (current_toolchain == v8_snapshot_toolchain) { ] deps = [ + ":torque_generated_definitions", ":v8_base_without_compiler", ":v8_compiler_for_mksnapshot", ":v8_init", ":v8_internal_headers", ":v8_libbase", ":v8_libplatform", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_icu", ":v8_maybe_temporal", ":v8_shared_internal_headers", ":v8_tracing", "//build/win:default_exe_manifest", ] + + if (v8_use_checked_in_generated_headers) { + # mksnapshot runs during the build and does not go through :v8_base; + # see verify_checked_in_generated_headers. + deps += [ ":verify_checked_in_generated_headers" ] + } } # This config disables a link time optimization "ICF", which may merge @@ -8496,6 +8742,12 @@ group("gn_all") { "tools:gn_all", ] + # Redline, an experimental coverage-guided JavaScript fuzzer, uses POSIX + # APIs. Only standalone V8 builds it: Chromium does not need it. + if (is_linux && !build_with_chromium) { + deps += [ "experimental/redline" ] + } + if (v8_custom_deps != "") { # Custom dependency from directory under v8/custom_deps. deps += [ v8_custom_deps ] @@ -9163,10 +9415,10 @@ if (v8_enable_webassembly) { deps = [ ":fuzzer_support", - ":generate_bytecode_builtins_list", - ":run_torque", + ":generated_headers", ":v8_internal_headers", ":v8_libbase", + ":v8_maybe_ecma402_icu4x", ":v8_maybe_temporal", ":v8_shared_internal_headers", ":v8_tracing", @@ -9287,7 +9539,6 @@ if (!build_with_chromium && v8_use_perfetto) { configs = [ ":v8_tracing_config" ] public_configs = [ "//third_party/perfetto/gn:public_config" ] deps = [ - "//third_party/perfetto/src/trace_processor:storage_minimal", "//third_party/perfetto/src/tracing/core", # TODO(skyostil): Support non-POSIX platforms. @@ -9297,16 +9548,31 @@ if (!build_with_chromium && v8_use_perfetto) { ] public_deps = [ - "//third_party/perfetto/include/perfetto/trace_processor", "//third_party/perfetto/protos/perfetto/config:cpp", "//third_party/perfetto/protos/perfetto/trace/chrome:zero", - "//third_party/perfetto/src/trace_processor:export_json", "//third_party/perfetto/src/tracing:client_api", ] + + if (v8_use_perfetto_json_export) { + deps += [ "//third_party/perfetto/src/trace_processor:storage_minimal" ] + public_deps += [ + "//third_party/perfetto/include/perfetto/trace_processor", + "//third_party/perfetto/src/trace_processor:export_json", + ] + } } } # if (!build_with_chromium && v8_use_perfetto) if (v8_fuzzilli) { + # The inline flag stores of -fsanitize-coverage=inline-bool-flag cannot + # temporarily grant access to the default pkey like the trace-pc-guard + # callback does (see src/fuzzilli/cov.cc). + assert(!v8_enable_sandbox_hardware_support || + string_replace(sanitizer_coverage_flags, "inline-bool-flag", "") == + sanitizer_coverage_flags, + "inline-bool-flag coverage is not supported with sandbox hardware " + + "support, use trace-pc-guard instead") + v8_source_set("fuzzilli_cov") { visibility = [ "*" ] sources = [ diff --git a/deps/v8/DEPS b/deps/v8/DEPS index 9547d0667a57..3d760d7ebce9 100644 --- a/deps/v8/DEPS +++ b/deps/v8/DEPS @@ -13,7 +13,7 @@ gclient_gn_args = [ vars = { # The version of the NDK. Set here, to allow the autoroller to update this # value when updating the CIPD hash. - 'android_ndk_version': Str('2@30.0.15729638'), + 'android_ndk_version': Str('2@30.0.16248370'), # Fetches only the SDK boot images which match at least one of the whitelist # entries in a comma-separated list. @@ -99,29 +99,29 @@ vars = { 'chromium_jetstream_git': 'https://chromium.googlesource.com/external/github.com/WebKit/JetStream.git', # GN CIPD package version. - 'gn_version': 'git_revision:127dd2a6d582528d6d61c4d838dc17385ef31abd', + 'gn_version': 'git_revision:938087829fcbcc8fd87835ee301dd522c7637685', # ninja CIPD package version # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja 'ninja_version': 'version:3@1.12.1.chromium.4', # siso CIPD package version - 'siso_version': 'git_revision:22353054fea20f637c8fa302a90daf9e2cc10497', + 'siso_version': 'git_revision:7ab4814901b3c7afc2dddf2ed1a6ff238a0d85c5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Fuchsia sdk # and whatever else without interference from each other. - 'fuchsia_version': 'version:33.20260915.5.1', + 'fuchsia_version': 'version:33.20261022.4.1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling partition_alloc_version # and whatever else without interference from each other. - 'partition_alloc_version': 'a0f30e381c6e132215a0c8d809fd08ff4cdad244', + 'partition_alloc_version': '566ebad54d97777c36615883259a9f9d2c106d37', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_build-tools_version # and whatever else without interference from each other. - 'android_sdk_build-tools_version': 'febJrTgiK9s1ANoUlc4Orn3--zs9GjGCj2vQc8g7OaMC', + 'android_sdk_build-tools_version': 'version_37.0.0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_emulator_version # and whatever else without interference from each other. @@ -133,7 +133,7 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_platforms_version # and whatever else without interference from each other. - 'android_sdk_platforms_version': 'WhtP32Q46ZHdTmgCgdauM3ws_H9iPoGKEZ_cPggcQ6wC', + 'android_sdk_platforms_version': 'JsUGMsJK2pkQxVKr7EcJbxbwjJEIWjEPLqcbv7ifdmcC', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling android_sdk_tools-lint_version # and whatever else without interference from each other. @@ -145,11 +145,11 @@ vars = { # Three lines of non-changing comments so that # the commit queue can handle CLs rolling agents-internal # and whatever else without interference from each other. - 'agents_internal_revision': '79ff29c61f3fcfd51da0a5be8579b01b4f6f61b3', + 'agents_internal_revision': '3eb5fb7503fbcde16249bce04b60c02d42602a74', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling agents-public # and whatever else without interference from each other. - 'agents_public_revision': '865684c4f7092e4ab05adcd3fcf068672ff28d27', + 'agents_public_revision': '9aac1662fc0475b8b36da5502544fa5ef4cd61f6', } deps = { @@ -161,9 +161,9 @@ deps = { 'condition': 'checkout_agents_internal', }, 'build': - Var('chromium_url') + '/chromium/src/build.git' + '@' + 'bc0661cf80717e97e1b6868396f61f7f94f2d04a', + Var('chromium_url') + '/chromium/src/build.git' + '@' + '0c1bea50d7016e2c9ca0c736765025d8f2284898', 'buildtools': - Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + 'c202b4a9dac30e789ed6e3b2354efa94357a56f3', + Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '2f41b66d4857c8efbfcb2a350f159944f71dbf7e', 'buildtools/linux64': { 'packages': [ { @@ -218,15 +218,15 @@ deps = { 'test/mozilla/data': Var('chromium_url') + '/v8/deps/third_party/mozilla-tests.git' + '@' + 'f6c578a10ea707b1a8ab0b88943fe5115ce2b9be', 'test/test262/data': - Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + '7ab7fafa0003f73fc85c1b95d88094d33f7eb8bd', + Var('chromium_url') + '/external/github.com/tc39/test262.git' + '@' + 'd53ebc8b1931d9f1541e43d59650776e4b766248', 'third_party/android_platform': { - 'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + 'e3919359f2387399042d31401817db4a02d756ec', + 'url': Var('chromium_url') + '/chromium/src/third_party/android_platform.git' + '@' + 'a2902d9644d9e26c519e5304f6a8a064efc3fa09', 'condition': 'checkout_android', }, 'third_party/android_sdk/public': { 'packages': [ { - 'package': 'chromium/third_party/android_sdk/public/build-tools/37.0.0', + 'package': 'chromium/third_party/android_sdk/public/build-tools/37.0.0/${{os}}', 'version': Var('android_sdk_build-tools_version'), }, { @@ -252,19 +252,21 @@ deps = { 'third_party/android_toolchain/ndk': { 'packages': [ { - 'package': 'chromium/third_party/android_toolchain/android_toolchain', + 'package': 'chromium/third_party/android_toolchain/android_toolchain/${{platform}}', 'version': 'version:' + Var('android_ndk_version'), }, ], - 'condition': 'checkout_android', + 'condition': 'checkout_android and ' + '((host_os == "linux" and host_cpu == "x64") or ' + '(host_os == "mac" and host_cpu == "arm64"))', 'dep_type': 'cipd', }, 'third_party/catapult': { - 'url': Var('chromium_url') + '/catapult.git' + '@' + 'e39ded11ffe971d360160c9d185a7e0ef98fb9a3', + 'url': Var('chromium_url') + '/catapult.git' + '@' + 'f44fbfda510b51755b644a7b76c71d0804aa653e', 'condition': 'checkout_android', }, 'third_party/clang-format/script': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + '70510081984cfcdb14a15b3e08dfe9776dc7ed37', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git' + '@' + '9f796802e5d633c96dbe97e0b6683d5e62594f9f', 'third_party/colorama/src': { 'url': Var('chromium_url') + '/external/colorama.git' + '@' + '3de9f013df4b470069d03d250224062e8cf15c49', 'condition': 'checkout_android', @@ -278,15 +280,15 @@ deps = { 'condition': 'checkout_android', }, 'third_party/depot_tools': - Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + '0306e4682b4ac35287c726fa35a983157a625902', + Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'b52fe87d04af61df3dd07748ff2c2c0b649dca09', 'third_party/dragonbox/src': Var('chromium_url') + '/external/github.com/jk-jeon/dragonbox.git' + '@' + 'beeeef91cf6fef89a4d4ba5e95d47ca64ccb3a44', 'third_party/fp16/src': Var('chromium_url') + '/external/github.com/Maratyszcza/FP16.git' + '@' + '782eea126dc5c755827be751a099eb01826175cf', 'third_party/fast_float/src': - Var('chromium_url') + '/external/github.com/fastfloat/fast_float.git' + '@' + 'b0ab987b3dfdde13fa1915f65ef2a5c068d9208c', + Var('chromium_url') + '/external/github.com/fastfloat/fast_float.git' + '@' + '42f254836ee416ffcf2f4e6576260003ac33d48c', 'third_party/fuchsia-gn-sdk': { - 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-gn-sdk.git' + '@' + '019c2f57c0f022f63d4d56b4e6427d4f4ea91daa', + 'url': Var('chromium_url') + '/chromium/src/third_party/fuchsia-gn-sdk.git' + '@' + '8488f5b23e737d08f2888cf0bb0d55fe7d313092', 'condition': 'checkout_fuchsia', }, 'third_party/simdutf': @@ -304,23 +306,23 @@ deps = { 'dep_type': 'cipd', }, 'third_party/google_benchmark_chrome': { - 'url': Var('chromium_url') + '/chromium/src/third_party/google_benchmark.git' + '@' + 'c3b654389bf74fac1f2d926d0439506f06c66751', + 'url': Var('chromium_url') + '/chromium/src/third_party/google_benchmark.git' + '@' + '57f4041d982b6900be1f525cfe909212a14d95c6', }, 'third_party/google_benchmark_chrome/src': { - 'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + '8abf1e701fbd88c8170f48fe0558247e2e5f8e7d', + 'url': Var('chromium_url') + '/external/github.com/google/benchmark.git' + '@' + 'a6b4a9f00b36c19af9997d68a1cf6e0b5b3d032c', }, 'third_party/fuzztest': - Var('chromium_url') + '/chromium/src/third_party/fuzztest.git' + '@' + '55970ac2863f6b740d3e8247ac0ec48e7acb2113', + Var('chromium_url') + '/chromium/src/third_party/fuzztest.git' + '@' + '0c2febf9c1f0b11df71c537cb75a2918f9a6ddc6', 'third_party/fuzztest/src': - Var('chromium_url') + '/external/github.com/google/fuzztest.git' + '@' + '7a8e9056de2a4f745082a4b3861a67ada47ced36', + Var('chromium_url') + '/external/github.com/google/fuzztest.git' + '@' + 'a2d3cb097f07a91dd26768db7d9f0898cd42b0f0', 'third_party/googletest/src': - Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + '4fe3307fb2d9f86d19777c7eb0e4809e9694dde7', + Var('chromium_url') + '/external/github.com/google/googletest.git' + '@' + '0b656495436f57212be8700794a3d5fb14000c5f', 'third_party/highway/src': Var('chromium_url') + '/external/github.com/google/highway.git' + '@' + '2607d3b5b0113992fe84d3848859eae13b3b52c1', 'third_party/icu': - Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '5aa526207171ecadf31597f0980a7b7ad8872f33', + Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '2a51536dfb3b448bdf3dae70c782ea2879c90904', 'third_party/instrumented_libs': { - 'url': Var('chromium_url') + '/chromium/third_party/instrumented_libraries.git' + '@' + 'd15c278eed5d38d9acf2d8054cf37baba93cef8e', + 'url': Var('chromium_url') + '/chromium/third_party/instrumented_libraries.git' + '@' + '83128b60913a82a39d01055312687a27bb959b59', 'condition': 'checkout_instrumented_libraries', }, 'third_party/ittapi': { @@ -334,186 +336,186 @@ deps = { 'third_party/jsoncpp/source': Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '3347a4b86bb914cb565f0cbda19c06e109513300', 'third_party/libc++/src': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '97b436da4c33663581d394f4ee0a5977fc38c2f4', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxx.git' + '@' + '9ba7713d3a0f1e179904c984bb626748b15e57d6', 'third_party/libc++abi/src': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '92767730c5f8350fc53f5b3de5c3c02d00bbab8c', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libcxxabi.git' + '@' + '440f88852530ac197479edb1463dda1916692cce', 'third_party/libpfm4': - Var('chromium_url') + '/chromium/src/third_party/libpfm4.git' + '@' + 'f2fec4fe8bc40a58b1f257e631fc5b8f49b39010', + Var('chromium_url') + '/chromium/src/third_party/libpfm4.git' + '@' + 'e02968592ac424c7f45441249e7175d4549a5e3a', 'third_party/libpfm4/src': - Var('chromium_url') + '/external/git.code.sf.net/p/perfmon2/libpfm4.git' + '@' + '9c24ffc9d179244e05584ce4df2f4fbfecdfde9b', + Var('chromium_url') + '/external/git.code.sf.net/p/perfmon2/libpfm4.git' + '@' + '186a658c3e1e49b0ee3da414a7db8ba971a00cb5', 'third_party/libunwind/src': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + '24a407d5353ad38f948f107c7d6bc2bcbb4bca24', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libunwind.git' + '@' + '9e44ea2ff4f53a60c2a3d2b6f511d7bab9ab12f0', 'third_party/llvm-libc/src': - Var('chromium_url') + '/external/github.com/llvm/llvm-project/libc.git' + '@' + '5e61624667bf9e44ea452191dbda0172997018a2', + Var('chromium_url') + '/external/github.com/llvm/llvm-project/libc.git' + '@' + '631cc29c6dde5bafcf4b22674af6ecad67147977', 'third_party/llvm-build/Release+Asserts': { 'dep_type': 'gcs', 'bucket': 'chromium-browser-clang', 'objects': [ { - 'object_name': 'Linux_x64/clang-android-runtime-library-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'b93725013ccd4f91d5ae40afc1a1b495e07c3be645ddbd7a3b48a7281fcecff8', - 'size_bytes': 6208368, - 'generation': 1789426565866244, + 'object_name': 'Linux_x64/clang-android-runtime-library-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'dd03492cad72f223d7743c2f4af39c405f5bac7f7f342de09697a45b7108ce4e', + 'size_bytes': 6188284, + 'generation': 1792086693754706, 'condition': 'checkout_android', }, { - 'object_name': 'Linux_x64/clang-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '8039b5c9e7375df3a8082761cd1220223f90344b81d829c949f69224350d9d47', - 'size_bytes': 57238740, - 'generation': 1789426559193435, + 'object_name': 'Linux_x64/clang-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '0b76afc1a29b0583f7723e966b9b65a22b15d8fdcd38e7c567ae32343c68944d', + 'size_bytes': 58394648, + 'generation': 1792086691304470, 'condition': 'host_os == "linux"', }, { - 'object_name': 'Linux_x64/clang-tidy-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'f8206d1964bd8b59283589ca82159650611e217ad01ab885389f09e177fc80c0', - 'size_bytes': 14935260, - 'generation': 1789426559088623, + 'object_name': 'Linux_x64/clang-tidy-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'cf2a7610086b45fb878f606709babd3cbd8e26ea97a087ea47929e4ee871b562', + 'size_bytes': 15213064, + 'generation': 1792086691338093, 'condition': 'host_os == "linux" and checkout_clang_tidy', }, { - 'object_name': 'Linux_x64/clangd-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '79e4777278ef296219350c6a765eb215e4d23a76c85617ae6b4ec7a7fda524bc', - 'size_bytes': 15086928, - 'generation': 1789426559098441, + 'object_name': 'Linux_x64/clangd-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '5ef64ed6fdeab8dfd91f11db07c601ce5107fc9e61e9d7a18dcee97af42f03c6', + 'size_bytes': 15595776, + 'generation': 1792086691391942, 'condition': 'host_os == "linux" and checkout_clangd', }, { - 'object_name': 'Linux_x64/llvm-code-coverage-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'b3b59473f37c63501c00d376c44ea46a59b840dab7298c67ba9101507c48ea65', - 'size_bytes': 2371412, - 'generation': 1789426559296849, + 'object_name': 'Linux_x64/llvm-code-coverage-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '756e08684179166571dd155471e0a9c4525223d30b45d776b3d75a4d53b820d3', + 'size_bytes': 2432768, + 'generation': 1792086691721951, 'condition': 'host_os == "linux" and checkout_clang_coverage_tools', }, { - 'object_name': 'Linux_x64/llvmobjdump-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '7da1f3e3754d2b841a909ddbdbdb91cf3cbea3fd7be4b51cbe2cfe171cbfa9d6', - 'size_bytes': 5917952, - 'generation': 1789426559151920, + 'object_name': 'Linux_x64/llvmobjdump-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '2282c8a4bdc6e12242989525039a36e7eeb4335b22d39d3b5d624c38083881c5', + 'size_bytes': 6011380, + 'generation': 1792086691439732, 'condition': '(checkout_linux or checkout_mac or checkout_android) and host_os == "linux"', }, { - 'object_name': 'Mac/clang-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '5721c0e801c03b276a9680080ab3d5f0f572945e9d9d683ed8cbd50285598ea0', - 'size_bytes': 56731544, - 'generation': 1789426567536829, + 'object_name': 'Mac/clang-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'ae29ec360eda6e80e96f8638d368ecdeea93d19c18c527c525dc0932bd5243a4', + 'size_bytes': 54834700, + 'generation': 1792086700293656, 'condition': 'host_os == "mac" and host_cpu == "x64"', }, { - 'object_name': 'Mac/clang-mac-runtime-library-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '5b7ee53434e68ca2d71a35da8c7bff79e246d5f3d499fddf10e0e3da564d9bdc', - 'size_bytes': 980916, - 'generation': 1789426574310634, + 'object_name': 'Mac/clang-mac-runtime-library-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'c18444eef64cf27a8913ce73ffa8fd92e6f41306a02bbc82d805aa0c521863e0', + 'size_bytes': 997164, + 'generation': 1792086707123823, 'condition': 'checkout_mac and not host_os == "mac"', }, { - 'object_name': 'Mac/clang-tidy-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '5aee98783a53c1acb489f78767c3562818759ee73ded863d08f9645233a3692e', - 'size_bytes': 14948968, - 'generation': 1789426567538151, + 'object_name': 'Mac/clang-tidy-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '3997f34e72dc28eb30af1b8af903ceb6b0f516db7821996297bf296793addc72', + 'size_bytes': 14437076, + 'generation': 1792086700400707, 'condition': 'host_os == "mac" and host_cpu == "x64" and checkout_clang_tidy', }, { - 'object_name': 'Mac/clangd-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '74451b27944643780298bf5b667d41c2bc026f9fabbaaa543bd6a569d7cf3181', - 'size_bytes': 16825280, - 'generation': 1789426567538026, + 'object_name': 'Mac/clangd-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '0fc9c351ad3bc6c357cc53a57dad6f8ebf45ba9e38150012cb457812f2a1314f', + 'size_bytes': 15359244, + 'generation': 1792086700318835, 'condition': 'host_os == "mac" and host_cpu == "x64" and checkout_clangd', }, { - 'object_name': 'Mac/llvm-code-coverage-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '25fcd6877fd1124a879650c5d828ab9aac6a89bbb679188de89875656c062836', - 'size_bytes': 2423848, - 'generation': 1789426567755049, + 'object_name': 'Mac/llvm-code-coverage-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'b8b2f099cb029ff36cce33c9983984f547d7da0d9c34c1b427bb1080a31b8047', + 'size_bytes': 2307268, + 'generation': 1792086700464636, 'condition': 'host_os == "mac" and host_cpu == "x64" and checkout_clang_coverage_tools', }, { - 'object_name': 'Mac/llvmobjdump-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'fddb9d463c7c86698711435c1cab0e3dfd039ca6716ba5faed765e215ace9472', - 'size_bytes': 5908332, - 'generation': 1789426567556141, + 'object_name': 'Mac/llvmobjdump-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'eae7800773f3955fd1dcc334d8779b9a232ca6ebd3a79a55be028bd8797b1197', + 'size_bytes': 5586688, + 'generation': 1792086700364844, 'condition': 'host_os == "mac" and host_cpu == "x64"', }, { - 'object_name': 'Mac_arm64/clang-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'c6519a944e9ddd34fcc5273cdf1997f674c6d929b70eecd9020646774aa7b8aa', - 'size_bytes': 47559168, - 'generation': 1789426576079342, + 'object_name': 'Mac_arm64/clang-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '0a8d887534b3153c7f6860265dc7e075d420174521c60ccd52c2c243949ef468', + 'size_bytes': 44917408, + 'generation': 1792086708845653, 'condition': 'host_os == "mac" and host_cpu == "arm64"', }, { - 'object_name': 'Mac_arm64/clang-tidy-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '6858c97a00a3e89de7b4bc1f4d2ed608811994067a5a8749ba830e39d10c456a', - 'size_bytes': 12998944, - 'generation': 1789426576095992, + 'object_name': 'Mac_arm64/clang-tidy-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '1aee3a0078bbe3b840125f521d3e6d985de61531ee6686a0bef80abc6e6d6a78', + 'size_bytes': 12291060, + 'generation': 1792086708806950, 'condition': 'host_os == "mac" and host_cpu == "arm64" and checkout_clang_tidy', }, { - 'object_name': 'Mac_arm64/clangd-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'e8898cbd3448cea483971f8bd72fc3f45e59d5f02c639ce674c08b484cb42a1b', - 'size_bytes': 13313524, - 'generation': 1789426576068075, + 'object_name': 'Mac_arm64/clangd-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '799e034e1fdff7eb7d899329ab20bbeb96642234844c9e070797059bd6ce5ee9', + 'size_bytes': 12292508, + 'generation': 1792086709015693, 'condition': 'host_os == "mac" and host_cpu == "arm64" and checkout_clangd', }, { - 'object_name': 'Mac_arm64/llvm-code-coverage-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'ce7a2040d2321222ae5751f0ecc3a8abf21da81f532095497524eb462ade02ff', - 'size_bytes': 2043608, - 'generation': 1789426576226450, + 'object_name': 'Mac_arm64/llvm-code-coverage-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'a77bacfb3e6c08af7d51981d88fb4aa07e4fb797f37937071dd8657b7c2dea8e', + 'size_bytes': 1897140, + 'generation': 1792086709049271, 'condition': 'host_os == "mac" and host_cpu == "arm64" and checkout_clang_coverage_tools', }, { - 'object_name': 'Mac_arm64/llvmobjdump-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '53bd87b22289bd2df2e05a0f6a1bd297c8d8fc636584562668c72fee224354e6', - 'size_bytes': 5645448, - 'generation': 1789426576105416, + 'object_name': 'Mac_arm64/llvmobjdump-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '8d15119ffd7e9d52e86676bfdcfd8159506f0ba6c4b292ae4112cbf15e629d7d', + 'size_bytes': 5269524, + 'generation': 1792086709009144, 'condition': 'host_os == "mac" and host_cpu == "arm64"', }, { - 'object_name': 'Win/clang-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'fcb789024398956d51b9b6018230b84981fe9160158c0de68e3ca4f254504cf3', - 'size_bytes': 51838392, - 'generation': 1789426584693424, + 'object_name': 'Win/clang-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '08abce6e1d01c2fff9b25a09e36d9976296f27842196f96411b8220364481818', + 'size_bytes': 52783904, + 'generation': 1792086718487613, 'condition': 'host_os == "win"', }, { - 'object_name': 'Win/clang-tidy-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'e9c2f8b25cf6c2cc024c23823fbfb0d19149ab08faaec3bdb67e525eb224b20d', - 'size_bytes': 15129656, - 'generation': 1789426584789667, + 'object_name': 'Win/clang-tidy-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'ee25e107e6da91254780b0e9b6fb34198dc03636330c5564a7786e6450916d45', + 'size_bytes': 15436080, + 'generation': 1792086718412245, 'condition': 'host_os == "win" and checkout_clang_tidy', }, { - 'object_name': 'Win/clang-win-runtime-library-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': '0556e0ba5ca0ecabdf16b544d3b671994f719a9b8530b77c9474ed5922d37f2b', - 'size_bytes': 2650852, - 'generation': 1789426591392711, + 'object_name': 'Win/clang-win-runtime-library-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': 'a156f6fa1f149e45faa683f2b2d1cc010df1e29912b3cb0a0dd3e3d9186c513b', + 'size_bytes': 2707764, + 'generation': 1792086725161419, 'condition': 'checkout_win and not host_os == "win"', }, { - 'object_name': 'Win/clangd-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'c8cf60febcf4e7fcba61ab32153ea089d2b49ebe7d8d05230eb0c1ddc6d449f6', - 'size_bytes': 15433972, - 'generation': 1789426584780463, + 'object_name': 'Win/clangd-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '0db39ead1a1f49137570fd5e99ab7520262c2e6444900b551862ae2cccdf6bb8', + 'size_bytes': 15910376, + 'generation': 1792086718402867, 'condition': 'host_os == "win" and checkout_clangd', }, { - 'object_name': 'Win/llvm-code-coverage-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'fe05d04734b47fd6e88602e597cab43a3f37eaa3f6f2e44f2ba808af8378a7b5', - 'size_bytes': 2527212, - 'generation': 1789426585050946, + 'object_name': 'Win/llvm-code-coverage-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '3cfd8304148bd6bdd86a99f4e5f01ea2b4fbcbf4f35e29a2ca3cb235cb88c393', + 'size_bytes': 2604364, + 'generation': 1792086718581883, 'condition': 'host_os == "win" and checkout_clang_coverage_tools', }, { - 'object_name': 'Win/llvmobjdump-llvmorg-24-init-7747-g62397f8b-29.tar.xz', - 'sha256sum': 'afb8027a34fd80557a3c500a3f77e1b0aa0c2f93c9c51becddd9dddbc555936e', - 'size_bytes': 6016140, - 'generation': 1789426584846994, + 'object_name': 'Win/llvmobjdump-llvmorg-24-init-14453-ge063be79-1.tar.xz', + 'sha256sum': '3b58242027a9e86114d05444e9e70a9ed497a6a9e9c14d1b86c355e140503a53', + 'size_bytes': 6123208, + 'generation': 1792086718463583, 'condition': '(checkout_linux or checkout_mac or checkout_android) and host_os == "win"', }, ], }, 'third_party/logdog/logdog': - Var('chromium_url') + '/infra/luci/luci-py/client/libs/logdog' + '@' + '6d8ea2699c6e78b344b2fc4956322aa2c463af10', + Var('chromium_url') + '/infra/luci/luci-py/client/libs/logdog' + '@' + 'dd1f72c4fefbd4a1fd3b6bdb5d56afede3612347', 'third_party/markupsafe': Var('chromium_url') + '/chromium/src/third_party/markupsafe.git' + '@' + '4256084ae14175d38a3ff7d739dca83ae49ccec6', 'third_party/ninja': { @@ -531,51 +533,51 @@ deps = { 'condition': 'not build_with_chromium', }, 'third_party/perfetto': - Var('chromium_url') + '/external/github.com/google/perfetto.git' + '@' + 'aac4c25edfa1ad236f61622959166bc180a8ad2b', + Var('chromium_url') + '/external/github.com/google/perfetto.git' + '@' + 'a39834aa20faca91179990afaff9c8551f6305a3', 'third_party/protobuf': - Var('chromium_url') + '/chromium/src/third_party/protobuf.git' + '@' + '398c57e93a383373546bc6ae5ac2052b6155f2ba', + Var('chromium_url') + '/chromium/src/third_party/protobuf.git' + '@' + '11b91b7d1a7cb96bb449c9085f338624d1825458', 'third_party/re2/src': - Var('chromium_url') + '/external/github.com/google/re2.git' + '@' + '972a15cedd008d846f1a39b2e88ce48d7f166cbd', + Var('chromium_url') + '/external/github.com/google/re2.git' + '@' + '2da0056814cf180480a19f5cf811e7e1c054bf6d', 'third_party/requests': { - 'url': Var('chromium_url') + '/external/github.com/kennethreitz/requests.git' + '@' + 'c7e0fc087ceeadb8b4c84a0953a422c474093d6d', + 'url': Var('chromium_url') + '/external/github.com/kennethreitz/requests.git' + '@' + 'c2b307dbefe21177af03f9feb37181a89a799fcc', 'condition': 'checkout_android', }, 'tools/rust': - Var('chromium_url') + '/chromium/src/tools/rust' + '@' + '187bdac7c732777cf5e1b82b9caf6034d3a7e4e5', + Var('chromium_url') + '/chromium/src/tools/rust' + '@' + '4ee29fc422ce116d176f71b461bf5b035420345b', 'tools/win': - Var('chromium_url') + '/chromium/src/tools/win' + '@' + '13cb6e5d223dc49eadd082d3aef4c2a5b0e4c0a0', + Var('chromium_url') + '/chromium/src/tools/win' + '@' + 'd72db9e3040567a7589e00c0ad7ddf25c3b070bc', 'third_party/rust': - Var('chromium_url') + '/chromium/src/third_party/rust' + '@' + '4be2b73f368c8c2a3f5a42c16459b80d7d81b318', + Var('chromium_url') + '/chromium/src/third_party/rust' + '@' + '12f0fa4c0128c109163f306262e5ec3c364c4bd8', 'third_party/rust-toolchain': { 'dep_type': 'gcs', 'bucket': 'chromium-browser-clang', 'objects': [ { - 'object_name': 'Linux_x64/rust-toolchain-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': '5a56edc35db24efbbe0373c724457c31a1febd75cbef6ac7fc9a1c5bca6fc697', - 'size_bytes': 276524576, - 'generation': 1789143384016025, + 'object_name': 'Linux_x64/rust-toolchain-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': '3f62ea86b027923b1fce17ac2ef002d1788b608245003440b46558a8e735b83d', + 'size_bytes': 287328068, + 'generation': 1792086676135089, 'condition': 'host_os == "linux"', }, { - 'object_name': 'Mac/rust-toolchain-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': '62530251d7e7d3741840289a45a3e4950ad0023857e03bf0e9d57f2d723a8624', - 'size_bytes': 264337576, - 'generation': 1789143387895737, + 'object_name': 'Mac/rust-toolchain-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': '54d1db81fbbc7a97387b3cc9192a3497eea096c258ccae8f94fa46b5dac463c8', + 'size_bytes': 274448924, + 'generation': 1792086679706753, 'condition': 'host_os == "mac" and host_cpu == "x64"', }, { - 'object_name': 'Mac_arm64/rust-toolchain-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': '5db21ffd4909ce82c0832df9d1eb06b01b15a54176b7341e39f7181f4b483dbc', - 'size_bytes': 248304876, - 'generation': 1789143391575553, + 'object_name': 'Mac_arm64/rust-toolchain-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': '40b95cd2e8ccfa77724058832cc9809bb3aa0c5cf990d8c7b10cf854315ccce5', + 'size_bytes': 258029728, + 'generation': 1792086684183512, 'condition': 'host_os == "mac" and host_cpu == "arm64"', }, { - 'object_name': 'Win/rust-toolchain-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': '487387d6c7cfec69b06d613eb0f68331a3b56b1081f73bc673a1b26299865379', - 'size_bytes': 416611108, - 'generation': 1789143395284107, + 'object_name': 'Win/rust-toolchain-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': '8d501e922bc40c4e3bb255e8e31783c027054bff27b17970150c399c80eaf647', + 'size_bytes': 426164384, + 'generation': 1792086687600249, 'condition': 'host_os == "win"', }, ], @@ -594,31 +596,31 @@ deps = { 'bucket': 'chromium-browser-clang', 'objects': [ { - 'object_name': 'Linux_x64/rust-libclang-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': '59c2086dabf6494fb7cc4690910d4dfddd9a598a1ecaf19d8408197445bbf7c3', - 'size_bytes': 22899948, - 'generation': 1789143385954506, + 'object_name': 'Linux_x64/rust-libclang-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': '505dfa0b8c6c7abb332437c83e1ba169595e53aa8eef8f0aa1ea7adce4576835', + 'size_bytes': 23017532, + 'generation': 1792086677820729, 'condition': 'host_os == "linux"', }, { - 'object_name': 'Mac/rust-libclang-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': '6fa15d9cf2ff55b5ae1e4276369cfbde1f4f770e60ccb133e1fc7446c5ce607e', - 'size_bytes': 23309500, - 'generation': 1789143389794597, + 'object_name': 'Mac/rust-libclang-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': 'add54dcb54194a627e6c0b7171aa06114064c231410e33f616a83948e4626882', + 'size_bytes': 23163236, + 'generation': 1792086682384306, 'condition': 'host_os == "mac" and host_cpu == "x64"', }, { - 'object_name': 'Mac_arm64/rust-libclang-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': 'd330fd41100be52b4e804c9252b3f3bb34cfed16d2973934de0930b297f7201e', - 'size_bytes': 20689276, - 'generation': 1789143393459608, + 'object_name': 'Mac_arm64/rust-libclang-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': '3abad0aab3e8f49e2bb596a85cc88c38ee872bfe1dd55c6dc76fcfab9c6f0ba7', + 'size_bytes': 20838968, + 'generation': 1792086685890604, 'condition': 'host_os == "mac" and host_cpu == "arm64"', }, { - 'object_name': 'Win/rust-libclang-1edd55dcfcd573872c727fa3e086369a71661ee0-2-llvmorg-24-init-7747-g62397f8b.tar.xz', - 'sha256sum': 'fbe9978289a35ca45da1c1393ed6ef8adc86907d36a4ce81fcf590f56b07a096', - 'size_bytes': 21677148, - 'generation': 1789143397092006, + 'object_name': 'Win/rust-libclang-8a9dd7abdf013ec10cfeaaa3685feba18ef1c90c-1-llvmorg-24-init-14453-ge063be79.tar.xz', + 'sha256sum': 'b0716ed45f80b964b058414a80eb417272cb2e1df684c86efa31edf6ede31211', + 'size_bytes': 21797328, + 'generation': 1792086689442006, 'condition': 'host_os == "win"', }, ], @@ -656,13 +658,13 @@ deps = { 'dep_type': 'cipd', }, 'third_party/zlib': - Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '13395eebe853e811d274f7bd9b71fb7d9b5a5851', + Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '9f9f52c60a14e8e772fb561029ae0a121fef7609', 'tools/clang': - Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '10f700407ca356594ea2a575572b7ce63183721d', + Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'cc704f55000e327592594bc295abca5fa004ea99', 'tools/protoc_wrapper': - Var('chromium_url') + '/chromium/src/tools/protoc_wrapper.git' + '@' + 'e9dbe1bf6a2a5d2d4973725874259eed587cf18d', + Var('chromium_url') + '/chromium/src/tools/protoc_wrapper.git' + '@' + '5c77c0c9fdebb2d87378bcea183e4c6937fd8c53', 'third_party/abseil-cpp': { - 'url': Var('chromium_url') + '/chromium/src/third_party/abseil-cpp.git' + '@' + 'edf0931ff4e2cddfeecade307ae948b5d09b8b38', + 'url': Var('chromium_url') + '/chromium/src/third_party/abseil-cpp.git' + '@' + '9a0a43cbad88a77703bd73093011a62bbe0a6740', 'condition': 'not build_with_chromium', }, 'third_party/fadec/src': { diff --git a/deps/v8/PRESUBMIT.py b/deps/v8/PRESUBMIT.py index 1bbf577c86dd..7e28c955ed5b 100644 --- a/deps/v8/PRESUBMIT.py +++ b/deps/v8/PRESUBMIT.py @@ -53,10 +53,14 @@ r"LICENSE" ) +# Checked-in generated files. The build compares them against the generator +# output, so editing them to satisfy a source check does not work; the +# generator would have to change. See src/gen/README.md. +_GENERATED_CHECKED_IN_PATHS = (r'src[\\\/]gen[\\\/].+',) + # Regular expression that matches code which should not be run through cpplint. _NO_LINT_PATHS = ( - r'src[\\\/]base[\\\/]export-template\.h', -) + r'src[\\\/]base[\\\/]export-template\.h',) + _GENERATED_CHECKED_IN_PATHS # Regular expression that matches code only used for test binaries @@ -109,6 +113,10 @@ def FilterJSFile(affected_file): affected_file, files_to_check=(r'.+\.m?js')) + def FilterGeneratedFile(affected_file): + return input_api.FilterSourceFile( + affected_file, files_to_skip=_GENERATED_CHECKED_IN_PATHS) + results = [] if not CppLintProcessor().RunOnFiles( input_api.AffectedFiles(file_filter=FilterFile, include_deletes=False)): @@ -122,7 +130,8 @@ def FilterJSFile(affected_file): include_deletes=False)): results.append(output_api.PresubmitError("JS format check failed")) if not SourceProcessor().RunOnFiles( - input_api.AffectedFiles(include_deletes=False)): + input_api.AffectedFiles( + file_filter=FilterGeneratedFile, include_deletes=False)): results.append(output_api.PresubmitError( "Copyright header, trailing whitespaces and two empty lines " \ "between declarations check failed")) @@ -291,7 +300,9 @@ def _CheckHeadersHaveIncludeGuards(input_api, output_api): file_inclusion_pattern = r'src/.+\.h' def FilterFile(affected_file): - files_to_skip = _EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + files_to_skip = ( + _EXCLUDED_PATHS + input_api.DEFAULT_FILES_TO_SKIP + + _GENERATED_CHECKED_IN_PATHS) return input_api.FilterSourceFile( affected_file, files_to_check=(file_inclusion_pattern, ), diff --git a/deps/v8/agents/PRESUBMIT.py b/deps/v8/agents/PRESUBMIT.py index 7cf5428231c9..c53bb84d1d9c 100644 --- a/deps/v8/agents/PRESUBMIT.py +++ b/deps/v8/agents/PRESUBMIT.py @@ -6,13 +6,16 @@ def _CommonChecks(input_api, output_api): - return input_api.RunTests( - input_api.canned_checks.GetUnitTestsInDirectory( - input_api, - output_api, - 'scripts', - files_to_check=[r'.+_test\.py$'], - run_on_python2=False)) + tests = [] + for directory in ('scripts', 'skills/clusterfuzz/scripts'): + tests.extend( + input_api.canned_checks.GetUnitTestsInDirectory( + input_api, + output_api, + directory, + files_to_check=[r'.+_test\.py$'], + run_on_python2=False)) + return input_api.RunTests(tests) def CheckChangeOnCommit(input_api, output_api): diff --git a/deps/v8/agents/rules/execution-constraints.md b/deps/v8/agents/rules/execution-constraints.md index 13a860d1ed81..976c2ff03759 100644 --- a/deps/v8/agents/rules/execution-constraints.md +++ b/deps/v8/agents/rules/execution-constraints.md @@ -55,15 +55,16 @@ To ensure efficient operation and prevent resource waste: 09. **Verify CL Contents Before Upload**: Before running `git cl upload`, ALWAYS verify that the diff relative to upstream contains ONLY the intended - changes. Use `git diff --name-only origin/main..HEAD` to check the list of + changes. Use `git diff --name-only @{upstream}...HEAD` to check the list of files being uploaded. If unrelated files are present, remove them before uploading. -10. **Respect Existing CL Descriptions**: **NEVER** run - `git cl upload --commit-description=+` or `git cl desc -n` with a generic - file to upload subsequent patchsets unless you have explicitly verified that - the user has not made Web UI edits. Omit `--commit-description` on - subsequent uploads to preserve human-authored online edits. +10. **Respect Existing CL Descriptions**: On subsequent patchset uploads, omit + `--commit-description` unless the CL description itself needs updating. + Before updating an existing CL's description (`git cl description -n +`), + check the current Gerrit description (`git cl description -d`) and carry + over any online edits and the `Change-Id:` footer into the local commit + message so human-authored changes are not lost. 11. **Explicit Absolute Paths**: When presenting or linking to files/directories that are outside the current workspace directory (such as the App Data diff --git a/deps/v8/agents/rules/git-cl.md b/deps/v8/agents/rules/git-cl.md index 2a36db0e0a23..fb2541b25079 100644 --- a/deps/v8/agents/rules/git-cl.md +++ b/deps/v8/agents/rules/git-cl.md @@ -10,67 +10,80 @@ These rules enforce V8-specific workflow mandates and guardrails when working with Chromium's `git cl` tool. For general Chromium Gerrit CL workflows, commands (such as creating commits, -running try jobs, polling presubmit status, and commenting), and options, refer -to the **`git-cl-helper`** skill -([SKILL.md](agents/shared/skills/git-cl-helper/SKILL.md)). +uploading CLs, updating descriptions with `git cl description -n +`, running try +jobs, polling presubmit status, and commenting), and options, refer to the +**`git-cl-helper`** skill +([SKILL.md](/agents/shared/skills/git-cl-helper/SKILL.md)). ## V8 Upload & Commit Mandates - **Always Format**: Run `git cl format` before creating a commit or uploading a - CL (as detailed in the `git-cl-helper` skill). Note that `upload_cl.sh` - enforces formatting compliance and will abort if uncommitted formatting diffs - exist. -- **Upload Script**: In V8, all initial and patchset uploads MUST be performed - using - `agents/scripts/upload_cl.sh [patchset_message] [additional flags...]`. - This script enforces formatting checks, performs non-interactive uploads, runs - release test checks, and validates commit description line lengths. - - **Initial Upload**: For a new CL without an existing issue association, - execute `agents/scripts/upload_cl.sh new check`. - - **Subsequent Uploads**: For updating an existing patchset, run - `agents/scripts/upload_cl.sh cur check "Brief patchset description"`. - - **Checks**: The "check" flag runs all mjsunit tests. When no code was - updated, or tests were already successfully run, "nocheck" can be passed. + CL (as detailed in the `git-cl-helper` skill). If it makes any changes, commit + them before proceeding with the upload. +- **Uploading CLs**: Use `git cl upload` (as detailed in the `git-cl-helper` + skill) with `SKIP_GCE_AUTH_FOR_GIT=1 GIT_EDITOR=true` to avoid interactive + editor or auth prompts: + - **Initial Upload (Always WIP)**: For a new CL without an existing issue + association (`git cl issue` is `None`), pass `-T -o wip` so the CL starts in + **WIP** mode without prompting for a patchset title: + `SKIP_GCE_AUTH_FOR_GIT=1 GIT_EDITOR=true git cl upload -T -o wip` + - **Subsequent Uploads (Default)**: While iterating on a CL, running + self-reviews, fixing bugs/tests, or addressing review comments, pass + `-t "Brief patchset description"` (and omit `-o wip`, `--ready`, and + `--commit-description`): + `SKIP_GCE_AUTH_FOR_GIT=1 GIT_EDITOR=true git cl upload -t "Brief patchset description"` + This lets Gerrit preserve the CL's existing WIP or Ready-for-Review state + and online description without switching a CL that is already in review back + to WIP. Only pass `-o wip` on a subsequent upload if explicitly switching a + CL back to WIP. + - **Ready for Review (Non-WIP + Mandatory Dry-Run)**: **ALWAYS obtain explicit + user confirmation before setting a CL to ready (non-WIP) or passing + `--ready`.** Only switch a CL to non-WIP once the user explicitly asks to + mark the CL "ready for review", "unjail/un-WIP", or "send to reviewers", and + only after a CQ dry-run (`-d` / `--cq-dry-run` or `git cl try`) has passed + on the current patchset. (User confirmation to *"upload"*, *"trigger a + dry-run"*, or *"watch the CQ"* is **NOT** confirmation to exit WIP.) Once + confirmed and the dry-run has passed, exit WIP using `--ready` on upload (if + uploading a new patchset) or via `gerrit_client.py`: + `gerrit_client.py rawapi --host https://chromium-review.googlesource.com --path "/changes//ready" --method POST --accept_status "200,204"` + If a dry-run fails, do not mark the CL ready; investigate the failing bots + (inspecting logs via `gerrit_cq`), determine the root cause, and ask the + user about next steps. - **Updating Description**: If the changes in a new patchset make the existing CL description **out-of-date** or inaccurate, you **MUST** explicitly update - it. Choose the approach based on your task: - - **When uploading code changes (Default)**: Pass `--commit-description="..."` - directly to `upload_cl.sh` so the patchset and description update atomically - in one step: - `agents/scripts/upload_cl.sh cur check "Patchset title" --commit-description="New cohesive description content"` - - **When updating description only**: If you are refining wording, fixing - typos, or updating tags without uploading new code changes, run the - standalone editor script: - `agents/scripts/edit_cl_description.sh "New cohesive description content"` - **⚠️ CRITICAL SAFETY CONSTRAINT**: Before passing `--commit-description` or - running `edit_cl_description.sh`, you must first inspect the live remote - description on Gerrit (using either `git cl desc -d` or the - `gerrit_get_change_details` MCP tool) to verify whether the user has - manually edited it. If manual user edits or refinements are detected, you - must carefully evaluate them: preserve any human-authored background - context, rationale, or formatting, while surgically updating only the - outdated technical statements resulting from the new patchset. -- **Wrap Commit Message**: Ensure commit message descriptions are strictly - wrapped at 78 characters. `upload_cl.sh` automatically enforces this limit. -- Verify `git diff` is not empty before uploading. + it in the local git commit message and sync it to Gerrit: + - **When uploading code changes**: Pass `--commit-description=+` to + `git cl upload` so the patchset and description update together. + - **When updating description only**: Amend the local git commit message and + run `git cl description -n +` (as detailed in the `git-cl-helper` skill). + **⚠️ CRITICAL SAFETY CONSTRAINT**: Before passing `--commit-description=+` + or running `git cl description -n +`, you must first inspect the live remote + description on Gerrit (using either `git cl description -d` or a Gerrit MCP + tool) to verify whether the user has manually edited it. Carry over any + human-authored online edits, rationale, or formatting — as well as the + `Change-Id:` footer line — into your local commit message while surgically + updating only the outdated technical statements. +- **Commit Message Length Limits**: Keep the commit title at most 72 characters + (aiming for ~50 characters) and wrap description body lines at 72 characters. +- Verify `git diff @{upstream}...HEAD` is not empty before uploading. ## Safeguards & Code Quality -- **Mandatory Reproducer Rule**: Before running `git cl upload` or - `upload_cl.sh`, you MUST verify that the diff contains a valid, working - regression test (typically under `test/mjsunit/` or its component-specific - subfolders like `compiler/`, `turboshaft/`, `maglev/`, etc.). Uploading - code-modifying CLs without an accompanying regression test is strictly - forbidden (unless explicitly waived by the user or if it's a - process-only/documentation change). +- **Mandatory Reproducer Rule**: Before running `git cl upload`, you MUST verify + that the diff contains a valid, working regression test (typically under + `test/mjsunit/` or its component-specific subfolders like `compiler/`, + `turboshaft/`, `maglev/`, etc.). Uploading code-modifying CLs without an + accompanying regression test is strictly forbidden (unless explicitly waived + by the user or if it's a process-only/documentation change). - **No Trailing Whitespace**: NEVER add trailing whitespace in any file you create or modify. - **Always Test Before Upload**: Always run tests (using `release` or `optdebug` mode, avoiding `debug` mode due to performance) before uploading. - **ALWAYS keep CLs separate**: If you are working on more than one task at the - same time always use `agents/scripts/create_worktree.sh ` to create - an isolated workspace for each independent task or CL. Worktrees are created - at `REPOSITORY_ROOT/worktrees/`. NEVER upload a CL from a workspace containing + same time always use + `agents/scripts/create_worktree.sh [base_branch]` to create an + isolated workspace for each independent task or CL. Worktrees are created at + `REPOSITORY_ROOT/worktrees/`. NEVER upload a CL from a workspace containing unrelated modifications. Always verify that the diff relative to upstream contains ONLY the intended changes before uploading. - **Consult user on external changes**: When `git cl upload` detects external @@ -84,33 +97,34 @@ to the **`git-cl-helper`** skill - **Verify Issue Description**: Before uploading, run `git cl status` to verify the Issue Description matches your task. - **Review Modified Files**: Review the modified files (`git show --stat`) or - run `git diff --name-only origin/main..HEAD` to ensure no unrelated files are + run `git diff --name-only @{upstream}...HEAD` to ensure no unrelated files are included. If you see commits or files that are not part of your specific task, - reset your branch to `origin/main` and cherry-pick only your intended commits + reset your branch to `@{upstream}` and cherry-pick only your intended commits instead of uploading. - **Verify Alignment**: Verify alignment of the subsystem/context in `git cl status` before proceeding, and consult the user if it seems mismatched. - **Process-Only CLs**: For CLs intended to contain ONLY process/documentation changes, verify that no code files (e.g., `.cc`, `.h`, `.js`, `.py`) are - modified using `git diff --name-only origin/main`. + modified using `git diff --name-only @{upstream}...HEAD`. ## Proactive Alert Handling & Post-Upload - **Proactive Alert Handling**: After uploading, check the presubmit and tryjob - status. Choose the approach based on your situation: - - **Immediate Check (Default)**: Run `git cl status` immediately after - uploading to verify branch alignment and quickly check high-level issue + status: + - Run `git cl status` after uploading to verify branch alignment and issue status. - - **When Waiting for Trybots**: If the user explicitly asks to monitor or wait - for tryjobs to complete, or if you need detailed Buildbucket failure logs to - debug presubmit build errors, run the polling script from the - `git-cl-helper` skill: - `vpython3 agents/shared/skills/git-cl-helper/scripts/git_cl_helper.py poll --gerrit_url ` - If you identify failing checks or try jobs, proactively suggest addressing - these alerts to the user. -- **Post-Upload**: Provide the `chromium-review.googlesource.com` link to the - user. + - When a CQ dry-run is triggered (`-d` / `--cq-dry-run` or `git cl try`), wait + for completion asynchronously in a background task (e.g., via + `vpython3 agents/shared/skills/git-cl-helper/scripts/git_cl_helper.py poll --gerrit_url ` + or monitoring `git cl status --field=status`) and inspect bot results using + `gerrit_cq`. + - If any builds fail, zoom into the failure logs + (`gerrit_cq(builder="")`), triage whether it is an infrastructure + issue, a known flake, or a real regression, and ask the user about next + steps with proposed fixes. +- **Post-Upload**: Provide the `chromium-review.googlesource.com` (or + `https://crrev.com/c/`) link to the user. ## Retrieving and Addressing Comments @@ -130,8 +144,9 @@ to the **`git-cl-helper`** skill When working on a chain of dependent changes (stacked CLs): - **Upstream Configuration**: Set the upstream of a child branch to its parent - branch (e.g., `git branch --set-upstream-to=parent-branch`). The base branch - at the bottom of the stack tracks `origin/main`. + branch (e.g., `agents/scripts/create_worktree.sh ` or + `git branch --set-upstream-to=parent-branch`). The base branch at the bottom + of the stack tracks `origin/main`. - **Rebasing**: When the parent branch changes, rebase the child branch on top of the updated parent. - **Unique Change-Ids**: Ensure each CL in the stack has a unique `Change-Id`. @@ -142,7 +157,7 @@ When working on a chain of dependent changes (stacked CLs): - Use `git cl patch ` to fetch and checkout the latest patchset of a CL. - Use `git cl land` to land the CL after approval. -- Use `git cl desc -d` to view the CL description. -- Use `agents/scripts/edit_cl_description.sh "New description"` (or `-f `) - to non-interactively update a CL description after validating line lengths and - code formatting. +- Use `git cl description -d` to view the CL description. +- Use `git cl description -n +` to update a CL description on Gerrit from the + latest local git commit (after checking `git cl description -d` and preserving + `Change-Id:` and any online edits). diff --git a/deps/v8/agents/rules/git-commit.md b/deps/v8/agents/rules/git-commit.md index d68536add77d..a0c9deb9c4b9 100644 --- a/deps/v8/agents/rules/git-commit.md +++ b/deps/v8/agents/rules/git-commit.md @@ -11,10 +11,15 @@ commands in V8. ## Commit Message Format - **Title**: Must follow the format `[component] Title`. + - Keep the title short, concise, and punchy: aim for ~50 characters, and at + most 72 characters (including the `[component]` prefix). Prefer high-level + intent over verbose implementation details. - Use `[agents] title` ONLY for changes to the agent automation suite itself. -- **Description**: Provide a clear explanation of "why" and "what". Wrap lines - at 72 characters. Focus on content and effects, not the process. Highlight the - rationale and key non-obvious design decisions. +- **Description**: Keep the body concise (aim for at most 10 lines) and include + only essential information. Explain "why" and the high-level "what" without + restating details that are obvious from the diff. Focus on content, rationale, + and key non-obvious design decisions, not the process. Wrap lines at 72 + characters. - Maintain a cohesive summary: Rewrite or integrate new descriptions into a cohesive summary instead of simply appending them. - **Tone**: Use concise, declarative, and natural engineering language. @@ -24,13 +29,16 @@ commands in V8. changes. - Ensure the `Change-Id` footer is preserved in the commit message. - **Bug Lines**: + - When a CL fixes a bug, write `Fixed: ` (e.g., `Fixed: 509339491`). + Write `Bug:` when the CL is related to a bug without fully resolving it. - For **public bugs** (e.g., `issues.chromium.org`), use the plain numerical - bug ID ONLY (e.g., `Bug: 509339491`) without any prefix. + bug ID ONLY (e.g., `Fixed: 509339491` or `Bug: 509339491`) without any + prefix. - For **internal bugs** (e.g., Google-internal Buganizer), use the `b:` - prefix (e.g., `Bug: b:349680002`). + prefix (e.g., `Fixed: b:349680002` or `Bug: b:349680002`). - When listing multiple bugs, limit bug listings to a maximum of 4 or 5 per line (Gerrit stops rendering them as links). If you have more, add a - second `Bug:` line. + second `Fixed:` or `Bug:` line. ## Git Command Usage & Avoiding Interactive Hangs @@ -48,7 +56,8 @@ commands in V8. changes and ask how they want to proceed (e.g., create new branch, discard, or hold) before uploading. - **Base on Clean Upstream**: Base new branches on a clean upstream (e.g., - `origin/main`). When creating a new worktree or branch (e.g., - `git worktree add -b branch_name path origin/main`), **always explicitly - specify `origin/main`** as the base commit to ensure isolation from unrelated - local commits. + `origin/main`, or the parent branch for stacked CLs). When creating a new + worktree or branch (e.g., via + `agents/scripts/create_worktree.sh [base_branch]`), **always + explicitly specify the base branch** (defaulting to `origin/main`) to ensure + isolation from unrelated local commits. diff --git a/deps/v8/agents/rules/v8-best-practices.md b/deps/v8/agents/rules/v8-best-practices.md index 6609c5c88ef9..f2bf3bd0467d 100644 --- a/deps/v8/agents/rules/v8-best-practices.md +++ b/deps/v8/agents/rules/v8-best-practices.md @@ -30,6 +30,14 @@ When proposing a fix, ensure the code adheres to V8 standards: - **Cross-Feature Awareness**: Understand how optimizations interact with core V8 features like Lazy Compilation, Ignition bytecode generation, and TurboFan/Maglev optimizations. +- **Fail Fast Over Defensive Workarounds**: Never introduce defensive + programming patterns to paper over unexpected compiler states or invariant + violations (e.g., silent early returns, fallback dummy values, defensive + clamping, or non-exhaustive switch `default: break;`). If an invariant is + expected to hold, assert it via `DCHECK` or `CHECK` so that violations are + caught immediately by debug builds and fuzzers rather than masked. +- **Encapsulation**: Encapsulate data-structure mutations as methods on the + owning class rather than duplicating low-level steps across callers. - **Mandatory Reproducer Rule**: Unless explicitly specified otherwise by the user, **every single bug fix in V8 MUST be uploaded with a working reproducer (regression test)**. Uploading just the fix alone is NEVER acceptable. @@ -41,6 +49,13 @@ When proposing a fix, ensure the code adheres to V8 standards: a missing definition, you are likely missing an `#include` for a `-inl.h` file. You can only include `-inl.h` files from other `-inl.h` files and `.cc` files. +- **`.cc` vs. `.h` Placement & Anonymous Namespaces**: Place non-trivial, + non-hot method definitions in the corresponding `.cc` file rather than inline + in `.h`, and place file-local helpers that do not need `this` in an anonymous + `namespace {}` in the `.cc` file rather than as private class methods. +- **Pre-Upload Diff Self-Review**: Inspect `git diff` before uploading to ensure + minimal diff noise, tight local variable scopes (declaring variables at first + use), and clean regression tests. - **Cleanup Constraint**: Keep diffs small by changing only the code intended for the task. Propose cleanups to nearby code as a separate patch to keep the current change focused. diff --git a/deps/v8/agents/rules/writing-skills.md b/deps/v8/agents/rules/writing-skills.md index 317ddf821825..9f36d5be682d 100644 --- a/deps/v8/agents/rules/writing-skills.md +++ b/deps/v8/agents/rules/writing-skills.md @@ -1,6 +1,7 @@ --- name: writing-skills-rule -trigger: agents/**/* +trigger: model_decision +description: Guidelines and best practices for writing, modifying, and structuring skills and rules in agents/ --- # Best Practices for Writing Skills and Rules in `agents/` @@ -80,10 +81,11 @@ Maintain a pristine context window by loading information only when needed. Create instructions for LLMs instead of humans. - **Tone and Style**: - - **Positive Framing**: Focus on what the agent *should* do. If you must - specify a constraint, provide an alternative. - - *Bad (Negative)*: "Do not use Python 2." - - *Good (Positive)*: "Always use Python 3 for new scripts." + - **Positive Framing (Prefer "ALWAYS" over "NEVER")**: Focus on affirmative + instructions rather than negative prohibitions. LLMs attend to mentioned + concepts; negative constraints ("NEVER do X") can prime the forbidden + behavior (pink elephant effect) without providing an actionable default. + State the required behavior directly ("ALWAYS do X" or "Only do X when Y"). - **Third-Person Imperative**: Frame instructions as direct commands (e.g., "Extract the text..." rather than "I will extract..."). - **Procedural Instructions**: diff --git a/deps/v8/agents/scripts/create_worktree.sh b/deps/v8/agents/scripts/create_worktree.sh index 81ee1049c500..9326711dbda7 100755 --- a/deps/v8/agents/scripts/create_worktree.sh +++ b/deps/v8/agents/scripts/create_worktree.sh @@ -3,8 +3,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. TASK_ID=$1 +BASE_BRANCH="${2:-origin/main}" if [ -z "$TASK_ID" ]; then - echo "Usage: create_worktree.sh " + echo "Usage: create_worktree.sh [base_branch]" exit 1 fi @@ -51,7 +52,8 @@ WORKTREE_PATH="$V8_ROOT/worktrees/$BRANCH_NAME" mkdir -p "$V8_ROOT/worktrees" -if ! git worktree add -b "$BRANCH_NAME" "$WORKTREE_PATH" origin/main; then +if ! git worktree add --track -b "$BRANCH_NAME" "$WORKTREE_PATH" "$BASE_BRANCH" 2>/dev/null && \ + ! git worktree add -b "$BRANCH_NAME" "$WORKTREE_PATH" "$BASE_BRANCH"; then echo "Error: Failed to create git worktree at $WORKTREE_PATH" >&2 exit 1 fi diff --git a/deps/v8/agents/scripts/edit_cl_description.sh b/deps/v8/agents/scripts/edit_cl_description.sh deleted file mode 100755 index 1bb1ab63f897..000000000000 --- a/deps/v8/agents/scripts/edit_cl_description.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# Copyright 2026 the V8 project authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Script to non-interactively edit/update the Gerrit CL description for the current branch. -# It enforces commit description line-length formatting (max 78 chars) and code formatting. - -if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then - echo "Usage: edit_cl_description.sh <\"New description string\" | -f | + | ->" - echo "Updates the Gerrit CL description for the current branch non-interactively after checking formatting." - exit 0 -fi - -DESC="" - -if [ "$1" = "-f" ] || [ "$1" = "--file" ]; then - if [ -z "$2" ] || [ ! -f "$2" ]; then - echo "Error: File '$2' not found." - exit 1 - fi - DESC=$(cat "$2") -elif [ "$1" = "-n" ] || [ "$1" = "-m" ] || [ "$1" = "--desc" ] || [ "$1" = "--message" ] || [ "$1" = "--new-description" ]; then - DESC="$2" -elif [[ "$1" == -n=* ]] || [[ "$1" == -m=* ]] || [[ "$1" == --desc=* ]] || [[ "$1" == --message=* ]] || [[ "$1" == --new-description=* ]]; then - DESC="${1#*=}" -elif [ "$1" = "+" ]; then - DESC=$(git log -1 --pretty=%B 2>/dev/null) -elif [ "$1" = "-" ]; then - DESC=$(cat) -elif [ -n "$1" ]; then - DESC="$*" -elif [ ! -t 0 ]; then - DESC=$(cat) -else - echo "Error: No new description provided." - echo "Usage: edit_cl_description.sh <\"New description string\" | -f | + | ->" - exit 1 -fi - -if [ -z "$DESC" ]; then - echo "Error: The provided CL description is empty." - exit 1 -fi - -# Guardrail: Early authentication check -if command -v gcertstatus >/dev/null 2>&1; then - if ! gcertstatus -nocheck_ssh -quiet 2>/dev/null; then - echo "Error: Authentication expired or missing. Please run 'gcert' before updating description." - exit 1 - fi -fi - -# Guardrail: Verify git cl format changes nothing -git cl format > /dev/null 2>&1 -if ! git diff --quiet HEAD; then - echo "Error: git cl format resulted in code formatting changes. Please review and commit code formatting changes before updating the CL description." - exit 1 -fi - -echo "$DESC" | "$SCRIPT_DIR/validate_cl_description.py" || exit 1 - -# Guardrail: Check if branch is associated with an issue -ISSUE_OUTPUT=$(git cl issue 2>&1) -if [[ "$ISSUE_OUTPUT" == *"None"* ]]; then - echo "Error: git cl issue reports no issue associated with this branch. Cannot update remote description." - exit 1 -fi - -echo "Updating CL description on Gerrit..." -SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl desc -f -n "$DESC" -STATUS=$? - -if [ $STATUS -ne 0 ]; then - echo "Error updating CL description." - exit $STATUS -fi - -echo "CL description updated successfully." diff --git a/deps/v8/agents/scripts/upload_cl.sh b/deps/v8/agents/scripts/upload_cl.sh deleted file mode 100755 index 4739d64fb344..000000000000 --- a/deps/v8/agents/scripts/upload_cl.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/bin/bash -# Copyright 2026 the V8 project authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -MODE="$1" -CHECK_MODE="$2" -PATCH_MSG="${3:-Update patchset}" - -if [ -z "$MODE" ] || [ -z "$CHECK_MODE" ]; then - echo "Usage: upload_cl.sh [patchset_message]" - exit 1 -fi - -if [ "$MODE" != "new" ] && [ "$MODE" != "cur" ]; then - echo "Error: First argument must be 'new' or 'cur'." - echo "Usage: upload_cl.sh [patchset_message]" - exit 1 -fi - -if [ "$CHECK_MODE" != "check" ] && [ "$CHECK_MODE" != "nocheck" ]; then - echo "Error: Second argument must be 'check' or 'nocheck'." - echo "Usage: upload_cl.sh [patchset_message]" - exit 1 -fi - -# Shift positional parameters so "$@" contains any additional flags passed to upload_cl.sh -if [ $# -ge 3 ]; then - shift 3 -else - shift $# -fi - -# Guardrail: Check commit description line lengths (max 78 chars, ignoring lines with URLs) -DESC_TO_CHECK="" -CHECK_DESC=false -HAS_CUSTOM_DESC=false - -prev_arg="" -for arg in "$@"; do - if [[ "$arg" == --commit-description=* ]] || [[ "$arg" == --message=* ]] || [[ "$arg" == -m=* ]]; then - HAS_CUSTOM_DESC=true - val="${arg#*=}" - if [ "$val" != "+" ]; then - DESC_TO_CHECK="$val" - CHECK_DESC=true - else - DESC_TO_CHECK=$(git log -1 --pretty=%B 2>/dev/null) - CHECK_DESC=true - fi - elif [ "$arg" == "-m+" ]; then - HAS_CUSTOM_DESC=true - DESC_TO_CHECK=$(git log -1 --pretty=%B 2>/dev/null) - CHECK_DESC=true - elif [ "$prev_arg" == "--commit-description" ] || [ "$prev_arg" == "--message" ] || [ "$prev_arg" == "-m" ]; then - HAS_CUSTOM_DESC=true - if [ "$arg" != "+" ]; then - DESC_TO_CHECK="$arg" - CHECK_DESC=true - else - DESC_TO_CHECK=$(git log -1 --pretty=%B 2>/dev/null) - CHECK_DESC=true - fi - elif [ "$arg" == "--commit-description" ] || [ "$arg" == "--message" ] || [ "$arg" == "-m" ]; then - HAS_CUSTOM_DESC=true - fi - prev_arg="$arg" -done - -# If uploading a new CL and no explicit commit description flag was passed, check local commit message -if [ "$CHECK_DESC" = false ] && [ "$MODE" = "new" ]; then - DESC_TO_CHECK=$(git log -1 --pretty=%B 2>/dev/null) - CHECK_DESC=true -fi - -if [ "$CHECK_DESC" = true ] && [ -n "$DESC_TO_CHECK" ]; then - echo "$DESC_TO_CHECK" | "$SCRIPT_DIR/validate_cl_description.py" || exit 1 -fi - -# Guardrail: Early authentication check -if command -v gcertstatus >/dev/null 2>&1; then - if ! gcertstatus -nocheck_ssh -quiet 2>/dev/null; then - echo "Error: Authentication expired or missing. Please run 'gcert' before uploading." - exit 1 - fi -fi - -# Guardrail: Never upload directly from main branch -CUR_BRANCH=$(git branch --show-current) -if [ "$CUR_BRANCH" = "main" ] || [ "$CUR_BRANCH" = "master" ]; then - echo "Error: Cannot upload directly from the main branch. Please switch to an isolated task branch." - exit 1 -fi - -# Guardrail: Verify git diff is not empty before uploading -if git diff --quiet origin/main; then - echo "Error: Branch has no changes relative to origin/main. Cannot upload an empty CL." - exit 1 -fi - -# Guardrail: Verify no edited files are uncommitted -if ! git diff --quiet HEAD; then - echo "Error: Uncommitted changes detected. Please commit or stash all tracked modified files before uploading." - exit 1 -fi - -# Guardrail: Ensure git cl format changes nothing -git cl format > /dev/null 2>&1 -if ! git diff --quiet HEAD; then - echo "Error: git cl format resulted in formatting changes. Please review and commit formatting changes before uploading." - exit 1 -fi - -# Guardrail: Ensure gm.py release checks pass if check requested -if [ "$CHECK_MODE" = "check" ]; then - V8_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" - - ARCH=$(uname -m) - if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then - V8_ARCH="arm64" - elif [ "$ARCH" = "x86_64" ]; then - V8_ARCH="x64" - elif [ "$ARCH" = "i686" ] || [ "$ARCH" = "i386" ]; then - V8_ARCH="ia32" - else - V8_ARCH="x64" - fi - - echo "Running '$V8_ROOT/tools/dev/gm.py quiet ${V8_ARCH}.release mjsunit'. This might take a while." - if ! "$V8_ROOT/tools/dev/gm.py" "quiet" "${V8_ARCH}.release" "mjsunit"; then - echo "Error: Tests failed (gm.py ${V8_ARCH}.release.check). Ensure all release checks pass before uploading." - exit 1 - fi -fi - -ISSUE_OUTPUT=$(git cl issue 2>&1) -if [[ "$ISSUE_OUTPUT" == *"None"* ]]; then - HAS_ISSUE=false -else - HAS_ISSUE=true -fi - -if [ "$MODE" = "new" ]; then - if [ "$HAS_ISSUE" = true ]; then - echo "Error: Mode 'new' specified, but git cl issue reports this branch is already associated with an issue." - exit 1 - fi - if [ "$HAS_CUSTOM_DESC" = true ]; then - UPLOAD_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload -t "Initial upload" "$@" 2>&1) - else - UPLOAD_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload --commit-description=+ -t "Initial upload" "$@" 2>&1) - fi - UPLOAD_STATUS=$? -else - if [ "$HAS_ISSUE" = false ]; then - echo "Error: Mode 'cur' specified, but git cl issue reports no issue associated with this branch. Link with the existing issue using \`git cl issue \`." - exit 1 - fi - UPLOAD_OUTPUT=$(SKIP_GCE_AUTH_FOR_GIT=1 EDITOR=cat git cl upload -t "$PATCH_MSG" "$@" 2>&1) - UPLOAD_STATUS=$? -fi - -if [ $UPLOAD_STATUS -ne 0 ]; then - echo "Error during git cl upload:" - echo "$UPLOAD_OUTPUT" - exit $UPLOAD_STATUS -fi - -CL_URL=$(echo "$UPLOAD_OUTPUT" | grep -o 'https://chromium-review.googlesource.com/c/v8/v8/+/[0-9]*' | head -n 1) -if [ -n "$CL_URL" ]; then - echo "$CL_URL" -else - echo "$UPLOAD_OUTPUT" -fi diff --git a/deps/v8/agents/scripts/validate_cl_description.py b/deps/v8/agents/scripts/validate_cl_description.py deleted file mode 100755 index db2e3cf14dd7..000000000000 --- a/deps/v8/agents/scripts/validate_cl_description.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 the V8 project authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Validates a commit description against Gerrit line length and Change-Id rules.""" - -import re -import subprocess -import sys - - -def validate_description(desc: str) -> bool: - if not desc or not desc.strip(): - return True - - lines = desc.splitlines() - bad_lines = [] - - footer_regex = re.compile( - r'^(Change-Id|Reviewed-on|Reviewed-by|Commit-Queue|Cr-Commit-Position|Bug|Fixed|TAG|Conversation-ID):' - ) - - for i, line in enumerate(lines, start=1): - # Ignore comment lines - if line.lstrip().startswith('#'): - continue - - if len(line) > 78: - # Exclude URLs and short links - if '://' in line or 'go/' in line or 'goto.google.com/' in line: - continue - # Exclude standard metadata footers - if footer_regex.match(line): - continue - # Exclude single unbroken tokens (file paths, symbol names) without whitespace - if ' ' not in line.strip(): - continue - - bad_lines.append(f'Line {i} ({len(line)} chars): {line[:40]}...') - - if bad_lines: - print( - 'Error: The commit description contains lines exceeding the 78 character maximum length limit:', - file=sys.stderr) - for bad in bad_lines: - print(f' {bad}', file=sys.stderr) - print( - 'Please wrap commit message descriptions strictly at 78 characters before proceeding.', - file=sys.stderr) - return False - - # Check Change-Id count - change_ids = [line for line in lines if line.startswith('Change-Id:')] - if len(change_ids) > 1: - print( - f'Error: Multiple Change-Id lines detected in commit message ({len(change_ids)} found).', - file=sys.stderr) - print( - 'Please keep only the correct Change-Id for this branch before proceeding.', - file=sys.stderr) - return False - - # Check Change-Id match against expected commit/CL - try: - expected_ids = [] - try: - cl_proc = subprocess.run(['git', 'cl', 'desc', '-d'], - capture_output=True, - text=True, - check=True) - expected_ids = [ - line.strip() - for line in cl_proc.stdout.splitlines() - if re.match(r'^Change-Id: I[0-9a-fA-F]+', line) - ] - except (subprocess.CalledProcessError, FileNotFoundError): - pass - - if not expected_ids: - log_proc = subprocess.run( - ['git', '--no-pager', 'log', '-1', '--pretty=%B'], - capture_output=True, - text=True, - check=True) - expected_ids = [ - line.strip() - for line in log_proc.stdout.splitlines() - if re.match(r'^Change-Id: I[0-9a-fA-F]+', line) - ] - - if expected_ids and len(change_ids) == 1: - expected_id = expected_ids[-1] - msg_id = change_ids[0].strip() - if msg_id != expected_id: - print( - f'Error: The Change-Id in the description ({msg_id}) does not match the expected Change-Id ({expected_id}) for this branch.', - file=sys.stderr) - print( - 'Please preserve the original Change-Id to avoid creating duplicate CLs.', - file=sys.stderr) - return False - except (subprocess.CalledProcessError, FileNotFoundError): - pass - - return True - - -def main(): - if len(sys.argv) > 1 and sys.argv[1] != '-': - desc = sys.argv[1] - else: - desc = sys.stdin.read() - - if not validate_description(desc): - sys.exit(1) - sys.exit(0) - - -if __name__ == '__main__': - main() diff --git a/deps/v8/agents/skills/clusterfuzz/SKILL.md b/deps/v8/agents/skills/clusterfuzz/SKILL.md new file mode 100644 index 000000000000..0b15333200c9 --- /dev/null +++ b/deps/v8/agents/skills/clusterfuzz/SKILL.md @@ -0,0 +1,137 @@ +--- +name: clusterfuzz +description: >- + Downloads, manages, and prepares test cases and reproducers for ClusterFuzz in V8. + Use when downloading test cases or fetching reproduction flags/metadata from + clusterfuzz.com, or preparing crashing POCs and upload packages for ClusterFuzz. + Don't use for generic git bisect or general bug triage. +--- + +# Skill: ClusterFuzz Test Case Management and Triage + +This skill provides procedures and tooling for interacting with public +ClusterFuzz (`clusterfuzz.com`) test cases in V8, including authenticated +downloads, flag/metadata extraction, reproducer escalation, and upload +packaging. (Note: This skill only works for public `clusterfuzz.com`; +corp-internal `clusterfuzz.corp.google.com` requires `sso_client`). + +______________________________________________________________________ + +## 1. Authentication (Setting Up `cookies.txt`) + +To authenticate with `clusterfuzz.com`, the tooling in this skill uses a +Netscape-formatted browser cookies file at `~/.config/clusterfuzz/cookies.txt`. + +**Manual User Prerequisite**: The agent CANNOT generate or export `cookies.txt` +itself. If `cookies.txt` is missing or expired, ask the user to perform these +manual steps: + +1. Log in to [https://clusterfuzz.com](https://clusterfuzz.com) in Chrome. +2. Export cookies for `clusterfuzz.com` in Netscape format (e.g., using the + Chrome extension + [Get cookies.txt LOCALLY](https://chromewebstore.google.com/detail/cclelndahbckbenkjhflpdbgdldlbecc)). +3. Save the file as `~/.config/clusterfuzz/cookies.txt`. + +______________________________________________________________________ + +## 2. Downloading Test Cases & Metadata + +### Using `fetch_testcase.py` (Recommended) + +Run the bundled [`fetch_testcase.py`](scripts/fetch_testcase.py) script to +handle cookies, redirects, and metadata: + +```bash +python3 agents/skills/clusterfuzz/scripts/fetch_testcase.py [options] +``` + +- **Download Test Case**: + + ```bash + python3 agents/skills/clusterfuzz/scripts/fetch_testcase.py [-o ] + ``` + + Auto-detects `~/.config/clusterfuzz/cookies.txt`. If `-o` is omitted, + downloads to a temporary file (`testcase_.js` or `.wasm`). + +- **Fetch Metadata & Minimized Flags (`--info`)**: + + ```bash + python3 agents/skills/clusterfuzz/scripts/fetch_testcase.py --info + ``` + + Queries `/testcase-detail/refresh` for minimized `d8` flags, random seed, job + type, crash revision, regression range, and recommended local `out/` + invocation. + +- **Save Full JSON Report (`--save-metadata`)**: + + ```bash + python3 agents/skills/clusterfuzz/scripts/fetch_testcase.py --save-metadata + ``` + +### Manual Fallback + +```bash +curl -b ~/.config/clusterfuzz/cookies.txt -s -L "https://clusterfuzz.com/download?testcase_id=" -o +``` + +______________________________________________________________________ + +## 3. Troubleshooting + +| Issue | Cause | Fix | +| :----------------------------- | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Response is HTML (~900 KB)** | Missing or expired `cookies.txt` on `clusterfuzz.com`. | Ask the user to re-export `cookies.txt` via [Get cookies.txt LOCALLY](https://chromewebstore.google.com/detail/cclelndahbckbenkjhflpdbgdldlbecc). | +| **Inaccessible / Redacted** | Restricted permissions. | Check Buganizer comments for attached POC, or ask user for testcase flags and content. | + +______________________________________________________________________ + +## 4. Preparing Reproducers for ClusterFuzz + +ClusterFuzz automated bisection and regression tracking require a **detectable +crash** (`DCHECK`, segfault, `SIGILL`, or `int3`). + +- **Standalone Script**: Must not depend on external files or shell wrappers. +- **Minimal Flags**: Keep only the minimum flags needed to reproduce. +- **Deterministic Crash**: Must reliably crash. +- **WebAssembly Reproducers**: If the testcase is a raw `.wasm` binary, convert + it to readable JavaScript using `wami` + (`out/x64.release/wami --mjsunit > `), following the + `minimize-reproducer` skill. + +### Escalating Silent Memory Corruption: + +If a bug causes memory corruption or a logic error without crashing: + +1. **Test Sanitized and Debug Builds**: Run against Debug (`x64.debug`), ASan + (`x64.asan`), or UBSan builds: + ```bash + timeout -v 15 out/x64.asan/d8 poc.js + ``` +2. **Force a Crash**: If no crash occurs naturally, modify the POC to force a + crash (e.g. overwrite an object Map or pointer with garbage `0x41414141` so + property access segfaults) while preserving the bug trigger. +3. **Verify on Release**: Confirm the reproducer crashes on Release builds. + +______________________________________________________________________ + +## 5. ClusterFuzz Upload Package + +The agent cannot upload directly to the web UI. If a verified crash is not yet +uploaded: + +1. **Verify**: Check Buganizer comments to confirm the crash is not already + uploaded. +2. **Assemble Package for User**: + - **Reproducer**: Path to minimized crashing script (e.g., `testcase.js` or + temporary file). + - **Job Type**: Recommended job (e.g., `linux_asan_d8`, `linux_d8_dbg`, + `v8_foozzie`). + - **Flags**: Minimal `d8` execution flags. + - **Target Revision**: Git commit hash and version from + `src/utils/version.h`. + - **Buganizer Issue ID**: Issue ID. + - **Upload URL**: `https://clusterfuzz.com/upload-testcase` +3. **User Action**: Present the package and advise the user to perform the + manual upload. diff --git a/deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase.py b/deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase.py new file mode 100755 index 000000000000..e4be3234cbbf --- /dev/null +++ b/deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase.py @@ -0,0 +1,398 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Fetches test cases and metadata from public ClusterFuzz (clusterfuzz.com). + +Supports: +- Downloading reproducer scripts (.js or .wasm) +- Fetching issue metadata (minimized d8 flags, job type, regression range, crash stack) +- Automatic cookie jar detection (~/.config/clusterfuzz/cookies.txt) +""" + +from __future__ import annotations + +import argparse +import http.cookiejar +import json +import os +from pathlib import Path +import re +import subprocess +import sys +import tempfile +from urllib.error import HTTPError, URLError +import urllib.parse +import urllib.request + +CLUSTERFUZZ_DOMAIN = "clusterfuzz.com" +DOWNLOAD_URL_FMT = "https://clusterfuzz.com/download?testcase_id={id}" +REFRESH_URL = "https://clusterfuzz.com/testcase-detail/refresh" + +COOKIE_EXTENSION_URL = ( + "https://chromewebstore.google.com/detail/cclelndahbckbenkjhflpdbgdldlbecc") + + +def print_missing_cookies_help() -> None: + """Prints instructions for exporting cookies.txt using the Chrome extension.""" + msg = f""" +================================================================================ +AUTHENTICATION REQUIRED: Missing or expired cookies for {CLUSTERFUZZ_DOMAIN} +================================================================================ +ClusterFuzz returned a login page or required authentication. +To authenticate command-line downloads: +1. Log in to https://clusterfuzz.com in Chrome with your @google.com or @chromium.org account. +2. Export your cookies for clusterfuzz.com in Netscape format. + Recommended extension: 'Get cookies.txt LOCALLY' + URL: {COOKIE_EXTENSION_URL} +3. Save the exported cookies file to: + ~/.config/clusterfuzz/cookies.txt + (or provide --cookies-file ). +================================================================================ +""" + print(msg.strip(), file=sys.stderr) + + +def find_cookies_file(specified: str | None = None) -> Path | None: + """Finds cookies.txt from CLI arguments or the default config location.""" + if specified: + p = Path(specified).expanduser().resolve() + if p.exists(): + return p + raise FileNotFoundError(f"Specified cookies file not found: {specified}") + + default_path = Path.home() / ".config" / "clusterfuzz" / "cookies.txt" + if default_path.exists(): + return default_path + return None + + +def parse_target(target: str) -> tuple[str, str]: + """Parses a target string (ID or URL) into (testcase_id, download_url).""" + target = target.strip() + + # Check if target is a pure numeric ID + if re.fullmatch(r"\d+", target): + return target, DOWNLOAD_URL_FMT.format(id=target) + + parsed = urllib.parse.urlparse(target) + if parsed.scheme not in ("http", "https") or parsed.hostname not in ( + CLUSTERFUZZ_DOMAIN, + f"www.{CLUSTERFUZZ_DOMAIN}", + ): + raise ValueError( + f"Invalid ClusterFuzz URL (expected {CLUSTERFUZZ_DOMAIN}): {target}") + + query_params = urllib.parse.parse_qs(parsed.query) + + testcase_id = None + for param in ("testcase_id", "id", "key"): + if param in query_params: + candidate = query_params[param][0] + if not re.fullmatch(r"\d+", candidate): + raise ValueError( + f"Invalid non-numeric testcase ID in URL query: {candidate!r}") + testcase_id = candidate + break + + if not testcase_id: + m = re.search(r"/(?:testcase-detail|testcase|download)/(\d+)(?:/|$)", + parsed.path) + if m: + testcase_id = m.group(1) + else: + m2 = re.search(r"/(\d+)/?$", parsed.path) + if m2: + testcase_id = m2.group(1) + + if not testcase_id or not re.fullmatch(r"\d+", testcase_id): + raise ValueError( + f"Could not extract a valid numeric testcase ID from target: {target}") + + return testcase_id, DOWNLOAD_URL_FMT.format(id=testcase_id) + + +def is_html_login_response(content: bytes) -> bool: + """Checks if content is an HTML login shell or error page instead of a testcase.""" + header_sample = content[:4096].lower() + if b" bytes: + """Downloads via curl, leveraging Netscape cookie jar if available.""" + cmd = ["curl", "-s", "-L"] + if cookies_file: + cmd.extend(["-b", str(cookies_file)]) + cmd.append(url) + + res = subprocess.run(cmd, capture_output=True, check=False) + if res.returncode != 0: + err_msg = res.stderr.decode("utf-8", errors="replace").strip() + raise RuntimeError(f"curl failed (exit {res.returncode}): {err_msg}") + return res.stdout + + +def download_urllib(url: str, cookies_file: Path | None) -> bytes: + """Downloads via urllib, using MozillaCookieJar if cookies file is available.""" + handlers: list[urllib.request.BaseHandler] = [] + if cookies_file: + try: + cj = http.cookiejar.MozillaCookieJar(str(cookies_file)) + cj.load(ignore_discard=True, ignore_expires=True) + handlers.append(urllib.request.HTTPCookieProcessor(cj)) + except Exception: + # If cookiejar parsing has formatting issues, fall back to curl + return download_curl(url, cookies_file) + + opener = urllib.request.build_opener(*handlers) + req = urllib.request.Request( + url, + headers={"User-Agent": "Mozilla/5.0 (v8-clusterfuzz-helper/1.0)"}, + ) + with opener.open(req, timeout=30) as resp: + return resp.read() + + +def download_testcase(url: str, cookies_file: Path | None) -> bytes: + """Downloads from ClusterFuzz with fallback between urllib and curl.""" + # Prefer curl when cookies are present for maximum compatibility with Netscape cookie files + if cookies_file: + return download_curl(url, cookies_file) + try: + return download_urllib(url, cookies_file) + except Exception: + return download_curl(url, cookies_file) + + +def parse_metadata_response(raw_output: bytes) -> dict: + """Parses JSON response from testcase-detail/refresh endpoint.""" + if is_html_login_response(raw_output): + raise PermissionError("Authentication required for metadata fetch") + + text = raw_output.decode("utf-8", errors="replace").strip() + text = re.sub(r"^\)]}'\s*", "", text) + + try: + data = json.loads(text) + except json.JSONDecodeError as e: + raise RuntimeError(f"Failed to parse JSON response: {e}") + + if isinstance(data, dict): + if data.get("status") == 401 or data.get("type") == "UnauthorizedError": + raise PermissionError( + "Authentication required: ClusterFuzz returned UnauthorizedError (401)" + ) + if "error" in data: + raise RuntimeError(f"ClusterFuzz error: {data['error']}") + if "testcase" not in data and "crash_type" not in data: + raise RuntimeError(f"Invalid metadata response from ClusterFuzz: {data}") + + return data + + +def fetch_testcase_metadata(testcase_id: str, + cookies_file: Path | None) -> dict: + """Queries the testcase-detail/refresh JSON endpoint to fetch report metadata.""" + cmd = [ + "curl", + "-s", + "-H", + "Content-Type: application/json", + "-d", + json.dumps({"testcaseId": testcase_id}), + ] + if cookies_file: + cmd.extend(["-b", str(cookies_file)]) + cmd.append(REFRESH_URL) + + res = subprocess.run(cmd, capture_output=True, check=False) + if res.returncode != 0: + err_msg = res.stderr.decode("utf-8", errors="replace").strip() + raise RuntimeError( + f"Metadata fetch failed (exit {res.returncode}): {err_msg}") + + return parse_metadata_response(res.stdout) + + +def map_job_to_local_out(job_type: str) -> str: + """Maps a ClusterFuzz bot job type to the standard local V8 build output directory.""" + j = job_type.lower() + if "asan" in j: + return "out/x64.asan/d8" + if "msan" in j: + return "out/x64.msan/d8" + if "tsan" in j: + return "out/x64.tsan/d8" + if "ubsan" in j: + return "out/x64.ubsan/d8" + if "optdebug" in j: + return "out/x64.optdebug/d8" + if "dbg" in j or "debug" in j: + return "out/x64.debug/d8" + return "out/x64.release/d8" + + +def display_metadata(data: dict) -> None: + """Displays extracted ClusterFuzz metadata in a clean, human-readable format.""" + tc = data.get("testcase", {}) + crash_type = data.get("crash_type") or tc.get("crash_type") or "N/A" + crash_state = data.get("crash_state") or tc.get("crash_state") or "N/A" + job_type = tc.get("job_type") or "N/A" + min_args = tc.get("minimized_arguments") or "N/A" + win_arg = tc.get("window_argument") or "" + crash_rev = data.get("crash_revision") or tc.get("crash_revision") or "N/A" + regression = data.get("regression") or tc.get("regression") or "N/A" + issue_url = data.get("issue_url") or "N/A" + + full_flags = min_args + if win_arg and win_arg not in full_flags: + full_flags = f"{full_flags} {win_arg}".strip() + + clean_regression = regression + if "<" in regression and ">" in regression: + clean_regression = re.sub(r"", "\n" + " " * 20, regression) + clean_regression = re.sub(r"<[^>]+>", "", clean_regression).strip() + + local_d8 = map_job_to_local_out(job_type) + + print("=" * 70) + print(f"ClusterFuzz Metadata (ID: {tc.get('id', 'N/A')})") + print("=" * 70) + print(f"Crash Type: {crash_type}") + print( + f"Crash State: {crash_state.splitlines()[0] if crash_state else 'N/A'}" + ) + print(f"Job Type: {job_type}") + print(f"Crash Revision: {crash_rev}") + print(f"Regression Range: {clean_regression}") + print(f"Issue Tracker: {issue_url}") + print("-" * 70) + print(f"Minimized d8 Flags: {min_args}") + if win_arg: + print(f"Window / Seed Flag: {win_arg}") + print("-" * 70) + print("Recommended Local Invocation:") + print(f"timeout -v 15 {local_d8} {full_flags} ") + print("=" * 70) + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Download ClusterFuzz test cases and metadata from clusterfuzz.com." + ) + parser.add_argument( + "target", + help="Testcase ID (e.g. 5197100195282944) or ClusterFuzz URL", + ) + parser.add_argument( + "-o", + "--output", + help="Output file path for reproducer script (defaults to a temporary file testcase_.)", + ) + parser.add_argument( + "-c", + "--cookies-file", + help="Path to Netscape cookies.txt file for clusterfuzz.com", + ) + parser.add_argument( + "--info", + "--metadata", + action="store_true", + dest="show_info", + help="Fetch and display testcase report metadata (flags, job type, regression)", + ) + parser.add_argument( + "--save-metadata", + help="Optional path to save full metadata JSON response", + ) + + args = parser.parse_args() + + try: + testcase_id, url = parse_target(args.target) + cookies_file = find_cookies_file(args.cookies_file) + except (ValueError, FileNotFoundError) as e: + print(f"Error: {e}", file=sys.stderr) + return 1 + + # Handle --info / --metadata mode + if args.show_info or args.save_metadata: + try: + metadata = fetch_testcase_metadata(testcase_id, cookies_file) + if args.show_info: + display_metadata(metadata) + if args.save_metadata: + meta_path = Path(args.save_metadata).resolve() + meta_path.parent.mkdir(parents=True, exist_ok=True) + meta_path.write_text(json.dumps(metadata, indent=2)) + print(f"Saved full metadata report to: {meta_path}") + return 0 + except PermissionError: + print_missing_cookies_help() + return 1 + except Exception as e: + print(f"Error fetching metadata: {e}", file=sys.stderr) + if not cookies_file: + print_missing_cookies_help() + return 1 + + # Download mode + output_path = args.output + print(f"Fetching testcase from: {url}") + if cookies_file: + print(f"Using cookies file: {cookies_file}") + else: + print("Notice: No cookies.txt found. Attempting unauthenticated download.") + + try: + content = download_testcase(url, cookies_file) + + if not content: + print("Warning: Received empty test case content.", file=sys.stderr) + + if is_html_login_response(content): + print_missing_cookies_help() + return 1 + + is_wasm = content.startswith(b"\x00asm") + if not output_path: + if not re.fullmatch(r"\d+", testcase_id): + raise ValueError(f"Invalid non-numeric testcase ID: {testcase_id!r}") + temp_dir = Path(tempfile.gettempdir()).resolve() + ext = ".wasm" if is_wasm else ".js" + out_file = (temp_dir / f"testcase_{testcase_id}{ext}").resolve() + if out_file.parent != temp_dir: + raise ValueError( + f"Refusing to write outside temp directory: {out_file}") + else: + out_file = Path(output_path).resolve() + if is_wasm and out_file.suffix.lower() == ".js": + print( + "Notice: Test case content is a WebAssembly binary module (starts with \\x00asm), " + f"but output path has .js extension: {out_file}", + file=sys.stderr) + + out_file.parent.mkdir(parents=True, exist_ok=True) + out_file.write_bytes(content) + + print(f"Successfully saved test case ({len(content)} bytes) to: {out_file}") + if is_wasm: + print("Notice: Downloaded test case is a WebAssembly binary module.") + print("To convert it into readable JavaScript (WasmModuleBuilder), run:") + print(f" out/x64.release/wami --mjsunit {out_file} > repro.js") + return 0 + + except Exception as e: + print(f"Error fetching testcase: {e}", file=sys.stderr) + if not cookies_file: + print_missing_cookies_help() + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase_test.py b/deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase_test.py new file mode 100644 index 000000000000..3f530b825426 --- /dev/null +++ b/deps/v8/agents/skills/clusterfuzz/scripts/fetch_testcase_test.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from pathlib import Path +import sys +import tempfile +import unittest +from unittest import mock + +sys.path.insert(0, str(Path(__file__).resolve().parent)) + +from fetch_testcase import ( + find_cookies_file, + is_html_login_response, + main, + map_job_to_local_out, + parse_metadata_response, + parse_target, +) + + +class FetchTestcaseTest(unittest.TestCase): + + def test_parse_target_numeric_id(self): + tc_id, url = parse_target("5197100195282944") + self.assertEqual(tc_id, "5197100195282944") + self.assertEqual( + url, "https://clusterfuzz.com/download?testcase_id=5197100195282944") + + def test_parse_target_public_url(self): + url_in = "https://clusterfuzz.com/testcase-detail/5197100195282944" + tc_id, url = parse_target(url_in) + self.assertEqual(tc_id, "5197100195282944") + self.assertEqual( + url, "https://clusterfuzz.com/download?testcase_id=5197100195282944") + + def test_parse_target_public_query_param(self): + url_in = "https://clusterfuzz.com/download?testcase_id=12345" + tc_id, url = parse_target(url_in) + self.assertEqual(tc_id, "12345") + self.assertEqual(url, url_in) + + def test_parse_target_rejects_path_traversal(self): + for bad_target in ( + "https://clusterfuzz.com/download?testcase_id=../../../etc/passwd", + "https://clusterfuzz.com/download?testcase_id=%2e%2e%2f%2e%2e%2fpwned", + "https://clusterfuzz.com/testcase?key=../pwned", + "../../../etc/passwd", + "https://clusterfuzz.com/testcase-detail/not_numeric", + ): + with self.subTest(target=bad_target): + with self.assertRaises(ValueError): + parse_target(bad_target) + + def test_parse_target_rejects_untrusted_host(self): + for bad_url in ( + "https://attacker.example/download?testcase_id=12345", + "http://127.0.0.1:8080/download?testcase_id=../../../tmp/pwned", + "file:///etc/passwd?testcase_id=12345", + ): + with self.subTest(url=bad_url): + with self.assertRaises(ValueError): + parse_target(bad_url) + + def test_main_rejects_path_traversal_url(self): + with tempfile.TemporaryDirectory() as d: + target_file = Path(d) / "pwned.js" + target_file_no_ext = str(target_file)[:-3] + traversal = "../" * 10 + target_file_no_ext.lstrip("/") + url = f"https://clusterfuzz.com/download?testcase_id={traversal}" + with mock.patch.object(sys, "argv", ["fetch_testcase.py", url]): + rc = main() + self.assertEqual(rc, 1) + self.assertFalse(target_file.exists()) + + def test_map_job_to_local_out(self): + self.assertEqual(map_job_to_local_out("linux_asan_d8"), "out/x64.asan/d8") + self.assertEqual(map_job_to_local_out("linux_msan_d8"), "out/x64.msan/d8") + self.assertEqual(map_job_to_local_out("linux_tsan_d8"), "out/x64.tsan/d8") + self.assertEqual( + map_job_to_local_out("linux_ubsan_vptr_d8"), "out/x64.ubsan/d8") + self.assertEqual(map_job_to_local_out("linux_d8_dbg"), "out/x64.debug/d8") + self.assertEqual( + map_job_to_local_out("linux_d8_optdebug"), "out/x64.optdebug/d8") + self.assertEqual(map_job_to_local_out("linux_d8_rel"), "out/x64.release/d8") + self.assertEqual(map_job_to_local_out("v8_foozzie"), "out/x64.release/d8") + + def test_is_html_login_response(self): + self.assertTrue( + is_html_login_response(b"Login")) + self.assertTrue(is_html_login_response(b"")) + self.assertTrue( + is_html_login_response(b"window.location = '/session-login'")) + self.assertFalse(is_html_login_response(b"print('hello world');")) + self.assertFalse(is_html_login_response(b"\x00asm\x01\x00\x00\x00")) + + def test_parse_metadata_response_valid(self): + raw = b')]}\'\n{"testcase": {"id": 12345, "job_type": "linux_asan_d8"}}' + data = parse_metadata_response(raw) + self.assertEqual(data["testcase"]["id"], 12345) + self.assertEqual(data["testcase"]["job_type"], "linux_asan_d8") + + def test_parse_metadata_response_unauthorized(self): + raw = b'{"status": 401, "type": "UnauthorizedError"}' + with self.assertRaises(PermissionError): + parse_metadata_response(raw) + + def test_find_cookies_file_specified(self): + with tempfile.NamedTemporaryFile() as tmp: + found = find_cookies_file(tmp.name) + self.assertEqual(found, Path(tmp.name).resolve()) + + with self.assertRaises(FileNotFoundError): + find_cookies_file("/non/existent/path/cookies.txt") + + def test_find_cookies_file_default_only_uses_config_dir(self): + with tempfile.TemporaryDirectory() as fake_home: + with mock.patch.object(Path, "home", return_value=Path(fake_home)): + self.assertIsNone(find_cookies_file()) + config_cookies = Path( + fake_home) / ".config" / "clusterfuzz" / "cookies.txt" + config_cookies.parent.mkdir(parents=True) + config_cookies.write_text("# Netscape HTTP Cookie File\n") + self.assertEqual(find_cookies_file(), config_cookies) + + def test_regression_html_stripping(self): + import re + regression = 'V8: 81576:81577
Common: 12345' + clean = regression + if "<" in regression and ">" in regression: + clean = re.sub(r"", "\n" + " " * 20, regression) + clean = re.sub(r"<[^>]+>", "", clean).strip() + self.assertEqual(clean, + "V8: 81576:81577\n Common: 12345") + + +if __name__ == "__main__": + unittest.main() diff --git a/deps/v8/agents/skills/v8-features/SKILL.md b/deps/v8/agents/skills/v8-features/SKILL.md new file mode 100644 index 000000000000..2fcbb844fe0b --- /dev/null +++ b/deps/v8/agents/skills/v8-features/SKILL.md @@ -0,0 +1,88 @@ +--- +name: v8-features +description: Manages the V8 feature shipping lifecycle, including checking feature status and consistency in src/flags/feature-flags.h, advancing features through shipping steps (experimental, pre-stage, stage, ship), checking Finch studies, fieldtrial configs, Origin Trials, and Chromestatus entries, generating Fuzzilli and Linux64 CI test coverage reports for features, bug IDs, CLs, or commits, and preparing V8 launch review documents. Use when the user asks to check, pre-stage, stage, ship, or audit V8 feature flags, check Finch/Origin Trial/Chromestatus status, calculate code coverage for a feature, bug, or commit, or create a V8 launch review. Don't use it for general compiler bug fixing, implementing new language features from scratch, or triaging standalone ClusterFuzz crash dumps. +--- + +This skill manages V8 features through the V8 shipping lifecycle: checking +feature status, trials, and checklist consistency, advancing features between +shipping steps, generating Fuzzilli and CI test coverage reports, and preparing +launch review documents. + +## Quick Reference: `src/flags/feature-flags.h` + +All tracked V8 features are defined in `src/flags/feature-flags.h` (which +supersedes legacy pre-`2628639aef5` macros in `src/wasm/wasm-feature-flags.h` +and `JAVASCRIPT_STAGED_FEATURES_BASE` still mentioned in `docs/`): + +- **Shipping step macros:** + - `FOREACH_EXPERIMENTAL_FEATURE_FLAG`: Experimental / in-progress (disabled by + default) + - `FOREACH_PRE_STAGED_FEATURE_FLAG`: Pre-staged for fuzzing / VRP (disabled by + default) + - `FOREACH_STAGED_FEATURE_FLAG`: Staged behind `--future` (disabled by + default) + - `FOREACH_SHIPPED_FEATURE_FLAG`: Shipped (enabled by default) +- **Feature type -> CLI flag mapping:** + - `WASM_FEATURE(foo_bar, ...)` -> `--wasm-foo-bar` (`v8_flags.wasm_foo_bar`) + - `JS_FEATURE(foo_bar, ...)` -> `--foo-bar` (`v8_flags.foo_bar`) + - `INTERNAL_FEATURE(foo_bar, ...)` -> `--foo-bar` (`v8_flags.foo_bar`) + +## Parallelization Guidelines + +Whenever a task involves multiple features or multiple independent checks on a +single feature, **maximize parallelism across subagents and within-turn tool +calls**: + +- **Batch tool calls in every turn:** Issue all independent `read_file`, + `run_command`, and search calls concurrently in a single turn. +- **Keep parallel subagents read-only:** When sharing a working directory, run + all repository-mutating steps (editing `src/flags/feature-flags.h`, building + with `tools/dev/gm.py`, etc.) in the main agent after parallel checks finish. +- **Pass shared context upfront:** Provide each subagent with the feature name, + CLI flag, macro name, and discovered bug/commit IDs so subagents do not repeat + discovery work. +- **For coverage reports and launch reviews:** Pre-compute shared coverage + artifacts once into `/tmp/v8-cov-/` before fanning out subagents (see + [references/coverage-report.md](references/coverage-report.md) and + [references/launch-reviews.md](references/launch-reviews.md)). + +## Tasks & Reference Routing + +### 1. Determine Status, Check Consistency, or Advance a Step + +Load [references/shipping-steps.md](references/shipping-steps.md) when checking +feature status, auditing consistency against `docs/feature-launch-process.md` +and `docs/wasm-shipping-checklist.md`, or advancing a feature to the next step: + +- **Status & Trials:** Check the macro and comment block in + `src/flags/feature-flags.h`, run + `python3 agents/skills/v8-features/scripts/read_finch_config.py` (which scans + both google3 Finch `.gcl` studies and Chromium's + `fieldtrial_testing_config.json`), check Origin Trial registration + (`src/wasm/wasm-features.cc` or `src/execution/isolate.cc`), and query + Chromestatus via `fetch_chromestatus.py`. +- **Consistency & Step Advancement:** Verify comment blocks in + `src/flags/feature-flags.h`, `InitializeGlobal_` in + `src/init/bootstrapper.cc` (for JS features), `proposal_flags` in + `test/{wasm-spec-tests,wasm-js}/testcfg.py` (for Pre-staged+ Wasm features), + and `check_use_counter` in `src/wasm/module-compiler.cc` (enforced by + `static_assert` for Staged/Shipped Wasm features). Build and verify changes + with `tools/dev/gm.py quiet x64.optdebug `. + +### 2. Generate a Coverage Report + +Load [references/coverage-report.md](references/coverage-report.md) to generate +Fuzzilli (`--source fuzzilli`), V8 Linux64 CI test (`--source tests`), or +combined (`--source both`) line coverage reports for any feature flag, bug ID, +Change-Id, or commit hash via `scripts/generate_coverage_report.py`, and to +triage `**[Needs Triage]**` blocks in parallel. + +### 3. Prepare a Launch Review + +Load [references/launch-reviews.md](references/launch-reviews.md) and copy the +report skeleton from +[assets/launch-review-template.md](assets/launch-review-template.md). Do not ask +the user for missing information; run Phase 1 pre-fetch, spawn the 8 parallel +research subagents in Phase 2, include checkbox options (`- [ ] ... (tba)`) and +an **Action items** checklist in Phase 3, and save the report to +`/tmp/launch-review-.md` (unless the user specifies another path). diff --git a/deps/v8/agents/skills/v8-features/assets/launch-review-template.md b/deps/v8/agents/skills/v8-features/assets/launch-review-template.md new file mode 100644 index 000000000000..d4d608f70dc7 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/assets/launch-review-template.md @@ -0,0 +1,170 @@ +# V8 Launch Review: `` + +## Executive summary + +- **Status:** `` +- **Fuzzilli coverage:** `/` (`%` raw; + `%` effective) +- **Test coverage (`V8 Linux64 - coverage`):** `/` + (`%` raw; `%` effective) +- **Key findings & risks:** + `<1-3 sentence summary of actionable items, coverage gaps, and technical risks>` + +## Overview + +### Feature scope + +`` + +### Owner(s) + +- **V8 owner(s):** `` + +### Feature flag + +- **CLI flag:** `--` (`v8_flags.`) +- **Macro definition:** + `(, "")` in + `src/flags/feature-flags.h` + +### Tracking bug + +- **Primary tracking bug:** + ` (or b/)>` +- **Related sub-bugs:** `` + +### Shipping step + +- **Current step:** `` + (`FOREACH__FEATURE_FLAG` in `src/flags/feature-flags.h`) +- **Finch / FieldTrial status:** + `` +- **Origin Trial status:** + `` + +| Step | Commit / CL | Date | V8 Version | Author | +| :----------------------- | :------------------------ | :------------- | :--------- | :--------- | +| Inception (Experimental) | `` | `` | `` | `` | +| Pre-staged | `` | `` | `` | `` | +| Staged | `` | `` | `` | `` | +| Shipped | `` | `` | `` | `` | + +### Chrome launch process + +- **Chromestatus entry:** ` or None>` +- **Launch bug:** ` or None>` + +### Spec or proposal overview + +- **Specification / Proposal:** + `` + +### Design docs + +- [ ] Link design doc(s): `tba` +- [ ] None + +## Fuzzing and testing + +### Fuzzilli coverage + +- **Coverage revision:** `Chromium ` / `V8 ` +- **Overall:** `/` executable lines covered (`%` + raw; `%` excluding benign) + +| File | Total Modified | Executable | Covered | Uncovered (Raw) | Benign | Genuine Gaps | Raw Cov % | Eff. Cov % | +| :------------------ | -------------: | ---------: | ------: | --------------: | -----: | -----------: | --------: | ---------: | +| `` | `` | `` | `` | `` | `` | `` | `%` | `%` | + +**Triage of uncovered blocks:** + +- `` + +### Other fuzzer coverage + +- **Wasm fuzzers (`random-module-generation.cc`, `test/fuzzer/wasm/`):** + `` +- **Binaryen fuzzer:** `` +- **FuzzTest / Centipede (`test/unittests/**/*fuzztest*.cc`):** `` +- **ClusterFuzz (`js_fuzzer`, `foozzie`):** `` + +### Tests + +1. **V8 unit and integration tests:** + `` +2. **Spec tests:** + `` +3. **Web Platform Tests (WPTs):** `` +4. **Test coverage (`V8 Linux64 - coverage`):** + - **Build:** `[Build #](/index.html)` (`V8 `) + - **Overall:** `/` executable lines covered + (`%` raw; `%` excluding benign) + +| File | Total Modified | Executable | Covered | Uncovered (Raw) | Benign | Genuine Gaps | Raw Cov % | Eff. Cov % | +| :------------------ | -------------: | ---------: | ------: | --------------: | -----: | -----------: | --------: | ---------: | +| `` | `` | `` | `` | `` | `` | `` | `%` | `%` | + +**Triage of uncovered test blocks:** + +- `` + +### Stress testing + +`<2-3 sentence summary of relevant stress flags, variants, and fuzzers>` + +### Other detection frameworks + +`<2-3 sentence summary of ASAN, MSAN, TSAN, UBSan, and GCMole coverage/annotations>` + +### Bug history + +| Bug ID | Short Description | Priority | Status | Found By | +| :--------- | :---------------- | :-------- | :---------------------- | :---------------------------------------------- | +| `` | `` | `` | `` | `` | + +## Rollout plan + +### Timeline and trials + +- [ ] Ship directly without a trial (Target milestone: `tba`) +- [ ] Origin Trial (Target milestones: `tba`) +- [ ] Finch / field trial (Target milestones: `tba`) +- [ ] Developer trial only (Target milestones: `tba`) + +### Risks + +- [ ] None known +- [ ] Performance regressions: `tba` +- [ ] Memory overhead: `tba` +- [ ] Web / backwards compatibility: `tba` +- [ ] Security / attack surface: `tba` + +### Metrics + +- **UseCounter (`include/v8-isolate.h`, `src/wasm/module-compiler.cc`):** + `` +- **Histograms (`src/logging/counters-definitions.h`) & UKM + (`include/v8-metrics.h`):** `` + +### Partner outreach + +- [ ] None / No specific partner outreach required +- [ ] Partner outreach planned or completed (Partners and status: `tba`) + +## Other Chromium components + +- [ ] None / No other Chromium components affected +- [ ] DevTools / debugging support (Status / checklist review: `tba`) +- [ ] Blink bindings or other Chromium components (Components and review status: + `tba`) + +## Action items + +- [ ] **Report completion:** Confirm or fill in `tba` options above (Design + docs, Timeline and trials, Risks, Partner outreach, Other Chromium + components). +- [ ] **Engineering & process prerequisites:** + `` +- [ ] **Launch review:** Share this document with the Bug Detection team and + relevant TLs, and schedule a launch review meeting or request an offline + review. diff --git a/deps/v8/agents/skills/v8-features/references/coverage-report.md b/deps/v8/agents/skills/v8-features/references/coverage-report.md new file mode 100644 index 000000000000..88f7e31a238d --- /dev/null +++ b/deps/v8/agents/skills/v8-features/references/coverage-report.md @@ -0,0 +1,93 @@ +# V8 Coverage Report Generation & Triage + +Generate line coverage reports for V8 features, tracking bugs, Change-Ids, or +commit hashes using Fuzzilli x64 coverage and/or the +[V8 Linux64 - coverage](https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux64%20-%20coverage) +CI builder. + +## 1. Automated Report Generation (Recommended) + +Run `generate_coverage_report.py` from the V8 repository root: + +```bash +python3 agents/skills/v8-features/scripts/generate_coverage_report.py \ + [ ...] \ + [--feature ] \ + [--grep ""] \ + [--source {fuzzilli,tests,ci,both}] \ + [--output-dir /tmp/v8-cov-] +``` + +### Key Options + +- ``: Git commit hash, Gerrit Change-Id (`Iabc123...`), Buganizer / + `crbug.com` ID or URL (`123456`, `b/123456`, `v8:12345`, + `https://crbug.com/...`), or V8 feature flag name (`wide_arithmetic`). +- `--feature` / `-f`: Traces the feature flag across + `src/flags/feature-flags.h`, `src/wasm/wasm-feature-flags.h`, and + `src/flags/flag-definitions.h` (`git log -G`), automatically resolving all + implementation commits and `Bug:` / `Fixed:` IDs in parallel. +- `--grep` / `-g`: Includes commits whose commit message matches the regex + (e.g., `"\\[wasm-wide-arith\\]"`). +- `--source` / `-s`: + - `fuzzilli` (default): Chromium Fuzzilli x64 coverage dashboard. + - `tests` (or `ci`): Latest `V8 Linux64 - coverage` CI build (`llvm-cov` HTML + report in GCS). + - `both`: Fetches and analyzes both Fuzzilli and CI test coverage + **concurrently in parallel**, reusing the resolved commit hashes. +- `--output-dir` / `-o`: Writes `commits.txt`, `bugs.txt`, + `fuzzilli-coverage.md`, and/or `tests-coverage.md` to the target directory + (always use `/tmp/...` or the agent scratch directory, never the git working + tree). +- `--no-snippets`: Omits C++ source snippets underneath uncovered blocks while + retaining per-file `Auto-Benign` vs. `Needs Triage` counts and block tags. +- `--checkout`: Checks out the coverage revision in the working tree. *(Omit + `--checkout` when running parallel subagents; the script inspects git history + and blames against the target revision without mutating `HEAD`.)* + +## 2. Triaging Uncovered Code Blocks & Parallelization + +- **Linux x64 scope:** Both coverage sources run only on Linux x64. Non-x64 + backend files (`arm`, `arm64`, `ia32`, `loong64`, `mips64`, `ppc64`, + `riscv32`, `riscv64`, `s390x`) and `test/`/`tools/` files are skipped + automatically before `git blame`. +- **Focus strictly on `**[Needs Triage]**` blocks:** + `generate_coverage_report.py` tracks `#if`/`#else`/`#endif` nesting and + automatically classifies common benign blocks (`UNREACHABLE()`, `DCHECK`, + `PrintOptions`, `inputs_rep()`, 32-bit/non-x64 preprocessor branches, and Wasm + libFuzzer generators under `fuzzilli`). +- **Use embedded `[cov: N]` vs. `[UNCOV]` context lines:** Each uncovered block + includes `±2` surrounding lines with execution counts so you can see + immediately whether the enclosing function ran and which branch was missed + (e.g., an instruction-selector immediate/memory branch, or a test running only + in Liftoff without `--no-liftoff`). Once the immediate condition for a + coverage gap is identified, record it and move on without tracing unrelated + compiler passes. +- **Shard across top-level subagents:** If more than 3–4 files have + `Needs Triage` lines in the per-file table, the main agent should partition + those files by subsystem (e.g., `src/wasm/`, `src/compiler/turboshaft/`, + `src/compiler/backend/`) across parallel subagents. +- **Report only the final post-triage numbers:** `Auto-Benign` vs. + `Needs Triage` in the script output is purely an internal pre-filter. Once the + `**[Needs Triage]**` blocks have been classified into benign vs. genuine gaps, + present a single combined **Benign** count, **Genuine Gaps** count, and final + post-triage **Effective Coverage %** (`Covered / (Executable - Benign)`). Do + not distinguish "auto-benign" from "manual benign" or report pre-triage + intermediate effective percentages in the final user-facing report. + +## 3. Debugging Individual Pipeline Steps + +If you need to debug a specific phase of `generate_coverage_report.py` without +mutating `HEAD`: + +1. **Map Chromium hash to V8 revision (Fuzzilli):** + `python3 agents/skills/v8-features/scripts/get_v8_revision.py ` +2. **Fetch the target V8 revision into the object store (no checkout):** + `git fetch --no-write-fetch-head origin ` +3. **Resolve commit hashes or blame affected blocks at ``:** + `python3 agents/skills/v8-features/scripts/find_affected_blocks.py --revision [--hashes-only] [--feature ] [ ...]` +4. **Extract line counts from a downloaded coverage HTML file in `/tmp`:** + `python3 agents/skills/v8-features/scripts/extract_coverage.py /tmp/.html - [...]` + *(Supports both Chromium Fuzzilli HTML and V8 CI `llvm-cov` HTML; outputs + `line: count` where `0` = uncovered, `>0` = covered, `None` = + non-executable).* diff --git a/deps/v8/agents/skills/v8-features/references/launch-reviews.md b/deps/v8/agents/skills/v8-features/references/launch-reviews.md new file mode 100644 index 000000000000..cd8984a7a7c6 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/references/launch-reviews.md @@ -0,0 +1,234 @@ +# V8 Launch Review Workflow + +Prepare a comprehensive V8 launch review document by running a 3-phase +multi-agent workflow and populating +[assets/launch-review-template.md](../assets/launch-review-template.md). + +## Workflow Guidelines + +1. **Do not ask the user:** Complete all local codebase, script, and git history + research and generate the full report directly without prompting the user for + missing information. +2. **Parallelize with subagents:** After a quick Phase 1 discovery & coverage + pre-fetch on the main agent, spawn parallel read-only subagents in a single + turn to research all sections concurrently. +3. **Include options in the report:** When information cannot be inferred + automatically (e.g., design docs, rollout timelines, trial plans, known + risks, partner outreach, or cross-component reviews), keep the checkbox + options (`- [ ] ... (tba)`) from + [assets/launch-review-template.md](../assets/launch-review-template.md) so + the user can select or fill them in. +4. **Create a list of action items:** Conclude with an **Action items** + checklist (`- [ ] ...`) covering both `tba` user decisions and any + engineering or process gaps discovered during the review. +5. **Use relative repository paths:** Always format V8 file references relative + to the V8 repository root (never absolute filesystem paths or leading + slashes). +6. **Save outside the git working tree by default:** Write the synthesized + document to `/tmp/launch-review-.md` (or the agent's + artifact/scratch directory), unless the user explicitly specifies an output + path. Never leave untracked files in the V8 repository root. + +______________________________________________________________________ + +## Phase 1: Initial Discovery & Coverage Pre-Fetch (Main Agent) + +Before spawning subagents, establish shared context and pre-compute both +coverage reports in a single pass so no subagent repeats git history, +`git blame`, or coverage downloads: + +1. **Locate the feature flag & macro (`src/flags/feature-flags.h`):** + - Identify the macro + (`FOREACH_{EXPERIMENTAL,PRE_STAGED,STAGED,SHIPPED}_FEATURE_FLAG`), feature + type (`WASM_FEATURE`, `JS_FEATURE`, `INTERNAL_FEATURE`), CLI flag name, and + preceding comment block (or check `src/flags/flag-definitions.h` if not yet + in `src/flags/feature-flags.h`; see + [references/shipping-steps.md](shipping-steps.md)). + - If only a bug ID is provided, run + `git log -E -i --grep="^(Bug|Fixed):.*" --oneline -n 20` first to + identify the feature flag name and commit subject prefix (e.g., + `[wasm-foo]`). +2. **Inspect flag transition history & pre-fetch both coverage reports in + parallel:** + - Run `git log -G` across current and historical flag files (prefer `-G` over + `-S` or `git blame`, which misses same-file macro moves and breaks on bulk + refactor `2628639aef5`): + ```bash + git log -G"\b\b" -p -- src/flags/feature-flags.h src/wasm/wasm-feature-flags.h src/flags/flag-definitions.h + ``` + - Concurrently run `generate_coverage_report.py` with `--source both` and + `--output-dir /tmp/v8-cov-` (see + [references/coverage-report.md](coverage-report.md)): + ```bash + python3 agents/skills/v8-features/scripts/generate_coverage_report.py \ + --source both \ + --output-dir /tmp/v8-cov- \ + --feature [ ...] [--grep ""] + ``` + This writes + `/tmp/v8-cov-/{commits.txt,bugs.txt,fuzzilli-coverage.md,tests-coverage.md}`. + Reuse `commits.txt` and `bugs.txt` across all downstream steps (do **not** + re-run `find_affected_blocks.py --hashes-only` or + `generate_coverage_report.py`). + +______________________________________________________________________ + +## Phase 2: Parallel Subagent Research + +Spawn **8 focused, load-balanced subagents concurrently in a single turn** (plus +extra sharded subagents if `fuzzilli-coverage.md` or `tests-coverage.md` has +`>4` files with `Needs Triage` lines—read-only subagents like `research-google` +cannot spawn child subagents themselves, so the **main agent** must shard +`Needs Triage` files across top-level subagents based on Phase 1's per-file +table). + +Pass every subagent: + +- Feature name, CLI flag, macro name, and comment block from + `src/flags/feature-flags.h` +- Discovered bug IDs (`bugs.txt`), commit hashes (`commits.txt`), and + `/tmp/v8-cov-/` path +- Instructions to keep the workspace strictly read-only and to **batch all + independent `read_file`, `run_command`, and search calls within each turn**. + +| Subagent | Template Sections Owned | Key Checks & Commands | +| :-------------------------------------- | :---------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **1 — Overview, Lifecycle & Checklist** | `Feature scope`, `Owner(s)`, `Feature flag`, `Tracking bug`, `Shipping step` (table), `Design docs` | Resolve exact V8 versions for transition commits via `git show :include/v8-version.h` in one batched command; audit consistency against [references/shipping-steps.md](shipping-steps.md); search CLs/bugs/`v8-status-updates` for design docs. | +| **2 — Chromestatus, Spec & Trials** | `Shipping step` (trials), `Chrome launch process`, `Spec or proposal overview`, `Timeline and trials` | Run `read_finch_config.py --filter ` and `fetch_chromestatus.py ` concurrently; check Origin Trial registration (`src/wasm/wasm-features.cc` or `src/execution/isolate.cc`); check [TC39](https://github.com/tc39/proposals) / [Wasm](https://github.com/WebAssembly/proposals) proposals and [Launch](https://launch.corp.google.com/). | +| **3 — Fuzzilli Coverage Triage** | `Fuzzilli coverage` | Read `/tmp/v8-cov-/fuzzilli-coverage.md` (do **not** re-run coverage scripts). Inspect only `**[Needs Triage]**` blocks using embedded `[cov: N]` / `[UNCOV]` context counts and stop once the immediate condition is identified (see Section 2 below). | +| **4 — CI Test Coverage Triage** | `Tests` (#4 `Test coverage`) | Read `/tmp/v8-cov-/tests-coverage.md` (do **not** re-run coverage scripts). Cross-reference `**[Needs Triage]**` blocks against test flags and default CI variants and stop once the immediate condition is identified (see Section 2 below). | +| **5 — Unit, Spec & WPT Tests** | `Tests` (#1–#3) | Inspect test files from `commits.txt` and `.status` files; run available tests via `tools/dev/gm.py quiet x64.optdebug ` (or `tools/run-tests.py --outdir=out/x64.optdebug `); compare spec tests against upstream (see Section 2 below). | +| **6 — Fuzzers, Stress & Sanitizers** | `Other fuzzer coverage`, `Stress testing`, `Other detection frameworks` | Check Wasm/JS fuzzers, Binaryen, FuzzTest, ClusterFuzz/Foozzie, stress flags/variants, sanitizers, and GCMole (see Section 3 below). | +| **7 — Bug History & Technical Risks** | `Bug history`, `Risks` | Batch `git show` on bug-fix/regression commits in `commits.txt` and `test/mjsunit/regress/`; synthesize technical risks and open `TODO`s (see Section 4 below). | +| **8 — Metrics, Partners & Components** | `Metrics`, `Partner outreach`, `Other Chromium components` | Check `UseCounterFeature`, histograms, UKM, partner notes, and DevTools/inspector support (see Section 5 below). | + +______________________________________________________________________ + +## Detailed Research Instructions by Section + +### 1. Chromestatus, Spec Proposals & Trials (Subagent 2) + +- **Chromestatus (`fetch_chromestatus.py`):** Queries + `https://chromestatus.com/api/v0/features` and strips the `)]}'\n` XSSI prefix + automatically. If `search_web` returns an opaque grounding redirect URL + (`https://vertexaisearch.cloud.google.com/grounding-api-redirect/...`, which + often targets `https://*-dot-cr-status.appspot.com/feature/`), pass the + redirect URL directly to `fetch_chromestatus.py` (or use `--resolve-only`). + Internal/optimization features without web-observable changes may have no + Chromestatus entry and instead use a + [Launch bug](https://launch.corp.google.com/). +- **Finch & Origin Trials:** Follow Section 2 of + [references/shipping-steps.md](shipping-steps.md) to distinguish active + google3 Finch GCL studies from Chromium `fieldtrial_testing_config.json` + entries and Origin Trials. + +### 2. Fuzzilli Coverage, CI Test Coverage & Test Suites (Subagents 3, 4, 5) + +- **Coverage Triage (Subagents 3 & 4):** + - Read `/tmp/v8-cov-/fuzzilli-coverage.md` and + `/tmp/v8-cov-/tests-coverage.md` generated in Phase 1. + - Distinguish benign uncovered code (`UNREACHABLE()`/`DCHECK`, non-x64/32-bit + fallbacks, disassemblers, tracing/diagnostics, or libFuzzer-only generators + in Fuzzilli) from genuine coverage gaps. + - **Stop once the immediate condition is identified (explicitly include this + in the subagent prompt):** Use the embedded `[cov: N]` vs. `[UNCOV]` + surrounding context lines to determine whether the enclosing function ran + and which immediate branch, overload, or test flag (such as `--no-liftoff`) + was missed. Once the immediate condition is identified, record it and move + on—do **not** trace transitive root causes across unrelated compiler passes, + IR effect definitions (`OpEffects`), or generic instruction-selector helpers + (such as `CanCover`). + - Note on Wasm tier coverage in `V8 Linux64 - coverage`: While CI tests run + both with `--liftoff-only` and `--no-liftoff`, the coverage report only + records the default configuration behavior. A lack of coverage in one tier + alone is therefore likely not actionable (and should be counted as benign + when covered by the other tier on standard CI bots). + - **Report only the final post-triage numbers:** `Auto-Benign` vs. + `Needs Triage` in `fuzzilli-coverage.md` and `tests-coverage.md` is purely + an internal pre-filter to reduce subagent work. In the synthesized launch + review (Executive summary, Overall bullets, Per-file tables, and Triage + summaries), merge script-triaged and subagent-triaged benign lines into a + single **Benign** column (`Benign` + `Genuine Gaps` = `Uncovered (Raw)`), + and report a single final **Eff. Cov %** + (`Covered / (Executable - Benign)`). Do **not** expose intermediate + pre-triage percentages or distinguish "auto-benign" from "manual benign" in + the final report. +- **Unit, Spec & WPT Tests (Subagent 5):** + - **V8 unit/integration tests:** Check + `test/{mjsunit,unittests,cctest,inspector,intl}/` and corresponding + `.status` files (`mjsunit.status`, `unittests.status`, `cctest.status`) to + verify tests are not skipped or failing. If an `out/` build exists (or when + verifying locally), run tests via + `tools/dev/gm.py quiet x64.optdebug ` (or + `tools/run-tests.py --outdir=out/x64.optdebug `). + - **Spec tests:** + - *JavaScript:* Check `test/test262/` (`local-tests/`, staging tests) and + `test/test262/test262.status`. + - *WebAssembly:* Check `test/wasm-spec-tests/tests/proposals//` + (`wasm-spec-tests.status`) and `test/wasm-js/tests/proposals//` + (`wasm-js.status`), plus `tools/wasm/update-wasm-spec-tests.sh` and + `proposal_flags` in `test/{wasm-spec-tests,wasm-js}/testcfg.py`. Compare + V8's spec tests against the upstream proposal's `test/core` and + `test/js-api` directories. *(Never run + `tools/wasm/update-wasm-spec-tests.sh` during a review—it wipes local + directories, requires OCaml, and uploads to GCS; add an action item + instead.)* + - **Web Platform Tests (WPTs):** Check `test/wasm-js/tests/wpt/` in V8 and + `third_party/blink/web_tests/external/wpt/` (or upstream + [WPT](https://github.com/web-platform-tests/wpt)) if Blink/Web APIs are + involved. + +### 3. Other Fuzzers, Stress Testing & Detection Frameworks (Subagent 6) + +- **Other fuzzer coverage:** Inspect `commits.txt` CLs and codebase support in: + - *Wasm fuzzers:* `src/wasm/fuzzing/random-module-generation.cc`, + `test/common/wasm/fuzzer-common.cc`, `test/fuzzer/wasm/`. + - *Binaryen fuzzer:* + [WebAssembly/binaryen](https://github.com/WebAssembly/binaryen) (for Wasm + features). + - *FuzzTest / Centipede:* `test/unittests/**/*fuzztest*.cc`. + - *ClusterFuzz JS & differential fuzzing:* `tools/clusterfuzz/js_fuzzer/` and + `tools/clusterfuzz/foozzie/` (`v8_fuzz_flags.json`, `v8_fuzz_config.py`). +- **Stress testing:** Check `src/flags/flag-definitions.h`, + `tools/testrunner/local/variants.py`, + `tools/clusterfuzz/foozzie/v8_fuzz_flags.json`, and + `tools/clusterfuzz/trials/clusterfuzz_trials_config.json` for stress modes + (`--stress-*`, `--deopt-every-n-times`, `--liftoff-only`). +- **Other detection frameworks:** Check `commits.txt` and `.status` files for + ASAN, MSAN, TSAN, UBSan (`src/base/sanitizer/`), and GCMole (`tools/gcmole/`, + `DisallowGarbageCollection`). + +### 4. Bug History & Technical Risks (Subagent 7) + +- **Bug history:** Inspect all bug-fix/regression commits in `commits.txt` and + `test/mjsunit/regress/` in a single batched `git show` command; populate the + Bug ID, short description, priority, status, and fuzzer/test source. +- **Risks:** Synthesize technical risks from implementation complexity, past + regression patterns (e.g., register allocation, multi-output IR nodes, + architecture ports, stack slots), and open `TODO`s; keep the fallback checkbox + categories from + [assets/launch-review-template.md](../assets/launch-review-template.md) if no + specific risks are found. + +### 5. Metrics, Partner Outreach & Other Chromium Components (Subagent 8) + +- **Metrics:** Check `v8::Isolate::UseCounterFeature` in `include/v8-isolate.h`, + `kUseCounters` / `check_use_counter` in `src/wasm/module-compiler.cc`, + histograms in `src/logging/counters-definitions.h`, and UKM in + `include/v8-metrics.h`. +- **Partner outreach:** Check tracking bug and Chromestatus comments for partner + mentions; include the template checkboxes if unknown. +- **Other Chromium components:** Check `src/inspector/`, `test/inspector/`, + `src/wasm/wasm-disassembler.cc`, and debugging checklists in + `docs/feature-launch-process.md` and `docs/wasm-shipping-checklist.md`. + +______________________________________________________________________ + +## Phase 3: Synthesis & Action Items (Main Agent) + +Copy the skeleton from +[assets/launch-review-template.md](../assets/launch-review-template.md), fill in +all sections from Subagents 1–8, consolidate every open `tba` choice and +discovered engineering/process gap into the final **Action items** checklist, +and save the completed report to `/tmp/launch-review-.md` (or the +user-specified path). diff --git a/deps/v8/agents/skills/v8-features/references/shipping-steps.md b/deps/v8/agents/skills/v8-features/references/shipping-steps.md new file mode 100644 index 000000000000..c44dc141c3e6 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/references/shipping-steps.md @@ -0,0 +1,124 @@ +# V8 Feature Status, Consistency & Step Advancement + +This reference covers determining a V8 feature's shipping status, checking +consistency against V8's shipping checklists, and advancing a feature to the +next step. + +## 1. Feature Flag Macros & CLI Flag Mapping (`src/flags/feature-flags.h`) + +All V8 features following the launch process are tracked in +`src/flags/feature-flags.h` under one of four shipping-step macros: + +| Shipping Step | Macro in `src/flags/feature-flags.h` | Default State | +| :--------------------------- | :----------------------------------- | :---------------------------------------------------- | +| **Experimental (Inception)** | `FOREACH_EXPERIMENTAL_FEATURE_FLAG` | Disabled by default (in-progress) | +| **Pre-staged** | `FOREACH_PRE_STAGED_FEATURE_FLAG` | Disabled by default; ready for fuzzing / VRP | +| **Staged** | `FOREACH_STAGED_FEATURE_FLAG` | Disabled by default; enabled via `--future` / staging | +| **Shipped** | `FOREACH_SHIPPED_FEATURE_FLAG` | Enabled by default | + +Each entry uses one of three type macros (optionally wrapped in a build-flag +conditional such as `IF_INTL_ENABLED`, `IF_REVEC_ENABLED`, or +`IF_SPARKPLUG_PLUS_ENABLED`): + +- `WASM_FEATURE(foo_bar, "description")` -> CLI flag `--wasm-foo-bar` + (`v8_flags.wasm_foo_bar`) +- `JS_FEATURE(foo_bar, "description")` -> CLI flag `--foo-bar` + (`v8_flags.foo_bar`) +- `INTERNAL_FEATURE(foo_bar, "description")` -> CLI flag `--foo-bar` + (`v8_flags.foo_bar`) + +> [!IMPORTANT] `docs/feature-launch-process.md` and +> `docs/wasm-shipping-checklist.md` still reference legacy pre-`2628639aef5` +> files and macros (`src/wasm/wasm-feature-flags.h`, 3-parameter +> `FOREACH_WASM_*`, `JAVASCRIPT_STAGED_FEATURES_BASE`). +> `src/flags/feature-flags.h` supersedes those legacy macro definitions. + +## 2. Determining Feature Status, Trials & External Metadata + +1. **Macro & Comment Block (`src/flags/feature-flags.h`):** Check which + `FOREACH_*_FEATURE_FLAG` macro contains the feature and inspect the preceding + comment block for: + - Feature description / internal name + - Proposal link (`https://github.com/tc39/...` or + `https://github.com/WebAssembly/...`) + - V8-side owner(s) + - Staging/shipping milestone or trial annotations (e.g., + `/* Staged in 15.7 */`) +2. **Finch Studies & FieldTrial Testing Config:** Run: + ```bash + python3 agents/skills/v8-features/scripts/read_finch_config.py [--filter ] + ``` + This inspects both: + - **Google3 Finch GCL studies** + (`/google/src/files/head/depot/google3/googledata/googleclient/chrome/finch/gcl_studies/`, + when accessible on a Googler machine) for active Finch rollouts. + - **Chromium FieldTrial testing config** + (`testing/variations/fieldtrial_testing_config.json`), noting enabled vs. + disabled (kill-switch) states. *(A fieldtrial config is required for Finch, + but presence in `fieldtrial_testing_config.json` alone does not mean an + active Finch study is running.)* +3. **Origin Trial Status:** + - **WebAssembly features:** Check `WasmEnabledFeatures::FromContext` in + `src/wasm/wasm-features.cc`. + - **JavaScript features:** Check `Isolate::InstallConditionalFeatures` in + `src/execution/isolate.cc`. +4. **Chromestatus Entry:** If not linked in `src/flags/feature-flags.h`, query + Chromestatus (or resolve `search_web` redirect URLs) via: + ```bash + python3 agents/skills/v8-features/scripts/fetch_chromestatus.py + ``` +5. **Transition History across Flag Files:** Always use `git log -G` (diff regex + search) rather than `git log -S` or `git blame` (which breaks on bulk + refactor `2628639aef5` and multiline macro `\` continuations): + ```bash + git log -G"\b\b" -p -- src/flags/feature-flags.h src/wasm/wasm-feature-flags.h src/flags/flag-definitions.h + ``` + +## 3. Step Consistency Checklist + +Cross-reference the feature's current (or target) step against these codebase +requirements: + +- **All tracked features (`src/flags/feature-flags.h`):** + - Preceded by a comment block with description, proposal URL (if applicable), + V8 owner, and trial/milestone notes. +- **JavaScript features (`JS_FEATURE`):** + - `Genesis::InitializeGlobal_()` is defined in `src/init/bootstrapper.cc` + (required whenever a `JS_FEATURE` is in `src/flags/feature-flags.h`). +- **WebAssembly features (`WASM_FEATURE`) in Pre-staged or later:** + - Proposal repository is listed in `repos` in + `tools/wasm/update-wasm-spec-tests.sh`. + - Feature flag is registered in `proposal_flags` in both + `test/wasm-spec-tests/testcfg.py` and `test/wasm-js/testcfg.py`. +- **WebAssembly features (`WASM_FEATURE`) in Staged or Shipped:** + - Mapped to a `v8::Isolate::UseCounterFeature` in `kUseCounters` inside + `src/wasm/module-compiler.cc` (or explicitly listed in + `kIntentionallyNoUseCounter`), enforced at compile time by + `static_assert(check_use_counter(WasmDetectedFeature::feat))`. +- **Flags outside `src/flags/feature-flags.h`:** + - Helper or non-V8-tracked flags may live directly in + `src/flags/flag-definitions.h`. If asked to advance one, ask the user + whether it should be migrated to `src/flags/feature-flags.h`. Query the user + before overriding any intentional deviation from the documented process. + +## 4. Procedure to Advance a Feature Step + +1. **Verify Consistency:** Audit the feature against Section 3 above (using + parallel read-only subagents if advancing multiple features). +2. **Apply Code Changes:** + - Move the feature entry to the target `FOREACH__FEATURE_FLAG` macro in + `src/flags/feature-flags.h` and update its milestone/status comment. + - Update `src/init/bootstrapper.cc`, `src/wasm/module-compiler.cc`, + `test/wasm-spec-tests/testcfg.py`, and/or `test/wasm-js/testcfg.py` if + required by the target step. +3. **Build & Run Verification Tests:** + - Compile and run the relevant test suites using `gm.py` (which builds and + runs tests in `out/`): + ```bash + tools/dev/gm.py quiet x64.optdebug + ``` + (e.g., `wasm-spec-tests wasm-js` for WebAssembly features, or + `mjsunit test262` for JavaScript features; or run + `tools/run-tests.py --outdir=out/x64.optdebug ` once built). + - Ensure the build succeeds (including `check_use_counter` static assertions) + and all tests pass. diff --git a/deps/v8/agents/skills/v8-features/scripts/extract_coverage.py b/deps/v8/agents/skills/v8-features/scripts/extract_coverage.py new file mode 100755 index 000000000000..4712c0b9a480 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/scripts/extract_coverage.py @@ -0,0 +1,79 @@ +#! /usr/bin/python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import sys +import re +import argparse + + +def get_coverage(file, lines): + content = file.read() + + results = [] + coverage_map = {} + + # Format 1: Chromium/Fuzzilli coverage dashboard () + row_pattern = re.compile(r'(.*?)', re.DOTALL) + for match in row_pattern.finditer(content): + line_num = int(match.group(1)) + row_content = match.group(2) + if 'class="uncovered-count"' in row_content: + coverage_map[line_num] = "0" + elif 'class="covered-count"' in row_content: + count_match = re.search(r'class="covered-count" title="(\d+)"', + row_content) + coverage_map[line_num] = count_match.group( + 1) if count_match else "covered" + else: + coverage_map[line_num] = None + + # Format 2: V8 CI llvm-cov HTML report () + if not coverage_map: + llvm_row_pattern = re.compile( + r"]*>\s*]*>" + r"\s*
\s*\d+\s*
\s*
\s*\s*" + r"]*>" + r"\s*(?:
([^<]*)
)?\s*") + for match in llvm_row_pattern.finditer(content): + line_num = int(match.group(1)) + line_class = match.group(2) + count_text = (match.group(3) or "").strip() + if line_class == "covered-line": + coverage_map[line_num] = count_text if count_text else "covered" + elif line_class == "uncovered-line": + if coverage_map.get(line_num) in (None, "0"): + coverage_map[line_num] = "0" + else: + if line_num not in coverage_map: + coverage_map[line_num] = None + + # Resolve requested lines from the map + for line_range in lines: + if '-' in line_range: + start, end = map(int, line_range.split('-')) + line_nums = range(start, end + 1) + else: + line_nums = [int(line_range)] + + for line_num in line_nums: + results.append((line_num, coverage_map.get(line_num, "Not found"))) + return results + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Extract line coverage from a Fuzzilli coverage report') + parser.add_argument( + 'file', + type=argparse.FileType('r'), + help='the downloaded HTML file containing the coverage report') + parser.add_argument( + 'line', + nargs='+', + help='either a line number or a block of lines denoted as -') + args = parser.parse_args() + coverage = get_coverage(args.file, args.line) + for line_num, status in coverage: + print(f"{line_num}: {status}") diff --git a/deps/v8/agents/skills/v8-features/scripts/fetch_chromestatus.py b/deps/v8/agents/skills/v8-features/scripts/fetch_chromestatus.py new file mode 100755 index 000000000000..3b2aca783a98 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/scripts/fetch_chromestatus.py @@ -0,0 +1,258 @@ +#! /usr/bin/python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import concurrent.futures +import json +import re +import sys +import requests + +CHROMESTATUS_API_BASE = 'https://chromestatus.com/api/v0/features' +CHROMESTATUS_FEATURE_URL = 'https://chromestatus.com/feature/{}' +FEATURE_ID_PATTERN = re.compile( + r'(?:chromestatus\.com|cr-status\.appspot\.com)/(?:api/v0/)?features?/(\d+)' +) +XSSI_PREFIX = ")]}'\n" + + +def parse_xssi_json(text: str): + if text.startswith(")]}'"): + text = text.split('\n', 1)[1] if '\n' in text else '' + return json.loads(text) + + +def resolve_redirect(url: str, timeout: int = 10) -> str: + try: + resp = requests.head( + url, + allow_redirects=True, + timeout=timeout, + headers={'User-Agent': 'Mozilla/5.0'}, + ) + if resp.url and (resp.ok or resp.url != url): + return resp.url + except requests.RequestException: + pass + try: + resp = requests.get( + url, + allow_redirects=True, + stream=True, + timeout=timeout, + headers={'User-Agent': 'Mozilla/5.0'}, + ) + resp.close() + return resp.url + except requests.RequestException as e: + print(f'ERROR - Could not resolve URL {url}: {e}', file=sys.stderr) + return url + + +def fetch_feature_by_id(feature_id: str, timeout: int = 10) -> dict: + url = f'{CHROMESTATUS_API_BASE}/{feature_id}' + resp = requests.get( + url, timeout=timeout, headers={'User-Agent': 'Mozilla/5.0'}) + if resp.status_code != 200: + print( + f'ERROR - Could not fetch Chromestatus feature {feature_id} ' + f'(HTTP {resp.status_code})', + file=sys.stderr, + ) + return {} + return parse_xssi_json(resp.text) + + +def search_features(query: str, timeout: int = 10) -> list[dict]: + # Normalize flag-like names (e.g. --wasm-wide-arithmetic or wide_arithmetic). + normalized = query.lstrip('-') + for prefix in ('experimental-wasm-', 'wasm-', 'experimental_wasm_', 'wasm_'): + if normalized.lower().startswith(prefix): + normalized = normalized[len(prefix):] + break + normalized = normalized.replace('_', ' ').replace('-', ' ').strip() + + queries_to_try = [query] + if normalized and normalized.lower() != query.lower(): + queries_to_try.insert(0, normalized) + + seen_ids = set() + results = [] + for q in queries_to_try: + resp = requests.get( + CHROMESTATUS_API_BASE, + params={'q': q}, + timeout=timeout, + headers={'User-Agent': 'Mozilla/5.0'}, + ) + if resp.status_code != 200: + continue + data = parse_xssi_json(resp.text) + items = [] + for item in data.get('features', []): + fid = item.get('id') + if fid and fid not in seen_ids: + seen_ids.add(fid) + items.append((fid, item)) + if items: + with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: + fut_map = { + fid: executor.submit( + fetch_feature_by_id, str(fid), + timeout=timeout) for fid, _ in items + } + for fid, item in items: + detail = fut_map[fid].result() + results.append(detail or item) + if results: + break + return results + + +def format_feature_markdown(f: dict) -> str: + fid = f.get('id') + name = f.get('name', 'Unknown') + url = CHROMESTATUS_FEATURE_URL.format(fid) if fid else 'Unknown' + chrome = f.get('browsers', {}).get('chrome', {}) + status = chrome.get('status', {}).get('text') or f.get('intent_stage') + standards = f.get('standards', {}) + maturity = standards.get('maturity', {}).get('text') or standards.get( + 'maturity', {}).get('short_text') + spec = f.get('spec_link') or standards.get('spec') + bug = f.get('bug_url') or chrome.get('bug') + launch_bug = f.get('launch_bug_url') + owners = f.get('owner_emails') or chrome.get('owners') or [] + editors = f.get('editor_emails') or f.get('editors') or [] + cc_list = f.get('cc_emails') or f.get('cc_recipients') or [] + + lines = [ + f'### {name} (ID: `{fid}`)', + f'- **URL:** {url}', + f'- **Summary:** {f.get("summary")}', + f'- **Blink Component(s):** {", ".join(f.get("blink_components", []))}', + f'- **Status:** {status} (Intent stage: {f.get("intent_stage")})', + f'- **Feature Type:** {f.get("feature_type")}', + f'- **Rollout Plan:** {f.get("rollout_plan_displayname")}', + f'- **Flag / Finch Name:** flag=`{f.get("flag_name")}`, ' + f'finch=`{f.get("finch_name")}`', + f'- **Owners:** {", ".join(owners) if owners else "None"}', + f'- **Editors:** {", ".join(editors) if editors else "None"}', + f'- **CC:** {", ".join(cc_list) if cc_list else "None"}', + f'- **Tracking Bug:** {bug}', + f'- **Launch Bug:** {launch_bug}', + f'- **Spec Link:** {spec}', + f'- **Standards Maturity:** {maturity}', + f'- **Explainer Links:** {f.get("explainer_links") or []}', + f'- **Doc Links:** {f.get("doc_links") or []}', + f'- **TAG Review:** {f.get("tag_review")} ' + f'({f.get("tag_review_status")})', + f'- **Security / Privacy Review:** ' + f'security={f.get("security_review_status")}, ' + f'privacy={f.get("privacy_review_status")}', + f'- **Created / Updated:** ' + f'created={f.get("created", {}).get("when")} by ' + f'{f.get("created", {}).get("by")}, ' + f'updated={f.get("updated", {}).get("when")} by ' + f'{f.get("updated", {}).get("by")}', + ] + + # Extract milestone / intent thread details from stages if populated. + stage_summaries = [] + for st in f.get('stages', []): + milestones = { + k: st.get(k) for k in ( + 'desktop_first', + 'android_first', + 'ios_first', + 'webview_first', + 'rollout_milestone', + ) if st.get(k) is not None + } + intent_url = st.get('intent_thread_url') + finch_url = st.get('finch_url') + if milestones or intent_url or finch_url: + stage_summaries.append(f'stage_type={st.get("stage_type")} ' + f'milestones={milestones} ' + f'intent_thread={intent_url} ' + f'finch_url={finch_url}') + if stage_summaries: + lines.append('- **Populated Stages:** ' + '; '.join(stage_summaries)) + + return '\n'.join(lines) + + +def main(): + parser = argparse.ArgumentParser( + description=( + 'Search Chromestatus features, fetch feature metadata by ID/URL, ' + 'or resolve search_web redirect URLs.')) + parser.add_argument( + 'inputs', + nargs='+', + help=('Feature search query, V8 flag name (e.g. wide_arithmetic), ' + 'Chromestatus feature ID/URL, or HTTP redirect URL.'), + ) + parser.add_argument( + '--json', + action='store_true', + help='Output raw JSON instead of formatted markdown summary.', + ) + parser.add_argument( + '--resolve-only', + action='store_true', + help='Only resolve redirect URLs and print their target URLs.', + ) + args = parser.parse_args() + + features = [] + for item in args.inputs: + item = item.strip() + if item.startswith(('http://', 'https://')): + match = FEATURE_ID_PATTERN.search(item) if not args.resolve_only else None + if match: + feat = fetch_feature_by_id(match.group(1)) + if feat: + features.append(feat) + continue + resolved = resolve_redirect(item) + match = FEATURE_ID_PATTERN.search(resolved) + if args.resolve_only or not match: + if match: + canonical = CHROMESTATUS_FEATURE_URL.format(match.group(1)) + print(f'{item} -> {canonical} (raw: {resolved})') + else: + print(f'{item} -> {resolved}') + if args.resolve_only: + continue + if match: + feat = fetch_feature_by_id(match.group(1)) + if feat: + features.append(feat) + elif item.isdigit(): + feat = fetch_feature_by_id(item) + if feat: + features.append(feat) + else: + features.extend(search_features(item)) + + if args.resolve_only: + return + + if args.json: + print(json.dumps(features, indent=2)) + return + + if not features: + print('No matching Chromestatus entries found.') + return + + for idx, feat in enumerate(features): + if idx > 0: + print('\n---\n') + print(format_feature_markdown(feat)) + + +if __name__ == '__main__': + main() diff --git a/deps/v8/agents/skills/v8-features/scripts/find_affected_blocks.py b/deps/v8/agents/skills/v8-features/scripts/find_affected_blocks.py new file mode 100755 index 000000000000..19c7644ef738 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/scripts/find_affected_blocks.py @@ -0,0 +1,535 @@ +#! /usr/bin/python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re +import subprocess +import os +import sys +import argparse +import concurrent.futures + + +def run_command(*args: str) -> str: + git_process = subprocess.run(args, capture_output=True, text=True) + if git_process.returncode == 0: + return git_process.stdout.rstrip('\n') + else: + raise Exception( + 'Failed to run command {0} (return code {1})'.format( + ' '.join(git_process.args), git_process.returncode), + git_process.stderr) + + +class FileBlocks: + + class Block: + file: str + begin: int + end: int + + def __init__(self, file: str, begin: int, end: int): + self.file = file + self.begin = begin + self.end = end + + def __str__(self) -> str: + if self.begin == self.end: + return '{0}:{1}'.format(self.file, self.begin) + else: + return '{0}:{1}-{2}'.format(self.file, self.begin, self.end) + + porcelain_pattern = re.compile('([0-9a-f]{40}) ([0-9]+) ([0-9]+)( .*)?') + + commit_hashes: set[str] + revision: str + affected_files: set[str] + affected_blocks: list[Block] + + def __init__(self, + commit_hashes: set[str], + revision: str = None, + skip_file_predicate=None): + self.commit_hashes = commit_hashes + self.revision = revision + self.skip_file_predicate = skip_file_predicate + self.affected_files = set() + self.skipped_files = set() + self.min_commit_timestamp = None + self.find_affected_files() + self.affected_blocks = [] + self.find_affected_blocks() + + def files(self) -> set[str]: + return self.affected_files + + def skipped(self) -> set[str]: + return self.skipped_files + + def blocks(self) -> list[Block]: + return self.affected_blocks + + def find_affected_files(self) -> None: + if self.revision: + try: + run_command('git', 'rev-parse', '--verify', + f'{self.revision}^{{commit}}') + except Exception as e: + raise Exception( + f'Revision {self.revision} is not present in the local git object ' + f'store (run `git fetch origin {self.revision}` first)') from e + + if not self.commit_hashes: + return + + existing_at_rev = None + if self.revision: + tree_output = run_command('git', 'ls-tree', '-r', '--name-only', + self.revision) + existing_at_rev = set(tree_output.split('\n')) if tree_output else set() + + commit_list = sorted(self.commit_hashes) + try: + ts_output = run_command('git', 'show', '-s', '--format=%ct', *commit_list) + timestamps = [ + int(line.strip()) + for line in ts_output.split('\n') + if line.strip().isdigit() + ] + if timestamps: + # Subtract 1 day buffer to ensure git blame --since includes the oldest commit. + self.min_commit_timestamp = min(timestamps) - 86400 + except Exception: + self.min_commit_timestamp = None + + batch_size = 100 + candidate_files = set() + for i in range(0, len(commit_list), batch_size): + batch = commit_list[i:i + batch_size] + output = run_command('git', 'show', '--name-only', '--pretty=format:', + *batch) + if output: + for line in output.split('\n'): + line = line.strip() + if line: + candidate_files.add(line) + + for line in candidate_files: + exists = False + if self.revision: + if existing_at_rev is not None: + exists = line in existing_at_rev + else: + try: + run_command('git', 'cat-file', '-e', f'{self.revision}:{line}') + exists = True + except Exception: + pass + elif os.path.isfile(line): + exists = True + + if exists: + if self.skip_file_predicate and self.skip_file_predicate(line): + self.skipped_files.add(line) + else: + self.affected_files.add(line) + + def find_affected_blocks(self) -> None: + + def process_file(file: str) -> list[FileBlocks.Block]: + line_numbers = set() + cmd = ['git', 'blame', '--porcelain'] + if self.min_commit_timestamp is not None: + cmd.append(f'--since=@{self.min_commit_timestamp}') + if self.revision: + cmd.append(self.revision) + cmd.extend(['--', file]) + try: + output = run_command(*cmd) + except Exception: + return [] + if output is not None and len(output) > 0: + for line in output.split('\n'): + if line[:40] in self.commit_hashes: + match = FileBlocks.porcelain_pattern.fullmatch(line) + if match is not None: + line_numbers.add(int(match.group(3))) + blocks = [] + block = None + for line_number in sorted(line_numbers): + if block is None: + block = FileBlocks.Block(file, line_number, line_number) + elif block.end + 1 == line_number: + block.end = line_number + else: + blocks.append(block) + block = FileBlocks.Block(file, line_number, line_number) + if block is not None: + blocks.append(block) + return blocks + + with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: + results = executor.map(process_file, sorted(self.affected_files)) + for blocks in results: + self.affected_blocks.extend(blocks) + + +class HashResolver: + commit_hashes: set[str] + resolved_bugs: set[str] + + # Bulk feature-flags refactoring commit/bug to ignore when tracing flag history. + BULK_FLAG_REFACTOR_PREFIXES = ('2628639aef5',) + BULK_FLAG_REFACTOR_BUGS = {'448864127'} + FLAG_FILES = [ + 'src/flags/feature-flags.h', + 'src/wasm/wasm-feature-flags.h', + 'src/flags/flag-definitions.h', + ] + + def __init__(self): + self.commit_hashes = set() + self.resolved_bugs = set() + + commit_message_bug_pattern = re.compile( + '(?:https?://crbug\\.com/(?:v8/|chromium/)?|((v8|chromium|crbug|b)(:|/)))?([0-9]+)' + ) + commit_hash_pattern = re.compile('[0-9a-fA-F]{7,40}') + pure_digits_pattern = re.compile('^[0-9]+$') + change_id_pattern = re.compile('I([0-9a-fA-F]{40})') + bug_ref_patterns = [ + re.compile('b/([0-9]+)'), + re.compile('b:([0-9]+)'), + re.compile('v8:([0-9]+)'), + re.compile('chromium:([0-9]+)'), + re.compile( + '(?:https?://)?crbug\\.com/(?:v8/|chromium/)?([0-9]+)([\\?#].*)?'), + re.compile('https://b.corp.google.com/([0-9]+)([\\?#].*)?'), + re.compile('https://b.corp.google.com/issues/([0-9]+)([\\?#].*)?'), + re.compile('https://g-issues.chromium.org/issues/([0-9]+)([\\?#].*)?'), + re.compile('https://issues.chromium.org/issues/([0-9]+)([\\?#].*)?'), + re.compile('https://issues.chromium.org/([0-9]+)([\\?#].*)?'), + re.compile('https://buganizer.corp.google.com/([0-9]+)([\\?#].*)?'), + re.compile('^([0-9]+)$') + ] + + def hashes(self) -> set[str]: + return self.commit_hashes + + def bugs(self) -> set[str]: + return self.resolved_bugs + + @staticmethod + def extract_bug_numbers_from_text(text: str) -> set[str]: + bug_numbers = set() + if not text: + return bug_numbers + for line in text.split('\n'): + line = line.strip(' ') + lower = line.lower() + if lower.startswith('bug:'): + line = line[4:] + elif lower.startswith('fixed:'): + line = line[6:] + else: + continue + for bug_id in re.split(r'[,\s]+', line.strip()): + if not bug_id: + continue + bug_match = HashResolver.commit_message_bug_pattern.fullmatch( + bug_id.strip()) + if bug_match is not None: + bug_numbers.add(bug_match.group(4)) + return bug_numbers + + @staticmethod + def extract_bug_numbers(commit_hash: str) -> set[str]: + output = run_command('git', 'log', '-n', '1', '--pretty=format:%B', + commit_hash, '--') + return HashResolver.extract_bug_numbers_from_text(output) + + def _resolve_bug_ids(self, bug_ids: set[str]) -> set[str]: + """Resolves multiple bug IDs in a single git log --all traversal.""" + pending = sorted(b for b in bug_ids if b and b not in self.resolved_bugs) + if not pending: + return set(bug_ids) & self.resolved_bugs + + grep_args = [ + f'--grep=^(Bug|Fixed):[[:space:]]*.*(chromium:|v8:|b:|b/)?{b}\\b' + for b in pending + ] + output = run_command('git', 'log', '--all', '-E', '-i', *grep_args, + '--pretty=format:%H%x00%B%x1e') + found_bugs = set() + if output: + pending_set = set(pending) + for record in output.split('\x1e'): + record = record.strip() + if not record or '\x00' not in record: + continue + commit_hash, body = record.split('\x00', 1) + commit_hash = commit_hash.strip() + matched = HashResolver.extract_bug_numbers_from_text(body) & pending_set + if matched: + self.commit_hashes.add(commit_hash) + found_bugs.update(matched) + self.resolved_bugs.update(found_bugs) + return (set(bug_ids) & self.resolved_bugs) | found_bugs + + def _resolve_bug_id(self, bug_id: str) -> bool: + return bug_id in self._resolve_bug_ids({bug_id}) + + @staticmethod + def _match_commit_hash(reference: str) -> str | None: + match = HashResolver.commit_hash_pattern.fullmatch(reference) + if match is None: + return None + commit_hash = match.group(0).lower() + try: + output = run_command('git', 'log', '--pretty=format:%H', '-n', '1', + commit_hash, '--') + if output: + return output + except Exception: + pass + return None + + def _try_resolve_commit_hash(self, reference: str) -> bool: + resolved = self._match_commit_hash(reference) + if resolved: + self.commit_hashes.add(resolved) + return True + return False + + def _scan_feature_flag_history( + self, feature_name: str) -> tuple[set[str], set[str]]: + """Scans flag files for a feature name, returning (commit_hashes, bug_ids).""" + norm = feature_name.strip().lstrip('-').replace('-', '_') + if norm.startswith('experimental_'): + norm = norm[len('experimental_'):] + if norm.startswith('wasm_'): + norm = norm[len('wasm_'):] + + flag_files = list(HashResolver.FLAG_FILES) + if os.path.isfile('src/flags/feature-flags.h'): + try: + with open('src/flags/feature-flags.h', 'r', errors='replace') as f: + ff_content = f.read() + if re.search(rf'\bWASM_FEATURE\s*\(\s*{re.escape(norm)}\b', ff_content): + flag_files = [ + 'src/flags/feature-flags.h', + 'src/wasm/wasm-feature-flags.h', + ] + elif re.search( + rf'\b(JS_FEATURE|INTERNAL_FEATURE)\s*\(\s*{re.escape(norm)}\b', + ff_content): + flag_files = [ + 'src/flags/feature-flags.h', + 'src/flags/flag-definitions.h', + ] + except Exception: + pass + + output = run_command('git', 'log', f'-G\\b{re.escape(norm)}\\b', + '--pretty=format:%H%x00%B%x1e', '--', *flag_files) + commits = set() + bugs = set() + if output: + for record in output.split('\x1e'): + record = record.strip() + if not record or '\x00' not in record: + continue + commit_hash, body = record.split('\x00', 1) + commit_hash = commit_hash.strip() + if commit_hash.startswith(HashResolver.BULK_FLAG_REFACTOR_PREFIXES): + continue + commits.add(commit_hash) + for bug_id in HashResolver.extract_bug_numbers_from_text(body): + if bug_id not in HashResolver.BULK_FLAG_REFACTOR_BUGS: + bugs.add(bug_id) + if not commits: + raise Exception(f'Could not find flag history for feature {feature_name}') + return commits, bugs + + def add_feature(self, feature_name: str) -> None: + """Resolves a feature flag name across flag history and related bugs.""" + commits, bugs = self._scan_feature_flag_history(feature_name) + self.commit_hashes.update(commits) + if bugs: + self._resolve_bug_ids(bugs) + + @staticmethod + def _scan_grep(pattern: str) -> set[str]: + """Finds commits whose commit message matches the given regex pattern.""" + output = run_command('git', 'log', '--all', f'--grep={pattern}', + '--pretty=format:%H') + commits = {line.strip() for line in output.split('\n') if line.strip() + } if output else set() + if not commits: + raise Exception(f'Could not find commits matching --grep={pattern}') + return commits + + def add_grep(self, pattern: str) -> None: + """Resolves commits whose commit message matches the given regex pattern.""" + self.commit_hashes.update(self._scan_grep(pattern)) + + def _resolve_non_bug_reference(self, + reference: str) -> tuple[set[str], set[str]]: + """Resolves a non-bug reference (Change-Id, commit hash, or feature name) without mutating self.""" + # 1. Check for Gerrit Change-Ids first (I<40 hex chars>) + match = HashResolver.change_id_pattern.fullmatch(reference) + if match is not None: + output = run_command( + 'git', 'log', '--all', + '--grep=Change-Id: I{0}'.format(match.group(1).lower()), + '--pretty=format:%H', '-n', '1') + if output is not None and len(output) > 0: + return {output}, set() + raise Exception('Could not find hash for change id I{0}'.format( + match.group(1).lower())) + + # 2. Check for hexadecimal commit hashes + resolved_hash = self._match_commit_hash(reference) + if resolved_hash: + return {resolved_hash}, set() + + # 3. Fallback: try resolving as a feature flag name + try: + return self._scan_feature_flag_history(reference) + except Exception: + pass + + raise Exception('Could not understand {0}'.format(reference)) + + def resolve_all(self, references=None, features=None, greps=None) -> None: + """Resolves all references, features, and grep patterns concurrently.""" + references = list(references or []) + features = list(features or []) + greps = list(greps or []) + + explicit_bugs = set() + other_refs = [] + for ref in references: + if HashResolver.pure_digits_pattern.fullmatch(ref): + explicit_bugs.add(ref) + continue + matched_bug = None + for pattern in HashResolver.bug_ref_patterns: + m = pattern.fullmatch(ref) + if m is not None: + matched_bug = m.group(1) + break + if matched_bug is not None: + explicit_bugs.add(matched_bug) + else: + other_refs.append(ref) + + with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: + feat_futures = { + executor.submit(self._scan_feature_flag_history, f): f + for f in features + } + grep_futures = {executor.submit(self._scan_grep, g): g for g in greps} + ref_futures = { + executor.submit(self._resolve_non_bug_reference, r): r + for r in other_refs + } + + discovered_bugs = set(explicit_bugs) + for fut in concurrent.futures.as_completed(feat_futures): + commits, bugs = fut.result() + self.commit_hashes.update(commits) + discovered_bugs.update(bugs) + for fut in concurrent.futures.as_completed(grep_futures): + self.commit_hashes.update(fut.result()) + for fut in concurrent.futures.as_completed(ref_futures): + commits, bugs = fut.result() + self.commit_hashes.update(commits) + discovered_bugs.update(bugs) + + if discovered_bugs: + found_bugs = self._resolve_bug_ids(discovered_bugs) + for b in explicit_bugs - found_bugs: + if HashResolver.pure_digits_pattern.fullmatch( + b) and self._try_resolve_commit_hash(b): + continue + raise Exception(f'Could not find hashes for bug {b}') + + def add_reference(self, reference: str) -> None: + # 1. If reference is purely digits, prioritize bug ID lookup before + # treating it as a potential hex commit hash prefix. + if HashResolver.pure_digits_pattern.fullmatch(reference): + if self._resolve_bug_id(reference): + return + if self._try_resolve_commit_hash(reference): + return + raise Exception(f'Could not find hashes for bug {reference}') + + # 2. Check explicit bug URL / prefixed bug patterns (b/..., v8:..., etc.) + for pattern in HashResolver.bug_ref_patterns: + match = pattern.fullmatch(reference) + if match is not None: + bug_id = match.group(1) + if self._resolve_bug_id(bug_id): + return + raise Exception(f'Could not find hashes for bug {bug_id}') + + # 3. Resolve Change-Id, commit hash, or feature flag name + commits, bugs = self._resolve_non_bug_reference(reference) + self.commit_hashes.update(commits) + if bugs: + self._resolve_bug_ids(bugs) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Find all code blocks affected by a list of references to CLs' + ) + parser.add_argument( + 'reference', + nargs='*', + help='Git commit hash, Gerrit Change-Id, bug ID/URL, or feature flag name' + ) + parser.add_argument( + '--feature', + '-f', + action='append', + default=[], + help='Feature flag name (e.g. wide_arithmetic) to trace across flag files and bugs' + ) + parser.add_argument( + '--grep', + '-g', + action='append', + default=[], + help='Commit message regex/substring (e.g. "\\[wasm-wide-arith\\]") to include' + ) + parser.add_argument( + '--hashes-only', + '-H', + action="store_true", + help='only output Git commit hashes of all the referenced CLs') + parser.add_argument( + '--revision', + '-r', + help='Git revision to blame against (defaults to HEAD)') + args = parser.parse_args() + if not args.reference and not args.feature and not args.grep: + parser.error('At least one reference, --feature, or --grep is required.') + try: + hash_resolver = HashResolver() + hash_resolver.resolve_all(args.reference, args.feature, args.grep) + if args.hashes_only: + for hash in sorted(hash_resolver.hashes()): + print(hash) + else: + blocks = FileBlocks(hash_resolver.hashes(), revision=args.revision) + for block in blocks.blocks(): + print(block) + except Exception as exception: + print('ERROR - {}'.format(exception.args[0]), file=sys.stderr) + for arg in exception.args[1:]: + for line in arg.rstrip('\n').split('\n'): + print(' {}'.format(line), file=sys.stderr) + sys.exit(1) diff --git a/deps/v8/agents/skills/v8-features/scripts/generate_coverage_report.py b/deps/v8/agents/skills/v8-features/scripts/generate_coverage_report.py new file mode 100755 index 000000000000..559a5bafd2ec --- /dev/null +++ b/deps/v8/agents/skills/v8-features/scripts/generate_coverage_report.py @@ -0,0 +1,791 @@ +#!/usr/bin/python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""End-to-end automated coverage report generator. + +Pulls the tip-of-tree coverage, resolves affected blocks, fetches +individual file coverage pages, extracts coverage data, +and compiles a beautiful markdown summary report. +""" + +import argparse +import concurrent.futures +import json +import os +import re +import subprocess +import sys +import tempfile +import requests + +# Add scripts directory to path to reuse existing modules +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +from get_v8_revision import retrieve_v8_version +from find_affected_blocks import HashResolver, FileBlocks +from extract_coverage import get_coverage + +FUZZILLI_DASHBOARD_URL = ("https://analysis.chromium.org/coverage/p/chromium" + "?platform=fuzzilli-x64&test_suite_type=any&path=//" + "&host=chromium.googlesource.com&project=chromium/src" + "&ref=refs/heads/main&modifier_id=0") + +BUILDBUCKET_SEARCH_URL = ( + "https://cr-buildbucket.appspot.com/prpc/buildbucket.v2.Builds/SearchBuilds" +) +V8_CI_COVERAGE_GCS_PREFIX = ( + "https://storage.googleapis.com/chromium-v8/coverage/ci/linux64_rel") + + +def run_command(args, capture=True): + res = subprocess.run(args, capture_output=capture, text=True) + if res.returncode != 0: + raise Exception(f"Command failed: {' '.join(args)}\nError: {res.stderr}") + return res.stdout.strip() if capture else "" + + +def ensure_revision_in_git(v8_revision): + """Ensures v8_revision exists in the local git object database without mutating HEAD.""" + check = subprocess.run(["git", "cat-file", "-e", f"{v8_revision}^{{commit}}"], + capture_output=True, + text=True) + if check.returncode == 0: + return True + print(f"Fetching V8 revision {v8_revision[:7]} into git object store...") + fetch = subprocess.run( + ["git", "fetch", "--no-write-fetch-head", "origin", v8_revision], + capture_output=True, + text=True) + if fetch.returncode == 0: + return True + return False + + +def fetch_url(url): + """Fetches HTML content from a URL.""" + response = requests.get(url) + response.raise_for_status() + return response.text + + +def get_chromium_revision(): + """Fetches the fuzzilli dashboard and extracts the Chromium commit hash.""" + print("Fetching Fuzzilli dashboard to determine tip-of-tree revision...") + html = fetch_url(FUZZILLI_DASHBOARD_URL) + + # Try to extract full revision from the V8 link first (most precise) + rev_match = re.search(r'revision=([0-9a-f]{40})', html) + if rev_match: + return rev_match.group(1) + + # Fallback to title tag 7-char hash + title_match = re.search( + r'Coverage Summary for chromium/src - ([0-9a-f]{7}) - //', html) + if title_match: + return title_match.group(1) + + raise Exception( + "Could not find Chromium commit hash in Fuzzilli dashboard HTML.") + + +def get_ci_test_coverage_revision(): + """Fetches the latest V8 Linux64 - coverage build revision and report URL.""" + print( + "Querying 'V8 Linux64 - coverage' builder for the latest test coverage report..." + ) + headers = {"Content-Type": "application/json", "Accept": "application/json"} + payload = { + "predicate": { + "builder": { + "project": "v8", + "bucket": "ci", + "builder": "V8 Linux64 - coverage" + }, + }, + "pageSize": + 15, + "fields": ("builds.*.id,builds.*.number,builds.*.status," + "builds.*.output.properties,builds.*.steps"), + } + response = requests.post( + BUILDBUCKET_SEARCH_URL, headers=headers, json=payload) + response.raise_for_status() + text = response.text + if text.startswith(")]}'"): + text = text[4:] + data = json.loads(text) + + candidates = [] + for build in data.get("builds", []): + rev = build.get("output", {}).get("properties", {}).get("got_revision") + report_url = None + for step in build.get("steps", []): + if step.get("name") == "Code coverage": + summary = step.get("summaryMarkdown", "") + match = re.search(r'\((https://[^\s)]+/index\.html)\)', summary) + if match: + report_url = match.group(1)[:-len("/index.html")] + if not rev: + rev_match = re.search(r'/([0-9a-f]{40})$', report_url) + if rev_match: + rev = rev_match.group(1) + break + if rev and report_url: + candidates.append((build.get("number"), rev, report_url)) + elif rev and build.get("status") == "SUCCESS": + candidates.append( + (build.get("number"), rev, f"{V8_CI_COVERAGE_GCS_PREFIX}/{rev}")) + + if not candidates: + raise Exception( + "Could not find any finished 'V8 Linux64 - coverage' build with a coverage report." + ) + + for build_num, rev, report_url in candidates: + if ensure_revision_in_git(rev): + return build_num, rev, report_url + + # Fallback to the latest candidate if git fetch was unavailable + return candidates[0] + + +def fetch_file_coverage(file_path, + temp_dir, + source="fuzzilli", + chromium_revision=None, + ci_report_base_url=None): + """Fetches the coverage HTML for a specific V8 file and saves it locally.""" + if source == "fuzzilli": + coverage_url = ( + f"https://analysis.chromium.org/coverage/p/chromium/file" + f"?host=chromium.googlesource.com&project=chromium/src&ref=refs/heads/main" + f"&revision={chromium_revision}&path=//v8/{file_path}" + f"&platform=fuzzilli-x64&test_suite_type=any&modifier_id=0") + else: + coverage_url = ( + f"{ci_report_base_url}/coverage/b/s/w/ir/cache/builder/v8/{file_path}.html" + ) + + try: + print(f"Fetching {source} coverage for {file_path}...") + response = requests.get(coverage_url) + if response.status_code == 404 and source != "fuzzilli": + # llvm-cov omits HTML files for headers/files with 0 instrumented lines on Linux64 + return file_path, "NOT_INSTRUMENTED" + response.raise_for_status() + html_content = response.text + + temp_file_path = os.path.join( + temp_dir, f"{source}_" + file_path.replace("/", "_") + ".html") + with open(temp_file_path, "w") as f: + f.write(html_content) + return file_path, temp_file_path + except Exception as e: + print( + f"Warning: Failed to fetch {source} coverage for {file_path}: {e}", + file=sys.stderr) + return file_path, None + + +NON_X64_OR_TEST_PATH_RE = re.compile( + r"^(test|tools)/|" + r"/(arm|arm64|ia32|loong64|mips64|ppc|ppc64|riscv|riscv32|riscv64|s390|s390x)/|" + r"-(arm|arm64|ia32|loong64|mips64|ppc|ppc64|riscv|riscv32|riscv64|s390|s390x)(-|\.)" +) + +PREPROC_IF_RE = re.compile(r"^#\s*(if|ifdef|ifndef)\b") +PREPROC_ELIF_RE = re.compile(r"^#\s*elif\b") +PREPROC_ELSE_RE = re.compile(r"^#\s*else\b") +PREPROC_ENDIF_RE = re.compile(r"^#\s*endif\b") + +FUNC_HEADER_RE = re.compile( + r"^\s*(?:[\w:<>\*~&]+\s+)+([A-Za-z_~][\w:<>]*)\s*\([^;]*$") +BENIGN_LINE_RE = re.compile( + r"^\s*(UNREACHABLE\s*\(\)\s*;?|DCHECK[_A-Z]*\s*\(.*\)\s*;?|" + r"CHECK[_A-Z]*\s*\(.*\)\s*;?|default\s*:|break\s*;|" + r"return\s+Next::Reduce.*|\}\s*(else\b.*)?|//.*)?\s*$") + + +def is_non_x64_or_test_file(file_path): + """Returns True if file_path is a test/tool or non-x64 backend file.""" + return bool(NON_X64_OR_TEST_PATH_RE.search(file_path)) + + +def get_file_lines_at_revision(file_path, v8_revision): + """Returns 1-indexed list of lines (index 0 unused) at v8_revision.""" + try: + content = run_command(["git", "show", f"{v8_revision}:{file_path}"]) + return [""] + content.splitlines() + except Exception: + if os.path.isfile(file_path): + with open(file_path, "r", errors="replace") as f: + return [""] + f.read().splitlines() + return [] + + +def _full_preproc_directive(lines, idx): + """Joins backslash-continued preprocessor directive lines starting at idx.""" + parts = [] + cur = idx + while cur < len(lines): + s = lines[cur].strip() + if s.endswith("\\"): + parts.append(s[:-1].strip()) + cur += 1 + else: + parts.append(s) + break + return " ".join(parts) + + +def find_enclosing_context(lines, start_line): + """Finds the nearest enclosing function signature or #if guard above start_line.""" + enclosing_func = None + enclosing_ifdef = None + ifdef_depth = 0 + in_else_branch = False + else_line_idx = None + active_elif = None + + for idx in range( + min(start_line, + len(lines) - 1), max(0, start_line - 120), -1): + line = lines[idx] + stripped = line.strip() + if enclosing_ifdef is None: + if PREPROC_ENDIF_RE.match(stripped): + ifdef_depth += 1 + elif PREPROC_ELSE_RE.match(stripped): + if ifdef_depth == 0 and not in_else_branch and active_elif is None: + in_else_branch = True + else_line_idx = idx + elif PREPROC_ELIF_RE.match(stripped): + if ifdef_depth == 0 and not in_else_branch and active_elif is None: + active_elif = f"L{idx}: {_full_preproc_directive(lines, idx)}" + elif PREPROC_IF_RE.match(stripped): + if ifdef_depth > 0: + ifdef_depth -= 1 + else: + full_dir = _full_preproc_directive(lines, idx) + if active_elif is not None: + enclosing_ifdef = active_elif + elif in_else_branch: + enclosing_ifdef = ( + f"L{else_line_idx}: #else (negating L{idx}: {full_dir})") + else: + enclosing_ifdef = f"L{idx}: {full_dir}" + elif ifdef_depth == 0 and "if constexpr" in stripped: + enclosing_ifdef = f"L{idx}: {stripped}" + + if enclosing_func is None and FUNC_HEADER_RE.match(line): + enclosing_func = f"L{idx}: {stripped}" + if enclosing_ifdef is not None: + break + return enclosing_func, enclosing_ifdef + + +def _has_positive_token(expr, tokens): + """Returns True if any token in tokens appears in expr without a preceding '!'.""" + for tok in tokens: + for m in re.finditer(rf"\b{tok}\b", expr): + prefix = expr[:m.start()] + if not re.search(r"!\s*(?:defined\s*\(\s*)?$", prefix): + return True + return False + + +def _has_negated_token(expr, tokens): + """Returns True if any token in tokens is directly negated by '!' in expr.""" + for tok in tokens: + if re.search(rf"!\s*(?:defined\s*\(\s*)?\b{tok}\b", expr): + return True + return False + + +def _is_non_x64_ifdef(enclosing_ifdef): + if not enclosing_ifdef: + return False + non_x64_tokens = ( + "V8_TARGET_ARCH_32_BIT", + "V8_TARGET_ARCH_IA32", + "V8_TARGET_ARCH_ARM", + "V8_TARGET_ARCH_ARM64", + "V8_TARGET_ARCH_PPC", + "V8_TARGET_ARCH_PPC64", + "V8_TARGET_ARCH_S390", + "V8_TARGET_ARCH_S390X", + "V8_TARGET_ARCH_MIPS64", + "V8_TARGET_ARCH_LOONG64", + "V8_TARGET_ARCH_RISCV", + "V8_TARGET_ARCH_RISCV32", + "V8_TARGET_ARCH_RISCV64", + ) + x64_tokens = ( + "V8_TARGET_ARCH_64_BIT", + "V8_TARGET_ARCH_X64", + ) + if ": #else (negating " in enclosing_ifdef: + negated_part = enclosing_ifdef.split(": #else (negating ", 1)[1] + if "#ifndef " in negated_part: + return (_has_positive_token(negated_part, non_x64_tokens) and + not _has_positive_token(negated_part, x64_tokens)) + if _has_positive_token(negated_part, x64_tokens): + return True + if (_has_negated_token(negated_part, non_x64_tokens) and + not _has_negated_token(negated_part, x64_tokens)): + return True + return False + if "#ifndef " in enclosing_ifdef: + return _has_positive_token(enclosing_ifdef, x64_tokens) + if _has_positive_token(enclosing_ifdef, x64_tokens): + return False + if _has_negated_token(enclosing_ifdef, x64_tokens): + return True + return _has_positive_token(enclosing_ifdef, non_x64_tokens) + + +def classify_uncovered_block(file_path, + lines, + start_line, + end_line, + enclosing_func, + enclosing_ifdef, + source="fuzzilli"): + """Heuristic auto-triage hint for an uncovered block.""" + block_lines = [ + lines[i] for i in range(start_line, min(end_line + 1, len(lines))) + ] + joined = "\n".join(block_lines) + if block_lines and all(BENIGN_LINE_RE.match(l) for l in block_lines): + return "Benign — UNREACHABLE / DCHECK / control-flow boilerplate" + if "V8_TARGET_ARCH_64_BIT" in joined and "UNREACHABLE()" in joined: + return "Benign — 32-bit only (UNREACHABLE on 64-bit)" + if "ShouldSkipOptimizationStep" in joined: + return "Benign — Optimization bisection guard" + if (enclosing_func and "PrintOptions" in enclosing_func) or ("PrintOptions" + in joined): + return "Benign — IR printing / diagnostics" + if (enclosing_func and "inputs_rep" in enclosing_func) or ("inputs_rep()" + in joined): + return "Benign — Turboshaft IR metadata / debug validation" + if _is_non_x64_ifdef(enclosing_ifdef): + return "Benign — Non-x64 / 32-bit fallback" + if source == "fuzzilli" and file_path.endswith("random-module-generation.cc"): + return "Benign — Wasm libFuzzer random module generator" + return None + + +def _generate_single_source_report(commits, + source="fuzzilli", + checkout=False, + show_snippets=True): + log_lines = [] + chromium_revision = None + ci_report_base_url = None + ci_build_num = None + + if source == "fuzzilli": + chromium_revision = get_chromium_revision() + v8_revision = retrieve_v8_version(chromium_revision) + ensure_revision_in_git(v8_revision) + log_lines.append( + f"Fuzzilli Tip of Tree: Chromium={chromium_revision[:7]} -> V8={v8_revision[:7]}" + ) + else: + ci_build_num, v8_revision, ci_report_base_url = ( + get_ci_test_coverage_revision()) + log_lines.append( + f"V8 Linux64 - coverage (Build #{ci_build_num}): V8={v8_revision[:7]} ({ci_report_base_url}/index.html)" + ) + + # Handle git checkout if requested + current_revision = run_command(["git", "rev-parse", "HEAD"]) + if checkout and current_revision != v8_revision: + log_lines.append(f"Checking out V8 revision {v8_revision[:7]}...") + run_command(["git", "fetch"]) + run_command(["git", "checkout", v8_revision]) + + # Find affected files and blocks (skipping non-x64/test files before git blame) + log_lines.append( + f"Analyzing Git diffs and blames against revision {v8_revision[:7]} to identify affected blocks..." + ) + blocks_analyzer = FileBlocks( + commits, + revision=v8_revision, + skip_file_predicate=is_non_x64_or_test_file) + affected_blocks = blocks_analyzer.blocks() + skipped_files = blocks_analyzer.skipped() + + if not affected_blocks and not skipped_files: + log_lines.append("No code blocks were affected by the provided references.") + return "\n".join(log_lines) + + # Group blocks by file + files_to_blocks = {} + for block in affected_blocks: + files_to_blocks.setdefault(block.file, []).append(block) + + # Fetch coverage HTMLs in parallel using ThreadPoolExecutor + temp_files = {} + with tempfile.TemporaryDirectory() as temp_dir: + log_lines.append( + f"Downloading {source} coverage reports for {len(files_to_blocks)} x64/shared files " + f"(skipped {len(skipped_files)} non-x64/test files)...") + with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: + futures = [ + executor.submit( + fetch_file_coverage, + file_path, + temp_dir, + source=source, + chromium_revision=chromium_revision, + ci_report_base_url=ci_report_base_url) + for file_path in files_to_blocks.keys() + ] + for future in concurrent.futures.as_completed(futures): + file_path, temp_file = future.result() + if temp_file: + temp_files[file_path] = temp_file + + # Parse coverage and compile statistics + if (files_to_blocks and all( + temp_files.get(fp) == "NOT_INSTRUMENTED" for fp in files_to_blocks)): + raise Exception( + f"All {len(files_to_blocks)} requested files returned 404 from " + f"{ci_report_base_url}. The report URL layout may have changed.") + + covered_lines = 0 + uncovered_lines = 0 + ignored_lines = 0 + per_file_stats = [] + uncovered_blocks_entries = [] + file_coverage_maps = {} + + for file_path in sorted(files_to_blocks.keys()): + blocks = files_to_blocks[file_path] + html_file = temp_files.get(file_path) + if html_file == "NOT_INSTRUMENTED": + for block in blocks: + ignored_lines += (block.end - block.begin + 1) + continue + if not html_file: + for block in blocks: + uncovered_blocks_entries.append( + (file_path, block.begin, block.end, "No coverage data available")) + continue + + # Map blocks (including ±3 context lines) to line ranges for extract_coverage + line_ranges = [] + for block in blocks: + ctx_begin = max(1, block.begin - 3) + ctx_end = block.end + 3 + line_ranges.append(f"{ctx_begin}-{ctx_end}") + + with open(html_file, "r") as f: + coverage_results = get_coverage(f, line_ranges) + + coverage_map = dict(coverage_results) + file_coverage_maps[file_path] = coverage_map + file_cov = 0 + file_uncov = 0 + file_ign = 0 + + for block in blocks: + current_uncovered_start = None + for line_num in range(block.begin, block.end + 1): + status = coverage_map.get(line_num) + if status is None or status == "Not found": + ignored_lines += 1 + file_ign += 1 + if current_uncovered_start is not None: + uncovered_blocks_entries.append( + (file_path, current_uncovered_start, line_num - 1, None)) + current_uncovered_start = None + elif status == "0": + uncovered_lines += 1 + file_uncov += 1 + if current_uncovered_start is None: + current_uncovered_start = line_num + else: + covered_lines += 1 + file_cov += 1 + if current_uncovered_start is not None: + uncovered_blocks_entries.append( + (file_path, current_uncovered_start, line_num - 1, None)) + current_uncovered_start = None + + if current_uncovered_start is not None: + uncovered_blocks_entries.append( + (file_path, current_uncovered_start, block.end, None)) + + file_exec = file_cov + file_uncov + file_total = file_exec + file_ign + if file_exec > 0: + per_file_stats.append( + (file_path, file_total, file_exec, file_cov, file_uncov, file_ign)) + + # Pre-fetch source files at v8_revision in parallel for uncovered blocks + file_lines_cache = {} + uncovered_files = sorted( + {fp for fp, _, _, note in uncovered_blocks_entries if not note}) + if uncovered_files: + with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: + fut_to_fp = { + executor.submit(get_file_lines_at_revision, fp, v8_revision): fp + for fp in uncovered_files + } + for fut in concurrent.futures.as_completed(fut_to_fp): + file_lines_cache[fut_to_fp[fut]] = fut.result() + + # Classify uncovered blocks and compute auto-triaged benign counts per file + file_benign_uncov = {} + classified_entries = [] + for file_path, start_line, end_line, note in uncovered_blocks_entries: + enclosing_func = None + enclosing_ifdef = None + hint = None + if not note: + lines = file_lines_cache.get(file_path, []) + enclosing_func, enclosing_ifdef = find_enclosing_context( + lines, start_line) + hint = classify_uncovered_block( + file_path, + lines, + start_line, + end_line, + enclosing_func, + enclosing_ifdef, + source=source) + if hint and hint.startswith("Benign"): + file_benign_uncov[file_path] = ( + file_benign_uncov.get(file_path, 0) + (end_line - start_line + 1)) + classified_entries.append((file_path, start_line, end_line, note, + enclosing_func, enclosing_ifdef, hint)) + + total_benign_uncov = sum(file_benign_uncov.values()) + total_needs_triage = uncovered_lines - total_benign_uncov + + # Build markdown report + out = list(log_lines) + report_title = ("FUZZILLI LINE COVERAGE SUMMARY REPORT" + if source == "fuzzilli" else + "V8 LINUX64 TEST COVERAGE SUMMARY REPORT") + out.append("\n" + "=" * 80) + out.append(f" {report_title}") + out.append("=" * 80) + + total_lines = covered_lines + uncovered_lines + ignored_lines + executable_lines = covered_lines + uncovered_lines + covered_pct = (covered_lines / executable_lines * + 100) if executable_lines > 0 else 0 + uncovered_pct = (uncovered_lines / executable_lines * + 100) if executable_lines > 0 else 0 + effective_exec = executable_lines - total_benign_uncov + effective_pct = (covered_lines / effective_exec * + 100) if effective_exec > 0 else 100.0 + + out.append("\n### Summary Metrics") + if source == "fuzzilli": + out.append( + f"* **Coverage source:** Fuzzilli (`Chromium {chromium_revision[:7]}` / `V8 {v8_revision[:7]}`)" + ) + else: + out.append( + f"* **Coverage source:** V8 Linux64 - coverage ([Build #{ci_build_num}]({ci_report_base_url}/index.html), `V8 {v8_revision[:7]}`)" + ) + out.append(f"* **Total lines modified by CLs:** {total_lines}") + out.append(f"* **Executable lines:** {executable_lines}") + out.append( + f"* **Covered lines:** {covered_lines} ({covered_pct:.1f}% raw; {effective_pct:.1f}% excluding auto-triaged benign)" + ) + out.append( + f"* **Uncovered lines:** {uncovered_lines} ({uncovered_pct:.1f}%) — " + f"{total_benign_uncov} auto-triaged benign, **{total_needs_triage} needing triage**" + ) + out.append( + f"* **Ignored lines (no coverage info / non-x64 / tests):** {ignored_lines}" + ) + + if per_file_stats: + out.append("\n### Per-File Coverage Breakdown (Executable on Linux x64)") + out.append( + "| File | Total Modified | Executable | Covered | Uncovered (Raw) | Auto-Benign | Needs Triage | Ignored | Raw Cov % | Eff. Cov % |" + ) + out.append( + "| :--- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |" + ) + for (fp, f_tot, f_exec, f_cov, f_uncov, f_ign) in per_file_stats: + f_benign = file_benign_uncov.get(fp, 0) + f_triage = f_uncov - f_benign + pct = (f_cov / f_exec * 100) if f_exec > 0 else 0.0 + eff_denom = f_exec - f_benign + eff_pct_str = f"{(f_cov / eff_denom * 100):.1f}%" if eff_denom > 0 else "N/A" + fp_cell = f"**`{fp}`**" if f_triage > 0 else f"`{fp}`" + out.append( + f"| {fp_cell} | {f_tot} | {f_exec} | {f_cov} | {f_uncov} | {f_benign} | {f_triage} | {f_ign} | {pct:.1f}% | {eff_pct_str} |" + ) + + out.append("\n### Uncovered Code Blocks") + if classified_entries: + for (file_path, start_line, end_line, note, enclosing_func, + enclosing_ifdef, hint) in classified_entries: + range_str = (f"{file_path}:{start_line}-{end_line}" + if start_line != end_line else f"{file_path}:{start_line}") + if note: + out.append(f"- `{range_str}` ({note})") + continue + + header_suffix = f" — **[{hint}]**" if hint else " — **[Needs Triage]**" + context_parts = [p for p in (enclosing_func, enclosing_ifdef) if p] + context_str = (f" *(Context: {'; '.join(context_parts)})*" + if context_parts else "") + out.append(f"- `{range_str}`{header_suffix}{context_str}") + if show_snippets: + lines = file_lines_cache.get(file_path, []) + cov_map = file_coverage_maps.get(file_path, {}) + if lines: + out.append(" ```cpp") + ctx_start = max(1, start_line - 2) + ctx_end = min(len(lines) - 1, end_line + 2) + for ln in range(ctx_start, ctx_end + 1): + st = cov_map.get(ln) + if st == "0": + tag = "UNCOV " + elif st is None or st == "Not found": + tag = " --- " + else: + tag = f"cov:{str(st):>3s}" + marker = ">>" if start_line <= ln <= end_line else " " + out.append(f" {marker}{ln:4d} [{tag}]: {lines[ln]}") + out.append(" ```") + else: + out.append( + "🎉 **100% Line Coverage!** No uncovered blocks found in modified lines." + ) + out.append("\n" + "=" * 80) + return "\n".join(out) + + +def generate_report(references, + features=None, + greps=None, + source="fuzzilli", + checkout=False, + show_snippets=True, + output_dir=None): + # Step 1: Resolve references to commit hashes in parallel + print("Resolving references to commit hashes...") + hash_resolver = HashResolver() + hash_resolver.resolve_all(references, features, greps) + commits = hash_resolver.hashes() + bugs = sorted(hash_resolver.bugs()) + print(f"Resolved to {len(commits)} commits" + + (f" across bugs {', '.join(bugs)}" if bugs else "") + + f": {', '.join(sorted(commits))}") + + if output_dir: + os.makedirs(output_dir, exist_ok=True) + with open(os.path.join(output_dir, "commits.txt"), "w") as f: + f.write("\n".join(sorted(commits)) + "\n") + with open(os.path.join(output_dir, "bugs.txt"), "w") as f: + f.write("\n".join(bugs) + "\n") + + norm_source = "tests" if source == "ci" else source + sources = ["fuzzilli", "tests"] if norm_source == "both" else [norm_source] + + if len(sources) > 1 and not checkout: + with concurrent.futures.ThreadPoolExecutor( + max_workers=len(sources)) as executor: + fut_map = { + src: + executor.submit( + _generate_single_source_report, + commits, + source=src, + checkout=False, + show_snippets=show_snippets) for src in sources + } + for src in sources: + report_text = fut_map[src].result() + if output_dir: + out_path = os.path.join(output_dir, f"{src}-coverage.md") + with open(out_path, "w") as f: + f.write(report_text + "\n") + try: + print(report_text) + except BrokenPipeError: + pass + else: + for src in sources: + report_text = _generate_single_source_report( + commits, source=src, checkout=checkout, show_snippets=show_snippets) + if output_dir: + out_path = os.path.join(output_dir, f"{src}-coverage.md") + with open(out_path, "w") as f: + f.write(report_text + "\n") + try: + print(report_text) + except BrokenPipeError: + pass + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Generate an end-to-end line coverage report.") + parser.add_argument( + "reference", + nargs="*", + help="Git commit hash, Change-Id, bug ID/link, or feature flag name.") + parser.add_argument( + "--feature", + "-f", + action="append", + default=[], + help="Feature flag name (e.g. wide_arithmetic) to trace across flag files and bugs." + ) + parser.add_argument( + "--grep", + "-g", + action="append", + default=[], + help="Commit message regex/substring (e.g. '\\[wasm-wide-arith\\]') to include." + ) + parser.add_argument( + "--source", + "-s", + choices=["fuzzilli", "tests", "ci", "both"], + default="fuzzilli", + help=( + "Coverage report source: 'fuzzilli' (Fuzzilli x64 dashboard, default), " + "'tests' / 'ci' (latest 'V8 Linux64 - coverage' CI build), or 'both'." + )) + parser.add_argument( + "--output-dir", + "-o", + help=("Optional directory (e.g. /tmp/v8-coverage) to save commits.txt, " + "bugs.txt, fuzzilli-coverage.md, and tests-coverage.md.")) + parser.add_argument( + "--checkout", + action="store_true", + help="Automatically checkout the matching V8 revision.") + parser.add_argument( + "--no-snippets", + action="store_true", + help="Omit source code snippets and auto-triage hints for uncovered blocks." + ) + args = parser.parse_args() + if not args.reference and not args.feature and not args.grep: + parser.error("At least one reference, --feature, or --grep is required.") + + try: + generate_report( + args.reference, + features=args.feature, + greps=args.grep, + source=args.source, + checkout=args.checkout, + show_snippets=not args.no_snippets, + output_dir=args.output_dir) + except Exception as e: + print(f"\nERROR: {e}", file=sys.stderr) + sys.exit(1) diff --git a/deps/v8/agents/skills/v8-features/scripts/get_v8_revision.py b/deps/v8/agents/skills/v8-features/scripts/get_v8_revision.py new file mode 100755 index 000000000000..bd7dde088abd --- /dev/null +++ b/deps/v8/agents/skills/v8-features/scripts/get_v8_revision.py @@ -0,0 +1,38 @@ +#! /usr/bin/python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import requests +import base64 +import re +import sys +import argparse + + +def retrieve_v8_version(chromium_hash: str) -> str: + v8_version_pattern = re.compile(' *\'v8_revision\': *\'([0-9a-f]{40})\',') + request = requests.get( + 'https://chromium.googlesource.com/chromium/src.git/+/{0}/DEPS?format=TEXT' + .format(chromium_hash)) + if request.status_code != 200: + raise Exception(f'Unknown Chromium hash {chromium_hash}') + content = base64.b64decode(request.text).decode('utf-8') + for line in content.split('\n'): + match = v8_version_pattern.fullmatch(line) + if match is not None: + return match.group(1) + raise Exception( + f'Could not find v8_revision in DEPS for Chromium hash {chromium_hash}') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Output the V8 Git hash corresponding to a Chromium Git hash') + parser.add_argument('hash', help='Chromium commit hash') + args = parser.parse_args() + try: + print(retrieve_v8_version(args.hash)) + except Exception as e: + print(f'ERROR - {e}', file=sys.stderr) + sys.exit(1) diff --git a/deps/v8/agents/skills/v8-features/scripts/read_finch_config.py b/deps/v8/agents/skills/v8-features/scripts/read_finch_config.py new file mode 100755 index 000000000000..1b1fb15facd3 --- /dev/null +++ b/deps/v8/agents/skills/v8-features/scripts/read_finch_config.py @@ -0,0 +1,332 @@ +#! /usr/bin/python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Reads active V8/Wasm Finch study configs from google3 and Chromium's fieldtrial_testing_config.json.""" + +import argparse +import base64 +import concurrent.futures +import json +import os +import re +import shutil +import subprocess +import sys +import requests + +GOOGLE3_FINCH_GCL_DIR = ( + '/google/src/files/head/depot/google3/googledata/googleclient/chrome/finch/gcl_studies' +) +FIELDTRIAL_TESTING_CONFIG_URL = ( + 'https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/' + 'testing/variations/fieldtrial_testing_config.json') + +FEATURE_DECL_RE = re.compile( + r'\bFeature\s+([A-Za-z0-9_]+)\s*=\s*' + r'(configs\.(enabled|disabled)_feature|\{\s*enabled\s*=\s*(true|false))') +ROLLOUT_HELPER_RE = re.compile( + r'configs\.(?:BinaryFeatureGroups|StandardFeatureRollout(?:WithPreperiods)?)' + r'\s*\([^)]*?\'([^\']+)\'') +STUDY_NAME_RE = re.compile( + r'Study\s+study\s*=\s*\{[^}]*?\bname\s*=\s*\'([^\']+)\'', re.DOTALL) +ACTIVE_STAGE_RE = re.compile(r'^\s*(?:RolloutStage\s+)?active\s*=\s*([^\n{]+)', + re.MULTILINE) +CHANNEL_CONFIG_RE = re.compile( + r'^\s*Config\s+(canary_dev|canary|dev|beta|stable)\s*=', re.MULTILINE) + + +def is_v8_or_wasm_feature(name: str) -> bool: + norm = name[1:] if name.startswith('k') and name[1:2].isupper() else name + return norm.startswith(('V8', 'WebAssembly', 'Wasm', 'JavaScript')) + + +def format_v8_flag(feature_name: str) -> str: + if feature_name.startswith('V8Flag_'): + raw = feature_name[len('V8Flag_'):] + return f'--{raw.lower().replace("_", "-")} ({feature_name})' + return feature_name + + +class Google3FinchGclScanner: + """Scans actual Finch GCL study files in google3.""" + + SKIP_DIRS = {'launched', 'autoconverted', 'legacy', 'metrics', 'templates'} + + def __init__(self, + gcl_dir: str = GOOGLE3_FINCH_GCL_DIR, + include_launched: bool = False): + self.gcl_dir = gcl_dir + self.include_launched = include_launched + self.available = os.path.isdir(gcl_dir) + # Maps feature_or_flag -> list of (study_name, rel_path, state_str, stage_str) + self.entries: dict[str, list[tuple[str, str, str, str]]] = {} + if self.available: + self._scan() + + def _discover_candidate_files(self) -> set[str]: + candidates = set() + if shutil.which('cs'): + excl = '' if self.include_launched else '-f:/(launched|autoconverted|legacy|ukm_sampling)/ ' + query = ( + f'f:^//depot/google3/googledata/googleclient/chrome/finch/gcl_studies/ ' + f'{excl}' + f'(V8Flag_|WebAssembly|Feature\\s+V8|BinaryFeatureGroups.*(V8|Wasm|WebAssembly|JavaScript)|' + f'StandardFeatureRollout.*(V8|Wasm|WebAssembly|JavaScript))') + try: + res = subprocess.run( + ['cs', '--max_num_results=500', '-l', query], + capture_output=True, + text=True, + timeout=8, + ) + if res.returncode == 0 and res.stdout: + for line in res.stdout.splitlines(): + line = line.strip() + if line.endswith('.gcl') and os.path.isfile(line): + candidates.add(line) + except Exception: + pass + + if candidates: + for sub in ('', 'performance_teams', 'web_platform'): + d = os.path.join(self.gcl_dir, sub) if sub else self.gcl_dir + if not os.path.isdir(d): + continue + for fn in os.listdir(d): + if fn.endswith('.gcl') and any( + k in fn.lower() + for k in ('v8', 'wasm', 'webassembly', 'javascript')): + candidates.add(os.path.join(d, fn)) + return candidates + + skip_dirs = ({'autoconverted', 'legacy', 'metrics', 'templates'} + if self.include_launched else self.SKIP_DIRS) + for dirpath, dirnames, filenames in os.walk(self.gcl_dir): + dirnames[:] = [d for d in dirnames if d not in skip_dirs] + for fn in filenames: + if fn.endswith('.gcl') and any( + k in fn.lower() + for k in ('v8', 'wasm', 'webassembly', 'javascript')): + candidates.add(os.path.join(dirpath, fn)) + return candidates + + def _parse_gcl_file(self, path: str) -> list[tuple[str, str, str, str, str]]: + try: + with open(path, 'r', errors='replace') as f: + text = f.read() + except OSError: + return [] + + rel_path = os.path.relpath(path, self.gcl_dir) + study_match = STUDY_NAME_RE.search(text) + study_name = study_match.group(1) if study_match else os.path.splitext( + os.path.basename(path))[0] + + active_stages = [ + s.strip() for s in ACTIVE_STAGE_RE.findall(text) if s.strip() + ] + channel_configs = CHANNEL_CONFIG_RE.findall(text) + is_killswitch = bool( + re.search(r'_group_templates\.disabled|Kill[Ss]witch', text) and + not re.search(r'_group_templates\.enabled', text)) + + if active_stages: + stage_str = active_stages[-1] + if stage_str.startswith('configs.LaunchStage'): + stage_str = 'KillSwitch/LaunchStage' if is_killswitch else 'LaunchStage' + elif stage_str.startswith('configs.MultiArmConfig'): + stage_str = 'MultiArmConfig' + elif channel_configs: + stage_str = 'channels:' + ','.join(dict.fromkeys(channel_configs)) + else: + stage_str = 'configured' + + if not self.include_launched and stage_str == 'LAUNCHED': + return [] + + feat_states: dict[str, set[str]] = {} + for m in FEATURE_DECL_RE.finditer(text): + feat = m.group(1) + if not is_v8_or_wasm_feature(feat): + continue + st = 'enabled' if (m.group(3) == 'enabled' or + m.group(4) == 'true') else 'disabled' + feat_states.setdefault(feat, set()).add(st) + + for m in ROLLOUT_HELPER_RE.finditer(text): + feat = m.group(1) + if not is_v8_or_wasm_feature(feat): + continue + st = 'disabled' if is_killswitch else 'enabled' + feat_states.setdefault(feat, set()).add(st) + + results = [] + for feat, states in feat_states.items(): + if 'enabled' in states and 'disabled' in states: + state_str = 'enabled+control' + elif 'enabled' in states: + state_str = 'enabled' + else: + state_str = 'disabled (kill-switch)' + results.append((feat, study_name, rel_path, state_str, stage_str)) + return results + + def _scan(self) -> None: + files = sorted(self._discover_candidate_files()) + with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: + for file_results in executor.map(self._parse_gcl_file, files): + for feat, study_name, rel_path, state_str, stage_str in file_results: + self.entries.setdefault(feat, []).append( + (study_name, rel_path, state_str, stage_str)) + + +class FieldTrialConfig: + """Parses Chromium's testing/variations/fieldtrial_testing_config.json.""" + + def __init__(self, content: str): + data = json.loads(content) + # Maps feature_or_flag -> list of (study_name, exp_name, state, platforms) + self.v8_flags: dict[str, list[tuple[str, str, str, list[str]]]] = {} + self.base_features: dict[str, list[tuple[str, str, str, list[str]]]] = {} + for study_name, config_array in data.items(): + for config in config_array: + platforms = config.get('platforms', []) + for experiment in config.get('experiments', []): + exp_name = experiment.get('name', 'unnamed') + for key, state in ( + ('enable_features', 'enabled'), + ('disable_features', 'disabled'), + ): + for feature in experiment.get(key, []): + if feature.startswith('V8Flag_'): + self.v8_flags.setdefault(feature, []).append( + (study_name, exp_name, state, platforms)) + elif is_v8_or_wasm_feature(feature): + self.base_features.setdefault(feature, []).append( + (study_name, exp_name, state, platforms)) + + +def _format_fieldtrial_entries(entries: list[tuple[str, str, str, list[str]]], + include_disabled: bool) -> str | None: + has_enabled = any(st == 'enabled' for _, _, st, _ in entries) + if not has_enabled and not include_disabled: + return None + parts = sorted({f'{s}/{e} ({st})' for s, e, st, _ in entries}) + return ', '.join(parts) + + +def print_report( + gcl_scanner: Google3FinchGclScanner | None, + fieldtrial_config: FieldTrialConfig | None, + filter_pattern: str | None = None, + include_disabled: bool = False, +) -> None: + regex = re.compile(filter_pattern, re.IGNORECASE) if filter_pattern else None + + if gcl_scanner and gcl_scanner.available: + print(f'=== Google3 Finch Studies ({gcl_scanner.gcl_dir}) ===') + printed_gcl = 0 + for feat in sorted(gcl_scanner.entries.keys()): + items = gcl_scanner.entries[feat] + has_enabled = any(st.startswith('enabled') for _, _, st, _ in items) + if not has_enabled and not include_disabled: + continue + label = format_v8_flag(feat) + studies = ', '.join(f'{study} [{rel}: {st}, stage={stage}]' + for study, rel, st, stage in items) + line = f'{label} -> Finch GCL: {studies}' + if regex and not regex.search(line): + continue + print(line) + printed_gcl += 1 + if printed_gcl == 0: + print(' (No matching active Finch GCL studies found)') + print() + + if fieldtrial_config: + print('=== Chromium FieldTrial Testing Config ' + '(testing/variations/fieldtrial_testing_config.json) ===') + print( + 'Note: FieldTrial testing config is required before running a Finch trial, ' + 'but presence here alone does not mean an active Finch rollout is running.' + ) + printed_ft = 0 + all_ft = {} + all_ft.update(fieldtrial_config.v8_flags) + all_ft.update(fieldtrial_config.base_features) + for feat in sorted(all_ft.keys()): + summary = _format_fieldtrial_entries(all_ft[feat], include_disabled) + if not summary: + continue + label = format_v8_flag(feat) + line = f'{label} -> FieldTrial: {summary}' + if regex and not regex.search(line): + continue + print(line) + printed_ft += 1 + if printed_ft == 0: + print(' (No matching FieldTrial testing config entries found)') + + +def fetch_fieldtrial_config(url: str) -> FieldTrialConfig: + request = requests.get(url + '?format=TEXT', timeout=15) + if request.status_code != 200: + raise Exception( + f'Could not load FieldTrial testing configuration from {url} ' + f'(HTTP {request.status_code})') + content = base64.b64decode(request.text).decode('utf-8') + return FieldTrialConfig(content) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=( + 'Report active V8/Wasm Finch studies from google3 GCL configs ' + 'and Chromium fieldtrial_testing_config.json.')) + parser.add_argument( + '--gcl-dir', + default=GOOGLE3_FINCH_GCL_DIR, + help='Path to google3 Finch GCL studies directory', + ) + parser.add_argument( + '--url', + default=FIELDTRIAL_TESTING_CONFIG_URL, + help='URL of Chromium fieldtrial_testing_config.json', + ) + parser.add_argument( + '--filter', + '-f', + help='Optional case-insensitive regex to filter reported flags/features', + ) + parser.add_argument( + '--include-disabled', + action='store_true', + help='Include disabled-only (kill-switch / control-only) entries', + ) + parser.add_argument( + '--include-launched', + action='store_true', + help='Include GCL studies marked LAUNCHED or in launched/ directory', + ) + args = parser.parse_args() + + with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: + gcl_future = executor.submit(Google3FinchGclScanner, args.gcl_dir, + args.include_launched) + ft_future = executor.submit(fetch_fieldtrial_config, args.url) + gcl_scanner = gcl_future.result() + try: + ft_config = ft_future.result() + except Exception as e: + print(f'ERROR - {e}', file=sys.stderr) + if not gcl_scanner.available: + sys.exit(1) + ft_config = None + + print_report( + gcl_scanner, + ft_config, + filter_pattern=args.filter, + include_disabled=args.include_disabled, + ) diff --git a/deps/v8/agents/skills/v8-poc-classification/SKILL.md b/deps/v8/agents/skills/v8-poc-classification/SKILL.md index 7d453aede493..c2d1cdc472d5 100644 --- a/deps/v8/agents/skills/v8-poc-classification/SKILL.md +++ b/deps/v8/agents/skills/v8-poc-classification/SKILL.md @@ -1,6 +1,6 @@ --- name: v8-poc-classification -description: Checks if a POC provided by some JS and d8 flags is a vulnerability or just a regular bug. +description: Reproduces, heals (e.g., converting browser/HTML POCs to d8), minimizes, and classifies whether a V8 POC is a security vulnerability or a regular bug. --- # Skill: V8 POC Classification @@ -36,6 +36,12 @@ Confirm the bug exists as reported. - **Action**: Run `d8 <provided-flags> <poc.js>`. - **Escalation**: If it doesn't reproduce, try multiple revisions (Reporter's commit and Main) and build configurations (Debug, ASan, Release). +- **Browser Web Worker Translation**: When converting a browser `Worker` POC + (e.g., from `poc.html`) to `d8`, note that `d8` uses + `new Worker(fn, {type: 'function'})`, passes messages directly to + `onmessage = function(msg) { ... }` (not wrapped in `{data: msg}` like DOM + `MessageEvent`), and receives messages on the main thread via + `worker.getMessage()`. - **Deep Dive**: Capture the initial backtrace and faulting instruction in GDB. - **Check for Explicit Aborts:** Look for evidence that execution was intentionally terminated by V8 (e.g., via `SBXCHECK`, `FATAL`, or traps). If @@ -84,8 +90,8 @@ Technical proof of the vulnerability's severity. - If it stops crashing or is caught by a hardened check (`SBXCHECK`, `FATAL`), classify it as **Intended Behavior** or a **Bug**. - **Crashing POC for ClusterFuzz**: A crashing POC (segfault) is highly - preferred for ClusterFuzz upload. Always try to provide a standalone `.js` - file that crashes on a Release build. + preferred for ClusterFuzz upload (see the `clusterfuzz` skill). Always try to + provide a standalone `.js` file that crashes on a Release build. - **Deep Dive (GDB)**: - Verify **Attacker Control**: Do registers or memory at the crash site reflect values set in the POC (e.g., `0x41414141`)? @@ -101,18 +107,22 @@ Technical proof of the vulnerability's severity. The classification MUST be supported by empirical evidence from the local reproduction: -- **Local Reproduction Findings**: - - **Status**: Reproduced / Not Reproduced. - - **Reproduction**: `d8 <flags> <poc.js>` (Exact command used locally). - - **Result**: Summarize the result of running the command (output, crash, - sandbox violation, harmless memory access). - - **Build**: The build variant (e.g., x64.release, x64.debug, asan). Always - include the V8 version from `src/utils/version.h` and the specific git hash - using `git rev-parse HEAD` for technical accuracy. - - **Verified Impact**: Summarize the **Verified Impact** (e.g., confirmed OOB - write). If the bug is purely logical and caught by runtime protections (like - `ref.cast` or bounds checks) without crashing, state this clearly. - - **GDB Backtrace**: Include a snippet if it supports the classification. +- **Local Reproduction Findings** (keep sub-bullets to 1 concise line, except + `GDB Backtrace` if multiple lines help): + - **Status**: `Reproduced` / `Not Reproduced`. + - **Reproduction**: `d8 <flags> <poc.js>` (filename only, omit local paths). + - **Result**: 1–2 short sentences summarizing the output, crash, or sandbox + violation. + - **Build**: Build variant(s) (e.g., `x64.release`, `x64.asan`), V8 version + (from `include/v8-version.h`), and revision number (from + `Cr-Commit-Position`), skipping the git hash and with no link to Gerrit + (only link to Gerrit and include the commit title when the specific *change* + in a commit is important; omit boilerplate GN args). + - **Verified Impact**: 1 sentence stating the verified primitive and attacker + control. + - **GDB Backtrace**: A concise snippet of the faulting instruction/registers + and relevant stack frames (can span multiple lines if helpful; trim + unrelated frames). Summary of rules from [triaging.md](../../../docs/security/triaging.md) based on the threat model: diff --git a/deps/v8/agents/skills/v8-regression-testing/SKILL.md b/deps/v8/agents/skills/v8-regression-testing/SKILL.md index 9e4ab2c768b0..31a5f94551dd 100644 --- a/deps/v8/agents/skills/v8-regression-testing/SKILL.md +++ b/deps/v8/agents/skills/v8-regression-testing/SKILL.md @@ -112,8 +112,8 @@ ______________________________________________________________________ thoroughly understood and strictly necessary to reproduce the issue. Remove all useless or redundant flags. - **Prefer "Leaf" Flags over "Compound" Flags**: - - **Bad**: Using `--jit-fuzzing` or `--fuzzing` because it implies a massive, - ever-changing bundle of underlying behaviors. + - **Bad**: Using `--jit-fuzzing`, `--fuzzing`, or `--experimental-fuzzing` + because they imply a massive, ever-changing bundle of underlying behaviors. - **Good**: Identifying and specifying the exact leaf flags responsible (e.g., `--no-lazy-feedback-allocation`, `--homomorphic-ic`, `--stress-concurrent-inlining-attach-code`). @@ -162,3 +162,13 @@ Avoid default fuzzer variable and function names (`__f_0`, `__v_10`, `v17`, invocations solely to cover different compiler pipelines, unless the test specifically exercises tier-up dynamics, on-stack replacement, or deoptimization transitions between them. + +### 6. Component-Specific Subdirectories + +- Place new `mjsunit` regression tests in the most specific component + subdirectory (e.g., `test/mjsunit/compiler/`, `test/mjsunit/maglev/`, + `test/mjsunit/turbolev/`, `test/mjsunit/turboshaft/`, `test/mjsunit/wasm/`) + rather than the generic catch-all `test/mjsunit/regress/` directory, and test + features in the configuration where they are enabled by default. +- When inheriting or rebasing a regression test from an earlier draft, audit it + against all guidelines in this skill before uploading. diff --git a/deps/v8/agents/skills/v8-review/OWNERS b/deps/v8/agents/skills/v8-review/OWNERS new file mode 100644 index 000000000000..9b3da1bcdfb2 --- /dev/null +++ b/deps/v8/agents/skills/v8-review/OWNERS @@ -0,0 +1,2 @@ +clemensb@chromium.org +dlehmann@chromium.org diff --git a/deps/v8/agents/skills/v8-review/SKILL.md b/deps/v8/agents/skills/v8-review/SKILL.md new file mode 100644 index 000000000000..635306967dd8 --- /dev/null +++ b/deps/v8/agents/skills/v8-review/SKILL.md @@ -0,0 +1,233 @@ +--- +name: v8-review +description: Runs a parallel multi-subagent V8 code review covering security, V8 Sandbox safety, GC invariants, compiler/codegen logic, concurrency, performance, tests, and style, then verifies and merges the findings. Use when reviewing a V8 CL, commit, or local diff. Do not use for triaging bug reports or writing fixes from scratch. +--- + +# V8 Code Review Workflow + +## Step 1: Context Setup (Main Agent) + +1. Save the target commit (`git --no-pager show <commit>`), Gerrit CL + (`gerrit_fetch`), or local diff (`git --no-pager diff HEAD`, plus any + untracked files from `git status --short`) including the commit message (if + any) to `v8-review-<id>.patch` in the conversation's `scratch/` directory. + Never write temporary files into the V8 checkout. + +## Step 2: Parallel Subagents + +Call `invoke_subagent` ONCE with 8 entries (`TypeName: "self"`, +`Model: "inherit"`): + +1. `sandbox-security`: + + - **In-sandbox TOCTOU / double-fetch**: In-sandbox memory (`HeapObject` + fields, lengths, offsets, bitfields) can be concurrently mutated by an + attacker; load once into a local variable before validating/reusing. Never + read in-sandbox memory inside `SBXCHECK(...)` (trips + `DisallowSandboxAccess`). + - **Pointer tables, casts & swap attacks**: Never store raw pointers or + direct `TrustedObject` refs in-sandbox; require `ExternalPointerTable`, + `TrustedPointerTable`, `CodePointerTable`, `JSDispatchTable`, or + `CppHeapPointerTable` with narrow tags (`ExternalPointerTag`, + `TrustedPointerTag`), and `ProtectedPointerSlot` between `TrustedObject`s. + Never use `TrustedCast<T>` on untrusted or 1:N TPT-tagged inputs (use + `SbxCast<T>` / `TryCast<T>`). Guard against **pointer-swap attacks** across + same-tag handles: never assume a `TrustedObject` (`BytecodeArray`, `Code`, + `WasmTrustedInstanceData`, `RegExpData`) matches its holder's in-sandbox + state (parameter count, context, internal fields). Read Wasm security state + from `WasmTrustedInstanceData`, not `WasmInstanceObject`. + - **Out-of-sandbox & trusted writes**: Bounds-check any `TrustedObject` + (`TrustedFixedArray`, `WasmDispatchTable`), C++ heap, or stack access + indexed by in-sandbox values (`Smi`, `BoundedSize`, buffer length/offset) + via `SBXCHECK` / `SBXCHECK_BOUNDS` / `CSA_SBXCHECK` / `SbxCheck` / + `sbxcheck` (never `DCHECK` / `UnsafeCast`), checking signedness and integer + overflow before address math. Require `WritableJitAllocation` / + `ThreadIsolation` for JIT code/jump-table writes. + - **JS re-entrancy & language security**: Check C++/CSA/Torque builtins for + user JS execution (`Object::ToNumber`, `GetProperty`, `Execution::Call`, + Proxy traps, `valueOf`/`toString`, Wasm imports) that can detach/shrink + `ArrayBuffer`s (including RAB/GSAB), transition `Map`s, change + `ElementsKind`, or mutate lengths mid-operation. Ensure hole sentinels + (`TheHole`, etc.) or uninitialized memory never leak to JS. + +2. `correctness-gc`: + + - **Spec & functional correctness**: ECMAScript/Wasm spec compliance, + exception propagation (`RETURN_ON_EXCEPTION`, `has_exception()`, never + running JS with a pending exception), `MaybeDirectHandle`/`MaybeHandle` + empty checks, RAII cleanup on early return. + - **Integer overflow & truncation**: Signed/unsigned mismatches, 32-bit vs. + 64-bit truncation (`int32_t` vs. `size_t`/`uintptr_t`, Wasm `memory64` + offsets), `Smi` range/tagging overflow, promoting to `size_t` or + `base::CheckedNumeric` before arithmetic + (`slots * kSystemPointerSize + offset`). + - **GC safepoints, handles & Oilpan**: Raw `Tagged<T>` or interior pointers + held across allocations/GC (must use `DirectHandle<T>` / `Handle<T>`), + missing `DisallowGarbageCollection` scopes, stale pointers after + resize/migration, Torque missing `transitioning` on macros/builtins that + can allocate/call JS. In Oilpan (`CppHeap`), never place `cppgc::Member<T>` + on the stack or raw `GarbageCollected<T>*` in heap objects (trace all + `Member<T>` in `Trace(Visitor*)` and call `Base::Trace(visitor)`). + - **Write barriers & heap invariants**: Missing `WriteBarrier`, + `CONDITIONAL_WRITE_BARRIER`, `TrustedPointerWriteBarrier`, or + `ProtectedPointerWriteBarrier`, unsafe `SKIP_WRITE_BARRIER`, `Smi` vs. + `HeapObject` assumptions. + +3. `compiler-codegen`: + + - **IR reductions & effects**: Turboshaft, TurboFan, Maglev, Sparkplug, and + Liftoff lowerings; 32-bit `I64` lowering (`Int64LoweringReducer`); 64-bit + upper-32-bit sign/zero-extension; Maglev `kHoleyFloat64` signaling-NaN hole + checks; accurate Turboshaft `OpEffects` and Maglev `OpProperties` + (`can_allocate`, `can_eager_deopt`, `can_lazy_deopt`, `can_read`, + `can_write`); CSA `TVARIABLE` binding on all incoming `BIND` paths. + - **Deoptimization & protectors**: Missing deopt checks, lazy deopt frame + state completeness, map/prototype/species/array protector checks and + invalidation, Wasm subtyping and signature checks. + - **MacroAssembler & backend**: Register aliasing (`dst` aliasing `src` in + multi-instruction sequences, `UseUniqueRegister`), clobbered scratch + registers (`TemporaryRegisterScope`, Liftoff cache spills) across + helper/barrier calls, stack frame alignment and slot accounting, + condition/branch inversions. + - **Fail-fast assertions vs. defensive masking**: Prefer failing fast via + `DCHECK`/`CHECK` on unexpected compiler states or invariant violations. Do + NOT recommend adding defensive workarounds (e.g., silent early returns, + fallback dummy values, defensive clamping, or non-exhaustive switch + `default: break;`) that paper over upstream invariant violations. + +4. `concurrency`: + + - **Object publication & TOCTOU**: Safe publication to background threads + (`SharedObjectSafePublishGuard`, `SharedObjectConditionalSafePublishGuard`, + release-store / acquire-load), concurrent map/descriptor/transition array + reads. (Return `[]` for purely main-thread code; leave in-sandbox attacker + races to `sandbox-security`.) + - **Concurrent JIT & GC**: Background compilation (Maglev/Turboshaft/Wasm) + racing with main-thread mutation or concurrent GC + marking/sweeping/evacuation; shared space (`SharedStruct`, `SharedArray`, + shared Wasm objects) synchronization. + - **Atomics & locks**: `std::memory_order` correctness, lock + ordering/deadlocks, accessing non-thread-safe `Isolate` state from + background threads (`LocalIsolate`/`LocalHeap` boundaries). + +5. `architecture-api`: + + - **Cross-arch, cross-tier & variant completeness**: Parity across the 4 + supported architectures (`x64`, `arm64`, `ia32`, `arm` — ignore community + ports like `riscv`, `loong64`, `ppc64`, `s390x`, `mips64` unless targeted + by the CL), execution tiers (Ignition, Sparkplug, Maglev, Turboshaft, + Liftoff), and all affected opcodes/builtins. For bug fixes, perform variant + analysis to check if the same bug pattern exists in sibling opcodes, + builtins, reducers, or tiers. + - **Optimization preservation & design**: Fix specific invariant flaws rather + than disabling fast paths wholesale; reuse existing helpers/passes and + encapsulate state mutations on the owning class; keep headers lean (`.cc` + definitions for non-hot methods, `namespace {}` in `.cc` for helpers not + using `this`); avoid `#if V8_TARGET_ARCH_...` in shared code; flag edits to + generated files (`out/`) or unrelated drive-by refactors. + - **API surface, flags & presubmit**: Swallowed errors or defensive + workarounds instead of `CHECK`/`DCHECK`/`UNREACHABLE()` (never suggest + defensive fallbacks that mask unexpected states or invariant violations), + error fallbacks bypassing subsequent checks, unused parameters/fields, dead + code, missing flag implications (`DEFINE_IMPLICATION`) under `--fuzzing`, + production `.cc` code calling `*ForTest*` helpers, new `V8_OBJECT`/`V8_IT_` + headers missing from `src/objects/all-objects.h`. + +6. `performance-containers`: + + - **Hot-path performance**: Heap allocations on hot paths (ICs, dispatch, GC, + interpreter/JIT fast paths, frequent compiler phases), cold error/runtime + paths inlined into hot assembly (prefer `OutOfLineCode` / deferred blocks), + redundant runtime checks. + - **Algorithmic & data layout**: `O(n^2)` scans over IR + nodes/instructions/registers, Zone memory bloat, and (on hot/high-volume + paths) missing `reserve()`, unnecessary copies, or poor struct field + packing. + - **Types & containers**: Strong types / `enum class` / `base::Flags` over + boolean flags; V8 containers (`base::SmallVector`, `base::Vector`, + `base::UniqueArray`, `absl::flat_hash_map`, `absl::flat_hash_set`, + `base::FunctionRef`). + +7. `tests`: + + - **Mandatory reproducer & fidelity**: Flag a `bug` if a bug fix omits a + regression test. Verify tests (`test/mjsunit/`, `test/unittests/`, + `test/cctest/`) exercise the modified path and fail without the fix (watch + for early errors in helper closures before target code, or missing + `%PrepareFunctionForOptimization` + warmup call before + `%OptimizeFunctionOnNextCall`). + - **Boundary coverage**: Edge cases (`0`, `-0`, `NaN`, `INT32_MIN`, + `INT32_MAX`, `UINT32_MAX`, `Smi` range, empty/max-size buffers or Wasm + modules). + - **V8 test guidelines**: Component-specific subdirectory over catch-all + `test/mjsunit/regress/`; `assertEquals(expected, found)` order; never + include `d8.file.execute('test/mjsunit/mjsunit.js')`; minimal leaf flags + over `--fuzzing`/`--jit-fuzzing`/`--experimental-fuzzing`; no hardcoded + tier flags (`--no-liftoff`, `--turboshaft`, `--maglev`) already covered by + test variants unless testing tier-up/OSR (`assertOptimized()` requires + `--maglev`/`--turbolev`/`--turbofan`); `--allow-natives-syntax` with no + space after `%` (`%Foo()`); `--stack-size=100` on stack-exhaustion tests; + no CPU-burning warmup loops or fuzzer boilerplate (`__f_0`, `__v_0`, + `__wrapTC`, swallowed `catch (e) {}`). + +8. `style-comments`: + + - **V8 C++ style & presubmit**: Spell out types instead of `auto` unless + obvious or overly long; tight local variable scope (declared at first use); + `const`-correctness and `std::forward`; `base::bit_cast` (never + `std::bit_cast`), `UNREACHABLE()`; V8 banned constructs (`<regex>`, + `std::mutex`, `absl::FunctionRef`, `dynamic_cast`, exceptions, trailing + whitespace); `-inl.h` rules (never `#include "*-inl.h"` in normal `.h`; + `foo-inl.h` must `#include "foo.h"` first); `V8_NOEXCEPT` on copy/move + constructors and assignment operators; `{}` braces on all multi-line `if` + statements; copyright header on new files. + - **Comments & readability**: Documenting class invariants and non-obvious + rationale; updating stale adjacent comments contradicted by the diff; + identifying pure code moves. + +Instructions for every subagent: + +- Read the patch file from Step 1, then inspect modified files, callers, and + callees using `view_file` and `repo_git_grep` (or `git --no-pager grep` via + `run_command`; avoid `code_search` as it searches stale/multiple google3 V8 + snapshots). +- NEVER modify any files, mutate git state, or run builds/tests (only read-only + `git --no-pager grep`/`show`/`log` commands are allowed). +- Comment ONLY on modified or directly impacted lines (never flag unrelated + pre-existing issues in untouched code; if the change newly exposes, triggers, + or relies on a pre-existing bug, or misses a bug variant in adjacent code, + flag it anchored on the relevant modified line; if an issue exists in moved + code, note that it is pre-existing). +- Treat each test case (`TEST`, `UNINITIALIZED_TEST`, `TEST_F`, `TEST_P`) in + `test/cctest/`, `test/unittests/`, and `test/mjsunit/` as running in its own + isolated OS process (`tools/run-tests.py` runs one test per process/fork); + only flag static, global, or `v8_flags` state issues in those suites if they + cause a bug within a single test execution. +- Send ONLY a JSON array (`[]` if clean): + `[{"file": "src/...", "line": 123, "type": "security|bug|design|question|nit", "comment": "Issue, impact, and suggested fix.", "suggestion": "..."}]` + +## Step 3: Filter, Merge & Format (Main Agent) + +1. **Verify**: Check every candidate comment against the source files; drop + false positives, speculative issues without a concrete mechanism, and + comments on unmodified lines (unless flagging a newly exposed bug or missed + variant anchored to the diff). +2. **Commit Message** (if reviewing a commit/CL): Verify factual accuracy + against the diff. Check `[subsystem] Imperative subject` (\<= 64 chars, + aiming for ~50, no period), concise body (\<= 10 lines, wrapped at \<= 72 + chars, explaining *why* and high-level *what*), CL references as + `https://crrev.com/c/<number>` (not git hashes), and trailers (`Bug: <id>` or + `Fixed: <id>` with plain numeric ID for Chromium or `b:<id>` for Buganizer, + never `BUG=`; plus `TAG=agy` and `R=<reviewer>@chromium.org` for + agent-authored CLs). +3. **Deduplicate**: Merge overlapping comments on the same `file:line` (within 2 + lines) or the same root cause repeated across architectures/files. Keep \<= + 25 comments ordered by `security` > `bug` > `design` > `question` > `nit`. +4. **Output**: + - **Executive Summary**: Subsystems, Size, Risk, Key Findings (including + verified pure code moves/refactorings), and Recommended File Review Order. + - **Commit Message Review**: Current message, factual accuracy, and + formatting/trailer check (omit if reviewing an uncommitted diff). + - **Inline Comments**: Grouped by `Must Fix` (security & bugs), + `Questions & Design`, and `Nits`, with clickable `file://` links + (`[path:line](file:///abs/path#L123)`) and concrete code/diff suggestions. diff --git a/deps/v8/agents/skills/v8-security-triaging/SKILL.md b/deps/v8/agents/skills/v8-security-triaging/SKILL.md index 0144f72d27cf..bd582084baf4 100644 --- a/deps/v8/agents/skills/v8-security-triaging/SKILL.md +++ b/deps/v8/agents/skills/v8-security-triaging/SKILL.md @@ -60,7 +60,7 @@ security vulnerability report. restricted attachments. - **ClusterFuzz Check**: Check the issue's comments for indications that the crash has already been uploaded to ClusterFuzz. If not uploaded, provide the - user with manual upload instructions in Step 5. + user with manual upload instructions in Step 5 using the `clusterfuzz` skill. - **Exhaustive Verification**: Never classify a bug based solely on the report. Exhaustive technical verification via `v8-poc-classification` is mandatory. - **Artifact Preservation**: Before removing a worktree or cleaning up a @@ -82,8 +82,9 @@ security vulnerability report. When executing a triage task, delegate tactical steps to subagents: -- **Researcher**: Fetching report details, identifying experts - (`find_experts_for_file`), and locating Buganizer components. +- **Researcher**: Fetching report details, searching for duplicate issues, + identifying experts (`find_experts_for_file`), and locating Buganizer + components. - **Builder**: Setting up the environment (`git checkout`) and building specific variants (Release, ASan, non-ASan). - **Tester**: Baseline reproduction across multiple configurations and security @@ -110,32 +111,55 @@ Buganizer. - **Orchestrator Instruction**: "Retrieve the `INVOKER_INFO_SESSION_ID` from the environment. Invoke the Researcher to render Buganizer issue `<id>`, extract - the POC and d8 flags, find top experts for affected files, and identify the - correct component. Instruct the subagent to return only a concise technical - summary." + the POC and d8 flags, search for duplicate or related issues, find top experts + for affected files, and identify the correct component. Instruct the subagent + to return only a concise technical summary." - **Conversation ID Persistence**: The Orchestrator MUST store the `INVOKER_INFO_SESSION_ID` in its current context immediately to ensure the mandatory first sentence in Phase 5 uses the correct, verified ID. - **Extraction**: The summary must include the POC script, required `d8` flags, - the reporter's environment (commit hash/version), and the identified - **introduction commit (regression range)**. + the reporter's environment (commit hash/version), the issue's current + `Priority`, `Severity`, `ReleaseBlock` custom field (`1223086`), and attached + hotlists (specifically any `Security_Impact-*` hotlists), as well as the + identified **introduction commit (regression range)**. - **Version and Commit Identification**: Always retrieve the current V8 version - number from `src/utils/version.h` and the specific git hash using - `git rev-parse HEAD`. Prioritize referencing specific git hashes over generic - terms like "HEAD" in triage reports. For any commit referenced in the report, - retrieve its Gerrit changelist link (from `Reviewed-on:` in - `git log -n 1 --format=%b <hash>`). + number from `include/v8-version.h` and the revision number from + `Cr-Commit-Position` + (`git log -n 1 --format="%(trailers:key=Cr-Commit-Position)" HEAD`). + Distinguish between commits referenced for their **change** vs. their + **version**: + - When the **change** is important (e.g., an introduction/regression commit or + a fixing commit), include the commit title and link to its Gerrit changelist + (from `Reviewed-on:` in `git log -n 1 --format=%b <hash>`). + - When only the **version** is important (e.g., the version used for a local + build or the reporter's tested version), include both the V8 version and the + `Cr-Commit-Position` revision number, skipping the git hash and with **no + link to Gerrit**. - **Attachment Check**: Ensure the subagent checks for mentioned files (e.g., "poc.html", "crash.log") that are NOT in the attachments list. If retrieval of an attachment via MCP tools fails, the subagent **MUST** use the `buganizer-cli` (`issues download-attachment`) as a fallback. - **Stop Condition**: If both MCP and CLI retrieval attempts for critical attachments (POC, flags, etc.) fail or if they are redacted/inaccessible, the - Orchestrator **MUST** stop immediately and ask the user to provide them - manually before proceeding to Phase 2. This includes asking for the **exact - command line** if a ClusterFuzz report link is inaccessible. + Orchestrator **MUST** attempt retrieval via the `clusterfuzz` skill (using + `fetch_testcase.py`) for ClusterFuzz links before stopping and asking the user + to provide them manually. This includes asking for the **exact command line** + if a ClusterFuzz report link remains inaccessible. - **Mapping**: Include identified experts and the specific Buganizer component (e.g., `Blink > JavaScript > Maglev`). +- **Duplicate Check**: Search Buganizer across both open and closed issues (via + `issues readonly search` using the crash state, assertion expression, and + affected file or function name, plus `lookup_similar_issues` and + `lookup-recommendations`) for existing reports of the same root cause. Record + any matching issue IDs, their current status, assignee, and prior triage + decisions: + - If an **open** canonical issue already has a working minimal reproducer and + triage decision, surface it to the user and ask whether to fast-path + directly to deduplication. + - If a matching ClusterFuzz issue was **auto-closed** (`VERIFIED` or + `NOT_REPRODUCIBLE`) when an older testcase stopped reproducing, proceed with + reproduction and minimization so the canonical issue can be reopened with a + clean reproducer. ### 2. Phase: Exhaustive Reproduction (Delegation) @@ -146,8 +170,9 @@ the issue. You MUST confirm the bug exists before proceeding. revision. - **Escalation**: If initial attempt fails, task **Builder** and **Tester** to verify across Release, Debug, and ASan variants at HEAD. -- **Healing (Initial)**: If still failing, task **Generalist** to analyze and - "heal" the POC for environmental dependencies. +- **Healing (Initial)**: If still failing (or if the POC is a browser/HTML + reproducer like `poc.html`), task **Generalist** to analyze and "heal" the POC + for `d8` and environmental dependencies following `v8-poc-classification`. - **Summary**: Review the subagent's reproduction command and result. Stop if reproduction fails after exhaustive attempts. @@ -175,11 +200,11 @@ of impact. - **ClusterFuzz Compatibility (Crash Escalation)**: Because ClusterFuzz requires a detectable crash (DCHECK, segfault, SIGILL, or int3), you **MUST** exhaustively pursue a crashing reproducer if the initial POC only proves - silent memory corruption. Task **Builder** and **Tester** to run the POC - against **Debug**, **ASan**, and **UBSan** builds. If no crash occurs - naturally, task **Generalist** to modify the POC to force a crash (e.g., by - overwriting a Map with a garbage pointer) while maintaining the original bug - trigger. + silent memory corruption, following the guidelines in the `clusterfuzz` skill. + Task **Builder** and **Tester** to run the POC against **Debug**, **ASan**, + and **UBSan** builds. If no crash occurs naturally, task **Generalist** to + modify the POC to force a crash (e.g., by overwriting a Map with a garbage + pointer) while maintaining the original bug trigger. - **Verification**: Task **Tester** to verify on Standard Release and ASan builds. - **Minimization**: Task **Generalist** to reduce the POC and flags to the @@ -192,12 +217,19 @@ of impact. ### 5. Phase: Drafting Findings -Draft a concise synthesis based on verified subagent findings. +Draft a short, precise synthesis based on verified subagent findings. +- **Strict Brevity Mandate**: Keep the entire report compact and to the point + (~20–30 lines total). Avoid filler prose, redundant explanations across + bullets, full `args.gn` dumps, or untrimmed stack traces. Never include local + workstation paths (e.g., `/usr/local/google/home/...` or `file:///`) in the + Buganizer comment text; use only the POC filename (e.g., `poc.js`) in the + `Reproduction` line and keep local paths strictly in the `(User Only)` + section. - **Mandatory First Sentence**: "This analysis is AI-generated using the `v8-security-triaging` skill (Conversation ID: `<id>`)." You **MUST** retrieve - the `<id>` from the `INVOKER_INFO_SESSION_ID` environment variable. The - variable must always be present. + the `<id>` from the Orchestrator's `INVOKER_INFO_SESSION_ID` environment + variable. - **Formatting Requirement**: Use a **bulleted list** format for the main points (Status, Classification, Rationale, etc.) and ensure there are **double line breaks** between each list item for optimal rendering in Buganizer. If a list @@ -205,51 +237,65 @@ Draft a concise synthesis based on verified subagent findings. **MUST** be indented by **at least four spaces** and **MUST NOT** be separated by double line breaks within the same nested list. - **Content**: - - **Classification**: Vulnerability / Bug / Not a Bug (Intended Behavior) / - Failed to Reproduce. **MANDATORY**: Only classify as "Vulnerability" if - local reproduction was successful. If reproduction fails, classify as - "Failed to Reproduce". - - - **Security Impact**: Classify as "**None**" (experimental, disabled) or - "**Yes**" (shipping, web-exploitable) with a mandatory technical rationale; - omit specific channel labels (e.g., `Security_Impact-Stable`) as they are - auto-derived from `FoundIn`. Skip or simplify the CVSS vector unless - requested. - - - **Proposed Severity**: Provide the proposed severity (e.g., `S1`) based on - [triaging.md](../../../docs/security/triaging.md) and Chromium guidelines. - - - **Introduced In / Regression Range**: Provide the commit or version where - the vulnerability was introduced, if identifiable. Always include a - clickable markdown link to the commit's Gerrit changelist (e.g. - `[commit <hash>](https://chromium-review.googlesource.com/c/v8/v8/+/<cl>)`). - - - **Rationale**: Explain the technical conclusion. For sandbox bypasses, - explicitly state if it violates the threat model. - - - **Local Reproduction Findings**: Follow the structure and mandatory fields - defined in the **Classification Guidelines** of `v8-poc-classification`. - Ensure all technical data (Status, Reproduction command, Result, Build - (including version from `src/utils/version.h` and git hash with a Gerrit - link), Verified Impact, and optional GDB Backtrace) is included here. - - - **Proposed Owner**: Based on expert discovery. Include a very short (half - sentence) explanation for the choice (e.g., "author of affected code", - "primary maintainer of subsystem"). - - - **Proposed Component**: Propose the most specific Buganizer component - possible (e.g., `Parser`, `Maglev`, `Turbofan`) if the current component is - the top-level V8 engine component or is otherwise incorrect. Include the - component path and ID. - - - **Proposed Title**: If the current title is generic, propose a more - descriptive title. + - **Classification** (1 line): `Vulnerability` / `Bug` / + `Not a Bug (Intended Behavior)` / `Failed to Reproduce` (append + `(Duplicate of issue <id>)` if a canonical duplicate was identified). + **MANDATORY**: Only classify as "Vulnerability" if local reproduction was + successful. + + - **Security Impact** (1 line): Classify as "**None**" (experimental, + disabled, or V8 Sandbox bypass with `Security_Impact-None` and `v8-sandbox` + hotlist) or "**Yes**" (shipping, web-exploitable) with a brief parenthetical + rationale; omit specific channel labels (e.g., `Security_Impact-Stable`). + + - **Proposed Severity** (1 line): Provide the severity (e.g., `S1` or `S2`) + and proposed priority (if it needs adjustment) based on + [triaging.md](../../../docs/security/triaging.md), where priority is at + least the severity for active vulnerabilities, can be lower than severity + for `Security_Impact-None` (e.g., `S1` -> `P2`), and should be lowered + (e.g., `P2` or `P3`) when downgrading to a non-security `Bug`. + + - **Introduced In** (1 line): Commit and version where the bug was introduced + (and fixed, if already fixed), including the commit title and a clickable + Gerrit link (e.g., + `[commit <hash>](https://chromium-review.googlesource.com/c/v8/v8/+/<cl>) ("<title>", V8 <version>)`). + + - **Rationale** (2–4 concise sentences max): State the root cause and why it + violates (or does not violate) the security threat model. Do not repeat + reproduction outputs or register values covered in + `Local Reproduction Findings`. + + - **Local Reproduction Findings** (1 concise line per sub-bullet, except + `GDB Backtrace` if multiple lines help): Follow the mandatory fields in + `v8-poc-classification`: + + - `Status`: `Reproduced` / `Not Reproduced`. + - `Reproduction`: `d8 <flags> <poc_filename.js>` (filename only, no local + paths). + - `Result`: 1–2 short sentences summarizing the observed crash/output. + - `Build`: Build variant(s), V8 version (from `include/v8-version.h`), and + revision number (from `Cr-Commit-Position`), skipping the git hash and + Gerrit link (omit boilerplate GN args). + - `Verified Impact`: 1 sentence stating the verified primitive and attacker + control. + - `GDB Backtrace`: A concise snippet of the faulting instruction/registers + and relevant stack frames (can span multiple lines if helpful; trim + unrelated frames). + + - **Proposed Owner** (1 line): `<email>` with a short phrase explaining why + (e.g., "author of introducing commit and JSPI maintainer"). + + - **Proposed Component** (1 line): Short component path and ID (e.g., + `Blink > JavaScript > WebAssembly` (ID: `1456332`, already set)). + + - **Proposed Title** (1 line): New descriptive title, or + `Keep current (<title>)` if already accurate. - **ClusterFuzz Upload Info (User Only)**: If a real crash or memory - corruption is confirmed and it has NOT yet been uploaded to ClusterFuzz, - provide all necessary details for a manual upload (repro file, job name, - issue ID, and flags) to the user. Explicitly advise the user to perform the - upload. + corruption is confirmed and not yet on ClusterFuzz, assemble the upload + package (local repro file path, job name, issue ID, target revision, and + flags) using the `clusterfuzz` skill for manual upload. Omit this section + when posting the comment to Buganizer. ### 6. Phase: Verification & Self-Correction (Audit) @@ -258,9 +304,9 @@ the draft. - **Orchestrator Instruction**: "Audit the attached triage draft against `docs/security/triaging.md` and the Technical Quality Checklist. Ensure the - classification is technically sound and the formatting is correct. If errors - are found, distinguish between text-only corrections and missing technical - work." + classification is technically sound, the report is concise, and the formatting + is correct. If errors are found, distinguish between text-only corrections and + missing technical work." - **Loop-back Mandate**: If the Auditor identifies missing technical evidence (e.g., skipped boundary checks, missing GDB analysis, or unverified impact on Release builds), the Orchestrator **MUST** return to the relevant previous @@ -270,16 +316,47 @@ the draft. - The classification (Vulnerability vs. Bug) is consistent with the reproduction results (e.g., if it needs experimental flags, it's a Bug). - The "Local Reproduction Findings" section contains the exact d8 command, V8 - version, git hash, and the observed result. + version and revision number (skipping the git hash and Gerrit link), and the + observed result. + - Commits where the *change* is important include both the commit title and a + Gerrit link, whereas references where only the *version* is important + include both the V8 version and revision number, skipping the git hash and + Gerrit link. + - **Brevity & Cleanliness**: The report follows the line/sentence budgets + (1-line metadata fields, 2–4 sentence Rationale, concise 1-line sub-bullets + in Local Reproduction Findings except GDB Backtrace when multi-line helps, + and no local `/usr/local/...` paths outside the `User Only` section). - The formatting (double line breaks between top-level list items AND four-space indented sub-bullets for findings without internal double line breaks) is strictly followed. - - The conversation ID is correct and matches the `INVOKER_INFO_SESSION_ID` - environment variable. The auditor MUST run - `env | grep INVOKER_INFO_SESSION_ID` to verify this independently. + - The conversation ID matches the Orchestrator's `INVOKER_INFO_SESSION_ID` + (passed by the Orchestrator to the Auditor, as subagents have their own + session IDs). - **Action**: Present the *audited and verified* analysis to the user for - approval ONLY after all technical gaps identified by the auditor have been - addressed. + approval ONLY after all technical or formatting gaps identified by the auditor + have been addressed. +- **Applying Approved Buganizer Updates**: Once the user approves updating + Buganizer metadata: + - **Hotlist Cleanup**: When adding `Security_Impact-None` (`5433277`) via + `add_issue_to_hotlist`, you **MUST** also remove any existing + release-channel `Security_Impact-*` hotlists from the issue via + `remove_issue_from_hotlist`: `Security_Impact-Head` (`5432216`), + `Security_Impact-Beta` (`5433097`), `Security_Impact-Stable` (`5432902`), + and `Security_Impact-Extended` (`5432548`). When applicable, also add + `v8-sandbox` (`4802478`) or `v8-unsupported-chrome` (`8384111`). + - **Priority & ReleaseBlock Adjustment**: When lowering `Severity` or + downgrading an issue (e.g., to `Type=Bug` or `Security_Impact-None`), you + **MUST** check that `Priority` still makes sense and lower it accordingly + via `update_issue_priority` (e.g., `P2` or `P3` for downgraded bugs or + `Security_Impact-None` issues), and clear any `ReleaseBlock` values on + custom field `1223086` (`set_issue_custom_field` with + `customFieldId: "1223086"` and `customFieldValue: ""`) so release automation + does not re-promote the issue. + - **Deduplication**: When the user approves deduplicating into an existing + canonical issue, mark the duplicate issue(s) via `mark_issue_as_duplicate` + (`issues mutate update duplicate --issue_id <dup_id> --target_id <canonical_id>`). + If the canonical issue was prematurely auto-closed (e.g., by ClusterFuzz), + reopen it to `ASSIGNED` and attach the minimized POC. ### 7. Phase: Cleanup & Preservation @@ -296,15 +373,23 @@ Finalize the session by securing artifacts and cleaning up the environment. ## Technical Quality Checklist +- [ ] **Duplicate Check**: Did the Researcher search Buganizer (open and closed + issues) for existing reports with the same crash signature or root cause? - [ ] **Classification Accuracy**: Does the result match the criteria in `docs/security/triaging.md`? (e.g., `nullptr` is a Bug, safe termination is Intended Behavior). - [ ] **Boundary Verification**: Was the POC tested with the security filter flag (`--run-as-[sandbox]-security-poc`)? -- [ ] **Mandatory Data**: Are the V8 version and git hash included in the Build - description? -- [ ] **Gerrit Links**: Are all referenced commits and CLs (introduction CL, - build commit, etc.) linked to their corresponding Gerrit changelists? +- [ ] **Mandatory Data**: Are both the V8 version and revision number (without + git hash or Gerrit link) included in the Build description? +- [ ] **Commit vs. Version Linking**: Do commits where the *change* is important + (e.g., introduction or fix CLs) include their commit title and Gerrit link, + while references where only the *version* is important include both the V8 + version and revision number, skipping the git hash and Gerrit link? +- [ ] **Brevity & No Local Paths**: Is the Rationale \<= 4 sentences, are all + other bullets/sub-bullets 1 line each (except `GDB Backtrace` if multiple + lines help), and are local `/usr/local/...` paths excluded from the Buganizer + comment text? - [ ] **Formatting**: Are there double line breaks between all top-level bulleted list items? Are sub-bullets indented by at least four spaces without internal double line breaks? diff --git a/deps/v8/agents/skills/v8-testing/SKILL.md b/deps/v8/agents/skills/v8-testing/SKILL.md index 2f740af6035f..74e2a0653446 100644 --- a/deps/v8/agents/skills/v8-testing/SKILL.md +++ b/deps/v8/agents/skills/v8-testing/SKILL.md @@ -15,11 +15,15 @@ build output directory and the tests you want to run. ## Key Test Suites -- **unittests**: C++ unit tests for V8's internal components. +- **unittests**: C++ unit tests (`v8_unittests`, GoogleTest) for V8's internal + components. `tools/run-tests.py` executes each test (`TEST`, `TEST_F`, + `TEST_P`) in its own isolated process (via `--fork-server` on POSIX or a fresh + subprocess with `--gtest_filter=<Suite.Test>`). - **cctest**: Another, older format for C++ unit tests (deprecated, in the - process of being moved to unittests). + process of being moved to unittests). Each `TEST` / `UNINITIALIZED_TEST` runs + in its own `cctest` process (`cctest` rejects multiple test arguments). - **mjsunit**: JavaScript-based tests for JavaScript language features and - builtins. + builtins. Each `.js` file runs in a fresh `d8` process. ## Running Tests @@ -33,6 +37,15 @@ tools/run-tests.py --progress dots --exit-after-n-failures=5 --outdir=out/x64.op # Run a specific test file tools/run-tests.py --progress dots --exit-after-n-failures=5 --outdir=out/x64.optdebug cctest/test-heap +# Run unittests matching a glob via the test runner (preserves per-test process isolation) +tools/run-tests.py --progress dots --exit-after-n-failures=5 --outdir=out/x64.optdebug 'unittests/Torque*' + +# Direct binary execution (for debugging a single test, e.g. under gdb) +# Always pass a single test to preserve process isolation; use tools/run-tests.py +# when running multiple tests or wildcards. +out/x64.optdebug/cctest test-heap/HeapObjects +out/x64.optdebug/v8_unittests --gtest_filter=TorqueTest.Scanner + # Manual execution with d8 # Note: mjsunit tests always require test/mjsunit/mjsunit.js. # tools/run-tests.py prepends this automatically for all tests in mjsunit, diff --git a/deps/v8/agents/skills/v8-turboshaft/SKILL.md b/deps/v8/agents/skills/v8-turboshaft/SKILL.md new file mode 100644 index 000000000000..eefb19060cba --- /dev/null +++ b/deps/v8/agents/skills/v8-turboshaft/SKILL.md @@ -0,0 +1,73 @@ +--- +name: v8-turboshaft +description: Turboshaft C++ coding conventions. Use when writing, modifying, or reviewing code in src/compiler/turboshaft/. +--- + +# Turboshaft Coding Conventions + +- Prefer `V<T>` and `OptionalV<T>` over raw `OpIndex` and `OptionalOpIndex` + (e.g., `V<Word32>`, `V<JSReceiver>`, `V<Any>`, `V<None>`). Use + `V<T>::Invalid()` instead of `OpIndex::Invalid()`. + +- Use the most precise `V<T>` type possible (e.g., `V<JSArray>` over + `V<JSReceiver>` over `V<Object>`). Define new union types when needed: + `Union<...>` for tagged types and `UntaggedUnion<...>` for untagged types. + +- Use `V<T>::Cast` only when downcasting another `V<U>`. Never use `V<T>::Cast` + on `OpIndex` or for upcasting (`V<T>` is implicitly constructible from + `OpIndex` and from `V<SubType>`). For calls, use `__ Call<T>(...)` instead of + `V<T>::Cast(__ Call(...))`. + +- Prefer structured control flow (`IF` / `IF_NOT` / `ELSE`, using `ScopedVar<T>` + to merge values across branches) over `Label<T>` with `GOTO` / `GOTO_IF` / + `GOTO_IF_NOT` when possible. + +- With `ScopedVar<T>`, use direct assignment (`var = ...`) and implicit reads + instead of `.Set()` / `.Get()`. + +- Avoid explicit `__ Word32Constant(...)` / `__ Float64Constant(...)` calls: + most functions taking untagged value inputs use `ConstOrV<T>` parameters (and + new helpers should too), which accept raw C++ constants directly. + +- When matching operations, prefer a single `op.TryCast<Op>()` (with + `Opmask::k...` when checking `Kind`/operands) over `op.Is<Op>()` + + `op.Cast<Op>()`. + +- Use named, typed input getters on operations (e.g., `op.left()`, `op.input()`) + instead of generic indexed `op.input(0)` (and define them on new operations in + `operations.h`). + +- Prefer `BuiltinCallDescriptor` with `__ CallBuiltin<builtin::Foo>(...)` over + manual `Call` descriptors. + +- In `REDUCE` methods, use early returns or + `LABEL_BLOCK(no_change) { return Next::Reduce...(...); }` with + `goto no_change;` to avoid deep nesting or repeated `Next::Reduce...` calls. + +- Only prefix Assembler/reducer-stack calls with `__`; call private helper + methods on the current reducer directly (without `__`). + +- When defining operations in `operations.h`, inherit from + `FixedArityOperationT<N, Op>` if possible, rely on its default + `options()`-based `operator==`/`hash_value`/`PrintOptions`, omit empty + `Validate()` methods, and expose typed helpers in `assembler.h` rather than + calling `ReduceIfReachable*` directly. + +- Operations that can throw JS exceptions must be added to + `TURBOSHAFT_JS_THROWING_OPERATION_LIST` with `THROWING_OP_BOILERPLATE`, and + wrapped in a `ThrowingScope` when emitted in `GraphBuilder` / + `TurbolevGraphBuilder`. + +- To minimize binary size and compile time, reuse existing phases + (`CopyingPhase<...>`) rather than introducing new phases when possible, and + avoid branching at runtime between two `CopyingPhase` instantiations with + different reducer lists (include the reducer unconditionally and check flags + inside it). + +- Optimization reducers should check `ShouldSkipOptimizationStep()` (at least at + the beginning of `REDUCE` / `REDUCE_INPUT_GRAPH` methods) before performing + non-mandatory transformations. + +- For every branch, consider whether it is checking something that can actually + happen or whether compiler invariants prevent the condition from being true + (or false), in which case it should be a `DCHECK` instead. diff --git a/deps/v8/agents/skills/v8-workflow/SKILL.md b/deps/v8/agents/skills/v8-workflow/SKILL.md index 7b20b892daf9..04f9ade278dc 100644 --- a/deps/v8/agents/skills/v8-workflow/SKILL.md +++ b/deps/v8/agents/skills/v8-workflow/SKILL.md @@ -13,8 +13,9 @@ development environment in V8. Before starting any feature or bug fix, you MUST decide on a strategy: - **Isolated Strategy (Recommended)**: Create a dedicated git worktree and - branch. This prevents cross-contamination between tasks. Use - `create_worktree.sh`. + branch (`task-<id>`) to prevent cross-contamination between tasks. Run + `agents/scripts/create_worktree.sh <id> [base_branch]` and use the worktree + path printed to stdout (`worktrees/task-<id>`). - **Reuse Strategy**: Work in the current directory and branch. @@ -56,3 +57,14 @@ development: - **[cleanup_worktree.sh](../../scripts/cleanup_worktree.sh)**: Safely removes task workspaces (Git worktrees or Rift subvolumes) and prunes remnants once a CL is landed or abandoned. +- **[setup_worktree_build.py](../../../tools/dev/setup_worktree_build.py)**: + Sets up shared `gclient` dependency symlinks in a worktree (invoked + automatically by `create_worktree.sh` and `gm.py`). When a worktree's `DEPS` + differs from the main repository, it caches a synced dependency tree under + `<main_repo>/worktrees/.deps_cache/<hash>` and automatically prunes old + unreferenced entries (keeping at least the 3 most recent). + - `tools/dev/setup_worktree_build.py prune-cache <main_repo>`: Manually prune + unreferenced `.deps_cache` entries (keeping all referenced entries and the 3 + most recently used). + - `tools/dev/setup_worktree_build.py clear-cache <main_repo>`: Remove all + entries in `<main_repo>/worktrees/.deps_cache`. diff --git a/deps/v8/agents/skills/workflow-debugging/SKILL.md b/deps/v8/agents/skills/workflow-debugging/SKILL.md index f91754a6f592..3b2f5550c8f2 100644 --- a/deps/v8/agents/skills/workflow-debugging/SKILL.md +++ b/deps/v8/agents/skills/workflow-debugging/SKILL.md @@ -126,14 +126,15 @@ Once the fix is approved by the user: - **Issue Association in Commits**: - The commit message must follow the V8 convention. - - It MUST include a `Bug: <issue_id>` line at the bottom. + - When a CL fixes a bug, it MUST include a `Fixed: <issue_id>` line at the + bottom (rather than `Bug: <issue_id>`). - Example Commit Message: ``` [compiler] Fix crash in Turboshaft during loop unrolling The loop unroller failed to handle cases where... - Bug: 12345 + Fixed: 12345 ``` - **Test Naming and Placement**: diff --git a/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md b/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md index db0d24017a4b..0e7f39c3f0e6 100644 --- a/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md +++ b/deps/v8/agents/skills/workflow-gerrit-fix/SKILL.md @@ -58,9 +58,11 @@ Gerrit Change List (CL). - **Local Build/Test**: Instruct the subagent to verify that the fix compiles locally and the reproduced failure is now resolved. -- **Upload**: Once verified locally, upload a new patchset using - `agents/scripts/upload_cl.sh cur check "<what you changed>"` to Gerrit to run - the remote checks or ask for re-review. +- **Upload**: Once verified locally, follow `agents/rules/git-cl.md` and the + `git-cl-helper` skill to upload the new patchset + (`SKIP_GCE_AUTH_FOR_GIT=1 GIT_EDITOR=true git cl upload -t "<what you changed>"`), + preserving the CL's current WIP or Ready-for-Review status on Gerrit. Only + mark a WIP CL Ready for Review when the user explicitly asks to do so. ## Example: Fixing Errors diff --git a/deps/v8/agents/skills/workflow-perf/scripts/upload_and_pinpoint.py b/deps/v8/agents/skills/workflow-perf/scripts/upload_and_pinpoint.py index 3bc796cb883b..0c96db6f0ed2 100755 --- a/deps/v8/agents/skills/workflow-perf/scripts/upload_and_pinpoint.py +++ b/deps/v8/agents/skills/workflow-perf/scripts/upload_and_pinpoint.py @@ -5,17 +5,21 @@ from __future__ import annotations import argparse -import subprocess +import os +from pathlib import Path import re -import sys import shlex -from pathlib import Path +import subprocess +import sys def run_command(cmd: list[str], cwd: str | None = None) -> str: print(f"Running: {shlex.join(cmd)}") + env = os.environ.copy() + env["SKIP_GCE_AUTH_FOR_GIT"] = "1" + env["GIT_EDITOR"] = "true" result = subprocess.run( - cmd, cwd=cwd, capture_output=True, text=True, check=False) + cmd, cwd=cwd, env=env, capture_output=True, text=True, check=False) if result.returncode != 0: print(f"Error running command: {result.stderr}") print(f"Stdout: {result.stdout}") @@ -45,7 +49,11 @@ def main() -> None: # 1. Upload CL # Assumes changes are already committed on the current branch. - upload_cmd = ["./agents/scripts/upload_cl.sh", "cur", "nocheck", args.message] + issue_out = run_command(["git", "cl", "issue"], cwd=args.v8_dir) + if "None" in issue_out: + upload_cmd = ["git", "cl", "upload", "-T", "-o", "wip"] + else: + upload_cmd = ["git", "cl", "upload", "-t", args.message] stdout = run_command(upload_cmd, cwd=args.v8_dir) print(stdout) diff --git a/deps/v8/bazel/defs.bzl b/deps/v8/bazel/defs.bzl index 68f283bcfc3c..3b9fc02feb41 100644 --- a/deps/v8/bazel/defs.bzl +++ b/deps/v8/bazel/defs.bzl @@ -57,6 +57,8 @@ def _custom_config_impl(ctx): defs = [] defs.append("V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=" + str(ctx.attr._v8_typed_array_max_size_in_heap[FlagInfo].value)) + defs.append("V8_EMBEDDER_DATA_ARRAY_SIZE=" + + str(ctx.attr._v8_embedder_data_array_size[FlagInfo].value)) context = cc_common.create_compilation_context(defines = depset(defs)) return [CcInfo(compilation_context = context)] @@ -64,6 +66,7 @@ v8_custom_config = rule( implementation = _custom_config_impl, attrs = { "_v8_typed_array_max_size_in_heap": attr.label(default = ":v8_typed_array_max_size_in_heap"), + "_v8_embedder_data_array_size": attr.label(default = ":v8_embedder_data_array_size"), }, ) @@ -130,6 +133,7 @@ def _default_args(): "-Wno-bitwise-instead-of-logical", "-Wno-builtin-assume-aligned-alignment", "-Wno-unused-parameter", + "-Wno-unused-variable", "-Wno-implicit-int-float-conversion", "-Wno-deprecated-copy", "-Wno-non-virtual-dtor", @@ -330,104 +334,6 @@ def v8_library( **kwargs ) -# Use a single generator target for torque definitions and initializers. We can -# split the set of outputs by using OutputGroupInfo, that way we do not need to -# run the torque generator twice. -def _torque_files_impl(ctx): - # Allow building V8 as a dependency: workspace_root points to external/v8 - # when building V8 from a different repository and empty otherwise. - v8root = ctx.label.workspace_root - if v8root == "": - v8root = "." - - # Arguments - args = [] - args += ctx.attr.args - args.append("-o") - args.append(ctx.bin_dir.path + "/" + v8root + "/" + ctx.attr.prefix + "/torque-generated") - args.append("-strip-v8-root") - args.append("-v8-root") - args.append(v8root) - - # Sources - args += [f.path for f in ctx.files.srcs] - - # Generate/declare output files - defs = [] - inits = [] - for src in ctx.files.srcs: - root, _period, _ext = src.path.rpartition(".") - - # Strip v8root - if root[:len(v8root)] == v8root: - root = root[len(v8root):] - file = ctx.attr.prefix + "/torque-generated/" + root - defs.append(ctx.actions.declare_file(file + "-tq.cc")) - inits.append(ctx.actions.declare_file(file + "-tq-csa.cc")) - inits.append(ctx.actions.declare_file(file + "-tq-csa.h")) - - defs += [ctx.actions.declare_file(ctx.attr.prefix + "/torque-generated/" + f) for f in ctx.attr.definition_extras] - inits += [ctx.actions.declare_file(ctx.attr.prefix + "/torque-generated/" + f) for f in ctx.attr.initializer_extras] - outs = defs + inits - ctx.actions.run( - outputs = outs, - inputs = ctx.files.srcs, - arguments = args, - executable = ctx.executable.tool, - mnemonic = "GenTorqueFiles", - progress_message = "Generating Torque files", - ) - return [ - DefaultInfo(files = depset(outs)), - OutputGroupInfo( - initializers = depset(inits), - definitions = depset(defs), - ), - ] - -_v8_torque_files = rule( - implementation = _torque_files_impl, - # cfg = v8_target_cpu_transition, - attrs = { - "prefix": attr.string(mandatory = True), - "srcs": attr.label_list(allow_files = True, mandatory = True), - "definition_extras": attr.string_list(), - "initializer_extras": attr.string_list(), - "tool": attr.label( - allow_files = True, - executable = True, - cfg = "exec", - ), - "args": attr.string_list(), - }, -) - -def v8_torque_files(name, noicu_srcs, icu_srcs, args, definition_extras, initializer_extras): - _v8_torque_files( - name = "noicu/" + name, - prefix = "noicu", - srcs = noicu_srcs, - args = args, - definition_extras = definition_extras, - initializer_extras = initializer_extras, - tool = select({ - "@v8//bazel/config:v8_target_is_32_bits": ":noicu/torque_non_pointer_compression", - "//conditions:default": ":noicu/torque", - }), - ) - _v8_torque_files( - name = "icu/" + name, - prefix = "icu", - srcs = icu_srcs, - args = args, - definition_extras = definition_extras, - initializer_extras = initializer_extras, - tool = select({ - "@v8//bazel/config:v8_target_is_32_bits": ":icu/torque_non_pointer_compression", - "//conditions:default": ":icu/torque", - }), - ) - def _v8_target_cpu_transition_impl(settings, attr, # @unused ): @@ -608,6 +514,7 @@ def build_config_content(cpu, icu): ("slow_dchecks", "false"), ("target_cpu", cpu), ("temporal", "false"), + ("ecma402_icu4x", "false"), ("tsan", "false"), ("ubsan", "false"), ("use_sanitizer", "false"), @@ -623,11 +530,11 @@ def build_config_content(cpu, icu): ]) # ============================================================================= -# Metagen: libclang-driven instance-type generator. +# Metagen: libclang-driven metadata generator. # -# Produces gen/metagen/instance-types.h, the file `src/objects/instance-types- -# gen.h` includes when V8_USE_METAGEN_INSTANCE_TYPES=1, i.e. under -# --//:v8_use_metagen_instance_types. +# Produces gen/metagen/instance-types.h -- the file `src/objects/instance- +# types-gen.h` includes when V8_USE_METAGEN=1, i.e. under +# --//:v8_use_metagen -- along with layouts.json for Torque. # # The generator runs tools/metagen/metagen.py, which uses libclang to parse # V8_OBJECT-annotated C++ headers and emits the IT enum macros. We feed it @@ -641,13 +548,12 @@ def build_config_content(cpu, icu): # Metagen-specific cflags that don't propagate via CcInfo (they're copts on # v8_library, not on the `:define_flags` we depend on). Kept tiny on # purpose -- everything else comes from the toolchain or CcInfo. -_METAGEN_USER_COPTS = [ - "-std=c++20", - "-fno-rtti", - "-fno-exceptions", -] +_METAGEN_USER_COPTS = { + "gcc": ["-std=c++20", "-fno-rtti", "-fno-exceptions"], + "cl": ["/std:c++20", "/GR-", "/EHs-c-"], +} -def _metagen_instance_types_impl(ctx): +def _run_metagen_impl(ctx): v8root = ctx.label.workspace_root if v8root == "": v8root = "." @@ -655,6 +561,11 @@ def _metagen_instance_types_impl(ctx): out_h = ctx.actions.declare_file( ctx.attr.prefix + "/metagen/instance-types.h", ) + out_layouts = ctx.actions.declare_file( + ctx.attr.prefix + "/metagen/layouts.json", + ) + # TODO(jgruber): Add a non-critical diagnostics target that requests + # --enable-layout-positions when C++ source positions are consumed. out_dir = out_h.dirname # Merge CcInfo from all cc_compilation_context_from targets -- this is @@ -671,6 +582,10 @@ def _metagen_instance_types_impl(ctx): requested_features = ctx.features, unsupported_features = ctx.disabled_features + ["module_maps"], ) + driver_mode = (ctx.attr.driver_mode_flag[FlagInfo].value or + ctx.attr.default_driver_mode) + if driver_mode not in _METAGEN_USER_COPTS: + fail("v8_metagen_driver_mode must be 'gcc' or 'cl', got %r" % driver_mode) # -I dirs for the generated headers (torque, bytecode_builtins). # None of these live in a cc_library CcInfo so they're added directly. @@ -686,7 +601,7 @@ def _metagen_instance_types_impl(ctx): feature_configuration = feature_configuration, cc_toolchain = cc_toolchain, source_file = "tools/metagen/probe.cc", - user_compile_flags = _METAGEN_USER_COPTS, + user_compile_flags = _METAGEN_USER_COPTS[driver_mode], include_directories = cc_context.includes, quote_include_directories = depset( extra_quote_includes, @@ -714,7 +629,7 @@ def _metagen_instance_types_impl(ctx): ) # Synthesize a one-entry compile_commands.json for metagen. (The GN - # side instead harvests flags via `gn desc`; this is the Bazel path.) + # side instead reads flags via `gn desc`; this is the Bazel path.) # The `directory` is the action's cwd (execroot); the bogus # `probe.cc` file + `-c`/`-o` args are filtered out by metagen. compile_db = ctx.actions.declare_file( @@ -732,11 +647,12 @@ def _metagen_instance_types_impl(ctx): args = ctx.actions.args() args.add("--v8-root", v8root) args.add("--compile-commands", compile_db.path) + args.add("--driver-mode", driver_mode) args.add("--driver", ctx.file.driver.path) args.add("--out", out_dir) # Where libclang comes from. Both modes are explicit, so a mismatch - # is an analysis-time error rather than a harvest that quietly parses + # is an analysis-time error rather than a Metagen run that quietly parses # with the wrong library. if ctx.attr.libclang_from_python_env: if ctx.files.libclang_files: @@ -757,21 +673,21 @@ def _metagen_instance_types_impl(ctx): # what the GN action passes for //third_party/llvm-libclang. args.add("--libclang-dir", v8root + "/third_party/llvm-libclang") - # Clang's builtin headers. Find the directory via stddef.h rather - # than files[0].dirname: the staged set contains subdirectories - # (sanitizer/, cuda_wrappers/, ...), so element 0 sits at the include - # root only by luck of ordering, and a dir one level too deep fails - # as a wall of parse errors rather than a build error. + # Find the include root via stddef.h; other headers may be in + # subdirectories. builtin_headers_dir = None for f in ctx.files.clang_builtin_headers: if f.basename == "stddef.h": builtin_headers_dir = f.dirname break - if builtin_headers_dir == None: - fail("clang_builtin_headers contains no stddef.h, so the clang " + - "builtin-header directory cannot be located. Pass the target " + - "that stages clang's builtin headers (lib/Headers).") - args.add("--clang-builtin-headers-dir", builtin_headers_dir) + if builtin_headers_dir == None or not builtin_headers_dir.endswith("/include"): + fail("clang_builtin_headers must contain stddef.h under " + + "<resource-dir>/include") + for f in ctx.files.clang_builtin_headers: + if not f.path.startswith(builtin_headers_dir + "/"): + fail("clang_builtin_headers must all be under " + + builtin_headers_dir + ": " + f.path) + args.add("--clang-resource-dir", builtin_headers_dir[:-len("/include")]) all_inputs = depset( direct = [compile_db, ctx.file.driver], @@ -786,17 +702,22 @@ def _metagen_instance_types_impl(ctx): ) ctx.actions.run( - outputs = [out_h], + outputs = [out_h, out_layouts], inputs = all_inputs, executable = ctx.executable.tool, arguments = [args], - mnemonic = "MetagenInstanceTypes", - progress_message = "Generating metagen/instance-types.h", + mnemonic = "RunMetagen", + progress_message = "Generating metagen metadata", ) - return [DefaultInfo(files = depset([out_h]))] + return [ + DefaultInfo(files = depset([out_h])), + OutputGroupInfo( + layouts = depset([out_layouts]), + ), + ] -# The harvest is a host tool that must reason about the target build, so +# Metagen is a host tool that must reason about the target build, so # this rule's inputs fall into two groups -- the same split GN gets from # v8_generator_toolchain (see gni/snapshot_toolchain.gni), where the # generator is a host binary compiled with the target's V8 configuration: @@ -811,19 +732,21 @@ def _metagen_instance_types_impl(ctx): # `cc_compilation_context_from`, `extra_defines`, and # `extra_sandbox_files` (V8's own source headers). # These must reflect the TARGET build -- exec- -# configuring them would harvest the host's defines, +# configuring them would use the host's defines, # which today changes nothing but would silently emit # host object layout once metagen generates layout. -_metagen_instance_types = rule( - implementation = _metagen_instance_types_impl, +_run_metagen = rule( + implementation = _run_metagen_impl, attrs = { "prefix": attr.string(mandatory = True), + "default_driver_mode": attr.string(mandatory = True), + "driver_mode_flag": attr.label(providers = [FlagInfo], mandatory = True), # The checked-in C++ driver, passed straight through as --driver. Its # direct includes are staged by extra_sandbox_files, not by this attr. "driver": attr.label(allow_single_file = True, mandatory = True), "libclang_files": attr.label_list(allow_files = True, cfg = "exec"), # Clang's builtin headers (stddef.h etc.), staged into the action - # sandbox and passed to metagen as -isystem. Separate from + # sandbox and passed to metagen as -resource-dir=. Separate from # extra_sandbox_files because this is host toolchain material: # it needs cfg = "exec", whereas V8's own headers must not have it. "clang_builtin_headers": attr.label_list( @@ -854,7 +777,7 @@ _metagen_instance_types = rule( providers = [CcInfo], mandatory = True, ), - # Additional -D defines for the harvest that do not propagate + # Additional -D defines for Metagen that do not propagate # via CcInfo (v8_library applies them as per-variant copts, # e.g. V8_INTL_SUPPORT on the icu prefix). "extra_defines": attr.string_list(), @@ -873,19 +796,19 @@ _metagen_instance_types = rule( toolchains = use_cc_toolchain(), ) -def metagen_instance_types(name, driver, - python_srcs, tool, - cc_compilation_context_from, - clang_builtin_headers, - libclang_files = [], - libclang_from_python_env = False, - extra_sandbox_files = [], - icu_extra_defines = [], - icu_cc_compilation_context_from = []): - """Emit gen/metagen/instance-types.h for both icu/ and noicu/ prefixes. +def run_metagen(name, driver, default_driver_mode, driver_mode_flag, + python_srcs, tool, + cc_compilation_context_from, + clang_builtin_headers, + libclang_files = [], + libclang_from_python_env = False, + extra_sandbox_files = [], + icu_extra_defines = [], + icu_cc_compilation_context_from = []): + """Emit metagen metadata for both icu/ and noicu/ prefixes. Mirrors the v8_torque_files double-emission pattern so each consumer - library can include the correctly-prefixed copy. The two harvests + library can include the correctly-prefixed copy. The two runs differ: v8_library compiles the icu variant with V8_INTL_SUPPORT (via copts, invisible to CcInfo) and the intl object sources, so the icu emission additionally enables the driver's i18n includes with the @@ -894,13 +817,19 @@ def metagen_instance_types(name, driver, Pass either `libclang_files` (the bundled llvm-libclang package) or `libclang_from_python_env = True` (bindings supplied through `tool`'s Python deps) -- exactly one, enforced by the rule. + + `default_driver_mode` follows the target OS. The `driver_mode_flag` + overrides it for toolchains that use a different flag syntax, such as + MinGW or clang-cl cross builds. """ for prefix in ("noicu", "icu"): is_icu = prefix == "icu" - _metagen_instance_types( + _run_metagen( name = prefix + "/" + name, prefix = prefix, driver = driver, + default_driver_mode = default_driver_mode, + driver_mode_flag = driver_mode_flag, libclang_files = libclang_files, libclang_from_python_env = libclang_from_python_env, clang_builtin_headers = clang_builtin_headers, diff --git a/deps/v8/bazel/v8-generators.bzl b/deps/v8/bazel/v8-generators.bzl new file mode 100644 index 000000000000..76a18ec27965 --- /dev/null +++ b/deps/v8/bazel/v8-generators.bzl @@ -0,0 +1,170 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Private helpers for V8 generators.""" + +visibility("private") + +# Use a single generator target for torque definitions and initializers. We can +# split the set of outputs by using OutputGroupInfo, that way we do not need to +# run the torque generator twice. +def _torque_files_impl(ctx): + # Allow building V8 as a dependency: workspace_root points to external/v8 + # when building V8 from a different repository and empty otherwise. + v8root = ctx.label.workspace_root + if v8root == "": + v8root = "." + + # Arguments + args = [] + args += ctx.attr.args + args.append("-o") + args.append(ctx.bin_dir.path + "/" + v8root + "/" + ctx.attr.prefix + "/torque-generated") + args.append("-strip-v8-root") + args.append("-v8-root") + args.append(v8root) + inputs = ctx.files.srcs + if ctx.file.layout_json: + args.append("-use-cpp-layouts") + args.append("-layout-json") + args.append(ctx.file.layout_json.path) + inputs = inputs + [ctx.file.layout_json] + + # Sources + args += [f.path for f in ctx.files.srcs] + + # Generate/declare output files + defs = [] + inits = [] + for src in ctx.files.srcs: + root, _period, _ext = src.path.rpartition(".") + + # Strip v8root + if root[:len(v8root)] == v8root: + root = root[len(v8root):] + file = ctx.attr.prefix + "/torque-generated/" + root + defs.append(ctx.actions.declare_file(file + "-tq.cc")) + inits.append(ctx.actions.declare_file(file + "-tq-csa.cc")) + inits.append(ctx.actions.declare_file(file + "-tq-csa.h")) + + defs += [ctx.actions.declare_file(ctx.attr.prefix + "/torque-generated/" + f) for f in ctx.attr.definition_extras] + inits += [ctx.actions.declare_file(ctx.attr.prefix + "/torque-generated/" + f) for f in ctx.attr.initializer_extras] + outs = defs + inits + ctx.actions.run( + outputs = outs, + inputs = inputs, + arguments = args, + executable = ctx.attr.tool[V8ToolInfo].files_to_run, + mnemonic = "GenTorqueFiles", + progress_message = "Generating Torque files", + toolchain = None, + ) + return [ + DefaultInfo(files = depset(outs)), + OutputGroupInfo( + initializers = depset(inits), + definitions = depset(defs), + ), + ] + +# Generator tools must be built for the machine that runs them while using +# the V8 settings that determine their output. These helpers apply those +# settings after Bazel chooses the execution platform, then pass the original +# executable and runfiles to the action without copying the binary. +# The tool and action use the same default execution group so the executable +# is built for the platform that runs the action. +# TODO: Remove these helpers once V8 requires a Bazel version that preserves +# scoped build settings when composing exec and V8 transitions. +V8ToolInfo = provider( + doc = "The configured executable used by a V8 generator.", + fields = { + "files_to_run": "The original binary's FilesToRunProvider, including its runfiles.", + }, +) + +def v8_tool_impl(ctx): + [binary] = ctx.attr.binary + return [V8ToolInfo(files_to_run = binary[DefaultInfo].files_to_run)] + +def _v8_torque_pointer_compression_transition_impl(_settings, attr): + return { + "//:v8_enable_pointer_compression": str(attr.pointer_compression), + } + +_v8_torque_pointer_compression_transition = transition( + implementation = _v8_torque_pointer_compression_transition_impl, + inputs = [], + outputs = ["//:v8_enable_pointer_compression"], +) + +_v8_torque_tool = rule( + implementation = v8_tool_impl, + attrs = { + "binary": attr.label( + mandatory = True, + executable = True, + cfg = _v8_torque_pointer_compression_transition, + ), + "pointer_compression": attr.bool(mandatory = True), + }, +) + +_v8_torque_files = rule( + implementation = _torque_files_impl, + attrs = { + "prefix": attr.string(mandatory = True), + "srcs": attr.label_list(allow_files = True, mandatory = True), + "definition_extras": attr.string_list(), + "initializer_extras": attr.string_list(), + "tool": attr.label( + mandatory = True, + providers = [V8ToolInfo], + cfg = "exec", + ), + "args": attr.string_list(), + "layout_json": attr.label( + allow_single_file = True, + ), + }, +) + +def v8_torque_files( + name, + noicu_srcs, + icu_srcs, + args, + definition_extras, + initializer_extras, + noicu_layout_json, + icu_layout_json): + # Torque's pointer sizes must match the V8 build that consumes its output. + # Select pointer compression before Bazel configures Torque for execution. + for prefix, srcs, layout_json in [ + ("noicu", noicu_srcs, noicu_layout_json), + ("icu", icu_srcs, icu_layout_json), + ]: + tool_name = prefix + "/" + name + "_tool_" + tools = {} + for layout, pointer_compression in [("compressed", True), ("uncompressed", False)]: + _v8_torque_tool( + name = tool_name + layout, + binary = ":" + prefix + "/torque", + pointer_compression = pointer_compression, + tags = ["manual"], + visibility = ["//visibility:private"], + ) + tools[layout] = native.package_relative_label(":" + tool_name + layout) + _v8_torque_files( + name = prefix + "/" + name, + prefix = prefix, + srcs = srcs, + args = args, + definition_extras = definition_extras, + initializer_extras = initializer_extras, + layout_json = layout_json, + tool = select({ + ":is_v8_enable_pointer_compression": tools["compressed"], + "//conditions:default": tools["uncompressed"], + }), + ) diff --git a/deps/v8/bazel/v8-non-pointer-compression.bzl b/deps/v8/bazel/v8-non-pointer-compression.bzl index 8f257bb3ef47..cc481017f645 100644 --- a/deps/v8/bazel/v8-non-pointer-compression.bzl +++ b/deps/v8/bazel/v8-non-pointer-compression.bzl @@ -1,7 +1,4 @@ -""" -Exposes the rule v8_binary_non_pointer_compression, which forces a label -to be compiled without pointer compression. -""" +"""A transition to compile targets without pointer compression.""" def _v8_disable_pointer_compression(settings, attr): return { @@ -13,42 +10,3 @@ v8_disable_pointer_compression = transition( inputs = [], outputs = ["//:v8_enable_pointer_compression"], ) - -# The implementation of transition_rule: all this does is copy the -# cc_binary's output to its own output and propagate its runfiles -# and executable to use for "$ bazel run". -# -# This makes transition_rule as close to a pure wrapper of cc_binary -# as possible. -def _v8_binary_non_pointer_compression(ctx): - binary = ctx.attr.binary[0] - outfile = ctx.actions.declare_file(ctx.label.name) - cc_binary_outfile = binary[DefaultInfo].files.to_list()[0] - - ctx.actions.run_shell( - mnemonic = "V8BinaryNonPointerCompression", - inputs = [cc_binary_outfile], - outputs = [outfile], - command = "cp %s %s" % (cc_binary_outfile.path, outfile.path), - ) - return [ - DefaultInfo( - executable = outfile, - data_runfiles = binary[DefaultInfo].data_runfiles, - ), - ] - -# The purpose of this rule is to transition to a config where v8_target_cpu is -# set to the appropriate architecture, which will remain in place through exec -# transitions, so mksnapshot can for instance build on x64 but for arm64. -v8_binary_non_pointer_compression = rule( - implementation = _v8_binary_non_pointer_compression, - attrs = { - # This is the cc_binary whose deps will select() on that feature. - # Note specificaly how it's configured with v8_target_cpu_transition, which - # ensures that setting propagates down the graph. - "binary": attr.label(cfg = v8_disable_pointer_compression), - }, - # Making this executable means it works with "$ bazel run". - executable = True, -) diff --git a/deps/v8/docs/committer-responsibility.md b/deps/v8/docs/committer-responsibility.md index 68e7b4ab827e..8eb5ec474307 100644 --- a/deps/v8/docs/committer-responsibility.md +++ b/deps/v8/docs/committer-responsibility.md @@ -5,9 +5,8 @@ description: 'This document lists guidelines for V8 contributors.' When you’re committing to the V8 repositories, ensure that you follow these guidelines (adapted from <https://dev.chromium.org/developers/committers-responsibility>): 1. Find the right reviewer for your changes and for patches you’re asked to review. -1. Be available on IM and/or email before and after you land the change. -1. Watch the [waterfall](https://ci.chromium.org/p/v8/g/main/console) until all bots turn green after your change. -1. When landing a TBR change (To Be Reviewed), make sure to notify the people whose code you’re changing. Usually just send the review e-mail. +1. Use the [Commit Queue](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/infra/cq.md) to commit your change (by setting Commit-Queue +2 on the code review page). For exceptional cases where you might not use the CQ, see [Directly committing code](https://www.chromium.org/developers/contributing-code/direct-commit). +1. If you need to revert your change, use the *Revert* button on the code review page. In short, do the right thing for the project, not the easiest thing to get code committed, and above all: use your best judgement. diff --git a/deps/v8/docs/heap/roots.md b/deps/v8/docs/heap/roots.md index 6a11a2f2e963..c6d66dec78ed 100644 --- a/deps/v8/docs/heap/roots.md +++ b/deps/v8/docs/heap/roots.md @@ -32,7 +32,7 @@ When `v8_enable_static_roots = true` is enabled (supported under pointer compres * **Cage Placement**: The read-only heap is placed at the very beginning of every Pointer Compression Cage. This ensures that the 32-bit compressed offset of any read-only object is constant across all isolates in a process. * **Deterministic Layout**: The `mksnapshot` tool deterministically creates a bit-identical read-only heap. * **Two-Stage Build (Conceptual)**: To use these addresses in C++ code (`libv8`), V8 needs to know them at compile time. - 1. `mksnapshot` (or specialized generator tools) is run to generate the addresses and write them to configuration-specific headers (e.g., `src/roots/static-roots-intl-wasm.h`), which are included by `src/roots/static-roots.h` based on build flags. + 1. `mksnapshot` (or specialized generator tools) is run to generate the addresses and write them to configuration-specific headers (e.g., `src/gen/intl-wasm/static-roots.h`), which are included by `src/roots/static-roots.h` based on build flags. 2. The main V8 binary is compiled, using these hardcoded offsets (e.g., `StaticReadOnlyRoot::kUndefinedValue`). * *Note*: In practice, these generated headers are checked into the repository and only validated as part of normal compilation. If the read-only heap layout changes, the headers have to be regenerated with the `tools/dev/gen-static-roots.py` script. diff --git a/deps/v8/docs/parsing/hole-check-elimination-parser.md b/deps/v8/docs/parsing/hole-check-elimination-parser.md index 305fb0106a56..57dfb03660ef 100644 --- a/deps/v8/docs/parsing/hole-check-elimination-parser.md +++ b/deps/v8/docs/parsing/hole-check-elimination-parser.md @@ -229,12 +229,12 @@ In this scenario, the access to `x` inside `inner` becomes a `DynamicLocal`. V8 --- ### Can the underlying variable be in the same closure as the `eval`? -No. To understand why, we must first clarify where `DynamicLocal` variables are introduced: they are created in the **body's declaration scope** if that body contains an `eval` call within the closure. This is because the `eval` might dynamically introduce variables into that declaration scope at runtime, potentially shadowing existing variables. +Usually no, with one exception (`VarBlock` scopes for functions with non-simple parameters). To understand why, we must first clarify where `DynamicLocal` variables are introduced: they are created in the **body's declaration scope** if that body contains an `eval` call within the closure. This is because the `eval` might dynamically introduce variables into that declaration scope at runtime, potentially shadowing existing variables. Given that, we look at how V8 handles different variable modes in this scenario: -- **For `let` and `const`**: `eval` can only introduce `var` declarations into the outer scope (since `let` and `const` stay strictly local to the `eval` itself). If we have a `let` or `const` variable in that same closure scope, attempting to introduce a `var` with the same name via `eval` is a **SyntaxError** in JavaScript. Thus, a valid `DynamicLocal` representing a TDZ variable can never be shadowed by `eval` in the same closure. +- **For `let` and `const`**: `eval` can only introduce `var` declarations into the outer scope (since `let` and `const` stay strictly local to the `eval` itself). If we have a `let` or `const` variable in that same declaration scope, attempting to introduce a `var` with the same name via `eval` is a **SyntaxError** in JavaScript. Thus, a valid `DynamicLocal` can never shadow a `let` or `const` declared in the same declaration scope. - **For standard `var`**: If `eval` introduces a `var` that matches an existing `var` in the same closure, V8 simply resolves it directly or merges them rather than creating a `DynamicLocal`. -- **For `VarBlock` scopes**: A `VarBlock` is a block scope that acts as a declaration scope. V8 uses them for **class static blocks** and for **functions with non-simple parameters**. Since classes are always in strict mode, an `eval` inside a class static block cannot introduce dynamic variables, so `DynamicLocal` is never needed there. For functions with non-simple parameters, a `DynamicLocal` inside the `VarBlock` body *could* target a variable outside of it but within the same closure (like function parameters). However, these parameters are always `kCreatedInitialized` in V8, meaning they **never need a hole check**! +- **For `VarBlock` scopes**: A `VarBlock` is a block scope that acts as a declaration scope. V8 uses them for **class static blocks** and for **functions with non-simple parameters**. Since classes are always in strict mode, an `eval` inside a class static block cannot introduce dynamic variables, so `DynamicLocal` is never needed there. For functions with non-simple parameters, parameters are declared as `kLet` with `kNeedsInitialization` in the `FUNCTION_SCOPE`, while the body runs in an inner `VarBlock` within the same closure scope. A `DynamicLocal` in the `VarBlock` can therefore target a parameter in the same closure scope (`target->scope()->IsOuterScopeUpToClosureScopeOf(var->scope())`). Because that `DynamicLocal` variable can be shared between references in the body (`same_closure_scope == true`) and references in inner closures (`same_closure_scope == false`), `HoleCheckState` is not scope-independent and is not cached on the `DynamicLocal` variable in this case; instead, V8 delegates directly to the underlying parameter variable (which never has a stale `access_position` since no closure boundary exists between the `VarBlock` and the `FUNCTION_SCOPE`). -Therefore, for any variable that actually *requires a hole check* (i.e., `let` and `const` variables), the shadowed target must always be in a different, outer closure! Thus, `same_closure_scope` is guaranteed to be false for these lookups. +Whenever a `DynamicLocal` variable caches `HoleCheckState` (`!target->scope()->IsOuterScopeUpToClosureScopeOf(var->scope())`), the shadowed target is guaranteed to be in a different, outer closure, so `same_closure_scope` is guaranteed to be false for all lookups through it. diff --git a/deps/v8/docs/security/reproducing-bugs.md b/deps/v8/docs/security/reproducing-bugs.md index 685fae85f4de..11888bab2d53 100644 --- a/deps/v8/docs/security/reproducing-bugs.md +++ b/deps/v8/docs/security/reproducing-bugs.md @@ -10,6 +10,7 @@ Reproductions (POCs) should work on `d8`. To help identify whether a bug is a valid vulnerability or a regular correctness bug, various flags are used to filter out configurations that are not relevant for security testing. The recommended way to verify if a bug is a security vulnerability is to run the reproduction with `--run-as-security-poc` as first argument in addition to any provided flags. +While security impact is always reasoned about against a release configuration, reproducing a `DCHECK` failure in a debugging build with `--run-as-security-poc` is sufficient and the unmodified POC does not need to crash a release build. If the crash still occurs with this flag enabled, it is likely a valid security vulnerability (**Type=Vulnerability**). ### Fine-grained control over configurations diff --git a/deps/v8/docs/security/triaging.md b/deps/v8/docs/security/triaging.md index 86ead358de95..cb72550a9e26 100644 --- a/deps/v8/docs/security/triaging.md +++ b/deps/v8/docs/security/triaging.md @@ -110,14 +110,23 @@ Fields: **Type=Bug**, **[Security_Impact-None][hl-impact-none]** V8 relies on `nullptr` dereferences to deterministically crash. -### Bogus `DCHECK`s or reliable `CHECK` crashers +### Reliable `CHECK` crashers Fields: **Type=Bug**, **[Security_Impact-None][hl-impact-none]** -Rationale: These issues are not considered security vulnerabilities because the crashes either cannot happen in production builds (e.g., `DCHECK` failures, which are compiled out) or they result in a safe, deterministic crash (e.g., `CHECK` failures). -Invalid ("bogus") `DCHECK`s should still be fixed or removed. +Rationale: Unconditional `CHECK` failures (as well as `UNREACHABLE()` and `SBXCHECK`) result in a safe, deterministic crash in production builds before unsafe execution can proceed. -Note: `CHECK`s must not be behind special builds or phases, such as `--verify-*`. +Note: This only applies to `CHECK`s that are active in production builds. +`CHECK`s behind verification flags or special builds (such as `--verify-heap` or `OBJECT_PRINT`) often indicate prior memory or heap corruption and must be investigated as potential vulnerabilities. + +### `DCHECK` failures + +Fields: **Type=Vulnerability**, **Security_Impact-{[Head][hl-impact-head], [Beta][hl-impact-beta], [Stable][hl-impact-stable], [Extended][hl-impact-extended]}** + +Rationale: Unlike `CHECK`s, `DCHECK`s are compiled out in production builds and execution continues past the asserted condition, which can corrupt state or memory if subsequent code relies on the invariant. + +Note: Benign `DCHECK`s that are mitigated by subsequent code, overzealous conditions, or simply wrong conditions/invariants result in lowering to **Type=Bug** and **[Security_Impact-None][hl-impact-none]**. +For [sandbox bypasses](#sandbox-bypasses), where in-sandbox memory is intentionally corrupted, `DCHECK` failures are expected and ignored unless continuing past the `DCHECK` in a release build leads to write access outside of the sandbox. ### Leaking _Hole_ values into JavaScript diff --git a/deps/v8/experimental/redline/.clang-tidy b/deps/v8/experimental/redline/.clang-tidy new file mode 100644 index 000000000000..02182fa877ad --- /dev/null +++ b/deps/v8/experimental/redline/.clang-tidy @@ -0,0 +1,72 @@ +--- +# clang-tidy configuration for experimental/redline (overrides the V8 root .clang-tidy +# for this directory only). +# +# Enable the modern guideline families, drop the opinionated style noise and +# the checks that contradict how a fuzzer in the V8 tree is written: +# - shared-memory and REPRL plumbing needs reinterpret_cast, pointer +# arithmetic and unchecked indexing into bitmaps and vectors; +# - generator tables are made of literal numbers and C arrays, and the +# command-line flags are globals; +# - V8 style keeps nested namespace blocks, explicit types instead of auto, +# positional aggregate initialization and plain enums for small kinds; +# - bugprone-signed-bitwise and performance-enum-size flag every hash and +# flag computation and every enum, without a bug behind them. +# +# Run it with a compilation database of the redline target: +# gn gen out/x64.release --add-export-compile-commands=//experimental/redline:redline +# clang-tidy -p out/x64.release experimental/redline/<dir>/<file>.cc +Checks: > + -*, + bugprone-*, + cert-*, + clang-analyzer-*, + cppcoreguidelines-*, + modernize-*, + performance-*, + readability-avoid-const-params-in-decls, + readability-container-size-empty, + readability-delete-null-pointer, + readability-redundant-*, + readability-simplify-boolean-expr, + -bugprone-easily-swappable-parameters, + -bugprone-signed-bitwise, + -cert-err58-cpp, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-const-or-ref-data-members, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-non-private-member-variables-in-classes, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-type-static-cast-downcast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-vararg, + -modernize-avoid-c-arrays, + -modernize-concat-nested-namespaces, + -modernize-use-auto, + -modernize-use-designated-initializers, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -performance-enum-size + +# Warnings as errors: the bug-finding families must stay clean. +WarningsAsErrors: 'bugprone-*,performance-*,clang-analyzer-*' + +# Only report findings in this directory's own headers. +HeaderFilterRegex: 'experimental/redline/.*' +FormatStyle: file + +CheckOptions: + # Rule of five, but a sole default destructor or deleted copy operations + # are fine. + cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor: true + cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions: true + cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted: true +... diff --git a/deps/v8/experimental/redline/.gitignore b/deps/v8/experimental/redline/.gitignore new file mode 100644 index 000000000000..b11f271011c4 --- /dev/null +++ b/deps/v8/experimental/redline/.gitignore @@ -0,0 +1 @@ +!GEMINI.md diff --git a/deps/v8/experimental/redline/BUILD.gn b/deps/v8/experimental/redline/BUILD.gn new file mode 100644 index 000000000000..b375a6f5f4f0 --- /dev/null +++ b/deps/v8/experimental/redline/BUILD.gn @@ -0,0 +1,172 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("../../gni/v8.gni") + +# Redline is a coverage-guided JavaScript fuzzer for d8, written in C++ and +# living in the V8 tree. The fuzzer itself does not need coverage +# instrumentation: it drives a separately built, instrumented d8 (built with +# v8_fuzzilli=true and sanitizer_coverage_flags set) over the REPRL protocol +# that d8 already implements for Fuzzilli. See README.md. + +# Stricter diagnostics for this directory only. The V8 headers that redline +# includes (include/, src/base/, ...) are treated as system headers so that +# only Redline's own code is held to these flags. +config("redline_warnings") { + cflags = [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wconversion", + "-Wshadow", + "-Wunused", + "-Werror", + ] + if (is_clang) { + cflags += [ + "--system-header-prefix=include/", + "--system-header-prefix=src/", + "--system-header-prefix=third_party/", + "--system-header-prefix=absl/", + ] + } + cflags_cc = [ + "-Wnon-virtual-dtor", + "-Wold-style-cast", + "-Woverloaded-virtual", + ] +} + +v8_executable("redline") { + sources = [ + "base/file_util.cc", + "base/file_util.h", + "base/flags.cc", + "base/flags.h", + "base/json.cc", + "base/json.h", + "base/json_parser.cc", + "base/json_parser.h", + "base/log.cc", + "base/log.h", + "base/subprocess.cc", + "base/subprocess.h", + "base/time_util.h", + "base/v8_runtime.cc", + "base/v8_runtime.h", + "commands/amplify_command.cc", + "commands/command.h", + "commands/exec_command.cc", + "commands/fuzz_command.cc", + "commands/minimize_command.cc", + "commands/mutate_command.cc", + "commands/parse_command.cc", + "commands/replay_command.cc", + "commands/roundtrip_command.cc", + "commands/selftest_checker.h", + "commands/selftest_command.cc", + "commands/selftest_selection.cc", + "commands/selftest_selection.h", + "commands/shell_command.cc", + "core/adaptive_selector.h", + "core/ast_builder.cc", + "core/ast_builder.h", + "core/builder.cc", + "core/builder.h", + "core/component.cc", + "core/component.h", + "core/environment.cc", + "core/environment.h", + "core/program.cc", + "core/program.h", + "core/random.h", + "core/selection.cc", + "core/selection.h", + "core/tunable.cc", + "core/tunable.h", + "core/weighted_selector.h", + "corpus/corpus.cc", + "corpus/corpus.h", + "engine/amplifier.cc", + "engine/amplifier.h", + "engine/config.cc", + "engine/config.h", + "engine/crash.cc", + "engine/crash.h", + "engine/fuzzer.cc", + "engine/fuzzer.h", + "engine/importer.cc", + "engine/importer.h", + "engine/prelude.cc", + "engine/prelude.h", + "engine/shared_coverage.cc", + "engine/shared_coverage.h", + "engine/stages.cc", + "engine/stages.h", + "exec/coverage.cc", + "exec/coverage.h", + "exec/execution.cc", + "exec/execution.h", + "exec/process_run.cc", + "exec/process_run.h", + "exec/reprl.cc", + "exec/reprl.h", + "exec/runner.cc", + "exec/runner.h", + "exec/target_options.cc", + "exec/target_options.h", + "fast/arena.cc", + "fast/arena.h", + "fast/ast.cc", + "fast/ast.h", + "fast/ast_visit.h", + "fast/lexer.cc", + "fast/lexer.h", + "fast/parser.cc", + "fast/parser.h", + "fast/printer.cc", + "fast/printer.h", + "fast/scope.cc", + "fast/scope.h", + "fast/tree.cc", + "fast/tree.h", + "generators/codegen.cc", + "generators/codegen.h", + "generators/generator.h", + "generators/generators.cc", + "generators/wasm_module.cc", + "generators/wasm_module.h", + "main.cc", + "minimizer/minimizer.cc", + "minimizer/minimizer.h", + "mutators/explore.cc", + "mutators/explore.h", + "mutators/mutator.h", + "mutators/mutators.cc", + "mutators/probing.cc", + "mutators/probing.h", + ] + + configs = [ + # Note: don't use :internal_config here because this target will get + # the :external_config applied to it by virtue of depending on :v8, and + # you can't have both applied to the same target. + "../..:internal_config_base", + ":redline_warnings", + + # Chromium builds with -Wexit-time-destructors. This config gives the + # same warning in a standalone V8 build. + "//build/config/compiler:wexit_time_destructors", + ] + + deps = [ + "../..:v8", + "../..:v8_abseil", + "../..:v8_internal_headers", + "../..:v8_libbase", + "../..:v8_libplatform", + "../..:v8_version", + "//build/win:default_exe_manifest", + ] +} diff --git a/deps/v8/experimental/redline/CONTRIBUTE.md b/deps/v8/experimental/redline/CONTRIBUTE.md new file mode 100644 index 000000000000..99699a43cf09 --- /dev/null +++ b/deps/v8/experimental/redline/CONTRIBUTE.md @@ -0,0 +1,968 @@ +# Contributing to Redline + +This guide is for V8 engineers who want to change Redline. +Each section is a walkthrough with real commands and real outputs. +We ran every command on a workstation in October 2026, with a fuzzing d8 of 2,038,918 edges. +Your numbers will be different. The shape of the output will be the same. + +Read these documents first: + +- [DESIGN.md](DESIGN.md): the pipeline, the stages and the rules that keep Redline simple. +- [TUTORIAL.md](TUTORIAL.md): the commands, from one file to an overnight session. + +The walkthroughs add three example components: the generator `AtomicsOps`, the mutator `NegateCondition` and the seed strategy `smallest`. +They are examples only. They are not part of Redline. + +Contents: + +1. [Prepare your workstation](#1-prepare-your-workstation) +2. [Concepts](#2-concepts) +3. [Add a generator](#3-add-a-generator) +4. [Add a mutator](#4-add-a-mutator) +5. [Add a reducer](#5-add-a-reducer) +6. [Add a selection strategy](#6-add-a-selection-strategy) +7. [Change the other stages](#7-change-the-other-stages) +8. [Tune a preset](#8-tune-a-preset) +9. [Debug a stage](#9-debug-a-stage) +10. [Measure a change](#10-measure-a-change) +11. [Checklist for a CL](#11-checklist-for-a-cl) + +--- + +## 1. Prepare your workstation + +```sh +V8=<your V8 checkout> +cd $V8 +gn gen out/redline --args='is_debug=false target_cpu="x64" use_allocator_shim=false use_remoteexec=true' +autoninja -C out/redline redline # TUTORIAL.md section 2 explains the args +alias redline=$V8/out/redline/redline +export REDLINE_D8=$V8/out/fuzzbuild/d8 # TUTORIAL.md section 1 builds it +``` + +You need two builds of d8: + +| d8 build | Use | +|---|---| +| a fuzzing d8 at your revision (`$REDLINE_D8`) | everyday checks, the shell, sessions | +| a fuzzing d8 with known bugs (`$D8_BUGS`) | the overfitting audit (section 3.7) | + +To make a d8 with known bugs, build the fuzzing d8 of [TUTORIAL.md](TUTORIAL.md) section 1 at a V8 revision that is a few months old. Each `test/mjsunit/regress/` test that is newer than that revision shows a bug that this d8 has. + +`experimental/redline/BUILD.gn` compiles Redline with `-Werror` and strict warnings, for example `-Wconversion`, `-Wshadow` and `-Wold-style-cast`. +The build fails on every warning. Format and lint your files with these commands: + +```sh +git cl format # uses the V8 style (the root .clang-format) +gn gen out/redline --add-export-compile-commands=//experimental/redline:redline +clang-tidy -p out/redline experimental/redline/generators/generators.cc +``` + +--- + +## 2. Concepts + +### 2.1 Where the code is + +| Stage | You add | File | Registration | Configuration key | +|---|---|---|---|---| +| Init | an init strategy | `engine/config.cc` | `ReadInitConfig` | `init` | +| Pick | a seed or partner strategy (`Selector<const Program>`) | `corpus/corpus.cc` | `RegisterBuiltinSelectors<const Program>` | `selection.seeds`, `selection.partners` | +| Mutate | a mutator (`Mutator`) | `mutators/mutators.cc` | `MutatorSet::CreateDefault` | `selection.mutators` | +| Mutate | a generator | `generators/generators.cc` | `GeneratorSet::CreateDefault` | `selection.generators` | +| Mutate | a mutator or generator strategy | `mutators/mutators.cc`, `generators/generators.cc` | `RegisterBuiltinSelectors<Mutator>`, `RegisterBuiltinSelectors<Generator>` | `selection.mutators`, `selection.generators` | +| Accept | a criterion | `engine/config.cc`, `engine/fuzzer.cc` | `ReadAcceptConfig`, `Worker::Commit` | `accept`, `stages.check` | +| Minimize | a reducer (`Reducer`) | `minimizer/minimizer.cc` | `Minimizer::CreateDefaultReducers` | `stages.minimize.reducers` | +| Crash triage | an amplify strategy (`AmplifyStrategy`) | `engine/amplifier.cc` | `CreateAmplifyStrategy`, `AmplifyStrategies` | `amplify` | +| any | a number (tunable) | next to its use | `REDLINE_TUNABLE` | `tunables` | + +Execute and Publish are fixed code in `engine/fuzzer.cc` and `exec/`. Crash triage is in `engine/crash.cc`, `engine/fuzzer.cc` and `engine/amplifier.cc`. +File names in the text and the tables are relative to `experimental/redline/`. The commands run in the root of the V8 checkout. + +### 2.2 Programs, FAST and the Builder + +- A `Program` (`core/program.h`) is immutable. It holds a FAST tree, its printed source, its lineage and its corpus data. +- FAST (`fast/ast.h`) is the typed JavaScript AST of Redline. One X-macro list defines the node kinds. Every node has a stable `id`. +- A mutator never changes a corpus program. `ApplyMutation` copies the tree, and the mutator edits the copy through a `Builder` (`core/builder.h`). +- The `Builder` knows the scopes, the parent of each node and the visible variables at each position. It also knows the syntactic context, for example "strict" or "in a loop". +- The `Builder` has edit primitives: `Insert`, `InsertAll`, `Remove`, `Replace` and `Blockify`. If you edit the tree directly, call `Builder::Invalidate()`. The Builder then computes its analyses again. +- New nodes come from the `mk::` helpers (`core/ast_builder.h`), for example `mk::CallMethod(t, object, "name", {arguments})`. +- The in-process V8 parser is the syntax oracle. Redline never executes JavaScript in its own process. The target d8 executes every program. + +### 2.3 Components + +A component is a generator, a mutator or a reducer. Every component derives from `Component` (`core/component.h`). A component has: + +- a name, which the configuration, the shell and the statistics use, +- a description of one line, which `redline mutate --list` and the shell show, +- a `ComponentStats` record: invocations, results, invalid results, executions, outcomes, new coverage and time. + +The engine fills the statistics. Your component does not count anything. + +Generators and mutators also have a default weight. The selection strategy uses it. A weight of 0 disables a component. The configuration can change every weight without a new build. + +### 2.4 Strategies + +A strategy makes one decision: which seed, which partner, which mutator or which generator. +A strategy is a `Selector<T>` (`core/selection.h`). A `SelectorRegistry<T>` keeps the strategies by name, with the parameters (`ParamSpec`) of each one. +The registry checks the configuration before any target starts. It also writes the strategy part of `redline fuzz --help-config`. + +### 2.5 Tunables + +A tunable is a named number with a default, a range and one line of documentation (`core/tunable.h`): + +```cpp +REDLINE_TUNABLE(kAtomicsOpsMaxCalls, "generators.AtomicsOps.max_calls", 3, 1, + 16, "most Atomics calls"); +// ... +const int calls = 1 + r.SmallCount(kAtomicsOpsMaxCalls.AsInt() - 1); +``` + +Rules: + +- Every probability, count and limit in a component is a tunable. Do not write a number in the code. +- The name starts with the owner: `generators.<Generator>.`, `mutators.<Mutator>.`, `codegen.<helper>.` or `minimizer.<reducer>.`. +- When you replace a number in existing code, the default is the old number. Then the behavior does not change. +- `redline fuzz --help-tunables` lists all tunables. The flag `--tunable=NAME=VALUE` and the `tunables` block set them. The flag also works with `mutate` and `audit`. + +Redline has 267 tunables today: 169 in generators, 61 in the CodeGen helpers, 36 in mutators and 1 in the minimizer. + +### 2.6 Configuration + +One JSON configuration sets everything. Four layers apply, and a later layer wins: + +1. the built-in defaults, +2. the preset (`--preset=NAME` or `--preset=FILE`), +3. the configuration (`--config=FILE` or inline JSON), +4. the command-line flags. + +`redline fuzz --dump-config` prints the complete result, with every default. It needs no target. Section 8 shows how to tune a preset. + +### 2.7 Tests that protect you + +| Test | Command | It finds | +|---|---|---| +| golden traces | `redline selftest --offline` | a change in the picks or the output of a component, for fixed seeds | +| node kinds | `redline selftest --offline` | a FAST node kind that no generator produces | +| configuration | `redline selftest --offline` | a preset that does not load, an error that is not reported, a dump that does not load back | +| validity | `redline mutate --generate --generator=NAME --n=500` | output that the V8 parser rejects | +| runtime | the same command with `--run` | output that throws or times out too often | +| overfitting | `redline audit --generator=NAME` | a generator that is a template of one known bug | +| parser | `redline roundtrip --dir=test/mjsunit` | JavaScript that FAST cannot parse or print | + +The offline selftest takes less than one second. Run it after every change. + +--- + +## 3. Add a generator + +We add `AtomicsOps`. It calls `Atomics` functions on an integer typed array. + +### 3.1 How a generator works + +The `CodeGen` mutator picks an insertion point in a program. Then it asks the generator strategy for a generator that can run at that point. +The generator appends statements to `out`, and `CodeGen` inserts them at the insertion point. + +A generator gets a `GenContext` (`generators/generator.h`): + +| Member | Use | +|---|---| +| `ctx.syntax` | the syntactic context at the insertion point: `strict`, `in_function`, `in_loop`, `in_async` and others | +| `ctx.visible` | the variables that are visible and initialized at the insertion point, innermost first, each with a type guess (`JsType`) | +| `ctx.rng()` | the random generator of the worker. Use only this one: the same seed must give the same program. | +| `ctx.tree()` | the tree that owns the new nodes (`T(ctx)` in `generators.cc`) | +| `ctx.depth`, `ctx.max_depth` | the nesting depth of generated code | + +The helper `CodeGen cg` (`generators/codegen.h`) makes values and statements. +Examples: `cg.Integer()`, `cg.Value(type)`, `cg.Variable(type)`, `cg.Arguments(min, max)`, `cg.Declare(init, type, prefix)`, `cg.DeclareGuarded(init, type)` and `cg.Body(nested, count)`. + +Requirements tell the strategy where a generator can run. +For example, `kNeedsFunction` means "this generator emits `return`". The strategy then never picks it outside a function. +`kRecursive` means "this generator emits nested code". The strategy stops it at `max_depth`. + +### 3.2 Write the generator + +Add this code to `generators/generators.cc`, before `#undef GEN`: + +```cpp +REDLINE_TUNABLE(kAtomicsOpsMaxCalls, "generators.AtomicsOps.max_calls", 3, 1, + 16, "most Atomics calls"); +REDLINE_TUNABLE(kAtomicsOpsLength, "generators.AtomicsOps.length", 16, 1, 1024, + "elements of a new Int32Array"); +REDLINE_TUNABLE( + kAtomicsOpsReuseChance, "generators.AtomicsOps.reuse_chance", 0.3, 0, 1, + "probability to use a visible typed array instead of a new one"); + +GEN(AtomicsOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + + // A visible typed array, or a new Int32Array on a SharedArrayBuffer. + Identifier* array = r.Chance(kAtomicsOpsReuseChance()) + ? cg.Variable(JsType::kTypedArray) + : nullptr; + const bool reused = array != nullptr; + const int length = kAtomicsOpsLength.AsInt(); + if (!reused) { + Expression* buffer = + mk::New(t, mk::Id(t, "SharedArrayBuffer"), {mk::Num(t, 4.0 * length)}); + Push(out, cg.Declare(mk::New(t, mk::Id(t, "Int32Array"), {buffer}), + JsType::kTypedArray, "ta")); + array = mk::Id( + t, ctx.visible.front().name); // Declare() put the new name first + } + + const int calls = 1 + r.SmallCount(kAtomicsOpsMaxCalls.AsInt() - 1); + for (int i = 0; i < calls; i++) { + std::string_view op = r.Pick({"add", "sub", "and", "or", "xor", "exchange", + "compareExchange", "load", "store"}); + // An index inside the new array; any integer for a visible array. + Expression* index = + reused ? cg.Integer() + : mk::Num(t, static_cast<double>(r.Range(0, length - 1))); + std::vector<Expression*> args = {mk::Id(t, array->name), index}; + if (op != "load") { + args.push_back(cg.Integer()); + } + if (op == "compareExchange") { + args.push_back(cg.Integer()); + } + Expression* call = + mk::CallMethod(t, mk::Id(t, "Atomics"), op, std::move(args)); + // A visible typed array can have an element type that Atomics rejects. + if (reused) { + for (Statement* s : cg.DeclareGuarded(call, JsType::kNumber)) { + Push(out, s); + } + } else { + Push(out, cg.Declare(call, JsType::kNumber)); + } + } + return true; +} +``` + +What the code does: + +- `GEN(AtomicsOps)` declares the function `GenAtomicsOps(GenContext& ctx, CodeGen& cg, Statements* out)`. +- `cg.Variable(JsType::kTypedArray)` returns a visible typed array, or `nullptr`. Code at the start of a program sees no variables. Thus a generator must also work without them. DESIGN.md calls this rule "missing data is normal". +- `cg.Declare(...)` makes a `let`, `const` or `var` declaration with a fresh name. It also adds the name to `ctx.visible`, so `ctx.visible.front()` is the new name. Generators that run later in the same insertion can use the new variable. +- A visible typed array can be a float array, and `Atomics` throws a `TypeError` for it. `cg.DeclareGuarded(...)` puts the call in a `try` block, so the exception does not end the program. +- A generator returns `false` when it cannot generate anything at this point. `CodeGen` then discards its output. +- Each number in the generator is a tunable. + +### 3.3 Register the generator + +Add one line at the end of the list in `GeneratorSet::CreateDefault()`: + +```cpp +add("AtomicsOps", "Atomics operations on a shared Int32Array", 1, + kNoRequirement, GenAtomicsOps); +``` + +The arguments are the name, the description, the default weight, the requirements and the function. + +### 3.4 Build it and check the syntax + +``` +$ autoninja -C out/redline redline +$ redline mutate --list | grep AtomicsOps + AtomicsOps w=1 Atomics operations on a shared Int32Array +$ redline mutate --generate --generator=AtomicsOps --n=500 --quiet +generators + component invoked produced invalid executed ok% fail tmo crash new edges spent ms + AtomicsOps 500 500 0 0 0.0% 0 0 0 0 0 0 0 +summary: 500 produced, 0 no-op, 500 V8-accepted (100.0%); mutation time 0.7 ms total (0.00 ms/sample), wall 0.0 s +``` + +`--generate` starts from an empty program. The in-process V8 parser checks each result. The target is at least 99.8% accepted. +`--print` shows every program. `--print-invalid` shows only the rejected programs, with the error of the parser. + +### 3.5 Run it in d8 + +``` +$ redline mutate --generate --generator=AtomicsOps --n=500 --run --quiet +generators + component invoked produced invalid executed ok% fail tmo crash new edges spent ms + AtomicsOps 500 500 0 500 100.0% 0 0 0 70 0 0 1863 +summary: 500 produced, 0 no-op, 500 V8-accepted (100.0%), 500 executed, 500 succeeded (100.0%), 0 crashed; mutation time 4.9 ms total (0.01 ms/sample), wall 1.9 s +``` + +The columns: + +- `ok%`: the share of programs that ran to the end without an uncaught exception. +- `fail`: uncaught exceptions. `tmo`: timeouts. `crash`: crashes. +- `new`: programs that reached edges that the earlier programs of the same command did not reach. + +An empty program has no visible typed array, so this run tests only one branch. +To test the other branch, make a program with a typed array, and force the branch with a tunable: + +``` +$ redline mutate --generate --generator=TypedArrayDecl --n=1 --seed=7 --out-dir=/tmp/contrib/seeds --quiet +$ redline mutate --generator=AtomicsOps --n=500 --run --quiet \ + --tunable=generators.AtomicsOps.reuse_chance=1 /tmp/contrib/seeds/TypedArrayDecl-0-0.js +generators + component invoked produced invalid executed ok% fail tmo crash new edges spent ms + AtomicsOps 500 500 0 500 100.0% 0 0 0 71 0 0 1842 +``` + +The first command writes a program that declares an `Int16Array`. +With a file argument, `mutate` inserts the generated code at a random position of that program. +Before the declaration, the typed array is not visible. Then the generator makes a new array. + +### 3.6 Examine it in the shell + +``` +$ redline shell /tmp/contrib/seeds/TypedArrayDecl-0-0.js +target: .../d8 (2038918 edges) +loaded /tmp/contrib/seeds/TypedArrayDecl-0-0.js: 10 nodes, 50 bytes +redline> generate AtomicsOps 3 +=> AtomicsOps (seed 3): inserted 2 statement(s): 28 nodes, V8 accepts +redline> run +succeeded in 4.64 ms, exit 0; 14680 edges +``` + +The shell also prints the new program and a diff. We do not show them here. +The last argument of `generate` is the seed. Try other seeds to see other outputs. `undo` goes back one step. `tree` shows the FAST nodes, and `scopes` shows the visible variables. + +### 3.7 Run the overfitting audit + +``` +$ EXTRA="--random-seed=42 --single-threaded --future --jit-fuzzing --no-baseline-batch-compilation \ + --no-lazy-feedback-allocation --turbolev --turbolev-future --wasm-inlining-ignore-call-counts" +$ redline audit --d8=$D8_BUGS --d8-extra-args="$EXTRA" --generator=AtomicsOps --n=1000 +... + AtomicsOps 1000 1000 0 1000 100.0% 0 0 0 88 4425 +audit: largest share of one crash signature per generator (threshold 0.50%) +audit: 0 of 1 generators crashed, 0 above the threshold +``` + +`$EXTRA` holds the d8 flags of the A/B experiment. +A generator passes if no crash signature takes more than 0.5% of its programs. +If your generator fails, make it more general. A lower weight does not fix the problem. DESIGN.md section 10 tells why. + +### 3.8 Update the golden traces + +``` +$ redline selftest --offline +... +FAIL selection: generator picks match the golden trace: first difference at line 1: golden '0 PropertyStore', now '0 ElementLoad' +FAIL selection: CodeGen insertions match the golden trace: first difference at line 1: ... +FAIL components: every generator's output matches the golden trace: first difference at line 77: ... +FAIL components: every mutator's output matches the golden trace: first difference at line 2: ... +selftest: 61 passed, 4 failed +``` + +These failures are correct. A new generator with a weight above 0 changes the generator draws. +Write the new traces and examine the diff: + +``` +$ redline selftest --offline --write-golden +$ git diff --stat experimental/redline/testdata + experimental/redline/testdata/selection/codegen.trace | 1994 ++++++++++---------- + .../testdata/selection/generator_outputs.trace | 131 +- + experimental/redline/testdata/selection/generators.trace | 1364 ++++++------- + .../testdata/selection/mutator_outputs.trace | 17 +- + 4 files changed, 1758 insertions(+), 1748 deletions(-) +$ redline selftest --offline +... +selftest: 65 passed, 0 failed +``` + +(This run also contains the mutator of section 4.) How to examine the diff: + +- `generators.trace` and `codegen.trace` record the generator of each draw. They change for each new generator with a weight above 0. +- `generator_outputs.trace` records five outputs of each generator. Your generator adds five lines. Generators that draw nested code, for example `FunctionDecl`, also change. +- `mutator_outputs.trace` changes for the mutators that insert generated code, for example `CodeGen`. +- Other changes are not expected. Find their cause before you continue. + +Commit the new traces in the same CL as the generator. + +### 3.9 Measure the effect + +A generator is useful only if it finds coverage or bugs that Redline did not find before. +Section 10 shows how to compare two sessions. +Put the result in the CL description. + +--- + +## 4. Add a mutator + +We add `NegateCondition`. It negates the test of an `if` statement, a loop or a conditional expression. + +### 4.1 How a mutator works + +The worker picks a mutator with the mutator strategy. `ApplyMutation` copies the tree of the parent, makes a `Builder` on the copy and calls `Mutate` (`mutators/mutator.h`): + +```cpp +virtual bool Mutate(Builder& builder, MutationContext& ctx) = 0; +``` + +The contract: + +1. Edit the tree through the `Builder`. After a direct edit, call `builder.Invalidate()`. +2. Return `false` when there is nothing to do. The tree must then be unchanged. +3. Write one line about the change in `ctx.detail`. The corpus lineage and the shell show it. +4. Keep the program valid. For example, do not move a declaration after its uses. `VisibleAt`, `EscapingBindings` and `ContextAt` of the Builder help. +5. Use only `builder.rng()`. + +The arguments of the `Mutator` constructor are the name, the description, the default weight, `needs_partner` and `max_simultaneous`. +`needs_partner` is true for mutators that take code from a second program (`ctx.partner`), for example `Splice`. +`max_simultaneous` is the largest number of changes in one application. The engine draws the number from 1 to this value. + +### 4.2 Write the mutator + +Add this class to `mutators/mutators.cc`, in the unnamed namespace: + +```cpp +// Negates the test of an if, a loop or a conditional expression. +class NegateConditionMutator final : public Mutator { + public: + NegateConditionMutator() + : Mutator("NegateCondition", + "negates the test of an if, a loop or a conditional", 0, + false) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + std::vector<Node*> nodes = b.Collect(HasTest); + if (nodes.empty()) { + return false; // nothing to do: the tree is unchanged + } + Node* node = nodes[b.rng().Index(nodes.size())]; + Expression** test = TestOf(node); + *test = mk::Unary(b.tree(), UnaryOp::kNot, *test); + b.Invalidate(); // a structural edit outside the Builder's own primitives + ctx.detail = std::string("negated the test of ") + node->kind_name(); + return true; + } + + private: + // True if `n` has a test that this mutator can negate. + static bool HasTest(Node* n) { return TestOf(n) != nullptr; } + + // The test slot of `n`, or nullptr if `n` has no test. + static Expression** TestOf(Node* n) { + switch (n->kind) { + case NodeKind::kIfStatement: + return &n->Cast<IfStatement>()->test; + case NodeKind::kWhileStatement: + return &n->Cast<WhileStatement>()->test; + case NodeKind::kDoWhileStatement: + return &n->Cast<DoWhileStatement>()->test; + case NodeKind::kConditionalExpression: + return &n->Cast<ConditionalExpression>()->test; + case NodeKind::kForStatement: { + auto* loop = n->Cast<ForStatement>(); + return loop->test != nullptr ? &loop->test : nullptr; + } + default: + return nullptr; + } + } +}; +``` + +### 4.3 Register the mutator + +Add one line at the end of `MutatorSet::CreateDefault()`: + +```cpp +add(std::make_unique<NegateConditionMutator>()); +``` + +The default weight is 0. A session does not use the mutator until you enable it. +A new mutator starts at weight 0. An A/B experiment decides its weight. + +### 4.4 Test the mutator + +`$FILES` holds eight `test/mjsunit` files: + +```sh +FILES="test/mjsunit/array-push3.js test/mjsunit/set-prototype-of-Object_prototype.js + test/mjsunit/new-function.js test/mjsunit/regress-1146106.js + test/mjsunit/unbox-smi-field-indexed.js test/mjsunit/allocation-folding.js + test/mjsunit/optimized-map.js test/mjsunit/regress-507036687.js" +``` + +``` +$ redline mutate --mutator=NegateCondition --n=50 --run --quiet $FILES +mutators + component invoked produced invalid executed ok% fail tmo crash new edges spent ms + NegateCondition 400 100 0 100 97.0% 0 3 0 60 0 0 11134 +summary: 100 produced, 300 no-op, 100 V8-accepted (100.0%), 100 executed, 97 succeeded (97.0%), 0 crashed; mutation time 6.4 ms total (0.02 ms/sample), wall 11.5 s +``` + +How to read the result: + +- 300 no-ops: six of the eight files have no `if`, no loop and no conditional expression. A no-op costs no execution. +- 100% accepted: a negated test is always valid syntax. +- 3 timeouts: a negated test can make a loop run until the timeout. A timeout costs the full timeout (1,000 ms by default). The other programs take about 20 ms. Thus these 3 programs took more time than the other 97. + +### 4.5 Use the mutator in a session + +Enable the mutator with a weight, and save the programs that time out: + +``` +$ redline fuzz --preset=default --config='{"selection": {"seeds": {"strategy": "smallest"}}}' \ + --mutator-weights=NegateCondition=1 --capture=mutate:timeout:NegateCondition:20 \ + --jobs=4 --seed=1 --duration=120 --stats-interval=60 --out=/tmp/contrib/session +[fuzz] session: 4 worker(s), seed 1, 2038918 edges in target, 0 file(s) to import, seeds smallest, partners rarity-partner, mutators adaptive, generators adaptive, output /tmp/contrib/session +[fuzz] 00:02:00 | execs 58249 (485/s) | cov 5.484% (112149 edges) | corpus 503 | ok 68.3% fail 31.4% timeout 0.4% | ... + component invoked produced invalid executed ok% fail tmo crash new edges spent ms + NegateCondition 157 70 0 70 75.7% 16 1 0 19 0 0 922 + ... + AtomicsOps 45 45 0 13 69.2% 4 0 0 5 230 +$ ls /tmp/contrib/session/captures/mutate/ +0000-timeout-NegateCondition.child.js 0000-timeout-NegateCondition.json 0000-timeout-NegateCondition.parent.js +``` + +This session also uses the seed strategy `smallest` of section 6. +The capture saved the parent, the child and a JSON file with the worker, the time and the lineage of the parent. +Compare the parent with the child. In this capture, the mutator negated the test of a `for` loop, and the program timed out. +A possible change: remove the loop cases from `TestOf`. Measure the change with section 10 before you keep it. + +--- + +## 5. Add a reducer + +A reducer makes a program smaller while the oracle stays true. The oracle is a function: "does this candidate still have the property?". +For a corpus program, the property is "these new edges are still set". For a crash, it is "the same crash signature". + +### 5.1 How a reducer works + +```cpp +class Reducer : public Component { + public: + Reducer(std::string name, std::string_view description); + // Applies all reductions this reducer can find, keeping the ones the + // oracle accepts. Returns the number of accepted reductions. + virtual int Reduce(MinimizationHelper& helper) = 0; +}; +``` + +The contract (`minimizer/minimizer.h`): + +1. Edit the tree of `helper.tree()`. +2. Call `helper.Test()`. It prints the tree and asks the oracle. +3. If `Test()` returns false, undo your edit. +4. Stop when `helper.BudgetExhausted()` is true. `Test()` also returns false then. +5. Return the number of accepted edits. + +A reducer must work with any oracle. It does not know why the program entered the corpus. DESIGN.md section 5.5 explains this rule. + +### 5.2 The smallest reducer: `truncate` + +`truncate` is the simplest reducer in `minimizer/minimizer.cc`. Copy it to start your reducer: + +```cpp +class Truncator : public Reducer { + public: + Truncator() + : Reducer("truncate", + "keep the shortest prefix of the top-level statements") {} + + int Reduce(MinimizationHelper& helper) override { + StatementList* body = StatementListOf(helper.tree()->root()); + if (body == nullptr || body->size() < 2) { + return 0; + } + const std::vector<Statement*> all = *body; + // Invariant: the prefix of length `good` passes (the whole program + // does), prefixes shorter than `lo` were tested and failed. + size_t lo = 0, good = all.size(); + while (lo < good && !helper.BudgetExhausted()) { + size_t mid = lo + (good - lo) / 2; + body->assign(all.begin(), all.begin() + static_cast<ptrdiff_t>(mid)); + if (helper.Test()) { + good = mid; + } else { + lo = mid + 1; + } + } + body->assign(all.begin(), all.begin() + static_cast<ptrdiff_t>(good)); + return good < all.size() ? 1 : 0; + } +}; +``` + +### 5.3 Register the reducer + +1. Add `reducers.push_back(std::make_unique<YourReducer>());` to `Minimizer::CreateDefaultReducers()`. +2. Do not add it to `Minimizer::DefaultOrder()` yet. The default order applies to every session. Change it only with A/B evidence. +3. Select your reducer in the configuration: + +```json +{"stages": {"minimize": {"reducers": ["truncate", "dataflow", "statements", "unwrap", "lists", "expressions"]}}} +``` + +An unknown name in this list is an error at startup. + +### 5.4 Try the reducer on captured pairs + +A session can save the parent and the child of each mutation that found new edges: `--capture=mutate:interesting:400`. +Then `redline minimize --baseline=PARENT CHILD` keeps the edges that the child has and the parent does not have. That is the oracle of the fuzzer. +Here, one captured pair goes through three reducer lists: + +``` +$ for list in statements,unwrap,lists,expressions truncate,dataflow \ + truncate,dataflow,statements,unwrap,lists,expressions; do + redline minimize --d8=$D8_BUGS --d8-extra-args="$EXTRA" --prelude=none --oracle=edges \ + --baseline=$P.parent.js --reducer=$list --out=/dev/null $P.child.js + done +[minimize] 302 -> 73 nodes (24.2%), 236 tests (23 accepted, 0 syntax-rejected) in 1.3 s; property DOES NOT HOLD on the result +[minimize] 302 -> 283 nodes (93.7%), 19 tests (3 accepted, 0 syntax-rejected) in 0.1 s; property HOLDS on the result +[minimize] 302 -> 61 nodes (20.2%), 252 tests (31 accepted, 0 syntax-rejected) in 1.3 s; property HOLDS on the result +``` + +`$P` is the path of the pair without the suffix, for example `OUT/captures/mutate/0016-interesting-Splice`. +Examine the first line: the final check of the result failed once. The target is not deterministic, so one run of one pair proves nothing. +Measure on many pairs. On 198 pairs, `truncate` and `dataflow` alone used about 10 times fewer tests than the default order. Their programs stayed larger: 91% to 95% of the original size, against 73% to 75%. + +The shell runs reducers too: `reduce truncate`, `reduce truncate,statements`, `reduce default` or `reduce all`. + +--- + +## 6. Add a selection strategy + +We add the seed strategy `smallest`. Of `size` random corpus programs, it picks the one with the fewest AST nodes. + +### 6.1 How a strategy works + +A strategy is a `Selector<T>` (`core/selection.h`). `T` is `const Program` for seeds and partners, `Mutator` for mutators and `Generator` for generators. + +| Method | Called when | +|---|---| +| `Initialize(candidates, error)` | once, before the first pick. Check the parameters that name candidates here. | +| `Pick(candidates, rng, eligible)` | for every pick. Return an index into `candidates`, or `kNoChoice`. | +| `PickRelated(candidates, anchor, rng, eligible)` | for a partner. The default picks like `Pick`, but never the anchor. | +| `OnAdded(candidates, index)` | after a program enters the corpus | +| `OnOutcome(picked, outcome)` | after each execution of a mutation result | +| `OnCrashEdges(edges)`, `WantsHitEdges()` | corpus strategies only, see `rarity` in `corpus/corpus.cc` | +| `Params()` | for the `start` event: the effective parameters | + +Threads: the corpus calls its strategies with the corpus lock held, so a seed strategy can keep plain state. +All workers share the mutator and generator strategies. These strategies must have no state between calls, or they must synchronize their state. + +### 6.2 Write the strategy + +Add this class to `corpus/corpus.cc`, next to `TournamentSeeds`: + +```cpp +// Of `size` random programs, the smallest one (fewest AST nodes) wins. +class SmallestSeeds final : public ProgramSelector { + public: + static std::vector<ParamSpec> Specs() { + return { + {"size", ParamSpec::Type::kNumber, "3", "candidates per tournament"}}; + } + explicit SmallestSeeds(const JsonValue& params) + : size_(static_cast<int>(params.GetInt("size", 3))) {} + std::string_view name() const override { return "smallest"; } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + size_t best = rng.Index(candidates.size()); + for (int i = 1; i < size_; i++) { + size_t candidate = rng.Index(candidates.size()); + if (candidates[candidate]->node_count() < + candidates[best]->node_count()) { + best = candidate; + } + } + return best; + } + JsonObject Params() const override { + JsonObject o; + o.Add("size", size_); + return o; + } + + private: + int size_; +}; +``` + +### 6.3 Register the strategy + +Add one entry to `RegisterBuiltinSelectors<const Program>()`: + +```cpp +registry.Register(Entry{"smallest", "smallest of a few random candidates", + SmallestSeeds::Specs(), + [](const JsonValue& params, + std::string*) -> std::unique_ptr<ProgramSelector> { + return std::make_unique<SmallestSeeds>(params); + }}); +``` + +The `ParamSpec` list declares the parameters. The registry uses it for three things: + +``` +$ redline fuzz --help-config | grep -A1 "^ smallest" + smallest: smallest of a few random candidates + size = 3 candidates per tournament +$ redline fuzz --dump-config --config='{"selection": {"seeds": {"strategy": "smallest", "params": {"sizes": 4}}}}' +[fuzz] selection.seeds: selection strategy 'smallest': unknown parameter 'sizes' (known: size) +$ redline fuzz --dump-config --config='{"selection": {"seeds": {"strategy": "smallest", "params": {"size": 4}}}}' \ + | python3 -c 'import json, sys; print(json.load(sys.stdin)["selection"]["seeds"])' +{'strategy': 'smallest', 'params': {'size': 4}} +``` + +### 6.4 Use the strategy + +The session of section 4.5 used `smallest`. Its statistics have one row for the seed strategy: + +``` + component invoked produced invalid executed ok% fail tmo crash new edges spent ms + smallest 472 472 0 0 0.0% 0 0 0 495 0 0 0 +``` + +`invoked` counts the picks. `new` counts the new corpus programs that came from these picks. +A seed strategy changes the whole session. Compare it with `rarity`, the seed strategy of the presets, as section 10 shows. +New strategies for mutators and generators follow the same steps in `mutators/mutators.cc` and `generators/generators.cc`. + +--- + +## 7. Change the other stages + +### 7.1 Init + +Init fills the corpus before the loop starts. `ReadInitConfig` in `engine/config.cc` reads the `init` block. +Each strategy sets fields of `FuzzConfig` that the engine already uses: + +| Strategy | Parameters | `FuzzConfig` fields | +|---|---|---| +| `generate` | `programs` | `initial_programs` (the imports are cleared) | +| `import` | `paths`, `root`, `keep` (`new-coverage` or `all`), `minimize` | `imports`, `import_root`, `import_all`, `minimize_imports` | + +To add a strategy: + +1. Add its name and its parameter names to `ReadInitConfig`. Unknown names stay errors. +2. Set existing `FuzzConfig` fields if possible. Add a field only if no field fits. +3. Write the `init` block back in `FuzzConfig::ToJson`. Then `--dump-config` shows it and the `start` event records it. +4. Add a case to `CheckConfigErrors` in `commands/selftest_selection.cc`. Then the offline selftest checks the new error messages. + +### 7.2 Accept + +Accept decides if a program enters the corpus. Today it has one criterion: `new-edges`. +The code is in `Worker::Commit` (`engine/fuzzer.cc`): + +1. The mutate stage claims the new edges of a result (`ClaimNewEdges`). If there are none, the result does not go to Commit. +2. The determinism check runs the program again. It keeps only the edges that every run sets. Its parameters are in `stages.check`. +3. The minimizer runs with an oracle: "the program succeeds and all kept edges are set". +4. Publish adds the program to the corpus. + +A second criterion must follow the rule of DESIGN.md section 5.5: it returns a frozen reason, and the reason becomes the oracle of step 3. +The reason must not depend on the corpus state at a later time. To add a criterion: + +1. Add its name to `ReadAcceptConfig` in `engine/config.cc`. +2. In the mutate stage, decide if a result is a candidate for your criterion. +3. In `Worker::Commit`, compute your reason once and build the minimizer oracle from it. +4. Add a selftest case and an A/B result. + +When Accept has a second criterion, it gets a registry like the selection strategies. + +### 7.3 A new stage parameter + +1. Add a field to `FuzzConfig` (`engine/config.h`). Its default is the old behavior. +2. Read it in the stage block of `engine/config.cc` (search for `"stages"`), and write it in `FuzzConfig::ToJson`. +3. Document it in `FuzzConfig::JsonHelp`, which prints `--help-config`. +4. Use it in `engine/fuzzer.cc`. +5. Add a case to `CheckStageConfig` in `commands/selftest_selection.cc`. Then run `redline selftest --offline`. It also loads the full dump back and compares the result. + +### 7.4 A new JavaScript feature in FAST + +When V8 adds syntax, FAST must parse it, and a generator must produce it. Two tests enforce this: + +- `redline roundtrip --dir=test/mjsunit` fails when FAST cannot parse or print the tests of the feature. +- `redline selftest --offline` fails when a FAST node kind comes out of no generator (40 samples per generator). + +The steps for a new node kind: + +1. Add the kind to the X-macro list in `fast/ast.h`, and define its struct. +2. Build. `ForEachChildSlot` in `fast/ast_visit.h` has no `default` case, so the compiler reports the missing kind. Add its children there. +3. Parse it in `fast/parser.cc`, and print it in `fast/printer.cc`. +4. If it declares or uses names, add it to the scope analysis in `fast/scope.cc`. +5. Add an `mk::` helper in `core/ast_builder.h`. +6. Generate it: extend a generator, or add one (section 3). +7. Run `redline roundtrip --dir=test/mjsunit` and `redline selftest --offline`. + +If no generator can produce a kind, add it to `kUngeneratedKinds` in `commands/selftest_selection.cc`, with a reason. + +--- + +## 8. Tune a preset + +A preset is a JSON configuration for one area of V8, in `experimental/redline/presets/`. +`--preset=maglev` loads `presets/maglev.json`. `--preset=FILE.json` loads any file. + +### 8.1 Start from a preset + +``` +$ cat experimental/redline/presets/maglev.json +{ + "d8_extra_args": ["--maglev", "--no-turbofan", "--jit-fuzzing"], + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "JitOptimize": 8, "Deopt": 3, "OsrLoop": 3, "ElementsKind": 4, "ShapeChange": 3}}}} +} +``` + +- `d8_extra_args` is appended to the d8 flags, like `--d8-extra-args`. +- `selection` sets the strategies. All presets use the strategies of the latest A/B experiment: `rarity`, `rarity-partner` and `adaptive`. +- `weights` replaces the base weight of the named generators. The others keep their built-in weight. + +### 8.2 Make your own preset + +Copy a preset and change it. This example gives more weight to object-model generators, and changes two tunables: + +```json +{ + "d8_extra_args": ["--maglev", "--no-turbofan", "--jit-fuzzing"], + "selection": { + "seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, + "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", + "params": {"weights": {"JitOptimize": 8, "ShapeChange": 4, "DefineProperty": 3, "WasmModule": 0}}} + }, + "tunables": {"generators.ClassDecl.max_members": 6, "generators.ShapeChange.max_changes": 6}, + "stages": {"minimize": {"max_tests": 200}} +} +``` + +Check the result before a long run: + +``` +$ redline fuzz --preset=/tmp/my-preset.json --dump-config > /tmp/effective.json # needs no target +$ sed 's/max_changes/max_change/' /tmp/my-preset.json > /tmp/bad-preset.json +$ redline fuzz --preset=/tmp/bad-preset.json --dump-config +[fuzz] --preset=/tmp/bad-preset.json: config: unknown tunable 'generators.ShapeChange.max_change' (redline fuzz --help-tunables lists them) +$ redline fuzz --preset=/tmp/my-preset.json --jobs=32 --duration=36000 --out=/tmp/night +``` + +The full dump lists every weight, every tunable and every strategy parameter, with the values of your preset. +An unknown generator, tunable, strategy or key stops `redline fuzz` before any d8 starts. +`redline fuzz --help-tunables` lists the tunable names. `redline mutate --list` lists the generator and mutator names. + +### 8.3 Rules for presets + +- Do not raise the weight of a generator that resembles one known bug. The A/B results must stay valid for every preset. +- Keep `WasmModule` at weight 0, except in the `wasm` preset. The A/B experiment compares JavaScript-only runs. +- Measure a preset with section 10 before you commit it. A new preset also needs `redline selftest --offline`: it loads every preset. + +--- + +## 9. Debug a stage + +### 9.1 The shell + +The shell runs each stage on one program. [TUTORIAL.md](TUTORIAL.md) section 5.4 explains it. Useful commands: + +| Command | Stage | +|---|---| +| `mutate NAME SEED`, `generate NAME SEED`, `random N` | Mutate | +| `run`, `run verbose` | Execute | +| `accept N` | Accept: N runs, then the deterministic and the flaky edges | +| `reduce NAMES ORACLE` | Minimize | +| `tree`, `scopes`, `info`, `diff`, `check` | FAST and the syntax oracle | + +The shell reads commands from stdin, so you can script a reproduction: + +```sh +printf 'generate AtomicsOps 3\nrun\naccept 10\n' | redline shell /tmp/contrib/seeds/TypedArrayDecl-0-0.js +``` + +### 9.2 Captures and stage logs + +A capture saves the programs of a stage when a trigger fires: + +| Stage | Triggers | +|---|---| +| mutate | `timeout`, `crash`, `failed`, `invalid`, `noop`, `interesting` | +| check | `flaky`, `timeout` | +| minimize | `rejected`, `timeout` | +| prefix | `noop` | + +```sh +redline fuzz ... --capture='mutate:timeout:NegateCondition:20;check:flaky:20' +redline fuzz ... --stage-log=check,minimize +``` + +The first command saves up to 20 timeouts of `NegateCondition` and up to 20 flaky candidates in `OUT/captures/<stage>/`. +The second command writes one event per check and per minimization in `OUT/events.jsonl`. +[TUTORIAL.md](TUTORIAL.md) section 7.7 shows how to read the event log. + +### 9.3 A crash + +A crash goes to `OUT/crashes/` with the minimized program (`.js`), the original program (`.orig.js`) and a report (`.txt`). +The report has the crash signature and the result of the reproduction runs. +`redline minimize --oracle=crash FILE` runs the program with the same prelude as a session, and minimizes it again. +If the crash needs earlier programs, the `.history/` directory of the crash has them. + +--- + +## 10. Measure a change + +A change to a component changes the whole session. Only a comparison of two sessions shows its effect. + +### 10.1 A local A/B run + +Run two sessions at the same time, with the same d8, flags, seed and number of workers. Change only one thing: + +```sh +COMMON=(--d8=$REDLINE_D8 --d8-extra-args="--single-threaded --random-seed=42" --preset=default + --jobs=8 --seed=42 --duration=600 --stats-interval=60 --no-component-stats) +redline fuzz "${COMMON[@]}" --out=/tmp/ab/base > /tmp/ab/base.log 2>&1 & +redline fuzz "${COMMON[@]}" --mutator-weights=NegateCondition=1 --out=/tmp/ab/negate > /tmp/ab/negate.log 2>&1 & +wait +``` + +Compare the coverage at the same elapsed time. The `stats` events of `events.jsonl` have it: + +```sh +python3 - /tmp/ab/base/events.jsonl /tmp/ab/negate/events.jsonl <<'EOF' +import json, sys +runs = [[json.loads(line) for line in open(path, errors="replace")] for path in sys.argv[1:]] +series = [{round(e["t"] / 60): e for e in run if e["event"] == "stats"} for run in runs] +for minute in sorted(set(series[0]) & set(series[1])): + a, b = series[0][minute], series[1][minute] + print(f"{minute:4d} min base {100 * a['coverage']:.3f}% change {100 * b['coverage']:.3f}% " + f"diff {100 * (b['coverage'] - a['coverage']):+.3f} pp execs {a['executions']} / {b['executions']}") +EOF +``` + +The result of this run: + +``` + 1 min base 4.309% change 4.623% diff +0.314 pp execs 41350 / 41916 + 2 min base 5.867% change 5.455% diff -0.413 pp execs 79525 / 71356 + ... + 9 min base 8.175% change 7.902% diff -0.273 pp execs 228442 / 219440 + 10 min base 8.335% change 8.232% diff -0.103 pp execs 238887 / 233144 +``` + +The sign of the difference changed after one minute, and the difference stayed below 0.5 points. +This short run shows no effect of `NegateCondition`. It does not show that the mutator is useless. + +### 10.2 Read the result correctly + +- Ten minutes show only the start of a session. Use at least one hour on a workstation, and repeat the run. +- Two identical sessions differ by 0.25 to 0.35 percentage points. A difference below 0.5 points is probably noise. +- Compare at the same elapsed time first: a slower component must pay for its time. The same number of executions gives a second view. +- For bugs, use the d8 with known bugs and the time to the first crash of each bug. + +--- + +## 11. Checklist for a CL + +The [redline-presubmit](skills/redline-presubmit/SKILL.md) skill turns this +checklist into commands and a report. + +- [ ] `autoninja -C out/redline redline` builds without a warning. +- [ ] `git cl format` reports nothing for your files, and `clang-tidy` reports no new findings in them. +- [ ] Every new number is a tunable with a name, a range and a description. +- [ ] `redline selftest --offline` passes. You examined the diff of the golden traces. +- [ ] Validity: at least 99.8% of the programs of a new generator or mutator are accepted. +- [ ] `--run`: the share of failures and timeouts is known and explained in the CL description. +- [ ] Audit: no crash signature above 0.5% for a new or changed generator. +- [ ] A/B: a change of a weight, a strategy or a default has a measured result in the CL description. +- [ ] [TUTORIAL.md](TUTORIAL.md), [DESIGN.md](DESIGN.md) and this guide are still correct. diff --git a/deps/v8/experimental/redline/CPPLINT.cfg b/deps/v8/experimental/redline/CPPLINT.cfg new file mode 100644 index 000000000000..66cd2c16c265 --- /dev/null +++ b/deps/v8/experimental/redline/CPPLINT.cfg @@ -0,0 +1,7 @@ +# cpplint settings for experimental/redline. The code uses the V8 style +# (`git cl format`). The rules below turn off two cpplint checks that do not fit +# a standalone tool: +# build/c++11: Redline is a standalone executable and uses std::thread, +# std::mutex and <chrono> directly; +# runtime/int: `static_cast<unsigned long long>` for printf("%llu"). +filter=-build/c++11,-runtime/int diff --git a/deps/v8/experimental/redline/DEPS b/deps/v8/experimental/redline/DEPS new file mode 100644 index 000000000000..5936ebff6784 --- /dev/null +++ b/deps/v8/experimental/redline/DEPS @@ -0,0 +1,10 @@ +include_rules = [ + # Redline is a standalone executable (like d8) that brings up its own + # platform for the in-process syntax oracle. + "+include/libplatform/libplatform.h", + # The lexer and the printer use V8's number conversions and character + # classes, so that they read and print literals and identifiers as V8 does. + "+src/base/vector.h", + "+src/numbers/conversions.h", + "+src/strings/char-predicates-inl.h", +] diff --git a/deps/v8/experimental/redline/DESIGN.md b/deps/v8/experimental/redline/DESIGN.md new file mode 100644 index 000000000000..3a9865021b9a --- /dev/null +++ b/deps/v8/experimental/redline/DESIGN.md @@ -0,0 +1,482 @@ +# Redline design + +This document describes how Redline works and why. It does not describe the commands. +[README.md](README.md) gives an overview and the build steps. [TUTORIAL.md](TUTORIAL.md) shows the commands. +[CONTRIBUTE.md](CONTRIBUTE.md) shows how to change each part. +Source paths are relative to `experimental/redline/`. Paths such as `test/mjsunit` are relative to the root of the V8 checkout. +`OUT` is the output directory of a session. + +## 1. Goals + +Redline is a coverage-guided JavaScript fuzzer for V8. +It mutates JavaScript programs, runs them in an instrumented d8, and keeps the programs that reach new code in V8. +It is C++ code in the V8 tree, so that the V8 team can own and change it. It builds on Linux only, because it uses Linux process and memory APIs. + +1. **Understandable.** A V8 engineer can follow and debug every step. +2. **Changeable.** An engineer can change one step without changes to the other steps. Each decision is a strategy behind one interface. +3. **Configurable.** One configuration sets every part of a session. A preset is a configuration for one area of V8, for example Maglev. +4. **Plain JavaScript.** Redline imports any script that V8 parses, for example the tests in `test/mjsunit`. + Each corpus program and each crash is a plain JavaScript file. +5. **Observable.** Each stage and each component reports statistics. A session writes an event log. +6. **Useful crash reports.** Redline groups crashes, makes reproducible crashes smaller, and searches for the conditions that reproduce the other crashes. + +## 2. Principles + +- **KISS.** The fuzzing loop is a fixed sequence of stages in plain C++ code. There is no plugin framework and no dynamic graph. + Strategies make the decisions that can change from one session to the next. +- **DRY.** One interface and one registry template serve the four selection points. + One configuration holds every setting, and the command-line flags are shorthands for its keys. +- **In-tree C++.** Redline builds with the V8 build files and links V8. The V8 parser in the Redline process is the syntax oracle. +- **No magic numbers.** A new number in a generator, a mutator or a reducer must be a tunable: + a named number with a default, a range and one line of documentation (`core/tunable.h`). +- **Each component runs alone.** The shell (`redline shell`) applies one mutator, generator or reducer to one program. + `redline mutate`, `redline minimize`, `redline exec` and `redline amplify` run one part on files. +- **Missing data is normal.** A stage must work, possibly with less effect, when optional data is missing. + For example, a generator must also work at the start of a program, where no variable is visible. +- **Pinned behavior.** Golden traces record the picks of the default strategies and the output of each generator and mutator for fixed seeds. + A change of behavior shows as a diff. + +## 3. Terms + +| Term | Meaning | +|---|---| +| target | The instrumented d8 that Redline runs. It speaks the REPRL protocol and writes edge coverage to shared memory. | +| worker | A thread that owns one target and runs the fuzzing loop. | +| program | A JavaScript program, held as a FAST tree and its printed source. Its tree and its source do not change. | +| FAST | The typed JavaScript AST of Redline (`fast/`). | +| corpus | The programs that Accept admitted. All workers share one corpus. | +| candidate | A program that reached new edges. Accept decides if it enters the corpus. | +| component | A generator, a mutator or a reducer. A component has a name, a description and statistics. Generators and mutators also have a weight. | +| strategy | A pluggable policy for one decision, for example the choice of the next seed. | +| prelude | JavaScript that Redline puts in front of each program when it runs the program. The corpus does not store it. | + +## 4. Architecture + +### 4.1 Code layout + +| Directory | Contents | +|---|---| +| `main.cc`, `commands/` | The command-line tool, with one file per command. | +| `base/` | Flags, logging, JSON, files, subprocesses, and the V8 parser in the Redline process. | +| `exec/` | The REPRL client, the coverage map, the target options, and one plain d8 run for the amplify step. | +| `fast/` | FAST: the AST, the arena, the lexer, the parser, the printer and the scope analysis. | +| `core/` | `Program`, `Builder`, `Environment`, `Component`, the random generator, the selection interface and the tunables. | +| `generators/`, `mutators/` | The generators with their shared expression synthesis (`CodeGen`), and the mutators. | +| `corpus/` | The shared corpus and the seed and partner strategies. | +| `minimizer/` | The minimizer and its reducers. | +| `engine/` | The configuration, the stages, the fuzzer and its workers, the shared coverage, the crash signatures, the amplify step, the importer and the prelude. | +| `presets/`, `testdata/` | The presets, and the golden traces of the offline selftest. | + +### 4.2 The fuzzing loop + +```mermaid +flowchart LR + init["Init (once)"] --> pick["Pick"] + pick --> prefix["Prefix"] + prefix --> mutate["Mutate"] + mutate --> exec["Execute"] + exec -->|"new edges"| accept["Accept"] + accept -->|"admitted"| minimize["Minimize"] + minimize --> publish["Publish"] + publish --> more{"chain shorter than N?"} + accept -->|"dropped"| more + exec -->|"nothing new"| more + exec -->|"crash"| triage["Crash triage"] + more -->|"yes"| mutate + more -->|"no"| pick + triage --> pick +``` + +Init runs first (5.1). Then each worker runs this loop: + +1. The worker picks a corpus program, the seed. While the corpus is small, it sometimes starts from the empty program (5.1). +2. It puts fresh value declarations at the top of the seed (the prefix, 5.3). +3. It applies a chain of up to N mutations (`stages.mutate.consecutive`) and runs each result in its target. + A result that runs without an error becomes the parent of the next link. After a failure or a timeout, the next link uses the same parent. +4. A result with new edges goes to Accept. If Accept admits it, Minimize makes a smaller copy, and Publish adds the copy to the corpus. + The chain continues from the result as it ran, because minimization would remove material that the next mutations can use. +5. A result that crashes goes to crash triage, and the chain ends. +6. After N links, the worker picks a new seed. + +### 4.3 Observability + +- Each component counts its invocations, results, executions, outcomes, new edges and time (`core/component.h`). + Each stage counts its invocations, executions, time, timeouts and successes (`engine/stages.h`). A session prints these tables at an interval. +- The event log `OUT/events.jsonl` has one JSON object per event. The `start` event records the effective configuration and the strategies. + The `stats` event records the counters of the session and of the stages. +- Each stage has three switches. `log` writes one event per occurrence. `capture` saves the programs of the stage when a trigger fires. + `stats` adds a row to the stage table. +- Each corpus file starts with its lineage: its origin, its parent and its position in the chain. + +## 5. Stages + +The worker loop in `engine/fuzzer.cc` calls the stages in a fixed order. The stages delegate their decisions to strategies and components. +The stage statistics use the names `pick`, `prefix`, `mutate`, `check`, `minimize` and `publish`. `check` is the determinism check of Accept. + +| Stage | What it does | Configuration | +|---|---|---| +| Init | fills the corpus with imported files, or lets the workers generate programs | `init` | +| Pick | picks a seed and, for `Splice` and `Combine`, a partner | `selection.seeds`, `selection.partners` | +| Mutate | adds a prefix, then applies a chain of mutations | `selection.mutators`, `selection.generators`, `stages.prefix`, `stages.mutate` | +| Execute | runs a program in the target of the worker | `d8`, `d8_args`, `timeout_ms` and other target keys | +| Accept | decides if a candidate enters the corpus | `accept`, `stages.check` | +| Minimize | makes a new corpus program or a crash smaller | `stages.minimize`, `crash_minimizer` | +| Publish | adds the program to the corpus and saves it | `stages.publish` | +| Crash triage | groups, reproduces, amplifies, minimizes and saves crashes | `amplify` and the crash keys | + +### 5.1 Init + +The `init` block selects one of two strategies: + +- `import` loads JavaScript files (`paths`). With `keep: new-coverage`, a file stays only if it runs without an error and reaches new edges. + With `keep: all`, each file that runs without an error stays. Use `keep: all` to continue a session from its corpus directory. +- `generate` imports nothing. Its parameter `programs` sets `initial_programs`. + +While the corpus has fewer than `initial_programs` programs, a worker starts a chain from the empty program with a probability of one half. +It always does so while the corpus is empty. This rule also applies after an import. +A chain from the empty program uses only the `CodeGen` mutator until a result runs without an error. + +The importer replaces top-level `load()` and `d8.file.execute()` calls with the statements of the loaded file, so that each program is self-contained. +It removes the loads of `mjsunit.js`, because the prelude supplies their functions. It also removes the loads that it cannot resolve. +The V8 parser in the Redline process checks each imported file before the file runs in a target. + +### 5.2 Pick + +Pick chooses the next seed. For `Splice` and `Combine`, it also chooses a partner: a second corpus program that supplies code. +The seed strategy and the partner strategy share one registry. The corpus calls them with its lock held, so they can keep plain state. + +| Strategy | Picks | +|---|---| +| `uniform` | each program with the same probability. This is the default seed strategy. | +| `recency` | a part of the picks from the newest programs, and the other picks uniformly | +| `tournament` | the program with the fewest picks among a few random programs | +| `productive` | the program with the most children among a few random programs | +| `rarity` | the program with the highest energy (see below) | +| `uniform-partner` | a random program other than the seed. This is the default partner strategy. | +| `rarity-partner` | the program with the highest energy among a few random programs | + +The `rarity` strategy prefers programs that reach rare edges, are small and had few picks (`corpus/corpus.cc`): + +```text +energy(p) = rarity(p) / ((age(p) + 1)^age_exponent * (1 + ln(size(p))^size_exponent)) +rarity(p) = sum over the tracked edges e of p with count(e) < rare_edge_limit of 1 / count(e)^rarity_exponent +``` + +- `count(e)` is the number of corpus programs that reach edge `e`. The age grows with each pick. +- A new corpus program records its rarest edges from its full edge set (5.7), or from its new edges if the set is missing. +- The edges of a reproducible crash count as one more program. This lowers the energy of the programs that lead to a known crash. + +### 5.3 Mutate + +A **generator** makes new statements for one insertion point. It declares what its code needs from the context, for example a loop for `continue`. +Redline uses a generator only where the context allows it. Generated code uses only the variables that are visible and initialized at that point. + +A **mutator** changes a program. Mutators insert generated code (`CodeGen`, `JitStress`), change code in place (`Input`, `Operation`, `Expression`, `Call`), +copy code from a partner (`Splice`, `Combine`), change the structure (`Remove`, `Wrap`, `Duplicate`, `Reorder`), or ask the target (`Explore`, `Probing`). +`redline mutate --list` shows the mutators and generators with their weights. A weight of 0 disables a mutator or a generator. + +One link of the chain works like this: + +1. The mutator strategy picks a mutator. A mutator that needs a partner is eligible only when the corpus has at least two programs. +2. `ApplyMutation` copies the tree of the parent. The mutator edits the copy through a `Builder` (9.3). + It makes from one change up to its own maximum, or exactly `stages.mutate.rounds` changes if that value is above 0. +3. If the mutator finds nothing to do, the link costs no execution. Otherwise, the worker prints the tree and runs the source. + +**Prefix.** The prefix gives the mutators new values to work with. It uses only generators whose code cannot throw, +because an exception in the prefix would make each result of the chain fail. Minimize removes the values that a new corpus program does not use. +The `Prefix` mutator makes the prefix. Its weight is 0, so that the mutator strategy does not pick it. + +**Runtime-assisted mutators.** A type guess from the source does not tell which properties a value has. `Explore` and `Probing` ask the target instead. +They insert probes, and the worker runs the instrumented program once with a helper script in front. +The helper writes its findings to the fuzzout channel. The mutator turns the findings into ordinary code and removes the probes. +`Explore` examines a variable and does an action that fits its value. `Probing` installs properties that the program asks an object for but the object does not have. + +**Environment.** Generators use a hand-written model of the globals, methods and runtime functions of d8 (`core/environment.h`). +At the start of a session, one target runs an introspection script that lists its globals and their members. +With this list, the `DiscoveredApi` generator and `Explore` also reach builtins that the model does not describe. + +**Strategies.** `weighted` is the default: one weighted random draw among the eligible components. +`adaptive` moves the weights toward the components with a higher recent yield (`core/adaptive_selector.h`). +With `reward: edges`, the yield is new edges per target execution spent. These executions include the reruns, the minimizer tests and the crash triage of the results. +The weight stays between `min_factor` and `max_factor` times the base weight, because the yield of a component changes as the corpus grows. + +### 5.4 Execute + +The target is the fuzzing build of d8, which has sanitizer coverage and the REPRL interface. [TUTORIAL.md](TUTORIAL.md) shows how to build it. +Redline starts the target once and sends it many programs over the REPRL protocol (`exec/reprl.h`). +The target gets two control pipes and two data channels. +One data channel carries the script. The other carries the text that the script sends back through a builtin of the fuzzing build (fuzzout). +For each execution, Redline writes the script, sends a command and waits for a status word, the death of the target or the timeout. + +| Outcome | Meaning | +|---|---| +| `succeeded` | The script ended with status 0. | +| `failed` | The script ended with an uncaught exception or a nonzero exit status. | +| `crashed` | The target died from a signal. | +| `timed_out` | The script ran longer than the timeout. Redline kills the target. | + +- Redline replaces the target after a timeout, after a crash and after `max_execs_before_respawn` executions. This limits the state in one process. +- After an infrastructure failure, Redline tries the execution again once with a fresh target. Ten such failures in a row stop the session. +- A session uses a short timeout (`FuzzConfig::Load` in `engine/config.cc`), because a mutant that runs longer is almost always an endless loop. +- By default, the target decides if a program is valid: an uncaught SyntaxError without a stack frame marks it invalid. + With `syntax_check`, the V8 parser in the Redline process checks each mutant first. +- The default prelude defines the mjsunit assertion functions so that they do not throw. + +**Coverage.** Each target has its own coverage map: POSIX shared memory with the edge count and one bit per edge. +Redline clears the bitmap before each execution and reads it after the execution. +Only successful executions count for coverage, so the corpus holds only programs that run to the end. Crashes have a separate set of crash bits. +All workers share one map of the edges that the session found (`engine/shared_coverage.h`). +A worker claims new edges with atomic operations, so two workers never claim the same edge. If no corpus program results, the worker gives the edges back. + +### 5.5 Accept + +Accept decides if a candidate enters the corpus. It has two parts: + +1. **Criterion.** The `accept` block names the criterion. The only criterion is `new-edges`: + a result is a candidate if it claims at least one edge that the session did not find before. +2. **Determinism check** (`stages.check`). The target is not deterministic, because concurrent compilation and garbage collection change the edges of a run. + Thus Redline runs the candidate again: + - It runs the candidate at least `min_reruns` times, and until the set of new edges stays the same for `min_stable_reruns` runs. + - An edge that a rerun does not reach leaves the set. Redline gives the edge back, so that a later program can claim it. + - An edge that fails the check `flaky_threshold` times stays claimed. It costs no more reruns, and it does not count as coverage. + - If a rerun fails, or if the set does not settle within `max_reruns` runs, Redline drops the candidate. + +**The oracle.** When Accept admits a program, it also sets the property that Minimize must keep. +For `new-edges`, the property is "the program runs without an error and reaches all its new edges that survived the check". +Accept computes this property once and freezes it. The property does not depend on the corpus at a later time. + +This rule keeps Minimize generic. Minimize sees only an oracle, not the criterion. +Thus a reducer must work with any oracle, and a new criterion must supply its own frozen oracle. + +### 5.6 Minimize + +Minimize makes a program smaller while its oracle stays true. +For a crash that reproduces alone, the oracle is "the program crashes with the same signature", so the minimizer cannot move to a different bug. + +| Reducer | What it removes or replaces | +|---|---| +| `statements` | chunks of statements of halving size from the end of each statement list, down to single statements | +| `unwrap` | a block, an `if`, a loop, a `try` or an immediately invoked function, replaced by its body | +| `lists` | call arguments, array elements, object properties, class members, declarators and parameters | +| `expressions` | an expression, replaced by one of its operands or by a constant | +| `truncate` | all top-level statements after the shortest prefix that keeps the oracle true | +| `dataflow` | the top-level statements that the rest of the program does not use, from a def-use graph of the scope analysis | + +The default order is `statements`, `unwrap`, `lists`, `expressions` (`Minimizer::DefaultOrder`). `stages.minimize.reducers` sets another list. +The def-use graph only proposes a cut. The oracle decides, because globals, prototypes or getters can connect statements that share no binding. + +- The minimizer runs its reducers in rounds until a round changes nothing or the budget ends. + A reducer edits the tree and asks the oracle. If the oracle says no, the reducer undoes the edit. +- The budget limits the tests, the time and the rounds. It has fewer tests for slow programs (`target_time_ms`). + Crashes have a larger budget (`crash_minimizer`), because they are rare. +- Each test has a short timeout from the run time of the program (`probe_timeout_*`), because a reduction can make an endless loop. + For the same reason, `expressions` replaces a loop condition only with `0`. +- The result must pass the oracle again in one of `verify_attempts` runs. If it does not, Redline keeps the original program. + +### 5.7 Publish + +Publish sets the new edges and the run time of the program. +If a strategy asks for the full edge set, Publish runs the program two more times and keeps the edges that both runs reach. +Then it adds the program to the shared corpus, which gives the program its id. +It writes `OUT/corpus/NNNNNN.js` and a `corpus_add` event. + +### 5.8 Crash triage + +A crash can come from a result, from an imported file or from an instrumented program. + +1. **Signature.** For a V8 fatal error, the signature is the file, the line and the check message. + For a sanitizer report, it is the kind of error and the first function. For a signal, it is the signal and the first three named frames (`engine/crash.h`). + For a stack overflow, the functions that repeat in the trace name the crash, because the first frames depend on where the stack ran out. +2. **Budget.** Redline saves at most `max_crashes_per_signature` crashes of one signature, and minimizes at most `minimize_crashes_per_signature` of them. +3. **Reproduction.** Redline runs the program again in a fresh target, up to `crash_reruns` times. +4. **History replay.** If the crash does not reproduce alone, Redline replays the earlier programs of the same target, and then the crash. + If the crash then occurs, a binary search finds the smallest number of programs from the end of this history that cause it. +5. **Amplify.** If the crash does not reproduce alone, the amplify step searches for d8 flags that make it reproduce. + This also applies after a successful replay, because an earlier program can turn on a feature that a d8 flag can also turn on. +6. **Minimize.** Redline minimizes a crash that reproduces alone, against its signature. +7. **Save.** Redline writes the program, the report and, if they exist, the original program and the history to `OUT/crashes/`. + +History replay and the amplify step run only for crashes that Redline saves. + +**Amplify.** Some crashes depend on timing, for example on a profiler signal or a GC at one moment. +One run in a fresh target does not show them, and ClusterFuzz cannot reproduce them either. +The amplify step searches for a plain d8 command line that reproduces the crash reliably, because ClusterFuzz accepts a testcase together with its d8 flags. +The `flags` strategy (`engine/amplifier.cc`) works like this: + +- The candidates are the flags of the stack rules that match the crash output, and then no extra flags. + For example, a rule adds the CPU profiler flags for profiler frames. +- Each candidate runs fresh d8 processes with `--stress-runs` and a new `--random-seed`. It succeeds when `min_hits` of `processes` runs crash with the same signature. +- d8 stops the stress loop at the first uncaught exception. Thus, if the program ends with an uncaught exception, + the candidates run on a copy with all statements in one try statement (`wrap`). +- The amplify step runs at most `per_signature` times for one signature in a session. +- The report gets the flags in `amplified_args`. A tool that uploads the crash must send these flags with the testcase. + +The `none` strategy turns the amplify step off. + +## 6. Data flow + +- A **program** (`core/program.h`) holds the FAST tree, the printed source, a hash of the source and the lineage. + Seed strategies keep their state in the program under the corpus lock. +- An **execution** (`exec/execution.h`) holds the outcome, the exit code or the signal, the run time, and the text from fuzzout, stdout and stderr. + The coverage bitmap stays in the coverage map of the worker until the next execution. +- The **edges** of a candidate are the new edges that its worker claimed. After Accept, the edges that survived become the edges of the program. + +A stage reads only the data that it needs. A strategy that needs optional data declares it, and the engine computes the data only in that case. +For example, `WantsHitEdges` asks for the full edge set. A strategy has a fallback when the data is missing. + +## 7. Strategies and registries + +The four selection points (seeds, partners, mutators and generators) use one interface, `Selector<T>`, and one registry template, `SelectorRegistry<T>` (`core/selection.h`). + +- A strategy is one C++ class and one registration line. The registry keeps its name, its documentation and its parameters (`ParamSpec`). +- At startup, the configuration loader builds each configured strategy once. + An unknown strategy, parameter or weight name, or a wrong type, stops the session before any target starts. +- The registry writes the strategy part of `redline fuzz --help-config`. +- Strategies get feedback through hooks: `OnAdded` (a new corpus program), `OnOutcome` (the result of a pick) and `OnCrashEdges` (the edges of a reproducible crash). +- All workers share the mutator and generator strategies. Such a strategy must keep no state between calls, or it must synchronize its state. + +```json +{"selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, + "mutators": {"strategy": "adaptive", "params": {"weights": {"Splice": 4}}}}} +``` + +Some parts are pluggable without this registry. The amplify strategies come from `CreateAmplifyStrategy` (`engine/amplifier.cc`), with the same `ParamSpec` declarations. +The loader checks the names of the Init strategies and Accept criteria (`ReadInitConfig`, `ReadAcceptConfig`). +The minimizer finds reducers by name (`stages.minimize.reducers`). + +## 8. Configuration and presets + +One JSON configuration describes a session. `FuzzConfig` (`engine/config.h`) defines the keys and their defaults. +`redline fuzz --dump-config` prints the complete effective configuration. It needs no target, and the loader reads its output back to the same configuration. + +The configuration comes from four layers. A later layer wins: + +1. the built-in defaults, +2. the preset (`--preset`), +3. the configuration of `--config`: a file, or inline JSON that starts with `{`, +4. the command-line flags. + +Inline JSON can set any key, so a key does not need its own flag. In one JSON object, the `stages` block wins over the older flat keys. +The loader checks the names inside the blocks: stages, capture triggers, Init, Accept, amplify, strategies, parameters, weights, tunables and reducers. +A wrong name stops the session before any target starts. +The loader ignores unknown top-level keys, and unknown keys in some blocks, for example in `selection` and in `crash_minimizer`. + +**Presets.** `--preset=NAME` loads `presets/NAME.json`, and `--preset=FILE.json` loads any file. +A preset can add d8 flags for its area (`d8_extra_args`) and change the weights of generators and mutators. +Each preset selects `rarity`, `rarity-partner` and `adaptive`. Without a preset, the defaults are `uniform`, `uniform-partner` and `weighted`. + +| Preset | d8 flags added | Higher weights | +|---|---|---| +| `default` | none | none | +| `maglev` | `--maglev --no-turbofan --jit-fuzzing` | JIT, deoptimization, OSR, elements-kind and shape generators | +| `turbolev` | `--turbolev --turbolev-future --jit-fuzzing` | the same generators as `maglev` | +| `runtime` | `--no-turbofan --no-maglev --no-sparkplug` | property, prototype, proxy, freeze and shape generators. The JIT generators are off. | +| `parser` | none | class, destructuring, arrow, template, label, `using`, `eval` and `with` generators, and `Splice` and `Combine` | +| `builtins` | none | discovered-API, builtin-call, method-call, string, typed-array, collection and worker generators | +| `wasm` | none | `WasmModule`, and JIT, OSR and typed-array generators | + +The `WasmModule` generator builds WebAssembly modules that are valid by construction. +Its default weight is 0, so a session without the `wasm` preset generates no WebAssembly modules. +A preset must not raise the weight of a generator that resembles one known bug (section 10 tells why). + +## 9. FAST + +FAST is the typed JavaScript AST of Redline (`fast/`). Redline does not use the AST of V8 for two reasons. +The V8 parser desugars some constructs before its AST is visible, for example the `let` bindings of `for` loops. +Also, the AST of V8 lives in a Zone that belongs to an Isolate. + +### 9.1 The tree and node ids + +- The tree has the shape of ESTree, the AST format of tools such as acorn and esprima. + Each literal type has its own node kind, and so do `%Name(...)` runtime calls. The printer derives the parentheses from precedence. +- One X-macro list in `fast/ast.h` defines all node kinds. `ForEachChildSlot` (`fast/ast_visit.h`) has no default case, so the compiler reports a new kind that it does not handle. +- Nodes are plain structs in an arena that belongs to one program. The arena owns all nodes, so a mutator can detach a subtree and forget it. +- Each node has an id that is unique in its tree. `Tree::Copy` keeps the ids, so an id that the shell shows stays valid in the next mutation step. + The ids are dense, so analyses keep facts per node in vectors indexed by id, not in hash maps. + +### 9.2 Parser, printer and syntax oracle + +- The parser (`fast/parser.cc`) is a recursive-descent parser for scripts: ES2024, plus the V8 extensions that tests use. It does not parse modules. +- The parser does not report early errors that keep the tree shape, for example duplicate declarations. V8 is the validity oracle instead. + The parser must reject what FAST cannot represent, and it must never make a tree that prints to a program with a different meaning. +- The printer (`fast/printer.cc`) always writes semicolons. Its output parses back to a tree that prints to the same text. +- The syntax oracle (`SyntaxChecker` in `base/v8_runtime.h`) compiles a script but never runs it. The target executes each program. + +### 9.3 Scope analysis and the Builder + +- The scope analysis (`fast/scope.h`) resolves each identifier to its binding. Each mutation that moves, removes or adds code uses it. + It is a static approximation of the specification. It marks scopes with direct `eval` or `with` as dynamic, and it marks bindings in cases that it does not model, for example Annex B. +- `redline roundtrip --rename` tests the analysis. It renames each binding that it can rename safely, and checks that the program behaves the same. +- Mutators and generators edit a program through a `Builder` (`core/builder.h`): a copy of the tree, its analyses and edit operations. + The Builder knows the syntactic context of each position and the visible variables, each with a coarse type guess. The guess is not a type system. +- `EscapingBindings` finds the declarations that a removal or a move would separate from their uses. `Remove`, `Wrap` and `Reorder` use it. + +### 9.4 New JavaScript features + +The goal: when V8 gets a new JavaScript feature, FAST must represent it and Redline must generate it. + +A compile-time check cannot enforce this goal. A new feature often adds no V8 AST node type, and V8 AST nodes do not map one to one to syntax. +Two tests enforce the goal instead, at the point where V8 engineers already add tests: + +1. **FAST must represent the feature.** A new feature comes with `test/mjsunit` tests. + `redline roundtrip --dir=test/mjsunit` parses, prints and runs each file. It fails until FAST parses and prints the new syntax. +2. **Redline must generate the feature.** `redline selftest --offline` fails if a FAST node kind comes out of no generator. + The exceptions are on a list with a reason each (`kUngeneratedKinds` in `commands/selftest_selection.cc`). + The check also fails when a listed kind starts to appear, so that the list stays current. + +## 10. Checks + +These checks protect the design. [CONTRIBUTE.md](CONTRIBUTE.md) tells when to run them. + +- `redline selftest --offline` needs no target. It checks the golden traces, the configuration, the crash signatures, the FAST node kinds and the presets. +- `redline selftest --d8=PATH` also checks the execution layer against a real target. +- `redline roundtrip --dir=test/mjsunit` checks that V8 and FAST agree on validity, and that each printed program behaves like the original. +- `redline audit` checks generators for overfitting. It generates programs with each generator and runs them in a d8 with known bugs. + It fails if one crash signature takes more than `--threshold` percent of the programs of one generator. + +Such a generator is a template of one bug. It finds that bug again, and little else. +A lower weight does not solve the problem: the weight changes how often the generator runs, not what its programs do. Make the generator more general instead. + +The V8 bots build Redline, because the root `BUILD.gn` adds it to `gn_all` on Linux. The bots do not run these checks. + +## 11. Measuring a change + +[CONTRIBUTE.md](CONTRIBUTE.md) shows how to compare two sessions. + +## 12. Threading and memory + +A session is one process. The main thread loads the configuration, starts the targets and starts one thread per worker (`jobs`). +Then it only checks the stop conditions and writes the statistics. +A worker owns its target, its coverage map, its random generator, its isolate for the syntax oracle and its crash history. + +| Shared state | Protection | +|---|---| +| corpus, and the seed and partner strategies | a mutex. Programs do not change, so a worker uses a program without the lock. | +| seen edges and crash edges | atomic operations on 64-bit words | +| mutator and generator strategies | no state between calls, or a mutex of their own (`adaptive`) | +| flaky-edge counts, crash bookkeeping, event log | a mutex each | +| counters | atomic counters | + +- Each worker seeds its random generator from the session seed and its worker number. + With one worker and a deterministic target, a session with the same seed repeats the same steps. + Time limits can change the steps, for example the time budget of the minimizer and the time window of `adaptive`. +- Each tree has its own arena. The arena takes memory in segments from a pool of its thread, and gives them back when the tree dies. + Thus a tree costs only bump allocation. +- Programs are immutable and shared (`std::shared_ptr<const Program>`). A mutation copies the tree. +- The corpus keeps each program for the whole session, so memory grows with the corpus. +- All isolates of the syntax oracle share one pointer-compression cage. Thus each isolate has small heap limits and compiles lazily. + +## 13. Design decisions + +| Decision | Reason | +|---|---| +| Mutate a typed AST of plain JavaScript. | Redline imports any script that V8 parses, without loss. The scope analysis keeps edits valid. | +| Keep the parser lenient, with V8 as the validity oracle. | FAST and V8 cannot disagree about validity. | +| Keep the target alive over REPRL, and replace it from time to time. | A new process for each program is slow. A process that lives for a long time collects state. | +| Check candidates for determinism, and suppress flaky edges. | Without the check, noise fills the corpus. Without the suppression, an edge that never settles costs reruns forever. | +| Freeze the oracle at acceptance. | Minimize and the reducers stay independent of the criterion. | +| Group crashes by signature, with a budget per signature. | The work per bug stays bounded. | +| Replay the history of a crash, and search for amplifying flags. | Some crashes depend on earlier programs or on timing. | +| Put the prelude in front of each execution, and never store it. | Corpus files stay clean, and imported tests run without `mjsunit.js`. | +| Run all workers in one process, with one corpus and one coverage map. | The workers need no protocol to exchange programs. | +| Keep the pipeline fixed, and make the decisions pluggable. | The loop stays easy to read, and a decision can change without a change to the loop. | diff --git a/deps/v8/experimental/redline/GEMINI.md b/deps/v8/experimental/redline/GEMINI.md new file mode 100644 index 000000000000..c1aa8b822447 --- /dev/null +++ b/deps/v8/experimental/redline/GEMINI.md @@ -0,0 +1,17 @@ +# Redline agent instructions + +Read the documentation in this directory before you change, review or test code +in `experimental/redline/`: + +- [README.md](README.md): what Redline is, the quick start (`out/fuzzbuild/d8` + and `out/redline`), the directory layout and the code conventions. +- [DESIGN.md](DESIGN.md): the architecture, the stages and the design rules. +- [TUTORIAL.md](TUTORIAL.md): the commands, from the build to a fuzzing session + with your own configuration. +- [CONTRIBUTE.md](CONTRIBUTE.md): how to add or change a component. Section 10 + tells how to measure a change, and section 11 is the checklist for a CL. Read + this file before you change or review code. + +Before you upload a change to `experimental/redline/`, do the checks of the +[redline-presubmit](skills/redline-presubmit/SKILL.md) skill. Put its report in +the CL description. diff --git a/deps/v8/experimental/redline/README.md b/deps/v8/experimental/redline/README.md new file mode 100644 index 000000000000..1fea3cdbcc75 --- /dev/null +++ b/deps/v8/experimental/redline/README.md @@ -0,0 +1,152 @@ +# Redline + +Redline is a coverage-guided JavaScript fuzzer for V8, written in C++ in the V8 tree. +It runs a fuzzing build of d8, the *target*, as a persistent child process. +Redline sends each program to the target over the REPRL protocol, and it reads the edge coverage from shared memory. + +Redline parses each program into FAST, its typed syntax tree. +Generators write new code, mutators change the tree, and a printer writes the tree back as JavaScript. +Redline keeps the programs that reach new edges in V8, and it makes them smaller. +It groups the crashes by signature, and it minimizes the crashes that reproduce. +The corpus programs and the crash files are plain JavaScript files. + +## Status + +- Redline is experimental, and it builds only on Linux. +- The V8 bots compile Redline on Linux, because the root `BUILD.gn` adds `experimental/redline` to `gn_all`. +- The bots do not run the Redline tests yet. Run the [checks](#checks) before you upload a change. + +## Quick start + +You need a Linux x64 workstation, a V8 checkout, and depot_tools in your `PATH`. +Run all commands from the root of the V8 checkout. +[TUTORIAL.md](TUTORIAL.md) explains each step in more detail. + +### Build the fuzzing d8 + +The target is a d8 with coverage instrumentation and the REPRL loop: + +```shell +gn gen out/fuzzbuild --args='is_debug=false dcheck_always_on=true v8_enable_debug_code=true v8_static_library=true v8_enable_verify_heap=true v8_fuzzilli=true v8_enable_backtrace=true v8_enable_partition_alloc=false v8_enable_builtins_profiling=true sanitizer_coverage_flags="inline-bool-flag" target_cpu="x64" use_remoteexec=true' +autoninja -C out/fuzzbuild d8 +``` + +### Build Redline + +Redline itself needs no coverage instrumentation: + +```shell +gn gen out/redline --args='is_debug=false target_cpu="x64" use_allocator_shim=false use_remoteexec=true' +autoninja -C out/redline redline +``` + +If you do not have remote build execution, remove `use_remoteexec=true` from the arguments of both builds. +Keep the binary in `out/redline`. Redline finds its presets and test data in `experimental/redline`, two directories above its binary. +`out/redline/redline help` lists the commands. `out/redline/redline help <command>` lists the flags of one command. + +### Check the build + +```shell +out/redline/redline selftest --offline +out/redline/redline selftest --d8=out/fuzzbuild/d8 +``` + +The first command runs the checks that need no target. +The second command runs the same checks, and then it checks the execution layer against the target. +Both commands print `PASS` or `FAIL` for each check, and a summary at the end: + +```text +... +PASS presets: maglev.json loads +... +selftest: <n> passed, 0 failed +``` + +### Run a short session + +Fuzz Maglev for one minute with the built-in preset `maglev`: + +```shell +out/redline/redline fuzz --d8=out/fuzzbuild/d8 --preset=maglev --jobs=4 --duration=60 --out=/tmp/redline-maglev +``` + +```text +[<time> I] [fuzz] session: 4 worker(s), seed <n>, <n> edges in target, 0 file(s) to import, seeds rarity, partners rarity-partner, mutators adaptive, generators adaptive, output /tmp/redline-maglev +[<time> I] [fuzz] 00:00:30 | execs <n> (<n>/s) | cov <n>% (<n> edges) | corpus <n> | ok <n>% fail <n>% timeout <n>% | ... +... +[<time> I] [fuzz] final: 00:01:00 | execs <n> (<n>/s) | cov <n>% (<n> edges) | corpus <n> | ... +``` + +- `--preset=maglev` loads `experimental/redline/presets/maglev.json`. + This preset adds the d8 flags `--maglev`, `--no-turbofan` and `--jit-fuzzing`, and it gives higher weights to some generators. +- `--jobs=4` starts four workers. Each worker runs its own d8. +- Without seed files, the session starts from generated programs. `--import=DIR` adds the `.js` files of a directory as seed files. +- Without `--duration`, the session runs until you press Ctrl-C. +- The output directory gets the corpus, the crashes and the event log `events.jsonl`. + +## Documentation + +- [DESIGN.md](DESIGN.md): the architecture, with the fuzzing loop, the stages, the strategies, the configuration and FAST. +- [TUTORIAL.md](TUTORIAL.md): build Redline, explore the components, and write and run your own configuration. +- [CONTRIBUTE.md](CONTRIBUTE.md): add or change components, run the checks before you upload, and measure a change. + +## Directory layout + +| Directory | Contents | +|---|---| +| `base/` | Flags, logging, JSON, files, time, subprocesses, and the in-process V8 parser that checks the syntax. | +| `commands/` | One file for each command, for example `fuzz`, `shell` and `selftest`. `main.cc` selects the command. | +| `core/` | Programs, the `Builder`, the `Environment`, components, random numbers, tunables, AST helpers, and the selection interface. | +| `corpus/` | The shared corpus, and the seed and partner strategies. | +| `engine/` | The configuration, the fuzzer and its workers, the stages, the shared coverage, the crash signatures, the amplify step, the importer and the prelude. | +| `exec/` | The REPRL client, the coverage map, the script runner, the target options, and the plain d8 runs of the amplify step. | +| `fast/` | FAST: the syntax tree, the arena, the lexer, the parser, the printer and the scope analysis. | +| `generators/` | The code generators, the expression synthesis that they share (`CodeGen`), and the Wasm module generator. | +| `minimizer/` | The minimizer and its reducers. | +| `mutators/` | The mutators. `Explore` and `Probing` run the program in the target before they choose a change. | +| `presets/` | The built-in presets: one JSON configuration for each area of V8. | +| `testdata/` | The golden traces of `redline selftest --offline`. [testdata/README.md](testdata/README.md) describes them. | + +## Code conventions + +Redline uses the V8 code style. Run `git cl format` before you upload. +These files add settings for `experimental/redline` only: + +- `CPPLINT.cfg`: it turns off two cpplint checks that do not fit a standalone tool. Its comments give the reasons. + `git cl lint` runs cpplint on the files of your change. +- `.clang-tidy`: the `bugprone`, `cert`, `clang-analyzer`, `cppcoreguidelines`, `modernize` and `performance` checks, and some `readability` checks. + The findings of `bugprone`, `clang-analyzer` and `performance` are errors. + The comments at the top of the file give the reasons for the checks that it turns off. +- `BUILD.gn`: Redline compiles with `-Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wunused -Werror`. + The C++ files also get `-Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual`. + The V8 and third-party headers count as system headers, so these flags apply only to the Redline code. + +To run clang-tidy, write a compilation database for the `redline` target, and give it to clang-tidy: + +```shell +gn gen out/redline --add-export-compile-commands=//experimental/redline:redline +third_party/llvm-build/Release+Asserts/bin/clang-tidy -p out/redline experimental/redline/corpus/corpus.cc +``` + +`gclient sync` downloads clang-tidy if your `.gclient` file sets `"checkout_clang_tidy": True` in `custom_vars`. + +## Checks + +The bots do not run these checks yet. Run them before you upload a change: + +```shell +out/redline/redline selftest --offline +out/redline/redline selftest --d8=out/fuzzbuild/d8 +out/redline/redline roundtrip --dir=test/mjsunit --no-run +``` + +- `selftest --offline` compares the picks and the outputs of the default components with the golden traces in `testdata/`. + It also loads each preset and checks the configuration. +- `selftest --d8=PATH` runs the same checks, and then it checks the execution layer against the target. +- `roundtrip --no-run` checks the FAST parser and printer on each file below `test/mjsunit`. + FAST must accept each file that V8 accepts. + FAST and V8 must accept each printed program, and a second print must give the same text. + +[CONTRIBUTE.md](CONTRIBUTE.md) has the full checklist for a change. +The [redline-presubmit](skills/redline-presubmit/SKILL.md) skill turns this +checklist into commands and a report. diff --git a/deps/v8/experimental/redline/TUTORIAL.md b/deps/v8/experimental/redline/TUTORIAL.md new file mode 100644 index 000000000000..f55f8331397b --- /dev/null +++ b/deps/v8/experimental/redline/TUTORIAL.md @@ -0,0 +1,784 @@ +# Redline tutorial + +This tutorial is for V8 developers who want to fuzz the part of V8 that they work on. + +Redline is a coverage-guided JavaScript fuzzer for V8. It runs a fuzzing build of d8 as a child process. +It changes JavaScript programs, runs them in d8, and keeps the programs that reach new code in V8. + +## Goal + +At the end of this tutorial, you have these items: + +- a fuzzing d8 in `out/fuzzbuild/d8`, +- a Redline binary in `out/redline/redline`, +- your own configuration file for one area of V8, +- a fuzzing session that runs your configuration against your d8, +- a procedure to reproduce and minimize a crash. + +This tutorial uses typed arrays as the example area. +For your area, do the same steps with your own components and seed files. + +You need a Linux x64 workstation, because Redline builds only on Linux. +You also need a V8 checkout, and depot_tools in your `PATH`. + +Run all commands from the root of your V8 checkout. +The example files of this tutorial go into `/tmp/redline-tutorial`: + +```shell +mkdir -p /tmp/redline-tutorial +``` + +The output samples come from real runs. +Values that change from run to run, for example times, edge counts and rates, show as `<n>`. + +Contents: + +1. [Build the fuzzing d8](#1-build-the-fuzzing-d8) +2. [Build Redline](#2-build-redline) +3. [Run one program](#3-run-one-program) +4. [Examine the syntax tree and the scopes](#4-examine-the-syntax-tree-and-the-scopes) +5. [Try the components](#5-try-the-components) +6. [Presets and configuration layers](#6-presets-and-configuration-layers) +7. [Fuzz your area](#7-fuzz-your-area) +8. [Next steps](#8-next-steps) + +## 1. Build the fuzzing d8 + +Redline does not execute JavaScript in its own process. +A d8 with coverage instrumentation executes every program. This d8 is the *target*. +Build the target: + +```shell +gn gen out/fuzzbuild --args='is_debug=false dcheck_always_on=true v8_enable_debug_code=true v8_static_library=true v8_enable_verify_heap=true v8_fuzzilli=true v8_enable_backtrace=true v8_enable_partition_alloc=false v8_enable_builtins_profiling=true sanitizer_coverage_flags="inline-bool-flag" target_cpu="x64" use_remoteexec=true' +autoninja -C out/fuzzbuild d8 +``` + +If you do not have remote build execution, remove `use_remoteexec=true` from the arguments. + +| Argument | What it does | +|---|---| +| `is_debug=false` | Makes a release build. d8 runs faster, so Redline runs more programs. | +| `dcheck_always_on=true` | Keeps the `DCHECK` assertions in the release build. A failed `DCHECK` is a crash for Redline. | +| `v8_enable_debug_code=true` | Makes the d8 flag `--debug-code` available. This flag adds assertions to the code that V8 generates. | +| `v8_static_library=true` | Builds the V8 libraries as static libraries instead of source sets. | +| `v8_enable_verify_heap=true` | Compiles the heap verifier (`VERIFY_HEAP`) into d8. | +| `v8_fuzzilli=true` | Adds the REPRL loop and the shared-memory coverage map to d8. Redline uses both. | +| `v8_enable_backtrace=true` | Makes d8 print a stack trace when it crashes. Redline uses the top frames for crash signatures. | +| `v8_enable_partition_alloc=false` | Makes d8 use the system allocator instead of PartitionAlloc. | +| `v8_enable_builtins_profiling=true` | Makes d8 report the basic blocks of the builtins as additional coverage edges. | +| `sanitizer_coverage_flags="inline-bool-flag"` | Gives each edge of the C++ code a flag byte. After each execution, d8 copies the flags into the coverage map. | +| `target_cpu="x64"` | Builds for x64. | +| `use_remoteexec=true` | Uses remote build execution. | + +REPRL (read, eval, print, reset loop) keeps one d8 process alive. +Redline sends a program, d8 runs it and reports the result, and then d8 waits for the next program. + +## 2. Build Redline + +Redline is a normal V8 executable. It needs no coverage instrumentation. +Build it in its own output directory: + +```shell +gn gen out/redline --args='is_debug=false target_cpu="x64" use_allocator_shim=false use_remoteexec=true' +autoninja -C out/redline redline +``` + +If you do not have remote build execution, remove `use_remoteexec=true` from the arguments. +`use_allocator_shim=false` keeps the system `malloc`. +With the allocator shim, all worker threads of Redline share one PartitionAlloc lock and lose CPU time to it. + +Keep the binary in `out/redline`. +Redline looks for its presets and its test data in `experimental/redline`, two directories above its binary. +`out/redline/redline help` lists the commands. `out/redline/redline help <command>` lists the flags of one command. + +### 2.1 Check the two binaries + +Run the checks that need no target: + +```shell +out/redline/redline selftest --offline +``` + +```text +... +PASS presets: maglev.json loads +... +selftest: <n> passed, 0 failed +``` + +Then run the checks against the fuzzing d8: + +```shell +out/redline/redline selftest --d8=out/fuzzbuild/d8 +``` + +```text +... +PASS REPRL handshake and coverage initialization +INFO instrumented edges: <n> +PASS empty script succeeds: succeeded (exit code 0, signal 0, <n> ms) +PASS uncaught exception is reported as failed: failed (exit code 1, signal 0, <n> ms) +... +selftest: <n> passed, 0 failed +``` + +The second command checks the execution layer: the REPRL handshake, the outcomes, the output capture, the coverage and the restart of d8. +If a check fails, examine the build of the target first. + +## 3. Run one program + +Write this program to `/tmp/redline-tutorial/first.js`: + +```javascript +function sum(ta) { + let s = 0; + for (let i = 0; i < ta.length; i++) s += ta[i]; + return s; +} +const ta = new Uint8Array([1, 2, 3]); +print(sum(ta)); +``` + +Run it three times in the target: + +```shell +out/redline/redline exec --d8=out/fuzzbuild/d8 --repeat=3 --print-output /tmp/redline-tutorial/first.js +``` + +```text +[<time> I] [exec] Target: out/fuzzbuild/d8 --expose-gc --expose-externalize-string --omit-quit --allow-natives-syntax --fuzzing --harmony --experimental-fuzzing --js-staging --wasm-staging --wasm-fast-api --expose-fast-api --wasm-test-streaming +[<time> I] [exec] <n> edges instrumented +/tmp/redline-tutorial/first.js [run 1]: succeeded in <n> ms, <n> edges hit, <n> new, <n> found total (<n>%) +---- stdout (2 bytes) ---- +6 +... +/tmp/redline-tutorial/first.js: <n> edges hit in every run, <n> in at least one run (<n> non-deterministic) +[<time> I] [exec] 3 executions: 3 succeeded, 0 failed, 0 crashed, 0 timed out; 1 spawns +``` + +The output shows what the fuzzer sees: + +- The first line shows the d8 flags. `--d8-extra-args="..."` adds flags. `--d8-args="..."` replaces all of them. +- An *edge* is a transition between two basic blocks of V8 code. Coverage is the set of edges that successful executions reach. +- Some edges change from run to run, because of concurrent GC and compiler threads. Thus Redline runs a program again before it trusts its new edges. + +| Outcome | Meaning | +|---|---| +| `succeeded` | The program ran to its end. | +| `failed` | The program threw an uncaught exception. Its edges do not count as coverage. | +| `crashed` | d8 stopped with a signal, for example after a failed `DCHECK`. | +| `timed_out` | The program did not stop before the timeout. | + +## 4. Examine the syntax tree and the scopes + +Redline does not edit program text. It parses each program into FAST, its typed syntax tree in the shape of ESTree. +The generators and mutators change the tree, and a printer writes the tree back as JavaScript. + +Print the program as Redline prints it, with node ids: + +```shell +out/redline/redline parse --print --ids /tmp/redline-tutorial/first.js +``` + +```text +/*n1*/ function sum(ta) { + let s = 0; // n5 + /*n13*/ for (let i = 0; i < ta.length; i++) + s += ta[i]; // n21 + return s; // n27 +} +const ta = new Uint8Array([1, 2, 3]); // n29 +print(sum(ta)); // n38 +``` + +Each node of the tree has an id. A node keeps its id until a mutation removes the node. +`--ids` shows the ids of the statements only. A statement on one line gets `// nN` at its end. +A statement that contains other statements, for example a function or a loop, gets `/*nN*/` in front. + +Print the scope analysis: + +```shell +out/redline/redline parse --scopes /tmp/redline-tutorial/first.js +``` + +```text +script scope n0 (Program) + function sum (n2): 1 refs, pinned [n40] + const ta (n31): 1 refs, pinned [n41] + function scope n1 (FunctionDeclaration) + param ta (n3): 2 refs [n15 n24] + let s (n7): 2 refs, assigned [n22 n28] + block scope n13 (ForStatement) + let i (n11): 3 refs, assigned [n14 n19 n26] +globals: Uint8Array print +... +``` + +A scope line gives the kind of the scope and the id of the node that makes the scope. +A binding line, for example `let s (n7): 2 refs, assigned [n22 n28]`, has these parts: + +- `let s`: the kind and the name of the binding. +- `(n7)`: the id of the identifier node that declares the binding. +- `2 refs [n22 n28]`: the number of references, and the ids of the identifier nodes that reference the binding. The list shows at most eight ids. +- `assigned`: the program assigns a new value to the binding. +- `pinned`: Redline does not rename the binding, because a rename can change the behavior. For example, code in `eval` can reach a script-level binding by its name. + +The ids in the binding lines are ids of identifier nodes inside statements. +`--ids` prints only the statement ids, so you do not find most of these ids in the printed source. +No `parse` flag prints the id of every node. The `tree` command of the shell prints them: + +```shell +printf 'tree 38\n' | out/redline/redline shell /tmp/redline-tutorial/first.js +``` + +```text +... +redline> tree 38 +ExpressionStatement #38 + CallExpression #43 print(sum(ta)) + Identifier #39 print + CallExpression #42 sum(ta) + Identifier #40 sum + Identifier #41 ta +(6 nodes in the subtree) +``` + +`n40` and `n41` are the references of `sum` and `ta` in the binding lines above. +`tree` without an id prints the whole program. + +The scope analysis keeps the mutations plausible. +Generated code uses only the variables that are visible and initialized at its position. + +## 5. Try the components + +Redline has three kinds of components: + +- A *generator* writes new code, for example a typed array declaration. +- A *mutator* changes a program, for example it replaces a variable or an operator. The `CodeGen` mutator inserts the code of the generators. +- A *reducer* makes a program smaller while a condition, the *oracle*, stays true. + +*Strategies* make the decisions of a session: the next corpus program, its partner program, the mutator and the generator. + +### 5.1 List the components + +```shell +out/redline/redline mutate --list # mutators and generators, with their default weights +out/redline/redline minimize --list # reducers +out/redline/redline fuzz --help-config # the configuration format, and the strategies with their parameters +out/redline/redline fuzz --help-tunables # the numbers inside the components +``` + +A weight is a relative probability. +The selection strategies do not pick a component with weight 0, but the commands of this section can apply it. + +Find the components for your area: + +```shell +out/redline/redline mutate --list | grep -i typed +``` + +```text + TypedArrayDecl w=1 let ta = new XArray(...) + TypedArrayOps w=1.5 typed array element access, detach, views +``` + +### 5.2 Generators + +Show the code that a generator writes: + +```shell +out/redline/redline mutate --generate --generator=TypedArrayOps --n=3 --print +``` + +```text +----- TypedArrayOps #0: 2 statements ----- +let ta0 = new Uint8Array(["0", "constructor", "true", "a"]); +ta0.set(ta0); +----- TypedArrayOps #1: 2 statements ----- +const ta0 = new Uint8ClampedArray(1174); +const v0 = ta0.byteLength; +... +``` + +`--generate` starts from an empty program. +Then run the results in the target: + +```shell +out/redline/redline mutate --generate --generator=TypedArrayDecl,TypedArrayOps --n=20 --run --d8=out/fuzzbuild/d8 --quiet +``` + +The table has one line for each generator. +`executed` counts the programs that ran, and `ok%` is the share of programs that succeeded. +`fail`, `tmo` and `crash` count the failures, the timeouts and the crashes. +`new` counts the programs that reached new edges. + +A program that fails stops at the exception, so the code after it does not run. +Give a high weight only to generators whose programs usually succeed. + +### 5.3 Mutators + +Apply two mutators to your program: + +```shell +out/redline/redline mutate --mutator=Input,Operation --n=2 --seed=10 --print /tmp/redline-tutorial/first.js +``` + +```text +----- Input #0: input i -> ta ----- +function sum(ta) { + let s = 0; + for (let i = 0; ta < ta.length; i++) +... +----- Operation #0: number 0 -> -1 ----- +function sum(ta) { + let s = (-1); +... +``` + +The header of each result names the mutator and the change. +With `--seed=S`, sample `i` uses the seed `S+i`. The same seed gives the same result on the same program. +`Splice` and `Combine` need a second program. Give it with `--partner=FILE`. + +### 5.4 The shell + +The shell is a workbench for one program. +Apply generators, mutators and reducers one at a time, run the result, and undo a step. + +```shell +out/redline/redline shell --d8=out/fuzzbuild/d8 /tmp/redline-tutorial/first.js +``` + +```text +redline> generate TypedArrayOps 1 +=> TypedArrayOps (seed 1): inserted 1 statement(s): 50 nodes, V8 accepts ++ ta.set(ta); +redline> run +succeeded in <n> ms, exit 0; <n> edges +redline> generate JitOptimize 2 +=> JitOptimize (seed 2): inserted 6 statement(s): 71 nodes, V8 accepts ++ %PrepareFunctionForOptimization(sum); ++ sum(); +... +redline> run +failed (uncaught exception) in <n> ms, exit 1; <n> edges (+<n> new, -<n> gone since the previous run) + stdout: fuzzcode.js:71: TypeError: Cannot read properties of undefined (reading 'set') +... +redline> undo +undid generate JitOptimize seed=2; 50 nodes +``` + +The second argument of `generate` and `mutate` is the seed. +The first generator used the parameter `ta`, because `ta` is visible at the insertion point. +The second generator added a call `sum()` without an argument, so `ta.set(ta)` threw a `TypeError`. +Type `help` in the shell for all commands. +The shell reads its commands from stdin, so you can also give them with `printf`, as in section 4. + +### 5.5 Reducers + +Minimize your program, and keep its output: + +```shell +out/redline/redline minimize --d8=out/fuzzbuild/d8 --oracle=output /tmp/redline-tutorial/first.js +``` + +```text +function sum() { + let s = 0; + for (let i = 0; i < ta.length; i++) + s += ta[i]; + return s; +} +const ta = [1, 2, 3]; +print(sum()); +``` + +The program still prints `6`. +The reducers removed the parameter and the argument, and they replaced the typed array by an array. +A reducer keeps only what its oracle measures. + +| Oracle | The reduced program must | +|---|---| +| `edges` (default) | reach the same stable edges. With `--baseline=FILE`, only the edges that `FILE` does not reach count. | +| `crash` | crash. Any crash is sufficient. | +| `fail` | throw the same uncaught exception, with the same type and message. | +| `output` | have the same outcome and print the same output. | + +`--reducer=NAME,...` runs only these reducers, in this order. +Without it, `minimize` runs all reducers. +A session runs only `statements`, `unwrap`, `lists` and `expressions`, unless the configuration key `stages.minimize.reducers` names other reducers. + +### 5.6 Selection strategies + +`fuzz --help-config` lists the strategies for the four decisions of a session: + +| Decision | Configuration key | Strategies | +|---|---|---| +| the next corpus program (the seed) | `selection.seeds` | `uniform` (default), `recency`, `tournament`, `productive`, `rarity` | +| the partner for `Splice` and `Combine` | `selection.partners` | `uniform-partner` (default), `rarity-partner` | +| the mutator | `selection.mutators` | `weighted` (default), `adaptive` | +| the generator | `selection.generators` | `weighted` (default), `adaptive` | + +- `rarity` prefers small programs that reach rare edges and that Redline used less often. Use `rarity-partner` with it. +- `weighted` uses the weights as they are. +- `adaptive` moves the weight of each component toward its recent yield of new edges per execution. A weight stays between `min_factor` and `max_factor` times its base weight. + +All built-in presets use `rarity`, `rarity-partner` and `adaptive`. +The seed and partner strategies work only in a session. +The flag `--scheduler=NAME` of `fuzz` sets the seed strategy for one session. + +## 6. Presets and configuration layers + +A *preset* is a JSON configuration for one area of V8, for example `maglev`, `runtime` or `wasm`. +The built-in presets are in `experimental/redline/presets/`. + +```shell +cat experimental/redline/presets/maglev.json +``` + +```json +{ + "d8_extra_args": ["--maglev", "--no-turbofan", "--jit-fuzzing"], + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "JitOptimize": 8, "Deopt": 3, "OsrLoop": 3, "ElementsKind": 4, "ShapeChange": 3}}}} +} +``` + +- `d8_extra_args` adds flags to the d8 flags, like `--d8-extra-args`. +- `selection` sets the strategies. `weights` sets the base weight of the named generators. The other generators keep their default weights. + +`--preset=maglev` loads `presets/maglev.json`. `--preset=FILE.json` loads any file. + +Redline makes the effective configuration from four layers. A later layer wins: + +1. the built-in defaults, +2. the preset (`--preset=NAME` or `--preset=FILE`), +3. the configuration (`--config=FILE`, or inline JSON such as `--config='{"jobs": 4}'`), +4. the command-line flags. + +These rules apply when the layers merge: + +- Each layer adds its `d8_extra_args` to the d8 flags. The flag `--d8-extra-args` adds more flags. +- A `params` object in `selection` replaces the `params` object of an earlier layer. For example, the `weights` of your file replace all the weights of the preset. +- The flags `--generator-weights`, `--mutator-weights`, `--disable-generator` and `--disable-mutator` change single weights. The other weights stay. +- The flag `--import` adds files to the seed files of the configuration. + +Print the effective configuration: + +```shell +out/redline/redline fuzz --preset=maglev --dump-config +``` + +The output lists every key, every weight and every tunable with its value. +The command needs no target. +You can edit the output and give it back with `--config`. + +## 7. Fuzz your area + +### 7.1 Select the components and the seed files + +Use sections 5.1 to 5.3 for your area. For typed arrays, this tutorial uses: + +- the generators `TypedArrayDecl` and `TypedArrayOps`, and also `JitOptimize` and `Deopt` for the optimizing compilers, +- some typed array tests of `test/mjsunit` as seed files, +- the d8 flag `--jit-fuzzing`, which lowers the JIT tiering thresholds, +- the strategies of the built-in presets. + +Redline imports `.js` files and directories. It replaces each `load()` call of a test by the loaded file. +At execution time, Redline puts a small prelude before each program. +The prelude defines the mjsunit assertion functions, which never throw, and empty `load` and `quit` functions. + +### 7.2 Write the configuration file + +Write this file to `/tmp/redline-tutorial/typedarray.json`: + +```json +{ + "d8_extra_args": ["--jit-fuzzing"], + "init": {"strategy": "import", "params": {"paths": [ + "test/mjsunit/es6/typedarray.js", + "test/mjsunit/es6/typedarray-detached.js", + "test/mjsunit/es6/typedarray-set-length.js", + "test/mjsunit/compiler/typedarray-keyed.js", + "test/mjsunit/compiler/typed-array-constructor.js" + ]}}, + "selection": { + "seeds": {"strategy": "rarity"}, + "partners": {"strategy": "rarity-partner"}, + "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "TypedArrayDecl": 6, "TypedArrayOps": 8, "JitOptimize": 6, "Deopt": 2}}} + }, + "tunables": {"generators.TypedArrayOps.max_args": 3} +} +``` + +| Key | Meaning | +|---|---| +| `d8_extra_args` | The d8 flags for your area. Redline adds them to its default d8 flags. | +| `init` | The seed files and directories. Redline keeps a seed file only if it reaches new edges. | +| `selection` | The strategies and the generator weights. The other generators keep their default weights. | +| `tunables` | The numbers inside the components. Here, a typed array method call gets up to three arguments. | + +The paths of the seed files are relative to the directory where you start Redline. +Keep the session settings, for example `--jobs` and `--out`, on the command line. +Then the same file can also be a preset (section 7.9). + +### 7.3 Check the configuration + +Print the effective configuration, and look at your values: + +```shell +out/redline/redline fuzz --config=/tmp/redline-tutorial/typedarray.json --dump-config > /tmp/redline-tutorial/effective.json +grep -E '"(TypedArrayDecl|TypedArrayOps|JitOptimize|Deopt)"|TypedArrayOps.max_args' /tmp/redline-tutorial/effective.json +``` + +```text + "TypedArrayDecl": 6, + "TypedArrayOps": 8, + "JitOptimize": 6, + "Deopt": 2, + "generators.TypedArrayOps.max_args": 3, +``` + +Also make sure that `d8_args` ends with `--jit-fuzzing`, and that `init.params.paths` lists your seed files. + +Redline checks the names in the `init`, `selection`, `stages` and `tunables` blocks before it starts d8. +A wrong name stops the command with an error, for example: + +```text +[<time> E] [fuzz] selection.generators: unknown generator in weights: TypedArrayOp +``` + +Redline does not check the top-level keys. +It ignores a top-level key that it does not know, for example `"jobz"`. +It also ignores `d8_extra_args` if the value is not a list. +Thus, always compare the output of `--dump-config` with your file. + +### 7.4 Run the session + +```shell +out/redline/redline fuzz --d8=out/fuzzbuild/d8 --config=/tmp/redline-tutorial/typedarray.json --jobs=4 --duration=120 --out=/tmp/redline-typedarray +``` + +- `--jobs=N`: the number of worker threads. Each worker runs its own d8 process. +- `--duration=SEC`: stop after `SEC` seconds. Without this flag, the session runs until you stop it. +- `--out=DIR`: the output directory. Use a new directory for each session. Redline adds to an existing `events.jsonl` and writes over old corpus files. + +Start with a short session, as above. +When the session works, start a long session without `--duration`. +For an unknown flag, `fuzz` shows a warning, for example `unknown flag --jobz (ignored)`. + +### 7.5 Read the progress output + +```text +[<time> I] [fuzz] environment: <n> globals/namespaces with <n> members discovered in the target +[<time> I] [fuzz] session: 4 worker(s), seed <n>, <n> edges in target, 5 file(s) to import, seeds rarity, partners rarity-partner, mutators adaptive, generators adaptive, output /tmp/redline-typedarray +[<time> I] [fuzz] import done: 5 files, 5 added, 0 redundant, 0 failed; coverage <n>%, corpus 5 +[<time> I] [fuzz] 00:00:30 | execs <n> (<n>/s) | cov <n>% (<n> edges) | corpus <n> | ok <n>% fail <n>% timeout <n>% | invalid <n>% noop <n> | crashes 0 (0 sigs, 0 repro) | cands <n> flaky <n> | min <n> tests (<n>% of execs, <n>% of time) | exec <n>% busy | avg exec <n> ms | avg nodes <n> (corpus <n>) (+<n>) +... +[<time> I] [fuzz] final: 00:02:00 | execs <n> (<n>/s) | cov <n>% (<n> edges) | corpus <n> | ... +``` + +The first lines: + +- `environment`: d8 lists its globals at the start. The `DiscoveredApi` generator uses this list. +- `session`: the workers, the seed of the session and the strategies. +- `import done`: the result of the seed files. An `added` file reached new edges. A `redundant` file reached no new edges. A `failed` file threw an exception, timed out or crashed. + +Examine the `import done` line first. A seed file that fails does not go into the corpus. + +After each interval of `--stats-interval` seconds, Redline prints a status line: + +| Field | Meaning | +|---|---| +| `00:00:30` | The time since the start of the session. | +| `execs` | All executions in d8, and the rate per second. | +| `cov` | The edges that successful executions reached, as a share of all edges. | +| `corpus` | The number of programs in the corpus. | +| `ok`, `fail`, `timeout` | The outcomes of the mutated programs. | +| `invalid`, `noop` | The programs with a syntax error, and the mutations that changed nothing. | +| `crashes A (B sigs, C repro)` | The crashed executions, the different crash signatures, and the crashes that reproduced. | +| `cands`, `flaky` | The programs with new edges, and the candidates whose new edges did not stay stable. | +| `min` | The executions of the minimizer, as a share of all executions and of the worker time. | +| `exec ... busy` | The share of the worker time that d8 used. | +| `avg exec`, `avg nodes` | The mean execution time, and the mean size of the mutated programs and of the corpus programs. | +| `(+N)` | The new corpus programs since the last status line. | + +After each status line, Redline prints tables for the mutators, the reducers, the stages, the seed strategy and the generators. +`--no-component-stats` removes the tables. `--quiet` removes all periodic output. + +### 7.6 Stop the session + +Press Ctrl-C one time. +Redline stops the workers, prints the `final:` status line, and writes the `end` event: + +```text +[redline] stopping (press Ctrl-C again to abort) +[<time> I] [fuzz] final: 00:00:46 | execs <n> (<n>/s) | cov <n>% (<n> edges) | corpus <n> | ... +``` + +If you press Ctrl-C a second time, Redline stops immediately. Then the last line of `events.jsonl` can be incomplete. +The signal `SIGTERM` has the same effect as Ctrl-C. + +### 7.7 Examine the output directory + +```text +/tmp/redline-typedarray/ + corpus/000001.js one file for each corpus program + crashes/ the crashes and their reports + events.jsonl one JSON object for each event +``` + +Each corpus file starts with a lineage line, for example: + +```text +// redline corpus #120 | origin Input | parent #118 +1 | generation 10 | <n> new edges | 12 nodes | worker 3 | input f0 -> a0; input f0 -> obj2 +``` + +- `origin`: the mutator that made the program, or `import` for a seed file. +- `parent #118 +1`: the mutation chain started from corpus program 118, and this program is the first mutation of the chain. +- `generation`: the number of corpus ancestors of the program. +- The last part tells what the mutator changed. + +`events.jsonl` has these event kinds: `start`, `import`, `import_done`, `corpus_add`, `flaky`, `crash`, `stats` and `end`. +The `start` event records the effective configuration, so you can repeat a session. + +To continue a session, import its corpus into a new session: + +```shell +out/redline/redline fuzz --d8=out/fuzzbuild/d8 --config=/tmp/redline-tutorial/typedarray.json --import=/tmp/redline-typedarray/corpus --import-all --jobs=4 --out=/tmp/redline-typedarray-2 +``` + +`--import-all` keeps all programs that run successfully, also the programs without new edges. + +### 7.8 Reproduce and minimize a crash + +When a worker finds a crash, Redline does these steps: + +1. It runs the program again in a new d8, to find out if the crash reproduces. +2. If the crash does not reproduce alone, Redline runs the earlier programs of the same d8 before it. A crash that needs them is *state-dependent*. +3. If the crash still does not reproduce, Redline searches for d8 flags that make it reproduce. This is the amplify step. +4. Redline minimizes a reproducible crash. The minimized program must give the same crash signature. +5. Redline saves the files, and adds the signature to `crashes/signatures.txt`. + +The log shows one line for each saved crash: + +```text +[<time> W] [fuzz] CRASH [<signature>] (new crash edges, minimized) saved to /tmp/redline-typedarray/crashes/crash_sig6_<hash>.js +``` + +The file names contain the signal number and a hash: + +| File | Content | +|---|---| +| `crash_sig6_<hash>.js` | The minimized program, or the original program if Redline did not minimize it. | +| `crash_sig6_<hash>.orig.js` | The original program, if Redline minimized it. | +| `crash_sig6_<hash>.txt` | The report: the signature, the reproduction runs, the minimization, and the output of d8. | +| `crash_sig6_<hash>.history/` | For a state-dependent crash only: the programs to run first, in their order. | +| `signatures.txt` | One line for each crash signature. | + +The `.js` file starts with a header: + +```text +// redline crash: signal 6, minimized +// signature: <signature> +// reproducible (2/2 fresh-target runs crashed), worker 2 (target had run <n> programs), origin <origin>, parent #<n>, generation <n> +// d8 out/fuzzbuild/d8 --expose-gc --expose-externalize-string --omit-quit --allow-natives-syntax --fuzzing --harmony --experimental-fuzzing --js-staging --wasm-staging --wasm-fast-api --expose-fast-api --wasm-test-streaming --jit-fuzzing +``` + +The last header line is the d8 command line of the session. + +Reproduce the crash in the target, as the fuzzer does: + +```shell +CRASH=/tmp/redline-typedarray/crashes/crash_sig6_<hash>.js +out/redline/redline exec --d8=out/fuzzbuild/d8 --d8-extra-args=--jit-fuzzing --print-output "$CRASH" +``` + +```text +/tmp/redline-typedarray/crashes/crash_sig6_<hash>.js: crashed (signal 6) in <n> ms, <n> edges hit, 0 new, 0 found total (<n>%) +---- stderr (<n> bytes) ---- +... +``` + +`--d8-extra-args` adds the d8 flags of your configuration. Use the same flags as the session. + +Reproduce the crash without Redline, with the d8 command line of the header: + +```shell +$(sed -n 's|^// d8 ||p' "$CRASH") "$CRASH" +``` + +The crash files do not contain the prelude, and `exec`, `replay` and d8 do not add it. +If the program calls an mjsunit assertion function, it fails in these commands before it gets to the crash. +`redline minimize` adds the prelude, so use it for these programs. + +Minimize the crash again, for example with all reducers and a larger budget: + +```shell +out/redline/redline minimize --d8=out/fuzzbuild/d8 --d8-extra-args=--jit-fuzzing --oracle=crash --max-tests=1000 --out=/tmp/redline-tutorial/crash.min.js /tmp/redline-typedarray/crashes/crash_sig6_<hash>.orig.js +``` + +```text +[<time> I] [minimize] <n> -> <n> nodes (<n>%), <n> tests (<n> accepted, 0 syntax-rejected) in <n> s; property HOLDS on the result +``` + +The `crash` oracle of `minimize` accepts any crash, not only the signature of the session. +Run the result with `exec --print-output`, and compare its stderr with the report. + +After a change in V8, run all crash files of a session again: + +```shell +out/redline/redline replay --d8=out/fuzzbuild/d8 --d8-extra-args=--jit-fuzzing --corpus=/tmp/redline-typedarray/crashes +``` + +```text +[<time> W] [replay] /tmp/redline-typedarray/crashes/crash_sig6_<hash>.js crashed the target (signal 6) +[<time> W] [replay] /tmp/redline-typedarray/crashes/crash_sig6_<hash>.orig.js crashed the target (signal 6) +replay: 2 files (0 unreadable): 0 succeeded, 0 failed, 2 crashed, 0 timed out +``` + +`replay` runs every `.js` file below the directory in one d8, as a corpus import does. + +If the report says `NOT reproduced`, the crash needs a special timing or state of d8. +Run the amplify step again on this crash: + +```shell +out/redline/redline amplify --d8=out/fuzzbuild/d8 --d8-extra-args=--jit-fuzzing --crash=/tmp/redline-typedarray/crashes/crash_sig6_<hash>.txt "$CRASH" +``` + +`amplify` runs the program in new d8 processes with additional flags, for example `--stress-runs`. +It prints the flags that reproduce the crash as `amplified_args`. +For a state-dependent crash, run the files of the `.history/` directory in their order, and then the crash program. + +### 7.9 Make a named preset + +`--preset=NAME` loads `experimental/redline/presets/NAME.json`. +Copy your file into this directory, and check it: + +```shell +cp /tmp/redline-tutorial/typedarray.json experimental/redline/presets/typedarray.json +out/redline/redline selftest --offline +``` + +```text +... +PASS presets: typedarray.json loads +... +``` + +`selftest --offline` loads every file of the presets directory, as `fuzz --preset` does. +Then use the name of the preset: + +```shell +out/redline/redline fuzz --d8=out/fuzzbuild/d8 --preset=typedarray --jobs=4 --out=/tmp/redline-typedarray-3 +``` + +A preset is the second layer. Thus, a `--config` file and the flags can still change it. +If you want to share your preset with other V8 developers, read [CONTRIBUTE.md](CONTRIBUTE.md) before you upload it. + +## 8. Next steps + +- [CONTRIBUTE.md](CONTRIBUTE.md): add your own generator, mutator or reducer, if your area needs code that no component writes. +- [DESIGN.md](DESIGN.md): the architecture of Redline, the stages of a session and the strategies. diff --git a/deps/v8/experimental/redline/base/file_util.cc b/deps/v8/experimental/redline/base/file_util.cc new file mode 100644 index 000000000000..b07121d02696 --- /dev/null +++ b/deps/v8/experimental/redline/base/file_util.cc @@ -0,0 +1,193 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/file_util.h" + +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <algorithm> +#include <cerrno> +#include <cstdio> +#include <cstring> + +#include "experimental/redline/base/log.h" + +namespace redline { + +bool ReadFileToString(const std::string& path, std::string* contents, + std::string* error) { + FILE* file = fopen(path.c_str(), "rbe"); + if (file == nullptr) { + *error = StringPrintf("Cannot open %s: %s", path.c_str(), strerror(errno)); + return false; + } + contents->clear(); + char buffer[64 * 1024]; + while (true) { + size_t n = fread(buffer, 1, sizeof(buffer), file); + if (n > 0) { + contents->append(buffer, n); + } + if (n < sizeof(buffer)) { + break; + } + } + bool ok = ferror(file) == 0; + if (!ok) { + *error = + StringPrintf("Error reading %s: %s", path.c_str(), strerror(errno)); + } + fclose(file); + return ok; +} + +bool WriteStringToFile(const std::string& path, std::string_view contents, + std::string* error) { + FILE* file = fopen(path.c_str(), "wbe"); + if (file == nullptr) { + *error = + StringPrintf("Cannot create %s: %s", path.c_str(), strerror(errno)); + return false; + } + bool ok = + fwrite(contents.data(), 1, contents.size(), file) == contents.size(); + if (fclose(file) != 0) { + ok = false; + } + if (!ok) { + *error = + StringPrintf("Error writing %s: %s", path.c_str(), strerror(errno)); + } + return ok; +} + +bool MakeDirectories(const std::string& path, std::string* error) { + if (path.empty()) { + return true; + } + std::string current; + size_t start = 0; + while (start <= path.size()) { + size_t end = path.find('/', start); + if (end == std::string::npos) { + end = path.size(); + } + current = path.substr(0, end); + start = end + 1; + if (current.empty()) { + continue; + } + if (mkdir(current.c_str(), 0755) != 0 && errno != EEXIST) { + *error = StringPrintf("Cannot create directory %s: %s", current.c_str(), + strerror(errno)); + return false; + } + } + if (!IsDirectory(path)) { + *error = StringPrintf("%s exists but is not a directory", path.c_str()); + return false; + } + return true; +} + +bool IsDirectory(const std::string& path) { + struct stat st; + return stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode); +} + +bool FileExists(const std::string& path) { + struct stat st; + return stat(path.c_str(), &st) == 0; +} + +namespace { + +bool EndsWith(const std::string& text, const std::string& suffix) { + return text.ends_with(suffix); +} + +void ListFilesInto(const std::string& directory, const std::string& suffix, + std::vector<std::string>* out) { + DIR* dir = opendir(directory.c_str()); + if (dir == nullptr) { + return; + } + while (struct dirent* entry = readdir(dir)) { + std::string name = entry->d_name; + if (name == "." || name == "..") { + continue; + } + std::string path = directory; + path += '/'; + path += name; + struct stat st; + if (stat(path.c_str(), &st) != 0) { + continue; + } + if (S_ISDIR(st.st_mode)) { + ListFilesInto(path, suffix, out); + } else if (S_ISREG(st.st_mode) && EndsWith(name, suffix)) { + out->push_back(path); + } + } + closedir(dir); +} + +} // namespace + +std::vector<std::string> ListFiles(const std::string& directory, + const std::string& suffix) { + std::vector<std::string> files; + std::string root = directory; + while (root.size() > 1 && root.back() == '/') { + root.pop_back(); + } + struct stat st; + if (stat(root.c_str(), &st) != 0) { + return files; + } + if (S_ISREG(st.st_mode)) { + if (EndsWith(root, suffix)) { + files.push_back(root); + } + return files; + } + ListFilesInto(root, suffix, &files); + std::sort(files.begin(), files.end()); + return files; +} + +std::string BaseName(const std::string& path) { + size_t slash = path.find_last_of('/'); + if (slash == std::string::npos) { + return path; + } + return path.substr(slash + 1); +} + +std::string RedlineDataDir(const std::string& name) { + char buffer[4096]; + ssize_t n = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); + if (n <= 0) { + return ""; + } + std::string exe(buffer, static_cast<size_t>(n)); + size_t slash = exe.rfind('/'); + if (slash == std::string::npos) { + return ""; + } + for (const char* relative : {"/", "/../../experimental/redline/"}) { + std::string candidate = exe.substr(0, slash); + candidate += relative; + candidate += name; + if (IsDirectory(candidate)) { + return candidate; + } + } + return ""; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/file_util.h b/deps/v8/experimental/redline/base/file_util.h new file mode 100644 index 000000000000..1b2f970f62a6 --- /dev/null +++ b/deps/v8/experimental/redline/base/file_util.h @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_FILE_UTIL_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_FILE_UTIL_H_ + +#include <string> +#include <string_view> +#include <vector> + +namespace redline { + +// Reads a whole file. Returns false with a message if it cannot be read. +bool ReadFileToString(const std::string& path, std::string* contents, + std::string* error); + +// Writes `contents` to `path`, replacing any existing file. +bool WriteStringToFile(const std::string& path, std::string_view contents, + std::string* error); + +// Creates `path` and all missing parents. Succeeds if it already exists. +bool MakeDirectories(const std::string& path, std::string* error); + +bool IsDirectory(const std::string& path); +bool FileExists(const std::string& path); + +// Lists regular files below `directory` (recursively, following symlinks) +// whose names end with `suffix`, sorted by path. If `directory` is itself a +// matching file, returns just that file. +std::vector<std::string> ListFiles(const std::string& directory, + const std::string& suffix); + +// Last path component. +std::string BaseName(const std::string& path); + +// A data directory of redline (`testdata`, `presets`) found from the location +// of the binary: next to it (a deployed bundle), or in the source tree +// (out/<dir>/redline -> ../../experimental/redline/<name>). Empty if neither +// exists. +std::string RedlineDataDir(const std::string& name); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_FILE_UTIL_H_ diff --git a/deps/v8/experimental/redline/base/flags.cc b/deps/v8/experimental/redline/base/flags.cc new file mode 100644 index 000000000000..3244d7ef7dae --- /dev/null +++ b/deps/v8/experimental/redline/base/flags.cc @@ -0,0 +1,181 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/flags.h" + +#include <cerrno> +#include <cstdlib> + +#include "experimental/redline/base/log.h" + +namespace redline { + +bool ParseInt64(std::string_view text, int64_t* out) { + if (text.empty()) { + return false; + } + std::string buffer(text); + int64_t multiplier = 1; + char last = buffer.back(); + if (last == 'k' || last == 'K') { + multiplier = 1024; + } else if (last == 'm' || last == 'M') { + multiplier = static_cast<int64_t>(1024) * 1024; + } else if (last == 'g' || last == 'G') { + multiplier = static_cast<int64_t>(1024) * 1024 * 1024; + } + if (multiplier != 1) { + buffer.pop_back(); + } + if (buffer.empty()) { + return false; + } + errno = 0; + char* end = nullptr; + long long value = strtoll(buffer.c_str(), &end, 0); + if (errno != 0 || end == nullptr || *end != '\0') { + return false; + } + *out = static_cast<int64_t>(value) * multiplier; + return true; +} + +// static +Flags Flags::Parse(int argc, const char* const* argv, int start_index) { + Flags flags; + bool only_positional = false; + for (int i = start_index; i < argc; i++) { + std::string_view arg(argv[i]); + if (only_positional || !arg.starts_with("--")) { + flags.positional_.emplace_back(arg); + continue; + } + if (arg == "--") { + only_positional = true; + continue; + } + arg.remove_prefix(2); + size_t eq = arg.find('='); + if (eq != std::string_view::npos) { + flags.values_[std::string(arg.substr(0, eq))] = + std::string(arg.substr(eq + 1)); + } else if (arg.size() > 3 && arg.starts_with("no-")) { + flags.values_[std::string(arg.substr(3))] = "false"; + } else { + flags.values_[std::string(arg)] = "true"; + } + } + return flags; +} + +bool Flags::Has(std::string_view name) const { + queried_.emplace(name); + return values_.find(name) != values_.end(); +} + +std::string Flags::GetString(std::string_view name, + std::string default_value) const { + queried_.emplace(name); + auto it = values_.find(name); + if (it == values_.end()) { + return default_value; + } + return it->second; +} + +int64_t Flags::GetInt(std::string_view name, int64_t default_value) const { + queried_.emplace(name); + auto it = values_.find(name); + if (it == values_.end()) { + return default_value; + } + int64_t value; + if (!ParseInt64(it->second, &value)) { + Fatal("Flag --%s expects an integer, got '%s'", std::string(name).c_str(), + it->second.c_str()); + } + return value; +} + +double Flags::GetDouble(std::string_view name, double default_value) const { + queried_.emplace(name); + auto it = values_.find(name); + if (it == values_.end()) { + return default_value; + } + char* end = nullptr; + double value = strtod(it->second.c_str(), &end); + if (end == nullptr || *end != '\0' || it->second.empty()) { + Fatal("Flag --%s expects a number, got '%s'", std::string(name).c_str(), + it->second.c_str()); + } + return value; +} + +bool Flags::GetBool(std::string_view name, bool default_value) const { + queried_.emplace(name); + auto it = values_.find(name); + if (it == values_.end()) { + return default_value; + } + const std::string& v = it->second; + if (v == "true" || v == "1" || v == "yes" || v == "on") { + return true; + } + if (v == "false" || v == "0" || v == "no" || v == "off") { + return false; + } + Fatal("Flag --%s expects a boolean, got '%s'", std::string(name).c_str(), + v.c_str()); +} + +std::vector<std::string> Flags::GetList(std::string_view name, + char separator) const { + std::vector<std::string> result; + std::string value = GetString(name); + size_t start = 0; + while (start <= value.size()) { + size_t end = value.find(separator, start); + if (end == std::string::npos) { + end = value.size(); + } + if (end > start) { + result.push_back(value.substr(start, end - start)); + } + start = end + 1; + } + return result; +} + +std::vector<std::string> Flags::UnusedFlags() const { + std::vector<std::string> unused; + for (const auto& [name, value] : values_) { + if (queried_.find(name) == queried_.end()) { + unused.push_back(name); + } + } + return unused; +} + +std::string Flags::ToString() const { + std::string result; + for (const auto& [name, value] : values_) { + if (!result.empty()) { + result += ' '; + } + result += "--"; + result += name; + result += '='; + result += value; + } + for (const std::string& p : positional_) { + if (!result.empty()) { + result += ' '; + } + result += p; + } + return result; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/flags.h b/deps/v8/experimental/redline/base/flags.h new file mode 100644 index 000000000000..6973359cc1d9 --- /dev/null +++ b/deps/v8/experimental/redline/base/flags.h @@ -0,0 +1,61 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_FLAGS_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_FLAGS_H_ + +#include <cstdint> +#include <map> +#include <set> +#include <string> +#include <string_view> +#include <vector> + +namespace redline { + +// A deliberately small command line parser. Every redline command accepts +// flags of the form "--name=value", "--name" (boolean true) and "--no-name" +// (boolean false). Everything else is a positional argument. "--" ends flag +// parsing. Flags are recorded as strings and converted on access, so a +// command can report unknown flags via UnusedFlags() after it has queried +// everything it understands. +class Flags { + public: + Flags() = default; + + // Parses argv[start_index..argc). + static Flags Parse(int argc, const char* const* argv, int start_index); + + bool Has(std::string_view name) const; + + std::string GetString(std::string_view name, + std::string default_value = "") const; + int64_t GetInt(std::string_view name, int64_t default_value) const; + double GetDouble(std::string_view name, double default_value) const; + bool GetBool(std::string_view name, bool default_value) const; + // Splits a flag value on `separator`, dropping empty pieces. + std::vector<std::string> GetList(std::string_view name, + char separator = ',') const; + + const std::vector<std::string>& positional() const { return positional_; } + + // Flags that were given but never queried through one of the getters. + std::vector<std::string> UnusedFlags() const; + + // Human readable rendering of all flags (for logs and event files). + std::string ToString() const; + + private: + std::map<std::string, std::string, std::less<>> values_; + mutable std::set<std::string, std::less<>> queried_; + std::vector<std::string> positional_; +}; + +// Parses an integer with an optional size suffix (k, m, g). Returns false +// on malformed input. +bool ParseInt64(std::string_view text, int64_t* out); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_FLAGS_H_ diff --git a/deps/v8/experimental/redline/base/json.cc b/deps/v8/experimental/redline/base/json.cc new file mode 100644 index 000000000000..59af56addcd8 --- /dev/null +++ b/deps/v8/experimental/redline/base/json.cc @@ -0,0 +1,302 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/json.h" + +#include <cinttypes> +#include <cmath> + +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { + +// Length of the well-formed UTF-8 sequence of 2 to 4 bytes that starts at +// text[i], or 0 if there is none (RFC 3629: no overlong forms, no +// surrogates, nothing above U+10FFFF). +size_t Utf8SequenceLength(std::string_view text, size_t i) { + const unsigned int lead = static_cast<unsigned char>(text[i]); + size_t length = 0; + unsigned int low = 0x80, high = 0xbf; // range of the second byte + if (lead >= 0xc2 && lead <= 0xdf) { + length = 2; + } else if (lead >= 0xe0 && lead <= 0xef) { + length = 3; + low = lead == 0xe0 ? 0xa0 : 0x80; + high = lead == 0xed ? 0x9f : 0xbf; + } else if (lead >= 0xf0 && lead <= 0xf4) { + length = 4; + low = lead == 0xf0 ? 0x90 : 0x80; + high = lead == 0xf4 ? 0x8f : 0xbf; + } else { + return 0; + } + if (i + length > text.size()) { + return 0; + } + for (size_t k = 1; k < length; k++) { + const unsigned int c = static_cast<unsigned char>(text[i + k]); + if (c < (k == 1 ? low : 0x80u) || c > (k == 1 ? high : 0xbfu)) { + return 0; + } + } + return length; +} + +} // namespace + +std::string JsonQuote(std::string_view text) { + std::string out; + out.reserve(text.size() + 2); + out.push_back('"'); + for (size_t i = 0; i < text.size(); i++) { + const unsigned char c = static_cast<unsigned char>(text[i]); + switch (c) { + case '"': + out += "\\\""; + break; + case '\\': + out += "\\\\"; + break; + case '\n': + out += "\\n"; + break; + case '\r': + out += "\\r"; + break; + case '\t': + out += "\\t"; + break; + case '\b': + out += "\\b"; + break; + case '\f': + out += "\\f"; + break; + default: + if (c < 0x20 || c == 0x7f) { + char buffer[8]; + snprintf(buffer, sizeof(buffer), "\\u%04x", c); + out += buffer; + } else if (c < 0x80) { + out.push_back(static_cast<char>(c)); + } else if (size_t length = Utf8SequenceLength(text, i); length > 0) { + out.append(text.substr(i, length)); + i += length - 1; + } else { + // Not UTF-8 (for example a lone surrogate from a string + // literal): the output must stay valid JSON text. + out += "\\ufffd"; + } + } + } + out.push_back('"'); + return out; +} + +std::string JsonPretty(std::string_view json, int indent) { + std::string out; + out.reserve(json.size() * 2); + int depth = 0; + int array_depth = 0; // > 0 while inside an array: stay on one line + bool in_string = false; + auto newline = [&] { + out.push_back('\n'); + out.append(static_cast<size_t>(depth) * static_cast<size_t>(indent), ' '); + }; + for (size_t i = 0; i < json.size(); i++) { + const char c = json[i]; + if (in_string) { + out.push_back(c); + if (c == '\\' && i + 1 < json.size()) { + out.push_back(json[++i]); // escaped character, including \" + } else if (c == '"') { + in_string = false; + } + continue; + } + switch (c) { + case '"': + in_string = true; + out.push_back(c); + break; + case '{': + out.push_back(c); + if (i + 1 < json.size() && json[i + 1] == '}') { + out.push_back(json[++i]); // empty object stays "{}" + break; + } + depth++; + newline(); + break; + case '}': + depth--; + newline(); + out.push_back(c); + break; + case '[': + array_depth++; + out.push_back(c); + break; + case ']': + array_depth--; + out.push_back(c); + break; + case ',': + out.push_back(c); + if (array_depth > 0) { + out.push_back(' '); + } else { + newline(); + } + break; + case ':': + out += ": "; + break; + case ' ': + case '\n': + case '\t': + case '\r': + break; // the compact form has none; drop any anyway + default: + out.push_back(c); + } + } + return out; +} + +void JsonObject::AppendKey(std::string_view key) { + buffer_ += buffer_.empty() ? "{" : ","; + buffer_ += JsonQuote(key); + buffer_.push_back(':'); +} + +JsonObject& JsonObject::Add(std::string_view key, std::string_view value) { + AppendKey(key); + buffer_ += JsonQuote(value); + return *this; +} + +JsonObject& JsonObject::Add(std::string_view key, const char* value) { + return Add(key, std::string_view(value)); +} + +JsonObject& JsonObject::Add(std::string_view key, int64_t value) { + AppendKey(key); + buffer_ += StringPrintf("%" PRId64, value); + return *this; +} + +JsonObject& JsonObject::Add(std::string_view key, uint64_t value) { + AppendKey(key); + buffer_ += StringPrintf("%" PRIu64, value); + return *this; +} + +JsonObject& JsonObject::Add(std::string_view key, int value) { + return Add(key, static_cast<int64_t>(value)); +} + +JsonObject& JsonObject::Add(std::string_view key, unsigned value) { + return Add(key, static_cast<uint64_t>(value)); +} + +JsonObject& JsonObject::Add(std::string_view key, double value) { + AppendKey(key); + if (std::isfinite(value)) { + buffer_ += StringPrintf("%.6g", value); + } else { + buffer_ += "null"; + } + return *this; +} + +JsonObject& JsonObject::Add(std::string_view key, bool value) { + AppendKey(key); + buffer_ += value ? "true" : "false"; + return *this; +} + +JsonObject& JsonObject::AddRaw(std::string_view key, std::string_view json) { + AppendKey(key); + buffer_ += json; + return *this; +} + +JsonObject& JsonObject::AddArray(std::string_view key, + const std::vector<uint32_t>& v) { + AppendKey(key); + buffer_.push_back('['); + for (size_t i = 0; i < v.size(); i++) { + if (i > 0) { + buffer_.push_back(','); + } + buffer_ += StringPrintf("%u", v[i]); + } + buffer_.push_back(']'); + return *this; +} + +JsonObject& JsonObject::AddArray(std::string_view key, + const std::vector<std::string>& v) { + AppendKey(key); + buffer_.push_back('['); + for (size_t i = 0; i < v.size(); i++) { + if (i > 0) { + buffer_.push_back(','); + } + buffer_ += JsonQuote(v[i]); + } + buffer_.push_back(']'); + return *this; +} + +std::string JsonObject::ToString() const { + if (buffer_.empty()) { + return "{}"; + } + return buffer_ + "}"; +} + +JsonlWriter::~JsonlWriter() { + if (file_ != nullptr) { + fclose(file_); + } +} + +bool JsonlWriter::Open(const std::string& path, bool truncate) { + std::scoped_lock<std::mutex> guard(mutex_); + if (file_ != nullptr) { + fclose(file_); + } + file_ = fopen(path.c_str(), truncate ? "w" : "a"); + if (file_ == nullptr) { + REDLINE_ERROR("jsonl", "Cannot open %s for writing", path.c_str()); + return false; + } + return true; +} + +void JsonlWriter::Write(const JsonObject& object) { + WriteLine(object.ToString()); +} + +void JsonlWriter::WriteLine(std::string_view json_line) { + std::scoped_lock<std::mutex> guard(mutex_); + if (file_ == nullptr) { + return; + } + fwrite(json_line.data(), 1, json_line.size(), file_); + fputc('\n', file_); +} + +void JsonlWriter::Flush() { + std::scoped_lock<std::mutex> guard(mutex_); + if (file_ != nullptr) { + fflush(file_); + } +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/json.h b/deps/v8/experimental/redline/base/json.h new file mode 100644 index 000000000000..aaf8ef95302e --- /dev/null +++ b/deps/v8/experimental/redline/base/json.h @@ -0,0 +1,77 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_JSON_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_JSON_H_ + +#include <cstdint> +#include <cstdio> +#include <mutex> +#include <string> +#include <string_view> +#include <vector> + +namespace redline { + +// Escapes `text` as the contents of a JSON string literal (quotes included). +std::string JsonQuote(std::string_view text); + +// Re-indents compact JSON for humans: one member per line, `indent` spaces +// per level; arrays stay on one line. The input must be valid JSON. +std::string JsonPretty(std::string_view json, int indent = 2); + +// Builds a single flat JSON object. Values are emitted in insertion order. +// Example: +// JsonObject o; +// o.Add("file", name).Add("edges", 42); +// std::string line = o.ToString(); // {"file":"a.js","edges":42} +class JsonObject { + public: + JsonObject& Add(std::string_view key, std::string_view value); + JsonObject& Add(std::string_view key, const char* value); + JsonObject& Add(std::string_view key, int64_t value); + JsonObject& Add(std::string_view key, uint64_t value); + JsonObject& Add(std::string_view key, int value); + JsonObject& Add(std::string_view key, unsigned value); + JsonObject& Add(std::string_view key, double value); + JsonObject& Add(std::string_view key, bool value); + // Adds an already serialized JSON value (array, object, ...). + JsonObject& AddRaw(std::string_view key, std::string_view json); + JsonObject& AddArray(std::string_view key, const std::vector<uint32_t>& v); + JsonObject& AddArray(std::string_view key, const std::vector<std::string>& v); + + std::string ToString() const; + + private: + void AppendKey(std::string_view key); + std::string buffer_; +}; + +// Appends one JSON object per line to a file ("JSON Lines"). Thread-safe. +// Every redline command that produces data writes it through this class so +// that runs can be compared and replayed from their event logs. +class JsonlWriter { + public: + JsonlWriter() = default; + ~JsonlWriter(); + JsonlWriter(const JsonlWriter&) = delete; + JsonlWriter& operator=(const JsonlWriter&) = delete; + + // Opens `path` for appending (or truncating when `truncate` is set). + // Returns false and leaves the writer disabled on failure. + bool Open(const std::string& path, bool truncate); + bool is_open() const { return file_ != nullptr; } + + void Write(const JsonObject& object); + void WriteLine(std::string_view json_line); + void Flush(); + + private: + std::mutex mutex_; + FILE* file_ = nullptr; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_JSON_H_ diff --git a/deps/v8/experimental/redline/base/json_parser.cc b/deps/v8/experimental/redline/base/json_parser.cc new file mode 100644 index 000000000000..1467bd3f6250 --- /dev/null +++ b/deps/v8/experimental/redline/base/json_parser.cc @@ -0,0 +1,428 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/json_parser.h" + +#include <cmath> +#include <cstdlib> + +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { +const JsonValue kNullValue; +} // namespace + +const JsonValue& JsonValue::Get(std::string_view key) const { + for (const auto& [k, v] : object_) { + if (k == key) { + return v; + } + } + return kNullValue; +} + +bool JsonValue::Has(std::string_view key) const { + for (const auto& [k, v] : object_) { + if (k == key) { + return true; + } + } + return false; +} + +double JsonValue::GetNumber(std::string_view key, double fallback) const { + const JsonValue& v = Get(key); + return v.is_number() ? v.as_number() : fallback; +} + +int64_t JsonValue::GetInt(std::string_view key, int64_t fallback) const { + const JsonValue& v = Get(key); + return v.is_number() ? v.as_int() : fallback; +} + +bool JsonValue::GetBool(std::string_view key, bool fallback) const { + const JsonValue& v = Get(key); + return v.is_bool() ? v.as_bool() : fallback; +} + +std::string JsonValue::GetString(std::string_view key, + std::string_view fallback) const { + const JsonValue& v = Get(key); + return v.is_string() ? v.as_string() : std::string(fallback); +} + +class JsonParser { + public: + explicit JsonParser(std::string_view text) : text_(text) {} + + bool Parse(JsonValue* out, std::string* error) { + SkipWhitespace(); + if (!ParseValue(out, 0)) { + *error = StringPrintf("%d:%d: %s", line_, Column(), error_.c_str()); + return false; + } + SkipWhitespace(); + if (pos_ != text_.size()) { + *error = StringPrintf("%d:%d: trailing characters", line_, Column()); + return false; + } + return true; + } + + private: + static constexpr int kMaxDepth = 64; + + int Column() const { + size_t line_start = text_.rfind('\n', pos_ == 0 ? 0 : pos_ - 1); + size_t start = line_start == std::string_view::npos ? 0 : line_start + 1; + return static_cast<int>(pos_ - start) + 1; + } + + void SkipWhitespace() { + while (pos_ < text_.size()) { + char c = text_[pos_]; + if (c == '\n') { + line_++; + } + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { + break; + } + pos_++; + } + } + + bool Fail(const char* message) { + error_ = message; + return false; + } + + bool ParseValue(JsonValue* out, int depth) { + if (depth > kMaxDepth) { + return Fail("nesting too deep"); + } + if (pos_ >= text_.size()) { + return Fail("unexpected end of input"); + } + char c = text_[pos_]; + if (c == '{') { + return ParseObject(out, depth); + } + if (c == '[') { + return ParseArray(out, depth); + } + if (c == '"') { + out->type_ = JsonValue::Type::kString; + return ParseString(&out->string_); + } + if (c == 't' || c == 'f' || c == 'n') { + return ParseKeyword(out); + } + if (c == '-' || (c >= '0' && c <= '9')) { + return ParseNumber(out); + } + return Fail("unexpected character"); + } + + bool ParseKeyword(JsonValue* out) { + std::string_view rest = text_.substr(pos_); + if (rest.starts_with("true")) { + pos_ += 4; + out->type_ = JsonValue::Type::kBool; + out->bool_ = true; + return true; + } + if (rest.starts_with("false")) { + pos_ += 5; + out->type_ = JsonValue::Type::kBool; + out->bool_ = false; + return true; + } + if (rest.starts_with("null")) { + pos_ += 4; + out->type_ = JsonValue::Type::kNull; + return true; + } + return Fail("invalid literal"); + } + + bool ParseNumber(JsonValue* out) { + size_t start = pos_; + if (text_[pos_] == '-') { + pos_++; + } + auto digits = [&] { + size_t before = pos_; + while (pos_ < text_.size() && text_[pos_] >= '0' && text_[pos_] <= '9') { + pos_++; + } + return pos_ > before; + }; + if (!digits()) { + return Fail("invalid number"); + } + if (pos_ < text_.size() && text_[pos_] == '.') { + pos_++; + if (!digits()) { + return Fail("invalid number"); + } + } + if (pos_ < text_.size() && (text_[pos_] == 'e' || text_[pos_] == 'E')) { + pos_++; + if (pos_ < text_.size() && (text_[pos_] == '+' || text_[pos_] == '-')) { + pos_++; + } + if (!digits()) { + return Fail("invalid number"); + } + } + std::string literal(text_.substr(start, pos_ - start)); + out->type_ = JsonValue::Type::kNumber; + out->number_ = strtod(literal.c_str(), nullptr); + return true; + } + + static void AppendUtf8(std::string* out, uint32_t code_point) { + if (code_point < 0x80) { + out->push_back(static_cast<char>(code_point)); + } else if (code_point < 0x800) { + out->push_back(static_cast<char>(0xC0 | (code_point >> 6))); + out->push_back(static_cast<char>(0x80 | (code_point & 0x3F))); + } else if (code_point < 0x10000) { + out->push_back(static_cast<char>(0xE0 | (code_point >> 12))); + out->push_back(static_cast<char>(0x80 | ((code_point >> 6) & 0x3F))); + out->push_back(static_cast<char>(0x80 | (code_point & 0x3F))); + } else { + out->push_back(static_cast<char>(0xF0 | (code_point >> 18))); + out->push_back(static_cast<char>(0x80 | ((code_point >> 12) & 0x3F))); + out->push_back(static_cast<char>(0x80 | ((code_point >> 6) & 0x3F))); + out->push_back(static_cast<char>(0x80 | (code_point & 0x3F))); + } + } + + bool ParseHex4(uint32_t* out) { + if (pos_ + 4 > text_.size()) { + return Fail("truncated \\u escape"); + } + uint32_t value = 0; + for (int i = 0; i < 4; i++) { + char c = text_[pos_++]; + value <<= 4; + if (c >= '0' && c <= '9') { + value |= static_cast<uint32_t>(c - '0'); + } else if (c >= 'a' && c <= 'f') { + value |= static_cast<uint32_t>(c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + value |= static_cast<uint32_t>(c - 'A' + 10); + } else { + return Fail("invalid \\u escape"); + } + } + *out = value; + return true; + } + + bool ParseString(std::string* out) { + pos_++; // opening quote + while (true) { + if (pos_ >= text_.size()) { + return Fail("unterminated string"); + } + char c = text_[pos_++]; + if (c == '"') { + return true; + } + if (c == '\n') { + return Fail("newline in string"); + } + if (c != '\\') { + out->push_back(c); + continue; + } + if (pos_ >= text_.size()) { + return Fail("unterminated escape"); + } + char e = text_[pos_++]; + switch (e) { + case '"': + out->push_back('"'); + break; + case '\\': + out->push_back('\\'); + break; + case '/': + out->push_back('/'); + break; + case 'b': + out->push_back('\b'); + break; + case 'f': + out->push_back('\f'); + break; + case 'n': + out->push_back('\n'); + break; + case 'r': + out->push_back('\r'); + break; + case 't': + out->push_back('\t'); + break; + case 'u': { + uint32_t code_point; + if (!ParseHex4(&code_point)) { + return false; + } + if (code_point >= 0xD800 && code_point < 0xDC00 && + pos_ + 6 <= text_.size() && text_[pos_] == '\\' && + text_[pos_ + 1] == 'u') { + size_t saved_pos = pos_; + pos_ += 2; + uint32_t low; + if (!ParseHex4(&low)) { + return false; + } + if (low >= 0xDC00 && low <= 0xDFFF) { + code_point = + 0x10000 + ((code_point - 0xD800) << 10) + (low - 0xDC00); + } else { + pos_ = saved_pos; + } + } + AppendUtf8(out, code_point); + break; + } + default: + return Fail("invalid escape"); + } + } + } + + bool ParseArray(JsonValue* out, int depth) { + pos_++; // [ + out->type_ = JsonValue::Type::kArray; + SkipWhitespace(); + if (pos_ < text_.size() && text_[pos_] == ']') { + pos_++; + return true; + } + while (true) { + SkipWhitespace(); + out->array_.emplace_back(); + if (!ParseValue(&out->array_.back(), depth + 1)) { + return false; + } + SkipWhitespace(); + if (pos_ >= text_.size()) { + return Fail("unterminated array"); + } + char c = text_[pos_++]; + if (c == ']') { + return true; + } + if (c != ',') { + return Fail("expected ',' or ']'"); + } + } + } + + bool ParseObject(JsonValue* out, int depth) { + pos_++; // { + out->type_ = JsonValue::Type::kObject; + SkipWhitespace(); + if (pos_ < text_.size() && text_[pos_] == '}') { + pos_++; + return true; + } + while (true) { + SkipWhitespace(); + if (pos_ >= text_.size() || text_[pos_] != '"') { + return Fail("expected object key"); + } + std::string key; + if (!ParseString(&key)) { + return false; + } + SkipWhitespace(); + if (pos_ >= text_.size() || text_[pos_] != ':') { + return Fail("expected ':'"); + } + pos_++; + SkipWhitespace(); + out->object_.emplace_back(std::move(key), JsonValue()); + if (!ParseValue(&out->object_.back().second, depth + 1)) { + return false; + } + SkipWhitespace(); + if (pos_ >= text_.size()) { + return Fail("unterminated object"); + } + char c = text_[pos_++]; + if (c == '}') { + return true; + } + if (c != ',') { + return Fail("expected ',' or '}'"); + } + } + } + + std::string_view text_; + size_t pos_ = 0; + int line_ = 1; + std::string error_; +}; + +// static +bool JsonValue::Parse(std::string_view text, JsonValue* out, + std::string* error) { + *out = JsonValue(); + JsonParser parser(text); + return parser.Parse(out, error); +} + +std::string JsonValue::ToString() const { + switch (type_) { + case Type::kNull: + return "null"; + case Type::kBool: + return bool_ ? "true" : "false"; + case Type::kNumber: { + if (std::isfinite(number_) && number_ == std::floor(number_) && + std::fabs(number_) < 1e15) { + return StringPrintf("%lld", static_cast<long long>(number_)); + } + return StringPrintf("%.17g", number_); + } + case Type::kString: + return JsonQuote(string_); + case Type::kArray: { + std::string out = "["; + for (size_t i = 0; i < array_.size(); i++) { + if (i != 0) { + out += ','; + } + out += array_[i].ToString(); + } + return out + "]"; + } + case Type::kObject: { + std::string out = "{"; + for (size_t i = 0; i < object_.size(); i++) { + if (i != 0) { + out += ','; + } + out += JsonQuote(object_[i].first); + out += ':'; + out += object_[i].second.ToString(); + } + return out + "}"; + } + } + return "null"; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/json_parser.h b/deps/v8/experimental/redline/base/json_parser.h new file mode 100644 index 000000000000..230900a72117 --- /dev/null +++ b/deps/v8/experimental/redline/base/json_parser.h @@ -0,0 +1,83 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_JSON_PARSER_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_JSON_PARSER_H_ + +#include <cmath> +#include <cstdint> +#include <limits> +#include <memory> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +namespace redline { + +// A parsed JSON document (configuration files, saved state). Small and +// strict: no comments, no trailing commas, numbers are doubles. +class JsonValue { + public: + enum class Type { kNull, kBool, kNumber, kString, kArray, kObject }; + + JsonValue() = default; + static JsonValue Null() { return JsonValue(); } + + Type type() const { return type_; } + bool is_null() const { return type_ == Type::kNull; } + bool is_bool() const { return type_ == Type::kBool; } + bool is_number() const { return type_ == Type::kNumber; } + bool is_string() const { return type_ == Type::kString; } + bool is_array() const { return type_ == Type::kArray; } + bool is_object() const { return type_ == Type::kObject; } + + bool as_bool() const { return bool_; } + double as_number() const { return number_; } + int64_t as_int() const { + if (!std::isfinite(number_)) { + return 0; + } + if (number_ >= static_cast<double>(std::numeric_limits<int64_t>::max())) { + return std::numeric_limits<int64_t>::max(); + } + if (number_ <= static_cast<double>(std::numeric_limits<int64_t>::min())) { + return std::numeric_limits<int64_t>::min(); + } + return static_cast<int64_t>(number_); + } + const std::string& as_string() const { return string_; } + const std::vector<JsonValue>& as_array() const { return array_; } + const std::vector<std::pair<std::string, JsonValue>>& as_object() const { + return object_; + } + + // Object member lookup; returns a null value for missing keys. + const JsonValue& Get(std::string_view key) const; + bool Has(std::string_view key) const; + // Typed getters with defaults (also used for missing keys). + double GetNumber(std::string_view key, double fallback) const; + int64_t GetInt(std::string_view key, int64_t fallback) const; + bool GetBool(std::string_view key, bool fallback) const; + std::string GetString(std::string_view key, std::string_view fallback) const; + + // Parses `text`; on error returns false and sets `error` ("line:col: msg"). + static bool Parse(std::string_view text, JsonValue* out, std::string* error); + + // Serializes back to compact JSON (for round-trip tests and dumps). + std::string ToString() const; + + private: + friend class JsonParser; + Type type_ = Type::kNull; + bool bool_ = false; + double number_ = 0; + std::string string_; + std::vector<JsonValue> array_; + std::vector<std::pair<std::string, JsonValue>> object_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_JSON_PARSER_H_ diff --git a/deps/v8/experimental/redline/base/log.cc b/deps/v8/experimental/redline/base/log.cc new file mode 100644 index 000000000000..5c3935b90d4f --- /dev/null +++ b/deps/v8/experimental/redline/base/log.cc @@ -0,0 +1,118 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/log.h" + +#include <sys/time.h> + +#include <atomic> +#include <cstdio> +#include <cstdlib> +#include <ctime> +#include <mutex> + +namespace redline { + +namespace { + +std::atomic<int> g_log_level{static_cast<int>(LogLevel::kInfo)}; +std::mutex& LogMutex() { + static std::mutex* mutex = new std::mutex(); + return *mutex; +} + +const char* LevelTag(LogLevel level) { + switch (level) { + case LogLevel::kVerbose: + return "V"; + case LogLevel::kInfo: + return "I"; + case LogLevel::kWarning: + return "W"; + case LogLevel::kError: + return "E"; + } + return "?"; +} + +void FormatTimestamp(char* buffer, size_t size) { + struct timeval tv; + gettimeofday(&tv, nullptr); + struct tm tm_buf; + localtime_r(&tv.tv_sec, &tm_buf); + size_t n = strftime(buffer, size, "%H:%M:%S", &tm_buf); + snprintf(buffer + n, size - n, ".%03d", static_cast<int>(tv.tv_usec / 1000)); +} + +} // namespace + +void SetLogLevel(LogLevel level) { + g_log_level.store(static_cast<int>(level), std::memory_order_relaxed); +} + +LogLevel GetLogLevel() { + return static_cast<LogLevel>(g_log_level.load(std::memory_order_relaxed)); +} + +void LogV(LogLevel level, const char* component, const char* format, + va_list args) { + if (static_cast<int>(level) < g_log_level.load(std::memory_order_relaxed)) { + return; + } + std::string message = StringPrintfV(format, args); + char timestamp[32]; + FormatTimestamp(timestamp, sizeof(timestamp)); + std::scoped_lock<std::mutex> guard(LogMutex()); + fprintf(stderr, "[%s %s] [%s] %s\n", timestamp, LevelTag(level), component, + message.c_str()); + fflush(stderr); +} + +void Log(LogLevel level, const char* component, const char* format, ...) { + va_list args; + va_start(args, format); + LogV(level, component, format, args); + va_end(args); +} + +void Fatal(const char* format, ...) { + va_list args; + va_start(args, format); + std::string message = StringPrintfV(format, args); + va_end(args); + { + std::scoped_lock<std::mutex> guard(LogMutex()); + fprintf(stderr, "[FATAL] %s\n", message.c_str()); + fflush(stderr); + } + abort(); +} + +std::string StringPrintfV(const char* format, va_list args) { + va_list copy; + va_copy(copy, args); + char stack_buffer[512]; + int needed = vsnprintf(stack_buffer, sizeof(stack_buffer), format, copy); + va_end(copy); + if (needed < 0) { + return std::string(); + } + if (static_cast<size_t>(needed) < sizeof(stack_buffer)) { + return std::string(stack_buffer, static_cast<size_t>(needed)); + } + std::string result(static_cast<size_t>(needed) + 1, '\0'); + vsnprintf(result.data(), result.size(), format, args); + result.resize(static_cast<size_t>(needed)); + return result; +} + +std::string StringPrintf(const char* format, ...) { + va_list args; + va_start(args, format); + std::string result = StringPrintfV(format, args); + va_end(args); + return result; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/log.h b/deps/v8/experimental/redline/base/log.h new file mode 100644 index 000000000000..02e88a023084 --- /dev/null +++ b/deps/v8/experimental/redline/base/log.h @@ -0,0 +1,47 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_LOG_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_LOG_H_ + +#include <cstdarg> +#include <string> + +namespace redline { + +enum class LogLevel { kVerbose = 0, kInfo = 1, kWarning = 2, kError = 3 }; + +// Minimum level that is printed. Defaults to kInfo. +void SetLogLevel(LogLevel level); +LogLevel GetLogLevel(); + +// Thread-safe, printf-style logging to stderr with a timestamp and a +// component label, e.g. "[12:34:56.789] [REPRL] message". +void Log(LogLevel level, const char* component, const char* format, ...) + __attribute__((format(printf, 3, 4))); +void LogV(LogLevel level, const char* component, const char* format, + va_list args); + +// Prints the message and aborts. Never returns. +[[noreturn]] void Fatal(const char* format, ...) + __attribute__((format(printf, 1, 2))); + +// Convenience wrappers. +#define REDLINE_LOG(component, ...) \ + ::redline::Log(::redline::LogLevel::kInfo, component, __VA_ARGS__) +#define REDLINE_VLOG(component, ...) \ + ::redline::Log(::redline::LogLevel::kVerbose, component, __VA_ARGS__) +#define REDLINE_WARN(component, ...) \ + ::redline::Log(::redline::LogLevel::kWarning, component, __VA_ARGS__) +#define REDLINE_ERROR(component, ...) \ + ::redline::Log(::redline::LogLevel::kError, component, __VA_ARGS__) + +// printf into a std::string. +std::string StringPrintf(const char* format, ...) + __attribute__((format(printf, 1, 2))); +std::string StringPrintfV(const char* format, va_list args); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_LOG_H_ diff --git a/deps/v8/experimental/redline/base/subprocess.cc b/deps/v8/experimental/redline/base/subprocess.cc new file mode 100644 index 000000000000..336fa003dc66 --- /dev/null +++ b/deps/v8/experimental/redline/base/subprocess.cc @@ -0,0 +1,215 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/subprocess.h" + +#include <fcntl.h> +#include <poll.h> +#include <spawn.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <algorithm> +#include <cerrno> +#include <csignal> +#include <cstring> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" + +extern "C" char** environ; + +namespace redline { + +namespace { + +// Reads from `fd` into `out` until EOF, keeping at most `limit` bytes. +// Returns false on EOF or error (i.e. when the fd should be closed). +bool DrainFd(int fd, std::string* out, size_t limit) { + char buffer[65536]; + while (true) { + ssize_t n = read(fd, buffer, sizeof(buffer)); + if (n < 0) { + if (errno == EINTR) { + continue; + } + return errno == EAGAIN; // keep open only if it would block + } + if (n == 0) { + return false; + } + if (out->size() < limit) { + out->append(buffer, static_cast<size_t>(std::min<size_t>( + static_cast<size_t>(n), limit - out->size()))); + } + } +} + +void SetNonBlocking(int fd) { + int flags = fcntl(fd, F_GETFL, 0); + if (flags >= 0) { + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } +} + +} // namespace + +SubprocessResult RunSubprocess(const std::vector<std::string>& argv, + int64_t timeout_ms, + const std::vector<std::string>& extra_env, + size_t max_output_bytes) { + SubprocessResult result; + if (argv.empty()) { + result.error = "empty argv"; + return result; + } + + int out_pipe[2], err_pipe[2]; + if (pipe2(out_pipe, O_CLOEXEC) != 0) { + result.error = StringPrintf("pipe failed: %s", strerror(errno)); + return result; + } + if (pipe2(err_pipe, O_CLOEXEC) != 0) { + int saved_errno = errno; + close(out_pipe[0]); + close(out_pipe[1]); + result.error = StringPrintf("pipe failed: %s", strerror(saved_errno)); + return result; + } + + std::vector<char*> c_argv; + c_argv.reserve(argv.size() + 1); + for (const std::string& arg : argv) { + c_argv.push_back(const_cast<char*>(arg.c_str())); + } + c_argv.push_back(nullptr); + + std::vector<char*> c_env; + for (char** e = environ; e != nullptr && *e != nullptr; e++) { + c_env.push_back(*e); + } + for (const std::string& kv : extra_env) { + c_env.push_back(const_cast<char*>(kv.c_str())); + } + c_env.push_back(nullptr); + + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_init(&actions); + posix_spawn_file_actions_addopen(&actions, STDIN_FILENO, "/dev/null", + O_RDONLY, 0); + posix_spawn_file_actions_adddup2(&actions, out_pipe[1], STDOUT_FILENO); + posix_spawn_file_actions_adddup2(&actions, err_pipe[1], STDERR_FILENO); + + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + sigset_t empty_set; + sigemptyset(&empty_set); + posix_spawnattr_setsigmask(&attr, &empty_set); + sigset_t default_set; + sigfillset(&default_set); + posix_spawnattr_setsigdefault(&attr, &default_set); + // A new process group so that a timeout kill takes helper processes too. + posix_spawnattr_setpgroup(&attr, 0); + posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETPGROUP); + + pid_t pid = -1; + Stopwatch stopwatch; + int rc = posix_spawn(&pid, c_argv[0], &actions, &attr, c_argv.data(), + c_env.data()); + posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); + close(out_pipe[1]); + close(err_pipe[1]); + + if (rc != 0) { + close(out_pipe[0]); + close(err_pipe[0]); + result.error = StringPrintf("posix_spawn(%s) failed: %s", argv[0].c_str(), + strerror(rc)); + return result; + } + // No core dumps from children (they may crash on purpose). Setting this on + // the child pid avoids racing with other threads or suppressing core dumps + // for redline itself. + struct rlimit no_core = {0, 0}; + prlimit(pid, RLIMIT_CORE, &no_core, nullptr); + result.started = true; + SetNonBlocking(out_pipe[0]); + SetNonBlocking(err_pipe[0]); + + int fds[2] = {out_pipe[0], err_pipe[0]}; + std::string* sinks[2] = {&result.stdout_data, &result.stderr_data}; + int open_count = 2; + bool killed = false; + while (open_count > 0) { + struct pollfd pfds[2]; + int n = 0; + for (int i = 0; i < 2; i++) { + if (fds[i] >= 0) { + pfds[n++] = {fds[i], POLLIN, 0}; + } + } + int64_t elapsed_ms = static_cast<int64_t>(stopwatch.ElapsedUs() / 1000); + int wait_ms = + killed + ? 1000 + : static_cast<int>(std::max<int64_t>(0, timeout_ms - elapsed_ms)); + int ready = poll(pfds, static_cast<nfds_t>(n), wait_ms); + if (ready < 0) { + if (errno == EINTR) { + continue; + } + break; + } + if (ready == 0) { + if (killed) { + break; // give up waiting for output after a kill + } + // Timeout: kill the whole process group. + kill(-pid, SIGKILL); + kill(pid, SIGKILL); + result.timed_out = true; + killed = true; + continue; + } + for (int i = 0, j = 0; i < 2; i++) { + if (fds[i] < 0) { + continue; + } + const struct pollfd& p = pfds[j++]; + if (p.revents == 0) { + continue; + } + if (!DrainFd(fds[i], sinks[i], max_output_bytes)) { + close(fds[i]); + fds[i] = -1; + open_count--; + } + } + } + for (int i = 0; i < 2; i++) { + if (fds[i] >= 0) { + close(fds[i]); + } + } + + int status = 0; + while (waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) { + break; + } + } + result.elapsed_us = stopwatch.ElapsedUs(); + if (WIFEXITED(status)) { + result.exit_code = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + result.signal = WTERMSIG(status); + } + return result; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/subprocess.h b/deps/v8/experimental/redline/base/subprocess.h new file mode 100644 index 000000000000..8cf59e128fcb --- /dev/null +++ b/deps/v8/experimental/redline/base/subprocess.h @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_SUBPROCESS_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_SUBPROCESS_H_ + +#include <cstdint> +#include <string> +#include <vector> + +namespace redline { + +// Result of running a child process to completion. +struct SubprocessResult { + // True if the child was started at all. + bool started = false; + // True if the child was killed because it exceeded the timeout. + bool timed_out = false; + // Exit code if the child exited normally, otherwise -1. + int exit_code = -1; + // Terminating signal if the child was killed by one, otherwise 0. + int signal = 0; + std::string stdout_data; + std::string stderr_data; + uint64_t elapsed_us = 0; + // Why `started` is false. + std::string error; + + bool Succeeded() const { return started && !timed_out && exit_code == 0; } +}; + +// Runs `argv` (argv[0] is the executable path) with stdin from /dev/null, +// capturing stdout and stderr (each truncated at `max_output_bytes`). Kills +// the process group after `timeout_ms` milliseconds. Core dumps are disabled. +// The child's environment is inherited; `extra_env` (KEY=VALUE) is appended. +SubprocessResult RunSubprocess(const std::vector<std::string>& argv, + int64_t timeout_ms, + const std::vector<std::string>& extra_env = {}, + size_t max_output_bytes = 1 << 20); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_SUBPROCESS_H_ diff --git a/deps/v8/experimental/redline/base/time_util.h b/deps/v8/experimental/redline/base/time_util.h new file mode 100644 index 000000000000..6366dc980479 --- /dev/null +++ b/deps/v8/experimental/redline/base/time_util.h @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_TIME_UTIL_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_TIME_UTIL_H_ + +#include <time.h> + +#include <cstdint> + +namespace redline { + +// Monotonic clock in microseconds. +inline uint64_t MonotonicNowUs() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast<uint64_t>(ts.tv_sec) * 1000000 + + static_cast<uint64_t>(ts.tv_nsec) / 1000; +} + +// Wall clock in milliseconds since the epoch (for event timestamps). +inline uint64_t WallClockNowMs() { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return static_cast<uint64_t>(ts.tv_sec) * 1000 + + static_cast<uint64_t>(ts.tv_nsec) / 1000000; +} + +// Simple stopwatch. +class Stopwatch { + public: + Stopwatch() : start_(MonotonicNowUs()) {} + uint64_t ElapsedUs() const { return MonotonicNowUs() - start_; } + double ElapsedSeconds() const { + return static_cast<double>(ElapsedUs()) / 1e6; + } + void Restart() { start_ = MonotonicNowUs(); } + + private: + uint64_t start_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_TIME_UTIL_H_ diff --git a/deps/v8/experimental/redline/base/v8_runtime.cc b/deps/v8/experimental/redline/base/v8_runtime.cc new file mode 100644 index 000000000000..30b930b57a9a --- /dev/null +++ b/deps/v8/experimental/redline/base/v8_runtime.cc @@ -0,0 +1,170 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/base/v8_runtime.h" + +#include <unistd.h> + +#include <mutex> + +#include "experimental/redline/base/log.h" +#include "include/libplatform/libplatform.h" +#include "include/v8-context.h" +#include "include/v8-exception.h" +#include "include/v8-initialization.h" +#include "include/v8-isolate.h" +#include "include/v8-local-handle.h" +#include "include/v8-message.h" +#include "include/v8-primitive.h" +#include "include/v8-script.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "v8"; + +// V8 uses the platform until the process exits, so it is never deleted. +v8::Platform* g_platform = nullptr; +bool g_initialized = false; +std::mutex g_init_mutex; + +std::string ExecutablePath() { + char buffer[4096]; + ssize_t n = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); + if (n <= 0) { + return "redline"; + } + buffer[n] = '\0'; + return buffer; +} + +std::string ToStdString(v8::Isolate* isolate, v8::Local<v8::Value> value) { + if (value.IsEmpty()) { + return ""; + } + v8::String::Utf8Value utf8(isolate, value); + return *utf8 == nullptr ? "" : std::string(*utf8, utf8.length()); +} + +} // namespace + +bool InitializeV8(const std::string& flags, std::string* error) { + std::scoped_lock<std::mutex> lock(g_init_mutex); + if (g_initialized) { + return true; + } + std::string exe = ExecutablePath(); + // ICU data and the startup snapshot live next to the executable (as for + // d8). Failing to find ICU is not fatal for parsing. + if (!v8::V8::InitializeICUDefaultLocation(exe.c_str())) { + REDLINE_VLOG(kLog, "ICU data not found next to %s; continuing without it", + exe.c_str()); + } + v8::V8::InitializeExternalStartupData(exe.c_str()); + if (!flags.empty()) { + v8::V8::SetFlagsFromString(flags.c_str()); + } + // The oracle only parses; cached compiled scripts would just retain memory + // (one isolate per worker, all in the same pointer-compression cage). + v8::V8::SetFlagsFromString("--no-compilation-cache"); + g_platform = + v8::platform::NewDefaultPlatform( + /*thread_pool_size=*/2, v8::platform::IdleTaskSupport::kDisabled) + .release(); + v8::V8::InitializePlatform(g_platform); + if (!v8::V8::Initialize()) { + *error = "v8::V8::Initialize() failed"; + return false; + } + g_initialized = true; + REDLINE_VLOG(kLog, "V8 %s initialized in-process (flags: %s)", + v8::V8::GetVersion(), flags.c_str()); + return true; +} + +struct SyntaxChecker::Impl { + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator; + v8::Isolate* isolate = nullptr; + v8::Global<v8::Context> context; + uint64_t checks = 0; +}; + +SyntaxChecker::SyntaxChecker() : impl_(std::make_unique<Impl>()) { + impl_->allocator.reset(v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + v8::Isolate::CreateParams params; + params.array_buffer_allocator = impl_->allocator.get(); + // Every worker thread owns one of these isolates and all of them live in + // the process' single pointer-compression cage (4 GB), so each must stay + // small: a lazily compiled script of a few hundred KB needs a few MB. + constexpr size_t kMB = static_cast<size_t>(1024) * 1024; + params.constraints.set_max_old_generation_size_in_bytes(64 * kMB); + params.constraints.set_max_young_generation_size_in_bytes(8 * kMB); + impl_->isolate = v8::Isolate::New(params); + v8::Isolate::Scope isolate_scope(impl_->isolate); + v8::HandleScope handle_scope(impl_->isolate); + v8::Local<v8::Context> context = v8::Context::New(impl_->isolate); + impl_->context.Reset(impl_->isolate, context); +} + +SyntaxChecker::~SyntaxChecker() { + impl_->context.Reset(); + impl_->isolate->Dispose(); +} + +bool SyntaxChecker::Accepts(std::string_view source, std::string* message) { + v8::Isolate* isolate = impl_->isolate; + v8::Isolate::Scope isolate_scope(isolate); + // Keep the heap compact: everything from previous checks is garbage. + if (++impl_->checks % 4096 == 0) { + isolate->LowMemoryNotification(); + } + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = impl_->context.Get(isolate); + v8::Context::Scope context_scope(context); + v8::TryCatch try_catch(isolate); + try_catch.SetVerbose(false); + + v8::Local<v8::String> text; + if (!v8::String::NewFromUtf8(isolate, source.data(), + v8::NewStringType::kNormal, + static_cast<int>(source.size())) + .ToLocal(&text)) { + if (message) { + *message = "source is too large or not valid UTF-8"; + } + return false; + } + v8::ScriptOrigin origin( + v8::String::NewFromUtf8Literal(isolate, "redline-syntax-check.js")); + v8::ScriptCompiler::Source compiler_source(text, origin); + v8::Local<v8::UnboundScript> script; + // Lazy compilation, like d8: inner functions are pre-parsed, which reports + // every early error, and nothing but the top-level bytecode is generated. + // (Eager compilation retained the bytecode of every function of every + // checked program until the next GC; with one isolate per worker that + // exhausted the pointer-compression cage on big inputs.) + if (v8::ScriptCompiler::CompileUnboundScript( + isolate, &compiler_source, v8::ScriptCompiler::kNoCompileOptions) + .ToLocal(&script)) { + return true; + } + if (message) { + std::string text_message = "SyntaxError"; + if (try_catch.HasCaught()) { + v8::Local<v8::Message> v8_message = try_catch.Message(); + text_message = ToStdString(isolate, try_catch.Exception()); + if (!v8_message.IsEmpty()) { + int line = v8_message->GetLineNumber(context).FromMaybe(0); + int column = v8_message->GetStartColumn(context).FromMaybe(-1) + 1; + text_message = + StringPrintf("%d:%d: %s", line, column, text_message.c_str()); + } + } + *message = text_message; + } + return false; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/base/v8_runtime.h b/deps/v8/experimental/redline/base/v8_runtime.h new file mode 100644 index 000000000000..333d83e790f6 --- /dev/null +++ b/deps/v8/experimental/redline/base/v8_runtime.h @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_BASE_V8_RUNTIME_H_ +#define V8_EXPERIMENTAL_REDLINE_BASE_V8_RUNTIME_H_ + +#include <memory> +#include <string> +#include <string_view> + +namespace v8 { +class Isolate; +class ArrayBuffer; +} // namespace v8 + +namespace redline { + +// Initializes the V8 engine linked into this binary (platform, ICU, startup +// snapshot). Idempotent; `flags` (e.g. "--allow-natives-syntax") are only +// applied by the first call because V8 freezes its flags afterwards. +// Returns false with a message if initialization fails. +bool InitializeV8(const std::string& flags, std::string* error); + +// An isolate that only compiles scripts, to ask the real V8 parser whether +// it accepts a piece of source text. One instance per thread. +class SyntaxChecker { + public: + SyntaxChecker(); + ~SyntaxChecker(); + SyntaxChecker(const SyntaxChecker&) = delete; + SyntaxChecker& operator=(const SyntaxChecker&) = delete; + + // Compiles `source` as a classic script (no execution). Returns true if V8 + // accepts it; otherwise `message` receives V8's SyntaxError message with + // line and column. + bool Accepts(std::string_view source, std::string* message); + + private: + struct Impl; + std::unique_ptr<Impl> impl_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_BASE_V8_RUNTIME_H_ diff --git a/deps/v8/experimental/redline/commands/amplify_command.cc b/deps/v8/experimental/redline/commands/amplify_command.cc new file mode 100644 index 000000000000..c23ce768e549 --- /dev/null +++ b/deps/v8/experimental/redline/commands/amplify_command.cc @@ -0,0 +1,237 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline amplify": runs the amplify step (DESIGN.md 5.8) on one program and +// prints the d8 flags that reproduce its crash, if any. The same code runs in +// the fuzzer's crash triage. + +#include <unistd.h> + +#include <cerrno> +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json_parser.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/engine/amplifier.h" +#include "experimental/redline/engine/prelude.h" +#include "experimental/redline/exec/process_run.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "amplify"; + +// The value of a "key: value" line of a crash report header, or "". +std::string ReportField(const std::string& report, const std::string& key) { + const std::string prefix = key + ": "; + size_t pos = 0; + while (pos < report.size()) { + size_t end = report.find('\n', pos); + if (end == std::string::npos) { + end = report.size(); + } + if (report.compare(pos, 4, "--- ") == 0) { + break; + } + if (report.compare(pos, prefix.size(), prefix) == 0) { + return report.substr(pos + prefix.size(), end - pos - prefix.size()); + } + pos = end + 1; + } + return ""; +} + +// The text between "--- stderr ---" and "--- stdout ---" of a crash report. +std::string ReportStderr(const std::string& report) { + const std::string open = "--- stderr ---\n"; + size_t from = report.find(open); + if (from == std::string::npos) { + return ""; + } + from += open.size(); + size_t to = report.find("\n--- stdout ---", from); + return report.substr(from, + to == std::string::npos ? std::string::npos : to - from); +} + +int RunAmplify(const Flags& flags) { + TargetOptions target; + std::string error; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + if (flags.positional().size() != 1) { + REDLINE_ERROR(kLog, "Give exactly one JavaScript file"); + return kExitUsage; + } + std::string program; + if (!ReadFileToString(flags.positional()[0], &program, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + // The prelude: "default" (Redline's), "none", or a file. + std::string prelude; + const std::string prelude_flag = flags.GetString("prelude", "default"); + if (prelude_flag == "default") { + prelude = std::string(DefaultPrelude()); + } else if (prelude_flag != "none" && + !ReadFileToString(prelude_flag, &prelude, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + // The strategy: {"strategy": NAME, "params": {...}}, default flags. + JsonValue amplify; + if (flags.Has("amplify") && + !JsonValue::Parse(flags.GetString("amplify"), &lify, &error)) { + REDLINE_ERROR(kLog, "--amplify: %s", error.c_str()); + return kExitUsage; + } + std::unique_ptr<AmplifyStrategy> strategy = CreateAmplifyStrategy( + amplify.GetString("strategy", "flags"), amplify.Get("params"), &error); + if (strategy == nullptr) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + + AmplifyRequest request; + request.target = target; + request.program = program; + request.prelude = prelude; + bool remove_script_on_exit = false; + if (flags.Has("work-file")) { + request.script_path = flags.GetString("work-file"); + } else { + char tmpl[] = "/tmp/redline_amplify_XXXXXX.js"; + int fd = mkstemps(tmpl, 3); + if (fd < 0) { + REDLINE_ERROR(kLog, "mkstemps failed: %s", strerror(errno)); + return kExitFailure; + } + close(fd); + request.script_path = tmpl; + remove_script_on_exit = true; + } + struct ScriptFileGuard { + std::string path; + bool active = false; + ~ScriptFileGuard() { + if (active && !path.empty()) { + std::remove(path.c_str()); + } + } + } script_guard{request.script_path, remove_script_on_exit}; + if (!WriteStringToFile(request.script_path, + prelude.empty() ? program : prelude + "\n" + program, + &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + // One plain run without extra flags: its time sets --stress-runs, and + // without --crash its crash is the one to amplify. + std::vector<std::string> args = target.args; + args.push_back(request.script_path); + const ProcessResult first = + RunProcess(target.executable, args, target.PlainEnvironment(), + static_cast<uint64_t>(60) * 1000 * 1000); + if (!first.started) { + REDLINE_ERROR(kLog, "Cannot start d8: %s", first.error.c_str()); + return kExitFailure; + } + request.exec_time_us = first.wall_us; + if (flags.Has("crash")) { + std::string report; + if (!ReadFileToString(flags.GetString("crash"), &report, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + request.stderr_text = ReportStderr(report); + request.signature = CrashSignature::FromOutput( + static_cast<int>( + strtol(ReportField(report, "signal").c_str(), nullptr, 10)), + static_cast<int>( + strtol(ReportField(report, "exit_code").c_str(), nullptr, 10)), + request.stderr_text); + const std::string recorded = ReportField(report, "signature"); + if (!recorded.empty() && + request.signature.text.rfind(recorded.substr(0, 40), 0) != 0) { + REDLINE_WARN(kLog, + "signature from the report's stderr (%s) differs from its " + "header (%s)", + request.signature.text.c_str(), recorded.c_str()); + } + } else { + if (first.signal == 0 && first.exit_code == 0) { + REDLINE_ERROR(kLog, + "The program does not crash in one plain run: pass " + "--crash=REPORT.txt"); + return kExitFailure; + } + request.signature = CrashSignature::FromOutput( + first.signal, first.exit_code, first.stderr_text); + request.stderr_text = first.stderr_text; + } + printf("signature: %s\nfirst plain run: %.0f ms\n", + request.signature.text.c_str(), + static_cast<double>(first.wall_us) / 1000.0); + + Random rng(static_cast<uint64_t>( + flags.GetInt("seed", static_cast<int64_t>(WallClockNowMs())))); + const AmplifyResult result = strategy->Amplify(request, rng); + printf( + "amplified: %s\n%s: %s\namplified_rate: %d/%d\namplify_processes: " + "%d\namplify_time_sec: %.0f\n" + "program_wrapped: %s\ntried: %s\n", + result.amplified ? "yes" : "no", + result.amplified ? "amplified_args" : "best_candidate", + result.args.c_str(), result.hits, result.processes, + result.total_processes, result.time_sec, + result.program.empty() ? "no" : "yes", result.note.c_str()); + // The changed program, which the amplified flags reproduce. + if (!result.program.empty() && flags.Has("out")) { + if (!WriteStringToFile(flags.GetString("out"), result.program, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + printf("wrapped program: %s\n", flags.GetString("out").c_str()); + } + return result.amplified ? kExitOk : kExitFailure; +} + +} // namespace + +const Command kAmplifyCommand = { + "amplify", + "Search d8 flags that reproduce a flaky crash", + "usage: redline amplify --d8=PATH [options] FILE.js\n" + "\n" + "Runs the amplify step of crash triage on one program: candidate d8 flags\n" + "(from stack rules, then the plain loop) each run in fresh plain d8\n" + "processes with --stress-runs. Prints the flags that reproduce the crash.\n" + "Exit code 0 if amplified, 1 otherwise.\n" + "\n" + "options:\n" + " --crash=REPORT.txt the crash to reproduce (a Redline crash report);\n" + " default: the crash of one plain run\n" + " --prelude=FILE the prelude to put before the program, " + "\"default\"\n" + " (Redline's) or \"none\" (default: default)\n" + " --amplify=JSON {\"strategy\": \"flags\", \"params\": {...}}\n" + " --seed=N random seed (the --random-seed values of d8)\n" + " --work-file=PATH where to write the script for d8\n" + " --out=FILE write the wrapped program here, if the step " + "wrapped\n" + " it in try/catch (the amplified flags reproduce " + "it)\n", + RunAmplify, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/command.h b/deps/v8/experimental/redline/commands/command.h new file mode 100644 index 000000000000..5b138956776c --- /dev/null +++ b/deps/v8/experimental/redline/commands/command.h @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_COMMANDS_COMMAND_H_ +#define V8_EXPERIMENTAL_REDLINE_COMMANDS_COMMAND_H_ + +#include <string> +#include <vector> + +namespace redline { + +class Flags; + +// A redline subcommand: "redline <name> [flags] [positional args]". +struct Command { + const char* name; + const char* summary; + // Full usage text, printed by "redline help <name>". + const char* usage; + int (*run)(const Flags& flags); +}; + +// Exit codes shared by all commands. +constexpr int kExitOk = 0; +constexpr int kExitFailure = 1; +constexpr int kExitUsage = 2; + +extern const Command kAmplifyCommand; +extern const Command kAuditCommand; +extern const Command kExecCommand; +extern const Command kFuzzCommand; +extern const Command kMinimizeCommand; +extern const Command kMutateCommand; +extern const Command kParseCommand; +extern const Command kReplayCommand; +extern const Command kRoundtripCommand; +extern const Command kSelftestCommand; +extern const Command kShellCommand; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_COMMANDS_COMMAND_H_ diff --git a/deps/v8/experimental/redline/commands/exec_command.cc b/deps/v8/experimental/redline/commands/exec_command.cc new file mode 100644 index 000000000000..ae782cd8d01f --- /dev/null +++ b/deps/v8/experimental/redline/commands/exec_command.cc @@ -0,0 +1,182 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline exec": runs one or more JavaScript files through the target and +// reports outcome, timing and coverage for each. The simplest way to check +// what the fuzzer sees for a given program. + +#include <algorithm> +#include <cstdio> +#include <iterator> +#include <set> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/exec/runner.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "exec"; + +void PrintOutput(const char* label, const std::string& text) { + if (text.empty()) { + return; + } + printf("---- %s (%zu bytes) ----\n%s%s", label, text.size(), text.c_str(), + text.back() == '\n' ? "" : "\n"); +} + +int RunExec(const Flags& flags) { + TargetOptions target; + std::string error; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + int repeat = static_cast<int>(flags.GetInt("repeat", 1)); + bool print_output = flags.GetBool("print-output", false); + bool print_edges = flags.GetBool("print-edges", false); + std::string events_path = flags.GetString("events"); + + if (flags.positional().empty()) { + REDLINE_ERROR(kLog, "No JavaScript files given"); + return kExitUsage; + } + + JsonlWriter events; + if (!events_path.empty() && !events.Open(events_path, /*truncate=*/true)) { + return kExitFailure; + } + + std::unique_ptr<ScriptRunner> runner = + ScriptRunner::Create(target, 0, &error); + if (!runner || !runner->Initialize(&error)) { + REDLINE_ERROR(kLog, "Cannot start target: %s", error.c_str()); + return kExitFailure; + } + REDLINE_LOG(kLog, "Target: %s", target.CommandLine().c_str()); + REDLINE_LOG(kLog, "%u edges instrumented", runner->coverage().num_edges()); + + int exit_code = kExitOk; + for (const std::string& path : flags.positional()) { + std::string script; + if (!ReadFileToString(path, &script, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + exit_code = kExitFailure; + continue; + } + // For --repeat we track which edges were hit in every run vs. in any + // run, which is what the fuzzer's determinism check looks at. + std::vector<uint32_t> edges_in_all_runs; + std::set<uint32_t> edges_in_any_run; + for (int run = 0; run < repeat; run++) { + ScriptRunner::Result result; + if (!runner->Run(script, &result, &error)) { + REDLINE_ERROR(kLog, "%s: execution failed: %s", path.c_str(), + error.c_str()); + exit_code = kExitFailure; + break; + } + const Execution& execution = result.execution; + std::vector<uint32_t> current = runner->coverage().CurrentEdges(); + if (run == 0) { + edges_in_all_runs = current; + } else { + std::vector<uint32_t> intersection; + std::set_intersection(edges_in_all_runs.begin(), + edges_in_all_runs.end(), current.begin(), + current.end(), std::back_inserter(intersection)); + edges_in_all_runs.swap(intersection); + } + edges_in_any_run.insert(current.begin(), current.end()); + + printf("%s%s: %s", path.c_str(), + repeat > 1 ? StringPrintf(" [run %d]", run + 1).c_str() : "", + OutcomeName(execution.outcome)); + if (execution.outcome == Outcome::kFailed) { + printf(" (exit code %d)", execution.exit_code); + } else if (execution.outcome == Outcome::kCrashed) { + printf(" (signal %d)", execution.signal); + } + printf(" in %.1f ms, %u edges hit, %zu new, %u found total (%.3f%%)\n", + static_cast<double>(execution.exec_time_us) / 1000.0, + result.edges_hit, result.new_edges.size(), + runner->coverage().found_edges(), + runner->coverage().coverage_fraction() * 100.0); + if (print_output) { + PrintOutput("stdout", execution.stdout_output); + PrintOutput("stderr", execution.stderr_output); + PrintOutput("fuzzout", execution.fuzzout); + } + if (print_edges && !result.new_edges.empty()) { + printf("new edges:"); + for (uint32_t edge : result.new_edges) { + printf(" %u", edge); + } + printf("\n"); + } + if (events.is_open()) { + JsonObject event; + event.Add("event", "exec") + .Add("file", path) + .Add("run", run) + .Add("outcome", OutcomeName(execution.outcome)) + .Add("exit_code", execution.exit_code) + .Add("signal", execution.signal) + .Add("exec_us", execution.exec_time_us) + .Add("edges_hit", result.edges_hit) + .Add("new_edges", static_cast<uint64_t>(result.new_edges.size())) + .Add("found_edges", runner->coverage().found_edges()); + if (print_edges) { + event.AddArray("new_edge_list", result.new_edges); + } + events.Write(event); + } + } + if (repeat > 1) { + printf( + "%s: %zu edges hit in every run, %zu in at least one run " + "(%zu non-deterministic)\n", + path.c_str(), edges_in_all_runs.size(), edges_in_any_run.size(), + edges_in_any_run.size() - edges_in_all_runs.size()); + } + } + + const ScriptRunner::Stats& stats = runner->stats(); + REDLINE_LOG(kLog, + "%llu executions: %llu succeeded, %llu failed, %llu crashed, " + "%llu timed out; %llu spawns", + static_cast<unsigned long long>(stats.executions), + static_cast<unsigned long long>(stats.succeeded), + static_cast<unsigned long long>(stats.failed), + static_cast<unsigned long long>(stats.crashed), + static_cast<unsigned long long>(stats.timed_out), + static_cast<unsigned long long>(runner->child().total_spawns())); + return exit_code; +} + +} // namespace + +const Command kExecCommand = { + "exec", + "Run JavaScript files through the target and report coverage", + "usage: redline exec --d8=PATH [options] FILE.js...\n" + "\n" + "Runs each file (in order, in the same target process, like the fuzzer\n" + "would) and prints outcome, execution time and the number of new edges.\n" + "\n" + "options:\n" + " --repeat=N run each file N times and report edge stability\n" + " --print-output dump the target's stdout, stderr and fuzzout\n" + " --print-edges list the indices of newly found edges\n" + " --events=FILE write one JSON object per execution to FILE\n", + RunExec, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/fuzz_command.cc b/deps/v8/experimental/redline/commands/fuzz_command.cc new file mode 100644 index 000000000000..fff16153fa66 --- /dev/null +++ b/deps/v8/experimental/redline/commands/fuzz_command.cc @@ -0,0 +1,228 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// redline fuzz: the coverage-guided fuzzing session. + +#include <unistd.h> + +#include <atomic> +#include <csignal> +#include <cstdio> +#include <string> + +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/engine/config.h" +#include "experimental/redline/engine/fuzzer.h" + +namespace redline { + +namespace { + +constexpr char kLog[] = "fuzz"; + +const char kUsage[] = + "usage: redline fuzz --d8=PATH [options]\n" + "\n" + "Runs a coverage-guided fuzzing session against the instrumented d8:\n" + "imports the seed programs, then repeatedly picks a corpus program,\n" + "mutates it, executes it, and keeps it if it reaches new deterministic\n" + "edges (after minimization). Stops on --duration/--max-execs or Ctrl-C\n" + "(a second Ctrl-C aborts immediately).\n" + "\n" + "output (--out=DIR, default redline-out):\n" + " DIR/corpus/NNNNNN.js every corpus program with its lineage header\n" + " DIR/crashes/*.js|.txt crashing programs (minimized) and their " + "reports;\n" + " *.orig.js the unminimized program, *.history/\n" + " the programs a state-dependent crash needs " + "first\n" + " DIR/crashes/signatures.txt one line per distinct crash signature\n" + " DIR/events.jsonl one JSON object per event (start, import,\n" + " corpus_add, crash, flaky, stats, end)\n" + "\n" + "session options:\n" + " --import=DIR|FILE,... seed programs (directories are searched for\n" + " .js files; load() calls are inlined)\n" + " --import-root=DIR base directory for load(\"test/...\") paths\n" + " --import-all keep seeds that run fine but add no coverage\n" + " --jobs=N worker threads, one d8 each (default 1)\n" + " --seed=S run seed (default: clock); --jobs=1 runs are\n" + " reproducible given a deterministic target\n" + " --duration=SEC stop after SEC seconds\n" + " --max-execs=N stop after N target executions\n" + " --out=DIR output directory\n" + " --preset=NAME|FILE a configuration for one use case, applied " + "before\n" + " --config and the flags: default, maglev,\n" + " turbolev, runtime, parser, builtins, wasm\n" + " (experimental/redline/presets/NAME.json) or a " + "file\n" + " --config=FILE|'{json}' JSON configuration (see --help-config); " + "inline\n" + " JSON sets any key without a dedicated flag\n" + " --stats-interval=SEC print statistics every SEC seconds (30)\n" + " --no-component-stats omit the per-mutator/reducer tables\n" + " --quiet no periodic statistics\n" + " --prelude=FILE|none JS prepended at execution time (default: the\n" + " mjsunit assertion shim)\n" + " --v8-flags=\"...\" flags for the in-process V8 syntax oracle\n" + " --syntax-check parse every mutant and minimizer probe " + "in-process\n" + " before running it (off: the target's " + "SyntaxError\n" + " counts it as invalid; saves ~1 ms of CPU per " + "mutant)\n" + " --no-introspect do not enumerate the target's globals at " + "startup\n" + " (the DiscoveredApi generator then has " + "nothing)\n" + "\n" + "policy options (all also settable in the config file):\n" + " --scheduler=NAME uniform (default), recency, tournament,\n" + " productive, rarity (--preset=default)\n" + " --mutator-weights=Name=W,... override mutator weights (0 disables)\n" + " --generator-weights=Name=W,... override generator weights\n" + " --disable-mutator=Name,... shorthand for weight 0\n" + " --disable-generator=Name,...\n" + " --consecutive-mutations=N mutations chained per picked parent (5)\n" + " --rounds=N sub-mutations per mutation (0: 1..7 at " + "random,\n" + " 1..3 for CodeGen, like Fuzzilli)\n" + " --min-reruns=N re-runs of every candidate (5)\n" + " --min-stable-reruns=N consecutive re-runs without edge loss that " + "end\n" + " the determinism check (1)\n" + " --max-reruns=N re-run budget per candidate (50; a candidate\n" + " that has not converged by then is dropped)\n" + " --flaky-threshold=N suppress an edge after N determinism\n" + " failures (50; suppressed edges do not count)\n" + " --no-value-prefix do not prepend fresh values to mutation " + "parents\n" + " --prefix-min-values=N fresh values of the prefix: N plus 0..M (10)\n" + " --prefix-extra-values=M (5)\n" + " --capture=RULE[;RULE] save the programs of a stage when a trigger " + "fires:\n" + " " + "STAGE:TRIGGER[,TRIGGER..][:MUTATOR[,MUTATOR..]][:MAX]\n" + " e.g. mutate:timeout:Splice:50 or " + "check:flaky:20;\n" + " files go to OUT/captures/<stage>/ (see " + "--help-config)\n" + " --stage-log=STAGE,... one JSONL event per occurrence of a stage\n" + " (pick, prefix, mutate, check, minimize, " + "publish)\n" + " --tunable=NAME=V,... set numbers inside " + "generators/mutators/reducers\n" + " --help-tunables list them with defaults, ranges and " + "documentation\n" + " --no-minimize do not minimize new corpus programs\n" + " --no-minimize-crashes do not minimize crashes\n" + " --minimize-imports minimize imported seeds too\n" + " --minimizer-max-tests=N oracle executions per minimization (300)\n" + " --minimizer-max-time-ms=N wall-clock bound per minimization (30000)\n" + " --minimizer-target-time-ms=N scale the test budget of slow programs\n" + " down to about N ms per minimization (6000;\n" + " 0 = always max-tests)\n" + " --crash-reruns=N fresh-target re-executions to check whether a\n" + " crash reproduces (3)\n" + " --max-crashes-per-signature=N crash files kept per crash signature\n" + " (5; further ones are only counted)\n" + " --minimize-crashes-per-signature=N ... of which N are minimized (2)\n" + " --crash-history=N for crashes that do not reproduce alone: " + "replay\n" + " up to N preceding programs of the same target\n" + " to find state-dependent crashes (100; 0 = " + "off)\n" + " --crash-history-budget=SEC time limit for that replay (90)\n" + " --crash-minimizer-max-tests=N, --crash-minimizer-max-time-ms=N\n" + " minimization budget for crashes (1000, " + "120000)\n" + " --initial-programs=N bootstrap from generated programs until the\n" + " corpus has N entries (32)\n" + " --no-save-corpus do not write DIR/corpus\n" + " --help-config print the config file format and exit\n" + " --dump-config print the complete effective configuration " + "(every\n" + " key, tunable and strategy parameter, defaults\n" + " included) as JSON and exit; needs no target\n" + "\n"; + +std::atomic<Fuzzer*> g_fuzzer{nullptr}; +std::atomic<int> g_interrupts{0}; + +void HandleInterrupt(int /*signal*/) { + int count = g_interrupts.fetch_add(1) + 1; + if (count >= 2) { + _exit(130); + } + Fuzzer* fuzzer = g_fuzzer.load(); + if (fuzzer != nullptr) { + fuzzer->RequestStop(); + } + const char message[] = "\n[redline] stopping (press Ctrl-C again to abort)\n"; + ssize_t ignored = write(STDERR_FILENO, message, sizeof(message) - 1); + (void)ignored; +} + +int Run(const Flags& flags) { + if (flags.GetBool("help-config", false)) { + fputs(FuzzConfig::JsonHelp().c_str(), stdout); + return kExitOk; + } + if (flags.GetBool("help-tunables", false)) { + printf( + "tunables (set with \"tunables\": {name: value} in --config or " + "--tunable=name=value,...):\n"); + fputs(TunableRegistry::Instance().Help().c_str(), stdout); + return kExitOk; + } + FuzzConfig config; + std::string error; + const bool dump = flags.GetBool("dump-config", false); + if (!FuzzConfig::Load(flags, &config, &error, /*for_run=*/!dump)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + if (dump) { + printf("%s\n", + JsonPretty(config.ToJson(FuzzConfig::Detail::kFull)).c_str()); + return kExitOk; + } + std::vector<std::string> unused = flags.UnusedFlags(); + for (const std::string& flag : unused) { + if (flag == "log-level" || flag == "verbose") { + continue; + } + REDLINE_WARN(kLog, "unknown flag --%s (ignored)", flag.c_str()); + } + + Fuzzer fuzzer(config); + if (!fuzzer.Initialize(&error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + g_fuzzer.store(&fuzzer); + struct sigaction action = {}; + action.sa_handler = HandleInterrupt; + sigaction(SIGINT, &action, nullptr); + sigaction(SIGTERM, &action, nullptr); + int result = fuzzer.Run(); + g_fuzzer.store(nullptr); + return result == 0 ? kExitOk : kExitFailure; +} + +} // namespace + +const Command kFuzzCommand = { + "fuzz", + "Run a coverage-guided fuzzing session (the main command)", + kUsage, + Run, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/minimize_command.cc b/deps/v8/experimental/redline/commands/minimize_command.cc new file mode 100644 index 000000000000..ed0283318cbd --- /dev/null +++ b/deps/v8/experimental/redline/commands/minimize_command.cc @@ -0,0 +1,352 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// redline minimize: run the minimizer (or single reducers) on a program +// against a chosen oracle, outside of a fuzzing session. + +#include <algorithm> +#include <cstdio> +#include <iterator> +#include <memory> +#include <string> +#include <vector> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/base/v8_runtime.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/core/component.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/engine/prelude.h" +#include "experimental/redline/exec/runner.h" +#include "experimental/redline/exec/target_options.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/minimizer/minimizer.h" + +namespace redline { + +namespace { + +constexpr char kLog[] = "minimize"; + +const char kUsage[] = + "usage: redline minimize --d8=PATH [options] FILE.js\n" + "\n" + "Minimizes FILE.js while an oracle keeps holding, and prints the result\n" + "(or writes it with --out=FILE). Oracles:\n" + " --oracle=edges (default) the edges the program reaches on its\n" + " first run and that survive --reruns re-executions\n" + " must still be reached, by a successful execution.\n" + " With --baseline=FILE,... only the edges that none\n" + " of the baseline programs reach count (this is what\n" + " the fuzzer preserves: the edges new w.r.t. the\n" + " parent)\n" + " --oracle=crash the program must still crash\n" + " --oracle=fail the program must still fail (uncaught exception)\n" + " --oracle=output stdout of the program must stay identical\n" + "\n" + "options:\n" + " --baseline=FILE,... programs whose edges are subtracted (edges oracle)\n" + " --reducer=NAME,... run only these reducers, in this order (see " + "--list)\n" + " --max-tests=N oracle executions (default 300)\n" + " --max-time-ms=N wall-clock bound (default 30000)\n" + " --reruns=N re-runs to settle the edge set (default 2)\n" + " --probe-timeout-ms=N timeout for the reduced candidates (default:\n" + " 5x the program's run time + 20 ms, at least 50 ms;\n" + " a reduction can create an endless loop)\n" + " --prelude=FILE|none JS prepended at execution time (default: the\n" + " mjsunit shim)\n" + " --out=FILE write the result to FILE instead of stdout\n" + " --list list the reducers and exit\n" + " --v8-flags=\"...\" flags for the in-process V8 syntax oracle\n" + "\n"; + +int Run(const Flags& flags) { + Minimizer minimizer; + if (flags.GetBool("list", false)) { + printf("reducers (default order):\n"); + for (const auto& reducer : minimizer.reducers()) { + printf(" %-12s %s\n", reducer->name().c_str(), + std::string(reducer->description()).c_str()); + } + return kExitOk; + } + if (flags.positional().size() != 1) { + fputs(kUsage, stderr); + return kExitUsage; + } + const std::string& path = flags.positional()[0]; + std::string source, error; + if (!ReadFileToString(path, &source, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + Lineage lineage; + lineage.origin = "import"; + lineage.detail = path; + std::shared_ptr<Program> program = Program::Parse(source, lineage, &error); + if (program == nullptr) { + REDLINE_ERROR(kLog, "%s: %s", path.c_str(), error.c_str()); + return kExitFailure; + } + + std::vector<Reducer*> reducers; + for (const std::string& name : flags.GetList("reducer")) { + Reducer* reducer = minimizer.Find(name); + if (reducer == nullptr) { + REDLINE_ERROR(kLog, "unknown reducer '%s' (see --list)", name.c_str()); + return kExitUsage; + } + reducers.push_back(reducer); + } + if (reducers.empty()) { + for (const auto& reducer : minimizer.reducers()) { + reducers.push_back(reducer.get()); + } + } + MinimizerOptions options; + options.max_tests = + static_cast<int>(flags.GetInt("max-tests", options.max_tests)); + options.max_time_ms = static_cast<uint64_t>( + flags.GetInt("max-time-ms", static_cast<int64_t>(options.max_time_ms))); + Minimizer configured(options); + // Use the reducers of `minimizer` (which carry the stats) with the + // configured budget. + std::string oracle_name = flags.GetString("oracle", "edges"); + std::string prelude; + std::string prelude_flag = flags.GetString("prelude"); + if (prelude_flag.empty()) { + prelude = std::string(DefaultPrelude()); + } else if (prelude_flag != "none" && + !ReadFileToString(prelude_flag, &prelude, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + + if (!InitializeV8(flags.GetString( + "v8-flags", + "--allow-natives-syntax --js-staging --js-decorators"), + &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + SyntaxChecker checker; + TargetOptions target; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + std::unique_ptr<ScriptRunner> runner = + ScriptRunner::Create(target, 0, &error); + if (runner == nullptr || !runner->Initialize(&error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + auto execute = [&](const std::string& candidate, Execution* execution, + uint64_t timeout_us) { + std::string script = + prelude.empty() ? candidate : prelude + "\n" + candidate; + std::string exec_error; + if (!runner->RunWithoutEvaluation(script, timeout_us, execution, + &exec_error)) { + REDLINE_WARN(kLog, "execution failed: %s", exec_error.c_str()); + return false; + } + return true; + }; + auto execute_full = [&](const std::string& candidate, Execution* execution) { + return execute(candidate, execution, target.timeout_us); + }; + + // Establish the property on the original program. + Execution first; + if (!execute_full(program->source(), &first)) { + return kExitFailure; + } + uint64_t probe_timeout_us = + static_cast<uint64_t>(flags.GetInt("probe-timeout-ms", 0)) * 1000; + if (probe_timeout_us == 0) { + probe_timeout_us = + std::max<uint64_t>(5 * first.exec_time_us + 20'000, 50'000); + } + probe_timeout_us = std::min(probe_timeout_us, target.timeout_us); + + std::vector<uint32_t> edges; + std::string expected_output; + MinimizationOracle oracle; + if (oracle_name == "edges") { + if (!first.succeeded()) { + REDLINE_ERROR(kLog, + "the program does not run successfully (outcome %s); use " + "--oracle=crash/fail", + first.crashed() ? "crashed" + : first.timed_out() ? "timed out" + : "failed"); + return kExitFailure; + } + edges = runner->coverage().CurrentEdges(); + int reruns = static_cast<int>(flags.GetInt("reruns", 2)); + for (int i = 0; i < reruns; i++) { + Execution again; + if (!execute_full(program->source(), &again) || !again.succeeded()) { + REDLINE_ERROR( + kLog, + "the program is not deterministic (re-run %d did not succeed)", + i + 1); + return kExitFailure; + } + std::vector<uint32_t> missing = runner->coverage().MissingEdges(edges); + if (!missing.empty()) { + std::vector<uint32_t> kept; + std::set_difference(edges.begin(), edges.end(), missing.begin(), + missing.end(), std::back_inserter(kept)); + edges.swap(kept); + } + } + size_t settled = edges.size(); + // Subtract everything the baseline programs reach in any of their runs. + std::vector<std::string> baselines = flags.GetList("baseline"); + if (!baselines.empty()) { + std::vector<uint8_t> seen(runner->coverage().num_edges() + 1, 0); + for (const std::string& baseline_path : baselines) { + std::string baseline; + if (!ReadFileToString(baseline_path, &baseline, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + for (int i = 0; i <= reruns; i++) { + Execution run; + if (!execute_full(baseline, &run)) { + return kExitFailure; + } + for (uint32_t edge : runner->coverage().CurrentEdges()) { + if (edge < seen.size()) { + seen[edge] = 1; + } + } + } + } + std::vector<uint32_t> remaining; + for (uint32_t edge : edges) { + if (edge >= seen.size() || !seen[edge]) { + remaining.push_back(edge); + } + } + edges.swap(remaining); + if (edges.empty()) { + REDLINE_ERROR( + kLog, + "the program reaches no edge beyond the %zu baseline program(s)", + baselines.size()); + return kExitFailure; + } + } + REDLINE_LOG(kLog, + "preserving %zu edges (%zu settled over %d re-runs%s); probe " + "timeout %llu ms", + edges.size(), settled, reruns, + baselines.empty() ? "" : ", minus the baseline", + static_cast<unsigned long long>(probe_timeout_us / 1000)); + oracle = [&](const std::string& candidate) { + Execution execution; + return execute(candidate, &execution, probe_timeout_us) && + execution.succeeded() && runner->coverage().AllEdgesSet(edges); + }; + } else if (oracle_name == "crash") { + if (!first.crashed()) { + REDLINE_ERROR(kLog, "the program does not crash (exit code %d)", + first.exit_code); + return kExitFailure; + } + oracle = [&](const std::string& candidate) { + Execution execution; + return execute(candidate, &execution, probe_timeout_us) && + execution.crashed(); + }; + } else if (oracle_name == "fail") { + if (first.outcome != Outcome::kFailed) { + REDLINE_ERROR(kLog, "the program does not fail"); + return kExitFailure; + } + std::string signature = first.ExceptionSignature(); + if (signature.empty()) { + REDLINE_LOG(kLog, + "preserving the failure (no exception message captured)"); + } else { + REDLINE_LOG(kLog, "preserving the failure `%s`", signature.c_str()); + } + oracle = [&, signature](const std::string& candidate) { + Execution execution; + return execute(candidate, &execution, probe_timeout_us) && + execution.outcome == Outcome::kFailed && + execution.ExceptionSignature() == signature; + }; + } else if (oracle_name == "output") { + expected_output = first.stdout_output; + oracle = [&](const std::string& candidate) { + Execution execution; + return execute(candidate, &execution, probe_timeout_us) && + execution.outcome == first.outcome && + execution.stdout_output == expected_output; + }; + } else { + REDLINE_ERROR(kLog, "unknown oracle '%s'", oracle_name.c_str()); + return kExitUsage; + } + + std::unique_ptr<fast::Tree> tree = program->CopyTree(); + MinimizationResult result = + configured.MinimizeWith(reducers, tree.get(), oracle, &checker); + std::string minimized = fast::Print(tree->root()); + + // Verify the result once more (a few attempts: the target is not fully + // deterministic, see the fuzzer's determinism check). + bool holds = false; + for (int attempt = 0; attempt < 3 && !holds; attempt++) { + holds = oracle(minimized); + } + std::string out_path = flags.GetString("out"); + if (!out_path.empty()) { + if (!WriteStringToFile(out_path, minimized, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + } else { + printf("%s\n", minimized.c_str()); + } + std::vector<const Component*> components; + components.reserve(reducers.size()); + for (Reducer* reducer : reducers) { + components.push_back(reducer); + } + fputs(FormatStatsTable("reducers", components).c_str(), stderr); + REDLINE_LOG(kLog, + "%zu -> %zu nodes (%.1f%%), %d tests (%d accepted, %d " + "syntax-rejected) in %.1f s%s; " + "property %s on the result", + result.nodes_before, result.nodes_after, + result.nodes_before + ? 100.0 * static_cast<double>(result.nodes_after) / + static_cast<double>(result.nodes_before) + : 0.0, + result.tests, result.accepted, result.syntax_rejected, + static_cast<double>(result.time_us) / 1e6, + result.budget_exhausted ? " (budget exhausted)" : "", + holds ? "HOLDS" : "DOES NOT HOLD"); + return holds ? kExitOk : kExitFailure; +} + +} // namespace + +const Command kMinimizeCommand = { + "minimize", + "Minimize a program while an oracle (edges, crash, fail, output) holds", + kUsage, + Run, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/mutate_command.cc b/deps/v8/experimental/redline/commands/mutate_command.cc new file mode 100644 index 000000000000..2dbc55ef385f --- /dev/null +++ b/deps/v8/experimental/redline/commands/mutate_command.cc @@ -0,0 +1,664 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline mutate": applies mutators or generators to a program and measures +// how often the result is accepted by V8's parser and, optionally, how it +// behaves when executed. This is the black-box test bench for every +// mutator/generator and the way to look at what they produce. +// +// "redline audit" is the same bench in one fixed mode: every generator from +// an empty program, run in the target, crashes counted per signature. + +#include <algorithm> +#include <cstdio> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/base/v8_runtime.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/core/builder.h" +#include "experimental/redline/core/component.h" +#include "experimental/redline/core/environment.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/core/random.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/engine/config.h" +#include "experimental/redline/engine/crash.h" +#include "experimental/redline/engine/prelude.h" +#include "experimental/redline/exec/execution.h" +#include "experimental/redline/exec/runner.h" +#include "experimental/redline/exec/target_options.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/generators/generator.h" +#include "experimental/redline/mutators/mutator.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "mutate"; + +const char kUsage[] = + "usage: redline mutate [flags] FILE...\n" + " redline mutate [flags] --source=CODE\n" + " redline mutate [flags] --generate\n" + "\n" + "Applies mutators (or generators) to the input program(s) and reports\n" + "how many results V8 accepts syntactically and, with --run, how they\n" + "behave in d8. Use it to test and look at every mutator/generator.\n" + "\n" + "flags:\n" + " --mutator=NAME,...|all mutators to apply (default: all)\n" + " --generator=NAME,...|all test generators instead: each sample inserts\n" + " generated code at a random place of the input\n" + " --generate start from an empty program\n" + " --n=K samples per mutator/generator and input (20)\n" + " --rounds=R sub-mutations per sample (1)\n" + " --seed=S base seed (1); sample i uses seed S+i\n" + " --partner=FILE donor program for Splice/Combine (default:\n" + " the next input file, or the input itself)\n" + " --print print every produced program\n" + " --print-invalid print programs V8 rejects, with the error\n" + " --print-failed print programs that fail at runtime (--run)\n" + " --out-dir=DIR also write samples to DIR/<name>-<i>.js\n" + " --run execute results in d8 (--d8=PATH or " + "$REDLINE_D8)\n" + " --d8-args=ARGS --timeout-ms=N target options for --run\n" + " --prelude=FILE|none JS prepended at execution time (default: the\n" + " built-in mjsunit assertion stubs)\n" + " --v8-flags=FLAGS flags for the in-process V8 syntax oracle\n" + " --tunable=NAME=V,... set numbers inside generators/mutators (the " + "same\n" + " names as redline fuzz --help-tunables)\n" + " --list list mutators and generators and exit\n" + " --no-introspect with --run: do not ask the target about its " + "globals\n" + " --quiet only print the summary\n"; + +const char kAuditUsage[] = + "usage: redline audit --d8=PATH [flags]\n" + "\n" + "Overfitting check for generators (DESIGN.md 10). Generates --n programs\n" + "per generator from an empty program, runs each one in d8 and counts the\n" + "crashes per crash signature. A generator fails if one signature takes\n" + "more than --threshold percent of its programs: it is then closer to a\n" + "template of that crash than to a general generator. Run it against a\n" + "d8 with known bugs. Exits non-zero if a generator fails.\n" + "\n" + "flags:\n" + " --generator=NAME,...|all generators to check (default: all)\n" + " --n=K programs per generator (400)\n" + " --threshold=PCT largest allowed share of one signature (0.5)\n" + " --seed=S base seed (1)\n" + " --d8-args=ARGS --d8-extra-args=ARGS --timeout-ms=N target options\n" + " --tunable=NAME=V,... audit with these tunable values\n" + " --print print every program\n" + " --out-dir=DIR write every program to DIR/<name>-0-<i>.js\n" + " --quiet no line per crash, only the tables\n" + " --no-introspect do not ask the target about its globals\n"; + +struct Options { + std::vector<std::string> files; + std::string source; + bool generate = false; + std::vector<std::string> mutators; + std::vector<std::string> generators; + bool generator_mode = false; + int n = 20; + int rounds = 1; + uint64_t seed = 1; + std::string partner; + bool print = false; + bool print_invalid = false; + bool print_failed = false; + std::string out_dir; + bool run = false; + bool list = false; + bool quiet = false; + bool introspect = true; + std::string v8_flags; + std::string prelude; + // redline audit: crash signatures per generator, judged by `threshold`. + bool audit = false; + double threshold = 0.5; +}; + +bool ParseOptions(const Flags& flags, Options* o, bool audit) { + o->files = flags.positional(); + o->source = flags.GetString("source"); + o->generate = flags.GetBool("generate", false); + if (flags.Has("generator")) { + o->generator_mode = true; + std::string g = flags.GetString("generator", "all"); + if (g != "all") { + o->generators = flags.GetList("generator"); + } + } + std::string m = flags.GetString("mutator", "all"); + if (m != "all") { + o->mutators = flags.GetList("mutator"); + } + o->n = static_cast<int>(flags.GetInt("n", audit ? 400 : 20)); + o->rounds = static_cast<int>(flags.GetInt("rounds", 1)); + o->seed = static_cast<uint64_t>(flags.GetInt("seed", 1)); + o->partner = flags.GetString("partner"); + o->print = flags.GetBool("print", false); + o->print_invalid = flags.GetBool("print-invalid", false); + o->print_failed = flags.GetBool("print-failed", false); + o->out_dir = flags.GetString("out-dir"); + o->run = flags.GetBool("run", false); + o->list = flags.GetBool("list", false); + o->quiet = flags.GetBool("quiet", false); + o->introspect = flags.GetBool("introspect", true); + o->v8_flags = flags.GetString( + "v8-flags", "--allow-natives-syntax --js-staging --js-decorators"); + std::string prelude = flags.GetString("prelude"); + if (prelude.empty()) { + o->prelude = std::string(DefaultPrelude()); + } else if (prelude != "none") { + std::string error; + if (!ReadFileToString(prelude, &o->prelude, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return false; + } + } + if (flags.Has("tunable")) { + std::string error; + if (!TunableRegistry::Instance().SetFromList(flags.GetString("tunable"), + &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return false; + } + } + if (audit) { + o->audit = true; + o->generate = true; + o->generator_mode = true; + o->run = true; + o->threshold = flags.GetDouble("threshold", o->threshold); + } + return true; +} + +void PrintProgram(const char* title, const std::string& source) { + printf("----- %s -----\n", title); + fwrite(source.data(), 1, source.size(), stdout); + if (source.empty() || source.back() != '\n') { + fputc('\n', stdout); + } +} + +std::string FirstLine(const std::string& s) { + size_t nl = s.find('\n'); + std::string line = nl == std::string::npos ? s : s.substr(0, nl); + if (line.size() > 100) { + line = line.substr(0, 97) + "..."; + } + return line; +} + +// Shared evaluation of one produced program: syntax oracle, optional +// execution, printing and statistics. +class Evaluator { + public: + Evaluator(const Options& options, SyntaxChecker* checker, + ScriptRunner* runner) + : options_(options), checker_(checker), runner_(runner) {} + + void Evaluate(Component* component, const std::string& name, int index, + const std::string& source, const std::string& detail) { + ComponentStats& stats = component->stats(); + std::string title = + StringPrintf("%s #%d: %s", name.c_str(), index, detail.c_str()); + samples_[name]++; + if (!options_.out_dir.empty()) { + std::string path = + StringPrintf("%s/%s-%zu-%d.js", options_.out_dir.c_str(), + name.c_str(), input_index_, index); + std::string error; + if (!WriteStringToFile(path, source, &error)) { + REDLINE_WARN(kLog, "%s", error.c_str()); + } + } + std::string message; + bool accepted = checker_->Accepts(source, &message); + total_++; + if (!accepted) { + stats.invalid++; + invalid_++; + if (options_.print_invalid || options_.print) { + PrintProgram(title.c_str(), source); + printf("REJECTED: %s\n", message.c_str()); + } + return; + } + if (options_.print) { + PrintProgram(title.c_str(), source); + } + if (runner_ == nullptr) { + return; + } + ScriptRunner::Result result; + std::string error; + // The prelude is an execution-time detail (test harness shims); it is + // never part of the program itself, so it is not printed or saved. + std::string exec_source = + options_.prelude.empty() ? source : options_.prelude + "\n" + source; + if (!runner_->Run(exec_source, &result, &error)) { + REDLINE_WARN(kLog, "execution failed: %s", error.c_str()); + return; + } + stats.executed++; + stats.time_us += result.execution.exec_time_us; + executed_++; + switch (result.execution.outcome) { + case Outcome::kSucceeded: + stats.succeeded++; + succeeded_++; + break; + case Outcome::kFailed: + stats.failed++; + if (options_.print_failed) { + if (!options_.print) { + PrintProgram(title.c_str(), source); + } + printf("FAILED (exit %d): %s\n", result.execution.exit_code, + FirstLine(result.execution.stderr_output.empty() + ? result.execution.stdout_output + : result.execution.stderr_output) + .c_str()); + } + break; + case Outcome::kTimedOut: + stats.timed_out++; + if (options_.print_failed && !options_.print) { + PrintProgram(title.c_str(), source); + } + if (options_.print_failed) { + printf("TIMED OUT\n"); + } + break; + case Outcome::kCrashed: + stats.crashed++; + crashed_++; + if (options_.audit) { + std::string signature = + CrashSignature::FromExecution(result.execution).text; + crashes_[name][signature]++; + if (!options_.quiet) { + printf("CRASH %s: %s\n", title.c_str(), signature.c_str()); + } + break; + } + PrintProgram(title.c_str(), source); + printf("CRASHED (signal %d)\n", result.execution.signal); + break; + } + if (!result.new_edges.empty()) { + stats.interesting++; + } + } + + uint64_t total() const { return total_; } + uint64_t invalid() const { return invalid_; } + uint64_t executed() const { return executed_; } + uint64_t succeeded() const { return succeeded_; } + uint64_t crashed() const { return crashed_; } + // The index of the input program being processed (part of --out-dir names). + void set_input_index(size_t index) { input_index_ = index; } + + // redline audit: one line per generator that crashed, the generator's + // largest share of one signature, and the verdict. Returns the number of + // generators above the threshold. + int PrintAudit() const { + printf( + "\naudit: largest share of one crash signature per generator " + "(threshold %.2f%%)\n", + options_.threshold); + int failing = 0; + for (const auto& [name, signatures] : crashes_) { + auto top = std::max_element( + signatures.begin(), signatures.end(), + [](const auto& a, const auto& b) { return a.second < b.second; }); + uint64_t samples = samples_.at(name); + double share = 100.0 * static_cast<double>(top->second) / + static_cast<double>(samples); + bool over = share > options_.threshold; + failing += over ? 1 : 0; + printf( + " %s %-26s %4llu of %4llu (%5.2f%%) %s\n", over ? "FAIL" : "ok ", + name.c_str(), static_cast<unsigned long long>(top->second), + static_cast<unsigned long long>(samples), share, top->first.c_str()); + } + printf("audit: %zu of %zu generators crashed, %d above the threshold\n", + crashes_.size(), samples_.size(), failing); + return failing; + } + + private: + const Options& options_; + SyntaxChecker* checker_; + ScriptRunner* runner_; + size_t input_index_ = 0; + uint64_t total_ = 0; + uint64_t invalid_ = 0; + uint64_t executed_ = 0; + uint64_t succeeded_ = 0; + uint64_t crashed_ = 0; + // Programs per component, and crash signature -> count per component. + std::map<std::string, uint64_t> samples_; + std::map<std::string, std::map<std::string, uint64_t>> crashes_; +}; + +int RunBench(const Flags& flags, bool audit) { + Options options; + if (!ParseOptions(flags, &options, audit)) { + return kExitUsage; + } + + std::unique_ptr<MutatorSet> mutators = MutatorSet::CreateDefault(); + std::unique_ptr<GeneratorSet> generators = GeneratorSet::CreateDefault(); + + if (options.list) { + printf("mutators:\n"); + for (const auto& m : mutators->all()) { + printf(" %-14s w=%-4g %s%s\n", m->name().c_str(), m->weight(), + std::string(m->description()).c_str(), + m->needs_partner() ? " [needs partner]" : ""); + } + printf("generators:\n"); + for (const auto& g : generators->all()) { + printf(" %-18s w=%-4g %s\n", g->name().c_str(), g->weight(), + std::string(g->description()).c_str()); + } + return kExitOk; + } + + // Inputs. + std::vector<std::pair<std::string, std::string>> inputs; // name, source + if (options.generate) { + inputs.emplace_back("empty", ""); + } else if (flags.Has("source")) { + inputs.emplace_back("<source>", options.source); + } else { + for (const std::string& path : options.files) { + std::string source, error; + if (!ReadFileToString(path, &source, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + inputs.emplace_back(path, source); + } + } + if (inputs.empty()) { + fputs(kUsage, stderr); + return kExitUsage; + } + std::vector<ProgramPtr> programs; + for (const auto& [name, source] : inputs) { + std::string error; + Lineage lineage; + lineage.origin = "import"; + lineage.detail = name; + ProgramPtr program = Program::Parse(source, lineage, &error); + if (program == nullptr) { + REDLINE_ERROR(kLog, "%s: %s", name.c_str(), error.c_str()); + return kExitFailure; + } + programs.push_back(program); + } + ProgramPtr explicit_partner; + if (!options.partner.empty()) { + std::string source, error; + if (!ReadFileToString(options.partner, &source, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + Lineage lineage; + lineage.origin = "import"; + lineage.detail = options.partner; + explicit_partner = Program::Parse(source, lineage, &error); + if (explicit_partner == nullptr) { + REDLINE_ERROR(kLog, "%s: %s", options.partner.c_str(), error.c_str()); + return kExitFailure; + } + } + + // Selection. + std::vector<Mutator*> selected_mutators; + std::vector<Generator*> selected_generators; + if (options.generator_mode) { + if (options.generators.empty()) { + for (const auto& g : generators->all()) { + selected_generators.push_back(g.get()); + } + } else { + for (const std::string& name : options.generators) { + Generator* g = generators->Find(name); + if (g == nullptr) { + REDLINE_ERROR(kLog, "unknown generator '%s' (see --list)", + name.c_str()); + return kExitUsage; + } + selected_generators.push_back(g); + } + } + } else if (options.mutators.empty()) { + for (const auto& m : mutators->all()) { + selected_mutators.push_back(m.get()); + } + } else { + for (const std::string& name : options.mutators) { + Mutator* m = mutators->Find(name); + if (m == nullptr) { + REDLINE_ERROR(kLog, "unknown mutator '%s' (see --list)", name.c_str()); + return kExitUsage; + } + selected_mutators.push_back(m); + } + } + + // Oracle and target. + std::string error; + if (!InitializeV8(options.v8_flags, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + SyntaxChecker checker; + std::unique_ptr<ScriptRunner> runner; + std::unique_ptr<Environment> discovered; + if (options.run) { + TargetOptions target; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + runner = ScriptRunner::Create(target, 0, &error); + if (runner == nullptr || !runner->Initialize(&error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + // Like a fuzzing session: ask the target what it offers, so that the + // generators using the discovered API produce the same code here. + if (options.introspect) { + Execution execution; + const uint64_t timeout_us = + static_cast<uint64_t>(FuzzConfig().introspect_timeout_ms * 1000.0); + if (runner->RunWithoutEvaluation(Environment::IntrospectionScript(), + timeout_us, &execution, &error) && + execution.succeeded()) { + discovered = Environment::WithDiscovered(execution.fuzzout, &error); + } + if (discovered == nullptr) { + REDLINE_WARN( + kLog, + "environment introspection failed (%s); using the built-in model", + error.c_str()); + } else { + REDLINE_LOG(kLog, + "environment: %zu globals/namespaces with %zu members " + "discovered in the target", + discovered->discovered().size(), + discovered->discovered_member_count()); + } + } + } + const Environment& env = + discovered != nullptr ? *discovered : Environment::Default(); + if (!options.out_dir.empty() && !MakeDirectories(options.out_dir, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + + Evaluator evaluator(options, &checker, runner.get()); + Stopwatch stopwatch; + uint64_t noop = 0; + uint64_t mutation_time_us = 0; + + for (size_t input = 0; input < programs.size(); input++) { + evaluator.set_input_index(input); + const ProgramPtr& parent = programs[input]; + ProgramPtr partner = explicit_partner; + if (partner == nullptr) { + partner = programs.size() > 1 ? programs[(input + 1) % programs.size()] + : parent; + } + if (options.generator_mode) { + for (Generator* g : selected_generators) { + for (int i = 0; i < options.n; i++) { + Random rng(options.seed + static_cast<uint64_t>(i) * 7919 + + Program::HashSource(g->name()) + input * 104729); + std::unique_ptr<fast::Tree> tree = parent->CopyTree(); + Builder builder(tree.get(), &rng); + Stopwatch sw; + std::vector<fast::Statement*> out; + Builder::Slot slot; + bool generated = false; + for (int attempt = 0; attempt < 10 && !generated; attempt++) { + slot = builder.RandomInsertionSlot(); + if (!slot.valid()) { + break; + } + GenContext ctx = MakeGenContext(builder, slot, *generators, env); + if (!g->Applicable(ctx)) { + continue; + } + ctx.out = &out; + g->stats().invocations++; + if (g->Generate(ctx, &out) && !out.empty()) { + g->stats().produced++; + generated = true; + } else { + out.clear(); + } + } + mutation_time_us += sw.ElapsedUs(); + if (!generated) { + noop++; + continue; + } + builder.InsertAll(slot, out); + std::string source = fast::Print(tree->root()); + evaluator.Evaluate(g, g->name(), i, source, + StringPrintf("%zu statements", out.size())); + } + } + continue; + } + for (Mutator* m : selected_mutators) { + for (int i = 0; i < options.n; i++) { + Random rng(options.seed + static_cast<uint64_t>(i) * 7919 + + Program::HashSource(m->name()) + input * 104729); + Stopwatch sw; + std::string detail; + std::unique_ptr<fast::Tree> tree = + ApplyMutation(*m, *parent, partner, rng, env, *generators, + options.rounds, &detail); + mutation_time_us += sw.ElapsedUs(); + if (tree == nullptr) { + noop++; + continue; + } + std::string source = fast::Print(tree->root()); + evaluator.Evaluate(m, m->name(), i, source, detail); + } + } + } + + // Summary. + std::vector<const Component*> components; + if (options.generator_mode) { + for (Generator* g : selected_generators) { + components.push_back(g); + } + } else { + for (Mutator* m : selected_mutators) { + components.push_back(m); + } + } + std::string table = FormatStatsTable( + options.generator_mode ? "generators" : "mutators", components); + fputs(table.c_str(), stdout); + if (!options.generator_mode) { + std::string gtable = FormatStatsTable("generators (used by mutators)", + generators->Components()); + fputs(gtable.c_str(), stdout); + } + uint64_t total = evaluator.total(); + uint64_t valid = total - evaluator.invalid(); + printf("summary: %llu produced, %llu no-op, %llu V8-accepted (%.1f%%)", + static_cast<unsigned long long>(total), + static_cast<unsigned long long>(noop), + static_cast<unsigned long long>(valid), + total ? 100.0 * static_cast<double>(valid) / static_cast<double>(total) + : 0.0); + if (runner != nullptr) { + printf(", %llu executed, %llu succeeded (%.1f%%), %llu crashed", + static_cast<unsigned long long>(evaluator.executed()), + static_cast<unsigned long long>(evaluator.succeeded()), + evaluator.executed() + ? 100.0 * static_cast<double>(evaluator.succeeded()) / + static_cast<double>(evaluator.executed()) + : 0.0, + static_cast<unsigned long long>(evaluator.crashed())); + } + printf("; mutation time %.1f ms total (%.2f ms/sample), wall %.1f s\n", + static_cast<double>(mutation_time_us) / 1000.0, + total + noop ? static_cast<double>(mutation_time_us) / 1000.0 / + static_cast<double>(total + noop) + : 0.0, + stopwatch.ElapsedSeconds()); + if (options.audit && evaluator.PrintAudit() > 0) { + return kExitFailure; + } + return kExitOk; +} + +int Run(const Flags& flags) { return RunBench(flags, /*audit=*/false); } + +int RunAudit(const Flags& flags) { return RunBench(flags, /*audit=*/true); } + +} // namespace + +const Command kMutateCommand = { + "mutate", + "apply mutators/generators to a program and measure validity", + kUsage, + Run, +}; + +const Command kAuditCommand = { + "audit", + "overfitting check: crash signatures per generator, against a threshold", + kAuditUsage, + RunAudit, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/parse_command.cc b/deps/v8/experimental/redline/commands/parse_command.cc new file mode 100644 index 000000000000..77b4ff95806b --- /dev/null +++ b/deps/v8/experimental/redline/commands/parse_command.cc @@ -0,0 +1,247 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline parse": parses JavaScript into FAST, optionally prints it back and +// checks that printing is a fixpoint (parse -> print -> parse -> print gives +// the same text). This is the smallest black-box test of the frontend. + +#include <cstdio> +#include <memory> +#include <string> +#include <vector> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/parser.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/fast/scope.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "parse"; + +const char kUsage[] = + "usage: redline parse [flags] FILE...\n" + " redline parse [flags] --source=CODE\n" + "\n" + "Parses JavaScript into the fuzzer's AST (FAST) and checks that\n" + "printing it is a fixpoint. Exit status is non-zero if any input\n" + "fails to parse or to round-trip.\n" + "\n" + "flags:\n" + " --source=CODE parse this snippet instead of files\n" + " --print print the program as JavaScript\n" + " --compact print everything on one line\n" + " --ids annotate printed statements with node ids\n" + " --no-fixpoint skip the print/reparse/print check\n" + " --no-natives reject %Native() calls\n" + " --strict parse as strict mode code\n" + " --scopes dump the scope analysis (scopes, bindings, refs)\n" + " --rename[=all] rename all variables (or also functions/classes)\n" + " to fresh names before printing\n" + " --stats print node count and timings per input\n" + " --quiet only report failures\n"; + +struct Outcome { + bool parsed = false; + bool fixpoint = true; + size_t nodes = 0; + double parse_ms = 0; + double print_ms = 0; + std::string message; +}; + +struct ScopeFlags { + bool dump = false; + bool rename = false; + fast::RenameScope rename_scope = fast::RenameScope::kVariables; +}; + +Outcome ProcessOne(const std::string& name, const std::string& source, + const fast::ParseOptions& parse_options, + const fast::PrintOptions& print_options, bool do_print, + bool do_fixpoint, const ScopeFlags& scope_flags) { + Outcome outcome; + fast::ParseError error; + Stopwatch stopwatch; + std::unique_ptr<fast::Tree> tree = + fast::Parser::ParseScript(source, parse_options, &error); + outcome.parse_ms = static_cast<double>(stopwatch.ElapsedUs()) / 1000.0; + if (!tree) { + outcome.message = error.ToString(); + return outcome; + } + outcome.parsed = true; + outcome.nodes = fast::CountNodes(tree->root()); + + if (scope_flags.dump || scope_flags.rename) { + stopwatch.Restart(); + std::unique_ptr<fast::ScopeAnalysis> analysis = + fast::ScopeAnalysis::Analyze(tree.get()); + double scope_ms = static_cast<double>(stopwatch.ElapsedUs()) / 1000.0; + if (scope_flags.dump) { + std::string dump = analysis->Dump(); + fwrite(dump.data(), 1, dump.size(), stdout); + printf("%zu scopes, %zu bindings, %zu unresolved, %.2f ms\n", + analysis->scopes().size(), analysis->bindings().size(), + analysis->unresolved().size(), scope_ms); + } + if (scope_flags.rename) { + size_t renamed = fast::RenameAllBindings(tree.get(), analysis.get(), "v", + scope_flags.rename_scope); + REDLINE_VLOG(kLog, "%s: renamed %zu bindings", name.c_str(), renamed); + } + } + + if (!do_print && !do_fixpoint) { + return outcome; + } + + stopwatch.Restart(); + std::string printed = fast::Print(tree->root(), print_options); + outcome.print_ms = static_cast<double>(stopwatch.ElapsedUs()) / 1000.0; + if (do_print) { + fwrite(printed.data(), 1, printed.size(), stdout); + if (printed.empty() || printed.back() != '\n') { + fputc('\n', stdout); + } + } + + if (do_fixpoint) { + // Node id comments are not part of the language; reparse without them. + fast::PrintOptions plain = print_options; + plain.node_ids = false; + std::string first = plain.node_ids == print_options.node_ids + ? printed + : fast::Print(tree->root(), plain); + fast::ParseError reparse_error; + std::unique_ptr<fast::Tree> second = + fast::Parser::ParseScript(first, parse_options, &reparse_error); + if (!second) { + outcome.fixpoint = false; + outcome.message = + "printed program does not reparse: " + reparse_error.ToString(); + return outcome; + } + std::string again = fast::Print(second->root(), plain); + if (again != first) { + outcome.fixpoint = false; + // Find the first differing line for the report. + size_t pos = 0; + size_t limit = std::min(first.size(), again.size()); + while (pos < limit && first[pos] == again[pos]) { + pos++; + } + int line, column; + fast::ComputeLineColumn(first, static_cast<int32_t>(pos), &line, &column); + size_t line_start = first.rfind('\n', pos == 0 ? 0 : pos - 1); + line_start = line_start == std::string::npos ? 0 : line_start + 1; + size_t line_end = first.find('\n', pos); + size_t line_end2 = again.find('\n', pos); + outcome.message = StringPrintf( + "print is not a fixpoint at %d:%d\n first: %s\n second: %s", line, + column, first.substr(line_start, line_end - line_start).c_str(), + again.substr(line_start, line_end2 - line_start).c_str()); + } + if (fast::CountNodes(second->root()) != outcome.nodes && outcome.fixpoint) { + // Not necessarily wrong (e.g. parentheses are not nodes) but worth + // knowing about while the printer is young. + REDLINE_VLOG(kLog, "%s: node count changed on reparse: %zu -> %zu", + name.c_str(), outcome.nodes, + fast::CountNodes(second->root())); + } + } + return outcome; +} + +int RunParse(const Flags& flags) { + fast::ParseOptions parse_options; + parse_options.allow_natives_syntax = !flags.GetBool("no-natives", false); + parse_options.strict = flags.GetBool("strict", false); + fast::PrintOptions print_options; + print_options.pretty = !flags.GetBool("compact", false); + print_options.node_ids = flags.GetBool("ids", false); + bool do_print = flags.GetBool("print", false) || print_options.node_ids; + bool do_fixpoint = flags.GetBool("fixpoint", true); + bool stats = flags.GetBool("stats", false); + bool quiet = flags.GetBool("quiet", false); + ScopeFlags scope_flags; + scope_flags.dump = flags.GetBool("scopes", false); + if (flags.Has("rename")) { + scope_flags.rename = true; + std::string which = flags.GetString("rename", ""); + scope_flags.rename_scope = which == "all" ? fast::RenameScope::kAll + : fast::RenameScope::kVariables; + do_print = do_print || !scope_flags.dump; + } + std::string inline_source = flags.GetString("source"); + + std::vector<std::pair<std::string, std::string>> inputs; + if (flags.Has("source")) { + inputs.emplace_back("<source>", inline_source); + } + for (const std::string& path : flags.positional()) { + std::string contents, error; + if (!ReadFileToString(path, &contents, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + inputs.emplace_back(path, std::move(contents)); + } + if (inputs.empty()) { + fputs(kUsage, stderr); + return kExitUsage; + } + + int failures = 0; + uint64_t total_nodes = 0; + double total_parse_ms = 0; + for (const auto& [name, source] : inputs) { + Outcome outcome = ProcessOne(name, source, parse_options, print_options, + do_print, do_fixpoint, scope_flags); + total_nodes += outcome.nodes; + total_parse_ms += outcome.parse_ms; + if (!outcome.parsed) { + failures++; + printf("FAIL %s: %s\n", name.c_str(), outcome.message.c_str()); + continue; + } + if (!outcome.fixpoint) { + failures++; + printf("FAIL %s: %s\n", name.c_str(), outcome.message.c_str()); + continue; + } + if (!quiet && !do_print) { + printf("OK %s: %zu nodes\n", name.c_str(), outcome.nodes); + } + if (stats) { + printf(" %s: parse %.2f ms, print %.2f ms, %.1f MB/s\n", name.c_str(), + outcome.parse_ms, outcome.print_ms, + outcome.parse_ms > 0 ? static_cast<double>(source.size()) / 1e6 / + (outcome.parse_ms / 1000.0) + : 0.0); + } + } + if (inputs.size() > 1 || stats) { + printf("%zu inputs, %d failed, %llu nodes, parse %.1f ms total\n", + inputs.size(), failures, + static_cast<unsigned long long>(total_nodes), total_parse_ms); + } + return failures == 0 ? kExitOk : kExitFailure; +} + +} // namespace + +const Command kParseCommand = { + "parse", "Parse JavaScript into FAST and check print round-trip", kUsage, + RunParse}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/replay_command.cc b/deps/v8/experimental/redline/commands/replay_command.cc new file mode 100644 index 000000000000..85a5c807cb05 --- /dev/null +++ b/deps/v8/experimental/redline/commands/replay_command.cc @@ -0,0 +1,319 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline replay": executes a directory of JavaScript files through the +// target exactly like the fuzzer would import a corpus, and reports the +// coverage reached. This is the Phase 0 acceptance tool: for the same +// corpus and the same d8 the edge counts must match Fuzzilli's. + +#include <algorithm> +#include <cstdio> +#include <iterator> +#include <random> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/exec/runner.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "replay"; + +struct ReplayTotals { + uint64_t files = 0; + uint64_t unreadable = 0; + uint64_t succeeded = 0; + uint64_t failed = 0; + uint64_t crashed = 0; + uint64_t timed_out = 0; + uint64_t with_new_edges = 0; + uint64_t new_edges = 0; + uint64_t nondeterministic_edges = 0; + uint64_t determinism_runs = 0; +}; + +// Re-runs `script` `attempts` times and drops the edges of `new_edges` that +// are not reached by every run from the coverage state. Returns the number +// of edges dropped. +uint64_t CheckDeterminism(ScriptRunner* runner, const std::string& script, + std::vector<uint32_t>* new_edges, int attempts, + std::string* error) { + std::vector<uint32_t> flaky; + for (int i = 0; i < attempts && !new_edges->empty(); i++) { + Execution execution; + if (!runner->RunWithoutEvaluation(script, runner->options().timeout_us, + &execution, error)) { + break; + } + std::vector<uint32_t> missing; + if (!execution.succeeded()) { + // A program that does not reliably succeed does not reliably cover + // anything either. + missing = *new_edges; + } else { + missing = runner->coverage().MissingEdges(*new_edges); + } + if (missing.empty()) { + continue; + } + std::vector<uint32_t> kept; + std::set_difference(new_edges->begin(), new_edges->end(), missing.begin(), + missing.end(), std::back_inserter(kept)); + new_edges->swap(kept); + flaky.insert(flaky.end(), missing.begin(), missing.end()); + } + if (!flaky.empty()) { + runner->coverage().ForgetEdges(flaky); + } + return flaky.size(); +} + +int RunReplay(const Flags& flags) { + TargetOptions target; + std::string error; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + std::vector<std::string> inputs = flags.GetList("corpus"); + for (const std::string& p : flags.positional()) { + inputs.push_back(p); + } + if (inputs.empty()) { + REDLINE_ERROR(kLog, "No corpus given: pass --corpus=DIR or directories"); + return kExitUsage; + } + std::string suffix = flags.GetString("suffix", ".js"); + int64_t max_files = flags.GetInt("max-files", 0); + bool shuffle = flags.GetBool("shuffle", false); + uint64_t seed = static_cast<uint64_t>(flags.GetInt("seed", 1)); + int determinism = static_cast<int>(flags.GetInt("determinism", 0)); + std::string events_path = flags.GetString("events"); + std::string dump_edges_path = flags.GetString("dump-edges"); + int64_t progress_every = flags.GetInt("progress-every", 500); + + std::vector<std::string> files; + for (const std::string& input : inputs) { + std::vector<std::string> listed = ListFiles(input, suffix); + if (listed.empty()) { + REDLINE_WARN(kLog, "No *%s files found in %s", suffix.c_str(), + input.c_str()); + } + files.insert(files.end(), listed.begin(), listed.end()); + } + if (shuffle) { + std::mt19937_64 rng(seed); + std::shuffle(files.begin(), files.end(), rng); + } + if (max_files > 0 && static_cast<int64_t>(files.size()) > max_files) { + files.resize(static_cast<size_t>(max_files)); + } + if (files.empty()) { + REDLINE_ERROR(kLog, "Nothing to replay"); + return kExitFailure; + } + + JsonlWriter events; + std::vector<uint32_t> all_covered_edges; + if (!events_path.empty() && !events.Open(events_path, /*truncate=*/true)) { + return kExitFailure; + } + + std::unique_ptr<ScriptRunner> runner = + ScriptRunner::Create(target, 0, &error); + if (!runner || !runner->Initialize(&error)) { + REDLINE_ERROR(kLog, "Cannot start target: %s", error.c_str()); + return kExitFailure; + } + REDLINE_LOG(kLog, "Target: %s", target.CommandLine().c_str()); + REDLINE_LOG(kLog, "%u edges instrumented; replaying %zu files", + runner->coverage().num_edges(), files.size()); + if (events.is_open()) { + JsonObject header; + header.Add("event", "start") + .Add("command", "replay") + .Add("target", target.CommandLine()) + .Add("num_edges", runner->coverage().num_edges()) + .Add("files", static_cast<uint64_t>(files.size())) + .Add("timeout_us", target.timeout_us) + .Add("determinism", determinism) + .Add("flags", flags.ToString()) + .Add("wall_ms", WallClockNowMs()); + events.Write(header); + } + + Stopwatch stopwatch; + ReplayTotals totals; + for (size_t i = 0; i < files.size(); i++) { + const std::string& path = files[i]; + totals.files++; + std::string script; + if (!ReadFileToString(path, &script, &error)) { + REDLINE_WARN(kLog, "%s", error.c_str()); + totals.unreadable++; + continue; + } + ScriptRunner::Result result; + if (!runner->Run(script, &result, &error)) { + REDLINE_ERROR(kLog, "%s: %s", path.c_str(), error.c_str()); + return kExitFailure; + } + const Execution& execution = result.execution; + switch (execution.outcome) { + case Outcome::kSucceeded: + totals.succeeded++; + break; + case Outcome::kFailed: + totals.failed++; + break; + case Outcome::kCrashed: + totals.crashed++; + REDLINE_WARN(kLog, "%s crashed the target (signal %d)", path.c_str(), + execution.signal); + break; + case Outcome::kTimedOut: + totals.timed_out++; + break; + } + uint64_t flaky = 0; + if (!result.new_edges.empty() && determinism > 0) { + flaky = CheckDeterminism(runner.get(), script, &result.new_edges, + determinism, &error); + totals.determinism_runs += static_cast<uint64_t>(determinism); + totals.nondeterministic_edges += flaky; + } + + if (!result.new_edges.empty()) { + all_covered_edges.insert(all_covered_edges.end(), + result.new_edges.begin(), + result.new_edges.end()); + totals.with_new_edges++; + totals.new_edges += result.new_edges.size(); + } + if (events.is_open()) { + JsonObject event; + event.Add("event", "file") + .Add("index", static_cast<uint64_t>(i)) + .Add("file", path) + .Add("outcome", OutcomeName(execution.outcome)) + .Add("exit_code", execution.exit_code) + .Add("signal", execution.signal) + .Add("exec_us", execution.exec_time_us) + .Add("edges_hit", result.edges_hit) + .Add("new_edges", static_cast<uint64_t>(result.new_edges.size())) + .Add("flaky_edges", flaky) + .Add("found_edges", runner->coverage().found_edges()); + events.Write(event); + } + if (progress_every > 0 && + (i + 1) % static_cast<size_t>(progress_every) == 0) { + REDLINE_LOG(kLog, "%zu/%zu files, %u edges (%.3f%%), %.1f execs/s", i + 1, + files.size(), runner->coverage().found_edges(), + runner->coverage().coverage_fraction() * 100.0, + static_cast<double>(runner->stats().executions) / + std::max(stopwatch.ElapsedSeconds(), 1e-9)); + } + } + + double wall_s = stopwatch.ElapsedSeconds(); + const ScriptRunner::Stats& stats = runner->stats(); + const CoverageMap& coverage = runner->coverage(); + printf( + "replay: %llu files (%llu unreadable): %llu succeeded, %llu failed, " + "%llu crashed, %llu timed out\n" + "replay: %llu files found new edges; %llu edges found of %u " + "(%.4f%%)%s\n" + "replay: %llu executions in %.1f s (%.1f execs/s, %.1f ms avg target " + "time), %llu target spawns, %llu infrastructure failures\n", + static_cast<unsigned long long>(totals.files), + static_cast<unsigned long long>(totals.unreadable), + static_cast<unsigned long long>(totals.succeeded), + static_cast<unsigned long long>(totals.failed), + static_cast<unsigned long long>(totals.crashed), + static_cast<unsigned long long>(totals.timed_out), + static_cast<unsigned long long>(totals.with_new_edges), + static_cast<unsigned long long>(coverage.found_edges()), + coverage.num_edges(), coverage.coverage_fraction() * 100.0, + determinism > 0 + ? StringPrintf( + " after dropping %llu non-deterministic edges", + static_cast<unsigned long long>(totals.nondeterministic_edges)) + .c_str() + : "", + static_cast<unsigned long long>(stats.executions), wall_s, + static_cast<double>(stats.executions) / std::max(wall_s, 1e-9), + stats.executions == 0 + ? 0.0 + : static_cast<double>(stats.total_exec_time_us) / + static_cast<double>(stats.executions) / 1000.0, + static_cast<unsigned long long>(runner->child().total_spawns()), + static_cast<unsigned long long>(stats.infrastructure_failures)); + + if (events.is_open()) { + JsonObject summary; + summary.Add("event", "summary") + .Add("files", totals.files) + .Add("unreadable", totals.unreadable) + .Add("succeeded", totals.succeeded) + .Add("failed", totals.failed) + .Add("crashed", totals.crashed) + .Add("timed_out", totals.timed_out) + .Add("files_with_new_edges", totals.with_new_edges) + .Add("found_edges", coverage.found_edges()) + .Add("num_edges", coverage.num_edges()) + .Add("coverage", coverage.coverage_fraction()) + .Add("nondeterministic_edges", totals.nondeterministic_edges) + .Add("executions", stats.executions) + .Add("spawns", runner->child().total_spawns()) + .Add("infrastructure_failures", stats.infrastructure_failures) + .Add("total_exec_us", stats.total_exec_time_us) + .Add("wall_s", wall_s); + events.Write(summary); + events.Flush(); + } + + if (!dump_edges_path.empty()) { + std::sort(all_covered_edges.begin(), all_covered_edges.end()); + FILE* f = fopen(dump_edges_path.c_str(), "w"); + if (f) { + for (uint32_t e : all_covered_edges) { + fprintf(f, "%u\n", e); + } + fclose(f); + } + } + return kExitOk; +} + +} // namespace + +const Command kReplayCommand = { + "replay", + "Execute a corpus directory and report the coverage it reaches", + "usage: redline replay --d8=PATH --corpus=DIR[,DIR...] [options]\n" + "\n" + "Runs every *.js file below the given directories (sorted by path)\n" + "through one target process, tracking new edges exactly like the\n" + "fuzzer does when importing a corpus, and prints a summary.\n" + "\n" + "options:\n" + " --suffix=.js file name suffix to replay\n" + " --max-files=N stop after N files\n" + " --shuffle --seed=N randomize the file order\n" + " --determinism=N re-run programs that found new edges N times and\n" + " drop edges that are not reached every time\n" + " --events=FILE write one JSON object per file to FILE\n" + " --dump-edges=FILE write the union of all covered edge indices to " + "FILE\n" + " --progress-every=N log progress every N files (default 500)\n", + RunReplay, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/roundtrip_command.cc b/deps/v8/experimental/redline/commands/roundtrip_command.cc new file mode 100644 index 000000000000..18682b78c1e7 --- /dev/null +++ b/deps/v8/experimental/redline/commands/roundtrip_command.cc @@ -0,0 +1,997 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline roundtrip": measures how faithfully the FAST frontend handles real +// JavaScript. For every input file it answers, in this order: +// +// 1. Does V8 accept the file? (in-process v8::ScriptCompiler, no execution) +// 2. Do we accept the file? (fast::Parser) +// 3. Does printing round-trip? (print -> reparse -> print is a fixpoint) +// 4. Does V8 accept the printed program? +// 5. Does the printed program behave like the original? (both run on d8, +// exit status + stdout + error lines compared; flaky inputs detected by +// re-running the original) +// +// The verdict per file is one of the categories below; the summary reports +// counts and the key metrics: the false-reject rate (V8 accepts, we don't) +// and the semantic round-trip rate. + +#include <unistd.h> + +#include <algorithm> +#include <atomic> +#include <cerrno> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <memory> +#include <mutex> +#include <random> +#include <string> +#include <thread> +#include <vector> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/subprocess.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/base/v8_runtime.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/parser.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/fast/scope.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "roundtrip"; + +const char kUsage[] = + "usage: redline roundtrip [flags] [--dir=DIR,...] [FILE...]\n" + "\n" + "Parses every .js file, prints it back and checks (a) that V8 and the\n" + "FAST parser agree on what is valid, (b) that printing is a fixpoint,\n" + "(c) that V8 accepts the printed program and (d) that original and\n" + "printed program behave identically on d8.\n" + "\n" + "input selection:\n" + " --dir=DIR,... directories to scan recursively\n" + " --suffix=.js file suffix to pick (default .js)\n" + " --max-files=N only the first N files (after sorting)\n" + " --sample=N --seed=S a random sample of N files instead\n" + "\n" + "checks:\n" + " --rename[=all] alpha-rename all variables (or also functions\n" + " and classes) before printing: tests the scope\n" + " analysis, since behaviour must not change\n" + " --no-v8-check skip the in-process V8 syntax oracle\n" + " --no-run skip the behavioural comparison on d8\n" + " --v8-flags=\"...\" flags for the in-process V8 (default\n" + " --allow-natives-syntax --js-staging " + "--js-decorators)\n" + "\n" + "behavioural comparison:\n" + " --d8=PATH d8 to run (default out/x64.release/d8, " + "$REDLINE_D8)\n" + " --d8-args=\"...\" d8 flags (default --allow-natives-syntax); the\n" + " '// Flags:' lines of each test are added\n" + " --preload=FILE,... scripts loaded before each test (default:\n" + " test/mjsunit/mjsunit.js when under test/mjsunit)\n" + " --files-base=DIR base directory for '// Files:' lines\n" + " --timeout-ms=N per d8 run (default 10000)\n" + " --work-dir=DIR scratch directory (default " + "/tmp/redline-roundtrip.PID)\n" + "\n" + "output:\n" + " --jobs=N worker threads (default 8)\n" + " --events=FILE.jsonl one JSON record per file\n" + " --out-dir=DIR keep original, printed program and outputs of\n" + " every failing file\n" + " --list=N failing files listed per category (default 20)\n" + " --max-failures=N exit non-zero if more real failures (default 0)\n"; + +enum class Verdict { + kOk, // everything agrees + kBothReject, // V8 and we reject (fine) + kFalseReject, // V8 accepts, we reject (the key metric) + kFalseAccept, // we accept, V8 rejects + kReparseError, // our printed program does not reparse + kPrintedRejectedByV8, // V8 rejects our printed program + kFixpointMismatch, // print(reparse(print(t))) != print(t) + kBehaviourMismatch, // d8 output differs + kFlaky, // original is not deterministic itself + kTimeout, // original times out; nothing to compare + kEnvError, // d8 could not run the original (bad flags, ...) + kSkipped, // module / unreadable + kCount +}; + +const char* const kVerdictNames[] = { + "ok", + "both_reject", + "false_reject", + "false_accept", + "reparse_error", + "printed_rejected_by_v8", + "fixpoint_mismatch", + "behaviour_mismatch", + "flaky", + "timeout", + "env_error", + "skipped", +}; +static_assert(sizeof(kVerdictNames) / sizeof(kVerdictNames[0]) == + static_cast<size_t>(Verdict::kCount)); + +bool IsRealFailure(Verdict v) { + switch (v) { + case Verdict::kFalseReject: + case Verdict::kReparseError: + case Verdict::kPrintedRejectedByV8: + case Verdict::kFixpointMismatch: + case Verdict::kBehaviourMismatch: + return true; + default: + return false; + } +} + +struct Options { + std::vector<std::string> dirs; + std::vector<std::string> files; + std::string suffix = ".js"; + int64_t max_files = 0; + int64_t sample = 0; + uint64_t seed = 1; + bool v8_check = true; + bool run = true; + bool rename = false; + fast::RenameScope rename_scope = fast::RenameScope::kVariables; + std::string v8_flags; + std::string d8; + std::vector<std::string> d8_args; + std::vector<std::string> preload; + std::string files_base; + int64_t timeout_ms = 10000; + std::string work_dir; + int jobs = 8; + std::string events_path; + std::string out_dir; + int64_t list = 20; + int64_t max_failures = 0; +}; + +struct FileResult { + Verdict verdict = Verdict::kSkipped; + std::string detail; + size_t bytes = 0; + size_t nodes = 0; + double parse_ms = 0; + double print_ms = 0; + double run_ms = 0; + bool original_exit_zero = false; +}; + +// --- test metadata --------------------------------------------------------- + +struct TestMeta { + std::vector<std::string> flags; // from "// Flags:" lines + std::vector<std::string> files; // from "// Files:" lines + bool is_module = false; + bool only_strict = false; // test262 "onlyStrict" + bool raw = false; // test262 "raw" +}; + +std::vector<std::string> SplitWhitespace(std::string_view text) { + std::vector<std::string> out; + size_t i = 0; + while (i < text.size()) { + while (i < text.size() && isspace(static_cast<unsigned char>(text[i]))) { + i++; + } + size_t start = i; + while (i < text.size() && !isspace(static_cast<unsigned char>(text[i]))) { + i++; + } + if (i > start) { + out.emplace_back(text.substr(start, i - start)); + } + } + return out; +} + +TestMeta ExtractMeta(const std::string& source, const std::string& path) { + TestMeta meta; + if (path.size() > 4 && path.ends_with(".mjs")) { + meta.is_module = true; + } + size_t pos = 0; + while (pos < source.size()) { + size_t end = source.find('\n', pos); + if (end == std::string::npos) { + end = source.size(); + } + std::string_view line(source.data() + pos, end - pos); + pos = end + 1; + size_t first = line.find_first_not_of(" \t\r"); + if (first == std::string_view::npos) { + continue; + } + line = line.substr(first); + if (line.starts_with("// Flags:")) { + for (std::string& flag : SplitWhitespace(line.substr(9))) { + meta.flags.push_back(std::move(flag)); + } + } else if (line.starts_with("// Files:")) { + for (std::string& file : SplitWhitespace(line.substr(9))) { + meta.files.push_back(std::move(file)); + } + } else if (line.starts_with("// MODULE")) { + meta.is_module = true; + } + } + // test262 front matter. + size_t fm_start = source.find("/*---"); + if (fm_start != std::string::npos) { + size_t fm_end = source.find("---*/", fm_start); + if (fm_end != std::string::npos) { + std::string_view fm(source.data() + fm_start, fm_end - fm_start); + size_t flags_pos = fm.find("flags:"); + if (flags_pos != std::string_view::npos) { + size_t line_end = fm.find('\n', flags_pos); + std::string_view flags_line = + fm.substr(flags_pos, line_end == std::string_view::npos + ? std::string_view::npos + : line_end - flags_pos); + if (flags_line.find("module") != std::string_view::npos) { + meta.is_module = true; + } + if (flags_line.find("onlyStrict") != std::string_view::npos) { + meta.only_strict = true; + } + if (flags_line.find("raw") != std::string_view::npos) { + meta.raw = true; + } + } + } + } + return meta; +} + +// --- output normalization ---------------------------------------------------- + +void ReplaceAll(std::string* text, const std::string& from, + const std::string& to) { + if (from.empty()) { + return; + } + size_t pos = 0; + while ((pos = text->find(from, pos)) != std::string::npos) { + text->replace(pos, from.size(), to); + pos += to.size(); + } +} + +// Replaces "<script>:12:3", "<script>:12" and "<script> 12:3" (the format +// of mjsunit's stack frames) by "<script>:L" / "<script> L" so that line +// numbers, which legitimately differ after printing, do not count. +void NormalizePositions(std::string* text) { + const std::string marker = "<script>"; + size_t pos = 0; + while ((pos = text->find(marker, pos)) != std::string::npos) { + size_t i = pos + marker.size(); + if (i >= text->size() || ((*text)[i] != ':' && (*text)[i] != ' ')) { + pos = i; + continue; + } + i++; + size_t digits_start = i; + while (i < text->size() && + isdigit(static_cast<unsigned char>((*text)[i]))) { + i++; + } + if (i == digits_start) { + pos = i; + continue; + } + size_t j = i; + if (j < text->size() && (*text)[j] == ':') { + size_t k = j + 1; + while (k < text->size() && + isdigit(static_cast<unsigned char>((*text)[k]))) { + k++; + } + if (k > j + 1) { + j = k; + } + } + text->replace(digits_start, j - digits_start, "L"); + pos = digits_start + 1; + } +} + +// d8 reports uncaught exceptions on stdout as +// <script>:12: TypeError: boom +// <the source line> +// <spaces and ^^^ carets> +// The last two lines legitimately differ after printing; drop them. +std::string DropSourceEchoLines(const std::string& text) { + std::string out; + size_t pos = 0; + int skip = 0; + while (pos < text.size()) { + size_t end = text.find('\n', pos); + if (end == std::string::npos) { + end = text.size(); + } + std::string_view line(text.data() + pos, end - pos); + pos = end + 1; + if (skip > 0) { + skip--; + // Only the caret line is recognizable; be permissive about the echo. + bool caret_line = !line.empty() && + line.find_first_not_of(" ^") == std::string_view::npos; + if (skip == 0 && !caret_line) { + // The second line was not a caret line: keep it. + out.append(line); + out.push_back('\n'); + } + continue; + } + out.append(line); + out.push_back('\n'); + if (line.starts_with("<script>:L: ") && + line.find("Error") != std::string_view::npos) { + skip = 2; + } + } + return out; +} + +std::string NormalizeStdout(std::string text, const std::string& path_a, + const std::string& path_b) { + ReplaceAll(&text, path_a, "<script>"); + ReplaceAll(&text, path_b, "<script>"); + NormalizePositions(&text); + return DropSourceEchoLines(text); +} + +// Keeps only the error lines of stderr: uncaught exception reports contain +// a source echo and a caret line that differ after printing. +std::string NormalizeStderr(std::string text, const std::string& path_a, + const std::string& path_b) { + ReplaceAll(&text, path_a, "<script>"); + ReplaceAll(&text, path_b, "<script>"); + NormalizePositions(&text); + std::string out; + size_t pos = 0; + while (pos < text.size()) { + size_t end = text.find('\n', pos); + if (end == std::string::npos) { + end = text.size(); + } + std::string_view line(text.data() + pos, end - pos); + pos = end + 1; + if (line.starts_with(" at ")) { + continue; + } + bool error_like = line.find("Error") != std::string_view::npos || + line.find("error") != std::string_view::npos || + line.find("Uncaught") != std::string_view::npos || + line.find("Warning") != std::string_view::npos; + if (!error_like) { + continue; + } + out.append(line); + out.push_back('\n'); + } + return out; +} + +struct RunSummary { + bool timed_out = false; + int exit_code = -1; + int signal = 0; + std::string stdout_norm; + std::string stderr_norm; + std::string raw_stdout; + std::string raw_stderr; + + bool operator==(const RunSummary& other) const { + return timed_out == other.timed_out && exit_code == other.exit_code && + signal == other.signal && stdout_norm == other.stdout_norm && + stderr_norm == other.stderr_norm; + } + std::string Describe() const { + if (timed_out) { + return "timeout"; + } + if (signal != 0) { + return StringPrintf("signal %d", signal); + } + return StringPrintf("exit %d", exit_code); + } +}; + +std::string FirstDifference(const std::string& a, const std::string& b) { + size_t pos = 0; + size_t limit = std::min(a.size(), b.size()); + while (pos < limit && a[pos] == b[pos]) { + pos++; + } + auto line_of = [](const std::string& s, size_t p) { + size_t start = s.rfind('\n', p == 0 ? 0 : p - 1); + start = start == std::string::npos ? 0 : start + 1; + size_t end = s.find('\n', p); + std::string line = s.substr( + start, end == std::string::npos ? std::string::npos : end - start); + if (line.size() > 160) { + line = line.substr(0, 160) + "..."; + } + return line; + }; + return "original: " + line_of(a, pos) + " | printed: " + line_of(b, pos); +} + +// --- the harness +// --------------------------------------------------------------- + +class Harness { + public: + Harness(const Options& options, std::vector<std::string> files) + : options_(options), files_(std::move(files)), results_(files_.size()) {} + + bool Run(); + int Report(); + + private: + void Worker(int worker_id); + FileResult ProcessFile(size_t index, SyntaxChecker* checker, int worker_id); + RunSummary RunD8(const std::vector<std::string>& argv, + const std::string& path_a, const std::string& path_b, + double* run_ms); + void KeepFailure(const std::string& path, const std::string& source, + const std::string& printed, const FileResult& result, + const RunSummary* a, const RunSummary* b); + + Options options_; + std::vector<std::string> files_; + std::vector<FileResult> results_; + std::atomic<size_t> next_{0}; + std::atomic<size_t> done_{0}; + std::mutex mutex_; + JsonlWriter events_; + Stopwatch stopwatch_; + uint64_t last_progress_us_ = 0; +}; + +bool Harness::Run() { + if (!options_.events_path.empty() && + !events_.Open(options_.events_path, /*truncate=*/true)) { + return false; + } + std::string error; + bool clean_work_dir = false; + if (options_.run) { + if (options_.work_dir.empty()) { + char tmpl[] = "/tmp/redline-roundtrip.XXXXXX"; + if (mkdtemp(tmpl) == nullptr) { + REDLINE_ERROR(kLog, "mkdtemp failed: %s", strerror(errno)); + return false; + } + options_.work_dir = std::string(tmpl); + clean_work_dir = true; + } else if (!MakeDirectories(options_.work_dir, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return false; + } + } + if (!options_.out_dir.empty() && !MakeDirectories(options_.out_dir, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return false; + } + if (options_.v8_check && !InitializeV8(options_.v8_flags, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return false; + } + int jobs = std::max( + 1, std::min<int>(options_.jobs, static_cast<int>(files_.size()))); + REDLINE_LOG(kLog, "%zu files, %d workers, v8-check=%s, run=%s%s", + files_.size(), jobs, options_.v8_check ? "yes" : "no", + options_.run ? "yes" : "no", + options_.run ? (" (" + options_.d8 + ")").c_str() : ""); + std::vector<std::thread> threads; + threads.reserve(static_cast<size_t>(jobs)); + for (int i = 0; i < jobs; i++) { + threads.emplace_back([this, i] { Worker(i); }); + } + for (std::thread& thread : threads) { + thread.join(); + } + if (clean_work_dir) { + for (int i = 0; i < jobs; i++) { + std::remove( + StringPrintf("%s/%d.a.js", options_.work_dir.c_str(), i).c_str()); + std::remove( + StringPrintf("%s/%d.b.js", options_.work_dir.c_str(), i).c_str()); + } + rmdir(options_.work_dir.c_str()); + } + events_.Flush(); + return true; +} + +void Harness::Worker(int worker_id) { + std::unique_ptr<SyntaxChecker> checker; + if (options_.v8_check) { + checker = std::make_unique<SyntaxChecker>(); + } + while (true) { + size_t index = next_.fetch_add(1); + if (index >= files_.size()) { + break; + } + FileResult result = ProcessFile(index, checker.get(), worker_id); + results_[index] = result; + if (events_.is_open()) { + JsonObject record; + record.Add("file", files_[index]) + .Add("verdict", kVerdictNames[static_cast<int>(result.verdict)]) + .Add("detail", result.detail) + .Add("bytes", static_cast<uint64_t>(result.bytes)) + .Add("nodes", static_cast<uint64_t>(result.nodes)) + .Add("parse_ms", result.parse_ms) + .Add("print_ms", result.print_ms) + .Add("run_ms", result.run_ms) + .Add("original_exit_zero", result.original_exit_zero); + events_.Write(record); + } + size_t done = done_.fetch_add(1) + 1; + uint64_t now = stopwatch_.ElapsedUs(); + std::scoped_lock<std::mutex> lock(mutex_); + if (IsRealFailure(result.verdict)) { + REDLINE_LOG(kLog, "%s: %s: %s", + kVerdictNames[static_cast<int>(result.verdict)], + files_[index].c_str(), result.detail.c_str()); + } + if (now - last_progress_us_ > 5000000 || done == files_.size()) { + last_progress_us_ = now; + REDLINE_LOG(kLog, "%zu/%zu files (%.0f s)", done, files_.size(), + static_cast<double>(now) / 1e6); + } + } +} + +RunSummary Harness::RunD8(const std::vector<std::string>& argv, + const std::string& path_a, const std::string& path_b, + double* run_ms) { + SubprocessResult r = RunSubprocess(argv, options_.timeout_ms); + *run_ms += static_cast<double>(r.elapsed_us) / 1000.0; + RunSummary summary; + summary.timed_out = r.timed_out; + summary.exit_code = r.exit_code; + summary.signal = r.signal; + summary.raw_stdout = r.stdout_data; + summary.raw_stderr = r.stderr_data; + summary.stdout_norm = NormalizeStdout(r.stdout_data, path_a, path_b); + summary.stderr_norm = NormalizeStderr(r.stderr_data, path_a, path_b); + if (!r.started) { + summary.stderr_norm = "redline: " + r.error; + } + return summary; +} + +void Harness::KeepFailure(const std::string& path, const std::string& source, + const std::string& printed, const FileResult& result, + const RunSummary* a, const RunSummary* b) { + if (options_.out_dir.empty()) { + return; + } + std::string base = options_.out_dir + "/" + BaseName(path); + std::string error; + WriteStringToFile(base, source, &error); + if (!printed.empty()) { + WriteStringToFile(base + ".printed.js", printed, &error); + } + std::string report = + std::string(kVerdictNames[static_cast<int>(result.verdict)]) + ": " + + result.detail + "\n"; + if (a != nullptr) { + report += "\n=== original: " + a->Describe() + "\n--- stdout\n" + + a->raw_stdout + "\n--- stderr\n" + a->raw_stderr; + } + if (b != nullptr) { + report += "\n=== printed: " + b->Describe() + "\n--- stdout\n" + + b->raw_stdout + "\n--- stderr\n" + b->raw_stderr; + } + WriteStringToFile(base + ".report.txt", report, &error); +} + +FileResult Harness::ProcessFile(size_t index, SyntaxChecker* checker, + int worker_id) { + const std::string& path = files_[index]; + FileResult result; + std::string source, error; + if (!ReadFileToString(path, &source, &error)) { + result.verdict = Verdict::kSkipped; + result.detail = error; + return result; + } + result.bytes = source.size(); + TestMeta meta = ExtractMeta(source, path); + if (meta.is_module) { + result.verdict = Verdict::kSkipped; + result.detail = "module"; + return result; + } + // test262 onlyStrict tests are run with a "use strict" prologue. + std::string effective_source = source; + if (meta.only_strict && !meta.raw) { + effective_source = "\"use strict\";\n" + source; + } + + // 1. V8's verdict on the original. + bool v8_accepts = true; + std::string v8_message; + if (checker != nullptr) { + v8_accepts = checker->Accepts(effective_source, &v8_message); + } + + // 2. Ours. + fast::ParseOptions parse_options; + fast::ParseError parse_error; + Stopwatch stopwatch; + std::unique_ptr<fast::Tree> tree = + fast::Parser::ParseScript(effective_source, parse_options, &parse_error); + result.parse_ms = static_cast<double>(stopwatch.ElapsedUs()) / 1000.0; + if (!tree) { + if (!v8_accepts) { + result.verdict = Verdict::kBothReject; + result.detail = parse_error.ToString(); + } else { + result.verdict = Verdict::kFalseReject; + result.detail = parse_error.ToString(); + KeepFailure(path, source, "", result, nullptr, nullptr); + } + return result; + } + result.nodes = fast::CountNodes(tree->root()); + if (!v8_accepts) { + result.verdict = Verdict::kFalseAccept; + result.detail = v8_message; + return result; + } + + // 2b. Optionally rename every binding (scope analysis self-test). + if (options_.rename) { + std::unique_ptr<fast::ScopeAnalysis> analysis = + fast::ScopeAnalysis::Analyze(tree.get()); + fast::RenameAllBindings(tree.get(), analysis.get(), "v", + options_.rename_scope); + } + + // 3. Print and check the fixpoint. + stopwatch.Restart(); + fast::PrintOptions print_options; + std::string printed = fast::Print(tree->root(), print_options); + result.print_ms = static_cast<double>(stopwatch.ElapsedUs()) / 1000.0; + fast::ParseError reparse_error; + std::unique_ptr<fast::Tree> second = + fast::Parser::ParseScript(printed, parse_options, &reparse_error); + if (!second) { + result.verdict = Verdict::kReparseError; + result.detail = reparse_error.ToString(); + KeepFailure(path, source, printed, result, nullptr, nullptr); + return result; + } + std::string printed_again = fast::Print(second->root(), print_options); + if (printed_again != printed) { + result.verdict = Verdict::kFixpointMismatch; + result.detail = FirstDifference(printed, printed_again); + KeepFailure(path, source, printed, result, nullptr, nullptr); + return result; + } + + // 4. V8's verdict on the printed program. + if (checker != nullptr && !checker->Accepts(printed, &v8_message)) { + result.verdict = Verdict::kPrintedRejectedByV8; + result.detail = v8_message; + KeepFailure(path, source, printed, result, nullptr, nullptr); + return result; + } + + if (!options_.run) { + result.verdict = Verdict::kOk; + return result; + } + + // 5. Behavioural comparison on d8. + std::string path_a = + StringPrintf("%s/%d.a.js", options_.work_dir.c_str(), worker_id); + std::string path_b = + StringPrintf("%s/%d.b.js", options_.work_dir.c_str(), worker_id); + if (!WriteStringToFile(path_a, effective_source, &error) || + !WriteStringToFile(path_b, printed, &error)) { + result.verdict = Verdict::kEnvError; + result.detail = error; + return result; + } + std::vector<std::string> argv; + argv.push_back(options_.d8); + for (const std::string& arg : options_.d8_args) { + argv.push_back(arg); + } + for (const std::string& flag : meta.flags) { + argv.push_back(flag); + } + for (const std::string& preload : options_.preload) { + argv.push_back(preload); + } + for (const std::string& file : meta.files) { + if (file.empty() || file[0] == '/' || FileExists(file)) { + argv.push_back(file); + } else { + argv.push_back(options_.files_base + "/" + file); + } + } + argv.push_back(path_a); + RunSummary a = RunD8(argv, path_a, path_b, &result.run_ms); + if (a.timed_out) { + result.verdict = Verdict::kTimeout; + result.detail = StringPrintf("original timed out after %lld ms", + static_cast<long long>(options_.timeout_ms)); + return result; + } + if (a.raw_stderr.find("unrecognized flag") != std::string::npos || + a.raw_stderr.find("Error: unknown flag") != std::string::npos || + a.raw_stderr.find("Error loading file") != std::string::npos) { + result.verdict = Verdict::kEnvError; + size_t end = a.raw_stderr.find('\n'); + result.detail = a.raw_stderr.substr(0, end); + return result; + } + result.original_exit_zero = a.exit_code == 0; + argv.back() = path_b; + RunSummary b = RunD8(argv, path_a, path_b, &result.run_ms); + if (a == b) { + result.verdict = Verdict::kOk; + return result; + } + // Re-run both: is the test deterministic at all? + argv.back() = path_a; + RunSummary a2 = RunD8(argv, path_a, path_b, &result.run_ms); + if (!(a == a2)) { + result.verdict = Verdict::kFlaky; + result.detail = "original differs from itself: " + a.Describe() + " vs " + + a2.Describe(); + return result; + } + argv.back() = path_b; + RunSummary b2 = RunD8(argv, path_a, path_b, &result.run_ms); + if (!(b == b2)) { + result.verdict = Verdict::kFlaky; + result.detail = + "printed differs from itself: " + b.Describe() + " vs " + b2.Describe(); + return result; + } + result.verdict = Verdict::kBehaviourMismatch; + if (a.timed_out != b.timed_out || a.exit_code != b.exit_code || + a.signal != b.signal) { + result.detail = "status " + a.Describe() + " vs " + b.Describe(); + if (!b.stderr_norm.empty()) { + size_t end = b.stderr_norm.find('\n'); + result.detail += " (" + b.stderr_norm.substr(0, end) + ")"; + } + } else if (a.stdout_norm != b.stdout_norm) { + result.detail = "stdout: " + FirstDifference(a.stdout_norm, b.stdout_norm); + } else { + result.detail = "stderr: " + FirstDifference(a.stderr_norm, b.stderr_norm); + } + KeepFailure(path, source, printed, result, &a, &b); + return result; +} + +int Harness::Report() { + size_t counts[static_cast<size_t>(Verdict::kCount)] = {}; + size_t ok_passing = 0; + size_t total_bytes = 0; + double total_parse_ms = 0; + for (const FileResult& r : results_) { + counts[static_cast<size_t>(r.verdict)]++; + if (r.verdict == Verdict::kOk && r.original_exit_zero) { + ok_passing++; + } + total_bytes += r.bytes; + total_parse_ms += r.parse_ms; + } + size_t total = results_.size(); + size_t v8_accepted = 0, real_failures = 0; + for (size_t v = 0; v < static_cast<size_t>(Verdict::kCount); v++) { + Verdict verdict = static_cast<Verdict>(v); + if (verdict != Verdict::kBothReject && verdict != Verdict::kFalseAccept && + verdict != Verdict::kSkipped) { + v8_accepted += counts[v]; + } + if (IsRealFailure(verdict)) { + real_failures += counts[v]; + } + } + size_t compared = counts[static_cast<size_t>(Verdict::kOk)] + + counts[static_cast<size_t>(Verdict::kBehaviourMismatch)]; + + printf("\nroundtrip: %zu files, %.1f MB, %.1f s wall, parse %.0f ms total\n", + total, static_cast<double>(total_bytes) / 1e6, + stopwatch_.ElapsedSeconds(), total_parse_ms); + for (size_t v = 0; v < static_cast<size_t>(Verdict::kCount); v++) { + if (counts[v] == 0 && !IsRealFailure(static_cast<Verdict>(v))) { + continue; + } + printf(" %-24s %6zu", kVerdictNames[v], counts[v]); + if (static_cast<Verdict>(v) == Verdict::kOk && options_.run) { + printf(" (%zu with exit 0)", ok_passing); + } + printf("\n"); + } + if (v8_accepted > 0) { + printf("false-reject rate: %zu / %zu V8-accepted files = %.2f%%\n", + counts[static_cast<size_t>(Verdict::kFalseReject)], v8_accepted, + 100.0 * + static_cast<double>( + counts[static_cast<size_t>(Verdict::kFalseReject)]) / + static_cast<double>(v8_accepted)); + } + if (compared > 0) { + printf("semantic round-trip: %zu / %zu compared files = %.2f%%\n", + counts[static_cast<size_t>(Verdict::kOk)], compared, + 100.0 * + static_cast<double>(counts[static_cast<size_t>(Verdict::kOk)]) / + static_cast<double>(compared)); + } + + // List failing files per category. + for (size_t v = 0; v < static_cast<size_t>(Verdict::kCount); v++) { + Verdict verdict = static_cast<Verdict>(v); + if (!IsRealFailure(verdict) && verdict != Verdict::kFalseAccept) { + continue; + } + if (counts[v] == 0) { + continue; + } + printf("\n%s (%zu):\n", kVerdictNames[v], counts[v]); + int64_t listed = 0; + for (size_t i = 0; i < results_.size() && listed < options_.list; i++) { + if (results_[i].verdict != verdict) { + continue; + } + printf(" %s: %s\n", files_[i].c_str(), results_[i].detail.c_str()); + listed++; + } + if (static_cast<int64_t>(counts[v]) > listed) { + printf(" ... %zu more\n", counts[v] - static_cast<size_t>(listed)); + } + } + bool pass = static_cast<int64_t>(real_failures) <= options_.max_failures; + printf("\n%s: %zu real failures (max %lld)\n", pass ? "PASS" : "FAIL", + real_failures, static_cast<long long>(options_.max_failures)); + return pass ? kExitOk : kExitFailure; +} + +bool ParseOptions(const Flags& flags, Options* options) { + options->dirs = flags.GetList("dir"); + options->files = flags.positional(); + options->suffix = flags.GetString("suffix", ".js"); + options->max_files = flags.GetInt("max-files", 0); + options->sample = flags.GetInt("sample", 0); + options->seed = static_cast<uint64_t>(flags.GetInt("seed", 1)); + options->v8_check = flags.GetBool("v8-check", true); + options->run = flags.GetBool("run", true); + if (flags.Has("rename")) { + options->rename = true; + options->rename_scope = flags.GetString("rename", "") == "all" + ? fast::RenameScope::kAll + : fast::RenameScope::kVariables; + } + options->v8_flags = flags.GetString( + "v8-flags", "--allow-natives-syntax --js-staging --js-decorators"); + options->d8 = flags.GetString("d8"); + if (options->d8.empty()) { + const char* env = getenv("REDLINE_D8"); + if (env != nullptr && env[0] != '\0') { + options->d8 = env; + } else if (FileExists("out/x64.release/d8")) { + options->d8 = "out/x64.release/d8"; + } + } + options->d8_args = + SplitWhitespace(flags.GetString("d8-args", "--allow-natives-syntax")); + options->preload = flags.GetList("preload"); + options->files_base = flags.GetString("files-base"); + options->timeout_ms = flags.GetInt("timeout-ms", 10000); + options->work_dir = flags.GetString("work-dir"); + options->jobs = static_cast<int>(flags.GetInt("jobs", 8)); + options->events_path = flags.GetString("events"); + options->out_dir = flags.GetString("out-dir"); + options->list = flags.GetInt("list", 20); + options->max_failures = flags.GetInt("max-failures", 0); + + // mjsunit conventions. + bool under_mjsunit = false; + for (const std::string& dir : options->dirs) { + if (dir.find("mjsunit") != std::string::npos) { + under_mjsunit = true; + } + } + for (const std::string& file : options->files) { + if (file.find("mjsunit") != std::string::npos) { + under_mjsunit = true; + } + } + if (under_mjsunit) { + if (!flags.Has("preload") && FileExists("test/mjsunit/mjsunit.js")) { + options->preload = {"test/mjsunit/mjsunit.js"}; + } + if (options->files_base.empty()) { + options->files_base = "test/mjsunit"; + } + } + if (options->files_base.empty() && !options->dirs.empty()) { + options->files_base = options->dirs[0]; + } + if (options->run && (options->d8.empty() || !FileExists(options->d8))) { + REDLINE_ERROR(kLog, + "No d8 found (--d8=PATH or $REDLINE_D8); use --no-run to " + "skip execution"); + return false; + } + return true; +} + +int RunRoundtrip(const Flags& flags) { + Options options; + if (!ParseOptions(flags, &options)) { + return kExitUsage; + } + std::vector<std::string> files = options.files; + for (const std::string& dir : options.dirs) { + std::vector<std::string> found = ListFiles(dir, options.suffix); + if (found.empty()) { + REDLINE_WARN(kLog, "No %s files under %s", options.suffix.c_str(), + dir.c_str()); + } + files.insert(files.end(), found.begin(), found.end()); + } + if (files.empty()) { + fputs(kUsage, stderr); + return kExitUsage; + } + if (options.sample > 0 && + static_cast<size_t>(options.sample) < files.size()) { + std::mt19937_64 rng(options.seed); + std::shuffle(files.begin(), files.end(), rng); + files.resize(static_cast<size_t>(options.sample)); + std::sort(files.begin(), files.end()); + } + if (options.max_files > 0 && + static_cast<size_t>(options.max_files) < files.size()) { + files.resize(static_cast<size_t>(options.max_files)); + } + Harness harness(options, std::move(files)); + if (!harness.Run()) { + return kExitFailure; + } + return harness.Report(); +} + +} // namespace + +const Command kRoundtripCommand = { + "roundtrip", "Check parse/print fidelity of the FAST frontend on a corpus", + kUsage, RunRoundtrip}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/selftest_checker.h b/deps/v8/experimental/redline/commands/selftest_checker.h new file mode 100644 index 000000000000..302e18ea8f9f --- /dev/null +++ b/deps/v8/experimental/redline/commands/selftest_checker.h @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_COMMANDS_SELFTEST_CHECKER_H_ +#define V8_EXPERIMENTAL_REDLINE_COMMANDS_SELFTEST_CHECKER_H_ + +#include <cstdio> +#include <string> + +namespace redline { + +// Counts and prints the PASS/FAIL lines of `redline selftest`. Shared by the +// target checks (selftest_command.cc) and the offline checks +// (selftest_selection.cc). +class Checker { + public: + bool Check(const char* name, bool ok, const std::string& details = "") { + printf("%s %s%s%s\n", ok ? "PASS" : "FAIL", name, + details.empty() ? "" : ": ", details.c_str()); + fflush(stdout); + if (ok) { + passed_++; + } else { + failed_++; + } + return ok; + } + + void Info(const char* name, const std::string& details) { + printf("INFO %s: %s\n", name, details.c_str()); + fflush(stdout); + } + + int passed() const { return passed_; } + int failed() const { return failed_; } + + private: + int passed_ = 0; + int failed_ = 0; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_COMMANDS_SELFTEST_CHECKER_H_ diff --git a/deps/v8/experimental/redline/commands/selftest_command.cc b/deps/v8/experimental/redline/commands/selftest_command.cc new file mode 100644 index 000000000000..26f345698c0b --- /dev/null +++ b/deps/v8/experimental/redline/commands/selftest_command.cc @@ -0,0 +1,425 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline selftest": end-to-end checks of the execution layer against a +// real target. Modeled on Fuzzilli's startup tests, extended with the +// behaviours the fuzzer relies on (timeouts, respawning, output capture, +// coverage evaluation and edge determinism). Prints one PASS/FAIL line per +// check and exits non-zero if any check failed. + +#include <unistd.h> + +#include <algorithm> +#include <cstdio> +#include <iterator> +#include <set> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/commands/selftest_checker.h" +#include "experimental/redline/commands/selftest_selection.h" +#include "experimental/redline/engine/crash.h" +#include "experimental/redline/exec/runner.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "selftest"; + +std::string Describe(const Execution& e) { + return StringPrintf("%s (exit code %d, signal %d, %.1f ms)", + OutcomeName(e.outcome), e.exit_code, e.signal, + static_cast<double>(e.exec_time_us) / 1000.0); +} + +// Runs `script` and returns false on infrastructure failure (reported as +// a failed check). +bool RunOrFail(Checker* checker, ScriptRunner* runner, const char* name, + const std::string& script, ScriptRunner::Result* result) { + std::string error; + if (!runner->Run(script, result, &error)) { + checker->Check(name, false, "execution failed: " + error); + return false; + } + return true; +} + +// experimental/redline/testdata, found from the location of the binary, or +// empty. Look for testdata/selection so we do not pick up unrelated +// out/<dir>/testdata directories created by other build targets. +std::string DefaultTestdataDir() { + std::string selection = RedlineDataDir("testdata/selection"); + if (!selection.empty()) { + return selection.substr(0, selection.rfind('/')); + } + return RedlineDataDir("testdata"); +} + +// Offline: crash signatures. A recursion that overflows the stack must get +// the same signature wherever the stack ran out; other crashes keep their +// first frames. +void RunCrashSignatureChecks(Checker* checker) { + auto frame = [](const char* mangled) { + return StringPrintf("./d8(%s+0x10)[0x5555]\n", mangled); + }; + auto trace = [&](const char* top, int depth) { + std::string text = "Received signal 11 SEGV_MAPERR 7ffd00000ff8\n\n"; + text += "==== C stack trace ===============================\n\n"; + text += frame(top); + const char* cycle[] = {"_ZN2v88internal3FooEv", "_ZN2v88internal3BarEv", + "_ZN2v88internal3BazEv"}; + for (int i = 0; i < depth; i++) { + text += frame(cycle[i % 3]); + } + return text + "[end of stack trace]\n"; + }; + CrashSignature a = + CrashSignature::FromOutput(11, 0, trace("_ZN2v88internal4Top1Ev", 57)); + CrashSignature b = + CrashSignature::FromOutput(11, 0, trace("_ZN2v88internal4Top2Ev", 55)); + checker->Check( + "crash signature: a stack overflow does not depend on the faulting frame", + a == b, a.text + " vs " + b.text); + checker->Check("crash signature: a stack overflow names its recursion", + a.text == + "sig11 SEGV_MAPERR stack-overflow v8::internal::Bar | " + "v8::internal::Baz | v8::internal::Foo", + a.text); + CrashSignature c = + CrashSignature::FromOutput(11, 0, trace("_ZN2v88internal4Top1Ev", 2)); + checker->Check("crash signature: other crashes keep their first three frames", + c.text == + "sig11 SEGV_MAPERR v8::internal::Top1 < v8::internal::Foo " + "< v8::internal::Bar", + c.text); +} + +int RunSelftest(const Flags& flags) { + Checker checker; + std::string error; + + // Offline checks first: they need no target. + RunCrashSignatureChecks(&checker); + RunNodeKindChecks(&checker); + RunPresetChecks(&checker); + std::string testdata = flags.GetString("testdata", DefaultTestdataDir()); + if (testdata.empty()) { + checker.Check("selection: locate experimental/redline/testdata", false, + "not found next to the binary; pass --testdata=DIR"); + } else { + RunSelectionChecks(&checker, testdata, + flags.GetBool("write-golden", false)); + } + if (flags.GetBool("offline", false)) { + printf("selftest: %d passed, %d failed\n", checker.passed(), + checker.failed()); + return checker.failed() == 0 ? kExitOk : kExitFailure; + } + + TargetOptions target; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + // The respawn behaviour is part of what is tested; use a small value. + target.max_execs_before_respawn = + static_cast<int>(flags.GetInt("max-execs-before-respawn", 50)); + int speed_runs = static_cast<int>(flags.GetInt("speed-runs", 200)); + + printf("target: %s\n", target.CommandLine().c_str()); + + std::unique_ptr<ScriptRunner> runner = + ScriptRunner::Create(target, 0, &error); + if (!checker.Check("create runner", runner != nullptr, error)) { + return kExitFailure; + } + if (!checker.Check("REPRL handshake and coverage initialization", + runner->Initialize(&error), error)) { + return kExitFailure; + } + checker.Info("instrumented edges", + StringPrintf("%u", runner->coverage().num_edges())); + + ScriptRunner::Result result; + + // Basic outcomes. + if (RunOrFail(&checker, runner.get(), "empty script", "", &result)) { + checker.Check("empty script succeeds", result.execution.succeeded(), + Describe(result.execution)); + } + if (RunOrFail(&checker, runner.get(), "uncaught exception", + "throw new Error('expected');", &result)) { + checker.Check("uncaught exception is reported as failed", + result.execution.outcome == Outcome::kFailed, + Describe(result.execution)); + } + if (RunOrFail(&checker, runner.get(), "syntax error", "let let = ;", + &result)) { + checker.Check("syntax error is reported as failed", + result.execution.outcome == Outcome::kFailed, + Describe(result.execution)); + } + + // Output channels. + if (RunOrFail(&checker, runner.get(), "fuzzout", + "fuzzilli('FUZZILLI_PRINT', 'hello fuzzout');", &result)) { + checker.Check( + "fuzzilli('FUZZILLI_PRINT') is captured", + result.execution.succeeded() && + result.execution.fuzzout.find("hello fuzzout") != std::string::npos, + Describe(result.execution) + ", fuzzout=\"" + result.execution.fuzzout + + "\""); + } + if (RunOrFail(&checker, runner.get(), "stdout", + "print('hello stdout'); console.log('hello console');", + &result)) { + bool ok = result.execution.succeeded() && + result.execution.stdout_output.find("hello stdout") != + std::string::npos && + result.execution.stdout_output.find("hello console") != + std::string::npos; + checker.Check("stdout is captured", ok, + Describe(result.execution) + ", stdout=\"" + + result.execution.stdout_output + "\""); + } + if (RunOrFail(&checker, runner.get(), "stderr", "console.error('to stderr')", + &result)) { + checker.Check( + "stderr is captured", + result.execution.stderr_output.find("to stderr") != std::string::npos, + "stderr=\"" + result.execution.stderr_output + "\""); + } + if (RunOrFail(&checker, runner.get(), "output isolation", "print('second')", + &result)) { + checker.Check( + "output of earlier executions is not leaked", + result.execution.stdout_output.find("hello") == std::string::npos && + result.execution.fuzzout.empty(), + "stdout=\"" + result.execution.stdout_output + "\""); + } + + // Timeouts. + { + uint64_t timeout_us = static_cast<uint64_t>(300) * 1000; + Stopwatch stopwatch; + if (runner->Run("while (true) {}", timeout_us, &result, &error)) { + uint64_t elapsed = stopwatch.ElapsedUs(); + checker.Check("infinite loop times out", + result.execution.outcome == Outcome::kTimedOut && + elapsed >= timeout_us && elapsed < timeout_us * 20, + Describe(result.execution) + + StringPrintf(", wall %.1f ms", + static_cast<double>(elapsed) / 1000.0)); + } else { + checker.Check("infinite loop times out", false, error); + } + if (RunOrFail(&checker, runner.get(), "after timeout", "1 + 1", &result)) { + checker.Check("target is respawned after a timeout", + result.execution.succeeded(), Describe(result.execution)); + } + } + + // Crashes. + struct CrashCase { + const char* description; + int kind; + bool required; + }; + const CrashCase crash_cases[] = { + {"IMMEDIATE_CRASH", 0, true}, {"CHECK failure", 1, true}, + {"DCHECK failure", 2, false}, {"wild write", 3, true}, + {"DEBUG build check", 8, false}, {"sandbox violation", 9, false}, + }; + for (const CrashCase& c : crash_cases) { + std::string script = StringPrintf("fuzzilli('FUZZILLI_CRASH', %d)", c.kind); + std::string name = StringPrintf("fuzzilli('FUZZILLI_CRASH', %d) [%s]", + c.kind, c.description); + if (!RunOrFail(&checker, runner.get(), name.c_str(), script, &result)) { + continue; + } + bool crashed = result.execution.crashed(); + if (c.required) { + checker.Check(name.c_str(), crashed, Describe(result.execution)); + } else { + checker.Info(name.c_str(), (crashed ? "crashes" : "does not crash") + + std::string(" -- ") + + Describe(result.execution)); + } + if (RunOrFail(&checker, runner.get(), "after crash", "1 + 1", &result)) { + checker.Check("target is respawned after a crash", + result.execution.succeeded(), Describe(result.execution)); + } + } + + // Coverage. + const char* kProgramA = + "function f(a) { let s = 0; for (let i = 0; i < a.length; i++) s += " + "a[i]; return s; }\n" + "let arr = [1, 2.5, 'x', {}, null];\n" + "for (let j = 0; j < 100; j++) f(arr);\n" + "class C { #p = 1; get p() { return this.#p; } }\n" + "new C().p;\n"; + const char* kProgramB = + "let m = new Map(); for (let i = 0; i < 50; i++) m.set(i, 'v' + i);\n" + "let s = new Set([1, 2, 3]); [...m.keys()].filter(x => s.has(x));\n" + "JSON.parse(JSON.stringify({a: [1, {b: 2}], c: 'd'}));\n" + "/a(b+)c/.exec('xxabbbcxx'); new Date(0).toISOString();\n"; + std::vector<uint32_t> edges_a; + if (RunOrFail(&checker, runner.get(), "coverage A", kProgramA, &result)) { + edges_a = result.new_edges; + checker.Check("first execution of a program finds new edges", + result.execution.succeeded() && !result.new_edges.empty(), + StringPrintf("%zu new edges, %u hit", result.new_edges.size(), + result.edges_hit)); + } + if (RunOrFail(&checker, runner.get(), "coverage A again", kProgramA, + &result)) { + checker.Check( + "re-running the same program finds (almost) no new edges", + result.new_edges.size() * 100 < std::max<size_t>(edges_a.size(), 1), + StringPrintf("%zu new edges on second run vs %zu on first", + result.new_edges.size(), edges_a.size())); + } + if (RunOrFail(&checker, runner.get(), "coverage B", kProgramB, &result)) { + checker.Check("a different program finds new edges", + result.execution.succeeded() && !result.new_edges.empty(), + StringPrintf("%zu new edges", result.new_edges.size())); + } + if (RunOrFail(&checker, runner.get(), "coverage of failing program", + "let q = []; q.push(1); throw 1;", &result)) { + checker.Check("failed executions do not advance coverage", + result.execution.outcome == Outcome::kFailed && + result.new_edges.empty() && result.edges_hit > 0, + StringPrintf("%zu new edges, %u hit", result.new_edges.size(), + result.edges_hit)); + } + + // Determinism of edges across runs. V8 is not deterministic at the edge + // level: GC timing, tiering decisions and concurrent compiler threads make + // 5-15% of the edges of any script flaky (even `let x = 1 + 2;` shows ~6%). + // This is the reason for the multi-run determinism check in the fuzzing + // loop; here we only sanity-check that the stable core is large (a broken + // coverage map would show up as near-random bitmaps) and report the rate. + { + struct Probe { + const char* name; + const char* script; + }; + const Probe kProbes[] = {{"trivial script", "let x = 1 + 2;"}, + {"program A", kProgramA}}; + for (const Probe& probe : kProbes) { + std::vector<uint32_t> all_runs; + std::set<uint32_t> any_run; + bool ok = true; + for (int i = 0; i < 5; i++) { + Execution execution; + if (!runner->RunWithoutEvaluation(probe.script, target.timeout_us, + &execution, &error)) { + ok = false; + break; + } + std::vector<uint32_t> current = runner->coverage().CurrentEdges(); + if (i == 0) { + all_runs = current; + } else { + std::vector<uint32_t> intersection; + std::set_intersection(all_runs.begin(), all_runs.end(), + current.begin(), current.end(), + std::back_inserter(intersection)); + all_runs.swap(intersection); + } + any_run.insert(current.begin(), current.end()); + } + double stable_pct = any_run.empty() + ? 0.0 + : 100.0 * static_cast<double>(all_runs.size()) / + static_cast<double>(any_run.size()); + checker.Info( + StringPrintf("edge nondeterminism of %s", probe.name).c_str(), + StringPrintf("%zu edges in every one of 5 runs, %zu in at " + "least one run (%.1f%% stable)", + all_runs.size(), any_run.size(), stable_pct)); + checker.Check( + StringPrintf("stable edge core of %s is >= 75%% of the union", + probe.name) + .c_str(), + ok && !all_runs.empty() && stable_pct >= 75.0, + StringPrintf("%.1f%%", stable_pct)); + } + } + + // Respawning. + { + uint64_t spawns_before = runner->child().total_spawns(); + int runs = target.max_execs_before_respawn * 2 + 1; + bool ok = true; + for (int i = 0; i < runs; i++) { + if (!runner->Run("", &result, &error) || !result.execution.succeeded()) { + ok = false; + break; + } + } + uint64_t spawns = runner->child().total_spawns() - spawns_before; + checker.Check("target is respawned every max_execs_before_respawn runs", + ok && spawns >= 2, + StringPrintf("%llu spawns in %d runs", + static_cast<unsigned long long>(spawns), runs)); + } + + // Speed (informational). + if (speed_runs > 0) { + Stopwatch stopwatch; + bool ok = true; + for (int i = 0; i < speed_runs; i++) { + if (!runner->Run("let x = 1 + 1;", &result, &error)) { + ok = false; + break; + } + } + double seconds = stopwatch.ElapsedSeconds(); + checker.Info( + "execution speed", + ok ? StringPrintf("%.0f execs/s for a trivial script (%d runs)", + static_cast<double>(speed_runs) / seconds, speed_runs) + : "failed: " + error); + } + + printf("selftest: %d passed, %d failed\n", checker.passed(), + checker.failed()); + return checker.failed() == 0 ? kExitOk : kExitFailure; +} + +} // namespace + +const Command kSelftestCommand = { + "selftest", + "Check that the execution layer works against a target", + "usage: redline selftest --d8=PATH [options] | --offline [options]\n" + "\n" + "Runs a series of checks against the target: REPRL handshake, outcome\n" + "classification (success, exception, timeout, crash), output capture,\n" + "coverage evaluation, edge determinism and respawning. Prints PASS/FAIL\n" + "per check and exits with 1 if any check failed.\n" + "\n" + "Before the target checks it runs the offline selection checks: the\n" + "default seed, partner, mutator and generator strategies must reproduce\n" + "the picks recorded in experimental/redline/testdata/selection/*.trace.\n" + "\n" + "options:\n" + " --speed-runs=N executions for the speed measurement (200)\n" + " --offline only the checks that need no target (--d8 not " + "needed)\n" + " --testdata=DIR experimental/redline/testdata (default: found next " + "to the binary)\n" + " --write-golden rewrite the selection traces instead of comparing " + "them\n" + " (only for an intended change of the default picks)\n", + RunSelftest, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/selftest_selection.cc b/deps/v8/experimental/redline/commands/selftest_selection.cc new file mode 100644 index 000000000000..19fd70abd7ba --- /dev/null +++ b/deps/v8/experimental/redline/commands/selftest_selection.cc @@ -0,0 +1,1088 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/commands/selftest_selection.h" + +#include <algorithm> +#include <climits> +#include <cmath> +#include <cstdlib> +#include <limits> +#include <memory> +#include <string> +#include <vector> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/core/adaptive_selector.h" +#include "experimental/redline/core/builder.h" +#include "experimental/redline/core/environment.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/core/random.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/corpus/corpus.h" +#include "experimental/redline/engine/amplifier.h" +#include "experimental/redline/engine/config.h" +#include "experimental/redline/engine/prelude.h" +#include "experimental/redline/engine/stages.h" +#include "experimental/redline/fast/parser.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/generators/generator.h" +#include "experimental/redline/mutators/mutator.h" + +namespace redline { + +namespace { + +// The fixed seed and sizes of the traces. Changing any of them invalidates +// the golden files (regenerate with --write-golden and explain why). +constexpr uint64_t kSeed = 20261011; +constexpr int kMutatorPicks = 2000; +constexpr int kGeneratorPicks = 2000; +constexpr int kCodeGenMutations = 1000; +constexpr int kCorpusPrograms = 50; +constexpr int kCorpusPicks = 1000; + +// A program with a few variables of different types, so that every +// generator finds something to work with. +constexpr const char* kProgram = R"(let n = 42; +let s = "text"; +let a = [1, 2, 3]; +let o = {x: 1, y: "two"}; +function f(p, q) { + let t = p + q; + for (let i = 0; i < 3; i++) { + t += a[i]; + } + return t; +} +let r = f(n, 7); +class C { + constructor(v) { this.v = v; } + get value() { return this.v; } +} +let c = new C(r); +)"; + +std::shared_ptr<Program> ParseOrDie(const std::string& source, + const std::string& origin) { + Lineage lineage; + lineage.origin = origin; + std::string error; + std::shared_ptr<Program> program = Program::Parse(source, lineage, &error); + if (program == nullptr) { + REDLINE_ERROR("selftest", "selection check program does not parse: %s", + error.c_str()); + abort(); + } + return program; +} + +// --- the four traces ------------------------------------------------------ + +// Which mutator is applied: MutatorSet::Pick with and without a partner. +std::string TraceMutatorPicks(const MutatorSet& mutators) { + Random rng(kSeed); + std::string trace; + for (int i = 0; i < kMutatorPicks; i++) { + bool has_partner = (i % 3) != 0; + Mutator* m = mutators.Pick(rng, has_partner); + trace += StringPrintf("%d\t%d\t%s\n", i, has_partner ? 1 : 0, + m != nullptr ? m->name().c_str() : "-"); + } + return trace; +} + +// Which generator is chosen for a random insertion slot of the fixed +// program: GeneratorSet::Pick. +std::string TraceGeneratorPicks(const GeneratorSet& generators, + const Environment& env) { + Random rng(kSeed); + ProgramPtr program = ParseOrDie(kProgram, "selftest"); + std::string trace; + for (int i = 0; i < kGeneratorPicks; i++) { + std::unique_ptr<fast::Tree> tree = program->CopyTree(); + Builder builder(tree.get(), &rng); + Builder::Slot slot = builder.RandomInsertionSlot(); + if (!slot.valid()) { + trace += StringPrintf("%d\t(no slot)\n", i); + continue; + } + GenContext ctx = MakeGenContext(builder, slot, generators, env); + Generator* g = generators.Pick(ctx); + trace += + StringPrintf("%d\t%s\n", i, g != nullptr ? g->name().c_str() : "-"); + } + return trace; +} + +// Which generators CodeGen inserts, through the whole mutator (its own +// generator filter and slot choice included): the `detail` of each mutation. +std::string TraceCodeGen(const MutatorSet& mutators, + const GeneratorSet& generators, + const Environment& env) { + Mutator* codegen = mutators.Find("CodeGen"); + if (codegen == nullptr) { + return "(no CodeGen mutator)\n"; + } + Random rng(kSeed); + ProgramPtr program = ParseOrDie(kProgram, "selftest"); + std::string trace; + for (int i = 0; i < kCodeGenMutations; i++) { + std::string detail; + std::unique_ptr<fast::Tree> tree = + ApplyMutation(*codegen, *program, nullptr, rng, env, generators, + /*rounds=*/1, &detail); + trace += + StringPrintf("%d\t%s\n", i, tree != nullptr ? detail.c_str() : "noop"); + } + return trace; +} + +// Which corpus program a scheduler picks next and which partner it offers, +// with the feedback a fuzzing session would give (every 7th mutation +// "interesting"). +std::string TraceScheduler(const std::string& name) { + std::string error; + SelectorRegistry<const Program>& registry = + SelectorRegistry<const Program>::Instance(); + std::unique_ptr<ProgramSelector> seeds = + registry.Create(SelectionConfig{name, JsonValue()}, &error); + if (seeds == nullptr) { + return "(" + error + ")\n"; + } + std::unique_ptr<ProgramSelector> partners = + registry.Create(SelectionConfig{"uniform-partner", JsonValue()}, &error); + if (partners == nullptr) { + return "(" + error + ")\n"; + } + Corpus corpus(std::move(seeds), std::move(partners)); + for (int i = 0; i < kCorpusPrograms; i++) { + corpus.Add(ParseOrDie(StringPrintf("let v%d = %d;\n", i, i), "selftest")); + } + Random rng(kSeed); + std::string trace; + for (int i = 0; i < kCorpusPicks; i++) { + ProgramPtr parent = corpus.Pick(rng); + if (parent == nullptr) { + trace += StringPrintf("%d\t-\t-\n", i); + continue; + } + ProgramPtr partner = corpus.PickPartner(*parent, rng); + corpus.OnResult(*parent, (i % 7) == 0); + trace += StringPrintf("%d\t%u\t%u\n", i, parent->id, + partner != nullptr ? partner->id : 0u); + } + return trace; +} + +// --- component outputs +// -------------------------------------------------------- +// +// The output of every generator and every mutator for a fixed seed: pins +// the numbers inside them (the tunables), not only which one is picked. One +// line per output: name, index, FNV-1a hash of the program, a glimpse. + +constexpr int kOutputsPerComponent = 5; + +std::string Glimpse(const std::string& source) { + std::string out; + for (char c : source) { + if (out.size() >= 70) { + break; + } + out += (c == '\n' || c == '\t') ? ' ' : c; + } + return out; +} + +// Sample `i` of generator `g`: inserts its code at a random place of a copy +// of `program`. Returns the tree and the generated statements in `*out`, or +// nullptr if the generator produced nothing. +std::unique_ptr<fast::Tree> GenerateSample(Generator* g, int i, + const Program& program, + const GeneratorSet& generators, + const Environment& env, + std::vector<fast::Statement*>* out) { + Random rng(kSeed + static_cast<uint64_t>(i) * 7919 + + Program::HashSource(g->name())); + std::unique_ptr<fast::Tree> tree = program.CopyTree(); + Builder builder(tree.get(), &rng); + for (int attempt = 0; attempt < 10; attempt++) { + Builder::Slot slot = builder.RandomInsertionSlot(); + if (!slot.valid()) { + break; + } + GenContext ctx = MakeGenContext(builder, slot, generators, env); + if (!g->Applicable(ctx)) { + continue; + } + ctx.out = out; + if (g->Generate(ctx, out) && !out->empty()) { + builder.InsertAll(slot, *out); + return tree; + } + break; + } + return nullptr; +} + +std::string TraceGeneratorOutputs(const GeneratorSet& generators, + const Environment& env) { + std::shared_ptr<Program> program = ParseOrDie(kProgram, "selftest"); + std::string trace; + for (Generator* g : generators.candidates()) { + for (int i = 0; i < kOutputsPerComponent; i++) { + std::vector<fast::Statement*> out; + std::unique_ptr<fast::Tree> tree = + GenerateSample(g, i, *program, generators, env, &out); + std::string result = tree != nullptr ? fast::Print(tree->root()) : "noop"; + trace += StringPrintf( + "%s\t%d\t%016llx\t%s\n", g->name().c_str(), i, + static_cast<unsigned long long>(Program::HashSource(result)), + Glimpse(result).c_str()); + } + } + return trace; +} + +std::string TraceMutatorOutputs(const MutatorSet& mutators, + const GeneratorSet& generators, + const Environment& env) { + std::shared_ptr<Program> program = ParseOrDie(kProgram, "selftest"); + std::shared_ptr<Program> partner = ParseOrDie( + "function g(x) { return x * 2; }\nlet q = [g(1), g(2)];\nlet m = new " + "Map([[1, 'a']]);\n", + "selftest"); + std::string trace; + for (Mutator* m : mutators.candidates()) { + for (int i = 0; i < kOutputsPerComponent; i++) { + Random rng(kSeed + static_cast<uint64_t>(i) * 7919 + + Program::HashSource(m->name())); + std::string detail; + std::unique_ptr<fast::Tree> tree = ApplyMutation( + *m, *program, partner, rng, env, generators, /*rounds=*/1, &detail); + std::string result = tree != nullptr ? fast::Print(tree->root()) : "noop"; + trace += StringPrintf( + "%s\t%d\t%016llx\t%s\t%s\n", m->name().c_str(), i, + static_cast<unsigned long long>(Program::HashSource(result)), + detail.c_str(), Glimpse(result).c_str()); + } + } + return trace; +} + +// --- golden comparison ------------------------------------------------------ + +// Returns the first line that differs, formatted for a FAIL message. +std::string FirstDifference(const std::string& expected, + const std::string& actual) { + size_t line = 1; + size_t i = 0; + while (i < expected.size() && i < actual.size() && expected[i] == actual[i]) { + if (expected[i] == '\n') { + line++; + } + i++; + } + auto line_at = [](const std::string& s, size_t pos) { + size_t start = s.rfind('\n', pos == 0 ? 0 : pos - 1); + start = start == std::string::npos ? 0 : start + 1; + size_t end = s.find('\n', pos); + return s.substr(start, (end == std::string::npos ? s.size() : end) - start); + }; + return StringPrintf("first difference at line %zu: golden '%s', now '%s'", + line, line_at(expected, i).c_str(), + line_at(actual, i).c_str()); +} + +void CompareOrWrite(Checker* checker, const std::string& check_name, + const std::string& path, const std::string& trace, + bool write_golden) { + std::string error; + if (write_golden) { + bool ok = WriteStringToFile(path, trace, &error); + checker->Check(check_name.c_str(), ok, ok ? "written: " + path : error); + return; + } + std::string golden; + if (!ReadFileToString(path, &golden, &error)) { + checker->Check( + check_name.c_str(), false, + "cannot read " + path + " (" + error + "); --write-golden creates it"); + return; + } + if (golden == trace) { + size_t lines = + static_cast<size_t>(std::count(trace.begin(), trace.end(), '\n')); + checker->Check(check_name.c_str(), true, + StringPrintf("%zu picks identical to %s", lines, + BaseName(path).c_str())); + return; + } + checker->Check(check_name.c_str(), false, FirstDifference(golden, trace)); +} + +// Parses a JSON `selection` block the way FuzzConfig::Load does and runs the +// startup validation. Returns the error message ("" when accepted). +std::string SelectionError(const std::string& selection_json) { + std::string text = "{\"selection\": " + selection_json + "}"; + JsonValue json; + std::string error; + if (!JsonValue::Parse(text, &json, &error)) { + return "test bug, invalid JSON: " + error; + } + FuzzConfig config; + // The JSON part of the real loader, then the startup validation that + // Load() runs last. + if (!FuzzConfig::LoadJsonForTest(json, &config, &error)) { + return error; + } + return FuzzConfig::ValidateSelection(config.selection, &error) ? "" : error; +} + +void CheckConfigErrors(Checker* checker) { + struct Case { + const char* name; + const char* json; + bool accepted; + const char* expect; // substring of the error message + }; + const Case cases[] = { + {"selection: default block is accepted", "{}", true, ""}, + {"selection: all built-in strategies with parameters are accepted", + R"({"seeds": {"strategy": "recency", "params": {"recent_share": 0.3}}, + "partners": {"strategy": "uniform-partner", "params": {"tries": 2}}, + "mutators": {"strategy": "weighted", "params": {"weights": {"Splice": 4, "Reorder": 0}}}, + "generators": {"strategy": "weighted", "params": {"weights": {"JitOptimize": 10}}}})", + true, ""}, + {"selection: unknown strategy is an error", + R"({"seeds": {"strategy": "ml-magic"}})", false, + "unknown selection strategy 'ml-magic'"}, + {"selection: unknown parameter is an error", + R"({"seeds": {"strategy": "tournament", "params": {"sizes": 3}}})", + false, "unknown parameter 'sizes'"}, + {"selection: wrong parameter type is an error", + R"({"partners": {"strategy": "uniform-partner", "params": {"tries": "four"}}})", + false, "must be a number"}, + {"selection: unknown mutator in weights is an error", + R"({"mutators": {"strategy": "weighted", "params": {"weights": {"Splicer": 4}}}})", + false, "unknown mutator in weights: Splicer"}, + {"selection: unknown generator in weights is an error", + R"({"generators": {"params": {"weights": {"JitOptimise": 1}}}})", false, + "unknown generator in weights: JitOptimise"}, + {"selection: a parameter the strategy does not take is an error", + R"({"mutators": {"strategy": "weighted", "params": {"tries": 1}}})", + false, "unknown parameter 'tries'"}, + {"selection: a weight that is not a number is an error", + R"({"mutators": {"strategy": "weighted", "params": {"weights": {"Splice": "many"}}}})", + false, "weight of 'Splice' must be a non-negative number"}, + }; + for (const Case& c : cases) { + std::string error = SelectionError(c.json); + bool ok = c.accepted ? error.empty() + : (!error.empty() && + error.find(c.expect) != std::string::npos); + checker->Check(c.name, ok, error.empty() ? "accepted" : error); + } +} + +// The "stages" block: parameters land in the right fields, the block wins +// over the flat keys, and mistakes are reported. +void CheckStageConfig(Checker* checker) { + auto load = [](const std::string& text, FuzzConfig* config) -> std::string { + JsonValue json; + std::string error; + if (!JsonValue::Parse(text, &json, &error)) { + return "test bug, invalid JSON: " + error; + } + return FuzzConfig::LoadJsonForTest(json, config, &error) ? "" : error; + }; + { + FuzzConfig config; + std::string error = load( + R"({"consecutive_mutations": 9, + "stages": {"prefix": {"min_values": 3, "extra_values": 1}, + "mutate": {"consecutive": 2, "rounds": 1, "log": "events", + "capture": {"on": "timeout,invalid", "mutators": ["Input"], "max": 3}}, + "check": {"min_reruns": 2, "max_reruns": 8, "capture": {"on": ["flaky"]}}, + "minimize": {"enabled": false, "max_tests": 12}, + "publish": {"save_corpus": false, "stats": false}}})", + &config); + bool ok = + error.empty() && config.prefix_min_values == 3 && + config.prefix_extra_values == 1 && config.consecutive_mutations == 2 && + config.mutation_rounds == 1 && config.stage(Stage::kMutate).events && + config.stage(Stage::kMutate).capture.on.size() == 2 && + config.stage(Stage::kMutate).capture.mutators == + std::vector<std::string>{"Input"} && + config.stage(Stage::kMutate).capture.max == 3 && + config.min_reruns == 2 && config.max_reruns == 8 && + config.stage(Stage::kCheck) + .capture.Matches(CaptureTrigger::kFlaky, "") && + !config.minimize && config.minimizer.max_tests == 12 && + !config.save_corpus && !config.stage(Stage::kPublish).stats; + checker->Check( + "stages: block sets the stage parameters and wins over flat keys", ok, + error.empty() ? "" : error); + // The block round-trips through ToJson (what the start event records). + JsonValue again; + std::string parse_error; + bool round_trip = + JsonValue::Parse(config.ToJson(), &again, &parse_error) && + again.Get("stages").Get("mutate").GetInt("consecutive", 0) == 2 && + again.Get("stages").Get("mutate").Get("capture").Get("on").is_array() && + !again.Get("stages").Get("minimize").GetBool("enabled", true); + checker->Check( + "stages: block round-trips through the recorded configuration", + round_trip, parse_error); + } + struct Case { + const char* name; + const char* json; + const char* expect; + }; + const Case cases[] = { + {"stages: unknown stage is an error", R"({"stages": {"mutat": {}}})", + "unknown stage \"mutat\""}, + {"stages: unknown key is an error", + R"({"stages": {"mutate": {"consecutiv": 3}}})", + "unknown key \"consecutiv\" in stages.mutate"}, + {"stages: trigger that does not apply is an error", + R"({"stages": {"check": {"capture": {"on": ["interesting"]}}}})", + "does not apply to the check stage"}, + {"stages: bad log value is an error", + R"({"stages": {"minimize": {"log": "verbose"}}})", + "log must be \"events\" or \"off\""}, + {"stages: capture.mutators outside mutate is an error", + R"({"stages": {"pick": {"capture": {"mutators": ["Splice"]}}}})", + "only applies to the mutate stage"}, + {"stages: unknown trigger is an error", + R"({"stages": {"mutate": {"capture": {"on": ["slow"]}}}})", + "unknown capture trigger 'slow'"}, + }; + for (const Case& c : cases) { + FuzzConfig config; + std::string error = load(c.json, &config); + checker->Check(c.name, + !error.empty() && error.find(c.expect) != std::string::npos, + error); + } + // The flag form of a capture rule. + { + Stage stage = Stage::kPick; + CaptureRule rule; + std::string error; + bool ok = CaptureRule::FromFlag("mutate:timeout,crash:Splice,Combine:7", + &stage, &rule, &error) && + stage == Stage::kMutate && rule.on.size() == 2 && + rule.mutators.size() == 2 && rule.max == 7 && + rule.Matches(CaptureTrigger::kCrash, "Combine") && + !rule.Matches(CaptureTrigger::kCrash, "Input"); + checker->Check("stages: --capture rule parses", ok, error); + ok = !CaptureRule::FromFlag("publish:timeout", &stage, &rule, &error) && + error.find("does not apply") != std::string::npos; + checker->Check("stages: --capture with an inapplicable trigger is an error", + ok, error); + } +} + +// Tunables (core/tunable.h): set from the config, validated, reported. +// A component for the adaptive selector tests. +struct FakeComponent { + std::string label; + double base = 1; + ComponentStats counters; + + const std::string& name() const { return label; } + double weight() const { return base; } + ComponentStats& stats() { return counters; } + const ComponentStats& stats() const { return counters; } +}; + +void CheckAdaptiveWindow(Checker* checker) { + using Selector = AdaptiveSelector<FakeComponent>; + Selector::Settings settings; + settings.prior_executions = 10; + Selector selector("component", {}, settings); + uint64_t now_us = 0; + selector.SetClockForTesting([&now_us] { return now_us; }); + FakeComponent cheap; + cheap.label = "Cheap"; + FakeComponent costly; + costly.label = "Costly"; + std::string error; + const bool initialized = selector.Initialize({&cheap, &costly}, &error); + // Same new edges; Costly spent 10 times more executions for them. + cheap.counters.new_edges = 100; + cheap.counters.spent = 1000; + costly.counters.new_edges = 100; + costly.counters.spent = 10000; + Random rng(1); + now_us = 1000000; + selector.Pick({&cheap, &costly}, rng, + [](const FakeComponent&) { return true; }); + checker->Check( + "adaptive: no weight update before window_sec", + initialized && selector.WeightOf(cheap) == selector.WeightOf(costly), + error); + now_us = 601000000; + selector.Pick({&cheap, &costly}, rng, + [](const FakeComponent&) { return true; }); + checker->Check( + "adaptive: the time window updates the weights, and new edges per spent " + "execution favour the cheap one", + selector.WeightOf(cheap) > selector.WeightOf(costly), + StringPrintf("Cheap %.2f, Costly %.2f", selector.WeightOf(cheap), + selector.WeightOf(costly))); +} + +void CheckAmplifyConfig(Checker* checker) { + struct Case { + const char* name; + const char* strategy; + const char* params; + bool accepted; + const char* expect; // substring of the error message + }; + const Case cases[] = { + {"amplify: the default strategy is accepted", "flags", "{}", true, ""}, + {"amplify: none is accepted", "none", "{}", true, ""}, + {"amplify: rules are accepted", "flags", + R"({"rules": [{"frames": ["Heap::"], "args": "--stress-compaction"}], "processes": 3, "min_hits": 2})", + true, ""}, + {"amplify: unknown strategy is an error", "magic", "{}", false, + "unknown amplify strategy"}, + {"amplify: unknown param is an error", "flags", R"({"retries": 3})", + false, "unknown amplify param"}, + {"amplify: min_hits above processes is an error", "flags", + R"({"processes": 3, "min_hits": 4})", false, "min_hits <= processes"}, + {"amplify: a rule without args is an error", "flags", + R"({"rules": [{"frames": ["Heap::"]}]})", false, "needs \"frames\""}, + }; + for (const Case& c : cases) { + JsonValue params; + std::string error; + JsonValue::Parse(c.params, ¶ms, &error); + const bool built = + CreateAmplifyStrategy(c.strategy, params, &error) != nullptr; + const bool ok = c.accepted + ? built + : (!built && error.find(c.expect) != std::string::npos); + checker->Check(c.name, ok, built ? "accepted" : error); + } + checker->Check( + "amplify: --stress-runs follows the run time within [2, max_loops]", + StressRunsFor(215000, 10, 100) == 46 && + StressRunsFor(100, 10, 100) == 100 && + StressRunsFor(60000000, 10, 100) == 2, + StringPrintf("%d, %d, %d", StressRunsFor(215000, 10, 100), + StressRunsFor(100, 10, 100), + StressRunsFor(60000000, 10, 100))); +} + +// WrapInTry on a real script (Redline's own prelude): the result parses, and +// everything except a leading directive prologue is in one try statement. +void CheckWrapInTry(Checker* checker) { + const std::string wrapped = WrapInTry(std::string(DefaultPrelude())); + fast::ParseError error; + std::unique_ptr<fast::Tree> tree = + wrapped.empty() + ? nullptr + : fast::Parser::ParseScript(wrapped, fast::ParseOptions(), &error); + size_t statements = 0; + bool last_is_try = false; + if (tree != nullptr && tree->root() != nullptr) { + for (const fast::Statement* s : tree->root()->body) { + const auto* e = s->As<fast::ExpressionStatement>(); + if (e == nullptr || !e->is_directive) { + statements++; + } + } + last_is_try = + !tree->root()->body.empty() && + tree->root()->body.back()->As<fast::TryStatement>() != nullptr; + } + checker->Check( + "amplify: WrapInTry puts the program into one try statement that parses", + statements == 1 && last_is_try, + tree == nullptr ? "does not parse: " + error.message + : StringPrintf("%zu top-level statements", statements)); + checker->Check("amplify: WrapInTry of an empty program is empty", + WrapInTry("").empty()); +} + +void CheckTunables(Checker* checker) { + TunableRegistry& registry = TunableRegistry::Instance(); + registry.Reset(); + std::vector<const Tunable*> all = registry.All(); + checker->Check("tunables: the registry is populated", !all.empty(), + StringPrintf("%zu tunables declared", all.size())); + if (all.empty()) { + return; + } + const Tunable* t = all.front(); + std::string error; + // A value inside the range is accepted and visible; the recorded + // configuration lists it as non-default. + double inside = t->min() == t->max() ? t->min() : (t->min() + t->max()) / 2; + bool ok = registry.Set(t->name(), inside, &error) && (*t)() == inside; + checker->Check("tunables: a value in range is set", ok, + error.empty() ? std::string(t->name()) : error); + std::string json = registry.NonDefaultsJson(); + checker->Check( + "tunables: changed values appear in the recorded configuration", + inside == t->default_value() || + json.find(std::string(t->name())) != std::string::npos, + json); + registry.Reset(); + checker->Check("tunables: Reset restores the default", + (*t)() == t->default_value()); + ok = !registry.Set(t->name(), t->max() + 1, &error) && + error.find("outside its range") != std::string::npos; + checker->Check("tunables: a value outside the range is an error", ok, error); + ok = !registry.Set("generators.NoSuchThing.chance", 0.5, &error) && + error.find("unknown tunable") != std::string::npos; + checker->Check("tunables: an unknown name is an error", ok, error); + ok = registry.SetFromList( + std::string(t->name()) + "=" + std::to_string(inside), &error) && + (*t)() == inside; + checker->Check("tunables: --tunable=name=value parses", ok, error); + registry.Reset(); + ok = !registry.SetFromList("nonsense", &error) && + error.find("NAME=VALUE") != std::string::npos; + checker->Check("tunables: a malformed --tunable is an error", ok, error); + // Through the config loader. + JsonValue cfg; + FuzzConfig config; + std::string parse; + JsonValue::Parse("{\"tunables\": {\"generators.NoSuchThing.chance\": 1}}", + &cfg, &parse); + ok = !FuzzConfig::LoadJsonForTest(cfg, &config, &error) && + error.find("unknown tunable") != std::string::npos; + checker->Check("tunables: unknown name in the config file is an error", ok, + error); + registry.Reset(); +} + +// The engine options that used to be constants, inline --config JSON, and +// the full configuration dump: complete, loadable, identical after a round +// trip. +void CheckConfigDump(Checker* checker) { + TunableRegistry::Instance().Reset(); + std::string error; + // The engine knobs land in their fields. + { + JsonValue json; + FuzzConfig config; + JsonValue::Parse( + R"({"introspect_timeout_ms": 5000, "crash_reruns_stop_after": 1, + "stages": {"minimize": {"probe_timeout_factor": 2, "probe_timeout_extra_ms": 10, + "probe_timeout_min_ms": 30, "verify_attempts": 5}}})", + &json, &error); + bool ok = FuzzConfig::LoadJsonForTest(json, &config, &error) && + config.introspect_timeout_ms == 5000 && + config.crash_reruns_stop_after == 1 && + config.probe_timeout_factor == 2 && + config.probe_timeout_extra_ms == 10 && + config.probe_timeout_min_ms == 30 && config.verify_attempts == 5; + checker->Check("config: engine options are read from the JSON", ok, error); + } + // Inline JSON on the command line goes through the same reader. + { + const char* argv[] = { + "redline", "fuzz", + R"(--config={"stages": {"minimize": {"verify_attempts": 7}}})"}; + Flags flags = Flags::Parse(3, argv, 2); + FuzzConfig config; + bool ok = FuzzConfig::Load(flags, &config, &error, /*for_run=*/false) && + config.verify_attempts == 7; + checker->Check("config: --config accepts inline JSON", ok, error); + const char* bad[] = {"redline", "fuzz", "--config={\"stages\": nonsense}"}; + flags = Flags::Parse(3, bad, 2); + ok = !FuzzConfig::Load(flags, &config, &error, /*for_run=*/false) && + error.find("--config:") != std::string::npos; + checker->Check("config: malformed inline JSON is an error naming --config", + ok, error); + } + // The full dump: every tunable and every weight, and it round-trips. + { + error.clear(); + FuzzConfig config; + std::string dump = config.ToJson(FuzzConfig::Detail::kFull); + JsonValue json; + bool ok = JsonValue::Parse(dump, &json, &error); + size_t tunables = ok ? json.Get("tunables").as_object().size() : 0; + size_t weights = ok ? json.Get("selection") + .Get("mutators") + .Get("params") + .Get("weights") + .as_object() + .size() + : 0; + ok = ok && tunables == TunableRegistry::Instance().size() && + weights == MutatorSet::CreateDefault()->candidates().size() && + json.Has("introspect_timeout_ms") && + json.Get("stages").Get("minimize").Has("verify_attempts"); + checker->Check( + "config: the full dump lists every tunable and every mutator weight", + ok, StringPrintf("%zu tunables, %zu weights", tunables, weights)); + FuzzConfig again; + ok = FuzzConfig::LoadJsonForTest(json, &again, &error) && + again.ToJson(FuzzConfig::Detail::kFull) == dump; + checker->Check( + "config: the full dump loads back to an identical configuration", ok, + error); + // The compact form only lists what differs from the defaults. + JsonValue compact; + ok = JsonValue::Parse(config.ToJson(), &compact, &error) && + compact.Get("tunables").as_object().empty(); + checker->Check( + "config: the compact form lists no tunable when all are at their " + "default", + ok, error); + // The pretty form is the same JSON. + JsonValue pretty; + ok = JsonValue::Parse(JsonPretty(dump), &pretty, &error) && + pretty.ToString() == json.ToString(); + checker->Check("json: the pretty form parses to the same value", ok, error); + } + { + // Event logs must stay valid UTF-8: UTF-8 is kept, other bytes + // (a lone surrogate from a string literal) become U+FFFD. + const std::string quoted = JsonQuote( + "a\xc3\xa9\xe2\x82\xac\xf0\x9f\x98\x80|\xed\xa0\x80|\xff|\xc3"); + const std::string expect = + "\"a\xc3\xa9\xe2\x82\xac\xf0\x9f\x98\x80|\\ufffd\\ufffd\\ufffd|\\ufffd|" + "\\ufffd\""; + checker->Check("json: strings are quoted as valid UTF-8", quoted == expect, + quoted); + } + TunableRegistry::Instance().Reset(); +} + +// The "init" and "accept" blocks and stages.minimize.reducers: values land +// in their fields, mistakes are reported. +void CheckStrategyBlocks(Checker* checker) { + auto load = [](const std::string& text, FuzzConfig* config) -> std::string { + JsonValue json; + std::string error; + if (!JsonValue::Parse(text, &json, &error)) { + return "test bug, invalid JSON: " + error; + } + if (!FuzzConfig::LoadJsonForTest(json, config, &error)) { + return error; + } + return FuzzConfig::ValidateReducers(config->minimizer_reducers, &error) + ? "" + : error; + }; + { + FuzzConfig config; + std::string error = load( + R"({"init": {"strategy": "import", "params": {"paths": ["a.js", "dir"], "root": "/r", "keep": "all"}}, + "accept": {"strategy": "new-edges"}, + "stages": {"minimize": {"reducers": ["truncate", "statements"]}}})", + &config); + bool ok = error.empty() && + config.imports == std::vector<std::string>{"a.js", "dir"} && + config.import_root == "/r" && config.import_all && + config.minimizer_reducers == + std::vector<std::string>{"truncate", "statements"}; + checker->Check("init, accept, reducers: the blocks set their fields", ok, + error); + error = + load(R"({"init": {"strategy": "generate", "params": {"programs": 5}}})", + &config); + ok = + error.empty() && config.imports.empty() && config.initial_programs == 5; + checker->Check( + "init: generate clears the imports and sets the program count", ok, + error); + } + struct Case { + const char* name; + const char* json; + const char* expect; + }; + const Case cases[] = { + {"init: unknown strategy is an error", + R"({"init": {"strategy": "resume"}})", "unknown init strategy"}, + {"init: unknown parameter is an error", + R"({"init": {"strategy": "generate", "params": {"paths": []}}})", + "unknown parameter \"paths\""}, + {"init: bad keep value is an error", + R"({"init": {"strategy": "import", "params": {"keep": "some"}}})", + "keep must be"}, + {"accept: unknown criterion is an error", + R"({"accept": {"strategy": "rarity"}})", "unknown accept strategy"}, + {"minimize: unknown reducer is an error", + R"({"stages": {"minimize": {"reducers": ["statements", "shrink"]}}})", + "unknown reducer \"shrink\""}, + }; + for (const Case& c : cases) { + FuzzConfig config; + std::string error = load(c.json, &config); + checker->Check(c.name, + !error.empty() && error.find(c.expect) != std::string::npos, + error); + } +} + +// --- FAST node kinds -------------------------------------------------------- + +// Samples per generator for the node-kind check. Fixed seeds: the result +// only changes when a generator changes. +constexpr int kKindSamples = 40; + +// The node kinds that no generator produces, with the reason. A kind that +// a generator starts to produce must leave this list (the check says so). +struct UngeneratedKind { + const char* kind; + const char* reason; +}; +const UngeneratedKind kUngeneratedKinds[] = { + {"Program", "the root of every tree, never inside generated code"}, + {"EmptyStatement", "`;` has no behaviour to test"}, + {"DebuggerStatement", + "`debugger;` does nothing without an attached debugger, and d8 runs " + "without one"}, + {"ImportExpression", + "import() loads module files, and a fuzzed program is one script without " + "modules"}, +}; + +// Which node kinds appear in the code of any generator. +std::vector<bool> GeneratedKinds() { + std::unique_ptr<GeneratorSet> generators = GeneratorSet::CreateDefault(); + const Environment& env = Environment::Default(); + std::shared_ptr<Program> program = ParseOrDie(kProgram, "selftest"); + std::vector<bool> seen(fast::kNumNodeKinds, false); + for (Generator* g : generators->candidates()) { + for (int i = 0; i < kKindSamples; i++) { + std::vector<fast::Statement*> out; + // The statements live in the tree's arena: keep the tree. + std::unique_ptr<fast::Tree> tree = + GenerateSample(g, i, *program, *generators, env, &out); + if (tree == nullptr) { + continue; + } + for (fast::Statement* statement : out) { + fast::Walk(statement, [&](fast::Node* node) { + seen[static_cast<size_t>(node->kind)] = true; + return true; + }); + } + } + } + return seen; +} + +void CheckEdgeCases(Checker* checker) { + // Lexer & Parser edge cases: invalid UTF-8, invalid numeric literals, + // `for (await using of ...)` disambiguation, and deep expression chains. + { + fast::ParseOptions opts; + fast::ParseError err; + bool rejected_overlong = + fast::Parser::ParseScript("let \xc0\xaf = 1;", opts, &err) == nullptr && + fast::Parser::ParseScript("let \xf4\x90\x80\x80 = 1;", opts, &err) == + nullptr; + checker->Check( + "lexer: overlong and out-of-range UTF-8 sequences are rejected", + rejected_overlong, err.message); + + const char* bad_numbers[] = { + "let x = 0_1;", "let x = 07_7;", "let x = 0x1g;", "let x = 0b12;", + "let x = 0o78;", "let x = 1n2;", "let x = 08a;"}; + bool all_bad_rejected = true; + for (const char* src : bad_numbers) { + if (fast::Parser::ParseScript(src, opts, &err) != nullptr) { + all_bad_rejected = false; + break; + } + } + checker->Check( + "lexer: invalid numeric separators and trailing identifier chars are " + "rejected", + all_bad_rejected, err.message); + + bool for_await_using_ok = + fast::Parser::ParseScript( + "async function f(x) { for await (using of x) {} }", opts, &err) != + nullptr && + fast::Parser::ParseScript( + "async function f(x) { for (await using y of x) {} }", opts, + &err) != nullptr && + fast::Parser::ParseScript( + "async function f(x) { for (await using of of x) {} }", opts, + &err) != nullptr && + fast::Parser::ParseScript("for (using \\u006ff of []) {}", opts, + &err) != nullptr; + checker->Check("parser: for-await with 'using' identifier vs declaration", + for_await_using_ok, err.message); + + std::string deep = "let x = 0"; + for (int i = 0; i < 1300; i++) { + deep += " + 1"; + } + deep += ";"; + bool deep_rejected = + fast::Parser::ParseScript(deep, opts, &err) == nullptr && + err.message.find("nesting") != std::string::npos; + checker->Check("parser: excessive binary expression nesting is rejected", + deep_rejected, err.message); + } + // JSON and Random edge cases. + { + JsonValue val; + std::string err; + bool surrogate_not_swallowed = + JsonValue::Parse("\"\\uD800\\u0041\"", &val, &err) && + val.as_string().size() == 4 && val.as_string().back() == 'A'; + JsonValue pos_huge, neg_huge; + bool clamp_ok = JsonValue::Parse("1e100", &pos_huge, &err) && + pos_huge.as_int() == std::numeric_limits<int64_t>::max() && + JsonValue::Parse("-1e100", &neg_huge, &err) && + neg_huge.as_int() == std::numeric_limits<int64_t>::min(); + checker->Check( + "json: non-surrogate \\u after high surrogate and out-of-range " + "as_int()", + surrogate_not_swallowed && clamp_ok, err); + + Random rng(42); + int64_t r = rng.Range(INT64_MIN, INT64_MAX); + (void)r; + std::vector<double> weights = {1.0, 0.0}; + bool weighted_ok = true; + for (int i = 0; i < 32; i++) { + if (rng.Weighted(weights) != 0) { + weighted_ok = false; + } + } + checker->Check( + "random: full int64 Range and trailing zero weight in Weighted", + weighted_ok); + } +} + +} // namespace + +void RunSelectionChecks(Checker* checker, const std::string& testdata_dir, + bool write_golden) { + // Defaults everywhere before the traces are compared. + TunableRegistry::Instance().Reset(); + CheckConfigErrors(checker); + CheckStageConfig(checker); + CheckStrategyBlocks(checker); + const std::string dir = testdata_dir + "/selection"; + std::string error; + if (write_golden && !MakeDirectories(dir, &error)) { + checker->Check("selection: create golden directory", false, error); + return; + } + std::unique_ptr<MutatorSet> mutators = MutatorSet::CreateDefault(); + std::unique_ptr<GeneratorSet> generators = GeneratorSet::CreateDefault(); + const Environment& env = Environment::Default(); + + CompareOrWrite(checker, "selection: mutator picks match the golden trace", + dir + "/mutators.trace", TraceMutatorPicks(*mutators), + write_golden); + CompareOrWrite(checker, "selection: generator picks match the golden trace", + dir + "/generators.trace", + TraceGeneratorPicks(*generators, env), write_golden); + CompareOrWrite(checker, + "selection: CodeGen insertions match the golden trace", + dir + "/codegen.trace", + TraceCodeGen(*mutators, *generators, env), write_golden); + CompareOrWrite( + checker, "components: every generator's output matches the golden trace", + dir + "/generator_outputs.trace", TraceGeneratorOutputs(*generators, env), + write_golden); + CompareOrWrite( + checker, "components: every mutator's output matches the golden trace", + dir + "/mutator_outputs.trace", + TraceMutatorOutputs(*mutators, *generators, env), write_golden); + for (const std::string& name : + {"uniform", "recency", "tournament", "productive"}) { + std::string check = "selection: scheduler '"; + check += name; + check += "' picks match the golden trace"; + std::string path = dir; + path += "/scheduler_"; + path += name; + path += ".trace"; + CompareOrWrite(checker, check, path, TraceScheduler(name), write_golden); + } + CheckTunables(checker); + CheckConfigDump(checker); + CheckAdaptiveWindow(checker); + CheckAmplifyConfig(checker); + CheckWrapInTry(checker); + CheckEdgeCases(checker); +} + +void RunNodeKindChecks(Checker* checker) { + TunableRegistry::Instance().Reset(); + const std::vector<bool> seen = GeneratedKinds(); + std::vector<std::string> missing, stale; + for (int i = 0; i < fast::kNumNodeKinds; i++) { + const char* name = fast::NodeKindName(static_cast<fast::NodeKind>(i)); + bool listed = std::any_of( + std::begin(kUngeneratedKinds), std::end(kUngeneratedKinds), + [&](const UngeneratedKind& k) { return std::string(k.kind) == name; }); + if (!seen[static_cast<size_t>(i)] && !listed) { + missing.emplace_back(name); + } + if (seen[static_cast<size_t>(i)] && listed) { + stale.emplace_back(name); + } + } + auto join = [](const std::vector<std::string>& names) { + std::string out; + for (const std::string& name : names) { + out += (out.empty() ? "" : ", ") + name; + } + return out; + }; + checker->Check("node kinds: every FAST node kind comes out of a generator", + missing.empty(), + missing.empty() ? StringPrintf("%d kinds", fast::kNumNodeKinds) + : "no generator produces " + join(missing) + + " (add a generator, or list the kind in " + "kUngeneratedKinds with a reason)"); + checker->Check("node kinds: the list of ungenerated kinds is up to date", + stale.empty(), + stale.empty() ? "" + : "generators now produce " + join(stale) + + ": remove them from kUngeneratedKinds"); +} + +void RunPresetChecks(Checker* checker) { + const std::string dir = RedlineDataDir("presets"); + checker->Check("presets: locate experimental/redline/presets", !dir.empty(), + dir); + if (dir.empty()) { + return; + } + std::vector<std::string> files = ListFiles(dir, ".json"); + checker->Check("presets: the directory has presets", !files.empty(), dir); + for (const std::string& path : files) { + // The same path as `redline fuzz --preset=FILE`: the preset, then + // the validation that every configuration goes through. + std::string arg = "--preset=" + path; + const char* argv[] = {"redline", "fuzz", arg.c_str()}; + Flags flags = Flags::Parse(3, argv, 2); + FuzzConfig config; + std::string error; + bool ok = FuzzConfig::Load(flags, &config, &error, /*for_run=*/false); + checker->Check(("presets: " + BaseName(path) + " loads").c_str(), ok, + error); + } + TunableRegistry::Instance().Reset(); +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/commands/selftest_selection.h b/deps/v8/experimental/redline/commands/selftest_selection.h new file mode 100644 index 000000000000..0f1d4910d57c --- /dev/null +++ b/deps/v8/experimental/redline/commands/selftest_selection.h @@ -0,0 +1,42 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_COMMANDS_SELFTEST_SELECTION_H_ +#define V8_EXPERIMENTAL_REDLINE_COMMANDS_SELFTEST_SELECTION_H_ + +#include <string> + +#include "experimental/redline/commands/selftest_checker.h" + +namespace redline { + +// Offline checks (no target needed) of the four selection points: which +// corpus program is mutated next, which partner Splice/Combine get, which +// mutator is applied, and which generators CodeGen inserts. +// +// Every check drives the real selection code with a fixed seed and writes +// what was picked, one line per pick, into a text trace. The trace is +// compared with the file of the same name in `testdata_dir/selection/`. +// Those golden files were recorded before the selection code was moved +// behind the strategy interface, so a passing check proves that the default +// strategies pick exactly what the old code picked, draw for draw. +// +// With `write_golden` the traces are written instead of compared (only for +// deliberate behaviour changes; say so in the CL description). +void RunSelectionChecks(Checker* checker, const std::string& testdata_dir, + bool write_golden); + +// Offline: every FAST node kind comes out of at least one generator, except +// the kinds on a short list with a reason each (DESIGN.md 9). A new node +// kind fails this check until a generator produces it or it is listed. +void RunNodeKindChecks(Checker* checker); + +// Offline: every preset in experimental/redline/presets loads and names only +// existing strategies, mutators and generators. Skipped if the directory is not +// found. +void RunPresetChecks(Checker* checker); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_COMMANDS_SELFTEST_SELECTION_H_ diff --git a/deps/v8/experimental/redline/commands/shell_command.cc b/deps/v8/experimental/redline/commands/shell_command.cc new file mode 100644 index 000000000000..cc0ea9264e01 --- /dev/null +++ b/deps/v8/experimental/redline/commands/shell_command.cc @@ -0,0 +1,1133 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// "redline shell": an interactive workbench for one program. Load a file, +// look at it in every representation FAST offers (JavaScript, node ids, +// AST tree, scopes), apply a named mutator / generator / reducer with a +// chosen seed, run the result in d8 and see its outcome and coverage, +// undo, save. Everything the fuzzer does to a program, one step at a time. +// +// Reads commands from stdin (interactive with a prompt on a terminal, or +// scripted through a pipe / here-document). + +#include <unistd.h> + +#include <algorithm> +#include <cctype> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <iterator> +#include <memory> +#include <string> +#include <vector> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/base/v8_runtime.h" +#include "experimental/redline/commands/command.h" +#include "experimental/redline/core/builder.h" +#include "experimental/redline/core/component.h" +#include "experimental/redline/core/environment.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/core/random.h" +#include "experimental/redline/corpus/corpus.h" +#include "experimental/redline/engine/prelude.h" +#include "experimental/redline/exec/runner.h" +#include "experimental/redline/exec/target_options.h" +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/fast/scope.h" +#include "experimental/redline/fast/tree.h" +#include "experimental/redline/generators/generator.h" +#include "experimental/redline/minimizer/minimizer.h" +#include "experimental/redline/mutators/mutator.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "shell"; + +const char kUsage[] = + "usage: redline shell [--d8=PATH] [FILE.js]\n" + "\n" + "Interactive workbench for one program: inspect it in every FAST\n" + "representation, apply mutators / generators / reducers one at a time,\n" + "run the result in d8, undo, save. Commands are read from stdin, so the\n" + "shell can also be scripted (`redline shell f.js <<< 'mutate Splice'`).\n" + "Type `help` inside the shell for the command list.\n" + "\n" + "flags:\n" + " --d8=PATH enables run/reduce (or $REDLINE_D8)\n" + " --seed=S first seed used by mutate/generate/random (1)\n" + " --no-auto-print do not print the program after every change\n" + " --prelude=FILE|none JS prepended at execution time (default: the\n" + " mjsunit shim)\n" + " --v8-flags=\"...\" flags for the in-process V8 syntax oracle\n" + "\n"; + +const char kHelp[] = + "program\n" + " load FILE parse FILE as the current program (history reset)\n" + " source CODE parse CODE (rest of the line) as the program\n" + " new start from an empty program\n" + " save FILE write the current program\n" + " partner FILE|self donor program for Splice/Combine (default self)\n" + "views\n" + " print | p the program as JavaScript (canonical printer)\n" + " ids ... with `// nN` node id comments per statement\n" + " compact ... on one line\n" + " tree | t [ID] the AST (kind #id and a source snippet), or the\n" + " subtree of node ID\n" + " scopes scope analysis: scopes, bindings, references\n" + " info node count, size, syntax verdict, lineage\n" + " diff what the last step changed (line diff)\n" + " check | c ask the in-process V8 parser about validity\n" + "components\n" + " list [mutators|generators|reducers|strategies]\n" + " mutate | m NAME [SEED] apply mutator NAME (seed: next in " + "sequence)\n" + " generate | g NAME [SEED] insert code of generator NAME at a random\n" + " statement position\n" + " random | r [N] N weighted-random mutations, like a worker\n" + " reduce NAMES|default|all [ORACLE]\n" + " run reducer(s): one name, a comma list,\n" + " `default` (the fuzzer's order) or `all`;\n" + " ORACLE: edges (default,\n" + " edges of the current program minus those\n" + " of the previous one, if any), all-edges,\n" + " output, fail, crash (needs --d8)\n" + " seed [N] show/set the next seed\n" + " rounds [N] sub-mutations per mutate (1)\n" + "execution (needs --d8)\n" + " run | x [verbose] execute in d8: outcome, time, edges, new edges\n" + " since the previous run; verbose: stdout/stderr\n" + " accept [N] the Accept stage: N runs (10), deterministic and\n" + " flaky edges, and whether the step from the\n" + " previous program would be accepted\n" + "history\n" + " undo | u back to the previous program\n" + " reset back to the loaded program\n" + " history | h the steps so far\n" + "misc\n" + " stats component statistics tables\n" + " auto on|off print the program after every change (on)\n" + " help, quit\n"; + +std::vector<std::string> Split(const std::string& line) { + std::vector<std::string> words; + size_t i = 0; + while (i < line.size()) { + while (i < line.size() && isspace(static_cast<unsigned char>(line[i]))) { + i++; + } + size_t start = i; + while (i < line.size() && !isspace(static_cast<unsigned char>(line[i]))) { + i++; + } + if (i > start) { + words.push_back(line.substr(start, i - start)); + } + } + return words; +} + +std::vector<std::string> SplitComma(const std::string& text) { + std::vector<std::string> parts; + size_t start = 0; + while (start <= text.size()) { + size_t comma = text.find(',', start); + if (comma == std::string::npos) { + comma = text.size(); + } + if (comma > start) { + parts.push_back(text.substr(start, comma - start)); + } + start = comma + 1; + } + return parts; +} + +std::vector<std::string> Lines(const std::string& text) { + std::vector<std::string> lines; + size_t start = 0; + while (start < text.size()) { + size_t nl = text.find('\n', start); + if (nl == std::string::npos) { + nl = text.size(); + } + lines.push_back(text.substr(start, nl - start)); + start = nl + 1; + } + return lines; +} + +// Minimal LCS line diff, enough to show what one step changed. +void PrintLineDiff(const std::string& before, const std::string& after) { + std::vector<std::string> a = Lines(before), b = Lines(after); + const size_t kLimit = 1500; + if (a.size() > kLimit || b.size() > kLimit) { + printf("(programs too large for the diff view: %zu -> %zu lines)\n", + a.size(), b.size()); + return; + } + size_t n = a.size(), m = b.size(); + std::vector<std::vector<uint16_t>> lcs(n + 1, + std::vector<uint16_t>(m + 1, 0)); + for (size_t i = n; i-- > 0;) { + for (size_t j = m; j-- > 0;) { + lcs[i][j] = a[i] == b[j] ? static_cast<uint16_t>(lcs[i + 1][j + 1] + 1) + : std::max(lcs[i + 1][j], lcs[i][j + 1]); + } + } + size_t i = 0, j = 0; + int changes = 0; + while (i < n || j < m) { + if (i < n && j < m && a[i] == b[j]) { + i++; + j++; + } else if (i < n && (j == m || lcs[i + 1][j] >= lcs[i][j + 1])) { + printf("- %s\n", a[i++].c_str()); + changes++; + } else { + printf("+ %s\n", b[j++].c_str()); + changes++; + } + } + if (changes == 0) { + printf("(no textual change)\n"); + } +} + +std::string Snippet(const fast::Node* node, size_t limit = 60) { + fast::PrintOptions options; + options.pretty = false; + std::string text = fast::Print(node, options); + for (char& c : text) { + if (c == '\n') { + c = ' '; + } + } + if (text.size() > limit) { + text = text.substr(0, limit - 3) + "..."; + } + return text; +} + +void DumpTree(fast::Node* node, int depth, int* count) { + if (node == nullptr) { + return; + } + (*count)++; + std::string detail; + switch (node->kind) { + case fast::NodeKind::kIdentifier: + detail = std::string(node->Cast<fast::Identifier>()->name); + break; + case fast::NodeKind::kNumericLiteral: + case fast::NodeKind::kStringLiteral: + case fast::NodeKind::kBooleanLiteral: + case fast::NodeKind::kNullLiteral: + case fast::NodeKind::kBigIntLiteral: + case fast::NodeKind::kRegExpLiteral: + detail = Snippet(node, 40); + break; + default: + if (depth > 0 && (node->IsStatement() || node->IsExpression())) { + detail = Snippet(node); + } + break; + } + printf("%*s%s #%u%s%s\n", depth * 2, "", node->kind_name(), node->id, + detail.empty() ? "" : " ", detail.c_str()); + fast::ForEachChild( + node, [&](fast::Node* child) { DumpTree(child, depth + 1, count); }); +} + +class Shell { + public: + Shell(const Flags& flags, std::unique_ptr<ScriptRunner> runner, + std::string prelude) + : mutators_(MutatorSet::CreateDefault()), + generators_(GeneratorSet::CreateDefault()), + env_(Environment::Default()), + runner_(std::move(runner)), + prelude_(std::move(prelude)), + seed_(static_cast<uint64_t>(flags.GetInt("seed", 1))), + auto_print_(!flags.GetBool("no-auto-print", false) && + flags.GetBool("auto-print", true)) { + interactive_ = isatty(STDIN_FILENO) != 0; + } + + bool Load(const std::string& path) { + std::string source, error; + if (!ReadFileToString(path, &source, &error)) { + Error(error); + return false; + } + return SetSource(source, "load", path); + } + + bool SetSource(const std::string& source, const std::string& origin, + const std::string& detail) { + std::string error; + Lineage lineage; + lineage.origin = origin; + lineage.detail = detail; + ProgramPtr program = Program::Parse(source, lineage, &error); + if (program == nullptr) { + Error(error); + return false; + } + history_.clear(); + steps_.clear(); + current_ = program; + if (partner_ == nullptr) { + partner_ = program; + } + last_edges_.clear(); + printf("loaded %s: %zu nodes, %zu bytes\n", detail.c_str(), + program->node_count(), program->source().size()); + return true; + } + + int Loop() { + std::string line; + char buffer[4096]; + while (true) { + if (interactive_) { + fputs("redline> ", stdout); + fflush(stdout); + } + if (fgets(buffer, sizeof buffer, stdin) == nullptr) { + break; + } + line = buffer; + while (!line.empty() && (line.back() == '\n' || line.back() == '\r')) { + line.pop_back(); + } + if (!interactive_) { + printf("redline> %s\n", line.c_str()); + } + if (!Execute(line)) { + break; + } + fflush(stdout); + } + return kExitOk; + } + + private: + void Error(const std::string& message) { + printf("error: %s\n", message.c_str()); + } + + bool Require() { + if (current_ != nullptr) { + return true; + } + Error("no program loaded (load FILE, source CODE or new)"); + return false; + } + + bool RequireTarget() { + if (runner_ != nullptr) { + return true; + } + Error("no target: start the shell with --d8=PATH (or $REDLINE_D8)"); + return false; + } + + void Push(ProgramPtr next, const std::string& step) { + history_.push_back(current_); + steps_.push_back(step); + current_ = std::move(next); + } + + void ShowProgram() { + fast::PrintOptions options; + std::string text = fast::Print(current_->tree().root(), options); + fwrite(text.data(), 1, text.size(), stdout); + if (text.empty() || text.back() != '\n') { + fputc('\n', stdout); + } + } + + void AfterChange(const std::string& step) { + std::string message; + bool accepted = checker_.Accepts(current_->source(), &message); + printf("=> %s: %zu nodes, V8 %s%s%s\n", step.c_str(), + current_->node_count(), accepted ? "accepts" : "REJECTS", + accepted ? "" : ": ", accepted ? "" : message.c_str()); + if (auto_print_) { + if (!history_.empty()) { + PrintLineDiff(history_.back()->source(), current_->source()); + } else { + ShowProgram(); + } + } + } + + // --- commands --------------------------------------------------------- + + bool Execute(const std::string& line) { + std::vector<std::string> words = Split(line); + if (words.empty()) { + return true; + } + const std::string& cmd = words[0]; + if (cmd[0] == '#') { + return true; + } + if (cmd == "quit" || cmd == "exit" || cmd == "q") { + return false; + } + if (cmd == "help" || cmd == "?") { + fputs(kHelp, stdout); + } else if (cmd == "load") { + if (words.size() < 2) { + return Usage("load FILE"); + } + Load(words[1]); + if (current_ != nullptr && auto_print_) { + ShowProgram(); + } + } else if (cmd == "source") { + size_t pos = line.find("source"); + std::string code = line.substr(pos + 6); + SetSource(code, "source", "<source>"); + if (current_ != nullptr && auto_print_) { + ShowProgram(); + } + } else if (cmd == "new") { + SetSource("", "new", "<empty>"); + } else if (cmd == "save") { + if (words.size() < 2) { + return Usage("save FILE"); + } + if (!Require()) { + return true; + } + std::string error; + if (!WriteStringToFile(words[1], current_->source(), &error)) { + Error(error); + } else { + printf("saved %s (%zu bytes)\n", words[1].c_str(), + current_->source().size()); + } + } else if (cmd == "partner") { + if (words.size() < 2) { + return Usage("partner FILE|self"); + } + if (words[1] == "self") { + partner_ = current_; + printf("partner: the program itself\n"); + } else { + std::string source, error; + if (!ReadFileToString(words[1], &source, &error)) { + Error(error); + } else { + Lineage lineage; + lineage.origin = "import"; + lineage.detail = words[1]; + ProgramPtr p = Program::Parse(source, lineage, &error); + if (p == nullptr) { + Error(error); + } else { + partner_ = p; + printf("partner: %s (%zu nodes)\n", words[1].c_str(), + p->node_count()); + } + } + } + } else if (cmd == "print" || cmd == "p") { + if (Require()) { + ShowProgram(); + } + } else if (cmd == "ids") { + if (Require()) { + fast::PrintOptions options; + options.node_ids = true; + printf("%s\n", fast::Print(current_->tree().root(), options).c_str()); + } + } else if (cmd == "compact") { + if (Require()) { + fast::PrintOptions options; + options.pretty = false; + printf("%s\n", fast::Print(current_->tree().root(), options).c_str()); + } + } else if (cmd == "tree" || cmd == "t") { + if (Require()) { + Tree(words); + } + } else if (cmd == "scopes") { + if (Require()) { + std::unique_ptr<fast::Tree> copy = current_->CopyTree(); + std::unique_ptr<fast::ScopeAnalysis> analysis = + fast::ScopeAnalysis::Analyze(copy.get()); + fputs(analysis->Dump().c_str(), stdout); + } + } else if (cmd == "info") { + if (Require()) { + Info(); + } + } else if (cmd == "diff") { + if (Require()) { + if (history_.empty()) { + printf("(no previous step)\n"); + } else { + PrintLineDiff(history_.back()->source(), current_->source()); + } + } + } else if (cmd == "check" || cmd == "c") { + if (Require()) { + std::string message; + Stopwatch sw; + bool ok = checker_.Accepts(current_->source(), &message); + printf("V8 %s (%.2f ms)%s%s\n", + ok ? "accepts the program" : "REJECTS the program", + static_cast<double>(sw.ElapsedUs()) / 1000.0, ok ? "" : ": ", + message.c_str()); + } + } else if (cmd == "list" || cmd == "ls") { + List(words.size() > 1 ? words[1] : ""); + } else if (cmd == "mutate" || cmd == "m") { + if (words.size() < 2) { + return Usage("mutate NAME [SEED]"); + } + if (Require()) { + Mutate(words[1], words.size() > 2 ? ParseSeed(words[2]) : NextSeed()); + } + } else if (cmd == "generate" || cmd == "g") { + if (words.size() < 2) { + return Usage("generate NAME [SEED]"); + } + if (Require()) { + Generate(words[1], words.size() > 2 ? ParseSeed(words[2]) : NextSeed()); + } + } else if (cmd == "random" || cmd == "r") { + int n = words.size() > 1 + ? static_cast<int>(strtol(words[1].c_str(), nullptr, 10)) + : 1; + if (Require()) { + for (int i = 0; i < std::max(n, 1); i++) { + RandomMutation(NextSeed()); + } + } + } else if (cmd == "reduce") { + if (words.size() < 2) { + return Usage( + "reduce NAME[,NAME..]|default|all " + "[edges|all-edges|output|fail|crash]"); + } + if (Require() && RequireTarget()) { + Reduce(words[1], words.size() > 2 ? words[2] : "edges"); + } + } else if (cmd == "accept") { + if (Require() && RequireTarget()) { + int runs = words.size() > 1 + ? static_cast<int>(strtol(words[1].c_str(), nullptr, 10)) + : 10; + Accept(std::max(2, runs)); + } + } else if (cmd == "seed") { + if (words.size() > 1) { + seed_ = ParseSeed(words[1]); + } + printf("next seed: %llu\n", static_cast<unsigned long long>(seed_)); + } else if (cmd == "rounds") { + if (words.size() > 1) { + rounds_ = std::max( + 1, static_cast<int>(strtol(words[1].c_str(), nullptr, 10))); + } + printf("rounds: %d\n", rounds_); + } else if (cmd == "run" || cmd == "x") { + if (Require() && RequireTarget()) { + Run(words.size() > 1 && words[1] == "verbose"); + } + } else if (cmd == "undo" || cmd == "u") { + if (history_.empty()) { + printf("(nothing to undo)\n"); + } else { + current_ = history_.back(); + history_.pop_back(); + printf("undid %s; %zu nodes\n", steps_.back().c_str(), + current_->node_count()); + steps_.pop_back(); + if (auto_print_) { + ShowProgram(); + } + } + } else if (cmd == "reset") { + if (!history_.empty()) { + current_ = history_.front(); + history_.clear(); + steps_.clear(); + } + if (current_ != nullptr) { + printf("back to the loaded program (%zu nodes)\n", + current_->node_count()); + } + } else if (cmd == "history" || cmd == "h") { + for (size_t i = 0; i < steps_.size(); i++) { + printf(" %zu. %s (%zu nodes)\n", i + 1, steps_[i].c_str(), + i + 1 < history_.size() ? history_[i + 1]->node_count() + : current_->node_count()); + } + if (steps_.empty()) { + printf(" (no steps yet)\n"); + } + } else if (cmd == "stats") { + fputs(FormatStatsTable("mutators", mutators_->Components()).c_str(), + stdout); + fputs(FormatStatsTable("reducers", minimizer_.Components()).c_str(), + stdout); + fputs(FormatStatsTable("generators", generators_->Components()).c_str(), + stdout); + } else if (cmd == "auto") { + if (words.size() > 1) { + auto_print_ = words[1] != "off"; + } + printf("auto print: %s\n", auto_print_ ? "on" : "off"); + } else { + Error("unknown command '" + cmd + "' (try help)"); + } + return true; + } + + bool Usage(const char* usage) { + printf("usage: %s\n", usage); + return true; + } + + uint64_t NextSeed() { return seed_++; } + static uint64_t ParseSeed(const std::string& word) { + return strtoull(word.c_str(), nullptr, 10); + } + + void Tree(const std::vector<std::string>& words) { + if (words.size() > 1) { + uint32_t id = + static_cast<uint32_t>(strtoul(words[1].c_str(), nullptr, 10)); + fast::Node* node = current_->tree().FindNode(id); + if (node == nullptr) { + Error("no node #" + words[1] + " (see `ids`)"); + return; + } + int count = 0; + DumpTree(node, 0, &count); + printf("(%d nodes in the subtree)\n", count); + return; + } + int count = 0; + DumpTree(current_->tree().root(), 0, &count); + printf("(%d nodes)\n", count); + } + + void Info() { + std::string message; + bool ok = checker_.Accepts(current_->source(), &message); + const Lineage& l = current_->lineage(); + printf("nodes: %zu bytes: %zu V8: %s%s%s\n", current_->node_count(), + current_->source().size(), ok ? "accepts" : "REJECTS", + ok ? "" : " - ", ok ? "" : message.c_str()); + printf("origin: %s%s%s generation: %d steps: %zu\n", l.origin.c_str(), + l.detail.empty() ? "" : " ", l.detail.c_str(), l.generation, + steps_.size()); + if (!last_edges_.empty()) { + printf("last run: %zu edges\n", last_edges_.size()); + } + std::unique_ptr<fast::Tree> copy = current_->CopyTree(); + std::unique_ptr<fast::ScopeAnalysis> analysis = + fast::ScopeAnalysis::Analyze(copy.get()); + printf("scopes: %zu bindings: %zu unresolved: %zu\n", + analysis->scopes().size(), analysis->bindings().size(), + analysis->unresolved().size()); + } + + void List(const std::string& what) { + if (what.empty() || what == "mutators") { + printf("mutators:\n"); + for (const auto& m : mutators_->all()) { + printf(" %-14s w=%-4g %s%s\n", m->name().c_str(), m->weight(), + std::string(m->description()).c_str(), + m->needs_partner() ? " [uses partner]" : ""); + } + } + if (what.empty() || what == "generators") { + printf("generators:\n"); + for (const auto& g : generators_->all()) { + printf(" %-18s w=%-4g %s\n", g->name().c_str(), g->weight(), + std::string(g->description()).c_str()); + } + } + if (what.empty() || what == "reducers") { + printf("reducers:\n"); + for (const auto& r : minimizer_.reducers()) { + printf(" %-14s %s\n", r->name().c_str(), + std::string(r->description()).c_str()); + } + } + if (what.empty() || what == "schedulers" || what == "strategies") { + printf( + "selection strategies (fuzz --config, \"selection\" block; fuzz " + "--scheduler=NAME for seeds):\n"); + fputs(SelectorRegistry<const Program>::Instance() + .Help("seeds / partners") + .c_str(), + stdout); + fputs(SelectorRegistry<Mutator>::Instance().Help("mutators").c_str(), + stdout); + fputs(SelectorRegistry<Generator>::Instance().Help("generators").c_str(), + stdout); + } + } + + void Mutate(const std::string& name, uint64_t seed) { + Mutator* mutator = mutators_->Find(name); + if (mutator == nullptr) { + Error("unknown mutator '" + name + "' (list mutators)"); + return; + } + Random rng(seed); + std::string detail; + Stopwatch sw; + std::unique_ptr<fast::Tree> tree = + ApplyMutation(*mutator, *current_, partner_, rng, env_, *generators_, + rounds_, &detail); + uint64_t us = sw.ElapsedUs(); + if (tree == nullptr) { + printf("%s (seed %llu): nothing to do on this program\n", name.c_str(), + static_cast<unsigned long long>(seed)); + return; + } + Lineage lineage = current_->lineage(); + lineage.origin = name; + lineage.detail = detail; + lineage.generation++; + Push(Program::FromTree(std::move(tree), lineage), + StringPrintf("%s seed=%llu: %s", name.c_str(), + static_cast<unsigned long long>(seed), detail.c_str())); + AfterChange(StringPrintf("%s (seed %llu, %.2f ms): %s", name.c_str(), + static_cast<unsigned long long>(seed), + static_cast<double>(us) / 1000.0, detail.c_str())); + } + + void Generate(const std::string& name, uint64_t seed) { + Generator* generator = generators_->Find(name); + if (generator == nullptr) { + Error("unknown generator '" + name + "' (list generators)"); + return; + } + Random rng(seed); + std::unique_ptr<fast::Tree> tree = current_->CopyTree(); + Builder builder(tree.get(), &rng); + std::vector<fast::Statement*> out; + Builder::Slot slot; + bool generated = false; + for (int attempt = 0; attempt < 10 && !generated; attempt++) { + slot = builder.RandomInsertionSlot(); + if (!slot.valid()) { + break; + } + GenContext ctx = MakeGenContext(builder, slot, *generators_, env_); + if (!generator->Applicable(ctx)) { + continue; + } + ctx.out = &out; + generator->stats().invocations++; + if (generator->Generate(ctx, &out) && !out.empty()) { + generator->stats().produced++; + generated = true; + } else { + out.clear(); + } + } + if (!generated) { + printf("%s (seed %llu): not applicable here\n", name.c_str(), + static_cast<unsigned long long>(seed)); + return; + } + builder.InsertAll(slot, out); + Lineage lineage = current_->lineage(); + lineage.origin = "generate"; + lineage.detail = name; + lineage.generation++; + Push(Program::FromTree(std::move(tree), lineage), + StringPrintf("generate %s seed=%llu", name.c_str(), + static_cast<unsigned long long>(seed))); + AfterChange( + StringPrintf("%s (seed %llu): inserted %zu statement(s)", name.c_str(), + static_cast<unsigned long long>(seed), out.size())); + } + + void RandomMutation(uint64_t seed) { + Random rng(seed); + Mutator* mutator = mutators_->Pick(rng, partner_ != nullptr); + if (mutator == nullptr) { + return; + } + Mutate(mutator->name(), seed); + } + + bool Exec(const std::string& source, Execution* execution, + uint64_t timeout_us = 0) { + std::string script = prelude_.empty() ? source : prelude_ + "\n" + source; + std::string error; + if (timeout_us == 0) { + timeout_us = runner_->options().timeout_us; + } + if (!runner_->RunWithoutEvaluation(script, timeout_us, execution, &error)) { + Error("execution failed: " + error); + return false; + } + return true; + } + + static const char* OutcomeName(Outcome outcome) { + switch (outcome) { + case Outcome::kSucceeded: + return "succeeded"; + case Outcome::kFailed: + return "failed (uncaught exception)"; + case Outcome::kCrashed: + return "CRASHED"; + case Outcome::kTimedOut: + return "timed out"; + } + return "?"; + } + + void Run(bool verbose) { + Execution execution; + if (!Exec(current_->source(), &execution)) { + return; + } + std::vector<uint32_t> edges = runner_->coverage().CurrentEdges(); + std::vector<uint32_t> gained, lost; + std::set_difference(edges.begin(), edges.end(), last_edges_.begin(), + last_edges_.end(), std::back_inserter(gained)); + std::set_difference(last_edges_.begin(), last_edges_.end(), edges.begin(), + edges.end(), std::back_inserter(lost)); + printf( + "%s in %.2f ms, exit %d%s; %zu edges", OutcomeName(execution.outcome), + static_cast<double>(execution.exec_time_us) / 1000.0, + execution.exit_code, + execution.signal ? StringPrintf(", signal %d", execution.signal).c_str() + : "", + edges.size()); + if (!last_edges_.empty()) { + printf(" (+%zu new, -%zu gone since the previous run)", gained.size(), + lost.size()); + } + printf("\n"); + if (verbose || execution.outcome != Outcome::kSucceeded) { + std::vector<std::string> out = Lines(execution.stdout_output); + std::vector<std::string> err = Lines(execution.stderr_output); + for (size_t i = 0; i < out.size() && i < 20; i++) { + printf(" stdout: %s\n", out[i].c_str()); + } + for (size_t i = 0; i < err.size() && i < 20; i++) { + printf(" stderr: %s\n", err[i].c_str()); + } + if (!execution.fuzzout.empty()) { + printf(" fuzzout: %s\n", Lines(execution.fuzzout)[0].c_str()); + } + } + last_edges_ = std::move(edges); + } + + // The Accept stage alone: runs the program `runs` times and splits its + // edges into deterministic ones (set by every run) and flaky ones (set by + // some runs only). Relative to the previous program of the history, the + // deterministic edges it gained are what the fuzzer's default criterion + // (`new-edges`) would accept and keep through minimization. + void Accept(int runs) { + std::vector<uint32_t> all, every; + for (int i = 0; i < runs; i++) { + Execution execution; + if (!Exec(current_->source(), &execution)) { + return; + } + if (!execution.succeeded()) { + printf("run %d: %s; only successful runs count as coverage\n", i + 1, + OutcomeName(execution.outcome)); + return; + } + std::vector<uint32_t> edges = runner_->coverage().CurrentEdges(); + std::vector<uint32_t> merged, common; + std::set_union(all.begin(), all.end(), edges.begin(), edges.end(), + std::back_inserter(merged)); + all.swap(merged); + if (i == 0) { + every = edges; + } else { + std::set_intersection(every.begin(), every.end(), edges.begin(), + edges.end(), std::back_inserter(common)); + every.swap(common); + } + } + printf("%d runs: %zu deterministic edges, %zu flaky\n", runs, every.size(), + all.size() - every.size()); + if (history_.empty()) { + printf( + "(no previous program: load or mutate one to see what the step " + "gained)\n"); + return; + } + std::vector<uint8_t> seen(runner_->coverage().num_edges() + 1, 0); + for (int i = 0; i < runs; i++) { + Execution run; + if (!Exec(history_.back()->source(), &run)) { + return; + } + for (uint32_t e : runner_->coverage().CurrentEdges()) { + if (e < seen.size()) { + seen[e] = 1; + } + } + } + size_t gained = 0; + for (uint32_t e : every) { + gained += (e >= seen.size() || !seen[e]) ? 1 : 0; + } + printf( + "vs the previous program: %zu deterministic edges gained -> %s by " + "`new-edges`\n", + gained, gained > 0 ? "accepted" : "rejected"); + } + + void Reduce(const std::string& which, const std::string& oracle_name) { + std::vector<Reducer*> reducers; + if (which == "all") { + for (const auto& r : minimizer_.reducers()) { + reducers.push_back(r.get()); + } + } else if (which == "default") { + for (std::string_view name : Minimizer::DefaultOrder()) { + reducers.push_back(minimizer_.Find(name)); + } + } else { + for (const std::string& name : SplitComma(which)) { + Reducer* r = minimizer_.Find(name); + if (r == nullptr) { + Error("unknown reducer '" + name + "' (list reducers)"); + return; + } + reducers.push_back(r); + } + } + // Establish the property. + Execution first; + if (!Exec(current_->source(), &first)) { + return; + } + uint64_t probe_timeout_us = + std::min(std::max<uint64_t>(5 * first.exec_time_us + 20'000, 50'000), + runner_->options().timeout_us); + std::vector<uint32_t> edges; + MinimizationOracle oracle; + if (oracle_name == "edges" || oracle_name == "all-edges") { + if (!first.succeeded()) { + Error( + "the program does not run successfully; use the output/fail/crash " + "oracle"); + return; + } + edges = runner_->coverage().CurrentEdges(); + // Settle over two re-runs. + for (int i = 0; i < 2; i++) { + Execution again; + if (!Exec(current_->source(), &again) || !again.succeeded()) { + return; + } + std::vector<uint32_t> missing = runner_->coverage().MissingEdges(edges); + std::vector<uint32_t> kept; + std::set_difference(edges.begin(), edges.end(), missing.begin(), + missing.end(), std::back_inserter(kept)); + edges.swap(kept); + } + size_t settled = edges.size(); + if (oracle_name == "edges" && !history_.empty()) { + // Relative to the previous program of the history: the edges the + // last step(s) gained, exactly what the fuzzer would preserve. + std::vector<uint8_t> seen(runner_->coverage().num_edges() + 1, 0); + for (int i = 0; i < 3; i++) { + Execution run; + if (!Exec(history_.back()->source(), &run)) { + return; + } + for (uint32_t e : runner_->coverage().CurrentEdges()) { + if (e < seen.size()) { + seen[e] = 1; + } + } + } + std::vector<uint32_t> remaining; + for (uint32_t e : edges) { + if (e >= seen.size() || !seen[e]) { + remaining.push_back(e); + } + } + edges.swap(remaining); + printf( + "preserving %zu edges: the %zu settled edges of the program minus " + "those of the " + "previous program\n", + edges.size(), settled); + if (edges.empty()) { + Error( + "the last step added no edges; nothing to preserve (try " + "all-edges or output)"); + return; + } + } else { + printf("preserving all %zu settled edges of the program\n", + edges.size()); + } + oracle = [&](const std::string& candidate) { + Execution e; + return Exec(candidate, &e, probe_timeout_us) && e.succeeded() && + runner_->coverage().AllEdgesSet(edges); + }; + } else if (oracle_name == "output") { + std::string expected = first.stdout_output; + Outcome outcome = first.outcome; + printf("preserving the outcome (%s) and %zu bytes of stdout\n", + OutcomeName(outcome), expected.size()); + oracle = [&, expected, outcome](const std::string& candidate) { + Execution e; + return Exec(candidate, &e, probe_timeout_us) && e.outcome == outcome && + e.stdout_output == expected; + }; + } else if (oracle_name == "fail") { + if (first.outcome != Outcome::kFailed) { + Error("the program does not fail"); + return; + } + std::string signature = first.ExceptionSignature(); + printf("preserving the failure `%s`\n", + signature.empty() ? "(no exception message captured)" + : signature.c_str()); + oracle = [&, signature](const std::string& candidate) { + Execution e; + return Exec(candidate, &e, probe_timeout_us) && + e.outcome == Outcome::kFailed && + e.ExceptionSignature() == signature; + }; + } else if (oracle_name == "crash") { + if (!first.crashed()) { + Error("the program does not crash"); + return; + } + oracle = [&](const std::string& candidate) { + Execution e; + return Exec(candidate, &e, probe_timeout_us) && e.crashed(); + }; + } else { + Error("unknown oracle '" + oracle_name + + "' (edges, all-edges, output, fail, crash)"); + return; + } + std::unique_ptr<fast::Tree> work = current_->CopyTree(); + MinimizationResult result = + minimizer_.MinimizeWith(reducers, work.get(), oracle, &checker_); + if (result.accepted == 0) { + printf("%s: nothing could be removed (%d tests, %.1f s)\n", which.c_str(), + result.tests, static_cast<double>(result.time_us) / 1e6); + return; + } + Lineage lineage = current_->lineage(); + lineage.origin = "reduce"; + lineage.detail = which; + Push(Program::FromTree(std::move(work), lineage), + StringPrintf("reduce %s (%s oracle)", which.c_str(), + oracle_name.c_str())); + AfterChange(StringPrintf( + "%s: %zu -> %zu nodes, %d tests (%d accepted) in %.1f s%s", + which.c_str(), result.nodes_before, result.nodes_after, result.tests, + result.accepted, static_cast<double>(result.time_us) / 1e6, + result.budget_exhausted ? " (budget exhausted)" : "")); + } + + std::unique_ptr<MutatorSet> mutators_; + std::unique_ptr<GeneratorSet> generators_; + const Environment& env_; + Minimizer minimizer_; + SyntaxChecker checker_; + std::unique_ptr<ScriptRunner> runner_; + std::string prelude_; + uint64_t seed_; + int rounds_ = 1; + bool auto_print_; + bool interactive_ = false; + ProgramPtr current_; + ProgramPtr partner_; + std::vector<ProgramPtr> history_; + std::vector<std::string> steps_; + std::vector<uint32_t> last_edges_; +}; + +int Run(const Flags& flags) { + if (flags.positional().size() > 1) { + fputs(kUsage, stderr); + return kExitUsage; + } + std::string error; + if (!InitializeV8(flags.GetString( + "v8-flags", + "--allow-natives-syntax --js-staging --js-decorators"), + &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + std::string prelude; + std::string prelude_flag = flags.GetString("prelude"); + if (prelude_flag.empty()) { + prelude = std::string(DefaultPrelude()); + } else if (prelude_flag != "none" && + !ReadFileToString(prelude_flag, &prelude, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + std::unique_ptr<ScriptRunner> runner; + if (flags.Has("d8") || getenv("REDLINE_D8") != nullptr) { + TargetOptions target; + if (!TargetOptions::FromFlags(flags, &target, &error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitUsage; + } + runner = ScriptRunner::Create(target, 0, &error); + if (runner == nullptr || !runner->Initialize(&error)) { + REDLINE_ERROR(kLog, "%s", error.c_str()); + return kExitFailure; + } + printf("target: %s (%u edges)\n", target.executable.c_str(), + runner->coverage().num_edges()); + } else { + printf("no --d8: run/reduce are disabled\n"); + } + Shell shell(flags, std::move(runner), std::move(prelude)); + if (!flags.positional().empty() && !shell.Load(flags.positional()[0])) { + return kExitFailure; + } + if (isatty(STDIN_FILENO)) { + printf("type help for the commands\n"); + } + return shell.Loop(); +} + +} // namespace + +const Command kShellCommand = { + "shell", + "Interactive workbench: inspect, mutate, generate, reduce, run one program", + kUsage, + Run, +}; + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/adaptive_selector.h b/deps/v8/experimental/redline/core/adaptive_selector.h new file mode 100644 index 000000000000..b98835e14fdd --- /dev/null +++ b/deps/v8/experimental/redline/core/adaptive_selector.h @@ -0,0 +1,298 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_ADAPTIVE_SELECTOR_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_ADAPTIVE_SELECTOR_H_ + +#include <algorithm> +#include <atomic> +#include <cstdint> +#include <functional> +#include <mutex> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/core/selection.h" + +namespace redline { + +// A weighted draw whose weights follow the candidates' recent yield. Every +// `window_sec` seconds (or every `window` picks, if set), the strategy reads +// each candidate's ComponentStats, turns the increments since the previous +// update into a yield (with `reward: edges`, the default: new edges per target +// execution spent; with `reward: adds`: corpus adds per executed result), +// smooths it with `prior_executions` pseudo-executions at the overall rate, +// folds it into an exponential moving average (`ema`), and sets +// +// weight = base * clamp(rate / mean rate, min_factor, max_factor) +// +// so productive candidates are drawn more often while every enabled one keeps +// at least `min_factor` of its base weight (the yield of a candidate changes as +// the corpus grows, so none is ever starved). The base weights are the +// built-in ones, overridden by `weights` like the "weighted" strategy. +// +// Thread safety: shared by all workers; the state is guarded by a mutex (one +// pick per mutation, negligible next to an execution). +// +// T must provide name(), weight() and stats() (a ComponentStats). +template <typename T> +class AdaptiveSelector final : public Selector<T> { + public: + using typename Selector<T>::Candidates; + using typename Selector<T>::Filter; + using Selector<T>::kNoChoice; + + static constexpr std::string_view kName = "adaptive"; + + struct Settings { + double window = 0; // picks between updates; 0: off + double window_sec = 600; // seconds between updates; 0: off + bool reward_edges = + true; // edges per spent execution (else adds per execution) + double ema = 0.3; + double prior_executions = 30000; + double min_factor = 0.25; + double max_factor = 4.0; + }; + + static std::vector<ParamSpec> Specs() { + return { + {"weights", ParamSpec::Type::kObject, "{}", + "{\"Name\": number, ...}: overrides the built-in base weights, 0 " + "disables"}, + {"window", ParamSpec::Type::kNumber, "0", + "picks between two weight updates (0: off)"}, + {"window_sec", ParamSpec::Type::kNumber, "600", + "seconds between two weight updates (0: off)"}, + {"reward", ParamSpec::Type::kString, "\"edges\"", + "\"edges\": new edges per execution spent; \"adds\": corpus adds per " + "execution"}, + {"ema", ParamSpec::Type::kNumber, "0.3", + "weight of the newest window in the moving average"}, + {"prior_executions", ParamSpec::Type::kNumber, "30000", + "pseudo-executions at the overall rate added to every candidate's " + "window"}, + {"min_factor", ParamSpec::Type::kNumber, "0.25", + "lowest multiple of the base weight"}, + {"max_factor", ParamSpec::Type::kNumber, "4", + "highest multiple of the base weight"}, + }; + } + + static Settings ReadParams(const JsonValue& params) { + Settings p; + p.window = params.GetNumber("window", p.window); + p.window_sec = params.GetNumber("window_sec", p.window_sec); + p.reward_edges = params.GetString("reward", "edges") != "adds"; + p.ema = params.GetNumber("ema", p.ema); + p.prior_executions = + params.GetNumber("prior_executions", p.prior_executions); + p.min_factor = params.GetNumber("min_factor", p.min_factor); + p.max_factor = params.GetNumber("max_factor", p.max_factor); + return p; + } + + static bool Validate(const Settings& p, std::string* error) { + if (p.window < 0 || p.window_sec < 0 || + (p.window == 0 && p.window_sec == 0) || p.ema <= 0 || p.ema > 1 || + p.prior_executions < 0 || p.min_factor <= 0 || + p.max_factor < p.min_factor) { + *error = + "need window >= 0, window_sec >= 0 (not both 0), 0 < ema <= 1, " + "prior_executions >= 0, " + "0 < min_factor <= max_factor"; + return false; + } + return true; + } + + AdaptiveSelector(std::string kind, + std::vector<std::pair<std::string, double>> overrides, + const Settings& params) + : kind_(std::move(kind)), + overrides_(std::move(overrides)), + params_(params), + last_update_us_(NowUs()) {} + + // Test hook: replaces the monotonic clock (microseconds). + void SetClockForTesting(std::function<uint64_t()> clock) { + std::scoped_lock<std::mutex> lock(mutex_); + clock_ = std::move(clock); + last_update_us_ = NowUs(); + } + + std::string_view name() const override { return kName; } + + bool Initialize(const Candidates& candidates, std::string* error) override { + std::scoped_lock<std::mutex> lock(mutex_); + candidates_ = candidates; + base_.clear(); + for (const T* c : candidates) { + base_.push_back(c->weight()); + } + for (const auto& [name, weight] : overrides_) { + if (!SetBaseLocked(name, weight)) { + *error = "unknown " + kind_ + " in weights: " + name; + return false; + } + } + factor_.assign(candidates.size(), 1.0); + rate_.assign(candidates.size(), -1.0); // no estimate yet + last_cost_.assign(candidates.size(), 0); + last_gain_.assign(candidates.size(), 0); + return true; + } + + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& eligible) override { + std::scoped_lock<std::mutex> lock(mutex_); + ++picks_since_update_; + const bool picks_due = + params_.window > 0 && + picks_since_update_ >= static_cast<uint64_t>(params_.window); + const bool time_due = params_.window_sec > 0 && + NowUs() - last_update_us_ >= + static_cast<uint64_t>(params_.window_sec * 1e6); + if (picks_due || time_due) { + UpdateLocked(); + } + std::vector<double> weights(candidates.size(), 0.0); + double total = 0; + for (size_t i = 0; i < candidates.size() && i < base_.size(); i++) { + if (base_[i] <= 0 || !eligible(*candidates[i])) { + continue; + } + weights[i] = base_[i] * factor_[i]; + total += weights[i]; + } + if (total <= 0) { + return kNoChoice; + } + return rng.Weighted(weights); + } + + double WeightOf(const T& candidate) const override { + std::scoped_lock<std::mutex> lock(mutex_); + for (size_t i = 0; i < candidates_.size(); i++) { + if (candidates_[i] == &candidate) { + return base_[i] * factor_[i]; + } + } + return 0.0; + } + + bool SetWeight(std::string_view candidate_name, double weight) override { + std::scoped_lock<std::mutex> lock(mutex_); + return SetBaseLocked(candidate_name, weight); + } + + JsonObject Params() const override { + std::scoped_lock<std::mutex> lock(mutex_); + JsonObject weights; + for (size_t i = 0; i < candidates_.size(); i++) { + weights.Add(candidates_[i]->name(), base_[i]); + } + JsonObject params; + params.AddRaw("weights", weights.ToString()); + params.Add("window", params_.window).Add("window_sec", params_.window_sec); + params.Add("reward", params_.reward_edges ? "edges" : "adds") + .Add("ema", params_.ema); + params.Add("prior_executions", params_.prior_executions); + params.Add("min_factor", params_.min_factor) + .Add("max_factor", params_.max_factor); + return params; + } + + private: + uint64_t NowUs() const { return clock_ ? clock_() : MonotonicNowUs(); } + + bool SetBaseLocked(std::string_view candidate_name, double weight) { + for (size_t i = 0; i < candidates_.size(); i++) { + if (candidates_[i]->name() == candidate_name) { + base_[i] = weight; + return true; + } + } + return false; + } + + // The yield of a candidate over a window is gain / cost. With + // reward_edges: gain = new edges of its corpus programs, cost = every + // target execution it caused (`spent`, or `executed` if nothing was + // spent). Otherwise: gain = corpus adds, cost = executed results. + void UpdateLocked() { + picks_since_update_ = 0; + last_update_us_ = NowUs(); + const size_t n = candidates_.size(); + std::vector<uint64_t> cost(n), gain(n); + uint64_t total_cost = 0, total_gain = 0; + for (size_t i = 0; i < n; i++) { + const auto& stats = candidates_[i]->stats(); + const uint64_t executed = stats.executed.load(std::memory_order_relaxed); + const uint64_t spent = stats.spent.load(std::memory_order_relaxed); + uint64_t c = executed; + uint64_t g = stats.interesting.load(std::memory_order_relaxed); + if (params_.reward_edges) { + c = spent > 0 ? spent : executed; + g = stats.new_edges.load(std::memory_order_relaxed); + } + cost[i] = c - std::min(c, last_cost_[i]); + gain[i] = g - std::min(g, last_gain_[i]); + last_cost_[i] = c; + last_gain_[i] = g; + if (base_[i] > 0) { + total_cost += cost[i]; + total_gain += gain[i]; + } + } + if (total_cost == 0) { + return; + } + const double overall = + static_cast<double>(total_gain) / static_cast<double>(total_cost); + double sum = 0; + int active = 0; + for (size_t i = 0; i < n; i++) { + if (base_[i] <= 0) { + continue; + } + double window_rate = + (static_cast<double>(gain[i]) + params_.prior_executions * overall) / + (static_cast<double>(cost[i]) + params_.prior_executions); + rate_[i] = rate_[i] < 0 + ? window_rate + : (1 - params_.ema) * rate_[i] + params_.ema * window_rate; + sum += rate_[i]; + active++; + } + const double mean = active > 0 ? sum / active : 0; + for (size_t i = 0; i < n; i++) { + factor_[i] = (base_[i] <= 0 || mean <= 0) + ? 1.0 + : std::clamp(rate_[i] / mean, params_.min_factor, + params_.max_factor); + } + } + + std::string kind_; + std::vector<std::pair<std::string, double>> overrides_; + Settings params_; + mutable std::mutex mutex_; + Candidates candidates_; + std::vector<double> base_; + std::vector<double> factor_; + std::vector<double> rate_; + std::vector<uint64_t> last_cost_; + std::vector<uint64_t> last_gain_; + uint64_t picks_since_update_ = 0; + std::function<uint64_t()> clock_; // empty: MonotonicNowUs + uint64_t last_update_us_ = 0; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_ADAPTIVE_SELECTOR_H_ diff --git a/deps/v8/experimental/redline/core/ast_builder.cc b/deps/v8/experimental/redline/core/ast_builder.cc new file mode 100644 index 000000000000..c94361515e0a --- /dev/null +++ b/deps/v8/experimental/redline/core/ast_builder.cc @@ -0,0 +1,551 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/ast_builder.h" + +#include <string> + +namespace redline { +namespace mk { + +using namespace fast; // NOLINT(build/namespaces) + +Identifier* Id(Tree* t, std::string_view name) { + Identifier* id = t->New<Identifier>(); + id->name = t->Intern(name); + return id; +} + +NumericLiteral* Num(Tree* t, double value) { + NumericLiteral* n = t->New<NumericLiteral>(); + n->value = value; + return n; +} + +StringLiteral* Str(Tree* t, std::string_view value) { + StringLiteral* s = t->New<StringLiteral>(); + s->value = std::string(value); + return s; +} + +BooleanLiteral* Bool(Tree* t, bool value) { + BooleanLiteral* b = t->New<BooleanLiteral>(); + b->value = value; + return b; +} + +NullLiteral* Null(Tree* t) { return t->New<NullLiteral>(); } + +Identifier* Undefined(Tree* t) { return Id(t, "undefined"); } + +BigIntLiteral* BigInt(Tree* t, std::string_view digits) { + BigIntLiteral* b = t->New<BigIntLiteral>(); + b->raw = t->Intern(std::string(digits) + "n"); + return b; +} + +RegExpLiteral* RegExp(Tree* t, std::string_view pattern, + std::string_view flags) { + RegExpLiteral* r = t->New<RegExpLiteral>(); + r->pattern = t->Intern(pattern); + r->regexp_flags = t->Intern(flags); + return r; +} + +ThisExpression* This(Tree* t) { return t->New<ThisExpression>(); } + +MetaProperty* NewTarget(Tree* t) { + MetaProperty* m = t->New<MetaProperty>(); + m->meta_kind = MetaPropertyKind::kNewTarget; + return m; +} + +TemplateLiteral* Template(Tree* t, std::vector<std::string_view> strings, + std::vector<Expression*> expressions) { + TemplateLiteral* tl = t->New<TemplateLiteral>(); + for (size_t i = 0; i < strings.size(); i++) { + TemplateElement* e = t->New<TemplateElement>(); + e->raw = t->Intern(strings[i]); + e->cooked = std::string(strings[i]); + e->tail = i + 1 == strings.size(); + tl->quasis.push_back(e); + } + tl->expressions = std::move(expressions); + return tl; +} + +ArrayExpression* Array(Tree* t, std::vector<Expression*> elements) { + ArrayExpression* a = t->New<ArrayExpression>(); + a->elements = std::move(elements); + return a; +} + +ObjectExpression* Object(Tree* t, std::vector<Node*> properties) { + ObjectExpression* o = t->New<ObjectExpression>(); + o->properties = std::move(properties); + return o; +} + +Property* Prop(Tree* t, std::string_view key, Expression* value) { + Property* p = t->New<Property>(); + p->key = Id(t, key); + p->value = value; + return p; +} + +Property* Prop(Tree* t, Expression* key, Expression* value, bool computed) { + Property* p = t->New<Property>(); + p->key = key; + p->value = value; + p->computed = computed; + return p; +} + +Property* Accessor(Tree* t, std::string_view key, FunctionExpression* fn, + bool getter) { + Property* p = Prop(t, key, fn); + p->property_kind = getter ? PropertyKind::kGet : PropertyKind::kSet; + return p; +} + +Property* Method(Tree* t, std::string_view key, FunctionExpression* fn) { + Property* p = Prop(t, key, fn); + p->method = true; + return p; +} + +SpreadElement* Spread(Tree* t, Expression* argument) { + SpreadElement* s = t->New<SpreadElement>(); + s->argument = argument; + return s; +} + +UnaryExpression* Unary(Tree* t, UnaryOp op, Expression* argument) { + UnaryExpression* u = t->New<UnaryExpression>(); + u->op = op; + u->argument = argument; + return u; +} + +UpdateExpression* Update(Tree* t, UpdateOp op, bool prefix, + Expression* argument) { + UpdateExpression* u = t->New<UpdateExpression>(); + u->op = op; + u->prefix = prefix; + u->argument = argument; + return u; +} + +BinaryExpression* Binary(Tree* t, BinaryOp op, Expression* left, + Expression* right) { + BinaryExpression* b = t->New<BinaryExpression>(); + b->op = op; + b->left = left; + b->right = right; + return b; +} + +LogicalExpression* Logical(Tree* t, LogicalOp op, Expression* left, + Expression* right) { + LogicalExpression* l = t->New<LogicalExpression>(); + l->op = op; + l->left = left; + l->right = right; + return l; +} + +AssignmentExpression* Assign(Tree* t, Expression* target, Expression* value, + AssignOp op) { + AssignmentExpression* a = t->New<AssignmentExpression>(); + a->op = op; + a->left = target; + a->right = value; + return a; +} + +ConditionalExpression* Cond(Tree* t, Expression* test, Expression* consequent, + Expression* alternate) { + ConditionalExpression* c = t->New<ConditionalExpression>(); + c->test = test; + c->consequent = consequent; + c->alternate = alternate; + return c; +} + +SequenceExpression* Seq(Tree* t, std::vector<Expression*> expressions) { + SequenceExpression* s = t->New<SequenceExpression>(); + s->expressions = std::move(expressions); + return s; +} + +MemberExpression* Member(Tree* t, Expression* object, std::string_view name) { + MemberExpression* m = t->New<MemberExpression>(); + m->object = object; + m->property = Id(t, name); + return m; +} + +MemberExpression* Index(Tree* t, Expression* object, Expression* index) { + MemberExpression* m = t->New<MemberExpression>(); + m->object = object; + m->property = index; + m->computed = true; + return m; +} + +CallExpression* Call(Tree* t, Expression* callee, + std::vector<Expression*> args) { + CallExpression* c = t->New<CallExpression>(); + c->callee = callee; + c->arguments = std::move(args); + return c; +} + +CallExpression* CallMethod(Tree* t, Expression* object, std::string_view name, + std::vector<Expression*> args) { + return Call(t, Member(t, object, name), std::move(args)); +} + +NewExpression* New(Tree* t, Expression* callee, std::vector<Expression*> args) { + NewExpression* n = t->New<NewExpression>(); + n->callee = callee; + n->arguments = std::move(args); + return n; +} + +NativeCallExpression* Native(Tree* t, std::string_view name, + std::vector<Expression*> args) { + NativeCallExpression* n = t->New<NativeCallExpression>(); + n->name = t->Intern(name); + n->arguments = std::move(args); + return n; +} + +AwaitExpression* Await(Tree* t, Expression* argument) { + AwaitExpression* a = t->New<AwaitExpression>(); + a->argument = argument; + return a; +} + +YieldExpression* Yield(Tree* t, Expression* argument, bool delegate) { + YieldExpression* y = t->New<YieldExpression>(); + y->argument = argument; + y->delegate = delegate; + return y; +} + +ChainExpression* Chain(Tree* t, Expression* expression) { + ChainExpression* c = t->New<ChainExpression>(); + c->expression = expression; + return c; +} + +namespace { + +void FillFunction(Tree* t, FunctionData* fn, std::string_view name, + std::vector<std::string_view>& params, + std::vector<Statement*>* body, bool is_async, + bool is_generator) { + if (!name.empty()) { + fn->name = Id(t, name); + } + for (std::string_view param : params) { + fn->params.push_back(Id(t, param)); + } + if (body != nullptr) { + fn->body = Block(t, std::move(*body)); + } + fn->is_async = is_async; + fn->is_generator = is_generator; +} + +} // namespace + +FunctionExpression* Function(Tree* t, std::string_view name, + std::vector<std::string_view> params, + std::vector<Statement*> body, bool is_async, + bool is_generator) { + FunctionExpression* fn = t->New<FunctionExpression>(); + FillFunction(t, fn, name, params, &body, is_async, is_generator); + return fn; +} + +ArrowFunctionExpression* Arrow(Tree* t, std::vector<std::string_view> params, + std::vector<Statement*> body, bool is_async) { + ArrowFunctionExpression* fn = t->New<ArrowFunctionExpression>(); + FillFunction(t, fn, {}, params, &body, is_async, false); + fn->is_arrow = true; + return fn; +} + +ArrowFunctionExpression* ArrowExpr(Tree* t, + std::vector<std::string_view> params, + Expression* body, bool is_async) { + ArrowFunctionExpression* fn = t->New<ArrowFunctionExpression>(); + FillFunction(t, fn, {}, params, nullptr, is_async, false); + fn->is_arrow = true; + fn->expression_body = body; + return fn; +} + +FunctionDeclaration* FunctionDecl(Tree* t, std::string_view name, + std::vector<std::string_view> params, + std::vector<Statement*> body, bool is_async, + bool is_generator) { + FunctionDeclaration* fn = t->New<FunctionDeclaration>(); + FillFunction(t, fn, name, params, &body, is_async, is_generator); + return fn; +} + +MethodDefinition* ClassMethod(Tree* t, std::string_view name, + FunctionExpression* fn, MethodKind kind, + bool is_static) { + return ClassMethod(t, Id(t, name), fn, kind, is_static); +} + +PropertyDefinition* ClassField(Tree* t, std::string_view name, + Expression* value, bool is_static) { + return ClassField(t, Id(t, name), value, is_static); +} + +MethodDefinition* ClassMethod(Tree* t, Expression* key, FunctionExpression* fn, + MethodKind kind, bool is_static) { + MethodDefinition* m = t->New<MethodDefinition>(); + m->key = key; + m->value = fn; + m->method_kind = kind; + m->is_static = is_static; + return m; +} + +PropertyDefinition* ClassField(Tree* t, Expression* key, Expression* value, + bool is_static) { + PropertyDefinition* p = t->New<PropertyDefinition>(); + p->key = key; + p->value = value; + p->is_static = is_static; + return p; +} + +PrivateIdentifier* PrivateId(Tree* t, std::string_view name) { + PrivateIdentifier* p = t->New<PrivateIdentifier>(); + p->name = t->Intern(name); + return p; +} + +MemberExpression* PrivateMember(Tree* t, Expression* object, + std::string_view name) { + MemberExpression* m = t->New<MemberExpression>(); + m->object = object; + m->property = PrivateId(t, name); + return m; +} + +namespace { + +void FillClass(Tree* t, ClassData* cls, std::string_view name, + Expression* super_class, std::vector<Node*>& members) { + if (!name.empty()) { + cls->name = Id(t, name); + } + cls->super_class = super_class; + cls->body = t->New<ClassBody>(); + cls->body->members = std::move(members); +} + +} // namespace + +ClassDeclaration* ClassDecl(Tree* t, std::string_view name, + Expression* super_class, + std::vector<Node*> members) { + ClassDeclaration* cls = t->New<ClassDeclaration>(); + FillClass(t, cls, name, super_class, members); + return cls; +} + +ClassExpression* Class(Tree* t, std::string_view name, Expression* super_class, + std::vector<Node*> members) { + ClassExpression* cls = t->New<ClassExpression>(); + FillClass(t, cls, name, super_class, members); + return cls; +} + +ExpressionStatement* ExprStmt(Tree* t, Expression* expression) { + ExpressionStatement* s = t->New<ExpressionStatement>(); + s->expression = expression; + return s; +} + +VariableDeclaration* Declare(Tree* t, VariableKind kind, std::string_view name, + Expression* init) { + VariableDeclaration* d = t->New<VariableDeclaration>(); + d->declaration_kind = kind; + VariableDeclarator* declarator = t->New<VariableDeclarator>(); + declarator->target = Id(t, name); + declarator->init = init; + d->declarations.push_back(declarator); + return d; +} + +VariableDeclaration* Let(Tree* t, std::string_view name, Expression* init) { + return Declare(t, VariableKind::kLet, name, init); +} +VariableDeclaration* Const(Tree* t, std::string_view name, Expression* init) { + return Declare(t, VariableKind::kConst, name, init); +} +VariableDeclaration* Var(Tree* t, std::string_view name, Expression* init) { + return Declare(t, VariableKind::kVar, name, init); +} + +BlockStatement* Block(Tree* t, std::vector<Statement*> body) { + BlockStatement* b = t->New<BlockStatement>(); + b->body = std::move(body); + return b; +} + +BlockStatement* AsBlock(Tree* t, Statement* statement) { + if (auto* block = statement->As<BlockStatement>()) { + return block; + } + return Block(t, {statement}); +} + +IfStatement* If(Tree* t, Expression* test, Statement* consequent, + Statement* alternate) { + IfStatement* s = t->New<IfStatement>(); + s->test = test; + s->consequent = consequent; + s->alternate = alternate; + return s; +} + +ReturnStatement* Return(Tree* t, Expression* argument) { + ReturnStatement* s = t->New<ReturnStatement>(); + s->argument = argument; + return s; +} + +ThrowStatement* Throw(Tree* t, Expression* argument) { + ThrowStatement* s = t->New<ThrowStatement>(); + s->argument = argument; + return s; +} + +ForStatement* For(Tree* t, Node* init, Expression* test, Expression* update, + Statement* body) { + ForStatement* s = t->New<ForStatement>(); + s->init = init; + s->test = test; + s->update = update; + s->body = body; + return s; +} + +ForStatement* CountedLoop(Tree* t, std::string_view counter, Expression* count, + Statement* body) { + return For(t, Let(t, counter, Num(t, 0)), + Binary(t, BinaryOp::kLessThan, Id(t, counter), count), + Update(t, UpdateOp::kIncrement, false, Id(t, counter)), body); +} + +WhileStatement* While(Tree* t, Expression* test, Statement* body) { + WhileStatement* s = t->New<WhileStatement>(); + s->test = test; + s->body = body; + return s; +} + +DoWhileStatement* DoWhile(Tree* t, Statement* body, Expression* test) { + DoWhileStatement* s = t->New<DoWhileStatement>(); + s->body = body; + s->test = test; + return s; +} + +ForOfStatement* ForOf(Tree* t, VariableKind kind, std::string_view name, + Expression* iterable, Statement* body, bool is_await) { + ForOfStatement* s = t->New<ForOfStatement>(); + s->left = Declare(t, kind, name, nullptr); + s->right = iterable; + s->body = body; + s->is_await = is_await; + return s; +} + +ForInStatement* ForIn(Tree* t, VariableKind kind, std::string_view name, + Expression* object, Statement* body) { + ForInStatement* s = t->New<ForInStatement>(); + s->left = Declare(t, kind, name, nullptr); + s->right = object; + s->body = body; + return s; +} + +TryStatement* Try(Tree* t, std::vector<Statement*> block, + std::string_view catch_param, std::vector<Statement*> handler, + std::vector<Statement*>* finalizer) { + TryStatement* s = t->New<TryStatement>(); + s->block = Block(t, std::move(block)); + CatchClause* clause = t->New<CatchClause>(); + if (!catch_param.empty()) { + clause->param = Id(t, catch_param); + } + clause->body = Block(t, std::move(handler)); + s->handler = clause; + if (finalizer != nullptr) { + s->finalizer = Block(t, std::move(*finalizer)); + } + return s; +} + +SwitchStatement* Switch(Tree* t, Expression* discriminant, + std::vector<SwitchCase*> cases) { + SwitchStatement* s = t->New<SwitchStatement>(); + s->discriminant = discriminant; + s->cases = std::move(cases); + return s; +} + +SwitchCase* Case(Tree* t, Expression* test, std::vector<Statement*> body) { + SwitchCase* c = t->New<SwitchCase>(); + c->test = test; + c->consequent = std::move(body); + return c; +} + +BreakStatement* Break(Tree* t, std::string_view label) { + BreakStatement* s = t->New<BreakStatement>(); + if (!label.empty()) { + s->label = Id(t, label); + } + return s; +} + +ContinueStatement* Continue(Tree* t, std::string_view label) { + ContinueStatement* s = t->New<ContinueStatement>(); + if (!label.empty()) { + s->label = Id(t, label); + } + return s; +} + +LabeledStatement* Labeled(Tree* t, std::string_view label, Statement* body) { + LabeledStatement* s = t->New<LabeledStatement>(); + s->label = Id(t, label); + s->body = body; + return s; +} + +EmptyStatement* Empty(Tree* t) { return t->New<EmptyStatement>(); } + +void Anchor(Node* node, int32_t anchor) { + Walk(node, [anchor](Node* n) { + n->start = anchor; + n->end = anchor; + return true; + }); +} + +} // namespace mk +} // namespace redline diff --git a/deps/v8/experimental/redline/core/ast_builder.h b/deps/v8/experimental/redline/core/ast_builder.h new file mode 100644 index 000000000000..2d89cc31556d --- /dev/null +++ b/deps/v8/experimental/redline/core/ast_builder.h @@ -0,0 +1,219 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_AST_BUILDER_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_AST_BUILDER_H_ + +#include <initializer_list> +#include <string_view> +#include <vector> + +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/tree.h" + +// Short factory functions for synthesizing FAST nodes. Every generator and +// mutator builds code through these, so generated code stays uniform (no +// source positions, names interned in the owning tree). +namespace redline { +namespace mk { + +using fast::ArrayExpression; +using fast::ArrowFunctionExpression; +using fast::AssignmentExpression; +using fast::AssignOp; +using fast::AwaitExpression; +using fast::BigIntLiteral; +using fast::BinaryExpression; +using fast::BinaryOp; +using fast::BlockStatement; +using fast::BooleanLiteral; +using fast::BreakStatement; +using fast::CallExpression; +using fast::ChainExpression; +using fast::ClassDeclaration; +using fast::ClassExpression; +using fast::ConditionalExpression; +using fast::ContinueStatement; +using fast::DoWhileStatement; +using fast::EmptyStatement; +using fast::Expression; +using fast::ExpressionStatement; +using fast::ForInStatement; +using fast::ForOfStatement; +using fast::ForStatement; +using fast::FunctionDeclaration; +using fast::FunctionExpression; +using fast::Identifier; +using fast::IfStatement; +using fast::LabeledStatement; +using fast::LogicalExpression; +using fast::LogicalOp; +using fast::MemberExpression; +using fast::MetaProperty; +using fast::MethodDefinition; +using fast::MethodKind; +using fast::NativeCallExpression; +using fast::NewExpression; +using fast::Node; +using fast::NullLiteral; +using fast::NumericLiteral; +using fast::ObjectExpression; +using fast::PrivateIdentifier; +using fast::Property; +using fast::PropertyDefinition; +using fast::RegExpLiteral; +using fast::ReturnStatement; +using fast::SequenceExpression; +using fast::SpreadElement; +using fast::Statement; +using fast::StringLiteral; +using fast::SwitchCase; +using fast::SwitchStatement; +using fast::TemplateLiteral; +using fast::ThisExpression; +using fast::ThrowStatement; +using fast::Tree; +using fast::TryStatement; +using fast::UnaryExpression; +using fast::UnaryOp; +using fast::UpdateExpression; +using fast::UpdateOp; +using fast::VariableDeclaration; +using fast::VariableKind; +using fast::WhileStatement; +using fast::YieldExpression; + +Identifier* Id(Tree* t, std::string_view name); +NumericLiteral* Num(Tree* t, double value); +StringLiteral* Str(Tree* t, std::string_view value); +BooleanLiteral* Bool(Tree* t, bool value); +NullLiteral* Null(Tree* t); +Identifier* Undefined(Tree* t); +BigIntLiteral* BigInt(Tree* t, std::string_view digits); // without 'n' +RegExpLiteral* RegExp(Tree* t, std::string_view pattern, + std::string_view flags); +ThisExpression* This(Tree* t); +MetaProperty* NewTarget(Tree* t); +TemplateLiteral* Template(Tree* t, std::vector<std::string_view> strings, + std::vector<Expression*> expressions); + +ArrayExpression* Array(Tree* t, std::vector<Expression*> elements); +ObjectExpression* Object(Tree* t, std::vector<Node*> properties); +Property* Prop(Tree* t, std::string_view key, Expression* value); +Property* Prop(Tree* t, Expression* key, Expression* value, bool computed); +Property* Accessor(Tree* t, std::string_view key, FunctionExpression* fn, + bool getter); +Property* Method(Tree* t, std::string_view key, FunctionExpression* fn); +SpreadElement* Spread(Tree* t, Expression* argument); + +UnaryExpression* Unary(Tree* t, UnaryOp op, Expression* argument); +UpdateExpression* Update(Tree* t, UpdateOp op, bool prefix, + Expression* argument); +BinaryExpression* Binary(Tree* t, BinaryOp op, Expression* left, + Expression* right); +LogicalExpression* Logical(Tree* t, LogicalOp op, Expression* left, + Expression* right); +AssignmentExpression* Assign(Tree* t, Expression* target, Expression* value, + AssignOp op = AssignOp::kAssign); +ConditionalExpression* Cond(Tree* t, Expression* test, Expression* consequent, + Expression* alternate); +SequenceExpression* Seq(Tree* t, std::vector<Expression*> expressions); +MemberExpression* Member(Tree* t, Expression* object, std::string_view name); +// `object.#name` (name without the '#'). +MemberExpression* PrivateMember(Tree* t, Expression* object, + std::string_view name); +MemberExpression* Index(Tree* t, Expression* object, Expression* index); +CallExpression* Call(Tree* t, Expression* callee, + std::vector<Expression*> args); +CallExpression* CallMethod(Tree* t, Expression* object, std::string_view name, + std::vector<Expression*> args); +NewExpression* New(Tree* t, Expression* callee, std::vector<Expression*> args); +NativeCallExpression* Native(Tree* t, std::string_view name, + std::vector<Expression*> args); +AwaitExpression* Await(Tree* t, Expression* argument); +YieldExpression* Yield(Tree* t, Expression* argument, bool delegate = false); +ChainExpression* Chain(Tree* t, Expression* expression); + +// Functions. `body` statements are moved into a fresh block. +FunctionExpression* Function(Tree* t, std::string_view name, + std::vector<std::string_view> params, + std::vector<Statement*> body, + bool is_async = false, bool is_generator = false); +ArrowFunctionExpression* Arrow(Tree* t, std::vector<std::string_view> params, + std::vector<Statement*> body, + bool is_async = false); +ArrowFunctionExpression* ArrowExpr(Tree* t, + std::vector<std::string_view> params, + Expression* body, bool is_async = false); +FunctionDeclaration* FunctionDecl(Tree* t, std::string_view name, + std::vector<std::string_view> params, + std::vector<Statement*> body, + bool is_async = false, + bool is_generator = false); +MethodDefinition* ClassMethod(Tree* t, std::string_view name, + FunctionExpression* fn, + MethodKind kind = MethodKind::kMethod, + bool is_static = false); +PropertyDefinition* ClassField(Tree* t, std::string_view name, + Expression* value, bool is_static = false); +// The same with an explicit key node (a PrivateIdentifier for `#name` +// members, or any expression for computed keys). +MethodDefinition* ClassMethod(Tree* t, Expression* key, FunctionExpression* fn, + MethodKind kind, bool is_static); +PropertyDefinition* ClassField(Tree* t, Expression* key, Expression* value, + bool is_static); +PrivateIdentifier* PrivateId(Tree* t, + std::string_view name); // name without the '#' +ClassDeclaration* ClassDecl(Tree* t, std::string_view name, + Expression* super_class, + std::vector<Node*> members); +ClassExpression* Class(Tree* t, std::string_view name, Expression* super_class, + std::vector<Node*> members); + +// Statements. +ExpressionStatement* ExprStmt(Tree* t, Expression* expression); +VariableDeclaration* Declare(Tree* t, VariableKind kind, std::string_view name, + Expression* init); +VariableDeclaration* Let(Tree* t, std::string_view name, Expression* init); +VariableDeclaration* Const(Tree* t, std::string_view name, Expression* init); +VariableDeclaration* Var(Tree* t, std::string_view name, Expression* init); +BlockStatement* Block(Tree* t, std::vector<Statement*> body); +// Wraps a statement into a block unless it already is one. +BlockStatement* AsBlock(Tree* t, Statement* statement); +IfStatement* If(Tree* t, Expression* test, Statement* consequent, + Statement* alternate = nullptr); +ReturnStatement* Return(Tree* t, Expression* argument); +ThrowStatement* Throw(Tree* t, Expression* argument); +// for (let i = 0; i < count; i++) body +ForStatement* CountedLoop(Tree* t, std::string_view counter, Expression* count, + Statement* body); +ForStatement* For(Tree* t, Node* init, Expression* test, Expression* update, + Statement* body); +WhileStatement* While(Tree* t, Expression* test, Statement* body); +DoWhileStatement* DoWhile(Tree* t, Statement* body, Expression* test); +ForOfStatement* ForOf(Tree* t, VariableKind kind, std::string_view name, + Expression* iterable, Statement* body, + bool is_await = false); +ForInStatement* ForIn(Tree* t, VariableKind kind, std::string_view name, + Expression* object, Statement* body); +TryStatement* Try(Tree* t, std::vector<Statement*> block, + std::string_view catch_param, std::vector<Statement*> handler, + std::vector<Statement*>* finalizer = nullptr); +SwitchStatement* Switch(Tree* t, Expression* discriminant, + std::vector<SwitchCase*> cases); +SwitchCase* Case(Tree* t, Expression* test, std::vector<Statement*> body); +BreakStatement* Break(Tree* t, std::string_view label = {}); +ContinueStatement* Continue(Tree* t, std::string_view label = {}); +LabeledStatement* Labeled(Tree* t, std::string_view label, Statement* body); +EmptyStatement* Empty(Tree* t); + +// Sets the source position of every node in `node`'s subtree to +// [anchor, anchor] so that textual-order based analyses (TDZ +// approximation) treat synthesized code as located at `anchor`. +void Anchor(Node* node, int32_t anchor); + +} // namespace mk +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_AST_BUILDER_H_ diff --git a/deps/v8/experimental/redline/core/builder.cc b/deps/v8/experimental/redline/core/builder.cc new file mode 100644 index 000000000000..bbf196abbe8d --- /dev/null +++ b/deps/v8/experimental/redline/core/builder.cc @@ -0,0 +1,1013 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/builder.h" + +#include <algorithm> + +#include "experimental/redline/core/ast_builder.h" + +namespace redline { + +using namespace fast; // NOLINT(build/namespaces) + +const char* JsTypeName(JsType type) { + switch (type) { + case JsType::kUnknown: + return "unknown"; + case JsType::kNumber: + return "number"; + case JsType::kString: + return "string"; + case JsType::kBoolean: + return "boolean"; + case JsType::kBigInt: + return "bigint"; + case JsType::kSymbol: + return "symbol"; + case JsType::kNullish: + return "nullish"; + case JsType::kArray: + return "array"; + case JsType::kObject: + return "object"; + case JsType::kFunction: + return "function"; + case JsType::kClass: + return "class"; + case JsType::kRegExp: + return "regexp"; + case JsType::kMap: + return "map"; + case JsType::kSet: + return "set"; + case JsType::kPromise: + return "promise"; + case JsType::kTypedArray: + return "typedarray"; + case JsType::kArrayBuffer: + return "arraybuffer"; + case JsType::kDate: + return "date"; + case JsType::kError: + return "error"; + } + return "?"; +} + +Builder::Builder(Tree* tree, Random* rng) : tree_(tree), rng_(rng) {} +Builder::~Builder() = default; + +void Builder::Invalidate() { + scopes_.reset(); + parents_valid_ = false; + // used_names_ only grows; names of removed code stay reserved, which is + // harmless. +} + +namespace { + +// Assigns pre-order positions: start on entry, end on exit, each unique. +// Scope analysis orders declarations and references by these positions +// (TDZ approximation), so after edits they must reflect tree order rather +// than the original source offsets, and synthesized nodes must have them. +void Renumber(Node* node, int32_t* counter) { + node->start = (*counter)++; + ForEachChild(node, [&](Node* child) { Renumber(child, counter); }); + node->end = (*counter)++; +} + +} // namespace + +void Builder::EnsureAnalysis() { + if (scopes_ != nullptr) { + return; + } + int32_t counter = 0; + Renumber(tree_->root(), &counter); + scopes_ = ScopeAnalysis::Analyze(tree_); +} + +ScopeAnalysis& Builder::scopes() { + EnsureAnalysis(); + return *scopes_; +} + +void Builder::BuildParentMap() { + parents_.assign(tree_->id_limit(), nullptr); + Walk(tree_->root(), [&](Node* node) { + ForEachChild(node, [&](Node* child) { + if (child->id >= parents_.size()) { + parents_.resize(child->id + 1, nullptr); + } + parents_[child->id] = node; + }); + return true; + }); + parents_valid_ = true; +} + +Node* Builder::ParentOf(Node* node) { + if (!parents_valid_) { + BuildParentMap(); + } + return node->id < parents_.size() ? parents_[node->id] : nullptr; +} + +// --- statement lists --------------------------------------------------------- + +// static +int Builder::LeadingDirectives(const std::vector<Statement*>& list) { + int n = 0; + for (Statement* s : list) { + auto* e = s->As<ExpressionStatement>(); + if (e == nullptr || !e->is_directive) { + break; + } + n++; + } + return n; +} + +template <typename F> +void Builder::ForEachStatementList(F&& f) { + Walk(tree_->root(), [&](Node* node) { + switch (node->kind) { + case NodeKind::kProgram: + f(&node->Cast<Program>()->body, node); + break; + case NodeKind::kBlockStatement: + f(&node->Cast<BlockStatement>()->body, node); + break; + case NodeKind::kSwitchCase: + f(&node->Cast<SwitchCase>()->consequent, node); + break; + case NodeKind::kStaticBlock: + f(&node->Cast<StaticBlock>()->body, node); + break; + default: + break; + } + return true; + }); +} + +std::vector<Builder::Slot> Builder::InsertionSlots() { + std::vector<Slot> slots; + ForEachStatementList([&](std::vector<Statement*>* list, Node* owner) { + size_t first = static_cast<size_t>(LeadingDirectives(*list)); + for (size_t i = first; i <= list->size(); i++) { + slots.push_back({list, i, owner}); + } + }); + return slots; +} + +std::vector<Builder::Slot> Builder::StatementSlots() { + std::vector<Slot> slots; + ForEachStatementList([&](std::vector<Statement*>* list, Node* owner) { + size_t first = static_cast<size_t>(LeadingDirectives(*list)); + for (size_t i = first; i < list->size(); i++) { + slots.push_back({list, i, owner}); + } + }); + return slots; +} + +Builder::Slot Builder::RandomInsertionSlot() { + std::vector<Slot> slots = InsertionSlots(); + if (slots.empty()) { + return Slot{&tree_->root()->body, 0, tree_->root()}; + } + return rng_->Pick(slots); +} + +Builder::Slot Builder::RandomStatementSlot() { + std::vector<Slot> slots = StatementSlots(); + if (slots.empty()) { + return Slot{}; + } + return rng_->Pick(slots); +} + +Builder::Slot Builder::SlotOf(Statement* statement) { + Slot result; + ForEachStatementList([&](std::vector<Statement*>* list, Node* owner) { + if (result.valid()) { + return; + } + for (size_t i = 0; i < list->size(); i++) { + if ((*list)[i] == statement) { + result = {list, i, owner}; + return; + } + } + }); + return result; +} + +Node* Builder::AnchorNodeFor(const Slot& slot, int32_t* position) { + // Code inserted at `slot` sees what the previous statement sees (or what + // the owner sees for the first position). + Node* anchor = slot.index > 0 ? (*slot.list)[slot.index - 1] : slot.owner; + if (position != nullptr) { + *position = slot.index > 0 ? anchor->end : anchor->start; + if (*position < 0) { + *position = 0; + } + } + return anchor; +} + +void Builder::Insert(const Slot& slot, Statement* statement) { + int32_t position = 0; + AnchorNodeFor(slot, &position); + mk::Anchor(statement, position); + slot.list->insert(slot.list->begin() + static_cast<ptrdiff_t>(slot.index), + statement); + Invalidate(); +} + +void Builder::InsertAll(const Slot& slot, + const std::vector<Statement*>& statements) { + Slot cursor = slot; + for (Statement* statement : statements) { + Insert(cursor, statement); + cursor.index++; + } +} + +Statement* Builder::Remove(const Slot& slot) { + if (!slot.valid() || slot.index >= slot.list->size()) { + return nullptr; + } + Statement* removed = (*slot.list)[slot.index]; + slot.list->erase(slot.list->begin() + static_cast<ptrdiff_t>(slot.index)); + Invalidate(); + return removed; +} + +bool Builder::Replace(Node* old_node, Node* new_node) { + Node* parent = ParentOf(old_node); + if (parent == nullptr) { + return false; + } + bool replaced = false; + ForEachChildSlot(parent, [&](Node** slot) { + if (*slot == old_node) { + *slot = new_node; + replaced = true; + } + }); + if (replaced) { + if (old_node->start >= 0) { + mk::Anchor(new_node, old_node->start); + } + Invalidate(); + } + return replaced; +} + +Builder::Slot Builder::Blockify(Statement* statement) { + if (auto* block = statement->As<BlockStatement>()) { + return Slot{&block->body, 0, block}; + } + Slot existing = SlotOf(statement); + if (existing.valid()) { + return existing; + } + BlockStatement* block = mk::Block(tree_, {statement}); + block->start = statement->start; + block->end = statement->end; + if (!Replace(statement, block)) { + return Slot{}; + } + return Slot{&block->body, 0, block}; +} + +// --- node queries ------------------------------------------------------------ + +std::vector<Node*> Builder::Collect(const std::function<bool(Node*)>& pred) { + std::vector<Node*> result; + Walk(tree_->root(), [&](Node* node) { + if (pred(node)) { + result.push_back(node); + } + return true; + }); + return result; +} + +Node* Builder::RandomNode(const std::function<bool(Node*)>& pred) { + std::vector<Node*> nodes = Collect(pred); + if (nodes.empty()) { + return nullptr; + } + return rng_->Pick(nodes); +} + +namespace { + +bool IsPatternKind(NodeKind kind) { + return kind == NodeKind::kObjectPattern || kind == NodeKind::kArrayPattern || + kind == NodeKind::kAssignmentPattern || kind == NodeKind::kRestElement; +} + +} // namespace + +ExpressionRole Builder::RoleOf(Node* node) { + if (!node->IsExpression()) { + return ExpressionRole::kNotReplaceable; + } + Node* parent = ParentOf(node); + if (parent == nullptr) { + return ExpressionRole::kNotReplaceable; + } + if (node->kind == NodeKind::kSuper || + node->kind == NodeKind::kPrivateIdentifier || IsPatternKind(node->kind)) { + return ExpressionRole::kNotReplaceable; + } + // `{...x}`: the entry must stay a spread (or a property); its argument is + // the replaceable part. + if (node->kind == NodeKind::kSpreadElement && + parent->kind == NodeKind::kObjectExpression) { + return ExpressionRole::kNotReplaceable; + } + switch (parent->kind) { + case NodeKind::kAssignmentExpression: + if (parent->Cast<AssignmentExpression>()->left == node) { + return node->kind == NodeKind::kIdentifier || + node->kind == NodeKind::kMemberExpression + ? ExpressionRole::kTarget + : ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + case NodeKind::kUpdateExpression: + return ExpressionRole::kTarget; + case NodeKind::kForInStatement: + if (parent->Cast<ForInStatement>()->left == node) { + return ExpressionRole::kTarget; + } + return ExpressionRole::kValue; + case NodeKind::kForOfStatement: + if (parent->Cast<ForOfStatement>()->left == node) { + return ExpressionRole::kTarget; + } + return ExpressionRole::kValue; + case NodeKind::kMemberExpression: { + auto* m = parent->Cast<MemberExpression>(); + if (m->property == node && !m->computed) { + return ExpressionRole::kNotReplaceable; + } + if (m->object == node && node->kind == NodeKind::kSuper) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + } + case NodeKind::kProperty: { + auto* p = parent->Cast<Property>(); + if (p->key == node && !p->computed) { + return ExpressionRole::kNotReplaceable; + } + if (p->value == node && + (p->method || p->property_kind != PropertyKind::kInit)) { + return ExpressionRole::kNotReplaceable; + } + // Patterns: the value is a binding/assignment target. + Node* grandparent = ParentOf(parent); + if (grandparent != nullptr && + grandparent->kind == NodeKind::kObjectPattern && p->value == node) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + } + case NodeKind::kMethodDefinition: + case NodeKind::kPropertyDefinition: { + Expression* key = parent->kind == NodeKind::kMethodDefinition + ? parent->Cast<MethodDefinition>()->key + : parent->Cast<PropertyDefinition>()->key; + bool computed = parent->kind == NodeKind::kMethodDefinition + ? parent->Cast<MethodDefinition>()->computed + : parent->Cast<PropertyDefinition>()->computed; + if (key == node && !computed) { + return ExpressionRole::kNotReplaceable; + } + if (parent->kind == NodeKind::kMethodDefinition && key != node) { + return ExpressionRole::kNotReplaceable; // the method function + } + return ExpressionRole::kValue; + } + case NodeKind::kVariableDeclarator: + if (parent->Cast<VariableDeclarator>()->target == node) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + case NodeKind::kFunctionDeclaration: + case NodeKind::kFunctionExpression: + case NodeKind::kArrowFunctionExpression: { + const FunctionData* fn = AsFunctionData(parent); + if (fn->name == node) { + return ExpressionRole::kNotReplaceable; + } + for (Expression* param : fn->params) { + if (param == node) { + return ExpressionRole::kNotReplaceable; + } + } + return ExpressionRole::kValue; // concise arrow body + } + case NodeKind::kClassDeclaration: + case NodeKind::kClassExpression: + if (AsClassData(parent)->name == node) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; // heritage + case NodeKind::kLabeledStatement: + case NodeKind::kBreakStatement: + case NodeKind::kContinueStatement: + case NodeKind::kCatchClause: // the parameter + return ExpressionRole::kNotReplaceable; + case NodeKind::kTaggedTemplateExpression: + if (parent->Cast<TaggedTemplateExpression>()->quasi == node) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + case NodeKind::kChainExpression: + case NodeKind::kObjectPattern: + case NodeKind::kArrayPattern: + case NodeKind::kRestElement: + return ExpressionRole::kNotReplaceable; + case NodeKind::kAssignmentPattern: + if (parent->Cast<AssignmentPattern>()->left == node) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + case NodeKind::kCallExpression: + if (parent->Cast<CallExpression>()->callee == node && + node->kind == NodeKind::kSuper) { + return ExpressionRole::kNotReplaceable; + } + return ExpressionRole::kValue; + case NodeKind::kBinaryExpression: + // `#x in obj` has a PrivateIdentifier on the left (handled above). + default: + return ExpressionRole::kValue; + } +} + +std::vector<Expression*> Builder::ValueExpressions() { + std::vector<Expression*> result; + Walk(tree_->root(), [&](Node* node) { + if (node->IsExpression() && RoleOf(node) == ExpressionRole::kValue) { + result.push_back(node->Cast<Expression>()); + } + return true; + }); + return result; +} + +Statement* Builder::EnclosingStatement(Node* node) { + for (Node* n = node; n != nullptr; n = ParentOf(n)) { + if (n->IsStatement()) { + return n->Cast<Statement>(); + } + } + return nullptr; +} + +Node* Builder::EnclosingFunction(Node* node) { + for (Node* n = ParentOf(node); n != nullptr; n = ParentOf(n)) { + if (n->IsFunction()) { + return n; + } + } + return nullptr; +} + +// --- context ----------------------------------------------------------------- + +namespace { + +bool IsLoopKind(NodeKind kind) { + return kind == NodeKind::kForStatement || kind == NodeKind::kWhileStatement || + kind == NodeKind::kDoWhileStatement || + kind == NodeKind::kForInStatement || kind == NodeKind::kForOfStatement; +} + +} // namespace + +Builder::Context Builder::ContextAt(Node* node) { + Context c; + // Any function (arrows included) ends the reach of enclosing loops, + // switches and labels and fixes return/await/yield/strictness. + bool code_boundary = false; + // A non-arrow function, field initializer or static block fixes + // this/super/arguments. + bool this_boundary = false; + bool class_resolved = false; + Node* child = nullptr; + for (Node* n = node; n != nullptr; child = n, n = ParentOf(n)) { + switch (n->kind) { + case NodeKind::kProgram: + if (!code_boundary) { + c.strict = n->Cast<Program>()->strict; + } + break; + case NodeKind::kForStatement: + case NodeKind::kWhileStatement: + case NodeKind::kDoWhileStatement: + case NodeKind::kForInStatement: + case NodeKind::kForOfStatement: + if (!code_boundary && n != node) { + c.in_loop = true; + } + break; + case NodeKind::kSwitchStatement: + if (!code_boundary && n != node) { + c.in_switch = true; + } + break; + case NodeKind::kLabeledStatement: + if (!code_boundary && n != node) { + c.labels.push_back(n->Cast<LabeledStatement>()->label->name); + } + break; + case NodeKind::kFunctionDeclaration: + case NodeKind::kFunctionExpression: + case NodeKind::kArrowFunctionExpression: { + if (n == node) { + break; + } + const FunctionData* fn = AsFunctionData(n); + // Code in the parameter list or body of the function. + if (!code_boundary) { + c.in_function = true; + c.in_async = fn->is_async; + c.in_generator = fn->is_generator; + c.strict = fn->strict; + code_boundary = true; + } + if (!this_boundary && !fn->is_arrow) { + this_boundary = true; + c.has_arguments = true; + Node* parent = ParentOf(n); + if (parent != nullptr) { + if (auto* m = parent->As<MethodDefinition>()) { + if (m->value == n) { + c.in_method = true; + c.in_constructor = m->method_kind == MethodKind::kConstructor; + } + } else if (auto* p = parent->As<Property>()) { + if (p->value == n && + (p->method || p->property_kind != PropertyKind::kInit)) { + c.in_method = true; // object literal methods have super too + class_resolved = true; + } + } + } + if (!c.in_method) { + class_resolved = true; + } + } + break; + } + case NodeKind::kPropertyDefinition: + if (!code_boundary && child == n->Cast<PropertyDefinition>()->value) { + c.in_class_field = true; + c.in_method = true; // super.x is allowed in field initializers + c.strict = true; + c.in_function = false; + code_boundary = true; + this_boundary = true; + } + break; + case NodeKind::kStaticBlock: + if (!code_boundary) { + c.in_static_block = true; + c.in_method = true; + c.strict = true; + code_boundary = true; + this_boundary = true; + } + break; + case NodeKind::kClassBody: + c.strict = true; // class bodies are strict, nested functions too + break; + case NodeKind::kClassDeclaration: + case NodeKind::kClassExpression: + c.strict = true; + if (c.in_method && !class_resolved) { + c.has_super_class = AsClassData(n)->super_class != nullptr; + class_resolved = true; + } + break; + default: + break; + } + } + return c; +} + +Builder::Context Builder::ContextAtSlot(const Slot& slot) { + // A statement list owner (block, case, static block, program) adds no + // context of its own except: a block that is a loop/switch body is + // inside that loop/switch, and ContextAt() deliberately ignores the + // node's own loop markers. + Context c = ContextAt(slot.owner); + if (slot.owner->kind == NodeKind::kSwitchCase) { + c.in_switch = true; + } + if (slot.owner->kind == NodeKind::kStaticBlock) { + c.in_static_block = true; + c.in_method = true; + c.strict = true; + c.in_function = false; + c.in_loop = false; + c.in_switch = false; + c.labels.clear(); + } + Node* parent = ParentOf(slot.owner); + if (parent != nullptr && IsLoopKind(parent->kind)) { + c.in_loop = true; + } + return c; +} + +// --- variables --------------------------------------------------------------- + +// static +JsType Builder::GuessType(const Expression* e) { + if (e == nullptr) { + return JsType::kUnknown; + } + switch (e->kind) { + case NodeKind::kNumericLiteral: + return JsType::kNumber; + case NodeKind::kStringLiteral: + case NodeKind::kTemplateLiteral: + return JsType::kString; + case NodeKind::kBooleanLiteral: + return JsType::kBoolean; + case NodeKind::kBigIntLiteral: + return JsType::kBigInt; + case NodeKind::kNullLiteral: + return JsType::kNullish; + case NodeKind::kRegExpLiteral: + return JsType::kRegExp; + case NodeKind::kArrayExpression: + return JsType::kArray; + case NodeKind::kObjectExpression: + return JsType::kObject; + case NodeKind::kFunctionExpression: + case NodeKind::kArrowFunctionExpression: + return JsType::kFunction; + case NodeKind::kClassExpression: + return JsType::kClass; + case NodeKind::kIdentifier: { + std::string_view name = e->Cast<Identifier>()->name; + if (name == "undefined") { + return JsType::kNullish; + } + if (name == "NaN" || name == "Infinity") { + return JsType::kNumber; + } + return JsType::kUnknown; + } + case NodeKind::kUnaryExpression: { + auto* u = e->Cast<UnaryExpression>(); + switch (u->op) { + case UnaryOp::kNot: + case UnaryOp::kDelete: + return JsType::kBoolean; + case UnaryOp::kTypeof: + return JsType::kString; + case UnaryOp::kVoid: + return JsType::kNullish; + case UnaryOp::kMinus: + case UnaryOp::kPlus: + case UnaryOp::kBitNot: + return u->op == UnaryOp::kPlus ? JsType::kNumber + : GuessType(u->argument) == JsType::kBigInt ? JsType::kBigInt + : JsType::kNumber; + } + return JsType::kUnknown; + } + case NodeKind::kUpdateExpression: + return JsType::kNumber; + case NodeKind::kBinaryExpression: { + auto* b = e->Cast<BinaryExpression>(); + switch (b->op) { + case BinaryOp::kEq: + case BinaryOp::kNotEq: + case BinaryOp::kStrictEq: + case BinaryOp::kStrictNotEq: + case BinaryOp::kLessThan: + case BinaryOp::kLessThanEq: + case BinaryOp::kGreaterThan: + case BinaryOp::kGreaterThanEq: + case BinaryOp::kIn: + case BinaryOp::kInstanceof: + return JsType::kBoolean; + case BinaryOp::kAdd: { + JsType l = GuessType(b->left), r = GuessType(b->right); + if (l == JsType::kString || r == JsType::kString) { + return JsType::kString; + } + if (l == JsType::kNumber && r == JsType::kNumber) { + return JsType::kNumber; + } + if (l == JsType::kBigInt && r == JsType::kBigInt) { + return JsType::kBigInt; + } + return JsType::kUnknown; + } + default: + return GuessType(b->left) == JsType::kBigInt ? JsType::kBigInt + : JsType::kNumber; + } + } + case NodeKind::kLogicalExpression: { + auto* l = e->Cast<LogicalExpression>(); + JsType a = GuessType(l->left), b = GuessType(l->right); + return a == b ? a : JsType::kUnknown; + } + case NodeKind::kConditionalExpression: { + auto* c = e->Cast<ConditionalExpression>(); + JsType a = GuessType(c->consequent), b = GuessType(c->alternate); + return a == b ? a : JsType::kUnknown; + } + case NodeKind::kAssignmentExpression: + return GuessType(e->Cast<AssignmentExpression>()->right); + case NodeKind::kSequenceExpression: { + auto* s = e->Cast<SequenceExpression>(); + return s->expressions.empty() ? JsType::kUnknown + : GuessType(s->expressions.back()); + } + case NodeKind::kAwaitExpression: + return JsType::kUnknown; + case NodeKind::kNewExpression: { + auto* n = e->Cast<NewExpression>(); + auto* callee = n->callee->As<Identifier>(); + if (callee == nullptr) { + return JsType::kObject; + } + std::string_view name = callee->name; + if (name == "Array") { + return JsType::kArray; + } + if (name == "Map" || name == "WeakMap") { + return JsType::kMap; + } + if (name == "Set" || name == "WeakSet") { + return JsType::kSet; + } + if (name == "Promise") { + return JsType::kPromise; + } + if (name == "RegExp") { + return JsType::kRegExp; + } + if (name == "Date") { + return JsType::kDate; + } + if (name == "ArrayBuffer" || name == "SharedArrayBuffer") { + return JsType::kArrayBuffer; + } + if (name == "String") { + return JsType::kObject; + } + if (name == "Number") { + return JsType::kObject; + } + if (name.size() > 5 && name.ends_with("Array")) { + return JsType::kTypedArray; // Uint8Array, Float64Array, ... + } + if (name.size() > 5 && name.ends_with("Error")) { + return JsType::kError; + } + return JsType::kObject; + } + case NodeKind::kCallExpression: { + auto* c = e->Cast<CallExpression>(); + if (auto* callee = c->callee->As<Identifier>()) { + std::string_view name = callee->name; + if (name == "String") { + return JsType::kString; + } + if (name == "Number" || name == "parseInt" || name == "parseFloat") { + return JsType::kNumber; + } + if (name == "Boolean") { + return JsType::kBoolean; + } + if (name == "BigInt") { + return JsType::kBigInt; + } + if (name == "Symbol") { + return JsType::kSymbol; + } + if (name == "Array") { + return JsType::kArray; + } + if (name == "Object") { + return JsType::kObject; + } + return JsType::kUnknown; + } + if (auto* member = c->callee->As<MemberExpression>()) { + auto* object = member->object->As<Identifier>(); + auto* property = member->property->As<Identifier>(); + if (object == nullptr || property == nullptr || member->computed) { + return JsType::kUnknown; + } + std::string_view o = object->name, p = property->name; + if (o == "Math") { + return JsType::kNumber; + } + if (o == "JSON") { + return p == "stringify" ? JsType::kString : JsType::kUnknown; + } + if (o == "Object") { + if (p == "keys" || p == "values" || p == "entries" || + p == "getOwnPropertyNames") { + return JsType::kArray; + } + return JsType::kObject; + } + if (o == "Array") { + return JsType::kArray; + } + if (o == "String") { + return JsType::kString; + } + if (o == "Number") { + return JsType::kNumber; + } + if (o == "Reflect" && p == "ownKeys") { + return JsType::kArray; + } + if (o == "Promise") { + return JsType::kPromise; + } + return JsType::kUnknown; + } + return JsType::kUnknown; + } + default: + return JsType::kUnknown; + } +} + +JsType Builder::GuessType(const Binding* binding) { + switch (binding->kind) { + case BindingKind::kFunction: + case BindingKind::kFunctionName: + return JsType::kFunction; + case BindingKind::kClass: + case BindingKind::kClassName: + return JsType::kClass; + case BindingKind::kCatchParameter: + return JsType::kError; + case BindingKind::kImplicit: + return JsType::kObject; // arguments + case BindingKind::kParameter: + return JsType::kUnknown; + default: + break; + } + if (binding->declaration == nullptr) { + return JsType::kUnknown; + } + if (auto* declarator = binding->declaration->As<VariableDeclarator>()) { + if (declarator->target != binding->identifier) { + return JsType::kUnknown; + } + return GuessType(declarator->init); + } + return JsType::kUnknown; +} + +Variable Builder::ToVariable(Binding* binding) { + Variable v; + v.name = binding->name; + v.binding = binding; + v.type = GuessType(binding); + v.is_constant = binding->is_constant(); + return v; +} + +std::vector<Variable> Builder::VisibleAt(Node* node) { + std::vector<Variable> result; + for (Binding* binding : scopes().VisibleAt(node, /*initialized_only=*/true)) { + result.push_back(ToVariable(binding)); + } + return result; +} + +std::vector<Variable> Builder::VisibleAtSlot(const Slot& slot) { + // The analysis renumbers positions; compute the slot position afterwards. + ScopeAnalysis& analysis = scopes(); + int32_t position = 0; + AnchorNodeFor(slot, &position); + std::vector<Variable> result; + for (Binding* binding : + analysis.VisibleIn(slot.owner, position, /*initialized_only=*/true)) { + result.push_back(ToVariable(binding)); + } + return result; +} + +std::vector<Binding*> Builder::EscapingBindings(const std::vector<Node*>& nodes, + bool block_scoped_only) { + ScopeAnalysis& analysis = scopes(); // renumbers positions first + auto inside = [&](const Node* n) { + for (const Node* root : nodes) { + if (root->start <= n->start && n->end <= root->end) { + return true; + } + } + return false; + }; + std::vector<Binding*> result; + absl::flat_hash_set<Binding*> seen; + for (Node* root : nodes) { + Walk(root, [&](Node* n) { + auto* id = n->As<Identifier>(); + if (id == nullptr || !analysis.IsDeclaration(id)) { + return true; + } + Binding* binding = analysis.BindingOf(id); + if (binding == nullptr || !seen.insert(binding).second) { + return true; + } + if (block_scoped_only && binding->kind == BindingKind::kVar) { + return true; + } + // Also declared elsewhere (`var x; ... var x;`): nothing is lost. + for (Identifier* declaration : binding->declarations) { + if (!inside(declaration)) { + return true; + } + } + for (Identifier* reference : binding->references) { + if (!inside(reference)) { + result.push_back(binding); + break; + } + } + return true; + }); + } + return result; +} + +// static +std::vector<Variable> Builder::OfType(const std::vector<Variable>& candidates, + JsType type) { + std::vector<Variable> result; + for (const Variable& v : candidates) { + if (v.type == type) { + result.push_back(v); + } + } + return result; +} + +// --- names ------------------------------------------------------------------- + +void Builder::EnsureUsedNames() { + if (used_names_valid_) { + return; + } + // The analysis' names are views into tree_'s arena, which outlives the + // analysis: no copy needed. + const absl::flat_hash_set<std::string_view>& names = scopes().all_names(); + used_names_.insert(names.begin(), names.end()); + used_names_valid_ = true; +} + +std::string_view Builder::FreshName(std::string_view prefix) { + EnsureUsedNames(); + std::string key(prefix); + int& counter = name_counters_[key]; + for (;;) { + std::string candidate = key + std::to_string(counter++); + if (!used_names_.contains(candidate)) { + std::string_view interned = tree_->Intern(candidate); + used_names_.insert(interned); + return interned; + } + } +} + +void Builder::ReserveNames(const absl::flat_hash_set<std::string_view>& names) { + EnsureUsedNames(); + for (std::string_view name : names) { + if (!used_names_.contains(name)) { + used_names_.insert(tree_->Intern(name)); + } + } +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/builder.h b/deps/v8/experimental/redline/core/builder.h new file mode 100644 index 000000000000..f99ea09c3d44 --- /dev/null +++ b/deps/v8/experimental/redline/core/builder.h @@ -0,0 +1,213 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_BUILDER_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_BUILDER_H_ + +#include <cstdint> +#include <functional> +#include <memory> +#include <string> +#include <string_view> +#include <unordered_map> +#include <vector> + +#include "absl/container/flat_hash_set.h" +#include "experimental/redline/core/random.h" +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/scope.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { + +// Coarse value types used to pick plausible operands and methods. This is +// not a type system; it is a guess derived from declarations. +enum class JsType : uint8_t { + kUnknown, + kNumber, + kString, + kBoolean, + kBigInt, + kSymbol, + kNullish, + kArray, + kObject, + kFunction, + kClass, + kRegExp, + kMap, + kSet, + kPromise, + kTypedArray, + kArrayBuffer, + kDate, + kError, +}; + +const char* JsTypeName(JsType type); + +struct Variable { + std::string_view name; + JsType type = JsType::kUnknown; + fast::Binding* binding = nullptr; // nullptr for globals/builtins + bool is_constant = false; +}; + +// What a mutator may do at a node. +enum class ExpressionRole { + kValue, // an ordinary expression: may be replaced by any expression + kTarget, // assignment target: may only be replaced by another target + kNotReplaceable, // declaration name, property key, label, pattern part, ... +}; + +// A mutable program under construction: a FAST tree plus the analyses and +// editing primitives mutators and generators need. Analyses are recomputed +// lazily after structural edits (Invalidate()). +class Builder { + public: + Builder(fast::Tree* tree, Random* rng); + ~Builder(); + Builder(const Builder&) = delete; + Builder& operator=(const Builder&) = delete; + + fast::Tree* tree() { return tree_; } + Random& rng() { return *rng_; } + fast::Program* root() { return tree_->root(); } + + // Scope analysis and parent map, (re)computed on demand. + fast::ScopeAnalysis& scopes(); + fast::Node* ParentOf(fast::Node* node); + // Must be called after every structural edit done outside the Builder's + // own primitives. + void Invalidate(); + + // --- statement lists ------------------------------------------------------ + + // A position in a statement list: `index` may equal list->size() for an + // insertion at the end. + struct Slot { + std::vector<fast::Statement*>* list = nullptr; + size_t index = 0; + fast::Node* owner = + nullptr; // Program, BlockStatement, SwitchCase, StaticBlock + bool valid() const { return list != nullptr; } + fast::Statement* statement() const { + return index < list->size() ? (*list)[index] : nullptr; + } + }; + + // Every insertion point (after directive prologues). + std::vector<Slot> InsertionSlots(); + // Every existing statement position. + std::vector<Slot> StatementSlots(); + Slot RandomInsertionSlot(); + Slot RandomStatementSlot(); + // The slot holding `statement`, if it sits in a statement list. + Slot SlotOf(fast::Statement* statement); + + // Inserts `statement` at `slot` (anchoring its source positions so that + // scope analysis orders it correctly) and invalidates analyses. + void Insert(const Slot& slot, fast::Statement* statement); + void InsertAll(const Slot& slot, + const std::vector<fast::Statement*>& statements); + fast::Statement* Remove(const Slot& slot); + // Replaces `old_node` with `new_node` wherever it is referenced from its + // parent. Returns false if `old_node` has no parent. + bool Replace(fast::Node* old_node, fast::Node* new_node); + // Replaces a single-statement body (if/loop body) by a block so that more + // statements can be inserted next to it. Returns the slot of the original + // statement inside the new block. + Slot Blockify(fast::Statement* statement); + + // --- node queries --------------------------------------------------------- + + std::vector<fast::Node*> Collect( + const std::function<bool(fast::Node*)>& pred); + fast::Node* RandomNode(const std::function<bool(fast::Node*)>& pred); + // Expression nodes in value position (see ExpressionRole). + std::vector<fast::Expression*> ValueExpressions(); + ExpressionRole RoleOf(fast::Node* node); + // The nearest enclosing statement of `node`. + fast::Statement* EnclosingStatement(fast::Node* node); + // The nearest enclosing function-like node, or nullptr at the top level. + fast::Node* EnclosingFunction(fast::Node* node); + + // --- syntactic context ---------------------------------------------------- + + struct Context { + bool strict = false; + bool in_function = false; // `return` allowed + bool in_async = false; // `await` allowed + bool in_generator = false; // `yield` allowed + bool in_loop = false; // `continue` allowed (`break` too) + bool in_switch = false; // `break` allowed + bool in_method = false; // `super.x` allowed + bool in_constructor = false; // `super()` allowed (if derived) + bool has_super_class = false; + bool in_static_block = false; + bool in_class_field = false; + bool has_this = true; // `this` meaningful (always syntactically ok) + bool has_arguments = false; // inside a non-arrow function + std::vector<std::string_view> labels; // enclosing labels + bool break_allowed() const { return in_loop || in_switch; } + }; + Context ContextAt(fast::Node* node); + Context ContextAtSlot(const Slot& slot); + + // --- variables ------------------------------------------------------------ + + // Bindings visible at `node`, innermost first, with type guesses. + std::vector<Variable> VisibleAt(fast::Node* node); + std::vector<Variable> VisibleAtSlot(const Slot& slot); + // Variables of (roughly) the given type among `candidates`. + static std::vector<Variable> OfType(const std::vector<Variable>& candidates, + JsType type); + JsType GuessType(const fast::Binding* binding); + static JsType GuessType(const fast::Expression* expression); + + // Bindings that are declared (only) inside `nodes` and referenced outside + // them: removing the nodes, or moving them into a block, would turn those + // references into ReferenceErrors. With `block_scoped_only`, `var` + // bindings are ignored (they stay visible when hoisted out of a block + // that is not a function). + std::vector<fast::Binding*> EscapingBindings( + const std::vector<fast::Node*>& nodes, bool block_scoped_only); + + // --- names ---------------------------------------------------------------- + + // A name of the form <prefix><n> unused anywhere in the program. + std::string_view FreshName(std::string_view prefix = "v"); + // Marks `names` as taken for FreshName() (e.g. the names of a splice + // donor). The views may point anywhere; they are copied into the tree. + void ReserveNames(const absl::flat_hash_set<std::string_view>& names); + + // Node id of the next synthesized node (for anchoring/logging). + uint32_t id_limit() const { return tree_->id_limit(); } + + private: + void EnsureAnalysis(); + void BuildParentMap(); + void EnsureUsedNames(); + Variable ToVariable(fast::Binding* binding); + static int LeadingDirectives(const std::vector<fast::Statement*>& list); + fast::Node* AnchorNodeFor(const Slot& slot, int32_t* position); + template <typename F> + void ForEachStatementList(F&& f); + + fast::Tree* tree_; + Random* rng_; + std::unique_ptr<fast::ScopeAnalysis> scopes_; + // Parent of each node, indexed by Node::id (nullptr for the root and for + // nodes created after the map was built). + std::vector<fast::Node*> parents_; + bool parents_valid_ = false; + // Names FreshName() must avoid; all views are interned in tree_. + absl::flat_hash_set<std::string_view> used_names_; + bool used_names_valid_ = false; + std::unordered_map<std::string, int> name_counters_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_BUILDER_H_ diff --git a/deps/v8/experimental/redline/core/component.cc b/deps/v8/experimental/redline/core/component.cc new file mode 100644 index 000000000000..5aee6d30ac64 --- /dev/null +++ b/deps/v8/experimental/redline/core/component.cc @@ -0,0 +1,42 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/component.h" + +#include "experimental/redline/base/log.h" + +namespace redline { + +std::string FormatStatsTable(std::string_view title, + const std::vector<const Component*>& components) { + std::string out = StringPrintf( + "%.*s\n %-26s %9s %9s %7s %9s %6s %6s %6s %6s %6s %7s %9s %8s\n", + static_cast<int>(title.size()), title.data(), "component", "invoked", + "produced", "invalid", "executed", "ok%", "fail", "tmo", "crash", "new", + "edges", "spent", "ms"); + for (const Component* component : components) { + ComponentStats::Snapshot s = component->stats().snapshot(); + if (s.invocations == 0) { + continue; + } + out += StringPrintf( + " %-26s %9llu %9llu %7llu %9llu %5.1f%% %6llu %6llu %6llu %6llu %7llu " + "%9llu %8llu\n", + component->name().c_str(), + static_cast<unsigned long long>(s.invocations), + static_cast<unsigned long long>(s.produced), + static_cast<unsigned long long>(s.invalid), + static_cast<unsigned long long>(s.executed), s.success_rate(), + static_cast<unsigned long long>(s.failed), + static_cast<unsigned long long>(s.timed_out), + static_cast<unsigned long long>(s.crashed), + static_cast<unsigned long long>(s.interesting), + static_cast<unsigned long long>(s.new_edges), + static_cast<unsigned long long>(s.spent), + static_cast<unsigned long long>(s.time_us / 1000)); + } + return out; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/component.h b/deps/v8/experimental/redline/core/component.h new file mode 100644 index 000000000000..a5bf8109347a --- /dev/null +++ b/deps/v8/experimental/redline/core/component.h @@ -0,0 +1,83 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_COMPONENT_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_COMPONENT_H_ + +#include <atomic> +#include <cstdint> +#include <string> +#include <string_view> +#include <vector> + +namespace redline { + +// Counters every pluggable component (mutator, generator, reducer, +// scheduler) keeps by default. They are the data behind the periodic stats +// table and the `--stats` output of the CLI commands. +struct ComponentStats { + std::atomic<uint64_t> invocations{0}; // times the component was asked + std::atomic<uint64_t> produced{0}; // ... and produced a result + std::atomic<uint64_t> invalid{0}; // result rejected by the V8 parser + std::atomic<uint64_t> executed{0}; // results executed in the target + std::atomic<uint64_t> succeeded{0}; + std::atomic<uint64_t> failed{0}; + std::atomic<uint64_t> timed_out{0}; + std::atomic<uint64_t> crashed{0}; + std::atomic<uint64_t> interesting{0}; // results with new deterministic edges + std::atomic<uint64_t> time_us{0}; // time spent inside the component + // New deterministic edges of the corpus programs credited to the component. + std::atomic<uint64_t> new_edges{0}; + // All target executions the component caused: its results, the instrumented + // runs of a runtime-assisted mutator, and the determinism re-runs and + // minimizer probes of its candidates (the engine decides what it credits). + std::atomic<uint64_t> spent{0}; + + struct Snapshot { + uint64_t invocations, produced, invalid, executed, succeeded, failed, + timed_out, crashed, interesting, time_us, new_edges, spent; + double success_rate() const { + return executed ? 100.0 * static_cast<double>(succeeded) / + static_cast<double>(executed) + : 0.0; + } + double interesting_rate() const { + return executed ? 100.0 * static_cast<double>(interesting) / + static_cast<double>(executed) + : 0.0; + } + }; + Snapshot snapshot() const { + return {invocations.load(), produced.load(), invalid.load(), + executed.load(), succeeded.load(), failed.load(), + timed_out.load(), crashed.load(), interesting.load(), + time_us.load(), new_edges.load(), spent.load()}; + } +}; + +class Component { + public: + explicit Component(std::string name) : name_(std::move(name)) {} + virtual ~Component() = default; + Component(const Component&) = delete; + Component& operator=(const Component&) = delete; + + const std::string& name() const { return name_; } + ComponentStats& stats() { return stats_; } + const ComponentStats& stats() const { return stats_; } + // One line of help for `redline help` / the shell. + virtual std::string_view description() const { return ""; } + + private: + std::string name_; + ComponentStats stats_; +}; + +// Renders a stats table (one row per component) for logging. +std::string FormatStatsTable(std::string_view title, + const std::vector<const Component*>& components); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_COMPONENT_H_ diff --git a/deps/v8/experimental/redline/core/environment.cc b/deps/v8/experimental/redline/core/environment.cc new file mode 100644 index 000000000000..3f5b624ede61 --- /dev/null +++ b/deps/v8/experimental/redline/core/environment.cc @@ -0,0 +1,823 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/environment.h" + +#include <cmath> +#include <limits> + +#include "experimental/redline/base/json_parser.h" + +namespace redline { + +namespace { + +using T = JsType; + +BuiltinFunction F(std::string_view name, int min_args, int max_args, + JsType result, JsType a0 = T::kUnknown, + JsType a1 = T::kUnknown, JsType a2 = T::kUnknown) { + BuiltinFunction f{name, min_args, max_args, result}; + f.args[0] = a0; + f.args[1] = a1; + f.args[2] = a2; + return f; +} + +} // namespace + +// static +const Environment& Environment::Default() { + static const Environment* instance = new Environment(); + return *instance; +} + +Environment::Environment() { + // --- values by type ------------------------------------------------------- + types_ = { + {T::kArray, + {F("push", 0, 3, T::kNumber), + F("pop", 0, 0, T::kUnknown), + F("shift", 0, 0, T::kUnknown), + F("unshift", 0, 3, T::kNumber), + F("slice", 0, 2, T::kArray, T::kNumber, T::kNumber), + F("splice", 1, 3, T::kArray, T::kNumber, T::kNumber), + F("concat", 0, 2, T::kArray), + F("join", 0, 1, T::kString, T::kString), + F("reverse", 0, 0, T::kArray), + F("sort", 0, 1, T::kArray, T::kFunction), + F("indexOf", 1, 2, T::kNumber), + F("includes", 1, 2, T::kBoolean), + F("map", 1, 1, T::kArray, T::kFunction), + F("filter", 1, 1, T::kArray, T::kFunction), + F("forEach", 1, 1, T::kNullish, T::kFunction), + F("reduce", 1, 2, T::kUnknown, T::kFunction), + F("some", 1, 1, T::kBoolean, T::kFunction), + F("every", 1, 1, T::kBoolean, T::kFunction), + F("find", 1, 1, T::kUnknown, T::kFunction), + F("findIndex", 1, 1, T::kNumber, T::kFunction), + F("findLast", 1, 1, T::kUnknown, T::kFunction), + F("fill", 1, 3, T::kArray, T::kUnknown, T::kNumber, T::kNumber), + F("flat", 0, 1, T::kArray, T::kNumber), + F("flatMap", 1, 1, T::kArray, T::kFunction), + F("at", 1, 1, T::kUnknown, T::kNumber), + F("keys", 0, 0, T::kObject), + F("values", 0, 0, T::kObject), + F("entries", 0, 0, T::kObject), + F("copyWithin", 2, 3, T::kArray, T::kNumber, T::kNumber), + F("lastIndexOf", 1, 1, T::kNumber), + F("toString", 0, 0, T::kString), + F("toSorted", 0, 1, T::kArray, T::kFunction), + F("toReversed", 0, 0, T::kArray), + F("with", 2, 2, T::kArray, T::kNumber)}, + {"length", "0", "1", "constructor"}}, + {T::kString, + {F("charAt", 1, 1, T::kString, T::kNumber), + F("charCodeAt", 1, 1, T::kNumber, T::kNumber), + F("codePointAt", 1, 1, T::kNumber, T::kNumber), + F("concat", 1, 2, T::kString, T::kString), + F("indexOf", 1, 2, T::kNumber, T::kString), + F("includes", 1, 1, T::kBoolean, T::kString), + F("startsWith", 1, 1, T::kBoolean, T::kString), + F("endsWith", 1, 1, T::kBoolean, T::kString), + F("slice", 1, 2, T::kString, T::kNumber, T::kNumber), + F("substring", 1, 2, T::kString, T::kNumber, T::kNumber), + F("substr", 1, 2, T::kString, T::kNumber, T::kNumber), + F("split", 0, 2, T::kArray, T::kString, T::kNumber), + F("replace", 2, 2, T::kString, T::kUnknown, T::kUnknown), + F("replaceAll", 2, 2, T::kString, T::kString, T::kString), + F("repeat", 1, 1, T::kString, T::kNumber), + F("padStart", 1, 2, T::kString, T::kNumber, T::kString), + F("padEnd", 1, 2, T::kString, T::kNumber, T::kString), + F("trim", 0, 0, T::kString), + F("toUpperCase", 0, 0, T::kString), + F("toLowerCase", 0, 0, T::kString), + F("at", 1, 1, T::kString, T::kNumber), + F("match", 1, 1, T::kUnknown, T::kRegExp), + F("matchAll", 1, 1, T::kObject, T::kRegExp), + F("search", 1, 1, T::kNumber, T::kRegExp), + F("localeCompare", 1, 1, T::kNumber, T::kString), + F("normalize", 0, 1, T::kString), + F("valueOf", 0, 0, T::kString), + F("toString", 0, 0, T::kString), + F("isWellFormed", 0, 0, T::kBoolean)}, + {"length", "0", "constructor"}}, + {T::kNumber, + {F("toString", 0, 1, T::kString, T::kNumber), + F("toFixed", 0, 1, T::kString, T::kNumber), + F("toPrecision", 0, 1, T::kString, T::kNumber), + F("toExponential", 0, 1, T::kString, T::kNumber), + F("valueOf", 0, 0, T::kNumber)}, + {}}, + {T::kBigInt, + {F("toString", 0, 1, T::kString, T::kNumber), + F("valueOf", 0, 0, T::kBigInt)}, + {}}, + {T::kObject, + {F("hasOwnProperty", 1, 1, T::kBoolean, T::kString), + F("toString", 0, 0, T::kString), F("valueOf", 0, 0, T::kUnknown), + F("isPrototypeOf", 1, 1, T::kBoolean), + F("propertyIsEnumerable", 1, 1, T::kBoolean, T::kString)}, + {"a", "b", "c", "x", "y", "length", "constructor", "__proto__", + "valueOf", "toString", "0", "1", "name"}}, + {T::kFunction, + {F("call", 0, 3, T::kUnknown), + F("apply", 0, 2, T::kUnknown, T::kUnknown, T::kArray), + F("bind", 0, 2, T::kFunction), F("toString", 0, 0, T::kString)}, + {"length", "name", "prototype"}}, + {T::kClass, + {F("toString", 0, 0, T::kString)}, + {"prototype", "name", "length"}}, + {T::kRegExp, + {F("test", 1, 1, T::kBoolean, T::kString), + F("exec", 1, 1, T::kUnknown, T::kString), + F("toString", 0, 0, T::kString)}, + {"lastIndex", "source", "flags", "global", "sticky"}}, + {T::kMap, + {F("get", 1, 1, T::kUnknown), F("set", 2, 2, T::kMap), + F("has", 1, 1, T::kBoolean), F("delete", 1, 1, T::kBoolean), + F("clear", 0, 0, T::kNullish), F("keys", 0, 0, T::kObject), + F("values", 0, 0, T::kObject), F("entries", 0, 0, T::kObject), + F("forEach", 1, 1, T::kNullish, T::kFunction)}, + {"size"}}, + {T::kSet, + {F("add", 1, 1, T::kSet), F("has", 1, 1, T::kBoolean), + F("delete", 1, 1, T::kBoolean), F("clear", 0, 0, T::kNullish), + F("values", 0, 0, T::kObject), + F("forEach", 1, 1, T::kNullish, T::kFunction), + F("union", 1, 1, T::kSet, T::kSet), + F("intersection", 1, 1, T::kSet, T::kSet)}, + {"size"}}, + {T::kPromise, + {F("then", 1, 2, T::kPromise, T::kFunction, T::kFunction), + F("catch", 1, 1, T::kPromise, T::kFunction), + F("finally", 1, 1, T::kPromise, T::kFunction)}, + {}}, + {T::kTypedArray, + {F("fill", 1, 3, T::kTypedArray, T::kNumber, T::kNumber, T::kNumber), + F("set", 1, 2, T::kNullish, T::kArray, T::kNumber), + F("subarray", 0, 2, T::kTypedArray, T::kNumber, T::kNumber), + F("slice", 0, 2, T::kTypedArray, T::kNumber, T::kNumber), + F("map", 1, 1, T::kTypedArray, T::kFunction), + F("sort", 0, 1, T::kTypedArray), + F("indexOf", 1, 1, T::kNumber, T::kNumber), F("join", 0, 1, T::kString), + F("reverse", 0, 0, T::kTypedArray), + F("at", 1, 1, T::kNumber, T::kNumber), + F("copyWithin", 2, 3, T::kTypedArray, T::kNumber, T::kNumber)}, + {"length", "byteLength", "byteOffset", "buffer", "0", "1"}}, + {T::kArrayBuffer, + {F("slice", 0, 2, T::kArrayBuffer, T::kNumber, T::kNumber), + F("resize", 1, 1, T::kNullish, T::kNumber), + F("transfer", 0, 1, T::kArrayBuffer, T::kNumber), + F("grow", 1, 1, T::kNullish, T::kNumber)}, + {"byteLength", "maxByteLength", "resizable", "detached", "growable"}}, + {T::kDate, + {F("getTime", 0, 0, T::kNumber), F("getFullYear", 0, 0, T::kNumber), + F("toISOString", 0, 0, T::kString), + F("setTime", 1, 1, T::kNumber, T::kNumber), + F("valueOf", 0, 0, T::kNumber)}, + {}}, + {T::kError, + {F("toString", 0, 0, T::kString)}, + {"message", "name", "stack"}}, + {T::kSymbol, {F("toString", 0, 0, T::kString)}, {"description"}}, + }; + + // --- globals -------------------------------------------------------------- + globals_ = { + {"Object", + T::kClass, + true, + T::kObject, + 0, + 1, + {F("keys", 1, 1, T::kArray, T::kObject), + F("values", 1, 1, T::kArray, T::kObject), + F("entries", 1, 1, T::kArray, T::kObject), + F("assign", 1, 3, T::kObject, T::kObject, T::kObject), + F("freeze", 1, 1, T::kObject, T::kObject), + F("seal", 1, 1, T::kObject, T::kObject), + F("preventExtensions", 1, 1, T::kObject, T::kObject), + F("isFrozen", 1, 1, T::kBoolean), + F("create", 1, 2, T::kObject, T::kObject), + F("getPrototypeOf", 1, 1, T::kObject, T::kObject), + F("setPrototypeOf", 2, 2, T::kObject, T::kObject, T::kObject), + F("defineProperty", 3, 3, T::kObject, T::kObject, T::kString, + T::kObject), + F("getOwnPropertyNames", 1, 1, T::kArray, T::kObject), + F("getOwnPropertyDescriptor", 2, 2, T::kObject, T::kObject, T::kString), + F("fromEntries", 1, 1, T::kObject, T::kArray), + F("groupBy", 2, 2, T::kObject, T::kArray, T::kFunction), + F("is", 2, 2, T::kBoolean), + F("hasOwn", 2, 2, T::kBoolean, T::kObject, T::kString)}, + {"prototype"}}, + {"Array", + T::kClass, + true, + T::kArray, + 0, + 3, + {F("from", 1, 2, T::kArray, T::kUnknown, T::kFunction), + F("of", 0, 3, T::kArray), F("isArray", 1, 1, T::kBoolean)}, + {"prototype"}}, + {"Function", T::kClass, true, T::kFunction, 0, 2, {}, {"prototype"}}, + {"String", + T::kClass, + false, + T::kString, + 0, + 1, + {F("fromCharCode", 0, 3, T::kString, T::kNumber, T::kNumber, T::kNumber), + F("fromCodePoint", 0, 2, T::kString, T::kNumber, T::kNumber), + F("raw", 1, 1, T::kString, T::kObject)}, + {"prototype"}}, + {"Number", + T::kClass, + false, + T::kNumber, + 0, + 1, + {F("isInteger", 1, 1, T::kBoolean), + F("isSafeInteger", 1, 1, T::kBoolean), F("isNaN", 1, 1, T::kBoolean), + F("isFinite", 1, 1, T::kBoolean), + F("parseFloat", 1, 1, T::kNumber, T::kString), + F("parseInt", 1, 2, T::kNumber, T::kString, T::kNumber)}, + {"MAX_SAFE_INTEGER", "MIN_SAFE_INTEGER", "MAX_VALUE", "MIN_VALUE", + "EPSILON", "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY"}}, + {"Boolean", T::kClass, false, T::kBoolean, 0, 1, {}, {}}, + {"Symbol", + T::kFunction, + false, + T::kSymbol, + 0, + 1, + {F("for", 1, 1, T::kSymbol, T::kString)}, + {"iterator", "asyncIterator", "hasInstance", "toPrimitive", + "toStringTag", "species", "isConcatSpreadable", "match", "replace", + "split", "unscopables", "dispose"}}, + {"BigInt", + T::kFunction, + false, + T::kBigInt, + 1, + 1, + {F("asIntN", 2, 2, T::kBigInt, T::kNumber, T::kBigInt), + F("asUintN", 2, 2, T::kBigInt, T::kNumber, T::kBigInt)}, + {}}, + {"Math", + T::kObject, + false, + T::kObject, + 0, + 0, + {F("abs", 1, 1, T::kNumber, T::kNumber), + F("floor", 1, 1, T::kNumber, T::kNumber), + F("ceil", 1, 1, T::kNumber, T::kNumber), + F("round", 1, 1, T::kNumber, T::kNumber), + F("trunc", 1, 1, T::kNumber, T::kNumber), + F("sign", 1, 1, T::kNumber, T::kNumber), + F("sqrt", 1, 1, T::kNumber, T::kNumber), + F("cbrt", 1, 1, T::kNumber, T::kNumber), + F("pow", 2, 2, T::kNumber, T::kNumber, T::kNumber), + F("max", 0, 3, T::kNumber, T::kNumber, T::kNumber, T::kNumber), + F("min", 0, 3, T::kNumber, T::kNumber, T::kNumber, T::kNumber), + F("random", 0, 0, T::kNumber), + F("sin", 1, 1, T::kNumber, T::kNumber), + F("cos", 1, 1, T::kNumber, T::kNumber), + F("atan2", 2, 2, T::kNumber, T::kNumber, T::kNumber), + F("log", 1, 1, T::kNumber, T::kNumber), + F("exp", 1, 1, T::kNumber, T::kNumber), + F("imul", 2, 2, T::kNumber, T::kNumber, T::kNumber), + F("clz32", 1, 1, T::kNumber, T::kNumber), + F("fround", 1, 1, T::kNumber, T::kNumber), + F("hypot", 0, 3, T::kNumber, T::kNumber, T::kNumber, T::kNumber), + F("f16round", 1, 1, T::kNumber, T::kNumber)}, + {"PI", "E", "LN2", "SQRT2"}}, + {"JSON", + T::kObject, + false, + T::kObject, + 0, + 0, + {F("stringify", 1, 3, T::kString), + F("parse", 1, 2, T::kUnknown, T::kString, T::kFunction), + F("rawJSON", 1, 1, T::kObject, T::kString)}, + {}}, + {"Reflect", + T::kObject, + false, + T::kObject, + 0, + 0, + {F("get", 2, 3, T::kUnknown, T::kObject, T::kString), + F("set", 3, 3, T::kBoolean, T::kObject, T::kString), + F("has", 2, 2, T::kBoolean, T::kObject, T::kString), + F("ownKeys", 1, 1, T::kArray, T::kObject), + F("apply", 3, 3, T::kUnknown, T::kFunction, T::kUnknown, T::kArray), + F("construct", 2, 3, T::kObject, T::kClass, T::kArray), + F("defineProperty", 3, 3, T::kBoolean, T::kObject, T::kString, + T::kObject), + F("deleteProperty", 2, 2, T::kBoolean, T::kObject, T::kString), + F("getPrototypeOf", 1, 1, T::kObject, T::kObject), + F("setPrototypeOf", 2, 2, T::kBoolean, T::kObject, T::kObject)}, + {}}, + {"Map", + T::kClass, + true, + T::kMap, + 0, + 1, + {F("groupBy", 2, 2, T::kMap, T::kArray, T::kFunction)}, + {}}, + {"Set", T::kClass, true, T::kSet, 0, 1, {}, {}}, + {"WeakMap", T::kClass, true, T::kMap, 0, 1, {}, {}}, + {"WeakSet", T::kClass, true, T::kSet, 0, 1, {}, {}}, + {"WeakRef", T::kClass, true, T::kObject, 1, 1, {}, {}}, + {"FinalizationRegistry", T::kClass, true, T::kObject, 1, 1, {}, {}}, + {"Promise", + T::kClass, + true, + T::kPromise, + 1, + 1, + {F("resolve", 0, 1, T::kPromise), F("reject", 0, 1, T::kPromise), + F("all", 1, 1, T::kPromise, T::kArray), + F("allSettled", 1, 1, T::kPromise, T::kArray), + F("race", 1, 1, T::kPromise, T::kArray), + F("any", 1, 1, T::kPromise, T::kArray), + F("withResolvers", 0, 0, T::kObject), + F("try", 1, 2, T::kPromise, T::kFunction)}, + {}}, + {"RegExp", T::kClass, true, T::kRegExp, 1, 2, {}, {}}, + {"Date", + T::kClass, + true, + T::kDate, + 0, + 1, + {F("now", 0, 0, T::kNumber)}, + {}}, + {"Error", + T::kClass, + true, + T::kError, + 0, + 2, + {F("captureStackTrace", 1, 1, T::kNullish, T::kObject)}, + {}}, + {"TypeError", T::kClass, true, T::kError, 0, 1, {}, {}}, + {"RangeError", T::kClass, true, T::kError, 0, 1, {}, {}}, + {"ArrayBuffer", + T::kClass, + true, + T::kArrayBuffer, + 1, + 2, + {F("isView", 1, 1, T::kBoolean)}, + {}}, + {"SharedArrayBuffer", T::kClass, true, T::kArrayBuffer, 1, 2, {}, {}}, + {"DataView", T::kClass, true, T::kObject, 1, 3, {}, {}}, + {"Uint8Array", + T::kClass, + true, + T::kTypedArray, + 0, + 3, + {F("from", 1, 1, T::kTypedArray, T::kArray), + F("of", 0, 3, T::kTypedArray, T::kNumber, T::kNumber, T::kNumber)}, + {"BYTES_PER_ELEMENT"}}, + {"Int8Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Uint8ClampedArray", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Int16Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Uint16Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Int32Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Uint32Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Float32Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Float64Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"BigInt64Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"BigUint64Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Float16Array", T::kClass, true, T::kTypedArray, 0, 3, {}, {}}, + {"Proxy", + T::kClass, + true, + T::kObject, + 2, + 2, + {F("revocable", 2, 2, T::kObject, T::kObject, T::kObject)}, + {}}, + {"Atomics", + T::kObject, + false, + T::kObject, + 0, + 0, + {F("add", 3, 3, T::kNumber, T::kTypedArray, T::kNumber, T::kNumber), + F("load", 2, 2, T::kNumber, T::kTypedArray, T::kNumber), + F("store", 3, 3, T::kNumber, T::kTypedArray, T::kNumber, T::kNumber), + F("compareExchange", 4, 4, T::kNumber, T::kTypedArray, T::kNumber, + T::kNumber)}, + {}}, + {"Iterator", + T::kClass, + false, + T::kObject, + 0, + 0, + {F("from", 1, 1, T::kObject)}, + {"prototype"}}, + {"globalThis", T::kObject, false, T::kObject, 0, 0, {}, {}}, + {"parseInt", T::kFunction, false, T::kNumber, 1, 2, {}, {}}, + {"parseFloat", T::kFunction, false, T::kNumber, 1, 1, {}, {}}, + {"isNaN", T::kFunction, false, T::kBoolean, 1, 1, {}, {}}, + {"isFinite", T::kFunction, false, T::kBoolean, 1, 1, {}, {}}, + {"encodeURIComponent", T::kFunction, false, T::kString, 1, 1, {}, {}}, + {"decodeURIComponent", T::kFunction, false, T::kString, 1, 1, {}, {}}, + {"escape", T::kFunction, false, T::kString, 1, 1, {}, {}}, + {"gc", T::kFunction, false, T::kNullish, 0, 1, {}, {}}, + }; + + // --- natives (all safe with --fuzzing) + // -------------------------------------- + natives_ = { + {"PrepareFunctionForOptimization", 1, T::kFunction}, + {"OptimizeFunctionOnNextCall", 1, T::kFunction}, + {"OptimizeMaglevOnNextCall", 1, T::kFunction}, + {"CompileBaseline", 1, T::kFunction}, + {"DeoptimizeFunction", 1, T::kFunction}, + {"DeoptimizeNow", 0, T::kUnknown}, + {"NeverOptimizeFunction", 1, T::kFunction}, + {"OptimizeOsr", 0, T::kUnknown}, + {"BaselineOsr", 0, T::kUnknown}, + {"SimulateNewspaceFull", 0, T::kUnknown}, + {"ArrayBufferDetach", 1, T::kArrayBuffer}, + {"HaveSameMap", 2, T::kObject}, + {"HasFastProperties", 1, T::kObject}, + {"HasSmiElements", 1, T::kArray}, + {"HasDoubleElements", 1, T::kArray}, + {"HasHoleyElements", 1, T::kArray}, + {"HasDictionaryElements", 1, T::kArray}, + {"NormalizeElements", 1, T::kArray}, + {"ToFastProperties", 1, T::kObject}, + {"InternalizeString", 1, T::kString}, + {"ConstructConsString", 2, T::kString}, + {"ConstructSlicedString", 2, T::kString}, + {"FlattenString", 1, T::kString}, + {"IsBeingInterpreted", 0, T::kUnknown}, + {"PretenureAllocationSite", 1, T::kObject}, + {"SetAllocationTimeout", 2, T::kNumber}, + }; + + property_names_ = {"a", + "b", + "c", + "d", + "x", + "y", + "z", + "foo", + "bar", + "baz", + "length", + "name", + "value", + "valueOf", + "toString", + "constructor", + "prototype", + "__proto__", + "get", + "set", + "then", + "next", + "done", + "0", + "1", + "2", + "100", + "4294967295", + "-1", + "1.5", + "key", + "size", + "callee", + "caller", + "arguments", + "Symbol.iterator", + "Symbol.toPrimitive", + "Symbol.hasInstance", + "Symbol.species"}; + + numbers_ = {0, + -0.0, + 1, + -1, + 2, + 3, + 4, + 7, + 8, + 10, + 16, + 31, + 32, + 42, + 63, + 64, + 100, + 127, + 128, + 255, + 256, + 1000, + 1023, + 1024, + 4095, + 4096, + 65535, + 65536, + 1e5, + 1e6, + 16777215, + 16777216, + 2147483647, + 2147483648, + -2147483648, + -2147483649, + 4294967295, + 4294967296, + 1e10, + 9007199254740991, + 9007199254740992, + -9007199254740991, + 1e21, + 1e300, + 1.7976931348623157e308, + 5e-324, + 2.2250738585072014e-308, + 0.1, + 0.5, + 1.5, + -1.5, + 0.3, + 1 / 3.0, + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::infinity(), + -std::numeric_limits<double>::infinity()}; + + strings_ = {"", + "a", + "ab", + "abc", + "foo", + "bar", + "0", + "1", + "-1", + "1.5", + "NaN", + "undefined", + "null", + "true", + "length", + "constructor", + "__proto__", + "valueOf", + "toString", + "prototype", + "hello world", + "\xC3\xA9\xC3\xA8\xC3\xA0", + "\xE2\x82\xAC", + "\xF0\x9F\x98\x80", + "\\u0000", + " ", + "\t\n", + "x", + "\x7F", + "\\n"}; + + regexps_ = {{"a", ""}, {"(a|b)*", "g"}, {"\\d+", "u"}, + {"^$", "m"}, {"[a-z]+", "gi"}, {"(?<x>a)\\k<x>", ""}, + {".", "s"}, {"a*?", "y"}, {"\\p{L}", "v"}, + {"(?:)", "d"}}; +} // NOLINT(readability/fn_size) + +const BuiltinType* Environment::ForType(JsType type) const { + for (const BuiltinType& t : types_) { + if (t.type == type) { + return &t; + } + } + return nullptr; +} + +const BuiltinGlobal* Environment::Global(std::string_view name) const { + for (const BuiltinGlobal& g : globals_) { + if (g.name == name) { + return &g; + } + } + return nullptr; +} + +std::vector<const BuiltinGlobal*> Environment::ConstructorsOf( + JsType type) const { + std::vector<const BuiltinGlobal*> result; + for (const BuiltinGlobal& g : globals_) { + if (g.constructible && g.instance_type == type) { + result.push_back(&g); + } + } + return result; +} + +size_t Environment::discovered_member_count() const { + size_t n = 0; + for (const DiscoveredApi& api : discovered_) { + n += api.statics.size() + api.methods.size() + api.getters.size(); + } + return n; +} + +std::string_view Environment::Intern(std::string_view text) { + owned_strings_.emplace_back(text); + return owned_strings_.back(); +} + +// static +std::string_view Environment::IntrospectionScript() { + // Printed as one JSON line: [{"p": "Intl.NumberFormat", "k": "C", "a": 0, + // "s": [["supportedLocalesOf", 1]], "m": [["format", 1], ...], "g": + // ["<getter name>", ...]}, ...]. Kinds: F function, C constructor, N + // namespace object. Shell I/O, process control, threads and WebAssembly + // are left out on purpose. + static constexpr char kScript[] = R"js((function() { + const out = []; + const seen = new Set(); + const deny = new Set(['print', 'printErr', 'write', 'quit', 'load', 'read', 'readline', + 'readbuffer', 'os', 'version', 'Worker', 'fuzzilli', 'testRunner', + 'globalThis', 'setTimeout', 'queueMicrotask', 'arguments', '__redline_explore', + 'd8.file', 'd8.log', 'd8.terminate', 'd8.quit', 'd8.debugger', 'd8.profiler', 'd8.dom', 'd8.wasm', + 'Realm.dispose', 'Realm.navigate', 'Realm.detachGlobal', 'performance.measureMemory', + 'Atomics.wait', 'Atomics.waitAsync', 'Atomics.pause']); + function isConstructor(f) { + try { Reflect.construct(function() {}, [], f); return true; } catch (e) { return false; } + } + function members(o, skip) { + const statics = [], getters = []; + let names; + try { names = Object.getOwnPropertyNames(o); } catch (e) { return [statics, getters]; } + for (const n of names) { + if (skip.has(n) || n === 'constructor' || n === 'prototype' || n === '__proto__' || + n === 'caller' || n === 'callee' || n === 'arguments' || n === 'length' || + n === 'name') continue; + let d; + try { d = Object.getOwnPropertyDescriptor(o, n); } catch (e) { continue; } + if (!d) continue; + if (typeof d.get === 'function') { getters.push(n); continue; } + if (typeof d.value === 'function') { + let a = d.value.length; + statics.push([n, (typeof a === 'number' && a >= 0 && a < 10) ? a : 1]); + } + } + return [statics, getters]; + } + function describe(path, v, depth) { + if (seen.has(v)) return; + const t = typeof v; + if (t === 'function') { + seen.add(v); + const ctor = isConstructor(v); + const [statics] = members(v, new Set()); + let methods = [], getters = []; + if (ctor) { + let proto; + try { proto = v.prototype; } catch (e) {} + if (proto && typeof proto === 'object') { + [methods, getters] = members(proto, new Set()); + // Subclasses (typed arrays, errors) inherit their methods from an + // intermediate prototype (%TypedArray%.prototype, Error.prototype). + let parent = null; + try { parent = Object.getPrototypeOf(proto); } catch (e) {} + if (parent && parent !== Object.prototype && parent !== Function.prototype) { + const [pm, pg] = members(parent, new Set()); + methods = methods.concat(pm); + getters = getters.concat(pg); + } + } + } + out.push({p: path, k: ctor ? 'C' : 'F', a: v.length | 0, s: statics, m: methods, g: getters}); + if (depth < 1) nested(path, v, depth); + } else if (t === 'object' && v !== null) { + seen.add(v); + const [statics, getters] = members(v, new Set()); + out.push({p: path, k: 'N', a: 0, s: statics, m: [], g: getters}); + if (depth < 2) nested(path, v, depth); + } + } + // A nested function is worth an entry of its own only if it is a class + // (uppercase name or a prototype with members); plain functions are + // already listed as statics of their namespace. + function isClassLike(f, name) { + if (!isConstructor(f)) return false; + const c = name.charCodeAt(0); + if (c >= 65 && c <= 90) return true; + try { return Object.getOwnPropertyNames(f.prototype).length > 1; } catch (e) { return false; } + } + function nested(path, v, depth) { + let names; + try { names = Object.getOwnPropertyNames(v); } catch (e) { return; } + for (const n of names) { + if (n === 'prototype' || n === 'constructor' || n === '__proto__') continue; + const p = path + '.' + n; + if (deny.has(p)) continue; + let d; + try { d = Object.getOwnPropertyDescriptor(v, n); } catch (e) { continue; } + if (!d || !('value' in d)) continue; + const w = d.value; + if (typeof w === 'object' && w !== null && !Array.isArray(w)) describe(p, w, depth + 1); + else if (typeof w === 'function' && isClassLike(w, n)) describe(p, w, depth + 1); + } + } + const globals = Object.getOwnPropertyNames(globalThis); + for (const n of globals) { + if (deny.has(n)) continue; + let d; + try { d = Object.getOwnPropertyDescriptor(globalThis, n); } catch (e) { continue; } + if (!d || !('value' in d)) continue; + describe(n, d.value, 0); + } + fuzzilli('FUZZILLI_PRINT', JSON.stringify(out)); +})(); +)js"; + return kScript; +} + +// static +std::unique_ptr<Environment> Environment::WithDiscovered( + const std::string& json, std::string* error) { + std::unique_ptr<Environment> env(new Environment()); + auto read_members = [&env](const JsonValue& array, + std::vector<DiscoveredMember>* out) { + if (!array.is_array()) { + return; + } + for (const JsonValue& item : array.as_array()) { + if (item.is_string()) { + out->push_back({env->Intern(item.as_string()), -1}); + } else if (item.is_array() && item.as_array().size() == 2 && + item.as_array()[0].is_string()) { + const JsonValue& arity = item.as_array()[1]; + out->push_back( + {env->Intern(item.as_array()[0].as_string()), + arity.is_number() ? static_cast<int>(arity.as_number()) : 1}); + } + } + }; + JsonValue root; + // The target may have printed other things first; take the last line + // that looks like a JSON array. + size_t start = json.rfind("\n["); + std::string text = start == std::string::npos ? json : json.substr(start + 1); + if (!JsonValue::Parse(text, &root, error)) { + return nullptr; + } + if (!root.is_array()) { + *error = "introspection output is not a JSON array"; + return nullptr; + } + for (const JsonValue& item : root.as_array()) { + if (!item.is_object()) { + continue; + } + DiscoveredApi api; + api.path = env->Intern(item.GetString("p", "")); + if (api.path.empty()) { + continue; + } + std::string kind = item.GetString("k", "N"); + api.kind = kind == "C" ? DiscoveredApi::Kind::kConstructor + : kind == "F" ? DiscoveredApi::Kind::kFunction + : DiscoveredApi::Kind::kNamespace; + api.arity = static_cast<int>(item.GetInt("a", 0)); + if (api.arity < 0 || api.arity > 8) { + api.arity = 1; + } + read_members(item.Get("s"), &api.statics); + read_members(item.Get("m"), &api.methods); + read_members(item.Get("g"), &api.getters); + // Namespaces without anything callable are useless to the generators. + if (api.kind == DiscoveredApi::Kind::kNamespace && api.statics.empty() && + api.getters.empty()) { + continue; + } + env->discovered_.push_back(std::move(api)); + } + if (env->discovered_.empty()) { + *error = "introspection found no usable globals"; + return nullptr; + } + return env; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/environment.h b/deps/v8/experimental/redline/core/environment.h new file mode 100644 index 000000000000..9edc6d979a2d --- /dev/null +++ b/deps/v8/experimental/redline/core/environment.h @@ -0,0 +1,132 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_ENVIRONMENT_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_ENVIRONMENT_H_ + +#include <deque> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/core/builder.h" + +namespace redline { + +// A method or function: name, arity range and result type guess. +struct BuiltinFunction { + std::string_view name; + int min_args = 0; + int max_args = 0; + JsType result = JsType::kUnknown; + // Argument type hints (kUnknown = anything), at most 3 used. + JsType args[3] = {JsType::kUnknown, JsType::kUnknown, JsType::kUnknown}; +}; + +// Methods and properties available on values of a given coarse type. +struct BuiltinType { + JsType type = JsType::kUnknown; + std::vector<BuiltinFunction> methods; + std::vector<std::string_view> properties; +}; + +// A global binding: constructor (Array, Map, ...), namespace (Math, JSON) +// or function (parseInt). +struct BuiltinGlobal { + std::string_view name; + JsType type = JsType::kUnknown; // type of the global itself + bool constructible = false; // `new Name(...)` makes sense + JsType instance_type = JsType::kUnknown; // type of `new Name()` / `Name()` + int min_args = 0; + int max_args = 0; + std::vector<BuiltinFunction> static_methods; + std::vector<std::string_view> static_properties; +}; + +// V8 runtime functions usable with --allow-natives-syntax --fuzzing. +struct NativeFunction { + std::string_view name; + int args = 0; // number of arguments + JsType arg_type = + JsType::kUnknown; // type of the (first) argument, kFunction for most +}; + +// A callable member discovered on the target: a static method, a prototype +// method or a getter (arity -1). +struct DiscoveredMember { + std::string_view name; + int arity = 0; // Function.length; -1 for getters/plain properties +}; + +// A global (or dotted path such as "Intl.NumberFormat" or "d8.test") the +// target exposes, as reported by Environment::IntrospectionScript(). +struct DiscoveredApi { + enum class Kind { kFunction, kConstructor, kNamespace }; + std::string_view path; + Kind kind = Kind::kNamespace; + int arity = 0; // for functions/constructors + std::vector<DiscoveredMember> statics; // own function-valued properties + std::vector<DiscoveredMember> methods; // prototype methods (constructors) + std::vector<DiscoveredMember> getters; // prototype accessors +}; + +// The static model of what d8 offers: a hand-written, typed core (what the +// generators use for type-directed code) plus everything the target itself +// reports about its globals when the session starts (what the DiscoveredApi +// generator and the Explore mutator use to reach builtins nobody modelled). +class Environment { + public: + static const Environment& Default(); + // The hand-written model extended with the target's answer to + // IntrospectionScript() (the JSON it printed on fuzzout). Returns nullptr + // with *error set if the JSON is unusable. + static std::unique_ptr<Environment> WithDiscovered(const std::string& json, + std::string* error); + // JavaScript that enumerates the target's globals and prints them as one + // JSON line via fuzzilli('FUZZILLI_PRINT', ...). + static std::string_view IntrospectionScript(); + + const std::vector<BuiltinGlobal>& globals() const { return globals_; } + const std::vector<BuiltinType>& types() const { return types_; } + const std::vector<NativeFunction>& natives() const { return natives_; } + const std::vector<DiscoveredApi>& discovered() const { return discovered_; } + // Common property names for synthesized objects/accesses. + const std::vector<std::string_view>& property_names() const { + return property_names_; + } + // Interesting numbers, strings and regexps. + const std::vector<double>& numbers() const { return numbers_; } + const std::vector<std::string_view>& strings() const { return strings_; } + const std::vector<std::pair<std::string_view, std::string_view>>& regexps() + const { + return regexps_; + } + + const BuiltinType* ForType(JsType type) const; + const BuiltinGlobal* Global(std::string_view name) const; + // Globals whose instance_type is `type` and that are constructible. + std::vector<const BuiltinGlobal*> ConstructorsOf(JsType type) const; + // Number of discovered members (statics + methods + getters), for logs. + size_t discovered_member_count() const; + + private: + Environment(); + std::string_view Intern(std::string_view text); + + std::vector<BuiltinGlobal> globals_; + std::vector<BuiltinType> types_; + std::vector<NativeFunction> natives_; + std::vector<std::string_view> property_names_; + std::vector<double> numbers_; + std::vector<std::string_view> strings_; + std::vector<std::pair<std::string_view, std::string_view>> regexps_; + std::vector<DiscoveredApi> discovered_; + // Backing storage for the string_views of discovered entries. + std::deque<std::string> owned_strings_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_ENVIRONMENT_H_ diff --git a/deps/v8/experimental/redline/core/program.cc b/deps/v8/experimental/redline/core/program.cc new file mode 100644 index 000000000000..b1762f1453e1 --- /dev/null +++ b/deps/v8/experimental/redline/core/program.cc @@ -0,0 +1,66 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/program.h" + +#include "experimental/redline/fast/parser.h" +#include "experimental/redline/fast/printer.h" + +namespace redline { + +// static +uint64_t Program::HashSource(std::string_view source) { + // FNV-1a 64. + uint64_t h = 0xcbf29ce484222325ull; + for (char ch : source) { + const unsigned char c = static_cast<unsigned char>(ch); + h ^= c; + h *= 0x100000001b3ull; + } + return h; +} + +// static +std::shared_ptr<Program> Program::FromTree(std::unique_ptr<fast::Tree> tree, + Lineage lineage) { + std::string source = fast::Print(tree->root()); + return FromTree(std::move(tree), std::move(lineage), std::move(source)); +} + +// static +std::shared_ptr<Program> Program::FromTree(std::unique_ptr<fast::Tree> tree, + Lineage lineage, + std::string source) { + std::shared_ptr<Program> program(new Program()); + program->tree_ = std::move(tree); + program->source_ = std::move(source); + program->hash_ = HashSource(program->source_); + program->node_count_ = fast::CountNodes(program->tree_->root()); + program->lineage_ = std::move(lineage); + return program; +} + +// static +std::shared_ptr<Program> Program::Parse(std::string_view source, + Lineage lineage, std::string* error) { + fast::ParseError parse_error; + std::unique_ptr<fast::Tree> tree = + fast::Parser::ParseScript(source, fast::ParseOptions(), &parse_error); + if (tree == nullptr) { + if (error != nullptr) { + *error = parse_error.message; + } + return nullptr; + } + return FromTree(std::move(tree), std::move(lineage)); +} + +const fast::ScopeAnalysis& Program::scopes() const { + std::call_once(scopes_once_, [this] { + scopes_ = fast::ScopeAnalysis::Analyze(tree_.get()); + }); + return *scopes_; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/program.h b/deps/v8/experimental/redline/core/program.h new file mode 100644 index 000000000000..54335afe0b9f --- /dev/null +++ b/deps/v8/experimental/redline/core/program.h @@ -0,0 +1,109 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_PROGRAM_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_PROGRAM_H_ + +#include <atomic> +#include <cstdint> +#include <memory> +#include <mutex> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/fast/scope.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { + +// Where a program came from. +struct Lineage { + // "import", "generate", or the name of the mutator that produced it. + std::string origin; + // For imports: the file path. For mutations: the mutator parameters. + std::string detail; + // The immediate parent (which may be an intermediate program of a chain + // of consecutive mutations that never entered the corpus) ... + uint64_t parent_hash = 0; + // ... and the corpus program the chain started from (0: none). + uint32_t parent_id = 0; + // Mutations applied since that corpus program (1: a direct child). + int chain = 0; + // For splice/combine: the second parent. + uint64_t partner_hash = 0; + int generation = 0; + int worker = -1; +}; + +// A JavaScript program held by the fuzzer. Immutable once created: mutators +// copy the tree. Corpus bookkeeping fields (id, edges) are assigned by the +// coordinator before the program is published. +class Program { + public: + // Takes ownership of `tree`; prints it once to obtain the canonical source. + static std::shared_ptr<Program> FromTree(std::unique_ptr<fast::Tree> tree, + Lineage lineage); + // Same, for a caller that already holds Print(tree->root()) (the default + // pretty form): saves printing the tree a second time. + static std::shared_ptr<Program> FromTree(std::unique_ptr<fast::Tree> tree, + Lineage lineage, std::string source); + // Parses `source` (nullptr with `error` set on failure). + static std::shared_ptr<Program> Parse(std::string_view source, + Lineage lineage, std::string* error); + + const fast::Tree& tree() const { return *tree_; } + const std::string& source() const { return source_; } + uint64_t hash() const { return hash_; } + size_t node_count() const { return node_count_; } + const Lineage& lineage() const { return lineage_; } + // Lazily computed scope analysis of the (immutable) tree. + const fast::ScopeAnalysis& scopes() const; + + // A fresh mutable copy of the tree, for mutation. + std::unique_ptr<fast::Tree> CopyTree() const { return tree_->Copy(); } + + // --- corpus bookkeeping (written once by the coordinator) --- + uint32_t id = 0; + // Deterministic edges this program contributed when it was added. + std::vector<uint32_t> edges; + // Edges set by a successful execution (all of them, not only new ones). + uint32_t edges_hit = 0; + uint64_t exec_time_us = 0; + uint64_t added_at_ms = 0; + // All edges the program reaches deterministically (set only when the + // seed strategy asks for it, see Selector::WantsHitEdges). The strategy + // consumes and clears it when the program is added. + mutable std::vector<uint32_t> hit_edges; + + // --- scheduler state (owned by the seed strategy, under the corpus lock) --- + // Edges of this program that were still rare when it was added. + mutable std::vector<uint32_t> rare_edges; + // Uses as a parent (1 each) and as a splice partner (a fraction each). + mutable double age = 0.0; + + // --- scheduler feedback (updated concurrently by workers) --- + // Times this program was picked as a parent for mutation. + mutable std::atomic<uint32_t> picks{0}; + // Mutations of this program that produced a new corpus program. + mutable std::atomic<uint32_t> children{0}; + + static uint64_t HashSource(std::string_view source); + + private: + Program() = default; + std::unique_ptr<fast::Tree> tree_; + std::string source_; + uint64_t hash_ = 0; + size_t node_count_ = 0; + Lineage lineage_; + mutable std::once_flag scopes_once_; + mutable std::unique_ptr<fast::ScopeAnalysis> scopes_; +}; + +using ProgramPtr = std::shared_ptr<const Program>; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_PROGRAM_H_ diff --git a/deps/v8/experimental/redline/core/random.h b/deps/v8/experimental/redline/core/random.h new file mode 100644 index 000000000000..2ab5c49e79d8 --- /dev/null +++ b/deps/v8/experimental/redline/core/random.h @@ -0,0 +1,155 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_RANDOM_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_RANDOM_H_ + +#include <cstddef> +#include <cstdint> +#include <initializer_list> +#include <vector> + +namespace redline { + +// Deterministic pseudo random generator (xoshiro256**). Every worker and +// every command owns one, seeded from the run seed, so that a run can be +// replayed from its event log. +class Random { + public: + explicit Random(uint64_t seed) { Seed(seed); } + + void Seed(uint64_t seed) { + // splitmix64 to spread the seed over the state. + for (uint64_t& word : state_) { + seed += 0x9E3779B97F4A7C15ull; + uint64_t z = seed; + z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; + z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; + word = z ^ (z >> 31); + } + } + + uint64_t Next() { + const uint64_t result = Rotl(state_[1] * 5, 7) * 9; + const uint64_t t = state_[1] << 17; + state_[2] ^= state_[0]; + state_[3] ^= state_[1]; + state_[1] ^= state_[2]; + state_[0] ^= state_[3]; + state_[2] ^= t; + state_[3] = Rotl(state_[3], 45); + return result; + } + + // Uniform in [0, n). n == 0 returns 0. + uint64_t Uniform(uint64_t n) { + if (n == 0) { + return 0; + } + // Lemire's nearly divisionless method. + uint64_t l = 0; + uint64_t h = MulHigh(Next(), n, &l); + if (l < n) { + uint64_t t = (0 - n) % n; + while (l < t) { + h = MulHigh(Next(), n, &l); + } + } + return h; + } + size_t Index(size_t n) { return static_cast<size_t>(Uniform(n)); } + // Uniform in [lo, hi] (inclusive). + int64_t Range(int64_t lo, int64_t hi) { + if (hi <= lo) { + return lo; + } + const uint64_t span = static_cast<uint64_t>(hi) - static_cast<uint64_t>(lo); + if (span == UINT64_MAX) { + return static_cast<int64_t>(Next()); + } + return static_cast<int64_t>(static_cast<uint64_t>(lo) + Uniform(span + 1)); + } + // Uniform in [0, 1). + double Double() { return static_cast<double>(Next() >> 11) * 0x1.0p-53; } + bool Chance(double probability) { return Double() < probability; } + bool Coin() { return (Next() & 1) != 0; } + + template <typename T> + const T& Pick(const std::vector<T>& items) { + return items[Index(items.size())]; + } + template <typename T> + T& Pick(std::vector<T>& items) { + return items[Index(items.size())]; + } + template <typename T> + T Pick(std::initializer_list<T> items) { + return *(items.begin() + Index(items.size())); + } + // Index drawn with the given (non-negative) weights. + size_t Weighted(const std::vector<double>& weights) { + double total = 0; + size_t last_positive = 0; + for (size_t i = 0; i < weights.size(); i++) { + total += weights[i]; + if (weights[i] > 0) { + last_positive = i; + } + } + if (total <= 0) { + return Index(weights.size()); + } + double r = Double() * total; + for (size_t i = 0; i < weights.size(); i++) { + if (r < weights[i]) { + return i; + } + r -= weights[i]; + } + return last_positive; + } + // Geometric-ish small count: 0 with probability 1-p, else 1 + ... + int SmallCount(int max, double continue_probability = 0.5) { + int n = 0; + while (n < max && Chance(continue_probability)) { + n++; + } + return n; + } + + // A fresh generator derived from this one (for sub-tasks that must not + // disturb the main stream). + Random Fork() { return Random(Next()); } + + private: + static uint64_t Rotl(uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } + // Full 64 x 64 -> 128 bit product: returns the high 64 bits and writes + // the low 64 bits to *lo. The portable branch is for 32-bit targets + // (ia32, arm), which have no __uint128_t. Both branches give the same + // result, so a seed gives the same run on every target. + static uint64_t MulHigh(uint64_t a, uint64_t b, uint64_t* lo) { +#if defined(__SIZEOF_INT128__) + const __uint128_t m = static_cast<__uint128_t>(a) * b; + *lo = static_cast<uint64_t>(m); + return static_cast<uint64_t>(m >> 64); +#else + const uint64_t a_lo = a & 0xFFFFFFFFull; + const uint64_t a_hi = a >> 32; + const uint64_t b_lo = b & 0xFFFFFFFFull; + const uint64_t b_hi = b >> 32; + const uint64_t p0 = a_lo * b_lo; + const uint64_t p1 = a_lo * b_hi; + const uint64_t p2 = a_hi * b_lo; + const uint64_t mid = + (p0 >> 32) + (p1 & 0xFFFFFFFFull) + (p2 & 0xFFFFFFFFull); + *lo = (mid << 32) | (p0 & 0xFFFFFFFFull); + return a_hi * b_hi + (p1 >> 32) + (p2 >> 32) + (mid >> 32); +#endif + } + uint64_t state_[4]; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_RANDOM_H_ diff --git a/deps/v8/experimental/redline/core/selection.cc b/deps/v8/experimental/redline/core/selection.cc new file mode 100644 index 000000000000..27452ded9423 --- /dev/null +++ b/deps/v8/experimental/redline/core/selection.cc @@ -0,0 +1,126 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/selection.h" + +#include <string> +#include <vector> + +namespace redline { + +namespace { + +const char* TypeName(ParamSpec::Type type) { + switch (type) { + case ParamSpec::Type::kNumber: + return "number"; + case ParamSpec::Type::kBool: + return "bool"; + case ParamSpec::Type::kString: + return "string"; + case ParamSpec::Type::kObject: + return "object"; + } + return "?"; +} + +bool HasType(const JsonValue& value, ParamSpec::Type type) { + switch (type) { + case ParamSpec::Type::kNumber: + return value.is_number(); + case ParamSpec::Type::kBool: + return value.is_bool(); + case ParamSpec::Type::kString: + return value.is_string(); + case ParamSpec::Type::kObject: + return value.is_object(); + } + return false; +} + +} // namespace + +bool ValidateParams(std::string_view strategy, const JsonValue& params, + const std::vector<ParamSpec>& specs, std::string* error) { + if (params.is_null()) { + return true; + } + std::string prefix = "selection strategy '" + std::string(strategy) + "': "; + if (!params.is_object()) { + *error = prefix + "\"params\" must be an object"; + return false; + } + for (const auto& [key, value] : params.as_object()) { + const ParamSpec* spec = nullptr; + for (const ParamSpec& s : specs) { + if (s.name == key) { + spec = &s; + break; + } + } + if (spec == nullptr) { + std::vector<std::string> known; + known.reserve(specs.size()); + for (const ParamSpec& s : specs) { + known.emplace_back(s.name); + } + *error = prefix; + *error += "unknown parameter '"; + *error += key; + *error += '\''; + if (known.empty()) { + *error += " (it takes no parameters)"; + } else { + *error += " (known: "; + *error += JoinNames(known); + *error += ')'; + } + return false; + } + if (!HasType(value, spec->type)) { + *error = prefix; + *error += "parameter '"; + *error += key; + *error += "' must be a "; + *error += TypeName(spec->type); + return false; + } + } + return true; +} + +bool ReadWeightOverrides(const JsonValue& params, + std::vector<std::pair<std::string, double>>* out, + std::string* error) { + out->clear(); + if (params.is_null() || !params.Has("weights")) { + return true; + } + const JsonValue& weights = params.Get("weights"); + if (!weights.is_object()) { + *error = "\"weights\" must be an object of {\"Name\": number}"; + return false; + } + for (const auto& [name, value] : weights.as_object()) { + if (!value.is_number() || value.as_number() < 0) { + *error = "weight of '" + name + "' must be a non-negative number"; + return false; + } + out->emplace_back(name, value.as_number()); + } + return true; +} + +std::string JoinNames(const std::vector<std::string>& names) { + std::string out; + for (const std::string& n : names) { + if (!out.empty()) { + out += ", "; + } + out += n; + } + return out; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/selection.h b/deps/v8/experimental/redline/core/selection.h new file mode 100644 index 000000000000..c21e3a92dd76 --- /dev/null +++ b/deps/v8/experimental/redline/core/selection.h @@ -0,0 +1,305 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Pluggable selection strategies. +// +// Redline picks four kinds of things while fuzzing: +// +// seeds which corpus program a worker mutates next +// partners which second program Splice/Combine take material from +// mutators which mutator is applied +// generators which generator CodeGen inserts +// +// Each pick goes through a Selector<T>: "choose one eligible candidate among +// N, with the worker's RNG, knowing the candidates' static weights and live +// feedback". Which Selector is used, and with which parameters, comes from +// the configuration: +// +// "selection": { +// "mutators": { "strategy": "weighted", "params": { "weights": { "Splice": +// 4 } } } +// } +// +// Strategies live in a SelectorRegistry<T> under a name, together with the +// list of parameters they accept (ParamSpec). The registry validates the +// configuration (unknown strategy, unknown parameter, wrong type -> error +// before anything runs) and builds the selector. +// +// Adding a strategy for, say, mutators: +// 1. write `class MyStrategy : public Selector<Mutator>` (mutators.cc), +// 2. add one Register() line to +// RegisterBuiltinSelectors(SelectorRegistry<Mutator>&). +// The fuzzing loop, the mutators and the generators do not change. +// +// The default strategies reproduce Redline's historical behaviour exactly; +// `redline selftest --offline` checks that against recorded traces +// (experimental/redline/testdata/selection). + +#ifndef V8_EXPERIMENTAL_REDLINE_CORE_SELECTION_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_SELECTION_H_ + +#include <cstdint> +#include <functional> +#include <limits> +#include <map> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/json_parser.h" +#include "experimental/redline/core/random.h" + +namespace redline { + +// Live, read-only feedback about a candidate. Mutators and generators fill it +// from their ComponentStats, corpus programs from their pick/children +// counters. A strategy may use it to prefer or avoid candidates. +struct Feedback { + uint64_t attempts = 0; // times the candidate was picked / invoked + uint64_t produced = 0; // ... and produced something that could run + uint64_t succeeded = 0; + uint64_t failed = 0; + uint64_t timed_out = 0; + uint64_t crashed = 0; + uint64_t interesting = 0; // results with new deterministic edges + uint64_t time_us = 0; // time spent inside the candidate +}; + +// What happened with the last pick, reported back to the strategy. +struct SelectionOutcome { + enum class Kind { + kNoop, // the candidate had nothing to do + kInvalid, // its result was rejected before execution + kSucceeded, + kFailed, + kTimedOut, + kCrashed + }; + Kind kind = Kind::kNoop; + bool interesting = false; // new deterministic edges + uint64_t time_us = 0; +}; + +// The configured strategy of one selection point. +struct SelectionConfig { + std::string strategy; // empty: the registry's default + JsonValue params; // object; null when not given +}; + +// A parameter a strategy accepts. Used to validate the configuration and to +// print the documentation (`redline fuzz --help-config`). +struct ParamSpec { + enum class Type { + kNumber, + kBool, + kString, + kObject // free-form object, validated by the strategy itself + }; + std::string_view name; + Type type; + std::string_view default_value; // as JSON text, for the documentation + std::string_view doc; +}; + +// One strategy instance per selection point. T is Mutator, Generator or +// Program. Candidates are passed as a vector of pointers whose order is +// stable (registration order for mutators and generators, insertion order +// for the corpus); picks are indices into that vector. +// +// Threading: mutator and generator selectors are shared by all workers and +// must be stateless between calls or synchronize their own state. Corpus +// selectors are called with the corpus lock held. +template <typename T> +class Selector { + public: + using Candidates = std::vector<T*>; + using Filter = std::function<bool(const T&)>; + static constexpr size_t kNoChoice = std::numeric_limits<size_t>::max(); + + virtual ~Selector() = default; + + virtual std::string_view name() const = 0; + + // Called once before the first pick with the candidates known at that + // time (the corpus may still be empty); strategies validate the + // parameters that refer to candidates here (e.g. weight names). + virtual bool Initialize(const Candidates& candidates, std::string* error) { + (void)candidates; + (void)error; + return true; + } + // A candidate was appended (corpus growth). + virtual void OnAdded(const Candidates& candidates, size_t index) { + (void)candidates; + (void)index; + } + + // Picks one candidate for which `eligible` is true, or kNoChoice. + virtual size_t Pick(const Candidates& candidates, Random& rng, + const Filter& eligible) = 0; + // Picks a candidate to go with `anchor` (the splice partner); an anchor + // past the end means "exclude nothing". The default picks like Pick() + // but never `anchor`. + virtual size_t PickRelated(const Candidates& candidates, size_t anchor, + Random& rng, const Filter& eligible) { + return Pick(candidates, rng, [&](const T& c) { + return (anchor >= candidates.size() || &c != candidates[anchor]) && + eligible(c); + }); + } + // Feedback for the strategy; the default strategies ignore it. + virtual void OnOutcome(T& picked, const SelectionOutcome& outcome) { + (void)picked; + (void)outcome; + } + + // Corpus strategies only: true if the strategy needs every edge a new + // program reaches deterministically (Program::hit_edges), which costs one + // extra execution per corpus addition. + virtual bool WantsHitEdges() const { return false; } + // Corpus strategies only: called on the partner strategy with the seed + // strategy, so that the two can share state (e.g. seed ages). + virtual void AttachSeedStrategy(Selector<T>* seeds) { (void)seeds; } + // Corpus strategies only: the edges of a crash that reproduces. Treating + // them as already covered steers seeds away from the same crash. + virtual void OnCrashEdges(const std::vector<uint32_t>& edges) { (void)edges; } + + // Static weights, for strategies that have them (the stats tables and + // the --mutator-weights/--generator-weights shorthands use these). + virtual double WeightOf(const T& candidate) const { + (void)candidate; + return 1.0; + } + virtual bool SetWeight(std::string_view candidate_name, double weight) { + (void)candidate_name; + (void)weight; + return false; + } + + // The effective parameters, for the `start` event. + virtual JsonObject Params() const = 0; +}; + +// Name -> factory. One registry per candidate type; the built-in strategies +// are registered by RegisterBuiltinSelectors<T>() (defined next to the +// strategies: corpus.cc, mutators.cc, generators.cc). +template <typename T> +class SelectorRegistry { + public: + // Builds the strategy from validated params; may still reject them + // (returns nullptr with *error set), e.g. a weight that is not a number. + using Factory = std::unique_ptr<Selector<T>> (*)(const JsonValue& params, + std::string* error); + + struct Entry { + std::string name; + std::string doc; + std::vector<ParamSpec> params; + Factory factory; + }; + + static SelectorRegistry& Instance(); + + void Register(Entry entry) { entries_.emplace(entry.name, std::move(entry)); } + // The strategy used when the configuration names none. + void SetDefault(std::string_view name) { default_ = std::string(name); } + + // Validates `config` (strategy name, parameter names and types) and + // builds the selector. On error returns nullptr and sets *error. + std::unique_ptr<Selector<T>> Create(const SelectionConfig& config, + std::string* error) const; + + std::vector<std::string> Names() const; + const std::string& default_name() const { return default_; } + // Documentation of all strategies and their parameters. + std::string Help(std::string_view point_name) const; + + private: + std::map<std::string, Entry> entries_; + std::string default_; +}; + +// Defined per candidate type next to the built-in strategies. +template <typename T> +void RegisterBuiltinSelectors(SelectorRegistry<T>& registry); + +// --- shared helpers for strategies and registries (selection.cc) -------- + +// Checks that `params` is an object whose keys are all declared in `specs` +// with the declared types. Returns false with a message naming the offender. +bool ValidateParams(std::string_view strategy, const JsonValue& params, + const std::vector<ParamSpec>& specs, std::string* error); + +// Reads params.weights ({"Name": number, ...}) into `out`. Returns false with +// a message for a non-object or a non-numeric weight. Names are checked +// later against the candidates (Initialize). +bool ReadWeightOverrides(const JsonValue& params, + std::vector<std::pair<std::string, double>>* out, + std::string* error); + +std::string JoinNames(const std::vector<std::string>& names); + +// --- template definitions --------------------------------------------------- + +template <typename T> +SelectorRegistry<T>& SelectorRegistry<T>::Instance() { + static SelectorRegistry<T>* registry = [] { + auto* r = new SelectorRegistry<T>(); + RegisterBuiltinSelectors<T>(*r); + return r; + }(); + return *registry; +} + +template <typename T> +std::unique_ptr<Selector<T>> SelectorRegistry<T>::Create( + const SelectionConfig& config, std::string* error) const { + const std::string& name = + config.strategy.empty() ? default_ : config.strategy; + auto found = entries_.find(name); + if (found == entries_.end()) { + *error = "unknown selection strategy '" + name + + "' (known: " + JoinNames(Names()) + ")"; + return nullptr; + } + if (!ValidateParams(name, config.params, found->second.params, error)) { + return nullptr; + } + std::unique_ptr<Selector<T>> selector = + found->second.factory(config.params, error); + if (selector == nullptr && !error->empty()) { + *error = "selection strategy '" + name + "': " + *error; + } + return selector; +} + +template <typename T> +std::vector<std::string> SelectorRegistry<T>::Names() const { + std::vector<std::string> names; + names.reserve(entries_.size()); + for (const auto& [name, entry] : entries_) { + names.push_back(name); + } + return names; +} + +template <typename T> +std::string SelectorRegistry<T>::Help(std::string_view point_name) const { + std::string out = + " " + std::string(point_name) + " (default: " + default_ + ")\n"; + for (const auto& [name, entry] : entries_) { + out += " " + name + ": " + entry.doc + "\n"; + for (const ParamSpec& p : entry.params) { + out += " " + std::string(p.name) + " = " + + std::string(p.default_value) + " " + std::string(p.doc) + "\n"; + } + } + return out; +} + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_SELECTION_H_ diff --git a/deps/v8/experimental/redline/core/tunable.cc b/deps/v8/experimental/redline/core/tunable.cc new file mode 100644 index 000000000000..49fbc25f0fee --- /dev/null +++ b/deps/v8/experimental/redline/core/tunable.cc @@ -0,0 +1,149 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/core/tunable.h" + +#include <algorithm> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <string> + +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/log.h" + +namespace redline { + +Tunable::Tunable(std::string_view name, double default_value, double min, + double max, std::string_view doc) + : name_(name), + value_(default_value), + default_(default_value), + min_(min), + max_(max), + doc_(doc) { + TunableRegistry::Instance().Register(this); +} + +// static +TunableRegistry& TunableRegistry::Instance() { + static TunableRegistry* registry = new TunableRegistry(); + return *registry; +} + +void TunableRegistry::Register(Tunable* tunable) { + // Two declarations with the same name would silently diverge; refuse. + if (Find(tunable->name()) != nullptr) { + fprintf(stderr, "redline: tunable '%.*s' declared twice\n", + static_cast<int>(tunable->name().size()), tunable->name().data()); + abort(); + } + tunables_.push_back(tunable); +} + +const Tunable* TunableRegistry::Find(std::string_view name) const { + for (const Tunable* t : tunables_) { + if (t->name() == name) { + return t; + } + } + return nullptr; +} + +bool TunableRegistry::Set(std::string_view name, double value, + std::string* error) { + for (Tunable* t : tunables_) { + if (t->name() != name) { + continue; + } + if (!std::isfinite(value) || value < t->min() || value > t->max()) { + *error = StringPrintf("tunable '%.*s': %g is outside its range [%g, %g]", + static_cast<int>(name.size()), name.data(), value, + t->min(), t->max()); + return false; + } + t->value_ = value; + return true; + } + *error = StringPrintf( + "unknown tunable '%.*s' (redline fuzz --help-tunables lists them)", + static_cast<int>(name.size()), name.data()); + return false; +} + +bool TunableRegistry::SetFromList(std::string_view list, std::string* error) { + size_t start = 0; + while (start < list.size()) { + size_t comma = list.find(',', start); + if (comma == std::string_view::npos) { + comma = list.size(); + } + std::string_view item = list.substr(start, comma - start); + start = comma + 1; + if (item.empty()) { + continue; + } + size_t eq = item.find('='); + if (eq == std::string_view::npos) { + *error = "--tunable expects NAME=VALUE, got '" + std::string(item) + "'"; + return false; + } + char* end = nullptr; + std::string text(item.substr(eq + 1)); + double value = strtod(text.c_str(), &end); + if (end == text.c_str() || *end != '\0') { + *error = "--tunable: '" + text + "' is not a number"; + return false; + } + if (!Set(item.substr(0, eq), value, error)) { + return false; + } + } + return true; +} + +void TunableRegistry::Reset() { + for (Tunable* t : tunables_) { + t->value_ = t->default_; + } +} + +std::vector<const Tunable*> TunableRegistry::All() const { + std::vector<const Tunable*> all(tunables_.begin(), tunables_.end()); + std::sort(all.begin(), all.end(), [](const Tunable* a, const Tunable* b) { + return a->name() < b->name(); + }); + return all; +} + +std::string TunableRegistry::Help() const { + std::string out; + for (const Tunable* t : All()) { + out += StringPrintf(" %-52.*s = %-8g (default %g, range %g..%g) %.*s\n", + static_cast<int>(t->name().size()), t->name().data(), + (*t)(), t->default_value(), t->min(), t->max(), + static_cast<int>(t->doc().size()), t->doc().data()); + } + return out; +} + +std::string TunableRegistry::NonDefaultsJson() const { + JsonObject o; + for (const Tunable* t : All()) { + if (!t->is_default()) { + o.Add(t->name(), (*t)()); + } + } + return o.ToString(); +} + +std::string TunableRegistry::AllJson() const { + JsonObject o; + for (const Tunable* t : All()) { + o.Add(t->name(), (*t)()); + } + return o.ToString(); +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/core/tunable.h b/deps/v8/experimental/redline/core/tunable.h new file mode 100644 index 000000000000..cb08c497d5df --- /dev/null +++ b/deps/v8/experimental/redline/core/tunable.h @@ -0,0 +1,107 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Tunables: the numbers inside generators, mutators and the engine that +// used to be literals ("insert 1-3 fields", "replace by a literal with +// probability 0.15"). Each one has a name that says who owns it +// (`generators.ObjectDecl.max_fields`, `mutators.Input.literal_chance`), a +// default, a range and one line of documentation, and can be set from the +// configuration: +// +// "tunables": {"generators.ObjectDecl.max_fields": 5} +// --tunable=generators.ObjectDecl.max_fields=5,mutators.Input.literal_chance=0.3 +// +// An unknown name or a value outside the range is an error at startup. +// `redline fuzz --help-tunables` lists them all; the `start` event records +// the ones that differ from their default. +// +// Declare one at namespace scope next to its use: +// +// REDLINE_TUNABLE(kObjectDeclMaxExtraFields, +// "generators.ObjectDecl.max_extra_fields", 3, 0, 32, +// "fields an object literal gets beyond the first +// (geometric)"); +// ... +// int fields = 1 + r.SmallCount(kObjectDeclMaxExtraFields.AsInt()); +// +// Convention: a tunable's default is exactly the number it replaced, so the +// code reads as before; "max_extra_*" names the n in `1 + SmallCount(n)`. +// +// Reading a tunable is a plain load; values are set once, before the +// workers start. + +#ifndef V8_EXPERIMENTAL_REDLINE_CORE_TUNABLE_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_TUNABLE_H_ + +#include <string> +#include <string_view> +#include <vector> + +namespace redline { + +class Tunable { + public: + Tunable(std::string_view name, double default_value, double min, double max, + std::string_view doc); + Tunable(const Tunable&) = delete; + Tunable& operator=(const Tunable&) = delete; + ~Tunable() = default; + + double operator()() const { return value_; } + int AsInt() const { return static_cast<int>(value_); } + + std::string_view name() const { return name_; } + double default_value() const { return default_; } + double min() const { return min_; } + double max() const { return max_; } + std::string_view doc() const { return doc_; } + bool is_default() const { return value_ == default_; } + + private: + friend class TunableRegistry; + std::string_view name_; + double value_; + double default_; + double min_; + double max_; + std::string_view doc_; +}; + +// All tunables, by name (registered by their constructors). +class TunableRegistry { + public: + static TunableRegistry& Instance(); + + // Sets a tunable; false with *error for an unknown name or a value + // outside its range. + bool Set(std::string_view name, double value, std::string* error); + // Parses "name=value[,name=value...]" (the --tunable flag). + bool SetFromList(std::string_view list, std::string* error); + // Back to the defaults (tests). + void Reset(); + + const Tunable* Find(std::string_view name) const; + std::vector<const Tunable*> All() const; // sorted by name + // One line per tunable: name = value (default, range) doc. + std::string Help() const; + // {"name": value} of the tunables that differ from their default. + std::string NonDefaultsJson() const; + // {"name": value} of all tunables (the full configuration dump). + std::string AllJson() const; + size_t size() const { return tunables_.size(); } + + private: + friend class Tunable; + void Register(Tunable* tunable); + + std::vector<Tunable*> tunables_; +}; + +// Declares a tunable at namespace scope. +#define REDLINE_TUNABLE(identifier, name, default_value, min, max, doc) \ + static ::redline::Tunable identifier(name, default_value, min, max, doc) + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_TUNABLE_H_ diff --git a/deps/v8/experimental/redline/core/weighted_selector.h b/deps/v8/experimental/redline/core/weighted_selector.h new file mode 100644 index 000000000000..3d1c7b7cfb07 --- /dev/null +++ b/deps/v8/experimental/redline/core/weighted_selector.h @@ -0,0 +1,123 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORE_WEIGHTED_SELECTOR_H_ +#define V8_EXPERIMENTAL_REDLINE_CORE_WEIGHTED_SELECTOR_H_ + +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +#include "experimental/redline/core/selection.h" + +namespace redline { + +// The default strategy for mutators and generators: one weighted random draw +// among the eligible candidates ("flat but configurable"). Every candidate +// starts with its built-in weight (T::weight()); the `weights` parameter +// overrides them by name, 0 disables a candidate. Feedback is ignored. +// +// This is Redline's historical pick, kept draw-for-draw identical: the +// weights are laid out in candidate order, non-eligible candidates get 0, +// and one Random::Weighted() call chooses. +// +// T must provide `const std::string& name() const` and `double weight() const`. +template <typename T> +class WeightedSelector final : public Selector<T> { + public: + using typename Selector<T>::Candidates; + using typename Selector<T>::Filter; + using Selector<T>::kNoChoice; + + static constexpr std::string_view kName = "weighted"; + + static std::vector<ParamSpec> Specs() { + return {{"weights", ParamSpec::Type::kObject, "{}", + "{\"Name\": number, ...}: overrides the built-in weights, 0 " + "disables"}}; + } + + // `kind` names the candidates in error messages ("mutator", "generator"). + WeightedSelector(std::string kind, + std::vector<std::pair<std::string, double>> overrides) + : kind_(std::move(kind)), overrides_(std::move(overrides)) {} + + std::string_view name() const override { return kName; } + + bool Initialize(const Candidates& candidates, std::string* error) override { + candidates_ = candidates; + weights_.clear(); + weights_.reserve(candidates.size()); + for (const T* c : candidates) { + weights_.push_back(c->weight()); + } + for (const auto& [name, weight] : overrides_) { + if (!SetWeight(name, weight)) { + *error = "unknown " + kind_ + " in weights: " + name; + return false; + } + } + return true; + } + + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& eligible) override { + std::vector<double> weights(candidates.size(), 0.0); + double total = 0; + for (size_t i = 0; i < candidates.size(); i++) { + if (weights_[i] <= 0) { + continue; + } + if (!eligible(*candidates[i])) { + continue; + } + weights[i] = weights_[i]; + total += weights_[i]; + } + if (total <= 0) { + return kNoChoice; + } + return rng.Weighted(weights); + } + + double WeightOf(const T& candidate) const override { + for (size_t i = 0; i < candidates_.size(); i++) { + if (candidates_[i] == &candidate) { + return weights_[i]; + } + } + return 0.0; + } + + bool SetWeight(std::string_view candidate_name, double weight) override { + for (size_t i = 0; i < candidates_.size(); i++) { + if (candidates_[i]->name() == candidate_name) { + weights_[i] = weight; + return true; + } + } + return false; + } + + JsonObject Params() const override { + JsonObject weights; + for (size_t i = 0; i < candidates_.size(); i++) { + weights.Add(candidates_[i]->name(), weights_[i]); + } + JsonObject params; + params.AddRaw("weights", weights.ToString()); + return params; + } + + private: + std::string kind_; + std::vector<std::pair<std::string, double>> overrides_; + Candidates candidates_; + std::vector<double> weights_; // effective, by candidate index +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORE_WEIGHTED_SELECTOR_H_ diff --git a/deps/v8/experimental/redline/corpus/corpus.cc b/deps/v8/experimental/redline/corpus/corpus.cc new file mode 100644 index 000000000000..51c97496bc97 --- /dev/null +++ b/deps/v8/experimental/redline/corpus/corpus.cc @@ -0,0 +1,704 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/corpus/corpus.h" + +#include <algorithm> +#include <cmath> +#include <queue> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" + +namespace redline { + +// --------------------------------------------------------------------------- +// Seed strategies: which corpus program a worker mutates next. +// +// To add one: derive from ProgramSelector, then add a Register() line in +// RegisterBuiltinSelectors<const Program> below. Picks return an index into +// `candidates` (the corpus in insertion order); rng.Index(n) draws a +// uniform index. + +namespace { + +using Candidates = ProgramSelector::Candidates; +using Filter = ProgramSelector::Filter; + +// Every program is equally likely. The baseline every other strategy is +// measured against. +class UniformSeeds final : public ProgramSelector { + public: + std::string_view name() const override { return "uniform"; } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + return rng.Index(candidates.size()); + } + JsonObject Params() const override { return JsonObject(); } +}; + +// Part of the picks go to the newest programs (the coverage frontier), the +// rest are uniform. +class RecencySeeds final : public ProgramSelector { + public: + static std::vector<ParamSpec> Specs() { + return { + {"window_fraction", ParamSpec::Type::kNumber, "0.1", + "share of the corpus (newest first) that counts as recent"}, + {"min_window", ParamSpec::Type::kNumber, "8", + "the recent window is at least this many programs"}, + {"recent_share", ParamSpec::Type::kNumber, "0.5", + "probability of picking from the recent window"}, + }; + } + explicit RecencySeeds(const JsonValue& params) + : window_fraction_(params.GetNumber("window_fraction", 0.1)), + min_window_(static_cast<size_t>(params.GetInt("min_window", 8))), + recent_share_(params.GetNumber("recent_share", 0.5)) {} + std::string_view name() const override { return "recency"; } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + size_t n = candidates.size(); + size_t window = std::max<size_t>( + min_window_, + static_cast<size_t>(static_cast<double>(n) * window_fraction_)); + // The historical draw for the default share is a coin flip (one RNG + // word, low bit); other shares use the probability draw. Both consume + // one word, so the sequence of later picks is the same either way. + bool recent = recent_share_ == 0.5 ? rng.Coin() : rng.Chance(recent_share_); + if (window < n && recent) { + return n - window + rng.Index(window); + } + return rng.Index(n); + } + JsonObject Params() const override { + JsonObject o; + o.Add("window_fraction", window_fraction_); + o.Add("min_window", static_cast<uint64_t>(min_window_)); + o.Add("recent_share", recent_share_); + return o; + } + + private: + double window_fraction_; + size_t min_window_; + double recent_share_; +}; + +// Tournament selection on the number of times a program was already +// mutated: of `size` random candidates, the least mutated one wins. Gives +// every program a fair number of mutations (Fuzzilli's +// minMutationsPerSample) without any bookkeeping beyond a counter. +class TournamentSeeds final : public ProgramSelector { + public: + static std::vector<ParamSpec> Specs() { + return { + {"size", ParamSpec::Type::kNumber, "3", "candidates per tournament"}}; + } + explicit TournamentSeeds(const JsonValue& params) + : size_(static_cast<int>(params.GetInt("size", 3))) {} + std::string_view name() const override { return "tournament"; } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + size_t best = rng.Index(candidates.size()); + for (int i = 1; i < size_; i++) { + size_t candidate = rng.Index(candidates.size()); + if (candidates[candidate]->picks.load(std::memory_order_relaxed) < + candidates[best]->picks.load(std::memory_order_relaxed)) { + best = candidate; + } + } + return best; + } + JsonObject Params() const override { + JsonObject o; + o.Add("size", size_); + return o; + } + + private: + int size_; +}; + +// Prefers programs whose mutations already produced new corpus programs: +// of `size` random candidates, the one with most children wins (ties: least +// mutated), so that it stays O(1). +class ProductiveSeeds final : public ProgramSelector { + public: + static std::vector<ParamSpec> Specs() { + return { + {"size", ParamSpec::Type::kNumber, "3", "candidates per tournament"}}; + } + explicit ProductiveSeeds(const JsonValue& params) + : size_(static_cast<int>(params.GetInt("size", 3))) {} + std::string_view name() const override { return "productive"; } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + size_t best = rng.Index(candidates.size()); + for (int i = 1; i < size_; i++) { + size_t candidate = rng.Index(candidates.size()); + uint32_t bc = candidates[best]->children.load(std::memory_order_relaxed); + uint32_t cc = + candidates[candidate]->children.load(std::memory_order_relaxed); + if (cc > bc || + (cc == bc && + candidates[candidate]->picks.load(std::memory_order_relaxed) < + candidates[best]->picks.load(std::memory_order_relaxed))) { + best = candidate; + } + } + return best; + } + JsonObject Params() const override { + JsonObject o; + o.Add("size", size_); + return o; + } + + private: + int size_; +}; + +// Partner strategy: a uniform pick that is not the anchor, in at most +// `tries` attempts (none: no partner, the mutation is skipped). +class UniformPartners final : public ProgramSelector { + public: + static std::vector<ParamSpec> Specs() { + return {{"tries", ParamSpec::Type::kNumber, "4", + "attempts to draw a program other than the anchor"}}; + } + explicit UniformPartners(const JsonValue& params) + : tries_(static_cast<int>(params.GetInt("tries", 4))) {} + std::string_view name() const override { return "uniform-partner"; } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + return rng.Index(candidates.size()); + } + size_t PickRelated(const Candidates& candidates, size_t anchor, Random& rng, + const Filter& /*eligible*/) override { + if (candidates.size() < 2) { + return kNoChoice; + } + for (int attempt = 0; attempt < tries_; attempt++) { + size_t candidate = rng.Index(candidates.size()); + if (candidate != anchor) { + return candidate; + } + } + return kNoChoice; + } + JsonObject Params() const override { + JsonObject o; + o.Add("tries", tries_); + return o; + } + + private: + int tries_; +}; + +// --- rarity ----------------------------------------------------------------- +// +// Fuzzilli's RarityCorpus (Sources/Fuzzilli/Corpus/RarityCorpus.swift), on +// Redline's shared corpus (so it is also the --sharedCorpus variant): +// +// energy(p) = rarity(p) / ((age(p) + 1)^age_exponent * (1 + +// ln(size(p))^size_exponent)) rarity(p) = sum over the tracked edges e of p +// with count(e) < rare_edge_limit +// of 1 / count(e)^rarity_exponent +// +// count(e) is the number of corpus programs that reach e deterministically +// (saturating at rare_edge_limit). A program tracks at most max_tracked_edges +// of its edges that were still rare when it was added, rarest (its new edges) +// first. The seed pick takes the program with the highest energy and ages it +// by 1; the partner pick is a tournament of partner_pool programs with +// non-zero energy and ages the winner by partner_age_increment. Energies only +// decrease (counts and ages only grow), so a lazy max-heap is exact: a popped +// entry whose energy dropped is re-inserted with its current value. +class RarityState { + public: + struct Params { + double age_exponent = 1.5; + double size_exponent = 2.0; + double rarity_exponent = 3.0; + int rare_edge_limit = 8; + int max_tracked_edges = 128; + double size_unit = 4.0; + int partner_pool = 3; + double partner_age_increment = 0.2; + }; + + static std::vector<ParamSpec> Specs() { + return { + {"age_exponent", ParamSpec::Type::kNumber, "1.5", + "energy decay with uses: (age + 1)^-x"}, + {"size_exponent", ParamSpec::Type::kNumber, "2.0", + "size penalty: 1 + ln(size)^x"}, + {"rarity_exponent", ParamSpec::Type::kNumber, "3.0", + "edge weight 1 / count^x"}, + {"rare_edge_limit", ParamSpec::Type::kNumber, "8", + "an edge reached by this many programs is common"}, + {"max_tracked_edges", ParamSpec::Type::kNumber, "128", + "rare edges remembered per program"}, + {"size_unit", ParamSpec::Type::kNumber, "4", + "AST nodes per size unit (Fuzzilli counts instructions)"}, + {"partner_pool", ParamSpec::Type::kNumber, "3", + "tournament size of the partner pick"}, + {"partner_age_increment", ParamSpec::Type::kNumber, "0.2", + "age added to a program picked as partner"}, + }; + } + + static Params ReadParams(const JsonValue& params) { + Params p; + p.age_exponent = params.GetNumber("age_exponent", p.age_exponent); + p.size_exponent = params.GetNumber("size_exponent", p.size_exponent); + p.rarity_exponent = params.GetNumber("rarity_exponent", p.rarity_exponent); + p.rare_edge_limit = + static_cast<int>(params.GetInt("rare_edge_limit", p.rare_edge_limit)); + p.max_tracked_edges = static_cast<int>( + params.GetInt("max_tracked_edges", p.max_tracked_edges)); + p.size_unit = params.GetNumber("size_unit", p.size_unit); + p.partner_pool = + static_cast<int>(params.GetInt("partner_pool", p.partner_pool)); + p.partner_age_increment = + params.GetNumber("partner_age_increment", p.partner_age_increment); + return p; + } + + static bool Validate(const Params& p, std::string* error) { + if (p.rare_edge_limit < 1 || p.rare_edge_limit > 254) { + *error = "rare_edge_limit must be in [1, 254]"; + return false; + } + if (p.max_tracked_edges < 1 || p.partner_pool < 1 || p.size_unit <= 0.0) { + *error = "max_tracked_edges and partner_pool must be >= 1, size_unit > 0"; + return false; + } + for (double x : {p.age_exponent, p.size_exponent, p.rarity_exponent, + p.partner_age_increment}) { + if (!std::isfinite(x) || x < 0.0) { + *error = "exponents and partner_age_increment must be finite and >= 0"; + return false; + } + } + return true; + } + + explicit RarityState(const Params& params) : params_(params) {} + + const Params& params() const { return params_; } + + JsonObject ParamsJson() const { + JsonObject o; + o.Add("age_exponent", params_.age_exponent) + .Add("size_exponent", params_.size_exponent); + o.Add("rarity_exponent", params_.rarity_exponent) + .Add("rare_edge_limit", params_.rare_edge_limit); + o.Add("max_tracked_edges", params_.max_tracked_edges) + .Add("size_unit", params_.size_unit); + o.Add("partner_pool", params_.partner_pool) + .Add("partner_age_increment", params_.partner_age_increment); + return o; + } + + void OnAdded(const Candidates& candidates, size_t index) { + const Program& program = *candidates[index]; + // Without the full edge set (e.g. imports that were not re-run), fall + // back to the program's new edges. + std::vector<uint32_t> edges = + program.hit_edges.empty() ? program.edges : program.hit_edges; + for (uint32_t edge : program.edges) { + edges.push_back(edge); + } + std::sort(edges.begin(), edges.end()); + edges.erase(std::unique(edges.begin(), edges.end()), edges.end()); + const uint8_t limit = static_cast<uint8_t>(params_.rare_edge_limit); + if (!edges.empty() && edges.back() >= counts_.size()) { + counts_.resize(static_cast<size_t>(edges.back()) + 4096, 0); + } + std::vector<uint32_t> rare; + for (uint32_t edge : edges) { + uint8_t& count = counts_[edge]; + if (count < limit) { + count++; + } + if (count < limit) { + rare.push_back(edge); + } + } + std::stable_sort(rare.begin(), rare.end(), [&](uint32_t a, uint32_t b) { + return counts_[a] < counts_[b]; + }); + if (rare.size() > static_cast<size_t>(params_.max_tracked_edges)) { + rare.resize(static_cast<size_t>(params_.max_tracked_edges)); + } + program.rare_edges = std::move(rare); + heap_.push({Energy(program), index}); + } + + // Fuzzilli's RarityCorpus counts the edges of a reproducible crash as + // seen once more, which lowers the energy of the programs leading there. + void RecordCrashEdges(const std::vector<uint32_t>& edges) { + const uint8_t limit = static_cast<uint8_t>(params_.rare_edge_limit); + for (uint32_t edge : edges) { + if (edge >= counts_.size()) { + counts_.resize(static_cast<size_t>(edge) + 4096, 0); + } + if (counts_[edge] < limit) { + counts_[edge]++; + } + } + } + + double Energy(const Program& program) const { + double rarity = 0.0; + for (uint32_t edge : program.rare_edges) { + uint8_t count = counts_[edge]; + if (count < params_.rare_edge_limit) { + rarity += + 1.0 / std::pow(static_cast<double>(std::max<uint8_t>(1, count)), + params_.rarity_exponent); + } + } + if (rarity == 0.0) { + return 0.0; + } + double size = std::max( + 1.0, static_cast<double>(program.node_count()) / params_.size_unit); + double ln_size = std::log(size); + double size_pen = 1.0 + std::pow(ln_size, params_.size_exponent); + return rarity / + (std::pow(program.age + 1.0, params_.age_exponent) * size_pen); + } + + // The seed pick: highest current energy (kNoChoice if every program's + // energy is 0; the caller then picks uniformly). + size_t PickSeed(const Candidates& candidates) { + while (!heap_.empty()) { + Entry top = heap_.top(); + heap_.pop(); + double current = Energy(*candidates[top.index]); + if (current <= 0.0) { + continue; // never schedulable again: drop it from the heap + } + if (current < top.energy * (1.0 - 1e-9)) { + heap_.push({current, top.index}); + continue; + } + const Program& program = *candidates[top.index]; + program.age += 1.0; + heap_.push({Energy(program), top.index}); + return top.index; + } + return ProgramSelector::kNoChoice; + } + + // The partner pick: the best of `partner_pool` random programs with + // energy (uniform among all if none has energy left). + size_t PickPartner(const Candidates& candidates, size_t anchor, Random& rng) { + size_t n = candidates.size(); + if (n < 2) { + return ProgramSelector::kNoChoice; + } + size_t best = ProgramSelector::kNoChoice; + double best_energy = 0.0; + for (int i = 0, attempts = 0; + i < params_.partner_pool && attempts < 4 * params_.partner_pool; + attempts++) { + size_t candidate = rng.Index(n); + if (candidate == anchor) { + continue; + } + double energy = Energy(*candidates[candidate]); + if (energy <= 0.0) { + continue; + } + i++; + if (best == ProgramSelector::kNoChoice || energy > best_energy) { + best = candidate; + best_energy = energy; + } + } + if (best == ProgramSelector::kNoChoice) { + for (int attempt = 0; attempt < 4 && best == ProgramSelector::kNoChoice; + attempt++) { + size_t candidate = rng.Index(n); + if (candidate != anchor) { + best = candidate; + } + } + return best; + } + candidates[best]->age += params_.partner_age_increment; + return best; + } + + private: + struct Entry { + double energy; + size_t index; + bool operator<(const Entry& other) const { + return energy != other.energy ? energy < other.energy + : index > other.index; + } + }; + Params params_; + std::vector<uint8_t> counts_; + std::priority_queue<Entry> heap_; +}; + +class RaritySeeds final : public ProgramSelector { + public: + explicit RaritySeeds(const RarityState::Params& params) + : state_(std::make_shared<RarityState>(params)) {} + std::string_view name() const override { return "rarity"; } + bool WantsHitEdges() const override { return true; } + void OnAdded(const Candidates& candidates, size_t index) override { + state_->OnAdded(candidates, index); + } + void OnCrashEdges(const std::vector<uint32_t>& edges) override { + state_->RecordCrashEdges(edges); + } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + size_t index = state_->PickSeed(candidates); + return index != kNoChoice ? index : rng.Index(candidates.size()); + } + size_t PickRelated(const Candidates& candidates, size_t anchor, Random& rng, + const Filter& /*eligible*/) override { + return state_->PickPartner(candidates, anchor, rng); + } + JsonObject Params() const override { return state_->ParamsJson(); } + std::shared_ptr<RarityState> state() const { return state_; } + + private: + std::shared_ptr<RarityState> state_; +}; + +// The partner side of "rarity": shares the seed strategy's state (counts and +// ages) when the seeds use "rarity" too, otherwise keeps its own. +class RarityPartners final : public ProgramSelector { + public: + explicit RarityPartners(const RarityState::Params& params) + : own_(std::make_shared<RarityState>(params)) {} + std::string_view name() const override { return "rarity-partner"; } + bool WantsHitEdges() const override { return true; } + void AttachSeedStrategy(ProgramSelector* seeds) override { + // No RTTI in V8 builds: the name identifies the class. + if (seeds != nullptr && seeds->name() == "rarity") { + shared_ = static_cast<RaritySeeds*>(seeds)->state(); + } else if (seeds != nullptr && seeds->name() == "rarity-partner") { + shared_ = static_cast<RarityPartners*>(seeds)->own_; + } + } + void OnAdded(const Candidates& candidates, size_t index) override { + if (shared_ == nullptr) { + own_->OnAdded(candidates, index); + } + } + void OnCrashEdges(const std::vector<uint32_t>& edges) override { + if (shared_ == nullptr) { + own_->RecordCrashEdges(edges); + } + } + size_t Pick(const Candidates& candidates, Random& rng, + const Filter& /*eligible*/) override { + return rng.Index(candidates.size()); + } + size_t PickRelated(const Candidates& candidates, size_t anchor, Random& rng, + const Filter& /*eligible*/) override { + return (shared_ != nullptr ? shared_ : own_) + ->PickPartner(candidates, anchor, rng); + } + JsonObject Params() const override { + JsonObject o = own_->ParamsJson(); + o.Add("shares_seed_state", shared_ != nullptr); + return o; + } + + private: + std::shared_ptr<RarityState> own_; + std::shared_ptr<RarityState> shared_; +}; + +} // namespace + +// Seeds and partners share one registry (both pick corpus programs); the +// seed strategies ignore the anchor and the partner strategy has a plain +// Pick() too, so either can be configured at either point. +template <> +void RegisterBuiltinSelectors<const Program>( + SelectorRegistry<const Program>& registry) { + using Entry = SelectorRegistry<const Program>::Entry; + registry.Register(Entry{ + "uniform", + "every program equally likely", + {}, + [](const JsonValue&, std::string*) -> std::unique_ptr<ProgramSelector> { + return std::make_unique<UniformSeeds>(); + }}); + registry.Register( + Entry{"recency", + "some picks from the newest part of the corpus, the rest uniform", + RecencySeeds::Specs(), + [](const JsonValue& params, + std::string*) -> std::unique_ptr<ProgramSelector> { + return std::make_unique<RecencySeeds>(params); + }}); + registry.Register(Entry{"tournament", + "least mutated of a few random candidates", + TournamentSeeds::Specs(), + [](const JsonValue& params, + std::string*) -> std::unique_ptr<ProgramSelector> { + return std::make_unique<TournamentSeeds>(params); + }}); + registry.Register( + Entry{"productive", + "most productive of a few random candidates (ties: least mutated)", + ProductiveSeeds::Specs(), + [](const JsonValue& params, + std::string*) -> std::unique_ptr<ProgramSelector> { + return std::make_unique<ProductiveSeeds>(params); + }}); + registry.Register( + Entry{"uniform-partner", + "a uniform pick other than the anchor (the partner strategy)", + UniformPartners::Specs(), + [](const JsonValue& params, + std::string*) -> std::unique_ptr<ProgramSelector> { + return std::make_unique<UniformPartners>(params); + }}); + registry.Register( + Entry{"rarity", + "Fuzzilli's RarityCorpus: highest energy (rare edges, age, size) " + "as seed, tournament as partner", + RarityState::Specs(), + [](const JsonValue& params, + std::string* error) -> std::unique_ptr<ProgramSelector> { + RarityState::Params p = RarityState::ReadParams(params); + if (!RarityState::Validate(p, error)) { + return nullptr; + } + return std::make_unique<RaritySeeds>(p); + }}); + registry.Register( + Entry{"rarity-partner", + "partner strategy of \"rarity\": best of a few random programs by " + "energy (shares the seed state)", + RarityState::Specs(), + [](const JsonValue& params, + std::string* error) -> std::unique_ptr<ProgramSelector> { + RarityState::Params p = RarityState::ReadParams(params); + if (!RarityState::Validate(p, error)) { + return nullptr; + } + return std::make_unique<RarityPartners>(p); + }}); + registry.SetDefault("uniform"); +} + +// --------------------------------------------------------------------------- +// Corpus + +Corpus::Corpus(std::unique_ptr<ProgramSelector> seeds, + std::unique_ptr<ProgramSelector> partners) + : seeds_(std::move(seeds)), + partners_(std::move(partners)), + seed_stats_(std::string(seeds_->name())) { + partners_->AttachSeedStrategy(seeds_.get()); +} + +bool Corpus::WantsHitEdges() const { + return seeds_->WantsHitEdges() || partners_->WantsHitEdges(); +} + +void Corpus::RecordCrashEdges(const std::vector<uint32_t>& edges) { + std::scoped_lock<std::mutex> lock(mutex_); + seeds_->OnCrashEdges(edges); + partners_->OnCrashEdges(edges); +} + +Corpus::~Corpus() = default; + +ProgramPtr Corpus::Add(std::shared_ptr<Program> program) { + std::scoped_lock<std::mutex> lock(mutex_); + program->id = static_cast<uint32_t>(programs_.size() + 1); + if (program->added_at_ms == 0) { + program->added_at_ms = WallClockNowMs(); + } + total_nodes_.fetch_add(program->node_count(), std::memory_order_relaxed); + total_edges_.fetch_add(program->edges.size(), std::memory_order_relaxed); + ProgramPtr published = std::move(program); + programs_.push_back(published); + candidates_.push_back(published.get()); + seeds_->OnAdded(candidates_, candidates_.size() - 1); + partners_->OnAdded(candidates_, candidates_.size() - 1); + std::vector<uint32_t>().swap(published->hit_edges); + return published; +} + +ProgramPtr Corpus::Pick(Random& rng) { + std::scoped_lock<std::mutex> lock(mutex_); + if (programs_.empty()) { + return nullptr; + } + seed_stats_.stats().invocations++; + size_t index = + seeds_->Pick(candidates_, rng, [](const Program&) { return true; }); + if (index == ProgramSelector::kNoChoice) { + return nullptr; + } + const ProgramPtr& picked = programs_[index]; + picked->picks.fetch_add(1, std::memory_order_relaxed); + seed_stats_.stats().produced++; + return picked; +} + +ProgramPtr Corpus::PickPartner(const Program& parent, Random& rng) { + std::scoped_lock<std::mutex> lock(mutex_); + // The anchor is the parent's position in the corpus; an intermediate + // program of a mutation chain is not in the corpus, so nothing is + // excluded for it (anchor past the end). + size_t anchor = candidates_.size(); + if (parent.id != 0 && parent.id <= programs_.size() && + programs_[parent.id - 1].get() == &parent) { + anchor = parent.id - 1; + } + size_t index = partners_->PickRelated(candidates_, anchor, rng, + [](const Program&) { return true; }); + return index == ProgramSelector::kNoChoice ? nullptr : programs_[index]; +} + +void Corpus::OnResult(const Program& parent, bool interesting) { + if (interesting) { + parent.children.fetch_add(1, std::memory_order_relaxed); + seed_stats_.stats().interesting++; + } + std::scoped_lock<std::mutex> lock(mutex_); + SelectionOutcome outcome; + outcome.kind = SelectionOutcome::Kind::kSucceeded; + outcome.interesting = interesting; + seeds_->OnOutcome(parent, outcome); +} + +size_t Corpus::size() const { + std::scoped_lock<std::mutex> lock(mutex_); + return programs_.size(); +} + +ProgramPtr Corpus::Get(uint32_t id) const { + std::scoped_lock<std::mutex> lock(mutex_); + if (id == 0 || id > programs_.size()) { + return nullptr; + } + return programs_[id - 1]; +} + +std::vector<ProgramPtr> Corpus::Snapshot() const { + std::scoped_lock<std::mutex> lock(mutex_); + return programs_; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/corpus/corpus.h b/deps/v8/experimental/redline/corpus/corpus.h new file mode 100644 index 000000000000..f02d3b4bd852 --- /dev/null +++ b/deps/v8/experimental/redline/corpus/corpus.h @@ -0,0 +1,88 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_CORPUS_CORPUS_H_ +#define V8_EXPERIMENTAL_REDLINE_CORPUS_CORPUS_H_ + +#include <cstdint> +#include <memory> +#include <mutex> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/core/component.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/core/random.h" +#include "experimental/redline/core/selection.h" + +namespace redline { + +// The strategies that pick corpus programs are Selector<const Program> +// (core/selection.h): one picks the seed a worker mutates next (built-in: +// uniform, recency, tournament, productive), one picks the partner that +// Splice/Combine take material from (built-in: uniform). They are created +// from the configuration through SelectorRegistry<const Program> and are +// called with the corpus lock held, so they may keep plain state; they must +// be cheap because every mutation goes through them. +using ProgramSelector = Selector<const Program>; + +// The set of programs known to reach new coverage. Append-only and shared +// between all workers; programs are immutable so readers only need the lock +// for the vector itself. +class Corpus { + public: + Corpus(std::unique_ptr<ProgramSelector> seeds, + std::unique_ptr<ProgramSelector> partners); + ~Corpus(); + + // Assigns an id and publishes the program. Returns the published pointer. + ProgramPtr Add(std::shared_ptr<Program> program); + + // Picks a parent for mutation (nullptr if the corpus is empty) and counts + // the pick on the program. + ProgramPtr Pick(Random& rng); + // Picks a partner for `parent` (nullptr if there is no other program). + ProgramPtr PickPartner(const Program& parent, Random& rng); + // Reports the outcome of a mutation of `parent` back to the strategies. + void OnResult(const Program& parent, bool interesting); + // True if a strategy needs Program::hit_edges filled before Add(). + bool WantsHitEdges() const; + // The edges of a crash that reproduces (see Selector::OnCrashEdges). + void RecordCrashEdges(const std::vector<uint32_t>& edges); + + size_t size() const; + ProgramPtr Get(uint32_t id) const; + std::vector<ProgramPtr> Snapshot() const; + // Sum of node_count over the corpus and total number of edges attributed + // to corpus programs (informational). + uint64_t total_nodes() const { + return total_nodes_.load(std::memory_order_relaxed); + } + uint64_t total_edges() const { + return total_edges_.load(std::memory_order_relaxed); + } + + const ProgramSelector& seeds() const { return *seeds_; } + const ProgramSelector& partners() const { return *partners_; } + // Statistics of the seed picks, named after the strategy, for the stats + // tables (invocations = picks, interesting = picks whose mutation + // produced a new corpus program). + const Component& seed_stats() const { return seed_stats_; } + + private: + mutable std::mutex mutex_; + std::vector<ProgramPtr> programs_; + std::vector<const Program*> + candidates_; // programs_ as the selectors see them + std::unique_ptr<ProgramSelector> seeds_; + std::unique_ptr<ProgramSelector> partners_; + Component seed_stats_; + std::atomic<uint64_t> total_nodes_{0}; + std::atomic<uint64_t> total_edges_{0}; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_CORPUS_CORPUS_H_ diff --git a/deps/v8/experimental/redline/engine/amplifier.cc b/deps/v8/experimental/redline/engine/amplifier.cc new file mode 100644 index 000000000000..af88b60eff06 --- /dev/null +++ b/deps/v8/experimental/redline/engine/amplifier.cc @@ -0,0 +1,411 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/amplifier.h" + +#include <algorithm> +#include <sstream> +#include <utility> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/exec/process_run.h" +#include "experimental/redline/fast/parser.h" +#include "experimental/redline/fast/printer.h" + +namespace redline { + +namespace { + +constexpr char kLog[] = "amplify"; + +std::vector<std::string> SplitArgs(const std::string& text) { + std::vector<std::string> out; + std::istringstream stream(text); + std::string piece; + while (stream >> piece) { + out.push_back(piece); + } + return out; +} + +// A stack rule: if one of `frames` occurs in the crash output, try `args`. +struct Rule { + std::vector<std::string> frames; + std::string args; +}; + +std::vector<Rule> DefaultRules() { + return { + {{"HandleProfilerSignal", "CpuSampler", "TickSample"}, + "--cpu-profiler --cpu-profiler-sampling-interval=10"}, + {{"MarkCompactCollector", "Scavenger", "ConcurrentMarking", "Sweeper"}, + "--stress-compaction"}, + }; +} + +std::string RulesJson(const std::vector<Rule>& rules) { + std::string out = "["; + for (size_t i = 0; i < rules.size(); i++) { + JsonObject o; + o.AddArray("frames", rules[i].frames); + o.Add("args", rules[i].args); + out += (i > 0 ? "," : "") + o.ToString(); + } + return out + "]"; +} + +// The session's flags with a new --random-seed (appended if absent), then +// the candidate's flags, then --stress-runs. +std::vector<std::string> ProcessArgs(const std::vector<std::string>& base, + const std::string& extra, int stress_runs, + Random& rng) { + const std::string seed = + "--random-seed=" + std::to_string(1 + rng.Index(2000000000)); + std::vector<std::string> args; + bool seeded = false; + for (const std::string& arg : base) { + if (arg.starts_with("--random-seed=") || + arg.starts_with("--random_seed=")) { + args.push_back(seed); + seeded = true; + } else if (!arg.starts_with("--stress-runs=") && + !arg.starts_with("--stress_runs=")) { + args.push_back(arg); + } + } + if (!seeded) { + args.push_back(seed); + } + for (std::string& arg : SplitArgs(extra)) { + args.push_back(std::move(arg)); + } + args.push_back("--stress-runs=" + std::to_string(stress_runs)); + return args; +} + +class NoneStrategy final : public AmplifyStrategy { + public: + std::string_view name() const override { return "none"; } + AmplifyResult Amplify(const AmplifyRequest&, Random&) override { + AmplifyResult r; + r.note = "amplify strategy none"; + return r; + } + JsonObject Params() const override { return JsonObject(); } + int per_signature() const override { return 0; } +}; + +class FlagsStrategy final : public AmplifyStrategy { + public: + struct Settings { + double budget_sec = 180; + int processes = 5; + int min_hits = 4; + double loop_time_sec = 10; + int max_loops = 100; + double run_timeout_sec = 30; + int per_signature = 1; + bool wrap = true; + std::vector<Rule> rules = DefaultRules(); + }; + + static std::vector<ParamSpec> Specs() { + return { + {"budget_sec", ParamSpec::Type::kNumber, "180", + "time limit of the search for one crash"}, + {"processes", ParamSpec::Type::kNumber, "5", + "fresh d8 processes per candidate"}, + {"min_hits", ParamSpec::Type::kNumber, "4", + "processes with the same signature that make it amplified"}, + {"loop_time_sec", ParamSpec::Type::kNumber, "10", + "target duration of one process (sets --stress-runs)"}, + {"max_loops", ParamSpec::Type::kNumber, "100", + "largest --stress-runs value"}, + {"run_timeout_sec", ParamSpec::Type::kNumber, "30", + "a process is killed after this time"}, + {"per_signature", ParamSpec::Type::kNumber, "1", + "searches per signature and session"}, + {"wrap", ParamSpec::Type::kBool, "true", + "if the program throws an uncaught exception, wrap its statements in " + "try/catch"}, + {"rules", ParamSpec::Type::kObject, "built-in", + "[{\"frames\": [substrings], \"args\": \"extra d8 flags\"}, ...]: " + "candidates from the crash stack"}, + }; + } + + static bool Read(const JsonValue& params, Settings* s, std::string* error) { + if (!params.is_null() && !params.is_object()) { + *error = "amplify.params must be an object"; + return false; + } + if (params.is_object()) { + for (const auto& [key, value] : params.as_object()) { + const auto specs = Specs(); + if (std::none_of(specs.begin(), specs.end(), + [&](const ParamSpec& p) { return p.name == key; })) { + *error = "unknown amplify param \"" + key + "\" for strategy flags"; + return false; + } + } + } + s->budget_sec = params.GetNumber("budget_sec", s->budget_sec); + s->processes = static_cast<int>(params.GetInt("processes", s->processes)); + s->min_hits = static_cast<int>(params.GetInt("min_hits", s->min_hits)); + s->loop_time_sec = params.GetNumber("loop_time_sec", s->loop_time_sec); + s->max_loops = static_cast<int>(params.GetInt("max_loops", s->max_loops)); + s->run_timeout_sec = + params.GetNumber("run_timeout_sec", s->run_timeout_sec); + s->per_signature = + static_cast<int>(params.GetInt("per_signature", s->per_signature)); + s->wrap = params.GetBool("wrap", s->wrap); + const JsonValue& rules = params.Get("rules"); + if (!rules.is_null()) { + if (!rules.is_array()) { + *error = "amplify.params.rules must be a list"; + return false; + } + s->rules.clear(); + for (const JsonValue& rule : rules.as_array()) { + if (!rule.is_object() || !rule.Get("frames").is_array()) { + *error = + "every amplify rule needs \"frames\" (non-empty strings) and " + "\"args\""; + return false; + } + Rule r; + r.args = rule.GetString("args", ""); + for (const JsonValue& frame : rule.Get("frames").as_array()) { + if (frame.is_string() && !frame.as_string().empty()) { + r.frames.push_back(frame.as_string()); + } + } + if (r.frames.empty() || r.args.empty()) { + *error = + "every amplify rule needs \"frames\" (non-empty strings) and " + "\"args\""; + return false; + } + s->rules.push_back(std::move(r)); + } + } + if (s->budget_sec <= 0 || s->processes < 1 || s->min_hits < 1 || + s->min_hits > s->processes || s->loop_time_sec <= 0 || + s->max_loops < 2 || s->run_timeout_sec <= 0 || s->per_signature < 0) { + *error = + "amplify flags: need budget_sec > 0, 1 <= min_hits <= processes, " + "loop_time_sec > 0, max_loops >= 2, " + "run_timeout_sec > 0, per_signature >= 0"; + return false; + } + return true; + } + + explicit FlagsStrategy(Settings settings) : s_(std::move(settings)) {} + + std::string_view name() const override { return "flags"; } + int per_signature() const override { return s_.per_signature; } + + JsonObject Params() const override { + JsonObject o; + o.Add("budget_sec", s_.budget_sec) + .Add("processes", s_.processes) + .Add("min_hits", s_.min_hits); + o.Add("loop_time_sec", s_.loop_time_sec).Add("max_loops", s_.max_loops); + o.Add("run_timeout_sec", s_.run_timeout_sec) + .Add("per_signature", s_.per_signature); + o.Add("wrap", s_.wrap); + o.AddRaw("rules", RulesJson(s_.rules)); + return o; + } + + AmplifyResult Amplify(const AmplifyRequest& request, Random& rng) override { + AmplifyResult result; + const Stopwatch clock; + const uint64_t timeout_us = static_cast<uint64_t>(s_.run_timeout_sec * 1e6); + const auto env = request.target.PlainEnvironment(); + auto write = [&](const std::string& program) { + std::string script = + request.prelude.empty() ? program : request.prelude + "\n" + program; + std::string write_error; + if (!WriteStringToFile(request.script_path, script, &write_error)) { + result.note = + "cannot write " + request.script_path + ": " + write_error; + return false; + } + return true; + }; + if (!write(request.program)) { + return result; + } + // One plain run without extra flags: if the program ends with an + // uncaught exception, d8 would end every --stress-runs loop after the + // first run. Then the candidates run on the wrapped program. + std::string wrapped; + if (s_.wrap) { + std::vector<std::string> args = request.target.args; + args.push_back(request.script_path); + const ProcessResult probe = + RunProcess(request.target.executable, args, env, timeout_us); + result.total_processes++; + const bool throws = + probe.started && !probe.timed_out && probe.signal == 0 && + probe.exit_code != 0 && + !(CrashSignature::FromOutput(probe.signal, probe.exit_code, + probe.stderr_text) == request.signature); + if (throws) { + wrapped = WrapInTry(request.program); + if (!wrapped.empty() && !write(wrapped)) { + return result; + } + } + } + // Candidates: the matching rules in their order, then the plain loop. + std::vector<std::string> candidates; + for (const Rule& rule : s_.rules) { + for (const std::string& frame : rule.frames) { + if (request.stderr_text.find(frame) != std::string::npos) { + candidates.push_back(rule.args); + break; + } + } + } + candidates.emplace_back(); + const int loops = + StressRunsFor(request.exec_time_us, s_.loop_time_sec, s_.max_loops); + const uint64_t budget_us = static_cast<uint64_t>(s_.budget_sec * 1e6); + std::string tried = wrapped.empty() ? "" : "program wrapped in try/catch; "; + for (const std::string& extra : candidates) { + int hits = 0, runs = 0; + for (; runs < s_.processes; runs++) { + if (clock.ElapsedUs() > budget_us || + (request.stopping && request.stopping())) { + break; + } + // Stop when this candidate can no longer reach min_hits. + if (hits + (s_.processes - runs) < s_.min_hits) { + break; + } + const std::vector<std::string> args = + ProcessArgs(request.target.args, extra, loops, rng); + std::vector<std::string> with_script(args); + with_script.push_back(request.script_path); + const ProcessResult run = + RunProcess(request.target.executable, with_script, env, timeout_us); + result.total_processes++; + if (!run.started) { + result.note = "cannot start d8: " + run.error; + return result; + } + if (!run.timed_out && + CrashSignature::FromOutput(run.signal, run.exit_code, + run.stderr_text) == request.signature) { + hits++; + } + } + tried += StringPrintf("%s[%s]: %d/%d", + tried.empty() || tried.back() == ' ' ? "" : "; ", + extra.empty() ? "loop" : extra.c_str(), hits, runs); + if (hits > result.hits || result.processes == 0) { + result.hits = hits; + result.processes = runs; + result.args = (extra.empty() ? "" : extra + " ") + + "--stress-runs=" + std::to_string(loops); + } + if (hits >= s_.min_hits) { + result.amplified = true; + break; + } + if (clock.ElapsedUs() > budget_us || + (request.stopping && request.stopping())) { + break; + } + } + result.time_sec = static_cast<double>(clock.ElapsedUs()) / 1e6; + result.note = tried; + if (result.amplified) { + result.program = wrapped; // empty if the program did not change + } + REDLINE_LOG(kLog, "%s after %d processes in %.0f s: %s", + result.amplified ? "amplified" : "not amplified", + result.total_processes, result.time_sec, tried.c_str()); + return result; + } + + private: + Settings s_; +}; + +} // namespace + +int StressRunsFor(uint64_t exec_time_us, double loop_time_sec, int max_loops) { + const double one = + std::max<double>(static_cast<double>(exec_time_us), 1000.0); + const double n = loop_time_sec * 1e6 / one; + return static_cast<int>( + std::clamp<double>(n, 2.0, static_cast<double>(max_loops))); +} + +std::string WrapInTry(const std::string& program) { + fast::ParseError error; + std::unique_ptr<fast::Tree> tree = + fast::Parser::ParseScript(program, fast::ParseOptions(), &error); + if (tree == nullptr || tree->root() == nullptr) { + return ""; + } + fast::Program* root = tree->root(); + std::vector<fast::Statement*> head, body; + for (fast::Statement* statement : root->body) { + const auto* expression = statement->As<fast::ExpressionStatement>(); + if (body.empty() && expression != nullptr && expression->is_directive) { + head.push_back(statement); // the directive prologue stays in front + } else { + body.push_back(statement); + } + } + if (body.empty()) { + return ""; + } + head.push_back(mk::Try(tree.get(), body, "redline_exception", {})); + root->body = std::move(head); + return fast::Print(root); +} + +std::unique_ptr<AmplifyStrategy> CreateAmplifyStrategy(std::string_view name, + const JsonValue& params, + std::string* error) { + if (name.empty() || name == "flags") { + FlagsStrategy::Settings settings; + if (!FlagsStrategy::Read(params, &settings, error)) { + return nullptr; + } + return std::make_unique<FlagsStrategy>(std::move(settings)); + } + if (name == "none") { + if (params.is_object() && !params.as_object().empty()) { + *error = "amplify strategy none takes no params"; + return nullptr; + } + return std::make_unique<NoneStrategy>(); + } + *error = "unknown amplify strategy \"" + std::string(name) + + "\" (known: flags, none)"; + return nullptr; +} + +std::vector<AmplifyStrategyInfo> AmplifyStrategies() { + return { + {"flags", + "extra d8 flags from stack rules, then the plain loop; each candidate " + "runs fresh processes with " + "--stress-runs", + FlagsStrategy::Specs()}, + {"none", "the amplify step is off", {}}, + }; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/amplifier.h b/deps/v8/experimental/redline/engine/amplifier.h new file mode 100644 index 000000000000..96f4e2893489 --- /dev/null +++ b/deps/v8/experimental/redline/engine/amplifier.h @@ -0,0 +1,103 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Crash amplification (DESIGN.md 5.8). Some crashes do not reproduce in a +// fresh target because they depend on timing: a profiler signal, a concurrent +// compile, a GC at a particular moment. The amplify step searches for a plain +// d8 command line that reproduces such a crash reliably, for example extra +// flags plus --stress-runs=K, which runs the script K times in one process. +// ClusterFuzz accepts a testcase together with its d8 flags, so an amplified +// crash can be uploaded. If the program throws an uncaught exception, the +// step wraps its statements in try/catch (param `wrap`), because d8 ends the +// --stress-runs loop at the first uncaught exception. +// +// Strategies (registry, configured with {"amplify": {"strategy": NAME, +// "params": {...}}}): +// none the step is off. +// flags candidates from stack rules, then the plain loop (default). + +#ifndef V8_EXPERIMENTAL_REDLINE_ENGINE_AMPLIFIER_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_AMPLIFIER_H_ + +#include <cstdint> +#include <functional> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/json_parser.h" +#include "experimental/redline/core/random.h" +#include "experimental/redline/core/selection.h" +#include "experimental/redline/engine/crash.h" +#include "experimental/redline/exec/target_options.h" + +namespace redline { + +// One crash to amplify. +struct AmplifyRequest { + TargetOptions + target; // executable, args (with the session's flags), extra env + std::string program; // the crashing program, without the prelude + std::string prelude; // put in front of the program (empty: none) + std::string script_path; // where to write the script for the plain runs + CrashSignature signature; // the crash to reproduce + std::string + stderr_text; // of the original crash (stack frames for the rules) + uint64_t exec_time_us = 0; // the longest execution seen for this program + std::function<bool()> stopping; // optional: true when the fuzzer stops +}; + +struct AmplifyResult { + bool amplified = false; + std::string args; // extra d8 flags that reproduce it, with --stress-runs=K + int hits = 0; // crashes with the same signature, best candidate + int processes = 0; // processes run for the best candidate + int total_processes = 0; // all processes of the search + double time_sec = 0; + std::string note; // one line: what was tried + // Set if the step changed the program: its statements wrapped in + // try/catch, because an uncaught exception ends the --stress-runs loop. + // The args reproduce this program, not the original. + std::string program; +}; + +class AmplifyStrategy { + public: + virtual ~AmplifyStrategy() = default; + virtual std::string_view name() const = 0; + virtual AmplifyResult Amplify(const AmplifyRequest& request, Random& rng) = 0; + // The effective parameters, for the `start` event and --print-config. + virtual JsonObject Params() const = 0; + // How many times the step may run for one signature in one session. + virtual int per_signature() const { return 1; } +}; + +// Builds a strategy from its name and params; nullptr with a message if the +// name or a parameter is unknown or out of range. +std::unique_ptr<AmplifyStrategy> CreateAmplifyStrategy(std::string_view name, + const JsonValue& params, + std::string* error); + +// Name, parameters and documentation of every strategy, for --help-config. +struct AmplifyStrategyInfo { + std::string_view name; + std::string_view doc; + std::vector<ParamSpec> params; +}; +std::vector<AmplifyStrategyInfo> AmplifyStrategies(); + +// The --stress-runs count for one process: about loop_time_sec of runs, +// between 2 and max_loops. +int StressRunsFor(uint64_t exec_time_us, double loop_time_sec, int max_loops); + +// `program` with its statements inside try { ... } catch (e) {} (a directive +// prologue stays in front), so that an uncaught exception does not end a +// --stress-runs loop. Empty if the program does not parse or is empty. +std::string WrapInTry(const std::string& program); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_AMPLIFIER_H_ diff --git a/deps/v8/experimental/redline/engine/config.cc b/deps/v8/experimental/redline/engine/config.cc new file mode 100644 index 000000000000..757d4138e3ad --- /dev/null +++ b/deps/v8/experimental/redline/engine/config.cc @@ -0,0 +1,1390 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/config.h" + +#include <unistd.h> + +#include <cctype> +#include <cerrno> +#include <cmath> +#include <cstdlib> +#include <cstring> +#include <initializer_list> +#include <string_view> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/json_parser.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/corpus/corpus.h" +#include "experimental/redline/engine/amplifier.h" +#include "experimental/redline/engine/prelude.h" +#include "experimental/redline/generators/generator.h" +#include "experimental/redline/mutators/mutator.h" + +namespace redline { + +namespace { + +std::vector<std::string> SplitWhitespace(const std::string& text) { + std::vector<std::string> out; + size_t i = 0; + while (i < text.size()) { + while (i < text.size() && isspace(static_cast<unsigned char>(text[i]))) { + i++; + } + size_t start = i; + while (i < text.size() && !isspace(static_cast<unsigned char>(text[i]))) { + i++; + } + if (i > start) { + out.push_back(text.substr(start, i - start)); + } + } + return out; +} + +// --- selection ------------------------------------------------------------- + +// "init": {"strategy": "generate"|"import", "params": {...}} (DESIGN.md 5.1). +// Both strategies set the fields the engine already uses: +// generate: {"programs": N} -> initial_programs +// import: {"paths": [...], "root": DIR, -> imports, import_root, +// "keep": "new-coverage"|"all", -> import_all +// "minimize": BOOL} -> minimize_imports +bool ReadInitConfig(const JsonValue& init, FuzzConfig* c, std::string* error) { + if (init.is_null()) { + return true; + } + const std::string usage = + "config: \"init\" must be {\"strategy\": \"generate\"|\"import\", " + "\"params\": {...}}"; + if (!init.is_object()) { + *error = usage; + return false; + } + for (const auto& [key, value] : init.as_object()) { + if (key != "strategy" && key != "params") { + *error = usage; + return false; + } + } + const std::string strategy = init.GetString("strategy", ""); + const JsonValue& params = init.Get("params"); + if (!params.is_null() && !params.is_object()) { + *error = usage; + return false; + } + std::vector<std::string> allowed; + if (strategy == "generate") { + allowed = {"programs"}; + } else if (strategy == "import") { + allowed = {"paths", "root", "keep", "minimize"}; + } else { + *error = "config: unknown init strategy \"" + strategy + + "\" (known: generate, import)"; + return false; + } + if (params.is_object()) { + for (const auto& [key, value] : params.as_object()) { + if (std::find(allowed.begin(), allowed.end(), key) == allowed.end()) { + *error = StringPrintf( + "config: unknown parameter \"%s\" of init strategy \"%s\" (known: " + "%s)", + key.c_str(), strategy.c_str(), JoinNames(allowed).c_str()); + return false; + } + } + } + if (strategy == "generate") { + c->imports.clear(); + if (params.is_object()) { + c->initial_programs = + static_cast<int>(params.GetInt("programs", c->initial_programs)); + } + return true; + } + if (!params.is_object()) { + return true; + } + const JsonValue& paths = params.Get("paths"); + if (!paths.is_null()) { + if (!paths.is_array()) { + *error = + "config: init.params.paths must be a list of files or directories"; + return false; + } + c->imports.clear(); + for (const JsonValue& path : paths.as_array()) { + if (!path.is_string()) { + *error = + "config: init.params.paths must be a list of files or directories"; + return false; + } + c->imports.push_back(path.as_string()); + } + } + c->import_root = params.GetString("root", c->import_root); + c->minimize_imports = params.GetBool("minimize", c->minimize_imports); + if (params.Has("keep")) { + const std::string keep = params.GetString("keep", ""); + if (keep != "new-coverage" && keep != "all") { + *error = "config: init.params.keep must be \"new-coverage\" or \"all\""; + return false; + } + c->import_all = keep == "all"; + } + return true; +} + +// "accept": {"strategy": "new-edges"} (DESIGN.md 5.5). The criterion that +// admits a sample into the corpus; its determinism check is configured in +// stages.check. `new-edges` is the only criterion today: a new one adds a +// name here and returns its frozen reason to Commit (the minimizer oracle). +bool ReadAcceptConfig(const JsonValue& accept, FuzzConfig* c, + std::string* error) { + if (accept.is_null()) { + return true; + } + if (!accept.is_object()) { + *error = "config: \"accept\" must be {\"strategy\": \"new-edges\"}"; + return false; + } + for (const auto& [key, value] : accept.as_object()) { + if (key != "strategy") { + *error = + "config: unknown key \"" + key + "\" in \"accept\" (known: strategy)"; + return false; + } + } + const std::string strategy = accept.GetString("strategy", ""); + if (strategy != "new-edges") { + *error = "config: unknown accept strategy \"" + strategy + + "\" (known: new-edges)"; + return false; + } + c->accept_strategy = strategy; + return true; +} + +// "amplify": {"strategy": "flags"|"none", "params": {...}} (DESIGN.md 5.8). +// The strategy validates its params when it is built. +bool ReadAmplifyConfig(const JsonValue& amplify, FuzzConfig* c, + std::string* error) { + if (amplify.is_null()) { + return true; + } + if (!amplify.is_object()) { + *error = + "config: \"amplify\" must be {\"strategy\": NAME, \"params\": {...}}"; + return false; + } + for (const auto& [key, value] : amplify.as_object()) { + if (key != "strategy" && key != "params") { + *error = "config: unknown key \"" + key + + "\" in \"amplify\" (known: strategy, params)"; + return false; + } + } + const std::string strategy = + amplify.GetString("strategy", c->amplify_strategy); + const JsonValue& params = amplify.Get("params"); + std::string why; + if (CreateAmplifyStrategy(strategy, params, &why) == nullptr) { + *error = "config: " + why; + return false; + } + c->amplify_strategy = strategy; + c->amplify_params = params.is_null() ? "{}" : params.ToString(); + return true; +} + +// Reads one {"strategy": NAME, "params": {...}} object into `out`. A plain +// string is accepted as a strategy name without parameters. +bool ReadSelectionConfig(const JsonValue& object, const char* point, + SelectionConfig* out, std::string* error) { + const JsonValue& value = object.Get(point); + if (value.is_null()) { + return true; + } + if (value.is_string()) { + out->strategy = value.as_string(); + return true; + } + if (!value.is_object()) { + *error = StringPrintf( + "config: \"selection.%s\" must be {\"strategy\": NAME, \"params\": " + "{...}}", + point); + return false; + } + for (const auto& [key, member] : value.as_object()) { + if (key == "strategy") { + if (!member.is_string()) { + *error = StringPrintf( + "config: \"selection.%s.strategy\" must be a string", point); + return false; + } + out->strategy = member.as_string(); + } else if (key == "params") { + if (!member.is_object()) { + *error = StringPrintf( + "config: \"selection.%s.params\" must be an object", point); + return false; + } + out->params = member; + } else { + *error = StringPrintf("config: unknown key \"%s\" in \"selection.%s\"", + key.c_str(), point); + return false; + } + } + return true; +} + +// Merges name -> weight pairs into cfg->params.weights (later pairs win). +// JsonValue has no setters, so the object is rebuilt as text and parsed. +bool AddWeightOverrides( + SelectionConfig* cfg, + const std::vector<std::pair<std::string, double>>& pairs, + std::string* error) { + if (pairs.empty()) { + return true; + } + std::vector<std::pair<std::string, double>> merged; + if (!ReadWeightOverrides(cfg->params, &merged, error)) { + return false; + } + for (const auto& [name, weight] : pairs) { + bool replaced = false; + for (auto& existing : merged) { + if (existing.first == name) { + existing.second = weight; + replaced = true; + } + } + if (!replaced) { + merged.emplace_back(name, weight); + } + } + JsonObject weights; + for (const auto& [name, weight] : merged) { + weights.Add(name, weight); + } + JsonObject params; + if (cfg->params.is_object()) { + for (const auto& [key, member] : cfg->params.as_object()) { + if (key != "weights") { + params.AddRaw(key, member.ToString()); + } + } + } + params.AddRaw("weights", weights.ToString()); + return JsonValue::Parse(params.ToString(), &cfg->params, error); +} + +// Reads the legacy {"Name": weight} object under `key` into `pairs`. +bool ReadLegacyWeights(const JsonValue& object, const char* key, + std::vector<std::pair<std::string, double>>* pairs, + std::string* error) { + const JsonValue& weights = object.Get(key); + if (weights.is_null()) { + return true; + } + if (!weights.is_object()) { + *error = + StringPrintf("config: \"%s\" must be an object of name -> weight", key); + return false; + } + for (const auto& [name, value] : weights.as_object()) { + if (!value.is_number() || value.as_number() < 0) { + *error = + StringPrintf("config: weight of \"%s\" must be a non-negative number", + name.c_str()); + return false; + } + pairs->emplace_back(name, value.as_number()); + } + return true; +} + +std::string SelectionConfigJson(const SelectionConfig& cfg, + std::string_view default_name) { + JsonObject o; + o.Add("strategy", + cfg.strategy.empty() ? std::string(default_name) : cfg.strategy); + o.AddRaw("params", cfg.params.is_null() ? "{}" : cfg.params.ToString()); + return o.ToString(); +} + +// Parses "Name=W,Name2=W2" from the command line. +bool ParseWeightList(const std::vector<std::string>& items, + std::vector<std::pair<std::string, double>>* out, + std::string* error) { + for (const std::string& item : items) { + size_t eq = item.find('='); + if (eq == std::string::npos || eq == 0 || eq + 1 >= item.size()) { + *error = StringPrintf("expected NAME=WEIGHT, got '%s'", item.c_str()); + return false; + } + const char* start = item.c_str() + eq + 1; + char* end = nullptr; + double weight = strtod(start, &end); + if (end == start || *end != '\0' || !std::isfinite(weight) || + weight < 0.0) { + *error = + StringPrintf("weight of '%s' must be a non-negative number, got '%s'", + item.substr(0, eq).c_str(), start); + return false; + } + out->emplace_back(item.substr(0, eq), weight); + } + return true; +} + +void ReadMinimizerOptions(const JsonValue& object, MinimizerOptions* m) { + if (!object.is_object()) { + return; + } + m->max_tests = static_cast<int>(object.GetInt("max_tests", m->max_tests)); + m->max_time_ms = static_cast<uint64_t>( + object.GetInt("max_time_ms", static_cast<int64_t>(m->max_time_ms))); + m->max_rounds = static_cast<int>(object.GetInt("max_rounds", m->max_rounds)); + m->target_time_ms = static_cast<uint64_t>( + object.GetInt("target_time_ms", static_cast<int64_t>(m->target_time_ms))); + m->min_tests = static_cast<int>(object.GetInt("min_tests", m->min_tests)); +} + +std::string MinimizerOptionsJson(const MinimizerOptions& m) { + JsonObject o; + o.Add("max_tests", m.max_tests); + o.Add("max_time_ms", static_cast<uint64_t>(m.max_time_ms)); + o.Add("max_rounds", m.max_rounds); + o.Add("target_time_ms", static_cast<uint64_t>(m.target_time_ms)); + o.Add("min_tests", m.min_tests); + return o.ToString(); +} + +// --- stages ---------------------------------------------------------------- + +// Reads the three common knobs of a stage ("log", "capture", "stats"). +bool ReadStageOptions(Stage stage, const JsonValue& object, StageOptions* out, + std::string* error) { + std::string stage_name(StageName(stage)); + if (object.Has("log")) { + const JsonValue& log = object.Get("log"); + if (!log.is_string() || + (log.as_string() != "events" && log.as_string() != "off")) { + *error = + "config: stages." + stage_name + ".log must be \"events\" or \"off\""; + return false; + } + out->events = log.as_string() == "events"; + } + if (object.Has("capture")) { + std::string detail; + if (!CaptureRule::FromJson(stage, object.Get("capture"), &out->capture, + &detail)) { + *error = "config: stages." + stage_name + ": " + detail; + return false; + } + } + if (object.Has("stats")) { + out->stats = object.GetBool("stats", out->stats); + } + return true; +} + +// The names of a constant list of keys, for an error message. +std::string JoinKeys(std::initializer_list<std::string_view> keys) { + return JoinNames(std::vector<std::string>(keys.begin(), keys.end())); +} + +// The "stages" block: every stage with its own parameters (which are the +// policy fields of FuzzConfig) plus log/capture/stats. +bool ReadStages(const JsonValue& json, FuzzConfig* c, std::string* error) { + const JsonValue& stages = json.Get("stages"); + if (stages.is_null()) { + return true; + } + if (!stages.is_object()) { + *error = "config: \"stages\" must be an object"; + return false; + } + // Known parameter keys per stage; "log", "capture" and "stats" are + // common to all. + static constexpr std::initializer_list<std::string_view> kCommon = { + "log", "capture", "stats"}; + static constexpr std::initializer_list<std::string_view> kKeys[kNumStages] = { + {}, // pick + {"enabled", "min_values", "extra_values"}, // prefix + {"consecutive", "rounds"}, // mutate + {"min_reruns", "min_stable_reruns", "max_reruns", + "flaky_threshold"}, // check + {"enabled", "max_tests", "max_time_ms", "max_rounds", "target_time_ms", + "min_tests", "probe_timeout_factor", "probe_timeout_extra_ms", + "probe_timeout_min_ms", "verify_attempts", "reducers"}, // minimize + {"save_corpus"}, // publish + }; + for (const auto& [stage_name, object] : stages.as_object()) { + Stage stage; + if (!ParseStage(stage_name, &stage)) { + *error = "config: unknown stage \"" + stage_name + + "\" (known: pick, prefix, mutate, check, minimize, publish)"; + return false; + } + if (!object.is_object()) { + *error = "config: stages." + stage_name + " must be an object"; + return false; + } + const std::initializer_list<std::string_view>& keys = + kKeys[static_cast<int>(stage)]; + for (const auto& [key, value] : object.as_object()) { + bool known = + std::find(kCommon.begin(), kCommon.end(), key) != kCommon.end() || + std::find(keys.begin(), keys.end(), key) != keys.end(); + if (!known) { + *error = "config: unknown key \""; + *error += key; + *error += "\" in stages."; + *error += stage_name; + *error += " (known: "; + *error += JoinKeys(keys); + *error += keys.size() == 0 ? "" : ", "; + *error += JoinKeys(kCommon); + *error += ')'; + return false; + } + } + if (!ReadStageOptions(stage, object, &c->stage(stage), error)) { + return false; + } + switch (stage) { + case Stage::kPick: + break; + case Stage::kPrefix: + c->value_prefix = object.GetBool("enabled", c->value_prefix); + c->prefix_min_values = + static_cast<int>(object.GetInt("min_values", c->prefix_min_values)); + c->prefix_extra_values = static_cast<int>( + object.GetInt("extra_values", c->prefix_extra_values)); + break; + case Stage::kMutate: + c->consecutive_mutations = static_cast<int>( + object.GetInt("consecutive", c->consecutive_mutations)); + c->mutation_rounds = + static_cast<int>(object.GetInt("rounds", c->mutation_rounds)); + break; + case Stage::kCheck: + c->min_reruns = + static_cast<int>(object.GetInt("min_reruns", c->min_reruns)); + c->min_stable_reruns = static_cast<int>( + object.GetInt("min_stable_reruns", c->min_stable_reruns)); + c->max_reruns = + static_cast<int>(object.GetInt("max_reruns", c->max_reruns)); + c->flaky_threshold = static_cast<int>( + object.GetInt("flaky_threshold", c->flaky_threshold)); + break; + case Stage::kMinimize: + c->minimize = object.GetBool("enabled", c->minimize); + ReadMinimizerOptions(object, &c->minimizer); + c->probe_timeout_factor = + object.GetNumber("probe_timeout_factor", c->probe_timeout_factor); + c->probe_timeout_extra_ms = object.GetNumber("probe_timeout_extra_ms", + c->probe_timeout_extra_ms); + c->probe_timeout_min_ms = + object.GetNumber("probe_timeout_min_ms", c->probe_timeout_min_ms); + c->verify_attempts = static_cast<int>( + object.GetInt("verify_attempts", c->verify_attempts)); + if (object.Has("reducers")) { + const JsonValue& list = object.Get("reducers"); + if (!list.is_array()) { + *error = + "config: stages.minimize.reducers must be a list of reducer " + "names"; + return false; + } + c->minimizer_reducers.clear(); + for (const JsonValue& name : list.as_array()) { + if (!name.is_string()) { + *error = + "config: stages.minimize.reducers must be a list of reducer " + "names"; + return false; + } + c->minimizer_reducers.push_back(name.as_string()); + } + } + break; + case Stage::kPublish: + c->save_corpus = object.GetBool("save_corpus", c->save_corpus); + break; + } + } + return true; +} + +std::string StagesJson(const FuzzConfig& c) { + auto common = [&](Stage stage, JsonObject* o) { + const StageOptions& opt = c.stage(stage); + o->Add("log", opt.events ? "events" : "off"); + o->AddRaw("capture", opt.capture.ToJson()); + o->Add("stats", opt.stats); + }; + JsonObject stages; + { + JsonObject o; + common(Stage::kPick, &o); + stages.AddRaw("pick", o.ToString()); + } + { + JsonObject o; + o.Add("enabled", c.value_prefix); + o.Add("min_values", c.prefix_min_values) + .Add("extra_values", c.prefix_extra_values); + common(Stage::kPrefix, &o); + stages.AddRaw("prefix", o.ToString()); + } + { + JsonObject o; + o.Add("consecutive", c.consecutive_mutations) + .Add("rounds", c.mutation_rounds); + common(Stage::kMutate, &o); + stages.AddRaw("mutate", o.ToString()); + } + { + JsonObject o; + o.Add("min_reruns", c.min_reruns) + .Add("min_stable_reruns", c.min_stable_reruns); + o.Add("max_reruns", c.max_reruns).Add("flaky_threshold", c.flaky_threshold); + common(Stage::kCheck, &o); + stages.AddRaw("check", o.ToString()); + } + { + JsonObject o; + o.Add("enabled", c.minimize); + o.Add("max_tests", c.minimizer.max_tests) + .Add("max_time_ms", c.minimizer.max_time_ms); + o.Add("max_rounds", c.minimizer.max_rounds) + .Add("target_time_ms", c.minimizer.target_time_ms); + o.Add("min_tests", c.minimizer.min_tests); + o.Add("probe_timeout_factor", c.probe_timeout_factor) + .Add("probe_timeout_extra_ms", c.probe_timeout_extra_ms); + o.Add("probe_timeout_min_ms", c.probe_timeout_min_ms) + .Add("verify_attempts", c.verify_attempts); + { + // The effective order: without a configured list, the default one. + std::vector<std::string> reducers = c.minimizer_reducers; + if (reducers.empty()) { + reducers.assign(Minimizer::DefaultOrder().begin(), + Minimizer::DefaultOrder().end()); + } + o.AddArray("reducers", reducers); + } + common(Stage::kMinimize, &o); + stages.AddRaw("minimize", o.ToString()); + } + { + JsonObject o; + o.Add("save_corpus", c.save_corpus); + common(Stage::kPublish, &o); + stages.AddRaw("publish", o.ToString()); + } + return stages.ToString(); +} + +bool ApplyJson(const JsonValue& json, FuzzConfig* c, std::string* error) { + if (!json.is_object()) { + *error = "config: top level must be an object"; + return false; + } + c->jobs = static_cast<int>(json.GetInt("jobs", c->jobs)); + c->seed = + static_cast<uint64_t>(json.GetInt("seed", static_cast<int64_t>(c->seed))); + c->out_dir = json.GetString("out_dir", c->out_dir); + c->import_root = json.GetString("import_root", c->import_root); + c->duration_sec = json.GetNumber("duration_sec", c->duration_sec); + c->max_execs = static_cast<uint64_t>( + json.GetInt("max_execs", static_cast<int64_t>(c->max_execs))); + c->stats_interval_sec = + json.GetNumber("stats_interval_sec", c->stats_interval_sec); + c->component_stats = json.GetBool("component_stats", c->component_stats); + c->save_corpus = json.GetBool("save_corpus", c->save_corpus); + c->introspect = json.GetBool("introspect", c->introspect); + c->introspect_timeout_ms = + json.GetNumber("introspect_timeout_ms", c->introspect_timeout_ms); + c->v8_flags = json.GetString("v8_flags", c->v8_flags); + c->syntax_check = json.GetBool("syntax_check", c->syntax_check); + c->consecutive_mutations = static_cast<int>( + json.GetInt("consecutive_mutations", c->consecutive_mutations)); + c->mutation_rounds = + static_cast<int>(json.GetInt("mutation_rounds", c->mutation_rounds)); + c->min_reruns = static_cast<int>(json.GetInt("min_reruns", c->min_reruns)); + c->min_stable_reruns = + static_cast<int>(json.GetInt("min_stable_reruns", c->min_stable_reruns)); + c->max_reruns = static_cast<int>(json.GetInt("max_reruns", c->max_reruns)); + c->flaky_threshold = + static_cast<int>(json.GetInt("flaky_threshold", c->flaky_threshold)); + c->value_prefix = json.GetBool("value_prefix", c->value_prefix); + c->minimize = json.GetBool("minimize", c->minimize); + c->minimize_crashes = json.GetBool("minimize_crashes", c->minimize_crashes); + c->minimize_imports = json.GetBool("minimize_imports", c->minimize_imports); + c->import_all = json.GetBool("import_all", c->import_all); + c->initial_programs = + static_cast<int>(json.GetInt("initial_programs", c->initial_programs)); + if (json.Has("scheduler")) { + c->selection.seeds = + SelectionConfig{json.GetString("scheduler", ""), JsonValue()}; + } + c->crash_reruns = + static_cast<int>(json.GetInt("crash_reruns", c->crash_reruns)); + c->crash_reruns_stop_after = static_cast<int>( + json.GetInt("crash_reruns_stop_after", c->crash_reruns_stop_after)); + c->max_crashes_per_signature = static_cast<int>( + json.GetInt("max_crashes_per_signature", c->max_crashes_per_signature)); + c->minimize_crashes_per_signature = static_cast<int>(json.GetInt( + "minimize_crashes_per_signature", c->minimize_crashes_per_signature)); + c->crash_history = + static_cast<int>(json.GetInt("crash_history", c->crash_history)); + c->crash_history_budget_sec = + json.GetNumber("crash_history_budget_sec", c->crash_history_budget_sec); + c->target.timeout_us = static_cast<uint64_t>( + json.GetNumber("timeout_ms", + static_cast<double>(c->target.timeout_us) / 1000.0) * + 1000.0); + c->target.max_execs_before_respawn = static_cast<int>(json.GetInt( + "max_execs_before_respawn", c->target.max_execs_before_respawn)); + if (json.Has("d8")) { + c->target.executable = json.GetString("d8", ""); + } + const JsonValue& d8_args = json.Get("d8_args"); + if (d8_args.is_array()) { + c->target.args.clear(); + for (const JsonValue& arg : d8_args.as_array()) { + if (arg.is_string()) { + c->target.args.push_back(arg.as_string()); + } + } + } + // Appended to the d8 flags, like --d8-extra-args (presets use it). + const JsonValue& d8_extra_args = json.Get("d8_extra_args"); + if (d8_extra_args.is_array()) { + for (const JsonValue& arg : d8_extra_args.as_array()) { + if (arg.is_string()) { + c->target.args.push_back(arg.as_string()); + } + } + } + ReadMinimizerOptions(json.Get("minimizer"), &c->minimizer); + ReadMinimizerOptions(json.Get("crash_minimizer"), &c->crash_minimizer); + const JsonValue& imports = json.Get("imports"); + if (imports.is_array()) { + c->imports.clear(); + for (const JsonValue& path : imports.as_array()) { + if (path.is_string()) { + c->imports.push_back(path.as_string()); + } + } + } + if (json.Has("prelude")) { + c->prelude_source = json.GetString("prelude", "default"); + } + // When both "imports" and "init" are present (such as in a full config dump + // where "imports" is edited in place), keep explicit "imports" if "init" + // only carries the default "generate" strategy. + std::vector<std::string> explicit_imports = c->imports; + if (!ReadInitConfig(json.Get("init"), c, error) || + !ReadAcceptConfig(json.Get("accept"), c, error) || + !ReadAmplifyConfig(json.Get("amplify"), c, error)) { + return false; + } + if (c->imports.empty() && !explicit_imports.empty() && + json.Get("init").GetString("strategy", "") == "generate" && + imports.is_array() && !imports.as_array().empty()) { + c->imports = std::move(explicit_imports); + } + const JsonValue& selection = json.Get("selection"); + if (!selection.is_null() && !selection.is_object()) { + *error = "config: \"selection\" must be an object"; + return false; + } + if (!ReadSelectionConfig(selection, "seeds", &c->selection.seeds, error) || + !ReadSelectionConfig(selection, "partners", &c->selection.partners, + error) || + !ReadSelectionConfig(selection, "mutators", &c->selection.mutators, + error) || + !ReadSelectionConfig(selection, "generators", &c->selection.generators, + error)) { + return false; + } + // Legacy shorthands: {"mutators": {"Name": weight}}, same for generators. + std::vector<std::pair<std::string, double>> pairs; + if (!ReadLegacyWeights(json, "mutators", &pairs, error) || + !AddWeightOverrides(&c->selection.mutators, pairs, error)) { + return false; + } + pairs.clear(); + if (!ReadLegacyWeights(json, "generators", &pairs, error) || + !AddWeightOverrides(&c->selection.generators, pairs, error)) { + return false; + } + // Tunables: {"name": value}. + const JsonValue& tunables = json.Get("tunables"); + if (!tunables.is_null()) { + if (!tunables.is_object()) { + *error = "config: \"tunables\" must be an object of {\"name\": number}"; + return false; + } + for (const auto& [name, value] : tunables.as_object()) { + if (!value.is_number()) { + *error = "config: tunable \"" + name + "\" must be a number"; + return false; + } + if (!TunableRegistry::Instance().Set(name, value.as_number(), error)) { + *error = "config: " + *error; + return false; + } + } + } + // The "stages" block last: it groups the same parameters by stage and + // wins over the flat keys above. + return ReadStages(json, c, error); +} + +} // namespace + +// static +bool FuzzConfig::Load(const Flags& flags, FuzzConfig* c, std::string* error, + bool for_run) { + TunableRegistry::Instance().Reset(); + c->target.args = TargetOptions::DefaultArgs(); + // Fuzzing favours a short timeout: a mutant that runs longer than that is + // almost always an endless loop, and it would eat the time of ten others. + c->target.timeout_us = static_cast<uint64_t>(500) * 1000; + c->prelude_source = "default"; + + // Layer 1b: a preset (DESIGN.md 8), a configuration for one use case: + // --preset=NAME loads experimental/redline/presets/NAME.json (found next to + // the binary, like the testdata), --preset=FILE.json any file. --config and + // the flags override it. + std::string preset = flags.GetString("preset"); + if (!preset.empty()) { + std::string path = preset; + if (path.find('/') == std::string::npos && + path.find(".json") == std::string::npos) { + path = RedlineDataDir("presets") + "/" + preset + ".json"; + } + std::string text; + if (!ReadFileToString(path, &text, error)) { + *error = "--preset=" + preset + ": " + *error; + return false; + } + JsonValue json; + if (!JsonValue::Parse(text, &json, error) || !ApplyJson(json, c, error)) { + *error = "--preset=" + preset + ": " + *error; + return false; + } + } + + // Layer 2: config file, or inline JSON ('{...}') for a one-off override + // of any key from the command line. + std::string config_arg = flags.GetString("config"); + if (!config_arg.empty()) { + std::string text; + std::string where = "--config"; + if (config_arg[0] == '{') { + text = config_arg; + } else { + where = config_arg; + if (!ReadFileToString(config_arg, &text, error)) { + return false; + } + } + JsonValue json; + if (!JsonValue::Parse(text, &json, error)) { + *error = where + ":" + *error; + return false; + } + if (!ApplyJson(json, c, error)) { + return false; + } + } + + // Layer 3: command line. Each target flag overrides the file only when + // given; the executable falls back to the file, then to $REDLINE_D8. + { + std::string d8 = flags.GetString("d8"); + if (d8.empty()) { + d8 = c->target.executable; + } + if (d8.empty()) { + const char* from_env = getenv("REDLINE_D8"); + if (from_env != nullptr) { + d8 = from_env; + } + } + if (d8.empty() && for_run) { + *error = + "No target given: pass --d8=PATH, set \"d8\" in the config or " + "$REDLINE_D8"; + return false; + } + if (for_run && !d8.empty() && access(d8.c_str(), X_OK) != 0) { + *error = StringPrintf("--d8=%s is not an executable file: %s", d8.c_str(), + strerror(errno)); + return false; + } + c->target.executable = d8; + if (flags.Has("d8-args")) { + c->target.args = SplitWhitespace(flags.GetString("d8-args")); + } + for (const std::string& arg : + SplitWhitespace(flags.GetString("d8-extra-args"))) { + c->target.args.push_back(arg); + } + for (const std::string& entry : flags.GetList("d8-env")) { + size_t eq = entry.find('='); + if (eq == std::string::npos) { + *error = StringPrintf( + "--d8-env entry '%s' is not of the form KEY=VALUE", entry.c_str()); + return false; + } + c->target.extra_env.emplace_back(entry.substr(0, eq), + entry.substr(eq + 1)); + } + if (flags.Has("timeout-ms")) { + int64_t timeout_ms = flags.GetInt("timeout-ms", 1000); + if (timeout_ms <= 0) { + *error = "--timeout-ms must be positive"; + return false; + } + c->target.timeout_us = static_cast<uint64_t>(timeout_ms) * 1000; + } + if (flags.Has("max-execs-before-respawn")) { + c->target.max_execs_before_respawn = + static_cast<int>(flags.GetInt("max-execs-before-respawn", 1000)); + } + c->target.capture_output = + flags.GetBool("capture-output", c->target.capture_output); + } + + c->jobs = static_cast<int>(flags.GetInt("jobs", c->jobs)); + c->seed = static_cast<uint64_t>( + flags.GetInt("seed", static_cast<int64_t>(c->seed))); + c->out_dir = flags.GetString("out", c->out_dir); + c->import_root = flags.GetString("import-root", c->import_root); + c->duration_sec = flags.GetDouble("duration", c->duration_sec); + c->max_execs = static_cast<uint64_t>( + flags.GetInt("max-execs", static_cast<int64_t>(c->max_execs))); + c->stats_interval_sec = + flags.GetDouble("stats-interval", c->stats_interval_sec); + c->component_stats = flags.GetBool("component-stats", c->component_stats); + c->save_corpus = flags.GetBool("save-corpus", c->save_corpus); + c->quiet = flags.GetBool("quiet", c->quiet); + c->introspect = flags.GetBool("introspect", c->introspect); + c->syntax_check = flags.GetBool("syntax-check", c->syntax_check); + c->consecutive_mutations = static_cast<int>( + flags.GetInt("consecutive-mutations", c->consecutive_mutations)); + c->mutation_rounds = + static_cast<int>(flags.GetInt("rounds", c->mutation_rounds)); + c->min_reruns = static_cast<int>(flags.GetInt("min-reruns", c->min_reruns)); + c->min_stable_reruns = + static_cast<int>(flags.GetInt("min-stable-reruns", c->min_stable_reruns)); + c->max_reruns = static_cast<int>(flags.GetInt("max-reruns", c->max_reruns)); + c->flaky_threshold = + static_cast<int>(flags.GetInt("flaky-threshold", c->flaky_threshold)); + c->value_prefix = flags.GetBool("value-prefix", c->value_prefix); + c->minimize = flags.GetBool("minimize", c->minimize); + c->minimize_crashes = flags.GetBool("minimize-crashes", c->minimize_crashes); + c->minimize_imports = flags.GetBool("minimize-imports", c->minimize_imports); + c->import_all = flags.GetBool("import-all", c->import_all); + c->initial_programs = + static_cast<int>(flags.GetInt("initial-programs", c->initial_programs)); + c->minimizer.max_tests = static_cast<int>( + flags.GetInt("minimizer-max-tests", c->minimizer.max_tests)); + c->minimizer.max_time_ms = static_cast<uint64_t>(flags.GetInt( + "minimizer-max-time-ms", static_cast<int64_t>(c->minimizer.max_time_ms))); + c->minimizer.target_time_ms = static_cast<uint64_t>( + flags.GetInt("minimizer-target-time-ms", + static_cast<int64_t>(c->minimizer.target_time_ms))); + c->crash_reruns = + static_cast<int>(flags.GetInt("crash-reruns", c->crash_reruns)); + c->max_crashes_per_signature = static_cast<int>( + flags.GetInt("max-crashes-per-signature", c->max_crashes_per_signature)); + c->minimize_crashes_per_signature = static_cast<int>(flags.GetInt( + "minimize-crashes-per-signature", c->minimize_crashes_per_signature)); + c->crash_history = + static_cast<int>(flags.GetInt("crash-history", c->crash_history)); + c->crash_history_budget_sec = + flags.GetDouble("crash-history-budget", c->crash_history_budget_sec); + c->crash_minimizer.max_tests = static_cast<int>( + flags.GetInt("crash-minimizer-max-tests", c->crash_minimizer.max_tests)); + c->crash_minimizer.max_time_ms = static_cast<uint64_t>( + flags.GetInt("crash-minimizer-max-time-ms", + static_cast<int64_t>(c->crash_minimizer.max_time_ms))); + if (flags.Has("scheduler")) { + // The flag names a strategy without parameters: it replaces the + // whole seeds setting, including parameters a config file gave to + // another strategy. + c->selection.seeds = + SelectionConfig{flags.GetString("scheduler", ""), JsonValue()}; + } + c->v8_flags = flags.GetString("v8-flags", c->v8_flags); + for (const std::string& path : flags.GetList("import")) { + c->imports.push_back(path); + } + std::vector<std::pair<std::string, double>> pairs; + if (!ParseWeightList(flags.GetList("mutator-weights"), &pairs, error)) { + return false; + } + for (const std::string& name : flags.GetList("disable-mutator")) { + pairs.emplace_back(name, 0.0); + } + if (!AddWeightOverrides(&c->selection.mutators, pairs, error)) { + return false; + } + pairs.clear(); + if (!ParseWeightList(flags.GetList("generator-weights"), &pairs, error)) { + return false; + } + for (const std::string& name : flags.GetList("disable-generator")) { + pairs.emplace_back(name, 0.0); + } + if (!AddWeightOverrides(&c->selection.generators, pairs, error)) { + return false; + } + c->prefix_min_values = + static_cast<int>(flags.GetInt("prefix-min-values", c->prefix_min_values)); + c->prefix_extra_values = static_cast<int>( + flags.GetInt("prefix-extra-values", c->prefix_extra_values)); + for (const std::string& rule : flags.GetList("capture", ';')) { + Stage stage; + CaptureRule capture; + if (!CaptureRule::FromFlag(rule, &stage, &capture, error)) { + return false; + } + c->stage(stage).capture = capture; + } + if (flags.Has("tunable") && !TunableRegistry::Instance().SetFromList( + flags.GetString("tunable"), error)) { + return false; + } + for (const std::string& name : flags.GetList("stage-log")) { + Stage stage; + if (!ParseStage(name, &stage)) { + *error = "--stage-log: unknown stage '" + name + + "' (known: pick, prefix, mutate, check, minimize, publish)"; + return false; + } + c->stage(stage).events = true; + } + if (flags.Has("prelude")) { + c->prelude_source = flags.GetString("prelude", "default"); + } + + // Resolve the prelude. + if (c->prelude_source.empty() || c->prelude_source == "default") { + c->prelude = std::string(DefaultPrelude()); + c->prelude_source = "default"; + } else if (c->prelude_source == "none") { + c->prelude.clear(); + } else if (!ReadFileToString(c->prelude_source, &c->prelude, error)) { + return false; + } + + // Validation. + if (c->jobs < 1) { + *error = "--jobs must be at least 1"; + return false; + } + // The run seed is drawn only when there is a run; --dump-config shows 0 + // (= from the clock) like the configuration said. + if (c->seed == 0 && for_run) { + c->seed = WallClockNowMs() ^ 0x5eed5eed5eedull; + } + if (c->consecutive_mutations < 1) { + c->consecutive_mutations = 1; + } + if (c->mutation_rounds < 0) { + c->mutation_rounds = 0; + } + if (c->prefix_min_values < 1) { + c->prefix_min_values = 1; + } + if (c->prefix_extra_values < 0) { + c->prefix_extra_values = 0; + } + if (c->min_stable_reruns < 1) { + c->min_stable_reruns = 1; + } + if (c->min_reruns < c->min_stable_reruns) { + c->min_reruns = c->min_stable_reruns; + } + if (c->max_reruns < c->min_reruns) { + c->max_reruns = c->min_reruns; + } + if (c->flaky_threshold < 1) { + c->flaky_threshold = 1; + } + if (c->crash_reruns < 1) { + c->crash_reruns = 1; + } + if (c->crash_reruns_stop_after < 1) { + c->crash_reruns_stop_after = 1; + } + if (c->max_crashes_per_signature < 1) { + c->max_crashes_per_signature = 1; + } + if (c->crash_history < 0) { + c->crash_history = 0; + } + if (c->verify_attempts < 1) { + c->verify_attempts = 1; + } + c->probe_timeout_factor = std::max(0.0, c->probe_timeout_factor); + c->probe_timeout_extra_ms = std::max(0.0, c->probe_timeout_extra_ms); + c->probe_timeout_min_ms = std::max(0.0, c->probe_timeout_min_ms); + c->introspect_timeout_ms = std::max(1.0, c->introspect_timeout_ms); + if (!ValidateReducers(c->minimizer_reducers, error)) { + return false; + } + return ValidateSelection(c->selection, error); +} + +// static +bool FuzzConfig::ValidateReducers(const std::vector<std::string>& names, + std::string* error) { + std::vector<std::string> known; + for (const auto& reducer : Minimizer::CreateDefaultReducers()) { + known.push_back(reducer->name()); + } + for (const std::string& name : names) { + if (std::find(known.begin(), known.end(), name) == known.end()) { + *error = "config: unknown reducer \"" + name + + "\" in stages.minimize.reducers (known: " + JoinNames(known) + + ")"; + return false; + } + } + return true; +} + +namespace { + +// The selectors built from `selection` exactly as the fuzzer builds them: +// validation and the full configuration dump both go through here, so what +// is reported is what will run. +struct BuiltSelectors { + std::unique_ptr<ProgramSelector> seeds; + std::unique_ptr<ProgramSelector> partners; + std::unique_ptr<MutatorSet> mutators; // owns the mutator selector + std::unique_ptr<GeneratorSet> generators; // owns the generator selector +}; + +bool BuildSelectors(const FuzzConfig::SelectionSettings& selection, + BuiltSelectors* out, std::string* error) { + out->seeds = SelectorRegistry<const Program>::Instance().Create( + selection.seeds, error); + if (out->seeds == nullptr) { + *error = "selection.seeds: " + *error; + return false; + } + SelectionConfig partners = selection.partners; + if (partners.strategy.empty()) { + partners.strategy = "uniform-partner"; + } + out->partners = + SelectorRegistry<const Program>::Instance().Create(partners, error); + if (out->partners == nullptr) { + *error = "selection.partners: " + *error; + return false; + } + out->mutators = MutatorSet::CreateDefault(); + out->generators = GeneratorSet::CreateDefault(); + std::unique_ptr<Selector<Mutator>> mutator_selector = + SelectorRegistry<Mutator>::Instance().Create(selection.mutators, error); + if (mutator_selector == nullptr || + !out->mutators->SetSelector(std::move(mutator_selector), error)) { + *error = "selection.mutators: " + *error; + return false; + } + std::unique_ptr<Selector<Generator>> generator_selector = + SelectorRegistry<Generator>::Instance().Create(selection.generators, + error); + if (generator_selector == nullptr || + !out->generators->SetSelector(std::move(generator_selector), error)) { + *error = "selection.generators: " + *error; + return false; + } + return true; +} + +} // namespace + +std::string FuzzConfig::ToJson(Detail detail) const { + const bool full = detail == Detail::kFull; + JsonObject o; + o.Add("d8", target.executable); + o.AddArray("d8_args", target.args); + o.Add("timeout_ms", static_cast<double>(target.timeout_us) / 1000.0); + o.Add("max_execs_before_respawn", target.max_execs_before_respawn); + o.Add("prelude", prelude_source); + o.Add("jobs", jobs); + o.Add("seed", static_cast<uint64_t>(seed)); + o.Add("out_dir", out_dir); + o.AddArray("imports", imports); + o.Add("import_root", import_root); + o.Add("duration_sec", duration_sec); + o.Add("max_execs", static_cast<uint64_t>(max_execs)); + o.Add("stats_interval_sec", stats_interval_sec); + o.Add("introspect", introspect); + o.Add("introspect_timeout_ms", introspect_timeout_ms); + o.Add("v8_flags", v8_flags); + o.Add("syntax_check", syntax_check); + o.Add("component_stats", component_stats); + o.Add("minimize_crashes", minimize_crashes); + o.Add("minimize_imports", minimize_imports); + o.Add("import_all", import_all); + o.Add("initial_programs", initial_programs); + o.Add("crash_reruns", crash_reruns); + o.Add("crash_reruns_stop_after", crash_reruns_stop_after); + o.Add("max_crashes_per_signature", max_crashes_per_signature); + o.Add("minimize_crashes_per_signature", minimize_crashes_per_signature); + o.Add("crash_history", crash_history); + o.Add("crash_history_budget_sec", crash_history_budget_sec); + o.AddRaw("crash_minimizer", MinimizerOptionsJson(crash_minimizer)); + { + // The Init strategy as the fields describe it, so that loading the + // output back gives the same configuration. + JsonObject init, params; + if (imports.empty()) { + init.Add("strategy", "generate"); + params.Add("programs", initial_programs); + } else { + init.Add("strategy", "import"); + params.AddArray("paths", imports); + params.Add("root", import_root); + params.Add("keep", import_all ? "all" : "new-coverage"); + params.Add("minimize", minimize_imports); + } + init.AddRaw("params", params.ToString()); + o.AddRaw("init", init.ToString()); + JsonObject accept; + accept.Add("strategy", accept_strategy); + o.AddRaw("accept", accept.ToString()); + JsonObject amplify; + amplify.Add("strategy", amplify_strategy); + amplify.AddRaw("params", amplify_params); + o.AddRaw("amplify", amplify.ToString()); + } + JsonObject sel; + BuiltSelectors built; + std::string ignored; + if (full && BuildSelectors(selection, &built, &ignored)) { + // Every parameter of the chosen strategies, as the strategies see + // them (all weights, including the ones left at their default). + auto point = [](std::string_view strategy, const JsonObject& params) { + JsonObject p; + p.Add("strategy", strategy); + p.AddRaw("params", params.ToString()); + return p.ToString(); + }; + sel.AddRaw("seeds", point(built.seeds->name(), built.seeds->Params())); + sel.AddRaw("partners", + point(built.partners->name(), built.partners->Params())); + sel.AddRaw("mutators", point(built.mutators->selector().name(), + built.mutators->selector().Params())); + sel.AddRaw("generators", point(built.generators->selector().name(), + built.generators->selector().Params())); + } else { + sel.AddRaw("seeds", + SelectionConfigJson( + selection.seeds, + SelectorRegistry<const Program>::Instance().default_name())); + sel.AddRaw("partners", + SelectionConfigJson(selection.partners, "uniform-partner")); + sel.AddRaw("mutators", + SelectionConfigJson( + selection.mutators, + SelectorRegistry<Mutator>::Instance().default_name())); + sel.AddRaw("generators", + SelectionConfigJson( + selection.generators, + SelectorRegistry<Generator>::Instance().default_name())); + } + o.AddRaw("selection", sel.ToString()); + o.AddRaw("stages", StagesJson(*this)); + // Compact: only the tunables that were changed (--help-tunables lists + // them all). Full: every one of them with its current value. + o.AddRaw("tunables", full ? TunableRegistry::Instance().AllJson() + : TunableRegistry::Instance().NonDefaultsJson()); + return o.ToString(); +} + +// static +bool FuzzConfig::LoadJsonForTest(const JsonValue& json, FuzzConfig* config, + std::string* error) { + return ApplyJson(json, config, error); +} + +// static +bool FuzzConfig::ValidateSelection(const SelectionSettings& selection, + std::string* error) { + // Build every selector once, exactly as the fuzzer will, so that an + // unknown strategy, parameter or weight name is reported before any + // target is started. + BuiltSelectors built; + return BuildSelectors(selection, &built, error); +} + +// static +std::string FuzzConfig::JsonHelp() { + std::string help = + "config file (--config=FILE or --config='{...}', JSON; flags override " + "it, and it\n" + "overrides --preset=NAME|FILE, a configuration per area in " + "experimental/redline/presets;\n" + "`redline fuzz --dump-config` prints the complete effective " + "configuration with\n" + "every default, ready to be edited and passed back):\n" + " {\n" + " \"d8\": \"out/fuzzbuild/d8\", \"d8_args\": [\"--expose-gc\", ...],\n" + " \"d8_extra_args\": [\"--maglev\"], // appended to d8_args (like " + "--d8-extra-args)\n" + " \"timeout_ms\": 1000, \"jobs\": 8, \"seed\": 1, \"out_dir\": " + "\"redline-out\",\n" + " \"imports\": [\"test/mjsunit\"], \"import_root\": \".\", " + "\"prelude\": \"default\",\n" + " \"duration_sec\": 0, \"max_execs\": 0, \"stats_interval_sec\": 30,\n" + " \"introspect\": true, \"introspect_timeout_ms\": 20000,\n" + " \"syntax_check\": false, // parse mutants in-process " + "before executing them\n" + " \"stages\": { // the worker loop, stage by " + "stage\n" + " \"pick\": {\"stats\": true},\n" + " \"prefix\": {\"enabled\": true, \"min_values\": 10, " + "\"extra_values\": 5},\n" + " \"mutate\": {\"consecutive\": 5, \"rounds\": 0, \"log\": " + "\"off\",\n" + " \"capture\": {\"on\": [\"timeout\"], \"mutators\": " + "[\"Splice\"], \"max\": 50}},\n" + " \"check\": {\"min_reruns\": 5, \"min_stable_reruns\": 1, " + "\"max_reruns\": 50,\n" + " \"flaky_threshold\": 50, \"capture\": {\"on\": " + "[\"flaky\"], \"max\": 20}},\n" + " \"minimize\": {\"enabled\": true, \"max_tests\": 300, " + "\"max_time_ms\": 30000,\n" + " \"max_rounds\": 3, \"target_time_ms\": 6000, " + "\"min_tests\": 40,\n" + " \"probe_timeout_factor\": 5, " + "\"probe_timeout_extra_ms\": 20,\n" + " \"probe_timeout_min_ms\": 50, \"verify_attempts\": " + "3,\n" + " \"reducers\": [\"statements\", \"unwrap\", " + "\"lists\", \"expressions\"]},\n" + " \"publish\": {\"save_corpus\": true}\n" + " },\n" + " \"minimize_crashes\": true, \"minimize_imports\": false,\n" + " \"crash_reruns\": 3, \"crash_reruns_stop_after\": 2, " + "\"max_crashes_per_signature\": 5,\n" + " \"minimize_crashes_per_signature\": 2, \"crash_history\": 100,\n" + " \"crash_history_budget_sec\": 90,\n" + " \"crash_minimizer\": {\"max_tests\": 1000, \"max_time_ms\": 120000, " + "\"max_rounds\": 4,\n" + " \"target_time_ms\": 30000, \"min_tests\": " + "200},\n" + " \"import_all\": false, \"initial_programs\": 32, \"save_corpus\": " + "true,\n" + " \"init\": {\"strategy\": \"import\", // or \"generate\" with " + "{\"programs\": N}\n" + " \"params\": {\"paths\": [\"test/mjsunit\"], \"root\": " + "\".\",\n" + " \"keep\": \"new-coverage\", \"minimize\": " + "false}}, // keep: or \"all\"\n" + " \"accept\": {\"strategy\": \"new-edges\"},\n" + " \"selection\": {\n" + " \"seeds\": {\"strategy\": \"uniform\"},\n" + " \"partners\": {\"strategy\": \"uniform-partner\", \"params\": " + "{\"tries\": 4}},\n" + " \"mutators\": {\"strategy\": \"weighted\", \"params\": " + "{\"weights\": {\"Splice\": 4, \"Reorder\": " + "0}}},\n" + " \"generators\": {\"strategy\": \"weighted\", \"params\": " + "{\"weights\": {\"JitOptimize\": 10}}}\n" + " }\n" + " }\n" + "\n" + " Every stage takes \"log\": \"events\"|\"off\" (one JSONL event per " + "occurrence),\n" + " \"capture\": {\"on\": [trigger, ...], \"mutators\": [...], \"max\": " + "N} (save the\n" + " programs of the stage to OUT/captures/<stage>/ when a trigger fires; " + "triggers:\n" + " mutate: timeout crash failed invalid noop interesting; check: flaky " + "timeout;\n" + " minimize: rejected timeout; prefix: noop) and \"stats\": true|false " + "(row in the\n" + " stages table). Flags: " + "--capture=STAGE:TRIGGER[,..][:MUTATOR[,..]][:MAX] (\';\' between\n" + " rules), --stage-log=STAGE[,..]. The flat keys consecutive_mutations, " + "mutation_rounds,\n" + " min_reruns, min_stable_reruns, max_reruns, flaky_threshold, " + "value_prefix, minimize,\n" + " minimizer, save_corpus are still accepted as shorthands for the stage " + "parameters.\n" + "\n" + " \"tunables\": {\"name\": value} sets the numbers inside generators, " + "mutators and\n" + " reducers (also --tunable=name=value,...); redline fuzz " + "--help-tunables lists\n" + " them with defaults, ranges and documentation. Unknown names and " + "values outside\n" + " the range are errors.\n" + "\n" + " \"init\" sets imports, import_root, import_all and minimize_imports " + "(generate\n" + " clears the imports); the flags --import, --import-all, " + "--initial-programs set the\n" + " same values. \"accept\" names the corpus admission criterion " + "(new-edges only).\n" + " stages.minimize.reducers lists the reducers in order (also truncate, " + "dataflow);\n" + " without it the four above run. Unknown names are errors.\n" + "\n" + " Shorthands: \"scheduler\": NAME (= selection.seeds.strategy), " + "\"mutators\" and\n" + " \"generators\": {\"Name\": weight} (= params.weights of the weighted " + "strategy;\n" + " weight 0 disables). Unknown strategies, parameters and names are " + "errors.\n" + "\n" + " Selection strategies and their parameters (name = default " + "description):\n"; + help += SelectorRegistry<const Program>::Instance().Help("seeds / partners"); + help += SelectorRegistry<Mutator>::Instance().Help("mutators"); + help += SelectorRegistry<Generator>::Instance().Help("generators"); + // The amplify step of crash triage (DESIGN.md 5.8), from its registry. + help += + "\n \"amplify\": {\"strategy\": NAME, \"params\": {...}} searches d8 " + "flags that reproduce a crash\n" + " that does not reproduce alone (default strategy: flags):\n"; + for (const AmplifyStrategyInfo& info : AmplifyStrategies()) { + help += StringPrintf(" %.*s: %.*s\n", static_cast<int>(info.name.size()), + info.name.data(), static_cast<int>(info.doc.size()), + info.doc.data()); + for (const ParamSpec& p : info.params) { + help += StringPrintf( + " %.*s = %.*s %.*s\n", static_cast<int>(p.name.size()), + p.name.data(), static_cast<int>(p.default_value.size()), + p.default_value.data(), static_cast<int>(p.doc.size()), p.doc.data()); + } + } + return help; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/config.h b/deps/v8/experimental/redline/engine/config.h new file mode 100644 index 000000000000..d252aedbd2c2 --- /dev/null +++ b/deps/v8/experimental/redline/engine/config.h @@ -0,0 +1,227 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_ENGINE_CONFIG_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_CONFIG_H_ + +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +#include "experimental/redline/core/selection.h" +#include "experimental/redline/engine/stages.h" +#include "experimental/redline/exec/target_options.h" +#include "experimental/redline/minimizer/minimizer.h" + +namespace redline { + +class Flags; + +// Everything a fuzzing session is parameterized by. Four layers, later +// ones win: built-in defaults, the preset (--preset), the JSON given with +// --config, and the command line. The effective configuration is written +// to the event log so that a run can be reproduced. +// +// JSON keys mirror the field names below (snake_case). The selection +// strategies are configured under "selection" (see SelectionSettings); the +// older top-level keys "scheduler", "mutators" and "generators" are still +// accepted as shorthands for them. +struct FuzzConfig { + // --- target ------------------------------------------------------------- + TargetOptions target; + std::string prelude; // JS prepended to every execution (not mutated) + std::string prelude_source; // "default", "none" or the file it came from + // Flags for the in-process V8 (syntax oracle). Must accept everything the + // target accepts: natives syntax and staged language features. + std::string v8_flags = "--allow-natives-syntax --js-staging --js-decorators"; + // Parse every mutant and every minimizer probe with the in-process V8 + // before executing it, so that syntactically invalid programs never + // reach the target and are counted as `invalid` per mutator. Off by + // default: the mutators produce 0.02% invalid programs and the minimizer + // 0.04% invalid probes, while the parse costs as much worker CPU as the + // mutation itself. Without it, an invalid program fails in the target + // (a SyntaxError at parse time, as cheap as the check) and is counted + // as `invalid` from the target's error message. + bool syntax_check = false; + + // --- session ------------------------------------------------------------ + int jobs = 1; + uint64_t seed = 0; // 0: derived from the clock + std::string out_dir = "redline-out"; + std::vector<std::string> imports; // .js files or directories + std::string import_root; // base for load("...") paths (default: cwd) + double duration_sec = 0; // 0: until interrupted + uint64_t max_execs = 0; // 0: unlimited + double stats_interval_sec = 30; + bool component_stats = true; // per-mutator/generator tables with the stats + bool save_corpus = true; + bool quiet = false; // no periodic stats on stderr + // Enumerate the target's globals at startup + // (Environment::IntrospectionScript) + // ... + bool introspect = true; + // ... giving the script this long; it walks every builtin. + double introspect_timeout_ms = 20000; + + // --- policy ------------------------------------------------------------- + // Mutations applied in a row to one parent, each executed (Fuzzilli's + // numConsecutiveMutations); the chain continues from the child only if + // it ran successfully. + int consecutive_mutations = 5; + // Sub-mutations per mutator application. 0: drawn uniformly from + // 1..Mutator::max_simultaneous() (7 for in-place and splice mutators, 3 + // for code generation, 1 for runtime-assisted and whole-program ones), + // like Fuzzilli's BaseInstructionMutator. N > 0: exactly N. + int mutation_rounds = 0; + // Determinism check (Fuzzilli's processMaybeInteresting): a candidate is + // re-executed at least min_reruns times and until the set of its new + // edges that survived every re-execution did not change for + // min_stable_reruns re-executions in a row; edges that disappear are + // dropped. A candidate that has not converged after max_reruns is + // discarded. + int min_reruns = 5; + int min_stable_reruns = 1; + int max_reruns = 50; + // Edges that failed the determinism check this many times are treated as + // seen forever (they only cost re-runs). They are not counted as found. + int flaky_threshold = 50; + // Prepend fresh value declarations to the parent of every mutation chain + // (prefix stage): between prefix_min_values and + // prefix_min_values + prefix_extra_values of them (Fuzzilli: 10-15). + bool value_prefix = true; + int prefix_min_values = 10; + int prefix_extra_values = 5; + bool minimize = true; + // Minimizer probes run with a timeout derived from the execution time of + // the program being reduced: + // clamp(probe_timeout_factor * exec_time + probe_timeout_extra_ms, + // probe_timeout_min_ms, timeout_ms) + // Generous enough for JIT-tier variance, short enough that a probe which + // turned a terminating loop into an endless one is cheap. + double probe_timeout_factor = 5; + double probe_timeout_extra_ms = 20; + double probe_timeout_min_ms = 50; + // A minimized program must still qualify (reach its edges, or crash the + // same way) in one of this many re-executions; otherwise the unminimized + // program is kept. More than one because the target's own + // non-determinism (concurrent GC, compilation) occasionally hides an edge. + int verify_attempts = 3; + bool minimize_crashes = true; + bool minimize_imports = false; + // Keep imported programs that run successfully even without new edges. + bool import_all = false; + // Programs generated from scratch when there is nothing to import. + int initial_programs = 32; + // The "init" block of the configuration (DESIGN.md 5.1) sets the import + // fields above. The "accept" block names the Accept criterion (5.5); + // `new-edges` is the only one today. + std::string accept_strategy = "new-edges"; + // The "amplify" block (DESIGN.md 5.8): the strategy that searches extra + // d8 flags for a crash that does not reproduce in a fresh target, and its + // params as JSON text (engine/amplifier.h). "none" turns the step off. + std::string amplify_strategy = "flags"; + std::string amplify_params = "{}"; + MinimizerOptions minimizer; + // The minimizer's reducers, in the order they run (stages.minimize.reducers). + // Empty: the default order (Minimizer::DefaultOrder). + std::vector<std::string> minimizer_reducers; + // Which strategy picks seeds, partners, mutators and generators, and + // with which parameters (core/selection.h). JSON: + // "selection": {"mutators": {"strategy": "weighted", + // "params": {"weights": {"Splice": 4, "Reorder": + // 0}}}} + // Shorthands: "scheduler": NAME (seeds), "mutators"/"generators": + // {"Name": weight} and the --scheduler/--mutator-weights/ + // --generator-weights/--disable-* flags. Validated when loaded: an + // unknown strategy, parameter or weight name is an error. + struct SelectionSettings { + SelectionConfig seeds; + SelectionConfig partners; + SelectionConfig mutators; + SelectionConfig generators; + }; + SelectionSettings selection; + + // --- stages ------------------------------------------------------------- + // The log/capture/stats switches of every stage (engine/stages.h). The + // stage parameters are the policy fields above; the "stages" block of + // the configuration groups them by stage: + // "stages": { + // "prefix": {"enabled": true, "min_values": 10, "extra_values": 5}, + // "mutate": {"consecutive": 5, "rounds": 0, "log": "events", + // "capture": {"on": ["timeout"], "mutators": ["Splice"], + // "max": 50}}, + // "check": {"min_reruns": 5, "min_stable_reruns": 1, "max_reruns": 50, + // "flaky_threshold": 50}, "minimize": {"enabled": true, "max_tests": 300, + // ..., "probe_timeout_factor": 5, + // "verify_attempts": 3, "capture": {"on": ["rejected"]}}, + // "publish": {"save_corpus": true} + // } + // Flags: --capture=STAGE:TRIGGER[,..][:MUTATOR[,..]][:MAX] (several, + // separated by ';'), --stage-log=STAGE[,STAGE..]. + StageOptions stages[kNumStages]; + StageOptions& stage(Stage s) { return stages[static_cast<int>(s)]; } + const StageOptions& stage(Stage s) const { + return stages[static_cast<int>(s)]; + } + + // --- crashes ------------------------------------------------------------ + // Re-executions of a crashing program in a fresh target. The crash counts + // as reproducible if any of them crashes again (with any signature) ... + int crash_reruns = 3; + // ... and the re-executions stop early once this many crashed again: + // that is deterministic enough. + int crash_reruns_stop_after = 2; + // Crash files saved per signature; later crashes with the same signature + // are only counted. The first `minimize_crashes_per_signature` of them + // are minimized (if they reproduce). + int max_crashes_per_signature = 5; + int minimize_crashes_per_signature = 2; + // For crashes that do not reproduce in a fresh target: up to this many of + // the programs the same target executed before the crash are replayed in + // front of it, to find out whether the crash depends on state left behind + // by earlier programs (0 disables the replay) ... + int crash_history = 100; + // ... spending at most this long per crash. + double crash_history_budget_sec = 90; + // Budget for minimizing crashes (they are rare and worth more tests than + // corpus programs). + MinimizerOptions crash_minimizer{/*max_tests=*/1000, + /*max_time_ms=*/120000, + /*max_rounds=*/4, + /*target_time_ms=*/30000, + /*min_tests=*/200}; + + // Applies --config (a file, or inline JSON starting with '{') then the + // command line flags. `for_run` is false only for --dump-config: then no + // target is needed and no clock seed is drawn. + static bool Load(const Flags& flags, FuzzConfig* config, std::string* error, + bool for_run = true); + // Builds the configured selectors once to report an unknown strategy, + // parameter or weight name (called by Load). + static bool ValidateSelection(const SelectionSettings& selection, + std::string* error); + // Reports a reducer name in stages.minimize.reducers that does not exist. + static bool ValidateReducers(const std::vector<std::string>& names, + std::string* error); + // The JSON part of Load() alone (no flags, no prelude, no validation), + // for the selftest. + static bool LoadJsonForTest(const JsonValue& json, FuzzConfig* config, + std::string* error); + // The effective configuration as JSON (one object). The compact form + // (the `start` event) lists only the tunables that were changed and the + // selection parameters that were given; the full form (--dump-config) + // lists every tunable and every parameter of the chosen strategies, so + // it documents all the defaults and can be edited and passed back with + // --config. + enum class Detail { kCompact, kFull }; + std::string ToJson(Detail detail = Detail::kCompact) const; + // Documentation of the config file, for `redline help fuzz`. + static std::string JsonHelp(); +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_CONFIG_H_ diff --git a/deps/v8/experimental/redline/engine/crash.cc b/deps/v8/experimental/redline/engine/crash.cc new file mode 100644 index 000000000000..3ad55be9433d --- /dev/null +++ b/deps/v8/experimental/redline/engine/crash.cc @@ -0,0 +1,402 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/crash.h" + +#include <cxxabi.h> + +#include <cctype> +#include <cstdlib> +#include <cstring> +#include <map> +#include <string_view> + +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { + +uint64_t Fnv1a(std::string_view text) { + uint64_t hash = 0xcbf29ce484222325ull; + for (char ch : text) { + const unsigned char c = static_cast<unsigned char>(ch); + hash ^= c; + hash *= 0x100000001b3ull; + } + return hash; +} + +std::string_view Trim(std::string_view s) { + while (!s.empty() && isspace(static_cast<unsigned char>(s.front()))) { + s.remove_prefix(1); + } + while (!s.empty() && isspace(static_cast<unsigned char>(s.back()))) { + s.remove_suffix(1); + } + return s; +} + +std::vector<std::string_view> Lines(std::string_view text) { + std::vector<std::string_view> lines; + size_t start = 0; + while (start < text.size()) { + size_t nl = text.find('\n', start); + if (nl == std::string_view::npos) { + nl = text.size(); + } + lines.push_back(Trim(text.substr(start, nl - start))); + start = nl + 1; + } + return lines; +} + +std::string Basename(std::string_view path) { + size_t slash = path.find_last_of('/'); + return std::string(slash == std::string_view::npos ? path + : path.substr(slash + 1)); +} + +std::string Truncated(std::string_view text, size_t limit) { + if (text.size() <= limit) { + return std::string(text); + } + return std::string(text.substr(0, limit)) + "..."; +} + +// Frames of the crash machinery itself, libc and the sanitizer runtime are +// not part of the signature. +bool IsNoiseFrame(const std::string& function, std::string_view module) { + if (function.empty()) { + return true; + } + if (module.find("libc.so") != std::string_view::npos || + module.find("libpthread") != std::string_view::npos || + module.find("ld-linux") != std::string_view::npos) { + return true; + } + static const char* const kPrefixes[] = { + "v8::base::debug::", + "v8::base::OS::Abort", + "v8::base::OS::DebugBreak", + "V8_Fatal", + "v8::base::FatalOOM", + "v8::base::(anonymous namespace)::", + "v8::V8::FatalProcessOutOfMemory", + "abort", + "raise", + "gsignal", + "__GI_", + "__libc_", + "__restore_rt", + "__asan", + "__interceptor", + "__sanitizer", + "_start", + "__libc_start", + }; + for (const char* prefix : kPrefixes) { + if (function.compare(0, strlen(prefix), prefix) == 0) { + return true; + } + } + // The DCHECK/CHECK failure helpers between V8_Fatal and the real frame. + if (function.starts_with("v8::base::CheckFailed") || + function.starts_with("v8::base::internal::PrintCheckOperand") || + function.starts_with("v8::base::internal::MakeCheckOpString")) { + return true; + } + return false; +} + +// Parses one line of a glibc/V8 backtrace: +// "<module>(<symbol>+0x<off>)[0x<addr>]" or "<module>(<symbol>+0x<off>) +// [0x<addr>]". Returns false if the line is not a frame. `symbol` may be empty +// (no symbol for that address). +bool ParseBacktraceFrame(std::string_view line, std::string* module, + std::string* symbol) { + size_t open = line.find('('); + if (open == std::string_view::npos) { + return false; + } + size_t bracket = line.rfind('['); + if (bracket == std::string_view::npos || bracket < open) { + return false; + } + size_t close = line.rfind(')', bracket); + if (close == std::string_view::npos || close < open) { + return false; + } + std::string_view inner = line.substr(open + 1, close - open - 1); + size_t plus = inner.rfind("+0x"); + if (plus == std::string_view::npos) { + return false; + } + *module = std::string(line.substr(0, open)); + *symbol = std::string(inner.substr(0, plus)); + return true; +} + +// Parses a sanitizer frame: "#3 0x7f... in v8::internal::Foo(...) +// file.cc:12:3". +bool ParseSanitizerFrame(std::string_view line, std::string* symbol) { + if (line.empty() || line[0] != '#') { + return false; + } + size_t in = line.find(" in "); + if (in == std::string_view::npos) { + return false; + } + std::string_view rest = line.substr(in + 4); + // The function name ends at the parameter list or at the file position. + size_t end = 0; + int depth = 0; + for (; end < rest.size(); end++) { + char c = rest[end]; + if (c == '(') { + depth++; + } + if (c == ')') { + depth--; + } + if (c == ' ' && depth <= 0) { + break; + } + } + *symbol = std::string(rest.substr(0, end)); + return !symbol->empty(); +} + +} // namespace + +std::string ShortFunctionName(const std::string& symbol) { + std::string name = symbol; + if (name.starts_with("_Z")) { + int status = 0; + char* demangled = + abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status); + if (status == 0 && demangled != nullptr) { + name = demangled; + } + free(demangled); + } + // Strip the parameter list (and anything after it), but keep "operator()". + size_t paren = name.find('('); + if (paren != std::string::npos) { + if (name.compare(paren, 10, "(anonymous") == 0) { + size_t next = name.find('(', paren + 1); + paren = next; + } else if (paren >= 8 && name.compare(paren - 8, 8, "operator") == 0) { + size_t next = name.find('(', paren + 2); + paren = next; + } + if (paren != std::string::npos) { + name.erase(paren); + } + } + // Drop a leading return type ("void v8::internal::Foo<int>" -> + // "v8::internal::Foo<int>"): the last space outside of template arguments + // separates the two, except for "operator new"/"operator delete". + int depth = 0; + size_t last_space = std::string::npos; + for (size_t i = 0; i < name.size(); i++) { + if (name[i] == '<') { + depth++; + } + if (name[i] == '>') { + depth--; + } + if (name[i] == ' ' && depth == 0) { + last_space = i; + } + } + if (last_space != std::string::npos && + name.find("operator ") == std::string::npos) { + name.erase(0, last_space + 1); + } + return name; +} + +std::vector<std::string> CrashFrames(const std::string& stderr_text) { + std::vector<std::string> frames; + std::string module, symbol; + for (std::string_view line : Lines(stderr_text)) { + if (ParseBacktraceFrame(line, &module, &symbol)) { + std::string function = ShortFunctionName(symbol); + if (IsNoiseFrame(function, module)) { + continue; + } + frames.push_back(function); + } else if (ParseSanitizerFrame(line, &symbol)) { + std::string function = ShortFunctionName(symbol); + if (IsNoiseFrame(function, "")) { + continue; + } + frames.push_back(function); + } + } + return frames; +} + +std::vector<std::string> RecursionCycle( + const std::vector<std::string>& frames) { + std::map<std::string, size_t> counts; + for (const std::string& frame : frames) { + counts[frame]++; + } + std::vector<std::string> cycle; + size_t covered = 0; + for (const auto& [function, count] : counts) // sorted by name + { + if (count >= kMinRecursionRepeats) { + cycle.push_back(function); + covered += count; + } + } + // The recursion has to dominate the (length-limited) trace; a function + // that merely shows up a few times in a long trace is no recursion. + if (cycle.empty() || covered * 2 < frames.size()) { + return {}; + } + if (cycle.size() > kMaxRecursionCycleFunctions) { + cycle.resize(kMaxRecursionCycleFunctions); + } + return cycle; +} + +// static +CrashSignature CrashSignature::FromExecution(const Execution& execution) { + return FromOutput(execution.signal, execution.exit_code, + execution.stderr_output); +} + +// static +CrashSignature CrashSignature::FromOutput(int signal, int exit_code, + const std::string& stderr_text) { + CrashSignature signature; + std::vector<std::string_view> lines = Lines(stderr_text); + std::string text; + + // 1. V8 fatal errors and out-of-memory. + for (size_t i = 0; i < lines.size() && text.empty(); i++) { + std::string_view line = lines[i]; + constexpr std::string_view kFatal = "Fatal error in "; + constexpr std::string_view kOom = "Fatal process out of memory: "; + constexpr std::string_view kJsOom = "Fatal JavaScript out of memory: "; + constexpr std::string_view kJsInvalidSize = + "Fatal JavaScript invalid size error"; + if (size_t oom_at = line.find(kOom); oom_at != std::string_view::npos) { + text = "oom " + Truncated(Trim(line.substr(oom_at + kOom.size())), 60); + } else if (size_t js_oom_at = line.find(kJsOom); + js_oom_at != std::string_view::npos) { + text = + "oom " + Truncated(Trim(line.substr(js_oom_at + kJsOom.size())), 60); + } else if (line.find(kJsInvalidSize) != std::string_view::npos) { + text = "oom invalid size"; + } else if (size_t fatal_at = line.find(kFatal); + fatal_at != std::string_view::npos) { + std::string_view rest = line.substr(fatal_at + kFatal.size()); + size_t comma = rest.find(", line "); + std::string location; + if (comma != std::string_view::npos) { + location = Basename(rest.substr(0, comma)) + ":" + + std::string(Trim(rest.substr(comma + 7))); + } else { + location = std::string(Trim(rest)); + } + text = "fatal " + location; + // The check that failed usually follows within a few lines. + for (size_t j = i + 1; j < lines.size() && j < i + 6; j++) { + std::string_view next = lines[j]; + constexpr std::string_view kCheck = "heck failed: "; + size_t at = next.find(kCheck); + if (at != std::string_view::npos) { + text += " " + Truncated(Trim(next.substr(at + kCheck.size())), 80); + break; + } + if (next.find("Sandbox violation") != std::string_view::npos || + next.find("sandbox violation") != std::string_view::npos) { + text += " sandbox violation"; + break; + } + } + } + } + + // 2. Sanitizer reports. + if (text.empty()) { + for (std::string_view line : lines) { + size_t pos = line.find("ERROR: "); + if (pos == std::string_view::npos) { + continue; + } + std::string_view rest = line.substr(pos + 7); + size_t colon = rest.find(": "); + if (colon == std::string_view::npos) { + continue; + } + std::string_view tool = rest.substr(0, colon); + if (tool.find("Sanitizer") == std::string_view::npos) { + continue; + } + std::string_view kind = rest.substr(colon + 2); + size_t space = kind.find(' '); + if (space != std::string_view::npos) { + kind = kind.substr(0, space); + } + text = "asan " + std::string(kind); + std::vector<std::string> frames = CrashFrames(stderr_text); + if (!frames.empty()) { + text += " " + frames[0]; + } + break; + } + } + + // 3. Signals with a stack trace. + if (text.empty()) { + std::string head = StringPrintf("sig%d", signal); + for (std::string_view line : lines) { + constexpr std::string_view kSignal = "Received signal "; + size_t pos = line.find(kSignal); + if (pos == std::string_view::npos) { + continue; + } + std::string_view rest = line.substr(pos + kSignal.size()); + // "11 SEGV_MAPERR 000000000000" -> "sig11 SEGV_MAPERR" (the address is + // not part of the signature). + size_t space = rest.find(' '); + if (space != std::string_view::npos) { + std::string_view code = rest.substr(space + 1); + size_t end = code.find(' '); + if (end != std::string_view::npos) { + code = code.substr(0, end); + } + head += " " + std::string(code); + } + break; + } + std::vector<std::string> frames = CrashFrames(stderr_text); + text = head; + std::vector<std::string> cycle = RecursionCycle(frames); + if (!cycle.empty()) { + text += " stack-overflow"; + for (size_t i = 0; i < cycle.size(); i++) { + text += (i == 0 ? " " : " | ") + cycle[i]; + } + } + for (size_t i = 0; cycle.empty() && i < frames.size() && i < 3; i++) { + text += (i == 0 ? " " : " < ") + frames[i]; + } + if (signal == 0 && frames.empty()) { + text = StringPrintf("exit%d", exit_code); + } + } + + signature.text = text; + signature.hash = Fnv1a(text); + return signature; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/crash.h b/deps/v8/experimental/redline/engine/crash.h new file mode 100644 index 000000000000..8980b25ac7cf --- /dev/null +++ b/deps/v8/experimental/redline/engine/crash.h @@ -0,0 +1,76 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_ENGINE_CRASH_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_CRASH_H_ + +#include <cstdint> +#include <string> +#include <vector> + +#include "experimental/redline/exec/execution.h" + +namespace redline { + +// A stable summary of a crash, derived from what the target printed. Two +// crashes with the same signature are the same bug for the purpose of +// deduplication (the saved-crash budget, the per-signature statistics and +// the minimizer's oracle, which must not wander off into a different bug). +// +// Recognized formats (in this order): +// - V8 fatal errors: "# Fatal error in ../../src/foo.cc, line 123" plus +// the following "Check failed: ..." / "Debug check failed: ..." line, if +// any. Signature: "fatal foo.cc:123 <check>". +// - Sanitizer reports: "ERROR: AddressSanitizer: heap-use-after-free ..." +// plus the function of the first frame. Signature: "asan <kind> <fn>". +// - Signals: "Received signal 11 SEGV_MAPERR ..." plus the first three +// frames of the C stack trace that name a function (frames without a +// symbol, the stack-trace machinery itself and libc are skipped). +// Signature: "sig11 SEGV_MAPERR fn1 < fn2 < fn3". +// A stack overflow faults wherever the stack runs out, so its first +// frames differ from crash to crash; when the trace is dominated by +// functions that repeat (see RecursionCycle), those name the crash +// instead: "sig11 SEGV_MAPERR stack-overflow fnA | fnB | fnC". +// - Anything else: "sig<N>" (or "exit<code>") alone. +struct CrashSignature { + std::string text; + uint64_t hash = 0; + + static CrashSignature FromExecution(const Execution& execution); + // Also exposed for tests: builds the signature from the raw stderr text. + static CrashSignature FromOutput(int signal, int exit_code, + const std::string& stderr_text); + + bool operator==(const CrashSignature& other) const { + return hash == other.hash; + } + bool operator!=(const CrashSignature& other) const { + return hash != other.hash; + } +}; + +// Demangles an Itanium C++ symbol and strips the parameter list, so that +// "_ZN2v88internal6Parser17GetBigIntAsSymbolEv" becomes +// "v8::internal::Parser::GetBigIntAsSymbol". Non-mangled input is returned +// unchanged (minus a parameter list, if it has one). +std::string ShortFunctionName(const std::string& symbol); + +// The frames of a V8 "==== C stack trace ====" block (or a sanitizer stack) +// that name a function, innermost first, already shortened. +std::vector<std::string> CrashFrames(const std::string& stderr_text); + +// A function counts as part of a recursion when it appears at least this +// many times among the frames of one trace. +inline constexpr size_t kMinRecursionRepeats = 8; +inline constexpr size_t kMaxRecursionCycleFunctions = 4; + +// The functions of a recursion that fills the trace: those appearing at least +// kMinRecursionRepeats times, sorted by name (so the result does not depend +// on where the stack ran out), at most kMaxRecursionCycleFunctions of them. +// Empty unless they make up at least half of the frames. +std::vector<std::string> RecursionCycle(const std::vector<std::string>& frames); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_CRASH_H_ diff --git a/deps/v8/experimental/redline/engine/fuzzer.cc b/deps/v8/experimental/redline/engine/fuzzer.cc new file mode 100644 index 000000000000..acb18ecf5fc0 --- /dev/null +++ b/deps/v8/experimental/redline/engine/fuzzer.cc @@ -0,0 +1,2055 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/fuzzer.h" + +#include <algorithm> +#include <chrono> +#include <cstdio> +#include <deque> +#include <functional> +#include <iterator> +#include <thread> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/base/v8_runtime.h" +#include "experimental/redline/core/environment.h" +#include "experimental/redline/engine/importer.h" +#include "experimental/redline/exec/runner.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/mutators/explore.h" + +namespace redline { + +namespace { + +constexpr char kLog[] = "fuzz"; +constexpr size_t kMaxSavedOutput = static_cast<size_t>(64) * 1024; + +// Runs a function when the scope ends (all exits of a loop iteration). +class ScopeExit { + public: + explicit ScopeExit(std::function<void()> fn) : fn_(std::move(fn)) {} + ~ScopeExit() { fn_(); } + ScopeExit(const ScopeExit&) = delete; + ScopeExit& operator=(const ScopeExit&) = delete; + + private: + std::function<void()> fn_; +}; + +// {"strategy": NAME, "params": {...}} of a selector as built, for the +// `start` event. +template <typename T> +std::string EffectiveSelector(const Selector<T>& selector) { + JsonObject o; + o.Add("strategy", selector.name()); + o.AddRaw("params", selector.Params().ToString()); + return o.ToString(); +} + +std::string FormatDuration(uint64_t seconds) { + return StringPrintf("%02llu:%02llu:%02llu", + static_cast<unsigned long long>(seconds / 3600), + static_cast<unsigned long long>((seconds / 60) % 60), + static_cast<unsigned long long>(seconds % 60)); +} + +double Percent(uint64_t part, uint64_t total) { + return total == 0 + ? 0.0 + : 100.0 * static_cast<double>(part) / static_cast<double>(total); +} + +std::string Truncate(const std::string& text, size_t limit) { + if (text.size() <= limit) { + return text; + } + return text.substr(0, limit) + "\n... (truncated)\n"; +} + +} // namespace + +// --------------------------------------------------------------------------- +// Worker: one thread, one target process. + +class Worker { + public: + Worker(Fuzzer* fuzzer, int id) + : fuzzer_(fuzzer), + id_(id), + rng_(fuzzer->config().seed * 0x9E3779B97F4A7C15ull + + static_cast<uint64_t>(id) + 1) {} + + int id() const { return id_; } + + // Starts the target synchronously so that configuration problems are + // reported before any thread runs. + bool Start(std::string* error) { + runner_ = ScriptRunner::Create(fuzzer_->config().target, id_, error); + if (runner_ == nullptr) { + return false; + } + if (!runner_->Initialize(error)) { + return false; + } + const CoverageMap& coverage = runner_->coverage(); + return fuzzer_->coverage_.Initialize(coverage.num_edges(), + coverage.bitmap_size(), error); + } + + void Launch() { + thread_ = std::thread([this] { Run(); }); + } + + // Runs the environment introspection script in this worker's target and + // returns what it printed on fuzzout. Called before Launch(). + bool Introspect(std::string* json, std::string* error) { + Execution execution; + const uint64_t timeout_us = + static_cast<uint64_t>(config().introspect_timeout_ms * 1000.0); + if (!runner_->RunWithoutEvaluation(Environment::IntrospectionScript(), + timeout_us, &execution, error)) { + return false; + } + if (!execution.succeeded()) { + *error = StringPrintf("introspection script %s: %s", + OutcomeName(execution.outcome), + FirstLines(execution.stderr_output).c_str()); + return false; + } + *json = execution.fuzzout; + return true; + } + void Join() { + if (thread_.joinable()) { + thread_.join(); + } + } + + private: + const FuzzConfig& config() const { return fuzzer_->config(); } + FuzzerStats& stats() { return fuzzer_->stats_; } + bool stopping() const { return fuzzer_->stop_requested(); } + // The syntax checker for minimizer probes: only with syntax_check on + // (nullptr makes the minimizer skip the in-process parse). + SyntaxChecker* probe_checker() const { + return config().syntax_check ? checker_.get() : nullptr; + } + + void Run() { + checker_ = std::make_unique<SyntaxChecker>(); + ImportPhase(); + while (!stopping()) { + FuzzOne(); + } + // Let the target go now; the main thread only joins. + runner_.reset(); + } + + // --- execution -------------------------------------------------------- + + // Runs `source` behind the prelude without touching per-runner coverage + // bookkeeping. Returns false on an infrastructure failure. + bool Execute(const std::string& source, Execution* execution, + uint64_t timeout_us = 0) { + if (timeout_us == 0) { + timeout_us = config().target.timeout_us; + } + const std::string& prelude = config().prelude; + std::string error; + bool ok; + if (prelude.empty()) { + ok = runner_->RunWithoutEvaluation(source, timeout_us, execution, &error); + } else { + std::string script; + script.reserve(prelude.size() + 1 + source.size()); + script.append(prelude).append("\n").append(source); + ok = runner_->RunWithoutEvaluation(script, timeout_us, execution, &error); + } + if (!ok) { + stats().infrastructure_failures++; + history_.clear(); + if (++consecutive_failures_ >= 10) { + fuzzer_->Fail(StringPrintf("worker %d: target keeps failing: %s", id_, + error.c_str())); + } else { + REDLINE_WARN(kLog, "worker %d: execution failed: %s", id_, + error.c_str()); + } + return false; + } + consecutive_failures_ = 0; + executions_++; + stats().executions++; + stats().exec_time_us += execution->exec_time_us; + RememberExecution(source); + return true; + } + + // The programs the current target process executed, oldest first (bounded + // by crash_history entries and kHistoryBytes). A fresh process starts an + // empty history; the entry for the execution that killed a process stays + // at the end until the next execution. + void RememberExecution(const std::string& source) { + if (config().crash_history <= 0) { + return; + } + if (runner_->child().execs_since_spawn() <= 1) { + history_.clear(); + history_bytes_ = 0; + } + history_.push_back(source); + history_bytes_ += source.size(); + while (history_.size() > static_cast<size_t>(config().crash_history) || + (history_bytes_ > kHistoryBytes && history_.size() > 1)) { + history_bytes_ -= history_.front().size(); + history_.pop_front(); + } + } + static constexpr size_t kHistoryBytes = static_cast<size_t>(8) * 1024 * 1024; + + // Timeout for minimizer probes, derived from the execution time of the + // program being reduced (stages.minimize.probe_timeout_*): generous + // enough for JIT-tier variance, short enough that a probe which runs + // forever is cheap. + uint64_t ProbeTimeout(uint64_t exec_time_us) const { + const FuzzConfig& c = config(); + auto probe = static_cast<uint64_t>(c.probe_timeout_factor * + static_cast<double>(exec_time_us) + + c.probe_timeout_extra_ms * 1000.0); + probe = + std::max(probe, static_cast<uint64_t>(c.probe_timeout_min_ms * 1000.0)); + return std::min(probe, c.target.timeout_us); + } + + // Bookkeeping for a mutant that is not valid JavaScript: per-mutator and + // global counters, the verbose event, the capture and the mutant event. + // Without the in-process syntax check the verdict comes from the target + // (Execution::IsParseError()). + void CountInvalid(Mutator& mutator, const std::string& detail, + uint32_t ancestor_id, const Program* parent, + const std::string& source, const std::string& message) { + mutator.stats().invalid++; + stats().invalid++; + if (GetLogLevel() == LogLevel::kVerbose) { + JsonObject event; + event.Add("event", "invalid") + .Add("mutator", mutator.name()) + .Add("detail", detail); + event.Add("error", message).Add("parent", ancestor_id).Add("worker", id_); + fuzzer_->LogEvent(event); + } + JsonObject why; + why.Add("error", message); + Capture(Stage::kMutate, CaptureTrigger::kInvalid, mutator.name(), parent, + source, why); + LogMutant(mutator, detail, ancestor_id, "invalid", nullptr, 0); + } + + // Feedback for the mutator strategy (core/selection.h). "interesting" + // is only known after the determinism check, so it is reported as false + // here; the strategy can read it later from the mutator's stats. + void ReportToSelector(Mutator& mutator, const Execution& execution) { + SelectionOutcome outcome; + outcome.time_us = execution.exec_time_us; + switch (execution.outcome) { + case Outcome::kSucceeded: + outcome.kind = SelectionOutcome::Kind::kSucceeded; + break; + case Outcome::kFailed: + outcome.kind = SelectionOutcome::Kind::kFailed; + break; + case Outcome::kTimedOut: + outcome.kind = SelectionOutcome::Kind::kTimedOut; + break; + case Outcome::kCrashed: + outcome.kind = SelectionOutcome::Kind::kCrashed; + break; + } + fuzzer_->mutators().selector().OnOutcome(mutator, outcome); + } + + static void Account(ComponentStats& stats, const Execution& execution) { + stats.executed++; + stats.time_us += execution.exec_time_us; + switch (execution.outcome) { + case Outcome::kSucceeded: + stats.succeeded++; + break; + case Outcome::kFailed: + stats.failed++; + break; + case Outcome::kTimedOut: + stats.timed_out++; + break; + case Outcome::kCrashed: + stats.crashed++; + break; + } + } + + void AccountFuzzExecution(const Execution& execution) { + stats().fuzz_executions++; + switch (execution.outcome) { + case Outcome::kSucceeded: + stats().succeeded++; + break; + case Outcome::kFailed: + stats().failed++; + break; + case Outcome::kTimedOut: + stats().timed_out++; + break; + case Outcome::kCrashed: + stats().crashed++; + break; + } + } + + // --- import ----------------------------------------------------------- + + void ImportPhase() { + fuzzer_->workers_importing_++; + ImportOptions options; + options.root = config().import_root; + while (!stopping()) { + size_t index = fuzzer_->next_import_.fetch_add(1); + if (index >= fuzzer_->import_files_.size()) { + break; + } + ImportFile(fuzzer_->import_files_[index], options); + } + fuzzer_->workers_importing_--; + } + + void ImportFile(const std::string& path, const ImportOptions& options) { + stats().imports_total++; + JsonObject event; + event.Add("event", "import").Add("file", path).Add("worker", id_); + std::string source, error; + if (!ReadFileToString(path, &source, &error)) { + stats().imports_failed++; + fuzzer_->LogEvent(event.Add("result", "unreadable").Add("error", error)); + return; + } + ImportInfo info; + std::unique_ptr<fast::Tree> tree = + ImportSource(source, path, options, &info, &error); + if (tree == nullptr) { + stats().imports_failed++; + fuzzer_->LogEvent(event.Add("result", "parse_error").Add("error", error)); + return; + } + if (!info.inlined.empty()) { + event.AddArray("inlined", info.inlined); + } + if (!info.dropped.empty()) { + event.AddArray("dropped_loads", info.dropped); + } + Lineage lineage; + lineage.origin = "import"; + lineage.detail = path; + lineage.worker = id_; + std::shared_ptr<Program> program = + Program::FromTree(std::move(tree), lineage); + std::string message; + if (!checker_->Accepts(program->source(), &message)) { + stats().imports_failed++; + fuzzer_->LogEvent( + event.Add("result", "syntax_error").Add("error", message)); + return; + } + Execution execution; + if (!Execute(program->source(), &execution)) { + stats().imports_failed++; + fuzzer_->LogEvent(event.Add("result", "infrastructure_failure")); + return; + } + event.Add("exec_time_ms", + static_cast<double>(execution.exec_time_us) / 1000.0); + if (execution.crashed()) { + stats().imports_failed++; + fuzzer_->LogEvent(event.Add("result", "crashed")); + ProcessCrash(program->source(), *program, execution, lineage); + return; + } + if (!execution.succeeded()) { + stats().imports_failed++; + event.Add("result", execution.timed_out() ? "timed_out" : "failed"); + event.Add("stderr", FirstLines(execution.stderr_output.empty() + ? execution.stdout_output + : execution.stderr_output)); + fuzzer_->LogEvent(event); + return; + } + std::vector<uint32_t> claimed = + fuzzer_->coverage_.ClaimNewEdges(runner_->coverage().bitmap()); + if (claimed.empty() && !config().import_all) { + stats().imports_redundant++; + fuzzer_->LogEvent(event.Add("result", "redundant")); + return; + } + ProgramPtr added = Commit(program, std::move(claimed), execution, + config().minimize_imports, + /*mutator=*/nullptr); + if (added == nullptr) { + stats().imports_failed++; + fuzzer_->LogEvent(event.Add("result", "flaky")); + return; + } + stats().imports_added++; + fuzzer_->LogEvent( + event.Add("result", "added") + .Add("id", added->id) + .Add("edges", static_cast<uint64_t>(added->edges.size()))); + } + + static std::string FirstLines(const std::string& text) { + size_t end = 0; + for (int lines = 0; lines < 3 && end < text.size(); lines++) { + size_t nl = text.find('\n', end); + end = nl == std::string::npos ? text.size() : nl + 1; + } + std::string out = text.substr(0, std::min<size_t>(end, 400)); + while (!out.empty() && (out.back() == '\n' || out.back() == '\r')) { + out.pop_back(); + } + return out; + } + + // --- fuzzing ---------------------------------------------------------- + + void FuzzOne() { + Corpus& corpus = fuzzer_->corpus(); + Stopwatch pick_time; + ProgramPtr parent = corpus.Pick(rng_); + bool from_empty = false; + if (parent == nullptr || + (corpus.size() < static_cast<size_t>(config().initial_programs) && + rng_.Coin())) { + parent = fuzzer_->empty_program_; + from_empty = true; + } + { + StageStats& st = stage(Stage::kPick); + st.invocations++; + st.time_us += pick_time.ElapsedUs(); + if (!from_empty) { + st.successes++; + } + if (config().stage(Stage::kPick).events) { + JsonObject event; + event.Add("event", "pick") + .Add("worker", id_) + .Add("program", from_empty ? 0u : parent->id); + fuzzer_->LogEvent(event); + } + } + // The corpus program the chain of consecutive mutations started from + // (the scheduler's feedback and the lineage refer to it), and the + // number of mutations applied since. + ProgramPtr ancestor = parent; + int chain = 0; + const Environment& env = *fuzzer_->env_; + MutatorSet& mutators = fuzzer_->mutators(); + GeneratorSet& generators = fuzzer_->generators(); + + // Fresh values at the top of the parent give every mutation of the chain + // something new to work with (Fuzzilli's buildPrefix()). The prefix is + // not a mutation of its own: it is only executed as part of the first + // child, and the minimizer drops whatever ends up unused. + if (!from_empty && config().value_prefix && + fuzzer_->prefix_mutator_ != nullptr) { + Stopwatch prefix_time; + std::string detail; + std::unique_ptr<fast::Tree> prefixed = + ApplyMutation(*fuzzer_->prefix_mutator_, *parent, nullptr, rng_, env, + generators, 1, &detail); + StageStats& st = stage(Stage::kPrefix); + st.invocations++; + st.time_us += prefix_time.ElapsedUs(); + if (prefixed != nullptr) { + st.successes++; + parent = Program::FromTree(std::move(prefixed), parent->lineage()); + } else { + Capture(Stage::kPrefix, CaptureTrigger::kNoop, "Prefix", parent.get(), + "", JsonObject()); + } + if (config().stage(Stage::kPrefix).events) { + JsonObject event; + event.Add("event", "prefix") + .Add("worker", id_) + .Add("program", ancestor->id); + event.Add("applied", prefixed != nullptr).Add("detail", detail); + fuzzer_->LogEvent(event); + } + } + + for (int round = 0; round < config().consecutive_mutations && !stopping(); + round++) { + Mutator* mutator = from_empty ? fuzzer_->codegen_mutator_ + : mutators.Pick(rng_, corpus.size() >= 2); + if (mutator == nullptr) { + return; + } + ProgramPtr partner; + if (mutator->needs_partner()) { + partner = corpus.PickPartner(*parent, rng_); + if (partner == nullptr) { + continue; + } + } + Stopwatch mutation_time; + Stopwatch + stage_time; // the whole mutate stage: mutate, check syntax, execute + StageStats& mutate_stage = stage(Stage::kMutate); + mutate_stage.invocations++; + std::string detail; + std::vector<ExploreProbe> probes; + // Sub-mutations per application: a fixed number if configured, + // otherwise 1..max_simultaneous() like Fuzzilli's + // BaseInstructionMutator (Int.random(in: 1...maxSimultaneousMutations)). + int rounds = config().mutation_rounds; + if (rounds <= 0) { + rounds = 1 + static_cast<int>(rng_.Index(static_cast<size_t>( + std::max(1, mutator->max_simultaneous())))); + } + BeginGeneratorUsage(); + const uint64_t spent_before = executions_; + std::unique_ptr<fast::Tree> tree = + ApplyMutation(*mutator, *parent, partner, rng_, env, generators, + rounds, &detail, &probes); + // The generators this mutation used share the credit for its result. + const std::vector<Generator*> used_generators = GeneratorsUsed(); + // Every target execution of this step (the mutant, instrumented + // probe runs, determinism reruns, minimizer runs, crash triage) + // counts as spent by the mutator and by the generators it used. + const ScopeExit credit_spent([&] { + const uint64_t spent = executions_ - spent_before; + mutator->stats().spent += spent; + for (Generator* g : used_generators) { + g->stats().spent += spent; + } + }); + stats().mutation_time_us += mutation_time.ElapsedUs(); + if (tree == nullptr) { + stats().noop++; + mutate_stage.time_us += stage_time.ElapsedUs(); + Capture(Stage::kMutate, CaptureTrigger::kNoop, mutator->name(), + parent.get(), "", JsonObject()); + LogMutant(*mutator, detail, ancestor->id, "noop", nullptr, 0); + continue; + } + if (mutator->runtime_assisted()) { + bool crashed = false; + if (!CompleteRuntimeAssisted(*mutator, tree.get(), probes, &detail, + &crashed)) { + mutate_stage.time_us += stage_time.ElapsedUs(); + if (crashed) { + return; + } + stats().noop++; + Capture(Stage::kMutate, CaptureTrigger::kNoop, mutator->name(), + parent.get(), "", JsonObject()); + LogMutant(*mutator, detail, ancestor->id, "noop", nullptr, 0); + continue; + } + } + std::string source = fast::Print(tree->root()); + std::string message; + if (config().syntax_check && !checker_->Accepts(source, &message)) { + CountInvalid(*mutator, detail, ancestor->id, parent.get(), source, + message); + mutate_stage.time_us += stage_time.ElapsedUs(); + continue; + } + Execution execution; + if (!Execute(source, &execution)) { + if (fuzzer_->failed_.load()) { + return; + } + continue; + } + if (!config().syntax_check && execution.IsParseError()) { + // The target did the parsing: same verdict, no in-process V8. + CountInvalid(*mutator, detail, ancestor->id, parent.get(), source, + execution.ExceptionSignature()); + mutate_stage.time_us += stage_time.ElapsedUs(); + continue; + } + Account(mutator->stats(), execution); + for (Generator* g : used_generators) { + Account(g->stats(), execution); + } + AccountFuzzExecution(execution); + ReportToSelector(*mutator, execution); + stats().fuzz_nodes += fast::CountNodes(tree->root()); + mutate_stage.executions++; + mutate_stage.exec_time_us += execution.exec_time_us; + mutate_stage.time_us += stage_time.ElapsedUs(); + if (execution.outcome == Outcome::kTimedOut) { + mutate_stage.timeouts++; + Capture(Stage::kMutate, CaptureTrigger::kTimeout, mutator->name(), + parent.get(), source, JsonObject()); + } else if (execution.outcome == Outcome::kFailed) { + Capture(Stage::kMutate, CaptureTrigger::kFailed, mutator->name(), + parent.get(), source, JsonObject()); + } else if (execution.outcome == Outcome::kCrashed) { + Capture(Stage::kMutate, CaptureTrigger::kCrash, mutator->name(), + parent.get(), source, JsonObject()); + } + + Lineage lineage; + lineage.origin = mutator->name(); + lineage.detail = detail; + lineage.parent_hash = parent->hash(); + lineage.parent_id = ancestor->id; + lineage.chain = chain + 1; + lineage.partner_hash = partner != nullptr ? partner->hash() : 0; + lineage.generation = parent->lineage().generation + 1; + lineage.worker = id_; + + switch (execution.outcome) { + case Outcome::kSucceeded: { + std::vector<uint32_t> claimed = + fuzzer_->coverage_.ClaimNewEdges(runner_->coverage().bitmap()); + std::shared_ptr<Program> child = + Program::FromTree(std::move(tree), lineage, source); + ProgramPtr added; + size_t new_edges = claimed.size(); + if (!claimed.empty()) { + stats().candidates++; + mutate_stage.successes++; + JsonObject why; + why.Add("new_edges", static_cast<uint64_t>(new_edges)); + Capture(Stage::kMutate, CaptureTrigger::kInteresting, + mutator->name(), parent.get(), source, why); + added = Commit(child, std::move(claimed), execution, + config().minimize, mutator); + if (added != nullptr) { + // Each generator the mutant used gets the full credit. + for (Generator* g : used_generators) { + g->stats().interesting++; + g->stats().new_edges += added->edges.size(); + } + } + } + LogMutant(*mutator, detail, ancestor->id, + OutcomeName(execution.outcome), &execution, new_edges); + if (ancestor->id != 0) { + corpus.OnResult(*ancestor, added != nullptr); + } + // The chain continues from the child as executed, not from + // its minimized form (Fuzzilli's MutationEngine does the + // same: minimization happens on the side); the lineage of + // what follows refers to the published program. + parent = child; + if (added != nullptr) { + ancestor = added; + chain = 0; + } else { + chain++; + } + from_empty = false; + break; + } + case Outcome::kCrashed: { + LogMutant(*mutator, detail, ancestor->id, + OutcomeName(execution.outcome), &execution, 0); + std::shared_ptr<Program> child = + Program::FromTree(std::move(tree), lineage, source); + ProcessCrash(source, *child, execution, lineage); + return; + } + case Outcome::kFailed: + case Outcome::kTimedOut: + LogMutant(*mutator, detail, ancestor->id, + OutcomeName(execution.outcome), &execution, 0); + if (ancestor->id != 0) { + corpus.OnResult(*ancestor, false); + } + break; + } + } + } + + // --- stages: statistics, events and captures --------------------------- + + StageStats& stage(Stage s) { return fuzzer_->stages_[s]; } + + // One "mutant" event per executed (or dropped) mutation result when the + // mutate stage logs events. + void LogMutant(const Mutator& mutator, const std::string& detail, + uint32_t parent_id, const char* outcome, + const Execution* execution, size_t new_edges) { + if (!config().stage(Stage::kMutate).events) { + return; + } + JsonObject event; + event.Add("event", "mutant") + .Add("worker", id_) + .Add("origin", mutator.name()) + .Add("detail", detail); + event.Add("parent", parent_id).Add("outcome", outcome); + if (execution != nullptr) { + event.Add("exec_ms", + static_cast<double>(execution->exec_time_us) / 1000.0); + } + event.Add("new_edges", static_cast<uint64_t>(new_edges)); + fuzzer_->LogEvent(event); + } + + // Saves `parent` (if any) and `child` (if not empty) under + // OUT/captures/<stage>/ when the stage's capture rule matches `trigger` + // for `mutator`, within the rule's cap. `details` go to the JSON sidecar. + void Capture(Stage s, CaptureTrigger trigger, std::string_view mutator, + const Program* parent, const std::string& child, + const JsonObject& details) { + const CaptureRule& rule = config().stage(s).capture; + if (!rule.enabled() || !rule.Matches(trigger, mutator)) { + return; + } + fuzzer_->WriteCapture(s, trigger, mutator, parent, child, details, id_); + } + + // Second half of a runtime-assisted mutation (see mutators/explore.h): + // runs the instrumented tree with the runtime helper prepended and turns + // the target's answers into ordinary code in `tree`. Returns false if + // nothing came of it (the caller treats the mutation as a no-op). + bool CompleteRuntimeAssisted(Mutator& base, fast::Tree* tree, + const std::vector<ExploreProbe>& probes, + std::string* detail, bool* crashed) { + *crashed = false; + if (probes.empty()) { + return false; + } + auto& mutator = static_cast<RuntimeAssistedMutator&>(base); + std::string instrumented = + std::string(mutator.runtime()) + fast::Print(tree->root()); + std::string message; + if (config().syntax_check && !checker_->Accepts(instrumented, &message)) { + mutator.stats().invalid++; + return false; + } + Execution execution; + if (!Execute(instrumented, &execution)) { + return false; + } + stats().explore_executions++; + stage(Stage::kMutate).executions++; + stage(Stage::kMutate).exec_time_us += execution.exec_time_us; + if (execution.crashed()) { + // Crashes of the instrumented program count like any other crash; the + // saved program includes the runtime so that it reproduces. + *crashed = true; + Account(mutator.stats(), execution); + AccountFuzzExecution(execution); + ReportToSelector(mutator, execution); + Lineage lineage; + lineage.origin = mutator.name(); + lineage.detail = "instrumented program"; + lineage.worker = id_; + std::shared_ptr<Program> program = + Program::Parse(instrumented, lineage, &message); + if (program != nullptr) { + ProcessCrash(instrumented, *program, execution, lineage); + } + return false; + } + if (execution.timed_out()) { + stats().explore_timeouts++; + stage(Stage::kMutate).timeouts++; + } + if (execution.fuzzout.empty()) { + return false; + } + Stopwatch mutation_time; + Builder builder(tree, &rng_); + MutationContext ctx; + ctx.env = fuzzer_->env_; + ctx.generators = &fuzzer_->generators(); + int applied = + mutator.Apply(builder, probes, execution.fuzzout, ctx, detail); + stats().mutation_time_us += mutation_time.ElapsedUs(); + if (applied > 0) { + stats().explore_applied++; + } + return applied > 0; + } + + // Determinism check, minimization and publication of a program that + // reached `claimed` new edges. Returns the published program, or nullptr + // if the program was dropped (edges released or suppressed as flaky). + ProgramPtr Commit(std::shared_ptr<Program> program, + std::vector<uint32_t> claimed, + const Execution& first_execution, bool minimize, + Mutator* mutator) { + SharedCoverage& shared = fuzzer_->coverage_; + const bool claimed_was_empty = claimed.empty(); + std::vector<uint32_t> edges = std::move(claimed); + std::vector<uint32_t> release; + auto drop = [&](const std::vector<uint32_t>& dropped) { + for (uint32_t edge : dropped) { + if (!shared.RecordFlaky(edge, config().flaky_threshold)) { + release.push_back(edge); + } + } + }; + + // 1. Determinism (Fuzzilli's processMaybeInteresting): every edge that + // is kept must be reached by all of the re-executions; edges that + // disappear are dropped from the set. There are at least min_reruns + // re-executions, and the loop ends once the set survived + // min_stable_reruns re-runs unchanged. A candidate that still loses + // edges after max_reruns re-executions has not converged and is + // dropped. + int stable = 0; + int reruns = 0; + size_t dropped = 0; + bool deterministic = true; + bool converged = false; + bool rerun_timeout = false; + uint64_t exec_time_us = first_execution.exec_time_us; + uint32_t edges_hit = runner_->coverage().CountCurrentEdges(); + Stopwatch check_time; + StageStats& check_stage = stage(Stage::kCheck); + check_stage.invocations++; + // (A program imported with --import-all may have no new edges at all; + // it is still re-run so that only reliable programs are published.) + while (deterministic && (!edges.empty() || claimed_was_empty)) { + if (stable >= config().min_stable_reruns && + reruns >= config().min_reruns) { + converged = true; + break; + } + if (reruns >= config().max_reruns) { + break; + } + Execution execution; + if (!Execute(program->source(), &execution)) { + deterministic = false; + break; + } + reruns++; + stats().rerun_executions++; + check_stage.executions++; + check_stage.exec_time_us += execution.exec_time_us; + if (execution.outcome == Outcome::kTimedOut) { + check_stage.timeouts++; + rerun_timeout = true; + } + if (!execution.succeeded()) { + deterministic = false; + break; + } + exec_time_us = std::min(exec_time_us, execution.exec_time_us); + std::vector<uint32_t> missing = runner_->coverage().MissingEdges(edges); + if (missing.empty()) { + stable++; + continue; + } + stable = 0; + dropped += missing.size(); + drop(missing); + std::vector<uint32_t> kept; + std::set_difference(edges.begin(), edges.end(), missing.begin(), + missing.end(), std::back_inserter(kept)); + edges.swap(kept); + } + // A program without new edges is only published for --import-all; it + // still had to run reliably. + const bool keep_without_edges = + edges.empty() && claimed_was_empty && config().import_all; + const bool survived = + deterministic && converged && (!edges.empty() || keep_without_edges); + check_stage.time_us += check_time.ElapsedUs(); + if (survived) { + check_stage.successes++; + } + if (config().stage(Stage::kCheck).events) { + JsonObject event; + event.Add("event", "check") + .Add("worker", id_) + .Add("origin", program->lineage().origin); + event.Add("reruns", reruns) + .Add("dropped_edges", static_cast<uint64_t>(dropped)); + event.Add("kept_edges", static_cast<uint64_t>(edges.size())) + .Add("survived", survived); + event.Add("deterministic_outcome", deterministic) + .Add("converged", converged); + fuzzer_->LogEvent(event); + } + if (!survived || rerun_timeout) { + JsonObject why; + why.Add("reruns", reruns) + .Add("dropped_edges", static_cast<uint64_t>(dropped)); + why.Add("deterministic_outcome", deterministic) + .Add("converged", converged); + Capture(Stage::kCheck, + rerun_timeout ? CaptureTrigger::kTimeout : CaptureTrigger::kFlaky, + program->lineage().origin, nullptr, program->source(), why); + } + if (!survived) { + drop(edges); + shared.Release(release); + stats().flaky++; + JsonObject event; + event.Add("event", "flaky").Add("origin", program->lineage().origin); + event.Add("deterministic_outcome", deterministic).Add("worker", id_); + event.Add("reruns", reruns) + .Add("dropped_edges", static_cast<uint64_t>(dropped)); + fuzzer_->LogEvent(event); + return nullptr; + } + shared.Release(release); + + // 2. Minimization against the surviving edges. + MinimizationResult minimization; + bool minimized = false; + if (minimize && !edges.empty() && !stopping()) { + Stopwatch minimize_time; + StageStats& minimize_stage = stage(Stage::kMinimize); + const size_t nodes_before = program->node_count(); + minimize_stage.invocations++; + std::unique_ptr<fast::Tree> work = program->CopyTree(); + // A reduction can turn a terminating loop into an infinite one; such + // probes must not pay the full target timeout (plus a child respawn). + const uint64_t probe_timeout_us = ProbeTimeout(exec_time_us); + MinimizationOracle oracle = [&](const std::string& candidate) { + if (stopping()) { + return false; + } + Execution execution; + if (!Execute(candidate, &execution, probe_timeout_us)) { + return false; + } + minimize_stage.executions++; + minimize_stage.exec_time_us += execution.exec_time_us; + if (execution.outcome == Outcome::kTimedOut) { + minimize_stage.timeouts++; + Capture(Stage::kMinimize, CaptureTrigger::kTimeout, + program->lineage().origin, program.get(), candidate, + JsonObject()); + } + return execution.succeeded() && runner_->coverage().AllEdgesSet(edges); + }; + const MinimizerOptions budget = + config().minimizer.ForProgram(exec_time_us); + minimization = + fuzzer_->Minimize(work.get(), oracle, probe_checker(), budget); + stats().minimizer_tests += static_cast<uint64_t>(minimization.tests); + stats().minimizer_time_us += minimization.time_us; + if (minimization.accepted > 0) { + // Guard against a flaky oracle: the result must still qualify. The + // verification itself is retried a few times because target-inherent + // non-determinism (concurrent GC and compilation) occasionally hides + // an edge that is reached deterministically otherwise. + std::shared_ptr<Program> candidate = + Program::FromTree(std::move(work), program->lineage()); + for (int attempt = 0; attempt < config().verify_attempts && !stopping(); + attempt++) { + Execution execution; + if (!Execute(candidate->source(), &execution)) { + break; + } + stats().rerun_executions++; + if (!execution.succeeded()) { + break; + } + if (!runner_->coverage().AllEdgesSet(edges)) { + continue; + } + stats().minimizer_nodes_removed += static_cast<uint64_t>( + program->node_count() - candidate->node_count()); + program = + candidate; // a copy: `candidate` is reported below if rejected + exec_time_us = execution.exec_time_us; + edges_hit = runner_->coverage().CountCurrentEdges(); + minimized = true; + break; + } + if (!minimized) { + stats().minimizer_rejected++; + JsonObject why; + why.Add("tests", minimization.tests); + Capture(Stage::kMinimize, CaptureTrigger::kRejected, + program->lineage().origin, program.get(), candidate->source(), + why); + } + } + minimize_stage.time_us += minimize_time.ElapsedUs(); + if (minimized) { + minimize_stage.successes++; + } + if (config().stage(Stage::kMinimize).events) { + JsonObject event; + event.Add("event", "minimize") + .Add("worker", id_) + .Add("origin", program->lineage().origin); + event.Add("tests", minimization.tests) + .Add("accepted", minimization.accepted); + event.Add("nodes_before", static_cast<uint64_t>(nodes_before)); + event.Add("nodes_after", static_cast<uint64_t>(program->node_count())); + event.Add("minimized", minimized) + .Add("time_ms", static_cast<double>(minimization.time_us) / 1000.0); + fuzzer_->LogEvent(event); + } + } + + // 3. Publish. + Stopwatch publish_time; + StageStats& publish_stage = stage(Stage::kPublish); + publish_stage.invocations++; + program->edges = edges; + program->edges_hit = edges_hit; + program->exec_time_us = exec_time_us; + if (fuzzer_->corpus().WantsHitEdges() && !stopping()) { + // Every edge the final program reaches in two runs (Fuzzilli's + // RarityCorpus does the same two executions). + std::vector<uint32_t> hit; + for (int run = 0; run < 2; run++) { + Execution execution; + if (!Execute(program->source(), &execution) || !execution.succeeded()) { + hit.clear(); + break; + } + stats().rerun_executions++; + std::vector<uint32_t> current = runner_->coverage().CurrentEdges(); + std::sort(current.begin(), current.end()); + if (run == 0) { + hit.swap(current); + continue; + } + std::vector<uint32_t> both; + std::set_intersection(hit.begin(), hit.end(), current.begin(), + current.end(), std::back_inserter(both)); + hit.swap(both); + } + program->hit_edges = std::move(hit); + } + ProgramPtr added = fuzzer_->corpus().Add(program); + stats().corpus_added++; + stats().corpus_nodes += program->node_count(); + if (mutator != nullptr) { + mutator->stats().interesting++; + mutator->stats().new_edges += added->edges.size(); + } + if (config().save_corpus) { + fuzzer_->SaveCorpusProgram(*added); + } + publish_stage.successes++; + publish_stage.time_us += publish_time.ElapsedUs(); + JsonObject event; + event.Add("event", "corpus_add").Add("id", added->id); + event.Add("edges", static_cast<uint64_t>(edges.size())) + .Add("edges_hit", edges_hit); + event.Add("origin", added->lineage().origin) + .Add("detail", added->lineage().detail); + event.Add("parent", added->lineage().parent_id) + .Add("chain", added->lineage().chain); + event.Add("generation", added->lineage().generation); + event.Add("nodes", static_cast<uint64_t>(added->node_count())); + event.Add("reruns", reruns) + .Add("dropped_edges", static_cast<uint64_t>(dropped)); + event.Add("exec_time_ms", static_cast<double>(exec_time_us) / 1000.0); + event.Add("worker", id_); + if (minimize) { + event.Add("minimized", minimized).Add("min_tests", minimization.tests); + event.Add("min_nodes_before", + static_cast<uint64_t>(minimization.nodes_before)); + event.Add("min_nodes_after", + static_cast<uint64_t>(minimization.nodes_after)); + event.Add("min_time_ms", + static_cast<double>(minimization.time_us) / 1000.0); + } + event.Add("coverage", shared.coverage_fraction()); + fuzzer_->LogEvent(event); + return added; + } + + // --- crashes ---------------------------------------------------------- + + // Replays the last `count` programs of `history` in a fresh target, then + // `source`. Returns true if `source` then crashes (its execution is left + // in *execution). A history program that itself crashes or hangs resets + // the state being rebuilt, so the replay cannot answer the question then. + bool ReplayCrash(const std::vector<std::string>& history, size_t count, + const std::string& source, Execution* execution) { + runner_->child().Kill(); + for (size_t i = history.size() - count; i < history.size(); i++) { + Execution e; + if (stopping() || !Execute(history[i], &e)) { + return false; + } + stats().crash_replay_executions++; + if (e.crashed() || e.timed_out()) { + return false; + } + } + if (stopping() || !Execute(source, execution)) { + return false; + } + stats().crash_replay_executions++; + return execution->crashed(); + } + + // Everything learned about one crash, for the report and the event log. + struct CrashInfo { + CrashSignature signature; + int child_age = 0; // executions of the target before the crash + int reruns = 0; // fresh-target re-executions + int reproduced = 0; // ... that crashed again + int same_signature = 0; // ... with the same signature + bool replayed = false; // the history replay was attempted + bool state_dependent = false; // crashes only behind (part of) the history + size_t history_needed = 0; // shortest history suffix that reproduces it + size_t history_available = 0; + uint64_t replay_executions = 0; + bool minimized = false; + MinimizationResult minimization; + bool amplify_ran = false; // the amplify step ran (5.8) + AmplifyResult amplify; + bool reproducible() const { return reproduced > 0; } + }; + + // The amplify lines of the crash report (read by the uploader). + // `amplified_program` names the file of the changed program, if any. + static std::string AmplifyReportLines(const CrashInfo& info, + const std::string& amplified_program) { + if (!info.amplify_ran) { + return "amplified: skipped\n"; + } + return StringPrintf( + "amplified: %s\namplified_args: %s\namplified_rate: " + "%d/%d\namplify_processes: %d\n" + "amplify_time_sec: %.0f\namplify_note: %s\n%s", + info.amplify.amplified ? "yes" : "no", + info.amplify.amplified ? info.amplify.args.c_str() : "", + info.amplify.hits, info.amplify.processes, info.amplify.total_processes, + info.amplify.time_sec, info.amplify.note.c_str(), + amplified_program.empty() + ? "" + : ("amplified_program: " + amplified_program + "\n").c_str()); + } + + void ProcessCrash(const std::string& source, const Program& program, + const Execution& execution, const Lineage& lineage) { + SharedCoverage& shared = fuzzer_->coverage_; + const bool unique = shared.ClaimNewCrashEdges(runner_->coverage().bitmap()); + const uint64_t hash = Program::HashSource(source); + // The crash's edges, for a seed strategy that wants them (taken now: + // the reruns below overwrite the coverage map). + const std::vector<uint32_t> crash_edges = + fuzzer_->corpus().WantsHitEdges() ? runner_->coverage().CurrentEdges() + : std::vector<uint32_t>(); + CrashInfo info; + info.signature = CrashSignature::FromExecution(execution); + // Executions of this target before the crashing one, and those programs + // (Execute() appended the crasher itself; drop it). + info.child_age = std::max(0, runner_->child().execs_since_spawn() - 1); + std::vector<std::string> history(history_.begin(), history_.end()); + if (!history.empty()) { + history.pop_back(); + } + info.history_available = history.size(); + const Fuzzer::CrashDecision decision = + fuzzer_->RegisterCrash(hash, info.signature); + if (unique) { + stats().unique_crashes++; + } else { + stats().duplicate_crashes++; + } + REDLINE_LOG(kLog, "worker %d: crash #%d of signature \"%s\" (%s, %s)", id_, + decision.signature_count, info.signature.text.c_str(), + unique ? "new crash edges" : "known crash edges", + decision.save ? "saving" : "only counted"); + + // 1. Does it reproduce in a fresh target? The crash killed the target, + // so the first re-execution already runs in a new process. + // crash_reruns_stop_after crashes are deterministic enough to stop + // early. + uint64_t exec_time_us = execution.exec_time_us; + for (; info.reruns < config().crash_reruns && !stopping(); info.reruns++) { + Execution again; + if (!Execute(source, &again)) { + break; + } + stats().rerun_executions++; + exec_time_us = std::max(exec_time_us, again.exec_time_us); + if (!again.crashed()) { + continue; + } + info.reproduced++; + if (CrashSignature::FromExecution(again) == info.signature) { + info.same_signature++; + } + if (info.reproduced >= config().crash_reruns_stop_after) { + info.reruns++; + break; + } + } + if (info.reproducible()) { + stats().crashes_reproduced++; + if (!crash_edges.empty()) { + fuzzer_->corpus().RecordCrashEdges(crash_edges); + } + } + + // 2. If not: does it reproduce behind the programs the same target ran + // before it? If so, the shortest suffix of that history that still + // reproduces it is determined by binary search (every probe replays + // the suffix in a fresh target). Only worth doing for crashes that + // are saved, within the time budget. + const uint64_t replay_start_us = MonotonicNowUs(); + const uint64_t replay_budget_us = + static_cast<uint64_t>(config().crash_history_budget_sec * 1e6); + auto over_budget = [&] { + return MonotonicNowUs() - replay_start_us > replay_budget_us; + }; + if (!info.reproducible() && decision.save && !history.empty() && + replay_budget_us > 0 && !stopping()) { + info.replayed = true; + const uint64_t replay_execs_before = + stats().crash_replay_executions.load(); + Execution e; + if (ReplayCrash(history, history.size(), source, &e)) { + info.state_dependent = true; + size_t low = 0; // known not to reproduce (fresh target) + size_t high = history.size(); // known to reproduce + while (high - low > 1 && !over_budget() && !stopping()) { + size_t mid = low + (high - low) / 2; + if (ReplayCrash(history, mid, source, &e)) { + high = mid; + } else { + low = mid; + } + } + info.history_needed = high; + history.erase(history.begin(), + history.end() - static_cast<ptrdiff_t>(high)); + stats().crashes_state_dependent++; + } + info.replay_executions = + stats().crash_replay_executions.load() - replay_execs_before; + } + + // 2b. If it does not reproduce alone: the amplify step searches for a + // plain d8 command line (extra flags, --stress-runs) that + // reproduces the program alone, reliably (DESIGN.md 5.8). This + // also runs for state-dependent crashes: an earlier program may + // have switched on a feature (for example the CPU profiler) that + // a flag can switch on as well. Once per signature. + if (!info.reproducible() && decision.save && !stopping() && + fuzzer_->ClaimAmplify(info.signature)) { + AmplifyRequest request; + request.target = config().target; + request.program = source; + request.prelude = config().prelude; + request.script_path = StringPrintf("%s/crashes/amplify_%016llx.js", + config().out_dir.c_str(), + static_cast<unsigned long long>(hash)); + request.signature = info.signature; + request.stderr_text = execution.stderr_output; + request.exec_time_us = exec_time_us; + request.stopping = [this] { return stopping(); }; + info.amplify = fuzzer_->amplifier_->Amplify(request, rng_); + info.amplify_ran = true; + std::remove(request.script_path.c_str()); + stats().amplify_processes += + static_cast<uint64_t>(info.amplify.total_processes); + if (info.amplify.amplified) { + stats().crashes_amplified++; + } + REDLINE_LOG(kLog, "worker %d: signature \"%s\" %s (%d/%d with \"%s\")", + id_, info.signature.text.c_str(), + info.amplify.amplified ? "amplified" : "not amplified", + info.amplify.hits, info.amplify.processes, + info.amplify.args.c_str()); + } + + // 3. Minimization, against the same signature so that the reduction + // cannot wander off into a different bug. Crashes are rare, so they + // get their own, larger budget. + std::string final_source = source; + if (info.reproducible() && config().minimize_crashes && decision.minimize && + !stopping()) { + std::unique_ptr<fast::Tree> work = program.CopyTree(); + const uint64_t probe_timeout_us = ProbeTimeout(exec_time_us); + const CrashSignature& wanted = info.signature; + MinimizationOracle oracle = [&](const std::string& candidate) { + if (stopping()) { + return false; + } + Execution e; + if (!Execute(candidate, &e, probe_timeout_us) || !e.crashed()) { + return false; + } + return CrashSignature::FromExecution(e) == wanted; + }; + const MinimizerOptions budget = + config().crash_minimizer.ForProgram(exec_time_us); + info.minimization = + fuzzer_->Minimize(work.get(), oracle, probe_checker(), budget); + stats().minimizer_tests += static_cast<uint64_t>(info.minimization.tests); + stats().minimizer_time_us += info.minimization.time_us; + if (info.minimization.accepted > 0) { + std::string candidate = fast::Print(work->root()); + for (int attempt = 0; attempt < config().verify_attempts && !stopping(); + attempt++) { + Execution e; + if (!Execute(candidate, &e)) { + break; + } + stats().rerun_executions++; + if (!e.crashed() || CrashSignature::FromExecution(e) != wanted) { + continue; + } + final_source = candidate; + info.minimized = true; + break; + } + if (!info.minimized) { + stats().minimizer_rejected++; + } + } + } + + // 4. Store. + std::string path; + if (decision.save) { + path = SaveCrash(source, final_source, execution, lineage, info, unique, + hash, history); + } + fuzzer_->RecordCrashOutcome(info.signature, decision.save, info.minimized, + info.reproducible() || info.state_dependent, + path); + + JsonObject event; + event.Add("event", "crash") + .Add("hash", + StringPrintf("%016llx", static_cast<unsigned long long>(hash))); + event.Add("signature", info.signature.text); + event.Add("signature_hash", + StringPrintf("%016llx", static_cast<unsigned long long>( + info.signature.hash))); + event.Add("signature_count", decision.signature_count); + event.Add("signal", execution.signal) + .Add("unique_edges", unique) + .Add("saved", decision.save); + event.Add("reproducible", info.reproducible()).Add("reruns", info.reruns); + event.Add("reproduced", info.reproduced) + .Add("same_signature", info.same_signature); + event.Add("child_age", info.child_age).Add("replayed", info.replayed); + event.Add("state_dependent", info.state_dependent); + event.Add("history_needed", static_cast<uint64_t>(info.history_needed)); + event.Add("history_available", + static_cast<uint64_t>(info.history_available)); + event.Add("replay_executions", info.replay_executions); + event.Add("minimized", info.minimized) + .Add("min_tests", info.minimization.tests); + event.Add("min_nodes_before", + static_cast<uint64_t>(info.minimization.nodes_before)); + event.Add("min_nodes_after", + static_cast<uint64_t>(info.minimization.nodes_after)); + event.Add("amplify", info.amplify_ran + ? (info.amplify.amplified ? "yes" : "no") + : "skipped"); + if (info.amplify_ran) { + event.Add("amplified_args", info.amplify.args); + event.Add("amplified_hits", info.amplify.hits) + .Add("amplified_processes", info.amplify.processes); + event.Add("amplify_processes", info.amplify.total_processes); + event.Add("amplify_time_sec", info.amplify.time_sec) + .Add("amplify_note", info.amplify.note); + } + event.Add("origin", lineage.origin) + .Add("detail", lineage.detail) + .Add("parent", lineage.parent_id); + event.Add("path", path).Add("worker", id_); + event.Add("stderr", FirstLines(execution.stderr_output)); + fuzzer_->LogEvent(event); + } + + // Writes NAME.js (the minimized program, or the original), NAME.orig.js + // (if minimized), NAME.txt (the report) and NAME.history/NNN.js (the + // programs a state-dependent crash needs first). Returns the .js path. + std::string SaveCrash(const std::string& source, + const std::string& final_source, + const Execution& execution, const Lineage& lineage, + const CrashInfo& info, bool unique, uint64_t hash, + const std::vector<std::string>& history) { + std::string base = + StringPrintf("%s/crashes/crash_sig%d_%016llx", config().out_dir.c_str(), + execution.signal, static_cast<unsigned long long>(hash)); + std::string status; + if (info.reproducible()) { + status = StringPrintf("reproducible (%d/%d fresh-target runs crashed)", + info.reproduced, info.reruns); + } else if (info.state_dependent) { + status = StringPrintf( + "STATE-DEPENDENT: does not crash alone, crashes after the %zu " + "program(s) in " + "%s.history/ ran in the same d8 (replay them in order first)", + info.history_needed, base.substr(base.rfind('/') + 1).c_str()); + } else if (info.amplify.amplified) { + status = StringPrintf( + "AMPLIFIED: not reproduced in %d fresh-target runs, but %d/%d plain " + "d8 processes crashed with the " + "extra flags: %s", + info.reruns, info.amplify.hits, info.amplify.processes, + info.amplify.args.c_str()); + } else { + status = StringPrintf( + "NOT reproduced (%d fresh-target runs%s)", info.reruns, + info.replayed ? ", nor behind the target's history" : ""); + } + std::string header = StringPrintf( + "// redline crash: signal %d, %s\n// signature: %s\n// %s, worker %d " + "(target had run %d " + "programs), origin %s (%s), parent #%u, generation %d\n// d8 %s\n", + execution.signal, info.minimized ? "minimized" : "not minimized", + info.signature.text.c_str(), status.c_str(), id_, info.child_age, + lineage.origin.c_str(), lineage.detail.c_str(), lineage.parent_id, + lineage.generation, config().target.CommandLine().c_str()); + std::string error; + std::string path = base + ".js"; + if (!WriteStringToFile(path, header + final_source, &error)) { + REDLINE_WARN(kLog, "%s", error.c_str()); + } + if (info.minimized) { + WriteStringToFile(base + ".orig.js", header + source, &error); + } + // The program the amplified flags reproduce, if the amplify step + // changed it (wrapped in try/catch). + std::string amplified_program; + if (info.amplify.amplified && !info.amplify.program.empty()) { + amplified_program = base.substr(base.rfind('/') + 1) + ".amplified.js"; + WriteStringToFile(base + ".amplified.js", header + info.amplify.program, + &error); + } + if (info.state_dependent) { + std::string dir = base + ".history"; + if (MakeDirectories(dir, &error)) { + for (size_t i = 0; i < history.size(); i++) { + WriteStringToFile(StringPrintf("%s/%03zu.js", dir.c_str(), i), + history[i], &error); + } + } else { + REDLINE_WARN(kLog, "%s", error.c_str()); + } + } + std::string report = StringPrintf( + "signal: %d\nexit_code: %d\nsignature: %s\nunique_crash_edges: %s\n" + "reproducible: %s\nfresh_target_runs: %d\nfresh_target_crashes: %d\n" + "same_signature_crashes: %d\ntarget_age: %d executions before the " + "crash\n" + "history_replayed: %s\nstate_dependent: %s\nhistory_needed: %zu of " + "%zu\n" + "minimized: %s (%d tests, %zu -> %zu nodes)\n%s\n--- stderr " + "---\n%s\n--- stdout ---\n%s\n" + "--- fuzzout ---\n%s\n", + execution.signal, execution.exit_code, info.signature.text.c_str(), + unique ? "yes" : "no", info.reproducible() ? "yes" : "no", info.reruns, + info.reproduced, info.same_signature, info.child_age, + info.replayed ? "yes" : "no", info.state_dependent ? "yes" : "no", + info.history_needed, info.history_available, + info.minimized ? "yes" : "no", info.minimization.tests, + info.minimization.nodes_before, info.minimization.nodes_after, + AmplifyReportLines(info, amplified_program).c_str(), + Truncate(execution.stderr_output, kMaxSavedOutput).c_str(), + Truncate(execution.stdout_output, kMaxSavedOutput).c_str(), + Truncate(execution.fuzzout, kMaxSavedOutput).c_str()); + WriteStringToFile(base + ".txt", report, &error); + REDLINE_WARN( + kLog, "CRASH [%s] (%s%s%s) saved to %s", info.signature.text.c_str(), + unique ? "new crash edges" : "known crash edges", + info.reproducible() ? "" + : (info.state_dependent ? ", state-dependent" + : ", not reproducible"), + info.minimized ? ", minimized" : "", path.c_str()); + return path; + } + + Fuzzer* fuzzer_; + int id_; + Random rng_; + std::unique_ptr<ScriptRunner> runner_; + std::unique_ptr<SyntaxChecker> checker_; + std::thread thread_; + int consecutive_failures_ = 0; + uint64_t executions_ = 0; // target executions of this worker + std::deque<std::string> history_; + size_t history_bytes_ = 0; +}; + +// --------------------------------------------------------------------------- +// Fuzzer + +Fuzzer::Fuzzer(FuzzConfig config) : config_(std::move(config)) {} + +Fuzzer::~Fuzzer() { + for (auto& worker : workers_) { + worker->Join(); + } +} + +bool Fuzzer::Initialize(std::string* error) { + if (!MakeDirectories(config_.out_dir + "/crashes", error)) { + return false; + } + if (config_.save_corpus && + !MakeDirectories(config_.out_dir + "/corpus", error)) { + return false; + } + std::string events_path = config_.out_dir + "/events.jsonl"; + if (!events_.Open(events_path, /*truncate=*/false)) { + *error = "cannot open " + events_path; + return false; + } + if (!InitializeV8(config_.v8_flags, error)) { + return false; + } + + // The amplify step (DESIGN.md 5.8); FuzzConfig::Load validated it. + { + JsonValue amplify_params; + if (!JsonValue::Parse(config_.amplify_params, &lify_params, error)) { + return false; + } + amplifier_ = + CreateAmplifyStrategy(config_.amplify_strategy, amplify_params, error); + if (amplifier_ == nullptr) { + return false; + } + } + + // The selection strategies (core/selection.h). The configuration was + // validated by FuzzConfig::Load, so errors here are unexpected. + std::unique_ptr<ProgramSelector> seeds = + SelectorRegistry<const Program>::Instance().Create( + config_.selection.seeds, error); + if (seeds == nullptr) { + return false; + } + SelectionConfig partner_config = config_.selection.partners; + if (partner_config.strategy.empty()) { + partner_config.strategy = "uniform-partner"; + } + std::unique_ptr<ProgramSelector> partners = + SelectorRegistry<const Program>::Instance().Create(partner_config, error); + if (partners == nullptr) { + return false; + } + corpus_ = std::make_unique<Corpus>(std::move(seeds), std::move(partners)); + mutators_ = MutatorSet::CreateDefault(); + generators_ = GeneratorSet::CreateDefault(); + minimizer_ = std::make_unique<Minimizer>(config_.minimizer); + for (const std::string& name : config_.minimizer_reducers) { + minimizer_reducers_.push_back( + minimizer_->Find(name)); // names validated by FuzzConfig::Load + } + env_ = &Environment::Default(); + std::unique_ptr<Selector<Mutator>> mutator_selector = + SelectorRegistry<Mutator>::Instance().Create(config_.selection.mutators, + error); + if (mutator_selector == nullptr || + !mutators_->SetSelector(std::move(mutator_selector), error)) { + return false; + } + std::unique_ptr<Selector<Generator>> generator_selector = + SelectorRegistry<Generator>::Instance().Create( + config_.selection.generators, error); + if (generator_selector == nullptr || + !generators_->SetSelector(std::move(generator_selector), error)) { + return false; + } + mutators_->ConfigurePrefix(config_.prefix_min_values, + config_.prefix_extra_values); + codegen_mutator_ = mutators_->Find("CodeGen"); + if (codegen_mutator_ == nullptr) { + *error = "the CodeGen mutator is required for bootstrapping"; + return false; + } + prefix_mutator_ = mutators_->Find("Prefix"); + Lineage empty; + empty.origin = "empty"; + empty_program_ = Program::Parse("", empty, error); + if (empty_program_ == nullptr) { + return false; + } + + CollectImports(); + + for (int i = 0; i < config_.jobs; i++) { + auto worker = std::make_unique<Worker>(this, i); + if (!worker->Start(error)) { + *error = StringPrintf("worker %d: %s", i, error->c_str()); + return false; + } + workers_.push_back(std::move(worker)); + } + + // Ask the target what it offers beyond the hand-written model. + if (config_.introspect) { + std::string json, problem; + if (!workers_[0]->Introspect(&json, &problem)) { + REDLINE_WARN(kLog, + "environment introspection failed (%s); using the built-in " + "model only", + problem.c_str()); + } else { + discovered_env_ = Environment::WithDiscovered(json, &problem); + if (discovered_env_ == nullptr) { + REDLINE_WARN(kLog, + "environment introspection unusable (%s); using the " + "built-in model only", + problem.c_str()); + } else { + env_ = discovered_env_.get(); + REDLINE_LOG(kLog, + "environment: %zu globals/namespaces with %zu members " + "discovered in the target", + env_->discovered().size(), env_->discovered_member_count()); + } + } + } + return true; +} + +void Fuzzer::CollectImports() { + for (const std::string& path : config_.imports) { + std::vector<std::string> files = ListFiles(path, ".js"); + if (files.empty()) { + REDLINE_WARN(kLog, "--import=%s: no .js files found", path.c_str()); + } + import_files_.insert(import_files_.end(), files.begin(), files.end()); + } + // Spread big directories over the workers in a reproducible order that + // does not put all the slow tests of one directory on one worker. + Random rng(config_.seed); + for (size_t i = import_files_.size(); i > 1; i--) { + std::swap(import_files_[i - 1], import_files_[rng.Index(i)]); + } +} + +void Fuzzer::Fail(const std::string& message) { + { + std::scoped_lock<std::mutex> lock(failure_mutex_); + if (failure_.empty()) { + failure_ = message; + } + } + failed_.store(true); + RequestStop(); +} + +bool Fuzzer::ClaimAmplify(const CrashSignature& signature) { + std::scoped_lock<std::mutex> lock(crash_mutex_); + SignatureInfo& info = crash_signatures_[signature.hash]; + if (amplifier_ == nullptr || info.amplify >= amplifier_->per_signature()) { + return false; + } + info.amplify++; + return true; +} + +Fuzzer::CrashDecision Fuzzer::RegisterCrash(uint64_t source_hash, + const CrashSignature& signature) { + std::scoped_lock<std::mutex> lock(crash_mutex_); + CrashDecision decision; + SignatureInfo& info = crash_signatures_[signature.hash]; + if (info.count == 0) { + info.text = signature.text; + info.first_seen_sec = + static_cast<double>(WallClockNowMs() - start_ms_) / 1000.0; + stats_.crash_signatures = crash_signatures_.size(); + } + info.count++; + decision.signature_count = info.count; + decision.new_source = crash_hashes_.insert(source_hash).second; + decision.save = + decision.new_source && info.saved < config_.max_crashes_per_signature; + decision.minimize = + decision.save && info.minimized < config_.minimize_crashes_per_signature; + // Reserve the slots now so that concurrent crashes of the same signature + // do not all get saved/minimized; RecordCrashOutcome corrects the counts. + if (decision.save) { + info.saved++; + } + if (decision.minimize) { + info.minimized++; + } + return decision; +} + +void Fuzzer::RecordCrashOutcome(const CrashSignature& signature, bool saved, + bool minimized, bool reproduced, + const std::string& path) { + std::scoped_lock<std::mutex> lock(crash_mutex_); + SignatureInfo& info = crash_signatures_[signature.hash]; + // RegisterCrash reserved a save slot and a minimize slot; give back the + // minimize slot if the minimization did not happen or failed, so the + // next crash of this signature gets a chance. + if (saved && !minimized && info.minimized > 0) { + info.minimized--; + } + if (reproduced) { + info.reproduced++; + } + if (saved && info.first_path.empty()) { + info.first_path = path; + } + WriteSignatureSummary(); +} + +// Called with crash_mutex_ held. +void Fuzzer::WriteSignatureSummary() { + std::string text = + "# signature | crashes | saved | minimized | reproduced | first seen (s) " + "| first file\n"; + for (const auto& [hash, info] : crash_signatures_) { + text += + StringPrintf("%s | %d | %d | %d | %d | %.0f | %s\n", info.text.c_str(), + info.count, info.saved, info.minimized, info.reproduced, + info.first_seen_sec, info.first_path.c_str()); + } + std::string error; + if (!WriteStringToFile(config_.out_dir + "/crashes/signatures.txt", text, + &error)) { + REDLINE_WARN(kLog, "%s", error.c_str()); + } +} + +bool Fuzzer::SaveCorpusProgram(const Program& program) { + const Lineage& lineage = program.lineage(); + std::string header = StringPrintf( + "// redline corpus #%u | origin %s | parent #%u +%d | generation %d | " + "%zu new edges | " + "%zu nodes | worker %d%s%s\n", + program.id, lineage.origin.c_str(), lineage.parent_id, lineage.chain, + lineage.generation, program.edges.size(), program.node_count(), + lineage.worker, lineage.detail.empty() ? "" : " | ", + lineage.detail.c_str()); + std::string path = + StringPrintf("%s/corpus/%06u.js", config_.out_dir.c_str(), program.id); + std::string error; + if (!WriteStringToFile(path, header + program.source(), &error)) { + REDLINE_WARN(kLog, "%s", error.c_str()); + return false; + } + return true; +} + +void Fuzzer::LogEvent(const JsonObject& event) { + // Every event carries the session time so logs of different runs can be + // aligned. + JsonObject stamped; + stamped.Add("t", static_cast<double>(WallClockNowMs() - start_ms_) / 1000.0); + std::string line = stamped.ToString(); + std::string body = event.ToString(); + // {"t":1.5} + {"event":...} -> {"t":1.5,"event":...} + line.pop_back(); + line += ','; + line += body.substr(1); + events_.WriteLine(line); +} + +bool Fuzzer::ShouldStop() const { + if (stop_requested()) { + return true; + } + if (config_.duration_sec > 0 && + static_cast<double>(WallClockNowMs() - start_ms_) / 1000.0 >= + config_.duration_sec) { + return true; + } + if (config_.max_execs > 0 && stats_.executions.load() >= config_.max_execs) { + return true; + } + return false; +} + +std::string Fuzzer::StatusLine() const { + uint64_t elapsed_ms = WallClockNowMs() - start_ms_; + double elapsed_s = std::max(0.001, static_cast<double>(elapsed_ms) / 1000.0); + uint64_t execs = stats_.executions.load(); + uint64_t fuzz = stats_.fuzz_executions.load(); + uint64_t produced = fuzz + stats_.invalid.load(); + double exec_share = Percent(stats_.exec_time_us.load(), + static_cast<uint64_t>(elapsed_s * 1e6) * + static_cast<uint64_t>(config_.jobs)); + return StringPrintf( + "%s | execs %llu (%.0f/s) | cov %.3f%% (%u edges) | corpus %zu | " + "ok %.1f%% fail %.1f%% timeout %.1f%% | invalid %.2f%% noop %llu | " + "crashes %llu (%llu sigs, %llu repro) | cands %llu flaky %llu | min %llu " + "tests (%.1f%% of execs, %.1f%% of " + "time) | " + "exec %.0f%% busy | avg exec %.1f ms | avg nodes %.0f (corpus %.0f)", + FormatDuration(elapsed_ms / 1000).c_str(), + static_cast<unsigned long long>(execs), + static_cast<double>(execs) / elapsed_s, + 100.0 * coverage_.coverage_fraction(), coverage_.found_edges(), + corpus_->size(), Percent(stats_.succeeded.load(), fuzz), + Percent(stats_.failed.load(), fuzz), + Percent(stats_.timed_out.load(), fuzz), + Percent(stats_.invalid.load(), produced), + static_cast<unsigned long long>(stats_.noop.load()), + static_cast<unsigned long long>(stats_.crashed.load()), + static_cast<unsigned long long>(stats_.crash_signatures.load()), + static_cast<unsigned long long>(stats_.crashes_reproduced.load()) + + static_cast<unsigned long long>( + stats_.crashes_state_dependent.load()), + static_cast<unsigned long long>(stats_.candidates.load()), + static_cast<unsigned long long>(stats_.flaky.load()), + static_cast<unsigned long long>(stats_.minimizer_tests.load()), + Percent(stats_.minimizer_tests.load(), execs), + Percent(stats_.minimizer_time_us.load(), + static_cast<uint64_t>(elapsed_s * 1e6) * + static_cast<uint64_t>(config_.jobs)), + exec_share, + execs == 0 ? 0.0 + : static_cast<double>(stats_.exec_time_us.load()) / 1000.0 / + static_cast<double>(execs), + fuzz == 0 ? 0.0 + : static_cast<double>(stats_.fuzz_nodes.load()) / + static_cast<double>(fuzz), + stats_.corpus_added.load() == 0 + ? 0.0 + : static_cast<double>(stats_.corpus_nodes.load()) / + static_cast<double>(stats_.corpus_added.load())); +} + +std::string Fuzzer::ComponentTables(bool include_generators) const { + std::string out = FormatStatsTable("mutators", mutators_->Components()); + out += FormatStatsTable("reducers", minimizer_->Components()); + bool enabled[kNumStages]; + for (int i = 0; i < kNumStages; i++) { + enabled[i] = config_.stages[i].stats; + } + out += stages_.Format(enabled); + out += FormatStatsTable("seeds", {&corpus_->seed_stats()}); + if (include_generators) { + out += FormatStatsTable("generators", generators_->Components()); + } + return out; +} + +void Fuzzer::WriteStatsEvent() { + JsonObject event; + event.Add("event", "stats"); + event.Add("executions", stats_.executions.load()); + event.Add("fuzz_executions", stats_.fuzz_executions.load()); + event.Add("succeeded", stats_.succeeded.load()) + .Add("failed", stats_.failed.load()); + event.Add("timed_out", stats_.timed_out.load()) + .Add("crashed", stats_.crashed.load()); + event.Add("invalid", stats_.invalid.load()).Add("noop", stats_.noop.load()); + event.Add("candidates", stats_.candidates.load()) + .Add("flaky", stats_.flaky.load()); + event.Add("corpus", static_cast<uint64_t>(corpus_->size())); + event.Add("corpus_added", stats_.corpus_added.load()); + event.Add("coverage", coverage_.coverage_fraction()); + event.Add("found_edges", coverage_.found_edges()) + .Add("num_edges", coverage_.num_edges()); + event.Add("suppressed_flaky_edges", coverage_.suppressed_flaky_edges()); + event.Add("unique_crashes", stats_.unique_crashes.load()); + event.Add("duplicate_crashes", stats_.duplicate_crashes.load()); + event.Add("crash_signatures", stats_.crash_signatures.load()); + event.Add("crashes_reproduced", stats_.crashes_reproduced.load()); + event.Add("crashes_state_dependent", stats_.crashes_state_dependent.load()); + event.Add("crashes_amplified", stats_.crashes_amplified.load()); + event.Add("amplify_processes", stats_.amplify_processes.load()); + event.Add("crash_replay_executions", stats_.crash_replay_executions.load()); + event.Add("imports_total", stats_.imports_total.load()); + event.Add("imports_added", stats_.imports_added.load()); + event.Add("imports_failed", stats_.imports_failed.load()); + event.Add("imports_redundant", stats_.imports_redundant.load()); + event.Add("minimizer_tests", stats_.minimizer_tests.load()); + event.Add("minimizer_time_us", stats_.minimizer_time_us.load()); + event.Add("minimizer_nodes_removed", stats_.minimizer_nodes_removed.load()); + event.Add("minimizer_rejected", stats_.minimizer_rejected.load()); + event.Add("rerun_executions", stats_.rerun_executions.load()); + event.Add("explore_executions", stats_.explore_executions.load()); + event.Add("explore_applied", stats_.explore_applied.load()); + event.Add("explore_timeouts", stats_.explore_timeouts.load()); + event.Add("exec_time_us", stats_.exec_time_us.load()); + event.Add("fuzz_nodes", stats_.fuzz_nodes.load()); + event.Add("corpus_nodes", stats_.corpus_nodes.load()); + event.Add("mutation_time_us", stats_.mutation_time_us.load()); + event.Add("infrastructure_failures", stats_.infrastructure_failures.load()); + event.AddRaw("stages", stages_.ToJson()); + LogEvent(event); +} + +bool Fuzzer::WriteCapture(Stage stage, CaptureTrigger trigger, + std::string_view mutator, const Program* parent, + const std::string& child, const JsonObject& details, + int worker) { + const CaptureRule& rule = config_.stage(stage).capture; + uint64_t index = captures_[static_cast<int>(stage)].fetch_add( + 1, std::memory_order_relaxed); + if (index >= static_cast<uint64_t>(rule.max)) { + return false; + } + std::string dir = + config_.out_dir + "/captures/" + std::string(StageName(stage)); + std::string error; + if (!MakeDirectories(dir, &error)) { + REDLINE_WARN(kLog, "capture: %s", error.c_str()); + return false; + } + std::string base = StringPrintf( + "%s/%04llu-%.*s%s%.*s", dir.c_str(), + static_cast<unsigned long long>(index), + static_cast<int>(CaptureTriggerName(trigger).size()), + CaptureTriggerName(trigger).data(), mutator.empty() ? "" : "-", + static_cast<int>(mutator.size()), mutator.data()); + if (parent != nullptr) { + WriteStringToFile(base + ".parent.js", parent->source(), &error); + } + if (!child.empty()) { + WriteStringToFile(base + ".child.js", child, &error); + } + JsonObject sidecar; + sidecar.Add("stage", StageName(stage)) + .Add("trigger", CaptureTriggerName(trigger)); + sidecar.Add("mutator", mutator).Add("worker", worker); + sidecar.Add("elapsed_sec", + static_cast<double>(WallClockNowMs() - start_ms_) / 1000.0); + if (parent != nullptr) { + sidecar.Add("parent_id", parent->id) + .Add("parent_origin", parent->lineage().origin); + sidecar.Add("parent_detail", parent->lineage().detail); + } + sidecar.AddRaw("details", details.ToString()); + WriteStringToFile(base + ".json", sidecar.ToString() + "\n", &error); + if (index + 1 == static_cast<uint64_t>(rule.max)) { + REDLINE_LOG( + kLog, "capture: %s reached its cap of %d, no more files for this stage", + dir.c_str(), rule.max); + } + return true; +} + +MinimizationResult Fuzzer::Minimize(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker, + const MinimizerOptions& options) const { + if (minimizer_reducers_.empty()) { + return minimizer_->Minimize(tree, oracle, checker, options); + } + return minimizer_->MinimizeWith(minimizer_reducers_, tree, oracle, checker, + options); +} + +int Fuzzer::Run() { + start_ms_ = WallClockNowMs(); + { + JsonObject event; + event.Add("event", "start").AddRaw("config", config_.ToJson()); + // The strategies as built, with every parameter filled in. + JsonObject selectors; + selectors.AddRaw("seeds", EffectiveSelector(corpus_->seeds())); + selectors.AddRaw("partners", EffectiveSelector(corpus_->partners())); + selectors.AddRaw("mutators", EffectiveSelector(mutators_->selector())); + selectors.AddRaw("generators", EffectiveSelector(generators_->selector())); + event.AddRaw("selectors", selectors.ToString()); + event.Add("imports", static_cast<uint64_t>(import_files_.size())); + event.Add("num_edges", coverage_.num_edges()); + LogEvent(event); + } + REDLINE_LOG( + kLog, + "session: %d worker(s), seed %llu, %u edges in target, %zu file(s) to " + "import, " + "seeds %.*s, partners %.*s, mutators %.*s, generators %.*s, output %s", + config_.jobs, static_cast<unsigned long long>(config_.seed), + coverage_.num_edges(), import_files_.size(), + static_cast<int>(corpus_->seeds().name().size()), + corpus_->seeds().name().data(), + static_cast<int>(corpus_->partners().name().size()), + corpus_->partners().name().data(), + static_cast<int>(mutators_->selector().name().size()), + mutators_->selector().name().data(), + static_cast<int>(generators_->selector().name().size()), + generators_->selector().name().data(), config_.out_dir.c_str()); + for (auto& worker : workers_) { + worker->Launch(); + } + + uint64_t last_stats_ms = start_ms_; + size_t last_corpus = 0; + int intervals = 0; + bool import_reported = import_files_.empty(); + while (!ShouldStop()) { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + uint64_t now = WallClockNowMs(); + if (!import_reported && workers_importing_.load() == 0 && + next_import_.load() >= import_files_.size()) { + import_reported = true; + REDLINE_LOG( + kLog, + "import done: %llu files, %llu added, %llu redundant, %llu failed; " + "coverage %.3f%%, corpus %zu", + static_cast<unsigned long long>(stats_.imports_total.load()), + static_cast<unsigned long long>(stats_.imports_added.load()), + static_cast<unsigned long long>(stats_.imports_redundant.load()), + static_cast<unsigned long long>(stats_.imports_failed.load()), + 100.0 * coverage_.coverage_fraction(), corpus_->size()); + JsonObject event; + event.Add("event", "import_done") + .Add("total", stats_.imports_total.load()); + event.Add("added", stats_.imports_added.load()); + event.Add("redundant", stats_.imports_redundant.load()); + event.Add("failed", stats_.imports_failed.load()); + event.Add("coverage", coverage_.coverage_fraction()); + LogEvent(event); + } + if (config_.stats_interval_sec > 0 && + static_cast<double>(now - last_stats_ms) / 1000.0 >= + config_.stats_interval_sec) { + last_stats_ms = now; + intervals++; + WriteStatsEvent(); + if (!config_.quiet) { + size_t corpus_size = corpus_->size(); + REDLINE_LOG(kLog, "%s (+%zu)", StatusLine().c_str(), + corpus_size - last_corpus); + last_corpus = corpus_size; + if (config_.component_stats) { + fputs(ComponentTables(intervals % 10 == 0).c_str(), stderr); + } + } + } + } + stop_.store(true); + for (auto& worker : workers_) { + worker->Join(); + } + + WriteStatsEvent(); + { + JsonObject event; + event.Add("event", "end") + .Add("reason", failed_.load() ? "failure" : "stop"); + event.Add("elapsed_sec", + static_cast<double>(WallClockNowMs() - start_ms_) / 1000.0); + LogEvent(event); + } + events_.Flush(); + REDLINE_LOG(kLog, "final: %s", StatusLine().c_str()); + if (config_.component_stats) { + fputs(ComponentTables(true).c_str(), stderr); + } + if (failed_.load()) { + REDLINE_ERROR(kLog, "%s", failure_.c_str()); + return 1; + } + return 0; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/fuzzer.h b/deps/v8/experimental/redline/engine/fuzzer.h new file mode 100644 index 000000000000..b7d59191476b --- /dev/null +++ b/deps/v8/experimental/redline/engine/fuzzer.h @@ -0,0 +1,201 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_ENGINE_FUZZER_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_FUZZER_H_ + +#include <atomic> +#include <cstdint> +#include <map> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_set> +#include <vector> + +#include "experimental/redline/base/json.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/corpus/corpus.h" +#include "experimental/redline/engine/amplifier.h" +#include "experimental/redline/engine/config.h" +#include "experimental/redline/engine/crash.h" +#include "experimental/redline/engine/shared_coverage.h" +#include "experimental/redline/engine/stages.h" +#include "experimental/redline/generators/generator.h" +#include "experimental/redline/minimizer/minimizer.h" +#include "experimental/redline/mutators/mutator.h" + +namespace redline { + +class Environment; +class Worker; + +// Session-wide counters. Everything a worker does is accounted here (and, +// per component, in the ComponentStats of mutators/generators/reducers). +struct FuzzerStats { + std::atomic<uint64_t> executions{0}; // all target executions + std::atomic<uint64_t> fuzz_executions{0}; // ... of fresh mutation results + std::atomic<uint64_t> succeeded{0}; // outcome of fuzz executions + std::atomic<uint64_t> failed{0}; + std::atomic<uint64_t> timed_out{0}; + std::atomic<uint64_t> crashed{0}; + std::atomic<uint64_t> invalid{0}; // rejected by the V8 parser + std::atomic<uint64_t> noop{0}; // mutator found nothing to do + std::atomic<uint64_t> candidates{0}; // executions with new edges + std::atomic<uint64_t> flaky{0}; // candidates that failed determinism + std::atomic<uint64_t> corpus_added{0}; + std::atomic<uint64_t> imports_total{0}; + std::atomic<uint64_t> imports_added{0}; + std::atomic<uint64_t> imports_failed{0}; // parse error / failed / timed out + std::atomic<uint64_t> imports_redundant{0}; // ran fine, no new edges + std::atomic<uint64_t> unique_crashes{0}; // crashes reaching new crash edges + std::atomic<uint64_t> duplicate_crashes{0}; + std::atomic<uint64_t> crash_signatures{0}; // distinct signatures so far + std::atomic<uint64_t> crashes_reproduced{0}; // reproduced in a fresh target + std::atomic<uint64_t> crashes_state_dependent{0}; // only with history + std::atomic<uint64_t> crashes_amplified{0}; // reproduced by the amplify step + std::atomic<uint64_t> amplify_processes{ + 0}; // plain d8 runs of the amplify step + std::atomic<uint64_t> crash_replay_executions{0}; // spent on history replays + std::atomic<uint64_t> minimizer_tests{0}; + std::atomic<uint64_t> minimizer_time_us{0}; + std::atomic<uint64_t> minimizer_nodes_removed{0}; + std::atomic<uint64_t> minimizer_rejected{0}; // result failed verification + std::atomic<uint64_t> rerun_executions{0}; + std::atomic<uint64_t> explore_executions{0}; // instrumented runs + std::atomic<uint64_t> explore_applied{0}; // ... that produced a mutation + std::atomic<uint64_t> explore_timeouts{0}; + std::atomic<uint64_t> exec_time_us{0}; + std::atomic<uint64_t> fuzz_nodes{0}; // AST nodes of executed mutants + std::atomic<uint64_t> corpus_nodes{0}; // AST nodes of added corpus programs + std::atomic<uint64_t> mutation_time_us{0}; + std::atomic<uint64_t> infrastructure_failures{0}; +}; + +// The coordinator of one fuzzing session: owns the configuration, the +// shared state (corpus, coverage, components, event log) and the worker +// threads. Each worker owns a target process and mutates/executes +// independently; the only shared mutable state is the corpus (mutex), the +// coverage bits (atomics) and the counters. +class Fuzzer { + public: + explicit Fuzzer(FuzzConfig config); + ~Fuzzer(); + Fuzzer(const Fuzzer&) = delete; + Fuzzer& operator=(const Fuzzer&) = delete; + + // Creates the output directory, the event log and the components, and + // initializes the in-process V8. Returns false with a message on failure. + bool Initialize(std::string* error); + // Runs the session until a stop condition (duration, max_execs, stop + // request) is met. Returns a process exit code. + int Run(); + // Asks all workers to stop after their current step (signal-safe). + void RequestStop() { stop_.store(true, std::memory_order_release); } + bool stop_requested() const { return stop_.load(std::memory_order_acquire); } + + const FuzzConfig& config() const { return config_; } + const FuzzerStats& stats() const { return stats_; } + Corpus& corpus() { return *corpus_; } + SharedCoverage& coverage() { return coverage_; } + MutatorSet& mutators() { return *mutators_; } + GeneratorSet& generators() { return *generators_; } + Minimizer& minimizer() { return *minimizer_; } + // Minimizes with the configured reducer order (stages.minimize.reducers). + MinimizationResult Minimize(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker, + const MinimizerOptions& options) const; + + // One line summarizing the session so far. + std::string StatusLine() const; + // The per-component tables (mutators, reducers, scheduler, generators). + std::string ComponentTables(bool include_generators) const; + + private: + friend class Worker; + + void LogEvent(const JsonObject& event); + void WriteStatsEvent(); + bool ShouldStop() const; + void CollectImports(); + bool SaveCorpusProgram(const Program& program); + // Saves the programs of a stage that matched its capture rule (see + // engine/stages.h) under out_dir/captures/<stage>/. Returns false once + // the rule's cap is reached. + bool WriteCapture(Stage stage, CaptureTrigger trigger, + std::string_view mutator, const Program* parent, + const std::string& child, const JsonObject& details, + int worker); + // Records a fatal problem and stops the session. + void Fail(const std::string& message); + + FuzzConfig config_; + FuzzerStats stats_; + StageTable stages_; // per-stage counters + std::atomic<uint64_t> captures_[kNumStages] = {}; // files written per stage + std::atomic<bool> stop_{false}; + std::atomic<bool> failed_{false}; + std::string failure_; + std::mutex failure_mutex_; + + SharedCoverage coverage_; + std::unique_ptr<Corpus> corpus_; + std::unique_ptr<MutatorSet> mutators_; + std::unique_ptr<GeneratorSet> generators_; + std::unique_ptr<Minimizer> minimizer_; + // The configured reducer order (stages.minimize.reducers); empty: the + // default order. + std::vector<Reducer*> minimizer_reducers_; + const Environment* env_ = nullptr; + std::unique_ptr<Environment> discovered_env_; // owns env_ when introspected + Mutator* codegen_mutator_ = nullptr; + Mutator* prefix_mutator_ = nullptr; + ProgramPtr empty_program_; + JsonlWriter events_; + uint64_t start_ms_ = 0; + + // Import work queue, drained by the workers before they start fuzzing. + std::vector<std::string> import_files_; + std::atomic<size_t> next_import_{0}; + std::atomic<int> workers_importing_{0}; + + // Crash bookkeeping, by signature. + struct SignatureInfo { + std::string text; + int count = 0; // crashes seen with this signature + int saved = 0; // ... whose program was written to disk + int minimized = 0; // ... that were minimized + int reproduced = 0; // ... that reproduced in a fresh target + int amplify = 0; // ... that ran the amplify step + std::string first_path; + double first_seen_sec = 0; + }; + // What ProcessCrash should do with a crash, decided under crash_mutex_. + struct CrashDecision { + bool new_source = false; // this exact program was not seen crashing before + bool save = false; // write the files + bool minimize = false; // spend minimization budget on it + int signature_count = 0; // including this crash + }; + CrashDecision RegisterCrash(uint64_t source_hash, + const CrashSignature& signature); + // True if the amplify step may run for this signature now (reserves it). + bool ClaimAmplify(const CrashSignature& signature); + void RecordCrashOutcome(const CrashSignature& signature, bool saved, + bool minimized, bool reproduced, + const std::string& path); + // Rewrites DIR/crashes/signatures.txt. + void WriteSignatureSummary(); + std::mutex crash_mutex_; + std::unordered_set<uint64_t> crash_hashes_; + std::map<uint64_t, SignatureInfo> crash_signatures_; + std::unique_ptr<AmplifyStrategy> amplifier_; // the amplify step (5.8) + + std::vector<std::unique_ptr<Worker>> workers_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_FUZZER_H_ diff --git a/deps/v8/experimental/redline/engine/importer.cc b/deps/v8/experimental/redline/engine/importer.cc new file mode 100644 index 000000000000..9c63498ad454 --- /dev/null +++ b/deps/v8/experimental/redline/engine/importer.cc @@ -0,0 +1,167 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/importer.h" + +#include <cstring> + +#include "experimental/redline/base/file_util.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/parser.h" + +namespace redline { + +namespace { + +constexpr char kLog[] = "import"; + +// If `statement` is `load("f")` or `d8.file.execute("f")`, returns "f". +std::string LoadedFile(const fast::Statement* statement) { + const auto* expression_statement = statement->As<fast::ExpressionStatement>(); + if (expression_statement == nullptr) { + return ""; + } + const auto* call = + expression_statement->expression->As<fast::CallExpression>(); + if (call == nullptr || call->arguments.size() != 1) { + return ""; + } + const auto* argument = call->arguments[0]->As<fast::StringLiteral>(); + if (argument == nullptr) { + return ""; + } + if (const auto* callee = call->callee->As<fast::Identifier>()) { + if (callee->name != "load") { + return ""; + } + return argument->value; + } + // d8.file.execute(...) + const auto* execute = call->callee->As<fast::MemberExpression>(); + if (execute == nullptr || execute->computed) { + return ""; + } + const auto* execute_name = execute->property->As<fast::Identifier>(); + if (execute_name == nullptr || execute_name->name != "execute") { + return ""; + } + const auto* file = execute->object->As<fast::MemberExpression>(); + if (file == nullptr || file->computed) { + return ""; + } + const auto* file_name = file->property->As<fast::Identifier>(); + const auto* d8 = file->object->As<fast::Identifier>(); + if (file_name == nullptr || file_name->name != "file" || d8 == nullptr || + d8->name != "d8") { + return ""; + } + return argument->value; +} + +std::string DirName(const std::string& path) { + size_t slash = path.rfind('/'); + if (slash == std::string::npos) { + return "."; + } + if (slash == 0) { + return "/"; + } + return path.substr(0, slash); +} + +bool EndsWith(const std::string& text, const char* suffix) { + size_t n = strlen(suffix); + return text.size() >= n && text.compare(text.size() - n, n, suffix) == 0; +} + +// Finds the file a load() refers to: relative to the import root, then to +// the loading file, then to the current directory. +bool Resolve(const std::string& file, const std::string& loader_path, + const ImportOptions& options, std::string* resolved) { + std::vector<std::string> candidates; + if (!file.empty() && file[0] == '/') { + candidates.push_back(file); + } else { + if (!options.root.empty()) { + candidates.push_back(options.root + "/" + file); + } + candidates.push_back(DirName(loader_path) + "/" + file); + candidates.push_back(file); + } + for (const std::string& candidate : candidates) { + if (FileExists(candidate)) { + *resolved = candidate; + return true; + } + } + return false; +} + +// Replaces load() statements in `tree` (parsed from `path`) by the loaded +// files' statements, recursively. +void InlineLoads(fast::Tree* tree, const std::string& path, + const ImportOptions& options, int depth, ImportInfo* info) { + std::vector<fast::Statement*>& body = tree->root()->body; + for (size_t i = 0; i < body.size();) { + std::string file = LoadedFile(body[i]); + if (file.empty()) { + i++; + continue; + } + body.erase(body.begin() + static_cast<ptrdiff_t>(i)); + // The mjsunit harness is provided by the execution prelude. + if (EndsWith(file, "mjsunit.js")) { + continue; + } + std::string resolved; + if (depth >= options.max_depth || + !Resolve(file, path, options, &resolved)) { + info->dropped.push_back(file); + continue; + } + std::string source, error; + if (!ReadFileToString(resolved, &source, &error)) { + info->dropped.push_back(file); + continue; + } + fast::ParseError parse_error; + std::unique_ptr<fast::Tree> loaded = + fast::Parser::ParseScript(source, fast::ParseOptions(), &parse_error); + if (loaded == nullptr) { + REDLINE_VLOG(kLog, "%s: cannot inline %s: %s", path.c_str(), + resolved.c_str(), parse_error.ToString().c_str()); + info->dropped.push_back(file); + continue; + } + InlineLoads(loaded.get(), resolved, options, depth + 1, info); + std::vector<fast::Statement*> clones; + for (const fast::Statement* statement : loaded->root()->body) { + clones.push_back(tree->Clone(statement)); + } + body.insert(body.begin() + static_cast<ptrdiff_t>(i), clones.begin(), + clones.end()); + info->inlined.push_back(resolved); + i += clones.size(); + } +} + +} // namespace + +std::unique_ptr<fast::Tree> ImportSource(std::string_view source, + const std::string& path, + const ImportOptions& options, + ImportInfo* info, std::string* error) { + fast::ParseError parse_error; + std::unique_ptr<fast::Tree> tree = + fast::Parser::ParseScript(source, fast::ParseOptions(), &parse_error); + if (tree == nullptr) { + *error = parse_error.ToString(); + return nullptr; + } + InlineLoads(tree.get(), path, options, 0, info); + return tree; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/importer.h b/deps/v8/experimental/redline/engine/importer.h new file mode 100644 index 000000000000..42b1b9d6218a --- /dev/null +++ b/deps/v8/experimental/redline/engine/importer.h @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_ENGINE_IMPORTER_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_IMPORTER_H_ + +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/fast/tree.h" + +namespace redline { + +struct ImportOptions { + // Directory that load("test/mjsunit/...") paths are relative to + // (usually the V8 checkout). Empty: the current directory. + std::string root; + // Nesting limit for inlined files that load other files. + int max_depth = 4; +}; + +struct ImportInfo { + std::vector<std::string> inlined; // files whose statements were spliced in + std::vector<std::string> dropped; // load() calls that could not be resolved +}; + +// Parses a test file into a FAST tree suitable for the corpus: top-level +// `load("f")` and `d8.file.execute("f")` statements are replaced by the +// statements of `f` (so that helpers such as wasm-module-builder.js become +// part of the program and the result is self-contained); loads that cannot +// be resolved, and loads of mjsunit.js (whose API the execution prelude +// provides), are removed. Returns nullptr with `error` on a parse error. +std::unique_ptr<fast::Tree> ImportSource(std::string_view source, + const std::string& path, + const ImportOptions& options, + ImportInfo* info, std::string* error); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_IMPORTER_H_ diff --git a/deps/v8/experimental/redline/engine/prelude.cc b/deps/v8/experimental/redline/engine/prelude.cc new file mode 100644 index 000000000000..abb4c3bf93ad --- /dev/null +++ b/deps/v8/experimental/redline/engine/prelude.cc @@ -0,0 +1,81 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/prelude.h" + +namespace redline { + +namespace { + +// Keep this small: it runs before every execution. The functions evaluate +// their arguments (so that the values flow) but never throw, except +// assertThrows-style helpers which must run their callback. +const char kDefaultPrelude[] = R"JS( +var __redline_noop = function() {}; +var __redline_call = function(f) { + try { return typeof f === "function" ? f() : eval(String(f)); } catch (e) { return e; } +}; +var assertSame = function(a, b) { return a === b; }; +var assertNotSame = function(a, b) { return a !== b; }; +var assertEquals = function(a, b) { return a == b; }; +var assertNotEquals = function(a, b) { return a != b; }; +var assertEqualsDelta = function(a, b, d) { return Math.abs(a - b) <= d; }; +var assertArrayEquals = function(a, b) { return a && b && a.length === b.length; }; +var assertPropertiesEqual = function(a, b) { return a && b && Object.keys(a).length === Object.keys(b).length; }; +var assertToStringEquals = function(a, b) { return a == String(b); }; +var assertTrue = function(a) { return !!a; }; +var assertFalse = function(a) { return !a; }; +var assertNull = function(a) { return a === null; }; +var assertNotNull = function(a) { return a !== null; }; +var assertThrows = function(f) { return __redline_call(f); }; +var assertThrowsEquals = function(f) { return __redline_call(f); }; +var assertThrowsAtRuntime = function(f) { return __redline_call(f); }; +var assertThrowsAsync = function(p) { if (p && p.then) p.then(__redline_noop, __redline_noop); return p; }; +var assertDoesNotThrow = function(f) { return __redline_call(f); }; +var assertEarlyError = function(s) { try { new Function(s); } catch (e) {} }; +var assertException = __redline_call; +var assertUnreachable = __redline_noop; +var assertContains = function(a, b) { return b && b.indexOf && b.indexOf(a) >= 0; }; +var assertMatches = function(r, s) { return r && r.test && r.test(s); }; +var assertInstanceof = function(o, c) { return o instanceof c; }; +var assertPromiseResult = function(p, f, r) { + if (p && p.then) p.then(typeof f === "function" ? f : __redline_noop, typeof r === "function" ? r : __redline_noop); + return p; +}; +var assertOptimized = __redline_noop; +var assertUnoptimized = __redline_noop; +var assertMaglevved = __redline_noop; +var assertNotMaglevved = __redline_noop; +var fail = __redline_noop; +var failWithMessage = __redline_noop; +var isNeverOptimize = function() { return false; }; +var isNeverOptimizeLiteMode = function() { return false; }; +var isLazy = function() { return false; }; +var isInterpreted = function(f) { return %ActiveTierIsIgnition(f); }; +var isBaseline = function(f) { return %ActiveTierIsSparkplug(f); }; +var isUnoptimized = function(f) { return !%ActiveTierIsMaglev(f) && !%ActiveTierIsTurbofan(f); }; +var isOptimized = function(f) { return %ActiveTierIsMaglev(f) || %ActiveTierIsTurbofan(f); }; +var isMaglevved = function(f) { return %ActiveTierIsMaglev(f); }; +var isTurboFanned = function(f) { return %ActiveTierIsTurbofan(f); }; +var topFrameIsInterpreted = function() { return false; }; +var topFrameIsBaseline = function() { return false; }; +var topFrameIsMaglevved = function() { return false; }; +var topFrameIsTurboFanned = function() { return false; }; +var willBeMaglevved = function() { return true; }; +var willBeTurbofanned = function() { return true; }; +var prettyPrinted = function(v) { try { return String(v); } catch (e) { return ""; } }; +var deepEquals = function(a, b) { return a == b; }; +var promiseTestChain = Promise.resolve(); +var MjsUnitAssertionError = function(m) { this.message = m; }; +var load = __redline_noop; +var quit = __redline_noop; +var testRunner = { quit: __redline_noop }; +try { if (typeof d8 === "object" && d8.file) d8.file.execute = __redline_noop; } catch (e) {} +)JS"; + +} // namespace + +std::string_view DefaultPrelude() { return kDefaultPrelude; } + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/prelude.h b/deps/v8/experimental/redline/engine/prelude.h new file mode 100644 index 000000000000..33beb560c853 --- /dev/null +++ b/deps/v8/experimental/redline/engine/prelude.h @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_ENGINE_PRELUDE_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_PRELUDE_H_ + +#include <string_view> + +namespace redline { + +// JavaScript prepended to every program when it is executed (never part of +// the mutable program itself). The default prelude defines the mjsunit +// assertion API as non-throwing stubs so that imported mjsunit tests and +// their descendants keep running (and covering code) instead of failing on +// the first assertion. +std::string_view DefaultPrelude(); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_PRELUDE_H_ diff --git a/deps/v8/experimental/redline/engine/shared_coverage.cc b/deps/v8/experimental/redline/engine/shared_coverage.cc new file mode 100644 index 000000000000..587f753123b0 --- /dev/null +++ b/deps/v8/experimental/redline/engine/shared_coverage.cc @@ -0,0 +1,179 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/shared_coverage.h" + +#include <cstring> + +#include "experimental/redline/base/log.h" + +namespace redline { + +bool SharedCoverage::Initialize(uint32_t num_edges, uint32_t bitmap_size, + std::string* error) { + std::scoped_lock<std::mutex> lock(flaky_mutex_); + if (words_ != 0) { + if (num_edges != num_edges_ || bitmap_size != words_ * 8) { + *error = StringPrintf( + "target reports %u edges but the session was started with %u; " + "are all workers running the same d8?", + num_edges, num_edges_); + return false; + } + return true; + } + if (num_edges == 0 || bitmap_size == 0 || bitmap_size % 8 != 0) { + *error = "invalid coverage bitmap geometry"; + return false; + } + num_edges_ = num_edges; + uint32_t words = bitmap_size / 8; + virgin_ = std::make_unique<std::atomic<uint64_t>[]>(words); + crash_virgin_ = std::make_unique<std::atomic<uint64_t>[]>(words); + for (uint32_t i = 0; i < words; i++) { + virgin_[i].store(~uint64_t{0}, std::memory_order_relaxed); + crash_virgin_[i].store(~uint64_t{0}, std::memory_order_relaxed); + } + // Edge 0 is never reported; bits beyond num_edges never get set. + virgin_[0].fetch_and(~uint64_t{1}, std::memory_order_relaxed); + crash_virgin_[0].fetch_and(~uint64_t{1}, std::memory_order_relaxed); + uint32_t tail_bits = (num_edges + 1) % 64; + if (tail_bits != 0) { + uint64_t tail_mask = (uint64_t{1} << tail_bits) - 1; + virgin_[words - 1].fetch_and(tail_mask, std::memory_order_relaxed); + crash_virgin_[words - 1].fetch_and(tail_mask, std::memory_order_relaxed); + } + words_ = words; // publishes the state (last) + return true; +} + +double SharedCoverage::coverage_fraction() const { + if (num_edges_ == 0) { + return 0.0; + } + // Suppressed flaky edges were claimed but never reached deterministically; + // they are not coverage. + uint64_t found = found_edges(); + uint64_t suppressed = suppressed_flaky_edges(); + found = found > suppressed ? found - suppressed : 0; + return static_cast<double>(found) / static_cast<double>(num_edges_ + 1); +} + +std::vector<uint32_t> SharedCoverage::ClaimNewEdges(const uint8_t* bitmap) { + std::vector<uint32_t> claimed; + uint32_t count = 0; + for (uint32_t w = 0; w < words_; w++) { + uint64_t current; + memcpy(¤t, bitmap + static_cast<size_t>(w) * 8, 8); + if (current == 0) { + continue; + } + uint64_t fresh = current & virgin_[w].load(std::memory_order_relaxed); + if (fresh == 0) { + continue; + } + // Clear the bits; whatever was still set in the old value is ours. + uint64_t old = virgin_[w].fetch_and(~fresh, std::memory_order_acq_rel); + uint64_t mine = old & fresh; + while (mine != 0) { + uint32_t bit = static_cast<uint32_t>(__builtin_ctzll(mine)); + claimed.push_back(w * 64 + bit); + mine &= mine - 1; + count++; + } + } + if (count != 0) { + found_edges_.fetch_add(count, std::memory_order_relaxed); + } + return claimed; +} + +bool SharedCoverage::HasNewEdges(const uint8_t* bitmap) const { + for (uint32_t w = 0; w < words_; w++) { + uint64_t current; + memcpy(¤t, bitmap + static_cast<size_t>(w) * 8, 8); + if (current == 0) { + continue; + } + if ((current & virgin_[w].load(std::memory_order_relaxed)) != 0) { + return true; + } + } + return false; +} + +void SharedCoverage::Release(const std::vector<uint32_t>& edges) { + uint32_t count = 0; + for (uint32_t edge : edges) { + if (edge == 0 || edge > num_edges_) { + continue; + } + uint64_t bit = uint64_t{1} << (edge % 64); + uint64_t old = virgin_[edge / 64].fetch_or(bit, std::memory_order_acq_rel); + if ((old & bit) == 0) { + count++; + } + } + if (count != 0) { + found_edges_.fetch_sub(count, std::memory_order_relaxed); + } +} + +void SharedCoverage::MarkSeen(const std::vector<uint32_t>& edges) { + uint32_t count = 0; + for (uint32_t edge : edges) { + if (edge == 0 || edge > num_edges_) { + continue; + } + uint64_t bit = uint64_t{1} << (edge % 64); + uint64_t old = + virgin_[edge / 64].fetch_and(~bit, std::memory_order_acq_rel); + if ((old & bit) != 0) { + count++; + } + } + if (count != 0) { + found_edges_.fetch_add(count, std::memory_order_relaxed); + } +} + +bool SharedCoverage::IsSeen(uint32_t edge) const { + if (edge == 0 || edge > num_edges_) { + return true; + } + uint64_t bit = uint64_t{1} << (edge % 64); + return (virgin_[edge / 64].load(std::memory_order_relaxed) & bit) == 0; +} + +bool SharedCoverage::ClaimNewCrashEdges(const uint8_t* bitmap) { + bool any = false; + for (uint32_t w = 0; w < words_; w++) { + uint64_t current; + memcpy(¤t, bitmap + static_cast<size_t>(w) * 8, 8); + if (current == 0) { + continue; + } + uint64_t fresh = current & crash_virgin_[w].load(std::memory_order_relaxed); + if (fresh == 0) { + continue; + } + uint64_t old = + crash_virgin_[w].fetch_and(~fresh, std::memory_order_acq_rel); + if ((old & fresh) != 0) { + any = true; + } + } + return any; +} + +bool SharedCoverage::RecordFlaky(uint32_t edge, int threshold) { + std::scoped_lock<std::mutex> lock(flaky_mutex_); + int count = ++flaky_counts_[edge]; + if (count == threshold) { + suppressed_.fetch_add(1, std::memory_order_relaxed); + } + return count >= threshold; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/shared_coverage.h b/deps/v8/experimental/redline/engine/shared_coverage.h new file mode 100644 index 000000000000..b29115c9c79d --- /dev/null +++ b/deps/v8/experimental/redline/engine/shared_coverage.h @@ -0,0 +1,84 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_ENGINE_SHARED_COVERAGE_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_SHARED_COVERAGE_H_ + +#include <atomic> +#include <cstdint> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <vector> + +namespace redline { + +// Coverage bookkeeping shared by all workers of a fuzzing session: which +// edges some corpus program already reaches ("virgin bits", one bit per +// edge, set while unseen), which edges some crash already reached, and how +// often each edge failed a determinism check. +// +// Every worker owns a target process with its own bitmap (CoverageMap); the +// bitmaps are scanned against this shared state. Claiming is atomic per +// 64-bit word, so two workers that reach the same new edge at the same time +// never both consider it new. +class SharedCoverage { + public: + SharedCoverage() = default; + SharedCoverage(const SharedCoverage&) = delete; + SharedCoverage& operator=(const SharedCoverage&) = delete; + + // Called by every worker after its target started. The first call sizes + // the state; later calls only check that the target is the same binary. + bool Initialize(uint32_t num_edges, uint32_t bitmap_size, std::string* error); + bool initialized() const { return words_ != 0; } + + uint32_t num_edges() const { return num_edges_; } + uint32_t found_edges() const { + return found_edges_.load(std::memory_order_relaxed); + } + // found_edges() / (num_edges() + 1), the ratio Fuzzilli reports. + double coverage_fraction() const; + + // Claims every edge set in `bitmap` that nobody claimed before and + // returns them (strictly increasing). The caller is now responsible for + // these edges: it must either add a program for them or Release() them. + std::vector<uint32_t> ClaimNewEdges(const uint8_t* bitmap); + // Whether `bitmap` has unclaimed edges, without claiming them. + bool HasNewEdges(const uint8_t* bitmap) const; + // Gives claimed edges back (the program reaching them was not kept). + void Release(const std::vector<uint32_t>& edges); + // Marks edges as claimed without a program (state import, flaky edges). + void MarkSeen(const std::vector<uint32_t>& edges); + // Whether `edge` is currently claimed. + bool IsSeen(uint32_t edge) const; + + // Like ClaimNewEdges for the crash bits; returns whether the crash reached + // edges no earlier crash reached (i.e. it is probably a new crash). + bool ClaimNewCrashEdges(const uint8_t* bitmap); + + // Records that `edge` was reached by a program but not reproducibly. + // Returns true if the edge has now failed `threshold` times: the caller + // should keep it claimed (so that it stops costing determinism re-runs) + // instead of releasing it. + bool RecordFlaky(uint32_t edge, int threshold); + uint64_t suppressed_flaky_edges() const { + return suppressed_.load(std::memory_order_relaxed); + } + + private: + uint32_t num_edges_ = 0; + uint32_t words_ = 0; + std::unique_ptr<std::atomic<uint64_t>[]> virgin_; + std::unique_ptr<std::atomic<uint64_t>[]> crash_virgin_; + std::atomic<uint32_t> found_edges_{0}; + std::mutex flaky_mutex_; + std::unordered_map<uint32_t, int> flaky_counts_; + std::atomic<uint64_t> suppressed_{0}; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_SHARED_COVERAGE_H_ diff --git a/deps/v8/experimental/redline/engine/stages.cc b/deps/v8/experimental/redline/engine/stages.cc new file mode 100644 index 000000000000..b8d41e205adc --- /dev/null +++ b/deps/v8/experimental/redline/engine/stages.cc @@ -0,0 +1,355 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/engine/stages.h" + +#include <cstdlib> +#include <string> +#include <vector> + +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { + +constexpr std::string_view kStageNames[kNumStages] = { + "pick", "prefix", "mutate", "check", "minimize", "publish"}; + +struct TriggerInfo { + CaptureTrigger trigger; + std::string_view name; + bool stages[kNumStages]; // pick, prefix, mutate, check, minimize, publish +}; + +constexpr TriggerInfo kTriggers[] = { + {CaptureTrigger::kTimeout, + "timeout", + {false, false, true, true, true, false}}, + {CaptureTrigger::kCrash, + "crash", + {false, false, true, false, false, false}}, + {CaptureTrigger::kFailed, + "failed", + {false, false, true, false, false, false}}, + {CaptureTrigger::kInvalid, + "invalid", + {false, false, true, false, false, false}}, + {CaptureTrigger::kNoop, "noop", {false, true, true, false, false, false}}, + {CaptureTrigger::kInteresting, + "interesting", + {false, false, true, false, false, false}}, + {CaptureTrigger::kFlaky, + "flaky", + {false, false, false, true, false, false}}, + {CaptureTrigger::kRejected, + "rejected", + {false, false, false, false, true, false}}, +}; + +const TriggerInfo& Info(CaptureTrigger trigger) { + for (const TriggerInfo& t : kTriggers) { + if (t.trigger == trigger) { + return t; + } + } + return kTriggers[0]; +} + +std::vector<std::string> SplitList(std::string_view text) { + std::vector<std::string> out; + size_t start = 0; + while (start <= text.size()) { + size_t comma = text.find(',', start); + if (comma == std::string_view::npos) { + comma = text.size(); + } + if (comma > start) { + out.emplace_back(text.substr(start, comma - start)); + } + start = comma + 1; + } + return out; +} + +std::string TriggerList() { + std::string out; + for (const TriggerInfo& t : kTriggers) { + if (!out.empty()) { + out += ", "; + } + out += t.name; + } + return out; +} + +} // namespace + +std::string_view StageName(Stage stage) { + return kStageNames[static_cast<int>(stage)]; +} + +bool ParseStage(std::string_view name, Stage* out) { + for (int i = 0; i < kNumStages; i++) { + if (kStageNames[i] == name) { + *out = static_cast<Stage>(i); + return true; + } + } + return false; +} + +std::string_view CaptureTriggerName(CaptureTrigger trigger) { + return Info(trigger).name; +} + +bool ParseCaptureTrigger(std::string_view name, CaptureTrigger* out) { + for (const TriggerInfo& t : kTriggers) { + if (t.name == name) { + *out = t.trigger; + return true; + } + } + return false; +} + +bool CaptureTriggerApplies(Stage stage, CaptureTrigger trigger) { + return Info(trigger).stages[static_cast<int>(stage)]; +} + +// --- CaptureRule +// -------------------------------------------------------------- + +bool CaptureRule::Matches(CaptureTrigger trigger, + std::string_view mutator) const { + bool wanted = false; + for (CaptureTrigger t : on) { + if (t == trigger) { + wanted = true; + break; + } + } + if (!wanted) { + return false; + } + if (mutators.empty()) { + return true; + } + for (const std::string& m : mutators) { + if (m == mutator) { + return true; + } + } + return false; +} + +namespace { + +bool AddTriggers(Stage stage, const std::vector<std::string>& names, + CaptureRule* out, std::string* error) { + for (const std::string& name : names) { + CaptureTrigger trigger; + if (!ParseCaptureTrigger(name, &trigger)) { + *error = "unknown capture trigger '" + name + + "' (known: " + TriggerList() + ")"; + return false; + } + if (!CaptureTriggerApplies(stage, trigger)) { + *error = "capture trigger '" + name + "' does not apply to the " + + std::string(StageName(stage)) + " stage"; + return false; + } + out->on.push_back(trigger); + } + return true; +} + +} // namespace + +// static +bool CaptureRule::FromJson(Stage stage, const JsonValue& value, + CaptureRule* out, std::string* error) { + *out = CaptureRule(); + if (value.is_null()) { + return true; + } + if (!value.is_object()) { + *error = + "\"capture\" must be {\"on\": [trigger, ...], \"mutators\": [name, " + "...], \"max\": N}"; + return false; + } + for (const auto& [key, member] : value.as_object()) { + if (key == "on") { + std::vector<std::string> names; + if (member.is_string()) { + names = SplitList(member.as_string()); + } else if (member.is_array()) { + for (const JsonValue& v : member.as_array()) { + if (!v.is_string()) { + *error = "\"capture.on\" must be a list of trigger names"; + return false; + } + names.push_back(v.as_string()); + } + } else { + *error = "\"capture.on\" must be a list of trigger names"; + return false; + } + if (!AddTriggers(stage, names, out, error)) { + return false; + } + } else if (key == "mutators") { + if (!member.is_array()) { + *error = "\"capture.mutators\" must be a list of mutator names"; + return false; + } + for (const JsonValue& v : member.as_array()) { + if (!v.is_string()) { + *error = "\"capture.mutators\" must be a list of mutator names"; + return false; + } + out->mutators.push_back(v.as_string()); + } + // An empty list (no filter) is what the recorded configuration says + // for every stage; a real filter only makes sense where mutators run. + if (stage != Stage::kMutate && !out->mutators.empty()) { + *error = "\"capture.mutators\" only applies to the mutate stage"; + return false; + } + } else if (key == "max") { + if (!member.is_number() || member.as_number() < 0) { + *error = "\"capture.max\" must be a non-negative number"; + return false; + } + out->max = static_cast<int>(member.as_int()); + } else { + *error = "unknown key \"" + key + + "\" in \"capture\" (known: on, mutators, max)"; + return false; + } + } + return true; +} + +// static +bool CaptureRule::FromFlag(std::string_view text, Stage* stage, + CaptureRule* out, std::string* error) { + // STAGE:TRIGGERS[:MUTATORS][:MAX] + std::vector<std::string> parts; + size_t start = 0; + while (true) { + size_t colon = text.find(':', start); + parts.emplace_back(text.substr(start, colon == std::string_view::npos + ? std::string_view::npos + : colon - start)); + if (colon == std::string_view::npos) { + break; + } + start = colon + 1; + } + if (parts.size() < 2 || parts.size() > 4) { + *error = + "--capture expects " + "STAGE:TRIGGER[,TRIGGER..][:MUTATOR[,MUTATOR..]][:MAX], got '" + + std::string(text) + "'"; + return false; + } + if (!ParseStage(parts[0], stage)) { + *error = "--capture: unknown stage '" + parts[0] + + "' (known: pick, prefix, mutate, check, minimize, publish)"; + return false; + } + *out = CaptureRule(); + if (!AddTriggers(*stage, SplitList(parts[1]), out, error)) { + return false; + } + // The optional parts: a mutator list and/or a number, in that order; a + // part that is all digits is the number. + for (size_t i = 2; i < parts.size(); i++) { + const std::string& part = parts[i]; + bool number = !part.empty() && + part.find_first_not_of("0123456789") == std::string::npos; + if (number) { + out->max = static_cast<int>(strtol(part.c_str(), nullptr, 10)); + } else if (*stage == Stage::kMutate) { + out->mutators = SplitList(part); + } else { + *error = "--capture: mutator names only apply to the mutate stage ('" + + part + "')"; + return false; + } + } + return true; +} + +std::string CaptureRule::ToJson() const { + JsonObject o; + std::vector<std::string> names; + names.reserve(on.size()); + for (CaptureTrigger t : on) { + names.emplace_back(CaptureTriggerName(t)); + } + o.AddArray("on", names); + o.AddArray("mutators", mutators); + o.Add("max", max); + return o.ToString(); +} + +// --- StageTable +// --------------------------------------------------------------- + +std::string StageTable::ToJson() const { + JsonObject o; + for (int i = 0; i < kNumStages; i++) { + StageStats::Snapshot s = stats[i].snapshot(); + JsonObject row; + row.Add("invocations", s.invocations) + .Add("executions", s.executions) + .Add("time_us", s.time_us) + .Add("exec_time_us", s.exec_time_us) + .Add("timeouts", s.timeouts) + .Add("successes", s.successes); + o.AddRaw(kStageNames[i], row.ToString()); + } + return o.ToString(); +} + +std::string StageTable::Format(const bool enabled[kNumStages]) const { + StageStats::Snapshot rows[kNumStages]; + uint64_t total_execs = 0, total_time = 0, total_timeouts = 0; + for (int i = 0; i < kNumStages; i++) { + rows[i] = stats[i].snapshot(); + total_execs += rows[i].executions; + total_time += rows[i].time_us; + total_timeouts += rows[i].timeouts; + } + auto share = [](uint64_t part, uint64_t total) { + return total == 0 + ? 0.0 + : 100.0 * static_cast<double>(part) / static_cast<double>(total); + }; + std::string out = "stages\n"; + out += StringPrintf(" %-9s %12s %12s %7s %10s %7s %9s %7s %9s\n", "stage", + "invoked", "execs", "execs%", "time s", "time%", + "timeouts", "tmo%", "success%"); + for (int i = 0; i < kNumStages; i++) { + if (!enabled[i]) { + continue; + } + const StageStats::Snapshot& s = rows[i]; + out += StringPrintf( + " %-9.*s %12llu %12llu %6.1f%% %10.1f %6.1f%% %9llu %6.1f%% %8.1f%%\n", + static_cast<int>(kStageNames[i].size()), kStageNames[i].data(), + static_cast<unsigned long long>(s.invocations), + static_cast<unsigned long long>(s.executions), + share(s.executions, total_execs), static_cast<double>(s.time_us) / 1e6, + share(s.time_us, total_time), + static_cast<unsigned long long>(s.timeouts), + share(s.timeouts, total_timeouts), share(s.successes, s.invocations)); + } + return out; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/engine/stages.h b/deps/v8/experimental/redline/engine/stages.h new file mode 100644 index 000000000000..bbd23be64d58 --- /dev/null +++ b/deps/v8/experimental/redline/engine/stages.h @@ -0,0 +1,136 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The stages of a worker's loop, as an assembly line: +// +// pick -> prefix -> mutate -> check -> minimize -> publish +// +// pick a corpus program is chosen (selection.seeds) +// prefix fresh value declarations are put in front of it +// mutate a mutator is chosen (selection.mutators) and applied, the +// result is syntax-checked and executed; repeated along a chain +// check a result with new edges is re-executed until its edges are +// known to be deterministic +// minimize the surviving program is reduced against those edges +// publish it is added to the corpus and saved +// +// Every stage has the same three knobs next to its own parameters +// (StageOptions): `log` (one JSONL event per occurrence), `capture` (save +// the programs that went through the stage when a trigger fires) and +// `stats` (a row in the stages table). The parameters themselves live in +// FuzzConfig; the "stages" block of the configuration groups them by stage. +// +// StageStats are the per-stage counters a session keeps, reported in the +// `stats` event and in the periodic tables as shares of executions, time +// and timeouts. + +#ifndef V8_EXPERIMENTAL_REDLINE_ENGINE_STAGES_H_ +#define V8_EXPERIMENTAL_REDLINE_ENGINE_STAGES_H_ + +#include <atomic> +#include <cstdint> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/base/json.h" +#include "experimental/redline/base/json_parser.h" + +namespace redline { + +enum class Stage { kPick, kPrefix, kMutate, kCheck, kMinimize, kPublish }; +constexpr int kNumStages = 6; + +std::string_view StageName(Stage stage); +// Returns false for an unknown name. +bool ParseStage(std::string_view name, Stage* out); + +// What can trigger a capture. Not every trigger applies to every stage: +// mutate timeout, crash, failed, invalid, noop, interesting +// check flaky (edges lost), timeout +// minimize rejected (result failed verification), timeout +// prefix noop +// An inapplicable trigger is a configuration error. +enum class CaptureTrigger { + kTimeout, + kCrash, + kFailed, + kInvalid, + kNoop, + kInteresting, + kFlaky, + kRejected +}; + +std::string_view CaptureTriggerName(CaptureTrigger trigger); +bool ParseCaptureTrigger(std::string_view name, CaptureTrigger* out); +bool CaptureTriggerApplies(Stage stage, CaptureTrigger trigger); + +// "Save the programs of this stage when one of `on` happens" (for the +// mutate stage optionally only for the listed mutators), at most `max` +// times per session. Written to OUT/captures/<stage>/. +struct CaptureRule { + std::vector<CaptureTrigger> on; + std::vector<std::string> mutators; // empty: any + int max = 50; + + bool enabled() const { return !on.empty(); } + bool Matches(CaptureTrigger trigger, std::string_view mutator) const; + // {"on": [...], "mutators": [...], "max": N}; `stage` is used to check + // that the triggers apply. Flag form: + // "STAGE:TRIGGER[,TRIGGER..][:MUTATOR[,MUTATOR..]][:MAX]". + static bool FromJson(Stage stage, const JsonValue& value, CaptureRule* out, + std::string* error); + static bool FromFlag(std::string_view text, Stage* stage, CaptureRule* out, + std::string* error); + std::string ToJson() const; +}; + +// The three knobs every stage has. +struct StageOptions { + bool events = false; // "log": "events" -> one JSONL event per occurrence + CaptureRule capture; + bool stats = true; // a row in the stages table +}; + +// Per-stage counters. `successes` means: pick/prefix/publish - completed; +// mutate - executed results with new edges; check - candidates whose edges +// survived; minimize - accepted reductions. +struct StageStats { + std::atomic<uint64_t> invocations{0}; // times the stage ran + std::atomic<uint64_t> executions{0}; // target executions it caused + std::atomic<uint64_t> time_us{0}; // wall time inside the stage (all workers) + std::atomic<uint64_t> exec_time_us{0}; // ... of which target execution time + std::atomic<uint64_t> timeouts{0}; // executions that timed out + std::atomic<uint64_t> successes{0}; + + struct Snapshot { + uint64_t invocations, executions, time_us, exec_time_us, timeouts, + successes; + }; + Snapshot snapshot() const { + return {invocations.load(), executions.load(), time_us.load(), + exec_time_us.load(), timeouts.load(), successes.load()}; + } +}; + +// All stages of one session. +struct StageTable { + StageStats stats[kNumStages]; + + StageStats& operator[](Stage stage) { return stats[static_cast<int>(stage)]; } + const StageStats& operator[](Stage stage) const { + return stats[static_cast<int>(stage)]; + } + + // {"pick": {"invocations": ..., ...}, ...} for the stats event. + std::string ToJson() const; + // A table with shares: % of executions, % of time, % of timeouts, + // success rate. `enabled` selects the rows (StageOptions::stats). + std::string Format(const bool enabled[kNumStages]) const; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_ENGINE_STAGES_H_ diff --git a/deps/v8/experimental/redline/exec/coverage.cc b/deps/v8/experimental/redline/exec/coverage.cc new file mode 100644 index 000000000000..294c49ba2746 --- /dev/null +++ b/deps/v8/experimental/redline/exec/coverage.cc @@ -0,0 +1,262 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/exec/coverage.h" + +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <algorithm> +#include <cerrno> +#include <cstring> + +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { + +inline bool GetBit(const uint8_t* bits, uint32_t index) { + return (bits[index / 8] >> (index % 8)) & 1; +} + +inline void SetBit(uint8_t* bits, uint32_t index) { + bits[index / 8] |= static_cast<uint8_t>(1u << (index % 8)); +} + +inline void ClearBit(uint8_t* bits, uint32_t index) { + bits[index / 8] &= static_cast<uint8_t>(~(1u << (index % 8))); +} + +} // namespace + +// static +std::unique_ptr<CoverageMap> CoverageMap::Create(int id, std::string* error) { + std::string name = + StringPrintf("/shm_id_%d_%d", static_cast<int>(getpid()), id); + shm_unlink(name.c_str()); + int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, + S_IRUSR | S_IWUSR); + if (fd < 0) { + *error = + StringPrintf("shm_open(%s) failed: %s", name.c_str(), strerror(errno)); + return nullptr; + } + if (ftruncate(fd, static_cast<off_t>(kShmSize)) != 0) { + *error = + StringPrintf("ftruncate(%s) failed: %s", name.c_str(), strerror(errno)); + close(fd); + shm_unlink(name.c_str()); + return nullptr; + } + void* mapping = + mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + if (mapping == MAP_FAILED) { + *error = StringPrintf("mmap(%s) failed: %s", name.c_str(), strerror(errno)); + shm_unlink(name.c_str()); + return nullptr; + } + memset(mapping, 0, kShmSize); + return std::unique_ptr<CoverageMap>(new CoverageMap(id, name, mapping)); +} + +CoverageMap::CoverageMap(int id, std::string shm_name, void* mapping) + : id_(id), + shm_name_(std::move(shm_name)), + shmem_(static_cast<ShmemData*>(mapping)) {} + +CoverageMap::~CoverageMap() { + munmap(shmem_, kShmSize); + shm_unlink(shm_name_.c_str()); +} + +bool CoverageMap::FinishInitialization(std::string* error) { + uint32_t num_edges = shmem_->num_edges; + if (num_edges == 0) { + *error = + "The target did not publish an edge count; is it built with " + "coverage instrumentation (sanitizer_coverage_flags) and " + "v8_fuzzilli=true?"; + return false; + } + // Index 0 is unused; the bitmap must hold indices 0..num_edges. + if (num_edges > kMaxEdges) { + *error = StringPrintf("Too many edges (%u) for the shared memory region", + num_edges); + return false; + } + if (num_edges_ != 0 && num_edges_ != num_edges) { + *error = StringPrintf( + "The target changed its edge count (%u -> %u); mixing binaries?", + num_edges_, num_edges); + return false; + } + if (num_edges_ == num_edges) { + return true; + } + + num_edges_ = num_edges; + uint32_t bitmap_size = (num_edges + 1 + 7) / 8; + // Round up to a multiple of 8 bytes so that the scans can use 64-bit + // words. + bitmap_size += 7 - ((bitmap_size - 1) % 8); + bitmap_size_ = bitmap_size; + virgin_bits_.assign(bitmap_size_, 0xff); + crash_bits_.assign(bitmap_size_, 0xff); + ResetState(); + return true; +} + +double CoverageMap::coverage_fraction() const { + if (num_edges_ == 0) { + return 0.0; + } + return static_cast<double>(found_edges_) / + static_cast<double>(num_edges_ + 1); +} + +void CoverageMap::ClearBitmap() { + if (bitmap_size_ == 0) { + return; + } + memset(shm_edges(), 0, bitmap_size_); +} + +uint32_t CoverageMap::ScanNewEdges(uint8_t* virgin_bits, + std::vector<uint32_t>* out) { + uint32_t count = 0; + const uint8_t* edges = shm_edges(); + for (uint32_t offset = 0; offset < bitmap_size_; offset += 8) { + uint64_t current, virgin; + memcpy(¤t, edges + offset, 8); + memcpy(&virgin, virgin_bits + offset, 8); + uint64_t fresh = current & virgin; + if (fresh == 0) { + continue; + } + while (fresh != 0) { + uint32_t bit = static_cast<uint32_t>(__builtin_ctzll(fresh)); + uint32_t index = offset * 8 + bit; + ClearBit(virgin_bits, index); + if (out != nullptr) { + out->push_back(index); + } + count++; + fresh &= fresh - 1; + } + } + return count; +} + +std::vector<uint32_t> CoverageMap::EvaluateNewEdges() { + std::vector<uint32_t> new_edges; + if (bitmap_size_ == 0) { + return new_edges; + } + found_edges_ += ScanNewEdges(virgin_bits_.data(), &new_edges); + return new_edges; +} + +bool CoverageMap::EvaluateCrash() { + if (bitmap_size_ == 0) { + return false; + } + return ScanNewEdges(crash_bits_.data(), nullptr) > 0; +} + +bool CoverageMap::AllEdgesSet(const std::vector<uint32_t>& edges) const { + for (uint32_t index : edges) { + if (index == 0 || index > num_edges_ || !GetBit(shm_edges(), index)) { + return false; + } + } + return true; +} + +std::vector<uint32_t> CoverageMap::MissingEdges( + const std::vector<uint32_t>& edges) const { + std::vector<uint32_t> missing; + for (uint32_t index : edges) { + if (index == 0 || index > num_edges_ || !GetBit(shm_edges(), index)) { + missing.push_back(index); + } + } + return missing; +} + +std::vector<uint32_t> CoverageMap::CurrentEdges() const { + std::vector<uint32_t> result; + const uint8_t* edges = shm_edges(); + for (uint32_t offset = 0; offset < bitmap_size_; offset += 8) { + uint64_t current; + memcpy(¤t, edges + offset, 8); + while (current != 0) { + uint32_t bit = static_cast<uint32_t>(__builtin_ctzll(current)); + uint32_t index = offset * 8 + bit; + if (index != 0 && index <= num_edges_) { + result.push_back(index); + } + current &= current - 1; + } + } + return result; +} + +uint32_t CoverageMap::CountCurrentEdges() const { + uint32_t count = 0; + const uint8_t* edges = shm_edges(); + for (uint32_t offset = 0; offset < bitmap_size_; offset += 8) { + uint64_t current; + memcpy(¤t, edges + offset, 8); + count += static_cast<uint32_t>(__builtin_popcountll(current)); + } + if (count > 0 && GetBit(edges, 0)) { + count--; + } + return count; +} + +void CoverageMap::ForgetEdges(const std::vector<uint32_t>& edges) { + for (uint32_t index : edges) { + if (index == 0 || index > num_edges_) { + continue; + } + if (!GetBit(virgin_bits_.data(), index)) { + SetBit(virgin_bits_.data(), index); + found_edges_--; + } + } +} + +void CoverageMap::MarkSeen(const std::vector<uint32_t>& edges) { + for (uint32_t index : edges) { + if (index == 0 || index > num_edges_) { + continue; + } + if (GetBit(virgin_bits_.data(), index)) { + ClearBit(virgin_bits_.data(), index); + found_edges_++; + } + } +} + +void CoverageMap::ResetState() { + if (bitmap_size_ == 0) { + return; + } + std::fill(virgin_bits_.begin(), virgin_bits_.end(), 0xff); + std::fill(crash_bits_.begin(), crash_bits_.end(), 0xff); + ClearBit(virgin_bits_.data(), 0); + ClearBit(crash_bits_.data(), 0); + for (uint32_t index = num_edges_ + 1; index < bitmap_size_ * 8; index++) { + ClearBit(virgin_bits_.data(), index); + ClearBit(crash_bits_.data(), index); + } + found_edges_ = 0; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/exec/coverage.h b/deps/v8/experimental/redline/exec/coverage.h new file mode 100644 index 000000000000..f481eefdd4d6 --- /dev/null +++ b/deps/v8/experimental/redline/exec/coverage.h @@ -0,0 +1,130 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_EXEC_COVERAGE_H_ +#define V8_EXPERIMENTAL_REDLINE_EXEC_COVERAGE_H_ + +#include <cstdint> +#include <memory> +#include <string> +#include <vector> + +namespace redline { + +// The edge coverage bitmap shared with one target process, plus the +// bookkeeping of which edges have been seen so far ("virgin bits"). +// +// Layout and semantics are those of Fuzzilli's libcoverage / V8's +// src/fuzzilli/cov.cc: a POSIX shared memory object named +// "shm_id_<pid>_<id>" of kShmSize bytes starting with a uint32 edge count +// written by the target at startup, followed by one bit per edge. Edge +// indices start at 1; index 0 is never reported. The target sets a bit the +// first time an edge executes within a REPRL iteration and resets its +// guards at the end of every iteration, so the parent must clear the bitmap +// before each execution and read it afterwards. +// +// Not thread-safe; one instance per ReprlChild. +class CoverageMap { + public: + // Must match SHM_SIZE in src/fuzzilli/cov.cc: the target maps this many + // bytes, so a smaller region would make it fault. + static constexpr size_t kShmSize = 0x200000; + // The 4-byte num_edges header leaves kShmSize - 4 bytes for the bitmap, + // and scans read 8-byte words, so the usable bitmap is the largest multiple + // of 8 bytes that fits after the header. + static constexpr uint32_t kMaxEdges = static_cast<uint32_t>( + ((kShmSize - sizeof(uint32_t)) & ~size_t{7}) * 8 - 1); + + // Creates the shared memory object; `id` must be unique within this + // process (one per target child). + static std::unique_ptr<CoverageMap> Create(int id, std::string* error); + ~CoverageMap(); + CoverageMap(const CoverageMap&) = delete; + CoverageMap& operator=(const CoverageMap&) = delete; + + // Value for the SHM_ID environment variable of the target. + const std::string& shm_name() const { return shm_name_; } + int id() const { return id_; } + + // Reads the edge count published by the target. Must be called after the + // target has started (i.e. after the REPRL handshake) and before any + // evaluation. Returns false if the target did not publish an edge count, + // which means it is not instrumented. + bool FinishInitialization(std::string* error); + bool initialized() const { return num_edges_ != 0; } + + // Number of instrumented edges reported by the target. + uint32_t num_edges() const { return num_edges_; } + // Number of distinct edges discovered so far (through EvaluateNewEdges). + uint32_t found_edges() const { return found_edges_; } + // found_edges() / (num_edges() + 1): the same ratio Fuzzilli reports. + double coverage_fraction() const; + + // Zeroes the bitmap. Call before every execution. + void ClearBitmap(); + + // Returns the edges set in the bitmap that have never been seen before + // and marks them as seen. Indices are strictly increasing. + std::vector<uint32_t> EvaluateNewEdges(); + + // Like EvaluateNewEdges but against a separate set of bits used for + // crashing executions, so that crash triage does not pollute the regular + // coverage state. Returns true if the crash reached unseen crash edges. + bool EvaluateCrash(); + + // Whether every edge in `edges` is set in the current bitmap. + bool AllEdgesSet(const std::vector<uint32_t>& edges) const; + // The subset of `edges` that is not set in the current bitmap. + std::vector<uint32_t> MissingEdges(const std::vector<uint32_t>& edges) const; + + // All edges currently set in the bitmap (index 0 excluded). + std::vector<uint32_t> CurrentEdges() const; + // Number of edges currently set in the bitmap. + uint32_t CountCurrentEdges() const; + + // Marks `edges` as unseen again (used when edges found by a program turn + // out to be non-deterministic and the program is discarded). + void ForgetEdges(const std::vector<uint32_t>& edges); + + // Imports a set of edges as already seen (e.g. when loading a state). + void MarkSeen(const std::vector<uint32_t>& edges); + + // Resets all bookkeeping to the initial state. + void ResetState(); + + // Raw access to the bitmap written by the target (bitmap_size() bytes, a + // multiple of 8), for coverage bookkeeping shared between several targets + // (see engine/shared_coverage.h). + const uint8_t* bitmap() const { return shm_edges(); } + uint32_t bitmap_size() const { return bitmap_size_; } + + private: + CoverageMap(int id, std::string shm_name, void* mapping); + + // Layout of the shared memory region (libcoverage's shmem_data): the edge + // count followed by the edge bitmap. The bitmap starts right after the + // header, see shm_edges(). + struct ShmemData { + uint32_t num_edges; + }; + uint8_t* shm_edges() { return reinterpret_cast<uint8_t*>(shmem_ + 1); } + const uint8_t* shm_edges() const { + return reinterpret_cast<const uint8_t*>(shmem_ + 1); + } + + uint32_t ScanNewEdges(uint8_t* virgin_bits, std::vector<uint32_t>* out); + + int id_; + std::string shm_name_; + ShmemData* shmem_; + uint32_t num_edges_ = 0; + uint32_t bitmap_size_ = 0; // bytes, multiple of 8 + uint32_t found_edges_ = 0; + std::vector<uint8_t> virgin_bits_; + std::vector<uint8_t> crash_bits_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_EXEC_COVERAGE_H_ diff --git a/deps/v8/experimental/redline/exec/execution.cc b/deps/v8/experimental/redline/exec/execution.cc new file mode 100644 index 000000000000..daf3d3b7399d --- /dev/null +++ b/deps/v8/experimental/redline/exec/execution.cc @@ -0,0 +1,81 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/exec/execution.h" + +#include <cctype> +#include <string_view> + +namespace redline { + +const char* OutcomeName(Outcome outcome) { + switch (outcome) { + case Outcome::kSucceeded: + return "succeeded"; + case Outcome::kFailed: + return "failed"; + case Outcome::kCrashed: + return "crashed"; + case Outcome::kTimedOut: + return "timed_out"; + } + return "unknown"; +} + +namespace { + +// Finds "<Name>Error: ..." in `line` (d8 prints "file:line: TypeError: msg" +// first, then the source line, then the bare "TypeError: msg" + stack). +std::string_view ErrorIn(std::string_view line) { + size_t pos = line.find("Error: "); + if (pos == std::string_view::npos) { + return {}; + } + size_t begin = pos; + while (begin > 0 && + (std::isalnum(static_cast<unsigned char>(line[begin - 1])) || + line[begin - 1] == '_' || line[begin - 1] == '$')) { + begin--; + } + return line.substr(begin); +} + +} // namespace + +std::string Execution::ExceptionSignature() const { + for (const std::string* output : {&stdout_output, &stderr_output}) { + std::string_view rest = *output; + while (!rest.empty()) { + size_t newline = rest.find('\n'); + std::string_view line = rest.substr(0, newline); + std::string_view error = ErrorIn(line); + if (!error.empty()) { + return std::string(error); + } + if (newline == std::string_view::npos) { + break; + } + rest.remove_prefix(newline + 1); + } + } + return std::string(); +} + +bool Execution::IsParseError() const { + if (outcome != Outcome::kFailed) { + return false; + } + std::string signature = ExceptionSignature(); + if (!std::string_view(signature).starts_with("SyntaxError")) { + return false; + } + for (const std::string* output : {&stdout_output, &stderr_output}) { + if (output->find("\n at ") != std::string::npos) { + return false; + } + } + return true; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/exec/execution.h b/deps/v8/experimental/redline/exec/execution.h new file mode 100644 index 000000000000..840960c99b64 --- /dev/null +++ b/deps/v8/experimental/redline/exec/execution.h @@ -0,0 +1,58 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_EXEC_EXECUTION_H_ +#define V8_EXPERIMENTAL_REDLINE_EXEC_EXECUTION_H_ + +#include <cstdint> +#include <string> + +namespace redline { + +// How a script execution in the target ended. The classification follows +// Fuzzilli's so that numbers are directly comparable: +// - kSucceeded: the target exited the REPRL iteration with status 0. +// - kFailed: the script terminated with an uncaught exception (or the +// target reported a non-zero exit code for the iteration). +// - kCrashed: the target process died from a signal. +// - kTimedOut: the execution exceeded the timeout and the target was +// killed. +enum class Outcome : uint8_t { kSucceeded, kFailed, kCrashed, kTimedOut }; + +const char* OutcomeName(Outcome outcome); + +struct Execution { + Outcome outcome = Outcome::kSucceeded; + // Exit code for kSucceeded/kFailed, terminating signal for kCrashed. + int exit_code = 0; + int signal = 0; + // Wall time spent waiting for the target, in microseconds. + uint64_t exec_time_us = 0; + // Output produced by the target during this execution. The "fuzzout" + // channel is what fuzzilli('FUZZILLI_PRINT', ...) writes to; stdout and + // stderr are only captured when enabled on the ReprlChild. + std::string fuzzout; + std::string stdout_output; + std::string stderr_output; + + bool succeeded() const { return outcome == Outcome::kSucceeded; } + bool crashed() const { return outcome == Outcome::kCrashed; } + bool timed_out() const { return outcome == Outcome::kTimedOut; } + + // For failed executions: the uncaught exception as d8 reports it, e.g. + // "TypeError: Cannot read properties of undefined (reading 'length')" + // (the first "<Name>Error: <message>" line of the output, without the + // "file:line:" prefix). Empty if no such line was captured. + std::string ExceptionSignature() const; + + // True if the target rejected the script itself as invalid JavaScript: + // an uncaught SyntaxError reported without any stack frame. (A + // SyntaxError thrown while running, by JSON.parse, new RegExp or eval, + // comes with " at ..." frames.) Needs the output to be captured. + bool IsParseError() const; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_EXEC_EXECUTION_H_ diff --git a/deps/v8/experimental/redline/exec/process_run.cc b/deps/v8/experimental/redline/exec/process_run.cc new file mode 100644 index 000000000000..ac3a09f07276 --- /dev/null +++ b/deps/v8/experimental/redline/exec/process_run.cc @@ -0,0 +1,140 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/exec/process_run.h" + +#include <fcntl.h> +#include <poll.h> +#include <signal.h> +#include <spawn.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <algorithm> +#include <cerrno> +#include <cstring> + +#include "experimental/redline/base/time_util.h" + +namespace redline { + +ProcessResult RunProcess( + const std::string& executable, const std::vector<std::string>& args, + const std::vector<std::pair<std::string, std::string>>& env, + uint64_t timeout_us, size_t max_stderr) { + ProcessResult result; + int err_pipe[2]; + if (pipe2(err_pipe, O_CLOEXEC) != 0) { + result.error = std::string("pipe2: ") + strerror(errno); + return result; + } + + std::vector<std::string> argv_storage; + argv_storage.reserve(args.size() + 1); + argv_storage.push_back(executable); + argv_storage.insert(argv_storage.end(), args.begin(), args.end()); + std::vector<char*> argv; + argv.reserve(argv_storage.size() + 1); + for (std::string& s : argv_storage) { + argv.push_back(s.data()); + } + argv.push_back(nullptr); + std::vector<std::string> env_storage; + env_storage.reserve(env.size()); + for (const auto& [key, value] : env) { + std::string entry = key; + entry += '='; + entry += value; + env_storage.push_back(std::move(entry)); + } + std::vector<char*> envp; + envp.reserve(env_storage.size() + 1); + for (std::string& s : env_storage) { + envp.push_back(s.data()); + } + envp.push_back(nullptr); + + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_init(&actions); + posix_spawn_file_actions_addopen(&actions, STDIN_FILENO, "/dev/null", + O_RDONLY, 0); + posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, "/dev/null", + O_WRONLY, 0); + posix_spawn_file_actions_adddup2(&actions, err_pipe[1], STDERR_FILENO); + + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + sigset_t empty_set; + sigemptyset(&empty_set); + posix_spawnattr_setsigmask(&attr, &empty_set); + sigset_t default_set; + sigfillset(&default_set); + posix_spawnattr_setsigdefault(&attr, &default_set); + posix_spawnattr_setpgroup(&attr, 0); + posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETPGROUP); + + pid_t pid = 0; + const Stopwatch clock; + const int rc = posix_spawn(&pid, executable.c_str(), &actions, &attr, + argv.data(), envp.data()); + posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); + close(err_pipe[1]); + if (rc != 0) { + close(err_pipe[0]); + result.error = std::string("posix_spawn: ") + strerror(rc); + return result; + } + struct rlimit no_core = {0, 0}; + prlimit(pid, RLIMIT_CORE, &no_core, nullptr); + result.started = true; + + // Read stderr until EOF or the timeout; keep at most max_stderr bytes. + char buffer[8192]; + bool open = true; + while (open) { + const uint64_t elapsed = clock.ElapsedUs(); + if (elapsed >= timeout_us) { + result.timed_out = true; + kill(-pid, SIGKILL); + kill(pid, SIGKILL); + break; + } + const uint64_t left_ms = (timeout_us - elapsed + 999) / 1000; + struct pollfd pfd = {err_pipe[0], POLLIN, 0}; + const int ready = + poll(&pfd, 1, static_cast<int>(std::min<uint64_t>(left_ms, 1000))); + if (ready < 0 && errno != EINTR) { + break; + } + if (ready <= 0) { + continue; + } + const ssize_t n = read(err_pipe[0], buffer, sizeof(buffer)); + if (n > 0) { + const size_t room = + max_stderr - std::min(max_stderr, result.stderr_text.size()); + result.stderr_text.append(buffer, std::min(room, static_cast<size_t>(n))); + } else if (n == 0 || errno != EINTR) { + open = false; + } + } + close(err_pipe[0]); + + int status = 0; + while (waitpid(pid, &status, 0) < 0 && errno == EINTR) { + } + result.wall_us = clock.ElapsedUs(); + if (WIFSIGNALED(status)) { + result.signal = WTERMSIG(status); + } else if (WIFEXITED(status)) { + result.exit_code = WEXITSTATUS(status); + } + return result; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/exec/process_run.h b/deps/v8/experimental/redline/exec/process_run.h new file mode 100644 index 000000000000..b1dda961b7fd --- /dev/null +++ b/deps/v8/experimental/redline/exec/process_run.h @@ -0,0 +1,39 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Runs a program once as a plain process (no REPRL): stdout goes to +// /dev/null, stderr is captured (bounded), and the process is killed after a +// timeout. The crash amplifier uses it to measure a d8 command line exactly as +// ClusterFuzz runs it. + +#ifndef V8_EXPERIMENTAL_REDLINE_EXEC_PROCESS_RUN_H_ +#define V8_EXPERIMENTAL_REDLINE_EXEC_PROCESS_RUN_H_ + +#include <cstddef> +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +namespace redline { + +struct ProcessResult { + bool started = false; // false: the process could not be spawned + int exit_code = 0; // valid if signal == 0 + int signal = 0; // the signal that ended the process, or 0 + bool timed_out = false; // killed after the timeout + uint64_t wall_us = 0; + std::string stderr_text; // at most max_stderr bytes + std::string error; // why it could not be spawned +}; + +// `args` without argv[0]; `env` is the complete environment of the child. +ProcessResult RunProcess( + const std::string& executable, const std::vector<std::string>& args, + const std::vector<std::pair<std::string, std::string>>& env, + uint64_t timeout_us, size_t max_stderr = static_cast<size_t>(256) * 1024); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_EXEC_PROCESS_RUN_H_ diff --git a/deps/v8/experimental/redline/exec/reprl.cc b/deps/v8/experimental/redline/exec/reprl.cc new file mode 100644 index 000000000000..d6be2085ea5a --- /dev/null +++ b/deps/v8/experimental/redline/exec/reprl.cc @@ -0,0 +1,570 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/exec/reprl.h" + +#include <fcntl.h> +#include <poll.h> +#include <spawn.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <algorithm> +#include <cerrno> +#include <csignal> +#include <cstring> +#include <mutex> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" + +namespace redline { + +namespace { + +// Well-known file descriptor numbers on the child side. +constexpr int kChildCtrlIn = 100; +constexpr int kChildCtrlOut = 101; +constexpr int kChildDataIn = 102; +constexpr int kChildDataOut = 103; + +// Maximum size of a data channel (and thus of a script / of captured +// output). Same value as Fuzzilli's REPRL_MAX_DATA_SIZE. +constexpr size_t kMaxDataSize = size_t{16} << 20; + +// poll(2) takes an int number of milliseconds. +constexpr uint64_t kMaxTimeoutUs = uint64_t{INT32_MAX} * 1000; + +constexpr const char* kLog = "reprl"; + +std::string Errno(const char* what) { + return StringPrintf("%s: %s", what, strerror(errno)); +} + +bool ReadExact(int fd, void* dst, size_t len) { + uint8_t* p = static_cast<uint8_t*>(dst); + size_t remaining = len; + while (remaining > 0) { + ssize_t n = read(fd, p, remaining); + if (n < 0) { + if (errno == EINTR) { + continue; + } + return false; + } + if (n == 0) { + return false; + } + p += n; + remaining -= static_cast<size_t>(n); + } + return true; +} + +bool WriteExact(int fd, const void* src, size_t len) { + const uint8_t* p = static_cast<const uint8_t*>(src); + size_t remaining = len; + while (remaining > 0) { + ssize_t n = write(fd, p, remaining); + if (n < 0) { + if (errno == EINTR) { + continue; + } + return false; + } + p += n; + remaining -= static_cast<size_t>(n); + } + return true; +} + +// Reserves the well-known fds once per process so that no other descriptor +// of ours can collide with them (which would break the dup2 dance during +// spawning), and ignores SIGPIPE since we may write to a pipe whose child +// has already died. +void InitializeProcessOnce() { + static std::once_flag once; + std::call_once(once, [] { + int devnull = open("/dev/null", O_RDWR | O_CLOEXEC); + if (devnull >= 0) { + for (int fd : + {kChildCtrlIn, kChildCtrlOut, kChildDataIn, kChildDataOut}) { + dup3(devnull, fd, O_CLOEXEC); + } + close(devnull); + } + signal(SIGPIPE, SIG_IGN); + }); +} + +} // namespace + +// A unidirectional channel for larger amounts of data, implemented as a +// RAM-backed file whose descriptor is shared with the child and which is +// mapped into our address space. Because the child's descriptor is a dup of +// ours, both share the file offset: the child simply read(2)s / write(2)s +// and we learn how much it wrote from lseek(SEEK_CUR). +class DataChannel { + public: + static std::unique_ptr<DataChannel> Create(const char* name, + std::string* error) { + int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd < 0) { + *error = Errno("memfd_create"); + return nullptr; + } + if (ftruncate(fd, static_cast<off_t>(kMaxDataSize)) != 0) { + *error = Errno("ftruncate"); + close(fd); + return nullptr; + } + // Seal the size of the file to the size of our mapping. A child cannot + // shrink the file, which would make the mapping fault with SIGBUS. A child + // also cannot grow it: a write past the end fails with EPERM. Thus each + // channel uses at most kMaxDataSize of memory. + if (fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW) != 0) { + *error = Errno("fcntl(F_ADD_SEALS)"); + close(fd); + return nullptr; + } + void* mapping = + mmap(nullptr, kMaxDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mapping == MAP_FAILED) { + *error = Errno("mmap"); + close(fd); + return nullptr; + } + return std::unique_ptr<DataChannel>( + new DataChannel(fd, static_cast<char*>(mapping))); + } + + ~DataChannel() { + munmap(mapping_, kMaxDataSize); + close(fd_); + } + + int fd() const { return fd_; } + char* mapping() { return mapping_; } + + void Rewind() { lseek(fd_, 0, SEEK_SET); } + + std::string_view Content() const { + off_t pos = lseek(fd_, 0, SEEK_CUR); + if (pos < 0) { + pos = 0; + } + size_t size = std::min(static_cast<size_t>(pos), kMaxDataSize); + return std::string_view(mapping_, size); + } + + private: + DataChannel(int fd, char* mapping) : fd_(fd), mapping_(mapping) {} + int fd_; + char* mapping_; +}; + +// static +std::unique_ptr<ReprlChild> ReprlChild::Create(Options options, + std::string* error) { + InitializeProcessOnce(); + std::unique_ptr<ReprlChild> child(new ReprlChild(std::move(options))); + if (!child->Initialize(error)) { + return nullptr; + } + return child; +} + +ReprlChild::ReprlChild(Options options) : options_(std::move(options)) {} + +ReprlChild::~ReprlChild() { Kill(); } + +bool ReprlChild::Initialize(std::string* error) { + if (options_.executable.empty()) { + *error = "No target executable given"; + return false; + } + if (access(options_.executable.c_str(), X_OK) != 0) { + *error = StringPrintf("Target executable %s is not executable: %s", + options_.executable.c_str(), strerror(errno)); + return false; + } + + argv_storage_.push_back(options_.executable); + for (const std::string& arg : options_.args) { + argv_storage_.push_back(arg); + } + for (std::string& s : argv_storage_) { + argv_.push_back(s.data()); + } + argv_.push_back(nullptr); + + for (const auto& [key, value] : options_.env) { + std::string entry = key; + entry += '='; + entry += value; + env_storage_.push_back(std::move(entry)); + } + for (std::string& s : env_storage_) { + envp_.push_back(s.data()); + } + envp_.push_back(nullptr); + + script_channel_ = DataChannel::Create("redline_reprl_script", error); + if (!script_channel_) { + return false; + } + fuzzout_channel_ = DataChannel::Create("redline_reprl_fuzzout", error); + if (!fuzzout_channel_) { + return false; + } + if (options_.capture_stdout) { + stdout_channel_ = DataChannel::Create("redline_reprl_stdout", error); + if (!stdout_channel_) { + return false; + } + } + if (options_.capture_stderr) { + stderr_channel_ = DataChannel::Create("redline_reprl_stderr", error); + if (!stderr_channel_) { + return false; + } + } + return true; +} + +void ReprlChild::OnChildTerminated() { + if (pid_ == 0) { + return; + } + pid_ = 0; + close(ctrl_in_); + close(ctrl_out_); + ctrl_in_ = ctrl_out_ = -1; +} + +void ReprlChild::Kill() { + if (pid_ == 0) { + return; + } + kill(-pid_, SIGKILL); + kill(pid_, SIGKILL); + int status; + while (waitpid(pid_, &status, 0) < 0 && errno == EINTR) { + } + OnChildTerminated(); +} + +bool ReprlChild::Spawn(std::string* error) { + int child_to_parent[2] = {-1, -1}; + int parent_to_child[2] = {-1, -1}; + if (pipe2(child_to_parent, O_CLOEXEC) != 0) { + *error = Errno("pipe2"); + return false; + } + if (pipe2(parent_to_child, O_CLOEXEC) != 0) { + *error = Errno("pipe2"); + close(child_to_parent[0]); + close(child_to_parent[1]); + return false; + } + + // posix_spawn uses vfork semantics on Linux, which is what makes + // respawning cheap. All descriptors we own are O_CLOEXEC, so only the + // explicitly dup2'ed ones survive the exec. + posix_spawn_file_actions_t actions; + posix_spawn_file_actions_init(&actions); + posix_spawn_file_actions_adddup2(&actions, parent_to_child[0], kChildCtrlIn); + posix_spawn_file_actions_adddup2(&actions, child_to_parent[1], kChildCtrlOut); + posix_spawn_file_actions_adddup2(&actions, script_channel_->fd(), + kChildDataIn); + posix_spawn_file_actions_adddup2(&actions, fuzzout_channel_->fd(), + kChildDataOut); + posix_spawn_file_actions_addopen(&actions, STDIN_FILENO, "/dev/null", + O_RDONLY, 0); + if (stdout_channel_) { + posix_spawn_file_actions_adddup2(&actions, stdout_channel_->fd(), + STDOUT_FILENO); + } else { + posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, "/dev/null", + O_WRONLY, 0); + } + if (stderr_channel_) { + posix_spawn_file_actions_adddup2(&actions, stderr_channel_->fd(), + STDERR_FILENO); + } else { + posix_spawn_file_actions_addopen(&actions, STDERR_FILENO, "/dev/null", + O_WRONLY, 0); + } + + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + // Start the child with a clean signal mask and default dispositions + // (we ignore SIGPIPE ourselves, the child should not inherit that). + sigset_t empty_set; + sigemptyset(&empty_set); + posix_spawnattr_setsigmask(&attr, &empty_set); + sigset_t default_set; + sigemptyset(&default_set); + sigaddset(&default_set, SIGPIPE); + posix_spawnattr_setsigdefault(&attr, &default_set); + posix_spawnattr_setpgroup(&attr, 0); + posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETPGROUP); + + pid_t pid = 0; + int rc = + posix_spawn(&pid, argv_[0], &actions, &attr, argv_.data(), envp_.data()); + posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); + close(child_to_parent[1]); + close(parent_to_child[0]); + + if (rc != 0) { + close(child_to_parent[0]); + close(parent_to_child[1]); + *error = StringPrintf("posix_spawn(%s) failed: %s", argv_[0], strerror(rc)); + return false; + } + + pid_ = pid; + ctrl_in_ = child_to_parent[0]; + ctrl_out_ = parent_to_child[1]; + execs_since_spawn_ = 0; + total_spawns_++; + + // No core dumps from the target: with crashes being the point of the + // exercise they would fill the disk. Doing this from the parent keeps + // core dumps enabled for redline itself. + struct rlimit no_core = {0, 0}; + if (prlimit(pid_, RLIMIT_CORE, &no_core, nullptr) != 0) { + REDLINE_WARN(kLog, "prlimit(RLIMIT_CORE) failed: %s", strerror(errno)); + } + + // HELO handshake. + uint64_t startup_deadline = MonotonicNowUs() + options_.startup_timeout_us; + int res = 0; + while (true) { + uint64_t now = MonotonicNowUs(); + int remaining_ms = + now >= startup_deadline + ? 0 + : static_cast<int>(std::min<uint64_t>( + (startup_deadline - now + 999) / 1000, INT32_MAX)); + struct pollfd pfd = {ctrl_in_, POLLIN, 0}; + res = poll(&pfd, 1, remaining_ms); + if (res < 0 && errno == EINTR) { + continue; + } + break; + } + char helo[4] = {0, 0, 0, 0}; + if (res != 1 || !ReadExact(ctrl_in_, helo, 4)) { + std::string output; + if (stderr_channel_) { + output = std::string(stderr_channel_->Content()); + } + Kill(); + *error = StringPrintf( + "Did not receive HELO from target %s (%s). Is it built with " + "v8_fuzzilli=true? stderr: %s", + argv_[0], res == 0 ? "timeout" : "child exited", output.c_str()); + return false; + } + if (memcmp(helo, "HELO", 4) != 0) { + Kill(); + *error = "Received invalid HELO message from target"; + return false; + } + if (!WriteExact(ctrl_out_, "HELO", 4)) { + Kill(); + *error = Errno("Failed to send HELO reply"); + return false; + } + + // Detect targets that re-enable core dumps themselves. + struct rlimit core_limit = {0, 0}; + if (prlimit(pid_, RLIMIT_CORE, nullptr, &core_limit) == 0 && + (core_limit.rlim_cur != 0 || core_limit.rlim_max != 0)) { + Kill(); + *error = "Target raised RLIMIT_CORE; refusing to fuzz it"; + return false; + } + return true; +} + +void ReprlChild::CollectOutput(Execution* result) { + result->fuzzout = std::string(fuzzout_channel_->Content()); + if (stdout_channel_) { + result->stdout_output = std::string(stdout_channel_->Content()); + } + if (stderr_channel_) { + result->stderr_output = std::string(stderr_channel_->Content()); + } +} + +bool ReprlChild::Execute(std::string_view script, uint64_t timeout_us, + Execution* result, std::string* error) { + *result = Execution(); + if (script.size() > kMaxDataSize) { + *error = StringPrintf("Script too large (%zu bytes)", script.size()); + return false; + } + if (timeout_us > kMaxTimeoutUs) { + *error = "Timeout too large"; + return false; + } + + if (pid_ != 0 && options_.max_execs_before_respawn > 0 && + execs_since_spawn_ >= options_.max_execs_before_respawn) { + Kill(); + } + + // Reset the file positions so the child can simply read(2) and write(2). + script_channel_->Rewind(); + fuzzout_channel_->Rewind(); + if (stdout_channel_) { + stdout_channel_->Rewind(); + } + if (stderr_channel_) { + stderr_channel_->Rewind(); + } + + if (pid_ == 0 && !Spawn(error)) { + return false; + } + + memcpy(script_channel_->mapping(), script.data(), script.size()); + uint64_t script_size = script.size(); + if (!WriteExact(ctrl_out_, "exec", 4) || + !WriteExact(ctrl_out_, &script_size, 8)) { + // The child may have died between executions. + int status = 0; + if (waitpid(pid_, &status, WNOHANG) == pid_) { + OnChildTerminated(); + if (WIFEXITED(status)) { + *error = StringPrintf( + "Child unexpectedly exited with status %d between executions", + WEXITSTATUS(status)); + } else { + *error = StringPrintf( + "Child unexpectedly terminated with signal %d between executions", + WTERMSIG(status)); + } + return false; + } + std::string message = Errno("Failed to send command to child"); + Kill(); + *error = message; + return false; + } + + total_executions_++; + execs_since_spawn_++; + + // Wait for the status word, EOF (child died) or the timeout. + uint64_t start = MonotonicNowUs(); + uint64_t deadline = start + timeout_us; + int res; + while (true) { + uint64_t now = MonotonicNowUs(); + int remaining_ms = now >= deadline + ? 0 + : static_cast<int>(std::min<uint64_t>( + (deadline - now + 999) / 1000, INT32_MAX)); + struct pollfd pfd = {ctrl_in_, POLLIN, 0}; + res = poll(&pfd, 1, remaining_ms); + if (res < 0 && errno == EINTR) { + continue; + } + break; + } + result->exec_time_us = MonotonicNowUs() - start; + + if (res == 0) { + Kill(); + result->outcome = Outcome::kTimedOut; + CollectOutput(result); + return true; + } + if (res < 0) { + std::string message = Errno("poll"); + Kill(); + *error = message; + return false; + } + + int status = 0; + ssize_t rv = 0; + do { + rv = read(ctrl_in_, &status, 4); + } while (rv < 0 && errno == EINTR); + if (rv < 0) { + std::string message = Errno("Failed to read from control pipe"); + Kill(); + *error = message; + return false; + } + if (rv != 4) { + // EOF: most likely the child crashed. Reap it; waitpid may not succeed + // immediately after the pipe closed, so retry briefly. + int wait_status = 0; + bool reaped = false; + uint64_t wait_deadline = + MonotonicNowUs() + std::max<uint64_t>(timeout_us, 1000000); + while (MonotonicNowUs() < wait_deadline) { + pid_t r = waitpid(pid_, &wait_status, WNOHANG); + if (r == pid_) { + reaped = true; + break; + } + if (r < 0 && errno != EINTR) { + break; + } + usleep(10); + } + if (!reaped) { + Kill(); + *error = "Child in unexpected state after execution"; + return false; + } + OnChildTerminated(); + if (WIFEXITED(wait_status)) { + status = WEXITSTATUS(wait_status) << 8; + } else if (WIFSIGNALED(wait_status)) { + status = WTERMSIG(wait_status); + } else { + *error = StringPrintf("waitpid returned unexpected child state %d", + wait_status); + return false; + } + } + if (status < 0) { + Kill(); + *error = StringPrintf("Child reported invalid status %d", status); + return false; + } + + status &= 0xffff; + int signal_number = status & 0xff; + int exit_code = (status >> 8) & 0xff; + if (signal_number != 0) { + result->outcome = Outcome::kCrashed; + result->signal = signal_number; + // A child that reported a signal in-band cannot be trusted anymore. + if (pid_ != 0) { + Kill(); + } + } else { + result->exit_code = exit_code; + result->outcome = exit_code == 0 ? Outcome::kSucceeded : Outcome::kFailed; + } + CollectOutput(result); + return true; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/exec/reprl.h b/deps/v8/experimental/redline/exec/reprl.h new file mode 100644 index 000000000000..3551cc1c017b --- /dev/null +++ b/deps/v8/experimental/redline/exec/reprl.h @@ -0,0 +1,111 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_EXEC_REPRL_H_ +#define V8_EXPERIMENTAL_REDLINE_EXEC_REPRL_H_ + +#include <sys/types.h> + +#include <cstdint> +#include <memory> +#include <string> +#include <string_view> +#include <utility> +#include <vector> + +#include "experimental/redline/exec/execution.h" + +namespace redline { + +class DataChannel; + +// Drives one target process over the REPRL ("read-eval-print-reset-loop") +// protocol implemented by d8 when built with v8_fuzzilli=true. This is a C++ +// port of Fuzzilli's libreprl and speaks exactly the same protocol, so any +// d8 that works with Fuzzilli works here: +// +// - The child is started with four well-known file descriptors: +// 100: control pipe, child reads commands ("exec" + 8 byte script size) +// 101: control pipe, child writes a 4 byte status word per execution +// 102: data channel, child reads the script source +// 103: data channel, child writes fuzzilli('FUZZILLI_PRINT') output +// plus an "SHM_ID" environment variable naming the coverage bitmap. +// - After startup the child writes "HELO" on 101 and expects "HELO" on 100. +// - Per execution the parent writes the script into the 102 channel, sends +// "exec" and the size, waits for the status word (or a timeout, or EOF +// which means the child died). The status word is `exit_code << 8`; +// children that die report their wait status (signal in the low byte). +// - The same child is reused for many executions; it is killed on timeouts, +// crashes, and after max_execs_before_respawn executions. +// +// Instances are not thread-safe: use one per worker thread. +class ReprlChild { + public: + struct Options { + std::string executable; + std::vector<std::string> args; // without argv[0] + // Complete environment of the child (this class adds nothing itself). + std::vector<std::pair<std::string, std::string>> env; + bool capture_stdout = true; + bool capture_stderr = true; + // Kill and respawn the child after this many executions to bound the + // amount of state that accumulates in the target. 0 disables this. + int max_execs_before_respawn = 1000; + // How long to wait for the HELO handshake after spawning. + uint64_t startup_timeout_us = static_cast<uint64_t>(60) * 1000 * 1000; + }; + + static std::unique_ptr<ReprlChild> Create(Options options, + std::string* error); + ~ReprlChild(); + ReprlChild(const ReprlChild&) = delete; + ReprlChild& operator=(const ReprlChild&) = delete; + + // Executes `script`, spawning a child first if none is running. Returns + // true if the execution happened (whatever its outcome). Returns false + // on an infrastructure failure (cannot spawn, protocol violation) with a + // description in *error; the child, if any, has been killed in that case + // and the next call will spawn a fresh one. + bool Execute(std::string_view script, uint64_t timeout_us, Execution* result, + std::string* error); + + // Terminates the current child, if any. + void Kill(); + + bool is_running() const { return pid_ != 0; } + pid_t pid() const { return pid_; } + int execs_since_spawn() const { return execs_since_spawn_; } + uint64_t total_spawns() const { return total_spawns_; } + uint64_t total_executions() const { return total_executions_; } + const Options& options() const { return options_; } + + private: + explicit ReprlChild(Options options); + bool Initialize(std::string* error); + bool Spawn(std::string* error); + void OnChildTerminated(); + void CollectOutput(Execution* result); + + Options options_; + std::vector<std::string> argv_storage_; + std::vector<std::string> env_storage_; + std::vector<char*> argv_; + std::vector<char*> envp_; + + std::unique_ptr<DataChannel> script_channel_; // parent -> child (fd 102) + std::unique_ptr<DataChannel> fuzzout_channel_; // child -> parent (fd 103) + std::unique_ptr<DataChannel> stdout_channel_; + std::unique_ptr<DataChannel> stderr_channel_; + + pid_t pid_ = 0; + int ctrl_in_ = -1; // we read status words here + int ctrl_out_ = -1; // we write commands here + int execs_since_spawn_ = 0; + uint64_t total_spawns_ = 0; + uint64_t total_executions_ = 0; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_EXEC_REPRL_H_ diff --git a/deps/v8/experimental/redline/exec/runner.cc b/deps/v8/experimental/redline/exec/runner.cc new file mode 100644 index 000000000000..fd062c4c327c --- /dev/null +++ b/deps/v8/experimental/redline/exec/runner.cc @@ -0,0 +1,148 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/exec/runner.h" + +#include <unistd.h> + +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { +constexpr const char* kLog = "runner"; +} + +// static +std::unique_ptr<ScriptRunner> ScriptRunner::Create(const TargetOptions& options, + int id, std::string* error) { + std::unique_ptr<ScriptRunner> runner(new ScriptRunner(options, id)); + runner->coverage_ = CoverageMap::Create(id, error); + if (!runner->coverage_) { + return nullptr; + } + runner->child_ = ReprlChild::Create( + options.ToReprlOptions(runner->coverage_->shm_name()), error); + if (!runner->child_) { + return nullptr; + } + return runner; +} + +ScriptRunner::ScriptRunner(TargetOptions options, int id) + : options_(std::move(options)), id_(id) {} + +ScriptRunner::~ScriptRunner() = default; + +bool ScriptRunner::Initialize(std::string* error) { + if (initialized_) { + return true; + } + // An empty script lets the target start up and publish its edge count. + Execution execution; + if (!child_->Execute("", options_.timeout_us, &execution, error)) { + return false; + } + if (!execution.succeeded()) { + *error = StringPrintf( + "The target cannot even run an empty script (%s, exit code %d, " + "signal %d). stderr: %s", + OutcomeName(execution.outcome), execution.exit_code, execution.signal, + execution.stderr_output.c_str()); + return false; + } + if (!coverage_->FinishInitialization(error)) { + return false; + } + initialized_ = true; + REDLINE_VLOG(kLog, "Runner %d ready: %u edges instrumented, target pid %d", + id_, coverage_->num_edges(), static_cast<int>(child_->pid())); + return true; +} + +void ScriptRunner::Account(const Execution& execution) { + stats_.executions++; + stats_.total_exec_time_us += execution.exec_time_us; + switch (execution.outcome) { + case Outcome::kSucceeded: + stats_.succeeded++; + break; + case Outcome::kFailed: + stats_.failed++; + break; + case Outcome::kCrashed: + stats_.crashed++; + break; + case Outcome::kTimedOut: + stats_.timed_out++; + break; + } +} + +bool ScriptRunner::ExecuteWithRetry(std::string_view script, + uint64_t timeout_us, Execution* execution, + std::string* error) { + if (child_->Execute(script, timeout_us, execution, error)) { + return true; + } + // Like Fuzzilli: retry once with a fresh instance after a short pause; + // transient failures (e.g. a child that died between executions) are + // expected now and then. + stats_.infrastructure_failures++; + REDLINE_WARN(kLog, + "Script execution failed: %s. Retrying with a fresh target.", + error->c_str()); + usleep(100 * 1000); + child_->Kill(); + coverage_->ClearBitmap(); + if (child_->Execute(script, timeout_us, execution, error)) { + // A respawned child publishes its edge count again; make sure it is + // the same binary. + return coverage_->FinishInitialization(error); + } + stats_.infrastructure_failures++; + return false; +} + +bool ScriptRunner::Run(std::string_view script, Result* result, + std::string* error) { + return Run(script, options_.timeout_us, result, error); +} + +bool ScriptRunner::Run(std::string_view script, uint64_t timeout_us, + Result* result, std::string* error) { + *result = Result(); + coverage_->ClearBitmap(); + if (!ExecuteWithRetry(script, timeout_us, &result->execution, error)) { + return false; + } + Account(result->execution); + result->edges_hit = coverage_->CountCurrentEdges(); + switch (result->execution.outcome) { + case Outcome::kSucceeded: + result->new_edges = coverage_->EvaluateNewEdges(); + break; + case Outcome::kCrashed: + result->new_crash_edges = coverage_->EvaluateCrash(); + break; + case Outcome::kFailed: + case Outcome::kTimedOut: + break; + } + return true; +} + +bool ScriptRunner::RunWithoutEvaluation(std::string_view script, + uint64_t timeout_us, + Execution* execution, + std::string* error) { + coverage_->ClearBitmap(); + if (!ExecuteWithRetry(script, timeout_us, execution, error)) { + return false; + } + Account(*execution); + return true; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/exec/runner.h b/deps/v8/experimental/redline/exec/runner.h new file mode 100644 index 000000000000..e2519dd88d33 --- /dev/null +++ b/deps/v8/experimental/redline/exec/runner.h @@ -0,0 +1,94 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_EXEC_RUNNER_H_ +#define V8_EXPERIMENTAL_REDLINE_EXEC_RUNNER_H_ + +#include <cstdint> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/exec/coverage.h" +#include "experimental/redline/exec/execution.h" +#include "experimental/redline/exec/reprl.h" +#include "experimental/redline/exec/target_options.h" + +namespace redline { + +// One target process plus its coverage bitmap: the unit a worker thread +// owns. Runs scripts and reports which edges were new. +// +// Policy (identical to Fuzzilli's): only executions that *succeed* are +// evaluated for new coverage; crashes are checked against a separate set of +// crash bits; failed and timed out executions never advance the coverage +// state. +class ScriptRunner { + public: + struct Result { + Execution execution; + // Edges that this execution reached for the first time (only filled for + // successful executions). + std::vector<uint32_t> new_edges; + // For crashes: whether the crash reached edges no earlier crash reached. + bool new_crash_edges = false; + // Number of edges set in the bitmap by this execution, whatever the + // outcome (informational). + uint32_t edges_hit = 0; + }; + + struct Stats { + uint64_t executions = 0; + uint64_t succeeded = 0; + uint64_t failed = 0; + uint64_t crashed = 0; + uint64_t timed_out = 0; + uint64_t total_exec_time_us = 0; + uint64_t infrastructure_failures = 0; + }; + + // `id` must be unique per process (it names the shared memory object). + static std::unique_ptr<ScriptRunner> Create(const TargetOptions& options, + int id, std::string* error); + ~ScriptRunner(); + + // Starts the target, verifies the REPRL handshake and that the target + // publishes coverage information. Must be called once before Run(). + bool Initialize(std::string* error); + + // Runs `script` with the default timeout and evaluates coverage. + bool Run(std::string_view script, Result* result, std::string* error); + bool Run(std::string_view script, uint64_t timeout_us, Result* result, + std::string* error); + + // Runs `script` without touching the coverage bookkeeping. The bitmap is + // cleared before and left as is afterwards, so callers can inspect it via + // coverage() (determinism checks, minimization probes). + bool RunWithoutEvaluation(std::string_view script, uint64_t timeout_us, + Execution* execution, std::string* error); + + CoverageMap& coverage() { return *coverage_; } + ReprlChild& child() { return *child_; } + const TargetOptions& options() const { return options_; } + const Stats& stats() const { return stats_; } + int id() const { return id_; } + + private: + ScriptRunner(TargetOptions options, int id); + bool ExecuteWithRetry(std::string_view script, uint64_t timeout_us, + Execution* execution, std::string* error); + void Account(const Execution& execution); + + TargetOptions options_; + int id_; + std::unique_ptr<CoverageMap> coverage_; + std::unique_ptr<ReprlChild> child_; + Stats stats_; + bool initialized_ = false; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_EXEC_RUNNER_H_ diff --git a/deps/v8/experimental/redline/exec/target_options.cc b/deps/v8/experimental/redline/exec/target_options.cc new file mode 100644 index 000000000000..53474324de75 --- /dev/null +++ b/deps/v8/experimental/redline/exec/target_options.cc @@ -0,0 +1,158 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/exec/target_options.h" + +#include <unistd.h> + +#include <cerrno> +#include <cstdlib> +#include <cstring> +#include <sstream> + +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" + +namespace redline { + +namespace { + +std::vector<std::string> SplitWhitespace(const std::string& text) { + std::vector<std::string> result; + std::istringstream stream(text); + std::string piece; + while (stream >> piece) { + result.push_back(piece); + } + return result; +} + +} // namespace + +// static +std::vector<std::string> TargetOptions::DefaultArgs() { + // Keep in sync with v8ProcessArgs() in Fuzzilli's V8CommonProfile.swift. + return { + "--expose-gc", + "--expose-externalize-string", + "--omit-quit", + "--allow-natives-syntax", + "--fuzzing", + "--harmony", + "--experimental-fuzzing", + "--js-staging", + "--wasm-staging", + "--wasm-fast-api", + "--expose-fast-api", + "--wasm-test-streaming", + }; +} + +// static +bool TargetOptions::FromFlags(const Flags& flags, TargetOptions* out, + std::string* error) { + out->executable = flags.GetString("d8"); + if (out->executable.empty()) { + const char* from_env = getenv("REDLINE_D8"); + if (from_env != nullptr) { + out->executable = from_env; + } + } + if (out->executable.empty()) { + *error = "No target given: pass --d8=PATH or set $REDLINE_D8"; + return false; + } + if (access(out->executable.c_str(), X_OK) != 0) { + *error = StringPrintf("--d8=%s is not an executable file: %s", + out->executable.c_str(), strerror(errno)); + return false; + } + + if (flags.Has("d8-args")) { + out->args = SplitWhitespace(flags.GetString("d8-args")); + } else { + out->args = DefaultArgs(); + } + for (const std::string& arg : + SplitWhitespace(flags.GetString("d8-extra-args"))) { + out->args.push_back(arg); + } + + for (const std::string& entry : flags.GetList("d8-env")) { + size_t eq = entry.find('='); + if (eq == std::string::npos) { + *error = StringPrintf("--d8-env entry '%s' is not of the form KEY=VALUE", + entry.c_str()); + return false; + } + out->extra_env.emplace_back(entry.substr(0, eq), entry.substr(eq + 1)); + } + + int64_t timeout_ms = flags.GetInt("timeout-ms", 1000); + if (timeout_ms <= 0) { + *error = "--timeout-ms must be positive"; + return false; + } + out->timeout_us = static_cast<uint64_t>(timeout_ms) * 1000; + out->max_execs_before_respawn = + static_cast<int>(flags.GetInt("max-execs-before-respawn", 1000)); + out->capture_output = flags.GetBool("capture-output", true); + return true; +} + +ReprlChild::Options TargetOptions::ToReprlOptions( + const std::string& shm_name) const { + ReprlChild::Options options; + options.executable = executable; + options.args = args; + options.capture_stdout = capture_output; + options.capture_stderr = capture_output; + options.max_execs_before_respawn = max_execs_before_respawn; + options.env = InheritedEnvironment(); + options.env.emplace_back("SHM_ID", shm_name); + for (const auto& kv : extra_env) { + options.env.push_back(kv); + } + return options; +} + +// static +std::vector<std::pair<std::string, std::string>> +TargetOptions::InheritedEnvironment() { + static const char* const kInheritedVariables[] = { + "PATH", "HOME", + "TMPDIR", "LANG", + "ASAN_OPTIONS", "MSAN_OPTIONS", + "UBSAN_OPTIONS", "TSAN_OPTIONS", + "LSAN_OPTIONS", "LD_LIBRARY_PATH", + }; + std::vector<std::pair<std::string, std::string>> env; + for (const char* name : kInheritedVariables) { + const char* value = getenv(name); + if (value != nullptr) { + env.emplace_back(name, value); + } + } + return env; +} + +std::vector<std::pair<std::string, std::string>> +TargetOptions::PlainEnvironment() const { + std::vector<std::pair<std::string, std::string>> env = InheritedEnvironment(); + for (const auto& kv : extra_env) { + env.push_back(kv); + } + return env; +} + +std::string TargetOptions::CommandLine() const { + std::string result = executable; + for (const std::string& arg : args) { + result += ' '; + result += arg; + } + return result; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/exec/target_options.h b/deps/v8/experimental/redline/exec/target_options.h new file mode 100644 index 000000000000..97aa1d4789ce --- /dev/null +++ b/deps/v8/experimental/redline/exec/target_options.h @@ -0,0 +1,65 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_EXEC_TARGET_OPTIONS_H_ +#define V8_EXPERIMENTAL_REDLINE_EXEC_TARGET_OPTIONS_H_ + +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +#include "experimental/redline/exec/reprl.h" + +namespace redline { + +class Flags; + +// Everything needed to start and talk to the target: the d8 binary, its +// flags and environment, and the execution timeout. All commands that run +// scripts share these flags: +// +// --d8=PATH the instrumented d8 (or $REDLINE_D8) +// --d8-args="--a --b" replaces the default d8 flags +// --d8-extra-args="--c" appended to the (default or given) d8 flags +// --d8-env=K=V,K2=V2 extra environment variables for d8 +// --timeout-ms=N per-execution timeout (default 1000) +// --max-execs-before-respawn=N respawn d8 after N executions (1000) +// --capture-output capture d8 stdout/stderr (default true) +struct TargetOptions { + std::string executable; + std::vector<std::string> args; + std::vector<std::pair<std::string, std::string>> extra_env; + uint64_t timeout_us = static_cast<uint64_t>(1000) * 1000; + int max_execs_before_respawn = 1000; + bool capture_output = true; + + // The flags Fuzzilli's V8 profile passes to d8 (without the randomized + // part), so that coverage numbers are comparable. + static std::vector<std::string> DefaultArgs(); + + // Parses the shared target flags. Returns false with a message if the + // target is not usable. + static bool FromFlags(const Flags& flags, TargetOptions* out, + std::string* error); + + // Builds the REPRL options for a child whose coverage bitmap is named + // `shm_name`. The environment is deliberately minimal: a small allowlist + // inherited from this process, SHM_ID, and extra_env. + ReprlChild::Options ToReprlOptions(const std::string& shm_name) const; + + // The environment of a plain (non-REPRL) d8 run: the same allowlist as + // ToReprlOptions plus extra_env, without SHM_ID. + std::vector<std::pair<std::string, std::string>> PlainEnvironment() const; + + // The variables a target inherits from this process (allowlist). + static std::vector<std::pair<std::string, std::string>> + InheritedEnvironment(); + + std::string CommandLine() const; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_EXEC_TARGET_OPTIONS_H_ diff --git a/deps/v8/experimental/redline/fast/arena.cc b/deps/v8/experimental/redline/fast/arena.cc new file mode 100644 index 000000000000..a43807b6de6d --- /dev/null +++ b/deps/v8/experimental/redline/fast/arena.cc @@ -0,0 +1,105 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/arena.h" + +#include <algorithm> +#include <cstring> + +namespace redline { +namespace fast { + +namespace { + +// Segments of kSegmentSize released by dead arenas, kept for reuse by the +// thread that freed them. Bounded so that a thread which only frees (e.g. the +// coordinator evicting corpus programs) cannot hoard memory. +class SegmentPool { + public: + static constexpr size_t kMaxSegments = 64; // 4 MB per thread + + char* Take() { + if (free_.empty()) { + return new char[Arena::kSegmentSize]; + } + char* segment = free_.back(); + free_.pop_back(); + return segment; + } + + void Give(char* segment) { + if (free_.size() >= kMaxSegments) { + delete[] segment; + return; + } + free_.push_back(segment); + } + + private: + std::vector<char*> free_; +}; + +SegmentPool& ThreadPool() { + // Deliberately leaked: an arena with static storage duration may be + // destroyed after the thread's thread_local objects, and must still find + // a live pool. Threads are long-lived in redline, so nothing accumulates. + thread_local SegmentPool* pool = new SegmentPool; + return *pool; +} + +} // namespace + +Arena::~Arena() { + for (auto it = destructors_.rbegin(); it != destructors_.rend(); ++it) { + it->destroy(it->object); + } + for (const Segment& segment : segments_) { + if (segment.size == kSegmentSize) { + ThreadPool().Give(segment.memory); + } else { + delete[] segment.memory; + } + } +} + +void* Arena::Allocate(size_t size, size_t alignment) { + if (size == 0) { + size = 1; + } + uintptr_t aligned = (reinterpret_cast<uintptr_t>(cursor_) + alignment - 1) & + ~(static_cast<uintptr_t>(alignment) - 1); + if (cursor_ == nullptr || + aligned + size > reinterpret_cast<uintptr_t>(limit_)) { + Segment segment{nullptr, 0}; + if (size + alignment <= kSegmentSize) { + segment = {ThreadPool().Take(), kSegmentSize}; + } else { + segment = {new char[size + alignment], size + alignment}; + } + segments_.push_back(segment); + cursor_ = segment.memory; + limit_ = cursor_ + segment.size; + aligned = (reinterpret_cast<uintptr_t>(cursor_) + alignment - 1) & + ~(static_cast<uintptr_t>(alignment) - 1); + } + // Pointer arithmetic on an aligned bump allocator: the alignment is + // computed on the integer value of the cursor, so the round-trip through + // uintptr_t is intentional. + cursor_ = reinterpret_cast<char*>(aligned + + size); // NOLINT(performance-no-int-to-ptr) + bytes_allocated_ += size; + return reinterpret_cast<void*>(aligned); // NOLINT(performance-no-int-to-ptr) +} + +std::string_view Arena::CopyString(std::string_view text) { + if (text.empty()) { + return std::string_view(); + } + char* memory = static_cast<char*>(Allocate(text.size(), 1)); + memcpy(memory, text.data(), text.size()); + return std::string_view(memory, text.size()); +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/arena.h b/deps/v8/experimental/redline/fast/arena.h new file mode 100644 index 000000000000..75ea38540c7e --- /dev/null +++ b/deps/v8/experimental/redline/fast/arena.h @@ -0,0 +1,80 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_ARENA_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_ARENA_H_ + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <new> +#include <string> +#include <string_view> +#include <type_traits> +#include <utility> +#include <vector> + +namespace redline { +namespace fast { + +// A bump allocator owning every node of one program. Objects allocated here +// live as long as the arena; objects with non-trivial destructors are +// destroyed when the arena dies (in reverse allocation order). Mutators are +// therefore free to detach subtrees and forget about them. +// +// Memory comes in fixed-size segments that are recycled through a per-thread +// pool (see arena.cc): a fuzzing worker creates and drops thousands of trees +// per second, and with the pool a tree costs bump allocation only, no trips +// to malloc. +class Arena { + public: + Arena() = default; + ~Arena(); + Arena(const Arena&) = delete; + Arena& operator=(const Arena&) = delete; + + void* Allocate(size_t size, size_t alignment = alignof(std::max_align_t)); + + template <typename T, typename... Args> + T* New(Args&&... args) { + void* memory = Allocate(sizeof(T), alignof(T)); + T* object = new (memory) T(std::forward<Args>(args)...); + if constexpr (!std::is_trivially_destructible_v<T>) { + destructors_.push_back( + {object, [](void* p) { static_cast<T*>(p)->~T(); }}); + } + return object; + } + + // Copies `text` into the arena; the returned view lives as long as it. + std::string_view CopyString(std::string_view text); + + size_t bytes_allocated() const { return bytes_allocated_; } + + // Size of a pooled segment; requests larger than this get a segment of + // their own that is not pooled. + static constexpr size_t kSegmentSize = static_cast<size_t>(64) * 1024; + + private: + struct Destructor { + void* object; + void (*destroy)(void*); + }; + + struct Segment { + char* memory; + size_t size; + }; + + std::vector<Segment> segments_; + std::vector<Destructor> destructors_; + char* cursor_ = nullptr; + char* limit_ = nullptr; + size_t bytes_allocated_ = 0; +}; + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_ARENA_H_ diff --git a/deps/v8/experimental/redline/fast/ast.cc b/deps/v8/experimental/redline/fast/ast.cc new file mode 100644 index 000000000000..ccbfc3b98f24 --- /dev/null +++ b/deps/v8/experimental/redline/fast/ast.cc @@ -0,0 +1,201 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/ast.h" + +namespace redline { +namespace fast { + +const char* NodeKindName(NodeKind kind) { + switch (kind) { +#define KIND_NAME(name) \ + case NodeKind::k##name: \ + return #name; + FAST_NODE_KIND_LIST(KIND_NAME) +#undef KIND_NAME + } + return "?"; +} + +bool IsStatementKind(NodeKind kind) { + switch (kind) { +#define STATEMENT_CASE(name) case NodeKind::k##name: + FAST_STATEMENT_KIND_LIST(STATEMENT_CASE) +#undef STATEMENT_CASE + return true; + default: + return false; + } +} + +bool IsExpressionKind(NodeKind kind) { + switch (kind) { +#define EXPRESSION_CASE(name) case NodeKind::k##name: + FAST_EXPRESSION_KIND_LIST(EXPRESSION_CASE) +#undef EXPRESSION_CASE + return true; + default: + return false; + } +} + +bool Node::IsPattern() const { + switch (kind) { + case NodeKind::kObjectPattern: + case NodeKind::kArrayPattern: + case NodeKind::kAssignmentPattern: + case NodeKind::kRestElement: + return true; + default: + return false; + } +} + +bool Node::IsFunction() const { + switch (kind) { + case NodeKind::kFunctionDeclaration: + case NodeKind::kFunctionExpression: + case NodeKind::kArrowFunctionExpression: + return true; + default: + return false; + } +} + +bool Node::IsClass() const { + return kind == NodeKind::kClassDeclaration || + kind == NodeKind::kClassExpression; +} + +#define OPERATOR_TEXT(type, list) \ + const char* OperatorText(type op) { \ + switch (op) { list(OPERATOR_CASE) } \ + return "?"; \ + } +#define OPERATOR_CASE(name, text) \ + case decltype(op)::name: \ + return text; +OPERATOR_TEXT(UnaryOp, FAST_UNARY_OP_LIST) +OPERATOR_TEXT(UpdateOp, FAST_UPDATE_OP_LIST) +OPERATOR_TEXT(BinaryOp, FAST_BINARY_OP_LIST) +OPERATOR_TEXT(LogicalOp, FAST_LOGICAL_OP_LIST) +OPERATOR_TEXT(AssignOp, FAST_ASSIGN_OP_LIST) +#undef OPERATOR_CASE +#undef OPERATOR_TEXT + +int BinaryPrecedence(BinaryOp op) { + switch (op) { + case BinaryOp::kBitOr: + return 4; + case BinaryOp::kBitXor: + return 5; + case BinaryOp::kBitAnd: + return 6; + case BinaryOp::kEq: + case BinaryOp::kNotEq: + case BinaryOp::kStrictEq: + case BinaryOp::kStrictNotEq: + return 7; + case BinaryOp::kLessThan: + case BinaryOp::kLessThanEq: + case BinaryOp::kGreaterThan: + case BinaryOp::kGreaterThanEq: + case BinaryOp::kIn: + case BinaryOp::kInstanceof: + return 8; + case BinaryOp::kShiftLeft: + case BinaryOp::kShiftRight: + case BinaryOp::kShiftRightLogical: + return 9; + case BinaryOp::kAdd: + case BinaryOp::kSub: + return 10; + case BinaryOp::kMul: + case BinaryOp::kDiv: + case BinaryOp::kMod: + return 11; + case BinaryOp::kExp: + return 12; + } + return 0; +} + +int LogicalPrecedence(LogicalOp op) { + switch (op) { + case LogicalOp::kNullish: + return 1; + case LogicalOp::kOr: + return 2; + case LogicalOp::kAnd: + return 3; + } + return 0; +} + +const char* VariableKindText(VariableKind kind) { + switch (kind) { + case VariableKind::kVar: + return "var"; + case VariableKind::kLet: + return "let"; + case VariableKind::kConst: + return "const"; + case VariableKind::kUsing: + return "using"; + case VariableKind::kAwaitUsing: + return "await using"; + } + return "?"; +} + +FunctionData* AsFunctionData(Node* node) { + if (node == nullptr) { + return nullptr; + } + switch (node->kind) { + case NodeKind::kFunctionDeclaration: + return node->Cast<FunctionDeclaration>(); + case NodeKind::kFunctionExpression: + return node->Cast<FunctionExpression>(); + case NodeKind::kArrowFunctionExpression: + return node->Cast<ArrowFunctionExpression>(); + default: + return nullptr; + } +} + +const FunctionData* AsFunctionData(const Node* node) { + return AsFunctionData(const_cast<Node*>(node)); +} + +ClassData* AsClassData(Node* node) { + if (node == nullptr) { + return nullptr; + } + switch (node->kind) { + case NodeKind::kClassDeclaration: + return node->Cast<ClassDeclaration>(); + case NodeKind::kClassExpression: + return node->Cast<ClassExpression>(); + default: + return nullptr; + } +} + +const ClassData* AsClassData(const Node* node) { + return AsClassData(const_cast<Node*>(node)); +} + +size_t CountNodes(const Node* node) { + size_t count = 0; + Walk(const_cast<Node*>(node), [&](Node* visited) { + (void)visited; + count++; + return true; + }); + return count; +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/ast.h b/deps/v8/experimental/redline/fast/ast.h new file mode 100644 index 000000000000..6181362cbe56 --- /dev/null +++ b/deps/v8/experimental/redline/fast/ast.h @@ -0,0 +1,769 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// FAST: the fuzzer's JavaScript AST. +// +// The tree is deliberately shaped like ESTree (the AST format of acorn, +// babel, esprima, ...) so that dumps are comparable with those tools and so +// that the literature on AST mutation applies directly. Differences: +// * literals are split into one node kind per literal type, +// * `%RuntimeFunction(...)` calls (--allow-natives-syntax) are their own +// kind, +// * parentheses are not represented; the printer re-derives them from +// precedence. +// +// Nodes are plain structs allocated in a per-program Arena; child pointers +// are raw and owned by the arena. Each node has a per-program id (stable for +// the lifetime of the program; the shell and attribution logs refer to nodes +// by id) and the [start, end) byte range it was parsed from (-1 when the node +// was synthesized by the fuzzer). + +#ifndef V8_EXPERIMENTAL_REDLINE_FAST_AST_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_AST_H_ + +#include <cstdint> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/fast/arena.h" + +namespace redline { +namespace fast { + +// V(kind, class) +#define FAST_STATEMENT_KIND_LIST(V) \ + V(ExpressionStatement) \ + V(BlockStatement) \ + V(EmptyStatement) \ + V(DebuggerStatement) \ + V(WithStatement) \ + V(ReturnStatement) \ + V(LabeledStatement) \ + V(BreakStatement) \ + V(ContinueStatement) \ + V(IfStatement) \ + V(SwitchStatement) \ + V(ThrowStatement) \ + V(TryStatement) \ + V(WhileStatement) \ + V(DoWhileStatement) \ + V(ForStatement) \ + V(ForInStatement) \ + V(ForOfStatement) \ + V(FunctionDeclaration) \ + V(VariableDeclaration) \ + V(ClassDeclaration) + +#define FAST_EXPRESSION_KIND_LIST(V) \ + V(Identifier) \ + V(PrivateIdentifier) \ + V(NullLiteral) \ + V(BooleanLiteral) \ + V(NumericLiteral) \ + V(BigIntLiteral) \ + V(StringLiteral) \ + V(RegExpLiteral) \ + V(ThisExpression) \ + V(Super) \ + V(ArrayExpression) \ + V(ObjectExpression) \ + V(FunctionExpression) \ + V(ArrowFunctionExpression) \ + V(ClassExpression) \ + V(UnaryExpression) \ + V(UpdateExpression) \ + V(BinaryExpression) \ + V(LogicalExpression) \ + V(AssignmentExpression) \ + V(MemberExpression) \ + V(ConditionalExpression) \ + V(CallExpression) \ + V(NewExpression) \ + V(SequenceExpression) \ + V(YieldExpression) \ + V(AwaitExpression) \ + V(TemplateLiteral) \ + V(TaggedTemplateExpression) \ + V(MetaProperty) \ + V(ImportExpression) \ + V(ChainExpression) \ + V(SpreadElement) \ + V(ObjectPattern) \ + V(ArrayPattern) \ + V(RestElement) \ + V(AssignmentPattern) \ + V(NativeCallExpression) + +#define FAST_OTHER_KIND_LIST(V) \ + V(Program) \ + V(VariableDeclarator) \ + V(SwitchCase) \ + V(CatchClause) \ + V(Property) \ + V(ClassBody) \ + V(MethodDefinition) \ + V(PropertyDefinition) \ + V(StaticBlock) \ + V(TemplateElement) + +#define FAST_NODE_KIND_LIST(V) \ + FAST_STATEMENT_KIND_LIST(V) \ + FAST_EXPRESSION_KIND_LIST(V) \ + FAST_OTHER_KIND_LIST(V) + +enum class NodeKind : uint8_t { +#define DECLARE_KIND(name) k##name, + FAST_NODE_KIND_LIST(DECLARE_KIND) +#undef DECLARE_KIND +}; + +#define COUNT_KIND(name) \ + +1 // NOLINT(bugprone-macro-parentheses): X-macro summand, `(+1)` would not + // chain +constexpr int kNumNodeKinds = 0 FAST_NODE_KIND_LIST(COUNT_KIND); +#undef COUNT_KIND + +const char* NodeKindName(NodeKind kind); +bool IsStatementKind(NodeKind kind); +bool IsExpressionKind(NodeKind kind); + +#define FORWARD_DECLARE(name) struct name; +FAST_NODE_KIND_LIST(FORWARD_DECLARE) +#undef FORWARD_DECLARE + +// --------------------------------------------------------------------------- +// Operators. + +#define FAST_UNARY_OP_LIST(V) \ + V(kMinus, "-") \ + V(kPlus, "+") \ + V(kNot, "!") \ + V(kBitNot, "~") \ + V(kTypeof, "typeof") \ + V(kVoid, "void") \ + V(kDelete, "delete") + +#define FAST_UPDATE_OP_LIST(V) \ + V(kIncrement, "++") \ + V(kDecrement, "--") + +// Ordered by precedence group; see BinaryPrecedence(). +#define FAST_BINARY_OP_LIST(V) \ + V(kEq, "==") \ + V(kNotEq, "!=") \ + V(kStrictEq, "===") \ + V(kStrictNotEq, "!==") \ + V(kLessThan, "<") \ + V(kLessThanEq, "<=") \ + V(kGreaterThan, ">") \ + V(kGreaterThanEq, ">=") \ + V(kShiftLeft, "<<") \ + V(kShiftRight, ">>") \ + V(kShiftRightLogical, ">>>") \ + V(kAdd, "+") \ + V(kSub, "-") \ + V(kMul, "*") \ + V(kDiv, "/") \ + V(kMod, "%") \ + V(kExp, "**") \ + V(kBitOr, "|") \ + V(kBitXor, "^") \ + V(kBitAnd, "&") \ + V(kIn, "in") \ + V(kInstanceof, "instanceof") + +#define FAST_LOGICAL_OP_LIST(V) \ + V(kOr, "||") \ + V(kAnd, "&&") \ + V(kNullish, "??") + +#define FAST_ASSIGN_OP_LIST(V) \ + V(kAssign, "=") \ + V(kAddAssign, "+=") \ + V(kSubAssign, "-=") \ + V(kMulAssign, "*=") \ + V(kDivAssign, "/=") \ + V(kModAssign, "%=") \ + V(kExpAssign, "**=") \ + V(kShiftLeftAssign, "<<=") \ + V(kShiftRightAssign, ">>=") \ + V(kShiftRightLogicalAssign, ">>>=") \ + V(kBitOrAssign, "|=") \ + V(kBitXorAssign, "^=") \ + V(kBitAndAssign, "&=") \ + V(kOrAssign, "||=") \ + V(kAndAssign, "&&=") \ + V(kNullishAssign, "??=") + +#define DECLARE_ENUM(name, text) name, +enum class UnaryOp : uint8_t { FAST_UNARY_OP_LIST(DECLARE_ENUM) }; +enum class UpdateOp : uint8_t { FAST_UPDATE_OP_LIST(DECLARE_ENUM) }; +enum class BinaryOp : uint8_t { FAST_BINARY_OP_LIST(DECLARE_ENUM) }; +enum class LogicalOp : uint8_t { FAST_LOGICAL_OP_LIST(DECLARE_ENUM) }; +enum class AssignOp : uint8_t { FAST_ASSIGN_OP_LIST(DECLARE_ENUM) }; +#undef DECLARE_ENUM + +const char* OperatorText(UnaryOp op); +const char* OperatorText(UpdateOp op); +const char* OperatorText(BinaryOp op); +const char* OperatorText(LogicalOp op); +const char* OperatorText(AssignOp op); + +// Binary operator precedence (higher binds tighter), 1 = `??`, 2 = `||`, +// 3 = `&&`, 4 = `|`, 5 = `^`, 6 = `&`, 7 = equality, 8 = relational, +// 9 = shift, 10 = additive, 11 = multiplicative, 12 = `**`. +int BinaryPrecedence(BinaryOp op); +int LogicalPrecedence(LogicalOp op); + +enum class VariableKind : uint8_t { kVar, kLet, kConst, kUsing, kAwaitUsing }; +const char* VariableKindText(VariableKind kind); + +enum class PropertyKind : uint8_t { kInit, kGet, kSet }; +enum class MethodKind : uint8_t { kConstructor, kMethod, kGet, kSet }; +enum class MetaPropertyKind : uint8_t { kNewTarget, kImportMeta }; + +// --------------------------------------------------------------------------- +// Nodes. + +struct Node { + explicit Node(NodeKind k) : kind(k) {} + + NodeKind kind; + // Set by the parser for directive prologues / strictness tracking etc. + uint8_t flags = 0; + uint32_t id = 0; + // Byte offsets into the source this node was parsed from, or -1. + int32_t start = -1; + int32_t end = -1; + + bool Is(NodeKind k) const { return kind == k; } + template <typename T> + bool Is() const { + return kind == T::kKind; + } + template <typename T> + T* As() { + return kind == T::kKind ? static_cast<T*>(this) : nullptr; + } + template <typename T> + const T* As() const { + return kind == T::kKind ? static_cast<const T*>(this) : nullptr; + } + template <typename T> + T* Cast() { + return static_cast<T*>(this); + } + template <typename T> + const T* Cast() const { + return static_cast<const T*>(this); + } + bool IsStatement() const { return IsStatementKind(kind); } + bool IsExpression() const { return IsExpressionKind(kind); } + bool IsPattern() const; // ObjectPattern/ArrayPattern/AssignmentPattern/Rest + bool IsFunction() const; // FunctionDeclaration/FunctionExpression/Arrow + bool IsClass() const; // ClassDeclaration/ClassExpression + const char* kind_name() const { return NodeKindName(kind); } +}; + +struct Statement : Node { + using Node::Node; +}; +struct Expression : Node { + using Node::Node; +}; + +#define NODE_BOILERPLATE(name, base) \ + static constexpr NodeKind kKind = NodeKind::k##name; \ + name() : base(NodeKind::k##name) {} + +// --- Program --------------------------------------------------------------- + +struct Program : Node { + NODE_BOILERPLATE(Program, Node) + std::vector<Statement*> body; + bool strict = false; // has a "use strict" directive +}; + +// --- Statements ------------------------------------------------------------ + +struct ExpressionStatement : Statement { + NODE_BOILERPLATE(ExpressionStatement, Statement) + Expression* expression = nullptr; + // For directive prologue entries (e.g. "use strict"): the raw string + // literal text without quotes. Empty for ordinary statements. + std::string_view directive; + bool is_directive = false; +}; + +struct BlockStatement : Statement { + NODE_BOILERPLATE(BlockStatement, Statement) + std::vector<Statement*> body; +}; + +struct EmptyStatement : Statement { + NODE_BOILERPLATE(EmptyStatement, Statement) +}; + +struct DebuggerStatement : Statement { + NODE_BOILERPLATE(DebuggerStatement, Statement) +}; + +struct WithStatement : Statement { + NODE_BOILERPLATE(WithStatement, Statement) + Expression* object = nullptr; + Statement* body = nullptr; +}; + +struct ReturnStatement : Statement { + NODE_BOILERPLATE(ReturnStatement, Statement) + Expression* argument = nullptr; // nullable +}; + +struct LabeledStatement : Statement { + NODE_BOILERPLATE(LabeledStatement, Statement) + Identifier* label = nullptr; + Statement* body = nullptr; +}; + +struct BreakStatement : Statement { + NODE_BOILERPLATE(BreakStatement, Statement) + Identifier* label = nullptr; // nullable +}; + +struct ContinueStatement : Statement { + NODE_BOILERPLATE(ContinueStatement, Statement) + Identifier* label = nullptr; // nullable +}; + +struct IfStatement : Statement { + NODE_BOILERPLATE(IfStatement, Statement) + Expression* test = nullptr; + Statement* consequent = nullptr; + Statement* alternate = nullptr; // nullable +}; + +struct SwitchCase : Node { + NODE_BOILERPLATE(SwitchCase, Node) + Expression* test = nullptr; // nullptr for `default:` + std::vector<Statement*> consequent; +}; + +struct SwitchStatement : Statement { + NODE_BOILERPLATE(SwitchStatement, Statement) + Expression* discriminant = nullptr; + std::vector<SwitchCase*> cases; +}; + +struct ThrowStatement : Statement { + NODE_BOILERPLATE(ThrowStatement, Statement) + Expression* argument = nullptr; +}; + +struct CatchClause : Node { + NODE_BOILERPLATE(CatchClause, Node) + Expression* param = nullptr; // Identifier or pattern; nullptr if omitted + BlockStatement* body = nullptr; +}; + +struct TryStatement : Statement { + NODE_BOILERPLATE(TryStatement, Statement) + BlockStatement* block = nullptr; + CatchClause* handler = nullptr; // nullable + BlockStatement* finalizer = nullptr; // nullable +}; + +struct WhileStatement : Statement { + NODE_BOILERPLATE(WhileStatement, Statement) + Expression* test = nullptr; + Statement* body = nullptr; +}; + +struct DoWhileStatement : Statement { + NODE_BOILERPLATE(DoWhileStatement, Statement) + Statement* body = nullptr; + Expression* test = nullptr; +}; + +struct ForStatement : Statement { + NODE_BOILERPLATE(ForStatement, Statement) + Node* init = nullptr; // VariableDeclaration or Expression; nullable + Expression* test = nullptr; // nullable + Expression* update = nullptr; // nullable + Statement* body = nullptr; +}; + +struct ForInStatement : Statement { + NODE_BOILERPLATE(ForInStatement, Statement) + Node* left = nullptr; // VariableDeclaration or pattern/Identifier/Member + Expression* right = nullptr; + Statement* body = nullptr; +}; + +struct ForOfStatement : Statement { + NODE_BOILERPLATE(ForOfStatement, Statement) + Node* left = nullptr; + Expression* right = nullptr; + Statement* body = nullptr; + bool is_await = false; +}; + +// Fields shared by all function-like nodes. Not a Node itself. +struct FunctionData { + Identifier* name = nullptr; // nullable (not Node::id) + std::vector<Expression*> params; // Identifier / patterns / RestElement + BlockStatement* body = nullptr; // nullptr for concise arrow bodies + Expression* expression_body = nullptr; // concise arrow body + bool is_async = false; + bool is_generator = false; + bool is_arrow = false; + bool strict = false; // body (or enclosing code) is strict +}; + +struct FunctionDeclaration : Statement, FunctionData { + NODE_BOILERPLATE(FunctionDeclaration, Statement) +}; + +struct VariableDeclarator : Node { + NODE_BOILERPLATE(VariableDeclarator, Node) + Expression* target = nullptr; // Identifier or pattern + Expression* init = nullptr; // nullable +}; + +struct VariableDeclaration : Statement { + NODE_BOILERPLATE(VariableDeclaration, Statement) + VariableKind declaration_kind = VariableKind::kVar; + std::vector<VariableDeclarator*> declarations; +}; + +// Fields shared by class declarations and expressions. +struct ClassData { + Identifier* name = nullptr; // nullable (not Node::id) + Expression* super_class = nullptr; // nullable + ClassBody* body = nullptr; +}; + +struct ClassDeclaration : Statement, ClassData { + NODE_BOILERPLATE(ClassDeclaration, Statement) +}; + +// --- Expressions ----------------------------------------------------------- + +struct Identifier : Expression { + NODE_BOILERPLATE(Identifier, Expression) + std::string_view name; // cooked (escapes resolved), UTF-8 +}; + +struct PrivateIdentifier : Expression { + NODE_BOILERPLATE(PrivateIdentifier, Expression) + std::string_view name; // without the leading '#' +}; + +struct NullLiteral : Expression { + NODE_BOILERPLATE(NullLiteral, Expression) +}; + +struct BooleanLiteral : Expression { + NODE_BOILERPLATE(BooleanLiteral, Expression) + bool value = false; +}; + +struct NumericLiteral : Expression { + NODE_BOILERPLATE(NumericLiteral, Expression) + double value = 0; + std::string_view raw; // source text when parsed, empty when synthesized +}; + +struct BigIntLiteral : Expression { + NODE_BOILERPLATE(BigIntLiteral, Expression) + std::string_view raw; // including the trailing 'n' +}; + +struct StringLiteral : Expression { + NODE_BOILERPLATE(StringLiteral, Expression) + std::string value; // cooked, WTF-8 (lone surrogates encoded as 3 bytes) + std::string_view raw; // source text including quotes, or empty +}; + +struct RegExpLiteral : Expression { + NODE_BOILERPLATE(RegExpLiteral, Expression) + std::string_view pattern; + std::string_view regexp_flags; +}; + +struct ThisExpression : Expression { + NODE_BOILERPLATE(ThisExpression, Expression) +}; + +struct Super : Expression { + NODE_BOILERPLATE(Super, Expression) +}; + +struct ArrayExpression : Expression { + NODE_BOILERPLATE(ArrayExpression, Expression) + std::vector<Expression*> elements; // nullptr entries are holes +}; + +struct Property : Node { + NODE_BOILERPLATE(Property, Node) + Expression* key = nullptr; // Identifier, String/Numeric/BigInt literal, + // PrivateIdentifier, or any expr if computed + Expression* value = nullptr; // FunctionExpression for methods/accessors + PropertyKind property_kind = PropertyKind::kInit; + bool computed = false; + bool shorthand = false; + bool method = false; +}; + +struct ObjectExpression : Expression { + NODE_BOILERPLATE(ObjectExpression, Expression) + std::vector<Node*> properties; // Property or SpreadElement +}; + +struct FunctionExpression : Expression, FunctionData { + NODE_BOILERPLATE(FunctionExpression, Expression) +}; + +struct ArrowFunctionExpression : Expression, FunctionData { + NODE_BOILERPLATE(ArrowFunctionExpression, Expression) +}; + +struct ClassExpression : Expression, ClassData { + NODE_BOILERPLATE(ClassExpression, Expression) +}; + +struct UnaryExpression : Expression { + NODE_BOILERPLATE(UnaryExpression, Expression) + UnaryOp op = UnaryOp::kMinus; + Expression* argument = nullptr; +}; + +struct UpdateExpression : Expression { + NODE_BOILERPLATE(UpdateExpression, Expression) + UpdateOp op = UpdateOp::kIncrement; + bool prefix = false; + Expression* argument = nullptr; +}; + +struct BinaryExpression : Expression { + NODE_BOILERPLATE(BinaryExpression, Expression) + BinaryOp op = BinaryOp::kAdd; + Expression* left = nullptr; // PrivateIdentifier for `#x in obj` + Expression* right = nullptr; +}; + +struct LogicalExpression : Expression { + NODE_BOILERPLATE(LogicalExpression, Expression) + LogicalOp op = LogicalOp::kAnd; + Expression* left = nullptr; + Expression* right = nullptr; +}; + +struct AssignmentExpression : Expression { + NODE_BOILERPLATE(AssignmentExpression, Expression) + AssignOp op = AssignOp::kAssign; + Expression* left = nullptr; // Identifier, MemberExpression or pattern + Expression* right = nullptr; +}; + +struct MemberExpression : Expression { + NODE_BOILERPLATE(MemberExpression, Expression) + Expression* object = nullptr; // may be Super + Expression* property = nullptr; // Identifier/PrivateIdentifier or expr + bool computed = false; + bool optional = false; // `a?.b` +}; + +struct ConditionalExpression : Expression { + NODE_BOILERPLATE(ConditionalExpression, Expression) + Expression* test = nullptr; + Expression* consequent = nullptr; + Expression* alternate = nullptr; +}; + +struct CallExpression : Expression { + NODE_BOILERPLATE(CallExpression, Expression) + Expression* callee = nullptr; // may be Super + std::vector<Expression*> arguments; // SpreadElement allowed + bool optional = false; // `f?.()` +}; + +struct NewExpression : Expression { + NODE_BOILERPLATE(NewExpression, Expression) + Expression* callee = nullptr; + std::vector<Expression*> arguments; +}; + +struct SequenceExpression : Expression { + NODE_BOILERPLATE(SequenceExpression, Expression) + std::vector<Expression*> expressions; +}; + +struct YieldExpression : Expression { + NODE_BOILERPLATE(YieldExpression, Expression) + Expression* argument = nullptr; // nullable + bool delegate = false; +}; + +struct AwaitExpression : Expression { + NODE_BOILERPLATE(AwaitExpression, Expression) + Expression* argument = nullptr; +}; + +struct TemplateElement : Node { + NODE_BOILERPLATE(TemplateElement, Node) + std::string_view raw; + std::string cooked; + bool cooked_valid = true; // false for invalid escapes in tagged templates + bool tail = false; +}; + +struct TemplateLiteral : Expression { + NODE_BOILERPLATE(TemplateLiteral, Expression) + std::vector<TemplateElement*> + quasis; // quasis.size() == expressions.size() + 1 + std::vector<Expression*> expressions; +}; + +struct TaggedTemplateExpression : Expression { + NODE_BOILERPLATE(TaggedTemplateExpression, Expression) + Expression* tag = nullptr; + TemplateLiteral* quasi = nullptr; +}; + +struct MetaProperty : Expression { + NODE_BOILERPLATE(MetaProperty, Expression) + MetaPropertyKind meta_kind = MetaPropertyKind::kNewTarget; +}; + +struct ImportExpression : Expression { + NODE_BOILERPLATE(ImportExpression, Expression) + Expression* source = nullptr; + Expression* options = nullptr; // nullable + // `import.defer(...)` (deferred import evaluation proposal). + bool is_defer = false; +}; + +// Wraps an optional chain (`a?.b.c`) so that short-circuiting extent and +// parenthesization are explicit. +struct ChainExpression : Expression { + NODE_BOILERPLATE(ChainExpression, Expression) + Expression* expression = nullptr; // MemberExpression or CallExpression +}; + +struct SpreadElement : Expression { + NODE_BOILERPLATE(SpreadElement, Expression) + Expression* argument = nullptr; +}; + +struct ObjectPattern : Expression { + NODE_BOILERPLATE(ObjectPattern, Expression) + std::vector<Node*> + properties; // Property (value is a pattern) or RestElement +}; + +struct ArrayPattern : Expression { + NODE_BOILERPLATE(ArrayPattern, Expression) + std::vector<Expression*> elements; // nullptr entries are holes +}; + +struct RestElement : Expression { + NODE_BOILERPLATE(RestElement, Expression) + Expression* argument = nullptr; +}; + +struct AssignmentPattern : Expression { + NODE_BOILERPLATE(AssignmentPattern, Expression) + Expression* left = nullptr; + Expression* right = nullptr; +}; + +// `%Name(args)` with --allow-natives-syntax. +struct NativeCallExpression : Expression { + NODE_BOILERPLATE(NativeCallExpression, Expression) + std::string_view name; // without the '%' + std::vector<Expression*> arguments; +}; + +// --- Classes --------------------------------------------------------------- + +struct MethodDefinition : Node { + NODE_BOILERPLATE(MethodDefinition, Node) + Expression* key = nullptr; + FunctionExpression* value = nullptr; + MethodKind method_kind = MethodKind::kMethod; + bool computed = false; + bool is_static = false; +}; + +struct PropertyDefinition : Node { + NODE_BOILERPLATE(PropertyDefinition, Node) + Expression* key = nullptr; + Expression* value = nullptr; // nullable + bool computed = false; + bool is_static = false; + // `accessor x = 1;` auto-accessor (decorators proposal, --js-decorators). + bool is_auto_accessor = false; +}; + +struct StaticBlock : Node { + NODE_BOILERPLATE(StaticBlock, Node) + std::vector<Statement*> body; +}; + +struct ClassBody : Node { + NODE_BOILERPLATE(ClassBody, Node) + std::vector<Node*> + members; // MethodDefinition/PropertyDefinition/StaticBlock +}; + +#undef NODE_BOILERPLATE + +// --------------------------------------------------------------------------- +// Helpers. + +// Returns the FunctionData of a function-like node, or nullptr. +FunctionData* AsFunctionData(Node* node); +const FunctionData* AsFunctionData(const Node* node); +ClassData* AsClassData(Node* node); +const ClassData* AsClassData(const Node* node); + +// Calls `f(Node**)` for every child slot of `node`, in source order. Slots may +// hold nullptr (optional children, array holes); they are still visited so +// that callers can fill them. The callback may replace the slot's content. +template <typename F> +void ForEachChildSlot(Node* node, F&& f); + +// Calls `f(Node*)` for every non-null child, in source order. +template <typename F> +void ForEachChild(Node* node, F&& f) { + ForEachChildSlot(node, [&](Node** slot) { + if (*slot != nullptr) { + f(*slot); + } + }); +} + +// Pre-order traversal of the whole subtree; `f(Node*)` returns false to skip +// the node's children. +template <typename F> +void Walk(Node* node, F&& f) { + if (node == nullptr) { + return; + } + if (!f(node)) { + return; + } + ForEachChild(node, [&](Node* child) { Walk(child, f); }); +} + +size_t CountNodes(const Node* node); + +} // namespace fast +} // namespace redline + +#include "experimental/redline/fast/ast_visit.h" + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_AST_H_ diff --git a/deps/v8/experimental/redline/fast/ast_visit.h b/deps/v8/experimental/redline/fast/ast_visit.h new file mode 100644 index 000000000000..b9cb332b6291 --- /dev/null +++ b/deps/v8/experimental/redline/fast/ast_visit.h @@ -0,0 +1,336 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_AST_VISIT_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_AST_VISIT_H_ + +#include "experimental/redline/fast/ast.h" + +namespace redline { +namespace fast { + +namespace detail { + +// All node pointer types share the representation of Node* (single +// inheritance chain from Node comes first in every node class), so a slot +// holding a derived pointer can be handed out as a Node** slot. +template <typename T, typename F> +inline void VisitSlot(T*& slot, F& f) { + static_assert(std::is_base_of_v<Node, T>); + Node* child = slot; + f(&child); + slot = static_cast<T*>(child); +} + +template <typename T, typename F> +inline void VisitList(std::vector<T*>& list, F& f) { + static_assert(std::is_base_of_v<Node, T>); + for (T*& element : list) { + VisitSlot(element, f); + } +} + +template <typename F> +inline void VisitFunction(FunctionData* fn, F& f) { + VisitSlot(fn->name, f); + VisitList(fn->params, f); + VisitSlot(fn->body, f); + VisitSlot(fn->expression_body, f); +} + +template <typename F> +inline void VisitClass(ClassData* cls, F& f) { + VisitSlot(cls->name, f); + VisitSlot(cls->super_class, f); + VisitSlot(cls->body, f); +} + +} // namespace detail + +template <typename F> +void ForEachChildSlot(Node* node, F&& f) { + using detail::VisitList; + using detail::VisitSlot; + switch (node->kind) { + case NodeKind::kProgram: + VisitList(node->Cast<Program>()->body, f); + return; + case NodeKind::kExpressionStatement: + VisitSlot(node->Cast<ExpressionStatement>()->expression, f); + return; + case NodeKind::kBlockStatement: + VisitList(node->Cast<BlockStatement>()->body, f); + return; + case NodeKind::kEmptyStatement: + case NodeKind::kDebuggerStatement: + return; + case NodeKind::kWithStatement: { + auto* n = node->Cast<WithStatement>(); + VisitSlot(n->object, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kReturnStatement: + VisitSlot(node->Cast<ReturnStatement>()->argument, f); + return; + case NodeKind::kLabeledStatement: { + auto* n = node->Cast<LabeledStatement>(); + VisitSlot(n->label, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kBreakStatement: + VisitSlot(node->Cast<BreakStatement>()->label, f); + return; + case NodeKind::kContinueStatement: + VisitSlot(node->Cast<ContinueStatement>()->label, f); + return; + case NodeKind::kIfStatement: { + auto* n = node->Cast<IfStatement>(); + VisitSlot(n->test, f); + VisitSlot(n->consequent, f); + VisitSlot(n->alternate, f); + return; + } + case NodeKind::kSwitchStatement: { + auto* n = node->Cast<SwitchStatement>(); + VisitSlot(n->discriminant, f); + VisitList(n->cases, f); + return; + } + case NodeKind::kSwitchCase: { + auto* n = node->Cast<SwitchCase>(); + VisitSlot(n->test, f); + VisitList(n->consequent, f); + return; + } + case NodeKind::kThrowStatement: + VisitSlot(node->Cast<ThrowStatement>()->argument, f); + return; + case NodeKind::kTryStatement: { + auto* n = node->Cast<TryStatement>(); + VisitSlot(n->block, f); + VisitSlot(n->handler, f); + VisitSlot(n->finalizer, f); + return; + } + case NodeKind::kCatchClause: { + auto* n = node->Cast<CatchClause>(); + VisitSlot(n->param, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kWhileStatement: { + auto* n = node->Cast<WhileStatement>(); + VisitSlot(n->test, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kDoWhileStatement: { + auto* n = node->Cast<DoWhileStatement>(); + VisitSlot(n->body, f); + VisitSlot(n->test, f); + return; + } + case NodeKind::kForStatement: { + auto* n = node->Cast<ForStatement>(); + VisitSlot(n->init, f); + VisitSlot(n->test, f); + VisitSlot(n->update, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kForInStatement: { + auto* n = node->Cast<ForInStatement>(); + VisitSlot(n->left, f); + VisitSlot(n->right, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kForOfStatement: { + auto* n = node->Cast<ForOfStatement>(); + VisitSlot(n->left, f); + VisitSlot(n->right, f); + VisitSlot(n->body, f); + return; + } + case NodeKind::kFunctionDeclaration: + detail::VisitFunction(node->Cast<FunctionDeclaration>(), f); + return; + case NodeKind::kVariableDeclaration: + VisitList(node->Cast<VariableDeclaration>()->declarations, f); + return; + case NodeKind::kVariableDeclarator: { + auto* n = node->Cast<VariableDeclarator>(); + VisitSlot(n->target, f); + VisitSlot(n->init, f); + return; + } + case NodeKind::kClassDeclaration: + detail::VisitClass(node->Cast<ClassDeclaration>(), f); + return; + case NodeKind::kIdentifier: + case NodeKind::kPrivateIdentifier: + case NodeKind::kNullLiteral: + case NodeKind::kBooleanLiteral: + case NodeKind::kNumericLiteral: + case NodeKind::kBigIntLiteral: + case NodeKind::kStringLiteral: + case NodeKind::kRegExpLiteral: + case NodeKind::kThisExpression: + case NodeKind::kSuper: + case NodeKind::kMetaProperty: + case NodeKind::kTemplateElement: + return; + case NodeKind::kArrayExpression: + VisitList(node->Cast<ArrayExpression>()->elements, f); + return; + case NodeKind::kObjectExpression: + VisitList(node->Cast<ObjectExpression>()->properties, f); + return; + case NodeKind::kProperty: { + auto* n = node->Cast<Property>(); + VisitSlot(n->key, f); + VisitSlot(n->value, f); + return; + } + case NodeKind::kFunctionExpression: + detail::VisitFunction(node->Cast<FunctionExpression>(), f); + return; + case NodeKind::kArrowFunctionExpression: + detail::VisitFunction(node->Cast<ArrowFunctionExpression>(), f); + return; + case NodeKind::kClassExpression: + detail::VisitClass(node->Cast<ClassExpression>(), f); + return; + case NodeKind::kUnaryExpression: + VisitSlot(node->Cast<UnaryExpression>()->argument, f); + return; + case NodeKind::kUpdateExpression: + VisitSlot(node->Cast<UpdateExpression>()->argument, f); + return; + case NodeKind::kBinaryExpression: { + auto* n = node->Cast<BinaryExpression>(); + VisitSlot(n->left, f); + VisitSlot(n->right, f); + return; + } + case NodeKind::kLogicalExpression: { + auto* n = node->Cast<LogicalExpression>(); + VisitSlot(n->left, f); + VisitSlot(n->right, f); + return; + } + case NodeKind::kAssignmentExpression: { + auto* n = node->Cast<AssignmentExpression>(); + VisitSlot(n->left, f); + VisitSlot(n->right, f); + return; + } + case NodeKind::kMemberExpression: { + auto* n = node->Cast<MemberExpression>(); + VisitSlot(n->object, f); + VisitSlot(n->property, f); + return; + } + case NodeKind::kConditionalExpression: { + auto* n = node->Cast<ConditionalExpression>(); + VisitSlot(n->test, f); + VisitSlot(n->consequent, f); + VisitSlot(n->alternate, f); + return; + } + case NodeKind::kCallExpression: { + auto* n = node->Cast<CallExpression>(); + VisitSlot(n->callee, f); + VisitList(n->arguments, f); + return; + } + case NodeKind::kNewExpression: { + auto* n = node->Cast<NewExpression>(); + VisitSlot(n->callee, f); + VisitList(n->arguments, f); + return; + } + case NodeKind::kSequenceExpression: + VisitList(node->Cast<SequenceExpression>()->expressions, f); + return; + case NodeKind::kYieldExpression: + VisitSlot(node->Cast<YieldExpression>()->argument, f); + return; + case NodeKind::kAwaitExpression: + VisitSlot(node->Cast<AwaitExpression>()->argument, f); + return; + case NodeKind::kTemplateLiteral: { + // Interleave quasis and expressions in source order. + auto* n = node->Cast<TemplateLiteral>(); + for (size_t i = 0; i < n->quasis.size(); i++) { + VisitSlot(n->quasis[i], f); + if (i < n->expressions.size()) { + VisitSlot(n->expressions[i], f); + } + } + return; + } + case NodeKind::kTaggedTemplateExpression: { + auto* n = node->Cast<TaggedTemplateExpression>(); + VisitSlot(n->tag, f); + VisitSlot(n->quasi, f); + return; + } + case NodeKind::kImportExpression: { + auto* n = node->Cast<ImportExpression>(); + VisitSlot(n->source, f); + VisitSlot(n->options, f); + return; + } + case NodeKind::kChainExpression: + VisitSlot(node->Cast<ChainExpression>()->expression, f); + return; + case NodeKind::kSpreadElement: + VisitSlot(node->Cast<SpreadElement>()->argument, f); + return; + case NodeKind::kObjectPattern: + VisitList(node->Cast<ObjectPattern>()->properties, f); + return; + case NodeKind::kArrayPattern: + VisitList(node->Cast<ArrayPattern>()->elements, f); + return; + case NodeKind::kRestElement: + VisitSlot(node->Cast<RestElement>()->argument, f); + return; + case NodeKind::kAssignmentPattern: { + auto* n = node->Cast<AssignmentPattern>(); + VisitSlot(n->left, f); + VisitSlot(n->right, f); + return; + } + case NodeKind::kNativeCallExpression: + VisitList(node->Cast<NativeCallExpression>()->arguments, f); + return; + case NodeKind::kClassBody: + VisitList(node->Cast<ClassBody>()->members, f); + return; + case NodeKind::kMethodDefinition: { + auto* n = node->Cast<MethodDefinition>(); + VisitSlot(n->key, f); + VisitSlot(n->value, f); + return; + } + case NodeKind::kPropertyDefinition: { + auto* n = node->Cast<PropertyDefinition>(); + VisitSlot(n->key, f); + VisitSlot(n->value, f); + return; + } + case NodeKind::kStaticBlock: + VisitList(node->Cast<StaticBlock>()->body, f); + return; + } +} + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_AST_VISIT_H_ diff --git a/deps/v8/experimental/redline/fast/lexer.cc b/deps/v8/experimental/redline/fast/lexer.cc new file mode 100644 index 000000000000..3644d2a37901 --- /dev/null +++ b/deps/v8/experimental/redline/fast/lexer.cc @@ -0,0 +1,1170 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/lexer.h" + +#include <cstring> +#include <string_view> + +#include "src/base/vector.h" +#include "src/numbers/conversions.h" +#include "src/strings/char-predicates-inl.h" + +namespace redline { +namespace fast { + +namespace { + +constexpr uint32_t kEndOfInput = 0xFFFFFFFFu; + +bool IsLineTerminator(uint32_t c) { + return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029; +} + +bool IsAsciiIdentifierStart(uint32_t c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || + c == '$'; +} + +bool IsAsciiIdentifierPart(uint32_t c) { + return IsAsciiIdentifierStart(c) || (c >= '0' && c <= '9'); +} + +bool IsIdStart(uint32_t c) { + if (c < 128) { + return IsAsciiIdentifierStart(c); + } + if (c == kEndOfInput) { + return false; + } + return v8::internal::IsIdentifierStart(static_cast<v8::base::uc32>(c)); +} + +bool IsIdPart(uint32_t c) { + if (c < 128) { + return IsAsciiIdentifierPart(c); + } + if (c == kEndOfInput) { + return false; + } + return v8::internal::IsIdentifierPart(static_cast<v8::base::uc32>(c)); +} + +bool IsJsWhiteSpace(uint32_t c) { + if (c == ' ' || c == '\t' || c == 0x0B || c == 0x0C) { + return true; + } + if (c < 128 || c == kEndOfInput) { + return false; + } + return v8::internal::IsWhiteSpace(static_cast<v8::base::uc32>(c)); +} + +int HexValue(uint32_t c) { + if (c >= '0' && c <= '9') { + return static_cast<int>(c - '0'); + } + if (c >= 'a' && c <= 'f') { + return static_cast<int>(c - 'a' + 10); + } + if (c >= 'A' && c <= 'F') { + return static_cast<int>(c - 'A' + 10); + } + return -1; +} + +struct KeywordEntry { + const char* text; + Tok tok; +}; + +const KeywordEntry kKeywords[] = { +#define KEYWORD_ENTRY(name, text) {text, Tok::name}, + FAST_KEYWORD_LIST(KEYWORD_ENTRY) +#undef KEYWORD_ENTRY +}; + +Tok LookupKeyword(std::string_view text) { + if (text.size() < 2 || text.size() > 10) { + return Tok::kName; + } + for (const KeywordEntry& entry : kKeywords) { + if (text == entry.text) { + return entry.tok; + } + } + return Tok::kName; +} + +} // namespace + +const char* TokName(Tok tok) { + switch (tok) { +#define TOKEN_NAME(name, text) \ + case Tok::name: \ + return text; + FAST_PUNCTUATOR_LIST(TOKEN_NAME) + FAST_KEYWORD_LIST(TOKEN_NAME) +#undef TOKEN_NAME + case Tok::kName: + return "identifier"; + case Tok::kPrivateName: + return "private name"; + case Tok::kNumber: + return "number"; + case Tok::kBigInt: + return "bigint"; + case Tok::kString: + return "string"; + case Tok::kTemplateHead: + case Tok::kNoSubstitutionTemplate: + case Tok::kTemplateMiddle: + case Tok::kTemplateTail: + return "template"; + case Tok::kRegExp: + return "regexp"; + case Tok::kEOF: + return "end of input"; + case Tok::kIllegal: + return "illegal token"; + } + return "?"; +} + +bool IsKeyword(Tok tok) { return tok >= Tok::kBreak && tok <= Tok::kWith; } + +bool IsAssignmentOperator(Tok tok) { + return tok >= Tok::kAssign && tok <= Tok::kAssignNullish; +} + +void AppendUtf8(std::string* out, uint32_t c) { + if (c < 0x80) { + out->push_back(static_cast<char>(c)); + } else if (c < 0x800) { + out->push_back(static_cast<char>(0xC0 | (c >> 6))); + out->push_back(static_cast<char>(0x80 | (c & 0x3F))); + } else if (c < 0x10000) { + // Includes lone surrogates (WTF-8). + out->push_back(static_cast<char>(0xE0 | (c >> 12))); + out->push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F))); + out->push_back(static_cast<char>(0x80 | (c & 0x3F))); + } else { + out->push_back(static_cast<char>(0xF0 | (c >> 18))); + out->push_back(static_cast<char>(0x80 | ((c >> 12) & 0x3F))); + out->push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F))); + out->push_back(static_cast<char>(0x80 | (c & 0x3F))); + } +} + +uint32_t DecodeUtf8(std::string_view text, size_t pos, size_t* length) { + if (pos >= text.size()) { + *length = 0; + return kEndOfInput; + } + uint8_t b0 = static_cast<uint8_t>(text[pos]); + if (b0 < 0x80) { + *length = 1; + return b0; + } + int extra; + uint32_t c; + if ((b0 & 0xE0) == 0xC0) { + extra = 1; + c = b0 & 0x1F; + } else if ((b0 & 0xF0) == 0xE0) { + extra = 2; + c = b0 & 0x0F; + } else if ((b0 & 0xF8) == 0xF0) { + extra = 3; + c = b0 & 0x07; + } else { + *length = 1; + return 0xFFFD; + } + for (int i = 1; i <= extra; i++) { + if (pos + static_cast<size_t>(i) >= text.size()) { + *length = 1; + return 0xFFFD; + } + uint8_t b = static_cast<uint8_t>(text[pos + static_cast<size_t>(i)]); + if ((b & 0xC0) != 0x80) { + *length = 1; + return 0xFFFD; + } + c = (c << 6) | (b & 0x3F); + } + uint32_t min_code = extra == 1 ? 0x80u : extra == 2 ? 0x800u : 0x10000u; + if (c < min_code || c > 0x10FFFFu) { + *length = 1; + return 0xFFFD; + } + *length = static_cast<size_t>(extra) + 1; + return c; +} + +Lexer::Lexer(std::string_view source) : source_(source) { + // Skip a UTF-8 BOM. + if (source_.size() >= 3 && static_cast<uint8_t>(source_[0]) == 0xEF && + static_cast<uint8_t>(source_[1]) == 0xBB && + static_cast<uint8_t>(source_[2]) == 0xBF) { + pos_ = 3; + } + // Hashbang comment. + if (source_.substr(pos_, 2) == "#!") { + size_t len; + while (pos_ < source_.size()) { + uint32_t c = Peek(&len); + if (IsLineTerminator(c)) { + break; + } + pos_ += len; + } + } +} + +uint32_t Lexer::Peek(size_t* length) const { + return DecodeUtf8(source_, pos_, length); +} + +uint32_t Lexer::PeekAt(size_t pos, size_t* length) const { + return DecodeUtf8(source_, pos, length); +} + +void Lexer::SetError(const std::string& message, size_t pos) { + if (error_.empty()) { + error_ = message; + error_pos_ = static_cast<int32_t>(pos); + } +} + +void Lexer::SkipWhitespaceAndComments(bool* newline_seen) { + size_t len; + while (pos_ < source_.size()) { + uint32_t c = Peek(&len); + if (IsLineTerminator(c)) { + *newline_seen = true; + at_line_start_ = true; + pos_ += len; + continue; + } + if (IsJsWhiteSpace(c) || c == 0xA0 || c == 0xFEFF) { + pos_ += len; + continue; + } + if (c == '/') { + size_t len2; + uint32_t c2 = PeekAt(pos_ + 1, &len2); + if (c2 == '/') { + pos_ += 2; + while (pos_ < source_.size()) { + c = Peek(&len); + if (IsLineTerminator(c)) { + break; + } + pos_ += len; + } + continue; + } + if (c2 == '*') { + size_t comment_start = pos_; + pos_ += 2; + bool closed = false; + while (pos_ < source_.size()) { + c = Peek(&len); + if (c == '*' && pos_ + 1 < source_.size() && + source_[pos_ + 1] == '/') { + pos_ += 2; + closed = true; + break; + } + if (IsLineTerminator(c)) { + *newline_seen = true; + at_line_start_ = true; + } + pos_ += len; + } + if (!closed) { + SetError("Unterminated comment", comment_start); + } + continue; + } + return; + } + // Annex B HTML-like comments (script goal only). + if (c == '<' && source_.substr(pos_, 4) == "<!--") { + pos_ += 4; + while (pos_ < source_.size()) { + c = Peek(&len); + if (IsLineTerminator(c)) { + break; + } + pos_ += len; + } + continue; + } + if (c == '-' && at_line_start_ && source_.substr(pos_, 3) == "-->") { + pos_ += 3; + while (pos_ < source_.size()) { + c = Peek(&len); + if (IsLineTerminator(c)) { + break; + } + pos_ += len; + } + continue; + } + return; + } +} + +const Token& Lexer::Next() { + bool newline_seen = false; + SkipWhitespaceAndComments(&newline_seen); + token_ = Token(); + token_.newline_before = newline_seen; + token_start_ = pos_; + token_.start = static_cast<int32_t>(pos_); + if (pos_ >= source_.size()) { + token_.type = Tok::kEOF; + token_.end = token_.start; + return token_; + } + ScanToken(); + at_line_start_ = false; + return token_; +} + +void Lexer::Finish(Tok type) { + token_.type = type; + token_.end = static_cast<int32_t>(pos_); +} + +void Lexer::ScanToken() { + size_t len; + uint32_t c = Peek(&len); + switch (c) { + case '{': + pos_++; + return Finish(Tok::kLeftBrace); + case '}': + pos_++; + return Finish(Tok::kRightBrace); + case '(': + pos_++; + return Finish(Tok::kLeftParen); + case ')': + pos_++; + return Finish(Tok::kRightParen); + case '[': + pos_++; + return Finish(Tok::kLeftBracket); + case ']': + pos_++; + return Finish(Tok::kRightBracket); + case ';': + pos_++; + return Finish(Tok::kSemicolon); + case ',': + pos_++; + return Finish(Tok::kComma); + case ':': + pos_++; + return Finish(Tok::kColon); + case '~': + pos_++; + return Finish(Tok::kBitNot); + case '@': + pos_++; + return Finish(Tok::kAt); + case '.': { + size_t l2; + uint32_t c2 = PeekAt(pos_ + 1, &l2); + if (c2 >= '0' && c2 <= '9') { + return ScanNumber(c); + } + if (source_.substr(pos_, 3) == "...") { + pos_ += 3; + return Finish(Tok::kEllipsis); + } + pos_++; + return Finish(Tok::kPeriod); + } + case '?': { + if (source_.substr(pos_, 3) == "??=") { + pos_ += 3; + return Finish(Tok::kAssignNullish); + } + if (source_.substr(pos_, 2) == "??") { + pos_ += 2; + return Finish(Tok::kNullish); + } + if (source_.substr(pos_, 2) == "?.") { + size_t l2; + uint32_t c2 = PeekAt(pos_ + 2, &l2); + if (!(c2 >= '0' && c2 <= '9')) { + pos_ += 2; + return Finish(Tok::kQuestionPeriod); + } + } + pos_++; + return Finish(Tok::kQuestion); + } + case '<': + if (source_.substr(pos_, 3) == "<<=") { + pos_ += 3; + return Finish(Tok::kAssignShl); + } + if (source_.substr(pos_, 2) == "<<") { + pos_ += 2; + return Finish(Tok::kShl); + } + if (source_.substr(pos_, 2) == "<=") { + pos_ += 2; + return Finish(Tok::kLessThanEq); + } + pos_++; + return Finish(Tok::kLessThan); + case '>': + if (source_.substr(pos_, 4) == ">>>=") { + pos_ += 4; + return Finish(Tok::kAssignShr); + } + if (source_.substr(pos_, 3) == ">>>") { + pos_ += 3; + return Finish(Tok::kShr); + } + if (source_.substr(pos_, 3) == ">>=") { + pos_ += 3; + return Finish(Tok::kAssignSar); + } + if (source_.substr(pos_, 2) == ">>") { + pos_ += 2; + return Finish(Tok::kSar); + } + if (source_.substr(pos_, 2) == ">=") { + pos_ += 2; + return Finish(Tok::kGreaterThanEq); + } + pos_++; + return Finish(Tok::kGreaterThan); + case '=': + if (source_.substr(pos_, 3) == "===") { + pos_ += 3; + return Finish(Tok::kStrictEq); + } + if (source_.substr(pos_, 2) == "==") { + pos_ += 2; + return Finish(Tok::kEq); + } + if (source_.substr(pos_, 2) == "=>") { + pos_ += 2; + return Finish(Tok::kArrow); + } + pos_++; + return Finish(Tok::kAssign); + case '!': + if (source_.substr(pos_, 3) == "!==") { + pos_ += 3; + return Finish(Tok::kStrictNotEq); + } + if (source_.substr(pos_, 2) == "!=") { + pos_ += 2; + return Finish(Tok::kNotEq); + } + pos_++; + return Finish(Tok::kNot); + case '+': + if (source_.substr(pos_, 2) == "++") { + pos_ += 2; + return Finish(Tok::kInc); + } + if (source_.substr(pos_, 2) == "+=") { + pos_ += 2; + return Finish(Tok::kAssignAdd); + } + pos_++; + return Finish(Tok::kAdd); + case '-': + if (source_.substr(pos_, 2) == "--") { + pos_ += 2; + return Finish(Tok::kDec); + } + if (source_.substr(pos_, 2) == "-=") { + pos_ += 2; + return Finish(Tok::kAssignSub); + } + pos_++; + return Finish(Tok::kSub); + case '*': + if (source_.substr(pos_, 3) == "**=") { + pos_ += 3; + return Finish(Tok::kAssignExp); + } + if (source_.substr(pos_, 2) == "**") { + pos_ += 2; + return Finish(Tok::kExp); + } + if (source_.substr(pos_, 2) == "*=") { + pos_ += 2; + return Finish(Tok::kAssignMul); + } + pos_++; + return Finish(Tok::kMul); + case '/': + if (source_.substr(pos_, 2) == "/=") { + pos_ += 2; + return Finish(Tok::kAssignDiv); + } + pos_++; + return Finish(Tok::kDiv); + case '%': + if (source_.substr(pos_, 2) == "%=") { + pos_ += 2; + return Finish(Tok::kAssignMod); + } + pos_++; + return Finish(Tok::kMod); + case '&': + if (source_.substr(pos_, 3) == "&&=") { + pos_ += 3; + return Finish(Tok::kAssignAnd); + } + if (source_.substr(pos_, 2) == "&&") { + pos_ += 2; + return Finish(Tok::kAnd); + } + if (source_.substr(pos_, 2) == "&=") { + pos_ += 2; + return Finish(Tok::kAssignBitAnd); + } + pos_++; + return Finish(Tok::kBitAnd); + case '|': + if (source_.substr(pos_, 3) == "||=") { + pos_ += 3; + return Finish(Tok::kAssignOr); + } + if (source_.substr(pos_, 2) == "||") { + pos_ += 2; + return Finish(Tok::kOr); + } + if (source_.substr(pos_, 2) == "|=") { + pos_ += 2; + return Finish(Tok::kAssignBitOr); + } + pos_++; + return Finish(Tok::kBitOr); + case '^': + if (source_.substr(pos_, 2) == "^=") { + pos_ += 2; + return Finish(Tok::kAssignBitXor); + } + pos_++; + return Finish(Tok::kBitXor); + case '"': + case '\'': + return ScanString(c); + case '`': + pos_++; + return ScanTemplateSpan(true); + case '#': { + pos_++; + size_t l2; + uint32_t c2 = Peek(&l2); + if (IsIdStart(c2) || c2 == '\\') { + return ScanIdentifierOrKeyword(c2, l2, true); + } + SetError("Invalid or unexpected token", token_start_); + return Finish(Tok::kIllegal); + } + case '\\': { + return ScanIdentifierOrKeyword(c, len, false); + } + default: + break; + } + if (c >= '0' && c <= '9') { + return ScanNumber(c); + } + if (IsIdStart(c)) { + return ScanIdentifierOrKeyword(c, len, false); + } + SetError("Invalid or unexpected token", token_start_); + pos_ += len == 0 ? 1 : len; + Finish(Tok::kIllegal); +} + +bool Lexer::ScanUnicodeEscapeInIdentifier(uint32_t* code_point) { + // pos_ is at the backslash. + if (pos_ + 1 >= source_.size() || source_[pos_ + 1] != 'u') { + return false; + } + size_t p = pos_ + 2; + uint32_t value = 0; + if (p < source_.size() && source_[p] == '{') { + p++; + int digits = 0; + while (p < source_.size() && source_[p] != '}') { + int h = HexValue(static_cast<uint8_t>(source_[p])); + if (h < 0) { + return false; + } + value = value * 16 + static_cast<uint32_t>(h); + if (value > 0x10FFFF) { + return false; + } + digits++; + p++; + } + if (p >= source_.size() || digits == 0) { + return false; + } + p++; // '}' + } else { + for (int i = 0; i < 4; i++) { + if (p >= source_.size()) { + return false; + } + int h = HexValue(static_cast<uint8_t>(source_[p])); + if (h < 0) { + return false; + } + value = value * 16 + static_cast<uint32_t>(h); + p++; + } + } + pos_ = p; + *code_point = value; + return true; +} + +void Lexer::ScanIdentifierOrKeyword(uint32_t first, size_t first_len, + bool is_private) { + std::string name; + bool has_escape = false; + bool is_first = true; + (void)first; + (void)first_len; + while (pos_ < source_.size()) { + size_t len; + uint32_t c = Peek(&len); + if (c == '\\') { + uint32_t code_point; + if (!ScanUnicodeEscapeInIdentifier(&code_point) || + !(is_first ? IsIdStart(code_point) : IsIdPart(code_point))) { + SetError("Invalid Unicode escape sequence", pos_); + pos_++; + return Finish(Tok::kIllegal); + } + has_escape = true; + AppendUtf8(&name, code_point); + } else if (is_first ? IsIdStart(c) : IsIdPart(c)) { + name.append(source_.substr(pos_, len)); + pos_ += len; + } else { + break; + } + is_first = false; + } + token_.has_escape = has_escape; + token_.value = std::move(name); + if (is_private) { + return Finish(Tok::kPrivateName); + } + Tok keyword = has_escape ? Tok::kName : LookupKeyword(token_.value); + Finish(keyword); +} + +void Lexer::ScanNumber(uint32_t first) { + size_t start = pos_; + std::string digits; // cleaned text for conversion + auto is_digit = [](uint32_t c) { return c >= '0' && c <= '9'; }; + auto scan_digits = [&](auto predicate, bool allow_separator) -> bool { + bool any = false; + bool last_was_separator = false; + while (pos_ < source_.size()) { + uint8_t c = static_cast<uint8_t>(source_[pos_]); + if (predicate(c)) { + digits.push_back(static_cast<char>(c)); + any = true; + last_was_separator = false; + pos_++; + } else if (c == '_' && allow_separator && any && !last_was_separator) { + last_was_separator = true; + pos_++; + } else { + break; + } + } + if (last_was_separator) { + SetError( + "Numeric separators are not allowed at the end of numeric " + "literals", + pos_ - 1); + return false; + } + return any; + }; + + auto check_no_trailing_id_or_digit = [&]() -> bool { + size_t len; + uint32_t next = Peek(&len); + if (IsIdStart(next) || (next >= '0' && next <= '9')) { + SetError("Invalid or unexpected token", pos_); + Finish(Tok::kIllegal); + return false; + } + return true; + }; + + bool is_bigint_allowed = true; + if (first == '0' && pos_ + 1 < source_.size()) { + char p = source_[pos_ + 1]; + int radix = 0; + if (p == 'x' || p == 'X') { + radix = 16; + } + if (p == 'o' || p == 'O') { + radix = 8; + } + if (p == 'b' || p == 'B') { + radix = 2; + } + if (radix != 0) { + digits.append(source_.substr(pos_, 2)); + pos_ += 2; + bool ok = scan_digits( + [radix](uint8_t c) { + int h = HexValue(c); + return h >= 0 && h < radix; + }, + true); + if (!ok) { + SetError("Invalid or unexpected token", start); + return Finish(Tok::kIllegal); + } + if (pos_ < source_.size() && source_[pos_] == 'n') { + pos_++; + if (!check_no_trailing_id_or_digit()) { + return; + } + token_.value = digits; + return Finish(Tok::kBigInt); + } + if (!check_no_trailing_id_or_digit()) { + return; + } + // The const char* overload is the exported one (component builds). + token_.number_value = v8::internal::StringToDouble( + digits.c_str(), v8::internal::ALLOW_NON_DECIMAL_PREFIX); + return Finish(Tok::kNumber); + } + if (p == '_') { + SetError("Numeric separator can not be used after leading 0", pos_ + 1); + return Finish(Tok::kIllegal); + } + if (is_digit(static_cast<uint8_t>(p))) { + // Legacy octal (017) or legacy decimal with leading zero (089). + pos_++; + bool octal = true; + std::string legacy; + while (pos_ < source_.size() && + is_digit(static_cast<uint8_t>(source_[pos_]))) { + if (source_[pos_] >= '8') { + octal = false; + } + legacy.push_back(source_[pos_]); + pos_++; + } + if (pos_ < source_.size() && source_[pos_] == '_') { + SetError("Numeric separator can not be used after leading 0", pos_); + return Finish(Tok::kIllegal); + } + token_.legacy_octal = true; + is_bigint_allowed = false; + if (octal) { + if (!check_no_trailing_id_or_digit()) { + return; + } + double value = 0; + for (char d : legacy) { + value = value * 8 + (d - '0'); + } + token_.number_value = value; + return Finish(Tok::kNumber); + } + // Legacy decimal: may continue with a fraction/exponent. + digits = legacy; + } + } + if (digits.empty() && first != '.') { + scan_digits(is_digit, true); + } + bool integer_only = true; + if (pos_ < source_.size() && source_[pos_] == '.') { + integer_only = false; + digits.push_back('.'); + pos_++; + scan_digits(is_digit, true); + } + if (pos_ < source_.size() && (source_[pos_] == 'e' || source_[pos_] == 'E')) { + size_t save = pos_; + std::string exponent = "e"; + pos_++; + if (pos_ < source_.size() && + (source_[pos_] == '+' || source_[pos_] == '-')) { + exponent.push_back(source_[pos_]); + pos_++; + } + std::string saved_digits = digits; + digits.clear(); + if (!scan_digits(is_digit, true)) { + SetError("Invalid or unexpected token", save); + return Finish(Tok::kIllegal); + } + exponent += digits; + digits = saved_digits + exponent; + integer_only = false; + } + if (integer_only && is_bigint_allowed && pos_ < source_.size() && + source_[pos_] == 'n') { + pos_++; + if (!check_no_trailing_id_or_digit()) { + return; + } + token_.value = digits; + return Finish(Tok::kBigInt); + } + if (digits.empty() || digits == ".") { + SetError("Invalid or unexpected token", start); + return Finish(Tok::kIllegal); + } + if (!check_no_trailing_id_or_digit()) { + return; + } + // The const char* overload is the exported one (component builds). + token_.number_value = v8::internal::StringToDouble( + digits.c_str(), v8::internal::NO_CONVERSION_FLAG); + Finish(Tok::kNumber); +} + +// Scans an escape sequence; pos_ is at the backslash. Appends the cooked +// value to `out`. In templates, invalid escapes clear *cooked_valid instead of +// raising an error. +bool Lexer::ScanEscape(std::string* out, bool in_template, bool* cooked_valid) { + size_t escape_start = pos_; + pos_++; // backslash + size_t len; + uint32_t c = Peek(&len); + auto invalid = [&](const char* message) { + if (in_template) { + *cooked_valid = false; + return true; + } + SetError(message, escape_start); + return false; + }; + if (c == kEndOfInput) { + SetError("Invalid or unexpected token", escape_start); + return false; + } + pos_ += len; + switch (c) { + case 'n': + out->push_back('\n'); + return true; + case 't': + out->push_back('\t'); + return true; + case 'r': + out->push_back('\r'); + return true; + case 'b': + out->push_back('\b'); + return true; + case 'f': + out->push_back('\f'); + return true; + case 'v': + out->push_back('\v'); + return true; + case '\r': + // Line continuation; \r\n counts as one terminator. + if (pos_ < source_.size() && source_[pos_] == '\n') { + pos_++; + } + return true; + case '\n': + case 0x2028: + case 0x2029: + return true; + case 'x': { + int h1 = pos_ < source_.size() + ? HexValue(static_cast<uint8_t>(source_[pos_])) + : -1; + int h2 = pos_ + 1 < source_.size() + ? HexValue(static_cast<uint8_t>(source_[pos_ + 1])) + : -1; + if (h1 < 0 || h2 < 0) { + return invalid("Invalid hexadecimal escape sequence"); + } + pos_ += 2; + AppendUtf8(out, static_cast<uint32_t>(h1 * 16 + h2)); + return true; + } + case 'u': { + uint32_t value = 0; + if (pos_ < source_.size() && source_[pos_] == '{') { + pos_++; + int digits = 0; + while (pos_ < source_.size() && source_[pos_] != '}') { + int h = HexValue(static_cast<uint8_t>(source_[pos_])); + if (h < 0) { + return invalid("Invalid Unicode escape sequence"); + } + value = value * 16 + static_cast<uint32_t>(h); + if (value > 0x10FFFF) { + return invalid("Undefined Unicode code-point"); + } + digits++; + pos_++; + } + if (pos_ >= source_.size() || digits == 0) { + return invalid("Invalid Unicode escape sequence"); + } + pos_++; + } else { + for (int i = 0; i < 4; i++) { + int h = pos_ < source_.size() + ? HexValue(static_cast<uint8_t>(source_[pos_])) + : -1; + if (h < 0) { + return invalid("Invalid Unicode escape sequence"); + } + value = value * 16 + static_cast<uint32_t>(h); + pos_++; + } + // Combine surrogate pairs written as two escapes. + if (value >= 0xD800 && value <= 0xDBFF && pos_ + 5 < source_.size() && + source_[pos_] == '\\' && source_[pos_ + 1] == 'u') { + uint32_t low = 0; + bool ok = true; + for (int i = 0; i < 4; i++) { + int h = HexValue(static_cast<uint8_t>( + source_[pos_ + 2 + static_cast<size_t>(i)])); + if (h < 0) { + ok = false; + break; + } + low = low * 16 + static_cast<uint32_t>(h); + } + if (ok && low >= 0xDC00 && low <= 0xDFFF) { + pos_ += 6; + value = 0x10000 + ((value - 0xD800) << 10) + (low - 0xDC00); + } + } + } + AppendUtf8(out, value); + return true; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + // \0 not followed by a digit is the null character; everything else is + // a legacy octal escape (sloppy mode only, never in templates). + bool next_is_digit = + pos_ < source_.size() && source_[pos_] >= '0' && source_[pos_] <= '9'; + if (c == '0' && !next_is_digit) { + out->push_back('\0'); + return true; + } + if (in_template) { + *cooked_valid = false; + return true; + } + token_.legacy_octal_escape = true; + uint32_t value = c - '0'; + // Up to two more octal digits (three total, max \377). + int max_more = c <= '3' ? 2 : 1; + for (int i = 0; i < max_more; i++) { + if (pos_ < source_.size() && source_[pos_] >= '0' && + source_[pos_] <= '7') { + value = value * 8 + static_cast<uint32_t>(source_[pos_] - '0'); + pos_++; + } else { + break; + } + } + AppendUtf8(out, value); + return true; + } + case '8': + case '9': + if (in_template) { + *cooked_valid = false; + return true; + } + token_.legacy_octal_escape = true; + out->push_back(static_cast<char>(c)); + return true; + default: + AppendUtf8(out, c); + return true; + } +} + +void Lexer::ScanString(uint32_t quote) { + pos_++; // opening quote + std::string value; + while (true) { + size_t len; + uint32_t c = Peek(&len); + if (c == kEndOfInput || c == '\n' || c == '\r') { + SetError("Invalid or unexpected token", token_start_); + return Finish(Tok::kIllegal); + } + if (c == quote) { + pos_++; + break; + } + if (c == '\\') { + bool cooked_valid = true; + if (!ScanEscape(&value, false, &cooked_valid)) { + return Finish(Tok::kIllegal); + } + continue; + } + value.append(source_.substr(pos_, len)); + pos_ += len; + } + token_.value = std::move(value); + Finish(Tok::kString); +} + +// Scans a template span; pos_ is just after the opening '`' or the '}' that +// closes a substitution. +void Lexer::ScanTemplateSpan(bool is_head) { + std::string cooked; + bool cooked_valid = true; + while (true) { + size_t len; + uint32_t c = Peek(&len); + if (c == kEndOfInput) { + SetError("Unterminated template literal", token_start_); + return Finish(Tok::kIllegal); + } + if (c == '`') { + pos_++; + token_.value = std::move(cooked); + token_.cooked_valid = cooked_valid; + return Finish(is_head ? Tok::kNoSubstitutionTemplate + : Tok::kTemplateTail); + } + if (c == '$' && pos_ + 1 < source_.size() && source_[pos_ + 1] == '{') { + pos_ += 2; + token_.value = std::move(cooked); + token_.cooked_valid = cooked_valid; + return Finish(is_head ? Tok::kTemplateHead : Tok::kTemplateMiddle); + } + if (c == '\\') { + if (!ScanEscape(&cooked, true, &cooked_valid)) { + return Finish(Tok::kIllegal); + } + continue; + } + if (c == '\r') { + // Normalize CRLF / CR to LF in the cooked value. + pos_++; + if (pos_ < source_.size() && source_[pos_] == '\n') { + pos_++; + } + cooked.push_back('\n'); + continue; + } + cooked.append(source_.substr(pos_, len)); + pos_ += len; + } +} + +bool Lexer::RescanAsTemplateContinuation() { + if (token_.type != Tok::kRightBrace) { + return false; + } + pos_ = static_cast<size_t>(token_.start) + 1; + token_start_ = static_cast<size_t>(token_.start); + bool newline_before = token_.newline_before; + token_ = Token(); + token_.newline_before = newline_before; + token_.start = static_cast<int32_t>(token_start_); + ScanTemplateSpan(false); + return token_.type != Tok::kIllegal; +} + +bool Lexer::RescanAsRegExp() { + if (token_.type != Tok::kDiv && token_.type != Tok::kAssignDiv) { + return false; + } + pos_ = static_cast<size_t>(token_.start) + 1; + token_start_ = static_cast<size_t>(token_.start); + bool newline_before = token_.newline_before; + token_ = Token(); + token_.newline_before = newline_before; + token_.start = static_cast<int32_t>(token_start_); + std::string pattern; + bool in_class = false; + while (true) { + size_t len; + uint32_t c = Peek(&len); + if (c == kEndOfInput || IsLineTerminator(c)) { + SetError("Invalid regular expression: missing /", token_start_); + Finish(Tok::kIllegal); + return false; + } + if (c == '\\') { + pattern.push_back('\\'); + pos_++; + c = Peek(&len); + if (c == kEndOfInput || IsLineTerminator(c)) { + SetError("Invalid regular expression: missing /", token_start_); + Finish(Tok::kIllegal); + return false; + } + pattern.append(source_.substr(pos_, len)); + pos_ += len; + continue; + } + if (c == '[') { + in_class = true; + } else if (c == ']') { + in_class = false; + } else if (c == '/' && !in_class) { + pos_++; + break; + } + pattern.append(source_.substr(pos_, len)); + pos_ += len; + } + std::string flags; + while (pos_ < source_.size()) { + size_t len; + uint32_t c = Peek(&len); + if (!IsIdPart(c)) { + break; + } + flags.append(source_.substr(pos_, len)); + pos_ += len; + } + token_.value = std::move(pattern); + token_.flags = std::move(flags); + Finish(Tok::kRegExp); + return true; +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/lexer.h b/deps/v8/experimental/redline/fast/lexer.h new file mode 100644 index 000000000000..8fc72f19f19d --- /dev/null +++ b/deps/v8/experimental/redline/fast/lexer.h @@ -0,0 +1,234 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_LEXER_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_LEXER_H_ + +#include <cstdint> +#include <string> +#include <string_view> + +namespace redline { +namespace fast { + +// Punctuators: V(name, text). Keywords: K(name, text). +#define FAST_PUNCTUATOR_LIST(V) \ + V(kLeftBrace, "{") \ + V(kRightBrace, "}") \ + V(kLeftParen, "(") \ + V(kRightParen, ")") \ + V(kLeftBracket, "[") \ + V(kRightBracket, "]") \ + V(kPeriod, ".") \ + V(kEllipsis, "...") \ + V(kSemicolon, ";") \ + V(kComma, ",") \ + V(kLessThan, "<") \ + V(kGreaterThan, ">") \ + V(kLessThanEq, "<=") \ + V(kGreaterThanEq, ">=") \ + V(kEq, "==") \ + V(kNotEq, "!=") \ + V(kStrictEq, "===") \ + V(kStrictNotEq, "!==") \ + V(kAdd, "+") \ + V(kSub, "-") \ + V(kMul, "*") \ + V(kDiv, "/") \ + V(kMod, "%") \ + V(kExp, "**") \ + V(kInc, "++") \ + V(kDec, "--") \ + V(kShl, "<<") \ + V(kSar, ">>") \ + V(kShr, ">>>") \ + V(kBitAnd, "&") \ + V(kBitOr, "|") \ + V(kBitXor, "^") \ + V(kNot, "!") \ + V(kBitNot, "~") \ + V(kAnd, "&&") \ + V(kOr, "||") \ + V(kNullish, "??") \ + V(kQuestion, "?") \ + V(kQuestionPeriod, "?.") \ + V(kColon, ":") \ + V(kAssign, "=") \ + V(kAssignAdd, "+=") \ + V(kAssignSub, "-=") \ + V(kAssignMul, "*=") \ + V(kAssignDiv, "/=") \ + V(kAssignMod, "%=") \ + V(kAssignExp, "**=") \ + V(kAssignShl, "<<=") \ + V(kAssignSar, ">>=") \ + V(kAssignShr, ">>>=") \ + V(kAssignBitAnd, "&=") \ + V(kAssignBitOr, "|=") \ + V(kAssignBitXor, "^=") \ + V(kAssignAnd, "&&=") \ + V(kAssignOr, "||=") \ + V(kAssignNullish, "??=") \ + V(kArrow, "=>") \ + V(kAt, "@") + +#define FAST_KEYWORD_LIST(K) \ + K(kBreak, "break") \ + K(kCase, "case") \ + K(kCatch, "catch") \ + K(kClass, "class") \ + K(kConst, "const") \ + K(kContinue, "continue") \ + K(kDebugger, "debugger") \ + K(kDefault, "default") \ + K(kDelete, "delete") \ + K(kDo, "do") \ + K(kElse, "else") \ + K(kEnum, "enum") \ + K(kExport, "export") \ + K(kExtends, "extends") \ + K(kFalse, "false") \ + K(kFinally, "finally") \ + K(kFor, "for") \ + K(kFunction, "function") \ + K(kIf, "if") \ + K(kImport, "import") \ + K(kIn, "in") \ + K(kInstanceof, "instanceof") \ + K(kNew, "new") \ + K(kNull, "null") \ + K(kReturn, "return") \ + K(kSuper, "super") \ + K(kSwitch, "switch") \ + K(kThis, "this") \ + K(kThrow, "throw") \ + K(kTrue, "true") \ + K(kTry, "try") \ + K(kTypeof, "typeof") \ + K(kVar, "var") \ + K(kVoid, "void") \ + K(kWhile, "while") \ + K(kWith, "with") + +enum class Tok : uint8_t { +#define DECLARE_TOKEN(name, text) name, + FAST_PUNCTUATOR_LIST(DECLARE_TOKEN) FAST_KEYWORD_LIST(DECLARE_TOKEN) +#undef DECLARE_TOKEN + // Identifiers, including contextual keywords (let, yield, await, async, + // of, get, set, static, using, ...), and escaped reserved words. + kName, + kPrivateName, // #name + kNumber, + kBigInt, + kString, + kTemplateHead, // `...${ + kNoSubstitutionTemplate, // `...` + kTemplateMiddle, // }...${ + kTemplateTail, // }...` + kRegExp, + kEOF, + kIllegal, +}; + +const char* TokName(Tok tok); +bool IsKeyword(Tok tok); +bool IsAssignmentOperator(Tok tok); + +struct Token { + Tok type = Tok::kEOF; + int32_t start = 0; + int32_t end = 0; + // A line terminator precedes the token (for ASI and restricted productions). + bool newline_before = false; + // Identifier/keyword written with unicode escapes. + bool has_escape = false; + // Numeric literal with a legacy octal / leading-zero form (strict error). + bool legacy_octal = false; + // Strings/templates: contained a legacy octal escape or \8 \9. + bool legacy_octal_escape = false; + // Templates: the cooked value is invalid (only allowed in tagged templates). + bool cooked_valid = true; + double number_value = 0; + // Cooked value: identifier name (always set), string contents, template + // span contents, regexp pattern. + std::string value; + // RegExp flags. + std::string flags; +}; + +class Lexer { + public: + explicit Lexer(std::string_view source); + + // Scans the next token; '/' and '/=' are returned as division operators. + const Token& Next(); + const Token& current() const { return token_; } + + // Called by the parser when the current token is kDiv or kAssignDiv in a + // position where a regular expression literal is allowed. + bool RescanAsRegExp(); + // Called by the parser when the current token is kRightBrace closing a + // template substitution. + bool RescanAsTemplateContinuation(); + + struct State { + size_t pos; + Token token; + bool at_line_start; + }; + State Save() const { return State{pos_, token_, at_line_start_}; } + void Restore(const State& state) { + pos_ = state.pos; + token_ = state.token; + at_line_start_ = state.at_line_start; + } + + bool has_error() const { return !error_.empty(); } + const std::string& error() const { return error_; } + int32_t error_pos() const { return error_pos_; } + + std::string_view source() const { return source_; } + std::string_view TokenText(const Token& token) const { + return source_.substr(static_cast<size_t>(token.start), + static_cast<size_t>(token.end - token.start)); + } + + // Number of bytes consumed so far. + size_t position() const { return pos_; } + + private: + // Returns the code point at pos_ and its length in bytes (0 at EOF). + uint32_t Peek(size_t* length) const; + uint32_t PeekAt(size_t pos, size_t* length) const; + void SkipWhitespaceAndComments(bool* newline_seen); + void ScanToken(); + void ScanIdentifierOrKeyword(uint32_t first, size_t first_len, + bool is_private); + void ScanNumber(uint32_t first); + void ScanString(uint32_t quote); + void ScanTemplateSpan(bool is_head); + bool ScanEscape(std::string* out, bool in_template, bool* cooked_valid); + bool ScanUnicodeEscapeInIdentifier(uint32_t* code_point); + void SetError(const std::string& message, size_t pos); + void Finish(Tok type); + + std::string_view source_; + size_t pos_ = 0; + size_t token_start_ = 0; + bool at_line_start_ = true; + Token token_; + std::string error_; + int32_t error_pos_ = -1; +}; + +// UTF-8 helpers shared with the printer. +void AppendUtf8(std::string* out, uint32_t code_point); +// Decodes one code point at `pos` (returns U+FFFD for malformed input and +// consumes one byte). +uint32_t DecodeUtf8(std::string_view text, size_t pos, size_t* length); + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_LEXER_H_ diff --git a/deps/v8/experimental/redline/fast/parser.cc b/deps/v8/experimental/redline/fast/parser.cc new file mode 100644 index 000000000000..e88dc92bc9a7 --- /dev/null +++ b/deps/v8/experimental/redline/fast/parser.cc @@ -0,0 +1,2891 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/parser.h" + +#include <algorithm> +#include <utility> + +#include "experimental/redline/base/log.h" + +namespace redline { +namespace fast { + +namespace { + +constexpr int kMaxDepth = 1200; + +struct DepthGuard { + explicit DepthGuard(int* depth) : depth_(depth) { (*depth_)++; } + ~DepthGuard() { (*depth_)--; } + int* depth_; +}; + +bool IsStrictReservedWord(std::string_view name) { + return name == "let" || name == "static" || name == "implements" || + name == "interface" || name == "package" || name == "private" || + name == "protected" || name == "public"; +} + +int BinaryPrecedenceOfToken(Tok tok, bool no_in, BinaryOp* bin_op, + LogicalOp* log_op, bool* is_logical) { + *is_logical = false; + switch (tok) { + case Tok::kNullish: + *is_logical = true; + *log_op = LogicalOp::kNullish; + return 1; + case Tok::kOr: + *is_logical = true; + *log_op = LogicalOp::kOr; + return 2; + case Tok::kAnd: + *is_logical = true; + *log_op = LogicalOp::kAnd; + return 3; + case Tok::kBitOr: + *bin_op = BinaryOp::kBitOr; + return 4; + case Tok::kBitXor: + *bin_op = BinaryOp::kBitXor; + return 5; + case Tok::kBitAnd: + *bin_op = BinaryOp::kBitAnd; + return 6; + case Tok::kEq: + *bin_op = BinaryOp::kEq; + return 7; + case Tok::kNotEq: + *bin_op = BinaryOp::kNotEq; + return 7; + case Tok::kStrictEq: + *bin_op = BinaryOp::kStrictEq; + return 7; + case Tok::kStrictNotEq: + *bin_op = BinaryOp::kStrictNotEq; + return 7; + case Tok::kLessThan: + *bin_op = BinaryOp::kLessThan; + return 8; + case Tok::kLessThanEq: + *bin_op = BinaryOp::kLessThanEq; + return 8; + case Tok::kGreaterThan: + *bin_op = BinaryOp::kGreaterThan; + return 8; + case Tok::kGreaterThanEq: + *bin_op = BinaryOp::kGreaterThanEq; + return 8; + case Tok::kInstanceof: + *bin_op = BinaryOp::kInstanceof; + return 8; + case Tok::kIn: + if (no_in) { + return 0; + } + *bin_op = BinaryOp::kIn; + return 8; + case Tok::kShl: + *bin_op = BinaryOp::kShiftLeft; + return 9; + case Tok::kSar: + *bin_op = BinaryOp::kShiftRight; + return 9; + case Tok::kShr: + *bin_op = BinaryOp::kShiftRightLogical; + return 9; + case Tok::kAdd: + *bin_op = BinaryOp::kAdd; + return 10; + case Tok::kSub: + *bin_op = BinaryOp::kSub; + return 10; + case Tok::kMul: + *bin_op = BinaryOp::kMul; + return 11; + case Tok::kDiv: + *bin_op = BinaryOp::kDiv; + return 11; + case Tok::kMod: + *bin_op = BinaryOp::kMod; + return 11; + case Tok::kExp: + *bin_op = BinaryOp::kExp; + return 12; + default: + return 0; + } +} + +bool AssignOpOfToken(Tok tok, AssignOp* op) { + switch (tok) { + case Tok::kAssign: + *op = AssignOp::kAssign; + return true; + case Tok::kAssignAdd: + *op = AssignOp::kAddAssign; + return true; + case Tok::kAssignSub: + *op = AssignOp::kSubAssign; + return true; + case Tok::kAssignMul: + *op = AssignOp::kMulAssign; + return true; + case Tok::kAssignDiv: + *op = AssignOp::kDivAssign; + return true; + case Tok::kAssignMod: + *op = AssignOp::kModAssign; + return true; + case Tok::kAssignExp: + *op = AssignOp::kExpAssign; + return true; + case Tok::kAssignShl: + *op = AssignOp::kShiftLeftAssign; + return true; + case Tok::kAssignSar: + *op = AssignOp::kShiftRightAssign; + return true; + case Tok::kAssignShr: + *op = AssignOp::kShiftRightLogicalAssign; + return true; + case Tok::kAssignBitAnd: + *op = AssignOp::kBitAndAssign; + return true; + case Tok::kAssignBitOr: + *op = AssignOp::kBitOrAssign; + return true; + case Tok::kAssignBitXor: + *op = AssignOp::kBitXorAssign; + return true; + case Tok::kAssignAnd: + *op = AssignOp::kAndAssign; + return true; + case Tok::kAssignOr: + *op = AssignOp::kOrAssign; + return true; + case Tok::kAssignNullish: + *op = AssignOp::kNullishAssign; + return true; + default: + return false; + } +} + +} // namespace + +// --------------------------------------------------------------------------- +// ParseError + +void ComputeLineColumn(std::string_view source, int32_t position, int* line, + int* column) { + *line = 1; + *column = 1; + if (position < 0) { + return; + } + size_t limit = std::min(static_cast<size_t>(position), source.size()); + for (size_t i = 0; i < limit; i++) { + if (source[i] == '\n') { + (*line)++; + *column = 1; + } else { + (*column)++; + } + } +} + +std::string ParseError::ToString() const { + return StringPrintf("%d:%d: %s", line, column, message.c_str()); +} + +// --------------------------------------------------------------------------- +// Entry points + +std::unique_ptr<Tree> Parser::ParseScript(std::string_view source, + const ParseOptions& options, + ParseError* error) { + auto tree = std::make_unique<Tree>(); + tree->SetSource(source); + Parser parser(tree.get(), tree->source(), options); + Program* program = parser.ParseProgram(); + if (program == nullptr || parser.has_error()) { + if (error != nullptr) { + *error = parser.error_; + } + return nullptr; + } + tree->set_root(program); + return tree; +} + +Expression* Parser::ParseExpressionInto(Tree* tree, std::string_view source, + const ParseOptions& options, + ParseError* error) { + std::string_view interned = tree->Intern(source); + Parser parser(tree, interned, options); + parser.Advance(); + Expression* expression = parser.ParseExpression(); + if (expression != nullptr && !parser.has_error() && + !parser.Check(Tok::kEOF)) { + parser.FailUnexpected(); + } + if (expression == nullptr || parser.has_error()) { + if (error != nullptr) { + *error = parser.error_; + } + return nullptr; + } + return expression; +} + +Parser::Parser(Tree* tree, std::string_view source, const ParseOptions& options) + : tree_(tree), source_(source), options_(options), lexer_(source) { + function_state_.strict = options.strict; +} + +// --------------------------------------------------------------------------- +// Token helpers + +void Parser::Advance() { + prev_token_end_ = cur().end; + lexer_.Next(); + if (lexer_.has_error() && !failed_) { + Fail(lexer_.error(), lexer_.error_pos()); + } +} + +bool Parser::Eat(Tok type) { + if (!Check(type)) { + return false; + } + Advance(); + return true; +} + +bool Parser::EatName(std::string_view name) { + if (!CheckName(name)) { + return false; + } + Advance(); + return true; +} + +bool Parser::Expect(Tok type) { + if (Check(type)) { + Advance(); + return true; + } + return FailUnexpected(); +} + +bool Parser::ExpectName(std::string_view name) { + if (CheckName(name)) { + Advance(); + return true; + } + return FailUnexpected(); +} + +bool Parser::CanInsertSemicolon() const { + return Check(Tok::kEOF) || Check(Tok::kRightBrace) || cur().newline_before; +} + +bool Parser::ConsumeSemicolon() { + if (Eat(Tok::kSemicolon)) { + return true; + } + if (CanInsertSemicolon()) { + return true; + } + return FailUnexpected(); +} + +Token Parser::PeekNext() { + Lexer::State state = lexer_.Save(); + Token next = lexer_.Next(); + lexer_.Restore(state); + return next; +} + +Token Parser::PeekNext2() { + Lexer::State state = lexer_.Save(); + lexer_.Next(); + Token next2 = lexer_.Next(); + lexer_.Restore(state); + return next2; +} + +bool Parser::Fail(const std::string& message, int32_t position) { + if (!failed_) { + failed_ = true; + error_.message = message; + error_.position = position; + ComputeLineColumn(source_, position, &error_.line, &error_.column); + } + return false; +} + +bool Parser::FailUnexpected() { + if (failed_) { + return false; + } + const Token& token = cur(); + std::string message; + switch (token.type) { + case Tok::kEOF: + message = "Unexpected end of input"; + break; + case Tok::kNumber: + case Tok::kBigInt: + message = "Unexpected number"; + break; + case Tok::kString: + message = "Unexpected string"; + break; + case Tok::kTemplateHead: + case Tok::kNoSubstitutionTemplate: + case Tok::kTemplateMiddle: + case Tok::kTemplateTail: + message = "Unexpected template string"; + break; + case Tok::kName: + message = IsReservedWordInContext(token.value) + ? "Unexpected reserved word" + : "Unexpected identifier '" + token.value + "'"; + break; + case Tok::kIllegal: + message = "Invalid or unexpected token"; + break; + default: + message = std::string("Unexpected token '") + + std::string(lexer_.TokenText(token)) + "'"; + break; + } + return Fail(message, token.start); +} + +// --------------------------------------------------------------------------- +// Identifier classification + +bool Parser::IsReservedWordInContext(std::string_view name) const { + if (name == "yield") { + return function_state_.strict || function_state_.is_generator; + } + if (name == "await") { + return function_state_.is_async || function_state_.in_static_block; + } + if (function_state_.strict && IsStrictReservedWord(name)) { + return true; + } + return false; +} + +bool Parser::IsIdentifierToken() const { + if (!Check(Tok::kName)) { + return false; + } + if (cur().has_escape) { + return true; // lenient + } + return !IsReservedWordInContext(cur().value); +} + +bool Parser::TokenCanStartPropertyName(Tok type) { + switch (type) { + case Tok::kName: + case Tok::kPrivateName: + case Tok::kString: + case Tok::kNumber: + case Tok::kBigInt: + case Tok::kLeftBracket: + return true; + default: + return IsKeyword(type); + } +} + +bool Parser::IsLetDeclarationStart() { + // Current token is the name `let`. + if (function_state_.strict) { + return true; + } + Token next = PeekNext(); + if (next.type == Tok::kLeftBracket || next.type == Tok::kLeftBrace) { + return true; + } + if (next.type == Tok::kName) { + // `let` followed by an identifier (on any line) is a declaration; `let` + // followed by a keyword such as `in` or `instanceof` is an identifier. + return true; + } + return false; +} + +bool Parser::IsUsingDeclarationStart() { + // Current token is the name `using`; a declaration if followed on the + // same line by a binding identifier that is not `in`/`of`. + Token next = PeekNext(); + if (next.newline_before) { + return false; + } + if (next.type != Tok::kName) { + return false; + } + if (next.value == "of" && !next.has_escape) { + // `for (using of x)` iterates with the identifier `using`, but V8 (and + // the spec) accept `using of = 1` as a declaration of `of` in C-style + // for loops and plain statements, and `for (using of of x)` declares `of`. + Token next2 = PeekNext2(); + return next2.type == Tok::kAssign || + (next2.type == Tok::kName && !next2.has_escape && + next2.value == "of"); + } + return true; +} + +bool Parser::TokenStartsExpression() const { + switch (peek_type()) { + case Tok::kName: + case Tok::kPrivateName: + case Tok::kNumber: + case Tok::kBigInt: + case Tok::kString: + case Tok::kTemplateHead: + case Tok::kNoSubstitutionTemplate: + case Tok::kRegExp: + case Tok::kLeftParen: + case Tok::kLeftBracket: + case Tok::kLeftBrace: + case Tok::kAdd: + case Tok::kSub: + case Tok::kNot: + case Tok::kBitNot: + case Tok::kInc: + case Tok::kDec: + case Tok::kDiv: + case Tok::kAssignDiv: + case Tok::kThis: + case Tok::kSuper: + case Tok::kNew: + case Tok::kFunction: + case Tok::kClass: + case Tok::kTypeof: + case Tok::kVoid: + case Tok::kDelete: + case Tok::kNull: + case Tok::kTrue: + case Tok::kFalse: + case Tok::kImport: + case Tok::kMod: + return true; + default: + return false; + } +} + +// --------------------------------------------------------------------------- +// Program and statements + +Program* Parser::ParseProgram() { + Program* program = New<Program>(0); + Advance(); + if (has_error()) { + return nullptr; + } + bool strict = function_state_.strict; + if (!ParseDirectivePrologue(&program->body, &strict)) { + return nullptr; + } + program->strict = strict; + while (!Check(Tok::kEOF)) { + if (has_error()) { + return nullptr; + } + Statement* statement = ParseStatementListItem(); + if (statement == nullptr) { + return nullptr; + } + program->body.push_back(statement); + } + program->end = static_cast<int32_t>(source_.size()); + return program; +} + +// Parses leading string-literal expression statements. Sets *strict when a +// "use strict" directive is found (and switches the parser to strict mode). +bool Parser::ParseDirectivePrologue(std::vector<Statement*>* body, + bool* strict) { + while (Check(Tok::kString)) { + Token string_token = cur(); + int32_t start = start_pos(); + Statement* statement = ParseStatementListItem(); + if (statement == nullptr) { + return false; + } + body->push_back(statement); + auto* expression_statement = statement->As<ExpressionStatement>(); + if (expression_statement == nullptr) { + return true; + } + auto* literal = expression_statement->expression->As<StringLiteral>(); + if (literal == nullptr || literal->start != start || + literal->end != string_token.end) { + return true; // e.g. "a" + b; or "a".length; -- not a directive + } + expression_statement->is_directive = true; + expression_statement->directive = + Slice(string_token.start + 1, string_token.end - 1); + if (expression_statement->directive == "use strict") { + *strict = true; + function_state_.strict = true; + } + } + return true; +} + +Statement* Parser::ParseStatementListItem() { return ParseStatement(false); } + +// `single_statement` is true for the body of if/loops/with/labels, where +// declarations are not allowed (`if (x) let y;` is `let` the identifier +// followed by an error, `if (x) const y = 1;` is a SyntaxError). Annex B +// allows plain function declarations there in sloppy mode. +Statement* Parser::ParseStatement(bool single_statement) { + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + if (has_error()) { + return nullptr; + } + int32_t start = start_pos(); + switch (peek_type()) { + case Tok::kLeftBrace: + return ParseBlock(); + case Tok::kSemicolon: { + Advance(); + return Finish(New<EmptyStatement>(start)); + } + case Tok::kVar: + return ParseVariableStatement(VariableKind::kVar, start); + case Tok::kConst: + if (single_statement) { + Fail("Lexical declaration cannot appear in a single-statement context", + start); + return nullptr; + } + return ParseVariableStatement(VariableKind::kConst, start); + case Tok::kIf: + return ParseIfStatement(); + case Tok::kFor: + return ParseForStatement(); + case Tok::kWhile: + return ParseWhileStatement(); + case Tok::kDo: + return ParseDoWhileStatement(); + case Tok::kContinue: + return ParseBreakContinue(false); + case Tok::kBreak: + return ParseBreakContinue(true); + case Tok::kReturn: + return ParseReturnStatement(); + case Tok::kWith: + return ParseWithStatement(); + case Tok::kSwitch: + return ParseSwitchStatement(); + case Tok::kThrow: + return ParseThrowStatement(); + case Tok::kTry: + return ParseTryStatement(); + case Tok::kDebugger: { + Advance(); + if (!ConsumeSemicolon()) { + return nullptr; + } + return Finish(New<DebuggerStatement>(start)); + } + case Tok::kFunction: + if (single_statement && + (function_state_.strict || PeekNext().type == Tok::kMul)) { + Fail( + "Function declarations are not allowed in a single-statement " + "context", + start); + return nullptr; + } + return ParseFunctionDeclaration(start, false); + case Tok::kClass: + if (single_statement) { + Fail("Class declaration cannot appear in a single-statement context", + start); + return nullptr; + } + return ParseClassDeclaration(); + case Tok::kImport: { + Token next = PeekNext(); + if (next.type == Tok::kLeftParen || next.type == Tok::kPeriod) { + return ParseExpressionOrLabeledStatement(); + } + Fail("Cannot use import statement outside a module", start); + return nullptr; + } + case Tok::kExport: + Fail("Unexpected token 'export'", start); + return nullptr; + case Tok::kName: { + if (cur().has_escape) { + return ParseExpressionOrLabeledStatement(); + } + const std::string& name = cur().value; + if (name == "let") { + if (single_statement) { + // ExpressionStatement has a [lookahead != `let [`] restriction; + // any other `let` here is an identifier (and `let x` is an error + // reported when the `x` is not followed by a terminator). + if (PeekNext().type == Tok::kLeftBracket) { + Fail( + "Lexical declaration cannot appear in a single-statement " + "context", + start); + return nullptr; + } + } else if (IsLetDeclarationStart()) { + return ParseVariableStatement(VariableKind::kLet, start); + } + } + if (name == "async") { + Token next = PeekNext(); + if (next.type == Tok::kFunction && !next.newline_before) { + if (single_statement) { + Fail( + "Async functions can only be declared at the top level or " + "inside a block", + start); + return nullptr; + } + Advance(); + return ParseFunctionDeclaration(start, true); + } + } + if (name == "using" && !single_statement && IsUsingDeclarationStart()) { + return ParseVariableStatement(VariableKind::kUsing, start); + } + if (name == "await" && !single_statement && function_state_.is_async) { + Token next = PeekNext(); + if (next.type == Tok::kName && !next.has_escape && + next.value == "using" && !next.newline_before) { + Token next2 = PeekNext2(); + if (next2.type == Tok::kName && !next2.newline_before) { + Advance(); // await + return ParseVariableStatement(VariableKind::kAwaitUsing, start); + } + } + } + return ParseExpressionOrLabeledStatement(); + } + default: + return ParseExpressionOrLabeledStatement(); + } +} + +BlockStatement* Parser::ParseBlock() { + BlockStatement* block = New<BlockStatement>(start_pos()); + if (!Expect(Tok::kLeftBrace)) { + return nullptr; + } + while (!Check(Tok::kRightBrace)) { + if (has_error() || Check(Tok::kEOF)) { + FailUnexpected(); + return nullptr; + } + Statement* statement = ParseStatementListItem(); + if (statement == nullptr) { + return nullptr; + } + block->body.push_back(statement); + } + Advance(); + return Finish(block); +} + +Statement* Parser::ParseVariableStatement(VariableKind kind, int32_t start) { + Advance(); // var / let / const / using + VariableDeclaration* declaration = + ParseVariableDeclarationList(kind, start, false, false); + if (declaration == nullptr) { + return nullptr; + } + if (!ConsumeSemicolon()) { + return nullptr; + } + return Finish(declaration); +} + +VariableDeclaration* Parser::ParseVariableDeclarationList(VariableKind kind, + int32_t start, + bool no_in, + bool for_init) { + VariableDeclaration* declaration = New<VariableDeclaration>(start); + declaration->declaration_kind = kind; + while (true) { + VariableDeclarator* declarator = New<VariableDeclarator>(start_pos()); + declarator->target = ParseBindingPattern(); + if (declarator->target == nullptr) { + return nullptr; + } + if (Eat(Tok::kAssign)) { + declarator->init = ParseAssignment(no_in); + if (declarator->init == nullptr) { + return nullptr; + } + } else if (!for_init && (kind == VariableKind::kConst || + !declarator->target->Is<Identifier>())) { + // `const x;` and `let {a};` are errors; the target rejects them too, + // but a missing initializer makes the tree lie about the semantics. + Fail("Missing initializer in declaration", prev_end()); + return nullptr; + } + Finish(declarator); + declaration->declarations.push_back(declarator); + if (!Eat(Tok::kComma)) { + break; + } + } + return Finish(declaration); +} + +Statement* Parser::ParseIfStatement() { + IfStatement* statement = New<IfStatement>(start_pos()); + Advance(); + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + statement->test = ParseExpression(); + if (statement->test == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + statement->consequent = ParseStatement(true); + if (statement->consequent == nullptr) { + return nullptr; + } + if (Eat(Tok::kElse)) { + statement->alternate = ParseStatement(true); + if (statement->alternate == nullptr) { + return nullptr; + } + } + return Finish(statement); +} + +Statement* Parser::ParseForStatement() { + int32_t start = start_pos(); + Advance(); // for + bool is_await = false; + if (CheckName("await")) { + is_await = true; + Advance(); + } + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + + Node* init = nullptr; + Node* left = nullptr; + bool is_declaration = false; + VariableKind kind = VariableKind::kVar; + if (Check(Tok::kVar)) { + is_declaration = true; + kind = VariableKind::kVar; + } else if (Check(Tok::kConst)) { + is_declaration = true; + kind = VariableKind::kConst; + } else if (CheckName("let") && IsLetDeclarationStart()) { + is_declaration = true; + kind = VariableKind::kLet; + } else if (CheckName("using") && IsUsingDeclarationStart()) { + is_declaration = true; + kind = VariableKind::kUsing; + } else if (CheckName("await") && function_state_.is_async) { + Token next = PeekNext(); + if (next.type == Tok::kName && !next.has_escape && next.value == "using" && + !next.newline_before) { + Token next2 = PeekNext2(); + if (next2.type == Tok::kName && !next2.newline_before) { + Advance(); + is_declaration = true; + kind = VariableKind::kAwaitUsing; + } + } + } + + if (Check(Tok::kSemicolon)) { + // for (;;) + } else if (is_declaration) { + int32_t declaration_start = start_pos(); + Advance(); // var / let / const / using + VariableDeclaration* declaration = + ParseVariableDeclarationList(kind, declaration_start, true, true); + if (declaration == nullptr) { + return nullptr; + } + if (Check(Tok::kIn) || CheckName("of")) { + left = declaration; + } else { + init = declaration; + } + } else { + Expression* expression = ParseExpression(true); + if (expression == nullptr) { + return nullptr; + } + if (Check(Tok::kIn) || CheckName("of")) { + if (expression->Is<ObjectExpression>() || + expression->Is<ArrayExpression>()) { + expression = ToPattern(expression, false); + if (expression == nullptr) { + return nullptr; + } + } else if (!IsValidSimpleAssignmentTarget(expression)) { + Fail("Invalid left-hand side in for-loop", expression->start); + return nullptr; + } + left = expression; + } else { + init = expression; + } + } + + if (left != nullptr) { + bool is_of = CheckName("of"); + Advance(); // in / of + Expression* right = is_of ? ParseAssignment() : ParseExpression(); + if (right == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + Statement* body = ParseStatement(true); + if (body == nullptr) { + return nullptr; + } + if (is_of) { + ForOfStatement* statement = New<ForOfStatement>(start); + statement->left = left; + statement->right = right; + statement->body = body; + statement->is_await = is_await; + return Finish(statement); + } + if (is_await) { + Fail("Unexpected token 'in'", start); + return nullptr; + } + ForInStatement* statement = New<ForInStatement>(start); + statement->left = left; + statement->right = right; + statement->body = body; + return Finish(statement); + } + + if (is_await) { + FailUnexpected(); + return nullptr; + } + ForStatement* statement = New<ForStatement>(start); + statement->init = init; + if (!Expect(Tok::kSemicolon)) { + return nullptr; + } + if (!Check(Tok::kSemicolon)) { + statement->test = ParseExpression(); + if (statement->test == nullptr) { + return nullptr; + } + } + if (!Expect(Tok::kSemicolon)) { + return nullptr; + } + if (!Check(Tok::kRightParen)) { + statement->update = ParseExpression(); + if (statement->update == nullptr) { + return nullptr; + } + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + statement->body = ParseStatement(true); + if (statement->body == nullptr) { + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseWhileStatement() { + WhileStatement* statement = New<WhileStatement>(start_pos()); + Advance(); + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + statement->test = ParseExpression(); + if (statement->test == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + statement->body = ParseStatement(true); + if (statement->body == nullptr) { + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseDoWhileStatement() { + DoWhileStatement* statement = New<DoWhileStatement>(start_pos()); + Advance(); + statement->body = ParseStatement(true); + if (statement->body == nullptr) { + return nullptr; + } + if (!Expect(Tok::kWhile)) { + return nullptr; + } + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + statement->test = ParseExpression(); + if (statement->test == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + // A semicolon after do-while is optional even without a newline. + Eat(Tok::kSemicolon); + return Finish(statement); +} + +Statement* Parser::ParseBreakContinue(bool is_break) { + int32_t start = start_pos(); + Advance(); + Identifier* label = nullptr; + if (Check(Tok::kName) && !cur().newline_before && IsIdentifierToken()) { + label = ParseBindingIdentifier(); + if (label == nullptr) { + return nullptr; + } + } + if (!ConsumeSemicolon()) { + return nullptr; + } + if (is_break) { + BreakStatement* statement = New<BreakStatement>(start); + statement->label = label; + return Finish(statement); + } + ContinueStatement* statement = New<ContinueStatement>(start); + statement->label = label; + return Finish(statement); +} + +Statement* Parser::ParseReturnStatement() { + ReturnStatement* statement = New<ReturnStatement>(start_pos()); + Advance(); + if (!Check(Tok::kSemicolon) && !CanInsertSemicolon()) { + statement->argument = ParseExpression(); + if (statement->argument == nullptr) { + return nullptr; + } + } + if (!ConsumeSemicolon()) { + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseWithStatement() { + WithStatement* statement = New<WithStatement>(start_pos()); + Advance(); + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + statement->object = ParseExpression(); + if (statement->object == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + statement->body = ParseStatement(true); + if (statement->body == nullptr) { + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseSwitchStatement() { + SwitchStatement* statement = New<SwitchStatement>(start_pos()); + Advance(); + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + statement->discriminant = ParseExpression(); + if (statement->discriminant == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + if (!Expect(Tok::kLeftBrace)) { + return nullptr; + } + while (!Check(Tok::kRightBrace)) { + if (has_error()) { + return nullptr; + } + SwitchCase* switch_case = New<SwitchCase>(start_pos()); + if (Eat(Tok::kCase)) { + switch_case->test = ParseExpression(); + if (switch_case->test == nullptr) { + return nullptr; + } + } else if (!Expect(Tok::kDefault)) { + return nullptr; + } + if (!Expect(Tok::kColon)) { + return nullptr; + } + while (!Check(Tok::kCase) && !Check(Tok::kDefault) && + !Check(Tok::kRightBrace)) { + if (has_error() || Check(Tok::kEOF)) { + FailUnexpected(); + return nullptr; + } + Statement* consequent = ParseStatementListItem(); + if (consequent == nullptr) { + return nullptr; + } + switch_case->consequent.push_back(consequent); + } + statement->cases.push_back(Finish(switch_case)); + } + Advance(); + return Finish(statement); +} + +Statement* Parser::ParseThrowStatement() { + ThrowStatement* statement = New<ThrowStatement>(start_pos()); + Advance(); + if (cur().newline_before) { + Fail("Illegal newline after throw", start_pos()); + return nullptr; + } + statement->argument = ParseExpression(); + if (statement->argument == nullptr) { + return nullptr; + } + if (!ConsumeSemicolon()) { + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseTryStatement() { + TryStatement* statement = New<TryStatement>(start_pos()); + Advance(); + statement->block = ParseBlock(); + if (statement->block == nullptr) { + return nullptr; + } + if (Check(Tok::kCatch)) { + CatchClause* handler = New<CatchClause>(start_pos()); + Advance(); + if (Eat(Tok::kLeftParen)) { + handler->param = ParseBindingPattern(); + if (handler->param == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + } + handler->body = ParseBlock(); + if (handler->body == nullptr) { + return nullptr; + } + statement->handler = Finish(handler); + } + if (Eat(Tok::kFinally)) { + statement->finalizer = ParseBlock(); + if (statement->finalizer == nullptr) { + return nullptr; + } + } + if (statement->handler == nullptr && statement->finalizer == nullptr) { + Fail("Missing catch or finally after try", start_pos()); + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseExpressionOrLabeledStatement() { + int32_t start = start_pos(); + if (Check(Tok::kName) && IsIdentifierToken()) { + Token next = PeekNext(); + if (next.type == Tok::kColon) { + LabeledStatement* statement = New<LabeledStatement>(start); + statement->label = ParseBindingIdentifier(); + if (statement->label == nullptr) { + return nullptr; + } + Advance(); // ':' + statement->body = ParseStatement(true); + if (statement->body == nullptr) { + return nullptr; + } + return Finish(statement); + } + } + ExpressionStatement* statement = New<ExpressionStatement>(start); + statement->expression = ParseExpression(); + if (statement->expression == nullptr) { + return nullptr; + } + if (!ConsumeSemicolon()) { + return nullptr; + } + return Finish(statement); +} + +Statement* Parser::ParseFunctionDeclaration(int32_t start, bool is_async) { + FunctionDeclaration* fn = New<FunctionDeclaration>(start); + fn->is_async = is_async; + Advance(); // function + fn->is_generator = Eat(Tok::kMul); + fn->name = ParseBindingIdentifier(); + if (fn->name == nullptr) { + return nullptr; + } + if (!ParseFunctionRest(fn, start, false, false, false, false)) { + return nullptr; + } + return Finish(fn); +} + +Statement* Parser::ParseClassDeclaration() { + ClassDeclaration* cls = New<ClassDeclaration>(start_pos()); + if (!ParseClass(cls, cls->start, false)) { + return nullptr; + } + if (cls->name == nullptr) { + Fail("Class declarations require a name", cls->start); + return nullptr; + } + return Finish(cls); +} + +// --------------------------------------------------------------------------- +// Functions and classes + +bool Parser::ParseFunctionRest(FunctionData* fn, int32_t /*start*/, + bool /*is_method*/, bool /*is_getter*/, + bool /*is_setter*/, bool /*is_constructor*/ +) { + function_stack_.push_back(function_state_); + FunctionState state; + state.is_async = fn->is_async; + state.is_generator = fn->is_generator; + state.is_arrow = false; + state.in_function = true; + state.strict = function_state_.strict; + function_state_ = state; + bool ok = ParseFormalParameters(fn) && ParseFunctionBody(fn); + fn->strict = function_state_.strict; + function_state_ = function_stack_.back(); + function_stack_.pop_back(); + return ok; +} + +bool Parser::ParseFormalParameters(FunctionData* fn) { + if (!Expect(Tok::kLeftParen)) { + return false; + } + while (!Check(Tok::kRightParen)) { + if (has_error()) { + return false; + } + if (Check(Tok::kEllipsis)) { + RestElement* rest = New<RestElement>(start_pos()); + Advance(); + rest->argument = ParseBindingPattern(); + if (rest->argument == nullptr) { + return false; + } + fn->params.push_back(Finish(rest)); + if (!Check(Tok::kRightParen)) { + return FailUnexpected(); + } + break; + } + Expression* param = ParseBindingElement(); + if (param == nullptr) { + return false; + } + fn->params.push_back(param); + if (!Check(Tok::kRightParen) && !Expect(Tok::kComma)) { + return false; + } + } + return Expect(Tok::kRightParen); +} + +bool Parser::ParseFunctionBody(FunctionData* fn) { + BlockStatement* body = New<BlockStatement>(start_pos()); + if (!Expect(Tok::kLeftBrace)) { + return false; + } + bool strict = function_state_.strict; + if (!ParseDirectivePrologue(&body->body, &strict)) { + return false; + } + while (!Check(Tok::kRightBrace)) { + if (has_error() || Check(Tok::kEOF)) { + return FailUnexpected(); + } + Statement* statement = ParseStatementListItem(); + if (statement == nullptr) { + return false; + } + body->body.push_back(statement); + } + Advance(); + fn->body = Finish(body); + return true; +} + +bool Parser::ParseArrowBody(ArrowFunctionExpression* arrow) { + if (Check(Tok::kLeftBrace)) { + return ParseFunctionBody(arrow); + } + arrow->expression_body = ParseAssignment(); + return arrow->expression_body != nullptr; +} + +Expression* Parser::ParseArrowFromParams(std::vector<Expression*> params, + int32_t start, bool is_async) { + ArrowFunctionExpression* arrow = New<ArrowFunctionExpression>(start); + arrow->is_arrow = true; + arrow->is_async = is_async; + for (size_t i = 0; i < params.size(); i++) { + Expression* param = params[i]; + if (auto* spread = param->As<SpreadElement>()) { + if (i + 1 != params.size()) { + Fail("Rest parameter must be last formal parameter", spread->start); + return nullptr; + } + RestElement* rest = New<RestElement>(spread->start); + rest->argument = ToPattern(spread->argument, true); + if (rest->argument == nullptr) { + return nullptr; + } + rest->end = spread->end; + param = rest; + } else { + param = ToPattern(param, true); + if (param == nullptr) { + return nullptr; + } + } + arrow->params.push_back(param); + } + function_stack_.push_back(function_state_); + FunctionState state; + state.is_async = is_async; + state.is_generator = false; + state.is_arrow = true; + state.in_function = true; + state.strict = function_state_.strict; + function_state_ = state; + bool ok = ParseArrowBody(arrow); + arrow->strict = function_state_.strict; + function_state_ = function_stack_.back(); + function_stack_.pop_back(); + if (!ok) { + return nullptr; + } + return Finish(arrow); +} + +bool Parser::ParseClass(ClassData* cls, int32_t /*start*/, + bool /*is_expression*/) { + // A class expression in the heritage clause recurses into ParseClass + // through ParseLeftHandSide and ParsePrimary, which have no guard. + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return false; + } + Advance(); // class + bool saved_strict = function_state_.strict; + function_state_.strict = true; + if (Check(Tok::kName) && !CheckName("extends")) { + cls->name = ParseBindingIdentifier(); + if (cls->name == nullptr) { + return false; + } + } + if (Eat(Tok::kExtends)) { + cls->super_class = ParseLeftHandSide(); + if (cls->super_class == nullptr) { + return false; + } + } + ClassBody* body = New<ClassBody>(start_pos()); + if (!Expect(Tok::kLeftBrace)) { + return false; + } + while (!Check(Tok::kRightBrace)) { + if (has_error() || Check(Tok::kEOF)) { + return FailUnexpected(); + } + if (Eat(Tok::kSemicolon)) { + continue; + } + Node* member = ParseClassMember(); + if (member == nullptr) { + return false; + } + body->members.push_back(member); + } + Advance(); + cls->body = Finish(body); + function_state_.strict = saved_strict; + return true; +} + +Node* Parser::ParseClassMember() { + int32_t start = start_pos(); + bool is_static = false; + if (CheckName("static")) { + Token next = PeekNext(); + if (next.type == Tok::kLeftBrace) { + // static { ... } + Advance(); + StaticBlock* block = New<StaticBlock>(start); + Advance(); // '{' + function_stack_.push_back(function_state_); + FunctionState state; + state.in_function = true; + state.in_static_block = true; + state.strict = true; + function_state_ = state; + bool ok = true; + while (!Check(Tok::kRightBrace)) { + if (has_error() || Check(Tok::kEOF)) { + ok = FailUnexpected(); + break; + } + Statement* statement = ParseStatementListItem(); + if (statement == nullptr) { + ok = false; + break; + } + block->body.push_back(statement); + } + function_state_ = function_stack_.back(); + function_stack_.pop_back(); + if (!ok) { + return nullptr; + } + Advance(); // '}' + return Finish(block); + } + bool is_modifier = + !(next.type == Tok::kLeftParen || next.type == Tok::kAssign || + next.type == Tok::kSemicolon || next.type == Tok::kRightBrace); + if (is_modifier) { + is_static = true; + Advance(); + } + } + + MethodKind method_kind = MethodKind::kMethod; + bool is_async = false; + bool is_generator = false; + bool is_accessor = false; + if (CheckName("get") || CheckName("set") || CheckName("async")) { + Token next = PeekNext(); + bool is_modifier = + !(next.type == Tok::kLeftParen || next.type == Tok::kAssign || + next.type == Tok::kSemicolon || next.type == Tok::kRightBrace || + (cur().value == "async" && next.newline_before)); + // `get`/`set` must be followed by a property name; `get\n*m() {}` is a + // field named `get` (ASI) followed by a generator method. + if (is_modifier && cur().value != "async" && + !TokenCanStartPropertyName(next.type)) { + is_modifier = false; + } + if (is_modifier) { + if (cur().value == "get") { + method_kind = MethodKind::kGet; + is_accessor = true; + } else if (cur().value == "set") { + method_kind = MethodKind::kSet; + is_accessor = true; + } else { + is_async = true; + } + Advance(); + } + } + if (Check(Tok::kMul)) { + is_generator = true; + Advance(); + } + // `accessor` [no LineTerminator here] ClassElementName: an auto-accessor + // field. Otherwise `accessor` is an ordinary field or method name. + bool is_auto_accessor = false; + if (!is_accessor && !is_async && !is_generator && CheckName("accessor")) { + Token next = PeekNext(); + bool is_modifier = + !(next.type == Tok::kLeftParen || next.type == Tok::kAssign || + next.type == Tok::kSemicolon || next.type == Tok::kRightBrace || + next.newline_before); + if (is_modifier) { + is_auto_accessor = true; + Advance(); + } + } + + bool computed = false; + int32_t key_start = start_pos(); + Expression* key = ParsePropertyKey(&computed, true); + if (key == nullptr) { + return nullptr; + } + + if (!is_auto_accessor && + (Check(Tok::kLeftParen) || is_accessor || is_async || is_generator)) { + MethodDefinition* method = New<MethodDefinition>(start); + method->key = key; + method->computed = computed; + method->is_static = is_static; + method->method_kind = method_kind; + if (!is_static && !computed && method_kind == MethodKind::kMethod) { + bool is_constructor = false; + if (auto* id = key->As<Identifier>()) { + is_constructor = id->name == "constructor"; + } else if (auto* str = key->As<StringLiteral>()) { + is_constructor = str->value == "constructor"; + } + if (is_constructor) { + method->method_kind = MethodKind::kConstructor; + } + } + FunctionExpression* fn = New<FunctionExpression>(key_start); + fn->is_async = is_async; + fn->is_generator = is_generator; + if (!ParseFunctionRest(fn, key_start, true, method_kind == MethodKind::kGet, + method_kind == MethodKind::kSet, + method->method_kind == MethodKind::kConstructor)) { + return nullptr; + } + method->value = Finish(fn); + return Finish(method); + } + + // Field definition. + PropertyDefinition* field = New<PropertyDefinition>(start); + field->key = key; + field->computed = computed; + field->is_static = is_static; + field->is_auto_accessor = is_auto_accessor; + if (Eat(Tok::kAssign)) { + function_stack_.push_back(function_state_); + FunctionState state; + state.in_function = true; + state.in_class_field_init = true; + state.strict = true; + function_state_ = state; + field->value = ParseAssignment(); + function_state_ = function_stack_.back(); + function_stack_.pop_back(); + if (field->value == nullptr) { + return nullptr; + } + } + if (!ConsumeSemicolon()) { + return nullptr; + } + return Finish(field); +} + +Expression* Parser::ParsePropertyKey(bool* computed, bool allow_private) { + *computed = false; + int32_t start = start_pos(); + switch (peek_type()) { + case Tok::kString: { + StringLiteral* literal = New<StringLiteral>(start); + literal->value = cur().value; + literal->raw = Slice(cur().start, cur().end); + Advance(); + return Finish(literal); + } + case Tok::kNumber: { + NumericLiteral* literal = New<NumericLiteral>(start); + literal->value = cur().number_value; + literal->raw = Slice(cur().start, cur().end); + Advance(); + return Finish(literal); + } + case Tok::kBigInt: { + BigIntLiteral* literal = New<BigIntLiteral>(start); + literal->raw = Slice(cur().start, cur().end); + Advance(); + return Finish(literal); + } + case Tok::kLeftBracket: { + Advance(); + *computed = true; + Expression* key = ParseAssignment(); + if (key == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightBracket)) { + return nullptr; + } + return key; + } + case Tok::kPrivateName: { + if (!allow_private) { + FailUnexpected(); + return nullptr; + } + PrivateIdentifier* id = New<PrivateIdentifier>(start); + id->name = Intern(cur().value); + Advance(); + return Finish(id); + } + default: + if (Check(Tok::kName) || IsKeyword(peek_type())) { + return ParseIdentifierName(); + } + FailUnexpected(); + return nullptr; + } +} + +// --------------------------------------------------------------------------- +// Expressions + +Expression* Parser::ParseExpression(bool no_in) { + int32_t start = start_pos(); + Expression* expression = ParseAssignment(no_in); + if (expression == nullptr) { + return nullptr; + } + if (!Check(Tok::kComma)) { + return expression; + } + SequenceExpression* sequence = New<SequenceExpression>(start); + sequence->expressions.push_back(expression); + while (Eat(Tok::kComma)) { + Expression* next = ParseAssignment(no_in); + if (next == nullptr) { + return nullptr; + } + sequence->expressions.push_back(next); + } + return Finish(sequence); +} + +Expression* Parser::ParseAssignment(bool no_in) { + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + if (has_error()) { + return nullptr; + } + if (CheckName("yield") && + (function_state_.is_generator || function_state_.strict)) { + if (function_state_.is_generator) { + return ParseYield(no_in); + } + // `yield` in strict non-generator code is a reserved word. + FailUnexpected(); + return nullptr; + } + int32_t start = start_pos(); + // Single-identifier arrow function: x => ... + if (Check(Tok::kName) && IsIdentifierToken() && !CheckName("async")) { + Token next = PeekNext(); + if (next.type == Tok::kArrow && !next.newline_before) { + Identifier* param = ParseBindingIdentifier(); + if (param == nullptr) { + return nullptr; + } + Advance(); // => + return ParseArrowFromParams({param}, start, false); + } + } + if (CheckName("async")) { + // async x => ... (async function/arrow with parens are handled by the + // primary expression parser), or `async => ...` with async as the + // parameter name. + Token next = PeekNext(); + if (next.type == Tok::kArrow && !next.newline_before) { + Identifier* param = ParseBindingIdentifier(); + if (param == nullptr) { + return nullptr; + } + Advance(); // => + return ParseArrowFromParams({param}, start, false); + } + if (next.type == Tok::kName && !next.newline_before) { + Token next2 = PeekNext2(); + if (next2.type == Tok::kArrow && !next2.newline_before) { + Advance(); // async + function_stack_.push_back(function_state_); + function_state_.is_async = true; + Identifier* param = ParseBindingIdentifier(); + function_state_ = function_stack_.back(); + function_stack_.pop_back(); + if (param == nullptr) { + return nullptr; + } + Advance(); // => + return ParseArrowFromParams({param}, start, true); + } + } + } + + Expression* left = ParseConditional(no_in); + if (left == nullptr) { + return nullptr; + } + AssignOp op; + if (!AssignOpOfToken(peek_type(), &op)) { + return left; + } + if (IsBareArrow(left)) { + FailUnexpected(); + return nullptr; + } + if (op == AssignOp::kAssign && + (left->Is<ObjectExpression>() || left->Is<ArrayExpression>())) { + left = ToPattern(left, false); + if (left == nullptr) { + return nullptr; + } + } else if (!IsValidSimpleAssignmentTarget(left)) { + Fail("Invalid left-hand side in assignment", left->start); + return nullptr; + } + Advance(); // operator + AssignmentExpression* assignment = New<AssignmentExpression>(left->start); + assignment->op = op; + assignment->left = left; + assignment->right = ParseAssignment(no_in); + if (assignment->right == nullptr) { + return nullptr; + } + return Finish(assignment); +} + +Expression* Parser::ParseYield(bool no_in) { + YieldExpression* yield = New<YieldExpression>(start_pos()); + Advance(); // yield + if (cur().newline_before) { + return Finish(yield); + } + if (Eat(Tok::kMul)) { + yield->delegate = true; + yield->argument = ParseAssignment(no_in); + if (yield->argument == nullptr) { + return nullptr; + } + return Finish(yield); + } + if (TokenStartsExpression()) { + yield->argument = ParseAssignment(no_in); + if (yield->argument == nullptr) { + return nullptr; + } + } + return Finish(yield); +} + +Expression* Parser::ParseConditional(bool no_in) { + int32_t start = start_pos(); + Expression* test = ParseBinary(0, no_in); + if (test == nullptr) { + return nullptr; + } + if (!Check(Tok::kQuestion)) { + return test; + } + if (IsBareArrow(test)) { + return test; + } + Advance(); + ConditionalExpression* conditional = New<ConditionalExpression>(start); + conditional->test = test; + conditional->consequent = ParseAssignment(false); + if (conditional->consequent == nullptr) { + return nullptr; + } + if (!Expect(Tok::kColon)) { + return nullptr; + } + conditional->alternate = ParseAssignment(no_in); + if (conditional->alternate == nullptr) { + return nullptr; + } + return Finish(conditional); +} + +Expression* Parser::ParseBinary(int min_precedence, bool no_in) { + // The right operand of a right-associative operator (`**`) recurses into + // ParseBinary, so this frame counts toward the nesting depth. + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + int32_t start = start_pos(); + Expression* left; + if (Check(Tok::kPrivateName)) { + // `#x in obj` + Token next = PeekNext(); + if (next.type != Tok::kIn || no_in) { + FailUnexpected(); + return nullptr; + } + PrivateIdentifier* id = New<PrivateIdentifier>(start); + id->name = Intern(cur().value); + Advance(); + left = Finish(id); + } else { + left = ParseUnary(); + if (left == nullptr) { + return nullptr; + } + if (IsBareArrow(left)) { + return left; + } + } + int chain_depth = 0; + while (true) { + BinaryOp bin_op = BinaryOp::kAdd; + LogicalOp log_op = LogicalOp::kAnd; + bool is_logical = false; + int precedence = BinaryPrecedenceOfToken(peek_type(), no_in, &bin_op, + &log_op, &is_logical); + if (precedence == 0 || precedence <= min_precedence) { + break; + } + if (depth_ + ++chain_depth > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + Advance(); + // `**` is right-associative. + int right_min = + bin_op == BinaryOp::kExp && !is_logical ? precedence - 1 : precedence; + Expression* right = ParseBinary(right_min, no_in); + if (right == nullptr) { + return nullptr; + } + if (is_logical) { + LogicalExpression* logical = New<LogicalExpression>(start); + logical->op = log_op; + logical->left = left; + logical->right = right; + left = Finish(logical); + } else { + BinaryExpression* binary = New<BinaryExpression>(start); + binary->op = bin_op; + binary->left = left; + binary->right = right; + left = Finish(binary); + } + } + return left; +} + +Expression* Parser::ParseUnary() { + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + int32_t start = start_pos(); + UnaryOp op; + bool is_unary = true; + switch (peek_type()) { + case Tok::kSub: + op = UnaryOp::kMinus; + break; + case Tok::kAdd: + op = UnaryOp::kPlus; + break; + case Tok::kNot: + op = UnaryOp::kNot; + break; + case Tok::kBitNot: + op = UnaryOp::kBitNot; + break; + case Tok::kTypeof: + op = UnaryOp::kTypeof; + break; + case Tok::kVoid: + op = UnaryOp::kVoid; + break; + case Tok::kDelete: + op = UnaryOp::kDelete; + break; + default: + is_unary = false; + op = UnaryOp::kMinus; + break; + } + if (is_unary) { + Advance(); + UnaryExpression* unary = New<UnaryExpression>(start); + unary->op = op; + unary->argument = ParseUnary(); + if (unary->argument == nullptr) { + return nullptr; + } + return Finish(unary); + } + if (Check(Tok::kInc) || Check(Tok::kDec)) { + UpdateExpression* update = New<UpdateExpression>(start); + update->op = Check(Tok::kInc) ? UpdateOp::kIncrement : UpdateOp::kDecrement; + update->prefix = true; + Advance(); + update->argument = ParseUnary(); + if (update->argument == nullptr) { + return nullptr; + } + if (!IsValidSimpleAssignmentTarget(update->argument)) { + Fail("Invalid left-hand side expression in prefix operation", + update->argument->start); + return nullptr; + } + return Finish(update); + } + if (CheckName("await") && function_state_.is_async) { + AwaitExpression* await_expression = New<AwaitExpression>(start); + Advance(); + await_expression->argument = ParseUnary(); + if (await_expression->argument == nullptr) { + return nullptr; + } + return Finish(await_expression); + } + return ParsePostfix(); +} + +Expression* Parser::ParsePostfix() { + int32_t start = start_pos(); + Expression* expression = ParseLeftHandSide(); + if (expression == nullptr) { + return nullptr; + } + if ((Check(Tok::kInc) || Check(Tok::kDec)) && !cur().newline_before) { + if (!IsValidSimpleAssignmentTarget(expression)) { + Fail("Invalid left-hand side expression in postfix operation", + expression->start); + return nullptr; + } + UpdateExpression* update = New<UpdateExpression>(start); + update->op = Check(Tok::kInc) ? UpdateOp::kIncrement : UpdateOp::kDecrement; + update->prefix = false; + update->argument = expression; + Advance(); + return Finish(update); + } + return expression; +} + +Expression* Parser::ParseLeftHandSide() { + int32_t start = start_pos(); + Expression* base = ParsePrimary(); + if (base == nullptr) { + return nullptr; + } + if (IsBareArrow(base)) { + return base; + } + return ParseSubscripts(base, start, false); +} + +Expression* Parser::ParseSubscripts(Expression* base, int32_t start, + bool no_calls) { + bool maybe_async_arrow = false; + if (auto* id = base->As<Identifier>()) { + maybe_async_arrow = + id->name == "async" && !cur().newline_before && base->end == prev_end(); + } + bool optional_chained = false; + int chain_depth = 0; + while (true) { + if (has_error()) { + return nullptr; + } + if (Check(Tok::kPeriod)) { + Advance(); + MemberExpression* member = New<MemberExpression>(start); + member->object = base; + if (Check(Tok::kPrivateName)) { + PrivateIdentifier* id = New<PrivateIdentifier>(start_pos()); + id->name = Intern(cur().value); + Advance(); + member->property = Finish(id); + } else { + member->property = ParseIdentifierName(); + if (member->property == nullptr) { + return nullptr; + } + } + base = Finish(member); + } else if (Check(Tok::kQuestionPeriod)) { + Advance(); + optional_chained = true; + if (Check(Tok::kLeftParen)) { + if (no_calls) { + FailUnexpected(); + return nullptr; + } + CallExpression* call = New<CallExpression>(start); + call->callee = base; + call->optional = true; + if (!ParseArguments(&call->arguments)) { + return nullptr; + } + base = Finish(call); + } else if (Check(Tok::kLeftBracket)) { + Advance(); + MemberExpression* member = New<MemberExpression>(start); + member->object = base; + member->computed = true; + member->optional = true; + member->property = ParseExpression(); + if (member->property == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightBracket)) { + return nullptr; + } + base = Finish(member); + } else if (Check(Tok::kPrivateName)) { + MemberExpression* member = New<MemberExpression>(start); + member->object = base; + member->optional = true; + PrivateIdentifier* id = New<PrivateIdentifier>(start_pos()); + id->name = Intern(cur().value); + Advance(); + member->property = Finish(id); + base = Finish(member); + } else { + MemberExpression* member = New<MemberExpression>(start); + member->object = base; + member->optional = true; + member->property = ParseIdentifierName(); + if (member->property == nullptr) { + return nullptr; + } + base = Finish(member); + } + } else if (Check(Tok::kLeftBracket)) { + Advance(); + MemberExpression* member = New<MemberExpression>(start); + member->object = base; + member->computed = true; + member->property = ParseExpression(); + if (member->property == nullptr) { + return nullptr; + } + if (!Expect(Tok::kRightBracket)) { + return nullptr; + } + base = Finish(member); + } else if (!no_calls && Check(Tok::kLeftParen)) { + std::vector<Expression*> arguments; + if (!ParseArguments(&arguments)) { + return nullptr; + } + if (maybe_async_arrow && Check(Tok::kArrow) && !cur().newline_before) { + Advance(); // => + return ParseArrowFromParams(std::move(arguments), start, true); + } + CallExpression* call = New<CallExpression>(start); + call->callee = base; + call->arguments = std::move(arguments); + base = Finish(call); + } else if (Check(Tok::kTemplateHead) || + Check(Tok::kNoSubstitutionTemplate)) { + if (optional_chained) { + Fail("Invalid tagged template on optional chain", start_pos()); + return nullptr; + } + TaggedTemplateExpression* tagged = New<TaggedTemplateExpression>(start); + tagged->tag = base; + Expression* quasi = ParseTemplateLiteral(true); + if (quasi == nullptr) { + return nullptr; + } + tagged->quasi = quasi->Cast<TemplateLiteral>(); + base = Finish(tagged); + } else { + break; + } + if (depth_ + ++chain_depth > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + maybe_async_arrow = false; + } + if (optional_chained) { + ChainExpression* chain = New<ChainExpression>(start); + chain->expression = base; + return Finish(chain); + } + return base; +} + +bool Parser::ParseArguments(std::vector<Expression*>* arguments) { + if (!Expect(Tok::kLeftParen)) { + return false; + } + while (!Check(Tok::kRightParen)) { + if (has_error()) { + return false; + } + Expression* argument = ParseSpreadOrAssignment(); + if (argument == nullptr) { + return false; + } + arguments->push_back(argument); + if (!Check(Tok::kRightParen) && !Expect(Tok::kComma)) { + return false; + } + } + return Expect(Tok::kRightParen); +} + +Expression* Parser::ParseSpreadOrAssignment() { + if (Check(Tok::kEllipsis)) { + SpreadElement* spread = New<SpreadElement>(start_pos()); + Advance(); + spread->argument = ParseAssignment(); + if (spread->argument == nullptr) { + return nullptr; + } + return Finish(spread); + } + return ParseAssignment(); +} + +Expression* Parser::ParseNewExpression() { + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + int32_t start = start_pos(); + Advance(); // new + if (Eat(Tok::kPeriod)) { + if (!CheckName("target")) { + FailUnexpected(); + return nullptr; + } + Advance(); + MetaProperty* meta = New<MetaProperty>(start); + meta->meta_kind = MetaPropertyKind::kNewTarget; + return Finish(meta); + } + NewExpression* new_expression = New<NewExpression>(start); + int32_t callee_start = start_pos(); + Expression* callee; + if (Check(Tok::kNew)) { + callee = ParseNewExpression(); + } else if (Check(Tok::kImport)) { + Fail("Cannot use new with import", start_pos()); + return nullptr; + } else { + callee = ParsePrimary(); + } + if (callee == nullptr) { + return nullptr; + } + callee = ParseSubscripts(callee, callee_start, true); + if (callee == nullptr) { + return nullptr; + } + if (callee->Is<ChainExpression>()) { + Fail("Invalid optional chain from new expression", callee->start); + return nullptr; + } + new_expression->callee = callee; + if (Check(Tok::kLeftParen) && !ParseArguments(&new_expression->arguments)) { + return nullptr; + } + return Finish(new_expression); +} + +Expression* Parser::ParseSuper() { + Super* super = New<Super>(start_pos()); + Advance(); + if (!Check(Tok::kLeftParen) && !Check(Tok::kPeriod) && + !Check(Tok::kLeftBracket)) { + Fail("'super' keyword unexpected here", super->start); + return nullptr; + } + return Finish(super); +} + +Expression* Parser::ParseImportExpressionOrMeta() { + int32_t start = start_pos(); + Advance(); // import + bool is_defer = false; + if (Eat(Tok::kPeriod)) { + if (CheckName("defer")) { + Advance(); + is_defer = true; + } else { + if (!ExpectName("meta")) { + return nullptr; + } + MetaProperty* meta = New<MetaProperty>(start); + meta->meta_kind = MetaPropertyKind::kImportMeta; + return Finish(meta); + } + } + ImportExpression* import = New<ImportExpression>(start); + import->is_defer = is_defer; + if (!Expect(Tok::kLeftParen)) { + return nullptr; + } + import->source = ParseAssignment(); + if (import->source == nullptr) { + return nullptr; + } + if (Eat(Tok::kComma) && !Check(Tok::kRightParen)) { + import->options = ParseAssignment(); + if (import->options == nullptr) { + return nullptr; + } + Eat(Tok::kComma); + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + return Finish(import); +} + +Expression* Parser::ParseNativeCall() { + NativeCallExpression* call = New<NativeCallExpression>(start_pos()); + Advance(); // % + if (!Check(Tok::kName) && !IsKeyword(peek_type())) { + FailUnexpected(); + return nullptr; + } + call->name = Intern(cur().value); + Advance(); + if (!ParseArguments(&call->arguments)) { + return nullptr; + } + return Finish(call); +} + +Expression* Parser::ParsePrimary() { + int32_t start = start_pos(); + switch (peek_type()) { + case Tok::kThis: + Advance(); + return Finish(New<ThisExpression>(start)); + case Tok::kNull: + Advance(); + return Finish(New<NullLiteral>(start)); + case Tok::kTrue: + case Tok::kFalse: { + BooleanLiteral* literal = New<BooleanLiteral>(start); + literal->value = Check(Tok::kTrue); + Advance(); + return Finish(literal); + } + case Tok::kNumber: { + NumericLiteral* literal = New<NumericLiteral>(start); + literal->value = cur().number_value; + literal->raw = Slice(cur().start, cur().end); + Advance(); + return Finish(literal); + } + case Tok::kBigInt: { + BigIntLiteral* literal = New<BigIntLiteral>(start); + literal->raw = Slice(cur().start, cur().end); + Advance(); + return Finish(literal); + } + case Tok::kString: { + StringLiteral* literal = New<StringLiteral>(start); + literal->value = cur().value; + literal->raw = Slice(cur().start, cur().end); + Advance(); + return Finish(literal); + } + case Tok::kDiv: + case Tok::kAssignDiv: { + if (!lexer_.RescanAsRegExp()) { + Fail(lexer_.has_error() ? lexer_.error() : "Invalid regular expression", + start); + return nullptr; + } + RegExpLiteral* literal = New<RegExpLiteral>(start); + literal->pattern = Intern(cur().value); + literal->regexp_flags = Intern(cur().flags); + Advance(); + return Finish(literal); + } + case Tok::kTemplateHead: + case Tok::kNoSubstitutionTemplate: + return ParseTemplateLiteral(false); + case Tok::kLeftParen: + return ParseParenthesized(); + case Tok::kLeftBracket: + return ParseArrayLiteral(); + case Tok::kLeftBrace: + return ParseObjectLiteral(); + case Tok::kFunction: + return ParseFunctionExpression(start, false); + case Tok::kClass: { + ClassExpression* cls = New<ClassExpression>(start); + if (!ParseClass(cls, start, true)) { + return nullptr; + } + return Finish(cls); + } + case Tok::kNew: + return ParseNewExpression(); + case Tok::kSuper: + return ParseSuper(); + case Tok::kImport: + return ParseImportExpressionOrMeta(); + case Tok::kMod: + if (options_.allow_natives_syntax) { + return ParseNativeCall(); + } + FailUnexpected(); + return nullptr; + case Tok::kName: { + if (CheckName("async")) { + Token next = PeekNext(); + if (next.type == Tok::kFunction && !next.newline_before) { + Advance(); // async + return ParseFunctionExpression(start, true); + } + } + return ParseIdentifierReference(); + } + default: + FailUnexpected(); + return nullptr; + } +} + +Expression* Parser::ParseIdentifierReference() { + if (!IsIdentifierToken()) { + FailUnexpected(); + return nullptr; + } + Identifier* id = New<Identifier>(start_pos()); + id->name = Intern(cur().value); + Advance(); + return Finish(id); +} + +Identifier* Parser::ParseIdentifierName() { + if (!Check(Tok::kName) && !IsKeyword(peek_type())) { + FailUnexpected(); + return nullptr; + } + Identifier* id = New<Identifier>(start_pos()); + id->name = Intern(cur().value); + Advance(); + return Finish(id); +} + +Identifier* Parser::ParseBindingIdentifier() { + if (!IsIdentifierToken()) { + FailUnexpected(); + return nullptr; + } + Identifier* id = New<Identifier>(start_pos()); + id->name = Intern(cur().value); + Advance(); + return Finish(id); +} + +Expression* Parser::ParseBindingPattern() { + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", start_pos()); + return nullptr; + } + int32_t start = start_pos(); + if (Check(Tok::kLeftBracket)) { + ArrayPattern* pattern = New<ArrayPattern>(start); + Advance(); + while (!Check(Tok::kRightBracket)) { + if (has_error()) { + return nullptr; + } + if (Check(Tok::kComma)) { + Advance(); + pattern->elements.push_back(nullptr); + continue; + } + if (Check(Tok::kEllipsis)) { + RestElement* rest = New<RestElement>(start_pos()); + Advance(); + rest->argument = ParseBindingPattern(); + if (rest->argument == nullptr) { + return nullptr; + } + pattern->elements.push_back(Finish(rest)); + if (!Check(Tok::kRightBracket)) { + FailUnexpected(); + return nullptr; + } + break; + } + Expression* element = ParseBindingElement(); + if (element == nullptr) { + return nullptr; + } + pattern->elements.push_back(element); + if (!Check(Tok::kRightBracket) && !Expect(Tok::kComma)) { + return nullptr; + } + } + if (!Expect(Tok::kRightBracket)) { + return nullptr; + } + return Finish(pattern); + } + if (Check(Tok::kLeftBrace)) { + ObjectPattern* pattern = New<ObjectPattern>(start); + Advance(); + while (!Check(Tok::kRightBrace)) { + if (has_error()) { + return nullptr; + } + if (Check(Tok::kEllipsis)) { + RestElement* rest = New<RestElement>(start_pos()); + Advance(); + rest->argument = ParseBindingIdentifier(); + if (rest->argument == nullptr) { + return nullptr; + } + pattern->properties.push_back(Finish(rest)); + if (!Check(Tok::kRightBrace)) { + FailUnexpected(); + return nullptr; + } + break; + } + Property* property = New<Property>(start_pos()); + bool computed = false; + bool key_is_plain_name = Check(Tok::kName); + property->key = ParsePropertyKey(&computed, false); + if (property->key == nullptr) { + return nullptr; + } + property->computed = computed; + if (Eat(Tok::kColon)) { + property->value = ParseBindingElement(); + if (property->value == nullptr) { + return nullptr; + } + } else { + if (!key_is_plain_name || computed) { + FailUnexpected(); + return nullptr; + } + auto* key = property->key->Cast<Identifier>(); + if (IsReservedWordInContext(key->name)) { + Fail("Unexpected reserved word", key->start); + return nullptr; + } + property->shorthand = true; + Identifier* value = New<Identifier>(key->start); + value->name = key->name; + value->end = key->end; + if (Check(Tok::kAssign)) { + Advance(); + AssignmentPattern* with_default = New<AssignmentPattern>(key->start); + with_default->left = value; + with_default->right = ParseAssignment(); + if (with_default->right == nullptr) { + return nullptr; + } + property->value = Finish(with_default); + } else { + property->value = value; + } + } + pattern->properties.push_back(Finish(property)); + if (!Check(Tok::kRightBrace) && !Expect(Tok::kComma)) { + return nullptr; + } + } + if (!Expect(Tok::kRightBrace)) { + return nullptr; + } + return Finish(pattern); + } + return ParseBindingIdentifier(); +} + +Expression* Parser::ParseBindingElement() { + int32_t start = start_pos(); + Expression* target = ParseBindingPattern(); + if (target == nullptr) { + return nullptr; + } + if (!Check(Tok::kAssign)) { + return target; + } + Advance(); + AssignmentPattern* pattern = New<AssignmentPattern>(start); + pattern->left = target; + pattern->right = ParseAssignment(); + if (pattern->right == nullptr) { + return nullptr; + } + return Finish(pattern); +} + +Expression* Parser::ParseParenthesized() { + int32_t start = start_pos(); + Advance(); // ( + std::vector<Expression*> items; + bool has_rest = false; + bool trailing_comma = false; + int32_t trailing_comma_pos = -1; + while (!Check(Tok::kRightParen)) { + if (has_error()) { + return nullptr; + } + if (Check(Tok::kEllipsis)) { + SpreadElement* spread = New<SpreadElement>(start_pos()); + Advance(); + spread->argument = ParseBindingPattern(); + if (spread->argument == nullptr) { + return nullptr; + } + items.push_back(Finish(spread)); + has_rest = true; + if (!Check(Tok::kRightParen)) { + FailUnexpected(); + return nullptr; + } + break; + } + Expression* item = ParseAssignment(); + if (item == nullptr) { + return nullptr; + } + items.push_back(item); + if (Check(Tok::kRightParen)) { + break; + } + trailing_comma_pos = start_pos(); + if (!Expect(Tok::kComma)) { + return nullptr; + } + trailing_comma = Check(Tok::kRightParen); + } + if (!Expect(Tok::kRightParen)) { + return nullptr; + } + if (Check(Tok::kArrow) && !cur().newline_before) { + Advance(); // => + return ParseArrowFromParams(std::move(items), start, false); + } + if (items.empty() || has_rest || trailing_comma) { + Fail("Unexpected token", + has_rest || items.empty() ? prev_end() : trailing_comma_pos); + return nullptr; + } + if (items.size() == 1) { + return items[0]; + } + SequenceExpression* sequence = New<SequenceExpression>(items[0]->start); + sequence->expressions = std::move(items); + sequence->end = sequence->expressions.back()->end; + return sequence; +} + +Expression* Parser::ParseArrayLiteral() { + ArrayExpression* array = New<ArrayExpression>(start_pos()); + Advance(); // [ + while (!Check(Tok::kRightBracket)) { + if (has_error()) { + return nullptr; + } + if (Check(Tok::kComma)) { + Advance(); + array->elements.push_back(nullptr); + continue; + } + Expression* element = ParseSpreadOrAssignment(); + if (element == nullptr) { + return nullptr; + } + array->elements.push_back(element); + if (!Check(Tok::kRightBracket) && !Expect(Tok::kComma)) { + return nullptr; + } + } + Advance(); // ] + return Finish(array); +} + +Expression* Parser::ParseObjectLiteral() { + ObjectExpression* object = New<ObjectExpression>(start_pos()); + Advance(); // { + while (!Check(Tok::kRightBrace)) { + if (has_error()) { + return nullptr; + } + Node* property = ParseObjectProperty(); + if (property == nullptr) { + return nullptr; + } + object->properties.push_back(property); + if (!Check(Tok::kRightBrace) && !Expect(Tok::kComma)) { + return nullptr; + } + } + Advance(); // } + return Finish(object); +} + +Node* Parser::ParseObjectProperty() { + int32_t start = start_pos(); + if (Check(Tok::kEllipsis)) { + SpreadElement* spread = New<SpreadElement>(start); + Advance(); + spread->argument = ParseAssignment(); + if (spread->argument == nullptr) { + return nullptr; + } + return Finish(spread); + } + Property* property = New<Property>(start); + bool is_async = false; + bool is_generator = false; + if (CheckName("get") || CheckName("set") || CheckName("async")) { + Token next = PeekNext(); + bool is_modifier = + !(next.type == Tok::kComma || next.type == Tok::kColon || + next.type == Tok::kLeftParen || next.type == Tok::kRightBrace || + next.type == Tok::kAssign || + (cur().value == "async" && next.newline_before)); + if (is_modifier) { + if (cur().value == "get") { + property->property_kind = PropertyKind::kGet; + } else if (cur().value == "set") { + property->property_kind = PropertyKind::kSet; + } else { + is_async = true; + } + Advance(); + } + } + if (Check(Tok::kMul)) { + is_generator = true; + Advance(); + } + bool computed = false; + bool key_is_plain_name = Check(Tok::kName); + int32_t key_start = start_pos(); + property->key = ParsePropertyKey(&computed, false); + if (property->key == nullptr) { + return nullptr; + } + property->computed = computed; + + bool is_accessor = property->property_kind != PropertyKind::kInit; + if (Check(Tok::kLeftParen) || is_accessor || is_async || is_generator) { + FunctionExpression* fn = New<FunctionExpression>(key_start); + fn->is_async = is_async; + fn->is_generator = is_generator; + if (!ParseFunctionRest( + fn, key_start, true, property->property_kind == PropertyKind::kGet, + property->property_kind == PropertyKind::kSet, false)) { + return nullptr; + } + property->value = Finish(fn); + property->method = !is_accessor; + return Finish(property); + } + if (Eat(Tok::kColon)) { + property->value = ParseAssignment(); + if (property->value == nullptr) { + return nullptr; + } + return Finish(property); + } + // Shorthand `{a}` or cover-initialized `{a = 1}` (only valid as a pattern). + if (!key_is_plain_name || computed) { + FailUnexpected(); + return nullptr; + } + auto* key = property->key->Cast<Identifier>(); + if (IsReservedWordInContext(key->name)) { + Fail("Unexpected reserved word", key->start); + return nullptr; + } + property->shorthand = true; + Identifier* value = New<Identifier>(key->start); + value->name = key->name; + value->end = key->end; + if (Check(Tok::kAssign)) { + Advance(); + AssignmentPattern* with_default = New<AssignmentPattern>(key->start); + with_default->left = value; + with_default->right = ParseAssignment(); + if (with_default->right == nullptr) { + return nullptr; + } + property->value = Finish(with_default); + } else { + property->value = value; + } + return Finish(property); +} + +Expression* Parser::ParseTemplateLiteral(bool tagged) { + TemplateLiteral* literal = New<TemplateLiteral>(start_pos()); + auto add_quasi = [&](const Token& token) -> bool { + TemplateElement* element = New<TemplateElement>(token.start); + bool is_tail = token.type == Tok::kNoSubstitutionTemplate || + token.type == Tok::kTemplateTail; + // Strip the delimiters: a leading '`' or '}' and a trailing '`' or '${'. + int32_t raw_start = token.start + 1; + int32_t raw_end = token.end - (is_tail ? 1 : 2); + element->raw = Slice(raw_start, raw_end); + element->cooked = token.value; + element->cooked_valid = token.cooked_valid; + element->tail = is_tail; + if (!tagged && !token.cooked_valid) { + Fail("Invalid escape sequence in template", token.start); + return false; + } + element->end = token.end; + literal->quasis.push_back(element); + return true; + }; + Token token = cur(); + if (!add_quasi(token)) { + return nullptr; + } + if (token.type == Tok::kNoSubstitutionTemplate) { + Advance(); + return Finish(literal); + } + Advance(); // past the head + while (true) { + if (has_error()) { + return nullptr; + } + Expression* expression = ParseExpression(); + if (expression == nullptr) { + return nullptr; + } + literal->expressions.push_back(expression); + if (!Check(Tok::kRightBrace)) { + FailUnexpected(); + return nullptr; + } + if (!lexer_.RescanAsTemplateContinuation()) { + Fail(lexer_.has_error() ? lexer_.error() : "Unterminated template", + start_pos()); + return nullptr; + } + token = cur(); + if (!add_quasi(token)) { + return nullptr; + } + Advance(); + if (token.type == Tok::kTemplateTail) { + break; + } + } + return Finish(literal); +} + +Expression* Parser::ParseFunctionExpression(int32_t start, bool is_async) { + FunctionExpression* fn = New<FunctionExpression>(start); + fn->is_async = is_async; + Advance(); // function + fn->is_generator = Eat(Tok::kMul); + if (!Check(Tok::kLeftParen)) { + // The name of a function expression is bound inside the function, so + // yield/await keyword-ness follows the function's own kind. + function_stack_.push_back(function_state_); + function_state_.is_async = is_async; + function_state_.is_generator = fn->is_generator; + function_state_.in_static_block = false; + fn->name = ParseBindingIdentifier(); + function_state_ = function_stack_.back(); + function_stack_.pop_back(); + if (fn->name == nullptr) { + return nullptr; + } + } + if (!ParseFunctionRest(fn, start, false, false, false, false)) { + return nullptr; + } + return Finish(fn); +} + +// --------------------------------------------------------------------------- +// Cover grammar + +bool Parser::IsValidSimpleAssignmentTarget(Expression* expression) const { + switch (expression->kind) { + case NodeKind::kIdentifier: + case NodeKind::kMemberExpression: + // Web compat: V8 accepts `f() = 1`, `f() += 1`, `f()++` and + // `for (f() in o)` in any mode and throws a ReferenceError at runtime. + case NodeKind::kCallExpression: + return true; + default: + return false; + } +} + +Expression* Parser::ToPattern(Expression* expression, bool binding) { + DepthGuard guard(&depth_); + if (depth_ > kMaxDepth) { + Fail("Maximum nesting depth exceeded", expression->start); + return nullptr; + } + switch (expression->kind) { + case NodeKind::kIdentifier: + return expression; + case NodeKind::kMemberExpression: + if (binding) { + break; + } + return expression; + case NodeKind::kObjectPattern: + case NodeKind::kArrayPattern: + case NodeKind::kAssignmentPattern: + case NodeKind::kRestElement: + return expression; + case NodeKind::kObjectExpression: { + auto* object = expression->Cast<ObjectExpression>(); + ObjectPattern* pattern = New<ObjectPattern>(object->start); + pattern->end = object->end; + for (size_t i = 0; i < object->properties.size(); i++) { + Node* entry = object->properties[i]; + if (auto* spread = entry->As<SpreadElement>()) { + if (i + 1 != object->properties.size()) { + Fail("Rest element must be last element", spread->start); + return nullptr; + } + RestElement* rest = New<RestElement>(spread->start); + rest->end = spread->end; + rest->argument = ToPattern(spread->argument, binding); + if (rest->argument == nullptr) { + return nullptr; + } + pattern->properties.push_back(rest); + continue; + } + auto* property = entry->Cast<Property>(); + if (property->method || + property->property_kind != PropertyKind::kInit) { + Fail("Invalid destructuring assignment target", property->start); + return nullptr; + } + property->value = ToPattern(property->value, binding); + if (property->value == nullptr) { + return nullptr; + } + pattern->properties.push_back(property); + } + return pattern; + } + case NodeKind::kArrayExpression: { + auto* array = expression->Cast<ArrayExpression>(); + ArrayPattern* pattern = New<ArrayPattern>(array->start); + pattern->end = array->end; + for (size_t i = 0; i < array->elements.size(); i++) { + Expression* element = array->elements[i]; + if (element == nullptr) { + pattern->elements.push_back(nullptr); + continue; + } + if (auto* spread = element->As<SpreadElement>()) { + if (i + 1 != array->elements.size()) { + Fail("Rest element must be last element", spread->start); + return nullptr; + } + RestElement* rest = New<RestElement>(spread->start); + rest->end = spread->end; + rest->argument = ToPattern(spread->argument, binding); + if (rest->argument == nullptr) { + return nullptr; + } + pattern->elements.push_back(rest); + continue; + } + Expression* converted = ToPattern(element, binding); + if (converted == nullptr) { + return nullptr; + } + pattern->elements.push_back(converted); + } + return pattern; + } + case NodeKind::kAssignmentExpression: { + auto* assignment = expression->Cast<AssignmentExpression>(); + if (assignment->op != AssignOp::kAssign) { + break; + } + AssignmentPattern* pattern = New<AssignmentPattern>(assignment->start); + pattern->end = assignment->end; + pattern->left = ToPattern(assignment->left, binding); + if (pattern->left == nullptr) { + return nullptr; + } + pattern->right = assignment->right; + return pattern; + } + default: + break; + } + Fail(binding ? "Invalid destructuring assignment target" + : "Invalid left-hand side in assignment", + expression->start); + return nullptr; +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/parser.h b/deps/v8/experimental/redline/fast/parser.h new file mode 100644 index 000000000000..8e93e11c0ed2 --- /dev/null +++ b/deps/v8/experimental/redline/fast/parser.h @@ -0,0 +1,216 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_PARSER_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_PARSER_H_ + +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/fast/ast.h" +#include "experimental/redline/fast/lexer.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { +namespace fast { + +struct ParseOptions { + // Accept `%RuntimeFunction(...)` calls (d8 --allow-natives-syntax). + bool allow_natives_syntax = true; + // Parse as strict code from the start. + bool strict = false; +}; + +struct ParseError { + std::string message; + int32_t position = -1; // byte offset + int line = 0; // 1-based + int column = 0; // 1-based, in bytes + + std::string ToString() const; +}; + +// Computes line/column for a byte offset. +void ComputeLineColumn(std::string_view source, int32_t position, int* line, + int* column); + +// A recursive-descent parser for ECMAScript scripts (ES2024 plus the V8 +// extensions used by tests: natives syntax, `using` declarations, HTML +// comments). It is deliberately lenient about early errors that do not +// affect the tree shape (the target engine reports those); it must reject +// what it cannot represent and must never produce a tree that prints to a +// program with different semantics than the input. +class Parser { + public: + // Parses a script. Returns nullptr and fills `error` on failure. + static std::unique_ptr<Tree> ParseScript(std::string_view source, + const ParseOptions& options, + ParseError* error); + + // Parses a single expression (for the shell). Returns nullptr on failure. + static Expression* ParseExpressionInto(Tree* tree, std::string_view source, + const ParseOptions& options, + ParseError* error); + + private: + struct FunctionState { + bool is_async = false; + bool is_generator = false; + bool is_arrow = false; + bool in_function = false; // false at the top level + bool in_class_field_init = false; + bool in_static_block = false; + bool strict = false; + }; + + Parser(Tree* tree, std::string_view source, const ParseOptions& options); + + // --- token helpers --- + const Token& cur() const { return lexer_.current(); } + Tok peek_type() const { return lexer_.current().type; } + bool Check(Tok type) const { return peek_type() == type; } + bool CheckName(std::string_view name) const { + return peek_type() == Tok::kName && !cur().has_escape && + cur().value == name; + } + void Advance(); + bool Eat(Tok type); + bool EatName(std::string_view name); + bool Expect(Tok type); + bool ExpectName(std::string_view name); + bool ConsumeSemicolon(); + bool CanInsertSemicolon() const; + // Looks at the token after the current one without consuming anything. + Token PeekNext(); + Token PeekNext2(); + + // Errors. + bool Fail(const std::string& message, int32_t position); + bool FailUnexpected(); + bool has_error() const { return failed_; } + + int32_t start_pos() const { return cur().start; } + int32_t prev_end() const { return prev_token_end_; } + // True if `e` is an arrow function that was not wrapped in parentheses: + // nothing (no operator, subscript or `?`) may follow it. A parenthesized + // arrow ends before the `)` that was consumed after it. + bool IsBareArrow(const Expression* e) const { + return e->Is<ArrowFunctionExpression>() && e->end == prev_end(); + } + + template <typename T> + T* New(int32_t start) { + return tree_->New<T>(start, -1); + } + template <typename T> + T* Finish(T* node) { + node->end = prev_end(); + return node; + } + std::string_view Intern(const std::string& text) { + return tree_->Intern(text); + } + std::string_view Slice(int32_t start, int32_t end) const { + return source_.substr(static_cast<size_t>(start), + static_cast<size_t>(end - start)); + } + + // Identifier classification. + bool IsIdentifierToken() const; // kName usable as a binding/reference + bool IsReservedWordInContext(std::string_view name) const; + static bool TokenCanStartPropertyName(Tok type); + bool IsLetDeclarationStart(); + bool IsUsingDeclarationStart(); + bool TokenStartsExpression() const; + + // --- program & statements --- + Program* ParseProgram(); + bool ParseDirectivePrologue(std::vector<Statement*>* body, bool* strict); + Statement* ParseStatementListItem(); + Statement* ParseStatement(bool single_statement); + BlockStatement* ParseBlock(); + Statement* ParseVariableStatement(VariableKind kind, int32_t start); + VariableDeclaration* ParseVariableDeclarationList(VariableKind kind, + int32_t start, bool no_in, + bool for_init); + Statement* ParseIfStatement(); + Statement* ParseForStatement(); + Statement* ParseWhileStatement(); + Statement* ParseDoWhileStatement(); + Statement* ParseBreakContinue(bool is_break); + Statement* ParseReturnStatement(); + Statement* ParseWithStatement(); + Statement* ParseSwitchStatement(); + Statement* ParseThrowStatement(); + Statement* ParseTryStatement(); + Statement* ParseExpressionOrLabeledStatement(); + Statement* ParseFunctionDeclaration(int32_t start, bool is_async); + Statement* ParseClassDeclaration(); + + // --- functions & classes --- + bool ParseFunctionRest(FunctionData* fn, int32_t start, bool is_method, + bool is_getter, bool is_setter, bool is_constructor); + bool ParseFormalParameters(FunctionData* fn); + bool ParseFunctionBody(FunctionData* fn); + Expression* ParseArrowFromParams(std::vector<Expression*> params, + int32_t start, bool is_async); + bool ParseArrowBody(ArrowFunctionExpression* arrow); + bool ParseClass(ClassData* cls, int32_t start, bool is_expression); + Node* ParseClassMember(); + Expression* ParsePropertyKey(bool* computed, bool allow_private); + + // --- expressions --- + Expression* ParseExpression(bool no_in = false); + Expression* ParseAssignment(bool no_in = false); + Expression* ParseYield(bool no_in); + Expression* ParseConditional(bool no_in); + Expression* ParseBinary(int min_precedence, bool no_in); + Expression* ParseUnary(); + Expression* ParsePostfix(); + Expression* ParseLeftHandSide(); + Expression* ParseSubscripts(Expression* base, int32_t start, bool no_calls); + Expression* ParseNewExpression(); + Expression* ParsePrimary(); + Expression* ParseParenthesized(); + Expression* ParseArrayLiteral(); + Expression* ParseObjectLiteral(); + Node* ParseObjectProperty(); + Expression* ParseTemplateLiteral(bool tagged); + Expression* ParseFunctionExpression(int32_t start, bool is_async); + Expression* ParseNativeCall(); + Expression* ParseIdentifierReference(); + Identifier* ParseIdentifierName(); // any name incl. reserved words + Identifier* ParseBindingIdentifier(); + Expression* + ParseBindingPattern(); // Identifier / ObjectPattern / ArrayPattern + Expression* ParseBindingElement(); // pattern with optional default + bool ParseArguments(std::vector<Expression*>* arguments); + Expression* ParseSpreadOrAssignment(); + Expression* ParseImportExpressionOrMeta(); + Expression* ParseSuper(); + + // Cover grammar: reinterprets an expression as an assignment/binding + // pattern. Returns nullptr (with an error) if that is not possible. + Expression* ToPattern(Expression* expression, bool binding); + bool IsValidSimpleAssignmentTarget(Expression* expression) const; + + Tree* tree_; + std::string_view source_; + ParseOptions options_; + Lexer lexer_; + int32_t prev_token_end_ = 0; + bool failed_ = false; + ParseError error_; + FunctionState function_state_; + std::vector<FunctionState> function_stack_; + // Nesting depth guard against pathological inputs. + int depth_ = 0; +}; + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_PARSER_H_ diff --git a/deps/v8/experimental/redline/fast/printer.cc b/deps/v8/experimental/redline/fast/printer.cc new file mode 100644 index 000000000000..2ea810207ccf --- /dev/null +++ b/deps/v8/experimental/redline/fast/printer.cc @@ -0,0 +1,1550 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/printer.h" + +#include <cmath> +#include <cstring> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/fast/lexer.h" +#include "src/base/vector.h" +#include "src/numbers/conversions.h" + +namespace redline { +namespace fast { + +namespace { + +// Expression precedence levels used by the printer (higher binds tighter). +enum Precedence : int { + kPrecSequence = 0, + kPrecAssign = 1, // assignment, arrow, yield + kPrecConditional = 2, + kPrecNullish = 3, + kPrecOr = 4, + kPrecAnd = 5, + kPrecBitOr = 6, + kPrecBitXor = 7, + kPrecBitAnd = 8, + kPrecEquality = 9, + kPrecRelational = 10, + kPrecShift = 11, + kPrecAdditive = 12, + kPrecMultiplicative = 13, + kPrecExponent = 14, + kPrecUnary = 15, + kPrecPostfix = 16, + kPrecCall = 18, // call, optional chain + kPrecMember = 19, // member, new with arguments, tagged template + kPrecPrimary = 20, +}; + +int BinaryPrec(BinaryOp op) { return 2 + BinaryPrecedence(op); } +int LogicalPrec(LogicalOp op) { return 2 + LogicalPrecedence(op); } + +bool IsAllDigits(std::string_view text) { + if (text.empty()) { + return false; + } + for (char c : text) { + if (!(c >= '0' && c <= '9') && c != '_') { + return false; + } + } + return true; +} + +class Printer { + public: + Printer(const PrintOptions& options, std::vector<NodeSpan>* spans) + : options_(options), spans_(spans) {} + + std::string Finish() { return std::move(out_); } + + void PrintNode(const Node* node) { + if (node->IsExpression()) { + PrintExpression(node->Cast<Expression>(), kPrecSequence); + } else if (node->IsStatement()) { + PrintStatement(node->Cast<Statement>()); + } else { + switch (node->kind) { + case NodeKind::kProgram: + PrintProgram(node->Cast<Program>()); + break; + case NodeKind::kVariableDeclarator: + PrintDeclarator(node->Cast<VariableDeclarator>()); + break; + case NodeKind::kSwitchCase: + PrintSwitchCase(node->Cast<SwitchCase>()); + break; + case NodeKind::kCatchClause: + PrintCatchClause(node->Cast<CatchClause>()); + break; + case NodeKind::kProperty: + PrintProperty(node->Cast<Property>()); + break; + case NodeKind::kClassBody: + PrintClassBody(node->Cast<ClassBody>()); + break; + case NodeKind::kMethodDefinition: + case NodeKind::kPropertyDefinition: + case NodeKind::kStaticBlock: + PrintClassMember(node); + break; + case NodeKind::kTemplateElement: + Emit(node->Cast<TemplateElement>()->raw); + break; + default: + Emit("/* ? */"); + break; + } + } + } + + private: + struct SpanScope { + SpanScope(Printer* printer, const Node* node) + : printer_(printer), + node_(node), + start_(static_cast<int32_t>(printer->out_.size())) {} + ~SpanScope() { + if (printer_->spans_ != nullptr) { + printer_->spans_->push_back( + {node_->id, start_, static_cast<int32_t>(printer_->out_.size())}); + } + } + Printer* printer_; + const Node* node_; + int32_t start_; + }; + + // Clears the "no `in`" restriction inside brackets/braces/function bodies. + struct AllowIn { + explicit AllowIn(Printer* printer) + : printer_(printer), saved_(printer->no_in_) { + printer_->no_in_ = false; + } + ~AllowIn() { printer_->no_in_ = saved_; } + Printer* printer_; + bool saved_; + }; + + void Emit(std::string_view text) { out_.append(text); } + void Emit(char c) { out_.push_back(c); } + + void Newline() { + if (!options_.pretty) { + Emit(' '); + return; + } + Emit('\n'); + for (int i = 0; i < indent_; i++) { + Emit(" "); + } + } + + // With PrintOptions::node_ids, simple statements get a trailing + // `// nN` comment and compound statements (blocks, loops, functions, ...) + // a leading `/*nN*/` marker, so that every statement id is visible. + static bool IsSimpleStatement(NodeKind kind) { + switch (kind) { + case NodeKind::kExpressionStatement: + case NodeKind::kVariableDeclaration: + case NodeKind::kReturnStatement: + case NodeKind::kThrowStatement: + case NodeKind::kBreakStatement: + case NodeKind::kContinueStatement: + case NodeKind::kEmptyStatement: + case NodeKind::kDebuggerStatement: + return true; + default: + return false; + } + } + void EmitLeadingNodeId(const Node* node) { + if (options_.node_ids && !IsSimpleStatement(node->kind)) { + Emit(StringPrintf("/*n%u*/ ", node->id)); + } + } + void EmitTrailingNodeId(const Node* node) { + if (options_.node_ids && IsSimpleStatement(node->kind)) { + Emit(StringPrintf(" // n%u", node->id)); + } + } + + // --- program & statements --- + + void PrintProgram(const Program* program) { + SpanScope span(this, program); + for (size_t i = 0; i < program->body.size(); i++) { + if (i > 0) { + Newline(); + } + PrintStatement(program->body[i]); + } + if (options_.pretty && !program->body.empty()) { + Emit('\n'); + } + } + + void PrintStatementList(const std::vector<Statement*>& statements) { + indent_++; + for (const Statement* statement : statements) { + Newline(); + PrintStatement(statement); + } + indent_--; + } + + void PrintBlock(const BlockStatement* block) { + SpanScope span(this, block); + AllowIn allow_in(this); + Emit('{'); + if (block->body.empty()) { + Emit('}'); + return; + } + PrintStatementList(block->body); + Newline(); + Emit('}'); + } + + // Prints the body of if/loops/with/labeled statements. + void PrintBody(const Statement* body) { + if (body->Is<BlockStatement>()) { + Emit(' '); + PrintBlock(body->Cast<BlockStatement>()); + return; + } + if (body->Is<EmptyStatement>()) { + Emit(';'); + return; + } + indent_++; + Newline(); + PrintStatement(body); + indent_--; + } + + // True if `statement` ends with an `if` without `else` (so that an `else` + // following it would bind to the wrong `if`). + static bool EndsWithDanglingIf(const Statement* statement) { + while (statement != nullptr) { + switch (statement->kind) { + case NodeKind::kIfStatement: { + auto* if_statement = statement->Cast<IfStatement>(); + if (if_statement->alternate == nullptr) { + return true; + } + statement = if_statement->alternate; + break; + } + case NodeKind::kLabeledStatement: + statement = statement->Cast<LabeledStatement>()->body; + break; + case NodeKind::kWithStatement: + statement = statement->Cast<WithStatement>()->body; + break; + case NodeKind::kWhileStatement: + statement = statement->Cast<WhileStatement>()->body; + break; + case NodeKind::kForStatement: + statement = statement->Cast<ForStatement>()->body; + break; + case NodeKind::kForInStatement: + statement = statement->Cast<ForInStatement>()->body; + break; + case NodeKind::kForOfStatement: + statement = statement->Cast<ForOfStatement>()->body; + break; + default: + return false; + } + } + return false; + } + + void PrintStatement(const Statement* statement) { + SpanScope span(this, statement); + EmitLeadingNodeId(statement); + switch (statement->kind) { + case NodeKind::kExpressionStatement: { + auto* s = statement->Cast<ExpressionStatement>(); + if (s->is_directive && s->expression->Is<StringLiteral>() && + !s->expression->Cast<StringLiteral>()->raw.empty()) { + Emit(s->expression->Cast<StringLiteral>()->raw); + } else if (StartsWithForbiddenToken(s->expression)) { + Emit('('); + { + AllowIn allow_in(this); + PrintExpression(s->expression, kPrecSequence); + } + Emit(')'); + } else { + PrintExpression(s->expression, kPrecSequence); + } + Emit(';'); + break; + } + case NodeKind::kBlockStatement: + PrintBlock(statement->Cast<BlockStatement>()); + break; + case NodeKind::kEmptyStatement: + Emit(';'); + break; + case NodeKind::kDebuggerStatement: + Emit("debugger;"); + break; + case NodeKind::kWithStatement: { + auto* s = statement->Cast<WithStatement>(); + Emit("with ("); + PrintExpression(s->object, kPrecSequence); + Emit(')'); + PrintBody(s->body); + break; + } + case NodeKind::kReturnStatement: { + auto* s = statement->Cast<ReturnStatement>(); + Emit("return"); + if (s->argument != nullptr) { + Emit(' '); + PrintExpression(s->argument, kPrecSequence); + } + Emit(';'); + break; + } + case NodeKind::kLabeledStatement: { + auto* s = statement->Cast<LabeledStatement>(); + Emit(s->label->name); + Emit(':'); + if (s->body->Is<BlockStatement>()) { + Emit(' '); + PrintBlock(s->body->Cast<BlockStatement>()); + } else { + Emit(' '); + PrintStatement(s->body); + } + break; + } + case NodeKind::kBreakStatement: { + auto* s = statement->Cast<BreakStatement>(); + Emit("break"); + if (s->label != nullptr) { + Emit(' '); + Emit(s->label->name); + } + Emit(';'); + break; + } + case NodeKind::kContinueStatement: { + auto* s = statement->Cast<ContinueStatement>(); + Emit("continue"); + if (s->label != nullptr) { + Emit(' '); + Emit(s->label->name); + } + Emit(';'); + break; + } + case NodeKind::kIfStatement: { + auto* s = statement->Cast<IfStatement>(); + Emit("if ("); + PrintExpression(s->test, kPrecSequence); + Emit(')'); + if (s->alternate != nullptr && !s->consequent->Is<BlockStatement>() && + EndsWithDanglingIf(s->consequent)) { + Emit(" {"); + indent_++; + Newline(); + PrintStatement(s->consequent); + indent_--; + Newline(); + Emit('}'); + } else { + PrintBody(s->consequent); + } + if (s->alternate != nullptr) { + if (s->consequent->Is<BlockStatement>()) { + Emit(' '); + } else { + Newline(); + } + Emit("else"); + if (s->alternate->Is<IfStatement>()) { + Emit(' '); + PrintStatement(s->alternate); + } else { + PrintBody(s->alternate); + } + } + break; + } + case NodeKind::kSwitchStatement: { + auto* s = statement->Cast<SwitchStatement>(); + Emit("switch ("); + PrintExpression(s->discriminant, kPrecSequence); + Emit(") {"); + indent_++; + for (const SwitchCase* switch_case : s->cases) { + Newline(); + PrintSwitchCase(switch_case); + } + indent_--; + Newline(); + Emit('}'); + break; + } + case NodeKind::kThrowStatement: { + auto* s = statement->Cast<ThrowStatement>(); + Emit("throw "); + PrintExpression(s->argument, kPrecSequence); + Emit(';'); + break; + } + case NodeKind::kTryStatement: { + auto* s = statement->Cast<TryStatement>(); + Emit("try "); + PrintBlock(s->block); + if (s->handler != nullptr) { + Emit(' '); + PrintCatchClause(s->handler); + } + if (s->finalizer != nullptr) { + Emit(" finally "); + PrintBlock(s->finalizer); + } + break; + } + case NodeKind::kWhileStatement: { + auto* s = statement->Cast<WhileStatement>(); + Emit("while ("); + PrintExpression(s->test, kPrecSequence); + Emit(')'); + PrintBody(s->body); + break; + } + case NodeKind::kDoWhileStatement: { + auto* s = statement->Cast<DoWhileStatement>(); + Emit("do"); + PrintBody(s->body); + if (s->body->Is<BlockStatement>()) { + Emit(' '); + } else { + Newline(); + } + Emit("while ("); + PrintExpression(s->test, kPrecSequence); + Emit(");"); + break; + } + case NodeKind::kForStatement: { + auto* s = statement->Cast<ForStatement>(); + Emit("for ("); + if (s->init != nullptr) { + bool saved = no_in_; + no_in_ = true; + if (s->init->Is<VariableDeclaration>()) { + PrintVariableDeclaration(s->init->Cast<VariableDeclaration>(), + false); + } else { + PrintExpression(s->init->Cast<Expression>(), kPrecSequence); + } + no_in_ = saved; + } + Emit(';'); + if (s->test != nullptr) { + Emit(' '); + PrintExpression(s->test, kPrecSequence); + } + Emit(';'); + if (s->update != nullptr) { + Emit(' '); + PrintExpression(s->update, kPrecSequence); + } + Emit(')'); + PrintBody(s->body); + break; + } + case NodeKind::kForInStatement: { + auto* s = statement->Cast<ForInStatement>(); + Emit("for ("); + PrintForEachLeft(s->left, false); + Emit(" in "); + PrintExpression(s->right, kPrecSequence); + Emit(')'); + PrintBody(s->body); + break; + } + case NodeKind::kForOfStatement: { + auto* s = statement->Cast<ForOfStatement>(); + Emit(s->is_await ? "for await (" : "for ("); + PrintForEachLeft(s->left, true); + Emit(" of "); + PrintExpression(s->right, kPrecAssign); + Emit(')'); + PrintBody(s->body); + break; + } + case NodeKind::kFunctionDeclaration: + PrintFunction(statement->Cast<FunctionDeclaration>(), statement); + break; + case NodeKind::kVariableDeclaration: + PrintVariableDeclaration(statement->Cast<VariableDeclaration>(), true); + break; + case NodeKind::kClassDeclaration: + PrintClass(statement->Cast<ClassDeclaration>(), statement); + break; + default: + Emit("/* unknown statement */;"); + break; + } + EmitTrailingNodeId(statement); + } + + void PrintForEachLeft(const Node* left, bool for_of) { + bool saved = no_in_; + no_in_ = true; + if (left->Is<VariableDeclaration>()) { + PrintVariableDeclaration(left->Cast<VariableDeclaration>(), false); + } else { + // `for (async of ...)` is forbidden, but `for ((async) of ...)` is + // fine; the caller tells us whether this is a for-of head. + auto* expression = left->Cast<Expression>(); + bool is_async_identifier = + expression->Is<Identifier>() && + expression->Cast<Identifier>()->name == "async"; + if (is_async_identifier && for_of) { + Emit('('); + PrintExpression(expression, kPrecSequence); + Emit(')'); + } else { + PrintExpression(expression, kPrecCall); + } + } + no_in_ = saved; + } + + void PrintSwitchCase(const SwitchCase* switch_case) { + SpanScope span(this, switch_case); + if (switch_case->test != nullptr) { + Emit("case "); + PrintExpression(switch_case->test, kPrecSequence); + Emit(':'); + } else { + Emit("default:"); + } + PrintStatementList(switch_case->consequent); + } + + void PrintCatchClause(const CatchClause* handler) { + SpanScope span(this, handler); + Emit("catch"); + if (handler->param != nullptr) { + Emit(" ("); + PrintPattern(handler->param); + Emit(')'); + } + Emit(' '); + PrintBlock(handler->body); + } + + void PrintVariableDeclaration(const VariableDeclaration* declaration, + bool with_semicolon) { + SpanScope span(this, declaration); + Emit(VariableKindText(declaration->declaration_kind)); + Emit(' '); + for (size_t i = 0; i < declaration->declarations.size(); i++) { + if (i > 0) { + Emit(", "); + } + PrintDeclarator(declaration->declarations[i]); + } + if (with_semicolon) { + Emit(';'); + } + } + + void PrintDeclarator(const VariableDeclarator* declarator) { + SpanScope span(this, declarator); + PrintPattern(declarator->target); + if (declarator->init != nullptr) { + Emit(" = "); + PrintExpression(declarator->init, kPrecAssign); + } + } + + // --- functions & classes --- + + void PrintParams(const std::vector<Expression*>& params) { + AllowIn allow_in(this); + Emit('('); + for (size_t i = 0; i < params.size(); i++) { + if (i > 0) { + Emit(", "); + } + PrintPattern(params[i]); + } + Emit(')'); + } + + void PrintFunctionBody(const BlockStatement* body) { + AllowIn allow_in(this); + PrintBlock(body); + } + + void PrintFunction(const FunctionData* fn, const Node* node) { + SpanScope span(this, node); + if (fn->is_async) { + Emit("async "); + } + Emit("function"); + if (fn->is_generator) { + Emit('*'); + } + if (fn->name != nullptr) { + Emit(' '); + Emit(fn->name->name); + } + PrintParams(fn->params); + Emit(' '); + PrintFunctionBody(fn->body); + } + + void PrintArrow(const ArrowFunctionExpression* arrow) { + if (arrow->is_async) { + Emit("async "); + } + PrintParams(arrow->params); + Emit(" => "); + if (arrow->body != nullptr) { + PrintFunctionBody(arrow->body); + return; + } + const Expression* body = arrow->expression_body; + if (body->Is<ObjectExpression>() || StartsWithObjectLiteral(body)) { + Emit('('); + AllowIn allow_in(this); + PrintExpression(body, kPrecSequence); + Emit(')'); + } else { + PrintExpression(body, kPrecAssign); + } + } + + void PrintClass(const ClassData* cls, const Node* node) { + SpanScope span(this, node); + AllowIn allow_in(this); + Emit("class"); + if (cls->name != nullptr) { + Emit(' '); + Emit(cls->name->name); + } + if (cls->super_class != nullptr) { + Emit(" extends "); + PrintExpression(cls->super_class, kPrecCall); + } + Emit(' '); + PrintClassBody(cls->body); + } + + void PrintClassBody(const ClassBody* body) { + SpanScope span(this, body); + Emit('{'); + if (body->members.empty()) { + Emit('}'); + return; + } + indent_++; + for (const Node* member : body->members) { + Newline(); + PrintClassMember(member); + } + indent_--; + Newline(); + Emit('}'); + } + + void PrintPropertyKey(const Expression* key, bool computed) { + if (computed) { + Emit('['); + AllowIn allow_in(this); + PrintExpression(key, kPrecAssign); + Emit(']'); + return; + } + switch (key->kind) { + case NodeKind::kIdentifier: + Emit(key->Cast<Identifier>()->name); + break; + case NodeKind::kPrivateIdentifier: + Emit('#'); + Emit(key->Cast<PrivateIdentifier>()->name); + break; + case NodeKind::kStringLiteral: + PrintStringLiteral(key->Cast<StringLiteral>()); + break; + case NodeKind::kNumericLiteral: + PrintNumericLiteral(key->Cast<NumericLiteral>(), false); + break; + case NodeKind::kBigIntLiteral: + Emit(key->Cast<BigIntLiteral>()->raw); + break; + default: + // Not a valid non-computed key; print computed to stay parseable. + Emit('['); + PrintExpression(key, kPrecAssign); + Emit(']'); + break; + } + } + + void PrintMethodSignatureAndBody(const FunctionExpression* fn) { + PrintParams(fn->params); + Emit(' '); + PrintFunctionBody(fn->body); + } + + void PrintClassMember(const Node* member) { + SpanScope span(this, member); + switch (member->kind) { + case NodeKind::kMethodDefinition: { + auto* m = member->Cast<MethodDefinition>(); + if (m->is_static) { + Emit("static "); + } + if (m->method_kind == MethodKind::kGet) { + Emit("get "); + } + if (m->method_kind == MethodKind::kSet) { + Emit("set "); + } + if (m->value->is_async) { + Emit("async "); + } + if (m->value->is_generator) { + Emit('*'); + } + PrintPropertyKey(m->key, m->computed); + PrintMethodSignatureAndBody(m->value); + break; + } + case NodeKind::kPropertyDefinition: { + auto* p = member->Cast<PropertyDefinition>(); + if (p->is_static) { + Emit("static "); + } + if (p->is_auto_accessor) { + Emit("accessor "); + } + PrintPropertyKey(p->key, p->computed); + if (p->value != nullptr) { + Emit(" = "); + AllowIn allow_in(this); + PrintExpression(p->value, kPrecAssign); + } + Emit(';'); + break; + } + case NodeKind::kStaticBlock: { + auto* block = member->Cast<StaticBlock>(); + Emit("static {"); + PrintStatementList(block->body); + Newline(); + Emit('}'); + break; + } + default: + Emit("/* ? */;"); + break; + } + } + + // --- object literal properties and patterns --- + + void PrintProperty(const Property* property) { + SpanScope span(this, property); + if (property->property_kind == PropertyKind::kGet || + property->property_kind == PropertyKind::kSet || property->method) { + auto* fn = property->value->Cast<FunctionExpression>(); + if (property->property_kind == PropertyKind::kGet) { + Emit("get "); + } + if (property->property_kind == PropertyKind::kSet) { + Emit("set "); + } + if (fn->is_async) { + Emit("async "); + } + if (fn->is_generator) { + Emit('*'); + } + PrintPropertyKey(property->key, property->computed); + PrintMethodSignatureAndBody(fn); + return; + } + if (property->shorthand && !property->computed && + property->key->Is<Identifier>()) { + // `{a}` or `{a = 1}` (in patterns). + if (auto* with_default = property->value->As<AssignmentPattern>()) { + if (auto* id = with_default->left->As<Identifier>()) { + if (id->name == property->key->Cast<Identifier>()->name) { + Emit(id->name); + Emit(" = "); + PrintExpression(with_default->right, kPrecAssign); + return; + } + } + } else if (auto* id = property->value->As<Identifier>()) { + if (id->name == property->key->Cast<Identifier>()->name) { + Emit(id->name); + return; + } + } + } + PrintPropertyKey(property->key, property->computed); + Emit(": "); + PrintPattern(property->value); + } + + // Prints a binding/assignment target (patterns or plain expressions). + void PrintPattern(const Expression* pattern) { + switch (pattern->kind) { + case NodeKind::kObjectPattern: { + SpanScope span(this, pattern); + AllowIn allow_in(this); + auto* p = pattern->Cast<ObjectPattern>(); + Emit('{'); + for (size_t i = 0; i < p->properties.size(); i++) { + if (i > 0) { + Emit(", "); + } + const Node* entry = p->properties[i]; + if (auto* rest = entry->As<RestElement>()) { + SpanScope rest_span(this, rest); + Emit("..."); + PrintPattern(rest->argument); + } else { + PrintProperty(entry->Cast<Property>()); + } + } + Emit('}'); + break; + } + case NodeKind::kArrayPattern: { + SpanScope span(this, pattern); + AllowIn allow_in(this); + auto* p = pattern->Cast<ArrayPattern>(); + Emit('['); + for (size_t i = 0; i < p->elements.size(); i++) { + if (i > 0) { + Emit(", "); + } + const Expression* element = p->elements[i]; + if (element == nullptr) { + if (i + 1 == p->elements.size()) { + Emit(','); + } + continue; + } + PrintPattern(element); + } + Emit(']'); + break; + } + case NodeKind::kRestElement: { + SpanScope span(this, pattern); + Emit("..."); + PrintPattern(pattern->Cast<RestElement>()->argument); + break; + } + case NodeKind::kAssignmentPattern: { + SpanScope span(this, pattern); + auto* p = pattern->Cast<AssignmentPattern>(); + PrintPattern(p->left); + Emit(" = "); + PrintExpression(p->right, kPrecAssign); + break; + } + default: + PrintExpression(pattern, kPrecAssign); + break; + } + } + + // --- expressions --- + + static int PrecedenceOf(const Expression* e) { + switch (e->kind) { + case NodeKind::kSequenceExpression: + return kPrecSequence; + case NodeKind::kAssignmentExpression: + case NodeKind::kArrowFunctionExpression: + case NodeKind::kYieldExpression: + return kPrecAssign; + case NodeKind::kConditionalExpression: + return kPrecConditional; + case NodeKind::kLogicalExpression: + return LogicalPrec(e->Cast<LogicalExpression>()->op); + case NodeKind::kBinaryExpression: + return BinaryPrec(e->Cast<BinaryExpression>()->op); + case NodeKind::kUnaryExpression: + case NodeKind::kAwaitExpression: + return kPrecUnary; + case NodeKind::kUpdateExpression: + return e->Cast<UpdateExpression>()->prefix ? kPrecUnary : kPrecPostfix; + case NodeKind::kCallExpression: + case NodeKind::kChainExpression: + case NodeKind::kImportExpression: + return kPrecCall; + case NodeKind::kMemberExpression: + case NodeKind::kNewExpression: + case NodeKind::kTaggedTemplateExpression: + case NodeKind::kMetaProperty: + return kPrecMember; + case NodeKind::kNumericLiteral: + return e->Cast<NumericLiteral>()->value < 0 || + std::signbit(e->Cast<NumericLiteral>()->value) + ? kPrecUnary + : kPrecPrimary; + default: + return kPrecPrimary; + } + } + + // Expression statements may not start with `{`, `function`, `class`, + // `async function` or `let [`. + static bool StartsWithForbiddenToken(const Expression* e) { + const Expression* parent = nullptr; + while (true) { + switch (e->kind) { + case NodeKind::kObjectExpression: + case NodeKind::kObjectPattern: + case NodeKind::kFunctionExpression: + case NodeKind::kClassExpression: + return true; + case NodeKind::kIdentifier: + return e->Cast<Identifier>()->name == "let" && parent != nullptr && + parent->Is<MemberExpression>() && + parent->Cast<MemberExpression>()->computed; + case NodeKind::kSequenceExpression: + parent = e; + e = e->Cast<SequenceExpression>()->expressions.front(); + break; + case NodeKind::kAssignmentExpression: + parent = e; + e = e->Cast<AssignmentExpression>()->left; + break; + case NodeKind::kConditionalExpression: + parent = e; + e = e->Cast<ConditionalExpression>()->test; + break; + case NodeKind::kBinaryExpression: + parent = e; + e = e->Cast<BinaryExpression>()->left; + break; + case NodeKind::kLogicalExpression: + parent = e; + e = e->Cast<LogicalExpression>()->left; + break; + case NodeKind::kCallExpression: + parent = e; + e = e->Cast<CallExpression>()->callee; + break; + case NodeKind::kMemberExpression: + parent = e; + e = e->Cast<MemberExpression>()->object; + break; + case NodeKind::kTaggedTemplateExpression: + parent = e; + e = e->Cast<TaggedTemplateExpression>()->tag; + break; + case NodeKind::kChainExpression: + parent = e; + e = e->Cast<ChainExpression>()->expression; + break; + case NodeKind::kUpdateExpression: + if (e->Cast<UpdateExpression>()->prefix) { + return false; + } + parent = e; + e = e->Cast<UpdateExpression>()->argument; + break; + default: + return false; + } + } + } + + static bool StartsWithObjectLiteral(const Expression* e) { + while (true) { + switch (e->kind) { + case NodeKind::kObjectExpression: + case NodeKind::kObjectPattern: + return true; + case NodeKind::kSequenceExpression: + e = e->Cast<SequenceExpression>()->expressions.front(); + break; + case NodeKind::kAssignmentExpression: + e = e->Cast<AssignmentExpression>()->left; + break; + case NodeKind::kConditionalExpression: + e = e->Cast<ConditionalExpression>()->test; + break; + case NodeKind::kBinaryExpression: + e = e->Cast<BinaryExpression>()->left; + break; + case NodeKind::kLogicalExpression: + e = e->Cast<LogicalExpression>()->left; + break; + case NodeKind::kCallExpression: + e = e->Cast<CallExpression>()->callee; + break; + case NodeKind::kMemberExpression: + e = e->Cast<MemberExpression>()->object; + break; + case NodeKind::kTaggedTemplateExpression: + e = e->Cast<TaggedTemplateExpression>()->tag; + break; + case NodeKind::kChainExpression: + e = e->Cast<ChainExpression>()->expression; + break; + case NodeKind::kUpdateExpression: + if (e->Cast<UpdateExpression>()->prefix) { + return false; + } + e = e->Cast<UpdateExpression>()->argument; + break; + default: + return false; + } + } + } + + // True if the member/call spine of a `new` callee contains a call, which + // would otherwise capture the `new` arguments. + static bool NewCalleeNeedsParens(const Expression* e) { + while (true) { + switch (e->kind) { + case NodeKind::kCallExpression: + case NodeKind::kChainExpression: + case NodeKind::kImportExpression: + return true; + case NodeKind::kMemberExpression: + e = e->Cast<MemberExpression>()->object; + break; + case NodeKind::kTaggedTemplateExpression: + e = e->Cast<TaggedTemplateExpression>()->tag; + break; + default: + return false; + } + } + } + + void PrintParenthesized(const Expression* e) { + Emit('('); + AllowIn allow_in(this); + PrintExpression(e, kPrecSequence); + Emit(')'); + } + + void PrintExpression(const Expression* e, int min_precedence) { + SpanScope span(this, e); + if (PrecedenceOf(e) < min_precedence) { + PrintParenthesized(e); + return; + } + switch (e->kind) { + case NodeKind::kIdentifier: + Emit(e->Cast<Identifier>()->name); + break; + case NodeKind::kPrivateIdentifier: + Emit('#'); + Emit(e->Cast<PrivateIdentifier>()->name); + break; + case NodeKind::kNullLiteral: + Emit("null"); + break; + case NodeKind::kBooleanLiteral: + Emit(e->Cast<BooleanLiteral>()->value ? "true" : "false"); + break; + case NodeKind::kNumericLiteral: + PrintNumericLiteral(e->Cast<NumericLiteral>(), true); + break; + case NodeKind::kBigIntLiteral: + Emit(e->Cast<BigIntLiteral>()->raw); + break; + case NodeKind::kStringLiteral: + PrintStringLiteral(e->Cast<StringLiteral>()); + break; + case NodeKind::kRegExpLiteral: { + auto* r = e->Cast<RegExpLiteral>(); + Emit('/'); + Emit(r->pattern); + Emit('/'); + Emit(r->regexp_flags); + break; + } + case NodeKind::kThisExpression: + Emit("this"); + break; + case NodeKind::kSuper: + Emit("super"); + break; + case NodeKind::kArrayExpression: { + auto* a = e->Cast<ArrayExpression>(); + AllowIn allow_in(this); + Emit('['); + for (size_t i = 0; i < a->elements.size(); i++) { + if (i > 0) { + Emit(", "); + } + const Expression* element = a->elements[i]; + if (element == nullptr) { + if (i + 1 == a->elements.size()) { + Emit(','); + } + continue; + } + PrintExpression(element, kPrecAssign); + } + Emit(']'); + break; + } + case NodeKind::kObjectExpression: { + auto* o = e->Cast<ObjectExpression>(); + AllowIn allow_in(this); + Emit('{'); + for (size_t i = 0; i < o->properties.size(); i++) { + if (i > 0) { + Emit(", "); + } + const Node* entry = o->properties[i]; + if (auto* spread = entry->As<SpreadElement>()) { + SpanScope spread_span(this, spread); + Emit("..."); + PrintExpression(spread->argument, kPrecAssign); + } else { + PrintProperty(entry->Cast<Property>()); + } + } + Emit('}'); + break; + } + case NodeKind::kFunctionExpression: + PrintFunction(e->Cast<FunctionExpression>(), e); + break; + case NodeKind::kArrowFunctionExpression: + PrintArrow(e->Cast<ArrowFunctionExpression>()); + break; + case NodeKind::kClassExpression: + PrintClass(e->Cast<ClassExpression>(), e); + break; + case NodeKind::kUnaryExpression: { + auto* u = e->Cast<UnaryExpression>(); + const char* op = OperatorText(u->op); + Emit(op); + bool keyword = u->op == UnaryOp::kTypeof || u->op == UnaryOp::kVoid || + u->op == UnaryOp::kDelete; + bool same_sign = false; + if (auto* inner = u->argument->As<UnaryExpression>()) { + same_sign = + (u->op == UnaryOp::kMinus && inner->op == UnaryOp::kMinus) || + (u->op == UnaryOp::kPlus && inner->op == UnaryOp::kPlus); + } else if (auto* update = u->argument->As<UpdateExpression>()) { + same_sign = + update->prefix && + ((u->op == UnaryOp::kMinus && + update->op == UpdateOp::kDecrement) || + (u->op == UnaryOp::kPlus && update->op == UpdateOp::kIncrement)); + } else if (auto* number = u->argument->As<NumericLiteral>()) { + same_sign = u->op == UnaryOp::kMinus && std::signbit(number->value); + } + if (keyword || same_sign) { + Emit(' '); + } + PrintExpression(u->argument, kPrecUnary); + break; + } + case NodeKind::kUpdateExpression: { + auto* u = e->Cast<UpdateExpression>(); + if (u->prefix) { + Emit(OperatorText(u->op)); + PrintExpression(u->argument, kPrecUnary); + } else { + PrintExpression(u->argument, kPrecPostfix); + Emit(OperatorText(u->op)); + } + break; + } + case NodeKind::kBinaryExpression: { + auto* b = e->Cast<BinaryExpression>(); + if (b->op == BinaryOp::kIn && no_in_) { + PrintParenthesized(e); + break; + } + int prec = BinaryPrec(b->op); + if (b->op == BinaryOp::kExp) { + // Right-associative; a unary expression on the left is a syntax + // error without parentheses. + bool left_parens = + b->left->Is<UnaryExpression>() || b->left->Is<AwaitExpression>(); + if (left_parens) { + PrintParenthesized(b->left); + } else { + PrintExpression(b->left, prec + 1); + } + Emit(" ** "); + PrintExpression(b->right, prec); + } else { + PrintExpression(b->left, prec); + Emit(' '); + Emit(OperatorText(b->op)); + Emit(' '); + PrintExpression(b->right, prec + 1); + } + break; + } + case NodeKind::kLogicalExpression: { + auto* l = e->Cast<LogicalExpression>(); + int prec = LogicalPrec(l->op); + auto needs_mixing_parens = [&](const Expression* child) { + auto* inner = child->As<LogicalExpression>(); + if (inner == nullptr) { + return false; + } + bool outer_nullish = l->op == LogicalOp::kNullish; + bool inner_nullish = inner->op == LogicalOp::kNullish; + return outer_nullish != inner_nullish; + }; + if (needs_mixing_parens(l->left)) { + PrintParenthesized(l->left); + } else { + PrintExpression(l->left, prec); + } + Emit(' '); + Emit(OperatorText(l->op)); + Emit(' '); + if (needs_mixing_parens(l->right)) { + PrintParenthesized(l->right); + } else { + PrintExpression(l->right, prec + 1); + } + break; + } + case NodeKind::kAssignmentExpression: { + auto* a = e->Cast<AssignmentExpression>(); + PrintPattern(a->left); + Emit(' '); + Emit(OperatorText(a->op)); + Emit(' '); + PrintExpression(a->right, kPrecAssign); + break; + } + case NodeKind::kMemberExpression: { + auto* m = e->Cast<MemberExpression>(); + PrintMemberObject(m->object); + if (m->computed) { + Emit(m->optional ? "?.[" : "["); + AllowIn allow_in(this); + PrintExpression(m->property, kPrecSequence); + Emit(']'); + } else { + Emit(m->optional ? "?." : "."); + if (auto* priv = m->property->As<PrivateIdentifier>()) { + Emit('#'); + Emit(priv->name); + } else { + Emit(m->property->Cast<Identifier>()->name); + } + } + break; + } + case NodeKind::kConditionalExpression: { + auto* c = e->Cast<ConditionalExpression>(); + PrintExpression(c->test, kPrecNullish); + Emit(" ? "); + { + AllowIn allow_in(this); + PrintExpression(c->consequent, kPrecAssign); + } + Emit(" : "); + PrintExpression(c->alternate, kPrecAssign); + break; + } + case NodeKind::kCallExpression: { + auto* c = e->Cast<CallExpression>(); + if (c->callee->Is<ChainExpression>()) { + PrintParenthesized(c->callee); + } else { + PrintExpression(c->callee, kPrecCall); + } + if (c->optional) { + Emit("?."); + } + PrintArguments(c->arguments); + break; + } + case NodeKind::kNewExpression: { + auto* n = e->Cast<NewExpression>(); + Emit("new "); + if (NewCalleeNeedsParens(n->callee)) { + PrintParenthesized(n->callee); + } else { + PrintExpression(n->callee, kPrecMember); + } + PrintArguments(n->arguments); + break; + } + case NodeKind::kSequenceExpression: { + auto* s = e->Cast<SequenceExpression>(); + for (size_t i = 0; i < s->expressions.size(); i++) { + if (i > 0) { + Emit(", "); + } + PrintExpression(s->expressions[i], kPrecAssign); + } + break; + } + case NodeKind::kYieldExpression: { + auto* y = e->Cast<YieldExpression>(); + Emit(y->delegate ? "yield*" : "yield"); + if (y->argument != nullptr) { + Emit(' '); + PrintExpression(y->argument, kPrecAssign); + } + break; + } + case NodeKind::kAwaitExpression: + Emit("await "); + PrintExpression(e->Cast<AwaitExpression>()->argument, kPrecUnary); + break; + case NodeKind::kTemplateLiteral: + PrintTemplate(e->Cast<TemplateLiteral>()); + break; + case NodeKind::kTaggedTemplateExpression: { + auto* t = e->Cast<TaggedTemplateExpression>(); + if (t->tag->Is<ChainExpression>()) { + PrintParenthesized(t->tag); + } else { + PrintExpression(t->tag, kPrecCall); + } + PrintTemplate(t->quasi); + break; + } + case NodeKind::kMetaProperty: + Emit(e->Cast<MetaProperty>()->meta_kind == MetaPropertyKind::kNewTarget + ? "new.target" + : "import.meta"); + break; + case NodeKind::kImportExpression: { + auto* i = e->Cast<ImportExpression>(); + AllowIn allow_in(this); + Emit(i->is_defer ? "import.defer(" : "import("); + PrintExpression(i->source, kPrecAssign); + if (i->options != nullptr) { + Emit(", "); + PrintExpression(i->options, kPrecAssign); + } + Emit(')'); + break; + } + case NodeKind::kChainExpression: + PrintExpression(e->Cast<ChainExpression>()->expression, kPrecCall); + break; + case NodeKind::kSpreadElement: + Emit("..."); + PrintExpression(e->Cast<SpreadElement>()->argument, kPrecAssign); + break; + case NodeKind::kObjectPattern: + case NodeKind::kArrayPattern: + case NodeKind::kRestElement: + case NodeKind::kAssignmentPattern: + PrintPattern(e); + break; + case NodeKind::kNativeCallExpression: { + auto* n = e->Cast<NativeCallExpression>(); + Emit('%'); + Emit(n->name); + PrintArguments(n->arguments); + break; + } + default: + Emit("/* ? */"); + break; + } + } + + void PrintMemberObject(const Expression* object) { + if (object->Is<ChainExpression>()) { + PrintParenthesized(object); + return; + } + if (auto* number = object->As<NumericLiteral>()) { + std::string_view raw = number->raw; + if (raw.empty() || IsAllDigits(raw)) { + PrintParenthesized(object); + return; + } + } + PrintExpression(object, kPrecCall); + } + + void PrintArguments(const std::vector<Expression*>& arguments) { + AllowIn allow_in(this); + Emit('('); + for (size_t i = 0; i < arguments.size(); i++) { + if (i > 0) { + Emit(", "); + } + PrintExpression(arguments[i], kPrecAssign); + } + Emit(')'); + } + + void PrintTemplate(const TemplateLiteral* t) { + SpanScope span(this, t); + AllowIn allow_in(this); + Emit('`'); + for (size_t i = 0; i < t->quasis.size(); i++) { + Emit(t->quasis[i]->raw); + if (i < t->expressions.size()) { + Emit("${"); + PrintExpression(t->expressions[i], kPrecSequence); + Emit('}'); + } + } + Emit('`'); + } + + void PrintStringLiteral(const StringLiteral* s) { + if (!s->raw.empty()) { + Emit(s->raw); + } else { + Emit(QuoteJsString(s->value)); + } + } + + void PrintNumericLiteral(const NumericLiteral* n, bool allow_parens) { + if (!n->raw.empty()) { + Emit(n->raw); + return; + } + std::string text = NumberToJs(n->value); + if (text[0] == '-' && allow_parens) { + Emit('('); + Emit(text); + Emit(')'); + } else { + Emit(text); + } + } + + const PrintOptions& options_; + std::vector<NodeSpan>* spans_; + std::string out_; + int indent_ = 0; + bool no_in_ = false; +}; + +} // namespace + +std::string QuoteJsString(std::string_view value) { + std::string out; + out.reserve(value.size() + 2); + out.push_back('"'); + size_t pos = 0; + while (pos < value.size()) { + size_t length; + uint32_t c = DecodeUtf8(value, pos, &length); + pos += length; + switch (c) { + case '"': + out += "\\\""; + break; + case '\\': + out += "\\\\"; + break; + case '\n': + out += "\\n"; + break; + case '\r': + out += "\\r"; + break; + case '\t': + out += "\\t"; + break; + case '\b': + out += "\\b"; + break; + case '\f': + out += "\\f"; + break; + case '\v': + out += "\\v"; + break; + case 0: + out += "\\0"; + break; + case 0x2028: + out += "\\u2028"; + break; + case 0x2029: + out += "\\u2029"; + break; + default: + if (c < 0x20 || c == 0x7F) { + out += StringPrintf("\\x%02X", c); + } else if (c >= 0xD800 && c <= 0xDFFF) { + // Lone surrogate (WTF-8): must be escaped. + out += StringPrintf("\\u%04X", c); + } else if (c < 0x80) { + out.push_back(static_cast<char>(c)); + } else if (c == 0xFFFD && length == 1) { + // Malformed input byte; escape it so the output is valid UTF-8. + out += StringPrintf( + "\\x%02X", + static_cast<unsigned>(static_cast<uint8_t>(value[pos - 1]))); + } else { + AppendUtf8(&out, c); + } + break; + } + } + out.push_back('"'); + return out; +} + +std::string NumberToJs(double value) { + if (std::isnan(value)) { + return "NaN"; + } + if (std::isinf(value)) { + return value < 0 ? "-Infinity" : "Infinity"; + } + if (value == 0) { + return std::signbit(value) ? "-0" : "0"; + } + char buffer[v8::internal::kDoubleToStringMinBufferSize]; + std::string_view text = v8::internal::DoubleToStringView( + value, v8::base::Vector<char>(buffer, sizeof(buffer))); + return std::string(text); +} + +std::string Print(const Node* node, const PrintOptions& options) { + return Print(node, options, nullptr); +} + +std::string Print(const Node* node, const PrintOptions& options, + std::vector<NodeSpan>* spans) { + Printer printer(options, spans); + if (node != nullptr) { + printer.PrintNode(node); + } + return printer.Finish(); +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/printer.h b/deps/v8/experimental/redline/fast/printer.h new file mode 100644 index 000000000000..c1ffc8f739a4 --- /dev/null +++ b/deps/v8/experimental/redline/fast/printer.h @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_PRINTER_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_PRINTER_H_ + +#include <cstdint> +#include <string> +#include <vector> + +#include "experimental/redline/fast/ast.h" + +namespace redline { +namespace fast { + +struct PrintOptions { + // Newlines and two-space indentation (otherwise everything on one line). + bool pretty = true; + // Append `// nN` comments with node ids after each statement. + bool node_ids = false; +}; + +// Output byte range of a printed node. +struct NodeSpan { + uint32_t node_id = 0; + int32_t start = 0; + int32_t end = 0; +}; + +// Prints a FAST subtree as JavaScript source. The output re-parses to a tree +// with identical semantics (parentheses are derived from precedence, ASI +// hazards are avoided by always emitting semicolons). +std::string Print(const Node* node, + const PrintOptions& options = PrintOptions()); +std::string Print(const Node* node, const PrintOptions& options, + std::vector<NodeSpan>* spans); + +// Quotes a cooked (WTF-8) string as a double-quoted JS string literal. +std::string QuoteJsString(std::string_view value); +// Shortest round-trip representation of a double as a JS numeric literal +// (negative values get a leading '-'). +std::string NumberToJs(double value); + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_PRINTER_H_ diff --git a/deps/v8/experimental/redline/fast/scope.cc b/deps/v8/experimental/redline/fast/scope.cc new file mode 100644 index 000000000000..b0f22f649100 --- /dev/null +++ b/deps/v8/experimental/redline/fast/scope.cc @@ -0,0 +1,1416 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/scope.h" + +#include <algorithm> +#include <functional> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { +namespace fast { + +const char* ScopeKindName(ScopeKind kind) { + switch (kind) { + case ScopeKind::kScript: + return "script"; + case ScopeKind::kFunction: + return "function"; + case ScopeKind::kArrow: + return "arrow"; + case ScopeKind::kFunctionBody: + return "function-body"; + case ScopeKind::kBlock: + return "block"; + case ScopeKind::kCatch: + return "catch"; + case ScopeKind::kClass: + return "class"; + case ScopeKind::kStaticBlock: + return "static-block"; + case ScopeKind::kFieldInit: + return "field-init"; + case ScopeKind::kWith: + return "with"; + } + return "?"; +} + +const char* BindingKindName(BindingKind kind) { + switch (kind) { + case BindingKind::kVar: + return "var"; + case BindingKind::kLet: + return "let"; + case BindingKind::kConst: + return "const"; + case BindingKind::kUsing: + return "using"; + case BindingKind::kAwaitUsing: + return "await-using"; + case BindingKind::kFunction: + return "function"; + case BindingKind::kClass: + return "class"; + case BindingKind::kParameter: + return "param"; + case BindingKind::kCatchParameter: + return "catch-param"; + case BindingKind::kFunctionName: + return "function-name"; + case BindingKind::kClassName: + return "class-name"; + case BindingKind::kImplicit: + return "implicit"; + } + return "?"; +} + +bool Binding::safe_to_rename() const { + if (kind == BindingKind::kImplicit) { + return false; + } + if (pinned || has_dynamic_reference) { + return false; + } + if (scope == nullptr) { + return false; + } + if (scope->is_dynamic() || scope->dynamic_inside) { + return false; + } + // Declaring `arguments` changes whether and where the arguments object + // exists; leave the name alone in either direction. + if (name == "arguments") { + return false; + } + // Script-level bindings are reachable by name from outside the program + // text: other scripts, `new Function` bodies, indirect eval, and for + // `var`/function declarations also as properties of the global object. + if (scope->kind == ScopeKind::kScript) { + return false; + } + return true; +} + +bool Scope::is_dynamic() const { + for (const Scope* s = this; s != nullptr; s = s->parent) { + if (s->kind == ScopeKind::kWith || s->has_direct_eval) { + return true; + } + } + return false; +} + +Scope* Scope::var_scope() { + Scope* s = this; + while (!s->is_var_scope() && s->parent != nullptr) { + s = s->parent; + } + return s; +} + +const Scope* Scope::var_scope() const { + return const_cast<Scope*>(this)->var_scope(); +} + +const Scope* Scope::this_scope() const { + for (const Scope* s = this; s != nullptr; s = s->parent) { + if (s->kind == ScopeKind::kFunction || s->kind == ScopeKind::kStaticBlock || + s->kind == ScopeKind::kFieldInit) { + return s; + } + } + return nullptr; +} + +Binding* Scope::Lookup(std::string_view name) const { + for (const Scope* s = this; s != nullptr; s = s->parent) { + auto it = s->by_name.find(name); + if (it != s->by_name.end()) { + return it->second; + } + } + return nullptr; +} + +int Scope::Depth() const { + int depth = 0; + for (const Scope* s = parent; s != nullptr; s = s->parent) { + depth++; + } + return depth; +} + +void CollectBoundIdentifiers(Node* pattern, std::vector<Identifier*>* out) { + if (pattern == nullptr) { + return; + } + switch (pattern->kind) { + case NodeKind::kIdentifier: + out->push_back(pattern->Cast<Identifier>()); + return; + case NodeKind::kObjectPattern: + for (Node* property : pattern->Cast<ObjectPattern>()->properties) { + if (auto* p = property->As<Property>()) { + CollectBoundIdentifiers(p->value, out); + } else { + CollectBoundIdentifiers(property, out); + } + } + return; + case NodeKind::kArrayPattern: + for (Expression* element : pattern->Cast<ArrayPattern>()->elements) { + CollectBoundIdentifiers(element, out); + } + return; + case NodeKind::kAssignmentPattern: + CollectBoundIdentifiers(pattern->Cast<AssignmentPattern>()->left, out); + return; + case NodeKind::kRestElement: + CollectBoundIdentifiers(pattern->Cast<RestElement>()->argument, out); + return; + default: + return; + } +} + +// --------------------------------------------------------------------------- + +class ScopeBuilder { + public: + explicit ScopeBuilder(ScopeAnalysis* analysis) : analysis_(analysis) {} + + void Build(Tree* tree) { + Program* program = tree->root(); + Scope* root = NewScope(ScopeKind::kScript, program); + root->strict = program->strict; + analysis_->root_ = root; + current_ = root; + for (Statement* statement : program->body) { + VisitStatement(statement); + } + Resolve(); + PinAnnexBFunctions(); + for (Identifier* identifier : names_function_ids_) { + if (Binding* binding = analysis_->BindingOf(identifier)) { + binding->names_function = true; + } + } + FillMissingScopes(program); + PropagateDynamic(root); + } + + private: + struct PendingReference { + Identifier* identifier; + Scope* scope; + bool is_write; + }; + + // --- scopes and bindings --- + + Scope* NewScope(ScopeKind kind, Node* node) { + Scope* scope = analysis_->NewScope(); + scope->kind = kind; + scope->node = node; + scope->parent = current_; + scope->start = node->start; + scope->end = node->end; + if (current_ != nullptr) { + scope->strict = current_->strict; + scope->is_async = current_->is_async; + scope->is_generator = current_->is_generator; + current_->children.push_back(scope); + } + if (node != nullptr) { + analysis_->SetScopeOf(node, scope); + } + return scope; + } + + struct ScopeGuard { + ScopeGuard(ScopeBuilder* builder, Scope* scope) + : builder_(builder), saved_(builder->current_) { + builder_->current_ = scope; + } + ~ScopeGuard() { builder_->current_ = saved_; } + ScopeBuilder* builder_; + Scope* saved_; + }; + + void Enter(Node* node) { + if (node != nullptr) { + analysis_->SetScopeIfUnset(node, current_); + } + } + + void NoteName(std::string_view name) { analysis_->all_names_.insert(name); } + + Binding* Declare(Identifier* identifier, BindingKind kind, Node* declaration, + Scope* scope) { + NoteName(identifier->name); + analysis_->AddFlag(identifier, ScopeAnalysis::IdFlag::kIsDeclaration); + if (kind == BindingKind::kVar) { + if (Binding* merged = VarMergeTarget(identifier->name, scope)) { + merged->declarations.push_back(identifier); + analysis_->SetBindingOf(identifier, merged); + PinCatchParameterRedeclaration(merged); + return merged; + } + } + Binding* result = nullptr; + auto it = scope->by_name.find(identifier->name); + if (it != scope->by_name.end()) { + Binding* existing = it->second; + bool existing_is_inner_name = + existing->kind == BindingKind::kFunctionName || + existing->kind == BindingKind::kClassName; + if (!existing_is_inner_name) { + // Redeclaration (`var x; var x;`, or an early error we tolerate): + // one binding, several declaration sites. `var x; function x(){}` + // is a function binding (its name is observable). + existing->declarations.push_back(identifier); + if (kind == BindingKind::kFunction && + existing->kind == BindingKind::kVar) { + existing->kind = BindingKind::kFunction; + } + analysis_->SetBindingOf(identifier, existing); + result = existing; + } + // Parameters and body declarations shadow a function expression's + // own name; keep the inner-name binding around but hide it. + } + if (result == nullptr) { + Binding* binding = analysis_->NewBinding(); + binding->name = identifier->name; + binding->kind = kind; + binding->scope = scope; + binding->identifier = identifier; + binding->declaration = declaration; + binding->declarations.push_back(identifier); + result = binding; + scope->bindings.push_back(result); + scope->by_name[result->name] = result; + analysis_->SetBindingOf(identifier, result); + } + if (kind == BindingKind::kVar) { + PinCatchParameterRedeclaration(result); + } + return result; + } + + // A `var` does not always create a binding of its own: + // - in the separate body scope of a function with non-simple parameters, + // `var x` where `x` is a parameter creates a body binding that is + // initialized from the parameter; treating both as one binding keeps + // renaming sound (closures in parameter defaults do not observe body + // writes, which a later dataflow analysis may want to model); + // - `var arguments` in a function keeps the implicit arguments object. + Binding* VarMergeTarget(std::string_view name, Scope* var_scope) { + Scope* function_scope = var_scope; + if (var_scope->kind == ScopeKind::kFunctionBody) { + function_scope = var_scope->parent; + auto it = function_scope->by_name.find(name); + if (it != function_scope->by_name.end() && + it->second->kind == BindingKind::kParameter) { + // Unless a function declaration in the body owns the name: then + // the body binding starts out as that function, not the parameter. + auto names = body_function_names_.find(var_scope); + if (names == body_function_names_.end() || !names->second.count(name)) { + return it->second; + } + } + } + if (name == "arguments" && function_scope->kind == ScopeKind::kFunction) { + auto it = function_scope->by_name.find(name); + if (it == function_scope->by_name.end()) { + return ImplicitArguments(function_scope); + } + if (it->second->kind == BindingKind::kImplicit) { + return it->second; + } + } + return nullptr; + } + + // Annex B.3.4: `var e` inside `catch (e)` is allowed in sloppy and strict + // code alike; the declaration hoists as usual but its initializer assigns + // the catch parameter. Neither binding can be renamed on its own. + void PinCatchParameterRedeclaration(Binding* var_binding) { + for (Scope* s = current_; s != nullptr && s != var_binding->scope; + s = s->parent) { + if (s->kind != ScopeKind::kCatch) { + continue; + } + auto it = s->by_name.find(var_binding->name); + if (it != s->by_name.end() && + it->second->kind == BindingKind::kCatchParameter) { + it->second->pinned = true; + var_binding->pinned = true; + } + } + } + + void Reference(Identifier* identifier, bool is_write) { + NoteName(identifier->name); + Enter(identifier); + analysis_->AddFlag(identifier, ScopeAnalysis::IdFlag::kIsReference); + pending_.push_back({identifier, current_, is_write}); + } + + // --- statements --- + + void VisitStatements(const std::vector<Statement*>& statements) { + for (Statement* statement : statements) { + VisitStatement(statement); + } + } + + void VisitBlockBody(BlockStatement* block) { + // The statements of a block whose scope was already created. + Enter(block); + VisitStatements(block->body); + } + + void VisitBlock(BlockStatement* block) { + Scope* scope = NewScope(ScopeKind::kBlock, block); + ScopeGuard guard(this, scope); + VisitStatements(block->body); + } + + void VisitStatement(Statement* statement) { + if (statement == nullptr) { + return; + } + Enter(statement); + switch (statement->kind) { + case NodeKind::kExpressionStatement: + VisitExpression(statement->Cast<ExpressionStatement>()->expression); + break; + case NodeKind::kBlockStatement: + VisitBlock(statement->Cast<BlockStatement>()); + break; + case NodeKind::kEmptyStatement: + case NodeKind::kDebuggerStatement: + break; + case NodeKind::kWithStatement: { + auto* s = statement->Cast<WithStatement>(); + VisitExpression(s->object); + Scope* scope = NewScope(ScopeKind::kWith, s); + ScopeGuard guard(this, scope); + VisitStatement(s->body); + break; + } + case NodeKind::kReturnStatement: + VisitExpression(statement->Cast<ReturnStatement>()->argument); + break; + case NodeKind::kThrowStatement: + VisitExpression(statement->Cast<ThrowStatement>()->argument); + break; + case NodeKind::kLabeledStatement: { + auto* s = statement->Cast<LabeledStatement>(); + NoteName(s->label->name); + Enter(s->label); + VisitStatement(s->body); + break; + } + case NodeKind::kBreakStatement: { + auto* s = statement->Cast<BreakStatement>(); + if (s->label != nullptr) { + NoteName(s->label->name); + Enter(s->label); + } + break; + } + case NodeKind::kContinueStatement: { + auto* s = statement->Cast<ContinueStatement>(); + if (s->label != nullptr) { + NoteName(s->label->name); + Enter(s->label); + } + break; + } + case NodeKind::kIfStatement: { + auto* s = statement->Cast<IfStatement>(); + VisitExpression(s->test); + VisitStatement(s->consequent); + VisitStatement(s->alternate); + break; + } + case NodeKind::kSwitchStatement: { + auto* s = statement->Cast<SwitchStatement>(); + VisitExpression(s->discriminant); + Scope* scope = NewScope(ScopeKind::kBlock, s); + ScopeGuard guard(this, scope); + for (SwitchCase* switch_case : s->cases) { + Enter(switch_case); + VisitExpression(switch_case->test); + VisitStatements(switch_case->consequent); + } + break; + } + case NodeKind::kTryStatement: { + auto* s = statement->Cast<TryStatement>(); + VisitBlock(s->block); + if (s->handler != nullptr) { + Scope* scope = NewScope(ScopeKind::kCatch, s->handler); + ScopeGuard guard(this, scope); + if (s->handler->param != nullptr) { + VisitBindingPattern(s->handler->param, BindingKind::kCatchParameter, + s->handler); + } + VisitBlock(s->handler->body); + } + if (s->finalizer != nullptr) { + VisitBlock(s->finalizer); + } + break; + } + case NodeKind::kWhileStatement: { + auto* s = statement->Cast<WhileStatement>(); + VisitExpression(s->test); + VisitStatement(s->body); + break; + } + case NodeKind::kDoWhileStatement: { + auto* s = statement->Cast<DoWhileStatement>(); + VisitStatement(s->body); + VisitExpression(s->test); + break; + } + case NodeKind::kForStatement: { + auto* s = statement->Cast<ForStatement>(); + Scope* scope = HasLexicalDeclaration(s->init) + ? NewScope(ScopeKind::kBlock, s) + : current_; + ScopeGuard guard(this, scope); + if (s->init != nullptr) { + if (auto* declaration = s->init->As<VariableDeclaration>()) { + VisitVariableDeclaration(declaration); + } else { + VisitExpression(s->init->Cast<Expression>()); + } + } + VisitExpression(s->test); + VisitExpression(s->update); + VisitStatement(s->body); + break; + } + case NodeKind::kForInStatement: { + auto* s = statement->Cast<ForInStatement>(); + VisitForEach(s, s->left, s->right, s->body); + break; + } + case NodeKind::kForOfStatement: { + auto* s = statement->Cast<ForOfStatement>(); + VisitForEach(s, s->left, s->right, s->body); + break; + } + case NodeKind::kFunctionDeclaration: { + auto* fn = statement->Cast<FunctionDeclaration>(); + if (fn->name != nullptr) { + Binding* binding = + Declare(fn->name, BindingKind::kFunction, fn, current_); + Enter(fn->name); + // Annex B.3.3: in sloppy code a plain function declared in a block + // is also hoisted as a `var` to the enclosing function scope, + // unless a lexical declaration of the same name is in the way. + if (!current_->strict && !current_->is_var_scope() && !fn->is_async && + !fn->is_generator) { + binding->pinned = true; + annex_b_functions_.push_back( + {current_->var_scope(), fn->name->name}); + } + } + VisitFunction(fn, fn, /*is_arrow=*/false, /*is_expression=*/false); + break; + } + case NodeKind::kVariableDeclaration: + VisitVariableDeclaration(statement->Cast<VariableDeclaration>()); + break; + case NodeKind::kClassDeclaration: { + auto* cls = statement->Cast<ClassDeclaration>(); + if (cls->name != nullptr) { + Declare(cls->name, BindingKind::kClass, cls, current_); + Enter(cls->name); + } + VisitClass(cls, cls, /*is_expression=*/false); + break; + } + default: + REDLINE_WARN("scope", "Unhandled statement kind %s", + NodeKindName(statement->kind)); + break; + } + } + + static bool HasLexicalDeclaration(Node* node) { + auto* declaration = + node == nullptr ? nullptr : node->As<VariableDeclaration>(); + return declaration != nullptr && + declaration->declaration_kind != VariableKind::kVar; + } + + void VisitForEach(Statement* loop, Node* left, Expression* right, + Statement* body) { + Scope* scope = HasLexicalDeclaration(left) + ? NewScope(ScopeKind::kBlock, loop) + : current_; + ScopeGuard guard(this, scope); + if (auto* declaration = left->As<VariableDeclaration>()) { + VisitVariableDeclaration(declaration); + } else { + VisitAssignmentTarget(left->Cast<Expression>()); + } + VisitExpression(right); + VisitStatement(body); + } + + void VisitVariableDeclaration(VariableDeclaration* declaration) { + Enter(declaration); + BindingKind kind = BindingKind::kVar; + switch (declaration->declaration_kind) { + case VariableKind::kVar: + kind = BindingKind::kVar; + break; + case VariableKind::kLet: + kind = BindingKind::kLet; + break; + case VariableKind::kConst: + kind = BindingKind::kConst; + break; + case VariableKind::kUsing: + kind = BindingKind::kUsing; + break; + case VariableKind::kAwaitUsing: + kind = BindingKind::kAwaitUsing; + break; + } + for (VariableDeclarator* declarator : declaration->declarations) { + Enter(declarator); + VisitBindingPattern(declarator->target, kind, declarator); + VisitExpression(declarator->init); + NoteNameInference(declarator->target, declarator->init); + } + } + + // `x = function() {}`, `let x = class {}`, `[x = () => {}] = a`: the + // function's `name` property is taken from the binding. + static bool IsAnonymousFunctionDefinition(Expression* e) { + if (e == nullptr) { + return false; + } + switch (e->kind) { + case NodeKind::kArrowFunctionExpression: + return true; + case NodeKind::kFunctionExpression: + return e->Cast<FunctionExpression>()->name == nullptr; + case NodeKind::kClassExpression: + return e->Cast<ClassExpression>()->name == nullptr; + default: + return false; + } + } + + void NoteNameInference(Node* target, Expression* value) { + if (target == nullptr || target->kind != NodeKind::kIdentifier) { + return; + } + if (!IsAnonymousFunctionDefinition(value)) { + return; + } + names_function_ids_.push_back(target->Cast<Identifier>()); + } + + // Declares the identifiers of a binding pattern; default values and + // computed keys are expressions evaluated in the current scope. + void VisitBindingPattern(Node* pattern, BindingKind kind, Node* declaration) { + if (pattern == nullptr) { + return; + } + Enter(pattern); + switch (pattern->kind) { + case NodeKind::kIdentifier: { + Scope* scope = + kind == BindingKind::kVar ? current_->var_scope() : current_; + Declare(pattern->Cast<Identifier>(), kind, declaration, scope); + break; + } + case NodeKind::kObjectPattern: + for (Node* property : pattern->Cast<ObjectPattern>()->properties) { + Enter(property); + if (auto* p = property->As<Property>()) { + VisitPropertyKey(p->key, p->computed); + VisitBindingPattern(p->value, kind, declaration); + } else { + VisitBindingPattern(property, kind, declaration); + } + } + break; + case NodeKind::kArrayPattern: + for (Expression* element : pattern->Cast<ArrayPattern>()->elements) { + VisitBindingPattern(element, kind, declaration); + } + break; + case NodeKind::kAssignmentPattern: { + auto* p = pattern->Cast<AssignmentPattern>(); + VisitBindingPattern(p->left, kind, declaration); + VisitExpression(p->right); + NoteNameInference(p->left, p->right); + break; + } + case NodeKind::kRestElement: + VisitBindingPattern(pattern->Cast<RestElement>()->argument, kind, + declaration); + break; + default: + // Not a pattern (e.g. a MemberExpression in a sloppy for-in head + // that the parser let through): treat as an assignment target. + VisitAssignmentTarget(pattern->Cast<Expression>()); + break; + } + } + + // --- expressions --- + + void VisitPropertyKey(Expression* key, bool computed) { + if (key == nullptr) { + return; + } + if (computed) { + VisitExpression(key); + return; + } + Enter(key); + if (auto* id = key->As<Identifier>()) { + NoteName(id->name); + } + if (auto* id = key->As<PrivateIdentifier>()) { + NoteName(id->name); + } + } + + void VisitExpressions(const std::vector<Expression*>& expressions) { + for (Expression* expression : expressions) { + VisitExpression(expression); + } + } + + // An expression in assignment-target position: identifiers are writes, + // patterns bind nothing (they assign to existing targets). + void VisitAssignmentTarget(Expression* target) { + if (target == nullptr) { + return; + } + Enter(target); + switch (target->kind) { + case NodeKind::kIdentifier: + Reference(target->Cast<Identifier>(), /*is_write=*/true); + break; + case NodeKind::kObjectPattern: + for (Node* property : target->Cast<ObjectPattern>()->properties) { + Enter(property); + if (auto* p = property->As<Property>()) { + VisitPropertyKey(p->key, p->computed); + VisitAssignmentTarget(p->value); + } else { + VisitAssignmentTarget(property->Cast<Expression>()); + } + } + break; + case NodeKind::kArrayPattern: + for (Expression* element : target->Cast<ArrayPattern>()->elements) { + VisitAssignmentTarget(element); + } + break; + case NodeKind::kAssignmentPattern: { + auto* p = target->Cast<AssignmentPattern>(); + VisitAssignmentTarget(p->left); + VisitExpression(p->right); + NoteNameInference(p->left, p->right); + break; + } + case NodeKind::kRestElement: + VisitAssignmentTarget(target->Cast<RestElement>()->argument); + break; + default: + VisitExpression(target); + break; + } + } + + void VisitExpression(Expression* e) { + if (e == nullptr) { + return; + } + Enter(e); + switch (e->kind) { + case NodeKind::kIdentifier: + Reference(e->Cast<Identifier>(), /*is_write=*/false); + break; + case NodeKind::kPrivateIdentifier: + NoteName(e->Cast<PrivateIdentifier>()->name); + break; + case NodeKind::kNullLiteral: + case NodeKind::kBooleanLiteral: + case NodeKind::kNumericLiteral: + case NodeKind::kBigIntLiteral: + case NodeKind::kStringLiteral: + case NodeKind::kRegExpLiteral: + case NodeKind::kThisExpression: + case NodeKind::kSuper: + case NodeKind::kMetaProperty: + break; + case NodeKind::kArrayExpression: + VisitExpressions(e->Cast<ArrayExpression>()->elements); + break; + case NodeKind::kObjectExpression: + for (Node* property : e->Cast<ObjectExpression>()->properties) { + Enter(property); + if (auto* p = property->As<Property>()) { + VisitPropertyKey(p->key, p->computed); + VisitExpression(p->value); + } else { + VisitExpression(property->Cast<Expression>()); + } + } + break; + case NodeKind::kFunctionExpression: + VisitFunction(e->Cast<FunctionExpression>(), e, + /*is_arrow=*/false, + /*is_expression=*/true); + break; + case NodeKind::kArrowFunctionExpression: + VisitFunction(e->Cast<ArrowFunctionExpression>(), e, + /*is_arrow=*/true, + /*is_expression=*/true); + break; + case NodeKind::kClassExpression: + VisitClass(e->Cast<ClassExpression>(), e, /*is_expression=*/true); + break; + case NodeKind::kUnaryExpression: + VisitExpression(e->Cast<UnaryExpression>()->argument); + break; + case NodeKind::kUpdateExpression: + VisitAssignmentTarget(e->Cast<UpdateExpression>()->argument); + break; + case NodeKind::kBinaryExpression: { + auto* b = e->Cast<BinaryExpression>(); + VisitExpression(b->left); + VisitExpression(b->right); + break; + } + case NodeKind::kLogicalExpression: { + auto* l = e->Cast<LogicalExpression>(); + VisitExpression(l->left); + VisitExpression(l->right); + break; + } + case NodeKind::kAssignmentExpression: { + auto* a = e->Cast<AssignmentExpression>(); + VisitAssignmentTarget(a->left); + VisitExpression(a->right); + if (a->op == AssignOp::kAssign || a->op == AssignOp::kOrAssign || + a->op == AssignOp::kAndAssign || + a->op == AssignOp::kNullishAssign) { + NoteNameInference(a->left, a->right); + } + break; + } + case NodeKind::kMemberExpression: { + auto* m = e->Cast<MemberExpression>(); + VisitExpression(m->object); + VisitPropertyKey(m->property, m->computed); + break; + } + case NodeKind::kConditionalExpression: { + auto* c = e->Cast<ConditionalExpression>(); + VisitExpression(c->test); + VisitExpression(c->consequent); + VisitExpression(c->alternate); + break; + } + case NodeKind::kCallExpression: { + auto* c = e->Cast<CallExpression>(); + if (auto* callee = c->callee->As<Identifier>()) { + if (callee->name == "eval") { + current_->has_direct_eval = true; + } + } + VisitExpression(c->callee); + VisitExpressions(c->arguments); + break; + } + case NodeKind::kNewExpression: { + auto* n = e->Cast<NewExpression>(); + VisitExpression(n->callee); + VisitExpressions(n->arguments); + break; + } + case NodeKind::kSequenceExpression: + VisitExpressions(e->Cast<SequenceExpression>()->expressions); + break; + case NodeKind::kYieldExpression: + VisitExpression(e->Cast<YieldExpression>()->argument); + break; + case NodeKind::kAwaitExpression: + VisitExpression(e->Cast<AwaitExpression>()->argument); + break; + case NodeKind::kTemplateLiteral: { + auto* t = e->Cast<TemplateLiteral>(); + for (TemplateElement* quasi : t->quasis) { + Enter(quasi); + } + VisitExpressions(t->expressions); + break; + } + case NodeKind::kTaggedTemplateExpression: { + auto* t = e->Cast<TaggedTemplateExpression>(); + VisitExpression(t->tag); + VisitExpression(t->quasi); + break; + } + case NodeKind::kImportExpression: { + auto* i = e->Cast<ImportExpression>(); + VisitExpression(i->source); + VisitExpression(i->options); + break; + } + case NodeKind::kChainExpression: + VisitExpression(e->Cast<ChainExpression>()->expression); + break; + case NodeKind::kSpreadElement: + VisitExpression(e->Cast<SpreadElement>()->argument); + break; + case NodeKind::kNativeCallExpression: + VisitExpressions(e->Cast<NativeCallExpression>()->arguments); + break; + case NodeKind::kObjectPattern: + case NodeKind::kArrayPattern: + case NodeKind::kAssignmentPattern: + case NodeKind::kRestElement: + // Patterns only occur in target positions; be robust anyway. + VisitAssignmentTarget(e); + break; + default: + REDLINE_WARN("scope", "Unhandled expression kind %s", + NodeKindName(e->kind)); + break; + } + } + + // --- functions and classes --- + + static bool HasSimpleParameters(const FunctionData* fn) { + for (const Expression* param : fn->params) { + if (param == nullptr || param->kind != NodeKind::kIdentifier) { + return false; + } + } + return true; + } + + void VisitFunction(FunctionData* fn, Node* node, bool is_arrow, + bool is_expression) { + Scope* scope = + NewScope(is_arrow ? ScopeKind::kArrow : ScopeKind::kFunction, node); + scope->strict = scope->strict || fn->strict; + scope->is_async = fn->is_async; + scope->is_generator = fn->is_generator; + ScopeGuard guard(this, scope); + if (is_expression && fn->name != nullptr) { + Declare(fn->name, BindingKind::kFunctionName, node, scope); + Enter(fn->name); + } + for (Expression* param : fn->params) { + VisitBindingPattern(param, BindingKind::kParameter, node); + } + if (fn->body == nullptr) { + VisitExpression(fn->expression_body); + } else if (HasSimpleParameters(fn)) { + VisitBlockBody(fn->body); + } else { + // Parameter expressions (defaults, computed keys) must not see the + // body's declarations: the body gets a var scope of its own. + Scope* body_scope = NewScope(ScopeKind::kFunctionBody, fn->body); + ScopeGuard body_guard(this, body_scope); + for (Statement* statement : fn->body->body) { + if (auto* declaration = statement->As<FunctionDeclaration>()) { + if (declaration->name != nullptr) { + body_function_names_[body_scope].insert(declaration->name->name); + } + } + } + VisitStatements(fn->body->body); + } + } + + void VisitClass(ClassData* cls, Node* node, bool is_expression) { + Scope* scope = NewScope(ScopeKind::kClass, node); + scope->strict = true; + ScopeGuard guard(this, scope); + if (is_expression && cls->name != nullptr) { + Declare(cls->name, BindingKind::kClassName, node, scope); + Enter(cls->name); + } + // The heritage is evaluated inside the class scope, where the class's + // own name is in its temporal dead zone (`class x extends x {}`). + VisitExpression(cls->super_class); + if (cls->body == nullptr) { + return; + } + Enter(cls->body); + for (Node* member : cls->body->members) { + Enter(member); + switch (member->kind) { + case NodeKind::kMethodDefinition: { + auto* m = member->Cast<MethodDefinition>(); + VisitPropertyKey(m->key, m->computed); + if (m->value != nullptr) { + VisitFunction(m->value, m->value, + /*is_arrow=*/false, + /*is_expression=*/false); + } + break; + } + case NodeKind::kPropertyDefinition: { + auto* p = member->Cast<PropertyDefinition>(); + VisitPropertyKey(p->key, p->computed); + if (p->value != nullptr) { + Scope* init_scope = NewScope(ScopeKind::kFieldInit, p); + ScopeGuard init_guard(this, init_scope); + VisitExpression(p->value); + } + break; + } + case NodeKind::kStaticBlock: { + auto* block = member->Cast<StaticBlock>(); + Scope* block_scope = NewScope(ScopeKind::kStaticBlock, block); + ScopeGuard block_guard(this, block_scope); + VisitStatements(block->body); + break; + } + default: + break; + } + } + } + + // --- resolution --- + + void Resolve() { + for (const PendingReference& reference : pending_) { + Binding* binding = nullptr; + bool dynamic = false; + for (Scope* s = reference.scope; s != nullptr; s = s->parent) { + if (s->kind == ScopeKind::kWith || s->has_direct_eval) { + dynamic = true; + } + auto it = s->by_name.find(reference.identifier->name); + if (it != s->by_name.end()) { + binding = it->second; + break; + } + if (reference.identifier->name == "arguments" && + s->kind == ScopeKind::kFunction) { + binding = ImplicitArguments(s); + break; + } + } + if (binding == nullptr) { + analysis_->unresolved_.push_back(reference.identifier); + continue; + } + analysis_->SetBindingOf(reference.identifier, binding); + binding->references.push_back(reference.identifier); + if (reference.is_write) { + binding->assigned = true; + } + if (dynamic) { + binding->has_dynamic_reference = true; + } + } + } + + Binding* ImplicitArguments(Scope* scope) { + Binding* binding = analysis_->NewBinding(); + binding->name = "arguments"; + binding->kind = BindingKind::kImplicit; + binding->scope = scope; + scope->bindings.push_back(binding); + scope->by_name[binding->name] = binding; + return binding; + } + + // Annex B.3.3, second half: whether a block-level function is hoisted + // depends on the lexical bindings of the same name between the block and + // the function scope, and the hoisted `var` merges with any var-scoped + // binding of that name. Pin all of them. + void PinAnnexBFunctions() { + for (const AnnexBFunction& fn : annex_b_functions_) { + for (Binding* binding : analysis_->bindings_) { + if (binding->name != fn.name) { + continue; + } + for (Scope* s = binding->scope; s != nullptr; s = s->parent) { + if (s == fn.var_scope) { + binding->pinned = true; + break; + } + } + } + } + } + + // Nodes the explicit visitor did not touch (holes, template elements, + // ...) inherit the scope of their parent. + void FillMissingScopes(Node* root) { + Walk(root, [this](Node* node) { + Scope* scope = analysis_->ScopeOf(node); + if (scope == nullptr) { + scope = current_; + } + ForEachChild( + node, [&](Node* child) { analysis_->SetScopeIfUnset(child, scope); }); + return true; + }); + } + + static bool PropagateDynamic(Scope* scope) { + bool dynamic = scope->kind == ScopeKind::kWith || scope->has_direct_eval; + for (Scope* child : scope->children) { + if (PropagateDynamic(child)) { + dynamic = true; + } + } + scope->dynamic_inside = dynamic; + return dynamic; + } + + struct AnnexBFunction { + Scope* var_scope; + std::string_view name; + }; + + ScopeAnalysis* analysis_; + Scope* current_ = nullptr; + std::vector<PendingReference> pending_; + std::vector<AnnexBFunction> annex_b_functions_; + std::vector<Identifier*> names_function_ids_; + // Names of the function declarations directly in a kFunctionBody scope. + absl::flat_hash_map<Scope*, absl::flat_hash_set<std::string_view>> + body_function_names_; +}; + +// --------------------------------------------------------------------------- + +ScopeAnalysis::ScopeAnalysis() = default; +ScopeAnalysis::~ScopeAnalysis() = default; + +std::unique_ptr<ScopeAnalysis> ScopeAnalysis::Analyze(Tree* tree) { + auto analysis = std::make_unique<ScopeAnalysis>(); + size_t ids = tree->id_limit(); + analysis->scope_of_.assign(ids, nullptr); + analysis->binding_of_.assign(ids, nullptr); + analysis->id_flags_.assign(ids, 0); + ScopeBuilder builder(analysis.get()); + builder.Build(tree); + return analysis; +} + +// The tables are sized for the tree at Analyze() time; a node with a larger +// id was created afterwards (not a legal input, but keep the lookups total). +void ScopeAnalysis::SetScopeOf(const Node* node, Scope* scope) { + if (node->id >= scope_of_.size()) { + scope_of_.resize(node->id + 1, nullptr); + } + scope_of_[node->id] = scope; +} + +void ScopeAnalysis::SetScopeIfUnset(const Node* node, Scope* scope) { + if (ScopeOf(node) == nullptr) { + SetScopeOf(node, scope); + } +} + +void ScopeAnalysis::SetBindingOf(const Identifier* identifier, + Binding* binding) { + if (identifier->id >= binding_of_.size()) { + binding_of_.resize(identifier->id + 1, nullptr); + } + binding_of_[identifier->id] = binding; +} + +void ScopeAnalysis::AddFlag(const Identifier* identifier, IdFlag flag) { + if (identifier->id >= id_flags_.size()) { + id_flags_.resize(identifier->id + 1, 0); + } + id_flags_[identifier->id] = static_cast<uint8_t>(id_flags_[identifier->id] | + static_cast<uint8_t>(flag)); +} + +bool ScopeAnalysis::HasFlag(const Identifier* identifier, IdFlag flag) const { + return identifier->id < id_flags_.size() && + (id_flags_[identifier->id] & static_cast<uint8_t>(flag)) != 0; +} + +Scope* ScopeAnalysis::NewScope() { + scopes_.push_back(&scope_storage_.emplace_back()); + return scopes_.back(); +} + +Binding* ScopeAnalysis::NewBinding() { + bindings_.push_back(&binding_storage_.emplace_back()); + return bindings_.back(); +} + +Scope* ScopeAnalysis::ScopeOf(const Node* node) const { + return node->id < scope_of_.size() ? scope_of_[node->id] : nullptr; +} + +Binding* ScopeAnalysis::BindingOf(const Identifier* identifier) const { + return identifier->id < binding_of_.size() ? binding_of_[identifier->id] + : nullptr; +} + +bool ScopeAnalysis::IsReference(const Identifier* identifier) const { + return HasFlag(identifier, IdFlag::kIsReference); +} + +bool ScopeAnalysis::IsDeclaration(const Identifier* identifier) const { + return HasFlag(identifier, IdFlag::kIsDeclaration); +} + +std::vector<Binding*> ScopeAnalysis::CollectVisible( + Scope* scope, int32_t position, bool initialized_only) const { + std::vector<Binding*> result; + absl::flat_hash_set<std::string_view> seen; + for (Scope* s = scope; s != nullptr; s = s->parent) { + for (Binding* binding : s->bindings) { + if (seen.count(binding->name)) { + continue; + } + // Hidden inner names (shadowed function expression names). + auto it = s->by_name.find(binding->name); + if (it == s->by_name.end() || it->second != binding) { + continue; + } + if (initialized_only && binding->is_lexical() && + binding->identifier != nullptr && position >= 0 && + binding->identifier->start > position) { + seen.insert(binding->name); // shadows outer ones all the same (TDZ) + continue; + } + seen.insert(binding->name); + result.push_back(binding); + } + } + return result; +} + +namespace { + +// True if evaluation of code in `inner` is deferred relative to `outer` +// (a function boundary lies between them), so that a `let` whose +// initializer contains the code may already be initialized when it runs. +bool CrossesFunction(const Scope* inner, const Scope* outer) { + for (const Scope* s = inner; s != nullptr && s != outer; s = s->parent) { + if (s->kind == ScopeKind::kFunction || s->kind == ScopeKind::kArrow || + s->kind == ScopeKind::kFunctionBody) { + return true; + } + } + return false; +} + +} // namespace + +std::vector<Binding*> ScopeAnalysis::VisibleAt(const Node* node, + bool initialized_only) const { + Scope* scope = ScopeOf(node); + // A node that introduces a scope is itself evaluated in the enclosing one. + if (scope != nullptr && scope->node == node && scope->parent != nullptr) { + scope = scope->parent; + } + std::vector<Binding*> result = + CollectVisible(scope, node->start, initialized_only); + if (!initialized_only || node->start < 0) { + return result; + } + // `let x = ...node...`: x is in its TDZ while the initializer runs, unless + // the node sits in a nested function that runs later. + result.erase(std::remove_if(result.begin(), result.end(), + [&](Binding* binding) { + if (!binding->is_lexical() || + binding->declaration == nullptr) { + return false; + } + const Node* declaration = binding->declaration; + if (!declaration->Is<VariableDeclarator>()) { + return false; + } + if (declaration->start < 0 || + declaration->start > node->start || + node->end > declaration->end) { + return false; + } + return !CrossesFunction(scope, binding->scope); + }), + result.end()); + return result; +} + +std::vector<Binding*> ScopeAnalysis::VisibleIn(const Node* owner, + int32_t position, + bool initialized_only) const { + return CollectVisible(ScopeOf(owner), position, initialized_only); +} + +bool ScopeAnalysis::IsNameFreeAt(const Node* node, + std::string_view name) const { + Scope* scope = ScopeOf(node); + if (scope == nullptr) { + return !all_names_.count(name); + } + if (scope->Lookup(name) != nullptr) { + return false; + } + // Any reference to `name` from inside this scope would be captured. + for (const Identifier* reference : unresolved_) { + if (reference->name != name) { + continue; + } + for (Scope* s = ScopeOf(reference); s != nullptr; s = s->parent) { + if (s == scope) { + return false; + } + } + } + for (const Binding* binding : bindings_) { + if (binding->name != name) { + continue; + } + for (Identifier* reference : binding->references) { + for (Scope* s = ScopeOf(reference); s != nullptr; s = s->parent) { + if (s == scope) { + return false; + } + } + } + } + return true; +} + +std::string ScopeAnalysis::FreshName(std::string_view prefix) const { + for (int i = 0;; i++) { + std::string candidate = std::string(prefix) + std::to_string(i); + if (!all_names_.count(candidate)) { + return candidate; + } + } +} + +void RenameBinding(Tree* tree, Binding* binding, std::string_view new_name) { + std::string_view interned = tree->Intern(new_name); + binding->scope->by_name.erase(binding->name); + binding->name = interned; + binding->scope->by_name[interned] = binding; + for (Identifier* identifier : binding->declarations) { + identifier->name = interned; + } + for (Identifier* identifier : binding->references) { + identifier->name = interned; + } +} + +size_t RenameAllBindings(Tree* tree, ScopeAnalysis* analysis, + std::string_view prefix, RenameScope which) { + size_t renamed = 0; + int counter = 0; + for (Binding* binding : analysis->bindings()) { + if (!binding->safe_to_rename()) { + continue; + } + bool is_function_like = binding->kind == BindingKind::kFunction || + binding->kind == BindingKind::kClass || + binding->kind == BindingKind::kFunctionName || + binding->kind == BindingKind::kClassName || + binding->names_function; + if (which == RenameScope::kVariables && is_function_like) { + continue; + } + std::string candidate; + do { + candidate = std::string(prefix) + std::to_string(counter++); + } while (analysis->all_names().count(candidate)); + RenameBinding(tree, binding, candidate); + renamed++; + } + return renamed; +} + +std::string ScopeAnalysis::Dump() const { + std::string out; + std::function<void(const Scope*, int)> dump = [&](const Scope* scope, + int indent) { + out.append(static_cast<size_t>(indent) * 2, ' '); + out += StringPrintf( + "%s scope n%u (%s)%s%s%s%s\n", ScopeKindName(scope->kind), + scope->node->id, NodeKindName(scope->node->kind), + scope->strict ? " strict" : "", scope->is_async ? " async" : "", + scope->is_generator ? " generator" : "", + scope->has_direct_eval ? " direct-eval" : ""); + for (const Binding* binding : scope->bindings) { + out.append(static_cast<size_t>(indent) * 2 + 2, ' '); + out += StringPrintf("%s %.*s", BindingKindName(binding->kind), + static_cast<int>(binding->name.size()), + binding->name.data()); + if (binding->identifier != nullptr) { + out += StringPrintf(" (n%u)", binding->identifier->id); + } + out += StringPrintf(": %zu refs%s%s%s", binding->references.size(), + binding->assigned ? ", assigned" : "", + binding->names_function ? ", names-function" : "", + binding->safe_to_rename() ? "" : ", pinned"); + if (!binding->references.empty()) { + out += " ["; + for (size_t i = 0; i < binding->references.size() && i < 8; i++) { + if (i > 0) { + out += ' '; + } + out += StringPrintf("n%u", binding->references[i]->id); + } + if (binding->references.size() > 8) { + out += " ..."; + } + out += ']'; + } + out += '\n'; + } + for (const Scope* child : scope->children) { + dump(child, indent + 1); + } + }; + if (root_ != nullptr) { + dump(root_, 0); + } + if (!unresolved_.empty()) { + absl::flat_hash_set<std::string_view> names; + out += "globals:"; + for (const Identifier* id : unresolved_) { + if (names.insert(id->name).second) { + out += StringPrintf(" %.*s", static_cast<int>(id->name.size()), + id->name.data()); + } + } + out += '\n'; + } + return out; +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/scope.h b/deps/v8/experimental/redline/fast/scope.h new file mode 100644 index 000000000000..0aabcb782d10 --- /dev/null +++ b/deps/v8/experimental/redline/fast/scope.h @@ -0,0 +1,303 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_SCOPE_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_SCOPE_H_ + +#include <cstdint> +#include <deque> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "experimental/redline/fast/ast.h" + +namespace redline { +namespace fast { + +class Tree; + +// Scope analysis: which identifiers are declarations, which are references, +// and which declaration every reference resolves to. This is the substrate +// for every mutation that moves, deletes or introduces code: "what is +// visible here?", "is this name free?", "who uses this variable?". +// +// The analysis is deliberately a static approximation of the spec: +// - `var` and function declarations hoist to the nearest function/script +// scope, lexical declarations (`let`, `const`, `class`, `using`) bind in +// the nearest block scope. +// - A function with non-simple parameters gets a separate var scope for +// its body (as in the spec and in V8's parser); a body `var` that +// redeclares a parameter is treated as the same binding. +// - A class declaration has one binding (the outer, mutable one); the +// immutable inner name binding is only modelled for class expressions. +// - Sloppy-mode Annex B function hoisting out of blocks and `var` +// redeclarations of catch parameters are not modelled; the bindings +// involved are flagged (Binding::pinned) instead. +// - Direct `eval` and `with` make scopes dynamic; such scopes are flagged +// and references inside them resolve as usual but must be treated with +// suspicion by callers (see Scope::is_dynamic()). +// - References that resolve to nothing are globals (builtins, properties +// of the global object or runtime errors). +// Results are valid until the tree is modified. + +enum class ScopeKind { + kScript, // the whole program + kFunction, // function/method/getter/setter/constructor (params + body) + kArrow, // arrow function (no own this/arguments) + kFunctionBody, // body of a function with non-simple parameters: its + // `var`s live in a scope of their own that parameter + // default expressions cannot see + kBlock, // { } block, switch body, for-head lexical scope + kCatch, // catch (param) binding scope + kClass, // class name binding visible inside the class body + kStaticBlock, // class static { } block (a var scope) + kFieldInit, // class field initializer (a function-like scope) + kWith, // with (o) { } body: dynamic +}; + +const char* ScopeKindName(ScopeKind kind); + +enum class BindingKind { + kVar, + kLet, + kConst, + kUsing, + kAwaitUsing, + kFunction, // function declaration + kClass, // class declaration + kParameter, // formal parameter (including rest and pattern parts) + kCatchParameter, + kFunctionName, // the name of a named function expression (inner binding) + kClassName, // the inner binding of a (named) class + kImplicit, // `arguments` in non-arrow functions +}; + +const char* BindingKindName(BindingKind kind); + +struct Scope; + +struct Binding { + std::string_view name; + BindingKind kind = BindingKind::kVar; + Scope* scope = nullptr; + // The Identifier node that declares the binding (nullptr for kImplicit). + Identifier* identifier = nullptr; + // The declaring statement/parameter/function node (nullptr for kImplicit). + Node* declaration = nullptr; + // Every declaring identifier (`var x; var x;` has two), first one is + // `identifier`. + std::vector<Identifier*> declarations; + // All reference sites, in source order (reads, writes, updates). + std::vector<Identifier*> references; + // True if some reference assigns to the binding. + bool assigned = false; + // True if some reference sits in a dynamic scope (`with` body, scope + // with direct eval), where it may not actually refer to this binding. + bool has_dynamic_reference = false; + // True if the binding takes part in a sloppy-mode Annex B interaction the + // analysis does not model precisely: a `var` redeclaring a catch + // parameter inside its catch block (the initializer assigns the + // parameter), or a block-level function declaration that is hoisted to + // the function scope unless a lexical binding of the same name is in the + // way. Renaming such bindings may change the program. + bool pinned = false; + // True if the binding's name is observable as the `name` of a function + // or class: `let f = function() {}`, `const C = class {}`, + // `x = () => {}`, `{f = function() {}} = o`. + bool names_function = false; + + bool is_lexical() const { + return kind == BindingKind::kLet || kind == BindingKind::kConst || + kind == BindingKind::kUsing || kind == BindingKind::kAwaitUsing || + kind == BindingKind::kClass; + } + bool is_constant() const { + return kind == BindingKind::kConst || kind == BindingKind::kUsing || + kind == BindingKind::kAwaitUsing || + kind == BindingKind::kFunctionName || + kind == BindingKind::kClassName; + } + // True if renaming the binding and all its references cannot change the + // program's meaning: no dynamic scoping involved, not `arguments`, not a + // script-level binding (those are reachable by name from other scripts, + // `new Function` bodies and indirect eval), no Annex B interaction. + bool safe_to_rename() const; +}; + +struct Scope { + ScopeKind kind = ScopeKind::kBlock; + Scope* parent = nullptr; + // The node that introduced the scope (Program, function, block, ...). + Node* node = nullptr; + std::vector<Scope*> children; + // Bindings in declaration order. + std::vector<Binding*> bindings; + // Name lookup; for duplicate `var`s the first declaration wins. A flat + // table: one allocation per scope with bindings instead of one per name. + absl::flat_hash_map<std::string_view, Binding*> by_name; + bool strict = false; + bool is_async = false; + bool is_generator = false; + // A direct `eval(...)` call occurs in this scope (not in nested + // functions): any name may be introduced or read dynamically. + bool has_direct_eval = false; + // This scope or a nested one has direct eval or is a `with` scope, so + // bindings declared here may be accessed by name from such code. + bool dynamic_inside = false; + // Source range of the scope's node. + int32_t start = -1; + int32_t end = -1; + + // True for scopes that can declare `var`s: script, function (or its + // separate body scope), static block, field initializer. + bool is_var_scope() const { + return kind == ScopeKind::kScript || kind == ScopeKind::kFunction || + kind == ScopeKind::kArrow || kind == ScopeKind::kFunctionBody || + kind == ScopeKind::kStaticBlock || kind == ScopeKind::kFieldInit; + } + // True if names in this scope or an enclosing one may be resolved + // dynamically (`with`, direct eval). + bool is_dynamic() const; + // The nearest enclosing function-like scope (or the script scope). + Scope* var_scope(); + const Scope* var_scope() const; + // The nearest enclosing non-arrow function scope, or nullptr at the + // script level: where `this`/`arguments`/`new.target` come from. + const Scope* this_scope() const; + Binding* Lookup(std::string_view name) const; + int Depth() const; +}; + +class ScopeAnalysis { + public: + ScopeAnalysis(); + ~ScopeAnalysis(); + ScopeAnalysis(const ScopeAnalysis&) = delete; + ScopeAnalysis& operator=(const ScopeAnalysis&) = delete; + + // Analyzes the whole tree. + static std::unique_ptr<ScopeAnalysis> Analyze(Tree* tree); + + Scope* root() const { return root_; } + // All scopes / bindings in creation order (pre-order of the tree). + const std::vector<Scope*>& scopes() const { return scopes_; } + const std::vector<Binding*>& bindings() const { return bindings_; } + + // The innermost scope that contains `node` (for scope-introducing nodes: + // the scope they introduce). nullptr for nodes not in the analyzed tree. + Scope* ScopeOf(const Node* node) const; + // The binding a reference resolves to, or nullptr for globals and for + // identifiers that are not references (property names, labels, ...). + Binding* BindingOf(const Identifier* identifier) const; + // True if `identifier` is a variable reference (as opposed to a property + // name, label or binding identifier). + bool IsReference(const Identifier* identifier) const; + // True if `identifier` declares a binding. + bool IsDeclaration(const Identifier* identifier) const; + // Reference identifiers that resolve to no binding (globals/builtins). + const std::vector<Identifier*>& unresolved() const { return unresolved_; } + + // All bindings visible to an expression at `node` (i.e. to code replacing + // it), innermost first; shadowed bindings are omitted. For + // scope-introducing nodes (functions, classes, blocks, loops with lexical + // declarations, ...) this is the enclosing scope: code replacing a function + // expression does not see its parameters. With `initialized_only`, lexical + // bindings declared textually after `node` are omitted, as are `let`/`const` + // bindings whose own initializer contains `node` (TDZ approximation). + std::vector<Binding*> VisibleAt(const Node* node, + bool initialized_only = true) const; + + // All bindings visible to a statement inserted into the statement list of + // `owner` (Program, BlockStatement, SwitchCase, StaticBlock) at text + // position `position` (the end of the preceding statement, or the owner's + // start for the first slot): the scope `owner` holds its statements in plus + // the enclosing scopes. With `initialized_only`, lexical bindings declared + // after `position` are omitted (TDZ approximation). + std::vector<Binding*> VisibleIn(const Node* owner, int32_t position, + bool initialized_only = true) const; + + // True if no binding named `name` is visible at `node` and no reference + // to `name` resolves through `node`'s scope chain, i.e. introducing a + // declaration of `name` at `node` cannot change the meaning of existing + // code. + bool IsNameFreeAt(const Node* node, std::string_view name) const; + // A name of the form `<prefix><n>` that occurs nowhere in the program. + std::string FreshName(std::string_view prefix) const; + // Every identifier name in the program (declarations, references, + // property names, labels). + const absl::flat_hash_set<std::string_view>& all_names() const { + return all_names_; + } + + // Human-readable dump (used by `redline parse --scopes`). + std::string Dump() const; + + private: + friend class ScopeBuilder; + + // Per-node facts are kept in vectors indexed by Node::id: ids are dense + // (0 .. Tree::id_limit() at analysis time), so this replaces a hash lookup + // and a heap node per entry by an array access. Nodes created after the + // analysis have ids beyond the vectors and are simply unknown. + enum class IdFlag : uint8_t { + kIsReference = 1, + kIsDeclaration = 2, + }; + void SetScopeOf(const Node* node, Scope* scope); // overwrites + void SetScopeIfUnset(const Node* node, Scope* scope); + void SetBindingOf(const Identifier* identifier, Binding* binding); + void AddFlag(const Identifier* identifier, IdFlag flag); + bool HasFlag(const Identifier* identifier, IdFlag flag) const; + Scope* NewScope(); + Binding* NewBinding(); + + std::vector<Binding*> CollectVisible(Scope* scope, int32_t position, + bool initialized_only) const; + + Scope* root_ = nullptr; + // Object storage: a deque keeps addresses stable without one heap + // allocation per object. scopes_/bindings_ list the same objects in + // creation order. + std::deque<Scope> scope_storage_; + std::deque<Binding> binding_storage_; + std::vector<Scope*> scopes_; + std::vector<Binding*> bindings_; + std::vector<Scope*> scope_of_; // by Node::id + std::vector<Binding*> binding_of_; // by Node::id + std::vector<uint8_t> id_flags_; // by Node::id, IdFlag bits + std::vector<Identifier*> unresolved_; + absl::flat_hash_set<std::string_view> all_names_; +}; + +// Collects the binding identifiers of a pattern (Identifier, ObjectPattern, +// ArrayPattern, AssignmentPattern, RestElement) in source order. Default +// value expressions and computed keys are not descended into. +void CollectBoundIdentifiers(Node* pattern, std::vector<Identifier*>* out); + +// Renames a binding: all its declaration sites and references. `new_name` +// is interned in `tree`. The analysis stays consistent (names are updated +// in place) except for all_names()/FreshName(), which keep the old name. +void RenameBinding(Tree* tree, Binding* binding, std::string_view new_name); + +enum class RenameScope { + kVariables, // everything whose name is not observable through + // Function.prototype.name: no function/class names, no + // variables initialized with anonymous functions/classes + kAll, +}; + +// Renames every binding that is safe to rename to `<prefix><n>`. Returns +// the number of renamed bindings. Used as a behavioural self-test of the +// scope analysis: the renamed program must behave like the original. +size_t RenameAllBindings(Tree* tree, ScopeAnalysis* analysis, + std::string_view prefix, RenameScope which); + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_SCOPE_H_ diff --git a/deps/v8/experimental/redline/fast/tree.cc b/deps/v8/experimental/redline/fast/tree.cc new file mode 100644 index 000000000000..b6308e1dc05f --- /dev/null +++ b/deps/v8/experimental/redline/fast/tree.cc @@ -0,0 +1,122 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/fast/tree.h" + +namespace redline { +namespace fast { + +namespace { + +// Shallow copy of one node into `arena` (children still point into the +// source tree; the caller re-clones them). +Node* CopyShallow(Arena* arena, const Node* node) { + switch (node->kind) { +#define COPY_CASE(name) \ + case NodeKind::k##name: \ + return arena->New<name>(*node->Cast<name>()); + FAST_NODE_KIND_LIST(COPY_CASE) +#undef COPY_CASE + } + return nullptr; +} + +} // namespace + +Node* Tree::CloneImpl(const Node* node, bool keep_ids) { + if (node == nullptr) { + return nullptr; + } + Node* copy = CopyShallow(&arena_, node); + copy->id = keep_ids ? node->id : next_id_++; + // Re-intern string views that may point into another tree's arena. + switch (copy->kind) { + case NodeKind::kIdentifier: { + auto* n = copy->Cast<Identifier>(); + n->name = Intern(n->name); + break; + } + case NodeKind::kPrivateIdentifier: { + auto* n = copy->Cast<PrivateIdentifier>(); + n->name = Intern(n->name); + break; + } + case NodeKind::kNumericLiteral: { + auto* n = copy->Cast<NumericLiteral>(); + n->raw = Intern(n->raw); + break; + } + case NodeKind::kBigIntLiteral: { + auto* n = copy->Cast<BigIntLiteral>(); + n->raw = Intern(n->raw); + break; + } + case NodeKind::kStringLiteral: { + auto* n = copy->Cast<StringLiteral>(); + n->raw = Intern(n->raw); + break; + } + case NodeKind::kRegExpLiteral: { + auto* n = copy->Cast<RegExpLiteral>(); + n->pattern = Intern(n->pattern); + n->regexp_flags = Intern(n->regexp_flags); + break; + } + case NodeKind::kTemplateElement: { + auto* n = copy->Cast<TemplateElement>(); + n->raw = Intern(n->raw); + break; + } + case NodeKind::kNativeCallExpression: { + auto* n = copy->Cast<NativeCallExpression>(); + n->name = Intern(n->name); + break; + } + case NodeKind::kExpressionStatement: { + auto* n = copy->Cast<ExpressionStatement>(); + n->directive = Intern(n->directive); + break; + } + default: + break; + } + ForEachChildSlot(copy, [&](Node** slot) { + if (*slot != nullptr) { + *slot = CloneImpl(*slot, keep_ids); + } + }); + return copy; +} + +std::unique_ptr<Tree> Tree::Copy() const { + // The source text is not copied: the clone re-interns every string it + // needs, and node positions are only compared with each other (and + // renumbered before every scope analysis). The parser is the only reader + // of source(), on the tree it builds. + auto tree = std::make_unique<Tree>(); + if (root_ != nullptr) { + tree->set_root( + static_cast<Program*>(tree->CloneImpl(root_, /*keep_ids=*/true))); + } + tree->next_id_ = next_id_; + return tree; +} + +Node* Tree::FindNode(uint32_t id) const { + Node* found = nullptr; + Walk(root_, [&](Node* node) { + if (found != nullptr) { + return false; + } + if (node->id == id) { + found = node; + return false; + } + return true; + }); + return found; +} + +} // namespace fast +} // namespace redline diff --git a/deps/v8/experimental/redline/fast/tree.h b/deps/v8/experimental/redline/fast/tree.h new file mode 100644 index 000000000000..60d26fa36419 --- /dev/null +++ b/deps/v8/experimental/redline/fast/tree.h @@ -0,0 +1,84 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_FAST_TREE_H_ +#define V8_EXPERIMENTAL_REDLINE_FAST_TREE_H_ + +#include <cstdint> +#include <memory> +#include <string> +#include <string_view> + +#include "experimental/redline/fast/arena.h" +#include "experimental/redline/fast/ast.h" + +namespace redline { +namespace fast { + +// Owns one program: its arena, the original source text (if any), the root +// Program node and the node id counter. +class Tree { + public: + Tree() = default; + Tree(const Tree&) = delete; + Tree& operator=(const Tree&) = delete; + + Arena& arena() { return arena_; } + Program* root() const { return root_; } + void set_root(Program* root) { root_ = root; } + + // Allocates a node with a fresh id. + template <typename T> + T* New(int32_t start = -1, int32_t end = -1) { + T* node = arena_.New<T>(); + node->id = next_id_++; + node->start = start; + node->end = end; + return node; + } + + // The source this tree was parsed from (empty for generated programs). + std::string_view source() const { return source_; } + void SetSource(std::string_view source) { + source_ = arena_.CopyString(source); + } + + // Copies `text` into the arena (for names and raw literal text). + std::string_view Intern(std::string_view text) { + return arena_.CopyString(text); + } + + // Number of ids handed out so far (upper bound for ids in the tree). + uint32_t id_limit() const { return next_id_; } + + // Deep-copies `node` (from this or any other tree) into this tree. All + // nodes get fresh ids; string views are re-interned here. + Node* Clone(const Node* node) { return CloneImpl(node, /*keep_ids=*/false); } + template <typename T> + T* Clone(const T* node) { + return static_cast<T*>(Clone(static_cast<const Node*>(node))); + } + + // Deep copy of the whole tree. Node ids are preserved, so ids seen in one + // view of a program remain valid in the next mutation step, and new nodes + // get ids above `id_limit()`. The copy has no source text (strings are + // re-interned into the copy's arena). + std::unique_ptr<Tree> Copy() const; + + // Finds the node with the given id (linear walk), or nullptr. + Node* FindNode(uint32_t id) const; + + private: + Node* CloneImpl(const Node* node, bool keep_ids); + + Arena arena_; + Program* root_ = nullptr; + std::string_view source_; + uint32_t next_id_ = 0; +}; + +} // namespace fast +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_FAST_TREE_H_ diff --git a/deps/v8/experimental/redline/generators/codegen.cc b/deps/v8/experimental/redline/generators/codegen.cc new file mode 100644 index 000000000000..0add684ae3a3 --- /dev/null +++ b/deps/v8/experimental/redline/generators/codegen.cc @@ -0,0 +1,1436 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/generators/codegen.h" + +#include <algorithm> +#include <cmath> +#include <cstdlib> +#include <string> + +#include "experimental/redline/core/tunable.h" + +namespace redline { + +using namespace fast; // NOLINT(build/namespaces) + +namespace { + +bool IsIdentifierStart(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || + c == '$'; +} + +bool IsIdentifierPart(char c) { + return IsIdentifierStart(c) || (c >= '0' && c <= '9'); +} + +// Types for which a literal can be synthesized directly. +JsType RandomLiteralType(Random& rng) { + static const JsType kTypes[] = { + JsType::kNumber, JsType::kNumber, JsType::kNumber, JsType::kString, + JsType::kString, JsType::kBoolean, JsType::kBigInt, JsType::kRegExp, + JsType::kNullish, JsType::kArray, JsType::kObject}; + return kTypes[rng.Index(sizeof(kTypes) / sizeof(kTypes[0]))]; +} + +} // namespace + +bool IsIdentifierName(std::string_view name) { + if (name.empty() || !IsIdentifierStart(name[0])) { + return false; + } + for (char c : name) { + if (!IsIdentifierPart(c)) { + return false; + } + } + return true; +} + +// --- GenContext +// ---------------------------------------------------------------- + +GenContext GenContext::Nested(bool is_function, bool is_arrow, bool is_async, + bool is_generator) const { + GenContext nested(builder, generators, env); + nested.slot = slot; + nested.syntax = syntax; + nested.visible = visible; + nested.depth = depth + 1; + nested.max_depth = max_depth; + nested.out = nullptr; + if (is_function) { + nested.syntax.in_function = true; + nested.syntax.in_async = is_async; + nested.syntax.in_generator = is_generator; + nested.syntax.in_loop = false; + nested.syntax.in_switch = false; + nested.syntax.labels.clear(); + if (!is_arrow) { + nested.syntax.in_method = false; + nested.syntax.in_constructor = false; + nested.syntax.has_super_class = false; + nested.syntax.in_static_block = false; + nested.syntax.in_class_field = false; + nested.syntax.has_this = true; + nested.syntax.has_arguments = true; + } + } + return nested; +} + +GenContext GenContext::Inner(bool in_loop, bool in_switch) const { + GenContext inner(builder, generators, env); + inner.slot = slot; + inner.syntax = syntax; + inner.visible = visible; + inner.depth = depth + 1; + inner.max_depth = max_depth; + inner.out = nullptr; + if (in_loop) { + inner.syntax.in_loop = true; + } + if (in_switch) { + inner.syntax.in_switch = true; + } + return inner; +} + +// --- leaves +// -------------------------------------------------------------------- + +REDLINE_TUNABLE(kLiteralSmallIntMax, "codegen.literal.small_int_max", 10, 0, + 1024, + "largest value of a small random integer literal (0..max)"); +REDLINE_TUNABLE(kLiteralMediumIntMin, "codegen.literal.medium_int_min", -5, + -1024, 1024, + "smallest value of a medium random integer literal"); +REDLINE_TUNABLE(kLiteralMediumIntMax, "codegen.literal.medium_int_max", 100, + -1024, 1024, + "largest value of a medium random integer literal"); +REDLINE_TUNABLE(kLiteralLargeIntMax, "codegen.literal.large_int_max", 1 << 16, + 0, 1 << 30, + "largest value of a large random integer literal (0..max)"); + +fast::Expression* CodeGen::Integer() { + Random& r = rng(); + switch (r.Index(4)) { + case 0: + return mk::Num( + tree(), static_cast<double>(r.Range(0, kLiteralSmallIntMax.AsInt()))); + case 1: + return mk::Num( + tree(), static_cast<double>(r.Range(kLiteralMediumIntMin.AsInt(), + kLiteralMediumIntMax.AsInt()))); + case 2: { + double v = r.Pick(env().numbers()); + if (v != v || v != static_cast<double>(static_cast<int64_t>(v))) { + v = 1; + } + return mk::Num(tree(), v); + } + default: + return mk::Num( + tree(), static_cast<double>(r.Range(0, kLiteralLargeIntMax.AsInt()))); + } +} + +REDLINE_TUNABLE( + kLiteralFractionMin, "codegen.literal.fraction_min", -1000, -1048576, + 1048576, + "smallest numerator of a random fractional number literal (numerator / 8)"); +REDLINE_TUNABLE( + kLiteralFractionMax, "codegen.literal.fraction_max", 1000, -1048576, + 1048576, + "largest numerator of a random fractional number literal (numerator / 8)"); + +fast::Expression* CodeGen::Number() { + Random& r = rng(); + switch (r.Index(5)) { + case 0: + case 1: + return Integer(); + case 2: + return mk::Num(tree(), r.Pick(env().numbers())); + case 3: + return mk::Num(tree(), r.Double() * 10.0 - 5.0); + default: + return mk::Num(tree(), + static_cast<double>(r.Range(kLiteralFractionMin.AsInt(), + kLiteralFractionMax.AsInt())) / + 8.0); + } +} + +REDLINE_TUNABLE(kLiteralRandomStringChance, + "codegen.literal.random_string_chance", 0.15, 0, 1, + "probability that a string literal is a short random ASCII " + "string instead of a corpus string"); +REDLINE_TUNABLE(kLiteralRandomStringMaxLength, + "codegen.literal.random_string_max_length", 6, 0, 64, + "most characters in a random ASCII string literal"); +REDLINE_TUNABLE(kLiteralPropertyNameStringChance, + "codegen.literal.property_name_string_chance", 0.1, 0, 1, + "probability that a string literal is a property name (useful " + "for computed access)"); + +fast::Expression* CodeGen::String() { + Random& r = rng(); + if (r.Chance(kLiteralRandomStringChance())) { + // Short random ASCII string. + std::string s; + int n = static_cast<int>(r.Range(0, kLiteralRandomStringMaxLength.AsInt())); + for (int i = 0; i < n; i++) { + s.push_back(static_cast<char>('a' + r.Index(26))); + } + return mk::Str(tree(), s); + } + if (r.Chance(kLiteralPropertyNameStringChance())) { + // Property name as string (useful for computed access). + return mk::Str(tree(), PropertyName()); + } + return mk::Str(tree(), r.Pick(env().strings())); +} + +fast::Expression* CodeGen::Boolean() { return mk::Bool(tree(), rng().Coin()); } + +REDLINE_TUNABLE(kLiteralBigintTableChance, + "codegen.literal.bigint_table_chance", 0.6, 0, 1, + "probability that a BigInt literal comes from the table of " + "interesting values instead of being random"); +REDLINE_TUNABLE(kLiteralRandomBigintMax, "codegen.literal.random_bigint_max", + 1000000, 0, 1 << 30, "largest random BigInt literal (0..max)"); + +fast::Expression* CodeGen::BigInt() { + Random& r = rng(); + static const char* const kBig[] = {"0", + "1", + "2", + "255", + "256", + "4294967295", + "9007199254740993", + "18446744073709551615", + "18446744073709551616", + "340282366920938463463374607431768211456"}; + if (r.Chance(kLiteralBigintTableChance())) { + return mk::BigInt(tree(), kBig[r.Index(sizeof(kBig) / sizeof(kBig[0]))]); + } + return mk::BigInt( + tree(), std::to_string(r.Range(0, kLiteralRandomBigintMax.AsInt()))); +} + +REDLINE_TUNABLE(kRegExpGeneratedChance, "codegen.regexp.generated_chance", 0.75, + 0, 1, + "probability that a regexp literal gets a generated pattern " + "rather than one of the environment's fixed ones"); +REDLINE_TUNABLE(kRegExpMaxTerms, "codegen.regexp.max_terms", 4, 1, 16, + "most terms in one alternative of a pattern"); +REDLINE_TUNABLE(kRegExpMaxDepth, "codegen.regexp.max_depth", 2, 0, 8, + "deepest group nesting in a pattern"); +REDLINE_TUNABLE(kRegExpFlagChance, "codegen.regexp.flag_chance", 0.25, 0, 1, + "probability of each of the flags d, g, i, m, s, y and of one " + "unicode flag (u or v)"); + +namespace { + +// A random regular expression pattern from general building blocks: atoms, +// escapes, character classes, groups, lookarounds, modifiers, quantifiers, +// alternatives and backreferences. Valid by construction for its mode +// (`unicode`: the u or v flag, `sets`: the v flag). +class RegExpPatternBuilder { + public: + RegExpPatternBuilder(Random& r, bool unicode, bool sets) + : r_(r), unicode_(unicode), sets_(sets) {} + + std::string Build() { + std::string out; + Disjunction(0, &out); + return out; + } + + private: + void Disjunction(int depth, std::string* out) { + int alternatives = r_.Chance(0.25) ? 2 + static_cast<int>(r_.Index(2)) : 1; + for (int i = 0; i < alternatives; i++) { + if (i > 0) { + *out += '|'; + } + int terms = 1 + static_cast<int>(r_.Index( + static_cast<size_t>(kRegExpMaxTerms.AsInt()))); + for (int k = 0; k < terms; k++) { + Term(depth, out); + } + } + } + + void Term(int depth, std::string* out) { + bool nest = depth < kRegExpMaxDepth.AsInt(); + switch (r_.Index(nest ? 9 : 6)) { + case 0: + case 1: + Atom(out); + Quantifier(out); + break; + case 2: + Class(out); + Quantifier(out); + break; + case 3: + *out += r_.Pick({"^", "$", "\\b", "\\B"}); + break; + case 4: + Backreference(out); + break; + case 5: + *out += '.'; + Quantifier(out); + break; + case 6: + Group(depth, out); + Quantifier(out); + break; + case 7: + // Never quantified: an error for lookbehinds, and for all + // lookarounds in unicode mode. + *out += r_.Pick({"(?=", "(?!", "(?<=", "(?<!"}); + Disjunction(depth + 1, out); + *out += ')'; + break; + default: + *out += r_.Pick({"(?i:", "(?m:", "(?s:", "(?-i:", "(?i-s:", "(?ms:"}); + Disjunction(depth + 1, out); + *out += ')'; + Quantifier(out); + break; + } + } + + void Atom(std::string* out) { + switch (r_.Index(4)) { + case 0: + *out += r_.Pick({"a", "b", "x", "Z", "0", "7", "_", " ", ",", "-", ":", + "\u00e9", "\u4e2d"}); + break; + case 1: + *out += r_.Pick({"\\d", "\\D", "\\w", "\\W", "\\s", "\\S", "\\n", "\\t", + "\\.", "\\/", "\\\\"}); + break; + case 2: + *out += unicode_ ? r_.Pick({"\\u{1F600}", "\\u0041", "\\x7f", "\\cJ"}) + : r_.Pick({"\\u0041", "\\x7f", "\\cJ"}); + break; + default: + if (unicode_) { + *out += r_.Pick({"\\p{L}", "\\P{L}", "\\p{Lu}", "\\p{Nd}", + "\\p{Script=Greek}", "\\p{ASCII}"}); + } else { + *out += r_.Pick({"ab", "foo", "\\d\\d", "xyz"}); + } + break; + } + } + + void Class(std::string* out) { + if (sets_ && r_.Chance(0.4)) { + *out += r_.Pick({"[\\p{L}--[a-z]]", "[[a-z]&&[a-f]]", "[\\q{abc|d}]", + "[\\p{ASCII}--\\p{L}]", "[[0-9][a-c]]"}); + return; + } + *out += r_.Pick({"[a-z]", "[^a-z]", "[0-9a-f]", "[\\d]", "[\\s\\S]", + "[A-Z_]", "[^\\w]", "[xyz]"}); + } + + void Group(int depth, std::string* out) { + switch (r_.Index(3)) { + case 0: + *out += '('; + groups_++; + break; + case 1: + *out += "(?:"; + break; + default: + names_++; + groups_++; + *out += "(?<g" + std::to_string(names_) + ">"; + break; + } + Disjunction(depth + 1, out); + *out += ')'; + } + + void Backreference(std::string* out) { + if (names_ > 0 && r_.Coin()) { + *out += "\\k<g" + + std::to_string(1 + r_.Index(static_cast<size_t>(names_))) + ">"; + } else if (groups_ > 0) { + // In a group, so that a following digit does not extend the number. + *out += "(?:\\" + + std::to_string(1 + r_.Index(static_cast<size_t>(groups_))) + ")"; + } else { + Atom(out); + } + } + + void Quantifier(std::string* out) { + if (!r_.Chance(0.4)) { + return; + } + *out += r_.Pick({"*", "+", "?", "{2}", "{1,3}", "{0,}"}); + if (r_.Chance(0.3)) { + *out += '?'; + } + } + + Random& r_; + bool unicode_; + bool sets_; + int groups_ = 0; + int names_ = 0; +}; + +} // namespace + +fast::Expression* CodeGen::RegExp() { + Random& r = rng(); + if (!r.Chance(kRegExpGeneratedChance())) { + const auto& re = r.Pick(env().regexps()); + return mk::RegExp(tree(), re.first, re.second); + } + std::string flags; + for (char flag : {'d', 'g', 'i', 'm', 's', 'y'}) { + if (r.Chance(kRegExpFlagChance())) { + flags += flag; + } + } + bool unicode = r.Chance(kRegExpFlagChance()); + bool sets = unicode && r.Coin(); + if (unicode) { + flags += sets ? 'v' : 'u'; + } + RegExpPatternBuilder builder(r, unicode, sets); + return mk::RegExp(tree(), builder.Build(), flags); +} + +fast::Expression* CodeGen::Nullish() { + return rng().Coin() ? static_cast<fast::Expression*>(mk::Null(tree())) + : static_cast<fast::Expression*>(mk::Undefined(tree())); +} + +fast::Expression* CodeGen::Literal(JsType type) { + if (type == JsType::kUnknown) { + type = RandomLiteralType(rng()); + } + switch (type) { + case JsType::kNumber: + return Number(); + case JsType::kString: + return String(); + case JsType::kBoolean: + return Boolean(); + case JsType::kBigInt: + return BigInt(); + case JsType::kRegExp: + return RegExp(); + case JsType::kNullish: + return Nullish(); + case JsType::kArray: + return ArrayLiteral(1); + case JsType::kObject: + return ObjectLiteral(1); + case JsType::kFunction: + return FunctionValue(ctx_.max_depth); // leaf-ish: no nested statements + case JsType::kSymbol: + return mk::Call(tree(), mk::Id(tree(), "Symbol"), {String()}); + default: { + // Types that need a constructor. + if (fast::Expression* e = Construct(type)) { + return e; + } + return Number(); + } + } +} + +REDLINE_TUNABLE(kVariableRecentChance, "codegen.variable.recent_chance", 0.5, 0, + 1, + "probability that a variable reference is drawn from the first " + "few candidates only (recently declared ones)"); +REDLINE_TUNABLE(kVariableRecentWindow, "codegen.variable.recent_window", 4, 1, + 64, + "number of leading candidates considered when preferring " + "recently declared variables"); + +fast::Identifier* CodeGen::Variable(JsType type) { + std::vector<const redline::Variable*> candidates; + for (const redline::Variable& v : ctx_.visible) { + if (v.name == "arguments" && !ctx_.syntax.has_arguments) { + continue; + } + if (type == JsType::kUnknown || v.type == type) { + candidates.push_back(&v); + } + } + if (candidates.empty() && type != JsType::kUnknown) { + // Fall back to variables of unknown type, which may well have the + // requested type at runtime. + for (const redline::Variable& v : ctx_.visible) { + if (v.type == JsType::kUnknown && v.name != "arguments") { + candidates.push_back(&v); + } + } + } + if (candidates.empty()) { + return nullptr; + } + // Prefer recently declared (innermost) variables slightly. + size_t index = rng().Chance(kVariableRecentChance()) + ? rng().Index(std::min<size_t>( + candidates.size(), + static_cast<size_t>(kVariableRecentWindow.AsInt()))) + : rng().Index(candidates.size()); + return mk::Id(tree(), candidates[index]->name); +} + +fast::Identifier* CodeGen::MutableVariable(JsType type) { + std::vector<const redline::Variable*> candidates; + for (const redline::Variable& v : ctx_.visible) { + if (v.is_constant) { + continue; + } + if (v.name == "arguments" || v.name == "eval") { + continue; + } + if (type == JsType::kUnknown || v.type == type) { + candidates.push_back(&v); + } + } + if (candidates.empty()) { + return nullptr; + } + return mk::Id(tree(), rng().Pick(candidates)->name); +} + +bool CodeGen::HasVariable(JsType type) { + for (const redline::Variable& v : ctx_.visible) { + if (type == JsType::kUnknown || v.type == type) { + return true; + } + } + return false; +} + +// --- composite values +// ---------------------------------------------------------- + +REDLINE_TUNABLE(kValueVariableChance, "codegen.value.variable_chance", 0.6, 0, + 1, + "probability that a value is an existing visible variable " + "rather than a fresh expression"); +REDLINE_TUNABLE(kValueCompoundMaxDepth, "codegen.value.compound_max_depth", 2, + 0, 16, + "values nested less deeply than this may be compound " + "expressions (arithmetic, comparison, concatenation)"); +REDLINE_TUNABLE(kValueCompoundChance, "codegen.value.compound_chance", 0.2, 0, + 1, + "probability that a shallow value is a compound expression " + "instead of a literal"); +REDLINE_TUNABLE(kValueConstructChance, "codegen.value.construct_chance", 0.5, 0, + 1, + "probability that a value of an object-like type is a fresh " + "`new` expression rather than a literal"); + +fast::Expression* CodeGen::Value(JsType type, int depth) { + Random& r = rng(); + // Variables first: reusing existing values creates data flow. + if (r.Chance(kValueVariableChance())) { + if (fast::Identifier* id = Variable(type)) { + return id; + } + } + if (depth < kValueCompoundMaxDepth.AsInt() && + r.Chance(kValueCompoundChance())) { + switch (type) { + case JsType::kNumber: + return BinaryOperation(depth + 1); + case JsType::kBoolean: + return Comparison(depth + 1); + case JsType::kString: + if (fast::Identifier* id = Variable(JsType::kString)) { + return mk::Binary(tree(), BinaryOp::kAdd, id, String()); + } + break; + case JsType::kUnknown: + return Expression(depth + 1); + default: + break; + } + } + if (type != JsType::kUnknown && type != JsType::kNumber && + type != JsType::kString && type != JsType::kBoolean && + type != JsType::kBigInt && type != JsType::kNullish && + type != JsType::kRegExp && r.Chance(kValueConstructChance())) { + if (fast::Expression* e = Construct(type)) { + return e; + } + } + return Literal(type); +} + +REDLINE_TUNABLE(kExpressionMaxDepth, "codegen.expression.max_depth", 3, 0, 16, + "expression nesting depth at which Expression() stops nesting " + "and produces a plain value"); + +fast::Expression* CodeGen::Expression(int depth) { + Random& r = rng(); + if (depth >= kExpressionMaxDepth.AsInt()) { + return Value(JsType::kUnknown, depth); + } + switch (r.Index(12)) { + case 0: + return BinaryOperation(depth + 1); + case 1: + return Comparison(depth + 1); + case 2: + return UnaryOperation(depth + 1); + case 3: + return BuiltinCall(); + case 4: { + fast::Expression* object = ObjectLike(); + return MethodCall(object, Builder::GuessType(object)); + } + case 5: + return Property(ObjectLike()); + case 6: + return Construct(); + case 7: + return CallWithArguments(Callable()); + case 8: + return mk::Cond(tree(), Condition(depth + 1), + Value(JsType::kUnknown, depth + 1), + Value(JsType::kUnknown, depth + 1)); + case 9: + return mk::Logical(tree(), RandomLogicalOp(r), + Value(JsType::kUnknown, depth + 1), + Value(JsType::kUnknown, depth + 1)); + case 10: + return mk::Unary(tree(), UnaryOp::kTypeof, + Value(JsType::kUnknown, depth + 1)); + default: + return Literal(); + } +} + +REDLINE_TUNABLE(kObjectMaxFields, "codegen.object.max_fields", 5, 0, 64, + "most properties an object literal gets"); +REDLINE_TUNABLE(kObjectFieldContinueChance, + "codegen.object.field_continue_chance", 0.6, 0, 1, + "probability of adding one more property to an object literal " + "(geometric count)"); +REDLINE_TUNABLE(kObjectMethodMaxDepth, "codegen.object.method_max_depth", 2, 0, + 16, + "object literals nested less deeply than this may contain " + "methods and accessors"); +REDLINE_TUNABLE( + kObjectMethodChance, "codegen.object.method_chance", 0.15, 0, 1, + "probability that an object literal property is a method or accessor"); +REDLINE_TUNABLE(kObjectMethodMaxExtraStatements, + "codegen.object.method_max_extra_statements", 2, 0, 64, + "most statements an object-literal method body gets beyond its " + "first one (geometric count)"); +REDLINE_TUNABLE(kObjectGetterChance, "codegen.object.getter_chance", 0.3, 0, 1, + "probability that an object-literal method is a getter instead " + "of a plain method"); +REDLINE_TUNABLE(kObjectSpreadChance, "codegen.object.spread_chance", 0.1, 0, 1, + "probability that an object literal property is a spread of a " + "visible object variable"); +REDLINE_TUNABLE(kObjectLiteralKeyChance, "codegen.object.literal_key_chance", + 0.1, 0, 1, + "probability that an object literal property has a numeric, " + "string or bigint literal key"); + +fast::Expression* CodeGen::ObjectLiteral(int depth) { + Random& r = rng(); + std::vector<Node*> properties; + int n = r.SmallCount(kObjectMaxFields.AsInt(), kObjectFieldContinueChance()); + bool has_proto = false; + for (int i = 0; i < n; i++) { + std::string_view name = PropertyName(); + if (name == "__proto__") { + if (has_proto) { + continue; + } + has_proto = true; + } + if (!IsIdentifierName(name) && r.Coin()) { + properties.push_back( + mk::Prop(tree(), Key(), Value(JsType::kUnknown, depth + 1), true)); + continue; + } + if (depth < kObjectMethodMaxDepth.AsInt() && + r.Chance(kObjectMethodChance())) { + // Method or accessor. + GenContext nested = ctx_.Nested(true, false, false, false); + nested.syntax.in_method = true; + std::vector<Statement*> body = Body( + nested, 1 + r.SmallCount(kObjectMethodMaxExtraStatements.AsInt())); + body.push_back(mk::Return(tree(), Value(JsType::kUnknown, depth + 1))); + FunctionExpression* fn = mk::Function(tree(), "", {}, std::move(body)); + std::string_view key = IsIdentifierName(name) ? name : "m"; + if (r.Chance(kObjectGetterChance())) { + properties.push_back(mk::Accessor(tree(), key, fn, /*getter=*/true)); + } else { + properties.push_back(mk::Method(tree(), key, fn)); + } + continue; + } + if (r.Chance(kObjectSpreadChance())) { + if (fast::Expression* spread = Variable(JsType::kObject)) { + properties.push_back(mk::Spread(tree(), spread)); + continue; + } + } + std::string_view key = IsIdentifierName(name) ? name : "p"; + if (r.Chance(kObjectLiteralKeyChance())) { + // A literal key: `{1: v}`, `{"a b": v}`, `{10n: v}`. These are not + // computed keys: the parser canonicalizes them while building the + // literal's boilerplate, a path identifier keys never take. + fast::Expression* literal_key = nullptr; + switch (r.Index(3)) { + case 0: { + // A numeric key is a plain literal: no sign allowed. + fast::Expression* integer = Integer(); + if (auto* number = integer->As<NumericLiteral>()) { + number->value = std::fabs(number->value); + literal_key = number; + } else { + literal_key = mk::Num(tree(), static_cast<double>(r.Index(1000))); + } + break; + } + case 1: + literal_key = String(); + break; + default: + literal_key = BigInt(); + break; + } + properties.push_back(mk::Prop(tree(), literal_key, + Value(JsType::kUnknown, depth + 1), + /*computed=*/false)); + continue; + } + properties.push_back( + mk::Prop(tree(), key, Value(JsType::kUnknown, depth + 1))); + } + return mk::Object(tree(), std::move(properties)); +} + +REDLINE_TUNABLE(kArrayMaxElements, "codegen.array.max_elements", 8, 0, 64, + "most elements an array literal gets"); +REDLINE_TUNABLE(kArrayElementContinueChance, + "codegen.array.element_continue_chance", 0.7, 0, 1, + "probability of adding one more element to an array literal " + "(geometric count)"); +REDLINE_TUNABLE(kArrayHoleChance, "codegen.array.hole_chance", 0.05, 0, 1, + "probability that an array literal element is a hole"); +REDLINE_TUNABLE(kArraySpreadChance, "codegen.array.spread_chance", 0.05, 0, 1, + "probability that an array literal element is a spread of a " + "visible array variable"); +REDLINE_TUNABLE(kArrayIntegerElementChance, + "codegen.array.integer_element_chance", 0.7, 0, 1, + "probability that an element of a numeric array literal is an " + "integer literal rather than any number value"); + +fast::Expression* CodeGen::ArrayLiteral(int depth) { + Random& r = rng(); + std::vector<fast::Expression*> elements; + int n = + r.SmallCount(kArrayMaxElements.AsInt(), kArrayElementContinueChance()); + JsType element_type = JsType::kUnknown; + // Homogeneous arrays are common and exercise elements kinds. + switch (r.Index(5)) { + case 0: + element_type = JsType::kNumber; + break; + case 1: + element_type = JsType::kString; + break; + case 2: + element_type = JsType::kObject; + break; + default: + break; + } + for (int i = 0; i < n; i++) { + if (r.Chance(kArrayHoleChance())) { + elements.push_back(nullptr); // hole + } else if (r.Chance(kArraySpreadChance())) { + if (fast::Identifier* id = Variable(JsType::kArray)) { + elements.push_back(mk::Spread(tree(), id)); + continue; + } + elements.push_back(Value(element_type, depth + 1)); + } else if (element_type == JsType::kNumber && + r.Chance(kArrayIntegerElementChance())) { + elements.push_back(Integer()); + } else { + elements.push_back(Value(element_type, depth + 1)); + } + } + return mk::Array(tree(), std::move(elements)); +} + +REDLINE_TUNABLE(kFunctionMaxParams, "codegen.function.max_params", 3, 0, 16, + "most parameters a generated function expression declares"); +REDLINE_TUNABLE( + kFunctionArrowChance, "codegen.function.arrow_chance", 0.4, 0, 1, + "probability that a generated function expression is an arrow function"); +REDLINE_TUNABLE(kFunctionAsyncChance, "codegen.function.async_chance", 0.1, 0, + 1, "probability that a generated function expression is async"); +REDLINE_TUNABLE(kFunctionGeneratorChance, "codegen.function.generator_chance", + 0.08, 0, 1, + "probability that a generated non-arrow function expression is " + "a generator"); +REDLINE_TUNABLE(kFunctionMaxExtraStatements, + "codegen.function.max_extra_statements", 3, 0, 64, + "most statements a generated function body gets beyond its " + "first one (geometric count)"); + +fast::Expression* CodeGen::FunctionValue(int depth) { + Random& r = rng(); + std::vector<std::string_view> params; + int n = static_cast<int>(r.Range(0, kFunctionMaxParams.AsInt())); + GenContext nested = ctx_.Nested(true, /*is_arrow=*/false, false, false); + for (int i = 0; i < n; i++) { + std::string_view p = ctx_.builder.FreshName("a"); + params.push_back(p); + nested.Declare(p, JsType::kUnknown); + } + bool arrow = r.Chance(kFunctionArrowChance()); + bool is_async = r.Chance(kFunctionAsyncChance()); + bool is_generator = !arrow && r.Chance(kFunctionGeneratorChance()); + nested.syntax.in_async = is_async; + nested.syntax.in_generator = is_generator; + if (arrow) { + // Arrows keep the enclosing this/arguments/super context. + nested.syntax.has_arguments = ctx_.syntax.has_arguments; + nested.syntax.in_method = ctx_.syntax.in_method; + nested.syntax.in_constructor = false; + nested.syntax.in_class_field = ctx_.syntax.in_class_field; + nested.syntax.in_static_block = ctx_.syntax.in_static_block; + } + CodeGen inner(nested); + std::vector<Statement*> body; + if (depth < ctx_.max_depth) { + body = inner.Body(nested, + 1 + r.SmallCount(kFunctionMaxExtraStatements.AsInt())); + } + if (arrow && body.empty() && r.Coin()) { + return mk::ArrowExpr(tree(), params, inner.Expression(depth + 1), is_async); + } + body.push_back(mk::Return(tree(), inner.Value(JsType::kUnknown, depth + 1))); + if (arrow) { + return mk::Arrow(tree(), params, std::move(body), is_async); + } + return mk::Function(tree(), "", params, std::move(body), is_async, + is_generator); +} + +REDLINE_TUNABLE(kCallableVariableChance, "codegen.callable.variable_chance", + 0.7, 0, 1, + "probability that a callee is a visible function variable"); +REDLINE_TUNABLE( + kCallableBuiltinChance, "codegen.callable.builtin_chance", 0.5, 0, 1, + "probability that a callee is a builtin function-valued global"); +REDLINE_TUNABLE(kCallableClassChance, "codegen.callable.class_chance", 0.5, 0, + 1, "probability that a callee is a visible class variable"); + +fast::Expression* CodeGen::Callable() { + Random& r = rng(); + if (r.Chance(kCallableVariableChance())) { + if (fast::Identifier* id = Variable(JsType::kFunction)) { + return id; + } + } + if (r.Chance(kCallableBuiltinChance())) { + // A builtin function-valued global. + std::vector<const BuiltinGlobal*> functions; + for (const BuiltinGlobal& g : env().globals()) { + if (g.type == JsType::kFunction && !g.constructible) { + functions.push_back(&g); + } + } + if (!functions.empty()) { + return mk::Id(tree(), r.Pick(functions)->name); + } + } + if (r.Chance(kCallableClassChance())) { + if (fast::Identifier* id = Variable(JsType::kClass)) { + return id; + } + } + return FunctionValue(ctx_.depth + 1); +} + +REDLINE_TUNABLE(kObjectLikeVariableChance, + "codegen.object_like.variable_chance", 0.75, 0, 1, + "probability that an object-like operand is a visible variable " + "rather than a builtin or a fresh literal"); +REDLINE_TUNABLE(kObjectLikeBuiltinChance, "codegen.object_like.builtin_chance", + 0.15, 0, 1, + "probability that an object-like operand is a builtin " + "namespace or constructor object"); + +fast::Expression* CodeGen::ObjectLike() { + Random& r = rng(); + static const JsType kObjectTypes[] = { + JsType::kObject, JsType::kArray, JsType::kFunction, JsType::kMap, + JsType::kSet, JsType::kTypedArray, JsType::kClass, JsType::kRegExp, + JsType::kDate, JsType::kError, JsType::kPromise, JsType::kString}; + if (r.Chance(kObjectLikeVariableChance())) { + JsType type = + kObjectTypes[r.Index(sizeof(kObjectTypes) / sizeof(kObjectTypes[0]))]; + if (fast::Identifier* id = Variable(type)) { + return id; + } + if (fast::Identifier* id = Variable(JsType::kObject)) { + return id; + } + if (r.Coin()) { + if (fast::Identifier* id = Variable(JsType::kUnknown)) { + return id; + } + } + } + if (r.Chance(kObjectLikeBuiltinChance())) { + // A builtin namespace or constructor object. + const BuiltinGlobal& g = r.Pick(env().globals()); + if (g.type == JsType::kObject || g.constructible) { + return mk::Id(tree(), g.name); + } + } + if (r.Coin()) { + return ObjectLiteral(1); + } + return ArrayLiteral(1); +} + +REDLINE_TUNABLE(kTargetVariableChance, "codegen.target.variable_chance", 0.5, 0, + 1, + "probability that an assignment target is a mutable visible " + "variable rather than a property"); + +fast::Expression* CodeGen::Target() { + Random& r = rng(); + if (r.Chance(kTargetVariableChance())) { + if (fast::Identifier* id = MutableVariable()) { + return id; + } + } + fast::Expression* object = ObjectLike(); + if (object->Is<ObjectExpression>() || object->Is<ArrayExpression>()) { + // `[1,2].x = 3` is legal but pointless; prefer a variable if any. + if (fast::Identifier* id = MutableVariable()) { + return id; + } + } + return Property(object); +} + +std::string_view CodeGen::PropertyName() { + return rng().Pick(env().property_names()); +} + +fast::Expression* CodeGen::Property(fast::Expression* object, + std::string_view name) { + if (IsIdentifierName(name)) { + return mk::Member(tree(), object, name); + } + if (name.starts_with("Symbol.")) { + return mk::Index( + tree(), object, + mk::Member(tree(), mk::Id(tree(), "Symbol"), name.substr(7))); + } + // Numeric or otherwise non-identifier key. + bool numeric = !name.empty(); + for (char c : name) { + if (!((c >= '0' && c <= '9') || c == '.' || c == '-')) { + numeric = false; + } + } + if (numeric) { + double value = std::strtod(std::string(name).c_str(), nullptr); + return mk::Index(tree(), object, mk::Num(tree(), value)); + } + return mk::Index(tree(), object, mk::Str(tree(), name)); +} + +REDLINE_TUNABLE(kPropertyComputedChance, "codegen.property.computed_chance", + 0.15, 0, 1, + "probability that a property access is computed with a " + "variable or expression key"); +REDLINE_TUNABLE(kPropertyTypedNameChance, "codegen.property.typed_name_chance", + 0.6, 0, 1, + "probability that a property access on a value of known type " + "uses one of that type's properties"); + +fast::Expression* CodeGen::Property(fast::Expression* object) { + Random& r = rng(); + if (r.Chance(kPropertyComputedChance())) { + // Computed access with a variable or expression key. + if (fast::Identifier* key = + Variable(r.Coin() ? JsType::kNumber : JsType::kString)) { + return mk::Index(tree(), object, key); + } + return mk::Index(tree(), object, Key()); + } + // Type-directed property names when we know the type. + JsType type = Builder::GuessType(object); + if (object->Is<Identifier>()) { + for (const redline::Variable& v : ctx_.visible) { + if (v.name == object->Cast<Identifier>()->name) { + type = v.type; + break; + } + } + } + if (const BuiltinType* bt = env().ForType(type)) { + if (!bt->properties.empty() && r.Chance(kPropertyTypedNameChance())) { + return Property(object, r.Pick(bt->properties)); + } + } + return Property(object, PropertyName()); +} + +fast::Expression* CodeGen::Key() { + Random& r = rng(); + switch (r.Index(6)) { + case 0: + case 1: + return Integer(); + case 2: + return mk::Str(tree(), PropertyName()); + case 3: + return String(); + case 4: + return mk::Member( + tree(), mk::Id(tree(), "Symbol"), + r.Pick({"iterator", "toPrimitive", "hasInstance", "species", + "toStringTag", "asyncIterator", "isConcatSpreadable"})); + default: + return Number(); + } +} + +REDLINE_TUNABLE(kArgumentsArityViolationChance, + "codegen.arguments.arity_violation_chance", 0.05, 0, 1, + "probability that a builtin call ignores the builtin's arity " + "and passes a random number of arguments"); +REDLINE_TUNABLE(kArgumentsArityViolationMaxArgs, + "codegen.arguments.arity_violation_max_args", 4, 0, 16, + "most arguments an arity-violating builtin call passes"); +REDLINE_TUNABLE(kArgumentsCallbackArrowChance, + "codegen.arguments.callback_arrow_chance", 0.8, 0, 1, + "probability that a function-typed argument is a fresh short " + "arrow rather than an existing function value"); +REDLINE_TUNABLE(kArgumentsCallbackMaxParams, + "codegen.arguments.callback_max_params", 2, 0, 16, + "most parameters a callback arrow argument declares"); + +std::vector<fast::Expression*> CodeGen::Arguments( + const BuiltinFunction& function) { + Random& r = rng(); + int n = static_cast<int>(r.Range(function.min_args, function.max_args)); + if (r.Chance(kArgumentsArityViolationChance())) { + n = static_cast<int>(r.Range( + 0, kArgumentsArityViolationMaxArgs.AsInt())); // arity violations + } + std::vector<fast::Expression*> args; + for (int i = 0; i < n; i++) { + JsType hint = i < 3 ? function.args[i] : JsType::kUnknown; + if (hint == JsType::kFunction && + r.Chance(kArgumentsCallbackArrowChance())) { + // Callbacks: prefer short arrows over existing functions. + std::vector<std::string_view> params; + int np = + static_cast<int>(r.Range(0, kArgumentsCallbackMaxParams.AsInt())); + GenContext nested = ctx_.Nested(true, true, false, false); + for (int p = 0; p < np; p++) { + std::string_view name = ctx_.builder.FreshName("e"); + params.push_back(name); + nested.Declare(name, JsType::kUnknown); + } + CodeGen inner(nested); + args.push_back(mk::ArrowExpr(tree(), params, inner.Expression(2))); + continue; + } + args.push_back(Value(hint, 1)); + } + return args; +} + +std::vector<fast::Expression*> CodeGen::Arguments(int min_args, int max_args) { + int n = static_cast<int>(rng().Range(min_args, max_args)); + std::vector<fast::Expression*> args; + if (n > 0) { + args.reserve(static_cast<size_t>(n)); + } + for (int i = 0; i < n; i++) { + args.push_back(Value(JsType::kUnknown, 1)); + } + return args; +} + +fast::Expression* CodeGen::BuiltinCall() { + Random& r = rng(); + std::vector<const BuiltinGlobal*> candidates; + for (const BuiltinGlobal& g : env().globals()) { + if (!g.static_methods.empty() || + (g.type == JsType::kFunction && !g.constructible)) { + candidates.push_back(&g); + } + } + if (candidates.empty()) { + return Literal(); + } + const BuiltinGlobal& g = *r.Pick(candidates); + if (g.static_methods.empty() || + (g.type == JsType::kFunction && !g.constructible && r.Coin())) { + BuiltinFunction f{g.name, g.min_args, g.max_args, g.instance_type}; + return mk::Call(tree(), mk::Id(tree(), g.name), Arguments(f)); + } + const BuiltinFunction& m = r.Pick(g.static_methods); + return mk::CallMethod(tree(), mk::Id(tree(), g.name), m.name, Arguments(m)); +} + +REDLINE_TUNABLE(kMethodCallGenericChance, "codegen.method_call.generic_chance", + 0.1, 0, 1, + "probability that a method call on a value of known type uses " + "a generic Object method instead of one of the type's " + "methods"); + +fast::Expression* CodeGen::MethodCall(fast::Expression* object, JsType type) { + Random& r = rng(); + if (type == JsType::kUnknown && object->Is<Identifier>()) { + for (const redline::Variable& v : ctx_.visible) { + if (v.name == object->Cast<Identifier>()->name) { + type = v.type; + break; + } + } + } + const BuiltinType* bt = env().ForType(type); + if (bt == nullptr || bt->methods.empty() || + r.Chance(kMethodCallGenericChance())) { + // Generic object methods, or a guess. + static const BuiltinFunction kGeneric[] = { + {"toString", 0, 0, JsType::kString}, + {"valueOf", 0, 0, JsType::kUnknown}, + {"hasOwnProperty", 1, 1, JsType::kBoolean, {JsType::kString}}, + {"isPrototypeOf", 1, 1, JsType::kBoolean, {JsType::kObject}}, + {"propertyIsEnumerable", 1, 1, JsType::kBoolean, {JsType::kString}}, + {"toLocaleString", 0, 0, JsType::kString}, + }; + const BuiltinFunction& m = + kGeneric[r.Index(sizeof(kGeneric) / sizeof(kGeneric[0]))]; + return mk::CallMethod(tree(), object, m.name, Arguments(m)); + } + const BuiltinFunction& m = r.Pick(bt->methods); + return mk::CallMethod(tree(), object, m.name, Arguments(m)); +} + +REDLINE_TUNABLE(kConstructMaxUserArgs, "codegen.construct.max_user_args", 2, 0, + 16, + "most arguments passed when constructing a visible " + "user-defined class or function"); +REDLINE_TUNABLE(kConstructTypedArraySizeChance, + "codegen.construct.typed_array_size_chance", 0.7, 0, 1, + "probability that a typed array or ArrayBuffer is constructed " + "from a size rather than from a buffer or array"); + +fast::Expression* CodeGen::Construct(JsType type) { + Random& r = rng(); + std::vector<const BuiltinGlobal*> candidates; + if (type == JsType::kUnknown) { + for (const BuiltinGlobal& g : env().globals()) { + if (g.constructible) { + candidates.push_back(&g); + } + } + } else { + candidates = env().ConstructorsOf(type); + } + if (candidates.empty()) { + if (type == JsType::kUnknown || type == JsType::kObject || + type == JsType::kClass) { + if (fast::Identifier* id = Variable(JsType::kClass)) { + return mk::New(tree(), id, Arguments(0, kConstructMaxUserArgs.AsInt())); + } + if (fast::Identifier* id = Variable(JsType::kFunction)) { + return mk::New(tree(), id, Arguments(0, kConstructMaxUserArgs.AsInt())); + } + } + return nullptr; + } + const BuiltinGlobal& g = *r.Pick(candidates); + BuiltinFunction f{g.name, g.min_args, g.max_args, g.instance_type}; + // Typed arrays and ArrayBuffers take sizes; promises take executors. + if (g.instance_type == JsType::kTypedArray || + g.instance_type == JsType::kArrayBuffer) { + if (r.Chance(kConstructTypedArraySizeChance())) { + return mk::New(tree(), mk::Id(tree(), g.name), {Integer()}); + } + if (fast::Identifier* id = Variable(JsType::kArrayBuffer)) { + return mk::New(tree(), mk::Id(tree(), g.name), {id}); + } + return mk::New(tree(), mk::Id(tree(), g.name), {ArrayLiteral(1)}); + } + if (g.instance_type == JsType::kPromise) { + std::vector<std::string_view> params = {ctx_.builder.FreshName("resolve"), + ctx_.builder.FreshName("reject")}; + std::vector<Statement*> body = { + Stmt(mk::Call(tree(), mk::Id(tree(), params[r.Index(2)]), + {Value(JsType::kUnknown, 1)}))}; + return mk::New(tree(), mk::Id(tree(), g.name), + {mk::Arrow(tree(), params, std::move(body))}); + } + if (g.instance_type == JsType::kFunction && g.name == "Function") { + return mk::New(tree(), mk::Id(tree(), g.name), + {mk::Str(tree(), "a"), mk::Str(tree(), "return a")}); + } + if (g.name == "Proxy") { + return mk::New(tree(), mk::Id(tree(), g.name), + {ObjectLike(), ObjectLiteral(1)}); + } + return mk::New(tree(), mk::Id(tree(), g.name), Arguments(f)); +} + +// --- operators +// ------------------------------------------------------------------- + +// static +BinaryOp CodeGen::RandomArithmeticOp(Random& r) { + static const BinaryOp kOps[] = { + BinaryOp::kAdd, BinaryOp::kSub, + BinaryOp::kMul, BinaryOp::kDiv, + BinaryOp::kMod, BinaryOp::kExp, + BinaryOp::kBitOr, BinaryOp::kBitXor, + BinaryOp::kBitAnd, BinaryOp::kShiftLeft, + BinaryOp::kShiftRight, BinaryOp::kShiftRightLogical}; + return kOps[r.Index(sizeof(kOps) / sizeof(kOps[0]))]; +} + +// static +BinaryOp CodeGen::RandomComparisonOp(Random& r) { + static const BinaryOp kOps[] = { + BinaryOp::kEq, BinaryOp::kNotEq, BinaryOp::kStrictEq, + BinaryOp::kStrictNotEq, BinaryOp::kLessThan, BinaryOp::kLessThanEq, + BinaryOp::kGreaterThan, BinaryOp::kGreaterThanEq}; + return kOps[r.Index(sizeof(kOps) / sizeof(kOps[0]))]; +} + +REDLINE_TUNABLE(kBinaryArithmeticOpChance, + "codegen.binary.arithmetic_op_chance", 0.7, 0, 1, + "probability that a random binary operator is arithmetic " + "rather than a comparison"); + +// static +BinaryOp CodeGen::RandomBinaryOp(Random& r) { + return r.Chance(kBinaryArithmeticOpChance()) ? RandomArithmeticOp(r) + : RandomComparisonOp(r); +} + +// static +UnaryOp CodeGen::RandomUnaryOp(Random& r) { + static const UnaryOp kOps[] = {UnaryOp::kMinus, UnaryOp::kPlus, + UnaryOp::kNot, UnaryOp::kBitNot, + UnaryOp::kTypeof, UnaryOp::kVoid}; + return kOps[r.Index(sizeof(kOps) / sizeof(kOps[0]))]; +} + +// static +AssignOp CodeGen::RandomCompoundAssignOp(Random& r) { + static const AssignOp kOps[] = {AssignOp::kAddAssign, + AssignOp::kSubAssign, + AssignOp::kMulAssign, + AssignOp::kDivAssign, + AssignOp::kModAssign, + AssignOp::kExpAssign, + AssignOp::kShiftLeftAssign, + AssignOp::kShiftRightAssign, + AssignOp::kShiftRightLogicalAssign, + AssignOp::kBitOrAssign, + AssignOp::kBitXorAssign, + AssignOp::kBitAndAssign, + AssignOp::kOrAssign, + AssignOp::kAndAssign, + AssignOp::kNullishAssign}; + return kOps[r.Index(sizeof(kOps) / sizeof(kOps[0]))]; +} + +// static +LogicalOp CodeGen::RandomLogicalOp(Random& r) { + return r.Pick({LogicalOp::kAnd, LogicalOp::kOr, LogicalOp::kNullish}); +} + +REDLINE_TUNABLE(kBinaryBigintChance, "codegen.binary.bigint_chance", 0.1, 0, 1, + "probability that a binary arithmetic operation is on BigInts"); +REDLINE_TUNABLE(kBinaryMixedTypeChance, "codegen.binary.mixed_type_chance", + 0.15, 0, 1, + "probability that a binary arithmetic operation takes operands " + "of arbitrary type"); + +fast::Expression* CodeGen::BinaryOperation(int depth) { + Random& r = rng(); + BinaryOp op = RandomArithmeticOp(r); + JsType type = + r.Chance(kBinaryBigintChance()) ? JsType::kBigInt : JsType::kNumber; + if (r.Chance(kBinaryMixedTypeChance())) { + type = JsType::kUnknown; // mixed-type arithmetic + } + fast::Expression* left = Value(type, depth); + fast::Expression* right = Value(type, depth); + // `-a ** b` is a syntax error; the printer parenthesizes unary operands, + // but avoid the pattern anyway. + if (op == BinaryOp::kExp && left->Is<UnaryExpression>()) { + op = BinaryOp::kMul; + } + return mk::Binary(tree(), op, left, right); +} + +fast::Expression* CodeGen::Comparison(int depth) { + Random& r = rng(); + JsType type = r.Coin() ? JsType::kNumber : JsType::kUnknown; + fast::Expression* left = Value(type, depth); + fast::Expression* right = Value(type, depth); + return mk::Binary(tree(), RandomComparisonOp(r), left, right); +} + +REDLINE_TUNABLE(kUnaryDeleteChance, "codegen.unary.delete_chance", 0.1, 0, 1, + "probability that a unary operation is a property delete"); +REDLINE_TUNABLE(kUnaryUpdateChance, "codegen.unary.update_chance", 0.3, 0, 1, + "probability that a unary operation is ++ or -- on a mutable " + "number variable"); + +fast::Expression* CodeGen::UnaryOperation(int depth) { + Random& r = rng(); + UnaryOp op = RandomUnaryOp(r); + if (r.Chance(kUnaryDeleteChance())) { + // delete obj.prop + return mk::Unary(tree(), UnaryOp::kDelete, Property(ObjectLike())); + } + if (r.Chance(kUnaryUpdateChance())) { + if (fast::Identifier* id = MutableVariable(JsType::kNumber)) { + return mk::Update(tree(), + r.Coin() ? UpdateOp::kIncrement : UpdateOp::kDecrement, + r.Coin(), id); + } + } + JsType type = op == UnaryOp::kNot ? JsType::kUnknown : JsType::kNumber; + return mk::Unary(tree(), op, Value(type, depth)); +} + +fast::Expression* CodeGen::Condition(int depth) { + Random& r = rng(); + switch (r.Index(6)) { + case 0: + case 1: + return Comparison(depth); + case 2: + if (fast::Identifier* id = Variable(JsType::kBoolean)) { + return id; + } + return Comparison(depth); + case 3: + return mk::Unary(tree(), UnaryOp::kNot, Value(JsType::kUnknown, depth)); + case 4: { + fast::Expression* object = ObjectLike(); + return mk::Binary(tree(), BinaryOp::kIn, mk::Str(tree(), PropertyName()), + object); + } + default: + return Value(JsType::kUnknown, depth); + } +} + +// --- statements +// ------------------------------------------------------------------ + +std::vector<fast::Statement*> CodeGen::DeclareGuarded(fast::Expression* init, + JsType type, + std::string_view prefix) { + std::string_view name = ctx_.builder.FreshName(prefix); + std::vector<fast::Statement*> out; + out.push_back(mk::Let(tree(), name, nullptr)); + out.push_back(mk::Try( + tree(), + {mk::ExprStmt(tree(), mk::Assign(tree(), mk::Id(tree(), name), init))}, + "e", {})); + ctx_.Declare(name, type); + return out; +} + +void CodeGen::DeclareMaybeGuarded(std::vector<fast::Statement*>* out, + fast::Expression* init, JsType type, + std::string_view prefix, + double guard_probability) { + if (rng().Chance(guard_probability)) { + for (fast::Statement* s : DeclareGuarded(init, type, prefix)) { + out->push_back(s); + } + } else { + out->push_back(Declare(init, type, prefix)); + } +} + +fast::Statement* CodeGen::Declare(fast::Expression* init, JsType type, + std::string_view prefix) { + Random& r = rng(); + std::string_view name = ctx_.builder.FreshName(prefix); + VariableKind kind = VariableKind::kLet; + switch (r.Index(10)) { + case 0: + case 1: + kind = VariableKind::kConst; + break; + case 2: + kind = VariableKind::kVar; + break; + default: + break; + } + ctx_.Declare(name, type, kind == VariableKind::kConst); + return mk::Declare(tree(), kind, name, init); +} + +std::vector<fast::Statement*> CodeGen::Body(GenContext& nested, int count) { + std::vector<Statement*> body; + if (nested.depth > nested.max_depth) { + return body; + } + nested.out = &body; + ctx_.generators.Generate(nested, count, &body); + nested.out = nullptr; + return body; +} + +REDLINE_TUNABLE(kCallSpreadChance, "codegen.call.spread_chance", 0.05, 0, 1, + "probability that a call appends a spread of a visible array " + "variable to its arguments"); + +fast::CallExpression* CodeGen::CallWithArguments(fast::Expression* callee, + int max_args) { + std::vector<fast::Expression*> args = Arguments(0, max_args); + if (rng().Chance(kCallSpreadChance())) { + if (fast::Identifier* id = Variable(JsType::kArray)) { + args.push_back(mk::Spread(tree(), id)); + } + } + return mk::Call(tree(), callee, std::move(args)); +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/generators/codegen.h b/deps/v8/experimental/redline/generators/codegen.h new file mode 100644 index 000000000000..efd9db668fb6 --- /dev/null +++ b/deps/v8/experimental/redline/generators/codegen.h @@ -0,0 +1,125 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_GENERATORS_CODEGEN_H_ +#define V8_EXPERIMENTAL_REDLINE_GENERATORS_CODEGEN_H_ + +#include <string_view> +#include <vector> + +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/generators/generator.h" + +namespace redline { + +// Expression and small-statement synthesis shared by all generators and by +// the expression-level mutators. Everything is typed only by the coarse +// JsType guesses; the V8 parser remains the validity oracle. +class CodeGen { + public: + explicit CodeGen(GenContext& ctx) : ctx_(ctx) {} + + GenContext& ctx() { return ctx_; } + fast::Tree* tree() { return ctx_.tree(); } + Random& rng() { return ctx_.rng(); } + const Environment& env() { return ctx_.env; } + + // --- leaves ---------------------------------------------------------------- + + fast::Expression* Literal(JsType type = JsType::kUnknown); + fast::Expression* Integer(); // small or interesting integer + fast::Expression* Number(); + fast::Expression* String(); + fast::Expression* Boolean(); + fast::Expression* BigInt(); + fast::Expression* RegExp(); + fast::Expression* Nullish(); + + // A visible variable of `type` (kUnknown = any), or nullptr. + fast::Identifier* Variable(JsType type = JsType::kUnknown); + // A visible variable that may be assigned to, or nullptr. + fast::Identifier* MutableVariable(JsType type = JsType::kUnknown); + bool HasVariable(JsType type = JsType::kUnknown); + + // --- composite values ------------------------------------------------------ + + // A value of (roughly) `type`: variable, literal or a small expression. + fast::Expression* Value(JsType type = JsType::kUnknown, int depth = 0); + // Any expression, possibly nested (depth-limited). + fast::Expression* Expression(int depth = 0); + fast::Expression* ObjectLiteral(int depth = 0); + fast::Expression* ArrayLiteral(int depth = 0); + // A function or arrow expression with a generated body. + fast::Expression* FunctionValue(int depth = 0); + // Something callable: a function variable, a builtin function or a new + // arrow function. + fast::Expression* Callable(); + // Something with properties: an object-ish variable or a literal. + fast::Expression* ObjectLike(); + // An assignment target: a mutable variable or a member of an object. + fast::Expression* Target(); + // `object.name` or `object[expr]` depending on the name. + fast::Expression* Property(fast::Expression* object, std::string_view name); + fast::Expression* Property(fast::Expression* object); // random name + std::string_view PropertyName(); + // Random key expression for computed access: string, number, symbol. + fast::Expression* Key(); + + // Arguments for a builtin function (respecting its arity and hints). + std::vector<fast::Expression*> Arguments(const BuiltinFunction& function); + std::vector<fast::Expression*> Arguments(int min_args, int max_args); + + // Builtin calls. + fast::Expression* BuiltinCall(); // Math.max(..) etc. + fast::Expression* MethodCall(fast::Expression* object, JsType type); + fast::Expression* Construct(JsType type = JsType::kUnknown); // new X(..) + + // Operators. + fast::Expression* BinaryOperation(int depth = 0); + fast::Expression* Comparison(int depth = 0); + fast::Expression* UnaryOperation(int depth = 0); + fast::Expression* Condition(int depth = 0); // boolean-ish expression + + // --- statements ------------------------------------------------------------ + + // `let/const/var name = init;` registering the new variable. + fast::Statement* Declare(fast::Expression* init, JsType type, + std::string_view prefix = "v"); + // `let name; try { name = init; } catch (e) {}` registering the new + // variable: for calls whose signature is unknown (discovered APIs, + // methods applied to foreign receivers), where an exception would + // otherwise end the program. `name` is undefined if `init` threw. + std::vector<fast::Statement*> DeclareGuarded(fast::Expression* init, + JsType type, + std::string_view prefix = "v"); + // Declare() or DeclareGuarded() with the given probability of guarding. + void DeclareMaybeGuarded(std::vector<fast::Statement*>* out, + fast::Expression* init, JsType type, + std::string_view prefix, double guard_probability); + // Statements for a nested body (function/loop), via the generator set. + std::vector<fast::Statement*> Body(GenContext& nested, int count); + // A call of `callee` with random arguments. + fast::CallExpression* CallWithArguments(fast::Expression* callee, + int max_args = 3); + // Wraps an expression in a statement. + fast::Statement* Stmt(fast::Expression* e) { return mk::ExprStmt(tree(), e); } + + // Operator tables. + static fast::BinaryOp RandomArithmeticOp(Random& rng); + static fast::BinaryOp RandomComparisonOp(Random& rng); + static fast::BinaryOp RandomBinaryOp(Random& rng); + static fast::UnaryOp RandomUnaryOp(Random& rng); + static fast::AssignOp RandomCompoundAssignOp(Random& rng); + static fast::LogicalOp RandomLogicalOp(Random& rng); + + private: + GenContext& ctx_; +}; + +// True for names usable as `obj.name` without quoting. +bool IsIdentifierName(std::string_view name); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_GENERATORS_CODEGEN_H_ diff --git a/deps/v8/experimental/redline/generators/generator.h b/deps/v8/experimental/redline/generators/generator.h new file mode 100644 index 000000000000..606476332365 --- /dev/null +++ b/deps/v8/experimental/redline/generators/generator.h @@ -0,0 +1,158 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_GENERATORS_GENERATOR_H_ +#define V8_EXPERIMENTAL_REDLINE_GENERATORS_GENERATOR_H_ + +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/core/builder.h" +#include "experimental/redline/core/component.h" +#include "experimental/redline/core/environment.h" +#include "experimental/redline/core/selection.h" + +namespace redline { + +class GeneratorSet; + +// Everything a generator needs to know about the place it generates code +// for. Generated statements are collected by the caller and inserted at +// `slot` in one go; `visible` is extended by generators that declare new +// variables so that later generators in the same session can use them. +struct GenContext { + GenContext(Builder& b, const GeneratorSet& g, const Environment& e) + : builder(b), generators(g), env(e) {} + + Builder& builder; + const GeneratorSet& generators; + const Environment& env; + Builder::Slot slot; + Builder::Context syntax; + std::vector<Variable> visible; // innermost first + int depth = 0; // nesting depth of generated code + int max_depth = 3; + // Statements generated by this session so far (for generators that want + // to refer to something they just created). + std::vector<fast::Statement*>* out = nullptr; + + fast::Tree* tree() { return builder.tree(); } + Random& rng() { return builder.rng(); } + + // Registers a variable created by generated code. + void Declare(std::string_view name, JsType type, bool is_constant = false) { + visible.insert(visible.begin(), Variable{name, type, nullptr, is_constant}); + } + // A context for code nested inside a function-like node generated at + // this position. + GenContext Nested(bool is_function, bool is_arrow, bool is_async, + bool is_generator) const; + // A context for a loop/switch/block body at this position. + GenContext Inner(bool in_loop, bool in_switch) const; +}; + +// Requirements a generator has on the syntactic context. +enum GenRequirement : uint32_t { + kNoRequirement = 0, + kNeedsFunction = 1u << 0, // emits `return` + kNeedsAsync = 1u << 1, // emits `await` + kNeedsGenerator = 1u << 2, // emits `yield` + kNeedsLoop = 1u << 3, // emits `continue` + kNeedsBreak = 1u << 4, // emits `break` + kNeedsSloppy = 1u << 5, // emits sloppy-only syntax (`with`) + kNeedsArguments = 1u << 6, // uses `arguments` + kNeedsThis = 1u << 7, // uses `this` meaningfully + kRecursive = 1u << 8, // generates nested code (depth-limited) +}; + +class Generator : public Component { + public: + Generator(std::string name, std::string_view description, double weight, + uint32_t requirements) + : Component(std::move(name)), + description_(description), + weight_(weight), + requirements_(requirements) {} + + std::string_view description() const override { return description_; } + double weight() const { return weight_; } + uint32_t requirements() const { return requirements_; } + bool Applicable(const GenContext& ctx) const; + + // Appends zero or more statements to `out`. Returns false if nothing + // suitable could be generated here. + virtual bool Generate(GenContext& ctx, + std::vector<fast::Statement*>* out) = 0; + + private: + std::string_view description_; + double weight_; + uint32_t requirements_; +}; + +// All generators, and the strategy that picks among them (core/selection.h). +// CreateDefault() installs the built-in generators with the default +// `weighted` strategy; a fuzzing session replaces the strategy with the +// configured one through SetSelector(). +class GeneratorSet { + public: + // All built-in generators with default weights. + static std::unique_ptr<GeneratorSet> CreateDefault(); + + const std::vector<std::unique_ptr<Generator>>& all() const { + return generators_; + } + // The same generators as plain pointers, in the same order: what the + // selector sees. + const std::vector<Generator*>& candidates() const { return candidates_; } + Generator* Find(std::string_view name) const; + std::vector<std::string> Names() const; + + // Installs a selection strategy and initializes it with the generators + // (weight names are validated here). Returns false with *error set. + bool SetSelector(std::unique_ptr<Selector<Generator>> selector, + std::string* error); + Selector<Generator>& selector() const { return *selector_; } + // Shorthands for the strategy's static weights (0 disables a generator). + bool SetWeight(std::string_view name, double weight) { + return selector_->SetWeight(name, weight); + } + double WeightOf(const Generator* generator) const { + return selector_->WeightOf(*generator); + } + + // Picks an applicable generator with the strategy, or nullptr. + Generator* Pick(const GenContext& ctx) const; + // Generates roughly `count` statements at ctx.slot, appending them to + // `out`. Returns the number of generator invocations that produced code. + int Generate(GenContext& ctx, int count, + std::vector<fast::Statement*>* out) const; + + std::vector<const Component*> Components() const; + + private: + std::vector<std::unique_ptr<Generator>> generators_; + std::vector<Generator*> candidates_; + std::unique_ptr<Selector<Generator>> selector_; +}; + +// A generation context for inserting statements at `slot`: syntactic +// context and visible variables are computed from the builder. +GenContext MakeGenContext(Builder& builder, const Builder::Slot& slot, + const GeneratorSet& generators, + const Environment& env); + +// The generators that produced output on this thread since the last +// BeginGeneratorUsage() (deduplicated). The engine credits them with the +// execution of the mutation result and with its coverage, which feeds the +// "adaptive" generator strategy. +void BeginGeneratorUsage(); +void NoteGeneratorUsed(Generator* generator); +std::vector<Generator*> GeneratorsUsed(); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_GENERATORS_GENERATOR_H_ diff --git a/deps/v8/experimental/redline/generators/generators.cc b/deps/v8/experimental/redline/generators/generators.cc new file mode 100644 index 000000000000..5f3d856a5207 --- /dev/null +++ b/deps/v8/experimental/redline/generators/generators.cc @@ -0,0 +1,4776 @@ +// Copyright 2026 the V8 project 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 <algorithm> +#include <string> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/core/adaptive_selector.h" +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/core/weighted_selector.h" +#include "experimental/redline/generators/codegen.h" +#include "experimental/redline/generators/generator.h" +#include "experimental/redline/generators/wasm_module.h" + +namespace redline { + +using namespace fast; // NOLINT(build/namespaces) + +bool Generator::Applicable(const GenContext& ctx) const { + const Builder::Context& s = ctx.syntax; + if ((requirements_ & kNeedsFunction) && + (!s.in_function || s.in_static_block || s.in_class_field)) { + return false; + } + if ((requirements_ & kNeedsAsync) && (!s.in_async || s.in_static_block)) { + return false; + } + if ((requirements_ & kNeedsGenerator) && !s.in_generator) { + return false; + } + if ((requirements_ & kNeedsLoop) && !s.in_loop) { + return false; + } + if ((requirements_ & kNeedsBreak) && !s.break_allowed()) { + return false; + } + if ((requirements_ & kNeedsSloppy) && s.strict) { + return false; + } + if ((requirements_ & kNeedsArguments) && !s.has_arguments) { + return false; + } + if ((requirements_ & kNeedsThis) && !s.has_this) { + return false; + } + if ((requirements_ & kRecursive) && ctx.depth >= ctx.max_depth) { + return false; + } + return true; +} + +namespace { + +using Statements = std::vector<Statement*>; +using GenFn = bool (*)(GenContext& ctx, CodeGen& cg, Statements* out); + +class FnGenerator final : public Generator { + public: + FnGenerator(std::string name, std::string_view description, double weight, + uint32_t requirements, GenFn fn) + : Generator(std::move(name), description, weight, requirements), + fn_(fn) {} + + bool Generate(GenContext& ctx, Statements* out) override { + CodeGen cg(ctx); + return fn_(ctx, cg, out); + } + + private: + GenFn fn_; +}; + +// Generators share one signature; not every generator needs every argument. +#define GEN(name) \ + bool Gen##name([[maybe_unused]] GenContext& ctx, \ + [[maybe_unused]] CodeGen& cg, Statements* out) + +// Shorthands. +Tree* T(GenContext& ctx) { return ctx.tree(); } + +Statement* Push(Statements* out, Statement* s) { + out->push_back(s); + return s; +} + +// A loop counter bound that is small most of the time. +double LoopCount(Random& r) { + // Mostly small: a handful of iterations is enough to warm up feedback, + // and %OptimizeOsr()/%OptimizeFunctionOnNextCall() replace long warm-up + // loops (which only cost time and timeouts). + static const double kCounts[] = {1, 2, 3, 3, 4, 5, 5, 8, + 10, 10, 16, 20, 32, 100, 1000}; + return kCounts[r.Index(sizeof(kCounts) / sizeof(kCounts[0]))]; +} + +REDLINE_TUNABLE(kInnerBodyMaxStatements, "generators.InnerBody.max_statements", + 3, 1, 64, + "most statements in a nested if/try body unless the generator " + "asks for another bound"); + +// A nested body for a loop/if/try at this position. +Statements InnerBody(GenContext& ctx, CodeGen& cg, bool in_loop, bool in_switch, + int max_statements = kInnerBodyMaxStatements.AsInt()) { + GenContext inner = ctx.Inner(in_loop, in_switch); + return cg.Body(inner, 1 + ctx.rng().SmallCount(max_statements - 1)); +} + +// --- value declarations +// --------------------------------------------------------- + +GEN(WasmModule) { + WasmModule m = RandomWasmModule(ctx.rng()); + + // Create Uint8Array with the bytes + std::vector<Expression*> byte_exprs; + byte_exprs.reserve(m.bytes.size()); + for (uint8_t b : m.bytes) { + byte_exprs.push_back(mk::Num(T(ctx), b)); + } + Expression* arr = mk::Array(T(ctx), byte_exprs); + Expression* typed_arr = mk::New(T(ctx), mk::Id(T(ctx), "Uint8Array"), {arr}); + + std::string_view bytes_name = ctx.builder.FreshName("bytes"); + Statement* bytes_decl = mk::Const(T(ctx), bytes_name, typed_arr); + Push(out, bytes_decl); + ctx.Declare(bytes_name, JsType::kObject, true); + + // Create import object {m: {f0: ..., f1: ...}} + std::vector<Node*> m_props; + for (size_t i = 0; i < m.imports.size(); i++) { + Expression* func_expr = cg.Callable(); + if (!func_expr) { + func_expr = mk::ArrowExpr(T(ctx), {}, mk::Num(T(ctx), 0)); + } + std::string fname = "f" + std::to_string(i); + m_props.push_back(mk::Prop(T(ctx), fname, func_expr)); + } + Expression* m_obj = mk::Object(T(ctx), m_props); + Expression* import_obj = mk::Object(T(ctx), {mk::Prop(T(ctx), "m", m_obj)}); + + // new WebAssembly.Module(bytes) + Expression* module_expr = mk::New( + T(ctx), mk::Member(T(ctx), mk::Id(T(ctx), "WebAssembly"), "Module"), + {mk::Id(T(ctx), bytes_name)}); + + std::string_view module_name = ctx.builder.FreshName("module"); + Statement* module_decl = mk::Const(T(ctx), module_name, module_expr); + Push(out, module_decl); + ctx.Declare(module_name, JsType::kObject, true); + + // new WebAssembly.Instance(module, import_obj) + Expression* instance_expr = mk::New( + T(ctx), mk::Member(T(ctx), mk::Id(T(ctx), "WebAssembly"), "Instance"), + {mk::Id(T(ctx), module_name), import_obj}); + std::string_view instance_name = ctx.builder.FreshName("instance"); + Statement* instance_decl = mk::Const(T(ctx), instance_name, instance_expr); + Push(out, instance_decl); + ctx.Declare(instance_name, JsType::kObject, true); + + // exports = instance.exports + Expression* exports_expr = + mk::Member(T(ctx), mk::Id(T(ctx), instance_name), "exports"); + std::string_view exports_name = ctx.builder.FreshName("exports"); + Statement* exports_decl = mk::Const(T(ctx), exports_name, exports_expr); + Push(out, exports_decl); + ctx.Declare(exports_name, JsType::kObject, true); + + // exported functions + for (size_t i = 0; i < m.functions.size(); i++) { + std::string ename = "e" + std::to_string(i); + Expression* func_load = + mk::Member(T(ctx), mk::Id(T(ctx), exports_name), ename); + std::string_view func_name = ctx.builder.FreshName("f"); + Statement* func_decl = mk::Const(T(ctx), func_name, func_load); + Push(out, func_decl); + ctx.Declare(func_name, JsType::kFunction, true); + + // Call it 1-3 times + int calls = 1 + static_cast<int>(ctx.rng().Index(3)); + for (int c = 0; c < calls; ++c) { + std::vector<Expression*> args; + for (auto t : m.functions[i].params) { + if (t == WasmType::kI64) { + args.push_back( + mk::BigInt(T(ctx), std::to_string(ctx.rng().Range(0, 100)))); + } else { + args.push_back(mk::Num(T(ctx), ctx.rng().Double() * 100)); + } + } + Expression* call_expr = mk::Call(T(ctx), mk::Id(T(ctx), func_name), args); + Push(out, cg.Stmt(call_expr)); + } + } + + if (m.memory) { + Expression* mem_load = + mk::Member(T(ctx), mk::Id(T(ctx), exports_name), "mem"); + std::string_view mem_name = ctx.builder.FreshName("mem"); + Statement* mem_decl = mk::Const(T(ctx), mem_name, mem_load); + Push(out, mem_decl); + ctx.Declare(mem_name, JsType::kObject, true); + + if (ctx.rng().Coin()) { + Expression* buf_load = + mk::Member(T(ctx), mk::Id(T(ctx), mem_name), "buffer"); + Expression* view_expr = + mk::New(T(ctx), mk::Id(T(ctx), "Uint8Array"), {buf_load}); + std::string_view view_name = ctx.builder.FreshName("view"); + Statement* view_decl = mk::Const(T(ctx), view_name, view_expr); + Push(out, view_decl); + ctx.Declare(view_name, JsType::kTypedArray, true); + } else { + Expression* grow_call = mk::CallMethod(T(ctx), mk::Id(T(ctx), mem_name), + "grow", {mk::Num(T(ctx), 1)}); + Push(out, cg.Stmt(grow_call)); + } + } + + if (m.table) { + Expression* tab_load = + mk::Member(T(ctx), mk::Id(T(ctx), exports_name), "tab"); + std::string_view tab_name = ctx.builder.FreshName("tab"); + Statement* tab_decl = mk::Const(T(ctx), tab_name, tab_load); + Push(out, tab_decl); + ctx.Declare(tab_name, JsType::kObject, true); + + if (ctx.rng().Coin()) { + Expression* get_call = mk::CallMethod(T(ctx), mk::Id(T(ctx), tab_name), + "get", {mk::Num(T(ctx), 0)}); + Push(out, cg.Stmt(get_call)); + } else { + Expression* len_load = + mk::Member(T(ctx), mk::Id(T(ctx), tab_name), "length"); + Push(out, cg.Stmt(len_load)); + } + } + + int g_idx = 0; + for (auto t : m.globals) { + std::string gname = "g" + std::to_string(g_idx++); + Expression* glob_load = + mk::Member(T(ctx), mk::Id(T(ctx), exports_name), gname); + std::string_view glob_name = ctx.builder.FreshName("g"); + Statement* glob_decl = mk::Const(T(ctx), glob_name, glob_load); + Push(out, glob_decl); + ctx.Declare(glob_name, JsType::kObject, true); + + if (ctx.rng().Coin()) { + Expression* val_load = + mk::Member(T(ctx), mk::Id(T(ctx), glob_name), "value"); + Push(out, cg.Stmt(val_load)); + } else { + Expression* val_store = mk::Assign( + T(ctx), mk::Member(T(ctx), mk::Id(T(ctx), glob_name), "value"), + (t == WasmType::kI64) + ? static_cast<Expression*>(mk::BigInt(T(ctx), "42")) + : static_cast<Expression*>(mk::Num(T(ctx), 42))); + Push(out, cg.Stmt(val_store)); + } + } + + return true; +} + +GEN(IntegerDecl) { + Push(out, cg.Declare(cg.Integer(), JsType::kNumber)); + return true; +} + +REDLINE_TUNABLE(kFloatDeclInterestingChance, + "generators.FloatDecl.interesting_chance", 0.5, 0, 1, + "probability that the number is one of the environment's " + "interesting values rather than a fresh literal"); + +GEN(FloatDecl) { + Random& r = ctx.rng(); + Expression* v = r.Chance(kFloatDeclInterestingChance()) + ? mk::Num(T(ctx), r.Pick(ctx.env.numbers())) + : cg.Number(); + Push(out, cg.Declare(v, JsType::kNumber)); + return true; +} + +GEN(StringDecl) { + Push(out, cg.Declare(cg.String(), JsType::kString, "s")); + return true; +} + +GEN(BooleanDecl) { + Push(out, cg.Declare(cg.Boolean(), JsType::kBoolean, "b")); + return true; +} + +GEN(BigIntDecl) { + Push(out, cg.Declare(cg.BigInt(), JsType::kBigInt, "n")); + return true; +} + +GEN(RegExpDecl) { + Push(out, cg.Declare(cg.RegExp(), JsType::kRegExp, "re")); + return true; +} + +GEN(NullishDecl) { + Push(out, cg.Declare(cg.Nullish(), JsType::kNullish)); + return true; +} + +GEN(SymbolDecl) { + Random& r = ctx.rng(); + Expression* v = nullptr; + if (r.Coin()) { + v = mk::Call(T(ctx), mk::Id(T(ctx), "Symbol"), {cg.String()}); + } else { + v = mk::Member(T(ctx), mk::Id(T(ctx), "Symbol"), + r.Pick({"iterator", "toPrimitive", "hasInstance", "species", + "toStringTag", "asyncIterator"})); + } + Push(out, cg.Declare(v, JsType::kSymbol, "sym")); + return true; +} + +GEN(ArrayDecl) { + Push(out, cg.Declare(cg.ArrayLiteral(0), JsType::kArray, "arr")); + return true; +} + +GEN(ObjectDecl) { + Push(out, cg.Declare(cg.ObjectLiteral(0), JsType::kObject, "obj")); + return true; +} + +GEN(ConstructDecl) { + Random& r = ctx.rng(); + std::vector<const BuiltinGlobal*> ctors; + for (const BuiltinGlobal& g : ctx.env.globals()) { + if (g.constructible) { + ctors.push_back(&g); + } + } + if (ctors.empty()) { + return false; + } + const BuiltinGlobal& g = *r.Pick(ctors); + Expression* v = cg.Construct(g.instance_type); + if (v == nullptr) { + return false; + } + Push(out, cg.Declare(v, g.instance_type, "o")); + return true; +} + +GEN(TypedArrayDecl) { + Expression* v = cg.Construct(JsType::kTypedArray); + if (v == nullptr) { + return false; + } + Push(out, cg.Declare(v, JsType::kTypedArray, "ta")); + return true; +} + +GEN(ComputedDecl) { + Expression* v = cg.Expression(0); + Push(out, cg.Declare(v, Builder::GuessType(v))); + return true; +} + +REDLINE_TUNABLE(kTemplateDeclMinSubstitutions, + "generators.TemplateDecl.min_substitutions", 1, 0, 64, + "fewest ${...} substitutions in the template literal"); +REDLINE_TUNABLE(kTemplateDeclMaxSubstitutions, + "generators.TemplateDecl.max_substitutions", 3, 1, 64, + "most ${...} substitutions in the template literal"); + +REDLINE_TUNABLE(kTemplateDeclTaggedChance, + "generators.TemplateDecl.tagged_chance", 0.2, 0, 1, + "probability that the template is tagged (tag`...`) with a " + "function variable or String.raw"); + +GEN(TemplateDecl) { + Random& r = ctx.rng(); + std::vector<std::string_view> strings; + std::vector<Expression*> expressions; + int n = static_cast<int>(r.Range(kTemplateDeclMinSubstitutions.AsInt(), + kTemplateDeclMaxSubstitutions.AsInt())); + static const char* const kParts[] = {"", "a", "b", " ", + "foo", "x=", ", ", "!"}; + for (int i = 0; i < n; i++) { + strings.emplace_back(kParts[r.Index(sizeof(kParts) / sizeof(kParts[0]))]); + expressions.push_back(cg.Value(JsType::kUnknown, 1)); + } + strings.emplace_back(kParts[r.Index(sizeof(kParts) / sizeof(kParts[0]))]); + TemplateLiteral* literal = + mk::Template(T(ctx), std::move(strings), std::move(expressions)); + if (r.Chance(kTemplateDeclTaggedChance())) { + // The tag gets the array of strings and the substituted values. + Expression* tag = cg.Variable(JsType::kFunction); + if (tag == nullptr) { + tag = mk::Member(T(ctx), mk::Id(T(ctx), "String"), "raw"); + } + TaggedTemplateExpression* tagged = T(ctx)->New<TaggedTemplateExpression>(); + tagged->tag = tag; + tagged->quasi = literal; + Push(out, cg.Declare(tagged, JsType::kUnknown, "s")); + return true; + } + Push(out, cg.Declare(literal, JsType::kString, "s")); + return true; +} + +REDLINE_TUNABLE(kDestructuringMinProperties, + "generators.Destructuring.min_properties", 1, 0, 64, + "fewest properties in an object destructuring pattern"); +REDLINE_TUNABLE(kDestructuringMaxProperties, + "generators.Destructuring.max_properties", 3, 1, 64, + "most properties in an object destructuring pattern"); +REDLINE_TUNABLE(kDestructuringMinElements, + "generators.Destructuring.min_elements", 1, 0, 64, + "fewest elements in an array destructuring pattern"); +REDLINE_TUNABLE(kDestructuringMaxElements, + "generators.Destructuring.max_elements", 4, 1, 64, + "most elements in an array destructuring pattern"); +REDLINE_TUNABLE(kDestructuringDefaultChance, + "generators.Destructuring.default_chance", 0.3, 0, 1, + "probability that a destructured binding gets a default value"); +REDLINE_TUNABLE(kDestructuringRestChance, + "generators.Destructuring.rest_chance", 0.3, 0, 1, + "probability that the pattern ends with a ...rest element"); +REDLINE_TUNABLE(kDestructuringHoleChance, + "generators.Destructuring.hole_chance", 0.15, 0, 1, + "probability that an array pattern element is a hole"); + +GEN(Destructuring) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + if (r.Coin()) { + // let {a, b: v1, ...rest} = obj; + Expression* source = cg.ObjectLike(); + ObjectPattern* pattern = t->New<ObjectPattern>(); + int n = static_cast<int>(r.Range(kDestructuringMinProperties.AsInt(), + kDestructuringMaxProperties.AsInt())); + for (int i = 0; i < n; i++) { + std::string_view key = cg.PropertyName(); + if (!IsIdentifierName(key)) { + key = "a"; + } + std::string_view name = ctx.builder.FreshName("d"); + Property* p = mk::Prop(t, key, mk::Id(t, name)); + if (r.Chance(kDestructuringDefaultChance())) { + AssignmentPattern* ap = t->New<AssignmentPattern>(); + ap->left = mk::Id(t, name); + ap->right = cg.Value(JsType::kUnknown, 1); + p->value = ap; + } + pattern->properties.push_back(p); + ctx.Declare(name, JsType::kUnknown); + } + if (r.Chance(kDestructuringRestChance())) { + RestElement* rest = t->New<RestElement>(); + std::string_view name = ctx.builder.FreshName("rest"); + rest->argument = mk::Id(t, name); + pattern->properties.push_back(rest); + ctx.Declare(name, JsType::kObject); + } + VariableDeclaration* decl = mk::Let(t, "x", source); + decl->declarations[0]->target = pattern; + Push(out, decl); + } else { + // let [a, , b = 1, ...rest] = arr; + Expression* source = nullptr; + if (Identifier* id = cg.Variable(JsType::kArray)) { + source = id; + } else if (Identifier* id2 = cg.Variable(JsType::kString)) { + source = id2; + } else { + source = cg.ArrayLiteral(1); + } + ArrayPattern* pattern = t->New<ArrayPattern>(); + int n = static_cast<int>(r.Range(kDestructuringMinElements.AsInt(), + kDestructuringMaxElements.AsInt())); + for (int i = 0; i < n; i++) { + if (r.Chance(kDestructuringHoleChance())) { + pattern->elements.push_back(nullptr); + continue; + } + std::string_view name = ctx.builder.FreshName("d"); + if (r.Chance(kDestructuringDefaultChance())) { + AssignmentPattern* ap = t->New<AssignmentPattern>(); + ap->left = mk::Id(t, name); + ap->right = cg.Value(JsType::kUnknown, 1); + pattern->elements.push_back(ap); + } else { + pattern->elements.push_back(mk::Id(t, name)); + } + ctx.Declare(name, JsType::kUnknown); + } + if (r.Chance(kDestructuringRestChance())) { + RestElement* rest = t->New<RestElement>(); + std::string_view name = ctx.builder.FreshName("rest"); + rest->argument = mk::Id(t, name); + pattern->elements.push_back(rest); + ctx.Declare(name, JsType::kArray); + } + VariableDeclaration* decl = mk::Let(t, "x", source); + decl->declarations[0]->target = pattern; + Push(out, decl); + } + return true; +} + +// --- functions and classes +// ------------------------------------------------------ + +REDLINE_TUNABLE(kFunctionDeclMaxParams, "generators.FunctionDecl.max_params", 3, + 0, 16, "most parameters of the function"); +REDLINE_TUNABLE(kFunctionDeclAsyncChance, + "generators.FunctionDecl.async_chance", 0.1, 0, 1, + "probability that the function is async"); +REDLINE_TUNABLE(kFunctionDeclGeneratorChance, + "generators.FunctionDecl.generator_chance", 0.08, 0, 1, + "probability that the function is a generator"); +REDLINE_TUNABLE( + kFunctionDeclMaxStatements, "generators.FunctionDecl.max_statements", 5, 1, + 64, "most statements in the function body before the optional return"); +REDLINE_TUNABLE(kFunctionDeclReturnChance, + "generators.FunctionDecl.return_chance", 0.8, 0, 1, + "probability that the body ends with a return of a value"); +REDLINE_TUNABLE( + kFunctionDeclCallChance, "generators.FunctionDecl.call_chance", 0.7, 0, 1, + "probability that the function is called right after its declaration"); +REDLINE_TUNABLE(kFunctionDeclMaxCalls, "generators.FunctionDecl.max_calls", 3, + 1, 64, "most calls emitted right after the declaration"); + +GEN(FunctionDecl) { + Random& r = ctx.rng(); + std::string_view name = ctx.builder.FreshName("f"); + std::vector<std::string_view> params; + int n = static_cast<int>(r.Range(0, kFunctionDeclMaxParams.AsInt())); + bool is_async = r.Chance(kFunctionDeclAsyncChance()); + bool is_generator = r.Chance(kFunctionDeclGeneratorChance()); + GenContext nested = ctx.Nested(true, false, is_async, is_generator); + // The function may call itself. + nested.Declare(name, JsType::kFunction); + for (int i = 0; i < n; i++) { + std::string_view p = ctx.builder.FreshName("a"); + params.push_back(p); + nested.Declare(p, JsType::kUnknown); + } + CodeGen inner(nested); + Statements body = inner.Body( + nested, 1 + r.SmallCount(kFunctionDeclMaxStatements.AsInt() - 1)); + if (r.Chance(kFunctionDeclReturnChance())) { + body.push_back(mk::Return(T(ctx), inner.Value(JsType::kUnknown, 1))); + } + Push(out, mk::FunctionDecl(T(ctx), name, params, std::move(body), is_async, + is_generator)); + ctx.Declare(name, JsType::kFunction); + // Use it right away most of the time. + if (r.Chance(kFunctionDeclCallChance())) { + int calls = 1 + r.SmallCount(kFunctionDeclMaxCalls.AsInt() - 1); + for (int i = 0; i < calls; i++) { + Push(out, cg.Stmt(cg.CallWithArguments(mk::Id(T(ctx), name), n + 1))); + } + } + return true; +} + +GEN(ArrowDecl) { + Expression* fn = cg.FunctionValue(ctx.depth); + Push(out, cg.Declare(fn, JsType::kFunction, "f")); + return true; +} + +REDLINE_TUNABLE( + kClassDeclSuperClassChance, "generators.ClassDecl.super_class_chance", 0.4, + 0, 1, "probability that the class extends a visible class or a builtin"); +REDLINE_TUNABLE(kClassDeclConstructorMaxParams, + "generators.ClassDecl.constructor_max_params", 2, 0, 16, + "most parameters of the constructor"); +REDLINE_TUNABLE(kClassDeclConstructorMaxFields, + "generators.ClassDecl.constructor_max_fields", 3, 1, 64, + "most this.x = ... initializations in the constructor"); +REDLINE_TUNABLE( + kClassDeclConstructorMaxStatements, + "generators.ClassDecl.constructor_max_statements", 2, 0, 64, + "most extra statements in the constructor after the field initializations"); +REDLINE_TUNABLE(kClassDeclManyMembersChance, + "generators.ClassDecl.many_members_chance", 0.05, 0, 1, + "probability that a class has many members"); +REDLINE_TUNABLE(kClassDeclManyMembersCount, + "generators.ClassDecl.many_members_count", 50, 10, 200, + "most members when the class has many"); +REDLINE_TUNABLE(kClassDeclMaxMembers, "generators.ClassDecl.max_members", 4, 1, + 64, + "most methods, accessors and fields besides the constructor"); +REDLINE_TUNABLE(kClassDeclStaticChance, "generators.ClassDecl.static_chance", + 0.2, 0, 1, "probability that a member is static"); +REDLINE_TUNABLE(kClassDeclMethodAsyncChance, + "generators.ClassDecl.method_async_chance", 0.1, 0, 1, + "probability that a method is async"); +REDLINE_TUNABLE(kClassDeclMethodGeneratorChance, + "generators.ClassDecl.method_generator_chance", 0.1, 0, 1, + "probability that a method is a generator"); +REDLINE_TUNABLE(kClassDeclMethodMaxParams, + "generators.ClassDecl.method_max_params", 2, 0, 16, + "most parameters of a method"); +REDLINE_TUNABLE(kClassDeclMethodMaxStatements, + "generators.ClassDecl.method_max_statements", 3, 1, 64, + "most statements in a method body before its return"); +REDLINE_TUNABLE(kClassDeclMethodThisStoreChance, + "generators.ClassDecl.method_this_store_chance", 0.3, 0, 1, + "probability that a method stores to this.x"); +REDLINE_TUNABLE( + kClassDeclSuperCallChance, "generators.ClassDecl.super_call_chance", 0.3, 0, + 1, "probability that a method of a derived class calls a super method"); +REDLINE_TUNABLE( + kClassDeclInstantiateChance, "generators.ClassDecl.instantiate_chance", 0.8, + 0, 1, + "probability that the class is instantiated right after its declaration"); +REDLINE_TUNABLE(kClassDeclInstantiateMaxArgs, + "generators.ClassDecl.instantiate_max_args", 2, 0, 16, + "most arguments passed to new C(...)"); + +REDLINE_TUNABLE(kClassDeclExpressionChance, + "generators.ClassDecl.expression_chance", 0.15, 0, 1, + "probability that the class is a class expression bound to a " + "const (const C = class {...})"); +REDLINE_TUNABLE(kClassDeclStaticBlockChance, + "generators.ClassDecl.static_block_chance", 0.15, 0, 1, + "probability that the class gets a static { ... } block"); +REDLINE_TUNABLE(kClassDeclStaticBlockMaxStatements, + "generators.ClassDecl.static_block_max_statements", 3, 1, 64, + "most statements in the static block"); + +GEN(ClassDecl) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view name = ctx.builder.FreshName("C"); + Expression* super_class = nullptr; + if (r.Chance(kClassDeclSuperClassChance())) { + if (Identifier* id = cg.Variable(JsType::kClass)) { + super_class = id; + } else if (r.Coin()) { + super_class = + mk::Id(t, r.Pick({"Array", "Error", "Map", "Set", "Object", "Promise", + "Uint8Array", "Function", "RegExp", "Date"})); + } + } + std::vector<Node*> members; + // Constructor. + { + GenContext nested = ctx.Nested(true, false, false, false); + nested.syntax.strict = true; + nested.syntax.in_method = true; + nested.syntax.in_constructor = true; + nested.syntax.has_super_class = super_class != nullptr; + std::vector<std::string_view> params; + int n = + static_cast<int>(r.Range(0, kClassDeclConstructorMaxParams.AsInt())); + for (int i = 0; i < n; i++) { + std::string_view p = ctx.builder.FreshName("a"); + params.push_back(p); + nested.Declare(p, JsType::kUnknown); + } + CodeGen inner(nested); + Statements body; + if (super_class != nullptr) { + std::vector<Expression*> args; + args.reserve(params.size()); + for (std::string_view p : params) { + args.push_back(mk::Id(t, p)); + } + body.push_back(inner.Stmt(mk::Call(t, t->New<Super>(), std::move(args)))); + } + int fields = 1 + r.SmallCount(kClassDeclConstructorMaxFields.AsInt() - 1); + for (int i = 0; i < fields; i++) { + body.push_back(inner.Stmt( + mk::Assign(t, inner.Property(mk::This(t), inner.PropertyName()), + inner.Value(JsType::kUnknown, 1)))); + } + Statements more = inner.Body( + nested, r.SmallCount(kClassDeclConstructorMaxStatements.AsInt())); + body.insert(body.end(), more.begin(), more.end()); + members.push_back(mk::ClassMethod( + t, "constructor", mk::Function(t, "", params, std::move(body)), + MethodKind::kConstructor)); + } + // Methods, accessors, fields. + int n = 1 + r.SmallCount(kClassDeclMaxMembers.AsInt() - 1); + if (r.Chance(kClassDeclManyMembersChance())) { + n = static_cast<int>(r.Range(10, kClassDeclManyMembersCount.AsInt())); + } + for (int i = 0; i < n; i++) { + std::string_view mname = ctx.builder.FreshName("m"); + bool is_static = r.Chance(kClassDeclStaticChance()); + switch (r.Index(5)) { + case 0: { + // Field. + GenContext nested = ctx.Nested(true, true, false, false); + nested.syntax.strict = true; + nested.syntax.in_class_field = true; + nested.syntax.has_arguments = false; + nested.syntax.in_method = true; + CodeGen inner(nested); + members.push_back(mk::ClassField( + t, mname, inner.Value(JsType::kUnknown, 1), is_static)); + break; + } + case 1: { + // Getter (+ setter). + GenContext nested = ctx.Nested(true, false, false, false); + nested.syntax.strict = true; + nested.syntax.in_method = true; + nested.syntax.has_super_class = super_class != nullptr; + CodeGen inner(nested); + Statements body = {mk::Return(t, inner.Value(JsType::kUnknown, 1))}; + members.push_back( + mk::ClassMethod(t, mname, mk::Function(t, "", {}, std::move(body)), + MethodKind::kGet, is_static)); + if (r.Coin()) { + std::string_view p = ctx.builder.FreshName("v"); + GenContext setter = ctx.Nested(true, false, false, false); + setter.syntax.strict = true; + setter.syntax.in_method = true; + setter.Declare(p, JsType::kUnknown); + CodeGen sg(setter); + Statements sbody = {sg.Stmt( + mk::Assign(t, mk::Member(t, mk::This(t), "x"), mk::Id(t, p)))}; + members.push_back(mk::ClassMethod( + t, mname, mk::Function(t, "", {p}, std::move(sbody)), + MethodKind::kSet, is_static)); + } + break; + } + default: { + // Method. + GenContext nested = + ctx.Nested(true, false, r.Chance(kClassDeclMethodAsyncChance()), + r.Chance(kClassDeclMethodGeneratorChance())); + nested.syntax.strict = true; + nested.syntax.in_method = true; + nested.syntax.has_super_class = super_class != nullptr; + std::vector<std::string_view> params; + int np = + static_cast<int>(r.Range(0, kClassDeclMethodMaxParams.AsInt())); + for (int p = 0; p < np; p++) { + std::string_view pn = ctx.builder.FreshName("a"); + params.push_back(pn); + nested.Declare(pn, JsType::kUnknown); + } + CodeGen inner(nested); + Statements body = inner.Body( + nested, + 1 + r.SmallCount(kClassDeclMethodMaxStatements.AsInt() - 1)); + if (r.Chance(kClassDeclMethodThisStoreChance())) { + body.push_back( + inner.Stmt(mk::Assign(t, mk::Member(t, mk::This(t), "x"), + inner.Value(JsType::kUnknown, 1)))); + } + if (super_class != nullptr && r.Chance(kClassDeclSuperCallChance())) { + MemberExpression* sm = mk::Member( + t, t->New<Super>(), r.Pick({"toString", "valueOf", "x", "m"})); + body.push_back(inner.Stmt(mk::Call(t, sm, {}))); + } + body.push_back(mk::Return(t, r.Coin() + ? static_cast<Expression*>(mk::This(t)) + : inner.Value(JsType::kUnknown, 1))); + members.push_back(mk::ClassMethod( + t, mname, + mk::Function(t, "", params, std::move(body), nested.syntax.in_async, + nested.syntax.in_generator), + MethodKind::kMethod, is_static)); + break; + } + } + } + if (r.Chance(kClassDeclStaticBlockChance())) { + // static { ... }: runs once when the class is defined; `this` is the + // class. The same context as the builder computes for a static block + // of an imported program (Builder::ContextAtSlot). + GenContext nested = ctx.Nested(false, false, false, false); + nested.syntax.in_static_block = true; + nested.syntax.in_method = true; + nested.syntax.strict = true; + nested.syntax.in_function = false; + nested.syntax.in_async = false; + nested.syntax.in_generator = false; + nested.syntax.in_loop = false; + nested.syntax.in_switch = false; + nested.syntax.in_constructor = false; + nested.syntax.has_arguments = false; + nested.syntax.has_super_class = super_class != nullptr; + nested.syntax.labels.clear(); + CodeGen inner(nested); + StaticBlock* block = t->New<StaticBlock>(); + block->body = inner.Body( + nested, + 1 + r.SmallCount(kClassDeclStaticBlockMaxStatements.AsInt() - 1)); + members.push_back(block); + } + if (r.Chance(kClassDeclExpressionChance())) { + Push(out, + mk::Const(t, name, mk::Class(t, "", super_class, std::move(members)))); + } else { + Push(out, mk::ClassDecl(t, name, super_class, std::move(members))); + } + ctx.Declare(name, JsType::kClass, true); + // Instantiate it. + if (r.Chance(kClassDeclInstantiateChance())) { + Push(out, cg.Declare(mk::New(t, mk::Id(t, name), + cg.Arguments( + 0, kClassDeclInstantiateMaxArgs.AsInt())), + JsType::kObject, "o")); + } + return true; +} + +REDLINE_TUNABLE(kIifeAsyncChance, "generators.Iife.async_chance", 0.2, 0, 1, + "probability that the IIFE is async"); +REDLINE_TUNABLE(kIifeMaxStatements, "generators.Iife.max_statements", 4, 1, 64, + "most statements in the IIFE body"); + +GEN(Iife) { + Random& r = ctx.rng(); + bool is_async = r.Chance(kIifeAsyncChance()); + bool is_arrow = r.Coin(); + GenContext nested = ctx.Nested(true, is_arrow, is_async, false); + CodeGen inner(nested); + Statements body = + inner.Body(nested, 1 + r.SmallCount(kIifeMaxStatements.AsInt() - 1)); + Expression* fn = is_arrow + ? static_cast<Expression*>( + mk::Arrow(T(ctx), {}, std::move(body), is_async)) + : static_cast<Expression*>(mk::Function( + T(ctx), "", {}, std::move(body), is_async, false)); + Push(out, cg.Stmt(mk::Call(T(ctx), fn, {}))); + return true; +} + +// --- operations +// ----------------------------------------------------------------- + +GEN(BinaryOp) { + Expression* v = cg.BinaryOperation(0); + Push(out, cg.Declare(v, Builder::GuessType(v))); + return true; +} + +GEN(Compare) { + Push(out, cg.Declare(cg.Comparison(0), JsType::kBoolean, "b")); + return true; +} + +GEN(UnaryOp) { + Expression* v = cg.UnaryOperation(0); + if (v->Is<UpdateExpression>() || + (v->Is<UnaryExpression>() && + v->Cast<UnaryExpression>()->op == UnaryOp::kDelete)) { + Push(out, cg.Stmt(v)); + return true; + } + Push(out, cg.Declare(v, Builder::GuessType(v))); + return true; +} + +GEN(Update) { + Random& r = ctx.rng(); + Expression* target = cg.MutableVariable(JsType::kNumber); + if (target == nullptr) { + target = cg.Target(); + } + if (target->Is<Identifier>() && + target->Cast<Identifier>()->name == "arguments") { + return false; + } + Push(out, cg.Stmt(mk::Update( + T(ctx), r.Coin() ? UpdateOp::kIncrement : UpdateOp::kDecrement, + r.Coin(), target))); + return true; +} + +REDLINE_TUNABLE( + kAssignmentPlainChance, "generators.Assignment.plain_chance", 0.6, 0, 1, + "probability of a plain = rather than a compound assignment operator"); +REDLINE_TUNABLE(kAssignmentNumberHintChance, + "generators.Assignment.number_hint_chance", 0.7, 0, 1, + "probability that the right-hand side of a compound assignment " + "is generated as a number"); + +GEN(Assignment) { + Random& r = ctx.rng(); + Expression* target = cg.Target(); + AssignOp op = r.Chance(kAssignmentPlainChance()) + ? AssignOp::kAssign + : CodeGen::RandomCompoundAssignOp(r); + JsType hint = JsType::kUnknown; + if (target->Is<Identifier>()) { + for (const Variable& v : ctx.visible) { + if (v.name == target->Cast<Identifier>()->name) { + hint = v.type; + } + } + } + if (op != AssignOp::kAssign && r.Chance(kAssignmentNumberHintChance())) { + hint = JsType::kNumber; + } + Push(out, cg.Stmt(mk::Assign(T(ctx), target, cg.Value(hint, 0), op))); + return true; +} + +// `object?.name` or `object?.[key]` from a property load. +Expression* OptionalChain(Tree* t, Expression* load) { + if (!load->Is<MemberExpression>()) { + return load; + } + load->Cast<MemberExpression>()->optional = true; + return mk::Chain(t, load); +} + +REDLINE_TUNABLE(kPropertyLoadOptionalChance, + "generators.PropertyLoad.optional_chance", 0.1, 0, 1, + "probability that the load is an optional chain (o?.p)"); + +GEN(PropertyLoad) { + Expression* v = cg.Property(cg.ObjectLike()); + if (ctx.rng().Chance(kPropertyLoadOptionalChance())) { + v = OptionalChain(T(ctx), v); + } + Push(out, cg.Declare(v, JsType::kUnknown)); + return true; +} + +GEN(PropertyStore) { + Expression* object = cg.ObjectLike(); + if (object->Is<ObjectExpression>() || object->Is<ArrayExpression>()) { + // Bind literals first so that the store is observable. + Statement* decl = cg.Declare(object, JsType::kObject, "obj"); + Push(out, decl); + object = mk::Id(T(ctx), decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + } + Push(out, cg.Stmt(mk::Assign(T(ctx), cg.Property(object), + cg.Value(JsType::kUnknown, 0)))); + return true; +} + +REDLINE_TUNABLE(kElementLoadVariableKeyChance, + "generators.ElementLoad.variable_key_chance", 0.6, 0, 1, + "probability that the index is a visible number variable " + "rather than a generated key"); +REDLINE_TUNABLE(kElementLoadOptionalChance, + "generators.ElementLoad.optional_chance", 0.1, 0, 1, + "probability that the load is an optional chain (a?.[i])"); + +GEN(ElementLoad) { + Random& r = ctx.rng(); + Expression* object = nullptr; + if (Identifier* id = + cg.Variable(r.Coin() ? JsType::kArray : JsType::kTypedArray)) { + object = id; + } else { + object = cg.ObjectLike(); + } + Expression* key = nullptr; + if (r.Chance(kElementLoadVariableKeyChance())) { + if (Identifier* id = cg.Variable(JsType::kNumber)) { + key = id; + } + } + if (key == nullptr) { + key = cg.Key(); + } + Expression* load = mk::Index(T(ctx), object, key); + if (r.Chance(kElementLoadOptionalChance())) { + load = OptionalChain(T(ctx), load); + } + Push(out, cg.Declare(load, JsType::kUnknown)); + return true; +} + +REDLINE_TUNABLE(kElementStoreVariableKeyChance, + "generators.ElementStore.variable_key_chance", 0.6, 0, 1, + "probability that the index is a visible number variable " + "rather than a generated key"); + +GEN(ElementStore) { + Random& r = ctx.rng(); + Expression* object = nullptr; + if (Identifier* id = + cg.Variable(r.Coin() ? JsType::kArray : JsType::kTypedArray)) { + object = id; + } else if (Identifier* id2 = cg.Variable(JsType::kObject)) { + object = id2; + } else { + return false; + } + Expression* key = nullptr; + if (r.Chance(kElementStoreVariableKeyChance())) { + if (Identifier* id = cg.Variable(JsType::kNumber)) { + key = id; + } + } + if (key == nullptr) { + key = cg.Key(); + } + Push(out, cg.Stmt(mk::Assign(T(ctx), mk::Index(T(ctx), object, key), + cg.Value(JsType::kUnknown, 0)))); + return true; +} + +GEN(PropertyDelete) { + Identifier* object = cg.Variable(JsType::kObject); + if (object == nullptr) { + object = cg.Variable(JsType::kArray); + } + if (object == nullptr) { + return false; + } + Push(out, cg.Stmt(mk::Unary(T(ctx), UnaryOp::kDelete, cg.Property(object)))); + return true; +} + +REDLINE_TUNABLE(kMethodCallDeclareChance, + "generators.MethodCall.declare_chance", 0.6, 0, 1, + "probability that the call result is bound to a variable " + "rather than discarded"); + +GEN(MethodCall) { + Random& r = ctx.rng(); + Expression* object = cg.ObjectLike(); + Expression* call = cg.MethodCall(object, Builder::GuessType(object)); + if (r.Chance(kMethodCallDeclareChance())) { + Push(out, cg.Declare(call, JsType::kUnknown)); + } else { + Push(out, cg.Stmt(call)); + } + return true; +} + +REDLINE_TUNABLE(kFunctionCallUntypedCalleeChance, + "generators.FunctionCall.untyped_callee_chance", 0.3, 0, 1, + "probability of calling an untyped variable when no function " + "variable is visible"); +REDLINE_TUNABLE(kFunctionCallCallApplyChance, + "generators.FunctionCall.call_apply_chance", 0.1, 0, 1, + "probability of f.call(thisArg, ...)/f.apply(thisArg, [...]) " + "rather than a direct call"); +REDLINE_TUNABLE(kFunctionCallDeclareChance, + "generators.FunctionCall.declare_chance", 0.5, 0, 1, + "probability that the call result is bound to a variable " + "rather than discarded"); + +GEN(FunctionCall) { + Random& r = ctx.rng(); + Identifier* callee = cg.Variable(JsType::kFunction); + if (callee == nullptr && r.Chance(kFunctionCallUntypedCalleeChance())) { + callee = cg.Variable(JsType::kUnknown); + } + if (callee == nullptr) { + return false; + } + Expression* call = cg.CallWithArguments(callee); + if (r.Chance(kFunctionCallCallApplyChance())) { + // f.call(thisArg, ...) / f.apply(thisArg, [...]) + if (r.Coin()) { + call = mk::CallMethod(T(ctx), callee, "call", + {cg.ObjectLike(), cg.Value(JsType::kUnknown, 1)}); + } else { + call = mk::CallMethod(T(ctx), callee, "apply", + {cg.ObjectLike(), cg.ArrayLiteral(1)}); + } + } + if (r.Chance(kFunctionCallDeclareChance())) { + Push(out, cg.Declare(call, JsType::kUnknown)); + } else { + Push(out, cg.Stmt(call)); + } + return true; +} + +REDLINE_TUNABLE(kBuiltinCallDeclareChance, + "generators.BuiltinCall.declare_chance", 0.6, 0, 1, + "probability that the call result is bound to a variable " + "rather than discarded"); + +GEN(BuiltinCall) { + Random& r = ctx.rng(); + Expression* call = cg.BuiltinCall(); + if (r.Chance(kBuiltinCallDeclareChance())) { + Push(out, cg.Declare(call, Builder::GuessType(call))); + } else { + Push(out, cg.Stmt(call)); + } + return true; +} + +REDLINE_TUNABLE(kConstructMaxArgs, "generators.Construct.max_args", 2, 0, 16, + "most arguments passed to new on a visible class or function"); + +GEN(Construct) { + Random& r = ctx.rng(); + Expression* v = nullptr; + if (r.Coin()) { + if (Identifier* id = cg.Variable(JsType::kClass)) { + v = mk::New(T(ctx), id, cg.Arguments(0, kConstructMaxArgs.AsInt())); + } + } + if (v == nullptr && r.Coin()) { + if (Identifier* id = cg.Variable(JsType::kFunction)) { + v = mk::New(T(ctx), id, cg.Arguments(0, kConstructMaxArgs.AsInt())); + } + } + if (v == nullptr) { + v = cg.Construct(); + } + if (v == nullptr) { + return false; + } + Push(out, cg.Declare(v, Builder::GuessType(v), "o")); + return true; +} + +GEN(TypeCheck) { + Random& r = ctx.rng(); + Expression* v = nullptr; + switch (r.Index(4)) { + case 0: + v = mk::Unary(T(ctx), UnaryOp::kTypeof, cg.Value(JsType::kUnknown, 1)); + break; + case 1: { + Expression* ctor = cg.Variable(JsType::kClass); + if (ctor == nullptr) { + ctor = mk::Id(T(ctx), r.Pick({"Object", "Array", "Function", "Error", + "Map", "Set"})); + } + v = mk::Binary(T(ctx), BinaryOp::kInstanceof, + cg.Value(JsType::kUnknown, 1), ctor); + break; + } + case 2: + v = mk::Binary(T(ctx), BinaryOp::kIn, + r.Coin() ? cg.Key() : mk::Str(T(ctx), cg.PropertyName()), + cg.ObjectLike()); + break; + default: { + Expression* type_str = + mk::Str(T(ctx), r.Pick({"undefined", "object", "boolean", "number", + "bigint", "string", "symbol", "function"})); + v = mk::Binary( + T(ctx), CodeGen::RandomComparisonOp(r), + mk::Unary(T(ctx), UnaryOp::kTypeof, cg.Value(JsType::kUnknown, 1)), + type_str); + break; + } + } + Push(out, cg.Declare(v, Builder::GuessType(v), "b")); + return true; +} + +GEN(SpreadCall) { + Identifier* arr = cg.Variable(JsType::kArray); + if (arr == nullptr) { + return false; + } + Expression* callee = cg.Callable(); + std::vector<Expression*> args; + if (ctx.rng().Coin()) { + args.push_back(cg.Value(JsType::kUnknown, 1)); + } + args.push_back(mk::Spread(T(ctx), arr)); + Push(out, + cg.Declare(mk::Call(T(ctx), callee, std::move(args)), JsType::kUnknown)); + return true; +} + +// --- control flow +// --------------------------------------------------------------- + +REDLINE_TUNABLE(kCountedLoopMaxStatements, + "generators.CountedLoop.max_statements", 4, 1, 64, + "most statements in the loop body"); +REDLINE_TUNABLE(kCountedLoopLiteralCountChance, + "generators.CountedLoop.literal_count_chance", 0.8, 0, 1, + "probability that the loop bound is a literal count rather " + "than a computed number"); + +GEN(CountedLoop) { + Random& r = ctx.rng(); + std::string_view counter = ctx.builder.FreshName("i"); + GenContext inner = ctx.Inner(true, false); + inner.Declare(counter, JsType::kNumber); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kCountedLoopMaxStatements.AsInt() - 1)); + Expression* count = r.Chance(kCountedLoopLiteralCountChance()) + ? mk::Num(T(ctx), LoopCount(r)) + : cg.Value(JsType::kNumber, 1); + Push(out, mk::CountedLoop(T(ctx), counter, count, + mk::Block(T(ctx), std::move(body)))); + return true; +} + +REDLINE_TUNABLE(kWhileLoopMaxStatements, "generators.WhileLoop.max_statements", + 4, 1, 64, "most statements in the loop body"); +REDLINE_TUNABLE(kWhileLoopDoWhileChance, "generators.WhileLoop.do_while_chance", + 0.25, 0, 1, "probability of do-while rather than while"); + +GEN(WhileLoop) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + // Bounded: let n = 0; while (cond && n++ < N) { ... } + std::string_view counter = ctx.builder.FreshName("n"); + Push(out, mk::Let(t, counter, mk::Num(t, 0))); + GenContext inner = ctx.Inner(true, false); + inner.Declare(counter, JsType::kNumber); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kWhileLoopMaxStatements.AsInt() - 1)); + Expression* bound = + mk::Binary(t, BinaryOp::kLessThan, + mk::Update(t, UpdateOp::kIncrement, false, mk::Id(t, counter)), + mk::Num(t, LoopCount(r))); + Expression* test = + r.Coin() ? bound + : mk::Logical(t, LogicalOp::kAnd, cg.Condition(1), bound); + if (r.Chance(kWhileLoopDoWhileChance())) { + Push(out, mk::DoWhile(t, mk::Block(t, std::move(body)), test)); + } else { + Push(out, mk::While(t, test, mk::Block(t, std::move(body)))); + } + return true; +} + +REDLINE_TUNABLE(kForOfMaxStatements, "generators.ForOf.max_statements", 3, 1, + 64, "most statements in the loop body"); +REDLINE_TUNABLE(kForOfAwaitChance, "generators.ForOf.await_chance", 0.2, 0, 1, + "probability of for await when in an async context"); +REDLINE_TUNABLE(kForOfConstChance, "generators.ForOf.const_chance", 0.7, 0, 1, + "probability that the loop variable is const rather than let"); + +GEN(ForOf) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* iterable = nullptr; + switch (r.Index(6)) { + case 0: + iterable = cg.Variable(JsType::kArray); + break; + case 1: + iterable = cg.Variable(JsType::kString); + break; + case 2: + iterable = cg.Variable(r.Coin() ? JsType::kMap : JsType::kSet); + break; + case 3: + iterable = cg.Variable(JsType::kTypedArray); + break; + case 4: + iterable = + mk::CallMethod(t, mk::Id(t, "Object"), r.Coin() ? "keys" : "entries", + {cg.ObjectLike()}); + break; + default: + break; + } + if (iterable == nullptr) { + iterable = cg.ArrayLiteral(1); + } + std::string_view name = ctx.builder.FreshName("e"); + GenContext inner = ctx.Inner(true, false); + inner.Declare(name, JsType::kUnknown); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kForOfMaxStatements.AsInt() - 1)); + bool is_await = ctx.syntax.in_async && !ctx.syntax.in_static_block && + r.Chance(kForOfAwaitChance()); + Push(out, mk::ForOf(t, + r.Chance(kForOfConstChance()) ? VariableKind::kConst + : VariableKind::kLet, + name, iterable, mk::Block(t, std::move(body)), is_await)); + return true; +} + +REDLINE_TUNABLE(kForInMaxStatements, "generators.ForIn.max_statements", 3, 1, + 64, "most statements in the loop body"); +REDLINE_TUNABLE(kForInTouchPropertyChance, + "generators.ForIn.touch_property_chance", 0.5, 0, 1, + "probability that the body starts by loading obj[k] when the " + "object is a variable"); + +GEN(ForIn) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view name = ctx.builder.FreshName("k"); + Expression* object = cg.ObjectLike(); + GenContext inner = ctx.Inner(true, false); + inner.Declare(name, JsType::kString); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kForInMaxStatements.AsInt() - 1)); + if (r.Chance(kForInTouchPropertyChance()) && object->Is<Identifier>()) { + // Touch the property inside the loop. + body.insert( + body.begin(), + icg.Declare(mk::Index(t, mk::Id(t, object->Cast<Identifier>()->name), + mk::Id(t, name)), + JsType::kUnknown)); + } + Push(out, mk::ForIn(t, VariableKind::kLet, name, object, + mk::Block(t, std::move(body)))); + return true; +} + +REDLINE_TUNABLE(kIfElseElseChance, "generators.IfElse.else_chance", 0.5, 0, 1, + "probability that the if has an else branch"); + +GEN(IfElse) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Statements consequent = InnerBody(ctx, cg, false, false); + Statement* alternate = nullptr; + if (r.Chance(kIfElseElseChance())) { + Statements alt = InnerBody(ctx, cg, false, false); + alternate = mk::Block(t, std::move(alt)); + } + Push(out, mk::If(t, cg.Condition(0), mk::Block(t, std::move(consequent)), + alternate)); + return true; +} + +REDLINE_TUNABLE(kSwitchMaxCases, "generators.Switch.max_cases", 4, 1, 64, + "most case clauses, not counting default"); +REDLINE_TUNABLE(kSwitchCaseMaxStatements, + "generators.Switch.case_max_statements", 3, 1, 64, + "most statements in a case or default body"); +REDLINE_TUNABLE(kSwitchBreakChance, "generators.Switch.break_chance", 0.7, 0, 1, + "probability that a case ends with break"); +REDLINE_TUNABLE(kSwitchIntegerLabelChance, + "generators.Switch.integer_label_chance", 0.6, 0, 1, + "probability that a case label is an integer literal rather " + "than an arbitrary value"); +REDLINE_TUNABLE(kSwitchDefaultChance, "generators.Switch.default_chance", 0.5, + 0, 1, "probability that the switch has a default clause"); + +GEN(Switch) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* discriminant = + cg.Value(r.Coin() ? JsType::kNumber : JsType::kUnknown, 0); + std::vector<SwitchCase*> cases; + int n = 1 + r.SmallCount(kSwitchMaxCases.AsInt() - 1); + for (int i = 0; i < n; i++) { + GenContext inner = ctx.Inner(false, true); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kSwitchCaseMaxStatements.AsInt() - 1)); + if (r.Chance(kSwitchBreakChance())) { + body.push_back(mk::Break(t)); + } + cases.push_back(mk::Case(t, + r.Chance(kSwitchIntegerLabelChance()) + ? cg.Integer() + : cg.Value(JsType::kUnknown, 1), + std::move(body))); + } + if (r.Chance(kSwitchDefaultChance())) { + GenContext inner = ctx.Inner(false, true); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kSwitchCaseMaxStatements.AsInt() - 1)); + cases.insert( + cases.begin() + static_cast<std::ptrdiff_t>(r.Index(cases.size() + 1)), + mk::Case(t, nullptr, std::move(body))); + } + Push(out, mk::Switch(t, discriminant, std::move(cases))); + return true; +} + +REDLINE_TUNABLE(kTryCatchThrowChance, "generators.TryCatch.throw_chance", 0.3, + 0, 1, "probability that the try block ends with a throw"); +REDLINE_TUNABLE(kTryCatchParamChance, "generators.TryCatch.param_chance", 0.8, + 0, 1, "probability that the catch clause binds the exception"); +REDLINE_TUNABLE(kTryCatchHandlerMaxStatements, + "generators.TryCatch.handler_max_statements", 2, 0, 64, + "most statements in the catch handler"); +REDLINE_TUNABLE(kTryCatchFinallyChance, "generators.TryCatch.finally_chance", + 0.3, 0, 1, "probability of a finally block"); +REDLINE_TUNABLE(kTryCatchFinallyMaxStatements, + "generators.TryCatch.finally_max_statements", 2, 1, 64, + "most statements in the finally block"); + +GEN(TryCatch) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Statements block = InnerBody(ctx, cg, false, false); + if (r.Chance(kTryCatchThrowChance())) { + block.push_back(mk::Throw(t, cg.Value(JsType::kUnknown, 1))); + } + std::string_view param = r.Chance(kTryCatchParamChance()) + ? ctx.builder.FreshName("e") + : std::string_view(); + GenContext inner = ctx.Inner(false, false); + if (!param.empty()) { + inner.Declare(param, JsType::kError); + } + CodeGen icg(inner); + Statements handler = + icg.Body(inner, r.SmallCount(kTryCatchHandlerMaxStatements.AsInt())); + if (r.Chance(kTryCatchFinallyChance())) { + Statements finalizer = + InnerBody(ctx, cg, false, false, kTryCatchFinallyMaxStatements.AsInt()); + Push(out, + mk::Try(t, std::move(block), param, std::move(handler), &finalizer)); + } else { + Push(out, mk::Try(t, std::move(block), param, std::move(handler))); + } + return true; +} + +GEN(Throw) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* value = nullptr; + if (r.Coin()) { + value = mk::New( + t, + mk::Id(t, r.Pick({"Error", "TypeError", "RangeError", "SyntaxError"})), + {cg.String()}); + } else { + value = cg.Value(JsType::kUnknown, 1); + } + // Only inside a try so that execution continues. + Statements block = {mk::Throw(t, value)}; + std::string_view param = ctx.builder.FreshName("e"); + Push(out, mk::Try(t, std::move(block), param, {})); + return true; +} + +REDLINE_TUNABLE(kLabeledBlockMaxStatements, + "generators.LabeledBlock.max_statements", 3, 1, 64, + "most statements in the labeled block"); + +GEN(LabeledBlock) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view label = ctx.builder.FreshName("L"); + GenContext inner = ctx.Inner(false, false); + inner.syntax.labels.push_back(label); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kLabeledBlockMaxStatements.AsInt() - 1)); + if (r.Coin()) { + body.insert( + body.begin() + static_cast<std::ptrdiff_t>(r.Index(body.size() + 1)), + mk::If(t, icg.Condition(1), mk::Break(t, label))); + } else { + body.push_back(mk::Break(t, label)); + } + Push(out, mk::Labeled(t, label, mk::Block(t, std::move(body)))); + return true; +} + +REDLINE_TUNABLE(kReturnValueChance, "generators.Return.value_chance", 0.8, 0, 1, + "probability that the return has a value"); +REDLINE_TUNABLE(kReturnConditionalChance, + "generators.Return.conditional_chance", 0.7, 0, 1, + "probability that the return is guarded by an if (keeping the " + "rest of the function reachable)"); + +GEN(Return) { + Random& r = ctx.rng(); + // Conditional returns keep the rest of the function reachable. + Statement* ret = mk::Return(T(ctx), r.Chance(kReturnValueChance()) + ? cg.Value(JsType::kUnknown, 0) + : nullptr); + if (r.Chance(kReturnConditionalChance())) { + Push(out, mk::If(T(ctx), cg.Condition(0), mk::Block(T(ctx), {ret}))); + } else { + Push(out, ret); + } + return true; +} + +GEN(BreakContinue) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Statement* s = nullptr; + if (ctx.syntax.in_loop && r.Coin()) { + s = mk::Continue(t); + } else { + s = mk::Break(t); + } + Push(out, mk::If(t, cg.Condition(0), mk::Block(t, {s}))); + return true; +} + +// --- JIT +// ------------------------------------------------------------------------ + +// Picks a function to compile: a visible function variable, or a fresh one. +Identifier* FunctionForJit(GenContext& ctx, CodeGen& cg, Statements* out) { + if (Identifier* f = cg.Variable(JsType::kFunction)) { + return f; + } + Statements decl; + if (!GenFunctionDecl(ctx, cg, &decl)) { + return nullptr; + } + out->insert(out->end(), decl.begin(), decl.end()); + // The declaration registered the name as the newest visible function. + for (const Variable& v : ctx.visible) { + if (v.type == JsType::kFunction) { + return mk::Id(T(ctx), v.name); + } + } + return nullptr; +} + +REDLINE_TUNABLE(kJitOptimizeMaxWarmupCalls, + "generators.JitOptimize.max_warmup_calls", 4, 1, 64, + "most calls between %PrepareFunctionForOptimization and the " + "optimization request"); +REDLINE_TUNABLE(kJitOptimizeTurbofanChance, + "generators.JitOptimize.turbofan_chance", 0.6, 0, 1, + "probability of %OptimizeFunctionOnNextCall rather than " + "%OptimizeMaglevOnNextCall"); +REDLINE_TUNABLE(kJitOptimizeExtraCallChance, + "generators.JitOptimize.extra_call_chance", 0.3, 0, 1, + "probability of a second call of the optimized function"); +REDLINE_TUNABLE( + kJitOptimizeDeoptChance, "generators.JitOptimize.deopt_chance", 0.2, 0, 1, + "probability of a %DeoptimizeFunction followed by another call"); +REDLINE_TUNABLE(kJitOptimizeConstantCallerChance, + "generators.JitOptimize.constant_caller_chance", 0.2, 0, 1, + "probability that the optimized function is a new caller " + "passing literal arguments to the warmed-up function"); + +GEN(JitOptimize) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Identifier* f = FunctionForJit(ctx, cg, out); + if (f == nullptr) { + return false; + } + std::string_view name = f->name; + std::string_view target_name = name; + + bool constant_caller = r.Chance(kJitOptimizeConstantCallerChance()); + if (constant_caller) { + target_name = ctx.builder.FreshName("caller"); + std::vector<Expression*> args; + int args_count = 1 + static_cast<int>(r.Index(3)); + args.reserve(static_cast<size_t>(args_count)); + for (int i = 0; i < args_count; i++) { + args.push_back(cg.Literal()); + } + Statements caller_body; + caller_body.push_back( + mk::Return(t, mk::Call(t, mk::Id(t, name), std::move(args)))); + Push(out, mk::FunctionDecl(t, target_name, {}, std::move(caller_body), + false, false)); + ctx.Declare(target_name, JsType::kFunction); + } + + Push(out, cg.Stmt(mk::Native(t, "PrepareFunctionForOptimization", + {mk::Id(t, target_name)}))); + int warmup = 1 + r.SmallCount(kJitOptimizeMaxWarmupCalls.AsInt() - 1); + for (int i = 0; i < warmup; i++) { + Push(out, cg.Stmt(cg.CallWithArguments(mk::Id(t, name)))); + } + const char* tier = r.Chance(kJitOptimizeTurbofanChance()) + ? "OptimizeFunctionOnNextCall" + : "OptimizeMaglevOnNextCall"; + Push(out, cg.Stmt(mk::Native(t, tier, {mk::Id(t, target_name)}))); + + auto call_target = [&] { + if (constant_caller) { + return cg.Stmt(mk::Call(t, mk::Id(t, target_name), {})); + } + return cg.Stmt(cg.CallWithArguments(mk::Id(t, name))); + }; + + Push(out, call_target()); + if (r.Chance(kJitOptimizeExtraCallChance())) { + Push(out, call_target()); + } + if (r.Chance(kJitOptimizeDeoptChance())) { + Push(out, cg.Stmt(mk::Native(t, "DeoptimizeFunction", + {mk::Id(t, target_name)}))); + Push(out, call_target()); + } + return true; +} + +GEN(JitBaseline) { + Tree* t = T(ctx); + Identifier* f = FunctionForJit(ctx, cg, out); + if (f == nullptr) { + return false; + } + Push(out, cg.Stmt(mk::Native(t, "CompileBaseline", {f}))); + Push(out, cg.Stmt(cg.CallWithArguments(mk::Id(t, f->name)))); + return true; +} + +REDLINE_TUNABLE(kDeoptDeoptimizeFunctionChance, + "generators.Deopt.deoptimize_function_chance", 0.8, 0, 1, + "probability of %DeoptimizeFunction(f) rather than " + "%NeverOptimizeFunction(f)"); + +GEN(Deopt) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + if (r.Coin()) { + Push(out, cg.Stmt(mk::Native(t, "DeoptimizeNow", {}))); + return true; + } + Identifier* f = cg.Variable(JsType::kFunction); + if (f == nullptr) { + return false; + } + Push(out, cg.Stmt(mk::Native(t, + r.Chance(kDeoptDeoptimizeFunctionChance()) + ? "DeoptimizeFunction" + : "NeverOptimizeFunction", + {f}))); + return true; +} + +REDLINE_TUNABLE(kOsrLoopMaxStatements, "generators.OsrLoop.max_statements", 4, + 1, 64, "most statements in the OSR loop body"); +REDLINE_TUNABLE( + kOsrLoopMinTriggerIteration, "generators.OsrLoop.min_trigger_iteration", 1, + 0, 256, + "earliest loop iteration at which %OptimizeOsr/%BaselineOsr is requested"); +REDLINE_TUNABLE( + kOsrLoopMaxTriggerIteration, "generators.OsrLoop.max_trigger_iteration", 50, + 1, 256, + "latest loop iteration at which %OptimizeOsr/%BaselineOsr is requested"); + +GEN(OsrLoop) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view counter = ctx.builder.FreshName("i"); + GenContext inner = ctx.Inner(true, false); + inner.Declare(counter, JsType::kNumber); + CodeGen icg(inner); + Statements body = + icg.Body(inner, 1 + r.SmallCount(kOsrLoopMaxStatements.AsInt() - 1)); + Statement* osr = + icg.Stmt(mk::Native(t, r.Coin() ? "OptimizeOsr" : "BaselineOsr", {})); + body.insert( + body.begin(), + mk::If(t, + mk::Binary(t, BinaryOp::kStrictEq, mk::Id(t, counter), + mk::Num(t, static_cast<double>(r.Range( + kOsrLoopMinTriggerIteration.AsInt(), + kOsrLoopMaxTriggerIteration.AsInt())))), + mk::Block(t, {osr}))); + Push(out, mk::CountedLoop(t, counter, + mk::Num(t, r.Pick({5.0, 7.0, 10.0, 20.0, 100.0})), + mk::Block(t, std::move(body)))); + return true; +} + +REDLINE_TUNABLE( + kNativeCallDeclareChance, "generators.NativeCall.declare_chance", 0.3, 0, 1, + "probability that the result of the %Native call is bound to a variable"); + +GEN(NativeCall) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + const NativeFunction& n = r.Pick(ctx.env.natives()); + std::vector<Expression*> args; + for (int i = 0; i < n.args; i++) { + Expression* arg = nullptr; + if (n.arg_type != JsType::kUnknown) { + arg = cg.Variable(n.arg_type); + } + if (arg == nullptr) { + arg = i == 0 && n.arg_type == JsType::kFunction ? cg.Callable() + : cg.Value(n.arg_type, 1); + } + args.push_back(arg); + } + Expression* call = mk::Native(t, n.name, std::move(args)); + if (r.Chance(kNativeCallDeclareChance())) { + Push(out, cg.Declare(call, JsType::kUnknown)); + } else { + Push(out, cg.Stmt(call)); + } + return true; +} + +GEN(Gc) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + switch (r.Index(6)) { + case 0: + Push(out, cg.Stmt(mk::Call(t, mk::Id(t, "gc"), {}))); + break; + case 1: + Push(out, + cg.Stmt(mk::Call( + t, mk::Id(t, "gc"), + {mk::Object(t, {mk::Prop(t, "type", mk::Str(t, "minor"))})}))); + break; + case 2: + Push(out, cg.Stmt(mk::Native(t, "SimulateNewspaceFull", {}))); + break; + case 3: { + // %PretenureAllocationSite(o); gc(): objects allocated at o's site + // go to old space from now on, so later stores into them take the + // write-barrier paths that young objects skip. + Expression* object = cg.Variable(JsType::kObject); + if (object == nullptr) { + object = cg.Variable(JsType::kArray); + } + if (object == nullptr) { + object = cg.ObjectLiteral(1); + } + Push(out, cg.Stmt(mk::Native(t, "PretenureAllocationSite", {object}))); + Push(out, cg.Stmt(mk::Call(t, mk::Id(t, "gc"), {}))); + break; + } + default: + Push(out, + cg.Stmt(mk::Call(t, mk::Id(t, "gc"), + {mk::Object(t, {mk::Prop(t, "execution", + mk::Str(t, "async"))})}))); + break; + } + return true; +} + +// --- object model games +// --------------------------------------------------------- + +REDLINE_TUNABLE(kPrototypeSetNullChance, "generators.PrototypeSet.null_chance", + 0.3, 0, 1, "probability that the new prototype is null"); + +GEN(PrototypeSet) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* object = cg.ObjectLike(); + Expression* proto = r.Chance(kPrototypeSetNullChance()) + ? static_cast<Expression*>(mk::Null(t)) + : cg.ObjectLike(); + if (r.Coin()) { + Push(out, cg.Stmt(mk::CallMethod(t, mk::Id(t, "Object"), "setPrototypeOf", + {object, proto}))); + } else { + Push(out, + cg.Stmt(mk::Assign(t, mk::Member(t, object, "__proto__"), proto))); + } + return true; +} + +REDLINE_TUNABLE(kDefinePropertyStringKeyChance, + "generators.DefineProperty.string_key_chance", 0.7, 0, 1, + "probability that the defined key is a property name string " + "rather than a computed key"); + +GEN(DefineProperty) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* object = cg.ObjectLike(); + std::vector<Node*> descriptor; + if (r.Coin()) { + GenContext nested = ctx.Nested(true, false, false, false); + CodeGen inner(nested); + Statements getter = {mk::Return(t, inner.Value(JsType::kUnknown, 1))}; + descriptor.push_back( + mk::Prop(t, "get", mk::Function(t, "", {}, std::move(getter)))); + if (r.Coin()) { + std::string_view p = ctx.builder.FreshName("v"); + Statements setter = {inner.Stmt( + mk::Assign(t, mk::Member(t, mk::This(t), "x"), mk::Id(t, p)))}; + descriptor.push_back( + mk::Prop(t, "set", mk::Function(t, "", {p}, std::move(setter)))); + } + } else { + descriptor.push_back(mk::Prop(t, "value", cg.Value(JsType::kUnknown, 1))); + if (r.Coin()) { + descriptor.push_back(mk::Prop(t, "writable", cg.Boolean())); + } + } + if (r.Coin()) { + descriptor.push_back(mk::Prop(t, "configurable", cg.Boolean())); + } + if (r.Coin()) { + descriptor.push_back(mk::Prop(t, "enumerable", cg.Boolean())); + } + Expression* key = r.Chance(kDefinePropertyStringKeyChance()) + ? mk::Str(t, cg.PropertyName()) + : cg.Key(); + Push(out, cg.Stmt(mk::CallMethod( + t, mk::Id(t, "Object"), "defineProperty", + {object, key, mk::Object(t, std::move(descriptor))}))); + return true; +} + +GEN(ValueOfOverride) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* object = cg.Variable(JsType::kObject); + if (object == nullptr) { + object = cg.Variable(JsType::kArray); + } + if (object == nullptr) { + object = cg.ObjectLike(); + } + GenContext nested = ctx.Nested(true, true, false, false); + CodeGen inner(nested); + Expression* fn = mk::ArrowExpr( + t, {}, inner.Value(r.Coin() ? JsType::kNumber : JsType::kUnknown, 1)); + Expression* target = nullptr; + switch (r.Index(3)) { + case 0: + target = mk::Member(t, object, "valueOf"); + break; + case 1: + target = mk::Member(t, object, "toString"); + break; + default: + target = mk::Index(t, object, + mk::Member(t, mk::Id(t, "Symbol"), "toPrimitive")); + break; + } + Push(out, cg.Stmt(mk::Assign(t, target, fn))); + // Trigger a conversion. + if (r.Coin()) { + Push(out, + cg.Declare(mk::Binary(t, r.Coin() ? BinaryOp::kAdd : BinaryOp::kMul, + object, cg.Number()), + JsType::kUnknown)); + } + return true; +} + +REDLINE_TUNABLE(kElementsKindMaxTransitions, + "generators.ElementsKind.max_transitions", 4, 1, 64, + "most elements-kind transitions applied to the array"); + +GEN(ElementsKind) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Identifier* arr = cg.Variable(JsType::kArray); + if (arr == nullptr) { + Statement* decl = cg.Declare(cg.ArrayLiteral(1), JsType::kArray, "arr"); + Push(out, decl); + arr = mk::Id(t, decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + } + int n = 1 + r.SmallCount(kElementsKindMaxTransitions.AsInt() - 1); + for (int i = 0; i < n; i++) { + Identifier* a = mk::Id(t, arr->name); + switch (r.Index(9)) { + case 0: + Push(out, cg.Stmt(mk::CallMethod(t, a, "push", {mk::Num(t, 1.5)}))); + break; + case 1: + Push(out, cg.Stmt(mk::CallMethod(t, a, "push", {cg.ObjectLike()}))); + break; + case 2: + Push(out, cg.Stmt(mk::Assign( + t, + mk::Index(t, a, + mk::Num(t, r.Pick({10.0, 100.0, 1000.0, + 100000.0, 4294967294.0}))), + cg.Value(JsType::kNumber, 1)))); + break; + case 3: + Push(out, + cg.Stmt(mk::Assign(t, mk::Member(t, a, "length"), cg.Integer()))); + break; + case 4: + Push(out, cg.Stmt(mk::CallMethod( + t, a, r.Pick({"pop", "shift", "reverse", "sort"}), {}))); + break; + case 5: + Push(out, + cg.Stmt(mk::Assign( + t, mk::Index(t, a, mk::Num(t, 0)), + cg.Value(r.Coin() ? JsType::kString : JsType::kNumber, 1)))); + break; + case 6: + Push(out, cg.Stmt(mk::Unary(t, UnaryOp::kDelete, + mk::Index(t, a, cg.Integer())))); + break; + case 7: + Push(out, cg.Stmt(mk::CallMethod(t, a, "unshift", + {cg.Value(JsType::kUnknown, 1)}))); + break; + default: + Push(out, cg.Stmt(mk::Native(t, "NormalizeElements", {a}))); + break; + } + } + return true; +} + +GEN(FreezeSeal) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* object = cg.ObjectLike(); + Push(out, cg.Stmt(mk::CallMethod( + t, mk::Id(t, "Object"), + r.Pick({"freeze", "seal", "preventExtensions"}), {object}))); + return true; +} + +REDLINE_TUNABLE(kProxyDeclMaxTraps, "generators.ProxyDecl.max_traps", 3, 1, 64, + "most traps in the proxy handler"); +REDLINE_TUNABLE(kProxyDeclTrapMaxStatements, + "generators.ProxyDecl.trap_max_statements", 2, 0, 64, + "most statements in a trap body before its return"); + +GEN(ProxyDecl) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* target = cg.ObjectLike(); + std::vector<Node*> handler; + int n = 1 + r.SmallCount(kProxyDeclMaxTraps.AsInt() - 1); + for (int i = 0; i < n; i++) { + const char* trap = r.Pick({"get", "set", "has", "deleteProperty", "ownKeys", + "getOwnPropertyDescriptor", "apply", "construct", + "getPrototypeOf", "defineProperty"}); + std::string_view p1 = ctx.builder.FreshName("t"); + std::string_view p2 = ctx.builder.FreshName("k"); + GenContext nested = ctx.Nested(true, false, false, false); + nested.Declare(p1, JsType::kObject); + nested.Declare(p2, JsType::kUnknown); + CodeGen inner(nested); + Statements body = + inner.Body(nested, r.SmallCount(kProxyDeclTrapMaxStatements.AsInt())); + Expression* result = nullptr; + std::string_view trap_name = trap; + if (trap_name == "set" || trap_name == "has" || + trap_name == "deleteProperty" || trap_name == "defineProperty") { + result = mk::Bool(t, true); + } else if (trap_name == "ownKeys") { + result = + mk::CallMethod(t, mk::Id(t, "Reflect"), "ownKeys", {mk::Id(t, p1)}); + } else if (trap_name == "getOwnPropertyDescriptor") { + result = + mk::CallMethod(t, mk::Id(t, "Reflect"), "getOwnPropertyDescriptor", + {mk::Id(t, p1), mk::Id(t, p2)}); + } else if (trap_name == "getPrototypeOf") { + result = mk::CallMethod(t, mk::Id(t, "Reflect"), "getPrototypeOf", + {mk::Id(t, p1)}); + } else if (trap_name == "get") { + result = r.Coin() ? static_cast<Expression*>( + mk::CallMethod(t, mk::Id(t, "Reflect"), "get", + {mk::Id(t, p1), mk::Id(t, p2)})) + : inner.Value(JsType::kUnknown, 1); + } else { + result = inner.Value(JsType::kUnknown, 1); + } + body.push_back(mk::Return(t, result)); + handler.push_back( + mk::Method(t, trap, mk::Function(t, "", {p1, p2}, std::move(body)))); + } + Push(out, cg.Declare(mk::New(t, mk::Id(t, "Proxy"), + {target, mk::Object(t, std::move(handler))}), + JsType::kObject, "proxy")); + return true; +} + +REDLINE_TUNABLE(kWithMaxStatements, "generators.With.max_statements", 2, 1, 64, + "most statements in the with body"); + +GEN(With) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + WithStatement* w = t->New<WithStatement>(); + w->object = cg.ObjectLike(); + Statements body = + InnerBody(ctx, cg, false, false, kWithMaxStatements.AsInt()); + (void)r; + w->body = mk::Block(t, std::move(body)); + Push(out, w); + return true; +} + +REDLINE_TUNABLE(kShapeChangeMaxChanges, "generators.ShapeChange.max_changes", 4, + 1, 64, "most property additions/deletions on the object"); +REDLINE_TUNABLE( + kShapeChangeAddChance, "generators.ShapeChange.add_chance", 0.7, 0, 1, + "probability that a change stores a property rather than deleting one"); + +GEN(ShapeChange) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Identifier* object = cg.Variable(JsType::kObject); + if (object == nullptr) { + Statement* decl = cg.Declare(cg.ObjectLiteral(1), JsType::kObject, "obj"); + Push(out, decl); + object = mk::Id(t, decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + } + int n = 1 + r.SmallCount(kShapeChangeMaxChanges.AsInt() - 1); + for (int i = 0; i < n; i++) { + Identifier* o = mk::Id(t, object->name); + if (r.Chance(kShapeChangeAddChance())) { + std::string_view name = cg.PropertyName(); + if (name == "__proto__") { + name = "x"; + } + Push(out, cg.Stmt(mk::Assign(t, cg.Property(o, name), + cg.Value(JsType::kUnknown, 1)))); + } else { + Push(out, cg.Stmt(mk::Unary(t, UnaryOp::kDelete, cg.Property(o)))); + } + } + return true; +} + +REDLINE_TUNABLE(kIterationArrayTypeChance, + "generators.Iteration.array_type_chance", 0.75, 0, 1, + "probability that the result variable is declared as an array " + "rather than an object"); + +GEN(Iteration) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* source = cg.ObjectLike(); + Expression* v = nullptr; + switch (r.Index(4)) { + case 0: + v = mk::CallMethod(t, mk::Id(t, "Array"), "from", {source}); + break; + case 1: + v = mk::Array(t, {mk::Spread(t, source)}); + break; + case 2: + v = mk::Object(t, {mk::Spread(t, source)}); + break; + default: + v = mk::CallMethod( + t, mk::Id(t, "Object"), + r.Pick({"keys", "values", "entries", "getOwnPropertyNames"}), + {source}); + break; + } + Push(out, cg.Declare(v, + r.Chance(kIterationArrayTypeChance()) ? JsType::kArray + : JsType::kObject, + "arr")); + return true; +} + +// --- discovered APIs and builtin plumbing +// ----------------------------------------- + +// "Intl.NumberFormat" -> Intl.NumberFormat (a member chain on identifiers). +Expression* PathExpression(Tree* t, std::string_view path) { + size_t dot = path.find('.'); + Expression* e = mk::Id(t, path.substr(0, dot)); + while (dot != std::string_view::npos) { + size_t next = path.find('.', dot + 1); + std::string_view part = path.substr(dot + 1, next == std::string_view::npos + ? std::string_view::npos + : next - dot - 1); + e = IsIdentifierName(part) + ? static_cast<Expression*>(mk::Member(t, e, part)) + : static_cast<Expression*>(mk::Index(t, e, mk::Str(t, part))); + dot = next; + } + return e; +} + +Expression* MemberOf(Tree* t, Expression* object, std::string_view name) { + if (IsIdentifierName(name)) { + return mk::Member(t, object, name); + } + return mk::Index(t, object, mk::Str(t, name)); +} + +// The name declared by the last cg.Declare() (it registers the variable at +// the front of the visible list). +std::string_view LastDeclared(GenContext& ctx) { + return ctx.visible.front().name; +} + +// A value produced by something the target reported about itself: an +// instance of a discovered class, or the result of a discovered function or +// namespace static. nullptr if nothing was discovered. Such values are the +// embedder's own object kinds (API objects, interceptors, access-checked +// objects, ...), which plain generation never produces. `*source` receives +// the API the value came from. +Expression* DiscoveredValue(GenContext& ctx, CodeGen& cg, + const DiscoveredApi** source = nullptr) { + const std::vector<DiscoveredApi>& apis = ctx.env.discovered(); + if (apis.empty()) { + return nullptr; + } + Random& r = ctx.rng(); + Tree* t = T(ctx); + // Draw by surface: a namespace counts once per static it offers, a + // function or constructor once, so every producer the target reported + // is equally likely regardless of how the embedder grouped them. + size_t total = 0; + for (const DiscoveredApi& a : apis) { + total += a.kind == DiscoveredApi::Kind::kNamespace ? a.statics.size() : 1; + } + if (total == 0) { + return nullptr; + } + size_t pick = r.Index(total); + const DiscoveredApi* found = nullptr; + for (const DiscoveredApi& a : apis) { + size_t weight = + a.kind == DiscoveredApi::Kind::kNamespace ? a.statics.size() : 1; + if (pick < weight) { + found = &a; + break; + } + pick -= weight; + } + if (found == nullptr) { + return nullptr; // not reachable: the weights sum to `total` + } + const DiscoveredApi& api = *found; + if (source != nullptr) { + *source = &api; + } + switch (api.kind) { + case DiscoveredApi::Kind::kConstructor: + return mk::New(t, PathExpression(t, api.path), + cg.Arguments(0, api.arity)); + case DiscoveredApi::Kind::kFunction: + return mk::Call(t, PathExpression(t, api.path), + cg.Arguments(0, api.arity)); + case DiscoveredApi::Kind::kNamespace: + if (api.statics.empty()) { + return nullptr; + } + const DiscoveredMember& m = r.Pick(api.statics); + return mk::Call(t, MemberOf(t, PathExpression(t, api.path), m.name), + cg.Arguments(0, m.arity)); + } + return nullptr; +} + +// A discovered function or namespace static called with `value` as its +// first argument (the rest random): hands an object the program built back +// to the embedder's API. With `preferred` (the API the value came from) the +// function is taken from that API first: the functions of one namespace +// usually operate on each other's objects. nullptr if there is no such +// function. +Expression* DiscoveredCallOn(GenContext& ctx, CodeGen& cg, Expression* value, + const DiscoveredApi* preferred = nullptr) { + const std::vector<DiscoveredApi>& apis = ctx.env.discovered(); + if (apis.empty()) { + return nullptr; + } + Random& r = ctx.rng(); + Tree* t = T(ctx); + for (int attempt = 0; attempt < 8; attempt++) { + const DiscoveredApi& api = preferred != nullptr && attempt < 4 + ? *preferred + : apis[r.Index(apis.size())]; + Expression* callee = nullptr; + int arity = 0; + if (api.kind == DiscoveredApi::Kind::kFunction && + (api.statics.empty() || r.Coin())) { + callee = PathExpression(t, api.path); + arity = api.arity; + } else if (!api.statics.empty()) { + const DiscoveredMember& m = r.Pick(api.statics); + callee = MemberOf(t, PathExpression(t, api.path), m.name); + arity = m.arity; + } + if (callee == nullptr || arity < 1) { + continue; + } + std::vector<Expression*> args = cg.Arguments(0, arity - 1); + args.insert(args.begin(), value); + return mk::Call(t, callee, std::move(args)); + } + return nullptr; +} + +// Signatures are unknown, so most calls are guarded; the unguarded +// minority keeps exceptions (and their handlers) in the picture. +REDLINE_TUNABLE(kDiscoveredApiGuardChance, + "generators.DiscoveredApi.guard_chance", 0.8, 0, 1, + "probability that a discovered-API construction, call or " + "getter load is wrapped in a try/catch"); +REDLINE_TUNABLE(kDiscoveredApiConstructorStaticChance, + "generators.DiscoveredApi.constructor_static_chance", 0.25, 0, + 1, + "probability of calling a static of a discovered constructor " + "instead of constructing an instance"); +REDLINE_TUNABLE(kDiscoveredApiMethodChance, + "generators.DiscoveredApi.method_chance", 0.85, 0, 1, + "probability of calling a prototype method on the new instance " + "rather than loading a getter"); +REDLINE_TUNABLE(kDiscoveredApiFunctionStaticChance, + "generators.DiscoveredApi.function_static_chance", 0.3, 0, 1, + "probability of calling a static of a discovered function " + "instead of the function itself"); +REDLINE_TUNABLE(kDiscoveredApiNamespaceStaticChance, + "generators.DiscoveredApi.namespace_static_chance", 0.8, 0, 1, + "probability of calling a static of a discovered namespace " + "rather than loading one of its getters"); + +// Uses something the target itself reported to exist (see +// Environment::IntrospectionScript): constructs a discovered class and calls +// one of its prototype methods or loads a getter, calls a static method of a +// namespace/class, or calls a discovered function. The result variables are +// untyped; the Explore mutator takes it from there. +GEN(DiscoveredApi) { + const std::vector<DiscoveredApi>& apis = ctx.env.discovered(); + if (apis.empty()) { + return false; + } + Random& r = ctx.rng(); + Tree* t = T(ctx); + const DiscoveredApi& api = apis[r.Index(apis.size())]; + auto call_static = [&](const DiscoveredMember& m) { + cg.DeclareMaybeGuarded( + out, + mk::Call(t, MemberOf(t, PathExpression(t, api.path), m.name), + cg.Arguments(0, m.arity)), + JsType::kUnknown, "r", kDiscoveredApiGuardChance()); + }; + switch (api.kind) { + case DiscoveredApi::Kind::kConstructor: { + if (!api.statics.empty() && + r.Chance(kDiscoveredApiConstructorStaticChance())) { + call_static(r.Pick(api.statics)); + return true; + } + Expression* value = + mk::New(t, PathExpression(t, api.path), cg.Arguments(0, api.arity)); + cg.DeclareMaybeGuarded(out, value, JsType::kObject, "o", + kDiscoveredApiGuardChance()); + std::string_view name = LastDeclared(ctx); + if (!api.methods.empty() && r.Chance(kDiscoveredApiMethodChance())) { + const DiscoveredMember& m = r.Pick(api.methods); + cg.DeclareMaybeGuarded(out, + mk::Call(t, MemberOf(t, mk::Id(t, name), m.name), + cg.Arguments(0, m.arity)), + JsType::kUnknown, "r", + kDiscoveredApiGuardChance()); + } else if (!api.getters.empty()) { + cg.DeclareMaybeGuarded( + out, MemberOf(t, mk::Id(t, name), r.Pick(api.getters).name), + JsType::kUnknown, "r", kDiscoveredApiGuardChance()); + } + return true; + } + case DiscoveredApi::Kind::kFunction: + if (!api.statics.empty() && + r.Chance(kDiscoveredApiFunctionStaticChance())) { + call_static(r.Pick(api.statics)); + return true; + } + cg.DeclareMaybeGuarded( + out, + mk::Call(t, PathExpression(t, api.path), cg.Arguments(0, api.arity)), + JsType::kUnknown, "r", kDiscoveredApiGuardChance()); + return true; + case DiscoveredApi::Kind::kNamespace: + if (!api.statics.empty() && + (api.getters.empty() || + r.Chance(kDiscoveredApiNamespaceStaticChance()))) { + call_static(r.Pick(api.statics)); + return true; + } + if (api.getters.empty()) { + return false; + } + cg.DeclareMaybeGuarded( + out, + MemberOf(t, PathExpression(t, api.path), r.Pick(api.getters).name), + JsType::kUnknown, "r", kDiscoveredApiGuardChance()); + return true; + } + return false; +} + +REDLINE_TUNABLE(kPrototypeMethodCallObjectReceiverChance, + "generators.PrototypeMethodCall.object_receiver_chance", 0.7, 0, + 1, + "probability that the foreign receiver is an object-like value " + "rather than any value"); +REDLINE_TUNABLE( + kPrototypeMethodCallCallChance, + "generators.PrototypeMethodCall.call_chance", 0.7, 0, 1, + "probability of invoking the method with .call rather than .apply"); +REDLINE_TUNABLE(kPrototypeMethodCallGuardChance, + "generators.PrototypeMethodCall.guard_chance", 0.8, 0, 1, + "probability that the invocation is wrapped in a try/catch"); + +// A builtin prototype method applied to an unrelated receiver: +// `Array.prototype.map.call(obj, f)`, `String.prototype.at.call(123, 0)`. +GEN(PrototypeMethodCall) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + struct Entry { + const char* ctor; + JsType type; + }; + static const Entry kEntries[] = {{"Array", JsType::kArray}, + {"String", JsType::kString}, + {"Object", JsType::kObject}, + {"Function", JsType::kFunction}, + {"Map", JsType::kMap}, + {"Set", JsType::kSet}, + {"Promise", JsType::kPromise}, + {"RegExp", JsType::kRegExp}, + {"Date", JsType::kDate}, + {"Number", JsType::kNumber}, + {"Uint8Array", JsType::kTypedArray}}; + const Entry& e = kEntries[r.Index(sizeof(kEntries) / sizeof(kEntries[0]))]; + const BuiltinType* bt = ctx.env.ForType(e.type); + if (bt == nullptr || bt->methods.empty()) { + return false; + } + const BuiltinFunction& m = r.Pick(bt->methods); + Expression* method = + mk::Member(t, mk::Member(t, mk::Id(t, e.ctor), "prototype"), m.name); + Expression* receiver = r.Chance(kPrototypeMethodCallObjectReceiverChance()) + ? cg.ObjectLike() + : cg.Value(JsType::kUnknown, 1); + std::vector<Expression*> args = cg.Arguments(m); + Expression* call; + if (r.Chance(kPrototypeMethodCallCallChance())) { + args.insert(args.begin(), receiver); + call = mk::CallMethod(t, method, "call", std::move(args)); + } else { + call = mk::CallMethod(t, method, "apply", + {receiver, mk::Array(t, std::move(args))}); + } + cg.DeclareMaybeGuarded(out, call, m.result, "r", + kPrototypeMethodCallGuardChance()); + return true; +} + +REDLINE_TUNABLE(kUnboundMethodCallMaxArgs, + "generators.UnboundMethodCall.max_args", 2, 0, 16, + "most arguments when the method is a generic name rather than " + "a known builtin"); +REDLINE_TUNABLE(kUnboundMethodCallBuiltinChance, + "generators.UnboundMethodCall.builtin_chance", 0.8, 0, 1, + "probability of taking a builtin method of the object's type " + "rather than a generic method name"); +REDLINE_TUNABLE(kUnboundMethodCallMethodGuardChance, + "generators.UnboundMethodCall.method_guard_chance", 0.5, 0, 1, + "probability that the method load is wrapped in a try/catch"); +REDLINE_TUNABLE(kUnboundMethodCallObjectReceiverChance, + "generators.UnboundMethodCall.object_receiver_chance", 0.6, 0, + 1, + "probability that the new receiver is an object-like value " + "rather than any value"); +REDLINE_TUNABLE(kUnboundMethodCallCallGuardChance, + "generators.UnboundMethodCall.call_guard_chance", 0.8, 0, 1, + "probability that the call/apply/bind invocation is wrapped in " + "a try/catch"); + +// A method taken off its object and invoked with another `this`, or bound: +// `const m = obj.method; m.call(other, ...)`, `obj.method.bind(other)(...)`. +GEN(UnboundMethodCall) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Identifier* object = cg.Variable(JsType::kUnknown); + if (object == nullptr) { + return false; + } + JsType type = JsType::kUnknown; + for (const Variable& v : ctx.visible) { + if (v.name == object->name) { + type = v.type; + break; + } + } + const BuiltinType* bt = ctx.env.ForType(type); + std::string_view method_name; + int min_args = 0, max_args = kUnboundMethodCallMaxArgs.AsInt(); + if (bt != nullptr && !bt->methods.empty() && + r.Chance(kUnboundMethodCallBuiltinChance())) { + const BuiltinFunction& m = r.Pick(bt->methods); + method_name = m.name; + min_args = m.min_args; + max_args = m.max_args; + } else { + method_name = r.Pick({"toString", "valueOf", "call", "apply", "bind", + "constructor", "hasOwnProperty", "toLocaleString"}); + } + cg.DeclareMaybeGuarded(out, MemberOf(t, mk::Id(t, object->name), method_name), + JsType::kFunction, "m", + kUnboundMethodCallMethodGuardChance()); + std::string_view m = LastDeclared(ctx); + Expression* receiver = r.Chance(kUnboundMethodCallObjectReceiverChance()) + ? cg.ObjectLike() + : cg.Value(JsType::kUnknown, 1); + std::vector<Expression*> args = cg.Arguments(min_args, max_args); + Expression* call; + switch (r.Index(3)) { + case 0: + args.insert(args.begin(), receiver); + call = mk::CallMethod(t, mk::Id(t, m), "call", std::move(args)); + break; + case 1: + call = mk::CallMethod(t, mk::Id(t, m), "apply", + {receiver, mk::Array(t, std::move(args))}); + break; + default: + call = mk::Call(t, mk::CallMethod(t, mk::Id(t, m), "bind", {receiver}), + std::move(args)); + break; + } + cg.DeclareMaybeGuarded(out, call, JsType::kUnknown, "r", + kUnboundMethodCallCallGuardChance()); + return true; +} + +REDLINE_TUNABLE(kBuiltinOverwritePrototypeChance, + "generators.BuiltinOverwrite.prototype_chance", 0.6, 0, 1, + "probability of overwriting a prototype method rather than a " + "static method of a namespace"); +REDLINE_TUNABLE(kBuiltinOverwriteSymbolChance, + "generators.BuiltinOverwrite.symbol_chance", 0.25, 0, 1, + "probability that the overwritten prototype member is a " + "well-known symbol hook rather than a named method"); +REDLINE_TUNABLE(kBuiltinOverwriteCallableChance, + "generators.BuiltinOverwrite.callable_chance", 0.3, 0, 1, + "probability that the replacement is an existing callable " + "rather than a fresh function"); + +// Replaces a builtin (prototype) method or a well-known symbol hook by a +// function of our own: `Array.prototype.join = function(...) {...}`, +// `Object.prototype[Symbol.toPrimitive] = ...`, `Math.max = ...`. +GEN(BuiltinOverwrite) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* target = nullptr; + if (r.Chance(kBuiltinOverwritePrototypeChance())) { + struct Entry { + const char* ctor; + JsType type; + }; + static const Entry kEntries[] = { + {"Array", JsType::kArray}, {"String", JsType::kString}, + {"Object", JsType::kObject}, {"Function", JsType::kFunction}, + {"Number", JsType::kNumber}, {"RegExp", JsType::kRegExp}, + {"Promise", JsType::kPromise}, {"Map", JsType::kMap}}; + const Entry& e = kEntries[r.Index(sizeof(kEntries) / sizeof(kEntries[0]))]; + const BuiltinType* bt = ctx.env.ForType(e.type); + if (bt == nullptr || bt->methods.empty()) { + return false; + } + Expression* proto = mk::Member(t, mk::Id(t, e.ctor), "prototype"); + if (r.Chance(kBuiltinOverwriteSymbolChance())) { + target = mk::Index( + t, proto, + mk::Member(t, mk::Id(t, "Symbol"), + r.Pick({"iterator", "toPrimitive", "hasInstance", + "species", "toStringTag", "isConcatSpreadable", + "match", "replace", "split"}))); + } else { + target = mk::Member(t, proto, r.Pick(bt->methods).name); + } + } else { + std::vector<const BuiltinGlobal*> namespaces; + for (const BuiltinGlobal& g : ctx.env.globals()) { + if (!g.static_methods.empty()) { + namespaces.push_back(&g); + } + } + if (namespaces.empty()) { + return false; + } + const BuiltinGlobal& g = *r.Pick(namespaces); + target = mk::Member(t, mk::Id(t, g.name), r.Pick(g.static_methods).name); + } + Expression* replacement = r.Chance(kBuiltinOverwriteCallableChance()) + ? static_cast<Expression*>(cg.Callable()) + : cg.FunctionValue(ctx.depth + 1); + Push(out, cg.Stmt(mk::Assign(t, target, replacement))); + return true; +} + +REDLINE_TUNABLE(kConstructorFunctionMinParams, + "generators.ConstructorFunction.min_params", 1, 1, 16, + "fewest parameters of the constructor function (the first one " + "is passed to the new.target fallback)"); +REDLINE_TUNABLE(kConstructorFunctionMaxParams, + "generators.ConstructorFunction.max_params", 3, 1, 16, + "most parameters of the constructor function"); +REDLINE_TUNABLE(kConstructorFunctionMaxFields, + "generators.ConstructorFunction.max_fields", 4, 1, 64, + "most this.x = ... initializations in the constructor body"); +REDLINE_TUNABLE(kConstructorFunctionParamFieldChance, + "generators.ConstructorFunction.param_field_chance", 0.6, 0, 1, + "probability that a field is initialized from the matching " + "parameter rather than a fresh value"); +REDLINE_TUNABLE( + kConstructorFunctionLengthChance, + "generators.ConstructorFunction.length_chance", 0.3, 0, 1, + "probability of an extra this.length = <integer> initialization"); +REDLINE_TUNABLE(kConstructorFunctionPrototypeMethodChance, + "generators.ConstructorFunction.prototype_method_chance", 0.3, + 0, 1, "probability of adding a method to C.prototype"); + +// A constructor function in the old style, with `new.target`, `this.x =` +// initialization, default and rest parameters, then instantiated. +GEN(ConstructorFunction) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view name = ctx.builder.FreshName("C"); + GenContext nested = ctx.Nested(true, false, false, false); + std::vector<std::string_view> params; + int np = static_cast<int>(r.Range(kConstructorFunctionMinParams.AsInt(), + kConstructorFunctionMaxParams.AsInt())); + for (int i = 0; i < np; i++) { + std::string_view p = ctx.builder.FreshName("a"); + params.push_back(p); + nested.Declare(p, JsType::kUnknown); + } + CodeGen inner(nested); + Statements body; + // if (!new.target) { throw ... } / return new C(...) + body.push_back( + mk::If(t, mk::Unary(t, UnaryOp::kNot, mk::NewTarget(t)), + mk::Block(t, {mk::Return(t, mk::New(t, mk::Id(t, name), + {mk::Id(t, params[0])}))}))); + int fields = 1 + r.SmallCount(kConstructorFunctionMaxFields.AsInt() - 1); + for (int i = 0; i < fields; i++) { + Expression* value = + i < np && r.Chance(kConstructorFunctionParamFieldChance()) + ? static_cast<Expression*>( + mk::Id(t, params[static_cast<size_t>(i)])) + : inner.Value(JsType::kUnknown, 1); + body.push_back(mk::ExprStmt( + t, mk::Assign(t, + mk::Member(t, mk::This(t), + ctx.env.property_names()[r.Index(12)]), + value))); + } + if (r.Chance(kConstructorFunctionLengthChance())) { + body.push_back(mk::ExprStmt( + t, + mk::Assign(t, mk::Member(t, mk::This(t), "length"), inner.Integer()))); + } + FunctionDeclaration* decl = + mk::FunctionDecl(t, name, params, std::move(body)); + Push(out, decl); + ctx.Declare(name, JsType::kClass); + if (r.Chance(kConstructorFunctionPrototypeMethodChance())) { + // A prototype method that uses this. + GenContext method_ctx = ctx.Nested(true, false, false, false); + CodeGen method_cg(method_ctx); + Statements mbody; + mbody.push_back(mk::Return( + t, mk::Member(t, mk::This(t), ctx.env.property_names()[r.Index(12)]))); + Push(out, cg.Stmt(mk::Assign( + t, + mk::Member(t, mk::Member(t, mk::Id(t, name), "prototype"), + r.Pick({"get", "valueOf", "toString", "m", "f"})), + mk::Function(t, "", {}, std::move(mbody))))); + } + Push(out, cg.Declare(mk::New(t, mk::Id(t, name), cg.Arguments(0, np)), + JsType::kObject, "o")); + return true; +} + +// --- async / generators +// --------------------------------------------------------- + +GEN(Await) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* value = nullptr; + switch (r.Index(4)) { + case 0: + value = cg.Value(JsType::kPromise, 1); + break; + case 1: + value = mk::CallMethod(t, mk::Id(t, "Promise"), + r.Coin() ? "resolve" : "reject", + {cg.Value(JsType::kUnknown, 1)}); + break; + default: + value = cg.Value(JsType::kUnknown, 1); + break; + } + Expression* a = mk::Await(t, value); + if (r.Coin()) { + Push(out, cg.Declare(a, JsType::kUnknown)); + } else { + Push(out, cg.Stmt(a)); + } + return true; +} + +REDLINE_TUNABLE(kYieldDelegateChance, "generators.Yield.delegate_chance", 0.2, + 0, 1, "probability of yield* over an array"); +REDLINE_TUNABLE(kYieldValueChance, "generators.Yield.value_chance", 0.9, 0, 1, + "probability that a plain yield has a value"); + +GEN(Yield) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* y = nullptr; + if (r.Chance(kYieldDelegateChance())) { + Expression* iterable = cg.Variable(JsType::kArray); + if (iterable == nullptr) { + iterable = cg.ArrayLiteral(1); + } + y = mk::Yield(t, iterable, /*delegate=*/true); + } else { + y = mk::Yield(t, r.Chance(kYieldValueChance()) + ? cg.Value(JsType::kUnknown, 1) + : nullptr); + } + if (r.Coin()) { + Push(out, cg.Declare(y, JsType::kUnknown)); + } else { + Push(out, cg.Stmt(y)); + } + return true; +} + +REDLINE_TUNABLE(kAsyncIifeMaxStatements, "generators.AsyncIife.max_statements", + 4, 1, 64, "most statements in the async IIFE body"); + +GEN(AsyncIife) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + GenContext nested = ctx.Nested(true, true, true, false); + CodeGen inner(nested); + Statements body = + inner.Body(nested, 1 + r.SmallCount(kAsyncIifeMaxStatements.AsInt() - 1)); + // Make sure there is an await in there. + Statements await_stmt; + GenAwait(nested, inner, &await_stmt); + body.insert( + body.begin() + static_cast<std::ptrdiff_t>(r.Index(body.size() + 1)), + await_stmt.begin(), await_stmt.end()); + Expression* fn = mk::Arrow(t, {}, std::move(body), /*is_async=*/true); + Expression* call = mk::Call(t, fn, {}); + if (r.Coin()) { + Push(out, cg.Declare(call, JsType::kPromise, "p")); + } else { + Push(out, cg.Stmt(call)); + } + return true; +} + +REDLINE_TUNABLE(kGeneratorIterateMaxStatements, + "generators.GeneratorIterate.max_statements", 2, 0, 64, + "most statements in the generator body besides the yields"); +REDLINE_TUNABLE(kGeneratorIterateMaxYields, + "generators.GeneratorIterate.max_yields", 4, 1, 64, + "most yields in the generator body"); +REDLINE_TUNABLE( + kGeneratorIterateLoopMaxStatements, + "generators.GeneratorIterate.loop_max_statements", 3, 1, 64, + "most statements in the for-of body that consumes the generator"); +REDLINE_TUNABLE(kGeneratorIterateMaxSteps, + "generators.GeneratorIterate.max_steps", 4, 1, 64, + "most manual it.next()/it.return() steps when the generator is " + "not consumed by a loop"); +REDLINE_TUNABLE( + kGeneratorIterateNextChance, "generators.GeneratorIterate.next_chance", 0.8, + 0, 1, + "probability that a manual step is it.next() rather than it.return()"); + +GEN(GeneratorIterate) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + // function* g() { yield ...; } for (const x of g()) {...} + std::string_view name = ctx.builder.FreshName("gen"); + GenContext nested = ctx.Nested(true, false, false, true); + CodeGen inner(nested); + Statements body = + inner.Body(nested, r.SmallCount(kGeneratorIterateMaxStatements.AsInt())); + int yields = 1 + r.SmallCount(kGeneratorIterateMaxYields.AsInt() - 1); + for (int i = 0; i < yields; i++) { + Statements y; + GenYield(nested, inner, &y); + body.insert( + body.begin() + static_cast<std::ptrdiff_t>(r.Index(body.size() + 1)), + y.begin(), y.end()); + } + Push(out, mk::FunctionDecl(t, name, {}, std::move(body), false, true)); + ctx.Declare(name, JsType::kFunction); + if (r.Coin()) { + std::string_view e = ctx.builder.FreshName("e"); + GenContext loop = ctx.Inner(true, false); + loop.Declare(e, JsType::kUnknown); + CodeGen lcg(loop); + Statements lbody = lcg.Body( + loop, 1 + r.SmallCount(kGeneratorIterateLoopMaxStatements.AsInt() - 1)); + Push(out, + mk::ForOf(t, VariableKind::kConst, e, mk::Call(t, mk::Id(t, name), {}), + mk::Block(t, std::move(lbody)))); + } else { + Statement* it = + cg.Declare(mk::Call(t, mk::Id(t, name), {}), JsType::kObject, "it"); + Push(out, it); + std::string_view it_name = it->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name; + int steps = 1 + r.SmallCount(kGeneratorIterateMaxSteps.AsInt() - 1); + for (int i = 0; i < steps; i++) { + Push(out, + cg.Declare( + mk::CallMethod( + t, mk::Id(t, it_name), + r.Chance(kGeneratorIterateNextChance()) ? "next" : "return", + r.Coin() ? std::vector<Expression*>{} + : std::vector<Expression*>{cg.Value( + JsType::kUnknown, 1)}), + JsType::kObject)); + } + } + return true; +} + +REDLINE_TUNABLE(kPromiseThenResolveChance, + "generators.PromiseThen.resolve_chance", 0.8, 0, 1, + "probability of Promise.resolve rather than Promise.reject " + "when no promise variable is visible"); +REDLINE_TUNABLE( + kPromiseThenMaxStatements, "generators.PromiseThen.max_statements", 3, 1, + 64, "most statements in the fulfillment callback before its return"); +REDLINE_TUNABLE(kPromiseThenThenChance, "generators.PromiseThen.then_chance", + 0.8, 0, 1, "probability of .then rather than .finally"); + +GEN(PromiseThen) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* promise = nullptr; + if (Identifier* p = cg.Variable(JsType::kPromise)) { + promise = p; + } else { + promise = mk::CallMethod( + t, mk::Id(t, "Promise"), + r.Chance(kPromiseThenResolveChance()) ? "resolve" : "reject", + {cg.Value(JsType::kUnknown, 1)}); + } + std::string_view p = ctx.builder.FreshName("v"); + GenContext nested = ctx.Nested(true, true, false, false); + nested.Declare(p, JsType::kUnknown); + CodeGen inner(nested); + Statements body = inner.Body( + nested, 1 + r.SmallCount(kPromiseThenMaxStatements.AsInt() - 1)); + body.push_back(mk::Return(t, inner.Value(JsType::kUnknown, 1))); + std::vector<Expression*> args = {mk::Arrow(t, {p}, std::move(body))}; + if (r.Coin()) { + std::string_view e = ctx.builder.FreshName("e"); + args.push_back(mk::ArrowExpr(t, {e}, mk::Id(t, e))); + } + Expression* call = mk::CallMethod( + t, promise, r.Chance(kPromiseThenThenChance()) ? "then" : "finally", + std::move(args)); + if (r.Coin()) { + Push(out, cg.Declare(call, JsType::kPromise, "p")); + } else { + Push(out, cg.Stmt(call)); + } + return true; +} + +GEN(StringOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* s = cg.Value(JsType::kString, 1); + Expression* v = nullptr; + switch (r.Index(6)) { + case 0: + v = mk::Binary(t, BinaryOp::kAdd, s, cg.Value(JsType::kUnknown, 1)); + break; + case 1: + v = mk::CallMethod(t, s, "repeat", {cg.Integer()}); + break; + case 2: + v = mk::Index(t, s, cg.Integer()); + break; + case 3: + v = mk::Native(t, r.Pick({"InternalizeString", "FlattenString"}), {s}); + break; + case 4: + v = mk::CallMethod(t, s, + r.Pick({"charCodeAt", "codePointAt", "at", "slice", + "indexOf", "split"}), + {cg.Value(JsType::kUnknown, 1)}); + break; + default: { + Expression* target_str = + r.Coin() ? s : mk::Str(t, "a\u0301b\u0323c\u0304"); + v = mk::CallMethod(t, target_str, "normalize", + {mk::Str(t, r.Pick({"NFC", "NFD", "NFKC", "NFKD"}))}); + break; + } + } + Push(out, cg.Declare(v, JsType::kUnknown, "s")); + return true; +} + +REDLINE_TUNABLE(kIntlOpsMaxCalls, "generators.IntlOps.max_calls", 3, 1, 16, + "most method calls on the Intl object after its construction"); +REDLINE_TUNABLE(kIntlOpsGuardChance, "generators.IntlOps.guard_chance", 0.5, 0, + 1, + "probability that a call is wrapped in try/catch (values from " + "the program can make it throw)"); + +// One Intl service: a constructor, consistent options and its methods. The +// locales and options are valid, so that ICU's locale and formatting code +// runs instead of the argument checks. +GEN(IntlOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + auto str = [&](std::string_view s) -> Expression* { return mk::Str(t, s); }; + auto locale = [&]() -> Expression* { + static const char* const kLocales[] = {"en", + "en-US", + "de-DE", + "fr-CA", + "ja-JP", + "zh-Hant-TW", + "ar-EG", + "he-IL", + "th-TH-u-nu-thai", + "hi-IN", + "ru", + "tr", + "und", + "en-u-ca-buddhist", + "de-u-co-phonebk", + "es-419", + "sr-Latn-RS", + "pt-BR", + "ko-KR", + "fa-IR-u-nu-arabext", + "ja-JP-u-ca-japanese", + "en-GB-u-hc-h23"}; + auto pick = [&]() { + return str(kLocales[r.Index(sizeof(kLocales) / sizeof(kLocales[0]))]); + }; + switch (r.Index(5)) { + case 0: + return mk::Undefined(t); + case 1: + return mk::Array(t, {pick(), pick()}); + default: + return pick(); + } + }; + auto option = [&](std::vector<Node*>* props, std::string_view key, + std::initializer_list<const char*> values) { + props->push_back( + mk::Prop(t, key, str(*(values.begin() + r.Index(values.size()))))); + }; + auto number = [&]() -> Expression* { + return r.Coin() ? cg.Value(JsType::kNumber, 1) : cg.Number(); + }; + auto string = [&]() -> Expression* { + return r.Coin() ? cg.Value(JsType::kString, 1) : cg.String(); + }; + auto date = [&]() -> Expression* { + return mk::New( + t, mk::Id(t, "Date"), + {r.Coin() + ? number() + : mk::Num(t, 1.7e12 + static_cast<double>(r.Range(0, 1000000)))}); + }; + + std::vector<Node*> props; + std::string_view ctor; + std::vector<std::pair<std::string_view, int>> + methods; // name, kind of argument + enum { + kNumberArg, + kStringArg, + kDateArg, + kTwoNumbers, + kTwoDates, + kTwoStrings, + kStringList, + kNone, + kUnit + }; + switch (r.Index(10)) { + case 0: { + ctor = "NumberFormat"; + const char* style = r.Pick({"decimal", "percent", "currency", "unit"}); + props.push_back(mk::Prop(t, "style", str(style))); + if (std::string_view(style) == "currency") { + option(&props, "currency", {"EUR", "JPY", "USD", "BHD", "CHF"}); + option(&props, "currencyDisplay", + {"symbol", "code", "name", "narrowSymbol"}); + } + if (std::string_view(style) == "unit") { + option(&props, "unit", + {"kilometer-per-hour", "liter", "byte", "percent", "celsius"}); + option(&props, "unitDisplay", {"short", "long", "narrow"}); + } + if (r.Coin()) { + option(&props, "notation", + {"standard", "scientific", "engineering", "compact"}); + } + if (r.Coin()) { + option(&props, "signDisplay", + {"auto", "always", "exceptZero", "negative", "never"}); + } + if (r.Coin()) { + option(&props, "roundingMode", + {"ceil", "floor", "halfEven", "halfExpand", "trunc"}); + props.push_back(mk::Prop(t, "maximumFractionDigits", + mk::Num(t, static_cast<double>(r.Index(6))))); + } + methods = {{"format", kNumberArg}, + {"formatToParts", kNumberArg}, + {"formatRange", kTwoNumbers}, + {"resolvedOptions", kNone}}; + break; + } + case 1: { + ctor = "DateTimeFormat"; + if (r.Coin()) { + option(&props, "dateStyle", {"full", "long", "medium", "short"}); + option(&props, "timeStyle", {"full", "long", "medium", "short"}); + } else { + option(&props, "weekday", {"long", "short", "narrow"}); + option(&props, "hour", {"numeric", "2-digit"}); + option(&props, "era", {"long", "short", "narrow"}); + if (r.Coin()) { + props.push_back( + mk::Prop(t, "fractionalSecondDigits", + mk::Num(t, static_cast<double>(1 + r.Index(3))))); + } + } + option(&props, "timeZone", + {"UTC", "Asia/Kolkata", "America/New_York", "Europe/Berlin", + "Pacific/Chatham"}); + if (r.Coin()) { + option(&props, "calendar", + {"gregory", "islamic", "hebrew", "japanese", "chinese", + "ethiopic"}); + } + methods = {{"format", kDateArg}, + {"formatToParts", kDateArg}, + {"formatRange", kTwoDates}, + {"formatRangeToParts", kTwoDates}, + {"resolvedOptions", kNone}}; + break; + } + case 2: + ctor = "Collator"; + option(&props, "sensitivity", {"base", "accent", "case", "variant"}); + if (r.Coin()) { + props.push_back(mk::Prop(t, "numeric", mk::Bool(t, r.Coin()))); + option(&props, "caseFirst", {"upper", "lower", "false"}); + } + option(&props, "usage", {"sort", "search"}); + methods = {{"compare", kTwoStrings}, {"resolvedOptions", kNone}}; + break; + case 3: + ctor = "PluralRules"; + option(&props, "type", {"cardinal", "ordinal"}); + methods = {{"select", kNumberArg}, + {"selectRange", kTwoNumbers}, + {"resolvedOptions", kNone}}; + break; + case 4: + ctor = "RelativeTimeFormat"; + option(&props, "numeric", {"always", "auto"}); + option(&props, "style", {"long", "short", "narrow"}); + methods = {{"format", kUnit}, + {"formatToParts", kUnit}, + {"resolvedOptions", kNone}}; + break; + case 5: + ctor = "ListFormat"; + option(&props, "type", {"conjunction", "disjunction", "unit"}); + option(&props, "style", {"long", "short", "narrow"}); + methods = {{"format", kStringList}, + {"formatToParts", kStringList}, + {"resolvedOptions", kNone}}; + break; + case 6: + ctor = "DisplayNames"; + option(&props, "type", + {"region", "language", "script", "currency", "calendar", + "dateTimeField"}); + option(&props, "fallback", {"code", "none"}); + methods = {{"of", kStringArg}, {"resolvedOptions", kNone}}; + break; + case 7: + ctor = "Segmenter"; + option(&props, "granularity", {"grapheme", "word", "sentence"}); + methods = {{"segment", kStringArg}, {"resolvedOptions", kNone}}; + break; + case 8: + ctor = "DurationFormat"; + option(&props, "style", {"long", "short", "narrow", "digital"}); + methods = {{"format", kNone}, + {"formatToParts", kNone}, + {"resolvedOptions", kNone}}; + break; + default: { + // Primitive methods that take locales and options. + Expression* v = nullptr; + switch (r.Index(4)) { + case 0: + v = mk::CallMethod(t, number(), "toLocaleString", {locale()}); + break; + case 1: + v = mk::CallMethod( + t, date(), r.Pick({"toLocaleDateString", "toLocaleTimeString"}), + {locale()}); + break; + case 2: + v = mk::CallMethod(t, string(), "localeCompare", + {string(), locale()}); + break; + default: + v = mk::CallMethod(t, string(), + r.Pick({"toLocaleUpperCase", "toLocaleLowerCase"}), + {locale()}); + break; + } + cg.DeclareMaybeGuarded(out, v, JsType::kUnknown, "loc", + kIntlOpsGuardChance()); + return true; + } + } + // const f = new Intl.X(locales, {...}); + Expression* construct = mk::New(t, mk::Member(t, mk::Id(t, "Intl"), ctor), + {locale(), mk::Object(t, std::move(props))}); + Statement* decl = cg.Declare(construct, JsType::kObject, "intl"); + Push(out, decl); + std::string_view name = decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name; + int calls = 1 + static_cast<int>( + r.Index(static_cast<size_t>(kIntlOpsMaxCalls.AsInt()))); + for (int i = 0; i < calls; i++) { + const auto& method = methods[r.Index(methods.size())]; + std::vector<Expression*> args; + switch (method.second) { + case kNumberArg: + args = {r.Chance(0.2) ? cg.BigInt() : number()}; + break; + case kStringArg: + args = {r.Chance(0.5) + ? str(r.Pick({"US", "de", "Latn", "EUR", "gregory", "era", + "a\u0301b\U0001F600c d."})) + : string()}; + break; + case kDateArg: + args = {date()}; + break; + case kTwoNumbers: + args = {number(), number()}; + break; + case kTwoDates: + args = {date(), date()}; + break; + case kTwoStrings: + args = {string(), string()}; + break; + case kStringList: + args = {mk::Array(t, {string(), string(), str("x")})}; + break; + case kUnit: + args = {number(), + str(r.Pick({"second", "minutes", "day", "quarter", "years"}))}; + break; + default: + if (ctor == "DurationFormat" && method.first != "resolvedOptions") { + args = {mk::Object( + t, {mk::Prop(t, "hours", + mk::Num(t, static_cast<double>(r.Index(30)))), + mk::Prop(t, "minutes", number())})}; + } + break; + } + Expression* call = + mk::CallMethod(t, mk::Id(t, name), method.first, std::move(args)); + if (method.first == "segment" && r.Coin()) { + call = mk::Array(t, {mk::Spread(t, call)}); // iterate the segments + } + cg.DeclareMaybeGuarded(out, call, JsType::kUnknown, "r", + kIntlOpsGuardChance()); + } + return true; +} + +REDLINE_TUNABLE(kTypedArrayOpsMaxArgs, "generators.TypedArrayOps.max_args", 2, + 0, 16, "most arguments passed to a typed array method"); + +GEN(TypedArrayOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Identifier* ta = cg.Variable(JsType::kTypedArray); + if (ta == nullptr) { + Expression* ctor = cg.Construct(JsType::kTypedArray); + if (ctor == nullptr) { + return false; + } + Statement* decl = cg.Declare(ctor, JsType::kTypedArray, "ta"); + Push(out, decl); + ta = mk::Id(t, decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + } + Identifier* a = mk::Id(t, ta->name); + + std::vector<const char*> all_kinds = { + "Uint8Array", "Uint8ClampedArray", "Int8Array", "Uint16Array", + "Int16Array", "Uint32Array", "Int32Array", "Float32Array", + "Float64Array", "BigInt64Array", "BigUint64Array"}; + if (cg.env().Global("Float16Array") != nullptr) { + all_kinds.push_back("Float16Array"); + } + const char* random_kind = r.Pick(all_kinds); + + switch (r.Index(8)) { + case 0: + Push(out, cg.Stmt(mk::Assign(t, mk::Index(t, a, cg.Integer()), + cg.Value(JsType::kNumber, 1)))); + break; + case 1: + Push(out, cg.Declare(mk::Index(t, a, cg.Integer()), JsType::kNumber)); + break; + case 2: + Push(out, cg.Stmt(mk::Native(t, "ArrayBufferDetach", + {mk::Member(t, a, "buffer")}))); + break; + case 3: + Push(out, cg.Declare(mk::CallMethod( + t, a, r.Pick({"fill", "map", "sort"}), + cg.Arguments(0, kTypedArrayOpsMaxArgs.AsInt())), + JsType::kUnknown)); + break; + case 4: + // original new from buffer, modified to use all kinds + Push(out, cg.Declare(mk::New(t, mk::Id(t, random_kind), + {mk::Member(t, a, "buffer")}), + JsType::kTypedArray, "ta")); + break; + case 5: { + // set with another typed array or plain array + Expression* source = r.Coin() ? cg.Value(JsType::kArray, 1) + : cg.Value(JsType::kTypedArray, 1); + Push(out, cg.Stmt(mk::CallMethod(t, a, "set", {source}))); + break; + } + case 6: { + // constructors from another typed array, from, of, subarray, slice across + // element kinds + const char* op = + r.Pick({"from", "of", "subarray", "slice", "constructor"}); + if (std::string_view(op) == "constructor") { + Push(out, cg.Declare(mk::New(t, mk::Id(t, random_kind), {a}), + JsType::kTypedArray, "ta")); + } else if (std::string_view(op) == "from" || + std::string_view(op) == "of") { + Expression* arg = (std::string_view(op) == "from") + ? static_cast<Expression*>(a) + : static_cast<Expression*>(mk::Spread(t, a)); + Push(out, + cg.Declare(mk::CallMethod(t, mk::Id(t, random_kind), op, {arg}), + JsType::kTypedArray, "ta")); + } else { // subarray, slice + Push(out, + cg.Declare(mk::CallMethod(t, a, op, {cg.Integer(), cg.Integer()}), + JsType::kUnknown)); + } + break; + } + default: + Push(out, cg.Declare(mk::Member(t, a, + r.Pick({"length", "byteLength", + "byteOffset", "buffer"})), + JsType::kUnknown)); + break; + } + return true; +} + +REDLINE_TUNABLE(kFrozenArrayOpsMaxArgs, "generators.FrozenArrayOps.max_args", 3, + 0, 16, "most arguments passed to a frozen array method"); + +GEN(FrozenArrayOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* arr = cg.ArrayLiteral(1); + Expression* sealed_or_frozen = mk::CallMethod( + t, mk::Id(t, "Object"), r.Coin() ? "freeze" : "seal", {arr}); + Statement* decl = cg.Declare(sealed_or_frozen, JsType::kArray, "farr"); + Push(out, decl); + Identifier* a = mk::Id(t, decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + + switch (r.Index(3)) { + case 0: + Push(out, cg.Declare(mk::CallMethod(t, a, r.Pick({"includes", "indexOf"}), + cg.Arguments(1, 2)), + JsType::kUnknown)); + break; + case 1: + Push(out, cg.Declare(mk::CallMethod( + t, a, "concat", + cg.Arguments(1, kFrozenArrayOpsMaxArgs.AsInt())), + JsType::kUnknown)); + break; + default: { + Expression* obj = mk::Object( + t, + {mk::Prop(t, mk::Member(t, mk::Id(t, "Symbol"), "isConcatSpreadable"), + mk::Bool(t, r.Coin()), true), + mk::Prop(t, "length", cg.Integer()), + mk::Prop(t, "0", cg.Value(JsType::kUnknown, 1))}); + Push(out, + cg.Declare(mk::CallMethod(t, a, "concat", {obj}), JsType::kUnknown)); + break; + } + } + return true; +} + +REDLINE_TUNABLE( + kTemporalOpsMaxCalls, "generators.TemporalOps.max_calls", 3, 1, 16, + "most method calls on the Temporal object after its construction"); +REDLINE_TUNABLE(kTemporalOpsGuardChance, "generators.TemporalOps.guard_chance", + 0.9, 0, 1, + "probability that a call is wrapped in try/catch (values from " + "the program can make it throw)"); + +GEN(TemporalOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + + auto create_temporal = [&](const char* ctor) -> Expression* { + std::vector<Expression*> args; + if (std::string_view(ctor) == "PlainDate") { + args = {mk::Num(t, 2023), mk::Num(t, static_cast<double>(r.Range(1, 13))), + mk::Num(t, static_cast<double>(r.Range(1, 29)))}; + } else if (std::string_view(ctor) == "PlainTime") { + args = {mk::Num(t, static_cast<double>(r.Range(0, 24))), + mk::Num(t, static_cast<double>(r.Range(0, 60))), + mk::Num(t, static_cast<double>(r.Range(0, 60)))}; + } else if (std::string_view(ctor) == "PlainDateTime") { + args = {mk::Num(t, 2023), mk::Num(t, static_cast<double>(r.Range(1, 13))), + mk::Num(t, static_cast<double>(r.Range(1, 29))), + mk::Num(t, static_cast<double>(r.Range(0, 24)))}; + } else if (std::string_view(ctor) == "ZonedDateTime") { + args = {mk::BigInt(t, "123456789"), mk::Str(t, "UTC")}; + } else if (std::string_view(ctor) == "Instant") { + args = {mk::BigInt(t, "123456789")}; + } else if (std::string_view(ctor) == "Duration") { + args = {mk::Num(t, static_cast<double>(r.Range(0, 11))), + mk::Num(t, static_cast<double>(r.Range(0, 11)))}; + } + return mk::New(t, mk::Member(t, mk::Id(t, "Temporal"), ctor), + std::move(args)); + }; + + const char* ctors[] = {"PlainDate", "PlainTime", "PlainDateTime", + "ZonedDateTime", "Instant", "Duration"}; + const char* ctor = ctors[r.Index(sizeof(ctors) / sizeof(ctors[0]))]; + + Expression* construct = create_temporal(ctor); + Statement* decl = cg.Declare(construct, JsType::kObject, "temp"); + Push(out, decl); + Identifier* a = mk::Id(t, decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + + int calls = 1 + static_cast<int>(r.Index( + static_cast<size_t>(kTemporalOpsMaxCalls.AsInt()))); + for (int i = 0; i < calls; i++) { + std::vector<const char*> all_methods = {"add", "subtract", "with", + "round", "compare", "toString"}; + if (std::string_view(ctor) != "Duration") { + all_methods.push_back("since"); + all_methods.push_back("until"); + } + const char* method = r.Pick(all_methods); + std::vector<Expression*> args; + + if (std::string_view(method) == "compare") { + args = {a, create_temporal(ctor)}; + Expression* call = + mk::CallMethod(t, mk::Member(t, mk::Id(t, "Temporal"), ctor), method, + std::move(args)); + cg.DeclareMaybeGuarded(out, call, JsType::kNumber, "r", + kTemporalOpsGuardChance()); + } else if (std::string_view(method) == "toString") { + if (r.Coin()) { + args = {mk::Object( + t, {mk::Prop(t, "fractionalSecondDigits", mk::Str(t, "auto"))})}; + } + Expression* call = mk::CallMethod(t, a, method, std::move(args)); + cg.DeclareMaybeGuarded(out, call, JsType::kString, "r", + kTemporalOpsGuardChance()); + } else if (std::string_view(method) == "with") { + if (std::string_view(ctor) == "PlainDate" || + std::string_view(ctor) == "PlainDateTime" || + std::string_view(ctor) == "ZonedDateTime") { + args = {mk::Object(t, {mk::Prop(t, "year", mk::Num(t, 2024))})}; + } else if (std::string_view(ctor) == "PlainTime") { + args = {mk::Object(t, {mk::Prop(t, "hour", mk::Num(t, 12))})}; + } else if (std::string_view(ctor) == "Duration") { + args = {mk::Object(t, {mk::Prop(t, "hours", mk::Num(t, 5))})}; + } else { + args = {a}; + } + Expression* call = mk::CallMethod(t, a, method, std::move(args)); + cg.DeclareMaybeGuarded(out, call, JsType::kUnknown, "r", + kTemporalOpsGuardChance()); + } else if (std::string_view(method) == "add" || + std::string_view(method) == "subtract") { + args = {create_temporal("Duration")}; + Expression* call = mk::CallMethod(t, a, method, std::move(args)); + cg.DeclareMaybeGuarded(out, call, JsType::kUnknown, "r", + kTemporalOpsGuardChance()); + } else if (std::string_view(method) == "since" || + std::string_view(method) == "until") { + args = {create_temporal(ctor)}; + Expression* call = mk::CallMethod(t, a, method, std::move(args)); + cg.DeclareMaybeGuarded(out, call, JsType::kUnknown, "r", + kTemporalOpsGuardChance()); + } else { + // round + if (std::string_view(ctor) == "PlainDate") { + args = { + mk::Object(t, {mk::Prop(t, "smallestUnit", mk::Str(t, "day"))})}; + } else { + args = { + mk::Object(t, {mk::Prop(t, "smallestUnit", mk::Str(t, "second"))})}; + } + Expression* call = mk::CallMethod(t, a, method, std::move(args)); + cg.DeclareMaybeGuarded(out, call, JsType::kUnknown, "r", + kTemporalOpsGuardChance()); + } + } + return true; +} + +REDLINE_TUNABLE(kMapSetOpsMaxOps, "generators.MapSetOps.max_ops", 4, 1, 64, + "most set/get/has/delete operations on the map or set"); + +GEN(MapSetOps) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + bool map = r.Coin(); + Identifier* m = cg.Variable(map ? JsType::kMap : JsType::kSet); + if (m == nullptr) { + Statement* decl = + cg.Declare(mk::New(t, mk::Id(t, map ? "Map" : "Set"), {}), + map ? JsType::kMap : JsType::kSet, map ? "map" : "set"); + Push(out, decl); + m = mk::Id(t, decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name); + } + int n = 1 + r.SmallCount(kMapSetOpsMaxOps.AsInt() - 1); + for (int i = 0; i < n; i++) { + Identifier* o = mk::Id(t, m->name); + if (map) { + switch (r.Index(4)) { + case 0: + Push(out, cg.Stmt(mk::CallMethod(t, o, "set", + {cg.Value(JsType::kUnknown, 1), + cg.Value(JsType::kUnknown, 1)}))); + break; + case 1: + Push(out, cg.Declare(mk::CallMethod(t, o, "get", + {cg.Value(JsType::kUnknown, 1)}), + JsType::kUnknown)); + break; + case 2: + Push(out, cg.Stmt(mk::CallMethod(t, o, "delete", + {cg.Value(JsType::kUnknown, 1)}))); + break; + default: + Push(out, cg.Declare(mk::CallMethod(t, o, "has", + {cg.Value(JsType::kUnknown, 1)}), + JsType::kBoolean, "b")); + break; + } + } else { + switch (r.Index(3)) { + case 0: + Push(out, cg.Stmt(mk::CallMethod(t, o, "add", + {cg.Value(JsType::kUnknown, 1)}))); + break; + case 1: + Push(out, cg.Stmt(mk::CallMethod(t, o, "delete", + {cg.Value(JsType::kUnknown, 1)}))); + break; + default: + Push(out, cg.Declare(mk::CallMethod(t, o, "has", + {cg.Value(JsType::kUnknown, 1)}), + JsType::kBoolean, "b")); + break; + } + } + } + return true; +} + +GEN(ArgumentsUse) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + Expression* v = nullptr; + switch (r.Index(3)) { + case 0: + v = mk::Member(t, mk::Id(t, "arguments"), "length"); + break; + case 1: + v = mk::Index(t, mk::Id(t, "arguments"), cg.Integer()); + break; + default: + v = mk::Array(t, {mk::Spread(t, mk::Id(t, "arguments"))}); + break; + } + Push(out, cg.Declare(v, JsType::kUnknown)); + return true; +} + +GEN(ThisUse) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + if (r.Coin()) { + Push(out, cg.Declare(cg.Property(mk::This(t)), JsType::kUnknown)); + } else { + std::string_view name = cg.PropertyName(); + if (name == "__proto__") { + name = "x"; + } + Push(out, cg.Stmt(mk::Assign(t, cg.Property(mk::This(t), name), + cg.Value(JsType::kUnknown, 1)))); + } + return true; +} + +REDLINE_TUNABLE( + kEvalExplicitStrictChance, "generators.Eval.explicit_strict_chance", 0.3, 0, + 1, "chance to explicitly prepend 'use strict' to the eval snippet"); + +GEN(Eval) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + // Indirect and direct eval of small snippets. + std::vector<const char*> snippets = {"1+1", "this", "typeof x", "[]", + "({})", "new Array(3)", "undefined"}; + if (!ctx.syntax.strict) { + snippets.push_back("var a=1; a;"); + snippets.push_back("function f(){return 2;} f();"); + } + const char* snippet = r.Pick(snippets); + Expression* callee = mk::Id(t, "eval"); + if (r.Coin()) { + callee = mk::Seq(t, {mk::Num(t, 0), callee}); // indirect + } + Expression* arg = mk::Str(t, snippet); + bool use_strict = r.Chance(kEvalExplicitStrictChance()); + // if we added sloppy mode snippets, make sure we don't accidentally + // strict-ify them + if (std::string_view(snippet) == "var a=1; a;" || + std::string_view(snippet) == "function f(){return 2;} f();") { + use_strict = false; + } + if (use_strict) { + arg = mk::Binary(t, BinaryOp::kAdd, mk::Str(t, "'use strict'; "), arg); + } + Push(out, cg.Declare(mk::Call(t, callee, {arg}), JsType::kUnknown)); + return true; +} + +REDLINE_TUNABLE(kClosureMaxStatements, "generators.Closure.max_statements", 2, + 0, 64, + "most statements in the arrow body before the update of the " + "captured variable"); +REDLINE_TUNABLE(kClosureMaxCalls, "generators.Closure.max_calls", 4, 1, 64, + "most calls of the closure after it is declared"); + +GEN(Closure) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + // let v = 0; const f = () => v++; f(); f(); + Statement* decl = cg.Declare(cg.Value(JsType::kNumber, 1), JsType::kNumber); + Push(out, decl); + std::string_view captured = decl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name; + decl->Cast<VariableDeclaration>()->declaration_kind = VariableKind::kLet; + for (Variable& v : ctx.visible) { + if (v.name == captured) { + v.is_constant = false; + } + } + GenContext nested = ctx.Nested(true, true, false, false); + CodeGen inner(nested); + Statements body = + inner.Body(nested, r.SmallCount(kClosureMaxStatements.AsInt())); + body.push_back(inner.Stmt(mk::Assign(t, mk::Id(t, captured), + inner.Value(JsType::kNumber, 1), + CodeGen::RandomCompoundAssignOp(r)))); + body.push_back(mk::Return(t, mk::Id(t, captured))); + Statement* fdecl = + cg.Declare(mk::Arrow(t, {}, std::move(body)), JsType::kFunction, "f"); + Push(out, fdecl); + std::string_view f = fdecl->Cast<VariableDeclaration>() + ->declarations[0] + ->target->Cast<Identifier>() + ->name; + int calls = 1 + r.SmallCount(kClosureMaxCalls.AsInt() - 1); + for (int i = 0; i < calls; i++) { + Push(out, cg.Stmt(mk::Call(t, mk::Id(t, f), {}))); + } + return true; +} + +// --- stress patterns +// ------------------------------------------------------------------ +// +// Each generator below builds a situation that V8 regressions keep coming +// back to; all are parameterized over the visible values and random counts, +// none reproduces a particular test. + +REDLINE_TUNABLE(kRecursionUnboundedChance, + "generators.Recursion.unbounded_chance", 0.5, 0, 1, + "probability that the recursion has no depth guard and ends in " + "a caught stack overflow"); +REDLINE_TUNABLE(kRecursionMaxDepth, "generators.Recursion.max_depth", 5000, 1, + 100000, "largest depth guard of a bounded recursion"); +REDLINE_TUNABLE(kRecursionConstructorChance, + "generators.Recursion.constructor_chance", 0.4, 0, 1, + "probability that the recursive function is a constructor " + "recursing through new this.constructor()"); +REDLINE_TUNABLE( + kRecursionMaxStatements, "generators.Recursion.max_statements", 2, 0, 64, + "most generated statements executed at every level of the recursion"); + +// A function that calls itself under try/catch, until a depth guard or until +// the stack overflows (the RangeError is then caught at every level on the +// way out). Whatever the body does at each level is interrupted at some +// depth and resumed while unwinding: literals, property definitions and map +// transitions left half-done there are a classic source of stale state. +GEN(Recursion) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view name = ctx.builder.FreshName("rec"); + std::string_view depth = ctx.builder.FreshName("d"); + bool unbounded = r.Chance(kRecursionUnboundedChance()); + bool as_ctor = r.Chance(kRecursionConstructorChance()); + GenContext nested = ctx.Nested(true, false, false, false); + nested.Declare(depth, JsType::kNumber); + CodeGen inner(nested); + Statements body; + if (as_ctor) { + // if (!new.target) return new rec(d); + body.push_back( + mk::If(t, mk::Unary(t, UnaryOp::kNot, mk::NewTarget(t)), + mk::Block(t, {mk::Return(t, mk::New(t, mk::Id(t, name), + {mk::Id(t, depth)}))}))); + } + Statements level = + inner.Body(nested, r.SmallCount(kRecursionMaxStatements.AsInt())); + body.insert(body.end(), level.begin(), level.end()); + // The recursive call: through the name, or through this.constructor for + // constructors (which also exercises the prototype chain lookup). + Expression* callee = + as_ctor && r.Coin() + ? static_cast<Expression*>(mk::Member(t, mk::This(t), "constructor")) + : static_cast<Expression*>(mk::Id(t, name)); + Expression* next = + mk::Binary(t, BinaryOp::kAdd, mk::Id(t, depth), mk::Num(t, 1)); + Expression* call = + as_ctor ? static_cast<Expression*>(mk::New(t, callee, {next})) + : static_cast<Expression*>(mk::Call(t, callee, {next})); + Statement* guarded = + mk::Try(t, {mk::ExprStmt(t, call)}, ctx.builder.FreshName("e"), {}); + if (unbounded) { + body.push_back(guarded); + } else { + double limit = static_cast<double>(r.Range(1, kRecursionMaxDepth.AsInt())); + body.push_back(mk::If( + t, + mk::Binary(t, BinaryOp::kLessThan, mk::Id(t, depth), mk::Num(t, limit)), + guarded)); + } + // Statements the body may contain can run after the recursion returns + // too: a second generated statement after the call keeps the unwinding + // path busy. + if (r.Coin()) { + Statements after = inner.Body(nested, 1); + body.insert(body.end(), after.begin(), after.end()); + } + Push(out, mk::FunctionDecl(t, name, {depth}, std::move(body))); + ctx.Declare(name, as_ctor ? JsType::kClass : JsType::kFunction); + // Start it. The top-level call is guarded too: the overflow may happen + // before the first level installed its handler. + Expression* start = as_ctor ? static_cast<Expression*>(mk::New( + t, mk::Id(t, name), {mk::Num(t, 0)})) + : static_cast<Expression*>(mk::Call( + t, mk::Id(t, name), {mk::Num(t, 0)})); + Push(out, + mk::Try(t, {mk::ExprStmt(t, start)}, ctx.builder.FreshName("e"), {})); + return true; +} + +REDLINE_TUNABLE(kWrapperChainMaxLength, "generators.WrapperChain.max_length", + 50000, 1, 1000000, + "longest chain built (the length is drawn from a heavy-tailed " + "list capped here)"); +REDLINE_TUNABLE(kWrapperChainOptimizeChance, + "generators.WrapperChain.optimize_chance", 0.5, 0, 1, + "probability that the consumer of the chain is a function that " + "gets JIT-optimized"); + +// A value wrapped around itself N times in a loop (a bound function bound +// again, an object whose prototype is the previous one, an array or object +// nested in a new one, a proxy around a proxy, a string appended to), then +// consumed by an operation that walks the whole chain. Anything that recurses +// over such a chain (instanceof, call reduction in the optimizing compilers, +// prototype walks, JSON, string flattening) meets its depth limits here. +GEN(WrapperChain) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view w = ctx.builder.FreshName("w"); + std::string_view i = ctx.builder.FreshName("i"); + enum Kind { kBind, kProto, kArray, kObject, kProxy, kString }; + Kind kind = static_cast<Kind>(r.Index(6)); + Expression* seed = nullptr; + Expression* wrap = nullptr; + switch (kind) { + case kBind: + seed = cg.Callable(); + wrap = mk::CallMethod( + t, mk::Id(t, w), "bind", + r.Coin() ? std::vector<Expression*>{} + : std::vector<Expression*>{cg.Value(JsType::kUnknown, 1)}); + break; + case kProto: + seed = cg.ObjectLike(); + wrap = mk::CallMethod(t, mk::Id(t, "Object"), "create", {mk::Id(t, w)}); + break; + case kArray: + seed = cg.ArrayLiteral(1); + wrap = mk::Array(t, {mk::Id(t, w)}); + break; + case kObject: { + std::string_view key = cg.PropertyName(); + seed = cg.ObjectLiteral(1); + wrap = mk::Object( + t, {IsIdentifierName(key) ? mk::Prop(t, key, mk::Id(t, w)) + : mk::Prop(t, mk::Str(t, key), mk::Id(t, w), + /*computed=*/true)}); + break; + } + case kProxy: + seed = cg.ObjectLike(); + wrap = mk::New(t, mk::Id(t, "Proxy"), {mk::Id(t, w), mk::Object(t, {})}); + break; + case kString: + seed = cg.String(); + wrap = mk::Binary(t, BinaryOp::kAdd, mk::Id(t, w), cg.String()); + break; + } + static const double kLengths[] = {10, 100, 1000, 1000, + 5000, 10000, 20000, 50000}; + double length = + std::min(kLengths[r.Index(sizeof(kLengths) / sizeof(kLengths[0]))], + static_cast<double>(kWrapperChainMaxLength.AsInt())); + Push(out, mk::Let(t, w, seed)); + ctx.Declare(w, kind == kBind ? JsType::kFunction + : kind == kString ? JsType::kString + : JsType::kObject); + Push(out, + mk::CountedLoop( + t, i, mk::Num(t, length), + mk::Block(t, {mk::ExprStmt(t, mk::Assign(t, mk::Id(t, w), wrap))}))); + // A consumer that has to walk the chain. + Expression* use = nullptr; + switch (kind) { + case kBind: + switch (r.Index(3)) { + case 0: + use = mk::Binary(t, BinaryOp::kInstanceof, + cg.Value(JsType::kObject, 1), mk::Id(t, w)); + break; + case 1: + use = mk::Call(t, mk::Id(t, w), {}); + break; + default: + use = mk::New(t, mk::Id(t, w), {}); + break; + } + break; + case kProto: + case kProxy: + switch (r.Index(3)) { + case 0: + use = cg.Property(mk::Id(t, w)); + break; + case 1: + use = mk::Binary(t, BinaryOp::kIn, mk::Str(t, cg.PropertyName()), + mk::Id(t, w)); + break; + default: + use = + mk::CallMethod(t, mk::Id(t, "JSON"), "stringify", {mk::Id(t, w)}); + break; + } + break; + case kArray: + case kObject: + use = r.Coin() ? static_cast<Expression*>(mk::CallMethod( + t, mk::Id(t, "JSON"), "stringify", {mk::Id(t, w)})) + : static_cast<Expression*>( + mk::Call(t, mk::Id(t, "String"), {mk::Id(t, w)})); + break; + case kString: + use = + r.Coin() + ? static_cast<Expression*>( + mk::CallMethod(t, mk::Id(t, w), "indexOf", {cg.String()})) + : static_cast<Expression*>(mk::Member(t, mk::Id(t, w), "length")); + break; + } + Statement* guarded_use = + mk::Try(t, {mk::ExprStmt(t, use)}, ctx.builder.FreshName("e"), {}); + if (!r.Chance(kWrapperChainOptimizeChance())) { + Push(out, guarded_use); + return true; + } + // The consumer inside a function the optimizing compiler gets to see + // (the chain is a constant to it). + std::string_view f = ctx.builder.FreshName("f"); + Push(out, mk::FunctionDecl(t, f, {}, {guarded_use})); + ctx.Declare(f, JsType::kFunction); + Push(out, cg.Stmt(mk::Native(t, "PrepareFunctionForOptimization", + {mk::Id(t, f)}))); + Push(out, cg.Stmt(mk::Call(t, mk::Id(t, f), {}))); + Push(out, + cg.Stmt(mk::Native(t, "OptimizeFunctionOnNextCall", {mk::Id(t, f)}))); + Push(out, cg.Stmt(mk::Call(t, mk::Id(t, f), {}))); + return true; +} + +REDLINE_TUNABLE(kManyPropertiesMaxCount, "generators.ManyProperties.max_count", + 2000, 1, 100000, + "most properties added (counts are drawn around V8's limits: " + "1020 descriptors, 1024 fast properties, " + "the dictionary-mode and large-object thresholds)"); + +// A loop that gives an object N distinct property names, with N drawn around +// the points where V8 changes representation (1020 descriptors, 1024 fast +// properties, dictionary mode beyond, literal boilerplates with ever new +// names). The name is built from the loop counter, so every iteration brings +// a name the object has not seen. +GEN(ManyProperties) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view o = ctx.builder.FreshName("obj"); + std::string_view i = ctx.builder.FreshName("i"); + static const double kCounts[] = {8, 32, 127, 128, 129, 1000, 1019, + 1020, 1021, 1024, 1025, 1100, 2000}; + double count = + std::min(kCounts[r.Index(sizeof(kCounts) / sizeof(kCounts[0]))], + static_cast<double>(kManyPropertiesMaxCount.AsInt())); + // "p" + i + Expression* name = mk::Binary(t, BinaryOp::kAdd, + mk::Str(t, cg.PropertyName()), mk::Id(t, i)); + Expression* value = r.Coin() ? static_cast<Expression*>(mk::Id(t, i)) + : cg.Value(JsType::kUnknown, 1); + Statement* step = nullptr; + switch (r.Index(3)) { + case 0: + // obj["p" + i] = v + step = mk::ExprStmt( + t, mk::Assign(t, mk::Index(t, mk::Id(t, o), name), value)); + break; + case 1: + // Object.defineProperty(obj, "p" + i, {value: v, + // configurable/enumerable/writable at random}) + step = mk::ExprStmt( + t, mk::CallMethod( + t, mk::Id(t, "Object"), "defineProperty", + {mk::Id(t, o), name, + mk::Object( + t, {mk::Prop(t, "value", value), + mk::Prop(t, "configurable", mk::Bool(t, r.Coin())), + mk::Prop(t, "enumerable", mk::Bool(t, r.Coin())), + mk::Prop(t, "writable", mk::Bool(t, r.Coin()))})})); + break; + default: { + // eval("({" + ("p" + i) + ": 1})"): a literal with a name the parser has + // never seen + Expression* text = + mk::Binary(t, BinaryOp::kAdd, + mk::Binary(t, BinaryOp::kAdd, mk::Str(t, "({"), name), + mk::Str(t, ": 1})")); + step = mk::ExprStmt( + t, + mk::Assign(t, mk::Id(t, o), mk::Call(t, mk::Id(t, "eval"), {text}))); + break; + } + } + Push(out, mk::Let(t, o, cg.ObjectLike())); + ctx.Declare(o, JsType::kObject); + Push(out, mk::CountedLoop(t, i, mk::Num(t, count), mk::Block(t, {step}))); + // Then use the result: a new literal (fresh boilerplate next to the full + // caches), a property count or a key walk. + switch (r.Index(3)) { + case 0: + Push(out, cg.Declare(cg.ObjectLiteral(1), JsType::kObject, "obj")); + break; + case 1: + Push(out, cg.Declare(mk::Member(t, + mk::CallMethod(t, mk::Id(t, "Object"), + "keys", {mk::Id(t, o)}), + "length"), + JsType::kNumber)); + break; + default: + Push(out, cg.Stmt(mk::Assign(t, cg.Property(mk::Id(t, o)), + cg.Value(JsType::kUnknown, 1)))); + break; + } + return true; +} + +REDLINE_TUNABLE( + kReturnOverrideMaxMembers, "generators.ReturnOverride.max_members", 3, 1, + 16, "most fields and methods the derived class installs on the receiver"); +REDLINE_TUNABLE(kReturnOverridePrivateChance, + "generators.ReturnOverride.private_chance", 0.6, 0, 1, + "probability that a member is a private (#name) field or " + "method rather than a public field"); +REDLINE_TUNABLE(kReturnOverrideMaxReceivers, + "generators.ReturnOverride.max_receivers", 4, 1, 32, + "most receivers the class is applied to"); +REDLINE_TUNABLE(kReturnOverrideRepeat, "generators.ReturnOverride.repeat", 20, + 1, 1000, + "iterations of the loop that applies the class and its " + "accessors to the receivers"); +REDLINE_TUNABLE(kReturnOverrideDiscoveredChance, + "generators.ReturnOverride.discovered_chance", 0.35, 0, 1, + "probability that a receiver is an object produced by the " + "target's own API (DiscoveredValue) rather than " + "one of the generic kinds"); + +// A derived class whose base constructor returns its argument, so that the +// derived class's fields and private members are installed on that argument +// (a function, an array, a proxy, an API object, ...). Static methods give +// the program access to the private members afterwards. +GEN(ReturnOverride) { + Random& r = ctx.rng(); + Tree* t = T(ctx); + std::string_view base = ctx.builder.FreshName("B"); + std::string_view cls = ctx.builder.FreshName("D"); + std::string_view arg = ctx.builder.FreshName("o"); + Statements base_body = {mk::Return(t, mk::Id(t, arg))}; + MethodDefinition* base_ctor = mk::ClassMethod( + t, "constructor", mk::Function(t, "", {arg}, std::move(base_body)), + MethodKind::kConstructor); + Push(out, mk::ClassDecl(t, base, nullptr, {base_ctor})); + ctx.Declare(base, JsType::kClass); + GenContext nested = ctx.Nested(true, false, false, false); + nested.syntax.strict = true; + nested.syntax.in_method = true; + CodeGen inner(nested); + std::vector<Node*> members; + struct Accessor { + std::string_view name; + int arity; + }; + std::vector<Accessor> accessors; + std::string_view param = ctx.builder.FreshName("o"); + std::string_view vparam = ctx.builder.FreshName("v"); + int n = 1 + r.SmallCount(kReturnOverrideMaxMembers.AsInt() - 1); + for (int k = 0; k < n; k++) { + std::string_view pname = ctx.builder.FreshName("p"); + if (!r.Chance(kReturnOverridePrivateChance())) { + members.push_back( + mk::ClassField(t, pname, inner.Value(JsType::kUnknown, 1))); + continue; + } + if (r.Chance(0.25)) { + // #m() { return v; } static call(o) { return o.#m(); } + Statements mbody = {mk::Return(t, inner.Value(JsType::kUnknown, 1))}; + members.push_back(mk::ClassMethod( + t, mk::PrivateId(t, pname), mk::Function(t, "", {}, std::move(mbody)), + MethodKind::kMethod, false)); + std::string_view call = ctx.builder.FreshName("call"); + Statements cbody = {mk::Return( + t, mk::Call(t, mk::PrivateMember(t, mk::Id(t, param), pname), {}))}; + members.push_back(mk::ClassMethod( + t, call, mk::Function(t, "", {param}, std::move(cbody)), + MethodKind::kMethod, true)); + accessors.push_back({call, 1}); + continue; + } + // #p = v; static get(o) { return o.#p; } static set(o, v) { o.#p = v; } + members.push_back(mk::ClassField(t, mk::PrivateId(t, pname), + inner.Value(JsType::kUnknown, 1), false)); + std::string_view get = ctx.builder.FreshName("get"); + Statements gbody = { + mk::Return(t, mk::PrivateMember(t, mk::Id(t, param), pname))}; + members.push_back( + mk::ClassMethod(t, get, mk::Function(t, "", {param}, std::move(gbody)), + MethodKind::kMethod, true)); + accessors.push_back({get, 1}); + std::string_view set = ctx.builder.FreshName("set"); + Statements sbody = {mk::ExprStmt( + t, mk::Assign(t, mk::PrivateMember(t, mk::Id(t, param), pname), + mk::Id(t, vparam)))}; + members.push_back(mk::ClassMethod( + t, set, mk::Function(t, "", {param, vparam}, std::move(sbody)), + MethodKind::kMethod, true)); + accessors.push_back({set, 2}); + } + Push(out, mk::ClassDecl(t, cls, mk::Id(t, base), std::move(members))); + ctx.Declare(cls, JsType::kClass); + struct Receiver { + Expression* value; + const DiscoveredApi* source; // the API it came from, if any + }; + std::vector<Receiver> receivers; + int nr = 1 + r.SmallCount(kReturnOverrideMaxReceivers.AsInt() - 1); + for (int k = 0; k < nr; k++) { + Expression* receiver = nullptr; + const DiscoveredApi* source = nullptr; + // Objects of the embedder's own kinds first (DiscoveredValue), then + // the generic kinds; case 5 is DiscoveredValue too, for sessions + // without introspection it falls through to a plain object. + int kind = r.Chance(kReturnOverrideDiscoveredChance()) + ? 5 + : static_cast<int>(r.Index(10)); + switch (kind) { + case 0: + receiver = cg.Variable(); + break; + case 1: + receiver = cg.Callable(); + break; + case 2: + receiver = mk::New(t, mk::Id(t, "Proxy"), + {cg.ObjectLike(), mk::Object(t, {})}); + break; + case 3: + receiver = cg.Construct(); + break; + case 4: + receiver = mk::Id(t, "globalThis"); + break; + case 5: + // An object of the embedder's own kinds (see DiscoveredValue). + receiver = DiscoveredValue(ctx, cg, &source); + if (receiver == nullptr) { + receiver = cg.ObjectLike(); + } + break; + case 6: + // A function that already carries own properties: + // Object.assign(f, {p: v}). + receiver = mk::CallMethod( + t, mk::Id(t, "Object"), "assign", + {cg.Callable(), + mk::Object(t, {mk::Prop(t, ctx.env.property_names()[r.Index(12)], + cg.Value(JsType::kUnknown, 1))})}); + break; + case 7: + // A function made by the Function constructor, sloppy or strict: + // new Function("'use strict'") has a map of its own. + receiver = mk::New(t, mk::Id(t, "Function"), + {mk::Str(t, r.Coin() ? "'use strict'" : "")}); + break; + case 8: { + // The same, constructed with a foreign new.target (a visible + // class, or a builtin): its prototype is taken from there, so + // the function gets a map of yet another shape. + Expression* new_target = cg.Variable(JsType::kClass); + if (new_target == nullptr) { + new_target = mk::Id(t, r.Pick({"Object", "Array", "Proxy", "Map", + "Error", "Promise"})); + } + receiver = mk::CallMethod( + t, mk::Id(t, "Reflect"), "construct", + {mk::Id(t, "Function"), + mk::Array(t, {mk::Str(t, r.Coin() ? "'use strict'" : "")}), + new_target}); + break; + } + default: + receiver = cg.ObjectLike(); + break; + } + if (receiver != nullptr) { + receivers.push_back({receiver, source}); + } + } + // for (let i = 0; i < repeat; i++) { try { new D(r); D.get(r); D.set(r, v); } + // catch (e) {} ... } + Statements loop_body; + auto guarded = [&](Expression* e) { + return mk::Try(t, {mk::ExprStmt(t, e)}, ctx.builder.FreshName("e"), {}); + }; + auto accessor_calls = [&](std::string_view rv, Statements* steps) { + for (const Accessor& a : accessors) { + std::vector<Expression*> args = {mk::Id(t, rv)}; + if (a.arity > 1) { + args.push_back(cg.Value(JsType::kUnknown, 1)); + } + steps->push_back( + guarded(mk::CallMethod(t, mk::Id(t, cls), a.name, std::move(args)))); + } + }; + for (const Receiver& receiver : receivers) { + std::string_view rv = ctx.builder.FreshName("r"); + loop_body.push_back(mk::Let(t, rv, nullptr)); + loop_body.push_back(guarded(mk::Assign(t, mk::Id(t, rv), receiver.value))); + loop_body.push_back(guarded(mk::New(t, mk::Id(t, cls), {mk::Id(t, rv)}))); + accessor_calls(rv, &loop_body); + // Hand the object to the embedder in between (an API that changes + // its state, say) and read the members back afterwards; twice, so + // that a state can be left and entered again. + int rounds = static_cast<int>(r.Index(3)); + for (int round = 0; round < rounds; round++) { + Expression* embedder = + DiscoveredCallOn(ctx, cg, mk::Id(t, rv), receiver.source); + if (embedder == nullptr) { + break; + } + loop_body.push_back(guarded(embedder)); + accessor_calls(rv, &loop_body); + } + } + std::string_view i = ctx.builder.FreshName("i"); + double repeat = + static_cast<double>(r.Range(1, kReturnOverrideRepeat.AsInt())); + Push(out, mk::CountedLoop(t, i, mk::Num(t, repeat), + mk::Block(t, std::move(loop_body)))); + return true; +} + +// --- General Code Patterns +// ------------------------------------------------------ + +REDLINE_TUNABLE(kArrowStoreGCChance, "generators.ArrowStore.gc_chance", 0.5, 0, + 1, "chance to do GC"); +REDLINE_TUNABLE(kArrowStoreArgumentsChance, + "generators.ArrowStore.arguments_chance", 0.15, 0, 1, + "chance to reference arguments"); + +GEN(ArrowStore) { + Tree* t = T(ctx); + Random& r = ctx.rng(); + + GenContext f_ctx = ctx.Nested(true, false, false, false); + CodeGen f_cg(f_ctx); + std::vector<Statement*> f_body; + + int num_locals = static_cast<int>(r.Range(1, 4)); + f_body.reserve(static_cast<size_t>(num_locals)); + for (int i = 0; i < num_locals; i++) { + f_body.push_back(f_cg.Declare(f_cg.Value(), JsType::kUnknown)); + } + + Expression* arrow_body = f_cg.Expression(2); + Expression* arrow = mk::Arrow(t, {}, {mk::Return(t, arrow_body)}); + std::string_view arrow_name = f_ctx.builder.FreshName("arrow"); + f_body.push_back(mk::Let(t, arrow_name, arrow)); + + std::string_view result_name = f_ctx.builder.FreshName("res"); + Expression* call_arrow = mk::Call(t, mk::Id(t, arrow_name), {}); + + if (r.Chance(0.5)) { + std::string_view wrap_name = f_ctx.builder.FreshName("wrap"); + std::string_view p = f_ctx.builder.FreshName("p"); + Statement* call_stmt = mk::Return(t, mk::Call(t, mk::Id(t, p), {})); + if (r.Chance(0.5)) { + call_stmt = mk::Try(t, {call_stmt}, "e", {}); + } + f_body.push_back(mk::FunctionDecl(t, wrap_name, {p}, {call_stmt})); + call_arrow = mk::Call(t, mk::Id(t, wrap_name), {mk::Id(t, arrow_name)}); + } + + f_body.push_back(mk::Let(t, result_name, call_arrow)); + f_ctx.Declare(result_name, JsType::kUnknown); + + int num_ops = static_cast<int>(r.Range(1, 4)); + for (int i = 0; i < num_ops; i++) { + if (r.Chance(0.3)) { + f_body.push_back( + f_cg.Stmt(mk::Binary(t, CodeGen::RandomBinaryOp(r), + mk::Id(t, result_name), f_cg.Value()))); + } else if (r.Chance(0.5)) { + f_body.push_back( + f_cg.Stmt(mk::Assign(t, f_cg.Target(), mk::Id(t, result_name)))); + } else { + f_body.push_back( + f_cg.Stmt(f_cg.CallWithArguments(mk::Id(t, result_name), 2))); + } + } + + f_body.push_back(mk::Return(t, f_cg.Value())); + + std::string_view f_name = ctx.builder.FreshName("f"); + Push(out, mk::FunctionDecl(t, f_name, {}, std::move(f_body))); + + Statement* call_f = cg.Stmt(mk::Call(t, mk::Id(t, f_name), {})); + if (r.Chance(0.5)) { + Push(out, mk::CountedLoop(t, ctx.builder.FreshName("i"), + mk::Num(t, LoopCount(r)), call_f)); + } else { + Push(out, cg.Stmt(mk::Native(t, "PrepareFunctionForOptimization", + {mk::Id(t, f_name)}))); + Push(out, call_f); + Push(out, cg.Stmt(mk::Native(t, "OptimizeFunctionOnNextCall", + {mk::Id(t, f_name)}))); + Push(out, call_f); + } + + return true; +} + +REDLINE_TUNABLE(kDynamicFunctionStrictChance, + "generators.DynamicFunctionTransition.strict_chance", 0.5, 0, 1, + "chance to emit strict mode"); + +GEN(DynamicFunctionTransition) { + Tree* t = T(ctx); + Random& r = ctx.rng(); + + Expression* body = cg.String(); + if (r.Chance(kDynamicFunctionStrictChance())) { + body = mk::Binary(t, BinaryOp::kAdd, mk::Str(t, "'use strict'; "), body); + } + + Expression* func_ctor = nullptr; + if (r.Chance(0.3)) { + func_ctor = + mk::CallMethod(t, mk::Id(t, "Reflect"), "construct", + {mk::Id(t, "Function"), mk::Array(t, {body}), + r.Chance(0.5) ? cg.Value() : mk::Id(t, "Proxy")}); + } else if (r.Chance(0.5)) { + func_ctor = mk::New(t, mk::Id(t, "Function"), {body}); + } else { + func_ctor = mk::Call(t, mk::Id(t, "Function"), {body}); + } + + std::string_view fn_name = ctx.builder.FreshName("dynFn"); + Push(out, mk::Let(t, fn_name, func_ctor)); + ctx.Declare(fn_name, JsType::kFunction); + + if (r.Chance(0.5)) { + std::string_view base_name = ctx.builder.FreshName("Base"); + std::string_view o_param = ctx.builder.FreshName("o"); + FunctionExpression* base_ctor = + mk::Function(t, "", {o_param}, {mk::Return(t, mk::Id(t, fn_name))}); + Node* base_ctor_method = + mk::ClassMethod(t, "constructor", base_ctor, MethodKind::kConstructor); + Push(out, mk::ClassDecl(t, base_name, nullptr, {base_ctor_method})); + + std::string_view def_name = ctx.builder.FreshName("Derived"); + std::vector<Node*> class_members; + int num_fields = static_cast<int>(r.Range(0, 3)); + for (int i = 0; i < num_fields; i++) { + // A class field named "constructor" is a SyntaxError. + std::string_view field = cg.PropertyName(); + if (field == "constructor") { + field = ctx.builder.FreshName("f"); + } + class_members.push_back( + mk::ClassField(t, mk::Str(t, field), cg.Value(), false)); + } + Push(out, mk::ClassDecl(t, def_name, mk::Id(t, base_name), + std::move(class_members))); + + Statement* create_derived = + cg.Stmt(mk::New(t, mk::Id(t, def_name), {cg.Value()})); + Push(out, mk::CountedLoop(t, ctx.builder.FreshName("i"), + mk::Num(t, LoopCount(r)), create_derived)); + } else { + int num_props = static_cast<int>(r.Range(1, 4)); + for (int i = 0; i < num_props; i++) { + Push(out, + cg.Stmt(mk::Assign(t, cg.Property(mk::Id(t, fn_name)), cg.Value()))); + } + Statement* call_fn = cg.Stmt(cg.CallWithArguments(mk::Id(t, fn_name), 2)); + Push(out, mk::CountedLoop(t, ctx.builder.FreshName("i"), + mk::Num(t, LoopCount(r)), call_fn)); + } + + return true; +} + +REDLINE_TUNABLE(kCrossContextPrivateStoreLoopChance, + "generators.CrossContextPrivateStore.loop_chance", 0.8, 0, 1, + "chance to wrap in a loop"); +REDLINE_TUNABLE(kCrossContextPrivateStoreAccessCheckedChance, + "generators.CrossContextPrivateStore.access_checked_chance", + 0.05, 0, 1, "chance to use access-checked receiver"); + +GEN(CrossContextPrivateStore) { + Tree* t = T(ctx); + Random& r = ctx.rng(); + + std::string_view cls_name = ctx.builder.FreshName("PrivClass"); + + std::vector<Node*> members; + int num_fields = static_cast<int>(r.Range(1, 4)); + std::vector<std::string_view> private_names; + + for (int i = 0; i < num_fields; i++) { + std::string_view p_name = ctx.builder.FreshName("p"); + private_names.push_back(p_name); + members.push_back( + mk::ClassField(t, mk::PrivateId(t, p_name), cg.Value(), false)); + } + + int num_methods = static_cast<int>(r.Range(1, 3)); + std::vector<std::string_view> method_names; + + for (int i = 0; i < num_methods; i++) { + std::string_view m_name = ctx.builder.FreshName("m"); + method_names.push_back(m_name); + std::string_view obj_param = ctx.builder.FreshName("o"); + std::string_view val_param = ctx.builder.FreshName("v"); + + std::string_view p_name = r.Pick(private_names); + + Statements body; + Expression* target_obj = + r.Chance(0.5) ? static_cast<Expression*>(mk::Id(t, obj_param)) + : static_cast<Expression*>(mk::This(t)); + + if (r.Chance(0.5)) { + Statement* assign = mk::ExprStmt( + t, mk::Assign(t, mk::PrivateMember(t, target_obj, p_name), + mk::Id(t, val_param))); + if (r.Chance(0.5)) { + body.push_back(mk::Try(t, {assign}, "e", {})); + } else { + body.push_back(assign); + } + } else { + Statement* ret = mk::Return(t, mk::PrivateMember(t, target_obj, p_name)); + if (r.Chance(0.5)) { + body.push_back(mk::Try(t, {ret}, "e", {mk::Return(t, cg.Value())})); + } else { + body.push_back(ret); + } + } + members.push_back(mk::ClassMethod( + t, m_name, mk::Function(t, "", {obj_param, val_param}, std::move(body)), + MethodKind::kMethod, r.Chance(0.5))); + } + + Expression* base_expr = nullptr; + if (r.Chance(0.5)) { + std::string_view base_name = ctx.builder.FreshName("Base"); + std::string_view base_o = ctx.builder.FreshName("o"); + FunctionExpression* base_ctor = + mk::Function(t, "", {base_o}, + {r.Chance(0.5) ? mk::Return(t, mk::Id(t, base_o)) + : mk::Return(t, cg.ObjectLiteral())}); + Node* base_ctor_method = + mk::ClassMethod(t, "constructor", base_ctor, MethodKind::kConstructor); + Push(out, mk::ClassDecl(t, base_name, nullptr, {base_ctor_method})); + base_expr = mk::Id(t, base_name); + } + + Push(out, mk::ClassDecl(t, cls_name, base_expr, std::move(members))); + ctx.Declare(cls_name, JsType::kClass); + + Statements loop_body; + std::string_view rec_name = ctx.builder.FreshName("rec"); + + Expression* receiver = nullptr; + int rec_type = static_cast<int>(r.Range(0, 8)); + if (rec_type == 0) { + receiver = mk::CallMethod(t, mk::Member(t, mk::Id(t, "d8"), "test"), + "createAccessCheckedObject", + {mk::Bool(t, r.Chance(0.5))}); + } else if (rec_type == 1) { + receiver = mk::New(t, mk::Id(t, "Proxy"), + {cg.ObjectLiteral(), cg.ObjectLiteral()}); + } else if (rec_type == 2) { + receiver = cg.ObjectLike(); + if (!receiver) { + receiver = cg.ObjectLiteral(); + } + } else if (rec_type == 3) { + receiver = mk::New(t, mk::Id(t, cls_name), {cg.Value()}); + } else if (rec_type == 4) { + receiver = cg.ArrayLiteral(); + } else if (rec_type == 5) { + receiver = cg.String(); + } else if (rec_type == 6) { + receiver = cg.Number(); + } else { + receiver = cg.Value(); + } + + loop_body.push_back(mk::Let(t, rec_name, receiver)); + + if (r.Chance(0.5)) { + loop_body.push_back( + cg.Stmt(mk::New(t, mk::Id(t, cls_name), {mk::Id(t, rec_name)}))); + } + + int num_calls = static_cast<int>(r.Range(1, 4)); + for (int i = 0; i < num_calls; i++) { + std::string_view m = r.Pick(method_names); + loop_body.push_back(cg.Stmt(mk::CallMethod( + t, mk::Id(t, cls_name), m, {mk::Id(t, rec_name), cg.Value()}))); + } + + Push(out, + mk::CountedLoop(t, ctx.builder.FreshName("i"), mk::Num(t, LoopCount(r)), + mk::Block(t, std::move(loop_body)))); + + return true; +} + +GEN(UsingDecl) { + Tree* t = T(ctx); + Expression* init = cg.Value(JsType::kObject, 1); + VariableDeclaration* d = mk::Declare( + t, VariableKind::kUsing, ctx.builder.FreshName("using_var"), init); + Push(out, mk::Block(t, {d})); + return true; +} + +GEN(AwaitUsingDecl) { + Tree* t = T(ctx); + Expression* init = cg.Value(JsType::kObject, 1); + VariableDeclaration* d = + mk::Declare(t, VariableKind::kAwaitUsing, + ctx.builder.FreshName("await_using_var"), init); + Push(out, mk::Block(t, {d})); + return true; +} + +REDLINE_TUNABLE(kRawThrowConditionChance, + "generators.RawThrow.condition_chance", 0.5, 0, 1, + "chance to wrap throw in an if statement"); + +GEN(RawThrow) { + Tree* t = T(ctx); + Random& r = ctx.rng(); + Statement* th = mk::Throw(t, cg.Value(JsType::kUnknown, 1)); + if (r.Chance(kRawThrowConditionChance())) { + Push(out, mk::If(t, cg.Boolean(), th)); + } else { + Push(out, th); + } + return true; +} + +GEN(NewTargetExpr) { + Tree* t = T(ctx); + Push(out, mk::Let(t, ctx.builder.FreshName("nt"), mk::NewTarget(t))); + return true; +} + +REDLINE_TUNABLE(kWorkerTerminateChance, + "generators.WorkerSpawn.terminate_chance", 0.5, 0, 1, + "chance to terminate the worker immediately"); + +GEN(WorkerSpawn) { + Tree* t = T(ctx); + Random& r = ctx.rng(); + + std::string_view w_name = ctx.builder.FreshName("w"); + Expression* worker_src = + mk::Str(t, "onmessage = function(e) { postMessage(e.data); }"); + Expression* worker_opts = + mk::Object(t, {mk::Prop(t, "type", mk::Str(t, "string"))}); + Push(out, + mk::Let(t, w_name, + mk::New(t, mk::Id(t, "Worker"), {worker_src, worker_opts}))); + ctx.Declare(w_name, JsType::kUnknown); + + Push(out, cg.Stmt(mk::CallMethod(t, mk::Id(t, w_name), "postMessage", + {cg.Value(JsType::kUnknown, 1)}))); + + if (r.Chance(kWorkerTerminateChance())) { + Push(out, cg.Stmt(mk::CallMethod(t, mk::Id(t, w_name), "terminate", {}))); + } else { + // If we don't terminate, we can call getMessage to block and wait for the + // message! But getMessage might hang if serialization fails! The + // instructions say: "Keep runs deterministic and bounded: no long-lived + // threads, and always terminate or await so programs finish within the 400 + // ms timeout." Let's just always terminate it! But wait! The tunable says + // "chance to terminate immediately". If I don't terminate immediately, I + // can do some operations and THEN terminate it. Actually, d8 cleans up + // workers on exit, so if we just run, it terminates at the end. BUT to be + // safe, I will just call terminate() at the end unconditionally, and maybe + // getMessage() optionally. + + if (r.Coin()) { + Push(out, + cg.Stmt(mk::CallMethod(t, mk::Id(t, w_name), "getMessage", {}))); + } + Push(out, cg.Stmt(mk::CallMethod(t, mk::Id(t, w_name), "terminate", {}))); + } + + return true; +} + +#undef GEN + +} // namespace + +// --- GeneratorSet +// ----------------------------------------------------------------- + +// static +std::unique_ptr<GeneratorSet> GeneratorSet::CreateDefault() { + auto set = std::make_unique<GeneratorSet>(); + auto add = [&](const char* name, const char* description, double weight, + uint32_t requirements, GenFn fn) { + set->generators_.push_back(std::make_unique<FnGenerator>( + name, description, weight, requirements, fn)); + set->candidates_.push_back(set->generators_.back().get()); + }; + // Values. + add("IntegerDecl", "let v = <integer>", 3, kNoRequirement, GenIntegerDecl); + add("FloatDecl", "let v = <number>", 2, kNoRequirement, GenFloatDecl); + add("StringDecl", "let s = <string>", 2, kNoRequirement, GenStringDecl); + add("BooleanDecl", "let b = <boolean>", 1, kNoRequirement, GenBooleanDecl); + add("BigIntDecl", "let n = <bigint>", 1, kNoRequirement, GenBigIntDecl); + add("RegExpDecl", "let re = /.../", 1, kNoRequirement, GenRegExpDecl); + add("NullishDecl", "let v = null | undefined", 0.5, kNoRequirement, + GenNullishDecl); + add("SymbolDecl", "let sym = Symbol(...)", 0.5, kNoRequirement, + GenSymbolDecl); + add("ArrayDecl", "let arr = [...]", 3, kNoRequirement, GenArrayDecl); + add("ObjectDecl", "let obj = {...}", 3, kRecursive, GenObjectDecl); + add("ConstructDecl", "let o = new Builtin(...)", 2, kNoRequirement, + GenConstructDecl); + add("TypedArrayDecl", "let ta = new XArray(...)", 1, kNoRequirement, + GenTypedArrayDecl); + add("ComputedDecl", "let v = <expression>", 3, kNoRequirement, + GenComputedDecl); + add("TemplateDecl", "let s = `...${}...`", 1, kNoRequirement, + GenTemplateDecl); + add("Destructuring", "let {a, b} = obj / let [x, y] = arr", 1, kNoRequirement, + GenDestructuring); + // Functions and classes. + add("FunctionDecl", "function f(a, b) {...} f();", 4, kRecursive, + GenFunctionDecl); + add("ArrowDecl", "const f = (a) => {...}", 2, kRecursive, GenArrowDecl); + add("ClassDecl", "class C extends ... {...}; new C()", 2, kRecursive, + GenClassDecl); + add("Iife", "(function() {...})()", 1, kRecursive, GenIife); + add("Closure", "captured variable mutated by an arrow, called repeatedly", 1, + kRecursive, GenClosure); + // Operations. + add("BinaryOp", "let v = a <op> b", 4, kNoRequirement, GenBinaryOp); + add("Compare", "let b = a <cmp> b", 1.5, kNoRequirement, GenCompare); + add("UnaryOp", "let v = <op> a / a++ / delete o.p", 1.5, kNoRequirement, + GenUnaryOp); + add("Update", "x++ / --o.p", 1.5, kNoRequirement, GenUpdate); + add("Assignment", "target (op)= value", 3, kNoRequirement, GenAssignment); + add("PropertyLoad", "let v = obj.p", 3, kNoRequirement, GenPropertyLoad); + add("PropertyStore", "obj.p = v", 3, kNoRequirement, GenPropertyStore); + add("ElementLoad", "let v = arr[i]", 2, kNoRequirement, GenElementLoad); + add("ElementStore", "arr[i] = v", 2, kNoRequirement, GenElementStore); + add("PropertyDelete", "delete obj.p", 1, kNoRequirement, GenPropertyDelete); + add("MethodCall", "let v = obj.method(args)", 4, kNoRequirement, + GenMethodCall); + add("FunctionCall", "let v = f(args) / f.call / f.apply", 4, kNoRequirement, + GenFunctionCall); + add("BuiltinCall", "let v = Math.max(...) / JSON.stringify(...) ...", 3, + kNoRequirement, GenBuiltinCall); + add("Construct", "let o = new C(args)", 2, kNoRequirement, GenConstruct); + add("TypeCheck", "typeof / instanceof / in", 1, kNoRequirement, GenTypeCheck); + add("SpreadCall", "f(...arr)", 1, kNoRequirement, GenSpreadCall); + add("StringOps", "string concatenation, indexing, cons/flat strings", 1.5, + kNoRequirement, GenStringOps); + add("TypedArrayOps", "typed array element access, detach, views", 1.5, + kNoRequirement, GenTypedArrayOps); + add("MapSetOps", "Map/Set set/get/has/delete", 1, kNoRequirement, + GenMapSetOps); + add("IntlOps", + "Intl services with valid locales and options, locale-aware primitive " + "methods", + 1, kNoRequirement, GenIntlOps); + add("FrozenArrayOps", "sealed and frozen arrays with includes/indexOf/concat", + 1, kNoRequirement, GenFrozenArrayOps); + add("TemporalOps", "Temporal with valid arguments and options", 1, + kNoRequirement, GenTemporalOps); + + // Weight 0: the A/B experiment compares JavaScript-only runs (Fuzzilli runs + // without --wasm). The `wasm` preset enables it. + add("WasmModule", + "WebAssembly module from building blocks, instantiated and called", 0, + kNoRequirement, GenWasmModule); + add("Iteration", "Array.from / [...x] / Object.keys", 1, kNoRequirement, + GenIteration); + add("DiscoveredApi", "new X()/X.m()/ns.f() for builtins the target reported", + 6, kNoRequirement, GenDiscoveredApi); + add("PrototypeMethodCall", "Builtin.prototype.m.call(otherReceiver, ...)", + 1.5, kNoRequirement, GenPrototypeMethodCall); + add("UnboundMethodCall", + "const m = obj.method; m.call/apply/bind(other, ...)", 1.5, + kNoRequirement, GenUnboundMethodCall); + add("BuiltinOverwrite", "Builtin.prototype.m = function...; Math.max = ...", + 1, kRecursive, GenBuiltinOverwrite); + add("ConstructorFunction", + "function C(a, b) { if (!new.target) ...; this.x = a; }; new C()", 1.5, + kRecursive, GenConstructorFunction); + // Control flow. + add("CountedLoop", "for (let i = 0; i < N; i++) {...}", 3, kRecursive, + GenCountedLoop); + add("WhileLoop", "bounded while / do-while", 1, kRecursive, GenWhileLoop); + add("ForOf", "for (const e of iterable) {...}", 2, kRecursive, GenForOf); + add("ForIn", "for (let k in obj) {...}", 1, kRecursive, GenForIn); + add("IfElse", "if (cond) {...} else {...}", 3, kRecursive, GenIfElse); + add("Switch", "switch (v) { case ...: }", 1, kRecursive, GenSwitch); + add("TryCatch", "try {...} catch (e) {...} finally {...}", 2, kRecursive, + GenTryCatch); + add("Throw", "try { throw ... } catch {}", 0.5, kNoRequirement, GenThrow); + add("LabeledBlock", "L: { ... break L; }", 0.5, kRecursive, GenLabeledBlock); + add("Return", "if (cond) return v;", 1, kNeedsFunction, GenReturn); + add("BreakContinue", "if (cond) break/continue;", 0.5, kNeedsBreak, + GenBreakContinue); + // JIT. + add("JitOptimize", + "%PrepareFunctionForOptimization(f); f(); " + "%OptimizeFunctionOnNextCall(f); f();", + 4, kNoRequirement, GenJitOptimize); + add("JitBaseline", "%CompileBaseline(f); f();", 0.5, kNoRequirement, + GenJitBaseline); + add("Deopt", "%DeoptimizeNow() / %DeoptimizeFunction(f)", 1, kNoRequirement, + GenDeopt); + add("OsrLoop", "loop with %OptimizeOsr()", 1, kRecursive, GenOsrLoop); + add("NativeCall", "%Native(...) from the environment table", 1, + kNoRequirement, GenNativeCall); + add("Gc", "gc() / %SimulateNewspaceFull()", 0.5, kNoRequirement, GenGc); + // Object model. + add("PrototypeSet", "Object.setPrototypeOf / __proto__ =", 1, kNoRequirement, + GenPrototypeSet); + add("DefineProperty", "Object.defineProperty(obj, k, {get/value...})", 1.5, + kRecursive, GenDefineProperty); + add("ValueOfOverride", + "obj.valueOf / toString / Symbol.toPrimitive = () => ...", 1, + kNoRequirement, GenValueOfOverride); + add("ElementsKind", "array elements kind transitions", 2, kNoRequirement, + GenElementsKind); + add("FreezeSeal", "Object.freeze/seal/preventExtensions", 0.5, kNoRequirement, + GenFreezeSeal); + add("ProxyDecl", "let p = new Proxy(target, {traps})", 1, kRecursive, + GenProxyDecl); + add("With", "with (obj) {...}", 0.3, kNeedsSloppy | kRecursive, GenWith); + add("ShapeChange", "add/delete properties on an object", 1.5, kNoRequirement, + GenShapeChange); + add("Eval", "eval / indirect eval of a snippet", 0.3, kNoRequirement, + GenEval); + // Stress patterns. + add("Recursion", + "f calls itself under try/catch, bounded or until a caught stack " + "overflow", + 1, kRecursive, GenRecursion); + add("WrapperChain", + "w = wrap(w) N times (bind, Object.create, [w], proxy, string), then " + "consumed", + 1, kNoRequirement, GenWrapperChain); + add("ManyProperties", + "N distinct property names via stores, defineProperty or eval'd literals", + 1, kNoRequirement, GenManyProperties); + add("ReturnOverride", + "class B { constructor(o) { return o; } } class D extends B { #p; static " + "get(o) {...} }; new D(x)", + 1.5, kRecursive, GenReturnOverride); + add("ArgumentsUse", "arguments.length / arguments[i] / [...arguments]", 0.5, + kNeedsArguments, GenArgumentsUse); + add("ThisUse", "this.p load/store", 1, kNeedsThis, GenThisUse); + // Async and generators. + add("Await", "let v = await ...", 2, kNeedsAsync, GenAwait); + add("Yield", "let v = yield ...", 2, kNeedsGenerator, GenYield); + add("AsyncIife", "(async () => { ... await ... })()", 1, kRecursive, + GenAsyncIife); + add("GeneratorIterate", + "function* g() {...}; for (const x of g()) / it.next()", 1, kRecursive, + GenGeneratorIterate); + add("PromiseThen", "promise.then(v => ..., e => ...)", 1, kRecursive, + GenPromiseThen); + add("WorkerSpawn", "spawn a WebWorker", 1.0, kNoRequirement, GenWorkerSpawn); + add("ArrowStore", "store an object or smi to an arrow function", 1.0, + kNoRequirement, GenArrowStore); + add("DynamicFunctionTransition", "dynamic function with map transition", 1.0, + kNoRequirement, GenDynamicFunctionTransition); + add("CrossContextPrivateStore", "cross-context private field store", 1.0, + kNoRequirement, GenCrossContextPrivateStore); + add("UsingDecl", "using x = ...", 1.0, kNoRequirement, GenUsingDecl); + add("AwaitUsingDecl", "await using x = ...", 1.0, kNeedsAsync, + GenAwaitUsingDecl); + add("RawThrow", "throw ...", 0.5, kNoRequirement, GenRawThrow); + add("NewTargetExpr", "let nt = new.target", 1.0, kNeedsArguments, + GenNewTargetExpr); + std::string error; + if (!set->SetSelector( + std::make_unique<WeightedSelector<Generator>>( + "generator", std::vector<std::pair<std::string, double>>{}), + &error)) { + REDLINE_ERROR("generators", "default generator strategy: %s", + error.c_str()); + return nullptr; + } + return set; +} + +bool GeneratorSet::SetSelector(std::unique_ptr<Selector<Generator>> selector, + std::string* error) { + if (!selector->Initialize(candidates_, error)) { + return false; + } + selector_ = std::move(selector); + return true; +} + +Generator* GeneratorSet::Find(std::string_view name) const { + for (const auto& g : generators_) { + if (g->name() == name) { + return g.get(); + } + } + return nullptr; +} + +std::vector<std::string> GeneratorSet::Names() const { + std::vector<std::string> names; + names.reserve(generators_.size()); + for (const auto& g : generators_) { + names.push_back(g->name()); + } + return names; +} + +Generator* GeneratorSet::Pick(const GenContext& ctx) const { + size_t index = + selector_->Pick(candidates_, ctx.builder.rng(), + [&](const Generator& g) { return g.Applicable(ctx); }); + return index == Selector<Generator>::kNoChoice ? nullptr : candidates_[index]; +} + +// --- selection strategies for generators ----------------------------------- +// +// To add one: derive from Selector<Generator>, then add a Register() line +// below. Parameters are declared in the Entry so that the configuration is +// validated before the fuzzer starts. + +template <> +void RegisterBuiltinSelectors<Generator>( + SelectorRegistry<Generator>& registry) { + registry.Register( + {std::string(AdaptiveSelector<Generator>::kName), + "weighted draw whose weights follow each generator's recent yield", + AdaptiveSelector<Generator>::Specs(), + [](const JsonValue& params, + std::string* error) -> std::unique_ptr<Selector<Generator>> { + std::vector<std::pair<std::string, double>> overrides; + if (!ReadWeightOverrides(params, &overrides, error)) { + return nullptr; + } + AdaptiveSelector<Generator>::Settings p = + AdaptiveSelector<Generator>::ReadParams(params); + if (!AdaptiveSelector<Generator>::Validate(p, error)) { + return nullptr; + } + return std::make_unique<AdaptiveSelector<Generator>>( + "generator", std::move(overrides), p); + }}); + registry.Register({std::string(WeightedSelector<Generator>::kName), + "one weighted random draw among the applicable generators", + WeightedSelector<Generator>::Specs(), + [](const JsonValue& params, std::string* error) + -> std::unique_ptr<Selector<Generator>> { + std::vector<std::pair<std::string, double>> overrides; + if (!ReadWeightOverrides(params, &overrides, error)) { + return nullptr; + } + // Names are checked against the generators in + // Initialize(). + return std::make_unique<WeightedSelector<Generator>>( + "generator", std::move(overrides)); + }}); + registry.SetDefault(WeightedSelector<Generator>::kName); +} + +int GeneratorSet::Generate(GenContext& ctx, int count, + std::vector<fast::Statement*>* out) const { + int produced = 0; + std::vector<fast::Statement*>* saved_out = ctx.out; + for (int i = 0; i < count; i++) { + Generator* g = Pick(ctx); + if (g == nullptr) { + break; + } + g->stats().invocations++; + size_t before = out->size(); + ctx.out = out; + if (g->Generate(ctx, out) && out->size() > before) { + g->stats().produced++; + produced++; + } else { + out->resize(before); + } + } + ctx.out = saved_out; + return produced; +} + +std::vector<const Component*> GeneratorSet::Components() const { + std::vector<const Component*> components; + components.reserve(generators_.size()); + for (const auto& g : generators_) { + components.push_back(g.get()); + } + return components; +} + +GenContext MakeGenContext(Builder& builder, const Builder::Slot& slot, + const GeneratorSet& generators, + const Environment& env) { + GenContext ctx(builder, generators, env); + ctx.slot = slot; + ctx.syntax = builder.ContextAtSlot(slot); + ctx.visible = builder.VisibleAtSlot(slot); + return ctx; +} + +} // namespace redline + +namespace redline { +namespace { +// One list for each thread. The list is never deleted, so that the thread has +// no destructor to run when it exits. +std::vector<Generator*>& UsedGenerators() { + thread_local std::vector<Generator*>* used = new std::vector<Generator*>(); + return *used; +} +} // namespace +void BeginGeneratorUsage() { UsedGenerators().clear(); } +void NoteGeneratorUsed(Generator* g) { + std::vector<Generator*>& used = UsedGenerators(); + if (std::find(used.begin(), used.end(), g) == used.end()) { + used.push_back(g); + } +} +std::vector<Generator*> GeneratorsUsed() { return UsedGenerators(); } +} // namespace redline diff --git a/deps/v8/experimental/redline/generators/wasm_module.cc b/deps/v8/experimental/redline/generators/wasm_module.cc new file mode 100644 index 000000000000..302df28a65b6 --- /dev/null +++ b/deps/v8/experimental/redline/generators/wasm_module.cc @@ -0,0 +1,680 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/generators/wasm_module.h" + +#include <cstring> +#include <string> + +#include "experimental/redline/core/random.h" +#include "experimental/redline/core/tunable.h" + +namespace redline { + +REDLINE_TUNABLE(kWasmMaxImports, "generators.WasmModule.max_imports", 5, 0, 20, + "max imported functions"); +REDLINE_TUNABLE(kWasmMaxFunctions, "generators.WasmModule.max_functions", 5, 1, + 50, "max defined functions"); +REDLINE_TUNABLE(kWasmMaxGlobals, "generators.WasmModule.max_globals", 10, 0, 50, + "max globals"); +REDLINE_TUNABLE(kWasmMaxMemoryPages, "generators.WasmModule.max_memory_pages", + 2, 1, 10, "max memory pages"); +REDLINE_TUNABLE(kWasmMemoryProb, "generators.WasmModule.memory_probability", + 0.5, 0, 1, "probability of memory"); +REDLINE_TUNABLE(kWasmTableProb, "generators.WasmModule.table_probability", 0.5, + 0, 1, "probability of table"); +REDLINE_TUNABLE(kWasmMaxParams, "generators.WasmModule.max_params", 3, 0, 10, + "max function parameters"); +REDLINE_TUNABLE(kWasmMaxLocals, "generators.WasmModule.max_locals", 5, 0, 20, + "max function locals"); +REDLINE_TUNABLE(kWasmMaxExprDepth, "generators.WasmModule.max_expr_depth", 5, 1, + 20, "max expression depth"); +REDLINE_TUNABLE(kWasmMaxBodySize, "generators.WasmModule.max_body_size", 20, 1, + 200, "max body instructions"); +REDLINE_TUNABLE(kWasmTrapMemoryProb, + "generators.WasmModule.trap_memory_probability", 0.05, 0, 1, + "probability of unmasked memory access"); +REDLINE_TUNABLE(kWasmTrapDivProb, "generators.WasmModule.trap_div_probability", + 0.05, 0, 1, "probability of non-guarded div/rem"); +REDLINE_TUNABLE(kWasmTrapConvertProb, + "generators.WasmModule.trap_convert_probability", 0.05, 0, 1, + "probability of non-saturating convert"); + +namespace { + +void EncodeU32(std::vector<uint8_t>& buf, uint32_t value) { + do { + uint8_t byte = static_cast<uint8_t>(value & 0x7F); + value >>= 7; + if (value != 0) { + byte |= 0x80; + } + buf.push_back(byte); + } while (value != 0); +} + +void EncodeI32(std::vector<uint8_t>& buf, int32_t value) { + bool more = true; + while (more) { + uint8_t byte = static_cast<uint8_t>(value & 0x7F); + value >>= 7; + bool sign_bit = (byte & 0x40) != 0; + if ((value == 0 && !sign_bit) || (value == -1 && sign_bit)) { + more = false; + } else { + byte |= 0x80; + } + buf.push_back(byte); + } +} + +void EncodeI64(std::vector<uint8_t>& buf, int64_t value) { + bool more = true; + while (more) { + uint8_t byte = static_cast<uint8_t>(value & 0x7F); + value >>= 7; + bool sign_bit = (byte & 0x40) != 0; + if ((value == 0 && !sign_bit) || (value == -1 && sign_bit)) { + more = false; + } else { + byte |= 0x80; + } + buf.push_back(byte); + } +} + +void EncodeF32(std::vector<uint8_t>& buf, float value) { + uint32_t bits = 0; + std::memcpy(&bits, &value, sizeof(bits)); + for (size_t i = 0; i < 4; ++i) { + buf.push_back(static_cast<uint8_t>((bits >> (8 * i)) & 0xFF)); + } +} + +void EncodeF64(std::vector<uint8_t>& buf, double value) { + uint64_t bits = 0; + std::memcpy(&bits, &value, sizeof(bits)); + for (size_t i = 0; i < 8; ++i) { + buf.push_back(static_cast<uint8_t>((bits >> (8 * i)) & 0xFF)); + } +} + +void EncodeString(std::vector<uint8_t>& buf, const std::string& str) { + EncodeU32(buf, static_cast<uint32_t>(str.size())); + for (char c : str) { + buf.push_back(static_cast<uint8_t>(c)); + } +} + +class WasmBuilder { + public: + explicit WasmBuilder(Random& r) : r_(r) {} + + WasmModule Build() { + WasmModule m; + + size_t num_imports = + r_.Index(static_cast<size_t>(kWasmMaxImports.AsInt()) + 1); + size_t num_funcs = + 1 + r_.Index(static_cast<size_t>(kWasmMaxFunctions.AsInt())); + m.memory = r_.Chance(kWasmMemoryProb()); + m.table = r_.Chance(kWasmTableProb()); + size_t num_globals = + r_.Index(static_cast<size_t>(kWasmMaxGlobals.AsInt()) + 1); + + for (size_t i = 0; i < num_imports; ++i) { + WasmSignature sig; + size_t params = r_.Index(static_cast<size_t>(kWasmMaxParams.AsInt()) + 1); + for (size_t p = 0; p < params; ++p) { + sig.params.push_back(RandomTypeNoI64()); + } + if (r_.Coin()) { + sig.results.push_back(RandomTypeNoI64()); + } + m.imports.push_back(sig); + sigs_.push_back(sig); + } + + for (size_t i = 0; i < num_funcs; ++i) { + WasmSignature sig; + size_t params = r_.Index(static_cast<size_t>(kWasmMaxParams.AsInt()) + 1); + for (size_t p = 0; p < params; ++p) { + sig.params.push_back(RandomType()); + } + if (r_.Coin()) { + sig.results.push_back(RandomType()); + } + m.functions.push_back(sig); + sigs_.push_back(sig); + } + + for (size_t i = 0; i < num_globals; ++i) { + WasmType type = RandomType(); + bool mut = r_.Coin(); + globals_.push_back({type, mut}); + if (mut) { + m.globals.push_back(type); + } + } + + std::vector<uint8_t>& b = m.bytes; + b.insert(b.end(), {0x00, 0x61, 0x73, 0x6D}); + b.insert(b.end(), {0x01, 0x00, 0x00, 0x00}); + + b.push_back(1); + std::vector<uint8_t> sec_types; + EncodeU32(sec_types, static_cast<uint32_t>(sigs_.size())); + for (const auto& sig : sigs_) { + sec_types.push_back(0x60); + EncodeU32(sec_types, static_cast<uint32_t>(sig.params.size())); + for (auto t : sig.params) { + sec_types.push_back(static_cast<uint8_t>(t)); + } + EncodeU32(sec_types, static_cast<uint32_t>(sig.results.size())); + for (auto t : sig.results) { + sec_types.push_back(static_cast<uint8_t>(t)); + } + } + EncodeU32(b, static_cast<uint32_t>(sec_types.size())); + b.insert(b.end(), sec_types.begin(), sec_types.end()); + + if (num_imports > 0) { + b.push_back(2); + std::vector<uint8_t> sec; + EncodeU32(sec, static_cast<uint32_t>(num_imports)); + for (size_t i = 0; i < num_imports; ++i) { + EncodeString(sec, "m"); + EncodeString(sec, "f" + std::to_string(i)); + sec.push_back(0x00); + EncodeU32(sec, static_cast<uint32_t>(i)); + } + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (num_funcs > 0) { + b.push_back(3); + std::vector<uint8_t> sec; + EncodeU32(sec, static_cast<uint32_t>(num_funcs)); + for (size_t i = 0; i < num_funcs; ++i) { + EncodeU32(sec, static_cast<uint32_t>(num_imports + i)); + } + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (m.table) { + b.push_back(4); + std::vector<uint8_t> sec; + EncodeU32(sec, 1); + sec.push_back(0x70); + sec.push_back(0x00); + EncodeU32(sec, static_cast<uint32_t>(num_funcs)); + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (m.memory) { + b.push_back(5); + std::vector<uint8_t> sec; + EncodeU32(sec, 1); + sec.push_back(0x00); + mem_pages_ = + 1 + r_.Index(static_cast<size_t>(kWasmMaxMemoryPages.AsInt())); + EncodeU32(sec, static_cast<uint32_t>(mem_pages_)); + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (num_globals > 0) { + b.push_back(6); + std::vector<uint8_t> sec; + EncodeU32(sec, static_cast<uint32_t>(num_globals)); + for (const auto& g : globals_) { + sec.push_back(static_cast<uint8_t>(g.type)); + sec.push_back(g.mut ? 0x01 : 0x00); + EmitConst(sec, g.type); + sec.push_back(0x0B); + } + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + { + b.push_back(7); + std::vector<uint8_t> sec; + uint32_t num_exports = + static_cast<uint32_t>(num_funcs + (m.memory ? 1 : 0) + + (m.table ? 1 : 0) + m.globals.size()); + EncodeU32(sec, num_exports); + for (size_t i = 0; i < num_funcs; ++i) { + EncodeString(sec, "e" + std::to_string(i)); + sec.push_back(0x00); + EncodeU32(sec, static_cast<uint32_t>(num_imports + i)); + } + if (m.memory) { + EncodeString(sec, "mem"); + sec.push_back(0x02); + EncodeU32(sec, 0); + } + if (m.table) { + EncodeString(sec, "tab"); + sec.push_back(0x01); + EncodeU32(sec, 0); + } + size_t g_idx = 0; + size_t g_exp = 0; + for (const auto& g : globals_) { + if (g.mut) { + EncodeString(sec, "g" + std::to_string(g_exp++)); + sec.push_back(0x03); + EncodeU32(sec, static_cast<uint32_t>(g_idx)); + } + g_idx++; + } + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (m.table && num_funcs > 0) { + b.push_back(9); + std::vector<uint8_t> sec; + EncodeU32(sec, 1); + sec.push_back(0x00); + sec.push_back(0x41); + EncodeI32(sec, 0); + sec.push_back(0x0B); + EncodeU32(sec, static_cast<uint32_t>(num_funcs)); + for (size_t i = 0; i < num_funcs; ++i) { + EncodeU32(sec, static_cast<uint32_t>(num_imports + i)); + } + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (num_funcs > 0) { + b.push_back(10); + std::vector<uint8_t> sec; + EncodeU32(sec, static_cast<uint32_t>(num_funcs)); + for (size_t i = 0; i < num_funcs; ++i) { + std::vector<uint8_t> code; + size_t num_locals = + r_.Index(static_cast<size_t>(kWasmMaxLocals.AsInt()) + 1); + std::vector<WasmType> locals; + locals.reserve(num_locals); + for (size_t l = 0; l < num_locals; ++l) { + locals.push_back(RandomType()); + } + EncodeU32(code, static_cast<uint32_t>(locals.size())); + for (auto t : locals) { + EncodeU32(code, 1); + code.push_back(static_cast<uint8_t>(t)); + } + + std::vector<WasmType> all_locals = m.functions[i].params; + all_locals.insert(all_locals.end(), locals.begin(), locals.end()); + + WasmType res = m.functions[i].results.empty() + ? WasmType::kI32 + : m.functions[i].results[0]; + + std::vector<WasmType> block_stack; + if (!m.functions[i].results.empty()) { + block_stack.push_back(res); + } + + BuildExpr(code, res, all_locals, kWasmMaxExprDepth.AsInt(), + num_imports + i, block_stack, m); + if (m.functions[i].results.empty()) { + code.push_back(0x1A); + } + + code.push_back(0x0B); + + EncodeU32(sec, static_cast<uint32_t>(code.size())); + sec.insert(sec.end(), code.begin(), code.end()); + } + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + if (m.memory) { + b.push_back(11); + std::vector<uint8_t> sec; + EncodeU32(sec, 1); + sec.push_back(0x00); + sec.push_back(0x41); + EncodeI32(sec, 0); + sec.push_back(0x0B); + std::vector<uint8_t> data(16, 0x42); + EncodeU32(sec, static_cast<uint32_t>(data.size())); + sec.insert(sec.end(), data.begin(), data.end()); + EncodeU32(b, static_cast<uint32_t>(sec.size())); + b.insert(b.end(), sec.begin(), sec.end()); + } + + return m; + } + + private: + Random& r_; + std::vector<WasmSignature> sigs_; + struct Global { + WasmType type; + bool mut; + }; + std::vector<Global> globals_; + size_t mem_pages_ = 0; + + WasmType RandomType() { + size_t t = r_.Index(4); + if (t == 0) { + return WasmType::kI32; + } + if (t == 1) { + return WasmType::kI64; + } + if (t == 2) { + return WasmType::kF32; + } + return WasmType::kF64; + } + + WasmType RandomTypeNoI64() { + size_t t = r_.Index(3); + if (t == 0) { + return WasmType::kI32; + } + if (t == 1) { + return WasmType::kF32; + } + return WasmType::kF64; + } + + void EmitConst(std::vector<uint8_t>& code, WasmType type) { + if (type == WasmType::kI32) { + code.push_back(0x41); + EncodeI32(code, static_cast<int32_t>(r_.Range(-1000, 1000))); + } else if (type == WasmType::kI64) { + code.push_back(0x42); + EncodeI64(code, r_.Range(-1000, 1000)); + } else if (type == WasmType::kF32) { + code.push_back(0x43); + EncodeF32(code, static_cast<float>(r_.Double() * 100.0)); + } else { + code.push_back(0x44); + EncodeF64(code, r_.Double() * 100.0); + } + } + + void BuildExpr(std::vector<uint8_t>& code, WasmType res, + const std::vector<WasmType>& locals, int depth, size_t my_func, + std::vector<WasmType>& block_stack, const WasmModule& m) { + if (depth <= 0) { + EmitConst(code, res); + return; + } + size_t choice = r_.Index(10); + switch (choice) { + default: + break; + case 1: { + std::vector<size_t> cands; + for (size_t i = 0; i < locals.size(); ++i) { + if (locals[i] == res) { + cands.push_back(i); + } + } + if (!cands.empty()) { + code.push_back(0x20); + EncodeU32(code, static_cast<uint32_t>(r_.Pick(cands))); + return; + } + break; + } + case 2: { + std::vector<size_t> cands; + for (size_t i = 0; i < globals_.size(); ++i) { + if (globals_[i].type == res) { + cands.push_back(i); + } + } + if (!cands.empty()) { + code.push_back(0x23); + EncodeU32(code, static_cast<uint32_t>(r_.Pick(cands))); + return; + } + break; + } + case 3: { + WasmType arg_type = res; + if (res == WasmType::kI32 && r_.Coin()) { + arg_type = RandomType(); + } + BuildExpr(code, arg_type, locals, depth - 1, my_func, block_stack, m); + BuildExpr(code, arg_type, locals, depth - 1, my_func, block_stack, m); + + if (res == arg_type && r_.Chance(0.2)) { + if (!r_.Chance(kWasmTrapDivProb())) { + if (arg_type == WasmType::kI32) { + code.push_back(0x41); + EncodeI32(code, 1); + code.push_back(0x72); // i32.or 1 (never 0) + code.push_back(0x6E); // i32.div_u + } else if (arg_type == WasmType::kI64) { + code.push_back(0x42); + EncodeI64(code, 1); + code.push_back(0x84); // i64.or 1 (never 0) + code.push_back(0x80); // i64.div_u + } else if (arg_type == WasmType::kF32) { + code.push_back(0x43); + EncodeF32(code, 1.0f); + code.push_back(0x92); + code.push_back(0x95); // f32.div + } else { + code.push_back(0x44); + EncodeF64(code, 1.0); + code.push_back(0xA0); + code.push_back(0xA3); // f64.div + } + } else { + if (arg_type == WasmType::kI32) { + code.push_back(0x6D); // i32.div_s + } else if (arg_type == WasmType::kI64) { + code.push_back(0x7F); // i64.div_s + } else if (arg_type == WasmType::kF32) { + code.push_back(0x95); // f32.div + } else { + code.push_back(0xA3); // f64.div + } + } + } else { + if (arg_type == WasmType::kI32) { + if (res == WasmType::kI32) { + code.push_back(r_.Coin() ? 0x6A : 0x6B); + } else { + code.push_back(r_.Coin() ? 0x46 : 0x47); + } + } else if (arg_type == WasmType::kI64) { + if (res == WasmType::kI64) { + code.push_back(r_.Coin() ? 0x7C : 0x7D); + } else { + code.push_back(r_.Coin() ? 0x51 : 0x52); + } + } else if (arg_type == WasmType::kF32) { + if (res == WasmType::kF32) { + code.push_back(r_.Coin() ? 0x92 : 0x93); + } else { + code.push_back(r_.Coin() ? 0x5B : 0x5C); + } + } else { + if (res == WasmType::kF64) { + code.push_back(r_.Coin() ? 0xA0 : 0xA1); + } else { + code.push_back(r_.Coin() ? 0x61 : 0x62); + } + } + } + return; + } + case 4: { + std::vector<size_t> cands; + for (size_t i = 0; i < sigs_.size(); ++i) { + if (i < my_func && + ((sigs_[i].results.empty() && res == WasmType::kI32) || + (!sigs_[i].results.empty() && sigs_[i].results[0] == res))) { + cands.push_back(i); + } + } + if (!cands.empty()) { + size_t callee = r_.Pick(cands); + for (auto t : sigs_[callee].params) { + BuildExpr(code, t, locals, depth - 1, my_func, block_stack, m); + } + code.push_back(0x10); + EncodeU32(code, static_cast<uint32_t>(callee)); + if (sigs_[callee].results.empty()) { + EmitConst(code, res); + } + return; + } + break; + } + case 5: { + WasmType arg_type = RandomType(); + BuildExpr(code, arg_type, locals, depth - 1, my_func, block_stack, m); + if (res == WasmType::kI32 && arg_type == WasmType::kI64) { + code.push_back(0xA7); + } else if (res == WasmType::kI32 && arg_type == WasmType::kF32) { + if (r_.Chance(kWasmTrapConvertProb())) { + code.push_back(0xA8); + } else { + code.push_back(0xFC); + EncodeU32(code, 0); + } + } else if (res == WasmType::kI32 && arg_type == WasmType::kF64) { + if (r_.Chance(kWasmTrapConvertProb())) { + code.push_back(0xAA); + } else { + code.push_back(0xFC); + EncodeU32(code, 2); + } + } else if (res == WasmType::kI64 && arg_type == WasmType::kI32) { + code.push_back(0xAC); + } else if (res == WasmType::kI64 && arg_type == WasmType::kF32) { + if (r_.Chance(kWasmTrapConvertProb())) { + code.push_back(0xAE); + } else { + code.push_back(0xFC); + EncodeU32(code, 4); + } + } else if (res == WasmType::kI64 && arg_type == WasmType::kF64) { + if (r_.Chance(kWasmTrapConvertProb())) { + code.push_back(0xB0); + } else { + code.push_back(0xFC); + EncodeU32(code, 6); + } + } else if (res == WasmType::kF32 && arg_type == WasmType::kI32) { + code.push_back(0xB2); + } else if (res == WasmType::kF32 && arg_type == WasmType::kI64) { + code.push_back(0xB4); + } else if (res == WasmType::kF32 && arg_type == WasmType::kF64) { + code.push_back(0xB6); + } else if (res == WasmType::kF64 && arg_type == WasmType::kI32) { + code.push_back(0xB7); + } else if (res == WasmType::kF64 && arg_type == WasmType::kI64) { + code.push_back(0xB9); + } else if (res == WasmType::kF64 && arg_type == WasmType::kF32) { + code.push_back(0xBB); + } else { + code.push_back(0x1A); + EmitConst(code, res); + } + return; + } + case 6: { + if (m.memory) { + BuildExpr(code, WasmType::kI32, locals, depth - 1, my_func, + block_stack, m); + if (!r_.Chance(kWasmTrapMemoryProb())) { + code.push_back(0x41); + EncodeI32(code, static_cast<int32_t>((mem_pages_ * 65536) - 8)); + code.push_back(0x71); + } + if (res == WasmType::kI32) { + code.push_back(0x28); + EncodeU32(code, 2); + EncodeU32(code, 0); + } else if (res == WasmType::kI64) { + code.push_back(0x29); + EncodeU32(code, 3); + EncodeU32(code, 0); + } else if (res == WasmType::kF32) { + code.push_back(0x2A); + EncodeU32(code, 2); + EncodeU32(code, 0); + } else { + code.push_back(0x2B); + EncodeU32(code, 3); + EncodeU32(code, 0); + } + return; + } + break; + } + case 7: { + block_stack.push_back(res); + code.push_back(0x02); + code.push_back(static_cast<uint8_t>(res)); + BuildExpr(code, res, locals, depth - 1, my_func, block_stack, m); + code.push_back(0x0B); + block_stack.pop_back(); + return; + } + case 8: { + BuildExpr(code, WasmType::kI32, locals, depth - 1, my_func, block_stack, + m); + block_stack.push_back(res); + code.push_back(0x04); + code.push_back(static_cast<uint8_t>(res)); + BuildExpr(code, res, locals, depth - 1, my_func, block_stack, m); + code.push_back(0x05); + BuildExpr(code, res, locals, depth - 1, my_func, block_stack, m); + code.push_back(0x0B); + block_stack.pop_back(); + return; + } + case 9: { + if (!block_stack.empty()) { + std::vector<size_t> cands; + for (size_t i = 0; i < block_stack.size(); ++i) { + if (block_stack[block_stack.size() - 1 - i] == res) { + cands.push_back(i); + } + } + if (!cands.empty()) { + BuildExpr(code, res, locals, depth - 1, my_func, block_stack, m); + BuildExpr(code, WasmType::kI32, locals, depth - 1, my_func, + block_stack, m); + code.push_back(0x0D); + EncodeU32(code, static_cast<uint32_t>(r_.Pick(cands))); + return; + } + } + break; + } + } + EmitConst(code, res); + } +}; + +} // namespace + +WasmModule RandomWasmModule(Random& r) { + WasmBuilder builder(r); + return builder.Build(); +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/generators/wasm_module.h b/deps/v8/experimental/redline/generators/wasm_module.h new file mode 100644 index 000000000000..8bd53f23b85b --- /dev/null +++ b/deps/v8/experimental/redline/generators/wasm_module.h @@ -0,0 +1,54 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_GENERATORS_WASM_MODULE_H_ +#define V8_EXPERIMENTAL_REDLINE_GENERATORS_WASM_MODULE_H_ + +#include <cstdint> +#include <string> +#include <vector> + +#include "experimental/redline/core/random.h" + +namespace redline { + +// Value types of the generated modules (their binary encoding). +enum class WasmType : uint8_t { + kI32 = 0x7F, + kI64 = 0x7E, + kF32 = 0x7D, + kF64 = 0x7C, +}; + +struct WasmSignature { + std::vector<WasmType> params; + std::vector<WasmType> results; // empty or one value +}; + +// A random WebAssembly module, valid by construction, and what the JavaScript +// side needs to use it. +struct WasmModule { + std::vector<uint8_t> bytes; + // Imported functions "m"."f0", "m"."f1", ... with their signatures. + std::vector<WasmSignature> imports; + // Exported functions "e0", "e1", ... with their signatures. + std::vector<WasmSignature> functions; + // Exported mutable globals "g0", "g1", ... with their types. + std::vector<WasmType> globals; + bool memory = false; // exported as "mem" + bool table = false; // exported as "tab" +}; + +// Builds a module from general building blocks: function types, imports, +// a memory with data, a function table with an element segment, globals and +// functions whose bodies are typed expression trees (arithmetic, +// comparisons, conversions, loads and stores, calls, call_indirect, select, +// blocks, ifs and bounded loops). Calls only go to lower function indices, +// loops are counted, and memory addresses are masked, so most executions +// terminate without a trap. +WasmModule RandomWasmModule(Random& r); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_GENERATORS_WASM_MODULE_H_ diff --git a/deps/v8/experimental/redline/main.cc b/deps/v8/experimental/redline/main.cc new file mode 100644 index 000000000000..15e2198aed02 --- /dev/null +++ b/deps/v8/experimental/redline/main.cc @@ -0,0 +1,154 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// redline: a coverage-guided JavaScript fuzzer for d8. +// +// redline <command> [--flags] [args] +// +// Run "redline help" for the list of commands and "redline help <command>" +// for the flags of one command. + +#include <cstdio> +#include <cstring> +#include <string> +#include <vector> + +#include "experimental/redline/base/flags.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/commands/command.h" +#include "include/v8-version-string.h" + +namespace redline { + +namespace { + +constexpr const char* kLog = "redline"; + +const char kGlobalFlagsHelp[] = + "global flags:\n" + " --log-level=verbose|info|warning|error (default info)\n" + " --verbose same as --log-level=verbose\n" + "\n" + "target flags (commands that run d8):\n" + " --d8=PATH the instrumented d8 (or $REDLINE_D8)\n" + " --d8-args=\"--a --b\" replace the default d8 flags\n" + " --d8-extra-args=\"--c\" append to the d8 flags\n" + " --d8-env=K=V,K2=V2 extra environment variables for d8\n" + " --timeout-ms=N per-execution timeout (default 1000)\n" + " --max-execs-before-respawn=N respawn d8 after N executions (1000)\n" + " --no-capture-output do not capture d8 stdout/stderr\n"; + +int RunVersion(const Flags&); +int RunHelp(const Flags& flags); + +const Command kVersionCommand = { + "version", "Print the V8 version this binary was built from", + "usage: redline version\n", RunVersion}; + +const Command kHelpCommand = {"help", "Show help for a command", + "usage: redline help [command]\n", RunHelp}; + +const Command* const kCommands[] = { + &kFuzzCommand, &kShellCommand, &kMutateCommand, &kAuditCommand, + &kMinimizeCommand, &kAmplifyCommand, &kExecCommand, &kReplayCommand, + &kParseCommand, &kRoundtripCommand, &kSelftestCommand, &kVersionCommand, + &kHelpCommand, +}; + +const Command* FindCommand(const std::string& name) { + for (const Command* command : kCommands) { + if (name == command->name) { + return command; + } + } + return nullptr; +} + +void PrintCommandList() { + printf("usage: redline <command> [flags] [args]\n\ncommands:\n"); + for (const Command* command : kCommands) { + printf(" %-10s %s\n", command->name, command->summary); + } + printf("\n%s", kGlobalFlagsHelp); +} + +int RunVersion(const Flags&) { + printf("redline (V8 %s)\n", V8_VERSION_STRING); + return kExitOk; +} + +int RunHelp(const Flags& flags) { + if (flags.positional().empty()) { + PrintCommandList(); + return kExitOk; + } + const Command* command = FindCommand(flags.positional()[0]); + if (command == nullptr) { + fprintf(stderr, "Unknown command '%s'\n", flags.positional()[0].c_str()); + PrintCommandList(); + return kExitUsage; + } + printf("%s\n%s", command->usage, kGlobalFlagsHelp); + return kExitOk; +} + +bool ApplyGlobalFlags(const Flags& flags) { + std::string level = flags.GetString("log-level", "info"); + if (flags.GetBool("verbose", false)) { + level = "verbose"; + } + if (level == "verbose") { + SetLogLevel(LogLevel::kVerbose); + } else if (level == "info") { + SetLogLevel(LogLevel::kInfo); + } else if (level == "warning") { + SetLogLevel(LogLevel::kWarning); + } else if (level == "error") { + SetLogLevel(LogLevel::kError); + } else { + fprintf(stderr, "Unknown --log-level=%s\n", level.c_str()); + return false; + } + return true; +} + +int Main(int argc, const char* const* argv) { + if (argc < 2 || strcmp(argv[1], "--help") == 0 || + strcmp(argv[1], "-h") == 0) { + PrintCommandList(); + return argc < 2 ? kExitUsage : kExitOk; + } + const Command* command = FindCommand(argv[1]); + if (command == nullptr) { + fprintf(stderr, "Unknown command '%s'\n\n", argv[1]); + PrintCommandList(); + return kExitUsage; + } + Flags flags = Flags::Parse(argc, argv, 2); + if (flags.GetBool("help", false)) { + printf("%s\n%s", command->usage, kGlobalFlagsHelp); + return kExitOk; + } + if (!ApplyGlobalFlags(flags)) { + return kExitUsage; + } + int result = command->run(flags); + // A command that stopped early on an error has not read its remaining + // flags; reporting those as typos would only bury the real error. + if (result == kExitOk) { + for (const std::string& unused : flags.UnusedFlags()) { + REDLINE_WARN(kLog, "Flag --%s is not used by '%s' (typo?)", + unused.c_str(), command->name); + } + } + return result; +} + +} // namespace + +} // namespace redline + +int main(int argc, char* argv[]) { + return redline::Main(argc, const_cast<const char* const*>(argv)); +} diff --git a/deps/v8/experimental/redline/minimizer/minimizer.cc b/deps/v8/experimental/redline/minimizer/minimizer.cc new file mode 100644 index 000000000000..0a9c7fb7a6a3 --- /dev/null +++ b/deps/v8/experimental/redline/minimizer/minimizer.cc @@ -0,0 +1,1153 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/minimizer/minimizer.h" + +#include <algorithm> +#include <limits> +#include <map> +#include <unordered_set> +#include <utility> + +#include "experimental/redline/base/log.h" +#include "experimental/redline/base/time_util.h" +#include "experimental/redline/base/v8_runtime.h" +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/fast/ast_visit.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/fast/scope.h" + +namespace redline { + +using fast::Expression; +using fast::Node; +using fast::NodeKind; +using fast::Statement; +using StatementList = std::vector<Statement*>; + +// --------------------------------------------------------------------------- +// MinimizationHelper + +MinimizationHelper::MinimizationHelper(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker, + const MinimizerOptions& options) + : tree_(tree), + oracle_(oracle), + checker_(checker), + options_(options), + start_us_(MonotonicNowUs()) {} + +bool MinimizationHelper::BudgetExhausted() const { + if (result_.tests >= options_.max_tests) { + return true; + } + if (options_.max_time_ms != 0 && + (MonotonicNowUs() - start_us_) / 1000 >= options_.max_time_ms) { + return true; + } + return false; +} + +bool MinimizationHelper::Test() { + if (BudgetExhausted()) { + result_.budget_exhausted = true; + return false; + } + std::string source = fast::Print(tree_->root()); + if (checker_ != nullptr) { + std::string message; + if (!checker_->Accepts(source, &message)) { + result_.syntax_rejected++; + if (reducer_ != nullptr) { + reducer_->stats().invalid++; + } + return false; + } + } + result_.tests++; + Stopwatch stopwatch; + bool ok = oracle_(source); + if (reducer_ != nullptr) { + ComponentStats& stats = reducer_->stats(); + stats.executed++; + stats.time_us += stopwatch.ElapsedUs(); + if (ok) { + stats.succeeded++; + } else { + stats.failed++; + } + } + if (ok) { + result_.accepted++; + } + return ok; +} + +// --------------------------------------------------------------------------- +// Tree helpers + +namespace { + +template <typename F> +void Walk(Node* node, F& f) { + if (node == nullptr) { + return; + } + f(node); + fast::ForEachChildSlot(node, [&](Node** slot) { + if (*slot != nullptr) { + Walk(*slot, f); + } + }); +} + +StatementList* StatementListOf(Node* node) { + switch (node->kind) { + case NodeKind::kProgram: + return &node->Cast<fast::Program>()->body; + case NodeKind::kBlockStatement: + return &node->Cast<fast::BlockStatement>()->body; + case NodeKind::kSwitchCase: + return &node->Cast<fast::SwitchCase>()->consequent; + case NodeKind::kStaticBlock: + return &node->Cast<fast::StaticBlock>()->body; + default: + return nullptr; + } +} + +// Every statement list reachable from `root`, outermost first. +std::vector<StatementList*> CollectStatementLists(Node* root) { + std::vector<StatementList*> lists; + auto visit = [&](Node* node) { + StatementList* list = StatementListOf(node); + if (list != nullptr) { + lists.push_back(list); + } + }; + Walk(root, visit); + return lists; +} + +// The statements of a body: the block's statements or the statement itself. +void BodyStatements(Statement* body, std::vector<Statement*>* out) { + if (body == nullptr) { + return; + } + if (auto* block = body->As<fast::BlockStatement>()) { + out->insert(out->end(), block->body.begin(), block->body.end()); + } else { + out->push_back(body); + } +} + +bool IsUnlabeledBreak(const Statement* s) { + const auto* b = s->As<fast::BreakStatement>(); + return b != nullptr && b->label == nullptr; +} + +// Removes a contiguous range of a list, tests, and restores on failure. +// Returns whether the removal was kept. +template <typename T> +bool TryRemoveRange(std::vector<T*>& list, size_t begin, size_t end, + MinimizationHelper& helper) { + std::vector<T*> removed(list.begin() + static_cast<ptrdiff_t>(begin), + list.begin() + static_cast<ptrdiff_t>(end)); + list.erase(list.begin() + static_cast<ptrdiff_t>(begin), + list.begin() + static_cast<ptrdiff_t>(end)); + if (helper.Test()) { + return true; + } + list.insert(list.begin() + static_cast<ptrdiff_t>(begin), removed.begin(), + removed.end()); + return false; +} + +// Delta-debugging style trimming of a list: tries to remove chunks of +// halving size, from the end of the list (later elements rarely have +// dependants). Never shrinks the list below `min_size`. +template <typename T> +int TrimList(std::vector<T*>& list, size_t min_size, + MinimizationHelper& helper) { + int accepted = 0; + if (list.size() <= min_size) { + return 0; + } + size_t chunk = std::max<size_t>(1, list.size() / 2); + while (!helper.BudgetExhausted()) { + size_t end = list.size(); + while (end > 0 && list.size() > min_size && !helper.BudgetExhausted()) { + size_t begin = end > chunk ? end - chunk : 0; + // Respect the minimum size. + if (list.size() - (end - begin) < min_size) { + begin = end - (list.size() - min_size); + } + if (begin >= end) { + break; + } + if (TryRemoveRange(list, begin, end, helper)) { + accepted++; + } + end = begin; + } + if (chunk == 1) { + break; + } + chunk = std::max<size_t>(1, chunk / 2); + } + return accepted; +} + +// Removes trailing elements one at a time until the oracle objects. +template <typename T> +int TrimTrailing(std::vector<T*>& list, size_t min_size, + MinimizationHelper& helper) { + int accepted = 0; + while (list.size() > min_size && !helper.BudgetExhausted()) { + T* last = list.back(); + list.pop_back(); + if (helper.Test()) { + accepted++; + } else { + list.push_back(last); + break; + } + } + return accepted; +} + +void RemoveEmptyStatements(Node* root) { + for (StatementList* list : CollectStatementLists(root)) { + list->erase(std::remove_if( + list->begin(), list->end(), + [](Statement* s) { return s->Is<fast::EmptyStatement>(); }), + list->end()); + } +} + +// --------------------------------------------------------------------------- +// Reducers + +// Keeps the shortest prefix of the top-level statements that still passes +// the oracle: what comes after the point where the preserved property is +// reached goes away in about log2(N) tests (binary search on the prefix +// length). Works with any oracle. Runs before `statements`, which then +// works on the shorter program. +class Truncator : public Reducer { + public: + Truncator() + : Reducer("truncate", + "keep the shortest prefix of the top-level statements") {} + + int Reduce(MinimizationHelper& helper) override { + StatementList* body = StatementListOf(helper.tree()->root()); + if (body == nullptr || body->size() < 2) { + return 0; + } + const std::vector<Statement*> all = *body; + // Invariant: the prefix of length `good` passes (the whole program + // does), prefixes shorter than `lo` were tested and failed. + size_t lo = 0, good = all.size(); + while (lo < good && !helper.BudgetExhausted()) { + size_t mid = lo + (good - lo) / 2; + body->assign(all.begin(), all.begin() + static_cast<ptrdiff_t>(mid)); + if (helper.Test()) { + good = mid; + } else { + lo = mid + 1; + } + } + body->assign(all.begin(), all.begin() + static_cast<ptrdiff_t>(good)); + return good < all.size() ? 1 : 0; + } +}; + +// Removes the parts of the program that the rest does not use: the +// top-level statements form a graph in which two statements are connected +// when one references a binding the other declares (scope analysis +// resolves every identifier). Each connected part that does not contain +// every statement is removed with one test. Side effects through globals, +// prototypes or getters can connect statements that share no binding, so +// the graph only proposes the cut; the oracle decides. +class DataflowReducer : public Reducer { + public: + DataflowReducer() + : Reducer("dataflow", + "remove top-level statements the rest of the program does not " + "use") {} + + int Reduce(MinimizationHelper& helper) override { + StatementList* body = StatementListOf(helper.tree()->root()); + if (body == nullptr || body->size() < 2) { + return 0; + } + std::vector<std::vector<size_t>> parts = Parts(helper.tree(), *body); + if (parts.size() < 2) { + return 0; + } + // Later parts first: later statements rarely have dependants. + std::sort(parts.begin(), parts.end(), + [](const auto& a, const auto& b) { return a.back() > b.back(); }); + const std::vector<Statement*> all = *body; + std::vector<bool> removed(all.size(), false); + int accepted = 0; + for (const std::vector<size_t>& part : parts) { + if (helper.BudgetExhausted()) { + break; + } + for (size_t index : part) { + removed[index] = true; + } + Assign(all, removed, body); + if (body->empty()) { + for (size_t index : part) { + removed[index] = false; + } + continue; + } + if (helper.Test()) { + accepted++; + continue; + } + for (size_t index : part) { + removed[index] = false; + } + } + Assign(all, removed, body); + return accepted; + } + + private: + static void Assign(const std::vector<Statement*>& all, + const std::vector<bool>& removed, StatementList* body) { + body->clear(); + for (size_t i = 0; i < all.size(); i++) { + if (!removed[i]) { + body->push_back(all[i]); + } + } + } + + // The connected parts of the def-use graph of the top-level statements, + // each as a sorted list of statement indices. + static std::vector<std::vector<size_t>> Parts(fast::Tree* tree, + const StatementList& body) { + // Which top-level statement each node belongs to. + constexpr size_t kNone = std::numeric_limits<size_t>::max(); + std::vector<size_t> owner(tree->id_limit(), kNone); + for (size_t i = 0; i < body.size(); i++) { + auto mark = [&](Node* node) { + if (node->id < owner.size()) { + owner[node->id] = i; + } + }; + Walk(body[i], mark); + } + std::vector<size_t> parent(body.size()); + for (size_t i = 0; i < parent.size(); i++) { + parent[i] = i; + } + auto find = [&](size_t x) { + while (parent[x] != x) { + parent[x] = parent[parent[x]]; + x = parent[x]; + } + return x; + }; + std::unique_ptr<fast::ScopeAnalysis> scopes = + fast::ScopeAnalysis::Analyze(tree); + auto owner_of = [&](const Node* node) { + return node != nullptr && node->id < owner.size() ? owner[node->id] + : kNone; + }; + for (const fast::Binding* binding : scopes->bindings()) { + size_t declared = owner_of(binding->identifier); + if (declared == kNone) { + continue; + } + for (const fast::Identifier* reference : binding->references) { + size_t used = owner_of(reference); + if (used != kNone && used != declared) { + parent[find(used)] = find(declared); + } + } + } + std::map<size_t, std::vector<size_t>> by_root; + for (size_t i = 0; i < body.size(); i++) { + by_root[find(i)].push_back(i); + } + std::vector<std::vector<size_t>> parts; + parts.reserve(by_root.size()); + for (auto& [root, part] : by_root) { + parts.push_back(std::move(part)); + } + return parts; + } +}; + +// Removes statements: chunks first, then single statements, outermost +// lists first. The workhorse; most of the size reduction comes from here. +class StatementRemover : public Reducer { + public: + StatementRemover() + : Reducer("statements", "remove statements (chunks, then one by one)") {} + + int Reduce(MinimizationHelper& helper) override { + int accepted = 0; + std::unordered_set<StatementList*> done; + while (!helper.BudgetExhausted()) { + StatementList* list = nullptr; + for (StatementList* candidate : + CollectStatementLists(helper.tree()->root())) { + if (done.count(candidate) == 0) { + list = candidate; + break; + } + } + if (list == nullptr) { + break; + } + done.insert(list); + accepted += TrimList(*list, 0, helper); + } + return accepted; + } +}; + +// Replaces a compound statement by (parts of) its body: `if (c) { S }` by +// `S`, a loop by its body, `try { S } catch {}` by `S`, an IIFE by its +// statements, and so on. Exposes nested statements to StatementRemover. +class Unwrapper : public Reducer { + public: + Unwrapper() + : Reducer("unwrap", + "replace blocks, ifs, loops, try, IIFEs by their bodies") {} + + int Reduce(MinimizationHelper& helper) override { + int accepted = 0; + std::unordered_set<Statement*> failed; + bool progress = true; + while (progress && !helper.BudgetExhausted()) { + progress = false; + for (StatementList* list : CollectStatementLists(helper.tree()->root())) { + for (size_t i = 0; i < list->size() && !helper.BudgetExhausted(); i++) { + Statement* statement = (*list)[i]; + if (failed.count(statement) != 0) { + continue; + } + std::vector<std::vector<Statement*>> alternatives; + Alternatives(helper.tree(), statement, &alternatives); + if (alternatives.empty()) { + continue; + } + bool kept = false; + for (const std::vector<Statement*>& replacement : alternatives) { + list->erase(list->begin() + static_cast<ptrdiff_t>(i)); + list->insert(list->begin() + static_cast<ptrdiff_t>(i), + replacement.begin(), replacement.end()); + if (helper.Test()) { + kept = true; + break; + } + list->erase( + list->begin() + static_cast<ptrdiff_t>(i), + list->begin() + static_cast<ptrdiff_t>(i + replacement.size())); + list->insert(list->begin() + static_cast<ptrdiff_t>(i), statement); + } + if (kept) { + accepted++; + progress = true; + // The list and the nested lists changed: start over. + goto restart; + } + failed.insert(statement); + } + } + restart: {} + } + return accepted; + } + + private: + static void Alternatives(fast::Tree* tree, Statement* statement, + std::vector<std::vector<Statement*>>* out) { + switch (statement->kind) { + case NodeKind::kBlockStatement: + out->push_back(statement->Cast<fast::BlockStatement>()->body); + return; + case NodeKind::kIfStatement: { + auto* n = statement->Cast<fast::IfStatement>(); + out->emplace_back(); + BodyStatements(n->consequent, &out->back()); + if (n->alternate != nullptr) { + out->emplace_back(); + BodyStatements(n->alternate, &out->back()); + } + return; + } + case NodeKind::kWhileStatement: + out->emplace_back(); + BodyStatements(statement->Cast<fast::WhileStatement>()->body, + &out->back()); + return; + case NodeKind::kDoWhileStatement: + out->emplace_back(); + BodyStatements(statement->Cast<fast::DoWhileStatement>()->body, + &out->back()); + return; + case NodeKind::kForStatement: { + auto* n = statement->Cast<fast::ForStatement>(); + out->emplace_back(); + if (n->init != nullptr) { + if (n->init->IsStatement()) { + out->back().push_back(static_cast<Statement*>(n->init)); + } else if (n->init->IsExpression()) { + out->back().push_back( + mk::ExprStmt(tree, static_cast<Expression*>(n->init))); + } + } + BodyStatements(n->body, &out->back()); + return; + } + case NodeKind::kForInStatement: + case NodeKind::kForOfStatement: { + Node* left; + Expression* right; + Statement* body; + if (auto* fi = statement->As<fast::ForInStatement>()) { + left = fi->left; + right = fi->right; + body = fi->body; + } else { + auto* fo = statement->Cast<fast::ForOfStatement>(); + left = fo->left; + right = fo->right; + body = fo->body; + } + out->emplace_back(); + // Keep the data flow: bind the loop variable to the iterated value. + if (auto* decl = left->As<fast::VariableDeclaration>()) { + if (decl->declarations.size() == 1 && + decl->declarations[0]->init == nullptr) { + auto* bound = tree->New<fast::VariableDeclaration>(); + bound->declaration_kind = + decl->declaration_kind == fast::VariableKind::kConst + ? fast::VariableKind::kLet + : decl->declaration_kind; + auto* declarator = tree->New<fast::VariableDeclarator>(); + declarator->target = decl->declarations[0]->target; + declarator->init = right; + bound->declarations.push_back(declarator); + out->back().push_back(bound); + } + } else if (left->IsExpression()) { + out->back().push_back(mk::ExprStmt( + tree, mk::Assign(tree, static_cast<Expression*>(left), right))); + } + BodyStatements(body, &out->back()); + return; + } + case NodeKind::kTryStatement: { + auto* n = statement->Cast<fast::TryStatement>(); + out->emplace_back(n->block->body); + if (n->finalizer != nullptr) { + out->back().insert(out->back().end(), n->finalizer->body.begin(), + n->finalizer->body.end()); + } + if (n->handler != nullptr && !n->handler->body->body.empty()) { + out->emplace_back(n->handler->body->body); + } + return; + } + case NodeKind::kLabeledStatement: + out->emplace_back(); + BodyStatements(statement->Cast<fast::LabeledStatement>()->body, + &out->back()); + return; + case NodeKind::kWithStatement: + out->emplace_back(); + BodyStatements(statement->Cast<fast::WithStatement>()->body, + &out->back()); + return; + case NodeKind::kSwitchStatement: { + auto* n = statement->Cast<fast::SwitchStatement>(); + out->emplace_back(); + for (fast::SwitchCase* c : n->cases) { + for (Statement* s : c->consequent) { + if (!IsUnlabeledBreak(s)) { + out->back().push_back(s); + } + } + } + return; + } + case NodeKind::kExpressionStatement: { + // IIFE: (function () { S })() or (() => { S })(). + auto* expression = + statement->Cast<fast::ExpressionStatement>()->expression; + auto* call = expression->As<fast::CallExpression>(); + if (call == nullptr || !call->arguments.empty()) { + return; + } + fast::FunctionData* fn = nullptr; + if (auto* f = call->callee->As<fast::FunctionExpression>()) { + fn = f; + } + if (auto* a = call->callee->As<fast::ArrowFunctionExpression>()) { + fn = a; + } + if (fn == nullptr || fn->body == nullptr || !fn->params.empty()) { + return; + } + out->emplace_back(fn->body->body); + return; + } + default: + return; + } + } +}; + +// Shortens lists that are not statement lists: call arguments, array +// elements, object properties, class members, declarators, parameters. +class ListTrimmer : public Reducer { + public: + ListTrimmer() + : Reducer("lists", + "drop call arguments, array elements, properties, parameters") { + } + + int Reduce(MinimizationHelper& helper) override { + int accepted = 0; + auto visit = [&](Node* node) { + if (helper.BudgetExhausted()) { + return; + } + switch (node->kind) { + case NodeKind::kCallExpression: + accepted += TrimList(node->Cast<fast::CallExpression>()->arguments, 0, + helper); + break; + case NodeKind::kNewExpression: + accepted += + TrimList(node->Cast<fast::NewExpression>()->arguments, 0, helper); + break; + case NodeKind::kArrayExpression: + accepted += TrimList(node->Cast<fast::ArrayExpression>()->elements, 0, + helper); + break; + case NodeKind::kObjectExpression: + accepted += TrimList(node->Cast<fast::ObjectExpression>()->properties, + 0, helper); + break; + case NodeKind::kClassBody: + accepted += + TrimList(node->Cast<fast::ClassBody>()->members, 0, helper); + break; + case NodeKind::kVariableDeclaration: + accepted += TrimList( + node->Cast<fast::VariableDeclaration>()->declarations, 1, helper); + break; + case NodeKind::kSequenceExpression: + accepted += TrimList( + node->Cast<fast::SequenceExpression>()->expressions, 1, helper); + break; + case NodeKind::kSwitchStatement: + accepted += + TrimList(node->Cast<fast::SwitchStatement>()->cases, 0, helper); + break; + case NodeKind::kFunctionDeclaration: + accepted += TrimTrailing( + node->Cast<fast::FunctionDeclaration>()->params, 0, helper); + break; + case NodeKind::kFunctionExpression: + accepted += TrimTrailing( + node->Cast<fast::FunctionExpression>()->params, 0, helper); + break; + case NodeKind::kArrowFunctionExpression: + accepted += TrimTrailing( + node->Cast<fast::ArrowFunctionExpression>()->params, 0, helper); + break; + default: + break; + } + }; + Walk(helper.tree()->root(), visit); + return accepted; + } +}; + +REDLINE_TUNABLE(kExpressionsMaxCallArguments, + "minimizer.expressions.max_call_arguments", 2, 0, 8, + "leading arguments of a call or `new` that are tried as its " + "replacement (the callee always is)"); + +// Replaces expressions by one of their operands or by a constant: +// `a + f(b)` -> `a`, `f(b)` -> `b`, `o.p.q` -> `o.p`, `x ? y : z` -> `y`, +// anything -> `0` / `undefined`. +class ExpressionSimplifier : public Reducer { + public: + ExpressionSimplifier() + : Reducer("expressions", + "replace expressions by an operand or a constant") {} + + int Reduce(MinimizationHelper& helper) override { + int accepted = 0; + // (slot, alternative index) pairs that were already rejected. + std::unordered_set<uint64_t> failed; + bool progress = true; + while (progress && !helper.BudgetExhausted()) { + progress = false; + std::vector<Slot> slots = CollectSlots(helper.tree()->root()); + for (const Slot& s : slots) { + if (helper.BudgetExhausted()) { + break; + } + Node** slot = s.field; + auto* current = static_cast<Expression*>(*slot); + if (IsAtomic(current)) { + continue; + } + // A loop condition is only ever replaced by a falsy constant: any + // other replacement risks turning the loop into an infinite one. + std::vector<Expression*> alternatives = + s.loop_test ? std::vector<Expression*>{mk::Num(helper.tree(), 0)} + : Alternatives(helper.tree(), current); + for (size_t alt = 0; alt < alternatives.size(); alt++) { + // Slots are 8-byte aligned pointers; 4 bits hold the index of + // any alternative (at most max_call_arguments + 3 of them). + uint64_t key = reinterpret_cast<uint64_t>(slot) * 16 + alt; + if (failed.count(key) != 0) { + continue; + } + *slot = alternatives[alt]; + if (helper.Test()) { + accepted++; + progress = true; + break; + } + *slot = current; + failed.insert(key); + } + if (progress) { + break; // the tree changed: recollect the slots + } + } + } + return accepted; + } + + private: + static bool IsAtomic(const Expression* e) { + switch (e->kind) { + case NodeKind::kIdentifier: + case NodeKind::kNullLiteral: + case NodeKind::kBooleanLiteral: + case NodeKind::kNumericLiteral: + case NodeKind::kBigIntLiteral: + case NodeKind::kStringLiteral: + case NodeKind::kRegExpLiteral: + case NodeKind::kThisExpression: + case NodeKind::kSuper: + case NodeKind::kPrivateIdentifier: + case NodeKind::kMetaProperty: + case NodeKind::kTemplateLiteral: + return true; + default: + return false; + } + } + + static bool IsValueOperand(const Expression* e) { + return e != nullptr && !e->Is<fast::SpreadElement>() && + !e->Is<fast::Super>() && !e->Is<fast::PrivateIdentifier>() && + !e->IsPattern(); + } + + // An expression slot in value position. `loop_test` marks the condition of + // a loop, which must only be replaced by something that terminates it. + struct Slot { + Node** field; + bool loop_test; + }; + + // Slots holding an expression in value position whose replacement by an + // arbitrary expression keeps the program syntactically valid. + static std::vector<Slot> CollectSlots(Node* root) { + std::vector<Slot> slots; + auto add = [&](auto*& field) { + if (IsValueOperand(field)) { + slots.push_back({reinterpret_cast<Node**>(&field), false}); + } + }; + auto add_loop_test = [&](auto*& field) { + if (IsValueOperand(field)) { + slots.push_back({reinterpret_cast<Node**>(&field), true}); + } + }; + auto add_list = [&](std::vector<Expression*>& list) { + for (Expression*& e : list) { + add(e); + } + }; + auto visit = [&](Node* node) { + switch (node->kind) { + case NodeKind::kExpressionStatement: { + auto* n = node->Cast<fast::ExpressionStatement>(); + if (!n->is_directive) { + add(n->expression); + } + break; + } + case NodeKind::kVariableDeclarator: + add(node->Cast<fast::VariableDeclarator>()->init); + break; + case NodeKind::kReturnStatement: + add(node->Cast<fast::ReturnStatement>()->argument); + break; + case NodeKind::kThrowStatement: + add(node->Cast<fast::ThrowStatement>()->argument); + break; + case NodeKind::kIfStatement: + add(node->Cast<fast::IfStatement>()->test); + break; + case NodeKind::kWhileStatement: + add_loop_test(node->Cast<fast::WhileStatement>()->test); + break; + case NodeKind::kDoWhileStatement: + add_loop_test(node->Cast<fast::DoWhileStatement>()->test); + break; + case NodeKind::kForStatement: + // The update expression is deliberately left alone: `i++` -> `0` + // is an infinite loop whenever the test still depends on `i`. + add_loop_test(node->Cast<fast::ForStatement>()->test); + break; + case NodeKind::kForInStatement: + add(node->Cast<fast::ForInStatement>()->right); + break; + case NodeKind::kForOfStatement: + add(node->Cast<fast::ForOfStatement>()->right); + break; + case NodeKind::kSwitchStatement: + add(node->Cast<fast::SwitchStatement>()->discriminant); + break; + case NodeKind::kSwitchCase: + add(node->Cast<fast::SwitchCase>()->test); + break; + case NodeKind::kCallExpression: { + auto* n = node->Cast<fast::CallExpression>(); + add(n->callee); + add_list(n->arguments); + break; + } + case NodeKind::kNewExpression: + add_list(node->Cast<fast::NewExpression>()->arguments); + break; + case NodeKind::kNativeCallExpression: + add_list(node->Cast<fast::NativeCallExpression>()->arguments); + break; + case NodeKind::kBinaryExpression: { + auto* n = node->Cast<fast::BinaryExpression>(); + add(n->left); + add(n->right); + break; + } + case NodeKind::kLogicalExpression: { + auto* n = node->Cast<fast::LogicalExpression>(); + add(n->left); + add(n->right); + break; + } + case NodeKind::kAssignmentExpression: + add(node->Cast<fast::AssignmentExpression>()->right); + break; + case NodeKind::kUnaryExpression: { + auto* n = node->Cast<fast::UnaryExpression>(); + if (n->op != fast::UnaryOp::kDelete) { + add(n->argument); + } + break; + } + case NodeKind::kMemberExpression: { + auto* n = node->Cast<fast::MemberExpression>(); + add(n->object); + if (n->computed) { + add(n->property); + } + break; + } + case NodeKind::kConditionalExpression: { + auto* n = node->Cast<fast::ConditionalExpression>(); + add(n->test); + add(n->consequent); + add(n->alternate); + break; + } + case NodeKind::kArrayExpression: + add_list(node->Cast<fast::ArrayExpression>()->elements); + break; + case NodeKind::kObjectExpression: { + for (Node* member : + node->Cast<fast::ObjectExpression>()->properties) { + auto* property = member->As<fast::Property>(); + if (property == nullptr || + property->property_kind != fast::PropertyKind::kInit || + property->shorthand || property->method) { + continue; + } + add(property->value); + if (property->computed) { + add(property->key); + } + } + break; + } + case NodeKind::kSpreadElement: + add(node->Cast<fast::SpreadElement>()->argument); + break; + case NodeKind::kAwaitExpression: + add(node->Cast<fast::AwaitExpression>()->argument); + break; + case NodeKind::kYieldExpression: + add(node->Cast<fast::YieldExpression>()->argument); + break; + case NodeKind::kSequenceExpression: + add_list(node->Cast<fast::SequenceExpression>()->expressions); + break; + case NodeKind::kTemplateLiteral: + add_list(node->Cast<fast::TemplateLiteral>()->expressions); + break; + case NodeKind::kArrowFunctionExpression: + add(node->Cast<fast::ArrowFunctionExpression>()->expression_body); + break; + case NodeKind::kPropertyDefinition: + add(node->Cast<fast::PropertyDefinition>()->value); + break; + default: + break; + } + }; + Walk(root, visit); + return slots; + } + + static std::vector<Expression*> Alternatives(fast::Tree* tree, + Expression* e) { + std::vector<Expression*> out; + auto operand = [&](Expression* candidate) { + if (IsValueOperand(candidate)) { + out.push_back(candidate); + } + }; + switch (e->kind) { + case NodeKind::kBinaryExpression: { + auto* n = e->Cast<fast::BinaryExpression>(); + operand(n->left); + operand(n->right); + break; + } + case NodeKind::kLogicalExpression: { + auto* n = e->Cast<fast::LogicalExpression>(); + operand(n->left); + operand(n->right); + break; + } + case NodeKind::kConditionalExpression: { + auto* n = e->Cast<fast::ConditionalExpression>(); + operand(n->consequent); + operand(n->alternate); + break; + } + case NodeKind::kCallExpression: { + auto* n = e->Cast<fast::CallExpression>(); + const size_t max_args = + static_cast<size_t>(kExpressionsMaxCallArguments.AsInt()); + for (size_t i = 0; i < n->arguments.size() && i < max_args; i++) { + operand(n->arguments[i]); + } + operand(n->callee); + break; + } + case NodeKind::kNewExpression: { + auto* n = e->Cast<fast::NewExpression>(); + const size_t max_args = + static_cast<size_t>(kExpressionsMaxCallArguments.AsInt()); + for (size_t i = 0; i < n->arguments.size() && i < max_args; i++) { + operand(n->arguments[i]); + } + break; + } + case NodeKind::kMemberExpression: + operand(e->Cast<fast::MemberExpression>()->object); + break; + case NodeKind::kUnaryExpression: + operand(e->Cast<fast::UnaryExpression>()->argument); + break; + case NodeKind::kAwaitExpression: + operand(e->Cast<fast::AwaitExpression>()->argument); + break; + case NodeKind::kYieldExpression: + operand(e->Cast<fast::YieldExpression>()->argument); + break; + case NodeKind::kAssignmentExpression: + operand(e->Cast<fast::AssignmentExpression>()->right); + break; + case NodeKind::kSequenceExpression: { + auto* n = e->Cast<fast::SequenceExpression>(); + if (!n->expressions.empty()) { + operand(n->expressions.back()); + } + break; + } + case NodeKind::kChainExpression: + operand(e->Cast<fast::ChainExpression>()->expression); + break; + case NodeKind::kTaggedTemplateExpression: + operand(e->Cast<fast::TaggedTemplateExpression>()->quasi); + break; + default: + break; + } + out.push_back(mk::Num(tree, 0)); + out.push_back(mk::Undefined(tree)); + return out; + } +}; + +} // namespace + +// --------------------------------------------------------------------------- +// Minimizer + +Minimizer::Minimizer(MinimizerOptions options) + : options_(options), reducers_(CreateDefaultReducers()) {} + +Minimizer::~Minimizer() = default; + +// static +std::vector<std::unique_ptr<Reducer>> Minimizer::CreateDefaultReducers() { + std::vector<std::unique_ptr<Reducer>> reducers; + reducers.push_back(std::make_unique<StatementRemover>()); + reducers.push_back(std::make_unique<Unwrapper>()); + reducers.push_back(std::make_unique<ListTrimmer>()); + reducers.push_back(std::make_unique<ExpressionSimplifier>()); + // Not in the default order (see DefaultOrder): on crash reproducers they + // reach the same result as `statements` with 5-12% more tests. Enable + // them with stages.minimize.reducers or `minimize --reducer=`. + reducers.push_back(std::make_unique<Truncator>()); + reducers.push_back(std::make_unique<DataflowReducer>()); + return reducers; +} + +// static +const std::vector<std::string_view>& Minimizer::DefaultOrder() { + // Never deleted: no destructor runs when the process exits. + static const std::vector<std::string_view>* const kOrder = + new std::vector<std::string_view>{"statements", "unwrap", "lists", + "expressions"}; + return *kOrder; +} + +Reducer* Minimizer::Find(std::string_view name) const { + for (const auto& reducer : reducers_) { + if (reducer->name() == name) { + return reducer.get(); + } + } + return nullptr; +} + +std::vector<std::string> Minimizer::Names() const { + std::vector<std::string> names; + names.reserve(reducers_.size()); + for (const auto& reducer : reducers_) { + names.push_back(reducer->name()); + } + return names; +} + +std::vector<const Component*> Minimizer::Components() const { + std::vector<const Component*> components; + components.reserve(reducers_.size()); + for (const auto& reducer : reducers_) { + components.push_back(reducer.get()); + } + return components; +} + +MinimizationResult Minimizer::Minimize(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker) const { + return Minimize(tree, oracle, checker, options_); +} + +MinimizationResult Minimizer::Minimize(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker, + const MinimizerOptions& options) const { + std::vector<Reducer*> reducers; + for (std::string_view name : DefaultOrder()) { + reducers.push_back(Find(name)); + } + return MinimizeWith(reducers, tree, oracle, checker, options); +} + +MinimizationResult Minimizer::MinimizeWith( + const std::vector<Reducer*>& reducers, fast::Tree* tree, + const MinimizationOracle& oracle, SyntaxChecker* checker) const { + return MinimizeWith(reducers, tree, oracle, checker, options_); +} + +MinimizationResult Minimizer::MinimizeWith( + const std::vector<Reducer*>& reducers, fast::Tree* tree, + const MinimizationOracle& oracle, SyntaxChecker* checker, + const MinimizerOptions& options) const { + Stopwatch stopwatch; + MinimizationHelper helper(tree, oracle, checker, options); + helper.mutable_result()->nodes_before = fast::CountNodes(tree->root()); + for (int round = 0; round < options.max_rounds; round++) { + int accepted = 0; + for (Reducer* reducer : reducers) { + if (helper.BudgetExhausted()) { + break; + } + helper.set_reducer(reducer); + reducer->stats().invocations++; + int n = reducer->Reduce(helper); + reducer->stats().produced += static_cast<uint64_t>(n); + accepted += n; + } + if (accepted == 0 || helper.BudgetExhausted()) { + break; + } + } + // Semantically neutral clean-up that needs no test. + RemoveEmptyStatements(tree->root()); + MinimizationResult result = helper.result(); + result.nodes_after = fast::CountNodes(tree->root()); + result.time_us = stopwatch.ElapsedUs(); + result.budget_exhausted = helper.BudgetExhausted(); + return result; +} + +int MinimizerOptions::TestsFor(uint64_t exec_time_us) const { + if (target_time_ms == 0 || exec_time_us == 0) { + return max_tests; + } + uint64_t affordable = target_time_ms * 1000 / exec_time_us; + int tests = affordable > static_cast<uint64_t>(max_tests) + ? max_tests + : static_cast<int>(affordable); + return std::max(tests, std::min(min_tests, max_tests)); +} + +MinimizerOptions MinimizerOptions::ForProgram(uint64_t exec_time_us) const { + MinimizerOptions scaled = *this; + scaled.max_tests = TestsFor(exec_time_us); + return scaled; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/minimizer/minimizer.h b/deps/v8/experimental/redline/minimizer/minimizer.h new file mode 100644 index 000000000000..d1a100c51c38 --- /dev/null +++ b/deps/v8/experimental/redline/minimizer/minimizer.h @@ -0,0 +1,148 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_MINIMIZER_MINIMIZER_H_ +#define V8_EXPERIMENTAL_REDLINE_MINIMIZER_MINIMIZER_H_ + +#include <cstdint> +#include <functional> +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/core/component.h" +#include "experimental/redline/fast/tree.h" + +namespace redline { + +class SyntaxChecker; + +// Answers whether a candidate program still has the property that is being +// preserved: reaches a given set of edges, still crashes, ... Called once +// per minimization test, typically running the program in the target. +using MinimizationOracle = std::function<bool(const std::string& source)>; + +struct MinimizerOptions { + // Oracle calls per minimization. Executions are the expensive part, so + // this bounds the cost of adding one program to the corpus. + int max_tests = 300; + // Wall-clock bound per minimization (0 = none). + uint64_t max_time_ms = 30000; + // Passes over all reducers (a pass that changes nothing ends early). + int max_rounds = 3; + // Adaptive budget: a program's test budget is max_tests scaled down so + // that about target_time_ms are spent (each probe costs one execution + // of a program about as slow as the original), but never below + // min_tests. 0 disables the scaling. + uint64_t target_time_ms = 6000; + int min_tests = 40; + + // The test budget for a program that executes in exec_time_us. + int TestsFor(uint64_t exec_time_us) const; + // These options with max_tests replaced by TestsFor(exec_time_us). + MinimizerOptions ForProgram(uint64_t exec_time_us) const; +}; + +struct MinimizationResult { + int tests = 0; // oracle calls + int accepted = 0; // ... that kept the property (reductions kept) + int syntax_rejected = 0; // candidates the V8 parser refused (not executed) + size_t nodes_before = 0; + size_t nodes_after = 0; + uint64_t time_us = 0; + bool budget_exhausted = false; +}; + +class Reducer; + +// Shared state of one minimization: the tree, the oracle, the budget and +// the statistics. Reducers edit the tree and call Test(); on a false return +// they must undo their edit. +class MinimizationHelper { + public: + MinimizationHelper(fast::Tree* tree, const MinimizationOracle& oracle, + SyntaxChecker* checker, const MinimizerOptions& options); + + fast::Tree* tree() { return tree_; } + // Prints the tree and asks the oracle whether the property still holds. + // Returns false without testing once the budget is exhausted. + bool Test(); + bool BudgetExhausted() const; + void set_reducer(Reducer* reducer) { reducer_ = reducer; } + const MinimizationResult& result() const { return result_; } + MinimizationResult* mutable_result() { return &result_; } + + private: + fast::Tree* tree_; + const MinimizationOracle& oracle_; + SyntaxChecker* checker_; + const MinimizerOptions& options_; + Reducer* reducer_ = nullptr; + MinimizationResult result_; + uint64_t start_us_; +}; + +// One minimization strategy (statement removal, block unwrapping, ...). +// Reducers are Components: `redline minimize --reducer=NAME` runs one alone. +class Reducer : public Component { + public: + Reducer(std::string name, std::string_view description) + : Component(std::move(name)), description_(description) {} + std::string_view description() const override { return description_; } + + // Applies all reductions this reducer can find, keeping the ones the + // oracle accepts. Returns the number of accepted reductions. + virtual int Reduce(MinimizationHelper& helper) = 0; + + private: + std::string_view description_; +}; + +class Minimizer { + public: + explicit Minimizer(MinimizerOptions options = MinimizerOptions()); + ~Minimizer(); + + // Every reducer (the components), in registration order. + static std::vector<std::unique_ptr<Reducer>> CreateDefaultReducers(); + // The reducers Minimize() runs when no order is configured, in order. + static const std::vector<std::string_view>& DefaultOrder(); + + const MinimizerOptions& options() const { return options_; } + const std::vector<std::unique_ptr<Reducer>>& reducers() const { + return reducers_; + } + Reducer* Find(std::string_view name) const; + std::vector<std::string> Names() const; + std::vector<const Component*> Components() const; + + // Minimizes `tree` in place with all reducers. `checker` (optional) + // filters candidates the V8 parser rejects before they reach the oracle. + MinimizationResult Minimize(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker) const; + MinimizationResult Minimize(fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker, + const MinimizerOptions& options) const; + // Same with an explicit reducer sequence. + MinimizationResult MinimizeWith(const std::vector<Reducer*>& reducers, + fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker) const; + MinimizationResult MinimizeWith(const std::vector<Reducer*>& reducers, + fast::Tree* tree, + const MinimizationOracle& oracle, + SyntaxChecker* checker, + const MinimizerOptions& options) const; + + private: + MinimizerOptions options_; + std::vector<std::unique_ptr<Reducer>> reducers_; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_MINIMIZER_MINIMIZER_H_ diff --git a/deps/v8/experimental/redline/mutators/explore.cc b/deps/v8/experimental/redline/mutators/explore.cc new file mode 100644 index 000000000000..ae937a62d499 --- /dev/null +++ b/deps/v8/experimental/redline/mutators/explore.cc @@ -0,0 +1,872 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/mutators/explore.h" + +#include <algorithm> +#include <cstdlib> +#include <cstring> +#include <unordered_map> + +#include "experimental/redline/base/json_parser.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/generators/codegen.h" + +namespace redline { + +using namespace fast; // NOLINT(build/namespaces) + +// --------------------------------------------------------------------------- +// The runtime side. Everything the helper needs from the builtins is +// captured up front because the program under test may have replaced them. +// Actions are reported as "EXPLORE_ACTION: <json>" lines on the fuzzout +// channel (fuzzilli('FUZZILLI_PRINT', ...)); failures as "EXPLORE_FAILURE: +// <id>". Argument descriptors: {"a": i} the i-th probe argument, {"n": "7"} +// a number, {"s": "x"} a string, {"bi": "7"} a bigint, {"b": true}, +// {"u": 1} undefined, {"f": 1} a fresh identity-like callback. +const char kExploreRuntime[] = R"js(const __redline_explore = (function() { + const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames; + const ObjectGetPrototypeOf = Object.getPrototypeOf; + const ObjectPrototype = Object.prototype; + const FunctionPrototype = Function.prototype; + const ReflectApply = Reflect.apply; + const ReflectConstruct = Reflect.construct; + const ArrayPush = Array.prototype.push; + const JSONStringify = JSON.stringify; + const NumberIsInteger = Number.isInteger; + const NumberIsFinite = Number.isFinite; + const NumberIsNaN = Number.isNaN; + const MathFloor = Math.floor; + const SymbolIterator = Symbol.iterator; + const StringCharCodeAt = String.prototype.charCodeAt; + const emit = typeof fuzzilli === 'function' ? function(s) { fuzzilli('FUZZILLI_PRINT', s); } + : function(s) {}; + function push(a, v) { ReflectApply(ArrayPush, a, [v]); } + + let rngState = 1; + function reseed(s) { rngState = (s >>> 0) || 1; } + function random() { + let x = rngState; + x ^= x << 13; x >>>= 0; + x ^= x >>> 17; + x ^= x << 5; x >>>= 0; + rngState = x; + return x / 4294967296; + } + function randomInt(n) { return MathFloor(random() * n); } + function pick(a) { return a[randomInt(a.length)]; } + function chance(p) { return random() < p; } + function hashString(s) { + let h = 2166136261; + for (let i = 0; i < s.length; i++) { + h ^= ReflectApply(StringCharCodeAt, s, [i]); + h = (h * 16777619) >>> 0; + } + return h; + } + + const results = {__proto__: null}; + let exploring = false; + let args = []; + let canAwait = false; + let mutable = false; + + const INTEGERS = [0, 1, -1, 2, 3, 7, 8, 16, 31, 32, 64, 100, 127, 128, 255, 256, 1000, + 1023, 1024, 4096, 65535, 65536, 1073741823, 2147483647, 2147483648, + 4294967295, 4294967296, 9007199254740991, -2147483648]; + const NUMBERS = [0.5, -0.0, 1.5, 1e6, 1e-6, 3.14, 1e21, 1e300, NaN, Infinity, -Infinity]; + const STRINGS = ['', 'a', 'abc', 'length', '0', '1', 'x', 'constructor', 'valueOf', 'toString', + 'undefined', '\u0000', 'ab\u{1F600}']; + const PROPERTY_NAMES = ['a', 'b', 'c', 'x', 'y', 'foo', 'bar', 'length', 'name', 'value', + 'valueOf', 'toString', 'then', 'next', 'done', '0', '1', '2', '100', + '-1', '4294967295', 'size', 'key']; + const CALLBACK_METHODS = ['map', 'filter', 'forEach', 'reduce', 'reduceRight', 'sort', 'find', + 'findIndex', 'findLast', 'findLastIndex', 'some', 'every', 'flatMap', + 'then', 'catch', 'finally', 'replace', 'replaceAll', 'toSorted', + 'groupBy', 'from', 'register', 'addEventListener', 'take', 'drop']; + const ARITHMETIC = ['+', '-', '*', '/', '%', '**']; + const BITWISE = ['|', '&', '^', '<<', '>>', '>>>']; + const COMPARISONS = ['==', '===', '!=', '!==', '<', '<=', '>', '>=']; + const UNARY = ['-', '+', '!', '~', 'typeof', 'void']; + + function isObject(v) { return typeof v === 'object' && v !== null; } + function isFunction(v) { return typeof v === 'function'; } + function includes(a, v) { for (let i = 0; i < a.length; i++) if (a[i] === v) return true; return false; } + + // --- inputs --------------------------------------------------------------- + function argInput(i) { return {a: i}; } + function randomArgument() { + if (args.length === 0) return {u: 1}; + return argInput(randomInt(args.length)); + } + function findArgument(predicate) { + for (let i = 0; i < args.length; i++) { + let ok = false; + try { ok = predicate(args[i]); } catch (e) {} + if (ok) return argInput(i); + } + return null; + } + function randomNumberInput() { + return findArgument(x => typeof x === 'number') || + (chance(0.7) ? {n: '' + pick(INTEGERS)} : {n: '' + pick(NUMBERS)}); + } + function randomIntegerInput(lo, hi) { + return findArgument(x => NumberIsInteger(x) && x >= lo && x < hi) || + {n: '' + (lo + randomInt(hi - lo))}; + } + function randomBigintInput() { + return findArgument(x => typeof x === 'bigint') || {bi: '' + pick(INTEGERS)}; + } + function randomStringInput() { + return findArgument(x => typeof x === 'string') || {s: pick(STRINGS)}; + } + function anyInput() { + const r = random(); + if (r < 0.6 && args.length > 0) return randomArgument(); + if (r < 0.75) return {n: '' + pick(INTEGERS)}; + if (r < 0.85) return {s: pick(STRINGS)}; + if (r < 0.9) return {b: chance(0.5)}; + if (r < 0.95) return {f: 1}; + return {u: 1}; + } + function argumentsFor(name, count) { + const inputs = []; + const wantsCallback = includes(CALLBACK_METHODS, name); + for (let i = 0; i < count; i++) { + if (i === 0 && wantsCallback && chance(0.8)) push(inputs, {f: 1}); + else push(inputs, anyInput()); + } + return inputs; + } + function valueOf(input) { + if ('a' in input) return args[input.a]; + if ('n' in input) return +input.n; + if ('s' in input) return input.s; + if ('bi' in input) return BigInt(input.n === undefined ? input.bi : input.n); + if ('b' in input) return input.b; + if ('f' in input) return function(a, b) { return a; }; + return undefined; + } + function valuesOf(inputs) { + const out = []; + for (let i = 0; i < inputs.length; i++) push(out, valueOf(inputs[i])); + return out; + } + + // --- introspection ------------------------------------------------------- + function propertyNames(o, skipOwn) { + const names = []; + const seen = {__proto__: null}; + let depth = 0; + let p = o; + // Large arrays/typed arrays: enumerating every index is slow and + // pointless; start at the prototype. + if (skipOwn) { try { p = ObjectGetPrototypeOf(o); } catch (e) { return names; } } + for (; p !== null && p !== undefined && depth < 6; depth++) { + if ((p === ObjectPrototype || p === FunctionPrototype) && !chance(0.15)) break; + let own; + try { own = ObjectGetOwnPropertyNames(p); } catch (e) { break; } + for (let i = 0; i < own.length; i++) { + const n = own[i]; + if (n === '__proto__' || n === 'caller' || n === 'callee' || n === 'arguments') continue; + if (n === 'constructor' && !chance(0.1)) continue; + if (seen[n]) continue; + seen[n] = true; + push(names, n); + } + try { p = ObjectGetPrototypeOf(p); } catch (e) { break; } + } + return names; + } + function looksLikeConstructor(f) { + let name; + try { name = f.name; } catch (e) { return false; } + if (typeof name !== 'string' || name.length === 0) return chance(0.1); + const c = ReflectApply(StringCharCodeAt, name, [0]); + return (c >= 65 && c <= 90) ? chance(0.9) : chance(0.1); + } + function arity(f) { + let n; + try { n = f.length; } catch (e) { return 0; } + if (!NumberIsInteger(n) || n < 0 || n > 8) return 1; + return n; + } + + // --- action selection ---------------------------------------------------- + function exploreObject(o) { + const r = random(); + let length = -1; + try { if (NumberIsInteger(o.length) && o.length >= 0) length = o.length; } catch (e) {} + if (length > 0 && r < 0.2) { + const index = randomIntegerInput(0, length + 1); + return chance(0.5) ? {op: 'getElem', index: index} + : {op: 'setElem', index: index, args: [anyInput()]}; + } + let iterable = false; + try { iterable = isFunction(o[SymbolIterator]); } catch (e) {} + if (iterable && r < 0.3) return chance(0.7) ? {op: 'iterate'} : {op: 'keys'}; + let thenable = false; + try { thenable = isFunction(o.then); } catch (e) {} + if (thenable && canAwait && r < 0.5) return {op: 'await'}; + const names = propertyNames(o, length > 200); + if (names.length === 0 || r > 0.9) { + return {op: 'setProp', name: pick(PROPERTY_NAMES), args: [anyInput()]}; + } + const name = pick(names); + let value; + try { value = o[name]; } catch (e) { return {op: 'getProp', name: name}; } + if (isFunction(value)) { + const inputs = argumentsFor(name, arity(value)); + const construct = looksLikeConstructor(value); + return {op: construct ? 'constructMethod' : 'callMethod', name: name, args: inputs}; + } + const r2 = random(); + if (r2 < 0.55) return {op: 'getProp', name: name}; + if (r2 < 0.85) return {op: 'setProp', name: name, args: [anyInput()]}; + return {op: 'setProp', name: pick(PROPERTY_NAMES), args: [anyInput()]}; + } + function exploreFunction(f) { + if (chance(0.4)) return exploreObject(f); + const inputs = argumentsFor(f.name, arity(f)); + return {op: looksLikeConstructor(f) ? 'construct' : 'call', args: inputs}; + } + function exploreNumber(n) { + const r = random(); + if (r < 0.15) return exploreObject(new Number(n)); + if (r < 0.3) { + if (NumberIsNaN(n) || !NumberIsFinite(n)) return {op: 'unary', operator: pick(UNARY)}; + return {op: 'compare', operator: pick(COMPARISONS), args: [randomNumberInput()]}; + } + if (r < 0.45) return {op: 'unary', operator: pick(UNARY)}; + if (r < 0.55 && mutable) return {op: 'update', operator: chance(0.5) ? '++' : '--'}; + if (r < 0.75) return {op: 'binary', operator: pick(BITWISE), args: [randomIntegerInput(0, 64)]}; + return {op: 'binary', operator: pick(ARITHMETIC), args: [randomNumberInput()]}; + } + function exploreBigint(b) { + const r = random(); + if (r < 0.15) return exploreObject(Object(b)); + if (r < 0.35) return {op: 'compare', operator: pick(COMPARISONS), args: [randomBigintInput()]}; + if (r < 0.5) return {op: 'unary', operator: chance(0.5) ? '-' : '~'}; + const ops = ['+', '-', '*', '/', '%', '**', '|', '&', '^', '<<', '>>']; + return {op: 'binary', operator: pick(ops), args: [randomBigintInput()]}; + } + function exploreString(s) { + const r = random(); + if (r < 0.1) return {op: 'compare', operator: pick(['==', '===', '<', '>']), args: [randomStringInput()]}; + if (r < 0.2) return {op: 'binary', operator: '+', args: [anyInput()]}; + if (r < 0.3 && s.length > 0) return {op: 'getElem', index: randomIntegerInput(0, s.length)}; + return exploreObject(new String(s)); + } + function exploreBoolean(b) { + const r = random(); + if (r < 0.3) return {op: 'unary', operator: '!'}; + return {op: 'logical', operator: pick(['&&', '||']), args: [randomArgument()]}; + } + function exploreNullish(v) { + return chance(0.7) ? {op: 'logical', operator: '??', args: [randomArgument()]} + : {op: 'compare', operator: pick(['==', '===']), args: [anyInput()]}; + } + function exploreSymbol(s) { + return chance(0.5) ? {op: 'getProp', name: 'description'} + : {op: 'callMethod', name: 'toString', args: []}; + } + function chooseAction(v) { + if (v === null || v === undefined) return exploreNullish(v); + switch (typeof v) { + case 'object': return exploreObject(v); + case 'function': return exploreFunction(v); + case 'number': return exploreNumber(v); + case 'bigint': return exploreBigint(v); + case 'string': return exploreString(v); + case 'boolean': return exploreBoolean(v); + case 'symbol': return exploreSymbol(v); + default: return exploreObject(Object(v)); + } + } + + // --- action execution (validation) --------------------------------------- + function perform(action, v) { + const a = action.args ? valuesOf(action.args) : []; + switch (action.op) { + case 'callMethod': return ReflectApply(v[action.name], v, a); + case 'constructMethod': return ReflectConstruct(v[action.name], a); + case 'getProp': return v[action.name]; + case 'setProp': v[action.name] = a[0]; return; + case 'getElem': return v[valueOf(action.index)]; + case 'setElem': v[valueOf(action.index)] = a[0]; return; + case 'call': return ReflectApply(v, undefined, a); + case 'construct': return ReflectConstruct(v, a); + case 'binary': + switch (action.operator) { + case '+': return v + a[0]; case '-': return v - a[0]; case '*': return v * a[0]; + case '/': return v / a[0]; case '%': return v % a[0]; case '**': return v ** a[0]; + case '|': return v | a[0]; case '&': return v & a[0]; case '^': return v ^ a[0]; + case '<<': return v << a[0]; case '>>': return v >> a[0]; case '>>>': return v >>> a[0]; + } + return; + case 'compare': + switch (action.operator) { + case '==': return v == a[0]; case '===': return v === a[0]; + case '!=': return v != a[0]; case '!==': return v !== a[0]; + case '<': return v < a[0]; case '<=': return v <= a[0]; + case '>': return v > a[0]; case '>=': return v >= a[0]; + } + return; + case 'unary': + switch (action.operator) { + case '-': return -v; case '+': return +v; case '!': return !v; case '~': return ~v; + case 'typeof': return typeof v; case 'void': return void v; + } + return; + case 'update': return action.operator === '++' ? v + 1 : v - 1; + case 'logical': + switch (action.operator) { + case '&&': return v && a[0]; case '||': return v || a[0]; case '??': return v ?? a[0]; + } + return; + case 'iterate': { let n = 0; for (const x of v) { if (++n > 100) break; } return; } + case 'keys': { let n = 0; for (const k in v) { if (++n > 100) break; } return; } + case 'await': return; + } + } + + function explore(id, v, probeArgs, flags, seed) { + if (exploring) return; + exploring = true; + try { + args = probeArgs; + canAwait = (flags & 1) !== 0; + mutable = (flags & 2) !== 0; + let action = results[id]; + if (action === undefined) { + reseed(hashString(id) ^ seed); + for (let attempt = 0; attempt < 4 && action === undefined; attempt++) { + const candidate = chooseAction(v); + let ok = true; + try { perform(candidate, v); } catch (e) { ok = false; } + if (ok) action = candidate; + } + if (action === undefined) { + results[id] = null; + emit('EXPLORE_FAILURE: ' + id); + } else { + action.id = id; + results[id] = action; + emit('EXPLORE_ACTION: ' + JSONStringify(action)); + } + } else if (action !== null) { + try { perform(action, v); } catch (e) {} + } + } catch (e) { + try { emit('EXPLORE_ERROR: ' + id + ' ' + e); } catch (e2) {} + } + exploring = false; + } + return explore; +})(); +try { %NeverOptimizeFunction(__redline_explore); } catch (e) {} +)js"; + +namespace { + +constexpr int kMaxProbes = 3; + +bool IsBoring(const Variable& v) { + // Exploring `arguments`/`undefined`-like names makes little sense. + return v.name == "arguments" || v.name == "undefined" || v.name == "NaN" || + v.name == "Infinity"; +} + +// Prefers variables whose static type is unknown or object-like: those are +// the ones where runtime inspection adds the most information. +double ExploreWeight(const Variable& v) { + switch (v.type) { + case JsType::kUnknown: + case JsType::kObject: + case JsType::kClass: + case JsType::kFunction: + return 4; + case JsType::kArray: + case JsType::kTypedArray: + case JsType::kMap: + case JsType::kSet: + case JsType::kPromise: + case JsType::kRegExp: + case JsType::kArrayBuffer: + case JsType::kDate: + case JsType::kError: + return 2; + default: + return 1; + } +} + +Expression* LiteralFor(Tree* t, const ExploreArg& arg) { + switch (arg.kind) { + case ExploreArg::Kind::kVariable: + return mk::Id(t, arg.text); + case ExploreArg::Kind::kNumber: + return mk::Num(t, strtod(arg.text.c_str(), nullptr)); + case ExploreArg::Kind::kString: + return mk::Str(t, arg.text); + case ExploreArg::Kind::kBoolean: + return mk::Bool(t, arg.flag); + case ExploreArg::Kind::kBigInt: + return mk::BigInt(t, arg.text); + case ExploreArg::Kind::kNull: + return mk::Null(t); + case ExploreArg::Kind::kUndefined: + return mk::Undefined(t); + } + return mk::Undefined(t); +} + +// The statement `try { __redline_explore("id", v, [args], flags, seed); } catch +// (e) {}`. +Statement* MakeExploreProbe(Tree* t, const ExploreProbe& probe, + bool mutable_variable, uint32_t seed) { + std::vector<Expression*> args; + args.reserve(probe.args.size()); + for (const ExploreArg& arg : probe.args) { + args.push_back(LiteralFor(t, arg)); + } + int flags = (probe.can_await ? 1 : 0) | (mutable_variable ? 2 : 0); + return RuntimeAssistedMutator::MakeProbe( + t, ExploreMutator::kProbeFunction, probe, + {mk::Array(t, std::move(args)), mk::Num(t, flags), + mk::Num(t, static_cast<double>(seed))}); +} + +// --- applying actions ------------------------------------------------------- + +struct Action { + std::string id; + std::string op; + std::string name; + std::string op_text; // operator + JsonValue index; + std::vector<JsonValue> args; +}; + +bool ParseAction(const JsonValue& json, Action* action) { + if (!json.is_object()) { + return false; + } + action->id = json.GetString("id", ""); + action->op = json.GetString("op", ""); + action->name = json.GetString("name", ""); + action->op_text = json.GetString("operator", ""); + action->index = json.Get("index"); + const JsonValue& args = json.Get("args"); + if (args.is_array()) { + for (const JsonValue& a : args.as_array()) { + action->args.push_back(a); + } + } + return !action->id.empty() && !action->op.empty(); +} + +// Maps an argument descriptor to an expression; nullptr if malformed. +Expression* ExpressionFor(Builder& b, const ExploreProbe& probe, + const JsonValue& input) { + Tree* t = b.tree(); + if (!input.is_object()) { + return nullptr; + } + if (input.Has("a")) { + int64_t i = input.GetInt("a", -1); + if (i < 0 || static_cast<size_t>(i) >= probe.args.size()) { + return nullptr; + } + return LiteralFor(t, probe.args[static_cast<size_t>(i)]); + } + if (input.Has("n")) { + return mk::Num(t, strtod(input.GetString("n", "0").c_str(), nullptr)); + } + if (input.Has("s")) { + return mk::Str(t, input.GetString("s", "")); + } + if (input.Has("bi")) { + return mk::BigInt(t, input.GetString("bi", "0")); + } + if (input.Has("b")) { + return mk::Bool(t, input.GetBool("b", false)); + } + if (input.Has("f")) { + std::string_view p0 = b.FreshName("p"); + std::string_view p1 = b.FreshName("p"); + return mk::ArrowExpr(t, {p0, p1}, mk::Id(t, p0)); + } + return mk::Undefined(t); +} + +template <typename Op> +bool OpFromText(const std::string& text, Op* out, Op first, Op last) { + for (int i = static_cast<int>(first); i <= static_cast<int>(last); i++) { + Op op = static_cast<Op>(i); + if (text == OperatorText(op)) { + *out = op; + return true; + } + } + return false; +} + +Expression* Access(Tree* t, Expression* object, const std::string& name) { + if (IsIdentifierName(name)) { + return mk::Member(t, object, name); + } + return mk::Index(t, object, mk::Str(t, name)); +} + +// Builds the statements for `action` on `probe.variable`; empty if the +// action cannot be expressed (malformed or not applicable). +std::vector<Statement*> StatementsFor(Builder& b, const ExploreProbe& probe, + const Action& action, + std::string* describe) { + Tree* t = b.tree(); + std::vector<Statement*> out; + auto var = [&] { return mk::Id(t, probe.variable); }; + std::vector<Expression*> args; + for (const JsonValue& a : action.args) { + Expression* e = ExpressionFor(b, probe, a); + if (e == nullptr) { + return out; + } + args.push_back(e); + } + auto result = [&](Expression* value) { + out.push_back(mk::Let(t, b.FreshName("r"), value)); + }; + const std::string& op = action.op; + *describe = probe.variable + " " + op; + if (op == "callMethod" || op == "constructMethod") { + if (action.name.empty()) { + return out; + } + *describe += " " + action.name; + Expression* callee = Access(t, var(), action.name); + result(op == "callMethod" + ? static_cast<Expression*>(mk::Call(t, callee, std::move(args))) + : static_cast<Expression*>(mk::New(t, callee, std::move(args)))); + } else if (op == "getProp") { + if (action.name.empty()) { + return out; + } + *describe += " " + action.name; + result(Access(t, var(), action.name)); + } else if (op == "setProp") { + if (action.name.empty() || args.size() != 1) { + return out; + } + *describe += " " + action.name; + out.push_back( + mk::ExprStmt(t, mk::Assign(t, Access(t, var(), action.name), args[0]))); + } else if (op == "getElem" || op == "setElem") { + Expression* index = ExpressionFor(b, probe, action.index); + if (index == nullptr) { + return out; + } + if (op == "getElem") { + result(mk::Index(t, var(), index)); + } else { + if (args.size() != 1) { + return out; + } + out.push_back( + mk::ExprStmt(t, mk::Assign(t, mk::Index(t, var(), index), args[0]))); + } + } else if (op == "call") { + result(mk::Call(t, var(), std::move(args))); + } else if (op == "construct") { + result(mk::New(t, var(), std::move(args))); + } else if (op == "binary" || op == "compare") { + BinaryOp bop; + if (args.size() != 1 || !OpFromText(action.op_text, &bop, BinaryOp::kEq, + BinaryOp::kInstanceof)) { + return out; + } + *describe += " " + action.op_text; + result(mk::Binary(t, bop, var(), args[0])); + } else if (op == "logical") { + LogicalOp lop; + if (args.size() != 1 || !OpFromText(action.op_text, &lop, LogicalOp::kOr, + LogicalOp::kNullish)) { + return out; + } + *describe += " " + action.op_text; + result(mk::Logical(t, lop, var(), args[0])); + } else if (op == "unary") { + UnaryOp uop; + if (!OpFromText(action.op_text, &uop, UnaryOp::kMinus, UnaryOp::kDelete)) { + return out; + } + if (uop == UnaryOp::kDelete) { + return out; + } + *describe += " " + action.op_text; + result(mk::Unary(t, uop, var())); + } else if (op == "update") { + UpdateOp uop = + action.op_text == "--" ? UpdateOp::kDecrement : UpdateOp::kIncrement; + out.push_back(mk::ExprStmt(t, mk::Update(t, uop, /*prefix=*/false, var()))); + } else if (op == "iterate") { + std::string_view counter = b.FreshName("r"); + std::string_view element = b.FreshName("e"); + out.push_back(mk::Let(t, counter, mk::Num(t, 0))); + Statement* guard = + mk::If(t, + mk::Binary(t, BinaryOp::kGreaterThan, + mk::Update(t, UpdateOp::kIncrement, /*prefix=*/true, + mk::Id(t, counter)), + mk::Num(t, 100)), + mk::Break(t)); + out.push_back(mk::ForOf(t, VariableKind::kConst, element, var(), + mk::Block(t, {guard}))); + } else if (op == "keys") { + std::string_view keys = b.FreshName("r"); + std::string_view key = b.FreshName("k"); + out.push_back(mk::Let(t, keys, mk::Array(t, {}))); + Statement* body = mk::ExprStmt( + t, mk::CallMethod(t, mk::Id(t, keys), "push", {mk::Id(t, key)})); + out.push_back( + mk::ForIn(t, VariableKind::kConst, key, var(), mk::Block(t, {body}))); + } else if (op == "await") { + if (!probe.can_await) { + return out; + } + result(mk::Await(t, var())); + } else { + return out; + } + return out; +} + +} // namespace + +// static +Statement* RuntimeAssistedMutator::MakeProbe( + Tree* t, std::string_view function, const ExploreProbe& probe, + const std::vector<Expression*>& extra) { + std::vector<Expression*> args = {mk::Str(t, probe.id), + mk::Id(t, probe.variable)}; + for (Expression* e : extra) { + args.push_back(e); + } + CallExpression* call = mk::Call(t, mk::Id(t, function), std::move(args)); + return mk::Try(t, {mk::ExprStmt(t, call)}, "e", {}); +} + +// static +Statement* RuntimeAssistedMutator::FindProbe(Builder& b, + std::string_view function, + const std::string& id) { + std::vector<Node*> calls = b.Collect([&](Node* n) { + auto* call = n->As<CallExpression>(); + if (call == nullptr || call->arguments.empty()) { + return false; + } + auto* callee = call->callee->As<Identifier>(); + if (callee == nullptr || callee->name != function) { + return false; + } + auto* literal = call->arguments[0]->As<StringLiteral>(); + return literal != nullptr && literal->value == id; + }); + if (calls.empty()) { + return nullptr; + } + Statement* statement = b.EnclosingStatement(calls[0]); + if (statement == nullptr) { + return nullptr; + } + Node* block = b.ParentOf(statement); + Node* try_statement = block != nullptr ? b.ParentOf(block) : nullptr; + if (try_statement != nullptr && try_statement->Is<TryStatement>()) { + return try_statement->Cast<TryStatement>(); + } + return statement; +} + +ExploreMutator::ExploreMutator() + : RuntimeAssistedMutator("Explore", + "inspects variables at runtime and performs an " + "action fitting their actual value", + 3, false) {} + +std::string_view ExploreMutator::runtime() const { return kExploreRuntime; } + +int ExploreMutator::Apply(Builder& builder, + const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, MutationContext& /*ctx*/, + std::string* detail) { + return ApplyExploreActions(builder, probes, fuzzout, detail); +} + +bool ExploreMutator::Mutate(Builder& b, MutationContext& ctx) { + Random& r = b.rng(); + ctx.probes.clear(); + std::vector<Builder::Slot> slots = b.InsertionSlots(); + if (slots.empty()) { + return false; + } + int wanted = 1 + r.SmallCount(kMaxProbes - 1); + const uint32_t seed = static_cast<uint32_t>(r.Next()); + std::vector<std::pair<Builder::Slot, Statement*>> insertions; + std::vector<std::string> explored; + for (int attempt = 0; + attempt < 4 * wanted && static_cast<int>(ctx.probes.size()) < wanted; + attempt++) { + const Builder::Slot& slot = slots[r.Index(slots.size())]; + Builder::Context syntax = b.ContextAtSlot(slot); + if (syntax.in_class_field) { + continue; + } + std::vector<Variable> visible = b.VisibleAtSlot(slot); + std::vector<const Variable*> candidates; + std::vector<double> weights; + for (const Variable& v : visible) { + if (IsBoring(v)) { + continue; + } + if (std::find(explored.begin(), explored.end(), std::string(v.name)) != + explored.end()) { + continue; + } + candidates.push_back(&v); + weights.push_back(ExploreWeight(v)); + } + if (candidates.empty()) { + continue; + } + const Variable& target = *candidates[r.Weighted(weights)]; + ExploreProbe probe; + probe.id = StringPrintf("e%u", static_cast<unsigned>(r.Next() % 100000)); + probe.variable = std::string(target.name); + probe.can_await = syntax.in_async && !syntax.in_static_block; + // Up to 4 other visible variables plus a literal or two as arguments. + std::vector<const Variable*> others; + for (const Variable& v : visible) { + if (v.name != target.name && !IsBoring(v)) { + others.push_back(&v); + } + } + for (int i = 0; i < 4 && !others.empty(); i++) { + size_t index = r.Index(others.size()); + ExploreArg arg; + arg.kind = ExploreArg::Kind::kVariable; + arg.text = std::string(others[index]->name); + probe.args.push_back(arg); + others.erase(others.begin() + static_cast<std::ptrdiff_t>(index)); + } + { + ExploreArg arg; + arg.kind = ExploreArg::Kind::kNumber; + const std::vector<double>& numbers = ctx.env->numbers(); + double n = numbers[r.Index(numbers.size())]; + arg.text = StringPrintf("%.17g", n); + if (arg.text.find("nan") != std::string::npos || + arg.text.find("inf") != std::string::npos) { + arg.text = "0"; + } + probe.args.push_back(arg); + } + if (r.Coin()) { + ExploreArg arg; + arg.kind = ExploreArg::Kind::kString; + const std::vector<std::string_view>& strings = ctx.env->strings(); + arg.text = std::string(strings[r.Index(strings.size())]); + probe.args.push_back(arg); + } + Statement* statement = + MakeExploreProbe(b.tree(), probe, !target.is_constant, seed); + insertions.emplace_back(slot, statement); + explored.push_back(probe.variable); + ctx.probes.push_back(std::move(probe)); + } + if (ctx.probes.empty()) { + return false; + } + // Insert back to front within each list so that earlier slot indices stay + // valid; different lists do not interfere. + std::stable_sort(insertions.begin(), insertions.end(), + [](const auto& x, const auto& y) { + return x.first.index > y.first.index; + }); + for (auto& [slot, statement] : insertions) { + b.Insert(slot, statement); + } + ctx.detail = "probing"; + for (const ExploreProbe& p : ctx.probes) { + ctx.detail += " " + p.variable; + } + return true; +} + +int ApplyExploreActions(Builder& b, const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, std::string* detail) { + std::unordered_map<std::string, Action> actions; + size_t start = 0; + while (start < fuzzout.size()) { + size_t nl = fuzzout.find('\n', start); + if (nl == std::string::npos) { + nl = fuzzout.size(); + } + std::string_view line(fuzzout.data() + start, nl - start); + start = nl + 1; + constexpr std::string_view kAction = "EXPLORE_ACTION: "; + if (!line.starts_with(kAction)) { + continue; + } + JsonValue json; + std::string error; + if (!JsonValue::Parse(line.substr(kAction.size()), &json, &error)) { + REDLINE_VLOG("explore", "unparsable action: %s", error.c_str()); + continue; + } + Action action; + if (ParseAction(json, &action)) { + actions[action.id] = std::move(action); + } + } + int applied = 0; + std::string description; + for (const ExploreProbe& probe : probes) { + Statement* statement = RuntimeAssistedMutator::FindProbe( + b, ExploreMutator::kProbeFunction, probe.id); + if (statement == nullptr) { + continue; + } + Builder::Slot slot = b.SlotOf(statement); + if (!slot.valid()) { + continue; + } + std::vector<Statement*> replacement; + auto it = actions.find(probe.id); + if (it != actions.end()) { + std::string describe; + replacement = StatementsFor(b, probe, it->second, &describe); + if (!replacement.empty()) { + applied++; + if (!description.empty()) { + description += "; "; + } + description += describe; + } + } + b.Remove(slot); + if (!replacement.empty()) { + b.InsertAll(slot, replacement); + } + } + if (detail != nullptr) { + *detail = "explored " + description; + } + return applied; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/mutators/explore.h b/deps/v8/experimental/redline/mutators/explore.h new file mode 100644 index 000000000000..744236d2155d --- /dev/null +++ b/deps/v8/experimental/redline/mutators/explore.h @@ -0,0 +1,115 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_MUTATORS_EXPLORE_H_ +#define V8_EXPERIMENTAL_REDLINE_MUTATORS_EXPLORE_H_ + +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/mutators/mutator.h" + +namespace redline { + +// The runtime-assisted "Explore" mutator, after Fuzzilli's ExplorationMutator. +// +// Static type guesses only go so far: for most variables the fuzzer does not +// know which properties and methods exist, and it never knows about objects +// coming from builtins it has no model of (d8.test.*, Intl, user classes, +// ...). Exploration asks the target instead: +// +// 1. Mutate(): inserts a few probes `__redline_explore("eN", v, [args])` +// (wrapped in try/catch) at random statement positions, each exploring +// one visible variable `v` with a few other visible variables and +// literals as potential arguments. The probes are described in +// MutationContext::probes. +// 2. The worker executes the instrumented program with kExploreRuntime +// prepended. At runtime the probe inspects the value (typeof, property +// names along the prototype chain, function arity, ...) picks an action +// that makes sense for it (call a method, load/store a property, call or +// construct a function, arithmetic/comparison for primitives, iterate, +// ...), performs it to check that it does not throw, and reports it as +// one JSON line "EXPLORE_ACTION: {...}" on the fuzzout channel. +// 3. ApplyExploreActions() replaces every probe that reported an action by +// ordinary code performing exactly that action (`let rN = v.m(a, b);`), +// and removes the probes that reported nothing. The result is a normal, +// deterministic program that is executed and evaluated as usual. +// +// One exploration therefore costs one extra execution. + +struct ExploreArg { + enum class Kind { + kVariable, + kNumber, + kString, + kBoolean, + kBigInt, + kUndefined, + kNull + }; + Kind kind = Kind::kUndefined; + std::string text; // variable name, number/bigint digits or string value + bool flag = false; // boolean value +}; + +struct ExploreProbe { + std::string id; // "e<N>"/"p<N>", unique within the program + std::string variable; // explored/probed variable + std::vector<ExploreArg> args; + bool can_await = false; // the probe sits in an async function +}; + +// A mutator in two halves: Mutate() only instruments the tree (and fills +// MutationContext::probes); the worker runs the instrumented program with +// runtime() prepended and hands the target's fuzzout to Apply(), which +// turns the probes into ordinary code. +class RuntimeAssistedMutator : public Mutator { + public: + using Mutator::Mutator; + bool runtime_assisted() const override { return true; } + // JavaScript prepended to the instrumented program. + virtual std::string_view runtime() const = 0; + // Rewrites the probes according to `fuzzout`. Returns the number of probes + // turned into code (0: nothing useful happened; the mutation is a no-op). + // Probes without an answer are removed. `detail` gets a short description. + virtual int Apply(Builder& builder, const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, MutationContext& ctx, + std::string* detail) = 0; + + // Finds the probe statement for `id` (the try statement wrapping the call + // of `function`), or nullptr. + static fast::Statement* FindProbe(Builder& builder, std::string_view function, + const std::string& id); + // The statement `try { function("id", v, extra...); } catch (e) {}`. + static fast::Statement* MakeProbe( + fast::Tree* tree, std::string_view function, const ExploreProbe& probe, + const std::vector<fast::Expression*>& extra); +}; + +class ExploreMutator final : public RuntimeAssistedMutator { + public: + ExploreMutator(); + bool Mutate(Builder& builder, MutationContext& ctx) override; + std::string_view runtime() const override; + int Apply(Builder& builder, const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, MutationContext& ctx, + std::string* detail) override; + + // Name of the runtime helper function the probes call. + static constexpr std::string_view kProbeFunction = "__redline_explore"; +}; + +// JavaScript defining kProbeFunction; prepended to instrumented programs. +extern const char kExploreRuntime[]; + +// Rewrites the probes in `builder`'s tree according to the actions in the +// target's fuzzout output (see ExploreMutator::Apply). +int ApplyExploreActions(Builder& builder, + const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, std::string* detail); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_MUTATORS_EXPLORE_H_ diff --git a/deps/v8/experimental/redline/mutators/mutator.h b/deps/v8/experimental/redline/mutators/mutator.h new file mode 100644 index 000000000000..6e5df9223b1e --- /dev/null +++ b/deps/v8/experimental/redline/mutators/mutator.h @@ -0,0 +1,143 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_MUTATORS_MUTATOR_H_ +#define V8_EXPERIMENTAL_REDLINE_MUTATORS_MUTATOR_H_ + +#include <memory> +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/core/builder.h" +#include "experimental/redline/core/component.h" +#include "experimental/redline/core/environment.h" +#include "experimental/redline/core/program.h" +#include "experimental/redline/core/selection.h" +#include "experimental/redline/generators/generator.h" + +namespace redline { + +struct ExploreProbe; + +struct MutationContext { + // The program being mutated (its tree is NOT the one in the Builder; the + // Builder works on a copy). May be null for ad-hoc trees. + ProgramPtr parent; + // A second program for splicing/combining; null if none available. + ProgramPtr partner; + const Environment* env = nullptr; + const GeneratorSet* generators = nullptr; + // Out: a short human-readable description of what was changed. + std::string detail; + // Out, for runtime-assisted mutators: the probes they inserted. The + // worker executes the instrumented program and completes the mutation + // from the target's answers (see mutators/explore.h). + std::vector<ExploreProbe> probes; + + MutationContext(); + ~MutationContext(); + MutationContext(const MutationContext&) = delete; + MutationContext& operator=(const MutationContext&) = delete; +}; + +class Mutator : public Component { + public: + // `max_simultaneous` is the largest number of sub-mutations one + // application may perform (Fuzzilli's maxSimultaneousMutations: 7 for + // instruction-level mutators, 3 for code generation, 1 for everything + // else); the engine draws the actual number uniformly from 1..max. + Mutator(std::string name, std::string_view description, double weight, + bool needs_partner, int max_simultaneous = 1) + : Component(std::move(name)), + description_(description), + weight_(weight), + needs_partner_(needs_partner), + max_simultaneous_(max_simultaneous) {} + + std::string_view description() const override { return description_; } + double weight() const { return weight_; } + bool needs_partner() const { return needs_partner_; } + int max_simultaneous() const { return max_simultaneous_; } + + // Mutates the Builder's tree in place. Returns false if the mutator could + // not find anything to do (the tree is then unchanged). + virtual bool Mutate(Builder& builder, MutationContext& ctx) = 0; + // True if Mutate() only instruments the program and the worker must run + // it and apply the target's answers to obtain the real mutation. + virtual bool runtime_assisted() const { return false; } + // For mutators that insert generated code: how many generator outputs + // one application inserts (min_count plus 0..extra_count). Others + // return false. + virtual bool SetInsertCounts(int min_count, int extra_count) { + (void)min_count; + (void)extra_count; + return false; + } + + private: + std::string_view description_; + double weight_; + bool needs_partner_; + int max_simultaneous_; +}; + +// All mutators, and the strategy that picks among them (core/selection.h). +// CreateDefault() installs the built-in mutators with the default `weighted` +// strategy; a fuzzing session replaces the strategy with the configured one +// through SetSelector(). +class MutatorSet { + public: + static std::unique_ptr<MutatorSet> CreateDefault(); + + const std::vector<std::unique_ptr<Mutator>>& all() const { return mutators_; } + // The same mutators as plain pointers, in the same order: what the + // selector sees. + const std::vector<Mutator*>& candidates() const { return candidates_; } + Mutator* Find(std::string_view name) const; + std::vector<std::string> Names() const; + + // Installs a selection strategy and initializes it with the mutators + // (weight names are validated here). Returns false with *error set. + bool SetSelector(std::unique_ptr<Selector<Mutator>> selector, + std::string* error); + // Number of fresh values the Prefix mutator declares: min_values plus + // 0..extra_values (FuzzConfig::prefix_min_values/prefix_extra_values). + bool ConfigurePrefix(int min_values, int extra_values); + Selector<Mutator>& selector() const { return *selector_; } + // Shorthands for the strategy's static weights (0 disables a mutator). + bool SetWeight(std::string_view name, double weight) { + return selector_->SetWeight(name, weight); + } + double WeightOf(const Mutator* mutator) const { + return selector_->WeightOf(*mutator); + } + + // Picks a mutator with the strategy. Mutators needing a partner are only + // eligible when `has_partner`. + Mutator* Pick(Random& rng, bool has_partner) const; + + std::vector<const Component*> Components() const; + + private: + std::vector<std::unique_ptr<Mutator>> mutators_; + std::vector<Mutator*> candidates_; + std::unique_ptr<Selector<Mutator>> selector_; +}; + +// Applies `mutator` to a copy of `parent`'s tree. On success returns the +// mutated tree; on failure returns nullptr. `rounds` sub-mutations are +// attempted (at least one must succeed). +// Applies `mutator` `rounds` times to a copy of `parent`'s tree. Returns the +// mutated tree, or nullptr if no round changed anything. For runtime-assisted +// mutators `probes` (if given) receives the inserted probes. +std::unique_ptr<fast::Tree> ApplyMutation( + Mutator& mutator, const Program& parent, const ProgramPtr& partner, + Random& rng, const Environment& env, const GeneratorSet& generators, + int rounds, std::string* detail, + std::vector<ExploreProbe>* probes = nullptr); + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_MUTATORS_MUTATOR_H_ diff --git a/deps/v8/experimental/redline/mutators/mutators.cc b/deps/v8/experimental/redline/mutators/mutators.cc new file mode 100644 index 000000000000..f06b2c3d12e6 --- /dev/null +++ b/deps/v8/experimental/redline/mutators/mutators.cc @@ -0,0 +1,2057 @@ +// Copyright 2026 the V8 project 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 <algorithm> +#include <cmath> +#include <string> + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/core/adaptive_selector.h" +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/core/weighted_selector.h" +#include "experimental/redline/fast/printer.h" +#include "experimental/redline/generators/codegen.h" +#include "experimental/redline/mutators/explore.h" +#include "experimental/redline/mutators/mutator.h" +#include "experimental/redline/mutators/probing.h" + +namespace redline { + +using namespace fast; // NOLINT(build/namespaces) + +namespace { + +// --- subtree analysis +// ------------------------------------------------------------ + +// What a piece of code needs from its surroundings to stay syntactically +// valid when moved elsewhere. +struct Requirements { + bool needs_function = false; // `return` outside a nested function + bool needs_async = false; // `await` / for-await outside a nested fn + bool needs_generator = false; // `yield` + bool needs_break = false; // unlabeled `break` outside own loop/switch + bool needs_continue = false; // unlabeled `continue` outside own loop + bool needs_sloppy = false; // `with`, `delete x`, legacy octal + bool needs_arguments = false; // `arguments` outside own non-arrow fn + bool needs_super = false; // `super` outside own method + bool needs_new_target = false; // `new.target` outside own function + bool has_external_label = false; // labeled jump to a label not inside + bool has_lexical_declaration = false; // top-level let/const/class + // Labels declared by the node itself (outside nested functions): the + // destination must not already be inside a label of the same name. + std::vector<std::string_view> declared_labels; +}; + +bool IsLegacyOctal(std::string_view raw) { + if (raw.size() < 2 || raw[0] != '0') { + return false; + } + return raw[1] >= '0' && raw[1] <= '9'; +} + +class RequirementsAnalyzer { + public: + Requirements Analyze(Node* root) { + req_ = Requirements(); + if (root->Is<VariableDeclaration>()) { + VariableKind k = root->Cast<VariableDeclaration>()->declaration_kind; + req_.has_lexical_declaration = k != VariableKind::kVar; + } else if (root->Is<ClassDeclaration>()) { + req_.has_lexical_declaration = true; + } + Visit(root, 0, 0, 0, 0); + return req_; + } + + private: + void Visit(Node* node, int fn_depth, int this_fn_depth, int loop_depth, + int switch_depth) { + if (node == nullptr) { + return; + } + switch (node->kind) { + case NodeKind::kReturnStatement: + if (fn_depth == 0) { + req_.needs_function = true; + } + break; + case NodeKind::kAwaitExpression: + if (fn_depth == 0) { + req_.needs_async = true; + } + break; + case NodeKind::kYieldExpression: + if (fn_depth == 0) { + req_.needs_generator = true; + } + break; + case NodeKind::kForOfStatement: + if (node->Cast<ForOfStatement>()->is_await && fn_depth == 0) { + req_.needs_async = true; + } + break; + case NodeKind::kBreakStatement: { + Identifier* label = node->Cast<BreakStatement>()->label; + if (label != nullptr) { + if (!HasLabel(label->name)) { + req_.has_external_label = true; + } + } else if (loop_depth == 0 && switch_depth == 0) { + req_.needs_break = true; + } + return; + } + case NodeKind::kContinueStatement: { + Identifier* label = node->Cast<ContinueStatement>()->label; + if (label != nullptr) { + if (!HasLabel(label->name)) { + req_.has_external_label = true; + } + } else if (loop_depth == 0) { + req_.needs_continue = true; + } + return; + } + case NodeKind::kWithStatement: + req_.needs_sloppy = true; + break; + case NodeKind::kUnaryExpression: { + auto* u = node->Cast<UnaryExpression>(); + if (u->op == UnaryOp::kDelete && u->argument->Is<Identifier>()) { + req_.needs_sloppy = true; + } + break; + } + case NodeKind::kNumericLiteral: + if (IsLegacyOctal(node->Cast<NumericLiteral>()->raw)) { + req_.needs_sloppy = true; + } + return; + case NodeKind::kIdentifier: + if (node->Cast<Identifier>()->name == "arguments" && + this_fn_depth == 0) { + req_.needs_arguments = true; + } + return; + case NodeKind::kSuper: + if (this_fn_depth == 0) { + req_.needs_super = true; + } + return; + case NodeKind::kMetaProperty: + if (node->Cast<MetaProperty>()->meta_kind == + MetaPropertyKind::kNewTarget && + this_fn_depth == 0) { + req_.needs_new_target = true; + } + return; + case NodeKind::kFunctionDeclaration: + case NodeKind::kFunctionExpression: + case NodeKind::kArrowFunctionExpression: { + const FunctionData* fn = AsFunctionData(node); + int next_this = this_fn_depth + (fn->is_arrow ? 0 : 1); + std::vector<std::string_view> saved = std::move(labels_); + labels_.clear(); + ForEachChild(node, [&](Node* child) { + Visit(child, fn_depth + 1, next_this, 0, 0); + }); + labels_ = std::move(saved); + return; + } + case NodeKind::kPropertyDefinition: + case NodeKind::kStaticBlock: { + std::vector<std::string_view> saved = std::move(labels_); + labels_.clear(); + ForEachChild(node, [&](Node* child) { + Visit(child, fn_depth + 1, this_fn_depth + 1, 0, 0); + }); + labels_ = std::move(saved); + return; + } + case NodeKind::kLabeledStatement: { + auto* l = node->Cast<LabeledStatement>(); + if (fn_depth == 0) { + req_.declared_labels.push_back(l->label->name); + } + labels_.push_back(l->label->name); + Visit(l->body, fn_depth, this_fn_depth, loop_depth, switch_depth); + labels_.pop_back(); + return; + } + case NodeKind::kWhileStatement: + case NodeKind::kDoWhileStatement: + case NodeKind::kForStatement: + case NodeKind::kForInStatement: + ForEachChild(node, [&](Node* child) { + Visit(child, fn_depth, this_fn_depth, loop_depth + 1, switch_depth); + }); + return; + case NodeKind::kSwitchStatement: + ForEachChild(node, [&](Node* child) { + Visit(child, fn_depth, this_fn_depth, loop_depth, switch_depth + 1); + }); + return; + default: + break; + } + if (node->Is<ForOfStatement>()) { + ForEachChild(node, [&](Node* child) { + Visit(child, fn_depth, this_fn_depth, loop_depth + 1, switch_depth); + }); + return; + } + ForEachChild(node, [&](Node* child) { + Visit(child, fn_depth, this_fn_depth, loop_depth, switch_depth); + }); + } + + bool HasLabel(std::string_view name) const { + return std::find(labels_.begin(), labels_.end(), name) != labels_.end(); + } + + Requirements req_; + std::vector<std::string_view> labels_; +}; + +Requirements AnalyzeRequirements(Node* node) { + RequirementsAnalyzer analyzer; + return analyzer.Analyze(node); +} + +bool Compatible(const Requirements& req, const Builder::Context& ctx) { + if (req.has_external_label) { + return false; + } + for (std::string_view label : req.declared_labels) { + if (std::find(ctx.labels.begin(), ctx.labels.end(), label) != + ctx.labels.end()) { + return false; + } + } + if (req.needs_function && + (!ctx.in_function || ctx.in_static_block || ctx.in_class_field)) { + return false; + } + if (req.needs_async && (!ctx.in_async || ctx.in_static_block)) { + return false; + } + if (req.needs_generator && !ctx.in_generator) { + return false; + } + if (req.needs_break && !ctx.break_allowed()) { + return false; + } + if (req.needs_continue && !ctx.in_loop) { + return false; + } + if (req.needs_sloppy && ctx.strict) { + return false; + } + if (req.needs_arguments && !ctx.has_arguments) { + return false; + } + if (req.needs_super && !ctx.in_method) { + return false; + } + if (req.needs_new_target && + !(ctx.has_arguments || ctx.in_class_field || ctx.in_static_block)) { + return false; + } + return true; +} + +// Visits two subtrees of identical shape in parallel. +template <typename F> +void ParallelWalk(Node* a, Node* b, F&& f) { + if (a == nullptr || b == nullptr) { + return; + } + f(a, b); + std::vector<Node*> ca, cb; + ForEachChild(a, [&](Node* c) { ca.push_back(c); }); + ForEachChild(b, [&](Node* c) { cb.push_back(c); }); + for (size_t i = 0; i < ca.size() && i < cb.size(); i++) { + ParallelWalk(ca[i], cb[i], f); + } +} + +bool IsLexicalDeclaration(const Statement* s) { + if (auto* v = s->As<VariableDeclaration>()) { + return v->declaration_kind != VariableKind::kVar; + } + return s->Is<ClassDeclaration>(); +} + +bool IsDirective(const Statement* s) { + auto* e = s->As<ExpressionStatement>(); + return e != nullptr && e->is_directive; +} + +// True if `root` mentions a private name (`o.#p`, `#p in o`) without being +// the class that declares it: moved anywhere else, such code is an early +// error ("Private field must be declared in an enclosing class"). +bool UsesPrivateNameOfEnclosingClass(Node* root) { + if (root->IsClass()) { + return false; + } + bool found = false; + Walk(root, [&](Node* n) { + if (found || n->IsClass()) { + return false; // a nested class declares its own names + } + if (n->Is<PrivateIdentifier>()) { + found = true; + } + return true; + }); + return found; +} + +// True if `root` contains a reference to one of `bindings`. +bool Uses(Builder& b, Node* root, const std::vector<Binding*>& bindings) { + if (bindings.empty()) { + return false; + } + absl::flat_hash_set<const Binding*> set(bindings.begin(), bindings.end()); + bool found = false; + Walk(root, [&](Node* n) { + if (found) { + return false; + } + auto* id = n->As<Identifier>(); + if (id != nullptr && b.scopes().IsReference(id) && + set.count(b.scopes().BindingOf(id))) { + found = true; + } + return !found; + }); + return found; +} + +// Builds a generation context at a statement slot. +GenContext ContextForSlot(Builder& b, const Builder::Slot& slot, + MutationContext& ctx) { + GenContext gen(b, *ctx.generators, *ctx.env); + gen.slot = slot; + gen.syntax = b.ContextAtSlot(slot); + gen.visible = b.VisibleAtSlot(slot); + return gen; +} + +// Builds a generation context at an arbitrary node. +GenContext ContextForNode(Builder& b, Node* node, MutationContext& ctx) { + GenContext gen(b, *ctx.generators, *ctx.env); + Statement* enclosing = b.EnclosingStatement(node); + if (enclosing != nullptr) { + gen.slot = b.SlotOf(enclosing); + } + gen.syntax = b.ContextAt(node); + gen.visible = b.VisibleAt(node); + return gen; +} + +Node* ReplaceAnchored(Builder& b, Node* old_node, Node* new_node) { + if (old_node->start >= 0) { + mk::Anchor(new_node, old_node->start); + } + return b.Replace(old_node, new_node) ? new_node : nullptr; +} + +std::string Describe(Node* node) { + std::string s = Print(node, fast::PrintOptions{}, nullptr); + if (s.size() > 60) { + s = s.substr(0, 57) + "..."; + } + for (char& c : s) { + if (c == '\n') { + c = ' '; + } + } + return s; +} + +// --- Operation mutator +// -------------------------------------------------------------- + +REDLINE_TUNABLE(kOperationEmptyStringCandidateChance, + "mutators.Operation.empty_string_candidate_chance", 0.2, 0, 1, + "probability that an empty string literal is kept as an " + "Operation candidate"); +REDLINE_TUNABLE(kOperationMaxAttempts, "mutators.Operation.max_attempts", 8, 1, + 16, + "candidate nodes the Operation mutator tries before giving up"); +REDLINE_TUNABLE( + kOperationBinaryOpAttempts, "mutators.Operation.binary_op_attempts", 4, 1, + 16, "draws to find a binary operator different from the current one"); +REDLINE_TUNABLE(kOperationPlainAssignChance, + "mutators.Operation.plain_assign_chance", 0.2, 0, 1, + "probability that a mutated assignment operator becomes plain " + "`=` rather than a compound one"); +REDLINE_TUNABLE(kOperationRandomNumberMax, + "mutators.Operation.random_number_max", 100, 1, 1024, + "upper bound of the uniform random replacement for a numeric " + "literal (0..max)"); +REDLINE_TUNABLE(kOperationPropertyNameAttempts, + "mutators.Operation.property_name_attempts", 4, 1, 16, + "draws to find a property name different from the current one"); + +class OperationMutator final : public Mutator { + public: + // Fuzzilli: OperationMutator, weight 1, up to 7 simultaneous. + OperationMutator() + : Mutator("Operation", + "changes an operator, literal value or property name in place", + 1, false, 7) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + std::vector<Node*> candidates = b.Collect([&](Node* n) { + switch (n->kind) { + case NodeKind::kBinaryExpression: + case NodeKind::kLogicalExpression: + case NodeKind::kUnaryExpression: + case NodeKind::kUpdateExpression: + case NodeKind::kAssignmentExpression: + case NodeKind::kNumericLiteral: + case NodeKind::kBooleanLiteral: + case NodeKind::kMemberExpression: + return true; + case NodeKind::kStringLiteral: + return !n->Cast<StringLiteral>()->value.empty() || + r.Chance(kOperationEmptyStringCandidateChance()); + default: + return false; + } + }); + for (int attempt = 0; + attempt < kOperationMaxAttempts.AsInt() && !candidates.empty(); + attempt++) { + Node* node = candidates[r.Index(candidates.size())]; + if (MutateNode(b, node, ctx)) { + return true; + } + } + return false; + } + + private: + bool MutateNode(Builder& b, Node* node, MutationContext& ctx) { + Random& r = b.rng(); + Tree* t = b.tree(); + switch (node->kind) { + case NodeKind::kBinaryExpression: { + auto* e = node->Cast<BinaryExpression>(); + if (e->left->Is<PrivateIdentifier>()) { + return false; + } + BinaryOp op = e->op; + for (int i = 0; i < kOperationBinaryOpAttempts.AsInt() && op == e->op; + i++) { + op = CodeGen::RandomBinaryOp(r); + } + if (op == BinaryOp::kExp && (e->left->Is<UnaryExpression>() || + e->left->Is<AwaitExpression>())) { + return false; + } + ctx.detail = std::string("binary ") + OperatorText(e->op) + " -> " + + OperatorText(op); + e->op = op; + return true; + } + case NodeKind::kLogicalExpression: { + auto* e = node->Cast<LogicalExpression>(); + LogicalOp op = e->op; + while (op == e->op) { + op = CodeGen::RandomLogicalOp(r); + } + // `a ?? b || c` without parentheses is an error; the printer adds + // them when precedences mix, so this is safe. + ctx.detail = std::string("logical ") + OperatorText(e->op) + " -> " + + OperatorText(op); + e->op = op; + return true; + } + case NodeKind::kUnaryExpression: { + auto* e = node->Cast<UnaryExpression>(); + if (e->op == UnaryOp::kDelete) { + return false; + } + UnaryOp op = e->op; + while (op == e->op) { + op = CodeGen::RandomUnaryOp(r); + } + Node* parent = b.ParentOf(node); + if (parent != nullptr && parent->Is<BinaryExpression>() && + parent->Cast<BinaryExpression>()->op == BinaryOp::kExp && + parent->Cast<BinaryExpression>()->left == node) { + return false; // `-x ** 2` + } + ctx.detail = std::string("unary ") + OperatorText(e->op) + " -> " + + OperatorText(op); + e->op = op; + return true; + } + case NodeKind::kUpdateExpression: { + auto* e = node->Cast<UpdateExpression>(); + if (r.Coin()) { + e->op = e->op == UpdateOp::kIncrement ? UpdateOp::kDecrement + : UpdateOp::kIncrement; + ctx.detail = "update operator flipped"; + } else { + e->prefix = !e->prefix; + ctx.detail = "update prefix flipped"; + } + return true; + } + case NodeKind::kAssignmentExpression: { + auto* e = node->Cast<AssignmentExpression>(); + if (!e->left->Is<Identifier>() && !e->left->Is<MemberExpression>()) { + return false; + } + AssignOp op = r.Chance(kOperationPlainAssignChance()) + ? AssignOp::kAssign + : CodeGen::RandomCompoundAssignOp(r); + if (op == e->op) { + return false; + } + ctx.detail = std::string("assignment ") + OperatorText(e->op) + " -> " + + OperatorText(op); + e->op = op; + return true; + } + case NodeKind::kNumericLiteral: { + auto* n = node->Cast<NumericLiteral>(); + double old = n->value; + double v; // Assigned on every path of the switch below. + switch (r.Index(8)) { + case 0: + v = old + 1; + break; + case 1: + v = old - 1; + break; + case 2: + v = -old; + break; + case 3: + v = old * 2; + break; + case 4: + v = r.Pick(ctx.env->numbers()); + break; + case 5: + v = static_cast<double>( + r.Range(0, kOperationRandomNumberMax.AsInt())); + break; + case 6: + v = old / 2; + break; + default: + v = static_cast<double>(r.Next() >> 32); + break; + } + if (v == old) { + return false; + } + // Negative numbers as object keys or member names are not literals. + Node* parent = b.ParentOf(node); + bool is_key = + parent != nullptr && + ((parent->Is<Property>() && parent->Cast<Property>()->key == node && + !parent->Cast<Property>()->computed) || + (parent->Is<MethodDefinition>() && + parent->Cast<MethodDefinition>()->key == node && + !parent->Cast<MethodDefinition>()->computed) || + (parent->Is<PropertyDefinition>() && + parent->Cast<PropertyDefinition>()->key == node && + !parent->Cast<PropertyDefinition>()->computed)); + if (is_key && (v < 0 || v != v || std::isinf(v))) { + v = std::abs(v == v ? v : 1); + } + if (is_key && std::isinf(v)) { + v = 1; + } + n->value = v; + n->raw = {}; + ctx.detail = StringPrintf("number %g -> %g", old, v); + return true; + } + case NodeKind::kBooleanLiteral: { + auto* lit = node->Cast<BooleanLiteral>(); + lit->value = !lit->value; + ctx.detail = "boolean flipped"; + return true; + } + case NodeKind::kStringLiteral: { + auto* s = node->Cast<StringLiteral>(); + Node* parent = b.ParentOf(node); + if (parent != nullptr && parent->Is<ExpressionStatement>() && + parent->Cast<ExpressionStatement>()->is_directive) { + return false; + } + if (parent != nullptr && parent->Is<ImportExpression>()) { + return false; + } + std::string old = s->value; + std::string v; + switch (r.Index(5)) { + case 0: + v = std::string(r.Pick(ctx.env->strings())); + break; + case 1: + v = std::string(r.Pick(ctx.env->property_names())); + break; + case 2: + v = old + old; + break; + case 3: + v = old.substr(0, old.size() / 2); + break; + default: + v = old + "x"; + break; + } + if (v == old) { + return false; + } + s->value = v; + s->raw = {}; + ctx.detail = + "string \"" + (old.size() > 20 ? old.substr(0, 20) + "..." : old) + + "\" -> \"" + (v.size() > 20 ? v.substr(0, 20) + "..." : v) + "\""; + return true; + } + case NodeKind::kMemberExpression: { + auto* m = node->Cast<MemberExpression>(); + if (m->computed || !m->property->Is<Identifier>() || + m->object->Is<Super>()) { + return false; + } + std::string_view old = m->property->Cast<Identifier>()->name; + std::string_view name = old; + // Type-directed names when the object is a known variable. + JsType type = Builder::GuessType(m->object); + const BuiltinType* bt = ctx.env->ForType(type); + for (int i = 0; + i < kOperationPropertyNameAttempts.AsInt() && name == old; i++) { + if (bt != nullptr && r.Coin()) { + if (!bt->methods.empty() && r.Coin()) { + name = r.Pick(bt->methods).name; + } else if (!bt->properties.empty()) { + name = r.Pick(bt->properties); + } + } else { + name = r.Pick(ctx.env->property_names()); + } + if (!IsIdentifierName(name)) { + name = old; + } + } + if (name == old) { + return false; + } + m->property = mk::Id(t, name); + ctx.detail = + "property ." + std::string(old) + " -> ." + std::string(name); + return true; + } + default: + return false; + } + } +}; + +// --- Input mutator +// ------------------------------------------------------------------- + +REDLINE_TUNABLE(kInputSkipUndefinedChance, + "mutators.Input.skip_undefined_chance", 0.7, 0, 1, + "probability that a reference to `undefined` is skipped as an " + "Input candidate"); +REDLINE_TUNABLE( + kInputMaxAttempts, "mutators.Input.max_attempts", 8, 1, 16, + "identifier references the Input mutator tries before giving up"); +REDLINE_TUNABLE(kInputTypeMismatchChance, "mutators.Input.type_mismatch_chance", + 0.2, 0, 1, + "probability that a visible variable of a different type is an " + "acceptable replacement"); +REDLINE_TUNABLE(kInputLiteralChance, "mutators.Input.literal_chance", 0.15, 0, + 1, + "probability that a value reference is replaced by a literal " + "rather than another variable"); + +class InputMutator final : public Mutator { + public: + // Fuzzilli: InputMutator (loose 2 + aware 1), up to 7 simultaneous. + InputMutator() + : Mutator("Input", + "replaces a variable reference by another visible variable", 3, + false, 7) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + ScopeAnalysis& scopes = b.scopes(); + std::vector<Node*> candidates = b.Collect([&](Node* n) { + if (!n->Is<Identifier>()) { + return false; + } + auto* id = n->Cast<Identifier>(); + if (!scopes.IsReference(id)) { + return false; + } + if (id->name == "undefined" && r.Chance(kInputSkipUndefinedChance())) { + return false; + } + return b.RoleOf(n) != ExpressionRole::kNotReplaceable; + }); + for (int attempt = 0; + attempt < kInputMaxAttempts.AsInt() && !candidates.empty(); + attempt++) { + auto* id = candidates[r.Index(candidates.size())]->Cast<Identifier>(); + ExpressionRole role = b.RoleOf(id); + std::vector<Variable> visible = b.VisibleAt(id); + Binding* binding = scopes.BindingOf(id); + JsType type = + binding != nullptr ? b.GuessType(binding) : JsType::kUnknown; + std::vector<const Variable*> options; + for (const Variable& v : visible) { + if (v.name == id->name) { + continue; + } + if (v.name == "arguments" && !b.ContextAt(id).has_arguments) { + continue; + } + if (role == ExpressionRole::kTarget && + (v.is_constant || v.name == "arguments")) { + continue; + } + if (type == JsType::kUnknown || v.type == type || + v.type == JsType::kUnknown || + r.Chance(kInputTypeMismatchChance())) { + options.push_back(&v); + } + } + if (role == ExpressionRole::kValue && r.Chance(kInputLiteralChance())) { + // Replace by a literal of the same type instead. + GenContext gen = ContextForNode(b, id, ctx); + CodeGen cg(gen); + std::string old(id->name); + if (ReplaceAnchored(b, id, cg.Literal(type)) != nullptr) { + ctx.detail = "input " + old + " -> literal"; + return true; + } + continue; + } + if (options.empty()) { + continue; + } + const Variable& choice = *options[r.Index(options.size())]; + // Don't create `delete name` in strict code. + Node* parent = b.ParentOf(id); + if (parent != nullptr && parent->Is<UnaryExpression>() && + parent->Cast<UnaryExpression>()->op == UnaryOp::kDelete) { + continue; + } + ctx.detail = + "input " + std::string(id->name) + " -> " + std::string(choice.name); + id->name = b.tree()->Intern(choice.name); + b.Invalidate(); + return true; + } + return false; + } +}; + +// --- Remove mutator +// ----------------------------------------------------------------- + +REDLINE_TUNABLE(kRemoveElementChance, "mutators.Remove.element_chance", 0.3, 0, + 1, + "probability of removing an argument, element or property " + "instead of a statement"); +REDLINE_TUNABLE(kRemoveMaxAttempts, "mutators.Remove.max_attempts", 8, 1, 16, + "statement slots the Remove mutator tries before giving up"); + +class RemoveMutator final : public Mutator { + public: + // No Fuzzilli counterpart: weight 0 by default (enable with + // --mutator-weights). + RemoveMutator() + : Mutator("Remove", "removes a statement, argument, element or property", + 0, false) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + if (r.Chance(kRemoveElementChance()) && RemoveElement(b, ctx)) { + return true; + } + std::vector<Builder::Slot> slots = b.StatementSlots(); + for (int attempt = 0; + attempt < kRemoveMaxAttempts.AsInt() && !slots.empty(); attempt++) { + const Builder::Slot& slot = slots[r.Index(slots.size())]; + Statement* s = slot.statement(); + if (s == nullptr || IsDirective(s)) { + continue; + } + // Removing a declaration that later code still uses only produces a + // ReferenceError: never do that. + if (!b.EscapingBindings({s}, /*block_scoped_only=*/false).empty()) { + continue; + } + ctx.detail = + std::string("removed ") + s->kind_name() + " `" + Describe(s) + "`"; + b.Remove(slot); + return true; + } + return false; + } + + private: + bool RemoveElement(Builder& b, MutationContext& ctx) { + Random& r = b.rng(); + std::vector<Node*> candidates = b.Collect([&](Node* n) { + switch (n->kind) { + case NodeKind::kCallExpression: + return !n->Cast<CallExpression>()->arguments.empty(); + case NodeKind::kNewExpression: + return !n->Cast<NewExpression>()->arguments.empty(); + case NodeKind::kArrayExpression: + return !n->Cast<ArrayExpression>()->elements.empty(); + case NodeKind::kObjectExpression: + return !n->Cast<ObjectExpression>()->properties.empty(); + default: + return false; + } + }); + if (candidates.empty()) { + return false; + } + Node* node = candidates[r.Index(candidates.size())]; + switch (node->kind) { + case NodeKind::kCallExpression: { + auto& args = node->Cast<CallExpression>()->arguments; + args.erase(args.begin() + + static_cast<std::ptrdiff_t>(r.Index(args.size()))); + ctx.detail = "removed call argument"; + break; + } + case NodeKind::kNewExpression: { + auto& args = node->Cast<NewExpression>()->arguments; + args.erase(args.begin() + + static_cast<std::ptrdiff_t>(r.Index(args.size()))); + ctx.detail = "removed constructor argument"; + break; + } + case NodeKind::kArrayExpression: { + auto& elements = node->Cast<ArrayExpression>()->elements; + elements.erase(elements.begin() + + static_cast<std::ptrdiff_t>(r.Index(elements.size()))); + ctx.detail = "removed array element"; + break; + } + case NodeKind::kObjectExpression: { + auto& props = node->Cast<ObjectExpression>()->properties; + props.erase(props.begin() + + static_cast<std::ptrdiff_t>(r.Index(props.size()))); + ctx.detail = "removed object property"; + break; + } + default: + return false; + } + b.Invalidate(); + return true; + } +}; + +// --- Insert (code generation) mutator +// -------------------------------------------------- + +REDLINE_TUNABLE(kInsertSlotAttempts, "mutators.Insert.slot_attempts", 6, 1, 16, + "slots drawn to find one with a function in scope when " + "preferring functions"); +REDLINE_TUNABLE(kInsertExtraContinueChance, + "mutators.Insert.extra_continue_chance", 0.6, 0, 1, + "probability of inserting one more generator output beyond the " + "minimum (geometric)"); + +class InsertMutator final : public Mutator { + public: + // Inserts between min_count and min_count + extra_count generator outputs + // (geometrically distributed) at a random slot, or at the top of the + // program with `at_top` (the "fresh values" prefix every mutation chain + // starts with, after Fuzzilli's buildPrefix()). `max_simultaneous` slots + // may be filled per application (Fuzzilli's CodeGenMutator: 3). + InsertMutator(std::string name, std::string_view description, double weight, + std::vector<std::string> generator_names, bool prefer_functions, + int min_count = 1, int extra_count = 2, bool at_top = false, + int max_simultaneous = 1) + : Mutator(std::move(name), description, weight, false, max_simultaneous), + generator_names_(std::move(generator_names)), + prefer_functions_(prefer_functions), + min_count_(min_count), + extra_count_(extra_count), + at_top_(at_top) {} + + // How many generator outputs one application inserts: min_count plus a + // geometrically distributed 0..extra_count. + bool SetInsertCounts(int min_count, int extra_count) override { + min_count_ = min_count; + extra_count_ = extra_count; + return true; + } + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + Builder::Slot slot; + if (at_top_) { + std::vector<Builder::Slot> slots = b.InsertionSlots(); + for (const Builder::Slot& s : slots) { + if (s.owner == b.root()) { + slot = s; + break; + } + } + if (!slot.valid()) { + return false; + } + } + for (int attempt = 0; attempt < kInsertSlotAttempts.AsInt() && !at_top_; + attempt++) { + slot = b.RandomInsertionSlot(); + if (!slot.valid()) { + return false; + } + if (!prefer_functions_) { + break; + } + std::vector<Variable> visible = b.VisibleAtSlot(slot); + if (!Builder::OfType(visible, JsType::kFunction).empty()) { + break; + } + } + GenContext gen = ContextForSlot(b, slot, ctx); + std::vector<Statement*> out; + gen.out = &out; + int count = + min_count_ + r.SmallCount(extra_count_, kInsertExtraContinueChance()); + std::string names; + for (int i = 0; i < count; i++) { + Generator* g = PickGenerator(gen); + if (g == nullptr) { + break; + } + g->stats().invocations++; + size_t before = out.size(); + if (g->Generate(gen, &out) && out.size() > before) { + g->stats().produced++; + NoteGeneratorUsed(g); + if (!names.empty()) { + names += '+'; + } + names += g->name(); + } else { + out.resize(before); + } + } + if (out.empty()) { + return false; + } + b.InsertAll(slot, out); + ctx.detail = "inserted " + names; + return true; + } + + private: + // Asks the generator strategy for one generator that is applicable here + // and, if this mutator has a generator list, on that list. + Generator* PickGenerator(const GenContext& gen) { + const GeneratorSet& set = gen.generators; + auto eligible = [&](const Generator& g) { + if (!generator_names_.empty() && + std::find(generator_names_.begin(), generator_names_.end(), + g.name()) == generator_names_.end()) { + return false; + } + return g.Applicable(gen); + }; + size_t index = + set.selector().Pick(set.candidates(), gen.builder.rng(), eligible); + return index == Selector<Generator>::kNoChoice ? nullptr + : set.candidates()[index]; + } + + std::vector<std::string> generator_names_; + bool prefer_functions_; + int min_count_; + int extra_count_; + bool at_top_; +}; + +// --- Expression mutator +// ------------------------------------------------------------- + +REDLINE_TUNABLE( + kExpressionMaxAttempts, "mutators.Expression.max_attempts", 8, 1, 16, + "value expressions the Expression mutator tries before giving up"); +REDLINE_TUNABLE(kExpressionComplexCandidateChance, + "mutators.Expression.complex_candidate_chance", 0.2, 0, 1, + "probability that a spread, template, function or class " + "expression is kept as a candidate"); + +class ExpressionMutator final : public Mutator { + public: + // Closest Fuzzilli counterpart: PropertyAccessorMutator (weight 1, shared + // with Call), up to 3 simultaneous. + ExpressionMutator() + : Mutator("Expression", + "replaces or wraps an expression in value position", 0.5, false, + 3) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + std::vector<Expression*> candidates = b.ValueExpressions(); + for (int attempt = 0; + attempt < kExpressionMaxAttempts.AsInt() && !candidates.empty(); + attempt++) { + Expression* e = candidates[r.Index(candidates.size())]; + if ((e->Is<SpreadElement>() || e->Is<TemplateLiteral>() || + e->Is<FunctionExpression>() || e->Is<ClassExpression>() || + e->Is<ArrowFunctionExpression>()) && + !r.Chance(kExpressionComplexCandidateChance())) { + continue; + } + Node* parent = b.ParentOf(e); + if (parent == nullptr) { + continue; + } + if (parent->Is<ExpressionStatement>() && + parent->Cast<ExpressionStatement>()->is_directive) { + continue; + } + if (parent->Is<SpreadElement>() && !r.Coin()) { + continue; + } + bool under_delete = + parent->Is<UnaryExpression>() && + parent->Cast<UnaryExpression>()->op == UnaryOp::kDelete; + bool exp_left = parent->Is<BinaryExpression>() && + parent->Cast<BinaryExpression>()->op == BinaryOp::kExp && + parent->Cast<BinaryExpression>()->left == e; + GenContext gen = ContextForNode(b, e, ctx); + CodeGen cg(gen); + JsType type = Builder::GuessType(e); + Expression* replacement = nullptr; + std::string how; + switch (r.Index(10)) { + case 0: + case 1: + case 2: { + Identifier* v = cg.Variable(type); + if (v == nullptr || under_delete) { + continue; + } + replacement = v; + how = "variable"; + break; + } + case 3: + case 4: + replacement = cg.Literal(type); + how = "literal"; + break; + case 5: + case 6: + replacement = cg.Expression(1); + how = "expression"; + break; + default: { + if (e->Is<SpreadElement>()) { + continue; // `...x + 1` is not an expression + } + replacement = Wrap(cg, e, gen, exp_left); + how = "wrap"; + break; + } + } + if (replacement == nullptr) { + continue; + } + if (under_delete && replacement->Is<Identifier>()) { + continue; + } + std::string old = Describe(e); + if (ReplaceAnchored(b, e, replacement) == nullptr) { + continue; + } + ctx.detail = "expression `"; + ctx.detail += old; + ctx.detail += "` -> "; + ctx.detail += how; + return true; + } + return false; + } + + private: + // Wraps `e` in a new expression that uses it. `e` is detached from its + // parent by the caller's Replace; it may be reused inside the wrapper. + Expression* Wrap(CodeGen& cg, Expression* e, GenContext& gen, bool exp_left) { + Random& r = cg.rng(); + Tree* t = cg.tree(); + switch (r.Index(14)) { + case 0: + return mk::Binary(t, CodeGen::RandomArithmeticOp(r), e, + cg.Value(JsType::kNumber, 1)); + case 1: + return mk::Binary(t, CodeGen::RandomArithmeticOp(r), + cg.Value(JsType::kUnknown, 1), e); + case 2: + return mk::Call(t, + mk::Id(t, r.Pick({"String", "Number", "Boolean", + "Object", "BigInt", "Symbol"})), + {e}); + case 3: + return mk::CallMethod(t, mk::Id(t, "Math"), + r.Pick({"abs", "floor", "round", "sqrt", "trunc", + "fround", "sign"}), + {e}); + case 4: + return mk::Array(t, {e}); + case 5: + return mk::Object(t, {mk::Prop(t, "x", e)}); + case 6: + if (exp_left) { + return nullptr; + } + return mk::Unary(t, CodeGen::RandomUnaryOp(r), e); + case 7: + return mk::Cond(t, cg.Condition(1), e, cg.Value(JsType::kUnknown, 1)); + case 8: + return mk::Cond(t, cg.Condition(1), cg.Value(JsType::kUnknown, 1), e); + case 9: + return mk::Seq(t, {cg.Value(JsType::kUnknown, 1), e}); + case 10: + if (gen.syntax.in_async && !gen.syntax.in_static_block && !exp_left) { + return mk::Await(t, e); + } + return mk::Call(t, mk::ArrowExpr(t, {}, e), {}); + case 11: + return mk::Logical(t, CodeGen::RandomLogicalOp(r), e, + cg.Value(JsType::kUnknown, 1)); + case 12: + return mk::CallMethod( + t, mk::Id(t, "JSON"), "parse", + {mk::CallMethod(t, mk::Id(t, "JSON"), "stringify", {e})}); + default: { + std::string_view p = gen.builder.FreshName("x"); + return mk::Call(t, mk::ArrowExpr(t, {p}, mk::Id(t, p)), {e}); + } + } + } +}; + +// --- Wrap mutator +// --------------------------------------------------------------------- + +REDLINE_TUNABLE(kWrapMaxAttempts, "mutators.Wrap.max_attempts", 8, 1, 16, + "statement slots the Wrap mutator tries before giving up"); +REDLINE_TUNABLE(kWrapMaxExtraStatements, "mutators.Wrap.max_extra_statements", + 3, 0, 64, + "most statements after the first that one wrapper encloses"); +REDLINE_TUNABLE( + kWrapExtraStatementChance, "mutators.Wrap.extra_statement_chance", 0.4, 0, + 1, "probability of extending the wrapped run by one more statement"); + +class WrapMutator final : public Mutator { + public: + // No Fuzzilli counterpart: weight 0 by default. + WrapMutator() + : Mutator("Wrap", "wraps statements in a loop, if, try, label or IIFE", 0, + false) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + std::vector<Builder::Slot> slots = b.StatementSlots(); + for (int attempt = 0; attempt < kWrapMaxAttempts.AsInt() && !slots.empty(); + attempt++) { + Builder::Slot slot = slots[r.Index(slots.size())]; + Statement* first = slot.statement(); + if (first == nullptr || IsDirective(first)) { + continue; + } + // A run of 1..4 statements. + size_t count = + 1 + static_cast<size_t>(r.SmallCount(kWrapMaxExtraStatements.AsInt(), + kWrapExtraStatementChance())); + count = std::min(count, slot.list->size() - slot.index); + std::vector<Statement*> run; + Requirements req; + for (size_t i = 0; i < count; i++) { + Statement* s = (*slot.list)[slot.index + i]; + if (IsDirective(s)) { + break; + } + Requirements sr = AnalyzeRequirements(s); + req.needs_function |= sr.needs_function; + req.needs_async |= sr.needs_async; + req.needs_generator |= sr.needs_generator; + req.needs_break |= sr.needs_break; + req.needs_continue |= sr.needs_continue; + req.needs_sloppy |= sr.needs_sloppy; + req.needs_arguments |= sr.needs_arguments; + req.needs_super |= sr.needs_super; + req.needs_new_target |= sr.needs_new_target; + req.has_external_label |= sr.has_external_label; + run.push_back(s); + } + if (run.empty()) { + continue; + } + // Moving block-scoped declarations into a block hides them from the + // code that uses them; `var`s survive every wrapper except the IIFE. + std::vector<Node*> run_nodes(run.begin(), run.end()); + if (!b.EscapingBindings(run_nodes, /*block_scoped_only=*/true).empty()) { + continue; + } + bool vars_escape = + !b.EscapingBindings(run_nodes, /*block_scoped_only=*/false).empty(); + Tree* t = b.tree(); + GenContext gen = ContextForSlot(b, slot, ctx); + CodeGen cg(gen); + Statement* wrapper = nullptr; + std::string how; + switch (r.Index(8)) { + case 0: + case 1: { + std::string_view counter = b.FreshName("i"); + static const double kCounts[] = {2, 3, 5, 10, 100, 1000, 10000}; + wrapper = mk::CountedLoop(t, counter, mk::Num(t, kCounts[r.Index(7)]), + mk::Block(t, run)); + how = "loop"; + break; + } + case 2: + wrapper = mk::If(t, cg.Condition(1), mk::Block(t, run)); + how = "if"; + break; + case 3: + wrapper = mk::Try(t, run, b.FreshName("e"), {}); + how = "try"; + break; + case 4: { + std::vector<Statement*> finalizer; + wrapper = mk::Try(t, run, {}, {}, &finalizer); + how = "try-finally"; + break; + } + case 5: { + std::string_view label = b.FreshName("L"); + wrapper = mk::Labeled(t, label, mk::Block(t, run)); + how = "label"; + break; + } + case 6: { + if (req.needs_generator || req.needs_break || req.needs_continue || + req.has_external_label || vars_escape) { + continue; + } + Expression* fn = mk::Arrow(t, {}, run, req.needs_async); + wrapper = mk::ExprStmt(t, mk::Call(t, fn, {})); + how = "iife"; + break; + } + default: { + std::string_view e = b.FreshName("e"); + wrapper = mk::ForOf(t, VariableKind::kConst, e, cg.ArrayLiteral(1), + mk::Block(t, run)); + how = "for-of"; + break; + } + } + // Replace the run by the wrapper. + slot.list->erase( + slot.list->begin() + static_cast<std::ptrdiff_t>(slot.index), + slot.list->begin() + + static_cast<std::ptrdiff_t>(slot.index + run.size())); + b.Invalidate(); + b.Insert(slot, wrapper); + ctx.detail = + "wrapped " + std::to_string(run.size()) + " statement(s) in " + how; + return true; + } + return false; + } +}; + +// --- Duplicate / Reorder +// ------------------------------------------------------------------ + +REDLINE_TUNABLE(kDuplicateMaxAttempts, "mutators.Duplicate.max_attempts", 8, 1, + 16, + "statement slots the Duplicate mutator tries before giving up"); + +class DuplicateMutator final : public Mutator { + public: + // No Fuzzilli counterpart: weight 0 by default. + DuplicateMutator() + : Mutator("Duplicate", "duplicates a statement", 0, false) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + std::vector<Builder::Slot> slots = b.StatementSlots(); + for (int attempt = 0; + attempt < kDuplicateMaxAttempts.AsInt() && !slots.empty(); attempt++) { + Builder::Slot slot = slots[r.Index(slots.size())]; + Statement* s = slot.statement(); + if (s == nullptr || IsDirective(s) || IsLexicalDeclaration(s)) { + continue; + } + if (s->Is<FunctionDeclaration>()) { + // Duplicate function declarations are only fine in sloppy + // function/script scope. + Builder::Context c = b.ContextAtSlot(slot); + bool function_body = slot.owner->Is<BlockStatement>() && + b.ParentOf(slot.owner) != nullptr && + b.ParentOf(slot.owner)->IsFunction(); + if (c.strict || !(slot.owner->Is<fast::Program>() || function_body)) { + continue; + } + } + Statement* copy = b.tree()->Clone(s); + Builder::Slot where = slot; + where.index = r.Coin() ? slot.index + 1 + : static_cast<size_t>(r.Range( + static_cast<int64_t>(slot.index) + 1, + static_cast<int64_t>(slot.list->size()))); + b.Insert(where, copy); + ctx.detail = std::string("duplicated ") + s->kind_name() + " `" + + Describe(s) + "`"; + return true; + } + return false; + } +}; + +REDLINE_TUNABLE(kReorderMaxAttempts, "mutators.Reorder.max_attempts", 8, 1, 16, + "statement slots the Reorder mutator tries before giving up"); + +class ReorderMutator final : public Mutator { + public: + // No Fuzzilli counterpart: weight 0 by default. + ReorderMutator() + : Mutator("Reorder", "swaps two adjacent statements", 0, false) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + std::vector<Builder::Slot> slots = b.StatementSlots(); + for (int attempt = 0; + attempt < kReorderMaxAttempts.AsInt() && !slots.empty(); attempt++) { + Builder::Slot slot = slots[r.Index(slots.size())]; + if (slot.index + 1 >= slot.list->size()) { + continue; + } + Statement* a = (*slot.list)[slot.index]; + Statement* c = (*slot.list)[slot.index + 1]; + if (IsDirective(a) || IsDirective(c)) { + continue; + } + // Do not move a declaration past a use of it (TDZ, undefined values). + if (Uses(b, c, b.EscapingBindings({a}, false)) || + Uses(b, a, b.EscapingBindings({c}, false))) { + continue; + } + std::swap((*slot.list)[slot.index], (*slot.list)[slot.index + 1]); + b.Invalidate(); + ctx.detail = + std::string("swapped ") + a->kind_name() + " and " + c->kind_name(); + return true; + } + return false; + } +}; + +// --- Call mutator +// ------------------------------------------------------------------------ + +REDLINE_TUNABLE(kCallMaxAttempts, "mutators.Call.max_attempts", 8, 1, 16, + "call/new expressions the Call mutator tries before giving up"); + +class CallMutator final : public Mutator { + public: + // Closest Fuzzilli counterpart: PropertyAccessorMutator (weight 1, shared + // with Expression), up to 3 simultaneous. + CallMutator() + : Mutator("Call", + "adds/removes/spreads arguments, swaps callees, call <-> new", + 0.5, false, 3) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + Random& r = b.rng(); + std::vector<Node*> candidates = b.Collect([&](Node* n) { + if (auto* c = n->As<CallExpression>()) { + return !c->callee->Is<Super>() && !c->optional; + } + return n->Is<NewExpression>(); + }); + for (int attempt = 0; + attempt < kCallMaxAttempts.AsInt() && !candidates.empty(); attempt++) { + Node* node = candidates[r.Index(candidates.size())]; + Node* parent = b.ParentOf(node); + if (parent == nullptr) { + continue; + } + if (parent->Is<ChainExpression>()) { + continue; + } + GenContext gen = ContextForNode(b, node, ctx); + CodeGen cg(gen); + Tree* t = b.tree(); + std::vector<Expression*>* args = + node->Is<CallExpression>() ? &node->Cast<CallExpression>()->arguments + : &node->Cast<NewExpression>()->arguments; + Expression*& callee = node->Is<CallExpression>() + ? node->Cast<CallExpression>()->callee + : node->Cast<NewExpression>()->callee; + switch (r.Index(6)) { + case 0: + case 1: { + size_t at = r.Index(args->size() + 1); + args->insert(args->begin() + static_cast<std::ptrdiff_t>(at), + cg.Value(JsType::kUnknown, 1)); + ctx.detail = "added argument"; + break; + } + case 2: { + if (args->empty()) { + continue; + } + size_t at = r.Index(args->size()); + Expression* old = (*args)[at]; + if (old->Is<SpreadElement>()) { + continue; + } + (*args)[at] = + r.Coin() + ? static_cast<Expression*>(mk::Spread(t, mk::Array(t, {old}))) + : cg.Value(JsType::kUnknown, 1); + ctx.detail = "replaced argument"; + break; + } + case 3: { + Identifier* f = cg.Variable(JsType::kFunction); + if (f == nullptr) { + f = cg.Variable(JsType::kClass); + } + if (f == nullptr) { + continue; + } + if (callee->Is<Identifier>() && + callee->Cast<Identifier>()->name == f->name) { + continue; + } + ctx.detail = "callee -> " + std::string(f->name); + callee = f; + break; + } + case 4: { + // call <-> new + if (node->Is<CallExpression>()) { + if (callee->Is<MemberExpression>() && + callee->Cast<MemberExpression>()->optional) { + continue; + } + if (callee->Is<ChainExpression>() || + callee->Is<ArrowFunctionExpression>()) { + continue; + } + NewExpression* n = mk::New(t, callee, *args); + if (ReplaceAnchored(b, node, n) == nullptr) { + continue; + } + ctx.detail = "call -> new"; + } else { + CallExpression* c = mk::Call(t, callee, *args); + if (ReplaceAnchored(b, node, c) == nullptr) { + continue; + } + ctx.detail = "new -> call"; + } + return true; + } + default: { + if (!node->Is<CallExpression>()) { + continue; + } + // f(args) -> f.call(thisArg, args) / Reflect.apply + std::vector<Expression*> new_args = {cg.ObjectLike()}; + new_args.insert(new_args.end(), args->begin(), args->end()); + CallExpression* c = mk::CallMethod( + t, callee, r.Coin() ? "call" : "bind", std::move(new_args)); + if (ReplaceAnchored(b, node, c) == nullptr) { + continue; + } + ctx.detail = "call -> .call/.bind"; + return true; + } + } + b.Invalidate(); + return true; + } + return false; + } +}; + +// --- Splice mutator +// --------------------------------------------------------------------- + +REDLINE_TUNABLE(kSpliceMinDonorNodes, "mutators.Splice.min_donor_nodes", 2, 1, + 1024, + "fewest AST nodes a donor statement must have to be spliced"); +REDLINE_TUNABLE(kSpliceMaxDonorNodes, "mutators.Splice.max_donor_nodes", 400, 1, + 4096, + "most AST nodes a donor statement may have to be spliced"); +REDLINE_TUNABLE(kSpliceMaxAttempts, "mutators.Splice.max_attempts", 6, 1, 16, + "donor statements the Splice mutator tries before giving up"); +REDLINE_TUNABLE( + kSpliceSlotAttempts, "mutators.Splice.slot_attempts", 8, 1, 16, + "insertion slots drawn to find one compatible with the donor statement"); +REDLINE_TUNABLE(kSpliceAnyTypeRewireChance, + "mutators.Splice.any_type_rewire_chance", 0.5, 0, 1, + "probability of rewiring an external input to a variable of " + "any type when none of its type is visible"); + +// Clones a statement from a donor tree into the destination, renaming the +// donor's own bindings to avoid clashes and rewiring references to +// variables declared outside the donor statement to variables visible at +// the destination (or fresh declarations). +class SpliceMutator final : public Mutator { + public: + // Fuzzilli: SpliceMutator, weight 2, up to 7 simultaneous. + SpliceMutator() + : Mutator( + "Splice", + "copies a statement from another program and rewires its inputs", 2, + true, 7) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + if (ctx.partner == nullptr) { + return false; + } + Random& r = b.rng(); + std::unique_ptr<Tree> donor_tree = ctx.partner->CopyTree(); + Random donor_rng = r.Fork(); + Builder donor(donor_tree.get(), &donor_rng); + std::vector<Node*> candidates = donor.Collect([&](Node* n) { + if (!n->IsStatement()) { + return false; + } + auto* s = n->Cast<Statement>(); + if (IsDirective(s) || s->Is<EmptyStatement>() || + s->Is<BreakStatement>() || s->Is<ContinueStatement>() || + s->Is<ReturnStatement>() || s->Is<DebuggerStatement>()) { + return false; + } + // Loop heads (`for (const e of ...)`) are declarations without + // initializers: not statements on their own. + if (s->Is<VariableDeclaration>()) { + Node* parent = donor.ParentOf(n); + if (parent != nullptr && + (parent->Is<ForStatement>() || parent->Is<ForInStatement>() || + parent->Is<ForOfStatement>())) { + return false; + } + } + // Code using a private name of its class cannot leave it. + if (UsesPrivateNameOfEnclosingClass(n)) { + return false; + } + size_t size = CountNodes(n); + size_t min_nodes = static_cast<size_t>(kSpliceMinDonorNodes.AsInt()); + size_t max_nodes = static_cast<size_t>(kSpliceMaxDonorNodes.AsInt()); + return size >= min_nodes && size <= max_nodes; + }); + if (candidates.empty()) { + return false; + } + for (int attempt = 0; attempt < kSpliceMaxAttempts.AsInt(); attempt++) { + Node* donor_node = candidates[r.Index(candidates.size())]; + Requirements req = AnalyzeRequirements(donor_node); + // Find a compatible insertion slot. + Builder::Slot slot; + bool found = false; + for (int i = 0; i < kSpliceSlotAttempts.AsInt(); i++) { + slot = b.RandomInsertionSlot(); + if (!slot.valid()) { + return false; + } + if (Compatible(req, b.ContextAtSlot(slot))) { + found = true; + break; + } + } + if (!found) { + continue; + } + if (Splice(b, donor, donor_node->Cast<Statement>(), slot, ctx)) { + return true; + } + } + return false; + } + + private: + bool Splice(Builder& b, Builder& donor, Statement* donor_stmt, + const Builder::Slot& slot, MutationContext& ctx) { + Random& r = b.rng(); + Tree* t = b.tree(); + ScopeAnalysis& donor_scopes = donor.scopes(); + // Nodes inside the donor statement. + absl::flat_hash_set<const Node*> inside; + Walk(donor_stmt, [&](Node* n) { + inside.insert(n); + return true; + }); + // Clone and map donor nodes to clone nodes. + Statement* clone = t->Clone(donor_stmt); + absl::flat_hash_map<const Node*, Node*> to_clone; + ParallelWalk(donor_stmt, clone, [&](Node* a, Node* c) { to_clone[a] = c; }); + // Classify bindings touched by the donor. They are collected in the + // order of their first occurrence in the (source-ordered) walk so that + // the renaming below is deterministic for a given seed. + std::vector<Binding*> internal, external; + absl::flat_hash_set<Binding*> seen; + Walk(donor_stmt, [&](Node* n) { + if (auto* id = n->As<Identifier>()) { + Binding* binding = donor_scopes.BindingOf(id); + if (binding == nullptr || !seen.insert(binding).second) { + return true; + } + bool declared_inside = false; + for (Identifier* d : binding->declarations) { + if (inside.count(d)) { + declared_inside = true; + } + } + (declared_inside ? internal : external).push_back(binding); + } + return true; + }); + // Names in the destination and in the donor must not collide with fresh + // names. + b.ReserveNames(donor_scopes.all_names()); + const absl::flat_hash_set<std::string_view>& dest_names = + b.scopes().all_names(); + std::vector<Variable> visible = b.VisibleAtSlot(slot); + auto rename = [&](Binding* binding, std::string_view new_name) { + std::string_view interned = t->Intern(new_name); + for (Identifier* d : binding->declarations) { + auto it = to_clone.find(d); + if (it != to_clone.end()) { + it->second->Cast<Identifier>()->name = interned; + } + } + for (Identifier* ref : binding->references) { + auto it = to_clone.find(ref); + if (it != to_clone.end()) { + it->second->Cast<Identifier>()->name = interned; + } + } + }; + int renamed = 0, rewired = 0, declared = 0; + for (Binding* binding : internal) { + if (dest_names.count(binding->name) || binding->name == "arguments") { + if (binding->name == "arguments") { + continue; + } + rename(binding, b.FreshName(binding->name)); + renamed++; + } + } + std::vector<Statement*> prologue; + for (Binding* binding : external) { + if (binding->name == "arguments") { + continue; + } + JsType type = donor.GuessType(binding); + std::vector<const Variable*> options; + for (const Variable& v : visible) { + if (v.name == "arguments") { + continue; + } + if (binding->assigned && v.is_constant) { + continue; + } + if (type == JsType::kUnknown || v.type == type) { + options.push_back(&v); + } + } + if (options.empty() && r.Chance(kSpliceAnyTypeRewireChance())) { + for (const Variable& v : visible) { + if (v.name == "arguments" || (binding->assigned && v.is_constant)) { + continue; + } + options.push_back(&v); + } + } + if (!options.empty()) { + const Variable& choice = *options[r.Index(options.size())]; + rename(binding, choice.name); + rewired++; + } else { + // Declare a stand-in before the spliced statement. + std::string_view name = dest_names.count(binding->name) + ? b.FreshName(binding->name) + : t->Intern(binding->name); + if (name != binding->name) { + rename(binding, name); + } + GenContext gen = ContextForSlot(b, slot, ctx); + CodeGen cg(gen); + prologue.push_back(mk::Let(t, name, cg.Literal(type))); + declared++; + } + } + prologue.push_back(clone); + b.InsertAll(slot, prologue); + ctx.detail = StringPrintf( + "spliced %s (%zu nodes; %d renamed, %d rewired, %d declared)", + donor_stmt->kind_name(), CountNodes(donor_stmt), renamed, rewired, + declared); + return true; + } +}; + +// --- Combine mutator +// ----------------------------------------------------------------------- + +REDLINE_TUNABLE(kCombineIifeChance, "mutators.Combine.iife_chance", 0.5, 0, 1, + "probability of merging the partner program as an IIFE rather " + "than flat at the top level"); +REDLINE_TUNABLE(kCombineSlotAttempts, "mutators.Combine.slot_attempts", 8, 1, + 16, + "insertion slots drawn to find one whose strictness suits the " + "partner program"); +REDLINE_TUNABLE(kCombineIifeAtEndChance, "mutators.Combine.iife_at_end_chance", + 0.6, 0, 1, + "probability that the IIFE goes at the end of the program " + "rather than at a random slot"); +REDLINE_TUNABLE(kCombineFlatAtEndChance, "mutators.Combine.flat_at_end_chance", + 0.5, 0, 1, + "probability that the flat merge is appended at the end rather " + "than at a random top-level index"); + +class CombineMutator final : public Mutator { + public: + // Fuzzilli: CombineMutator, weight 1, one program per application. + CombineMutator() + : Mutator("Combine", + "merges another whole program in (as an IIFE or flat with " + "renaming)", + 1, true) {} + + bool Mutate(Builder& b, MutationContext& ctx) override { + if (ctx.partner == nullptr) { + return false; + } + Random& r = b.rng(); + std::unique_ptr<Tree> donor_tree = ctx.partner->CopyTree(); + Random donor_rng = r.Fork(); + Builder donor(donor_tree.get(), &donor_rng); + fast::Program* donor_root = donor.root(); + if (donor_root->body.empty()) { + return false; + } + Requirements req = AnalyzeRequirements(donor_root); + Tree* t = b.tree(); + if (r.Chance(kCombineIifeChance())) { + // IIFE: `(function() { <donor> })();` at a random insertion slot. + Builder::Slot slot; + bool found = false; + for (int i = 0; i < kCombineSlotAttempts.AsInt(); i++) { + slot = r.Chance(kCombineIifeAtEndChance()) + ? Builder::Slot{&b.root()->body, b.root()->body.size(), + b.root()} + : b.RandomInsertionSlot(); + if (!slot.valid()) { + return false; + } + Builder::Context c = b.ContextAtSlot(slot); + if (!req.needs_sloppy || !c.strict) { + found = true; + break; + } + } + if (!found) { + return false; + } + std::vector<Statement*> body; + body.reserve(donor_root->body.size()); + for (Statement* s : donor_root->body) { + body.push_back(t->Clone(s)); + } + Expression* fn = mk::Function(t, "", {}, std::move(body)); + b.Insert(slot, mk::ExprStmt(t, mk::Call(t, fn, {}))); + ctx.detail = StringPrintf("combined as IIFE (%zu statements)", + donor_root->body.size()); + return true; + } + // Flat merge into the top level, renaming clashing top-level bindings. + if (req.needs_sloppy && b.root()->strict) { + return false; + } + ScopeAnalysis& donor_scopes = donor.scopes(); + b.ReserveNames(donor_scopes.all_names()); + const absl::flat_hash_set<std::string_view>& dest_names = + b.scopes().all_names(); + int renamed = 0; + std::vector<Binding*> clashing; + for (Binding* binding : donor_scopes.root()->bindings) { + if (dest_names.count(binding->name)) { + clashing.push_back(binding); + } + } + for (Binding* binding : clashing) { + RenameBinding(donor_tree.get(), binding, b.FreshName(binding->name)); + renamed++; + } + std::vector<Statement*> statements; + for (Statement* s : donor_root->body) { + if (IsDirective(s)) { + continue; + } + statements.push_back(t->Clone(s)); + } + if (statements.empty()) { + return false; + } + std::vector<Statement*>& dest = b.root()->body; + size_t first = 0; + while (first < dest.size() && IsDirective(dest[first])) { + first++; + } + size_t index = + r.Chance(kCombineFlatAtEndChance()) + ? dest.size() + : static_cast<size_t>(r.Range(static_cast<int64_t>(first), + static_cast<int64_t>(dest.size()))); + Builder::Slot slot{&dest, index, b.root()}; + b.InsertAll(slot, statements); + ctx.detail = StringPrintf("combined flat (%zu statements, %d renamed)", + statements.size(), renamed); + return true; + } +}; + +} // namespace + +// --- MutatorSet +// ------------------------------------------------------------------------------ + +// static +std::unique_ptr<MutatorSet> MutatorSet::CreateDefault() { + auto set = std::make_unique<MutatorSet>(); + auto add = [&](std::unique_ptr<Mutator> m) { + set->candidates_.push_back(m.get()); + set->mutators_.push_back(std::move(m)); + }; + // Fuzzilli: CodeGenMutator, weight 2, 1-3 insertion points per + // application, each with about five instructions' worth of new code + // (defaultCodeGenerationAmount) = 1-3 generator outputs here. + add(std::make_unique<InsertMutator>("CodeGen", + "inserts freshly generated statements", 2, + std::vector<std::string>{}, false, + /*min_count=*/1, + /*extra_count=*/2, + /*at_top=*/false, + /*max_simultaneous=*/3)); + add(std::make_unique<ExploreMutator>()); + add(std::make_unique<ProbingMutator>()); + // Weight 0: never picked at random; the worker applies it to the parent of + // every mutation chain so that the mutators have fresh values to work with + // (10-15 values, like Fuzzilli's buildPrefix()). Only generators that + // cannot throw: an exception in the prefix would fail every mutant of the + // chain. + add(std::make_unique<InsertMutator>( + "Prefix", + "fresh value declarations at the top of a mutation chain's parent", 0, + std::vector<std::string>{"IntegerDecl", "FloatDecl", "StringDecl", + "BooleanDecl", "BigIntDecl", "RegExpDecl", + "SymbolDecl", "ArrayDecl", "ObjectDecl", + "TypedArrayDecl", "ArrowDecl", "TemplateDecl"}, + false, + /*min_count=*/10, + /*extra_count=*/5, + /*at_top=*/true)); + add(std::make_unique<SpliceMutator>()); + add(std::make_unique<CombineMutator>()); + add(std::make_unique<InputMutator>()); + add(std::make_unique<OperationMutator>()); + add(std::make_unique<ExpressionMutator>()); + add(std::make_unique<CallMutator>()); + add(std::make_unique<RemoveMutator>()); + add(std::make_unique<WrapMutator>()); + add(std::make_unique<DuplicateMutator>()); + add(std::make_unique<ReorderMutator>()); + // No Fuzzilli counterpart as a mutator (Fuzzilli reaches the JIT through + // its code generators, which CodeGen also has): weight 0 by default. + add(std::make_unique<InsertMutator>( + "JitStress", + "inserts JIT tiering/deopt/GC idioms around existing functions", 0, + std::vector<std::string>{"JitOptimize", "JitBaseline", "Deopt", "OsrLoop", + "NativeCall", "Gc", "ElementsKind", + "ShapeChange"}, + true)); + std::string error; + if (!set->SetSelector( + std::make_unique<WeightedSelector<Mutator>>( + "mutator", std::vector<std::pair<std::string, double>>{}), + &error)) { + REDLINE_ERROR("mutators", "default mutator strategy: %s", error.c_str()); + return nullptr; + } + return set; +} + +bool MutatorSet::ConfigurePrefix(int min_values, int extra_values) { + Mutator* prefix = Find("Prefix"); + return prefix != nullptr && prefix->SetInsertCounts(min_values, extra_values); +} + +bool MutatorSet::SetSelector(std::unique_ptr<Selector<Mutator>> selector, + std::string* error) { + if (!selector->Initialize(candidates_, error)) { + return false; + } + selector_ = std::move(selector); + return true; +} + +Mutator* MutatorSet::Find(std::string_view name) const { + for (const auto& m : mutators_) { + if (m->name() == name) { + return m.get(); + } + } + return nullptr; +} + +std::vector<std::string> MutatorSet::Names() const { + std::vector<std::string> names; + names.reserve(mutators_.size()); + for (const auto& m : mutators_) { + names.push_back(m->name()); + } + return names; +} + +Mutator* MutatorSet::Pick(Random& rng, bool has_partner) const { + size_t index = + selector_->Pick(candidates_, rng, [has_partner](const Mutator& m) { + return has_partner || !m.needs_partner(); + }); + return index == Selector<Mutator>::kNoChoice ? nullptr : candidates_[index]; +} + +// --- selection strategies for mutators ------------------------------------- +// +// To add one: derive from Selector<Mutator>, then add a Register() line +// below. Parameters are declared in the Entry so that the configuration is +// validated before the fuzzer starts. + +template <> +void RegisterBuiltinSelectors<Mutator>(SelectorRegistry<Mutator>& registry) { + registry.Register({std::string(WeightedSelector<Mutator>::kName), + "one weighted random draw among the eligible mutators", + WeightedSelector<Mutator>::Specs(), + [](const JsonValue& params, std::string* error) + -> std::unique_ptr<Selector<Mutator>> { + std::vector<std::pair<std::string, double>> overrides; + if (!ReadWeightOverrides(params, &overrides, error)) { + return nullptr; + } + // Names are checked against the mutators in + // Initialize(). + return std::make_unique<WeightedSelector<Mutator>>( + "mutator", std::move(overrides)); + }}); + registry.SetDefault(WeightedSelector<Mutator>::kName); + registry.Register({std::string(AdaptiveSelector<Mutator>::kName), + "weighted draw whose weights follow each mutator's recent " + "yield (new corpus programs per execution)", + AdaptiveSelector<Mutator>::Specs(), + [](const JsonValue& params, std::string* error) + -> std::unique_ptr<Selector<Mutator>> { + std::vector<std::pair<std::string, double>> overrides; + if (!ReadWeightOverrides(params, &overrides, error)) { + return nullptr; + } + AdaptiveSelector<Mutator>::Settings p = + AdaptiveSelector<Mutator>::ReadParams(params); + if (!AdaptiveSelector<Mutator>::Validate(p, error)) { + return nullptr; + } + return std::make_unique<AdaptiveSelector<Mutator>>( + "mutator", std::move(overrides), p); + }}); +} + +std::vector<const Component*> MutatorSet::Components() const { + std::vector<const Component*> components; + components.reserve(mutators_.size()); + for (const auto& m : mutators_) { + components.push_back(m.get()); + } + return components; +} + +MutationContext::MutationContext() = default; +MutationContext::~MutationContext() = default; + +std::unique_ptr<fast::Tree> ApplyMutation( + Mutator& mutator, const redline::Program& parent, const ProgramPtr& partner, + Random& rng, const Environment& env, const GeneratorSet& generators, + int rounds, std::string* detail, std::vector<ExploreProbe>* probes) { + std::unique_ptr<Tree> tree = parent.CopyTree(); + Builder builder(tree.get(), &rng); + MutationContext ctx; + ctx.partner = partner; + ctx.env = &env; + ctx.generators = &generators; + int applied = 0; + std::string all; + // Runtime-assisted mutators instrument once; their probes are completed + // by the worker. + if (mutator.runtime_assisted()) { + rounds = 1; + } + for (int i = 0; i < rounds; i++) { + ctx.detail.clear(); + mutator.stats().invocations++; + if (mutator.Mutate(builder, ctx)) { + applied++; + if (!all.empty()) { + all += "; "; + } + all += ctx.detail; + } + } + if (applied == 0) { + return nullptr; + } + mutator.stats().produced++; + if (detail != nullptr) { + *detail = all; + } + if (probes != nullptr) { + *probes = std::move(ctx.probes); + } + return tree; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/mutators/probing.cc b/deps/v8/experimental/redline/mutators/probing.cc new file mode 100644 index 000000000000..4d01cad8f721 --- /dev/null +++ b/deps/v8/experimental/redline/mutators/probing.cc @@ -0,0 +1,384 @@ +// Copyright 2026 the V8 project 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 "experimental/redline/mutators/probing.h" + +#include <algorithm> +#include <map> +#include <set> + +#include "experimental/redline/base/json_parser.h" +#include "experimental/redline/base/log.h" +#include "experimental/redline/core/ast_builder.h" +#include "experimental/redline/core/tunable.h" +#include "experimental/redline/generators/codegen.h" + +namespace redline { + +using namespace fast; // NOLINT(build/namespaces) + +namespace { + +// Reports each missing property an object is asked for, once, as +// "PROBE_HIT: {"id": ..., "kind": "get"|"set", "key": ...}". Well-known +// symbols are reported by their description ("Symbol.toPrimitive"). +constexpr char kProbeRuntime[] = R"js(const __redline_probe = (function() { + const ReflectGet = Reflect.get; + const ReflectSet = Reflect.set; + const ReflectHas = Reflect.has; + const ObjectGetPrototypeOf = Object.getPrototypeOf; + const ObjectSetPrototypeOf = Object.setPrototypeOf; + const ProxyConstructor = Proxy; + const JSONStringify = JSON.stringify; + const emit = typeof fuzzilli === 'function' ? function(s) { fuzzilli('FUZZILLI_PRINT', s); } + : function(s) {}; + const seen = {__proto__: null}; + let reporting = false; + function record(id, kind, target, key) { + if (reporting) return; + reporting = true; + try { + if (ReflectHas(target, key)) return; + let name = key; + if (typeof key === 'symbol') { + const d = key.description; + if (typeof d !== 'string' || d.length < 8 || d.substring(0, 7) !== 'Symbol.') return; + name = d; + } else if (typeof key !== 'string' || key.length === 0 || key.length > 40) { + return; + } + const token = id + '|' + kind + '|' + name; + if (seen[token]) return; + seen[token] = true; + emit('PROBE_HIT: ' + JSONStringify({id: id, kind: kind, key: name})); + } catch (e) { + } finally { + reporting = false; + } + } + function probe(id, v) { + if (v === null || (typeof v !== 'object' && typeof v !== 'function')) return; + let proto, newProto; + const handler = { + get(target, key, receiver) { + if (key === '__proto__' && receiver === v) return proto; + if (receiver === newProto) return ReflectGet(target, key); + record(id, 'get', target, key); + return ReflectGet(target, key, receiver); + }, + set(target, key, value, receiver) { + if (receiver === newProto) return ReflectSet(target, key, value); + record(id, 'set', target, key); + return ReflectSet(target, key, value, receiver); + }, + has(target, key) { + record(id, 'get', target, key); + return ReflectHas(target, key); + }, + }; + try { + proto = ObjectGetPrototypeOf(v); + newProto = new ProxyConstructor(proto === null ? {__proto__: null} : proto, handler); + ObjectSetPrototypeOf(v, newProto); + } catch (e) {} + } + return probe; +})(); +try { %NeverOptimizeFunction(__redline_probe); } catch (e) {} +)js"; + +bool ProbeWorthy(const Variable& v) { + switch (v.type) { + case JsType::kNumber: + case JsType::kString: + case JsType::kBoolean: + case JsType::kBigInt: + case JsType::kSymbol: + case JsType::kNullish: + return false; + default: + return v.name != "arguments" && v.name != "undefined"; + } +} + +struct Hit { + std::string kind; // "get" or "set" + std::string key; +}; + +// `v.key = value`, `v["key"] = value`, or `v[Symbol.name] = value`. +Expression* Target(Tree* t, std::string_view variable, const std::string& key) { + Expression* object = mk::Id(t, variable); + if (key.starts_with("Symbol.")) { + return mk::Index(t, object, + mk::Member(t, mk::Id(t, "Symbol"), key.substr(7))); + } + if (IsIdentifierName(key)) { + return mk::Member(t, object, key); + } + return mk::Index(t, object, mk::Str(t, key)); +} + +Expression* KeyExpression(Tree* t, const std::string& key) { + if (key.starts_with("Symbol.")) { + return mk::Member(t, mk::Id(t, "Symbol"), key.substr(7)); + } + return mk::Str(t, key); +} + +// A function suitable as the value of a well-known symbol property. +Expression* SymbolHook(CodeGen& cg, Tree* t, const std::string& key) { + std::vector<Statement*> body; + if (key == "Symbol.iterator" || key == "Symbol.asyncIterator") { + // function*() { yield <value>; yield <value>; } + body.push_back( + mk::ExprStmt(t, mk::Yield(t, cg.Value(JsType::kUnknown, 1)))); + body.push_back( + mk::ExprStmt(t, mk::Yield(t, cg.Value(JsType::kUnknown, 1)))); + return mk::Function(t, "", {}, std::move(body), + key == "Symbol.asyncIterator", + /*is_generator=*/true); + } + if (key == "Symbol.hasInstance") { + body.push_back(mk::Return(t, cg.Boolean())); + return mk::Function(t, "", {"v"}, std::move(body)); + } + if (key == "Symbol.species") { + return cg.Callable(); + } + if (key == "Symbol.toStringTag") { + return cg.String(); + } + if (key == "Symbol.isConcatSpreadable") { + return cg.Boolean(); + } + // Symbol.toPrimitive and the string/regexp hooks: a function returning a + // value. + body.push_back(mk::Return(t, cg.Value(JsType::kUnknown, 1))); + return mk::Function(t, "", {"hint"}, std::move(body)); +} + +} // namespace + +ProbingMutator::ProbingMutator() + : RuntimeAssistedMutator("Probing", + "finds which missing properties a program asks an " + "object for and installs them", + 2, false) {} + +std::string_view ProbingMutator::runtime() const { return kProbeRuntime; } + +REDLINE_TUNABLE(kProbingMaxProbes, "mutators.Probing.max_probes", 3, 1, 16, + "most variables probed per application"); +REDLINE_TUNABLE(kProbingAttemptsPerProbe, "mutators.Probing.attempts_per_probe", + 4, 1, 16, "slot draws per wanted probe before giving up"); +REDLINE_TUNABLE(kProbingUnreferencedCandidateChance, + "mutators.Probing.unreferenced_candidate_chance", 0.1, 0, 1, + "probability that a variable the program never references is " + "still a probe candidate"); + +bool ProbingMutator::Mutate(Builder& b, MutationContext& ctx) { + Random& r = b.rng(); + ctx.probes.clear(); + std::vector<Builder::Slot> slots = b.InsertionSlots(); + if (slots.empty()) { + return false; + } + // A probe only learns something if the program goes on to use the + // object: weight candidates by how often they are referenced. + std::map<std::string_view, int> references; + { + ScopeAnalysis& scopes = b.scopes(); + for (Node* n : b.Collect([&](Node* n) { + auto* id = n->As<Identifier>(); + return id != nullptr && scopes.IsReference(id); + })) { + references[n->Cast<Identifier>()->name]++; + } + } + int wanted = 1 + r.SmallCount(kProbingMaxProbes.AsInt() - 1); + std::vector<std::pair<Builder::Slot, Statement*>> insertions; + std::vector<std::string> probed; + for (int attempt = 0; attempt < kProbingAttemptsPerProbe.AsInt() * wanted && + static_cast<int>(ctx.probes.size()) < wanted; + attempt++) { + const Builder::Slot& slot = slots[r.Index(slots.size())]; + Builder::Context syntax = b.ContextAtSlot(slot); + if (syntax.in_class_field) { + continue; + } + std::vector<Variable> visible = b.VisibleAtSlot(slot); + std::vector<const Variable*> candidates; + std::vector<double> weights; + for (const Variable& v : visible) { + if (!ProbeWorthy(v)) { + continue; + } + if (std::find(probed.begin(), probed.end(), std::string(v.name)) != + probed.end()) { + continue; + } + auto it = references.find(v.name); + int uses = it == references.end() ? 0 : it->second; + if (uses == 0 && !r.Chance(kProbingUnreferencedCandidateChance())) { + continue; + } + candidates.push_back(&v); + weights.push_back(1.0 + uses); + } + if (candidates.empty()) { + continue; + } + const Variable& target = *candidates[r.Weighted(weights)]; + ExploreProbe probe; + probe.id = StringPrintf("p%u", static_cast<unsigned>(r.Next() % 100000)); + probe.variable = std::string(target.name); + insertions.emplace_back(slot, + MakeProbe(b.tree(), kProbeFunction, probe, {})); + probed.push_back(probe.variable); + ctx.probes.push_back(std::move(probe)); + } + if (ctx.probes.empty()) { + return false; + } + std::stable_sort(insertions.begin(), insertions.end(), + [](const auto& x, const auto& y) { + return x.first.index > y.first.index; + }); + for (auto& [slot, statement] : insertions) { + b.Insert(slot, statement); + } + ctx.detail = "probing"; + for (const ExploreProbe& p : ctx.probes) { + ctx.detail += " " + p.variable; + } + return true; +} + +REDLINE_TUNABLE(kProbingSecondInstallChance, + "mutators.Probing.second_install_chance", 0.4, 0, 1, + "probability of installing a second missing property when " + "several were asked for"); +REDLINE_TUNABLE(kProbingAccessorChance, "mutators.Probing.accessor_chance", + 0.35, 0, 1, + "probability of installing a missing property as a " + "getter/setter rather than a plain value"); + +int ProbingMutator::Apply(Builder& b, const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, MutationContext& ctx, + std::string* detail) { + std::map<std::string, std::vector<Hit>> hits; + size_t start = 0; + while (start < fuzzout.size()) { + size_t nl = fuzzout.find('\n', start); + if (nl == std::string::npos) { + nl = fuzzout.size(); + } + std::string_view line(fuzzout.data() + start, nl - start); + start = nl + 1; + constexpr std::string_view kHit = "PROBE_HIT: "; + if (!line.starts_with(kHit)) { + continue; + } + JsonValue json; + std::string error; + if (!JsonValue::Parse(line.substr(kHit.size()), &json, &error)) { + continue; + } + if (!json.is_object()) { + continue; + } + std::string id = json.GetString("id", ""); + Hit hit{json.GetString("kind", "get"), json.GetString("key", "")}; + if (id.empty() || hit.key.empty()) { + continue; + } + hits[id].push_back(std::move(hit)); + } + Random& r = b.rng(); + Tree* t = b.tree(); + int applied = 0; + std::string description; + for (const ExploreProbe& probe : probes) { + Statement* statement = FindProbe(b, kProbeFunction, probe.id); + if (statement == nullptr) { + continue; + } + Builder::Slot slot = b.SlotOf(statement); + if (!slot.valid()) { + continue; + } + std::vector<Statement*> replacement; + auto it = hits.find(probe.id); + if (it != hits.end() && !it->second.empty()) { + GenContext gen = MakeGenContext(b, slot, *ctx.generators, *ctx.env); + CodeGen cg(gen); + std::vector<Hit>& found = it->second; + int install = + 1 + + (found.size() > 1 && r.Chance(kProbingSecondInstallChance()) ? 1 : 0); + std::set<std::string> done; + for (int i = 0; i < install; i++) { + const Hit& hit = found[r.Index(found.size())]; + if (!done.insert(hit.key).second) { + continue; + } + if (hit.key.starts_with("Symbol.")) { + replacement.push_back( + mk::ExprStmt(t, mk::Assign(t, Target(t, probe.variable, hit.key), + SymbolHook(cg, t, hit.key)))); + } else if (r.Chance(kProbingAccessorChance())) { + // Object.defineProperty(v, "key", {get() {...}, set(x) {...}, + // configurable: true}) + std::vector<Statement*> getter_body = { + mk::Return(t, cg.Value(JsType::kUnknown, 1))}; + std::vector<Node*> descriptor; + descriptor.push_back(mk::Method( + t, "get", mk::Function(t, "", {}, std::move(getter_body)))); + if (hit.kind == "set" || r.Coin()) { + std::string_view param = b.FreshName("x"); + std::vector<Statement*> setter_body; + Expression* sink = cg.Target(); + if (sink != nullptr) { + setter_body.push_back( + mk::ExprStmt(t, mk::Assign(t, sink, mk::Id(t, param)))); + } + descriptor.push_back(mk::Method( + t, "set", + mk::Function(t, "", {param}, std::move(setter_body)))); + } + descriptor.push_back(mk::Prop(t, "configurable", mk::Bool(t, true))); + descriptor.push_back( + mk::Prop(t, "enumerable", mk::Bool(t, r.Coin()))); + replacement.push_back(mk::ExprStmt( + t, mk::CallMethod( + t, mk::Id(t, "Object"), "defineProperty", + {mk::Id(t, probe.variable), KeyExpression(t, hit.key), + mk::Object(t, std::move(descriptor))}))); + } else { + replacement.push_back( + mk::ExprStmt(t, mk::Assign(t, Target(t, probe.variable, hit.key), + cg.Value(JsType::kUnknown, 1)))); + } + if (!description.empty()) { + description += "; "; + } + description += probe.variable + " " + hit.kind + " " + hit.key; + } + if (!replacement.empty()) { + applied++; + } + } + b.Remove(slot); + if (!replacement.empty()) { + b.InsertAll(slot, replacement); + } + } + if (detail != nullptr) { + *detail = "installed " + description; + } + return applied; +} + +} // namespace redline diff --git a/deps/v8/experimental/redline/mutators/probing.h b/deps/v8/experimental/redline/mutators/probing.h new file mode 100644 index 000000000000..55e1e4177184 --- /dev/null +++ b/deps/v8/experimental/redline/mutators/probing.h @@ -0,0 +1,52 @@ +// Copyright 2026 the V8 project 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 V8_EXPERIMENTAL_REDLINE_MUTATORS_PROBING_H_ +#define V8_EXPERIMENTAL_REDLINE_MUTATORS_PROBING_H_ + +#include <string> +#include <string_view> +#include <vector> + +#include "experimental/redline/mutators/explore.h" + +namespace redline { + +// The runtime-assisted "Probing" mutator, after Fuzzilli's ProbingMutator. +// +// Where Explore asks "what can be done with this value", Probing asks "what +// does the program try to do with it that does not exist yet": +// +// 1. Mutate(): turns a few object-valued variables into probes with +// `__redline_probe("pN", v)`: the probe swaps the object's prototype for +// a Proxy around the original one, which sees every load, store and +// `in` test of a property the object does not have. +// 2. The worker executes the instrumented program with kProbeRuntime +// prepended; each distinct missing property is reported once as +// "PROBE_HIT: {"id","kind","key"}" on fuzzout (string keys and +// well-known symbols only). +// 3. ApplyProbeActions() replaces each probe by code that installs one or +// two of the reported properties on the object: a plain value, an +// accessor pair via Object.defineProperty, or a well-known-symbol +// method (Symbol.toPrimitive, Symbol.iterator, ...). Probes without +// hits are removed. +// +// Installing exactly the properties the program looks for exercises the +// engine's property lookup, IC and prototype-chain machinery along paths +// that generated code rarely reaches by accident. +class ProbingMutator final : public RuntimeAssistedMutator { + public: + ProbingMutator(); + bool Mutate(Builder& builder, MutationContext& ctx) override; + std::string_view runtime() const override; + int Apply(Builder& builder, const std::vector<ExploreProbe>& probes, + const std::string& fuzzout, MutationContext& ctx, + std::string* detail) override; + + static constexpr std::string_view kProbeFunction = "__redline_probe"; +}; + +} // namespace redline + +#endif // V8_EXPERIMENTAL_REDLINE_MUTATORS_PROBING_H_ diff --git a/deps/v8/experimental/redline/presets/.gitignore b/deps/v8/experimental/redline/presets/.gitignore new file mode 100644 index 000000000000..5b49168d10d5 --- /dev/null +++ b/deps/v8/experimental/redline/presets/.gitignore @@ -0,0 +1,4 @@ +# The root .gitignore ignores maglev*.json and turbo*.json (trace files). +# These two are presets, not traces. +!maglev.json +!turbolev.json diff --git a/deps/v8/experimental/redline/presets/builtins.json b/deps/v8/experimental/redline/presets/builtins.json new file mode 100644 index 000000000000..a4031b6bbf32 --- /dev/null +++ b/deps/v8/experimental/redline/presets/builtins.json @@ -0,0 +1,6 @@ +{ + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "DiscoveredApi": 12, "BuiltinCall": 8, "PrototypeMethodCall": 4, "UnboundMethodCall": 4, + "StringOps": 4, "TypedArrayOps": 4, "MapSetOps": 3, "WorkerSpawn": 2}}}} +} diff --git a/deps/v8/experimental/redline/presets/default.json b/deps/v8/experimental/redline/presets/default.json new file mode 100644 index 000000000000..6573f8a49c33 --- /dev/null +++ b/deps/v8/experimental/redline/presets/default.json @@ -0,0 +1,3 @@ +{ + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, "generators": {"strategy": "adaptive"}} +} diff --git a/deps/v8/experimental/redline/presets/maglev.json b/deps/v8/experimental/redline/presets/maglev.json new file mode 100644 index 000000000000..aeb32df6c6ce --- /dev/null +++ b/deps/v8/experimental/redline/presets/maglev.json @@ -0,0 +1,6 @@ +{ + "d8_extra_args": ["--maglev", "--no-turbofan", "--jit-fuzzing"], + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "JitOptimize": 8, "Deopt": 3, "OsrLoop": 3, "ElementsKind": 4, "ShapeChange": 3}}}} +} diff --git a/deps/v8/experimental/redline/presets/parser.json b/deps/v8/experimental/redline/presets/parser.json new file mode 100644 index 000000000000..d4e8d0f96e66 --- /dev/null +++ b/deps/v8/experimental/redline/presets/parser.json @@ -0,0 +1,7 @@ +{ + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, + "mutators": {"strategy": "adaptive", "params": {"weights": {"Splice": 4, "Combine": 2}}}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "ClassDecl": 5, "Destructuring": 4, "ArrowDecl": 4, "TemplateDecl": 3, "LabeledBlock": 2, + "UsingDecl": 2, "AwaitUsingDecl": 2, "Eval": 2, "With": 1}}}} +} diff --git a/deps/v8/experimental/redline/presets/runtime.json b/deps/v8/experimental/redline/presets/runtime.json new file mode 100644 index 000000000000..9fa8ed14280b --- /dev/null +++ b/deps/v8/experimental/redline/presets/runtime.json @@ -0,0 +1,8 @@ +{ + "d8_extra_args": ["--no-turbofan", "--no-maglev", "--no-sparkplug"], + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "JitOptimize": 0, "JitBaseline": 0, "Deopt": 0, "OsrLoop": 0, + "PropertyStore": 6, "DefineProperty": 4, "ShapeChange": 4, "PrototypeSet": 3, "ProxyDecl": 3, + "FreezeSeal": 2}}}} +} diff --git a/deps/v8/experimental/redline/presets/turbolev.json b/deps/v8/experimental/redline/presets/turbolev.json new file mode 100644 index 000000000000..51e63ea63b95 --- /dev/null +++ b/deps/v8/experimental/redline/presets/turbolev.json @@ -0,0 +1,6 @@ +{ + "d8_extra_args": ["--turbolev", "--turbolev-future", "--jit-fuzzing"], + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "JitOptimize": 8, "Deopt": 3, "OsrLoop": 3, "ElementsKind": 4, "ShapeChange": 3}}}} +} diff --git a/deps/v8/experimental/redline/presets/wasm.json b/deps/v8/experimental/redline/presets/wasm.json new file mode 100644 index 000000000000..41afaa51c014 --- /dev/null +++ b/deps/v8/experimental/redline/presets/wasm.json @@ -0,0 +1,5 @@ +{ + "selection": {"seeds": {"strategy": "rarity"}, "partners": {"strategy": "rarity-partner"}, "mutators": {"strategy": "adaptive"}, + "generators": {"strategy": "adaptive", "params": {"weights": { + "WasmModule": 6, "JitOptimize": 6, "OsrLoop": 2, "TypedArrayOps": 3}}}} +} diff --git a/deps/v8/experimental/redline/skills/redline-presubmit/SKILL.md b/deps/v8/experimental/redline/skills/redline-presubmit/SKILL.md new file mode 100644 index 000000000000..edee2afb3bb0 --- /dev/null +++ b/deps/v8/experimental/redline/skills/redline-presubmit/SKILL.md @@ -0,0 +1,148 @@ +--- +name: redline-presubmit +description: Runs and reports the checks that a change to experimental/redline must pass before upload. The checks cover formatting, lint, the build, the selftests, the parser round trip and the golden traces. They also cover the Markdown links, the ASD-STE100 language of the text, changed generators and mutators, and a before/after fuzzing comparison. Use it before you upload, or approve, a CL that changes experimental/redline. Do not use it for changes outside experimental/redline. +--- + +# Redline presubmit + +Use this skill before you upload a change to `experimental/redline/`. It turns +the checklist of [CONTRIBUTE.md](../../CONTRIBUTE.md) section 11 into commands, +and it gives a report for the CL description. + +Run all commands from the root of the V8 checkout, with depot_tools in your +`PATH`. The scripts are in `experimental/redline/skills/redline-presubmit/scripts/`. + +## 1. Prepare + +1. Build the fuzzing d8 in `out/fuzzbuild` and Redline in `out/redline`. + [TUTORIAL.md](../../TUTORIAL.md) sections 1 and 2 give the commands. +2. Commit your change. The scripts compare `HEAD` with a base revision. By + default, the base revision is the merge base with the upstream branch. + +## 2. Run the standard checks + +```shell +experimental/redline/skills/redline-presubmit/scripts/check.sh +``` + +The script prints one line for each check: + +| Check | Pass criterion | +|---|---| +| `git cl format` | No file needs formatting. | +| `git cl lint` | 0 errors. | +| build | `autoninja -C out/redline redline` succeeds. `BUILD.gn` makes every warning an error. | +| `selftest --offline` | All checks pass. | +| `selftest --d8` | All checks pass against `out/fuzzbuild/d8`. | +| `roundtrip --no-run` | 0 real failures on `test/mjsunit`. | +| golden traces | Information only: the number of changed files in `testdata/`. | +| Markdown links | `tools/dev/markdown_checker.py` accepts the changed Markdown files. | +| STE language | See step 4. | + +The options are `--out=DIR`, `--d8=PATH` and `--base=REV`. A FAIL line gives +the cause or the path of its log. Fix every FAIL before you continue. + +## 3. Check what your change touches + +| You changed | Do this | Pass criterion | +|---|---|---| +| The golden traces in `testdata/` | Make sure that you want the new output. Then run `out/redline/redline selftest --offline --write-golden` and examine `git diff experimental/redline/testdata/`. | The CL description tells why the traces changed. | +| `fast/`: lexer, parser, printer or scopes | `check.sh` runs `roundtrip --no-run`. For a change to the printer or to the scope analysis, also run the round trip with execution, at `HEAD` and at the base revision: `out/redline/redline roundtrip --dir=test/mjsunit --d8=out/fuzzbuild/d8`. | No new failure. This run reports known behavior differences as failures, so compare the two failure lists. | +| A generator | `out/redline/redline mutate --generate --generator=NAME --n=500 --run --d8=out/fuzzbuild/d8 --quiet` (CONTRIBUTE.md sections 3.4 and 3.5). If you have a d8 with known bugs, also run the audit of section 3.7. | The summary line shows at least 99.8% V8-accepted. In the audit, no crash signature takes more than 0.5% of the programs. | +| A mutator | `out/redline/redline mutate --mutator=NAME --n=50 --run --d8=out/fuzzbuild/d8 --quiet FILE...` with some `test/mjsunit` files (CONTRIBUTE.md section 4.4). | The summary line shows at least 99.8% V8-accepted. | +| What a session does: generators, mutators, selection strategies, presets, `engine/`, `exec/` or `corpus/` | Step 5. | See step 5. | + +## 4. Check the language + +Write the text of a change in ASD-STE100 Simplified Technical English. This +includes the Markdown files, the commit message and the code comments. Run the +linter on the text of your change: + +```shell +experimental/redline/skills/redline-presubmit/scripts/ste_check.py +``` + +| Text | Pass criterion | +|---|---| +| A Markdown file that the change adds or edits | No more hard findings than at the base revision. | +| The commit message of `HEAD` | No hard finding. | +| The comments that the change adds to C++, Python, shell and GN files | No hard finding. | + +Advisory findings, for example passive voice, do not make the check fail. Use +`--verbose` to see them, and fix them if the text stays clear. + +The linter is `ste_lint.py` in google3, so you need access to `/google/src`. +`ste_check.py` runs it with `vpython3` and +[scripts/ste_lint.vpython3](scripts/ste_lint.vpython3), which supplies +absl-py. Set `STE_LINT` to use another copy of the linter. To lint one more +file, for example a draft of a commit message: + +```shell +vpython3 -vpython-spec experimental/redline/skills/redline-presubmit/scripts/ste_lint.vpython3 \ + /google/src/files/head/depot/google3/learning/gemini/agents/skills/communication/asd_ste100/ste_lint.py FILE +``` + +If you cannot use the linter, apply the main rules yourself: one instruction +in each sentence, at most 20 words in an instruction and 25 words in a +description, active voice, and the imperative in instructions. + +## 5. Compare fuzzing before and after + +Do this step if your change can change what a session does: + +```shell +experimental/redline/skills/redline-presubmit/scripts/ab_run.sh --base=REV +``` + +REV is the revision before your change, for example `HEAD~1`. + +- The script builds Redline at REV and at `HEAD` in `out/redline`. It copies + each binary, with its presets and test data, to a work directory in `/tmp`. +- It runs the two sessions at the same time for one hour, with the flags of + CONTRIBUTE.md section 10.1: `--preset=default`, 8 workers each, seed 42, and + `--single-threaded --random-seed=42` for d8. +- It prints the coverage of both sessions every 5 minutes, and a summary. +- It checks out REV while it builds, so commit your change first. It then + restores your branch. +- The two sessions start 16 d8 processes. On a workstation with fewer than 24 + cores, use `--jobs=4`. + +The options are `--duration=SEC`, `--jobs=N`, `--work=DIR`, `--out=DIR` and +`--d8=PATH`. Flags after `--` go to both sessions. + +Read the result as CONTRIBUTE.md section 10.2 tells: + +- Two identical sessions differ by 0.25 to 0.35 percentage points. A + difference below 0.5 points is probably noise. +- Compare at the same elapsed time first. Then compare the executions: a + slower change must pay for its time. +- One run is weak evidence. If the difference is important, repeat the run. +- Compare the crash signatures. Explain each new signature. + +## 6. Write the report + +Add the results to the CL description, after the description of the change. +The commit message must also pass the STE check, so do not use semicolons: + +```text +Tested: + check.sh: all checks pass. The golden traces did not change. + Generator <NAME>: 500 programs, <P>% V8-accepted. + ab_run.sh --base=HEAD~1, 1 h, 8 workers each: coverage <A>% -> <B>% + (<D> pp, probably noise), executions <R>x, no new crash signature. +``` + +If a check does not apply, write why. If you did not do a check, write that. +After the upload, start a CQ dry run: the presubmit bots also check the +formatting and the Markdown links. + +## Known problems + +- `tools/dev/markdown_checker.py` does not skip code blocks. It reads text in + square brackets followed by text in parentheses as a link, also inside a + code block. A C++ lambda with an empty capture list causes this. Write the + example code in a different way. +- `ab_run.sh` stops if tracked files have changes, because it must check out + the base revision. Commit or stash your changes first. +- `ste_check.py` exits with status 3 and `check.sh` shows SKIP if the linter is + not available. diff --git a/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_compare.py b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_compare.py new file mode 100755 index 000000000000..d4bcda8cf0d7 --- /dev/null +++ b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_compare.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Compares two Redline fuzzing sessions at the same elapsed time. + +Usage: ab_compare.py BASE_EVENTS AFTER_EVENTS [--every=MINUTES] + +BASE_EVENTS and AFTER_EVENTS are the events.jsonl files of the two sessions. +The script reads their "stats" events, prints the coverage and the number of +executions of both sessions minute by minute, and then a summary. +CONTRIBUTE.md section 10.2 tells how to read the result. +""" + +import argparse +import json +import sys + +NOISE_PP = 0.5 # Two identical sessions differ by 0.25 to 0.35 points. + + +def load(path): + """Returns the stats events of a session, by elapsed minute.""" + stats = {} + with open(path, errors='replace') as f: + for line in f: + try: + event = json.loads(line) + except json.JSONDecodeError: + continue # An interrupted session can end with an incomplete line. + if event.get('event') == 'stats': + stats[round(event['t'] / 60)] = event + return stats + + +def pp(fraction): + return 100 * fraction + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.split('\n')[0]) + parser.add_argument('base_events') + parser.add_argument('after_events') + parser.add_argument( + '--every', + type=int, + default=5, + help='print one row every this many minutes (default 5)') + args = parser.parse_args() + base, after = load(args.base_events), load(args.after_events) + minutes = sorted(set(base) & set(after)) + if not minutes: + sys.exit('The two sessions have no stats event at the same minute.') + + print(' min base cov after cov diff (pp) base execs after execs') + for minute in minutes: + if minute % args.every and minute != minutes[-1]: + continue + a, b = base[minute], after[minute] + print( + f'{minute:4d} {pp(a["coverage"]):7.3f}% {pp(b["coverage"]):7.3f}%' + f' {pp(b["coverage"] - a["coverage"]):+8.3f} {a["executions"]:10d}' + f' {b["executions"]:10d}') + + last = minutes[-1] + a, b = base[last], after[last] + diff = pp(b['coverage'] - a['coverage']) + ahead = sum(1 for m in minutes if after[m]['coverage'] > base[m]['coverage']) + print() + print(f'At {last} min: coverage {pp(a["coverage"]):.3f}% -> ' + f'{pp(b["coverage"]):.3f}% ({diff:+.3f} pp), executions ' + f'{a["executions"]} -> {b["executions"]} ' + f'({b["executions"] / max(a["executions"], 1):.2f}x)') + print(f'The after session had more coverage in {ahead} of {len(minutes)} ' + 'minutes.') + for key in ('corpus', 'crash_signatures', 'unique_crashes', 'timed_out', + 'flaky', 'infrastructure_failures'): + print(f' {key}: {a.get(key, "?")} -> {b.get(key, "?")}') + if abs(diff) < NOISE_PP: + print(f'The difference is below {NOISE_PP} points: it is probably noise.') + else: + print(f'The difference is {diff:+.3f} points. Repeat the run before you ' + 'trust it.') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_run.sh b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_run.sh new file mode 100755 index 000000000000..c3baf920d4b1 --- /dev/null +++ b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ab_run.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Compares fuzzing before and after a change (CONTRIBUTE.md section 10). +# The script builds Redline at the base revision and at HEAD. It copies each +# binary with its data into a work directory. Then it runs the two sessions at +# the same time, with the same d8, flags and seed, and compares their coverage. +# +# Run it from the root of the V8 checkout. Commit your change first: the +# script checks out the base revision for some time, and it refuses to start +# if tracked files have changes. +# +# Usage: ab_run.sh --base=REV [--duration=SEC] [--jobs=N] [--work=DIR] +# [--out=DIR] [--d8=PATH] [-- FUZZ_FLAG...] +# --base=REV the revision before the change (required) +# --duration=SEC the length of each session (default: 3600) +# --jobs=N the workers of each session (default: 8) +# --work=DIR the work directory (default: a new /tmp/redline-ab.*) +# --out=DIR the Redline build directory (default: out/redline) +# --d8=PATH the fuzzing build of d8 (default: out/fuzzbuild/d8) +# FUZZ_FLAG more flags for both sessions, for example --preset=maglev + +set -u +BASE="" +DURATION=3600 +JOBS=8 +WORK="${AB_WORK:-}" +OUT=out/redline +D8=out/fuzzbuild/d8 +EXTRA=() +while [ $# -gt 0 ]; do + case "$1" in + --base=*) BASE="${1#--base=}" ;; + --duration=*) DURATION="${1#--duration=}" ;; + --jobs=*) JOBS="${1#--jobs=}" ;; + --work=*) WORK="${1#--work=}" ;; + --out=*) OUT="${1#--out=}" ;; + --d8=*) D8="${1#--d8=}" ;; + --) shift; EXTRA=("$@"); break ;; + *) echo "unknown argument: $1" >&2; exit 2 ;; + esac + shift +done +if [ -z "$BASE" ]; then + echo "--base=REV is required." >&2 + exit 2 +fi +if [ ! -d experimental/redline ]; then + echo "Run this script from the root of the V8 checkout." >&2 + exit 2 +fi +if [ ! -x "$D8" ]; then + echo "No d8 at $D8 (TUTORIAL.md section 1 tells how to build it)." >&2 + exit 2 +fi +if ! git diff --quiet HEAD --; then + echo "Tracked files have changes. Commit or stash them first." >&2 + exit 2 +fi +BASE_SHA="$(git rev-parse --verify --quiet "$BASE^{commit}")" +if [ -z "$BASE_SHA" ]; then + echo "Unknown revision: $BASE" >&2 + exit 2 +fi +if [ -z "$WORK" ]; then + WORK="$(mktemp -d /tmp/redline-ab.XXXXXX)" +fi +mkdir -p "$WORK/tools" "$WORK/base" "$WORK/after" + +# The checkout of the base revision can remove or change this script, so the +# script continues from a copy in the work directory. +if [ -z "${AB_COPY:-}" ]; then + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + cp "$SCRIPT_DIR/ab_run.sh" "$SCRIPT_DIR/ab_compare.py" "$WORK/tools/" + AB_COPY=1 AB_WORK="$WORK" exec bash "$WORK/tools/ab_run.sh" \ + --base="$BASE" --duration="$DURATION" --jobs="$JOBS" --out="$OUT" \ + --d8="$D8" -- "${EXTRA[@]}" +fi + +ORIG="$(git symbolic-ref -q --short HEAD || git rev-parse HEAD)" +ON_BASE=0 # 1 while the checkout is at the base revision. +PIDS=() +cleanup() { + for pid in "${PIDS[@]}"; do kill -INT "$pid" 2> /dev/null; done + if [ "$ON_BASE" = 1 ]; then + git checkout -q "$ORIG" && echo "Restored $ORIG." + fi +} +trap cleanup EXIT +trap 'exit 130' INT TERM + +# Builds Redline and copies the binary, its V8 startup files, the presets and +# the test data to DIR/bin. The binary reads presets/ and testdata/ next to +# itself before it looks in the source tree. +build_and_copy() { # build_and_copy DIR + echo "Building $(git log -1 --format='%h %s' HEAD) ..." + if ! autoninja -C "$OUT" redline > "$1/build.log" 2>&1; then + echo "The build failed: see $1/build.log" >&2 + exit 1 + fi + mkdir -p "$1/bin" + cp "$OUT/redline" "$OUT/snapshot_blob.bin" "$OUT/icudtl.dat" "$1/bin/" && + cp -r experimental/redline/presets experimental/redline/testdata \ + "$1/bin/" || exit 1 + git log -1 --format='%H %s' HEAD > "$1/revision.txt" +} + +ON_BASE=1 +git checkout -q --detach "$BASE_SHA" || exit 1 +build_and_copy "$WORK/base" +git checkout -q "$ORIG" || exit 1 +ON_BASE=0 +build_and_copy "$WORK/after" + +COMMON=(--d8="$D8" "--d8-extra-args=--single-threaded --random-seed=42" + --preset=default --jobs="$JOBS" --seed=42 --duration="$DURATION" + --stats-interval=60 --no-component-stats "${EXTRA[@]}") +echo "Flags of both sessions: ${COMMON[*]}" | tee "$WORK/flags.txt" +echo "Running two sessions of $DURATION s in $WORK ..." +for side in base after; do + "$WORK/$side/bin/redline" fuzz "${COMMON[@]}" --out="$WORK/$side/run" \ + > "$WORK/$side/fuzz.log" 2>&1 & + PIDS+=($!) +done +STATUS=0 +for pid in "${PIDS[@]}"; do wait "$pid" || STATUS=1; done +PIDS=() +if [ "$STATUS" != 0 ]; then + echo "A session failed: see $WORK/base/fuzz.log and $WORK/after/fuzz.log" >&2 +fi + +python3 "$WORK/tools/ab_compare.py" "$WORK/base/run/events.jsonl" \ + "$WORK/after/run/events.jsonl" | tee "$WORK/compare.txt" +echo "Base: $(cat "$WORK/base/revision.txt")" +echo "After: $(cat "$WORK/after/revision.txt")" +echo "Work directory: $WORK" +exit "$STATUS" diff --git a/deps/v8/experimental/redline/skills/redline-presubmit/scripts/check.sh b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/check.sh new file mode 100755 index 000000000000..810da4979818 --- /dev/null +++ b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/check.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Runs the checks that every change to experimental/redline must pass before +# upload, and prints one line for each check. Run it from the root of the V8 +# checkout, after you commit the change. +# +# Usage: check.sh [--out=DIR] [--d8=PATH] [--base=REV] +# --out=DIR the Redline build directory (default: out/redline) +# --d8=PATH the fuzzing build of d8 (default: out/fuzzbuild/d8) +# --base=REV the revision before the change (default: the merge base with +# the upstream branch, or origin/main) +# +# Exit status: 0 if no check fails, 1 if a check fails. + +set -u +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUT=out/redline +D8=out/fuzzbuild/d8 +BASE="" +for arg in "$@"; do + case "$arg" in + --out=*) OUT="${arg#--out=}" ;; + --d8=*) D8="${arg#--d8=}" ;; + --base=*) BASE="${arg#--base=}" ;; + *) echo "unknown argument: $arg" >&2; exit 2 ;; + esac +done +if [ ! -d experimental/redline ]; then + echo "Run this script from the root of the V8 checkout." >&2 + exit 2 +fi +if [ -z "$BASE" ]; then + BASE="$(git merge-base HEAD '@{upstream}' 2>/dev/null || + git merge-base HEAD origin/main)" || exit 2 +fi +LOGS="$(mktemp -d /tmp/redline-check.XXXXXX)" +FAILED=0 +RESULTS=() + +record() { # record NAME PASS|FAIL|SKIP|INFO DETAIL + RESULTS+=("$(printf '%-4s %-24s %s' "$2" "$1" "$3")") + if [ "$2" = FAIL ]; then FAILED=1; fi +} + +run() { # run NAME COMMAND... : PASS if the command exits with 0 + local name="$1" log + shift + log="$LOGS/$(echo "$name" | tr -c 'a-z0-9' '_').log" + if "$@" > "$log" 2>&1; then + record "$name" PASS "$(tail -n 1 "$log" | cut -c1-90)" + else + record "$name" FAIL "see $log" + fi +} + +echo "Base revision: $(git log -1 --format='%h %s' "$BASE")" +echo "Logs: $LOGS" + +if git cl format --dry-run > "$LOGS/format.log" 2>&1; then + record "git cl format" PASS "no change needed" +else + record "git cl format" FAIL "run 'git cl format' (see $LOGS/format.log)" +fi + +if git cl lint > "$LOGS/lint.log" 2>&1; then + record "git cl lint" PASS "0 errors" +else + LINT_ERRORS="$(sed -n -E 's/^(Total errors found: |cpplint: )([0-9]+).*/\2/p' \ + "$LOGS/lint.log" | tail -n 1)" + record "git cl lint" FAIL \ + "${LINT_ERRORS:-?} C++ errors or Python errors (see $LOGS/lint.log)" +fi + +if autoninja -C "$OUT" redline > "$LOGS/build.log" 2>&1; then + record "build" PASS "autoninja -C $OUT redline" + run "selftest --offline" "$OUT/redline" selftest --offline + if [ -x "$D8" ]; then + run "selftest --d8" "$OUT/redline" selftest --d8="$D8" + else + record "selftest --d8" FAIL "no d8 at $D8 (TUTORIAL.md section 1)" + fi + run "roundtrip --no-run" "$OUT/redline" roundtrip --dir=test/mjsunit --no-run +else + record "build" FAIL "see $LOGS/build.log" + record "selftests, roundtrip" SKIP "the build failed" +fi + +TRACES="$(git diff --name-only "$BASE" -- experimental/redline/testdata | wc -l)" +if [ "$TRACES" = 0 ]; then + record "golden traces" INFO "unchanged" +else + record "golden traces" INFO "$TRACES changed: explain them in the CL description" +fi + +mapfile -t MARKDOWN < <(git diff --name-only --diff-filter=AMR "$BASE" -- \ + 'experimental/redline/*.md') +if [ "${#MARKDOWN[@]}" = 0 ]; then + record "markdown links" SKIP "no Markdown file changed" +else + run "markdown links" vpython3 tools/dev/markdown_checker.py "${MARKDOWN[@]}" +fi + +python3 "$SCRIPT_DIR/ste_check.py" --base="$BASE" > "$LOGS/ste.log" 2>&1 +case $? in + 0) record "STE language" PASS "see $LOGS/ste.log" ;; + 3) record "STE language" SKIP "the linter is not available (see $LOGS/ste.log)" ;; + *) record "STE language" FAIL "see $LOGS/ste.log" ;; +esac + +echo +printf '%s\n' "${RESULTS[@]}" +exit "$FAILED" diff --git a/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_check.py b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_check.py new file mode 100755 index 000000000000..200d06ce5544 --- /dev/null +++ b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_check.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Runs the ASD-STE100 linter on the text of a Redline change. + +It checks three kinds of text: + - the Markdown files in experimental/redline that the change adds or edits, + - the commit message of HEAD, + - the comments that the change adds to the C++, Python, shell and GN files + in experimental/redline. + +A Markdown file fails if it has more hard findings than at the base revision. +The commit message and the added comments fail on any hard finding. Advisory +findings (for example passive voice) never fail, but the script shows them. + +Run it from the root of the V8 checkout. Exit status: 0 if all checks pass, +1 if a check fails, 3 if the linter is not available. +""" + +import argparse +import json +import os +import re +import subprocess +import sys +import tempfile + +DEFAULT_LINTER = ('/google/src/files/head/depot/google3/learning/gemini/agents/' + 'skills/communication/asd_ste100/ste_lint.py') +SPEC = os.path.join( + os.path.dirname(os.path.abspath(__file__)), 'ste_lint.vpython3') +REDLINE = 'experimental/redline/' +FOOTER = re.compile(r'^[A-Za-z][A-Za-z-]*: \S') +HUNK = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@') +SKIP_COMMENT = re.compile(r'^(NOLINT|clang-format|namespace\b|IWYU|=+$|-+$)') +LICENSE = re.compile(r'Copyright .* the V8 project authors|' + r'Use of this source code is governed|' + r'found in the LICENSE file') +CPP_FILES = ('.cc', '.h') +SCRIPT_FILES = ('.py', '.sh', '.gn', '.gni') + + +def git(*args): + return subprocess.run( + ['git'] + list(args), check=True, capture_output=True, text=True).stdout + + +def default_base(): + for ref in ('@{upstream}', 'origin/main'): + try: + return git('merge-base', 'HEAD', ref).strip() + except subprocess.CalledProcessError: + continue + sys.exit('Cannot find the base revision. Use --base=REV.') + + +def lint(linter, path): + """Returns the hard and the advisory findings for the file at path.""" + proc = subprocess.run( + ['vpython3', '-vpython-spec', SPEC, linter, '--json', path], + capture_output=True, + text=True) + try: + findings = json.loads(proc.stdout).get('violations', []) + except json.JSONDecodeError: + sys.exit(f'The linter failed on {path}:\n{proc.stdout}{proc.stderr}') + hard = [f for f in findings if f.get('level') != 'advisory'] + advisory = [f for f in findings if f.get('level') == 'advisory'] + return hard, advisory + + +def lint_text(linter, text): + with tempfile.NamedTemporaryFile('w', suffix='.md', delete=False) as f: + f.write(text) + try: + return lint(linter, f.name) + finally: + os.unlink(f.name) + + +def changed_markdown(base): + names = git('diff', '--name-only', '--diff-filter=AMR', base, '--', REDLINE) + return [ + name for name in names.splitlines() + if name.endswith('.md') and os.path.isfile(name) + ] + + +def commit_message(base): + if git('rev-parse', 'HEAD') == git('rev-parse', base): + return None + lines = git('log', '-1', '--format=%B', 'HEAD').rstrip('\n').split('\n') + while lines and (not lines[-1].strip() or FOOTER.match(lines[-1])): + lines.pop() + return '\n'.join(lines) + '\n' + + +def cpp_comment(code): + """Returns the text after the // of a C++ comment in a line, or None.""" + for match in re.finditer('//', code): + before = code[:match.start()] + quotes = before.count('"') - before.count('\\"') + if quotes % 2 == 0: # The // is not in a string literal. + return code[match.end():] + return None + + +def comment_of(path, code): + """Returns (text, full_line, list_item) for the comment in a line of code. + + The text is None if the line has no comment to check. A full-line comment + continues the paragraph of the line before it. A list item starts a new + paragraph: an indented line, or a line that starts with "-" or "*". + """ + stripped = code.lstrip() + if path.endswith(CPP_FILES): + raw = cpp_comment(code) + full_line = stripped.startswith('//') + elif stripped.startswith('#') and not stripped.startswith('#!'): + raw = stripped[1:] + full_line = True + else: + return None, False, False + if raw is None: + return None, False, False + text = raw.strip() + if not text or SKIP_COMMENT.match(text) or LICENSE.search(text): + return None, False, False + list_item = raw.startswith(' ') or text.startswith(('-', '*')) + return text, full_line, list_item + + +def added_comments(base): + """Returns (paragraph, origin) pairs for the comments that the change adds. + + The comments come from C++, Python, shell and GN files. Consecutive + full-line comments form one paragraph, so that the linter sees whole + sentences. A comment after code is a paragraph of its own. + """ + patterns = [REDLINE + '*' + ext for ext in CPP_FILES + SCRIPT_FILES] + diff = git('diff', '-U0', base, '--', *patterns) + paragraphs = [] + path, line, can_continue = None, 0, False + for row in diff.splitlines(): + if row.startswith('+++ '): + path = row[6:] if row.startswith('+++ b/') else None + can_continue = False + continue + hunk = HUNK.match(row) + if hunk: + line = int(hunk.group(1)) + can_continue = False + continue + if path is None or not row.startswith('+'): + continue + text, full_line, list_item = comment_of(path, row[1:]) + if text is None: + can_continue = False + elif full_line and can_continue and not list_item: + previous, origin = paragraphs[-1] + paragraphs[-1] = (previous + ' ' + text, origin) + else: + paragraphs.append((text, f'{path}:{line}')) + can_continue = full_line + line += 1 + return paragraphs + + +def show(findings, where=None): + for f in findings: + origin = where(f['line']) if where else f'line {f["line"]}' + print(f' {origin}: {f["rule"]} [{f.get("match", "")}] ' + f'{f.get("message", "")}') + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.split('\n')[0]) + parser.add_argument( + '--base', + help='the base revision (default: the merge ' + 'base with the upstream branch, or origin/main)') + parser.add_argument( + '--verbose', action='store_true', help='also show the advisory findings') + args = parser.parse_args() + if not os.path.isdir(REDLINE): + sys.exit('Run this script from the root of the V8 checkout.') + linter = os.environ.get('STE_LINT', DEFAULT_LINTER) + if not os.path.isfile(linter): + print(f'SKIP the STE linter is not at {linter}. Set STE_LINT.') + return 3 + base = args.base or default_base() + failed = False + + for name in changed_markdown(base): + hard, advisory = lint(linter, name) + base_hard, base_advisory = [], [] + if subprocess.run(['git', 'cat-file', '-e', f'{base}:{name}'], + capture_output=True).returncode == 0: + base_hard, base_advisory = lint_text(linter, git('show', + f'{base}:{name}')) + ok = len(hard) <= len(base_hard) + failed |= not ok + print(f'{"PASS" if ok else "FAIL"} {name}: hard {len(hard)} ' + f'(base {len(base_hard)}), advisory {len(advisory)} ' + f'(base {len(base_advisory)})') + if not ok: + show(hard) + if args.verbose: + show(advisory) + + message = commit_message(base) + if message is None: + print('SKIP commit message: HEAD is the base revision. Commit first.') + else: + hard, advisory = lint_text(linter, message) + failed |= bool(hard) + print(f'{"FAIL" if hard else "PASS"} commit message: hard {len(hard)}, ' + f'advisory {len(advisory)}') + show(hard) + if args.verbose: + show(advisory) + + paragraphs = added_comments(base) + if not paragraphs: + print('PASS added comments: none') + else: + hard, advisory = lint_text( + linter, '\n\n'.join(text for text, _ in paragraphs) + '\n') + origins = [origin for _, origin in paragraphs] + where = lambda temp_line: origins[min((temp_line - 1) // 2, + len(origins) - 1)] + failed |= bool(hard) + print(f'{"FAIL" if hard else "PASS"} added comments ({len(paragraphs)}): ' + f'hard {len(hard)}, advisory {len(advisory)}') + show(hard, where) + if args.verbose: + show(advisory, where) + return 1 if failed else 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_lint.vpython3 b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_lint.vpython3 new file mode 100644 index 000000000000..626e81b1601e --- /dev/null +++ b/deps/v8/experimental/redline/skills/redline-presubmit/scripts/ste_lint.vpython3 @@ -0,0 +1,9 @@ +# vpython3 spec for the ASD-STE100 linter (it needs absl-py). +# Used by ste_check.py. + +python_version: "3.11" + +wheel: < + name: "infra/python/wheels/absl-py-py3" + version: "version:2.1.0" +> diff --git a/deps/v8/experimental/redline/testdata/README.md b/deps/v8/experimental/redline/testdata/README.md new file mode 100644 index 000000000000..4123f365c6ef --- /dev/null +++ b/deps/v8/experimental/redline/testdata/README.md @@ -0,0 +1,35 @@ +# Test data + +The offline checks of `redline selftest` compare the current code with the golden traces in `selection/`. +Each trace records what the default components and strategies do for a fixed random seed. +A check fails if the code gives a different trace, and it prints the first line that differs. +Thus a change to a default pick or to the output of a component shows as a failing check. + +Each line of a trace is one record. Tabs separate the fields. + +| File | Each line records | Fields | +|---|---|---| +| `mutators.trace` | A pick of the default mutator strategy. | Index, partner flag (`1` if a partner program is available, else `0`), mutator. | +| `generators.trace` | A pick of the default generator strategy, for a random insertion point in a fixed program. | Index, generator. | +| `codegen.trace` | A `CodeGen` mutation of the fixed program. | Index, the generators that the mutator inserted. | +| `generator_outputs.trace` | An output of a generator for a fixed seed. | Generator, sample number, hash of the program, start of the program. | +| `mutator_outputs.trace` | An output of a mutator for a fixed seed. | Mutator, sample number, hash of the program, change, start of the program. | +| `scheduler_<name>.trace` | A pick from a fixed corpus with the seed strategy `<name>`. | Index, id of the seed, id of the partner. | + +The scheduler traces exist for the seed strategies `uniform`, `recency`, `tournament` and `productive`. +They use the partner strategy `uniform-partner`. Some picks report new coverage, as in a session. + +`experimental/redline/commands/selftest_selection.cc` makes the traces. +Redline finds this directory from the location of its binary. `--testdata=DIR` sets another directory. + +## Update the traces + +Update the traces only for an intended change of the default picks or outputs: + +```shell +out/redline/redline selftest --offline --write-golden +git diff --stat experimental/redline/testdata +``` + +Examine the diff, and explain the change in the CL description. +[CONTRIBUTE.md](../CONTRIBUTE.md) tells which traces change when you add a generator or a mutator. diff --git a/deps/v8/experimental/redline/testdata/selection/codegen.trace b/deps/v8/experimental/redline/testdata/selection/codegen.trace new file mode 100644 index 000000000000..b7b4d67dc2b1 --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/codegen.trace @@ -0,0 +1,1000 @@ +0 inserted Gc+DynamicFunctionTransition+ReturnOverride +1 inserted Gc +2 inserted WrapperChain+PropertyLoad +3 inserted ArrayDecl+Construct +4 inserted ManyProperties+FloatDecl+TemporalOps +5 inserted ForOf+FunctionDecl +6 inserted FunctionDecl+BinaryOp+RegExpDecl +7 inserted IntlOps+Compare +8 inserted Construct +9 inserted ObjectDecl +10 inserted CrossContextPrivateStore+ProxyDecl+JitOptimize +11 inserted CountedLoop +12 inserted BinaryOp +13 inserted FrozenArrayOps +14 inserted BinaryOp+Deopt +15 inserted FunctionCall+BinaryOp+BinaryOp +16 inserted Assignment +17 inserted Construct+UnaryOp +18 inserted MethodCall +19 inserted ConstructorFunction+PrototypeSet+Construct +20 noop +21 inserted JitOptimize +22 inserted ElementStore+Return +23 inserted StringOps+ComputedDecl+ElementsKind +24 inserted RegExpDecl+JitOptimize+ForIn +25 inserted Deopt+Update +26 inserted FunctionCall+ElementStore+BinaryOp +27 inserted BuiltinCall+ValueOfOverride+ArrayDecl +28 inserted PropertyStore+Iife +29 inserted Iteration +30 inserted ConstructDecl+PropertyDelete +31 inserted IntegerDecl +32 inserted ElementsKind+IntegerDecl +33 inserted WorkerSpawn +34 inserted Return+FunctionCall +35 inserted RawThrow+IntlOps+BinaryOp +36 inserted NewTargetExpr+Iteration +37 inserted FunctionCall +38 inserted ReturnOverride +39 inserted JitOptimize+ArrayDecl +40 inserted PropertyStore+GeneratorIterate+CrossContextPrivateStore +41 inserted Iteration+PropertyDelete +42 inserted ThisUse +43 inserted TypeCheck+Assignment +44 inserted Compare+BuiltinOverwrite +45 inserted PrototypeSet+TemplateDecl +46 inserted PrototypeSet+PromiseThen+PromiseThen +47 inserted ElementStore +48 inserted TryCatch +49 inserted With+OsrLoop+JitOptimize +50 inserted FunctionDecl +51 noop +52 inserted ArrayDecl+ConstructorFunction+ObjectDecl +53 inserted PropertyDelete+TypedArrayDecl+JitOptimize +54 inserted BinaryOp+Update +55 inserted ElementStore +56 inserted CountedLoop+BuiltinCall +57 inserted FunctionCall +58 inserted ForOf +59 inserted ComputedDecl+PropertyStore+FunctionCall +60 inserted JitOptimize +61 inserted BuiltinCall +62 inserted MethodCall +63 inserted RegExpDecl+JitOptimize +64 inserted ElementsKind+DefineProperty +65 inserted ShapeChange +66 inserted ObjectDecl+ElementLoad +67 inserted ValueOfOverride+IntegerDecl+MethodCall +68 inserted FunctionDecl +69 inserted Assignment +70 inserted ShapeChange+ElementLoad +71 inserted ElementLoad +72 inserted WrapperChain+Switch +73 inserted Switch +74 inserted BinaryOp +75 inserted JitOptimize +76 inserted Assignment+ElementStore+ConstructDecl +77 inserted ElementLoad+MethodCall+DefineProperty +78 inserted ConstructorFunction+StringDecl +79 inserted OsrLoop +80 inserted StringOps +81 inserted IfElse+ObjectDecl +82 inserted Recursion +83 inserted PropertyLoad +84 inserted JitOptimize+IfElse+ArrowDecl +85 inserted StringOps+ProxyDecl+PropertyStore +86 inserted ConstructDecl+Iteration+DynamicFunctionTransition +87 inserted RegExpDecl+StringDecl +88 inserted UnaryOp +89 inserted PrototypeMethodCall +90 inserted PropertyLoad +91 inserted CountedLoop+ProxyDecl+FloatDecl +92 inserted ForIn +93 inserted PromiseThen+BuiltinCall +94 inserted IntegerDecl+MapSetOps+ArrayDecl +95 inserted MethodCall +96 inserted ConstructDecl+BuiltinCall+ArrowStore +97 inserted DefineProperty +98 inserted TypedArrayOps+ElementStore +99 inserted FunctionDecl +100 inserted ForOf+PropertyDelete +101 inserted Iteration+Assignment+UnaryOp +102 inserted RegExpDecl +103 inserted IntegerDecl+UsingDecl +104 inserted ArrayDecl+WorkerSpawn +105 inserted Deopt+TypedArrayOps +106 inserted BinaryOp+PropertyStore +107 inserted WorkerSpawn+Assignment+StringDecl +108 inserted PropertyLoad +109 inserted ForIn+IfElse+ForOf +110 inserted StringOps+TemplateDecl +111 inserted FunctionCall +112 inserted FrozenArrayOps+RawThrow +113 inserted MethodCall+ManyProperties+FunctionDecl +114 inserted MapSetOps +115 noop +116 noop +117 inserted FunctionCall +118 inserted BinaryOp+ConstructDecl+UnboundMethodCall +119 inserted ManyProperties +120 inserted ForIn+FunctionCall+PropertyStore +121 inserted ValueOfOverride +122 inserted StringOps+TryCatch+Iteration +123 inserted JitOptimize+PrototypeMethodCall+ConstructorFunction +124 inserted UnboundMethodCall +125 inserted ManyProperties +126 inserted ElementsKind+TypedArrayDecl+ClassDecl +127 inserted CountedLoop +128 inserted ShapeChange+IntegerDecl+Switch +129 inserted BuiltinCall+ReturnOverride +130 inserted TypedArrayOps+BuiltinCall+StringDecl +131 inserted ConstructDecl +132 inserted FunctionCall +133 inserted PrototypeMethodCall +134 noop +135 inserted DefineProperty+FunctionCall+BuiltinCall +136 inserted MapSetOps+IntegerDecl +137 noop +138 inserted Iife+DynamicFunctionTransition+ObjectDecl +139 inserted IntlOps+DefineProperty +140 inserted IfElse +141 inserted BuiltinOverwrite +142 inserted TypedArrayDecl+GeneratorIterate+StringOps +143 inserted ElementsKind+ConstructorFunction+AsyncIife +144 inserted ReturnOverride +145 inserted IfElse+JitOptimize +146 inserted ArrowDecl+Iteration +147 inserted BinaryOp+Compare +148 inserted Destructuring+ValueOfOverride +149 inserted TemplateDecl +150 inserted ObjectDecl+UnaryOp +151 inserted ComputedDecl+IntegerDecl+ElementsKind +152 noop +153 inserted JitOptimize+PropertyLoad+FunctionCall +154 inserted ComputedDecl +155 inserted StringOps+TypeCheck +156 inserted FloatDecl +157 inserted Compare +158 inserted ElementsKind +159 inserted BinaryOp+PromiseThen +160 inserted ManyProperties+BinaryOp +161 inserted Switch +162 inserted ArrayDecl +163 inserted WorkerSpawn +164 inserted ComputedDecl+DefineProperty +165 noop +166 inserted IntegerDecl +167 inserted IfElse +168 inserted ComputedDecl +169 inserted ArrowDecl+Assignment +170 inserted IfElse+IfElse +171 inserted IfElse+MethodCall+ComputedDecl +172 inserted StringOps+Gc +173 inserted Destructuring +174 inserted ArrowDecl +175 inserted Assignment +176 inserted JitOptimize +177 inserted ComputedDecl+WorkerSpawn+ArrayDecl +178 inserted CrossContextPrivateStore+ThisUse +179 inserted JitOptimize +180 inserted PrototypeMethodCall +181 inserted WhileLoop +182 inserted BinaryOp+TemporalOps+ClassDecl +183 inserted ArrowDecl+TryCatch +184 inserted TypedArrayOps +185 inserted Construct+TypedArrayOps +186 noop +187 noop +188 inserted UnaryOp+BuiltinCall +189 inserted TemplateDecl+ClassDecl+ElementStore +190 inserted ClassDecl +191 inserted NewTargetExpr+FunctionCall+Iife +192 inserted FloatDecl+ValueOfOverride +193 inserted ForIn+ComputedDecl+PropertyDelete +194 inserted ObjectDecl+ForIn +195 inserted ObjectDecl+IfElse +196 inserted PrototypeMethodCall+UnaryOp +197 inserted Assignment+BinaryOp+ElementStore +198 inserted BinaryOp +199 inserted TryCatch+ValueOfOverride +200 inserted Update +201 inserted Assignment +202 inserted CountedLoop+BinaryOp +203 inserted FunctionCall +204 inserted UnboundMethodCall+CountedLoop +205 inserted IfElse +206 inserted Update +207 inserted AsyncIife +208 inserted TryCatch +209 inserted ConstructDecl+FunctionCall+ArrayDecl +210 inserted TemporalOps +211 inserted ConstructDecl+ValueOfOverride +212 inserted PropertyLoad+ArrowDecl+PromiseThen +213 inserted BinaryOp+WrapperChain +214 inserted WrapperChain+Deopt+ObjectDecl +215 inserted Compare +216 inserted OsrLoop+Update +217 inserted BigIntDecl+BigIntDecl +218 inserted ComputedDecl +219 inserted ElementStore+ObjectDecl+ElementsKind +220 inserted ManyProperties +221 inserted UnaryOp+IfElse +222 inserted StringOps+ClassDecl +223 inserted ComputedDecl +224 inserted ElementsKind+StringDecl+ConstructDecl +225 inserted PropertyStore+WorkerSpawn +226 inserted IfElse+PropertyLoad +227 inserted FunctionCall+Iife+IfElse +228 inserted UnaryOp +229 inserted IfElse+DefineProperty +230 inserted WrapperChain +231 inserted TemplateDecl +232 inserted JitOptimize +233 inserted FunctionDecl+FunctionDecl+MethodCall +234 inserted ElementsKind +235 inserted JitOptimize +236 inserted UnaryOp+ArrayDecl +237 inserted CountedLoop+JitBaseline+PrototypeSet +238 inserted AsyncIife+SpreadCall +239 inserted TemporalOps +240 inserted FunctionCall+FunctionDecl +241 inserted Compare +242 inserted JitOptimize+TryCatch+WrapperChain +243 inserted JitOptimize +244 inserted AsyncIife +245 inserted PropertyLoad+MapSetOps +246 inserted ClassDecl+BinaryOp+ElementsKind +247 inserted ProxyDecl+ComputedDecl+JitOptimize +248 inserted StringDecl+MethodCall+FunctionDecl +249 inserted Throw +250 inserted JitOptimize+PropertyStore +251 inserted NullishDecl+PropertyLoad+PromiseThen +252 inserted FloatDecl+Iife +253 inserted Compare+Construct +254 inserted StringDecl+StringDecl +255 inserted ArrayDecl+ArrowStore +256 inserted FunctionCall+ElementsKind +257 inserted Recursion+ArrayDecl+MethodCall +258 inserted TypedArrayOps+MethodCall +259 inserted IntegerDecl+Construct +260 inserted PropertyStore+JitOptimize +261 inserted NativeCall +262 inserted ReturnOverride +263 inserted ComputedDecl +264 inserted JitOptimize +265 inserted IntlOps +266 inserted SymbolDecl+ManyProperties+MethodCall +267 inserted ElementStore+DynamicFunctionTransition +268 inserted PrototypeSet+PropertyDelete +269 inserted ArrayDecl+ElementLoad+UnboundMethodCall +270 inserted ObjectDecl+PrototypeMethodCall+FunctionCall +271 inserted Destructuring+TemporalOps +272 inserted NullishDecl +273 inserted FrozenArrayOps+RawThrow+UnaryOp +274 inserted ArrowStore +275 inserted ElementLoad+ConstructorFunction+PrototypeMethodCall +276 inserted PropertyLoad+ThisUse +277 inserted PropertyStore +278 inserted BuiltinCall+Recursion+TemplateDecl +279 inserted BinaryOp+ElementsKind+FloatDecl +280 inserted Destructuring+BinaryOp+CountedLoop +281 inserted ArrayDecl+OsrLoop+ConstructDecl +282 inserted ShapeChange+FunctionDecl +283 inserted TypedArrayDecl+JitOptimize+BuiltinOverwrite +284 inserted AsyncIife+FloatDecl +285 inserted ComputedDecl +286 inserted BinaryOp+GeneratorIterate+Assignment +287 inserted With+ForOf+ElementsKind +288 inserted WorkerSpawn+StringDecl +289 inserted OsrLoop +290 inserted PropertyDelete +291 inserted ArrowDecl +292 inserted Assignment +293 inserted ValueOfOverride +294 inserted BigIntDecl +295 inserted NullishDecl +296 inserted Recursion +297 inserted ElementsKind +298 inserted ElementsKind+FunctionDecl+Assignment +299 inserted IntegerDecl +300 inserted ArrayDecl+Deopt +301 inserted PropertyLoad +302 inserted BuiltinOverwrite+TryCatch+ProxyDecl +303 inserted IntlOps +304 inserted JitOptimize +305 inserted Assignment+FunctionCall +306 inserted PromiseThen +307 inserted UnaryOp +308 inserted IfElse +309 inserted ElementLoad+DynamicFunctionTransition+JitOptimize +310 inserted PropertyStore+FunctionCall +311 inserted FunctionDecl +312 inserted PropertyStore +313 inserted StringOps+RegExpDecl +314 inserted ShapeChange +315 inserted ComputedDecl+ArrowStore +316 inserted ClassDecl+FunctionDecl +317 inserted IfElse +318 inserted ComputedDecl +319 inserted ClassDecl+BuiltinCall +320 inserted FunctionDecl+ClassDecl +321 inserted ElementLoad+Throw+IntegerDecl +322 inserted DefineProperty+ObjectDecl+IntegerDecl +323 inserted ComputedDecl+UnaryOp+FunctionDecl +324 inserted ForOf+Iteration +325 inserted TemporalOps+JitOptimize+ForOf +326 inserted CountedLoop+BinaryOp +327 inserted Iteration +328 inserted Iife +329 inserted BuiltinOverwrite+BuiltinOverwrite+BinaryOp +330 inserted IntegerDecl+PropertyStore+ObjectDecl +331 inserted AsyncIife+MapSetOps +332 inserted UsingDecl+ElementsKind +333 inserted MapSetOps+ShapeChange+Construct +334 inserted ObjectDecl +335 inserted TryCatch+PropertyStore+CountedLoop +336 inserted ArrayDecl+OsrLoop+Destructuring +337 inserted FunctionCall +338 inserted BuiltinCall+WhileLoop+PropertyLoad +339 inserted Return+PrototypeMethodCall +340 inserted PropertyLoad +341 inserted ArrayDecl+StringDecl+Iife +342 inserted MethodCall +343 inserted FloatDecl +344 inserted Switch +345 inserted IntegerDecl+Recursion +346 inserted TemplateDecl +347 inserted IfElse +348 inserted ForOf+CrossContextPrivateStore+Iteration +349 inserted ComputedDecl +350 inserted NativeCall+IntegerDecl+Update +351 inserted AsyncIife+MethodCall +352 inserted Construct +353 inserted FloatDecl+BooleanDecl +354 inserted GeneratorIterate +355 inserted ArrowStore +356 inserted ClassDecl+ArrayDecl +357 inserted ConstructDecl +358 inserted JitOptimize +359 inserted BinaryOp +360 inserted ThisUse+ArrayDecl+ArrayDecl +361 inserted OsrLoop+UnaryOp+IntegerDecl +362 inserted ConstructDecl +363 inserted WrapperChain +364 inserted PrototypeMethodCall+ForOf +365 inserted PrototypeMethodCall +366 inserted FunctionCall+ForOf+ClassDecl +367 inserted UsingDecl+Compare +368 inserted JitOptimize+WrapperChain+MethodCall +369 inserted MethodCall+NullishDecl+TypedArrayOps +370 inserted ForIn+Iteration+SpreadCall +371 inserted IntegerDecl +372 inserted UnboundMethodCall+SymbolDecl+DefineProperty +373 inserted MethodCall+AsyncIife+JitOptimize +374 inserted ArrayDecl +375 inserted DefineProperty+NativeCall+ForIn +376 inserted ArrayDecl +377 inserted Iteration+ReturnOverride+IntegerDecl +378 inserted JitOptimize+ForOf +379 inserted FunctionDecl+ValueOfOverride+Switch +380 inserted TryCatch+ElementsKind +381 inserted IfElse +382 inserted JitOptimize+AsyncIife+Assignment +383 inserted FunctionDecl +384 inserted WhileLoop+Iife +385 inserted TypedArrayOps+TryCatch +386 inserted ObjectDecl+AsyncIife +387 inserted ArrayDecl +388 inserted WhileLoop+ObjectDecl+Deopt +389 inserted WorkerSpawn +390 inserted PropertyStore+BooleanDecl+Throw +391 inserted MapSetOps+OsrLoop+TemplateDecl +392 inserted PropertyStore +393 inserted ArrowStore+Construct+ForIn +394 inserted UnboundMethodCall+BooleanDecl +395 inserted ComputedDecl+UnboundMethodCall+ObjectDecl +396 inserted BigIntDecl +397 inserted WorkerSpawn+FunctionCall +398 inserted IfElse +399 inserted JitOptimize +400 inserted IfElse+OsrLoop +401 inserted FreezeSeal +402 inserted ReturnOverride+ShapeChange +403 inserted BinaryOp +404 inserted FunctionCall+ElementStore+Return +405 inserted BinaryOp +406 inserted Throw +407 inserted ConstructorFunction +408 inserted NativeCall +409 inserted JitBaseline+Construct +410 inserted BinaryOp+ShapeChange +411 inserted Assignment+NativeCall+RegExpDecl +412 inserted CrossContextPrivateStore +413 inserted ClassDecl +414 noop +415 noop +416 inserted BooleanDecl+TypedArrayOps+ComputedDecl +417 inserted PropertyStore +418 inserted ElementLoad +419 inserted ElementStore +420 inserted BooleanDecl+FloatDecl+BinaryOp +421 inserted ObjectDecl +422 inserted Construct +423 inserted WrapperChain+ShapeChange+Recursion +424 inserted TryCatch +425 inserted FreezeSeal+NewTargetExpr +426 inserted WrapperChain +427 inserted Construct+ConstructorFunction+PropertyLoad +428 inserted ShapeChange +429 inserted MethodCall +430 noop +431 inserted Assignment+UnboundMethodCall+FunctionDecl +432 inserted TemplateDecl +433 inserted FrozenArrayOps+ElementLoad +434 inserted Return+Deopt+UsingDecl +435 inserted FunctionCall+ArrowDecl+ValueOfOverride +436 inserted Assignment+BinaryOp +437 inserted WrapperChain +438 inserted PropertyDelete +439 inserted ManyProperties+ArrayDecl +440 inserted ComputedDecl+IntegerDecl+Update +441 inserted FunctionCall +442 inserted AsyncIife+ConstructDecl +443 inserted ForOf+GeneratorIterate +444 inserted StringDecl+Closure +445 inserted ForOf+ObjectDecl+StringDecl +446 inserted MethodCall +447 inserted FunctionCall+TypedArrayOps +448 inserted MapSetOps +449 inserted DefineProperty +450 inserted ComputedDecl +451 inserted Iife+TypedArrayDecl +452 inserted PropertyDelete+GeneratorIterate+MethodCall +453 inserted IntegerDecl +454 inserted IntegerDecl+TryCatch+BinaryOp +455 inserted Switch +456 inserted RawThrow+ComputedDecl+IntlOps +457 inserted BuiltinCall +458 inserted IntegerDecl+WrapperChain +459 inserted TypedArrayDecl+GeneratorIterate+BinaryOp +460 inserted FunctionCall+PropertyLoad+FunctionDecl +461 inserted UnboundMethodCall +462 inserted Iteration +463 inserted NewTargetExpr+FunctionCall+Return +464 inserted CountedLoop+Assignment +465 inserted TryCatch +466 inserted ClassDecl+MethodCall +467 inserted RawThrow+Compare +468 inserted AsyncIife+StringDecl+PrototypeSet +469 inserted ReturnOverride+MethodCall+CountedLoop +470 inserted IntlOps+UnboundMethodCall +471 inserted CountedLoop+BinaryOp+IfElse +472 inserted ValueOfOverride+StringDecl+ThisUse +473 inserted BinaryOp+ConstructorFunction+NativeCall +474 inserted Compare+IfElse +475 inserted ForIn+ConstructorFunction+ObjectDecl +476 inserted ShapeChange +477 inserted FunctionCall +478 inserted ValueOfOverride +479 inserted StringOps+BuiltinOverwrite +480 inserted MethodCall +481 inserted PropertyLoad +482 inserted FunctionCall +483 inserted Destructuring +484 inserted FunctionCall +485 inserted ObjectDecl +486 inserted WorkerSpawn +487 inserted IntlOps+JitOptimize+PropertyLoad +488 inserted IntegerDecl+FunctionDecl +489 inserted JitOptimize +490 inserted Construct+AsyncIife +491 inserted LabeledBlock+TryCatch +492 inserted PromiseThen +493 inserted Update +494 inserted ProxyDecl+ConstructDecl+FunctionCall +495 inserted BinaryOp+PropertyLoad+IfElse +496 inserted ElementStore +497 inserted BigIntDecl+ElementStore+FunctionCall +498 inserted Destructuring+ConstructDecl +499 inserted JitOptimize +500 inserted Deopt+IntegerDecl+JitOptimize +501 inserted FunctionCall +502 inserted ConstructorFunction+FunctionDecl+TypeCheck +503 inserted MethodCall +504 inserted UnaryOp +505 inserted PropertyStore+JitOptimize +506 inserted JitOptimize +507 inserted Update +508 noop +509 inserted FunctionCall+ProxyDecl+BinaryOp +510 inserted ConstructDecl +511 inserted Assignment +512 inserted BinaryOp +513 inserted StringDecl+Assignment+ValueOfOverride +514 inserted PropertyStore +515 inserted ClassDecl +516 inserted BuiltinCall+ConstructorFunction+FreezeSeal +517 inserted Iteration +518 inserted RegExpDecl +519 inserted Construct+ComputedDecl +520 inserted ComputedDecl +521 inserted ValueOfOverride+With +522 inserted CountedLoop +523 inserted FunctionDecl+AsyncIife+RegExpDecl +524 inserted StringOps+ForIn+CountedLoop +525 inserted ElementLoad +526 inserted FunctionCall+LabeledBlock+CountedLoop +527 inserted DynamicFunctionTransition +528 inserted UnboundMethodCall+Switch +529 inserted IfElse+Iteration+ElementLoad +530 inserted ArrowDecl +531 inserted NewTargetExpr+TypedArrayOps+ElementsKind +532 inserted Closure+IntlOps +533 inserted BuiltinCall +534 inserted PropertyStore +535 inserted PropertyDelete+Update+NativeCall +536 inserted MethodCall +537 inserted FunctionDecl +538 inserted WhileLoop+Deopt +539 inserted ConstructorFunction+SymbolDecl+Eval +540 inserted FunctionCall+JitOptimize+ForIn +541 inserted TypeCheck+WrapperChain +542 inserted ObjectDecl+IfElse+PrototypeSet +543 inserted PropertyStore +544 inserted IntegerDecl+BinaryOp +545 inserted ElementLoad+PropertyDelete+MapSetOps +546 inserted Switch+ProxyDecl+WrapperChain +547 inserted ComputedDecl +548 inserted IntegerDecl+ArrayDecl +549 inserted IfElse+JitOptimize+UnaryOp +550 inserted PrototypeSet+ComputedDecl+BigIntDecl +551 inserted ElementStore +552 inserted TemporalOps +553 inserted FunctionCall +554 inserted TemplateDecl+MapSetOps +555 inserted PropertyLoad+Iife+PropertyLoad +556 inserted FunctionCall +557 inserted Construct +558 inserted ConstructorFunction+ManyProperties+PropertyDelete +559 noop +560 inserted TypedArrayOps+Throw+TypeCheck +561 inserted FrozenArrayOps+Deopt+With +562 inserted IntegerDecl +563 inserted BuiltinCall +564 inserted TypeCheck +565 noop +566 inserted TypedArrayDecl +567 inserted ConstructDecl+Construct +568 inserted CountedLoop +569 inserted WhileLoop+ArgumentsUse +570 inserted FunctionDecl+ArrowStore+ConstructDecl +571 inserted FreezeSeal+ArrowDecl +572 noop +573 inserted FloatDecl +574 inserted Construct+ObjectDecl+PrototypeMethodCall +575 inserted ForOf+ProxyDecl +576 inserted MethodCall+Switch+FunctionCall +577 inserted Compare+TemporalOps+WrapperChain +578 inserted PropertyDelete +579 inserted ComputedDecl+ArrowStore +580 inserted BinaryOp+ArrowDecl+Return +581 inserted Construct+ClassDecl +582 inserted PropertyLoad +583 inserted IfElse +584 inserted FunctionCall +585 inserted ComputedDecl+BooleanDecl+FunctionDecl +586 inserted IntegerDecl +587 inserted TemporalOps+FrozenArrayOps+TryCatch +588 inserted StringDecl +589 inserted ReturnOverride+ObjectDecl+ClassDecl +590 inserted IntlOps+BinaryOp +591 inserted MethodCall+PromiseThen+StringOps +592 inserted BuiltinCall+JitOptimize +593 inserted ArrayDecl+Construct+ComputedDecl +594 inserted ForOf+WorkerSpawn+ConstructorFunction +595 inserted ComputedDecl +596 inserted JitOptimize+IntlOps+TypeCheck +597 inserted ValueOfOverride+TypedArrayOps+Construct +598 inserted ArrayDecl+IfElse +599 inserted FunctionCall +600 inserted BuiltinCall+ArrowDecl +601 inserted ElementLoad+JitOptimize+BinaryOp +602 inserted MethodCall+IntegerDecl+Gc +603 inserted ElementLoad+Construct+Switch +604 inserted AsyncIife+Destructuring+Eval +605 inserted ProxyDecl+Gc +606 inserted FunctionDecl+TemporalOps +607 inserted DefineProperty +608 inserted IntegerDecl+ElementsKind+PropertyLoad +609 inserted BinaryOp+Closure+UnaryOp +610 inserted FloatDecl+FunctionCall +611 inserted TypedArrayOps+ForIn+ElementLoad +612 inserted BigIntDecl+ObjectDecl +613 inserted ObjectDecl+WhileLoop+FunctionCall +614 inserted Switch+Assignment+BreakContinue +615 inserted MethodCall+ComputedDecl+UnaryOp +616 inserted MethodCall+BinaryOp +617 inserted OsrLoop +618 inserted PropertyLoad+IntegerDecl +619 inserted UnboundMethodCall +620 inserted DynamicFunctionTransition +621 inserted ReturnOverride+ArrayDecl +622 noop +623 inserted BuiltinCall+IfElse+ObjectDecl +624 inserted Recursion+ConstructDecl+BuiltinCall +625 noop +626 inserted IfElse +627 inserted BigIntDecl +628 inserted ShapeChange +629 inserted ObjectDecl+Closure +630 inserted ArrowDecl+BooleanDecl +631 inserted ObjectDecl+Closure +632 inserted ShapeChange+Closure +633 inserted BooleanDecl +634 inserted ForOf+ArrowStore +635 inserted ComputedDecl+CountedLoop +636 inserted BinaryOp+CountedLoop +637 inserted MethodCall +638 inserted Construct+IntlOps+Assignment +639 inserted ReturnOverride+StringOps+Gc +640 inserted ObjectDecl+Gc+PropertyStore +641 inserted TypedArrayDecl+FunctionCall+BinaryOp +642 inserted JitOptimize+JitOptimize +643 inserted IntegerDecl +644 inserted ArrowDecl +645 inserted ElementStore+StringDecl+Deopt +646 noop +647 inserted ShapeChange+BuiltinOverwrite +648 inserted FunctionDecl +649 inserted BuiltinCall +650 inserted Assignment +651 inserted DefineProperty+IntegerDecl +652 inserted FunctionDecl+Construct +653 inserted ClassDecl +654 inserted BuiltinCall+FloatDecl+SpreadCall +655 inserted With +656 inserted Update+AsyncIife+ArrayDecl +657 inserted ComputedDecl +658 inserted TypedArrayDecl+PropertyLoad +659 inserted ObjectDecl +660 inserted CrossContextPrivateStore +661 inserted Destructuring+Construct +662 noop +663 inserted ArrowStore +664 inserted MethodCall+ElementStore +665 inserted Deopt+PrototypeMethodCall +666 inserted BuiltinCall +667 inserted JitOptimize+BuiltinCall+SymbolDecl +668 inserted PropertyDelete+BooleanDecl+Deopt +669 inserted IntlOps+FunctionCall +670 inserted FunctionCall +671 inserted TypedArrayDecl+FloatDecl+ForOf +672 inserted PropertyDelete +673 inserted ClassDecl+ComputedDecl +674 inserted IfElse+Eval+SpreadCall +675 inserted Closure +676 inserted Assignment+UnaryOp+TemplateDecl +677 inserted Destructuring +678 inserted RegExpDecl+DynamicFunctionTransition+BuiltinCall +679 inserted StringDecl+FunctionDecl+Construct +680 inserted ElementStore +681 inserted ElementStore +682 inserted AsyncIife+TypedArrayOps +683 inserted RawThrow +684 inserted PropertyLoad+TypeCheck +685 inserted WrapperChain +686 inserted TemplateDecl+TypeCheck+ElementsKind +687 inserted FloatDecl+ArrayDecl +688 inserted WorkerSpawn +689 inserted Iteration +690 inserted ForOf +691 inserted JitOptimize+ConstructorFunction+MethodCall +692 inserted FunctionCall+FloatDecl+ArrayDecl +693 inserted JitOptimize +694 inserted FunctionDecl+ConstructorFunction+ElementsKind +695 inserted MethodCall+CountedLoop +696 inserted RegExpDecl +697 inserted IfElse+CountedLoop+CountedLoop +698 inserted PrototypeSet+PropertyStore+Switch +699 inserted FunctionCall +700 inserted Recursion+DynamicFunctionTransition+ElementLoad +701 inserted ComputedDecl+JitOptimize +702 inserted ForIn+ArrayDecl +703 inserted ObjectDecl+UnaryOp+CountedLoop +704 inserted PrototypeMethodCall+PropertyLoad+FunctionCall +705 inserted FloatDecl+PropertyDelete +706 inserted ComputedDecl+Assignment+UnboundMethodCall +707 inserted ArrowDecl+ObjectDecl+ArrowDecl +708 inserted TemporalOps+FunctionCall +709 inserted MapSetOps+AsyncIife+ObjectDecl +710 inserted Iteration +711 inserted MethodCall+ClassDecl +712 inserted WhileLoop+BuiltinOverwrite +713 inserted IntegerDecl+ManyProperties +714 inserted ClassDecl+CountedLoop +715 inserted ObjectDecl+CountedLoop+BooleanDecl +716 inserted TryCatch+WhileLoop+ArrayDecl +717 inserted IntegerDecl+DynamicFunctionTransition +718 inserted FloatDecl+ElementsKind+ArgumentsUse +719 inserted Construct +720 inserted GeneratorIterate+UsingDecl+ConstructDecl +721 inserted ThisUse+UnboundMethodCall+ObjectDecl +722 inserted ObjectDecl +723 noop +724 inserted ElementStore +725 noop +726 inserted Assignment +727 inserted ObjectDecl +728 inserted DynamicFunctionTransition +729 inserted UsingDecl+ComputedDecl+ReturnOverride +730 inserted MethodCall+ConstructorFunction +731 inserted UnboundMethodCall +732 inserted Assignment+Switch+StringOps +733 inserted ElementLoad +734 inserted NativeCall+RegExpDecl+ArrowDecl +735 inserted IntegerDecl+ForIn+ArrowDecl +736 inserted PropertyLoad +737 inserted RawThrow+ShapeChange+FunctionDecl +738 inserted BuiltinCall+FunctionCall+ReturnOverride +739 inserted ConstructorFunction+BuiltinCall +740 inserted ArrowDecl+PropertyLoad+Update +741 inserted IntegerDecl+CountedLoop+IntegerDecl +742 inserted FloatDecl+Construct+FunctionCall +743 inserted BuiltinCall +744 inserted TypedArrayDecl+IntegerDecl +745 inserted ObjectDecl +746 inserted WrapperChain+PropertyLoad+StringOps +747 inserted ConstructorFunction+Recursion+ArrowDecl +748 inserted ClassDecl+BigIntDecl+MethodCall +749 inserted DynamicFunctionTransition+ConstructDecl +750 inserted ArrowStore+ThisUse +751 noop +752 inserted ComputedDecl +753 inserted TryCatch+OsrLoop+IntegerDecl +754 inserted BinaryOp +755 noop +756 inserted ReturnOverride+DynamicFunctionTransition+BuiltinOverwrite +757 inserted ObjectDecl +758 inserted Destructuring+ComputedDecl+BuiltinCall +759 inserted CountedLoop+MethodCall +760 inserted IfElse +761 inserted IntegerDecl +762 inserted ManyProperties +763 inserted PropertyStore+PrototypeMethodCall +764 inserted ElementsKind+WorkerSpawn+Iteration +765 inserted Assignment+PropertyStore+PrototypeSet +766 inserted Construct +767 inserted ReturnOverride+FreezeSeal +768 inserted NullishDecl+IntegerDecl +769 inserted BuiltinCall+ComputedDecl+JitOptimize +770 inserted ConstructorFunction +771 inserted BigIntDecl+BigIntDecl+FloatDecl +772 inserted ClassDecl+BooleanDecl +773 inserted FunctionDecl +774 inserted ForOf+StringDecl+MethodCall +775 inserted PropertyStore+ComputedDecl+ObjectDecl +776 inserted CountedLoop +777 inserted ManyProperties +778 inserted ArrowDecl +779 inserted CountedLoop+IfElse+JitBaseline +780 inserted CountedLoop+AsyncIife +781 inserted PropertyDelete+LabeledBlock +782 inserted JitOptimize+FunctionCall +783 inserted ArrayDecl+FunctionDecl +784 inserted BuiltinOverwrite+PropertyLoad+PrototypeMethodCall +785 inserted Assignment+ArrowStore +786 inserted CrossContextPrivateStore+StringOps+WorkerSpawn +787 inserted MethodCall+FreezeSeal +788 inserted ForOf +789 inserted BigIntDecl+IntegerDecl +790 inserted StringOps +791 inserted UnaryOp +792 inserted StringDecl +793 inserted ShapeChange+LabeledBlock +794 inserted FrozenArrayOps +795 inserted ComputedDecl+TypeCheck+GeneratorIterate +796 inserted ConstructorFunction+Throw +797 inserted Destructuring +798 inserted ShapeChange+TemplateDecl+Assignment +799 inserted UnboundMethodCall+TryCatch+UsingDecl +800 inserted TypeCheck +801 inserted ArrayDecl+BigIntDecl+BuiltinCall +802 inserted Compare +803 inserted TypedArrayDecl+FunctionDecl +804 inserted PropertyDelete+UnaryOp +805 inserted ConstructDecl+Compare +806 inserted FunctionDecl+UnboundMethodCall +807 inserted StringOps+UnboundMethodCall +808 inserted CountedLoop+ObjectDecl +809 inserted ElementsKind +810 inserted Construct +811 inserted FunctionDecl +812 inserted ArrayDecl+FunctionDecl+Switch +813 inserted BinaryOp+WrapperChain+ElementsKind +814 inserted PrototypeMethodCall +815 inserted FrozenArrayOps+ComputedDecl +816 inserted Assignment +817 inserted Destructuring +818 noop +819 inserted ComputedDecl +820 inserted Destructuring +821 inserted JitOptimize+PromiseThen +822 inserted ConstructorFunction +823 inserted ArrayDecl+PropertyDelete+TemplateDecl +824 inserted ValueOfOverride+MethodCall +825 inserted Assignment +826 inserted ArrayDecl +827 inserted ArrayDecl +828 inserted BigIntDecl+TypedArrayDecl +829 inserted ProxyDecl +830 inserted Recursion +831 inserted UsingDecl+StringDecl +832 noop +833 inserted Closure+IntlOps+Assignment +834 inserted TypedArrayOps+IntlOps +835 inserted PropertyStore +836 inserted LabeledBlock+DefineProperty +837 inserted MethodCall+LabeledBlock+Assignment +838 inserted CountedLoop +839 inserted DefineProperty +840 inserted FloatDecl+TemplateDecl+Recursion +841 inserted ProxyDecl+JitOptimize +842 inserted FunctionDecl+PropertyLoad +843 inserted PropertyStore+Iteration+ObjectDecl +844 inserted Assignment +845 inserted BinaryOp+CountedLoop+WhileLoop +846 inserted FunctionDecl+Destructuring +847 inserted IfElse +848 inserted ForOf+ElementLoad+PropertyLoad +849 inserted PrototypeMethodCall+Return +850 inserted Iife +851 inserted ElementsKind +852 inserted JitOptimize+FloatDecl +853 inserted CountedLoop +854 inserted StringDecl +855 inserted ObjectDecl+ConstructDecl +856 inserted MethodCall +857 inserted IntlOps +858 inserted Assignment+IntlOps +859 inserted UnboundMethodCall+GeneratorIterate+Recursion +860 inserted Assignment +861 noop +862 inserted PropertyLoad+CountedLoop+Update +863 inserted UsingDecl+IntegerDecl+ConstructDecl +864 inserted ElementLoad+IntegerDecl+FloatDecl +865 inserted Update+Gc+BuiltinCall +866 inserted PropertyStore+Assignment+ShapeChange +867 inserted JitOptimize +868 inserted Construct+Assignment +869 inserted ThisUse+ForOf +870 inserted ClassDecl+ObjectDecl +871 inserted Assignment +872 inserted ForOf+TypedArrayDecl+BuiltinOverwrite +873 inserted FreezeSeal+JitOptimize+IntlOps +874 inserted PromiseThen+ElementLoad +875 inserted FunctionCall+MethodCall +876 inserted RegExpDecl+ShapeChange+RawThrow +877 inserted ArrayDecl +878 inserted JitOptimize +879 inserted BinaryOp+ElementStore +880 inserted MethodCall+PropertyDelete +881 inserted ForOf +882 inserted MethodCall+ArrowStore+TemporalOps +883 inserted PrototypeMethodCall +884 inserted ElementStore+TemplateDecl+MethodCall +885 inserted Construct +886 inserted DynamicFunctionTransition+IfElse+ReturnOverride +887 inserted FloatDecl+ClassDecl +888 inserted FreezeSeal+PrototypeSet+Construct +889 inserted CountedLoop +890 inserted NativeCall +891 inserted BinaryOp +892 inserted IfElse +893 inserted ShapeChange+PrototypeSet+FloatDecl +894 inserted SpreadCall +895 inserted UnaryOp+Assignment +896 inserted BigIntDecl +897 inserted TemporalOps+ArrowDecl+TryCatch +898 inserted FloatDecl+ElementsKind +899 inserted IfElse +900 inserted SymbolDecl +901 inserted BinaryOp+CrossContextPrivateStore +902 inserted JitOptimize+LabeledBlock +903 inserted ComputedDecl+MethodCall +904 inserted ComputedDecl +905 inserted ThisUse +906 inserted StringDecl+FrozenArrayOps +907 inserted FunctionCall +908 inserted TypeCheck +909 inserted StringOps +910 inserted ComputedDecl+ComputedDecl+MethodCall +911 inserted FrozenArrayOps +912 inserted TryCatch+ElementLoad +913 inserted ArrowDecl+BooleanDecl+MethodCall +914 inserted ConstructDecl +915 inserted Assignment +916 inserted TryCatch+BinaryOp+CountedLoop +917 inserted IntegerDecl+IntegerDecl +918 inserted JitOptimize+FunctionDecl +919 inserted UsingDecl +920 inserted MethodCall +921 inserted BinaryOp+Iteration +922 inserted JitOptimize+UnboundMethodCall+FunctionCall +923 inserted ConstructDecl +924 inserted GeneratorIterate +925 inserted IntegerDecl+ComputedDecl+MethodCall +926 inserted ForOf+UnaryOp+ShapeChange +927 inserted PropertyLoad+TypedArrayOps +928 inserted WorkerSpawn+ArrowDecl +929 noop +930 inserted BooleanDecl +931 inserted ArrayDecl +932 inserted Construct+MethodCall+JitOptimize +933 inserted MethodCall+RegExpDecl+PropertyLoad +934 inserted ComputedDecl+PropertyLoad+PropertyLoad +935 inserted PropertyLoad+PropertyDelete+FunctionCall +936 inserted FunctionDecl+IfElse +937 inserted IfElse +938 inserted ElementsKind+FloatDecl +939 inserted ArgumentsUse +940 inserted Assignment +941 inserted StringOps+ConstructorFunction +942 inserted IfElse+ElementsKind+TemporalOps +943 inserted ElementLoad+BinaryOp +944 inserted RawThrow +945 inserted BuiltinOverwrite+MethodCall +946 inserted ConstructDecl +947 inserted FunctionCall+TypedArrayOps+BooleanDecl +948 inserted TypedArrayOps +949 inserted TypedArrayOps+WrapperChain+ObjectDecl +950 inserted ArrowDecl+Update+Deopt +951 inserted Deopt+FunctionDecl+PropertyStore +952 inserted MethodCall +953 inserted DynamicFunctionTransition+DynamicFunctionTransition +954 inserted JitOptimize +955 inserted ComputedDecl+ObjectDecl+FreezeSeal +956 inserted OsrLoop+ForOf +957 inserted ElementLoad +958 inserted ArrowDecl+IfElse+MethodCall +959 inserted FunctionCall+FloatDecl+UnboundMethodCall +960 inserted TryCatch+BuiltinCall+ArrowStore +961 inserted TemplateDecl+UnaryOp+Update +962 inserted Closure +963 inserted StringDecl+BooleanDecl +964 inserted NativeCall+PrototypeSet+UnboundMethodCall +965 inserted TemplateDecl+FunctionDecl+ConstructorFunction +966 inserted BooleanDecl +967 inserted DefineProperty+ProxyDecl+FunctionDecl +968 inserted FunctionCall+Closure +969 inserted Switch +970 inserted Assignment+ArrowDecl +971 inserted Assignment+PropertyLoad +972 inserted BinaryOp+ProxyDecl+PropertyStore +973 inserted BuiltinCall+FunctionCall+IntegerDecl +974 inserted ComputedDecl+Update +975 inserted IntlOps+FunctionCall+Assignment +976 inserted BuiltinOverwrite+BuiltinCall +977 inserted ForOf+TemporalOps+ClassDecl +978 inserted ProxyDecl +979 inserted ConstructDecl +980 inserted RegExpDecl+BinaryOp +981 inserted PropertyStore +982 inserted FunctionCall+NewTargetExpr +983 inserted PropertyLoad+FrozenArrayOps+ConstructDecl +984 inserted ConstructorFunction+ManyProperties +985 inserted ReturnOverride +986 inserted CountedLoop+TypedArrayDecl +987 inserted Deopt +988 inserted CrossContextPrivateStore+Construct+ArrayDecl +989 inserted Iteration +990 inserted ClassDecl+IfElse +991 inserted JitOptimize+ComputedDecl+FunctionDecl +992 inserted PrototypeSet+ClassDecl +993 inserted ArrayDecl+UsingDecl+Deopt +994 inserted MapSetOps +995 inserted ConstructDecl+Construct +996 inserted Construct+StringDecl +997 inserted FunctionDecl +998 inserted TryCatch+StringDecl +999 inserted IntlOps+DefineProperty+ValueOfOverride diff --git a/deps/v8/experimental/redline/testdata/selection/generator_outputs.trace b/deps/v8/experimental/redline/testdata/selection/generator_outputs.trace new file mode 100644 index 000000000000..09d3a679f43f --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/generator_outputs.trace @@ -0,0 +1,470 @@ +IntegerDecl 0 e927aa321a5c0e2f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntegerDecl 1 d1cd448a09ea2a5b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntegerDecl 2 1b25efd5bfafb6a0 let n = 42; let s = "text"; let a = [1, 2, 3]; const v0 = 9109; let o +IntegerDecl 3 a7c142938ed71051 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntegerDecl 4 30ad92463bce0bb4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FloatDecl 0 8bfdaac377cdf7b3 let v0 = (-9007199254740991); let n = 42; let s = "text"; let a = [1, +FloatDecl 1 13eeb02b23e75db8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FloatDecl 2 bb4b9d96be01936b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FloatDecl 3 0713d75decf4c949 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FloatDecl 4 d8c552e66d5da8c3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringDecl 0 4d17de4538bb89d8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringDecl 1 cd98622246df512b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringDecl 2 d35b978aa2337858 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringDecl 3 a80ab868befff0ec let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringDecl 4 d35b978aa2337858 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BooleanDecl 0 87741761c8218c3a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BooleanDecl 1 03b3cf63a74884e6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BooleanDecl 2 9e4c6be8c1c88a2a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BooleanDecl 3 74e73c63088b7fb2 let n = 42; let s = "text"; let b0 = false; let a = [1, 2, 3]; let o = +BooleanDecl 4 806767f2903f1278 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BigIntDecl 0 c23fa3772faa44da let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BigIntDecl 1 ce0fea6d44489e99 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BigIntDecl 2 359cb15572f79b14 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BigIntDecl 3 1225a992be699c2a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BigIntDecl 4 6d7976d82081baa8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RegExpDecl 0 a121759a6b0b5f8f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RegExpDecl 1 57bd6b9158f7a460 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RegExpDecl 2 2f1303b0baaabec2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RegExpDecl 3 242df484e5a89df9 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RegExpDecl 4 61a03c201973d9d9 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NullishDecl 0 2451f88fa2b1fc6a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NullishDecl 1 1540adcf895d9c56 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NullishDecl 2 c8ff3581d96866e3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NullishDecl 3 fbb56f1851379731 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NullishDecl 4 62b26b50dd8b3f70 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SymbolDecl 0 231d008c69910a7e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SymbolDecl 1 7ca4f70852edb3dd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SymbolDecl 2 b5e977fa69245a77 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SymbolDecl 3 a06af4993ccc3f27 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SymbolDecl 4 2b7ab35f00b39fd2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrayDecl 0 1b33b9ded28421f8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrayDecl 1 11ac1e068dd91d58 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrayDecl 2 40b40a10b7332016 const arr0 = [302395n]; let n = 42; let s = "text"; let a = [1, 2, 3]; +ArrayDecl 3 233b39c469ced728 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrayDecl 4 03aee093b95b9be9 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ObjectDecl 0 d8a57ccab377b006 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ObjectDecl 1 1f4718570f7d4779 let n = 42; let s = "text"; let obj0 = {a: n}; let a = [1, 2, 3]; let +ObjectDecl 2 c872aac0dfb4a731 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ObjectDecl 3 3eaa537ce5995f66 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ObjectDecl 4 d29b4181fa7484dc let n = 42; let s = "text"; let obj0 = {"length": 11}; let a = [1, 2, +ConstructDecl 0 1e93a9c7db96ab73 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructDecl 1 c524d88eac802135 let o0 = new Function("a", "return a"); let n = 42; let s = "text"; le +ConstructDecl 2 fe345a79b98cd2d2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructDecl 3 dfc16e64653096d1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructDecl 4 6de6cf30c911665c let n = 42; let s = "text"; let o0 = new Uint32Array([true, s, f, (-96 +TypedArrayDecl 0 3dc42ba462383164 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayDecl 1 9c7438de5b1aba15 let n = 42; let s = "text"; let a = [1, 2, 3]; let ta0 = new Uint16Arr +TypedArrayDecl 2 a79cad4551608b49 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayDecl 3 e2617509db04a5f7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayDecl 4 2f59cade95b1a87e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ComputedDecl 0 0476b496e31d7a29 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ComputedDecl 1 f3d09517d635a0a4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ComputedDecl 2 bf7114fd52fba3d1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ComputedDecl 3 debcb4b296dcbcf6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ComputedDecl 4 7d0e16c845274009 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemplateDecl 0 b749c1ef3c8f9512 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemplateDecl 1 eb83ff34e3b7475d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemplateDecl 2 395756c4279d336d let n = 42; let s = "text"; let a = [1, 2, 3]; let s0 = `b${n}a${n} `; +TemplateDecl 3 5065a8a073acf5df let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemplateDecl 4 657075434c4c4f59 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Destructuring 0 5e87ecfbb79518a0 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Destructuring 1 90726fa074d14f10 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Destructuring 2 47e1c5befdb99413 let n = 42; let [d0, ...rest0] = [{38: n, p: 498226n}, new Proxy([], { +Destructuring 3 5fb094ca1b8c4720 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Destructuring 4 fdfbddda576ffb93 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionDecl 0 18ccb2f0eda1c167 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionDecl 1 2c21996af764f783 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionDecl 2 26d20e1cd3178b70 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionDecl 3 fdd2b5e351062c66 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionDecl 4 e459a231032d9ec9 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowDecl 0 be55e1b25c8415a8 let n = 42; const f0 = function(a0, a1) { let arr0 = []; return a1 +ArrowDecl 1 5df0834dfd76b195 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowDecl 2 e98e0529f6d7e61f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowDecl 3 a342b345fd9c3722 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowDecl 4 4ca77b18f141184d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ClassDecl 0 68611ef119e30501 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ClassDecl 1 db010e154eddeb85 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ClassDecl 2 a7a783d92c4135ba let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ClassDecl 3 7b6c800d6a82ac36 let n = 42; let s = "text"; class C0 extends Function { constructor( +ClassDecl 4 16967d0f3f154b07 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iife 0 46c1a08062b17789 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iife 1 2c1290e69269d5eb let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iife 2 264f9fed2560f596 (function() { class C0 { constructor() { this[2] = f; +Iife 3 a190b1b44a500a84 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iife 4 cf61ea02804da90b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Closure 0 53aef6260a76b909 let n = 42; let s = "text"; let v0 = 9; let f0 = () => { v0 %= n; +Closure 1 2d1f8de421c4aa7f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Closure 2 7f80a44283918dea let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Closure 3 f685e26eff6df1ba let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Closure 4 40f91b7e981a85dd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BinaryOp 0 c4f2235234677590 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BinaryOp 1 ddc56a277a932fed let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BinaryOp 2 46310a316c79c467 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BinaryOp 3 1996c79ddc16a3a7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BinaryOp 4 a4929d95c02c0ce8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Compare 0 f0db1ec877fe64a3 let n = 42; let s = "text"; let b0 = new Function("a", "return a") !== +Compare 1 7ce7dd879e54249d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Compare 2 f675e3cc37fc72ba let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Compare 3 e6040eae1f6f48aa let n = 42; let s = "text"; let a = [1, 2, 3]; let b0 = "" >= n; let o +Compare 4 15ebfa38a0a5791d let n = 42; let b0 = n !== 7; let s = "text"; let a = [1, 2, 3]; let o +UnaryOp 0 0d33fec93cfb25e5 let n = 42; n++; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: +UnaryOp 1 184c6a9d8764cba2 let n = 42; var v0 = typeof n; let s = "text"; let a = [1, 2, 3]; let +UnaryOp 2 ca05301db2c21394 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnaryOp 3 c62fe5a4bd6d0fe6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnaryOp 4 90fe45b70cb87e8a let n = 42; let v0 = -n; let s = "text"; let a = [1, 2, 3]; let o = {x +Update 0 3b319c65e1c6390d let n = 42; let s = "text"; let a = [1, 2, 3]; n--; let o = {x: 1, y: +Update 1 84075c6b575c0847 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Update 2 8d7ab59dc38c526f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Update 3 35fadaf766e71101 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Update 4 4ea725f96ed3b513 let n = 42; let s = "text"; n++; let a = [1, 2, 3]; let o = {x: 1, y: +Assignment 0 6ea87eeccb0803c0 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Assignment 1 14754f3e5c88d9f2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Assignment 2 7061297f705fc7da let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Assignment 3 3bbfb5e1ffb8d4b1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Assignment 4 28ed3619e3edd36b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyLoad 0 9899942e0b0f86eb let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyLoad 1 9d99f2c45d825070 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyLoad 2 6aac094c54bd1769 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyLoad 3 b06c54fa236b8142 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyLoad 4 6579be7e6c8ae682 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyStore 0 8b0ff658ba4aa5ba let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyStore 1 1ebf8f5229844fa6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyStore 2 fb9274aaf6e8f807 let n = 42; let s = "text"; f.name = n; let a = [1, 2, 3]; let o = {x: +PropertyStore 3 ab9a8502a2ac4f9f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyStore 4 5e1ef7a0c0da2942 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementLoad 0 1b8ea8c01cba80c5 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementLoad 1 a03dccecbfe2b846 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementLoad 2 231e4164ea6b4d54 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementLoad 3 f3746f027e4fc1af let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementLoad 4 bd2848994167c5fe let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementStore 0 c9f878463492405b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementStore 1 3c1110bad16d326d noop +ElementStore 2 0901b3d1cc26ff84 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementStore 3 6a09da0212e682c3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementStore 4 faa413075f1f70ce let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyDelete 0 f78921c9be46a580 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyDelete 1 6674cdb2149c4065 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyDelete 2 3c1110bad16d326d noop +PropertyDelete 3 e369adae29108ba6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PropertyDelete 4 c19a9835413dc4ad let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MethodCall 0 2e004ea78ec3deee let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MethodCall 1 17296a0ac3de0bc2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MethodCall 2 ea2c75a2b9a65934 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MethodCall 3 8abf8e7e4c85c220 let n = 42; let s = "text"; let a = [1, 2, 3]; s.slice(10); let o = {x +MethodCall 4 bb9996fc6decd8fb let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionCall 0 741784451f1e03f0 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionCall 1 18e74c4dfaecb398 let n = 42; let v0 = f("éèà"); let s = "text"; let a = [1, 2, 3]; l +FunctionCall 2 742b8588adbbdcdb let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FunctionCall 3 70abb0ec022d8de4 let v0 = f(f, f); let n = 42; let s = "text"; let a = [1, 2, 3]; let o +FunctionCall 4 e9ad6b005293df57 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinCall 0 2e2b75e44c4503c4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinCall 1 33570bef966f7959 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinCall 2 f02edc0c529af65f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinCall 3 8815629472ea706c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinCall 4 950d7697470472b2 let v0 = Promise.reject(f); let n = 42; let s = "text"; let a = [1, 2, +Construct 0 cea245a7bde2cc0e let n = 42; let s = "text"; let a = [1, 2, 3]; const o0 = new Uint16Ar +Construct 1 ec6957e873527f4e let n = 42; let o0 = new f(/(?ms:[xyz]){2}ab+(?m:\cJ(?i:0+[A-Z_]ab)0|[ +Construct 2 805d5cbf5befe2aa let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Construct 3 f912d1189c548dbc let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Construct 4 4d589eca0df19114 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypeCheck 0 fa0d77ac3c4326b7 let b0 = "😀" in f; let n = 42; let s = "text"; let a = [1, 2, 3]; l +TypeCheck 1 cd0650227945e301 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypeCheck 2 b22e32d8123f45af let n = 42; var b0 = typeof n != "bigint"; let s = "text"; let a = [1, +TypeCheck 3 30face7241770731 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypeCheck 4 cdd089368664c7da let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SpreadCall 0 d929bafc94523901 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SpreadCall 1 f0eb21c16e1ad218 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SpreadCall 2 83ac8b9570fed73a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +SpreadCall 3 3c1110bad16d326d noop +SpreadCall 4 d28601acc25696d9 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringOps 0 04c909b364bd497f let n = 42; let s = "text"; let s0 = (s + "__proto__").repeat(4); let +StringOps 1 99402599e00ef6d7 let n = 42; let s = "text"; var s0 = s[0]; let a = [1, 2, 3]; let o = +StringOps 2 6a39ee093d477712 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringOps 3 e838149a7a4a5d1f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +StringOps 4 ea17e87a49d09ef6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayOps 0 d59a8f09b2b894ee let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayOps 1 bfbb3d2e0912ad2a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayOps 2 37a3319ea56a277c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayOps 3 5f1e3859e3e7b93d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TypedArrayOps 4 47d5d1cf21bf182f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MapSetOps 0 33443566dc5d4539 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MapSetOps 1 4f53558d3dd3b0fd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MapSetOps 2 2c6eeaaed42749ae let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MapSetOps 3 e7dedce127ecff1c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +MapSetOps 4 55d196618c5c29c7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntlOps 0 527c82fe676ad35e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntlOps 1 ffcf62984a7d4ae0 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntlOps 2 74b33f9eda2b1c4f let n = 42; let s = "text"; let a = [1, 2, 3]; let intl0 = new Intl.Pl +IntlOps 3 27dd0dcf8b3ed98d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IntlOps 4 0b70a7b5cde698c1 let n = 42; let s = "text"; var intl0 = new Intl.PluralRules("ar-EG", +FrozenArrayOps 0 b47df5ef5f720313 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FrozenArrayOps 1 85e73eb16e14a19f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FrozenArrayOps 2 f5feb3e0dce341e6 let n = 42; let s = "text"; var farr0 = Object.freeze([f]); const v0 = +FrozenArrayOps 3 d43a45480ffeb207 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FrozenArrayOps 4 967a20b0a07fd993 let n = 42; let s = "text"; let farr0 = Object.seal([s]); let v0 = far +TemporalOps 0 cf9e762b38927dee let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemporalOps 1 c25b7260b2a60201 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemporalOps 2 aacdd2dae5b78dc6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TemporalOps 3 357e40b1f1961168 let temp0 = new Temporal.Instant(123456789n); let r0; try { r0 = Tem +TemporalOps 4 c0dfa1a1f442f777 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WasmModule 0 3b9e697366cbb62e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WasmModule 1 cc7bc98aaf239ef6 const bytes0 = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 17, 3, +WasmModule 2 aa5e193fdef730d4 const bytes0 = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 30, 6, +WasmModule 3 3f330f1ab8ab352e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WasmModule 4 9d9fa66c07201b42 let n = 42; let s = "text"; let a = [1, 2, 3]; const bytes0 = new Uint +Iteration 0 5ce872d5f3c050ee let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iteration 1 9e1dd231acc56644 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iteration 2 c41a99bccef415ca let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iteration 3 0200042c2392fb34 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Iteration 4 9a6d7767b9ce7163 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DiscoveredApi 0 3c1110bad16d326d noop +DiscoveredApi 1 3c1110bad16d326d noop +DiscoveredApi 2 3c1110bad16d326d noop +DiscoveredApi 3 3c1110bad16d326d noop +DiscoveredApi 4 3c1110bad16d326d noop +PrototypeMethodCall 0 5c7932bd5e168f68 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeMethodCall 1 032ee8ae6ccf376f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeMethodCall 2 fb8b5596493f7b39 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeMethodCall 3 aa35f9308c7b5ceb let n = 42; let r0; try { r0 = Date.prototype.getFullYear.call([]); +PrototypeMethodCall 4 9838c58c9e21040b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnboundMethodCall 0 2e31977870ae0e6c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnboundMethodCall 1 d7580c31c5a6ba05 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnboundMethodCall 2 8f502edaa905c3ef let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnboundMethodCall 3 603e8514533bcb4d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UnboundMethodCall 4 12d7bbf37bb36077 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinOverwrite 0 2f2bb244a580ba27 let n = 42; let s = "text"; Iterator.from = function(a0, a1) { const +BuiltinOverwrite 1 1560196a06e5ec52 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinOverwrite 2 046b2041f6651638 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinOverwrite 3 77904ab49d463461 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BuiltinOverwrite 4 282714e396fe57e6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructorFunction 0 679f49b314daa83b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructorFunction 1 7ef184eec37f2b4f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructorFunction 2 ba9a4df64c6f3596 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ConstructorFunction 3 2693e18c72137806 let n = 42; function C0(a0, a1) { if (!new.target) { return new +ConstructorFunction 4 28807a1bb9cdefaa let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CountedLoop 0 c9107a3387c34f6a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CountedLoop 1 091afdf6c03a44f9 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CountedLoop 2 91da1e4799cf83cd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CountedLoop 3 ccb161483ecca3e0 for (let i0 = 0; i0 < (-9); i0++) { let v0 = (0, eval)("1+1"); } let +CountedLoop 4 d30681001c7ed41c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WhileLoop 0 54207e49044b74f1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WhileLoop 1 815256f695a7b516 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WhileLoop 2 84732beee7dda584 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WhileLoop 3 d5b27692eea7d274 let n = 42; let s = "text"; let a = [1, 2, 3]; let n0 = 0; do { let +WhileLoop 4 f261a2f53b0a3146 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForOf 0 320ba70528d2b08a for (let e0 of Object.keys(Int8Array)) { function rec0(d0) { if +ForOf 1 fa44ce02bc1ab828 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForOf 2 b1925621a3d08245 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForOf 3 fd8fcaddfb154caf let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForOf 4 4a718dc1d0adaeab let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForIn 0 e22acf3bb86d8e28 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForIn 1 a21ed18782e6bee5 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForIn 2 56cc81c5b7707657 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForIn 3 8c4c64f66ff17607 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ForIn 4 e39cab08045ad366 let n = 42; let s = "text"; let a = [1, 2, 3]; for (let k0 in [4]) { +IfElse 0 848ee64465f29196 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IfElse 1 cb817a5633b7849b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IfElse 2 5c4e1669ab359252 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IfElse 3 9053ad9ccb218fd4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +IfElse 4 f32a80844e8fbe80 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Switch 0 60f06d4de618eef1 let n = 42; switch (f) { case 9: function f0() { let v0 = +Switch 1 92fc8f1418c4b431 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Switch 2 556f9b8a5556ee37 let n = 42; let s = "text"; switch (s) { case 49929: class B0 { +Switch 3 3b58c45608929e8d let n = 42; switch (n) { case n: var m0 = f.call; let r0; +Switch 4 ea096cf820ccece8 let n = 42; let s = "text"; let a = [1, 2, 3]; switch ("toString" in { +TryCatch 0 5f2df9e141e25617 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TryCatch 1 883d611922c42aec let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TryCatch 2 18d99fee4c15c223 let n = 42; try { const v0 = 5; throw f; } catch { let o0 = new +TryCatch 3 91745fdc788ad397 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +TryCatch 4 e7e5c9dafd08d0e8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Throw 0 900a6aec15de6d09 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Throw 1 7e0bef672496e132 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Throw 2 311f5fba25b98410 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Throw 3 46103b053cc40f45 try { throw f; } catch (e0) {} let n = 42; let s = "text"; let a = [ +Throw 4 cc20ba700e94fb91 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +LabeledBlock 0 b4c504159a6f567d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +LabeledBlock 1 3116ada707a12837 let n = 42; let s = "text"; L0: { const v0 = new BigInt64Array(1); +LabeledBlock 2 bbbfabdb0876a3ee let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +LabeledBlock 3 4eab5efc52ef7120 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +LabeledBlock 4 4c14bf802fe9b144 let n = 42; let s = "text"; L0: { %CompileBaseline(f); f(n, new Ui +Return 0 3b839fb48f6ee6f2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Return 1 306cbba852db797d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Return 2 26d7f6ed91d5d71e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Return 3 97634560becc9e43 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Return 4 ab306353bc4b8e82 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BreakContinue 0 55750c67a65f7004 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BreakContinue 1 4ddb6bd5a368171e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BreakContinue 2 9ab58f462c9fc3b6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BreakContinue 3 6dd0f204fb20d002 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +BreakContinue 4 2c0ffe024cdf4d56 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitOptimize 0 b55c6300f9a377d7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitOptimize 1 16e6591c4d4c4758 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitOptimize 2 03cf8ebabefccef8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitOptimize 3 873cbf66f8ce35cf let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitOptimize 4 5f3f7882f3b92a1a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitBaseline 0 851224678766820b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitBaseline 1 c35e9c17806bce17 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitBaseline 2 830e31a10d4abc27 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitBaseline 3 9b2680deaa5ff899 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitBaseline 4 248ad7fb9784636c let n = 42; let s = "text"; let a = [1, 2, 3]; %CompileBaseline(f); f( +Deopt 0 7d172f4aca417f13 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Deopt 1 4bc84ef2c7e1ee7b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Deopt 2 f26af8207c77e9b3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Deopt 3 510e90f57e29b741 let n = 42; %DeoptimizeFunction(f); let s = "text"; let a = [1, 2, 3]; +Deopt 4 aeff274f9cb69dbd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +OsrLoop 0 27ade9e243f316fe let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +OsrLoop 1 a3930ceae52bff3d let n = 42; let s = "text"; for (let i0 = 0; i0 < 10; i0++) { if (i0 +OsrLoop 2 bb34929ab9ad8059 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +OsrLoop 3 42eb2fc7127afca4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +OsrLoop 4 3e087de209e7137e for (let i0 = 0; i0 < 5; i0++) { if (i0 === 32) { %OptimizeOsr() +NativeCall 0 1b035c7d9d8c5b4f let n = 42; let s = "text"; let a = [1, 2, 3]; let v0 = %HasDictionary +NativeCall 1 97f9f105049ab1dd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NativeCall 2 cb8a6892692b6723 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NativeCall 3 47129197c0970376 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NativeCall 4 5e8ee37c4be1b807 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Gc 0 2e28e2e3c22d80de let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Gc 1 60d32e81e006ba6e let n = 42; let s = "text"; gc(); let a = [1, 2, 3]; let o = {x: 1, y: +Gc 2 ca389f230e9b29d6 gc({execution: "async"}); let n = 42; let s = "text"; let a = [1, 2, 3 +Gc 3 8af22f5fed7a4eee let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Gc 4 336b5075ee6e4306 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeSet 0 6d3db32787e2a5f3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeSet 1 36e1809d0e35a541 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeSet 2 8f2e609fe86cfd0e f.__proto__ = f; let n = 42; let s = "text"; let a = [1, 2, 3]; let o +PrototypeSet 3 c2b9b6067cb2d879 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PrototypeSet 4 298ace00a2fb69af let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DefineProperty 0 647073e2288749e3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DefineProperty 1 32cf82f33412c796 Object.defineProperty({}, (-21.75), {value: (-4.440254125672173), writ +DefineProperty 2 82c67e4331482669 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DefineProperty 3 d15bc0e824ef1350 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DefineProperty 4 5fd56b8c2d88206a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ValueOfOverride 0 a7f701cc8ae8ef38 ({}[Symbol.toPrimitive] = () => 665917n); var v0 = {} + 96; let n = 42 +ValueOfOverride 1 ff262fbe8da9ff82 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ValueOfOverride 2 fcc9d1e0fff88476 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ValueOfOverride 3 a17eff224fd23545 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ValueOfOverride 4 988cc04c634f9a8f ({p: f, c: f}.valueOf = () => 2); var v0 = {p: f, c: f} + (-94.375); l +ElementsKind 0 e21f919dc5d4cbcb let n = 42; let arr0 = [{p: 2n, value: f, [7]: f}]; arr0.shift(); let +ElementsKind 1 6fc809d0da586d47 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementsKind 2 f8480a6b1e2b30f0 let arr0 = [new Object()]; %NormalizeElements(arr0); arr0.push(f); arr +ElementsKind 3 874af5694aabb8aa let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ElementsKind 4 3b1d3f38393b0c3a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FreezeSeal 0 7258823647c97181 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FreezeSeal 1 5171b5cf702ad031 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FreezeSeal 2 d77afd5f550b35fb let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FreezeSeal 3 7eb0b5437d884d92 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +FreezeSeal 4 dfb96195d15aa806 let n = 42; let s = "text"; let a = [1, 2, 3]; Object.preventExtension +ProxyDecl 0 dacd1fe65a6068e7 let proxy0 = new Proxy({}, {getOwnPropertyDescriptor(t0, k0) { retur +ProxyDecl 1 6f1367ca454cfb7f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ProxyDecl 2 52646197a81f8075 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ProxyDecl 3 4ee09dc8e03ac4c1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ProxyDecl 4 169cc926d9e6e91c let n = 42; let s = "text"; let proxy0 = new Proxy(s, {defineProperty( +With 0 e06b6dd0b6887129 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +With 1 db763d514faf41cb let n = 42; with (f) { f |= n; } let s = "text"; let a = [1, 2, 3]; +With 2 d9abb20776d893b7 let n = 42; let s = "text"; let a = [1, 2, 3]; with ([5, ...a, 19, 96, +With 3 0044ab53fb707278 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +With 4 9711b8e4999b0fcd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ShapeChange 0 d7a7b650901c6157 let n = 42; let s = "text"; let a = [1, 2, 3]; let obj0 = {p: "prototy +ShapeChange 1 383f21fde9b035df let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ShapeChange 2 e63c38fd42f2b4cc let n = 42; let obj0 = {p: f, y: /(?<!\B(?i:\b[xyz].?)\cJb)./, key: f} +ShapeChange 3 8f0c7960666e71e3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ShapeChange 4 b0dd2b09f7f48595 let n = 42; let s = "text"; let obj0 = {size: n, y: {a: n}}; delete ob +Eval 0 7fd79c914eb7e99c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Eval 1 9e4890e0eb281e0a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Eval 2 2ce06d76913e52d7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Eval 3 26a36bdee67277b8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Eval 4 c6e8e055531f54ab let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Recursion 0 79fac07139d847c8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Recursion 1 593f500be8384d58 let n = 42; let s = "text"; function rec0(d0) { const v0 = s[d0]; +Recursion 2 f8990874646a1360 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Recursion 3 d676c2b432959c26 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Recursion 4 e21d205ccc50892e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WrapperChain 0 ebc16e10c5cd3155 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WrapperChain 1 30c4df9a7d931a60 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WrapperChain 2 75e1d3520f83457e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WrapperChain 3 f6c6101b3dc0ddea let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WrapperChain 4 8e48052efb074ad4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ManyProperties 0 a2c3ab572e4027f4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ManyProperties 1 40dca84fa28879b9 let n = 42; let s = "text"; let a = [1, 2, 3]; let obj0 = s; for (let +ManyProperties 2 b23d00778397e3e5 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ManyProperties 3 265f4ff487964407 let n = 42; let obj0 = [undefined, f]; for (let i0 = 0; i0 < 128; i0++ +ManyProperties 4 d46fb10023c04158 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ReturnOverride 0 0a4d2fde3a7b5eb7 let n = 42; let s = "text"; let a = [1, 2, 3]; class B0 { constructo +ReturnOverride 1 20c913d317f00e24 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ReturnOverride 2 96dc0d9921736229 let n = 42; let s = "text"; class B0 { constructor(o0) { return +ReturnOverride 3 a397ca815ca0acb2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ReturnOverride 4 cfa9a93cb000de2c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArgumentsUse 0 c4990aca02847428 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArgumentsUse 1 f82bac662b57cfdd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArgumentsUse 2 52bf6f3ff3201dc1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArgumentsUse 3 52bf6f3ff3201dc1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArgumentsUse 4 fa638fca72884fc8 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ThisUse 0 29bab05a5c62f57f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ThisUse 1 9565df350f77ef25 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ThisUse 2 2c9cf887e447ad75 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ThisUse 3 3447c87ddeeda264 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ThisUse 4 83fc41237788ab5f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Await 0 3c1110bad16d326d noop +Await 1 3c1110bad16d326d noop +Await 2 3c1110bad16d326d noop +Await 3 3c1110bad16d326d noop +Await 4 3c1110bad16d326d noop +Yield 0 3c1110bad16d326d noop +Yield 1 3c1110bad16d326d noop +Yield 2 3c1110bad16d326d noop +Yield 3 3c1110bad16d326d noop +Yield 4 3c1110bad16d326d noop +AsyncIife 0 6a40efa33be59f47 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +AsyncIife 1 039ebffcba55bf61 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +AsyncIife 2 0bd62ee9aedc068f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +AsyncIife 3 bcf42907e0838541 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +AsyncIife 4 a2b4c27bc85aca01 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +GeneratorIterate 0 7f0e9fb553a4efdc let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +GeneratorIterate 1 c0932414ef9ef09e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +GeneratorIterate 2 be928494e0c535b2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +GeneratorIterate 3 248a673be7e19a85 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +GeneratorIterate 4 2b7a234adee6281d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PromiseThen 0 e7e10d5474ea5b6a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PromiseThen 1 3210e32ab6c7398d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PromiseThen 2 0d166dc5c4ef8696 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +PromiseThen 3 b14940cba3314c4d let n = 42; let s = "text"; Promise.resolve(true ?? f).then((v0) => { +PromiseThen 4 465f63fb7fed35e7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WorkerSpawn 0 42d53bb737152ff6 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WorkerSpawn 1 80de419722ab560a let w0 = new Worker("onmessage = function(e) { postMessage(e.data); }" +WorkerSpawn 2 d8e2706a9b45a489 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +WorkerSpawn 3 fbdbe624ed1841a6 let n = 42; let s = "text"; let w0 = new Worker("onmessage = function( +WorkerSpawn 4 be4956854b8ae32b let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowStore 0 ab28f573fe0cb5e7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowStore 1 f95296340537c4a3 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowStore 2 deb135d3981704d5 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +ArrowStore 3 e28dbbf3f44dd971 function f0() { const v0 = 255n; const v1 = f; var v2 = ["fcaw", +ArrowStore 4 abe0ff058ef42ddd let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DynamicFunctionTransition 0 7c481d460a2f3213 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DynamicFunctionTransition 1 36450bf1721e3a67 let n = 42; let s = "text"; let dynFn0 = Reflect.construct(Function, [ +DynamicFunctionTransition 2 a29bad378663ee38 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DynamicFunctionTransition 3 e4f438bb53beec77 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +DynamicFunctionTransition 4 0afbeb7b6b70cac6 let n = 42; let dynFn0 = new Function("'use strict'; " + "1"); dynFn0. +CrossContextPrivateStore 0 9fde8b6b37fb87fc let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CrossContextPrivateStore 1 7c195db234d9d9e5 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CrossContextPrivateStore 2 8b1138207d09f5f4 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CrossContextPrivateStore 3 a7ad7b8a820ff80f let n = 42; class PrivClass0 { #p0 = f; #p1 = f; #p2 = 1.1294121 +CrossContextPrivateStore 4 018ef033d6439880 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UsingDecl 0 b31a86379b4e5fc7 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UsingDecl 1 47a9444637a77f9c let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UsingDecl 2 86e003a1ee414580 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UsingDecl 3 420bc753d7ef748f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +UsingDecl 4 106f8ef2e53de039 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +AwaitUsingDecl 0 3c1110bad16d326d noop +AwaitUsingDecl 1 3c1110bad16d326d noop +AwaitUsingDecl 2 3c1110bad16d326d noop +AwaitUsingDecl 3 3c1110bad16d326d noop +AwaitUsingDecl 4 3c1110bad16d326d noop +RawThrow 0 bdc871ba79f2b38d let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RawThrow 1 c0ee9516a72befa1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RawThrow 2 8064773cd90f9e83 let n = 42; let s = "text"; let a = [1, 2, 3]; throw n; let o = {x: 1, +RawThrow 3 66026cd771054498 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +RawThrow 4 9fba1fda199a3d53 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NewTargetExpr 0 2fc176f45befbce2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NewTargetExpr 1 87451ef31cdbeb66 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NewTargetExpr 2 fe9e348275eb4986 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NewTargetExpr 3 6cbd57c33890cde2 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +NewTargetExpr 4 ed13c2a8ea07258e let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" diff --git a/deps/v8/experimental/redline/testdata/selection/generators.trace b/deps/v8/experimental/redline/testdata/selection/generators.trace new file mode 100644 index 000000000000..e428dd7069f5 --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/generators.trace @@ -0,0 +1,2000 @@ +0 PropertyStore +1 Gc +2 ArrowStore +3 ElementsKind +4 Closure +5 CountedLoop +6 TryCatch +7 CountedLoop +8 Destructuring +9 ElementStore +10 ArrayDecl +11 BigIntDecl +12 ComputedDecl +13 Deopt +14 BuiltinOverwrite +15 MethodCall +16 FloatDecl +17 Construct +18 PropertyStore +19 PropertyStore +20 ReturnOverride +21 DiscoveredApi +22 ManyProperties +23 ManyProperties +24 Update +25 IntegerDecl +26 WorkerSpawn +27 BuiltinOverwrite +28 ManyProperties +29 Eval +30 Iife +31 Iteration +32 IntegerDecl +33 BooleanDecl +34 TemplateDecl +35 StringDecl +36 Assignment +37 IfElse +38 UsingDecl +39 BuiltinOverwrite +40 Update +41 ElementStore +42 AsyncIife +43 PrototypeMethodCall +44 ClassDecl +45 ConstructorFunction +46 FloatDecl +47 PropertyLoad +48 CrossContextPrivateStore +49 DiscoveredApi +50 ForOf +51 ObjectDecl +52 WrapperChain +53 Recursion +54 JitOptimize +55 Update +56 ElementLoad +57 WhileLoop +58 ConstructDecl +59 BuiltinCall +60 IntegerDecl +61 PropertyStore +62 ManyProperties +63 UnboundMethodCall +64 UnaryOp +65 ForOf +66 ElementStore +67 Closure +68 TypedArrayDecl +69 ElementStore +70 MethodCall +71 Switch +72 SpreadCall +73 FloatDecl +74 ObjectDecl +75 CountedLoop +76 ElementStore +77 Assignment +78 JitOptimize +79 FunctionDecl +80 ElementsKind +81 ConstructorFunction +82 BigIntDecl +83 PropertyLoad +84 CrossContextPrivateStore +85 FloatDecl +86 IfElse +87 UnaryOp +88 Assignment +89 PropertyLoad +90 ElementsKind +91 Assignment +92 IfElse +93 FunctionDecl +94 StringOps +95 DiscoveredApi +96 IfElse +97 ArrayDecl +98 PropertyStore +99 BooleanDecl +100 TemplateDecl +101 PropertyLoad +102 ArrayDecl +103 MethodCall +104 Assignment +105 ElementLoad +106 Iteration +107 ForOf +108 MethodCall +109 OsrLoop +110 Switch +111 SpreadCall +112 TemplateDecl +113 Throw +114 StringOps +115 NativeCall +116 ArrayDecl +117 IntegerDecl +118 UnboundMethodCall +119 ArrayDecl +120 StringDecl +121 ClassDecl +122 TryCatch +123 Recursion +124 UsingDecl +125 ConstructorFunction +126 ElementStore +127 WhileLoop +128 ArrayDecl +129 WhileLoop +130 DefineProperty +131 TypeCheck +132 BuiltinOverwrite +133 ReturnOverride +134 JitOptimize +135 StringDecl +136 PrototypeMethodCall +137 MethodCall +138 TypedArrayOps +139 IntegerDecl +140 PrototypeSet +141 FunctionCall +142 BinaryOp +143 UnboundMethodCall +144 ObjectDecl +145 FunctionCall +146 Deopt +147 ObjectDecl +148 WhileLoop +149 BinaryOp +150 WrapperChain +151 DiscoveredApi +152 FunctionCall +153 FunctionCall +154 BinaryOp +155 RegExpDecl +156 ComputedDecl +157 Compare +158 Throw +159 ElementsKind +160 RegExpDecl +161 ManyProperties +162 ConstructDecl +163 TryCatch +164 TypeCheck +165 OsrLoop +166 IfElse +167 TryCatch +168 Switch +169 UnaryOp +170 PropertyStore +171 BinaryOp +172 IfElse +173 ReturnOverride +174 FunctionCall +175 FreezeSeal +176 ComputedDecl +177 FloatDecl +178 IntlOps +179 Assignment +180 IntlOps +181 ElementStore +182 DiscoveredApi +183 Closure +184 PrototypeSet +185 ArrayDecl +186 FloatDecl +187 TypedArrayDecl +188 ElementsKind +189 Assignment +190 Switch +191 Closure +192 MethodCall +193 TryCatch +194 ForOf +195 CountedLoop +196 BuiltinCall +197 ThisUse +198 JitOptimize +199 CrossContextPrivateStore +200 LabeledBlock +201 PromiseThen +202 ElementStore +203 TypedArrayOps +204 DiscoveredApi +205 ValueOfOverride +206 ElementsKind +207 FunctionCall +208 BinaryOp +209 AsyncIife +210 IntegerDecl +211 ForOf +212 Iteration +213 DiscoveredApi +214 ArrayDecl +215 PropertyStore +216 Return +217 Assignment +218 JitOptimize +219 PrototypeSet +220 DefineProperty +221 PropertyStore +222 ElementLoad +223 StringOps +224 LabeledBlock +225 ComputedDecl +226 StringDecl +227 IntegerDecl +228 FloatDecl +229 PrototypeSet +230 CountedLoop +231 CountedLoop +232 ArrayDecl +233 JitOptimize +234 PropertyStore +235 UnaryOp +236 DynamicFunctionTransition +237 ArrayDecl +238 MapSetOps +239 ClassDecl +240 DiscoveredApi +241 BooleanDecl +242 Construct +243 ElementStore +244 TypedArrayDecl +245 FunctionDecl +246 MapSetOps +247 Assignment +248 FunctionCall +249 NullishDecl +250 JitBaseline +251 ArrowDecl +252 DefineProperty +253 PrototypeMethodCall +254 Compare +255 FloatDecl +256 MethodCall +257 IntlOps +258 Eval +259 MethodCall +260 ArrowDecl +261 TypeCheck +262 Switch +263 Update +264 FunctionDecl +265 DynamicFunctionTransition +266 ForOf +267 ManyProperties +268 FunctionCall +269 WhileLoop +270 DiscoveredApi +271 UnaryOp +272 JitBaseline +273 PromiseThen +274 DiscoveredApi +275 FrozenArrayOps +276 JitOptimize +277 MethodCall +278 Deopt +279 BinaryOp +280 DiscoveredApi +281 IntlOps +282 ElementsKind +283 Switch +284 FunctionDecl +285 WorkerSpawn +286 ShapeChange +287 IntlOps +288 ShapeChange +289 JitOptimize +290 Compare +291 MethodCall +292 ForIn +293 Switch +294 Iife +295 MethodCall +296 CrossContextPrivateStore +297 BinaryOp +298 Assignment +299 ProxyDecl +300 RegExpDecl +301 CountedLoop +302 DiscoveredApi +303 ProxyDecl +304 Destructuring +305 ObjectDecl +306 ForIn +307 JitOptimize +308 DiscoveredApi +309 ConstructorFunction +310 ConstructorFunction +311 TypedArrayOps +312 WrapperChain +313 ArrowDecl +314 Closure +315 TypedArrayOps +316 FunctionDecl +317 IntegerDecl +318 FunctionDecl +319 Update +320 TypedArrayDecl +321 ElementsKind +322 ComputedDecl +323 BuiltinCall +324 ArrowDecl +325 ElementsKind +326 Switch +327 JitOptimize +328 TemporalOps +329 TypeCheck +330 BinaryOp +331 IntegerDecl +332 Assignment +333 ArrayDecl +334 ElementsKind +335 ArrayDecl +336 ShapeChange +337 IntegerDecl +338 NewTargetExpr +339 Deopt +340 UnboundMethodCall +341 Construct +342 OsrLoop +343 ArrowDecl +344 ClassDecl +345 ElementsKind +346 FloatDecl +347 ForIn +348 ArrayDecl +349 PropertyStore +350 Iteration +351 FunctionDecl +352 TryCatch +353 DiscoveredApi +354 DefineProperty +355 ShapeChange +356 PropertyLoad +357 FunctionCall +358 DiscoveredApi +359 ConstructorFunction +360 ClassDecl +361 BinaryOp +362 BinaryOp +363 PropertyLoad +364 ForOf +365 Update +366 ComputedDecl +367 ComputedDecl +368 UsingDecl +369 ConstructorFunction +370 ObjectDecl +371 PropertyStore +372 ArrowStore +373 NativeCall +374 WrapperChain +375 JitOptimize +376 GeneratorIterate +377 ProxyDecl +378 BinaryOp +379 PropertyStore +380 PrototypeMethodCall +381 Construct +382 ClassDecl +383 SpreadCall +384 BinaryOp +385 Assignment +386 ObjectDecl +387 PromiseThen +388 Update +389 ElementsKind +390 TypedArrayOps +391 ElementsKind +392 DiscoveredApi +393 Construct +394 FunctionCall +395 WrapperChain +396 DiscoveredApi +397 DiscoveredApi +398 TemplateDecl +399 SpreadCall +400 StringOps +401 ReturnOverride +402 UnaryOp +403 NullishDecl +404 Assignment +405 IntlOps +406 WrapperChain +407 ReturnOverride +408 MethodCall +409 CountedLoop +410 ObjectDecl +411 IntegerDecl +412 ThisUse +413 TemplateDecl +414 BigIntDecl +415 ArrowDecl +416 Assignment +417 StringOps +418 DiscoveredApi +419 UnaryOp +420 ShapeChange +421 ConstructorFunction +422 ComputedDecl +423 Construct +424 CountedLoop +425 UnboundMethodCall +426 CountedLoop +427 FloatDecl +428 DiscoveredApi +429 UnboundMethodCall +430 RawThrow +431 Destructuring +432 PropertyStore +433 ArrayDecl +434 Recursion +435 PrototypeMethodCall +436 ThisUse +437 UnaryOp +438 PropertyLoad +439 IntegerDecl +440 ObjectDecl +441 Iteration +442 PropertyStore +443 MethodCall +444 TemporalOps +445 MethodCall +446 WhileLoop +447 ObjectDecl +448 PropertyLoad +449 UnaryOp +450 WhileLoop +451 TemplateDecl +452 ConstructorFunction +453 JitOptimize +454 WorkerSpawn +455 IntegerDecl +456 FunctionCall +457 JitOptimize +458 IfElse +459 IfElse +460 FunctionCall +461 Construct +462 DefineProperty +463 ArrowStore +464 ElementLoad +465 ManyProperties +466 BigIntDecl +467 ElementsKind +468 CrossContextPrivateStore +469 Return +470 PropertyStore +471 IntegerDecl +472 FunctionCall +473 TemporalOps +474 PropertyStore +475 IntlOps +476 UnaryOp +477 ThisUse +478 DiscoveredApi +479 BuiltinCall +480 ReturnOverride +481 PrototypeMethodCall +482 RegExpDecl +483 ElementsKind +484 ArrayDecl +485 ShapeChange +486 FunctionCall +487 StringOps +488 JitOptimize +489 CrossContextPrivateStore +490 ElementsKind +491 CountedLoop +492 FunctionCall +493 ObjectDecl +494 ArrayDecl +495 ForIn +496 PropertyStore +497 Assignment +498 TryCatch +499 CountedLoop +500 MapSetOps +501 ConstructDecl +502 BigIntDecl +503 BuiltinCall +504 PropertyLoad +505 BuiltinOverwrite +506 PromiseThen +507 ArrowDecl +508 Destructuring +509 PropertyDelete +510 BuiltinCall +511 FunctionCall +512 PropertyStore +513 WhileLoop +514 Recursion +515 UnboundMethodCall +516 PropertyStore +517 ComputedDecl +518 JitOptimize +519 Iife +520 Recursion +521 JitOptimize +522 ReturnOverride +523 FloatDecl +524 Throw +525 ElementLoad +526 ObjectDecl +527 IfElse +528 JitOptimize +529 PromiseThen +530 LabeledBlock +531 ShapeChange +532 FunctionCall +533 TemplateDecl +534 Assignment +535 CountedLoop +536 Closure +537 TryCatch +538 ComputedDecl +539 DiscoveredApi +540 BinaryOp +541 WorkerSpawn +542 ValueOfOverride +543 BooleanDecl +544 ElementLoad +545 ObjectDecl +546 ForOf +547 IntegerDecl +548 IfElse +549 ConstructDecl +550 MethodCall +551 LabeledBlock +552 CountedLoop +553 CountedLoop +554 Destructuring +555 MapSetOps +556 GeneratorIterate +557 WrapperChain +558 Closure +559 BinaryOp +560 IntegerDecl +561 OsrLoop +562 Update +563 UnaryOp +564 ManyProperties +565 FunctionCall +566 BuiltinCall +567 JitOptimize +568 ArrowDecl +569 PropertyLoad +570 CountedLoop +571 JitOptimize +572 PropertyLoad +573 Compare +574 SymbolDecl +575 PromiseThen +576 DiscoveredApi +577 UsingDecl +578 FunctionDecl +579 StringDecl +580 IntegerDecl +581 RawThrow +582 ElementsKind +583 Construct +584 Closure +585 FloatDecl +586 IfElse +587 BuiltinCall +588 Compare +589 ForOf +590 FrozenArrayOps +591 UnboundMethodCall +592 PropertyLoad +593 ConstructDecl +594 PropertyStore +595 CrossContextPrivateStore +596 BuiltinOverwrite +597 TemporalOps +598 Switch +599 TryCatch +600 ComputedDecl +601 BuiltinCall +602 CrossContextPrivateStore +603 StringDecl +604 TemporalOps +605 PropertyStore +606 LabeledBlock +607 ElementLoad +608 ObjectDecl +609 TryCatch +610 BinaryOp +611 ClassDecl +612 Update +613 ElementStore +614 RegExpDecl +615 BinaryOp +616 FloatDecl +617 IntlOps +618 UsingDecl +619 Assignment +620 Recursion +621 PropertyLoad +622 PropertyStore +623 OsrLoop +624 ConstructorFunction +625 FreezeSeal +626 Update +627 ElementStore +628 ArrowDecl +629 DynamicFunctionTransition +630 PrototypeMethodCall +631 ConstructDecl +632 BuiltinCall +633 IntegerDecl +634 ArrowStore +635 ArrowDecl +636 SymbolDecl +637 ComputedDecl +638 ThisUse +639 IntegerDecl +640 ComputedDecl +641 TemplateDecl +642 ArrowStore +643 TryCatch +644 ElementStore +645 FunctionCall +646 IntegerDecl +647 TypedArrayOps +648 IntlOps +649 Gc +650 DiscoveredApi +651 PropertyLoad +652 FunctionCall +653 Destructuring +654 FunctionDecl +655 BuiltinCall +656 FloatDecl +657 FunctionDecl +658 NativeCall +659 DynamicFunctionTransition +660 DiscoveredApi +661 ValueOfOverride +662 PromiseThen +663 Iife +664 FunctionCall +665 ArrayDecl +666 ArrayDecl +667 TryCatch +668 FunctionCall +669 TryCatch +670 FunctionCall +671 FunctionCall +672 PropertyStore +673 PromiseThen +674 ArrayDecl +675 JitOptimize +676 CountedLoop +677 MethodCall +678 Construct +679 CountedLoop +680 ElementLoad +681 FunctionCall +682 CountedLoop +683 BuiltinCall +684 BinaryOp +685 OsrLoop +686 PropertyStore +687 PropertyStore +688 DefineProperty +689 ConstructDecl +690 BuiltinCall +691 WrapperChain +692 Update +693 UnaryOp +694 IfElse +695 LabeledBlock +696 DiscoveredApi +697 DiscoveredApi +698 ComputedDecl +699 DiscoveredApi +700 BuiltinCall +701 DefineProperty +702 BuiltinCall +703 BuiltinCall +704 SymbolDecl +705 ConstructDecl +706 ConstructorFunction +707 RegExpDecl +708 PropertyStore +709 ElementsKind +710 StringOps +711 PropertyLoad +712 ArgumentsUse +713 FunctionDecl +714 ElementsKind +715 DiscoveredApi +716 Construct +717 LabeledBlock +718 UnaryOp +719 ThisUse +720 ArrayDecl +721 SpreadCall +722 DiscoveredApi +723 UsingDecl +724 ForOf +725 FunctionDecl +726 FunctionCall +727 ConstructDecl +728 ValueOfOverride +729 Iife +730 ArrayDecl +731 FunctionDecl +732 JitOptimize +733 ObjectDecl +734 DiscoveredApi +735 FunctionCall +736 Compare +737 BuiltinCall +738 ElementLoad +739 Return +740 FunctionDecl +741 TemplateDecl +742 WhileLoop +743 ConstructDecl +744 PropertyLoad +745 FunctionCall +746 PropertyLoad +747 ComputedDecl +748 WrapperChain +749 BuiltinCall +750 UsingDecl +751 BuiltinCall +752 PropertyStore +753 MapSetOps +754 Update +755 ArrayDecl +756 CrossContextPrivateStore +757 SpreadCall +758 CountedLoop +759 SpreadCall +760 Throw +761 FrozenArrayOps +762 CountedLoop +763 NullishDecl +764 ConstructDecl +765 PropertyStore +766 IntlOps +767 PropertyStore +768 PropertyLoad +769 FunctionCall +770 PromiseThen +771 ConstructDecl +772 PropertyLoad +773 DiscoveredApi +774 ElementStore +775 DiscoveredApi +776 Recursion +777 BuiltinOverwrite +778 UnboundMethodCall +779 WhileLoop +780 TemporalOps +781 Compare +782 ArrayDecl +783 BinaryOp +784 ThisUse +785 FunctionCall +786 PrototypeMethodCall +787 Construct +788 Destructuring +789 ElementsKind +790 Assignment +791 FunctionDecl +792 PropertyStore +793 ThisUse +794 ComputedDecl +795 UsingDecl +796 WrapperChain +797 ArrowStore +798 FloatDecl +799 ArrowDecl +800 ElementLoad +801 DynamicFunctionTransition +802 ComputedDecl +803 TypedArrayDecl +804 ObjectDecl +805 ArrayDecl +806 TemporalOps +807 MethodCall +808 Recursion +809 BinaryOp +810 DynamicFunctionTransition +811 PropertyDelete +812 ClassDecl +813 WrapperChain +814 MethodCall +815 StringOps +816 JitOptimize +817 PropertyStore +818 ForOf +819 GeneratorIterate +820 FunctionDecl +821 BuiltinCall +822 CountedLoop +823 ShapeChange +824 TemplateDecl +825 ElementsKind +826 StringDecl +827 FunctionCall +828 Iife +829 PrototypeMethodCall +830 BooleanDecl +831 ArrayDecl +832 JitOptimize +833 WhileLoop +834 ManyProperties +835 IfElse +836 IfElse +837 IfElse +838 PropertyLoad +839 DiscoveredApi +840 TryCatch +841 ObjectDecl +842 BigIntDecl +843 DynamicFunctionTransition +844 ComputedDecl +845 PrototypeMethodCall +846 BinaryOp +847 WhileLoop +848 DiscoveredApi +849 BinaryOp +850 TypeCheck +851 BigIntDecl +852 IfElse +853 Iife +854 UnaryOp +855 ObjectDecl +856 WorkerSpawn +857 FloatDecl +858 FunctionCall +859 BinaryOp +860 UnboundMethodCall +861 Recursion +862 Compare +863 JitOptimize +864 ConstructDecl +865 CountedLoop +866 UnboundMethodCall +867 RawThrow +868 FloatDecl +869 ForOf +870 JitOptimize +871 DiscoveredApi +872 PrototypeSet +873 SpreadCall +874 Closure +875 IfElse +876 Switch +877 ClassDecl +878 FunctionDecl +879 DefineProperty +880 Assignment +881 TemporalOps +882 MethodCall +883 IntegerDecl +884 DefineProperty +885 JitOptimize +886 PromiseThen +887 ElementLoad +888 PropertyDelete +889 CrossContextPrivateStore +890 MethodCall +891 BuiltinOverwrite +892 ConstructorFunction +893 ReturnOverride +894 Assignment +895 StringDecl +896 ElementsKind +897 Recursion +898 Assignment +899 ArrayDecl +900 ValueOfOverride +901 DiscoveredApi +902 DiscoveredApi +903 AsyncIife +904 ArrowStore +905 ElementsKind +906 ElementsKind +907 ArrowDecl +908 DiscoveredApi +909 Update +910 MethodCall +911 ShapeChange +912 WorkerSpawn +913 PrototypeMethodCall +914 FunctionDecl +915 ArrayDecl +916 WrapperChain +917 Throw +918 FunctionCall +919 DiscoveredApi +920 ProxyDecl +921 JitOptimize +922 BooleanDecl +923 IfElse +924 FunctionDecl +925 Switch +926 PropertyStore +927 CrossContextPrivateStore +928 JitOptimize +929 FunctionDecl +930 BigIntDecl +931 IfElse +932 WhileLoop +933 ArrayDecl +934 BuiltinCall +935 AsyncIife +936 DiscoveredApi +937 CountedLoop +938 Assignment +939 PropertyStore +940 ArrayDecl +941 Compare +942 WrapperChain +943 UnboundMethodCall +944 DiscoveredApi +945 LabeledBlock +946 UnboundMethodCall +947 ProxyDecl +948 SpreadCall +949 BooleanDecl +950 BinaryOp +951 Iife +952 AsyncIife +953 Recursion +954 DiscoveredApi +955 Assignment +956 NativeCall +957 TryCatch +958 ArrowDecl +959 TemporalOps +960 ConstructDecl +961 MethodCall +962 PropertyLoad +963 Recursion +964 IfElse +965 Construct +966 TypedArrayOps +967 ClassDecl +968 ComputedDecl +969 UnaryOp +970 StringDecl +971 MapSetOps +972 TypeCheck +973 DiscoveredApi +974 CountedLoop +975 StringDecl +976 BooleanDecl +977 PropertyLoad +978 TypedArrayOps +979 ForOf +980 FunctionDecl +981 ArrayDecl +982 Update +983 PropertyLoad +984 PropertyDelete +985 ComputedDecl +986 ElementLoad +987 TypeCheck +988 ObjectDecl +989 CrossContextPrivateStore +990 ObjectDecl +991 PrototypeSet +992 TypedArrayOps +993 ForIn +994 ShapeChange +995 DiscoveredApi +996 ComputedDecl +997 FunctionCall +998 Construct +999 ElementStore +1000 ArrayDecl +1001 JitOptimize +1002 ArrayDecl +1003 ReturnOverride +1004 ComputedDecl +1005 ElementStore +1006 SymbolDecl +1007 ThisUse +1008 RawThrow +1009 ConstructDecl +1010 PropertyDelete +1011 ClassDecl +1012 Iife +1013 PropertyStore +1014 ElementLoad +1015 ElementsKind +1016 Assignment +1017 BuiltinCall +1018 JitBaseline +1019 PromiseThen +1020 IntegerDecl +1021 MethodCall +1022 StringDecl +1023 Recursion +1024 BinaryOp +1025 BuiltinCall +1026 Gc +1027 PropertyLoad +1028 WorkerSpawn +1029 BooleanDecl +1030 Assignment +1031 IfElse +1032 BuiltinCall +1033 ObjectDecl +1034 ManyProperties +1035 RegExpDecl +1036 ForOf +1037 CrossContextPrivateStore +1038 NullishDecl +1039 TryCatch +1040 BuiltinCall +1041 ConstructorFunction +1042 ElementStore +1043 FunctionCall +1044 ArrayDecl +1045 IfElse +1046 ArrowStore +1047 ConstructDecl +1048 LabeledBlock +1049 ComputedDecl +1050 UnboundMethodCall +1051 Assignment +1052 DiscoveredApi +1053 ForOf +1054 MethodCall +1055 CountedLoop +1056 Recursion +1057 Construct +1058 TypedArrayOps +1059 StringDecl +1060 DiscoveredApi +1061 AsyncIife +1062 ConstructorFunction +1063 ElementStore +1064 DefineProperty +1065 OsrLoop +1066 UnboundMethodCall +1067 Iteration +1068 FreezeSeal +1069 ConstructDecl +1070 UnaryOp +1071 Update +1072 ComputedDecl +1073 Destructuring +1074 Assignment +1075 PropertyStore +1076 DiscoveredApi +1077 DiscoveredApi +1078 DiscoveredApi +1079 MethodCall +1080 TypedArrayOps +1081 ProxyDecl +1082 TypeCheck +1083 PrototypeMethodCall +1084 JitOptimize +1085 BinaryOp +1086 ArrayDecl +1087 Assignment +1088 FunctionDecl +1089 ElementLoad +1090 Construct +1091 ArrowDecl +1092 ElementStore +1093 TypedArrayOps +1094 ForOf +1095 Assignment +1096 WhileLoop +1097 Deopt +1098 UsingDecl +1099 IntegerDecl +1100 ProxyDecl +1101 OsrLoop +1102 PropertyLoad +1103 ObjectDecl +1104 ShapeChange +1105 BuiltinOverwrite +1106 TryCatch +1107 IntegerDecl +1108 FunctionDecl +1109 IntegerDecl +1110 OsrLoop +1111 DefineProperty +1112 IntlOps +1113 BinaryOp +1114 TryCatch +1115 TryCatch +1116 DiscoveredApi +1117 Closure +1118 ComputedDecl +1119 ThisUse +1120 JitOptimize +1121 Assignment +1122 ArrowDecl +1123 ThisUse +1124 BreakContinue +1125 Destructuring +1126 ThisUse +1127 JitOptimize +1128 JitOptimize +1129 UnboundMethodCall +1130 Assignment +1131 Update +1132 IfElse +1133 NativeCall +1134 ForIn +1135 DefineProperty +1136 ComputedDecl +1137 PrototypeMethodCall +1138 ObjectDecl +1139 TypedArrayDecl +1140 RegExpDecl +1141 BinaryOp +1142 ForOf +1143 IntegerDecl +1144 ReturnOverride +1145 Compare +1146 FloatDecl +1147 FunctionCall +1148 ProxyDecl +1149 BooleanDecl +1150 DiscoveredApi +1151 Update +1152 ClassDecl +1153 AsyncIife +1154 NewTargetExpr +1155 ElementLoad +1156 PropertyLoad +1157 FunctionCall +1158 ElementLoad +1159 Assignment +1160 PropertyStore +1161 RegExpDecl +1162 ReturnOverride +1163 ElementsKind +1164 DiscoveredApi +1165 OsrLoop +1166 BigIntDecl +1167 ObjectDecl +1168 TemporalOps +1169 Construct +1170 StringOps +1171 UsingDecl +1172 JitOptimize +1173 UnaryOp +1174 ElementStore +1175 FloatDecl +1176 Recursion +1177 FloatDecl +1178 With +1179 CountedLoop +1180 ReturnOverride +1181 ManyProperties +1182 TemplateDecl +1183 StringDecl +1184 BinaryOp +1185 Recursion +1186 TypeCheck +1187 NativeCall +1188 IntegerDecl +1189 ElementLoad +1190 JitOptimize +1191 BinaryOp +1192 WorkerSpawn +1193 BigIntDecl +1194 CountedLoop +1195 IntegerDecl +1196 OsrLoop +1197 MapSetOps +1198 CountedLoop +1199 ComputedDecl +1200 TryCatch +1201 DiscoveredApi +1202 ElementsKind +1203 TypedArrayDecl +1204 StringDecl +1205 PropertyStore +1206 JitOptimize +1207 SymbolDecl +1208 DiscoveredApi +1209 Assignment +1210 ManyProperties +1211 PropertyStore +1212 ElementsKind +1213 ElementsKind +1214 BinaryOp +1215 ThisUse +1216 TryCatch +1217 PrototypeMethodCall +1218 IfElse +1219 ArgumentsUse +1220 PropertyLoad +1221 ReturnOverride +1222 WrapperChain +1223 FunctionCall +1224 Assignment +1225 ClassDecl +1226 StringDecl +1227 BuiltinCall +1228 CountedLoop +1229 TypedArrayDecl +1230 FunctionDecl +1231 BigIntDecl +1232 UsingDecl +1233 ConstructDecl +1234 ManyProperties +1235 ArrayDecl +1236 JitOptimize +1237 ElementsKind +1238 FunctionCall +1239 DiscoveredApi +1240 TypedArrayDecl +1241 OsrLoop +1242 FunctionDecl +1243 PromiseThen +1244 MethodCall +1245 DiscoveredApi +1246 MethodCall +1247 SymbolDecl +1248 TryCatch +1249 DefineProperty +1250 JitOptimize +1251 BinaryOp +1252 WhileLoop +1253 BuiltinOverwrite +1254 BinaryOp +1255 FunctionDecl +1256 UnaryOp +1257 Construct +1258 PrototypeSet +1259 ComputedDecl +1260 CountedLoop +1261 MethodCall +1262 TemplateDecl +1263 Switch +1264 OsrLoop +1265 Deopt +1266 BuiltinCall +1267 DefineProperty +1268 JitOptimize +1269 TypeCheck +1270 CountedLoop +1271 BuiltinCall +1272 FreezeSeal +1273 ArrayDecl +1274 RegExpDecl +1275 PropertyDelete +1276 IntegerDecl +1277 JitOptimize +1278 ConstructorFunction +1279 ArrayDecl +1280 TypedArrayOps +1281 Assignment +1282 BuiltinCall +1283 ManyProperties +1284 ThisUse +1285 PrototypeMethodCall +1286 WorkerSpawn +1287 DiscoveredApi +1288 DiscoveredApi +1289 ArrayDecl +1290 UnaryOp +1291 ConstructorFunction +1292 NativeCall +1293 BuiltinCall +1294 Compare +1295 ElementsKind +1296 ElementsKind +1297 ReturnOverride +1298 JitBaseline +1299 ElementLoad +1300 WhileLoop +1301 ObjectDecl +1302 LabeledBlock +1303 FunctionCall +1304 ElementStore +1305 ComputedDecl +1306 FunctionDecl +1307 ConstructDecl +1308 JitBaseline +1309 IntlOps +1310 JitOptimize +1311 PropertyStore +1312 UnboundMethodCall +1313 FunctionDecl +1314 ClassDecl +1315 ClassDecl +1316 DiscoveredApi +1317 TypedArrayDecl +1318 BuiltinCall +1319 TypedArrayOps +1320 GeneratorIterate +1321 ComputedDecl +1322 BinaryOp +1323 FunctionCall +1324 BinaryOp +1325 ProxyDecl +1326 Destructuring +1327 JitOptimize +1328 MethodCall +1329 WrapperChain +1330 ConstructorFunction +1331 ElementStore +1332 ElementLoad +1333 PropertyStore +1334 DefineProperty +1335 ArrowDecl +1336 UnboundMethodCall +1337 PropertyStore +1338 With +1339 BinaryOp +1340 FloatDecl +1341 FunctionCall +1342 PropertyStore +1343 JitOptimize +1344 ManyProperties +1345 ProxyDecl +1346 NativeCall +1347 Destructuring +1348 Construct +1349 IfElse +1350 ElementStore +1351 WrapperChain +1352 JitOptimize +1353 PropertyLoad +1354 Iteration +1355 FunctionDecl +1356 NewTargetExpr +1357 ShapeChange +1358 Update +1359 BuiltinCall +1360 FunctionCall +1361 PrototypeSet +1362 BigIntDecl +1363 ThisUse +1364 PropertyLoad +1365 DiscoveredApi +1366 ForOf +1367 JitBaseline +1368 FunctionCall +1369 JitOptimize +1370 IntegerDecl +1371 SpreadCall +1372 MethodCall +1373 TypeCheck +1374 CountedLoop +1375 ArrayDecl +1376 DiscoveredApi +1377 WorkerSpawn +1378 BuiltinCall +1379 BinaryOp +1380 WhileLoop +1381 Iife +1382 TypedArrayDecl +1383 PropertyStore +1384 IfElse +1385 TryCatch +1386 ProxyDecl +1387 FrozenArrayOps +1388 ArrayDecl +1389 ReturnOverride +1390 MethodCall +1391 ArrowDecl +1392 ArrowDecl +1393 ElementsKind +1394 TemplateDecl +1395 BinaryOp +1396 ElementLoad +1397 ComputedDecl +1398 FunctionDecl +1399 FunctionCall +1400 IntegerDecl +1401 CountedLoop +1402 ObjectDecl +1403 BinaryOp +1404 IntegerDecl +1405 WrapperChain +1406 OsrLoop +1407 BinaryOp +1408 ForOf +1409 FunctionDecl +1410 UsingDecl +1411 MethodCall +1412 DiscoveredApi +1413 IntegerDecl +1414 FunctionCall +1415 ConstructDecl +1416 ElementsKind +1417 JitOptimize +1418 Construct +1419 DiscoveredApi +1420 FloatDecl +1421 ArrowStore +1422 Destructuring +1423 AsyncIife +1424 ElementLoad +1425 Update +1426 FunctionDecl +1427 FunctionCall +1428 ForOf +1429 BuiltinCall +1430 DiscoveredApi +1431 DefineProperty +1432 IfElse +1433 ArrayDecl +1434 PropertyLoad +1435 ForOf +1436 ProxyDecl +1437 FunctionDecl +1438 IfElse +1439 ClassDecl +1440 BinaryOp +1441 DynamicFunctionTransition +1442 ConstructDecl +1443 TypeCheck +1444 SpreadCall +1445 IfElse +1446 Iteration +1447 Iife +1448 CrossContextPrivateStore +1449 ArrayDecl +1450 ArrayDecl +1451 Assignment +1452 BinaryOp +1453 ClassDecl +1454 DiscoveredApi +1455 WhileLoop +1456 BuiltinCall +1457 NewTargetExpr +1458 FunctionCall +1459 JitBaseline +1460 RawThrow +1461 ConstructDecl +1462 IntegerDecl +1463 ClassDecl +1464 StringDecl +1465 DiscoveredApi +1466 MethodCall +1467 ArrowStore +1468 DiscoveredApi +1469 ShapeChange +1470 ObjectDecl +1471 ComputedDecl +1472 ComputedDecl +1473 RegExpDecl +1474 ArrowStore +1475 Recursion +1476 PropertyLoad +1477 PropertyLoad +1478 ProxyDecl +1479 Compare +1480 ElementLoad +1481 FloatDecl +1482 WorkerSpawn +1483 TemporalOps +1484 BuiltinCall +1485 DiscoveredApi +1486 NewTargetExpr +1487 IntegerDecl +1488 WrapperChain +1489 NewTargetExpr +1490 FunctionDecl +1491 TypedArrayOps +1492 DefineProperty +1493 MethodCall +1494 ArrowDecl +1495 UnboundMethodCall +1496 BinaryOp +1497 BuiltinCall +1498 Return +1499 ForOf +1500 DynamicFunctionTransition +1501 MethodCall +1502 ComputedDecl +1503 JitOptimize +1504 IntlOps +1505 DefineProperty +1506 ElementLoad +1507 ElementLoad +1508 BinaryOp +1509 BuiltinOverwrite +1510 ArrayDecl +1511 DiscoveredApi +1512 ConstructorFunction +1513 IntegerDecl +1514 StringDecl +1515 WrapperChain +1516 IntlOps +1517 Construct +1518 MethodCall +1519 Compare +1520 StringOps +1521 Closure +1522 DiscoveredApi +1523 JitBaseline +1524 JitOptimize +1525 UnboundMethodCall +1526 ReturnOverride +1527 ComputedDecl +1528 IfElse +1529 TryCatch +1530 ArrayDecl +1531 TryCatch +1532 DiscoveredApi +1533 BinaryOp +1534 ComputedDecl +1535 PropertyLoad +1536 ObjectDecl +1537 TemplateDecl +1538 PrototypeSet +1539 JitOptimize +1540 PrototypeMethodCall +1541 StringDecl +1542 ArrayDecl +1543 WorkerSpawn +1544 PropertyLoad +1545 IfElse +1546 TypeCheck +1547 ForOf +1548 ReturnOverride +1549 ArrowStore +1550 PropertyStore +1551 ArrowStore +1552 BinaryOp +1553 ConstructorFunction +1554 Return +1555 UnaryOp +1556 ElementLoad +1557 BuiltinCall +1558 IfElse +1559 CountedLoop +1560 RegExpDecl +1561 ClassDecl +1562 Update +1563 ValueOfOverride +1564 ElementsKind +1565 FunctionDecl +1566 FloatDecl +1567 UnboundMethodCall +1568 TryCatch +1569 TryCatch +1570 LabeledBlock +1571 Construct +1572 BuiltinCall +1573 TypedArrayOps +1574 ConstructorFunction +1575 ElementsKind +1576 Update +1577 RegExpDecl +1578 Closure +1579 Destructuring +1580 LabeledBlock +1581 ArrowStore +1582 DynamicFunctionTransition +1583 DiscoveredApi +1584 Update +1585 Compare +1586 ForIn +1587 PropertyLoad +1588 FreezeSeal +1589 Assignment +1590 IntlOps +1591 TemplateDecl +1592 ElementLoad +1593 DefineProperty +1594 ValueOfOverride +1595 FloatDecl +1596 Assignment +1597 PromiseThen +1598 LabeledBlock +1599 ElementsKind +1600 ShapeChange +1601 PrototypeMethodCall +1602 ElementsKind +1603 JitBaseline +1604 TypedArrayOps +1605 IfElse +1606 ReturnOverride +1607 WorkerSpawn +1608 DefineProperty +1609 BinaryOp +1610 Assignment +1611 TryCatch +1612 ObjectDecl +1613 FunctionDecl +1614 DiscoveredApi +1615 ConstructorFunction +1616 ConstructDecl +1617 ComputedDecl +1618 UnaryOp +1619 MapSetOps +1620 DiscoveredApi +1621 UnboundMethodCall +1622 Compare +1623 ConstructDecl +1624 Iife +1625 IntegerDecl +1626 BooleanDecl +1627 StringDecl +1628 BinaryOp +1629 DefineProperty +1630 PropertyStore +1631 DiscoveredApi +1632 DiscoveredApi +1633 TemplateDecl +1634 IntegerDecl +1635 ConstructDecl +1636 ValueOfOverride +1637 ElementLoad +1638 ShapeChange +1639 JitOptimize +1640 DefineProperty +1641 TypedArrayOps +1642 ClassDecl +1643 BuiltinCall +1644 Recursion +1645 Update +1646 IntegerDecl +1647 Iife +1648 Deopt +1649 TypedArrayOps +1650 ObjectDecl +1651 ShapeChange +1652 Update +1653 ArgumentsUse +1654 ArrowStore +1655 FunctionDecl +1656 ForOf +1657 ElementLoad +1658 ArrayDecl +1659 BuiltinCall +1660 IntlOps +1661 DefineProperty +1662 JitOptimize +1663 PropertyLoad +1664 MethodCall +1665 FrozenArrayOps +1666 BinaryOp +1667 ElementLoad +1668 IntegerDecl +1669 ObjectDecl +1670 PropertyDelete +1671 TryCatch +1672 ThisUse +1673 IntegerDecl +1674 CountedLoop +1675 LabeledBlock +1676 FloatDecl +1677 ElementLoad +1678 ObjectDecl +1679 Assignment +1680 Assignment +1681 FunctionDecl +1682 ElementStore +1683 TryCatch +1684 UnboundMethodCall +1685 CountedLoop +1686 MethodCall +1687 DefineProperty +1688 SymbolDecl +1689 ConstructorFunction +1690 ConstructDecl +1691 ElementStore +1692 TypedArrayOps +1693 SpreadCall +1694 ClassDecl +1695 DynamicFunctionTransition +1696 ElementLoad +1697 BinaryOp +1698 TemplateDecl +1699 IfElse +1700 NewTargetExpr +1701 GeneratorIterate +1702 GeneratorIterate +1703 PropertyStore +1704 ThisUse +1705 TypedArrayDecl +1706 SpreadCall +1707 BuiltinOverwrite +1708 ObjectDecl +1709 IfElse +1710 PropertyStore +1711 DefineProperty +1712 SpreadCall +1713 IntlOps +1714 Closure +1715 StringDecl +1716 WrapperChain +1717 FloatDecl +1718 ShapeChange +1719 Assignment +1720 Recursion +1721 BinaryOp +1722 WrapperChain +1723 ObjectDecl +1724 MethodCall +1725 PropertyStore +1726 BuiltinCall +1727 ClassDecl +1728 IntegerDecl +1729 PropertyLoad +1730 ElementLoad +1731 BooleanDecl +1732 DynamicFunctionTransition +1733 FloatDecl +1734 UnaryOp +1735 PropertyStore +1736 ShapeChange +1737 IntegerDecl +1738 FunctionCall +1739 FunctionCall +1740 Assignment +1741 BinaryOp +1742 DefineProperty +1743 IntegerDecl +1744 FunctionDecl +1745 UnaryOp +1746 ElementLoad +1747 Recursion +1748 ConstructorFunction +1749 Construct +1750 Deopt +1751 StringDecl +1752 ElementLoad +1753 FloatDecl +1754 JitOptimize +1755 PropertyLoad +1756 CrossContextPrivateStore +1757 JitOptimize +1758 TryCatch +1759 StringDecl +1760 ReturnOverride +1761 MapSetOps +1762 JitOptimize +1763 ElementLoad +1764 IntegerDecl +1765 ReturnOverride +1766 DefineProperty +1767 PropertyLoad +1768 JitBaseline +1769 PrototypeSet +1770 DiscoveredApi +1771 Switch +1772 ElementLoad +1773 Assignment +1774 Update +1775 PrototypeMethodCall +1776 TypedArrayOps +1777 ManyProperties +1778 StringDecl +1779 ElementLoad +1780 SpreadCall +1781 BinaryOp +1782 ObjectDecl +1783 DiscoveredApi +1784 ConstructDecl +1785 CountedLoop +1786 FunctionDecl +1787 Iteration +1788 DiscoveredApi +1789 ConstructorFunction +1790 ForOf +1791 DefineProperty +1792 MapSetOps +1793 ForOf +1794 ArrowDecl +1795 Closure +1796 Update +1797 MethodCall +1798 PropertyLoad +1799 CountedLoop +1800 MethodCall +1801 ObjectDecl +1802 CountedLoop +1803 TryCatch +1804 MapSetOps +1805 JitOptimize +1806 ObjectDecl +1807 OsrLoop +1808 FunctionCall +1809 UnboundMethodCall +1810 ArrowDecl +1811 TemplateDecl +1812 FunctionCall +1813 DiscoveredApi +1814 MapSetOps +1815 FreezeSeal +1816 Iteration +1817 Update +1818 UnaryOp +1819 BinaryOp +1820 TypeCheck +1821 BuiltinCall +1822 BigIntDecl +1823 Update +1824 FloatDecl +1825 DiscoveredApi +1826 ElementLoad +1827 Closure +1828 FunctionDecl +1829 BigIntDecl +1830 OsrLoop +1831 PromiseThen +1832 ReturnOverride +1833 UnaryOp +1834 FunctionDecl +1835 NullishDecl +1836 CountedLoop +1837 ComputedDecl +1838 TryCatch +1839 BigIntDecl +1840 Deopt +1841 FloatDecl +1842 Gc +1843 ConstructDecl +1844 PrototypeMethodCall +1845 ObjectDecl +1846 ClassDecl +1847 BinaryOp +1848 Compare +1849 NewTargetExpr +1850 ProxyDecl +1851 ClassDecl +1852 RegExpDecl +1853 ArrowDecl +1854 FloatDecl +1855 JitOptimize +1856 TemplateDecl +1857 SpreadCall +1858 BigIntDecl +1859 ArrayDecl +1860 ConstructDecl +1861 Destructuring +1862 ReturnOverride +1863 Construct +1864 TryCatch +1865 ObjectDecl +1866 AsyncIife +1867 PrototypeSet +1868 FunctionDecl +1869 Update +1870 BuiltinCall +1871 ArrayDecl +1872 FunctionCall +1873 DefineProperty +1874 StringOps +1875 Construct +1876 ElementStore +1877 OsrLoop +1878 SpreadCall +1879 ElementStore +1880 FunctionDecl +1881 ConstructDecl +1882 DiscoveredApi +1883 ConstructDecl +1884 JitOptimize +1885 ComputedDecl +1886 TypedArrayOps +1887 ForIn +1888 ForOf +1889 WhileLoop +1890 PropertyDelete +1891 ProxyDecl +1892 PropertyStore +1893 ShapeChange +1894 TryCatch +1895 IntegerDecl +1896 TypedArrayDecl +1897 BinaryOp +1898 JitOptimize +1899 FunctionCall +1900 DynamicFunctionTransition +1901 ClassDecl +1902 FunctionDecl +1903 ElementStore +1904 ElementsKind +1905 ProxyDecl +1906 DiscoveredApi +1907 PropertyStore +1908 IntlOps +1909 ObjectDecl +1910 DiscoveredApi +1911 PropertyStore +1912 GeneratorIterate +1913 ProxyDecl +1914 ProxyDecl +1915 IfElse +1916 IntegerDecl +1917 Iife +1918 Assignment +1919 CountedLoop +1920 FunctionDecl +1921 PropertyStore +1922 Switch +1923 TryCatch +1924 CrossContextPrivateStore +1925 Construct +1926 CrossContextPrivateStore +1927 FloatDecl +1928 CountedLoop +1929 AsyncIife +1930 PropertyStore +1931 PropertyLoad +1932 IfElse +1933 StringDecl +1934 Iteration +1935 TypedArrayOps +1936 ConstructorFunction +1937 BuiltinCall +1938 ConstructDecl +1939 GeneratorIterate +1940 PropertyLoad +1941 Construct +1942 FunctionCall +1943 PromiseThen +1944 Destructuring +1945 Iife +1946 PropertyDelete +1947 Eval +1948 Closure +1949 UnaryOp +1950 WhileLoop +1951 ShapeChange +1952 PropertyLoad +1953 MethodCall +1954 GeneratorIterate +1955 FunctionCall +1956 FloatDecl +1957 ProxyDecl +1958 FunctionCall +1959 ClassDecl +1960 FunctionDecl +1961 Iteration +1962 FloatDecl +1963 ArrowDecl +1964 PrototypeSet +1965 Update +1966 ArrayDecl +1967 Update +1968 ComputedDecl +1969 PropertyLoad +1970 WorkerSpawn +1971 IntegerDecl +1972 ForIn +1973 PropertyLoad +1974 DiscoveredApi +1975 DefineProperty +1976 BooleanDecl +1977 Construct +1978 PropertyLoad +1979 UnboundMethodCall +1980 BigIntDecl +1981 Closure +1982 Compare +1983 ArgumentsUse +1984 UsingDecl +1985 ConstructDecl +1986 IfElse +1987 FreezeSeal +1988 MethodCall +1989 JitOptimize +1990 IntegerDecl +1991 PrototypeSet +1992 ElementStore +1993 JitOptimize +1994 TryCatch +1995 BuiltinCall +1996 WrapperChain +1997 TypeCheck +1998 IfElse +1999 MethodCall diff --git a/deps/v8/experimental/redline/testdata/selection/mutator_outputs.trace b/deps/v8/experimental/redline/testdata/selection/mutator_outputs.trace new file mode 100644 index 000000000000..e51e5cbd7d70 --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/mutator_outputs.trace @@ -0,0 +1,75 @@ +CodeGen 0 2c4bca1e80b60432 inserted ArrayDecl let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CodeGen 1 c48efdb32d0575f9 inserted CrossContextPrivateStore let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CodeGen 2 4ca6a681e79a15c7 inserted Update let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CodeGen 3 dbbfb2e7f10f803e inserted WhileLoop+SymbolDecl let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +CodeGen 4 a1e0f51725fadf5a inserted PrototypeMethodCall+NativeCall let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Explore 0 2a6eff1ab4f22172 probing r f let n = 42; let s = "text"; try { __redline_explore("e8834", f, [s, +Explore 1 be4a2707f13ec60b probing f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Explore 2 4d0c5008e0f101af probing f let n = 42; let s = "text"; let a = [1, 2, 3]; try { __redline_explo +Explore 3 e147f0525472f3f1 probing a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Explore 4 4dc3593c48954349 probing f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Probing 0 aff9e71d57cb5591 probing f let n = 42; let s = "text"; let a = [1, 2, 3]; try { __redline_probe +Probing 1 278ead283dba57af probing r C let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Probing 2 cf920d9572ee7281 probing f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Probing 3 6a1c72a883a17202 probing a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Probing 4 30aa747d96df02e3 probing f t a let n = 42; let s = "text"; try { __redline_probe("p74410", f); } ca +Prefix 0 cb32254c76ccedc6 inserted StringDecl+RegExpDecl+ArrayDecl+RegExpDecl+IntegerDecl+IntegerDecl+StringDecl+TemplateDecl+RegExpDecl+RegExpDecl+IntegerDecl+BooleanDecl let s0 = "iynbof"; let re0 = /(?i:\x7f(?s:[^a-z]{2})$)(?m:(?<g1>b*?.?) +Prefix 1 639981f9d881c5cd inserted IntegerDecl+ArrayDecl+IntegerDecl+ArrowDecl+ArrayDecl+ArrowDecl+ArrowDecl+RegExpDecl+TemplateDecl+ArrayDecl let v0 = 24096; let arr0 = [f]; let v1 = (-2147483649); let f0 = async +Prefix 2 ea22d2cad28ef9c6 inserted ObjectDecl+ObjectDecl+ArrayDecl+FloatDecl+IntegerDecl+ArrayDecl+ArrayDecl+FloatDecl+ObjectDecl+ArrayDecl let obj0 = {}; var obj1 = {name: obj0}; let arr0 = []; let v0 = (-0); +Prefix 3 88eb560515060234 inserted StringDecl+FloatDecl+FloatDecl+FloatDecl+StringDecl+ArrayDecl+IntegerDecl+StringDecl+IntegerDecl+BooleanDecl+BooleanDecl+RegExpDecl let s0 = "x"; let v0 = 2.2250738585072014e-308; var v1 = 0.1; const v2 +Prefix 4 5346e412f6559e57 inserted ArrayDecl+ArrowDecl+ObjectDecl+BigIntDecl+BigIntDecl+TemplateDecl+IntegerDecl+ArrayDecl+TemplateDecl+ArrayDecl+IntegerDecl let arr0 = [,]; var f0 = function(a0, a1) { let v0 = a0.toString(); +Splice 0 301f03ee3f8915e5 spliced VariableDeclaration (10 nodes; 1 renamed, 1 rewired, 0 declared) let n = 42; let s = "text"; let q0 = [f(1), f(2)]; let a = [1, 2, 3]; +Splice 1 e6d6dbd8ae131135 spliced VariableDeclaration (9 nodes; 0 renamed, 0 rewired, 0 declared) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Splice 2 2dd1ce2e1198085b spliced VariableDeclaration (9 nodes; 0 renamed, 0 rewired, 0 declared) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Splice 3 50207dfe55ca00a9 spliced VariableDeclaration (9 nodes; 0 renamed, 0 rewired, 0 declared) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Splice 4 230875f46334fb1d spliced FunctionDeclaration (8 nodes; 1 renamed, 0 rewired, 0 declared) let n = 42; let s = "text"; function g(x0) { return x0 * 2; } let a +Combine 0 086456d74bea46a1 combined flat (3 statements, 1 renamed) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Combine 1 086456d74bea46a1 combined flat (3 statements, 1 renamed) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Combine 2 3b0969c403cbc423 combined flat (3 statements, 1 renamed) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Combine 3 086456d74bea46a1 combined flat (3 statements, 1 renamed) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Combine 4 086456d74bea46a1 combined flat (3 statements, 1 renamed) let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Input 0 03af1649ee349fee input q -> a let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Input 1 873a848ef11fcbc8 input p -> n let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Input 2 f8538ed13175caac input t -> f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Input 3 528441f757780c1a input t -> literal let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Input 4 a04dd3c9a8806caa input t -> p let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Operation 0 20e57927760e33b0 property .v -> .valueOf let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Operation 1 a6a5717f0911ab59 assignment += -> <<= let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Operation 2 1a3503d83e16668f number 3 -> 1.5 let n = 42; let s = "text"; let a = [1, 2, 1.5]; let o = {x: 1, y: "tw +Operation 3 15c40bc3aba651cd number 0 -> -1 let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Operation 4 2df86dc044338d03 binary + -> ** let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Expression 0 f5115f19ad9af308 expression `i < 3` -> expression let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Expression 1 b7b19c37b296ed28 expression `new C(r)` -> wrap let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Expression 2 7ffb69bf2d5f9d78 expression `i < 3` -> literal let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Expression 3 61ae6bf5b8ca5a8f expression `2` -> expression let n = 42; let s = "text"; let a = [1, s ?? n, 3]; let o = {x: 1, y: +Expression 4 1bbd0b730a9d83f1 expression `7` -> literal let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Call 0 305702b13107bc51 added argument let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Call 1 68d472d977541808 replaced argument let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Call 2 0ac442cc4901b7eb callee -> f let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Call 3 5a95108d4af9b41a added argument let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Call 4 68d472d977541808 replaced argument let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Remove 0 cb60992f805d2d55 removed array element let n = 42; let s = "text"; let a = [2, 3]; let o = {x: 1, y: "two"}; +Remove 1 f616f94a2a5d3b59 removed ExpressionStatement `t += a[i];` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Remove 2 122f5bdf703ab95d removed ForStatement `for (let i = 0; i < 3; i++) { t += a[i]; }` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Remove 3 34c5f9ab9f31a7cf removed ReturnStatement `return t;` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Remove 4 59cd6cf74bfcf485 removed VariableDeclaration `let s = "text";` let n = 42; let a = [1, 2, 3]; let o = {x: 1, y: "two"}; function f(p, +Wrap 0 7d5578c77697c1aa wrapped 1 statement(s) in loop let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Wrap 1 55dd99ce96b117f8 wrapped 1 statement(s) in label let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Wrap 2 ff42ed09de1c2b10 wrapped 1 statement(s) in for-of let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Wrap 3 b585bc3fabc474f2 wrapped 1 statement(s) in label let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Wrap 4 cec1d879b6c7886a wrapped 1 statement(s) in loop let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Duplicate 0 29a450ad6e7879d3 duplicated FunctionDeclaration `function f(p, q) { let t = p + q; for (let i = 0; i <...` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Duplicate 1 ef454ec803004471 duplicated ExpressionStatement `t += a[i];` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Duplicate 2 5aeaf70ddb11ca47 duplicated ReturnStatement `return t;` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Duplicate 3 1a71a2c998acbfd9 duplicated FunctionDeclaration `function f(p, q) { let t = p + q; for (let i = 0; i <...` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Duplicate 4 ef454ec803004471 duplicated ExpressionStatement `t += a[i];` let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Reorder 0 4d04c76df980deb4 swapped ForStatement and ReturnStatement let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +Reorder 1 8467b3581d5f6f1e swapped VariableDeclaration and VariableDeclaration let n = 42; let s = "text"; let o = {x: 1, y: "two"}; let a = [1, 2, 3 +Reorder 2 85e178b5ff98c32c swapped VariableDeclaration and VariableDeclaration let n = 42; let a = [1, 2, 3]; let s = "text"; let o = {x: 1, y: "two" +Reorder 3 8467b3581d5f6f1e swapped VariableDeclaration and VariableDeclaration let n = 42; let s = "text"; let o = {x: 1, y: "two"}; let a = [1, 2, 3 +Reorder 4 85e178b5ff98c32c swapped VariableDeclaration and VariableDeclaration let n = 42; let a = [1, 2, 3]; let s = "text"; let o = {x: 1, y: "two" +JitStress 0 497b7df12deca2b1 inserted JitOptimize+JitOptimize let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitStress 1 0f49f3a8760eabb9 inserted JitOptimize let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitStress 2 54b6214f10d35d7d inserted NativeCall+JitOptimize+NativeCall let n = 42; let s = "text"; let v0 = %OptimizeFunctionOnNextCall(f); % +JitStress 3 1a81690d4f658b57 inserted Gc+ElementsKind+OsrLoop let n = 42; let s = "text"; let a = [1, 2, 3]; let o = {x: 1, y: "two" +JitStress 4 33e72206ae7eddd0 inserted Gc+Gc+JitOptimize let n = 42; let s = "text"; let a = [1, 2, 3]; gc({execution: "async"} diff --git a/deps/v8/experimental/redline/testdata/selection/mutators.trace b/deps/v8/experimental/redline/testdata/selection/mutators.trace new file mode 100644 index 000000000000..e37019b0c0dc --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/mutators.trace @@ -0,0 +1,2000 @@ +0 0 Input +1 1 Probing +2 1 Splice +3 0 Input +4 1 Probing +5 1 Call +6 0 Probing +7 1 Input +8 1 Input +9 0 Explore +10 1 Combine +11 1 Combine +12 0 Probing +13 1 Input +14 1 Explore +15 0 Input +16 1 Splice +17 1 Explore +18 0 Input +19 1 Probing +20 1 Call +21 0 CodeGen +22 1 Probing +23 1 CodeGen +24 0 Input +25 1 Explore +26 1 Probing +27 0 Input +28 1 Operation +29 1 Combine +30 0 Operation +31 1 Probing +32 1 Input +33 0 CodeGen +34 1 Expression +35 1 Splice +36 0 Expression +37 1 Probing +38 1 Explore +39 0 Explore +40 1 Splice +41 1 Operation +42 0 CodeGen +43 1 Splice +44 1 Expression +45 0 Operation +46 1 CodeGen +47 1 Operation +48 0 Input +49 1 Explore +50 1 Expression +51 0 CodeGen +52 1 Probing +53 1 Expression +54 0 Probing +55 1 Combine +56 1 CodeGen +57 0 Operation +58 1 Input +59 1 Operation +60 0 Explore +61 1 Explore +62 1 CodeGen +63 0 Input +64 1 Input +65 1 CodeGen +66 0 Explore +67 1 CodeGen +68 1 Input +69 0 CodeGen +70 1 Explore +71 1 CodeGen +72 0 Expression +73 1 Explore +74 1 Explore +75 0 Input +76 1 Explore +77 1 Call +78 0 Call +79 1 Combine +80 1 Input +81 0 Explore +82 1 Splice +83 1 Probing +84 0 Explore +85 1 Expression +86 1 Input +87 0 Input +88 1 Splice +89 1 Explore +90 0 CodeGen +91 1 Input +92 1 Input +93 0 CodeGen +94 1 Explore +95 1 Probing +96 0 Input +97 1 Call +98 1 Input +99 0 Input +100 1 Probing +101 1 Input +102 0 Operation +103 1 CodeGen +104 1 Expression +105 0 Operation +106 1 Splice +107 1 Operation +108 0 Input +109 1 Input +110 1 Explore +111 0 Explore +112 1 Probing +113 1 Probing +114 0 CodeGen +115 1 Input +116 1 Explore +117 0 CodeGen +118 1 Probing +119 1 Splice +120 0 Input +121 1 CodeGen +122 1 Explore +123 0 Explore +124 1 Explore +125 1 Operation +126 0 CodeGen +127 1 Combine +128 1 Probing +129 0 Explore +130 1 CodeGen +131 1 Input +132 0 Operation +133 1 Probing +134 1 Explore +135 0 Explore +136 1 Input +137 1 Explore +138 0 Input +139 1 Probing +140 1 Input +141 0 Explore +142 1 Probing +143 1 Input +144 0 Operation +145 1 Splice +146 1 Operation +147 0 CodeGen +148 1 Combine +149 1 CodeGen +150 0 Probing +151 1 Input +152 1 Splice +153 0 Explore +154 1 Probing +155 1 Explore +156 0 Probing +157 1 Input +158 1 Expression +159 0 Explore +160 1 Input +161 1 Input +162 0 Input +163 1 Combine +164 1 Explore +165 0 CodeGen +166 1 Input +167 1 Probing +168 0 Input +169 1 Call +170 1 CodeGen +171 0 CodeGen +172 1 CodeGen +173 1 Input +174 0 CodeGen +175 1 Explore +176 1 Operation +177 0 Explore +178 1 Explore +179 1 Probing +180 0 Expression +181 1 Input +182 1 Operation +183 0 Explore +184 1 Splice +185 1 Input +186 0 CodeGen +187 1 Explore +188 1 Probing +189 0 Probing +190 1 Explore +191 1 Combine +192 0 Explore +193 1 Input +194 1 CodeGen +195 0 CodeGen +196 1 Splice +197 1 Probing +198 0 Probing +199 1 CodeGen +200 1 Input +201 0 Explore +202 1 Expression +203 1 Probing +204 0 Input +205 1 CodeGen +206 1 Splice +207 0 Probing +208 1 Explore +209 1 Explore +210 0 Explore +211 1 Probing +212 1 Operation +213 0 Probing +214 1 Expression +215 1 Input +216 0 Input +217 1 Probing +218 1 Input +219 0 Input +220 1 Operation +221 1 Input +222 0 Expression +223 1 Splice +224 1 CodeGen +225 0 Explore +226 1 Call +227 1 Input +228 0 CodeGen +229 1 Splice +230 1 Operation +231 0 Input +232 1 Probing +233 1 CodeGen +234 0 Explore +235 1 CodeGen +236 1 CodeGen +237 0 Input +238 1 Explore +239 1 CodeGen +240 0 Operation +241 1 CodeGen +242 1 Input +243 0 Explore +244 1 Expression +245 1 Input +246 0 Explore +247 1 Operation +248 1 Probing +249 0 Call +250 1 Operation +251 1 Combine +252 0 Probing +253 1 Probing +254 1 Explore +255 0 Input +256 1 Probing +257 1 CodeGen +258 0 Explore +259 1 Input +260 1 Splice +261 0 Operation +262 1 Operation +263 1 Splice +264 0 Input +265 1 Combine +266 1 Input +267 0 Operation +268 1 Explore +269 1 Input +270 0 CodeGen +271 1 CodeGen +272 1 CodeGen +273 0 Input +274 1 CodeGen +275 1 Probing +276 0 Operation +277 1 Splice +278 1 Probing +279 0 CodeGen +280 1 Input +281 1 Input +282 0 Probing +283 1 Probing +284 1 Splice +285 0 Explore +286 1 CodeGen +287 1 Combine +288 0 Probing +289 1 CodeGen +290 1 Explore +291 0 Probing +292 1 Splice +293 1 Input +294 0 Call +295 1 CodeGen +296 1 Combine +297 0 Input +298 1 Input +299 1 Explore +300 0 Input +301 1 Operation +302 1 CodeGen +303 0 Input +304 1 Probing +305 1 Probing +306 0 Probing +307 1 Splice +308 1 CodeGen +309 0 Explore +310 1 Expression +311 1 CodeGen +312 0 Explore +313 1 Explore +314 1 Splice +315 0 Explore +316 1 Combine +317 1 Input +318 0 Probing +319 1 Input +320 1 Probing +321 0 CodeGen +322 1 CodeGen +323 1 Operation +324 0 Input +325 1 CodeGen +326 1 Probing +327 0 Input +328 1 Probing +329 1 Splice +330 0 CodeGen +331 1 Input +332 1 Splice +333 0 Input +334 1 Input +335 1 Input +336 0 Input +337 1 Input +338 1 Splice +339 0 Explore +340 1 Splice +341 1 Probing +342 0 Explore +343 1 Explore +344 1 Explore +345 0 Input +346 1 CodeGen +347 1 Operation +348 0 Explore +349 1 Probing +350 1 CodeGen +351 0 Operation +352 1 Explore +353 1 Explore +354 0 Input +355 1 CodeGen +356 1 Explore +357 0 Probing +358 1 CodeGen +359 1 Explore +360 0 Input +361 1 Splice +362 1 Input +363 0 Explore +364 1 Splice +365 1 Combine +366 0 Input +367 1 Explore +368 1 Combine +369 0 Input +370 1 Probing +371 1 CodeGen +372 0 Input +373 1 CodeGen +374 1 Expression +375 0 CodeGen +376 1 Probing +377 1 Input +378 0 Operation +379 1 Explore +380 1 Splice +381 0 Input +382 1 Explore +383 1 Explore +384 0 Explore +385 1 Probing +386 1 Explore +387 0 Input +388 1 Input +389 1 Input +390 0 CodeGen +391 1 Input +392 1 CodeGen +393 0 Probing +394 1 Input +395 1 Operation +396 0 Probing +397 1 Input +398 1 Probing +399 0 Call +400 1 CodeGen +401 1 Input +402 0 CodeGen +403 1 Expression +404 1 Explore +405 0 Explore +406 1 Input +407 1 Splice +408 0 Input +409 1 Splice +410 1 Input +411 0 Operation +412 1 Splice +413 1 Input +414 0 Explore +415 1 Splice +416 1 Operation +417 0 Explore +418 1 Explore +419 1 Expression +420 0 CodeGen +421 1 CodeGen +422 1 Input +423 0 Input +424 1 Operation +425 1 Splice +426 0 CodeGen +427 1 Splice +428 1 Explore +429 0 CodeGen +430 1 Combine +431 1 Probing +432 0 Expression +433 1 Input +434 1 Combine +435 0 Explore +436 1 Call +437 1 Input +438 0 CodeGen +439 1 Input +440 1 Explore +441 0 Operation +442 1 Explore +443 1 Probing +444 0 Explore +445 1 Probing +446 1 Combine +447 0 Probing +448 1 Operation +449 1 Input +450 0 Call +451 1 Explore +452 1 Input +453 0 CodeGen +454 1 CodeGen +455 1 CodeGen +456 0 CodeGen +457 1 CodeGen +458 1 Input +459 0 Input +460 1 Explore +461 1 Input +462 0 Explore +463 1 Input +464 1 Input +465 0 CodeGen +466 1 Operation +467 1 Input +468 0 Expression +469 1 Probing +470 1 Input +471 0 Explore +472 1 Input +473 1 Call +474 0 Expression +475 1 CodeGen +476 1 Combine +477 0 Probing +478 1 Probing +479 1 Explore +480 0 Probing +481 1 Splice +482 1 Probing +483 0 CodeGen +484 1 Expression +485 1 Splice +486 0 Operation +487 1 Probing +488 1 Splice +489 0 CodeGen +490 1 Input +491 1 Explore +492 0 Operation +493 1 Splice +494 1 Explore +495 0 Explore +496 1 Splice +497 1 Probing +498 0 Probing +499 1 CodeGen +500 1 CodeGen +501 0 Input +502 1 Input +503 1 Explore +504 0 Input +505 1 Input +506 1 Combine +507 0 Input +508 1 Probing +509 1 Explore +510 0 Input +511 1 CodeGen +512 1 Input +513 0 Explore +514 1 Operation +515 1 Splice +516 0 Explore +517 1 Operation +518 1 Probing +519 0 Probing +520 1 CodeGen +521 1 Explore +522 0 Operation +523 1 Splice +524 1 CodeGen +525 0 Input +526 1 CodeGen +527 1 Explore +528 0 Explore +529 1 Explore +530 1 Combine +531 0 Call +532 1 CodeGen +533 1 Input +534 0 Explore +535 1 Operation +536 1 Splice +537 0 Probing +538 1 Call +539 1 Input +540 0 Probing +541 1 Combine +542 1 Splice +543 0 Explore +544 1 Splice +545 1 Input +546 0 CodeGen +547 1 Expression +548 1 Splice +549 0 Input +550 1 Input +551 1 Splice +552 0 CodeGen +553 1 Input +554 1 Input +555 0 Probing +556 1 Input +557 1 Input +558 0 Operation +559 1 Explore +560 1 Probing +561 0 Input +562 1 Combine +563 1 Splice +564 0 Input +565 1 Input +566 1 Splice +567 0 Input +568 1 CodeGen +569 1 Explore +570 0 CodeGen +571 1 Expression +572 1 CodeGen +573 0 Operation +574 1 Input +575 1 Splice +576 0 Operation +577 1 Operation +578 1 Call +579 0 Input +580 1 Input +581 1 Explore +582 0 Operation +583 1 Probing +584 1 Input +585 0 Input +586 1 Input +587 1 Input +588 0 Input +589 1 Explore +590 1 Combine +591 0 Probing +592 1 Combine +593 1 Call +594 0 Explore +595 1 Explore +596 1 CodeGen +597 0 Explore +598 1 Splice +599 1 Operation +600 0 Explore +601 1 CodeGen +602 1 CodeGen +603 0 Input +604 1 Probing +605 1 Combine +606 0 Explore +607 1 Operation +608 1 Explore +609 0 Explore +610 1 Combine +611 1 CodeGen +612 0 Input +613 1 Input +614 1 Explore +615 0 Input +616 1 Splice +617 1 Splice +618 0 Input +619 1 Combine +620 1 Operation +621 0 Input +622 1 Splice +623 1 Splice +624 0 Input +625 1 Operation +626 1 Input +627 0 Explore +628 1 Expression +629 1 Explore +630 0 Expression +631 1 Splice +632 1 Probing +633 0 Explore +634 1 Input +635 1 CodeGen +636 0 Input +637 1 Explore +638 1 Explore +639 0 Explore +640 1 Splice +641 1 Explore +642 0 Input +643 1 Input +644 1 Probing +645 0 CodeGen +646 1 Input +647 1 Splice +648 0 Probing +649 1 Explore +650 1 Explore +651 0 Operation +652 1 Splice +653 1 Input +654 0 Input +655 1 Input +656 1 Combine +657 0 Probing +658 1 CodeGen +659 1 Splice +660 0 Operation +661 1 Explore +662 1 Combine +663 0 CodeGen +664 1 Explore +665 1 Explore +666 0 Explore +667 1 CodeGen +668 1 Explore +669 0 Operation +670 1 Splice +671 1 CodeGen +672 0 Input +673 1 Operation +674 1 Splice +675 0 CodeGen +676 1 Operation +677 1 Call +678 0 Input +679 1 Input +680 1 CodeGen +681 0 Input +682 1 Splice +683 1 Splice +684 0 Probing +685 1 Input +686 1 Input +687 0 Explore +688 1 Splice +689 1 Explore +690 0 Input +691 1 Input +692 1 Combine +693 0 CodeGen +694 1 Explore +695 1 Input +696 0 Explore +697 1 CodeGen +698 1 Input +699 0 Explore +700 1 Probing +701 1 Splice +702 0 Operation +703 1 Explore +704 1 CodeGen +705 0 Input +706 1 CodeGen +707 1 Combine +708 0 Input +709 1 Input +710 1 Input +711 0 Operation +712 1 Explore +713 1 Probing +714 0 Explore +715 1 Splice +716 1 Splice +717 0 Input +718 1 CodeGen +719 1 Input +720 0 Input +721 1 Explore +722 1 Input +723 0 Explore +724 1 Probing +725 1 Explore +726 0 CodeGen +727 1 Probing +728 1 CodeGen +729 0 Input +730 1 Expression +731 1 Explore +732 0 Operation +733 1 Explore +734 1 CodeGen +735 0 CodeGen +736 1 Input +737 1 Call +738 0 Probing +739 1 Combine +740 1 Input +741 0 CodeGen +742 1 Input +743 1 Probing +744 0 CodeGen +745 1 Call +746 1 Probing +747 0 Input +748 1 Input +749 1 Operation +750 0 CodeGen +751 1 Input +752 1 Explore +753 0 Expression +754 1 Splice +755 1 Operation +756 0 Explore +757 1 Explore +758 1 CodeGen +759 0 Explore +760 1 Call +761 1 Combine +762 0 Explore +763 1 Splice +764 1 Combine +765 0 Explore +766 1 Operation +767 1 Splice +768 0 Explore +769 1 Explore +770 1 Expression +771 0 Explore +772 1 Input +773 1 CodeGen +774 0 Call +775 1 Expression +776 1 Probing +777 0 Explore +778 1 Combine +779 1 Input +780 0 CodeGen +781 1 Splice +782 1 Operation +783 0 Operation +784 1 Input +785 1 Splice +786 0 Input +787 1 Splice +788 1 Splice +789 0 Probing +790 1 Explore +791 1 Operation +792 0 CodeGen +793 1 Splice +794 1 Operation +795 0 Input +796 1 CodeGen +797 1 Explore +798 0 Input +799 1 Splice +800 1 Input +801 0 Probing +802 1 CodeGen +803 1 Operation +804 0 Input +805 1 Explore +806 1 Expression +807 0 CodeGen +808 1 Combine +809 1 Explore +810 0 CodeGen +811 1 Splice +812 1 Explore +813 0 Operation +814 1 Input +815 1 Operation +816 0 Probing +817 1 Probing +818 1 Probing +819 0 Input +820 1 Input +821 1 CodeGen +822 0 Explore +823 1 CodeGen +824 1 Splice +825 0 Expression +826 1 Explore +827 1 Explore +828 0 Input +829 1 CodeGen +830 1 Input +831 0 Explore +832 1 Explore +833 1 Probing +834 0 Input +835 1 Splice +836 1 Splice +837 0 Probing +838 1 Splice +839 1 Explore +840 0 Input +841 1 Operation +842 1 Splice +843 0 Input +844 1 Input +845 1 Explore +846 0 Explore +847 1 Splice +848 1 Probing +849 0 Input +850 1 Input +851 1 Combine +852 0 Call +853 1 Input +854 1 Input +855 0 CodeGen +856 1 Operation +857 1 Combine +858 0 Operation +859 1 Combine +860 1 Input +861 0 Call +862 1 CodeGen +863 1 Explore +864 0 Probing +865 1 Probing +866 1 Operation +867 0 CodeGen +868 1 Splice +869 1 Operation +870 0 Probing +871 1 Combine +872 1 CodeGen +873 0 Expression +874 1 Explore +875 1 Explore +876 0 Explore +877 1 Probing +878 1 Input +879 0 CodeGen +880 1 Splice +881 1 CodeGen +882 0 Input +883 1 Splice +884 1 Splice +885 0 Explore +886 1 Explore +887 1 Probing +888 0 CodeGen +889 1 Splice +890 1 Input +891 0 Probing +892 1 Explore +893 1 Input +894 0 Probing +895 1 CodeGen +896 1 Splice +897 0 Explore +898 1 CodeGen +899 1 Explore +900 0 Expression +901 1 Input +902 1 Probing +903 0 Explore +904 1 Probing +905 1 Input +906 0 Input +907 1 Input +908 1 Input +909 0 Expression +910 1 Splice +911 1 CodeGen +912 0 Explore +913 1 Splice +914 1 Splice +915 0 Input +916 1 Call +917 1 Input +918 0 CodeGen +919 1 Input +920 1 Explore +921 0 Probing +922 1 Explore +923 1 Splice +924 0 Probing +925 1 Input +926 1 Splice +927 0 Call +928 1 Probing +929 1 Probing +930 0 CodeGen +931 1 Operation +932 1 Explore +933 0 CodeGen +934 1 Explore +935 1 Operation +936 0 Explore +937 1 Call +938 1 Input +939 0 Input +940 1 Operation +941 1 Probing +942 0 Explore +943 1 CodeGen +944 1 Explore +945 0 Probing +946 1 Explore +947 1 Splice +948 0 Probing +949 1 Probing +950 1 Splice +951 0 Probing +952 1 Expression +953 1 Explore +954 0 Probing +955 1 Operation +956 1 Explore +957 0 Input +958 1 Explore +959 1 Splice +960 0 Call +961 1 Operation +962 1 Expression +963 0 Input +964 1 Explore +965 1 CodeGen +966 0 CodeGen +967 1 Operation +968 1 Input +969 0 CodeGen +970 1 Explore +971 1 Operation +972 0 Operation +973 1 Probing +974 1 CodeGen +975 0 Probing +976 1 Explore +977 1 Input +978 0 Operation +979 1 Call +980 1 Probing +981 0 Operation +982 1 Call +983 1 Input +984 0 Operation +985 1 Splice +986 1 Explore +987 0 CodeGen +988 1 Splice +989 1 CodeGen +990 0 CodeGen +991 1 Input +992 1 Probing +993 0 Explore +994 1 CodeGen +995 1 Explore +996 0 Explore +997 1 Input +998 1 Input +999 0 Input +1000 1 Splice +1001 1 Splice +1002 0 Operation +1003 1 CodeGen +1004 1 Input +1005 0 CodeGen +1006 1 Operation +1007 1 Splice +1008 0 Call +1009 1 Probing +1010 1 Operation +1011 0 Input +1012 1 Explore +1013 1 Expression +1014 0 Operation +1015 1 Explore +1016 1 Explore +1017 0 Explore +1018 1 Operation +1019 1 Probing +1020 0 Explore +1021 1 Splice +1022 1 Explore +1023 0 Probing +1024 1 Probing +1025 1 Probing +1026 0 CodeGen +1027 1 Input +1028 1 Input +1029 0 Operation +1030 1 Input +1031 1 Combine +1032 0 Input +1033 1 Probing +1034 1 Input +1035 0 CodeGen +1036 1 Explore +1037 1 Input +1038 0 Input +1039 1 Explore +1040 1 Call +1041 0 Operation +1042 1 Operation +1043 1 Input +1044 0 Probing +1045 1 Operation +1046 1 Splice +1047 0 CodeGen +1048 1 Operation +1049 1 Input +1050 0 Explore +1051 1 Probing +1052 1 Operation +1053 0 CodeGen +1054 1 Splice +1055 1 Input +1056 0 Input +1057 1 Input +1058 1 Combine +1059 0 Expression +1060 1 Call +1061 1 Input +1062 0 Input +1063 1 Operation +1064 1 Input +1065 0 Probing +1066 1 Explore +1067 1 Explore +1068 0 Probing +1069 1 Explore +1070 1 Explore +1071 0 Input +1072 1 Operation +1073 1 Explore +1074 0 Expression +1075 1 Input +1076 1 Input +1077 0 CodeGen +1078 1 CodeGen +1079 1 Combine +1080 0 Explore +1081 1 Explore +1082 1 Splice +1083 0 Expression +1084 1 Splice +1085 1 Input +1086 0 Explore +1087 1 CodeGen +1088 1 Probing +1089 0 Explore +1090 1 Explore +1091 1 CodeGen +1092 0 Call +1093 1 Input +1094 1 CodeGen +1095 0 CodeGen +1096 1 Input +1097 1 Input +1098 0 Explore +1099 1 CodeGen +1100 1 Input +1101 0 Probing +1102 1 Explore +1103 1 Input +1104 0 Probing +1105 1 Input +1106 1 CodeGen +1107 0 Input +1108 1 Splice +1109 1 Explore +1110 0 Probing +1111 1 Splice +1112 1 Operation +1113 0 Expression +1114 1 CodeGen +1115 1 Operation +1116 0 Probing +1117 1 Explore +1118 1 CodeGen +1119 0 Explore +1120 1 CodeGen +1121 1 CodeGen +1122 0 Operation +1123 1 Input +1124 1 Probing +1125 0 Explore +1126 1 Expression +1127 1 Explore +1128 0 CodeGen +1129 1 Operation +1130 1 Input +1131 0 Probing +1132 1 Probing +1133 1 Splice +1134 0 Explore +1135 1 Input +1136 1 Explore +1137 0 Explore +1138 1 Splice +1139 1 Probing +1140 0 Probing +1141 1 Input +1142 1 CodeGen +1143 0 Input +1144 1 Explore +1145 1 Probing +1146 0 Input +1147 1 Explore +1148 1 Call +1149 0 CodeGen +1150 1 Splice +1151 1 Expression +1152 0 Explore +1153 1 Combine +1154 1 Input +1155 0 Call +1156 1 Probing +1157 1 Explore +1158 0 Probing +1159 1 CodeGen +1160 1 Probing +1161 0 CodeGen +1162 1 Splice +1163 1 Call +1164 0 Input +1165 1 Input +1166 1 Operation +1167 0 Probing +1168 1 Explore +1169 1 Explore +1170 0 CodeGen +1171 1 CodeGen +1172 1 Operation +1173 0 Input +1174 1 Combine +1175 1 Splice +1176 0 Probing +1177 1 Explore +1178 1 Combine +1179 0 Input +1180 1 Combine +1181 1 Splice +1182 0 Input +1183 1 Combine +1184 1 Input +1185 0 Explore +1186 1 Operation +1187 1 CodeGen +1188 0 Input +1189 1 Probing +1190 1 Expression +1191 0 Call +1192 1 CodeGen +1193 1 Combine +1194 0 Explore +1195 1 Splice +1196 1 CodeGen +1197 0 Input +1198 1 Combine +1199 1 Input +1200 0 Operation +1201 1 Explore +1202 1 CodeGen +1203 0 Probing +1204 1 Input +1205 1 Call +1206 0 Call +1207 1 CodeGen +1208 1 Combine +1209 0 Probing +1210 1 Combine +1211 1 Probing +1212 0 Probing +1213 1 Input +1214 1 Input +1215 0 Explore +1216 1 Explore +1217 1 CodeGen +1218 0 Input +1219 1 Input +1220 1 Operation +1221 0 Explore +1222 1 Operation +1223 1 Explore +1224 0 CodeGen +1225 1 Explore +1226 1 Splice +1227 0 Explore +1228 1 CodeGen +1229 1 CodeGen +1230 0 Probing +1231 1 Explore +1232 1 Call +1233 0 CodeGen +1234 1 Explore +1235 1 Splice +1236 0 Operation +1237 1 Call +1238 1 Combine +1239 0 Explore +1240 1 Explore +1241 1 Operation +1242 0 Explore +1243 1 Probing +1244 1 Probing +1245 0 Explore +1246 1 Probing +1247 1 Input +1248 0 Input +1249 1 Combine +1250 1 Probing +1251 0 Operation +1252 1 Input +1253 1 Explore +1254 0 Expression +1255 1 Probing +1256 1 Input +1257 0 Explore +1258 1 Combine +1259 1 Call +1260 0 CodeGen +1261 1 Combine +1262 1 Input +1263 0 CodeGen +1264 1 Operation +1265 1 Splice +1266 0 Input +1267 1 CodeGen +1268 1 Input +1269 0 Call +1270 1 Explore +1271 1 Explore +1272 0 CodeGen +1273 1 CodeGen +1274 1 Splice +1275 0 CodeGen +1276 1 Input +1277 1 Operation +1278 0 Input +1279 1 CodeGen +1280 1 Probing +1281 0 CodeGen +1282 1 Splice +1283 1 Explore +1284 0 Probing +1285 1 Expression +1286 1 CodeGen +1287 0 Input +1288 1 Explore +1289 1 Probing +1290 0 Operation +1291 1 Probing +1292 1 CodeGen +1293 0 CodeGen +1294 1 Input +1295 1 Splice +1296 0 Operation +1297 1 Splice +1298 1 Splice +1299 0 Input +1300 1 Combine +1301 1 Combine +1302 0 Probing +1303 1 Probing +1304 1 CodeGen +1305 0 Probing +1306 1 Input +1307 1 Explore +1308 0 Input +1309 1 Explore +1310 1 Input +1311 0 Probing +1312 1 Explore +1313 1 CodeGen +1314 0 Input +1315 1 Explore +1316 1 Explore +1317 0 Input +1318 1 Probing +1319 1 Call +1320 0 CodeGen +1321 1 Combine +1322 1 Expression +1323 0 Operation +1324 1 Splice +1325 1 Expression +1326 0 Input +1327 1 Explore +1328 1 Expression +1329 0 Probing +1330 1 Explore +1331 1 CodeGen +1332 0 Probing +1333 1 CodeGen +1334 1 CodeGen +1335 0 Input +1336 1 Combine +1337 1 Probing +1338 0 Explore +1339 1 Input +1340 1 Explore +1341 0 Probing +1342 1 Explore +1343 1 Probing +1344 0 CodeGen +1345 1 Probing +1346 1 Probing +1347 0 Expression +1348 1 CodeGen +1349 1 CodeGen +1350 0 Input +1351 1 Input +1352 1 Operation +1353 0 Input +1354 1 Input +1355 1 Probing +1356 0 CodeGen +1357 1 Splice +1358 1 Input +1359 0 Input +1360 1 Input +1361 1 Probing +1362 0 CodeGen +1363 1 Probing +1364 1 Probing +1365 0 Input +1366 1 Explore +1367 1 Splice +1368 0 Explore +1369 1 Explore +1370 1 Call +1371 0 Input +1372 1 Explore +1373 1 Probing +1374 0 Input +1375 1 Probing +1376 1 Probing +1377 0 Operation +1378 1 Splice +1379 1 CodeGen +1380 0 Explore +1381 1 Splice +1382 1 Probing +1383 0 Operation +1384 1 Splice +1385 1 Explore +1386 0 Input +1387 1 Explore +1388 1 CodeGen +1389 0 Input +1390 1 Input +1391 1 Input +1392 0 Input +1393 1 Splice +1394 1 Probing +1395 0 Input +1396 1 Operation +1397 1 Explore +1398 0 Input +1399 1 Splice +1400 1 Splice +1401 0 Probing +1402 1 Explore +1403 1 Input +1404 0 Input +1405 1 Splice +1406 1 Explore +1407 0 Probing +1408 1 CodeGen +1409 1 CodeGen +1410 0 Expression +1411 1 CodeGen +1412 1 CodeGen +1413 0 Input +1414 1 Call +1415 1 CodeGen +1416 0 Expression +1417 1 Probing +1418 1 CodeGen +1419 0 Operation +1420 1 Probing +1421 1 Splice +1422 0 Call +1423 1 Probing +1424 1 Input +1425 0 Expression +1426 1 Operation +1427 1 Explore +1428 0 Input +1429 1 Input +1430 1 CodeGen +1431 0 Input +1432 1 CodeGen +1433 1 Splice +1434 0 Operation +1435 1 Input +1436 1 Probing +1437 0 Explore +1438 1 Input +1439 1 Operation +1440 0 Input +1441 1 CodeGen +1442 1 Probing +1443 0 Probing +1444 1 Operation +1445 1 Combine +1446 0 Input +1447 1 Call +1448 1 Expression +1449 0 Input +1450 1 CodeGen +1451 1 Explore +1452 0 Probing +1453 1 Probing +1454 1 Splice +1455 0 CodeGen +1456 1 Expression +1457 1 Input +1458 0 Operation +1459 1 Explore +1460 1 Input +1461 0 CodeGen +1462 1 CodeGen +1463 1 Explore +1464 0 Explore +1465 1 Input +1466 1 CodeGen +1467 0 CodeGen +1468 1 Input +1469 1 Combine +1470 0 Call +1471 1 Probing +1472 1 Splice +1473 0 Explore +1474 1 Operation +1475 1 Splice +1476 0 Input +1477 1 Probing +1478 1 Input +1479 0 Input +1480 1 CodeGen +1481 1 Explore +1482 0 Explore +1483 1 Explore +1484 1 Explore +1485 0 Input +1486 1 Splice +1487 1 CodeGen +1488 0 Probing +1489 1 Probing +1490 1 Input +1491 0 Probing +1492 1 Probing +1493 1 Probing +1494 0 Explore +1495 1 Explore +1496 1 Input +1497 0 Operation +1498 1 Splice +1499 1 Splice +1500 0 Explore +1501 1 Call +1502 1 Explore +1503 0 Probing +1504 1 Operation +1505 1 Probing +1506 0 CodeGen +1507 1 Splice +1508 1 CodeGen +1509 0 Explore +1510 1 Expression +1511 1 CodeGen +1512 0 CodeGen +1513 1 Call +1514 1 Probing +1515 0 Probing +1516 1 Call +1517 1 Input +1518 0 Expression +1519 1 Splice +1520 1 Combine +1521 0 Input +1522 1 Probing +1523 1 Splice +1524 0 Probing +1525 1 Combine +1526 1 Input +1527 0 CodeGen +1528 1 Splice +1529 1 CodeGen +1530 0 CodeGen +1531 1 Probing +1532 1 Probing +1533 0 Probing +1534 1 CodeGen +1535 1 Probing +1536 0 CodeGen +1537 1 Probing +1538 1 Operation +1539 0 Probing +1540 1 Explore +1541 1 Expression +1542 0 Explore +1543 1 CodeGen +1544 1 Probing +1545 0 Explore +1546 1 Explore +1547 1 Combine +1548 0 Probing +1549 1 Probing +1550 1 CodeGen +1551 0 Input +1552 1 Expression +1553 1 Operation +1554 0 Explore +1555 1 Combine +1556 1 Probing +1557 0 Input +1558 1 Probing +1559 1 Input +1560 0 Call +1561 1 Splice +1562 1 Input +1563 0 Explore +1564 1 Input +1565 1 CodeGen +1566 0 Explore +1567 1 Explore +1568 1 Explore +1569 0 Expression +1570 1 Input +1571 1 Probing +1572 0 Input +1573 1 Combine +1574 1 Combine +1575 0 Probing +1576 1 Splice +1577 1 Explore +1578 0 Probing +1579 1 Input +1580 1 Probing +1581 0 Explore +1582 1 Combine +1583 1 Explore +1584 0 CodeGen +1585 1 Probing +1586 1 Input +1587 0 Expression +1588 1 Combine +1589 1 Explore +1590 0 Input +1591 1 Call +1592 1 Input +1593 0 Operation +1594 1 Splice +1595 1 Expression +1596 0 Input +1597 1 CodeGen +1598 1 Explore +1599 0 Explore +1600 1 Input +1601 1 Probing +1602 0 Input +1603 1 Call +1604 1 Splice +1605 0 CodeGen +1606 1 CodeGen +1607 1 Explore +1608 0 Input +1609 1 CodeGen +1610 1 Input +1611 0 CodeGen +1612 1 CodeGen +1613 1 Splice +1614 0 Call +1615 1 Probing +1616 1 CodeGen +1617 0 Operation +1618 1 Call +1619 1 Explore +1620 0 CodeGen +1621 1 Call +1622 1 CodeGen +1623 0 Explore +1624 1 Splice +1625 1 Explore +1626 0 Probing +1627 1 Operation +1628 1 Input +1629 0 Probing +1630 1 CodeGen +1631 1 Splice +1632 0 Input +1633 1 Input +1634 1 CodeGen +1635 0 Explore +1636 1 Combine +1637 1 Input +1638 0 Probing +1639 1 Expression +1640 1 Input +1641 0 Explore +1642 1 CodeGen +1643 1 Splice +1644 0 Probing +1645 1 Input +1646 1 Probing +1647 0 Operation +1648 1 Explore +1649 1 Explore +1650 0 Explore +1651 1 Input +1652 1 Operation +1653 0 CodeGen +1654 1 Explore +1655 1 Splice +1656 0 Input +1657 1 Explore +1658 1 Input +1659 0 Input +1660 1 Input +1661 1 CodeGen +1662 0 Input +1663 1 CodeGen +1664 1 Combine +1665 0 Input +1666 1 Combine +1667 1 Input +1668 0 Operation +1669 1 Operation +1670 1 Explore +1671 0 Input +1672 1 Splice +1673 1 Input +1674 0 Input +1675 1 Input +1676 1 Probing +1677 0 Explore +1678 1 Input +1679 1 Combine +1680 0 Operation +1681 1 Input +1682 1 Explore +1683 0 CodeGen +1684 1 Input +1685 1 CodeGen +1686 0 Explore +1687 1 Call +1688 1 Combine +1689 0 CodeGen +1690 1 Explore +1691 1 Combine +1692 0 Explore +1693 1 Explore +1694 1 Probing +1695 0 Input +1696 1 Input +1697 1 Combine +1698 0 Input +1699 1 Explore +1700 1 Explore +1701 0 Probing +1702 1 Input +1703 1 CodeGen +1704 0 Input +1705 1 Input +1706 1 Input +1707 0 Explore +1708 1 Explore +1709 1 Explore +1710 0 Call +1711 1 CodeGen +1712 1 Input +1713 0 Expression +1714 1 Explore +1715 1 CodeGen +1716 0 Explore +1717 1 Splice +1718 1 Probing +1719 0 Explore +1720 1 Splice +1721 1 Combine +1722 0 Explore +1723 1 Operation +1724 1 Explore +1725 0 Explore +1726 1 Explore +1727 1 Input +1728 0 Input +1729 1 CodeGen +1730 1 Operation +1731 0 Input +1732 1 Splice +1733 1 Combine +1734 0 Operation +1735 1 Call +1736 1 Explore +1737 0 CodeGen +1738 1 Explore +1739 1 Input +1740 0 Probing +1741 1 Input +1742 1 Operation +1743 0 Input +1744 1 Splice +1745 1 Input +1746 0 Operation +1747 1 Splice +1748 1 Explore +1749 0 Explore +1750 1 Explore +1751 1 Input +1752 0 Probing +1753 1 Input +1754 1 Explore +1755 0 Explore +1756 1 Combine +1757 1 Explore +1758 0 Operation +1759 1 Input +1760 1 Probing +1761 0 Explore +1762 1 Input +1763 1 Splice +1764 0 Input +1765 1 Probing +1766 1 Splice +1767 0 CodeGen +1768 1 Combine +1769 1 Input +1770 0 CodeGen +1771 1 Input +1772 1 Operation +1773 0 Expression +1774 1 Call +1775 1 Probing +1776 0 Input +1777 1 Probing +1778 1 Input +1779 0 Call +1780 1 Splice +1781 1 Probing +1782 0 Probing +1783 1 Combine +1784 1 Explore +1785 0 Input +1786 1 Expression +1787 1 Operation +1788 0 Input +1789 1 Explore +1790 1 Probing +1791 0 CodeGen +1792 1 Input +1793 1 Input +1794 0 Probing +1795 1 Operation +1796 1 Input +1797 0 Explore +1798 1 Combine +1799 1 CodeGen +1800 0 Input +1801 1 Input +1802 1 Splice +1803 0 Input +1804 1 Input +1805 1 Splice +1806 0 Probing +1807 1 Expression +1808 1 Combine +1809 0 Call +1810 1 Call +1811 1 Input +1812 0 CodeGen +1813 1 Input +1814 1 Explore +1815 0 Explore +1816 1 CodeGen +1817 1 Combine +1818 0 Explore +1819 1 Explore +1820 1 Explore +1821 0 Probing +1822 1 Operation +1823 1 Operation +1824 0 CodeGen +1825 1 Expression +1826 1 Splice +1827 0 Input +1828 1 Explore +1829 1 Explore +1830 0 Explore +1831 1 CodeGen +1832 1 Explore +1833 0 Operation +1834 1 Probing +1835 1 Input +1836 0 Explore +1837 1 Probing +1838 1 Explore +1839 0 Input +1840 1 Explore +1841 1 Operation +1842 0 Call +1843 1 Input +1844 1 CodeGen +1845 0 CodeGen +1846 1 Input +1847 1 Input +1848 0 Input +1849 1 Explore +1850 1 Probing +1851 0 Input +1852 1 Explore +1853 1 Probing +1854 0 Input +1855 1 Call +1856 1 Splice +1857 0 Input +1858 1 Input +1859 1 Explore +1860 0 Input +1861 1 CodeGen +1862 1 Splice +1863 0 Input +1864 1 Explore +1865 1 Input +1866 0 Expression +1867 1 CodeGen +1868 1 Combine +1869 0 Probing +1870 1 Explore +1871 1 Expression +1872 0 Explore +1873 1 Combine +1874 1 Operation +1875 0 Input +1876 1 Probing +1877 1 Explore +1878 0 Explore +1879 1 Probing +1880 1 Input +1881 0 CodeGen +1882 1 Explore +1883 1 Explore +1884 0 Input +1885 1 Operation +1886 1 Splice +1887 0 Input +1888 1 Splice +1889 1 Splice +1890 0 Explore +1891 1 Input +1892 1 Splice +1893 0 Input +1894 1 Splice +1895 1 Operation +1896 0 Explore +1897 1 Splice +1898 1 Splice +1899 0 CodeGen +1900 1 CodeGen +1901 1 Explore +1902 0 Operation +1903 1 Explore +1904 1 Input +1905 0 Expression +1906 1 Combine +1907 1 Operation +1908 0 Probing +1909 1 Splice +1910 1 Explore +1911 0 Explore +1912 1 Splice +1913 1 Input +1914 0 Probing +1915 1 Input +1916 1 CodeGen +1917 0 Explore +1918 1 Probing +1919 1 Splice +1920 0 Explore +1921 1 CodeGen +1922 1 Probing +1923 0 Probing +1924 1 Splice +1925 1 Probing +1926 0 CodeGen +1927 1 Operation +1928 1 Explore +1929 0 Input +1930 1 CodeGen +1931 1 Splice +1932 0 Operation +1933 1 Splice +1934 1 Input +1935 0 Explore +1936 1 CodeGen +1937 1 Explore +1938 0 Expression +1939 1 Explore +1940 1 Probing +1941 0 CodeGen +1942 1 Probing +1943 1 Splice +1944 0 Explore +1945 1 Splice +1946 1 Call +1947 0 Input +1948 1 Input +1949 1 Combine +1950 0 Input +1951 1 CodeGen +1952 1 Splice +1953 0 CodeGen +1954 1 Operation +1955 1 Probing +1956 0 Input +1957 1 Splice +1958 1 Probing +1959 0 Input +1960 1 Input +1961 1 Explore +1962 0 Operation +1963 1 CodeGen +1964 1 CodeGen +1965 0 Explore +1966 1 Explore +1967 1 Probing +1968 0 Explore +1969 1 Probing +1970 1 CodeGen +1971 0 CodeGen +1972 1 Explore +1973 1 Probing +1974 0 Probing +1975 1 Splice +1976 1 Explore +1977 0 CodeGen +1978 1 Input +1979 1 Call +1980 0 CodeGen +1981 1 CodeGen +1982 1 Explore +1983 0 Operation +1984 1 Explore +1985 1 Splice +1986 0 CodeGen +1987 1 Input +1988 1 Explore +1989 0 Operation +1990 1 Probing +1991 1 Combine +1992 0 CodeGen +1993 1 Explore +1994 1 Explore +1995 0 Probing +1996 1 Combine +1997 1 Splice +1998 0 Explore +1999 1 Probing diff --git a/deps/v8/experimental/redline/testdata/selection/scheduler_productive.trace b/deps/v8/experimental/redline/testdata/selection/scheduler_productive.trace new file mode 100644 index 000000000000..edde7903300e --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/scheduler_productive.trace @@ -0,0 +1,1000 @@ +0 38 42 +1 20 43 +2 41 34 +3 38 34 +4 30 20 +5 50 4 +6 31 41 +7 47 21 +8 38 26 +9 46 19 +10 7 30 +11 49 46 +12 37 1 +13 24 33 +14 1 45 +15 21 30 +16 38 3 +17 40 3 +18 17 37 +19 14 33 +20 42 20 +21 19 31 +22 12 34 +23 2 18 +24 32 30 +25 36 6 +26 45 42 +27 39 17 +28 5 11 +29 19 32 +30 1 7 +31 5 19 +32 15 43 +33 8 40 +34 38 36 +35 38 43 +36 26 32 +37 6 30 +38 18 26 +39 11 42 +40 43 16 +41 38 31 +42 49 7 +43 37 46 +44 16 48 +45 44 30 +46 4 23 +47 27 18 +48 5 30 +49 19 41 +50 9 39 +51 5 10 +52 17 47 +53 29 42 +54 22 44 +55 48 4 +56 38 2 +57 27 17 +58 1 4 +59 5 46 +60 3 47 +61 38 23 +62 47 26 +63 35 23 +64 35 25 +65 42 32 +66 33 15 +67 40 6 +68 32 45 +69 19 41 +70 28 24 +71 15 28 +72 6 25 +73 41 32 +74 38 39 +75 46 21 +76 23 6 +77 14 20 +78 25 31 +79 38 17 +80 4 40 +81 38 21 +82 26 27 +83 38 39 +84 28 29 +85 19 16 +86 47 19 +87 23 11 +88 9 12 +89 29 32 +90 28 29 +91 13 34 +92 21 31 +93 2 20 +94 44 27 +95 13 15 +96 38 36 +97 35 1 +98 47 22 +99 20 6 +100 39 11 +101 36 30 +102 35 29 +103 11 46 +104 14 9 +105 1 45 +106 8 10 +107 19 47 +108 33 50 +109 40 11 +110 19 9 +111 20 47 +112 38 37 +113 1 3 +114 2 15 +115 34 43 +116 5 47 +117 19 42 +118 47 33 +119 28 30 +120 3 26 +121 28 8 +122 10 28 +123 14 23 +124 22 41 +125 38 42 +126 31 15 +127 36 21 +128 28 45 +129 22 12 +130 1 38 +131 16 11 +132 49 36 +133 28 24 +134 35 31 +135 27 40 +136 5 30 +137 28 41 +138 34 41 +139 14 31 +140 28 43 +141 5 11 +142 1 45 +143 28 45 +144 50 15 +145 38 36 +146 31 12 +147 31 49 +148 13 17 +149 18 4 +150 1 32 +151 10 9 +152 32 36 +153 12 30 +154 45 33 +155 30 46 +156 35 13 +157 48 11 +158 1 11 +159 8 7 +160 43 8 +161 25 11 +162 25 37 +163 31 29 +164 6 14 +165 31 16 +166 14 44 +167 25 45 +168 28 50 +169 31 33 +170 30 41 +171 24 12 +172 43 2 +173 14 5 +174 19 30 +175 5 38 +176 31 42 +177 45 18 +178 12 30 +179 4 12 +180 14 3 +181 18 49 +182 16 6 +183 50 29 +184 33 34 +185 19 20 +186 45 4 +187 16 26 +188 13 3 +189 20 26 +190 46 26 +191 15 16 +192 41 48 +193 16 44 +194 28 44 +195 41 26 +196 28 46 +197 45 31 +198 3 26 +199 42 47 +200 47 4 +201 31 29 +202 35 46 +203 23 34 +204 19 1 +205 47 9 +206 33 11 +207 17 27 +208 29 15 +209 28 33 +210 20 26 +211 23 32 +212 38 2 +213 31 32 +214 5 9 +215 19 5 +216 23 32 +217 47 16 +218 20 1 +219 39 29 +220 19 22 +221 44 22 +222 25 6 +223 29 15 +224 47 9 +225 38 39 +226 48 1 +227 19 40 +228 37 17 +229 23 28 +230 49 21 +231 20 14 +232 10 18 +233 35 46 +234 1 10 +235 23 27 +236 19 48 +237 47 9 +238 24 49 +239 46 17 +240 4 38 +241 5 43 +242 23 12 +243 39 23 +244 49 45 +245 24 25 +246 5 21 +247 19 14 +248 38 30 +249 28 42 +250 24 50 +251 45 8 +252 48 16 +253 9 17 +254 25 23 +255 5 38 +256 45 35 +257 19 14 +258 37 49 +259 45 29 +260 2 47 +261 38 46 +262 6 34 +263 31 50 +264 38 35 +265 24 22 +266 35 45 +267 38 36 +268 31 19 +269 48 25 +270 43 22 +271 20 49 +272 1 42 +273 20 38 +274 11 24 +275 35 28 +276 28 45 +277 1 25 +278 5 3 +279 1 23 +280 16 5 +281 23 17 +282 25 8 +283 12 23 +284 35 9 +285 14 49 +286 48 11 +287 31 21 +288 23 24 +289 28 38 +290 26 13 +291 5 47 +292 25 28 +293 35 32 +294 28 39 +295 7 33 +296 19 6 +297 10 5 +298 38 43 +299 1 43 +300 49 34 +301 31 22 +302 19 16 +303 6 45 +304 13 6 +305 16 3 +306 24 50 +307 8 44 +308 50 12 +309 9 21 +310 19 38 +311 18 37 +312 20 40 +313 49 4 +314 7 47 +315 1 40 +316 49 2 +317 28 43 +318 47 23 +319 28 25 +320 38 11 +321 24 2 +322 1 44 +323 28 34 +324 31 5 +325 23 40 +326 25 10 +327 2 14 +328 19 6 +329 48 28 +330 48 23 +331 5 2 +332 38 12 +333 38 15 +334 19 20 +335 1 35 +336 34 37 +337 22 43 +338 20 7 +339 24 15 +340 25 50 +341 19 35 +342 19 30 +343 19 46 +344 28 15 +345 36 38 +346 30 31 +347 40 30 +348 24 43 +349 24 25 +350 48 7 +351 34 4 +352 48 44 +353 50 17 +354 47 9 +355 34 30 +356 45 39 +357 16 47 +358 5 27 +359 31 50 +360 1 11 +361 23 7 +362 47 13 +363 1 10 +364 5 6 +365 31 23 +366 15 24 +367 20 39 +368 17 9 +369 28 7 +370 22 23 +371 19 9 +372 45 25 +373 50 25 +374 19 28 +375 16 5 +376 50 27 +377 47 26 +378 38 29 +379 28 4 +380 25 19 +381 5 20 +382 45 24 +383 19 7 +384 23 32 +385 1 30 +386 48 33 +387 23 35 +388 38 14 +389 5 14 +390 47 23 +391 32 25 +392 24 43 +393 31 11 +394 19 47 +395 31 50 +396 42 49 +397 31 11 +398 38 49 +399 5 8 +400 41 5 +401 50 22 +402 49 14 +403 5 21 +404 28 46 +405 5 27 +406 1 20 +407 27 48 +408 3 25 +409 19 45 +410 16 44 +411 46 24 +412 34 32 +413 35 5 +414 33 35 +415 43 37 +416 25 36 +417 20 31 +418 38 6 +419 16 49 +420 16 32 +421 14 35 +422 31 13 +423 35 3 +424 42 12 +425 16 6 +426 48 2 +427 19 14 +428 28 45 +429 14 39 +430 38 34 +431 30 50 +432 14 36 +433 28 31 +434 24 26 +435 13 37 +436 38 12 +437 31 43 +438 17 29 +439 29 1 +440 31 39 +441 48 20 +442 21 49 +443 24 33 +444 47 46 +445 35 3 +446 39 45 +447 34 5 +448 24 31 +449 36 47 +450 31 43 +451 13 12 +452 32 16 +453 9 44 +454 49 32 +455 11 6 +456 11 39 +457 13 31 +458 16 40 +459 34 36 +460 31 38 +461 19 50 +462 40 10 +463 28 37 +464 48 5 +465 25 48 +466 45 34 +467 16 19 +468 5 15 +469 45 32 +470 16 39 +471 27 44 +472 21 3 +473 5 12 +474 47 45 +475 23 16 +476 30 38 +477 4 29 +478 24 22 +479 28 45 +480 12 26 +481 28 12 +482 1 15 +483 20 28 +484 20 31 +485 34 2 +486 45 18 +487 21 36 +488 10 5 +489 16 19 +490 1 9 +491 20 26 +492 7 49 +493 8 42 +494 28 36 +495 20 31 +496 14 24 +497 11 21 +498 31 39 +499 16 47 +500 16 21 +501 28 47 +502 11 7 +503 31 12 +504 45 19 +505 20 43 +506 38 24 +507 40 48 +508 1 22 +509 13 46 +510 13 25 +511 45 18 +512 48 3 +513 28 36 +514 25 6 +515 21 4 +516 47 49 +517 10 38 +518 24 33 +519 45 23 +520 5 37 +521 49 7 +522 47 8 +523 19 17 +524 31 36 +525 2 34 +526 45 25 +527 38 3 +528 31 47 +529 7 20 +530 6 41 +531 28 29 +532 25 7 +533 25 16 +534 26 9 +535 16 18 +536 20 30 +537 47 22 +538 5 44 +539 13 32 +540 20 13 +541 5 17 +542 11 20 +543 25 11 +544 20 27 +545 40 17 +546 1 41 +547 30 2 +548 44 41 +549 28 6 +550 45 33 +551 38 1 +552 5 1 +553 5 43 +554 28 14 +555 31 38 +556 19 13 +557 20 47 +558 45 17 +559 31 47 +560 5 9 +561 47 39 +562 50 32 +563 16 5 +564 38 22 +565 15 38 +566 16 42 +567 42 38 +568 13 30 +569 1 7 +570 19 45 +571 2 7 +572 38 27 +573 16 2 +574 45 38 +575 5 17 +576 25 37 +577 5 25 +578 19 31 +579 47 38 +580 31 41 +581 34 20 +582 25 2 +583 50 20 +584 40 11 +585 11 28 +586 45 7 +587 45 29 +588 46 5 +589 47 21 +590 45 44 +591 42 30 +592 1 2 +593 14 10 +594 49 8 +595 1 41 +596 28 34 +597 23 39 +598 3 43 +599 2 3 +600 19 39 +601 20 30 +602 47 46 +603 19 44 +604 11 14 +605 47 37 +606 2 37 +607 47 18 +608 46 19 +609 24 8 +610 38 50 +611 24 25 +612 7 45 +613 50 42 +614 46 25 +615 5 41 +616 24 9 +617 30 23 +618 44 40 +619 48 26 +620 46 8 +621 19 10 +622 43 19 +623 35 43 +624 11 10 +625 28 26 +626 24 8 +627 34 22 +628 20 38 +629 38 41 +630 24 42 +631 31 26 +632 34 25 +633 50 5 +634 35 21 +635 1 41 +636 14 6 +637 28 17 +638 24 46 +639 47 32 +640 31 30 +641 24 5 +642 38 33 +643 31 25 +644 14 44 +645 1 46 +646 16 20 +647 35 6 +648 45 23 +649 19 8 +650 49 7 +651 25 28 +652 5 19 +653 44 10 +654 45 12 +655 30 8 +656 25 28 +657 48 8 +658 14 23 +659 14 44 +660 11 40 +661 16 46 +662 31 20 +663 20 19 +664 24 11 +665 35 19 +666 45 13 +667 2 23 +668 19 40 +669 5 44 +670 46 9 +671 31 37 +672 20 45 +673 36 18 +674 30 10 +675 25 45 +676 5 25 +677 13 42 +678 16 47 +679 45 30 +680 10 40 +681 24 39 +682 1 27 +683 16 26 +684 45 5 +685 16 49 +686 24 14 +687 35 13 +688 32 18 +689 32 39 +690 5 28 +691 1 47 +692 20 11 +693 20 44 +694 20 14 +695 20 8 +696 40 23 +697 1 34 +698 5 14 +699 1 45 +700 20 13 +701 19 10 +702 47 22 +703 31 1 +704 48 7 +705 28 40 +706 26 31 +707 2 49 +708 2 47 +709 19 16 +710 34 24 +711 24 25 +712 31 42 +713 38 5 +714 23 35 +715 45 10 +716 38 12 +717 2 49 +718 33 26 +719 39 38 +720 26 13 +721 19 5 +722 1 17 +723 13 12 +724 30 35 +725 24 50 +726 24 41 +727 50 7 +728 1 12 +729 38 31 +730 40 49 +731 31 45 +732 13 8 +733 25 4 +734 49 45 +735 42 18 +736 47 15 +737 20 2 +738 49 29 +739 14 31 +740 45 1 +741 5 50 +742 20 27 +743 46 21 +744 11 33 +745 24 25 +746 48 35 +747 46 22 +748 14 40 +749 28 43 +750 20 19 +751 20 33 +752 5 31 +753 34 1 +754 38 46 +755 11 26 +756 40 15 +757 47 13 +758 31 40 +759 40 32 +760 5 8 +761 47 38 +762 5 38 +763 27 14 +764 48 18 +765 22 9 +766 42 41 +767 28 3 +768 5 48 +769 45 37 +770 16 35 +771 46 49 +772 19 49 +773 48 33 +774 47 15 +775 19 24 +776 27 34 +777 50 12 +778 24 43 +779 34 11 +780 31 32 +781 9 38 +782 45 25 +783 25 28 +784 34 43 +785 16 4 +786 47 9 +787 12 49 +788 50 30 +789 16 15 +790 5 17 +791 38 17 +792 28 9 +793 20 43 +794 34 2 +795 16 48 +796 27 43 +797 45 32 +798 15 40 +799 45 37 +800 28 48 +801 11 13 +802 17 39 +803 40 10 +804 5 34 +805 28 8 +806 15 28 +807 20 33 +808 5 7 +809 48 1 +810 11 3 +811 14 42 +812 20 32 +813 5 9 +814 1 7 +815 13 20 +816 45 39 +817 42 28 +818 29 24 +819 45 16 +820 1 13 +821 41 28 +822 19 45 +823 16 47 +824 31 10 +825 35 20 +826 5 25 +827 14 43 +828 31 18 +829 20 29 +830 25 20 +831 1 6 +832 21 38 +833 5 2 +834 5 39 +835 2 20 +836 28 17 +837 19 10 +838 47 38 +839 35 34 +840 42 43 +841 1 34 +842 20 21 +843 42 26 +844 16 49 +845 20 15 +846 20 37 +847 40 48 +848 19 18 +849 47 7 +850 40 33 +851 20 37 +852 19 43 +853 30 28 +854 25 3 +855 19 2 +856 45 17 +857 45 14 +858 24 6 +859 47 19 +860 25 12 +861 1 19 +862 20 3 +863 28 2 +864 47 19 +865 45 2 +866 24 10 +867 14 41 +868 1 10 +869 16 44 +870 45 34 +871 46 32 +872 30 38 +873 20 48 +874 40 6 +875 50 9 +876 3 45 +877 28 7 +878 20 16 +879 1 9 +880 18 46 +881 42 18 +882 38 20 +883 20 44 +884 16 34 +885 27 24 +886 24 21 +887 14 24 +888 50 20 +889 48 50 +890 14 28 +891 31 15 +892 42 3 +893 28 38 +894 13 27 +895 24 17 +896 47 36 +897 12 6 +898 38 43 +899 28 44 +900 16 41 +901 24 35 +902 24 40 +903 24 49 +904 28 39 +905 16 47 +906 14 33 +907 25 1 +908 16 4 +909 45 27 +910 20 24 +911 11 1 +912 48 14 +913 47 34 +914 4 28 +915 48 34 +916 38 14 +917 2 35 +918 42 33 +919 16 31 +920 35 37 +921 38 45 +922 49 1 +923 20 23 +924 35 39 +925 20 14 +926 5 20 +927 7 27 +928 23 16 +929 45 15 +930 48 27 +931 16 25 +932 24 23 +933 1 27 +934 19 20 +935 35 26 +936 25 10 +937 48 31 +938 11 40 +939 20 28 +940 47 35 +941 5 21 +942 45 19 +943 1 38 +944 1 8 +945 35 40 +946 28 49 +947 17 11 +948 20 44 +949 20 30 +950 5 28 +951 45 31 +952 20 48 +953 20 45 +954 47 1 +955 5 17 +956 34 10 +957 1 38 +958 38 50 +959 25 50 +960 2 34 +961 24 19 +962 33 37 +963 16 30 +964 28 34 +965 25 7 +966 48 18 +967 25 23 +968 48 10 +969 23 21 +970 45 13 +971 13 35 +972 45 18 +973 47 48 +974 24 2 +975 20 23 +976 47 11 +977 30 2 +978 19 42 +979 48 5 +980 16 9 +981 35 48 +982 1 36 +983 42 30 +984 45 3 +985 1 18 +986 42 3 +987 13 15 +988 35 50 +989 8 38 +990 1 21 +991 40 1 +992 45 21 +993 30 38 +994 25 46 +995 27 38 +996 2 49 +997 20 17 +998 2 17 +999 47 7 diff --git a/deps/v8/experimental/redline/testdata/selection/scheduler_recency.trace b/deps/v8/experimental/redline/testdata/selection/scheduler_recency.trace new file mode 100644 index 000000000000..e8b16208399f --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/scheduler_recency.trace @@ -0,0 +1,1000 @@ +0 19 30 +1 46 49 +2 43 41 +3 33 34 +4 38 17 +5 47 9 +6 46 50 +7 21 4 +8 8 20 +9 50 33 +10 46 38 +11 50 26 +12 45 15 +13 47 46 +14 47 49 +15 43 46 +16 45 48 +17 46 49 +18 33 1 +19 49 45 +20 44 4 +21 48 2 +22 3 40 +23 45 3 +24 45 15 +25 14 50 +26 33 42 +27 46 20 +28 48 39 +29 30 12 +30 48 37 +31 13 18 +32 50 42 +33 21 36 +34 43 49 +35 25 45 +36 49 12 +37 17 20 +38 35 11 +39 19 25 +40 1 8 +41 44 46 +42 48 19 +43 6 36 +44 46 8 +45 49 7 +46 46 36 +47 22 38 +48 47 46 +49 32 6 +50 35 30 +51 45 17 +52 40 49 +53 42 43 +54 33 16 +55 38 17 +56 49 7 +57 43 37 +58 15 46 +59 44 18 +60 44 46 +61 30 36 +62 44 23 +63 44 32 +64 37 2 +65 30 19 +66 43 41 +67 50 18 +68 5 27 +69 10 17 +70 20 47 +71 50 36 +72 46 37 +73 44 37 +74 26 4 +75 50 38 +76 27 45 +77 17 5 +78 43 4 +79 44 5 +80 43 35 +81 50 38 +82 46 23 +83 50 33 +84 20 15 +85 46 5 +86 48 25 +87 46 26 +88 33 40 +89 15 40 +90 3 6 +91 3 22 +92 27 19 +93 41 42 +94 46 24 +95 43 33 +96 6 11 +97 25 41 +98 6 32 +99 38 13 +100 46 7 +101 46 23 +102 46 6 +103 50 4 +104 9 25 +105 47 38 +106 44 17 +107 44 46 +108 7 22 +109 21 26 +110 49 27 +111 49 38 +112 37 28 +113 29 19 +114 14 16 +115 43 47 +116 46 6 +117 44 9 +118 2 12 +119 4 17 +120 28 34 +121 29 31 +122 13 34 +123 46 6 +124 2 48 +125 46 44 +126 16 27 +127 13 15 +128 45 38 +129 35 2 +130 1 25 +131 47 22 +132 46 50 +133 49 8 +134 44 21 +135 47 30 +136 48 43 +137 44 11 +138 46 14 +139 48 9 +140 48 35 +141 29 8 +142 10 5 +143 19 47 +144 48 17 +145 49 2 +146 44 43 +147 46 9 +148 32 27 +149 38 50 +150 37 2 +151 1 3 +152 49 42 +153 34 11 +154 43 5 +155 49 47 +156 41 15 +157 50 47 +158 48 28 +159 12 28 +160 46 3 +161 26 43 +162 28 8 +163 44 45 +164 45 17 +165 23 22 +166 43 41 +167 11 38 +168 31 32 +169 45 36 +170 49 21 +171 28 14 +172 20 22 +173 12 43 +174 43 38 +175 16 10 +176 48 49 +177 36 21 +178 28 24 +179 35 24 +180 27 16 +181 40 5 +182 47 30 +183 47 8 +184 48 22 +185 41 46 +186 23 31 +187 47 30 +188 30 37 +189 11 1 +190 4 45 +191 47 45 +192 50 40 +193 15 46 +194 38 36 +195 37 31 +196 33 22 +197 49 14 +198 7 17 +199 44 18 +200 43 35 +201 48 17 +202 10 9 +203 43 34 +204 12 40 +205 30 37 +206 50 33 +207 27 32 +208 35 11 +209 45 48 +210 22 11 +211 1 37 +212 8 16 +213 44 32 +214 46 8 +215 25 29 +216 7 43 +217 37 34 +218 31 29 +219 26 43 +220 47 1 +221 16 11 +222 14 44 +223 43 42 +224 28 1 +225 50 31 +226 1 33 +227 26 22 +228 37 11 +229 12 36 +230 34 2 +231 48 14 +232 44 19 +233 30 43 +234 43 38 +235 32 31 +236 41 45 +237 18 12 +238 46 30 +239 34 36 +240 36 14 +241 14 3 +242 43 36 +243 16 44 +244 43 8 +245 50 29 +246 39 6 +247 19 4 +248 20 42 +249 50 4 +250 16 48 +251 49 14 +252 43 20 +253 47 20 +254 48 12 +255 26 15 +256 48 16 +257 6 50 +258 21 16 +259 44 5 +260 45 44 +261 30 41 +262 28 23 +263 46 9 +264 50 31 +265 44 36 +266 42 27 +267 50 40 +268 47 4 +269 16 6 +270 9 46 +271 50 22 +272 23 34 +273 43 19 +274 47 17 +275 33 3 +276 11 8 +277 39 27 +278 29 15 +279 50 28 +280 48 9 +281 47 23 +282 42 32 +283 48 38 +284 50 31 +285 32 40 +286 5 9 +287 19 46 +288 47 45 +289 32 5 +290 45 16 +291 45 44 +292 47 6 +293 47 30 +294 14 22 +295 29 44 +296 44 35 +297 6 29 +298 43 15 +299 35 22 +300 46 34 +301 39 42 +302 29 1 +303 46 25 +304 50 37 +305 48 17 +306 45 26 +307 49 26 +308 21 20 +309 50 14 +310 10 44 +311 50 35 +312 50 19 +313 1 10 +314 44 29 +315 19 24 +316 48 15 +317 50 9 +318 44 24 +319 50 48 +320 17 4 +321 44 38 +322 45 43 +323 43 27 +324 49 44 +325 46 44 +326 34 45 +327 45 6 +328 43 4 +329 46 19 +330 17 14 +331 49 34 +332 47 46 +333 42 3 +334 24 50 +335 45 33 +336 48 42 +337 16 9 +338 21 17 +339 11 23 +340 19 5 +341 49 45 +342 32 35 +343 41 8 +344 49 37 +345 49 45 +346 49 29 +347 47 2 +348 38 13 +349 46 6 +350 48 34 +351 47 48 +352 38 37 +353 48 24 +354 9 22 +355 15 35 +356 44 46 +357 48 8 +358 31 19 +359 47 48 +360 49 12 +361 22 20 +362 7 49 +363 44 1 +364 36 20 +365 48 22 +366 49 24 +367 2 35 +368 9 24 +369 45 48 +370 50 25 +371 5 14 +372 43 41 +373 45 48 +374 5 46 +375 23 17 +376 45 39 +377 12 30 +378 23 35 +379 49 9 +380 48 14 +381 4 25 +382 11 31 +383 50 21 +384 23 3 +385 43 28 +386 38 44 +387 47 13 +388 43 2 +389 48 33 +390 47 15 +391 48 32 +392 39 32 +393 18 46 +394 33 19 +395 49 6 +396 10 29 +397 38 33 +398 49 8 +399 25 43 +400 50 3 +401 47 31 +402 46 39 +403 19 16 +404 49 37 +405 13 44 +406 6 16 +407 21 3 +408 24 15 +409 43 8 +410 50 32 +411 12 46 +412 45 21 +413 21 41 +414 33 18 +415 48 16 +416 46 40 +417 48 49 +418 32 42 +419 47 25 +420 1 40 +421 10 12 +422 43 28 +423 43 47 +424 43 23 +425 47 9 +426 49 5 +427 11 21 +428 46 2 +429 49 27 +430 47 26 +431 48 31 +432 45 5 +433 37 9 +434 44 40 +435 44 2 +436 44 14 +437 45 50 +438 48 43 +439 48 40 +440 50 23 +441 5 23 +442 2 38 +443 46 12 +444 10 23 +445 23 6 +446 20 48 +447 5 35 +448 44 34 +449 46 8 +450 49 34 +451 46 7 +452 45 35 +453 46 10 +454 50 41 +455 19 35 +456 22 43 +457 43 19 +458 45 46 +459 45 39 +460 2 37 +461 49 33 +462 17 31 +463 44 40 +464 47 24 +465 43 39 +466 45 25 +467 4 48 +468 43 34 +469 4 48 +470 3 44 +471 27 50 +472 49 47 +473 44 34 +474 43 30 +475 47 45 +476 46 16 +477 47 42 +478 46 27 +479 31 33 +480 48 35 +481 44 27 +482 47 7 +483 49 43 +484 49 5 +485 10 14 +486 5 6 +487 31 49 +488 47 15 +489 24 33 +490 44 39 +491 44 17 +492 12 35 +493 7 22 +494 49 23 +495 18 10 +496 48 45 +497 25 11 +498 9 25 +499 45 3 +500 7 16 +501 5 8 +502 23 27 +503 48 47 +504 33 38 +505 29 28 +506 49 4 +507 44 3 +508 46 29 +509 46 6 +510 45 24 +511 50 19 +512 23 18 +513 48 22 +514 1 30 +515 45 15 +516 23 33 +517 35 50 +518 48 14 +519 43 10 +520 45 47 +521 46 32 +522 48 25 +523 9 25 +524 18 17 +525 11 8 +526 37 47 +527 44 31 +528 42 46 +529 49 31 +530 45 11 +531 45 39 +532 46 9 +533 8 41 +534 40 5 +535 47 50 +536 6 46 +537 45 5 +538 4 21 +539 12 25 +540 36 22 +541 27 30 +542 43 20 +543 48 27 +544 49 10 +545 46 23 +546 19 45 +547 44 16 +548 46 3 +549 46 34 +550 42 32 +551 3 35 +552 33 39 +553 48 43 +554 15 37 +555 48 33 +556 46 18 +557 47 42 +558 44 6 +559 43 16 +560 33 8 +561 48 18 +562 46 35 +563 31 13 +564 26 35 +565 49 37 +566 12 11 +567 50 6 +568 50 12 +569 45 24 +570 45 28 +571 14 45 +572 45 11 +573 38 7 +574 34 30 +575 43 50 +576 2 8 +577 47 39 +578 31 24 +579 45 26 +580 45 13 +581 46 38 +582 44 31 +583 49 43 +584 45 40 +585 49 22 +586 1 31 +587 43 39 +588 50 49 +589 39 21 +590 49 24 +591 26 33 +592 48 47 +593 35 17 +594 3 39 +595 47 45 +596 45 34 +597 48 43 +598 31 36 +599 47 31 +600 50 43 +601 49 13 +602 43 32 +603 45 9 +604 50 44 +605 49 30 +606 44 10 +607 43 11 +608 22 39 +609 46 7 +610 45 44 +611 40 2 +612 34 36 +613 10 18 +614 8 19 +615 50 30 +616 49 10 +617 3 28 +618 15 35 +619 43 33 +620 44 48 +621 48 45 +622 46 17 +623 19 35 +624 44 15 +625 45 26 +626 26 30 +627 39 27 +628 47 44 +629 47 29 +630 43 13 +631 12 41 +632 34 45 +633 47 12 +634 47 41 +635 38 4 +636 46 29 +637 7 24 +638 28 17 +639 50 12 +640 2 26 +641 47 40 +642 1 9 +643 15 20 +644 46 28 +645 47 49 +646 48 33 +647 2 27 +648 50 18 +649 47 21 +650 49 10 +651 43 7 +652 15 19 +653 21 1 +654 44 20 +655 26 7 +656 49 8 +657 45 42 +658 28 5 +659 44 45 +660 47 4 +661 45 24 +662 25 11 +663 47 5 +664 49 10 +665 16 47 +666 44 16 +667 10 5 +668 47 11 +669 39 7 +670 21 31 +671 7 13 +672 19 17 +673 8 43 +674 45 38 +675 48 40 +676 50 8 +677 27 22 +678 43 13 +679 44 13 +680 25 45 +681 16 18 +682 48 44 +683 47 17 +684 36 2 +685 3 6 +686 46 10 +687 34 35 +688 49 10 +689 8 38 +690 25 24 +691 45 20 +692 46 40 +693 45 37 +694 50 4 +695 47 39 +696 8 10 +697 19 17 +698 47 7 +699 43 22 +700 48 40 +701 49 25 +702 27 37 +703 45 31 +704 50 41 +705 7 20 +706 43 42 +707 44 33 +708 47 39 +709 25 7 +710 45 42 +711 18 8 +712 9 32 +713 47 18 +714 32 3 +715 50 31 +716 46 39 +717 43 44 +718 26 3 +719 46 39 +720 13 34 +721 44 17 +722 44 13 +723 36 25 +724 44 18 +725 25 27 +726 36 33 +727 44 35 +728 41 43 +729 30 2 +730 49 12 +731 47 18 +732 43 44 +733 44 33 +734 48 30 +735 18 11 +736 1 11 +737 5 43 +738 28 38 +739 47 37 +740 49 19 +741 45 13 +742 9 41 +743 44 40 +744 45 50 +745 47 35 +746 43 9 +747 47 31 +748 47 39 +749 32 31 +750 48 16 +751 48 42 +752 46 36 +753 49 38 +754 45 32 +755 6 42 +756 49 4 +757 45 30 +758 49 1 +759 50 19 +760 50 2 +761 46 7 +762 48 3 +763 29 36 +764 43 12 +765 50 38 +766 43 20 +767 45 25 +768 48 19 +769 45 25 +770 43 4 +771 47 25 +772 38 31 +773 41 3 +774 6 20 +775 46 25 +776 47 33 +777 20 40 +778 45 11 +779 11 2 +780 50 49 +781 44 45 +782 34 29 +783 21 46 +784 9 47 +785 46 13 +786 45 44 +787 15 42 +788 1 25 +789 2 39 +790 45 10 +791 49 4 +792 34 40 +793 1 41 +794 47 17 +795 7 9 +796 49 3 +797 39 43 +798 44 3 +799 43 19 +800 39 25 +801 20 30 +802 17 47 +803 43 19 +804 44 25 +805 44 14 +806 47 32 +807 2 32 +808 48 36 +809 18 27 +810 15 46 +811 24 36 +812 44 12 +813 2 50 +814 6 35 +815 7 6 +816 50 4 +817 50 42 +818 8 46 +819 5 35 +820 49 43 +821 46 9 +822 50 7 +823 49 44 +824 40 48 +825 46 26 +826 46 21 +827 4 19 +828 44 43 +829 49 19 +830 2 35 +831 33 11 +832 44 10 +833 15 28 +834 48 42 +835 44 49 +836 37 22 +837 44 12 +838 38 41 +839 41 29 +840 47 42 +841 49 31 +842 44 34 +843 25 15 +844 50 5 +845 4 33 +846 50 1 +847 41 43 +848 14 6 +849 47 36 +850 48 24 +851 50 47 +852 32 15 +853 47 30 +854 30 10 +855 41 15 +856 48 31 +857 42 25 +858 14 41 +859 1 43 +860 46 7 +861 16 20 +862 48 7 +863 50 38 +864 46 14 +865 19 8 +866 44 17 +867 25 40 +868 28 5 +869 46 19 +870 32 44 +871 45 12 +872 44 32 +873 4 8 +874 25 7 +875 37 48 +876 44 29 +877 4 23 +878 45 3 +879 44 9 +880 49 16 +881 44 46 +882 33 43 +883 46 20 +884 19 24 +885 49 11 +886 48 35 +887 45 35 +888 50 2 +889 23 37 +890 13 40 +891 50 47 +892 50 41 +893 44 46 +894 31 37 +895 20 25 +896 48 39 +897 18 15 +898 6 10 +899 50 2 +900 5 16 +901 25 39 +902 44 42 +903 43 36 +904 48 18 +905 30 10 +906 36 40 +907 46 38 +908 31 1 +909 47 39 +910 45 26 +911 48 45 +912 33 30 +913 50 40 +914 49 14 +915 48 4 +916 36 7 +917 18 32 +918 6 39 +919 50 35 +920 1 5 +921 50 46 +922 20 11 +923 44 20 +924 46 9 +925 14 18 +926 21 8 +927 10 40 +928 47 1 +929 48 19 +930 5 14 +931 1 48 +932 46 41 +933 13 19 +934 49 10 +935 50 7 +936 33 31 +937 1 48 +938 37 7 +939 49 35 +940 21 26 +941 31 27 +942 49 2 +943 47 50 +944 50 16 +945 44 34 +946 46 36 +947 25 2 +948 45 42 +949 38 40 +950 23 18 +951 48 10 +952 36 10 +953 37 17 +954 50 13 +955 50 33 +956 26 39 +957 44 38 +958 29 17 +959 47 49 +960 43 42 +961 43 17 +962 13 34 +963 49 30 +964 48 31 +965 48 50 +966 24 4 +967 43 50 +968 44 40 +969 3 12 +970 3 38 +971 40 21 +972 50 14 +973 44 45 +974 43 10 +975 46 8 +976 43 3 +977 49 45 +978 45 37 +979 47 44 +980 15 23 +981 36 2 +982 50 41 +983 22 25 +984 47 27 +985 45 1 +986 50 33 +987 20 10 +988 47 46 +989 48 21 +990 11 7 +991 24 15 +992 46 48 +993 34 35 +994 50 10 +995 43 8 +996 40 14 +997 45 43 +998 46 37 +999 46 14 diff --git a/deps/v8/experimental/redline/testdata/selection/scheduler_tournament.trace b/deps/v8/experimental/redline/testdata/selection/scheduler_tournament.trace new file mode 100644 index 000000000000..7ddb345dd281 --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/scheduler_tournament.trace @@ -0,0 +1,1000 @@ +0 38 42 +1 20 43 +2 41 34 +3 24 34 +4 30 20 +5 50 4 +6 31 41 +7 47 21 +8 2 26 +9 46 19 +10 7 30 +11 49 46 +12 37 1 +13 24 33 +14 1 45 +15 21 30 +16 9 3 +17 40 3 +18 17 37 +19 14 33 +20 42 20 +21 19 31 +22 12 34 +23 13 18 +24 32 30 +25 36 6 +26 45 42 +27 39 17 +28 5 11 +29 25 32 +30 8 7 +31 33 19 +32 15 43 +33 20 40 +34 7 36 +35 22 43 +36 26 32 +37 6 30 +38 18 26 +39 11 42 +40 43 16 +41 4 31 +42 49 7 +43 37 46 +44 16 48 +45 44 30 +46 10 23 +47 27 18 +48 2 30 +49 29 41 +50 48 39 +51 5 10 +52 17 47 +53 29 42 +54 22 44 +55 48 4 +56 9 2 +57 27 17 +58 10 4 +59 33 46 +60 3 47 +61 38 23 +62 50 26 +63 35 23 +64 18 25 +65 42 32 +66 40 15 +67 3 6 +68 32 45 +69 19 41 +70 28 24 +71 15 28 +72 6 25 +73 41 32 +74 35 39 +75 46 21 +76 23 6 +77 14 20 +78 25 31 +79 28 17 +80 4 40 +81 7 21 +82 26 27 +83 37 39 +84 28 29 +85 19 16 +86 47 19 +87 23 11 +88 30 12 +89 29 32 +90 34 29 +91 31 34 +92 21 31 +93 2 20 +94 44 27 +95 13 15 +96 22 36 +97 34 1 +98 43 22 +99 40 6 +100 39 11 +101 36 30 +102 30 29 +103 11 46 +104 14 9 +105 1 45 +106 8 10 +107 5 47 +108 39 50 +109 42 11 +110 43 9 +111 20 47 +112 38 37 +113 3 2 +114 15 34 +115 11 5 +116 44 19 +117 41 49 +118 47 28 +119 12 30 +120 48 26 +121 43 8 +122 45 28 +123 17 23 +124 4 41 +125 39 42 +126 31 15 +127 36 21 +128 45 20 +129 6 43 +130 26 6 +131 16 33 +132 49 21 +133 46 50 +134 35 27 +135 16 5 +136 48 38 +137 8 36 +138 34 46 +139 23 34 +140 28 30 +141 37 1 +142 49 43 +143 45 50 +144 40 46 +145 22 35 +146 12 33 +147 31 14 +148 13 27 +149 18 1 +150 21 17 +151 10 32 +152 6 12 +153 25 37 +154 33 30 +155 27 35 +156 11 48 +157 27 34 +158 1 8 +159 16 32 +160 23 41 +161 25 7 +162 43 34 +163 29 6 +164 26 31 +165 1 11 +166 5 25 +167 42 28 +168 50 31 +169 41 30 +170 26 37 +171 24 36 +172 34 14 +173 36 44 +174 19 43 +175 38 4 +176 32 41 +177 12 24 +178 24 34 +179 36 14 +180 14 18 +181 4 16 +182 44 8 +183 50 33 +184 39 19 +185 20 42 +186 37 41 +187 16 44 +188 13 20 +189 32 26 +190 46 26 +191 15 16 +192 41 48 +193 21 44 +194 5 44 +195 30 26 +196 28 46 +197 9 31 +198 3 26 +199 42 47 +200 47 4 +201 31 29 +202 9 46 +203 22 34 +204 6 1 +205 17 9 +206 33 11 +207 8 27 +208 29 15 +209 45 33 +210 34 26 +211 35 32 +212 49 2 +213 45 32 +214 40 9 +215 23 5 +216 29 32 +217 47 16 +218 18 1 +219 30 29 +220 19 22 +221 8 22 +222 35 6 +223 18 15 +224 47 9 +225 38 39 +226 48 1 +227 24 40 +228 50 37 +229 17 26 +230 28 49 +231 21 46 +232 10 44 +233 18 39 +234 46 1 +235 10 29 +236 27 29 +237 15 47 +238 9 24 +239 49 32 +240 4 44 +241 14 45 +242 43 27 +243 12 50 +244 44 34 +245 24 6 +246 25 37 +247 7 17 +248 14 34 +249 30 7 +250 3 24 +251 50 33 +252 8 12 +253 16 21 +254 11 23 +255 23 35 +256 38 32 +257 35 8 +258 39 12 +259 44 40 +260 46 2 +261 13 20 +262 6 36 +263 34 48 +264 37 45 +265 35 9 +266 22 35 +267 13 38 +268 2 31 +269 19 48 +270 25 3 +271 20 7 +272 7 1 +273 42 7 +274 11 39 +275 2 35 +276 9 28 +277 1 46 +278 5 14 +279 3 41 +280 48 15 +281 5 23 +282 17 39 +283 12 18 +284 23 39 +285 9 14 +286 4 48 +287 31 50 +288 21 3 +289 1 50 +290 38 26 +291 13 2 +292 33 25 +293 15 35 +294 32 39 +295 7 33 +296 19 6 +297 33 5 +298 33 43 +299 8 43 +300 49 34 +301 29 22 +302 40 16 +303 6 45 +304 44 6 +305 16 3 +306 4 50 +307 2 44 +308 32 12 +309 46 21 +310 41 38 +311 18 37 +312 20 40 +313 11 4 +314 32 47 +315 25 40 +316 10 2 +317 28 43 +318 47 23 +319 8 25 +320 49 11 +321 21 2 +322 27 44 +323 26 34 +324 31 5 +325 37 40 +326 10 2 +327 14 42 +328 50 32 +329 48 40 +330 13 15 +331 5 2 +332 34 12 +333 38 15 +334 23 20 +335 1 35 +336 40 37 +337 22 43 +338 20 7 +339 24 15 +340 25 50 +341 41 35 +342 43 30 +343 7 19 +344 46 39 +345 15 36 +346 30 17 +347 31 40 +348 30 14 +349 39 17 +350 4 48 +351 3 50 +352 48 3 +353 27 50 +354 17 45 +355 9 6 +356 2 45 +357 39 34 +358 42 21 +359 27 33 +360 50 1 +361 11 27 +362 7 43 +363 40 1 +364 10 5 +365 36 49 +366 29 46 +367 24 44 +368 2 17 +369 12 28 +370 22 41 +371 19 10 +372 45 27 +373 25 9 +374 45 3 +375 28 49 +376 5 23 +377 34 47 +378 26 17 +379 29 40 +380 4 3 +381 19 5 +382 20 45 +383 14 19 +384 18 15 +385 32 1 +386 30 15 +387 33 22 +388 35 38 +389 14 10 +390 16 35 +391 23 33 +392 24 25 +393 43 31 +394 11 37 +395 47 31 +396 42 30 +397 49 17 +398 38 39 +399 9 5 +400 41 40 +401 2 50 +402 6 49 +403 50 4 +404 21 25 +405 36 5 +406 27 1 +407 36 27 +408 48 3 +409 35 19 +410 12 16 +411 44 17 +412 34 42 +413 3 35 +414 33 32 +415 43 15 +416 37 33 +417 36 31 +418 42 6 +419 16 49 +420 8 32 +421 18 35 +422 41 13 +423 26 3 +424 37 12 +425 11 6 +426 12 2 +427 18 14 +428 28 45 +429 15 39 +430 7 34 +431 32 50 +432 14 36 +433 39 31 +434 45 26 +435 13 37 +436 21 12 +437 31 43 +438 17 29 +439 22 1 +440 6 39 +441 46 20 +442 39 49 +443 26 33 +444 47 46 +445 17 3 +446 43 45 +447 42 5 +448 36 31 +449 30 47 +450 31 43 +451 9 12 +452 6 16 +453 22 44 +454 4 32 +455 10 6 +456 46 39 +457 13 31 +458 44 40 +459 3 36 +460 10 38 +461 8 50 +462 40 10 +463 3 37 +464 15 5 +465 33 48 +466 15 34 +467 17 19 +468 35 15 +469 45 32 +470 26 39 +471 27 44 +472 21 3 +473 5 12 +474 41 45 +475 23 16 +476 30 38 +477 12 29 +478 7 22 +479 28 45 +480 37 26 +481 40 12 +482 1 15 +483 20 28 +484 20 31 +485 34 2 +486 27 18 +487 33 36 +488 42 5 +489 16 19 +490 1 9 +491 12 26 +492 7 49 +493 8 42 +494 15 36 +495 45 31 +496 4 24 +497 25 21 +498 31 39 +499 10 47 +500 16 21 +501 5 47 +502 50 7 +503 6 12 +504 13 19 +505 17 43 +506 38 24 +507 37 48 +508 1 22 +509 29 46 +510 14 25 +511 45 18 +512 48 3 +513 28 36 +514 2 6 +515 21 4 +516 47 49 +517 10 38 +518 24 33 +519 20 23 +520 40 37 +521 49 7 +522 47 8 +523 19 17 +524 33 36 +525 2 34 +526 40 25 +527 38 3 +528 46 47 +529 41 20 +530 43 41 +531 28 29 +532 44 7 +533 25 16 +534 18 9 +535 32 18 +536 32 30 +537 49 22 +538 39 44 +539 26 32 +540 20 13 +541 34 17 +542 23 20 +543 36 11 +544 18 27 +545 36 17 +546 35 41 +547 50 2 +548 44 41 +549 28 6 +550 44 33 +551 35 1 +552 11 1 +553 11 43 +554 30 14 +555 31 38 +556 19 13 +557 9 47 +558 8 17 +559 50 47 +560 39 9 +561 37 39 +562 26 32 +563 16 5 +564 38 22 +565 15 38 +566 32 42 +567 6 38 +568 4 30 +569 1 7 +570 47 45 +571 2 7 +572 3 27 +573 29 2 +574 12 38 +575 5 17 +576 25 37 +577 19 25 +578 3 31 +579 43 38 +580 17 41 +581 34 20 +582 29 2 +583 27 20 +584 40 11 +585 21 28 +586 49 7 +587 45 29 +588 46 5 +589 9 21 +590 13 44 +591 42 30 +592 1 2 +593 14 10 +594 49 8 +595 34 1 +596 41 17 +597 7 23 +598 39 43 +599 2 3 +600 3 39 +601 25 30 +602 17 46 +603 43 44 +604 11 14 +605 36 37 +606 32 37 +607 47 18 +608 27 46 +609 24 17 +610 8 2 +611 24 35 +612 7 10 +613 4 50 +614 42 46 +615 5 39 +616 41 24 +617 9 7 +618 23 10 +619 48 22 +620 26 21 +621 19 38 +622 10 39 +623 13 35 +624 33 15 +625 11 15 +626 35 42 +627 24 34 +628 22 9 +629 12 41 +630 29 24 +631 31 39 +632 31 34 +633 15 44 +634 50 4 +635 21 1 +636 2 33 +637 14 28 +638 38 24 +639 46 47 +640 18 49 +641 30 10 +642 5 38 +643 33 42 +644 25 41 +645 44 28 +646 46 16 +647 20 7 +648 6 45 +649 23 19 +650 8 17 +651 7 44 +652 28 20 +653 19 44 +654 10 18 +655 12 4 +656 8 7 +657 48 10 +658 29 4 +659 23 3 +660 44 18 +661 22 10 +662 46 43 +663 20 13 +664 24 42 +665 30 35 +666 18 35 +667 13 12 +668 37 13 +669 40 47 +670 49 46 +671 9 31 +672 37 25 +673 45 3 +674 15 6 +675 50 2 +676 16 19 +677 39 13 +678 42 36 +679 47 45 +680 36 40 +681 22 39 +682 1 27 +683 22 26 +684 34 5 +685 16 49 +686 41 14 +687 17 13 +688 32 18 +689 6 39 +690 35 28 +691 1 47 +692 22 11 +693 50 44 +694 20 14 +695 21 8 +696 36 23 +697 38 34 +698 19 14 +699 48 45 +700 41 13 +701 42 10 +702 47 22 +703 33 1 +704 48 7 +705 28 40 +706 26 31 +707 27 49 +708 2 47 +709 44 16 +710 34 24 +711 3 25 +712 31 42 +713 11 5 +714 43 35 +715 10 38 +716 37 46 +717 13 33 +718 7 39 +719 26 29 +720 17 49 +721 5 4 +722 1 13 +723 12 30 +724 35 24 +725 9 24 +726 4 50 +727 29 1 +728 3 38 +729 40 29 +730 14 8 +731 45 10 +732 25 49 +733 4 39 +734 18 37 +735 18 49 +736 15 36 +737 49 41 +738 29 14 +739 27 45 +740 1 33 +741 50 34 +742 43 33 +743 21 7 +744 24 33 +745 48 34 +746 35 10 +747 22 14 +748 14 45 +749 43 37 +750 19 7 +751 33 6 +752 31 32 +753 3 38 +754 46 8 +755 26 40 +756 15 4 +757 13 27 +758 40 27 +759 32 5 +760 8 50 +761 38 27 +762 38 10 +763 14 48 +764 6 10 +765 9 7 +766 41 28 +767 5 42 +768 48 19 +769 16 37 +770 32 49 +771 49 37 +772 49 48 +773 39 27 +774 39 32 +775 24 43 +776 34 50 +777 12 42 +778 43 29 +779 30 31 +780 32 38 +781 45 25 +782 25 28 +783 23 43 +784 16 4 +785 47 9 +786 22 49 +787 11 30 +788 47 15 +789 36 17 +790 44 17 +791 28 9 +792 20 43 +793 34 2 +794 16 48 +795 27 43 +796 21 32 +797 15 40 +798 45 37 +799 23 48 +800 4 13 +801 17 39 +802 37 10 +803 5 34 +804 30 8 +805 7 28 +806 20 33 +807 44 7 +808 27 1 +809 17 3 +810 21 42 +811 19 32 +812 12 9 +813 13 7 +814 41 20 +815 9 39 +816 42 28 +817 10 24 +818 42 16 +819 1 13 +820 22 28 +821 6 45 +822 21 47 +823 31 10 +824 40 20 +825 35 25 +826 14 43 +827 39 18 +828 43 29 +829 25 20 +830 32 6 +831 10 38 +832 34 2 +833 23 39 +834 2 20 +835 28 17 +836 19 10 +837 9 38 +838 26 34 +839 42 43 +840 4 34 +841 7 21 +842 27 26 +843 16 49 +844 18 15 +845 50 37 +846 40 48 +847 48 18 +848 36 7 +849 26 33 +850 6 37 +851 30 43 +852 30 28 +853 29 3 +854 46 2 +855 14 17 +856 45 14 +857 24 6 +858 47 19 +859 36 12 +860 2 19 +861 38 3 +862 28 2 +863 15 19 +864 34 2 +865 24 10 +866 33 41 +867 1 10 +868 11 44 +869 8 34 +870 33 32 +871 3 38 +872 20 48 +873 10 6 +874 50 9 +875 39 45 +876 46 7 +877 7 16 +878 1 9 +879 18 46 +880 40 18 +881 38 20 +882 8 44 +883 16 34 +884 41 24 +885 2 21 +886 37 24 +887 6 20 +888 48 50 +889 10 28 +890 31 15 +891 36 3 +892 3 38 +893 12 27 +894 24 17 +895 18 36 +896 21 6 +897 35 43 +898 28 44 +899 6 41 +900 13 35 +901 11 40 +902 47 49 +903 44 39 +904 29 47 +905 15 33 +906 17 1 +907 4 2 +908 45 20 +909 13 11 +910 8 41 +911 23 47 +912 22 10 +913 4 34 +914 48 38 +915 30 41 +916 2 42 +917 17 32 +918 31 12 +919 37 15 +920 38 44 +921 49 4 +922 20 2 +923 35 9 +924 27 4 +925 5 7 +926 43 46 +927 23 39 +928 45 48 +929 42 11 +930 50 25 +931 5 23 +932 20 27 +933 25 20 +934 41 26 +935 25 10 +936 7 31 +937 11 40 +938 28 49 +939 36 32 +940 35 42 +941 44 34 +942 1 7 +943 4 35 +944 13 28 +945 26 17 +946 12 15 +947 21 20 +948 44 5 +949 19 4 +950 6 34 +951 19 21 +952 44 18 +953 37 5 +954 30 32 +955 34 10 +956 38 33 +957 50 44 +958 25 41 +959 2 24 +960 47 33 +961 17 16 +962 3 23 +963 28 41 +964 7 33 +965 48 49 +966 49 36 +967 3 36 +968 12 6 +969 10 27 +970 15 47 +971 41 47 +972 33 24 +973 46 20 +974 23 47 +975 11 22 +976 32 46 +977 42 48 +978 16 29 +979 9 35 +980 39 7 +981 1 42 +982 18 14 +983 43 1 +984 26 18 +985 33 22 +986 22 35 +987 27 44 +988 8 1 +989 29 46 +990 40 13 +991 42 30 +992 39 8 +993 46 9 +994 27 2 +995 49 50 +996 50 9 +997 29 47 +998 40 21 +999 24 2 diff --git a/deps/v8/experimental/redline/testdata/selection/scheduler_uniform.trace b/deps/v8/experimental/redline/testdata/selection/scheduler_uniform.trace new file mode 100644 index 000000000000..1b5d4b1e436e --- /dev/null +++ b/deps/v8/experimental/redline/testdata/selection/scheduler_uniform.trace @@ -0,0 +1,1000 @@ +0 38 19 +1 30 42 +2 20 49 +3 23 43 +4 41 13 +5 33 34 +6 24 38 +7 17 34 +8 30 9 +9 35 20 +10 50 5 +11 21 4 +12 31 8 +13 20 41 +14 47 33 +15 46 21 +16 38 2 +17 48 26 +18 46 19 +19 15 19 +20 30 46 +21 7 30 +22 49 46 +23 4 46 +24 37 16 +25 48 1 +26 24 49 +27 24 33 +28 1 46 +29 41 45 +30 21 13 +31 4 30 +32 38 2 +33 9 3 +34 40 9 +35 14 3 +36 46 17 +37 15 37 +38 14 50 +39 49 33 +40 42 16 +41 25 20 +42 19 48 +43 39 31 +44 30 12 +45 4 34 +46 37 2 +47 13 18 +48 32 50 +49 42 30 +50 21 36 +51 43 6 +52 49 45 +53 25 45 +54 42 39 +55 12 16 +56 17 20 +57 5 35 +58 11 7 +59 19 25 +60 32 1 +61 8 19 +62 7 46 +63 5 33 +64 19 15 +65 6 36 +66 43 20 +67 8 13 +68 40 7 +69 38 21 +70 36 21 +71 22 38 +72 43 26 +73 46 2 +74 32 6 +75 23 35 +76 30 21 +77 18 17 +78 26 40 +79 49 11 +80 42 43 +81 35 33 +82 16 4 +83 38 17 +84 31 49 +85 7 2 +86 7 37 +87 6 15 +88 46 16 +89 9 18 +90 48 44 +91 46 17 +92 30 36 +93 4 10 +94 23 27 +95 13 32 +96 18 37 +97 2 5 +98 30 19 +99 29 3 +100 41 9 +101 48 18 +102 39 5 +103 27 22 +104 10 17 +105 16 20 +106 47 29 +107 48 36 +108 42 22 +109 37 41 +110 44 37 +111 48 26 +112 4 9 +113 50 38 +114 2 27 +115 45 41 +116 17 5 +117 10 1 +118 4 33 +119 11 5 +120 46 3 +121 35 12 +122 47 38 +123 17 46 +124 23 50 +125 47 33 +126 26 20 +127 15 35 +128 23 5 +129 18 35 +130 25 42 +131 46 26 +132 32 33 +133 40 46 +134 15 40 +135 2 3 +136 6 32 +137 3 22 +138 45 27 +139 19 1 +140 41 42 +141 28 24 +142 24 15 +143 6 33 +144 28 6 +145 11 24 +146 25 41 +147 50 6 +148 32 35 +149 38 13 +150 39 46 +151 7 31 +152 21 23 +153 24 6 +154 14 48 +155 4 20 +156 9 25 +157 15 31 +158 38 28 +159 44 17 +160 4 7 +161 46 40 +162 7 22 +163 38 21 +164 26 2 +165 41 27 +166 37 40 +167 38 39 +168 37 28 +169 15 29 +170 19 17 +171 14 16 +172 37 2 +173 47 19 +174 23 6 +175 44 11 +176 9 30 +177 2 12 +178 29 4 +179 17 32 +180 28 34 +181 20 29 +182 31 32 +183 13 34 +184 42 21 +185 6 31 +186 2 48 +187 7 20 +188 44 43 +189 16 27 +190 37 13 +191 13 15 +192 22 13 +193 38 36 +194 35 2 +195 34 1 +196 25 43 +197 47 22 +198 40 20 +199 50 6 +200 39 8 +201 48 11 +202 21 36 +203 27 30 +204 30 35 +205 43 29 +206 44 11 +207 24 46 +208 14 48 +209 9 1 +210 37 35 +211 45 29 +212 8 30 +213 10 5 +214 31 19 +215 47 39 +216 33 17 +217 50 40 +218 2 42 +219 11 43 +220 11 19 +221 9 20 +222 32 27 +223 47 38 +224 50 8 +225 37 2 +226 3 1 +227 3 2 +228 39 42 +229 15 34 +230 11 34 +231 43 5 +232 44 39 +233 47 19 +234 41 15 +235 42 49 +236 47 5 +237 33 28 +238 23 12 +239 28 30 +240 20 3 +241 48 26 +242 43 20 +243 28 8 +244 37 10 +245 45 28 +246 14 17 +247 29 23 +248 22 4 +249 3 41 +250 39 11 +251 38 42 +252 31 32 +253 22 15 +254 36 2 +255 41 21 +256 45 28 +257 14 45 +258 20 22 +259 6 12 +260 43 26 +261 1 38 +262 6 16 +263 10 11 +264 33 49 +265 6 36 +266 21 46 +267 28 24 +268 50 35 +269 24 31 +270 27 16 +271 29 40 +272 5 48 +273 26 30 +274 38 28 +275 8 41 +276 36 22 +277 34 41 +278 46 14 +279 23 31 +280 34 28 +281 30 43 +282 30 37 +283 5 11 +284 1 49 +285 4 45 +286 43 28 +287 45 50 +288 40 43 +289 15 46 +290 22 38 +291 36 35 +292 37 31 +293 12 33 +294 22 31 +295 49 14 +296 13 7 +297 17 27 +298 44 18 +299 4 1 +300 35 21 +301 32 17 +302 44 10 +303 9 32 +304 6 34 +305 36 12 +306 40 25 +307 30 37 +308 33 45 +309 33 30 +310 27 32 +311 46 35 +312 11 48 +313 13 48 +314 27 22 +315 11 34 +316 1 37 +317 11 8 +318 16 30 +319 7 32 +320 43 23 +321 8 41 +322 25 29 +323 11 7 +324 43 25 +325 37 34 +326 40 31 +327 29 6 +328 26 43 +329 14 31 +330 1 12 +331 16 11 +332 5 14 +333 44 25 +334 5 42 +335 45 28 +336 1 45 +337 50 31 +338 41 1 +339 33 30 +340 26 22 +341 41 37 +342 11 24 +343 12 36 +344 43 34 +345 2 14 +346 36 14 +347 5 44 +348 19 30 +349 43 11 +350 5 38 +351 4 32 +352 31 42 +353 41 45 +354 12 18 +355 12 24 +356 24 30 +357 4 34 +358 36 12 +359 36 14 +360 23 14 +361 3 18 +362 4 36 +363 49 16 +364 44 8 +365 6 8 +366 36 50 +367 29 33 +368 39 6 +369 34 19 +370 4 49 +371 20 42 +372 37 45 +373 4 41 +374 16 48 +375 26 44 +376 14 13 +377 3 20 +378 50 32 +379 20 26 +380 32 12 +381 46 26 +382 15 48 +383 16 41 +384 6 50 +385 48 21 +386 16 32 +387 44 5 +388 28 45 +389 44 41 +390 30 41 +391 26 28 +392 23 11 +393 46 9 +394 30 45 +395 31 3 +396 9 36 +397 26 42 +398 27 4 +399 47 40 +400 15 47 +401 4 31 +402 16 6 +403 29 9 +404 46 35 +405 46 22 +406 22 23 +407 34 37 +408 6 19 +409 1 26 +410 47 17 +411 9 33 +412 3 36 +413 11 8 +414 17 39 +415 27 29 +416 29 15 +417 42 45 +418 28 33 +419 34 9 +420 20 26 +421 23 35 +422 42 32 +423 49 35 +424 38 2 +425 45 31 +426 43 32 +427 40 50 +428 5 9 +429 23 19 +430 46 5 +431 29 45 +432 23 32 +433 5 47 +434 14 16 +435 20 18 +436 44 1 +437 30 6 +438 39 29 +439 30 19 +440 14 22 +441 8 29 +442 44 22 +443 8 35 +444 25 6 +445 29 18 +446 6 15 +447 47 35 +448 22 9 +449 22 34 +450 38 39 +451 42 48 +452 29 1 +453 19 24 +454 25 40 +455 50 37 +456 8 37 +457 17 23 +458 16 26 +459 28 42 +460 26 49 +461 21 20 +462 3 46 +463 14 4 +464 10 44 +465 18 50 +466 35 39 +467 46 19 +468 21 1 +469 10 23 +470 12 29 +471 27 19 +472 24 29 +473 48 15 +474 29 47 +475 9 32 +476 12 24 +477 49 46 +478 48 32 +479 17 4 +480 8 44 +481 38 5 +482 14 45 +483 43 23 +484 4 27 +485 12 39 +486 44 50 +487 23 44 +488 49 34 +489 45 24 +490 17 6 +491 25 5 +492 4 37 +493 21 19 +494 7 17 +495 14 38 +496 42 34 +497 30 28 +498 46 7 +499 42 3 +500 46 24 +501 50 17 +502 45 33 +503 8 48 +504 42 12 +505 16 9 +506 46 21 +507 17 25 +508 11 23 +509 23 19 +510 5 35 +511 38 45 +512 35 32 +513 35 19 +514 41 8 +515 14 39 +516 37 12 +517 49 45 +518 44 40 +519 29 46 +520 29 2 +521 47 38 +522 13 20 +523 46 6 +524 27 36 +525 34 39 +526 31 48 +527 50 38 +528 37 45 +529 35 24 +530 16 9 +531 22 17 +532 15 35 +533 45 13 +534 46 38 +535 36 8 +536 2 31 +537 19 14 +538 29 48 +539 25 43 +540 12 3 +541 22 20 +542 16 7 +543 49 36 +544 7 1 +545 42 36 +546 20 7 +547 38 22 +548 11 39 +549 24 34 +550 2 35 +551 28 9 +552 24 28 +553 45 48 +554 1 46 +555 25 13 +556 5 14 +557 3 1 +558 43 41 +559 23 16 +560 48 15 +561 5 46 +562 34 23 +563 17 25 +564 15 39 +565 8 12 +566 30 18 +567 23 35 +568 5 39 +569 9 18 +570 37 14 +571 49 4 +572 25 48 +573 11 31 +574 43 50 +575 21 10 +576 23 3 +577 24 1 +578 28 50 +579 38 44 +580 46 26 +581 13 5 +582 2 47 +583 37 33 +584 25 28 +585 15 34 +586 35 32 +587 28 39 +588 32 39 +589 18 46 +590 7 33 +591 19 48 +592 49 6 +593 33 10 +594 29 5 +595 38 33 +596 37 43 +597 8 1 +598 25 43 +599 49 50 +600 3 34 +601 29 31 +602 19 22 +603 39 40 +604 19 16 +605 6 39 +606 37 45 +607 13 44 +608 12 6 +609 16 25 +610 21 3 +611 4 24 +612 15 50 +613 2 8 +614 29 44 +615 50 32 +616 17 12 +617 46 9 +618 18 21 +619 19 21 +620 41 38 +621 33 18 +622 44 37 +623 16 47 +624 20 40 +625 11 32 +626 49 4 +627 32 42 +628 7 47 +629 25 41 +630 1 40 +631 49 10 +632 12 2 +633 4 28 +634 8 43 +635 47 41 +636 1 23 +637 8 28 +638 9 25 +639 49 5 +640 38 11 +641 21 43 +642 24 2 +643 1 44 +644 27 44 +645 28 26 +646 42 34 +647 31 24 +648 18 5 +649 23 37 +650 9 40 +651 10 40 +652 25 10 +653 2 37 +654 10 14 +655 42 19 +656 50 6 +657 32 48 +658 43 28 +659 48 40 +660 13 48 +661 23 15 +662 5 23 +663 5 2 +664 38 34 +665 23 12 +666 38 10 +667 23 15 +668 23 6 +669 19 20 +670 48 1 +671 5 35 +672 40 44 +673 34 37 +674 22 8 +675 26 43 +676 34 44 +677 20 7 +678 24 19 +679 35 15 +680 25 10 +681 14 50 +682 41 13 +683 19 35 +684 19 22 +685 43 30 +686 7 19 +687 25 19 +688 46 28 +689 16 39 +690 15 2 +691 37 36 +692 38 33 +693 30 17 +694 31 46 +695 8 40 +696 30 29 +697 24 14 +698 43 39 +699 24 17 +700 25 5 +701 4 48 +702 7 3 +703 34 50 +704 4 48 +705 18 3 +706 44 18 +707 27 50 +708 17 38 +709 47 45 +710 9 34 +711 43 6 +712 30 2 +713 26 45 +714 39 22 +715 16 34 +716 47 42 +717 5 21 +718 27 44 +719 31 33 +720 50 48 +721 35 1 +722 11 27 +723 23 27 +724 7 47 +725 43 13 +726 40 5 +727 1 10 +728 14 40 +729 5 6 +730 36 31 +731 49 23 +732 29 15 +733 46 24 +734 33 20 +735 44 39 +736 2 10 +737 17 9 +738 12 35 +739 28 7 +740 22 18 +741 41 23 +742 19 18 +743 10 9 +744 35 45 +745 27 25 +746 11 50 +747 9 25 +748 45 19 +749 3 28 +750 7 16 +751 49 5 +752 8 50 +753 23 27 +754 49 34 +755 47 26 +756 33 38 +757 17 29 +758 28 34 +759 40 4 +760 25 7 +761 3 19 +762 23 29 +763 5 20 +764 6 18 +765 45 24 +766 14 48 +767 19 7 +768 23 18 +769 15 32 +770 22 21 +771 1 30 +772 48 45 +773 15 33 +774 23 33 +775 22 35 +776 50 29 +777 38 14 +778 34 5 +779 10 14 +780 16 47 +781 35 23 +782 32 33 +783 25 24 +784 9 25 +785 43 18 +786 17 31 +787 11 8 +788 19 37 +789 47 33 +790 8 31 +791 50 42 +792 46 30 +793 49 31 +794 2 17 +795 11 38 +796 19 39 +797 49 25 +798 9 5 +799 8 41 +800 6 40 +801 5 2 +802 29 50 +803 22 6 +804 46 49 +805 14 5 +806 50 4 +807 21 28 +808 12 25 +809 46 36 +810 22 5 +811 27 30 +812 40 1 +813 20 33 +814 36 27 +815 48 39 +816 10 3 +817 25 23 +818 35 19 +819 45 12 +820 9 16 +821 44 46 +822 3 17 +823 24 34 +824 13 42 +825 32 40 +826 3 35 +827 5 33 +828 39 32 +829 35 43 +830 46 15 +831 37 25 +832 36 33 +833 36 20 +834 18 36 +835 31 42 +836 38 8 +837 6 35 +838 4 16 +839 49 33 +840 8 16 +841 32 18 +842 14 23 +843 35 41 +844 31 13 +845 8 26 +846 35 3 +847 42 37 +848 39 12 +849 11 16 +850 50 6 +851 41 48 +852 12 2 +853 18 24 +854 19 14 +855 28 32 +856 14 45 +857 14 15 +858 11 39 +859 38 7 +860 45 34 +861 30 32 +862 43 50 +863 14 2 +864 8 36 +865 28 39 +866 46 31 +867 24 42 +868 45 26 +869 7 13 +870 13 37 +871 21 38 +872 13 12 +873 31 11 +874 44 43 +875 22 17 +876 40 29 +877 42 22 +878 29 1 +879 31 42 +880 6 39 +881 46 48 +882 49 20 +883 39 21 +884 36 49 +885 24 22 +886 26 33 +887 7 34 +888 47 46 +889 35 17 +890 18 3 +891 39 43 +892 27 45 +893 42 17 +894 34 5 +895 36 43 +896 24 31 +897 36 30 +898 27 47 +899 31 49 +900 50 43 +901 9 43 +902 13 12 +903 6 32 +904 12 16 +905 9 22 +906 46 44 +907 4 49 +908 30 32 +909 11 10 +910 18 6 +911 11 46 +912 22 39 +913 13 23 +914 7 31 +915 16 44 +916 50 40 +917 2 3 +918 34 36 +919 31 10 +920 18 38 +921 8 19 +922 30 50 +923 30 40 +924 40 10 +925 30 3 +926 28 37 +927 15 35 +928 48 5 +929 33 25 +930 10 48 +931 15 32 +932 45 34 +933 22 17 +934 16 19 +935 35 5 +936 10 15 +937 42 45 +938 26 32 +939 26 30 +940 16 39 +941 27 32 +942 29 44 +943 21 27 +944 29 3 +945 5 13 +946 45 12 +947 41 47 +948 34 45 +949 23 30 +950 12 16 +951 30 41 +952 27 38 +953 4 12 +954 21 29 +955 17 7 +956 24 22 +957 28 17 +958 4 45 +959 12 37 +960 2 26 +961 46 28 +962 40 12 +963 1 9 +964 47 15 +965 20 3 +966 22 28 +967 20 26 +968 49 31 +969 34 33 +970 39 2 +971 27 3 +972 45 18 +973 33 27 +974 21 36 +975 42 10 +976 46 5 +977 7 16 +978 15 19 +979 17 21 +980 1 9 +981 12 20 +982 30 26 +983 7 6 +984 42 49 +985 8 7 +986 17 42 +987 15 28 +988 5 36 +989 12 45 +990 20 31 +991 4 9 +992 14 24 +993 33 25 +994 11 21 +995 31 5 +996 27 39 +997 10 5 +998 16 47 +999 42 8 diff --git a/deps/v8/gni/v8.gni b/deps/v8/gni/v8.gni index 3fb7d2964ab1..d4b4ac3a8f5c 100644 --- a/deps/v8/gni/v8.gni +++ b/deps/v8/gni/v8.gni @@ -34,11 +34,11 @@ declare_args() { # Turns on compiler optimizations in V8 in Debug build. v8_optimized_debug = true - # Selects which instance-type generator's output V8 compiles in: - # metagen (tools/metagen/) or Torque's emission. When off, the metagen - # action is out of the build graph entirely, so nothing depends on the - # llvm-libclang package. Sets -DV8_USE_METAGEN_INSTANCE_TYPES=0 when off. - v8_use_metagen_instance_types = true + # Metagen reads the v8 object hierarchy from C++ headers via libclang. It + # produces instance-type definitions and object-layout files, used as inputs + # during the remaining build. During a transition period, it can be switched + # off using this flag (ie take the old torque paths). + v8_use_metagen = true # Support for backtrace_symbols on linux. v8_enable_backtrace = "" @@ -226,8 +226,7 @@ declare_args() { # Enable object names in cppgc for profiling purposes. cppgc_enable_object_names = - !(is_component_build && is_win) && - (is_chrome_for_testing || (!is_android && !is_fuchsia)) + is_chrome_for_testing || (!is_android && !is_fuchsia) # Enable young generation in cppgc. cppgc_enable_young_generation = false @@ -297,6 +296,13 @@ declare_args() { declare_args() { # Enable more (costly) verification features that help to detect bugs. v8_enable_verification_features = v8_enable_debugging_features + + # Enable ICU4X implementations for ECMA-402 (Intl) features. Enabling this + # feature will add a dependency on the icu_capi Rust library. + # Functionality is still controlled by runtime flags (e.g. + # --ecma402-icu4x-plural-rules). + v8_enable_ecma402_icu4x = + v8_enable_i18n_support && !(defined(build_with_node) && build_with_node) } assert(!v8_enable_debugging_features || v8_enable_verification_features, diff --git a/deps/v8/include/cppgc/allocation.h b/deps/v8/include/cppgc/allocation.h index 6381980bee92..ecadeb437ca5 100644 --- a/deps/v8/include/cppgc/allocation.h +++ b/deps/v8/include/cppgc/allocation.h @@ -8,6 +8,7 @@ #include <atomic> #include <cstddef> #include <cstdint> +#include <limits> #include <new> #include <type_traits> #include <utility> @@ -266,8 +267,8 @@ class MakeGarbageCollectedTraitBase * \endcode */ struct AdditionalBytes { - constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {} - const size_t value; + constexpr explicit AdditionalBytes(uint32_t bytes) : value(bytes) {} + const uint32_t value; }; /** @@ -285,6 +286,7 @@ class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> { public: template <typename... Args> static T* Call(AllocationHandle& handle, Args&&... args) { + static_assert(sizeof(T) <= std::numeric_limits<uint32_t>::max()); void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T)); T* object = ::new (memory) T(std::forward<Args>(args)...); @@ -295,8 +297,16 @@ class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> { template <typename... Args> static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes, Args&&... args) { - void* memory = MakeGarbageCollectedTraitBase<T>::Allocate( - handle, sizeof(T) + additional_bytes.value); + static_assert(sizeof(T) <= std::numeric_limits<uint32_t>::max()); + const size_t size_to_allocate = sizeof(T) + additional_bytes.value; + // On 64-bit systems, since sizeof(T) and additional_bytes.value are both at + // most 32 bits, we know that their sum can't overflow. On 32-bit systems, + // we need to check it. +#if !defined(V8_HOST_ARCH_64_BIT) + CPPGC_CHECK(size_to_allocate > additional_bytes.value); +#endif + void* memory = + MakeGarbageCollectedTraitBase<T>::Allocate(handle, size_to_allocate); T* object = ::new (memory) T(std::forward<Args>(args)...); MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object); return object; diff --git a/deps/v8/include/cppgc/common.h b/deps/v8/include/cppgc/common.h index 961038360ac4..2bfaf2fcd186 100644 --- a/deps/v8/include/cppgc/common.h +++ b/deps/v8/include/cppgc/common.h @@ -5,8 +5,13 @@ #ifndef INCLUDE_CPPGC_COMMON_H_ #define INCLUDE_CPPGC_COMMON_H_ +#include "cppgc/macros.h" #include "v8config.h" // NOLINT(build/include_directory) +#if V8_CC_MSVC +#include <intrin.h> // _AddressOfReturnAddress() +#endif + namespace cppgc { /** @@ -23,6 +28,29 @@ enum class EmbedderStackState { kNoHeapPointers, }; +/** + * A stack-allocated scope that sets the current thread's stack start address + * for conservative stack scanning and restores the previous stack start on + * destruction. + */ +class V8_EXPORT V8_NODISCARD StackStartScope final { + CPPGC_STACK_ALLOCATED(); + + public: +#if V8_CC_MSVC + explicit StackStartScope(void* stack_start = _AddressOfReturnAddress()); +#else + explicit StackStartScope(void* stack_start = __builtin_frame_address(0)); +#endif + ~StackStartScope(); + + StackStartScope(const StackStartScope&) = delete; + StackStartScope& operator=(const StackStartScope&) = delete; + + private: + void* const previous_stack_start_; +}; + } // namespace cppgc #endif // INCLUDE_CPPGC_COMMON_H_ diff --git a/deps/v8/include/cppgc/explicit-management.h b/deps/v8/include/cppgc/explicit-management.h index d7f1dcde6563..5ab3d11c2445 100644 --- a/deps/v8/include/cppgc/explicit-management.h +++ b/deps/v8/include/cppgc/explicit-management.h @@ -6,6 +6,7 @@ #define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_ #include <cstddef> +#include <limits> #include "cppgc/allocation.h" #include "cppgc/internal/logging.h" @@ -90,10 +91,16 @@ template <typename T> bool Resize(T& object, AdditionalBytes additional_bytes) { static_assert(IsGarbageCollectedTypeV<T>, "Object must be of type GarbageCollected."); + static_assert(sizeof(T) <= std::numeric_limits<uint32_t>::max()); const size_t new_object_size = sizeof(T) + additional_bytes.value; + // On 64-bit systems, since sizeof(T) and additional_bytes.value are both at + // most 32 bits, we know that their sum can't overflow. On 32-bit systems, we + // need to check it. +#if !defined(V8_HOST_ARCH_64_BIT) if (new_object_size < sizeof(T)) { return false; } +#endif return internal::ExplicitManagementImpl::Resize(&object, new_object_size); } diff --git a/deps/v8/include/cppgc/heap-consistency.h b/deps/v8/include/cppgc/heap-consistency.h index 23b5d909945b..31858f0a631b 100644 --- a/deps/v8/include/cppgc/heap-consistency.h +++ b/deps/v8/include/cppgc/heap-consistency.h @@ -146,8 +146,8 @@ class HeapConsistency final { } /** - * Steele-style write barrier that re-processes an object if it has already - * been processed. + * Steele-style write barrier that processes an object regardless of whether + * or not it has already been processed. * * \param params The parameters retrieved from `GetWriteBarrierType()`. * \param object The pointer to the object which must point to an object that diff --git a/deps/v8/include/cppgc/heap.h b/deps/v8/include/cppgc/heap.h index 77673be7d733..a8e1b5c8f759 100644 --- a/deps/v8/include/cppgc/heap.h +++ b/deps/v8/include/cppgc/heap.h @@ -15,6 +15,7 @@ #include "cppgc/platform.h" #include "v8config.h" // NOLINT(build/include_directory) +// TODO(540324230): Remove once embedders migrate to StackStartScope. #if V8_CC_MSVC #include <intrin.h> // _AddressOfReturnAddress() #endif @@ -38,6 +39,7 @@ class Heap; /** * A marker that captures the current stack start address. + * TODO(540324230): Remove once embedders migrate to StackStartScope. */ class V8_EXPORT StackStartMarker { public: @@ -177,6 +179,11 @@ class V8_EXPORT Heap { * heap. */ std::optional<StackStartMarker> stack_start_marker = std::nullopt; + + /** + * Optional allocation sampler. + */ + AllocationSampler* allocation_sampler = nullptr; }; /** * Creates a new heap that can be used for object allocation. diff --git a/deps/v8/include/cppgc/platform.h b/deps/v8/include/cppgc/platform.h index 8e19272f58bb..1a7758637bab 100644 --- a/deps/v8/include/cppgc/platform.h +++ b/deps/v8/include/cppgc/platform.h @@ -25,6 +25,60 @@ using TaskPriority = v8::TaskPriority; using TaskRunner = v8::TaskRunner; using TracingController = v8::TracingController; +/** + * Interface for observing object-level allocations and deallocations in cppgc. + * + * Implementations of these methods must not allocate on the managed heap(s) + * (C++ or JS) or otherwise call back into V8. + */ +class V8_EXPORT AllocationSampler { + public: + virtual ~AllocationSampler() = default; + + /** + * Returns the desired sampling interval in bytes. Embedders must return a + * non-zero value to activate periodic sampling. Must not allocate on the + * managed heap(s) (C++ or JS) or otherwise call back into V8. + * + * \returns the configured mean sampling interval in bytes, or 0 if unset. + */ + virtual size_t GetSampleInterval() const { return 0; } + + /** + * Invoked when an object or memory chunk is allocated. Must not allocate on + * the managed heap(s) (C++ or JS) or otherwise call back into V8. + * + * \param address Pointer to the allocated memory. + * \param size Total size of the allocation in bytes (including object + * header). + * \returns true if this allocation was selected as a sample and should be + * tracked for deallocation, false otherwise. + */ + virtual bool OnAllocated(void* address, size_t size) = 0; + + /** + * Invoked when an allocated object or memory chunk is freed/reclaimed. Must + * not allocate on the managed heap(s) (C++ or JS) or otherwise call back into + * V8. + * + * \param address Pointer to the allocated memory. + */ + virtual void OnFreed(void* address) = 0; + + /** + * Invoked when a sampled object is moved to a new location. Must not allocate + * on the managed heap(s) (C++ or JS) or otherwise call back into V8. + * + * \param from Pointer to the old memory location. + * \param to Pointer to the new memory location. + * \param size Total size of the allocation in bytes (including object + * header). + * \returns true if the moved allocation was selected as a sample and should + * be tracked for deallocation, false otherwise. + */ + virtual bool OnMove(void* from, void* to, size_t size) = 0; +}; + /** * Platform interface used by Heap. Contains allocators and executors. */ diff --git a/deps/v8/include/js_protocol.pdl b/deps/v8/include/js_protocol.pdl index ad0d42bfa398..7f1e0829a540 100644 --- a/deps/v8/include/js_protocol.pdl +++ b/deps/v8/include/js_protocol.pdl @@ -143,12 +143,17 @@ domain Debugger optional Location startLocation # Location in the source code where scope ends optional Location endLocation - # True if the scope does not declare any variables. - # Only present if true. + # Present if the scope has no variable values to show. Absent means that + # the scope declares at least one variable with an available value. # Empty scopes are retained in the scope chain because # they can be targeted via `evaluateOnCallFrame` (using `scopeNumber`) or # matched against scopes in source maps. - experimental optional boolean empty + experimental optional enum emptyReason + # The scope does not declare any variables. + no-variables + # The scope declares variables, but none of their values are available + # (e.g. because they were optimized out or are in their TDZ). + all-unavailable # Search match for resource. type SearchMatch extends object @@ -564,6 +569,10 @@ domain Debugger parameters # The skipList specifies location ranges that should be skipped on step over. experimental optional array of LocationRange skipList + # Functions whose source range lies within one of the enterRanges are + # entered as if by stepInto, even when they are called (directly or + # indirectly) from a call that is stepped over. + experimental optional array of LocationRange enterRanges # Fired when breakpoint is resolved to an actual script and location. # Deprecated in favor of `resolvedBreakpoints` in the `scriptParsed` event. diff --git a/deps/v8/include/v8-array-buffer.h b/deps/v8/include/v8-array-buffer.h index 839630680d72..912098a91a92 100644 --- a/deps/v8/include/v8-array-buffer.h +++ b/deps/v8/include/v8-array-buffer.h @@ -17,6 +17,7 @@ namespace v8 { +class ArrayBuffer; class SharedArrayBuffer; #if defined(V8_COMPRESS_POINTERS) && \ @@ -135,10 +136,112 @@ using BackingStoreDeleterCallback = void (*)(void* data, size_t length, #endif +/** + * A base class for an instance of the built-in ArrayBuffer or SharedArrayBuffer + * constructor. + */ +class V8_EXPORT ArrayBufferBase : public Object { + public: + /** + * Data length in bytes. + */ + size_t ByteLength() const; + + /** + * Maximum length in bytes. + */ + size_t MaxByteLength() const; + + /** + * Returns true if this is a SharedArrayBuffer, false if it is an ArrayBuffer. + */ + bool IsShared() const; + + /** + * Returns true if this ArrayBuffer may be detached. Always false for + * SharedArrayBuffer. + */ + bool IsDetachable() const; + + /** + * Returns true if this ArrayBuffer has been detached. Always false for + * SharedArrayBuffer. + */ + bool WasDetached() const; + + /** + * Returns true if this ArrayBuffer is immutable. Always false for + * SharedArrayBuffer. + */ + bool IsImmutable() const; + + /** + * Copy up to |bytes_to_copy| bytes from this ArrayBufferBase starting at + * position |source_start| to the target ArrayBufferBase starting at position + * |target_start|. Nothing is copied if the source or target ArrayBuffer is + * detached, or if the target ArrayBuffer is immutable. + * Returns the number of bytes actually copied. + */ + size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy, + Local<ArrayBufferBase> target, + size_t target_start) const; + + /** + * Get a shared pointer to the backing store of this array buffer. This + * pointer coordinates the lifetime management of the internal storage + * with any live ArrayBuffers on the heap, even across isolates. The embedder + * should not attempt to manage lifetime of the storage through other means. + * + * The returned shared pointer will not be empty, even if the ArrayBuffer has + * been detached. Use |WasDetached| to tell if it has been detached instead. + */ + std::shared_ptr<BackingStore> GetBackingStore(); + + /** + * More efficient shortcut for + * GetBackingStore()->IsResizableByUserJavaScript(). + */ + bool IsResizableByUserJavaScript() const; + + /** + * More efficient shortcut for GetBackingStore()->Data(). The returned pointer + * is valid as long as the ArrayBuffer is alive. + */ + void* Data() const; + + V8_INLINE static ArrayBufferBase* Cast(Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast<ArrayBufferBase*>(value); + } + + static constexpr int kInternalFieldCount = + V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; + static constexpr int kEmbedderFieldCount = kInternalFieldCount; + +#if V8_ENABLE_SANDBOX + static constexpr size_t kMaxByteLength = + internal::kMaxSafeBufferSizeForSandbox; +#elif V8_HOST_ARCH_32_BIT + static constexpr size_t kMaxByteLength = std::numeric_limits<int>::max(); +#else + // The maximum safe integer (2^53 - 1). + static constexpr size_t kMaxByteLength = + static_cast<size_t>((uint64_t{1} << 53) - 1); +#endif + + private: + ArrayBufferBase(); + static void CheckCast(Value* obj); + friend class ArrayBuffer; + friend class SharedArrayBuffer; +}; + /** * An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). */ -class V8_EXPORT ArrayBuffer : public Object { +class V8_EXPORT ArrayBuffer : public ArrayBufferBase { public: /** * A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. @@ -231,16 +334,6 @@ class V8_EXPORT ArrayBuffer : public Object { static Allocator* NewDefaultAllocator(); }; - /** - * Data length in bytes. - */ - size_t ByteLength() const; - - /** - * Maximum length in bytes. - */ - size_t MaxByteLength() const; - /** * Attempt to create a new ArrayBuffer. Allocate |byte_length| bytes. * Allocated memory will be owned by a created ArrayBuffer and @@ -328,32 +421,6 @@ class V8_EXPORT ArrayBuffer : public Object { static std::unique_ptr<BackingStore> NewResizableBackingStore( size_t byte_length, size_t max_byte_length); - /** - * Returns true if this ArrayBuffer may be detached. - */ - bool IsDetachable() const; - - /** - * Returns true if this ArrayBuffer has been detached. - */ - bool WasDetached() const; - - /** - * Returns true if this ArrayBuffer is immutable. - */ - bool IsImmutable() const; - - /** - * Copy up to |bytes_to_copy| bytes from this ArrayBuffer starting at - * position |source_start| to the target ArrayBuffer starting at position - * |target_start|. Nothing is copied if the source or target ArrayBuffer is - * detached. - * Returns the number of bytes actually copied. - */ - size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy, - Local<ArrayBuffer> target, - size_t target_start) const; - /** * Detaches this ArrayBuffer and all its views (typed arrays). * Detaching sets the byte length of the buffer and all typed arrays to zero, @@ -380,29 +447,6 @@ class V8_EXPORT ArrayBuffer : public Object { */ void SetDetachKey(v8::Local<v8::Value> key); - /** - * Get a shared pointer to the backing store of this array buffer. This - * pointer coordinates the lifetime management of the internal storage - * with any live ArrayBuffers on the heap, even across isolates. The embedder - * should not attempt to manage lifetime of the storage through other means. - * - * The returned shared pointer will not be empty, even if the ArrayBuffer has - * been detached. Use |WasDetached| to tell if it has been detached instead. - */ - std::shared_ptr<BackingStore> GetBackingStore(); - - /** - * More efficient shortcut for - * GetBackingStore()->IsResizableByUserJavaScript(). - */ - bool IsResizableByUserJavaScript() const; - - /** - * More efficient shortcut for GetBackingStore()->Data(). The returned pointer - * is valid as long as the ArrayBuffer is alive. - */ - void* Data() const; - V8_INLINE static ArrayBuffer* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); @@ -410,21 +454,6 @@ class V8_EXPORT ArrayBuffer : public Object { return static_cast<ArrayBuffer*>(value); } - static constexpr int kInternalFieldCount = - V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - static constexpr int kEmbedderFieldCount = kInternalFieldCount; - -#if V8_ENABLE_SANDBOX - static constexpr size_t kMaxByteLength = - internal::kMaxSafeBufferSizeForSandbox; -#elif V8_HOST_ARCH_32_BIT - static constexpr size_t kMaxByteLength = std::numeric_limits<int>::max(); -#else - // The maximum safe integer (2^53 - 1). - static constexpr size_t kMaxByteLength = - static_cast<size_t>((uint64_t{1} << 53) - 1); -#endif - private: ArrayBuffer(); static void CheckCast(Value* obj); @@ -445,7 +474,12 @@ class V8_EXPORT ArrayBufferView : public Object { /** * Returns underlying ArrayBuffer. */ + V8_DEPRECATE_SOON("Use GetBuffer instead") Local<ArrayBuffer> Buffer(); + /** + * Returns underlying ArrayBuffer or SharedArrayBuffer. + */ + Local<ArrayBufferBase> GetBuffer(); /** * Byte offset in |Buffer|. */ @@ -503,9 +537,7 @@ class V8_EXPORT ArrayBufferView : public Object { */ class V8_EXPORT DataView : public ArrayBufferView { public: - static Local<DataView> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<DataView> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<DataView> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static DataView* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -522,18 +554,8 @@ class V8_EXPORT DataView : public ArrayBufferView { /** * An instance of the built-in SharedArrayBuffer constructor. */ -class V8_EXPORT SharedArrayBuffer : public Object { +class V8_EXPORT SharedArrayBuffer : public ArrayBufferBase { public: - /** - * Data length in bytes. - */ - size_t ByteLength() const; - - /** - * Maximum length in bytes. - */ - size_t MaxByteLength() const; - /** * Create a new SharedArrayBuffer. Allocate |byte_length| bytes, which are * either zero-initialized or uninitialized. Allocated memory will be owned by @@ -607,30 +629,6 @@ class V8_EXPORT SharedArrayBuffer : public Object { void* data, size_t byte_length, v8::BackingStore::DeleterCallback deleter, void* deleter_data); - /** - * Get a shared pointer to the backing store of this array buffer. This - * pointer coordinates the lifetime management of the internal storage - * with any live ArrayBuffers on the heap, even across isolates. The embedder - * should not attempt to manage lifetime of the storage through other means. - */ - std::shared_ptr<BackingStore> GetBackingStore(); - - /** - * More efficient shortcut for GetBackingStore()->Data(). The returned pointer - * is valid as long as the ArrayBuffer is alive. - */ - void* Data() const; - - /** - * Copy up to |bytes_to_copy| bytes from this SharedArrayBuffer starting at - * position |source_start| to the target SharedArrayBuffer starting at - * position |target_start|. - * Returns the number of bytes actually copied. - */ - size_t CopyArrayBufferBytes(size_t source_start, size_t bytes_to_copy, - Local<SharedArrayBuffer> target, - size_t target_start) const; - V8_INLINE static SharedArrayBuffer* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); @@ -638,9 +636,6 @@ class V8_EXPORT SharedArrayBuffer : public Object { return static_cast<SharedArrayBuffer*>(value); } - static constexpr int kInternalFieldCount = - V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT; - private: SharedArrayBuffer(); static void CheckCast(Value* obj); diff --git a/deps/v8/include/v8-callbacks.h b/deps/v8/include/v8-callbacks.h index efa9de293072..bca245b6d666 100644 --- a/deps/v8/include/v8-callbacks.h +++ b/deps/v8/include/v8-callbacks.h @@ -314,6 +314,8 @@ using FailedAccessCheckCallback = void (*)(Local<Object> target, // --- WebAssembly compilation callbacks --- using ExtensionCallback = bool (*)(const FunctionCallbackInfo<Value>&); +using WasmModuleCallback = bool (*)(Isolate* isolate, Local<Value> source); +using WasmInstanceCallback = bool (*)(Isolate* isolate, Local<Value> source); using AllowWasmCodeGenerationCallback = bool (*)(Local<Context> context, Local<String> source); @@ -489,6 +491,14 @@ using PrepareStackTraceCallback = MaybeLocal<Value> (*)(Local<Context> context, Local<Value> error, Local<Array> sites); +/** + * DynamicScriptCompiledFromEmbedderCallback is called when a dynamic script + * (such as from eval or the Function constructor) is compiled from the embedder + * without a calling user JavaScript frame on the stack. + */ +using DynamicScriptCompiledFromEmbedderCallback = + void (*)(Local<Context> context, int script_id); + #if defined(V8_OS_WIN) /** * Callback to selectively enable ETW tracing based on the document URL. diff --git a/deps/v8/include/v8-context.h b/deps/v8/include/v8-context.h index 8da2c8e48c1f..acaeaae997fe 100644 --- a/deps/v8/include/v8-context.h +++ b/deps/v8/include/v8-context.h @@ -26,6 +26,11 @@ class ObjectTemplate; class Value; class String; +#ifndef V8_EMBEDDER_DATA_ARRAY_SIZE +// Defined using gn arg `v8_embedder_data_array_size`. +#define V8_EMBEDDER_DATA_ARRAY_SIZE 5 +#endif + /** * A container for extension names. */ @@ -285,8 +290,15 @@ class V8_EXPORT Context : public Data { * needed. Note that index 0 currently has a special meaning for Chrome's * debugger. */ + V8_DEPRECATE_SOON("Use SetEmbedderDataV3 instead") void SetEmbedderDataV2(int index, Local<Data> value); + /** + * Sets the embedder data with the given index. The index must be in the + * range of [0, V8_EMBEDDER_DATA_ARRAY_SIZE). + */ + void SetEmbedderDataV3(int index, Local<Data> value); + /** * Gets the embedder data with the given index, which must have been set by a * previous call to SetEmbedderData with the same index. @@ -307,7 +319,7 @@ class V8_EXPORT Context : public Data { * needed. Note that index 0 currently has a special meaning for Chrome's * debugger. */ - V8_DEPRECATE_SOON("Use SetEmbedderDataV2 instead") + V8_DEPRECATE_SOON("Use SetEmbedderDataV3 instead") void SetEmbedderData(int index, Local<Value> value); /** @@ -325,17 +337,30 @@ class V8_EXPORT Context : public Data { V8_INLINE T* GetAlignedPointerFromEmbedderData(Isolate* isolate, int index, CppHeapPointerTag tag); + V8_DEPRECATE_SOON("Use SetAlignedPointerInEmbedderDataV2 instead") void SetAlignedPointerInEmbedderData(int index, void* value, EmbedderDataTypeTag tag); template <typename T> requires(!std::is_void_v<T>) && cppgc::IsGarbageCollectedTypeV<T> + V8_DEPRECATE_SOON("Use SetAlignedPointerInEmbedderDataV2 instead") void SetAlignedPointerInEmbedderData(int index, T* value, CppHeapPointerTag tag) { SetAlignedPointerInEmbedderDataInternal(index, static_cast<void*>(value), tag); } + void SetAlignedPointerInEmbedderDataV2(int index, void* value, + EmbedderDataTypeTag tag); + + template <typename T> + requires(!std::is_void_v<T>) && cppgc::IsGarbageCollectedTypeV<T> + void SetAlignedPointerInEmbedderDataV2(int index, T* value, + CppHeapPointerTag tag) { + SetAlignedPointerInEmbedderDataInternalV2(index, static_cast<void*>(value), + tag); + } + /** * Control whether code generation from strings is allowed. Calling * this method with false will disable 'eval' and the 'Function' @@ -465,6 +490,8 @@ class V8_EXPORT Context : public Data { void* SlowGetAlignedPointerFromEmbedderData(int index, CppHeapPointerTag tag); void SetAlignedPointerInEmbedderDataInternal(int index, void* value, CppHeapPointerTag tag); + void SetAlignedPointerInEmbedderDataInternalV2(int index, void* value, + CppHeapPointerTag tag); }; // --- Implementation --- diff --git a/deps/v8/include/v8-cppgc.h b/deps/v8/include/v8-cppgc.h index 2bb82aa6f2cd..16d4ce5a8769 100644 --- a/deps/v8/include/v8-cppgc.h +++ b/deps/v8/include/v8-cppgc.h @@ -19,6 +19,7 @@ namespace cppgc { class AllocationHandle; +class AllocationSampler; class HeapHandle; } // namespace cppgc @@ -56,8 +57,14 @@ struct V8_EXPORT CppHeapCreateParams { /** * Optional marker representing the stack start of the thread creating the * heap. + * TODO(540324230): Remove once embedders migrate to StackStartScope. */ + V8_DEPRECATE_SOON("Use StackStartScope instead.") std::optional<cppgc::StackStartMarker> stack_start_marker = std::nullopt; + /** + * Optional allocation sampler. + */ + cppgc::AllocationSampler* allocation_sampler = nullptr; }; /** diff --git a/deps/v8/include/v8-fast-api-calls.h b/deps/v8/include/v8-fast-api-calls.h index 05486768e48e..4d68167b38e3 100644 --- a/deps/v8/include/v8-fast-api-calls.h +++ b/deps/v8/include/v8-fast-api-calls.h @@ -466,7 +466,7 @@ struct FastApiCallbackOptions { /** * The `data` passed to the FunctionTemplate constructor, or `undefined`. */ - V8_DEPRECATE_SOON("Use DataV2 instead") + V8_DEPRECATED("Use DataV2 instead") v8::Local<v8::Value> data; /** diff --git a/deps/v8/include/v8-forward.h b/deps/v8/include/v8-forward.h index 435fe856d97f..c23253d943de 100644 --- a/deps/v8/include/v8-forward.h +++ b/deps/v8/include/v8-forward.h @@ -16,6 +16,7 @@ namespace v8 { class AccessorSignature; class Array; class ArrayBuffer; +class ArrayBufferBase; class ArrayBufferView; class BigInt; class BigInt64Array; diff --git a/deps/v8/include/v8-function-callback.h b/deps/v8/include/v8-function-callback.h index de42be063916..ed2514f90f41 100644 --- a/deps/v8/include/v8-function-callback.h +++ b/deps/v8/include/v8-function-callback.h @@ -44,7 +44,12 @@ class ReturnValue { public: template <class S> V8_INLINE ReturnValue(const ReturnValue<S>& that) : value_(that.value_) { - static_assert(std::is_base_of_v<T, S>, "type check"); + // Allow narrowing `ReturnValue<Base>` to `ReturnValue<Derived>`, as any + // `Derived` value set on this `ReturnValue<T>` is also a valid `Base` + // value for the underlying `ReturnValue<S>` slot. Disallow widening + // `ReturnValue<Derived>` to `ReturnValue<Base>`, which would allow storing + // a general `Base` value into a slot that expects `Derived`. + static_assert(std::is_base_of_v<S, T>, "type check"); } // Handle-based setters. template <typename S> @@ -136,7 +141,7 @@ class FunctionCallbackInfo { /** Indicates whether this is a regular call or a construct call. */ V8_INLINE bool IsConstructCall() const; /** The data argument specified when creating the callback. */ - V8_DEPRECATE_SOON("Use DataV2 instead") + V8_DEPRECATED("Use DataV2 instead") V8_INLINE Local<Value> Data() const; /** The data argument specified when creating the callback as `v8::Data`. */ V8_INLINE Local<v8::Data> DataV2() const; @@ -238,7 +243,7 @@ class PropertyCallbackInfo { * `NamedPropertyHandlerConfiguration` or * `IndexedPropertyHandlerConfiguration.` */ - V8_DEPRECATE_SOON("Use DataV2 instead") + V8_DEPRECATED("Use DataV2 instead") V8_INLINE Local<Value> Data() const; /** diff --git a/deps/v8/include/v8-internal.h b/deps/v8/include/v8-internal.h index fd8fcda6f5ec..2c9ab67760bc 100644 --- a/deps/v8/include/v8-internal.h +++ b/deps/v8/include/v8-internal.h @@ -374,15 +374,23 @@ constexpr size_t kMaxExternalPointers = 0; #endif // V8_COMPRESS_POINTERS +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 +constexpr uint64_t kExternalPointerMarkBit = 1ULL << 56; +constexpr uint64_t kExternalPointerTagShift = 57; +constexpr uint64_t kExternalPointerTagMask = 0xfe00000000000000ULL; +constexpr uint64_t kExternalPointerTagAndMarkbitMask = 0xff00000000000000ULL; +constexpr uint64_t kExternalPointerPayloadMask = 0x00ffffffffffffffULL; +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) constexpr uint64_t kExternalPointerMarkBit = 1ULL << 48; constexpr uint64_t kExternalPointerTagShift = 49; constexpr uint64_t kExternalPointerTagMask = 0x00fe000000000000ULL; +constexpr uint64_t kExternalPointerTagAndMarkbitMask = 0x00ff000000000000ULL; +constexpr uint64_t kExternalPointerPayloadMask = 0xff00ffffffffffffULL; +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) constexpr uint64_t kExternalPointerShiftedTagMask = kExternalPointerTagMask >> kExternalPointerTagShift; static_assert(kExternalPointerShiftedTagMask << kExternalPointerTagShift == kExternalPointerTagMask); -constexpr uint64_t kExternalPointerTagAndMarkbitMask = 0x00ff000000000000ULL; -constexpr uint64_t kExternalPointerPayloadMask = 0xff00ffffffffffffULL; // A ExternalPointerHandle represents a (opaque) reference to an external // pointer that can be stored inside the sandbox. A ExternalPointerHandle has @@ -604,6 +612,7 @@ enum class ManagedTypeId : uint32_t { kTemporalPlainMonthDay, kTemporalZonedDateTime, kDisplayNamesInternal, + kPluralRulesInternal, kD8Worker, kD8ModuleEmbedderData, kD8AsyncHooksWrap, @@ -620,7 +629,6 @@ enum class ManagedTypeId : uint32_t { V(IcuDateIntervalFormatTag) \ V(IcuRelativeDateTimeFormatterTag) \ V(IcuLocalizedNumberFormatterTag) \ - V(IcuPluralRulesTag) \ V(IcuCollatorTag) #define FOREIGN_TAG_LIST(V) \ @@ -679,8 +687,8 @@ enum class ManagedTypeId : uint32_t { // use ExternalPointerHandles directly and use them to access the pointers in an // ExternalPointerTable. // -// The tag is currently in practice limited to 15 bits since it needs to fit -// together with a marking bit into the unused parts of a pointer. +// The tag is limited to 7 bits since it needs to fit together with a marking +// bit into the unused parts of a 57-bit pointer to support LA57 on x64. enum ExternalPointerTag : uint16_t { kFirstExternalPointerTag = 0, kExternalPointerNullTag = 0, @@ -694,8 +702,7 @@ enum ExternalPointerTag : uint16_t { // be accessed from multiple threads at the same time. The objects referenced // in this way must therefore always be thread-safe. kFirstSharedExternalPointerTag, - kWaiterQueueNodeTag = kFirstSharedExternalPointerTag, - kExternalStringResourceTag, + kExternalStringResourceTag = kFirstSharedExternalPointerTag, kExternalStringResourceDataTag, kLastSharedExternalPointerTag = kExternalStringResourceDataTag, @@ -762,6 +769,9 @@ enum ExternalPointerTag : uint16_t { kLastExternalPointerTag = 0x7f, }; +// All tags must fit into the 7 tag bits of an external pointer table entry. +static_assert(kLastExternalPointerTag <= 0x7f); + constexpr const char* ToString(ExternalPointerTag tag) { switch (tag) { #define ENUM_CASE(name) \ @@ -879,33 +889,6 @@ V8_INLINE static constexpr bool ExternalPointerCanBeEmpty( kAnyInterceptorInfoExternalPointerTagRange.Contains(tag_range); } -// Indirect Pointers. -// -// When the sandbox is enabled, indirect pointers are used to reference -// HeapObjects that live outside of the sandbox (but are still managed by V8's -// garbage collector). When object A references an object B through an indirect -// pointer, object A will contain a IndirectPointerHandle, i.e. a shifted -// 32-bit index, which identifies an entry in a pointer table (either the -// trusted pointer table for TrustedObjects, or the code pointer table if it is -// a Code object). This table entry then contains the actual pointer to object -// B. Further, object B owns this pointer table entry, and it is responsible -// for updating the "self-pointer" in the entry when it is relocated in memory. -// This way, in contrast to "normal" pointers, indirect pointers never need to -// be tracked by the GC (i.e. there is no remembered set for them). -// These pointers do not exist when the sandbox is disabled. - -// An IndirectPointerHandle represents a 32-bit index into a pointer table. -using IndirectPointerHandle = uint32_t; - -// A null handle always references an entry that contains nullptr. -constexpr IndirectPointerHandle kNullIndirectPointerHandle = 0; - -// When the sandbox is enabled, indirect pointers are used to implement: -// - TrustedPointers: an indirect pointer using the trusted pointer table (TPT) -// and referencing a TrustedObject in one of the trusted heap spaces. -// - CodePointers, an indirect pointer using the code pointer table (CPT) and -// referencing a Code object together with its instruction stream. - // // Trusted Pointers. // @@ -913,9 +896,19 @@ constexpr IndirectPointerHandle kNullIndirectPointerHandle = 0; // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table (TPT). They are used to reference trusted objects (located in // one of V8's trusted heap spaces, outside of the sandbox) from inside the -// sandbox in a memory-safe way. When the sandbox is disabled, these are -// regular tagged pointers. -using TrustedPointerHandle = IndirectPointerHandle; +// sandbox in a memory-safe way. When object A references an object B through a +// trusted pointer, object A will contain a TrustedPointerHandle, i.e. a shifted +// 32-bit index, which identifies an entry in the trusted pointer table. This +// table entry then contains the actual pointer to object B. Further, object B +// owns this pointer table entry, and it is responsible for updating the +// "self-pointer" in the entry when it is relocated in memory. This way, in +// contrast to "normal" pointers, trusted pointers never need to be tracked by +// the GC (i.e. there is no remembered set for them). +// When the sandbox is disabled, these are regular tagged pointers. + +// A TrustedPointerHandle represents a 32-bit index into a trusted pointer +// table. +using TrustedPointerHandle = uint32_t; // The size of the virtual memory reservation for the trusted pointer table. // As with the external pointer table, a maximum table size in combination with @@ -927,8 +920,7 @@ constexpr size_t kTrustedPointerTableReservationSize = 64 * MB; constexpr uint32_t kTrustedPointerHandleShift = 9; // A null handle always references an entry that contains nullptr. -constexpr TrustedPointerHandle kNullTrustedPointerHandle = - kNullIndirectPointerHandle; +constexpr TrustedPointerHandle kNullTrustedPointerHandle = 0; // The byte size of an entry in the trusted pointer table. constexpr int kTrustedPointerTableEntrySize = 8; @@ -1149,24 +1141,16 @@ class Internals { #if V8_STATIC_ROOTS_BOOL // These constants are copied from static-roots.h and guarded by static asserts. -#define EXPORTED_STATIC_ROOTS_PTR_LIST(V) \ - V(UndefinedValue, 0x11) \ - V(NullValue, 0x2d) \ - V(TrueValue, 0x71) \ - V(FalseValue, 0x55) \ - V(EmptyString, 0x49) \ - /* The Hole moves around depending on build flags, so define it */ \ - /* separately inside StaticReadOnlyRoot using build macros */ \ - V(TheHoleValue, kBuildDependentTheHoleValue) +#define EXPORTED_STATIC_ROOTS_PTR_LIST(V) \ + V(UndefinedValue, 0x11) \ + V(NullValue, 0x2d) \ + V(TrueValue, 0x71) \ + V(FalseValue, 0x55) \ + V(EmptyString, 0x49) \ + V(TheHoleValue, 0xfffd) using Tagged_t = uint32_t; struct StaticReadOnlyRoot { -#ifdef V8_ENABLE_WEBASSEMBLY - static constexpr Tagged_t kBuildDependentTheHoleValue = 0x2fffd; -#else - static constexpr Tagged_t kBuildDependentTheHoleValue = 0xfffd; -#endif - #define DEF_ROOT(name, value) static constexpr Tagged_t k##name = value; EXPORTED_STATIC_ROOTS_PTR_LIST(DEF_ROOT) #undef DEF_ROOT diff --git a/deps/v8/include/v8-isolate.h b/deps/v8/include/v8-isolate.h index a352b5f0164f..544e7a46fe57 100644 --- a/deps/v8/include/v8-isolate.h +++ b/deps/v8/include/v8-isolate.h @@ -198,6 +198,13 @@ enum class ContextDependants { */ using StackState = cppgc::EmbedderStackState; +/** + * A stack-allocated scope that sets the current thread's stack start address + * for conservative stack scanning and restores the previous stack start on + * destruction. + */ +using StackStartScope = cppgc::StackStartScope; + /** * The set of V8 isolates in a process is partitioned into groups. Each group * has its own sandbox (if V8 was configured with support for the sandbox) and @@ -267,6 +274,12 @@ class V8_EXPORT IsolateGroup { */ bool SandboxContains(void* pointer) const; VirtualAddressSpace* GetSandboxAddressSpace(); + + /** + * Sets the allocator used for allocations inside this group's sandbox. + * This must be called before the first Isolate is created in the group. + */ + void SetInSandboxAllocator(std::shared_ptr<Allocator> allocator); #else V8_INLINE bool SandboxContains(void* pointer) const { return true; } #endif @@ -670,6 +683,7 @@ class V8_EXPORT Isolate { kRegExpMatcherFlagsMismatch = 188, kRegExpCustomSpecies = 189, kWasmWideArithmetic = 190, + kBigInt = 191, // If you add new values here, you'll also need to update Chromium's: // web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to @@ -1732,6 +1746,14 @@ class V8_EXPORT Isolate { void SetModifyCodeGenerationFromStringsCallback( ModifyCodeGenerationFromStringsCallback2 callback); + /** + * Set the callback to invoke when a dynamic script (e.g. eval or Function) is + * compiled from the embedder without a calling user JavaScript script on the + * stack. + */ + void SetDynamicScriptCompiledFromEmbedderCallback( + DynamicScriptCompiledFromEmbedderCallback callback); + /** * Set the callback to invoke to check if wasm code generation should * be allowed. @@ -1743,7 +1765,11 @@ class V8_EXPORT Isolate { * Embedder over{ride|load} injection points for wasm APIs. The expectation * is that the embedder sets them at most once. */ + void SetWasmModuleCallback(WasmModuleCallback callback); + V8_DEPRECATE_SOON("Use the WasmModuleCallback overload instead") void SetWasmModuleCallback(ExtensionCallback callback); + void SetWasmInstanceCallback(WasmInstanceCallback callback); + V8_DEPRECATE_SOON("Use the WasmInstanceCallback overload instead") void SetWasmInstanceCallback(ExtensionCallback callback); void SetWasmStreamingCallback(WasmStreamingCallback callback); diff --git a/deps/v8/include/v8-local-handle.h b/deps/v8/include/v8-local-handle.h index a1762eb25735..1f4b30ea9b36 100644 --- a/deps/v8/include/v8-local-handle.h +++ b/deps/v8/include/v8-local-handle.h @@ -42,7 +42,7 @@ class BasicTracedReference; template <class F> class TracedReference; -class ArrayBuffer; +class ArrayBufferView; class Boolean; class Context; class EscapableHandleScope; @@ -56,6 +56,7 @@ class Primitive; class Private; template <class F> class PropertyCallbackInfo; +class RegExp; template <class F> class ReturnValue; class String; @@ -63,8 +64,8 @@ template <class F> class Traced; class TypecheckWitness; class Utils; -class Uint32; class Value; +class WasmMemoryObject; namespace debug { class ConsoleCallArguments; @@ -87,14 +88,6 @@ template <typename T, typename V = Value> void TypeCheckLocal(V* value) { // If `T` does not provide a `Cast` method we cannot check anything. if constexpr (requires { T::Cast(value); }) { - // TODO(419454582): Remove all these exceptions. - if (std::is_same_v<Array, T> && value->IsArgumentsObject()) return; - if (std::is_same_v<ArrayBuffer, T> && value->IsSharedArrayBuffer()) return; - if (std::is_same_v<Object, T> && value->IsNull()) return; - if (std::is_same_v<Object, T> && value->IsString()) return; - if (std::is_same_v<Object, T> && value->IsUndefined()) return; - if (std::is_same_v<Uint32, T> && value->IsInt32()) return; - if (std::is_same_v<Object, T> && value->IsNumber()) return; // Execute the actual check (part of the cast). T::Cast(value); } @@ -476,11 +469,14 @@ class V8_TRIVIAL_ABI Local : public LocalBase<T>, friend class FunctionCallbackInfo; template <class F> friend class PropertyCallbackInfo; + friend class ArrayBufferView; friend class String; friend class Object; friend class Context; friend class Isolate; friend class Private; + friend class RegExp; + friend class WasmMemoryObject; template <class F> friend class internal::CustomArguments; friend Local<Primitive> Undefined(Isolate* isolate); diff --git a/deps/v8/include/v8-object.h b/deps/v8/include/v8-object.h index f7fbd4e13023..650eddee7918 100644 --- a/deps/v8/include/v8-object.h +++ b/deps/v8/include/v8-object.h @@ -203,7 +203,7 @@ using AccessorNameSetterCallbackV2 = const PropertyCallbackInfo<Boolean>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using AccessorNameSetterCallback // - V8_DEPRECATE_SOON("Use AccessorNameSetterCallbackV2 instead.") = + V8_DEPRECATED("Use AccessorNameSetterCallbackV2 instead.") = void (*)(Local<Name> property, Local<Value> value, const PropertyCallbackInfo<void>& info); @@ -337,6 +337,23 @@ class V8_EXPORT Object : public Value { V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context, uint32_t index); + /** + * Like Get(), but only succeeds if the property can be read without side + * effects, i.e. without running JavaScript or any embedder callback that may + * have side effects. + * + * Returns the value if reading the property is determined to have no side + * effects, or an empty handle without throwing otherwise. + * + * For example, this can succeed if the lookup ends at a data property or a + * native data property whose getter is declared as + * SideEffectType::kHasNoSideEffect. It will return an empty handle if reading + * the property would require calling an accessor getter, an interceptor, or a + * Proxy trap, or if the lookup fails an access check. + */ + V8_WARN_UNUSED_RESULT MaybeLocal<Value> TryGetWithNoSideEffects( + Local<Context> context, Local<Name> key); + /** * Gets the property attributes of a property which can be None or * any combination of ReadOnly, DontEnum and DontDelete. Returns @@ -409,7 +426,7 @@ class V8_EXPORT Object : public Value { Local<Context> context, Local<Name> name, AccessorNameGetterCallback getter, AccessorNameSetterCallbackV2 setter = nullptr, - Local<Value> data = Local<Value>(), PropertyAttribute attributes = None, + Local<Data> data = Local<Data>(), PropertyAttribute attributes = None, SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); diff --git a/deps/v8/include/v8-platform.h b/deps/v8/include/v8-platform.h index abfccd3f57ff..96ed8e66107f 100644 --- a/deps/v8/include/v8-platform.h +++ b/deps/v8/include/v8-platform.h @@ -185,17 +185,26 @@ class TaskRunner { * Implementation of above methods with an additional `location` argument. */ virtual void PostTaskImpl(std::unique_ptr<Task> task, - const SourceLocation& location) {} + const SourceLocation& location) = 0; virtual void PostNonNestableTaskImpl(std::unique_ptr<Task> task, - const SourceLocation& location) {} + const SourceLocation& location) { + // This must be overridden if `NonNestableTasksEnabled()`. + abort(); + } virtual void PostDelayedTaskImpl(std::unique_ptr<Task> task, double delay_in_seconds, - const SourceLocation& location) {} + const SourceLocation& location) = 0; virtual void PostNonNestableDelayedTaskImpl(std::unique_ptr<Task> task, double delay_in_seconds, - const SourceLocation& location) {} + const SourceLocation& location) { + // This must be overridden if `NonNestableDelayedTasksEnabled()`. + abort(); + } virtual void PostIdleTaskImpl(std::unique_ptr<IdleTask> task, - const SourceLocation& location) {} + const SourceLocation& location) { + // This must be overridden if `IdleTasksEnabled()`. + abort(); + } }; /** diff --git a/deps/v8/include/v8-primitive.h b/deps/v8/include/v8-primitive.h index 8466df80175d..fe7a5f83a46a 100644 --- a/deps/v8/include/v8-primitive.h +++ b/deps/v8/include/v8-primitive.h @@ -285,6 +285,9 @@ class V8_EXPORT String : public Name { * Internally V8 will call this Unaccount method when the external string * resource should be unaccounted for. This method can be overridden in * subclasses to control how allocated external bytes are accounted. + * + * Implementations must not allocate on the V8 heap, trigger garbage + * collection, or execute JavaScript. */ virtual void Unaccount(Isolate* isolate) {} @@ -331,6 +334,9 @@ class V8_EXPORT String : public Name { * resource is no longer needed. The default implementation will use the * delete operator. This method can be overridden in subclasses to * control how allocated external string resources are disposed. + * + * Implementations must not allocate on the V8 heap, trigger garbage + * collection, or execute JavaScript. */ virtual void Dispose() { delete this; } diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index df60fd7f66d7..ee77b9b6d9f0 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -31,6 +31,39 @@ using NativeObject = void*; using SnapshotObjectId = uint32_t; using ProfilerId = uint32_t; +/** + * Embedder-supplied callback invoked as each CPU profile sample is captured. + * The returned pointer is stored on the sample and retrievable via + * CpuProfile::GetSampleContext. + * + * The context in which it runs depends on how the sample was taken. For + * samples taken by the sampling thread, it is invoked either from a POSIX + * signal handler interrupting the sampled thread, or (on platforms that sample + * by suspending that thread, such as Windows and Fuchsia) on the sampling + * thread itself. For samples requested via CpuProfiler::CollectSample, or + * recorded on deoptimization, it is invoked synchronously on the thread that + * triggered them. + * + * Consequently this function MUST NOT rely on thread-local storage. Where + * sampling suspends the profiled thread, the callback runs on the sampling + * thread, whose thread-locals are unrelated to the profiled thread's, and the + * profiled thread's are not reachable at all. Accessing a dynamically + * initialized thread-local is in any case not async-signal-safe. Use the + * supplied Isolate to determine what to return, keeping whatever per-isolate + * state that requires in memory the embedder maintains outside this callback. + * + * The signal-safety contract applies in all of these cases: this function + * MUST NOT allocate memory, acquire locks, call any V8 API, or perform any + * other operation that is not async-signal-safe. It SHOULD limit itself to + * reading from memory the embedder keeps stable for the duration of + * profiling, and returning a `void*` whose meaning is defined by the + * embedder. Note that V8 may hold internal locks while calling it, so + * reentering the CpuProfiler API from the extractor can deadlock. + * + * The returned pointer is treated as opaque by V8 and is not dereferenced. + */ +using SampleContextExtractor = void* (*)(Isolate*); + struct CpuProfileDeoptFrame { int script_id; size_t position; @@ -272,6 +305,15 @@ class V8_EXPORT CpuProfile { */ EmbedderStateTag GetSampleEmbedderState(int index) const; + /** + * Returns the embedder-supplied sample context for the sample at the given + * index. The pointer was produced by the SampleContextExtractor installed + * on the CpuProfilingOptions used to start this profile. If no extractor + * was installed, or the extractor returned nullptr for this sample, returns + * nullptr. + */ + void* GetSampleContext(int index) const; + /** * Returns time when the profile recording was stopped (in microseconds) * since some unspecified starting point. @@ -394,12 +436,19 @@ class V8_EXPORT CpuProfilingOptions { * \param filter_context If specified, profiles will only contain frames * using this context. Other frames will be elided. * \param profile_source Identifies the source of this CPU profile. + * \param sample_context_extractor Optional embedder callback invoked as each + * sample is captured. The returned pointer + * is stored on the sample and retrievable + * via CpuProfile::GetSampleContext. See + * SampleContextExtractor for the + * signal-safety contract. */ CpuProfilingOptions( CpuProfilingMode mode = kLeafNodeLineNumbers, unsigned max_samples = kNoSampleLimit, int sampling_interval_us = 0, MaybeLocal<Context> filter_context = MaybeLocal<Context>(), - CpuProfileSource profile_source = CpuProfileSource::kUnspecified); + CpuProfileSource profile_source = CpuProfileSource::kUnspecified, + SampleContextExtractor sample_context_extractor = nullptr); CpuProfilingOptions(CpuProfilingOptions&&) = default; CpuProfilingOptions& operator=(CpuProfilingOptions&&) = default; @@ -408,6 +457,9 @@ class V8_EXPORT CpuProfilingOptions { unsigned max_samples() const { return max_samples_; } int sampling_interval_us() const { return sampling_interval_us_; } CpuProfileSource profile_source() const { return profile_source_; } + SampleContextExtractor sample_context_extractor() const { + return sample_context_extractor_; + } private: friend class internal::CpuProfile; @@ -420,6 +472,7 @@ class V8_EXPORT CpuProfilingOptions { int sampling_interval_us_; Global<Context> filter_context_; CpuProfileSource profile_source_; + SampleContextExtractor sample_context_extractor_ = nullptr; }; /** @@ -841,6 +894,14 @@ class V8_EXPORT AllocationProfile { * Sample interval in bytes used when this sample was selected. */ uint64_t sample_interval; + + /** + * Value returned for this sample by the SampleContextExtractor passed to + * HeapProfiler::StartSamplingHeapProfiler, or nullptr if none was + * installed. The embedder is responsible for any pointee lifetime required + * when using it; V8 never dereferences it. + */ + void* context = nullptr; }; /** @@ -1251,11 +1312,19 @@ class V8_EXPORT HeapProfiler { * Objects allocated before the sampling is started will not be included in * the profile. * + * If |sample_context_extractor| is set, it is called on the isolate's thread + * for each sampled allocation, and its result is stored in + * AllocationProfile::Sample::context. Because it runs while the allocation is + * being sampled, it MUST NOT run JavaScript, allocate on a managed heap + * (including cppgc) or call into the HeapProfiler. It may create local + * handles. + * * Returns false if a sampling heap profiler is already running. */ - bool StartSamplingHeapProfiler(uint64_t sample_interval = 512 * 1024, - int stack_depth = 16, - SamplingFlags flags = kSamplingNoFlags); + bool StartSamplingHeapProfiler( + uint64_t sample_interval = 512 * 1024, int stack_depth = 16, + SamplingFlags flags = kSamplingNoFlags, + SampleContextExtractor sample_context_extractor = nullptr); /** * Stops the sampling heap profile and discards the current profile. diff --git a/deps/v8/include/v8-regexp.h b/deps/v8/include/v8-regexp.h index d1253d276a57..73b5fadc9f4f 100644 --- a/deps/v8/include/v8-regexp.h +++ b/deps/v8/include/v8-regexp.h @@ -75,8 +75,11 @@ class V8_EXPORT RegExp : public Object { * * Note: modifies global context state, accessible e.g. through RegExp.input. */ + V8_DEPRECATE_SOON("Use ExecV2 instead") V8_WARN_UNUSED_RESULT MaybeLocal<Object> Exec(Local<Context> context, Local<String> subject); + V8_WARN_UNUSED_RESULT MaybeLocal<Value> ExecV2(Local<Context> context, + Local<String> subject); /** * Returns the value of the source property: a string representing diff --git a/deps/v8/include/v8-template.h b/deps/v8/include/v8-template.h index 182293f05bd8..c2a835b85ac5 100644 --- a/deps/v8/include/v8-template.h +++ b/deps/v8/include/v8-template.h @@ -114,7 +114,7 @@ class V8_EXPORT Template : public Data { */ void SetLazyDataProperty( Local<Name> name, AccessorNameGetterCallback getter, - Local<Value> data = Local<Value>(), PropertyAttribute attribute = None, + Local<Data> data = Local<Data>(), PropertyAttribute attribute = None, SideEffectType getter_side_effect_type = SideEffectType::kHasSideEffect, SideEffectType setter_side_effect_type = SideEffectType::kHasSideEffect); @@ -218,7 +218,7 @@ using NamedPropertySetterCallbackV2 = const PropertyCallbackInfo<Boolean>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using NamedPropertySetterCallback // - V8_DEPRECATE_SOON("Use NamedPropertySetterCallbackV2 instead.") = + V8_DEPRECATED("Use NamedPropertySetterCallbackV2 instead.") = Intercepted (*)(Local<Name> property, Local<Value> value, const PropertyCallbackInfo<void>& info); @@ -318,7 +318,7 @@ using NamedPropertyDefinerCallbackV2 = const PropertyCallbackInfo<Boolean>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using NamedPropertyDefinerCallback // - V8_DEPRECATE_SOON("Use NamedPropertyDefinerCallbackV2 instead.") = + V8_DEPRECATED("Use NamedPropertyDefinerCallbackV2 instead.") = Intercepted (*)(Local<Name> property, const PropertyDescriptor& desc, const PropertyCallbackInfo<void>& info); @@ -353,7 +353,7 @@ using IndexedPropertyGetterCallback = Intercepted (*)(uint32_t index, const PropertyCallbackInfo<Value>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using IndexedPropertyGetterCallbackV2 // - V8_DEPRECATE_SOON("Use IndexedPropertyGetterCallback instead.") = + V8_DEPRECATED("Use IndexedPropertyGetterCallback instead.") = IndexedPropertyGetterCallback; /** @@ -364,7 +364,7 @@ using IndexedPropertySetterCallback = const PropertyCallbackInfo<Boolean>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using IndexedPropertySetterCallbackV2 // - V8_DEPRECATE_SOON("Use IndexedPropertySetterCallback instead.") = + V8_DEPRECATED("Use IndexedPropertySetterCallback instead.") = Intercepted (*)(uint32_t index, Local<Value> value, const PropertyCallbackInfo<void>& info); @@ -375,7 +375,7 @@ using IndexedPropertyQueryCallback = Intercepted (*)(uint32_t index, const PropertyCallbackInfo<Integer>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using IndexedPropertyQueryCallbackV2 // - V8_DEPRECATE_SOON("Use IndexedPropertyQueryCallback instead.") = + V8_DEPRECATED("Use IndexedPropertyQueryCallback instead.") = IndexedPropertyQueryCallback; /** @@ -385,7 +385,7 @@ using IndexedPropertyDeleterCallback = Intercepted (*)(uint32_t index, const PropertyCallbackInfo<Boolean>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using IndexedPropertyDeleterCallbackV2 // - V8_DEPRECATE_SOON("Use IndexedPropertyDeleterCallback instead.") = + V8_DEPRECATED("Use IndexedPropertyDeleterCallback instead.") = IndexedPropertyDeleterCallback; /** @@ -405,7 +405,7 @@ using IndexedPropertyDefinerCallback = const PropertyCallbackInfo<Boolean>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using IndexedPropertyDefinerCallbackV2 // - V8_DEPRECATE_SOON("Use IndexedPropertyDefinerCallback instead.") = + V8_DEPRECATED("Use IndexedPropertyDefinerCallback instead.") = Intercepted (*)(uint32_t index, const PropertyDescriptor& desc, const PropertyCallbackInfo<void>& info); @@ -416,7 +416,7 @@ using IndexedPropertyDescriptorCallback = Intercepted (*)(uint32_t index, const PropertyCallbackInfo<Value>& info); // TODO(https://crbug.com/348660658): deprecate and remove. using IndexedPropertyDescriptorCallbackV2 // - V8_DEPRECATE_SOON("Use IndexedPropertyDescriptorCallback instead.") = + V8_DEPRECATED("Use IndexedPropertyDescriptorCallback instead.") = IndexedPropertyDescriptorCallback; /** diff --git a/deps/v8/include/v8-typed-array.h b/deps/v8/include/v8-typed-array.h index 0451b1294cd1..cdadc2971540 100644 --- a/deps/v8/include/v8-typed-array.h +++ b/deps/v8/include/v8-typed-array.h @@ -60,9 +60,7 @@ class V8_EXPORT Uint8Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(uint8_t); static_assert(sizeof(uint8_t) == 1); - static Local<Uint8Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Uint8Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Uint8Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Uint8Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -88,11 +86,8 @@ class V8_EXPORT Uint8ClampedArray : public TypedArray { TypedArray::kMaxByteLength / sizeof(uint8_t); static_assert(sizeof(uint8_t) == 1); - static Local<Uint8ClampedArray> New(Local<ArrayBuffer> array_buffer, + static Local<Uint8ClampedArray> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); - static Local<Uint8ClampedArray> New( - Local<SharedArrayBuffer> shared_array_buffer, size_t byte_offset, - size_t length); V8_INLINE static Uint8ClampedArray* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); @@ -117,9 +112,7 @@ class V8_EXPORT Int8Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(int8_t); static_assert(sizeof(int8_t) == 1); - static Local<Int8Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Int8Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Int8Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Int8Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -145,9 +138,7 @@ class V8_EXPORT Uint16Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(uint16_t); static_assert(sizeof(uint16_t) == 2); - static Local<Uint16Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Uint16Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Uint16Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Uint16Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -173,9 +164,7 @@ class V8_EXPORT Int16Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(int16_t); static_assert(sizeof(int16_t) == 2); - static Local<Int16Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Int16Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Int16Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Int16Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -201,9 +190,7 @@ class V8_EXPORT Uint32Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(uint32_t); static_assert(sizeof(uint32_t) == 4); - static Local<Uint32Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Uint32Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Uint32Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Uint32Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -229,9 +216,7 @@ class V8_EXPORT Int32Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(int32_t); static_assert(sizeof(int32_t) == 4); - static Local<Int32Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Int32Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Int32Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Int32Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -253,9 +238,7 @@ class V8_EXPORT Float16Array : public TypedArray { static constexpr size_t kMaxLength = TypedArray::kMaxByteLength / sizeof(uint16_t); - static Local<Float16Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Float16Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Float16Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Float16Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -281,9 +264,7 @@ class V8_EXPORT Float32Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(float); static_assert(sizeof(float) == 4); - static Local<Float32Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Float32Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Float32Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Float32Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -309,9 +290,7 @@ class V8_EXPORT Float64Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(double); static_assert(sizeof(double) == 8); - static Local<Float64Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<Float64Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<Float64Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static Float64Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -337,9 +316,7 @@ class V8_EXPORT BigInt64Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(int64_t); static_assert(sizeof(int64_t) == 8); - static Local<BigInt64Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<BigInt64Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<BigInt64Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static BigInt64Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -365,9 +342,7 @@ class V8_EXPORT BigUint64Array : public TypedArray { TypedArray::kMaxByteLength / sizeof(uint64_t); static_assert(sizeof(uint64_t) == 8); - static Local<BigUint64Array> New(Local<ArrayBuffer> array_buffer, - size_t byte_offset, size_t length); - static Local<BigUint64Array> New(Local<SharedArrayBuffer> shared_array_buffer, + static Local<BigUint64Array> New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t length); V8_INLINE static BigUint64Array* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS diff --git a/deps/v8/include/v8-value.h b/deps/v8/include/v8-value.h index 4757dcc41856..4d6a0b0d4188 100644 --- a/deps/v8/include/v8-value.h +++ b/deps/v8/include/v8-value.h @@ -251,6 +251,11 @@ class V8_EXPORT Value : public Data { */ bool IsWeakRef() const; + /** + * Returns true if this value is an ArrayBuffer or SharedArrayBuffer. + */ + bool IsArrayBufferBase() const; + /** * Returns true if this value is an ArrayBuffer. */ diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index f91b6e7018f8..89aa8ae28a79 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -9,9 +9,9 @@ // NOTE these macros are used by some of the tool scripts and the build // system so their names cannot be changed without changing the scripts. #define V8_MAJOR_VERSION 15 -#define V8_MINOR_VERSION 6 -#define V8_BUILD_NUMBER 75 -#define V8_PATCH_LEVEL 25 +#define V8_MINOR_VERSION 8 +#define V8_BUILD_NUMBER 62 +#define V8_PATCH_LEVEL 0 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8-wasm.h b/deps/v8/include/v8-wasm.h index 17227e6d485b..e54351f4682e 100644 --- a/deps/v8/include/v8-wasm.h +++ b/deps/v8/include/v8-wasm.h @@ -10,6 +10,7 @@ #include <span> #include <string> #include <string_view> +#include <utility> #include <variant> #include "v8-internal.h" // NOLINT(build/include_directory) @@ -21,6 +22,7 @@ namespace v8 { class ArrayBuffer; +class ArrayBufferBase; class Promise; namespace internal::wasm { @@ -31,11 +33,40 @@ class NativeModule; * An owned byte buffer with associated size. */ struct OwnedBuffer { + V8_DEPRECATE_SOON("Use as_span() instead") std::unique_ptr<const uint8_t[]> buffer; + V8_DEPRECATE_SOON("Use as_span() instead") size_t size = 0; + + START_ALLOW_USE_DEPRECATED() + OwnedBuffer() = default; + ~OwnedBuffer() = default; + + V8_DEPRECATE_SOON( + "Use as_span() instead; external construction is deprecated") OwnedBuffer(std::unique_ptr<const uint8_t[]> buffer, size_t size) : buffer(std::move(buffer)), size(size) {} - OwnedBuffer() = default; + + OwnedBuffer(const OwnedBuffer&) = delete; + OwnedBuffer& operator=(const OwnedBuffer&) = delete; + + OwnedBuffer(OwnedBuffer&& other) noexcept + : buffer(std::move(other.buffer)), size(std::exchange(other.size, 0)) {} + + OwnedBuffer& operator=(OwnedBuffer&& other) noexcept { + if (this != &other) { + buffer = std::move(other.buffer); + size = std::exchange(other.size, 0); + } + return *this; + } + + constexpr bool empty() const { return size == 0; } + + constexpr std::span<const uint8_t> as_span() const { + return {buffer.get(), size}; + } + END_ALLOW_USE_DEPRECATED() }; /** @@ -77,7 +108,12 @@ class V8_EXPORT WasmMemoryObject : public Object { /** * Returns underlying ArrayBuffer. */ + V8_DEPRECATE_SOON("Use GetBuffer instead") Local<ArrayBuffer> Buffer(); + /** + * Returns underlying ArrayBuffer or SharedArrayBuffer. + */ + Local<ArrayBufferBase> GetBuffer(); V8_INLINE static WasmMemoryObject* Cast(Value* value) { #ifdef V8_ENABLE_CHECKS @@ -130,9 +166,8 @@ class V8_EXPORT WasmModuleObject : public Object { // remain valid for the duration of the compile call. const char* imported_string_constants_module = nullptr; // If non-empty, associated with the module's script as its source URL, for - // use in stack traces and developer tooling. If a script already exists in - // the isolate for the same module, its existing URL is retained. The - // string must remain valid for the duration of the compile call. + // use in stack traces and developer tooling. The string must remain valid + // for the duration of the compile call. std::string_view source_url = {}; }; diff --git a/deps/v8/include/v8config.h b/deps/v8/include/v8config.h index 79bb264d2c9f..b7aeeade6b81 100644 --- a/deps/v8/include/v8config.h +++ b/deps/v8/include/v8config.h @@ -609,15 +609,11 @@ path. Add it with -I<path> to the command line // functions. // Use like: // V8_NOINLINE V8_PRESERVE_MOST void UnlikelyMethod(); -#if V8_CC_MSVC -# define V8_PRESERVE_MOST -#else #if V8_HAS_ATTRIBUTE_PRESERVE_MOST # define V8_PRESERVE_MOST __attribute__((preserve_most)) #else # define V8_PRESERVE_MOST /* NOT SUPPORTED */ #endif -#endif // A macro (V8_DEPRECATED) to mark classes or functions as deprecated. diff --git a/deps/v8/infra/mb/gn_isolate_map.pyl b/deps/v8/infra/mb/gn_isolate_map.pyl index 924bba4adff0..ed7496cde71b 100644 --- a/deps/v8/infra/mb/gn_isolate_map.pyl +++ b/deps/v8/infra/mb/gn_isolate_map.pyl @@ -39,6 +39,10 @@ "label": "//test/unittests:generate-bytecode-expectations", "type": "script", }, + "intl": { + "label": "//test/intl:v8_intl", + "type": "script", + }, "mjsunit": { "label": "//test/mjsunit:v8_mjsunit", "type": "script", diff --git a/deps/v8/infra/mb/mb_config.pyl b/deps/v8/infra/mb/mb_config.pyl index 3102eaf1ee57..38e227a7d27e 100644 --- a/deps/v8/infra/mb/mb_config.pyl +++ b/deps/v8/infra/mb/mb_config.pyl @@ -107,6 +107,7 @@ 'V8 Linux64 TSAN - no-concurrent-marking - builder': 'release_x64_tsan_no_cm', 'V8 Linux - arm64 - sim - MSAN - builder': 'release_simulate_arm64_msan', # FYI. + 'Linux64 - icu4x - debug builder': 'debug_x64_icu4x', 'V8 iOS - sim - builder': 'release_x64_ios_simulator', 'V8 Linux64 - arm64 - ASAN - builder': 'release_arm64_asan', 'V8 Linux64 - arm64 - builder': 'release_arm64', @@ -126,8 +127,6 @@ 'V8 Linux64 - sticky mark bits - debug builder': 'debug_x64_sticky_mark_bits', 'V8 Linux64 - undefined double - debug builder': 'debug_x64_undefined_double', 'V8 Linux64 css - debug builder': 'debug_x64_conservative_stack_scanning', - 'V8 Linux64 - jammy - gcc - builder': 'release_x64_gcc', - 'V8 Linux64 - jammy - gcc - debug builder': 'debug_x64_gcc', 'V8 Fuchsia - builder': 'release_x64_fuchsia', 'V8 Fuchsia - debug builder': 'debug_x64_fuchsia', 'V8 Linux64 - cfi - builder': 'release_x64_cfi', @@ -298,13 +297,9 @@ 'v8_linux64_fuzzilli_imports_compile_rel': 'release_x64', 'v8_linux64_gc_stress_custom_snapshot_compile_dbg': 'debug_x64_trybot_custom', 'v8_linux64_gc_stress_compile_dbg': 'debug_x64_trybot', - 'v8_linux64_gcc_compile_dbg': 'debug_x64_gcc', - 'v8_linux64_jammy_gcc_compile_dbg': 'debug_x64_gcc', - 'v8_linux64_gcc_light_compile_dbg': 'debug_x64_gcc', - 'v8_linux64_gcc_compile_rel': 'release_x64_gcc', - 'v8_linux64_jammy_gcc_compile_rel': 'release_x64_gcc', 'v8_linux64_header_includes_dbg': 'debug_x64_header_includes', 'v8_linux64_fyi_compile_rel': 'release_x64_test_features_trybot', + 'v8_linux64_icu4x_compile_dbg': 'debug_x64_icu4x', 'v8_linux64_nodcheck_compile_rel': 'release_x64', 'v8_linux64_perfetto_compile_dbg': 'debug_x64_perfetto', 'v8_linux64_no_metagen_compile_dbg': @@ -666,8 +661,6 @@ 'release_bot', 'x64', 'fuchsia'], 'release_x64_fuchsia_trybot': [ 'release_trybot', 'x64', 'fuchsia'], - 'release_x64_gcc': [ - 'release_bot_no_remoteexec', 'x64', 'gcc', 'lld', 'no_custom_libcxx'], 'release_x64_ios_simulator': [ 'release_bot', 'x64', 'ios_simulator'], 'release_x64_internal': [ @@ -746,10 +739,10 @@ 'debug_bot', 'x64', 'v8_enable_drumbrake'], 'debug_x64_fuchsia': [ 'debug_bot', 'x64', 'fuchsia'], - 'debug_x64_gcc': [ - 'debug_bot_no_remoteexec', 'x64', 'gcc', 'lld', 'no_custom_libcxx'], 'debug_x64_header_includes': [ 'debug_bot', 'x64', 'v8_check_header_includes'], + 'debug_x64_icu4x': [ + 'debug_bot', 'x64', 'v8_enable_ecma402_icu4x'], 'debug_x64_no_shared_cage': [ 'debug_bot', 'x64', 'v8_disable_pointer_compression_shared_cage'], 'debug_x64_minimal_symbols': [ @@ -759,7 +752,7 @@ 'debug_x64_perfetto': [ 'debug_bot', 'x64', 'perfetto'], 'debug_x64_no_metagen': [ - 'debug_bot', 'x64', 'v8_disable_metagen_instance_types'], + 'debug_bot', 'x64', 'v8_disable_metagen'], 'debug_x64_no_sandbox': [ 'debug_bot', 'x64', 'no_sandbox'], 'debug_x64_sandbox_hardware_support': [ @@ -836,7 +829,7 @@ # Torque compare test 'torque_compare': [ - 'release_bot', 'verify_torque'], + 'release_bot', 'verify_torque', 'v8_disable_metagen'], # PGO 'builtins_profiling_x86': ['builtins_profiling', 'x86'], @@ -928,12 +921,6 @@ 'v8_optimized_debug', 'v8_enable_google_benchmark'], }, - 'debug_bot_no_remoteexec': { - 'mixins': [ - 'debug', 'shared', 'no_remoteexec', 'v8_enable_slow_dchecks', - 'v8_optimized_debug'], - }, - 'debug_trybot': { 'mixins': ['debug_bot', 'minimal_symbols'], }, @@ -972,10 +959,6 @@ 'target_environment="simulator" use_blink=true', }, - 'lld': { - 'gn_args': 'use_lld=true', - }, - 'lsan': { 'mixins': ['v8_enable_test_features'], 'gn_args': 'is_lsan=true', @@ -987,20 +970,12 @@ 'msan': { 'mixins': ['v8_enable_test_features'], - 'gn_args': 'is_msan=true msan_track_origins=2 instrumented_libraries_release="noble"', + 'gn_args': 'is_msan=true msan_track_origins=2 instrumented_libraries_release="resolute"', }, 'msan_no_origins': { 'mixins': ['v8_enable_test_features'], - 'gn_args': 'is_msan=true msan_track_origins=0 instrumented_libraries_release="noble"', - }, - - 'no_custom_libcxx': { - 'gn_args': 'use_custom_libcxx=false', - }, - - 'no_remoteexec': { - 'gn_args': 'use_remoteexec=false', + 'gn_args': 'is_msan=true msan_track_origins=0 instrumented_libraries_release="resolute"', }, 'no_sandbox': { @@ -1035,10 +1010,6 @@ 'mixins': ['release', 'static', 'remoteexec', 'v8_enable_google_benchmark'], }, - 'release_bot_no_remoteexec': { - 'mixins': ['release', 'static', 'no_remoteexec'], - }, - 'release_bot_remoteexec': { 'mixins': ['release', 'static', 'remoteexec'], }, @@ -1140,6 +1111,10 @@ 'gn_args': 'v8_enable_drumbrake=true', }, + 'v8_enable_ecma402_icu4x': { + 'gn_args': 'v8_enable_ecma402_icu4x=true', + }, + 'v8_enable_fuzzilli': { 'gn_args': 'v8_fuzzilli=true', }, @@ -1180,8 +1155,8 @@ 'gn_args': 'v8_dict_property_const_tracking=true', }, - 'v8_disable_metagen_instance_types': { - 'gn_args': 'v8_use_metagen_instance_types=false', + 'v8_disable_metagen': { + 'gn_args': 'v8_use_metagen=false', }, 'v8_disable_pointer_compression': { 'gn_args': 'v8_enable_pointer_compression=false', diff --git a/deps/v8/infra/testing/builders.pyl b/deps/v8/infra/testing/builders.pyl index cbc84e4984cb..b5ea604c9682 100644 --- a/deps/v8/infra/testing/builders.pyl +++ b/deps/v8/infra/testing/builders.pyl @@ -520,20 +520,13 @@ }, ], }, - 'v8_linux64_gcc_rel': { - 'swarming_dimensions' : { - 'os': 'Ubuntu-20.04', - }, - 'tests': [ - {'name': 'v8testing'}, - ], - }, - 'v8_linux64_jammy_gcc_rel': { - 'swarming_dimensions' : { + 'v8_linux64_icu4x_dbg': { + 'swarming_dimensions': { 'os': 'Ubuntu-22.04', }, 'tests': [ - {'name': 'v8testing'}, + {'name': 'intl', 'variant': 'ecma402_icu4x_plural_rules'}, + {'name': 'test262', 'variant': 'ecma402_icu4x_plural_rules', 'shards': 4}, ], }, 'v8_linux64_lower_limits_rel': { @@ -1177,6 +1170,15 @@ ### luci.v8.ci ############################################################################## # Main. + 'Linux64 - icu4x - debug': { + 'swarming_dimensions': { + 'os': 'Ubuntu-22.04', + }, + 'tests': [ + {'name': 'intl', 'variant': 'ecma402_icu4x_plural_rules'}, + {'name': 'test262', 'variant': 'ecma402_icu4x_plural_rules', 'shards': 4}, + ], + }, 'V8 Linux': { 'swarming_dimensions': { 'cpu': 'x86-64-avx2', @@ -1639,22 +1641,6 @@ }, ], }, - 'V8 Linux64 gcc': { - 'swarming_dimensions' : { - 'os': 'Ubuntu-20.04', - }, - 'tests': [ - {'name': 'v8testing'}, - ], - }, - 'V8 Linux64 - jammy - gcc': { - 'swarming_dimensions' : { - 'os': 'Ubuntu-22.04', - }, - 'tests': [ - {'name': 'v8testing'}, - ], - }, 'V8 Linux64 - gc stress': { 'swarming_dimensions': { 'cpu': 'x86-64-avx2', diff --git a/deps/v8/src/DEPS b/deps/v8/src/DEPS index 54108a8f1afa..41a8a71d16a4 100644 --- a/deps/v8/src/DEPS +++ b/deps/v8/src/DEPS @@ -14,6 +14,9 @@ include_rules = [ "+src/compiler/wasm-compiler-definitions.h", "+src/compiler/wasm-compiler.h", "-src/flags/flags-impl.h", + # Checked-in generated files. Each is included from one hand-written + # header, listed below (see src/gen/README.md). + "-src/gen", "-src/heap", "+src/heap/memory-chunk-constants.h", "+src/heap/base-page.h", @@ -94,6 +97,29 @@ include_rules = [ ] specific_include_rules = { + # The hand-written headers that include the checked-in generated files + # under src/gen/, one per file (see src/gen/README.md). + "static-roots\.h": [ + "+src/gen/intl-wasm/static-roots.h", + "+src/gen/intl-nowasm/static-roots.h", + "+src/gen/nointl-wasm/static-roots.h", + "+src/gen/nointl-nowasm/static-roots.h", + ], + "bytecodes-builtins-list\.h": [ + "+src/gen/intl-wasm/bytecodes-builtins-list.h", + ], + "builtins-definitions\.h": [ + "+src/gen/intl-wasm/builtin-definitions.h", + ], + "interface-descriptors\.h": [ + "+src/gen/intl-wasm/interface-descriptors.inc", + ], + "factory-base\.h": [ + "+src/gen/intl-wasm/class-forward-declarations.h", + ], + "instance-types-gen\.h": [ + "+src/gen/intl-wasm/instance-types.h", + ], "d8\.cc": [ "+include/libplatform/libplatform.h", "+include/libplatform/v8-tracing.h", diff --git a/deps/v8/src/api/api-arguments-inl.h b/deps/v8/src/api/api-arguments-inl.h index dbfae8ec545a..bc44e0ae5ac9 100644 --- a/deps/v8/src/api/api-arguments-inl.h +++ b/deps/v8/src/api/api-arguments-inl.h @@ -558,7 +558,7 @@ PropertyCallbackArguments::CallPropertyEnumerator( ExceptionContext::kNamedEnumerator); f(callback_info); DirectHandle<JSAny> result = GetReturnValue<JSAny>(); - DCHECK(IsUndefined(*result) || IsJSObject(*result)); + DCHECK(IsUndefined(*result) || IsJSArray(*result)); return Cast<JSObjectOrUndefined>(result); } diff --git a/deps/v8/src/api/api-natives.cc b/deps/v8/src/api/api-natives.cc index 68ba61b7cbc2..f3a01025a41f 100644 --- a/deps/v8/src/api/api-natives.cc +++ b/deps/v8/src/api/api-natives.cc @@ -639,8 +639,7 @@ Handle<JSFunction> ApiNatives::CreateApiFunction( DCHECK(result->has_prototype_slot()); if (obj->read_only_prototype()) { - result->set_map(isolate, - *isolate->sloppy_function_with_readonly_prototype_map()); + result->set_map(isolate, *isolate->function_with_readonly_prototype_map()); } if (IsTheHole(*prototype)) { @@ -691,7 +690,18 @@ Handle<JSFunction> ApiNatives::CreateApiFunction( map->set_indexed_interceptor(info); if (v8_flags.fast_api_iterable_to_list && info->has_indexed_iterable_to_list()) { - map->set_supports_fast_iterable_to_list(true); + bool is_valid = + !obj->needs_access_check() && + IsObjectTemplateInfo(obj->GetPrototypeTemplate()) && + IsArrayList(Cast<ObjectTemplateInfo>(obj->GetPrototypeTemplate()) + ->property_list()); + DCHECK(!obj->needs_access_check()); + DCHECK(IsObjectTemplateInfo(obj->GetPrototypeTemplate())); + DCHECK(IsArrayList(Cast<ObjectTemplateInfo>(obj->GetPrototypeTemplate()) + ->property_list())); + if (is_valid) { + map->set_supports_fast_iterable_to_list(true); + } } } else { map->set_indexed_interceptor( @@ -733,12 +743,6 @@ Handle<JSFunction> ApiNatives::CreateApiFunction( if (immutable_proto) map->set_is_immutable_proto(true); JSFunction::SetInitialMap(isolate, result, map, Cast<JSObject>(prototype)); - if (map->supports_fast_iterable_to_list()) { - // %CheckFastIterableToListPrototype() relies on the constness tracking - // which requires the prototype to be in fast mode. - DirectHandle<Map> proto_map(Cast<JSObject>(prototype)->map(), isolate); - Map::SetShouldBeFastPrototypeMap(proto_map, true, isolate); - } return result; } diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc index 568671193c5a..5e9bbb9653e6 100644 --- a/deps/v8/src/api/api.cc +++ b/deps/v8/src/api/api.cc @@ -46,6 +46,7 @@ #include "src/base/platform/time.h" #include "src/base/strong-alias.h" #include "src/base/template-utils.h" +#include "src/base/unique-array.h" #include "src/base/utils/random-number-generator.h" #include "src/base/vector.h" #include "src/builtins/accessors.h" @@ -1035,6 +1036,17 @@ void Context::SetEmbedderDataV2(int index, v8::Local<Data> value) { *Utils::OpenDirectHandle(*GetEmbedderDataV2(index))); } +void Context::SetEmbedderDataV3(int index, v8::Local<Data> value) { + const char* location = "v8::Context::SetEmbedderDataV3()"; + i::DirectHandle<i::EmbedderDataArray> data = + EmbedderDataFor(this, index, false, location); + if (data.is_null()) return; + auto val = Utils::OpenDirectHandle(*value); + i::EmbedderDataSlot::store_tagged(*data, index, *val); + DCHECK_EQ(*Utils::OpenDirectHandle(*value), + *Utils::OpenDirectHandle(*GetEmbedderDataV2(index))); +} + void* Context::GetAlignedPointerFromEmbedderData(int index, EmbedderDataTypeTag tag) { const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; @@ -1078,6 +1090,19 @@ void Context::SetAlignedPointerInEmbedderData(int index, void* value, DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index, tag)); } +void Context::SetAlignedPointerInEmbedderDataV2(int index, void* value, + EmbedderDataTypeTag tag) { + const char* location = "v8::Context::SetAlignedPointerInEmbedderDataV2()"; + i::Isolate* i_isolate = i::Isolate::Current(); + i::DirectHandle<i::EmbedderDataArray> data = + EmbedderDataFor(this, index, false, location); + if (data.is_null()) return; + bool ok = i::EmbedderDataSlot::store_aligned_pointer( + i_isolate, data, index, value, ToExternalPointerTag(tag)); + Utils::ApiCheck(ok, location, "Pointer is not aligned"); + DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index, tag)); +} + void Context::SetAlignedPointerInEmbedderDataInternal(int index, void* value, CppHeapPointerTag tag) { const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; @@ -1089,6 +1114,18 @@ void Context::SetAlignedPointerInEmbedderDataInternal(int index, void* value, Utils::ApiCheck(ok, location, "Pointer is not aligned"); } +void Context::SetAlignedPointerInEmbedderDataInternalV2(int index, void* value, + CppHeapPointerTag tag) { + const char* location = "v8::Context::SetAlignedPointerInEmbedderDataV2()"; + i::Isolate* i_isolate = i::Isolate::Current(); + i::DirectHandle<i::EmbedderDataArray> data = + EmbedderDataFor(this, index, false, location); + if (data.is_null()) return; + bool ok = i::EmbedderDataSlot(*data, index) + .store_aligned_pointer(i_isolate, *data, value, tag); + Utils::ApiCheck(ok, location, "Pointer is not aligned"); +} + // --- T e m p l a t e --- void Template::Set(v8::Local<Name> name, v8::Local<Data> value, @@ -1397,7 +1434,7 @@ template <typename Getter, typename Setter> i::DirectHandle<i::AccessorInfo> MakeAccessorInfo(i::Isolate* i_isolate, v8::Local<Name> name, Getter getter, Setter setter, - v8::Local<Value> data, + v8::Local<Data> data, bool replace_on_access) { i::DirectHandle<i::AccessorInfo> obj = i_isolate->factory()->NewAccessorInfo(); @@ -1590,7 +1627,7 @@ void Template::SetNativeDataProperty(v8::Local<Name> name, void Template::SetLazyDataProperty(v8::Local<Name> name, AccessorNameGetterCallback getter, - v8::Local<Value> data, + v8::Local<Data> data, PropertyAttribute attribute, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { @@ -1719,14 +1756,11 @@ void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback, auto cons = EnsureConstructor(i_isolate, this); EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallback"); - i::DirectHandle<i::Struct> struct_info = i_isolate->factory()->NewStruct( - i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); - auto info = i::Cast<i::AccessCheckInfo>(struct_info); + i::DirectHandle<i::AccessCheckInfo> info = + i_isolate->factory()->NewAccessCheckInfo(); SET_FIELD_WRAPPED(i_isolate, info, set_callback, callback, internal::kApiAccessCheckCallbackTag); - info->set_named_interceptor(i::Smi::zero()); - info->set_indexed_interceptor(i::Smi::zero()); if (data.IsEmpty()) { data = v8::Undefined(reinterpret_cast<v8::Isolate*>(i_isolate)); @@ -1749,9 +1783,8 @@ void ObjectTemplate::SetAccessCheckCallbackAndHandler( EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallbackWithHandler"); - i::DirectHandle<i::Struct> struct_info = i_isolate->factory()->NewStruct( - i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld); - auto info = i::Cast<i::AccessCheckInfo>(struct_info); + i::DirectHandle<i::AccessCheckInfo> info = + i_isolate->factory()->NewAccessCheckInfo(); SET_FIELD_WRAPPED(i_isolate, info, set_callback, callback, internal::kApiAccessCheckCallbackTag); @@ -2301,7 +2334,7 @@ Module::Status Module::GetStatus() const { // TODO(syg): Expose kEvaluatingAsync in API as well. case i::Module::kEvaluated: return kEvaluated; - case i::Module::kErrored: + case i::Module::kEvaluatedError: return kErrored; } UNREACHABLE(); @@ -3072,12 +3105,26 @@ i::Tagged<i::Object> ToObject(void* object) { return i::Tagged<i::Object>(reinterpret_cast<i::Address>(object)); } +// A v8::TryCatch must propagate (not swallow or clear) a termination exception +// when there is an outer v8::TryCatch handler (next_ != nullptr) or when +// execution is still nested inside an outer V8 API call (!CallDepthIsZero()). +// It must also propagate termination when should_check_side_effects() is +// active: v8::debug::SideEffectCheckScope may span multiple sequential +// top-level V8 API calls where CallDepthIsZero() is true between calls, and the +// side-effect termination exception must remain pending until +// Debug::StopSideEffectCheckMode() converts it into an EvalError. +bool MustPropagateTerminationException(i::Isolate* isolate) { + return !isolate->thread_local_top()->CallDepthIsZero() || + isolate->should_check_side_effects(); +} + } // namespace v8::TryCatch::~TryCatch() { if (HasCaught()) { - if (rethrow() || (V8_UNLIKELY(HasTerminated()) && - !i_isolate_->thread_local_top()->CallDepthIsZero())) { + if (rethrow() || + (V8_UNLIKELY(HasTerminated()) && + (next_ != nullptr || MustPropagateTerminationException(i_isolate_)))) { if (capture_message()) { // If an exception was caught and rethrow_ is indicated, the saved // message, script, and location need to be restored to Isolate TLS @@ -3158,7 +3205,7 @@ v8::Local<v8::Message> v8::TryCatch::Message() const { void v8::TryCatch::Reset() { if (rethrow()) return; if (V8_UNLIKELY(i_isolate_->is_execution_terminating()) && - !i_isolate_->thread_local_top()->CallDepthIsZero()) { + MustPropagateTerminationException(i_isolate_)) { return; } i_isolate_->clear_internal_exception(); @@ -3926,6 +3973,10 @@ bool Value::IsArray() const { return IsJSArray(*Utils::OpenDirectHandle(this)); } +bool Value::IsArrayBufferBase() const { + return IsJSArrayBuffer(*Utils::OpenDirectHandle(this)); +} + bool Value::IsArrayBuffer() const { auto obj = *Utils::OpenDirectHandle(this); if (!IsJSArrayBuffer(obj)) return false; @@ -4176,7 +4227,9 @@ MaybeLocal<Int32> Value::ToInt32(Local<Context> context) const { MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const { auto obj = Utils::OpenDirectHandle(this); - if (i::IsSmi(*obj)) return ToApiHandle<Uint32>(obj); + if (i::IsSmi(*obj) && i::Smi::ToInt(*obj) >= 0) { + return ToApiHandle<Uint32>(obj); + } PrepareForExecutionScope api_scope{context, RCCId::kAPI_Object_ToUint32}; i::Isolate* i_isolate = api_scope.i_isolate(); return api_scope.EscapeMaybe( @@ -4393,38 +4446,24 @@ void v8::BackingStore::EmptyDeleter(void* data, size_t length, DCHECK_NULL(deleter_data); } -std::shared_ptr<v8::BackingStore> v8::ArrayBuffer::GetBackingStore() { +std::shared_ptr<v8::BackingStore> v8::ArrayBufferBase::GetBackingStore() { auto self = Utils::OpenDirectHandle(this); std::shared_ptr<i::BackingStore> backing_store = self->GetBackingStore(); if (!backing_store) { - backing_store = i::BackingStore::EmptyBackingStore(i::SharedFlag{false}); + backing_store = i::BackingStore::EmptyBackingStore(self->is_shared()); } std::shared_ptr<i::BackingStoreBase> bs_base = backing_store; return std::static_pointer_cast<v8::BackingStore>(bs_base); } -void* v8::ArrayBuffer::Data() const { +void* v8::ArrayBufferBase::Data() const { return Utils::OpenDirectHandle(this)->backing_store(); } -bool v8::ArrayBuffer::IsResizableByUserJavaScript() const { +bool v8::ArrayBufferBase::IsResizableByUserJavaScript() const { return Utils::OpenDirectHandle(this)->is_resizable_by_js().value(); } -std::shared_ptr<v8::BackingStore> v8::SharedArrayBuffer::GetBackingStore() { - auto self = Utils::OpenDirectHandle(this); - std::shared_ptr<i::BackingStore> backing_store = self->GetBackingStore(); - if (!backing_store) { - backing_store = i::BackingStore::EmptyBackingStore(i::SharedFlag{true}); - } - std::shared_ptr<i::BackingStoreBase> bs_base = backing_store; - return std::static_pointer_cast<v8::BackingStore>(bs_base); -} - -void* v8::SharedArrayBuffer::Data() const { - return Utils::OpenDirectHandle(this)->backing_store(); -} - template <bool is_shared> static size_t CopyArrayBufferBytesImpl(const void* source_buffer, size_t source_start, @@ -4450,17 +4489,10 @@ static size_t CopyArrayBufferBytesImpl(const void* source_buffer, return bytes_to_copy; } -size_t v8::SharedArrayBuffer::CopyArrayBufferBytes( - size_t source_start, size_t bytes_to_copy, Local<SharedArrayBuffer> target, - size_t target_start) const { - i::DisallowGarbageCollection no_gc; - auto self = Utils::OpenDirectHandle(this); - auto that = Utils::OpenDirectHandle(*target); - DCHECK(!that->is_immutable()); - return CopyArrayBufferBytesImpl<true>(self->backing_store(), source_start, - self->GetByteLength(), - that->backing_store(), target_start, - that->GetByteLength(), bytes_to_copy); +void v8::ArrayBufferBase::CheckCast(Value* that) { + Utils::ApiCheck(IsJSArrayBuffer(*Utils::OpenDirectHandle(that)), + "v8::ArrayBufferBase::Cast()", + "Value is not an ArrayBuffer or SharedArrayBuffer"); } void v8::ArrayBuffer::CheckCast(Value* that) { @@ -4977,6 +5009,18 @@ MaybeLocal<Value> v8::Object::Get(Local<Context> context, uint32_t index) { i::JSReceiver::GetElement(i_isolate, self, index)); } +MaybeLocal<Value> v8::Object::TryGetWithNoSideEffects(Local<Context> context, + Local<Name> key) { + auto i_isolate = i::Isolate::Current(); + EnterV8NoScriptScope<InternalEscapableScope> api_scope{ + i_isolate, context, RCCId::kAPI_Object_TryGetWithNoSideEffects}; + auto self = Utils::OpenDirectHandle(this); + auto key_obj = Utils::OpenDirectHandle(*key); + i::PropertyKey lookup_key(i_isolate, key_obj); + i::LookupIterator it(i_isolate, self, lookup_key, self); + return api_scope.EscapeMaybe(i::JSReceiver::TryGetDataProperty(&it)); +} + MaybeLocal<Value> v8::Object::GetPrivate(Local<Context> context, Local<Private> key) { return Get(context, key.UnsafeAs<Value>()); @@ -5318,7 +5362,7 @@ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter, Maybe<bool> Object::SetNativeDataProperty( v8::Local<v8::Context> context, v8::Local<Name> name, AccessorNameGetterCallback getter, AccessorNameSetterCallbackV2 setter, - v8::Local<Value> data, PropertyAttribute attributes, + v8::Local<Data> data, PropertyAttribute attributes, SideEffectType getter_side_effect_type, SideEffectType setter_side_effect_type) { return ObjectSetAccessor(context, this, name, getter, setter, data, @@ -6706,7 +6750,7 @@ v8::V8::SandboxMode v8::V8::GetSandboxMode() { Utils::ApiCheck(sandbox->is_initialized(), "v8::V8::GetSandboxMode", "The sandbox must be initialized first"); const bool partial = sandbox->is_partially_reserved(); - const bool smi_inaccessible = sandbox->smi_address_range_is_inaccessible(); + const bool smi_inaccessible = sandbox->has_zero_segment(); if (!partial && smi_inaccessible) { return SandboxMode::kSecure; @@ -7145,6 +7189,7 @@ class ObjectVisitorDeepFreezer : i::ObjectVisitor { } i::DisallowGarbageCollection no_gc; + if (i::IsInaccessible(obj)) return true; i::InstanceType obj_type = obj->map()->instance_type(); // Skip common types that can't contain items to freeze. @@ -7679,7 +7724,7 @@ inline int StringLength(const uint16_t* string) { V8_WARN_UNUSED_RESULT inline i::MaybeHandle<i::String> NewString(i::Factory* factory, NewStringType type, - base::Vector<const char> string) { + std::string_view string) { if (type == NewStringType::kInternalized) { return factory->InternalizeUtf8String(string); } @@ -7727,7 +7772,7 @@ static_assert(v8::String::kMaxLength == i::String::kMaxLength); if (length < 0) length = StringLength(data); \ i::DirectHandle<i::String> handle_result = \ NewString(i_isolate->factory(), type, \ - base::Vector<const Char>(data, length)) \ + {data, static_cast<size_t>(length)}) \ .ToHandleChecked(); \ result = Utils::ToLocal(handle_result); \ } @@ -7742,7 +7787,7 @@ Local<String> String::NewFromUtf8Literal(Isolate* v8_isolate, RCCId::kAPI_String_NewFromUtf8Literal); i::DirectHandle<i::String> handle_result = NewString(i_isolate->factory(), type, - base::Vector<const char>(literal, length)) + {literal, static_cast<size_t>(length)}) .ToHandleChecked(); return Utils::ToLocal(handle_result); } @@ -8161,7 +8206,7 @@ v8::Local<v8::String> v8::Date::ToISOString() const { i::ToDateStringMode::kISODateAndTime); i::DirectHandle<i::String> str = i_isolate->factory() - ->NewStringFromUtf8(base::VectorOf(buffer)) + ->NewStringFromUtf8({buffer.data(), buffer.size()}) .ToHandleChecked(); return Utils::ToLocal(str); } @@ -8175,7 +8220,7 @@ v8::Local<v8::String> v8::Date::ToUTCString() const { i::ToDateStringMode::kUTCDateAndTime); i::DirectHandle<i::String> str = i_isolate->factory() - ->NewStringFromUtf8(base::VectorOf(buffer)) + ->NewStringFromUtf8({buffer.data(), buffer.size()}) .ToHandleChecked(); return Utils::ToLocal(str); } @@ -8243,6 +8288,13 @@ v8::RegExp::Flags v8::RegExp::GetFlags() const { MaybeLocal<v8::Object> v8::RegExp::Exec(Local<Context> context, Local<v8::String> subject) { + Local<Value> result; + if (!ExecV2(context, subject).ToLocal(&result)) return {}; + return result.UnsafeAs<Object>(); +} + +MaybeLocal<v8::Value> v8::RegExp::ExecV2(Local<Context> context, + Local<v8::String> subject) { PrepareForExecutionScope api_scope{context, RCCId::kAPI_RegExp_Exec}; i::Isolate* i_isolate = api_scope.i_isolate(); @@ -8259,11 +8311,7 @@ MaybeLocal<v8::Object> v8::RegExp::Exec(Local<Context> context, .ToHandle(&result)) { return {}; } - // RegExp::Exec is documented to return Null on failure, but the return type - // is `MaybeLocal<Object>` which cannot legally hold `Null`, thus the unsafe - // `Utils::Convert<Object>`. - // TODO(jgruber): Fix this. - return api_scope.Escape(Utils::Convert<i::JSAny, Object>(result)); + return api_scope.Escape(ToApiHandle<Value>(result)); } Local<v8::Array> v8::Array::New(Isolate* v8_isolate, int length) { @@ -9007,11 +9055,14 @@ OwnedBuffer CompiledWasmModule::Serialize() { TRACE_EVENT0("v8.wasm", "wasm.SerializeModule"); i::wasm::WasmSerializer wasm_serializer(native_module_.get()); size_t buffer_size = wasm_serializer.GetSerializedNativeModuleSize(); - std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); - if (!wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size})) { + base::UniqueArray<uint8_t> buffer = + base::UniqueArray<uint8_t>::NewForOverwrite(buffer_size); + if (!wasm_serializer.SerializeNativeModule(buffer.as_span())) { return {}; } - return {std::move(buffer), buffer_size}; + START_ALLOW_USE_DEPRECATED() + return {buffer.ReleaseData(), buffer_size}; + END_ALLOW_USE_DEPRECATED() #else UNREACHABLE(); #endif // V8_ENABLE_WEBASSEMBLY @@ -9027,6 +9078,10 @@ std::span<const uint8_t> CompiledWasmModule::GetWireBytesRef() { } Local<ArrayBuffer> v8::WasmMemoryObject::Buffer() { + return GetBuffer().UnsafeAs<ArrayBuffer>(); +} + +Local<ArrayBufferBase> v8::WasmMemoryObject::GetBuffer() { #if V8_ENABLE_WEBASSEMBLY i::DirectHandle<i::WasmMemoryObject> obj = Utils::OpenDirectHandle(this); i::Isolate* i_isolate = i::Isolate::Current(); @@ -9054,12 +9109,11 @@ MaybeLocal<WasmModuleObject> WasmModuleObject::FromCompiledModule( Isolate* v8_isolate, const CompiledWasmModule& compiled_module) { #if V8_ENABLE_WEBASSEMBLY i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); - i::MaybeDirectHandle<i::WasmModuleObject> module_object = + i::DirectHandle<i::WasmModuleObject> module_object = i::wasm::GetWasmEngine()->ImportNativeModule( i_isolate, compiled_module.native_module_, - base::VectorOf(compiled_module.source_url())); - if (module_object.is_null()) return {}; - return Utils::ToLocal(module_object.ToHandleChecked()); + compiled_module.source_url()); + return Utils::ToLocal(module_object); #else UNREACHABLE(); #endif // V8_ENABLE_WEBASSEMBLY @@ -9076,7 +9130,7 @@ MaybeLocal<WasmModuleObject> WasmModuleObject::Compile( #if V8_ENABLE_WEBASSEMBLY i::wasm::CompileTimeImports compile_imports = i::wasm::CompileTimeImportsFromOptions(options); - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(wire_bytes); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(wire_bytes); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); // We don't check for `IsWasmCodegenAllowed` here, because this function is // used for ESM integration, which in terms of security is equivalent to @@ -9088,9 +9142,7 @@ MaybeLocal<WasmModuleObject> WasmModuleObject::Compile( i::wasm::WasmEnabledFeatures::FromIsolate(i_isolate); maybe_compiled = i::wasm::GetWasmEngine()->SyncCompile( i_isolate, enabled_features, std::move(compile_imports), &thrower, - std::move(bytes), - base::Vector<const char>(options.source_url.data(), - options.source_url.size())); + std::move(bytes), options.source_url); } CHECK_EQ(maybe_compiled.is_null(), i_isolate->has_exception()); if (maybe_compiled.is_null()) return {}; @@ -9182,27 +9234,37 @@ v8::ArrayBuffer::Allocator* v8::ArrayBuffer::Allocator::NewDefaultAllocator( #endif // defined(V8_COMPRESS_POINTERS) && // !defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE) -bool v8::ArrayBuffer::IsDetachable() const { +bool v8::ArrayBufferBase::IsShared() const { + return Utils::OpenDirectHandle(this)->is_shared().value(); +} + +bool v8::ArrayBufferBase::IsDetachable() const { return Utils::OpenDirectHandle(this)->is_detachable(); } -bool v8::ArrayBuffer::WasDetached() const { +bool v8::ArrayBufferBase::WasDetached() const { return Utils::OpenDirectHandle(this)->was_detached(); } -bool v8::ArrayBuffer::IsImmutable() const { +bool v8::ArrayBufferBase::IsImmutable() const { return Utils::OpenDirectHandle(this)->is_immutable(); } -size_t v8::ArrayBuffer::CopyArrayBufferBytes(size_t source_start, - size_t bytes_to_copy, - Local<ArrayBuffer> target, - size_t target_start) const { +size_t v8::ArrayBufferBase::CopyArrayBufferBytes(size_t source_start, + size_t bytes_to_copy, + Local<ArrayBufferBase> target, + size_t target_start) const { i::DisallowGarbageCollection no_gc; auto self = Utils::OpenDirectHandle(this); auto that = Utils::OpenDirectHandle(*target); if (self->was_detached()) return 0; if (that->was_detached() || that->is_immutable()) return 0; + if (self->is_shared() || that->is_shared()) { + return CopyArrayBufferBytesImpl<true>(self->backing_store(), source_start, + self->GetByteLength(), + that->backing_store(), target_start, + that->GetByteLength(), bytes_to_copy); + } return CopyArrayBufferBytesImpl<false>(self->backing_store(), source_start, self->GetByteLength(), that->backing_store(), target_start, @@ -9254,11 +9316,11 @@ void v8::ArrayBuffer::SetDetachKey(v8::Local<v8::Value> key) { i::JSArrayBuffer::SetDetachKey(obj, i_key, i_isolate); } -size_t v8::ArrayBuffer::ByteLength() const { +size_t v8::ArrayBufferBase::ByteLength() const { return Utils::OpenDirectHandle(this)->GetByteLength(); } -size_t v8::ArrayBuffer::MaxByteLength() const { +size_t v8::ArrayBufferBase::MaxByteLength() const { return Utils::OpenDirectHandle(this)->max_byte_length(); } @@ -9292,7 +9354,7 @@ MaybeLocal<ArrayBuffer> v8::ArrayBuffer::MaybeNew( i::DirectHandle<i::JSArrayBuffer> array_buffer; if (!result.ToHandle(&array_buffer)) return {}; - return Utils::ToLocal(array_buffer); + return Utils::ToLocalUnshared(array_buffer); } Local<ArrayBuffer> v8::ArrayBuffer::New( @@ -9310,7 +9372,7 @@ Local<ArrayBuffer> v8::ArrayBuffer::New( i::V8::FatalProcessOutOfMemory(i_isolate, "v8::ArrayBuffer::New"); } - return Utils::ToLocal(array_buffer); + return Utils::ToLocalUnshared(array_buffer); } Local<ArrayBuffer> v8::ArrayBuffer::New( @@ -9332,7 +9394,7 @@ Local<ArrayBuffer> v8::ArrayBuffer::New( ->is_immutable()) { obj->MakeImmutable(i_isolate); } - return Utils::ToLocal(obj); + return Utils::ToLocalUnshared(obj); } std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore( @@ -9376,6 +9438,14 @@ VirtualAddressSpace* v8::IsolateGroup::GetSandboxAddressSpace() { "The sandbox must be initialized first"); return sandbox->address_space(); } + +void v8::IsolateGroup::SetInSandboxAllocator( + std::shared_ptr<Allocator> allocator) { + Utils::ApiCheck(isolate_group_->GetIsolateCount() == 0, + "v8::IsolateGroup::SetInSandboxAllocator", + "The allocator must be set before creating an Isolate"); + isolate_group_->sandbox()->set_in_sandbox_allocator(std::move(allocator)); +} #endif std::unique_ptr<v8::BackingStore> v8::ArrayBuffer::NewBackingStore( @@ -9431,6 +9501,10 @@ std::unique_ptr<BackingStore> v8::ArrayBuffer::NewResizableBackingStore( } Local<ArrayBuffer> v8::ArrayBufferView::Buffer() { + return GetBuffer().UnsafeAs<ArrayBuffer>(); +} + +Local<ArrayBufferBase> v8::ArrayBufferView::GetBuffer() { auto obj = Utils::OpenDirectHandle(this); i::Isolate* i_isolate = i::Isolate::Current(); if (i::IsJSDataView(*obj)) { @@ -9550,51 +9624,31 @@ static_assert(v8::TypedArray::kMaxByteLength == i::JSTypedArray::kMaxByteLength, "v8::TypedArray::kMaxByteLength must match " "i::JSTypedArray::kMaxByteLength"); -#define TYPED_ARRAY_NEW(Type, type, TYPE, ctype) \ - Local<Type##Array> Type##Array::New(Local<ArrayBuffer> array_buffer, \ - size_t byte_offset, size_t length) { \ - i::Isolate* i_isolate = i::Isolate::Current(); \ - ApiRuntimeCallStatsScope rcs_scope(i_isolate, \ - RCCId::kAPI_##Type##Array_New); \ - EnterV8NoScriptNoExceptionScope api_scope(i_isolate); \ - if (!Utils::ApiCheck(length <= kMaxLength, \ - "v8::" #Type \ - "Array::New(Local<ArrayBuffer>, size_t, size_t)", \ - "length exceeds max allowed value")) { \ - return {}; \ - } \ - auto buffer = Utils::OpenDirectHandle(*array_buffer); \ - i::DirectHandle<i::JSTypedArray> obj = \ - i_isolate->factory()->NewJSTypedArray(i::kExternal##Type##Array, \ - buffer, byte_offset, length); \ - return Utils::ToLocal##Type##Array(obj); \ - } \ - Local<Type##Array> Type##Array::New( \ - Local<SharedArrayBuffer> shared_array_buffer, size_t byte_offset, \ - size_t length) { \ - i::Isolate* i_isolate = i::Isolate::Current(); \ - ApiRuntimeCallStatsScope rcs_scope(i_isolate, \ - RCCId::kAPI_##Type##Array_New); \ - EnterV8NoScriptNoExceptionScope api_scope(i_isolate); \ - if (!Utils::ApiCheck( \ - length <= kMaxLength, \ - "v8::" #Type \ - "Array::New(Local<SharedArrayBuffer>, size_t, size_t)", \ - "length exceeds max allowed value")) { \ - return {}; \ - } \ - auto buffer = Utils::OpenDirectHandle(*shared_array_buffer); \ - i::DirectHandle<i::JSTypedArray> obj = \ - i_isolate->factory()->NewJSTypedArray(i::kExternal##Type##Array, \ - buffer, byte_offset, length); \ - return Utils::ToLocal##Type##Array(obj); \ +#define TYPED_ARRAY_NEW(Type, type, TYPE, ctype) \ + Local<Type##Array> Type##Array::New(Local<ArrayBufferBase> array_buffer, \ + size_t byte_offset, size_t length) { \ + i::Isolate* i_isolate = i::Isolate::Current(); \ + ApiRuntimeCallStatsScope rcs_scope(i_isolate, \ + RCCId::kAPI_##Type##Array_New); \ + EnterV8NoScriptNoExceptionScope api_scope(i_isolate); \ + if (!Utils::ApiCheck(length <= kMaxLength, \ + "v8::" #Type \ + "Array::New(Local<ArrayBufferBase>, size_t, size_t)", \ + "length exceeds max allowed value")) { \ + return {}; \ + } \ + auto buffer = Utils::OpenDirectHandle(*array_buffer); \ + i::DirectHandle<i::JSTypedArray> obj = \ + i_isolate->factory()->NewJSTypedArray(i::kExternal##Type##Array, \ + buffer, byte_offset, length); \ + return Utils::ToLocal##Type##Array(obj); \ } TYPED_ARRAYS_BASE(TYPED_ARRAY_NEW) #undef TYPED_ARRAY_NEW // TODO(v8:11111): Support creating length tracking DataViews via the API. -Local<DataView> DataView::New(Local<ArrayBuffer> array_buffer, +Local<DataView> DataView::New(Local<ArrayBufferBase> array_buffer, size_t byte_offset, size_t byte_length) { auto buffer = Utils::OpenDirectHandle(*array_buffer); i::Isolate* i_isolate = i::Isolate::Current(); @@ -9606,26 +9660,6 @@ Local<DataView> DataView::New(Local<ArrayBuffer> array_buffer, return Utils::ToLocal(obj); } -Local<DataView> DataView::New(Local<SharedArrayBuffer> shared_array_buffer, - size_t byte_offset, size_t byte_length) { - auto buffer = Utils::OpenDirectHandle(*shared_array_buffer); - i::Isolate* i_isolate = i::Isolate::Current(); - ApiRuntimeCallStatsScope rcs_scope(i_isolate, RCCId::kAPI_DataView_New); - EnterV8NoScriptNoExceptionScope api_scope(i_isolate); - auto obj = i::Cast<i::JSDataView>( - i_isolate->factory()->NewJSDataViewOrRabGsabDataView(buffer, byte_offset, - byte_length)); - return Utils::ToLocal(obj); -} - -size_t v8::SharedArrayBuffer::ByteLength() const { - return Utils::OpenDirectHandle(this)->GetByteLength(); -} - -size_t v8::SharedArrayBuffer::MaxByteLength() const { - return Utils::OpenDirectHandle(this)->max_byte_length(); -} - Local<SharedArrayBuffer> v8::SharedArrayBuffer::New( Isolate* v8_isolate, size_t byte_length, BackingStoreInitializationMode initialization_mode) { @@ -11048,11 +11082,19 @@ CALLBACK_SETTER(FatalErrorHandler, FatalErrorCallback, exception_behavior) CALLBACK_SETTER(ModifyCodeGenerationFromStringsCallback, ModifyCodeGenerationFromStringsCallback2, modify_code_gen_callback) +CALLBACK_SETTER(DynamicScriptCompiledFromEmbedderCallback, + DynamicScriptCompiledFromEmbedderCallback, + dynamic_script_callback) CALLBACK_SETTER(AllowWasmCodeGenerationCallback, AllowWasmCodeGenerationCallback, allow_wasm_code_gen_callback) -CALLBACK_SETTER(WasmModuleCallback, ExtensionCallback, wasm_module_callback) -CALLBACK_SETTER(WasmInstanceCallback, ExtensionCallback, wasm_instance_callback) +CALLBACK_SETTER(WasmModuleCallback, WasmModuleCallback, wasm_module_callback) +CALLBACK_SETTER(WasmModuleCallback, ExtensionCallback, + deprecated_wasm_module_callback) +CALLBACK_SETTER(WasmInstanceCallback, WasmInstanceCallback, + wasm_instance_callback) +CALLBACK_SETTER(WasmInstanceCallback, ExtensionCallback, + deprecated_wasm_instance_callback) CALLBACK_SETTER(WasmStreamingCallback, WasmStreamingCallback, wasm_streaming_callback) @@ -11697,6 +11739,11 @@ EmbedderStateTag CpuProfile::GetSampleEmbedderState(int index) const { return profile->sample(index).embedder_state_tag; } +void* CpuProfile::GetSampleContext(int index) const { + const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this); + return profile->sample(index).sample_context; +} + int64_t CpuProfile::GetStartTime() const { const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this); return profile->start_time().since_origin().InMicroseconds(); @@ -11733,15 +11780,15 @@ CpuProfiler* CpuProfiler::New(Isolate* v8_isolate, reinterpret_cast<i::Isolate*>(v8_isolate), naming_mode, logging_mode)); } -CpuProfilingOptions::CpuProfilingOptions(CpuProfilingMode mode, - unsigned max_samples, - int sampling_interval_us, - MaybeLocal<Context> filter_context, - CpuProfileSource profile_source) +CpuProfilingOptions::CpuProfilingOptions( + CpuProfilingMode mode, unsigned max_samples, int sampling_interval_us, + MaybeLocal<Context> filter_context, CpuProfileSource profile_source, + SampleContextExtractor sample_context_extractor) : mode_(mode), max_samples_(max_samples), sampling_interval_us_(sampling_interval_us), - profile_source_(profile_source) { + profile_source_(profile_source), + sample_context_extractor_(sample_context_extractor) { if (!filter_context.IsEmpty()) { Local<Context> local_filter_context = filter_context.ToLocalChecked(); filter_context_.Reset(v8::Isolate::GetCurrent(), local_filter_context); @@ -12116,11 +12163,11 @@ SnapshotObjectId HeapProfiler::GetHeapStats(OutputStream* stream, return heap_profiler->PushHeapObjectsStats(stream, timestamp_us); } -bool HeapProfiler::StartSamplingHeapProfiler(uint64_t sample_interval, - int stack_depth, - SamplingFlags flags) { +bool HeapProfiler::StartSamplingHeapProfiler( + uint64_t sample_interval, int stack_depth, SamplingFlags flags, + SampleContextExtractor sample_context_extractor) { return reinterpret_cast<i::HeapProfiler*>(this)->StartSamplingHeapProfiler( - sample_interval, stack_depth, flags); + sample_interval, stack_depth, flags, sample_context_extractor); } void HeapProfiler::StopSamplingHeapProfiler() { diff --git a/deps/v8/src/api/api.h b/deps/v8/src/api/api.h index ca11abb423e6..843d757ff4b8 100644 --- a/deps/v8/src/api/api.h +++ b/deps/v8/src/api/api.h @@ -106,13 +106,14 @@ class RegisteredExtension { V(ToLocal, JSMap, Map) \ V(ToLocal, JSSet, Set) \ V(ToLocal, JSProxy, Proxy) \ - V(ToLocal, JSArrayBuffer, ArrayBuffer) \ + V(ToLocal, JSArrayBuffer, ArrayBufferBase) \ + V(ToLocalShared, JSArrayBuffer, SharedArrayBuffer) \ + V(ToLocalUnshared, JSArrayBuffer, ArrayBuffer) \ V(ToLocal, JSArrayBufferView, ArrayBufferView) \ V(ToLocal, JSDataView, DataView) \ V(ToLocal, JSPromise, Promise) \ V(ToLocal, JSRabGsabDataView, DataView) \ V(ToLocal, JSTypedArray, TypedArray) \ - V(ToLocalShared, JSArrayBuffer, SharedArrayBuffer) \ V(ToLocal, FunctionTemplateInfo, FunctionTemplate) \ V(ToLocal, ObjectTemplateInfo, ObjectTemplate) \ V(ToLocal, DictionaryTemplateInfo, DictionaryTemplate) \ @@ -136,6 +137,7 @@ class RegisteredExtension { #define TO_LOCAL_NAME_LIST(V) \ V(ToLocal) \ + V(ToLocalUnshared) \ V(ToLocalShared) \ V(SignatureToLocal) \ V(MessageToLocal) \ @@ -151,62 +153,63 @@ class RegisteredExtension { V(PrimitiveArrayToLocal) \ V(CppHeapExternalToLocal) -#define OPEN_HANDLE_LIST(V) \ - V(Template, TemplateInfoWithProperties) \ - V(FunctionTemplate, FunctionTemplateInfo) \ - V(ObjectTemplate, ObjectTemplateInfo) \ - V(DictionaryTemplate, DictionaryTemplateInfo) \ - V(Signature, FunctionTemplateInfo) \ - V(Data, Object) \ - V(Number, Number) \ - V(RegExp, JSRegExp) \ - V(Object, JSReceiver) \ - V(Array, JSArray) \ - V(Map, JSMap) \ - V(Set, JSSet) \ - V(ArrayBuffer, JSArrayBuffer) \ - V(ArrayBufferView, JSArrayBufferView) \ - V(TypedArray, JSTypedArray) \ - V(Uint8Array, JSTypedArray) \ - V(Uint8ClampedArray, JSTypedArray) \ - V(Int8Array, JSTypedArray) \ - V(Uint16Array, JSTypedArray) \ - V(Int16Array, JSTypedArray) \ - V(Uint32Array, JSTypedArray) \ - V(Int32Array, JSTypedArray) \ - V(Float16Array, JSTypedArray) \ - V(Float32Array, JSTypedArray) \ - V(Float64Array, JSTypedArray) \ - V(DataView, JSDataViewOrRabGsabDataView) \ - V(SharedArrayBuffer, JSArrayBuffer) \ - V(Name, Name) \ - V(String, String) \ - V(Symbol, Symbol) \ - V(Script, JSFunction) \ - V(UnboundModuleScript, SharedFunctionInfo) \ - V(UnboundScript, SharedFunctionInfo) \ - V(Module, Module) \ - V(Function, JSReceiver) \ - V(CompileHintsCollector, Script) \ - V(Message, JSMessageObject) \ - V(Context, NativeContext) \ - V(External, Object) \ - V(StackTrace, StackTraceInfo) \ - V(StackFrame, StackFrameInfo) \ - V(Proxy, JSProxy) \ - V(debug::GeneratorObject, JSGeneratorObject) \ - V(debug::ScriptSource, HeapObject) \ - V(debug::Script, Script) \ - V(debug::EphemeronTable, EphemeronHashTable) \ - V(debug::AccessorPair, AccessorPair) \ - V(Promise, JSPromise) \ - V(Primitive, Object) \ - V(PrimitiveArray, FixedArray) \ - V(BigInt, BigInt) \ - V(ScriptOrModule, ScriptOrModule) \ - V(FixedArray, FixedArray) \ - V(ModuleRequest, ModuleRequest) \ - V(CppHeapExternal, CppHeapExternalObject) \ +#define OPEN_HANDLE_LIST(V) \ + V(Template, TemplateInfoWithProperties) \ + V(FunctionTemplate, FunctionTemplateInfo) \ + V(ObjectTemplate, ObjectTemplateInfo) \ + V(DictionaryTemplate, DictionaryTemplateInfo) \ + V(Signature, FunctionTemplateInfo) \ + V(Data, Object) \ + V(Number, Number) \ + V(RegExp, JSRegExp) \ + V(Object, JSReceiver) \ + V(Array, JSArray) \ + V(Map, JSMap) \ + V(Set, JSSet) \ + V(ArrayBufferBase, JSArrayBuffer) \ + V(ArrayBuffer, JSArrayBuffer) \ + V(ArrayBufferView, JSArrayBufferView) \ + V(TypedArray, JSTypedArray) \ + V(Uint8Array, JSTypedArray) \ + V(Uint8ClampedArray, JSTypedArray) \ + V(Int8Array, JSTypedArray) \ + V(Uint16Array, JSTypedArray) \ + V(Int16Array, JSTypedArray) \ + V(Uint32Array, JSTypedArray) \ + V(Int32Array, JSTypedArray) \ + V(Float16Array, JSTypedArray) \ + V(Float32Array, JSTypedArray) \ + V(Float64Array, JSTypedArray) \ + V(DataView, JSDataViewOrRabGsabDataView) \ + V(SharedArrayBuffer, JSArrayBuffer) \ + V(Name, Name) \ + V(String, String) \ + V(Symbol, Symbol) \ + V(Script, JSFunction) \ + V(UnboundModuleScript, SharedFunctionInfo) \ + V(UnboundScript, SharedFunctionInfo) \ + V(Module, Module) \ + V(Function, JSReceiver) \ + V(CompileHintsCollector, Script) \ + V(Message, JSMessageObject) \ + V(Context, NativeContext) \ + V(External, Object) \ + V(StackTrace, StackTraceInfo) \ + V(StackFrame, StackFrameInfo) \ + V(Proxy, JSProxy) \ + V(debug::GeneratorObject, JSGeneratorObject) \ + V(debug::ScriptSource, HeapObject) \ + V(debug::Script, Script) \ + V(debug::EphemeronTable, EphemeronHashTable) \ + V(debug::AccessorPair, AccessorPair) \ + V(Promise, JSPromise) \ + V(Primitive, Object) \ + V(PrimitiveArray, FixedArray) \ + V(BigInt, BigInt) \ + V(ScriptOrModule, ScriptOrModule) \ + V(FixedArray, FixedArray) \ + V(ModuleRequest, ModuleRequest) \ + V(CppHeapExternal, CppHeapExternalObject) \ IF_WASM(V, WasmMemoryObject, WasmMemoryObject) class Utils { diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h index b036f590d044..3264d4bc0dd0 100644 --- a/deps/v8/src/ast/ast.h +++ b/deps/v8/src/ast/ast.h @@ -2413,9 +2413,6 @@ class FunctionLiteral final : public Expression { // This should only be called if we don't have a shared function info yet. void set_raw_inferred_name(AstConsString* raw_inferred_name); - bool pretenure() const { return Pretenure::decode(bit_field_); } - void set_pretenure() { bit_field_ = Pretenure::update(bit_field_, true); } - bool has_duplicate_parameters() const { // Not valid for lazy functions. DCHECK(ShouldEagerCompile()); @@ -2510,7 +2507,6 @@ class FunctionLiteral final : public Expression { raw_inferred_name_(ast_value_factory->empty_cons_string()), produced_preparse_data_(produced_preparse_data) { bit_field_ |= FunctionSyntaxKindBits::encode(function_syntax_kind) | - Pretenure::encode(false) | HasDuplicateParameters::encode(has_duplicate_parameters == kHasDuplicateParameters) | RequiresInstanceMembersInitializer::encode(false) | @@ -2521,8 +2517,7 @@ class FunctionLiteral final : public Expression { using FunctionSyntaxKindBits = Expression::NextBitField<FunctionSyntaxKind, 3>; - using Pretenure = FunctionSyntaxKindBits::Next<bool, 1>; - using HasDuplicateParameters = Pretenure::Next<bool, 1>; + using HasDuplicateParameters = FunctionSyntaxKindBits::Next<bool, 1>; using RequiresInstanceMembersInitializer = HasDuplicateParameters::Next<bool, 1>; using HasStaticPrivateMethodsOrAccessorsField = @@ -3471,10 +3466,6 @@ class AstNodeFactory final { DCHECK_NOT_NULL(target); DCHECK_NOT_NULL(value); - if (op != Token::kInit && target->IsVariableProxy()) { - target->AsVariableProxy()->set_is_assigned(); - } - if (op == Token::kAssign || op == Token::kInit) { return zone_->New<Assignment>(AstNode::kAssignment, op, target, value, pos); diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc index bb576c8b5fbc..8625d72efdac 100644 --- a/deps/v8/src/ast/prettyprinter.cc +++ b/deps/v8/src/ast/prettyprinter.cc @@ -7,6 +7,7 @@ #include <stdarg.h> #include <algorithm> +#include <array> #include <string_view> #include "src/ast/ast-value-factory.h" @@ -853,13 +854,13 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var, if (var == nullptr) { PrintLiteralIndented(info, value, true); } else { - base::EmbeddedVector<char, 256> buf; - int pos = - SNPrintF(buf, "%s (%p) (mode = %s, assigned = %s", info, - reinterpret_cast<void*>(var), VariableMode2String(var->mode()), - var->maybe_assigned() == kMaybeAssigned ? "true" : "false"); - SNPrintF(buf + pos, ")"); - PrintLiteralIndented(buf.begin(), value, true); + std::array<char, 256> buf; + int pos = base::SNPrintF( + buf, "%s (%p) (mode = %s, assigned = %s", info, + reinterpret_cast<void*>(var), VariableMode2String(var->mode()), + var->maybe_assigned() == kMaybeAssigned ? "true" : "false"); + base::SNPrintF(base::VectorOf(buf) + pos, ")"); + PrintLiteralIndented(buf.data(), value, true); } } @@ -1199,10 +1200,11 @@ void AstPrinter::PrintClassProperty(ClassLiteral::Property* property) { prop_kind = "AUTO ACCESSOR"; break; } - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "PROPERTY%s%s - %s", property->is_static() ? " - STATIC" : "", - property->is_private() ? " - PRIVATE" : " - PUBLIC", prop_kind); - IndentedScope prop(this, buf.begin()); + std::array<char, 128> buf; + base::SNPrintF( + buf, "PROPERTY%s%s - %s", property->is_static() ? " - STATIC" : "", + property->is_private() ? " - PRIVATE" : " - PUBLIC", prop_kind); + IndentedScope prop(this, buf.data()); PrintIndentedVisit("KEY", property->key()); PrintIndentedVisit("VALUE", property->value()); } @@ -1263,14 +1265,14 @@ void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) { IndentedScope indent(this, "REGEXP LITERAL", node->position()); PrintLiteralIndented("PATTERN", node->raw_pattern(), false); int i = 0; - base::EmbeddedVector<char, 128> buf; + std::array<char, 128> buf; #define V(Lower, Camel, LowerCamel, Char, Bit) \ if (node->flags() & RegExp::k##Camel) buf[i++] = Char; REGEXP_FLAG_LIST(V) #undef V buf[i] = '\0'; PrintIndented("FLAGS "); - Print("%s", buf.begin()); + Print("%s", buf.data()); Print("\n"); } @@ -1306,19 +1308,19 @@ void AstPrinter::PrintObjectProperties( std::string_view(" (no emit store, first instance, last at )").size() + kMaxIntLen + 1); - base::EmbeddedVector<char, kPrintMaxLen> buf; - int pos = SNPrintF(buf, "PROPERTY - %s", prop_kind); + std::array<char, kPrintMaxLen> buf; + int pos = base::SNPrintF(buf, "PROPERTY - %s", prop_kind); if (!property->emit_store()) { if (property->is_first_instance_of_key()) { - pos += - SNPrintF(buf + pos, " (no emit store, first instance, last at %d)", - property->last_instance_index()); + pos += base::SNPrintF(base::VectorOf(buf) + pos, + " (no emit store, first instance, last at %d)", + property->last_instance_index()); } else { - pos += SNPrintF(buf + pos, " (no emit store)"); + pos += base::SNPrintF(base::VectorOf(buf) + pos, " (no emit store)"); } } - IndentedScope prop(this, buf.begin()); + IndentedScope prop(this, buf.data()); PrintIndentedVisit("KEY", properties->at(i)->key()); PrintIndentedVisit("VALUE", properties->at(i)->value()); } @@ -1337,38 +1339,40 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) { void AstPrinter::VisitVariableProxy(VariableProxy* node) { - base::EmbeddedVector<char, 128> buf; - int pos = SNPrintF(buf, "VAR PROXY"); + std::array<char, 128> buf; + int pos = base::SNPrintF(buf, "VAR PROXY"); if (!node->is_resolved()) { - SNPrintF(buf + pos, " unresolved"); - PrintLiteralWithModeIndented(buf.begin(), nullptr, node->raw_name()); + base::SNPrintF(base::VectorOf(buf) + pos, " unresolved"); + PrintLiteralWithModeIndented(buf.data(), nullptr, node->raw_name()); } else { Variable* var = node->var(); switch (var->location()) { case VariableLocation::UNALLOCATED: - SNPrintF(buf + pos, " unallocated"); + base::SNPrintF(base::VectorOf(buf) + pos, " unallocated"); break; case VariableLocation::PARAMETER: - SNPrintF(buf + pos, " parameter[%d]", var->index()); + base::SNPrintF(base::VectorOf(buf) + pos, " parameter[%d]", + var->index()); break; case VariableLocation::LOCAL: - SNPrintF(buf + pos, " local[%d]", var->index()); + base::SNPrintF(base::VectorOf(buf) + pos, " local[%d]", var->index()); break; case VariableLocation::CONTEXT: - SNPrintF(buf + pos, " context[%d]", var->index()); + base::SNPrintF(base::VectorOf(buf) + pos, " context[%d]", var->index()); break; case VariableLocation::LOOKUP: - SNPrintF(buf + pos, " lookup"); + base::SNPrintF(base::VectorOf(buf) + pos, " lookup"); break; case VariableLocation::MODULE: - SNPrintF(buf + pos, " module"); + base::SNPrintF(base::VectorOf(buf) + pos, " module"); break; case VariableLocation::REPL_GLOBAL: - SNPrintF(buf + pos, " repl global[%d]", var->index()); + base::SNPrintF(base::VectorOf(buf) + pos, " repl global[%d]", + var->index()); break; } - PrintLiteralWithModeIndented(buf.begin(), var, node->raw_name()); + PrintLiteralWithModeIndented(buf.data(), var, node->raw_name()); } } @@ -1384,23 +1388,23 @@ void AstPrinter::VisitCompoundAssignment(CompoundAssignment* node) { } void AstPrinter::VisitYield(Yield* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "YIELD"); - IndentedScope indent(this, buf.begin(), node->position()); + std::array<char, 128> buf; + base::SNPrintF(buf, "YIELD"); + IndentedScope indent(this, buf.data(), node->position()); Visit(node->expression()); } void AstPrinter::VisitYieldStar(YieldStar* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "YIELD_STAR"); - IndentedScope indent(this, buf.begin(), node->position()); + std::array<char, 128> buf; + base::SNPrintF(buf, "YIELD_STAR"); + IndentedScope indent(this, buf.data(), node->position()); Visit(node->expression()); } void AstPrinter::VisitAwait(Await* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "AWAIT"); - IndentedScope indent(this, buf.begin(), node->position()); + std::array<char, 128> buf; + base::SNPrintF(buf, "AWAIT"); + IndentedScope indent(this, buf.data(), node->position()); Visit(node->expression()); } @@ -1415,9 +1419,9 @@ void AstPrinter::VisitOptionalChain(OptionalChain* node) { } void AstPrinter::VisitProperty(Property* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "PROPERTY"); - IndentedScope indent(this, buf.begin(), node->position()); + std::array<char, 128> buf; + base::SNPrintF(buf, "PROPERTY"); + IndentedScope indent(this, buf.data(), node->position()); Visit(node->obj()); AssignType type = Property::GetAssignType(node); @@ -1458,9 +1462,9 @@ void AstPrinter::VisitProperty(Property* node) { } void AstPrinter::VisitCall(Call* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "CALL"); - IndentedScope indent(this, buf.begin()); + std::array<char, 128> buf; + base::SNPrintF(buf, "CALL"); + IndentedScope indent(this, buf.data()); Visit(node->expression()); PrintArguments(node->arguments()); @@ -1475,9 +1479,9 @@ void AstPrinter::VisitCallNew(CallNew* node) { void AstPrinter::VisitCallRuntime(CallRuntime* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "CALL RUNTIME %s", node->function()->name); - IndentedScope indent(this, buf.begin(), node->position()); + std::array<char, 128> buf; + base::SNPrintF(buf, "CALL RUNTIME %s", node->function()->name); + IndentedScope indent(this, buf.data(), node->position()); PrintArguments(node->arguments()); } @@ -1489,10 +1493,10 @@ void AstPrinter::VisitUnaryOperation(UnaryOperation* node) { void AstPrinter::VisitCountOperation(CountOperation* node) { - base::EmbeddedVector<char, 128> buf; - SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"), - Token::Name(node->op())); - IndentedScope indent(this, buf.begin(), node->position()); + std::array<char, 128> buf; + base::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"), + Token::Name(node->op())); + IndentedScope indent(this, buf.data(), node->position()); Visit(node->expression()); } diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index 725f007719d4..78b7ca135890 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -118,9 +118,11 @@ Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type) DCHECK(!is_script_scope()); SetDefaults(); set_language_mode(outer_scope->language_mode()); - set_private_name_lookup_skips_outer_class( - outer_scope->is_class_scope() && - outer_scope->AsClassScope()->IsParsingHeritage()); + if (outer_scope->is_class_scope() && + outer_scope->AsClassScope()->IsParsingHeritage()) { + set_private_name_lookup_skips_outer_class(true); + outer_scope->GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc(); + } outer_scope_->AddInnerScope(this); } @@ -180,6 +182,9 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope, params_(4, zone) { DCHECK(!is_script_scope()); SetDefaults(); + if (V8_UNLIKELY(private_name_lookup_skips_outer_class())) { + RecordNeedsPrivateNameContextChainRecalc(); + } } ModuleScope::ModuleScope(DeclarationScope* script_scope, @@ -305,18 +310,17 @@ DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type, DCHECK(IsClassConstructor(function_kind())); set_class_scope_has_private_brand(true); } + if (is_function_scope() && !scope_info->HasSimpleParameters()) { + SetHasNonSimpleParameters(); + } + if (V8_UNLIKELY(private_name_lookup_skips_outer_class())) { + RecordNeedsPrivateNameContextChainRecalc(); + } } Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info) - : outer_scope_(nullptr), - variables_(zone), - scope_info_(scope_info), - scope_type_(CATCH_SCOPE) { - SetDefaults(); -#ifdef DEBUG - already_resolved_ = true; -#endif + : Scope(zone, CATCH_SCOPE, nullptr, scope_info) { // Cache the catch variable, even though it's also available via the // scope_info, as the parser expects that a catch scope always has the catch // variable as first and only variable. @@ -326,7 +330,6 @@ Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, kCreatedInitialized, maybe_assigned, &was_added); DCHECK(was_added); AllocateHeapSlot(variable); - set_is_hoisted_in_context(scope_info->is_hoisted_in_context()); } void DeclarationScope::SetDefaults() { @@ -427,6 +430,7 @@ Scope* Scope::DeserializeScopeChain( Scope* current_scope = nullptr; Scope* innermost_scope = nullptr; Scope* outer_scope = nullptr; + bool has_debug_evaluate_scope = false; while (!scope_info.is_null()) { if (scope_info == eval_outer_info) { @@ -454,9 +458,14 @@ Scope* Scope::DeserializeScopeChain( eval_scope->set_start_position(position); eval_scope->set_end_position(position); eval_scope->set_eval_position(position); - if (current_scope != nullptr) { + eval_scope->set_private_name_lookup_skips_outer_class( + current_scope->private_name_lookup_skips_outer_class()); + current_scope->set_private_name_lookup_skips_outer_class(false); eval_scope->AddInnerScope(current_scope); + } else if (parse_info != nullptr) { + eval_scope->set_private_name_lookup_skips_outer_class( + parse_info->flags().private_name_lookup_skips_outer_class()); } current_scope = eval_scope; if (innermost_scope == nullptr) innermost_scope = current_scope; @@ -497,6 +506,9 @@ Scope* Scope::DeserializeScopeChain( if (deserialization_mode == DeserializationMode::kIncludingVariables) { script_scope->SetScriptScopeInfo(handle(scope_info, isolate)); } + script_scope->set_has_context_cells(scope_info->HasContextCells()); + script_scope->set_is_hoisted_in_context( + scope_info->is_hoisted_in_context()); script_scope->num_heap_slots_ = scope_info->ContextLength(); script_scope->set_start_position(scope_info->StartPosition()); script_scope->set_end_position(scope_info->EndPosition()); @@ -522,6 +534,7 @@ Scope* Scope::DeserializeScopeChain( zone->New<DeclarationScope>(zone, FUNCTION_SCOPE, ast_value_factory, handle(scope_info, isolate)); outer_scope->set_is_dynamic_scope(); + has_debug_evaluate_scope = true; } else { // For scope analysis, debug-evaluate is equivalent to a with scope. outer_scope = zone->New<Scope>(zone, WITH_SCOPE, ast_value_factory, @@ -530,7 +543,7 @@ Scope* Scope::DeserializeScopeChain( } else if (scope_info->scope_type() == MODULE_SCOPE) { outer_scope = zone->New<ModuleScope>(handle(scope_info, isolate), ast_value_factory); - if (parse_info) { + if (parse_info && has_debug_evaluate_scope) { parse_info->set_has_module_in_scope_chain(); } } else { @@ -700,6 +713,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { if (!should_hoist) continue; + Variable* var; if (factory) { DCHECK(!is_being_lazily_parsed_); int pos = sloppy_block_function->position(); @@ -721,7 +735,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { // Redeclarations for vars do not create new bindings, but the // redeclarations' initializers are still run. That is, shadowed FiB will // result in multiple assignments to the same synthesized var. - Variable* var = DeclareVariable( + var = DeclareVariable( declaration, name, pos, VariableMode::kVar, NORMAL_VARIABLE, Variable::DefaultInitializationFlag(VariableMode::kVar), &was_added, nullptr, &ok); @@ -737,20 +751,14 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { } else { DCHECK(is_being_lazily_parsed_); bool was_added; - Variable* var = DeclareVariableName(name, VariableMode::kVar, &was_added); - if (sloppy_block_function->init() == Token::kAssign) { - var->SetMaybeAssigned(); - } + var = DeclareVariableName(name, VariableMode::kVar, &was_added); + } + if (sloppy_block_function->init() == Token::kAssign) { + var->SetMaybeAssigned(); } } } -void DeclarationScope::TakeUnresolvedReferencesFromParent() { - DCHECK(outer_scope_->reparsing_for_class_initializer_); - unresolved_list_.MoveTail(&outer_scope_->unresolved_list_, - outer_scope_->unresolved_list_.begin()); -} - bool DeclarationScope::Analyze(ParseInfo* info) { RCS_SCOPE(info->runtime_call_stats(), RuntimeCallCounterId::kCompileScopeAnalysis, @@ -850,12 +858,15 @@ void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) { // According to https://tc39.es/ecma262/#sec-functiondeclarationinstantiation // step 18 we should set argumentsObjectNeeded to false if has lexical // declared arguments only when hasParameterExpressions is false - if (!was_added && IsLexicalVariableMode(arguments_->mode()) && - has_simple_parameters()) { - // Check if there's lexically declared variable named arguments to avoid - // redeclaration. See - // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation, step 20. - arguments_ = nullptr; + if (!was_added) { + if (IsLexicalVariableMode(arguments_->mode()) && has_simple_parameters()) { + // Check if there's lexically declared variable named arguments to avoid + // redeclaration. See + // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation, step 20. + arguments_ = nullptr; + } else { + arguments_->SetMaybeAssigned(); + } } } @@ -940,6 +951,7 @@ Scope* Scope::FinalizeBlockScope() { scope->outer_scope_ = outer_scope(); if (private_name_lookup_skips_outer_class()) { scope->set_private_name_lookup_skips_outer_class(true); + scope->GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc(); } if (scope->is_function_scope()) { scope->set_is_hoisted_in_context(false); @@ -997,12 +1009,14 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { for (; inner_scope->sibling() != top_inner_scope_; inner_scope = inner_scope->sibling()) { inner_scope->outer_scope_ = new_parent; + inner_scope->set_private_name_lookup_skips_outer_class(false); if (inner_scope->inner_scope_calls_eval()) { new_parent->set_inner_scope_calls_eval(true); } DCHECK_NE(inner_scope, new_parent); } inner_scope->outer_scope_ = new_parent; + inner_scope->set_private_name_lookup_skips_outer_class(false); if (inner_scope->inner_scope_calls_eval()) { new_parent->set_inner_scope_calls_eval(true); } @@ -1032,6 +1046,7 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { if (outer_scope_->calls_eval()) { new_parent->RecordEvalCall(); outer_scope_->set_calls_eval(false); + declaration_scope_->set_calls_eval(false); declaration_scope_->set_sloppy_eval_can_extend_vars(false); declaration_scope_->set_is_dynamic_scope(false); } @@ -1397,10 +1412,19 @@ Declaration* DeclarationScope::CheckConflictingVarDeclarations( current->LookupInScopeOrScopeInfo(decl->var()->raw_name(), current); if (other_var != nullptr && !current->is_catch_scope()) { // If this is a VAR, then we know that it doesn't conflict with - // anything, so we can't conflict with anything either. The one - // exception is the binding variable in catch scopes, which is handled - // by the if above. - if (!IsLexicalVariableMode(other_var->mode())) break; + // anything, so we can't conflict with anything either. The two + // exceptions are: + // - the binding variable in catch scopes, which is handled by the if + // above, and + // - the implicit 'arguments' binding in the parameter scope of a + // function with non-simple parameters, which has kVar mode even + // though var declarations in direct eval inside parameter + // initializers conflict with it. + if (!IsLexicalVariableMode(other_var->mode()) && + !(current->is_function_scope() && + !current->AsDeclarationScope()->has_simple_parameters())) { + break; + } return decl; } current = current->outer_scope(); @@ -1409,6 +1433,25 @@ Declaration* DeclarationScope::CheckConflictingVarDeclarations( return nullptr; } +bool DeclarationScope::HasConflictingArgumentsVarDeclaration( + AstValueFactory* ast_value_factory) { + DCHECK(is_eval_scope()); + if (!is_sloppy(language_mode())) return false; + + Variable* var = LookupLocal(ast_value_factory->arguments_string()); + if (var == nullptr || IsLexicalVariableMode(var->mode())) return false; + + // During parameter initialization, the parameter environment of a + // non-arrow function with non-simple parameters contains an implicit + // `arguments` binding between the eval's lexical and variable environments. + DeclarationScope* var_scope = outer_scope()->GetNonEvalDeclarationScope(); + if (!var_scope->is_function_scope() || var_scope->is_arrow_scope()) { + return false; + } + DCHECK(var_scope->from_scope_info()); + return !var_scope->scope_info()->HasSimpleParameters(); +} + const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope, VariableMode mode_limit) { const VariableMap& variables = scope->variables_; @@ -1454,7 +1497,12 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) { } // Don't allocate variables of preparsed scopes. - if (!was_lazily_parsed()) AllocateVariablesRecursively(); + if (!was_lazily_parsed()) { + AllocateVariablesRecursively(); + if (needs_private_name_context_chain_recalc()) { + RecalcPrivateNameContextChain(); + } + } return true; } @@ -1697,20 +1745,21 @@ void Scope::AnalyzePartially(DeclarationScope* max_outer_scope, bool maybe_in_arrowhead) { this->ForEach([max_outer_scope, ast_node_factory, new_unresolved_list, maybe_in_arrowhead](Scope* scope) { - // Skip already lazily parsed scopes. This can only happen to functions - // inside arrowheads. - if (WasLazilyParsed(scope)) { - DCHECK(max_outer_scope->is_arrow_scope()); - return Iteration::kContinue; - } + // Functions inside arrowheads may have already been lazily parsed. Their + // unresolved variables were already resolved against their own scope, so + // continue resolving them from their outer scope. + bool was_lazily_parsed = WasLazilyParsed(scope); + DCHECK_IMPLIES(was_lazily_parsed, max_outer_scope->is_arrow_scope()); + Scope* lookup_scope = was_lazily_parsed ? scope->outer_scope() : scope; for (VariableProxy* proxy = scope->unresolved_list_.first(); proxy != nullptr; proxy = proxy->next_unresolved()) { if (proxy->is_removed_from_unresolved()) continue; DCHECK(!proxy->is_resolved()); int access_position = proxy->position(); - Variable* var = Lookup<kParsedScope>( - proxy, scope, max_outer_scope->outer_scope(), &access_position); + Variable* var = Lookup<kParsedScope>(proxy, lookup_scope, + max_outer_scope->outer_scope(), + &access_position); if (var == nullptr) { // Don't copy unresolved references to the script scope, unless it's a // reference to a private name or method. In that case keep it so we @@ -1728,7 +1777,7 @@ void Scope::AnalyzePartially(DeclarationScope* max_outer_scope, // Clear unresolved_list_ as it's in an inconsistent state. scope->unresolved_list_.Clear(); - return Iteration::kDescend; + return was_lazily_parsed ? Iteration::kContinue : Iteration::kDescend; }); } @@ -1746,6 +1795,8 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, sloppy_block_functions_.Clear(); rare_data_ = nullptr; set_has_rest(false); + set_has_using_declaration(false); + set_has_await_using_declaration(false); function_ = nullptr; DCHECK_NE(zone(), ast_value_factory->single_parse_zone()); @@ -2332,6 +2383,12 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope, if (cache_scope != nullptr) cache_scope->variables_.Remove(invalidated); Scope* target = cache_scope == nullptr ? scope : cache_scope; + if (invalidated->IsReplGlobal()) { + // Top-level lexical variables in REPL mode can be redeclared across + // scripts and are looked up globally via the ScriptContextTable rather + // than at a fixed context slot index, so treat them as kDynamicGlobal. + return target->NonLocal(proxy->raw_name(), VariableMode::kDynamicGlobal); + } var = target->NonLocal(proxy->raw_name(), VariableMode::kDynamicLocal); var->set_local_if_not_shadowed(invalidated); @@ -2411,11 +2468,20 @@ bool UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope, // but the variable they shadow might need a hole check, which we want to do // if we decide that no shadowing variable was dynamically introduced. DCHECK_EQ(kCreatedInitialized, var->initialization_flag()); + Variable* target = var->local_if_not_shadowed(); + if (target->scope()->IsOuterScopeUpToClosureScopeOf(var->scope())) { + // When the shadowed variable is in the same closure scope as the + // kDynamicLocal variable (e.g., a non-simple parameter in FUNCTION_SCOPE + // shadowed by a kDynamicLocal in the body's VarBlock), HoleCheckState is + // not scope-independent because the kDynamicLocal variable can be shared + // across references in the body and references in inner closures. + return UpdateNeedsHoleCheck(target, proxy, scope, access_position); + } // The access_position passed to the recursive call is the closest access // position to the underlying variable (since it was updated during the // lookup traversal). - bool needs_check = UpdateNeedsHoleCheck(var->local_if_not_shadowed(), proxy, - scope, access_position); + bool needs_check = + UpdateNeedsHoleCheck(target, proxy, scope, access_position); if (needs_check) { var->set_hole_check_state(Variable::HoleCheckState::kForce); } else { @@ -2924,10 +2990,6 @@ void DeclarationScope::AllocateScopeInfos(ParseInfo* parse_info, } } - if (scope->needs_private_name_context_chain_recalc()) { - scope->RecalcPrivateNameContextChain(); - } - Tagged<WeakFixedArray> infos = script->infos(); std::unordered_map<int, Handle<ScopeInfo>> scope_infos_to_reuse; if (infos->ulength().value() != 0) { diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index fa13cc9a176c..9f4dd1329d21 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -135,6 +135,9 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { declaration_scope_->set_is_dynamic_scope(true); declaration_scope_->set_sloppy_eval_can_extend_vars(true); } + if (declaration_scope_calls_eval_) { + declaration_scope_->set_calls_eval(true); + } if (calls_eval_) { outer_scope_->set_calls_eval(true); } @@ -155,6 +158,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // scope. Otherwise the cached flags will be merged with the flags from the // arrow head. bool calls_eval_; + bool declaration_scope_calls_eval_; bool sloppy_eval_can_extend_vars_; }; @@ -643,7 +647,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { } void set_needs_home_object() { - DCHECK(is_home_object_scope()); + DCHECK(is_home_object_scope() || from_scope_info() || is_script_scope()); flags_ = NeedsHomeObjectField::update(flags_, true); } @@ -969,9 +973,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { IsAccessorFunction(function_kind()) || IsClassConstructor(function_kind())); set_uses_super_property(true); - Scope* home_object_scope = GetHomeObjectScope(); - DCHECK_NOT_NULL(home_object_scope); - home_object_scope->set_needs_home_object(); + DCHECK_IMPLIES(!from_scope_info(), outer_scope_->is_home_object_scope()); + outer_scope_->set_needs_home_object(); } bool uses_super_property() const { @@ -981,8 +984,6 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { flags_ = UsesSuperPropertyField::update(flags_, value); } - void TakeUnresolvedReferencesFromParent(); - bool is_arrow_scope() const { return is_function_scope() && IsArrowFunction(function_kind_); } @@ -1075,6 +1076,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { Declaration* CheckConflictingVarDeclarations( bool* allowed_catch_binding_var_redeclaration); + bool HasConflictingArgumentsVarDeclaration( + AstValueFactory* ast_value_factory); + void set_has_checked_syntax(bool value) { flags_ = HasCheckedSyntaxField::update(flags_, value); } @@ -1512,6 +1516,7 @@ void Scope::RecordEvalCall() { GetDeclarationScope()->RecordDeclarationScopeEvalCall(); } RecordInnerScopeEvalCall(); + GetClosureScope()->RecordNeedsPrivateNameContextChainRecalc(); // The eval contents might access "super" (if it's inside a function that // binds super). DeclarationScope* receiver_scope = GetReceiverScope(); @@ -1529,12 +1534,15 @@ Scope::Snapshot::Snapshot(Scope* scope) top_unresolved_(scope->unresolved_list_.end()), top_local_(scope->GetClosureScope()->locals_.end()), calls_eval_(outer_scope_->calls_eval()), + declaration_scope_calls_eval_(declaration_scope_->calls_eval()), sloppy_eval_can_extend_vars_( declaration_scope_->sloppy_eval_can_extend_vars()) { // Reset in order to record (sloppy) eval calls during this Snapshot's // lifetime. outer_scope_->set_calls_eval(false); + declaration_scope_->set_calls_eval(false); declaration_scope_->set_sloppy_eval_can_extend_vars(false); + declaration_scope_->set_is_dynamic_scope(false); } class ModuleScope final : public DeclarationScope { diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h index 342ac2740768..3f498718656d 100644 --- a/deps/v8/src/ast/variables.h +++ b/deps/v8/src/ast/variables.h @@ -90,9 +90,6 @@ class Variable final : public ZoneObject { MaybeAssignedFlag maybe_assigned() const { return MaybeAssignedFlagField::decode(bit_field_); } - void clear_maybe_assigned() { - bit_field_ = MaybeAssignedFlagField::update(bit_field_, kNotAssigned); - } void set_maybe_assigned() { bit_field_ = MaybeAssignedFlagField::update(bit_field_, kMaybeAssigned); } diff --git a/deps/v8/src/base/bits.h b/deps/v8/src/base/bits.h index 179a10f557df..7b7ee1cba2f5 100644 --- a/deps/v8/src/base/bits.h +++ b/deps/v8/src/base/bits.h @@ -210,64 +210,6 @@ inline constexpr int WhichPowerOfTwo(T value) #endif } -// RoundUpToPowerOfTwo32(value) returns the smallest power of two which is -// greater than or equal to |value|. If you pass in a |value| that is already a -// power of two, it is returned as is. |value| must be less than or equal to -// 0x80000000u. Uses computation based on leading zeros if we have compiler -// support for that. Falls back to the implementation from "Hacker's Delight" by -// Henry S. Warren, Jr., figure 3-3, page 48, where the function is called clp2. -V8_BASE_EXPORT constexpr uint32_t RoundUpToPowerOfTwo32(uint32_t value) { - DCHECK_LE(value, uint32_t{1} << 31); - if (value) --value; -// Use computation based on leading zeros if we have compiler support for that. -#if V8_HAS_BUILTIN_CLZ || V8_CC_MSVC - return 1u << (32 - CountLeadingZeros(value)); -#else - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - return value + 1; -#endif -} -// Same for 64 bit integers. |value| must be <= 2^63 -V8_BASE_EXPORT constexpr uint64_t RoundUpToPowerOfTwo64(uint64_t value) { - DCHECK_LE(value, uint64_t{1} << 63); - if (value) --value; -// Use computation based on leading zeros if we have compiler support for that. -#if V8_HAS_BUILTIN_CLZ - return uint64_t{1} << (64 - CountLeadingZeros(value)); -#else - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value |= value >> 32; - return value + 1; -#endif -} -// Same for size_t integers. -inline constexpr size_t RoundUpToPowerOfTwo(size_t value) { - if (sizeof(size_t) == sizeof(uint64_t)) { - return RoundUpToPowerOfTwo64(value); - } else { - // Without windows.h included this line triggers a truncation warning on - // 64-bit builds. Presumably windows.h disables the relevant warning. - return RoundUpToPowerOfTwo32(static_cast<uint32_t>(value)); - } -} - -// RoundDownToPowerOfTwo32(value) returns the greatest power of two which is -// less than or equal to |value|. If you pass in a |value| that is already a -// power of two, it is returned as is. -inline constexpr uint32_t RoundDownToPowerOfTwo32(uint32_t value) { - if (value > 0x80000000u) return 0x80000000u; - uint32_t result = RoundUpToPowerOfTwo32(value); - if (result > value) result >>= 1; - return result; -} // Precondition: 0 <= shift < 32 inline constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift) { diff --git a/deps/v8/src/base/cpu/cpu-arm.cc b/deps/v8/src/base/cpu/cpu-arm.cc index 2b6a9c8ab0ca..4a29ee62359f 100644 --- a/deps/v8/src/base/cpu/cpu-arm.cc +++ b/deps/v8/src/base/cpu/cpu-arm.cc @@ -115,6 +115,7 @@ namespace v8::base { /* * HWCAP2 flags - for elf_hwcap2 (in kernel) and AT_HWCAP2 */ +#define HWCAP2_SVE2 (1 << 1) #define HWCAP2_SVEBITPERM (1 << 4) #define HWCAP2_MTE (1 << 18) #define HWCAP2_CSSC (1UL << 34) @@ -353,6 +354,9 @@ void CPU::DetectFeatures() { #if !defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) constexpr int PF_ARM_SVE_INSTRUCTIONS_AVAILABLE = 46; #endif +#if !defined(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) + constexpr int PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE = 47; +#endif #if !defined(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE) constexpr int PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE = 67; #endif @@ -368,6 +372,7 @@ void CPU::DetectFeatures() { has_fp16_ = IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE); has_sha3_ = IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE); has_sve_ = IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE); + has_sve2_ = IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE); has_svebitperm_ = IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE); @@ -380,6 +385,7 @@ void CPU::DetectFeatures() { has_hbc_ = (hwcaps2 & HWCAP2_HBC) != 0; has_mops_ = (hwcaps2 & HWCAP2_MOPS) != 0; has_svebitperm_ = (hwcaps2 & HWCAP2_SVEBITPERM) != 0; + has_sve2_ = (hwcaps2 & HWCAP2_SVE2) != 0; if (hwcaps != 0) { has_jscvt_ = (hwcaps & HWCAP_JSCVT) != 0; has_dot_prod_ = (hwcaps & HWCAP_ASIMDDP) != 0; @@ -388,6 +394,7 @@ void CPU::DetectFeatures() { has_fp16_ = (hwcaps & HWCAP_FPHP) != 0; has_sha3_ = (hwcaps & HWCAP_SHA3) != 0; has_sve_ = (hwcaps & HWCAP_SVE) != 0; + has_lrcpc2_ = (hwcaps & HWCAP_ILRCPC) != 0; } else { // Try to fallback to "Features" CPUInfo field CPUInfo cpu_info; @@ -399,6 +406,7 @@ void CPU::DetectFeatures() { has_fp16_ = HasListItem(features, "half"); has_sha3_ = HasListItem(features, "sha3"); has_sve_ = HasListItem(features, "sve"); + has_lrcpc2_ = HasListItem(features, "ilrcpc"); delete[] features; } #elif V8_OS_DARWIN @@ -451,6 +459,14 @@ void CPU::DetectFeatures() { } else { has_sha3_ = feat_sha3; } + int64_t feat_lrcpc2 = 0; + size_t feat_lrcpc2_size = sizeof(feat_lrcpc2); + if (sysctlbyname("hw.optional.arm.FEAT_LRCPC2", &feat_lrcpc2, + &feat_lrcpc2_size, nullptr, 0) == -1) { + has_lrcpc2_ = false; + } else { + has_lrcpc2_ = feat_lrcpc2; + } #else // ARM64 Macs always have the following features. has_jscvt_ = true; @@ -459,6 +475,7 @@ void CPU::DetectFeatures() { has_pmull1q_ = true; has_fp16_ = true; has_sha3_ = true; + has_lrcpc2_ = true; #endif // V8_OS_IOS int64_t feat_cssc = 0; size_t feat_cssc_size = sizeof(feat_cssc); diff --git a/deps/v8/src/base/cpu/cpu-riscv.cc b/deps/v8/src/base/cpu/cpu-riscv.cc index 91fe06b3564c..0746f0a405e2 100644 --- a/deps/v8/src/base/cpu/cpu-riscv.cc +++ b/deps/v8/src/base/cpu/cpu-riscv.cc @@ -35,6 +35,29 @@ __attribute__((target("arch=+v"))) static unsigned vlen_intrinsic() { return static_cast<unsigned>(__riscv_vlenb() * 8); } + +#if V8_OS_LINUX +// Checks whether the given feature appears as a whole underscore-separated +// item in a RISC-V "isa" string (e.g. "rv64imafdcv_zba_zbb"). +static bool IsaHasFeature(const char* isa, const char* feature) { + if (isa == nullptr) { + return false; + } + size_t feature_len = strlen(feature); + const char* p = isa; + while (*p != '\0') { + while (*p == '_') ++p; + const char* q = p; + while (*q != '\0' && *q != '_') ++q; + if (static_cast<size_t>(q - p) == feature_len && + memcmp(p, feature, feature_len) == 0) { + return true; + } + p = q; + } + return false; +} +#endif // V8_OS_LINUX #endif namespace v8::base { @@ -72,6 +95,21 @@ void CPU::DetectFeatures() { if (pairs[0].value & RISCV_HWPROBE_IMA_C) { has_rvc_ = true; } + } else { + // The riscv_hwprobe syscall was introduced in Linux 6.4. On older + // kernels (e.g. vendor BSP kernels that backport RVV 1.0 but not + // hwprobe), fall back to the "isa" line of /proc/cpuinfo. This restores + // the fallback that src/base/cpu.cc had before the split into + // per-architecture files (89ad1535). + char* isa = cpu_info.ExtractField("isa"); + + if (IsaHasFeature(isa, "rv64imafdc")) { + has_fpu_ = true; + } + if (IsaHasFeature(isa, "rv64imafdcv")) { + has_fpu_ = true; + has_rvv_ = true; + } } char* mmu = cpu_info.ExtractField("mmu"); diff --git a/deps/v8/src/base/cpu/cpu.h b/deps/v8/src/base/cpu/cpu.h index 363cc715748a..aed73a030ec2 100644 --- a/deps/v8/src/base/cpu/cpu.h +++ b/deps/v8/src/base/cpu/cpu.h @@ -132,7 +132,9 @@ class V8_BASE_EXPORT CPU final { bool has_cssc() const { return has_cssc_; } bool has_mops() const { return has_mops_; } bool has_sve() const { return has_sve_; } + bool has_sve2() const { return has_sve2_; } bool has_svebitperm() const { return has_svebitperm_; } + bool has_lrcpc2() const { return has_lrcpc2_; } // mips features bool is_fp64_mode() const { return is_fp64_mode_; } @@ -223,7 +225,9 @@ class V8_BASE_EXPORT CPU final { bool has_cssc_ = false; bool has_mops_ = false; bool has_sve_ = false; + bool has_sve2_ = false; bool has_svebitperm_ = false; + bool has_lrcpc2_ = false; bool is_fp64_mode_ = false; bool has_non_stop_time_stamp_counter_ = false; bool is_running_in_vm_ = false; diff --git a/deps/v8/src/base/flags.h b/deps/v8/src/base/flags.h index 7ee0efe22e69..a8d52764193e 100644 --- a/deps/v8/src/base/flags.h +++ b/deps/v8/src/base/flags.h @@ -7,6 +7,7 @@ #include <cstddef> #include <initializer_list> +#include <type_traits> #include "src/base/compiler-specific.h" @@ -21,11 +22,13 @@ namespace base { // that there's no type checking at all; any enum value can be OR'd with any // other enum value and passed on to a function that takes an int or unsigned // int. -template <typename EnumT, typename BitfieldT = int, +template <typename EnumT, typename BitfieldT = std::underlying_type_t<EnumT>, typename BitfieldStorageT = BitfieldT> class Flags final { public: static_assert(sizeof(BitfieldStorageT) >= sizeof(BitfieldT)); + static_assert(sizeof(BitfieldT) >= sizeof(EnumT), + "base::Flags BitfieldT is narrower than EnumT"); using flag_type = EnumT; using mask_type = BitfieldT; diff --git a/deps/v8/src/base/fpu.cc b/deps/v8/src/base/fpu.cc deleted file mode 100644 index 10590de42d18..000000000000 --- a/deps/v8/src/base/fpu.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2025 the V8 project 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 "src/base/fpu.h" - -#include <float.h> - -#include "include/v8config.h" - -namespace v8::base { - -#if defined(V8_HOST_ARCH_X64) || defined(V8_HOST_ARCH_IA32) -#if defined(V8_CC_GNU) -namespace { -// Two bits on Intel CPUs, for FTZ (flush denormalized results to zero) and DAZ -// (flush denormalized inputs to zero). -constexpr int kFlushDenormToZeroBits = 0x8040; -int GetCSR() { - int result; - asm volatile("stmxcsr %0" : "=m"(result)); - return result; -} - -void SetCSR(int a) { - int temp = a; - asm volatile("ldmxcsr %0" : : "m"(temp)); -} -} // namespace - -bool FPU::GetFlushDenormals() { - int csr = GetCSR(); - return csr & kFlushDenormToZeroBits; -} - -void FPU::SetFlushDenormals(bool value) { - int old_csr = GetCSR(); - int new_csr = value ? old_csr | kFlushDenormToZeroBits - : old_csr & ~kFlushDenormToZeroBits; - SetCSR(new_csr); -} -#elif defined(V8_CC_MSVC) -bool FPU::GetFlushDenormals() { - unsigned int csr; - _controlfp_s(&csr, 0, 0); - return (csr & _MCW_DN) == _DN_FLUSH; -} - -void FPU::SetFlushDenormals(bool value) { - unsigned int csr; - _controlfp_s(&csr, value ? _DN_FLUSH : _DN_SAVE, _MCW_DN); -} -#else -#error "Unsupported compiler" -#endif - -#elif defined(V8_HOST_ARCH_ARM64) || defined(V8_HOST_ARCH_ARM) - -namespace { -// Bit 24 is the flush-to-zero mode control bit. Setting it to 1 flushes -// denormals to 0. -constexpr int kFlushDenormToZeroBit = (1 << 24); -int GetStatusWord() { - int result; -#if defined(V8_HOST_ARCH_ARM64) - asm volatile("mrs %x[result], FPCR" : [result] "=r"(result)); -#else - asm volatile("vmrs %[result], FPSCR" : [result] "=r"(result)); -#endif - return result; -} - -void SetStatusWord(int a) { -#if defined(V8_HOST_ARCH_ARM64) - asm volatile("msr FPCR, %x[src]" : : [src] "r"(a)); -#else - asm volatile("vmsr FPSCR, %[src]" : : [src] "r"(a)); -#endif -} -} // namespace - -bool FPU::GetFlushDenormals() { - int csr = GetStatusWord(); - return csr & kFlushDenormToZeroBit; -} - -void FPU::SetFlushDenormals(bool value) { - int old_csr = GetStatusWord(); - int new_csr = value ? old_csr | kFlushDenormToZeroBit - : old_csr & ~kFlushDenormToZeroBit; - SetStatusWord(new_csr); -} - -#else - -bool FPU::GetFlushDenormals() { return false; } -void FPU::SetFlushDenormals(bool value) {} - -#endif - -} // namespace v8::base diff --git a/deps/v8/src/base/fpu.h b/deps/v8/src/base/fpu.h deleted file mode 100644 index 9327ac2f6af4..000000000000 --- a/deps/v8/src/base/fpu.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2025 the V8 project 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 V8_BASE_FPU_H_ -#define V8_BASE_FPU_H_ - -#include "src/base/base-export.h" - -namespace v8::base { -class FPU final { - public: - V8_BASE_EXPORT static bool GetFlushDenormals(); - V8_BASE_EXPORT static void SetFlushDenormals(bool); -}; -class V8_BASE_EXPORT FlushDenormalsScope final { - public: - explicit FlushDenormalsScope(bool value) - : old_flush_state_(FPU::GetFlushDenormals()) { - FPU::SetFlushDenormals(value); - } - ~FlushDenormalsScope() { FPU::SetFlushDenormals(old_flush_state_); } - - private: - bool old_flush_state_; -}; -} // namespace v8::base - -#endif // V8_BASE_FPU_H_ diff --git a/deps/v8/src/base/growing-circular-queue.h b/deps/v8/src/base/growing-circular-queue.h new file mode 100644 index 000000000000..46a385faefc7 --- /dev/null +++ b/deps/v8/src/base/growing-circular-queue.h @@ -0,0 +1,165 @@ +// Copyright 2026 the V8 project 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 V8_BASE_GROWING_CIRCULAR_QUEUE_H_ +#define V8_BASE_GROWING_CIRCULAR_QUEUE_H_ + +#include <algorithm> +#include <cstddef> +#include <limits> +#include <memory> +#include <type_traits> +#include <utility> + +#include "include/v8config.h" +#include "src/base/logging.h" +#include "src/base/macros.h" + +namespace v8::base { + +// A dynamically growing FIFO circular queue backed by an `Allocator`-allocated +// buffer and two pointers (`head_` and `tail_`). +// +// Invariants: +// - When empty: `head_ == nullptr` (`tail_` is `nullptr` if unallocated, or in +// `[buffer_, buffer_end_)` if allocated). +// - When non-empty: `head_` points to the next element to be dequeued, and +// `tail_` points to the next slot to be written on enqueue. +// - When full (or unallocated): `head_ == tail_`. +template <typename T, typename Allocator = std::allocator<T>> +class GrowingCircularQueue final { + public: + static constexpr size_t kInitialCapacity = 4; + + GrowingCircularQueue() = default; + explicit GrowingCircularQueue(const Allocator& allocator) + : allocator_(allocator) {} + + GrowingCircularQueue(const GrowingCircularQueue&) = delete; + GrowingCircularQueue& operator=(const GrowingCircularQueue&) = delete; + + GrowingCircularQueue(GrowingCircularQueue&& other) V8_NOEXCEPT + : allocator_(std::move(other.allocator_)), + buffer_(std::exchange(other.buffer_, nullptr)), + buffer_end_(std::exchange(other.buffer_end_, nullptr)), + head_(std::exchange(other.head_, nullptr)), + tail_(std::exchange(other.tail_, nullptr)) {} + + GrowingCircularQueue& operator=(GrowingCircularQueue&& other) V8_NOEXCEPT { + if (this == &other) return *this; + if (buffer_ != nullptr) FreeStorage(); + allocator_ = std::move(other.allocator_); + buffer_ = std::exchange(other.buffer_, nullptr); + buffer_end_ = std::exchange(other.buffer_end_, nullptr); + head_ = std::exchange(other.head_, nullptr); + tail_ = std::exchange(other.tail_, nullptr); + return *this; + } + + ~GrowingCircularQueue() { + if (buffer_ != nullptr) FreeStorage(); + } + + constexpr bool empty() const { return head_ == nullptr; } + + constexpr size_t size() const { + if (empty()) return 0; + if (tail_ > head_) return tail_ - head_; + return capacity() - (head_ - tail_); + } + + constexpr size_t capacity() const { return buffer_end_ - buffer_; } + + void Enqueue(T value) { + if (V8_UNLIKELY(head_ == tail_)) { + return GrowAndEnqueue(std::move(value)); + } + EnqueueUnchecked(std::move(value)); + } + + T Dequeue() { + DCHECK(!empty()); + T result = std::move(*head_); + std::destroy_at(head_); + if (++head_ == buffer_end_) { + head_ = buffer_; + } + if (head_ == tail_) { + head_ = nullptr; + } + return result; + } + + void Clear() { + DestroyElements(); + head_ = nullptr; + tail_ = buffer_; + } + + private: + V8_INLINE void EnqueueUnchecked(T value) { + DCHECK_NE(head_, tail_); + if (head_ == nullptr) { + head_ = tail_; + } + std::construct_at(tail_, std::move(value)); + if (++tail_ == buffer_end_) { + tail_ = buffer_; + } + } + + V8_NOINLINE V8_PRESERVE_MOST void GrowAndEnqueue(T value) { + Grow(); + EnqueueUnchecked(std::move(value)); + } + + void Grow() { + DCHECK_EQ(head_, tail_); + if (buffer_ == nullptr) { + buffer_ = allocator_.allocate(kInitialCapacity); + buffer_end_ = buffer_ + kInitialCapacity; + tail_ = buffer_; + return; + } + size_t old_capacity = capacity(); + CHECK_LE(old_capacity, std::numeric_limits<size_t>::max() / 2); + size_t new_capacity = 2 * old_capacity; + T* new_buffer = allocator_.allocate(new_capacity); + T* mid = std::uninitialized_move(head_, buffer_end_, new_buffer); + tail_ = std::uninitialized_move(buffer_, head_, mid); + std::destroy(buffer_, buffer_end_); + allocator_.deallocate(buffer_, old_capacity); + buffer_ = new_buffer; + buffer_end_ = new_buffer + new_capacity; + head_ = new_buffer; + } + + void DestroyElements() { + if constexpr (!std::is_trivially_destructible_v<T>) { + if (!empty()) { + if (tail_ > head_) { + std::destroy(head_, tail_); + } else { + std::destroy(head_, buffer_end_); + std::destroy(buffer_, tail_); + } + } + } + } + + V8_NOINLINE V8_PRESERVE_MOST void FreeStorage() { + DestroyElements(); + allocator_.deallocate(buffer_, capacity()); + } + + V8_NO_UNIQUE_ADDRESS Allocator allocator_; + T* buffer_ = nullptr; + T* buffer_end_ = nullptr; + T* head_ = nullptr; + T* tail_ = nullptr; +}; + +} // namespace v8::base + +#endif // V8_BASE_GROWING_CIRCULAR_QUEUE_H_ diff --git a/deps/v8/src/base/hashing.h b/deps/v8/src/base/hashing.h index 7b875cb61b28..9ff7ccaa465f 100644 --- a/deps/v8/src/base/hashing.h +++ b/deps/v8/src/base/hashing.h @@ -11,6 +11,7 @@ #include <cstddef> #include <cstring> #include <functional> +#include <span> #include <type_traits> #include <utility> @@ -265,6 +266,11 @@ V8_INLINE size_t hash_value(T (&v)[N]) { return Hasher{}.AddRange(v, v + N).hash(); } +template <typename T, size_t N> +V8_INLINE size_t hash_value(std::span<T, N> v) { + return Hasher{}.AddRange(v.begin(), v.end()).hash(); +} + template <typename T> V8_INLINE size_t hash_value(T* const& v) { return hash_value(reinterpret_cast<uintptr_t>(v)); diff --git a/deps/v8/src/base/logging.cc b/deps/v8/src/base/logging.cc index fef51b12925a..cfeda003c544 100644 --- a/deps/v8/src/base/logging.cc +++ b/deps/v8/src/base/logging.cc @@ -48,7 +48,7 @@ std::string PrettyPrintChar(int ch) { if (std::isprint(ch)) { oss << '\'' << ch << '\''; } else { - oss << std::hex << "\\x" << static_cast<unsigned int>(ch); + oss << std::hex << "\\x" << static_cast<unsigned int>(ch) << std::dec; } } return oss.str(); diff --git a/deps/v8/src/base/logging.h b/deps/v8/src/base/logging.h index a647cc1c76b4..a2c860c80c85 100644 --- a/deps/v8/src/base/logging.h +++ b/deps/v8/src/base/logging.h @@ -378,6 +378,14 @@ struct comparison_underlying_type { using type = std::conditional_t<std::is_same_v<type_or_bool, bool>, unsigned int, type_or_bool>; }; +template <typename T> + requires requires { + typename std::decay_t<T>::flag_type; + typename std::decay_t<T>::mask_type; + } +struct comparison_underlying_type<T> { + using type = typename std::decay_t<T>::mask_type; +}; // Cast a value to its underlying type #define MAKE_UNDERLYING(Type, value) \ static_cast<typename comparison_underlying_type<Type>::type>(value) diff --git a/deps/v8/src/base/macros.h b/deps/v8/src/base/macros.h index 5b1619f9ef02..8b5c4c601484 100644 --- a/deps/v8/src/base/macros.h +++ b/deps/v8/src/base/macros.h @@ -627,16 +627,6 @@ static_assert(V8_ENABLE_SIMD128); #define IF_NO_V8_WASM_RANDOM_FUZZERS(V, ...) EXPAND(V(__VA_ARGS__)) #endif // V8_WASM_RANDOM_FUZZERS -#ifdef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS -#define IF_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS(V, ...) \ - EXPAND(V(__VA_ARGS__)) -#define IF_FUNCTION_ARGUMENTS_CALLER_ARE_ON_PROTOTYPE(V, ...) -#else -#define IF_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS(V, ...) -#define IF_FUNCTION_ARGUMENTS_CALLER_ARE_ON_PROTOTYPE(V, ...) \ - EXPAND(V(__VA_ARGS__)) -#endif // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - #ifdef GOOGLE3 // Disable FRIEND_TEST macro in Google3. #define FRIEND_TEST(test_case_name, test_name) diff --git a/deps/v8/src/base/numbers/bignum-dtoa.cc b/deps/v8/src/base/numbers/bignum-dtoa.cc index 6caf0dd936d9..4619fed0ebec 100644 --- a/deps/v8/src/base/numbers/bignum-dtoa.cc +++ b/deps/v8/src/base/numbers/bignum-dtoa.cc @@ -5,6 +5,7 @@ #include "src/base/numbers/bignum-dtoa.h" #include <cmath> +#include <span> #include "src/base/logging.h" #include "src/base/numbers/bignum.h" @@ -44,22 +45,22 @@ static void FixupMultiply10(int estimated_power, bool is_even, // digits yield the shortest decimal representation of v. static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, Bignum* delta_minus, Bignum* delta_plus, - bool is_even, Vector<char> buffer, + bool is_even, std::span<char> buffer, int* length); // Generates 'requested_digits' after the decimal point. static void BignumToFixed(int requested_digits, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector<char>(buffer), int* length); + std::span<char> buffer, int* length); // Generates 'count' digits of numerator/denominator. // Once 'count' digits have been produced rounds the result depending on the // remainder (remainders of exactly .5 round upwards). Might update the // decimal_point when rounding up (for example for 0.9999). static void GenerateCountedDigits(int count, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector<char>(buffer), int* length); + std::span<char> buffer, int* length); void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, - Vector<char> buffer, int* length, int* decimal_point) { + std::span<char> buffer, int* length, int* decimal_point) { DCHECK_GT(v, 0); DCHECK(!Double(v).IsSpecial()); uint64_t significand = Double(v).Significand(); @@ -134,7 +135,7 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, // will be produced. This should be the standard precondition. static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, Bignum* delta_minus, Bignum* delta_plus, - bool is_even, Vector<char> buffer, + bool is_even, std::span<char> buffer, int* length) { // Small optimization: if delta_minus and delta_plus are the same just reuse // one of the two bignums. @@ -231,7 +232,7 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, // exponent (decimal_point), when rounding upwards. static void GenerateCountedDigits(int count, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector<char>(buffer), int* length) { + std::span<char> buffer, int* length) { DCHECK_GE(count, 0); for (int i = 0; i < count - 1; ++i) { uint16_t digit; @@ -272,7 +273,7 @@ static void GenerateCountedDigits(int count, int* decimal_point, // Input verifies: 1 <= (numerator + delta) / denominator < 10. static void BignumToFixed(int requested_digits, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector<char>(buffer), int* length) { + std::span<char> buffer, int* length) { // Note that we have to look at more than just the requested_digits, since // a number could be rounded up. Example: v=0.5 with requested_digits=0. // Even though the power of v equals 0 we can't just stop here. diff --git a/deps/v8/src/base/numbers/bignum-dtoa.h b/deps/v8/src/base/numbers/bignum-dtoa.h index d90b62e4c4bf..8c79b6b341c0 100644 --- a/deps/v8/src/base/numbers/bignum-dtoa.h +++ b/deps/v8/src/base/numbers/bignum-dtoa.h @@ -5,7 +5,9 @@ #ifndef V8_BASE_NUMBERS_BIGNUM_DTOA_H_ #define V8_BASE_NUMBERS_BIGNUM_DTOA_H_ -#include "src/base/vector.h" +#include <span> + +#include "src/base/base-export.h" namespace v8 { namespace base { @@ -53,7 +55,7 @@ enum BignumDtoaMode { // 'BignumDtoa' expects the given buffer to be big enough to hold all digits // and a terminating null-character. V8_BASE_EXPORT void BignumDtoa(double v, BignumDtoaMode mode, - int requested_digits, Vector<char> buffer, + int requested_digits, std::span<char> buffer, int* length, int* point); } // namespace base diff --git a/deps/v8/src/base/numbers/bignum.cc b/deps/v8/src/base/numbers/bignum.cc index 007a1ca2d880..db67410d3fc9 100644 --- a/deps/v8/src/base/numbers/bignum.cc +++ b/deps/v8/src/base/numbers/bignum.cc @@ -4,18 +4,14 @@ #include "src/base/numbers/bignum.h" +#include <algorithm> +#include <string_view> + #include "src/base/strings.h" namespace v8 { namespace base { -Bignum::Bignum() - : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) { - for (int i = 0; i < kBigitCapacity; ++i) { - bigits_[i] = 0; - } -} - template <typename S> static int BitSize(S value) { return 8 * sizeof(value); @@ -60,7 +56,7 @@ void Bignum::AssignBignum(const Bignum& other) { used_digits_ = other.used_digits_; } -static uint64_t ReadUInt64(Vector<const char> buffer, int from, +static uint64_t ReadUInt64(std::string_view buffer, int from, int digits_to_read) { uint64_t result = 0; int to = from + digits_to_read; @@ -73,11 +69,11 @@ static uint64_t ReadUInt64(Vector<const char> buffer, int from, return result; } -void Bignum::AssignDecimalString(Vector<const char> value) { +void Bignum::AssignDecimalString(std::string_view value) { // 2^64 = 18446744073709551616 > 10^19 const int kMaxUint64DecimalDigits = 19; Zero(); - int length = value.length(); + int length = static_cast<int>(value.length()); int pos = 0; // Let's just say that each digit needs 4 bits. while (length >= kMaxUint64DecimalDigits) { @@ -100,9 +96,9 @@ static int HexCharValue(char c) { UNREACHABLE(); } -void Bignum::AssignHexString(Vector<const char> value) { +void Bignum::AssignHexString(std::string_view value) { Zero(); - int length = value.length(); + int length = static_cast<int>(value.length()); int needed_bigits = length * 4 / kBigitSize + 1; EnsureCapacity(needed_bigits); diff --git a/deps/v8/src/base/numbers/bignum.h b/deps/v8/src/base/numbers/bignum.h index 0e15c5bea353..715309c903af 100644 --- a/deps/v8/src/base/numbers/bignum.h +++ b/deps/v8/src/base/numbers/bignum.h @@ -5,7 +5,13 @@ #ifndef V8_BASE_NUMBERS_BIGNUM_H_ #define V8_BASE_NUMBERS_BIGNUM_H_ -#include "src/base/vector.h" +#include <stdint.h> + +#include <array> +#include <string_view> + +#include "src/base/base-export.h" +#include "src/base/logging.h" namespace v8 { namespace base { @@ -17,15 +23,15 @@ class V8_BASE_EXPORT Bignum { // exponent. static const int kMaxSignificantBits = 3584; - Bignum(); + Bignum() = default; Bignum(const Bignum&) = delete; Bignum& operator=(const Bignum&) = delete; void AssignUInt16(uint16_t value); void AssignUInt64(uint64_t value); void AssignBignum(const Bignum& other); - void AssignDecimalString(Vector<const char> value); - void AssignHexString(Vector<const char> value); + void AssignDecimalString(std::string_view value); + void AssignHexString(std::string_view value); void AssignPowerUInt16(uint16_t base, int exponent); @@ -106,13 +112,11 @@ class V8_BASE_EXPORT Bignum { Chunk BigitAt(int index) const; void SubtractTimes(const Bignum& other, int factor); - Chunk bigits_buffer_[kBigitCapacity]; - // A vector backed by bigits_buffer_. This way accesses to the array are - // checked for out-of-bounds errors. - Vector<Chunk> bigits_; - int used_digits_; + // Zero-initialize the bigits storage. + std::array<Chunk, kBigitCapacity> bigits_ = {}; + int used_digits_ = 0; // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize). - int exponent_; + int exponent_ = 0; }; } // namespace base diff --git a/deps/v8/src/base/numbers/dtoa.cc b/deps/v8/src/base/numbers/dtoa.cc index 6cdf076750a9..657eec301147 100644 --- a/deps/v8/src/base/numbers/dtoa.cc +++ b/deps/v8/src/base/numbers/dtoa.cc @@ -5,6 +5,7 @@ #include "src/base/numbers/dtoa.h" #include <cmath> +#include <span> #include "src/base/logging.h" #include "src/base/numbers/bignum-dtoa.h" @@ -29,7 +30,7 @@ static BignumDtoaMode DtoaToBignumDtoaMode(DtoaMode dtoa_mode) { } void DoubleToAscii(double v, DtoaMode mode, int requested_digits, - Vector<char> buffer, int* sign, int* length, int* point) { + std::span<char> buffer, int* sign, int* length, int* point) { DCHECK(!Double(v).IsSpecial()); DCHECK(mode == DTOA_SHORTEST || requested_digits >= 0); diff --git a/deps/v8/src/base/numbers/dtoa.h b/deps/v8/src/base/numbers/dtoa.h index 4633269db17a..9db7237d723f 100644 --- a/deps/v8/src/base/numbers/dtoa.h +++ b/deps/v8/src/base/numbers/dtoa.h @@ -5,7 +5,9 @@ #ifndef V8_BASE_NUMBERS_DTOA_H_ #define V8_BASE_NUMBERS_DTOA_H_ -#include "src/base/vector.h" +#include <span> + +#include "src/base/base-export.h" namespace v8 { namespace base { @@ -62,8 +64,8 @@ const int kBase10MaximalLength = 17; // at least kBase10MaximalLength + 1. Otherwise, the size of the output is // limited to requested_digits digits plus the null terminator. V8_BASE_EXPORT void DoubleToAscii(double v, DtoaMode mode, int requested_digits, - Vector<char> buffer, int* sign, int* length, - int* point); + std::span<char> buffer, int* sign, + int* length, int* point); } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/numbers/fast-dtoa.cc b/deps/v8/src/base/numbers/fast-dtoa.cc index 4dee33c98e72..105be0b48137 100644 --- a/deps/v8/src/base/numbers/fast-dtoa.cc +++ b/deps/v8/src/base/numbers/fast-dtoa.cc @@ -6,6 +6,8 @@ #include <stdint.h> +#include <span> + #include "src/base/logging.h" #include "src/base/numbers/cached-powers.h" #include "src/base/numbers/diy-fp.h" @@ -152,7 +154,7 @@ static bool RoundWeed(char* last_digit, uint64_t distance_too_high_w, // unambiguously determined. // // Precondition: rest < ten_kappa. -static bool RoundWeedCounted(Vector<char> buffer, int length, uint64_t rest, +static bool RoundWeedCounted(std::span<char> buffer, int length, uint64_t rest, uint64_t ten_kappa, uint64_t unit, int* kappa) { DCHECK(rest < ten_kappa); // The following tests are done in a specific order to avoid overflows. They @@ -526,8 +528,8 @@ static bool DigitGen(DiyFp low, DiyFp w, DiyFp high, char** outptr, // numbers. If the precision is not enough to guarantee all the postconditions // then false is returned. This usually happens rarely, but the failure-rate // increases with higher requested_digits. -static bool DigitGenCounted(DiyFp w, int requested_digits, Vector<char> buffer, - int* length, int* kappa) { +static bool DigitGenCounted(DiyFp w, int requested_digits, + std::span<char> buffer, int* length, int* kappa) { DCHECK(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); DCHECK_GE(kMinimalTargetExponent, -60); DCHECK_LE(kMaximalTargetExponent, -32); @@ -671,8 +673,9 @@ static bool Grisu3(double v, char** outptr, int* decimal_exponent) { // and with enough requested digits 0.1 will at some point print as 0.9999999... // Grisu3 is too imprecise for real halfway cases (1.5 will not work) and // therefore the rounding strategy for halfway cases is irrelevant. -static bool Grisu3Counted(double v, int requested_digits, Vector<char> buffer, - int* length, int* decimal_exponent) { +static bool Grisu3Counted(double v, int requested_digits, + std::span<char> buffer, int* length, + int* decimal_exponent) { DiyFp w = Double(v).AsNormalizedDiyFp(); DiyFp ten_mk; // Cached power of ten: 10^-k int mk; // -k @@ -711,7 +714,7 @@ static bool Grisu3Counted(double v, int requested_digits, Vector<char> buffer, } bool FastDtoa(double v, FastDtoaMode mode, int requested_digits, - Vector<char> buffer, int* length, int* decimal_point) { + std::span<char> buffer, int* length, int* decimal_point) { DCHECK_GT(v, 0); DCHECK(!Double(v).IsSpecial()); diff --git a/deps/v8/src/base/numbers/fast-dtoa.h b/deps/v8/src/base/numbers/fast-dtoa.h index 0a10b090b3e2..6ed61987b525 100644 --- a/deps/v8/src/base/numbers/fast-dtoa.h +++ b/deps/v8/src/base/numbers/fast-dtoa.h @@ -5,7 +5,9 @@ #ifndef V8_BASE_NUMBERS_FAST_DTOA_H_ #define V8_BASE_NUMBERS_FAST_DTOA_H_ -#include "src/base/vector.h" +#include <span> + +#include "src/base/base-export.h" namespace v8 { namespace base { @@ -51,7 +53,7 @@ const int kFastDtoaMaximalLength = 17; // false. // For both modes the buffer must be large enough to hold the result. V8_BASE_EXPORT bool FastDtoa(double d, FastDtoaMode mode, int requested_digits, - Vector<char> buffer, int* length, + std::span<char> buffer, int* length, int* decimal_point); } // namespace base diff --git a/deps/v8/src/base/numbers/fixed-dtoa.cc b/deps/v8/src/base/numbers/fixed-dtoa.cc index e0649a26acd0..ae1235260e54 100644 --- a/deps/v8/src/base/numbers/fixed-dtoa.cc +++ b/deps/v8/src/base/numbers/fixed-dtoa.cc @@ -7,6 +7,7 @@ #include <stdint.h> #include <cmath> +#include <span> #include "absl/numeric/int128.h" #include "src/base/logging.h" @@ -45,7 +46,7 @@ class UInt128 { static const int kDoubleSignificandSize = 53; // Includes the hidden bit. static void FillDigits32FixedLength(uint32_t number, int requested_length, - Vector<char> buffer, int* length) { + std::span<char> buffer, int* length) { for (int i = requested_length - 1; i >= 0; --i) { buffer[(*length) + i] = '0' + number % 10; number /= 10; @@ -53,7 +54,7 @@ static void FillDigits32FixedLength(uint32_t number, int requested_length, *length += requested_length; } -static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) { +static void FillDigits32(uint32_t number, std::span<char> buffer, int* length) { int number_length = 0; // We fill the digits in reverse order and exchange them afterwards. while (number != 0) { @@ -76,7 +77,7 @@ static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) { } static void FillDigits64FixedLength(uint64_t number, int requested_length, - Vector<char> buffer, int* length) { + std::span<char> buffer, int* length) { const uint32_t kTen7 = 10000000; // For efficiency cut the number into 3 uint32_t parts, and print those. uint32_t part2 = static_cast<uint32_t>(number % kTen7); @@ -89,7 +90,7 @@ static void FillDigits64FixedLength(uint64_t number, int requested_length, FillDigits32FixedLength(part2, 7, buffer, length); } -static void FillDigits64(uint64_t number, Vector<char> buffer, int* length) { +static void FillDigits64(uint64_t number, std::span<char> buffer, int* length) { const uint32_t kTen7 = 10000000; // For efficiency cut the number into 3 uint32_t parts, and print those. uint32_t part2 = static_cast<uint32_t>(number % kTen7); @@ -109,7 +110,8 @@ static void FillDigits64(uint64_t number, Vector<char> buffer, int* length) { } } -static void DtoaRoundUp(Vector<char> buffer, int* length, int* decimal_point) { +static void DtoaRoundUp(std::span<char> buffer, int* length, + int* decimal_point) { // An empty buffer represents 0. if (*length == 0) { buffer[0] = '1'; @@ -150,7 +152,7 @@ static void DtoaRoundUp(Vector<char> buffer, int* length, int* decimal_point) { // already contained "199" (thus yielding a buffer of "19999") then a // rounding-up will change the contents of the buffer to "20000". static void FillFractionals(uint64_t fractionals, int exponent, - int fractional_count, Vector<char> buffer, + int fractional_count, std::span<char> buffer, int* length, int* decimal_point) { DCHECK(-128 <= exponent && exponent <= 0); // 'fractionals' is a fixed-point number, with binary point at bit @@ -207,7 +209,7 @@ static void FillFractionals(uint64_t fractionals, int exponent, // Removes leading and trailing zeros. // If leading zeros are removed then the decimal point position is adjusted. -static void TrimZeros(Vector<char> buffer, int* length, int* decimal_point) { +static void TrimZeros(std::span<char> buffer, int* length, int* decimal_point) { while (*length > 0 && buffer[(*length) - 1] == '0') { (*length)--; } @@ -224,7 +226,7 @@ static void TrimZeros(Vector<char> buffer, int* length, int* decimal_point) { } } -bool FastFixedDtoa(double v, int fractional_count, Vector<char> buffer, +bool FastFixedDtoa(double v, int fractional_count, std::span<char> buffer, int* length, int* decimal_point) { const uint32_t kMaxUInt32 = 0xFFFFFFFF; uint64_t significand = Double(v).Significand(); diff --git a/deps/v8/src/base/numbers/fixed-dtoa.h b/deps/v8/src/base/numbers/fixed-dtoa.h index 94930da4eeb1..a2cb7e35c87d 100644 --- a/deps/v8/src/base/numbers/fixed-dtoa.h +++ b/deps/v8/src/base/numbers/fixed-dtoa.h @@ -5,7 +5,9 @@ #ifndef V8_BASE_NUMBERS_FIXED_DTOA_H_ #define V8_BASE_NUMBERS_FIXED_DTOA_H_ -#include "src/base/vector.h" +#include <span> + +#include "src/base/base-export.h" namespace v8 { namespace base { @@ -27,7 +29,7 @@ namespace base { // This method only works for some parameters. If it can't handle the input it // returns false. The output is null-terminated when the function succeeds. V8_BASE_EXPORT bool FastFixedDtoa(double v, int fractional_count, - Vector<char> buffer, int* length, + std::span<char> buffer, int* length, int* decimal_point); } // namespace base diff --git a/deps/v8/src/base/numbers/strtod.cc b/deps/v8/src/base/numbers/strtod.cc index 0fa83f65437f..9ac8a5fc02aa 100644 --- a/deps/v8/src/base/numbers/strtod.cc +++ b/deps/v8/src/base/numbers/strtod.cc @@ -8,7 +8,10 @@ #include <cmath> #include <limits> +#include <string_view> +#include "src/base/logging.h" +#include "src/base/macros.h" #include "src/base/numbers/bignum.h" #include "src/base/numbers/cached-powers.h" #include "src/base/numbers/double.h" @@ -70,25 +73,25 @@ static const int kExactPowersOfTenSize = arraysize(exact_powers_of_ten); // we round up to 780. static const int kMaxSignificantDecimalDigits = 780; -static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) { - for (int i = 0; i < buffer.length(); i++) { +static std::string_view TrimLeadingZeros(std::string_view buffer) { + for (size_t i = 0; i < buffer.length(); i++) { if (buffer[i] != '0') { - return buffer.SubVector(i, buffer.length()); + return buffer.substr(i); } } - return Vector<const char>(buffer.begin(), 0); + return {}; } -static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) { - for (int i = buffer.length() - 1; i >= 0; --i) { +static std::string_view TrimTrailingZeros(std::string_view buffer) { + for (int i = static_cast<int>(buffer.length()) - 1; i >= 0; --i) { if (buffer[i] != '0') { - return buffer.SubVector(0, i + 1); + return buffer.substr(0, i + 1); } } - return Vector<const char>(buffer.begin(), 0); + return {}; } -static void TrimToMaxSignificantDigits(Vector<const char> buffer, int exponent, +static void TrimToMaxSignificantDigits(std::string_view buffer, int exponent, char* significant_buffer, int* significant_exponent) { for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { @@ -100,8 +103,8 @@ static void TrimToMaxSignificantDigits(Vector<const char> buffer, int exponent, // Set the last digit to be non-zero. This is sufficient to guarantee // correct rounding. significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; - *significant_exponent = - exponent + (buffer.length() - kMaxSignificantDecimalDigits); + *significant_exponent = exponent + (static_cast<int>(buffer.length()) - + kMaxSignificantDecimalDigits); } // Reads digits from the buffer and converts them to a uint64. @@ -109,11 +112,12 @@ static void TrimToMaxSignificantDigits(Vector<const char> buffer, int exponent, // When the string starts with "1844674407370955161" no further digit is read. // Since 2^64 = 18446744073709551616 it would still be possible read another // digit if it was less or equal than 6, but this would complicate the code. -static uint64_t ReadUint64(Vector<const char> buffer, +static uint64_t ReadUint64(std::string_view buffer, int* number_of_read_digits) { uint64_t result = 0; int i = 0; - while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { + int length = static_cast<int>(buffer.length()); + while (i < length && result <= (kMaxUint64 / 10 - 1)) { int digit = buffer[i++] - '0'; DCHECK(0 <= digit && digit <= 9); result = 10 * result + digit; @@ -126,11 +130,12 @@ static uint64_t ReadUint64(Vector<const char> buffer, // The returned DiyFp is not necessarily normalized. // If remaining_decimals is zero then the returned DiyFp is accurate. // Otherwise it has been rounded and has error of at most 1/2 ulp. -static void ReadDiyFp(Vector<const char> buffer, DiyFp* result, +static void ReadDiyFp(std::string_view buffer, DiyFp* result, int* remaining_decimals) { int read_digits; uint64_t significand = ReadUint64(buffer, &read_digits); - if (buffer.length() == read_digits) { + int length = static_cast<int>(buffer.length()); + if (length == read_digits) { *result = DiyFp(significand, 0); *remaining_decimals = 0; } else { @@ -141,11 +146,11 @@ static void ReadDiyFp(Vector<const char> buffer, DiyFp* result, // Compute the binary exponent. int exponent = 0; *result = DiyFp(significand, exponent); - *remaining_decimals = buffer.length() - read_digits; + *remaining_decimals = length - read_digits; } } -static bool DoubleStrtod(Vector<const char> trimmed, int exponent, +static bool DoubleStrtod(std::string_view trimmed, int exponent, double* result) { #if (V8_TARGET_ARCH_IA32 || defined(USE_SIMULATOR)) && !defined(_MSC_VER) // On x86 the floating-point stack can be 64 or 80 bits wide. If it is @@ -160,7 +165,8 @@ static bool DoubleStrtod(Vector<const char> trimmed, int exponent, USE(kExactPowersOfTenSize); return false; #else - if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { + int length = static_cast<int>(trimmed.length()); + if (length <= kMaxExactDoubleIntegerDecimalDigits) { int read_digits; // The trimmed input fits into a double. // If the 10^exponent (resp. 10^-exponent) fits into a double too then we @@ -171,26 +177,25 @@ static bool DoubleStrtod(Vector<const char> trimmed, int exponent, if (exponent < 0 && -exponent < kExactPowersOfTenSize) { // 10^-exponent fits into a double. *result = static_cast<double>(ReadUint64(trimmed, &read_digits)); - DCHECK(read_digits == trimmed.length()); + DCHECK(read_digits == length); *result /= exact_powers_of_ten[-exponent]; return true; } if (0 <= exponent && exponent < kExactPowersOfTenSize) { // 10^exponent fits into a double. *result = static_cast<double>(ReadUint64(trimmed, &read_digits)); - DCHECK(read_digits == trimmed.length()); + DCHECK(read_digits == length); *result *= exact_powers_of_ten[exponent]; return true; } - int remaining_digits = - kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); + int remaining_digits = kMaxExactDoubleIntegerDecimalDigits - length; if ((0 <= exponent) && (exponent - remaining_digits < kExactPowersOfTenSize)) { // The trimmed string was short and we can multiply it with // 10^remaining_digits. As a result the remaining exponent now fits // into a double too. *result = static_cast<double>(ReadUint64(trimmed, &read_digits)); - DCHECK(read_digits == trimmed.length()); + DCHECK(read_digits == length); *result *= exact_powers_of_ten[remaining_digits]; *result *= exact_powers_of_ten[exponent - remaining_digits]; return true; @@ -231,8 +236,7 @@ static DiyFp AdjustmentPowerOfTen(int exponent) { // If the function returns true then the result is the correct double. // Otherwise it is either the correct double or the double that is just below // the correct double. -static bool DiyFpStrtod(Vector<const char> buffer, int exponent, - double* result) { +static bool DiyFpStrtod(std::string_view buffer, int exponent, double* result) { DiyFp input; int remaining_decimals; ReadDiyFp(buffer, &input, &remaining_decimals); @@ -265,7 +269,8 @@ static bool DiyFpStrtod(Vector<const char> buffer, int exponent, int adjustment_exponent = exponent - cached_decimal_exponent; DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); input.Multiply(adjustment_power); - if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { + if (kMaxUint64DecimalDigits - static_cast<int>(buffer.length()) >= + adjustment_exponent) { // The product of input with the adjustment power fits into a 64 bit // integer. DCHECK_EQ(DiyFp::kSignificandSize, 64); @@ -345,7 +350,7 @@ static bool DiyFpStrtod(Vector<const char> buffer, int exponent, // buffer.length() + exponent <= kMaxDecimalPower + 1 // buffer.length() + exponent > kMinDecimalPower // buffer.length() <= kMaxDecimalSignificantDigits -static double BignumStrtod(Vector<const char> buffer, int exponent, +static double BignumStrtod(std::string_view buffer, int exponent, double guess) { if (guess == std::numeric_limits<double>::infinity()) { return guess; @@ -353,8 +358,8 @@ static double BignumStrtod(Vector<const char> buffer, int exponent, DiyFp upper_boundary = Double(guess).UpperBoundary(); - DCHECK(buffer.length() + exponent <= kMaxDecimalPower + 1); - DCHECK_GT(buffer.length() + exponent, kMinDecimalPower); + DCHECK(static_cast<int>(buffer.length()) + exponent <= kMaxDecimalPower + 1); + DCHECK_GT(static_cast<int>(buffer.length()) + exponent, kMinDecimalPower); DCHECK_LE(buffer.length(), kMaxSignificantDecimalDigits); // Make sure that the Bignum will be able to hold all our numbers. // Our Bignum implementation has a separate field for exponents. Shifts will @@ -388,24 +393,25 @@ static double BignumStrtod(Vector<const char> buffer, int exponent, } } -double Strtod(Vector<const char> buffer, int exponent) { - Vector<const char> left_trimmed = TrimLeadingZeros(buffer); - Vector<const char> trimmed = TrimTrailingZeros(left_trimmed); - exponent += left_trimmed.length() - trimmed.length(); +double Strtod(std::string_view buffer, int exponent) { + std::string_view left_trimmed = TrimLeadingZeros(buffer); + std::string_view trimmed = TrimTrailingZeros(left_trimmed); + exponent += static_cast<int>(left_trimmed.length() - trimmed.length()); if (trimmed.empty()) return 0.0; - if (trimmed.length() > kMaxSignificantDecimalDigits) { + int trimmed_length = static_cast<int>(trimmed.length()); + if (trimmed_length > kMaxSignificantDecimalDigits) { char significant_buffer[kMaxSignificantDecimalDigits]; int significant_exponent; TrimToMaxSignificantDigits(trimmed, exponent, significant_buffer, &significant_exponent); return Strtod( - Vector<const char>(significant_buffer, kMaxSignificantDecimalDigits), + std::string_view(significant_buffer, kMaxSignificantDecimalDigits), significant_exponent); } - if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { + if (exponent + trimmed_length - 1 >= kMaxDecimalPower) { return std::numeric_limits<double>::infinity(); } - if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0; + if (exponent + trimmed_length <= kMinDecimalPower) return 0.0; double guess; if (DoubleStrtod(trimmed, exponent, &guess) || diff --git a/deps/v8/src/base/numbers/strtod.h b/deps/v8/src/base/numbers/strtod.h index 7faeb934d372..c28dcba921d6 100644 --- a/deps/v8/src/base/numbers/strtod.h +++ b/deps/v8/src/base/numbers/strtod.h @@ -5,14 +5,16 @@ #ifndef V8_BASE_NUMBERS_STRTOD_H_ #define V8_BASE_NUMBERS_STRTOD_H_ -#include "src/base/vector.h" +#include <string_view> + +#include "src/base/base-export.h" namespace v8 { namespace base { // The buffer must only contain digits in the range [0-9]. It must not // contain a dot or a sign. It must not start with '0', and must not be empty. -V8_BASE_EXPORT double Strtod(Vector<const char> buffer, int exponent); +V8_BASE_EXPORT double Strtod(std::string_view buffer, int exponent); } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/platform/mutex.h b/deps/v8/src/base/platform/mutex.h index 8d295d747874..7e424b8dcac0 100644 --- a/deps/v8/src/base/platform/mutex.h +++ b/deps/v8/src/base/platform/mutex.h @@ -199,6 +199,14 @@ class V8_NODISCARD LockGuard final { // `mutex_` is guaranteed to be non-null here. mutex_->Lock(); } + static std::optional<LockGuard> TryLock(Mutex* mutex) { + DCHECK_NOT_NULL(mutex); + if (!mutex->TryLock()) return {}; + return LockGuard(mutex, AdoptLock{}); + } + static std::optional<LockGuard> TryLock(Mutex& mutex) { + return TryLock(&mutex); + } LockGuard(const LockGuard&) = delete; LockGuard& operator=(const LockGuard&) = delete; LockGuard(LockGuard&& other) V8_NOEXCEPT : mutex_(other.mutex_) { @@ -213,6 +221,12 @@ class V8_NODISCARD LockGuard final { } private: + struct AdoptLock {}; + LockGuard(Mutex* mutex, AdoptLock) : mutex_(mutex) { + DCHECK_NOT_NULL(mutex_); + mutex_->AssertHeld(); + } + Mutex* mutex_; }; diff --git a/deps/v8/src/base/platform/platform-linux.cc b/deps/v8/src/base/platform/platform-linux.cc index 51d24a55044f..e299b03dc733 100644 --- a/deps/v8/src/base/platform/platform-linux.cc +++ b/deps/v8/src/base/platform/platform-linux.cc @@ -31,6 +31,9 @@ #include <sys/types.h> // mmap & munmap #include <sys/utsname.h> // uname #include <unistd.h> // sysconf +#if defined(V8_HOST_ARCH_X64) +#include <asm/prctl.h> +#endif // defined(V8_HOST_ARCH_X64) #include <cmath> #include <cstdio> @@ -53,6 +56,10 @@ #define MREMAP_DONTUNMAP 4 #endif +#if defined(V8_HOST_ARCH_X64) && !defined(ARCH_GET_UNTAG_MASK) +#define ARCH_GET_UNTAG_MASK 0x4001 +#endif // defined(V8_HOST_ARCH_X64) && !defined(ARCH_GET_UNTAG_MASK) + namespace v8 { namespace base { @@ -430,5 +437,18 @@ bool SignalSafeMapsParser::ReadDecimal(uintptr_t* out_val, char* out_delim) { } } +// static +uint64_t OS::GetAddressUntagMask() { + // TODO(559990948): The check clashes with Chrome's seccomp policy, disable it + // temporarily. + // #if defined(V8_HOST_ARCH_X64) + // uint64_t untag_mask = ~uint64_t{0}; + // if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &untag_mask) == 0) { + // return untag_mask; + // } + // #endif // defined(V8_HOST_ARCH_X64) + return ~uint64_t{0}; +} + } // namespace base } // namespace v8 diff --git a/deps/v8/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc index df122799fdca..f8c5b3e5a5cd 100644 --- a/deps/v8/src/base/platform/platform-posix.cc +++ b/deps/v8/src/base/platform/platform-posix.cc @@ -10,7 +10,6 @@ #include <limits.h> #include <pthread.h> -#include "src/base/fpu.h" #include "src/base/logging.h" #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include <pthread_np.h> // for pthread_set_name_np @@ -1101,8 +1100,7 @@ void OS::VPrintError(const char* format, va_list args) { #endif } - -int OS::SNPrintF(char* str, int length, const char* format, ...) { +int OS::SNPrintF(char* str, size_t length, const char* format, ...) { va_list args; va_start(args, format); int result = VSNPrintF(str, length, format, args); @@ -1110,13 +1108,9 @@ int OS::SNPrintF(char* str, int length, const char* format, ...) { return result; } - -int OS::VSNPrintF(char* str, - int length, - const char* format, - va_list args) { +int OS::VSNPrintF(char* str, size_t length, const char* format, va_list args) { int n = vsnprintf(str, length, format, args); - if (n < 0 || n >= length) { + if (n < 0 || static_cast<size_t>(n) >= length) { // If the length is zero, the assignment fails. if (length > 0) { str[length - 1] = '\0'; @@ -1127,12 +1121,11 @@ int OS::VSNPrintF(char* str, } } - // ---------------------------------------------------------------------------- // POSIX string support. // -void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { +void OS::StrNCpy(char* dest, size_t length, const char* src, size_t n) { strncpy(dest, src, n); } @@ -1277,9 +1270,7 @@ static void SetThreadName(const char* name) { } static void* ThreadEntry(void* arg) { - // Reset denormals state to default, in case we picked up a non-default one - // with the posix clone() call. - base::FPU::SetFlushDenormals(false); + Stack::SetCurrentThreadStackStart(); Thread* thread = reinterpret_cast<Thread*>(arg); // We take the lock here to make sure that pthread_create finished first since diff --git a/deps/v8/src/base/platform/platform-starboard.cc b/deps/v8/src/base/platform/platform-starboard.cc index c38c5408d4fb..aab62d1bc08b 100644 --- a/deps/v8/src/base/platform/platform-starboard.cc +++ b/deps/v8/src/base/platform/platform-starboard.cc @@ -330,7 +330,7 @@ void OS::VPrintError(const char* format, va_list args) { SbLogRawFormat(format, args); } -int OS::SNPrintF(char* str, int length, const char* format, ...) { +int OS::SNPrintF(char* str, size_t length, const char* format, ...) { va_list args; va_start(args, format); int result = VSNPrintF(str, length, format, args); @@ -338,9 +338,9 @@ int OS::SNPrintF(char* str, int length, const char* format, ...) { return result; } -int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { +int OS::VSNPrintF(char* str, size_t length, const char* format, va_list args) { int n = vsnprintf(str, length, format, args); - if (n < 0 || n >= length) { + if (n < 0 || static_cast<size_t>(n) >= length) { // If the length is zero, the assignment fails. if (length > 0) str[length - 1] = '\0'; return -1; @@ -353,7 +353,7 @@ int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { // POSIX string support. // -void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { +void OS::StrNCpy(char* dest, size_t length, const char* src, size_t n) { strncpy(dest, src, n); } @@ -381,6 +381,7 @@ Thread::~Thread() { delete data_; } static void SetThreadName(const char* name) { SbThreadSetName(name); } static void* ThreadEntry(void* arg) { + Stack::SetCurrentThreadStackStart(); Thread* thread = reinterpret_cast<Thread*>(arg); // We take the lock here to make sure that pthread_create finished first since // we don't know which thread will run first (the original thread or the new diff --git a/deps/v8/src/base/platform/platform-win32.cc b/deps/v8/src/base/platform/platform-win32.cc index ca1990b019b1..47c60a416297 100644 --- a/deps/v8/src/base/platform/platform-win32.cc +++ b/deps/v8/src/base/platform/platform-win32.cc @@ -708,8 +708,7 @@ void OS::VPrintError(const char* format, va_list args) { VPrintHelper(stderr, format, args); } - -int OS::SNPrintF(char* str, int length, const char* format, ...) { +int OS::SNPrintF(char* str, size_t length, const char* format, ...) { va_list args; va_start(args, format); int result = VSNPrintF(str, length, format, args); @@ -717,12 +716,11 @@ int OS::SNPrintF(char* str, int length, const char* format, ...) { return result; } - -int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { +int OS::VSNPrintF(char* str, size_t length, const char* format, va_list args) { int n = _vsnprintf_s(str, length, _TRUNCATE, format, args); // Make sure to zero-terminate the string if the output was // truncated or if there was an error. - if (n < 0 || n >= length) { + if (n < 0 || static_cast<size_t>(n) >= length) { if (length > 0) str[length - 1] = '\0'; return -1; @@ -731,18 +729,15 @@ int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { } } - -void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { +void OS::StrNCpy(char* dest, size_t length, const char* src, size_t n) { // Use _TRUNCATE or strncpy_s crashes (by design) if buffer is too small. - size_t buffer_size = static_cast<size_t>(length); - if (n + 1 > buffer_size) // count for trailing '\0' + if (n + 1 > length) // count for trailing '\0' n = _TRUNCATE; int result = strncpy_s(dest, length, src, n); USE(result); DCHECK(result == 0 || (n == _TRUNCATE && result == STRUNCATE)); } - #undef _TRUNCATE #undef STRUNCATE @@ -1746,6 +1741,7 @@ static const HANDLE kNoThread = INVALID_HANDLE_VALUE; // object. It is important that this function has __stdcall calling // convention. static unsigned int __stdcall ThreadEntry(void* arg) { + Stack::SetCurrentThreadStackStart(); Thread* thread = reinterpret_cast<Thread*>(arg); thread->NotifyStartedAndDispatch(); return 0; diff --git a/deps/v8/src/base/platform/platform.cc b/deps/v8/src/base/platform/platform.cc index a75d06dbeb02..178470d85aa2 100644 --- a/deps/v8/src/base/platform/platform.cc +++ b/deps/v8/src/base/platform/platform.cc @@ -9,22 +9,18 @@ namespace base { namespace { -// A pointer to current thread's stack beginning. -thread_local void* thread_stack_start = nullptr; +// A pointer to current thread's stack beginning, as reported by the OS. +thread_local void* os_thread_stack_start = nullptr; + +// A pointer to current thread's stack start, as overridden by V8 or by the +// embedder. +thread_local void* custom_thread_stack_start = nullptr; // A pointer to current thread's reserved stack limit. thread_local void* thread_reserved_stack_limit = nullptr; } // namespace -// static -Stack::StackSlot Stack::GetStackStartUnchecked() { - if (!thread_stack_start) { - thread_stack_start = ObtainCurrentThreadStackStart(); - } - return thread_stack_start; -} - // static Stack::StackSlot Stack::GetReservedStackLimit() { if (!thread_reserved_stack_limit) { @@ -34,7 +30,61 @@ Stack::StackSlot Stack::GetReservedStackLimit() { } // static -Stack::StackSlot Stack::GetStackStart() { return GetStackStartUnchecked(); } +Stack::StackSlot Stack::GetStackStart() { + if (!os_thread_stack_start) { + os_thread_stack_start = ObtainCurrentThreadStackStart(); + } + return os_thread_stack_start; +} + +// static +Stack::StackSlot Stack::GetEffectiveStackStart() { + if (custom_thread_stack_start) return custom_thread_stack_start; + return GetStackStart(); +} + +// static +Stack::StackSlot Stack::SetCurrentThreadStackStart(StackSlot stack_start) { + if (stack_start != nullptr) { + DCHECK_LE(GetCurrentStackPosition(), stack_start); + DCHECK_LE(stack_start, GetStackStart()); + } + StackSlot previous = custom_thread_stack_start; + custom_thread_stack_start = stack_start; + return previous; +} + +// static +bool Stack::HasCustomCurrentThreadStackStart() { + return custom_thread_stack_start != nullptr; +} + +// static +void Stack::ValidateStackSegment(const void* start, const void* top, + bool check_for_tls) { + CHECK_NOT_NULL(start); + CHECK_NOT_NULL(top); + CHECK_LE(top, start); + const void* current_stack_start = GetStackStart(); + const void* current_stack_top = GetCurrentStackPosition(); + CHECK_LE(current_stack_top, top); + CHECK_LE(start, current_stack_start); + // TODO(540324230): Remove check_for_tls entirely and check this + // unconditionally, once embedders correctly set the stack start for all + // threads. + if (check_for_tls) { + // Check that the stack segment does not contain TLS data. This may be + // violated on Linux with glibc, because pthread_create allocates a + // single memory region for TLS data and for the stack and all threads + // except the main thread of the process report the wrong stack start. + // + // If this check fails, it probably means that an embedder using V8 + // should have used v8::StackStartScope to appropriately set the stack + // start for the current thread. + const void* tls = &os_thread_stack_start; + CHECK(!(top <= tls && tls < start)); + } +} // static int OS::GetCurrentThreadId() { diff --git a/deps/v8/src/base/platform/platform.h b/deps/v8/src/base/platform/platform.h index 7692528c10b1..7256bb1bff5d 100644 --- a/deps/v8/src/base/platform/platform.h +++ b/deps/v8/src/base/platform/platform.h @@ -271,12 +271,12 @@ class V8_BASE_EXPORT OS { // Safe formatting print. Ensures that str is always null-terminated. // Returns the number of chars written, or -1 if output was truncated. - static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length, + static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, size_t length, const char* format, ...); - static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length, + static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, size_t length, const char* format, va_list args); - static void StrNCpy(char* dest, int length, const char* src, size_t n); + static void StrNCpy(char* dest, size_t length, const char* src, size_t n); // Support for the profiler. Can do nothing, in which case ticks // occurring in shared libraries will not be properly accounted for. @@ -364,6 +364,13 @@ class V8_BASE_EXPORT OS { // Make part of the process's data memory read-only. static void SetDataReadOnly(void* address, size_t size); + // Returns the address untag mask for the current process (~0ULL if disabled). +#if defined(V8_OS_LINUX) + static uint64_t GetAddressUntagMask(); +#else + static uint64_t GetAddressUntagMask() { return ~uint64_t{0}; } +#endif // defined(V8_OS_LINUX) + private: // Assign a name to a memory region. // @@ -680,11 +687,25 @@ class V8_BASE_EXPORT Stack { operator void*() const { return reinterpret_cast<void*>(value); } operator uintptr_t() const { return value; } // NOLINT + template <typename T> + requires std::is_convertible_v<T, StackSlot> + friend bool operator==(StackSlot slot, T other) { + return slot.value == StackSlot(other).value; + } + template <typename T> + requires std::is_convertible_v<T, StackSlot> + friend auto operator<=>(StackSlot slot, T other) { + return slot.value <=> StackSlot(other).value; + } + uintptr_t value; }; // Gets the start of the stack of the current thread. static StackSlot GetStackStart(); + // Gets the custom start of the stack of the current thread if set, otherwise + // the OS-reported stack start. + static StackSlot GetEffectiveStackStart(); // Gets the lowest address that the stack can grow to. static StackSlot GetReservedStackLimit(); @@ -719,6 +740,18 @@ class V8_BASE_EXPORT Stack { #undef DEFAULT_CURRENT_FRAME_ADDRESS + // Sets the start of the stack of the current thread and returns the previous + // value. + static StackSlot SetCurrentThreadStackStart( + StackSlot stack_start = GetCurrentFrameAddress()); + // TODO(540324230): Remove once Blink correctly sets the stack start for + // all non-main threads. + static bool HasCustomCurrentThreadStackStart(); + + // Checks that [top, start) is a valid stack segment. + static void ValidateStackSegment(const void* start, const void* top, + bool check_for_tls); + // Returns the real stack frame if slot is part of a fake frame, and slot // otherwise. static StackSlot GetRealStackAddressForSlot(StackSlot slot) { @@ -739,7 +772,6 @@ class V8_BASE_EXPORT Stack { private: // Return the current thread stack start pointer. - static StackSlot GetStackStartUnchecked(); static StackSlot ObtainCurrentThreadStackStart(); // Lowest address that the stack can grow to. static StackSlot ObtainCurrentThreadStackReservedLimit(); diff --git a/deps/v8/src/base/small-vector.h b/deps/v8/src/base/small-vector.h index 55c64c081f5d..cb16478659f0 100644 --- a/deps/v8/src/base/small-vector.h +++ b/deps/v8/src/base/small-vector.h @@ -6,22 +6,25 @@ #define V8_BASE_SMALL_VECTOR_H_ #include <algorithm> +#include <bit> +#include <span> #include <type_traits> #include <utility> #include "include/v8config.h" -#include "src/base/bits.h" #include "src/base/macros.h" #include "src/base/memcopy.h" -#include "src/base/vector.h" namespace v8 { namespace base { // Minimal SmallVector implementation. Uses inline storage first, switches to // dynamic storage when it overflows. +// The alignment is necessary for 32-bit MSVC: When passing SmallVector by +// value, it ends up being 4-byte aligned only (and so does `inline_storage`), +// unless we specify alignment here. template <typename T, size_t kSize, typename Allocator = std::allocator<T>> -class SmallVector { +class alignas(std::max(alignof(T), alignof(T*))) SmallVector { // TODO(mliedtke): Remove kHasTrivialElement and replace usages with the // proper conditions. static constexpr bool kHasTrivialElement = @@ -78,7 +81,7 @@ class SmallVector { std::uninitialized_move(init.begin(), init.end(), begin_); end_ = begin_ + init.size(); } - explicit V8_INLINE SmallVector(base::Vector<const T> init, + explicit V8_INLINE SmallVector(std::span<const T> init, const Allocator& allocator = Allocator()) : allocator_(allocator) { if (init.size() > capacity()) Grow(init.size()); @@ -355,8 +358,7 @@ class SmallVector { // Grows the backing store by a factor of two, and at least to {min_capacity}. V8_NOINLINE V8_PRESERVE_MOST void Grow(size_t min_capacity) { size_t in_use = end_ - begin_; - size_t new_capacity = - base::bits::RoundUpToPowerOfTwo(std::max(min_capacity, 2 * capacity())); + size_t new_capacity = std::bit_ceil(std::max(min_capacity, 2 * capacity())); T* new_storage = AllocateDynamicStorage(new_capacity); if (new_storage == nullptr) { FatalOOM(OOMType::kProcess, "base::SmallVector::Grow"); diff --git a/deps/v8/src/base/strings.cc b/deps/v8/src/base/strings.cc index 3b8723527166..e918c4b6c49b 100644 --- a/deps/v8/src/base/strings.cc +++ b/deps/v8/src/base/strings.cc @@ -7,17 +7,18 @@ #include <cstdint> #include <cstring> #include <limits> +#include <span> #include "src/base/platform/platform.h" namespace v8 { namespace base { -int VSNPrintF(Vector<char> str, const char* format, va_list args) { - return OS::VSNPrintF(str.begin(), str.length(), format, args); +int VSNPrintF(std::span<char> str, const char* format, va_list args) { + return OS::VSNPrintF(str.data(), str.size(), format, args); } -int SNPrintF(Vector<char> str, const char* format, ...) { +int SNPrintF(std::span<char> str, const char* format, ...) { va_list args; va_start(args, format); int result = VSNPrintF(str, format, args); @@ -25,8 +26,8 @@ int SNPrintF(Vector<char> str, const char* format, ...) { return result; } -void StrNCpy(base::Vector<char> dest, const char* src, size_t n) { - base::OS::StrNCpy(dest.begin(), dest.length(), src, n); +void StrNCpy(std::span<char> dest, const char* src, uint32_t n) { + base::OS::StrNCpy(dest.data(), dest.size(), src, n); } } // namespace base diff --git a/deps/v8/src/base/strings.h b/deps/v8/src/base/strings.h index c3015e72c880..73eb4064da13 100644 --- a/deps/v8/src/base/strings.h +++ b/deps/v8/src/base/strings.h @@ -5,9 +5,10 @@ #ifndef V8_BASE_STRINGS_H_ #define V8_BASE_STRINGS_H_ +#include <span> + #include "src/base/base-export.h" #include "src/base/macros.h" -#include "src/base/vector.h" namespace v8 { namespace base { @@ -20,14 +21,14 @@ using uc32 = uint32_t; constexpr int kUC16Size = sizeof(uc16); V8_BASE_EXPORT int PRINTF_FORMAT(2, 0) - VSNPrintF(Vector<char> str, const char* format, va_list args); + VSNPrintF(std::span<char> str, const char* format, va_list args); // Safe formatting print. Ensures that str is always null-terminated. // Returns the number of chars written, or -1 if output was truncated. V8_BASE_EXPORT int PRINTF_FORMAT(2, 3) - SNPrintF(Vector<char> str, const char* format, ...); + SNPrintF(std::span<char> str, const char* format, ...); -V8_BASE_EXPORT void StrNCpy(base::Vector<char> dest, const char* src, size_t n); +V8_BASE_EXPORT void StrNCpy(std::span<char> dest, const char* src, uint32_t n); // Returns the value (0 .. 15) of a hexadecimal character c. // If c is not a legal hexadecimal character, returns a value < 0. diff --git a/deps/v8/src/base/unique-array.h b/deps/v8/src/base/unique-array.h new file mode 100644 index 000000000000..d649334db63e --- /dev/null +++ b/deps/v8/src/base/unique-array.h @@ -0,0 +1,196 @@ +// Copyright 2026 the V8 project 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 V8_BASE_UNIQUE_ARRAY_H_ +#define V8_BASE_UNIQUE_ARRAY_H_ + +#include <algorithm> +#include <cstddef> +#include <iterator> +#include <memory> +#include <span> +#include <type_traits> +#include <utility> + +#include "include/v8config.h" +#include "src/base/algorithm.h" +#include "src/base/logging.h" + +namespace v8::base { + +// A dynamically allocated `unique_ptr<T[]>` keeping track of the size. This is +// analogous to std::dynarray or base::HeapArray in Chromium. +template <typename T> +class UniqueArray final { + public: + // Allocates a new array of the specified size via the default allocator. + // Elements in the new array are value-initialized. + static UniqueArray<T> New(size_t size) { + if (size == 0) return {}; + return UniqueArray<T>(std::make_unique<T[]>(size), size); + } + + // Allocates a new array of the specified size via the default allocator and + // initializes all elements by assigning from `init`. + template <typename U> + static UniqueArray<T> New(size_t size, U init) { + if (size == 0) return {}; + UniqueArray<std::remove_const_t<T>> arr = + UniqueArray<std::remove_const_t<T>>::NewForOverwrite(size); + std::fill_n(arr.begin(), size, init); + return arr; + } + + // Allocates a new array of the specified size via the default allocator. + // Elements in the new array are default-initialized. + static UniqueArray<T> NewForOverwrite(size_t size) { + if (size == 0) return {}; + return UniqueArray<T>(std::make_unique_for_overwrite<T[]>(size), size); + } + + // Allocates a new array containing the specified collection of values. + static UniqueArray<T> CopiedFrom(const std::remove_const_t<T>* data, + size_t size) { + auto result = UniqueArray<std::remove_const_t<T>>::NewForOverwrite(size); + base::Copy(data, data + size, result.begin()); + return result; + } + + static UniqueArray<T> CopiedFrom( + std::span<const std::remove_const_t<T>> that) { + return CopiedFrom(that.data(), that.size()); + } + + UniqueArray() = default; + + // Disallow copying. + UniqueArray(const UniqueArray&) = delete; + UniqueArray& operator=(const UniqueArray&) = delete; + + // Move construction and move assignment from `UniqueArray<U>` to + // `UniqueArray<T>`, instantiable if `std::unique_ptr<U[]>` can be converted + // to `std::unique_ptr<T[]>`. Can also be used to convert `UniqueArray<T>` to + // `UniqueArray<const T>`. + // These also function as the standard move construction/assignment operator. + // `other` is left as an empty array. + template <typename U> + requires std::is_convertible_v<std::unique_ptr<U[]>, std::unique_ptr<T[]>> + UniqueArray(UniqueArray<U>&& other) V8_NOEXCEPT { + *this = std::move(other); + } + + template <typename U> + requires std::is_convertible_v<std::unique_ptr<U[]>, std::unique_ptr<T[]>> + UniqueArray& operator=(UniqueArray<U>&& other) V8_NOEXCEPT { + static_assert(sizeof(U) == sizeof(T)); + data_ = std::move(other.data_); + length_ = other.length_; + DCHECK_NULL(other.data_); + other.length_ = 0; + return *this; + } + + // Returns the length of the array as a size_t. + constexpr size_t size() const { return length_; } + + // Returns whether or not the array is empty. + constexpr bool empty() const { return length_ == 0; } + + constexpr T* begin() const V8_LIFETIME_BOUND { + DCHECK_IMPLIES(length_ > 0, data_ != nullptr); + return data_.get(); + } + + constexpr T* end() const V8_LIFETIME_BOUND { return begin() + length_; } + + // In addition to `begin`, do provide a `data()` accessor for API + // compatibility with other sequential containers. + constexpr T* data() const V8_LIFETIME_BOUND { return begin(); } + + constexpr std::reverse_iterator<T*> rbegin() const V8_LIFETIME_BOUND { + return std::make_reverse_iterator(end()); + } + constexpr std::reverse_iterator<T*> rend() const V8_LIFETIME_BOUND { + return std::make_reverse_iterator(begin()); + } + + // Access individual array elements - checks bounds in debug mode. + T& operator[](size_t index) const V8_LIFETIME_BOUND { + DCHECK_LT(index, length_); + return data_[index]; + } + + // Returns a `std::span<T>` view of the data in this array. + std::span<T> as_span() const V8_LIFETIME_BOUND { return {begin(), size()}; } + std::span<T> first(size_t count) const V8_LIFETIME_BOUND { + return as_span().first(count); + } + std::span<T> last(size_t count) const V8_LIFETIME_BOUND { + return as_span().last(count); + } + std::span<T> subspan(size_t offset, size_t count = std::dynamic_extent) const + V8_LIFETIME_BOUND { + return as_span().subspan(offset, count); + } + + // Releases the backing data from this array and transfers ownership to the + // caller. This array will be empty afterwards. + std::unique_ptr<T[]> ReleaseData() { + length_ = 0; + return std::move(data_); + } + + bool operator==(std::nullptr_t) const { return data_ == nullptr; } + + private: + template <typename U> + friend class UniqueArray; + + UniqueArray(std::unique_ptr<T[]> data, size_t length) + : data_(std::move(data)), length_(length) { + DCHECK_IMPLIES(length_ > 0, data_ != nullptr); + } + + std::unique_ptr<T[]> data_; + size_t length_ = 0; +}; + +template <typename T> +constexpr bool operator==(const UniqueArray<T>& lhs, + const UniqueArray<T>& rhs) { + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template <typename T> + requires(!std::is_const_v<T>) +constexpr bool operator==(const UniqueArray<T>& lhs, + const UniqueArray<const T>& rhs) { + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template <typename T> +constexpr bool operator==(const UniqueArray<T>& lhs, + std::span<const std::remove_const_t<T>> rhs) { + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +// Construct a UniqueArray from a start pointer and a size. +// The data will be copied. +template <typename T> +inline UniqueArray<T> UniqueCopyOf(const T* data, size_t size) { + return UniqueArray<T>::CopiedFrom(data, size); +} + +// Construct a UniqueArray from anything compatible with std::data and +// std::size (e.g. an array, or a container providing a `data()` and `size()` +// accessor). The data will be copied. +template <typename Container> +inline auto UniqueCopyOf(const Container& c) + -> decltype(UniqueCopyOf(std::data(c), std::size(c))) { + return UniqueCopyOf(std::data(c), std::size(c)); +} + +} // namespace v8::base + +#endif // V8_BASE_UNIQUE_ARRAY_H_ diff --git a/deps/v8/src/base/vector.h b/deps/v8/src/base/vector.h index 7900785219ba..22ddc98c219d 100644 --- a/deps/v8/src/base/vector.h +++ b/deps/v8/src/base/vector.h @@ -6,11 +6,13 @@ #define V8_BASE_VECTOR_H_ #include <algorithm> +#include <array> #include <cstring> #include <iterator> #include <limits> #include <memory> #include <ranges> +#include <span> #include <type_traits> #include "include/v8config.h" @@ -44,26 +46,37 @@ class Vector final { using iterator = T*; using const_iterator = const T*; - constexpr Vector() : start_(nullptr), length_(0) {} + constexpr Vector() = default; constexpr Vector(T* data V8_LIFETIME_BOUND, size_t length) - : start_(data), length_(length) { + : span_(data, length) { DCHECK(length == 0 || data != nullptr); } - static Vector<T> New(size_t length) { - return Vector<T>(new T[length], length); - } + template <typename U, size_t n> + requires std::is_convertible_v<std::span<U, n>, std::span<T>> + // NOLINTNEXTLINE(runtime/explicit) + constexpr Vector(std::span<U, n> span) : span_(span) {} + + template <typename U, size_t n> + requires std::is_convertible_v<std::span<U, n>, std::span<T>> + // NOLINTNEXTLINE(runtime/explicit) + constexpr Vector(std::array<U, n>& arr V8_LIFETIME_BOUND) : span_(arr) {} + + template <typename U, size_t n> + requires std::is_convertible_v<std::span<const U, n>, std::span<T>> + // NOLINTNEXTLINE(runtime/explicit) + constexpr Vector(const std::array<U, n>& arr V8_LIFETIME_BOUND) + : span_(arr) {} // Returns a vector using the same backing storage as this one, // spanning from and including 'from', to but not including 'to'. - Vector<T> SubVector(size_t from, size_t to) const { + constexpr Vector<T> SubVector(size_t from, size_t to) const { DCHECK_LE(from, to); - DCHECK_LE(to, length_); - return Vector<T>(begin() + from, to - from); + return subspan(from, to - from); } - Vector<T> SubVectorFrom(size_t from) const { - return SubVector(from, length_); + constexpr Vector<T> SubVectorFrom(size_t from) const { + return subspan(from); } template <class U> @@ -81,46 +94,61 @@ class Vector final { // Returns the length of the vector. Only use this if you really need an // integer return value. Use {size()} otherwise. int length() const { - CHECK_GE(std::numeric_limits<int>::max(), length_); - return static_cast<int>(length_); + CHECK_GE(std::numeric_limits<int>::max(), size()); + return static_cast<int>(size()); } // Returns the length of the vector as a size_t. - constexpr size_t size() const { return length_; } + constexpr size_t size() const { return span_.size(); } // Returns whether or not the vector is empty. - constexpr bool empty() const { return length_ == 0; } + constexpr bool empty() const { return span_.empty(); } // Access individual vector elements - checks bounds in debug mode. T& operator[](size_t index) const { - DCHECK_LT(index, length_); - return start_[index]; + DCHECK_LT(index, size()); + return span_[index]; } const T& at(size_t index) const { return operator[](index); } - T& first() { return start_[0]; } - const T& first() const { return start_[0]; } + constexpr T& front() const { + DCHECK_LT(0, size()); + return span_.front(); + } - T& last() { - DCHECK_LT(0, length_); - return start_[length_ - 1]; + constexpr T& back() const { + DCHECK_LT(0, size()); + return span_.back(); } - const T& last() const { - DCHECK_LT(0, length_); - return start_[length_ - 1]; + + constexpr Vector<T> first(size_t count) const { + DCHECK_LE(count, size()); + return Vector<T>(span_.first(count)); + } + + constexpr Vector<T> last(size_t count) const { + DCHECK_LE(count, size()); + return Vector<T>(span_.last(count)); + } + + constexpr Vector<T> subspan(size_t offset, + size_t count = std::dynamic_extent) const { + DCHECK_LE(offset, size()); + DCHECK(count == std::dynamic_extent || count <= size() - offset); + return Vector<T>(span_.subspan(offset, count)); } // Returns a pointer to the start of the data in the vector. - constexpr T* begin() const { return start_; } - constexpr const T* cbegin() const { return start_; } + constexpr T* begin() const { return span_.data(); } + constexpr const T* cbegin() const { return span_.data(); } // For consistency with other containers, do also provide a {data} accessor. - constexpr T* data() const { return start_; } + constexpr T* data() const { return span_.data(); } // Returns a pointer past the end of the data in the vector. - constexpr T* end() const { return start_ + length_; } - constexpr const T* cend() const { return start_ + length_; } + constexpr T* end() const { return span_.data() + span_.size(); } + constexpr const T* cend() const { return span_.data() + span_.size(); } constexpr std::reverse_iterator<T*> rbegin() const { return std::make_reverse_iterator(end()); @@ -130,16 +158,8 @@ class Vector final { } void Truncate(size_t length) { - DCHECK_LE(length, length_); - length_ = length; - } - - // Releases the array underlying this vector. Once disposed the - // vector is empty. - void Dispose() { - delete[] start_; - start_ = nullptr; - length_ = 0; + DCHECK_LE(length, size()); + span_ = span_.first(length); } const Vector<T> operator+(size_t offset) const { @@ -147,9 +167,8 @@ class Vector final { } Vector<T> operator+=(size_t offset) { - DCHECK_LE(offset, length_); - start_ += offset; - length_ -= offset; + DCHECK_LE(offset, size()); + span_ = span_.subspan(offset); return *this; } @@ -160,10 +179,12 @@ class Vector final { // violate covariance. template <typename U> requires std::is_convertible_v<T*, const U*> && (sizeof(U) == sizeof(T)) - operator Vector<const U>() const { - return {start_, length_}; + constexpr operator Vector<const U>() const { + return {span_.data(), span_.size()}; } + explicit constexpr operator std::span<T>() const noexcept { return span_; } + template <typename S> static Vector<T> cast(Vector<S> input) { // Casting is potentially dangerous, so be really restrictive here. This @@ -187,8 +208,7 @@ class Vector final { } private: - T* start_; - size_t length_; + std::span<T> span_; }; template <typename T> @@ -196,145 +216,10 @@ V8_INLINE size_t hash_value(base::Vector<T> v) { return hash_range(v.begin(), v.end()); } -template <typename T> -class OwnedVector final { - public: - OwnedVector() = default; - - OwnedVector(std::unique_ptr<T[]> data, size_t length) - : data_(std::move(data)), length_(length) { - DCHECK_IMPLIES(length_ > 0, data_ != nullptr); - } - - // Disallow copying. - OwnedVector(const OwnedVector&) = delete; - OwnedVector& operator=(const OwnedVector&) = delete; - - // Move construction and move assignment from {OwnedVector<U>} to - // {OwnedVector<T>}, instantiable if {std::unique_ptr<U>} can be converted to - // {std::unique_ptr<T>}. Can also be used to convert {OwnedVector<T>} to - // {OwnedVector<const T>}. - // These also function as the standard move construction/assignment operator. - // {other} is left as an empty vector. - template <typename U> - requires std::is_convertible_v<std::unique_ptr<U>, std::unique_ptr<T>> - OwnedVector(OwnedVector<U>&& other) V8_NOEXCEPT { - *this = std::move(other); - } - - template <typename U> - requires std::is_convertible_v<std::unique_ptr<U>, std::unique_ptr<T>> - OwnedVector& operator=(OwnedVector<U>&& other) V8_NOEXCEPT { - static_assert(sizeof(U) == sizeof(T)); - data_ = std::move(other.data_); - length_ = other.length_; - DCHECK_NULL(other.data_); - other.length_ = 0; - return *this; - } - - // Returns the length of the vector as a size_t. - constexpr size_t size() const { return length_; } - - // Returns whether or not the vector is empty. - constexpr bool empty() const { return length_ == 0; } - - constexpr T* begin() const V8_LIFETIME_BOUND { - DCHECK_IMPLIES(length_ > 0, data_ != nullptr); - return data_.get(); - } - - constexpr T* end() const V8_LIFETIME_BOUND { return begin() + length_; } - - // In addition to {begin}, do provide a {data()} accessor for API - // compatibility with other sequential containers. - constexpr T* data() const V8_LIFETIME_BOUND { return begin(); } - - constexpr std::reverse_iterator<T*> rbegin() const V8_LIFETIME_BOUND { - return std::make_reverse_iterator(end()); - } - constexpr std::reverse_iterator<T*> rend() const V8_LIFETIME_BOUND { - return std::make_reverse_iterator(begin()); - } - - // Access individual vector elements - checks bounds in debug mode. - T& operator[](size_t index) const V8_LIFETIME_BOUND { - DCHECK_LT(index, length_); - return data_[index]; - } - - // Returns a {Vector<T>} view of the data in this vector. - Vector<T> as_vector() const V8_LIFETIME_BOUND { return {begin(), size()}; } - - // Releases the backing data from this vector and transfers ownership to the - // caller. This vector will be empty afterwards. - std::unique_ptr<T[]> ReleaseData() { - length_ = 0; - return std::move(data_); - } - - // Allocates a new vector of the specified size via the default allocator. - // Elements in the new vector are value-initialized. - static OwnedVector<T> New(size_t size) { - if (size == 0) return {}; - return OwnedVector<T>(std::make_unique<T[]>(size), size); - } - - // Allocates a new vector of the specified size via the default allocator and - // initializes all elements by assigning from `init`. - template <typename U> - static OwnedVector<T> New(size_t size, U init) { - if (size == 0) return {}; - OwnedVector<T> vec = NewForOverwrite(size); - std::fill_n(vec.begin(), size, init); - return vec; - } - - // Allocates a new vector of the specified size via the default allocator. - // Elements in the new vector are default-initialized. - static OwnedVector<T> NewForOverwrite(size_t size) { - if (size == 0) return {}; - return OwnedVector<T>(std::make_unique_for_overwrite<T[]>(size), size); - } - - // Allocates a new vector containing the specified collection of values. - template <typename U> - static OwnedVector<U> NewByCopying(const U* data, size_t size) { - auto result = OwnedVector<U>::NewForOverwrite(size); - base::Copy(data, data + size, result.begin()); - return result; - } - - bool operator==(std::nullptr_t) const { return data_ == nullptr; } - - private: - template <typename U> - friend class OwnedVector; - - std::unique_ptr<T[]> data_; - size_t length_ = 0; -}; - -// The vectors returned by {StaticCharVector}, {CStrVector}, or {OneByteVector} -// do not contain a null-termination byte. If you want the null byte, use +// The vectors returned by {OneByteVector} or {StaticOneByteVector} do not +// contain a null-termination byte. If you want the null byte, use // {ArrayVector}. -// Known length, constexpr. -template <size_t N> -constexpr Vector<const char> StaticCharVector( - const char (&array V8_LIFETIME_BOUND)[N]) { - return {array, N - 1}; -} - -// Unknown length, not constexpr. -inline Vector<const char> CStrVector(const char* data V8_LIFETIME_BOUND) { - return {data, strlen(data)}; -} - -inline Vector<const char> StrVector(std::string_view str V8_LIFETIME_BOUND) { - return {str.data(), str.size()}; -} - // OneByteVector is never constexpr because the data pointer is // {reinterpret_cast}ed. inline Vector<const uint8_t> OneByteVector(const char* data V8_LIFETIME_BOUND, @@ -354,7 +239,6 @@ Vector<const uint8_t> StaticOneByteVector( // For string literals, ArrayVector("foo") returns a vector ['f', 'o', 'o', \0] // with length 4 and null-termination. -// If you want ['f', 'o', 'o'], use CStrVector("foo"). template <typename T, size_t N> inline constexpr Vector<T> ArrayVector(T (&arr V8_LIFETIME_BOUND)[N]) { return {arr, N}; @@ -383,87 +267,6 @@ inline constexpr Vector<const T> VectorOf( return VectorOf(list.begin(), list.size()); } -// Construct an OwnedVector from a start pointer and a size. -// The data will be copied. -template <typename T> -inline OwnedVector<T> OwnedCopyOf(const T* data, size_t size) { - return OwnedVector<T>::NewByCopying(data, size); -} - -// Construct an OwnedVector from anything compatible with std::data and -// std::size (e.g. an array, or a container providing a {data()} and {size()} -// accessor). The data will be copied. -template <typename Container> -inline auto OwnedCopyOf(const Container& c) - -> decltype(OwnedCopyOf(std::data(c), std::size(c))) { - return OwnedCopyOf(std::data(c), std::size(c)); -} - -// Container with a fixed storage for `kSize` elements. -template <typename T, size_t kSize> -class EmbeddedVector final { - public: - constexpr EmbeddedVector() = default; - constexpr explicit EmbeddedVector(const T& initial_value) { - std::fill_n(buffer_, kSize, initial_value); - } - EmbeddedVector(const EmbeddedVector&) = delete; - EmbeddedVector& operator=(const EmbeddedVector&) = delete; - - constexpr Vector<T> SubVector(size_t from, size_t to) V8_LIFETIME_BOUND { - DCHECK_LE(from, to); - DCHECK_LE(to, length_); - return Vector<T>(buffer_ + from, to - from); - } - - constexpr Vector<T> SubVectorFrom(size_t from) V8_LIFETIME_BOUND { - return SubVector(from, length_); - } - - constexpr size_t size() const { return length_; } - - constexpr T& operator[](size_t index) V8_LIFETIME_BOUND { - DCHECK_LT(index, length_); - return buffer_[index]; - } - - constexpr const T& operator[](size_t index) const V8_LIFETIME_BOUND { - DCHECK_LT(index, length_); - return buffer_[index]; - } - - constexpr T* begin() V8_LIFETIME_BOUND { return buffer_; } - constexpr const T* begin() const V8_LIFETIME_BOUND { return buffer_; } - - constexpr T* data() V8_LIFETIME_BOUND { return buffer_; } - - constexpr T* end() V8_LIFETIME_BOUND { return buffer_ + length_; } - constexpr const T* end() const V8_LIFETIME_BOUND { return buffer_ + length_; } - - constexpr void Truncate(size_t length) { - DCHECK_LE(length, length_); - length_ = length; - } - - constexpr const Vector<T> operator+(size_t offset) V8_LIFETIME_BOUND { - return SubVectorFrom(offset); - } - - constexpr operator Vector<T>() V8_LIFETIME_BOUND { - return Vector<T>(buffer_, length_); - } - - template <typename U> - requires std::is_convertible_v<T*, const U*> && (sizeof(U) == sizeof(T)) - constexpr operator Vector<const U>() const V8_LIFETIME_BOUND { - return Vector<const U>(buffer_, length_); - } - - private: - T buffer_[kSize]; - size_t length_ = kSize; -}; - } // namespace v8::base #endif // V8_BASE_VECTOR_H_ diff --git a/deps/v8/src/baseline/arm64/baseline-assembler-arm64-inl.h b/deps/v8/src/baseline/arm64/baseline-assembler-arm64-inl.h index 27399c6235f6..0198f49d81e1 100644 --- a/deps/v8/src/baseline/arm64/baseline-assembler-arm64-inl.h +++ b/deps/v8/src/baseline/arm64/baseline-assembler-arm64-inl.h @@ -213,6 +213,97 @@ void BaselineAssembler::SmiAddConstantAndJumpIfOverflow(Register value, __ Mov(value, tmp); } } + +void BaselineAssembler::SmiAddSubAndJumpIfOverflow( + Register output, Register lhs, Tagged<Smi> rhs, Operation operation, + Label* overflow, Label::Distance) { + DCHECK(IsInlineSmiArithmeticBinaryOperationSupported(operation)); + + ScratchRegisterScope scope(this); + Register result = scope.AcquireScratch(); + if (SmiValuesAre31Bits()) { + switch (operation) { + case Operation::kAdd: + __ Adds(result.W(), lhs.W(), Operand(rhs)); + break; + case Operation::kSubtract: + __ Subs(result.W(), lhs.W(), Operand(rhs)); + break; + default: + UNREACHABLE(); + } + __ B(overflow, vs); + __ Mov(output.W(), result.W()); + } else { + DCHECK(SmiValuesAre32Bits()); + switch (operation) { + case Operation::kAdd: + __ Adds(result, lhs, Operand(rhs)); + break; + case Operation::kSubtract: + __ Subs(result, lhs, Operand(rhs)); + break; + default: + UNREACHABLE(); + } + __ B(overflow, vs); + __ Mov(output, result); + } +} + +void BaselineAssembler::SmiBitwiseOp(Register lhs, Tagged<Smi> rhs, + Operation operation) { + DCHECK(IsInlineSmiBitwiseBinaryOperationSupported(operation)); + + if (SmiValuesAre31Bits()) { + switch (operation) { + case Operation::kShiftRight: { + const int shift = rhs.value() & 31; + if (shift == 0) return; + // Shift the tagged value, then clear the bit shifted into the Smi tag. + __ Asr(lhs.W(), lhs.W(), shift); + __ And(lhs.W(), lhs.W(), ~kSmiTagMask); + break; + } + case Operation::kBitwiseAnd: + __ And(lhs.W(), lhs.W(), Operand(rhs)); + break; + case Operation::kBitwiseOr: + __ Orr(lhs.W(), lhs.W(), Operand(rhs)); + break; + case Operation::kBitwiseXor: + __ Eor(lhs.W(), lhs.W(), Operand(rhs)); + break; + default: + UNREACHABLE(); + } + } else { + DCHECK(SmiValuesAre32Bits()); + switch (operation) { + case Operation::kShiftRight: { + const int shift = rhs.value() & 31; + if (shift == 0) return; + // Combine untagging with the shift, then restore the Smi tag and + // padding. + __ Asr(lhs, lhs, kSmiShiftSize + kSmiTagSize + shift); + __ Lsl(lhs, lhs, kSmiShiftSize + kSmiTagSize); + break; + } + case Operation::kBitwiseAnd: + __ And(lhs, lhs, Operand(rhs)); + break; + case Operation::kBitwiseOr: + __ Orr(lhs, lhs, Operand(rhs)); + break; + case Operation::kBitwiseXor: + __ Eor(lhs, lhs, Operand(rhs)); + break; + default: + UNREACHABLE(); + } + } +} + #endif // V8_ENABLE_SPARKPLUG_PLUS void BaselineAssembler::JumpIfTagged(Condition cc, Register value, diff --git a/deps/v8/src/baseline/baseline-assembler.h b/deps/v8/src/baseline/baseline-assembler.h index d5aebea695f4..f61a7400167c 100644 --- a/deps/v8/src/baseline/baseline-assembler.h +++ b/deps/v8/src/baseline/baseline-assembler.h @@ -252,6 +252,18 @@ class BaselineAssembler { inline void SmiAddConstantAndJumpIfOverflow( Register value, int constant, Label* overflow, Label::Distance distance = Label::kFar); + + // Computes a tagged Smi Add/Sub into |output|. |output| may alias |lhs|. + // Jumps to |overflow| without modifying |lhs| when the result is not a Smi. + inline void SmiAddSubAndJumpIfOverflow( + Register output, Register lhs, Tagged<Smi> rhs, Operation operation, + Label* overflow, Label::Distance distance = Label::kFar); + + // Computes BitwiseAnd/BitwiseOr/BitwiseXor/ShiftRight in place. + // TODO(yuheng): Add support for ShiftLeft and ShiftRightLogical with overflow + // checks. They are currently omitted because their results can exceed the Smi + // range. + inline void SmiBitwiseOp(Register lhs, Tagged<Smi> rhs, Operation operation); #endif // V8_ENABLE_SPARKPLUG_PLUS inline void Switch(Register reg, int case_value_base, Label** labels, diff --git a/deps/v8/src/baseline/baseline-batch-compiler.cc b/deps/v8/src/baseline/baseline-batch-compiler.cc index 11c2f01e589f..42a6e0b84534 100644 --- a/deps/v8/src/baseline/baseline-batch-compiler.cc +++ b/deps/v8/src/baseline/baseline-batch-compiler.cc @@ -6,7 +6,6 @@ #include <algorithm> -#include "src/base/fpu.h" #include "src/base/numerics/checked_math.h" #include "src/baseline/baseline-compiler.h" #include "src/codegen/compiler.h" @@ -159,8 +158,6 @@ class ConcurrentBaselineCompiler { outgoing_queue_(outcoming_queue) {} void Run(JobDelegate* delegate) override { - base::FlushDenormalsScope flush_denormals_scope( - isolate_->flush_denormals()); LocalIsolate local_isolate(isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&local_isolate); LocalHandleScope handle_scope(&local_isolate); diff --git a/deps/v8/src/baseline/baseline-compiler.cc b/deps/v8/src/baseline/baseline-compiler.cc index b09ed33e0085..d5991212e00f 100644 --- a/deps/v8/src/baseline/baseline-compiler.cc +++ b/deps/v8/src/baseline/baseline-compiler.cc @@ -5,10 +5,10 @@ #include "src/baseline/baseline-compiler.h" #include <algorithm> +#include <bit> #include <optional> #include <type_traits> -#include "src/base/bits.h" #include "src/base/logging.h" #include "src/base/numerics/clamped_math.h" #include "src/base/strong-alias.h" @@ -317,7 +317,7 @@ BaselineCompiler::BaselineCompiler( // // 16 + (bytecode size) / 4 bytecode_offset_table_builder_.Reserve( - base::bits::RoundUpToPowerOfTwo(16 + bytecode_->Size() / 4)); + std::bit_ceil<size_t>(16 + bytecode_->Size() / 4)); } void BaselineCompiler::GenerateCode() { @@ -576,13 +576,16 @@ void BaselineCompiler::VisitSingleBytecode() { #ifdef DEBUG std::optional<EnsureAccumulatorPreservedScope> accumulator_preserved_scope; // We should make sure to preserve the accumulator whenever the bytecode - // isn't registered as writing to it. We can't do this for jumps or switches - // though, since the control flow would not match the control flow of this - // scope. + // isn't registered as writing to it. We can't do this for jumps, switches, + // returns, unconditional throws, or aborts though, since control flow does + // not fall through to the end of this scope. if (v8_flags.slow_debug_code && !interpreter::Bytecodes::WritesOrClobbersAccumulator(bytecode) && !interpreter::Bytecodes::IsJump(bytecode) && - !interpreter::Bytecodes::IsSwitch(bytecode)) { + !interpreter::Bytecodes::IsSwitch(bytecode) && + !interpreter::Bytecodes::Returns(bytecode) && + !interpreter::Bytecodes::UnconditionallyThrows(bytecode) && + bytecode != interpreter::Bytecode::kAbort) { accumulator_preserved_scope.emplace(&basm_); } #endif // DEBUG @@ -685,19 +688,12 @@ void BaselineCompiler::UpdateInterruptBudgetAndJumpToLabel( } void BaselineCompiler::JumpIfRoot(RootIndex root) { - Label dont_jump; - __ JumpIfNotRoot(kInterpreterAccumulatorRegister, root, &dont_jump, - Label::kNear); - __ Jump(BuildForwardJumpLabel()); - __ Bind(&dont_jump); + __ JumpIfRoot(kInterpreterAccumulatorRegister, root, BuildForwardJumpLabel()); } void BaselineCompiler::JumpIfNotRoot(RootIndex root) { - Label dont_jump; - __ JumpIfRoot(kInterpreterAccumulatorRegister, root, &dont_jump, - Label::kNear); - __ Jump(BuildForwardJumpLabel()); - __ Bind(&dont_jump); + __ JumpIfNotRoot(kInterpreterAccumulatorRegister, root, + BuildForwardJumpLabel()); } Label* BaselineCompiler::BuildForwardJumpLabel() { @@ -1271,9 +1267,27 @@ void BaselineCompiler::VisitDefineKeyedOwnPropertyInLiteral() { using Feedback = BinaryOperationFeedback; \ auto feedback_index_offset = \ iterator().GetEmbeddedFeedbackOffset(kEmbeddedFeedbackOperandIndex); \ + auto feedback_type = \ + Feedback::DecodeTypeIndex(static_cast<Feedback::TypeIndex>( \ + EmbeddedFeedback(kEmbeddedFeedbackOperandIndex))); \ + /* Use a lambda to discard the helper call for non-Smi operators. */ \ + if ([&](auto lhs, auto rhs) { \ + if constexpr (std::is_same_v<decltype(rhs), Tagged<Smi>> && \ + (IsInlineSmiArithmeticBinaryOperationSupported( \ + Operation::k##Name) || \ + IsInlineSmiBitwiseBinaryOperationSupported( \ + Operation::k##Name))) { \ + return TryEmitInlineSmiBinaryOperation< \ + Operation::k##Name, Builtin::k##Name##_SignedSmall_Baseline, \ + Builtin::k##GenericName##_Generic_Baseline>( \ + feedback_type, feedback_index_offset, lhs, rhs); \ + } \ + return false; \ + }(Lhs, Rhs)) { \ + return; \ + } \ if (allow_sparkplug_plus_) { \ - switch (Feedback::DecodeTypeIndex(static_cast<Feedback::TypeIndex>( \ - EmbeddedFeedback(kEmbeddedFeedbackOperandIndex)))) { \ + switch (feedback_type) { \ TypedStubList(TYPED_BINOP_CASE, Name, Lhs, Rhs) default \ : CallBuiltin<Builtin::k##GenericName##_Generic_Baseline>( \ Lhs, Rhs, feedback_index_offset); \ @@ -1480,6 +1494,43 @@ void BaselineCompiler::VisitShiftRightLogicalSmi() { #undef VISIT_TYPED_BINARY_OPERATION #ifdef V8_ENABLE_SPARKPLUG_PLUS +template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> +bool BaselineCompiler::TryEmitInlineSmiBinaryOperation( + BinaryOperationFeedback::Type feedback_type, int feedback_index_offset, + Register lhs, Tagged<Smi> rhs) { + if constexpr (!IsInlineSmiArithmeticBinaryOperationSupported(kOperation) && + !IsInlineSmiBitwiseBinaryOperationSupported(kOperation)) { + return false; + } + if (!v8_flags.sparkplug_inline_smi || + feedback_type != BinaryOperationFeedback::Type::kSignedSmall) { + return false; + } + + DCHECK_EQ(lhs, kInterpreterAccumulatorRegister); + ASM_CODE_COMMENT_STRING(&masm_, "inlined Smi binary immediate fast path"); + Label slow, done; + __ JumpIfNotSmi(lhs, &slow, Label::kNear); + if constexpr (IsInlineSmiArithmeticBinaryOperationSupported(kOperation)) { + __ SmiAddSubAndJumpIfOverflow(kInterpreterAccumulatorRegister, lhs, rhs, + kOperation, &slow, Label::kNear); + } else if constexpr (IsInlineSmiBitwiseBinaryOperationSupported(kOperation)) { + __ SmiBitwiseOp(lhs, rhs, kOperation); + } else { + UNREACHABLE(); + } + __ Jump(&done, Label::kNear); + + __ Bind(&slow); + if (allow_sparkplug_plus_) { + CallBuiltin<kSmiBuiltin>(lhs, rhs, feedback_index_offset); + } else { + CallBuiltin<kGenericBuiltin>(lhs, rhs, feedback_index_offset); + } + __ Bind(&done); + return true; +} + template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> bool BaselineCompiler::TryEmitInlineSmiUnary( BinaryOperationFeedback::Type feedback_type, int feedback_index_offset) { @@ -1983,6 +2034,33 @@ void BaselineCompiler::VisitConstructForwardAllArgs() { } #ifdef V8_ENABLE_SPARKPLUG_PLUS +std::optional<BaselineCompiler::CompareBranchCandidate> +BaselineCompiler::GetCompareBranchCandidate() { +#ifdef V8_TRACE_UNOPTIMIZED + if (v8_flags.trace_baseline_exec) return std::nullopt; +#endif +#ifdef V8_DUMPLING + if (v8_flags.sparkplug_dumping) return std::nullopt; +#endif + if (v8_flags.slow_debug_code) return std::nullopt; + + DisallowGarbageCollection no_gc; + interpreter::BytecodeArrayIterator next_iterator = iterator().Clone(no_gc); + next_iterator.Advance(); + switch (next_iterator.current_bytecode()) { + case interpreter::Bytecode::kJumpIfTrue: + case interpreter::Bytecode::kJumpIfTrueConstant: + return CompareBranchCandidate{next_iterator.GetJumpTargetOffset(), + next_iterator.next_offset()}; + case interpreter::Bytecode::kJumpIfFalse: + case interpreter::Bytecode::kJumpIfFalseConstant: + return CompareBranchCandidate{next_iterator.next_offset(), + next_iterator.GetJumpTargetOffset()}; + default: + return std::nullopt; + } +} + template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> bool BaselineCompiler::TryEmitInlineSmiCompare( CompareOperationFeedback::Type feedback_type, int feedback_index_offset) { @@ -1995,51 +2073,59 @@ bool BaselineCompiler::TryEmitInlineSmiCompare( } ASM_CODE_COMMENT_STRING(&masm_, "inlined Smi compare fast path"); - Label slow, done; - { - BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_); - Register lhs = scratch_scope.AcquireScratch(); - __ Move(lhs, RegisterOperand(0)); + Label slow, done, if_true; + std::optional<CompareBranchCandidate> candidate = GetCompareBranchCandidate(); + + BaselineAssembler::ScratchRegisterScope scratch_scope(&basm_); + Register lhs = scratch_scope.AcquireScratch(); + __ Move(lhs, RegisterOperand(0)); + if constexpr (kOperation == Operation::kEqual || + kOperation == Operation::kStrictEqual) { + // Equal Smis have identical tagged values, so check lhs first and let a + // tagged-equal hit return true without checking rhs. Only the not-equal + // edge needs to verify rhs before returning false. + __ JumpIfNotSmi(lhs, &slow, Label::kNear); + } else { + __ JumpIfNotBothSmi(lhs, kInterpreterAccumulatorRegister, &slow, + Label::kNear); + } + + auto jump_if_true = [&](Label* true_target, Label::Distance distance) { if constexpr (kOperation == Operation::kEqual || kOperation == Operation::kStrictEqual) { - // Equal Smis have identical tagged values, so check lhs first and let a - // tagged-equal hit return true without checking rhs. Only the not-equal - // edge needs to verify rhs before returning false. - __ JumpIfNotSmi(lhs, &slow, Label::kNear); + __ JumpIfTagged(kEqual, lhs, kInterpreterAccumulatorRegister, true_target, + distance); + // Neither path writes the boolean result before this check, so the + // accumulator still holds the rhs on the path to `slow`. + __ JumpIfNotSmi(kInterpreterAccumulatorRegister, &slow, Label::kNear); + } else if constexpr (kOperation == Operation::kLessThan) { + __ JumpIfTagged(kLessThan, lhs, kInterpreterAccumulatorRegister, + true_target, distance); + } else if constexpr (kOperation == Operation::kLessThanOrEqual) { + __ JumpIfTagged(kLessThanEqual, lhs, kInterpreterAccumulatorRegister, + true_target, distance); + } else if constexpr (kOperation == Operation::kGreaterThan) { + __ JumpIfTagged(kLessThan, kInterpreterAccumulatorRegister, lhs, + true_target, distance); } else { - __ JumpIfNotBothSmi(lhs, kInterpreterAccumulatorRegister, &slow, - Label::kNear); + static_assert(kOperation == Operation::kGreaterThanOrEqual); + __ JumpIfTagged(kLessThanEqual, kInterpreterAccumulatorRegister, lhs, + true_target, distance); } + }; + + if (candidate) { + jump_if_true(&if_true, Label::kNear); + __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kFalseValue); + __ Jump(EnsureLabel(candidate->false_offset)); - SelectBooleanConstant( - kInterpreterAccumulatorRegister, - [&](Label* if_true, Label::Distance distance) { - if constexpr (kOperation == Operation::kEqual || - kOperation == Operation::kStrictEqual) { - __ JumpIfTagged(kEqual, lhs, kInterpreterAccumulatorRegister, - if_true, distance); - // SelectBooleanConstant evaluates the condition before writing its - // output register, so the accumulator still holds the rhs on the - // path to `slow`. - __ JumpIfNotSmi(kInterpreterAccumulatorRegister, &slow, - Label::kNear); - } else if constexpr (kOperation == Operation::kLessThan) { - __ JumpIfTagged(kLessThan, lhs, kInterpreterAccumulatorRegister, - if_true, distance); - } else if constexpr (kOperation == Operation::kLessThanOrEqual) { - __ JumpIfTagged(kLessThanEqual, lhs, - kInterpreterAccumulatorRegister, if_true, distance); - } else if constexpr (kOperation == Operation::kGreaterThan) { - __ JumpIfTagged(kLessThan, kInterpreterAccumulatorRegister, lhs, - if_true, distance); - } else { - static_assert(kOperation == Operation::kGreaterThanOrEqual); - __ JumpIfTagged(kLessThanEqual, kInterpreterAccumulatorRegister, - lhs, if_true, distance); - } - }); + __ Bind(&if_true); + __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kTrueValue); + __ Jump(EnsureLabel(candidate->true_offset)); + } else { + SelectBooleanConstant(kInterpreterAccumulatorRegister, jump_if_true); + __ Jump(&done); } - __ Jump(&done); __ Bind(&slow); if (allow_sparkplug_plus_) { @@ -2052,7 +2138,6 @@ bool BaselineCompiler::TryEmitInlineSmiCompare( feedback_index_offset); } __ Bind(&done); - return true; } #endif // V8_ENABLE_SPARKPLUG_PLUS @@ -2484,11 +2569,8 @@ void BaselineCompiler::VisitCreateClosure() { CallBuiltin<Builtin::kFastNewClosureBaseline>( Constant<SharedFunctionInfo>(0), feedback_cell); } else { - Runtime::FunctionId function_id = - interpreter::CreateClosureFlags::PretenuredBit::decode(flags) - ? Runtime::kNewClosure_Tenured - : Runtime::kNewClosure; - CallRuntime(function_id, Constant<SharedFunctionInfo>(0), feedback_cell); + CallRuntime(Runtime::kNewClosure, Constant<SharedFunctionInfo>(0), + feedback_cell); } } @@ -2568,10 +2650,10 @@ void BaselineCompiler::VisitJumpLoop() { LoadFeedbackVector(feedback_vector); __ LoadWord8Field(osr_state, feedback_vector, offsetof(::v8::internal::FeedbackVector, osr_state_)); - static_assert(FeedbackVector::MaybeHasMaglevOsrCodeBit::encode(true) > - FeedbackVector::kMaxOsrUrgency); - static_assert(FeedbackVector::MaybeHasTurbofanOsrCodeBit::encode(true) > - FeedbackVector::kMaxOsrUrgency); + static_assert(FeedbackVector::OsrState::MaybeHasMaglevOsrCodeBit::encode( + true) > FeedbackVector::kMaxOsrUrgency); + static_assert(FeedbackVector::OsrState::MaybeHasTurbofanOsrCodeBit::encode( + true) > FeedbackVector::kMaxOsrUrgency); __ JumpIfByte(kUnsignedGreaterThan, osr_state, loop_depth, &osr_armed, Label::kNear); } @@ -2609,7 +2691,7 @@ void BaselineCompiler::VisitJumpLoop() { __ TryLoadOptimizedOsrCode(maybe_target_code, scratch0, iterator().GetSlotOperand(2), &osr, Label::kNear); - __ DecodeField<FeedbackVector::OsrUrgencyBits>(scratch1); + __ DecodeField<FeedbackVector::OsrState::OsrUrgencyBits>(scratch1); __ JumpIfByte(kUnsignedLessThanEqual, scratch1, loop_depth, &osr_not_armed, Label::kNear); } diff --git a/deps/v8/src/baseline/baseline-compiler.h b/deps/v8/src/baseline/baseline-compiler.h index 724996805a55..f08070c29ac1 100644 --- a/deps/v8/src/baseline/baseline-compiler.h +++ b/deps/v8/src/baseline/baseline-compiler.h @@ -5,6 +5,8 @@ #ifndef V8_BASELINE_BASELINE_COMPILER_H_ #define V8_BASELINE_BASELINE_COMPILER_H_ +#include <optional> + #include "src/base/logging.h" #include "src/base/numerics/checked_math.h" #include "src/base/pointer-with-payload.h" @@ -141,20 +143,34 @@ class BaselineCompiler { #ifdef V8_ENABLE_SPARKPLUG_PLUS // Emits an inlined Smi compare for |kOperation|, followed by a slow-path - // call to |kSmiStub|. Returns false without emitting anything when inlining - // is disabled or when the compile-time embedded feedback hint is not exactly - // kSignedSmall. + // call to |kSmiBuiltin|. Returns false without emitting anything when + // inlining is disabled or when the compile-time embedded feedback hint is not + // exactly kSignedSmall. template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> bool TryEmitInlineSmiCompare(CompareOperationFeedback::Type feedback_type, int feedback_index_offset); // Emits an inlined Smi Inc/Dec for |kOperation|, followed by a slow-path - // call to |kSmiStub|. Returns false without emitting anything when inlining - // is disabled or when the compile-time embedded feedback hint is not exactly - // kSignedSmall. + // call to |kSmiBuiltin|. Returns false without emitting anything when + // inlining is disabled or when the compile-time embedded feedback hint is not + // exactly kSignedSmall. template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> bool TryEmitInlineSmiUnary(BinaryOperationFeedback::Type feedback_type, int feedback_index_offset); + + struct CompareBranchCandidate { + int true_offset; + int false_offset; + }; + + std::optional<CompareBranchCandidate> GetCompareBranchCandidate(); + + // Emits an inlined Smi Add/Sub/And/Or/Xor/ShiftRight followed by a slow-path + // call to |kSmiBuiltin|. + template <Operation kOperation, Builtin kSmiBuiltin, Builtin kGenericBuiltin> + bool TryEmitInlineSmiBinaryOperation( + BinaryOperationFeedback::Type feedback_type, int feedback_index_offset, + Register lhs, Tagged<Smi> rhs); #endif // V8_ENABLE_SPARKPLUG_PLUS // Jumps based on calling ToBoolean on kInterpreterAccumulatorRegister. diff --git a/deps/v8/src/baseline/loong64/baseline-assembler-loong64-inl.h b/deps/v8/src/baseline/loong64/baseline-assembler-loong64-inl.h index 3398e47e6b4d..ebf207276d9c 100644 --- a/deps/v8/src/baseline/loong64/baseline-assembler-loong64-inl.h +++ b/deps/v8/src/baseline/loong64/baseline-assembler-loong64-inl.h @@ -212,6 +212,104 @@ void BaselineAssembler::SmiAddConstantAndJumpIfOverflow(Register value, __ Move(value, scratch1); } } + +void BaselineAssembler::SmiAddSubAndJumpIfOverflow( + Register output, Register lhs, Tagged<Smi> rhs, Operation operation, + Label* overflow, Label::Distance) { + DCHECK(IsInlineSmiArithmeticBinaryOperationSupported(operation)); + + const int rhs_value = rhs.value(); + ScratchRegisterScope temps(this); + if (SmiValuesAre31Bits()) { + Register canonical_lhs = temps.AcquireScratch(); + Register result = temps.AcquireScratch(); + __ slli_w(canonical_lhs, lhs, 0); + switch (operation) { + case Operation::kAdd: + __ Add_w(result, canonical_lhs, Operand(rhs)); + __ Branch(overflow, rhs_value > 0 ? lt : gt, result, + Operand(canonical_lhs)); + break; + case Operation::kSubtract: + __ Sub_w(result, canonical_lhs, Operand(rhs)); + __ Branch(overflow, rhs_value > 0 ? gt : lt, result, + Operand(canonical_lhs)); + break; + default: + UNREACHABLE(); + } + __ Move(output, result); + } else { + DCHECK(SmiValuesAre32Bits()); + Register result = temps.AcquireScratch(); + switch (operation) { + case Operation::kAdd: + __ Add_d(result, lhs, Operand(rhs)); + __ Branch(overflow, rhs_value > 0 ? lt : gt, result, Operand(lhs)); + break; + case Operation::kSubtract: + __ Sub_d(result, lhs, Operand(rhs)); + __ Branch(overflow, rhs_value > 0 ? gt : lt, result, Operand(lhs)); + break; + default: + UNREACHABLE(); + } + __ Move(output, result); + } +} + +void BaselineAssembler::SmiBitwiseOp(Register lhs, Tagged<Smi> rhs, + Operation operation) { + DCHECK(IsInlineSmiBitwiseBinaryOperationSupported(operation)); + + if (SmiValuesAre31Bits()) { + switch (operation) { + case Operation::kShiftRight: { + const int shift = rhs.value() & 31; + if (shift == 0) return; + // Shift the tagged value, then clear the bit shifted into the Smi tag. + __ srai_w(lhs, lhs, shift); + __ bstrins_d(lhs, zero_reg, 0, 0); + break; + } + case Operation::kBitwiseAnd: + __ And(lhs, lhs, Operand(rhs)); + break; + case Operation::kBitwiseOr: + __ Or(lhs, lhs, Operand(rhs)); + break; + case Operation::kBitwiseXor: + __ Xor(lhs, lhs, Operand(rhs)); + break; + default: + UNREACHABLE(); + } + } else { + DCHECK(SmiValuesAre32Bits()); + switch (operation) { + case Operation::kShiftRight: { + const int shift = rhs.value() & 31; + if (shift == 0) return; + // Combine untagging with the shift, then restore the Smi tag and + // padding. + __ srai_d(lhs, lhs, kSmiShiftSize + kSmiTagSize + shift); + __ slli_d(lhs, lhs, kSmiShiftSize + kSmiTagSize); + break; + } + case Operation::kBitwiseAnd: + __ And(lhs, lhs, Operand(rhs)); + break; + case Operation::kBitwiseOr: + __ Or(lhs, lhs, Operand(rhs)); + break; + case Operation::kBitwiseXor: + __ Xor(lhs, lhs, Operand(rhs)); + break; + default: + UNREACHABLE(); + } + } +} #endif // V8_ENABLE_SPARKPLUG_PLUS #ifdef V8_STATIC_ROOTS diff --git a/deps/v8/src/baseline/x64/baseline-assembler-x64-inl.h b/deps/v8/src/baseline/x64/baseline-assembler-x64-inl.h index ac3f109e7f2a..3496714ee975 100644 --- a/deps/v8/src/baseline/x64/baseline-assembler-x64-inl.h +++ b/deps/v8/src/baseline/x64/baseline-assembler-x64-inl.h @@ -215,6 +215,110 @@ void BaselineAssembler::SmiAddConstantAndJumpIfOverflow( __ movq(value, tmp); } } + +void BaselineAssembler::SmiAddSubAndJumpIfOverflow( + Register output, Register lhs, Tagged<Smi> rhs, Operation operation, + Label* overflow, Label::Distance distance) { + DCHECK(IsInlineSmiArithmeticBinaryOperationSupported(operation)); + + ScratchRegisterScope scope(this); + Register result = scope.AcquireScratch(); + if (SmiValuesAre31Bits()) { + __ movl(result, lhs); + switch (operation) { + case Operation::kAdd: + __ addl(result, Immediate(rhs)); + break; + case Operation::kSubtract: + __ subl(result, Immediate(rhs)); + break; + default: + UNREACHABLE(); + } + __ j(kOverflow, overflow, distance); + __ movl(output, result); + } else { + DCHECK(SmiValuesAre32Bits()); + Register tmp = scope.AcquireScratch(); + __ Move(tmp, rhs); + __ movq(result, lhs); + switch (operation) { + case Operation::kAdd: + __ addq(result, tmp); + break; + case Operation::kSubtract: + __ subq(result, tmp); + break; + default: + UNREACHABLE(); + } + __ j(kOverflow, overflow, distance); + __ movq(output, result); + } +} + +void BaselineAssembler::SmiBitwiseOp(Register lhs, Tagged<Smi> rhs, + Operation operation) { + DCHECK(IsInlineSmiBitwiseBinaryOperationSupported(operation)); + + if (SmiValuesAre31Bits()) { + switch (operation) { + case Operation::kShiftRight: { + const int shift = rhs.value() & 31; + if (shift == 0) return; + // Shift the tagged value, then clear the bit shifted into the Smi tag. + static_assert(kSmiTag == 0); + __ sarl(lhs, Immediate(shift)); + __ andl(lhs, Immediate(~kSmiTagMask)); + break; + } + case Operation::kBitwiseAnd: + __ andl(lhs, Immediate(rhs)); + break; + case Operation::kBitwiseOr: + __ orl(lhs, Immediate(rhs)); + break; + case Operation::kBitwiseXor: + __ xorl(lhs, Immediate(rhs)); + break; + default: + UNREACHABLE(); + } + } else { + DCHECK(SmiValuesAre32Bits()); + ScratchRegisterScope scope(this); + Register tmp = scope.AcquireScratch(); + switch (operation) { + case Operation::kShiftRight: { + const int shift = rhs.value() & 31; + if (shift == 0) return; + // Combine untagging with the shift, then restore the Smi tag and + // padding. + __ sarq(lhs, Immediate(kSmiShiftSize + kSmiTagSize + shift)); + __ shlq(lhs, Immediate(kSmiShiftSize + kSmiTagSize)); + break; + } + case Operation::kBitwiseAnd: { + __ Move(tmp, rhs); + __ andq(lhs, tmp); + break; + } + case Operation::kBitwiseOr: { + __ Move(tmp, rhs); + __ orq(lhs, tmp); + break; + } + case Operation::kBitwiseXor: { + __ Move(tmp, rhs); + __ xorq(lhs, tmp); + break; + } + default: + UNREACHABLE(); + } + } +} + #endif // V8_ENABLE_SPARKPLUG_PLUS void BaselineAssembler::JumpIfImmediate(Condition cc, Register left, int right, diff --git a/deps/v8/src/baseline/x64/baseline-compiler-x64-inl.h b/deps/v8/src/baseline/x64/baseline-compiler-x64-inl.h index 49e48c8f69c0..e4b3f7846316 100644 --- a/deps/v8/src/baseline/x64/baseline-compiler-x64-inl.h +++ b/deps/v8/src/baseline/x64/baseline-compiler-x64-inl.h @@ -84,14 +84,21 @@ void BaselineCompiler::PrologueFillFrame() { __ masm()->decl(scratch); __ masm()->j(greater, &loop); } + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL && + (bytecode_->register_count() & 1) != 0) { + __ Push(kInterpreterAccumulatorRegister); + } } void BaselineCompiler::VerifyFrameSize() { ASM_CODE_COMMENT(&masm_); __ Move(kScratchRegister, rsp); - __ masm()->addq(kScratchRegister, - Immediate(InterpreterFrameConstants::kFixedFrameSizeFromFp + - bytecode_->frame_size())); + __ masm() -> addq( + kScratchRegister, + Immediate(RoundUp( + InterpreterFrameConstants::kFixedFrameSizeFromFp + + bytecode_->frame_size(), + V8_X64_16BYTE_STACK_ALIGNMENT_BOOL ? 2 * kSystemPointerSize : 1))); __ masm()->cmpq(kScratchRegister, rbp); __ masm()->Assert(equal, AbortReason::kUnexpectedStackPointer); } diff --git a/deps/v8/src/builtins/accessors.cc b/deps/v8/src/builtins/accessors.cc index 313ac22137cd..c3223b6448e0 100644 --- a/deps/v8/src/builtins/accessors.cc +++ b/deps/v8/src/builtins/accessors.cc @@ -426,17 +426,6 @@ Handle<JSObject> ArgumentsFromDeoptInfo(JavaScriptFrame* frame, return arguments; } -int FindFunctionInFrame(JavaScriptFrame* frame, - DirectHandle<JSFunction> function) { - FrameSummaries summaries = frame->Summarize(); - for (int i = summaries.size(); i != 0; i--) { - if (*summaries.frames[i - 1].AsJavaScript().function() == *function) { - return static_cast<int>(i) - 1; - } - } - return -1; -} - Handle<JSObject> GetFrameArguments(Isolate* isolate, JavaScriptStackFrameIterator* it, int function_index) { @@ -506,55 +495,43 @@ Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame, UNREACHABLE(); // Requested frame not found. } +static inline bool AllowAccessToFunction(Tagged<Context> current_context, + Tagged<JSFunction> function) { + return current_context->native_context()->HasSameSecurityTokenAs( + function->context()->native_context()); +} + // static DirectHandle<Object> Accessors::GetLegacyFunctionArguments( Isolate* isolate, DirectHandle<JSFunction> function) { - DirectHandle<Object> result = isolate->factory()->null_value(); + DirectHandle<Object> null_value = isolate->factory()->null_value(); + // Don't return arguments from another security context. + if (!AllowAccessToFunction(isolate->context(), *function)) return null_value; if (!function->shared()->native()) { // Find the top invocation of the function by traversing frames. for (JavaScriptStackFrameIterator it(isolate); !it.done(); it.Advance()) { JavaScriptFrame* frame = it.frame(); - int function_index = FindFunctionInFrame(frame, function); - if (function_index >= 0) { - result = GetFrameArguments(isolate, &it, function_index); - break; + FrameSummaries summaries = frame->Summarize(); + for (int i = summaries.size() - 1; i >= 0; i--) { + DirectHandle<JSFunction> frame_function = + summaries.frames[i].AsJavaScript().function(); + // Don't cross origins boundary we are not allowed to access. + if (!AllowAccessToFunction(isolate->context(), *frame_function)) { + return null_value; + } + if (*frame_function == *function) { + return GetFrameArguments(isolate, &it, i); + } } } } - return result; -} - -#ifdef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - -void Accessors::FunctionArgumentsGetter( - v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); - RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionArgumentsGetter); - isolate->CountUsage(v8::Isolate::kFunctionPrototypeArguments); - HandleScope scope(isolate); - auto function = Cast<JSFunction>(Utils::OpenDirectHandle(*info.Holder())); - DirectHandle<Object> result = GetLegacyFunctionArguments(isolate, function); - info.GetReturnValue().Set(Utils::ToLocal(result)); -} - -DirectHandle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo( - Isolate* isolate) { - return MakeAccessor(isolate, isolate->factory()->arguments_string(), - &FunctionArgumentsGetter, nullptr); + return null_value; } -#endif // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - // // Accessors::FunctionCaller // -static inline bool AllowAccessToFunction(Tagged<Context> current_context, - Tagged<JSFunction> function) { - return current_context->native_context()->HasSameSecurityTokenAs( - function->context()->native_context()); -} - class FrameFunctionIterator { public: explicit FrameFunctionIterator(Isolate* isolate) @@ -626,8 +603,10 @@ class FrameFunctionIterator { --inlined_frame_index_; DirectHandle<JSFunction> next_function = summaries_.frames[inlined_frame_index_].AsJavaScript().function(); - // Skip functions from other origins. - if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue; + // Don't cross origins boundary we are not allowed to access. + if (!AllowAccessToFunction(isolate_->context(), *next_function)) { + return {}; + } return next_function; } } @@ -686,7 +665,7 @@ MaybeDirectHandle<JSFunction> FindCaller(Isolate* isolate, if (is_strict(caller->shared()->language_mode())) { return {}; } - // Don't return caller from another security context. + // Don't cross origins boundary we are not allowed to access. if (!AllowAccessToFunction(isolate->context(), *caller)) { return {}; } @@ -711,27 +690,6 @@ DirectHandle<Object> Accessors::GetLegacyFunctionCaller( return result; } -#ifdef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - -void Accessors::FunctionCallerGetter( - v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); - RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionCallerGetter); - isolate->CountUsage(v8::Isolate::kFunctionPrototypeCaller); - HandleScope scope(isolate); - DirectHandle<JSFunction> function = - Cast<JSFunction>(Utils::OpenDirectHandle(*info.Holder())); - DirectHandle<Object> result = GetLegacyFunctionCaller(isolate, function); - info.GetReturnValue().Set(Utils::ToLocal(result)); -} - -DirectHandle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) { - return MakeAccessor(isolate, isolate->factory()->caller_string(), - &FunctionCallerGetter, nullptr); -} - -#endif // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - // // Accessors::BoundFunctionLength // diff --git a/deps/v8/src/builtins/accessors.h b/deps/v8/src/builtins/accessors.h index 172a2429f0fc..8a80ffc41519 100644 --- a/deps/v8/src/builtins/accessors.h +++ b/deps/v8/src/builtins/accessors.h @@ -31,12 +31,6 @@ class JavaScriptFrame; kHasSideEffectToReceiver) \ V(_, bound_function_name, BoundFunctionName, kHasNoSideEffect, \ kHasSideEffectToReceiver) \ - IF_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS( \ - V, _, function_arguments, FunctionArguments, kHasNoSideEffect, \ - kHasSideEffectToReceiver) \ - IF_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS(V, _, function_caller, \ - FunctionCaller, kHasNoSideEffect, \ - kHasSideEffectToReceiver) \ V(_, function_name, FunctionName, kHasNoSideEffect, \ kHasSideEffectToReceiver) \ V(_, function_length, FunctionLength, kHasNoSideEffect, \ @@ -122,8 +116,7 @@ class Accessors : public AllStatic { // Used to implement legacy .arguments and .caller. // - // TODO(syg): Move these out of accessors once - // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS is removed. + // TODO(https://crbug.com/414525205): Move these out of accessors. static DirectHandle<Object> GetLegacyFunctionArguments( Isolate* isolate, DirectHandle<JSFunction> function); static DirectHandle<Object> GetLegacyFunctionCaller( diff --git a/deps/v8/src/builtins/arm/builtins-arm.cc b/deps/v8/src/builtins/arm/builtins-arm.cc index b3b37efa1f84..f9c79a9c8b67 100644 --- a/deps/v8/src/builtins/arm/builtins-arm.cc +++ b/deps/v8/src/builtins/arm/builtins-arm.cc @@ -176,7 +176,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ ldr(r4, FieldMemOperand(r1, offsetof(JSFunction, shared_function_info_))); __ ldr(r4, FieldMemOperand(r4, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(r4); __ JumpIfIsInRange( r4, r4, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -928,7 +928,8 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ ldrb(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ and_(scratch, scratch, Operand(~FeedbackVector::OsrUrgencyBits::kMask)); + __ and_(scratch, scratch, + Operand(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ strb(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -1160,9 +1161,12 @@ void Builtins::Generate_InterpreterEntryTrampoline( // Load frame size from the BytecodeArray object. __ ldr(r4, FieldMemOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + __ ldrh(r9, FieldMemOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ add(r9, r4, Operand(r9, LSL, kSystemPointerSizeLog2)); // Do a stack check to ensure we don't go over the limit. - __ sub(r9, sp, Operand(r4)); + __ sub(r9, sp, Operand(r9)); __ LoadStackLimit(r2, StackLimitKind::kRealStackLimit); __ cmp(r9, Operand(r2)); __ b(lo, &stack_overflow); @@ -1579,12 +1583,12 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( Label builtin_call; __ ldr(r2, FieldMemOperand(r1, offsetof(JSFunction, shared_function_info_))); __ ldr(r2, FieldMemOperand(r2, offsetof(SharedFunctionInfo, flags_))); - __ tst(r2, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ tst(r2, Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ b(ne, &builtin_call); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(r2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(r2); __ JumpIfIsInRange( r2, r2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -2479,8 +2483,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, // We need to convert the receiver for non-native sloppy mode functions. Label done_convert; __ ldr(r3, FieldMemOperand(r2, offsetof(SharedFunctionInfo, flags_))); - __ tst(r3, Operand(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + __ tst(r3, Operand(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); __ b(ne, &done_convert); { // ----------- S t a t e ------------- @@ -2678,7 +2682,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { // Jump to JSBuiltinsConstructStub or JSConstructStubGeneric. __ ldr(r4, FieldMemOperand(r1, offsetof(JSFunction, shared_function_info_))); __ ldr(r4, FieldMemOperand(r4, offsetof(SharedFunctionInfo, flags_))); - __ tst(r4, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ tst(r4, Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ b(eq, &call_generic_stub); __ TailCallBuiltin(Builtin::kJSBuiltinsConstructStub); @@ -2917,7 +2921,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameAndConstantPoolScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. constexpr DwVfpRegister first = WasmDebugBreakFrameConstants::kPushedFpRegs.first(); constexpr DwVfpRegister last = @@ -2959,7 +2968,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3794,6 +3803,7 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; auto regs = RegisterAllocator::WithAllocatableGeneralRegisters(); __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); @@ -3812,6 +3822,16 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { Label suspend; Register original_fp = no_reg; Register new_wrapper_buffer = no_reg; + + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int unpadded_stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; + constexpr int param_padding = + unpadded_stack_params_offset & kSystemPointerSize; + constexpr int stack_params_offset = + unpadded_stack_params_offset + param_padding; if (stack_switch) { SwitchToAllocatedStack(masm, regs, implicit_arg, wrapper_buffer, original_fp, new_wrapper_buffer, &suspend); @@ -3836,14 +3856,59 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ str(scratch, MemOperand(fp, WasmJspiFrameConstants::kResultArrayOffset)); + __ Zero(MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); } } + { - DEFINE_SCOPED(result_size); - __ ldr(result_size, + DEFINE_SCOPED(return_space); + // Calculate the stack space required for return values (in bytes). + __ ldr(return_space, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants:: kWrapperBufferStackReturnBufferSize)); - __ sub(sp, sp, Operand(result_size, LSL, kSystemPointerSizeLog2)); + __ mov(return_space, Operand(return_space, LSL, kSystemPointerSizeLog2)); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we + // calculate the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + DEFINE_SCOPED(total_space); + __ ldr(total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + DEFINE_SCOPED(params_start); + __ ldr( + params_start, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ sub(total_space, total_space, params_start); + __ sub(total_space, total_space, Operand(stack_params_offset)); + __ add(total_space, total_space, return_space); + + // Compare sp - total_space with the real stack limit. + // Note: sp - total_space will not underflow because sp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens + // of KiB). Thus, the unsigned comparison (lo) against the real stack + // limit is safe. + Register hypothetical_sp = total_space; + __ sub(hypothetical_sp, sp, total_space); + + DEFINE_SCOPED(stack_limit); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + __ cmp(hypothetical_sp, stack_limit); + __ b(lo, &stack_overflow); + } + + // Allocate stack space for return values. + __ sub(sp, sp, return_space); } __ str( @@ -3860,14 +3925,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { regs.Reserve(reg); } - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - int param_padding = stack_params_offset & kSystemPointerSize; - stack_params_offset += param_padding; - { DEFINE_SCOPED(params_start); __ ldr(params_start, @@ -3919,7 +3976,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { DCHECK_EQ(next_offset, stack_params_offset); } - __ Zero(MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); { DEFINE_SCOPED(call_target); __ ldr(call_target, @@ -3995,6 +4051,19 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { } // Emit constant pool now. __ CheckConstPool(true, false); + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ ldr(kContextRegister, + MemOperand(fp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ ldr(kContextRegister, + MemOperand(fp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + GetContextFromImplicitArg(masm, kContextRegister, r1); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -4245,21 +4314,23 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); __ mov(kCArgRegs[3], gap); + __ sub(kCArgRegs[0], frame_base, sp); __ mov(kCArgRegs[1], sp); - __ sub(kCArgRegs[2], frame_base, kCArgRegs[1]); - // On Arm we need preserve rbp value somewhere before entering - // INTERNAL frame later. It will be placed on the stack as an argument. - __ mov(kCArgRegs[0], fp); FrameScope scope(masm, StackFrame::INTERNAL); __ push(kCArgRegs[3]); - __ PrepareCallCFunction(5); - __ str(kCArgRegs[0], MemOperand(sp, 0 * kPointerSize)); // current_fp. + __ PrepareCallCFunction(6); + __ str(parameter_slots_size, MemOperand(sp, 1 * kPointerSize)); + __ ldr(kCArgRegs[2], MemOperand(fp, CommonFrameConstants::kCallerFPOffset)); + __ str(kCArgRegs[2], MemOperand(sp, 0 * kPointerSize)); + __ mov(kCArgRegs[2], kCArgRegs[0]); __ Move(kCArgRegs[0], ER::isolate_address()); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ pop(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4272,13 +4343,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ sub(fp, fp, sp); __ add(fp, fp, kReturnRegister0); __ mov(sp, kReturnRegister0); - { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - __ mov(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - __ str(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - } __ Ret(); __ bind(&call_runtime); @@ -4299,6 +4363,34 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Ret(); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + RegList gp_saves; + for (Register r : wasm::kGpReturnRegisters) gp_saves.set(r); + DoubleRegList fp_saves; + for (DoubleRegister r : wasm::kFpReturnRegisters) fp_saves.set(r); + + __ PushAll(gp_saves); + __ PushAll(fp_saves); + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = + gp_saves.Count() * kSystemPointerSize + fp_saves.Count() * kDoubleSize; + __ Move(kCArgRegs[0], ExternalReference::isolate_address()); + __ add(kCArgRegs[1], sp, Operand(saved_size)); + __ PrepareCallCFunction(2); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ mov(fp, kReturnRegister0); + + __ PopAll(fp_saves); + __ PopAll(gp_saves); + + __ mov(sp, fp); + __ ldm(ia_w, sp, {fp, lr}); + __ Jump(lr); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { diff --git a/deps/v8/src/builtins/arm64/builtins-arm64.cc b/deps/v8/src/builtins/arm64/builtins-arm64.cc index 17552f4d0dd3..ab0b987c9a3f 100644 --- a/deps/v8/src/builtins/arm64/builtins-arm64.cc +++ b/deps/v8/src/builtins/arm64/builtins-arm64.cc @@ -223,7 +223,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ LoadTaggedField( x4, FieldMemOperand(x1, offsetof(JSFunction, shared_function_info_))); __ Ldr(w4, FieldMemOperand(x4, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(w4); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(w4); __ JumpIfIsInRange( w4, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -1135,7 +1135,8 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ Ldrb(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ And(scratch, scratch, Operand(~FeedbackVector::OsrUrgencyBits::kMask)); + __ And(scratch, scratch, + Operand(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ Strb(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -1859,12 +1860,13 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( __ LoadTaggedField( x2, FieldMemOperand(x1, offsetof(JSFunction, shared_function_info_))); __ Ldr(w2, FieldMemOperand(x2, offsetof(SharedFunctionInfo, flags_))); - __ TestAndBranchIfAnySet(w2, SharedFunctionInfo::ConstructAsBuiltinBit::kMask, - &builtin_call); + __ TestAndBranchIfAnySet( + w2, SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask, + &builtin_call); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(w2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(w2); __ JumpIfIsInRange( w2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -2959,8 +2961,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, Label done_convert; __ Ldr(w3, FieldMemOperand(x2, offsetof(SharedFunctionInfo, flags_))); __ TestAndBranchIfAnySet(w3, - SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask, + SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask, &done_convert); { // ----------- S t a t e ------------- @@ -3206,7 +3208,8 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { x4, FieldMemOperand(x1, offsetof(JSFunction, shared_function_info_))); __ Ldr(w4, FieldMemOperand(x4, offsetof(SharedFunctionInfo, flags_))); __ TestAndBranchIfAllClear( - w4, SharedFunctionInfo::ConstructAsBuiltinBit::kMask, &call_generic_stub); + w4, SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask, + &call_generic_stub); __ TailCallBuiltin(Builtin::kJSBuiltinsConstructStub); @@ -3470,7 +3473,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { } namespace { -enum class DebugBreakKind { kBreak, kTrap }; +enum class DebugBreakKind { + kBreak, // Breakpoint or stepping (WasmDebugBreak). + kTrap, // Trap in debug code or trap handler (WasmTrapHandlerThrowTrap). +}; void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { HardAbortScope hard_abort(masm); // Avoid calls to Abort. @@ -3478,7 +3484,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. __ PushXRegList(WasmDebugBreakFrameConstants::kPushedGpRegs); __ PushQRegList(WasmDebugBreakFrameConstants::kPushedFpRegs); @@ -3517,7 +3528,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3804,6 +3815,12 @@ void Builtins::Generate_WasmToJsWrapperAsm(MacroAssembler* masm) { } void Builtins::Generate_WasmTrapHandlerLandingPad(MacroAssembler* masm) { + // Push MessageTemplate::kNone as trap reason for WasmTrapHandlerThrowTrap; + // the runtime will determine the actual trap reason from the trapping + // instruction. + static_assert(Smi::FromInt(static_cast<int>(MessageTemplate::kNone)).ptr() == + 0); + __ Push(xzr, xzr); __ Add(lr, kWasmTrapHandlerFaultAddressRegister, WasmFrameConstants::kTrappingInstructionReturnAddressOffset); __ TailCallBuiltin(Builtin::kWasmTrapHandlerThrowTrap); @@ -3831,10 +3848,8 @@ void Builtins::Generate_WasmSuspend(MacroAssembler* masm) { parent, FieldMemOperand(suspender, offsetof(WasmSuspenderObject, parent_))); DEFINE_REG(target_stack); - __ LoadExternalPointerField( - target_stack, - FieldMemOperand(parent, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ Ldr(target_stack, + FieldMemOperand(parent, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_suspend_stack(), target_stack, &resume, no_reg, {target_stack, suspender, parent}); @@ -3895,7 +3910,7 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { suspender, FieldMemOperand(resume_data, offsetof(WasmResumeData, trusted_suspender_)), - kWasmSuspenderIndirectPointerTag); + kWasmSuspenderTrustedPointerTag); regs.ResetExcept(suspender); // ------------------------------------------- @@ -3910,10 +3925,8 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { // Call the C function. // ------------------------------------------- DEFINE_REG(target_stack); - __ LoadExternalPointerField( - target_stack, - FieldMemOperand(suspender, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ Ldr(target_stack, + FieldMemOperand(suspender, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_resume_jspi_stack(), target_stack, &suspend, suspender, {target_stack}); regs.ResetExcept(target_stack); @@ -4218,9 +4231,7 @@ void SwitchToAllocatedStack(MacroAssembler* masm, RegisterAllocator& regs, DEFINE_SCOPED(scratch) DEFINE_REG(stack) __ LoadRootRelative(stack, IsolateData::active_suspender_offset()); - __ LoadExternalPointerField( - stack, FieldMemOperand(stack, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ Ldr(stack, FieldMemOperand(stack, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_start_stack(), stack, suspend, no_reg, {wasm_instance, wrapper_buffer}); FREE_REG(stack); @@ -4354,6 +4365,7 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; auto regs = RegisterAllocator::WithAllocatableGeneralRegisters(); __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); @@ -4373,6 +4385,11 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { Label suspend; Register original_fp = no_reg; Register new_wrapper_buffer = no_reg; + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; if (stack_switch) { SwitchToAllocatedStack(masm, regs, implicit_arg, wrapper_buffer, original_fp, new_wrapper_buffer, &suspend); @@ -4397,20 +4414,67 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ Str(scratch, MemOperand(fp, WasmJspiFrameConstants::kResultArrayOffset)); + __ Str(xzr, + MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); } } + { - DEFINE_SCOPED(result_size); - __ Ldr(result_size, + DEFINE_SCOPED(return_space); + // Calculate the stack space required for return values (aligned to 16 + // bytes). + __ Ldr(return_space, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants:: kWrapperBufferStackReturnBufferSize)); - // The `result_size` is the number of slots needed on the stack to store the - // return values of the wasm function. If `result_size` is an odd number, we - // have to add `1` to preserve stack pointer alignment. - __ Add(result_size, result_size, 1); - __ Bic(result_size, result_size, 1); - __ Sub(sp, sp, Operand(result_size, LSL, kSystemPointerSizeLog2)); + // Align return_space to multiple of 2 (i.e. multiple of 16 bytes when + // shifted). + __ Add(return_space, return_space, 1); + __ Bic(return_space, return_space, 1); + __ Lsl(return_space, return_space, kSystemPointerSizeLog2); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we + // calculate the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + DEFINE_SCOPED(total_space); + __ Ldr(total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + DEFINE_SCOPED(params_start); + __ Ldr( + params_start, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ Sub(total_space, total_space, params_start); + __ Sub(total_space, total_space, stack_params_offset); + __ Add(total_space, total_space, return_space); + + // Compare sp - total_space with the real stack limit. + // Note: sp - total_space will not underflow because sp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens + // of KiB). Thus, the unsigned comparison (lo) against the real stack + // limit is safe. + Register hypothetical_sp = total_space; + __ Sub(hypothetical_sp, sp, total_space); + + DEFINE_SCOPED(stack_limit); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + __ Cmp(hypothetical_sp, stack_limit); + __ B(lo, &stack_overflow); + } + + // Allocate stack space for return values. + __ Sub(sp, sp, return_space); } + { DEFINE_SCOPED(scratch); __ Mov(scratch, sp); @@ -4426,12 +4490,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { regs.Reserve(reg); } - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - { DEFINE_SCOPED(params_start); __ Ldr(params_start, @@ -4497,7 +4555,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { DCHECK_EQ(next_offset, stack_params_offset); } - __ Str(xzr, MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); { DEFINE_SCOPED(call_target); __ LoadWasmCodePointer( @@ -4573,6 +4630,19 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, regs, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ Ldr(kContextRegister, + MemOperand(fp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ Ldr(kContextRegister, + MemOperand(fp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + GetContextFromImplicitArg(masm, kContextRegister, x3); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -4860,9 +4930,12 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); + __ Mov(kCArgRegs[5], parameter_slots_size); __ Mov(kCArgRegs[3], gap); __ Mov(kCArgRegs[1], sp); __ Sub(kCArgRegs[2], frame_base, kCArgRegs[1]); @@ -4870,7 +4943,7 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(kCArgRegs[3], padreg); __ Mov(kCArgRegs[0], ER::isolate_address()); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ Pop(padreg, gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4888,12 +4961,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { } SwitchSimulatorStackLimit(masm); __ Mov(sp, kReturnRegister0); - { - UseScratchRegisterScope temps(masm); - Register scratch = temps.AcquireX(); - __ Mov(scratch, StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)); - __ Str(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - } __ Ret(); __ bind(&call_runtime); @@ -4914,6 +4981,34 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Ret(); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + RegList gp_saves; + for (Register r : wasm::kGpReturnRegisters) gp_saves.set(r); + DoubleRegList fp_saves; + for (DoubleRegister r : wasm::kFpReturnRegisters) fp_saves.set(r); + + __ PushAll(gp_saves); + __ PushAll(fp_saves, kSimd128Size); + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = + gp_saves.Count() * kSystemPointerSize + fp_saves.Count() * kSimd128Size; + __ Mov(kCArgRegs[0], ExternalReference::isolate_address()); + __ Add(kCArgRegs[1], sp, saved_size); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ Mov(fp, kReturnRegister0); + + __ PopAll(fp_saves, kSimd128Size); + __ PopAll(gp_saves); + + SwitchSimulatorStackLimit(masm); + __ Mov(sp, fp); + __ Pop<MacroAssembler::kAuthLR>(fp, lr); + __ Ret(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { @@ -5673,7 +5768,7 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( code_obj, FieldMemOperand(code_obj, offsetof(SharedFunctionInfo, trusted_function_data_)), - kCodeIndirectPointerTag); + kCodeTrustedPointerTag); // For OSR entry it is safe to assume we always have baseline code. if (v8_flags.debug_code) { diff --git a/deps/v8/src/builtins/array-reduce-right.tq b/deps/v8/src/builtins/array-reduce-right.tq index 6e92aefe66a8..70a00aefbd1d 100644 --- a/deps/v8/src/builtins/array-reduce-right.tq +++ b/deps/v8/src/builtins/array-reduce-right.tq @@ -103,8 +103,7 @@ transitioning builtin ArrayReduceRightLoopContinuation( // this means kPresent is false. typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight'); + ThrowTypeError(MessageTemplate::kReduceNoInitial); } case (accumulator: JSAny): { return accumulator; @@ -143,8 +142,7 @@ transitioning macro FastArrayReduceRight( } typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight'); + ThrowTypeError(MessageTemplate::kReduceNoInitial); } case (accumulator: JSAny): { return accumulator; diff --git a/deps/v8/src/builtins/array-reduce.tq b/deps/v8/src/builtins/array-reduce.tq index 7255508b7b8c..4b02aca01c81 100644 --- a/deps/v8/src/builtins/array-reduce.tq +++ b/deps/v8/src/builtins/array-reduce.tq @@ -102,8 +102,7 @@ transitioning builtin ArrayReduceLoopContinuation( // this means kPresent is false. typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); + ThrowTypeError(MessageTemplate::kReduceNoInitial); } case (accumulator: JSAny): { return accumulator; @@ -143,8 +142,7 @@ transitioning macro FastArrayReduce( } typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce'); + ThrowTypeError(MessageTemplate::kReduceNoInitial); } case (accumulator: JSAny): { return accumulator; diff --git a/deps/v8/src/builtins/array-slice.tq b/deps/v8/src/builtins/array-slice.tq index 354751410a3b..531919f22e5e 100644 --- a/deps/v8/src/builtins/array-slice.tq +++ b/deps/v8/src/builtins/array-slice.tq @@ -63,7 +63,7 @@ macro HandleFastAliasedSloppyArgumentsSlice( // Fill in the part of the result that map to context-mapped parameters. for (let current: intptr = Convert<intptr>(start); current < to; ++current) { - const e: Object = sloppyElements.mapped_entries[current]; + const e: Object = sloppyElements.objects[current]; const newElement = UnsafeCast<(JSAny | TheHole)>( e != TheHole ? argumentsContext.elements[UnsafeCast<Smi>(e)] : unmappedElements.objects[current]); diff --git a/deps/v8/src/builtins/array-splice.tq b/deps/v8/src/builtins/array-splice.tq index ae5b56cb9d74..2fef74dc996c 100644 --- a/deps/v8/src/builtins/array-splice.tq +++ b/deps/v8/src/builtins/array-splice.tq @@ -427,7 +427,7 @@ transitioning javascript builtin ArrayPrototypeSplice( // Bailout exception. const newLength: Number = len + insertCount - actualDeleteCount; if (newLength > kMaxSafeInteger) { - ThrowTypeError(MessageTemplate::kInvalidArrayLength, newLength); + ThrowTypeError(MessageTemplate::kInvalidArrayLength); } try { diff --git a/deps/v8/src/builtins/array-to-sorted.tq b/deps/v8/src/builtins/array-to-sorted.tq index 1192fc416f34..7983fe6a9c8f 100644 --- a/deps/v8/src/builtins/array-to-sorted.tq +++ b/deps/v8/src/builtins/array-to-sorted.tq @@ -115,7 +115,7 @@ transitioning javascript builtin ArrayPrototypeToSorted( // // The actual array will be created later, but perform the range check. if (len > kMaxArrayLength) { - ThrowRangeError(MessageTemplate::kInvalidArrayLength, len); + ThrowRangeError(MessageTemplate::kInvalidArrayLength); } // 5. Let SortCompare be a new Abstract Closure with parameters (x, y) that diff --git a/deps/v8/src/builtins/array-to-spliced.tq b/deps/v8/src/builtins/array-to-spliced.tq index 362313623137..3134a3bfa3b1 100644 --- a/deps/v8/src/builtins/array-to-spliced.tq +++ b/deps/v8/src/builtins/array-to-spliced.tq @@ -224,7 +224,7 @@ transitioning javascript builtin ArrayPrototypeToSpliced( // 12. If newLen > 2^53 - 1, throw a TypeError exception. if (newLen > kMaxSafeInteger) { - ThrowTypeError(MessageTemplate::kInvalidArrayLength, newLen); + ThrowTypeError(MessageTemplate::kInvalidArrayLength); } if (newLen == 0) return ArrayCreate(0); diff --git a/deps/v8/src/builtins/array.tq b/deps/v8/src/builtins/array.tq index 4a43b1a87566..3e52fd9d2c39 100644 --- a/deps/v8/src/builtins/array.tq +++ b/deps/v8/src/builtins/array.tq @@ -76,7 +76,7 @@ macro EnsureArrayLengthWritable(implicit context: Context)(map: Map): const descriptors: DescriptorArray = UnsafeCast<DescriptorArray>(map.instance_descriptors); const descriptor:&DescriptorEntry = - &descriptors.descriptors[kLengthDescriptorIndex]; + &descriptors.entries[kLengthDescriptorIndex]; dcheck(TaggedEqual(descriptor->key, LengthStringConstant())); const details: Smi = UnsafeCast<Smi>(descriptor->details); if ((details & kAttributesReadOnlyMask) != 0) { diff --git a/deps/v8/src/builtins/base.tq b/deps/v8/src/builtins/base.tq index 3bbd3108699b..4d587295ef69 100644 --- a/deps/v8/src/builtins/base.tq +++ b/deps/v8/src/builtins/base.tq @@ -13,7 +13,6 @@ #include 'src/objects/elements-kind.h' #include 'src/objects/free-space.h' #include 'src/objects/hash-seed-wrapper.h' -#include 'src/objects/js-atomics-synchronization.h' #include 'src/objects/js-disposable-stack.h' #include 'src/objects/js-function.h' #include 'src/objects/js-generator.h' @@ -301,7 +300,10 @@ type TrustedPointer type TrustedPointer<To : type extends ExposedTrustedObject> extends TrustedPointer; type ProtectedPointer extends Tagged; -type ProtectedPointer<To : type extends TrustedObject> extends ProtectedPointer; +// A protected pointer may also hold a Smi or a weak reference, as +// ProtectedTaggedMember<UnionOf<...>> does in C++. +type ProtectedPointer<To : type extends TrustedObject|Smi| + Weak<TrustedObject>> extends ProtectedPointer; extern class InstructionStream extends TrustedObject; type BuiltinPtr extends Smi generates 'BuiltinPtr'; @@ -312,8 +314,6 @@ extern class TransitionArray extends WeakFixedArray; type InstanceType extends uint16 constexpr 'InstanceType'; -type NoSharedNameSentinel extends Smi; - // Specialized types. The following three type definitions don't correspond to // actual C++ classes, but have Is... methods that check additional constraints. @@ -345,11 +345,8 @@ extern enum CallFeedbackContent extends int32 { kTarget, kReceiver } extern enum UnicodeEncoding { UTF16, UTF32 } // Promise constants -extern enum PromiseState extends int31 constexpr 'Promise::PromiseState' { - kPending, - kFulfilled, - kRejected -} +extern enum PromisePromiseState extends int31 + constexpr 'Promise::PromiseState' { kPending, kFulfilled, kRejected } const kTaggedSize: constexpr int31 generates 'kTaggedSize'; const kDoubleSize: constexpr int31 generates 'kDoubleSize'; @@ -606,9 +603,6 @@ const kNameDictionaryInitialCapacity: const kSwissNameDictionaryInitialCapacity: constexpr int32 generates 'SwissNameDictionary::kInitialCapacity'; -const kWasmArrayHeaderSize: - constexpr int32 generates 'WasmArray::kHeaderSize'; - const kHeapObjectHeaderSize: constexpr int32 generates 'sizeof(HeapObject)'; type Exception extends Oddball; @@ -1341,7 +1335,7 @@ operator '+' macro StringAdd( } operator '==' macro PromiseStateEquals( - s1: PromiseState, s2: PromiseState): bool { + s1: PromisePromiseState, s2: PromisePromiseState): bool { return Word32Equal(s1, s2); } @@ -2270,7 +2264,8 @@ extern operator '[]' macro LoadWeakFixedArrayElement( extern operator '[]' macro LoadUint8Ptr(RawPtr<uint8>, intptr): uint8; extern operator '[]' macro LoadUint64Ptr(RawPtr<uint64>, intptr): uint64; -extern enum HashFieldType extends uint32 constexpr 'Name::HashFieldType' { +extern enum NameHashFieldType extends uint32 + constexpr 'Name::HashFieldType' { kHash, kIntegerIndex, kForwardingIndex, @@ -2278,7 +2273,7 @@ extern enum HashFieldType extends uint32 constexpr 'Name::HashFieldType' { } operator '==' macro HashFieldTypeEquals( - s1: HashFieldType, s2: HashFieldType): bool { + s1: NameHashFieldType, s2: NameHashFieldType): bool { return Word32Equal(s1, s2); } diff --git a/deps/v8/src/builtins/builtins-array-gen.cc b/deps/v8/src/builtins/builtins-array-gen.cc index a26c52fe4b3d..6d50facb3623 100644 --- a/deps/v8/src/builtins/builtins-array-gen.cc +++ b/deps/v8/src/builtins/builtins-array-gen.cc @@ -1993,6 +1993,12 @@ GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, DontOverride, DONT_OVERRIDE) GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride, DONT_OVERRIDE) +GENERATE_ARRAY_CTOR(NoArgument, Packed, PACKED_ELEMENTS, DontOverride, + DONT_OVERRIDE) +GENERATE_ARRAY_CTOR(NoArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS, + DontOverride, DONT_OVERRIDE) +GENERATE_ARRAY_CTOR(NoArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS, + DontOverride, DONT_OVERRIDE) GENERATE_ARRAY_CTOR(NoArgument, PackedSmi, PACKED_SMI_ELEMENTS, DisableAllocationSites, DISABLE_ALLOCATION_SITES) GENERATE_ARRAY_CTOR(NoArgument, HoleySmi, HOLEY_SMI_ELEMENTS, @@ -2011,6 +2017,12 @@ GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS, DontOverride, DONT_OVERRIDE) GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, DontOverride, DONT_OVERRIDE) +GENERATE_ARRAY_CTOR(SingleArgument, Packed, PACKED_ELEMENTS, DontOverride, + DONT_OVERRIDE) +GENERATE_ARRAY_CTOR(SingleArgument, PackedDouble, PACKED_DOUBLE_ELEMENTS, + DontOverride, DONT_OVERRIDE) +GENERATE_ARRAY_CTOR(SingleArgument, HoleyDouble, HOLEY_DOUBLE_ELEMENTS, + DontOverride, DONT_OVERRIDE) GENERATE_ARRAY_CTOR(SingleArgument, PackedSmi, PACKED_SMI_ELEMENTS, DisableAllocationSites, DISABLE_ALLOCATION_SITES) GENERATE_ARRAY_CTOR(SingleArgument, HoleySmi, HOLEY_SMI_ELEMENTS, diff --git a/deps/v8/src/builtins/builtins-arraybuffer.cc b/deps/v8/src/builtins/builtins-arraybuffer.cc index 1768bee4c08b..6775df671e2d 100644 --- a/deps/v8/src/builtins/builtins-arraybuffer.cc +++ b/deps/v8/src/builtins/builtins-arraybuffer.cc @@ -119,7 +119,9 @@ Tagged<Object> ConstructBuffer(Isolate* isolate, NewJSObjectType::kMaybeEmbedderFieldsAndApiWrapper)); auto array_buffer = Cast<JSArrayBuffer>(result); const bool backing_store_creation_failed = !backing_store; - array_buffer->Setup(shared, resizable, std::move(backing_store), isolate); + array_buffer->Setup( + shared, backing_store_creation_failed ? ResizableFlag{false} : resizable, + std::move(backing_store), isolate); if (backing_store_creation_failed) { CHECK(range_error.has_value()); THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewRangeError(range_error.value())); @@ -729,7 +731,7 @@ Tagged<Object> ArrayBufferTransfer(Isolate* isolate, DirectHandle<JSArrayBuffer> result_buffer; // Case 1: We don't need a BackingStore. - if (new_byte_length == 0) { + if (new_byte_length == 0 && !resizable) { // 15. Perform ! DetachArrayBuffer(arrayBuffer). JSArrayBuffer::Detach(array_buffer).Check(); diff --git a/deps/v8/src/builtins/builtins-async-disposable-stack.cc b/deps/v8/src/builtins/builtins-async-disposable-stack.cc index 55663fa499a6..47b8a16e3f70 100644 --- a/deps/v8/src/builtins/builtins-async-disposable-stack.cc +++ b/deps/v8/src/builtins/builtins-async-disposable-stack.cc @@ -8,6 +8,7 @@ #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/common/globals.h" +#include "src/debug/debug.h" #include "src/execution/isolate.h" #include "src/handles/maybe-handles.h" #include "src/objects/heap-object.h" @@ -107,6 +108,9 @@ BUILTIN(AsyncDisposeFromSyncDispose) { isolate->clear_internal_exception(); isolate->clear_pending_message(); JSPromise::Reject(promise, direct_handle(exception, isolate)); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } } // f. Return promiseCapability.[[Promise]]. @@ -210,6 +214,9 @@ BUILTIN(AsyncDisposableStackPrototypeDisposeAsync) { JSPromise::Reject(promise, isolate->factory()->NewTypeError( MessageTemplate::kNotAnAsyncDisposableStack)); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } // b. Return promiseCapability.[[Promise]]. return *promise; } diff --git a/deps/v8/src/builtins/builtins-async-function-gen.cc b/deps/v8/src/builtins/builtins-async-function-gen.cc index 101c44fe0835..05ac594707eb 100644 --- a/deps/v8/src/builtins/builtins-async-function-gen.cc +++ b/deps/v8/src/builtins/builtins-async-function-gen.cc @@ -273,7 +273,8 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait() { // Mark the promise as handled. StoreObjectFieldNoWriteBarrier( js_promise, offsetof(JSPromise, flags_), - SmiOr(promise_flags, SmiConstant(JSPromise::HasHandlerBit::kMask))); + SmiOr(promise_flags, + SmiConstant(JSPromise::Flags::HasHandlerBit::kMask))); // Extract the fulfilled value. TNode<Object> fulfilled_value = diff --git a/deps/v8/src/builtins/builtins-async-gen.cc b/deps/v8/src/builtins/builtins-async-gen.cc index 3013d39f1bb2..cb47137ab3db 100644 --- a/deps/v8/src/builtins/builtins-async-gen.cc +++ b/deps/v8/src/builtins/builtins-async-gen.cc @@ -289,14 +289,14 @@ TNode<Object> AsyncBuiltinsAssembler::Await(TNode<Context> context, TNode<Int32T> promise_flags = SmiToInt32( LoadObjectField<Smi>(js_promise, offsetof(JSPromise, flags_))); - TNode<Int32T> status = - Word32And(promise_flags, Int32Constant(JSPromise::StatusBits::kMask)); + TNode<Int32T> status = Word32And( + promise_flags, Int32Constant(JSPromise::Flags::StatusBits::kMask)); GotoIfNot(Word32Equal(status, Int32Constant(v8::Promise::kFulfilled)), &if_perform_promise_then); // Mark the promise as handled. - TNode<Int32T> new_flags = - Word32Or(promise_flags, Int32Constant(JSPromise::HasHandlerBit::kMask)); + TNode<Int32T> new_flags = Word32Or( + promise_flags, Int32Constant(JSPromise::Flags::HasHandlerBit::kMask)); StoreObjectFieldNoWriteBarrier(js_promise, offsetof(JSPromise, flags_), SmiFromInt32(new_flags)); diff --git a/deps/v8/src/builtins/builtins-atomics-synchronization.cc b/deps/v8/src/builtins/builtins-atomics-synchronization.cc deleted file mode 100644 index d60667d9507a..000000000000 --- a/deps/v8/src/builtins/builtins-atomics-synchronization.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2022 the V8 project 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 "src/builtins/builtins-utils-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" -#include "src/objects/object-conversions-inl.h" - -namespace v8 { -namespace internal { -namespace { - -std::optional<base::TimeDelta> GetTimeoutDelta( - DirectHandle<Object> timeout_obj) { - double ms = Object::NumberValue(*timeout_obj); - if (!std::isnan(ms)) { - if (ms < 0) ms = 0; - if (ms <= static_cast<double>(std::numeric_limits<int64_t>::max())) { - return base::TimeDelta::FromMilliseconds(static_cast<int64_t>(ms)); - } - } - return std::nullopt; -} - -} // namespace - -BUILTIN(AtomicsMutexConstructor) { - DCHECK(v8_flags.harmony_struct); - HandleScope scope(isolate); - return *isolate->factory()->NewJSAtomicsMutex(); -} - -BUILTIN(AtomicsMutexLock) { - DCHECK(v8_flags.harmony_struct); - constexpr char method_name[] = "Atomics.Mutex.lock"; - HandleScope scope(isolate); - - DirectHandle<Object> js_mutex_obj = args.atOrUndefined(isolate, 1); - if (!IsJSAtomicsMutex(*js_mutex_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kMethodInvokedOnWrongType, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - DirectHandle<JSAtomicsMutex> js_mutex = Cast<JSAtomicsMutex>(js_mutex_obj); - DirectHandle<Object> run_under_lock = args.atOrUndefined(isolate, 2); - if (!IsCallable(*run_under_lock)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kNotCallable, run_under_lock)); - } - - // Like Atomics.wait, synchronous locking may block, and so is disallowed on - // the main thread. - // - // This is not a recursive lock, so also throw if recursively locking. - if (!isolate->allow_atomics_wait() || js_mutex->IsCurrentThreadOwner()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kAtomicsOperationNotAllowed, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - - DirectHandle<Object> result; - { - JSAtomicsMutex::LockGuard lock_guard(isolate, js_mutex); - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, - Execution::Call(isolate, run_under_lock, - isolate->factory()->undefined_value(), {})); - } - - return *result; -} - -BUILTIN(AtomicsMutexTryLock) { - DCHECK(v8_flags.harmony_struct); - constexpr char method_name[] = "Atomics.Mutex.tryLock"; - HandleScope scope(isolate); - - DirectHandle<Object> js_mutex_obj = args.atOrUndefined(isolate, 1); - if (!IsJSAtomicsMutex(*js_mutex_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kMethodInvokedOnWrongType, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - DirectHandle<JSAtomicsMutex> js_mutex = Cast<JSAtomicsMutex>(js_mutex_obj); - DirectHandle<Object> run_under_lock = args.atOrUndefined(isolate, 2); - if (!IsCallable(*run_under_lock)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kNotCallable, run_under_lock)); - } - - DirectHandle<Object> callback_result; - bool success; - { - JSAtomicsMutex::TryLockGuard try_lock_guard(isolate, js_mutex); - if (try_lock_guard.locked()) { - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, callback_result, - Execution::Call(isolate, run_under_lock, - isolate->factory()->undefined_value(), {})); - success = true; - } else { - callback_result = isolate->factory()->undefined_value(); - success = false; - } - } - DirectHandle<JSObject> result = - JSAtomicsMutex::CreateResultObject(isolate, callback_result, success); - return *result; -} - -BUILTIN(AtomicsMutexLockWithTimeout) { - DCHECK(v8_flags.harmony_struct); - constexpr char method_name[] = "Atomics.Mutex.lockWithTimeout"; - HandleScope scope(isolate); - - DirectHandle<Object> js_mutex_obj = args.atOrUndefined(isolate, 1); - if (!IsJSAtomicsMutex(*js_mutex_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kMethodInvokedOnWrongType, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - DirectHandle<JSAtomicsMutex> js_mutex = Cast<JSAtomicsMutex>(js_mutex_obj); - DirectHandle<Object> run_under_lock = args.atOrUndefined(isolate, 2); - if (!IsCallable(*run_under_lock)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kNotCallable, run_under_lock)); - } - - DirectHandle<Object> timeout_obj = args.atOrUndefined(isolate, 3); - std::optional<base::TimeDelta> timeout; - if (!IsNumber(*timeout_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIsNotNumber, timeout_obj, - Object::TypeOf(isolate, timeout_obj))); - } - timeout = GetTimeoutDelta(timeout_obj); - - // Like Atomics.wait, synchronous locking may block, and so is disallowed on - // the main thread. - // - // This is not a recursive lock, so also throw if recursively locking. - if (!isolate->allow_atomics_wait() || js_mutex->IsCurrentThreadOwner()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kAtomicsOperationNotAllowed, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - - DirectHandle<Object> callback_result; - bool success; - { - JSAtomicsMutex::LockGuard lock_guard(isolate, js_mutex, timeout); - if (V8_LIKELY(lock_guard.locked())) { - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, callback_result, - Execution::Call(isolate, run_under_lock, - isolate->factory()->undefined_value(), {})); - success = true; - } else { - callback_result = isolate->factory()->undefined_value(); - success = false; - } - } - DirectHandle<JSObject> result = - JSAtomicsMutex::CreateResultObject(isolate, callback_result, success); - return *result; -} - -BUILTIN(AtomicsConditionConstructor) { - DCHECK(v8_flags.harmony_struct); - HandleScope scope(isolate); - return *isolate->factory()->NewJSAtomicsCondition(); -} - -BUILTIN(AtomicsConditionWait) { - DCHECK(v8_flags.harmony_struct); - constexpr char method_name[] = "Atomics.Condition.wait"; - HandleScope scope(isolate); - - DirectHandle<Object> js_condition_obj = args.atOrUndefined(isolate, 1); - DirectHandle<Object> js_mutex_obj = args.atOrUndefined(isolate, 2); - DirectHandle<Object> timeout_obj = args.atOrUndefined(isolate, 3); - if (!IsJSAtomicsCondition(*js_condition_obj) || - !IsJSAtomicsMutex(*js_mutex_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kMethodInvokedOnWrongType, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - - std::optional<base::TimeDelta> timeout = std::nullopt; - if (!IsUndefined(*timeout_obj)) { - if (!IsNumber(*timeout_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIsNotNumber, timeout_obj, - Object::TypeOf(isolate, timeout_obj))); - } - timeout = GetTimeoutDelta(timeout_obj); - } - - if (!isolate->allow_atomics_wait()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kAtomicsOperationNotAllowed, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - - auto js_condition = Cast<JSAtomicsCondition>(js_condition_obj); - auto js_mutex = Cast<JSAtomicsMutex>(js_mutex_obj); - - if (!js_mutex->IsCurrentThreadOwner()) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, - NewTypeError(MessageTemplate::kAtomicsMutexNotOwnedByCurrentThread)); - } - - return isolate->heap()->ToBoolean( - JSAtomicsCondition::WaitFor(isolate, js_condition, js_mutex, timeout)); -} - -BUILTIN(AtomicsConditionNotify) { - DCHECK(v8_flags.harmony_struct); - constexpr char method_name[] = "Atomics.Condition.notify"; - HandleScope scope(isolate); - - DirectHandle<Object> js_condition_obj = args.atOrUndefined(isolate, 1); - DirectHandle<Object> count_obj = args.atOrUndefined(isolate, 2); - if (!IsJSAtomicsCondition(*js_condition_obj)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kMethodInvokedOnWrongType, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } - - uint32_t count; - if (IsUndefined(*count_obj)) { - count = JSAtomicsCondition::kAllWaiters; - } else { - double count_double; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, count_double, Object::IntegerValue(isolate, count_obj)); - if (count_double <= 0) { - return Smi::zero(); - } else if (count_double > JSAtomicsCondition::kAllWaiters) { - count_double = JSAtomicsCondition::kAllWaiters; - } - count = static_cast<uint32_t>(count_double); - } - - auto js_condition = Cast<JSAtomicsCondition>(js_condition_obj); - return *isolate->factory()->NewNumberFromUint( - JSAtomicsCondition::Notify(isolate, js_condition, count)); -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/builtins/builtins-bigint.cc b/deps/v8/src/builtins/builtins-bigint.cc index 8a8c037fe096..ff8376fcb445 100644 --- a/deps/v8/src/builtins/builtins-bigint.cc +++ b/deps/v8/src/builtins/builtins-bigint.cc @@ -17,6 +17,7 @@ namespace internal { BUILTIN(BigIntConstructor) { HandleScope scope(isolate); + isolate->CountUsage(v8::Isolate::kBigInt); if (!IsUndefined(*args.new_target())) { // [[Construct]] THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kNotConstructor, diff --git a/deps/v8/src/builtins/builtins-call-gen.cc b/deps/v8/src/builtins/builtins-call-gen.cc index d6e22ea95d02..d3d89c636921 100644 --- a/deps/v8/src/builtins/builtins-call-gen.cc +++ b/deps/v8/src/builtins/builtins-call-gen.cc @@ -773,7 +773,7 @@ void CallOrConstructBuiltinsAssembler::CallFunctionTemplate( &receiver_done); TNode<Uint32T> function_template_info_flags = LoadObjectField<Uint32T>( function_template_info, offsetof(FunctionTemplateInfo, flag_)); - Branch(IsSetWord32<FunctionTemplateInfo::AcceptAnyReceiverBit>( + Branch(IsSetWord32<FunctionTemplateInfo::Flags::AcceptAnyReceiverBit>( function_template_info_flags), &receiver_done, &receiver_needs_access_check); diff --git a/deps/v8/src/builtins/builtins-collections-gen.cc b/deps/v8/src/builtins/builtins-collections-gen.cc index 4166da123b05..58b4ee071343 100644 --- a/deps/v8/src/builtins/builtins-collections-gen.cc +++ b/deps/v8/src/builtins/builtins-collections-gen.cc @@ -506,7 +506,7 @@ void BaseCollectionsAssembler::GotoIfCannotBeHeldWeakly( Bind(&check_symbol_key); GotoIfNot(IsSymbolInstanceType(instance_type), if_cannot_be_held_weakly); TNode<Uint32T> flags = LoadSymbolFlags(CAST(obj)); - Branch(Word32And(flags, Symbol::IsInPublicSymbolTableBit::kMask), + Branch(Word32And(flags, Symbol::Flags::IsInPublicSymbolTableBit::kMask), if_cannot_be_held_weakly, &end); Bind(&end); @@ -2750,9 +2750,9 @@ TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::GetHash( Goto(&return_result); Bind(&if_symbol); CSA_DCHECK(this, IsSymbol(key)); - CSA_DCHECK(this, Word32BinaryNot( - Word32And(LoadSymbolFlags(CAST(key)), - Symbol::IsInPublicSymbolTableBit::kMask))); + CSA_DCHECK(this, Word32BinaryNot(Word32And( + LoadSymbolFlags(CAST(key)), + Symbol::Flags::IsInPublicSymbolTableBit::kMask))); var_hash = Signed(ChangeUint32ToWord(LoadNameHashAssumeComputed(CAST(key)))); Goto(&return_result); Bind(&return_result); @@ -3213,7 +3213,7 @@ TF_BUILTIN(WeakMapPrototypeSet, WeakCollectionsBuiltinsAssembler) { CallBuiltin(Builtin::kWeakCollectionSet, context, receiver, key, value)); BIND(&throw_invalid_key); - ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey, key); + ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey); } TF_BUILTIN(WeakMapPrototypeGetOrInsert, WeakCollectionsBuiltinsAssembler) { @@ -3241,7 +3241,7 @@ TF_BUILTIN(WeakMapPrototypeGetOrInsert, WeakCollectionsBuiltinsAssembler) { Return(value.value()); BIND(&throw_invalid_key); - ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey, key); + ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey); } TF_BUILTIN(WeakMapPrototypeGetOrInsertComputed, @@ -3276,7 +3276,7 @@ TF_BUILTIN(WeakMapPrototypeGetOrInsertComputed, Return(value); BIND(&throw_invalid_key); - ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey, key); + ThrowTypeError(context, MessageTemplate::kInvalidWeakMapKey); } TF_BUILTIN(WeakSetPrototypeAdd, WeakCollectionsBuiltinsAssembler) { @@ -3294,7 +3294,7 @@ TF_BUILTIN(WeakSetPrototypeAdd, WeakCollectionsBuiltinsAssembler) { TrueConstant())); BIND(&throw_invalid_value); - ThrowTypeError(context, MessageTemplate::kInvalidWeakSetValue, value); + ThrowTypeError(context, MessageTemplate::kInvalidWeakSetValue); } TF_BUILTIN(WeakSetPrototypeDelete, CodeStubAssembler) { diff --git a/deps/v8/src/builtins/builtins-console.cc b/deps/v8/src/builtins/builtins-console.cc index a909d38e5e84..86d33d7ea4d5 100644 --- a/deps/v8/src/builtins/builtins-console.cc +++ b/deps/v8/src/builtins/builtins-console.cc @@ -7,6 +7,7 @@ #include "src/api/api-inl.h" #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" +#include "src/debug/debug.h" #include "src/debug/interface-types.h" #include "src/logging/counters.h" #include "src/logging/log.h" @@ -37,8 +38,7 @@ namespace internal { V(Warn, warn, 1) \ V(Trace, trace, 1) \ V(Group, group, 1) \ - V(GroupCollapsed, groupCollapsed, 1) \ - V(Assert, assert, 2) + V(GroupCollapsed, groupCollapsed, 1) namespace { @@ -170,6 +170,9 @@ void ConsoleCall( (isolate->console_delegate()->*func)( debug::ConsoleCallArguments(isolate, args), v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name))); + if (isolate->debug()->IsRestartFrameScheduled()) { + isolate->TerminateExecution(); + } } void LogTimerEvent(Isolate* isolate, BuiltinArguments args, @@ -207,6 +210,7 @@ CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION) return ReadOnlyRoots(isolate).undefined_value(); \ } CONSOLE_METHOD_WITH_FORMATTER_LIST(CONSOLE_BUILTIN_IMPLEMENTATION) +CONSOLE_BUILTIN_IMPLEMENTATION(Assert, assert, 2) #undef CONSOLE_BUILTIN_IMPLEMENTATION BUILTIN(ConsoleTime) { @@ -243,7 +247,7 @@ void InstallContextFunction(Isolate* isolate, DirectHandle<JSObject> target, DirectHandle<Context> context) { Factory* const factory = isolate->factory(); - DirectHandle<Map> map = isolate->sloppy_function_without_prototype_map(); + DirectHandle<Map> map = isolate->function_without_prototype_map(); DirectHandle<String> name_string = factory->InternalizeUtf8String(name); @@ -311,6 +315,8 @@ BUILTIN(ConsoleContext) { CONSOLE_BUILTIN_SETUP(TimeEnd, timeEnd) CONSOLE_BUILTIN_SETUP(TimeStamp, timeStamp) #undef CONSOLE_BUILTIN_SETUP + InstallContextFunction(isolate, console_context, "assert", + Builtin::kFastConsoleAssert, context); return *console_context; } diff --git a/deps/v8/src/builtins/builtins-constructor-gen.cc b/deps/v8/src/builtins/builtins-constructor-gen.cc index 0f3125e8bfa3..fad526d9882d 100644 --- a/deps/v8/src/builtins/builtins-constructor-gen.cc +++ b/deps/v8/src/builtins/builtins-constructor-gen.cc @@ -248,7 +248,8 @@ TF_BUILTIN(FastNewClosure, ConstructorBuiltinsAssembler) { TNode<Uint32T> flags = LoadObjectField<Uint32T>( shared_function_info, offsetof(SharedFunctionInfo, flags_)); const TNode<IntPtrT> function_map_index = Signed(IntPtrAdd( - DecodeWordFromWord32<SharedFunctionInfo::FunctionMapIndexBits>(flags), + DecodeWordFromWord32<SharedFunctionInfo::Flags::FunctionMapIndexBits>( + flags), IntPtrConstant(Context::FIRST_FUNCTION_MAP_INDEX))); CSA_DCHECK(this, UintPtrLessThanOrEqual( function_map_index, @@ -505,8 +506,8 @@ TNode<JSRegExp> ConstructorBuiltinsAssembler::CreateRegExpLiteral( RootIndex::kEmptyFixedArray); // Initialize JSRegExp fields. StoreTrustedPointerField( - new_object, offsetof(JSRegExp, data_), kRegExpDataIndirectPointerTag, - LoadTrustedPointerFromObject<kRegExpDataIndirectPointerTag>( + new_object, offsetof(JSRegExp, data_), kRegExpDataTrustedPointerTag, + LoadTrustedPointerFromObject<kRegExpDataTrustedPointerTag>( boilerplate, offsetof(RegExpBoilerplateDescription, data_))); StoreObjectFieldNoWriteBarrier( new_object, offsetof(JSRegExp, flags_), @@ -724,7 +725,10 @@ TNode<HeapObject> ConstructorBuiltinsAssembler::CreateShallowObjectLiteral( GotoIf(TaggedIsSmi(field), &store_field); // TODO(leszeks): Read the field descriptor to decide if this heap // number is mutable or not. - GotoIf(IsHeapNumber(CAST(field)), &continue_with_write_barrier); + TNode<Map> field_map = LoadMap(CAST(field)); + GotoIf(IsHeapNumberMap(field_map), &continue_with_write_barrier); + GotoIf(IsUninitializedHeapNumberMap(field_map), + &continue_with_write_barrier); Goto(&store_field); BIND(&store_field); StoreObjectFieldNoWriteBarrier(copy, offset.value(), field); @@ -781,12 +785,17 @@ void ConstructorBuiltinsAssembler::CopyMutableHeapNumbersInObject( start_offset, end_offset, [=, this](TNode<IntPtrT> offset) { TNode<Object> field = LoadObjectField(copy, offset); - Label copy_heap_number(this, Label::kDeferred), continue_loop(this); + Label copy_heap_number(this, Label::kDeferred), + copy_uninitialized_heap_number(this, Label::kDeferred), + continue_loop(this); // We only have to clone complex field values. GotoIf(TaggedIsSmi(field), &continue_loop); // TODO(leszeks): Read the field descriptor to decide if this heap // number is mutable or not. - Branch(IsHeapNumber(CAST(field)), ©_heap_number, &continue_loop); + TNode<Map> field_map = LoadMap(CAST(field)); + GotoIf(IsHeapNumberMap(field_map), ©_heap_number); + Branch(IsUninitializedHeapNumberMap(field_map), + ©_uninitialized_heap_number, &continue_loop); BIND(©_heap_number); { TNode<Float64T> double_value = LoadHeapNumberValue(CAST(field)); @@ -795,6 +804,13 @@ void ConstructorBuiltinsAssembler::CopyMutableHeapNumbersInObject( StoreObjectField(copy, offset, heap_number); Goto(&continue_loop); } + BIND(©_uninitialized_heap_number); + { + TNode<UninitializedHeapNumber> heap_number = + AllocateUninitializedHeapNumber(); + StoreObjectField(copy, offset, heap_number); + Goto(&continue_loop); + } BIND(&continue_loop); }, kTaggedSize, kNoLoopUnrolling, IndexAdvanceMode::kPost); diff --git a/deps/v8/src/builtins/builtins-dataview.cc b/deps/v8/src/builtins/builtins-dataview.cc index e7781790d10c..365913e17f21 100644 --- a/deps/v8/src/builtins/builtins-dataview.cc +++ b/deps/v8/src/builtins/builtins-dataview.cc @@ -177,7 +177,8 @@ BUILTIN(DataViewConstructor) { if (!length_tracking && view_byte_offset + view_byte_length > buffer_byte_length) { THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength)); + isolate, + NewRangeError(MessageTemplate::kInvalidDataViewLength, byte_length)); } // 18. Set O.[[ViewedArrayBuffer]] to buffer. diff --git a/deps/v8/src/builtins/builtins-date.cc b/deps/v8/src/builtins/builtins-date.cc index ad5c62f6383c..f2b28d1c53f5 100644 --- a/deps/v8/src/builtins/builtins-date.cc +++ b/deps/v8/src/builtins/builtins-date.cc @@ -63,8 +63,8 @@ BUILTIN(DateConstructor) { static_cast<double>(JSDate::CurrentTimeValue(isolate)); DateBuffer buffer = ToDateString(time_val, isolate->date_cache(), ToDateStringMode::kLocalDateAndTime); - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8( + {buffer.data(), buffer.size()})); } // [Construct] int const argc = args.length() - 1; @@ -739,8 +739,8 @@ BUILTIN(DatePrototypeToDateString) { CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString"); DateBuffer buffer = ToDateString(date->value(), isolate->date_cache(), ToDateStringMode::kLocalDate); - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8( + {buffer.data(), buffer.size()})); } // ES6 section 20.3.4.36 Date.prototype.toISOString ( ) @@ -754,8 +754,8 @@ BUILTIN(DatePrototypeToISOString) { } DateBuffer buffer = ToDateString(time_val, isolate->date_cache(), ToDateStringMode::kISODateAndTime); - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8( + {buffer.data(), buffer.size()})); } // ES6 section 20.3.4.41 Date.prototype.toString ( ) @@ -764,8 +764,8 @@ BUILTIN(DatePrototypeToString) { CHECK_RECEIVER(JSDate, date, "Date.prototype.toString"); DateBuffer buffer = ToDateString(date->value(), isolate->date_cache(), ToDateStringMode::kLocalDateAndTime); - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8( + {buffer.data(), buffer.size()})); } // ES6 section 20.3.4.42 Date.prototype.toTimeString ( ) @@ -774,8 +774,8 @@ BUILTIN(DatePrototypeToTimeString) { CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString"); DateBuffer buffer = ToDateString(date->value(), isolate->date_cache(), ToDateStringMode::kLocalTime); - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8( + {buffer.data(), buffer.size()})); } #ifdef V8_INTL_SUPPORT @@ -846,8 +846,8 @@ BUILTIN(DatePrototypeToUTCString) { CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString"); DateBuffer buffer = ToDateString(date->value(), isolate->date_cache(), ToDateStringMode::kUTCDateAndTime); - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromUtf8(base::VectorOf(buffer))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromUtf8( + {buffer.data(), buffer.size()})); } // ES6 section B.2.4.1 Date.prototype.getYear ( ) diff --git a/deps/v8/src/builtins/builtins-definitions.h b/deps/v8/src/builtins/builtins-definitions.h index cdf103579956..b1d82f663ff8 100644 --- a/deps/v8/src/builtins/builtins-definitions.h +++ b/deps/v8/src/builtins/builtins-definitions.h @@ -16,8 +16,15 @@ #define BUILTIN_LIST_FROM_TORQUE(CPP, TFJ_TSA, TFJ, TFC_TSA, TFC, TFS, TFH, ASM) #define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) #else -#include "builtins-generated/bytecodes-builtins-list.h" -#include "torque-generated/builtin-definitions.h" +#include "src/builtins/bytecodes-builtins-list.h" +// Torque's builtin definitions: the checked-in copy under src/gen/ if +// v8_use_checked_in_generated_headers, the generated header otherwise. See +// src/gen/README.md. +#ifdef V8_USE_CHECKED_IN_GENERATED_HEADERS +#include "src/gen/intl-wasm/builtin-definitions.h" // IWYU pragma: export +#else +#include "torque-generated/builtin-definitions.h" // IWYU pragma: export, nogncheck +#endif #endif #include "src/base/strong-alias.h" #include "src/common/globals.h" @@ -227,8 +234,8 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; #define BUILTIN_LIST_BASE_TIER1(CPP, TFJ_TSA, TFJ, TFC_TSA, TFC, TFS, TFH, \ ASM) \ /* GC write barriers */ \ - TFC(IndirectPointerBarrierSaveFP, IndirectPointerWriteBarrier) \ - TFC(IndirectPointerBarrierIgnoreFP, IndirectPointerWriteBarrier) \ + TFC(TrustedPointerBarrierSaveFP, TrustedPointerWriteBarrier) \ + TFC(TrustedPointerBarrierIgnoreFP, TrustedPointerWriteBarrier) \ \ /* Adaptors for CPP builtins with various formal parameter counts. */ \ /* We split these versions for simplicity (not all architectures have */ \ @@ -534,6 +541,8 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; TFS(SetDataProperties, NeedsContext{true}, kTarget, kSource) \ TFS(ProxyGetPropertyFastPath, NeedsContext{true}, kProxy, kName, kReceiver, \ kHandler) \ + TFC(ProxyGetPropertyTrapResultLazyDeoptContinuation, \ + ProxyGetPropertyTrapResultLazyDeoptContinuation) \ TFC(CopyDataPropertiesWithExcludedPropertiesOnStack, \ CopyDataPropertiesWithExcludedPropertiesOnStack) \ TFC(CopyDataPropertiesWithExcludedProperties, \ @@ -563,6 +572,12 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; ArrayNoArgumentConstructor) \ TFC(ArrayNoArgumentConstructor_HoleySmi_DontOverride, \ ArrayNoArgumentConstructor) \ + TFC(ArrayNoArgumentConstructor_Packed_DontOverride, \ + ArrayNoArgumentConstructor) \ + TFC(ArrayNoArgumentConstructor_PackedDouble_DontOverride, \ + ArrayNoArgumentConstructor) \ + TFC(ArrayNoArgumentConstructor_HoleyDouble_DontOverride, \ + ArrayNoArgumentConstructor) \ TFC(ArrayNoArgumentConstructor_PackedSmi_DisableAllocationSites, \ ArrayNoArgumentConstructor) \ TFC(ArrayNoArgumentConstructor_HoleySmi_DisableAllocationSites, \ @@ -579,6 +594,12 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; ArraySingleArgumentConstructor) \ TFC(ArraySingleArgumentConstructor_HoleySmi_DontOverride, \ ArraySingleArgumentConstructor) \ + TFC(ArraySingleArgumentConstructor_Packed_DontOverride, \ + ArraySingleArgumentConstructor) \ + TFC(ArraySingleArgumentConstructor_PackedDouble_DontOverride, \ + ArraySingleArgumentConstructor) \ + TFC(ArraySingleArgumentConstructor_HoleyDouble_DontOverride, \ + ArraySingleArgumentConstructor) \ TFC(ArraySingleArgumentConstructor_PackedSmi_DisableAllocationSites, \ ArraySingleArgumentConstructor) \ TFC(ArraySingleArgumentConstructor_HoleySmi_DisableAllocationSites, \ @@ -798,14 +819,10 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; IF_WASM(TFJ, WasmMethodWrapper, kDontAdaptArgumentsSentinel) \ ASM(FunctionPrototypeCall, JSTrampoline) \ CPP(FunctionPrototypeToString, kDontAdaptArgumentsSentinel) \ - IF_FUNCTION_ARGUMENTS_CALLER_ARE_ON_PROTOTYPE( \ - CPP, FunctionPrototypeLegacyArgumentsGetter, JSParameterCount(0)) \ - IF_FUNCTION_ARGUMENTS_CALLER_ARE_ON_PROTOTYPE( \ - CPP, FunctionPrototypeLegacyArgumentsSetter, JSParameterCount(1)) \ - IF_FUNCTION_ARGUMENTS_CALLER_ARE_ON_PROTOTYPE( \ - CPP, FunctionPrototypeLegacyCallerGetter, JSParameterCount(0)) \ - IF_FUNCTION_ARGUMENTS_CALLER_ARE_ON_PROTOTYPE( \ - CPP, FunctionPrototypeLegacyCallerSetter, JSParameterCount(1)) \ + CPP(FunctionPrototypeLegacyArgumentsGetter, JSParameterCount(0)) \ + CPP(FunctionPrototypeLegacyArgumentsSetter, JSParameterCount(1)) \ + CPP(FunctionPrototypeLegacyCallerGetter, JSParameterCount(0)) \ + CPP(FunctionPrototypeLegacyCallerSetter, JSParameterCount(1)) \ \ /* Belongs to Objects but is a dependency of GeneratorPrototypeResume */ \ TFS(CreateIterResultObject, NeedsContext{true}, kValue, kDone) \ @@ -1497,9 +1514,10 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; IF_WASM(ASM, WasmCompileLazy, WasmDummy) \ IF_WASM(ASM, WasmLiftoffFrameSetup, WasmDummy) \ IF_WASM(ASM, WasmDebugBreak, WasmDummy) \ - IF_WASM(ASM, WasmDebugTrap, WasmDummy) \ + IF_WASM(ASM, WasmTrapHandlerThrowTrap, WasmDummy) \ IF_WASM(ASM, WasmOnStackReplace, WasmDummy) \ IF_WASM(ASM, WasmHandleStackOverflow, WasmHandleStackOverflow) \ + IF_WASM(ASM, WasmReturnFromSegment, WasmDummy) \ IF_WASM(TFC, WasmFloat32ToNumber, WasmFloat32ToNumber) \ IF_WASM(TFC, WasmFloat64ToNumber, WasmFloat64ToTagged) \ IF_WASM(TFC, WasmFloat64ToString, WasmFloat64ToTagged) \ @@ -1535,15 +1553,6 @@ constexpr int kGearboxGenericBuiltinIdOffset = -2; CPP(SharedStructConstructor, JSParameterCount(0)) \ CPP(SharedArrayConstructor, JSParameterCount(0)) \ CPP(SharedArrayIsSharedArray, JSParameterCount(1)) \ - CPP(AtomicsMutexConstructor, JSParameterCount(0)) \ - CPP(AtomicsMutexIsMutex, JSParameterCount(1)) \ - CPP(AtomicsMutexLock, JSParameterCount(2)) \ - CPP(AtomicsMutexLockWithTimeout, JSParameterCount(3)) \ - CPP(AtomicsMutexTryLock, JSParameterCount(2)) \ - CPP(AtomicsConditionConstructor, JSParameterCount(0)) \ - CPP(AtomicsConditionIsCondition, JSParameterCount(1)) \ - CPP(AtomicsConditionWait, kDontAdaptArgumentsSentinel) \ - CPP(AtomicsConditionNotify, kDontAdaptArgumentsSentinel) \ \ /* AsyncGenerator */ \ \ diff --git a/deps/v8/src/builtins/builtins-error.cc b/deps/v8/src/builtins/builtins-error.cc index 6f4d61698997..951802913d7c 100644 --- a/deps/v8/src/builtins/builtins-error.cc +++ b/deps/v8/src/builtins/builtins-error.cc @@ -33,7 +33,7 @@ BUILTIN(ErrorCaptureStackTrace) { if (!IsJSObject(*object_obj)) { THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kInvalidArgument, object_obj)); + isolate, NewTypeError(MessageTemplate::kInvalidArgument)); } DirectHandle<JSObject> object = Cast<JSObject>(object_obj); diff --git a/deps/v8/src/builtins/builtins-function.cc b/deps/v8/src/builtins/builtins-function.cc index f7ca54126017..6e3b8b3f6475 100644 --- a/deps/v8/src/builtins/builtins-function.cc +++ b/deps/v8/src/builtins/builtins-function.cc @@ -160,12 +160,9 @@ MaybeDirectHandle<Object> CreateDynamicFunction(Isolate* isolate, JSFunction::GetDerivedMap(isolate, target, new_target)); DirectHandle<SharedFunctionInfo> shared_info(function->shared(), isolate); - DirectHandle<Map> map = - Map::AsLanguageMode(isolate, initial_map, shared_info); - DirectHandle<Context> context(function->context(), isolate); function = Factory::JSFunctionBuilder{isolate, shared_info, context} - .set_map(map) + .set_map(initial_map) .set_allocation_type(AllocationType::kYoung) .Build(); } @@ -314,8 +311,6 @@ BUILTIN(FunctionPrototypeToString) { isolate->factory()->Function_string())); } -#ifndef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - namespace { bool IsSloppyNormalJSFunction(Tagged<Object> receiver) { @@ -374,7 +369,5 @@ BUILTIN(FunctionPrototypeLegacyCallerSetter) { return ReadOnlyRoots(isolate).undefined_value(); } -#endif // !V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/builtins/builtins-inl.h b/deps/v8/src/builtins/builtins-inl.h index 220ec111dd21..7f8cbb9ae7b7 100644 --- a/deps/v8/src/builtins/builtins-inl.h +++ b/deps/v8/src/builtins/builtins-inl.h @@ -26,12 +26,12 @@ constexpr Builtin Builtins::RecordWrite(SaveFPRegsMode fp_mode) { } // static -constexpr Builtin Builtins::IndirectPointerBarrier(SaveFPRegsMode fp_mode) { +constexpr Builtin Builtins::TrustedPointerBarrier(SaveFPRegsMode fp_mode) { switch (fp_mode) { case SaveFPRegsMode::kIgnore: - return Builtin::kIndirectPointerBarrierIgnoreFP; + return Builtin::kTrustedPointerBarrierIgnoreFP; case SaveFPRegsMode::kSave: - return Builtin::kIndirectPointerBarrierSaveFP; + return Builtin::kTrustedPointerBarrierSaveFP; } UNREACHABLE(); } diff --git a/deps/v8/src/builtins/builtins-internal-gen.cc b/deps/v8/src/builtins/builtins-internal-gen.cc index 74703bcdb5c8..330b40b14fc4 100644 --- a/deps/v8/src/builtins/builtins-internal-gen.cc +++ b/deps/v8/src/builtins/builtins-internal-gen.cc @@ -260,7 +260,7 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler { BIND(&next); } - void IndirectPointerWriteBarrier(SaveFPRegsMode fp_mode) { + void TrustedPointerWriteBarrier(SaveFPRegsMode fp_mode) { CSA_DCHECK(this, IsMarking()); // For this barrier, the slot contains an index into a pointer table and not @@ -268,15 +268,15 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler { // with the indirect pointer tag of the slot, so it cannot directly be // dereferenced but needs to be decoded first. TNode<IntPtrT> slot = UncheckedParameter<IntPtrT>( - IndirectPointerWriteBarrierDescriptor::kSlotAddress); + TrustedPointerWriteBarrierDescriptor::kSlotAddress); TNode<IntPtrT> object = BitcastTaggedToWord(UncheckedParameter<Object>( - IndirectPointerWriteBarrierDescriptor::kObject)); + TrustedPointerWriteBarrierDescriptor::kObject)); TNode<IntPtrT> tag = UncheckedParameter<IntPtrT>( - IndirectPointerWriteBarrierDescriptor::kIndirectPointerTag); + TrustedPointerWriteBarrierDescriptor::kTrustedPointerTag); TNode<ExternalReference> function = ExternalConstant( ExternalReference:: - write_barrier_indirect_pointer_marking_from_code_function()); + write_barrier_trusted_pointer_marking_from_code_function()); CallCFunctionWithCallerSavedRegisters( function, MachineTypeOf<Int32T>::value, fp_mode, std::make_pair(MachineTypeOf<IntPtrT>::value, object), @@ -577,7 +577,7 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler { Return(TrueConstant()); } - void GenerateIndirectPointerBarrier(SaveFPRegsMode fp_mode) { + void GenerateTrustedPointerBarrier(SaveFPRegsMode fp_mode) { if (V8_DISABLE_WRITE_BARRIERS_BOOL) { Return(TrueConstant()); return; @@ -588,7 +588,7 @@ class WriteBarrierCodeStubAssembler : public CodeStubAssembler { return; } - IndirectPointerWriteBarrier(fp_mode); + TrustedPointerWriteBarrier(fp_mode); IncrementCounter(isolate()->counters()->write_barriers(), 1); Return(TrueConstant()); } @@ -626,12 +626,12 @@ TF_BUILTIN(RecordWriteIgnoreFP, WriteBarrierCodeStubAssembler) { GenerateRecordWrite(SaveFPRegsMode::kIgnore); } -TF_BUILTIN(IndirectPointerBarrierSaveFP, WriteBarrierCodeStubAssembler) { - GenerateIndirectPointerBarrier(SaveFPRegsMode::kSave); +TF_BUILTIN(TrustedPointerBarrierSaveFP, WriteBarrierCodeStubAssembler) { + GenerateTrustedPointerBarrier(SaveFPRegsMode::kSave); } -TF_BUILTIN(IndirectPointerBarrierIgnoreFP, WriteBarrierCodeStubAssembler) { - GenerateIndirectPointerBarrier(SaveFPRegsMode::kIgnore); +TF_BUILTIN(TrustedPointerBarrierIgnoreFP, WriteBarrierCodeStubAssembler) { + GenerateTrustedPointerBarrier(SaveFPRegsMode::kIgnore); } TF_BUILTIN(EphemeronKeyBarrierSaveFP, WriteBarrierCodeStubAssembler) { @@ -865,9 +865,15 @@ class TSANRelaxedLoadCodeStubAssembler : public CodeStubAssembler { void GenerateTSANRelaxedLoad(SaveFPRegsMode fp_mode, int size) { TNode<ExternalReference> function = GetExternalReference(size); auto address = UncheckedParameter<IntPtrT>(TSANLoadDescriptor::kAddress); + auto shared_base = + UncheckedParameter<Object>(TSANLoadDescriptor::kSharedBase); + auto invoke_tsan_acquire = + UncheckedParameter<Int32T>(TSANLoadDescriptor::kInvokeTsanAcquire); CallCFunctionWithCallerSavedRegisters( function, MachineType::Int32(), fp_mode, - std::make_pair(MachineType::IntPtr(), address)); + std::make_pair(MachineType::IntPtr(), address), + std::make_pair(MachineType::AnyTagged(), shared_base), + std::make_pair(MachineType::Int32(), invoke_tsan_acquire)); Return(UndefinedConstant()); } }; @@ -1261,13 +1267,13 @@ TF_BUILTIN(ForInEnumerate, CodeStubAssembler) { } TF_BUILTIN(ForInPrepare, CodeStubAssembler) { - // The {enumerator} is either a Map or a FixedArray. + // The {enumerator} is either a Map, a FixedArray, or a ForInEnumeratorHolder. auto enumerator = Parameter<HeapObject>(Descriptor::kEnumerator); auto index = Parameter<TaggedIndex>(Descriptor::kVectorIndex); auto feedback_vector = Parameter<FeedbackVector>(Descriptor::kFeedbackVector); TNode<UintPtrT> vector_index = Unsigned(TaggedIndexToIntPtr(index)); - TNode<FixedArray> cache_array; + TNode<Union<FixedArray, ForInEnumeratorHolder>> cache_array; TNode<Smi> cache_length; ForInPrepare(enumerator, vector_index, feedback_vector, &cache_array, &cache_length, UpdateFeedbackMode::kGuaranteedFeedback); diff --git a/deps/v8/src/builtins/builtins-intl-gen.cc b/deps/v8/src/builtins/builtins-intl-gen.cc index d4c7168db241..ec3e5b8848ce 100644 --- a/deps/v8/src/builtins/builtins-intl-gen.cc +++ b/deps/v8/src/builtins/builtins-intl-gen.cc @@ -9,6 +9,7 @@ #include "src/builtins/builtins-iterator-gen.h" #include "src/builtins/builtins-utils-gen.h" #include "src/codegen/code-stub-assembler-inl.h" +#include "src/objects/intl-objects.h" #include "src/objects/js-list-format-inl.h" #include "src/objects/js-list-format.h" #include "src/objects/objects-inl.h" @@ -48,12 +49,12 @@ class IntlBuiltinsAssembler : public CodeStubAssembler { // Jumps to {target} if the first two characters of {seq_string} equal // {pattern} ignoring case. void JumpIfStartsWithIgnoreCase(TNode<SeqOneByteString> seq_string, - const char* pattern, Label* target) { + std::string_view pattern, Label* target) { size_t effective_offset = OFFSET_OF_DATA_START(SeqOneByteString) - kHeapObjectTag; TNode<Uint16T> raw = Load<Uint16T>(seq_string, IntPtrConstant(effective_offset)); - DCHECK_EQ(strlen(pattern), 2); + DCHECK_EQ(pattern.length(), 2); #if V8_TARGET_BIG_ENDIAN int raw_pattern = (pattern[0] << 8) + pattern[1]; #else @@ -141,9 +142,9 @@ void IntlBuiltinsAssembler::ToLowerCaseImpl( to_direct.TryToDirect(&runtime); if (kind == ToLowerCaseKind::kToLocaleLowerCase) { - Label fast(this), check_locale(this); + Label fast(this), check_locale(this), is_undefined(this); // Check for fast locales. - GotoIf(IsUndefined(maybe_locales), &fast); + GotoIf(IsUndefined(maybe_locales), &is_undefined); // Passing a Smi as locales requires performing a ToObject conversion // followed by reading the length property and the "indexed" properties of // it until a valid locale is found. @@ -162,11 +163,18 @@ void IntlBuiltinsAssembler::ToLowerCaseImpl( GotoIf(IsNonAlpha(GetChar(locale, 4)), &runtime); Goto(&check_locale); + Bind(&is_undefined); + GotoIf(Word32NotEqual( + Load<Uint8T>(IsolateField( + IsolateFieldId::kDefaultLocaleMayRequireSpecialCaseMapping)), + Int32Constant(0)), + &runtime); + Goto(&fast); + Bind(&check_locale); - JumpIfStartsWithIgnoreCase(locale, "az", &runtime); - JumpIfStartsWithIgnoreCase(locale, "el", &runtime); - JumpIfStartsWithIgnoreCase(locale, "lt", &runtime); - JumpIfStartsWithIgnoreCase(locale, "tr", &runtime); + for (std::string_view special_locale : Intl::kCaseMappingSpecialLocales) { + JumpIfStartsWithIgnoreCase(locale, special_locale, &runtime); + } Goto(&fast); Bind(&fast); diff --git a/deps/v8/src/builtins/builtins-intl.cc b/deps/v8/src/builtins/builtins-intl.cc index 315b5f8c2c77..00efa7abd43b 100644 --- a/deps/v8/src/builtins/builtins-intl.cc +++ b/deps/v8/src/builtins/builtins-intl.cc @@ -241,7 +241,7 @@ DirectHandle<JSFunction> CreateBoundFunction(Isolate* isolate, isolate->factory()->empty_string(), builtin, len, kAdapt); return Factory::JSFunctionBuilder{isolate, info, context} - .set_map(isolate->strict_function_without_prototype_map()) + .set_map(isolate->function_without_prototype_map()) .Build(); } @@ -1037,8 +1037,9 @@ bool IsFastLocale(Tagged<Object> maybe_locale) { } char first = chars[0] | 0x20; char second = chars[1] | 0x20; - return (first != 'a' || second != 'z') && (first != 'e' || second != 'l') && - (first != 'l' || second != 't') && (first != 't' || second != 'r'); + char language[] = {first, second}; + return !Intl::LocaleRequiresSpecialCaseMapping( + std::string_view(language, arraysize(language))); } // https://tc39.es/ecma402/#sup-string.prototype.tolocaleuppercase @@ -1046,7 +1047,11 @@ BUILTIN(StringPrototypeToLocaleUpperCase) { HandleScope scope(isolate); DirectHandle<Object> maybe_locale = args.atOrUndefined(isolate, 1); TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase"); - if (IsUndefined(*maybe_locale) || IsFastLocale(*maybe_locale)) { + bool can_use_fast_path = + IsUndefined(*maybe_locale) + ? !isolate->DefaultLocaleMayRequireSpecialCaseMapping() + : IsFastLocale(*maybe_locale); + if (can_use_fast_path) { string = String::Flatten(isolate, string); RETURN_RESULT_OR_FAILURE(isolate, Intl::ConvertToUpper(isolate, string)); } else { diff --git a/deps/v8/src/builtins/builtins-iterator-inl.h b/deps/v8/src/builtins/builtins-iterator-inl.h index ca0897c0855d..92ebe20ec123 100644 --- a/deps/v8/src/builtins/builtins-iterator-inl.h +++ b/deps/v8/src/builtins/builtins-iterator-inl.h @@ -16,7 +16,6 @@ #include "src/objects/js-array-inl.h" #include "src/objects/js-collection-inl.h" #include "src/objects/js-objects-inl.h" -#include "src/objects/js-regexp-string-iterator-inl.h" #include "src/objects/object-conversions-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/ordered-hash-table-inl.h" @@ -77,83 +76,64 @@ inline MaybeDirectHandle<JSReceiver> IteratorStep( // https://tc39.es/ecma262/#sec-iteratorclose inline void IteratorClose(Isolate* isolate, DirectHandle<JSReceiver> iterator) { DirectHandle<Object> completion_exception; + DirectHandle<Object> completion_message; + bool has_completion_exception = isolate->has_exception(); if (has_completion_exception) { + if (isolate->is_execution_terminating()) { + // Don't swallow the termination exception. + return; + } completion_exception = handle(isolate->exception(), isolate); + completion_message = handle(isolate->pending_message(), isolate); isolate->clear_exception(); + isolate->clear_pending_message(); } // 3. Let innerResult be GetMethod(iterator, "return"). DirectHandle<Object> return_method; - DirectHandle<Object> inner_exception; - bool has_inner_exception = false; - - if (!Object::GetProperty(isolate, iterator, - isolate->factory()->return_string()) - .ToHandle(&return_method)) { - has_inner_exception = true; - inner_exception = handle(isolate->exception(), isolate); - isolate->clear_exception(); - } else if (!IsNullOrUndefined(*return_method)) { + if (Object::GetProperty(isolate, iterator, + isolate->factory()->return_string()) + .ToHandle(&return_method) && + !IsNullOrUndefined(*return_method)) { // 4. If innerResult.[[Type]] is normal, then // a. Let return be innerResult.[[Value]]. // b. If return is undefined, return Completion(completion). // c. Set innerResult to Call(return, iterator). DirectHandle<Object> inner_result; - if (!Execution::Call(isolate, return_method, iterator, - base::Vector<const DirectHandle<Object>>()) - .ToHandle(&inner_result)) { - has_inner_exception = true; - inner_exception = handle(isolate->exception(), isolate); - isolate->clear_exception(); - } else { + if (Execution::Call(isolate, return_method, iterator, + base::Vector<const DirectHandle<Object>>()) + .ToHandle(&inner_result)) { // 7. If innerResult.[[Value]] is not an Object, throw a TypeError // exception. if (!has_completion_exception && !IsJSReceiver(*inner_result)) { - has_inner_exception = true; - inner_exception = isolate->factory()->NewTypeError( + isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kCalledOnNonObject, - isolate->factory()->return_string()); + isolate->factory()->return_string())); } } } // 5. If completion is a throw completion, return ? completion. - if (has_completion_exception) { + // 6. If innerResult is a throw completion, return ? innerResult. + if (has_completion_exception && !isolate->is_execution_terminating()) { isolate->set_exception(*completion_exception); - } else if (has_inner_exception) { - // 6. If innerResult is a throw completion, return ? innerResult. - isolate->set_exception(*inner_exception); + isolate->set_pending_message(*completion_message); } } -inline void CloseAndMarkIteratorDone(Isolate* isolate, - DirectHandle<JSReceiver> iterator) { - // 7.4.11 IteratorClose ( iteratorRecord, completion ) - // Ordinary iterators, generators, and iterator helpers implement a .return() - // method in JS/bytecode. IteratorClose successfully invokes their .return() - // method to finalize them. However, V8's core native built-in iterators - // (Array, Map, Set, String, RegExp) are implemented purely in C++ and lack a - // JS .return() method. For them, IteratorClose is a no-op, so we must - // manually exhaust them by wiping their C++ backing fields. We do this - // before calling IteratorClose to ensure that custom monkey-patched .return() - // methods observe the iterator as exhausted. - if (IsJSArrayIterator(*iterator)) { - auto num = isolate->factory()->NewNumberFromUint(kMaxUInt32); - Cast<JSArrayIterator>(iterator)->set_next_index(*num); - } else if (IsJSMapIterator(*iterator)) { - Cast<JSMapIterator>(iterator)->set_table( - ReadOnlyRoots(isolate).empty_ordered_hash_map()); - } else if (IsJSSetIterator(*iterator)) { - Cast<JSSetIterator>(iterator)->set_table( - ReadOnlyRoots(isolate).empty_ordered_hash_set()); - } else if (IsJSStringIterator(*iterator)) { - DirectHandle<JSStringIterator> str_iterator = - Cast<JSStringIterator>(iterator); - str_iterator->set_index(str_iterator->string()->length()); - } else if (IsJSRegExpStringIterator(*iterator)) { - Cast<JSRegExpStringIterator>(iterator)->set_done(true); - } +inline void CloseFreshArrayIterator(Isolate* isolate, + DirectHandle<JSReceiver> iterated_object, + double next_index) { + DirectHandle<Map> map(isolate->native_context()->initial_array_iterator_map(), + isolate); + DirectHandle<Number> next_index_obj = + isolate->factory()->NewNumber(next_index); + DirectHandle<JSArrayIterator> iterator = + Cast<JSArrayIterator>(isolate->factory()->NewJSObjectFromMap(map)); + iterator->set_iterated_object(*iterated_object); + iterator->set_next_index(*next_index_obj); + iterator->set_kind(IterationKind::kValues); IteratorClose(isolate, iterator); } @@ -194,7 +174,6 @@ MaybeDirectHandle<Object> IterableForEach( if (IsFastElementsKind(kind) && array->HasArrayPrototype(isolate) && (!IsHoleyElementsKind(kind) || Protectors::IsNoElementsIntact(isolate))) { - DisallowJavascriptExecution no_js; DirectHandle<FixedArrayBase> elements(array->elements(), isolate); uint32_t len; if (Object::ToUint32(array->length(), &len)) { @@ -205,67 +184,74 @@ MaybeDirectHandle<Object> IterableForEach( if (len == 0) { return isolate->root_handle(RootIndex::kUndefinedValue); } - const MaybeDirectHandle<Object> abort; - if (kind == PACKED_SMI_ELEMENTS) { - DirectHandle<FixedArray> smi_elements = Cast<FixedArray>(elements); - for (uint32_t i = 0; i < len; ++i) { - Tagged<Object> obj = smi_elements->get(i); - if (!int_visitor(Smi::ToInt(obj))) return abort; - } - } else if (kind == HOLEY_SMI_ELEMENTS) { - DirectHandle<FixedArray> smi_elements = Cast<FixedArray>(elements); - for (uint32_t i = 0; i < len; ++i) { - Tagged<Object> obj = smi_elements->get(i); - if (IsTheHole(obj)) { - if (!generic_visitor( - isolate->root_handle(RootIndex::kUndefinedValue))) { - return abort; + uint32_t i = 0; + { + DisallowJavascriptExecution no_js; + if (kind == PACKED_SMI_ELEMENTS) { + DirectHandle<FixedArray> smi_elements = Cast<FixedArray>(elements); + for (; i < len; ++i) { + Tagged<Object> obj = smi_elements->get(i); + if (!int_visitor(Smi::ToInt(obj))) break; + } + } else if (kind == HOLEY_SMI_ELEMENTS) { + DirectHandle<FixedArray> smi_elements = Cast<FixedArray>(elements); + for (; i < len; ++i) { + Tagged<Object> obj = smi_elements->get(i); + if (IsTheHole(obj)) { + if (!generic_visitor( + isolate->root_handle(RootIndex::kUndefinedValue))) { + break; + } + } else { + if (!int_visitor(Smi::ToInt(obj))) break; } - } else { - if (!int_visitor(Smi::ToInt(obj))) return abort; } - } - } else if (kind == PACKED_DOUBLE_ELEMENTS) { - DirectHandle<FixedDoubleArray> double_elements = - Cast<FixedDoubleArray>(elements); - for (uint32_t i = 0; i < len; ++i) { - if (!double_visitor(double_elements->get_scalar(i))) return abort; - } - } else if (kind == HOLEY_DOUBLE_ELEMENTS) { - DirectHandle<FixedDoubleArray> double_elements = - Cast<FixedDoubleArray>(elements); - for (uint32_t i = 0; i < len; ++i) { - if (double_elements->is_the_hole(i) || + } else if (kind == PACKED_DOUBLE_ELEMENTS) { + DirectHandle<FixedDoubleArray> double_elements = + Cast<FixedDoubleArray>(elements); + for (; i < len; ++i) { + if (!double_visitor(double_elements->get_scalar(i))) break; + } + } else if (kind == HOLEY_DOUBLE_ELEMENTS) { + DirectHandle<FixedDoubleArray> double_elements = + Cast<FixedDoubleArray>(elements); + for (; i < len; ++i) { + if (double_elements->is_the_hole(i) || #ifdef V8_ENABLE_UNDEFINED_DOUBLE - double_elements->is_undefined(i) + double_elements->is_undefined(i) #else - false + false #endif // V8_ENABLE_UNDEFINED_DOUBLE - ) { - if (!generic_visitor( - isolate->root_handle(RootIndex::kUndefinedValue))) { - return abort; + ) { + if (!generic_visitor( + isolate->root_handle(RootIndex::kUndefinedValue))) { + break; + } + } else { + if (!double_visitor(double_elements->get_scalar(i))) break; } - } else { - if (!double_visitor(double_elements->get_scalar(i))) return abort; } - } - } else { - DirectHandle<FixedArray> fast_elements = Cast<FixedArray>(elements); - DirectHandle<Object> obj_handle(Smi::zero(), isolate); - for (uint32_t i = 0; i < len; ++i) { - Tagged<Object> obj = fast_elements->get(i); - if (IsTheHole(obj)) { - if (!generic_visitor( - isolate->root_handle(RootIndex::kUndefinedValue))) { - return abort; + } else { + DirectHandle<FixedArray> fast_elements = Cast<FixedArray>(elements); + DirectHandle<Object> obj_handle(Smi::zero(), isolate); + for (; i < len; ++i) { + Tagged<Object> obj = fast_elements->get(i); + if (IsTheHole(obj)) { + if (!generic_visitor( + isolate->root_handle(RootIndex::kUndefinedValue))) { + break; + } + } else { + obj_handle.SetValue(obj); + if (!dispatch(obj_handle)) break; } - } else { - obj_handle.SetValue(obj); - if (!dispatch(obj_handle)) return abort; } } } + if (i < len) { + CloseFreshArrayIterator(isolate, array, i + 1); + return MaybeDirectHandle<Object>(); + } return isolate->root_handle(RootIndex::kUndefinedValue); } } @@ -290,6 +276,7 @@ MaybeDirectHandle<Object> IterableForEach( Protectors::IsArrayIteratorLookupChainIntact(isolate) && IsJSFunction(*iterator_fn)) { if (DirectHandle<JSFunction> func = Cast<JSFunction>(iterator_fn); + func->native_context() == *isolate->native_context() && isolate->builtins() ->code(Builtin::kTypedArrayPrototypeValues) .SafeEquals(func->code(isolate))) { @@ -320,18 +307,21 @@ MaybeDirectHandle<Object> IterableForEach( i * sizeof(ctype)); \ if constexpr (ElementsKind::TYPE##_ELEMENTS == FLOAT16_ELEMENTS) { \ if (!double_visitor(fp16_ieee_to_fp32_value(val))) { \ + CloseFreshArrayIterator(isolate, typed_array, i + 1); \ return MaybeDirectHandle<Object>(); \ } \ } else if constexpr (std::is_integral_v<ctype> && \ base::kIsTypeInRangeForNumericType<int, ctype>) { \ auto cast = [](auto v) { return base::strict_cast<int>(v); }; \ if (!int_visitor(cast(val))) { \ + CloseFreshArrayIterator(isolate, typed_array, i + 1); \ return MaybeDirectHandle<Object>(); \ } \ } else { \ static_assert(base::kIsTypeInRangeForNumericType<double, ctype>); \ auto cast = [](auto v) { return base::strict_cast<double>(v); }; \ if (!double_visitor(cast(val))) { \ + CloseFreshArrayIterator(isolate, typed_array, i + 1); \ return MaybeDirectHandle<Object>(); \ } \ } \ @@ -376,6 +366,8 @@ MaybeDirectHandle<Object> IterableForEach( // Medium fast path for JSArrayIterator. if (IsJSArrayIterator(*iterator) && + iterator->map()->prototype() == + isolate->native_context()->initial_array_iterator_prototype() && Protectors::IsArrayIteratorLookupChainIntact(isolate) && Protectors::IsNoElementsIntact(isolate)) { DirectHandle<JSArrayIterator> array_iterator = @@ -399,9 +391,6 @@ MaybeDirectHandle<Object> IterableForEach( Object::ToUint32(array_iterator->next_index(), ¤t_index)) { DCHECK_IMPLIES(max_count, len < *max_count); if (max_count_out) *max_count_out = len; - if (len == 0) { - return isolate->root_handle(RootIndex::kUndefinedValue); - } DirectHandle<Object> obj_handle(Smi::zero(), isolate); { std::optional<DisallowJavascriptExecution> no_js; @@ -487,6 +476,9 @@ MaybeDirectHandle<Object> IterableForEach( } // Check if all the required invariants still hold. if (!IsJSArrayIterator(*iterator) || + iterator->map()->prototype() != + isolate->native_context() + ->initial_array_iterator_prototype() || !Protectors::IsArrayIteratorLookupChainIntact(isolate) || !Protectors::IsNoElementsIntact(isolate) || !IsJSArray(*iterated_object) || @@ -502,12 +494,14 @@ MaybeDirectHandle<Object> IterableForEach( } if (switch_to_protocol || current_index < len) { if (!switch_to_protocol) { - CloseAndMarkIteratorDone(isolate, iterator); + if constexpr (!kAllowJSExecution) { + auto num = + isolate->factory()->NewNumberFromUint(current_index + 1); + array_iterator->set_next_index(*num); + } + IteratorClose(isolate, iterator); return MaybeDirectHandle<Object>(); } - auto num = - isolate->factory()->NewNumberFromUint(current_index + 1); - array_iterator->set_next_index(*num); // We had to abandon optimized iteration. Fall through and // continue normal iteration. } else { @@ -521,8 +515,10 @@ MaybeDirectHandle<Object> IterableForEach( } } - // Medium fast path for JSSetIterator. - if (!kAllowJSExecution && IsJSSetIterator(*iterator) && + // Medium fast path for JSSetValueIterator. + if (!kAllowJSExecution && IsJSSetValueIterator(*iterator) && + iterator->map()->prototype() == + isolate->native_context()->initial_set_iterator_prototype() && Protectors::IsSetIteratorLookupChainIntact(isolate)) { DirectHandle<JSSetIterator> set_iterator = Cast<JSSetIterator>(iterator); DirectHandle<Object> table_obj(set_iterator->table(), isolate); @@ -547,7 +543,8 @@ MaybeDirectHandle<Object> IterableForEach( } } if (current_index < capacity) { - CloseAndMarkIteratorDone(isolate, iterator); + set_iterator->set_index(Smi::FromInt(current_index + 1)); + IteratorClose(isolate, iterator); return MaybeDirectHandle<Object>(); } set_iterator->set_table( @@ -600,7 +597,7 @@ MaybeDirectHandle<Object> IterableForEach( if (max_count_out) *max_count_out = count; isolate->Throw(*isolate->factory()->NewRangeError( MessageTemplate::kStackOverflow)); - CloseAndMarkIteratorDone(isolate, iterator); + IteratorClose(isolate, iterator); return MaybeDirectHandle<Object>(); } } @@ -608,7 +605,7 @@ MaybeDirectHandle<Object> IterableForEach( if (!dispatch(next_value_handle)) { // 7.4.13 IfAbruptCloseIterator (value, iteratorRecord) // The dispatch failed (visitor threw). We must close the iterator. - CloseAndMarkIteratorDone(isolate, iterator); + IteratorClose(isolate, iterator); return MaybeDirectHandle<Object>(); } } diff --git a/deps/v8/src/builtins/builtins-proxy-gen.cc b/deps/v8/src/builtins/builtins-proxy-gen.cc index 1cce95ee3ae9..80ffe21da18b 100644 --- a/deps/v8/src/builtins/builtins-proxy-gen.cc +++ b/deps/v8/src/builtins/builtins-proxy-gen.cc @@ -451,13 +451,13 @@ TF_BUILTIN(ProxyGetPropertyFastPath, ProxiesCodeStubAssembler) { TNode<HeapObject> target = CAST(LoadObjectField(proxy, offsetof(JSProxy, target_))); GotoIf(TaggedEqual(target, NullConstant()), &miss); + TNode<Map> target_check_map; { TNode<MaybeObject> maybe_target_check_map = accessors.LoadHandlerDataField( handler, LoadHandler::kProxyTargetMapDataIndex); CSA_DCHECK(this, IsWeakOrCleared(maybe_target_check_map)); GotoIf(IsCleared(maybe_target_check_map), &miss); - TNode<Map> target_check_map = - CAST(GetHeapObjectAssumeWeak(maybe_target_check_map)); + target_check_map = CAST(GetHeapObjectAssumeWeak(maybe_target_check_map)); TNode<Map> target_map = LoadMap(target); GotoIfNot(TaggedEqual(target_check_map, target_map), &miss); } @@ -532,6 +532,14 @@ TF_BUILTIN(ProxyGetPropertyFastPath, ProxiesCodeStubAssembler) { TNode<Object> result = CallFunction( context, trap_function, ConvertReceiverMode::kNotNullOrUndefined, proxy_receiver, target_any, name, receiver); + Label check_result(this, Label::kDeferred); + TNode<Map> new_target_map = LoadMap(target); + GotoIfNot(TaggedEqual(target_check_map, new_target_map), &check_result); + Return(result); + + BIND(&check_result); + CheckGetSetTrapResult(context, CAST(target), proxy, name, result, + JSProxy::kGet); Return(result); } @@ -539,6 +547,19 @@ TF_BUILTIN(ProxyGetPropertyFastPath, ProxiesCodeStubAssembler) { Return(TheHoleConstant()); } +TF_BUILTIN(ProxyGetPropertyTrapResultLazyDeoptContinuation, + ProxiesCodeStubAssembler) { + auto context = Parameter<Context>(Descriptor::kContext); + auto target = Parameter<JSReceiver>(Descriptor::kTarget); + auto proxy = Parameter<JSProxy>(Descriptor::kProxy); + auto name = Parameter<Name>(Descriptor::kName); + auto trap_result = Parameter<Object>(Descriptor::kTrapResult); + + CheckGetSetTrapResult(context, target, proxy, name, trap_result, + JSProxy::kGet); + Return(trap_result); +} + #include "src/codegen/undef-code-stub-assembler-macros.inc" } // namespace internal diff --git a/deps/v8/src/builtins/builtins-regexp-gen.cc b/deps/v8/src/builtins/builtins-regexp-gen.cc index fa705e82105f..d02bf5b89768 100644 --- a/deps/v8/src/builtins/builtins-regexp-gen.cc +++ b/deps/v8/src/builtins/builtins-regexp-gen.cc @@ -177,8 +177,8 @@ void RegExpBuiltinsAssembler::SlowStoreLastIndex(TNode<Context> context, TNode<RegExpData> RegExpBuiltinsAssembler::LoadRegExpDataFromObject( TNode<HeapObject> object, int offset) { - return LoadTrustedPointerFromObject<kRegExpDataIndirectPointerTag>(object, - offset); + return LoadTrustedPointerFromObject<kRegExpDataTrustedPointerTag>(object, + offset); } // On a hit, sets {var_result} to a fresh array over the cached parts and jumps @@ -925,7 +925,7 @@ TNode<UintPtrT> RegExpBuiltinsAssembler::RegExpExecInternal( TVARIABLE(RawPtrT, var_string_start); TVARIABLE(RawPtrT, var_string_end); #ifdef V8_ENABLE_SANDBOX - using kVarCodeT = IndirectPointerHandleT; + using kVarCodeT = TrustedPointerHandleT; #else using kVarCodeT = Object; #endif @@ -970,7 +970,7 @@ TNode<UintPtrT> RegExpBuiltinsAssembler::RegExpExecInternal( #ifdef V8_ENABLE_SANDBOX GotoIf( - Word32Equal(var_code.value(), Int32Constant(kNullIndirectPointerHandle)), + Word32Equal(var_code.value(), Int32Constant(kNullTrustedPointerHandle)), &runtime); #else GotoIf(TaggedIsSmi(var_code.value()), &runtime); @@ -1034,7 +1034,7 @@ TNode<UintPtrT> RegExpBuiltinsAssembler::RegExpExecInternal( #ifdef V8_ENABLE_SANDBOX TNode<Code> code = TrustedCast<Code>( - ResolveIndirectPointerHandle(var_code.value(), kCodeIndirectPointerTag), + ResolveTrustedPointerHandle(var_code.value(), kCodeTrustedPointerTag), "from trusted table"); #else TNode<Code> code = TrustedCast<Code>(var_code.value(), "no sandbox"); diff --git a/deps/v8/src/builtins/builtins-regexp.cc b/deps/v8/src/builtins/builtins-regexp.cc index a817e87ef408..01aa5b80cfd4 100644 --- a/deps/v8/src/builtins/builtins-regexp.cc +++ b/deps/v8/src/builtins/builtins-regexp.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/base/unique-array.h" #include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins.h" #include "src/logging/counters.h" @@ -222,7 +223,7 @@ constexpr const uint8_t kAsciiEscapes[128]{ template <typename CharT> MaybeDirectHandle<String> RegExpEscapeImpl(Isolate* isolate, - base::OwnedVector<CharT> source) { + base::UniqueArray<CharT> source) { char double_to_radix_chars[kDoubleToRadixMaxChars]; base::Vector<char> double_to_radix_buffer = base::ArrayVector(double_to_radix_chars); @@ -373,18 +374,18 @@ BUILTIN(RegExpEscape) { // the escaped string using IncrementalStringBuilder, which may allocate. str = String::Flatten(isolate, str); if (String::IsOneByteRepresentationUnderneath(*str)) { - base::OwnedVector<const uint8_t> copy; + base::UniqueArray<const uint8_t> copy; { DisallowGarbageCollection no_gc; - copy = base::OwnedCopyOf(str->GetFlatContent(no_gc).ToOneByteVector()); + copy = base::UniqueCopyOf(str->GetFlatContent(no_gc).ToOneByteVector()); } ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, escaped, RegExpEscapeImpl(isolate, std::move(copy))); } else { - base::OwnedVector<const base::uc16> copy; + base::UniqueArray<const base::uc16> copy; { DisallowGarbageCollection no_gc; - copy = base::OwnedCopyOf(str->GetFlatContent(no_gc).ToUC16Vector()); + copy = base::UniqueCopyOf(str->GetFlatContent(no_gc).ToUC16Vector()); } ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, escaped, RegExpEscapeImpl(isolate, std::move(copy))); diff --git a/deps/v8/src/builtins/builtins-shadow-realm.cc b/deps/v8/src/builtins/builtins-shadow-realm.cc index ecd6be61383b..aeffcbbfa33a 100644 --- a/deps/v8/src/builtins/builtins-shadow-realm.cc +++ b/deps/v8/src/builtins/builtins-shadow-realm.cc @@ -87,17 +87,11 @@ BUILTIN(ShadowRealmPrototypeEvaluate) { HandleScope scope(isolate); Handle<Object> source_text = args.atOrUndefined(isolate, 1); - // 1. Let O be this value. - DirectHandle<Object> receiver = args.receiver(); - Factory* factory = isolate->factory(); + // 1. Let O be this value. // 2. Perform ? ValidateShadowRealmObject(O). - if (!IsJSShadowRealm(*receiver)) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver)); - } - auto shadow_realm = Cast<JSShadowRealm>(receiver); + CHECK_RECEIVER(JSShadowRealm, shadow_realm, "ShadowRealm.prototype.evaluate"); // 3. If Type(sourceText) is not String, throw a TypeError exception. if (!IsString(*source_text)) { diff --git a/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc b/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc index b19c353c2669..412d16af8017 100644 --- a/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc +++ b/deps/v8/src/builtins/builtins-sharedarraybuffer-gen.cc @@ -208,7 +208,7 @@ TNode<UintPtrT> SharedArrayBufferBuiltinsAssembler::ValidateAtomicAccess( Unreachable(); BIND(&range_error); - ThrowRangeError(context, MessageTemplate::kInvalidAtomicAccessIndex); + ThrowRangeError(context, MessageTemplate::kInvalidAtomicAccessIndex, index); // 6. Return accessIndex. BIND(&done); diff --git a/deps/v8/src/builtins/builtins-sharedarraybuffer.cc b/deps/v8/src/builtins/builtins-sharedarraybuffer.cc index 430a251b77b1..c5015226a930 100644 --- a/deps/v8/src/builtins/builtins-sharedarraybuffer.cc +++ b/deps/v8/src/builtins/builtins-sharedarraybuffer.cc @@ -100,7 +100,7 @@ V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess( if (!TryNumberToSize(*access_index_obj, &access_index) || access_index >= typed_array_length) { isolate->Throw(*isolate->factory()->NewRangeError( - MessageTemplate::kInvalidAtomicAccessIndex)); + MessageTemplate::kInvalidAtomicAccessIndex, access_index_obj)); return Nothing<size_t>(); } return Just<size_t>(access_index); diff --git a/deps/v8/src/builtins/builtins-string-tsa-inl.h b/deps/v8/src/builtins/builtins-string-tsa-inl.h index c8ded617619d..54ac7e45980f 100644 --- a/deps/v8/src/builtins/builtins-string-tsa-inl.h +++ b/deps/v8/src/builtins/builtins-string-tsa-inl.h @@ -59,13 +59,11 @@ class StringBuiltinsReducer : public Next { character_count); FOREACH(src_char, dst_offset, Zip(src_view, Sequence(dst_begin_offset, dst_stride))) { -#if DEBUG // Copying two-byte characters to one-byte is okay if callers have // checked that this loses no information. - if (v8_flags.debug_code && !src_one_byte && dst_one_byte) { + if (!src_one_byte && dst_one_byte) { TSA_DCHECK(this, __ Uint32LessThanOrEqual(src_char, 0xFF)); } -#endif __ Store(dst_offset, src_char, StoreOp::Kind::RawAligned(), dst_rep, compiler::kNoWriteBarrier); } @@ -490,10 +488,10 @@ class StringBuiltinsReducer : public Next { GOTO_IF(__ IsGetString(name), done, 1); GOTO_IF(__ IsThenString(name), done, 1); GOTO_IF_NOT(__ IsSymbolMap(__ LoadMapField(name)), done, 0); - GOTO_IF( - __ template IsSetWord32<Symbol::IsInterestingSymbolBit>(V<Word32>::Cast( - __ LoadField(name, AccessBuilderTS::ForSymbolFlags()))), - done, 1); + GOTO_IF(__ template IsSetWord32<Symbol::Flags::IsInterestingSymbolBit>( + V<Word32>::Cast( + __ LoadField(name, AccessBuilderTS::ForSymbolFlags()))), + done, 1); GOTO(done, 0); BIND(done, result); diff --git a/deps/v8/src/builtins/builtins-string.cc b/deps/v8/src/builtins/builtins-string.cc index 235d2f09c1e2..5a97eb702e14 100644 --- a/deps/v8/src/builtins/builtins-string.cc +++ b/deps/v8/src/builtins/builtins-string.cc @@ -84,9 +84,8 @@ BUILTIN(StringFromCodePoint) { } if (index == length) { - RETURN_RESULT_OR_FAILURE( - isolate, isolate->factory()->NewStringFromOneByte(base::Vector<uint8_t>( - one_byte_buffer.data(), one_byte_buffer.size()))); + RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromOneByte( + base::VectorOf(one_byte_buffer))); } std::vector<base::uc16> two_byte_buffer; @@ -113,8 +112,8 @@ BUILTIN(StringFromCodePoint) { DirectHandle<SeqTwoByteString> result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, - isolate->factory()->NewRawTwoByteString( - static_cast<int>(one_byte_buffer.size() + two_byte_buffer.size()))); + isolate->factory()->NewRawTwoByteString(static_cast<uint32_t>( + one_byte_buffer.size() + two_byte_buffer.size()))); DisallowGarbageCollection no_gc; CopyChars(result->GetChars(no_gc), one_byte_buffer.data(), diff --git a/deps/v8/src/builtins/builtins-struct.cc b/deps/v8/src/builtins/builtins-struct.cc index 0ab121a50120..01dc582ab5f6 100644 --- a/deps/v8/src/builtins/builtins-struct.cc +++ b/deps/v8/src/builtins/builtins-struct.cc @@ -176,7 +176,7 @@ BUILTIN(SharedStructTypeConstructor) { DirectHandle<JSFunction> constructor = Factory::JSFunctionBuilder{isolate, info, isolate->native_context()} - .set_map(isolate->strict_function_with_readonly_prototype_map()) + .set_map(isolate->function_with_readonly_prototype_map()) .Build(); constructor->set_prototype_or_initial_map(*instance_map, kReleaseStore); @@ -205,17 +205,5 @@ BUILTIN(SharedStructTypeIsSharedStruct) { IsJSSharedStruct(*args.atOrUndefined(isolate, 1))); } -BUILTIN(AtomicsMutexIsMutex) { - HandleScope scope(isolate); - return isolate->heap()->ToBoolean( - IsJSAtomicsMutex(*args.atOrUndefined(isolate, 1))); -} - -BUILTIN(AtomicsConditionIsCondition) { - HandleScope scope(isolate); - return isolate->heap()->ToBoolean( - IsJSAtomicsCondition(*args.atOrUndefined(isolate, 1))); -} - } // namespace internal } // namespace v8 diff --git a/deps/v8/src/builtins/builtins-typed-array-gen.cc b/deps/v8/src/builtins/builtins-typed-array-gen.cc index 9a14e7162b00..5048321f0ee7 100644 --- a/deps/v8/src/builtins/builtins-typed-array-gen.cc +++ b/deps/v8/src/builtins/builtins-typed-array-gen.cc @@ -63,8 +63,8 @@ TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer( StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0)); #endif - int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) | - (1 << JSArrayBuffer::IsDetachableBit::kShift); + int32_t bitfield_value = (1 << JSArrayBuffer::Bits::IsExternalBit::kShift) | + (1 << JSArrayBuffer::Bits::IsDetachableBit::kShift); StoreObjectFieldNoWriteBarrier(buffer, offsetof(JSArrayBuffer, bit_field_), Int32Constant(bitfield_value)); diff --git a/deps/v8/src/builtins/builtins-typed-array.cc b/deps/v8/src/builtins/builtins-typed-array.cc index 8dc3fe9b1bbb..abcc4ca64da7 100644 --- a/deps/v8/src/builtins/builtins-typed-array.cc +++ b/deps/v8/src/builtins/builtins-typed-array.cc @@ -642,13 +642,12 @@ BUILTIN(Uint8ArrayPrototypeSetFromBase64) { isolate, uint8array, JSTypedArray::Validate(isolate, args.receiver(), method_name, TypedArrayAccessMode::kWrite)); - ElementsKind elements_kind = uint8array->GetElementsKind(); - if (elements_kind != ElementsKind::UINT8_ELEMENTS && - elements_kind != ElementsKind::RAB_GSAB_UINT8_ELEMENTS) { + if (!IsUint8JSTypedArray(*uint8array)) { THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); + isolate, + NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, + isolate->factory()->NewStringFromAsciiChecked(method_name), + uint8array)); } // 3. If string is not a String, throw a TypeError exception. @@ -761,15 +760,7 @@ BUILTIN(Uint8ArrayPrototypeToBase64) { // 1. Let O be the this value. // 2. Perform ? ValidateUint8Array(O). - CHECK_RECEIVER(JSTypedArray, uint8array, method_name); - ElementsKind elements_kind = uint8array->GetElementsKind(); - if (elements_kind != ElementsKind::UINT8_ELEMENTS && - elements_kind != ElementsKind::RAB_GSAB_UINT8_ELEMENTS) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } + CHECK_RECEIVER(Uint8JSTypedArray, uint8array, method_name); // 3. Let opts be ? GetOptionsObject(options). DirectHandle<Object> input_options = args.atOrUndefined(isolate, 1); @@ -846,9 +837,9 @@ BUILTIN(Uint8ArrayPrototypeToBase64) { } DirectHandle<SeqOneByteString> output; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, output, - isolate->factory()->NewRawOneByteString(static_cast<int>(output_length))); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, output, + isolate->factory()->NewRawOneByteString( + static_cast<uint32_t>(output_length))); { DisallowGarbageCollection no_gc; // 8. Let toEncode be ? GetUint8ArrayBytes(O). @@ -976,13 +967,12 @@ BUILTIN(Uint8ArrayPrototypeSetFromHex) { isolate, uint8array, JSTypedArray::Validate(isolate, args.receiver(), method_name, TypedArrayAccessMode::kWrite)); - ElementsKind elements_kind = uint8array->GetElementsKind(); - if (elements_kind != ElementsKind::UINT8_ELEMENTS && - elements_kind != ElementsKind::RAB_GSAB_UINT8_ELEMENTS) { + if (!IsUint8JSTypedArray(*uint8array)) { THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); + isolate, + NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, + isolate->factory()->NewStringFromAsciiChecked(method_name), + uint8array)); } // 3. If string is not a String, throw a TypeError exception. @@ -1080,15 +1070,7 @@ BUILTIN(Uint8ArrayPrototypeToHex) { // 1. Let O be the this value. // 2. Perform ? ValidateUint8Array(O). - CHECK_RECEIVER(JSTypedArray, uint8array, method_name); - ElementsKind elements_kind = uint8array->GetElementsKind(); - if (elements_kind != ElementsKind::UINT8_ELEMENTS && - elements_kind != ElementsKind::RAB_GSAB_UINT8_ELEMENTS) { - THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, - isolate->factory()->NewStringFromAsciiChecked( - method_name))); - } + CHECK_RECEIVER(Uint8JSTypedArray, uint8array, method_name); // 3. Let toEncode be ? GetUint8ArrayBytes(O). bool out_of_bounds = false; @@ -1113,9 +1095,9 @@ BUILTIN(Uint8ArrayPrototypeToHex) { // 4. Let out be the empty String. DirectHandle<SeqOneByteString> output; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, output, - isolate->factory()->NewRawOneByteString(static_cast<int>(length) * 2)); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, output, + isolate->factory()->NewRawOneByteString( + static_cast<uint32_t>(length) * 2)); // 5. For each byte byte of toEncode, do // a. Let hex be Number::toString(𝔽(byte), 16). // b. Set hex to StringPad(hex, 2, "0", start). diff --git a/deps/v8/src/builtins/builtins-utils.h b/deps/v8/src/builtins/builtins-utils.h index 4577b396376d..c5de0c3653ef 100644 --- a/deps/v8/src/builtins/builtins-utils.h +++ b/deps/v8/src/builtins/builtins-utils.h @@ -52,20 +52,22 @@ class BuiltinArguments : public JavaScriptArguments { // Note: this should return the address after the receiver, // even when length() == 1. inline Address* address_of_first_argument() const { - return address_of_arg_at(kFirstArgsIndex); + return address_of_arg_at_or_end(kFirstArgsIndex); } static constexpr int kNewTargetIndex = 0; static constexpr int kTargetIndex = 1; static constexpr int kArgcIndex = 2; - // This padding is required only on arm64 to keep the SP 16-byte aligned. + // This padding is required on arm64 (and x64 with 16-byte stack alignment) to + // keep the SP 16-byte aligned. static constexpr int kOptionalPaddingIndex = 3; -#if V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || \ + (V8_TARGET_ARCH_X64 && V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) static constexpr int kNumExtraArgs = 4; #else static constexpr int kNumExtraArgs = 3; -#endif // V8_TARGET_ARCH_ARM64 +#endif static constexpr int kNumExtraArgsWithReceiver = kNumExtraArgs + 1; diff --git a/deps/v8/src/builtins/builtins-wasm-gen.cc b/deps/v8/src/builtins/builtins-wasm-gen.cc index 3ba93d9a05a7..584c1f14766a 100644 --- a/deps/v8/src/builtins/builtins-wasm-gen.cc +++ b/deps/v8/src/builtins/builtins-wasm-gen.cc @@ -24,11 +24,8 @@ WasmBuiltinsAssembler::LoadInstanceDataFromFrame() { // We can only load the instance from Wasm frames, which is not the case for // builtins called from a Wasm-in-JS inlined function. TNode<IntPtrT> marker = BitcastTaggedToWord(marker_or_context); - CSA_DCHECK(this, - Word32Or(WordEqual(marker, IntPtrConstant(StackFrame::TypeToMarker( - StackFrame::WASM))), - WordEqual(marker, IntPtrConstant(StackFrame::TypeToMarker( - StackFrame::WASM_SEGMENT_START))))); + CSA_DCHECK(this, WordEqual(marker, IntPtrConstant(StackFrame::TypeToMarker( + StackFrame::WASM)))); #endif return TrustedCast<WasmTrustedInstanceData>( LoadFromParentFrame(WasmFrameConstants::kWasmInstanceDataOffset), @@ -39,7 +36,7 @@ TNode<WasmTrustedInstanceData> WasmBuiltinsAssembler::LoadTrustedDataFromInstance( TNode<WasmInstanceObject> instance_object) { return LoadTrustedPointerFromObject< - kWasmTrustedInstanceDataIndirectPointerTag>( + kWasmTrustedInstanceDataTrustedPointerTag>( instance_object, offsetof(WasmInstanceObject, trusted_data_)); } @@ -59,15 +56,9 @@ TNode<NativeContext> WasmBuiltinsAssembler::LoadContextFromWasmOrJsFrame() { // Otherwise this must be a proper `WASM` frame, holding a // `WasmTrustedInstanceData` in the slot. - // There is a special case for wasm frames that are the first frame of a - // growable stack segment: they are represented with the special frame type - // `WASM_SEGMENT_START`. TNode<IntPtrT> marker = BitcastTaggedToWord(marker_or_context); - CSA_CHECK(this, - Word32Or(WordEqual(marker, IntPtrConstant(StackFrame::TypeToMarker( - StackFrame::WASM))), - WordEqual(marker, IntPtrConstant(StackFrame::TypeToMarker( - StackFrame::WASM_SEGMENT_START))))); + CSA_CHECK(this, WordEqual(marker, IntPtrConstant(StackFrame::TypeToMarker( + StackFrame::WASM)))); TNode<HeapObject> instance_data = CAST(LoadFromParentFrame(WasmFrameConstants::kWasmInstanceDataOffset)); context_result = diff --git a/deps/v8/src/builtins/builtins.cc b/deps/v8/src/builtins/builtins.cc index 31474ac5f24f..bf9a3143b6f6 100644 --- a/deps/v8/src/builtins/builtins.cc +++ b/deps/v8/src/builtins/builtins.cc @@ -344,8 +344,8 @@ void Builtins::PrintBuiltinCode() { for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast; ++builtin) { const char* builtin_name = name(builtin); - if (PassesFilter(base::CStrVector(builtin_name), - base::CStrVector(v8_flags.print_builtin_code_filter))) { + if (PassesFilter(builtin_name, + v8_flags.print_builtin_code_filter.value())) { CodeTracer::Scope trace_scope(isolate_->GetCodeTracer()); OFStream os(trace_scope.file()); Tagged<Code> builtin_code = code(builtin); @@ -631,9 +631,16 @@ Builtins::JSBuiltinStateFlags Builtins::GetJSBuiltinState(Builtin builtin) { } switch (builtin) { + case Builtin::kConstructFunction: + // Technically ConstructFunction belongs in the section below (helper + // builtin with JS calling convention never supposed to be called directly + // from user JS code). + // We classify it as (unconditionally) flag dependent just for testing. + // See test/mjsunit/sandbox/regress/regress-435630464-disabled.js + RETURN_FLAG_DEPENDENT_BUILTIN_STATE(false); + // Helper builtins with JS calling convention which are not supposed to be // called directly from user JS code. - case Builtin::kConstructFunction: case Builtin::kConstructBoundFunction: case Builtin::kConstructedNonConstructable: case Builtin::kConstructProxy: @@ -830,15 +837,6 @@ Builtins::JSBuiltinStateFlags Builtins::GetJSBuiltinState(Builtin builtin) { case Builtin::kSharedStructTypeIsSharedStruct: case Builtin::kSharedArrayConstructor: case Builtin::kSharedArrayIsSharedArray: - case Builtin::kAtomicsMutexConstructor: - case Builtin::kAtomicsMutexLock: - case Builtin::kAtomicsMutexLockWithTimeout: - case Builtin::kAtomicsMutexTryLock: - case Builtin::kAtomicsMutexIsMutex: - case Builtin::kAtomicsConditionConstructor: - case Builtin::kAtomicsConditionWait: - case Builtin::kAtomicsConditionNotify: - case Builtin::kAtomicsConditionIsCondition: RETURN_FLAG_DEPENDENT_BUILTIN_STATE(v8_flags.harmony_struct); case Builtin::kSharedStructConstructor: RETURN_FLAG_DEPENDENT_LAZY_BUILTIN_STATE(v8_flags.harmony_struct); diff --git a/deps/v8/src/builtins/builtins.h b/deps/v8/src/builtins/builtins.h index 938885ffdf74..35821217ae3c 100644 --- a/deps/v8/src/builtins/builtins.h +++ b/deps/v8/src/builtins/builtins.h @@ -279,8 +279,7 @@ class Builtins { // Convenience wrappers. // static inline constexpr Builtin RecordWrite(SaveFPRegsMode fp_mode); - static inline constexpr Builtin IndirectPointerBarrier( - SaveFPRegsMode fp_mode); + static inline constexpr Builtin TrustedPointerBarrier(SaveFPRegsMode fp_mode); static inline constexpr Builtin EphemeronKeyBarrier(SaveFPRegsMode fp_mode); static inline constexpr Builtin AdaptorWithBuiltinExitFrame( diff --git a/deps/v8/src/builtins/bytecodes-builtins-list.h b/deps/v8/src/builtins/bytecodes-builtins-list.h new file mode 100644 index 000000000000..f4d8c61bb308 --- /dev/null +++ b/deps/v8/src/builtins/bytecodes-builtins-list.h @@ -0,0 +1,18 @@ +// Copyright 2026 the V8 project 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 V8_BUILTINS_BYTECODES_BUILTINS_LIST_H_ +#define V8_BUILTINS_BYTECODES_BUILTINS_LIST_H_ + +// Includes the bytecode builtins list: the checked-in copy under src/gen/ if +// v8_use_checked_in_generated_headers, the generated header otherwise. +// Include this header, not either of those; src/DEPS enforces that. See +// src/gen/README.md. +#ifdef V8_USE_CHECKED_IN_GENERATED_HEADERS +#include "src/gen/intl-wasm/bytecodes-builtins-list.h" // IWYU pragma: export +#else +#include "builtins-generated/bytecodes-builtins-list.h" // IWYU pragma: export, nogncheck +#endif + +#endif // V8_BUILTINS_BYTECODES_BUILTINS_LIST_H_ diff --git a/deps/v8/src/builtins/cast.tq b/deps/v8/src/builtins/cast.tq index 24cd719932b6..ba324bf1c93c 100644 --- a/deps/v8/src/builtins/cast.tq +++ b/deps/v8/src/builtins/cast.tq @@ -94,6 +94,11 @@ macro IsJSPrototype(o: HeapObject): bool { return Is<JSPrototype>(o); } +@export +macro IsUninitializedHeapNumber(o: HeapObject): bool { + return Is<UninitializedHeapNumber>(o); +} + @export macro IsNativeContext(o: HeapObject): bool { return Is<NativeContext>(o); @@ -702,9 +707,7 @@ Cast<JSArrayForFastToString>( goto CastError; } dcheck(TaggedEqual( - %RawDownCast<DescriptorArray>(map.instance_descriptors) - .descriptors[0] - .key, + %RawDownCast<DescriptorArray>(map.instance_descriptors).entries[0].key, kLengthString)); } diff --git a/deps/v8/src/builtins/console.tq b/deps/v8/src/builtins/console.tq index fe3b36d4f94b..bbc6bad167f0 100644 --- a/deps/v8/src/builtins/console.tq +++ b/deps/v8/src/builtins/console.tq @@ -10,7 +10,7 @@ extern javascript builtin ConsoleAssert( DispatchHandle): JSAny; javascript builtin FastConsoleAssert( - js-implicit context: NativeContext, receiver: JSAny, newTarget: JSAny, + js-implicit context: Context, receiver: JSAny, newTarget: JSAny, target: JSFunction)(...arguments): JSAny { if (ToBoolean(arguments[0])) { return Undefined; diff --git a/deps/v8/src/builtins/conversion.tq b/deps/v8/src/builtins/conversion.tq index 28d3a2f3784d..1fe4fc634f55 100644 --- a/deps/v8/src/builtins/conversion.tq +++ b/deps/v8/src/builtins/conversion.tq @@ -164,7 +164,7 @@ transitioning builtin ToObject(implicit context: Context)(input: JSAny): if (index != kNoConstructorFunctionIndex) goto WrapPrimitive( %RawDownCast<Slot<NativeContext, JSFunction>>(index)); - ThrowTypeError(MessageTemplate::kUndefinedOrNullToObject, 'ToObject'); + ThrowTypeError(MessageTemplate::kUndefinedOrNullToObject); } } } label WrapPrimitive(constructorIndex: Slot<NativeContext, JSFunction>) { diff --git a/deps/v8/src/builtins/convert.tq b/deps/v8/src/builtins/convert.tq index ce4823056cba..9faf1c94f50e 100644 --- a/deps/v8/src/builtins/convert.tq +++ b/deps/v8/src/builtins/convert.tq @@ -168,9 +168,9 @@ FromConstexpr<LanguageModeSmi, constexpr LanguageMode>( c: constexpr LanguageMode): LanguageModeSmi { return %RawDownCast<LanguageModeSmi>(SmiConstant(c)); } -FromConstexpr<PromiseState, constexpr PromiseState>(c: constexpr PromiseState): - PromiseState { - return %RawDownCast<PromiseState>(Int32Constant(c)); +FromConstexpr<PromisePromiseState, constexpr PromisePromiseState>( + c: constexpr PromisePromiseState): PromisePromiseState { + return %RawDownCast<PromisePromiseState>(Int32Constant(c)); } FromConstexpr<InstanceType, constexpr InstanceType>(c: constexpr InstanceType): InstanceType { @@ -444,8 +444,8 @@ extern macro BIntToSmi(bint): Smi; Convert<Smi, bint>(v: bint): Smi { return BIntToSmi(v); } -Convert<PromiseState, int32>(s: int32): PromiseState { - return %RawDownCast<PromiseState>(s); +Convert<PromisePromiseState, int32>(s: int32): PromisePromiseState { + return %RawDownCast<PromisePromiseState>(s); } Convert<I8X16, Simd128>(s: Simd128): I8X16 { return %RawDownCast<I8X16>(s); diff --git a/deps/v8/src/builtins/function.tq b/deps/v8/src/builtins/function.tq index 799bc4581f0c..9d5994563028 100644 --- a/deps/v8/src/builtins/function.tq +++ b/deps/v8/src/builtins/function.tq @@ -30,7 +30,7 @@ const kCodeMaxArguments: constexpr intptr generates 'Code::kMaxArguments'; macro CheckAccessor( implicit context: Context)(array: DescriptorArray, index: constexpr int32, name: Name): void labels Slow { - const descriptor: DescriptorEntry = array.descriptors[index]; + const descriptor: DescriptorEntry = array.entries[index]; const key: Name|Undefined = descriptor.key; if (!TaggedEqual(key, name)) goto Slow; diff --git a/deps/v8/src/builtins/generate-bytecodes-builtins-list.cc b/deps/v8/src/builtins/generate-bytecodes-builtins-list.cc index 4af31d732745..9ed82d4d9730 100644 --- a/deps/v8/src/builtins/generate-bytecodes-builtins-list.cc +++ b/deps/v8/src/builtins/generate-bytecodes-builtins-list.cc @@ -48,8 +48,8 @@ void WriteHeader(const char* header_filename) { out << "// Automatically generated from interpreter/bytecodes.h\n" << "// The following list macro is used to populate the builtins list\n" << "// with the bytecode handlers\n\n" - << "#ifndef V8_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST\n" - << "#define V8_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST\n\n" + << "#ifndef V8_GEN_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST_H_\n" + << "#define V8_GEN_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST_H_\n\n" << "#include <stdint.h>\n\n" << "#include \"src/common/globals.h\"\n\n" << "namespace v8 {\n" @@ -91,7 +91,7 @@ void WriteHeader(const char* header_filename) { << "// Mapping from Bytecode to a dense form with all the illegal\n" << "// wide Bytecodes removed. Used to index into the builtins table.\n" << "constexpr uint8_t kWideBytecodeToBuiltinsMapping[" - << Bytecodes::kBytecodeCount << "] = { \n"; + << Bytecodes::kBytecodeCount << "] = {\n"; for (int i = Bytecodes::kBytecodeCount; i < 2 * Bytecodes::kBytecodeCount; ++i) { @@ -107,7 +107,7 @@ void WriteHeader(const char* header_filename) { out << "};\n\n" << "} // namespace internal\n" << "} // namespace v8\n" - << "#endif // V8_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST\n"; + << "#endif // V8_GEN_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST_H_\n"; } } // namespace interpreter diff --git a/deps/v8/src/builtins/ia32/builtins-ia32.cc b/deps/v8/src/builtins/ia32/builtins-ia32.cc index 5ca8c70758cf..98e0f761a023 100644 --- a/deps/v8/src/builtins/ia32/builtins-ia32.cc +++ b/deps/v8/src/builtins/ia32/builtins-ia32.cc @@ -175,7 +175,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ mov(eax, FieldOperand(edi, offsetof(JSFunction, shared_function_info_))); __ mov(eax, FieldOperand(eax, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(eax); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(eax); __ JumpIfIsInRange( eax, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), ecx, @@ -859,7 +859,7 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, Register feedback_vector, Register scratch) { __ mov_b(scratch, FieldOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ and_(scratch, Immediate(~FeedbackVector::OsrUrgencyBits::kMask)); + __ and_(scratch, Immediate(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ mov_b(FieldOperand(feedback_vector, offsetof(FeedbackVector, osr_state_)), scratch); } @@ -972,10 +972,13 @@ void Builtins::Generate_InterpreterEntryTrampoline( Register frame_size = ecx; __ mov(frame_size, FieldOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + __ movzx_w(eax, FieldOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ lea(eax, Operand(frame_size, eax, times_system_pointer_size, 0)); // Do a stack check to ensure we don't go over the limit. - __ mov(eax, esp); - __ sub(eax, frame_size); + __ neg(eax); + __ add(eax, esp); __ CompareStackLimit(eax, StackLimitKind::kRealStackLimit); __ j(below, &stack_overflow); @@ -1598,13 +1601,13 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( Label builtin_call; __ mov(ecx, FieldOperand(edi, offsetof(JSFunction, shared_function_info_))); __ test(FieldOperand(ecx, offsetof(SharedFunctionInfo, flags_)), - Immediate(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + Immediate(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ j(not_zero, &builtin_call); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; __ mov(ecx, FieldOperand(ecx, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(ecx); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(ecx); __ JumpIfIsInRange( ecx, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), ecx, @@ -2653,8 +2656,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, // We need to convert the receiver for non-native sloppy mode functions. Label done_convert; __ test(FieldOperand(edx, offsetof(SharedFunctionInfo, flags_)), - Immediate(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + Immediate(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); __ j(not_zero, &done_convert); { // ----------- S t a t e ------------- @@ -2858,7 +2861,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { // Jump to JSBuiltinsConstructStub or JSConstructStubGeneric. __ mov(ecx, FieldOperand(edi, offsetof(JSFunction, shared_function_info_))); __ test(FieldOperand(ecx, offsetof(SharedFunctionInfo, flags_)), - Immediate(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + Immediate(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ j(zero, &call_generic_stub, Label::kNear); // Calling convention for function specific ConstructStubs require @@ -3263,7 +3266,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. for (Register reg : base::Reversed(WasmDebugBreakFrameConstants::kPushedGpRegs)) { __ Push(reg); @@ -3314,7 +3322,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3579,6 +3587,17 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; + + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int unpadded_stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; + constexpr int param_padding = + unpadded_stack_params_offset & kSystemPointerSize; + constexpr int stack_params_offset = + unpadded_stack_params_offset + param_padding; __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); constexpr int kNumSpillSlots = WasmJspiFrameConstants::kNumSpillSlots; @@ -3611,21 +3630,60 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ mov(MemOperand(ebp, WasmJspiFrameConstants::kResultArrayOffset), result_array); + __ Move(MemOperand(ebp, WasmJspiFrameConstants::kGCScanSlotCountOffset), + Immediate(0)); } + // Calculate the stack space required for return values. Register result_size = eax; - original_fp = no_reg; - - MemOperand GCScanSlotPlace = - MemOperand(ebp, WasmJspiFrameConstants::kGCScanSlotCountOffset); - __ Move(GCScanSlotPlace, Immediate(0)); - __ mov( result_size, MemOperand( wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferStackReturnBufferSize)); __ shl(result_size, kSystemPointerSizeLog2); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we calculate + // the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + // + // Register Choices: + // - total_space: edx (scratch, will hold total bytes needed on stack). + // - hypothetical_esp: esi (scratch, original_fp is no longer needed). + // Cannot use ecx because ecx holds new_wrapper_buffer (under + // stack-switching), nor edi which holds wrapper_buffer. + Register total_space = edx; + __ mov(total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + __ sub(total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ sub(total_space, Immediate(stack_params_offset)); + __ add(total_space, result_size); + + // Compare esp - total_space with the real stack limit. + // Note: esp - total_space will not underflow because esp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens of + // KiB). Thus, the unsigned comparison (below) against the real stack limit + // is safe. + Register hypothetical_esp = esi; + __ mov(hypothetical_esp, esp); + __ sub(hypothetical_esp, total_space); + __ CompareStackLimit(hypothetical_esp, StackLimitKind::kRealStackLimit); + __ j(below, &stack_overflow); + } + + // Allocate stack space for return values. __ sub(esp, result_size); __ mov( MemOperand( @@ -3646,16 +3704,8 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + // Push stack parameters on the stack. Register last_stack_param = ecx; - - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - - int param_padding = stack_params_offset & kSystemPointerSize; - stack_params_offset += param_padding; __ lea(last_stack_param, MemOperand(params_start, stack_params_offset)); Label loop_start; @@ -3702,10 +3752,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { __ mov(call_target, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferCallTarget)); - if (stack_switch) { - __ Move(MemOperand(ebp, WasmJspiFrameConstants::kGCScanSlotCountOffset), - Immediate(0)); - } __ CallWasmCodePointer(call_target); wrapper_buffer = esi; @@ -3764,6 +3810,19 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ mov(kContextRegister, + MemOperand(ebp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ mov(kContextRegister, + MemOperand(ebp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + GetContextFromImplicitArg(masm, kContextRegister, edx); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -4452,25 +4511,28 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); // eax Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); // ecx - Register original_fp = edx; + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); // edx Register original_sp = esi; - __ mov(original_fp, ebp); __ mov(original_sp, esp); // Calculate frame size before SP is updated. __ sub(frame_base, esp); { Register scratch = edi; - DCHECK(!AreAliased(original_fp, original_sp, frame_base, gap, scratch)); + DCHECK(!AreAliased(original_sp, frame_base, gap, parameter_slots_size, + scratch)); FrameScope scope(masm, StackFrame::INTERNAL); __ push(gap); - __ PrepareCallCFunction(5, scratch); - __ mov(Operand(esp, 4 * kSystemPointerSize), original_fp); + __ PrepareCallCFunction(6, scratch); + __ mov(Operand(esp, 5 * kSystemPointerSize), parameter_slots_size); + __ mov(scratch, Operand(ebp, CommonFrameConstants::kCallerFPOffset)); + __ mov(Operand(esp, 4 * kSystemPointerSize), scratch); __ mov(Operand(esp, 3 * kSystemPointerSize), gap); __ mov(Operand(esp, 2 * kSystemPointerSize), frame_base); __ mov(Operand(esp, 1 * kSystemPointerSize), original_sp); __ Move(Operand(esp, 0 * kSystemPointerSize), Immediate(ExternalReference::isolate_address())); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ pop(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4478,15 +4540,10 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { // wasm_grow_stack returns zero if it cannot grow a stack. __ test(kReturnRegister0, kReturnRegister0); __ j(zero, &call_runtime, Label::kNear); - Register new_fp = edx; // Calculate old FP - SP offset to adjust FP accordingly to new SP. __ sub(ebp, esp); __ add(ebp, kReturnRegister0); __ mov(esp, kReturnRegister0); - Register tmp = new_fp; - __ mov(tmp, - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - __ mov(MemOperand(ebp, TypedFrameConstants::kFrameTypeOffset), tmp); __ ret(0); // If wasm_grow_stack returns zero interruption or stack overflow @@ -4507,6 +4564,43 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ ret(0); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + for (Register reg : base::Reversed(wasm::kGpReturnRegisters)) { + __ push(reg); + } + __ sub(esp, Immediate(arraysize(wasm::kFpReturnRegisters) * kSimd128Size)); + for (size_t i = 0; i < arraysize(wasm::kFpReturnRegisters); i++) { + __ Movdqu(Operand(esp, kSimd128Size * i), wasm::kFpReturnRegisters[i]); + } + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = arraysize(wasm::kGpReturnRegisters) * kSystemPointerSize + + arraysize(wasm::kFpReturnRegisters) * kSimd128Size; + __ mov(ecx, esp); + Register scratch = edx; + __ PrepareCallCFunction(2, scratch); + __ Move(Operand(esp, 0 * kSystemPointerSize), + Immediate(ExternalReference::isolate_address())); + __ lea(scratch, Operand(ecx, saved_size)); + __ mov(Operand(esp, 1 * kSystemPointerSize), scratch); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ mov(ebp, kReturnRegister0); + + for (size_t i = 0; i < arraysize(wasm::kFpReturnRegisters); i++) { + __ Movdqu(wasm::kFpReturnRegisters[i], Operand(esp, kSimd128Size * i)); + } + __ add(esp, Immediate(arraysize(wasm::kFpReturnRegisters) * kSimd128Size)); + for (Register reg : wasm::kGpReturnRegisters) { + __ pop(reg); + } + + __ mov(esp, ebp); + __ pop(ebp); + __ ret(0); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { diff --git a/deps/v8/src/builtins/internal.tq b/deps/v8/src/builtins/internal.tq index 677fb4d8e7ac..95469549e057 100644 --- a/deps/v8/src/builtins/internal.tq +++ b/deps/v8/src/builtins/internal.tq @@ -41,7 +41,7 @@ builtin GetTemplateObject( extern transitioning builtin ForInFilter( implicit context: Context)(JSAny, HeapObject): JSAny; -extern enum ForInFeedback extends uint31 { kAny, ...} +extern enum ForInFeedback extends uint31 { kEnumeratorHolder, kAny, ...} extern macro UpdateFeedback( SmiTagged<ForInFeedback>, Undefined|FeedbackVector, uintptr, constexpr UpdateFeedbackMode): void; @@ -58,18 +58,44 @@ transitioning macro ForInNextSlow( return ForInFilter(key, receiver); } +extern macro CheckHolderValidity(JSAnyNotSmi, ForInEnumeratorHolder): bool; + // Note: the untagged {slot} parameter must be in the first couple of args to // guarantee it's allocated in a register. transitioning builtin ForInNext( context: Context, slot: uintptr, receiver: JSAnyNotSmi, - cacheArray: FixedArray, cacheType: Object, cacheIndex: Smi, - feedbackVector: FeedbackVector): JSAny { - // Load the next key from the enumeration array. - const key = UnsafeCast<JSAny>(cacheArray.objects[cacheIndex]); - - if (receiver.map == cacheType) { - // The enum cache is in use for {receiver}, the {key} is definitely valid. - return key; + cacheArray: FixedArray|ForInEnumeratorHolder, cacheType: Object, + cacheIndex: Smi, feedbackVector: FeedbackVector): JSAny { + let key: JSAny; + typeswitch (cacheArray) { + case (holder: ForInEnumeratorHolder): { + const elementsLength = holder.elements_length; + if (cacheIndex < elementsLength) { + key = NumberToString(cacheIndex); + } else { + const namedKeys = holder.named_keys; + const namedIndex = cacheIndex - elementsLength; + key = UnsafeCast<JSAny>(namedKeys.objects[namedIndex]); + } + if (CheckHolderValidity(receiver, holder)) { + // Record feedback in case the FeedbackVector was lazily allocated + // inside the loop (after ForInPrepare). This avoids a deopt on OSR + // or subsequent optimization, because Maglev assumes + // kEnumCacheKeys/kEnumCacheKeysAndIndices when feedback is missing. + UpdateFeedback( + SmiTag<ForInFeedback>(ForInFeedback::kEnumeratorHolder), + feedbackVector, slot, UpdateFeedbackMode::kGuaranteedFeedback); + return key; + } + } + case (array: FixedArray): { + key = UnsafeCast<JSAny>(array.objects[cacheIndex]); + if (receiver.map == cacheType) { + // The enum cache is in use for {receiver}, the {key} is definitely + // valid. + return key; + } + } } return ForInNextSlow( diff --git a/deps/v8/src/builtins/iterator-helpers.tq b/deps/v8/src/builtins/iterator-helpers.tq index 50bf3b492b5a..309e8d55d0b3 100644 --- a/deps/v8/src/builtins/iterator-helpers.tq +++ b/deps/v8/src/builtins/iterator-helpers.tq @@ -864,8 +864,7 @@ transitioning javascript builtin IteratorPrototypeReduce( // a. Let next be ? IteratorStep(iterated). // b. If next is false, throw a TypeError exception. next = IteratorStep(iterated, fastIteratorResultMap) - otherwise ThrowTypeError( - MessageTemplate::kIteratorReduceNoInitial, methodName); + otherwise ThrowTypeError(MessageTemplate::kIteratorReduceNoInitial); // c. Let accumulator be ? IteratorValue(next). accumulator = IteratorValue(next, fastIteratorResultMap); // d. Let counter be 1. diff --git a/deps/v8/src/builtins/js-to-wasm.tq b/deps/v8/src/builtins/js-to-wasm.tq index 8d72eccf7f4d..e4bbfece6725 100644 --- a/deps/v8/src/builtins/js-to-wasm.tq +++ b/deps/v8/src/builtins/js-to-wasm.tq @@ -865,9 +865,20 @@ transitioning javascript builtin WasmStressSwitch( context, receiver, target, arguments, Promise::kStressSwitch); } -// Precondition: {retType.is_ref()}. macro WasmToJSObject(context: NativeContext, value: Object): JSAny { if (value == kWasmNull) return Null; + @if(V8_IS_TSAN) { + if (!TaggedIsSmi(value)) { + runtime::TsanAcquireForInitializationFence(kNoContext, value); + } + } + // Descriptor structs are mapped to their wrapper, which is lazily allocated + // on first use. + if (Is<WasmCustomMap>(value)) { + const maybeWrapper = UnsafeCast<WasmCustomMap>(value).js_wrapper; + if (maybeWrapper != Null) return maybeWrapper; + return runtime::WasmWasmToJSObject(context, value); + } // Functions are mapped to their "external" representation, if it has // already been lazily created. if (Is<WasmFuncRef>(value)) { diff --git a/deps/v8/src/builtins/loong64/builtins-loong64.cc b/deps/v8/src/builtins/loong64/builtins-loong64.cc index e3272c0fe56b..358996a5c086 100644 --- a/deps/v8/src/builtins/loong64/builtins-loong64.cc +++ b/deps/v8/src/builtins/loong64/builtins-loong64.cc @@ -169,7 +169,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ LoadTaggedField( t2, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Ld_wu(t2, FieldMemOperand(t2, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(t2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(t2); __ JumpIfIsInRange( t2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -953,7 +953,8 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ Ld_bu(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ And(scratch, scratch, Operand(~FeedbackVector::OsrUrgencyBits::kMask)); + __ And(scratch, scratch, + Operand(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ St_b(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -1202,9 +1203,12 @@ void Builtins::Generate_InterpreterEntryTrampoline( // Load frame size (word) from the BytecodeArray object. __ Ld_w(a5, FieldMemOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + __ Ld_hu(a7, FieldMemOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ Alsl_d(a7, a7, a5, kSystemPointerSizeLog2); // Do a stack check to ensure we don't go over the limit. - __ Sub_d(a6, sp, Operand(a5)); + __ Sub_d(a6, sp, Operand(a7)); __ LoadStackLimit(a2, StackLimitKind::kRealStackLimit); __ Branch(&stack_overflow, lo, a6, Operand(a2)); @@ -1627,12 +1631,13 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( __ LoadTaggedField( a2, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Ld_wu(a2, FieldMemOperand(a2, offsetof(SharedFunctionInfo, flags_))); - __ And(a5, a2, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ And(a5, a2, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ Branch(&builtin_call, ne, a5, Operand(zero_reg)); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(a2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(a2); __ JumpIfIsInRange( a2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -2602,8 +2607,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, Label done_convert; __ Ld_wu(a3, FieldMemOperand(a2, offsetof(SharedFunctionInfo, flags_))); __ And(kScratchReg, a3, - Operand(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + Operand(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); __ Branch(&done_convert, ne, kScratchReg, Operand(zero_reg)); { // ----------- S t a t e ------------- @@ -2768,7 +2773,8 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { __ LoadTaggedField( a4, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Ld_wu(a4, FieldMemOperand(a4, offsetof(SharedFunctionInfo, flags_))); - __ And(a4, a4, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ And(a4, a4, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ Branch(&call_generic_stub, eq, a4, Operand(zero_reg)); __ TailCallBuiltin(Builtin::kJSBuiltinsConstructStub); @@ -3065,17 +3071,25 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { } namespace { -enum class DebugBreakKind { kBreak, kTrap }; +enum class DebugBreakKind { + kBreak, // Breakpoint or stepping (WasmDebugBreak). + kTrap, // Trap in debug code or trap handler (WasmTrapHandlerThrowTrap). +}; void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { HardAbortScope hard_abort(masm); // Avoid calls to Abort. { FrameScope scope(masm, StackFrame::WASM_DEBUG_BREAK); + // Save all parameter registers. They might hold live values, we restore + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. UseScratchRegisterScope temps(masm); Register scratch = temps.Acquire(); - // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. __ MultiPush(WasmDebugBreakFrameConstants::kPushedGpRegs); { // Check if machine has simd enabled, if so push vector registers. If not @@ -3160,7 +3174,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3469,6 +3483,12 @@ void Builtins::Generate_WasmTrapHandlerLandingPad(MacroAssembler* masm) { // position of the faulty memory access, however, is recorded at the fault // address. Therefore the stack trace code would not find the source position // if we used the fault address as the return address. + // Push MessageTemplate::kNone as trap reason for WasmTrapHandlerThrowTrap; + // the runtime will determine the actual trap reason from the trapping + // instruction. + static_assert(Smi::FromInt(static_cast<int>(MessageTemplate::kNone)).ptr() == + 0); + __ Push(zero_reg); __ Add_d(ra, kWasmTrapHandlerFaultAddressRegister, 1); __ TailCallBuiltin(Builtin::kWasmTrapHandlerThrowTrap); } @@ -3495,10 +3515,8 @@ void Builtins::Generate_WasmSuspend(MacroAssembler* masm) { parent, FieldMemOperand(suspender, offsetof(WasmSuspenderObject, parent_))); DEFINE_REG(target_stack); - __ LoadExternalPointerField( - target_stack, - FieldMemOperand(parent, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ Ld_d(target_stack, + FieldMemOperand(parent, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_suspend_stack(), target_stack, &resume, no_reg, {target_stack, suspender, parent}); @@ -3557,7 +3575,7 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { suspender, FieldMemOperand(resume_data, offsetof(WasmResumeData, trusted_suspender_)), - kWasmSuspenderIndirectPointerTag); + kWasmSuspenderTrustedPointerTag); regs.ResetExcept(suspender); // ------------------------------------------- @@ -3571,10 +3589,8 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { // Call the C function. // ------------------------------------------- DEFINE_REG(target_stack); - __ LoadExternalPointerField( - target_stack, - FieldMemOperand(suspender, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ Ld_d(target_stack, + FieldMemOperand(suspender, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_resume_jspi_stack(), target_stack, &suspend, suspender, {target_stack}); regs.ResetExcept(target_stack); @@ -3869,9 +3885,7 @@ void SwitchToAllocatedStack(MacroAssembler* masm, RegisterAllocator& regs, DEFINE_SCOPED(scratch) DEFINE_REG(stack) __ LoadRootRelative(stack, IsolateData::active_suspender_offset()); - __ LoadExternalPointerField( - stack, FieldMemOperand(stack, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ Ld_d(stack, FieldMemOperand(stack, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_start_stack(), stack, suspend, no_reg, {wasm_instance, wrapper_buffer}); @@ -4012,6 +4026,7 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; auto regs = RegisterAllocator::WithAllocatableGeneralRegisters(); __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); @@ -4030,6 +4045,12 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { Label suspend; Register original_fp = no_reg; Register new_wrapper_buffer = no_reg; + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; + if (stack_switch) { SwitchToAllocatedStack(masm, regs, implicit_arg, wrapper_buffer, original_fp, new_wrapper_buffer, &suspend); @@ -4055,15 +4076,59 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ St_d(scratch, MemOperand(fp, WasmJspiFrameConstants::kResultArrayOffset)); + __ St_d(zero_reg, + MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); } } { - DEFINE_SCOPED(result_size); - __ Ld_d(result_size, MemOperand(wrapper_buffer, - JSToWasmWrapperFrameConstants:: - kWrapperBufferStackReturnBufferSize)); - __ slli_d(result_size, result_size, kSystemPointerSizeLog2); - __ Sub_d(sp, sp, result_size); + DEFINE_SCOPED(return_space); + // Calculate the stack space required for return values (in bytes). + __ Ld_d(return_space, MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants:: + kWrapperBufferStackReturnBufferSize)); + __ slli_d(return_space, return_space, kSystemPointerSizeLog2); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we + // calculate the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + DEFINE_SCOPED(total_space); + __ Ld_d( + total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + DEFINE_SCOPED(params_start); + __ Ld_d( + params_start, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ Sub_d(total_space, total_space, params_start); + __ Sub_d(total_space, total_space, Operand(stack_params_offset)); + __ Add_d(total_space, total_space, return_space); + + // Compare sp - total_space with the real stack limit. + // Note: sp - total_space will not underflow because sp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens + // of KiB). Thus, the unsigned comparison against the real stack limit is + // safe. + Register hypothetical_sp = total_space; + __ Sub_d(hypothetical_sp, sp, total_space); + + DEFINE_SCOPED(stack_limit); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + __ Branch(&stack_overflow, ult, hypothetical_sp, Operand(stack_limit)); + } + + // Allocate stack space for return values. + __ Sub_d(sp, sp, return_space); } __ St_d( @@ -4080,14 +4145,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { regs.Reserve(reg); } - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - int param_padding = stack_params_offset & kSystemPointerSize; - stack_params_offset += param_padding; - { DEFINE_SCOPED(params_start); __ Ld_d( @@ -4135,7 +4192,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { next_offset += kSystemPointerSize; } - next_offset += param_padding; for (size_t i = 0; i < arraysize(wasm::kFpParamRegisters); ++i) { __ Fld_d(wasm::kFpParamRegisters[i], MemOperand(params_start, next_offset)); @@ -4144,8 +4200,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { DCHECK_EQ(next_offset, stack_params_offset); } - __ St_d(zero_reg, - MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); { DEFINE_SCOPED(call_target); __ LoadWasmCodePointer( @@ -4225,6 +4279,22 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, regs, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ Ld_d(kContextRegister, + MemOperand(fp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ Ld_d(kContextRegister, + MemOperand(fp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + { + UseScratchRegisterScope temps(masm); + GetContextFromImplicitArg(masm, kContextRegister, temps.Acquire()); + } + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -4461,9 +4531,12 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); + __ mov(kCArgRegs[5], parameter_slots_size); __ mov(kCArgRegs[3], gap); __ mov(kCArgRegs[1], sp); __ sub_d(kCArgRegs[2], frame_base, kCArgRegs[1]); @@ -4471,8 +4544,8 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(kCArgRegs[3]); __ li(kCArgRegs[0], ER::isolate_address()); - __ PrepareCallCFunction(5, kScratchReg); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ PrepareCallCFunction(6, kScratchReg); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ Pop(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4488,12 +4561,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ mov(fp, new_fp); } __ mov(sp, kReturnRegister0); - { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - __ li(scratch, StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)); - __ St_d(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - } __ Ret(); __ bind(&call_runtime); @@ -4514,6 +4581,10 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Ret(); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + __ Trap(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { @@ -5250,7 +5321,7 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( code_obj, FieldMemOperand(code_obj, offsetof(SharedFunctionInfo, trusted_function_data_)), - kCodeIndirectPointerTag); + kCodeTrustedPointerTag); // For OSR entry it is safe to assume we always have baseline code. if (v8_flags.debug_code) { diff --git a/deps/v8/src/builtins/mips64/builtins-mips64.cc b/deps/v8/src/builtins/mips64/builtins-mips64.cc index ba302ca33eec..f725ccfa43cd 100644 --- a/deps/v8/src/builtins/mips64/builtins-mips64.cc +++ b/deps/v8/src/builtins/mips64/builtins-mips64.cc @@ -166,7 +166,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ Ld(t2, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ lwu(t2, FieldMemOperand(t2, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(t2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(t2); __ JumpIfIsInRange( t2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -919,7 +919,8 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ Lbu(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ And(scratch, scratch, Operand(~FeedbackVector::OsrUrgencyBits::kMask)); + __ And(scratch, scratch, + Operand(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ Sb(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -1147,9 +1148,12 @@ void Builtins::Generate_InterpreterEntryTrampoline( // Load frame size (word) from the BytecodeArray object. __ Lw(a5, FieldMemOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + __ Lhu(a7, FieldMemOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ Dlsa(a7, a5, a7, kSystemPointerSizeLog2); // Do a stack check to ensure we don't go over the limit. - __ Dsubu(a6, sp, Operand(a5)); + __ Dsubu(a6, sp, Operand(a7)); __ LoadStackLimit(a2, MacroAssembler::StackLimitKind::kRealStackLimit); __ Branch(&stack_overflow, lo, a6, Operand(a2)); @@ -1565,12 +1569,13 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( Label builtin_call; __ Ld(a2, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Lwu(a2, FieldMemOperand(a2, offsetof(SharedFunctionInfo, flags_))); - __ And(a5, a2, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ And(a5, a2, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ Branch(&builtin_call, ne, a5, Operand(zero_reg)); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(a2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(a2); __ JumpIfIsInRange( a2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -2494,8 +2499,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, Label done_convert; __ Lwu(a3, FieldMemOperand(a2, offsetof(SharedFunctionInfo, flags_))); __ And(kScratchReg, a3, - Operand(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + Operand(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); __ Branch(&done_convert, ne, kScratchReg, Operand(zero_reg)); { // ----------- S t a t e ------------- @@ -2659,7 +2664,8 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { // Jump to JSBuiltinsConstructStub or JSConstructStubGeneric. __ Ld(a4, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ lwu(a4, FieldMemOperand(a4, offsetof(SharedFunctionInfo, flags_))); - __ And(a4, a4, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ And(a4, a4, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ Branch(&call_generic_stub, eq, a4, Operand(zero_reg)); __ TailCallBuiltin(Builtin::kJSBuiltinsConstructStub); @@ -3037,7 +3043,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { Register scratch = temps.Acquire(); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. __ MultiPush(WasmDebugBreakFrameConstants::kPushedGpRegs); { // Check if machine has simd enabled, if so push vector registers. If not @@ -3115,7 +3126,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3322,6 +3333,10 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Trap(); } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + __ Trap(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { diff --git a/deps/v8/src/builtins/object-fromentries.tq b/deps/v8/src/builtins/object-fromentries.tq index 5fc5750e0b82..7ab70bdb5bec 100644 --- a/deps/v8/src/builtins/object-fromentries.tq +++ b/deps/v8/src/builtins/object-fromentries.tq @@ -73,7 +73,7 @@ transitioning javascript builtin ObjectFromEntries( ReThrowWithMessage(context, e, message); } } label Throw deferred { - ThrowTypeError(MessageTemplate::kNotIterable); + ThrowTypeError(MessageTemplate::kNotIterable, iterable); } } } // namespace object diff --git a/deps/v8/src/builtins/ppc/builtins-ppc.cc b/deps/v8/src/builtins/ppc/builtins-ppc.cc index 801176b74a4e..ca4d66b1af50 100644 --- a/deps/v8/src/builtins/ppc/builtins-ppc.cc +++ b/deps/v8/src/builtins/ppc/builtins-ppc.cc @@ -100,20 +100,21 @@ void Generate_OSREntry(MacroAssembler* masm, Register entry_address, __ Ret(); } -void ResetSharedFunctionInfoAge(MacroAssembler* masm, Register sfi, - Register scratch) { - DCHECK(!AreAliased(sfi, scratch)); +void ResetSharedFunctionInfoAge(MacroAssembler* masm, Register sfi) { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); __ mov(scratch, Operand(0)); __ StoreU16(scratch, FieldMemOperand(sfi, offsetof(SharedFunctionInfo, age_))); } -void ResetJSFunctionAge(MacroAssembler* masm, Register js_function, - Register scratch1, Register scratch2) { +void ResetJSFunctionAge(MacroAssembler* masm, Register js_function) { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); __ LoadTaggedField( - scratch1, FieldMemOperand(js_function, - offsetof(JSFunction, shared_function_info_))); - ResetSharedFunctionInfoAge(masm, scratch1, scratch2); + scratch, FieldMemOperand(js_function, + offsetof(JSFunction, shared_function_info_))); + ResetSharedFunctionInfoAge(masm, scratch); } void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, @@ -121,9 +122,9 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ LoadU8(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ andi( - scratch, scratch, - Operand(static_cast<uint8_t>(~FeedbackVector::OsrUrgencyBits::kMask))); + __ andi(scratch, scratch, + Operand(static_cast<uint8_t>( + ~FeedbackVector::OsrState::OsrUrgencyBits::kMask))); __ StoreU8(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -193,7 +194,7 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( code_obj, FieldMemOperand(closure, offsetof(JSFunction, shared_function_info_))); - ResetSharedFunctionInfoAge(masm, code_obj, r6); + ResetSharedFunctionInfoAge(masm, code_obj); __ LoadTaggedField( code_obj, FieldMemOperand(code_obj, offsetof(SharedFunctionInfo, @@ -517,7 +518,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ LoadTaggedField( r7, FieldMemOperand(r4, offsetof(JSFunction, shared_function_info_))); __ lwz(r7, FieldMemOperand(r7, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(r7); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(r7); __ JumpIfIsInRange( r7, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -868,28 +869,33 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type, // If the c_entry_fp is not already zero and we don't clear it, the // StackFrameIteratorForProfiler will assume we are executing C++ and miss the // JS frames on top. - __ li(r0, Operand(-1)); // Push a bad frame pointer to fail if it is used. - __ push(r0); - if (V8_EMBEDDED_CONSTANT_POOL_BOOL) { - __ li(kConstantPoolRegister, Operand::Zero()); - __ push(kConstantPoolRegister); - } - __ mov(r0, Operand(StackFrame::TypeToMarker(type))); - __ push(r0); - __ push(r0); + { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + // Push a bad frame pointer to fail if it is used. + __ li(scratch, Operand(-1)); + __ push(scratch); + if (V8_EMBEDDED_CONSTANT_POOL_BOOL) { + __ li(kConstantPoolRegister, Operand::Zero()); + __ push(kConstantPoolRegister); + } + __ mov(scratch, Operand(StackFrame::TypeToMarker(type))); + __ push(scratch); + __ push(scratch); - __ mov(r0, Operand::Zero()); - __ LoadU64(r3, __ AsMemOperand(IsolateFieldId::kCEntryFP)); - __ StoreU64(r0, __ AsMemOperand(IsolateFieldId::kCEntryFP)); - __ push(r3); + __ mov(scratch, Operand::Zero()); + __ LoadU64(r3, __ AsMemOperand(IsolateFieldId::kCEntryFP)); + __ StoreU64(scratch, __ AsMemOperand(IsolateFieldId::kCEntryFP)); + __ push(r3); - __ LoadU64(r3, __ AsMemOperand(IsolateFieldId::kFastCCallCallerFP)); - __ StoreU64(r0, __ AsMemOperand(IsolateFieldId::kFastCCallCallerFP)); - __ push(r3); + __ LoadU64(r3, __ AsMemOperand(IsolateFieldId::kFastCCallCallerFP)); + __ StoreU64(scratch, __ AsMemOperand(IsolateFieldId::kFastCCallCallerFP)); + __ push(r3); - __ LoadU64(r3, __ AsMemOperand(IsolateFieldId::kFastCCallCallerPC)); - __ StoreU64(r0, __ AsMemOperand(IsolateFieldId::kFastCCallCallerPC)); - __ push(r3); + __ LoadU64(r3, __ AsMemOperand(IsolateFieldId::kFastCCallCallerPC)); + __ StoreU64(scratch, __ AsMemOperand(IsolateFieldId::kFastCCallCallerPC)); + __ push(r3); + } Register scratch = r9; // Set up frame pointer for the frame to be pushed. @@ -1157,7 +1163,11 @@ static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, static_cast<int>(interpreter::Bytecode::kDebugBreakExtraWide)); __ cmpi(bytecode, Operand(0x3)); __ bgt(&process_bytecode); - __ andi(r0, bytecode, Operand(0x1)); + { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + __ andi(scratch, bytecode, Operand(0x1)); + } __ bne(&extra_wide, cr0); // Load the next bytecode and update table to the wide scaled table. @@ -1252,11 +1262,7 @@ void Builtins::Generate_BaselineOutOfLinePrologue(MacroAssembler* masm) { BaselineOutOfLinePrologueDescriptor::kCalleeContext); Register callee_js_function = descriptor.GetRegisterParameter( BaselineOutOfLinePrologueDescriptor::kClosure); - { - UseScratchRegisterScope inner_temps(masm); - Register scratch = inner_temps.Acquire(); - ResetJSFunctionAge(masm, callee_js_function, scratch, r0); - } + ResetJSFunctionAge(masm, callee_js_function); __ Push(callee_context, callee_js_function); DCHECK_EQ(callee_js_function, kJavaScriptCallTargetRegister); DCHECK_EQ(callee_js_function, kJSFunctionRegister); @@ -1293,7 +1299,7 @@ void Builtins::Generate_BaselineOutOfLinePrologue(MacroAssembler* masm) { // building the frame we can quickly precheck both at once. UseScratchRegisterScope inner_temps(masm); Register sp_minus_frame_size = inner_temps.Acquire(); - Register interrupt_limit = r0; + Register interrupt_limit = inner_temps.Acquire(); __ SubS64(sp_minus_frame_size, sp, frame_size); __ LoadStackLimit(interrupt_limit, StackLimitKind::kInterruptStackLimit); __ CmpU64(sp_minus_frame_size, interrupt_limit); @@ -1368,7 +1374,7 @@ void Builtins::Generate_InterpreterEntryTrampoline( __ LoadTaggedField( r7, FieldMemOperand(closure, offsetof(JSFunction, shared_function_info_))); - ResetSharedFunctionInfoAge(masm, r7, scratch); + ResetSharedFunctionInfoAge(masm, r7); // The bytecode array could have been flushed from the shared function info, // if so, call into CompileLazy. Label is_baseline, compile_lazy; @@ -1419,8 +1425,8 @@ void Builtins::Generate_InterpreterEntryTrampoline( Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); // Push bytecode array and Smi tagged bytecode array offset. - __ SmiTag(r0, kInterpreterBytecodeOffsetRegister); - __ Push(kInterpreterBytecodeArrayRegister, r0, feedback_vector); + __ SmiTag(scratch, kInterpreterBytecodeOffsetRegister); + __ Push(kInterpreterBytecodeArrayRegister, scratch, feedback_vector); // Allocate the local and temporary register file on the stack. Label stack_overflow; @@ -1428,9 +1434,13 @@ void Builtins::Generate_InterpreterEntryTrampoline( // Load frame size (word) from the BytecodeArray object. __ lwz(r5, FieldMemOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + __ LoadU16(r8, FieldMemOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ ShiftLeftU64(r8, r8, Operand(kSystemPointerSizeLog2)); + __ AddS64(r8, r5, r8); // Do a stack check to ensure we don't go over the limit. - __ sub(r8, sp, r5); + __ sub(r8, sp, r8); __ LoadStackLimit(scratch, StackLimitKind::kRealStackLimit); __ CmpU64(r8, scratch); __ blt(&stack_overflow); @@ -1569,8 +1579,8 @@ void Builtins::Generate_InterpreterEntryTrampoline( Operand(BytecodeArray::kHeaderSize - kHeapObjectTag)); __ LoadRoot(kInterpreterAccumulatorRegister, RootIndex::kUndefinedValue); - __ SmiTag(r0, kInterpreterBytecodeOffsetRegister); - __ StoreU64(r0, + __ SmiTag(scratch, kInterpreterBytecodeOffsetRegister); + __ StoreU64(scratch, MemOperand(fp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); __ jmp(&after_stack_check_interrupt); @@ -1599,7 +1609,9 @@ static void GenerateInterpreterPushArgs(MacroAssembler* masm, Register num_args, __ ShiftLeftU64(scratch, scratch, Operand(kSystemPointerSizeLog2)); __ sub(start_address, start_address, scratch); // Push the arguments. - __ PushArray(start_address, num_args, scratch, r0, + UseScratchRegisterScope temps(masm); + Register scratch2 = temps.Acquire(); + __ PushArray(start_address, num_args, scratch, scratch2, MacroAssembler::PushArrayOrder::kReverse); } @@ -1686,8 +1698,8 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl( GenerateInterpreterPushArgs(masm, argc_without_receiver, r7, r8); // Push a slot for the receiver to be constructed. - __ li(r0, Operand::Zero()); - __ push(r0); + __ li(scratch, Operand::Zero()); + __ push(scratch); if (mode == InterpreterPushArgsMode::kWithFinalSpread) { // Pass the spread in the register r2. @@ -1756,11 +1768,12 @@ void Builtins::Generate_ConstructForwardAllArgsImpl( // Copy arguments on the stack. r8 is a scratch register. Register argc_without_receiver = scratch; __ subi(argc_without_receiver, r3, Operand(kJSArgcReceiverSlots)); - __ PushArray(r7, argc_without_receiver, r8, r0); + Register scratch2 = temps.Acquire(); + __ PushArray(r7, argc_without_receiver, r8, scratch2); // Push a slot for the receiver to be constructed. - __ li(r0, Operand::Zero()); - __ push(r0); + __ li(scratch, Operand::Zero()); + __ push(scratch); // Call the constructor with r3, r4, and r6 unmodified. __ TailCallBuiltin(Builtin::kConstruct); @@ -1860,14 +1873,15 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( { UseScratchRegisterScope temps(masm); Register scratch = temps.Acquire(); - __ mov(scratch, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); - __ and_(r0, r5, scratch, SetRC); + __ mov(scratch, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); + __ and_(scratch, r5, scratch, SetRC); } __ bne(&builtin_call, cr0); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(r5); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(r5); __ JumpIfIsInRange( r5, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -1983,8 +1997,12 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { __ LoadU64(r5, MemOperand(r5)); __ bind(&trampoline_loaded); - __ addi(r0, r5, Operand(interpreter_entry_return_pc_offset.value())); - __ mtlr(r0); + { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + __ addi(scratch, r5, Operand(interpreter_entry_return_pc_offset.value())); + __ mtlr(scratch); + } // Initialize the dispatch table register. __ Move( @@ -2119,8 +2137,9 @@ void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, BuiltinContinuationFrameConstants::kFixedSlotCount - kJSArgcReceiverSlots; __ addi(r3, r3, Operand(return_value_offset)); - __ ShiftLeftU64(r0, r3, Operand(kSystemPointerSizeLog2)); - __ StoreU64(scratch, MemOperand(sp, r0)); + Register offset_scratch = temps.Acquire(); + __ ShiftLeftU64(offset_scratch, r3, Operand(kSystemPointerSizeLog2)); + __ StoreU64(scratch, MemOperand(sp, offset_scratch)); // Recover arguments count. __ subi(r3, r3, Operand(return_value_offset)); } @@ -2133,8 +2152,7 @@ void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, __ Pop(builtin); __ addi(sp, sp, Operand(BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); - __ Pop(r0); - __ mtlr(r0); + __ PopLR(); __ LoadEntryFromBuiltinIndex(builtin, builtin); __ Jump(builtin); } @@ -2463,13 +2481,15 @@ void Generate_AllocateSpaceAndShiftExistingArguments( Register dest = pointer_to_new_space_out; __ addi(dest, sp, Operand(-kSystemPointerSize)); Label loop, skip; - __ mr(r0, argc_in_out); - __ cmpi(r0, Operand::Zero()); + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + __ mr(scratch, argc_in_out); + __ cmpi(scratch, Operand::Zero()); __ ble(&skip); - __ mtctr(r0); + __ mtctr(scratch); __ bind(&loop); - __ LoadU64WithUpdate(r0, MemOperand(old_sp, kSystemPointerSize)); - __ StoreU64WithUpdate(r0, MemOperand(dest, kSystemPointerSize)); + __ LoadU64WithUpdate(scratch, MemOperand(old_sp, kSystemPointerSize)); + __ StoreU64WithUpdate(scratch, MemOperand(dest, kSystemPointerSize)); __ bdnz(&loop); __ bind(&skip); @@ -2650,8 +2670,8 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, { __ subi(r8, r8, Operand(1)); __ ShiftLeftU64(scratch, r8, Operand(kSystemPointerSizeLog2)); - __ LoadU64(r0, MemOperand(r7, scratch)); - __ StoreU64(r0, MemOperand(r5, scratch)); + __ LoadU64(scratch2, MemOperand(r7, scratch)); + __ StoreU64(scratch2, MemOperand(r5, scratch)); __ cmpi(r8, Operand::Zero()); __ bne(&loop); } @@ -2684,9 +2704,13 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, // We need to convert the receiver for non-native sloppy mode functions. Label done_convert; __ lwz(r6, FieldMemOperand(r5, offsetof(SharedFunctionInfo, flags_))); - __ andi(r0, r6, - Operand(SharedFunctionInfo::IsStrictBit::kMask | - SharedFunctionInfo::IsNativeBit::kMask)); + { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + __ andi(scratch, r6, + Operand(SharedFunctionInfo::Flags::IsStrictBit::kMask | + SharedFunctionInfo::Flags::IsNativeBit::kMask)); + } __ bne(&done_convert, cr0); { // ----------- S t a t e ------------- @@ -2778,18 +2802,14 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // -- r7 : the number of [[BoundArguments]] // ----------------------------------- - Register scratch = r9; - // Reserve stack space for the [[BoundArguments]]. + // Check the stack for overflow. { + Label stack_overflow; + __ StackOverflowCheck(r7, &stack_overflow); Label done; - __ ShiftLeftU64(r10, r7, Operand(kSystemPointerSizeLog2)); - __ sub(r0, sp, r10); - // Check the stack for overflow. We are not trying to catch interruptions - // (i.e. debug break and preemption) here, so check the "real stack - // limit". - __ LoadStackLimit(scratch, StackLimitKind::kRealStackLimit); - __ CmpU64(r0, scratch); - __ bgt(&done); // Signed comparison. + __ b(&done); + + __ bind(&stack_overflow); { FrameScope scope(masm, StackFrame::MANUAL); __ EnterFrame(StackFrame::INTERNAL); @@ -2804,6 +2824,7 @@ void Generate_PushBoundArguments(MacroAssembler* masm) { // Push [[BoundArguments]]. { Label loop, done; + Register scratch = r9; __ add(r3, r3, r7); // Adjust effective number of arguments. __ addi(r5, r5, Operand(OFFSET_OF_DATA_START(FixedArray) - kHeapObjectTag)); @@ -2881,7 +2902,8 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { __ LoadTaggedField( r7, FieldMemOperand(r4, offsetof(JSFunction, shared_function_info_))); __ lwz(r7, FieldMemOperand(r7, offsetof(SharedFunctionInfo, flags_))); - __ mov(scratch, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ mov(scratch, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ and_(r7, r7, scratch, SetRC); __ beq(&call_generic_stub, cr0); @@ -3061,8 +3083,9 @@ void Builtins::Generate_WasmLiftoffFrameSetup(MacroAssembler* masm) { // Increment the total invocation count of the function. __ LoadTaggedField( scratch, FieldMemOperand(vector, OFFSET_OF_DATA_START(FixedArray))); - __ Move(r0, Smi::FromInt(1)); - __ AddS64(scratch, scratch, r0); + Register smi_val = inner_temps.Acquire(); + __ Move(smi_val, Smi::FromInt(1)); + __ AddS64(scratch, scratch, smi_val); __ StoreTaggedField( scratch, FieldMemOperand(vector, OFFSET_OF_DATA_START(FixedArray))); } @@ -3172,7 +3195,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameAndConstantPoolScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. __ MultiPush(WasmDebugBreakFrameConstants::kPushedGpRegs); __ MultiPushF64AndV128(WasmDebugBreakFrameConstants::kPushedFpRegs, WasmDebugBreakFrameConstants::kPushedSimd128Regs); @@ -3210,7 +3238,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -4045,6 +4073,7 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; auto regs = RegisterAllocator::WithAllocatableGeneralRegisters(); __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); @@ -4063,6 +4092,12 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { Label suspend; Register original_fp = no_reg; Register new_wrapper_buffer = no_reg; + + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; if (stack_switch) { SwitchToAllocatedStack(masm, regs, implicit_arg, wrapper_buffer, original_fp, new_wrapper_buffer, &suspend); @@ -4088,16 +4123,62 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ StoreU64(scratch, MemOperand(fp, WasmJspiFrameConstants::kResultArrayOffset)); + __ Zero(MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); } } + { - DEFINE_SCOPED(result_size); + DEFINE_SCOPED(return_space); + // Calculate the stack space required for return values (in bytes). __ LoadU64( - result_size, + return_space, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants:: kWrapperBufferStackReturnBufferSize)); - __ ShiftLeftU64(r0, result_size, Operand(kSystemPointerSizeLog2)); - __ SubS64(sp, sp, r0); + __ ShiftLeftU64(return_space, return_space, + Operand(kSystemPointerSizeLog2)); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we + // calculate the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + DEFINE_SCOPED(total_space); + __ LoadU64( + total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + DEFINE_SCOPED(params_start); + __ LoadU64( + params_start, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ SubS64(total_space, total_space, params_start); + __ SubS64(total_space, total_space, Operand(stack_params_offset)); + __ AddS64(total_space, total_space, return_space); + + // Compare sp - total_space with the real stack limit. + // Note: sp - total_space will not underflow because sp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens + // of KiB). Thus, the unsigned comparison (lo) against the real stack + // limit is safe. + Register hypothetical_sp = total_space; + __ SubS64(hypothetical_sp, sp, total_space); + + DEFINE_SCOPED(stack_limit); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + __ CmpU64(hypothetical_sp, stack_limit); + __ blt(&stack_overflow); + } + + // Allocate stack space for return values. + __ SubS64(sp, sp, return_space); } __ StoreU64( @@ -4114,12 +4195,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { regs.Reserve(reg); } - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - { DEFINE_SCOPED(params_start); __ LoadU64( @@ -4146,8 +4221,10 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { // Push parameter { __ AddS64(params_end, params_end, Operand(-kSystemPointerSize)); - __ LoadU64(r0, MemOperand(params_end)); - __ push(r0); + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + __ LoadU64(scratch, MemOperand(params_end)); + __ push(scratch); } __ jmp(&loop_start); @@ -4173,7 +4250,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { DCHECK_EQ(next_offset, stack_params_offset); } - __ Zero(MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); { DEFINE_SCOPED(call_target); __ LoadWasmCodePointer( @@ -4251,6 +4327,20 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, regs, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ LoadU64(kContextRegister, + MemOperand(fp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ LoadU64( + kContextRegister, + MemOperand(fp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + GetContextFromImplicitArg(masm, kContextRegister, r4); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -4320,9 +4410,13 @@ void SwitchToTheCentralStackIfNeeded(MacroAssembler* masm, Register argc_input, // When we switch stack we leave home space allocated on the old stack. // Allocate home space on the central stack to prevent stack corruption. - __ li(r0, Operand::Zero()); - __ StoreU64WithUpdate( - r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kSystemPointerSize)); + { + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + __ li(scratch, Operand::Zero()); + __ StoreU64WithUpdate(scratch, MemOperand(sp, -kNumRequiredStackFrameSlots * + kSystemPointerSize)); + } // Update the sp saved in the frame. // It will be used to calculate the callee pc during GC. @@ -4378,8 +4472,6 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, static constexpr Register argc_input = r3; static constexpr Register target_fun = r15; // C callee-saved static constexpr Register argv = r4; - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); static constexpr Register argc_sav = r14; // C callee-saved __ mr(target_fun, argv); @@ -4476,9 +4568,12 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, // should have returned the exception sentinel. if (v8_flags.debug_code) { Label okay; + UseScratchRegisterScope debug_temps(masm); + Register scratch = debug_temps.Acquire(); + Register scratch2 = debug_temps.Acquire(); __ LoadU64(scratch, __ AsMemOperand(IsolateFieldId::kException)); - __ LoadRoot(r0, RootIndex::kTheHoleValue); - __ CompareTagged(r0, scratch); + __ LoadRoot(scratch2, RootIndex::kTheHoleValue); + __ CompareTagged(scratch2, scratch); // Cannot use check here as it attempts to generate call into runtime. __ beq(&okay); __ stop(); @@ -4525,6 +4620,9 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, __ StoreU64(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ bind(&skip); + UseScratchRegisterScope temps(masm); + Register scratch = temps.Acquire(); + // Clear c_entry_fp, like we do in `LeaveExitFrame`. __ mov(scratch, Operand::Zero()); __ StoreU64(scratch, __ AsMemOperand(IsolateFieldId::kCEntryFP)); @@ -4545,18 +4643,21 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); + __ mr(kCArgRegs[5], parameter_slots_size); __ mr(kCArgRegs[3], gap); __ mr(kCArgRegs[1], sp); __ SubS64(kCArgRegs[2], frame_base, kCArgRegs[1]); __ mr(kCArgRegs[4], fp); FrameScope scope(masm, StackFrame::INTERNAL); __ push(kCArgRegs[3]); - __ PrepareCallCFunction(5); + __ PrepareCallCFunction(6); __ Move(kCArgRegs[0], ER::isolate_address()); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ pop(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4569,13 +4670,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ SubS64(fp, fp, sp); __ AddS64(fp, fp, kReturnRegister0); __ mr(sp, kReturnRegister0); - { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - __ mov(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - __ StoreU64(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - } __ Ret(); __ bind(&call_runtime); @@ -4596,6 +4690,47 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Ret(); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + RegList gp_saves; + for (Register r : wasm::kGpReturnRegisters) gp_saves.set(r); + DoubleRegList fp_saves; + for (DoubleRegister r : wasm::kFpReturnRegisters) fp_saves.set(r); + Simd128RegList simd128_saves; + for (Simd128Register r : wasm::kSimd128ReturnRegisters) simd128_saves.set(r); + + __ MultiPush(gp_saves); + __ MultiPushF64AndV128(fp_saves, simd128_saves); + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = gp_saves.Count() * kSystemPointerSize + + fp_saves.Count() * kDoubleSize + + simd128_saves.Count() * kSimd128Size; + __ Move(kCArgRegs[0], ExternalReference::isolate_address()); + __ AddS64(kCArgRegs[1], sp, Operand(saved_size)); + __ PrepareCallCFunction(2); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ mr(fp, kReturnRegister0); + + __ MultiPopF64AndV128(fp_saves, simd128_saves); + __ MultiPop(gp_saves); + + UseScratchRegisterScope temps(masm); + Register scratch1 = temps.Acquire(); + Register scratch2 = temps.Acquire(); + __ LoadU64(scratch2, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); + __ LoadU64(scratch1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); + if (V8_EMBEDDED_CONSTANT_POOL_BOOL) { + __ LoadU64(kConstantPoolRegister, + MemOperand(fp, StandardFrameConstants::kConstantPoolOffset)); + } + __ mtlr(scratch2); + __ AddS64(sp, fp, Operand(StandardFrameConstants::kCallerSPOffset)); + __ mr(fp, scratch1); + __ blr(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { @@ -4667,32 +4802,36 @@ void Builtins::Generate_DoubleToI(MacroAssembler* masm) { static_assert(HeapNumber::kMantissaBitsInTopWord >= 16); __ oris(result_reg, result_reg, Operand(1 << ((HeapNumber::kMantissaBitsInTopWord)-16))); - __ ShiftLeftU32(r0, result_reg, scratch); - __ orx(result_reg, scratch_low, r0); - __ b(&negate); - - __ bind(&out_of_range); - __ mov(result_reg, Operand::Zero()); - __ b(&done); - - __ bind(&only_low); - // 52 <= exponent <= 83, shift only scratch_low. - // On entry, scratch contains: 52 - exponent. - __ neg(scratch, scratch); - __ ShiftLeftU32(result_reg, scratch_low, scratch); - - __ bind(&negate); - // If input was positive, scratch_high ASR 31 equals 0 and - // scratch_high LSR 31 equals zero. - // New result = (result eor 0) + 0 = result. - // If the input was negative, we have to negate the result. - // Input_high ASR 31 equals 0xFFFFFFFF and scratch_high LSR 31 equals 1. - // New result = (result eor 0xFFFFFFFF) + 1 = 0 - result. - __ srawi(r0, scratch_high, 31); - __ srdi(r0, r0, Operand(32)); - __ xor_(result_reg, result_reg, r0); - __ srwi(r0, scratch_high, Operand(31)); - __ add(result_reg, result_reg, r0); + { + UseScratchRegisterScope temps(masm); + Register temp = temps.Acquire(); + __ ShiftLeftU32(temp, result_reg, scratch); + __ orx(result_reg, scratch_low, temp); + __ b(&negate); + + __ bind(&out_of_range); + __ mov(result_reg, Operand::Zero()); + __ b(&done); + + __ bind(&only_low); + // 52 <= exponent <= 83, shift only scratch_low. + // On entry, scratch contains: 52 - exponent. + __ neg(scratch, scratch); + __ ShiftLeftU32(result_reg, scratch_low, scratch); + + __ bind(&negate); + // If input was positive, scratch_high ASR 31 equals 0 and + // scratch_high LSR 31 equals zero. + // New result = (result eor 0) + 0 = result. + // If the input was negative, we have to negate the result. + // Input_high ASR 31 equals 0xFFFFFFFF and scratch_high LSR 31 equals 1. + // New result = (result eor 0xFFFFFFFF) + 1 = 0 - result. + __ srawi(temp, scratch_high, 31); + __ srdi(temp, temp, Operand(32)); + __ xor_(result_reg, result_reg, temp); + __ srwi(temp, scratch_high, Operand(31)); + __ add(result_reg, result_reg, temp); + } __ bind(&done); __ Pop(scratch_high, scratch_low); diff --git a/deps/v8/src/builtins/promise-abstract-operations.tq b/deps/v8/src/builtins/promise-abstract-operations.tq index e3a3ee118c86..1d8db469bad0 100644 --- a/deps/v8/src/builtins/promise-abstract-operations.tq +++ b/deps/v8/src/builtins/promise-abstract-operations.tq @@ -208,8 +208,8 @@ transitioning macro TriggerPromiseReactions( // https://tc39.es/ecma262/#sec-fulfillpromise transitioning builtin FulfillPromise( implicit context: Context)(promise: JSPromise, value: JSAny): Undefined { - // Assert: The value of promise.[[PromiseState]] is "pending". - dcheck(promise.Status() == PromiseState::kPending); + // Assert: The value of promise.[[PromisePromiseState]] is "pending". + dcheck(promise.Status() == PromisePromiseState::kPending); RunContextPromiseHookResolve(promise); @@ -222,8 +222,8 @@ transitioning builtin FulfillPromise( // 5. Set promise.[[PromiseRejectReactions]] to undefined. promise.reactions_or_result = value; - // 6. Set promise.[[PromiseState]] to "fulfilled". - promise.SetStatus(PromiseState::kFulfilled); + // 6. Set promise.[[PromisePromiseState]] to "fulfilled". + promise.SetStatus(PromisePromiseState::kFulfilled); // 7. Return TriggerPromiseReactions(reactions, value). TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill); @@ -268,8 +268,8 @@ transitioning builtin RejectPromise( // 5. Set promise.[[PromiseRejectReactions]] to undefined. promise.reactions_or_result = reason; - // 6. Set promise.[[PromiseState]] to "rejected". - promise.SetStatus(PromiseState::kRejected); + // 6. Set promise.[[PromisePromiseState]] to "rejected". + promise.SetStatus(PromisePromiseState::kRejected); // 8. Return TriggerPromiseReactions(reactions, reason). TriggerPromiseReactions(reactions, reason, kPromiseReactionReject); @@ -470,7 +470,7 @@ transitioning macro PerformPromiseThenImpl( implicit context: Context)(promise: JSPromise, onFulfilled: Callable|Undefined, onRejected: Callable|Undefined, resultPromiseOrCapability: JSPromise|PromiseCapability|Undefined): void { - if (promise.Status() == PromiseState::kPending) { + if (promise.Status() == PromisePromiseState::kPending) { // The {promise} is still in "Pending" state, so we just record a new // PromiseReaction holding both the onFulfilled and onRejected callbacks. // Once the {promise} is resolved we decide on the concrete handler to @@ -485,14 +485,14 @@ transitioning macro PerformPromiseThenImpl( const reactionsOrResult = promise.reactions_or_result; let microtask: PromiseReactionJobTask; let handlerContext: Context; - if (promise.Status() == PromiseState::kFulfilled) { + if (promise.Status() == PromisePromiseState::kFulfilled) { handlerContext = ExtractHandlerContext(onFulfilled, onRejected); microtask = NewPromiseFulfillReactionJobTask( handlerContext, reactionsOrResult, onFulfilled, resultPromiseOrCapability); } else deferred { - dcheck(promise.Status() == PromiseState::kRejected); + dcheck(promise.Status() == PromisePromiseState::kRejected); handlerContext = ExtractHandlerContext(onRejected, onFulfilled); microtask = NewPromiseRejectReactionJobTask( handlerContext, reactionsOrResult, onRejected, @@ -542,7 +542,7 @@ transitioning javascript builtin PromiseReject( const promiseFun = *NativeContextSlot(ContextSlot::PROMISE_FUNCTION_INDEX); if (promiseFun == receiver) { - const promise = NewJSPromise(PromiseState::kRejected, reason); + const promise = NewJSPromise(PromisePromiseState::kRejected, reason); runtime::PromiseRejectEventFromStack(promise, reason); return promise; } else { diff --git a/deps/v8/src/builtins/promise-misc.tq b/deps/v8/src/builtins/promise-misc.tq index eefb2d0c40d2..c85bb3b45912 100644 --- a/deps/v8/src/builtins/promise-misc.tq +++ b/deps/v8/src/builtins/promise-misc.tq @@ -48,7 +48,7 @@ macro PromiseHasHandler(promise: JSPromise): bool { macro PromiseInit(promise: JSPromise): void { promise.reactions_or_result = kZero; promise.flags = SmiTag(JSPromiseFlags{ - status: PromiseState::kPending, + status: PromisePromiseState::kPending, is_native_resolver_invoked: false, has_handler: false, is_silent: false, @@ -68,7 +68,7 @@ macro InnerNewJSPromise(implicit context: Context)(): JSPromise { promise.elements = kEmptyFixedArray; promise.reactions_or_result = kZero; promise.flags = SmiTag(JSPromiseFlags{ - status: PromiseState::kPending, + status: PromisePromiseState::kPending, is_native_resolver_invoked: false, has_handler: false, is_silent: false, @@ -288,9 +288,9 @@ transitioning macro NewJSPromise(implicit context: Context)(): JSPromise { // fields. @export transitioning macro NewJSPromise( - implicit context: Context)(status: constexpr PromiseState, + implicit context: Context)(status: constexpr PromisePromiseState, result: JSAny): JSPromise { - dcheck(status != PromiseState::kPending); + dcheck(status != PromisePromiseState::kPending); const instance = InnerNewJSPromise(); instance.reactions_or_result = result; diff --git a/deps/v8/src/builtins/proxy-revocable.tq b/deps/v8/src/builtins/proxy-revocable.tq index 6b8cef66d57e..651764b6ba30 100644 --- a/deps/v8/src/builtins/proxy-revocable.tq +++ b/deps/v8/src/builtins/proxy-revocable.tq @@ -37,7 +37,7 @@ transitioning javascript builtin ProxyRevocable( // 8. Return result. return NewJSProxyRevocableResult(proxy, revoke); } label ThrowProxyNonObject deferred { - ThrowTypeError(MessageTemplate::kProxyNonObject, 'Proxy.revocable'); + ThrowTypeError(MessageTemplate::kProxyNonObject); } } } diff --git a/deps/v8/src/builtins/proxy-set-property.tq b/deps/v8/src/builtins/proxy-set-property.tq index 52dd3396dc4a..64d349099701 100644 --- a/deps/v8/src/builtins/proxy-set-property.tq +++ b/deps/v8/src/builtins/proxy-set-property.tq @@ -11,7 +11,7 @@ extern transitioning runtime SetPropertyWithReceiver( transitioning macro CallThrowTypeErrorIfStrict( implicit context: Context)(message: constexpr MessageTemplate): void { - ThrowTypeErrorIfStrict(SmiConstant(message), Null, Null); + ThrowTypeErrorIfStrict(SmiConstant(message), TheHole, TheHole); } // https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver diff --git a/deps/v8/src/builtins/proxy-set-prototype-of.tq b/deps/v8/src/builtins/proxy-set-prototype-of.tq index fda0c549634c..b91ff79e6fb4 100644 --- a/deps/v8/src/builtins/proxy-set-prototype-of.tq +++ b/deps/v8/src/builtins/proxy-set-prototype-of.tq @@ -39,8 +39,7 @@ transitioning builtin ProxySetPrototypeOf( // 9. If booleanTrapResult is false, return false. if (!ToBoolean(trapResult)) { if (doThrow == True) { - ThrowTypeError( - MessageTemplate::kProxyTrapReturnedFalsishFor, kTrapName); + ThrowTypeError(MessageTemplate::kProxyTrapReturnedFalsish, kTrapName); } return False; } diff --git a/deps/v8/src/builtins/riscv/builtins-riscv.cc b/deps/v8/src/builtins/riscv/builtins-riscv.cc index a663f76a2f2f..90d40cf679af 100644 --- a/deps/v8/src/builtins/riscv/builtins-riscv.cc +++ b/deps/v8/src/builtins/riscv/builtins-riscv.cc @@ -282,7 +282,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Load32U(func_info, FieldMemOperand( func_info, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(func_info); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(func_info); __ JumpIfIsInRange( func_info, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), @@ -1110,7 +1110,8 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ Lbu(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ And(scratch, scratch, Operand(~FeedbackVector::OsrUrgencyBits::kMask)); + __ And(scratch, scratch, + Operand(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ Sb(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -1378,9 +1379,16 @@ void Builtins::Generate_InterpreterEntryTrampoline( __ Lw(scratch, FieldMemOperand(bytecode_array, offsetof(BytecodeArray, frame_size_))); - // Do a stack check to ensure we don't go over the limit. + // Do a stack check to ensure we don't go over the limit. Include the + // arguments, which are also stored in the register file, in the frame size, + // to match BaselineCompiler::Prologue. DEFINE_REG(stack_addr); - __ SubWord(stack_addr, sp, Operand(scratch)); + __ Lhu(stack_addr, + FieldMemOperand(bytecode_array, + offsetof(BytecodeArray, max_arguments_))); + __ CalcScaledAddress(stack_addr, scratch, stack_addr, + kSystemPointerSizeLog2); + __ SubWord(stack_addr, sp, Operand(stack_addr)); DEFINE_REG(stack_limit); __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); __ Branch(&stack_overflow, Uless, stack_addr, Operand(stack_limit)); @@ -1799,12 +1807,13 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( __ LoadTaggedField( a2, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Load32U(a2, FieldMemOperand(a2, offsetof(SharedFunctionInfo, flags_))); - __ And(a5, a2, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ And(a5, a2, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ Branch(&builtin_call, ne, a5, Operand(zero_reg)); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(a2); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(a2); __ JumpIfIsInRange( a2, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -2827,8 +2836,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, Label done_convert; __ Load32U(a3, FieldMemOperand(a2, offsetof(SharedFunctionInfo, flags_))); __ And(kScratchReg, a3, - Operand(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + Operand(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); __ Branch(&done_convert, ne, kScratchReg, Operand(zero_reg)); { // ----------- S t a t e ------------- @@ -3026,7 +3035,8 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { __ LoadTaggedField( a4, FieldMemOperand(a1, offsetof(JSFunction, shared_function_info_))); __ Load32U(a4, FieldMemOperand(a4, offsetof(SharedFunctionInfo, flags_))); - __ And(a4, a4, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ And(a4, a4, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ Branch(&call_generic_stub, eq, a4, Operand(zero_reg), Label::Distance::kNear); @@ -3300,7 +3310,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { } namespace { -enum class DebugBreakKind { kBreak, kTrap }; +enum class DebugBreakKind { + kBreak, // Breakpoint or stepping (WasmDebugBreak). + kTrap, // Trap in debug code or trap handler (WasmTrapHandlerThrowTrap). +}; void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { HardAbortScope hard_abort(masm); // Avoid calls to Abort. @@ -3308,7 +3321,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. __ MultiPush(WasmDebugBreakFrameConstants::kPushedGpRegs); __ MultiPushFPU(WasmDebugBreakFrameConstants::kPushedFpRegs); @@ -3351,7 +3369,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3598,9 +3616,12 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); + __ mv(kCArgRegs[5], parameter_slots_size); __ mv(kCArgRegs[3], gap); __ mv(kCArgRegs[1], sp); __ SubWord(kCArgRegs[2], frame_base, kCArgRegs[1]); @@ -3608,8 +3629,8 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { FrameScope scope(masm, StackFrame::INTERNAL); __ Push(kCArgRegs[3]); __ li(kCArgRegs[0], ER::isolate_address()); - __ PrepareCallCFunction(5, kScratchReg); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ PrepareCallCFunction(6, kScratchReg); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ Pop(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -3626,13 +3647,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { } SwitchSimulatorStackLimit(masm); __ mv(sp, kReturnRegister0); - { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - __ li(scratch, StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)); - __ StoreWord(scratch, - MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - } __ Ret(); __ bind(&call_runtime); @@ -3653,6 +3667,44 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Ret(); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + RegList gp_saves; + for (Register r : wasm::kGpReturnRegisters) gp_saves.set(r); + DoubleRegList fp_saves; + for (DoubleRegister r : wasm::kFpReturnRegisters) fp_saves.set(r); + Simd128RegList simd_saves; + for (Simd128Register r : wasm::kSimd128ReturnRegisters) { + simd_saves.set(VRegister::from_code(r.code())); + } + + __ PushAll(gp_saves); + __ SaveVectorRegisters(simd_saves); + __ PushAll(fp_saves); + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = gp_saves.Count() * kSystemPointerSize + + simd_saves.Count() * kSimd128Size + + fp_saves.Count() * kDoubleSize; + __ li(kCArgRegs[0], ExternalReference::isolate_address()); + __ AddWord(kCArgRegs[1], sp, Operand(saved_size)); + __ PrepareCallCFunction(2, kScratchReg); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ mv(fp, kReturnRegister0); + + __ PopAll(fp_saves); + __ RestoreVectorRegisters(simd_saves); + __ PopAll(gp_saves); + + SwitchSimulatorStackLimit(masm); + __ Move(sp, fp); + __ LoadWord(ra, MemOperand(fp, CommonFrameConstants::kCallerPCOffset)); + __ LoadWord(fp, MemOperand(fp, CommonFrameConstants::kCallerFPOffset)); + __ AddWord(sp, sp, Operand(CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ Ret(); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { @@ -3819,6 +3871,12 @@ void Builtins::Generate_WasmTrapHandlerLandingPad(MacroAssembler* masm) { // position of the faulty memory access, however, is recorded at the fault // address. Therefore the stack trace code would not find the source position // if we used the fault address as the return address. + // Push MessageTemplate::kNone as trap reason for WasmTrapHandlerThrowTrap; + // the runtime will determine the actual trap reason from the trapping + // instruction. + static_assert(Smi::FromInt(static_cast<int>(MessageTemplate::kNone)).ptr() == + 0); + __ Push(zero_reg); __ AddWord(ra, kWasmTrapHandlerFaultAddressRegister, 1); __ TailCallBuiltin(Builtin::kWasmTrapHandlerThrowTrap); } @@ -3976,10 +4034,8 @@ void Builtins::Generate_WasmSuspend(MacroAssembler* masm) { parent, FieldMemOperand(suspender, offsetof(WasmSuspenderObject, parent_))); DEFINE_REG(target_stack); - __ LoadExternalPointerField( - target_stack, - FieldMemOperand(parent, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ LoadWord(target_stack, + FieldMemOperand(parent, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_suspend_stack(), target_stack, &resume, no_reg, scratch, {target_stack, suspender, parent}); @@ -4039,7 +4095,7 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { suspender, FieldMemOperand(resume_data, offsetof(WasmResumeData, trusted_suspender_)), - kWasmSuspenderIndirectPointerTag); + kWasmSuspenderTrustedPointerTag); regs.ResetExcept(suspender); // ------------------------------------------- @@ -4053,10 +4109,9 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { // Call the C function. // ------------------------------------------- DEFINE_REG(target_stack); - __ LoadExternalPointerField( + __ LoadWord( target_stack, - FieldMemOperand(suspender, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + FieldMemOperand(suspender, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_resume_jspi_stack(), target_stack, &suspend, suspender, scratch, {target_stack}); @@ -4361,9 +4416,8 @@ void SwitchToAllocatedStack(MacroAssembler* masm, RegisterAllocator& regs, DEFINE_SCOPED(scratch) DEFINE_REG(stack) __ LoadRootRelative(stack, IsolateData::active_suspender_offset()); - __ LoadExternalPointerField( - stack, FieldMemOperand(stack, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag); + __ LoadWord(stack, + FieldMemOperand(stack, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_start_stack(), stack, suspend, no_reg, scratch, {wasm_instance, wrapper_buffer}); FREE_REG(stack); @@ -4528,8 +4582,15 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; auto regs = RegisterAllocator::WithAllocatableGeneralRegisters(); + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; + __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); __ SubWord( @@ -4574,16 +4635,61 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ StoreWord(scratch, MemOperand(fp, WasmJspiFrameConstants::kResultArrayOffset)); + __ StoreWord( + zero_reg, + MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); } } { - DEFINE_SCOPED(result_size); + DEFINE_SCOPED(return_space); + // Calculate the stack space required for return values (in bytes). __ LoadWord( - result_size, + return_space, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants:: kWrapperBufferStackReturnBufferSize)); - __ SllWord(result_size, result_size, kSystemPointerSizeLog2); - __ SubWord(sp, sp, Operand(result_size)); + __ SllWord(return_space, return_space, kSystemPointerSizeLog2); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we + // calculate the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + DEFINE_SCOPED(total_space); + __ LoadWord( + total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + DEFINE_SCOPED(params_start); + __ LoadWord( + params_start, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ SubWord(total_space, total_space, params_start); + __ SubWord(total_space, total_space, stack_params_offset); + __ AddWord(total_space, total_space, return_space); + + // Compare sp - total_space with the real stack limit. + // Note: sp - total_space will not underflow because sp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens + // of KiB). Thus, the unsigned comparison against the real stack limit is + // safe. + Register hypothetical_sp = total_space; + __ SubWord(hypothetical_sp, sp, total_space); + + DEFINE_SCOPED(stack_limit); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + __ Branch(&stack_overflow, ult, hypothetical_sp, Operand(stack_limit)); + } + + // Allocate stack space for return values. + __ SubWord(sp, sp, Operand(return_space)); } __ StoreWord( @@ -4599,12 +4705,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { regs.Reserve(reg); } - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - { DEFINE_SCOPED(params_start); __ LoadWord( @@ -4658,8 +4758,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { DCHECK_EQ(next_offset, stack_params_offset); } - __ StoreWord(zero_reg, - MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); { DEFINE_SCOPED(call_target); __ LoadWasmCodePointer( @@ -4745,6 +4843,23 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, regs, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ LoadWord(kContextRegister, + MemOperand(fp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ LoadWord( + kContextRegister, + MemOperand(fp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + { + UseScratchRegisterScope temps(masm); + GetContextFromImplicitArg(masm, kContextRegister, temps.Acquire()); + } + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -5424,7 +5539,7 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( code_obj, FieldMemOperand(code_obj, offsetof(SharedFunctionInfo, trusted_function_data_)), - kCodeIndirectPointerTag); + kCodeTrustedPointerTag); // For OSR entry it is safe to assume we always have baseline code. if (v8_flags.debug_code) { diff --git a/deps/v8/src/builtins/s390/builtins-s390.cc b/deps/v8/src/builtins/s390/builtins-s390.cc index 8d7e01cb739b..73aa73168fff 100644 --- a/deps/v8/src/builtins/s390/builtins-s390.cc +++ b/deps/v8/src/builtins/s390/builtins-s390.cc @@ -124,7 +124,8 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, DCHECK(!AreAliased(feedback_vector, scratch)); __ LoadU8(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ AndP(scratch, scratch, Operand(~FeedbackVector::OsrUrgencyBits::kMask)); + __ AndP(scratch, scratch, + Operand(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ StoreU8(scratch, FieldMemOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); } @@ -496,7 +497,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { __ LoadTaggedField( r6, FieldMemOperand(r3, offsetof(JSFunction, shared_function_info_))); __ LoadU32(r6, FieldMemOperand(r6, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(r6); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(r6); __ JumpIfIsInRange( r6, r6, static_cast<uint8_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint8_t>(FunctionKind::kDerivedConstructor), @@ -1479,9 +1480,13 @@ void Builtins::Generate_InterpreterEntryTrampoline( // Load frame size (word) from the BytecodeArray object. __ LoadU32(r4, FieldMemOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + __ LoadU16(r8, FieldMemOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ ShiftLeftU64(r8, r8, Operand(kSystemPointerSizeLog2)); + __ AddS64(r8, r4, r8); // Do a stack check to ensure we don't go over the limit. - __ SubS64(r8, sp, r4); + __ SubS64(r8, sp, r8); __ CmpU64(r8, __ StackLimitAsMemOperand(StackLimitKind::kRealStackLimit)); __ blt(&stack_overflow); @@ -1903,12 +1908,13 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( __ LoadTaggedField( r4, FieldMemOperand(r3, offsetof(JSFunction, shared_function_info_))); __ LoadU32(r4, FieldMemOperand(r4, offsetof(SharedFunctionInfo, flags_))); - __ AndP(r0, r4, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ AndP(r0, r4, + Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ bne(&builtin_call); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(r4); __ JumpIfIsInRange( r4, r4, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -2706,8 +2712,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, Label done_convert; __ LoadU32(r5, FieldMemOperand(r4, offsetof(SharedFunctionInfo, flags_))); __ AndP(r0, r5, - Operand(SharedFunctionInfo::IsStrictBit::kMask | - SharedFunctionInfo::IsNativeBit::kMask)); + Operand(SharedFunctionInfo::Flags::IsStrictBit::kMask | + SharedFunctionInfo::Flags::IsNativeBit::kMask)); __ bne(&done_convert); { // ----------- S t a t e ------------- @@ -2899,7 +2905,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { __ LoadTaggedField( r6, FieldMemOperand(r3, offsetof(JSFunction, shared_function_info_))); __ LoadU32(r6, FieldMemOperand(r6, offsetof(SharedFunctionInfo, flags_))); - __ AndP(r6, Operand(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + __ AndP(r6, Operand(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ beq(&call_generic_stub); __ TailCallBuiltin(Builtin::kJSBuiltinsConstructStub); @@ -3162,7 +3168,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameAndConstantPoolScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. __ MultiPush(WasmDebugBreakFrameConstants::kPushedGpRegs); __ MultiPushF64OrV128(WasmDebugBreakFrameConstants::kPushedFpRegs, ip); @@ -3199,7 +3210,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -4036,6 +4047,7 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; auto regs = RegisterAllocator::WithAllocatableGeneralRegisters(); __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); @@ -4053,6 +4065,12 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { Label suspend; Register original_fp = no_reg; Register new_wrapper_buffer = no_reg; + + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; if (stack_switch) { SwitchToAllocatedStack(masm, regs, implicit_arg, wrapper_buffer, original_fp, new_wrapper_buffer, &suspend); @@ -4078,16 +4096,62 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ StoreU64(scratch, MemOperand(fp, WasmJspiFrameConstants::kResultArrayOffset)); + __ Zero(MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); } } + { - DEFINE_SCOPED(result_size); + DEFINE_SCOPED(return_space); + // Calculate the stack space required for return values (in bytes). __ LoadU64( - result_size, + return_space, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants:: kWrapperBufferStackReturnBufferSize)); - __ ShiftLeftU64(r0, result_size, Operand(kSystemPointerSizeLog2)); - __ SubS64(sp, sp, r0); + __ ShiftLeftU64(return_space, return_space, + Operand(kSystemPointerSizeLog2)); + + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we + // calculate the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + DEFINE_SCOPED(total_space); + __ LoadU64( + total_space, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + DEFINE_SCOPED(params_start); + __ LoadU64( + params_start, + MemOperand(wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); + __ SubS64(total_space, total_space, params_start); + __ SubS64(total_space, total_space, Operand(stack_params_offset)); + __ AddS64(total_space, total_space, return_space); + + // Compare sp - total_space with the real stack limit. + // Note: sp - total_space will not underflow because sp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens + // of KiB). Thus, the unsigned comparison (lo) against the real stack + // limit is safe. + Register hypothetical_sp = total_space; + __ SubS64(hypothetical_sp, sp, total_space); + + DEFINE_SCOPED(stack_limit); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + __ CmpU64(hypothetical_sp, stack_limit); + __ blt(&stack_overflow); + } + + // Allocate stack space for return values. + __ SubS64(sp, sp, return_space); } __ StoreU64( @@ -4104,12 +4168,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { regs.Reserve(reg); } - // The first GP parameter holds the trusted instance data or the import data. - // This is handled specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - { Register params_start = ip; __ LoadU64( @@ -4163,7 +4221,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { DCHECK_EQ(next_offset, stack_params_offset); } - __ Zero(MemOperand(fp, WasmJspiFrameConstants::kGCScanSlotCountOffset)); { DEFINE_SCOPED(call_target); __ LoadWasmCodePointer( @@ -4241,6 +4298,20 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, regs, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ LoadU64(kContextRegister, + MemOperand(fp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ LoadU64( + kContextRegister, + MemOperand(fp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + GetContextFromImplicitArg(masm, kContextRegister, r3); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -4563,18 +4634,23 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); + __ mov(kCArgRegs[4], fp); __ mov(kCArgRegs[3], gap); + __ mov(r1, parameter_slots_size); __ mov(kCArgRegs[1], sp); __ SubS64(kCArgRegs[2], frame_base, kCArgRegs[1]); - __ mov(kCArgRegs[4], fp); FrameScope scope(masm, StackFrame::INTERNAL); __ push(kCArgRegs[3]); - __ PrepareCallCFunction(5, r0); + __ PrepareCallCFunction(6, r0); + __ StoreU64(r1, + MemOperand(sp, kStackFrameExtraParamSlot * kSystemPointerSize)); __ Move(kCArgRegs[0], ER::isolate_address()); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ pop(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4587,13 +4663,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ SubS64(fp, fp, sp); __ AddS64(fp, fp, kReturnRegister0); __ mov(sp, kReturnRegister0); - { - UseScratchRegisterScope temps(masm); - Register scratch = temps.Acquire(); - __ mov(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - __ StoreU64(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - } __ Ret(); __ bind(&call_runtime); @@ -4614,6 +4683,36 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ Ret(); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + RegList gp_saves; + for (Register r : wasm::kGpReturnRegisters) gp_saves.set(r); + DoubleRegList fp_saves; + for (DoubleRegister r : wasm::kFpReturnRegisters) fp_saves.set(r); + + __ MultiPush(gp_saves); + __ MultiPushF64OrV128(fp_saves, r1); + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = + gp_saves.Count() * kSystemPointerSize + fp_saves.Count() * kSimd128Size; + __ Move(kCArgRegs[0], ExternalReference::isolate_address()); + __ AddS64(kCArgRegs[1], sp, Operand(saved_size)); + __ PrepareCallCFunction(2, r0); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ mov(fp, kReturnRegister0); + + __ MultiPopF64OrV128(fp_saves, r1); + __ MultiPop(gp_saves); + + __ LoadU64(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); + __ AddS64(r1, fp, Operand(StandardFrameConstants::kCallerSPOffset)); + __ LoadU64(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); + __ mov(sp, r1); + __ b(r14); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { diff --git a/deps/v8/src/builtins/setup-builtins-internal.cc b/deps/v8/src/builtins/setup-builtins-internal.cc index 93d6879a0b39..cf4ecea0fc58 100644 --- a/deps/v8/src/builtins/setup-builtins-internal.cc +++ b/deps/v8/src/builtins/setup-builtins-internal.cc @@ -108,6 +108,8 @@ AssemblerOptions BuiltinAssemblerOptions(Isolate* isolate, Builtin builtin) { if (wasm::BuiltinLookup::IsWasmBuiltinId(builtin) || builtin == Builtin::kJSToWasmWrapper || builtin == Builtin::kJSToWasmHandleReturns || + builtin == Builtin::kWasmReturnPromiseOnSuspendAsm || + builtin == Builtin::kJSToWasmStressSwitchStacksAsm || #ifdef V8_ENABLE_DRUMBRAKE builtin == Builtin::kJSToWasmInterpreterHandleReturns || builtin == Builtin::kJSToWasmInterpreterWrapper || @@ -278,7 +280,7 @@ V8_NOINLINE Tagged<Code> BuildWithTurboshaftAssemblerJS( isolate, builtin, generator, [argc](Zone* zone) { return compiler::Linkage::GetJSCallDescriptor( - zone, false, argc, compiler::CallDescriptor::kCanUseRoots); + zone, false, argc, compiler::CallDescriptor::kNoFlags); }, name, BuiltinAssemblerOptions(isolate, builtin)); return *code; diff --git a/deps/v8/src/builtins/superspread.h b/deps/v8/src/builtins/superspread.h index 596ff96a59b6..35b0dc517d52 100644 --- a/deps/v8/src/builtins/superspread.h +++ b/deps/v8/src/builtins/superspread.h @@ -11,7 +11,8 @@ namespace v8 { namespace internal { struct SuperSpreadArgs { -#ifdef V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || \ + (V8_TARGET_ARCH_X64 && V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) static constexpr int kNumExtraArgs = 5; #else static constexpr int kNumExtraArgs = 4; diff --git a/deps/v8/src/builtins/typed-array-createtypedarray.tq b/deps/v8/src/builtins/typed-array-createtypedarray.tq index 9af37f835701..97aba5f1af0b 100644 --- a/deps/v8/src/builtins/typed-array-createtypedarray.tq +++ b/deps/v8/src/builtins/typed-array-createtypedarray.tq @@ -22,6 +22,8 @@ extern runtime GrowableSharedArrayBufferByteLength( const kFloat16ArrayFeature: constexpr UseCounterFeature generates 'v8::Isolate::kFloat16Array'; +const kBigIntFeature: constexpr UseCounterFeature + generates 'v8::Isolate::kBigInt'; extern macro TypedArrayBuiltinsAssembler::IsTrackArrayBufferViewsEnabled(): bool; @@ -108,6 +110,8 @@ transitioning macro AllocateTypedArray( if (typedArray.elements_kind == ElementsKind::FLOAT16_ELEMENTS || typedArray.elements_kind == ElementsKind::RAB_GSAB_FLOAT16_ELEMENTS) { IncrementUseCounter(context, SmiConstant(kFloat16ArrayFeature)); + } else if (IsBigInt64ElementsKind(typedArray.elements_kind)) { + IncrementUseCounter(context, SmiConstant(kBigIntFeature)); } return typedArray; } diff --git a/deps/v8/src/builtins/typed-array-entries.tq b/deps/v8/src/builtins/typed-array-entries.tq index 1bc649f4d7ad..a34ec6396850 100644 --- a/deps/v8/src/builtins/typed-array-entries.tq +++ b/deps/v8/src/builtins/typed-array-entries.tq @@ -19,7 +19,7 @@ transitioning javascript builtin TypedArrayPrototypeEntries( EnsureValid(array, TypedArrayAccessMode::kRead) otherwise IsDetached; return CreateArrayIterator(array, IterationKind::kEntries); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameEntries); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label IsDetached deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, diff --git a/deps/v8/src/builtins/typed-array-every.tq b/deps/v8/src/builtins/typed-array-every.tq index c15fa7dfd068..9cb27cfa8397 100644 --- a/deps/v8/src/builtins/typed-array-every.tq +++ b/deps/v8/src/builtins/typed-array-every.tq @@ -67,7 +67,7 @@ transitioning javascript builtin TypedArrayPrototypeEvery( const thisArg = arguments[1]; return EveryAllElements(attachedArrayAndLength, callbackfn, thisArg); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameEvery); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, kBuiltinNameEvery); diff --git a/deps/v8/src/builtins/typed-array-filter.tq b/deps/v8/src/builtins/typed-array-filter.tq index c8c4f2740b3d..f9c15716cd0c 100644 --- a/deps/v8/src/builtins/typed-array-filter.tq +++ b/deps/v8/src/builtins/typed-array-filter.tq @@ -15,8 +15,7 @@ transitioning javascript builtin TypedArrayPrototypeFilter( // 2. Perform ? ValidateTypedArray(O). // 3. Let len be IntegerIndexedObjectLength(O). const array: JSTypedArray = Cast<JSTypedArray>(receiver) - otherwise ThrowTypeError( - MessageTemplate::kNotTypedArray, kBuiltinNameFilter); + otherwise ThrowTypeError(MessageTemplate::kNotTypedArray); const attachedArrayAndLength = EnsureValidAndReadLength( array, TypedArrayAccessMode::kRead) otherwise Fail; diff --git a/deps/v8/src/builtins/typed-array-find.tq b/deps/v8/src/builtins/typed-array-find.tq index 42044777c71d..76e27637fb0a 100644 --- a/deps/v8/src/builtins/typed-array-find.tq +++ b/deps/v8/src/builtins/typed-array-find.tq @@ -71,7 +71,7 @@ transitioning javascript builtin TypedArrayPrototypeFind( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFind); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, kBuiltinNameFind); diff --git a/deps/v8/src/builtins/typed-array-findindex.tq b/deps/v8/src/builtins/typed-array-findindex.tq index f96580451ee9..6eedce3020f7 100644 --- a/deps/v8/src/builtins/typed-array-findindex.tq +++ b/deps/v8/src/builtins/typed-array-findindex.tq @@ -65,7 +65,7 @@ transitioning javascript builtin TypedArrayPrototypeFindIndex( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFindIndex); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, diff --git a/deps/v8/src/builtins/typed-array-findlast.tq b/deps/v8/src/builtins/typed-array-findlast.tq index 274e0e8f301a..79eaa11bc2aa 100644 --- a/deps/v8/src/builtins/typed-array-findlast.tq +++ b/deps/v8/src/builtins/typed-array-findlast.tq @@ -70,7 +70,7 @@ transitioning javascript builtin TypedArrayPrototypeFindLast( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFindLast); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, diff --git a/deps/v8/src/builtins/typed-array-findlastindex.tq b/deps/v8/src/builtins/typed-array-findlastindex.tq index 2b408d0a1121..ac62b5292e75 100644 --- a/deps/v8/src/builtins/typed-array-findlastindex.tq +++ b/deps/v8/src/builtins/typed-array-findlastindex.tq @@ -70,7 +70,7 @@ transitioning javascript builtin TypedArrayPrototypeFindLastIndex( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameFindLastIndex); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, diff --git a/deps/v8/src/builtins/typed-array-foreach.tq b/deps/v8/src/builtins/typed-array-foreach.tq index 2fddaebfcf1c..ae77896a569f 100644 --- a/deps/v8/src/builtins/typed-array-foreach.tq +++ b/deps/v8/src/builtins/typed-array-foreach.tq @@ -66,7 +66,7 @@ transitioning javascript builtin TypedArrayPrototypeForEach( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameForEach); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, diff --git a/deps/v8/src/builtins/typed-array-keys.tq b/deps/v8/src/builtins/typed-array-keys.tq index dfa45c2e90f7..ae7eec0c0297 100644 --- a/deps/v8/src/builtins/typed-array-keys.tq +++ b/deps/v8/src/builtins/typed-array-keys.tq @@ -19,7 +19,7 @@ transitioning javascript builtin TypedArrayPrototypeKeys( EnsureValid(array, TypedArrayAccessMode::kRead) otherwise IsDetached; return CreateArrayIterator(array, IterationKind::kKeys); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameKeys); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label IsDetached deferred { ThrowTypeError( MessageTemplate::kTypedArrayDetachedErrorOperation, kBuiltinNameKeys); diff --git a/deps/v8/src/builtins/typed-array-reduce.tq b/deps/v8/src/builtins/typed-array-reduce.tq index 3de66e9bbd77..2a4cb4a14e5c 100644 --- a/deps/v8/src/builtins/typed-array-reduce.tq +++ b/deps/v8/src/builtins/typed-array-reduce.tq @@ -38,7 +38,7 @@ transitioning macro ReduceAllElements( } typeswitch (accumulator) { case (TheHole): { - ThrowTypeError(MessageTemplate::kReduceNoInitial, kBuiltinNameReduce); + ThrowTypeError(MessageTemplate::kReduceNoInitial); } case (accumulator: JSAny): { return accumulator; @@ -66,7 +66,7 @@ transitioning javascript builtin TypedArrayPrototypeReduce( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameReduce); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayDetachedErrorOperation, kBuiltinNameReduce); diff --git a/deps/v8/src/builtins/typed-array-reduceright.tq b/deps/v8/src/builtins/typed-array-reduceright.tq index 2dea2e2ab68a..33308a34d356 100644 --- a/deps/v8/src/builtins/typed-array-reduceright.tq +++ b/deps/v8/src/builtins/typed-array-reduceright.tq @@ -39,8 +39,7 @@ transitioning macro ReduceRightAllElements( } typeswitch (accumulator) { case (TheHole): { - ThrowTypeError( - MessageTemplate::kReduceNoInitial, kBuiltinNameReduceRight); + ThrowTypeError(MessageTemplate::kReduceNoInitial); } case (accumulator: JSAny): { return accumulator; @@ -70,7 +69,7 @@ transitioning javascript builtin TypedArrayPrototypeReduceRight( } label NotCallable deferred { ThrowCalledNonCallable(arguments[0]); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameReduceRight); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, diff --git a/deps/v8/src/builtins/typed-array-set.tq b/deps/v8/src/builtins/typed-array-set.tq index c77e07a0f423..d36a4b105f52 100644 --- a/deps/v8/src/builtins/typed-array-set.tq +++ b/deps/v8/src/builtins/typed-array-set.tq @@ -42,7 +42,7 @@ transitioning javascript builtin TypedArrayPrototypeSet( // 4. Assert: target has a [[ViewedArrayBuffer]] internal slot. target = Cast<JSTypedArray>(receiver) otherwise NotTypedArray; } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameSet); + ThrowTypeError(MessageTemplate::kNotTypedArray); } try { diff --git a/deps/v8/src/builtins/typed-array-some.tq b/deps/v8/src/builtins/typed-array-some.tq index d22f9c07f8df..62f35e1b0031 100644 --- a/deps/v8/src/builtins/typed-array-some.tq +++ b/deps/v8/src/builtins/typed-array-some.tq @@ -69,7 +69,7 @@ transitioning javascript builtin TypedArrayPrototypeSome( const thisArg = arguments[1]; return SomeAllElements(attachedArrayAndLength, callbackfn, thisArg); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameSome); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, kBuiltinNameSome); diff --git a/deps/v8/src/builtins/typed-array-values.tq b/deps/v8/src/builtins/typed-array-values.tq index da7ee2c392d5..b38501b587d7 100644 --- a/deps/v8/src/builtins/typed-array-values.tq +++ b/deps/v8/src/builtins/typed-array-values.tq @@ -19,7 +19,7 @@ transitioning javascript builtin TypedArrayPrototypeValues( EnsureValid(array, TypedArrayAccessMode::kRead) otherwise IsDetached; return CreateArrayIterator(array, IterationKind::kValues); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameValues); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label IsDetached deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, kBuiltinNameValues); diff --git a/deps/v8/src/builtins/typed-array-with.tq b/deps/v8/src/builtins/typed-array-with.tq index a8da3366d073..701a9bfa3e56 100644 --- a/deps/v8/src/builtins/typed-array-with.tq +++ b/deps/v8/src/builtins/typed-array-with.tq @@ -103,7 +103,7 @@ transitioning javascript builtin TypedArrayPrototypeWith( } label IndexOutOfBounds deferred { ThrowRangeError(MessageTemplate::kInvalidTypedArrayIndex); } label NotTypedArray deferred { - ThrowTypeError(MessageTemplate::kNotTypedArray, kBuiltinNameWith); + ThrowTypeError(MessageTemplate::kNotTypedArray); } label Fail deferred { ThrowTypeError( MessageTemplate::kTypedArrayValidateErrorOperation, kBuiltinNameWith); diff --git a/deps/v8/src/builtins/wasm-interpreter-wrappers.tq b/deps/v8/src/builtins/wasm-interpreter-wrappers.tq index 5a1f213f6faf..03362f075129 100644 --- a/deps/v8/src/builtins/wasm-interpreter-wrappers.tq +++ b/deps/v8/src/builtins/wasm-interpreter-wrappers.tq @@ -88,6 +88,13 @@ transitioning javascript builtin JSToWasmInterpreterWrapper( const sigTypes = torque_internal::unsafe::NewOffHeapConstSlice( %RawDownCast<RawPtr<uint32>>(reps), paramCount + returnCount); + let sigIt = sigTypes.Iterator(); + while (!sigIt.Empty()) { + if (sigIt.NextNotEmpty() == kWasmS128Type) { + ThrowTypeError(MessageTemplate::kWasmTrapJSTypeError); + } + } + // If the return count is greater than 1, then the return values are returned // as a JSArray. After returning from the call to wasm, the return values are // stored on an area of the stack the GC does not know about. To avoid a GC diff --git a/deps/v8/src/builtins/wasm.tq b/deps/v8/src/builtins/wasm.tq index 2f85cf06de05..89ce0f31e8e4 100644 --- a/deps/v8/src/builtins/wasm.tq +++ b/deps/v8/src/builtins/wasm.tq @@ -25,7 +25,6 @@ extern runtime WasmFunctionTableSet( extern runtime ThrowRangeError(Context, Smi): never; extern runtime ThrowWasmError(Context, Smi): never; extern runtime WasmThrowRangeError(Context, Smi): never; -extern runtime TrapHandlerThrowWasmError(Context): never; extern runtime WasmThrowTypeError(Context, Smi, JSAny): never; extern runtime WasmThrowDataViewTypeError(Context, Smi, JSAny): never; extern runtime WasmThrowDataViewDetachedError(Context, Smi): never; @@ -53,14 +52,18 @@ extern runtime WasmManagedObjectWaitRef( extern runtime WasmWaitqueueNew(Context): HeapObject; extern runtime WasmArrayCopy(Context, WasmArray, Smi, WasmArray, Smi, Smi): JSAny; +// Return type depends on v8_flags.wasm_merged_descriptors; simplify when +// dropping that flag. extern runtime WasmAllocateDescriptorStruct( - Context, WasmTrustedInstanceData, Map, Smi, Object): WasmStruct; + Context, WasmTrustedInstanceData, Map, Smi, Object): WasmStruct + |WasmCustomMap; extern runtime WasmArrayNewSegment( - Context, WasmTrustedInstanceData, Smi, Smi, Smi, Map): Object; + Context, WasmTrustedInstanceData, Smi, Smi, Smi, Smi, Map): Object; extern runtime WasmStringNewSegmentWtf8( Context, WasmTrustedInstanceData, Smi, Smi, Smi, Smi): String|WasmNull; extern runtime WasmArrayInitSegment( - Context, WasmTrustedInstanceData, Smi, WasmArray, Smi, Smi, Smi): JSAny; + Context, WasmTrustedInstanceData, Smi, Smi, WasmArray, Smi, Smi, + Smi): JSAny; extern runtime WasmStringNewWtf8( Context, WasmTrustedInstanceData, Smi, Smi, Number, Number): String |WasmNull; @@ -91,8 +94,8 @@ extern runtime WasmStringHash(NoContext, String): Smi; extern runtime WasmSubstring(Context, String, Smi, Smi): String; extern runtime WasmSubstringShared(Context, String, Smi, Smi): String; extern runtime WasmStringAdd_NoMapCheck_Shared(Context, String, String): String; -extern runtime WasmLiftoffDeoptFinish(NoContext, WasmTrustedInstanceData): - Undefined; +extern runtime WasmLiftoffDeoptFinish(NoContext): Undefined; +extern runtime WasmExternConvertAny(Context, HeapObject): JSAny; extern runtime PropagateException(NoContext): JSAny; extern runtime AllocateInSharedHeap(Context, Smi, Smi): HeapObject; @@ -130,7 +133,11 @@ const kMaxPolymorphism: constexpr int31 generates 'wasm::kMaxPolymorphism'; const kFixedFrameSizeAboveFp: constexpr int32 generates 'CommonFrameConstants::kFixedFrameSizeAboveFp'; const kDoubleAligned: constexpr int31 generates 'kDoubleAligned'; -const kDoubleUnaligned: constexpr int31 generates 'kDoubleUnaligned'; + +const kWasmUnsharedArrayHeaderSize: + constexpr int32 generates 'WasmArray::HeaderSize(SharedFlag{false})'; +const kWasmSharedArrayHeaderSize: + constexpr int32 generates 'WasmArray::HeaderSize(SharedFlag{true})'; extern macro WasmCrossInstanceCallSymbolConstant(): Symbol; @@ -438,8 +445,7 @@ builtin WasmAllocateFixedArray(size: intptr): FixedArray { } builtin WasmLiftoffDeoptFinish(): Undefined { - const trustedData = LoadInstanceDataFromFrame(); - tail runtime::WasmLiftoffDeoptFinish(kNoContext, trustedData); + tail runtime::WasmLiftoffDeoptFinish(kNoContext); } builtin WasmThrow( @@ -471,15 +477,20 @@ builtin WasmTriggerTierUp(): JSAny { tail runtime::WasmTriggerTierUp(LoadContextFromFrame(), trustedData); } -extern builtin WasmHandleStackOverflow(RawPtr, uint32): JSAny; +extern builtin WasmHandleStackOverflow(RawPtr, uint32, intptr): JSAny; -// {paramSlotsSize} is the size of the incoming stack parameters of the -// currently-executing function, which have to be copied along with its -// stack frame if the stack needs to be grown. -builtin WasmGrowableStackGuard(paramSlotsSize: intptr, gap: intptr): JSAny { +// {stackParamAndReturnSlotsSize} is the combined size of the incoming stack +// parameters and stack return slots of the currently-executing function, which +// have to be copied along with its stack frame if the stack needs to be grown. +// {parameterSlotsSize} is the size of incoming stack parameters (which is also +// the distance from the current FP to the relocated partial frame). +builtin WasmGrowableStackGuard( + stackParamAndReturnSlotsSize: intptr, gap: intptr, + parameterSlotsSize: intptr): JSAny { tail WasmHandleStackOverflow( - LoadParentFramePointer() + paramSlotsSize + kFixedFrameSizeAboveFp, - Unsigned(Convert<int32>(gap))); + LoadParentFramePointer() + stackParamAndReturnSlotsSize + + kFixedFrameSizeAboveFp, + Unsigned(Convert<int32>(gap)), parameterSlotsSize); } builtin WasmStackGuard(gap: intptr): JSAny { @@ -531,14 +542,14 @@ builtin WasmAllocateStructWithRtt(rtt: Map, instanceSize: int32): HeapObject { return result; } +// Return type depends on v8_flags.wasm_merged_descriptors; simplify when +// dropping that flag. builtin WasmAllocateDescriptorStruct( - map: Map, typeIndex: int32, firstField: Object): WasmStruct { - // TODO(42204563): Figure out support for shared objects. + map: Map, typeIndex: int32, firstField: Object): WasmStruct|WasmCustomMap { const trustedData: WasmTrustedInstanceData = LoadInstanceDataFromFrame(); - const result: WasmStruct = runtime::WasmAllocateDescriptorStruct( + return runtime::WasmAllocateDescriptorStruct( LoadContextFromInstanceData(trustedData), trustedData, map, SmiTag(Convert<intptr>(typeIndex)), firstField); - return result; } builtin WasmAllocateSharedStructWithRtt(rtt: Map, instanceSize: int32): @@ -556,11 +567,11 @@ builtin WasmAllocateSharedStructWithRtt(rtt: Map, instanceSize: int32): builtin WasmAllocateArray_Uninitialized( rtt: Map, length: uint32, elementSize: uint32): WasmArray { // instanceSize = RoundUp(elementSize * length, kObjectAlignment) - // + WasmArray::kHeaderSize + // + WasmArray::HeaderSize(SharedFlag{false}) const instanceSize: intptr = torque_internal::AlignTagged( Convert<intptr>(length) * Convert<intptr>(elementSize)) + - Convert<intptr>(kWasmArrayHeaderSize); + Convert<intptr>(kWasmUnsharedArrayHeaderSize); const result: HeapObject = unsafe::Allocate(instanceSize); *UnsafeConstCast(&result.map) = rtt; // TODO(ishell): consider removing properties_or_hash field from WasmObjects. @@ -572,14 +583,14 @@ builtin WasmAllocateArray_Uninitialized( builtin WasmAllocateSharedArray_Uninitialized( rtt: Map, length: uint32, elementSize: uint32): WasmArray { // instanceSize = RoundUp(elementSize * length, kObjectAlignment) - // + WasmArray::kHeaderSize + // + WasmArray::HeaderSize(SharedFlag{true}) const instanceSize: intptr = torque_internal::AlignTagged( Convert<intptr>(length) * Convert<intptr>(elementSize)) + - Convert<intptr>(kWasmArrayHeaderSize); + Convert<intptr>(kWasmSharedArrayHeaderSize); const result: HeapObject = runtime::AllocateInSharedHeap( LoadContextFromFrame(), SmiFromIntPtr(instanceSize), - SmiConstant(kDoubleUnaligned)); + SmiConstant(kDoubleAligned)); *UnsafeConstCast(&result.map) = rtt; // TODO(ishell): consider removing properties_or_hash field from WasmObjects. %RawDownCast<WasmArray>(result).properties_or_hash = kEmptyFixedArray; @@ -594,8 +605,10 @@ builtin WasmArrayNewSegment( try { const smiOffset = Convert<PositiveSmi>(offset) otherwise SegmentOutOfBounds; const smiLength = Convert<PositiveSmi>(length) otherwise ArrayTooLarge; - tail runtime::WasmArrayNewSegment( - LoadContextFromInstanceData(trustedData), trustedData, + // Cannot use a tail call because we are exceeding the maximum number of + // arguments. + return runtime::WasmArrayNewSegment( + LoadContextFromInstanceData(trustedData), trustedData, isElement, SmiFromUint32(segmentIndex), smiOffset, smiLength, rtt); } label SegmentOutOfBounds { if (isElement == SmiConstant(0)) { @@ -623,10 +636,11 @@ builtin WasmArrayInitSegment( const smiOffset = Convert<PositiveSmi>(segmentOffset) otherwise SegmentOutOfBounds; const smiLength = Convert<PositiveSmi>(length) otherwise ArrayOutOfBounds; - - tail runtime::WasmArrayInitSegment( - LoadContextFromInstanceData(trustedData), trustedData, segmentIndex, - array, smiArrayIndex, smiOffset, smiLength); + // Cannot use a tail call because we are exceeding the maximum number of + // arguments. + return runtime::WasmArrayInitSegment( + LoadContextFromInstanceData(trustedData), trustedData, isElement, + segmentIndex, array, smiArrayIndex, smiOffset, smiLength); } label SegmentOutOfBounds { if (isElement == SmiConstant(0)) { tail ThrowWasmTrapDataSegmentOutOfBounds(); @@ -867,10 +881,6 @@ builtin ThrowWasmTrapUnreachable(): JSAny { tail WasmTrap(SmiConstant(MessageTemplate::kWasmTrapUnreachable)); } -builtin WasmTrapHandlerThrowTrap(): JSAny { - tail runtime::TrapHandlerThrowWasmError(LoadContextFromWasmOrJsFrame()); -} - builtin WasmPropagateException(): JSAny { tail runtime::PropagateException(kNoContext); } @@ -1092,8 +1102,9 @@ builtin WasmStringNewWtf16Array( // TODO(448741522): Support inline creation of short shared Strings. // "config == 0" means both array and string are unshared. if (config != SmiConstant(0)) goto Runtime; + dcheck(!InSharedSpace(array)); if (length == 1) { - const offset = kWasmArrayHeaderSize + + const offset = kWasmUnsharedArrayHeaderSize + torque_internal::TimesSizeOf<char16>(Convert<intptr>(start)); const code: char16 = *torque_internal::unsafe::NewReference<char16>( array, offset); @@ -1106,7 +1117,7 @@ builtin WasmStringNewWtf16Array( if (length >= 32) goto Runtime; const intptrLength = Convert<intptr>(length); const arrayContent = torque_internal::unsafe::NewConstSlice<char16>( - array, kWasmArrayHeaderSize, Convert<intptr>(array.length)); + array, kWasmUnsharedArrayHeaderSize, Convert<intptr>(array.length)); const substring = Subslice(arrayContent, Convert<intptr>(start), intptrLength) otherwise goto OffsetOutOfRange; @@ -1215,7 +1226,10 @@ builtin WasmStringEncodeWtf16Array( if (start > array.length) goto OffsetOutOfRange; if (array.length - start < Unsigned(string.length)) goto OffsetOutOfRange; - const byteOffset: intptr = kWasmArrayHeaderSize + + const headerSize: intptr = InSharedSpace(array) ? + Convert<intptr>(kWasmSharedArrayHeaderSize) : + Convert<intptr>(kWasmUnsharedArrayHeaderSize); + const byteOffset: intptr = headerSize + torque_internal::TimesSizeOf<char16>(Convert<intptr>(start)); const arrayContent = torque_internal::unsafe::NewMutableSlice<char16>( array, byteOffset, string.length_intptr); @@ -1673,6 +1687,10 @@ builtin WasmAnyConvertExternShared(externObject: JSAny): JSAny { context, externObject, SmiConstant(kSharedAnyType)); } +builtin WasmExternConvertAny(wasmObject: HeapObject): JSAny { + tail runtime::WasmExternConvertAny( + LoadContextFromWasmOrJsFrame(), wasmObject); +} extern macro CallOrConstructBuiltinsAssembler::GetCompatibleReceiver( JSReceiver, HeapObject, Context): JSReceiver; @@ -1710,7 +1728,8 @@ builtin WasmLiftoffIsEqRefUnshared(obj: Object, nullSucceeds: bool): int32 { const heapObject: HeapObject = Cast<HeapObject>(obj) otherwise ReturnFalse; return Convert<int32>( !InSharedSpace(heapObject) && - (Is<WasmArray>(heapObject) || Is<WasmStruct>(heapObject))); + (Is<WasmArray>(heapObject) || Is<WasmStruct>(heapObject) || + Is<WasmCustomMap>(heapObject))); } label ReturnFalse { return 0; } @@ -1733,7 +1752,8 @@ builtin WasmLiftoffIsStructRefUnshared(obj: Object, nullSucceeds: bool): try { const heapObject: HeapObject = Cast<HeapObject>(obj) otherwise ReturnFalse; return Convert<int32>( - !InSharedSpace(heapObject) && Is<WasmStruct>(heapObject)); + !InSharedSpace(heapObject) && + (Is<WasmStruct>(heapObject) || Is<WasmCustomMap>(heapObject))); } label ReturnFalse { return 0; } @@ -1753,7 +1773,8 @@ builtin WasmLiftoffCastEqRefUnshared(obj: Object, nullSucceeds: bool): JSAny { } const heapObject: HeapObject = UnsafeCast<HeapObject>(obj); if (InSharedSpace(heapObject) || - (!Is<WasmArray>(heapObject) && !Is<WasmStruct>(heapObject))) { + (!Is<WasmArray>(heapObject) && !Is<WasmStruct>(heapObject) && + !Is<WasmCustomMap>(heapObject))) { goto IllegalCast; } return SmiConstant(0); @@ -1787,7 +1808,8 @@ builtin WasmLiftoffCastStructRefUnshared(obj: Object, nullSucceeds: bool): goto IllegalCast; } const heapObject: HeapObject = Cast<HeapObject>(obj) otherwise IllegalCast; - if (InSharedSpace(heapObject) || (!Is<WasmStruct>(heapObject))) { + if (InSharedSpace(heapObject) || + (!Is<WasmStruct>(heapObject) && !Is<WasmCustomMap>(heapObject))) { goto IllegalCast; } return SmiConstant(0); diff --git a/deps/v8/src/builtins/x64/builtins-x64.cc b/deps/v8/src/builtins/x64/builtins-x64.cc index a5a151bfac75..4ccd71265dce 100644 --- a/deps/v8/src/builtins/x64/builtins-x64.cc +++ b/deps/v8/src/builtins/x64/builtins-x64.cc @@ -26,7 +26,7 @@ #include "src/objects/js-generator.h" #include "src/objects/objects-inl.h" #include "src/objects/smi.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" #if V8_ENABLE_WEBASSEMBLY #include "src/wasm/baseline/liftoff-assembler-defs.h" @@ -201,7 +201,7 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { FieldOperand(rdi, offsetof(JSFunction, shared_function_info_))); __ movl(rbx, FieldOperand(shared_function_info, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(rbx); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(rbx); __ JumpIfIsInRange( rbx, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), static_cast<uint32_t>(FunctionKind::kDerivedConstructor), @@ -1051,7 +1051,7 @@ void ResetFeedbackVectorOsrUrgency(MacroAssembler* masm, Register feedback_vector, Register scratch) { __ movb(scratch, FieldOperand(feedback_vector, offsetof(FeedbackVector, osr_state_))); - __ andb(scratch, Immediate(~FeedbackVector::OsrUrgencyBits::kMask)); + __ andb(scratch, Immediate(~FeedbackVector::OsrState::OsrUrgencyBits::kMask)); __ movb(FieldOperand(feedback_vector, offsetof(FeedbackVector, osr_state_)), scratch); } @@ -1162,10 +1162,19 @@ void Builtins::Generate_InterpreterEntryTrampoline( // Load frame size from the BytecodeArray object. __ movl(rcx, FieldOperand(kInterpreterBytecodeArrayRegister, offsetof(BytecodeArray, frame_size_))); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + // Round up the frame size to a multiple of 2 * kSystemPointerSize. + __ addl(rcx, Immediate(kSystemPointerSize)); + __ andl(rcx, Immediate(~(2 * kSystemPointerSize - 1))); + } + + __ movzxwl(r11, FieldOperand(kInterpreterBytecodeArrayRegister, + offsetof(BytecodeArray, max_arguments_))); + __ leaq(r11, Operand(rcx, r11, times_system_pointer_size, 0)); // Do a stack check to ensure we don't go over the limit. __ movq(rax, rsp); - __ subq(rax, rcx); + __ subq(rax, r11); __ cmpq(rax, __ StackLimitAsOperand(StackLimitKind::kRealStackLimit)); __ j(below, &stack_overflow); @@ -1616,14 +1625,14 @@ void Builtins::Generate_InterpreterPushArgsThenFastConstructFunction( FieldOperand(rdi, offsetof(JSFunction, shared_function_info_))); __ testl( FieldOperand(shared_function_info, offsetof(SharedFunctionInfo, flags_)), - Immediate(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + Immediate(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ j(not_zero, &builtin_call); // Check if we need to create an implicit receiver. Label not_create_implicit_receiver; __ movl(kScratchRegister, FieldOperand(shared_function_info, offsetof(SharedFunctionInfo, flags_))); - __ DecodeField<SharedFunctionInfo::FunctionKindBits>(kScratchRegister); + __ DecodeField<SharedFunctionInfo::Flags::FunctionKindBits>(kScratchRegister); __ JumpIfIsInRange( kScratchRegister, static_cast<uint32_t>(FunctionKind::kDefaultDerivedConstructor), @@ -2094,7 +2103,8 @@ void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { DCHECK_EQ(kInterpreterAccumulatorRegister.code(), rax.code()); __ movq(rax, Operand(rsp, kPCOnStackSize)); - __ ret(1 * kSystemPointerSize); // Remove rax. + __ ret(AddArgumentPaddingSlots(1) * + kSystemPointerSize); // Remove rax and padding. } static void GenerateCall(MacroAssembler* masm, Register argc, Register target, @@ -2506,14 +2516,19 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, // Rewrite the stack frame to capture target, arguments list and length // Pop return address __ Pop(kScratchRegister); + constexpr int kPadding = V8_X64_16BYTE_STACK_ALIGNMENT_BOOL ? 1 : 0; // - receiver already on the stack. - static_assert(SuperSpreadArgs::kReceiverOffsetFromEnd == 4); + static_assert(SuperSpreadArgs::kReceiverOffsetFromEnd == 4 + kPadding); // - target - static_assert(SuperSpreadArgs::kTargetOffsetFromEnd == 3); + static_assert(SuperSpreadArgs::kTargetOffsetFromEnd == 3 + kPadding); __ Push(rdi); // - arguments list - static_assert(SuperSpreadArgs::kArglistOffsetFromEnd == 2); + static_assert(SuperSpreadArgs::kArglistOffsetFromEnd == 2 + kPadding); __ Push(rbx); + if constexpr (kPadding > 0) { + // - padding + __ Push(Immediate(0)); + } // - len of arguments list static_assert(SuperSpreadArgs::kArglistLengthOffsetFromEnd == 1); __ SmiTag(rcx); @@ -2636,8 +2651,8 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm, // We need to convert the receiver for non-native sloppy mode functions. Label done_convert; __ testl(FieldOperand(rdx, offsetof(SharedFunctionInfo, flags_)), - Immediate(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + Immediate(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); __ j(not_zero, &done_convert); { // ----------- S t a t e ------------- @@ -2832,7 +2847,7 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { FieldOperand(rdi, offsetof(JSFunction, shared_function_info_))); __ testl( FieldOperand(shared_function_info, offsetof(SharedFunctionInfo, flags_)), - Immediate(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); + Immediate(SharedFunctionInfo::Flags::ConstructAsBuiltinBit::kMask)); __ TailCallBuiltin(Builtin::kJSBuiltinsConstructStub, not_zero); __ TailCallBuiltin(Builtin::kJSConstructStubGeneric); @@ -3247,11 +3262,12 @@ void RestoreWasmParams(MacroAssembler* masm, int offset) { // When this builtin is called, the topmost stack entry is the calling pc. // This is replaced with the following: // -// [ calling pc ] <-- rsp; popped by {ret}. -// [ feedback vector ] -// [ Wasm instance data ] -// [ WASM frame marker ] -// [ saved rbp ] <-- rbp; this is where "calling pc" used to be. +// [ calling pc ] <-- rsp; popped by {ret}. +// [ alignment slot ] (only if V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) +// [ feedback vector ] +// [ Wasm instance data ] +// [ WASM frame marker ] +// [ saved rbp ] <-- rbp; this is where "calling pc" used to be. void Builtins::Generate_WasmLiftoffFrameSetup(MacroAssembler* masm) { Register func_index = wasm::kLiftoffFrameSetupFunctionReg; Register vector = r15; @@ -3274,6 +3290,16 @@ void Builtins::Generate_WasmLiftoffFrameSetup(MacroAssembler* masm) { Smi::FromInt(1)); __ Push(kWasmImplicitArgRegister); __ Push(vector); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + // Initialize the OSR target slot (at rbp - kOSRTargetOffset) to 0 so that + // the 4-slot static header leaves rsp 16-byte aligned (rbp - 32 instead of + // rbp - 24). Between this builtin's {ret} and the patched + // {sub rsp, frame_size}, the large-frame OOL stack check path may call + // {kWasmStackOverflow} or {kWasmHandleStackOverflow}, which requires {rsp} + // to be 16-byte aligned. + static_assert(wasm::kOSRTargetOffset == 4 * kSystemPointerSize); + __ Push(Immediate(0)); + } __ Push(calling_pc); __ ret(0); @@ -3356,7 +3382,10 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { } namespace { -enum class DebugBreakKind { kBreak, kTrap }; +enum class DebugBreakKind { + kBreak, // Breakpoint or stepping (WasmDebugBreak). + kTrap, // Trap in debug code or trap handler (WasmTrapHandlerThrowTrap). +}; void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { HardAbortScope hard_abort(masm); // Avoid calls to Abort. @@ -3364,7 +3393,12 @@ void Generate_WasmDebugBreakOrTrap(MacroAssembler* masm, DebugBreakKind kind) { FrameScope scope(masm, StackFrame::WASM_DEBUG_BREAK); // Save all parameter registers. They might hold live values, we restore - // them after the runtime call. + // them after the runtime call (for kBreak), or allow DevTools to inspect + // them at trap sites (for kTrap). + // Note: For non-debug execution, saving registers and creating a + // WASM_DEBUG_BREAK frame for trap handler traps might be redundant, but + // traps are cold exceptional paths so this negligible overhead is fine to + // keep the landing pad and trap handling unified. for (Register reg : base::Reversed(WasmDebugBreakFrameConstants::kPushedGpRegs)) { __ Push(reg); @@ -3418,7 +3452,7 @@ void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kBreak); } -void Builtins::Generate_WasmDebugTrap(MacroAssembler* masm) { +void Builtins::Generate_WasmTrapHandlerThrowTrap(MacroAssembler* masm) { Generate_WasmDebugBreakOrTrap(masm, DebugBreakKind::kTrap); } @@ -3543,9 +3577,7 @@ void SwitchToAllocatedStack(MacroAssembler* masm, Register wasm_instance, ResetWasmJspiFrameStackSlots(masm); Register stack = new_wrapper_buffer; __ LoadRootRelative(stack, IsolateData::active_suspender_offset()); - __ LoadExternalPointerField( - stack, FieldOperand(stack, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag, kScratchRegister); + __ movq(stack, FieldOperand(stack, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_start_stack(), stack, suspend, no_reg, {kWasmImplicitArgRegister, wrapper_buffer}); Register target_stack = scratch; @@ -3667,6 +3699,13 @@ void GenerateExceptionHandlingLandingPad(MacroAssembler* masm, void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { bool stack_switch = mode == wasm::kPromise || mode == wasm::kStressSwitch; + Label stack_overflow; + + // The first GP parameter holds the trusted instance data or the import data. + // This is handled specially. + constexpr int stack_params_offset = + (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + + arraysize(wasm::kFpParamRegisters) * kDoubleSize; __ EnterFrame(stack_switch ? StackFrame::WASM_JSPI : StackFrame::JS_TO_WASM); __ AllocateStackSpace(WasmJspiFrameConstants::kNumSpillSlots * @@ -3697,8 +3736,10 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { JSToWasmWrapperFrameConstants::kResultArrayParamOffset)); __ movq(MemOperand(rbp, WasmJspiFrameConstants::kResultArrayOffset), result_array); + __ Move(MemOperand(rbp, WasmJspiFrameConstants::kGCScanSlotCountOffset), 0); } + // Calculate the stack space required for return values. Register result_size = rax; __ movq( result_size, @@ -3706,35 +3747,63 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferStackReturnBufferSize)); __ shlq(result_size, Immediate(kSystemPointerSizeLog2)); - __ subq(rsp, result_size); - __ movq( - MemOperand( - new_wrapper_buffer, - JSToWasmWrapperFrameConstants::kWrapperBufferStackReturnBufferStart), - rsp); - Register call_target = rdi; - // param_start should not alias with any parameter registers. + + // params_start should not alias with any parameter registers. Register params_start = r11; __ movq(params_start, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferParamStart)); - Register params_end = rbx; + Register params_end = rcx; __ movq(params_end, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferParamEnd)); + // Preemptive Stack Overflow Check: + // Before allocating stack space for return values or pushing stack + // parameters (which could blindly overflow past the real stack limit, + // triggering DCHECK failures or crashes due to stack overflow), we calculate + // the total upcoming stack footprint and check if it fits. + { + // LocationAllocatorForParams reserves a fixed-size region of + // `stack_params_offset` bytes at `[params_start, params_start + + // stack_params_offset)` for all GP and FP register parameters (even if + // unused), and places stack parameters starting at `params_start + + // stack_params_offset`. Thus `params_end - params_start - + // stack_params_offset` is the exact stack parameter size (>= 0). + Register total_space = rdx; + __ movq(total_space, params_end); + __ subq(total_space, params_start); + __ subq(total_space, Immediate(stack_params_offset)); + __ addq(total_space, result_size); + + // Compare rsp - total_space with the real stack limit. + // Note: rsp - total_space will not underflow because rsp is a valid stack + // pointer (far above 0) and total_space is bounded by Wasm limits (~tens of + // KiB). Thus, the unsigned comparison (below) against the real stack limit + // is safe. + Register hypothetical_rsp = kScratchRegister; + __ movq(hypothetical_rsp, rsp); + __ subq(hypothetical_rsp, total_space); + __ cmpq(hypothetical_rsp, + __ StackLimitAsOperand(StackLimitKind::kRealStackLimit)); + __ j(below, &stack_overflow); + } + + // Allocate stack space for return values. + __ subq(rsp, result_size); + __ movq( + MemOperand( + new_wrapper_buffer, + JSToWasmWrapperFrameConstants::kWrapperBufferStackReturnBufferStart), + rsp); + Register call_target = rdi; __ LoadWasmCodePointer( call_target, MemOperand(wrapper_buffer, JSToWasmWrapperFrameConstants::kWrapperBufferCallTarget)); - Register last_stack_param = rcx; - - // The first GP parameter is the data, which we handle specially. - int stack_params_offset = - (arraysize(wasm::kGpParamRegisters) - 1) * kSystemPointerSize + - arraysize(wasm::kFpParamRegisters) * kDoubleSize; - + // Push stack parameters on the stack. + Register last_stack_param = rbx; __ leaq(last_stack_param, MemOperand(params_start, stack_params_offset)); Label loop_start; @@ -3767,10 +3836,6 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { } DCHECK_EQ(next_offset, stack_params_offset); - if (stack_switch) { - __ Move(MemOperand(rbp, WasmJspiFrameConstants::kGCScanSlotCountOffset), 0); - } - // We do the call without a signature check here, since the wrapper loaded the // signature from the same trusted object as the call target to set up the // stack layout. We could add a signature hash and pass it through to verify @@ -3836,6 +3901,20 @@ void JSToWasmWrapperHelper(MacroAssembler* masm, wasm::Promise mode) { if (mode == wasm::kPromise) { GenerateExceptionHandlingLandingPad(masm, &return_promise); } + + // OOL code for handling stack overflow. + __ bind(&stack_overflow); + if (stack_switch) { + __ movq(kContextRegister, + MemOperand(rbp, WasmJspiFrameConstants::kImplicitArgOffset)); + } else { + __ movq(kContextRegister, + MemOperand(rbp, JSToWasmWrapperFrameConstants::kImplicitArgOffset)); + } + GetContextFromImplicitArg(masm, kContextRegister); + __ AlignStackPointer(); + __ CallRuntime(Runtime::kThrowStackOverflow); + __ Trap(); } } // namespace @@ -3876,6 +3955,10 @@ void Builtins::Generate_WasmToJsWrapperAsm(MacroAssembler* masm) { } void Builtins::Generate_WasmTrapHandlerLandingPad(MacroAssembler* masm) { + // Push MessageTemplate::kNone as trap reason for WasmTrapHandlerThrowTrap; + // the runtime will determine the actual trap reason from the trapping + // instruction. + __ Push(Smi::FromInt(static_cast<int>(MessageTemplate::kNone))); __ addq( kWasmTrapHandlerFaultAddressRegister, Immediate(WasmFrameConstants::kTrappingInstructionReturnAddressOffset)); @@ -3913,9 +3996,8 @@ void Builtins::Generate_WasmSuspend(MacroAssembler* masm) { __ LoadProtectedPointerField( parent, FieldOperand(suspender, offsetof(WasmSuspenderObject, parent_))); Register target_stack = rcx; - __ LoadExternalPointerField( - target_stack, FieldOperand(parent, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag, kScratchRegister); + __ movq(target_stack, + FieldOperand(parent, offsetof(WasmSuspenderObject, stack_))); // Switch stacks. SwitchStacks(masm, ExternalReference::wasm_suspend_stack(), target_stack, @@ -3971,7 +4053,7 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { __ LoadTrustedPointerField( suspender, FieldOperand(resume_data, offsetof(WasmResumeData, trusted_suspender_)), - kWasmSuspenderIndirectPointerTag, kScratchRegister); + kWasmSuspenderTrustedPointerTag, kScratchRegister); closure = no_reg; sfi = no_reg; @@ -3986,10 +4068,8 @@ void Generate_WasmResumeHelper(MacroAssembler* masm, wasm::OnResume on_resume) { // Call the C function. // ------------------------------------------- Register target_stack = rbx; - __ LoadExternalPointerField( - target_stack, - FieldOperand(suspender, offsetof(WasmSuspenderObject, stack_)), - kWasmStackMemoryTag, kScratchRegister); + __ movq(target_stack, + FieldOperand(suspender, offsetof(WasmSuspenderObject, stack_))); SwitchStacks(masm, ExternalReference::wasm_resume_jspi_stack(), target_stack, &suspend, suspender, {target_stack}); suspender = no_reg; @@ -4545,6 +4625,7 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, __ PushReturnAddressFrom(rcx); } __ EnterSandbox(); + __ AssertFPCRState(); __ ret(0); // Handling of exception. @@ -4596,31 +4677,39 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { using ER = ExternalReference; Register frame_base = WasmHandleStackOverflowDescriptor::FrameBaseRegister(); Register gap = WasmHandleStackOverflowDescriptor::GapRegister(); + Register parameter_slots_size = + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(); { DCHECK_NE(kCArgRegs[1], frame_base); DCHECK_NE(kCArgRegs[3], frame_base); +#ifdef V8_TARGET_OS_WIN + Register old_fp = rdi; + Register params_size = rsi; + __ movq(old_fp, rbp); + __ movq(params_size, parameter_slots_size); __ movq(kCArgRegs[3], gap); __ movq(kCArgRegs[1], rsp); __ movq(kCArgRegs[2], frame_base); __ subq(kCArgRegs[2], kCArgRegs[1]); -#ifdef V8_TARGET_OS_WIN - Register old_fp = rcx; - // On windows we need preserve rbp value somewhere before entering - // INTERNAL frame later. It will be placed on the stack as an argument. - __ movq(old_fp, rbp); #else + __ movq(kCArgRegs[5], parameter_slots_size); + __ movq(kCArgRegs[3], gap); + __ movq(kCArgRegs[1], rsp); + __ movq(kCArgRegs[2], frame_base); + __ subq(kCArgRegs[2], kCArgRegs[1]); __ movq(kCArgRegs[4], rbp); #endif FrameScope scope(masm, StackFrame::INTERNAL); __ pushq(kCArgRegs[3]); - __ PrepareCallCFunction(5); + __ PrepareCallCFunction(6); // On windows put the arguments on the stack (PrepareCallCFunction // has created space for this). #ifdef V8_TARGET_OS_WIN __ movq(Operand(rsp, 4 * kSystemPointerSize), old_fp); + __ movq(Operand(rsp, 5 * kSystemPointerSize), params_size); #endif __ Move(kCArgRegs[0], ER::isolate_address()); - __ CallCFunction(ER::wasm_grow_stack(), 5); + __ CallCFunction(ER::wasm_grow_stack(), 6); __ popq(gap); DCHECK_NE(kReturnRegister0, gap); } @@ -4632,10 +4721,6 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ subq(rbp, rsp); __ addq(rbp, kReturnRegister0); __ movq(rsp, kReturnRegister0); - __ movq(kScratchRegister, - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - __ movq(MemOperand(rbp, TypedFrameConstants::kFrameTypeOffset), - kScratchRegister); __ ret(0); // If wasm_grow_stack returns zero, interruption or stack overflow @@ -4657,6 +4742,34 @@ void Builtins::Generate_WasmHandleStackOverflow(MacroAssembler* masm) { __ ret(0); } } + +void Builtins::Generate_WasmReturnFromSegment(MacroAssembler* masm) { + RegList gp_saves; + for (Register r : wasm::kGpReturnRegisters) gp_saves.set(r); + DoubleRegList fp_saves; + for (XMMRegister r : wasm::kFpReturnRegisters) fp_saves.set(r); + + __ PushAll(gp_saves); + __ PushAll(fp_saves, kSimd128Size); + + { + FrameScope scope(masm, StackFrame::MANUAL); + int saved_size = + gp_saves.Count() * kSystemPointerSize + fp_saves.Count() * kSimd128Size; + __ leaq(kCArgRegs[1], Operand(rsp, saved_size)); + __ PrepareCallCFunction(2); + __ LoadAddress(kCArgRegs[0], ExternalReference::isolate_address()); + __ CallCFunction(ExternalReference::wasm_shrink_stack(), 2); + } + __ movq(rbp, kReturnRegister0); + + __ PopAll(fp_saves, kSimd128Size); + __ PopAll(gp_saves); + + __ movq(rsp, rbp); + __ popq(rbp); + __ ret(0); +} #endif // V8_ENABLE_WEBASSEMBLY void Builtins::Generate_DoubleToI(MacroAssembler* masm) { @@ -5566,7 +5679,7 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( code_obj, FieldOperand(shared_function_info, offsetof(SharedFunctionInfo, trusted_function_data_)), - kCodeIndirectPointerTag, kScratchRegister); + kCodeTrustedPointerTag, kScratchRegister); // For OSR entry it is safe to assume we always have baseline code. if (v8_flags.debug_code) { @@ -5619,6 +5732,9 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( // Get bytecode array from the stack frame. __ movq(kInterpreterBytecodeArrayRegister, MemOperand(rbp, InterpreterFrameConstants::kBytecodeArrayFromFp)); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + __ pushq(kInterpreterAccumulatorRegister); + } __ pushq(kInterpreterAccumulatorRegister); { FrameScope scope(masm, StackFrame::INTERNAL); @@ -5631,6 +5747,9 @@ void Builtins::Generate_InterpreterOnStackReplacement_ToBaseline( __ LoadCodeInstructionStart(code_obj, code_obj, kJSEntrypointTag); __ addq(code_obj, kReturnRegister0); __ popq(kInterpreterAccumulatorRegister); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + __ popq(kInterpreterAccumulatorRegister); + } Generate_OSREntry(masm, code_obj); __ Trap(); // Unreachable. diff --git a/deps/v8/src/codegen/arm/macro-assembler-arm.cc b/deps/v8/src/codegen/arm/macro-assembler-arm.cc index a753eb6f5ee1..600c4f4c99ba 100644 --- a/deps/v8/src/codegen/arm/macro-assembler-arm.cc +++ b/deps/v8/src/codegen/arm/macro-assembler-arm.cc @@ -410,7 +410,7 @@ void MacroAssembler::JumpCodeObject(Register code_object, JumpMode jump_mode) { } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = r8; Register scratch = r9; diff --git a/deps/v8/src/codegen/arm/macro-assembler-arm.h b/deps/v8/src/codegen/arm/macro-assembler-arm.h index ab3048481cf2..ae8b931f3ac5 100644 --- a/deps/v8/src/codegen/arm/macro-assembler-arm.h +++ b/deps/v8/src/codegen/arm/macro-assembler-arm.h @@ -354,7 +354,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { JumpMode jump_mode = JumpMode::kJump); // Convenience functions to call/jmp to the code of a JSFunction object. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, diff --git a/deps/v8/src/codegen/arm64/assembler-arm64.cc b/deps/v8/src/codegen/arm64/assembler-arm64.cc index e3a6685ede1b..caa3f3236f81 100644 --- a/deps/v8/src/codegen/arm64/assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/assembler-arm64.cc @@ -60,6 +60,14 @@ CpuFeatureSet SimulatorFeaturesFromCommandLine() { } #endif // USE_SIMULATOR +#if defined(V8_HOST_ARCH_ARM64) && !defined(USE_SIMULATOR) && defined(__clang__) +__attribute__((target("sve"))) unsigned ReadSVEVectorLengthInBytes() { + // SVE vector length when all byte elements are used. + constexpr unsigned sv_all_bytes = 31; + return static_cast<unsigned>(__builtin_sve_svcntb_pat(sv_all_bytes)); +} +#endif + constexpr CpuFeatureSet CpuFeaturesFromCompiler() { CpuFeatureSet features; #if defined(__ARM_FEATURE_JCVT) && !defined(V8_TARGET_OS_IOS) @@ -94,8 +102,14 @@ constexpr CpuFeatureSet CpuFeaturesFromCompiler() { #if defined(__ARM_FEATURE_SVE) features.Add(SVE); #endif +#if defined(__ARM_FEATURE_SVE2) + features.Add(SVE2); +#endif #if defined(__ARM_FEATURE_SVE2_BITPERM) features.Add(SVEBITPERM); +#endif +#if defined(__ARM_FEATURE_RCPC) && __ARM_FEATURE_RCPC >= 2 + features.Add(LRCPC2); #endif return features; } @@ -109,6 +123,7 @@ constexpr CpuFeatureSet CpuFeaturesFromTargetOS() { features.Add(DOTPROD); features.Add(LSE); features.Add(PMULL1Q); + features.Add(LRCPC2); #endif return features; } @@ -125,6 +140,20 @@ bool CpuFeatures::SupportsSimd128() { #endif // V8_ENABLE_SIMD128 } +// TODO(whunt): simulate 256-bit vector registers. +unsigned CpuFeatures::svevlen() { +#ifdef USE_SIMULATOR + return kSimd128Size; +#elif defined(V8_HOST_ARCH_ARM64) && defined(__clang__) + if (!base::CPU::GetInstance().has_sve()) { + return 0; + } + return ReadSVEVectorLengthInBytes(); +#else + return 0; +#endif +} + void CpuFeatures::ProbeImpl(bool cross_compile) { // Only use statically determined features for cross compile (snapshot). if (cross_compile) { @@ -175,9 +204,15 @@ void CpuFeatures::ProbeImpl(bool cross_compile) { if (cpu.has_sve()) { runtime.Add(SVE); } + if (cpu.has_sve2()) { + runtime.Add(SVE2); + } if (cpu.has_svebitperm()) { runtime.Add(SVEBITPERM); } + if (cpu.has_lrcpc2()) { + runtime.Add(LRCPC2); + } // Use the best of the features found by CPU detection and those inferred from // the build system. @@ -1654,6 +1689,57 @@ void Assembler::stlxrh(const Register& rs, const Register& rt, Emit(STLXR_h | Rs(rs) | Rt2(x31) | RnSP(rn) | Rt(rt)); } +void Assembler::LoadStoreRCpcUnscaledOffset(const Register& rt, + const MemOperand& addr, + LoadStoreRCpcUnscaledOffsetOp op) { + DCHECK(IsEnabled(LRCPC2)); + DCHECK(addr.IsImmediateOffset()); + DCHECK(IsImmLSUnscaled(addr.offset())); + int offset = static_cast<int>(addr.offset()); + Emit(op | ImmLS(offset) | RnSP(addr.base()) | Rt(rt)); +} + +void Assembler::stlurb(const Register& rt, const MemOperand& dst) { + DCHECK(rt.Is32Bits()); + LoadStoreRCpcUnscaledOffset(rt, dst, STLURB); +} + +void Assembler::stlurh(const Register& rt, const MemOperand& dst) { + DCHECK(rt.Is32Bits()); + LoadStoreRCpcUnscaledOffset(rt, dst, STLURH); +} + +void Assembler::stlur(const Register& rt, const MemOperand& dst) { + LoadStoreRCpcUnscaledOffset(rt, dst, rt.Is64Bits() ? STLUR_x : STLUR_w); +} + +void Assembler::ldapurb(const Register& rt, const MemOperand& src) { + DCHECK(rt.Is32Bits()); + LoadStoreRCpcUnscaledOffset(rt, src, LDAPURB); +} + +void Assembler::ldapursb(const Register& rt, const MemOperand& src) { + LoadStoreRCpcUnscaledOffset(rt, src, rt.Is64Bits() ? LDAPURSB_x : LDAPURSB_w); +} + +void Assembler::ldapurh(const Register& rt, const MemOperand& src) { + DCHECK(rt.Is32Bits()); + LoadStoreRCpcUnscaledOffset(rt, src, LDAPURH); +} + +void Assembler::ldapursh(const Register& rt, const MemOperand& src) { + LoadStoreRCpcUnscaledOffset(rt, src, rt.Is64Bits() ? LDAPURSH_x : LDAPURSH_w); +} + +void Assembler::ldapur(const Register& rt, const MemOperand& src) { + LoadStoreRCpcUnscaledOffset(rt, src, rt.Is64Bits() ? LDAPUR_x : LDAPUR_w); +} + +void Assembler::ldapursw(const Register& rt, const MemOperand& src) { + DCHECK(rt.Is64Bits()); + LoadStoreRCpcUnscaledOffset(rt, src, LDAPURSW_x); +} + #define COMPARE_AND_SWAP_W_X_LIST(V) \ V(cas, CAS) \ V(casa, CASA) \ @@ -4433,6 +4519,13 @@ void Assembler::bext(const ZRegister& zd, const ZRegister& zn, Emit(BEXT | SVESize(zd) | Rm(zm) | Rn(zn) | Rd(zd)); } +void Assembler::mul(const ZRegister& zd, const ZRegister& zn, + const ZRegister& zm) { + DCHECK(IsEnabled(SVE2)); + DCHECK(AreSameLaneSize(zd, zn, zm)); + Emit(SVE2_MUL | SVESize(zd) | Rm(zm) | Rn(zn) | Rd(zd)); +} + bool Assembler::IsImmLSPair(int64_t offset, unsigned size) { bool offset_is_size_multiple = (static_cast<int64_t>(static_cast<uint64_t>(offset >> size) << size) == @@ -4756,7 +4849,8 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data, Handle<HeapObject> handle(reinterpret_cast<Address*>(data)); data = AddEmbeddedObject(handle); } - if (rmode == RelocInfo::COMPRESSED_EMBEDDED_OBJECT) { + if (rmode == RelocInfo::COMPRESSED_EMBEDDED_OBJECT || + rmode == RelocInfo::JS_DISPATCH_HANDLE) { if (constpool_.RecordEntry(static_cast<uint32_t>(data), rmode) == RelocInfoStatus::kMustOmitForDuplicate) { return; diff --git a/deps/v8/src/codegen/arm64/assembler-arm64.h b/deps/v8/src/codegen/arm64/assembler-arm64.h index 3d007d617e37..522aca873040 100644 --- a/deps/v8/src/codegen/arm64/assembler-arm64.h +++ b/deps/v8/src/codegen/arm64/assembler-arm64.h @@ -946,6 +946,33 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { // Store-release exclusive half-word. void stlxrh(const Register& rs, const Register& rt, const Register& rn); + // Store-release byte (unscaled offset) [Armv8.4]. + void stlurb(const Register& rt, const MemOperand& dst); + + // Store-release half-word (unscaled offset) [Armv8.4]. + void stlurh(const Register& rt, const MemOperand& dst); + + // Store-release word or doubleword (unscaled offset) [Armv8.4]. + void stlur(const Register& rt, const MemOperand& dst); + + // Load-acquire RCpc byte (unscaled offset) [Armv8.4]. + void ldapurb(const Register& rt, const MemOperand& src); + + // Load-acquire RCpc signed byte (unscaled offset) [Armv8.4]. + void ldapursb(const Register& rt, const MemOperand& src); + + // Load-acquire RCpc half-word (unscaled offset) [Armv8.4]. + void ldapurh(const Register& rt, const MemOperand& src); + + // Load-acquire RCpc signed half-word (unscaled offset) [Armv8.4]. + void ldapursh(const Register& rt, const MemOperand& src); + + // Load-acquire RCpc word or doubleword (unscaled offset) [Armv8.4]. + void ldapur(const Register& rt, const MemOperand& src); + + // Load-acquire RCpc signed word (unscaled offset) [Armv8.4]. + void ldapursw(const Register& rt, const MemOperand& src); + // Compare and Swap word or doubleword in memory [Armv8.1]. void cas(const Register& rs, const Register& rt, const MemOperand& src); @@ -2774,6 +2801,9 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { // Gather lower bits from positions selected by bitmask void bext(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm); + // Multiply (unpredicated). + void mul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm); + // Copy a string into the instruction stream, including the terminating // nullptr character. The instruction pointer (pc_) is then aligned correctly // for subsequent instructions. @@ -3212,6 +3242,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const; void LoadStore(const CPURegister& rt, const MemOperand& addr, LoadStoreOp op); + void LoadStoreRCpcUnscaledOffset(const Register& rt, const MemOperand& addr, + LoadStoreRCpcUnscaledOffsetOp op); inline void LoadStoreScaledImmOffset(Instr memop, int offset, unsigned size); inline void LoadStoreUnscaledImmOffset(Instr memop, int offset); inline void LoadStoreWRegOffset(Instr memop, const Register& regoffset); diff --git a/deps/v8/src/codegen/arm64/constant-pool-arm64.cc b/deps/v8/src/codegen/arm64/constant-pool-arm64.cc index 2028f8566973..37924aa3f45a 100644 --- a/deps/v8/src/codegen/arm64/constant-pool-arm64.cc +++ b/deps/v8/src/codegen/arm64/constant-pool-arm64.cc @@ -76,7 +76,8 @@ void ConstantPool::EmitAndClear(Jump require_jump) { // 1) Encode the size of the constant pool, for use by the disassembler. // 2) Terminate the program, to try to prevent execution from accidentally // flowing into the constant pool. - // 3) align the 64bit pool entries to 64-bit. + // 3) align the 64bit pool entries to 64-bit, with a 32-bit entry if there + // is one. // TODO(all): Make the alignment part less fragile. Currently code is // allocated as a byte array so there are no guarantees the alignment will // be preserved on compaction. Currently it works as allocation seems to be @@ -87,8 +88,7 @@ void ConstantPool::EmitAndClear(Jump require_jump) { assm_->RecordComment("[ Constant Pool"); EmitPrologue(require_alignment); - if (require_alignment == Alignment::kRequired) assm_->Align(kInt64Size); - EmitEntries(); + EmitEntries(require_alignment); assm_->RecordComment("]"); if (after_pool.is_linked()) assm_->bind(&after_pool); @@ -135,7 +135,25 @@ void ConstantPool::SetNextCheckIn(size_t instructions) { assm_->pc_offset() + static_cast<int>(instructions * kInstrSize); } -void ConstantPool::EmitEntries() { +void ConstantPool::EmitEntries(Alignment require_alignment) { + if (require_alignment == Alignment::kRequired) { + if (Entry32Count() == 0) { + assm_->Align(kInt64Size); + } else { + // 32-bit entries sort last, so put the last entry in the alignment gap + // instead of a nop. + auto last = std::prev(entries_.end()); + DCHECK(last->first.is_value32()); + auto first = last->first.AllowsDeduplication() + ? entries_.lower_bound(last->first) + : last; + for (auto it = first; it != entries_.end(); ++it) { + SetLoadOffsetToConstPoolEntry(it->second, assm_->pc(), it->first); + } + Emit(last->first); + entries_.erase(first, entries_.end()); + } + } for (auto iter = entries_.begin(); iter != entries_.end();) { DCHECK(iter->first.is_value32() || IsAligned(assm_->pc_offset(), 8)); auto range = entries_.equal_range(iter->first); @@ -174,10 +192,12 @@ bool ConstantPool::ShouldEmitNow(Jump require_jump, size_t margin) const { // (C) {dist32/64} exceeds the desired approximate distance to the pool. int worst_case_size = ComputeSize(Jump::kRequired, Alignment::kRequired); size_t pool_end_32 = assm_->pc_offset() + margin + worst_case_size; - size_t pool_end_64 = pool_end_32 - Entry32Count() * kInt32Size; + size_t pool_end_64 = + pool_end_32 - Entry32CountAfter64(Alignment::kRequired) * kInt32Size; if (Entry64Count() != 0) { - // The 64-bit constants are always emitted before the 32-bit constants, so - // we subtract the size of the 32-bit constants from {size}. + // The 64-bit constants are emitted before the 32-bit constants, except + // one that may fill the alignment gap, so we subtract the size of the + // 32-bit constants after them from {size}. size_t dist64 = pool_end_64 - first_use_64_; bool next_check_too_late = dist64 + 2 * kCheckInterval >= kMaxDistToPool64; bool opportune_emission_without_jump = @@ -205,12 +225,21 @@ bool ConstantPool::ShouldEmitNow(Jump require_jump, size_t margin) const { int ConstantPool::ComputeSize(Jump require_jump, Alignment require_alignment) const { int size_up_to_marker = PrologueSize(require_jump); + // The alignment gap holds a nop or a 32-bit entry. int alignment = require_alignment == Alignment::kRequired ? kInstrSize : 0; size_t size_after_marker = - Entry32Count() * kInt32Size + alignment + Entry64Count() * kInt64Size; + alignment + Entry64Count() * kInt64Size + + Entry32CountAfter64(require_alignment) * kInt32Size; return size_up_to_marker + static_cast<int>(size_after_marker); } +size_t ConstantPool::Entry32CountAfter64(Alignment require_alignment) const { + if (require_alignment == Alignment::kRequired && Entry32Count() != 0) { + return Entry32Count() - 1; + } + return Entry32Count(); +} + Alignment ConstantPool::IsAlignmentRequiredIfEmittedAt(Jump require_jump, int pc_offset) const { int size_up_to_marker = PrologueSize(require_jump); @@ -229,7 +258,8 @@ bool ConstantPool::IsInImmRangeIfEmittedAt(int pc_offset) { IsAlignmentRequiredIfEmittedAt(Jump::kRequired, pc_offset); size_t pool_end_32 = pc_offset + ComputeSize(Jump::kRequired, require_alignment); - size_t pool_end_64 = pool_end_32 - Entry32Count() * kInt32Size; + size_t pool_end_64 = + pool_end_32 - Entry32CountAfter64(require_alignment) * kInt32Size; bool entries_in_range_32 = Entry32Count() == 0 || (pool_end_32 < first_use_32_ + kMaxDistToPool32); bool entries_in_range_64 = diff --git a/deps/v8/src/codegen/arm64/constant-pool-arm64.h b/deps/v8/src/codegen/arm64/constant-pool-arm64.h index 62de4b5d2f50..21a5dfa58d84 100644 --- a/deps/v8/src/codegen/arm64/constant-pool-arm64.h +++ b/deps/v8/src/codegen/arm64/constant-pool-arm64.h @@ -55,7 +55,7 @@ class ConstantPoolKey { (is_value32() ? (value32() != 0) : (value64() != 0)); bool is_sharable_embedded_object = RelocInfo::IsEmbeddedObjectMode(rmode_); return RelocInfo::IsShareableRelocMode(rmode_) || is_sharable_code_target || - is_sharable_embedded_object; + is_sharable_embedded_object || RelocInfo::IsJSDispatchHandle(rmode_); } private: @@ -168,9 +168,10 @@ class ConstantPool { void StartBlock(); void EndBlock(); - void EmitEntries(); + void EmitEntries(Alignment require_alignment); void EmitPrologue(Alignment require_alignment); int PrologueSize(Jump require_jump) const; + size_t Entry32CountAfter64(Alignment require_alignment) const; RelocInfoStatus RecordKey(ConstantPoolKey key, int offset); RelocInfoStatus GetRelocInfoStatusFor(const ConstantPoolKey& key); void Emit(const ConstantPoolKey& key); diff --git a/deps/v8/src/codegen/arm64/constants-arm64.h b/deps/v8/src/codegen/arm64/constants-arm64.h index 641783193bb6..5f8d01f0e784 100644 --- a/deps/v8/src/codegen/arm64/constants-arm64.h +++ b/deps/v8/src/codegen/arm64/constants-arm64.h @@ -972,6 +972,41 @@ constexpr LoadStoreUnscaledOffsetOp LoadStoreUnscaledOffsetMask = 0xFFE00C00; LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED); #undef LOAD_STORE_UNSCALED +// Load-acquire/store-release unscaled offset [Armv8.4]. +using LoadStoreRCpcUnscaledOffsetOp = uint32_t; +constexpr LoadStoreRCpcUnscaledOffsetOp LoadStoreRCpcUnscaledOffsetFixed = + 0x19000000; +constexpr LoadStoreRCpcUnscaledOffsetOp LoadStoreRCpcUnscaledOffsetFMask = + 0x3F200C00; +constexpr LoadStoreRCpcUnscaledOffsetOp LoadStoreRCpcUnscaledOffsetMask = + 0xFFE00C00; +constexpr LoadStoreRCpcUnscaledOffsetOp STLURB = + LoadStoreRCpcUnscaledOffsetFixed | 0x00000000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURB = + LoadStoreRCpcUnscaledOffsetFixed | 0x00400000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURSB_x = + LoadStoreRCpcUnscaledOffsetFixed | 0x00800000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURSB_w = + LoadStoreRCpcUnscaledOffsetFixed | 0x00C00000; +constexpr LoadStoreRCpcUnscaledOffsetOp STLURH = + LoadStoreRCpcUnscaledOffsetFixed | 0x40000000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURH = + LoadStoreRCpcUnscaledOffsetFixed | 0x40400000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURSH_x = + LoadStoreRCpcUnscaledOffsetFixed | 0x40800000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURSH_w = + LoadStoreRCpcUnscaledOffsetFixed | 0x40C00000; +constexpr LoadStoreRCpcUnscaledOffsetOp STLUR_w = + LoadStoreRCpcUnscaledOffsetFixed | 0x80000000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPUR_w = + LoadStoreRCpcUnscaledOffsetFixed | 0x80400000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPURSW_x = + LoadStoreRCpcUnscaledOffsetFixed | 0x80800000; +constexpr LoadStoreRCpcUnscaledOffsetOp STLUR_x = + LoadStoreRCpcUnscaledOffsetFixed | 0xC0000000; +constexpr LoadStoreRCpcUnscaledOffsetOp LDAPUR_x = + LoadStoreRCpcUnscaledOffsetFixed | 0xC0400000; + // Load/store (post, pre, offset and unsigned.) using LoadStoreOp = uint32_t; constexpr LoadStoreOp LoadStoreMask = 0xC4C00000; @@ -2665,6 +2700,13 @@ constexpr SVEBitPermOp SVEBitPermFMask = 0xFF20F000; constexpr SVEBitPermOp SVEBitPermMask = 0xFF20FC00; constexpr SVEBitPermOp BEXT = SVEBitPermFixed; +// SVE2 multiply (unpredicated) instructions. +using SVE2MulOp = uint32_t; +constexpr SVE2MulOp SVE2MulFixed = 0x04206000; +constexpr SVE2MulOp SVE2MulFMask = 0xFF20F000; +constexpr SVE2MulOp SVE2MulMask = 0xFF20FC00; +constexpr SVE2MulOp SVE2_MUL = SVE2MulFixed; + // Unimplemented and unallocated instructions. These are defined to make fixed // bit assertion easier. using UnimplementedOp = uint32_t; diff --git a/deps/v8/src/codegen/arm64/decoder-arm64-inl.h b/deps/v8/src/codegen/arm64/decoder-arm64-inl.h index 2ed82d6a0fab..d02fed3597bf 100644 --- a/deps/v8/src/codegen/arm64/decoder-arm64-inl.h +++ b/deps/v8/src/codegen/arm64/decoder-arm64-inl.h @@ -17,7 +17,12 @@ void Decoder<V>::Decode(Instruction* instr) { if (instr->Bits(28, 27) == 0) { if (instr->Bits(31, 24) == 0x45 && instr->Bit(21) == 0 && instr->Bits(15, 12) == 0xB && instr->Bits(11, 10) != 3) { + // BEXP V::VisitSVEBitPerm(instr); + } else if (instr->Bits(31, 24) == 0x4 && instr->Bit(21) == 1 && + instr->Bits(15, 12) == 0x6 && instr->Bits(11, 10) == 0) { + // SVE2 Mul (no predicate). + V::VisitSVE2Mul(instr); } else { V::VisitUnallocated(instr); } @@ -349,6 +354,14 @@ void Decoder<V>::DecodeLoadStore(Instruction* instr) { } else if (instr->Mask(SetFMask) == SetFixed && instr->Bits(15, 14) != 0x3) { V::VisitSet(instr); + } else if (instr->Mask(LoadStoreRCpcUnscaledOffsetFMask) == + LoadStoreRCpcUnscaledOffsetFixed) { + if ((instr->Bits(31, 30) == 0x2 && instr->Bits(23, 22) == 0x3) || + (instr->Bits(31, 30) == 0x3 && instr->Bit(23) == 1)) { + V::VisitUnallocated(instr); + } else { + V::VisitLoadStoreRCpcUnscaledOffset(instr); + } } else { V::VisitUnallocated(instr); } diff --git a/deps/v8/src/codegen/arm64/decoder-arm64.h b/deps/v8/src/codegen/arm64/decoder-arm64.h index d31b701a5ccd..89992618e464 100644 --- a/deps/v8/src/codegen/arm64/decoder-arm64.h +++ b/deps/v8/src/codegen/arm64/decoder-arm64.h @@ -35,6 +35,7 @@ namespace internal { V(LoadStorePairPreIndex) \ V(LoadLiteral) \ V(LoadStoreUnscaledOffset) \ + V(LoadStoreRCpcUnscaledOffset) \ V(LoadStorePostIndex) \ V(LoadStorePreIndex) \ V(LoadStoreRegisterOffset) \ @@ -88,6 +89,7 @@ namespace internal { V(Cpy) \ V(Set) \ V(SVEBitPerm) \ + V(SVE2Mul) \ V(Unallocated) \ V(Unimplemented) diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h b/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h index 97ff415f2e8f..a1b28e860e29 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64-inl.h @@ -309,6 +309,14 @@ LSPAIR_MACRO_LIST(DEFINE_FUNCTION) LDA_STL_MACRO_LIST(DEFINE_FUNCTION) #undef DEFINE_FUNCTION +#define DEFINE_FUNCTION(FN, OP) \ + void MacroAssembler::FN(const Register& rt, const MemOperand& op) { \ + DCHECK(allow_macro_instructions()); \ + OP(rt, op); \ + } +LDA_STL_UNSCALED_MACRO_LIST(DEFINE_FUNCTION) +#undef DEFINE_FUNCTION + #define DEFINE_FUNCTION(FN, OP) \ void MacroAssembler::FN(const Register& rs, const Register& rt, \ const Register& rn) { \ diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc index a79bd6d3186d..5389162bec2a 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.cc @@ -1552,10 +1552,7 @@ void MacroAssembler::AssertSpAligned() { } void MacroAssembler::AssertFPCRState(Register fpcr) { - // TODO(olivf, 382005099) This check is currently behind `slow_debug_code` as - // a temporary hack to not have it enabled on dcheck enabled canaries. The - // reason is that this check is violated by callbacks from webaudio. - if (!v8_flags.slow_debug_code) return; + if (!v8_flags.debug_code) return; ASM_CODE_COMMENT(this); Label unexpected_mode, done; UseScratchRegisterScope temps(this); @@ -1566,8 +1563,7 @@ void MacroAssembler::AssertFPCRState(Register fpcr) { // Settings left to their default values: // - Assert that flush-to-zero is not set. - // TODO(leszeks): Reenable check based on isolate flag. - // Tbnz(fpcr, FZ_offset, &unexpected_mode); + Tbnz(fpcr, FZ_offset, &unexpected_mode); // - Assert that the rounding mode is nearest-with-ties-to-even. static_assert(FPTieEven == 0); Tst(fpcr, RMode_mask); @@ -2489,7 +2485,7 @@ void MacroAssembler::JumpCodeObject(Register code_object, CodeEntrypointTag tag, } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = kJavaScriptCallDispatchHandleRegister; Register parameter_count = x20; @@ -2499,12 +2495,26 @@ void MacroAssembler::CallJSFunction(Register function_object, FieldMemOperand(function_object, offsetof(JSFunction, dispatch_handle_))); LoadEntrypointAndParameterCountFromJSDispatchTable(code, parameter_count, dispatch_handle, scratch); - // Force a safe crash if the parameter count doesn't match. + // Force a safe crash if the parameter count doesn't match the expected count + // assumed at the call site, which would corrupt the stack on underapplication + // (caller pushes max(actual_argc, expected) slots; callee pops + // max(actual_argc, parameter_count) slots). // TODO(412398354): to avoid this runtime check, we should switch all // remaining users to call the function via its dispatch handle instead. See // CallJSDispatchEntry below and crbug.com/412398354 for more details. - Cmp(parameter_count, Immediate(argument_count)); - SbxCheck(le, AbortReason::kJSSignatureMismatch); + if (expected_parameter_count <= 1) { + // Both kDontAdaptArgumentsSentinel (0) and JSParameterCount(0) (1) are + // valid here: since actual_argc >= 1 (includes receiver), neither pads + // arguments and both pop actual_argc slots upon return. We cannot use an + // exact equality check because WasmToJS wrappers compute expected_arity + // via SFI::internal_formal_parameter_count_without_receiver(), which maps + // both cases to JSParameterCount(0) (1). + Cmp(parameter_count, Immediate(1)); + SbxCheck(le, AbortReason::kJSSignatureMismatch); + } else { + Cmp(parameter_count, Immediate(expected_parameter_count)); + SbxCheck(eq, AbortReason::kJSSignatureMismatch); + } Call(code); } @@ -2911,20 +2921,22 @@ void MacroAssembler::InvokeFunctionCode( // call sites. LoadEntrypointFromJSDispatchTable(kJavaScriptCallCodeStartRegister, dispatch_handle, scratch); + Label done; switch (type) { case InvokeType::kCall: Call(kJavaScriptCallCodeStartRegister); + B(&done); break; case InvokeType::kJump: // We jump through x17 here because for Branch Identification (BTI) we use // "Call" (`bti c`) rather than "Jump" (`bti j`) landing pads for // tail-called code. See TailCallBuiltin for more information. + // The tail jump does not return, so jumping to `done` here would be + // unreachable dead code. Mov(x17, kJavaScriptCallCodeStartRegister); Jump(x17); break; } - Label done; - B(&done); // Deferred debug hook. bind(&debug_hook); @@ -3583,15 +3595,102 @@ void MacroAssembler::StoreTaggedField(const Register& value, } } -void MacroAssembler::AtomicStoreTaggedField(const Register& value, - const Register& dst_base, - const Register& dst_index, - const Register& temp) { - Add(temp, dst_base, dst_index); +// Note: Ldar* is used for both acquire and seq-cst loads and therefore must +// emit RCsc `ldar*` rather than FEAT_LRCPC2 `ldapur*` (which only provides +// weaker RCpc acquire semantics and can be reordered before a preceding +// `stlr`/`stlur` to a different address). By contrast, Stlr* below can use +// FEAT_LRCPC2 `stlur*` unconditionally because both `stlr*` and `stlur*` +// provide full RCsc store-release semantics. +#define DEFINE_LDA_MEM_OP(FN, OP) \ + int MacroAssembler::FN(const Register& rt, const MemOperand& src) { \ + DCHECK(allow_macro_instructions()); \ + if (src.IsImmediateOffset() && src.offset() == 0) { \ + int pc_offset_of_load = pc_offset(); \ + OP(rt, src.base()); \ + return pc_offset_of_load; \ + } \ + UseScratchRegisterScope temps(this); \ + Register temp = temps.AcquireX(); \ + if (src.IsImmediateOffset()) { \ + int64_t offset = src.offset(); \ + if (IsImmAddSub(offset) || \ + (offset < 0 && offset != std::numeric_limits<int64_t>::min() && \ + IsImmAddSub(-offset))) { \ + Add(temp, src.base(), offset); \ + } else { \ + Mov(temp, offset); \ + Add(temp, src.base(), temp); \ + } \ + } else { \ + DCHECK(src.IsRegisterOffset()); \ + Operand offset_op = \ + (src.shift() != NO_SHIFT) \ + ? Operand(src.regoffset(), src.shift(), src.shift_amount()) \ + : Operand(src.regoffset(), src.extend(), src.shift_amount()); \ + Add(temp, src.base(), offset_op); \ + } \ + int pc_offset_of_load = pc_offset(); \ + OP(rt, temp); \ + return pc_offset_of_load; \ + } +DEFINE_LDA_MEM_OP(Ldarb, ldarb) +DEFINE_LDA_MEM_OP(Ldarh, ldarh) +DEFINE_LDA_MEM_OP(Ldar, ldar) +#undef DEFINE_LDA_MEM_OP + +#define DEFINE_STL_MEM_OP(FN, OP, UNSCALED_OP) \ + int MacroAssembler::FN(const Register& rt, const MemOperand& dst) { \ + DCHECK(allow_macro_instructions()); \ + if (dst.IsImmediateOffset()) { \ + int64_t offset = dst.offset(); \ + if (offset == 0) { \ + int pc_offset_of_store = pc_offset(); \ + OP(rt, dst.base()); \ + return pc_offset_of_store; \ + } \ + if (IsImmLSUnscaled(offset) && CpuFeatures::IsSupported(LRCPC2)) { \ + CpuFeatureScope scope(this, LRCPC2); \ + int pc_offset_of_store = pc_offset(); \ + UNSCALED_OP(rt, dst); \ + return pc_offset_of_store; \ + } \ + UseScratchRegisterScope temps(this); \ + Register temp = temps.AcquireX(); \ + if (IsImmAddSub(offset) || \ + (offset < 0 && offset != std::numeric_limits<int64_t>::min() && \ + IsImmAddSub(-offset))) { \ + Add(temp, dst.base(), offset); \ + } else { \ + Mov(temp, offset); \ + Add(temp, dst.base(), temp); \ + } \ + int pc_offset_of_store = pc_offset(); \ + OP(rt, temp); \ + return pc_offset_of_store; \ + } \ + DCHECK(dst.IsRegisterOffset()); \ + UseScratchRegisterScope temps(this); \ + Register temp = temps.AcquireX(); \ + Operand offset_op = \ + (dst.shift() != NO_SHIFT) \ + ? Operand(dst.regoffset(), dst.shift(), dst.shift_amount()) \ + : Operand(dst.regoffset(), dst.extend(), dst.shift_amount()); \ + Add(temp, dst.base(), offset_op); \ + int pc_offset_of_store = pc_offset(); \ + OP(rt, temp); \ + return pc_offset_of_store; \ + } +DEFINE_STL_MEM_OP(Stlrb, stlrb, stlurb) +DEFINE_STL_MEM_OP(Stlrh, stlrh, stlurh) +DEFINE_STL_MEM_OP(Stlr, stlr, stlur) +#undef DEFINE_STL_MEM_OP + +int MacroAssembler::AtomicStoreTaggedField( + const Register& value, const MemOperand& dst_field_operand) { if (COMPRESS_POINTERS_BOOL) { - Stlr(value.W(), temp); + return Stlr(value.W(), dst_field_operand); } else { - Stlr(value, temp); + return Stlr(value, dst_field_operand); } } @@ -3664,28 +3763,22 @@ void MacroAssembler::DecompressProtected(const Register& destination, #endif // V8_ENABLE_SANDBOX } -void MacroAssembler::AtomicDecompressTaggedSigned(const Register& destination, - const Register& base, - const Register& index, - const Register& temp) { +int MacroAssembler::AtomicDecompressTaggedSigned( + const Register& destination, const MemOperand& field_operand) { ASM_CODE_COMMENT(this); - Add(temp, base, index); - Ldar(destination.W(), temp); + int pc_offset_of_load = Ldar(destination.W(), field_operand); if (v8_flags.slow_debug_code) { // Corrupt the top 32 bits. Made up of 16 fixed bits and 16 pc offset bits. Add(destination, destination, ((kDebugZapValue << 16) | (pc_offset() & 0xffff)) << 32); } + return pc_offset_of_load; } int MacroAssembler::AtomicDecompressTagged(const Register& destination, - const Register& base, - const Register& index, - const Register& temp) { + const MemOperand& field_operand) { ASM_CODE_COMMENT(this); - Add(temp, base, index); - int pc_offset_of_load = pc_offset(); - Ldar(destination.W(), temp); + int pc_offset_of_load = Ldar(destination.W(), field_operand); Orr(destination, kPtrComprCageBaseRegister, destination); return pc_offset_of_load; } @@ -3920,9 +4013,14 @@ void MacroAssembler::LoadExternalPointerField(Register destination, void MacroAssembler::LoadTrustedPointerField(Register destination, MemOperand field_operand, - IndirectPointerTag tag) { + TrustedPointerTagRange tag_range) { #ifdef V8_ENABLE_SANDBOX - LoadIndirectPointerField(destination, field_operand, tag); + ASM_CODE_COMMENT(this); + UseScratchRegisterScope temps(this); + + Register handle = temps.AcquireX(); + Ldr(handle.W(), field_operand); + ResolveTrustedPointerHandle(destination, handle, tag_range); #else LoadTaggedField(destination, field_operand); #endif @@ -3945,10 +4043,10 @@ void MacroAssembler::LoadTrustedUnknownPointerField( Register handle = scratch; Ldr(handle.W(), field_operand); - static_assert(kNullIndirectPointerHandle == 0); + static_assert(kNullTrustedPointerHandle == 0); Cbz(handle, is_unavailable); - ResolveIndirectPointerHandle(destination, handle, kAllIndirectPointerTags); + ResolveTrustedPointerHandle(destination, handle, kAllTrustedPointerTags); } #else LoadTaggedField(destination, field_operand); @@ -3980,45 +4078,21 @@ void MacroAssembler::LoadTrustedUnknownPointerField( void MacroAssembler::StoreTrustedPointerField(Register value, MemOperand dst_field_operand) { -#ifdef V8_ENABLE_SANDBOX - StoreIndirectPointerField(value, dst_field_operand); -#else - StoreTaggedField(value, dst_field_operand); -#endif -} - -void MacroAssembler::LoadIndirectPointerField( - Register destination, MemOperand field_operand, - IndirectPointerTagRange tag_range) { -#ifdef V8_ENABLE_SANDBOX - ASM_CODE_COMMENT(this); - UseScratchRegisterScope temps(this); - - Register handle = temps.AcquireX(); - Ldr(handle.W(), field_operand); - ResolveIndirectPointerHandle(destination, handle, tag_range); -#else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX -} - -void MacroAssembler::StoreIndirectPointerField(Register value, - MemOperand dst_field_operand) { #ifdef V8_ENABLE_SANDBOX ASM_CODE_COMMENT(this); UseScratchRegisterScope temps(this); Register scratch = temps.AcquireX(); Ldr(scratch.W(), FieldMemOperand(value, offsetof(ExposedTrustedObject, - self_indirect_pointer_))); + self_trusted_pointer_))); Str(scratch.W(), dst_field_operand); #else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX + StoreTaggedField(value, dst_field_operand); +#endif } #ifdef V8_ENABLE_SANDBOX -void MacroAssembler::ResolveIndirectPointerHandle( - Register destination, Register handle, IndirectPointerTagRange tag_range) { +void MacroAssembler::ResolveTrustedPointerHandle( + Register destination, Register handle, TrustedPointerTagRange tag_range) { DCHECK(!AreAliased(handle, destination)); Register table = destination; @@ -4029,8 +4103,8 @@ void MacroAssembler::ResolveIndirectPointerHandle( Ldr(destination, MemOperand(table, handle, LSL, kTrustedPointerTableEntrySizeLog2)); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); And(destination, destination, Immediate(mask)); } else { Register tag_reg = handle; @@ -4174,22 +4248,21 @@ void MacroAssembler::CallEphemeronKeyBarrier(Register object, Operand offset, MaybeRestoreRegisters(registers); } -void MacroAssembler::CallIndirectPointerBarrier(Register object, Operand offset, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag) { +void MacroAssembler::CallTrustedPointerBarrier(Register object, Operand offset, + SaveFPRegsMode fp_mode, + TrustedPointerTag tag) { ASM_CODE_COMMENT(this); RegList registers = - IndirectPointerWriteBarrierDescriptor::ComputeSavedRegisters(object); + TrustedPointerWriteBarrierDescriptor::ComputeSavedRegisters(object); MaybeSaveRegisters(registers); - MoveObjectAndSlot( - IndirectPointerWriteBarrierDescriptor::ObjectRegister(), - IndirectPointerWriteBarrierDescriptor::SlotAddressRegister(), object, - offset); - Mov(IndirectPointerWriteBarrierDescriptor::IndirectPointerTagRegister(), + MoveObjectAndSlot(TrustedPointerWriteBarrierDescriptor::ObjectRegister(), + TrustedPointerWriteBarrierDescriptor::SlotAddressRegister(), + object, offset); + Mov(TrustedPointerWriteBarrierDescriptor::TrustedPointerTagRegister(), Operand(tag)); - CallBuiltin(Builtins::IndirectPointerBarrier(fp_mode)); + CallBuiltin(Builtins::TrustedPointerBarrier(fp_mode)); MaybeRestoreRegisters(registers); } @@ -4246,19 +4319,19 @@ void MacroAssembler::CallVerifySkippedWriteBarrierStub(Register object, SetIsolateDataSlots::kNo); } -void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStubSaveRegisters( +void MacroAssembler::CallVerifySkippedTrustedWriteBarrierStubSaveRegisters( Register object, Register value, SaveFPRegsMode fp_mode) { ASM_CODE_COMMENT(this); PushCallerSaved(fp_mode); - CallVerifySkippedIndirectWriteBarrierStub(object, value); + CallVerifySkippedTrustedWriteBarrierStub(object, value); PopCallerSaved(fp_mode); } -void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStub(Register object, - Register value) { +void MacroAssembler::CallVerifySkippedTrustedWriteBarrierStub(Register object, + Register value) { ASM_CODE_COMMENT(this); MovePair(kCArgRegs[0], object, kCArgRegs[1], value); - CallCFunction(ExternalReference::verify_skipped_indirect_write_barrier(), 2, + CallCFunction(ExternalReference::verify_skipped_trusted_write_barrier(), 2, SetIsolateDataSlots::kNo); } @@ -4314,9 +4387,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, Register temp = temps.AcquireX(); DCHECK(!AreAliased(object, value, temp)); Add(temp, object, offset); - if (slot.contains_indirect_pointer()) { - LoadIndirectPointerField(temp, MemOperand(temp), - slot.indirect_pointer_tag()); + if (slot.contains_trusted_pointer()) { + LoadTrustedPointerField(temp, MemOperand(temp), + slot.trusted_pointer_tag()); } else { DCHECK(slot.contains_direct_pointer()); LoadTaggedField(temp, MemOperand(temp)); @@ -4343,7 +4416,7 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, JumpIfSmi(value, &done); } - if (slot.contains_indirect_pointer()) { + if (slot.contains_trusted_pointer()) { // The indirect pointer write barrier is only enabled during marking. JumpIfNotMarking(&done); } else { @@ -4367,9 +4440,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, CallRecordWriteStub(object, slot_address, fp_mode, StubCallMode::kCallBuiltinPointer); } else { - DCHECK(slot.contains_indirect_pointer()); - CallIndirectPointerBarrier(object, offset, fp_mode, - slot.indirect_pointer_tag()); + DCHECK(slot.contains_trusted_pointer()); + CallTrustedPointerBarrier(object, offset, fp_mode, + slot.trusted_pointer_tag()); } if (lr_status == kLRHasNotBeenSaved) { Pop<MacroAssembler::kAuthLR>(lr, padreg); diff --git a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h index ec3b6eb71c02..e2a29b1edf13 100644 --- a/deps/v8/src/codegen/arm64/macro-assembler-arm64.h +++ b/deps/v8/src/codegen/arm64/macro-assembler-arm64.h @@ -66,6 +66,17 @@ class JumpTableAssembler; V(Stlrh, stlrh) \ V(Stlr, stlr) +#define LDA_STL_UNSCALED_MACRO_LIST(V) \ + V(Ldapurb, ldapurb) \ + V(Ldapursb, ldapursb) \ + V(Ldapurh, ldapurh) \ + V(Ldapursh, ldapursh) \ + V(Ldapur, ldapur) \ + V(Ldapursw, ldapursw) \ + V(Stlurb, stlurb) \ + V(Stlurh, stlurh) \ + V(Stlur, stlur) + #define STLX_MACRO_LIST(V) \ V(Stlxrb, stlxrb) \ V(Stlxrh, stlxrh) \ @@ -578,6 +589,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { bext(zd, zn, zm); } + void Mul(const ZRegister& zd, const ZRegister& zn, const ZRegister& zm) { + DCHECK(allow_macro_instructions()); + mul(zd, zn, zm); + } + // This is required for compatibility in architecture independent code. inline void jmp(Label* L); @@ -933,9 +949,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { void CallEphemeronKeyBarrier(Register object, Operand offset, SaveFPRegsMode fp_mode); - void CallIndirectPointerBarrier(Register object, Operand offset, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag); + void CallTrustedPointerBarrier(Register object, Operand offset, + SaveFPRegsMode fp_mode, TrustedPointerTag tag); void CallRecordWriteStubSaveRegisters( Register object, Operand offset, SaveFPRegsMode fp_mode, @@ -949,10 +964,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { SaveFPRegsMode fp_mode); void CallVerifySkippedWriteBarrierStub(Register object, Register value); - void CallVerifySkippedIndirectWriteBarrierStubSaveRegisters( + void CallVerifySkippedTrustedWriteBarrierStubSaveRegisters( Register object, Register value, SaveFPRegsMode fp_mode); - void CallVerifySkippedIndirectWriteBarrierStub(Register object, - Register value); + void CallVerifySkippedTrustedWriteBarrierStub(Register object, + Register value); // For a given |object| and |offset|: // - Move |object| to |dst_object|. @@ -1131,7 +1146,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { // validate the parameter count at runtime. Instead, we should replace them // with CallJSDispatchEntry that generates a call to a given (compile-time // constant) JSDispatchHandle. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, @@ -1481,6 +1497,22 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { LDA_STL_MACRO_LIST(DECLARE_FUNCTION) #undef DECLARE_FUNCTION +#define DECLARE_FUNCTION(FN, OP) \ + inline void FN(const Register& rt, const MemOperand& addr); + LDA_STL_UNSCALED_MACRO_LIST(DECLARE_FUNCTION) +#undef DECLARE_FUNCTION + + // Load-acquire/store-release macros with general MemOperand addressing. + // Because non-zero/non-LRCPC2 offsets emit address-calculation instructions + // before the memory access, these return the pc_offset() of the underlying + // load/store instruction itself for Wasm trap-handler registration. + int Ldarb(const Register& rt, const MemOperand& src); + int Ldarh(const Register& rt, const MemOperand& src); + int Ldar(const Register& rt, const MemOperand& src); + int Stlrb(const Register& rt, const MemOperand& dst); + int Stlrh(const Register& rt, const MemOperand& dst); + int Stlr(const Register& rt, const MemOperand& dst); + #define DECLARE_FUNCTION(FN, OP) \ inline void FN(const Register& rs, const Register& rt, const MemOperand& src); CAS_SINGLE_MACRO_LIST(DECLARE_FUNCTION) @@ -1618,8 +1650,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { StoreTaggedField(value, dst_field_operand); } - void AtomicStoreTaggedField(const Register& value, const Register& dst_base, - const Register& dst_index, const Register& temp); + // Returns the pc_offset() of the underlying atomic store instruction (after + // any address-calculation instructions) for Wasm trap-handler registration. + int AtomicStoreTaggedField(const Register& value, + const MemOperand& dst_field_operand); void DecompressTaggedSigned(const Register& destination, const MemOperand& field_operand); @@ -1630,12 +1664,12 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { void DecompressProtected(const Register& destination, const MemOperand& field_operand); - void AtomicDecompressTaggedSigned(const Register& destination, - const Register& base, const Register& index, - const Register& temp); - // Returns the pc offset of the atomic load instruction. - int AtomicDecompressTagged(const Register& destination, const Register& base, - const Register& index, const Register& temp); + // Return the pc_offset() of the underlying atomic load instruction (after + // any address-calculation instructions) for Wasm trap-handler registration. + int AtomicDecompressTaggedSigned(const Register& destination, + const MemOperand& field_operand); + int AtomicDecompressTagged(const Register& destination, + const MemOperand& field_operand); // Restore FP and LR from the values stored in the current frame. This will // authenticate the LR when pointer authentication is enabled. @@ -1675,8 +1709,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table. Otherwise they are regular tagged fields. void LoadTrustedPointerField(Register destination, MemOperand field_operand, - IndirectPointerTag tag); - // As above, but for kUnknownIndirectPointerTag. The type of the loaded object + TrustedPointerTagRange tag_range); + // As above, but for kUnknownTrustedPointerTag. The type of the loaded object // is unknown, so this helper will check for a series of expected types and // jump to the given labels if the loaded object has a matching type. If the // field is null (with enabled sandbox) or a Smi (with disabled sandbox) and @@ -1694,31 +1728,19 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { // Load a code pointer field. // These are special versions of trusted pointers that, when the sandbox is - // enabled, reference code objects through the code pointer table. + // enabled, reference code objects through the trusted pointer table. void LoadCodePointerField(Register destination, MemOperand field_operand) { - LoadTrustedPointerField(destination, field_operand, - kCodeIndirectPointerTag); + LoadTrustedPointerField(destination, field_operand, kCodeTrustedPointerTag); } // Store a code pointer field. void StoreCodePointerField(Register value, MemOperand dst_field_operand) { StoreTrustedPointerField(value, dst_field_operand); } - // Load an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void LoadIndirectPointerField(Register destination, MemOperand field_operand, - IndirectPointerTagRange tag_range); - - // Store an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void StoreIndirectPointerField(Register value, MemOperand dst_field_operand); - #ifdef V8_ENABLE_SANDBOX - // Retrieve the heap object referenced by the given indirect pointer handle. - void ResolveIndirectPointerHandle(Register destination, Register handle, - IndirectPointerTagRange tag_range); + // Retrieve the heap object referenced by the given trusted pointer handle. + void ResolveTrustedPointerHandle(Register destination, Register handle, + TrustedPointerTagRange tag_range); #endif void LoadEntrypointFromJSDispatchTable(Register destination, @@ -1992,19 +2014,29 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { inline void PushAll(DoubleRegList registers, int stack_slot_size = kDoubleSize) { - if (registers.Count() % 2 != 0) { - DCHECK(!registers.has(fp_zero)); - registers.set(fp_zero); + if (stack_slot_size == kSimd128Size) { + PushQRegList(registers); + } else { + DCHECK_EQ(stack_slot_size, kDoubleSize); + if (registers.Count() % 2 != 0) { + DCHECK(!registers.has(fp_zero)); + registers.set(fp_zero); + } + PushDRegList(registers); } - PushDRegList(registers); } inline void PopAll(DoubleRegList registers, int stack_slot_size = kDoubleSize) { - if (registers.Count() % 2 != 0) { - DCHECK(!registers.has(fp_zero)); - registers.set(fp_zero); + if (stack_slot_size == kSimd128Size) { + PopQRegList(registers); + } else { + DCHECK_EQ(stack_slot_size, kDoubleSize); + if (registers.Count() % 2 != 0) { + DCHECK(!registers.has(fp_zero)); + registers.set(fp_zero); + } + PopDRegList(registers); } - PopDRegList(registers); } // Push the specified register 'count' times. diff --git a/deps/v8/src/codegen/assembler.cc b/deps/v8/src/codegen/assembler.cc index 24865ac97823..9eeaa2e9d08f 100644 --- a/deps/v8/src/codegen/assembler.cc +++ b/deps/v8/src/codegen/assembler.cc @@ -40,7 +40,7 @@ #include <iomanip> #endif -#include "src/base/vector.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" #include "src/deoptimizer/deoptimizer.h" #include "src/diagnostics/disassembler.h" @@ -95,7 +95,7 @@ namespace { class DefaultAssemblerBuffer : public AssemblerBuffer { public: explicit DefaultAssemblerBuffer(int size) - : buffer_(base::OwnedVector<uint8_t>::NewForOverwrite( + : buffer_(base::UniqueArray<uint8_t>::NewForOverwrite( std::max(AssemblerBase::kMinimalBufferSize, size))) { #ifdef DEBUG ZapCode(reinterpret_cast<Address>(buffer_.begin()), buffer_.size()); @@ -112,7 +112,7 @@ class DefaultAssemblerBuffer : public AssemblerBuffer { } private: - base::OwnedVector<uint8_t> buffer_; + base::UniqueArray<uint8_t> buffer_; }; class ExternalAssemblerBufferImpl : public AssemblerBuffer { diff --git a/deps/v8/src/codegen/assembler.h b/deps/v8/src/codegen/assembler.h index 87e29895e6d1..f91d6f3e82d4 100644 --- a/deps/v8/src/codegen/assembler.h +++ b/deps/v8/src/codegen/assembler.h @@ -58,7 +58,7 @@ #include "src/flags/flags.h" #include "src/handles/handles.h" #include "src/objects/objects.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" #include "src/utils/ostreams.h" namespace v8 { @@ -281,48 +281,43 @@ class AssemblerBuffer { // Describes a HeapObject slot containing a pointer to another HeapObject. Such // a slot can either contain a direct/tagged pointer, or an indirect pointer // (i.e. an index into a pointer table, which then contains the actual pointer -// to the object) together with a specific IndirectPointerTag. +// to the object) together with a specific TrustedPointerTag. class SlotDescriptor { public: bool contains_direct_pointer() const { - return indirect_pointer_tag_ == kIndirectPointerNullTag; + return trusted_pointer_tag_ == kTrustedPointerNullTag; } - bool contains_indirect_pointer() const { - return indirect_pointer_tag_ != kIndirectPointerNullTag; + bool contains_trusted_pointer() const { + return trusted_pointer_tag_ != kTrustedPointerNullTag; } - IndirectPointerTag indirect_pointer_tag() const { - DCHECK(contains_indirect_pointer()); - return indirect_pointer_tag_; + TrustedPointerTag trusted_pointer_tag() const { + DCHECK(contains_trusted_pointer()); + return trusted_pointer_tag_; } static SlotDescriptor ForDirectPointerSlot() { - return SlotDescriptor(kIndirectPointerNullTag); + return SlotDescriptor(kTrustedPointerNullTag); } - static SlotDescriptor ForIndirectPointerSlot(IndirectPointerTag tag) { - return SlotDescriptor(tag); - } - - static SlotDescriptor ForTrustedPointerSlot(IndirectPointerTag tag) { + static SlotDescriptor ForTrustedPointerSlot(TrustedPointerTag tag) { #ifdef V8_ENABLE_SANDBOX - return ForIndirectPointerSlot(tag); + return SlotDescriptor(tag); #else return ForDirectPointerSlot(); #endif } static SlotDescriptor ForCodePointerSlot() { - return ForTrustedPointerSlot(kCodeIndirectPointerTag); + return ForTrustedPointerSlot(kCodeTrustedPointerTag); } private: - explicit SlotDescriptor(IndirectPointerTag tag) - : indirect_pointer_tag_(tag) {} + explicit SlotDescriptor(TrustedPointerTag tag) : trusted_pointer_tag_(tag) {} // If the tag is null, this object describes a direct pointer slot. - IndirectPointerTag indirect_pointer_tag_; + TrustedPointerTag trusted_pointer_tag_; }; // Allocate an AssemblerBuffer which uses an existing buffer. This buffer cannot diff --git a/deps/v8/src/codegen/bailout-reason.h b/deps/v8/src/codegen/bailout-reason.h index db2476fb8a0e..360d56e797ac 100644 --- a/deps/v8/src/codegen/bailout-reason.h +++ b/deps/v8/src/codegen/bailout-reason.h @@ -12,125 +12,124 @@ namespace v8 { namespace internal { -#define ABORT_MESSAGES_LIST(V) \ - V(kNoReason, "no reason") \ - \ - V(k32BitValueInRegisterIsNotZeroExtended, \ - "32 bit value in register is not zero-extended") \ - V(kSignBitOfSmiIsNotZero, "Sign bit of 31 bit smi register is not zero") \ - V(kAPICallReturnedInvalidObject, "API call returned invalid object") \ - V(kAccumulatorClobbered, "Accumulator clobbered") \ - V(kAllocatingNonEmptyPackedArray, "Allocating non-empty packed array") \ - V(kAllocationIsNotDoubleAligned, "Allocation is not double aligned") \ - V(kExpectedOptimizationSentinel, \ - "Expected optimized code cell or optimization sentinel") \ - V(kExpectedOsrCode, "Expected OSR code") \ - V(kExpectedUndefinedOrCell, "Expected undefined or cell in register") \ - V(kExpectedFeedbackCell, "Expected feedback cell") \ - V(kExpectedFeedbackVector, "Expected feedback vector") \ - V(kExpectedBaselineData, "Expected baseline data") \ - V(kFloat64IsNotAInt32, \ - "Float64 cannot be converted to Int32 without loss of precision") \ - V(kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, \ - "The function_data field should be a BytecodeArray on interpreter entry") \ - V(kInputStringTooLong, "Input string too long") \ - V(kInputDoesNotFitSmi, "Input number is too large to fit in a Smi") \ - V(kInvalidBytecode, "Invalid bytecode") \ - V(kInvalidBytecodeAdvance, "Cannot advance current bytecode, ") \ - V(kInvalidDeoptimizedCode, "Invoked code which is deoptimized") \ - V(kInvalidHandleScopeLevel, "Invalid HandleScope level") \ - V(kInvalidJumpTableIndex, "Invalid jump table index") \ - V(kInvalidParametersAndRegistersInGenerator, \ - "invalid parameters and registers in generator") \ - V(kMaglevGraphBuildingFailed, "Maglev optimized graph construction failed") \ - V(kMissingBytecodeArray, "Missing bytecode array from function") \ - V(kObjectNotTagged, "The object is not tagged") \ - V(kObjectTagged, "The object is tagged") \ - V(kOffsetOutOfRange, "Offset out of range") \ - V(kOperandIsASmi, "Operand is a smi") \ - V(kOperandIsASmiAndNotABoundFunction, \ - "Operand is a smi and not a bound function") \ - V(kOperandIsASmiAndNotAConstructor, \ - "Operand is a smi and not a constructor") \ - V(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function") \ - V(kOperandIsASmiAndNotAGeneratorObject, \ - "Operand is a smi and not a generator object") \ - V(kOperandIsCleared, "Operand is cleared") \ - V(kOperandIsNotABoundFunction, "Operand is not a bound function") \ - V(kOperandIsNotAConstructor, "Operand is not a constructor") \ - V(kOperandIsNotAFixedArray, "Operand is not a fixed array") \ - V(kOperandIsNotAFunction, "Operand is not a function") \ - V(kOperandIsNotACallableFunction, "Operand is not a callable function") \ - V(kOperandIsNotAGeneratorObject, "Operand is not a generator object") \ - V(kOperandIsNotACode, "Operand is not a Code object") \ - V(kOperandIsNotAMap, "Operand is not a Map object") \ - V(kOperandIsNotASmi, "Operand is not a smi") \ - V(kPromiseAlreadySettled, "Promise already settled") \ - V(kReceivedInvalidReturnAddress, "Received invalid return address") \ - V(kRegisterDidNotMatchExpectedRoot, "Register did not match expected root") \ - V(kReturnAddressNotFoundInFrame, "Return address not found in frame") \ - V(kShouldNotDirectlyEnterOsrFunction, \ - "Should not directly enter OSR-compiled function") \ - V(kStackAccessBelowStackPointer, "Stack access below stack pointer") \ - V(kOsrUnexpectedStackSize, "Unexpected stack size on OSR entry") \ - V(kStackFrameTypesMustMatch, "Stack frame types must match") \ - V(kUint32IsNotAInt32, \ - "Uint32 cannot be converted to Int32 without loss of precision") \ - V(kUnalignedCellInWriteBarrier, "Unaligned cell in write barrier") \ - V(kUnexpectedAdditionalPopValue, "Unexpected additional pop value") \ - V(kUnexpectedBigIntTerminationSentinel, \ - "Unexpected BigInt TerminationRequested sentinel") \ - V(kUnexpectedElementsKindInArrayConstructor, \ - "Unexpected ElementsKind in array constructor") \ - V(kUnexpectedFPCRMode, "Unexpected FPCR mode.") \ - V(kUnexpectedFunctionIDForInvokeIntrinsic, \ - "Unexpected runtime function id for the InvokeIntrinsic bytecode") \ - V(kUnexpectedInitialMapForArrayFunction, \ - "Unexpected initial map for Array function") \ - V(kUnexpectedLevelAfterReturnFromApiCall, \ - "Unexpected level after return from api call") \ - V(kUnexpectedNegativeValue, "Unexpected negative value") \ - V(kUnexpectedReturnFromFrameDropper, \ - "Unexpectedly returned from dropping frames") \ - V(kUnexpectedReturnFromThrow, "Unexpectedly returned from a throw") \ - V(kUnexpectedReturnFromWasmTrap, \ - "Should not return after throwing a wasm trap") \ - V(kUnexpectedStackPointer, "The stack pointer is not the expected value") \ - V(kUnexpectedValue, "Unexpected value") \ - V(kUninhabitableType, "Uninhabitable type") \ - V(kUnreachable, "Unreachable code") \ - V(kUnsupportedDeopt, \ - "Lazy deopt after a fast API call with return value is unsupported") \ - V(kUnsupportedModuleOperation, "Unsupported module operation") \ - V(kUnsupportedNonPrimitiveCompare, "Unsupported non-primitive compare") \ - V(kWrongAddressOrValuePassedToRecordWrite, \ - "Wrong address or value passed to RecordWrite") \ - V(kWrongArgumentCountForInvokeIntrinsic, \ - "Wrong number of arguments for intrinsic") \ - V(kWrongFunctionCodeStart, "Wrong value in code start register passed") \ - V(kWrongFunctionContext, "Wrong context passed to function") \ - V(kWrongFunctionDispatchHandle, \ - "Wrong value in dispatch handle register passed") \ - V(kInvalidReceiver, "Expected JS object or primitive object") \ - V(kUnexpectedInstanceType, "Unexpected instance type encountered") \ - V(kTurboshaftTypeAssertionFailed, \ - "A type assertion failed in Turboshaft-generated code") \ - V(kTurboshaftLoadEliminationError, \ - "Turboshaft's load elimination wrongly eliminated a Load") \ - V(kMetadataAreaStartDoesNotMatch, \ - "The metadata doesn't belong to the chunk") \ - V(kExternalPointerTagMismatch, \ - "Tag mismatch during external pointer access") \ - V(kIndirectPointerTagMismatch, \ - "Tag mismatch during indirect pointer access") \ - V(kJSSignatureMismatch, "Signature mismatch during JS function call") \ - V(kWasmSignatureMismatch, "Signature mismatch during Wasm indirect call") \ - V(kFastCallFallbackInvalid, "Fast call fallback returned incorrect type") \ - V(k32BitValueInRegisterIsNotSignExtended, \ - "32 bit value in register is not sign-extended") \ - V(kUnexpectedSandboxMode, "The sandboxing mode is not as expected") \ - IF_TARGET_ARCH_X64(V, kOSREmptyCheckFailed, \ - "OSR target slot should be empty") \ +#define ABORT_MESSAGES_LIST(V) \ + V(kNoReason, "no reason") \ + \ + V(k32BitValueInRegisterIsNotZeroExtended, \ + "32 bit value in register is not zero-extended") \ + V(kSignBitOfSmiIsNotZero, "Sign bit of 31 bit smi register is not zero") \ + V(kAPICallReturnedInvalidObject, "API call returned invalid object") \ + V(kAccumulatorClobbered, "Accumulator clobbered") \ + V(kAllocatingNonEmptyPackedArray, "Allocating non-empty packed array") \ + V(kAllocationIsNotDoubleAligned, "Allocation is not double aligned") \ + V(kExpectedOptimizationSentinel, \ + "Expected optimized code cell or optimization sentinel") \ + V(kExpectedOsrCode, "Expected OSR code") \ + V(kExpectedUndefinedOrCell, "Expected undefined or cell in register") \ + V(kExpectedFeedbackCell, "Expected feedback cell") \ + V(kExpectedFeedbackVector, "Expected feedback vector") \ + V(kExpectedBaselineData, "Expected baseline data") \ + V(kFloat64IsNotAInt32, \ + "Float64 cannot be converted to Int32 without loss of precision") \ + V(kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry, \ + "The function_data field should be a BytecodeArray on interpreter entry") \ + V(kInputStringTooLong, "Input string too long") \ + V(kInputDoesNotFitSmi, "Input number is too large to fit in a Smi") \ + V(kInvalidBytecode, "Invalid bytecode") \ + V(kInvalidBytecodeAdvance, "Cannot advance current bytecode, ") \ + V(kInvalidDeoptimizedCode, "Invoked code which is deoptimized") \ + V(kInvalidHandleScopeLevel, "Invalid HandleScope level") \ + V(kInvalidJumpTableIndex, "Invalid jump table index") \ + V(kInvalidParametersAndRegistersInGenerator, \ + "invalid parameters and registers in generator") \ + V(kMaglevGraphBuildingFailed, "Maglev optimized graph construction failed") \ + V(kMissingBytecodeArray, "Missing bytecode array from function") \ + V(kObjectNotTagged, "The object is not tagged") \ + V(kObjectTagged, "The object is tagged") \ + V(kOffsetOutOfRange, "Offset out of range") \ + V(kOperandIsASmi, "Operand is a smi") \ + V(kOperandIsASmiAndNotABoundFunction, \ + "Operand is a smi and not a bound function") \ + V(kOperandIsASmiAndNotAConstructor, \ + "Operand is a smi and not a constructor") \ + V(kOperandIsASmiAndNotAFunction, "Operand is a smi and not a function") \ + V(kOperandIsASmiAndNotAGeneratorObject, \ + "Operand is a smi and not a generator object") \ + V(kOperandIsCleared, "Operand is cleared") \ + V(kOperandIsNotABoundFunction, "Operand is not a bound function") \ + V(kOperandIsNotAConstructor, "Operand is not a constructor") \ + V(kOperandIsNotAFixedArray, "Operand is not a fixed array") \ + V(kOperandIsNotAFunction, "Operand is not a function") \ + V(kOperandIsNotACallableFunction, "Operand is not a callable function") \ + V(kOperandIsNotAGeneratorObject, "Operand is not a generator object") \ + V(kOperandIsNotACode, "Operand is not a Code object") \ + V(kOperandIsNotAMap, "Operand is not a Map object") \ + V(kOperandIsNotASmi, "Operand is not a smi") \ + V(kPromiseAlreadySettled, "Promise already settled") \ + V(kReceivedInvalidReturnAddress, "Received invalid return address") \ + V(kRegisterDidNotMatchExpectedRoot, "Register did not match expected root") \ + V(kReturnAddressNotFoundInFrame, "Return address not found in frame") \ + V(kShouldNotDirectlyEnterOsrFunction, \ + "Should not directly enter OSR-compiled function") \ + V(kStackAccessBelowStackPointer, "Stack access below stack pointer") \ + V(kOsrUnexpectedStackSize, "Unexpected stack size on OSR entry") \ + V(kStackFrameTypesMustMatch, "Stack frame types must match") \ + V(kUint32IsNotAInt32, \ + "Uint32 cannot be converted to Int32 without loss of precision") \ + V(kUnalignedCellInWriteBarrier, "Unaligned cell in write barrier") \ + V(kUnexpectedAdditionalPopValue, "Unexpected additional pop value") \ + V(kUnexpectedBigIntTerminationSentinel, \ + "Unexpected BigInt TerminationRequested sentinel") \ + V(kUnexpectedElementsKindInArrayConstructor, \ + "Unexpected ElementsKind in array constructor") \ + V(kUnexpectedFPCRMode, "Unexpected FPCR mode.") \ + V(kUnexpectedFunctionIDForInvokeIntrinsic, \ + "Unexpected runtime function id for the InvokeIntrinsic bytecode") \ + V(kUnexpectedInitialMapForArrayFunction, \ + "Unexpected initial map for Array function") \ + V(kUnexpectedLevelAfterReturnFromApiCall, \ + "Unexpected level after return from api call") \ + V(kUnexpectedNegativeValue, "Unexpected negative value") \ + V(kUnexpectedReturnFromFrameDropper, \ + "Unexpectedly returned from dropping frames") \ + V(kUnexpectedReturnFromThrow, "Unexpectedly returned from a throw") \ + V(kUnexpectedReturnFromWasmTrap, \ + "Should not return after throwing a wasm trap") \ + V(kUnexpectedStackPointer, "The stack pointer is not the expected value") \ + V(kUnexpectedValue, "Unexpected value") \ + V(kUninhabitableType, "Uninhabitable type") \ + V(kUnreachable, "Unreachable code") \ + V(kUnsupportedDeopt, \ + "Lazy deopt after a fast API call with return value is unsupported") \ + V(kUnsupportedModuleOperation, "Unsupported module operation") \ + V(kUnsupportedNonPrimitiveCompare, "Unsupported non-primitive compare") \ + V(kWrongAddressOrValuePassedToRecordWrite, \ + "Wrong address or value passed to RecordWrite") \ + V(kWrongArgumentCountForInvokeIntrinsic, \ + "Wrong number of arguments for intrinsic") \ + V(kWrongFunctionCodeStart, "Wrong value in code start register passed") \ + V(kWrongFunctionContext, "Wrong context passed to function") \ + V(kWrongFunctionDispatchHandle, \ + "Wrong value in dispatch handle register passed") \ + V(kInvalidReceiver, "Expected JS object or primitive object") \ + V(kUnexpectedInstanceType, "Unexpected instance type encountered") \ + V(kTurboshaftTypeAssertionFailed, \ + "A type assertion failed in Turboshaft-generated code") \ + V(kTurboshaftLoadEliminationError, \ + "Turboshaft's load elimination wrongly eliminated a Load") \ + V(kMetadataAreaStartDoesNotMatch, \ + "The metadata doesn't belong to the chunk") \ + V(kExternalPointerTagMismatch, \ + "Tag mismatch during external pointer access") \ + V(kTrustedPointerTagMismatch, "Tag mismatch during indirect pointer access") \ + V(kJSSignatureMismatch, "Signature mismatch during JS function call") \ + V(kWasmSignatureMismatch, "Signature mismatch during Wasm indirect call") \ + V(kFastCallFallbackInvalid, "Fast call fallback returned incorrect type") \ + V(k32BitValueInRegisterIsNotSignExtended, \ + "32 bit value in register is not sign-extended") \ + V(kUnexpectedSandboxMode, "The sandboxing mode is not as expected") \ + IF_TARGET_ARCH_X64(V, kOSREmptyCheckFailed, \ + "OSR target slot should be empty") \ V(kLastReason, "") #define TERMINAL_BAILOUT_MESSAGES_LIST(V) \ diff --git a/deps/v8/src/codegen/code-factory.cc b/deps/v8/src/codegen/code-factory.cc index 606d885b42bf..d32820ce6731 100644 --- a/deps/v8/src/codegen/code-factory.cc +++ b/deps/v8/src/codegen/code-factory.cc @@ -148,10 +148,12 @@ Callable CodeFactory::ArrayNoArgumentConstructor( isolate, \ Builtin::kArrayNoArgumentConstructor_##kind_camel##_##mode_camel); if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { - DCHECK(IsSmiElementsKind(kind)); switch (kind) { CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); + CASE(PACKED_ELEMENTS, Packed, DontOverride); + CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DontOverride); + CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DontOverride); default: UNREACHABLE(); } @@ -182,10 +184,12 @@ Callable CodeFactory::ArraySingleArgumentConstructor( isolate, \ Builtin::kArraySingleArgumentConstructor_##kind_camel##_##mode_camel) if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { - DCHECK(IsSmiElementsKind(kind)); switch (kind) { CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); + CASE(PACKED_ELEMENTS, Packed, DontOverride); + CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DontOverride); + CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DontOverride); default: UNREACHABLE(); } diff --git a/deps/v8/src/codegen/code-stub-assembler-inl.h b/deps/v8/src/codegen/code-stub-assembler-inl.h index 994e692f84f3..4d1066b0dc23 100644 --- a/deps/v8/src/codegen/code-stub-assembler-inl.h +++ b/deps/v8/src/codegen/code-stub-assembler-inl.h @@ -244,14 +244,14 @@ TNode<Object> CodeStubAssembler::FastCloneJSObject( return target; } -template <IndirectPointerTagRange tag_range> +template <TrustedPointerTagRange tag_range> inline TNode<TrustedTypeFor<tag_range>> CodeStubAssembler::LoadTrustedPointerFromObject(TNode<HeapObject> object, int field_offset) { using T = TrustedTypeFor<tag_range>; #ifdef V8_ENABLE_SANDBOX return TrustedCast<T>( - LoadIndirectPointerFromObject(object, field_offset, tag_range), + LoadTrustedPointerFromObject(object, field_offset, tag_range), "type tagged handle"); #else return TrustedCast<T>(LoadObjectField<Object>(object, field_offset), @@ -264,7 +264,7 @@ CodeStubAssembler::LoadTrustedPointerFromObject(TNode<HeapObject> object, TNode<WasmInternalFunction> CodeStubAssembler::LoadWasmInternalFunctionFromFuncRef( TNode<WasmFuncRef> func_ref) { - return LoadTrustedPointerFromObject<kWasmInternalFunctionIndirectPointerTag>( + return LoadTrustedPointerFromObject<kWasmInternalFunctionTrustedPointerTag>( func_ref, offsetof(WasmFuncRef, trusted_internal_)); } diff --git a/deps/v8/src/codegen/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc index 180facb5121a..b535dd1c9e43 100644 --- a/deps/v8/src/codegen/code-stub-assembler.cc +++ b/deps/v8/src/codegen/code-stub-assembler.cc @@ -6,6 +6,7 @@ #include <stdio.h> +#include <array> #include <functional> #include <optional> @@ -222,7 +223,7 @@ void CodeStubAssembler::FailAssert( const char* message, const std::vector<FileAndLine>& files_and_lines, std::initializer_list<ExtraNode> extra_nodes) { DCHECK_NOT_NULL(message); - base::EmbeddedVector<char, 1024> chars; + std::array<char, 1024> chars; std::stringstream stream; for (const auto& [file, line] : base::Reversed(files_and_lines)) { if (file != nullptr) { @@ -236,8 +237,8 @@ void CodeStubAssembler::FailAssert( } std::string files_and_lines_text = stream.str(); if (!files_and_lines_text.empty()) { - SNPrintF(chars, "%s%s", message, files_and_lines_text.c_str()); - message = chars.begin(); + base::SNPrintF(chars, "%s%s", message, files_and_lines_text.c_str()); + message = chars.data(); } TNode<String> message_node = StringConstant(message); @@ -1562,6 +1563,7 @@ void CodeStubAssembler::BranchIfFastIterableToListInterceptor( TNode<JSAnyNotSmi> iterable, Label* if_true, Label* if_false) { TNode<Map> map = LoadMap(iterable); GotoIfNot(HasIndexedInterceptor(map), if_false); + GotoIf(IsArrayIteratorProtectorCellInvalid(), if_false); CSA_DCHECK(this, IsJSInterceptorMap(map)); @@ -1734,8 +1736,8 @@ TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes, CSA_DCHECK(this, IsMarked(result.value())); } if (v8_flags.verify_write_barriers) { - TNode<ExternalReference> last_young_allocation_address = ExternalConstant( - ExternalReference::last_young_allocation_address(isolate())); + TNode<ExternalReference> last_young_allocation_address = + IsolateField(IsolateFieldId::kLastYoungAllocation); if (flags & AllocationFlag::kPretenured) { StoreNoWriteBarrier(MachineType::PointerRepresentation(), @@ -2008,14 +2010,12 @@ void CodeStubAssembler::StoreBoundedSizeToObject(TNode<HeapObject> object, TNode<RawPtrT> CodeStubAssembler::ExternalPointerTableAddress( ExternalPointerTagRange tag_range) { if (IsSharedExternalPointerType(tag_range)) { - TNode<ExternalReference> table_address_address = ExternalConstant( - ExternalReference::shared_external_pointer_table_address_address( - isolate())); + TNode<ExternalReference> table_address_address = + IsolateField(IsolateFieldId::kSharedExternalPointerTable); return UncheckedCast<RawPtrT>( Load(MachineType::Pointer(), table_address_address)); } - return ExternalConstant( - ExternalReference::external_pointer_table_address(isolate())); + return IsolateField(IsolateFieldId::kExternalPointerTable); } #endif // V8_ENABLE_SANDBOX @@ -2050,9 +2050,9 @@ TNode<RawPtrT> CodeStubAssembler::LoadExternalPointerFromObject( if (tag_range.Size() == 1) { // The common and simple case: we expect exactly one tag. TNode<IntPtrT> tag_bits = UncheckedCast<IntPtrT>( - WordAnd(entry, UintPtrConstant(kExternalPointerTagMask))); + WordAnd(entry, UniqueUintPtrConstant(kExternalPointerTagMask))); tag_bits = UncheckedCast<IntPtrT>( - WordShr(tag_bits, UintPtrConstant(kExternalPointerTagShift))); + WordShr(tag_bits, UniqueUintPtrConstant(kExternalPointerTagShift))); TNode<Uint32T> tag = UncheckedCast<Uint32T>(TruncateIntPtrToInt32(tag_bits)); TNode<Uint32T> expected_tag = Uint32Constant(tag_range.first); @@ -2063,7 +2063,7 @@ TNode<RawPtrT> CodeStubAssembler::LoadExternalPointerFromObject( UNREACHABLE(); } return UncheckedCast<IntPtrT>( - WordAnd(entry, UintPtrConstant(kExternalPointerPayloadMask))); + WordAnd(entry, UniqueUintPtrConstant(kExternalPointerPayloadMask))); #else return LoadObjectField<RawPtrT>(object, offset); #endif // V8_ENABLE_SANDBOX @@ -2093,8 +2093,8 @@ void CodeStubAssembler::StoreExternalPointerToObject(TNode<HeapObject> object, TNode<UintPtrT> value = UncheckedCast<UintPtrT>(pointer); value = UncheckedCast<UintPtrT>(WordOr( - value, UintPtrConstant((uint64_t{tag} << kExternalPointerTagShift) | - kExternalPointerMarkBit))); + value, UniqueUintPtrConstant((uint64_t{tag} << kExternalPointerTagShift) | + kExternalPointerMarkBit))); StoreNoWriteBarrier(MachineType::PointerRepresentation(), table, table_offset, value); #else @@ -2146,20 +2146,20 @@ void CodeStubAssembler::LoadTrustedUnknownPointerFromObject( TNode<HeapObject> object, int offset, TVariable<Object>* value_out, Label* if_empty, Label* if_default, const std::initializer_list<std::pair<InstanceType, Label*>>& cases, - IndirectPointerTagRange tag_range) { + TrustedPointerTagRange tag_range) { Label unreachable(this, Label::kDeferred); if (!if_default) if_default = &unreachable; if (!if_empty) if_empty = &unreachable; #ifdef V8_ENABLE_SANDBOX - TNode<IndirectPointerHandleT> handle = - LoadObjectField<IndirectPointerHandleT>(object, offset); + TNode<TrustedPointerHandleT> handle = + LoadObjectField<TrustedPointerHandleT>(object, offset); - GotoIf(Word32Equal(handle, Int32Constant(kNullIndirectPointerHandle)), + GotoIf(Word32Equal(handle, Int32Constant(kNullTrustedPointerHandle)), if_empty); - ResolveIndirectUnknownPointerHandle(handle, value_out, /* type_out */ nullptr, - if_default, cases, tag_range); + ResolveTrustedUnknownPointerHandle(handle, value_out, /* type_out */ nullptr, + if_default, cases, tag_range); #else *value_out = LoadObjectField<Object>(object, offset); GotoIf(TaggedIsSmi(value_out->value()), if_empty); @@ -2174,20 +2174,20 @@ void CodeStubAssembler::LoadTrustedUnknownPointerFromObject( } #ifdef V8_ENABLE_SANDBOX -void CodeStubAssembler::ResolveIndirectUnknownPointerHandle( - TNode<IndirectPointerHandleT> handle, TVariable<Object>* value_out, +void CodeStubAssembler::ResolveTrustedUnknownPointerHandle( + TNode<TrustedPointerHandleT> handle, TVariable<Object>* value_out, TVariable<Uint16T>* type_out, Label* if_default, const std::initializer_list<std::pair<InstanceType, Label*>>& cases, - IndirectPointerTagRange tag_range) { - *value_out = ResolveIndirectPointerHandle(handle, tag_range); + TrustedPointerTagRange tag_range) { + *value_out = ResolveTrustedPointerHandle(handle, tag_range); DispatchOnInstanceType(value_out->value(), type_out, if_default, cases); } #endif // V8_ENABLE_SANDBOX TNode<Code> CodeStubAssembler::LoadCodePointerFromObject( TNode<HeapObject> object, int field_offset) { - return LoadTrustedPointerFromObject<kCodeIndirectPointerTag>(object, - field_offset); + return LoadTrustedPointerFromObject<kCodeTrustedPointerTag>(object, + field_offset); } @@ -2199,7 +2199,7 @@ TNode<UintPtrT> CodeStubAssembler::ComputeJSDispatchTableEntryOffset( // to be sure that the offset will always fit into a 32-bit integer. static_assert(kJSDispatchTableReservationSize <= 4ULL * GB); TNode<UintPtrT> offset = ChangeUint32ToWord( - Word32Shl(index, Uint32Constant(kJSDispatchTableEntrySizeLog2))); + Word32Shl(index, UniqueUint32Constant(kJSDispatchTableEntrySizeLog2))); return offset; } @@ -2216,22 +2216,13 @@ TNode<Code> CodeStubAssembler::LoadCodeObjectFromJSDispatchTable( TNode<UintPtrT> shifted_value; if (JSDispatchEntry::kObjectPointerOffset == 0) { - shifted_value = -#if defined(__illumos__) && defined(V8_HOST_ARCH_64_BIT) - // Pointers in illumos span both the low 2^47 range and the high 2^47 - // range as well. Checking the high bit being set in illumos means all - // higher bits need to be set to 1 after shifting right. Use WordSar() - // so any high-bit check wouldn't be necessary. - UncheckedCast<UintPtrT>( - WordSar(UncheckedCast<IntPtrT>(value), - IntPtrConstant(JSDispatchEntry::kObjectPointerShift))); -#else - WordShr(value, UintPtrConstant(JSDispatchEntry::kObjectPointerShift)); -#endif /* __illumos__ and 64-bit */ + shifted_value = WordShr( + value, UniqueUintPtrConstant(JSDispatchEntry::kObjectPointerShift)); } else { shifted_value = UintPtrAdd( - WordShr(value, UintPtrConstant(JSDispatchEntry::kObjectPointerShift)), - UintPtrConstant(JSDispatchEntry::kObjectPointerOffset)); + WordShr(value, + UniqueUintPtrConstant(JSDispatchEntry::kObjectPointerShift)), + UniqueUintPtrConstant(JSDispatchEntry::kObjectPointerOffset)); } value = UncheckedCast<UintPtrT>( @@ -2244,8 +2235,8 @@ TNode<Uint16T> CodeStubAssembler::LoadParameterCountFromJSDispatchTable( TNode<RawPtrT> table = ExternalConstant(ExternalReference::js_dispatch_table_address(isolate())); TNode<UintPtrT> offset = ComputeJSDispatchTableEntryOffset(handle); - offset = UintPtrAdd(offset, - UintPtrConstant(JSDispatchEntry::kParameterCountOffset)); + offset = UintPtrAdd( + offset, UniqueUintPtrConstant(JSDispatchEntry::kParameterCountOffset)); static_assert(JSDispatchEntry::kParameterCountSize == 2); return Load<Uint16T>(table, offset); } @@ -2300,18 +2291,21 @@ void CodeStubAssembler::TailCallJSCode( #ifdef V8_ENABLE_SANDBOX -TNode<TrustedObject> CodeStubAssembler::LoadIndirectPointerFromObject( +TNode<TrustedObject> CodeStubAssembler::LoadTrustedPointerFromObject( TNode<HeapObject> object, int field_offset, - IndirectPointerTagRange tag_range) { - TNode<IndirectPointerHandleT> handle = - LoadObjectField<IndirectPointerHandleT>(object, field_offset); - return ResolveIndirectPointerHandle(handle, tag_range); -} - -TNode<TrustedObject> CodeStubAssembler::ResolveIndirectPointerHandle( - TNode<IndirectPointerHandleT> handle, IndirectPointerTagRange tag_range) { - TNode<RawPtrT> table = ExternalConstant( - ExternalReference::trusted_pointer_table_base_address(isolate())); + TrustedPointerTagRange tag_range) { + TNode<TrustedPointerHandleT> handle = + LoadObjectField<TrustedPointerHandleT>(object, field_offset); + return ResolveTrustedPointerHandle(handle, tag_range); +} + +TNode<TrustedObject> CodeStubAssembler::ResolveTrustedPointerHandle( + TNode<TrustedPointerHandleT> handle, TrustedPointerTagRange tag_range) { + TNode<ExternalReference> trusted_pointer_table_address = + IsolateField(IsolateFieldId::kTrustedPointerTable); + TNode<RawPtrT> table = LoadImmutable<RawPtrT>( + trusted_pointer_table_address, + UintPtrConstant(Internals::kExternalEntityTableBasePointerOffset)); TNode<Uint32T> index = Word32Shr(handle, Uint32Constant(kTrustedPointerHandleShift)); // We're using a 32-bit shift here to reduce code size, but for that we need @@ -2321,12 +2315,12 @@ TNode<TrustedObject> CodeStubAssembler::ResolveIndirectPointerHandle( Word32Shl(index, Uint32Constant(kTrustedPointerTableEntrySizeLog2))); TNode<UintPtrT> value = Load<UintPtrT>(table, offset); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); - value = WordAnd(value, UintPtrConstant(mask)); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); + value = WordAnd(value, UniqueUintPtrConstant(mask)); } else { TNode<UintPtrT> tag = - WordShr(value, UintPtrConstant(kTrustedPointerTableTagShift)); + WordShr(value, UniqueUintPtrConstant(kTrustedPointerTableTagShift)); TNode<BoolT> is_valid; if (tag_range.Size() == 1) { @@ -2339,7 +2333,8 @@ TNode<TrustedObject> CodeStubAssembler::ResolveIndirectPointerHandle( value = SelectConstant<UintPtrT>(is_valid, value, UintPtrConstant(0)); - value = WordAnd(value, UintPtrConstant(kTrustedPointerTablePayloadMask)); + value = + WordAnd(value, UniqueUintPtrConstant(kTrustedPointerTablePayloadMask)); } return TrustedCast<TrustedObject>(BitcastWordToTagged(value), "from trusted table"); @@ -3780,14 +3775,14 @@ TNode<BoolT> CodeStubAssembler::LoadScopeInfoHasExtensionField( TNode<ScopeInfo> scope_info) { TNode<Uint32T> value = LoadObjectField<Uint32T>(scope_info, offsetof(ScopeInfo, flags_)); - return IsSetWord32<ScopeInfo::HasContextExtensionSlotBit>(value); + return IsSetWord32<ScopeInfo::Flags::HasContextExtensionSlotBit>(value); } TNode<BoolT> CodeStubAssembler::LoadScopeInfoClassScopeHasPrivateBrand( TNode<ScopeInfo> scope_info) { TNode<Uint32T> value = LoadObjectField<Uint32T>(scope_info, offsetof(ScopeInfo, flags_)); - return IsSetWord32<ScopeInfo::ClassScopeHasPrivateBrandBit>(value); + return IsSetWord32<ScopeInfo::Flags::ClassScopeHasPrivateBrandBit>(value); } TNode<IntPtrT> CodeStubAssembler::LoadScopeInfoContextLocalCount( @@ -3796,6 +3791,106 @@ TNode<IntPtrT> CodeStubAssembler::LoadScopeInfoContextLocalCount( scope_info, offsetof(ScopeInfo, context_local_count_))); } +// LINT.IfChange(ScopeInfoContextLocalOffsets) +namespace { + +// Offset of the context_local_names section (or, when the locals are not +// inlined, of the single context_local_names_hashtable slot). Mirrors +// ScopeInfo::ContextLocalNamesOffset: the tail starts with a +// module_variable_count slot for module scopes only. +TNode<IntPtrT> ScopeInfoContextLocalNamesOffset(CodeStubAssembler* csa, + TNode<ScopeInfo> scope_info) { + TNode<Uint32T> flags = + csa->LoadObjectField<Uint32T>(scope_info, offsetof(ScopeInfo, flags_)); + TNode<BoolT> is_module = csa->Word32Equal( + csa->DecodeWord32<ScopeInfo::Flags::ScopeTypeBits>(flags), + csa->Uint32Constant(static_cast<uint32_t>(ScopeType::MODULE_SCOPE))); + return csa->Select<IntPtrT>( + is_module, + [=] { + return csa->IntPtrConstant(OFFSET_OF_DATA_START(ScopeInfo) + + kTaggedSize); + }, + [=] { return csa->IntPtrConstant(OFFSET_OF_DATA_START(ScopeInfo)); }); +} + +} // namespace + +TNode<IntPtrT> CodeStubAssembler::IndexOfLocalName(TNode<ScopeInfo> scope_info, + TNode<Name> name, + Label* not_found) { + TNode<IntPtrT> count = LoadScopeInfoContextLocalCount(scope_info); + TNode<IntPtrT> names_offset = + ScopeInfoContextLocalNamesOffset(this, scope_info); + + TVARIABLE(IntPtrT, var_result); + // Exits to |not_found| go through a local label so that no local variables + // are live at the jump; |not_found| may be an already-bound loop header. + Label inlined(this), hashtable(this), local_not_found(this), + done(this, &var_result); + Branch( + IntPtrLessThan(count, IntPtrConstant(kScopeInfoMaxInlinedLocalNamesSize)), + &inlined, &hashtable); + + BIND(&inlined); + { + // Mirrors ScopeInfo::InlinedLocalNamesLookup. + TVARIABLE(IntPtrT, var_index, IntPtrConstant(0)); + Label loop(this, &var_index), found(this); + Goto(&loop); + BIND(&loop); + GotoIfNot(IntPtrLessThan(var_index.value(), count), &local_not_found); + TNode<Object> local_name = LoadObjectField( + scope_info, + IntPtrAdd(names_offset, TimesTaggedSize(var_index.value()))); + GotoIf(TaggedEqual(local_name, name), &found); + var_index = IntPtrAdd(var_index.value(), IntPtrConstant(1)); + Goto(&loop); + + BIND(&found); + var_result = var_index.value(); + Goto(&done); + } + + BIND(&hashtable); + { + TNode<NameToIndexHashTable> table = + CAST(LoadObjectField(scope_info, names_offset)); + var_result = NameToIndexHashTableLookup(table, name, &local_not_found); + Goto(&done); + } + + BIND(&local_not_found); + Goto(not_found); + + BIND(&done); + return var_result.value(); +} + +TNode<Object> CodeStubAssembler::GetFunctionContextSlotInitialValue( + TNode<ScopeInfo> scope_info, TNode<IntPtrT> index) { + TNode<IntPtrT> count = LoadScopeInfoContextLocalCount(scope_info); + CSA_DCHECK(this, IntPtrLessThan(index, count)); + // Mirrors ScopeInfo::ContextLocalInfosOffset: the infos follow either the + // inlined names or the single hashtable slot. + TNode<IntPtrT> names_offset = + ScopeInfoContextLocalNamesOffset(this, scope_info); + TNode<IntPtrT> names_slots = Select<IntPtrT>( + IntPtrLessThan(count, IntPtrConstant(kScopeInfoMaxInlinedLocalNamesSize)), + [=] { return count; }, [this] { return IntPtrConstant(1); }); + TNode<IntPtrT> infos_offset = + IntPtrAdd(names_offset, TimesTaggedSize(names_slots)); + TNode<Smi> info = CAST(LoadObjectField( + scope_info, IntPtrAdd(infos_offset, TimesTaggedSize(index)))); + TNode<BoolT> maybe_assigned = Word32NotEqual( + DecodeWord32<ScopeInfo::MaybeAssignedFlagBit>(SmiToInt32(info)), + Uint32Constant(static_cast<uint32_t>(MaybeAssignedFlag::kNotAssigned))); + return Select<Object>( + maybe_assigned, [this] { return UndefinedContextCellConstant(); }, + [this] { return UndefinedConstant(); }); +} +// LINT.ThenChange(/src/objects/scope-info-inl.h:ContextLocalOffsets) + void CodeStubAssembler::StoreContextElementNoWriteBarrier( TNode<Context> context, int slot_index, TNode<Object> value) { int offset = Context::SlotOffset(slot_index); @@ -3905,7 +4000,7 @@ TNode<Uint32T> CodeStubAssembler::LoadFunctionKind(TNode<JSFunction> function) { function, offsetof(JSFunction, shared_function_info_)); const TNode<Uint32T> function_kind = - DecodeWord32<SharedFunctionInfo::FunctionKindBits>( + DecodeWord32<SharedFunctionInfo::Flags::FunctionKindBits>( LoadObjectField<Uint32T>(shared_function_info, offsetof(SharedFunctionInfo, flags_))); return function_kind; @@ -4058,7 +4153,7 @@ void CodeStubAssembler::GotoIfSharedFunctionInfoHasBaselineCode( LoadTrustedUnknownPointerFromObject( sfi, offsetof(SharedFunctionInfo, trusted_function_data_), &var_result, &if_default, &if_default, {{CODE_TYPE, &if_code}}, - SharedFunctionInfo::kTrustedDataIndirectPointerRange); + SharedFunctionInfo::kTrustedDataTrustedPointerRange); BIND(&if_code); CSA_SBXCHECK(this, @@ -4092,7 +4187,7 @@ TNode<BytecodeArray> CodeStubAssembler::LoadSharedFunctionInfoBytecodeArray( {CODE_TYPE, &is_code} #endif }, - SharedFunctionInfo::kTrustedDataIndirectPointerRange); + SharedFunctionInfo::kTrustedDataTrustedPointerRange); BIND(&is_interpreter_data); { @@ -4143,7 +4238,7 @@ TNode<WasmExportedFunctionData> CodeStubAssembler::LoadSharedFunctionInfoWasmExportedFunctionData( TNode<SharedFunctionInfo> sfi) { return LoadTrustedPointerFromObject< - kWasmExportedFunctionDataIndirectPointerTag>( + kWasmExportedFunctionDataTrustedPointerTag>( sfi, offsetof(SharedFunctionInfo, trusted_function_data_)); } #endif // V8_ENABLE_WEBASSEMBLY @@ -4183,8 +4278,11 @@ void CodeStubAssembler::StoreObjectByteNoWriteBarrier(TNode<HeapObject> object, IntPtrConstant(offset - kHeapObjectTag), value); } -void CodeStubAssembler::StoreHeapNumberValue(TNode<HeapNumber> object, - TNode<Float64T> value) { +void CodeStubAssembler::StoreHeapNumberValue( + TNode<UnionOf<HeapNumber, UninitializedHeapNumber>> object, + TNode<Float64T> value) { + static_assert(offsetof(HeapNumber, value_) == + offsetof(UninitializedHeapNumber, value_)); StoreObjectFieldNoWriteBarrier(object, offsetof(HeapNumber, value_), value); } @@ -4217,35 +4315,21 @@ void CodeStubAssembler::StoreObjectField(TNode<HeapObject> object, } } -void CodeStubAssembler::StoreIndirectPointerField( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, - TNode<ExposedTrustedObject> value) { - DCHECK(V8_ENABLE_SANDBOX_BOOL); - OptimizedStoreIndirectPointerField(object, offset, tag, value); -} - -void CodeStubAssembler::StoreIndirectPointerFieldNoWriteBarrier( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, - TNode<ExposedTrustedObject> value) { - DCHECK(V8_ENABLE_SANDBOX_BOOL); - OptimizedStoreIndirectPointerFieldNoWriteBarrier(object, offset, tag, value); -} - void CodeStubAssembler::StoreTrustedPointerField( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, + TNode<HeapObject> object, int offset, TrustedPointerTag tag, TNode<ExposedTrustedObject> value) { #ifdef V8_ENABLE_SANDBOX - StoreIndirectPointerField(object, offset, tag, value); + OptimizedStoreTrustedPointerField(object, offset, tag, value); #else StoreObjectField(object, offset, value); #endif // V8_ENABLE_SANDBOX } void CodeStubAssembler::StoreTrustedPointerFieldNoWriteBarrier( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, + TNode<HeapObject> object, int offset, TrustedPointerTag tag, TNode<ExposedTrustedObject> value) { #ifdef V8_ENABLE_SANDBOX - StoreIndirectPointerFieldNoWriteBarrier(object, offset, tag, value); + OptimizedStoreTrustedPointerFieldNoWriteBarrier(object, offset, tag, value); #else StoreObjectFieldNoWriteBarrier(object, offset, value); #endif // V8_ENABLE_SANDBOX @@ -4297,18 +4381,6 @@ void CodeStubAssembler::StoreMapNoWriteBarrier(TNode<HeapObject> object, DcheckHasValidMap(object); } -void CodeStubAssembler::StoreMapReleaseNoWriteBarrier( - TNode<HeapObject> object, RootIndex map_root_index) { - StoreMapReleaseNoWriteBarrier(object, CAST(LoadRoot(map_root_index))); -} - -void CodeStubAssembler::StoreMapReleaseNoWriteBarrier(TNode<HeapObject> object, - TNode<Map> map) { - MemoryBarrier(AtomicMemoryOrder::kAcqRel); - OptimizedStoreMap(object, map); - DcheckHasValidMap(object); -} - void CodeStubAssembler::StoreObjectFieldRoot(TNode<HeapObject> object, int offset, RootIndex root_index) { TNode<Object> root = LoadRoot(root_index); @@ -4669,6 +4741,20 @@ TNode<HeapNumber> CodeStubAssembler::AllocateHeapNumber() { return UncheckedCast<HeapNumber>(result); } +TNode<UninitializedHeapNumber> +CodeStubAssembler::AllocateUninitializedHeapNumber() { + // TODO(ishell, v8:8875): This requires double unaligned allocation when + // enabling USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL. + static_assert(!USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL); + static_assert(sizeof(HeapNumber) == sizeof(UninitializedHeapNumber)); + TNode<HeapObject> result = + Allocate(sizeof(UninitializedHeapNumber), AllocationFlag::kNone); + StoreMapNoWriteBarrier(result, RootIndex::kUninitializedHeapNumberMap); + StoreObjectFieldNoWriteBarrier( + result, offsetof(UninitializedHeapNumber, value_), Float64Constant(0.0)); + return UncheckedCast<UninitializedHeapNumber>(result); +} + TNode<HeapNumber> CodeStubAssembler::AllocateHeapNumberWithValue( TNode<Float64T> value) { TNode<HeapNumber> result = AllocateHeapNumber(); @@ -4714,6 +4800,8 @@ TNode<Object> CodeStubAssembler::CloneIfMutablePrimitive(TNode<Object> object) { Label done(this); GotoIf(TaggedIsSmi(object), &done); + CSA_DCHECK(this, Word32BinaryNot(IsUninitializedHeapNumber( + UncheckedCast<HeapObject>(object)))); // TODO(leszeks): Read the field descriptor to decide if this heap number is // mutable or not. GotoIfNot(IsHeapNumber(UncheckedCast<HeapObject>(object)), &done); @@ -8178,7 +8266,11 @@ void CodeStubAssembler::ThrowIfNotJSReceiver(TNode<Context> context, // The {value} is not a compatible receiver for this method. BIND(&throw_exception); - ThrowTypeError(context, msg_template, StringConstant(method_name), value); + if (method_name == nullptr || strlen(method_name) == 0) { + ThrowTypeError(context, msg_template); + } else { + ThrowTypeError(context, msg_template, StringConstant(method_name), value); + } BIND(&done); } @@ -8283,8 +8375,8 @@ void CodeStubAssembler::TerminateExecution(TNode<Context> context) { } TNode<Union<TheHole, JSMessageObject>> CodeStubAssembler::GetPendingMessage() { - TNode<ExternalReference> pending_message = ExternalConstant( - ExternalReference::address_of_pending_message(isolate())); + TNode<ExternalReference> pending_message = + IsolateField(IsolateFieldId::kPendingMessage); return UncheckedCast<Union<TheHole, JSMessageObject>>( LoadFullTagged(pending_message)); } @@ -8293,8 +8385,8 @@ void CodeStubAssembler::SetPendingMessage( CSA_DCHECK(this, Word32Or(IsTheHole(message), InstanceTypeEqual(LoadInstanceType(message), JS_MESSAGE_OBJECT_TYPE))); - TNode<ExternalReference> pending_message = ExternalConstant( - ExternalReference::address_of_pending_message(isolate())); + TNode<ExternalReference> pending_message = + IsolateField(IsolateFieldId::kPendingMessage); StoreFullTaggedNoWriteBarrier(pending_message, message); } @@ -8864,6 +8956,15 @@ TNode<BoolT> CodeStubAssembler::IsMapInstanceType(TNode<Int32T> instance_type) { return InstanceTypeEqual(instance_type, MAP_TYPE); } +TNode<BoolT> CodeStubAssembler::IsMapOrCustomMap(TNode<HeapObject> object) { +#if V8_ENABLE_WEBASSEMBLY + return UncheckedCast<BoolT>( + Word32Or(IsMap(object), HasInstanceType(object, WASM_CUSTOM_MAP_TYPE))); +#else + return IsMap(object); +#endif // V8_ENABLE_WEBASSEMBLY +} + TNode<BoolT> CodeStubAssembler::IsJSPrimitiveWrapperInstanceType( TNode<Int32T> instance_type) { return InstanceTypeEqual(instance_type, JS_PRIMITIVE_WRAPPER_TYPE); @@ -9257,7 +9358,7 @@ TNode<BoolT> CodeStubAssembler::IsAnyPrivateName(TNode<Symbol> symbol) { TNode<Uint32T> flags = LoadObjectField<Uint32T>(symbol, offsetof(Symbol, flags_)); return Int32GreaterThanOrEqual( - DecodeWord32<Symbol::PrivateSymbolKindBits>(flags), + DecodeWord32<Symbol::Flags::PrivateSymbolKindBits>(flags), Int32Constant(static_cast<int>(PrivateSymbolKind::kFieldName))); } @@ -13147,7 +13248,7 @@ TNode<BoolT> CodeStubAssembler::IsInterestingProperty(TNode<Name> name) { GotoIf(IsThenString(name), &return_true); GotoIfNot(InstanceTypeEqual(LoadMapInstanceType(LoadMap(name)), SYMBOL_TYPE), &return_false); - Branch(IsSetWord32<Symbol::IsInterestingSymbolBit>( + Branch(IsSetWord32<Symbol::Flags::IsInterestingSymbolBit>( LoadObjectField<Uint32T>(name, offsetof(Symbol, flags_))), &return_true, &return_false); @@ -18469,17 +18570,23 @@ TNode<Boolean> CodeStubAssembler::HasProperty(TNode<Context> context, return result.value(); } -void CodeStubAssembler::ForInPrepare(TNode<HeapObject> enumerator, - TNode<UintPtrT> slot, - TNode<HeapObject> maybe_feedback_vector, - TNode<FixedArray>* cache_array_out, - TNode<Smi>* cache_length_out, - UpdateFeedbackMode update_feedback_mode) { +void CodeStubAssembler::ForInPrepare( + TNode<HeapObject> enumerator, TNode<UintPtrT> slot, + TNode<HeapObject> maybe_feedback_vector, + TNode<Union<FixedArray, ForInEnumeratorHolder>>* cache_array_out, + TNode<Smi>* cache_length_out, UpdateFeedbackMode update_feedback_mode) { // Check if we're using an enum cache. - TVARIABLE(FixedArray, cache_array); + TVARIABLE((Union<FixedArray, ForInEnumeratorHolder>), cache_array); TVARIABLE(Smi, cache_length); - Label if_fast(this), if_slow(this, Label::kDeferred), out(this); - Branch(IsMap(enumerator), &if_fast, &if_slow); + + TNode<Uint16T> instance_type = LoadInstanceType(enumerator); + Label if_fast(this), if_holder(this), if_slow(this, Label::kDeferred), + out(this); + + GotoIf(InstanceTypeEqual(instance_type, MAP_TYPE), &if_fast); + GotoIf(InstanceTypeEqual(instance_type, FOR_IN_ENUMERATOR_HOLDER_TYPE), + &if_holder); + Goto(&if_slow); BIND(&if_fast); { @@ -18510,6 +18617,20 @@ void CodeStubAssembler::ForInPrepare(TNode<HeapObject> enumerator, Goto(&out); } + BIND(&if_holder); + { + TNode<ForInEnumeratorHolder> holder = CAST(enumerator); + + // Record the fact that we are using a ForInEnumeratorHolder. + UpdateFeedback(SmiConstant(ForInFeedback::kEnumeratorHolder), + maybe_feedback_vector, slot, update_feedback_mode); + + cache_array = holder; + cache_length = LoadObjectField<Smi>( + holder, ObjectTraits<ForInEnumeratorHolder>::kCacheLengthOffset); + Goto(&out); + } + BIND(&if_slow); { // The {enumerator} is a FixedArray with all the keys to iterate. @@ -18530,6 +18651,46 @@ void CodeStubAssembler::ForInPrepare(TNode<HeapObject> enumerator, *cache_length_out = cache_length.value(); } +// Checks that the receiver's map and elements length (either JSArray::length or +// elements->length() for non-JSArrays) haven't changed compared to what was +// recorded in the ForInEnumeratorHolder when enumeration started. +TNode<BoolT> CodeStubAssembler::CheckHolderValidity( + TNode<HeapObject> receiver, TNode<ForInEnumeratorHolder> holder) { + TVARIABLE(BoolT, result, BoolConstant(false)); + Label out(this); + + TNode<Map> receiver_map = LoadMap(receiver); + TNode<Map> holder_map = LoadObjectField<Map>( + holder, ObjectTraits<ForInEnumeratorHolder>::kEnumCacheMapOffset); + GotoIfNot(TaggedEqual(receiver_map, holder_map), &out); + + CSA_DCHECK(this, IsFastPackedElementsKind(LoadMapElementsKind(receiver_map))); + + TNode<Smi> elements_length = LoadObjectField<Smi>( + holder, ObjectTraits<ForInEnumeratorHolder>::kElementsLengthOffset); + + Label if_array(this), if_not_array(this); + Branch(IsJSArrayMap(receiver_map), &if_array, &if_not_array); + + BIND(&if_array); + { + TNode<JSArray> array = CAST(receiver); + result = TaggedEqual(LoadFastJSArrayLength(array), elements_length); + Goto(&out); + } + + BIND(&if_not_array); + { + TNode<FixedArrayBase> elements = LoadElements(CAST(receiver)); + result = WordEqual(LoadFixedArrayBaseLength(elements), + SmiUntag(elements_length)); + Goto(&out); + } + + BIND(&out); + return result.value(); +} + TNode<String> CodeStubAssembler::Typeof( TNode<Object> value, std::optional<TNode<UintPtrT>> slot_id, std::optional<TNode<HeapObject>> maybe_feedback_vector) { @@ -18686,10 +18847,10 @@ void CodeStubAssembler::FindNonDefaultConstructor( LoadObjectField<SharedFunctionInfo>( CAST(constructor.value()), offsetof(JSFunction, shared_function_info_)); - const TNode<Uint32T> has_class_fields = - DecodeWord32<SharedFunctionInfo::RequiresInstanceMembersInitializerBit>( - LoadObjectField<Uint32T>(shared_function_info, - offsetof(SharedFunctionInfo, flags_))); + const TNode<Uint32T> has_class_fields = DecodeWord32< + SharedFunctionInfo::Flags::RequiresInstanceMembersInitializerBit>( + LoadObjectField<Uint32T>(shared_function_info, + offsetof(SharedFunctionInfo, flags_))); GotoIf(Word32NotEqual(has_class_fields, Int32Constant(0)), found_something_else); @@ -20149,15 +20310,15 @@ void CodeStubAssembler::LoadSharedFunctionInfoTrustedDataAndDispatch( TVariable<Uint16T>* data_type_out, Label* if_empty, Label* if_default, const std::initializer_list<std::pair<InstanceType, Label*>>& cases) { #ifdef V8_ENABLE_SANDBOX - TNode<IndirectPointerHandleT> trusted_data_handle = - LoadObjectField<IndirectPointerHandleT>( + TNode<TrustedPointerHandleT> trusted_data_handle = + LoadObjectField<TrustedPointerHandleT>( shared_info, offsetof(SharedFunctionInfo, trusted_function_data_)); GotoIf(Word32Equal(trusted_data_handle, - Int32Constant(kNullIndirectPointerHandle)), + Int32Constant(kNullTrustedPointerHandle)), if_empty); - ResolveIndirectUnknownPointerHandle(trusted_data_handle, sfi_data_out, - data_type_out, if_default, cases); + ResolveTrustedUnknownPointerHandle(trusted_data_handle, sfi_data_out, + data_type_out, if_default, cases); #else *sfi_data_out = LoadObjectField<Object>( shared_info, offsetof(SharedFunctionInfo, trusted_function_data_)); @@ -20346,7 +20507,7 @@ TNode<JSFunction> CodeStubAssembler::AllocateRootFunctionWithContext( const TNode<NativeContext> native_context = maybe_native_context ? *maybe_native_context : LoadNativeContext(context); const TNode<Map> map = CAST(LoadContextElementNoCell( - native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); + native_context, Context::FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)); const TNode<HeapObject> fun = Allocate(JSFunctionWithoutPrototype::kMinSize); static_assert(JSFunctionWithoutPrototype::kMinSize == 7 * kTaggedSize); StoreMapNoWriteBarrier(fun, map); @@ -20503,7 +20664,7 @@ void CodeStubAssembler::PrintErr(const char* s) { void CodeStubAssembler::PrintToStream(const char* s, int stream) { std::string formatted(s); - formatted += "\n"; + formatted += '\n'; CallRuntime(Runtime::kGlobalPrint, NoContextConstant(), StringConstant(formatted.c_str()), SmiConstant(stream)); } @@ -20762,8 +20923,7 @@ void CodeStubAssembler::PerformStackCheck(TNode<Context> context) { Label ok(this), stack_check_interrupt(this, Label::kDeferred); TNode<UintPtrT> stack_limit = UncheckedCast<UintPtrT>( - Load(MachineType::Pointer(), - ExternalConstant(ExternalReference::address_of_jslimit(isolate())))); + Load(MachineType::Pointer(), IsolateField(IsolateFieldId::kJsLimit))); TNode<BoolT> sp_within_limit = StackPointerGreaterThan(stack_limit); Branch(sp_within_limit, &ok, &stack_check_interrupt); @@ -21553,13 +21713,6 @@ CodeStubAssembler::SwissNameDictionaryOffsetIntoPropertyDetailsTableMT( TNode<IntPtrT> property_details_table_start = IntPtrAdd(data_table_start, data_and_ctrl_table_size); - CSA_DCHECK( - this, - WordEqual(FieldSliceSwissNameDictionaryPropertyDetailsTable(dict).offset, - // Our calculation subtracted the tag, Torque's offset didn't. - IntPtrAdd(property_details_table_start, - IntPtrConstant(kHeapObjectTag)))); - TNode<IntPtrT> offset_within_details_table = index; return IntPtrAdd(property_details_table_start, offset_within_details_table); } @@ -21664,10 +21817,6 @@ void CodeStubAssembler::SwissNameDictionarySetCtrl( TNode<IntPtrT> one = IntPtrConstant(1); TNode<IntPtrT> offset = SwissNameDictionaryCtrlTableStartOffsetMT(capacity); - CSA_DCHECK(this, - WordEqual(FieldSliceSwissNameDictionaryCtrlTable(table).offset, - IntPtrAdd(offset, one))); - TNode<IntPtrT> offset_entry = IntPtrAdd(offset, entry); StoreToObject(MachineRepresentation::kWord8, table, offset_entry, ctrl, StoreToObjectWriteBarrier::kNone); diff --git a/deps/v8/src/codegen/code-stub-assembler.h b/deps/v8/src/codegen/code-stub-assembler.h index 004d38e895c4..63b3b9c92d22 100644 --- a/deps/v8/src/codegen/code-stub-assembler.h +++ b/deps/v8/src/codegen/code-stub-assembler.h @@ -44,8 +44,8 @@ #include "src/objects/tagged-index.h" #include "src/objects/tagged.h" #include "src/objects/templates.h" -#include "src/objects/trusted-pointer.h" #include "src/roots/roots.h" +#include "src/sandbox/trusted-pointer.h" #include "torque-generated/exported-macros-assembler.h" #if V8_ENABLE_WEBASSEMBLY @@ -1033,7 +1033,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler // Load a trusted pointer field. // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table. Otherwise they are regular tagged fields. - template <IndirectPointerTagRange tag_range> + template <TrustedPointerTagRange tag_range> inline TNode<TrustedTypeFor<tag_range>> LoadTrustedPointerFromObject( TNode<HeapObject> object, int field_offset); @@ -1041,7 +1041,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode<HeapObject> object, int offset, TVariable<Object>* value_out, Label* if_empty, Label* if_default, const std::initializer_list<std::pair<InstanceType, Label*>>& cases, - IndirectPointerTagRange tag_range = kAllIndirectPointerTags); + TrustedPointerTagRange tag_range = kAllTrustedPointerTags); // Load a code pointer field. // These are special versions of trusted pointers that, when the sandbox is @@ -1054,18 +1054,18 @@ class V8_EXPORT_PRIVATE CodeStubAssembler #ifdef V8_ENABLE_SANDBOX // Load an indirect pointer field. - TNode<TrustedObject> LoadIndirectPointerFromObject( - TNode<HeapObject> object, int offset, IndirectPointerTagRange tag_range); + TNode<TrustedObject> LoadTrustedPointerFromObject( + TNode<HeapObject> object, int offset, TrustedPointerTagRange tag_range); // Retrieve the heap object referenced by the given indirect pointer handle. - TNode<TrustedObject> ResolveIndirectPointerHandle( - TNode<IndirectPointerHandleT> handle, IndirectPointerTagRange tag_range); + TNode<TrustedObject> ResolveTrustedPointerHandle( + TNode<TrustedPointerHandleT> handle, TrustedPointerTagRange tag_range); - void ResolveIndirectUnknownPointerHandle( - TNode<IndirectPointerHandleT> handle, TVariable<Object>* value_out, + void ResolveTrustedUnknownPointerHandle( + TNode<TrustedPointerHandleT> handle, TVariable<Object>* value_out, TVariable<Uint16T>* type_out, Label* if_default, const std::initializer_list<std::pair<InstanceType, Label*>>& cases, - IndirectPointerTagRange tag_range = kAllIndirectPointerTags); + TrustedPointerTagRange tag_range = kAllTrustedPointerTags); #endif TNode<JSDispatchHandleT> InvalidDispatchHandleConstant(); @@ -1707,6 +1707,17 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode<BoolT> LoadScopeInfoClassScopeHasPrivateBrand( TNode<ScopeInfo> scope_info); TNode<IntPtrT> LoadScopeInfoContextLocalCount(TNode<ScopeInfo> scope_info); + // Returns the index of the named context local, i.e. its context slot + // index minus Context::MIN_CONTEXT_SLOTS. Assumes that |name| is + // internalized and uses pointer comparisons. Mirrors + // ScopeInfo::ContextSlotIndex. + TNode<IntPtrT> IndexOfLocalName(TNode<ScopeInfo> scope_info, TNode<Name> name, + Label* not_found); + // Returns the value a freshly allocated function context slot should be + // initialized with for the |index|-th context local: the undefined context + // cell for locals that may be reassigned, undefined otherwise. + TNode<Object> GetFunctionContextSlotInitialValue(TNode<ScopeInfo> scope_info, + TNode<IntPtrT> index); // Context manipulation: void StoreContextElementNoWriteBarrier(TNode<Context> context, int slot_index, @@ -1792,7 +1803,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode<Word32T> value); // Store the floating point value of a HeapNumber. - void StoreHeapNumberValue(TNode<HeapNumber> object, TNode<Float64T> value); + void StoreHeapNumberValue( + TNode<UnionOf<HeapNumber, UninitializedHeapNumber>> object, + TNode<Float64T> value); // Store a field to an object on the heap. void StoreObjectField(TNode<HeapObject> object, int offset, TNode<Smi> value); @@ -1803,41 +1816,29 @@ class V8_EXPORT_PRIVATE CodeStubAssembler void StoreObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset, TNode<Object> value); - // Store to an indirect pointer field. This involves loading the index for - // the pointer table entry owned by the pointed-to object (which points back - // to it) and storing that into the specified field. - // Stores that may require a write barrier also need to know the indirect - // pointer tag for the field. Otherwise, it is not needed - void StoreIndirectPointerField(TNode<HeapObject> object, int offset, - IndirectPointerTag tag, - TNode<ExposedTrustedObject> value); - void StoreIndirectPointerFieldNoWriteBarrier( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, - TNode<ExposedTrustedObject> value); - // Store a trusted pointer field. // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table. Otherwise they are regular tagged fields. void StoreTrustedPointerField(TNode<HeapObject> object, int offset, - IndirectPointerTag tag, + TrustedPointerTag tag, TNode<ExposedTrustedObject> value); void StoreTrustedPointerFieldNoWriteBarrier( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, + TNode<HeapObject> object, int offset, TrustedPointerTag tag, TNode<ExposedTrustedObject> value); void ClearTrustedPointerField(TNode<HeapObject> object, int offset); // Store a code pointer field. // These are special versions of trusted pointers that, when the sandbox is - // enabled, reference code objects through the code pointer table. + // enabled, reference code objects through the trusted pointer table. void StoreCodePointerField(TNode<HeapObject> object, int offset, TNode<Code> value) { - StoreTrustedPointerField(object, offset, kCodeIndirectPointerTag, value); + StoreTrustedPointerField(object, offset, kCodeTrustedPointerTag, value); } void StoreCodePointerFieldNoWriteBarrier(TNode<HeapObject> object, int offset, TNode<Code> value) { StoreTrustedPointerFieldNoWriteBarrier(object, offset, - kCodeIndirectPointerTag, value); + kCodeTrustedPointerTag, value); } template <class T> @@ -1871,9 +1872,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler void StoreMapNoWriteBarrier(TNode<HeapObject> object, RootIndex map_root_index); void StoreMapNoWriteBarrier(TNode<HeapObject> object, TNode<Map> map); - void StoreMapReleaseNoWriteBarrier(TNode<HeapObject> object, - RootIndex map_root_index); - void StoreMapReleaseNoWriteBarrier(TNode<HeapObject> object, TNode<Map> map); void StoreObjectFieldRoot(TNode<HeapObject> object, int offset, RootIndex root); @@ -2077,6 +2075,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler void StoreCellValue(TNode<Cell> cell, TNode<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + TNode<UninitializedHeapNumber> AllocateUninitializedHeapNumber(); + // Allocate a HeapNumber without initializing its value. TNode<HeapNumber> AllocateHeapNumber(); // Allocate a HeapNumber with a specific value. @@ -3000,6 +3000,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler TNode<BoolT> IsMapMap(TNode<Map> map); TNode<BoolT> IsMap(TNode<HeapObject> object); TNode<BoolT> IsMapInstanceType(TNode<Int32T> instance_type); + TNode<BoolT> IsMapOrCustomMap(TNode<HeapObject> object); TNode<BoolT> IsName(TNode<HeapObject> object); TNode<BoolT> IsNameInstanceType(TNode<Int32T> instance_type); TNode<BoolT> IsNullOrJSReceiver(TNode<HeapObject> object); @@ -3096,10 +3097,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler return LoadRuntimeFlag(ExternalReference::address_of_js_pr_3883_flag()); } - TNode<BoolT> HasSharedStringTableFlag() { - return LoadRuntimeFlag( - ExternalReference::address_of_shared_string_table_flag()); - } + TNode<BoolT> HasSharedStringTableFlag() { return BoolConstant(false); } TNode<BoolT> IsAdditiveSafeIntegerFeedbackEnabled() { if (Is64()) { @@ -4385,11 +4383,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler HasPropertyLookupMode::kHasProperty); } - void ForInPrepare(TNode<HeapObject> enumerator, TNode<UintPtrT> slot, - TNode<HeapObject> maybe_feedback_vector, - TNode<FixedArray>* cache_array_out, - TNode<Smi>* cache_length_out, - UpdateFeedbackMode update_feedback_mode); + void ForInPrepare( + TNode<HeapObject> enumerator, TNode<UintPtrT> slot, + TNode<HeapObject> maybe_feedback_vector, + TNode<Union<FixedArray, ForInEnumeratorHolder>>* cache_array_out, + TNode<Smi>* cache_length_out, UpdateFeedbackMode update_feedback_mode); + + TNode<BoolT> CheckHolderValidity(TNode<HeapObject> receiver, + TNode<ForInEnumeratorHolder> holder); TNode<String> Typeof( TNode<Object> value, std::optional<TNode<UintPtrT>> slot_id = {}, diff --git a/deps/v8/src/codegen/compiler.cc b/deps/v8/src/codegen/compiler.cc index 0a3599ee41c4..751a25d385d0 100644 --- a/deps/v8/src/codegen/compiler.cc +++ b/deps/v8/src/codegen/compiler.cc @@ -10,7 +10,6 @@ #include "include/v8-script.h" #include "src/api/api-inl.h" #include "src/ast/scopes.h" -#include "src/base/fpu.h" #include "src/base/logging.h" #include "src/base/platform/time.h" #include "src/base/strong-alias.h" @@ -469,29 +468,43 @@ CompilationJob::Status OptimizedCompilationJob::FinalizeJob(Isolate* isolate) { return UpdateState(FinalizeJobImpl(isolate), State::kSucceeded); } -GlobalHandleVector<Map> OptimizedCompilationJob::CollectRetainedMaps( - Isolate* isolate, DirectHandle<Code> code) { +// static +OptimizedCompilationJob::RetainedMaps +OptimizedCompilationJob::CollectRetainedMaps( + DirectHandle<Code> code, + std::unique_ptr<CanonicalHandlesMap> canonical_handles) { DCHECK(code->is_optimized_code()); + DCHECK_NOT_NULL(canonical_handles); DisallowGarbageCollection no_gc; - GlobalHandleVector<Map> maps(isolate->heap()); + RetainedMaps maps; int const mode_mask = RelocInfo::EmbeddedObjectModeMask(); for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { DCHECK(RelocInfo::IsEmbeddedObjectMode(it.rinfo()->rmode())); Tagged<HeapObject> target_object = it.rinfo()->target_object(); if (code->IsWeakObjectInOptimizedCode(target_object)) { - if (IsMap(target_object)) { - maps.Push(Cast<Map>(target_object)); + if (Tagged<Map> map; TryCast<Map>(target_object, &map)) { + // Every weak map embedded in optimized code was canonicalized into + // `canonical_handles` during compilation. Reuse its existing canonical + // PersistentHandle location and clear the map entry (`*entry = + // nullptr`) to deduplicate subsequent RelocInfo occurrences; + // `canonical_handles` is consumed and cleared at the end of this pass. + Address** entry = canonical_handles->Find(map); + DCHECK_NOT_NULL(entry); + if (Address* location = std::exchange(*entry, nullptr)) { + maps.push_back(IndirectHandle<Map>(location)); + } } } } + canonical_handles->Clear(); return maps; } void OptimizedCompilationJob::RegisterWeakObjectsInOptimizedCode( Isolate* isolate, DirectHandle<NativeContext> context, - DirectHandle<Code> code, GlobalHandleVector<Map> maps) { - isolate->heap()->AddRetainedMaps(context, std::move(maps)); + DirectHandle<Code> code, base::Vector<const IndirectHandle<Map>> maps) { + isolate->heap()->AddRetainedMaps(context, maps); code->set_can_have_weak_objects(true); } @@ -1373,7 +1386,8 @@ MaybeHandle<Code> GetOrCompileOptimized( void SpawnDuplicateConcurrentJobForStressTesting( Isolate* isolate, DirectHandle<JSFunction> function, ConcurrencyMode mode, CodeKind code_kind) { - // TODO(v8:7700): Support Maglev. + // TODO(v8:7700): Support Maglev (--maglev-as-top-tier currently explicitly + // disables --stress-concurrent-inlining). if (code_kind == CodeKind::MAGLEV) return; if (function->ActiveTierIsTurbofan(isolate)) return; @@ -1923,9 +1937,6 @@ bool BackgroundCompileTask::is_streaming_compilation() const { } void BackgroundCompileTask::Run() { - base::FlushDenormalsScope flush_denormals_scope( - isolate_for_local_isolate_->flush_denormals()); - DCHECK_NE(ThreadId::Current(), isolate_for_local_isolate_->thread_id()); LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&isolate); @@ -1949,6 +1960,14 @@ void BackgroundCompileTask::Run( compilation_details_ ? &compilation_details_->background_time_in_microseconds : nullptr); + std::optional<TimedHistogramScope> script_type_timer; + if (flags_.is_toplevel()) { + script_type_timer.emplace( + flags_.is_module() ? isolate_for_local_isolate_->counters() + ->compile_script_on_background_module() + : isolate_for_local_isolate_->counters() + ->compile_script_on_background_classic()); + } TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "BackgroundCompileTask::Run"); @@ -2024,6 +2043,9 @@ void BackgroundCompileTask::Run( parser.ParseOnBackground(isolate, &info, script_, start_position_, end_position_, function_literal_id_); parser.UpdateStatistics(script_, &use_counts_, &total_preparse_skipped_); + if (toplevel_script_compilation) { + debug_magic_comment_locations_ = parser.debug_magic_comment_locations(); + } TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCodeBackground"); @@ -2767,8 +2789,14 @@ MaybeHandle<SharedFunctionInfo> BackgroundCompileTask::FinalizeScript( { DisallowGarbageCollection no_gc; SetScriptFieldsFromDetails(isolate, *script, script_details, &no_gc); - LOG(isolate, ScriptDetails(*script)); } + // After SetScriptFieldsFromDetails, so that a source map URL provided + // through the API takes precedence. The locations come from the streamed + // source; the embedder is expected to pass the same source here, but an + // out-of-bounds location is ignored. + Parser::SetDebugMagicCommentFields(isolate, script, source, + debug_magic_comment_locations_); + LOG(isolate, ScriptDetails(*script)); } ReportStatistics(isolate); @@ -2843,10 +2871,8 @@ BackgroundDeserializeTask::BackgroundDeserializeTask( } void BackgroundDeserializeTask::Run() { - base::FlushDenormalsScope flush_denormals_scope( - isolate_for_local_isolate_->flush_denormals()); - TimedHistogramScope timer(timer_, nullptr, &background_time_in_microseconds_); + LazyTimedHistogramScope script_type_timer; LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&isolate); LocalHandleScope handle_scope(&isolate); @@ -2854,11 +2880,20 @@ void BackgroundDeserializeTask::Run() { DirectHandle<SharedFunctionInfo> inner_result; CodeSerializer::StartDeserializeOffThread(&isolate, &cached_data_, &off_thread_data_); - if (v8_flags.enable_slow_asserts && off_thread_data_.HasResult()) { + if (off_thread_data_.HasResult()) { + Tagged<Script> script = *off_thread_data_.GetOnlyScript(isolate.heap()); + script_type_timer.set_histogram( + script->origin_options().IsModule() + ? isolate_for_local_isolate_->counters() + ->deserialize_script_on_background_module() + : isolate_for_local_isolate_->counters() + ->deserialize_script_on_background_classic()); + if (v8_flags.enable_slow_asserts) { #ifdef ENABLE_SLOW_DCHECKS - MergeAssumptionChecker checker(&isolate, false); - checker.IterateObjects(*off_thread_data_.GetOnlyScript(isolate.heap())); + MergeAssumptionChecker checker(&isolate, false); + checker.IterateObjects(script); #endif + } } } @@ -2885,9 +2920,6 @@ bool BackgroundDeserializeTask::ShouldMergeWithExistingScript() const { void BackgroundDeserializeTask::MergeWithExistingScript() { DCHECK(ShouldMergeWithExistingScript()); - base::FlushDenormalsScope flush_denormals_scope( - isolate_for_local_isolate_->flush_denormals()); - LocalIsolate isolate(isolate_for_local_isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&isolate); LocalHandleScope handle_scope(isolate.heap()); @@ -3320,7 +3352,8 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( DirectHandle<SharedFunctionInfo> outer_info, DirectHandle<Context> context, LanguageMode language_mode, ParseRestriction restriction, int parameters_end_pos, int eval_position, - ParsingWhileDebugging parsing_while_debugging) { + ParsingWhileDebugging parsing_while_debugging, + bool private_name_lookup_skips_outer_class) { // The cache lookup key needs to be aware of the separation between the // parameters and the body to prevent this valid invocation: // Function("", "function anonymous(\n/**/) {\n}"); @@ -3337,9 +3370,36 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( DCHECK_EQ(eval_position, kNoSourcePosition); eval_cache_position = -parameters_end_pos; } + + Script::CompilationKind compilation_kind; + bool allow_eval_cache = true; + if (eval_position == kNoSourcePosition) { + compilation_kind = restriction == ONLY_SINGLE_FUNCTION_LITERAL + ? Script::CompilationKind::kFunctionConstructor + : Script::CompilationKind::kIndirectEval; + // If the position is missing, attempt to get the code offset by + // walking the stack. Do not translate the code offset into source + // position, but store it as negative value for lazy translation. + DebuggableStackFrameIterator it(isolate); + if (!it.done() && it.is_javascript()) { + FrameSummary summary = it.GetTopValidFrame(); + outer_info = + direct_handle(summary.AsJavaScript().function()->shared(), isolate); + eval_position = -summary.code_offset(); + } else { + eval_position = 0; + allow_eval_cache = false; + } + } else { + compilation_kind = Script::CompilationKind::kDirectEval; + } + CompilationCache* compilation_cache = isolate->compilation_cache(); - InfoCellPair eval_result = compilation_cache->LookupEval( - source, outer_info, context, language_mode, eval_cache_position); + InfoCellPair eval_result; + if (allow_eval_cache) { + eval_result = compilation_cache->LookupEval( + source, outer_info, context, language_mode, eval_cache_position); + } if (eval_result.has_js_function()) { DirectHandle<JSFunction> result = direct_handle(eval_result.js_function(), isolate); @@ -3358,7 +3418,6 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( DirectHandle<SharedFunctionInfo> shared_info; Handle<Script> script; IsCompiledScope is_compiled_scope; - bool allow_eval_cache; if (eval_result.has_shared()) { // Make sure that the scope_info of the context we're eval-ing in matches // the scope_info we compiled the code for. @@ -3369,13 +3428,14 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( DirectHandle<SharedFunctionInfo>(eval_result.shared(), isolate); script = Handle<Script>(Cast<Script>(shared_info->script()), isolate); is_compiled_scope = shared_info->is_compiled_scope(isolate); - allow_eval_cache = true; } else { UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile( isolate, true, language_mode, REPLMode::kNo, ScriptType::kClassic, v8_flags.lazy_eval); flags.set_is_eval(true); flags.set_parsing_while_debugging(parsing_while_debugging); + flags.set_private_name_lookup_skips_outer_class( + private_name_lookup_skips_outer_class); DCHECK(!flags.is_module()); flags.set_parse_restriction(restriction); @@ -3392,31 +3452,8 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( isolate, source, kNullMaybeHandle, OriginOptionsForEval(outer_info->script(), parsing_while_debugging)); script->set_outer_language_mode(language_mode); - if (eval_position == kNoSourcePosition) { - script->set_compilation_kind( - restriction == ONLY_SINGLE_FUNCTION_LITERAL - ? Script::CompilationKind::kFunctionConstructor - : Script::CompilationKind::kIndirectEval); - } else { - script->set_compilation_kind(Script::CompilationKind::kDirectEval); - } + script->set_compilation_kind(compilation_kind); script->set_eval_from_shared(*outer_info); - if (eval_position == kNoSourcePosition) { - // If the position is missing, attempt to get the code offset by - // walking the stack. Do not translate the code offset into source - // position, but store it as negative value for lazy translation. - DebuggableStackFrameIterator it(isolate); - if (!it.done() && it.is_javascript()) { - FrameSummary summary = it.GetTopValidFrame(); - script->set_eval_from_shared( - summary.AsJavaScript().function()->shared()); - script->set_origin_options( - OriginOptionsForEval(*summary.script(), parsing_while_debugging)); - eval_position = -summary.code_offset(); - } else { - eval_position = 0; - } - } script->set_eval_from_position(eval_position); if (!maybe_outer_scope_info.is_null()) { script->set_eval_from_scope_info( @@ -3429,7 +3466,9 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( .ToHandle(&shared_info)) { return MaybeDirectHandle<JSFunction>(); } - allow_eval_cache = parse_info.allow_eval_cache(); + if (!parse_info.allow_eval_cache()) { + allow_eval_cache = false; + } } // If caller is strict mode, the result must be in strict mode as well. @@ -3463,6 +3502,14 @@ MaybeDirectHandle<JSFunction> Compiler::GetFunctionFromEval( compilation_cache->PutEval(source, outer_info, result, eval_cache_position); } + if (isolate->dynamic_script_callback() && + !script->eval_from_shared()->IsUserJavaScript()) { + VMState<EXTERNAL> state(isolate); + DirectHandle<NativeContext> native_context(context->native_context(), + isolate); + isolate->dynamic_script_callback()(v8::Utils::ToLocal(native_context), + script->id()); + } } CHECK(is_compiled_scope.is_compiled()); @@ -3622,10 +3669,15 @@ struct ScriptCompileTimerScope { ScriptCompileTimerScope( Isolate* isolate, ScriptCompiler::NoCacheReason no_cache_reason, + ScriptType script_type, ScriptCompiler::CompilationDetails* compilation_details) : isolate_(isolate), histogram_scope_(&compilation_details->foreground_time_in_microseconds), all_scripts_histogram_scope_(isolate->counters()->compile_script()), + script_type_histogram_scope_( + script_type == ScriptType::kModule + ? isolate->counters()->compile_script_module() + : isolate->counters()->compile_script_classic()), no_cache_reason_(no_cache_reason), hit_isolate_cache_(false), consuming_code_cache_(false), @@ -3662,6 +3714,7 @@ struct ScriptCompileTimerScope { // TODO(leszeks): This timer is the sum of the other times, consider removing // it to save space. NestedTimedHistogramScope all_scripts_histogram_scope_; + NestedTimedHistogramScope script_type_histogram_scope_; ScriptCompiler::NoCacheReason no_cache_reason_; bool hit_isolate_cache_; bool consuming_code_cache_; @@ -3809,6 +3862,12 @@ MaybeDirectHandle<SharedFunctionInfo> CompileScriptOnMainThread( MaybeHandle<Script> maybe_script, IsCompiledScope* is_compiled_scope, CompileHintCallback compile_hint_callback = nullptr, void* compile_hint_callback_data = nullptr) { + NestedTimedHistogramScope main_thread_timer( + isolate->counters()->compile_script_main_thread()); + NestedTimedHistogramScope main_thread_script_type_timer( + flags.is_module() + ? isolate->counters()->compile_script_main_thread_module() + : isolate->counters()->compile_script_main_thread_classic()); UnoptimizedCompileState compile_state; ReusableUnoptimizedCompileState reusable_state(isolate); ParseInfo parse_info(isolate, flags, &compile_state, &reusable_state); @@ -3979,7 +4038,10 @@ MaybeDirectHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl( ScriptCompiler::CompileOptions compile_options, ScriptCompiler::NoCacheReason no_cache_reason, NativesFlag natives, ScriptCompiler::CompilationDetails* compilation_details) { - ScriptCompileTimerScope compile_timer(isolate, no_cache_reason, + const ScriptType script_type = script_details.origin_options.IsModule() + ? ScriptType::kModule + : ScriptType::kClassic; + ScriptCompileTimerScope compile_timer(isolate, no_cache_reason, script_type, compilation_details); if (compile_options & ScriptCompiler::kConsumeCodeCache) { @@ -4036,6 +4098,10 @@ MaybeDirectHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl( // Then check cached code provided by embedder. NestedTimedHistogramScope timer( isolate->counters()->compile_deserialize()); + NestedTimedHistogramScope script_type_timer( + script_type == ScriptType::kModule + ? isolate->counters()->compile_deserialize_module() + : isolate->counters()->compile_deserialize_classic()); RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileDeserialize); TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileDeserialize"); @@ -4062,6 +4128,13 @@ MaybeDirectHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl( // sufficiently unlikely, and ensuring a correct merge in the third case // would be non-trivial. } else { + NestedTimedHistogramScope main_thread_timer( + isolate->counters()->compile_deserialize_main_thread()); + NestedTimedHistogramScope main_thread_script_type_timer( + script_type == ScriptType::kModule + ? isolate->counters()->compile_deserialize_main_thread_module() + : isolate->counters() + ->compile_deserialize_main_thread_classic()); maybe_result = CodeSerializer::Deserialize( isolate, cached_data, source, script_details, maybe_script); } @@ -4096,10 +4169,7 @@ MaybeDirectHandle<SharedFunctionInfo> GetSharedFunctionInfoForScriptImpl( UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile( isolate, natives == NOT_NATIVES_CODE, language_mode, - script_details.repl_mode, - script_details.origin_options.IsModule() ? ScriptType::kModule - : ScriptType::kClassic, - v8_flags.lazy); + script_details.repl_mode, script_type, v8_flags.lazy); flags.set_is_eager(compile_options & ScriptCompiler::kEagerCompile); flags.set_compile_hints_magic_enabled( @@ -4211,8 +4281,8 @@ MaybeDirectHandle<JSFunction> Compiler::GetWrappedFunction( v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason) { ScriptCompiler::CompilationDetails compilation_details; - ScriptCompileTimerScope compile_timer(isolate, no_cache_reason, - &compilation_details); + ScriptCompileTimerScope compile_timer( + isolate, no_cache_reason, ScriptType::kClassic, &compilation_details); if (compile_options & ScriptCompiler::kConsumeCodeCache) { DCHECK(cached_data); @@ -4241,6 +4311,12 @@ MaybeDirectHandle<JSFunction> Compiler::GetWrappedFunction( compile_timer.set_consuming_code_cache(); // Then check cached code provided by embedder. NestedTimedHistogramScope timer(isolate->counters()->compile_deserialize()); + NestedTimedHistogramScope script_type_timer( + isolate->counters()->compile_deserialize_classic()); + NestedTimedHistogramScope main_thread_timer( + isolate->counters()->compile_deserialize_main_thread()); + NestedTimedHistogramScope main_thread_script_type_timer( + isolate->counters()->compile_deserialize_main_thread_classic()); RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileDeserialize); TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileDeserialize"); @@ -4262,6 +4338,10 @@ MaybeDirectHandle<JSFunction> Compiler::GetWrappedFunction( } if (maybe_result.is_null()) { + NestedTimedHistogramScope main_thread_timer( + isolate->counters()->compile_script_main_thread()); + NestedTimedHistogramScope main_thread_script_type_timer( + isolate->counters()->compile_script_main_thread_classic()); UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForToplevelCompile( isolate, true, language_mode, script_details.repl_mode, ScriptType::kClassic, v8_flags.lazy); @@ -4327,6 +4407,8 @@ Compiler::GetSharedFunctionInfoForStreamedScript( ScriptCompileTimerScope compile_timer( isolate, ScriptCompiler::kNoCacheBecauseStreamingSource, + script_details.origin_options.IsModule() ? ScriptType::kModule + : ScriptType::kClassic, compilation_details); PostponeInterruptsScope postpone(isolate); diff --git a/deps/v8/src/codegen/compiler.h b/deps/v8/src/codegen/compiler.h index cfa6af01010b..cc4af6529a28 100644 --- a/deps/v8/src/codegen/compiler.h +++ b/deps/v8/src/codegen/compiler.h @@ -24,6 +24,7 @@ #include "src/objects/debug-objects.h" #include "src/parsing/parse-info.h" #include "src/parsing/pending-compilation-error-handler.h" +#include "src/parsing/scanner.h" // For Scanner::DebugMagicCommentLocations. #include "src/snapshot/code-serializer.h" #include "src/utils/allocation.h" #include "src/zone/zone.h" @@ -166,7 +167,8 @@ class V8_EXPORT_PRIVATE Compiler : public AllStatic { ParseRestriction restriction, int parameters_end_pos, int eval_position, ParsingWhileDebugging parsing_while_debugging = - ParsingWhileDebugging::kNo); + ParsingWhileDebugging::kNo, + bool private_name_lookup_skips_outer_class = false); // Create a function that results from wrapping |source| in a function, // with |arguments| being a list of parameters for that function. @@ -432,6 +434,12 @@ class OptimizedCompilationJob : public CompilationJob { return timer_.Elapsed(); } + using RetainedMaps = base::SmallVector<IndirectHandle<Map>, 8>; + + static RetainedMaps CollectRetainedMaps( + DirectHandle<Code> code, + std::unique_ptr<CanonicalHandlesMap> canonical_handles); + protected: // Overridden by the actual implementation. virtual Status PrepareJobImpl(Isolate* isolate) = 0; @@ -440,12 +448,9 @@ class OptimizedCompilationJob : public CompilationJob { virtual Status FinalizeJobImpl(Isolate* isolate) = 0; // Register weak object to optimized code dependencies. - GlobalHandleVector<Map> CollectRetainedMaps(Isolate* isolate, - DirectHandle<Code> code); - void RegisterWeakObjectsInOptimizedCode(Isolate* isolate, - DirectHandle<NativeContext> context, - DirectHandle<Code> code, - GlobalHandleVector<Map> maps); + void RegisterWeakObjectsInOptimizedCode( + Isolate* isolate, DirectHandle<NativeContext> context, + DirectHandle<Code> code, base::Vector<const IndirectHandle<Map>> maps); base::TimeDelta time_taken_to_prepare_; base::TimeDelta time_taken_to_execute_; @@ -649,6 +654,9 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask { DeferredFinalizationJobDataList jobs_to_retry_finalization_on_main_thread_; base::SmallVector<v8::Isolate::UseCounterFeature, 8> use_counts_; int total_preparse_skipped_ = 0; + // The source is not available on the background thread, so the debug magic + // comment values are created from these locations when finalizing. + Scanner::DebugMagicCommentLocations debug_magic_comment_locations_; // Single function data for top-level function compilation. MaybeIndirectHandle<SharedFunctionInfo> input_shared_info_; diff --git a/deps/v8/src/codegen/cpu-features.h b/deps/v8/src/codegen/cpu-features.h index fdaa3e15aa37..80fb29cf1856 100644 --- a/deps/v8/src/codegen/cpu-features.h +++ b/deps/v8/src/codegen/cpu-features.h @@ -68,6 +68,10 @@ enum CpuFeature { SVE, // Scalable Vector Bit Permutes instructions SVEBITPERM, + // Scalable Vector Extension 2 + SVE2, + // Load-Acquire RCpc instructions v2 (LDAPUR and STLUR with unscaled offset) + LRCPC2, #elif V8_TARGET_ARCH_MIPS64 FPU, @@ -172,6 +176,9 @@ class V8_EXPORT_PRIVATE CpuFeatures : public AllStatic { return vlen_; } + // Current thread's SVE vector length in bytes, 0 if unavailable. + static unsigned svevlen(); + static void PrintInformation(); private: diff --git a/deps/v8/src/codegen/external-reference.cc b/deps/v8/src/codegen/external-reference.cc index 55aa84225782..6afe06549619 100644 --- a/deps/v8/src/codegen/external-reference.cc +++ b/deps/v8/src/codegen/external-reference.cc @@ -308,33 +308,6 @@ ExternalReference ExternalReference::empty_backing_store_buffer() { Sandbox::current()->constants().empty_backing_store_buffer_address()); } -ExternalReference ExternalReference::external_pointer_table_address( - Isolate* isolate) { - return ExternalReference(isolate->external_pointer_table_address()); -} - -ExternalReference -ExternalReference::shared_external_pointer_table_address_address( - Isolate* isolate) { - return ExternalReference( - isolate->shared_external_pointer_table_address_address()); -} - -ExternalReference ExternalReference::trusted_pointer_table_base_address( - Isolate* isolate) { - // TODO(saelo): maybe the external pointer table external references should - // also directly return the table base address? - return ExternalReference(isolate->trusted_pointer_table_base_address()); -} - -ExternalReference ExternalReference::shared_trusted_pointer_table_base_address( - Isolate* isolate) { - // TODO(saelo): maybe the external pointer table external references should - // also directly return the table base address? - return ExternalReference( - isolate->shared_trusted_pointer_table_base_address()); -} - ExternalReference ExternalReference::memory_chunk_metadata_table_address() { return ExternalReference( reinterpret_cast<Address>(MemoryChunk::MetadataTableAddress())); @@ -465,8 +438,8 @@ FUNCTION_REFERENCE(ieee754_fp16_raw_bits_to_fp32_raw_bits, FUNCTION_REFERENCE(write_barrier_marking_from_code_function, WriteBarrier::MarkingFromCode) -FUNCTION_REFERENCE(write_barrier_indirect_pointer_marking_from_code_function, - WriteBarrier::IndirectPointerMarkingFromCode) +FUNCTION_REFERENCE(write_barrier_trusted_pointer_marking_from_code_function, + WriteBarrier::TrustedPointerMarkingFromCode) FUNCTION_REFERENCE(write_barrier_shared_marking_from_code_function, WriteBarrier::SharedMarkingFromCode) @@ -480,8 +453,8 @@ FUNCTION_REFERENCE(insert_remembered_set_function, FUNCTION_REFERENCE(verify_skipped_write_barrier, Heap::VerifySkippedWriteBarrier) -FUNCTION_REFERENCE(verify_skipped_indirect_write_barrier, - Heap::VerifySkippedIndirectWriteBarrier) +FUNCTION_REFERENCE(verify_skipped_trusted_write_barrier, + Heap::VerifySkippedTrustedWriteBarrier) namespace { @@ -595,7 +568,6 @@ FUNCTION_REFERENCE(wasm_switch_from_the_central_stack_for_js, wasm::switch_from_the_central_stack_for_js) FUNCTION_REFERENCE(wasm_grow_stack, wasm::grow_stack) FUNCTION_REFERENCE(wasm_shrink_stack, wasm::shrink_stack) -FUNCTION_REFERENCE(wasm_load_old_fp, wasm::load_old_fp) FUNCTION_REFERENCE(wasm_f32_trunc, wasm::f32_trunc_wrapper) FUNCTION_REFERENCE(wasm_f32_floor, wasm::f32_floor_wrapper) FUNCTION_REFERENCE(wasm_f32_ceil, wasm::f32_ceil_wrapper) @@ -714,7 +686,7 @@ class GCedBuffer final : public cppgc::GarbageCollected<GCedBuffer> { void Trace(cppgc::Visitor* visitor) const {} }; -void* allocate_buffer_impl(Isolate* isolate, size_t size) { +void* allocate_buffer_impl(Isolate* isolate, uint32_t size) { void* result = cppgc::MakeGarbageCollected<GCedBuffer>( isolate->heap()->cpp_heap()->GetAllocationHandle(), cppgc::AdditionalBytes(size)); @@ -854,10 +826,6 @@ ExternalReference ExternalReference::address_of_runtime_stats_flag() { return ExternalReference(&TracingFlags::runtime_stats); } -ExternalReference ExternalReference::address_of_shared_string_table_flag() { - return ExternalReference(&v8_flags.shared_string_table); -} - ExternalReference ExternalReference::address_of_track_array_buffer_views_flag() { return ExternalReference(&v8_flags.track_array_buffer_views); @@ -1153,20 +1121,9 @@ ExternalReference::address_of_regexp_static_result_offsets_vector( isolate->address_of_regexp_static_result_offsets_vector()); } -ExternalReference ExternalReference::address_of_regexp_stack_limit_address( +ExternalReference ExternalReference::address_of_regexp_stack_thread_local( Isolate* isolate) { - return ExternalReference(isolate->regexp_stack()->limit_address_address()); -} - -ExternalReference ExternalReference::address_of_regexp_stack_memory_top_address( - Isolate* isolate) { - return ExternalReference( - isolate->regexp_stack()->memory_top_address_address()); -} - -ExternalReference ExternalReference::address_of_regexp_stack_stack_pointer( - Isolate* isolate) { - return ExternalReference(isolate->regexp_stack()->stack_pointer_address()); + return ExternalReference(isolate->regexp_stack()->thread_local_address()); } FUNCTION_REFERENCE_WITH_TYPE(ieee754_acos_function, base::ieee754::acos, @@ -1893,17 +1850,39 @@ void tsan_release_store_64_bits(Address addr, int64_t value) { #endif // V8_TARGET_ARCH_X64 } -// Same as above, for relaxed loads. -base::Atomic32 tsan_relaxed_load_32_bits(Address addr, int64_t value) { +// Similarly like above, for relaxed loads. +// If `invoke_tsan_acquire`, the `shared_base` parameter is a wasm shared object +// and is the base object of `addr`. In that case we must invoke TSAN_ACQUIRE +// to define the dependence between the initialization release fence and this +// load. +base::Atomic32 tsan_relaxed_load_32_bits(Address addr, Address shared_base, + int32_t invoke_tsan_acquire) { #if V8_TARGET_ARCH_X64 + if (invoke_tsan_acquire) { + // We might reach this point with a non-shared object, because wasm anyref + // may hold a shared reference. + Tagged<HeapObject> object( + reinterpret_cast<HeapObject*>(shared_base - kHeapObjectTag)); + if (HeapLayout::InWritableSharedSpace(object)) { + TSAN_ACQUIRE(object.address()); + } + } return base::Relaxed_Load(reinterpret_cast<base::Atomic32*>(addr)); #else UNREACHABLE(); #endif // V8_TARGET_ARCH_X64 } -base::Atomic64 tsan_relaxed_load_64_bits(Address addr, int64_t value) { +base::Atomic64 tsan_relaxed_load_64_bits(Address addr, Address shared_base, + int32_t invoke_tsan_acquire) { #if V8_TARGET_ARCH_X64 + if (invoke_tsan_acquire) { + Tagged<HeapObject> object( + reinterpret_cast<HeapObject*>(shared_base - kHeapObjectTag)); + if (HeapLayout::InWritableSharedSpace(object)) { + TSAN_ACQUIRE(object.address()); + } + } return base::Relaxed_Load(reinterpret_cast<base::Atomic64*>(addr)); #else UNREACHABLE(); diff --git a/deps/v8/src/codegen/external-reference.h b/deps/v8/src/codegen/external-reference.h index 87881c862b35..6c47d7b7f991 100644 --- a/deps/v8/src/codegen/external-reference.h +++ b/deps/v8/src/codegen/external-reference.h @@ -62,31 +62,12 @@ enum class IsolateFieldId : uint8_t; V(debug_suspended_generator_address, \ "Debug::step_suspended_generator_address()") \ V(context_address, "Isolate::context_address()") \ - V(address_of_regexp_stack_limit_address, \ - "regexp::Stack::limit_address_address()") \ - V(address_of_regexp_stack_memory_top_address, \ - "regexp::Stack::memory_top_address_address()") \ - V(address_of_regexp_stack_stack_pointer, \ - "regexp::Stack::stack_pointer_address()") \ + V(address_of_regexp_stack_thread_local, \ + "regexp::Stack::thread_local_address()") \ V(address_of_regexp_static_result_offsets_vector, \ "Isolate::address_of_regexp_static_result_offsets_vector") \ - EXTERNAL_REFERENCE_LIST_WITH_ISOLATE_SANDBOX(V) \ EXTERNAL_REFERENCE_LIST_LEAPTIERING(V) -#ifdef V8_ENABLE_SANDBOX -#define EXTERNAL_REFERENCE_LIST_WITH_ISOLATE_SANDBOX(V) \ - V(external_pointer_table_address, \ - "Isolate::external_pointer_table_address()") \ - V(shared_external_pointer_table_address_address, \ - "Isolate::shared_external_pointer_table_address_address()") \ - V(trusted_pointer_table_base_address, \ - "Isolate::trusted_pointer_table_base_address()") \ - V(shared_trusted_pointer_table_base_address, \ - "Isolate::shared_trusted_pointer_table_base_address()") -#else -#define EXTERNAL_REFERENCE_LIST_WITH_ISOLATE_SANDBOX(V) -#endif // V8_ENABLE_SANDBOX - #ifdef V8_ENABLE_REGEXP_DIAGNOSTICS #define EXTERNAL_REFERENCE_LIST_REGEXP_DIAGNOSTICS(V) \ V(address_of_trace_regexp_exec, "v8_flags.trace_regexp_exec") \ @@ -116,7 +97,6 @@ enum class IsolateFieldId : uint8_t; "v8_flags.mock_arraybuffer_allocator") \ V(address_of_one_half, "LDoubleConstant::one_half") \ V(address_of_runtime_stats_flag, "TracingFlags::runtime_stats") \ - V(address_of_shared_string_table_flag, "v8_flags.shared_string_table") \ V(address_of_the_hole_nan, "the_hole_nan") \ V(address_of_track_array_buffer_views_flag, \ "v8_flags.track_array_buffer_view") \ @@ -263,8 +243,8 @@ enum class IsolateFieldId : uint8_t; "simple_name_dictionary_lookup_forwarded_string") \ V(simple_name_dictionary_find_insertion_entry_forwarded_string, \ "simple_name_dictionary_find_insertion_entry_forwarded_string") \ - V(verify_skipped_indirect_write_barrier, \ - "Heap::VerifySkippedIndirectWriteBarrier") \ + V(verify_skipped_trusted_write_barrier, \ + "Heap::VerifySkippedTrustedWriteBarrier") \ V(verify_skipped_write_barrier, "Heap::VerifySkippedWriteBarrier") \ IF_WASM(V, wasm_start_stack, "wasm_start_stack") \ IF_WASM(V, wasm_suspender_has_js_frames, "wasm_suspender_has_js_frames") \ @@ -289,7 +269,6 @@ enum class IsolateFieldId : uint8_t; IF_WASM(V, wasm_code_pointer_table, "GetProcessWideWasmCodePointerTable()") \ IF_WASM(V, wasm_grow_stack, "wasm::grow_stack") \ IF_WASM(V, wasm_shrink_stack, "wasm::shrink_stack") \ - IF_WASM(V, wasm_load_old_fp, "wasm::load_old_fp") \ IF_WASM(V, wasm_f32_ceil, "wasm::f32_ceil_wrapper") \ IF_WASM(V, wasm_f32_floor, "wasm::f32_floor_wrapper") \ IF_WASM(V, wasm_f32_nearest_int, "wasm::f32_nearest_int_wrapper") \ @@ -442,8 +421,8 @@ enum class IsolateFieldId : uint8_t; "wasm_i32x8_int32_overflow_as_float") \ V(supports_cetss_address, "CpuFeatures::supports_cetss_address") \ V(write_barrier_marking_from_code_function, "WriteBarrier::MarkingFromCode") \ - V(write_barrier_indirect_pointer_marking_from_code_function, \ - "WriteBarrier::IndirectPointerMarkingFromCode") \ + V(write_barrier_trusted_pointer_marking_from_code_function, \ + "WriteBarrier::TrustedPointerMarkingFromCode") \ V(write_barrier_shared_marking_from_code_function, \ "WriteBarrier::SharedMarkingFromCode") \ V(shared_barrier_from_code_function, "WriteBarrier::SharedFromCode") \ diff --git a/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc b/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc index 35852941b892..af7735aaa68b 100644 --- a/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/codegen/ia32/macro-assembler-ia32.cc @@ -1083,13 +1083,6 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), Immediate(StackFrame::TypeToMarker(type))); j(equal, &ok, Label::kNear); -#if V8_ENABLE_WEBASSEMBLY - if (type == StackFrame::WASM && v8_flags.wasm_growable_stacks) { - cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - j(equal, &ok, Label::kNear); - } -#endif Abort(AbortReason::kStackFrameTypesMustMatch); bind(&ok); } @@ -2087,7 +2080,7 @@ void MacroAssembler::LoadEntrypointFromJSDispatchTable( } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); mov(ecx, FieldOperand(function_object, offsetof(JSFunction, dispatch_handle_))); diff --git a/deps/v8/src/codegen/ia32/macro-assembler-ia32.h b/deps/v8/src/codegen/ia32/macro-assembler-ia32.h index e864b884f6ab..22654ee68a30 100644 --- a/deps/v8/src/codegen/ia32/macro-assembler-ia32.h +++ b/deps/v8/src/codegen/ia32/macro-assembler-ia32.h @@ -177,7 +177,8 @@ class V8_EXPORT_PRIVATE MacroAssembler JumpMode jump_mode = JumpMode::kJump); // Convenience functions to call/jmp to the code of a JSFunction object. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); #ifdef V8_ENABLE_WEBASSEMBLY diff --git a/deps/v8/src/codegen/interface-descriptors-inl.h b/deps/v8/src/codegen/interface-descriptors-inl.h index 2f93e57a8a0a..2f40018f09bd 100644 --- a/deps/v8/src/codegen/interface-descriptors-inl.h +++ b/deps/v8/src/codegen/interface-descriptors-inl.h @@ -331,33 +331,32 @@ constexpr RegList WriteBarrierDescriptor::ComputeSavedRegisters( } // static -constexpr auto IndirectPointerWriteBarrierDescriptor::registers() { +constexpr auto TrustedPointerWriteBarrierDescriptor::registers() { return WriteBarrierDescriptor::registers(); } // static -constexpr Register IndirectPointerWriteBarrierDescriptor::ObjectRegister() { +constexpr Register TrustedPointerWriteBarrierDescriptor::ObjectRegister() { return std::get<kObject>(registers()); } // static -constexpr Register -IndirectPointerWriteBarrierDescriptor::SlotAddressRegister() { +constexpr Register TrustedPointerWriteBarrierDescriptor::SlotAddressRegister() { return std::get<kSlotAddress>(registers()); } // static constexpr Register -IndirectPointerWriteBarrierDescriptor::IndirectPointerTagRegister() { - return std::get<kIndirectPointerTag>(registers()); +TrustedPointerWriteBarrierDescriptor::TrustedPointerTagRegister() { + return std::get<kTrustedPointerTag>(registers()); } // static -constexpr RegList IndirectPointerWriteBarrierDescriptor::ComputeSavedRegisters( +constexpr RegList TrustedPointerWriteBarrierDescriptor::ComputeSavedRegisters( Register object, Register slot_address) { DCHECK(!AreAliased(object, slot_address)); // This write barrier behaves identical to the generic one, except that it // passes one additional parameter. RegList saved_registers = WriteBarrierDescriptor::ComputeSavedRegisters(object, slot_address); - saved_registers.set(IndirectPointerTagRegister()); + saved_registers.set(TrustedPointerTagRegister()); return saved_registers; } @@ -629,6 +628,12 @@ constexpr auto GetIteratorStackParameterDescriptor::registers() { return RegisterArray(); } +// static +constexpr auto +ProxyGetPropertyTrapResultLazyDeoptContinuationDescriptor::registers() { + return RegisterArray(); +} + // static constexpr auto ForOfNextResultDeoptContinuationDescriptor::registers() { return RegisterArray(); @@ -822,6 +827,11 @@ constexpr inline Register WasmHandleStackOverflowDescriptor::GapRegister() { return std::get<kGap>(registers()); } +constexpr inline Register +WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister() { + return std::get<kParameterSlotsSize>(registers()); +} + constexpr auto WasmToJSWrapperDescriptor::registers() { #if V8_ENABLE_WEBASSEMBLY return RegisterArray(wasm::kGpParamRegisters[0]); diff --git a/deps/v8/src/codegen/interface-descriptors.cc b/deps/v8/src/codegen/interface-descriptors.cc index dad687c569d9..bacc437e8b3d 100644 --- a/deps/v8/src/codegen/interface-descriptors.cc +++ b/deps/v8/src/codegen/interface-descriptors.cc @@ -176,7 +176,7 @@ void WriteBarrierDescriptor::Verify(CallInterfaceDescriptorData* data) { VerifyArgumentRegisterCount(data, 4); } // static -void IndirectPointerWriteBarrierDescriptor::Verify( +void TrustedPointerWriteBarrierDescriptor::Verify( CallInterfaceDescriptorData* data) { WriteBarrierDescriptor::Verify(data); } diff --git a/deps/v8/src/codegen/interface-descriptors.h b/deps/v8/src/codegen/interface-descriptors.h index 9da51025d9fc..9f957edd811e 100644 --- a/deps/v8/src/codegen/interface-descriptors.h +++ b/deps/v8/src/codegen/interface-descriptors.h @@ -135,6 +135,7 @@ namespace internal { V(NewHeapNumber) \ V(NoContext) \ V(OnStackReplacement) \ + V(ProxyGetPropertyTrapResultLazyDeoptContinuation) \ V(RegExpTrampoline) \ V(RestartFrameTrampoline) \ V(ResumeGenerator) \ @@ -176,7 +177,7 @@ namespace internal { V(WasmSuspend) \ V(WasmHandleStackOverflow) \ V(WriteBarrier) \ - V(IndirectPointerWriteBarrier) \ + V(TrustedPointerWriteBarrier) \ SELECT_TSA_LEVEL(IGNORE_BUILTIN, V, IGNORE_BUILTIN, ToString) \ IF_TSAN(V, TSANLoad) \ IF_TSAN(V, TSANStore) \ @@ -885,14 +886,17 @@ class WasmHandleStackOverflowDescriptor public: INTERNAL_DESCRIPTOR() SANDBOXING_MODE(kSandboxed) - DEFINE_PARAMETERS_NO_CONTEXT(kFrameBase, kGap) - DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), // result - MachineType::Pointer(), // kFrameBase - MachineType::Uint32()) // kGap + DEFINE_PARAMETERS_NO_CONTEXT(kFrameBase, kGap, kParameterSlotsSize) + DEFINE_RESULT_AND_PARAMETER_TYPES( + MachineType::AnyTagged(), // result + MachineType::Pointer(), // kFrameBase + MachineType::Uint32(), // kGap + MachineType::IntPtr()) // kParameterSlotsSize DECLARE_DESCRIPTOR(WasmHandleStackOverflowDescriptor) static constexpr inline Register FrameBaseRegister(); static constexpr inline Register GapRegister(); + static constexpr inline Register ParameterSlotsSizeRegister(); }; class AllocateDescriptor @@ -1701,26 +1705,26 @@ class WriteBarrierDescriptor final }; // Write barriers for indirect pointer field writes require one additional -// parameter (the IndirectPointerTag associated with the stored field). +// parameter (the TrustedPointerTag associated with the stored field). // Otherwise, they are identical to the other write barriers. -class IndirectPointerWriteBarrierDescriptor final +class TrustedPointerWriteBarrierDescriptor final : public StaticCallInterfaceDescriptor< - IndirectPointerWriteBarrierDescriptor> { + TrustedPointerWriteBarrierDescriptor> { public: INTERNAL_DESCRIPTOR() SANDBOXING_MODE(kSandboxed) - DEFINE_PARAMETERS_NO_CONTEXT(kObject, kSlotAddress, kIndirectPointerTag) + DEFINE_PARAMETERS_NO_CONTEXT(kObject, kSlotAddress, kTrustedPointerTag) DEFINE_PARAMETER_TYPES(MachineType::TaggedPointer(), // kObject MachineType::Pointer(), // kSlotAddress - MachineType::Uint64()) // kIndirectPointerTag + MachineType::Uint64()) // kTrustedPointerTag - DECLARE_DESCRIPTOR(IndirectPointerWriteBarrierDescriptor) + DECLARE_DESCRIPTOR(TrustedPointerWriteBarrierDescriptor) static constexpr auto registers(); static constexpr bool kRestrictAllocatableRegisters = true; static constexpr bool kCalleeSaveRegisters = true; static constexpr inline Register ObjectRegister(); static constexpr inline Register SlotAddressRegister(); - static constexpr inline Register IndirectPointerTagRegister(); + static constexpr inline Register TrustedPointerTagRegister(); static constexpr inline RegList ComputeSavedRegisters( Register object, Register slot_address = no_reg); #if DEBUG @@ -1749,8 +1753,10 @@ class TSANLoadDescriptor final public: INTERNAL_DESCRIPTOR() SANDBOXING_MODE(kSandboxed) - DEFINE_PARAMETERS_NO_CONTEXT(kAddress) - DEFINE_PARAMETER_TYPES(MachineType::Pointer()) // kAddress + DEFINE_PARAMETERS_NO_CONTEXT(kAddress, kSharedBase, kInvokeTsanAcquire) + DEFINE_PARAMETER_TYPES(MachineType::Pointer(), // kAddress + MachineType::AnyTagged(), // kBase + MachineType::Int32()) // kInvokeTsanAcquire DECLARE_DESCRIPTOR(TSANLoadDescriptor) @@ -1835,6 +1841,23 @@ class GetIteratorStackParameterDescriptor final static constexpr auto registers(); }; +class ProxyGetPropertyTrapResultLazyDeoptContinuationDescriptor final + : public StaticCallInterfaceDescriptor< + ProxyGetPropertyTrapResultLazyDeoptContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTarget, kProxy, kName, kTrapResult) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), // result value + MachineType::AnyTagged(), // kTarget + MachineType::AnyTagged(), // kProxy + MachineType::AnyTagged(), // kName + MachineType::AnyTagged()) // kTrapResult + DECLARE_DESCRIPTOR(ProxyGetPropertyTrapResultLazyDeoptContinuationDescriptor) + + static constexpr auto registers(); +}; + class ForOfNextResultDeoptContinuationDescriptor final : public StaticCallInterfaceDescriptor< ForOfNextResultDeoptContinuationDescriptor> { @@ -3294,8 +3317,14 @@ BUILTIN_LIST_TFS(DEFINE_TFS_BUILTIN_DESCRIPTOR) // This file contains interface descriptor class definitions for builtins // defined in Torque. It is included here because the class definitions need to -// precede the definition of name##Descriptor::key() below. -#include "torque-generated/interface-descriptors.inc" +// precede the definition of name##Descriptor::key() below. It is the checked-in +// copy under src/gen/ if v8_use_checked_in_generated_headers, the generated +// file otherwise. See src/gen/README.md. +#ifdef V8_USE_CHECKED_IN_GENERATED_HEADERS +#include "src/gen/intl-wasm/interface-descriptors.inc" +#else +#include "torque-generated/interface-descriptors.inc" // nogncheck +#endif #undef DECLARE_DEFAULT_DESCRIPTOR #undef DECLARE_DESCRIPTOR_WITH_BASE diff --git a/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc b/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc index cf8c680be936..2f362d2a3fac 100644 --- a/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc +++ b/deps/v8/src/codegen/loong64/macro-assembler-loong64.cc @@ -452,9 +452,14 @@ void MacroAssembler::LoadExternalPointerField(Register destination, void MacroAssembler::LoadTrustedPointerField(Register destination, MemOperand field_operand, - IndirectPointerTag tag) { + TrustedPointerTagRange tag_range) { #ifdef V8_ENABLE_SANDBOX - LoadIndirectPointerField(destination, field_operand, tag); + ASM_CODE_COMMENT(this); + UseScratchRegisterScope temps(this); + Register handle = temps.Acquire(); + Ld_wu(handle, field_operand); + + ResolveTrustedPointerHandle(destination, handle, tag_range); #else LoadTaggedField(destination, field_operand); #endif @@ -477,10 +482,10 @@ void MacroAssembler::LoadTrustedUnknownPointerField( Register handle = scratch; Ld_wu(handle, field_operand); - static_assert(kNullIndirectPointerHandle == 0); + static_assert(kNullTrustedPointerHandle == 0); Branch(is_unavailable, eq, handle, Operand(zero_reg)); - ResolveIndirectPointerHandle(destination, handle, kAllIndirectPointerTags); + ResolveTrustedPointerHandle(destination, handle, kAllTrustedPointerTags); } #else LoadTaggedField(destination, field_operand); @@ -509,46 +514,22 @@ void MacroAssembler::LoadTrustedUnknownPointerField( } void MacroAssembler::StoreTrustedPointerField(Register value, - MemOperand dst_field_operand) { -#ifdef V8_ENABLE_SANDBOX - StoreIndirectPointerField(value, dst_field_operand); -#else - StoreTaggedField(value, dst_field_operand); -#endif -} - -void MacroAssembler::LoadIndirectPointerField( - Register destination, MemOperand field_operand, - IndirectPointerTagRange tag_range) { -#ifdef V8_ENABLE_SANDBOX - ASM_CODE_COMMENT(this); - UseScratchRegisterScope temps(this); - Register handle = temps.Acquire(); - Ld_wu(handle, field_operand); - - ResolveIndirectPointerHandle(destination, handle, tag_range); -#else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX -} - -void MacroAssembler::StoreIndirectPointerField(Register value, - MemOperand dst_field_operand, - int* trap_pc) { + MemOperand dst_field_operand, + int* trap_pc) { #ifdef V8_ENABLE_SANDBOX UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); Ld_w(scratch, FieldMemOperand(value, offsetof(ExposedTrustedObject, - self_indirect_pointer_))); + self_trusted_pointer_))); St_w(scratch, dst_field_operand, trap_pc); #else - UNREACHABLE(); + StoreTaggedField(value, dst_field_operand, trap_pc); #endif } #ifdef V8_ENABLE_SANDBOX -void MacroAssembler::ResolveIndirectPointerHandle( - Register destination, Register handle, IndirectPointerTagRange tag_range) { +void MacroAssembler::ResolveTrustedPointerHandle( + Register destination, Register handle, TrustedPointerTagRange tag_range) { DCHECK(!AreAliased(handle, destination)); DCHECK(root_array_available_); @@ -559,8 +540,8 @@ void MacroAssembler::ResolveIndirectPointerHandle( Alsl_d(destination, handle, table, kTrustedPointerTableEntrySizeLog2); Ld_d(destination, MemOperand(destination, 0)); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); And(destination, destination, Operand(mask)); } else { Register tag_reg = handle; @@ -702,22 +683,21 @@ void MacroAssembler::CallEphemeronKeyBarrier(Register object, Operand offset, MaybeRestoreRegisters(registers); } -void MacroAssembler::CallIndirectPointerBarrier(Register object, Operand offset, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag) { +void MacroAssembler::CallTrustedPointerBarrier(Register object, Operand offset, + SaveFPRegsMode fp_mode, + TrustedPointerTag tag) { ASM_CODE_COMMENT(this); RegList registers = - IndirectPointerWriteBarrierDescriptor::ComputeSavedRegisters(object); + TrustedPointerWriteBarrierDescriptor::ComputeSavedRegisters(object); MaybeSaveRegisters(registers); - MoveObjectAndSlot( - IndirectPointerWriteBarrierDescriptor::ObjectRegister(), - IndirectPointerWriteBarrierDescriptor::SlotAddressRegister(), object, - offset); - li(IndirectPointerWriteBarrierDescriptor::IndirectPointerTagRegister(), + MoveObjectAndSlot(TrustedPointerWriteBarrierDescriptor::ObjectRegister(), + TrustedPointerWriteBarrierDescriptor::SlotAddressRegister(), + object, offset); + li(TrustedPointerWriteBarrierDescriptor::TrustedPointerTagRegister(), Operand(tag)); - CallBuiltin(Builtins::IndirectPointerBarrier(fp_mode)); + CallBuiltin(Builtins::TrustedPointerBarrier(fp_mode)); MaybeRestoreRegisters(registers); } @@ -779,22 +759,22 @@ void MacroAssembler::CallVerifySkippedWriteBarrierStub(Register object, SetIsolateDataSlots::kNo); } -void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStubSaveRegisters( +void MacroAssembler::CallVerifySkippedTrustedWriteBarrierStubSaveRegisters( Register object, Register value, SaveFPRegsMode fp_mode) { ASM_CODE_COMMENT(this); PushCallerSaved(fp_mode); - CallVerifySkippedIndirectWriteBarrierStub(object, value); + CallVerifySkippedTrustedWriteBarrierStub(object, value); PopCallerSaved(fp_mode); } -void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStub(Register object, - Register value) { +void MacroAssembler::CallVerifySkippedTrustedWriteBarrierStub(Register object, + Register value) { ASM_CODE_COMMENT(this); UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); PrepareCallCFunction(2, scratch); MovePair(kCArgRegs[0], object, kCArgRegs[1], value); - CallCFunction(ExternalReference::verify_skipped_indirect_write_barrier(), 2, + CallCFunction(ExternalReference::verify_skipped_trusted_write_barrier(), 2, SetIsolateDataSlots::kNo); } @@ -847,9 +827,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); Add_d(scratch, object, offset); - if (slot.contains_indirect_pointer()) { - LoadIndirectPointerField(scratch, MemOperand(scratch, 0), - slot.indirect_pointer_tag()); + if (slot.contains_trusted_pointer()) { + LoadTrustedPointerField(scratch, MemOperand(scratch, 0), + slot.trusted_pointer_tag()); } else { DCHECK(slot.contains_direct_pointer()); LoadTaggedField(scratch, MemOperand(scratch, 0)); @@ -876,7 +856,7 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, JumpIfSmi(value, &done); } - if (slot.contains_indirect_pointer()) { + if (slot.contains_trusted_pointer()) { // The indirect pointer write barrier is only enabled during marking. JumpIfNotMarking(&done); } else { @@ -900,9 +880,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, CallRecordWriteStub(object, slot_address, fp_mode, StubCallMode::kCallBuiltinPointer); } else { - DCHECK(slot.contains_indirect_pointer()); - CallIndirectPointerBarrier(object, offset, fp_mode, - slot.indirect_pointer_tag()); + DCHECK(slot.contains_trusted_pointer()); + CallTrustedPointerBarrier(object, offset, fp_mode, + slot.trusted_pointer_tag()); } if (ra_status == kRAHasNotBeenSaved) { Pop(ra); @@ -2839,19 +2819,35 @@ void MacroAssembler::RoundDouble(FPURegister dst, FPURegister src, } void MacroAssembler::Floor_d(FPURegister dst, FPURegister src) { - RoundDouble(dst, src, mode_floor); + if (IsEnabled(LSX)) { + vfrintrm_d(dst.toV(), src.toV()); + } else { + RoundDouble(dst, src, mode_floor); + } } void MacroAssembler::Ceil_d(FPURegister dst, FPURegister src) { - RoundDouble(dst, src, mode_ceil); + if (IsEnabled(LSX)) { + vfrintrp_d(dst.toV(), src.toV()); + } else { + RoundDouble(dst, src, mode_ceil); + } } void MacroAssembler::Trunc_d(FPURegister dst, FPURegister src) { - RoundDouble(dst, src, mode_trunc); + if (IsEnabled(LSX)) { + vfrintrz_d(dst.toV(), src.toV()); + } else { + RoundDouble(dst, src, mode_trunc); + } } void MacroAssembler::Round_d(FPURegister dst, FPURegister src) { - RoundDouble(dst, src, mode_round); + if (IsEnabled(LSX)) { + vfrintrne_d(dst.toV(), src.toV()); + } else { + RoundDouble(dst, src, mode_round); + } } void MacroAssembler::RoundFloat(FPURegister dst, FPURegister src, @@ -2868,19 +2864,35 @@ void MacroAssembler::RoundFloat(FPURegister dst, FPURegister src, } void MacroAssembler::Floor_s(FPURegister dst, FPURegister src) { - RoundFloat(dst, src, mode_floor); + if (IsEnabled(LSX)) { + vfrintrm_s(dst.toV(), src.toV()); + } else { + RoundFloat(dst, src, mode_floor); + } } void MacroAssembler::Ceil_s(FPURegister dst, FPURegister src) { - RoundFloat(dst, src, mode_ceil); + if (IsEnabled(LSX)) { + vfrintrp_s(dst.toV(), src.toV()); + } else { + RoundFloat(dst, src, mode_ceil); + } } void MacroAssembler::Trunc_s(FPURegister dst, FPURegister src) { - RoundFloat(dst, src, mode_trunc); + if (IsEnabled(LSX)) { + vfrintrz_s(dst.toV(), src.toV()); + } else { + RoundFloat(dst, src, mode_trunc); + } } void MacroAssembler::Round_s(FPURegister dst, FPURegister src) { - RoundFloat(dst, src, mode_round); + if (IsEnabled(LSX)) { + vfrintrne_s(dst.toV(), src.toV()); + } else { + RoundFloat(dst, src, mode_round); + } } void MacroAssembler::CompareF(FPURegister cmp1, FPURegister cmp2, @@ -4209,8 +4221,8 @@ void MacroAssembler::StoreReturnAddressAndCall(Register target) { St_d(ra, MemOperand(sp, 0)); // Stack is still aligned. - // TODO(LOONG_dev): can be jirl target? a0 -- a7? - jirl(zero_reg, target, 0); + // Call the C routine. + jirl(ra, target, 0); // Make sure the stored 'ra' points to this position. DCHECK_EQ(kNumInstructionsToJump, InstructionsGeneratedSince(&find_ra)); } @@ -4609,16 +4621,18 @@ void MacroAssembler::InvokeFunctionCode( // call sites. LoadEntrypointFromJSDispatchTable(kJavaScriptCallCodeStartRegister, dispatch_handle, scratch); + Label done; switch (type) { case InvokeType::kCall: Call(kJavaScriptCallCodeStartRegister); + Branch(&done); break; case InvokeType::kJump: + // The tail jump does not return, so jumping to `done` here would be + // unreachable dead code. Jump(kJavaScriptCallCodeStartRegister); break; } - Label done; - Branch(&done); // Deferred debug hook. bind(&debug_hook); @@ -5926,7 +5940,7 @@ void MacroAssembler::JumpCodeObject(Register code_object, CodeEntrypointTag tag, } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = kJavaScriptCallDispatchHandleRegister; Register parameter_count = s1; @@ -5938,9 +5952,23 @@ void MacroAssembler::CallJSFunction(Register function_object, LoadEntrypointAndParameterCountFromJSDispatchTable(code, parameter_count, dispatch_handle, scratch); - // Force a safe crash if the parameter count doesn't match. - SbxCheck(le, AbortReason::kJSSignatureMismatch, parameter_count, - Operand(argument_count)); + // Force a safe crash if the parameter count doesn't match the expected count + // assumed at the call site, which would corrupt the stack on underapplication + // (caller pushes max(actual_argc, expected) slots; callee pops + // max(actual_argc, parameter_count) slots). + if (expected_parameter_count <= 1) { + // Both kDontAdaptArgumentsSentinel (0) and JSParameterCount(0) (1) are + // valid here: since actual_argc >= 1 (includes receiver), neither pads + // arguments and both pop actual_argc slots upon return. We cannot use an + // exact equality check because WasmToJS wrappers compute expected_arity + // via SFI::internal_formal_parameter_count_without_receiver(), which maps + // both cases to JSParameterCount(0) (1). + SbxCheck(le, AbortReason::kJSSignatureMismatch, parameter_count, + Operand(1)); + } else { + SbxCheck(eq, AbortReason::kJSSignatureMismatch, parameter_count, + Operand(expected_parameter_count)); + } Call(code); } diff --git a/deps/v8/src/codegen/loong64/macro-assembler-loong64.h b/deps/v8/src/codegen/loong64/macro-assembler-loong64.h index 7ee25e9a467d..ba536778f414 100644 --- a/deps/v8/src/codegen/loong64/macro-assembler-loong64.h +++ b/deps/v8/src/codegen/loong64/macro-assembler-loong64.h @@ -294,7 +294,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { // validate the parameter count at runtime. Instead, we should replace them // with CallJSDispatchEntry that generates a call to a given (compile-time // constant) JSDispatchHandle. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); @@ -390,9 +391,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { void CallEphemeronKeyBarrier(Register object, Operand offset, SaveFPRegsMode fp_mode); - void CallIndirectPointerBarrier(Register object, Operand offset, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag); + void CallTrustedPointerBarrier(Register object, Operand offset, + SaveFPRegsMode fp_mode, TrustedPointerTag tag); void CallRecordWriteStubSaveRegisters( Register object, Operand offset, SaveFPRegsMode fp_mode, @@ -406,10 +406,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { SaveFPRegsMode fp_mode); void CallVerifySkippedWriteBarrierStub(Register object, Register value); - void CallVerifySkippedIndirectWriteBarrierStubSaveRegisters( + void CallVerifySkippedTrustedWriteBarrierStubSaveRegisters( Register object, Register value, SaveFPRegsMode fp_mode); - void CallVerifySkippedIndirectWriteBarrierStub(Register object, - Register value); + void CallVerifySkippedTrustedWriteBarrierStub(Register object, + Register value); // For a given |object| and |offset|: // - Move |object| to |dst_object|. @@ -1087,8 +1087,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table. Otherwise they are regular tagged fields. void LoadTrustedPointerField(Register destination, MemOperand field_operand, - IndirectPointerTag tag); - // As above, but for kUnknownIndirectPointerTag. The type of the loaded object + TrustedPointerTagRange tag_range); + // As above, but for kUnknownTrustedPointerTag. The type of the loaded object // is unknown, so this helper will check for a series of expected types and // jump to the given labels if the loaded object has a matching type. If the // field is null (with enabled sandbox) or a Smi (with disabled sandbox) and @@ -1102,36 +1102,24 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { const std::initializer_list<std::tuple<InstanceType, Label*>>& cases, Label* is_unavailable = nullptr); // Store a trusted pointer field. - void StoreTrustedPointerField(Register value, MemOperand dst_field_operand); + void StoreTrustedPointerField(Register value, MemOperand dst_field_operand, + int* trap_pc = NULL); // Load a code pointer field. // These are special versions of trusted pointers that, when the sandbox is - // enabled, reference code objects through the code pointer table. + // enabled, reference code objects through the trusted pointer table. void LoadCodePointerField(Register destination, MemOperand field_operand) { - LoadTrustedPointerField(destination, field_operand, - kCodeIndirectPointerTag); + LoadTrustedPointerField(destination, field_operand, kCodeTrustedPointerTag); } // Store a code pointer field. void StoreCodePointerField(Register value, MemOperand dst_field_operand) { StoreTrustedPointerField(value, dst_field_operand); } - // Loads an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void LoadIndirectPointerField(Register destination, MemOperand field_operand, - IndirectPointerTagRange tag_range); - - // Store an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void StoreIndirectPointerField(Register value, MemOperand dst_field_operand, - int* trap_pc = NULL); - #ifdef V8_ENABLE_SANDBOX - // Retrieve the heap object referenced by the given indirect pointer handle. - void ResolveIndirectPointerHandle(Register destination, Register handle, - IndirectPointerTagRange tag_range); + // Retrieve the heap object referenced by the given trusted pointer handle. + void ResolveTrustedPointerHandle(Register destination, Register handle, + TrustedPointerTagRange tag_range); #endif void LoadEntrypointFromJSDispatchTable(Register destination, diff --git a/deps/v8/src/codegen/machine-type.cc b/deps/v8/src/codegen/machine-type.cc index 30a4aeb7f0c5..f14c15553ce6 100644 --- a/deps/v8/src/codegen/machine-type.cc +++ b/deps/v8/src/codegen/machine-type.cc @@ -63,8 +63,8 @@ const char* MachineReprToString(MachineRepresentation rep) { return "kRepCompressed"; case MachineRepresentation::kProtectedPointer: return "kRepProtectedPointer"; - case MachineRepresentation::kIndirectPointer: - return "kRepIndirectPointer"; + case MachineRepresentation::kTrustedPointer: + return "kRepTrustedPointer"; case MachineRepresentation::kMapWord: return "kRepMapWord"; case MachineRepresentation::kSandboxedPointer: diff --git a/deps/v8/src/codegen/machine-type.h b/deps/v8/src/codegen/machine-type.h index 18ca74eb4163..12e7337da8d7 100644 --- a/deps/v8/src/codegen/machine-type.h +++ b/deps/v8/src/codegen/machine-type.h @@ -43,7 +43,7 @@ enum class MachineRepresentation : uint8_t { kCompressedPointer, // (compressed) HeapObject kCompressed, // (compressed) Object (Smi or HeapObject) kProtectedPointer, // (uncompressed) TrustedObject - kIndirectPointer, // (indirect) HeapObject + kTrustedPointer, // (indirect) HeapObject // A 64-bit pointer encoded in a way (e.g. as offset) that guarantees it will // point into the sandbox. kSandboxedPointer, @@ -163,8 +163,8 @@ class MachineType { constexpr bool IsCompressedPointer() const { return representation() == MachineRepresentation::kCompressedPointer; } - constexpr bool IsIndirectPointer() const { - return representation() == MachineRepresentation::kIndirectPointer; + constexpr bool IsTrustedPointer() const { + return representation() == MachineRepresentation::kTrustedPointer; } constexpr static MachineRepresentation PointerRepresentation() { return (kSystemPointerSize == 4) ? MachineRepresentation::kWord32 @@ -266,8 +266,8 @@ class MachineType { return MachineType(MachineRepresentation::kProtectedPointer, MachineSemantic::kAny); } - constexpr static MachineType IndirectPointer() { - return MachineType(MachineRepresentation::kIndirectPointer, + constexpr static MachineType TrustedPointer() { + return MachineType(MachineRepresentation::kTrustedPointer, MachineSemantic::kInt32); } constexpr static MachineType Bool() { @@ -310,8 +310,8 @@ class MachineType { return MachineType::TaggedPointer(); case MachineRepresentation::kCompressed: return MachineType::AnyCompressed(); - case MachineRepresentation::kIndirectPointer: - return MachineType::IndirectPointer(); + case MachineRepresentation::kTrustedPointer: + return MachineType::TrustedPointer(); case MachineRepresentation::kCompressedPointer: return MachineType::CompressedPointer(); case MachineRepresentation::kSandboxedPointer: @@ -420,8 +420,8 @@ constexpr inline bool CanBeCompressedPointer(MachineRepresentation rep) { rep == MachineRepresentation::kCompressedPointer; } -constexpr inline bool CanBeIndirectPointer(MachineRepresentation rep) { - return rep == MachineRepresentation::kIndirectPointer; +constexpr inline bool CanBeTrustedPointer(MachineRepresentation rep) { + return rep == MachineRepresentation::kTrustedPointer; } // Note: this is used in particular to decide which spill slots need @@ -432,10 +432,10 @@ constexpr inline bool CanBeTaggedOrCompressedPointer( rep == MachineRepresentation::kProtectedPointer; } -constexpr inline bool CanBeTaggedOrCompressedOrIndirectPointer( +constexpr inline bool CanBeTaggedOrCompressedOrTrustedPointer( MachineRepresentation rep) { return CanBeTaggedPointer(rep) || CanBeCompressedPointer(rep) || - CanBeIndirectPointer(rep); + CanBeTrustedPointer(rep); } constexpr inline bool IsAnyCompressed(MachineRepresentation rep) { @@ -454,7 +454,7 @@ V8_EXPORT_PRIVATE inline constexpr int ElementSizeLog2Of( return 1; case MachineRepresentation::kWord32: case MachineRepresentation::kFloat32: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: return 2; case MachineRepresentation::kWord64: case MachineRepresentation::kFloat64: diff --git a/deps/v8/src/codegen/macro-assembler-base.cc b/deps/v8/src/codegen/macro-assembler-base.cc index b5b307461841..64a851c5206d 100644 --- a/deps/v8/src/codegen/macro-assembler-base.cc +++ b/deps/v8/src/codegen/macro-assembler-base.cc @@ -135,6 +135,7 @@ int32_t MacroAssemblerBase::RootRegisterOffsetForExternalReferenceTableEntry( bool MacroAssemblerBase::IsAddressableThroughRootRegister( Isolate* isolate, const ExternalReference& reference) { if (reference.IsIsolateFieldId()) return true; + if (isolate == nullptr) return false; Address address = reference.address(); return isolate->root_register_addressable_region().contains(address); diff --git a/deps/v8/src/codegen/maglev-safepoint-table.cc b/deps/v8/src/codegen/maglev-safepoint-table.cc index edff237eaad5..694267214e73 100644 --- a/deps/v8/src/codegen/maglev-safepoint-table.cc +++ b/deps/v8/src/codegen/maglev-safepoint-table.cc @@ -117,8 +117,8 @@ void MaglevSafepointTable::Print(std::ostream& os) const { if (entry.has_deoptimization_index()) { os << " deopt " << std::setw(6) << entry.deoptimization_index() - << " trampoline: " << std::setw(6) << std::hex - << entry.trampoline_pc(); + << " trampoline: " << std::setw(6) << std::hex << entry.trampoline_pc() + << std::dec; } os << "\n"; } @@ -126,8 +126,8 @@ void MaglevSafepointTable::Print(std::ostream& os) const { MaglevSafepointTableBuilder::Safepoint MaglevSafepointTableBuilder::DefineSafepoint(Assembler* assembler) { - entries_.push_back(EntryBuilder(assembler->pc_offset_for_safepoint())); - return MaglevSafepointTableBuilder::Safepoint(&entries_.back()); + return MaglevSafepointTableBuilder::Safepoint( + assembler->pc_offset_for_safepoint(), this); } int MaglevSafepointTableBuilder::UpdateDeoptimizationInfo(int pc, @@ -136,7 +136,7 @@ int MaglevSafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int deopt_index) { DCHECK_NE(MaglevSafepointEntry::kNoTrampolinePC, trampoline); DCHECK_NE(MaglevSafepointEntry::kNoDeoptIndex, deopt_index); - auto it = entries_.Find(start); + auto it = entries_.begin() + start; DCHECK(std::any_of(it, entries_.end(), [pc](auto& entry) { return entry.pc == pc; })); int index = start; diff --git a/deps/v8/src/codegen/maglev-safepoint-table.h b/deps/v8/src/codegen/maglev-safepoint-table.h index b091cf77b0cb..db6ea65111d7 100644 --- a/deps/v8/src/codegen/maglev-safepoint-table.h +++ b/deps/v8/src/codegen/maglev-safepoint-table.h @@ -11,7 +11,8 @@ #include "src/codegen/safepoint-table-base.h" #include "src/common/assert-scope.h" #include "src/utils/allocation.h" -#include "src/zone/zone-chunk-list.h" +#include "src/utils/utils.h" +#include "src/zone/zone-containers.h" #include "src/zone/zone.h" namespace v8 { @@ -242,19 +243,26 @@ class MaglevSafepointTableBuilder : public SafepointTableBuilderBase { class Safepoint { public: + Safepoint(const Safepoint&) = delete; + Safepoint& operator=(const Safepoint&) = delete; + + ~Safepoint() { table_->entries_.push_back(entry_); } + void DefineTaggedRegister(int reg_code) { DCHECK_LT(reg_code, kBitsPerByte * sizeof(EntryBuilder::tagged_register_indexes)); - entry_->tagged_register_indexes |= 1u << reg_code; + entry_.tagged_register_indexes |= 1u << reg_code; } void SetNumExtraSpillSlots(uint8_t num_slots) { - entry_->num_extra_spill_slots = num_slots; + entry_.num_extra_spill_slots = num_slots; } private: friend class MaglevSafepointTableBuilder; - explicit Safepoint(EntryBuilder* entry) : entry_(entry) {} - EntryBuilder* const entry_; + Safepoint(int pc, MaglevSafepointTableBuilder* table) + : entry_(pc), table_(table) {} + EntryBuilder entry_; + MaglevSafepointTableBuilder* const table_; }; // Define a new safepoint for the current position in the body. @@ -272,7 +280,7 @@ class MaglevSafepointTableBuilder : public SafepointTableBuilderBase { private: const uint32_t num_tagged_slots_; - ZoneChunkList<EntryBuilder> entries_; + ZoneVector<EntryBuilder> entries_; }; } // namespace internal diff --git a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc index f556b79aefe1..5ab9f0a5691d 100644 --- a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc +++ b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc @@ -5316,16 +5316,18 @@ void MacroAssembler::InvokeFunctionCode( // call sites. LoadEntrypointFromJSDispatchTable(kJavaScriptCallCodeStartRegister, dispatch_handle, scratch); + Label done; switch (type) { case InvokeType::kCall: Call(kJavaScriptCallCodeStartRegister); + Branch(&done); break; case InvokeType::kJump: + // The tail jump does not return, so jumping to `done` here would be + // unreachable dead code. Jump(kJavaScriptCallCodeStartRegister); break; } - Label done; - Branch(&done); // Deferred debug hook. bind(&debug_hook); @@ -6503,7 +6505,7 @@ void MacroAssembler::JumpCodeObject(Register code_data_container_object, } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = kJavaScriptCallDispatchHandleRegister; Register parameter_count = s1; @@ -6514,9 +6516,23 @@ void MacroAssembler::CallJSFunction(Register function_object, LoadEntrypointAndParameterCountFromJSDispatchTable(code, parameter_count, dispatch_handle, scratch); - // Force a safe crash if the parameter count doesn't match. - SbxCheck(le, AbortReason::kJSSignatureMismatch, parameter_count, - Operand(argument_count)); + // Force a safe crash if the parameter count doesn't match the expected count + // assumed at the call site, which would corrupt the stack on underapplication + // (caller pushes max(actual_argc, expected) slots; callee pops + // max(actual_argc, parameter_count) slots). + if (expected_parameter_count <= 1) { + // Both kDontAdaptArgumentsSentinel (0) and JSParameterCount(0) (1) are + // valid here: since actual_argc >= 1 (includes receiver), neither pads + // arguments and both pop actual_argc slots upon return. We cannot use an + // exact equality check because WasmToJS wrappers compute expected_arity + // via SFI::internal_formal_parameter_count_without_receiver(), which maps + // both cases to JSParameterCount(0) (1). + SbxCheck(le, AbortReason::kJSSignatureMismatch, parameter_count, + Operand(1)); + } else { + SbxCheck(eq, AbortReason::kJSSignatureMismatch, parameter_count, + Operand(expected_parameter_count)); + } Call(code); } diff --git a/deps/v8/src/codegen/mips64/macro-assembler-mips64.h b/deps/v8/src/codegen/mips64/macro-assembler-mips64.h index 297628a41cdc..77c5e62b9964 100644 --- a/deps/v8/src/codegen/mips64/macro-assembler-mips64.h +++ b/deps/v8/src/codegen/mips64/macro-assembler-mips64.h @@ -301,7 +301,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { JumpMode jump_mode = JumpMode::kJump); // Convenience functions to call/jmp to the code of a JSFunction object. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); diff --git a/deps/v8/src/codegen/optimized-compilation-info.cc b/deps/v8/src/codegen/optimized-compilation-info.cc index c89835c4b840..23ada2e8fde0 100644 --- a/deps/v8/src/codegen/optimized-compilation-info.cc +++ b/deps/v8/src/codegen/optimized-compilation-info.cc @@ -61,20 +61,21 @@ OptimizedCompilationInfo::OptimizedCompilationInfo( } } -OptimizedCompilationInfo::OptimizedCompilationInfo( - base::Vector<const char> debug_name, Zone* zone, CodeKind code_kind, - Builtin builtin) +OptimizedCompilationInfo::OptimizedCompilationInfo(std::string_view debug_name, + Zone* zone, + CodeKind code_kind, + Builtin builtin) : isolate_unsafe_(nullptr), code_kind_(code_kind), builtin_(builtin), zone_(zone), optimization_id_(kNoOptimizationId), - debug_name_(debug_name.begin(), debug_name.end()) { + debug_name_(debug_name) { DCHECK_IMPLIES(builtin_ != Builtin::kNoBuiltinId, (code_kind_ == CodeKind::BUILTIN || code_kind_ == CodeKind::BYTECODE_HANDLER)); SetTracingFlags( - PassesFilter(debug_name, base::CStrVector(v8_flags.trace_turbo_filter))); + PassesFilter(debug_name, v8_flags.trace_turbo_filter.value())); ConfigureFlags(); DCHECK(!has_shared_info()); } diff --git a/deps/v8/src/codegen/optimized-compilation-info.h b/deps/v8/src/codegen/optimized-compilation-info.h index 7b2a5621066b..d454525e906c 100644 --- a/deps/v8/src/codegen/optimized-compilation-info.h +++ b/deps/v8/src/codegen/optimized-compilation-info.h @@ -6,8 +6,9 @@ #define V8_CODEGEN_OPTIMIZED_COMPILATION_INFO_H_ #include <memory> +#include <string> +#include <string_view> -#include "src/base/vector.h" #include "src/codegen/bailout-reason.h" #include "src/codegen/source-position-table.h" #include "src/codegen/tick-counter.h" @@ -112,7 +113,7 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final { : OptimizedCompilationInfo(zone, isolate, shared, closure, code_kind, BytecodeOffset::None()) {} // Construct a compilation info for stub compilation, Wasm, and testing. - OptimizedCompilationInfo(base::Vector<const char> debug_name, Zone* zone, + OptimizedCompilationInfo(std::string_view debug_name, Zone* zone, CodeKind code_kind, Builtin builtin = Builtin::kNoBuiltinId); @@ -280,7 +281,6 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final { } std::unique_ptr<CanonicalHandlesMap> DetachCanonicalHandles() { - DCHECK_NOT_NULL(canonical_handles_); return std::move(canonical_handles_); } diff --git a/deps/v8/src/codegen/pending-optimization-table.cc b/deps/v8/src/codegen/pending-optimization-table.cc index 4548e5683c89..273c1ecff86d 100644 --- a/deps/v8/src/codegen/pending-optimization-table.cc +++ b/deps/v8/src/codegen/pending-optimization-table.cc @@ -6,6 +6,8 @@ #include "src/base/flags.h" #include "src/execution/isolate-inl.h" +#include "src/execution/local-isolate-inl.h" +#include "src/handles/handles-inl.h" #include "src/heap/heap-inl.h" #include "src/objects/hash-table.h" #include "src/objects/js-objects.h" @@ -57,5 +59,43 @@ bool ManualOptimizationTable::IsMarkedForManualOptimization( return !IsTheHole(*entry); } +void ManualOptimizationTable::MarkFunctionForDisabledEagerInlining( + Isolate* isolate, DirectHandle<JSFunction> function) { + DCHECK(v8_flags.allow_natives_syntax); + base::MutexGuard guard(isolate->shared_function_info_access()); + + DirectHandle<SharedFunctionInfo> shared_info(function->shared(), isolate); + + Handle<ObjectHashTable> table = + IsUndefined( + isolate->heap()->functions_marked_for_disabled_eager_inlining()) + ? ObjectHashTable::New(isolate, 1) + : handle(Cast<ObjectHashTable>( + isolate->heap() + ->functions_marked_for_disabled_eager_inlining()), + isolate); + table = ObjectHashTable::Put(isolate, table, shared_info, + isolate->factory()->true_value()); + isolate->heap()->SetFunctionsMarkedForDisabledEagerInlining(*table); +} + +bool ManualOptimizationTable::IsMarkedForDisabledEagerInlining( + LocalIsolate* isolate, Tagged<SharedFunctionInfo> function) { + if (!v8_flags.allow_natives_syntax) return false; + + MutexGuardIfOffThread<LocalIsolate> mutex_guard( + isolate->shared_function_info_access(), isolate); + + Tagged<Object> table = isolate->GetMainThreadIsolateUnsafe() + ->heap() + ->functions_marked_for_disabled_eager_inlining(); + if (IsUndefined(table)) return false; + + Tagged<Object> entry = + Cast<ObjectHashTable>(table)->Lookup(direct_handle(function, isolate)); + + return !IsTheHole(entry); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/codegen/pending-optimization-table.h b/deps/v8/src/codegen/pending-optimization-table.h index 290d47d34516..c07c65ef880e 100644 --- a/deps/v8/src/codegen/pending-optimization-table.h +++ b/deps/v8/src/codegen/pending-optimization-table.h @@ -31,6 +31,15 @@ class ManualOptimizationTable { // function. static bool IsMarkedForManualOptimization(Isolate* isolate, Tagged<JSFunction> function); + + // Mark a function to disable eager inlining for it in optimizing compilers. + static void MarkFunctionForDisabledEagerInlining( + Isolate* isolate, DirectHandle<JSFunction> function); + + // Returns true if MarkFunctionForDisabledEagerInlining was called with this + // function. + static bool IsMarkedForDisabledEagerInlining( + LocalIsolate* isolate, Tagged<SharedFunctionInfo> function); }; } // namespace internal diff --git a/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc b/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc index 13367917f0be..3f1d9ce2aa43 100644 --- a/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc +++ b/deps/v8/src/codegen/ppc/macro-assembler-ppc.cc @@ -4795,7 +4795,7 @@ void MacroAssembler::JumpCodeObject(Register code_object, JumpMode jump_mode) { } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { Register code = kJavaScriptCallCodeStartRegister; UseScratchRegisterScope temps(this); Register dispatch_handle = temps.Acquire(); diff --git a/deps/v8/src/codegen/ppc/macro-assembler-ppc.h b/deps/v8/src/codegen/ppc/macro-assembler-ppc.h index 4955340befc4..69eee090786f 100644 --- a/deps/v8/src/codegen/ppc/macro-assembler-ppc.h +++ b/deps/v8/src/codegen/ppc/macro-assembler-ppc.h @@ -998,7 +998,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { } // Convenience functions to call/jmp to the code of a JSFunction object. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, diff --git a/deps/v8/src/codegen/riscv/assembler-riscv-inl.h b/deps/v8/src/codegen/riscv/assembler-riscv-inl.h index 4ee58ca5037e..05ad8fabcd09 100644 --- a/deps/v8/src/codegen/riscv/assembler-riscv-inl.h +++ b/deps/v8/src/codegen/riscv/assembler-riscv-inl.h @@ -38,6 +38,8 @@ #include "src/codegen/riscv/assembler-riscv.h" // Include the non-inl header before the rest of the headers. +#include <array> + #include "src/codegen/assembler-arch.h" #include "src/codegen/assembler.h" #include "src/debug/debug.h" @@ -142,13 +144,13 @@ Tagged_t Assembler::target_compressed_address_at(Address pc, Address constant_pool) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; disasm.InstructionDecode(disasm_buffer, reinterpret_cast<uint8_t*>(pc)); - DEBUG_PRINTF("%s\n", disasm_buffer.begin()); + DEBUG_PRINTF("%s\n", disasm_buffer.data()); disasm.InstructionDecode(disasm_buffer, reinterpret_cast<uint8_t*>(pc + kInstrSize)); - DEBUG_PRINTF("%s\n", disasm_buffer.begin()); + DEBUG_PRINTF("%s\n", disasm_buffer.data()); DEBUG_PRINTF("\t target_compressed_address_at %d\n", uint32_constant_at(pc, constant_pool)); @@ -185,13 +187,13 @@ Handle<HeapObject> Assembler::embedded_object_handle_at(Address pc) { DEBUG_PRINTF("\tembedded_object_handle_at: pc: 0x%" PRIxPTR " \n", pc); disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; disasm.InstructionDecode(disasm_buffer, reinterpret_cast<uint8_t*>(pc)); - DEBUG_PRINTF("%s\n", disasm_buffer.begin()); + DEBUG_PRINTF("%s\n", disasm_buffer.data()); disasm.InstructionDecode(disasm_buffer, reinterpret_cast<uint8_t*>(pc + kInstrSize)); - DEBUG_PRINTF("%s\n", disasm_buffer.begin()); + DEBUG_PRINTF("%s\n", disasm_buffer.data()); #if V8_TARGET_ARCH_RISCV64 Instr instr1 = Assembler::instr_at(pc); Instr instr2 = Assembler::instr_at(pc + kInstrSize); diff --git a/deps/v8/src/codegen/riscv/assembler-riscv.cc b/deps/v8/src/codegen/riscv/assembler-riscv.cc index f9c12ab9a755..3539aaa7ac54 100644 --- a/deps/v8/src/codegen/riscv/assembler-riscv.cc +++ b/deps/v8/src/codegen/riscv/assembler-riscv.cc @@ -34,6 +34,8 @@ #include "src/codegen/riscv/assembler-riscv.h" +#include <array> + #include "src/base/bits.h" #include "src/base/cpu/cpu.h" #include "src/codegen/assembler-inl.h" @@ -540,10 +542,10 @@ void Assembler::DisassembleInstructionHelper(uint8_t* pc) { CHECK(v8_flags.riscv_debug); disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; disasm.InstructionDecode(disasm_buffer, pc); - DEBUG_PRINTF("%s\n", disasm_buffer.begin()); + DEBUG_PRINTF("%s\n", disasm_buffer.data()); } void Assembler::target_at_put(int pos, int target_pos, bool is_internal) { diff --git a/deps/v8/src/codegen/riscv/assembler-riscv.h b/deps/v8/src/codegen/riscv/assembler-riscv.h index f3c8401dbb8d..67f363093a29 100644 --- a/deps/v8/src/codegen/riscv/assembler-riscv.h +++ b/deps/v8/src/codegen/riscv/assembler-riscv.h @@ -607,10 +607,11 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase, void set(int32_t avl, VSew sew, Vlmul lmul, TailAgnosticType tail = ta) { DCHECK(is_uint5(avl)); - if (avl != avl_ || sew != sew_ || lmul != lmul_) { + if (avl != avl_ || sew != sew_ || lmul != lmul_ || tail != tail_) { avl_ = avl; sew_ = sew; lmul_ = lmul; + tail_ = tail; assm_->vsetivli(zero_reg, static_cast<uint8_t>(avl), sew_, lmul_, tail); } } @@ -621,6 +622,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase, avl_ = -1; sew_ = sew; lmul_ = lmul; + tail_ = tail; } bool IsConfiguredForSimd128() const { @@ -731,12 +733,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase, avl_ = -1; sew_ = kVsInvalid; lmul_ = kVlInvalid; + tail_ = ta; } private: int32_t avl_ = -1; VSew sew_ = kVsInvalid; Vlmul lmul_ = kVlInvalid; + TailAgnosticType tail_ = ta; Assembler* assm_; FPURoundingMode mode_ = RNE; }; diff --git a/deps/v8/src/codegen/riscv/base-assembler-riscv.h b/deps/v8/src/codegen/riscv/base-assembler-riscv.h index 12366e42958c..f1011c6f7770 100644 --- a/deps/v8/src/codegen/riscv/base-assembler-riscv.h +++ b/deps/v8/src/codegen/riscv/base-assembler-riscv.h @@ -37,6 +37,7 @@ #include <stdio.h> +#include <array> #include <fstream> #include <memory> #include <set> @@ -74,9 +75,9 @@ class DebugFile : public std::ofstream { #define DEBUG_PRINTF(...) /* force 80 cols */ \ if (V8_UNLIKELY(v8_flags.riscv_debug)) { \ if (v8_flags.riscv_debug_file_path) { \ - base::EmbeddedVector<char, 1024> chars; \ - SNPrintF(chars, __VA_ARGS__); \ - DebugFile::GetDebugFile() << chars.begin(); \ + std::array<char, 1024> chars; \ + base::SNPrintF(chars, __VA_ARGS__); \ + DebugFile::GetDebugFile() << chars.data(); \ } else { \ PrintF(__VA_ARGS__); \ } \ diff --git a/deps/v8/src/codegen/riscv/constants-riscv.h b/deps/v8/src/codegen/riscv/constants-riscv.h index c9c67c08a6fe..aa4d2b3d288e 100644 --- a/deps/v8/src/codegen/riscv/constants-riscv.h +++ b/deps/v8/src/codegen/riscv/constants-riscv.h @@ -34,6 +34,7 @@ const int kInitialShadowStackSize = 1024; constexpr uint64_t kFP64DefaultNaN = 0x7FF8000000000000UL; constexpr uint32_t kFP32DefaultNaN = 0x7FC00000; +constexpr uint32_t kFP16DefaultNaN = 0x7E00; constexpr uint32_t kFP32FltMin = 0x00800000; constexpr uint64_t kFP64DblMin = 0x0010000000000000ULL; } // namespace internal diff --git a/deps/v8/src/codegen/riscv/macro-assembler-riscv.cc b/deps/v8/src/codegen/riscv/macro-assembler-riscv.cc index 8fa91106da4a..5c498ec7083b 100644 --- a/deps/v8/src/codegen/riscv/macro-assembler-riscv.cc +++ b/deps/v8/src/codegen/riscv/macro-assembler-riscv.cc @@ -318,9 +318,15 @@ void MacroAssembler::RecordWriteField(Register object, int offset, void MacroAssembler::LoadTrustedPointerField(Register destination, MemOperand field_operand, - IndirectPointerTag tag) { + TrustedPointerTagRange tag_range) { #ifdef V8_ENABLE_SANDBOX - LoadIndirectPointerField(destination, field_operand, tag); + ASM_CODE_COMMENT(this); + UseScratchRegisterScope temps(this); + Register handle = t6; + DCHECK_NE(handle, destination); + Lwu(handle, field_operand); + + ResolveTrustedPointerHandle(destination, handle, tag_range); #else LoadTaggedField(destination, field_operand); #endif @@ -345,10 +351,10 @@ void MacroAssembler::LoadTrustedUnknownPointerField( Register handle = scratch1; Lw(handle, field_operand); - static_assert(kNullIndirectPointerHandle == 0); + static_assert(kNullTrustedPointerHandle == 0); Branch(is_unavailable, eq, handle, Operand(zero_reg)); - ResolveIndirectPointerHandle(destination, handle, kAllIndirectPointerTags); + ResolveTrustedPointerHandle(destination, handle, kAllTrustedPointerTags); } #else LoadTaggedField(destination, field_operand); @@ -377,17 +383,22 @@ void MacroAssembler::LoadTrustedUnknownPointerField( } void MacroAssembler::StoreTrustedPointerField(Register value, - MemOperand dst_field_operand) { + MemOperand dst_field_operand, + Trapper&& trapper) { #ifdef V8_ENABLE_SANDBOX - StoreIndirectPointerField(value, dst_field_operand); + UseScratchRegisterScope temps(this); + Register scratch = temps.Acquire(); + Lw(scratch, FieldMemOperand(value, offsetof(ExposedTrustedObject, + self_trusted_pointer_))); + Sw(scratch, dst_field_operand, std::forward<Trapper>(trapper)); #else - StoreTaggedField(value, dst_field_operand); + StoreTaggedField(value, dst_field_operand, std::forward<Trapper>(trapper)); #endif } #ifdef V8_ENABLE_SANDBOX -void MacroAssembler::ResolveIndirectPointerHandle( - Register destination, Register handle, IndirectPointerTagRange tag_range) { +void MacroAssembler::ResolveTrustedPointerHandle( + Register destination, Register handle, TrustedPointerTagRange tag_range) { DCHECK(!AreAliased(handle, destination)); ASM_CODE_COMMENT(this); Register table = destination; @@ -479,38 +490,6 @@ void MacroAssembler::LoadExternalPointerField(Register destination, #endif // V8_ENABLE_SANDBOX } -#ifdef V8_TARGET_ARCH_RISCV64 -void MacroAssembler::LoadIndirectPointerField( - Register destination, MemOperand field_operand, - IndirectPointerTagRange tag_range) { -#ifdef V8_ENABLE_SANDBOX - ASM_CODE_COMMENT(this); - UseScratchRegisterScope temps(this); - Register handle = t6; - DCHECK_NE(handle, destination); - Lwu(handle, field_operand); - - ResolveIndirectPointerHandle(destination, handle, tag_range); -#else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX -} - -void MacroAssembler::StoreIndirectPointerField(Register value, - MemOperand dst_field_operand, - Trapper&& trapper) { -#ifdef V8_ENABLE_SANDBOX - UseScratchRegisterScope temps(this); - Register scratch = temps.Acquire(); - Lw(scratch, FieldMemOperand(value, offsetof(ExposedTrustedObject, - self_indirect_pointer_))); - Sw(scratch, dst_field_operand, std::forward<Trapper>(trapper)); -#else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX -} -#endif // V8_TARGET_ARCH_RISCV64 - void MacroAssembler::MaybeSaveRegisters(RegList registers) { if (registers.is_empty()) return; MultiPush(registers); @@ -537,22 +516,21 @@ void MacroAssembler::CallEphemeronKeyBarrier(Register object, Operand offset, MaybeRestoreRegisters(registers); } -void MacroAssembler::CallIndirectPointerBarrier(Register object, Operand offset, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag) { +void MacroAssembler::CallTrustedPointerBarrier(Register object, Operand offset, + SaveFPRegsMode fp_mode, + TrustedPointerTag tag) { ASM_CODE_COMMENT(this); RegList registers = - IndirectPointerWriteBarrierDescriptor::ComputeSavedRegisters(object); + TrustedPointerWriteBarrierDescriptor::ComputeSavedRegisters(object); MaybeSaveRegisters(registers); - MoveObjectAndSlot( - IndirectPointerWriteBarrierDescriptor::ObjectRegister(), - IndirectPointerWriteBarrierDescriptor::SlotAddressRegister(), object, - offset); - li(IndirectPointerWriteBarrierDescriptor::IndirectPointerTagRegister(), + MoveObjectAndSlot(TrustedPointerWriteBarrierDescriptor::ObjectRegister(), + TrustedPointerWriteBarrierDescriptor::SlotAddressRegister(), + object, offset); + li(TrustedPointerWriteBarrierDescriptor::TrustedPointerTagRegister(), Operand(tag)); - CallBuiltin(Builtins::IndirectPointerBarrier(fp_mode)); + CallBuiltin(Builtins::TrustedPointerBarrier(fp_mode)); MaybeRestoreRegisters(registers); } @@ -730,9 +708,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, DCHECK(!AreAliased(object, value, temp)); AddWord(temp, object, offset); #ifdef V8_TARGET_ARCH_RISCV64 - if (slot.contains_indirect_pointer()) { - LoadIndirectPointerField(temp, MemOperand(temp, 0), - slot.indirect_pointer_tag()); + if (slot.contains_trusted_pointer()) { + LoadTrustedPointerField(temp, MemOperand(temp, 0), + slot.trusted_pointer_tag()); } else { DCHECK(slot.contains_direct_pointer()); LoadTaggedField(temp, MemOperand(temp, 0)); @@ -762,7 +740,7 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, JumpIfSmi(value, &done); } - if (slot.contains_indirect_pointer()) { + if (slot.contains_trusted_pointer()) { // The indirect pointer write barrier is only enabled during marking. JumpIfNotMarking(&done); } else { @@ -793,9 +771,9 @@ void MacroAssembler::RecordWrite(Register object, Operand offset, CallRecordWriteStub(object, slot_address, fp_mode, StubCallMode::kCallBuiltinPointer); } else { - DCHECK(slot.contains_indirect_pointer()); - CallIndirectPointerBarrier(object, offset, fp_mode, - slot.indirect_pointer_tag()); + DCHECK(slot.contains_trusted_pointer()); + CallTrustedPointerBarrier(object, offset, fp_mode, + slot.trusted_pointer_tag()); } if (ra_status == kRAHasNotBeenSaved) { pop(ra); @@ -1891,10 +1869,15 @@ void MacroAssembler::ByteSwap(Register rd, Register rs, int operand_size, return; } UseScratchRegisterScope temps(this); - temps.Include(t4, t6); + temps.Include(t6); Register tmp0 = temps.Acquire(); Register tmp1 = temps.Acquire(); - DCHECK(!AreAliased(rs, rd, tmp0, tmp1, scratch)); + // {rs} and {rd} are allowed to alias: the implementation below reads {rs} + // before writing {rd} and is therefore safe when they are the same register. + // The checks below cover every pair except {rs}/{rd}. + DCHECK(!AreAliased(tmp0, tmp1, scratch)); + DCHECK(!AreAliased(rs, tmp0, tmp1, scratch)); + DCHECK(!AreAliased(rd, tmp0, tmp1, scratch)); BlockPoolsScope block_pools(this); if (operand_size == 4) { DCHECK((rd != t6) && (rs != t6)); @@ -2082,7 +2065,7 @@ void MacroAssembler::UnalignedFLoadHelper(FPURegister frd, AdjustBaseAndOffset(&source, scratch_base, OffsetAccessType::TWO_ACCESSES, NBYTES - 1); } - temps.Include(t4, t6); + temps.Include(t6); Register scratch = temps.Acquire(); Register scratch_other = temps.Acquire(); DCHECK(scratch != rs.rm() && scratch_other != scratch && @@ -2108,7 +2091,7 @@ void MacroAssembler::UnalignedFLoadHelper(FPURegister frd, AdjustBaseAndOffset(&source, scratch_base, OffsetAccessType::TWO_ACCESSES, NBYTES - 1); } - temps.Include(t4, t6); + temps.Include(t6); Register scratch = temps.Acquire(); Register scratch_other = temps.Acquire(); DCHECK(scratch != rs.rm() && scratch_other != scratch && @@ -2129,7 +2112,7 @@ void MacroAssembler::UnalignedDoubleHelper(FPURegister frd, AdjustBaseAndOffset(&source, scratch_base, OffsetAccessType::TWO_ACCESSES, 8 - 1); } - temps.Include(t4, t6); + temps.Include(t6); Register scratch = temps.Acquire(); Register scratch_other = temps.Acquire(); DCHECK(scratch != rs.rm() && scratch_other != scratch && @@ -2178,13 +2161,15 @@ void MacroAssembler::UnalignedFStoreHelper(FPURegister frd, const MemOperand& rs) { DCHECK(NBYTES == 8 || NBYTES == 4); UseScratchRegisterScope temps(this); + temps.Include(t6); Register scratch = temps.Acquire(); if (NBYTES == 4) { fmv_x_w(scratch, frd); } else { fmv_x_d(scratch, frd); } - UnalignedStoreHelper<NBYTES>(scratch, rs, t4); + Register scratch_other = temps.Acquire(); + UnalignedStoreHelper<NBYTES>(scratch, rs, scratch_other); } #elif V8_TARGET_ARCH_RISCV32 template <int NBYTES> @@ -2192,22 +2177,26 @@ void MacroAssembler::UnalignedFStoreHelper(FPURegister frd, const MemOperand& rs) { DCHECK_EQ(NBYTES, 4); UseScratchRegisterScope temps(this); + temps.Include(t6); Register scratch = temps.Acquire(); fmv_x_w(scratch, frd); - UnalignedStoreHelper<NBYTES>(scratch, rs, t4); + Register scratch_other = temps.Acquire(); + UnalignedStoreHelper<NBYTES>(scratch, rs, scratch_other); } void MacroAssembler::UnalignedDStoreHelper(FPURegister frd, const MemOperand& rs) { UseScratchRegisterScope temps(this); + temps.Include(t6); Register scratch = temps.Acquire(); + Register scratch_other = temps.Acquire(); Sub32(sp, sp, 8); StoreDouble(frd, MemOperand(sp, 0)); Lw(scratch, MemOperand(sp, 0)); - UnalignedStoreHelper<4>(scratch, rs, t4); + UnalignedStoreHelper<4>(scratch, rs, scratch_other); Lw(scratch, MemOperand(sp, 4)); MemOperand source = rs; source.set_offset(source.offset() + 4); - UnalignedStoreHelper<4>(scratch, source, t4); + UnalignedStoreHelper<4>(scratch, source, scratch_other); Add32(sp, sp, 8); } #endif @@ -7638,8 +7627,9 @@ void MacroAssembler::JumpCodeObject(Register code_object, CodeEntrypointTag tag, } #ifdef V8_TARGET_ARCH_RISCV64 -void MacroAssembler::CallJSFunction(Register function_object, - [[maybe_unused]] uint16_t argument_count) { +void MacroAssembler::CallJSFunction( + Register function_object, + [[maybe_unused]] uint16_t expected_parameter_count) { ASM_CODE_COMMENT(this); Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = kJavaScriptCallDispatchHandleRegister; @@ -7650,14 +7640,28 @@ void MacroAssembler::CallJSFunction(Register function_object, FieldMemOperand(function_object, offsetof(JSFunction, dispatch_handle_))); LoadEntrypointAndParameterCountFromJSDispatchTable(code, parameter_count, dispatch_handle, scratch); - // Force a safe crash if the parameter count doesn't match. - SbxCheck(le, AbortReason::kJSSignatureMismatch, parameter_count, - Operand(argument_count)); + // Force a safe crash if the parameter count doesn't match the expected count + // assumed at the call site, which would corrupt the stack on underapplication + // (caller pushes max(actual_argc, expected) slots; callee pops + // max(actual_argc, parameter_count) slots). + if (expected_parameter_count <= 1) { + // Both kDontAdaptArgumentsSentinel (0) and JSParameterCount(0) (1) are + // valid here: since actual_argc >= 1 (includes receiver), neither pads + // arguments and both pop actual_argc slots upon return. We cannot use an + // exact equality check because WasmToJS wrappers compute expected_arity + // via SFI::internal_formal_parameter_count_without_receiver(), which maps + // both cases to JSParameterCount(0) (1). + SbxCheck(le, AbortReason::kJSSignatureMismatch, parameter_count, + Operand(1)); + } else { + SbxCheck(eq, AbortReason::kJSSignatureMismatch, parameter_count, + Operand(expected_parameter_count)); + } Call(code); } #else void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = s1; UseScratchRegisterScope temps(this); diff --git a/deps/v8/src/codegen/riscv/macro-assembler-riscv.h b/deps/v8/src/codegen/riscv/macro-assembler-riscv.h index ec4fa942ff50..d218dafaa125 100644 --- a/deps/v8/src/codegen/riscv/macro-assembler-riscv.h +++ b/deps/v8/src/codegen/riscv/macro-assembler-riscv.h @@ -329,7 +329,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { JumpMode jump_mode = JumpMode::kJump); // Convenience functions to call/jmp to the code of a JSFunction object. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, @@ -425,9 +426,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { void CallEphemeronKeyBarrier(Register object, Operand offset, SaveFPRegsMode fp_mode); - void CallIndirectPointerBarrier(Register object, Operand offset, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag); + void CallTrustedPointerBarrier(Register object, Operand offset, + SaveFPRegsMode fp_mode, TrustedPointerTag tag); void CallRecordWriteStubSaveRegisters( Register object, Operand offset, SaveFPRegsMode fp_mode, StubCallMode mode = StubCallMode::kCallBuiltinPointer); @@ -1381,8 +1381,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table. Otherwise they are regular tagged fields. void LoadTrustedPointerField(Register destination, MemOperand field_operand, - IndirectPointerTag tag); - // As above, but for kUnknownIndirectPointerTag. The type of the loaded object + TrustedPointerTagRange tag_range); + // As above, but for kUnknownTrustedPointerTag. The type of the loaded object // is unknown, so this helper will check for a series of expected types and // jump to the given labels if the loaded object has a matching type. If the // field is null (with enabled sandbox) or a Smi (with disabled sandbox) and @@ -1397,13 +1397,14 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { const std::initializer_list<std::tuple<InstanceType, Label*>>& cases, Label* is_unavailable = nullptr); // Store a trusted pointer field. - void StoreTrustedPointerField(Register value, MemOperand dst_field_operand); + void StoreTrustedPointerField( + Register value, MemOperand dst_field_operand, + Trapper&& trapper = [](int) {}); // Load a code pointer field. // These are special versions of trusted pointers that, when the sandbox is - // enabled, reference code objects through the code pointer table. + // enabled, reference code objects through the trusted pointer table. void LoadCodePointerField(Register destination, MemOperand field_operand) { - LoadTrustedPointerField(destination, field_operand, - kCodeIndirectPointerTag); + LoadTrustedPointerField(destination, field_operand, kCodeTrustedPointerTag); } // Store a code pointer field. void StoreCodePointerField(Register value, MemOperand dst_field_operand) { @@ -1470,21 +1471,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { const MemOperand& dst_field_operand, Trapper&& trapper = [](int){}); - // Loads an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void LoadIndirectPointerField(Register destination, MemOperand field_operand, - IndirectPointerTagRange tag_range); - // Store an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void StoreIndirectPointerField(Register value, MemOperand dst_field_operand, - Trapper&& trapper = [](int){}); - #ifdef V8_ENABLE_SANDBOX - // Retrieve the heap object referenced by the given indirect pointer handle. - void ResolveIndirectPointerHandle(Register destination, Register handle, - IndirectPointerTagRange tag_range); + // Retrieve the heap object referenced by the given trusted pointer handle. + void ResolveTrustedPointerHandle(Register destination, Register handle, + TrustedPointerTagRange tag_range); #endif void AtomicDecompressTaggedSigned(Register dst, const MemOperand& src, diff --git a/deps/v8/src/codegen/riscv/register-riscv.h b/deps/v8/src/codegen/riscv/register-riscv.h index 447f3316dfa3..1dee5a0a2a93 100644 --- a/deps/v8/src/codegen/riscv/register-riscv.h +++ b/deps/v8/src/codegen/riscv/register-riscv.h @@ -23,10 +23,15 @@ namespace internal { // s6: roots in Javascript code s7: context register // s11: PtrComprCageBaseRegister // t3 t5 : scratch register used in scratch_register_list (in the assembler). -// t6 : call reg. +// t6 : call reg / kMaglevFlagsRegister. t6 is not allocatable, so it can be +// used as an extra scratch register: the default scratch list only holds two +// registers ({t3, t5}), so add t6 when a third one is needed. // t0 t1 t2 t4:caller saved scratch register can be used in macroassembler and // t2: kMaglevExtraScratchRegister // builtin-riscv64 +// Note: t4 is allocatable in Maglev, so macro-assembler helpers must not use it +// as an implicit scratch register. Add t6 instead, so that t4 is never +// clobbered. #define ALWAYS_ALLOCATABLE_GENERAL_REGISTERS(V) \ V(a0) V(a1) V(a2) V(a3) \ V(a4) V(a5) V(a6) V(a7) V(s1) V(s2) \ diff --git a/deps/v8/src/codegen/s390/macro-assembler-s390.cc b/deps/v8/src/codegen/s390/macro-assembler-s390.cc index 53cfe71665aa..ba2b9a6df1a2 100644 --- a/deps/v8/src/codegen/s390/macro-assembler-s390.cc +++ b/deps/v8/src/codegen/s390/macro-assembler-s390.cc @@ -4740,7 +4740,8 @@ void MacroAssembler::JumpCodeObject(Register code_object, JumpMode jump_mode) { } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count, Register scratch) { + uint16_t expected_parameter_count, + Register scratch) { Register code = kJavaScriptCallCodeStartRegister; Register dispatch_handle = r0; scratch = ip; diff --git a/deps/v8/src/codegen/s390/macro-assembler-s390.h b/deps/v8/src/codegen/s390/macro-assembler-s390.h index 70ed43dd1023..b4ed6e6e7e2a 100644 --- a/deps/v8/src/codegen/s390/macro-assembler-s390.h +++ b/deps/v8/src/codegen/s390/macro-assembler-s390.h @@ -1161,8 +1161,8 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { void BindExceptionHandler(Label* label) { bind(label); } // Convenience functions to call/jmp to the code of a JSFunction object. - void CallJSFunction(Register function_object, uint16_t argument_count, - Register scratch = r0); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count, Register scratch = r0); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, diff --git a/deps/v8/src/codegen/safepoint-table.cc b/deps/v8/src/codegen/safepoint-table.cc index a6e2afe31746..d61df6d04cb7 100644 --- a/deps/v8/src/codegen/safepoint-table.cc +++ b/deps/v8/src/codegen/safepoint-table.cc @@ -6,6 +6,7 @@ #include <iomanip> +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/macro-assembler.h" #include "src/deoptimizer/deoptimizer.h" @@ -185,7 +186,7 @@ void EncodeSafepointEntry(int stack_slot_count, uint32_t common_prefix, // Updates {ptr} as it consumes input. template <bool update_tagged_slots> void DecodeSafepointEntry(const uint8_t** ptr, - base::OwnedVector<uint8_t>& tagged_slots) { + base::UniqueArray<uint8_t>& tagged_slots) { uint8_t first_byte = **ptr; if (first_byte == 0) { (*ptr)++; @@ -265,9 +266,9 @@ void DecodeSafepointEntry(const uint8_t** ptr, } template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void DecodeSafepointEntry< - true>(const uint8_t** ptr, base::OwnedVector<uint8_t>& tagged_slots); + true>(const uint8_t** ptr, base::UniqueArray<uint8_t>& tagged_slots); template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void DecodeSafepointEntry< - false>(const uint8_t** ptr, base::OwnedVector<uint8_t>& tagged_slots); + false>(const uint8_t** ptr, base::UniqueArray<uint8_t>& tagged_slots); void SafepointTable::ResetIteration() { ptr_ = safepoint_table_address_ + kHeaderSize; @@ -435,7 +436,7 @@ void SafepointTable::Print(std::ostream& os) { if (entry_.has_deoptimization_index()) { os << " deopt " << std::setw(6) << entry_.deoptimization_index() << " trampoline: " << std::setw(6) << std::hex - << entry_.trampoline_pc(); + << entry_.trampoline_pc() << std::dec; } os << "\n"; } diff --git a/deps/v8/src/codegen/safepoint-table.h b/deps/v8/src/codegen/safepoint-table.h index 84cb4d9a04af..9c2f85be744a 100644 --- a/deps/v8/src/codegen/safepoint-table.h +++ b/deps/v8/src/codegen/safepoint-table.h @@ -7,6 +7,7 @@ #include "src/base/bit-field.h" #include "src/base/export-template.h" +#include "src/base/unique-array.h" #include "src/codegen/safepoint-table-base.h" #include "src/common/assert-scope.h" #include "src/utils/allocation.h" @@ -44,7 +45,7 @@ class SafepointEntry : public SafepointEntryBase { base::Vector<const uint8_t> tagged_slots() const { DCHECK(is_initialized()); DCHECK_NOT_NULL(tagged_slots_.data()); - return tagged_slots_.as_vector(); + return tagged_slots_.as_span(); } // For clearing cache entries. @@ -54,7 +55,7 @@ class SafepointEntry : public SafepointEntryBase { SafepointEntryBase::operator=(src); tagged_register_indexes_ = src.tagged_register_indexes_; tagged_slots_.ReleaseData(); - tagged_slots_ = base::OwnedCopyOf(src.tagged_slots()); + tagged_slots_ = base::UniqueCopyOf(src.tagged_slots()); } private: @@ -67,7 +68,7 @@ class SafepointEntry : public SafepointEntryBase { void ResetTaggedSlots(uint32_t num_tagged_slots) { size_t num_bytes = (num_tagged_slots + kBitsPerByte - 1) / kBitsPerByte; if (tagged_slots_.size() == 0) { - tagged_slots_ = base::OwnedVector<uint8_t>::New(num_bytes); + tagged_slots_ = base::UniqueArray<uint8_t>::New(num_bytes); } else { std::fill(tagged_slots_.begin(), tagged_slots_.end(), 0); } @@ -75,7 +76,7 @@ class SafepointEntry : public SafepointEntryBase { } uint32_t tagged_register_indexes_ = 0; - base::OwnedVector<uint8_t> tagged_slots_; + base::UniqueArray<uint8_t> tagged_slots_; }; // A wrapper class for accessing the safepoint table embedded into the @@ -372,7 +373,7 @@ V8_EXPORT_PRIVATE void EncodeSafepointEntry(int stack_slot_count, template <bool update_tagged_slots> EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) void DecodeSafepointEntry(const uint8_t** ptr, - base::OwnedVector<uint8_t>& tagged_slots); + base::UniqueArray<uint8_t>& tagged_slots); } // namespace internal } // namespace v8 diff --git a/deps/v8/src/codegen/source-position-table.cc b/deps/v8/src/codegen/source-position-table.cc index e13a6ccc64f2..7e6db716a0c2 100644 --- a/deps/v8/src/codegen/source-position-table.cc +++ b/deps/v8/src/codegen/source-position-table.cc @@ -6,6 +6,7 @@ #include "src/base/export-template.h" #include "src/base/logging.h" +#include "src/base/unique-array.h" #include "src/common/assert-scope.h" #include "src/heap/local-factory-inl.h" #include "src/heap/local-heap-inl.h" @@ -229,18 +230,18 @@ template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Handle<TrustedByteArray> SourcePositionTableBuilder::ToSourcePositionTable( LocalIsolate* isolate); -base::OwnedVector<uint8_t> +base::UniqueArray<uint8_t> SourcePositionTableBuilder::ToSourcePositionTableVector() { - if (bytes_.empty()) return base::OwnedVector<uint8_t>(); + if (bytes_.empty()) return base::UniqueArray<uint8_t>(); DCHECK(!Omit()); - base::OwnedVector<uint8_t> table = base::OwnedCopyOf(bytes_); + base::UniqueArray<uint8_t> table = base::UniqueCopyOf(bytes_); #ifdef ENABLE_SLOW_DCHECKS // Brute force testing: Record all positions and decode // the entire table to verify they are identical. SourcePositionTableIterator it( - table.as_vector(), SourcePositionTableIterator::kAll, + table.as_span(), SourcePositionTableIterator::kAll, SourcePositionTableIterator::kDontSkipFunctionEntry); CheckTableEquals(raw_entries_, &it); // No additional source positions after creating the table. diff --git a/deps/v8/src/codegen/source-position-table.h b/deps/v8/src/codegen/source-position-table.h index dc72b8a264ff..fc52f9895c8c 100644 --- a/deps/v8/src/codegen/source-position-table.h +++ b/deps/v8/src/codegen/source-position-table.h @@ -6,6 +6,7 @@ #define V8_CODEGEN_SOURCE_POSITION_TABLE_H_ #include "src/base/export-template.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/codegen/source-position.h" #include "src/common/assert-scope.h" @@ -62,7 +63,7 @@ class V8_EXPORT_PRIVATE SourcePositionTableBuilder { template <typename IsolateT> EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) Handle<TrustedByteArray> ToSourcePositionTable(IsolateT* isolate); - base::OwnedVector<uint8_t> ToSourcePositionTableVector(); + base::UniqueArray<uint8_t> ToSourcePositionTableVector(); inline bool Omit() const { return mode_ != RECORD_SOURCE_POSITIONS; } inline bool Lazy() const { return mode_ == LAZY_SOURCE_POSITIONS; } diff --git a/deps/v8/src/codegen/tnode.h b/deps/v8/src/codegen/tnode.h index adb30fee7eb2..44c316512066 100644 --- a/deps/v8/src/codegen/tnode.h +++ b/deps/v8/src/codegen/tnode.h @@ -98,7 +98,7 @@ struct CppHeapPointerHandleT : Uint32T { static constexpr MachineType kMachineType = MachineType::Uint32(); }; -struct IndirectPointerHandleT : Uint32T { +struct TrustedPointerHandleT : Uint32T { static constexpr MachineType kMachineType = MachineType::Uint32(); }; @@ -149,7 +149,7 @@ using TaggedT = IntPtrT; #endif #ifdef V8_ENABLE_SANDBOX -using TrustedPointerT = IndirectPointerHandleT; +using TrustedPointerT = TrustedPointerHandleT; #else using TrustedPointerT = TaggedT; #endif @@ -227,6 +227,9 @@ constexpr MachineType MachineTypeOf< HeapObjectSubtype, std::enable_if_t<std::is_base_of_v<HeapObject, HeapObjectSubtype>>>::value; +template <class T> +struct MachineTypeOf<ReadOnly<T>> : MachineTypeOf<T> {}; + template <> struct MachineTypeOf<ExternalReference> { static constexpr MachineType value = MachineType::Pointer(); diff --git a/deps/v8/src/codegen/turboshaft-builtins-assembler-inl.h b/deps/v8/src/codegen/turboshaft-builtins-assembler-inl.h index 2c0c2da77442..38c1626d22b6 100644 --- a/deps/v8/src/codegen/turboshaft-builtins-assembler-inl.h +++ b/deps/v8/src/codegen/turboshaft-builtins-assembler-inl.h @@ -434,12 +434,10 @@ class FeedbackCollectorReducer : public Next { using OperationStorageSlot = compiler::turboshaft::OperationStorageSlot; V<None> REDUCE(Return)(V<Word32> pop_count, - base::Vector<const OpIndex> return_values, - bool spill_caller_frame_slots) { + base::Vector<const OpIndex> return_values) { // Store feedback first, before we return from the function. UpdateFeedback(); - return Next::ReduceReturn(pop_count, return_values, - spill_caller_frame_slots); + return Next::ReduceReturn(pop_count, return_values); } private: @@ -1045,8 +1043,7 @@ class BuiltinsReducer : public Next { } V<String> StringConstant(const char* str) { - Handle<String> internalized_string = - factory()->InternalizeString(base::OneByteVector(str)); + Handle<String> internalized_string = factory()->InternalizeString(str); __ CanonicalizeEmbeddedBuiltinsConstantIfNeeded(internalized_string); return V<String>::Cast(__ HeapConstantNoHole(internalized_string)); } diff --git a/deps/v8/src/codegen/x64/assembler-x64.cc b/deps/v8/src/codegen/x64/assembler-x64.cc index 33f173c19f6b..20562a5e9b01 100644 --- a/deps/v8/src/codegen/x64/assembler-x64.cc +++ b/deps/v8/src/codegen/x64/assembler-x64.cc @@ -1426,6 +1426,14 @@ void Assembler::lfence() { emit(0xE8); } +void Assembler::stmxcsr(Operand dst) { + EnsureSpace ensure_space(this); + emit_optional_rex_32(dst); + emit(0x0F); + emit(0xAE); + emit_operand(3, dst); +} + void Assembler::rdpkru() { EnsureSpace ensure_space(this); emit(0x0F); @@ -4417,6 +4425,7 @@ void Assembler::rorxl(Register dst, Operand src, uint8_t imm8) { } void Assembler::pause() { + EnsureSpace ensure_space(this); emit(0xF3); emit(0x90); } diff --git a/deps/v8/src/codegen/x64/assembler-x64.h b/deps/v8/src/codegen/x64/assembler-x64.h index a92af5810416..f8a60d50fb71 100644 --- a/deps/v8/src/codegen/x64/assembler-x64.h +++ b/deps/v8/src/codegen/x64/assembler-x64.h @@ -753,7 +753,13 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { enum SIMDPrefix { kNoPrefix = 0x0, k66 = 0x1, kF3 = 0x2, kF2 = 0x3 }; enum VectorLength { kL128 = 0x0, kL256 = 0x4, kLIG = kL128, kLZ = kL128 }; enum VexW { kW0 = 0x0, kW1 = 0x80, kWIG = kW0 }; - enum LeadingOpcode { k0F = 0x1, k0F38 = 0x2, k0F3A = 0x3 }; + enum LeadingOpcode { + k0F = 0x1, + k0F38 = 0x2, + k0F3A = 0x3, + kMap5 = 0x5, // EVEX only (FP16). + kMap6 = 0x6 // EVEX only (FP16). + }; enum OpMask { k0 = 0x0, k1 = 0x1, k2 = 0x2 }; enum MaskingType { kMerging = 0x0, kZeroing = 0x80 }; enum TupleType { @@ -2651,6 +2657,60 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { } // AVX10.1 instructions + // Packed FP16 addition, without masking, broadcast, or embedded rounding. + void vaddph(XMMRegister dst, XMMRegister src1, XMMRegister src2) { + vinstr_evex(0x58, dst, src1, src2, kNoPrefix, kMap5, kW0); + } + void vaddph(XMMRegister dst, XMMRegister src1, Operand src2) { + vinstr_evex(0x58, dst, src1, src2, kNoPrefix, kMap5, kW0, kFull); + } + void vaddph(YMMRegister dst, YMMRegister src1, YMMRegister src2) { + vinstr_evex(0x58, dst, src1, src2, kNoPrefix, kMap5, kW0); + } + void vaddph(YMMRegister dst, YMMRegister src1, Operand src2) { + vinstr_evex(0x58, dst, src1, src2, kNoPrefix, kMap5, kW0, kFull); + } + + void vsubph(XMMRegister dst, XMMRegister src1, XMMRegister src2) { + vinstr_evex(0x5c, dst, src1, src2, kNoPrefix, kMap5, kW0); + } + void vsubph(XMMRegister dst, XMMRegister src1, Operand src2) { + vinstr_evex(0x5c, dst, src1, src2, kNoPrefix, kMap5, kW0, kFull); + } + void vsubph(YMMRegister dst, YMMRegister src1, YMMRegister src2) { + vinstr_evex(0x5c, dst, src1, src2, kNoPrefix, kMap5, kW0); + } + void vsubph(YMMRegister dst, YMMRegister src1, Operand src2) { + vinstr_evex(0x5c, dst, src1, src2, kNoPrefix, kMap5, kW0, kFull); + } + + // Packed FP16 FMA, without masking, broadcast, or embedded rounding. + // The destination is also the first multiplicand: (+/- dst * src1) + src2. + void vfmadd213ph(XMMRegister dst, XMMRegister src1, XMMRegister src2) { + vinstr_evex(0xa8, dst, src1, src2, k66, kMap6, kW0); + } + void vfmadd213ph(XMMRegister dst, XMMRegister src1, Operand src2) { + vinstr_evex(0xa8, dst, src1, src2, k66, kMap6, kW0, kFull); + } + void vfmadd213ph(YMMRegister dst, YMMRegister src1, YMMRegister src2) { + vinstr_evex(0xa8, dst, src1, src2, k66, kMap6, kW0); + } + void vfmadd213ph(YMMRegister dst, YMMRegister src1, Operand src2) { + vinstr_evex(0xa8, dst, src1, src2, k66, kMap6, kW0, kFull); + } + void vfnmadd213ph(XMMRegister dst, XMMRegister src1, XMMRegister src2) { + vinstr_evex(0xac, dst, src1, src2, k66, kMap6, kW0); + } + void vfnmadd213ph(XMMRegister dst, XMMRegister src1, Operand src2) { + vinstr_evex(0xac, dst, src1, src2, k66, kMap6, kW0, kFull); + } + void vfnmadd213ph(YMMRegister dst, YMMRegister src1, YMMRegister src2) { + vinstr_evex(0xac, dst, src1, src2, k66, kMap6, kW0); + } + void vfnmadd213ph(YMMRegister dst, YMMRegister src1, Operand src2) { + vinstr_evex(0xac, dst, src1, src2, k66, kMap6, kW0, kFull); + } + void vpmullq(XMMRegister dst, XMMRegister src1, XMMRegister src2) { vinstr_evex(0x40, dst, src1, src2, k66, k0F38, kW1); } @@ -2896,6 +2956,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { void mfence(); void lfence(); void pause(); + void stmxcsr(Operand dst); // Pkey support. // Registers rcx and rdx must be zero, rax is the input/output value. diff --git a/deps/v8/src/codegen/x64/interface-descriptors-x64-inl.h b/deps/v8/src/codegen/x64/interface-descriptors-x64-inl.h index 6861e8cbbb6a..0aa19cd3395c 100644 --- a/deps/v8/src/codegen/x64/interface-descriptors-x64-inl.h +++ b/deps/v8/src/codegen/x64/interface-descriptors-x64-inl.h @@ -67,7 +67,8 @@ constexpr auto TSANStoreDescriptor::registers() { // static constexpr auto TSANLoadDescriptor::registers() { - return RegisterArray(kCArgRegs[0], kReturnRegister0); + return RegisterArray(kCArgRegs[0], kCArgRegs[1], kCArgRegs[2], + kReturnRegister0); } #endif // V8_IS_TSAN diff --git a/deps/v8/src/codegen/x64/macro-assembler-x64.cc b/deps/v8/src/codegen/x64/macro-assembler-x64.cc index 5143a9616971..d725ea0e68cf 100644 --- a/deps/v8/src/codegen/x64/macro-assembler-x64.cc +++ b/deps/v8/src/codegen/x64/macro-assembler-x64.cc @@ -780,10 +780,13 @@ void MacroAssembler::LoadExternalPointerField( void MacroAssembler::LoadTrustedPointerField(Register destination, Operand field_operand, - IndirectPointerTagRange tag_range, + TrustedPointerTagRange tag_range, Register scratch) { #ifdef V8_ENABLE_SANDBOX - LoadIndirectPointerField(destination, field_operand, tag_range, scratch); + DCHECK(!AreAliased(destination, scratch)); + Register handle = scratch; + movl(handle, field_operand); + ResolveTrustedPointerHandle(destination, handle, tag_range); #else LoadTaggedField(destination, field_operand); #endif // V8_ENABLE_SANDBOX @@ -807,11 +810,11 @@ void MacroAssembler::LoadTrustedUnknownPointerField( Register handle = scratch; movl(handle, field_operand); - static_assert(kNullIndirectPointerHandle == 0); + static_assert(kNullTrustedPointerHandle == 0); testl(handle, handle); j(zero, is_unavailable, Label::kNear); - ResolveIndirectPointerHandle(destination, handle, kAllIndirectPointerTags); + ResolveTrustedPointerHandle(destination, handle, kAllTrustedPointerTags); } #else LoadTaggedField(destination, field_operand); @@ -841,41 +844,18 @@ void MacroAssembler::LoadTrustedUnknownPointerField( void MacroAssembler::StoreTrustedPointerField(Operand dst_field_operand, Register value) { -#ifdef V8_ENABLE_SANDBOX - StoreIndirectPointerField(dst_field_operand, value); -#else - StoreTaggedField(dst_field_operand, value); -#endif // V8_ENABLE_SANDBOX -} - -void MacroAssembler::LoadIndirectPointerField(Register destination, - Operand field_operand, - IndirectPointerTagRange tag_range, - Register scratch) { -#ifdef V8_ENABLE_SANDBOX - DCHECK(!AreAliased(destination, scratch)); - Register handle = scratch; - movl(handle, field_operand); - ResolveIndirectPointerHandle(destination, handle, tag_range); -#else - UNREACHABLE(); -#endif // V8_ENABLE_SANDBOX -} - -void MacroAssembler::StoreIndirectPointerField(Operand dst_field_operand, - Register value) { #ifdef V8_ENABLE_SANDBOX movl(kScratchRegister, FieldOperand(value, offsetof(ExposedTrustedObject, - self_indirect_pointer_))); + self_trusted_pointer_))); movl(dst_field_operand, kScratchRegister); #else - UNREACHABLE(); + StoreTaggedField(dst_field_operand, value); #endif // V8_ENABLE_SANDBOX } #ifdef V8_ENABLE_SANDBOX -void MacroAssembler::ResolveIndirectPointerHandle( - Register destination, Register handle, IndirectPointerTagRange tag_range) { +void MacroAssembler::ResolveTrustedPointerHandle( + Register destination, Register handle, TrustedPointerTagRange tag_range) { DCHECK(!AreAliased(handle, destination)); shrl(handle, Immediate(kTrustedPointerHandleShift)); static_assert(kTrustedPointerTableEntrySize == 8); @@ -884,8 +864,8 @@ void MacroAssembler::ResolveIndirectPointerHandle( Operand{kRootRegister, IsolateData::trusted_pointer_table_offset()}); movq(destination, Operand{destination, handle, times_8, 0}); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); movq(kScratchRegister, Immediate64(mask)); andq(destination, kScratchRegister); } else { @@ -905,8 +885,10 @@ void MacroAssembler::ResolveIndirectPointerHandle( xorq(destination, destination); bind(&done); - shlq(destination, Immediate(16)); - shrq(destination, Immediate(16)); + constexpr int kUntagShift = + kBitsPerSystemPointer - (kTrustedPointerTableTagShift - 1); + shlq(destination, Immediate(kUntagShift)); + shrq(destination, Immediate(kUntagShift)); } } @@ -936,7 +918,7 @@ void MacroAssembler::LoadParameterCountFromJSDispatchTable( shll(destination, Immediate(kJSDispatchTableEntrySizeLog2)); static_assert(JSDispatchEntry::kParameterCountMask == 0xffff); movzxwq(destination, Operand(kScratchRegister, destination, times_1, - JSDispatchEntry::kCodeObjectOffset)); + JSDispatchEntry::kParameterCountOffset)); } void MacroAssembler::LoadEntrypointAndParameterCountFromJSDispatchTable( @@ -954,7 +936,7 @@ void MacroAssembler::LoadEntrypointAndParameterCountFromJSDispatchTable( JSDispatchEntry::kEntrypointOffset)); static_assert(JSDispatchEntry::kParameterCountMask == 0xffff); movzxwq(parameter_count, Operand(kScratchRegister, offset, times_1, - JSDispatchEntry::kCodeObjectOffset)); + JSDispatchEntry::kParameterCountOffset)); } void MacroAssembler::PushDispatchHandle(Register dispatch_handle, @@ -1014,10 +996,10 @@ void MacroAssembler::CallEphemeronKeyBarrier(Register object, PopAll(registers); } -void MacroAssembler::CallIndirectPointerBarrier(Register object, - Register slot_address, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag) { +void MacroAssembler::CallTrustedPointerBarrier(Register object, + Register slot_address, + SaveFPRegsMode fp_mode, + TrustedPointerTag tag) { ASM_CODE_COMMENT(this); DCHECK(!AreAliased(object, slot_address)); // TODO(saelo) if necessary, we could introduce a "SaveRegisters version of @@ -1025,21 +1007,21 @@ void MacroAssembler::CallIndirectPointerBarrier(Register object, // probably not currently worth the effort though since stores to indirect // pointer fields are fairly rare. RegList registers = - IndirectPointerWriteBarrierDescriptor::ComputeSavedRegisters( - object, slot_address); + TrustedPointerWriteBarrierDescriptor::ComputeSavedRegisters(object, + slot_address); PushAll(registers); Register object_parameter = - IndirectPointerWriteBarrierDescriptor::ObjectRegister(); + TrustedPointerWriteBarrierDescriptor::ObjectRegister(); Register slot_address_parameter = - IndirectPointerWriteBarrierDescriptor::SlotAddressRegister(); + TrustedPointerWriteBarrierDescriptor::SlotAddressRegister(); MovePair(slot_address_parameter, slot_address, object_parameter, object); Register tag_parameter = - IndirectPointerWriteBarrierDescriptor::IndirectPointerTagRegister(); + TrustedPointerWriteBarrierDescriptor::TrustedPointerTagRegister(); Move(tag_parameter, tag); - CallBuiltin(Builtins::IndirectPointerBarrier(fp_mode)); + CallBuiltin(Builtins::TrustedPointerBarrier(fp_mode)); PopAll(registers); } @@ -1104,20 +1086,20 @@ void MacroAssembler::CallVerifySkippedWriteBarrierStub(Register object, CallCFunction(ExternalReference::verify_skipped_write_barrier(), 2); } -void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStubSaveRegisters( +void MacroAssembler::CallVerifySkippedTrustedWriteBarrierStubSaveRegisters( Register object, Register value, SaveFPRegsMode fp_mode) { ASM_CODE_COMMENT(this); PushCallerSaved(fp_mode); - CallVerifySkippedIndirectWriteBarrierStub(object, value); + CallVerifySkippedTrustedWriteBarrierStub(object, value); PopCallerSaved(fp_mode); } -void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStub(Register object, - Register value) { +void MacroAssembler::CallVerifySkippedTrustedWriteBarrierStub(Register object, + Register value) { ASM_CODE_COMMENT(this); MovePair(kCArgRegs[0], object, kCArgRegs[1], value); PrepareCallCFunction(2); - CallCFunction(ExternalReference::verify_skipped_indirect_write_barrier(), 2); + CallCFunction(ExternalReference::verify_skipped_trusted_write_barrier(), 2); } #ifdef V8_IS_TSAN @@ -1157,9 +1139,9 @@ void MacroAssembler::CallTSANStoreStub(Register address, Register value, PopAll(registers); } -void MacroAssembler::CallTSANRelaxedLoadStub(Register address, - SaveFPRegsMode fp_mode, int size, - StubCallMode mode) { +void MacroAssembler::CallTSANRelaxedLoadStub( + Register address, std::optional<SharedBaseTsanArgument> opt_shared_base, + SaveFPRegsMode fp_mode, int size, StubCallMode mode) { TSANLoadDescriptor descriptor; RegList registers = descriptor.allocatable_registers(); @@ -1167,9 +1149,25 @@ void MacroAssembler::CallTSANRelaxedLoadStub(Register address, Register address_parameter( descriptor.GetRegisterParameter(TSANLoadDescriptor::kAddress)); + Register base_parameter( + descriptor.GetRegisterParameter(TSANLoadDescriptor::kSharedBase)); + Register invoke_tsan_acquire_parameter( + descriptor.GetRegisterParameter(TSANLoadDescriptor::kInvokeTsanAcquire)); // Prepare argument registers for calling TSANRelaxedLoad. - Move(address_parameter, address); + if (opt_shared_base.has_value()) { + SharedBaseTsanArgument shared_base = opt_shared_base.value(); + DCHECK(!AreAliased(address, shared_base.reg)); + MovePair(address_parameter, address, base_parameter, shared_base.reg); + if (shared_base.must_decompress_reg) { + addq(base_parameter, kPtrComprCageBaseRegister); + } + } else { + Move(address_parameter, address); + Move(base_parameter, Immediate(0)); // Pass Smi(0) when unused. + } + Move(invoke_tsan_acquire_parameter, + Immediate(opt_shared_base.has_value() ? 1 : 0)); #if V8_ENABLE_WEBASSEMBLY if (mode != StubCallMode::kCallWasmRuntimeStub) { @@ -1218,13 +1216,13 @@ void MacroAssembler::RecordWrite(Register object, Register slot_address, if (v8_flags.slow_debug_code) { ASM_CODE_COMMENT_STRING(this, "Debug check slot_address"); Label ok; - if (slot.contains_indirect_pointer()) { + if (slot.contains_trusted_pointer()) { Push(object); // Use object register as scratch Register scratch = object; Push(slot_address); // Use slot address register to load the value into Register value_in_slot = slot_address; - LoadIndirectPointerField(value_in_slot, Operand(slot_address, 0), - slot.indirect_pointer_tag(), scratch); + LoadTrustedPointerField(value_in_slot, Operand(slot_address, 0), + slot.trusted_pointer_tag(), scratch); cmp_tagged(value, value_in_slot); // These pops don't affect the flag registers, so we can do them before // the conditional jump below. @@ -1252,7 +1250,7 @@ void MacroAssembler::RecordWrite(Register object, Register slot_address, JumpIfSmi(value, &done); } - if (slot.contains_indirect_pointer()) { + if (slot.contains_trusted_pointer()) { // The indirect pointer write barrier is only enabled during marking. JumpIfNotMarking(&done); } else { @@ -1292,9 +1290,9 @@ void MacroAssembler::RecordWrite(Register object, Register slot_address, CallRecordWriteStub(object, slot_address, fp_mode, StubCallMode::kCallBuiltinPointer); } else { - DCHECK(slot.contains_indirect_pointer()); - CallIndirectPointerBarrier(object, slot_address, fp_mode, - slot.indirect_pointer_tag()); + DCHECK(slot.contains_trusted_pointer()); + CallTrustedPointerBarrier(object, slot_address, fp_mode, + slot.trusted_pointer_tag()); } bind(&done); @@ -2311,6 +2309,20 @@ void MacroAssembler::F32x8Splat(YMMRegister dst, XMMRegister src) { vbroadcastss(dst, src); } +void MacroAssembler::F16x8Splat(XMMRegister dst, XMMRegister src) { + ASM_CODE_COMMENT(this); + CpuFeatureScope f16c_scope(this, F16C); + vcvtps2ph(dst, src, 0); + if (CpuFeatures::IsSupported(AVX2)) { + CpuFeatureScope avx2_scope(this, AVX2); + vpbroadcastw(dst, dst); + } else { + CpuFeatureScope avx_scope(this, AVX); + vpshuflw(dst, dst, uint8_t{0}); + vpunpcklqdq(dst, dst, dst); + } +} + void MacroAssembler::F64x4Min(YMMRegister dst, YMMRegister lhs, YMMRegister rhs, YMMRegister scratch) { ASM_CODE_COMMENT(this); @@ -2378,7 +2390,6 @@ void MacroAssembler::F16x8Min(YMMRegister dst, XMMRegister lhs, XMMRegister rhs, ASM_CODE_COMMENT(this); CpuFeatureScope f16c_scope(this, F16C); CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); vcvtph2ps(scratch, lhs); vcvtph2ps(scratch2, rhs); // The minps instruction doesn't propagate NaNs and +0's in its first @@ -2390,7 +2401,17 @@ void MacroAssembler::F16x8Min(YMMRegister dst, XMMRegister lhs, XMMRegister rhs, // Canonicalize NaNs by quieting and clearing the payload. vcmpunordps(dst, dst, scratch); vorps(scratch, scratch, dst); - vpsrld(dst, dst, uint8_t{10}); + if (CpuFeatures::IsSupported(AVX2)) { + CpuFeatureScope avx2_scope(this, AVX2); + vpsrld(dst, dst, uint8_t{10}); + } else { + XMMRegister xdst = dst; + XMMRegister xscratch2 = scratch2; + vextractf128(xscratch2, dst, 1); + vpsrld(xdst, xdst, uint8_t{10}); + vpsrld(xscratch2, xscratch2, uint8_t{10}); + vperm2f128(dst, dst, scratch2, 0x20); + } vandnps(dst, dst, scratch); vcvtps2ph(dst, dst, 0); } @@ -2400,7 +2421,6 @@ void MacroAssembler::F16x8Max(YMMRegister dst, XMMRegister lhs, XMMRegister rhs, ASM_CODE_COMMENT(this); CpuFeatureScope f16c_scope(this, F16C); CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); vcvtph2ps(scratch, lhs); vcvtph2ps(scratch2, rhs); // The maxps instruction doesn't propagate NaNs and +0's in its first @@ -2415,7 +2435,17 @@ void MacroAssembler::F16x8Max(YMMRegister dst, XMMRegister lhs, XMMRegister rhs, vsubps(scratch, scratch, dst); // Canonicalize NaNs by clearing the payload. Sign is non-deterministic. vcmpunordps(dst, dst, scratch); - vpsrld(dst, dst, uint8_t{10}); + if (CpuFeatures::IsSupported(AVX2)) { + CpuFeatureScope avx2_scope(this, AVX2); + vpsrld(dst, dst, uint8_t{10}); + } else { + XMMRegister xdst = dst; + XMMRegister xscratch2 = scratch2; + vextractf128(xscratch2, dst, 1); + vpsrld(xdst, xdst, uint8_t{10}); + vpsrld(xscratch2, xscratch2, uint8_t{10}); + vperm2f128(dst, dst, scratch2, 0x20); + } vandnps(dst, dst, scratch); vcvtps2ph(dst, dst, 0); } @@ -2550,12 +2580,8 @@ void MacroAssembler::I32x8SConvertF32x8(YMMRegister dst, YMMRegister src, void MacroAssembler::I16x8SConvertF16x8(YMMRegister dst, XMMRegister src, YMMRegister tmp, Register scratch) { ASM_CODE_COMMENT(this); - DCHECK(CpuFeatures::IsSupported(AVX) && CpuFeatures::IsSupported(AVX2) && - CpuFeatures::IsSupported(F16C)); - CpuFeatureScope f16c_scope(this, F16C); CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); Operand op = ExternalReferenceAsOperand( ExternalReference::address_of_wasm_i32x8_int32_overflow_as_float(), @@ -2576,42 +2602,28 @@ void MacroAssembler::I16x8SConvertF16x8(YMMRegister dst, XMMRegister src, // Convert all infinities to MAX_INT32 and let vpackssdw // clamp it to MAX_INT16 later. // 0x8000'0000 xor 0xffff'ffff(from 2 steps before) = 0x7fff'ffff (MAX_INT32) - vpxor(dst, dst, tmp); - // We now have 8 i32 values. Using one character per 16 bits: - // dst: [AABBCCDDEEFFGGHH] - // Create a copy of the upper four values in the lower half of {tmp} - // (so the upper half of the immediate doesn't matter): - vpermq(tmp, dst, 0x4E); // 0b01001110 - // tmp: [EEFFGGHHAABBCCDD] - // Now pack them together as i16s. Note that {vpackssdw} interleaves - // 128-bit chunks from each input, and takes care of saturating each - // value to kMinInt16 and kMaxInt16. We will then ignore the upper half - // of {dst}. - vpackssdw(dst, dst, tmp); - // dst: [EFGHABCDABCDEFGH] - // <--><--><--><--> - // ↑ ↑ ↑ └── from lower half of {dst} - // │ │ └────── from lower half of {tmp} - // │ └────────── from upper half of {dst} (ignored) - // └────────────── from upper half of {tmp} (ignored) + vxorps(dst, dst, tmp); + // We now have 8 i32 values in {dst}: 4 in the lower 128 bits and 4 in the + // upper 128 bits. Extract the upper 128 bits into {xtmp} and pack all 8 + // values into {xdst} as saturated i16s. + XMMRegister xdst = dst; + XMMRegister xtmp = tmp; + vextractf128(xtmp, dst, 1); + vpackssdw(xdst, xdst, xtmp); } void MacroAssembler::I16x8TruncF16x8U(YMMRegister dst, XMMRegister src, YMMRegister tmp) { ASM_CODE_COMMENT(this); - DCHECK(CpuFeatures::IsSupported(AVX) && CpuFeatures::IsSupported(AVX2) && - CpuFeatures::IsSupported(F16C)); - CpuFeatureScope f16c_scope(this, F16C); CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); Operand op = ExternalReferenceAsOperand( ExternalReference::address_of_wasm_i32x8_int32_overflow_as_float(), kScratchRegister); vcvtph2ps(dst, src); // NAN->0, negative->0. - vpxor(tmp, tmp, tmp); + vxorps(tmp, tmp, tmp); vmaxps(dst, dst, tmp); // Detect positive Infinity as an overflow above MAX_INT32. vcmpgeps(tmp, dst, op); @@ -2623,34 +2635,70 @@ void MacroAssembler::I16x8TruncF16x8U(YMMRegister dst, XMMRegister src, // Convert all infinities to MAX_INT32 and let vpackusdw // clamp it to MAX_INT16 later. // 0x8000'0000 xor 0xffff'ffff(from 2 steps before) = 0x7fff'ffff (MAX_INT32) - vpxor(dst, dst, tmp); - // Move high part to a spare register. - // See detailed comment in {I16x8SConvertF16x8} for how this works. - vpermq(tmp, dst, 0x4E); // 0b01001110 - vpackusdw(dst, dst, tmp); + vxorps(dst, dst, tmp); + XMMRegister xdst = dst; + XMMRegister xtmp = tmp; + vextractf128(xtmp, dst, 1); + vpackusdw(xdst, xdst, xtmp); +} + +void MacroAssembler::F16x8SConvertI16x8(XMMRegister dst, XMMRegister src, + YMMRegister tmp) { + ASM_CODE_COMMENT(this); + CpuFeatureScope f16c_scope(this, F16C); + CpuFeatureScope avx_scope(this, AVX); + if (CpuFeatures::IsSupported(AVX2)) { + CpuFeatureScope avx2_scope(this, AVX2); + vpmovsxwd(tmp, src); + } else { + XMMRegister xtmp = tmp; + vpshufd(xtmp, src, uint8_t{0x4E}); + vpmovsxwd(dst, src); + vpmovsxwd(xtmp, xtmp); + vperm2f128(tmp, YMMRegister::from_code(dst.code()), tmp, 0x20); + } + vcvtdq2ps(tmp, tmp); + vcvtps2ph(dst, tmp, 0); +} + +void MacroAssembler::F16x8UConvertI16x8(XMMRegister dst, XMMRegister src, + YMMRegister tmp) { + ASM_CODE_COMMENT(this); + CpuFeatureScope f16c_scope(this, F16C); + CpuFeatureScope avx_scope(this, AVX); + if (CpuFeatures::IsSupported(AVX2)) { + CpuFeatureScope avx2_scope(this, AVX2); + vpmovzxwd(tmp, src); + } else { + XMMRegister xtmp = tmp; + vpshufd(xtmp, src, uint8_t{0x4E}); + vpmovzxwd(dst, src); + vpmovzxwd(xtmp, xtmp); + vperm2f128(tmp, YMMRegister::from_code(dst.code()), tmp, 0x20); + } + vcvtdq2ps(tmp, tmp); + vcvtps2ph(dst, tmp, 0); } void MacroAssembler::F16x8Qfma(YMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, YMMRegister tmp, YMMRegister tmp2) { - CpuFeatureScope fma3_scope(this, FMA3); + DCHECK(!AreAliased(tmp, tmp2, dst)); + DCHECK(!AreAliased(XMMRegister{tmp}, XMMRegister{tmp2}, src1)); + DCHECK(!AreAliased(XMMRegister{tmp}, XMMRegister{tmp2}, src2)); + DCHECK(!AreAliased(XMMRegister{tmp}, XMMRegister{tmp2}, src3)); CpuFeatureScope f16c_scope(this, F16C); - if (dst.code() == src2.code()) { - vcvtph2ps(dst, dst); - vcvtph2ps(tmp, src1); - vcvtph2ps(tmp2, src3); - vfmadd213ps(dst, tmp, tmp2); - } else if (dst.code() == src3.code()) { - vcvtph2ps(dst, dst); - vcvtph2ps(tmp, src2); - vcvtph2ps(tmp2, src1); + vcvtph2ps(tmp, src1); + vcvtph2ps(tmp2, src2); + vcvtph2ps(dst, src3); + if (CpuFeatures::IsSupported(FMA3)) { + CpuFeatureScope fma3_scope(this, FMA3); vfmadd231ps(dst, tmp, tmp2); } else { - vcvtph2ps(dst, src1); - vcvtph2ps(tmp, src2); - vcvtph2ps(tmp2, src3); - vfmadd213ps(dst, tmp, tmp2); + CpuFeatureScope avx_scope(this, AVX); + vmulps(tmp, tmp, tmp2); + vaddps(dst, tmp, dst); } vcvtps2ph(dst, dst, 0); } @@ -2658,24 +2706,22 @@ void MacroAssembler::F16x8Qfma(YMMRegister dst, XMMRegister src1, void MacroAssembler::F16x8Qfms(YMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, YMMRegister tmp, YMMRegister tmp2) { - CpuFeatureScope fma3_scope(this, FMA3); + DCHECK(!AreAliased(tmp, tmp2, dst)); + DCHECK(!AreAliased(XMMRegister{tmp}, XMMRegister{tmp2}, src1)); + DCHECK(!AreAliased(XMMRegister{tmp}, XMMRegister{tmp2}, src2)); + DCHECK(!AreAliased(XMMRegister{tmp}, XMMRegister{tmp2}, src3)); CpuFeatureScope f16c_scope(this, F16C); - if (dst.code() == src2.code()) { - vcvtph2ps(dst, dst); - vcvtph2ps(tmp, src1); - vcvtph2ps(tmp2, src3); - vfnmadd213ps(dst, tmp, tmp2); - } else if (dst.code() == src3.code()) { - vcvtph2ps(dst, dst); - vcvtph2ps(tmp, src2); - vcvtph2ps(tmp2, src1); + vcvtph2ps(tmp, src1); + vcvtph2ps(tmp2, src2); + vcvtph2ps(dst, src3); + if (CpuFeatures::IsSupported(FMA3)) { + CpuFeatureScope fma3_scope(this, FMA3); vfnmadd231ps(dst, tmp, tmp2); } else { - vcvtph2ps(dst, src1); - vcvtph2ps(tmp, src2); - vcvtph2ps(tmp2, src3); - vfnmadd213ps(dst, tmp, tmp2); + CpuFeatureScope avx_scope(this, AVX); + vmulps(tmp, tmp, tmp2); + vsubps(dst, dst, tmp); } vcvtps2ph(dst, dst, 0); } @@ -3678,18 +3724,32 @@ void MacroAssembler::JumpCodeObject(Register code_object, CodeEntrypointTag tag, } void MacroAssembler::CallJSFunction(Register function_object, - uint16_t argument_count) { + uint16_t expected_parameter_count) { static_assert(kJavaScriptCallCodeStartRegister == rcx, "ABI mismatch"); static_assert(kJavaScriptCallDispatchHandleRegister == r15, "ABI mismatch"); movl(r15, FieldOperand(function_object, offsetof(JSFunction, dispatch_handle_))); LoadEntrypointAndParameterCountFromJSDispatchTable(rcx, rbx, r15); - // Force a safe crash if the parameter count doesn't match. + // Force a safe crash if the parameter count doesn't match the expected count + // assumed at the call site, which would corrupt the stack on underapplication + // (caller pushes max(actual_argc, expected) slots; callee pops + // max(actual_argc, parameter_count) slots). // TODO(412398354): to avoid this runtime check, we should switch all // remaining users to call the function via its dispatch handle instead. See // CallJSDispatchEntry below and crbug.com/412398354 for more details. - cmpl(rbx, Immediate(argument_count)); - SbxCheck(less_equal, AbortReason::kJSSignatureMismatch); + if (expected_parameter_count <= 1) { + // Both kDontAdaptArgumentsSentinel (0) and JSParameterCount(0) (1) are + // valid here: since actual_argc >= 1 (includes receiver), neither pads + // arguments and both pop actual_argc slots upon return. We cannot use an + // exact equality check because WasmToJS wrappers compute expected_arity + // via SFI::internal_formal_parameter_count_without_receiver(), which maps + // both cases to JSParameterCount(0) (1). + cmpl(rbx, Immediate(1)); + SbxCheck(below_equal, AbortReason::kJSSignatureMismatch); + } else { + cmpl(rbx, Immediate(expected_parameter_count)); + SbxCheck(equal, AbortReason::kJSSignatureMismatch); + } AssertSpAlignedForCall(); call(rcx); } @@ -4168,14 +4228,42 @@ Immediate MacroAssembler::ClearedValue() const { return Immediate(static_cast<int32_t>(i::kClearedWeakValue.ptr())); } +void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst, + const DoubleRegister src) { + AssertFPCRState(); + + // Subtracting 0.0 preserves all inputs except for signalling NaNs, which + // become quiet NaNs. We use subsd rather than addsd because subsd preserves + // -0.0 inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0. + Xorpd(kScratchDoubleReg, kScratchDoubleReg); + Subsd(dst, src, kScratchDoubleReg); +} + #ifdef V8_ENABLE_DEBUG_CODE void MacroAssembler::AssertSpAlignedForCall() { - if (v8_flags.enforce_x64_16byte_alignment && v8_flags.debug_code) { + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL && v8_flags.debug_code) { CheckStackAlignment(); } } +void MacroAssembler::AssertFPCRState() { + if (!v8_flags.debug_code) return; + ASM_CODE_COMMENT(this); + // Settings left to their default values: + // - Bit 6 (0x0040): DAZ (denormals-are-zeros) must not be set. + // - Bits 13-14 (0x6000): RC (rounding control) must be 0 + // (round-to-nearest-even). + // - Bit 15 (0x8000): FTZ (flush-to-zero) must not be set. + constexpr uint32_t kExpectedZeroMask = (1 << 6) | (3 << 13) | (1 << 15); + subq(rsp, Immediate(kSystemPointerSize)); + stmxcsr(Operand(rsp, 0)); + testl(Operand(rsp, 0), Immediate(kExpectedZeroMask)); + // Restore rsp without modifying flags. + leaq(rsp, Operand(rsp, kSystemPointerSize)); + Check(zero, AbortReason::kUnexpectedFPCRMode); +} + void MacroAssembler::AssertNotSmi(Register object) { if (!v8_flags.debug_code) return; ASM_CODE_COMMENT(this); @@ -4496,16 +4584,18 @@ void MacroAssembler::InvokeFunctionCode( // call sites. static_assert(kJavaScriptCallCodeStartRegister == rcx, "ABI mismatch"); LoadEntrypointFromJSDispatchTable(rcx, dispatch_handle); + Label done; switch (type) { case InvokeType::kCall: call(rcx); + jmp(&done, Label::kNear); break; case InvokeType::kJump: + // The tail jump does not return, so jumping to `done` here would be + // unreachable dead code. jmp(rcx); break; } - Label done; - jmp(&done, Label::kNear); // Deferred debug hook. bind(&debug_hook); @@ -4694,13 +4784,6 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { cmpq(Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset), Immediate(StackFrame::TypeToMarker(type))); j(equal, &ok, Label::kNear); -#if V8_ENABLE_WEBASSEMBLY - if (type == StackFrame::WASM && v8_flags.wasm_growable_stacks) { - cmpq(Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - j(equal, &ok, Label::kNear); - } -#endif Abort(AbortReason::kStackFrameTypesMustMatch); bind(&ok); } diff --git a/deps/v8/src/codegen/x64/macro-assembler-x64.h b/deps/v8/src/codegen/x64/macro-assembler-x64.h index 0a722ef83e93..19fc6e5693e5 100644 --- a/deps/v8/src/codegen/x64/macro-assembler-x64.h +++ b/deps/v8/src/codegen/x64/macro-assembler-x64.h @@ -18,7 +18,7 @@ #include "src/execution/isolate-data.h" #include "src/objects/contexts.h" #include "src/objects/tagged-index.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" namespace v8 { namespace internal { @@ -57,6 +57,15 @@ class StackArgumentsAccessor { DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor); }; +// When generating a TSAN-aware load, we sometimes pass the register of the base +// object of the load, if the object is shared. If the register holds the +// compressed object value, we must decompress it before passing it to the +// runtime function. +struct SharedBaseTsanArgument { + Register reg; + bool must_decompress_reg; +}; + class V8_EXPORT_PRIVATE MacroAssembler : public SharedMacroAssembler<MacroAssembler> { public: @@ -294,6 +303,8 @@ class V8_EXPORT_PRIVATE MacroAssembler void I16x8SConvertF16x8(YMMRegister dst, XMMRegister src, YMMRegister tmp, Register scratch); void I16x8TruncF16x8U(YMMRegister dst, XMMRegister src, YMMRegister tmp); + void F16x8SConvertI16x8(XMMRegister dst, XMMRegister src, YMMRegister tmp); + void F16x8UConvertI16x8(XMMRegister dst, XMMRegister src, YMMRegister tmp); void F16x8Qfma(YMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, YMMRegister tmp, YMMRegister tmp2); void F16x8Qfms(YMMRegister dst, XMMRegister src1, XMMRegister src2, @@ -321,6 +332,7 @@ class V8_EXPORT_PRIVATE MacroAssembler void F64x4Splat(YMMRegister dst, XMMRegister src); void F32x8Splat(YMMRegister dst, XMMRegister src); + void F16x8Splat(XMMRegister dst, XMMRegister src); void F32x8Qfma(YMMRegister dst, YMMRegister src1, YMMRegister src2, YMMRegister src3, YMMRegister tmp); @@ -581,7 +593,8 @@ class V8_EXPORT_PRIVATE MacroAssembler // validate the parameter count at runtime. Instead, we should replace them // with CallJSDispatchEntry that generates a call to a given (compile-time // constant) JSDispatchHandle. - void CallJSFunction(Register function_object, uint16_t argument_count); + void CallJSFunction(Register function_object, + uint16_t expected_parameter_count); void JumpJSFunction(Register function_object, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, @@ -714,10 +727,14 @@ class V8_EXPORT_PRIVATE MacroAssembler // Wrapper around CheckStackAlignment. This is used at call sites // to enforce rsp is correctly aligned and thus rbp is aligned within // the callee. This function can be removed and usages replaced with - // CheckStackAlignment when --enforce-x64-16byte-alignment is enabled + // CheckStackAlignment when V8_X64_16BYTE_STACK_ALIGNMENT_BOOL is enabled // by default. void AssertSpAlignedForCall() NOOP_UNLESS_DEBUG_CODE; + void AssertFPCRState() NOOP_UNLESS_DEBUG_CODE; + void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src); + void CanonicalizeNaN(const DoubleRegister reg) { CanonicalizeNaN(reg, reg); } + void AlignStackPointer(); // Activation support. @@ -757,9 +774,8 @@ class V8_EXPORT_PRIVATE MacroAssembler void CallEphemeronKeyBarrier(Register object, Register slot_address, SaveFPRegsMode fp_mode); - void CallIndirectPointerBarrier(Register object, Register slot_address, - SaveFPRegsMode fp_mode, - IndirectPointerTag tag); + void CallTrustedPointerBarrier(Register object, Register slot_address, + SaveFPRegsMode fp_mode, TrustedPointerTag tag); void CallRecordWriteStubSaveRegisters( Register object, Register slot_address, SaveFPRegsMode fp_mode, @@ -773,17 +789,18 @@ class V8_EXPORT_PRIVATE MacroAssembler SaveFPRegsMode fp_mode); void CallVerifySkippedWriteBarrierStub(Register object, Register value); - void CallVerifySkippedIndirectWriteBarrierStubSaveRegisters( + void CallVerifySkippedTrustedWriteBarrierStubSaveRegisters( Register object, Register value, SaveFPRegsMode fp_mode); - void CallVerifySkippedIndirectWriteBarrierStub(Register object, - Register value); + void CallVerifySkippedTrustedWriteBarrierStub(Register object, + Register value); #ifdef V8_IS_TSAN void CallTSANStoreStub(Register address, Register value, SaveFPRegsMode fp_mode, int size, StubCallMode mode, std::memory_order order); - void CallTSANRelaxedLoadStub(Register address, SaveFPRegsMode fp_mode, - int size, StubCallMode mode); + void CallTSANRelaxedLoadStub( + Register address, std::optional<SharedBaseTsanArgument> opt_shared_base, + SaveFPRegsMode fp_mode, int size, StubCallMode mode); #endif // V8_IS_TSAN void MoveNumber(Register dst, double value); @@ -929,9 +946,9 @@ class V8_EXPORT_PRIVATE MacroAssembler // When the sandbox is enabled, these are indirect pointers using the trusted // pointer table. Otherwise they are regular tagged fields. void LoadTrustedPointerField(Register destination, Operand field_operand, - IndirectPointerTagRange tag_range, + TrustedPointerTagRange tag_range, Register scratch); - // As above, but for kUnknownIndirectPointerTag. The type of the loaded object + // As above, but for kUnknownTrustedPointerTag. The type of the loaded object // is unknown, so this helper will check for a series of expected types and // jump to the given labels if the loaded object has a matching type. If the // field is null (with enabled sandbox) or a Smi (with disabled sandbox) and @@ -950,10 +967,10 @@ class V8_EXPORT_PRIVATE MacroAssembler // Load a code pointer field. // These are special versions of trusted pointers that, when the sandbox is - // enabled, reference code objects through the code pointer table. + // enabled, reference code objects through the trusted pointer table. void LoadCodePointerField(Register destination, Operand field_operand, Register scratch) { - LoadTrustedPointerField(destination, field_operand, kCodeIndirectPointerTag, + LoadTrustedPointerField(destination, field_operand, kCodeTrustedPointerTag, scratch); } // Store a code pointer field. @@ -961,22 +978,10 @@ class V8_EXPORT_PRIVATE MacroAssembler StoreTrustedPointerField(dst_field_operand, value); } - // Load an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void LoadIndirectPointerField(Register destination, Operand field_operand, - IndirectPointerTagRange tag_range, - Register scratch); - - // Store an indirect pointer field. - // Only available when the sandbox is enabled, but always visible to avoid - // having to place the #ifdefs into the caller. - void StoreIndirectPointerField(Operand dst_field_operand, Register value); - #ifdef V8_ENABLE_SANDBOX - // Retrieve the heap object referenced by the given indirect pointer handle. - void ResolveIndirectPointerHandle(Register destination, Register handle, - IndirectPointerTagRange tag_range); + // Retrieve the heap object referenced by the given trusted pointer handle. + void ResolveTrustedPointerHandle(Register destination, Register handle, + TrustedPointerTagRange tag_range); #endif // V8_ENABLE_SANDBOX void LoadEntrypointFromJSDispatchTable(Register destination, diff --git a/deps/v8/src/codegen/x64/register-x64.h b/deps/v8/src/codegen/x64/register-x64.h index 96e9290e5d27..e239d98430f8 100644 --- a/deps/v8/src/codegen/x64/register-x64.h +++ b/deps/v8/src/codegen/x64/register-x64.h @@ -252,8 +252,7 @@ constexpr int kRegisterPassedArguments = arraysize(kCArgRegs); // Returns the number of padding slots needed for stack pointer alignment. constexpr int ArgumentPaddingSlots(int argument_count) { - // No argument padding required. - return 0; + return V8_X64_16BYTE_STACK_ALIGNMENT_BOOL ? (argument_count & 1) : 0; } constexpr AliasingKind kFPAliasing = AliasingKind::kOverlap; diff --git a/deps/v8/src/common/code-memory-access.cc b/deps/v8/src/common/code-memory-access.cc index 7af7f4ac188d..1ac339ae38c1 100644 --- a/deps/v8/src/common/code-memory-access.cc +++ b/deps/v8/src/common/code-memory-access.cc @@ -192,6 +192,42 @@ ThreadIsolation::TryLookupJitPage(Address addr, size_t size) { return TryLookupJitPageLocked(addr, size); } +// static +std::optional<ThreadIsolation::JitPageReference> +ThreadIsolation::TryLookupJitPageWithoutBlocking(Address addr) { + // Try to lock the pages mutex and the mutex of the page itself to prevent + // potential deadlocks. The profiler can try to do a lookup from a signal + // handler. If that signal handler runs while the thread locked one of these + // mutexes, it would result in a deadlock. + std::optional<base::MutexGuard> guard = + base::MutexGuard::TryLock(trusted_data_.jit_pages_mutex_); + if (!guard) { + return {}; + } + + // upper_bound gives us an iterator to the position after address. + auto it = trusted_data_.jit_pages_->upper_bound(addr); + + // The previous page should be the one we're looking for. + if (it == trusted_data_.jit_pages_->begin()) { + return {}; + } + it--; + + std::optional<JitPageReference> jit_page = + JitPageReference::TryLock(it->second, it->first); + if (!jit_page) { + return {}; + } + + // If the address is not in the range of the jit page, return. + if (jit_page->End() <= addr) { + return {}; + } + + return jit_page; +} + // static std::optional<ThreadIsolation::JitPageReference> ThreadIsolation::TryLookupJitPageLocked(Address addr, size_t size) { @@ -299,6 +335,25 @@ ThreadIsolation::JitPageReference::JitPageReference(class JitPage* jit_page, base::Address address) : page_lock_(&jit_page->mutex_), jit_page_(jit_page), address_(address) {} +ThreadIsolation::JitPageReference::JitPageReference( + base::MutexGuard&& page_lock, class JitPage* jit_page, + base::Address address) + : page_lock_(std::move(page_lock)), + jit_page_(jit_page), + address_(address) {} + +// static +std::optional<ThreadIsolation::JitPageReference> +ThreadIsolation::JitPageReference::TryLock(class JitPage* jit_page, + base::Address address) { + std::optional<base::MutexGuard> page_lock = + base::MutexGuard::TryLock(&jit_page->mutex_); + if (!page_lock) { + return {}; + } + return JitPageReference(std::move(*page_lock), jit_page, address); +} + ThreadIsolation::JitPage::~JitPage() { // TODO(sroettger): check that the page is not in use (scan shadow stacks). } @@ -415,9 +470,19 @@ void ThreadIsolation::JitPageReference::UnregisterAllocationsExcept( jit_page_->allocations_.swap(keep_allocations); } -base::Address ThreadIsolation::JitPageReference::StartOfAllocationAt( +std::optional<base::Address> +ThreadIsolation::JitPageReference::StartOfAllocationAt( base::Address inner_pointer) { - return AllocationContaining(inner_pointer).first; + auto it = jit_page_->allocations_.upper_bound(inner_pointer); + if (it == jit_page_->allocations_.begin()) { + return {}; + } + it--; + size_t offset = inner_pointer - it->first; + if (it->second.Size() <= offset) { + return {}; + } + return it->first; } std::pair<base::Address, ThreadIsolation::JitAllocation&> @@ -644,53 +709,16 @@ bool ThreadIsolation::WriteProtectMemory( #endif } -namespace { - -class MutexUnlocker { - public: - explicit MutexUnlocker(base::Mutex& mutex) : mutex_(mutex) { - mutex_.AssertHeld(); - } - - ~MutexUnlocker() { - mutex_.AssertHeld(); - mutex_.Unlock(); - } - - private: - base::Mutex& mutex_; -}; - -} // namespace - // static -bool ThreadIsolation::CanLookupStartOfJitAllocationAt(Address inner_pointer) { - CFIMetadataWriteScope write_scope("CanLookupStartOfJitAllocationAt"); - - // Try to lock the pages mutex and the mutex of the page itself to prevent - // potential dead locks. The profiler can try to do a lookup from a signal - // handler. If that signal handler runs while the thread locked one of these - // mutexes, it would result in a dead lock. - if (!trusted_data_.jit_pages_mutex_->TryLock()) { - return false; - } - MutexUnlocker pages_mutex_unlocker(*trusted_data_.jit_pages_mutex_); - - // upper_bound gives us an iterator to the position after address. - auto it = trusted_data_.jit_pages_->upper_bound(inner_pointer); - - // The previous page should be the one we're looking for. - if (it == trusted_data_.jit_pages_->begin()) { +std::optional<Address> ThreadIsolation::TryLookupStartOfJitAllocationAt( + Address inner_pointer) { + CFIMetadataWriteScope write_scope("TryLookupStartOfJitAllocationAt"); + std::optional<JitPageReference> page = + TryLookupJitPageWithoutBlocking(inner_pointer); + if (!page) { return {}; } - it--; - - JitPage* jit_page = it->second; - if (jit_page->mutex_.TryLock()) { - jit_page->mutex_.Unlock(); - return true; - } - return false; + return page->StartOfAllocationAt(inner_pointer); } // static diff --git a/deps/v8/src/common/code-memory-access.h b/deps/v8/src/common/code-memory-access.h index cb649b558260..ca042b66e785 100644 --- a/deps/v8/src/common/code-memory-access.h +++ b/deps/v8/src/common/code-memory-access.h @@ -194,9 +194,10 @@ class V8_EXPORT ThreadIsolation { static void UnregisterWasmAllocation(Address addr, size_t size); - // Check for a potential dead lock in case we want to lookup the jit - // allocation from inside a signal handler. - static bool CanLookupStartOfJitAllocationAt(Address inner_pointer); + // Try to lookup the start of a jit allocation from inside a signal handler, + // returning std::nullopt if a required lock is already held. + static std::optional<Address> TryLookupStartOfJitAllocationAt( + Address inner_pointer); static std::optional<Address> StartOfJitAllocationAt(Address inner_pointer); // Write-protect a given range of memory. Address and size need to be page @@ -261,6 +262,10 @@ class V8_EXPORT ThreadIsolation { class V8_EXPORT JitPageReference { public: JitPageReference(class JitPage* page, Address address); + JitPageReference(base::MutexGuard&& page_lock, class JitPage* page, + Address address); + static std::optional<JitPageReference> TryLock(class JitPage* page, + Address address); JitPageReference(JitPageReference&&) V8_NOEXCEPT = default; JitPageReference(const JitPageReference&) = delete; JitPageReference& operator=(const JitPageReference&) = delete; @@ -279,7 +284,8 @@ class V8_EXPORT ThreadIsolation { const std::vector<base::Address>& addr); void UnregisterRange(base::Address addr, size_t size); - base::Address StartOfAllocationAt(base::Address inner_pointer); + std::optional<base::Address> StartOfAllocationAt( + base::Address inner_pointer); std::pair<base::Address, JitAllocation&> AllocationContaining( base::Address addr); base::Address EndOfLastAllocation(); @@ -312,8 +318,6 @@ class V8_EXPORT ThreadIsolation { size_t size_; friend class JitPageReference; - // Allow CanLookupStartOfJitAllocationAt to check if the mutex is locked. - friend bool ThreadIsolation::CanLookupStartOfJitAllocationAt(Address); }; private: @@ -363,6 +367,8 @@ class V8_EXPORT ThreadIsolation { static JitPageReference LookupJitPageLocked(Address addr, size_t size); static std::optional<JitPageReference> TryLookupJitPage(Address addr, size_t size); + static std::optional<JitPageReference> TryLookupJitPageWithoutBlocking( + Address addr); // The caller needs to hold a lock of the jit_pages_mutex_ static std::optional<JitPageReference> TryLookupJitPageLocked(Address addr, size_t size); diff --git a/deps/v8/src/common/globals.h b/deps/v8/src/common/globals.h index 16b4c069f5ef..a2c9e519e6fb 100644 --- a/deps/v8/src/common/globals.h +++ b/deps/v8/src/common/globals.h @@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include <bit> #include <limits> #include <ostream> @@ -198,8 +199,19 @@ namespace internal { // even just 1 KB less than the default stack size would be enough (see // crbug.com/1486275); to be more robust towards future CF reports we'll // use an even lower limit. +#if V8_OS_ANDROID +#define V8_DEFAULT_STACK_SIZE_KB 928 +#else #define V8_DEFAULT_STACK_SIZE_KB 960 +#endif #define V8_STACK_LIMIT_MARGIN_KB 64 +#elif V8_OS_ANDROID +// On 64-bit Android, Bionic's default pthread stack size +// (PTHREAD_STACK_SIZE_DEFAULT) is 992 KB (1 MB minus 32 KB for +// SIGNAL_STACK_SIZE_WITHOUT_GUARD). Leave the same 40 KB margin as on +// 1 MB stack systems. +#define V8_DEFAULT_STACK_SIZE_KB 952 +#define V8_STACK_LIMIT_MARGIN_KB 40 #else // Slightly less than 1MB, since Windows' default stack size for // the main execution thread is 1MB. @@ -378,6 +390,12 @@ const size_t kShortBuiltinCallsOldSpaceSizeThreshold = size_t{2} * GB; #define V8_EXPERIMENTAL_TQ_TO_TSA_BOOL false #endif +#ifdef V8_X64_16BYTE_STACK_ALIGNMENT +#define V8_X64_16BYTE_STACK_ALIGNMENT_BOOL true +#else +#define V8_X64_16BYTE_STACK_ALIGNMENT_BOOL false +#endif + #ifdef V8_ENABLE_EXPERIMENTAL_TQ_TO_TSA #ifndef V8_ENABLE_EXPERIMENTAL_TSA_BUILTINS #error "tq-to-tsa is not supported without tsa builtins" @@ -607,8 +625,13 @@ using JSDispatchHandle = constexpr JSDispatchHandle kNullJSDispatchHandle(0); +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 +constexpr int kJSDispatchTableEntrySize = 32; +constexpr int kJSDispatchTableEntrySizeLog2 = 5; +#else constexpr int kJSDispatchTableEntrySize = 16; constexpr int kJSDispatchTableEntrySizeLog2 = 4; +#endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 // The size of the virtual memory reservation for the JSDispatchTable. // As with the other tables, a maximum table size in combination with shifted @@ -621,7 +644,7 @@ constexpr int kJSDispatchTableEntrySizeLog2 = 4; constexpr size_t kJSDispatchTableReservationSize = 128 * MB; #else constexpr size_t kJSDispatchTableReservationSize = - (V8_LOWER_LIMITS_MODE_BOOL ? 16 : 256) * MB; + (V8_LOWER_LIMITS_MODE_BOOL ? 1 : 16) * kJSDispatchTableEntrySize * MB; #endif // defined(V8_TARGET_OS_IOS) && // !defined(V8_ENABLE_BUILTINS_OPTIMIZATION) // The maximum number of entries in a JSDispatchTable. @@ -689,12 +712,10 @@ static_assert(kCppHeapPointerSlotSize == sizeof(uint32_t)); static_assert(kCppHeapPointerSlotSize == kSystemPointerSize); #endif -constexpr int kIndirectPointerSize = sizeof(IndirectPointerHandle); -// When the sandbox is enabled, trusted pointers are implemented as indirect -// pointers (indices into the trusted pointer table). Otherwise they are regular -// tagged pointers. +// When the sandbox is enabled, trusted pointers are indices into the trusted +// pointer table. Otherwise they are regular tagged pointers. #ifdef V8_ENABLE_SANDBOX -constexpr int kTrustedPointerSize = kIndirectPointerSize; +constexpr int kTrustedPointerSize = sizeof(TrustedPointerHandle); using TrustedPointer_t = TrustedPointerHandle; #else constexpr int kTrustedPointerSize = kTaggedSize; @@ -907,13 +928,13 @@ enum class ContextMode { kNoContextCells, kHasContextCells }; // Whether floating point registers should be saved (and restored). enum class SaveFPRegsMode { kIgnore, kSave }; -// This enum describes the ownership semantics of an indirect pointer. -enum class IndirectPointerMode { - // A regular reference from one HeapObject to another one through an indirect +// This enum describes the ownership semantics of a trusted pointer. +enum class TrustedPointerMode { + // A regular reference from one HeapObject to another one through a trusted // pointer, where the referenced object should be kept alive as long as the // referencing object is alive. kStrong, - // A reference from one HeapObject to another one through an indirect pointer + // A reference from one HeapObject to another one through a trusted pointer // with custom ownership semantics. Used for example for references from // JSFunctions to Code objects which follow custom weak ownership semantics. kCustom @@ -1342,6 +1363,9 @@ using MaybeWeak = Union<T, Weak<T>>; // TODO(leszeks): Add a proper Zero type. using Zero = Smi; +// NaN is a special HeapNumber value. +using NaN = HeapNumber; + // Number is either a Smi or a HeapNumber. using Number = Union<Smi, HeapNumber>; // Numeric is either a Number or a BigInt. @@ -2374,10 +2398,6 @@ inline bool IsLexicalVariableMode(VariableMode mode) { return mode <= VariableMode::kLastLexicalVariableMode; } -inline bool IsResourceManagedVariableMode(VariableMode mode) { - return mode == VariableMode::kUsing || mode == VariableMode::kAwaitUsing; -} - enum VariableLocation : uint8_t { // Before and during variable allocation, a variable whose location is // not yet determined. After allocation, a variable looked up as a @@ -2542,7 +2562,7 @@ class BinaryOperationFeedback : public AllStatic { static_cast<uint32_t>(TypeIndex::kLastTypeIndex) + 1; // round up to 2^x for better memory access static constexpr uint32_t kTransitionMapStride = - base::bits::RoundUpToPowerOfTwo32(kNumTypeIndices); + std::bit_ceil(kNumTypeIndices); static constexpr Type DecodeTypeIndex(TypeIndex index) { switch (index) { @@ -2566,6 +2586,14 @@ class BinaryOperationFeedback : public AllStatic { return "Unknown"; } + static constexpr TypeIndex CombineTypeIndex(TypeIndex a, TypeIndex b) { + Type type_a = DecodeTypeIndex(a); + Type type_b = DecodeTypeIndex(b); + uint32_t combined_feedback_value = + static_cast<uint32_t>(type_a) | static_cast<uint32_t>(type_b); + return CalculateTypeIndex(combined_feedback_value); + } + private: static constexpr TypeIndex CalculateTypeIndex(uint32_t feedback_value) { #define CALCULATE_TYPE_INDEX(name) \ @@ -2578,14 +2606,6 @@ class BinaryOperationFeedback : public AllStatic { return TypeIndex::kAny; } - static constexpr TypeIndex CombineTypeIndex(TypeIndex a, TypeIndex b) { - Type type_a = DecodeTypeIndex(a); - Type type_b = DecodeTypeIndex(b); - uint32_t combined_feedback_value = - static_cast<uint32_t>(type_a) | static_cast<uint32_t>(type_b); - return CalculateTypeIndex(combined_feedback_value); - } - struct TransitionMap { uint8_t map[kNumTypeIndices][kTransitionMapStride]{}; }; @@ -2721,7 +2741,15 @@ class CompareOperationFeedback : public AllStatic { static_cast<uint32_t>(TypeIndex::kLastTypeIndex) + 1; // round up to 2^x for better memory access static constexpr uint32_t kTransitionMapStride = - base::bits::RoundUpToPowerOfTwo32(kNumTypeIndices); + std::bit_ceil(kNumTypeIndices); + + static constexpr TypeIndex CombineTypeIndex(TypeIndex a, TypeIndex b) { + Type type_a = DecodeTypeIndex(a); + Type type_b = DecodeTypeIndex(b); + uint32_t combined_feedback_value = + static_cast<uint32_t>(type_a) | static_cast<uint32_t>(type_b); + return CalculateTypeIndex(combined_feedback_value); + } private: static constexpr TypeIndex CalculateTypeIndex(uint32_t feedback_value) { @@ -2735,14 +2763,6 @@ class CompareOperationFeedback : public AllStatic { return TypeIndex::kAny; } - static constexpr TypeIndex CombineTypeIndex(TypeIndex a, TypeIndex b) { - Type type_a = DecodeTypeIndex(a); - Type type_b = DecodeTypeIndex(b); - uint32_t combined_feedback_value = - static_cast<uint32_t>(type_a) | static_cast<uint32_t>(type_b); - return CalculateTypeIndex(combined_feedback_value); - } - struct TransitionMap { uint8_t map[kNumTypeIndices][kTransitionMapStride]{}; }; @@ -2793,10 +2813,12 @@ class TypeOfFeedback { // at different points by performing an 'OR' operation. Type feedback moves // to a more generic type when we combine feedback. // kNone -> kEnumCacheKeysAndIndices -> kEnumCacheKeys -> kAny +// kNone -> kEnumeratorHolder -> kAny enum class ForInFeedback : uint8_t { kNone = 0x0, kEnumCacheKeysAndIndices = 0x1, kEnumCacheKeys = 0x3, + kEnumeratorHolder = 0x6, kAny = 0x7 }; static_assert((static_cast<int>(ForInFeedback::kNone) | @@ -2808,6 +2830,18 @@ static_assert((static_cast<int>(ForInFeedback::kEnumCacheKeysAndIndices) | static_assert((static_cast<int>(ForInFeedback::kEnumCacheKeys) | static_cast<int>(ForInFeedback::kAny)) == static_cast<int>(ForInFeedback::kAny)); +static_assert((static_cast<int>(ForInFeedback::kNone) | + static_cast<int>(ForInFeedback::kEnumeratorHolder)) == + static_cast<int>(ForInFeedback::kEnumeratorHolder)); +static_assert((static_cast<int>(ForInFeedback::kEnumCacheKeysAndIndices) | + static_cast<int>(ForInFeedback::kEnumeratorHolder)) == + static_cast<int>(ForInFeedback::kAny)); +static_assert((static_cast<int>(ForInFeedback::kEnumCacheKeys) | + static_cast<int>(ForInFeedback::kEnumeratorHolder)) == + static_cast<int>(ForInFeedback::kAny)); +static_assert((static_cast<int>(ForInFeedback::kEnumeratorHolder) | + static_cast<int>(ForInFeedback::kAny)) == + static_cast<int>(ForInFeedback::kAny)); enum class UnicodeEncoding : uint8_t { // Different unicode encodings in a |word32|: @@ -3194,7 +3228,7 @@ using NeedsContext = base::StrongAlias<struct NeedsContextTag, bool>; constexpr int kInvalidInfoId = -1; constexpr int kFunctionLiteralIdTopLevel = 0; -constexpr int kSwissNameDictionaryInitialCapacity = 4; +constexpr uint32_t kSwissNameDictionaryInitialCapacity = 4; constexpr int kSmallOrderedHashSetMinCapacity = 4; constexpr int kSmallOrderedHashMapMinCapacity = 4; diff --git a/deps/v8/src/common/message-template.h b/deps/v8/src/common/message-template.h index 4b47483f3998..2900d2381fa3 100644 --- a/deps/v8/src/common/message-template.h +++ b/deps/v8/src/common/message-template.h @@ -48,8 +48,6 @@ namespace internal { T(AwaitNotInDebugEvaluate, \ "await can not be used when evaluating code " \ "while paused in the debugger") \ - T(AtomicsMutexNotOwnedByCurrentThread, \ - "Atomics.Mutex is not owned by the current agent") \ T(AtomicsOperationNotAllowed, "% cannot be called in this context") \ T(BadRoundingType, "RoundingType is not fractionDigits") \ T(BadSortComparisonFunction, \ @@ -415,7 +413,7 @@ namespace internal { T(ArrayBufferAllocationFailed, "Array buffer allocation failed") \ T(Invalid, "Invalid % : %") \ T(InvalidArrayLength, "Invalid array length") \ - T(InvalidAtomicAccessIndex, "Invalid atomic access index") \ + T(InvalidAtomicAccessIndex, "Invalid atomic access index: %") \ T(InvalidCalendar, "Invalid calendar specified: %") \ T(InvalidCodePoint, "Invalid code point %") \ T(InvalidCountValue, "Invalid count value: %") \ @@ -424,7 +422,7 @@ namespace internal { T(InvalidDataViewLength, "Invalid DataView length %") \ T(InvalidOffset, "Start offset % is outside the bounds of the buffer") \ T(InvalidHint, "Invalid hint: %") \ - T(InvalidIndex, "Invalid value: not (convertible to) a safe integer") \ + T(InvalidIndex, "Invalid value %: not (convertible to) a safe integer") \ T(InvalidLanguageTag, "Invalid language tag: %") \ T(InvalidWeakMapKey, "Invalid value used as weak map key") \ T(InvalidWeakSetValue, "Invalid value used in weak set") \ diff --git a/deps/v8/src/common/operation.h b/deps/v8/src/common/operation.h index 8dbc3a050b1c..1a15f729dd67 100644 --- a/deps/v8/src/common/operation.h +++ b/deps/v8/src/common/operation.h @@ -91,6 +91,18 @@ constexpr inline bool IsComparisonOperation(Operation op) { } } +constexpr bool IsInlineSmiArithmeticBinaryOperationSupported( + Operation operation) { + return operation == Operation::kAdd || operation == Operation::kSubtract; +} + +constexpr bool IsInlineSmiBitwiseBinaryOperationSupported(Operation operation) { + return operation == Operation::kBitwiseAnd || + operation == Operation::kBitwiseOr || + operation == Operation::kBitwiseXor || + operation == Operation::kShiftRight; +} + inline std::ostream& operator<<(std::ostream& os, const Operation& operation) { switch (operation) { #define CASE(name) \ diff --git a/deps/v8/src/common/synchronization-point-support.cc b/deps/v8/src/common/synchronization-point-support.cc index 89bcc4756b64..70d1d799c601 100644 --- a/deps/v8/src/common/synchronization-point-support.cc +++ b/deps/v8/src/common/synchronization-point-support.cc @@ -91,7 +91,7 @@ bool SynchronizationPointSupport::WaitUntilBlocked( success = true; }; - LocalHeap* local_heap = LocalHeap::Current(); + LocalHeap* local_heap = LocalHeap::TryGetCurrent(); if (local_heap && local_heap->IsRunning()) { local_heap->ExecuteWhileParked(wait_loop); } else { diff --git a/deps/v8/src/compiler-dispatcher/lazy-compile-dispatcher.cc b/deps/v8/src/compiler-dispatcher/lazy-compile-dispatcher.cc index d2e679a2b533..1cafaadee8cd 100644 --- a/deps/v8/src/compiler-dispatcher/lazy-compile-dispatcher.cc +++ b/deps/v8/src/compiler-dispatcher/lazy-compile-dispatcher.cc @@ -7,7 +7,6 @@ #include <atomic> #include "include/v8-platform.h" -#include "src/base/fpu.h" #include "src/base/platform/mutex.h" #include "src/base/platform/time.h" #include "src/codegen/compiler.h" @@ -420,8 +419,6 @@ void LazyCompileDispatcher::ScheduleIdleTaskFromAnyThread( } void LazyCompileDispatcher::DoBackgroundWork(JobDelegate* delegate) { - base::FlushDenormalsScope flush_denormals_scope(isolate_->flush_denormals()); - TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.LazyCompileDispatcherDoBackgroundWork"); diff --git a/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc b/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc index 00b43f297347..616ec05197e8 100644 --- a/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc +++ b/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.cc @@ -5,10 +5,9 @@ #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" #include "src/base/atomicops.h" -#include "src/base/fpu.h" #include "src/base/logging.h" #include "src/base/platform/mutex.h" -#include "src/base/vector.h" +#include "src/base/unique-array.h" #include "src/codegen/compiler.h" #include "src/codegen/optimized-compilation-info.h" #include "src/execution/isolate.h" @@ -47,9 +46,6 @@ class OptimizingCompileTaskExecutor::CompileTask : public v8::JobTask { Isolate* const isolate = job->isolate(); { - base::FlushDenormalsScope flush_denormals_scope( - isolate->flush_denormals()); - // Note that LocalIsolate's lifetime is shorter than the isolate value // in task_state which is only cleared after this LocalIsolate instance // was destroyed. @@ -115,7 +111,7 @@ void OptimizingCompileTaskExecutor::EnsureStarted() { } task_states_ = - base::OwnedVector<OptimizingCompileTaskState>::New(max_tasks); + base::UniqueArray<OptimizingCompileTaskState>::New(max_tasks); job_handle_ = V8::GetCurrentPlatform()->PostJob( kTaskPriority, std::make_unique<CompileTask>(this)); } diff --git a/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.h b/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.h index baf94a40e0b3..20436e5b603c 100644 --- a/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.h +++ b/deps/v8/src/compiler-dispatcher/optimizing-compile-dispatcher.h @@ -10,7 +10,7 @@ #include "src/base/platform/condition-variable.h" #include "src/base/platform/mutex.h" -#include "src/base/vector.h" +#include "src/base/unique-array.h" #include "src/common/globals.h" #include "src/flags/flags.h" #include "src/handles/handles.h" @@ -147,7 +147,7 @@ class V8_EXPORT OptimizingCompileTaskExecutor { std::unique_ptr<JobHandle> job_handle_; - base::OwnedVector<OptimizingCompileTaskState> task_states_; + base::UniqueArray<OptimizingCompileTaskState> task_states_; // Used to avoid creating the JobHandle twice. bool is_initialized_ = false; diff --git a/deps/v8/src/compiler/OWNERS b/deps/v8/src/compiler/OWNERS index d2a7addeb76c..6f768fa3d01b 100644 --- a/deps/v8/src/compiler/OWNERS +++ b/deps/v8/src/compiler/OWNERS @@ -1,7 +1,7 @@ dmercadier@chromium.org jgruber@chromium.org +jkummerow@chromium.org manoskouk@chromium.org -mliedtke@chromium.org nicohartmann@chromium.org thibaudm@chromium.org ahaas@chromium.org @@ -10,13 +10,9 @@ victorgomes@chromium.org per-file wasm-*=clemensb@chromium.org per-file wasm-*=dlehmann@chromium.org per-file wasm-*=gdeepti@chromium.org -per-file wasm-*=jkummerow@chromium.org per-file turboshaft/wasm-*=clemensb@chromium.org per-file turboshaft/wasm-*=dlehmann@chromium.org per-file turboshaft/wasm-*=gdeepti@chromium.org -per-file turboshaft/wasm-*=jkummerow@chromium.org - -per-file pipeline.*=jkummerow@chromium.org per-file machine-operator.*=gdeepti@chromium.org diff --git a/deps/v8/src/compiler/access-builder.cc b/deps/v8/src/compiler/access-builder.cc index f5c48b4c6ea3..e14eb0bcc580 100644 --- a/deps/v8/src/compiler/access-builder.cc +++ b/deps/v8/src/compiler/access-builder.cc @@ -34,11 +34,13 @@ FieldAccess AccessBuilder::ForExternalIntPtr() { } // static -FieldAccess AccessBuilder::ForMap(WriteBarrierKind write_barrier) { +FieldAccess AccessBuilder::ForMap(WriteBarrierKind write_barrier, + SharedFlag shared_base) { FieldAccess access = {kTaggedBase, offsetof(HeapObject, map_), MaybeHandle<Name>(), OptionalMapRef(), Type::OtherInternal(), MachineType::MapInHeader(), write_barrier, "Map"}; + access.shared_base = shared_base; return access; } @@ -281,32 +283,6 @@ FieldAccess AccessBuilder::ForJSFunctionPrototypeOrInitialMap() { return access; } -// static -FieldAccess AccessBuilder::ForJSProxyTarget() { - FieldAccess access = {kTaggedBase, - offsetof(JSProxy, target_), - MaybeHandle<Name>(), - OptionalMapRef(), - Type::ReceiverOrNull(), - MachineType::TaggedPointer(), - kPointerWriteBarrier, - "JSProxyTarget"}; - return access; -} - -// static -FieldAccess AccessBuilder::ForJSProxyHandler() { - FieldAccess access = {kTaggedBase, - offsetof(JSProxy, handler_), - MaybeHandle<Name>(), - OptionalMapRef(), - Type::ReceiverOrNull(), - MachineType::TaggedPointer(), - kPointerWriteBarrier, - "JSProxyHandler"}; - return access; -} - // static FieldAccess AccessBuilder::ForJSFunctionContext() { FieldAccess access = {kTaggedBase, offsetof(JSFunction, context_), @@ -324,6 +300,7 @@ FieldAccess AccessBuilder::ForJSFunctionSharedFunctionInfo() { Handle<Name>(), OptionalMapRef(), Type::OtherInternal(), MachineType::TaggedPointer(), kPointerWriteBarrier, "JSFunctionSharedFunctionInfo"}; + access.is_immutable = true; return access; } @@ -758,13 +735,13 @@ FieldAccess AccessBuilder::ForJSRegExpData() { MaybeHandle<Name>(), OptionalMapRef(), Type::OtherInternal(), - MachineType::IndirectPointer(), - kIndirectPointerWriteBarrier, + MachineType::TrustedPointer(), + kTrustedPointerWriteBarrier, "JSRegExpData", ConstFieldInfo::None(), false, kExternalPointerNullTag, - kRegExpDataIndirectPointerTag, + kRegExpDataTrustedPointerTag, false, false}; return access; diff --git a/deps/v8/src/compiler/access-builder.h b/deps/v8/src/compiler/access-builder.h index 1f2a422d719c..ac3f1304ad11 100644 --- a/deps/v8/src/compiler/access-builder.h +++ b/deps/v8/src/compiler/access-builder.h @@ -34,7 +34,8 @@ class V8_EXPORT_PRIVATE AccessBuilder final // Access to heap object fields and elements (based on tagged pointer). // Provides access to HeapObject::map() field. - static FieldAccess ForMap(WriteBarrierKind write_barrier = kMapWriteBarrier); + static FieldAccess ForMap(WriteBarrierKind write_barrier = kMapWriteBarrier, + SharedFlag shared_base = SharedFlag{false}); // Provides access to HeapNumber::value() field. static FieldAccess ForHeapNumberValue(); @@ -104,12 +105,6 @@ class V8_EXPORT_PRIVATE AccessBuilder final // Provides access to JSFunction::prototype_or_initial_map() field. static FieldAccess ForJSFunctionPrototypeOrInitialMap(); - // Provides access to JSProxy::target() field. - static FieldAccess ForJSProxyTarget(); - - // Provides access to JSProxy::handler() field. - static FieldAccess ForJSProxyHandler(); - // Provides access to JSFunction::context() field. static FieldAccess ForJSFunctionContext(); diff --git a/deps/v8/src/compiler/access-info.cc b/deps/v8/src/compiler/access-info.cc index 94a6fd5caab2..f2768ac38286 100644 --- a/deps/v8/src/compiler/access-info.cc +++ b/deps/v8/src/compiler/access-info.cc @@ -64,7 +64,7 @@ bool CanInlinePropertyAccess(MapRef map, AccessMode access_mode) { !map.is_access_check_needed(); } #if V8_ENABLE_WEBASSEMBLY - if (IsWasmObjectMap(*map.object())) { + if (IsAnyWasmObjectMap(*map.object())) { DCHECK(!map.has_named_interceptor()); DCHECK(!map.is_access_check_needed()); // Accesses to Wasm objects all go through the prototype chain, but @@ -520,7 +520,7 @@ std::optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( return ElementAccessInfo({{map}, zone()}, map.elements_kind(), zone()); } #if V8_ENABLE_WEBASSEMBLY - if (map.IsWasmObjectMap() && + if (map.IsAnyWasmObjectMap() && (access_mode == AccessMode::kLoad || access_mode == AccessMode::kStore)) { // See if there is a Proxy on the prototype chain that will handle // element accesses. @@ -556,9 +556,11 @@ std::optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( if (!maybe_handler->IsJSObject()) return {}; JSObjectRef handler = maybe_handler.value().AsJSObject(); MapRef handler_map = handler.map(broker()); - // We could implement support for dictionary-mode handlers, but it's - // probably not worth it. - if (handler_map.is_dictionary_map()) return {}; + // We could implement support for dictionary-mode or unstable handlers, + // but it's probably not worth it. + if (handler_map.is_dictionary_map() || !handler_map.is_stable()) { + return {}; + } NameRef trap_name = access_mode == AccessMode::kLoad ? broker()->get_string() : broker()->set_string(); @@ -567,7 +569,10 @@ std::optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( if (!trap_info.IsFastDataConstant()) return {}; Representation repr = trap_info.field_representation(); if (!repr.IsHeapObject() && !repr.IsTagged()) return {}; - OptionalObjectRef trap = handler.GetOwnFastConstantDataProperty( + OptionalJSObjectRef trap_holder = trap_info.holder(); + JSObjectRef trap_holder_ref = + trap_holder.has_value() ? trap_holder.value() : handler; + OptionalObjectRef trap = trap_holder_ref.GetOwnFastConstantDataProperty( broker(), repr, trap_info.field_index(), dependencies()); if (!trap.has_value()) return {}; ObjectRef trap_value = trap.value(); @@ -607,10 +612,18 @@ std::optional<ElementAccessInfo> AccessInfoFactory::ComputeElementAccessInfo( } // Finally: all good! + trap_info.RecordDependencies(dependencies()); + if (trap_holder.has_value()) { + dependencies()->DependOnStablePrototypeChains( + trap_info.lookup_start_object_maps(), kStartAtReceiver, + trap_holder.value()); + } else { + dependencies()->DependOnStableMap(handler_map); + } bool string_keys = key_type == wasm::kWasmExternRef; return ElementAccessInfo(map, trap_value, target, string_keys, zone()); } - if (proto_map.IsWasmObjectMap()) { + if (proto_map.IsAnyWasmObjectMap()) { // Wasm objects are opaque and frozen, so we can safely skip over them. prototype = proto_map.prototype(broker()); continue; diff --git a/deps/v8/src/compiler/allocation-builder.h b/deps/v8/src/compiler/allocation-builder.h index 8af44422cd5f..bc7944de6d97 100644 --- a/deps/v8/src/compiler/allocation-builder.h +++ b/deps/v8/src/compiler/allocation-builder.h @@ -63,7 +63,7 @@ class AllocationBuilder final { // Compound store of a constant into a field. void Store(const FieldAccess& access, ObjectRef value) { - if (access.machine_type == MachineType::IndirectPointer()) { + if (access.machine_type == MachineType::TrustedPointer()) { Store(access, jsgraph()->TrustedHeapConstant(value.AsHeapObject().object())); } else { diff --git a/deps/v8/src/compiler/backend/arm/code-generator-arm.cc b/deps/v8/src/compiler/backend/arm/code-generator-arm.cc index bb60c451ec06..d87136948560 100644 --- a/deps/v8/src/compiler/backend/arm/code-generator-arm.cc +++ b/deps/v8/src/compiler/backend/arm/code-generator-arm.cc @@ -829,8 +829,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kArchCallJSFunction: { - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -839,7 +839,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( if (function->shared()->HasBuiltinId()) { Builtin builtin = function->shared()->builtin_id(); size_t expected = Builtins::GetFormalParameterCount(builtin); - if (num_arguments == expected) { + if (expected_parameter_count == expected) { __ CallBuiltin(builtin); } else { __ AssertUnreachable(AbortReason::kJSSignatureMismatch); @@ -848,7 +848,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( JSDispatchHandle dispatch_handle = function->dispatch_handle(); size_t expected = isolate()->js_dispatch_table().GetParameterCount( dispatch_handle); - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -856,7 +856,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -869,7 +870,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ cmp(cp, scratch); __ Assert(eq, AbortReason::kWrongFunctionContext); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } RecordCallPosition(instr); DCHECK_EQ(LeaveCC, i.OutputSBit()); @@ -1164,8 +1165,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } break; } - case kArchStoreIndirectWithWriteBarrier: - case kArchStoreIndirectSkippedWriteBarrier: + case kArchStoreTrustedWithWriteBarrier: + case kArchStoreTrustedSkippedWriteBarrier: UNREACHABLE(); case kArchStackSlot: { FrameOffset offset = @@ -3927,46 +3928,45 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { + if (call_descriptor->IsCFunctionCall()) { #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ StubPrologue(StackFrame::C_WASM_ENTRY); - // Reserve stack space for saving the c_entry_fp later. - __ AllocateStackSpace(kSystemPointerSize); + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ StubPrologue(StackFrame::C_WASM_ENTRY); + // Reserve stack space for saving the c_entry_fp later. + __ AllocateStackSpace(kSystemPointerSize); #else - // For balance. - if (false) { + // For balance. + if (false) { #endif // V8_ENABLE_WEBASSEMBLY - } else { - __ Push(lr, fp); - __ mov(fp, sp); - } - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); } else { - __ StubPrologue(info()->GetOutputStackFrameType()); + __ Push(lr, fp); + __ mov(fp, sp); + } + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + __ StubPrologue(info()->GetOutputStackFrameType()); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ Push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ AllocateStackSpace(kSystemPointerSize); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ Push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ AllocateStackSpace(kSystemPointerSize); } - - unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); +#endif // V8_ENABLE_WEBASSEMBLY } + unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); + int required_slots = frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount(); @@ -3986,78 +3986,98 @@ void CodeGenerator::AssembleConstructFrame() { const RegList saves = call_descriptor->CalleeSavedRegisters(); const DoubleRegList saves_fp = call_descriptor->CalleeSavedFPRegisters(); - if (required_slots > 0) { - DCHECK(frame_access_state()->has_frame()); #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; - - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { - UseScratchRegisterScope temps(masm()); - Register stack_limit = temps.Acquire(); - __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); - __ add(stack_limit, stack_limit, Operand(stack_space)); - __ cmp(sp, stack_limit); - __ b(cs, &done); - } + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - __ stm(db_w, sp, regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + UseScratchRegisterScope temps(masm()); + Register stack_limit = temps.Acquire(); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + if (stack_space > 0) { + __ add(stack_limit, stack_limit, + Operand(static_cast<int32_t>(stack_space))); + } + __ cmp(sp, stack_limit); + __ b(cs, &done); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + __ stm(db_w, sp, regs_to_save); + DoubleRegList fp_regs_to_save; + for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + if (!fp_regs_to_save.is_empty()) { __ vstm(db_w, sp, fp_regs_to_save.first(), fp_regs_to_save.last()); - __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), - Operand(stack_space)); - __ add( - WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); - __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); + } + __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), + Operand(static_cast<int32_t>(stack_space))); + __ add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ mov( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize)); + __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + if (!fp_regs_to_save.is_empty()) { __ vldm(ia_w, sp, fp_regs_to_save.first(), fp_regs_to_save.last()); - __ ldm(ia_w, sp, regs_to_save); - } else { - __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - if (v8_flags.debug_code) __ stop(); } - - __ bind(&done); + __ ldm(ia_w, sp, regs_to_save); + } else { + __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + if (v8_flags.debug_code) __ stop(); } + __ bind(&done); + } #endif // V8_ENABLE_WEBASSEMBLY - // Skip callee-saved and return slots, which are pushed below. - required_slots -= saves.Count(); - required_slots -= frame()->GetReturnSlotCount(); - required_slots -= 2 * saves_fp.Count(); - if (required_slots > 0) { - __ AllocateStackSpace(required_slots * kSystemPointerSize); - } + // Skip callee-saved and return slots, which are pushed below. + required_slots -= saves.Count(); + required_slots -= frame()->GetReturnSlotCount(); + required_slots -= 2 * saves_fp.Count(); + if (required_slots > 0) { + __ AllocateStackSpace(required_slots * kSystemPointerSize); } if (!saves_fp.is_empty()) { @@ -4126,35 +4146,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ ldr(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - __ cmp(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - __ b(&done, ne); - RegList regs_to_save; - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.set(reg); - __ stm(db_w, sp, regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - __ vstm(db_w, sp, fp_regs_to_save.first(), fp_regs_to_save.last()); - __ Move(kCArgRegs[0], ExternalReference::isolate_address()); - __ PrepareCallCFunction(1); - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - __ mov(fp, kReturnRegister0); - __ vldm(ia_w, sp, fp_regs_to_save.first(), fp_regs_to_save.last()); - __ ldm(ia_w, sp, regs_to_save); - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY Register argc_reg = r3; // Functions with JS linkage have at least one parameter (the receiver). diff --git a/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc b/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc index 908e379da41b..140c8905af3a 100644 --- a/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc +++ b/deps/v8/src/compiler/backend/arm/instruction-selector-arm.cc @@ -685,7 +685,7 @@ void InstructionSelector::VisitLoad(OpIndex node) { case MachineRepresentation::kCompressedPointer: // Fall through. case MachineRepresentation::kCompressed: // Fall through. case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kWord64: // Fall through. case MachineRepresentation::kMapWord: // Fall through. @@ -729,7 +729,7 @@ ArchOpcode GetStoreOpcode(MachineRepresentation rep) { case MachineRepresentation::kCompressedPointer: // Fall through. case MachineRepresentation::kCompressed: // Fall through. case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kWord64: // Fall through. case MachineRepresentation::kMapWord: // Fall through. diff --git a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc index f4efe50f64d1..45bad40db1da 100644 --- a/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/deps/v8/src/compiler/backend/arm64/code-generator-arm64.cc @@ -311,7 +311,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { CodeGenerator* gen, Register object, Operand offset, Register value, RecordWriteMode mode, StubCallMode stub_mode, UnwindingInfoWriter* unwinding_info_writer, - IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag) + TrustedPointerTag trusted_pointer_tag = kTrustedPointerNullTag) : OutOfLineCode(gen), object_(object), offset_(offset), @@ -323,20 +323,20 @@ class OutOfLineRecordWrite final : public OutOfLineCode { must_save_lr_(!gen->frame_access_state()->has_frame()), unwinding_info_writer_(unwinding_info_writer), zone_(gen->zone()), - indirect_pointer_tag_(indirect_pointer_tag) { + trusted_pointer_tag_(trusted_pointer_tag) { } void Generate() final { // When storing an indirect pointer, the value will always be a // full/decompressed pointer. if (COMPRESS_POINTERS_BOOL && - mode_ != RecordWriteMode::kValueIsIndirectPointer) { + mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ DecompressTagged(value_, value_); } // No need to check value page flags with the indirect pointer write barrier // because the value is always an ExposedTrustedObject. - if (mode_ != RecordWriteMode::kValueIsIndirectPointer) { + if (mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ CheckPageFlag(value_, MemoryChunk::kPointersToHereAreInterestingMask, eq, exit()); } @@ -351,12 +351,12 @@ class OutOfLineRecordWrite final : public OutOfLineCode { } if (mode_ == RecordWriteMode::kValueIsEphemeronKey) { __ CallEphemeronKeyBarrier(object_, offset_, save_fp_mode); - } else if (mode_ == RecordWriteMode::kValueIsIndirectPointer) { - // We must have a valid indirect pointer tag here. Otherwise, we risk not + } else if (mode_ == RecordWriteMode::kValueIsTrustedPointer) { + // We must have a valid trusted pointer tag here. Otherwise, we risk not // invoking the correct write barrier, which may lead to subtle issues. - CHECK(IsValidIndirectPointerTag(indirect_pointer_tag_)); - __ CallIndirectPointerBarrier(object_, offset_, save_fp_mode, - indirect_pointer_tag_); + CHECK(IsValidTrustedPointerTag(trusted_pointer_tag_)); + __ CallTrustedPointerBarrier(object_, offset_, save_fp_mode, + trusted_pointer_tag_); #if V8_ENABLE_WEBASSEMBLY } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) { // A direct call to a wasm runtime stub defined in this module. @@ -385,7 +385,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { bool must_save_lr_; UnwindingInfoWriter* const unwinding_info_writer_; Zone* zone_; - IndirectPointerTag indirect_pointer_tag_; + TrustedPointerTag trusted_pointer_tag_; }; class OutOfLineVerifySkippedWriteBarrier final : public OutOfLineCode { @@ -436,9 +436,9 @@ class OutOfLineVerifySkippedWriteBarrier final : public OutOfLineCode { Zone* zone_; }; -class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode { +class OutOfLineVerifySkippedTrustedWriteBarrier final : public OutOfLineCode { public: - OutOfLineVerifySkippedIndirectWriteBarrier( + OutOfLineVerifySkippedTrustedWriteBarrier( CodeGenerator* gen, Register object, Register value, UnwindingInfoWriter* unwinding_info_writer) : OutOfLineCode(gen), @@ -459,8 +459,8 @@ class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode { ? SaveFPRegsMode::kSave : SaveFPRegsMode::kIgnore; - __ CallVerifySkippedIndirectWriteBarrierStubSaveRegisters(object_, value_, - save_fp_mode); + __ CallVerifySkippedTrustedWriteBarrierStubSaveRegisters(object_, value_, + save_fp_mode); if (must_save_lr_) { __ Pop<MacroAssembler::kAuthLR>(padreg, lr); @@ -891,71 +891,6 @@ void CodeGenerator::AssembleDispatchHandleRegisterCheck() { void CodeGenerator::AssertNotDeoptimized() { __ AssertNotDeoptimized(); } -int32_t GetLaneMask(int32_t lane_count) { return lane_count * 2 - 1; } - -void Shuffle4Helper(MacroAssembler* masm, Arm64OperandConverter i, - VectorFormat f) { - VRegister dst = VRegister::Create(i.OutputSimd128Register().code(), f); - VRegister src0 = VRegister::Create(i.InputSimd128Register(0).code(), f); - VRegister src1 = VRegister::Create(i.InputSimd128Register(1).code(), f); - // Check for in-place shuffles, as we may need to use a temporary register - // to avoid overwriting an input. - if (dst == src0 || dst == src1) { - UseScratchRegisterScope scope(masm); - VRegister temp = scope.AcquireV(f); - if (dst == src0) { - masm->Mov(temp, src0); - src0 = temp; - } else if (dst == src1) { - masm->Mov(temp, src1); - src1 = temp; - } - } - int32_t shuffle = i.InputInt32(2); - int32_t lane_count = LaneCountFromFormat(f); - int32_t max_src0_lane = lane_count - 1; - int32_t lane_mask = GetLaneMask(lane_count); - - DCHECK_EQ(f, kFormat4S); - // Check whether we can reduce the number of vmovs by performing a dup - // first. So, for [1, 1, 2, 1] we can dup lane zero and then perform - // a single lane move for lane two. - const std::array<int, 4> input_lanes{ - shuffle & lane_mask, shuffle >> 8 & lane_mask, shuffle >> 16 & lane_mask, - shuffle >> 24 & lane_mask}; - std::array<int, 8> lane_counts = {0}; - for (int lane : input_lanes) { - ++lane_counts[lane]; - } - - // Find first duplicate lane, if any, and insert dup. - int duplicate_lane = -1; - for (size_t lane = 0; lane < lane_counts.size(); ++lane) { - if (lane_counts[lane] > 1) { - duplicate_lane = static_cast<int>(lane); - if (duplicate_lane > max_src0_lane) { - masm->Dup(dst, src1, duplicate_lane & max_src0_lane); - } else { - masm->Dup(dst, src0, duplicate_lane); - } - break; - } - } - - // Perform shuffle as a vmov per lane. - for (int i = 0; i < 4; i++) { - int lane = shuffle & lane_mask; - shuffle >>= 8; - if (lane == duplicate_lane) continue; - VRegister src = src0; - if (lane > max_src0_lane) { - src = src1; - lane &= max_src0_lane; - } - masm->Mov(dst, i, src, lane); - } -} - // Assembles an instruction after register allocation, producing machine code. CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Instruction* instr) { @@ -1039,6 +974,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( frame_access_state()->SetFrameAccessToDefault(); break; } + #endif // V8_ENABLE_WEBASSEMBLY case kArchTailCallCodeObject: { CodeEntrypointTag tag = @@ -1077,8 +1013,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kArchCallJSFunction: { - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -1088,7 +1024,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Builtin builtin = function->shared()->builtin_id(); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (Builtins::IsCompatibleJSBuiltin(builtin, num_arguments)) { + if (Builtins::IsCompatibleJSBuiltin(builtin, + expected_parameter_count)) { __ CallBuiltin(builtin); } else { __ Abort(AbortReason::kJSSignatureMismatch); @@ -1099,7 +1036,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( dispatch_handle); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -1107,7 +1044,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -1120,7 +1058,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ cmp(cp, temp); __ Assert(eq, AbortReason::kWrongFunctionContext); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } RecordCallPosition(instr); frame_access_state()->ClearSPDelta(); @@ -1325,7 +1263,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kArchStoreWithWriteBarrier: { RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); AddressingMode addressing_mode = AddressingModeField::decode(instr->opcode()); Register object = i.InputRegister(0); @@ -1350,7 +1288,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( &unwinding_info_writer_); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); __ StoreTaggedField(value, MemOperand(object, offset)); - if (mode > RecordWriteMode::kValueIsIndirectPointer) { + if (mode > RecordWriteMode::kValueIsTrustedPointer) { __ JumpIfSmi(value, ool->exit()); } __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask, @@ -1394,7 +1332,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( DCHECK_EQ(AddressingModeField::decode(instr->opcode()), kMode_MRR); RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); Register object = i.InputRegister(0); Register offset = i.InputRegister(1); Register value = i.InputRegister(2); @@ -1413,7 +1351,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( // valid if the value isn't an indirect pointer. Otherwise the value will // be a pointer table index, which will always look like a Smi (but // actually reference a pointer in the pointer table). - if (mode > RecordWriteMode::kValueIsIndirectPointer) { + if (mode > RecordWriteMode::kValueIsTrustedPointer) { __ JumpIfSmi(value, ool->exit()); } __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask, @@ -1445,9 +1383,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } break; } - case kArchStoreIndirectWithWriteBarrier: { + case kArchStoreTrustedWithWriteBarrier: { RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); - DCHECK_EQ(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_EQ(mode, RecordWriteMode::kValueIsTrustedPointer); AddressingMode addressing_mode = AddressingModeField::decode(instr->opcode()); Register object = i.InputRegister(0); @@ -1459,19 +1397,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( offset = Operand(i.InputRegister(1)); } Register value = i.InputRegister(2); - IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(i.InputInt64(3)); + DCHECK(IsValidTrustedPointerTag(tag)); auto ool = zone()->New<OutOfLineRecordWrite>( this, object, offset, value, mode, DetermineStubCallMode(), &unwinding_info_writer_, tag); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); - __ StoreIndirectPointerField(value, MemOperand(object, offset)); + __ StoreTrustedPointerField(value, MemOperand(object, offset)); __ JumpIfMarking(ool->entry()); __ Bind(ool->exit()); break; } - case kArchStoreIndirectSkippedWriteBarrier: { + case kArchStoreTrustedSkippedWriteBarrier: { AddressingMode addressing_mode = AddressingModeField::decode(instr->opcode()); Register object = i.InputRegister(0); @@ -1485,18 +1423,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register value = i.InputRegister(2); #if DEBUG - IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(i.InputInt64(3)); + DCHECK(IsValidTrustedPointerTag(tag)); #endif // DEBUG DCHECK(v8_flags.verify_write_barriers); - auto ool = zone()->New<OutOfLineVerifySkippedIndirectWriteBarrier>( + auto ool = zone()->New<OutOfLineVerifySkippedTrustedWriteBarrier>( this, object, value, &unwinding_info_writer_); __ jmp(ool->entry()); __ bind(ool->exit()); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); - __ StoreIndirectPointerField(value, MemOperand(object, offset)); + __ StoreTrustedPointerField(value, MemOperand(object, offset)); break; } case kArchStackSlot: { @@ -2125,7 +2063,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ PokePair(i.InputFloat64Register(1), i.InputFloat64Register(0), slot * kSystemPointerSize); } else { - __ PokePair(i.InputRegister(1), i.InputRegister(0), + __ PokePair(i.InputOrZeroRegister64(1), i.InputOrZeroRegister64(0), slot * kSystemPointerSize); } break; @@ -2641,11 +2579,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register base = i.InputRegister(0); int32_t offset = i.InputInt32(1); Register table = i.InputRegister(2); - IndirectPointerTag first = - static_cast<IndirectPointerTag>(i.InputInt32(3)); - IndirectPointerTag last = - static_cast<IndirectPointerTag>(i.InputInt32(4)); - IndirectPointerTagRange tag_range(first, last); + TrustedPointerTag first = static_cast<TrustedPointerTag>(i.InputInt32(3)); + TrustedPointerTag last = static_cast<TrustedPointerTag>(i.InputInt32(4)); + TrustedPointerTagRange tag_range(first, last); Register destination = i.OutputRegister(); Register handle = i.TempRegister(0); @@ -2656,9 +2592,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ Ldr(destination, MemOperand(table, handle, LSL, kTrustedPointerTableEntrySizeLog2)); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = - ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); __ And(destination, destination, mask); } else { Register tag = handle; // Reuse handle for tag @@ -2680,13 +2615,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } #endif case kArm64LdarDecompressTaggedSigned: - __ AtomicDecompressTaggedSigned(i.OutputRegister(), i.InputRegister(0), - i.InputRegister(1), i.TempRegister(0)); + __ AtomicDecompressTaggedSigned( + i.OutputRegister(), + MemOperand(i.InputRegister(0), i.InputRegister(1))); break; case kArm64LdarDecompressTagged: { - const int pc_offset = - __ AtomicDecompressTagged(i.OutputRegister(), i.InputRegister(0), - i.InputRegister(1), i.TempRegister(0)); + const int pc_offset = __ AtomicDecompressTagged( + i.OutputRegister(), + MemOperand(i.InputRegister(0), i.InputRegister(1))); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, pc_offset); break; } @@ -2709,12 +2645,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kArm64StlrCompressTagged: // To be consistent with other STLR instructions, the value is stored at // the 3rd input register instead of the 1st. - __ AtomicStoreTaggedField(i.InputRegister(2), i.InputRegister(0), - i.InputRegister(1), i.TempRegister(0)); + __ AtomicStoreTaggedField( + i.InputRegister(2), + MemOperand(i.InputRegister(0), i.InputRegister(1))); break; - case kArm64StrIndirectPointer: - __ StoreIndirectPointerField(i.InputOrZeroRegister64(0), - i.MemoryOperand(1)); + case kArm64StrTrustedPointer: + __ StoreTrustedPointerField(i.InputOrZeroRegister64(0), + i.MemoryOperand(1)); break; case kArm64StrEncodeSandboxedPointer: __ StoreSandboxedPointerField(i.InputOrZeroRegister64(0), @@ -2774,7 +2711,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kAtomicLoadInt8: DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32); ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldarb, Register32); - __ Sxtb(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxtb(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicLoadUint8: ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldarb, Register32); @@ -2782,7 +2719,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kAtomicLoadInt16: DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32); ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldarh, Register32); - __ Sxth(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxth(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicLoadUint16: ASSEMBLE_ATOMIC_LOAD_INTEGER(Ldarh, Register32); @@ -2807,14 +2744,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; case kAtomicExchangeInt8: ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(b, Register32); - __ Sxtb(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxtb(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicExchangeUint8: ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(b, Register32); break; case kAtomicExchangeInt16: ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(h, Register32); - __ Sxth(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxth(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicExchangeUint16: ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(h, Register32); @@ -2849,14 +2786,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kAtomicCompareExchangeInt8: ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(b, UXTB, Register32); - __ Sxtb(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxtb(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicCompareExchangeUint8: ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(b, UXTB, Register32); break; case kAtomicCompareExchangeInt16: ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(h, UXTH, Register32); - __ Sxth(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxth(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicCompareExchangeUint16: ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(h, UXTH, Register32); @@ -2931,14 +2868,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kAtomicSubInt8: ASSEMBLE_ATOMIC_SUB(b, Register32); - __ Sxtb(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxtb(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicSubUint8: ASSEMBLE_ATOMIC_SUB(b, Register32); break; case kAtomicSubInt16: ASSEMBLE_ATOMIC_SUB(h, Register32); - __ Sxth(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxth(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicSubUint16: ASSEMBLE_ATOMIC_SUB(h, Register32); @@ -2951,14 +2888,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; case kAtomicAndInt8: ASSEMBLE_ATOMIC_AND(b, Register32); - __ Sxtb(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxtb(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicAndUint8: ASSEMBLE_ATOMIC_AND(b, Register32); break; case kAtomicAndInt16: ASSEMBLE_ATOMIC_AND(h, Register32); - __ Sxth(i.OutputRegister(0), i.OutputRegister(0)); + __ Sxth(i.OutputRegister32(0), i.OutputRegister32(0)); break; case kAtomicAndUint16: ASSEMBLE_ATOMIC_AND(h, Register32); @@ -2972,14 +2909,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( #define ATOMIC_BINOP_CASE(op, inst, lse_instr) \ case kAtomic##op##Int8: \ ASSEMBLE_ATOMIC_BINOP(b, inst, lse_instr, Register32); \ - __ Sxtb(i.OutputRegister(0), i.OutputRegister(0)); \ + __ Sxtb(i.OutputRegister32(0), i.OutputRegister32(0)); \ break; \ case kAtomic##op##Uint8: \ ASSEMBLE_ATOMIC_BINOP(b, inst, lse_instr, Register32); \ break; \ case kAtomic##op##Int16: \ ASSEMBLE_ATOMIC_BINOP(h, inst, lse_instr, Register32); \ - __ Sxth(i.OutputRegister(0), i.OutputRegister(0)); \ + __ Sxth(i.OutputRegister32(0), i.OutputRegister32(0)); \ break; \ case kAtomic##op##Uint16: \ ASSEMBLE_ATOMIC_BINOP(h, inst, lse_instr, Register32); \ @@ -3048,6 +2985,36 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ Instr(dst, i.InputSimd128Register(1).Format(wide)); \ break; \ } +#define SIMD_LOW_NARROWING_BINOP_CASE(Op, Instr) \ + case Op: { \ + const VectorFormat wide = \ + VectorFormatFillQ(LaneSizeBits(LaneSizeField::decode(opcode))); \ + const VectorFormat narrow = VectorFormatHalfWidth(wide); \ + __ Instr(i.OutputSimd128Register().Format(narrow), \ + i.InputSimd128Register(0).Format(wide), \ + i.InputSimd128Register(1).Format(wide)); \ + break; \ + } +#define SIMD_HIGH_NARROWING_BINOP_CASE(Op, Instr) \ + case Op: { \ + const VectorFormat wide = \ + VectorFormatFillQ(LaneSizeBits(LaneSizeField::decode(opcode))); \ + const VectorFormat narrow = VectorFormatHalfWidthDoubleLanes(wide); \ + const VRegister dst = i.OutputSimd128Register().Format(narrow); \ + DCHECK_EQ(dst, i.InputSimd128Register(0).Format(narrow)); \ + __ Instr(dst, i.InputSimd128Register(1).Format(wide), \ + i.InputSimd128Register(2).Format(wide)); \ + break; \ + } +#define SIMD_SHIFT_LEFT_LONG_CASE(Op, Instr, SrcFormat, Shift) \ + case Op: { \ + const VectorFormat dst_f = \ + VectorFormatFillQ(LaneSizeBits(LaneSizeField::decode(opcode))); \ + const VectorFormat src_f = SrcFormat(dst_f); \ + __ Instr(i.OutputSimd128Register().Format(dst_f), \ + i.InputSimd128Register(0).Format(src_f), Shift); \ + break; \ + } #define SIMD_BINOP_CASE(Op, Instr, FORMAT) \ case Op: \ __ Instr(i.OutputSimd128Register().V##FORMAT(), \ @@ -3162,6 +3129,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( SIMD_HIGH_NARROWING_CASE(kArm64Sqxtn2, Sqxtn2); SIMD_LOW_NARROWING_CASE(kArm64Sqxtun, Sqxtun); SIMD_HIGH_NARROWING_CASE(kArm64Sqxtun2, Sqxtun2); + SIMD_LOW_NARROWING_BINOP_CASE(kArm64Addhn, Addhn); + SIMD_HIGH_NARROWING_BINOP_CASE(kArm64Addhn2, Addhn2); + SIMD_LOW_NARROWING_BINOP_CASE(kArm64Subhn, Subhn); + SIMD_HIGH_NARROWING_BINOP_CASE(kArm64Subhn2, Subhn2); case kArm64Sxtl: { VectorFormat wide = VectorFormatFillQ(LaneSizeBits(LaneSizeField::decode(opcode))); @@ -3194,6 +3165,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( i.InputSimd128Register(0).Format(narrow)); break; } + SIMD_SHIFT_LEFT_LONG_CASE(kArm64Sshll, Sshll, VectorFormatHalfWidth, + i.InputInt8(1)); + SIMD_SHIFT_LEFT_LONG_CASE(kArm64Sshll2, Sshll2, + VectorFormatHalfWidthDoubleLanes, + i.InputInt8(1)); + SIMD_SHIFT_LEFT_LONG_CASE(kArm64Ushll, Ushll, VectorFormatHalfWidth, + i.InputInt8(1)); + SIMD_SHIFT_LEFT_LONG_CASE(kArm64Ushll2, Ushll2, + VectorFormatHalfWidthDoubleLanes, + i.InputInt8(1)); + SIMD_SHIFT_LEFT_LONG_CASE(kArm64IShll, Shll, VectorFormatHalfWidth, + LaneSizeInBitsFromFormat(src_f)); + SIMD_SHIFT_LEFT_LONG_CASE(kArm64IShll2, Shll2, + VectorFormatHalfWidthDoubleLanes, + LaneSizeInBitsFromFormat(src_f)); case kArm64F64x2ConvertLowI32x4S: { VRegister dst = i.OutputSimd128Register().V2D(); __ Sxtl(dst, i.InputSimd128Register(0).V2S()); @@ -3351,6 +3337,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( VectorFormat s_f = ScalarFormatFromLaneSize(LaneSizeBits(LaneSizeField::decode(opcode))); VectorFormat v_f = VectorFormatFillQ(s_f); + DCHECK(v_f == kFormat4S || v_f == kFormat2D); __ Fmul(i.OutputSimd128Register().Format(v_f), i.InputSimd128Register(0).Format(v_f), i.InputSimd128Register(1).Format(s_f), i.InputInt8(2)); @@ -3376,15 +3363,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } __ Mov(dst, i.InputInt8(1), src2); break; - } - case kArm64IShll: { - int lane_size = LaneSizeBits(LaneSizeField::decode(opcode)); - VectorFormat dst_f = VectorFormatFillQ(lane_size); - VectorFormat src_f = VectorFormatHalfWidth(dst_f); - int shift_value = lane_size / 2; - __ Shll(i.OutputSimd128Register().Format(dst_f), - i.InputSimd128Register(0).Format(src_f), shift_value); - break; } SIMD_BINOP_LANE_SIZE_CASE(kArm64SShl, Sshl); SIMD_BINOP_LANE_SIZE_CASE(kArm64UShl, Ushl); @@ -3422,11 +3400,17 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kArm64IMul: { uint32_t lane_size = LaneSizeBits(LaneSizeField::decode(opcode)); - DCHECK_NE(lane_size, 64); - VectorFormat format = VectorFormatFillQ(lane_size); - __ Mul(i.OutputSimd128Register().Format(format), - i.InputSimd128Register(0).Format(format), - i.InputSimd128Register(1).Format(format)); + if (lane_size == 64) { + CpuFeatureScope scope(masm(), SVE2); + __ Mul(i.OutputSimd128Register().Z().VnD(), + i.InputSimd128Register(0).Z().VnD(), + i.InputSimd128Register(1).Z().VnD()); + } else { + VectorFormat format = VectorFormatFillQ(lane_size); + __ Mul(i.OutputSimd128Register().Format(format), + i.InputSimd128Register(0).Format(format), + i.InputSimd128Register(1).Format(format)); + } break; } case kArm64IAddv: { @@ -3696,6 +3680,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( i.InputSimd128Register(1).Format(tb)); break; } + SIMD_BINOP_LANE_SIZE_CASE(kArm64Shadd, Shadd); + SIMD_BINOP_LANE_SIZE_CASE(kArm64Uhadd, Uhadd); case kArm64Ssra: { int8_t laneSize = LaneSizeBits(LaneSizeField::decode(opcode)); VectorFormat f = VectorFormatFillQ(laneSize); @@ -3713,10 +3699,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( DCHECK_EQ(dst, i.InputSimd128Register(0).Format(f)); __ Usra(dst, i.InputSimd128Register(1).Format(f), i.InputUint8(2) & mask); break; - } - case kArm64S32x4Shuffle: { - Shuffle4Helper(masm(), i, kFormat4S); - break; } SIMD_BINOP_LANE_SIZE_CASE(kArm64S128UnzipLeft, Uzp1); SIMD_BINOP_LANE_SIZE_CASE(kArm64S128UnzipRight, Uzp2); @@ -3727,7 +3709,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( SIMD_LOW_BINOP_LANE_SIZE_CASE(kArm64S128LowZipRight, Zip2); SIMD_LOW_BINOP_LANE_SIZE_CASE(kArm64S128LowUnzipLeft, Uzp1); SIMD_LOW_BINOP_LANE_SIZE_CASE(kArm64S128LowUnzipRight, Uzp2); - case kArm64I8x16Swizzle: { + case kArm64S128Tbl1: { __ Tbl(i.OutputSimd128Register().V16B(), i.InputSimd128Register(0).V16B(), i.InputSimd128Register(1).V16B()); break; @@ -3885,6 +3867,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( #undef SIMD_UNOP_LANE_SIZE_CASE #undef SIMD_LOW_NARROWING_CASE #undef SIMD_HIGH_NARROWING_CASE +#undef SIMD_LOW_NARROWING_BINOP_CASE +#undef SIMD_HIGH_NARROWING_BINOP_CASE +#undef SIMD_SHIFT_LEFT_LONG_CASE #undef SIMD_BINOP_CASE #undef SIMD_BINOP_LANE_SIZE_CASE #undef SIMD_LOW_BINOP_LANE_SIZE_CASE @@ -4265,6 +4250,7 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); __ AssertSpAligned(); @@ -4283,164 +4269,180 @@ void CodeGenerator::AssembleConstructFrame() { const int returns = frame()->GetReturnSlotCount(); DCHECK_EQ(returns % 2, 0); - if (frame_access_state()->has_frame()) { - // Link the frame - if (call_descriptor->IsJSFunctionCall()) { - static_assert(StandardFrameConstants::kFixedFrameSize % 16 == 8); - DCHECK_EQ(required_slots % 2, 1); - __ Prologue(); - // Update required_slots count since we have just claimed one extra slot. - static_assert(MacroAssembler::kExtraSlotClaimedByPrologue == 1); - required_slots -= MacroAssembler::kExtraSlotClaimedByPrologue; + // Link the frame + if (call_descriptor->IsJSFunctionCall()) { + static_assert(StandardFrameConstants::kFixedFrameSize % 16 == 8); + DCHECK_EQ(required_slots % 2, 1); + __ Prologue(); + // Update required_slots count since we have just claimed one extra slot. + static_assert(MacroAssembler::kExtraSlotClaimedByPrologue == 1); + required_slots -= MacroAssembler::kExtraSlotClaimedByPrologue; #if V8_ENABLE_WEBASSEMBLY - } else if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmCapiFunction() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsResumeWasmContinuation() || - (call_descriptor->IsCFunctionCall() && - info()->GetOutputStackFrameType() == - StackFrame::C_WASM_ENTRY)) { - UseScratchRegisterScope temps(masm()); - Register scratch = temps.AcquireX(); - __ Mov(scratch, - StackFrame::TypeToMarker(info()->GetOutputStackFrameType())); - __ Push<MacroAssembler::kSignLR>(lr, fp, scratch, - kWasmImplicitArgRegister); - static constexpr int kSPToFPDelta = 2 * kSystemPointerSize; - __ Add(fp, sp, kSPToFPDelta); - if (call_descriptor->IsWasmCapiFunction()) { - // The C-API function has one extra slot for the PC. - required_slots++; - } - if (call_descriptor->IsResumeWasmContinuation()) { - // The stack entry wrapper does not have an instance slot, but we - // still push it for stack alignment. - required_slots--; - } -#endif // V8_ENABLE_WEBASSEMBLY - } else if (call_descriptor->kind() == CallDescriptor::kCallCodeObject) { - UseScratchRegisterScope temps(masm()); - Register scratch = temps.AcquireX(); - __ Mov(scratch, - StackFrame::TypeToMarker(info()->GetOutputStackFrameType())); - __ Push<MacroAssembler::kSignLR>(lr, fp, scratch, padreg); - static constexpr int kSPToFPDelta = 2 * kSystemPointerSize; - __ Add(fp, sp, kSPToFPDelta); - // One of the extra slots has just been claimed when pushing the padreg. - // We also know that we have at least one slot to claim here, as the typed - // frame has an odd number of fixed slots, and all other parts of the - // total frame slots are even, leaving {required_slots} to be odd. - DCHECK_GE(required_slots, 1); + } else if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmCapiFunction() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsResumeWasmContinuation() || + (call_descriptor->IsCFunctionCall() && + info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY)) { + UseScratchRegisterScope temps(masm()); + Register scratch = temps.AcquireX(); + __ Mov(scratch, + StackFrame::TypeToMarker(info()->GetOutputStackFrameType())); + __ Push<MacroAssembler::kSignLR>(lr, fp, scratch, kWasmImplicitArgRegister); + static constexpr int kSPToFPDelta = 2 * kSystemPointerSize; + __ Add(fp, sp, kSPToFPDelta); + if (call_descriptor->IsWasmCapiFunction()) { + // The C-API function has one extra slot for the PC. + required_slots++; + } + if (call_descriptor->IsResumeWasmContinuation()) { + // The stack entry wrapper does not have an instance slot, but we + // still push it for stack alignment. required_slots--; - } else { - __ Push<MacroAssembler::kSignLR>(lr, fp); - __ Mov(fp, sp); } - unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); - - // Create OSR entry if applicable - if (info()->is_osr()) { - // TurboFan OSR-compiled functions cannot be entered directly. - __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction); - - // Unoptimized code jumps directly to this entrypoint while the - // unoptimized frame is still on the stack. Optimized code uses OSR values - // directly from the unoptimized frame. Thus, all that needs to be done is - // to allocate the remaining stack slots. - __ RecordComment("-- OSR entrypoint --"); - osr_pc_offset_ = __ pc_offset(); - __ CodeEntry(); - size_t unoptimized_frame_slots = osr_helper()->UnoptimizedFrameSlots(); +#endif // V8_ENABLE_WEBASSEMBLY + } else if (call_descriptor->kind() == CallDescriptor::kCallCodeObject) { + UseScratchRegisterScope temps(masm()); + Register scratch = temps.AcquireX(); + __ Mov(scratch, + StackFrame::TypeToMarker(info()->GetOutputStackFrameType())); + __ Push<MacroAssembler::kSignLR>(lr, fp, scratch, padreg); + static constexpr int kSPToFPDelta = 2 * kSystemPointerSize; + __ Add(fp, sp, kSPToFPDelta); + // One of the extra slots has just been claimed when pushing the padreg. + // We also know that we have at least one slot to claim here, as the typed + // frame has an odd number of fixed slots, and all other parts of the + // total frame slots are even, leaving {required_slots} to be odd. + DCHECK_GE(required_slots, 1); + required_slots--; + } else { + __ Push<MacroAssembler::kSignLR>(lr, fp); + __ Mov(fp, sp); + } + unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); + + // Create OSR entry if applicable + if (info()->is_osr()) { + // TurboFan OSR-compiled functions cannot be entered directly. + __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction); + + // Unoptimized code jumps directly to this entrypoint while the + // unoptimized frame is still on the stack. Optimized code uses OSR values + // directly from the unoptimized frame. Thus, all that needs to be done is + // to allocate the remaining stack slots. + __ RecordComment("-- OSR entrypoint --"); + osr_pc_offset_ = __ pc_offset(); + __ CodeEntry(); + size_t unoptimized_frame_slots = osr_helper()->UnoptimizedFrameSlots(); #ifdef V8_ENABLE_SANDBOX_BOOL - UseScratchRegisterScope temps(masm()); - uint32_t expected_frame_size = - static_cast<uint32_t>(osr_helper()->UnoptimizedFrameSlots()) * - kSystemPointerSize + - StandardFrameConstants::kFixedFrameSizeFromFp; - Register scratch = temps.AcquireX(); - __ Add(scratch, sp, expected_frame_size); - __ Cmp(scratch, fp); - __ SbxCheck(eq, AbortReason::kOsrUnexpectedStackSize); + UseScratchRegisterScope temps(masm()); + uint32_t expected_frame_size = + static_cast<uint32_t>(osr_helper()->UnoptimizedFrameSlots()) * + kSystemPointerSize + + StandardFrameConstants::kFixedFrameSizeFromFp; + Register scratch = temps.AcquireX(); + __ Add(scratch, sp, expected_frame_size); + __ Cmp(scratch, fp); + __ SbxCheck(eq, AbortReason::kOsrUnexpectedStackSize); #endif // V8_ENABLE_SANDBOX_BOOL - DCHECK(call_descriptor->IsJSFunctionCall()); - DCHECK_EQ(unoptimized_frame_slots % 2, 1); - // One unoptimized frame slot has already been claimed when the actual - // arguments count was pushed. - required_slots -= - unoptimized_frame_slots - MacroAssembler::kExtraSlotClaimedByPrologue; - } + DCHECK(call_descriptor->IsJSFunctionCall()); + DCHECK_EQ(unoptimized_frame_slots % 2, 1); + // One unoptimized frame slot has already been claimed when the actual + // arguments count was pushed. + required_slots -= + unoptimized_frame_slots - MacroAssembler::kExtraSlotClaimedByPrologue; + } #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { - UseScratchRegisterScope temps(masm()); - Register stack_limit = temps.AcquireX(); - __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack + // exhaustion. + Label done; + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + UseScratchRegisterScope temps(masm()); + Register stack_limit = temps.AcquireX(); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + if (stack_space > 0) { __ Add(stack_limit, stack_limit, stack_space); - __ Cmp(sp, stack_limit); - __ B(hs, &done); } - - if (v8_flags.wasm_growable_stacks) { - CPURegList regs_to_save(kXRegSizeInBits, RegList{}); - regs_to_save.Combine(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.Combine( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.Combine(reg); - __ PushCPURegList(regs_to_save); - CPURegList fp_regs_to_save(kQRegSizeInBits, DoubleRegList{}); - for (auto reg : wasm::kFpParamRegisters) { - fp_regs_to_save.Combine(reg.Q()); - } - __ PushCPURegList(fp_regs_to_save); - __ Mov(WasmHandleStackOverflowDescriptor::GapRegister(), stack_space); - __ Add( - WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); - __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); - __ PopCPURegList(fp_regs_to_save); - __ PopCPURegList(regs_to_save); - } else { - __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - if (v8_flags.debug_code) __ Brk(0); + __ Cmp(sp, stack_limit); + __ B(hs, &done); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged + // spill slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + CPURegList regs_to_save(kXRegSizeInBits, RegList{}); + regs_to_save.Combine(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.Combine( + WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.Combine( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.Combine(reg); + __ PushCPURegList(regs_to_save); + CPURegList fp_regs_to_save(kQRegSizeInBits, DoubleRegList{}); + for (auto reg : wasm::kFpParamRegisters) { + fp_regs_to_save.Combine(reg.Q()); } - __ Bind(&done); - } + __ PushCPURegList(fp_regs_to_save); + __ Mov(WasmHandleStackOverflowDescriptor::GapRegister(), stack_space); + __ Add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ Mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + call_descriptor->ParameterSlotCount() * kSystemPointerSize); + __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + __ PopCPURegList(fp_regs_to_save); + __ PopCPURegList(regs_to_save); + } else { + __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + if (v8_flags.debug_code) __ Brk(0); + } + __ Bind(&done); + } #endif // V8_ENABLE_WEBASSEMBLY - // Skip callee-saved slots, which are pushed below. - required_slots -= saves.Count(); - required_slots -= saves_fp.Count(); - required_slots -= returns; + // Skip callee-saved slots, which are pushed below. + required_slots -= saves.Count(); + required_slots -= saves_fp.Count(); + required_slots -= returns; - __ Claim(required_slots); - } + __ Claim(required_slots); // Save FP registers. DCHECK_IMPLIES(saves_fp.Count() != 0, @@ -4498,42 +4500,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.AcquireX(); - __ Ldr(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - __ Cmp(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - __ B(ne, &done); - CPURegList regs_to_save(kXRegSizeInBits, RegList{}); - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.Combine(reg); - __ PushCPURegList(regs_to_save); - CPURegList fp_regs_to_save(kQRegSizeInBits, DoubleRegList{}); - for (auto reg : wasm::kFpReturnRegisters) { - fp_regs_to_save.Combine(reg.Q()); - } - __ PushCPURegList(fp_regs_to_save); - __ Mov(kCArgRegs[0], ExternalReference::isolate_address()); - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - __ Mov(fp, kReturnRegister0); - __ PopCPURegList(fp_regs_to_save); - __ PopCPURegList(regs_to_save); - if (masm()->options().enable_simulator_code) { - // The next instruction after shrinking stack is leaving the frame. - // So SP will be set to old FP there. Switch simulator stack limit here. - UseScratchRegisterScope temps{masm()}; - temps.Exclude(x16); - __ LoadStackLimit(x16, StackLimitKind::kRealStackLimit); - __ hlt(kImmExceptionIsSwitchStackLimit); - } - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY Register argc_reg = x3; // Functions with JS linkage have at least one parameter (the receiver). @@ -4912,10 +4878,19 @@ void CodeGenerator::AssembleMove(InstructionOperand* source, Constant src = g.ToConstant(source); MemOperand dst = g.ToMemOperand(destination, masm()); if (destination->IsStackSlot()) { - UseScratchRegisterScope scope(masm()); - Register temp = scope.AcquireX(); - MoveConstantToRegister(temp, src); - __ Str(temp, dst); + // A relocatable constant (e.g. a Wasm canonical signature id) is a + // placeholder that is patched later, so it must be materialized + // through the literal pool even when its value is zero. + if (RelocInfo::IsNoInfo(src.rmode()) && + ((src.type() == Constant::kInt32 && src.ToInt32() == 0) || + (src.type() == Constant::kInt64 && src.ToInt64() == 0))) { + __ Str(xzr, dst); + } else { + UseScratchRegisterScope scope(masm()); + Register temp = scope.AcquireX(); + MoveConstantToRegister(temp, src); + __ Str(temp, dst); + } } else if (destination->IsFloatStackSlot()) { if (base::bit_cast<int32_t>(src.ToFloat32()) == 0) { __ Str(wzr, dst); diff --git a/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h b/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h index 131b08a6e6cf..e965b6295ca8 100644 --- a/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h +++ b/deps/v8/src/compiler/backend/arm64/instruction-codes-arm64.h @@ -94,8 +94,7 @@ namespace compiler { V(Arm64S128LowUnzipRight) \ V(Arm64Ssra) \ V(Arm64Usra) \ - V(Arm64S32x4Shuffle) \ - V(Arm64I8x16Swizzle) \ + V(Arm64S128Tbl1) \ V(Arm64I8x16Shuffle) \ V(Arm64S128Extract) \ V(Arm64S128ExtractNarrow) \ @@ -107,10 +106,18 @@ namespace compiler { V(Arm64Sqxtn2) \ V(Arm64Sqxtun) \ V(Arm64Sqxtun2) \ + V(Arm64Addhn) \ + V(Arm64Addhn2) \ + V(Arm64Subhn) \ + V(Arm64Subhn2) \ V(Arm64Sxtl) \ V(Arm64Sxtl2) \ V(Arm64Uxtl) \ V(Arm64Uxtl2) \ + V(Arm64Sshll) \ + V(Arm64Sshll2) \ + V(Arm64Ushll) \ + V(Arm64Ushll2) \ V(Arm64FSplat) \ V(Arm64FAbs) \ V(Arm64FSqrt) \ @@ -123,6 +130,7 @@ namespace compiler { V(Arm64IExtractLane) \ V(Arm64IReplaceLane) \ V(Arm64IShll) \ + V(Arm64IShll2) \ V(Arm64IShl) \ V(Arm64IShrS) \ V(Arm64IShrU) \ @@ -201,7 +209,9 @@ namespace compiler { V(Arm64Ssubl) \ V(Arm64Ssubl2) \ V(Arm64Usubl) \ - V(Arm64Usubl2) + V(Arm64Usubl2) \ + V(Arm64Shadd) \ + V(Arm64Uhadd) #define TARGET_ARCH_OPCODE_LIST(V) \ TARGET_ARCH_OPCODE_WITH_MEMORY_ACCESS_MODE_LIST(V) \ @@ -374,7 +384,7 @@ namespace compiler { V(Arm64LdarDecompressTaggedSigned) \ V(Arm64LdarDecompressTagged) \ V(Arm64StlrCompressTagged) \ - V(Arm64StrIndirectPointer) \ + V(Arm64StrTrustedPointer) \ V(Arm64LdrDecodeSandboxedPointer) \ V(Arm64StrEncodeSandboxedPointer) \ V(Arm64DmbIsh) \ diff --git a/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc b/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc index 40077180be66..d446e2b8967e 100644 --- a/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc +++ b/deps/v8/src/compiler/backend/arm64/instruction-scheduler-arm64.cc @@ -71,7 +71,7 @@ ArchInstResource InstructionScheduler::GetInstructionResource( case kArm64StrCompressTagged: case kArm64Word64AtomicStoreWord64: case kArm64StlrCompressTagged: - case kArm64StrIndirectPointer: + case kArm64StrTrustedPointer: case kArm64StrEncodeSandboxedPointer: case kArm64DmbIsh: case kArm64DsbIsb: @@ -137,8 +137,9 @@ ArchInstResource InstructionScheduler::GetInstructionResource( case kArm64S128LowUnzipRight: case kArm64Ssra: case kArm64Usra: - case kArm64S32x4Shuffle: - case kArm64I8x16Swizzle: + case kArm64Shadd: + case kArm64Uhadd: + case kArm64S128Tbl1: case kArm64I8x16Shuffle: case kArm64S128Extract: case kArm64S128MoveLane: @@ -149,10 +150,18 @@ ArchInstResource InstructionScheduler::GetInstructionResource( case kArm64Sqxtn2: case kArm64Sqxtun: case kArm64Sqxtun2: + case kArm64Addhn: + case kArm64Addhn2: + case kArm64Subhn: + case kArm64Subhn2: case kArm64Sxtl: case kArm64Sxtl2: case kArm64Uxtl: case kArm64Uxtl2: + case kArm64Sshll: + case kArm64Sshll2: + case kArm64Ushll: + case kArm64Ushll2: case kArm64FSplat: case kArm64FAbs: case kArm64FSqrt: @@ -166,6 +175,7 @@ ArchInstResource InstructionScheduler::GetInstructionResource( case kArm64IReplaceLane: case kArm64IShl: case kArm64IShll: + case kArm64IShll2: case kArm64IShrS: case kArm64IShrU: case kArm64SShl: @@ -654,6 +664,7 @@ int InstructionScheduler::GetTargetInstructionFlags( case kArm64Mla: case kArm64Mls: case kArm64IShll: + case kArm64IShll2: case kArm64IShl: case kArm64IShrS: case kArm64IShrU: @@ -666,10 +677,18 @@ int InstructionScheduler::GetTargetInstructionFlags( case kArm64Sqxtn2: case kArm64Sqxtun: case kArm64Sqxtun2: + case kArm64Addhn: + case kArm64Addhn2: + case kArm64Subhn: + case kArm64Subhn2: case kArm64Sxtl: case kArm64Sxtl2: case kArm64Uxtl: case kArm64Uxtl2: + case kArm64Sshll: + case kArm64Sshll2: + case kArm64Ushll: + case kArm64Ushll2: case kArm64I32x4UConvertF32x4: case kArm64I32x4BitMask: case kArm64I32x4DotI8x16AddS: @@ -708,10 +727,11 @@ int InstructionScheduler::GetTargetInstructionFlags( case kArm64S128LowUnzipRight: case kArm64Ssra: case kArm64Usra: + case kArm64Shadd: + case kArm64Uhadd: case kArm64S128MoveLane: case kArm64S128MoveReg: - case kArm64S32x4Shuffle: - case kArm64I8x16Swizzle: + case kArm64S128Tbl1: case kArm64I8x16Shuffle: case kArm64S128Extract: case kArm64S128ExtractNarrow: @@ -788,7 +808,7 @@ int InstructionScheduler::GetTargetInstructionFlags( case kArm64StrPair: case kArm64StrCompressTagged: case kArm64StlrCompressTagged: - case kArm64StrIndirectPointer: + case kArm64StrTrustedPointer: case kArm64StrEncodeSandboxedPointer: case kArm64DmbIsh: case kArm64DsbIsb: @@ -1003,13 +1023,23 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) { case kArm64S128LowUnzipRight: case kArm64Ssra: case kArm64Usra: + case kArm64Shadd: + case kArm64Uhadd: case kArm64S128ExtractNarrow: case kArm64S128MoveLane: case kArm64S128MoveReg: + case kArm64Addhn: + case kArm64Addhn2: + case kArm64Subhn: + case kArm64Subhn2: case kArm64Sxtl: case kArm64Sxtl2: case kArm64Uxtl: case kArm64Uxtl2: + case kArm64Sshll: + case kArm64Sshll2: + case kArm64Ushll: + case kArm64Ushll2: case kArm64FSplat: case kArm64FAbs: case kArm64FNeg: @@ -1018,6 +1048,7 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) { case kArm64INeg: case kArm64IShl: case kArm64IShll: + case kArm64IShll2: case kArm64IShrS: case kArm64IShrU: case kArm64SShl: @@ -1070,6 +1101,7 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) { case kArm64Bcax: case kArm64Eor3: case kArm64Xar: + case kArm64S128Tbl1: return kDefaultSimdLatency; // pmin/pmax lower to compare plus bitselect. @@ -1146,8 +1178,6 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) { case kArm64F16x8DemoteF64x2Zero: case kArm64I32x4BitMask: case kArm64I64x2BitMask: - case kArm64I8x16Swizzle: - case kArm64S32x4Shuffle: case kArm64I8x16Shuffle: return kLongSimdLatency; diff --git a/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc b/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc index 6bc3280b70b9..ad354c3f146a 100644 --- a/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc +++ b/deps/v8/src/compiler/backend/arm64/instruction-selector-arm64.cc @@ -67,6 +67,9 @@ class Arm64OperandGenerator final : public OperandGenerator { selector()->Get(node).TryCast<ConstantOp>()) { if (constant->IsRelocatable()) return false; if (constant->IsIntegral() && constant->integral() == 0) return true; + if (constant->kind == ConstantOp::Kind::kSmi) { + return constant->smi().value() == 0; + } if (constant->kind == ConstantOp::Kind::kFloat32) { return constant->float32().get_bits() == 0; } @@ -249,6 +252,85 @@ void VisitRRI(InstructionSelector* selector, InstructionCode opcode, g.UseImmediate(op.lane)); } } + +bool TryEmitShiftLeftLong(InstructionSelector* selector, OpIndex node, + const Simd128ShiftOp& shift_op, LaneSize lane_size, + int shift_amount) { + using Kind = Simd128UnaryOp::Kind; + + if (auto* extension = selector->TryCast<Simd128UnaryOp>(shift_op.input())) { + const Kind kind = extension->kind; + const int source_lane_bits = LaneSizeBits(lane_size) / 2; + if (shift_amount <= source_lane_bits && + ElementSizeInBits(Simd128UnaryOp::InputElementRep(kind)) == + source_lane_bits && + selector->CanCover(node, shift_op.input())) { + const bool is_full_width_shift = shift_amount == source_lane_bits; + ArchOpcode opcode; + if (is_full_width_shift) { + switch (kind) { + case Kind::kI16x8SConvertI8x16Low: + case Kind::kI32x4SConvertI16x8Low: + case Kind::kI64x2SConvertI32x4Low: + case Kind::kI16x8UConvertI8x16Low: + case Kind::kI32x4UConvertI16x8Low: + case Kind::kI64x2UConvertI32x4Low: + opcode = kArm64IShll; + break; + case Kind::kI16x8SConvertI8x16High: + case Kind::kI32x4SConvertI16x8High: + case Kind::kI64x2SConvertI32x4High: + case Kind::kI16x8UConvertI8x16High: + case Kind::kI32x4UConvertI16x8High: + case Kind::kI64x2UConvertI32x4High: + opcode = kArm64IShll2; + break; + default: + return false; + } + } else { + switch (kind) { + case Kind::kI16x8SConvertI8x16Low: + case Kind::kI32x4SConvertI16x8Low: + case Kind::kI64x2SConvertI32x4Low: + opcode = kArm64Sshll; + break; + case Kind::kI16x8SConvertI8x16High: + case Kind::kI32x4SConvertI16x8High: + case Kind::kI64x2SConvertI32x4High: + opcode = kArm64Sshll2; + break; + case Kind::kI16x8UConvertI8x16Low: + case Kind::kI32x4UConvertI16x8Low: + case Kind::kI64x2UConvertI32x4Low: + opcode = kArm64Ushll; + break; + case Kind::kI16x8UConvertI8x16High: + case Kind::kI32x4UConvertI16x8High: + case Kind::kI64x2UConvertI32x4High: + opcode = kArm64Ushll2; + break; + default: + return false; + } + } + + Arm64OperandGenerator g(selector); + const InstructionCode code = opcode | LaneSizeField::encode(lane_size); + if (is_full_width_shift) { + selector->Emit(code, g.DefineAsRegister(node), + g.UseRegister(extension->input())); + } else { + selector->Emit(code, g.DefineAsRegister(node), + g.UseRegister(extension->input()), + g.UseImmediate(shift_amount)); + } + return true; + } + } + return false; +} + // If shift value is an immediate, we can call Shl, taking the shift // value modulo 2^width. Otherwise, emit code to perform the modulus // operation, and call Sshl. @@ -262,7 +344,12 @@ void VisitSimdShl(InstructionSelector* selector, OpIndex node, static_cast<int>(constant & (LaneSizeBits(lane_size) - 1)); if (amount == 0) { selector->EmitIdentity(node); - } else if (amount == 1) { + return; + } + if (TryEmitShiftLeftLong(selector, node, op, lane_size, amount)) { + return; + } + if (amount == 1) { selector->Emit(kArm64IAdd | LaneSizeField::encode(lane_size), g.DefineAsRegister(node), g.UseRegister(op.input()), g.UseRegister(op.input())); @@ -1060,10 +1147,7 @@ std::tuple<InstructionCode, ImmediateMode> GetStoreOpcodeAndImmediate( // We never store directly to protected pointers from generated code. UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); - case MemoryRepresentation::IndirectPointer(): - return {kArm64StrIndirectPointer, kLoadStoreImm32}; + return {kArm64StrTrustedPointer, kLoadStoreImm32}; case MemoryRepresentation::SandboxedPointer(): CHECK(!paired); return {kArm64StrEncodeSandboxedPointer, kLoadStoreImm64}; @@ -1407,8 +1491,6 @@ std::tuple<InstructionCode, ImmediateMode> GetLoadOpcodeAndImmediate( case MemoryRepresentation::ProtectedPointer(): CHECK(V8_ENABLE_SANDBOX_BOOL); return {kArm64LdrDecompressProtected, kNoImmediate}; - case MemoryRepresentation::IndirectPointer(): - UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): // Only LoadTrustedPointer uses this representation. UNREACHABLE(); @@ -1458,7 +1540,7 @@ void InstructionSelector::VisitStore(OpIndex node) { // TODO(arm64): I guess this could be done in a better way. if (write_barrier_kind != kNoWriteBarrier && !v8_flags.disable_write_barriers) { - DCHECK(CanBeTaggedOrCompressedOrIndirectPointer(representation)); + DCHECK(CanBeTaggedOrCompressedOrTrustedPointer(representation)); AddressingMode addressing_mode; InstructionOperand inputs[5]; size_t input_count = 0; @@ -1477,16 +1559,16 @@ void InstructionSelector::VisitStore(OpIndex node) { } inputs[input_count++] = g.UseUniqueRegister(store_view.value()); InstructionCode code; - if (store_rep == MemoryRepresentation::IndirectPointer()) { - DCHECK(write_barrier_kind == kIndirectPointerWriteBarrier || + if (store_rep == MemoryRepresentation::TrustedPointer()) { + DCHECK(write_barrier_kind == kTrustedPointerWriteBarrier || write_barrier_kind == kSkippedWriteBarrier); - // In this case we need to add the IndirectPointerTag as additional input. + // In this case we need to add the TrustedPointerTag as additional input. code = write_barrier_kind == kSkippedWriteBarrier - ? kArchStoreIndirectSkippedWriteBarrier - : kArchStoreIndirectWithWriteBarrier; - code |= RecordWriteModeField::encode( - RecordWriteMode::kValueIsIndirectPointer); - IndirectPointerTag tag = store_view.indirect_pointer_tag(); + ? kArchStoreTrustedSkippedWriteBarrier + : kArchStoreTrustedWithWriteBarrier; + code |= + RecordWriteModeField::encode(RecordWriteMode::kValueIsTrustedPointer); + TrustedPointerTag tag = store_view.trusted_pointer_tag(); inputs[input_count++] = g.UseImmediate64(static_cast<int64_t>(tag)); } else if (write_barrier_kind == kSkippedWriteBarrier) { code = kArchStoreSkippedWriteBarrier; @@ -1543,7 +1625,7 @@ void InstructionSelector::VisitStore(OpIndex node) { if (is_int32(delta)) { input_count = 2; InstructionOperand inputs[2]; - inputs[0] = g.UseRegister(store_view.value()); + inputs[0] = g.UseRegisterOrImmediateZero(store_view.value()); inputs[1] = g.UseImmediate(static_cast<int32_t>(delta)); opcode |= AddressingModeField::encode(kMode_Root); Emit(opcode, 0, nullptr, input_count, inputs); @@ -2456,7 +2538,7 @@ void InstructionSelector::VisitWord64Ror(OpIndex node) { V(Float64Max, kArm64Float64Max) \ V(Float32Min, kArm64Float32Min) \ V(Float64Min, kArm64Float64Min) \ - IF_SIMD128(V, I8x16Swizzle, kArm64I8x16Swizzle) + IF_SIMD128(V, I8x16Swizzle, kArm64S128Tbl1) #define RR_VISITOR(Name, opcode) \ void InstructionSelector::Visit##Name(OpIndex node) { \ @@ -3175,6 +3257,16 @@ void InstructionSelector::EmitPrepareArguments( } } + // Zero-valued constants (e.g. Smi zero) can be stored through the zero + // register, but only for non-FP parameters: the code generator dispatches + // FP pokes on the operand being an FP register. + auto poke_value = [&](const PushParameter& input) { + if (IsFloatingPoint(input.location.GetType().representation())) { + return g.UseRegister(input.node); + } + return g.UseRegisterOrImmediateZero(input.node); + }; + // Poke the arguments into the stack. while (slot >= 0) { PushParameter input0 = (*arguments)[slot]; @@ -3189,12 +3281,11 @@ void InstructionSelector::EmitPrepareArguments( // TODO(arm): Support consecutive Simd128 parameters. if (input1.node.valid() && input0.location.GetType() == input1.location.GetType()) { - Emit(kArm64PokePair, g.NoOutput(), g.UseRegister(input0.node), - g.UseRegister(input1.node), g.TempImmediate(slot)); + Emit(kArm64PokePair, g.NoOutput(), poke_value(input0), poke_value(input1), + g.TempImmediate(slot)); slot -= 2; } else { - Emit(kArm64Poke, g.NoOutput(), g.UseRegister(input0.node), - g.TempImmediate(slot)); + Emit(kArm64Poke, g.NoOutput(), poke_value(input0), g.TempImmediate(slot)); slot--; } } @@ -5009,6 +5100,7 @@ void InstructionSelector::VisitInt64AbsWithOverflow(OpIndex node) { V(F32x4RelaxedMax, kArm64FMax, LaneSize::kL32) \ V(F16x8Add, kArm64FAdd, LaneSize::kL16) \ V(F16x8Sub, kArm64FSub, LaneSize::kL16) \ + V(F16x8Mul, kArm64FMul, LaneSize::kL16) \ V(F16x8Div, kArm64FDiv, LaneSize::kL16) \ V(F16x8Min, kArm64FMin, LaneSize::kL16) \ V(F16x8Max, kArm64FMax, LaneSize::kL16) \ @@ -5445,10 +5537,110 @@ SIMD_BINOP_LIST(SIMD_VISIT_BINOP) #undef SIMD_VISIT_BINOP #undef SIMD_BINOP_LIST +namespace { + +struct AddSubHNMatch { + OpIndex left; + OpIndex right; + LaneSize lane_size; + InstructionCode low_opcode; + InstructionCode high_opcode; +}; + +std::optional<AddSubHNMatch> TryMatchAddSubHN(InstructionSelector* selector, + const Simd128ShiftOp& shift) { + using ShiftKind = Simd128ShiftOp::Kind; + using BinopKind = Simd128BinopOp::Kind; + + if (shift.kind == any_of(ShiftKind::kI16x8ShrS, ShiftKind::kI16x8ShrU, + ShiftKind::kI32x4ShrS, ShiftKind::kI32x4ShrU, + ShiftKind::kI64x2ShrS, ShiftKind::kI64x2ShrU)) { + if (const auto* binop = selector->TryCast<Simd128BinopOp>(shift.input())) { + const bool is_add = + binop->kind == any_of(BinopKind::kI16x8Add, BinopKind::kI32x4Add, + BinopKind::kI64x2Add); + const bool is_sub = + binop->kind == any_of(BinopKind::kI16x8Sub, BinopKind::kI32x4Sub, + BinopKind::kI64x2Sub); + + if ((is_add || is_sub) && + binop->input_element_rep() == shift.input_element_rep()) { + const int lane_bits = ElementSizeInBits(shift.input_element_rep()); + const int narrow_lane_bits = lane_bits / 2; + + int32_t amount; + if (selector->MatchIntegralWord32Constant(shift.shift(), &amount) && + (amount & (lane_bits - 1)) == narrow_lane_bits) { + const LaneSize lane_size = LaneSizeFromBits(lane_bits); + const InstructionCode lane_size_field = + LaneSizeField::encode(lane_size); + + return AddSubHNMatch{ + binop->left(), binop->right(), lane_size, + (is_add ? kArm64Addhn : kArm64Subhn) | lane_size_field, + (is_add ? kArm64Addhn2 : kArm64Subhn2) | lane_size_field}; + } + } + } + } + + return std::nullopt; +} + +bool TryEmitAddSubHNFromNarrow(InstructionSelector* selector, OpIndex node, + const Simd128BinopOp& op) { + DCHECK(op.kind == any_of(Simd128BinopOp::Kind::kI8x16SConvertI16x8, + Simd128BinopOp::Kind::kI8x16UConvertI16x8, + Simd128BinopOp::Kind::kI16x8SConvertI32x4, + Simd128BinopOp::Kind::kI16x8UConvertI32x4)); + if (!selector->CanCover(node, op.left()) || + !selector->CanCover(node, op.right())) { + return false; + } + const auto* low_shift = selector->TryCast<Simd128ShiftOp>(op.left()); + const auto* high_shift = selector->TryCast<Simd128ShiftOp>(op.right()); + if (!low_shift || !high_shift || high_shift->kind != low_shift->kind) { + return false; + } + const bool is_signed = + op.kind == any_of(Simd128BinopOp::Kind::kI8x16SConvertI16x8, + Simd128BinopOp::Kind::kI16x8SConvertI32x4); + if (low_shift->IsArithmeticShiftRight() != is_signed || + low_shift->input_element_rep() != op.input_element_rep()) { + return false; + } + if (!selector->CanCover(op.left(), low_shift->input()) || + !selector->CanCover(op.right(), high_shift->input())) { + return false; + } + + std::optional<AddSubHNMatch> low = TryMatchAddSubHN(selector, *low_shift); + if (!low) { + return false; + } + std::optional<AddSubHNMatch> high = TryMatchAddSubHN(selector, *high_shift); + if (!high) { + return false; + } + + Arm64OperandGenerator g(selector); + InstructionOperand temp = g.TempSimd128Register(); + selector->Emit(low->low_opcode, temp, g.UseRegister(low->left), + g.UseRegister(low->right)); + selector->Emit(high->high_opcode, g.DefineSameAsFirst(node), temp, + g.UseRegister(high->left), g.UseRegister(high->right)); + return true; +} + +} // namespace + #define SIMD_VISIT_INT_NARROWING(Name, Instr, LaneSize) \ void InstructionSelector::Visit##Name(OpIndex node) { \ - Arm64OperandGenerator g(this); \ const Simd128BinopOp& op = Cast<Simd128BinopOp>(node); \ + if (TryEmitAddSubHNFromNarrow(this, node, op)) { \ + return; \ + } \ + Arm64OperandGenerator g(this); \ const InstructionCode lane_size = LaneSizeField::encode(LaneSize); \ const InstructionOperand low = g.TempSimd128Register(); \ Emit(kArm64##Instr | lane_size, low, g.UseRegister(op.left())); \ @@ -5495,6 +5687,7 @@ struct MulWithDup { template <int LANES> MulWithDup TryMatchMulWithDup(InstructionSelector* selector, OpIndex node) { + static_assert(LANES == 4 || LANES == 2); // Pattern match: // f32x4.mul(x, shuffle(x, y, indices)) => f32x4.mul(x, y, laneidx) // f64x2.mul(x, shuffle(x, y, indices)) => f64x2.mul(x, y, laneidx) @@ -5533,19 +5726,61 @@ MulWithDup TryMatchMulWithDup(InstructionSelector* selector, OpIndex node) { return {input, dup_node, index}; } -} // namespace -void InstructionSelector::VisitF16x8Mul(OpIndex node) { - if (MulWithDup result = TryMatchMulWithDup<8>(this, node)) { - Arm64OperandGenerator g(this); - Emit(kArm64FMulElement | LaneSizeField::encode(LaneSize::kL16), - g.DefineAsRegister(node), g.UseRegister(result.input), - g.UseRegister(result.dup_node), g.UseImmediate(result.index)); - } else { - return VisitRRR(this, kArm64FMul | LaneSizeField::encode(LaneSize::kL16), - node); +bool TryEmitI64x2MixedSignExtMul(InstructionSelector* selector, OpIndex node) { + const Simd128BinopOp& op = selector->Cast<Simd128BinopOp>(node); + using Kind = Simd128UnaryOp::Kind; + const auto* signed_ext = selector->TryCast<Simd128UnaryOp>(op.left()); + const auto* unsigned_ext = selector->TryCast<Simd128UnaryOp>(op.right()); + if (signed_ext && unsigned_ext && selector->CanCover(node, op.left()) && + selector->CanCover(node, op.right())) { + if (signed_ext->kind == + any_of(Kind::kI64x2UConvertI32x4Low, Kind::kI64x2UConvertI32x4High)) { + std::swap(signed_ext, unsigned_ext); + } + const bool low = signed_ext->kind == Kind::kI64x2SConvertI32x4Low && + unsigned_ext->kind == Kind::kI64x2UConvertI32x4Low; + const bool high = signed_ext->kind == Kind::kI64x2SConvertI32x4High && + unsigned_ext->kind == Kind::kI64x2UConvertI32x4High; + if (low || high) { + Arm64OperandGenerator g(selector); + + // Let a and b be the original signed and unsigned 32-bit lanes. + InstructionOperand signed_input = g.UseRegister(signed_ext->input()); + InstructionOperand unsigned_input = g.UseRegister(unsigned_ext->input()); + + // Replicate b's top bit across each 32-bit lane. + // mask = b[31] ? 0xffffffff : 0 + InstructionOperand sign_mask = g.TempSimd128Register(); + selector->Emit(kArm64IShrS | LaneSizeField::encode(LaneSize::kL32), + sign_mask, unsigned_input, g.TempImmediate(31)); + + // Select a where b would be negative if interpreted as signed. + // correction_lanes = b[31] ? a : 0 + InstructionOperand correction_lanes = g.TempSimd128Register(); + selector->Emit(kArm64S128And, correction_lanes, sign_mask, signed_input); + + // Shift the selected low or high lanes into the upper 32 bits. + // correction = correction_lanes * 2^32 + InstructionOperand correction = g.TempSimd128Register(); + selector->Emit((high ? kArm64IShll2 : kArm64IShll) | + LaneSizeField::encode(LaneSize::kL64), + correction, correction_lanes); + + // Multiply the lanes as signed and accumulate the correction. + // If b < 2^31, signed32(b) = b and correction = 0. + // If b >= 2^31, signed32(b) = b - 2^32 and correction = a * 2^32. + // result = a * signed32(b) + correction = a * b + selector->Emit((high ? kArm64Smlal2 : kArm64Smlal) | + LaneSizeField::encode(LaneSize::kL64), + g.DefineSameAsFirst(node), correction, signed_input, + unsigned_input); + return true; + } } + return false; } +} // namespace void InstructionSelector::VisitF32x4Mul(OpIndex node) { if (MulWithDup result = TryMatchMulWithDup<4>(this, node)) { @@ -5572,11 +5807,19 @@ void InstructionSelector::VisitF64x2Mul(OpIndex node) { } void InstructionSelector::VisitI64x2Mul(OpIndex node) { + if (TryEmitI64x2MixedSignExtMul(this, node)) return; + Arm64OperandGenerator g(this); const Simd128BinopOp& op = Cast<Simd128BinopOp>(node); OpIndex left = op.left(); OpIndex right = op.right(); + // Call unpredicated SVE2 mul if supported. + if (IsSupported(SVE2) && CpuFeatures::svevlen() == kSimd128Size) { + return VisitRRR(this, kArm64IMul | LaneSizeField::encode(LaneSize::kL64), + node); + } + // This 2x64-bit multiplication is performed with several 32-bit // multiplications. @@ -5685,6 +5928,29 @@ bool ShraHelper(InstructionSelector* selector, OpIndex node, LaneSize lane_size, return false; } + // Matches (a & b) + ((a ^ b) >> 1) or (a & b) + ((b ^ a) >> 1) + // Since a + b = 2 x (a & b) + (a ^ b), right shift for a half-add + // floor((a + b) / 2) = (a & b) + ((a ^ b) >> 1) + if (lane_size != LaneSize::kL64 && + (constant & (LaneSizeBits(lane_size) - 1)) == 1 && + selector->Get(m.other_input()).Is<turboshaft::Opmask::kSimd128And>() && + selector->Get(shiftop.input()).Is<turboshaft::Opmask::kSimd128Xor>() && + selector->CanCover(node, m.other_input()) && + selector->CanCover(m.matched_input(), shiftop.input())) { + const auto& and_op = selector->Get(m.other_input()).Cast<Simd128BinopOp>(); + const auto& xor_op = selector->Get(shiftop.input()).Cast<Simd128BinopOp>(); + + if ((and_op.left() == xor_op.left() && and_op.right() == xor_op.right()) || + (and_op.left() == xor_op.right() && and_op.right() == xor_op.left())) { + const InstructionCode half_add_code = + shra_code == kArm64Ssra ? kArm64Shadd : kArm64Uhadd; + selector->Emit(half_add_code | LaneSizeField::encode(lane_size), + g.DefineAsRegister(node), g.UseRegister(and_op.left()), + g.UseRegister(and_op.right())); + return true; + } + } + // If shifting by zero, just do the addition if (constant % LaneSizeBits(lane_size) == 0) { selector->Emit(add_code | LaneSizeField::encode(lane_size), @@ -6615,6 +6881,119 @@ void EmitShuffle2(InstructionSelector* selector, OpIndex node, OpIndex input0, } } +template <int32_t lane_size> +void EmitShuffle4(InstructionSelector* selector, OpIndex node, OpIndex input0, + OpIndex input1, std::array<uint8_t, 4> shuffle) { + Arm64OperandGenerator g(selector); + + // Find first duplicate lane, if any. + std::array<unsigned, 32> lane_counts = {0}; + for (uint8_t lane : shuffle) { + DCHECK_LT(lane, lane_counts.size()); + ++lane_counts[lane]; + } + int32_t duplicate_lane = -1; + for (size_t lane = 0; lane < lane_counts.size(); ++lane) { + if (lane_counts[lane] > 1) { + duplicate_lane = static_cast<int32_t>(lane); + break; + } + } + + if (duplicate_lane == -1) { + // If no duplicate lane is found, then use a TBL if we've got a single + // source. + if (input0 == input1) { + if constexpr (lane_size == 8) { + uint32_t mask = SimdShuffle::Pack4Lanes(&shuffle[0]); + InstructionOperand mask_vector = g.TempSimd128Register(); + selector->Emit(kArm64S128Const, mask_vector, g.UseImmediate(mask), + g.UseImmediate(mask), g.UseImmediate(mask), + g.UseImmediate(mask)); + selector->Emit(kArm64S128Tbl1, g.DefineAsRegister(node), + g.UseRegister(input0), mask_vector); + return; + } else if constexpr (lane_size == 16) { + std::array<uint8_t, kSimd128HalfSize> mask; + for (size_t i = 0; i < shuffle.size(); ++i) { + uint8_t lane = shuffle[i]; + DCHECK_LT(lane, kSimd128HalfSize); + mask[i * 2] = static_cast<uint8_t>(lane * 2); + mask[i * 2 + 1] = static_cast<uint8_t>(lane * 2 + 1); + } + uint32_t mask_lo = SimdShuffle::Pack4Lanes(&mask[0]); + uint32_t mask_hi = SimdShuffle::Pack4Lanes(&mask[4]); + InstructionOperand mask_vector = g.TempSimd128Register(); + selector->Emit(kArm64S128Const, mask_vector, g.UseImmediate(mask_lo), + g.UseImmediate(mask_hi), g.UseImmediate(mask_lo), + g.UseImmediate(mask_hi)); + selector->Emit(kArm64S128Tbl1, g.DefineAsRegister(node), + g.UseRegister(input0), mask_vector); + return; + } + } + // If none is found, we'll just duplicate the first lane. + duplicate_lane = shuffle[0]; + } + + bool is_only_dup = true; + for (uint8_t lane : shuffle) { + if (lane != duplicate_lane) { + is_only_dup = false; + break; + } + } + + // Insert the dup. + OpIndex input = GetInput<lane_size>(input0, input1, duplicate_lane); + InstructionOperand dup_output = + is_only_dup ? g.DefineAsRegister(node) : g.TempSimd128Register(); + selector->Emit( + kArm64S128Dup | LaneSizeField::encode(LaneSizeFromBits(lane_size)), + dup_output, g.UseUniqueRegister(input), + g.UseImmediate(AdjustLane<lane_size>(duplicate_lane))); + + if (is_only_dup) return; + + // We have to ensure that node has a definition and we would like to do + // that with the last operation that is emitted, so discover the greatest + // index at which we could do it. + uint32_t define_at_index = 0; + for (int i = shuffle.size() - 1; i >= 0; --i) { + if (shuffle[i] != duplicate_lane) { + define_at_index = i; + break; + } + } + + // Populate the remaining lanes with MoveLane. + InstructionOperand current = dup_output; + for (unsigned i = 0; i < shuffle.size(); ++i) { + int32_t lane = shuffle[i]; + if (lane == duplicate_lane) continue; + + OpIndex input = GetInput<lane_size>(input0, input1, lane); + lane = AdjustLane<lane_size>(lane); + + if (define_at_index == i) { + selector->Emit(kArm64S128MoveLane | + LaneSizeField::encode(LaneSizeFromBits(lane_size)), + g.DefineSameAsFirst(node), current, + g.UseUniqueRegister(input), g.UseImmediate(lane), + g.UseImmediate(i)); + } else { + InstructionOperand next = g.TempSimd128Register(); + int next_vreg = UnallocatedOperand::cast(next).virtual_register(); + selector->Emit(kArm64S128MoveLane | + LaneSizeField::encode(LaneSizeFromBits(lane_size)), + g.DefineSameAsFirstForVreg(next_vreg), current, + g.UseUniqueRegister(input), g.UseImmediate(lane), + g.UseImmediate(i)); + current = g.UseRegisterForVreg(next_vreg); + } + } +} + } // namespace void InstructionSelector::VisitI8x1Shuffle(OpIndex node) { @@ -6667,11 +7046,7 @@ void InstructionSelector::VisitI8x4Shuffle(OpIndex node) { if (SimdShuffle::TryMatch16x2Shuffle(shuffle.data(), shuffle16x2.data())) { EmitShuffle2<16>(this, node, input0, input1, shuffle16x2); } else { - InstructionOperand src0, src1; - ArrangeShuffleTable(&g, input0, input1, &src0, &src1); - Emit(kArm64I8x16Shuffle, g.DefineAsRegister(node), src0, src1, - g.UseImmediate(SimdShuffle::Pack4Lanes(&shuffle[0])), - g.UseImmediate(0), g.UseImmediate(0), g.UseImmediate(0)); + EmitShuffle4<8>(this, node, input0, input1, shuffle); } } @@ -6714,6 +7089,9 @@ void InstructionSelector::VisitI8x8Shuffle(OpIndex node) { g.DefineAsRegister(node), g.UseRegister(input0), g.UseImmediate(index)); return; + } else { + EmitShuffle4<16>(this, node, input0, input1, shuffle16x4); + return; } } if (SimdShuffle::TryMatchSplat<16, kSimd128Size, kSimd128HalfSize>( @@ -6796,9 +7174,7 @@ void InstructionSelector::VisitI8x16Shuffle(OpIndex node) { g.UseImmediate(from), g.UseImmediate(to)); } } else { - Emit(kArm64S32x4Shuffle, g.DefineAsRegister(node), g.UseRegister(input0), - g.UseRegister(input1), - g.UseImmediate(SimdShuffle::Pack4Lanes(shuffle32x4.data()))); + EmitShuffle4<32>(this, node, input0, input1, shuffle32x4); } return; } diff --git a/deps/v8/src/compiler/backend/code-generator.cc b/deps/v8/src/compiler/backend/code-generator.cc index 28faaf109510..23c093b9ddbf 100644 --- a/deps/v8/src/compiler/backend/code-generator.cc +++ b/deps/v8/src/compiler/backend/code-generator.cc @@ -8,7 +8,9 @@ #include "src/base/bounds.h" #include "src/base/iterator.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" +#include "src/codegen/compiler.h" #include "src/codegen/macro-assembler-inl.h" #include "src/codegen/optimized-compilation-info.h" #include "src/compiler/backend/code-generator-impl.h" @@ -19,6 +21,7 @@ #include "src/diagnostics/eh-frame.h" #include "src/execution/frames.h" #include "src/flags/flags.h" +#include "src/handles/global-handles-inl.h" #include "src/logging/counters.h" #include "src/logging/log.h" #include "src/objects/code-kind.h" @@ -213,6 +216,9 @@ void CodeGenerator::MaybeEmitOutOfLineConstantPool() { void CodeGenerator::AssembleCode() { OptimizedCompilationInfo* info = this->info(); auto call_descriptor = linkage()->GetIncomingDescriptor(); + DCHECK_IMPLIES(call_descriptor->IsCFunctionCall() && + info->code_kind() != CodeKind::BYTECODE_HANDLER, + call_descriptor->InitializeRootRegister()); // Compute incoming parameter count for code using JS linkage. This will // ultimately set the parameter count on the resulting Code object. @@ -336,6 +342,7 @@ void CodeGenerator::AssembleCode() { #endif if (block->must_construct_frame()) { + DCHECK(frame_access_state()->has_frame()); AssembleConstructFrame(); // We need to setup the root register after we assemble the prologue, to // avoid clobbering callee saved registers in case of C linkage and @@ -501,20 +508,31 @@ void CodeGenerator::AssembleArchJump(RpoNumber target) { } } -base::OwnedVector<uint8_t> CodeGenerator::GetSourcePositionTable() { +base::UniqueArray<uint8_t> CodeGenerator::GetSourcePositionTable() { return source_position_table_builder_.ToSourcePositionTableVector(); } -base::OwnedVector<uint8_t> CodeGenerator::GetTrappingInstructionsData() { +base::UniqueArray<uint8_t> CodeGenerator::GetTrappingInstructionsData() { #if V8_ENABLE_WEBASSEMBLY - return base::OwnedCopyOf( + return base::UniqueCopyOf( base::Vector<uint8_t>::cast(base::VectorOf(trapping_instructions_))); #else return {}; #endif // V8_ENABLE_WEBASSEMBLY } -MaybeHandle<Code> CodeGenerator::FinalizeCode() { +void CodeGenerator::PrepareCodeOnBackground(LocalIsolate* local_isolate) { + LocalHandleScope handle_scope(local_isolate); + AllowHandleDereference allow_deref; + Handle<Code> code; + if (BuildCodeObject(local_isolate).ToHandle(&code)) { + code_ = local_isolate->heap()->NewPersistentHandle(code); + retained_maps_ = OptimizedCompilationJob::CollectRetainedMaps( + code, info_->DetachCanonicalHandles()); + } +} + +MaybeHandle<Code> CodeGenerator::BuildCodeObject(LocalIsolate* local_isolate) { if (result_ != kSuccess) { masm()->AbortedCodeGeneration(); return {}; @@ -522,12 +540,11 @@ MaybeHandle<Code> CodeGenerator::FinalizeCode() { // Allocate the source position table. Handle<TrustedByteArray> source_positions = - source_position_table_builder_.ToSourcePositionTable(isolate()); + source_position_table_builder_.ToSourcePositionTable(local_isolate); // Allocate and install the code. CodeDesc desc; - masm()->GetCode(isolate()->main_thread_local_isolate(), &desc, safepoints(), - handler_table_offset_); + masm()->GetCode(local_isolate, &desc, safepoints(), handler_table_offset_); #if defined(V8_OS_WIN64) if (Builtins::IsBuiltinId(info_->builtin())) { @@ -539,7 +556,7 @@ MaybeHandle<Code> CodeGenerator::FinalizeCode() { unwinding_info_writer_.eh_frame_writer()->GetEhFrame(&desc); } - Factory::CodeBuilder builder(isolate(), desc, info()->code_kind()); + Factory::CodeBuilder builder(local_isolate, desc, info()->code_kind()); builder.set_builtin(info()->builtin()) .set_inlined_bytecode_size(info()->inlined_bytecode_size()) .set_parameter_count(parameter_count_) @@ -554,7 +571,7 @@ MaybeHandle<Code> CodeGenerator::FinalizeCode() { } if (CodeKindUsesDeoptimizationData(info()->code_kind())) { - builder.set_deoptimization_data(GenerateDeoptimizationData()); + builder.set_deoptimization_data(GenerateDeoptimizationData(local_isolate)); DCHECK(info()->has_bytecode_array() || info()->code_kind() == CodeKind::WASM_FUNCTION); } @@ -567,9 +584,24 @@ MaybeHandle<Code> CodeGenerator::FinalizeCode() { return {}; } - LOG_CODE_EVENT(isolate(), CodeLinePosInfoRecordEvent( - code->instruction_start(), *source_positions, - JitCodeEvent::JIT_CODE)); + return code; +} + +MaybeHandle<Code> CodeGenerator::FinalizeCode() { + Handle<Code> code; + if (code_.ToHandle(&code)) { + code = handle(*code, isolate()); + } else if (!BuildCodeObject(isolate()->main_thread_local_isolate()) + .ToHandle(&code)) { + return {}; + } + + if (code->has_source_position_table()) { + LOG_CODE_EVENT(isolate(), + CodeLinePosInfoRecordEvent(code->instruction_start(), + code->source_position_table(), + JitCodeEvent::JIT_CODE)); + } return code; } @@ -608,9 +640,7 @@ void CodeGenerator::RecordSafepointWithoutTaggedSlots() { bool CodeGenerator::IsMaterializableFromRoot(Handle<HeapObject> object, RootIndex* index_return) { - const CallDescriptor* incoming_descriptor = - linkage()->GetIncomingDescriptor(); - if (incoming_descriptor->flags() & CallDescriptor::kCanUseRoots) { + if (isolate() != nullptr) { return isolate()->roots_table().IsRootHandle(object, index_return) && RootsTable::IsImmortalImmovable(*index_return); } @@ -965,9 +995,8 @@ bool CodeGenerator::GetSlotAboveSPBeforeTailCall(Instruction* instr, InstructionOperandConverter g(this, instr); *slot = g.InputInt32(instr->InputCount() - 1); return true; - } else { - return false; } + return false; } StubCallMode CodeGenerator::DetermineStubCallMode() const { @@ -997,13 +1026,14 @@ void CodeGenerator::AssembleGaps(Instruction* instr) { namespace { DirectHandle<TrustedPodArray<InliningPosition>> CreateInliningPositions( - OptimizedCompilationInfo* info, Isolate* isolate) { + OptimizedCompilationInfo* info, LocalIsolate* local_isolate) { const OptimizedCompilationInfo::InlinedFunctionList& inlined_functions = info->inlined_functions(); const uint32_t inlined_functions_len = static_cast<uint32_t>(inlined_functions.size()); DirectHandle<TrustedPodArray<InliningPosition>> inl_positions = - TrustedPodArray<InliningPosition>::New(isolate, inlined_functions_len); + TrustedPodArray<InliningPosition>::New(local_isolate, + inlined_functions_len); for (uint32_t i = 0; i < inlined_functions_len; ++i) { inl_positions->set(i, inlined_functions[i].position); } @@ -1012,18 +1042,18 @@ DirectHandle<TrustedPodArray<InliningPosition>> CreateInliningPositions( } // namespace -Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() { +Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData( + LocalIsolate* local_isolate) { OptimizedCompilationInfo* info = this->info(); int deopt_count = static_cast<int>(deoptimization_exits_.size()); if (deopt_count == 0 && !info->is_osr()) { - return DeoptimizationData::Empty(isolate()); + return DeoptimizationData::Empty(local_isolate); } Handle<DeoptimizationData> data = - DeoptimizationData::New(isolate(), deopt_count); + DeoptimizationData::New(local_isolate, deopt_count); DirectHandle<DeoptimizationFrameTranslation> translation_array = - translations_.ToFrameTranslation( - isolate()->main_thread_local_isolate()->factory()); + translations_.ToFrameTranslation(local_isolate->factory()); data->SetFrameTranslation(*translation_array); data->SetInlinedFunctionCount( @@ -1036,7 +1066,8 @@ Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() { if (info->has_shared_info()) { DirectHandle<SharedFunctionInfoWrapper> sfi_wrapper = - isolate()->factory()->NewSharedFunctionInfoWrapper(info->shared_info()); + local_isolate->factory()->NewSharedFunctionInfoWrapper( + info->shared_info()); data->SetWrappedSharedFunctionInfo(*sfi_wrapper); } else { data->SetWrappedSharedFunctionInfo(Smi::zero()); @@ -1045,7 +1076,7 @@ Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() { const uint32_t protected_deopt_literals_len = static_cast<uint32_t>(protected_deoptimization_literals_.size()); DirectHandle<ProtectedDeoptimizationLiteralArray> protected_literals = - isolate()->factory()->NewProtectedFixedArray( + local_isolate->factory()->NewProtectedFixedArray( protected_deopt_literals_len); for (uint32_t i = 0; i < protected_deopt_literals_len; i++) { IndirectHandle<TrustedObject> object = @@ -1058,16 +1089,18 @@ Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() { const uint32_t deopt_literals_len = static_cast<uint32_t>(deoptimization_literals_.size()); DirectHandle<DeoptimizationLiteralArray> literals = - isolate()->factory()->NewDeoptimizationLiteralArray(deopt_literals_len); + local_isolate->factory()->NewDeoptimizationLiteralArray( + deopt_literals_len); for (uint32_t i = 0; i < deopt_literals_len; i++) { - DirectHandle<Object> object = deoptimization_literals_[i].Reify(isolate()); + DirectHandle<Object> object = + deoptimization_literals_[i].Reify(local_isolate); CHECK(!object.is_null()); literals->set(i, *object); } data->SetLiteralArray(*literals); DirectHandle<TrustedPodArray<InliningPosition>> inl_pos = - CreateInliningPositions(info, isolate()); + CreateInliningPositions(info, local_isolate); data->SetInliningPositions(*inl_pos); if (info->is_osr()) { @@ -1101,7 +1134,7 @@ Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() { } #if V8_ENABLE_WEBASSEMBLY -base::OwnedVector<uint8_t> CodeGenerator::GenerateWasmDeoptimizationData() { +base::UniqueArray<uint8_t> CodeGenerator::GenerateWasmDeoptimizationData() { CHECK_EQ(result_, kSuccess); int deopt_count = static_cast<int>(deoptimization_exits_.size()); if (deopt_count == 0) { @@ -1113,7 +1146,7 @@ base::OwnedVector<uint8_t> CodeGenerator::GenerateWasmDeoptimizationData() { DCHECK_EQ(inlined_function_count_, 0); auto deopt_entries = - base::OwnedVector<wasm::WasmDeoptEntry>::New(deopt_count); + base::UniqueArray<wasm::WasmDeoptEntry>::New(deopt_count); // Populate deoptimization entries. for (int i = 0; i < deopt_count; i++) { const DeoptimizationExit* deoptimization_exit = deoptimization_exits_[i]; @@ -1125,7 +1158,7 @@ base::OwnedVector<uint8_t> CodeGenerator::GenerateWasmDeoptimizationData() { base::Vector<const uint8_t> frame_translations = translations_.ToFrameTranslationWasm(); - base::OwnedVector<uint8_t> result = wasm::WasmDeoptDataProcessor::Serialize( + base::UniqueArray<uint8_t> result = wasm::WasmDeoptDataProcessor::Serialize( deopt_exit_start_offset_, eager_deopt_count_, frame_translations, base::VectorOf(deopt_entries), deoptimization_literals_); #if DEBUG @@ -1153,7 +1186,7 @@ base::OwnedVector<uint8_t> CodeGenerator::GenerateWasmDeoptimizationData() { return result; } -base::OwnedVector<uint8_t> CodeGenerator::GenerateWasmEffectHandlers() { +base::UniqueArray<uint8_t> CodeGenerator::GenerateWasmEffectHandlers() { size_t size = 0; for (size_t i = 0; i < effect_handlers_.size(); ++i) { size += wasm::LEBHelper::sizeof_u32v(effect_handlers_[i].pc_offset); @@ -1164,7 +1197,7 @@ base::OwnedVector<uint8_t> CodeGenerator::GenerateWasmEffectHandlers() { size += wasm::LEBHelper::sizeof_u32v(effect_handlers_[i].sig.index); } } - auto bytes = base::OwnedVector<uint8_t>::New(size); + auto bytes = base::UniqueArray<uint8_t>::New(size); uint8_t* ptr = bytes.data(); for (size_t i = 0; i < effect_handlers_.size(); ++i) { wasm::LEBHelper::write_u32v(&ptr, effect_handlers_[i].pc_offset); @@ -1671,19 +1704,12 @@ void CodeGenerator::AddTranslationForOperand(Instruction* instr, case Constant::kFloat64: DCHECK(type.representation() == MachineRepresentation::kFloat64 || type.representation() == MachineRepresentation::kTagged); - if (type == MachineType::HoleyFloat64() && - constant.ToFloat64().AsUint64() == kHoleNanInt64) { - literal = DeoptimizationLiteral::HoleNaN(); -#ifdef V8_ENABLE_UNDEFINED_DOUBLE - } else if (type == MachineType::HoleyFloat64() && - constant.ToFloat64().AsUint64() == kUndefinedNanInt64) { - literal = - DeoptimizationLiteral(isolate()->factory()->undefined_value()); -#endif // V8_ENABLE_UNDEFINED_DOUBLE + if (type == MachineType::HoleyFloat64()) { + translations_.StoreHoleyDoubleLiteral(Float64(constant.ToFloat64())); } else { - literal = DeoptimizationLiteral(constant.ToFloat64().value()); + translations_.StoreDoubleLiteral(Float64(constant.ToFloat64())); } - break; + return; case Constant::kHeapObject: DCHECK_EQ(MachineRepresentation::kTagged, type.representation()); literal = DeoptimizationLiteral(constant.ToHeapObject()); diff --git a/deps/v8/src/compiler/backend/code-generator.h b/deps/v8/src/compiler/backend/code-generator.h index 1b5c3165a223..f70ef8ad59f5 100644 --- a/deps/v8/src/compiler/backend/code-generator.h +++ b/deps/v8/src/compiler/backend/code-generator.h @@ -8,6 +8,8 @@ #include <memory> #include <optional> +#include "src/base/small-vector.h" +#include "src/base/unique-array.h" #include "src/codegen/macro-assembler.h" #include "src/codegen/optimized-compilation-info.h" #include "src/codegen/safepoint-table.h" @@ -92,15 +94,20 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler { // produce the actual code object. If an error occurs during either phase, // FinalizeCode returns an empty MaybeHandle. void AssembleCode(); // Does not need to run on main thread. + void PrepareCodeOnBackground(LocalIsolate* local_isolate); + bool has_background_code() const { return !code_.is_null(); } + base::Vector<const IndirectHandle<Map>> retained_maps() const { + return base::VectorOf(retained_maps_); + } MaybeHandle<Code> FinalizeCode(); #if V8_ENABLE_WEBASSEMBLY - base::OwnedVector<uint8_t> GenerateWasmDeoptimizationData(); - base::OwnedVector<uint8_t> GenerateWasmEffectHandlers(); + base::UniqueArray<uint8_t> GenerateWasmDeoptimizationData(); + base::UniqueArray<uint8_t> GenerateWasmEffectHandlers(); #endif - base::OwnedVector<uint8_t> GetSourcePositionTable(); - base::OwnedVector<uint8_t> GetTrappingInstructionsData(); + base::UniqueArray<uint8_t> GetSourcePositionTable(); + base::UniqueArray<uint8_t> GetTrappingInstructionsData(); InstructionSequence* instructions() const { return instructions_; } FrameAccessState* frame_access_state() const { return frame_access_state_; } @@ -371,7 +378,9 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler { void RecordCallPosition(Instruction* instr); void RecordDeoptInfo(Instruction* instr, int pc_offset); - Handle<DeoptimizationData> GenerateDeoptimizationData(); + Handle<DeoptimizationData> GenerateDeoptimizationData( + LocalIsolate* local_isolate); + MaybeHandle<Code> BuildCodeObject(LocalIsolate* local_isolate); int DefineProtectedDeoptimizationLiteral( IndirectHandle<TrustedObject> object); int DefineDeoptimizationLiteral(DeoptimizationLiteral literal); @@ -496,6 +505,8 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler { TurbolizerCodeOffsetsInfo offsets_info_; ZoneVector<TurbolizerInstructionStartInfo> instr_starts_; MoveCycleState move_cycle_; + MaybeIndirectHandle<Code> code_; + base::SmallVector<IndirectHandle<Map>, 8> retained_maps_; const char* debug_name_ = nullptr; }; diff --git a/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc b/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc index 58cdec956a23..1ded761b495a 100644 --- a/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc +++ b/deps/v8/src/compiler/backend/ia32/code-generator-ia32.cc @@ -820,9 +820,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ cmp(esi, FieldOperand(func, offsetof(JSFunction, context_))); __ Assert(equal, AbortReason::kWrongFunctionContext); } - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); - __ CallJSFunction(func, num_arguments); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); + __ CallJSFunction(func, expected_parameter_count); RecordCallPosition(instr); frame_access_state()->ClearSPDelta(); break; @@ -1099,8 +1099,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } break; } - case kArchStoreIndirectSkippedWriteBarrier: - case kArchStoreIndirectWithWriteBarrier: + case kArchStoreTrustedSkippedWriteBarrier: + case kArchStoreTrustedWithWriteBarrier: UNREACHABLE(); case kArchStackSlot: { FrameOffset offset = @@ -1616,9 +1616,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kFloat32Div: { __ Divss(i.OutputDoubleRegister(), i.InputDoubleRegister(0), i.InputOperand(1)); - // Don't delete this mov. It may improve performance on some CPUs, - // when there is a (v)mulss depending on the result. - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); break; } case kFloat64Add: { @@ -1639,9 +1636,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kFloat64Div: { __ Divsd(i.OutputDoubleRegister(), i.InputDoubleRegister(0), i.InputOperand(1)); - // Don't delete this mov. It may improve performance on some CPUs, - // when there is a (v)mulsd depending on the result. - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); break; } case kFloat32Abs: { @@ -4151,38 +4145,37 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { - __ push(ebp); - __ mov(ebp, esp); + if (call_descriptor->IsCFunctionCall()) { + __ push(ebp); + __ mov(ebp, esp); #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ Push(Immediate(StackFrame::TypeToMarker(StackFrame::C_WASM_ENTRY))); - // Reserve stack space for saving the c_entry_fp later. - __ AllocateStackSpace(kSystemPointerSize); - } + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ Push(Immediate(StackFrame::TypeToMarker(StackFrame::C_WASM_ENTRY))); + // Reserve stack space for saving the c_entry_fp later. + __ AllocateStackSpace(kSystemPointerSize); + } #endif // V8_ENABLE_WEBASSEMBLY - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); - } else { - __ StubPrologue(info()->GetOutputStackFrameType()); + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + __ StubPrologue(info()->GetOutputStackFrameType()); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ AllocateStackSpace(kSystemPointerSize); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ AllocateStackSpace(kSystemPointerSize); } +#endif // V8_ENABLE_WEBASSEMBLY } int required_slots = @@ -4202,88 +4195,105 @@ void CodeGenerator::AssembleConstructFrame() { } const RegList saves = call_descriptor->CalleeSavedRegisters(); - if (required_slots > 0) { - DCHECK(frame_access_state()->has_frame()); #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + if (stack_space == 0) { + __ CompareStackLimit(esp, StackLimitKind::kRealStackLimit); + } else { Register scratch = esi; __ push(scratch); __ mov(scratch, esp); - __ sub(scratch, Immediate(stack_space)); + __ sub(scratch, Immediate(static_cast<int32_t>(stack_space))); __ CompareStackLimit(scratch, StackLimitKind::kRealStackLimit); __ pop(scratch); - __ j(above_equal, &done, Label::kNear); } - - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - for (Register reg : base::Reversed(regs_to_save)) { - __ push(reg); - } - __ sub(esp, - Immediate(arraysize(wasm::kFpParamRegisters) * kSimd128Size)); - for (size_t i = 0; i < arraysize(wasm::kFpParamRegisters); i++) { - __ Movdqu(Operand(esp, kSimd128Size * i), wasm::kFpParamRegisters[i]); - } - __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), - Immediate(stack_space)); - __ mov(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), ebp); - __ add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), - Immediate(static_cast<int32_t>( - call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp))); - __ wasm_call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); - for (size_t i = 0; i < arraysize(wasm::kFpParamRegisters); i++) { - __ Movdqu(wasm::kFpParamRegisters[i], Operand(esp, kSimd128Size * i)); - } - __ add(esp, - Immediate(arraysize(wasm::kFpParamRegisters) * kSimd128Size)); - for (Register reg : regs_to_save) { - __ pop(reg); - } - } else { - __ wasm_call(static_cast<Address>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - __ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap); + __ j(above_equal, &done, Label::kNear); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + for (Register reg : base::Reversed(regs_to_save)) { + __ push(reg); } - __ bind(&done); + __ sub(esp, Immediate(arraysize(wasm::kFpParamRegisters) * kSimd128Size)); + for (size_t i = 0; i < arraysize(wasm::kFpParamRegisters); i++) { + __ Movdqu(Operand(esp, kSimd128Size * i), wasm::kFpParamRegisters[i]); + } + __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), + Immediate(static_cast<int32_t>(stack_space))); + __ mov(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), ebp); + __ add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), + Immediate(static_cast<int32_t>( + (call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp))); + __ mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Immediate(static_cast<int32_t>( + call_descriptor->ParameterSlotCount() * kSystemPointerSize))); + __ wasm_call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + for (size_t i = 0; i < arraysize(wasm::kFpParamRegisters); i++) { + __ Movdqu(wasm::kFpParamRegisters[i], Operand(esp, kSimd128Size * i)); + } + __ add(esp, Immediate(arraysize(wasm::kFpParamRegisters) * kSimd128Size)); + for (Register reg : regs_to_save) { + __ pop(reg); + } + } else { + __ wasm_call(static_cast<Address>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap); } + __ bind(&done); + } #endif // V8_ENABLE_WEBASSEMBLY - // Skip callee-saved and return slots, which are created below. - required_slots -= saves.Count(); - required_slots -= frame()->GetReturnSlotCount(); - if (required_slots > 0) { - __ AllocateStackSpace(required_slots * kSystemPointerSize); - } + // Skip callee-saved and return slots, which are created below. + required_slots -= saves.Count(); + required_slots -= frame()->GetReturnSlotCount(); + if (required_slots > 0) { + __ AllocateStackSpace(required_slots * kSystemPointerSize); } if (!saves.is_empty()) { // Save callee-saved registers. @@ -4334,37 +4344,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - __ cmp(MemOperand(ebp, TypedFrameConstants::kFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - Label done; - __ j(not_equal, &done); - for (Register reg : base::Reversed(wasm::kGpReturnRegisters)) { - __ push(reg); - } - __ sub(esp, Immediate(arraysize(wasm::kFpReturnRegisters) * kSimd128Size)); - for (size_t i = 0; i < arraysize(wasm::kFpReturnRegisters); i++) { - __ Movdqu(Operand(esp, kSimd128Size * i), wasm::kFpReturnRegisters[i]); - } - __ PrepareCallCFunction(1, kReturnRegister0); - __ Move(Operand(esp, 0 * kSystemPointerSize), - Immediate(ExternalReference::isolate_address())); - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old ebp. We don't need to restore old esp explicitly, because - // it will be restored from ebp in LeaveFrame before return. - __ mov(ebp, kReturnRegister0); - for (size_t i = 0; i < arraysize(wasm::kFpReturnRegisters); i++) { - __ Movdqu(wasm::kFpReturnRegisters[i], Operand(esp, kSimd128Size * i)); - } - __ add(esp, Immediate(arraysize(wasm::kFpReturnRegisters) * kSimd128Size)); - for (Register reg : wasm::kGpReturnRegisters) { - __ pop(reg); - } - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY Register argc_reg = ecx; // Functions with JS linkage have at least one parameter (the receiver). diff --git a/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc b/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc index 13979cd4d6fc..c7eae16fc9f9 100644 --- a/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc +++ b/deps/v8/src/compiler/backend/ia32/instruction-selector-ia32.cc @@ -575,7 +575,7 @@ ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) { case MachineRepresentation::kCompressedPointer: // Fall through. case MachineRepresentation::kCompressed: // Fall through. case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kWord64: // Fall through. case MachineRepresentation::kMapWord: // Fall through. @@ -955,7 +955,7 @@ ArchOpcode GetStoreOpcode(MachineRepresentation rep) { case MachineRepresentation::kCompressedPointer: // Fall through. case MachineRepresentation::kCompressed: // Fall through. case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kWord64: // Fall through. case MachineRepresentation::kMapWord: // Fall through. diff --git a/deps/v8/src/compiler/backend/instruction-codes.h b/deps/v8/src/compiler/backend/instruction-codes.h index 03359d373ab0..a7d9271cafab 100644 --- a/deps/v8/src/compiler/backend/instruction-codes.h +++ b/deps/v8/src/compiler/backend/instruction-codes.h @@ -44,7 +44,7 @@ namespace compiler { enum class RecordWriteMode { kValueIsMap, kValueIsPointer, - kValueIsIndirectPointer, + kValueIsTrustedPointer, kValueIsEphemeronKey, kValueIsAny, }; @@ -56,8 +56,8 @@ inline RecordWriteMode WriteBarrierKindToRecordWriteMode( return RecordWriteMode::kValueIsMap; case kPointerWriteBarrier: return RecordWriteMode::kValueIsPointer; - case kIndirectPointerWriteBarrier: - return RecordWriteMode::kValueIsIndirectPointer; + case kTrustedPointerWriteBarrier: + return RecordWriteMode::kValueIsTrustedPointer; case kEphemeronKeyWriteBarrier: return RecordWriteMode::kValueIsEphemeronKey; case kFullWriteBarrier: @@ -110,10 +110,10 @@ inline RecordWriteMode WriteBarrierKindToRecordWriteMode( V(AtomicXorWord32) \ V(ArchStoreWithWriteBarrier) \ V(ArchAtomicStoreWithWriteBarrier) \ - V(ArchStoreIndirectWithWriteBarrier) \ + V(ArchStoreTrustedWithWriteBarrier) \ V(ArchStoreSkippedWriteBarrier) \ V(ArchAtomicStoreSkippedWriteBarrier) \ - V(ArchStoreIndirectSkippedWriteBarrier) \ + V(ArchStoreTrustedSkippedWriteBarrier) \ V(AtomicLoadInt8) \ V(AtomicLoadUint8) \ V(AtomicLoadInt16) \ @@ -389,7 +389,8 @@ using InstructionCode = uint32_t; // Field | Bits // Undefined | 5 // AccessMode | 1 -// Undefined | 3 +// SharedBase | 1 +// Undefined | 2 // // -- Vectors // Field | Bits @@ -451,6 +452,10 @@ static_assert(AtomicMemoryOrderField::kLastUsedBit >= LaneSizeField::kLastUsedBit); #endif +// Denotes that the a load has a shared tagged object as its base. Currently +// only used for TSAN. +using SharedBaseField = AccessModeField::Next<SharedFlag, 1>; + // TODO(turbofan): {HasMemoryAccessMode} is currently only used to guard // decoding (in CodeGenerator and InstructionScheduler). Encoding (in // InstructionSelector) is not yet guarded. There are in fact instructions for diff --git a/deps/v8/src/compiler/backend/instruction-scheduler.cc b/deps/v8/src/compiler/backend/instruction-scheduler.cc index 4407d5efc424..c694ec2f4d84 100644 --- a/deps/v8/src/compiler/backend/instruction-scheduler.cc +++ b/deps/v8/src/compiler/backend/instruction-scheduler.cc @@ -545,12 +545,12 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const { case kArchStoreWithWriteBarrier: case kArchAtomicStoreWithWriteBarrier: - case kArchStoreIndirectWithWriteBarrier: + case kArchStoreTrustedWithWriteBarrier: return kHasSideEffect; case kArchStoreSkippedWriteBarrier: case kArchAtomicStoreSkippedWriteBarrier: - case kArchStoreIndirectSkippedWriteBarrier: + case kArchStoreTrustedSkippedWriteBarrier: return kHasSideEffect; case kAtomicLoadInt8: diff --git a/deps/v8/src/compiler/backend/instruction-selector.cc b/deps/v8/src/compiler/backend/instruction-selector.cc index 2fe007252dfd..2783fe7fc28f 100644 --- a/deps/v8/src/compiler/backend/instruction-selector.cc +++ b/deps/v8/src/compiler/backend/instruction-selector.cc @@ -341,14 +341,6 @@ bool is_exclusive_user_of(const Graph* graph, OpIndex user, OpIndex value) { } return false; } - if (value_op.Is<ProjectionOp>()) { - // Projections always have a Tuple use, but it shouldn't count as a use as - // far as is_exclusive_user_of is concerned, since no instructions are - // emitted for the MakeTupleOp, which is just a Turboshaft "meta operation". - // We thus increase the use_count by 1, to attribute the MakeTupleOp use to - // the current operation. - use_count++; - } DCHECK_LE(use_count, graph->Get(value).saturated_use_count.GetMaybeSaturated()); return value_op.saturated_use_count.Is(static_cast<int>(use_count)); @@ -419,12 +411,8 @@ OptionalOpIndex InstructionSelector::FindProjection(OpIndex node, next = graph->NextIndex(next)) { const ProjectionOp* projection = graph->Get(next).TryCast<ProjectionOp>(); if (projection == nullptr) break; - DCHECK(!projection->saturated_use_count.Is(0)); - if (projection->saturated_use_count.Is(1)) { - // If the projection has a single use, it is the following tuple, so we - // don't return it, since there is no point in emitting it. - DCHECK(turboshaft_uses(next).size() == 1 && - graph->Get(turboshaft_uses(next)[0]).Is<MakeTupleOp>()); + if (projection->saturated_use_count.Is(0)) { + DCHECK(turboshaft_uses(next).empty()); continue; } if (projection->index == projection_index) return next; @@ -439,11 +427,7 @@ OptionalOpIndex InstructionSelector::FindProjection(OpIndex node, this->Get(use).TryCast<ProjectionOp>()) { DCHECK_EQ(projection->input(), node); if (projection->index == projection_index) { - // If we found the projection, it should have a single use: a Tuple - // (which doesn't count as a regular use since it is just an artifact of - // the Turboshaft graph). - DCHECK(turboshaft_uses(use).size() == 1 && - graph->Get(turboshaft_uses(use)[0]).Is<MakeTupleOp>()); + DCHECK(turboshaft_uses(use).empty()); } } } @@ -578,30 +562,21 @@ void InstructionSelector::SetEffectLevel(OpIndex node, int effect_level) { bool InstructionSelector::CanAddressRelativeToRootsRegister( const ExternalReference& reference) const { - // There are three things to consider here: - // 1. CanUseRootsRegister: Is kRootRegister initialized? - const bool root_register_is_available_and_initialized = CanUseRootsRegister(); - if (!root_register_is_available_and_initialized) return false; - - // 2. enable_roots_relative_addressing_: Can we address everything on the heap + // There are two things to consider here: + // 1. enable_roots_relative_addressing_: Can we address everything on the heap // through the root register, i.e. are root-relative addresses to arbitrary // addresses guaranteed not to change between code generation and // execution? if (enable_roots_relative_addressing_) return true; - // 3. IsAddressableThroughRootRegister: Is the target address guaranteed to - // have a fixed root-relative offset? If so, we can ignore 2. + // 2. IsAddressableThroughRootRegister: Is the target address guaranteed to + // have a fixed root-relative offset? If so, we can ignore 1. const bool this_root_relative_offset_is_constant = MacroAssemblerBase::IsAddressableThroughRootRegister(isolate(), reference); return this_root_relative_offset_is_constant; } -bool InstructionSelector::CanUseRootsRegister() const { - return linkage()->GetIncomingDescriptor()->flags() & - CallDescriptor::kCanUseRoots; -} - void InstructionSelector::MarkAsRepresentation(MachineRepresentation rep, const InstructionOperand& op) { UnallocatedOperand unalloc = UnallocatedOperand::cast(op); @@ -1180,6 +1155,7 @@ void InstructionSelector::InitializeCallBuffer( : g.DefineAsLocation(output, location); MarkAsRepresentation(rep, op); + // Caller frame slots are defined later via Peek in VisitCall. if (!UnallocatedOperand::cast(op).HasFixedSlotPolicy()) { buffer->outputs.push_back(op); buffer->output_nodes[i].node = {}; @@ -2073,11 +2049,9 @@ LinkageLocation ExceptionLocation() { constexpr InstructionCode EncodeCallDescriptorFlags( InstructionCode opcode, CallDescriptor::Flags flags) { - // Note: Not all bits of `flags` are preserved. - static_assert(CallDescriptor::kFlagsBitsEncodedInInstructionCode == - MiscField::kSize); + static_assert(MiscField::is_valid(CallDescriptor::kNoFunctionDescriptor)); DCHECK(Instruction::IsCallWithDescriptorFlags(opcode)); - return opcode | MiscField::encode(flags & MiscField::kMax); + return opcode | MiscField::encode(flags); } } // namespace @@ -2158,11 +2132,8 @@ bool InstructionSelector::CanDoBranchIfOverflowFusion(OpIndex binop) { return true; } - if (projection0.saturated_use_count.Is(1)) { - // If the projection has a single use, it is the following tuple, so we - // don't care about the value, and can do branch-if-overflow fusion. - DCHECK(turboshaft_uses(projection0_index).size() == 1 && - graph->Get(turboshaft_uses(projection0_index)[0]).Is<MakeTupleOp>()); + if (projection0.saturated_use_count.Is(0)) { + DCHECK(turboshaft_uses(projection0_index).empty()); return true; } @@ -2177,14 +2148,7 @@ bool InstructionSelector::CanDoBranchIfOverflowFusion(OpIndex binop) { // defined, which will imply that it's fine to define {projection0} and // {binop} now. for (OpIndex use : turboshaft_uses(projection0_index)) { - if (this->Get(use).template Is<MakeTupleOp>()) { - // The Tuple won't have any uses since it would have to be accessed - // through Projections, and Projections on Tuples return the original - // Projection instead (see Assembler::ReduceProjection in - // turboshaft/assembler.h). - DCHECK(this->Get(use).saturated_use_count.Is(0)); - continue; - } + DCHECK(!Is<MakeTupleOp>(use)); if (IsDefined(use)) continue; if (!InCurrentBlock(use)) { // {use} is in a later block, so it should already have been visited. Note @@ -2293,11 +2257,12 @@ void InstructionSelector::VisitCall( buffer.instruction_args.push_back( g.TempImmediate(call_descriptor->shifted_tag())); } else if (call_descriptor->IsJSFunctionCall()) { - // For JSFunctions we need to know the number of pushed parameters during - // code generation. - uint32_t parameter_count = - static_cast<uint32_t>(buffer.pushed_nodes.size()); - buffer.instruction_args.push_back(g.TempImmediate(parameter_count)); + // For JSFunctions we need to know the function's formal parameter count + // used during code generation. + uint32_t expected_parameter_count = + call_descriptor->expected_parameter_count(); + buffer.instruction_args.push_back( + g.TempImmediate(expected_parameter_count)); } // Pass label of exception handler block. @@ -2512,16 +2477,9 @@ void InstructionSelector::VisitReturn(OpIndex node) { } else { value_locations[0] = g.UseRegister(ret.pop_count()); } - for (size_t i = 0, return_value_idx = 0; i < return_count; ++i) { + for (size_t i = 0; i < return_count; ++i) { LinkageLocation loc = linkage()->GetReturnLocation(i); - // Return values passed via frame slots have already been stored - // on the stack by the GrowableStacksReducer. - if (loc.IsCallerFrameSlot() && ret.spill_caller_frame_slots) { - continue; - } - value_locations[return_value_idx + 1] = - g.UseLocation(ret.return_values()[return_value_idx], loc); - return_value_idx++; + value_locations[i + 1] = g.UseLocation(ret.return_values()[i], loc); } Emit(kArchRet, 0, nullptr, input_count, value_locations); } @@ -2614,10 +2572,8 @@ void InstructionSelector::TryPrepareScheduleFirstProjection( // {result} back into it through the back edge. In this case, it's // normal to schedule {result} before the Phi that uses it. for (OpIndex use : turboshaft_uses(result.value())) { - // We ignore MakeTupleOp uses, since MakeTupleOp don't lead to emitted - // machine instructions and are just Turboshaft "meta operations". - if (!Is<MakeTupleOp>(use) && !IsDefined(use) && InCurrentBlock(use) && - !Is<PhiOp>(use)) { + DCHECK(!Is<MakeTupleOp>(use)); + if (!IsDefined(use) && InCurrentBlock(use) && !Is<PhiOp>(use)) { return; } } diff --git a/deps/v8/src/compiler/backend/instruction-selector.h b/deps/v8/src/compiler/backend/instruction-selector.h index edc64bfac4ab..b8af2591b810 100644 --- a/deps/v8/src/compiler/backend/instruction-selector.h +++ b/deps/v8/src/compiler/backend/instruction-selector.h @@ -612,8 +612,6 @@ class V8_EXPORT_PRIVATE InstructionSelector final // to the roots register. bool CanAddressRelativeToRootsRegister( const ExternalReference& reference) const; - // Check if we can use the roots register to access GC roots. - bool CanUseRootsRegister() const; Isolate* isolate() const { return sequence()->isolate(); } @@ -783,6 +781,7 @@ class V8_EXPORT_PRIVATE InstructionSelector final } bool is_trapping() const { return kind().with_trap_handler; } bool is_atomic() const { return kind().is_atomic; } + bool has_shared_base() const { return kind().shared_base; } turboshaft::OpIndex base() const { if (load_) return load_->base(); @@ -899,8 +898,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final turboshaft::OpIndex base() const { return op_->base(); } turboshaft::OptionalOpIndex index() const { return op_->index(); } turboshaft::OpIndex value() const { return op_->value(); } - IndirectPointerTag indirect_pointer_tag() const { - return static_cast<IndirectPointerTag>(op_->indirect_pointer_tag()); + TrustedPointerTag trusted_pointer_tag() const { + return static_cast<TrustedPointerTag>(op_->trusted_pointer_tag()); } int32_t displacement() const { static_assert( diff --git a/deps/v8/src/compiler/backend/instruction.cc b/deps/v8/src/compiler/backend/instruction.cc index c9207826f070..5390a91d0586 100644 --- a/deps/v8/src/compiler/backend/instruction.cc +++ b/deps/v8/src/compiler/backend/instruction.cc @@ -298,7 +298,7 @@ std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) { case MachineRepresentation::kProtectedPointer: os << "|pp"; break; - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: os << "|ip"; break; case MachineRepresentation::kSandboxedPointer: @@ -1081,7 +1081,7 @@ static MachineRepresentation FilterRepresentation(MachineRepresentation rep) { return rep; case MachineRepresentation::kNone: case MachineRepresentation::kMapWord: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); } diff --git a/deps/v8/src/compiler/backend/instruction.h b/deps/v8/src/compiler/backend/instruction.h index 2f07ae1d8586..57fa5cbea540 100644 --- a/deps/v8/src/compiler/backend/instruction.h +++ b/deps/v8/src/compiler/backend/instruction.h @@ -597,7 +597,7 @@ class LocationOperand : public InstructionOperand { case MachineRepresentation::kNone: return false; case MachineRepresentation::kMapWord: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); } @@ -1002,6 +1002,7 @@ class V8_EXPORT_PRIVATE Instruction final { FlagsCondition flags_condition() const { return FlagsConditionField::decode(opcode()); } + SharedFlag shared_base() const { return SharedBaseField::decode(opcode()); } bool branch_hinted() const { return BranchHintField::decode(opcode()); } int misc() const { return MiscField::decode(opcode()); } bool HasMemoryAccessMode() const { @@ -1093,13 +1094,7 @@ class V8_EXPORT_PRIVATE Instruction final { } bool HasCallDescriptorFlag(CallDescriptor::Flag flag) const { DCHECK(IsCallWithDescriptorFlags()); - static_assert(CallDescriptor::kFlagsBitsEncodedInInstructionCode == - MiscField::kSize); -#ifdef DEBUG - static constexpr int kInstructionCodeFlagsMask = - ((1 << CallDescriptor::kFlagsBitsEncodedInInstructionCode) - 1); - DCHECK_EQ(static_cast<int>(flag) & kInstructionCodeFlagsMask, flag); -#endif + DCHECK(MiscField::is_valid(flag)); return MiscField::decode(opcode()) & flag; } @@ -1134,8 +1129,9 @@ class V8_EXPORT_PRIVATE Instruction final { } } - // For JS call instructions, computes the index of the argument count input. - size_t JSCallArgumentCountInputIndex() const { + // For JS call instructions, computes the index of the expected parameter + // count input. + size_t JSCallExpectedParameterCountInputIndex() const { // Keep in sync with instruction-selector.cc where the inputs are assembled. return InputCount() - 1 - HasCallDescriptorFlag(CallDescriptor::kHasExceptionHandler) - diff --git a/deps/v8/src/compiler/backend/loong64/code-generator-loong64.cc b/deps/v8/src/compiler/backend/loong64/code-generator-loong64.cc index df98f5d89c41..65c5d57a4223 100644 --- a/deps/v8/src/compiler/backend/loong64/code-generator-loong64.cc +++ b/deps/v8/src/compiler/backend/loong64/code-generator-loong64.cc @@ -152,7 +152,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { OutOfLineRecordWrite( CodeGenerator* gen, Register object, Operand offset, Register value, RecordWriteMode mode, StubCallMode stub_mode, - IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag) + TrustedPointerTag trusted_pointer_tag = kTrustedPointerNullTag) : OutOfLineCode(gen), object_(object), offset_(offset), @@ -163,20 +163,20 @@ class OutOfLineRecordWrite final : public OutOfLineCode { #endif // V8_ENABLE_WEBASSEMBLY must_save_ra_(!gen->frame_access_state()->has_frame()), zone_(gen->zone()), - indirect_pointer_tag_(indirect_pointer_tag) { + trusted_pointer_tag_(trusted_pointer_tag) { } void Generate() final { // When storing an indirect pointer, the value will always be a // full/decompressed pointer. if (COMPRESS_POINTERS_BOOL && - mode_ != RecordWriteMode::kValueIsIndirectPointer) { + mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ DecompressTagged(value_, value_); } // No need to check value page flags with the indirect pointer write barrier // because the value is always an ExposedTrustedObject. - if (mode_ != RecordWriteMode::kValueIsIndirectPointer) { + if (mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ CheckPageFlag(value_, MemoryChunk::kPointersToHereAreInterestingMask, eq, exit()); } @@ -190,10 +190,10 @@ class OutOfLineRecordWrite final : public OutOfLineCode { } if (mode_ == RecordWriteMode::kValueIsEphemeronKey) { __ CallEphemeronKeyBarrier(object_, offset_, save_fp_mode); - } else if (mode_ == RecordWriteMode::kValueIsIndirectPointer) { - DCHECK(IsValidIndirectPointerTag(indirect_pointer_tag_)); - __ CallIndirectPointerBarrier(object_, offset_, save_fp_mode, - indirect_pointer_tag_); + } else if (mode_ == RecordWriteMode::kValueIsTrustedPointer) { + DCHECK(IsValidTrustedPointerTag(trusted_pointer_tag_)); + __ CallTrustedPointerBarrier(object_, offset_, save_fp_mode, + trusted_pointer_tag_); #if V8_ENABLE_WEBASSEMBLY } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) { // A direct call to a wasm runtime stub defined in this module. @@ -220,7 +220,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { #endif // V8_ENABLE_WEBASSEMBLY bool must_save_ra_; Zone* zone_; - IndirectPointerTag indirect_pointer_tag_; + TrustedPointerTag trusted_pointer_tag_; }; #define CREATE_OOL_CLASS(ool_name, masm_ool_name, T) \ @@ -334,10 +334,10 @@ class OutOfLineVerifySkippedWriteBarrier final : public OutOfLineCode { Zone* zone_; }; -class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode { +class OutOfLineVerifySkippedTrustedWriteBarrier final : public OutOfLineCode { public: - OutOfLineVerifySkippedIndirectWriteBarrier(CodeGenerator* gen, - Register object, Register value) + OutOfLineVerifySkippedTrustedWriteBarrier(CodeGenerator* gen, Register object, + Register value) : OutOfLineCode(gen), object_(object), value_(value), @@ -354,8 +354,8 @@ class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode { ? SaveFPRegsMode::kSave : SaveFPRegsMode::kIgnore; - __ CallVerifySkippedIndirectWriteBarrierStubSaveRegisters(object_, value_, - save_fp_mode); + __ CallVerifySkippedTrustedWriteBarrierStubSaveRegisters(object_, value_, + save_fp_mode); if (must_save_ra_) { __ Pop(ra); } @@ -860,8 +860,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kArchCallJSFunction: { - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -871,7 +871,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Builtin builtin = function->shared()->builtin_id(); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (Builtins::IsCompatibleJSBuiltin(builtin, num_arguments)) { + if (Builtins::IsCompatibleJSBuiltin(builtin, + expected_parameter_count)) { __ CallBuiltin(builtin); } else { __ Abort(AbortReason::kJSSignatureMismatch); @@ -882,7 +883,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( dispatch_handle); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -890,7 +891,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -903,7 +905,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ Assert(eq, AbortReason::kWrongFunctionContext, cp, Operand(scratch)); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } RecordCallPosition(instr); frame_access_state()->ClearSPDelta(); @@ -1088,7 +1090,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kArchStoreWithWriteBarrier: { RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); AddressingMode addressing_mode = AddressingModeField::decode(instr->opcode()); Register object = i.InputRegister(0); @@ -1116,7 +1118,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ StoreTaggedField(value, MemOperand(object, i.InputRegister(1)), &trap_pc); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, trap_pc); - if (mode > RecordWriteMode::kValueIsIndirectPointer) { + if (mode > RecordWriteMode::kValueIsTrustedPointer) { __ JumpIfSmi(value, ool->exit()); } __ CheckPageFlag(object, @@ -1165,7 +1167,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( MacroAssembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); Register object = i.InputRegister(0); Register offset = i.InputRegister(1); Register value = i.InputRegister(2); @@ -1184,7 +1186,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( // valid if the value isn't an indirect pointer. Otherwise the value will // be a pointer table index, which will always look like a Smi (but // actually reference a pointer in the pointer table). - if (mode > RecordWriteMode::kValueIsIndirectPointer) { + if (mode > RecordWriteMode::kValueIsTrustedPointer) { __ JumpIfSmi(value, ool->exit()); } __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask, @@ -1218,13 +1220,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( RecordTrapInfoIfNeeded(zone(), this, opcode, instr, trap_pc); break; } - case kArchStoreIndirectWithWriteBarrier: { + case kArchStoreTrustedWithWriteBarrier: { RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); - DCHECK_EQ(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_EQ(mode, RecordWriteMode::kValueIsTrustedPointer); AddressingMode addressing_mode = AddressingModeField::decode(instr->opcode()); - IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(i.InputInt64(3)); + DCHECK(IsValidTrustedPointerTag(tag)); Register object = i.InputRegister(0); Register value = i.InputRegister(2); @@ -1232,8 +1234,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( auto ool = zone()->New<OutOfLineRecordWrite>( this, object, Operand(i.InputInt32(1)), value, mode, DetermineStubCallMode(), tag); - __ StoreIndirectPointerField(value, MemOperand(object, i.InputInt32(1)), - &trap_pc); + __ StoreTrustedPointerField(value, MemOperand(object, i.InputInt32(1)), + &trap_pc); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, trap_pc); __ JumpIfMarking(ool->entry()); __ bind(ool->exit()); @@ -1242,7 +1244,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( auto ool = zone()->New<OutOfLineRecordWrite>( this, object, Operand(i.InputRegister(1)), value, mode, DetermineStubCallMode(), tag); - __ StoreIndirectPointerField( + __ StoreTrustedPointerField( value, MemOperand(object, i.InputRegister(1)), &trap_pc); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, trap_pc); __ CheckPageFlag(object, @@ -1252,19 +1254,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } break; } - case kArchStoreIndirectSkippedWriteBarrier: { + case kArchStoreTrustedSkippedWriteBarrier: { AddressingMode addressing_mode = AddressingModeField::decode(instr->opcode()); Register object = i.InputRegister(0); Register value = i.InputRegister(2); #if DEBUG - IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(i.InputInt64(3)); + DCHECK(IsValidTrustedPointerTag(tag)); #endif // DEBUG DCHECK(v8_flags.verify_write_barriers); - auto ool = zone()->New<OutOfLineVerifySkippedIndirectWriteBarrier>( + auto ool = zone()->New<OutOfLineVerifySkippedTrustedWriteBarrier>( this, object, value); __ jmp(ool->entry()); __ bind(ool->exit()); @@ -1273,11 +1275,11 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( masm()); Operand offset(0); if (addressing_mode == kMode_MRI) { - __ StoreIndirectPointerField(value, MemOperand(object, i.InputInt32(1)), - &trap_pc); + __ StoreTrustedPointerField(value, MemOperand(object, i.InputInt32(1)), + &trap_pc); } else { DCHECK_EQ(addressing_mode, kMode_MRR); - __ StoreIndirectPointerField( + __ StoreTrustedPointerField( value, MemOperand(object, i.InputRegister(1)), &trap_pc); } RecordTrapInfoIfNeeded(zone(), this, opcode, instr, trap_pc); @@ -2093,11 +2095,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register base = i.InputRegister(0); int32_t offset = i.InputInt32(1); Register table = i.InputRegister(2); - IndirectPointerTag first = - static_cast<IndirectPointerTag>(i.InputInt32(3)); - IndirectPointerTag last = - static_cast<IndirectPointerTag>(i.InputInt32(4)); - IndirectPointerTagRange tag_range(first, last); + TrustedPointerTag first = static_cast<TrustedPointerTag>(i.InputInt32(3)); + TrustedPointerTag last = static_cast<TrustedPointerTag>(i.InputInt32(4)); + TrustedPointerTagRange tag_range(first, last); Register destination = i.OutputRegister(); Register handle = i.TempRegister(0); @@ -2108,9 +2108,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ Alsl_d(handle, handle, table, kTrustedPointerTableEntrySizeLog2); __ Ld_d(destination, MemOperand(handle, 0)); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = - ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); __ And(destination, destination, Operand(mask)); } else { Register tag = handle; // Reuse handle for tag @@ -2147,10 +2146,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ StoreSandboxedPointerField(i.InputOrZeroRegister(index), mem); break; } - case kLoong64StoreIndirectPointer: { + case kLoong64StoreTrustedPointer: { size_t index = 0; MemOperand mem = i.MemoryOperand(&index); - __ StoreIndirectPointerField(i.InputOrZeroRegister(index), mem); + __ StoreTrustedPointerField(i.InputOrZeroRegister(index), mem); break; } case kLoong64AtomicLoadDecompressTaggedSigned: @@ -3027,30 +3026,23 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kLoong64F64x2Splat: { CpuFeatureScope lsx_scope(masm(), LSX); - UseScratchRegisterScope temps(masm()); - Register TmpReg = temps.Acquire(); - __ Move(TmpReg, i.InputDoubleRegister(0)); - __ vreplgr2vr_d(i.OutputSimd128Register(), TmpReg); + FPURegister input0 = i.InputDoubleRegister(0); + __ vreplve_d(i.OutputSimd128Register(), input0.toV(), zero_reg); break; } case kLoong64F64x2ExtractLane: { CpuFeatureScope lsx_scope(masm(), LSX); - UseScratchRegisterScope temps(masm()); - Register TmpReg = temps.Acquire(); - __ vpickve2gr_d(TmpReg, i.InputSimd128Register(0), i.InputInt8(1)); - __ Move(i.OutputDoubleRegister(), TmpReg); + FPURegister output = i.OutputDoubleRegister(); + __ vreplvei_d(output.toV(), i.InputSimd128Register(0), i.InputInt8(1)); break; } case kLoong64F64x2ReplaceLane: { CpuFeatureScope lsx_scope(masm(), LSX); UseScratchRegisterScope temps(masm()); Register TmpReg = temps.Acquire(); - Simd128Register src = i.InputSimd128Register(0); Simd128Register dst = i.OutputSimd128Register(); + DCHECK_EQ(dst, i.InputSimd128Register(0)); __ Move(TmpReg, i.InputDoubleRegister(2)); - if (dst != src) { - __ vaddi_du(dst, src, 0); - } __ vinsgr2vr_d(dst, TmpReg, i.InputInt8(1)); break; } @@ -3256,30 +3248,23 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kLoong64F32x4Splat: { CpuFeatureScope lsx_scope(masm(), LSX); - UseScratchRegisterScope temps(masm()); - Register TmpReg = temps.Acquire(); - __ FmoveLow(TmpReg, i.InputSingleRegister(0)); - __ vreplgr2vr_w(i.OutputSimd128Register(), TmpReg); + FPURegister input0 = i.InputSingleRegister(0); + __ vreplve_w(i.OutputSimd128Register(), input0.toV(), zero_reg); break; } case kLoong64F32x4ExtractLane: { CpuFeatureScope lsx_scope(masm(), LSX); - UseScratchRegisterScope temps(masm()); - Register TmpReg = temps.Acquire(); - __ vpickve2gr_wu(TmpReg, i.InputSimd128Register(0), i.InputInt8(1)); - __ FmoveLow(i.OutputSingleRegister(), TmpReg); + FPURegister output = i.OutputSingleRegister(); + __ vreplvei_w(output.toV(), i.InputSimd128Register(0), i.InputInt8(1)); break; } case kLoong64F32x4ReplaceLane: { CpuFeatureScope lsx_scope(masm(), LSX); + Simd128Register dst = i.OutputSimd128Register(); UseScratchRegisterScope temps(masm()); Register TmpReg = temps.Acquire(); - Simd128Register src = i.InputSimd128Register(0); - Simd128Register dst = i.OutputSimd128Register(); - __ FmoveLow(TmpReg, i.InputSingleRegister(2)); - if (dst != src) { - __ vaddi_wu(dst, src, 0); - } + DCHECK_EQ(dst, i.InputSimd128Register(0)); + __ movfr2gr_s(TmpReg, i.InputSingleRegister(2)); __ vinsgr2vr_w(dst, TmpReg, i.InputInt8(1)); break; } @@ -3402,11 +3387,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kLoong64I64x2ReplaceLane: { CpuFeatureScope lsx_scope(masm(), LSX); - Simd128Register src = i.InputSimd128Register(0); Simd128Register dst = i.OutputSimd128Register(); - if (src != dst) { - __ vaddi_du(dst, src, 0); - } + DCHECK_EQ(dst, i.InputSimd128Register(0)); __ vinsgr2vr_d(dst, i.InputRegister(2), i.InputInt8(1)); break; } @@ -3575,11 +3557,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kLoong64I32x4ReplaceLane: { CpuFeatureScope lsx_scope(masm(), LSX); - Simd128Register src = i.InputSimd128Register(0); Simd128Register dst = i.OutputSimd128Register(); - if (src != dst) { - __ vaddi_wu(dst, src, 0); - } + DCHECK_EQ(dst, i.InputSimd128Register(0)); __ vinsgr2vr_w(dst, i.InputRegister(2), i.InputInt8(1)); break; } @@ -3820,11 +3799,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kLoong64I16x8ReplaceLane: { CpuFeatureScope lsx_scope(masm(), LSX); - Simd128Register src = i.InputSimd128Register(0); Simd128Register dst = i.OutputSimd128Register(); - if (src != dst) { - __ vaddi_hu(dst, src, 0); - } + DCHECK_EQ(dst, i.InputSimd128Register(0)); __ vinsgr2vr_h(dst, i.InputRegister(2), i.InputInt8(1)); break; } @@ -4051,11 +4027,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kLoong64I8x16ReplaceLane: { CpuFeatureScope lsx_scope(masm(), LSX); - Simd128Register src = i.InputSimd128Register(0); Simd128Register dst = i.OutputSimd128Register(); - if (src != dst) { - __ vaddi_bu(dst, src, 0); - } + DCHECK_EQ(dst, i.InputSimd128Register(0)); __ vinsgr2vr_b(dst, i.InputRegister(2), i.InputInt8(1)); break; } @@ -5050,43 +5023,42 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { + if (call_descriptor->IsCFunctionCall()) { #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ StubPrologue(StackFrame::C_WASM_ENTRY); - // Reserve stack space for saving the c_entry_fp later. - __ Sub_d(sp, sp, Operand(kSystemPointerSize)); + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ StubPrologue(StackFrame::C_WASM_ENTRY); + // Reserve stack space for saving the c_entry_fp later. + __ Sub_d(sp, sp, Operand(kSystemPointerSize)); #else - // For balance. - if (false) { + // For balance. + if (false) { #endif // V8_ENABLE_WEBASSEMBLY - } else { - __ Push(ra, fp); - __ mov(fp, sp); - } - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); } else { - __ StubPrologue(info()->GetOutputStackFrameType()); + __ Push(ra, fp); + __ mov(fp, sp); + } + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + __ StubPrologue(info()->GetOutputStackFrameType()); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ Push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ Sub_d(sp, sp, Operand(kSystemPointerSize)); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ Push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ Sub_d(sp, sp, Operand(kSystemPointerSize)); } +#endif // V8_ENABLE_WEBASSEMBLY } int required_slots = @@ -5118,72 +5090,88 @@ void CodeGenerator::AssembleConstructFrame() { const RegList saves = call_descriptor->CalleeSavedRegisters(); const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters(); - if (required_slots > 0) { - DCHECK(frame_access_state()->has_frame()); #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { - UseScratchRegisterScope temps(masm()); - Register stack_limit = temps.Acquire(); - __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + UseScratchRegisterScope temps(masm()); + Register stack_limit = temps.Acquire(); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + if (stack_space > 0) { __ Add_d(stack_limit, stack_limit, Operand(stack_space)); - __ Branch(&done, uge, sp, Operand(stack_limit)); } - - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - __ MultiPushFPUOrLSX(fp_regs_to_save); - __ li(WasmHandleStackOverflowDescriptor::GapRegister(), stack_space); - __ Add_d( - WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); - __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); - __ MultiPopFPUOrLSX(fp_regs_to_save); - __ MultiPop(regs_to_save); - } else { - __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - if (v8_flags.debug_code) { - __ stop(); - } + __ Branch(&done, uge, sp, Operand(stack_limit)); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + __ MultiPush(regs_to_save); + DoubleRegList fp_regs_to_save; + for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + __ MultiPushFPUOrLSX(fp_regs_to_save); + __ li(WasmHandleStackOverflowDescriptor::GapRegister(), stack_space); + __ Add_d(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ li(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + call_descriptor->ParameterSlotCount() * kSystemPointerSize); + __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + __ MultiPopFPUOrLSX(fp_regs_to_save); + __ MultiPop(regs_to_save); + } else { + __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + if (v8_flags.debug_code) { + __ stop(); } - - __ bind(&done); } -#endif // V8_ENABLE_WEBASSEMBLY + + __ bind(&done); } +#endif // V8_ENABLE_WEBASSEMBLY const int returns = frame()->GetReturnSlotCount(); @@ -5256,38 +5244,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - Label done; - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ Ld_d(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - __ BranchShort( - &done, ne, scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - RegList regs_to_save; - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpReturnRegisters) fp_regs_to_save.set(reg); - __ MultiPushFPUOrLSX(fp_regs_to_save); - __ li(kCArgRegs[0], ExternalReference::isolate_address()); - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ PrepareCallCFunction(1, scratch); - } - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - __ mov(fp, kReturnRegister0); - __ MultiPopFPUOrLSX(fp_regs_to_save); - __ MultiPop(regs_to_save); - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY - // Functions with JS linkage have at least one parameter (the receiver). // If {parameter_slots} == 0, it means it is a builtin with // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping diff --git a/deps/v8/src/compiler/backend/loong64/instruction-codes-loong64.h b/deps/v8/src/compiler/backend/loong64/instruction-codes-loong64.h index c263af6f3bcb..d1d3af2ef172 100644 --- a/deps/v8/src/compiler/backend/loong64/instruction-codes-loong64.h +++ b/deps/v8/src/compiler/backend/loong64/instruction-codes-loong64.h @@ -165,7 +165,7 @@ namespace compiler { V(Loong64Float64SilenceNaN) \ V(Loong64LoadDecodeSandboxedPointer) \ V(Loong64StoreEncodeSandboxedPointer) \ - V(Loong64StoreIndirectPointer) \ + V(Loong64StoreTrustedPointer) \ V(Loong64Push) \ V(Loong64Peek) \ V(Loong64Poke) \ diff --git a/deps/v8/src/compiler/backend/loong64/instruction-selector-loong64.cc b/deps/v8/src/compiler/backend/loong64/instruction-selector-loong64.cc index abafdc9ab6d4..889991a7e46f 100644 --- a/deps/v8/src/compiler/backend/loong64/instruction-selector-loong64.cc +++ b/deps/v8/src/compiler/backend/loong64/instruction-selector-loong64.cc @@ -211,15 +211,6 @@ static void VisitSimdShift(InstructionSelector* selector, ArchOpcode opcode, } } -static void VisitRRIR(InstructionSelector* selector, ArchOpcode opcode, - OpIndex node) { - Loong64OperandGenerator g(selector); - const turboshaft::Simd128ReplaceLaneOp& op = - selector->Get(node).template Cast<turboshaft::Simd128ReplaceLaneOp>(); - selector->Emit(opcode, g.DefineAsRegister(node), g.UseRegister(op.input(0)), - g.UseImmediate(op.lane), g.UseUniqueRegister(op.input(1))); -} - static void VisitUniqueRRR(InstructionSelector* selector, ArchOpcode opcode, OpIndex node) { Loong64OperandGenerator g(selector); @@ -744,8 +735,6 @@ ArchOpcode GetLoadOpcode(turboshaft::MemoryRepresentation loaded_rep, case MemoryRepresentation::ProtectedPointer(): CHECK(V8_ENABLE_SANDBOX_BOOL); return kLoong64LoadDecompressProtected; - case MemoryRepresentation::IndirectPointer(): - UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): UNREACHABLE(); case MemoryRepresentation::SandboxedPointer(): @@ -789,10 +778,7 @@ ArchOpcode GetStoreOpcode(MemoryRepresentation stored_rep) { // We never store directly to protected pointers from generated code. UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); - case MemoryRepresentation::IndirectPointer(): - return kLoong64StoreIndirectPointer; + return kLoong64StoreTrustedPointer; case MemoryRepresentation::SandboxedPointer(): return kLoong64StoreEncodeSandboxedPointer; case MemoryRepresentation::Simd128(): @@ -843,7 +829,7 @@ void InstructionSelector::VisitStore(OpIndex node) { // TODO(loong64): I guess this could be done in a better way. if (write_barrier_kind != kNoWriteBarrier && !v8_flags.disable_write_barriers) { - DCHECK(CanBeTaggedOrCompressedOrIndirectPointer(rep)); + DCHECK(CanBeTaggedOrCompressedOrTrustedPointer(rep)); AddressingMode addressing_mode; InstructionOperand inputs[4]; size_t input_count = 0; @@ -859,16 +845,16 @@ void InstructionSelector::VisitStore(OpIndex node) { } inputs[input_count++] = g.UseUniqueRegister(value); InstructionCode code; - if (rep == MachineRepresentation::kIndirectPointer) { - DCHECK(write_barrier_kind == kIndirectPointerWriteBarrier || + if (rep == MachineRepresentation::kTrustedPointer) { + DCHECK(write_barrier_kind == kTrustedPointerWriteBarrier || write_barrier_kind == kSkippedWriteBarrier); - // In this case we need to add the IndirectPointerTag as additional input. + // In this case we need to add the TrustedPointerTag as additional input. code = write_barrier_kind == kSkippedWriteBarrier - ? kArchStoreIndirectSkippedWriteBarrier - : kArchStoreIndirectWithWriteBarrier; - code |= RecordWriteModeField::encode( - RecordWriteMode::kValueIsIndirectPointer); - IndirectPointerTag tag = store_view.indirect_pointer_tag(); + ? kArchStoreTrustedSkippedWriteBarrier + : kArchStoreTrustedWithWriteBarrier; + code |= + RecordWriteModeField::encode(RecordWriteMode::kValueIsTrustedPointer); + TrustedPointerTag tag = store_view.trusted_pointer_tag(); inputs[input_count++] = g.UseImmediate64(static_cast<int64_t>(tag)); } else if (write_barrier_kind == kSkippedWriteBarrier) { code = kArchStoreSkippedWriteBarrier; @@ -3678,7 +3664,12 @@ SIMD_VISIT_EXTRACT_LANE(I8x16, S) #define SIMD_VISIT_REPLACE_LANE(Type) \ void InstructionSelector::Visit##Type##ReplaceLane(OpIndex node) { \ - VisitRRIR(this, kLoong64##Type##ReplaceLane, node); \ + Loong64OperandGenerator g(this); \ + const turboshaft::Simd128ReplaceLaneOp& op = \ + Get(node).template Cast<turboshaft::Simd128ReplaceLaneOp>(); \ + Emit(kLoong64##Type##ReplaceLane, g.DefineSameAsFirst(node), \ + g.UseRegister(op.input(0)), g.UseImmediate(op.lane), \ + g.UseRegister(op.input(1))); \ } SIMD_TYPE_LIST(SIMD_VISIT_REPLACE_LANE) #undef SIMD_VISIT_REPLACE_LANE diff --git a/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc b/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc index 8cddfacc3709..a0bc31e7664c 100644 --- a/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc +++ b/deps/v8/src/compiler/backend/mips64/code-generator-mips64.cc @@ -718,9 +718,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ Assert(eq, AbortReason::kWrongFunctionContext, cp, Operand(kScratchReg)); } - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); - __ CallJSFunction(func, num_arguments); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); + __ CallJSFunction(func, expected_parameter_count); RecordCallPosition(instr); frame_access_state()->ClearSPDelta(); break; @@ -930,8 +930,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kArchAtomicStoreSkippedWriteBarrier: case kArchStoreSkippedWriteBarrier: - case kArchStoreIndirectWithWriteBarrier: - case kArchStoreIndirectSkippedWriteBarrier: + case kArchStoreTrustedWithWriteBarrier: + case kArchStoreTrustedSkippedWriteBarrier: UNREACHABLE(); case kArchStackSlot: { FrameOffset offset = @@ -4260,43 +4260,42 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { + if (call_descriptor->IsCFunctionCall()) { #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ StubPrologue(StackFrame::C_WASM_ENTRY); - // Reserve stack space for saving the c_entry_fp later. - __ Dsubu(sp, sp, Operand(kSystemPointerSize)); + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ StubPrologue(StackFrame::C_WASM_ENTRY); + // Reserve stack space for saving the c_entry_fp later. + __ Dsubu(sp, sp, Operand(kSystemPointerSize)); #else - // For balance. - if (false) { + // For balance. + if (false) { #endif // V8_ENABLE_WEBASSEMBLY - } else { - __ Push(ra, fp); - __ mov(fp, sp); - } - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); } else { - __ StubPrologue(info()->GetOutputStackFrameType()); + __ Push(ra, fp); + __ mov(fp, sp); + } + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + __ StubPrologue(info()->GetOutputStackFrameType()); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ Push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ Dsubu(sp, sp, Operand(kSystemPointerSize)); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ Push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ Dsubu(sp, sp, Operand(kSystemPointerSize)); } +#endif // V8_ENABLE_WEBASSEMBLY } int required_slots = @@ -4328,39 +4327,52 @@ void CodeGenerator::AssembleConstructFrame() { const RegList saves = call_descriptor->CalleeSavedRegisters(); const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters(); - if (required_slots > 0) { - DCHECK(frame_access_state()->has_frame()); #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; - - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { - __ LoadStackLimit(kScratchReg, - MacroAssembler::StackLimitKind::kRealStackLimit); + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; + + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + __ LoadStackLimit(kScratchReg, + MacroAssembler::StackLimitKind::kRealStackLimit); + if (stack_space > 0) { __ Daddu(kScratchReg, kScratchReg, Operand(stack_space)); - __ Branch(&done, uge, sp, Operand(kScratchReg)); } + __ Branch(&done, uge, sp, Operand(kScratchReg)); + } + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ Abort(AbortReason::kUnexpectedReturnFromThrow); + } else { __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), RelocInfo::WASM_STUB_CALL); // The call does not return, hence we can ignore any references and just // define an empty safepoint. RecordSafepointWithoutTaggedSlots(); if (v8_flags.debug_code) __ stop(); - - __ bind(&done); } -#endif // V8_ENABLE_WEBASSEMBLY + + __ bind(&done); } +#endif // V8_ENABLE_WEBASSEMBLY const int returns = frame()->GetReturnSlotCount(); diff --git a/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc b/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc index 9be8d54d2803..a65d59818167 100644 --- a/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc +++ b/deps/v8/src/compiler/backend/mips64/instruction-selector-mips64.cc @@ -459,7 +459,7 @@ void InstructionSelector::VisitLoad(OpIndex node) { case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kCompressed: // Fall through. case MachineRepresentation::kMapWord: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kFloat16RawBits: // Fall through. case MachineRepresentation::kNone: UNREACHABLE(); @@ -550,7 +550,7 @@ void InstructionSelector::VisitStore(OpIndex node) { case MachineRepresentation::kProtectedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kMapWord: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kFloat16RawBits: // Fall through. case MachineRepresentation::kNone: UNREACHABLE(); @@ -1542,7 +1542,7 @@ void InstructionSelector::VisitUnalignedLoad(OpIndex node) { case MachineRepresentation::kProtectedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kMapWord: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kFloat16RawBits: // Fall through. case MachineRepresentation::kNone: UNREACHABLE(); @@ -1596,7 +1596,7 @@ void InstructionSelector::VisitUnalignedStore(OpIndex node) { case MachineRepresentation::kProtectedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kMapWord: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kFloat16RawBits: // Fall through. case MachineRepresentation::kNone: UNREACHABLE(); diff --git a/deps/v8/src/compiler/backend/move-optimizer.cc b/deps/v8/src/compiler/backend/move-optimizer.cc index dd4348850ca0..f80c453efca8 100644 --- a/deps/v8/src/compiler/backend/move-optimizer.cc +++ b/deps/v8/src/compiler/backend/move-optimizer.cc @@ -560,10 +560,31 @@ bool Is64BitsWide(const InstructionOperand& op) { #endif } +#if V8_TARGET_ARCH_X64 +bool IsSimd256(const InstructionOperand& op) { + return op.IsAnyLocationOperand() && + LocationOperand::cast(&op)->representation() == + MachineRepresentation::kSimd256; +} +#endif // V8_TARGET_ARCH_X64 + bool LoadCompare(const MoveOperands* a, const MoveOperands* b) { if (!a->source().EqualsCanonicalized(b->source())) { return a->source().CompareCanonicalized(b->source()); } +#if V8_TARGET_ARCH_X64 + // Simd256 must be preferred over Simd128 as the group's representative + // destination. kSimd256 and kSimd128 may share the same virtual register + // (e.g. an elided 128-bit lane-0 extraction aliased to its 256-bit + // producer on x64), so a Simd256 destination must never be rewritten to + // source from a Simd128 one, which would silently zero the upper 128 bits. + if (IsSimd256(a->destination()) && !IsSimd256(b->destination())) { + return true; + } + if (!IsSimd256(a->destination()) && IsSimd256(b->destination())) { + return false; + } +#endif // V8_TARGET_ARCH_X64 // The replacements below are only safe if wider values are preferred. // In particular, replacing an uncompressed pointer with a compressed // pointer is disallowed. diff --git a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc index fa085daf2a55..bde8d65ae413 100644 --- a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc +++ b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc @@ -185,7 +185,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { CodeGenerator* gen, Register object, Register offset, Register value, Register scratch0, Register scratch1, RecordWriteMode mode, StubCallMode stub_mode, UnwindingInfoWriter* unwinding_info_writer, - IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag) + TrustedPointerTag trusted_pointer_tag = kTrustedPointerNullTag) : OutOfLineCode(gen), object_(object), offset_(offset), @@ -650,11 +650,12 @@ static inline bool is_wasm_on_be(bool IsWasm) { do { \ UseScratchRegisterScope temps(masm()); \ Register scratch = temps.Acquire(); \ + Register scratch2 = temps.Acquire(); \ Register expected_val = i.InputRegister(2); \ Register new_val = i.InputRegister(3); \ Register dst = i.OutputRegister(); \ MAYBE_REVERSE_IF_WASM(scratch, expected_val, reverse_op, true); \ - MAYBE_REVERSE_IF_WASM(r0, new_val, reverse_op, true); \ + MAYBE_REVERSE_IF_WASM(scratch2, new_val, reverse_op, true); \ __ AtomicCompareExchange<_type>( \ MemOperand(i.InputRegister(0), i.InputRegister(1)), expected_val, \ new_val, dst); \ @@ -950,8 +951,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kArchCallJSFunction: { v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool( masm()); - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -960,7 +961,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( if (function->shared()->HasBuiltinId()) { Builtin builtin = function->shared()->builtin_id(); size_t expected = Builtins::GetFormalParameterCount(builtin); - if (num_arguments == expected) { + if (expected_parameter_count == expected) { __ CallBuiltin(builtin); } else { __ AssertUnreachable(AbortReason::kJSSignatureMismatch); @@ -969,7 +970,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( JSDispatchHandle dispatch_handle = function->dispatch_handle(); size_t expected = isolate()->js_dispatch_table().GetParameterCount( dispatch_handle); - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -977,7 +978,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -990,7 +992,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ CmpS64(cp, scratch); __ Assert(eq, AbortReason::kWrongFunctionContext); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } RecordCallPosition(instr); DCHECK_EQ(LeaveRC, i.OutputRCBit()); @@ -1269,8 +1271,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ StoreTaggedField(value, operand); break; } - case kArchStoreIndirectSkippedWriteBarrier: - case kArchStoreIndirectWithWriteBarrier: { + case kArchStoreTrustedSkippedWriteBarrier: + case kArchStoreTrustedWithWriteBarrier: { UNREACHABLE(); } case kArchStackSlot: { @@ -3164,55 +3166,53 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { + if (call_descriptor->IsCFunctionCall()) { #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ StubPrologue(StackFrame::C_WASM_ENTRY); - // Reserve stack space for saving the c_entry_fp later. - __ addi(sp, sp, Operand(-kSystemPointerSize)); + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ StubPrologue(StackFrame::C_WASM_ENTRY); + // Reserve stack space for saving the c_entry_fp later. + __ addi(sp, sp, Operand(-kSystemPointerSize)); #else - // For balance. - if (false) { + // For balance. + if (false) { #endif // V8_ENABLE_WEBASSEMBLY + } else { + __ mflr(r0); + if (V8_EMBEDDED_CONSTANT_POOL_BOOL) { + __ Push(r0, fp, kConstantPoolRegister); + // Adjust FP to point to saved FP. + __ SubS64(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset)); } else { - __ mflr(r0); - if (V8_EMBEDDED_CONSTANT_POOL_BOOL) { - __ Push(r0, fp, kConstantPoolRegister); - // Adjust FP to point to saved FP. - __ SubS64(fp, sp, - Operand(StandardFrameConstants::kConstantPoolOffset)); - } else { - __ Push(r0, fp); - __ mr(fp, sp); - } + __ Push(r0, fp); + __ mr(fp, sp); } - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); - } else { - StackFrame::Type type = info()->GetOutputStackFrameType(); - // TODO(mbrandy): Detect cases where ip is the entrypoint (for - // efficient initialization of the constant pool pointer register). - __ StubPrologue(type); + } + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + StackFrame::Type type = info()->GetOutputStackFrameType(); + // TODO(mbrandy): Detect cases where ip is the entrypoint (for + // efficient initialization of the constant pool pointer register). + __ StubPrologue(type); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ Push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ addi(sp, sp, Operand(-kSystemPointerSize)); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ Push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ addi(sp, sp, Operand(-kSystemPointerSize)); } - unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); +#endif // V8_ENABLE_WEBASSEMBLY } + unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); int required_slots = frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount(); @@ -3235,77 +3235,96 @@ void CodeGenerator::AssembleConstructFrame() { ? call_descriptor->CalleeSavedRegisters() - kConstantPoolRegister : call_descriptor->CalleeSavedRegisters(); - if (required_slots > 0) { #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; - - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { - UseScratchRegisterScope temps(masm()); - Register stack_limit = temps.Acquire(); - __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); - __ AddS64(stack_limit, stack_limit, Operand(stack_space)); - __ CmpU64(sp, stack_limit); - __ bge(&done); - } - - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - Simd128RegList simd128_regs_to_save; - for (auto reg : wasm::kSimd128ParamRegisters) - simd128_regs_to_save.set(reg); - __ MultiPushF64AndV128(fp_regs_to_save, simd128_regs_to_save); - __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), - Operand(stack_space)); - __ AddS64( - WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); - __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); - __ MultiPopF64AndV128(fp_regs_to_save, simd128_regs_to_save); - __ MultiPop(regs_to_save); - } else { - __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - if (v8_flags.debug_code) __ stop(); - } + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; - __ bind(&done); + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + UseScratchRegisterScope temps(masm()); + Register stack_limit = temps.Acquire(); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + if (stack_space > 0) { + __ AddS64(stack_limit, stack_limit, + Operand(static_cast<int32_t>(stack_space))); + } + __ CmpU64(sp, stack_limit); + __ bge(&done); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + __ MultiPush(regs_to_save); + DoubleRegList fp_regs_to_save; + for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + Simd128RegList simd128_regs_to_save; + for (auto reg : wasm::kSimd128ParamRegisters) + simd128_regs_to_save.set(reg); + __ MultiPushF64AndV128(fp_regs_to_save, simd128_regs_to_save); + __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), + Operand(static_cast<int32_t>(stack_space))); + __ AddS64(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ mov( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize)); + __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + __ MultiPopF64AndV128(fp_regs_to_save, simd128_regs_to_save); + __ MultiPop(regs_to_save); + } else { + __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + if (v8_flags.debug_code) __ stop(); } + __ bind(&done); + } #endif // V8_ENABLE_WEBASSEMBLY - // Skip callee-saved and return slots, which are pushed below. - required_slots -= saves.Count(); - required_slots -= frame()->GetReturnSlotCount(); - required_slots -= (kDoubleSize / kSystemPointerSize) * saves_fp.Count(); + // Skip callee-saved and return slots, which are pushed below. + required_slots -= saves.Count(); + required_slots -= frame()->GetReturnSlotCount(); + required_slots -= (kDoubleSize / kSystemPointerSize) * saves_fp.Count(); + if (required_slots > 0) { __ AddS64(sp, sp, Operand(-required_slots * kSystemPointerSize)); } @@ -3378,40 +3397,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ LoadU64(scratch, - MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - __ CmpU64( - scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - __ bne(&done); - RegList regs_to_save; - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - Simd128RegList simd128_regs_to_save; - for (auto reg : wasm::kSimd128ParamRegisters) simd128_regs_to_save.set(reg); - __ MultiPushF64AndV128(fp_regs_to_save, simd128_regs_to_save); - __ Move(kCArgRegs[0], ExternalReference::isolate_address()); - __ PrepareCallCFunction(1); - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - __ mr(fp, kReturnRegister0); - __ MultiPopF64AndV128(fp_regs_to_save, simd128_regs_to_save); - __ MultiPop(regs_to_save); - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY - Register argc_reg = r6; // Functions with JS linkage have at least one parameter (the receiver). // If {parameter_slots} == 0, it means it is a builtin with diff --git a/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc b/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc index 71432843293a..ff7db2fec3b3 100644 --- a/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc +++ b/deps/v8/src/compiler/backend/ppc/instruction-selector-ppc.cc @@ -247,10 +247,7 @@ ArchOpcode SelectLoadOpcode(MemoryRepresentation loaded_rep, *mode = kNoImmediate; return kPPC_LoadSimd128; case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); case MemoryRepresentation::ProtectedPointer(): - case MemoryRepresentation::IndirectPointer(): case MemoryRepresentation::SandboxedPointer(): case MemoryRepresentation::Simd256(): UNREACHABLE(); @@ -305,7 +302,7 @@ ArchOpcode SelectLoadOpcode(LoadRepresentation load_rep, ImmediateMode* mode) { case MachineRepresentation::kFloat16: UNIMPLEMENTED(); case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kSimd256: // Fall through. case MachineRepresentation::kMapWord: // Fall through. @@ -492,9 +489,6 @@ void VisitStoreCommon(InstructionSelector* selector, OpIndex node, mode = kNoImmediate; break; case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); - case MemoryRepresentation::IndirectPointer(): case MemoryRepresentation::SandboxedPointer(): case MemoryRepresentation::Simd256(): UNREACHABLE(); diff --git a/deps/v8/src/compiler/backend/register-allocation.h b/deps/v8/src/compiler/backend/register-allocation.h index e8465947f996..1449f3608166 100644 --- a/deps/v8/src/compiler/backend/register-allocation.h +++ b/deps/v8/src/compiler/backend/register-allocation.h @@ -95,7 +95,7 @@ inline int ByteWidthForStackSlot(MachineRepresentation rep) { return kSimd256Size; case MachineRepresentation::kNone: case MachineRepresentation::kMapWord: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); } diff --git a/deps/v8/src/compiler/backend/register-allocator-verifier.cc b/deps/v8/src/compiler/backend/register-allocator-verifier.cc index f0e00bd49b8f..e607dc7afb29 100644 --- a/deps/v8/src/compiler/backend/register-allocator-verifier.cc +++ b/deps/v8/src/compiler/backend/register-allocator-verifier.cc @@ -7,7 +7,6 @@ #include <optional> #include "src/compiler/backend/instruction.h" -#include "src/utils/bit-vector.h" #include "src/utils/ostreams.h" namespace v8::internal::compiler { @@ -60,10 +59,8 @@ int GetValue(const ImmediateOperand* imm) { } // namespace RegisterAllocatorVerifier::RegisterAllocatorVerifier( - Zone* zone, const RegisterConfiguration* config, - const InstructionSequence* sequence, const Frame* frame) + Zone* zone, const InstructionSequence* sequence, const Frame* frame) : zone_(zone), - config_(config), sequence_(sequence), constraints_(zone), assessments_(zone), @@ -437,9 +434,8 @@ BlockAssessments* RegisterAllocatorVerifier::CreateForBlock( V8_CLANG_NO_SANITIZE("coverage") void RegisterAllocatorVerifier::ValidatePendingAssessment( - RpoNumber block_id, InstructionOperand op, - const BlockAssessments* current_assessments, - PendingAssessment* const assessment, int virtual_register) { + RpoNumber block_id, PendingAssessment* const assessment, + int virtual_register) { if (assessment->IsAliasOf(virtual_register)) return; // When validating a pending assessment, it is possible some of the @@ -542,8 +538,7 @@ void RegisterAllocatorVerifier::ValidateUse( break; case Pending: { PendingAssessment* pending = PendingAssessment::cast(assessment); - ValidatePendingAssessment(block_id, op, current_assessments, pending, - virtual_register); + ValidatePendingAssessment(block_id, pending, virtual_register); break; } } @@ -624,7 +619,7 @@ void RegisterAllocatorVerifier::VerifyGapMoves() { vreg); break; case Pending: - ValidatePendingAssessment(block->rpo_number(), op, block_assessments, + ValidatePendingAssessment(block->rpo_number(), PendingAssessment::cast(found_op->second), vreg); break; diff --git a/deps/v8/src/compiler/backend/register-allocator-verifier.h b/deps/v8/src/compiler/backend/register-allocator-verifier.h index 230beff806aa..a7684d817086 100644 --- a/deps/v8/src/compiler/backend/register-allocator-verifier.h +++ b/deps/v8/src/compiler/backend/register-allocator-verifier.h @@ -204,8 +204,7 @@ class BlockAssessments : public ZoneObject { class RegisterAllocatorVerifier final : public ZoneObject { public: - RegisterAllocatorVerifier(Zone* zone, const RegisterConfiguration* config, - const InstructionSequence* sequence, + RegisterAllocatorVerifier(Zone* zone, const InstructionSequence* sequence, const Frame* frame); RegisterAllocatorVerifier(const RegisterAllocatorVerifier&) = delete; RegisterAllocatorVerifier& operator=(const RegisterAllocatorVerifier&) = @@ -270,7 +269,6 @@ class RegisterAllocatorVerifier final : public ZoneObject { }; Zone* zone() const { return zone_; } - const RegisterConfiguration* config() { return config_; } const InstructionSequence* sequence() const { return sequence_; } Constraints* constraints() { return &constraints_; } int spill_slot_delta() const { return spill_slot_delta_; } @@ -287,15 +285,13 @@ class RegisterAllocatorVerifier final : public ZoneObject { // Prove that this operand is an alias of this virtual register in the given // block. Update the assessment if that's the case. - void ValidatePendingAssessment(RpoNumber block_id, InstructionOperand op, - const BlockAssessments* current_assessments, + void ValidatePendingAssessment(RpoNumber block_id, PendingAssessment* const assessment, int virtual_register); void ValidateUse(RpoNumber block_id, BlockAssessments* current_assessments, InstructionOperand op, int virtual_register); Zone* const zone_; - const RegisterConfiguration* config_; const InstructionSequence* const sequence_; Constraints constraints_; ZoneMap<RpoNumber, BlockAssessments*> assessments_; diff --git a/deps/v8/src/compiler/backend/register-allocator.cc b/deps/v8/src/compiler/backend/register-allocator.cc index 6e85eca12994..dea3cbada453 100644 --- a/deps/v8/src/compiler/backend/register-allocator.cc +++ b/deps/v8/src/compiler/backend/register-allocator.cc @@ -4,6 +4,7 @@ #include "src/compiler/backend/register-allocator.h" +#include <array> #include <iomanip> #include <optional> @@ -16,8 +17,6 @@ #include "src/codegen/tick-counter.h" #include "src/compiler/backend/register-allocation.h" #include "src/compiler/backend/spill-placer.h" -#include "src/compiler/linkage.h" -#include "src/strings/string-stream.h" namespace v8 { namespace internal { @@ -153,12 +152,6 @@ UsePositionHintType UsePosition::HintTypeForOperand( UNREACHABLE(); } -void UsePosition::SetHint(UsePosition* use_pos) { - DCHECK_NOT_NULL(use_pos); - hint_ = use_pos; - flags_ = HintTypeField::update(flags_, UsePositionHintType::kUsePos); -} - void UsePosition::ResolveHint(UsePosition* use_pos) { DCHECK_NOT_NULL(use_pos); if (HintTypeField::decode(flags_) != UsePositionHintType::kUnresolved) return; @@ -166,15 +159,6 @@ void UsePosition::ResolveHint(UsePosition* use_pos) { flags_ = HintTypeField::update(flags_, UsePositionHintType::kUsePos); } -void UsePosition::set_type(UsePositionType type, bool register_beneficial) { - DCHECK_IMPLIES(type == UsePositionType::kRequiresSlot, !register_beneficial); - DCHECK_EQ(kUnassignedRegister, AssignedRegisterField::decode(flags_)); - flags_ = TypeField::encode(type) | - RegisterBeneficialField::encode(register_beneficial) | - HintTypeField::encode(HintTypeField::decode(flags_)) | - AssignedRegisterField::encode(kUnassignedRegister); -} - void LifetimePosition::Print() const { StdoutStream{} << *this << std::endl; } LiveRange::LiveRange(int relative_id, MachineRepresentation rep, @@ -232,11 +216,6 @@ void LiveRange::set_assigned_register(int reg) { bits_ = AssignedRegisterField::update(bits_, reg); } -void LiveRange::UnsetAssignedRegister() { - DCHECK(HasRegisterAssigned() && !spilled()); - bits_ = AssignedRegisterField::update(bits_, kUnassignedRegister); -} - void LiveRange::AttachToNext(Zone* zone) { DCHECK_NOT_NULL(next_); @@ -291,7 +270,7 @@ bool LiveRange::RegisterFromFirstHint(int* register_index) { return false; } DCHECK_GE(positions_span_[current_hint_position_index_]->pos(), - positions_span_.first()->pos()); + positions_span_.front()->pos()); DCHECK_LE(positions_span_[current_hint_position_index_]->pos(), End()); bool needs_revisit = false; @@ -310,12 +289,9 @@ bool LiveRange::RegisterFromFirstHint(int* register_index) { current_hint_position_index_ = std::distance(positions_span_.begin(), pos_it); } -#ifdef DEBUG - UsePosition** pos_check_it = - std::find_if(positions_span_.begin(), positions_span_.end(), - [](UsePosition* pos) { return pos->HasHint(); }); - CHECK_EQ(pos_it, pos_check_it); -#endif + SLOW_DCHECK(pos_it == + std::find_if(positions_span_.begin(), positions_span_.end(), + [](UsePosition* pos) { return pos->HasHint(); })); return pos_it != positions_span_.end(); } @@ -480,9 +456,11 @@ LiveRange* LiveRange::SplitAt(LifetimePosition position, Zone* zone) { current_interval_ = intervals_.begin(); result->current_interval_ = result->intervals_.begin(); -#ifdef DEBUG - VerifyChildStructure(); - result->VerifyChildStructure(); +#ifdef ENABLE_SLOW_DCHECKS + if (v8_flags.enable_slow_asserts) { + VerifyChildStructure(); + result->VerifyChildStructure(); + } #endif result->top_level_ = TopLevel(); @@ -544,8 +522,8 @@ bool LiveRange::ShouldBeAllocatedBefore(const LiveRange* other) const { } if (positions_span_.empty()) return false; if (other->positions_span_.empty()) return true; - UsePosition* pos = positions_span_.first(); - UsePosition* other_pos = other->positions_span_.first(); + UsePosition* pos = positions_span_.front(); + UsePosition* other_pos = other->positions_span_.front(); // To make the order total, handle the case where both positions are equal. if (pos->pos() == other_pos->pos()) { return TopLevel()->vreg() < other->TopLevel()->vreg(); @@ -693,12 +671,10 @@ TopLevelLiveRange::TopLevelLiveRange(int vreg, MachineRepresentation rep, : LiveRange(0, rep, this), vreg_(vreg), last_child_id_(0), + spill_start_index_(kMaxInt), spill_operand_(nullptr), spill_move_insertion_locations_(nullptr), - children_({this}, zone), - spilled_in_deferred_blocks_(false), - has_preassigned_slot_(false), - spill_start_index_(kMaxInt) { + children_({this}, zone) { bits_ |= SpillTypeField::encode(SpillType::kNoSpillType); } @@ -711,8 +687,7 @@ void TopLevelLiveRange::RecordSpillLocation(Zone* zone, int gap_index, void TopLevelLiveRange::CommitSpillMoves(RegisterAllocationData* data, const InstructionOperand& op) { - DCHECK_IMPLIES(op.IsConstant(), - GetSpillMoveInsertionLocations(data) == nullptr); + DCHECK_IMPLIES(op.IsConstant(), GetSpillMoveInsertionLocations() == nullptr); if (HasGeneralSpillRange()) { SetLateSpillingSelected(false); @@ -721,7 +696,7 @@ void TopLevelLiveRange::CommitSpillMoves(RegisterAllocationData* data, InstructionSequence* sequence = data->code(); Zone* zone = sequence->zone(); - for (SpillMoveInsertionList* to_spill = GetSpillMoveInsertionLocations(data); + for (SpillMoveInsertionList* to_spill = GetSpillMoveInsertionLocations(); to_spill != nullptr; to_spill = to_spill->next) { Instruction* instr = sequence->InstructionAt(to_spill->gap_index); ParallelMove* move = @@ -733,13 +708,12 @@ void TopLevelLiveRange::CommitSpillMoves(RegisterAllocationData* data, void TopLevelLiveRange::FilterSpillMoves(RegisterAllocationData* data, const InstructionOperand& op) { - DCHECK_IMPLIES(op.IsConstant(), - GetSpillMoveInsertionLocations(data) == nullptr); + DCHECK_IMPLIES(op.IsConstant(), GetSpillMoveInsertionLocations() == nullptr); bool might_be_duplicated = has_slot_use() || spilled(); InstructionSequence* sequence = data->code(); SpillMoveInsertionList* previous = nullptr; - for (SpillMoveInsertionList* to_spill = GetSpillMoveInsertionLocations(data); + for (SpillMoveInsertionList* to_spill = GetSpillMoveInsertionLocations(); to_spill != nullptr; previous = to_spill, to_spill = to_spill->next) { Instruction* instr = sequence->InstructionAt(to_spill->gap_index); ParallelMove* move = instr->GetParallelMove(Instruction::START); @@ -791,14 +765,19 @@ AllocatedOperand TopLevelLiveRange::GetSpillRangeOperand() const { } LiveRange* TopLevelLiveRange::GetChildCovers(LifetimePosition pos) { -#ifdef DEBUG - // Make sure the cache contains the correct, actual children. - LiveRange* child = this; - for (LiveRange* cached_child : children_) { - DCHECK_EQ(cached_child, child); - child = child->next(); + DCHECK(!children_.empty()); + DCHECK_EQ(children_.front(), this); + DCHECK_NULL(children_.back()->next()); +#ifdef ENABLE_SLOW_DCHECKS + if (v8_flags.enable_slow_asserts) { + // Make sure the cache contains the correct, actual children. + LiveRange* child = this; + for (LiveRange* cached_child : children_) { + DCHECK_EQ(cached_child, child); + child = child->next(); + } + DCHECK_NULL(child); } - DCHECK_NULL(child); #endif auto child_it = @@ -814,7 +793,7 @@ LiveRange* TopLevelLiveRange::GetChildCovers(LifetimePosition pos) { void TopLevelLiveRange::Verify() const { VerifyChildrenInOrder(); for (const LiveRange* child = this; child != nullptr; child = child->next()) { - VerifyChildStructure(); + child->VerifyChildStructure(); } } @@ -1069,8 +1048,8 @@ AreUseIntervalsIntersectingVector(base::Vector<const UseInterval> a, base::Vector<const UseInterval> b) { SLOW_DCHECK(std::is_sorted(a.begin(), a.end()) && std::is_sorted(b.begin(), b.end())); - if (a.empty() || b.empty() || a.last().end() <= b.first().start() || - b.last().end() <= a.first().start()) { + if (a.empty() || b.empty() || a.back().end() <= b.front().start() || + b.back().end() <= a.front().start()) { return {}; } @@ -1081,7 +1060,7 @@ AreUseIntervalsIntersectingVector(base::Vector<const UseInterval> a, auto a_it = a.begin(); // Advance `b` already to the interval that ends at or after `a_start`. - LifetimePosition a_start = a.first().start(); + LifetimePosition a_start = a.front().start(); auto b_it = std::lower_bound( b.begin(), b.end(), a_start, [](const UseInterval& interval, LifetimePosition position) { @@ -1197,7 +1176,6 @@ RegisterAllocationData::RegisterAllocationData( delayed_references_(allocation_zone()), assigned_registers_(nullptr), assigned_double_registers_(nullptr), - virtual_register_count_(code->VirtualRegisterCount()), preassigned_slot_ranges_(zone), spill_state_(code->InstructionBlockCount(), ZoneVector<LiveRange*>(zone), zone), @@ -1233,8 +1211,6 @@ RegisterAllocationData::RegisterAllocationData( fixed_fp_register_use_ = code_zone()->New<BitVector>( this->config()->num_double_registers(), code_zone()); if (kFPAliasing == AliasingKind::kIndependent) { - assigned_simd128_registers_ = code_zone()->New<BitVector>( - this->config()->num_simd128_registers(), code_zone()); fixed_simd128_register_use_ = code_zone()->New<BitVector>( this->config()->num_simd128_registers(), code_zone()); } @@ -1260,7 +1236,7 @@ MachineRepresentation RegisterAllocationData::RepresentationFor( TopLevelLiveRange* RegisterAllocationData::GetLiveRangeFor(int index) { TopLevelLiveRange* result = live_ranges()[index]; DCHECK_NOT_NULL(result); - DCHECK_EQ(live_ranges()[index]->vreg(), index); + DCHECK_EQ(result->vreg(), index); return result; } @@ -1302,8 +1278,8 @@ bool RegisterAllocationData::ExistsUseWithoutDefinition() { operand_index); LiveRange* range = GetLiveRangeFor(operand_index); PrintF(" (first use is at position %d in instruction %d)\n", - range->positions().first()->pos().value(), - range->positions().first()->pos().ToInstructionIndex()); + range->positions().front()->pos().value(), + range->positions().front()->pos().ToInstructionIndex()); if (debug_name() == nullptr) { PrintF("\n"); } else { @@ -1451,8 +1427,6 @@ void RegisterAllocationData::MarkAllocated(MachineRepresentation rep, if (rep == MachineRepresentation::kFloat16 || rep == MachineRepresentation::kFloat32) { assigned_double_registers_->Add(index); - } else { - assigned_simd128_registers_->Add(index); } } else { int alias_base_index = -1; @@ -1486,9 +1460,9 @@ bool RegisterAllocationData::IsBlockBoundary(LifetimePosition pos) const { ConstraintBuilder::ConstraintBuilder(RegisterAllocationData* data) : data_(data) {} -InstructionOperand* ConstraintBuilder::AllocateFixed( - UnallocatedOperand* operand, int pos, bool is_tagged, bool is_input, - bool is_output) { +void ConstraintBuilder::AllocateFixed(UnallocatedOperand* operand, int pos, + bool is_tagged, bool is_input, + bool is_output) { TRACE("Allocating fixed reg for op %d\n", operand->virtual_register()); DCHECK(operand->HasFixedPolicy()); InstructionOperand allocated; @@ -1498,6 +1472,19 @@ InstructionOperand* ConstraintBuilder::AllocateFixed( rep = data()->RepresentationFor(virtual_register); } if (operand->HasFixedSlotPolicy()) { +#ifdef V8_TARGET_ARCH_X64 + // A fixed slot is only ever used for ABI-visible locations (e.g. a wasm + // return value spilled to its caller frame slot), and Simd256 is never + // an ABI-visible type. So a Simd256 representation here can only come + // from an ExtractF128 node with lane 0 that got elided and aliased to + // its Simd256 input (see VisitExtractF128 on x64). Narrow it back to + // Simd128 so the move only writes the low 128 bits into the fixed slot, + // instead of overwriting the adjacent stack slot with the upper 128 + // bits of the aliased Simd256 value. + if (rep == MachineRepresentation::kSimd256) { + rep = MachineRepresentation::kSimd128; + } +#endif allocated = AllocatedOperand(AllocatedOperand::STACK_SLOT, rep, operand->fixed_slot_index()); } else if (operand->HasFixedRegisterPolicy()) { @@ -1550,7 +1537,6 @@ InstructionOperand* ConstraintBuilder::AllocateFixed( instr->reference_map()->RecordReference(*AllocatedOperand::cast(operand)); } } - return operand; } void ConstraintBuilder::MeetRegisterConstraints() { @@ -2209,9 +2195,8 @@ void LiveRangeBuilder::ProcessInstructions(const InstructionBlock* block, if (to_range->is_phi()) { phi_vreg = to_vreg; if (to_range->is_non_loop_phi()) { - hint = to_range->current_hint_position(); - hint_type = hint == nullptr ? UsePositionHintType::kNone - : UsePositionHintType::kUsePos; + hint = nullptr; + hint_type = UsePositionHintType::kNone; } else { hint_type = UsePositionHintType::kPhi; hint = data()->GetPhiMapValueFor(to_vreg); @@ -2454,10 +2439,9 @@ void LiveRangeBuilder::BuildLiveRanges() { if (!pos->pos().IsGapPosition()) { new_type = UsePositionType::kRequiresRegister; } - pos->set_type(new_type, true); + pos->set_register_beneficial(new_type); } } - range->ResetCurrentHintPosition(); } for (auto preassigned : data()->preassigned_slot_ranges()) { TopLevelLiveRange* range = preassigned.first; @@ -2738,9 +2722,8 @@ RegisterAllocator::RegisterAllocator(RegisterAllocationData* data, LifetimePosition RegisterAllocator::GetSplitPositionForInstruction( const LiveRange* range, int instruction_index) { - LifetimePosition ret = LifetimePosition::Invalid(); - - ret = LifetimePosition::GapFromInstructionIndex(instruction_index); + LifetimePosition ret = + LifetimePosition::GapFromInstructionIndex(instruction_index); if (range->Start() >= ret || ret >= range->End()) { return LifetimePosition::Invalid(); } @@ -2995,7 +2978,7 @@ void LinearScanAllocator::MaybeSpillPreviousRanges(LiveRange* begin_range, } } -void LinearScanAllocator::MaybeUndoPreviousSplit(LiveRange* range, Zone* zone) { +void LinearScanAllocator::MaybeUndoPreviousSplit(LiveRange* range) { if (range->next() != nullptr && range->next()->ShouldRecombine()) { LiveRange* to_remove = range->next(); TRACE("Recombining %d:%d with %d\n", range->TopLevel()->vreg(), @@ -3007,7 +2990,7 @@ void LinearScanAllocator::MaybeUndoPreviousSplit(LiveRange* range, Zone* zone) { DCHECK_EQ(removed_cnt, 1); USE(removed_cnt); - range->AttachToNext(zone); + range->AttachToNext(allocation_zone()); } else if (range->next() != nullptr) { TRACE("No recombine for %d:%d to %d\n", range->TopLevel()->vreg(), range->relative_id(), range->next()->relative_id()); @@ -3038,7 +3021,7 @@ void LinearScanAllocator::SpillNotLiveRanges(RangeRegisterSmallMap& to_be_live, // When spilling a previously spilled/reloaded range, we add back the // tail that we might have split off when we reloaded/spilled it // previously. Otherwise we might keep generating small split-offs. - MaybeUndoPreviousSplit(active_range, allocation_zone()); + MaybeUndoPreviousSplit(active_range); TRACE("Putting back %d:%d\n", toplevel->vreg(), active_range->relative_id()); LiveRange* split = SplitRangeAt(active_range, position); @@ -3168,7 +3151,7 @@ void LinearScanAllocator::ReloadLiveRanges( // in the middle of blocks. // If there is a gap between this range and the next, we can just keep // it as a register change won't hurt. - MaybeUndoPreviousSplit(to_resurrect, allocation_zone()); + MaybeUndoPreviousSplit(to_resurrect); if (to_resurrect->Start() == position) { // This range already starts at this block. It might have been spilled, // so we have to unspill it. Otherwise, it is already in the unhandled @@ -3568,20 +3551,6 @@ void LinearScanAllocator::UpdateDeferredFixedRanges(SpillMode spill_mode, } } -bool LinearScanAllocator::BlockIsDeferredOrImmediatePredecessorIsNotDeferred( - const InstructionBlock* block) { - if (block->IsDeferred()) return true; - if (block->PredecessorCount() == 0) return true; - bool pred_is_deferred = false; - for (auto pred : block->predecessors()) { - if (pred.IsNext(block->rpo_number())) { - pred_is_deferred = code()->InstructionBlockAt(pred)->IsDeferred(); - break; - } - } - return !pred_is_deferred; -} - bool LinearScanAllocator::HasNonDeferredPredecessor(InstructionBlock* block) { for (auto pred : block->predecessors()) { InstructionBlock* pred_block = code()->InstructionBlockAt(pred); @@ -4146,7 +4115,7 @@ void LinearScanAllocator::FindFreeRegistersForRange( // which are expensive. void LinearScanAllocator::ProcessCurrentRange(LiveRange* current, SpillMode spill_mode) { - base::EmbeddedVector<LifetimePosition, RegisterConfiguration::kMaxRegisters> + std::array<LifetimePosition, RegisterConfiguration::kMaxRegisters> free_until_pos; FindFreeRegistersForRange(current, free_until_pos); if (!TryAllocatePreferredReg(current, free_until_pos)) { @@ -4295,10 +4264,10 @@ void LinearScanAllocator::AllocateBlockedReg(LiveRange* current, // use_pos keeps track of positions a register/alias is used at. // block_pos keeps track of positions where a register/alias is blocked // from. - base::EmbeddedVector<LifetimePosition, RegisterConfiguration::kMaxRegisters> - use_pos(LifetimePosition::MaxPosition()); - base::EmbeddedVector<LifetimePosition, RegisterConfiguration::kMaxRegisters> - block_pos(LifetimePosition::MaxPosition()); + std::array<LifetimePosition, RegisterConfiguration::kMaxRegisters> use_pos; + use_pos.fill(LifetimePosition::MaxPosition()); + std::array<LifetimePosition, RegisterConfiguration::kMaxRegisters> block_pos; + block_pos.fill(LifetimePosition::MaxPosition()); for (LiveRange* range : active_live_ranges()) { int cur_reg = range->assigned_register(); @@ -4653,7 +4622,7 @@ void OperandAssigner::DecideSpillingMode() { for (auto range : data()->live_ranges()) { data()->tick_counter()->TickAndMaybeEnterSafepoint(); DCHECK_NOT_NULL(range); - if (range->IsSpilledOnlyInDeferredBlocks(data())) { + if (range->IsSpilledOnlyInDeferredBlocks()) { // If the range is spilled only in deferred blocks and starts in // a non-deferred block, we transition its representation here so // that the LiveRangeConnector processes them correctly. If, @@ -4788,7 +4757,7 @@ void OperandAssigner::CommitAssignment() { // blocks, we let ConnectLiveRanges and ResolveControlFlow find the blocks // where a spill operand is expected, and then finalize by inserting the // spills in the deferred blocks dominators. - if (!top_range->IsSpilledOnlyInDeferredBlocks(data()) && + if (!top_range->IsSpilledOnlyInDeferredBlocks() && !top_range->HasGeneralSpillRange()) { // Spill at definition if the range isn't spilled in a way that will be // handled later. @@ -4918,7 +4887,7 @@ void ReferenceMapPopulator::PopulateReferenceMaps() { // Check if the live range is spilled and the safe point is after // the spill position. - int spill_index = range->IsSpilledOnlyInDeferredBlocks(data()) || + int spill_index = range->IsSpilledOnlyInDeferredBlocks() || range->LateSpillingSelected() ? cur->Start().ToInstructionIndex() : range->spill_start_index(); @@ -5020,22 +4989,21 @@ void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) { } if (!uses_reg) continue; } - if (cur_range->TopLevel()->IsSpilledOnlyInDeferredBlocks(data()) && + if (cur_range->TopLevel()->IsSpilledOnlyInDeferredBlocks() && pred_block->IsDeferred()) { // The spill location should be defined in pred_block, so add // pred_block to the list of blocks requiring a spill operand. TRACE("Adding B%d to list of spill blocks for %d\n", pred_block->rpo_number().ToInt(), cur_range->TopLevel()->vreg()); - cur_range->TopLevel() - ->GetListOfBlocksRequiringSpillOperands(data()) - ->Add(pred_block->rpo_number().ToInt()); + cur_range->TopLevel()->GetListOfBlocksRequiringSpillOperands()->Add( + pred_block->rpo_number().ToInt()); } } int move_loc = ResolveControlFlow(block, cur_op, pred_block, pred_op); USE(move_loc); DCHECK_IMPLIES( - cur_range->TopLevel()->IsSpilledOnlyInDeferredBlocks(data()) && + cur_range->TopLevel()->IsSpilledOnlyInDeferredBlocks() && !(pred_op.IsAnyRegister() && cur_op.IsAnyRegister()) && move_loc != -1, code()->GetInstructionBlock(move_loc)->IsDeferred()); @@ -5046,7 +5014,7 @@ void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) { // At this stage, we collected blocks needing a spill operand due to reloads // from ConnectRanges and from ResolveControlFlow. Time to commit the spills // for deferred blocks. This is a convenient time to commit spills for general - // spill ranges also, because they need to use the LiveRangeFinder. + // spill ranges also. const size_t live_ranges_size = data()->live_ranges().size(); SpillPlacer spill_placer(data(), local_zone); for (TopLevelLiveRange* top : data()->live_ranges()) { @@ -5054,7 +5022,7 @@ void LiveRangeConnector::ResolveControlFlow(Zone* local_zone) { data()->live_ranges().size()); // TODO(neis): crbug.com/831822 DCHECK_NOT_NULL(top); if (top->IsEmpty()) continue; - if (top->IsSpilledOnlyInDeferredBlocks(data())) { + if (top->IsSpilledOnlyInDeferredBlocks()) { CommitSpillsInDeferredBlocks(top, local_zone); } else if (top->HasGeneralSpillRange()) { spill_placer.Add(top); @@ -5103,7 +5071,7 @@ void LiveRangeConnector::ConnectRanges(Zone* local_zone) { CHECK_EQ(live_ranges_size, data()->live_ranges().size()); // TODO(neis): crbug.com/831822 DCHECK_NOT_NULL(top_range); - bool connect_spilled = top_range->IsSpilledOnlyInDeferredBlocks(data()); + bool connect_spilled = top_range->IsSpilledOnlyInDeferredBlocks(); LiveRange* first_range = top_range; for (LiveRange *second_range = first_range->next(); second_range != nullptr; first_range = second_range, second_range = second_range->next()) { @@ -5128,7 +5096,7 @@ void LiveRangeConnector::ConnectRanges(Zone* local_zone) { DCHECK(block->IsDeferred()); // Performing a reload in this block, meaning the spill operand must // be defined here. - top_range->GetListOfBlocksRequiringSpillOperands(data())->Add( + top_range->GetListOfBlocksRequiringSpillOperands()->Add( block->rpo_number().ToInt()); } @@ -5192,7 +5160,7 @@ void LiveRangeConnector::ConnectRanges(Zone* local_zone) { void LiveRangeConnector::CommitSpillsInDeferredBlocks(TopLevelLiveRange* range, Zone* temp_zone) { - DCHECK(range->IsSpilledOnlyInDeferredBlocks(data())); + DCHECK(range->IsSpilledOnlyInDeferredBlocks()); DCHECK(!range->spilled()); InstructionSequence* code = data()->code(); @@ -5210,14 +5178,13 @@ void LiveRangeConnector::CommitSpillsInDeferredBlocks(TopLevelLiveRange* range, } range->AddBlockRequiringSpillOperand( code->GetInstructionBlock(pos->pos().ToInstructionIndex()) - ->rpo_number(), - data()); + ->rpo_number()); } } ZoneQueue<int> worklist(temp_zone); - for (int block_id : *range->GetListOfBlocksRequiringSpillOperands(data())) { + for (int block_id : *range->GetListOfBlocksRequiringSpillOperands()) { worklist.push(block_id); } diff --git a/deps/v8/src/compiler/backend/register-allocator.h b/deps/v8/src/compiler/backend/register-allocator.h index f97e57ed03fc..0dba7685fbfb 100644 --- a/deps/v8/src/compiler/backend/register-allocator.h +++ b/deps/v8/src/compiler/backend/register-allocator.h @@ -219,7 +219,6 @@ class RegisterAllocationData final : public ZoneObject { DCHECK_EQ(assigned_register_, kUnassignedRegister); assigned_register_ = register_code; } - void UnsetAssignedRegister() { assigned_register_ = kUnassignedRegister; } void AddOperand(InstructionOperand* operand); void CommitAssignment(const InstructionOperand& operand); @@ -295,7 +294,6 @@ class RegisterAllocationData final : public ZoneObject { SpillRange* AssignSpillRangeToLiveRange(TopLevelLiveRange* range, SpillMode spill_mode); - SpillRange* CreateSpillRangeForLiveRange(TopLevelLiveRange* range); MoveOperands* AddGapMove(int index, Instruction::GapPosition position, const InstructionOperand& from, @@ -358,11 +356,9 @@ class RegisterAllocationData final : public ZoneObject { DelayedReferences delayed_references_; BitVector* assigned_registers_; BitVector* assigned_double_registers_; - BitVector* assigned_simd128_registers_; BitVector* fixed_register_use_; BitVector* fixed_fp_register_use_; BitVector* fixed_simd128_register_use_; - int virtual_register_count_; RangesWithPreassignedSlots preassigned_slot_ranges_; ZoneVector<ZoneVector<LiveRange*>> spill_state_; TickCounter* const tick_counter_; @@ -482,7 +478,12 @@ class V8_EXPORT_PRIVATE UsePosition final } UsePositionType type() const { return TypeField::decode(flags_); } - void set_type(UsePositionType type, bool register_beneficial); + void set_register_beneficial(UsePositionType type) { + DCHECK_NE(type, UsePositionType::kRequiresSlot); + DCHECK_EQ(kUnassignedRegister, AssignedRegisterField::decode(flags_)); + flags_ = + TypeField::update(RegisterBeneficialField::update(flags_, true), type); + } LifetimePosition pos() const { return pos_; } @@ -499,7 +500,6 @@ class V8_EXPORT_PRIVATE UsePosition final } bool HasHint() const; bool HintRegister(int* register_code) const; - void SetHint(UsePosition* use_pos); void ResolveHint(UsePosition* use_pos); bool IsResolved() const { return hint_type() != UsePositionHintType::kUnresolved; @@ -517,7 +517,7 @@ class V8_EXPORT_PRIVATE UsePosition final using HintTypeField = base::BitField<UsePositionHintType, 2, 3>; using RegisterBeneficialField = base::BitField<bool, 5, 1>; using AssignedRegisterField = base::BitField<int32_t, 6, 6>; - using SpillDetrimentalField = base::BitField<int32_t, 12, 1>; + using SpillDetrimentalField = base::BitField<bool, 12, 1>; InstructionOperand* const operand_; void* hint_; @@ -525,8 +525,6 @@ class V8_EXPORT_PRIVATE UsePosition final uint32_t flags_; }; -class SpillRange; -class TopLevelLiveRange; class LiveRangeBundle; enum GrowthDirection { kFront, kFrontOrBack }; @@ -555,9 +553,8 @@ class DoubleEndedSplitVector { bool empty() const { return size() == 0; } size_t capacity() const { return storage_end_ - storage_begin_; } - T* data() const { return data_begin_; } - - void clear() { data_begin_ = data_end_; } + T* data() { return data_begin_; } + const T* data() const { return data_begin_; } T& operator[](size_t position) { DCHECK_LT(position, size()); @@ -820,7 +817,6 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) { return assigned_register() != kUnassignedRegister; } void set_assigned_register(int reg); - void UnsetAssignedRegister(); bool ShouldRecombine() const { return RecombineField::decode(bits_); } @@ -880,13 +876,9 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) { LiveRange* SplitAt(LifetimePosition position, Zone* zone); // Returns false when no register is hinted, otherwise sets register_index. - // Uses {current_hint_position_} as a cache, and tries to update it. + // Uses {current_hint_position_index_} as a cache, and tries to update it. bool RegisterFromFirstHint(int* register_index); - UsePosition* current_hint_position() const { - return positions_span_[current_hint_position_index_]; - } - LifetimePosition Start() const { DCHECK(!IsEmpty()); DCHECK_EQ(start_, intervals_.front().start()); @@ -917,8 +909,6 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) { void ConvertUsesToOperand(const InstructionOperand& op, const InstructionOperand& spill_op); void SetUseHints(int register_index); - void UnsetUseHints() { SetUseHints(kUnassignedRegister); } - void ResetCurrentHintPosition() { current_hint_position_index_ = 0; } void Print(const RegisterConfiguration* config, bool with_children) const; void Print(bool with_children) const; @@ -984,7 +974,7 @@ class V8_EXPORT_PRIVATE LiveRange : public NON_EXPORTED_BASE(ZoneObject) { // This is used as a cache in `FirstSearchIntervalForPosition`. UseIntervalVector::iterator current_interval_; - // This is used as a cache in `BuildLiveRanges` and during register + // This is used as a cache in `RegisterFromFirstHint` during register // allocation. size_t current_hint_position_index_ = 0; @@ -1077,9 +1067,6 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { return slot_use_kind() == SlotUseKind::kGeneralSlotUse; } - void reset_slot_use() { - bits_ = HasSlotUseField::update(bits_, SlotUseKind::kNoSlotUse); - } void register_slot_use(SlotUseKind value) { bits_ = HasSlotUseField::update(bits_, std::max(slot_use_kind(), value)); } @@ -1160,20 +1147,6 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { void CommitSpillMoves(RegisterAllocationData* data, const InstructionOperand& operand); - // If all the children of this range are spilled in deferred blocks, and if - // for any non-spilled child with a use position requiring a slot, that range - // is contained in a deferred block, mark the range as - // IsSpilledOnlyInDeferredBlocks, so that we avoid spilling at definition, - // and instead let the LiveRangeConnector perform the spills within the - // deferred blocks. If so, we insert here spills for non-spilled ranges - // with slot use positions. - void TreatAsSpilledInDeferredBlock(Zone* zone) { - spill_start_index_ = -1; - spilled_in_deferred_blocks_ = true; - spill_move_insertion_locations_ = nullptr; - list_of_blocks_requiring_spill_operands_ = zone->New<SparseBitVector>(zone); - } - // Updates internal data structures to reflect that this range is not // spilled at definition but instead spilled in some blocks only. void TransitionRangeToDeferredSpill(Zone* zone) { @@ -1191,10 +1164,6 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { } } - bool MayRequireSpillRange() const { - return !HasSpillOperand() && spill_range_ == nullptr; - } - void UpdateSpillRangePostMerge(TopLevelLiveRange* merged); int vreg() const { return vreg_; } #ifdef DEBUG @@ -1210,20 +1179,23 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { int GetNextChildId() { return ++last_child_id_; } - bool IsSpilledOnlyInDeferredBlocks(const RegisterAllocationData* data) const { + bool IsSpilledOnlyInDeferredBlocks() const { return spill_type() == SpillType::kDeferredSpillRange; } struct SpillMoveInsertionList; - SpillMoveInsertionList* GetSpillMoveInsertionLocations( - const RegisterAllocationData* data) const { - DCHECK(!IsSpilledOnlyInDeferredBlocks(data)); + SpillMoveInsertionList* GetSpillMoveInsertionLocations() const { + DCHECK(!IsSpilledOnlyInDeferredBlocks()); return spill_move_insertion_locations_; } - void MarkHasPreassignedSlot() { has_preassigned_slot_ = true; } - bool has_preassigned_slot() const { return has_preassigned_slot_; } + void MarkHasPreassignedSlot() { + bits_ = HasPreassignedSlotField::update(bits_, true); + } + bool has_preassigned_slot() const { + return HasPreassignedSlotField::decode(bits_); + } // Late spilling refers to spilling at places after the definition. These // spills are guaranteed to cover at least all of the sub-ranges where the @@ -1245,15 +1217,13 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { return SpillRangeModeField::decode(bits_) == SpillRangeMode::kSpillLater; } - void AddBlockRequiringSpillOperand(RpoNumber block_id, - const RegisterAllocationData* data) { - DCHECK(IsSpilledOnlyInDeferredBlocks(data)); - GetListOfBlocksRequiringSpillOperands(data)->Add(block_id.ToInt()); + void AddBlockRequiringSpillOperand(RpoNumber block_id) { + DCHECK(IsSpilledOnlyInDeferredBlocks()); + GetListOfBlocksRequiringSpillOperands()->Add(block_id.ToInt()); } - SparseBitVector* GetListOfBlocksRequiringSpillOperands( - const RegisterAllocationData* data) const { - DCHECK(IsSpilledOnlyInDeferredBlocks(data)); + SparseBitVector* GetListOfBlocksRequiringSpillOperands() const { + DCHECK(IsSpilledOnlyInDeferredBlocks()); return list_of_blocks_requiring_spill_operands_; } @@ -1279,9 +1249,11 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { using SpillAtLoopHeaderNotBeneficialField = DeferredFixedField::Next<bool, 1>; using SpillRangeModeField = SpillAtLoopHeaderNotBeneficialField::Next<SpillRangeMode, 2>; + using HasPreassignedSlotField = SpillRangeModeField::Next<bool, 1>; int vreg_; int last_child_id_; + int spill_start_index_; union { // Correct value determined by spill_type() InstructionOperand* spill_operand_; @@ -1300,13 +1272,6 @@ class V8_EXPORT_PRIVATE TopLevelLiveRange final : public LiveRange { // This is a cache for the binary search in `GetChildCovers`. // The `LiveRange`s are sorted by their `Start()` position. ZoneVector<LiveRange*> children_; - - // TODO(mtrofin): generalize spilling after definition, currently specialized - // just for spill in a single deferred block. - bool spilled_in_deferred_blocks_; - bool has_preassigned_slot_; - - int spill_start_index_; }; struct PrintableLiveRange { @@ -1378,9 +1343,8 @@ class ConstraintBuilder final : public ZoneObject { InstructionSequence* code() const { return data()->code(); } Zone* allocation_zone() const { return data()->allocation_zone(); } - InstructionOperand* AllocateFixed(UnallocatedOperand* operand, int pos, - bool is_tagged, bool is_input, - bool is_output); + void AllocateFixed(UnallocatedOperand* operand, int pos, bool is_tagged, + bool is_input, bool is_output); void MeetRegisterConstraints(const InstructionBlock* block); void MeetConstraintsBefore(int index); void MeetConstraintsAfter(int index); @@ -1548,7 +1512,6 @@ class RegisterAllocator : public ZoneObject { SpillMode spill_mode, LiveRange** begin_spill_out); - const ZoneVector<TopLevelLiveRange*>& GetFixedRegisters() const; const char* RegisterName(int allocation_index, RegisterKind kind) const; const char* RegisterName(int allocation_index, MachineRepresentation rep) const; @@ -1560,9 +1523,6 @@ class RegisterAllocator : public ZoneObject { int num_allocatable_registers_; const int* allocatable_register_codes_; bool check_fp_aliasing_; - - private: - bool no_combining_; }; // A map from `TopLevelLiveRange`s to their expected physical register. @@ -1586,7 +1546,7 @@ class LinearScanAllocator final : public RegisterAllocator { void MaybeSpillPreviousRanges(LiveRange* begin_range, LifetimePosition begin_pos, LiveRange* end_range); - void MaybeUndoPreviousSplit(LiveRange* range, Zone* zone); + void MaybeUndoPreviousSplit(LiveRange* range); void SpillNotLiveRanges(RangeRegisterSmallMap& to_be_live, LifetimePosition position, SpillMode spill_mode); LiveRange* AssignRegisterOnReload(LiveRange* range, int reg); @@ -1594,8 +1554,6 @@ class LinearScanAllocator final : public RegisterAllocator { LifetimePosition position); void UpdateDeferredFixedRanges(SpillMode spill_mode, InstructionBlock* block); - bool BlockIsDeferredOrImmediatePredecessorIsNotDeferred( - const InstructionBlock* block); bool HasNonDeferredPredecessor(InstructionBlock* block); struct UnhandledLiveRangeOrdering { @@ -1764,7 +1722,6 @@ class ReferenceMapPopulator final : public ZoneObject { RegisterAllocationData* const data_; }; -class LiveRangeBoundArray; // Insert moves of the form // // Operand(child_(k+1)) = Operand(child_k) diff --git a/deps/v8/src/compiler/backend/riscv/code-generator-riscv.cc b/deps/v8/src/compiler/backend/riscv/code-generator-riscv.cc index fb1c0f6e1c27..fe67f1d22a73 100644 --- a/deps/v8/src/compiler/backend/riscv/code-generator-riscv.cc +++ b/deps/v8/src/compiler/backend/riscv/code-generator-riscv.cc @@ -215,7 +215,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { OutOfLineRecordWrite( CodeGenerator* gen, Register object, Operand offset, Register value, RecordWriteMode mode, StubCallMode stub_mode, - IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag) + TrustedPointerTag trusted_pointer_tag = kTrustedPointerNullTag) : OutOfLineCode(gen), object_(object), offset_(offset), @@ -226,7 +226,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { #endif // V8_ENABLE_WEBASSEMBLY must_save_ra_(!gen->frame_access_state()->has_frame()), zone_(gen->zone()), - indirect_pointer_tag_(indirect_pointer_tag) { + trusted_pointer_tag_(trusted_pointer_tag) { } void Generate() final { @@ -234,7 +234,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { // When storing an indirect pointer, the value will always be a // full/decompressed pointer. if (COMPRESS_POINTERS_BOOL && - mode_ != RecordWriteMode::kValueIsIndirectPointer) { + mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ DecompressTagged(value_, value_); } #endif @@ -253,10 +253,10 @@ class OutOfLineRecordWrite final : public OutOfLineCode { } if (mode_ == RecordWriteMode::kValueIsEphemeronKey) { __ CallEphemeronKeyBarrier(object_, offset_, save_fp_mode); - } else if (mode_ == RecordWriteMode::kValueIsIndirectPointer) { - DCHECK(IsValidIndirectPointerTag(indirect_pointer_tag_)); - __ CallIndirectPointerBarrier(object_, offset_, save_fp_mode, - indirect_pointer_tag_); + } else if (mode_ == RecordWriteMode::kValueIsTrustedPointer) { + DCHECK(IsValidTrustedPointerTag(trusted_pointer_tag_)); + __ CallTrustedPointerBarrier(object_, offset_, save_fp_mode, + trusted_pointer_tag_); #if V8_ENABLE_WEBASSEMBLY } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) { // A direct call to a wasm runtime stub defined in this module. @@ -286,7 +286,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { #endif // V8_ENABLE_WEBASSEMBLY const bool must_save_ra_; Zone* zone_; - IndirectPointerTag indirect_pointer_tag_; + TrustedPointerTag trusted_pointer_tag_; }; class OutOfLineVerifySkippedWriteBarrier final : public OutOfLineCode { @@ -1063,8 +1063,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kArchCallJSFunction: { - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -1074,7 +1074,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Builtin builtin = function->shared()->builtin_id(); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (Builtins::IsCompatibleJSBuiltin(builtin, num_arguments)) { + if (Builtins::IsCompatibleJSBuiltin(builtin, + expected_parameter_count)) { __ CallBuiltin(builtin); } else { __ Abort(AbortReason::kJSSignatureMismatch); @@ -1085,7 +1086,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( dispatch_handle); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -1093,7 +1094,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputOrZeroRegister(0); @@ -1105,7 +1107,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ Assert(eq, AbortReason::kWrongFunctionContext, cp, Operand(kScratchReg)); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } RecordCallPosition(instr); frame_access_state()->ClearSPDelta(); @@ -1300,7 +1302,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kArchStoreWithWriteBarrier: { RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); Register object = i.InputRegister(0); Operand offset = i.InputOperand(1); Register value = i.InputRegister(2); @@ -1308,7 +1310,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( auto ool = zone()->New<OutOfLineRecordWrite>( this, object, offset, value, mode, DetermineStubCallMode()); __ StoreTaggedField(value, MemOperand(kScratchReg, 0), trapper); - if (mode > RecordWriteMode::kValueIsIndirectPointer) { + if (mode > RecordWriteMode::kValueIsTrustedPointer) { __ JumpIfSmi(value, ool->exit()); } __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask, @@ -1348,7 +1350,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( MacroAssembler::BlockPoolsScope block_pools(masm()); RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); Register object = i.InputRegister(0); Operand offset = i.InputOperand(1); Register value = i.InputRegister(2); @@ -1361,7 +1363,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( // valid if the value isn't an indirect pointer. Otherwise the value will // be a pointer table index, which will always look like a Smi (but // actually reference a pointer in the pointer table). - if (mode > RecordWriteMode::kValueIsIndirectPointer) { + if (mode > RecordWriteMode::kValueIsTrustedPointer) { __ JumpIfSmi(value, ool->exit()); } __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask, @@ -1393,19 +1395,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( UNREACHABLE(); #endif } - case kArchStoreIndirectWithWriteBarrier: { + case kArchStoreTrustedWithWriteBarrier: { #ifdef V8_TARGET_ARCH_RISCV64 RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); - DCHECK_EQ(mode, RecordWriteMode::kValueIsIndirectPointer); - IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3)); - DCHECK(IsValidIndirectPointerTag(tag)); + DCHECK_EQ(mode, RecordWriteMode::kValueIsTrustedPointer); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(i.InputInt64(3)); + DCHECK(IsValidTrustedPointerTag(tag)); Register object = i.InputRegister(0); Operand offset = i.InputOperand(1); Register value = i.InputRegister(2); __ AddWord(kScratchReg, object, offset); auto ool = zone()->New<OutOfLineRecordWrite>( this, object, offset, value, mode, DetermineStubCallMode(), tag); - __ StoreIndirectPointerField(value, MemOperand(kScratchReg, 0), trapper); + __ StoreTrustedPointerField(value, MemOperand(kScratchReg, 0), trapper); __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask, ne, ool->entry()); __ bind(ool->exit()); @@ -1414,19 +1416,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( UNREACHABLE(); #endif } - case kArchStoreIndirectSkippedWriteBarrier: { + case kArchStoreTrustedSkippedWriteBarrier: { #ifdef V8_TARGET_ARCH_RISCV64 Register object = i.InputRegister(0); Operand offset = i.InputOperand(1); Register value = i.InputRegister(2); #if DEBUG - IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(i.InputInt64(3)); + DCHECK(IsValidTrustedPointerTag(tag)); #endif // DEBUG __ AddWord(kScratchReg, object, offset); - __ StoreIndirectPointerField(value, MemOperand(kScratchReg, 0), trapper); + __ StoreTrustedPointerField(value, MemOperand(kScratchReg, 0), trapper); break; #else UNREACHABLE(); @@ -2827,9 +2829,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ StoreSandboxedPointerField(i.InputOrZeroRegister(0), mem, trapper); break; } - case kRiscvStoreIndirectPointer: { + case kRiscvStoreTrustedPointer: { MemOperand mem = i.MemoryOperand(1); - __ StoreIndirectPointerField(i.InputOrZeroRegister(0), mem, trapper); + __ StoreTrustedPointerField(i.InputOrZeroRegister(0), mem, trapper); break; } case kRiscvAtomicLoadDecompressTaggedSigned: { @@ -2856,11 +2858,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register base = i.InputRegister(0); int32_t offset = i.InputInt32(1); Register table = i.InputRegister(2); - IndirectPointerTag first = - static_cast<IndirectPointerTag>(i.InputInt32(3)); - IndirectPointerTag last = - static_cast<IndirectPointerTag>(i.InputInt32(4)); - IndirectPointerTagRange tag_range(first, last); + TrustedPointerTag first = static_cast<TrustedPointerTag>(i.InputInt32(3)); + TrustedPointerTag last = static_cast<TrustedPointerTag>(i.InputInt32(4)); + TrustedPointerTagRange tag_range(first, last); Register destination = i.OutputRegister(); Register handle = i.TempRegister(0); RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); @@ -2869,9 +2869,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ CalcScaledAddress(destination, table, handle, kTrustedPointerTableEntrySizeLog2); __ LoadWord(destination, MemOperand(destination, 0)); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = - ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); __ And(destination, destination, Operand(mask)); } else { Register tag = handle; // Reuse handle for tag @@ -2928,6 +2927,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kRiscvS128Load32Zero: { Simd128Register dst = i.OutputSimd128Register(); __ VU.SetSimd128(E32, tu); + // vmv.s.x only writes element 0, so zero the register first to make sure + // the upper lanes are zero as required by the Wasm spec. + __ vxor_vv(dst, dst, dst); __ Load32U(kScratchReg, i.MemoryOperand(), trapper); __ vmv_sx(dst, kScratchReg); break; @@ -2935,6 +2937,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kRiscvS128Load64Zero: { Simd128Register dst = i.OutputSimd128Register(); __ VU.SetSimd128(E64, tu); + // vmv.s.x only writes element 0, so zero the register first to make sure + // the upper lanes are zero as required by the Wasm spec. + __ vxor_vv(dst, dst, dst); #if V8_TARGET_ARCH_RISCV64 __ LoadWord(kScratchReg, i.MemoryOperand(), trapper); __ vmv_sx(dst, kScratchReg); @@ -5362,11 +5367,11 @@ void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) { for (size_t index = 2; index < instr->InputCount(); index += 2) { cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))}); } -#ifdef V8_COMPRESS_POINTERS // AssembleArchBinarySearchSwitchRange use JumpIfEqual and JumpIfLessThan to // compare the input value with the case values. - // In V8_COMPRESS_POINTERS, the compare is done with the lower 32 bits of the - // input, requiring a sign extension. + // The compare is performed on the full 64-bit registers, but the switch + // input is a 32-bit value whose upper 32 bits are not guaranteed to be + // sign-extended, so a sign extension is required. // Since the input value remains unchanged throughout // AssembleArchBinarySearchSwitch, we perform the sign extension once here, // rather than repeatedly in JumpIfEqual and JumpIfLessThan. This reduces the @@ -5374,7 +5379,6 @@ void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) { UseScratchRegisterScope temps(masm()); scratch = temps.Acquire(); __ SignExtendWord(scratch, input); -#endif AssembleArchBinarySearchSwitchRange(scratch, i.InputRpo(1), cases.data(), cases.data() + cases.size()); } @@ -5410,30 +5414,29 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ StubPrologue(StackFrame::C_WASM_ENTRY); - // Reserve stack space for saving the c_entry_fp later. - __ SubWord(sp, sp, Operand(kSystemPointerSize)); - } else { - __ PushCommonFrame(Register::no_reg()); - } - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); + if (call_descriptor->IsCFunctionCall()) { + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ StubPrologue(StackFrame::C_WASM_ENTRY); + // Reserve stack space for saving the c_entry_fp later. + __ SubWord(sp, sp, Operand(kSystemPointerSize)); } else { - __ StubPrologue(info()->GetOutputStackFrameType()); - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - __ Push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ SubWord(sp, sp, Operand(kSystemPointerSize)); - } + __ PushCommonFrame(Register::no_reg()); + } + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + __ StubPrologue(info()->GetOutputStackFrameType()); + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + __ Push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ SubWord(sp, sp, Operand(kSystemPointerSize)); } } @@ -5466,74 +5469,90 @@ void CodeGenerator::AssembleConstructFrame() { const RegList saves = call_descriptor->CalleeSavedRegisters(); const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters(); - if (required_slots > 0) { - DCHECK(frame_access_state()->has_frame()); #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < (v8_flags.stack_size * KB)) { - UseScratchRegisterScope temps(masm()); - Register stack_limit = temps.Acquire(); - __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); - __ AddWord(stack_limit, stack_limit, Operand(stack_space)); - __ Branch(&done, uge, sp, Operand(stack_limit)); + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + UseScratchRegisterScope temps(masm()); + Register stack_limit = temps.Acquire(); + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + if (stack_space > 0) { + __ AddWord(stack_limit, stack_limit, + Operand(static_cast<int32_t>(stack_space))); } - - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - __ MultiPushFPU(fp_regs_to_save); - Simd128RegList simd128_regs_to_save; - for (auto reg : wasm::kSimd128ParamRegisters) - simd128_regs_to_save.set(reg); - __ SaveVectorRegisters(simd128_regs_to_save); - __ li(WasmHandleStackOverflowDescriptor::GapRegister(), stack_space); - __ AddWord( - WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); - __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); - __ RestoreVectorRegisters(simd128_regs_to_save); - __ MultiPopFPU(fp_regs_to_save); - __ MultiPop(regs_to_save); - } else { - __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // We come from WebAssembly, there are no references for the GC. - RecordSafepointWithoutTaggedSlots(); - if (v8_flags.debug_code) { - __ stop(); - } + __ Branch(&done, uge, sp, Operand(stack_limit)); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + __ MultiPush(regs_to_save); + DoubleRegList fp_regs_to_save; + for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + __ MultiPushFPU(fp_regs_to_save); + Simd128RegList simd128_regs_to_save; + for (auto reg : wasm::kSimd128ParamRegisters) + simd128_regs_to_save.set(reg); + __ SaveVectorRegisters(simd128_regs_to_save); + __ li(WasmHandleStackOverflowDescriptor::GapRegister(), stack_space); + __ AddWord(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ li(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + call_descriptor->ParameterSlotCount() * kSystemPointerSize); + __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + __ RestoreVectorRegisters(simd128_regs_to_save); + __ MultiPopFPU(fp_regs_to_save); + __ MultiPop(regs_to_save); + } else { + __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // We come from WebAssembly, there are no references for the GC. + RecordSafepointWithoutTaggedSlots(); + if (v8_flags.debug_code) { + __ stop(); } - __ bind(&done); } -#endif // V8_ENABLE_WEBASSEMBLY + __ bind(&done); } +#endif // V8_ENABLE_WEBASSEMBLY const int returns = frame()->GetReturnSlotCount(); @@ -5605,54 +5624,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - Label done; - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ LoadWord(scratch, - MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - __ BranchShort( - &done, ne, scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - RegList regs_to_save; - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpReturnRegisters) fp_regs_to_save.set(reg); - __ MultiPushFPU(fp_regs_to_save); - Simd128RegList simd128_regs_to_save; - for (auto reg : wasm::kSimd128ReturnRegisters) - simd128_regs_to_save.set(reg); - __ SaveVectorRegisters(simd128_regs_to_save); - - __ li(kCArgRegs[0], ExternalReference::isolate_address()); - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ PrepareCallCFunction(1, scratch); - } - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - __ mv(fp, kReturnRegister0); - __ RestoreVectorRegisters(simd128_regs_to_save); - __ MultiPopFPU(fp_regs_to_save); - __ MultiPop(regs_to_save); - if (masm()->options().enable_simulator_code) { - UseScratchRegisterScope temps(masm()); - temps.Exclude(kSimulatorBreakArgument); - __ RecordComment("-- Set simulator stack limit --"); - __ LoadStackLimit(kSimulatorBreakArgument, - StackLimitKind::kRealStackLimit); - __ break_(kExceptionIsSwitchStackLimit, false); - } - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY - // Functions with JS linkage have at least one parameter (the receiver). // If {parameter_slots} == 0, it means it is a builtin with // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping diff --git a/deps/v8/src/compiler/backend/riscv/instruction-codes-riscv.h b/deps/v8/src/compiler/backend/riscv/instruction-codes-riscv.h index d52cf83a6a71..df70a193a030 100644 --- a/deps/v8/src/compiler/backend/riscv/instruction-codes-riscv.h +++ b/deps/v8/src/compiler/backend/riscv/instruction-codes-riscv.h @@ -94,7 +94,7 @@ namespace compiler { V(RiscvWord64AtomicExchangeUint64) \ V(RiscvLoadDecodeSandboxedPointer) \ V(RiscvStoreEncodeSandboxedPointer) \ - V(RiscvStoreIndirectPointer) \ + V(RiscvStoreTrustedPointer) \ V(RiscvAtomicLoadDecompressTaggedSigned) \ V(RiscvAtomicLoadDecompressTagged) \ V(RiscvLoadDecompressTrapping) \ diff --git a/deps/v8/src/compiler/backend/riscv/instruction-scheduler-riscv.cc b/deps/v8/src/compiler/backend/riscv/instruction-scheduler-riscv.cc index 35c0037371de..0de472639a87 100644 --- a/deps/v8/src/compiler/backend/riscv/instruction-scheduler-riscv.cc +++ b/deps/v8/src/compiler/backend/riscv/instruction-scheduler-riscv.cc @@ -345,7 +345,7 @@ int InstructionScheduler::GetTargetInstructionFlags( case kRiscvWord64AtomicCompareExchangeUint64: case kRiscvStoreCompressTagged: case kRiscvStoreEncodeSandboxedPointer: - case kRiscvStoreIndirectPointer: + case kRiscvStoreTrustedPointer: #elif V8_TARGET_ARCH_RISCV32 case kRiscvWord32AtomicPairStore: case kRiscvWord32AtomicPairAdd: @@ -1519,7 +1519,7 @@ ArchInstResource InstructionScheduler::GetInstructionResource( case kRiscvStoreCompressTagged: case kRiscvAtomicStoreCompressTagged: case kRiscvStoreEncodeSandboxedPointer: - case kRiscvStoreIndirectPointer: + case kRiscvStoreTrustedPointer: case kRiscvWord64AtomicStoreWord64: case kRiscvWord64AtomicAddUint64: case kRiscvWord64AtomicSubUint64: diff --git a/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv32.cc b/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv32.cc index 9bf247bae433..a6191ec050b7 100644 --- a/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv32.cc +++ b/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv32.cc @@ -229,7 +229,7 @@ void InstructionSelector::VisitLoad(OpIndex node) { case MachineRepresentation::kNone: case MachineRepresentation::kSimd256: // Fall through. case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kFloat16: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); @@ -272,12 +272,12 @@ void InstructionSelector::VisitStore(OpIndex node) { } else { RecordWriteMode record_write_mode = WriteBarrierKindToRecordWriteMode(write_barrier_kind); - if (rep == MachineRepresentation::kIndirectPointer) { - DCHECK_EQ(write_barrier_kind, kIndirectPointerWriteBarrier); - // In this case we need to add the IndirectPointerTag as additional + if (rep == MachineRepresentation::kTrustedPointer) { + DCHECK_EQ(write_barrier_kind, kTrustedPointerWriteBarrier); + // In this case we need to add the TrustedPointerTag as additional // input. - code = kArchStoreIndirectWithWriteBarrier; - IndirectPointerTag tag = store_view.indirect_pointer_tag(); + code = kArchStoreTrustedWithWriteBarrier; + TrustedPointerTag tag = store_view.trusted_pointer_tag(); inputs[input_count++] = g.UseImmediate64(static_cast<int64_t>(tag)); } else { code = kArchStoreWithWriteBarrier; @@ -321,7 +321,7 @@ void InstructionSelector::VisitStore(OpIndex node) { case MachineRepresentation::kWord64: case MachineRepresentation::kSimd256: // Fall through. case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kFloat16: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); diff --git a/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv64.cc b/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv64.cc index 58213f1efab0..fe318cafdb3b 100644 --- a/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv64.cc +++ b/deps/v8/src/compiler/backend/riscv/instruction-selector-riscv64.cc @@ -645,8 +645,6 @@ ArchOpcode GetLoadOpcode(MemoryRepresentation loaded_rep, case MemoryRepresentation::ProtectedPointer(): CHECK(V8_ENABLE_SANDBOX_BOOL); return kRiscvLoadDecompressTrapping; - case MemoryRepresentation::IndirectPointer(): - UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): // Only LoadTrustedPointer uses this representation. UNREACHABLE(); @@ -691,10 +689,7 @@ ArchOpcode GetStoreOpcode(MemoryRepresentation stored_rep) { // We never store directly to protected pointers from generated code. UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); - case MemoryRepresentation::IndirectPointer(): - return kRiscvStoreIndirectPointer; + return kRiscvStoreTrustedPointer; case MemoryRepresentation::SandboxedPointer(): return kRiscvStoreEncodeSandboxedPointer; case MemoryRepresentation::Simd128(): @@ -737,7 +732,7 @@ void InstructionSelector::VisitStore(OpIndex node) { // TODO(riscv): I guess this could be done in a better way. if (write_barrier_kind != kNoWriteBarrier && V8_LIKELY(!v8_flags.disable_write_barriers)) { - DCHECK(CanBeTaggedOrCompressedOrIndirectPointer(rep)); + DCHECK(CanBeTaggedOrCompressedOrTrustedPointer(rep)); InstructionOperand inputs[4]; InstructionCode code; size_t input_count = 0; @@ -749,16 +744,16 @@ void InstructionSelector::VisitStore(OpIndex node) { InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; size_t const temp_count = arraysize(temps); - if (rep == MachineRepresentation::kIndirectPointer) { - DCHECK(write_barrier_kind == kIndirectPointerWriteBarrier || + if (rep == MachineRepresentation::kTrustedPointer) { + DCHECK(write_barrier_kind == kTrustedPointerWriteBarrier || write_barrier_kind == kSkippedWriteBarrier); - // In this case we need to add the IndirectPointerTag as additional input. + // In this case we need to add the TrustedPointerTag as additional input. code = write_barrier_kind == kSkippedWriteBarrier - ? kArchStoreIndirectSkippedWriteBarrier - : kArchStoreIndirectWithWriteBarrier; - code |= RecordWriteModeField::encode( - RecordWriteMode::kValueIsIndirectPointer); - IndirectPointerTag tag = store_view.indirect_pointer_tag(); + ? kArchStoreTrustedSkippedWriteBarrier + : kArchStoreTrustedWithWriteBarrier; + code |= + RecordWriteModeField::encode(RecordWriteMode::kValueIsTrustedPointer); + TrustedPointerTag tag = store_view.trusted_pointer_tag(); inputs[input_count++] = g.UseImmediate64(static_cast<int64_t>(tag)); } else if (write_barrier_kind == kSkippedWriteBarrier) { code = kArchStoreSkippedWriteBarrier; diff --git a/deps/v8/src/compiler/backend/s390/code-generator-s390.cc b/deps/v8/src/compiler/backend/s390/code-generator-s390.cc index d9798f6f565a..93344953b743 100644 --- a/deps/v8/src/compiler/backend/s390/code-generator-s390.cc +++ b/deps/v8/src/compiler/backend/s390/code-generator-s390.cc @@ -1316,8 +1316,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kArchCallJSFunction: { - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -1326,7 +1326,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( if (function->shared()->HasBuiltinId()) { Builtin builtin = function->shared()->builtin_id(); size_t expected = Builtins::GetFormalParameterCount(builtin); - if (num_arguments == expected) { + if (expected_parameter_count == expected) { __ CallBuiltin(builtin); } else { __ AssertUnreachable(AbortReason::kJSSignatureMismatch); @@ -1335,7 +1335,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( JSDispatchHandle dispatch_handle = function->dispatch_handle(); size_t expected = isolate()->js_dispatch_table().GetParameterCount( dispatch_handle); - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -1343,7 +1343,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -1355,7 +1356,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ CmpS64(cp, kScratchReg); __ Assert(eq, AbortReason::kWrongFunctionContext); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } RecordCallPosition(instr); frame_access_state()->ClearSPDelta(); @@ -1609,8 +1610,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( __ StoreTaggedField(value, operand, r0); break; } - case kArchStoreIndirectWithWriteBarrier: - case kArchStoreIndirectSkippedWriteBarrier: + case kArchStoreTrustedWithWriteBarrier: + case kArchStoreTrustedSkippedWriteBarrier: UNREACHABLE(); case kArchStackSlot: { FrameOffset offset = @@ -3511,48 +3512,47 @@ void CodeGenerator::FinishFrame(Frame* frame) { } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (frame_access_state()->has_frame()) { - if (call_descriptor->IsCFunctionCall()) { + if (call_descriptor->IsCFunctionCall()) { #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ StubPrologue(StackFrame::C_WASM_ENTRY); - // Reserve stack space for saving the c_entry_fp later. - __ lay(sp, MemOperand(sp, -kSystemPointerSize)); + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ StubPrologue(StackFrame::C_WASM_ENTRY); + // Reserve stack space for saving the c_entry_fp later. + __ lay(sp, MemOperand(sp, -kSystemPointerSize)); #else - // For balance. - if (false) { + // For balance. + if (false) { #endif // V8_ENABLE_WEBASSEMBLY - } else { - __ Push(r14, fp); - __ mov(fp, sp); - } - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(ip); } else { - StackFrame::Type type = info()->GetOutputStackFrameType(); - // TODO(mbrandy): Detect cases where ip is the entrypoint (for - // efficient initialization of the constant pool pointer register). - __ StubPrologue(type); + __ Push(r14, fp); + __ mov(fp, sp); + } + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(ip); + } else { + StackFrame::Type type = info()->GetOutputStackFrameType(); + // TODO(mbrandy): Detect cases where ip is the entrypoint (for + // efficient initialization of the constant pool pointer register). + __ StubPrologue(type); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ Push(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ lay(sp, MemOperand(sp, -kSystemPointerSize)); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ Push(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ lay(sp, MemOperand(sp, -kSystemPointerSize)); } - unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); +#endif // V8_ENABLE_WEBASSEMBLY } + unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); int required_slots = frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount(); @@ -3572,73 +3572,92 @@ void CodeGenerator::AssembleConstructFrame() { const DoubleRegList saves_fp = call_descriptor->CalleeSavedFPRegisters(); const RegList saves = call_descriptor->CalleeSavedRegisters(); - if (required_slots > 0) { #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { - Register stack_limit = r1; - __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); - __ AddS64(stack_limit, stack_limit, Operand(stack_space)); - __ CmpU64(sp, stack_limit); - __ bge(&done); + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + Register stack_limit = r1; + __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit); + if (stack_space > 0) { + __ AddS64(stack_limit, stack_limit, + Operand(static_cast<int32_t>(stack_space))); } - - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - __ MultiPushF64OrV128(fp_regs_to_save, r1); - __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), - Operand(stack_space)); - __ AddS64( - WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); - __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just ignore any references and record an empty - // safepoint here. - RecordSafepointWithoutTaggedSlots(); - __ MultiPopF64OrV128(fp_regs_to_save, r1); - __ MultiPop(regs_to_save); - } else { - __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - if (v8_flags.debug_code) __ stop(); - } - - __ bind(&done); + __ CmpU64(sp, stack_limit); + __ bge(&done); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + __ MultiPush(regs_to_save); + DoubleRegList fp_regs_to_save; + for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + __ MultiPushF64OrV128(fp_regs_to_save, r1); + __ mov(WasmHandleStackOverflowDescriptor::GapRegister(), + Operand(static_cast<int32_t>(stack_space))); + __ AddS64(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + __ mov( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize)); + __ Call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just ignore any references and record an empty + // safepoint here. + RecordSafepointWithoutTaggedSlots(); + __ MultiPopF64OrV128(fp_regs_to_save, r1); + __ MultiPop(regs_to_save); + } else { + __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + if (v8_flags.debug_code) __ stop(); } + __ bind(&done); + } #endif // V8_ENABLE_WEBASSEMBLY - // Skip callee-saved and return slots, which are pushed below. - required_slots -= saves.Count(); - required_slots -= frame()->GetReturnSlotCount(); - required_slots -= (kDoubleSize / kSystemPointerSize) * saves_fp.Count(); + // Skip callee-saved and return slots, which are pushed below. + required_slots -= saves.Count(); + required_slots -= frame()->GetReturnSlotCount(); + required_slots -= (kDoubleSize / kSystemPointerSize) * saves_fp.Count(); + if (required_slots > 0) { __ lay(sp, MemOperand(sp, -required_slots * kSystemPointerSize)); } @@ -3706,38 +3725,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - { - UseScratchRegisterScope temps{masm()}; - Register scratch = temps.Acquire(); - __ LoadU64(scratch, - MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - __ CmpU64( - scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - __ bne(&done); - RegList regs_to_save; - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.set(reg); - __ MultiPush(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - __ MultiPushF64OrV128(fp_regs_to_save, r1); - __ Move(kCArgRegs[0], ExternalReference::isolate_address()); - __ PrepareCallCFunction(1, r0); - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - __ mov(fp, kReturnRegister0); - __ MultiPopF64OrV128(fp_regs_to_save, r1); - __ MultiPop(regs_to_save); - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY - Register argc_reg = r5; // Functions with JS linkage have at least one parameter (the receiver). // If {parameter_slots} == 0, it means it is a builtin with diff --git a/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc b/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc index 70b7c171bb95..3ddc155cbcbb 100644 --- a/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc +++ b/deps/v8/src/compiler/backend/s390/instruction-selector-s390.cc @@ -397,10 +397,7 @@ ArchOpcode SelectLoadOpcode(MemoryRepresentation loaded_rep, DCHECK_EQ(result_rep, RegisterRepresentation::Simd128()); return kS390_LoadSimd128; case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); case MemoryRepresentation::ProtectedPointer(): - case MemoryRepresentation::IndirectPointer(): case MemoryRepresentation::SandboxedPointer(): case MemoryRepresentation::Simd256(): UNREACHABLE(); @@ -458,7 +455,7 @@ ArchOpcode SelectLoadOpcode(LoadRepresentation load_rep) { case MachineRepresentation::kFloat16: UNIMPLEMENTED(); case MachineRepresentation::kProtectedPointer: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kSandboxedPointer: // Fall through. case MachineRepresentation::kSimd256: // Fall through. case MachineRepresentation::kMapWord: // Fall through. @@ -1016,9 +1013,6 @@ static void VisitGeneralStore( // We never store directly to protected pointers from generated code. UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); - case MemoryRepresentation::IndirectPointer(): case MemoryRepresentation::SandboxedPointer(): case MemoryRepresentation::Simd256(): UNREACHABLE(); diff --git a/deps/v8/src/compiler/backend/simd-shuffle.cc b/deps/v8/src/compiler/backend/simd-shuffle.cc index 60062d9b1f21..7054688d007b 100644 --- a/deps/v8/src/compiler/backend/simd-shuffle.cc +++ b/deps/v8/src/compiler/backend/simd-shuffle.cc @@ -53,6 +53,95 @@ constexpr SimdShuffle::ShuffleArray<kSimd128Size> expandQuarter( return expand<N, kSimd128QuarterSize>(in); } +using CanonicalShuffle = SimdShuffle::CanonicalShuffle; +using CanonicalPair = std::pair<const SimdShuffle::ShuffleArray<kSimd128Size>, + const CanonicalShuffle>; +static constexpr auto canonical_shuffle_list = std::to_array<CanonicalPair>({ + {expand<2>({0, 1}), CanonicalShuffle::kIdentity}, + {expandHalf<1>({0}), CanonicalShuffle::kIdentity}, + {expand<2>({0, 2}), CanonicalShuffle::kS64x2Even}, + {expand<2>({1, 3}), CanonicalShuffle::kS64x2Odd}, + {expand<2>({1, 0}), CanonicalShuffle::kS64x2Reverse}, + {expand<4>({0, 2, 4, 6}), CanonicalShuffle::kS32x4Even}, + {expand<4>({1, 3, 5, 7}), CanonicalShuffle::kS32x4Odd}, + {expand<4>({0, 4, 1, 5}), CanonicalShuffle::kS32x4InterleaveLowHalves}, + {expand<4>({2, 6, 3, 7}), CanonicalShuffle::kS32x4InterleaveHighHalves}, + {expand<4>({3, 2, 1, 0}), CanonicalShuffle::kS32x4Reverse}, + {expand<4>({0, 4, 2, 6}), CanonicalShuffle::kS32x4TransposeEven}, + {expand<4>({1, 5, 3, 7}), CanonicalShuffle::kS32x4TransposeOdd}, + {expand<4>({1, 0, 3, 2}), CanonicalShuffle::kS32x2Reverse}, + {expandHalf<4>({0, 2, 8, 10}), CanonicalShuffle::kS16x4Even}, + {expandHalf<4>({1, 3, 9, 11}), CanonicalShuffle::kS16x4Odd}, + {expand<8>({0, 2, 4, 6, 8, 10, 12, 14}), CanonicalShuffle::kS16x8Even}, + {expand<8>({1, 3, 5, 7, 9, 11, 13, 15}), CanonicalShuffle::kS16x8Odd}, + {expand<8>({0, 8, 1, 9, 2, 10, 3, 11}), + CanonicalShuffle::kS16x8InterleaveLowHalves}, + {expandHalf<4>({2, 10, 3, 11}), + CanonicalShuffle::kS16x4InterleaveHighHalves}, + {expand<8>({4, 12, 5, 13, 6, 14, 7, 15}), + CanonicalShuffle::kS16x8InterleaveHighHalves}, + {expand<8>({0, 8, 2, 10, 4, 12, 6, 14}), + CanonicalShuffle::kS16x8TransposeEven}, + {expand<8>({1, 9, 3, 11, 5, 13, 7, 15}), + CanonicalShuffle::kS16x8TransposeOdd}, + {expand<8>({0, 4, 1, 5, 2, 6, 3, 7}), + CanonicalShuffle::kS16x8TopBottomInterleave}, + {expand<8>({1, 0, 3, 2, 5, 4, 7, 6}), CanonicalShuffle::kS16x2Reverse}, + {expand<8>({3, 2, 1, 0, 7, 6, 5, 4}), CanonicalShuffle::kS16x4Reverse}, + {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, + CanonicalShuffle::kS64x2ReverseBytes}, + {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, + CanonicalShuffle::kS32x4ReverseBytes}, + {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, + CanonicalShuffle::kS16x8ReverseBytes}, + {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}, + CanonicalShuffle::kS8x16InterleaveLowHalves}, + {expandHalf<8>({4, 20, 5, 21, 6, 22, 7, 23}), + CanonicalShuffle::kS8x8InterleaveHighHalves}, + {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31}, + CanonicalShuffle::kS8x16InterleaveHighHalves}, + {expandHalf<8>({0, 2, 4, 6, 16, 18, 20, 22}), CanonicalShuffle::kS8x8Even}, + {expandHalf<8>({1, 3, 5, 7, 17, 19, 21, 23}), CanonicalShuffle::kS8x8Odd}, + {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}, + CanonicalShuffle::kS8x16Even}, + {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, + CanonicalShuffle::kS8x16Odd}, + {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30}, + CanonicalShuffle::kS8x16TransposeEven}, + {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31}, + CanonicalShuffle::kS8x16TransposeOdd}, + {expandHalf<8>({0, 4, 8, 12, 16, 20, 24, 28}), + CanonicalShuffle::kS8x8DeinterleaveEvenEven}, + {expandHalf<8>({1, 5, 9, 13, 17, 21, 25, 29}), + CanonicalShuffle::kS8x8DeinterleaveOddEven}, + {expandHalf<8>({2, 6, 10, 14, 18, 22, 26, 30}), + CanonicalShuffle::kS8x8DeinterleaveEvenOdd}, + {expandHalf<8>({3, 7, 11, 15, 19, 23, 27, 31}), + CanonicalShuffle::kS8x8DeinterleaveOddOdd}, + {expandHalf<4>({0, 4, 8, 12}), + CanonicalShuffle::kS16x4DeinterleaveEvenEven}, + {expandHalf<4>({1, 5, 9, 13}), CanonicalShuffle::kS16x4DeinterleaveOddEven}, + {expandHalf<4>({2, 6, 10, 14}), + CanonicalShuffle::kS16x4DeinterleaveEvenOdd}, + {expandHalf<4>({3, 7, 11, 15}), CanonicalShuffle::kS16x4DeinterleaveOddOdd}, + {expandQuarter<4>({0, 8, 16, 24}), + CanonicalShuffle::kS8x4DeinterleaveEvenEvenEven}, + {expandQuarter<4>({1, 9, 17, 25}), + CanonicalShuffle::kS8x4DeinterleaveOddEvenEven}, + {expandQuarter<4>({2, 10, 18, 26}), + CanonicalShuffle::kS8x4DeinterleaveEvenOddEven}, + {expandQuarter<4>({3, 11, 19, 27}), + CanonicalShuffle::kS8x4DeinterleaveOddOddEven}, + {expandQuarter<4>({4, 12, 20, 28}), + CanonicalShuffle::kS8x4DeinterleaveEvenEvenOdd}, + {expandQuarter<4>({5, 13, 21, 29}), + CanonicalShuffle::kS8x4DeinterleaveOddEvenOdd}, + {expandQuarter<4>({6, 14, 22, 30}), + CanonicalShuffle::kS8x4DeinterleaveEvenOddOdd}, + {expandQuarter<4>({7, 15, 23, 31}), + CanonicalShuffle::kS8x4DeinterleaveOddOddOdd}, +}); + // A single matcher for both full- and half-size shuffles, where the half-size // only shuffles are padded with the sentinel value. Half-size shuffles // only match the first half of each shuffle pattern. @@ -61,98 +150,6 @@ template <size_t N> N == kSimd128Size) SimdShuffle::CanonicalShuffle TryMatchCanonicalImpl( const SimdShuffle::ShuffleArray<N>& shuffle) { - using CanonicalShuffle = SimdShuffle::CanonicalShuffle; - using CanonicalPair = std::pair<const SimdShuffle::ShuffleArray<kSimd128Size>, - const CanonicalShuffle>; - static constexpr auto canonical_shuffle_list = std::to_array<CanonicalPair>({ - {expand<2>({0, 1}), CanonicalShuffle::kIdentity}, - {expandHalf<1>({0}), CanonicalShuffle::kIdentity}, - {expand<2>({0, 2}), CanonicalShuffle::kS64x2Even}, - {expand<2>({1, 3}), CanonicalShuffle::kS64x2Odd}, - {expand<2>({1, 0}), CanonicalShuffle::kS64x2Reverse}, - {expand<4>({0, 2, 4, 6}), CanonicalShuffle::kS32x4Even}, - {expand<4>({1, 3, 5, 7}), CanonicalShuffle::kS32x4Odd}, - {expand<4>({0, 4, 1, 5}), CanonicalShuffle::kS32x4InterleaveLowHalves}, - {expand<4>({2, 6, 3, 7}), CanonicalShuffle::kS32x4InterleaveHighHalves}, - {expand<4>({3, 2, 1, 0}), CanonicalShuffle::kS32x4Reverse}, - {expand<4>({0, 4, 2, 6}), CanonicalShuffle::kS32x4TransposeEven}, - {expand<4>({1, 5, 3, 7}), CanonicalShuffle::kS32x4TransposeOdd}, - {expand<4>({1, 0, 3, 2}), CanonicalShuffle::kS32x2Reverse}, - {expandHalf<4>({0, 2, 8, 10}), CanonicalShuffle::kS16x4Even}, - {expandHalf<4>({1, 3, 9, 11}), CanonicalShuffle::kS16x4Odd}, - {expand<8>({0, 2, 4, 6, 8, 10, 12, 14}), CanonicalShuffle::kS16x8Even}, - {expand<8>({1, 3, 5, 7, 9, 11, 13, 15}), CanonicalShuffle::kS16x8Odd}, - {expand<8>({0, 8, 1, 9, 2, 10, 3, 11}), - CanonicalShuffle::kS16x8InterleaveLowHalves}, - {expandHalf<4>({2, 10, 3, 11}), - CanonicalShuffle::kS16x4InterleaveHighHalves}, - {expand<8>({4, 12, 5, 13, 6, 14, 7, 15}), - CanonicalShuffle::kS16x8InterleaveHighHalves}, - {expand<8>({0, 8, 2, 10, 4, 12, 6, 14}), - CanonicalShuffle::kS16x8TransposeEven}, - {expand<8>({1, 9, 3, 11, 5, 13, 7, 15}), - CanonicalShuffle::kS16x8TransposeOdd}, - {expand<8>({0, 4, 1, 5, 2, 6, 3, 7}), - CanonicalShuffle::kS16x8TopBottomInterleave}, - {expand<8>({1, 0, 3, 2, 5, 4, 7, 6}), CanonicalShuffle::kS16x2Reverse}, - {expand<8>({3, 2, 1, 0, 7, 6, 5, 4}), CanonicalShuffle::kS16x4Reverse}, - {{7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}, - CanonicalShuffle::kS64x2ReverseBytes}, - {{3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12}, - CanonicalShuffle::kS32x4ReverseBytes}, - {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14}, - CanonicalShuffle::kS16x8ReverseBytes}, - {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}, - CanonicalShuffle::kS8x16InterleaveLowHalves}, - {expandHalf<8>({4, 20, 5, 21, 6, 22, 7, 23}), - CanonicalShuffle::kS8x8InterleaveHighHalves}, - {{8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31}, - CanonicalShuffle::kS8x16InterleaveHighHalves}, - {expandHalf<8>({0, 2, 4, 6, 16, 18, 20, 22}), - CanonicalShuffle::kS8x8Even}, - {expandHalf<8>({1, 3, 5, 7, 17, 19, 21, 23}), CanonicalShuffle::kS8x8Odd}, - {{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}, - CanonicalShuffle::kS8x16Even}, - {{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, - CanonicalShuffle::kS8x16Odd}, - {{0, 16, 2, 18, 4, 20, 6, 22, 8, 24, 10, 26, 12, 28, 14, 30}, - CanonicalShuffle::kS8x16TransposeEven}, - {{1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31}, - CanonicalShuffle::kS8x16TransposeOdd}, - {{0, 4, 8, 12, 16, 20, 24, 28}, - CanonicalShuffle::kS8x8DeinterleaveEvenEven}, - {{1, 5, 9, 13, 17, 21, 25, 29}, - CanonicalShuffle::kS8x8DeinterleaveOddEven}, - {{2, 6, 10, 14, 18, 22, 26, 30}, - CanonicalShuffle::kS8x8DeinterleaveEvenOdd}, - {{3, 7, 11, 15, 19, 23, 27, 31}, - CanonicalShuffle::kS8x8DeinterleaveOddOdd}, - {expandHalf<4>({0, 4, 8, 12}), - CanonicalShuffle::kS16x4DeinterleaveEvenEven}, - {expandHalf<4>({1, 5, 9, 13}), - CanonicalShuffle::kS16x4DeinterleaveOddEven}, - {expandHalf<4>({2, 6, 10, 14}), - CanonicalShuffle::kS16x4DeinterleaveEvenOdd}, - {expandHalf<4>({3, 7, 11, 15}), - CanonicalShuffle::kS16x4DeinterleaveOddOdd}, - {expandQuarter<4>({0, 8, 16, 24}), - CanonicalShuffle::kS8x4DeinterleaveEvenEvenEven}, - {expandQuarter<4>({1, 9, 17, 25}), - CanonicalShuffle::kS8x4DeinterleaveOddEvenEven}, - {expandQuarter<4>({2, 10, 18, 26}), - CanonicalShuffle::kS8x4DeinterleaveEvenOddEven}, - {expandQuarter<4>({3, 11, 19, 27}), - CanonicalShuffle::kS8x4DeinterleaveOddOddEven}, - {expandQuarter<4>({4, 12, 20, 28}), - CanonicalShuffle::kS8x4DeinterleaveEvenEvenOdd}, - {expandQuarter<4>({5, 13, 21, 29}), - CanonicalShuffle::kS8x4DeinterleaveOddEvenOdd}, - {expandQuarter<4>({6, 14, 22, 30}), - CanonicalShuffle::kS8x4DeinterleaveEvenOddOdd}, - {expandQuarter<4>({7, 15, 23, 31}), - CanonicalShuffle::kS8x4DeinterleaveOddOddOdd}, - - }); for (const auto& [lanes, canonical] : canonical_shuffle_list) { if (std::equal(lanes.begin(), lanes.begin() + N, shuffle.begin())) { return canonical; @@ -163,6 +160,18 @@ SimdShuffle::CanonicalShuffle TryMatchCanonicalImpl( } // namespace +std::optional<SimdShuffle::ShuffleArray<kSimd128Size>> +SimdShuffle::TryGetCanonicalMask( + const SimdShuffle::CanonicalShuffle canonical) { + for (const auto& [mask, kind] : canonical_shuffle_list) { + if (kind == canonical) { + return mask; + } + } + + return {}; +} + SimdShuffle::CanonicalShuffle SimdShuffle::TryMatchCanonical( const ShuffleArray<kSimd128Size>& shuffle) { return TryMatchCanonicalImpl<kSimd128Size>(shuffle); @@ -485,15 +494,6 @@ uint8_t SimdShuffle::PackBlend4(const uint8_t* shuffle32x4) { return result; } -int32_t SimdShuffle::Pack2Lanes(const std::array<uint8_t, 2>& shuffle) { - int32_t result = 0; - for (int i = 1; i >= 0; --i) { - result <<= 8; - result |= shuffle[i]; - } - return result; -} - int32_t SimdShuffle::Pack4Lanes(const uint8_t* shuffle) { int32_t result = 0; for (int i = 3; i >= 0; --i) { diff --git a/deps/v8/src/compiler/backend/simd-shuffle.h b/deps/v8/src/compiler/backend/simd-shuffle.h index 573d7e6a6943..dae746a51dfe 100644 --- a/deps/v8/src/compiler/backend/simd-shuffle.h +++ b/deps/v8/src/compiler/backend/simd-shuffle.h @@ -258,8 +258,6 @@ class V8_EXPORT_PRIVATE SimdShuffle { static uint8_t PackBlend8(const uint8_t* shuffle16x8); // Gets an 8 bit lane mask suitable for 32x4 pblendw. static uint8_t PackBlend4(const uint8_t* shuffle32x4); - // Packs 2 bytes of shuffle into a 32 bit immediate. - static int32_t Pack2Lanes(const std::array<uint8_t, 2>& shuffle); // Packs 4 bytes of shuffle into a 32 bit immediate. static int32_t Pack4Lanes(const uint8_t* shuffle); // Packs 16 bytes of shuffle into an array of 4 uint32_t. @@ -336,6 +334,10 @@ class V8_EXPORT_PRIVATE SimdShuffle { static CanonicalShuffle TryMatchCanonical( const ShuffleArray<kSimd128QuarterSize>& shuffle); + // Matches a CanonicalShuffle to a byte mask + static std::optional<ShuffleArray<kSimd128Size>> TryGetCanonicalMask( + const CanonicalShuffle canonical); + #ifdef V8_TARGET_ARCH_X64 // If matching success, the corresponding instrution should be: // vpshufd ymm, ymm, imm8 diff --git a/deps/v8/src/compiler/backend/spill-placer.cc b/deps/v8/src/compiler/backend/spill-placer.cc index 83ce91337ecf..f71d43bd852e 100644 --- a/deps/v8/src/compiler/backend/spill-placer.cc +++ b/deps/v8/src/compiler/backend/spill-placer.cc @@ -42,8 +42,8 @@ void SpillPlacer::Add(TopLevelLiveRange* range) { // saw benefits in some wasm benchmarks when enabling it for other ranges, so // the "--turbo-always-optimize-spills" flag is enabled by default now. It can // be cleaned up if this is stable and does not cause regressions. - if (range->GetSpillMoveInsertionLocations(data()) == nullptr || - range->spilled() || top_start_block->IsDeferred() || + if (range->GetSpillMoveInsertionLocations() == nullptr || range->spilled() || + top_start_block->IsDeferred() || (!v8_flags.turbo_always_optimize_spills && !range->is_loop_phi())) { range->CommitSpillMoves(data(), spill_operand); return; diff --git a/deps/v8/src/compiler/backend/spill-placer.h b/deps/v8/src/compiler/backend/spill-placer.h index e8a62612f543..1197a4dfc6d9 100644 --- a/deps/v8/src/compiler/backend/spill-placer.h +++ b/deps/v8/src/compiler/backend/spill-placer.h @@ -12,7 +12,6 @@ namespace internal { namespace compiler { -class LiveRangeFinder; class TopLevelLiveRange; class RegisterAllocationData; diff --git a/deps/v8/src/compiler/backend/x64/code-generator-x64.cc b/deps/v8/src/compiler/backend/x64/code-generator-x64.cc index 42ae89aeba43..baae3cd82310 100644 --- a/deps/v8/src/compiler/backend/x64/code-generator-x64.cc +++ b/deps/v8/src/compiler/backend/x64/code-generator-x64.cc @@ -33,8 +33,8 @@ #include "src/objects/shared-function-info-inl.h" #include "src/objects/smi.h" #include "src/roots/roots-inl.h" -#include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/js-dispatch-table-inl.h" +#include "src/sandbox/trusted-pointer-tag.h" #if V8_ENABLE_WEBASSEMBLY #include "src/wasm/wasm-linkage.h" @@ -386,7 +386,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { CodeGenerator* gen, Register object, Operand operand, Register value, Register scratch0, Register scratch1, RecordWriteMode mode, StubCallMode stub_mode, - IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag) + TrustedPointerTag trusted_pointer_tag = kTrustedPointerNullTag) : OutOfLineCode(gen), object_(object), operand_(operand), @@ -398,7 +398,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { stub_mode_(stub_mode), #endif // V8_ENABLE_WEBASSEMBLY zone_(gen->zone()), - indirect_pointer_tag_(indirect_pointer_tag) { + trusted_pointer_tag_(trusted_pointer_tag) { DCHECK(!AreAliased(object, scratch0, scratch1)); DCHECK(!AreAliased(value, scratch0, scratch1)); } @@ -411,13 +411,13 @@ class OutOfLineRecordWrite final : public OutOfLineCode { // When storing an indirect pointer, the value will always be a // full/decompressed pointer. if (COMPRESS_POINTERS_BOOL && - mode_ != RecordWriteMode::kValueIsIndirectPointer) { + mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ DecompressTagged(value_, value_); } // No need to check value page flags with the indirect pointer write barrier // because the value is always an ExposedTrustedObject. - if (mode_ != RecordWriteMode::kValueIsIndirectPointer) { + if (mode_ != RecordWriteMode::kValueIsTrustedPointer) { #if V8_ENABLE_STICKY_MARK_BITS_BOOL // TODO(333906585): Optimize this path. Label stub_call_with_decompressed_value; @@ -433,7 +433,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { __ bind(&stub_call_); if (COMPRESS_POINTERS_BOOL && - mode_ != RecordWriteMode::kValueIsIndirectPointer) { + mode_ != RecordWriteMode::kValueIsTrustedPointer) { __ DecompressTagged(value_, value_); } @@ -453,12 +453,12 @@ class OutOfLineRecordWrite final : public OutOfLineCode { if (mode_ == RecordWriteMode::kValueIsEphemeronKey) { __ CallEphemeronKeyBarrier(object_, scratch1_, save_fp_mode); - } else if (mode_ == RecordWriteMode::kValueIsIndirectPointer) { - // We must have a valid indirect pointer tag here. Otherwise, we risk not + } else if (mode_ == RecordWriteMode::kValueIsTrustedPointer) { + // We must have a valid trusted pointer tag here. Otherwise, we risk not // invoking the correct write barrier, which may lead to subtle issues. - CHECK(IsValidIndirectPointerTag(indirect_pointer_tag_)); - __ CallIndirectPointerBarrier(object_, scratch1_, save_fp_mode, - indirect_pointer_tag_); + CHECK(IsValidTrustedPointerTag(trusted_pointer_tag_)); + __ CallTrustedPointerBarrier(object_, scratch1_, save_fp_mode, + trusted_pointer_tag_); #if V8_ENABLE_WEBASSEMBLY } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) { // A direct call to a wasm runtime stub defined in this module. @@ -483,7 +483,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode { StubCallMode const stub_mode_; #endif // V8_ENABLE_WEBASSEMBLY Zone* zone_; - IndirectPointerTag indirect_pointer_tag_; + TrustedPointerTag trusted_pointer_tag_; #if V8_ENABLE_STICKY_MARK_BITS_BOOL Label stub_call_; #endif // V8_ENABLE_STICKY_MARK_BITS_BOOL @@ -521,10 +521,10 @@ class OutOfLineVerifySkippedWriteBarrier final : public OutOfLineCode { Zone* zone_; }; -class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode { +class OutOfLineVerifySkippedTrustedWriteBarrier final : public OutOfLineCode { public: - OutOfLineVerifySkippedIndirectWriteBarrier(CodeGenerator* gen, - Register object, Register value) + OutOfLineVerifySkippedTrustedWriteBarrier(CodeGenerator* gen, Register object, + Register value) : OutOfLineCode(gen), object_(object), value_(value), @@ -535,8 +535,8 @@ class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode { ? SaveFPRegsMode::kSave : SaveFPRegsMode::kIgnore; - __ CallVerifySkippedIndirectWriteBarrierStubSaveRegisters(object_, value_, - save_fp_mode); + __ CallVerifySkippedTrustedWriteBarrierStubSaveRegisters(object_, value_, + save_fp_mode); } private: @@ -571,8 +571,8 @@ int EmitStore(MacroAssembler* masm, Operand operand, Register value, case MachineRepresentation::kSandboxedPointer: masm->StoreSandboxedPointerField(operand, value); break; - case MachineRepresentation::kIndirectPointer: - masm->StoreIndirectPointerField(operand, value); + case MachineRepresentation::kTrustedPointer: + masm->StoreTrustedPointerField(operand, value); break; default: UNREACHABLE(); @@ -813,13 +813,12 @@ Register GetTSANValueRegister(MacroAssembler* masm, Register value, masm->movq(value_reg, value); masm->EncodeSandboxedPointer(value_reg); return value_reg; - } else if (rep == MachineRepresentation::kIndirectPointer) { + } else if (rep == MachineRepresentation::kTrustedPointer) { // Indirect pointer fields contain an index to a pointer table entry, which // is obtained from the referenced object. Register value_reg = i.TempRegister(1); - masm->movl(value_reg, - FieldOperand(value, offsetof(ExposedTrustedObject, - self_indirect_pointer_))); + masm->movl(value_reg, FieldOperand(value, offsetof(ExposedTrustedObject, + self_trusted_pointer_))); return value_reg; } return value; @@ -839,12 +838,12 @@ Register GetTSANValueRegister<std::memory_order_relaxed>( if (rep == MachineRepresentation::kSandboxedPointer) { // SandboxedPointers need to be encoded. masm->EncodeSandboxedPointer(value_reg); - } else if (rep == MachineRepresentation::kIndirectPointer) { + } else if (rep == MachineRepresentation::kTrustedPointer) { // Indirect pointer fields contain an index to a pointer table entry, which // is obtained from the referenced object. masm->movl(value_reg, FieldOperand(value_reg, offsetof(ExposedTrustedObject, - self_indirect_pointer_))); + self_trusted_pointer_))); } return value_reg; } @@ -907,10 +906,13 @@ void EmitTSANAwareStore(Zone* zone, CodeGenerator* codegen, class OutOfLineTSANRelaxedLoad final : public OutOfLineCode { public: OutOfLineTSANRelaxedLoad(CodeGenerator* gen, Operand operand, - Register scratch0, StubCallMode stub_mode, int size) + Register scratch0, + std::optional<SharedBaseTsanArgument> shared_base, + StubCallMode stub_mode, int size) : OutOfLineCode(gen), operand_(operand), scratch0_(scratch0), + shared_base_(shared_base), #if V8_ENABLE_WEBASSEMBLY stub_mode_(stub_mode), #endif // V8_ENABLE_WEBASSEMBLY @@ -929,19 +931,20 @@ class OutOfLineTSANRelaxedLoad final : public OutOfLineCode { // A direct call to a wasm runtime stub defined in this module. // Just encode the stub index. This will be patched when the code // is added to the native module and copied into wasm code space. - __ CallTSANRelaxedLoadStub(scratch0_, save_fp_mode, size_, + __ CallTSANRelaxedLoadStub(scratch0_, shared_base_, save_fp_mode, size_, StubCallMode::kCallWasmRuntimeStub); return; } #endif // V8_ENABLE_WEBASSEMBLY - __ CallTSANRelaxedLoadStub(scratch0_, save_fp_mode, size_, + __ CallTSANRelaxedLoadStub(scratch0_, shared_base_, save_fp_mode, size_, StubCallMode::kCallBuiltinPointer); } private: Operand const operand_; Register const scratch0_; + std::optional<SharedBaseTsanArgument> const shared_base_; #if V8_ENABLE_WEBASSEMBLY StubCallMode const stub_mode_; #endif // V8_ENABLE_WEBASSEMBLY @@ -949,10 +952,10 @@ class OutOfLineTSANRelaxedLoad final : public OutOfLineCode { Zone* zone_; }; -void EmitTSANRelaxedLoadOOLIfNeeded(Zone* zone, CodeGenerator* codegen, - MacroAssembler* masm, Operand operand, - X64OperandConverter& i, StubCallMode mode, - int size) { +void EmitTSANRelaxedLoadOOLIfNeeded( + Zone* zone, CodeGenerator* codegen, MacroAssembler* masm, Operand operand, + std::optional<SharedBaseTsanArgument> shared_base, X64OperandConverter& i, + StubCallMode mode, int size) { // The FOR_TESTING code doesn't initialize the root register. We can't call // the TSAN builtin since we need to load the external reference through the // root register. @@ -961,8 +964,8 @@ void EmitTSANRelaxedLoadOOLIfNeeded(Zone* zone, CodeGenerator* codegen, if (codegen->code_kind() == CodeKind::FOR_TESTING) return; Register scratch0 = i.TempRegister(0); - auto tsan_ool = zone->New<OutOfLineTSANRelaxedLoad>(codegen, operand, - scratch0, mode, size); + auto tsan_ool = zone->New<OutOfLineTSANRelaxedLoad>( + codegen, operand, scratch0, shared_base, mode, size); masm->jmp(tsan_ool->entry()); masm->bind(tsan_ool->exit()); } @@ -1008,10 +1011,10 @@ void EmitTSANAwareStore(Zone* zone, CodeGenerator* codegen, } } -void EmitTSANRelaxedLoadOOLIfNeeded(Zone* zone, CodeGenerator* codegen, - MacroAssembler* masm, Operand operand, - X64OperandConverter& i, StubCallMode mode, - int size) {} +void EmitTSANRelaxedLoadOOLIfNeeded( + Zone* zone, CodeGenerator* codegen, MacroAssembler* masm, Operand operand, + std::optional<SharedBaseTsanArgument> shared_base, X64OperandConverter& i, + StubCallMode mode, int size) {} #endif // V8_IS_TSAN } // namespace @@ -1654,6 +1657,20 @@ void CodeGenerator::AssemblePlaceHolderForLazyDeopt(Instruction* instr) { } } +namespace { +std::optional<SharedBaseTsanArgument> MakeSharedBaseTsanArgument( + Instruction* instr, X64OperandConverter& i) { + if (!instr->shared_base()) return {}; + // For those two modes, the cage base is used as a base for the load, and the + // first register argument (the object) is used as the index. For that reason, + // the object is kept compressed, so we must uncompress it before passing it + // to the builtin. + bool must_decompress_pointer = instr->addressing_mode() == kMode_MCR || + instr->addressing_mode() == kMode_MCRI; + return {{i.InputRegister(0), must_decompress_pointer}}; +} +} // namespace + // Assembles an instruction after register allocation, producing machine code. CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Instruction* instr) { @@ -1801,8 +1818,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } case kArchCallJSFunction: { static_assert(kJavaScriptCallCodeStartRegister == rcx, "ABI mismatch"); - uint32_t num_arguments = - i.InputUint32(instr->JSCallArgumentCountInputIndex()); + uint32_t expected_parameter_count = + i.InputUint32(instr->JSCallExpectedParameterCountInputIndex()); if (HasImmediateInput(instr, 0)) { Handle<HeapObject> constant = i.ToConstant(instr->InputAt(0)).ToHeapObject(); @@ -1812,7 +1829,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Builtin builtin = function->shared()->builtin_id(); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (Builtins::IsCompatibleJSBuiltin(builtin, num_arguments)) { + if (Builtins::IsCompatibleJSBuiltin(builtin, + expected_parameter_count)) { __ CallBuiltin(builtin); } else { __ Abort(AbortReason::kJSSignatureMismatch); @@ -1824,7 +1842,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( dispatch_handle); // Defer signature mismatch abort to run-time as optimized // unreachable calls can have mismatched signatures. - if (num_arguments >= expected) { + if (expected_parameter_count == expected) { __ RecordJSDispatchHandle(dispatch_handle, expected); __ CallJSDispatchEntry(dispatch_handle, expected); } else { @@ -1832,7 +1850,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } } } else { - __ CallJSFunction(kJavaScriptCallTargetRegister, num_arguments); + __ CallJSFunction(kJavaScriptCallTargetRegister, + expected_parameter_count); } } else { Register func = i.InputRegister(0); @@ -1842,7 +1861,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( FieldOperand(func, offsetof(JSFunction, context_))); __ Assert(equal, AbortReason::kWrongFunctionContext); } - __ CallJSFunction(func, num_arguments); + __ CallJSFunction(func, expected_parameter_count); } frame_access_state()->ClearSPDelta(); RecordCallPosition(instr); @@ -2084,7 +2103,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( // here. RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); // Indirect pointer writes must use a different opcode. - DCHECK_NE(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_NE(mode, RecordWriteMode::kValueIsTrustedPointer); Register object = i.InputRegister(0); size_t index = 0; Operand operand = i.MemoryOperand(&index); @@ -2160,16 +2179,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( } break; } - case kArchStoreIndirectWithWriteBarrier: { + case kArchStoreTrustedWithWriteBarrier: { RecordWriteMode mode = RecordWriteModeField::decode(instr->opcode()); - DCHECK_EQ(mode, RecordWriteMode::kValueIsIndirectPointer); + DCHECK_EQ(mode, RecordWriteMode::kValueIsTrustedPointer); Register object = i.InputRegister(0); size_t index = 0; Operand operand = i.MemoryOperand(&index); Register value = i.InputRegister(index++); - IndirectPointerTag tag = - static_cast<IndirectPointerTag>(i.InputInt64(index)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = + static_cast<TrustedPointerTag>(i.InputInt64(index)); + DCHECK(IsValidTrustedPointerTag(tag)); Register scratch0 = i.TempRegister(0); Register scratch1 = i.TempRegister(1); @@ -2178,31 +2197,31 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( DetermineStubCallMode(), tag); EmitTSANAwareStore<std::memory_order_relaxed>( zone(), this, masm(), operand, value, i, DetermineStubCallMode(), - MachineRepresentation::kIndirectPointer, instr); + MachineRepresentation::kTrustedPointer, instr); __ JumpIfMarking(ool->entry()); __ bind(ool->exit()); break; } - case kArchStoreIndirectSkippedWriteBarrier: { + case kArchStoreTrustedSkippedWriteBarrier: { Register object = i.InputRegister(0); size_t index = 0; Operand operand = i.MemoryOperand(&index); Register value = i.InputRegister(index++); #if DEBUG - IndirectPointerTag tag = - static_cast<IndirectPointerTag>(i.InputInt64(index)); - DCHECK(IsValidIndirectPointerTag(tag)); + TrustedPointerTag tag = + static_cast<TrustedPointerTag>(i.InputInt64(index)); + DCHECK(IsValidTrustedPointerTag(tag)); #endif // DEBUG DCHECK(v8_flags.verify_write_barriers); - auto ool = zone()->New<OutOfLineVerifySkippedIndirectWriteBarrier>( + auto ool = zone()->New<OutOfLineVerifySkippedTrustedWriteBarrier>( this, object, value); __ jmp(ool->entry()); __ bind(ool->exit()); EmitTSANAwareStore<std::memory_order_relaxed>( zone(), this, masm(), operand, value, i, DetermineStubCallMode(), - MachineRepresentation::kIndirectPointer, instr); + MachineRepresentation::kTrustedPointer, instr); break; } case kX64MFence: @@ -2569,9 +2588,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kSSEFloat32Div: RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); ASSEMBLE_SSE_BINOP(divss); - // Don't delete this mov. It may improve performance on some CPUs, - // when there is a (v)mulss depending on the result. - __ movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); break; case kSSEFloat32Sqrt: ASSEMBLE_SSE_UNOP(sqrtss); @@ -2619,9 +2635,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kSSEFloat64Div: RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); ASSEMBLE_SSE_BINOP(divsd); - // Don't delete this mov. It may improve performance on some CPUs, - // when there is a (v)mulsd depending on the result. - __ Movapd(i.OutputDoubleRegister(), i.OutputDoubleRegister()); break; case kSSEFloat64Mod: { __ AllocateStackSpace(kDoubleSize); @@ -3136,9 +3149,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kAVXFloat32Div: RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); ASSEMBLE_AVX_BINOP(vdivss); - // Don't delete this mov. It may improve performance on some CPUs, - // when there is a (v)mulss depending on the result. - __ Movaps(i.OutputDoubleRegister(), i.OutputDoubleRegister()); break; case kAVXFloat64Cmp: { CpuFeatureScope avx_scope(masm(), AVX); @@ -3164,9 +3174,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( case kAVXFloat64Div: RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); ASSEMBLE_AVX_BINOP(vdivsd); - // Don't delete this mov. It may improve performance on some CPUs, - // when there is a (v)mulsd depending on the result. - __ Movapd(i.OutputDoubleRegister(), i.OutputDoubleRegister()); break; case kX64Float32Abs: { __ Absps(i.OutputDoubleRegister(), i.InputDoubleRegister(0), @@ -3309,8 +3316,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kSSEFloat64SilenceNaN: - __ Xorpd(kScratchDoubleReg, kScratchDoubleReg); - __ Subsd(i.InputDoubleRegister(0), kScratchDoubleReg); + __ CanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); break; case kX64Movsxbl: RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); @@ -3388,8 +3394,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( if (HasAddressingMode(instr)) { Operand address(i.MemoryOperand()); __ movl(i.OutputRegister(), address); - EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, i, - DetermineStubCallMode(), kInt32Size); + EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, + MakeSharedBaseTsanArgument(instr, i), + i, DetermineStubCallMode(), + kInt32Size); } else { if (HasRegisterInput(instr, 0)) { __ movl(i.OutputRegister(), i.InputRegister(0)); @@ -3424,11 +3432,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register base = i.InputRegister(0); int32_t offset = i.InputInt32(1); Register table = i.InputRegister(2); - IndirectPointerTag first = - static_cast<IndirectPointerTag>(i.InputInt32(3)); - IndirectPointerTag last = - static_cast<IndirectPointerTag>(i.InputInt32(4)); - IndirectPointerTagRange tag_range(first, last); + TrustedPointerTag first = static_cast<TrustedPointerTag>(i.InputInt32(3)); + TrustedPointerTag last = static_cast<TrustedPointerTag>(i.InputInt32(4)); + TrustedPointerTagRange tag_range(first, last); Register destination = i.OutputRegister(); Register handle = i.TempRegister(0); @@ -3439,9 +3445,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( static_assert(kTrustedPointerTableEntrySizeLog2 == times_8); __ movq(destination, Operand{table, handle, times_8, 0}); - if (IsFastIndirectPointerTagRange(tag_range)) { - uint64_t mask = - ComputeUntaggingMaskForFastIndirectPointerTag(tag_range); + if (IsFastTrustedPointerTagRange(tag_range)) { + uint64_t mask = ComputeUntaggingMaskForFastTrustedPointerTag(tag_range); __ movq(kScratchRegister, Immediate64(mask)); __ andq(destination, kScratchRegister); } else { @@ -3470,7 +3475,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); Operand address(i.MemoryOperand()); __ DecompressTaggedSigned(i.OutputRegister(), address); - EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, i, + EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, + MakeSharedBaseTsanArgument(instr, i), i, DetermineStubCallMode(), kTaggedSize); break; } @@ -3479,7 +3485,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); Operand address(i.MemoryOperand()); __ DecompressTagged(i.OutputRegister(), address); - EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, i, + EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, + MakeSharedBaseTsanArgument(instr, i), i, DetermineStubCallMode(), kTaggedSize); break; } @@ -3506,11 +3513,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( CHECK(instr->HasOutput()); Operand address(i.MemoryOperand()); __ DecompressProtected(i.OutputRegister(), address); - EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, i, + DCHECK(!instr->shared_base()); + EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, {}, i, DetermineStubCallMode(), kTaggedSize); break; } - case kX64MovqStoreIndirectPointer: { + case kX64MovqStoreTrustedPointer: { CHECK(!instr->HasOutput()); size_t index = 0; Operand operand = i.MemoryOperand(&index); @@ -3518,7 +3526,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register value(i.InputRegister(index)); EmitTSANAwareStore<std::memory_order_relaxed>( zone(), this, masm(), operand, value, i, DetermineStubCallMode(), - MachineRepresentation::kIndirectPointer, instr); + MachineRepresentation::kTrustedPointer, instr); break; } case kX64MovqDecodeSandboxedPointer: { @@ -3527,7 +3535,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( Register dst = i.OutputRegister(); __ movq(dst, address); __ DecodeSandboxedPointer(dst); - EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, i, + DCHECK(!instr->shared_base()); + EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, {}, i, DetermineStubCallMode(), kSystemPointerSize); break; @@ -3548,7 +3557,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( RecordTrapInfoIfNeeded(zone(), this, opcode, instr, __ pc_offset()); Operand address(i.MemoryOperand()); __ movq(i.OutputRegister(), address); - EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, i, + EmitTSANRelaxedLoadOOLIfNeeded(zone(), this, masm(), address, + MakeSharedBaseTsanArgument(instr, i), i, DetermineStubCallMode(), kInt64Size); } else { size_t index = 0; @@ -3822,12 +3832,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( if (vec_len == VectorLength::kV128) { switch (lane_size) { case LaneSize::kL16: { - CpuFeatureScope f16c_scope(masm(), F16C); - CpuFeatureScope avx2_scope(masm(), AVX2); - __ vcvtps2ph(i.OutputDoubleRegister(0), i.InputDoubleRegister(0), - 0); - __ vpbroadcastw(i.OutputSimd128Register(), - i.OutputDoubleRegister(0)); + __ F16x8Splat(i.OutputSimd128Register(), i.InputDoubleRegister(0)); break; } case LaneSize::kL32: { @@ -4019,7 +4024,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( switch (lane_size) { case LaneSize::kL16: // F16x8Add - ASSEMBLE_SIMD_F16x8_BINOP(vaddps); + if (UseAvx10_1()) { + CpuFeatureScope avx10_1_scope(masm(), AVX10_1); + __ vaddph(i.OutputSimd128Register(), i.InputSimd128Register(0), + i.InputSimd128Register(1)); + } else { + ASSEMBLE_SIMD_F16x8_BINOP(vaddps); + } break; case LaneSize::kL32: { // F32x4Add @@ -4061,7 +4072,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( switch (lane_size) { case LaneSize::kL16: // F16x8Sub - ASSEMBLE_SIMD_F16x8_BINOP(vsubps); + if (UseAvx10_1()) { + CpuFeatureScope avx10_1_scope(masm(), AVX10_1); + __ vsubph(i.OutputSimd128Register(), i.InputSimd128Register(0), + i.InputSimd128Register(1)); + } else { + ASSEMBLE_SIMD_F16x8_BINOP(vsubps); + } break; case LaneSize::kL32: { // F32x4Sub @@ -4543,10 +4560,6 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kX64I16x8SConvertF16x8: { - CpuFeatureScope avx_scope(masm(), AVX); - CpuFeatureScope f16c_scope(masm(), F16C); - CpuFeatureScope avx2_scope(masm(), AVX2); - YMMRegister ydst = YMMRegister::from_code(i.OutputSimd128Register().code()); __ I16x8SConvertF16x8(ydst, i.InputSimd128Register(0), kScratchSimd256Reg, @@ -4554,31 +4567,19 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kX64I16x8UConvertF16x8: { - CpuFeatureScope avx_scope(masm(), AVX); - CpuFeatureScope f16c_scope(masm(), F16C); - CpuFeatureScope avx2_scope(masm(), AVX2); - YMMRegister ydst = YMMRegister::from_code(i.OutputSimd128Register().code()); __ I16x8TruncF16x8U(ydst, i.InputSimd128Register(0), kScratchSimd256Reg); break; } case kX64F16x8SConvertI16x8: { - CpuFeatureScope f16c_scope(masm(), F16C); - CpuFeatureScope avx_scope(masm(), AVX); - CpuFeatureScope avx2_scope(masm(), AVX2); - __ vpmovsxwd(kScratchSimd256Reg, i.InputSimd128Register(0)); - __ vcvtdq2ps(kScratchSimd256Reg, kScratchSimd256Reg); - __ vcvtps2ph(i.OutputSimd128Register(), kScratchSimd256Reg, 0); + __ F16x8SConvertI16x8(i.OutputSimd128Register(), + i.InputSimd128Register(0), kScratchSimd256Reg); break; } case kX64F16x8UConvertI16x8: { - CpuFeatureScope f16c_scope(masm(), F16C); - CpuFeatureScope avx_scope(masm(), AVX); - CpuFeatureScope avx2_scope(masm(), AVX2); - __ vpmovzxwd(kScratchSimd256Reg, i.InputSimd128Register(0)); - __ vcvtdq2ps(kScratchSimd256Reg, kScratchSimd256Reg); - __ vcvtps2ph(i.OutputSimd128Register(), kScratchSimd256Reg, 0); + __ F16x8UConvertI16x8(i.OutputSimd128Register(), + i.InputSimd128Register(0), kScratchSimd256Reg); break; } case kX64F16x8DemoteF32x4Zero: { @@ -4670,6 +4671,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kX64F16x8Qfma: { + if (UseAvx10_1()) { + CpuFeatureScope avx10_scope(masm(), AVX10_1); + DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0)); + if (instr->InputAt(2)->IsSimd128Register()) { + __ vfmadd213ph(i.OutputSimd128Register(), i.InputSimd128Register(1), + i.InputSimd128Register(2)); + } else { + __ vfmadd213ph(i.OutputSimd128Register(), i.InputSimd128Register(1), + i.InputOperand(2)); + } + break; + } YMMRegister ydst = YMMRegister::from_code(i.OutputSimd128Register().code()); __ F16x8Qfma(ydst, i.InputSimd128Register(0), i.InputSimd128Register(1), @@ -4678,6 +4691,18 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( break; } case kX64F16x8Qfms: { + if (UseAvx10_1()) { + CpuFeatureScope avx10_scope(masm(), AVX10_1); + DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0)); + if (instr->InputAt(2)->IsSimd128Register()) { + __ vfnmadd213ph(i.OutputSimd128Register(), i.InputSimd128Register(1), + i.InputSimd128Register(2)); + } else { + __ vfnmadd213ph(i.OutputSimd128Register(), i.InputSimd128Register(1), + i.InputOperand(2)); + } + break; + } YMMRegister ydst = YMMRegister::from_code(i.OutputSimd128Register().code()); __ F16x8Qfms(ydst, i.InputSimd128Register(0), i.InputSimd128Register(1), @@ -8370,56 +8395,55 @@ void CodeGenerator::FinishFrame(Frame* frame) { if (!saves.is_empty()) { // Save callee-saved registers. frame->AllocateSavedCalleeRegisterSlots(saves.Count()); } - if (v8_flags.enforce_x64_16byte_alignment) { + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { frame->AlignFrame(2 * kSystemPointerSize); } } void CodeGenerator::AssembleConstructFrame() { + DCHECK(frame_access_state()->has_frame()); auto call_descriptor = linkage()->GetIncomingDescriptor(); - if (v8_flags.enforce_x64_16byte_alignment) { + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { // The frame has been previously padded in CodeGenerator::FinishFrame(). DCHECK_EQ(frame()->GetTotalFrameSlotCount() % 2, 0); DCHECK_EQ(frame()->GetReturnSlotCount() % 2, 0); } - if (frame_access_state()->has_frame()) { - int pc_base = __ pc_offset(); + int pc_base = __ pc_offset(); - if (call_descriptor->IsCFunctionCall()) { - __ pushq(rbp); - __ movq(rbp, rsp); + if (call_descriptor->IsCFunctionCall()) { + __ pushq(rbp); + __ movq(rbp, rsp); #if V8_ENABLE_WEBASSEMBLY - if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { - __ Push(Immediate(StackFrame::TypeToMarker(StackFrame::C_WASM_ENTRY))); - // Reserve stack space for saving the c_entry_fp later. - __ AllocateStackSpace(kSystemPointerSize); - } + if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) { + __ Push(Immediate(StackFrame::TypeToMarker(StackFrame::C_WASM_ENTRY))); + // Reserve stack space for saving the c_entry_fp later. + __ AllocateStackSpace(kSystemPointerSize); + } #endif // V8_ENABLE_WEBASSEMBLY - } else if (call_descriptor->IsJSFunctionCall()) { - __ Prologue(); - } else { - __ StubPrologue(info()->GetOutputStackFrameType()); + } else if (call_descriptor->IsJSFunctionCall()) { + __ Prologue(); + } else { + __ StubPrologue(info()->GetOutputStackFrameType()); #if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() || - call_descriptor->IsWasmImportWrapper() || - call_descriptor->IsWasmCapiFunction()) { - // For import wrappers and C-API functions, this stack slot is only used - // for printing stack traces in V8. Also, it holds a WasmImportData - // instead of the trusted instance data, which is taken care of in the - // frames accessors. - __ pushq(kWasmImplicitArgRegister); - } - if (call_descriptor->IsWasmCapiFunction()) { - // Reserve space for saving the PC later. - __ AllocateStackSpace(kSystemPointerSize); - } -#endif // V8_ENABLE_WEBASSEMBLY + if (call_descriptor->IsAnyWasmFunctionCall() || + call_descriptor->IsWasmImportWrapper() || + call_descriptor->IsWasmCapiFunction()) { + // For import wrappers and C-API functions, this stack slot is only used + // for printing stack traces in V8. Also, it holds a WasmImportData + // instead of the trusted instance data, which is taken care of in the + // frames accessors. + __ pushq(kWasmImplicitArgRegister); + } + if (call_descriptor->IsWasmCapiFunction()) { + // Reserve space for saving the PC later. + __ AllocateStackSpace(kSystemPointerSize); } - - unwinding_info_writer_.MarkFrameConstructed(pc_base); +#endif // V8_ENABLE_WEBASSEMBLY } + + unwinding_info_writer_.MarkFrameConstructed(pc_base); int required_slots = frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount(); @@ -8449,76 +8473,95 @@ void CodeGenerator::AssembleConstructFrame() { const RegList saves = call_descriptor->CalleeSavedRegisters(); const DoubleRegList saves_fp = call_descriptor->CalleeSavedFPRegisters(); - if (required_slots > 0) { - DCHECK(frame_access_state()->has_frame()); #if V8_ENABLE_WEBASSEMBLY - int32_t stack_space = - required_slots * kSystemPointerSize + GetStackCheckOffset(); - if (info()->IsWasm() && stack_space > 4 * KB) { - // For WebAssembly functions with big frames we have to do the stack - // overflow check before we construct the frame. Otherwise we may not - // have enough space on the stack to call the runtime for the stack - // overflow. - Label done; - - // If the frame is bigger than the stack, we throw the stack overflow - // exception unconditionally. Thereby we can avoid the integer overflow - // check in the condition code. - if (stack_space < v8_flags.stack_size * KB) { + const bool is_js_to_wasm = code_kind() == CodeKind::JS_TO_WASM_FUNCTION; + DCHECK_GE(required_slots, 0); + size_t stack_space = + static_cast<size_t>(required_slots) * kSystemPointerSize + + GetStackCheckOffset(); + if (is_js_to_wasm || (info()->IsWasm() && stack_space > 4 * KB)) { + // For WebAssembly functions with big frames we have to do the stack + // overflow check before we allocate the frame slots. Otherwise we may not + // have enough space on the stack to call the runtime for the stack + // overflow. + // For compiled JS-to-Wasm wrappers, we unconditionally emit a stack check + // here because they are entered directly from JavaScript without an + // Ignition bytecode stack check, and may be invoked near stack exhaustion. + Label done; + + // If the frame is bigger than the stack, we throw the stack overflow + // exception unconditionally. Thereby we can avoid the integer overflow + // check in the condition code. + if (stack_space < static_cast<size_t>(v8_flags.stack_size) * KB) { + if (stack_space == 0) { + __ cmpq(rsp, __ StackLimitAsOperand(StackLimitKind::kRealStackLimit)); + } else { __ movq(kScratchRegister, __ StackLimitAsOperand(StackLimitKind::kRealStackLimit)); - __ addq(kScratchRegister, Immediate(stack_space)); + __ addq(kScratchRegister, Immediate(static_cast<int32_t>(stack_space))); __ cmpq(rsp, kScratchRegister); - __ j(above_equal, &done, Label::kNear); - } - - if (v8_flags.wasm_growable_stacks) { - RegList regs_to_save; - regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); - regs_to_save.set( - WasmHandleStackOverflowDescriptor::FrameBaseRegister()); - for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); - __ PushAll(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); - __ PushAll(fp_regs_to_save); - __ movq(WasmHandleStackOverflowDescriptor::GapRegister(), - Immediate(stack_space)); - __ movq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), rbp); - __ addq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), - Immediate(static_cast<int32_t>( - call_descriptor->ParameterSlotCount() * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp))); - __ near_call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), - RelocInfo::WASM_STUB_CALL); - // If the call successfully grew the stack, we don't expect it to have - // allocated any heap objects or otherwise triggered any GC. - // If it was not able to grow the stack, it may have triggered a GC when - // allocating the stack overflow exception object, but the call did not - // return in this case. - // So either way, we can just record an empty safepoint here. - RecordSafepointWithoutTaggedSlots(); - __ PopAll(fp_regs_to_save); - __ PopAll(regs_to_save); - } else { - __ near_call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), - RelocInfo::WASM_STUB_CALL); - // The call does not return, hence we can ignore any references and just - // define an empty safepoint. - RecordSafepointWithoutTaggedSlots(); - __ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap); - } - __ bind(&done); + } + __ j(above_equal, &done, Label::kNear); + } + + if (is_js_to_wasm) { + __ CallRuntime(Runtime::kThrowStackOverflow); + // RecordSafepointWithoutTaggedSlots is safe here because no tagged spill + // slots or parameters have been allocated on the stack frame yet. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromThrow); + } else if (v8_flags.wasm_growable_stacks) { + RegList regs_to_save; + regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); + regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); + for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg); + __ PushAll(regs_to_save); + DoubleRegList fp_regs_to_save; + for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg); + __ PushAll(fp_regs_to_save); + __ movq(WasmHandleStackOverflowDescriptor::GapRegister(), + Immediate(static_cast<int32_t>(stack_space))); + __ movq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), rbp); + __ addq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), + Immediate(static_cast<int32_t>( + (call_descriptor->ParameterSlotCount() + + call_descriptor->ReturnSlotCount()) * + kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp))); + __ movq(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Immediate(static_cast<int32_t>( + call_descriptor->ParameterSlotCount() * kSystemPointerSize))); + __ near_call(static_cast<Address>(Builtin::kWasmHandleStackOverflow), + RelocInfo::WASM_STUB_CALL); + // If the call successfully grew the stack, we don't expect it to have + // allocated any heap objects or otherwise triggered any GC. + // If it was not able to grow the stack, it may have triggered a GC when + // allocating the stack overflow exception object, but the call did not + // return in this case. + // So either way, we can just record an empty safepoint here. + RecordSafepointWithoutTaggedSlots(); + __ PopAll(fp_regs_to_save); + __ PopAll(regs_to_save); + } else { + __ near_call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), + RelocInfo::WASM_STUB_CALL); + // The call does not return, hence we can ignore any references and just + // define an empty safepoint. + RecordSafepointWithoutTaggedSlots(); + __ AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap); } + __ bind(&done); + } #endif // V8_ENABLE_WEBASSEMBLY - // Skip callee-saved and return slots, which are created below. - required_slots -= saves.Count(); - required_slots -= saves_fp.Count() * (kQuadWordSize / kSystemPointerSize); - required_slots -= frame()->GetReturnSlotCount(); - if (required_slots > 0) { - __ AllocateStackSpace(required_slots * kSystemPointerSize); - } + // Skip callee-saved and return slots, which are created below. + required_slots -= saves.Count(); + required_slots -= saves_fp.Count() * (kQuadWordSize / kSystemPointerSize); + required_slots -= frame()->GetReturnSlotCount(); + if (required_slots > 0) { + __ AllocateStackSpace(required_slots * kSystemPointerSize); } if (!saves_fp.is_empty()) { // Save callee-saved XMM registers. @@ -8596,31 +8639,6 @@ void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) { } } -#if V8_ENABLE_WEBASSEMBLY - if (call_descriptor->IsAnyWasmFunctionCall() && - v8_flags.wasm_growable_stacks) { - __ cmpq( - MemOperand(rbp, TypedFrameConstants::kFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - Label done; - __ j(not_equal, &done); - RegList regs_to_save; - for (auto reg : wasm::kGpReturnRegisters) regs_to_save.set(reg); - __ PushAll(regs_to_save); - DoubleRegList fp_regs_to_save; - for (auto reg : wasm::kFpReturnRegisters) fp_regs_to_save.set(reg); - __ PushAll(fp_regs_to_save); - __ PrepareCallCFunction(1); - __ LoadAddress(kCArgRegs[0], ExternalReference::isolate_address()); - __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP inside of AssembleDeconstructFrame. - __ movq(rbp, kReturnRegister0); - __ PopAll(fp_regs_to_save); - __ PopAll(regs_to_save); - __ bind(&done); - } -#endif // V8_ENABLE_WEBASSEMBLY Register argc_reg = rcx; // Functions with JS linkage have at least one parameter (the receiver). diff --git a/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h b/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h index 2d8d8c4878e8..bc6207a304f2 100644 --- a/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h +++ b/deps/v8/src/compiler/backend/x64/instruction-codes-x64.h @@ -191,7 +191,7 @@ namespace compiler { V(X64Float64Neg) \ V(X64Float32Abs) \ V(X64Float32Neg) \ - V(X64MovqStoreIndirectPointer) \ + V(X64MovqStoreTrustedPointer) \ V(X64MovqEncodeSandboxedPointer) \ V(X64MovqDecodeSandboxedPointer) \ V(X64BitcastFI) \ diff --git a/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc b/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc index 74a9645efbe5..b15ee4a1e541 100644 --- a/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc +++ b/deps/v8/src/compiler/backend/x64/instruction-scheduler-x64.cc @@ -404,7 +404,7 @@ int InstructionScheduler::GetTargetInstructionFlags( case kX64MovqDecompressTagged: case kX64MovqDecompressProtected: case kX64MovqCompressTagged: - case kX64MovqStoreIndirectPointer: + case kX64MovqStoreTrustedPointer: case kX64MovqDecodeSandboxedPointer: case kX64MovqEncodeSandboxedPointer: case kX64Movq: diff --git a/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc b/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc index e13d8b99d851..97a66ee51e03 100644 --- a/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc +++ b/deps/v8/src/compiler/backend/x64/instruction-selector-x64.cc @@ -902,8 +902,6 @@ ArchOpcode GetLoadOpcode(MemoryRepresentation loaded_rep, case MemoryRepresentation::ProtectedPointer(): CHECK(V8_ENABLE_SANDBOX_BOOL); return kX64MovqDecompressProtected; - case MemoryRepresentation::IndirectPointer(): - UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): // Only LoadTrustedPointer uses this representation. UNREACHABLE(); @@ -980,7 +978,7 @@ ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) { break; case MachineRepresentation::kNone: // Fall through. case MachineRepresentation::kMapWord: // Fall through. - case MachineRepresentation::kIndirectPointer: // Fall through. + case MachineRepresentation::kTrustedPointer: // Fall through. case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); } @@ -1019,10 +1017,7 @@ ArchOpcode GetStoreOpcode(MemoryRepresentation stored_rep) { // We never store directly to protected pointers from generated code. UNREACHABLE(); case MemoryRepresentation::TrustedPointer(): - // Only LoadTrustedPointer uses this representation. - UNREACHABLE(); - case MemoryRepresentation::IndirectPointer(): - return kX64MovqStoreIndirectPointer; + return kX64MovqStoreTrustedPointer; case MemoryRepresentation::SandboxedPointer(): return kX64MovqEncodeSandboxedPointer; case MemoryRepresentation::Simd128(): @@ -1410,6 +1405,9 @@ void InstructionSelector::VisitLoad(OpIndex node, OpIndex value, if (load.is_trapping()) { code |= AccessModeField::encode(kMemoryAccessTrapping); } + if (load.has_shared_base()) { + code |= SharedBaseField::encode(SharedFlag{true}); + } } Emit(code, 1, outputs, input_count, inputs, temp_count, temps); } @@ -1483,8 +1481,7 @@ void VisitStoreCommon(InstructionSelector* selector, if (write_barrier_kind != kNoWriteBarrier && !v8_flags.disable_write_barriers) { - DCHECK( - CanBeTaggedOrCompressedOrIndirectPointer(store_rep.representation())); + DCHECK(CanBeTaggedOrCompressedOrTrustedPointer(store_rep.representation())); // Uncompressed stores should not happen if we need a write barrier. CHECK((store.ts_stored_rep() != MemoryRepresentation::AnyUncompressedTagged()) && @@ -1503,16 +1500,16 @@ void VisitStoreCommon(InstructionSelector* selector, inputs[input_count++] = g.UseUniqueRegister(value); InstructionOperand temps[] = {g.TempRegister(), g.TempRegister()}; InstructionCode code; - if (store_rep.representation() == MachineRepresentation::kIndirectPointer) { - DCHECK(write_barrier_kind == kIndirectPointerWriteBarrier || + if (store_rep.representation() == MachineRepresentation::kTrustedPointer) { + DCHECK(write_barrier_kind == kTrustedPointerWriteBarrier || write_barrier_kind == kSkippedWriteBarrier); - // In this case we need to add the IndirectPointerTag as additional input. + // In this case we need to add the TrustedPointerTag as additional input. code = write_barrier_kind == kSkippedWriteBarrier - ? kArchStoreIndirectSkippedWriteBarrier - : kArchStoreIndirectWithWriteBarrier; - code |= RecordWriteModeField::encode( - RecordWriteMode::kValueIsIndirectPointer); - IndirectPointerTag tag = store.indirect_pointer_tag(); + ? kArchStoreTrustedSkippedWriteBarrier + : kArchStoreTrustedWithWriteBarrier; + code |= + RecordWriteModeField::encode(RecordWriteMode::kValueIsTrustedPointer); + TrustedPointerTag tag = store.trusted_pointer_tag(); inputs[input_count++] = g.UseImmediate64(static_cast<int64_t>(tag)); } else if (write_barrier_kind == kSkippedWriteBarrier) { code = is_atomic ? kArchAtomicStoreSkippedWriteBarrier @@ -1869,7 +1866,6 @@ void InstructionSelector::VisitStackPointerGreaterThan( namespace { // Shared routine for multiple 32-bit shift operations. -// TODO(bmeurer): Merge this with VisitWord64Shift using template magic? void VisitWord32Shift(InstructionSelector* selector, OpIndex node, ArchOpcode opcode) { X64OperandGenerator g(selector); @@ -1892,7 +1888,6 @@ void VisitWord32Shift(InstructionSelector* selector, OpIndex node, } // Shared routine for multiple 64-bit shift operations. -// TODO(bmeurer): Merge this with VisitWord32Shift using template magic? void VisitWord64Shift(InstructionSelector* selector, OpIndex node, ArchOpcode opcode) { X64OperandGenerator g(selector); @@ -2258,23 +2253,14 @@ void InstructionSelector::VisitInt32Sub(OpIndex node) { auto [left, right] = Inputs<WordBinopOp>(node); if (g.CanBeImmediate(right)) { int32_t imm = g.GetImmediateIntegerValue(right); - if (imm == 0) { - if (ZeroExtendsWord32ToWord64(left)) { - // {EmitIdentity} reuses the virtual register of the first input - // for the output. This is only safe if it is known to zero-extend - // (as the int32 subtraction advertises itself as zero-extending.) - EmitIdentity(node); - } else { - // Emit "movl" for subtraction of 0. - Emit(kX64Movl, g.DefineAsRegister(node), g.UseRegister(left)); - } - } else { - // Omit truncation and turn subtractions of constant values into immediate - // "leal" instructions by negating the value. - Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), - g.DefineAsRegister(node), g.UseRegister(left), - g.TempImmediate(base::NegateWithWraparound(imm))); - } + // This is guaranteed by the InstructionSelectionNormalizationReducer. If + // this DCHECK fails, it indicates a missed optimization only. + DCHECK_NE(imm, 0); + // Omit truncation and turn subtractions of constant values into immediate + // "leal" instructions by negating the value. + Emit(kX64Lea32 | AddressingModeField::encode(kMode_MRI), + g.DefineAsRegister(node), g.UseRegister(left), + g.TempImmediate(base::NegateWithWraparound(imm))); return; } @@ -2297,6 +2283,9 @@ void InstructionSelector::VisitInt64Sub(OpIndex node) { } if (auto constant = TryGetRightWordConstant(this, node)) { int64_t immediate_value = -*constant; + // This is guaranteed by the InstructionSelectionNormalizationReducer. If + // this DCHECK fails, it indicates a missed optimization only. + DCHECK_NE(immediate_value, 0); if (ValueFitsIntoImmediate(immediate_value)) { // Turn subtractions of constant values into immediate "leaq" instructions // by negating the value. @@ -3798,7 +3787,7 @@ void VisitWordCompare(InstructionSelector* selector, OpIndex node, void VisitWord64EqualImpl(InstructionSelector* selector, OpIndex node, FlagsContinuation* cont) { - if (selector->CanUseRootsRegister()) { + if (selector->isolate() != nullptr) { X64OperandGenerator g(selector); const RootsTable& roots_table = selector->isolate()->roots_table(); RootIndex root_index; @@ -3855,16 +3844,13 @@ void VisitWord32EqualImpl(InstructionSelector* selector, OpIndex node, root_index, selector->isolate())), cont); } - if (selector->CanUseRootsRegister()) { - InstructionCode opcode = - kX64Cmp32 | AddressingModeField::encode(kMode_Root); - return VisitCompare( - selector, opcode, - g.TempImmediate( - MacroAssemblerBase::RootRegisterOffsetForRootIndex( - root_index)), - g.UseRegister(left), cont); - } + InstructionCode opcode = + kX64Cmp32 | AddressingModeField::encode(kMode_Root); + return VisitCompare( + selector, opcode, + g.TempImmediate( + MacroAssemblerBase::RootRegisterOffsetForRootIndex(root_index)), + g.UseRegister(left), cont); } } } @@ -4783,8 +4769,6 @@ VISIT_ATOMIC_BINOP(Xor) V(S256Xor, SXor, LaneSize::kL8, VectorLength::kV256) #define SIMD_F16x8_BINOP_LIST(V) \ - V(F16x8Add, FAdd) \ - V(F16x8Sub, FSub) \ V(F16x8Mul, FMul) \ V(F16x8Div, FDiv) \ V(F16x8Min, FMin) \ @@ -5263,6 +5247,41 @@ SIMD_BINOP_SSE_AVX_LANE_SIZE_VECTOR_LENGTH_LIST( #undef VISIT_SIMD_BINOP_LANE_SIZE_VECTOR_LENGTH #undef SIMD_BINOP_SSE_AVX_LANE_SIZE_VECTOR_LENGTH_LIST +void InstructionSelector::VisitF16x8Add(OpIndex node) { + X64OperandGenerator g(this); + const Simd128BinopOp& op = Cast<Simd128BinopOp>(node); + InstructionCode code = kX64FAdd | LaneSizeField::encode(LaneSize::kL16) | + VectorLengthField::encode(VectorLength::kV128); + if (UseAvx10_1()) { + Emit(code, g.DefineAsRegister(node), g.UseRegister(op.left()), + g.UseRegister(op.right())); + } else { + InstructionOperand temps[] = {g.TempSimd256Register(), + g.TempSimd256Register()}; + Emit(code, g.DefineAsRegister(node), g.UseUniqueRegister(op.left()), + g.UseUniqueRegister(op.right()), arraysize(temps), temps); + } +} + +void InstructionSelector::VisitF16x8Sub(OpIndex node) { + X64OperandGenerator operands(this); + const Simd128BinopOp& operation = Cast<Simd128BinopOp>(node); + InstructionCode code = kX64FSub | LaneSizeField::encode(LaneSize::kL16) | + VectorLengthField::encode(VectorLength::kV128); + if (UseAvx10_1()) { + Emit(code, operands.DefineAsRegister(node), + operands.UseRegister(operation.left()), + operands.UseRegister(operation.right())); + } else { + InstructionOperand temps[] = {operands.TempSimd256Register(), + operands.TempSimd256Register()}; + Emit(code, operands.DefineAsRegister(node), + operands.UseUniqueRegister(operation.left()), + operands.UseUniqueRegister(operation.right()), arraysize(temps), + temps); + } +} + #define VISIT_SIMD_F16x8_BINOP(Name, Opcode) \ void InstructionSelector::Visit##Name(OpIndex node) { \ X64OperandGenerator g(this); \ @@ -5449,6 +5468,13 @@ VISIT_SIMD_QFMOP(F32x8Qfms) X64OperandGenerator g(this); \ const Operation& op = Get(node); \ DCHECK_EQ(op.input_count, 3); \ + if (UseAvx10_1()) { \ + /* The 213 form reads and overwrites the first multiplicand. */ \ + Emit(kX64##Opcode, g.DefineSameAsFirst(node), \ + g.UseRegister(op.input(0)), g.UseRegister(op.input(1)), \ + g.UseAny(op.input(2))); \ + return; \ + } \ InstructionOperand temps[] = {g.TempSimd256Register(), \ g.TempSimd256Register()}; \ Emit(kX64##Opcode, g.UseRegister(node), g.UseUniqueRegister(op.input(0)), \ @@ -6456,7 +6482,8 @@ InstructionSelector::SupportedMachineOperatorFlags() { MachineOperatorBuilder::kFloat64RoundTiesEven; } if (CpuFeatures::IsSupported(F16C)) { - // TODO(wasm): Support vector f16 operations with AVX512 or AVX10.2. + // TODO(wasm): Use native AVX10.1 instructions for the remaining vector f16 + // operations. F16C is still needed for their conversion-based lowering. flags |= MachineOperatorBuilder::kFloat16Arithmetic | MachineOperatorBuilder::kFloat16MemAccess; if (CpuFeatures::IsSupported(AVX)) { diff --git a/deps/v8/src/compiler/bytecode-analysis.cc b/deps/v8/src/compiler/bytecode-analysis.cc index 2906dcbe39ae..c18983c5ae6c 100644 --- a/deps/v8/src/compiler/bytecode-analysis.cc +++ b/deps/v8/src/compiler/bytecode-analysis.cc @@ -40,20 +40,10 @@ void BytecodeLoopAssignments::Add(interpreter::Register r) { } void BytecodeLoopAssignments::AddList(interpreter::Register r, uint32_t count) { - if (r.is_parameter()) { - for (uint32_t i = 0; i < count; i++) { - DCHECK(interpreter::Register(r.index() + i).is_parameter()); - bit_vector_->Add(r.ToParameterIndex() + i); - } - } else { - for (uint32_t i = 0; i < count; i++) { - DCHECK(!interpreter::Register(r.index() + i).is_parameter()); - bit_vector_->Add(parameter_count_ + r.index() + i); - } - } + DCHECK(!r.is_parameter()); + bit_vector_->Add(parameter_count_ + r.index(), count); } - void BytecodeLoopAssignments::Union(const BytecodeLoopAssignments& other) { bit_vector_->Union(*other.bit_vector_); } @@ -101,28 +91,16 @@ void UpdateInLivenessForOutOperand( } else if constexpr (operand_type == OperandType::kRegOutList) { Register r = iterator.GetRegisterOperand(i); uint32_t reg_count = iterator.GetRegisterCountOperand(i + 1); - if (!r.is_parameter()) { - for (uint32_t j = 0; j < reg_count; ++j) { - DCHECK(!Register(r.index() + j).is_parameter()); - in_liveness->MarkRegisterDead(r.index() + j); - } - } + DCHECK(!r.is_parameter()); + in_liveness->MarkRegistersDead(r.index(), reg_count); } else if constexpr (operand_type == OperandType::kRegOutPair) { Register r = iterator.GetRegisterOperand(i); - if (!r.is_parameter()) { - DCHECK(!Register(r.index() + 1).is_parameter()); - in_liveness->MarkRegisterDead(r.index()); - in_liveness->MarkRegisterDead(r.index() + 1); - } + DCHECK(!r.is_parameter()); + in_liveness->MarkRegistersDead(r.index(), 2); } else if constexpr (operand_type == OperandType::kRegOutTriple) { Register r = iterator.GetRegisterOperand(i); - if (!r.is_parameter()) { - DCHECK(!Register(r.index() + 1).is_parameter()); - DCHECK(!Register(r.index() + 2).is_parameter()); - in_liveness->MarkRegisterDead(r.index()); - in_liveness->MarkRegisterDead(r.index() + 1); - in_liveness->MarkRegisterDead(r.index() + 2); - } + DCHECK(!r.is_parameter()); + in_liveness->MarkRegistersDead(r.index(), 3); } else { DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_type)); } @@ -140,19 +118,15 @@ void UpdateInLivenessForInOperand( } } else if constexpr (operand_type == OperandType::kRegPair) { Register r = iterator.GetRegisterOperand(i); - if (!r.is_parameter()) { - DCHECK(!Register(r.index() + 1).is_parameter()); - in_liveness->MarkRegisterLive(r.index()); - in_liveness->MarkRegisterLive(r.index() + 1); - } + DCHECK(!r.is_parameter()); + in_liveness->MarkRegistersLive(r.index(), 2); } else if constexpr (operand_type == OperandType::kRegList) { Register r = iterator.GetRegisterOperand(i); uint32_t reg_count = iterator.GetRegisterCountOperand(i + 1); if (!r.is_parameter()) { - for (uint32_t j = 0; j < reg_count; ++j) { - DCHECK(!interpreter::Register(r.index() + j).is_parameter()); - in_liveness->MarkRegisterLive(r.index() + j); - } + in_liveness->MarkRegistersLive(r.index(), reg_count); + } else { + DCHECK_EQ(reg_count, 1); } } else { DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_type)); @@ -167,14 +141,18 @@ void UpdateInLiveness(BytecodeLivenessState* in_liveness, // Special case Suspend and Resume to just pass through liveness. if constexpr (bytecode == Bytecode::kSuspendGenerator) { // The generator object has to be live. - in_liveness->MarkRegisterLive(iterator.GetRegisterOperand(0).index()); + Register generator_reg = iterator.GetRegisterOperand(0); + DCHECK(!generator_reg.is_parameter()); + in_liveness->MarkRegisterLive(generator_reg.index()); // Suspend additionally reads and returns the accumulator DCHECK(Bytecodes::ReadsAccumulator(bytecode)); in_liveness->MarkAccumulatorLive(); return; } else if constexpr (bytecode == Bytecode::kResumeGenerator) { // The generator object has to be live. - in_liveness->MarkRegisterLive(iterator.GetRegisterOperand(0).index()); + Register generator_reg = iterator.GetRegisterOperand(0); + DCHECK(!generator_reg.is_parameter()); + in_liveness->MarkRegisterLive(generator_reg.index()); return; } @@ -272,11 +250,12 @@ void UpdateOutLiveness(BytecodeLiveness& liveness, if (IsFirstUpdate) { // The generator register won't be live in the fallthrough, so copy the // liveness and make it live here. - int generator_reg_index = iterator.GetRegisterOperand(0).index(); - DCHECK(!next_bytecode_in_liveness->RegisterIsLive(generator_reg_index)); + Register generator_reg = iterator.GetRegisterOperand(0); + DCHECK(!generator_reg.is_parameter()); + DCHECK(!next_bytecode_in_liveness->RegisterIsLive(generator_reg.index())); liveness.out = zone->New<BytecodeLivenessState>(*next_bytecode_in_liveness, zone); - liveness.out->MarkRegisterLive(generator_reg_index); + liveness.out->MarkRegisterLive(generator_reg.index()); } else { liveness.out->Union(*next_bytecode_in_liveness); } diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc index bdc98b4d3e8b..1b580b4ba310 100644 --- a/deps/v8/src/compiler/bytecode-graph-builder.cc +++ b/deps/v8/src/compiler/bytecode-graph-builder.cc @@ -2430,15 +2430,7 @@ void BytecodeGraphBuilder::VisitPopContext() { void BytecodeGraphBuilder::VisitCreateClosure() { SharedFunctionInfoRef shared_info = MakeRefForConstantPoolOperand<SharedFunctionInfo>(0); - AllocationType allocation = - interpreter::CreateClosureFlags::PretenuredBit::decode( - bytecode_iterator().GetFlag8Operand(2)) - ? AllocationType::kOld - : AllocationType::kYoung; - CodeRef compile_lazy = - MakeRef(broker(), *BUILTIN_CODE(jsgraph()->isolate(), CompileLazy)); - const Operator* op = - javascript()->CreateClosure(shared_info, compile_lazy, allocation); + const Operator* op = javascript()->CreateClosure(shared_info); Node* closure = NewNode( op, BuildLoadFeedbackCell(bytecode_iterator().GetFeedbackSlotOperand(1))); environment()->BindAccumulator(closure); diff --git a/deps/v8/src/compiler/bytecode-liveness-map.h b/deps/v8/src/compiler/bytecode-liveness-map.h index 9074ae7fb7a0..a66561eee505 100644 --- a/deps/v8/src/compiler/bytecode-liveness-map.h +++ b/deps/v8/src/compiler/bytecode-liveness-map.h @@ -77,12 +77,26 @@ class BytecodeLivenessState : public ZoneObject { bit_vector_.Add(index + 1); } + void MarkRegistersLive(int index, int count) { + DCHECK_GE(index, 0); + DCHECK_GE(count, 0); + DCHECK_LE(index + count, bit_vector_.length() - 1); + bit_vector_.Add(index + 1, count); + } + void MarkRegisterDead(int index) { DCHECK_GE(index, 0); DCHECK_LT(index, bit_vector_.length() - 1); bit_vector_.Remove(index + 1); } + void MarkRegistersDead(int index, int count) { + DCHECK_GE(index, 0); + DCHECK_GE(count, 0); + DCHECK_LE(index + count, bit_vector_.length() - 1); + bit_vector_.Remove(index + 1, count); + } + void MarkAccumulatorLive() { bit_vector_.Add(0); } void MarkAccumulatorDead() { bit_vector_.Remove(0); } @@ -101,6 +115,13 @@ class BytecodeLivenessState : public ZoneObject { bit_vector_.CopyFrom(other.bit_vector_); } + void CopyFrom(const BytecodeLivenessState& other, int index, int count) { + DCHECK_GE(index, 0); + DCHECK_GE(count, 0); + DCHECK_LE(index + count, bit_vector_.length() - 1); + bit_vector_.CopyFrom(other.bit_vector_, index + 1, count); + } + int register_count() const { return bit_vector_.length() - 1; } // Number of live values, including the accumulator. diff --git a/deps/v8/src/compiler/code-assembler.cc b/deps/v8/src/compiler/code-assembler.cc index db36c41b3b5a..86afaddf3ad7 100644 --- a/deps/v8/src/compiler/code-assembler.cc +++ b/deps/v8/src/compiler/code-assembler.cc @@ -389,8 +389,7 @@ TNode<HeapObject> CodeAssembler::UntypedHeapConstantHole( } TNode<String> CodeAssembler::StringConstant(const char* str) { - Handle<String> internalized_string = - factory()->InternalizeString(base::OneByteVector(str)); + Handle<String> internalized_string = factory()->InternalizeString(str); CanonicalizeEmbeddedBuiltinsConstantIfNeeded(internalized_string); return UncheckedCast<String>(HeapConstantNoHole(internalized_string)); } @@ -886,6 +885,14 @@ Node* CodeAssembler::Load(MachineType type, Node* base, Node* offset) { return raw_assembler()->Load(type, base, offset); } +Node* CodeAssembler::LoadImmutable(MachineType type, Node* base) { + return raw_assembler()->LoadImmutable(type, base); +} + +Node* CodeAssembler::LoadImmutable(MachineType type, Node* base, Node* offset) { + return raw_assembler()->LoadImmutable(type, base, offset); +} + TNode<Object> CodeAssembler::LoadFullTagged(Node* base) { return BitcastWordToTagged(Load<RawPtrT>(base)); } @@ -958,14 +965,11 @@ TNode<Object> CodeAssembler::LoadRoot(RootIndex root_index) { } } - // TODO(jgruber): In theory we could generate better code for this by - // letting the macro assembler decide how to load from the roots list. In most - // cases, it would boil down to loading from a fixed kRootRegister offset. - TNode<ExternalReference> isolate_root = - ExternalConstant(ExternalReference::isolate_root(isolate())); - int offset = IsolateData::root_slot_offset(root_index); + TNode<ExternalReference> roots_table = + IsolateField(IsolateFieldId::kRootsTable); + int offset = RootsTable::offset_of(root_index); return UncheckedCast<Object>( - LoadFullTagged(isolate_root, IntPtrConstant(offset))); + LoadFullTagged(roots_table, IntPtrConstant(offset))); } Node* CodeAssembler::UnalignedLoad(MachineType type, TNode<RawPtrT> base, @@ -1009,18 +1013,18 @@ void CodeAssembler::OptimizedStoreField(MachineRepresentation rep, WriteBarrierKind::kFullWriteBarrier); } -void CodeAssembler::OptimizedStoreIndirectPointerField(TNode<HeapObject> object, - int offset, - IndirectPointerTag tag, - Node* value) { - raw_assembler()->OptimizedStoreIndirectPointerField( +void CodeAssembler::OptimizedStoreTrustedPointerField(TNode<HeapObject> object, + int offset, + TrustedPointerTag tag, + Node* value) { + raw_assembler()->OptimizedStoreTrustedPointerField( object, offset, tag, value, - WriteBarrierKind::kIndirectPointerWriteBarrier); + WriteBarrierKind::kTrustedPointerWriteBarrier); } -void CodeAssembler::OptimizedStoreIndirectPointerFieldNoWriteBarrier( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, Node* value) { - raw_assembler()->OptimizedStoreIndirectPointerField( +void CodeAssembler::OptimizedStoreTrustedPointerFieldNoWriteBarrier( + TNode<HeapObject> object, int offset, TrustedPointerTag tag, Node* value) { + raw_assembler()->OptimizedStoreTrustedPointerField( object, offset, tag, value, WriteBarrierKind::kNoWriteBarrier); } @@ -1198,10 +1202,10 @@ void CodeAssembler::MemoryBarrier(AtomicMemoryOrder order) { void CodeAssembler::StoreRoot(RootIndex root_index, TNode<Object> value) { DCHECK(!RootsTable::IsImmortalImmovable(root_index)); - TNode<ExternalReference> isolate_root = - ExternalConstant(ExternalReference::isolate_root(isolate())); - int offset = IsolateData::root_slot_offset(root_index); - StoreFullTaggedNoWriteBarrier(isolate_root, IntPtrConstant(offset), value); + TNode<ExternalReference> roots_table = + IsolateField(IsolateFieldId::kRootsTable); + int offset = RootsTable::offset_of(root_index); + StoreFullTaggedNoWriteBarrier(roots_table, IntPtrConstant(offset), value); } void CodeAssembler::Retain(TNode<Object> value) { diff --git a/deps/v8/src/compiler/code-assembler.h b/deps/v8/src/compiler/code-assembler.h index 06a61b2fa0ce..286315481885 100644 --- a/deps/v8/src/compiler/code-assembler.h +++ b/deps/v8/src/compiler/code-assembler.h @@ -649,6 +649,9 @@ class V8_EXPORT_PRIVATE CodeAssembler { TNode<UintPtrT> UintPtrConstant(uintptr_t value) { return Unsigned(IntPtrConstant(base::bit_cast<intptr_t>(value))); } + TNode<UintPtrT> UniqueUintPtrConstant(uintptr_t value) { + return Unsigned(UniqueIntPtrConstant(base::bit_cast<intptr_t>(value))); + } TNode<TaggedIndex> TaggedIndexConstant(intptr_t value); TNode<RawPtrT> PointerConstant(void* value) { return ReinterpretCast<RawPtrT>( @@ -934,6 +937,17 @@ class V8_EXPORT_PRIVATE CodeAssembler { TNode<Type> Load(Node* base, TNode<WordT> offset) { return UncheckedCast<Type>(Load(MachineTypeOf<Type>::value, base, offset)); } + Node* LoadImmutable(MachineType type, Node* base); + Node* LoadImmutable(MachineType type, Node* base, Node* offset); + template <class Type> + TNode<Type> LoadImmutable(Node* base) { + return UncheckedCast<Type>(LoadImmutable(MachineTypeOf<Type>::value, base)); + } + template <class Type> + TNode<Type> LoadImmutable(Node* base, TNode<WordT> offset) { + return UncheckedCast<Type>( + LoadImmutable(MachineTypeOf<Type>::value, base, offset)); + } template <class Type> TNode<Type> AtomicLoad(AtomicMemoryOrder order, TNode<RawPtrT> base, TNode<WordT> offset) { @@ -1011,11 +1025,12 @@ class V8_EXPORT_PRIVATE CodeAssembler { StoreToObjectWriteBarrier write_barrier); void OptimizedStoreField(MachineRepresentation rep, TNode<HeapObject> object, int offset, Node* value); - void OptimizedStoreIndirectPointerField(TNode<HeapObject> object, int offset, - IndirectPointerTag tag, Node* value); - void OptimizedStoreIndirectPointerFieldNoWriteBarrier( - TNode<HeapObject> object, int offset, IndirectPointerTag tag, - Node* value); + void OptimizedStoreTrustedPointerField(TNode<HeapObject> object, int offset, + TrustedPointerTag tag, Node* value); + void OptimizedStoreTrustedPointerFieldNoWriteBarrier(TNode<HeapObject> object, + int offset, + TrustedPointerTag tag, + Node* value); void OptimizedStoreFieldAssertNoWriteBarrier(MachineRepresentation rep, TNode<HeapObject> object, int offset, Node* value); diff --git a/deps/v8/src/compiler/common-operator.cc b/deps/v8/src/compiler/common-operator.cc index 0bc7016d6aba..fe96407397d9 100644 --- a/deps/v8/src/compiler/common-operator.cc +++ b/deps/v8/src/compiler/common-operator.cc @@ -529,14 +529,14 @@ V8_EXPORT_PRIVATE std::ostream& operator<<( class LoadTrustedPointerOperator final : public Operator1<LoadTrustedPointerParameters> { public: - LoadTrustedPointerOperator(int offset, IndirectPointerTagRange tag) + LoadTrustedPointerOperator(int offset, TrustedPointerTagRange tag) : Operator1<LoadTrustedPointerParameters>( IrOpcode::kLoadTrustedPointer, Operator::kEliminatable, "LoadTrustedPointer", 1, 1, 1, 1, 1, 0, {offset, tag}) {} }; const Operator* CommonOperatorBuilder::LoadTrustedPointer( - int offset, IndirectPointerTagRange tag) { + int offset, TrustedPointerTagRange tag) { return zone_->New<LoadTrustedPointerOperator>(offset, tag); } #endif // V8_ENABLE_SANDBOX diff --git a/deps/v8/src/compiler/common-operator.h b/deps/v8/src/compiler/common-operator.h index 3a1188f3574f..1a0abe59b9d9 100644 --- a/deps/v8/src/compiler/common-operator.h +++ b/deps/v8/src/compiler/common-operator.h @@ -541,7 +541,7 @@ ExitMachineGraphParametersOf(const Operator* op) V8_WARN_UNUSED_RESULT; #if V8_ENABLE_SANDBOX struct LoadTrustedPointerParameters { int offset; - IndirectPointerTagRange tag; + TrustedPointerTagRange tag; bool operator==(const LoadTrustedPointerParameters&) const = default; }; @@ -631,7 +631,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final const Operator* CompressedHeapConstant(const Handle<HeapObject>&); const Operator* TrustedHeapConstant(const Handle<HeapObject>&); #if V8_ENABLE_SANDBOX - const Operator* LoadTrustedPointer(int offset, IndirectPointerTagRange tag); + const Operator* LoadTrustedPointer(int offset, TrustedPointerTagRange tag); #endif const Operator* ObjectId(uint32_t); diff --git a/deps/v8/src/compiler/compilation-dependencies.cc b/deps/v8/src/compiler/compilation-dependencies.cc index cb6ccaaed424..567d23708167 100644 --- a/deps/v8/src/compiler/compilation-dependencies.cc +++ b/deps/v8/src/compiler/compilation-dependencies.cc @@ -936,9 +936,7 @@ class GlobalPropertyDependency final : public CompilationDependency { class ContextCellDependency final : public CompilationDependency { public: ContextCellDependency(ContextCellRef slot, ContextCell::State state) - : CompilationDependency(kContextCell), slot_(slot), state_(state) { - DCHECK(v8_flags.script_context_cells || v8_flags.function_context_cells); - } + : CompilationDependency(kContextCell), slot_(slot), state_(state) {} bool IsValid(JSHeapBroker* broker) const override { return slot_.state() == state_; @@ -1338,7 +1336,6 @@ bool CompilationDependencies::DependOnContextCell(ContextRef script_context, bool CompilationDependencies::DependOnContextCell(ContextCellRef slot, ContextCell::State state) { - DCHECK(v8_flags.script_context_cells || v8_flags.function_context_cells); RecordDependency(zone_->New<ContextCellDependency>(slot, state)); return true; } diff --git a/deps/v8/src/compiler/graph-assembler.cc b/deps/v8/src/compiler/graph-assembler.cc index 1935184e7936..2544ce3c247f 100644 --- a/deps/v8/src/compiler/graph-assembler.cc +++ b/deps/v8/src/compiler/graph-assembler.cc @@ -338,11 +338,10 @@ Node* JSGraphAssembler::StoreField(FieldAccess const& access, Node* object, } Node* JSGraphAssembler::ClearPendingMessage() { - ExternalReference const ref = - ExternalReference::address_of_pending_message(isolate()); - return AddNode(graph()->NewNode( - simplified()->StoreMessage(), jsgraph()->ExternalConstant(ref), - jsgraph()->TheHoleConstant(), effect(), control())); + Node* const pending_message = IsolateField(IsolateFieldId::kPendingMessage); + return AddNode(graph()->NewNode(simplified()->StoreMessage(), pending_message, + jsgraph()->TheHoleConstant(), effect(), + control())); } #ifdef V8_MAP_PACKING @@ -707,7 +706,10 @@ class ArrayBufferViewAccessBuilder { return a .MachineSelectIf<UintPtrT>( - a.UintPtrLessThanOrEqual(byte_offset, byte_length)) + a.Word32And(a.UintPtrLessThanOrEqual( + byte_length, + a.UintPtrConstant(JSArrayBuffer::kMaxByteLength)), + a.UintPtrLessThanOrEqual(byte_offset, byte_length))) .Then([&]() { // length = floor((byte_length - byte_offset) / element_size) return a.UintPtrDiv(a.UintPtrSub(byte_length, byte_offset), @@ -732,7 +734,10 @@ class ArrayBufferViewAccessBuilder { return a .MachineSelectIf<UintPtrT>( - a.UintPtrLessThanOrEqual(byte_offset, byte_length)) + a.Word32And(a.UintPtrLessThanOrEqual( + byte_length, + a.UintPtrConstant(JSArrayBuffer::kMaxByteLength)), + a.UintPtrLessThanOrEqual(byte_offset, byte_length))) .Then([&]() { // length = floor((byte_length - byte_offset) / element_size) return a.UintPtrDiv(a.UintPtrSub(byte_length, byte_offset), @@ -838,7 +843,10 @@ class ArrayBufferViewAccessBuilder { return a .MachineSelectIf<UintPtrT>( - a.UintPtrLessThanOrEqual(byte_offset, byte_length)) + a.Word32And(a.UintPtrLessThanOrEqual( + byte_length, + a.UintPtrConstant(JSArrayBuffer::kMaxByteLength)), + a.UintPtrLessThanOrEqual(byte_offset, byte_length))) .Then([&]() { return RoundDownToElementSize( a.UintPtrSub(byte_length, byte_offset)); @@ -862,7 +870,10 @@ class ArrayBufferViewAccessBuilder { return a .MachineSelectIf<UintPtrT>( - a.UintPtrLessThanOrEqual(byte_offset, byte_length)) + a.Word32And(a.UintPtrLessThanOrEqual( + byte_length, + a.UintPtrConstant(JSArrayBuffer::kMaxByteLength)), + a.UintPtrLessThanOrEqual(byte_offset, byte_length))) .Then([&]() { return RoundDownToElementSize( a.UintPtrSub(byte_length, byte_offset)); @@ -984,7 +995,7 @@ TNode<Word32T> JSGraphAssembler::ArrayBufferDetachedBit( LoadField<Word32T>(AccessBuilder::ForJSArrayBufferBitField(), buffer), UseInfo::TruncatingWord32()); return Word32And(bitfield, - Uint32Constant(JSArrayBuffer::WasDetachedBit::kMask)); + Uint32Constant(JSArrayBuffer::Bits::WasDetachedBit::kMask)); } TNode<Word32T> JSGraphAssembler::ArrayBufferViewDetachedBit( diff --git a/deps/v8/src/compiler/heap-refs.cc b/deps/v8/src/compiler/heap-refs.cc index e6c1a18c71aa..cf2f7c69161a 100644 --- a/deps/v8/src/compiler/heap-refs.cc +++ b/deps/v8/src/compiler/heap-refs.cc @@ -23,6 +23,7 @@ #endif #include "src/api/api-inl.h" +#include "src/codegen/pending-optimization-table.h" #include "src/common/assert-scope.h" #include "src/compiler/compilation-dependencies.h" #include "src/compiler/js-heap-broker-inl.h" @@ -393,7 +394,8 @@ std::optional<Tagged<Object>> GetOwnFastConstantDataPropertyFromHeap( // TODO(leszeks): We could instead sleep/yield and spin the load, since the // timing on this is tight enough that we wouldn't delay the compiler thread // by much. - if (IsUninitializedHole(constant.value())) { + if (IsUninitializedHole(constant.value()) || + IsUninitializedHeapNumber(constant.value())) { TRACE_BROKER_MISSING(broker, "Read uninitialized property."); return {}; } @@ -656,8 +658,8 @@ class MapData : public HeapObjectData { InstanceType instance_type() const { return instance_type_; } int instance_size() const { return instance_size_; } - uint32_t bit_field2() const { return bit_field2_; } - uint32_t bit_field3() const { return bit_field3_; } + Map::Bits2 bit_field2() const { return bit_field2_; } + Map::Bits3 bit_field3() const { return bit_field3_; } int in_object_properties() const { CHECK(InstanceTypeChecker::IsJSObject(instance_type())); return in_object_properties_; @@ -674,8 +676,8 @@ class MapData : public HeapObjectData { InstanceType instance_type_; int instance_size_; - uint32_t bit_field2_; - uint32_t bit_field3_; + Map::Bits2 bit_field2_; + Map::Bits3 bit_field3_; int unused_property_fields_; bool is_abandoned_prototype_map_; int in_object_properties_; @@ -1230,13 +1232,13 @@ ObjectData* JSHeapBroker::TryGetOrCreateData(IndirectHandle<Object> object, ObjectData* object_data; InstanceType instance_type = heap_object->map()->instance_type(); -#define CREATE_DATA(Name) \ - if (i::InstanceTypeChecker::Is##Name(instance_type)) { \ - entry = refs_->InsertNew(object.address()); \ - object_data = zone()->New<ref_traits<Name>::data_type>( \ - this, &entry->value, instance_type, TrustedCast<Name>(object), \ - ObjectDataKindFor(ref_traits<Name>::ref_serialization_kind)); \ - /* NOLINTNEXTLINE(readability/braces) */ \ +#define CREATE_DATA(Name) \ + if (i::InstanceTypeChecker::Is##Name(instance_type)) { \ + entry = refs_->InsertNew(object.address()); \ + object_data = zone()->New<ref_traits<Name>::data_type>( \ + this, &entry->value, instance_type, UncheckedCast<Name>(object), \ + ObjectDataKindFor(ref_traits<Name>::ref_serialization_kind)); \ + /* NOLINTNEXTLINE(readability/braces) */ \ } else HEAP_BROKER_OBJECT_LIST(CREATE_DATA) #undef CREATE_DATA @@ -1319,7 +1321,13 @@ bool MapRef::IsUndefinedMap(JSHeapBroker* broker) const { return *this == broker->undefined_map(); } - +bool MapRef::IsAnyWasmObjectMap() const { +#if V8_ENABLE_WEBASSEMBLY + return IsWasmObjectMap() || IsWasmCustomMapMap(); +#else + return false; +#endif // V8_ENABLE_WEBASSEMBLY +} bool MapRef::IsStringWrapperMap() const { return IsJSPrimitiveWrapperMap() && @@ -1921,6 +1929,7 @@ HEAP_ACCESSOR_C(ScopeInfo, bool, HasContextExtensionSlot) HEAP_ACCESSOR_C(ScopeInfo, bool, SomeContextHasExtension) HEAP_ACCESSOR_C(ScopeInfo, bool, HasOuterScopeInfo) HEAP_ACCESSOR_C(ScopeInfo, bool, HasContext) +HEAP_ACCESSOR_C(ScopeInfo, bool, HasContextCells) HEAP_ACCESSOR_C(ScopeInfo, bool, ClassScopeHasPrivateBrand) HEAP_ACCESSOR_C(ScopeInfo, bool, SloppyEvalCanExtendVars) HEAP_ACCESSOR_C(ScopeInfo, bool, HasAllocatedReceiver) @@ -1956,6 +1965,13 @@ bool SharedFunctionInfoRef::is_toplevel() const { BROKER_SFI_FIELDS(DEF_SFI_ACCESSOR) #undef DEF_SFI_ACCESSOR +bool SharedFunctionInfoRef::is_eager_inlining_disabled( + JSHeapBroker* broker) const { + if (!v8_flags.allow_natives_syntax) return false; + return ManualOptimizationTable::IsMarkedForDisabledEagerInlining( + broker->local_isolate_or_isolate(), *object()); +} + bool SharedFunctionInfoRef::HasBreakInfo(JSHeapBroker* broker) const { if (broker->IsMainThread()) { return object()->HasBreakInfo(broker->isolate()); @@ -2094,7 +2110,7 @@ int MapRef::constructor_function_index() const { bool MapRef::is_stable() const { IF_ACCESS_FROM_HEAP_C(is_stable); - return !Map::Bits3::IsUnstableBit::decode(data()->AsMap()->bit_field3()); + return !data()->AsMap()->bit_field3().is_unstable(); } bool MapRef::CanBeDeprecated() const { return object()->CanBeDeprecated(); } @@ -2368,10 +2384,6 @@ std::optional<Float64> JSObjectRef::GetOwnFastConstantDoubleProperty( Float64 unboxed_value = Float64::FromBits( RacyReadHeapNumberBits(Cast<HeapNumber>(constant.value()))); - // Const double fields should not contain values with the hole NaN pattern - // unless in-sandbox memory was corrupted. - DCHECK_IMPLIES(!v8_flags.expose_memory_corruption_api, - !unboxed_value.is_hole_nan()); dependencies->DependOnOwnConstantDoubleProperty(*this, map(broker), index, unboxed_value); return unboxed_value; @@ -2805,7 +2817,7 @@ bool DataHandlerRef::IsFastProxyHandler() const { LoadHandler::Kind::kProxy) { return false; } - return data_field_count() >= LoadHandler::kProxyTrapMethodDataIndex; + return data_field_count() == LoadHandler::kProxyDataFieldCount; } #undef BIMODAL_ACCESSOR diff --git a/deps/v8/src/compiler/heap-refs.h b/deps/v8/src/compiler/heap-refs.h index 3d1f39064eed..f0b86bb54974 100644 --- a/deps/v8/src/compiler/heap-refs.h +++ b/deps/v8/src/compiler/heap-refs.h @@ -29,6 +29,7 @@ class BytecodeArray; class FixedDoubleArray; class FunctionTemplateInfo; class HeapNumber; +class UninitializedHeapNumber; class InternalizedString; class JSBoundFunction; class JSDataView; @@ -159,6 +160,7 @@ enum class RefSerializationKind { BACKGROUND_SERIALIZED(FixedArrayBase) \ NEVER_SERIALIZED(FunctionTemplateInfo) \ NEVER_SERIALIZED(HeapNumber) \ + NEVER_SERIALIZED(UninitializedHeapNumber) \ NEVER_SERIALIZED(ContextCell) \ BACKGROUND_SERIALIZED(JSReceiver) \ BACKGROUND_SERIALIZED(Map) \ @@ -306,6 +308,8 @@ template <> struct ref_traits<Boolean> : public ref_traits<HeapObject> {}; template <> struct ref_traits<JSWrappedFunction> : public ref_traits<JSFunction> {}; +template <typename T> +struct ref_traits<ReadOnly<T>> : public ref_traits<T> {}; template <class... T> struct ref_traits<Union<T...>> { @@ -759,9 +763,10 @@ class RegExpBoilerplateDescriptionRef : public HeapObjectRef { int flags() const; }; -// HeapNumberRef is only created for immutable HeapNumbers. Mutable -// HeapNumbers (those owned by in-object or backing store fields with -// representation type Double are not exposed to the compiler through +// HeapNumberRef is only created for immutable HeapNumbers and for initialized +// Double fields of boilerplate objects read via RawInobjectPropertyAt. +// Mutable HeapNumbers (those owned by in-object or backing store fields with +// representation type Double) are not exposed to the compiler through // HeapNumberRef. Instead, we read their value, and protect that read // with a field-constness Dependency. class HeapNumberRef : public HeapObjectRef { @@ -774,6 +779,15 @@ class HeapNumberRef : public HeapObjectRef { uint64_t value_as_bits() const; }; +// UninitializedHeapNumberRef is only created for uninitialized Double fields +// of boilerplate objects read via RawInobjectPropertyAt. +class UninitializedHeapNumberRef : public HeapObjectRef { + public: + DEFINE_REF_CONSTRUCTOR(UninitializedHeapNumber, HeapObjectRef) + + IndirectHandle<UninitializedHeapNumber> object() const; +}; + class DataHandlerRef : public HeapObjectRef { public: DEFINE_REF_CONSTRUCTOR(DataHandler, HeapObjectRef) @@ -1019,6 +1033,7 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef { bool IsBooleanMap(JSHeapBroker* broker) const; bool IsNullMap(JSHeapBroker* broker) const; bool IsUndefinedMap(JSHeapBroker* broker) const; + bool IsAnyWasmObjectMap() const; OptionalHeapObjectRef GetBackPointer(JSHeapBroker* broker) const; @@ -1208,6 +1223,7 @@ class ScopeInfoRef : public HeapObjectRef { MaybeAssignedFlag ContextLocalMaybeAssignedFlag(int var) const; VariableMode ContextLocalMode(int var) const; bool HasContext() const; + bool HasContextCells() const; bool HasOuterScopeInfo() const; bool HasContextExtensionSlot() const; bool SomeContextHasExtension() const; @@ -1245,6 +1261,7 @@ class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef { int context_header_size() const; int context_parameters_start() const; BytecodeArrayRef GetBytecodeArray(JSHeapBroker* broker) const; + bool is_eager_inlining_disabled(JSHeapBroker* broker) const; bool HasBreakInfo(JSHeapBroker* broker) const; SharedFunctionInfo::Inlineability GetInlineability( CodeKind code_kind, JSHeapBroker* broker) const; diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc index ef2524264c24..9c18c8c2362c 100644 --- a/deps/v8/src/compiler/js-call-reducer.cc +++ b/deps/v8/src/compiler/js-call-reducer.cc @@ -60,6 +60,18 @@ namespace compiler { // Shorter lambda declarations with less visual clutter. #define _ [&]() +namespace { + +// Optional integer positions treat an omitted or known undefined value as 0. +Node* GetArgumentOrZeroIfUndefined(const JSCallNode& call, int index, + JSGraph* jsgraph) { + Node* argument = call.ArgumentOr(index, jsgraph->ZeroConstant()); + return argument == jsgraph->UndefinedConstant() ? jsgraph->ZeroConstant() + : argument; +} + +} // namespace + class JSCallReducerAssembler : public JSGraphAssembler { static constexpr bool kMarkLoopExits = true; @@ -420,9 +432,9 @@ class JSCallReducerAssembler : public JSGraphAssembler { ArgumentCount() > index ? Argument(index) : UndefinedConstant()); } - TNode<Number> ArgumentOrZero(int index) { - return TNode<Number>::UncheckedCast( - ArgumentCount() > index ? Argument(index) : ZeroConstant()); + TNode<Object> ArgumentOrZeroIfUndefined(int index) { + return TNode<Object>::UncheckedCast( + GetArgumentOrZeroIfUndefined(JSCallNode{node_ptr()}, index, jsgraph())); } TNode<Context> ContextInput() const { @@ -450,10 +462,10 @@ enum class ArrayIndexOfIncludesVariant { kIncludes, kIndexOf }; // builtins. class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler { public: + // Not all users consult turbo_inline_array_builtins; ReduceArrayPrototypePush + // inlines unconditionally. IteratingArrayBuiltinReducerAssembler(JSCallReducer* reducer, Node* node) - : JSCallReducerAssembler(reducer, node) { - DCHECK(v8_flags.turbo_inline_array_builtins); - } + : JSCallReducerAssembler(reducer, node) {} TNode<Object> ReduceArrayPrototypeForEach(MapInference* inference, const bool has_stability_dependency, @@ -607,11 +619,8 @@ class PromiseBuiltinReducerAssembler : public JSCallReducerAssembler { DCHECK(shared.HasBuiltinId()); Handle<FeedbackCell> feedback_cell = isolate()->factory()->many_closures_cell(); - Callable const callable = - Builtins::CallableFor(isolate(), shared.builtin_id()); - CodeRef code = MakeRef(broker(), *callable.code()); return AddNode<JSFunction>(graph()->NewNode( - javascript()->CreateClosure(shared, code), HeapConstant(feedback_cell), + javascript()->CreateClosure(shared), HeapConstant(feedback_cell), context, effect(), control())); } @@ -1014,7 +1023,7 @@ TNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith( StringRef search_element_string) { DCHECK(search_element_string.IsContentAccessible()); TNode<Object> receiver = ReceiverInput(); - TNode<Object> start = ArgumentOrZero(1); + TNode<Object> start = ArgumentOrZeroIfUndefined(1); TNode<String> receiver_string = CheckString(receiver); TNode<Smi> start_smi = CheckSmi(start); @@ -1058,7 +1067,7 @@ TNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith( TNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith() { TNode<Object> receiver = ReceiverInput(); TNode<Object> search_element = ArgumentOrUndefined(0); - TNode<Object> start = ArgumentOrZero(1); + TNode<Object> start = ArgumentOrZeroIfUndefined(1); TNode<String> receiver_string = CheckString(receiver); TNode<String> search_string = CheckString(search_element); @@ -1232,7 +1241,7 @@ TNode<String> JSCallReducerAssembler::ReduceStringPrototypeCharAt( TNode<String> JSCallReducerAssembler::ReduceStringPrototypeCharAt( SpeculationMode speculation_mode) { TNode<Object> receiver = ReceiverInput(); - TNode<Object> index = ArgumentOrZero(0); + TNode<Object> index = ArgumentOrZeroIfUndefined(0); TNode<String> receiver_string = CheckString(receiver); TNode<Number> length = StringLength(receiver_string); @@ -1266,7 +1275,7 @@ TNode<String> JSCallReducerAssembler::ReduceStringPrototypeCharAt( TNode<Number> JSCallReducerAssembler::ReduceStringPrototypeCharCodeAt( SpeculationMode speculation_mode) { TNode<Object> receiver = ReceiverInput(); - TNode<Object> index = ArgumentOrZero(0); + TNode<Object> index = ArgumentOrZeroIfUndefined(0); TNode<String> receiver_string = CheckString(receiver); TNode<Number> length = StringLength(receiver_string); @@ -1417,8 +1426,7 @@ TNode<Object> JSCallReducerAssembler::ReduceJSCallMathMinMaxWithArrayLike( TNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeAt( ZoneVector<MapRef> maps, bool needs_fallback_builtin_call) { TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); - TNode<Object> index = ArgumentOrZero(0); - + TNode<Object> index = ArgumentOrZeroIfUndefined(0); TNode<Number> index_num = CheckSmi(index); TNode<FixedArrayBase> elements = LoadElements(receiver); @@ -2726,7 +2734,7 @@ IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeIndexOfIncludes( TNode<Context> context = ContextInput(); TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); TNode<Object> search_element = ArgumentOrUndefined(0); - TNode<Object> from_index = ArgumentOrZero(1); + TNode<Object> from_index = ArgumentOrZeroIfUndefined(1); // TODO(jgruber): This currently only reduces to a stub call. Create a full // reduction (similar to other higher-order array builtins) instead of @@ -5258,9 +5266,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) { // the {target} must have the same native context as the call site. // Same if the {target} is the result of a CheckClosure operation. if (target->opcode() == IrOpcode::kJSCreateClosure) { - CreateClosureParameters const& params = - JSCreateClosureNode{target}.Parameters(); - Reduction res = ReduceJSCall(node, params.shared_info()); + Reduction res = + ReduceJSCall(node, JSCreateClosureNode{target}.shared_info()); if (!res.Changed()) return NoChangeOrSoftDeopt(); return res; } else if (target->opcode() == IrOpcode::kCheckClosure) { @@ -5882,9 +5889,7 @@ bool TargetIsClassConstructor(Node* node, JSHeapBroker* broker) { shared = function.shared(broker); } } else if (target->opcode() == IrOpcode::kJSCreateClosure) { - CreateClosureParameters const& ccp = - JSCreateClosureNode{target}.Parameters(); - shared = ccp.shared_info(); + shared = JSCreateClosureNode{target}.shared_info(); } else if (target->opcode() == IrOpcode::kCheckClosure) { FeedbackCellRef cell = MakeRef(broker, FeedbackCellOf(target->op())); shared = cell.shared_function_info(broker); @@ -6215,11 +6220,10 @@ Reduction JSCallReducer::ReduceStringPrototypeIndexOfIncludes( graph()->NewNode(simplified()->CheckString(p.feedback()), search_string, effect, control); - Node* new_position = jsgraph()->ZeroConstant(); + Node* new_position = GetArgumentOrZeroIfUndefined(n, 1, jsgraph()); if (n.ArgumentCount() > 1) { - Node* position = n.Argument(1); new_position = effect = graph()->NewNode( - simplified()->CheckSmi(p.feedback()), position, effect, control); + simplified()->CheckSmi(p.feedback()), new_position, effect, control); Node* receiver_length = graph()->NewNode(simplified()->StringLength(), new_receiver); @@ -6570,6 +6574,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeAt(Node* node) { } // ES6 section 22.1.3.18 Array.prototype.push ( ) +// Inlined even with --no-turbo-inline-array-builtins, which gates the iterating +// array builtins; push is hot enough to always be worth inlining. Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) { JSCallNode n(node); CallParameters const& p = n.Parameters(); @@ -6944,7 +6950,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { static_assert(BuiltinArguments::kNewTargetIndex == 0); static_assert(BuiltinArguments::kTargetIndex == 1); static_assert(BuiltinArguments::kArgcIndex == 2); -#if V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || V8_X64_16BYTE_STACK_ALIGNMENT_BOOL // Make sure we insert required stack-alignment padding between extra // arguments and JS arguments. static_assert(BuiltinArguments::kNumExtraArgs == 4); @@ -6955,7 +6961,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { #else // No padding required. static_assert(BuiltinArguments::kNumExtraArgs == 3); -#endif // V8_TARGET_ARCH_ARM64 +#endif if_false1 = efalse1 = vfalse1 = graph()->NewNode( common()->Call(call_descriptor), stub_code, @@ -6963,7 +6969,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { jsgraph()->UndefinedConstant(), // new.target target, // target argc, // argc -#if V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || V8_X64_16BYTE_STACK_ALIGNMENT_BOOL padding_value, #endif // JS arguments. @@ -7509,9 +7515,9 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { buffer, effect, control); Node* check = graph()->NewNode( simplified()->NumberEqual(), - graph()->NewNode( - simplified()->NumberBitwiseAnd(), buffer_bit_field, - jsgraph()->ConstantNoHole(JSArrayBuffer::WasDetachedBit::kMask)), + graph()->NewNode(simplified()->NumberBitwiseAnd(), buffer_bit_field, + jsgraph()->ConstantNoHole( + JSArrayBuffer::Bits::WasDetachedBit::kMask)), jsgraph()->ZeroConstant()); effect = graph()->NewNode( simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached, @@ -7712,7 +7718,7 @@ Reduction JSCallReducer::ReduceStringPrototypeStringCodePointAt(Node* node) { } Node* receiver = n.receiver(); - Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant()); + Node* index = GetArgumentOrZeroIfUndefined(n, 0, jsgraph()); Effect effect = n.effect(); Control control = n.control(); @@ -8297,10 +8303,7 @@ Node* JSCallReducer::CreateClosureFromBuiltinSharedFunctionInfo( DCHECK(shared.HasBuiltinId()); Handle<FeedbackCell> feedback_cell = isolate()->factory()->many_closures_cell(); - Callable const callable = - Builtins::CallableFor(isolate(), shared.builtin_id()); - CodeRef code = MakeRef(broker(), *callable.code()); - return graph()->NewNode(javascript()->CreateClosure(shared, code), + return graph()->NewNode(javascript()->CreateClosure(shared), jsgraph()->HeapConstantNoHole(feedback_cell), context, effect, control); } @@ -8685,6 +8688,15 @@ Reduction JSCallReducer::ReduceArrayBufferViewByteLengthAccessor( TNode<Number> length = a.ArrayBufferViewByteLength( typed_array, instance_type, std::move(elements_kinds), a.ContextInput()); + if (!depended_on_detaching_protector) { + length = + a.MachineSelectIf<Number>(a.ArrayBufferViewDetachedBit(typed_array)) + .Then([&]() { return a.NumberConstant(0); }) + .Else([&]() { return length; }) + .ExpectFalse() + .Value(); + } + return ReplaceWithSubgraph(&a, length); } diff --git a/deps/v8/src/compiler/js-context-specialization.cc b/deps/v8/src/compiler/js-context-specialization.cc index be2b3c4d7e55..1e4ccb96d3a4 100644 --- a/deps/v8/src/compiler/js-context-specialization.cc +++ b/deps/v8/src/compiler/js-context-specialization.cc @@ -377,7 +377,6 @@ Reduction JSContextSpecialization::ReduceJSStoreContextNoCell(Node* node) { } Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) { - DCHECK(v8_flags.script_context_cells || v8_flags.function_context_cells); DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode()); const ContextAccess& access = ContextAccessOf(node->op()); diff --git a/deps/v8/src/compiler/js-create-lowering.cc b/deps/v8/src/compiler/js-create-lowering.cc index 2a1946aea904..2b96d0eed11a 100644 --- a/deps/v8/src/compiler/js-create-lowering.cc +++ b/deps/v8/src/compiler/js-create-lowering.cc @@ -946,8 +946,7 @@ Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) { Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) { JSCreateClosureNode n(node); - CreateClosureParameters const& p = n.Parameters(); - SharedFunctionInfoRef shared = p.shared_info(); + SharedFunctionInfoRef shared = n.shared_info(); FeedbackCellRef feedback_cell = n.GetFeedbackCellRefChecked(broker()); Effect effect = n.effect(); Control control = n.control(); @@ -991,21 +990,10 @@ Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) { feedback_cell_node, effect, control); } - // TODO(turbofan): We should use the pretenure flag from {p} here, - // but currently the heuristic in the parser works against us, as - // it marks closures like - // - // args[l] = function(...) { ... } - // - // for old-space allocation, which doesn't always make sense. For - // example in case of the bluebird-parallel benchmark, where this - // is a core part of the *promisify* logic (see crbug.com/810132). - AllocationType allocation = AllocationType::kYoung; - // Emit code to allocate the JSFunction instance. static_assert(JSFunctionWithoutPrototype::kHeaderSize == 7 * kTaggedSize); AllocationBuilder a(jsgraph(), broker(), effect, control); - a.Allocate(function_map.instance_size(), allocation, + a.Allocate(function_map.instance_size(), AllocationType::kYoung, Type::CallableFunction()); a.Store(AccessBuilder::ForMap(), function_map); a.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(), @@ -1835,16 +1823,15 @@ std::optional<Node*> JSCreateLowering::TryAllocateFastLiteral( // Uninitialized fields are marked through the `uninitialized_value` marker // (even for Smi representation!), or in the case of Double representation - // through a HeapNumber containing the hole-NaN. Since Double-to-Tagged + // through an UninitializedHeapNumber. Since Double-to-Tagged // representation changes are done in-place, we may even encounter these - // HeapNumbers in Tagged representation. + // UninitializedHeapNumbers in Tagged representation. // Note that although we create nodes to write `uninitialized_value` into // the object, the field should be overwritten immediately with a real // value, and `uninitialized_value` should never be exposed to JS. ObjectRef uninitialized_marker = broker()->uninitialized_value(); if (boilerplate_value.equals(uninitialized_marker) || - (boilerplate_value.IsHeapNumber() && - boilerplate_value.AsHeapNumber().value_as_bits() == kHoleNanInt64)) { + boilerplate_value.IsUninitializedHeapNumber()) { access.const_field_info = ConstFieldInfo::None(); } @@ -1857,11 +1844,16 @@ std::optional<Node*> JSCreateLowering::TryAllocateFastLiteral( if (!maybe_value.has_value()) return {}; value = effect = maybe_value.value(); } else if (property_details.representation().IsDouble()) { - double number = boilerplate_value.AsHeapNumber().value(); - // Allocate a mutable HeapNumber box and store the value into it. + // Allocate a mutable or uninitialized HeapNumber and store the value + // into it. + bool is_uninitialized = boilerplate_value.IsUninitializedHeapNumber(); + MapRef map = is_uninitialized ? broker()->uninitialized_heap_number_map() + : broker()->heap_number_map(); + double number = + is_uninitialized ? 0.0 : boilerplate_value.AsHeapNumber().value(); AllocationBuilder builder(jsgraph(), broker(), effect, control); builder.Allocate(sizeof(HeapNumber), allocation); - builder.Store(AccessBuilder::ForMap(), broker()->heap_number_map()); + builder.Store(AccessBuilder::ForMap(), map); builder.Store(AccessBuilder::ForHeapNumberValue(), jsgraph()->ConstantMaybeHole(number)); value = effect = builder.Finish(); diff --git a/deps/v8/src/compiler/js-generic-lowering.cc b/deps/v8/src/compiler/js-generic-lowering.cc index 2affa53f2fba..646c5598bee6 100644 --- a/deps/v8/src/compiler/js-generic-lowering.cc +++ b/deps/v8/src/compiler/js-generic-lowering.cc @@ -221,7 +221,8 @@ bool ShouldUseMegamorphicAccessBuiltin(FeedbackSource const& source, return feedback.AsElementAccess().transition_groups().empty(); } else if (feedback.kind() == ProcessedFeedback::kNamedAccess) { return feedback.AsNamedAccess().maps().empty(); - } else if (feedback.kind() == ProcessedFeedback::kInsufficient) { + } else if (feedback.kind() == ProcessedFeedback::kInsufficient || + feedback.kind() == ProcessedFeedback::kProxy) { return false; } UNREACHABLE(); @@ -672,19 +673,13 @@ void JSGenericLowering::LowerJSRegExpTest(Node* node) { void JSGenericLowering::LowerJSCreateClosure(Node* node) { JSCreateClosureNode n(node); - CreateClosureParameters const& p = n.Parameters(); - SharedFunctionInfoRef shared_info = p.shared_info(); + SharedFunctionInfoRef shared_info = n.shared_info(); static_assert(n.FeedbackCellIndex() == 0); node->InsertInput(zone(), 0, jsgraph()->ConstantNoHole(shared_info, broker())); node->RemoveInput(4); // control - // Use the FastNewClosure builtin only for functions allocated in new space. - if (p.allocation() == AllocationType::kYoung) { - ReplaceWithBuiltinCall(node, Builtin::kFastNewClosure); - } else { - ReplaceWithRuntimeCall(node, Runtime::kNewClosure_Tenured); - } + ReplaceWithBuiltinCall(node, Builtin::kFastNewClosure); } void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) { diff --git a/deps/v8/src/compiler/js-heap-broker.cc b/deps/v8/src/compiler/js-heap-broker.cc index 9c629176c82b..6e7164152261 100644 --- a/deps/v8/src/compiler/js-heap-broker.cc +++ b/deps/v8/src/compiler/js-heap-broker.cc @@ -609,16 +609,20 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess( smi_handler.has_value() && smi_handler.value().IsSmi()) { MapRef target_map = target_map_obj.value().AsMap(); MapRef handler_map = handler_map_obj.value().AsMap(); - float frequency = 0.0f; - OptionalObjectRef count_obj = - data_handler.data(this, LoadHandler::kProxyCounterDataIndex); - DCHECK(count_obj.has_value() && count_obj.value().IsSmi()); - int count = count_obj.value().AsSmi(); - int invocation_count = nexus.vector()->invocation_count(kRelaxedLoad); - frequency = static_cast<float>(count) / std::max(1, invocation_count); - return *zone()->New<ProxyFeedback>( - *name, maps[0], target_map, handler_map, *trap_method, - smi_handler.value().AsSmi(), frequency, kind); + if (!target_map.is_deprecated() && !handler_map.is_deprecated()) { + float frequency = 0.0f; + OptionalObjectRef count_obj = + data_handler.data(this, LoadHandler::kProxyCounterDataIndex); + DCHECK(count_obj.has_value() && count_obj.value().IsSmi()); + int count = count_obj.value().AsSmi(); + int invocation_count = + nexus.vector()->invocation_count(kRelaxedLoad); + frequency = + static_cast<float>(count) / std::max(1, invocation_count); + return *zone()->New<ProxyFeedback>( + name->UnpackIfThin(this), maps[0], target_map, handler_map, + *trap_method, smi_handler.value().AsSmi(), frequency, kind); + } } } } diff --git a/deps/v8/src/compiler/js-heap-broker.h b/deps/v8/src/compiler/js-heap-broker.h index 7736a7e3712d..c3fca2ebd364 100644 --- a/deps/v8/src/compiler/js-heap-broker.h +++ b/deps/v8/src/compiler/js-heap-broker.h @@ -172,6 +172,14 @@ class V8_EXPORT_PRIVATE JSHeapBroker { set_canonical_handles(info->canonical_handles()); } + template <typename CompilationInfoT> + void DetachCanonicalHandles(CompilationInfoT* info) { + set_canonical_handles(nullptr); + if (auto canonical_handles = info->DetachCanonicalHandles()) { + canonical_handles->Clear(); + } + } + bool StackHasOverflowed() const; #ifdef DEBUG diff --git a/deps/v8/src/compiler/js-inlining-heuristic.cc b/deps/v8/src/compiler/js-inlining-heuristic.cc index b6d9a3f0fd85..33680c288586 100644 --- a/deps/v8/src/compiler/js-inlining-heuristic.cc +++ b/deps/v8/src/compiler/js-inlining-heuristic.cc @@ -201,7 +201,7 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions( if (CanConsiderForInlining(broker(), feedback_cell)) { out.shared_info = feedback_cell.shared_function_info(broker()).value(); out.bytecode[0] = out.shared_info->GetBytecodeArray(broker()); - CHECK(out.shared_info->equals(n.Parameters().shared_info())); + CHECK(out.shared_info->equals(n.shared_info())); } out.num_functions = 1; return out; diff --git a/deps/v8/src/compiler/js-inlining.cc b/deps/v8/src/compiler/js-inlining.cc index 6ee9a688af4e..62a3c4d033f9 100644 --- a/deps/v8/src/compiler/js-inlining.cc +++ b/deps/v8/src/compiler/js-inlining.cc @@ -446,18 +446,13 @@ JSInliner::WasmInlineResult JSInliner::TryWasmInlining( return {}; } - const wasm::WasmModule* module = native_module->module(); - const wasm::FunctionSig* sig = module->functions[fct_index].sig; TFGraph::SubgraphScope graph_scope(graph()); - WasmGraphBuilder builder(nullptr, zone(), jsgraph(), sig, source_positions_, - WasmGraphBuilder::kJSFunctionAbiMode, isolate(), - native_module->enabled_features()); SourcePosition call_pos = source_positions_->GetSourcePosition(call_node); // Calculate hypothetical inlining id, so if we can't inline, we do not add // the wasm function to the list of inlined functions. int inlining_id = static_cast<int>(info_->inlined_functions().size()); - bool can_inline_body = - builder.TryWasmInlining(fct_index, native_module, inlining_id); + bool can_inline_body = compiler::TryWasmInlining( + fct_index, native_module, inlining_id, jsgraph(), source_positions_); if (can_inline_body) { int actual_id = info_->AddInlinedFunction(wasm_call_params.shared_fct_info().object(), @@ -506,7 +501,7 @@ Reduction JSInliner::ReduceJSWasmCall(Node* node) { subgraph_min_node_id = graph()->NodeCount(); BuildInlinedJSToWasmWrapper(graph()->zone(), jsgraph(), sig, isolate(), - source_positions_, continuation_frame_state); + continuation_frame_state); // Extract the inlinee start/end nodes. wrapper_start_node = graph()->start(); diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc index 901ccd3d4a40..f53804671639 100644 --- a/deps/v8/src/compiler/js-native-context-specialization.cc +++ b/deps/v8/src/compiler/js-native-context-specialization.cc @@ -1233,10 +1233,12 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) { if (feedback.IsScriptContextSlot()) { Effect effect = n.effect(); Control control = n.control(); + ContextRef script_context_ref = feedback.script_context(); Node* script_context = - jsgraph()->ConstantNoHole(feedback.script_context(), broker()); + jsgraph()->ConstantNoHole(script_context_ref, broker()); Node* value; - if (v8_flags.script_context_cells && !feedback.immutable()) { + if (script_context_ref.scope_info(broker()).HasContextCells() && + !feedback.immutable()) { // We collect feedback only for mutable context slots. value = effect = control = graph()->NewNode(javascript()->LoadContext(0, feedback.slot_index()), @@ -1275,9 +1277,10 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { Node* effect = n.effect(); Node* control = n.control(); Node* frame_state = n.frame_state(); + ContextRef script_context_ref = feedback.script_context(); Node* script_context = - jsgraph()->ConstantNoHole(feedback.script_context(), broker()); - if (v8_flags.script_context_cells) { + jsgraph()->ConstantNoHole(script_context_ref, broker()); + if (script_context_ref.scope_info(broker()).HasContextCells()) { effect = control = graph()->NewNode(javascript()->StoreContext(0, feedback.slot_index()), value, script_context, frame_state, effect, control); @@ -1298,143 +1301,6 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { } } -Reduction JSNativeContextSpecialization::ReduceProxyAccess( - Node* node, Node* value, ProxyFeedback const& feedback, - AccessMode access_mode, FeedbackSource const& source, Node* key) { - DCHECK_EQ(access_mode, AccessMode::kLoad); - - // For a super property load the proxy sits on the home object's prototype, - // not on input 0 (the receiver). The fast path below assumes the proxy is - // the receiver and lookup start object, so bail out and let the generic IC - // handle super accesses. - if (node->opcode() == IrOpcode::kJSLoadNamedFromSuper) return NoChange(); - - Node* context = NodeProperties::GetContextInput(node); - FrameState frame_state{NodeProperties::GetFrameStateInput(node)}; - Effect effect{NodeProperties::GetEffectInput(node)}; - Control control{NodeProperties::GetControlInput(node)}; - - // Ensure that {key} matches the specified name (if {key} is given). - if (key != nullptr) { - effect = BuildCheckEqualsName(feedback.name(), key, effect, &control); - } - - Node* receiver = NodeProperties::GetValueInput(node, 0); - Node* lookup_start_object = receiver; - - PropertyAccessInfo handler_access_info = broker()->GetPropertyAccessInfo( - feedback.handler_map(), broker()->get_string(), AccessMode::kLoad); - - if (handler_access_info.IsInvalid()) { - return NoChange(); - } - - // Collect call nodes to rewire exception edges. - ZoneVector<Node*> if_exception_nodes(zone()); - ZoneVector<Node*>* if_exceptions = nullptr; - Node* if_exception = nullptr; - if (NodeProperties::IsExceptionalCall(node, &if_exception)) { - if_exceptions = &if_exception_nodes; - } - - PropertyAccessBuilder access_builder(jsgraph(), broker()); - - // 1. Check receiver map - ZoneVector<MapRef> receiver_maps({feedback.receiver_map()}, zone()); - access_builder.BuildCheckMaps(receiver, &effect, control, receiver_maps); - - // 2. Load proxy target - Node* proxy_target = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSProxyTarget()), - lookup_start_object, effect, control); - - // 3. Check proxy target map - ZoneVector<MapRef> target_maps({feedback.target_map()}, zone()); - Effect e_effect(effect); - Control e_control(control); - access_builder.BuildCheckMaps(proxy_target, &e_effect, e_control, - target_maps); - effect = e_effect; - control = e_control; - - // 4. Load proxy handler - Node* proxy_handler = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSProxyHandler()), - lookup_start_object, effect, control); - - // 5. Check proxy handler map - ZoneVector<MapRef> handler_maps({feedback.handler_map()}, zone()); - e_effect = Effect(effect); - e_control = Control(control); - access_builder.BuildCheckMaps(proxy_handler, &e_effect, e_control, - handler_maps); - effect = e_effect; - control = e_control; - - // 6. Check trap - Node* target_function = - jsgraph()->ConstantNoHole(feedback.trap_method(), broker()); - - DCHECK(!feedback.trap_method().IsUndefined()); - DCHECK(feedback.trap_method().IsJSFunction()); - - handler_access_info.RecordDependencies(dependencies()); - std::optional<JSNativeContextSpecialization::ValueEffectControl> - maybe_loaded_trap = BuildPropertyLoad( - proxy_handler, proxy_handler, context, frame_state, effect, control, - broker()->get_string(), if_exceptions, handler_access_info, source); - - if (!maybe_loaded_trap.has_value()) { - return NoChange(); - } - - Node* loaded_trap = maybe_loaded_trap->value(); - effect = maybe_loaded_trap->effect(); - control = maybe_loaded_trap->control(); - - Node* check = graph()->NewNode(simplified()->ReferenceEqual(), loaded_trap, - target_function); - effect = graph()->NewNode( - simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check, effect, - control); - - // 6. Call trap - Node* name_node = jsgraph()->ConstantNoHole(feedback.name(), broker()); - Node* call_feedback = jsgraph()->UndefinedConstant(); - - Node* value_node = effect = control = graph()->NewNode( - jsgraph()->javascript()->Call(JSCallNode::ArityForArgc(3), - CallFrequency(feedback.frequency()), source, - ConvertReceiverMode::kNotNullOrUndefined), - target_function, proxy_handler, proxy_target, name_node, receiver, - call_feedback, context, frame_state, effect, control); - - if (if_exceptions != nullptr) { - Node* const if_exception_node = - graph()->NewNode(common()->IfException(), control, effect); - Node* const if_success = graph()->NewNode(common()->IfSuccess(), control); - if_exceptions->push_back(if_exception_node); - control = if_success; - } - - // Rewire exception edges if needed - if (if_exceptions != nullptr) { - DCHECK_EQ(1, if_exceptions->size()); - Node* merge = - graph()->NewNode(common()->Merge(1), 1, &if_exceptions->front()); - if_exceptions->push_back(merge); - Node* ephi = - graph()->NewNode(common()->EffectPhi(1), 2, &if_exceptions->front()); - Node* phi = - graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 1), 2, - &if_exceptions->front()); - ReplaceWithValue(if_exception, phi, ephi, merge); - } - - ReplaceWithValue(node, value_node, effect, control); - return Changed(value_node); -} - Reduction JSNativeContextSpecialization::ReduceMegaDOMPropertyAccess( Node* node, Node* value, MegaDOMPropertyAccessFeedback const& feedback, FeedbackSource const& source) { @@ -2483,7 +2349,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( if ((IsHoleyOrDictionaryElementsKind(receiver_map.elements_kind()) || StoreModeCanGrow(feedback.keyed_mode().store_mode())) && #if V8_ENABLE_WEBASSEMBLY - !(receiver_map.IsWasmObjectMap() && + !(receiver_map.IsAnyWasmObjectMap() && access_info.is_proxy_on_prototype()) && #endif // V8_ENABLE_WEBASSEMBLY !receiver_map.PrototypesElementsDoNotHaveAccessorsOrThrow( @@ -2785,9 +2651,7 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess( node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); case ProcessedFeedback::kProxy: - if (access_mode != AccessMode::kLoad) return NoChange(); - return ReduceProxyAccess(node, value, feedback->AsProxy(), access_mode, - source, key); + return NoChange(); case ProcessedFeedback::kNamedAccess: return ReduceNamedAccess(node, value, feedback->AsNamedAccess(), access_mode, source, key); @@ -3434,10 +3298,6 @@ JSNativeContextSpecialization::BuildPropertyStore( value = effect = graph()->NewNode(simplified()->CheckNumber(FeedbackSource()), value, effect, control); - if (access_info.IsFastDataConstant()) { - value = graph()->NewNode(jsgraph()->simplified()->NumberSilenceNaN(), - value); - } if (access_info.HasTransitionMap()) { // Allocate a HeapNumber for the new property. AllocationBuilder a(jsgraph(), broker(), effect, control); @@ -3509,7 +3369,7 @@ JSNativeContextSpecialization::BuildPropertyStore( case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kCompressed: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kSandboxedPointer: case MachineRepresentation::kWord8: case MachineRepresentation::kWord16: @@ -3575,8 +3435,19 @@ JSNativeContextSpecialization::BuildPropertyStore( jsgraph()->UndefinedConstant(), effect); } else { // Regular non-transitioning field store. + bool maybe_initializing_store = + access_mode == AccessMode::kStoreInLiteral || + access_mode == AccessMode::kDefine; + effect = graph()->NewNode(simplified()->StoreField(field_access), storage, value, effect, control); + if (maybe_initializing_store && + access_info.field_representation().IsDouble()) { + effect = graph()->NewNode( + simplified()->StoreField(AccessBuilder::ForMap()), storage, + jsgraph()->ConstantNoHole(broker()->heap_number_map(), broker()), + effect, control); + } } } @@ -3730,7 +3601,7 @@ JSNativeContextSpecialization::BuildElementAccess( } #if V8_ENABLE_WEBASSEMBLY - if (receiver_maps.size() == 1 && receiver_maps.front().IsWasmObjectMap() && + if (receiver_maps.size() == 1 && receiver_maps.front().IsAnyWasmObjectMap() && access_info.is_proxy_on_prototype()) { return BuildPrototypeProxyElementAccess( receiver, index, value, effect, control, context, access_info, diff --git a/deps/v8/src/compiler/js-native-context-specialization.h b/deps/v8/src/compiler/js-native-context-specialization.h index 7fd2b5307f7d..4c7f01032135 100644 --- a/deps/v8/src/compiler/js-native-context-specialization.h +++ b/deps/v8/src/compiler/js-native-context-specialization.h @@ -110,11 +110,6 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final AccessMode access_mode, FeedbackSource const& source, Node* key = nullptr); - Reduction ReduceProxyAccess(Node* node, Node* value, - ProxyFeedback const& feedback, - AccessMode access_mode, - FeedbackSource const& source, - Node* key = nullptr); Reduction ReduceHomomorphicAccess( Node* node, Node* value, HomomorphicPropertyAccessFeedback const& feedback, AccessMode access_mode, diff --git a/deps/v8/src/compiler/js-operator.cc b/deps/v8/src/compiler/js-operator.cc index 5aec87c5ad38..73c247f70752 100644 --- a/deps/v8/src/compiler/js-operator.cc +++ b/deps/v8/src/compiler/js-operator.cc @@ -619,39 +619,6 @@ const GetTemplateObjectParameters& GetTemplateObjectParametersOf( return OpParameter<GetTemplateObjectParameters>(op); } -bool operator==(CreateClosureParameters const& lhs, - CreateClosureParameters const& rhs) { - return lhs.allocation() == rhs.allocation() && - lhs.code_.object().location() == rhs.code_.object().location() && - lhs.shared_info_.object().location() == - rhs.shared_info_.object().location(); -} - - -bool operator!=(CreateClosureParameters const& lhs, - CreateClosureParameters const& rhs) { - return !(lhs == rhs); -} - - -size_t hash_value(CreateClosureParameters const& p) { - return base::hash_combine(p.allocation(), p.code_.object().location(), - p.shared_info_.object().location()); -} - - -std::ostream& operator<<(std::ostream& os, CreateClosureParameters const& p) { - return os << p.allocation() << ", " << Brief(*p.shared_info_.object()) << ", " - << Brief(*p.code_.object()); -} - - -const CreateClosureParameters& CreateClosureParametersOf(const Operator* op) { - DCHECK_EQ(IrOpcode::kJSCreateClosure, op->opcode()); - return OpParameter<CreateClosureParameters>(op); -} - - bool operator==(CreateLiteralParameters const& lhs, CreateLiteralParameters const& rhs) { return lhs.constant_.object().location() == @@ -1536,16 +1503,19 @@ const Operator* JSOperatorBuilder::CreateBoundFunction(size_t arity, } const Operator* JSOperatorBuilder::CreateClosure( - SharedFunctionInfoRef shared_info, CodeRef code, - AllocationType allocation) { + SharedFunctionInfoRef shared_info) { static constexpr int kFeedbackCell = 1; static constexpr int kArity = kFeedbackCell; - CreateClosureParameters parameters(shared_info, code, allocation); - return zone()->New<Operator1<CreateClosureParameters>>( // -- + return zone()->New<Operator1<SharedFunctionInfoRef>>( // -- IrOpcode::kJSCreateClosure, Operator::kEliminatable, // opcode "JSCreateClosure", // name kArity, 1, 1, 1, 1, 0, // counts - parameters); // parameter + shared_info); // parameter +} + +SharedFunctionInfoRef SharedFunctionInfoOf(const Operator* op) { + DCHECK_EQ(IrOpcode::kJSCreateClosure, op->opcode()); + return OpParameter<SharedFunctionInfoRef>(op); } const Operator* JSOperatorBuilder::CreateLiteralArray( diff --git a/deps/v8/src/compiler/js-operator.h b/deps/v8/src/compiler/js-operator.h index 80baa97bdb90..aab36aec7298 100644 --- a/deps/v8/src/compiler/js-operator.h +++ b/deps/v8/src/compiler/js-operator.h @@ -747,36 +747,6 @@ class CreateBoundFunctionParameters final { const CreateBoundFunctionParameters& CreateBoundFunctionParametersOf( const Operator* op); -// Defines shared information for the closure that should be created. This is -// used as a parameter by JSCreateClosure operators. -class CreateClosureParameters final { - public: - CreateClosureParameters(SharedFunctionInfoRef shared_info, CodeRef code, - AllocationType allocation) - : shared_info_(shared_info), code_(code), allocation_(allocation) {} - - SharedFunctionInfoRef shared_info() const { return shared_info_; } - CodeRef code() const { return code_; } - AllocationType allocation() const { return allocation_; } - - private: - const SharedFunctionInfoRef shared_info_; - const CodeRef code_; - AllocationType const allocation_; - - friend bool operator==(CreateClosureParameters const&, - CreateClosureParameters const&); - friend bool operator!=(CreateClosureParameters const&, - CreateClosureParameters const&); - - friend size_t hash_value(CreateClosureParameters const&); - - friend std::ostream& operator<<(std::ostream&, - CreateClosureParameters const&); -}; - -const CreateClosureParameters& CreateClosureParametersOf(const Operator* op); - class GetTemplateObjectParameters final { public: GetTemplateObjectParameters(TemplateObjectDescriptionRef description, @@ -995,6 +965,9 @@ int RegisterCountOf(Operator const* op) V8_WARN_UNUSED_RESULT; int GeneratorStoreValueCountOf(const Operator* op) V8_WARN_UNUSED_RESULT; int RestoreRegisterIndexOf(const Operator* op) V8_WARN_UNUSED_RESULT; +SharedFunctionInfoRef SharedFunctionInfoOf(const Operator* op) + V8_WARN_UNUSED_RESULT; + ScopeInfoRef ScopeInfoOf(const Operator* op) V8_WARN_UNUSED_RESULT; bool operator==(ScopeInfoRef, ScopeInfoRef); @@ -1070,9 +1043,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final const Operator* CreateAsyncFunctionObject(int register_count); const Operator* CreateCollectionIterator(CollectionKind, IterationKind); const Operator* CreateBoundFunction(size_t arity, MapRef map); - const Operator* CreateClosure( - SharedFunctionInfoRef shared_info, CodeRef code, - AllocationType allocation = AllocationType::kYoung); + const Operator* CreateClosure(SharedFunctionInfoRef shared_info); const Operator* CreateIterResultObject(); const Operator* CreateStringIterator(); const Operator* CreateKeyValueArray(); @@ -1877,8 +1848,8 @@ class JSCreateClosureNode final : public JSNodeWrapperBase { DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode()); } - const CreateClosureParameters& Parameters() const { - return CreateClosureParametersOf(node()->op()); + SharedFunctionInfoRef shared_info() const { + return SharedFunctionInfoOf(node()->op()); } #define INPUTS(V) V(FeedbackCell, feedback_cell, 0, FeedbackCell) diff --git a/deps/v8/src/compiler/js-typed-lowering.cc b/deps/v8/src/compiler/js-typed-lowering.cc index 77b5ff4320a4..3b0f85776c36 100644 --- a/deps/v8/src/compiler/js-typed-lowering.cc +++ b/deps/v8/src/compiler/js-typed-lowering.cc @@ -1609,7 +1609,7 @@ Reduction JSTypedLowering::ReduceJSHasContextExtension(Node* node) { UseInfo::TruncatingWord32()); TNode<Word32T> flags_masked = gasm.Word32And( scope_info_flags, - gasm.Uint32Constant(ScopeInfo::HasContextExtensionSlotBit::kMask)); + gasm.Uint32Constant(ScopeInfo::Flags::HasContextExtensionSlotBit::kMask)); TNode<Word32T> no_extension = gasm.Word32Equal(flags_masked, gasm.Uint32Constant(0)); TNode<Word32T> has_extension = @@ -1922,7 +1922,7 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, Builtin builtin, int arity, node->InsertInput(zone, 2, target); node->InsertInput(zone, 3, argc_node); -#if V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || V8_X64_16BYTE_STACK_ALIGNMENT_BOOL // Make sure we insert required stack-alignment padding between extra // arguments and JS arguments. static_assert(BuiltinArguments::kOptionalPaddingIndex == 3); @@ -1933,7 +1933,7 @@ void ReduceBuiltin(JSGraph* jsgraph, Node* node, Builtin builtin, int arity, #else // No padding required. static_assert(BuiltinArguments::kNumExtraArgs == 3); -#endif // V8_TARGET_ARCH_ARM64 +#endif // V8_TARGET_ARCH_ARM64 || V8_X64_16BYTE_STACK_ALIGNMENT_BOOL int cursor = arity + kStub + BuiltinArguments::kNumExtraArgsWithReceiver; @@ -2084,9 +2084,7 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { function = target_type.AsHeapConstant()->Ref().AsJSFunction(); shared = function->shared(broker()); } else if (target->opcode() == IrOpcode::kJSCreateClosure) { - CreateClosureParameters const& ccp = - JSCreateClosureNode{target}.Parameters(); - shared = ccp.shared_info(); + shared = JSCreateClosureNode{target}.shared_info(); } else if (target->opcode() == IrOpcode::kCheckClosure) { FeedbackCellRef cell = MakeRef(broker(), FeedbackCellOf(target->op())); shared = cell.shared_function_info(broker()); @@ -2143,9 +2141,14 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { Node* new_target = jsgraph()->UndefinedConstant(); // TODO(412398354): use the dispatch handle here to avoid a runtime check. - int formal_count = - shared->internal_formal_parameter_count_without_receiver_deprecated(); - if (formal_count > arity) { + int expected_formal_parameter_count = + shared->internal_formal_parameter_count_with_receiver_deprecated(); + + if (expected_formal_parameter_count > JSParameterCount(arity)) { + DCHECK_NE(expected_formal_parameter_count, kDontAdaptArgumentsSentinel); + // Formal parameter count without receiver. + int formal_count = expected_formal_parameter_count - kJSArgcReceiverSlots; + node->RemoveInput(n.FeedbackVectorIndex()); // Underapplication. Massage the arguments to match the expected number of // arguments. @@ -2163,10 +2166,10 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { graph()->zone(), formal_count + 4, jsgraph()->ConstantNoHole(kPlaceholderDispatchHandle.value())); #endif - NodeProperties::ChangeOp(node, - common()->Call(Linkage::GetJSCallDescriptor( - graph()->zone(), false, 1 + formal_count, - flags | CallDescriptor::kCanUseRoots))); + NodeProperties::ChangeOp( + node, common()->Call(Linkage::GetJSCallDescriptor( + graph()->zone(), false, JSParameterCount(formal_count), + expected_formal_parameter_count, flags))); } else if (shared->HasBuiltinId() && Builtins::IsCpp(shared->builtin_id())) { // Patch {node} to a direct CEntry call. @@ -2177,7 +2180,7 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { // This SBXCHECK is a defense-in-depth measure to ensure that we always // generate valid calls here (with matching signatures). - SBXCHECK_GE(arity + kJSArgcReceiverSlots, + SBXCHECK_GE(JSParameterCount(arity), Builtins::GetFormalParameterCount(builtin)); // Patch {node} to a direct code object call. @@ -2209,10 +2212,10 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { graph()->zone(), arity + 4, jsgraph()->ConstantNoHole(kPlaceholderDispatchHandle.value())); #endif - NodeProperties::ChangeOp(node, - common()->Call(Linkage::GetJSCallDescriptor( - graph()->zone(), false, 1 + arity, - flags | CallDescriptor::kCanUseRoots))); + NodeProperties::ChangeOp( + node, common()->Call(Linkage::GetJSCallDescriptor( + graph()->zone(), false, JSParameterCount(arity), + expected_formal_parameter_count, flags))); } return Changed(node); } @@ -2248,6 +2251,7 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) { } Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { + CHECK(!v8_flags.forin_enumerator_holder); JSForInNextNode n(node); Node* receiver = n.receiver(); Node* cache_array = n.cache_array(); @@ -2361,6 +2365,7 @@ Reduction JSTypedLowering::ReduceJSForInNext(Node* node) { } Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) { + CHECK(!v8_flags.forin_enumerator_holder); JSForInPrepareNode n(node); Node* enumerator = n.enumerator(); Effect effect = n.effect(); @@ -2504,7 +2509,7 @@ Reduction JSTypedLowering::ReduceJSForInPrepare(Node* node) { Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) { DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode()); ExternalReference const ref = - ExternalReference::address_of_pending_message(isolate()); + ExternalReference::Create(IsolateFieldId::kPendingMessage); node->ReplaceInput(0, jsgraph()->ExternalConstant(ref)); NodeProperties::ChangeOp(node, simplified()->LoadMessage()); return Changed(node); @@ -2513,7 +2518,7 @@ Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) { Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) { DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode()); ExternalReference const ref = - ExternalReference::address_of_pending_message(isolate()); + ExternalReference::Create(IsolateFieldId::kPendingMessage); Node* value = NodeProperties::GetValueInput(node, 0); node->ReplaceInput(0, jsgraph()->ExternalConstant(ref)); node->ReplaceInput(1, value); @@ -2830,7 +2835,7 @@ Reduction JSTypedLowering::ReduceJSAsyncFunctionAwait(Node* node) { AccessBuilder::ForJSObjectOffset(offsetof(JSPromise, flags_))), value, jsgraph()->SmiConstant(v8::Promise::kFulfilled | - JSPromise::HasHandlerBit::kMask), + JSPromise::Flags::HasHandlerBit::kMask), fast_effect, fast_control); // Note: resume_mode is NOT set here — the AsyncResumeTask handler in diff --git a/deps/v8/src/compiler/linkage.cc b/deps/v8/src/compiler/linkage.cc index 2f8a65819476..254b57662879 100644 --- a/deps/v8/src/compiler/linkage.cc +++ b/deps/v8/src/compiler/linkage.cc @@ -379,7 +379,7 @@ CallDescriptor* Linkage::ComputeIncoming(Zone* zone, info->bytecode_array()->parameter_count()); return GetJSCallDescriptor(zone, info->is_osr(), info->bytecode_array()->parameter_count(), - CallDescriptor::kCanUseRoots); + CallDescriptor::kNoFlags); } return nullptr; // TODO(titzer): ? } @@ -397,7 +397,6 @@ bool Linkage::NeedsFrameStateInput(Runtime::FunctionId function) { case Runtime::kGrowableSharedArrayBufferByteLength: case Runtime::kIncBlockCounter: case Runtime::kNewClosure: - case Runtime::kNewClosure_Tenured: case Runtime::kNewFunctionContext: case Runtime::kPushBlockContext: case Runtime::kPushCatchContext: @@ -531,6 +530,7 @@ CallDescriptor* Linkage::GetCEntryStubCallDescriptor( CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr, int js_parameter_count, + uint16_t expected_parameter_count, CallDescriptor::Flags flags, Operator::Properties properties) { const size_t return_count = 1; @@ -600,7 +600,11 @@ CallDescriptor* Linkage::GetJSCallDescriptor(Zone* zone, bool is_osr, kNoCalleeSaved, // callee-saved kNoCalleeSavedFp, // callee-saved fp flags, // flags - "js-call"); // debug name + "js-call", // debug name + RegList{}, // allocatable_registers + 0, // return_slot_count + kInvalidWasmSignatureHash, // signature_hash + expected_parameter_count); // expected_parameter_count } // TODO(turbofan): cache call descriptors for code stub calls. @@ -706,18 +710,18 @@ CallDescriptor* Linkage::GetStubCallDescriptor( DCHECK(!callee_saved_registers.is_empty()); } LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type); - return zone->New<CallDescriptor>( // -- - kind, // kind - descriptor.tag(), // tag - target_type, // target MachineType - target_loc, // target location - locations.Get(), // location_sig - stack_parameter_count, // stack_parameter_count - properties, // properties - callee_saved_registers, // callee-saved registers - kNoCalleeSavedFp, // callee-saved fp - CallDescriptor::kCanUseRoots | flags, // flags - descriptor.DebugName(), // debug name + return zone->New<CallDescriptor>( // -- + kind, // kind + descriptor.tag(), // tag + target_type, // target MachineType + target_loc, // target location + locations.Get(), // location_sig + stack_parameter_count, // stack_parameter_count + properties, // properties + callee_saved_registers, // callee-saved registers + kNoCalleeSavedFp, // callee-saved fp + flags, // flags + descriptor.DebugName(), // debug name allocatable_registers); } @@ -751,8 +755,7 @@ CallDescriptor* Linkage::GetBytecodeDispatchCallDescriptor( // The target for interpreter dispatches is a code entry address. MachineType target_type = MachineType::Pointer(); LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type); - const CallDescriptor::Flags kFlags = - CallDescriptor::kCanUseRoots | CallDescriptor::kFixedTargetRegister; + const CallDescriptor::Flags kFlags = CallDescriptor::kFixedTargetRegister; return zone->New<CallDescriptor>( // -- CallDescriptor::kCallAddress, // kind kBytecodeHandlerEntrypointTag, // tag diff --git a/deps/v8/src/compiler/linkage.h b/deps/v8/src/compiler/linkage.h index badf34bf4af9..01dd30f0d694 100644 --- a/deps/v8/src/compiler/linkage.h +++ b/deps/v8/src/compiler/linkage.h @@ -60,28 +60,24 @@ class V8_EXPORT_PRIVATE CallDescriptor final kCallBuiltinPointer, // target is a builtin pointer }; - // NOTE: The lowest 9 bits of the Flags field are encoded in InstructionCode - // (for use in the code generator). All higher bits are lost. - static constexpr int kFlagsBitsEncodedInInstructionCode = 9; enum Flag { kNoFlags = 0u, kNeedsFrameState = 1u << 0, kHasExceptionHandler = 1u << 1, - kCanUseRoots = 1u << 2, // Causes the code generator to initialize the root register. - kInitializeRootRegister = 1u << 3, + kInitializeRootRegister = 1u << 2, // Does not ever try to allocate space on our heap. - kNoAllocate = 1u << 4, + kNoAllocate = 1u << 3, // Repurpose this bit during instruction selection. Signal the presence of // an effect handler to code generation. kHasEffectHandler = kNoAllocate, // Use the kJavaScriptCallCodeStartRegister (fixed) register for the // indirect target address when calling. - kFixedTargetRegister = 1u << 5, - kCallerSavedRegisters = 1u << 6, + kFixedTargetRegister = 1u << 4, + kCallerSavedRegisters = 1u << 5, // The kCallerSavedFPRegisters only matters (and set) when the more general // flag for kCallerSavedRegisters above is also set. - kCallerSavedFPRegisters = 1u << 7, + kCallerSavedFPRegisters = 1u << 6, // Tail calls for tier up are special (in fact they are different enough // from normal tail calls to warrant a dedicated opcode; but they also have // enough similar aspects that reusing the TailCall opcode is pragmatic). @@ -97,27 +93,23 @@ class V8_EXPORT_PRIVATE CallDescriptor final // // In other words, behavior is identical to a jmp instruction prior caller // frame construction. - kIsTailCallForTierUp = 1u << 8, - - // Flags past here are *not* encoded in InstructionCode and are thus not - // accessible from the code generator. See also - // kFlagsBitsEncodedInInstructionCode. + kIsTailCallForTierUp = 1u << 7, // AIX has a function descriptor by default but it can be disabled for a // certain CFunction call (only used for Kind::kCallAddress). - kNoFunctionDescriptor = 1u << 9, + kNoFunctionDescriptor = 1u << 8, }; using Flags = base::Flags<Flag>; - CallDescriptor(Kind kind, CodeEntrypointTag tag, MachineType target_type, - LinkageLocation target_loc, LocationSignature* location_sig, - size_t param_slot_count, Operator::Properties properties, - RegList callee_saved_registers, - DoubleRegList callee_saved_fp_registers, Flags flags, - const char* debug_name = "", - const RegList allocatable_registers = {}, - size_t return_slot_count = 0, - uint64_t signature_hash = kInvalidWasmSignatureHash) + CallDescriptor( + Kind kind, CodeEntrypointTag tag, MachineType target_type, + LinkageLocation target_loc, LocationSignature* location_sig, + size_t param_slot_count, Operator::Properties properties, + RegList callee_saved_registers, DoubleRegList callee_saved_fp_registers, + Flags flags, const char* debug_name = "", + const RegList allocatable_registers = {}, size_t return_slot_count = 0, + uint64_t signature_hash = kInvalidWasmSignatureHash, + uint16_t expected_parameter_count = kDontAdaptArgumentsSentinel) : kind_(kind), tag_(tag), target_type_(target_type), @@ -125,6 +117,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final location_sig_(location_sig), param_slot_count_(param_slot_count), return_slot_count_(return_slot_count), + expected_parameter_count_(expected_parameter_count), properties_(properties), callee_saved_registers_(callee_saved_registers), callee_saved_fp_registers_(callee_saved_fp_registers), @@ -238,6 +231,15 @@ class V8_EXPORT_PRIVATE CallDescriptor final // The number of stack return value slots from the call. size_t ReturnSlotCount() const { return return_slot_count_; } + // The expected formal parameter count of the target JSFunction. It's used + // for ensuring that potentially adapted number of arguments pushed on the + // stack matches the target function's parameter count read from the dispatch + // table entry (V8 sandbox only). + uint16_t expected_parameter_count() const { + DCHECK(IsJSFunctionCall()); + return expected_parameter_count_; + } + // The number of parameters to the JS function call. size_t JSParameterCount() const { DCHECK(IsJSFunctionCall()); @@ -349,6 +351,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final const LocationSignature* const location_sig_; const size_t param_slot_count_; const size_t return_slot_count_; + const uint16_t expected_parameter_count_; const Operator::Properties properties_; const RegList callee_saved_registers_; const DoubleRegList callee_saved_fp_registers_; @@ -410,10 +413,20 @@ class V8_EXPORT_PRIVATE Linkage : public NON_EXPORTED_BASE(ZoneObject) { // Calls to JSFunctions should never overwrite the {properties}, but calls to // known builtins might. static CallDescriptor* GetJSCallDescriptor( - Zone* zone, bool is_osr, int parameter_count, CallDescriptor::Flags flags, + Zone* zone, bool is_osr, int js_parameter_count, + uint16_t expected_parameter_count, CallDescriptor::Flags flags, Operator::Properties properties = Operator::kNoProperties /* use with care! */); + static CallDescriptor* GetJSCallDescriptor( + Zone* zone, bool is_osr, int js_parameter_count, + CallDescriptor::Flags flags, + Operator::Properties properties = + Operator::kNoProperties /* use with care! */) { + return GetJSCallDescriptor(zone, is_osr, js_parameter_count, + js_parameter_count, flags, properties); + } + static CallDescriptor* GetRuntimeCallDescriptor( Zone* zone, Runtime::FunctionId function, int parameter_count, Operator::Properties properties, CallDescriptor::Flags flags, diff --git a/deps/v8/src/compiler/load-elimination.cc b/deps/v8/src/compiler/load-elimination.cc index ca52f4409b5d..05c5ca55f7a4 100644 --- a/deps/v8/src/compiler/load-elimination.cc +++ b/deps/v8/src/compiler/load-elimination.cc @@ -1158,7 +1158,7 @@ Reduction LoadElimination::ReduceLoadElement(Node* node) { case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kCompressed: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kSandboxedPointer: // TODO(turbofan): Add support for doing the truncations. break; @@ -1221,7 +1221,7 @@ Reduction LoadElimination::ReduceStoreElement(Node* node) { case MachineRepresentation::kCompressed: case MachineRepresentation::kSandboxedPointer: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: // TODO(turbofan): Add support for doing the truncations. break; case MachineRepresentation::kFloat64: @@ -1565,7 +1565,7 @@ LoadElimination::IndexRange LoadElimination::FieldIndexOf( case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kCompressed: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kSandboxedPointer: break; } @@ -1574,7 +1574,7 @@ LoadElimination::IndexRange LoadElimination::FieldIndexOf( // We assume that indirect pointers are tagged pointer sized if we see them // here since they should only ever be used in pointer compression // configurations. - DCHECK(rep != MachineRepresentation::kIndirectPointer || + DCHECK(rep != MachineRepresentation::kTrustedPointer || representation_size == kTaggedSize); if (representation_size < kTaggedSize) return IndexRange::Invalid(); DCHECK_EQ(0, representation_size % kTaggedSize); diff --git a/deps/v8/src/compiler/machine-graph-verifier.cc b/deps/v8/src/compiler/machine-graph-verifier.cc index 90b73f601e07..730237c69edf 100644 --- a/deps/v8/src/compiler/machine-graph-verifier.cc +++ b/deps/v8/src/compiler/machine-graph-verifier.cc @@ -163,7 +163,7 @@ class MachineRepresentationInferrer { case IrOpcode::kStore: case IrOpcode::kTrappingStore: case IrOpcode::kStoreTrapOnNull: - case IrOpcode::kStoreIndirectPointer: + case IrOpcode::kStoreTrustedPointer: representation_vector_[node->id()] = PromoteRepresentation( StoreRepresentationOf(node->op()).representation()); break; @@ -560,7 +560,7 @@ class MachineRepresentationChecker { MachineRepresentation::kWord32); [[fallthrough]]; case IrOpcode::kStore: - case IrOpcode::kStoreIndirectPointer: + case IrOpcode::kStoreTrustedPointer: case IrOpcode::kUnalignedStore: case IrOpcode::kWord32AtomicStore: case IrOpcode::kWord32AtomicExchange: @@ -583,7 +583,7 @@ class MachineRepresentationChecker { case MachineRepresentation::kTagged: case MachineRepresentation::kTaggedPointer: case MachineRepresentation::kTaggedSigned: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: if (COMPRESS_POINTERS_BOOL && ((node->opcode() == IrOpcode::kStore && IsAnyTagged(StoreRepresentationOf(node->op()) @@ -610,7 +610,7 @@ class MachineRepresentationChecker { case MachineRepresentation::kTagged: case MachineRepresentation::kTaggedPointer: case MachineRepresentation::kTaggedSigned: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: if (COMPRESS_POINTERS_BOOL) { CheckValueInputIsCompressedOrTagged(node, input); } else { @@ -1041,7 +1041,7 @@ class MachineRepresentationChecker { return IsAnyTagged(actual); case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kSandboxedPointer: case MachineRepresentation::kFloat16RawBits: case MachineRepresentation::kFloat16: diff --git a/deps/v8/src/compiler/machine-operator.cc b/deps/v8/src/compiler/machine-operator.cc index 538fd551300e..611db23f64aa 100644 --- a/deps/v8/src/compiler/machine-operator.cc +++ b/deps/v8/src/compiler/machine-operator.cc @@ -241,7 +241,7 @@ StoreRepresentation const& StoreRepresentationOf(Operator const* op) { DCHECK(IrOpcode::kStore == op->opcode() || IrOpcode::kTrappingStore == op->opcode() || IrOpcode::kStoreTrapOnNull == op->opcode() || - IrOpcode::kStoreIndirectPointer == op->opcode()); + IrOpcode::kStoreTrustedPointer == op->opcode()); return OpParameter<StoreRepresentation>(op); } @@ -1519,32 +1519,31 @@ struct MachineOperatorGlobalCache { #undef STORE_PAIR // Indirect pointer stores have an additional value input (the - // IndirectPointerTag associated with the field being stored to), but + // TrustedPointerTag associated with the field being stored to), but // otherwise are identical to regular stores. - struct StoreIndirectPointerOperator : public Operator1<StoreRepresentation> { - explicit StoreIndirectPointerOperator(WriteBarrierKind write_barrier_kind) + struct StoreTrustedPointerOperator : public Operator1<StoreRepresentation> { + explicit StoreTrustedPointerOperator(WriteBarrierKind write_barrier_kind) : Operator1<StoreRepresentation>( - IrOpcode::kStoreIndirectPointer, + IrOpcode::kStoreTrustedPointer, Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, - "StoreIndirectPointer", 4, 1, 1, 0, 1, 0, - StoreRepresentation(MachineRepresentation::kIndirectPointer, + "StoreTrustedPointer", 4, 1, 1, 0, 1, 0, + StoreRepresentation(MachineRepresentation::kTrustedPointer, write_barrier_kind)) {} }; - struct StoreIndirectPointerNoWriteBarrierOperator final - : public StoreIndirectPointerOperator { - StoreIndirectPointerNoWriteBarrierOperator() - : StoreIndirectPointerOperator(kNoWriteBarrier) {} + struct StoreTrustedPointerNoWriteBarrierOperator final + : public StoreTrustedPointerOperator { + StoreTrustedPointerNoWriteBarrierOperator() + : StoreTrustedPointerOperator(kNoWriteBarrier) {} }; - struct StoreIndirectPointerWithIndirectPointerWriteBarrierOperator final - : public StoreIndirectPointerOperator { - StoreIndirectPointerWithIndirectPointerWriteBarrierOperator() - : StoreIndirectPointerOperator(kIndirectPointerWriteBarrier) {} + struct StoreTrustedPointerWithTrustedPointerWriteBarrierOperator final + : public StoreTrustedPointerOperator { + StoreTrustedPointerWithTrustedPointerWriteBarrierOperator() + : StoreTrustedPointerOperator(kTrustedPointerWriteBarrier) {} }; - StoreIndirectPointerNoWriteBarrierOperator - kStoreIndirectPointerNoWriteBarrier; - StoreIndirectPointerWithIndirectPointerWriteBarrierOperator - kStoreIndirectPointerIndirectPointerWriteBarrier; + StoreTrustedPointerNoWriteBarrierOperator kStoreTrustedPointerNoWriteBarrier; + StoreTrustedPointerWithTrustedPointerWriteBarrierOperator + kStoreTrustedPointerTrustedPointerWriteBarrier; #define ATOMIC_LOAD_WITH_KIND(Type, Kind) \ struct Word32SeqCstLoad##Type##Kind##Operator \ @@ -1892,7 +1891,7 @@ const Operator* MachineOperatorBuilder::UnalignedStore( #undef STORE case MachineRepresentation::kBit: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kNone: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); @@ -2156,8 +2155,7 @@ const Operator* MachineOperatorBuilder::StackSlot(MachineRepresentation rep, const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) { DCHECK_NE(store_rep.representation(), MachineRepresentation::kMapWord); - DCHECK_NE(store_rep.representation(), - MachineRepresentation::kIndirectPointer); + DCHECK_NE(store_rep.representation(), MachineRepresentation::kTrustedPointer); switch (store_rep.representation()) { #define STORE(kRep) \ case MachineRepresentation::kRep: \ @@ -2172,7 +2170,7 @@ const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) { return &cache_.k##Store##kRep##MapWriteBarrier; \ case kPointerWriteBarrier: \ return &cache_.k##Store##kRep##PointerWriteBarrier; \ - case kIndirectPointerWriteBarrier: \ + case kTrustedPointerWriteBarrier: \ UNREACHABLE(); \ case kEphemeronKeyWriteBarrier: \ return &cache_.k##Store##kRep##EphemeronKeyWriteBarrier; \ @@ -2184,7 +2182,7 @@ const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) { #undef STORE case MachineRepresentation::kBit: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kNone: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); @@ -2192,13 +2190,13 @@ const Operator* MachineOperatorBuilder::Store(StoreRepresentation store_rep) { UNREACHABLE(); } -const Operator* MachineOperatorBuilder::StoreIndirectPointer( +const Operator* MachineOperatorBuilder::StoreTrustedPointer( WriteBarrierKind write_barrier_kind) { switch (write_barrier_kind) { case kNoWriteBarrier: - return &cache_.kStoreIndirectPointerNoWriteBarrier; - case kIndirectPointerWriteBarrier: - return &cache_.kStoreIndirectPointerIndirectPointerWriteBarrier; + return &cache_.kStoreTrustedPointerNoWriteBarrier; + case kTrustedPointerWriteBarrier: + return &cache_.kStoreTrustedPointerTrustedPointerWriteBarrier; default: UNREACHABLE(); } @@ -2234,7 +2232,7 @@ const Operator* MachineOperatorBuilder::TrappingStore( #undef STORE case MachineRepresentation::kBit: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kNone: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); @@ -2256,7 +2254,7 @@ const Operator* MachineOperatorBuilder::StoreTrapOnNull( #undef STORE case MachineRepresentation::kBit: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kNone: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); diff --git a/deps/v8/src/compiler/machine-operator.h b/deps/v8/src/compiler/machine-operator.h index 4292f76ac1da..aa5e4c74ea13 100644 --- a/deps/v8/src/compiler/machine-operator.h +++ b/deps/v8/src/compiler/machine-operator.h @@ -1256,7 +1256,7 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final const Operator* Store(StoreRepresentation rep); std::optional<const Operator*> TryStorePair(StoreRepresentation rep1, StoreRepresentation rep2); - const Operator* StoreIndirectPointer(WriteBarrierKind write_barrier_kind); + const Operator* StoreTrustedPointer(WriteBarrierKind write_barrier_kind); const Operator* TrappingStore(MachineRepresentation rep); const Operator* StoreTrapOnNull(StoreRepresentation rep); diff --git a/deps/v8/src/compiler/memory-lowering.cc b/deps/v8/src/compiler/memory-lowering.cc deleted file mode 100644 index caafb245b83d..000000000000 --- a/deps/v8/src/compiler/memory-lowering.cc +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright 2019 the V8 project 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 "src/compiler/memory-lowering.h" - -#include "src/codegen/interface-descriptors-inl.h" -#include "src/common/globals.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/linkage.h" -#include "src/compiler/node-matchers.h" -#include "src/compiler/node-properties.h" -#include "src/compiler/node.h" -#include "src/compiler/simplified-operator.h" -#include "src/roots/roots-inl.h" -#include "src/sandbox/external-pointer-inl.h" - -#if V8_ENABLE_WEBASSEMBLY -#include "src/wasm/wasm-linkage.h" -#include "src/wasm/wasm-objects.h" -#endif -namespace v8 { -namespace internal { -namespace compiler { - -// An allocation group represents a set of allocations that have been folded -// together. -class MemoryLowering::AllocationGroup final : public ZoneObject { - public: - AllocationGroup(Node* node, AllocationType allocation, Zone* zone); - AllocationGroup(Node* node, AllocationType allocation, Node* size, - Zone* zone); - ~AllocationGroup() = default; - - void Add(Node* object); - bool Contains(Node* object) const; - bool IsYoungGenerationAllocation() const { - return allocation() == AllocationType::kYoung; - } - - AllocationType allocation() const { return allocation_; } - Node* size() const { return size_; } - - private: - ZoneSet<NodeId> node_ids_; - AllocationType const allocation_; - Node* const size_; - - static inline AllocationType CheckAllocationType(AllocationType allocation) { - // For non-generational heap, all young allocations are redirected to old - // space. - if (v8_flags.single_generation && allocation == AllocationType::kYoung) { - return AllocationType::kOld; - } - return allocation; - } - - DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationGroup); -}; - -MemoryLowering::MemoryLowering(JSGraph* jsgraph, Zone* zone, - JSGraphAssembler* graph_assembler, bool is_wasm, - AllocationFolding allocation_folding, - WriteBarrierAssertFailedCallback callback, - const char* function_debug_name) - : isolate_(jsgraph->isolate()), - zone_(zone), - graph_(jsgraph->graph()), - common_(jsgraph->common()), - machine_(jsgraph->machine()), - graph_assembler_(graph_assembler), - is_wasm_(is_wasm), - allocation_folding_(allocation_folding), - write_barrier_assert_failed_(callback), - function_debug_name_(function_debug_name) {} - -Zone* MemoryLowering::graph_zone() const { return graph()->zone(); } - -Reduction MemoryLowering::Reduce(Node* node) { - switch (node->opcode()) { - case IrOpcode::kAllocate: - // Allocate nodes were purged from the graph in effect-control - // linearization. - UNREACHABLE(); - case IrOpcode::kAllocateRaw: - return ReduceAllocateRaw(node); - case IrOpcode::kLoadFromObject: - case IrOpcode::kLoadImmutableFromObject: - return ReduceLoadFromObject(node); - case IrOpcode::kLoadElement: - return ReduceLoadElement(node); - case IrOpcode::kLoadField: - return ReduceLoadField(node); - case IrOpcode::kStoreToObject: - case IrOpcode::kInitializeImmutableInObject: - return ReduceStoreToObject(node); - case IrOpcode::kStoreElement: - return ReduceStoreElement(node); - case IrOpcode::kStoreField: - return ReduceStoreField(node); - case IrOpcode::kStore: - return ReduceStore(node); - default: - return NoChange(); - } -} - -void MemoryLowering::EnsureAllocateOperator() { - if (allocate_operator_.is_set()) return; - - auto descriptor = AllocateDescriptor{}; - StubCallMode mode = isolate_ != nullptr ? StubCallMode::kCallCodeObject - : StubCallMode::kCallBuiltinPointer; - auto call_descriptor = Linkage::GetStubCallDescriptor( - graph_zone(), descriptor, descriptor.GetStackParameterCount(), - CallDescriptor::kCanUseRoots, Operator::kNoThrow, mode); - allocate_operator_.set(common()->Call(call_descriptor)); -} - -#if V8_ENABLE_WEBASSEMBLY -Node* MemoryLowering::GetWasmInstanceNode() { - if (wasm_instance_node_.is_set()) return wasm_instance_node_.get(); - for (Node* use : graph()->start()->uses()) { - if (use->opcode() == IrOpcode::kParameter && - ParameterIndexOf(use->op()) == wasm::kWasmInstanceDataParameterIndex) { - wasm_instance_node_.set(use); - return use; - } - } - UNREACHABLE(); // The instance node must have been created before. -} -#endif // V8_ENABLE_WEBASSEMBLY - -#define __ gasm()-> - -Node* MemoryLowering::AlignToAllocationAlignment(Node* value) { - if (!V8_COMPRESS_POINTERS_8GB_BOOL) return value; - - auto already_aligned = __ MakeLabel(MachineRepresentation::kWord64); - Node* alignment_check = __ WordEqual( - __ WordAnd(value, __ UintPtrConstant(kObjectAlignment8GbHeapMask)), - __ UintPtrConstant(0)); - - __ GotoIf(alignment_check, &already_aligned, value); - { - Node* aligned_value; - if (kObjectAlignment8GbHeap == 2 * kTaggedSize) { - aligned_value = __ IntPtrAdd(value, __ IntPtrConstant(kTaggedSize)); - } else { - aligned_value = __ WordAnd( - __ IntPtrAdd(value, __ IntPtrConstant(kObjectAlignment8GbHeapMask)), - __ UintPtrConstant(~kObjectAlignment8GbHeapMask)); - } - __ Goto(&already_aligned, aligned_value); - } - - __ Bind(&already_aligned); - - return already_aligned.PhiAt(0); -} - -Reduction MemoryLowering::ReduceAllocateRaw(Node* node, - AllocationType allocation_type, - AllocationState const** state_ptr) { - DCHECK_EQ(IrOpcode::kAllocateRaw, node->opcode()); - DCHECK_IMPLIES(allocation_folding_ == AllocationFolding::kDoAllocationFolding, - state_ptr != nullptr); - if (v8_flags.single_generation && allocation_type == AllocationType::kYoung) { - allocation_type = AllocationType::kOld; - } - // InstructionStream objects may have a maximum size smaller than - // kMaxHeapObjectSize due to guard pages. If we need to support allocating - // code here we would need to call - // MemoryChunkLayout::MaxRegularCodeObjectSize() at runtime. - DCHECK_NE(allocation_type, AllocationType::kCode); - Node* value; - Node* size = node->InputAt(0); - Node* effect = node->InputAt(1); - Node* control = node->InputAt(2); - - gasm()->InitializeEffectControl(effect, control); - - Node* allocate_builtin; - if (!is_wasm_) { - if (allocation_type == AllocationType::kYoung) { - allocate_builtin = __ AllocateInYoungGenerationStubConstant(); - } else { - allocate_builtin = __ AllocateInOldGenerationStubConstant(); - } - } else { -#if V8_ENABLE_WEBASSEMBLY - // This lowering is used by Wasm, where we compile isolate-independent - // code. Builtin calls simply encode the target builtin ID, which will - // be patched to the builtin's address later. - if (isolate_ == nullptr) { - Builtin builtin; - if (allocation_type == AllocationType::kYoung) { - builtin = Builtin::kWasmAllocateInYoungGeneration; - } else { - builtin = Builtin::kWasmAllocateInOldGeneration; - } - static_assert(std::is_same_v<Smi, BuiltinPtr>, "BuiltinPtr must be Smi"); - allocate_builtin = - graph()->NewNode(common()->NumberConstant(static_cast<int>(builtin))); - } else { - if (allocation_type == AllocationType::kYoung) { - allocate_builtin = __ WasmAllocateInYoungGenerationStubConstant(); - } else { - allocate_builtin = __ WasmAllocateInOldGenerationStubConstant(); - } - } -#else - UNREACHABLE(); -#endif - } - - // Determine the top/limit addresses. - Node* top_address = - __ IsolateField(allocation_type == AllocationType::kYoung - ? IsolateFieldId::kNewAllocationInfoTop - : IsolateFieldId::kOldAllocationInfoTop); - Node* limit_address = - __ IsolateField(allocation_type == AllocationType::kYoung - ? IsolateFieldId::kNewAllocationInfoLimit - : IsolateFieldId::kOldAllocationInfoLimit); - - // Check if we can fold this allocation into a previous allocation represented - // by the incoming {state}. - IntPtrMatcher m(size); - if (m.IsInRange(0, kMaxRegularHeapObjectSize) && v8_flags.inline_new && - allocation_folding_ == AllocationFolding::kDoAllocationFolding) { - intptr_t const object_size = - ALIGN_TO_ALLOCATION_ALIGNMENT(m.ResolvedValue()); - AllocationState const* state = *state_ptr; - if (state->size() <= kMaxRegularHeapObjectSize - object_size && - state->group()->allocation() == allocation_type) { - // We can fold this Allocate {node} into the allocation {group} - // represented by the given {state}. Compute the upper bound for - // the new {state}. - intptr_t const state_size = state->size() + object_size; - - // Update the reservation check to the actual maximum upper bound. - AllocationGroup* const group = state->group(); - if (machine()->Is64()) { - if (OpParameter<int64_t>(group->size()->op()) < state_size) { - NodeProperties::ChangeOp(group->size(), - common()->Int64Constant(state_size)); - } - } else { - if (OpParameter<int32_t>(group->size()->op()) < state_size) { - NodeProperties::ChangeOp( - group->size(), - common()->Int32Constant(static_cast<int32_t>(state_size))); - } - } - - // Update the allocation top with the new object allocation. - // TODO(bmeurer): Defer writing back top as much as possible. - DCHECK_IMPLIES(V8_COMPRESS_POINTERS_8GB_BOOL, - IsAligned(object_size, kObjectAlignment8GbHeap)); - Node* top = __ IntAdd(state->top(), __ IntPtrConstant(object_size)); - __ Store(StoreRepresentation(MachineType::PointerRepresentation(), - kNoWriteBarrier), - top_address, __ IntPtrConstant(0), top); - - // Compute the effective inner allocated address. - value = __ BitcastWordToTagged( - __ IntAdd(state->top(), __ IntPtrConstant(kHeapObjectTag))); - effect = gasm()->effect(); - control = gasm()->control(); - - // Extend the allocation {group}. - group->Add(value); - *state_ptr = - AllocationState::Open(group, state_size, top, effect, zone()); - } else { - auto call_runtime = __ MakeDeferredLabel(); - auto done = __ MakeLabel(MachineType::PointerRepresentation()); - - // Setup a mutable reservation size node; will be patched as we fold - // additional allocations into this new group. - Node* reservation_size = __ UniqueIntPtrConstant(object_size); - - // Load allocation top and limit. - Node* top = - __ Load(MachineType::Pointer(), top_address, __ IntPtrConstant(0)); - Node* limit = - __ Load(MachineType::Pointer(), limit_address, __ IntPtrConstant(0)); - - // Check if we need to collect garbage before we can start bump pointer - // allocation (always done for folded allocations). - Node* check = __ UintLessThan(__ IntAdd(top, reservation_size), limit); - - __ GotoIfNot(check, &call_runtime); - __ Goto(&done, top); - - __ Bind(&call_runtime); - { - EnsureAllocateOperator(); - Node* vfalse = __ BitcastTaggedToWord(__ Call( - allocate_operator_.get(), allocate_builtin, reservation_size)); - vfalse = __ IntSub(vfalse, __ IntPtrConstant(kHeapObjectTag)); - __ Goto(&done, vfalse); - } - - __ Bind(&done); - - // Compute the new top and write it back. - top = __ IntAdd(done.PhiAt(0), __ IntPtrConstant(object_size)); - __ Store(StoreRepresentation(MachineType::PointerRepresentation(), - kNoWriteBarrier), - top_address, __ IntPtrConstant(0), top); - - // Compute the initial object address. - value = __ BitcastWordToTagged( - __ IntAdd(done.PhiAt(0), __ IntPtrConstant(kHeapObjectTag))); - effect = gasm()->effect(); - control = gasm()->control(); - - // Start a new allocation group. - AllocationGroup* group = zone()->New<AllocationGroup>( - value, allocation_type, reservation_size, zone()); - *state_ptr = - AllocationState::Open(group, object_size, top, effect, zone()); - } - } else { - auto call_runtime = __ MakeDeferredLabel(); - auto done = __ MakeLabel(MachineRepresentation::kTaggedPointer); - - // Load allocation top and limit. - Node* top = - __ Load(MachineType::Pointer(), top_address, __ IntPtrConstant(0)); - Node* limit = - __ Load(MachineType::Pointer(), limit_address, __ IntPtrConstant(0)); - - // Compute the new top. - Node* new_top = __ IntAdd(top, AlignToAllocationAlignment(size)); - - // Check if we can do bump pointer allocation here. - Node* check = __ UintLessThan(new_top, limit); - __ GotoIfNot(check, &call_runtime); - __ GotoIfNot( - __ UintLessThan(size, __ IntPtrConstant(kMaxRegularHeapObjectSize)), - &call_runtime); - __ Store(StoreRepresentation(MachineType::PointerRepresentation(), - kNoWriteBarrier), - top_address, __ IntPtrConstant(0), new_top); - __ Goto(&done, __ BitcastWordToTagged( - __ IntAdd(top, __ IntPtrConstant(kHeapObjectTag)))); - - __ Bind(&call_runtime); - EnsureAllocateOperator(); - __ Goto(&done, __ Call(allocate_operator_.get(), allocate_builtin, size)); - - __ Bind(&done); - value = done.PhiAt(0); - effect = gasm()->effect(); - control = gasm()->control(); - - if (state_ptr) { - // Create an unfoldable allocation group. - AllocationGroup* group = - zone()->New<AllocationGroup>(value, allocation_type, zone()); - *state_ptr = AllocationState::Closed(group, effect, zone()); - } - } - - return Replace(value); -} - -Reduction MemoryLowering::ReduceLoadFromObject(Node* node) { - DCHECK(node->opcode() == IrOpcode::kLoadFromObject || - node->opcode() == IrOpcode::kLoadImmutableFromObject); - ObjectAccess const& access = ObjectAccessOf(node->op()); - - MachineType machine_type = access.machine_type; - - if (machine_type.IsMapWord()) { - CHECK_EQ(machine_type.semantic(), MachineSemantic::kAny); - return ReduceLoadMap(node); - } - - MachineRepresentation rep = machine_type.representation(); - const Operator* load_op = - ElementSizeInBytes(rep) > kTaggedSize && - !machine()->UnalignedLoadSupported(machine_type.representation()) - ? machine()->UnalignedLoad(machine_type) - : machine()->Load(machine_type); - NodeProperties::ChangeOp(node, load_op); - return Changed(node); -} - -Reduction MemoryLowering::ReduceLoadElement(Node* node) { - DCHECK_EQ(IrOpcode::kLoadElement, node->opcode()); - ElementAccess const& access = ElementAccessOf(node->op()); - Node* index = node->InputAt(1); - node->ReplaceInput(1, ComputeIndex(access, index)); - MachineType type = access.machine_type; - DCHECK(!type.IsMapWord()); - NodeProperties::ChangeOp(node, machine()->Load(type)); - return Changed(node); -} - -Reduction MemoryLowering::ReduceLoadExternalPointerField(Node* node) { - DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); - FieldAccess const& access = FieldAccessOf(node->op()); - -#ifdef V8_ENABLE_SANDBOX - ExternalPointerTag tag = access.external_pointer_tag; - DCHECK_NE(tag, kExternalPointerNullTag); - // Fields for sandboxed external pointer contain a 32-bit handle, not a - // 64-bit raw pointer. - NodeProperties::ChangeOp(node, machine()->Load(MachineType::Uint32())); - - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - __ InitializeEffectControl(effect, control); - - // Clone the load node and put it here. - // TODO(turbofan): consider adding GraphAssembler::Clone() suitable for - // cloning nodes from arbitrary locations in effect/control chains. - static_assert(kExternalPointerIndexShift > kSystemPointerSizeLog2); - Node* handle = __ AddNode(graph()->CloneNode(node)); - Node* shift_amount = - __ Int32Constant(kExternalPointerIndexShift - kSystemPointerSizeLog2); - Node* offset = __ Word32Shr(handle, shift_amount); - - // Uncomment this to generate a breakpoint for debugging purposes. - // __ DebugBreak(); - - // Decode loaded external pointer. - // - // Here we access the external pointer table through an ExternalReference. - // Alternatively, we could also hardcode the address of the table since it - // is never reallocated. However, in that case we must be able to guarantee - // that the generated code is never executed under a different Isolate, as - // that would allow access to external objects from different Isolates. It - // also would break if the code is serialized/deserialized at some point. - Node* table_address = - IsSharedExternalPointerType(tag) - ? __ - Load(MachineType::Pointer(), - __ ExternalConstant( - ExternalReference:: - shared_external_pointer_table_address_address( - isolate())), - __ IntPtrConstant(0)) - : __ ExternalConstant( - ExternalReference::external_pointer_table_address(isolate())); - Node* table = __ Load(MachineType::Pointer(), table_address, - Internals::kExternalEntityTableBasePointerOffset); - Node* pointer = - __ Load(MachineType::Pointer(), table, __ ChangeUint32ToUint64(offset)); - Node* actual_tag = - __ WordAnd(pointer, __ IntPtrConstant(kExternalPointerTagMask)); - actual_tag = __ TruncateInt64ToInt32( - __ WordShr(actual_tag, __ IntPtrConstant(kExternalPointerTagShift))); - Node* expected_tag = __ Int32Constant(tag); - pointer = - __ Word64And(pointer, __ IntPtrConstant(kExternalPointerPayloadMask)); - auto done = __ MakeLabel(MachineRepresentation::kWord64); - __ GotoIf(__ WordEqual(actual_tag, expected_tag), &done, pointer); - __ Goto(&done, __ IntPtrConstant(0)); - __ Bind(&done); - return Replace(done.PhiAt(0)); -#else - NodeProperties::ChangeOp(node, machine()->Load(access.machine_type)); - return Changed(node); -#endif // V8_ENABLE_SANDBOX -} - -Reduction MemoryLowering::ReduceLoadBoundedSize(Node* node) { -#ifdef V8_ENABLE_SANDBOX - const Operator* load_op = - !machine()->UnalignedLoadSupported(MachineRepresentation::kWord64) - ? machine()->UnalignedLoad(MachineType::Uint64()) - : machine()->Load(MachineType::Uint64()); - NodeProperties::ChangeOp(node, load_op); - - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - __ InitializeEffectControl(effect, control); - - Node* raw_value = __ AddNode(graph()->CloneNode(node)); - Node* shift_amount = __ IntPtrConstant(kBoundedSizeShift); - Node* decoded_size = __ Word64Shr(raw_value, shift_amount); - return Replace(decoded_size); -#else - UNREACHABLE(); -#endif -} - -Reduction MemoryLowering::ReduceLoadMap(Node* node) { -#ifdef V8_MAP_PACKING - NodeProperties::ChangeOp(node, machine()->Load(MachineType::AnyTagged())); - - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - __ InitializeEffectControl(effect, control); - - node = __ AddNode(graph()->CloneNode(node)); - return Replace(__ UnpackMapWord(node)); -#else - NodeProperties::ChangeOp(node, machine()->Load(MachineType::TaggedPointer())); - return Changed(node); -#endif -} - -Reduction MemoryLowering::ReduceLoadField(Node* node) { - DCHECK_EQ(IrOpcode::kLoadField, node->opcode()); - FieldAccess const& access = FieldAccessOf(node->op()); - Node* offset = __ IntPtrConstant(access.offset - access.tag()); - node->InsertInput(graph_zone(), 1, offset); - MachineType type = access.machine_type; - - if (type.IsMapWord()) { - DCHECK(!access.type.Is(Type::ExternalPointer())); - return ReduceLoadMap(node); - } - - if (access.type.Is(Type::ExternalPointer())) { - return ReduceLoadExternalPointerField(node); - } - - if (access.is_bounded_size_access) { - return ReduceLoadBoundedSize(node); - } - - NodeProperties::ChangeOp(node, machine()->Load(type)); - - return Changed(node); -} - -Reduction MemoryLowering::ReduceStoreToObject(Node* node, - AllocationState const* state) { - DCHECK(node->opcode() == IrOpcode::kStoreToObject || - node->opcode() == IrOpcode::kInitializeImmutableInObject); - ObjectAccess const& access = ObjectAccessOf(node->op()); - Node* object = node->InputAt(0); - Node* value = node->InputAt(2); - - WriteBarrierKind write_barrier_kind = ComputeWriteBarrierKind( - node, object, value, state, access.write_barrier_kind); - DCHECK(!access.machine_type.IsMapWord()); - MachineRepresentation rep = access.machine_type.representation(); - StoreRepresentation store_rep(rep, write_barrier_kind); - const Operator* store_op = ElementSizeInBytes(rep) > kTaggedSize && - !machine()->UnalignedStoreSupported(rep) - ? machine()->UnalignedStore(rep) - : machine()->Store(store_rep); - NodeProperties::ChangeOp(node, store_op); - return Changed(node); -} - -Reduction MemoryLowering::ReduceStoreElement(Node* node, - AllocationState const* state) { - DCHECK_EQ(IrOpcode::kStoreElement, node->opcode()); - ElementAccess const& access = ElementAccessOf(node->op()); - Node* object = node->InputAt(0); - Node* index = node->InputAt(1); - Node* value = node->InputAt(2); - node->ReplaceInput(1, ComputeIndex(access, index)); - WriteBarrierKind write_barrier_kind = ComputeWriteBarrierKind( - node, object, value, state, access.write_barrier_kind); - NodeProperties::ChangeOp( - node, machine()->Store(StoreRepresentation( - access.machine_type.representation(), write_barrier_kind))); - return Changed(node); -} - -Reduction MemoryLowering::ReduceStoreField(Node* node, - AllocationState const* state) { - DCHECK_EQ(IrOpcode::kStoreField, node->opcode()); - FieldAccess const& access = FieldAccessOf(node->op()); - // External pointer must never be stored by optimized code when sandbox is - // turned on - DCHECK(!access.type.Is(Type::ExternalPointer()) || !V8_ENABLE_SANDBOX_BOOL); - // SandboxedPointers are not currently stored by optimized code. - DCHECK(!access.type.Is(Type::SandboxedPointer())); - // Bounded size fields are not currently stored by optimized code. - DCHECK(!access.is_bounded_size_access); - MachineType machine_type = access.machine_type; - Node* object = node->InputAt(0); - Node* value = node->InputAt(1); - - Node* effect = NodeProperties::GetEffectInput(node); - Node* control = NodeProperties::GetControlInput(node); - __ InitializeEffectControl(effect, control); - - WriteBarrierKind write_barrier_kind = ComputeWriteBarrierKind( - node, object, value, state, access.write_barrier_kind); - Node* offset = __ IntPtrConstant(access.offset - access.tag()); - node->InsertInput(graph_zone(), 1, offset); - - if (machine_type.IsMapWord()) { - machine_type = MachineType::TaggedPointer(); -#ifdef V8_MAP_PACKING - Node* mapword = __ PackMapWord(TNode<Map>::UncheckedCast(value)); - node->ReplaceInput(2, mapword); -#endif - } - if (machine_type.representation() == - MachineRepresentation::kIndirectPointer) { - // Indirect pointer stores require knowledge of the indirect pointer tag of - // the field. This is technically only required for stores that need a - // write barrier, but currently we track the tag for all such stores. - DCHECK_NE(access.indirect_pointer_tag, kIndirectPointerNullTag); - Node* tag = __ IntPtrConstant(access.indirect_pointer_tag); - node->InsertInput(graph_zone(), 3, tag); - NodeProperties::ChangeOp( - node, machine()->StoreIndirectPointer(write_barrier_kind)); - } else { - NodeProperties::ChangeOp( - node, machine()->Store(StoreRepresentation( - machine_type.representation(), write_barrier_kind))); - } - return Changed(node); -} - -Reduction MemoryLowering::ReduceStore(Node* node, - AllocationState const* state) { - DCHECK_EQ(IrOpcode::kStore, node->opcode()); - StoreRepresentation representation = StoreRepresentationOf(node->op()); - Node* object = node->InputAt(0); - Node* value = node->InputAt(2); - WriteBarrierKind write_barrier_kind = ComputeWriteBarrierKind( - node, object, value, state, representation.write_barrier_kind()); - if (write_barrier_kind != representation.write_barrier_kind()) { - NodeProperties::ChangeOp( - node, machine()->Store(StoreRepresentation( - representation.representation(), write_barrier_kind))); - return Changed(node); - } - return NoChange(); -} - -Node* MemoryLowering::ComputeIndex(ElementAccess const& access, Node* index) { - int const element_size_shift = - ElementSizeLog2Of(access.machine_type.representation()); - if (element_size_shift) { - index = __ WordShl(index, __ IntPtrConstant(element_size_shift)); - } - int const fixed_offset = access.header_size - access.tag(); - if (fixed_offset) { - index = __ IntAdd(index, __ IntPtrConstant(fixed_offset)); - } - return index; -} - -#undef __ - -namespace { - -bool ValueNeedsWriteBarrier(Node* value, Isolate* isolate) { - switch (value->opcode()) { - case IrOpcode::kBitcastWordToTaggedSigned: - return false; - case IrOpcode::kHeapConstant: { - RootIndex root_index; - if (isolate->roots_table().IsRootHandle(HeapConstantOf(value->op()), - &root_index) && - RootsTable::IsImmortalImmovable(root_index)) { - return false; - } - break; - } - default: - break; - } - return true; -} - -} // namespace - -Reduction MemoryLowering::ReduceAllocateRaw(Node* node) { - DCHECK_EQ(IrOpcode::kAllocateRaw, node->opcode()); - const AllocateParameters& allocation = AllocateParametersOf(node->op()); - return ReduceAllocateRaw(node, allocation.allocation_type(), nullptr); -} - -WriteBarrierKind MemoryLowering::ComputeWriteBarrierKind( - Node* node, Node* object, Node* value, AllocationState const* state, - WriteBarrierKind write_barrier_kind) { - if (state && state->IsYoungGenerationAllocation() && - state->group()->Contains(object)) { - write_barrier_kind = kNoWriteBarrier; - } - if (!ValueNeedsWriteBarrier(value, isolate())) { - write_barrier_kind = kNoWriteBarrier; - } - if (v8_flags.disable_write_barriers) { - write_barrier_kind = kNoWriteBarrier; - } - if (write_barrier_kind == WriteBarrierKind::kAssertNoWriteBarrier) { - write_barrier_assert_failed_(node, object, function_debug_name_, zone()); - } - return write_barrier_kind; -} - -MemoryLowering::AllocationGroup::AllocationGroup(Node* node, - AllocationType allocation, - Zone* zone) - : node_ids_(zone), - allocation_(CheckAllocationType(allocation)), - size_(nullptr) { - node_ids_.insert(node->id()); -} - -MemoryLowering::AllocationGroup::AllocationGroup(Node* node, - AllocationType allocation, - Node* size, Zone* zone) - : node_ids_(zone), - allocation_(CheckAllocationType(allocation)), - size_(size) { - node_ids_.insert(node->id()); -} - -void MemoryLowering::AllocationGroup::Add(Node* node) { - node_ids_.insert(node->id()); -} - -bool MemoryLowering::AllocationGroup::Contains(Node* node) const { - // Additions should stay within the same allocated object, so it's safe to - // ignore them. - while (node_ids_.find(node->id()) == node_ids_.end()) { - switch (node->opcode()) { - case IrOpcode::kBitcastTaggedToWord: - case IrOpcode::kBitcastWordToTagged: - case IrOpcode::kInt32Add: - case IrOpcode::kInt64Add: - node = NodeProperties::GetValueInput(node, 0); - break; - default: - return false; - } - } - return true; -} - -MemoryLowering::AllocationState::AllocationState() - : group_(nullptr), - size_(std::numeric_limits<int>::max()), - top_(nullptr), - effect_(nullptr) {} - -MemoryLowering::AllocationState::AllocationState(AllocationGroup* group, - Node* effect) - : group_(group), - size_(std::numeric_limits<int>::max()), - top_(nullptr), - effect_(effect) {} - -MemoryLowering::AllocationState::AllocationState(AllocationGroup* group, - intptr_t size, Node* top, - Node* effect) - : group_(group), size_(size), top_(top), effect_(effect) {} - -bool MemoryLowering::AllocationState::IsYoungGenerationAllocation() const { - return group() && group()->IsYoungGenerationAllocation(); -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/compiler/memory-lowering.h b/deps/v8/src/compiler/memory-lowering.h deleted file mode 100644 index 1e237fac7657..000000000000 --- a/deps/v8/src/compiler/memory-lowering.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2019 the V8 project 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 V8_COMPILER_MEMORY_LOWERING_H_ -#define V8_COMPILER_MEMORY_LOWERING_H_ - -#include "src/compiler/graph-assembler.h" -#include "src/compiler/graph-reducer.h" - -namespace v8 { -namespace internal { -namespace compiler { - -// Forward declarations. -class CommonOperatorBuilder; -struct ElementAccess; -class TFGraph; -class JSGraph; -class MachineOperatorBuilder; -class Node; -class Operator; - -// Provides operations to lower all simplified memory access and allocation -// related nodes (i.e. Allocate, LoadField, StoreField and friends) to machine -// operators. -class MemoryLowering final : public Reducer { - public: - enum class AllocationFolding { kDoAllocationFolding, kDontAllocationFolding }; - class AllocationGroup; - - // An allocation state is propagated on the effect paths through the graph. - class AllocationState final : public ZoneObject { - public: - AllocationState(const AllocationState&) = delete; - AllocationState& operator=(const AllocationState&) = delete; - - static AllocationState const* Empty(Zone* zone) { - return zone->New<AllocationState>(); - } - static AllocationState const* Closed(AllocationGroup* group, Node* effect, - Zone* zone) { - return zone->New<AllocationState>(group, effect); - } - static AllocationState const* Open(AllocationGroup* group, intptr_t size, - Node* top, Node* effect, Zone* zone) { - return zone->New<AllocationState>(group, size, top, effect); - } - - bool IsYoungGenerationAllocation() const; - - AllocationGroup* group() const { return group_; } - Node* top() const { return top_; } - Node* effect() const { return effect_; } - intptr_t size() const { return size_; } - - private: - friend Zone; - - AllocationState(); - explicit AllocationState(AllocationGroup* group, Node* effect); - AllocationState(AllocationGroup* group, intptr_t size, Node* top, - Node* effect); - - AllocationGroup* const group_; - // The upper bound of the combined allocated object size on the current path - // (max int if allocation folding is impossible on this path). - intptr_t const size_; - Node* const top_; - Node* const effect_; - }; - - using WriteBarrierAssertFailedCallback = std::function<void( - Node* node, Node* object, const char* name, Zone* temp_zone)>; - - MemoryLowering( - JSGraph* jsgraph, Zone* zone, JSGraphAssembler* graph_assembler, - bool is_wasm, - AllocationFolding allocation_folding = - AllocationFolding::kDontAllocationFolding, - WriteBarrierAssertFailedCallback callback = [](Node*, Node*, const char*, - Zone*) { UNREACHABLE(); }, - const char* function_debug_name = nullptr); - - const char* reducer_name() const override { return "MemoryReducer"; } - - // Perform memory lowering reduction on the given Node. - Reduction Reduce(Node* node) override; - - // Specific reducers for each optype to enable keeping track of - // AllocationState by the MemoryOptimizer. - Reduction ReduceAllocateRaw(Node* node, AllocationType allocation_type, - AllocationState const** state); - Reduction ReduceLoadFromObject(Node* node); - Reduction ReduceLoadElement(Node* node); - Reduction ReduceLoadField(Node* node); - Reduction ReduceStoreToObject(Node* node, - AllocationState const* state = nullptr); - Reduction ReduceStoreElement(Node* node, - AllocationState const* state = nullptr); - Reduction ReduceStoreField(Node* node, - AllocationState const* state = nullptr); - Reduction ReduceStore(Node* node, AllocationState const* state = nullptr); - - private: - Reduction ReduceAllocateRaw(Node* node); - WriteBarrierKind ComputeWriteBarrierKind(Node* node, Node* object, - Node* value, - AllocationState const* state, - WriteBarrierKind); - Reduction ReduceLoadExternalPointerField(Node* node); - Reduction ReduceLoadBoundedSize(Node* node); - Reduction ReduceLoadMap(Node* node); - Node* ComputeIndex(ElementAccess const& access, Node* node); - void EnsureAllocateOperator(); - Node* GetWasmInstanceNode(); - - // Align the value to kObjectAlignment8GbHeap if V8_COMPRESS_POINTERS_8GB is - // defined. - Node* AlignToAllocationAlignment(Node* address); - - TFGraph* graph() const { return graph_; } - Isolate* isolate() const { return isolate_; } - Zone* zone() const { return zone_; } - inline Zone* graph_zone() const; - CommonOperatorBuilder* common() const { return common_; } - MachineOperatorBuilder* machine() const { return machine_; } - JSGraphAssembler* gasm() const { return graph_assembler_; } - - SetOncePointer<const Operator> allocate_operator_; - SetOncePointer<Node> wasm_instance_node_; - Isolate* isolate_; - Zone* zone_; - TFGraph* graph_; - CommonOperatorBuilder* common_; - MachineOperatorBuilder* machine_; - JSGraphAssembler* graph_assembler_; - bool is_wasm_; - AllocationFolding allocation_folding_; - WriteBarrierAssertFailedCallback write_barrier_assert_failed_; - const char* function_debug_name_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLowering); -}; - -} // namespace compiler -} // namespace internal -} // namespace v8 - -#endif // V8_COMPILER_MEMORY_LOWERING_H_ diff --git a/deps/v8/src/compiler/memory-optimizer.cc b/deps/v8/src/compiler/memory-optimizer.cc deleted file mode 100644 index 24bc838bc848..000000000000 --- a/deps/v8/src/compiler/memory-optimizer.cc +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright 2016 the V8 project 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 "src/compiler/memory-optimizer.h" - -#include "src/base/logging.h" -#include "src/codegen/tick-counter.h" -#include "src/compiler/common-operator.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/linkage.h" -#include "src/compiler/node-properties.h" -#include "src/compiler/node.h" -#include "src/roots/roots-inl.h" - -namespace v8 { -namespace internal { -namespace compiler { - -namespace { - -bool CanAllocate(const Node* node) { - switch (node->opcode()) { - case IrOpcode::kAbortCSADcheck: - case IrOpcode::kBitcastTaggedToWord: - case IrOpcode::kBitcastWordToTagged: - case IrOpcode::kCheckTurboshaftTypeOf: - case IrOpcode::kComment: - case IrOpcode::kDebugBreak: - case IrOpcode::kDeoptimizeIf: - case IrOpcode::kDeoptimizeUnless: - case IrOpcode::kEffectPhi: - case IrOpcode::kIfException: - case IrOpcode::kLoad: - case IrOpcode::kLoadImmutable: - case IrOpcode::kLoadElement: - case IrOpcode::kLoadField: - case IrOpcode::kLoadFromObject: - case IrOpcode::kLoadImmutableFromObject: - case IrOpcode::kMemoryBarrier: - case IrOpcode::kTrappingLoad: - case IrOpcode::kLoadTrapOnNull: - case IrOpcode::kTrappingStore: - case IrOpcode::kStoreTrapOnNull: - case IrOpcode::kRetain: - case IrOpcode::kStackPointerGreaterThan: -#if V8_ENABLE_WEBASSEMBLY - case IrOpcode::kLoadLane: - case IrOpcode::kLoadTransform: - case IrOpcode::kStoreLane: - case IrOpcode::kLoadStackPointer: - case IrOpcode::kSetStackPointer: -#endif // V8_ENABLE_WEBASSEMBLY - case IrOpcode::kStaticAssert: - // TODO(turbofan): Store nodes might do a bump-pointer allocation. - // We should introduce a special bump-pointer store node to - // differentiate that. - case IrOpcode::kStore: - case IrOpcode::kStoreElement: - case IrOpcode::kStoreField: - case IrOpcode::kStoreToObject: - case IrOpcode::kTraceInstruction: - case IrOpcode::kInitializeImmutableInObject: - case IrOpcode::kTrapIf: - case IrOpcode::kTrapUnless: - case IrOpcode::kUnalignedLoad: - case IrOpcode::kUnalignedStore: - case IrOpcode::kUnreachable: - case IrOpcode::kWord32AtomicAdd: - case IrOpcode::kWord32AtomicAnd: - case IrOpcode::kWord32AtomicCompareExchange: - case IrOpcode::kWord32AtomicExchange: - case IrOpcode::kWord32AtomicLoad: - case IrOpcode::kWord32AtomicOr: - case IrOpcode::kWord32AtomicPairAdd: - case IrOpcode::kWord32AtomicPairAnd: - case IrOpcode::kWord32AtomicPairCompareExchange: - case IrOpcode::kWord32AtomicPairExchange: - case IrOpcode::kWord32AtomicPairLoad: - case IrOpcode::kWord32AtomicPairOr: - case IrOpcode::kWord32AtomicPairStore: - case IrOpcode::kWord32AtomicPairSub: - case IrOpcode::kWord32AtomicPairXor: - case IrOpcode::kWord32AtomicStore: - case IrOpcode::kWord32AtomicSub: - case IrOpcode::kWord32AtomicXor: - case IrOpcode::kWord64AtomicAdd: - case IrOpcode::kWord64AtomicAnd: - case IrOpcode::kWord64AtomicCompareExchange: - case IrOpcode::kWord64AtomicExchange: - case IrOpcode::kWord64AtomicLoad: - case IrOpcode::kWord64AtomicOr: - case IrOpcode::kWord64AtomicStore: - case IrOpcode::kWord64AtomicSub: - case IrOpcode::kWord64AtomicXor: - return false; - - case IrOpcode::kCall: - return !(CallDescriptorOf(node->op())->flags() & - CallDescriptor::kNoAllocate); - default: - break; - } - return true; -} - -Node* SearchAllocatingNode(Node* start, Node* limit, Zone* temp_zone) { - ZoneQueue<Node*> queue(temp_zone); - ZoneSet<Node*> visited(temp_zone); - visited.insert(limit); - queue.push(start); - - while (!queue.empty()) { - Node* const current = queue.front(); - queue.pop(); - if (visited.find(current) == visited.end()) { - visited.insert(current); - - if (CanAllocate(current)) { - return current; - } - - for (int i = 0; i < current->op()->EffectInputCount(); ++i) { - queue.push(NodeProperties::GetEffectInput(current, i)); - } - } - } - return nullptr; -} - -bool CanLoopAllocate(Node* loop_effect_phi, Zone* temp_zone) { - Node* const control = NodeProperties::GetControlInput(loop_effect_phi); - // Start the effect chain walk from the loop back edges. - for (int i = 1; i < control->InputCount(); ++i) { - if (SearchAllocatingNode(loop_effect_phi->InputAt(i), loop_effect_phi, - temp_zone) != nullptr) { - return true; - } - } - return false; -} - -Node* EffectPhiForPhi(Node* phi) { - Node* control = NodeProperties::GetControlInput(phi); - for (Node* use : control->uses()) { - if (use->opcode() == IrOpcode::kEffectPhi) { - return use; - } - } - return nullptr; -} - -void WriteBarrierAssertFailed(Node* node, Node* object, const char* name, - Zone* temp_zone) { - std::stringstream str; - str << "MemoryOptimizer could not remove write barrier for node #" - << node->id() << "\n"; - str << " Run mksnapshot with --csa-trap-on-node=" << name << "," - << node->id() << " to break in CSA code.\n"; - Node* object_position = object; - if (object_position->opcode() == IrOpcode::kPhi) { - object_position = EffectPhiForPhi(object_position); - } - Node* allocating_node = nullptr; - if (object_position && object_position->op()->EffectOutputCount() > 0) { - allocating_node = SearchAllocatingNode(node, object_position, temp_zone); - } - if (allocating_node) { - str << "\n There is a potentially allocating node in between:\n"; - str << " " << *allocating_node << "\n"; - str << " Run mksnapshot with --csa-trap-on-node=" << name << "," - << allocating_node->id() << " to break there.\n"; - if (allocating_node->opcode() == IrOpcode::kCall) { - str << " If this is a never-allocating runtime call, you can add an " - "exception to Runtime::MayAllocate.\n"; - } - } else { - str << "\n It seems the store happened to something different than a " - "direct " - "allocation:\n"; - str << " " << *object << "\n"; - str << " Run mksnapshot with --csa-trap-on-node=" << name << "," - << object->id() << " to break there.\n"; - } - FATAL("%s", str.str().c_str()); -} - -} // namespace - -MemoryOptimizer::MemoryOptimizer( - JSHeapBroker* broker, JSGraph* jsgraph, Zone* zone, - MemoryLowering::AllocationFolding allocation_folding, - const char* function_debug_name, TickCounter* tick_counter, bool is_wasm) - : graph_assembler_(broker, jsgraph, zone, BranchSemantics::kMachine), - memory_lowering_(jsgraph, zone, &graph_assembler_, is_wasm, - allocation_folding, WriteBarrierAssertFailed, - function_debug_name), - wasm_address_reassociation_(jsgraph, zone), - jsgraph_(jsgraph), - empty_state_(AllocationState::Empty(zone)), - pending_(zone), - tokens_(zone), - zone_(zone), - tick_counter_(tick_counter) {} - -void MemoryOptimizer::Optimize() { - EnqueueUses(graph()->start(), empty_state(), graph()->start()->id()); - while (!tokens_.empty()) { - Token const token = tokens_.front(); - tokens_.pop(); - VisitNode(token.node, token.state, token.effect_chain); - } - if (v8_flags.turbo_wasm_address_reassociation) { - wasm_address_reassociation()->Optimize(); - } - DCHECK(pending_.empty()); - DCHECK(tokens_.empty()); -} - -void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state, - NodeId effect_chain) { - tick_counter_->TickAndMaybeEnterSafepoint(); - DCHECK(!node->IsDead()); - DCHECK_LT(0, node->op()->EffectInputCount()); - switch (node->opcode()) { - case IrOpcode::kAllocate: - // Allocate nodes were purged from the graph in effect-control - // linearization. - UNREACHABLE(); - case IrOpcode::kAllocateRaw: - return VisitAllocateRaw(node, state, effect_chain); - case IrOpcode::kCall: - return VisitCall(node, state, effect_chain); - case IrOpcode::kLoadFromObject: - case IrOpcode::kLoadImmutableFromObject: - return VisitLoadFromObject(node, state, effect_chain); - case IrOpcode::kLoadElement: - return VisitLoadElement(node, state, effect_chain); - case IrOpcode::kLoadField: - return VisitLoadField(node, state, effect_chain); - case IrOpcode::kTrappingLoad: - return VisitTrappingLoad(node, state, effect_chain); - case IrOpcode::kTrappingStore: - return VisitTrappingStore(node, state, effect_chain); - case IrOpcode::kStoreToObject: - case IrOpcode::kInitializeImmutableInObject: - return VisitStoreToObject(node, state, effect_chain); - case IrOpcode::kStoreElement: - return VisitStoreElement(node, state, effect_chain); - case IrOpcode::kStoreField: - return VisitStoreField(node, state, effect_chain); - case IrOpcode::kStore: - return VisitStore(node, state, effect_chain); - case IrOpcode::kStorePair: - // Store pairing should happen after this pass. - UNREACHABLE(); - default: - if (!CanAllocate(node)) { - // These operations cannot trigger GC. - return VisitOtherEffect(node, state, effect_chain); - } - } - DCHECK_EQ(0, node->op()->EffectOutputCount()); -} - -bool MemoryOptimizer::AllocationTypeNeedsUpdateToOld(Node* const node, - const Edge edge) { - // Test to see if we need to update the AllocationType. - if (node->opcode() == IrOpcode::kStoreField && edge.index() == 1) { - Node* parent = node->InputAt(0); - if (parent->opcode() == IrOpcode::kAllocateRaw && - AllocationTypeOf(parent->op()) == AllocationType::kOld) { - return true; - } - } - - return false; -} - -void MemoryOptimizer::ReplaceUsesAndKillNode(Node* node, Node* replacement) { - // Replace all uses of node and kill the node to make sure we don't leave - // dangling dead uses. - DCHECK_NE(replacement, node); - NodeProperties::ReplaceUses(node, replacement, graph_assembler_.effect(), - graph_assembler_.control()); - node->Kill(); -} - -void MemoryOptimizer::VisitAllocateRaw(Node* node, AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kAllocateRaw, node->opcode()); - const AllocateParameters& allocation = AllocateParametersOf(node->op()); - AllocationType allocation_type = allocation.allocation_type(); - - // Propagate tenuring from outer allocations to inner allocations, i.e. - // when we allocate an object in old space and store a newly allocated - // child object into the pretenured object, then the newly allocated - // child object also should get pretenured to old space. - if (allocation_type == AllocationType::kOld) { - for (Edge const edge : node->use_edges()) { - Node* const user = edge.from(); - if (user->opcode() == IrOpcode::kStoreField && edge.index() == 0) { - Node* child = user->InputAt(1); - if (child->opcode() == IrOpcode::kAllocateRaw && - AllocationTypeOf(child->op()) == AllocationType::kYoung) { - NodeProperties::ChangeOp(child, node->op()); - break; - } - } - } - } else { - DCHECK_EQ(AllocationType::kYoung, allocation_type); - for (Edge const edge : node->use_edges()) { - Node* const user = edge.from(); - if (AllocationTypeNeedsUpdateToOld(user, edge)) { - allocation_type = AllocationType::kOld; - break; - } - } - } - - Reduction reduction = - memory_lowering()->ReduceAllocateRaw(node, allocation_type, &state); - CHECK(reduction.Changed() && reduction.replacement() != node); - - ReplaceUsesAndKillNode(node, reduction.replacement()); - - EnqueueUses(state->effect(), state, effect_chain); -} - -void MemoryOptimizer::VisitLoadFromObject(Node* node, - AllocationState const* state, - NodeId effect_chain) { - DCHECK(node->opcode() == IrOpcode::kLoadFromObject || - node->opcode() == IrOpcode::kLoadImmutableFromObject); - Reduction reduction = memory_lowering()->ReduceLoadFromObject(node); - EnqueueUses(node, state, effect_chain); - if (V8_MAP_PACKING_BOOL && reduction.replacement() != node) { - ReplaceUsesAndKillNode(node, reduction.replacement()); - } -} - -void MemoryOptimizer::VisitStoreToObject(Node* node, - AllocationState const* state, - NodeId effect_chain) { - DCHECK(node->opcode() == IrOpcode::kStoreToObject || - node->opcode() == IrOpcode::kInitializeImmutableInObject); - memory_lowering()->ReduceStoreToObject(node, state); - EnqueueUses(node, state, effect_chain); -} - -void MemoryOptimizer::VisitLoadElement(Node* node, AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kLoadElement, node->opcode()); - memory_lowering()->ReduceLoadElement(node); - EnqueueUses(node, state, effect_chain); -} - -void MemoryOptimizer::VisitLoadField(Node* node, AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kLoadField, node->opcode()); - Reduction reduction = memory_lowering()->ReduceLoadField(node); - DCHECK(reduction.Changed()); - // In case of replacement, the replacement graph should not require futher - // lowering, so we can proceed iterating the graph from the node uses. - EnqueueUses(node, state, effect_chain); - - // Node can be replaced under two cases: - // 1. V8_ENABLE_SANDBOX is true and loading an external pointer value. - // 2. V8_MAP_PACKING_BOOL is enabled. - DCHECK_IMPLIES(!V8_ENABLE_SANDBOX_BOOL && !V8_MAP_PACKING_BOOL, - reduction.replacement() == node); - if ((V8_ENABLE_SANDBOX_BOOL || V8_MAP_PACKING_BOOL) && - reduction.replacement() != node) { - ReplaceUsesAndKillNode(node, reduction.replacement()); - } -} - -void MemoryOptimizer::VisitTrappingLoad(Node* node, - AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kTrappingLoad, node->opcode()); - if (v8_flags.turbo_wasm_address_reassociation) { - wasm_address_reassociation()->VisitTrappingMemOp(node, effect_chain); - EnqueueUses(node, state, effect_chain); - } else { - VisitOtherEffect(node, state, effect_chain); - } -} - -void MemoryOptimizer::VisitTrappingStore(Node* node, - AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kTrappingStore, node->opcode()); - if (v8_flags.turbo_wasm_address_reassociation) { - wasm_address_reassociation()->VisitTrappingMemOp(node, effect_chain); - EnqueueUses(node, state, effect_chain); - } else { - VisitOtherEffect(node, state, effect_chain); - } -} - -void MemoryOptimizer::VisitStoreElement(Node* node, - AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kStoreElement, node->opcode()); - memory_lowering()->ReduceStoreElement(node, state); - EnqueueUses(node, state, effect_chain); -} - -void MemoryOptimizer::VisitStoreField(Node* node, AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kStoreField, node->opcode()); - memory_lowering()->ReduceStoreField(node, state); - EnqueueUses(node, state, effect_chain); -} -void MemoryOptimizer::VisitStore(Node* node, AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kStore, node->opcode()); - memory_lowering()->ReduceStore(node, state); - EnqueueUses(node, state, effect_chain); -} - -void MemoryOptimizer::VisitCall(Node* node, AllocationState const* state, - NodeId effect_chain) { - DCHECK_EQ(IrOpcode::kCall, node->opcode()); - // If the call can allocate, we start with a fresh state. - if (!(CallDescriptorOf(node->op())->flags() & CallDescriptor::kNoAllocate)) { - state = empty_state(); - } - EnqueueUses(node, state, effect_chain); -} - -void MemoryOptimizer::VisitOtherEffect(Node* node, AllocationState const* state, - NodeId effect_chain) { - EnqueueUses(node, state, effect_chain); -} - -MemoryOptimizer::AllocationState const* MemoryOptimizer::MergeStates( - AllocationStates const& states) { - // Check if all states are the same; or at least if all allocation - // states belong to the same allocation group. - AllocationState const* state = states.front(); - MemoryLowering::AllocationGroup* group = state->group(); - for (size_t i = 1; i < states.size(); ++i) { - if (states[i] != state) state = nullptr; - if (states[i]->group() != group) group = nullptr; - } - if (state == nullptr) { - if (group != nullptr) { - // We cannot fold any more allocations into this group, but we can still - // eliminate write barriers on stores to this group. - // TODO(bmeurer): We could potentially just create a Phi here to merge - // the various tops; but we need to pay special attention not to create - // an unschedulable graph. - state = AllocationState::Closed(group, nullptr, zone()); - } else { - // The states are from different allocation groups. - state = empty_state(); - } - } - return state; -} - -void MemoryOptimizer::EnqueueMerge(Node* node, int index, - AllocationState const* state) { - DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode()); - NodeId effect_chain = node->id(); - int const input_count = node->InputCount() - 1; - DCHECK_LT(0, input_count); - Node* const control = node->InputAt(input_count); - if (control->opcode() == IrOpcode::kLoop) { - if (index == 0) { - if (CanLoopAllocate(node, zone())) { - // If the loop can allocate, we start with an empty state at the - // beginning. - EnqueueUses(node, empty_state(), effect_chain); - } else { - // If the loop cannot allocate, we can just propagate the state from - // before the loop. - EnqueueUses(node, state, effect_chain); - } - } else { - // Do not revisit backedges. - } - } else { - DCHECK_EQ(IrOpcode::kMerge, control->opcode()); - // Check if we already know about this pending merge. - NodeId const id = node->id(); - auto it = pending_.find(id); - if (it == pending_.end()) { - // Insert a new pending merge. - it = pending_.insert(std::make_pair(id, AllocationStates(zone()))).first; - } - // Add the next input state. - it->second.push_back(state); - // Check if states for all inputs are available by now. - if (it->second.size() == static_cast<size_t>(input_count)) { - // All inputs to this effect merge are done, merge the states given all - // input constraints, drop the pending merge and enqueue uses of the - // EffectPhi {node}. - state = MergeStates(it->second); - EnqueueUses(node, state, effect_chain); - pending_.erase(it); - } - } -} - -void MemoryOptimizer::EnqueueUses(Node* node, AllocationState const* state, - NodeId effect_chain) { - for (Edge const edge : node->use_edges()) { - if (NodeProperties::IsEffectEdge(edge)) { - EnqueueUse(edge.from(), edge.index(), state, effect_chain); - } - } -} - -void MemoryOptimizer::EnqueueUse(Node* node, int index, - AllocationState const* state, - NodeId effect_chain) { - if (node->opcode() == IrOpcode::kEffectPhi) { - // An EffectPhi represents a merge of different effect chains, which - // needs special handling depending on whether the merge is part of a - // loop or just a normal control join. - EnqueueMerge(node, index, state); - } else { - Token token = {node, state, effect_chain}; - tokens_.push(token); - } -} - -TFGraph* MemoryOptimizer::graph() const { return jsgraph()->graph(); } - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/compiler/memory-optimizer.h b/deps/v8/src/compiler/memory-optimizer.h deleted file mode 100644 index 897ea112c821..000000000000 --- a/deps/v8/src/compiler/memory-optimizer.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2016 the V8 project 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 V8_COMPILER_MEMORY_OPTIMIZER_H_ -#define V8_COMPILER_MEMORY_OPTIMIZER_H_ - -#include "src/compiler/graph-assembler.h" -#include "src/compiler/memory-lowering.h" -#include "src/zone/zone-containers.h" - -#ifdef V8_ENABLE_WEBASSEMBLY -#include "src/compiler/wasm-address-reassociation.h" -#else -namespace v8 { -namespace internal { -namespace compiler { - -class V8_EXPORT_PRIVATE WasmAddressReassociation final { - public: - WasmAddressReassociation(JSGraph* jsgraph, Zone* zone) {} - void Optimize() {} - void VisitTrappingMemOp(Node* node, uint32_t effect_chain) {} -}; - -} // namespace compiler -} // namespace internal -} // namespace v8 -#endif - -namespace v8 { -namespace internal { - -class TickCounter; - -namespace compiler { - -class JSGraph; -class TFGraph; - -// NodeIds are identifying numbers for nodes that can be used to index auxiliary -// out-of-line data associated with each node. -using NodeId = uint32_t; - -// Performs allocation folding and store write barrier elimination -// implicitly, while lowering all simplified memory access and allocation -// related nodes (i.e. Allocate, LoadField, StoreField and friends) to machine -// operators. -class MemoryOptimizer final { - public: - MemoryOptimizer(JSHeapBroker* broker, JSGraph* jsgraph, Zone* zone, - MemoryLowering::AllocationFolding allocation_folding, - const char* function_debug_name, TickCounter* tick_counter, - bool is_wasm); - ~MemoryOptimizer() = default; - - void Optimize(); - - private: - using AllocationState = MemoryLowering::AllocationState; - - // An array of allocation states used to collect states on merges. - using AllocationStates = ZoneVector<AllocationState const*>; - - // We thread through tokens to represent the current state on a given effect - // path through the graph. - struct Token { - Node* node; - AllocationState const* state; - // The most recent EffectPhi in the chain, which is used as a heuristic by - // address reassociation. - NodeId effect_chain; - }; - - void VisitNode(Node*, AllocationState const*, NodeId); - void VisitAllocateRaw(Node*, AllocationState const*, NodeId); - void VisitCall(Node*, AllocationState const*, NodeId); - void VisitLoadFromObject(Node*, AllocationState const*, NodeId); - void VisitLoadElement(Node*, AllocationState const*, NodeId); - void VisitLoadField(Node*, AllocationState const*, NodeId); - void VisitTrappingLoad(Node*, AllocationState const*, NodeId); - void VisitTrappingStore(Node*, AllocationState const*, NodeId); - void VisitStoreToObject(Node*, AllocationState const*, NodeId); - void VisitStoreElement(Node*, AllocationState const*, NodeId); - void VisitStoreField(Node*, AllocationState const*, NodeId); - void VisitStore(Node*, AllocationState const*, NodeId); - void VisitOtherEffect(Node*, AllocationState const*, NodeId); - - AllocationState const* MergeStates(AllocationStates const& states); - - void EnqueueMerge(Node*, int, AllocationState const*); - void EnqueueUses(Node*, AllocationState const*, NodeId); - void EnqueueUse(Node*, int, AllocationState const*, NodeId); - - void ReplaceUsesAndKillNode(Node* node, Node* replacement); - - // Returns true if the AllocationType of the current AllocateRaw node that we - // are visiting needs to be updated to kOld, due to propagation of tenuring - // from outer to inner allocations. - bool AllocationTypeNeedsUpdateToOld(Node* const user, const Edge edge); - - AllocationState const* empty_state() const { return empty_state_; } - MemoryLowering* memory_lowering() { return &memory_lowering_; } - WasmAddressReassociation* wasm_address_reassociation() { - return &wasm_address_reassociation_; - } - TFGraph* graph() const; - JSGraph* jsgraph() const { return jsgraph_; } - Zone* zone() const { return zone_; } - - JSGraphAssembler graph_assembler_; - MemoryLowering memory_lowering_; - WasmAddressReassociation wasm_address_reassociation_; - JSGraph* jsgraph_; - AllocationState const* const empty_state_; - ZoneMap<NodeId, AllocationStates> pending_; - ZoneQueue<Token> tokens_; - Zone* const zone_; - TickCounter* const tick_counter_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryOptimizer); -}; - -} // namespace compiler -} // namespace internal -} // namespace v8 - -#endif // V8_COMPILER_MEMORY_OPTIMIZER_H_ diff --git a/deps/v8/src/compiler/opcodes.h b/deps/v8/src/compiler/opcodes.h index d74406bfe7b0..30fd3e1693e2 100644 --- a/deps/v8/src/compiler/opcodes.h +++ b/deps/v8/src/compiler/opcodes.h @@ -814,7 +814,7 @@ V(LoadImmutable) \ V(Store) \ V(StorePair) \ - V(StoreIndirectPointer) \ + V(StoreTrustedPointer) \ V(StackSlot) \ V(Word32Popcnt) \ V(Word64Popcnt) \ diff --git a/deps/v8/src/compiler/operator.h b/deps/v8/src/compiler/operator.h index d1bce162c8a8..75ba893ecabe 100644 --- a/deps/v8/src/compiler/operator.h +++ b/deps/v8/src/compiler/operator.h @@ -37,7 +37,7 @@ class V8_EXPORT_PRIVATE Operator : public NON_EXPORTED_BASE(ZoneObject) { // Properties inform the operator-independent optimizer about legal // transformations for nodes that have this operator. - enum Property { + enum Property : uint8_t { kNoProperties = 0, kCommutative = 1 << 0, // OP(a, b) == OP(b, a) for all inputs. kAssociative = 1 << 1, // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs. diff --git a/deps/v8/src/compiler/pipeline.cc b/deps/v8/src/compiler/pipeline.cc index 27f9007b2dda..3fd3d83a5b9c 100644 --- a/deps/v8/src/compiler/pipeline.cc +++ b/deps/v8/src/compiler/pipeline.cc @@ -4,6 +4,7 @@ #include "src/compiler/pipeline.h" +#include <array> #include <fstream> #include <iostream> #include <memory> @@ -11,6 +12,7 @@ #include <sstream> #include "src/base/macros.h" +#include "src/base/unique-array.h" #include "src/builtins/builtins.h" #include "src/builtins/profile-data-reader.h" #include "src/codegen/bailout-reason.h" @@ -62,7 +64,6 @@ #include "src/compiler/loop-variable-optimizer.h" #include "src/compiler/machine-graph-verifier.h" #include "src/compiler/machine-operator-reducer.h" -#include "src/compiler/memory-optimizer.h" #include "src/compiler/node-observer.h" #include "src/compiler/node-origin-table.h" #include "src/compiler/osr.h" @@ -649,14 +650,9 @@ void PrintCode(Isolate* isolate, DirectHandle<Code> code, // part of a CheckMaps, this check will always fail afterwards and deoptimize. // This in turn relies on a runtime invariant that map migrations always target // newly allocated maps. -bool CheckNoDeprecatedMaps(DirectHandle<Code> code, Isolate* isolate) { - int mode_mask = RelocInfo::EmbeddedObjectModeMask(); - for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { - DCHECK(RelocInfo::IsEmbeddedObjectMode(it.rinfo()->rmode())); - Tagged<HeapObject> obj = it.rinfo()->target_object(); - if (Tagged<Map> map; TryCast<Map>(obj, &map) && map->is_deprecated()) { - return false; - } +bool CheckNoDeprecatedMaps(base::Vector<const IndirectHandle<Map>> maps) { + for (DirectHandle<Map> map : maps) { + if (map->is_deprecated()) return false; } return true; } @@ -827,15 +823,19 @@ PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl( if (context->IsDetached()) { return AbortOptimization(BailoutReason::kDetachedNativeContext); } - if (!CheckNoDeprecatedMaps(code, isolate)) { + CodeGenerator* code_generator = turboshaft_data_.code_generator(); + DCHECK_NOT_NULL(code_generator); + DCHECK(code_generator->has_background_code()); + base::Vector<const IndirectHandle<Map>> maps = + code_generator->retained_maps(); + if (!CheckNoDeprecatedMaps(maps)) { return RetryOptimization(BailoutReason::kConcurrentMapDeprecation); } if (!turboshaft_pipeline.CommitDependencies(code)) { return RetryOptimization(BailoutReason::kBailedOutDueToDependencyChange); } compilation_info()->SetCode(code); - GlobalHandleVector<Map> maps = CollectRetainedMaps(isolate, code); - RegisterWeakObjectsInOptimizedCode(isolate, context, code, std::move(maps)); + RegisterWeakObjectsInOptimizedCode(isolate, context, code, maps); return SUCCEEDED; } @@ -1318,36 +1318,6 @@ struct LoadEliminationPhase { } }; -struct MemoryOptimizationPhase { - DECL_PIPELINE_PHASE_CONSTANTS(MemoryOptimization) - - void Run(TFPipelineData* data, Zone* temp_zone) { - // The memory optimizer requires the graphs to be trimmed, so trim now. - GraphTrimmer trimmer(temp_zone, data->graph()); - NodeVector roots(temp_zone); - data->jsgraph()->GetCachedNodes(&roots); - { - UnparkedScopeIfNeeded scope(data->broker(), - v8_flags.trace_turbo_trimming); - trimmer.TrimGraph(roots.begin(), roots.end()); - } - - // Optimize allocations and load/store operations. -#if V8_ENABLE_WEBASSEMBLY - bool is_wasm = data->info()->IsWasm() || data->info()->IsWasmBuiltin(); -#else - bool is_wasm = false; -#endif - MemoryOptimizer optimizer( - data->broker(), data->jsgraph(), temp_zone, - data->info()->allocation_folding() - ? MemoryLowering::AllocationFolding::kDoAllocationFolding - : MemoryLowering::AllocationFolding::kDontAllocationFolding, - data->debug_name(), &data->info()->tick_counter(), is_wasm); - optimizer.Optimize(); - } -}; - #if V8_ENABLE_WEBASSEMBLY struct WasmTypingPhase { DECL_PIPELINE_PHASE_CONSTANTS(WasmTyping) @@ -1384,24 +1354,6 @@ struct WasmGCOptimizationPhase { } }; -struct WasmGCLoweringPhase { - DECL_PIPELINE_PHASE_CONSTANTS(WasmGCLowering) - - void Run(TFPipelineData* data, Zone* temp_zone, - const wasm::WasmModule* module) { - GraphReducer graph_reducer( - temp_zone, data->graph(), &data->info()->tick_counter(), data->broker(), - data->jsgraph()->Dead(), data->observe_node_manager()); - WasmGCLowering lowering(&graph_reducer, data->mcgraph(), module, false, - data->source_positions()); - DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), - data->common(), temp_zone); - AddReducer(data, &graph_reducer, &lowering); - AddReducer(data, &graph_reducer, &dead_code_elimination); - graph_reducer.ReduceGraph(); - } -}; - struct WasmOptimizationPhase { DECL_PIPELINE_PHASE_CONSTANTS(WasmOptimization) @@ -1562,8 +1514,7 @@ class WasmTurboshaftWrapperCompilationJob final CompilationJob::State::kReadyToExecute), zone_(wasm::GetWasmEngine()->allocator(), ZONE_NAME), debug_name_(std::move(debug_name)), - info_(base::CStrVector(debug_name_.get()), &zone_, - wrapper_info.code_kind), + info_(debug_name_.get(), &zone_, wrapper_info.code_kind), sig_(sig), wrapper_info_(wrapper_info), call_descriptor_( @@ -2081,7 +2032,7 @@ int ComputeInitialGraphHash(Builtin builtin, std::ofstream out(v8_flags.dump_builtins_hashes_to_file, std::ios_base::app); out << "Builtin: " << Builtins::name(builtin) << ", hash: 0x" << std::hex - << initial_graph_hash << std::endl; + << initial_graph_hash << std::dec << std::endl; } } return initial_graph_hash; @@ -2096,8 +2047,8 @@ const ProfileDataFromFile* ValidateProfileData( } if (v8_flags.abort_on_bad_builtin_profile_data || v8_flags.warn_about_builtin_profile_data) { - base::EmbeddedVector<char, 256> msg; - SNPrintF( + std::array<char, 256> msg; + base::SNPrintF( msg, "Rejected profile data for %s due to function change. " "Please use tools/builtins-pgo/generate.py to refresh it, you can " @@ -2115,9 +2066,9 @@ const ProfileDataFromFile* ValidateProfileData( // setting gn argument v8_builtins_profiling_log_file="". // One might also need to update the tools/builtins-pgo/generate.py if // the set of default release arguments has changed. - FATAL("%s", msg.begin()); + FATAL("%s", msg.data()); } else { - PrintF("%s\n", msg.begin()); + PrintF("%s\n", msg.data()); } } #ifdef LOG_BUILTIN_BLOCK_COUNT @@ -2165,7 +2116,7 @@ CodeAssemblerCompilationJob::CodeAssemblerCompilationJob( code_assembler_state_(isolate, &zone_, get_call_descriptor(&zone_), code_kind, name, builtin), assembler_options_(assembler_options), - compilation_info_(base::CStrVector(name), &zone_, code_kind), + compilation_info_(name, &zone_, code_kind), jump_opt_(ShouldOptimizeJumps(isolate) ? new JumpOptimizationInfo() : nullptr), finalize_order_(finalize_order) { @@ -2329,7 +2280,7 @@ TurboshaftAssemblerBuiltinCompilationJob:: name_(name), zone_stats_(isolate->allocator()), zone_(&zone_stats_, kBuiltinCompilationZoneName), - compilation_info_(base::CStrVector(name), zone_, code_kind), + compilation_info_(name, zone_, code_kind), data_(&zone_stats_, turboshaft::TurboshaftPipelineKind::kTSABuiltin, isolate, &compilation_info_, assembler_options), jump_opt_(ShouldOptimizeJumps(isolate) ? new JumpOptimizationInfo() @@ -2554,7 +2505,7 @@ Pipeline::NewJSLinkageCodeStubBuiltinCompilationJob( int finalize_order) { auto get_call_descriptor = [argc](Zone* zone) { return Linkage::GetJSCallDescriptor(zone, false, argc, - CallDescriptor::kCanUseRoots); + CallDescriptor::kNoFlags); }; return std::make_unique<CodeAssemblerTurboshaftCompilationJob>( isolate, builtin, generator, installer, assembler_options, @@ -2784,8 +2735,7 @@ Pipeline::GenerateCodeForWasmNativeStubFromTurboshaft( call_descriptor = GetI32WasmCallDescriptor(&zone, call_descriptor); } Linkage linkage(call_descriptor); - OptimizedCompilationInfo info(base::CStrVector(debug_name), &zone, - wrapper_info.code_kind); + OptimizedCompilationInfo info(debug_name, &zone, wrapper_info.code_kind); ZoneStats zone_stats(wasm_engine->allocator()); TFPipelineData data(&zone_stats, &info, nullptr, wasm::GetWasmEngine()->allocator(), nullptr, nullptr, @@ -2866,12 +2816,12 @@ Pipeline::GenerateCodeForWasmNativeStubFromTurboshaft( namespace { -base::OwnedVector<uint8_t> SerializeInliningPositions( +base::UniqueArray<uint8_t> SerializeInliningPositions( const ZoneVector<WasmInliningPosition>& positions) { const size_t entry_size = sizeof positions[0].inlinee_func_index + sizeof positions[0].was_tail_call + sizeof positions[0].caller_pos; - auto result = base::OwnedVector<uint8_t>::New(positions.size() * entry_size); + auto result = base::UniqueArray<uint8_t>::New(positions.size() * entry_size); uint8_t* iter = result.begin(); for (const auto& [func_index, was_tail_call, caller_pos] : positions) { size_t index_size = sizeof func_index; @@ -3001,7 +2951,8 @@ wasm::WasmCompilationResult Pipeline::GenerateWasmCode( &turboshaft_data, env, detected, turboshaft_data.graph(), compilation_data.func_body, compilation_data.wire_bytes_storage, compilation_data.validate_callees, &compilation_data.assumptions, - &inlining_positions, compilation_data.func_index, function_coverage_data); + &inlining_positions, compilation_data.func_index, function_coverage_data, + counter_updates); CodeTracer* code_tracer = nullptr; if (turboshaft_data.info()->trace_turbo_graph()) { // NOTE: We must not call `GetCodeTracer` if tracing is not enabled, diff --git a/deps/v8/src/compiler/raw-machine-assembler.h b/deps/v8/src/compiler/raw-machine-assembler.h index a8902144a706..3783df4d760c 100644 --- a/deps/v8/src/compiler/raw-machine-assembler.h +++ b/deps/v8/src/compiler/raw-machine-assembler.h @@ -208,7 +208,7 @@ class V8_EXPORT_PRIVATE RawMachineAssembler { void OptimizedStoreField(MachineRepresentation rep, Node* object, int offset, Node* value, WriteBarrierKind write_barrier) { DCHECK(!IsMapOffsetConstantMinusTag(offset)); - DCHECK_NE(rep, MachineRepresentation::kIndirectPointer); + DCHECK_NE(rep, MachineRepresentation::kTrustedPointer); AddNode(simplified()->StoreField( FieldAccess(BaseTaggedness::kTaggedBase, offset, MaybeHandle<Name>(), OptionalMapRef(), Type::Any(), @@ -216,16 +216,16 @@ class V8_EXPORT_PRIVATE RawMachineAssembler { write_barrier, "OptimizedStoreField")), object, value); } - void OptimizedStoreIndirectPointerField(Node* object, int offset, - IndirectPointerTag tag, Node* value, - WriteBarrierKind write_barrier) { + void OptimizedStoreTrustedPointerField(Node* object, int offset, + TrustedPointerTag tag, Node* value, + WriteBarrierKind write_barrier) { DCHECK(!IsMapOffsetConstantMinusTag(offset)); DCHECK(write_barrier == WriteBarrierKind::kNoWriteBarrier || - write_barrier == WriteBarrierKind::kIndirectPointerWriteBarrier); + write_barrier == WriteBarrierKind::kTrustedPointerWriteBarrier); FieldAccess access(BaseTaggedness::kTaggedBase, offset, MaybeHandle<Name>(), OptionalMapRef(), Type::Any(), - MachineType::IndirectPointer(), write_barrier, - "OptimizedStoreIndirectPointerField", + MachineType::TrustedPointer(), write_barrier, + "OptimizedStoreTrustedPointerField", ConstFieldInfo::None(), false, kExternalPointerNullTag, tag, false, false); AddNode(simplified()->StoreField(access), object, value); diff --git a/deps/v8/src/compiler/representation-change.cc b/deps/v8/src/compiler/representation-change.cc index b61c77d92a58..921f3565852f 100644 --- a/deps/v8/src/compiler/representation-change.cc +++ b/deps/v8/src/compiler/representation-change.cc @@ -297,7 +297,7 @@ Node* RepresentationChanger::GetRepresentationFor( case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kSandboxedPointer: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kMapWord: UNREACHABLE(); } diff --git a/deps/v8/src/compiler/simplified-lowering-verifier.cc b/deps/v8/src/compiler/simplified-lowering-verifier.cc index 6d41bbb8a324..416a68e08fc8 100644 --- a/deps/v8/src/compiler/simplified-lowering-verifier.cc +++ b/deps/v8/src/compiler/simplified-lowering-verifier.cc @@ -635,7 +635,7 @@ void SimplifiedLoweringVerifier::VisitNode(Node* node, CASE(LoadImmutable) CASE(Store) CASE(StorePair) - CASE(StoreIndirectPointer) + CASE(StoreTrustedPointer) CASE(StackSlot) CASE(Word32Popcnt) CASE(Word64Popcnt) diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc index d87dbb59d669..9ea2e639c1ca 100644 --- a/deps/v8/src/compiler/simplified-lowering.cc +++ b/deps/v8/src/compiler/simplified-lowering.cc @@ -158,7 +158,7 @@ UseInfo TruncatingUseInfoFromRepresentation( return UseInfo::TaggedSigned(); case MachineRepresentation::kTaggedPointer: case MachineRepresentation::kTagged: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kMapWord: return UseInfo::AnyTagged(); case MachineRepresentation::kFloat64: @@ -1645,8 +1645,8 @@ class RepresentationSelector { BaseTaggedness base_taggedness, MachineRepresentation field_representation, Type field_type, MachineRepresentation value_representation, Node* value) { - if (CanBeIndirectPointer(field_representation)) { - return kIndirectPointerWriteBarrier; + if (CanBeTrustedPointer(field_representation)) { + return kTrustedPointerWriteBarrier; } else if (base_taggedness == kTaggedBase && CanBeTaggedPointer(field_representation)) { Type value_type = NodeProperties::GetType(value); @@ -4020,10 +4020,7 @@ class RepresentationSelector { } case IrOpcode::kStringLength: case IrOpcode::kStringWrapperLength: { - // TODO(bmeurer): The input representation should be TaggedPointer. - // Fix this once we have a dedicated StringConcat/JSStringAdd - // operator, which marks it's output as TaggedPointer properly. - VisitUnop<T>(node, UseInfo::AnyTagged(), + VisitUnop<T>(node, UseInfo::TaggedPointer(), MachineRepresentation::kWord32); return; } diff --git a/deps/v8/src/compiler/simplified-operator.cc b/deps/v8/src/compiler/simplified-operator.cc index 80159d7cc658..8922e8775860 100644 --- a/deps/v8/src/compiler/simplified-operator.cc +++ b/deps/v8/src/compiler/simplified-operator.cc @@ -425,12 +425,13 @@ bool operator==(const ElementsTransitionWithMultipleSources& lhs, return lhs.sources() == rhs.sources(); } -size_t hash_value(ElementsTransition transition) { +V8_EXPORT_PRIVATE size_t hash_value(ElementsTransition transition) { return base::hash_combine(static_cast<uint8_t>(transition.mode()), transition.source(), transition.target()); } -size_t hash_value(ElementsTransitionWithMultipleSources transition) { +V8_EXPORT_PRIVATE size_t +hash_value(ElementsTransitionWithMultipleSources transition) { return base::hash_combine(transition.target(), transition.sources()); } diff --git a/deps/v8/src/compiler/simplified-operator.h b/deps/v8/src/compiler/simplified-operator.h index f97271fad954..1f2fcafbfd71 100644 --- a/deps/v8/src/compiler/simplified-operator.h +++ b/deps/v8/src/compiler/simplified-operator.h @@ -119,9 +119,9 @@ struct FieldAccess { ExternalPointerTag external_pointer_tag = kExternalPointerNullTag; // the external pointer tag if this is an // external pointer field - IndirectPointerTag indirect_pointer_tag = - kIndirectPointerNullTag; // the indirect pointer tag if this is an - // indirect pointer field + TrustedPointerTag trusted_pointer_tag = + kTrustedPointerNullTag; // the trusted pointer tag if this is an + // indirect pointer field bool maybe_initializing_or_transitioning_store; // store is potentially // initializing a newly // allocated object or part @@ -134,6 +134,8 @@ struct FieldAccess { // decoding. bool is_immutable = false; // Whether this field is known to be immutable for // the purpose of loads. + SharedFlag shared_base = SharedFlag{false}; // Whether the base is a shared + // tagged object. FieldAccess() : base_is_tagged(kTaggedBase), @@ -153,9 +155,10 @@ struct FieldAccess { ConstFieldInfo const_field_info = ConstFieldInfo::None(), bool is_store_in_literal = false, ExternalPointerTag external_pointer_tag = kExternalPointerNullTag, - IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag, + TrustedPointerTag trusted_pointer_tag = kTrustedPointerNullTag, bool maybe_initializing_or_transitioning_store = false, - bool is_immutable = false) + bool is_immutable = false, + SharedFlag shared_base = SharedFlag{false}) : base_is_tagged(base_is_tagged), offset(offset), name(name), @@ -166,10 +169,11 @@ struct FieldAccess { const_field_info(const_field_info), is_store_in_literal(is_store_in_literal), external_pointer_tag(external_pointer_tag), - indirect_pointer_tag(indirect_pointer_tag), + trusted_pointer_tag(trusted_pointer_tag), maybe_initializing_or_transitioning_store( maybe_initializing_or_transitioning_store), - is_immutable(is_immutable) { + is_immutable(is_immutable), + shared_base(shared_base) { DCHECK_GE(offset, 0); DCHECK_IMPLIES(machine_type.IsMapWord(), offset == offsetof(HeapObject, map_) && @@ -632,12 +636,13 @@ class ElementsTransitionWithMultipleSources final { FeedbackSource feedback_; }; -bool operator==(ElementsTransition const&, ElementsTransition const&); -bool operator==(ElementsTransitionWithMultipleSources const&, - ElementsTransitionWithMultipleSources const&); +V8_EXPORT_PRIVATE bool operator==(ElementsTransition const&, + ElementsTransition const&); +V8_EXPORT_PRIVATE bool operator==(ElementsTransitionWithMultipleSources const&, + ElementsTransitionWithMultipleSources const&); -size_t hash_value(ElementsTransition); -size_t hash_value(ElementsTransitionWithMultipleSources); +V8_EXPORT_PRIVATE size_t hash_value(ElementsTransition); +V8_EXPORT_PRIVATE size_t hash_value(ElementsTransitionWithMultipleSources); std::ostream& operator<<(std::ostream&, ElementsTransition); std::ostream& operator<<(std::ostream&, ElementsTransitionWithMultipleSources); diff --git a/deps/v8/src/compiler/turbofan-graph-visualizer.cc b/deps/v8/src/compiler/turbofan-graph-visualizer.cc index d8f750965b0a..e235ba126c99 100644 --- a/deps/v8/src/compiler/turbofan-graph-visualizer.cc +++ b/deps/v8/src/compiler/turbofan-graph-visualizer.cc @@ -4,6 +4,7 @@ #include "src/compiler/turbofan-graph-visualizer.h" +#include <array> #include <memory> #include <optional> #include <regex> @@ -304,7 +305,7 @@ std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info, const char* optional_base_dir, const char* phase, const char* suffix) { - base::EmbeddedVector<char, 256> filename(0); + std::array<char, 256> filename = {}; std::unique_ptr<char[]> debug_name = info->GetDebugName(); const char* file_prefix = v8_flags.trace_turbo_file_prefix.value(); int optimization_id = info->IsOptimizing() ? info->optimization_id() : 0; @@ -314,16 +315,16 @@ std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info, static int fast_call_wrappers_count = 0; optimization_id = ++fast_call_wrappers_count; } - SNPrintF(filename, "%s-%s-%i", file_prefix, debug_name.get(), - optimization_id); + base::SNPrintF(filename, "%s-%s-%i", file_prefix, debug_name.get(), + optimization_id); } else if (info->has_shared_info()) { - SNPrintF(filename, "%s-%p-%i", file_prefix, - reinterpret_cast<void*>(info->shared_info()->address()), - optimization_id); + base::SNPrintF(filename, "%s-%p-%i", file_prefix, + reinterpret_cast<void*>(info->shared_info()->address()), + optimization_id); } else { - SNPrintF(filename, "%s-none-%i", file_prefix, optimization_id); + base::SNPrintF(filename, "%s-none-%i", file_prefix, optimization_id); } - base::EmbeddedVector<char, 256> source_file(0); + std::array<char, 256> source_file = {}; bool source_available = false; if (v8_flags.trace_file_names && info->has_shared_info() && IsScript(info->shared_info()->script())) { @@ -332,7 +333,7 @@ std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info, if (IsString(source_name)) { Tagged<String> str = Cast<String>(source_name); if (str->length() > 0) { - SNPrintF(source_file, "%s", str->ToCString().get()); + base::SNPrintF(source_file, "%s", str->ToCString().get()); std::replace(source_file.begin(), source_file.begin() + source_file.size(), '/', '_'); source_available = true; @@ -347,31 +348,31 @@ std::unique_ptr<char[]> GetVisualizerLogFileName(OptimizedCompilationInfo* info, std::replace(filename.begin(), filename.begin() + filename.size(), '>', '}'); #endif // V8_OS_WIN - base::EmbeddedVector<char, 256> base_dir; + std::array<char, 256> base_dir; if (optional_base_dir != nullptr) { - SNPrintF(base_dir, "%s%c", optional_base_dir, - base::OS::DirectorySeparator()); + base::SNPrintF(base_dir, "%s%c", optional_base_dir, + base::OS::DirectorySeparator()); } else { base_dir[0] = '\0'; } - base::EmbeddedVector<char, 256> full_filename; + std::array<char, 256> full_filename; if (phase == nullptr && !source_available) { - SNPrintF(full_filename, "%s%s.%s", base_dir.begin(), filename.begin(), - suffix); + base::SNPrintF(full_filename, "%s%s.%s", base_dir.data(), filename.data(), + suffix); } else if (phase != nullptr && !source_available) { - SNPrintF(full_filename, "%s%s-%s.%s", base_dir.begin(), filename.begin(), - phase, suffix); + base::SNPrintF(full_filename, "%s%s-%s.%s", base_dir.data(), + filename.data(), phase, suffix); } else if (phase == nullptr && source_available) { - SNPrintF(full_filename, "%s%s_%s.%s", base_dir.begin(), filename.begin(), - source_file.begin(), suffix); + base::SNPrintF(full_filename, "%s%s_%s.%s", base_dir.data(), + filename.data(), source_file.data(), suffix); } else { - SNPrintF(full_filename, "%s%s_%s-%s.%s", base_dir.begin(), filename.begin(), - source_file.begin(), phase, suffix); + base::SNPrintF(full_filename, "%s%s_%s-%s.%s", base_dir.data(), + filename.data(), source_file.data(), phase, suffix); } char* buffer = new char[full_filename.size() + 1]; - memcpy(buffer, full_filename.begin(), full_filename.size()); + memcpy(buffer, full_filename.data(), full_filename.size()); buffer[full_filename.size()] = '\0'; return std::unique_ptr<char[]>(buffer); } diff --git a/deps/v8/src/compiler/turbofan-typer.cc b/deps/v8/src/compiler/turbofan-typer.cc index 04df61211293..e52c358e97e2 100644 --- a/deps/v8/src/compiler/turbofan-typer.cc +++ b/deps/v8/src/compiler/turbofan-typer.cc @@ -180,7 +180,7 @@ class Typer::Visitor : public Reducer { DECLARE_IMPOSSIBLE_CASE(LoadImmutable) DECLARE_IMPOSSIBLE_CASE(StorePair) DECLARE_IMPOSSIBLE_CASE(Store) - DECLARE_IMPOSSIBLE_CASE(StoreIndirectPointer) + DECLARE_IMPOSSIBLE_CASE(StoreTrustedPointer) DECLARE_IMPOSSIBLE_CASE(StackSlot) DECLARE_IMPOSSIBLE_CASE(Word32Popcnt) DECLARE_IMPOSSIBLE_CASE(Word64Popcnt) @@ -1529,8 +1529,7 @@ Type Typer::Visitor::TypeJSCreateGeneratorObject(Node* node) { } Type Typer::Visitor::TypeJSCreateClosure(Node* node) { - SharedFunctionInfoRef shared = - JSCreateClosureNode{node}.Parameters().shared_info(); + SharedFunctionInfoRef shared = JSCreateClosureNode{node}.shared_info(); if (IsClassConstructor(shared.kind())) { return Type::ClassConstructor(); } else { diff --git a/deps/v8/src/compiler/turbofan-types.cc b/deps/v8/src/compiler/turbofan-types.cc index 11de500c4641..4099929beb29 100644 --- a/deps/v8/src/compiler/turbofan-types.cc +++ b/deps/v8/src/compiler/turbofan-types.cc @@ -196,6 +196,8 @@ Type::bitset BitsetType::Lub(MapRefLike map, JSHeapBroker* broker) { UNREACHABLE(); case HEAP_NUMBER_TYPE: return kNumber; + case UNINITIALIZED_HEAP_NUMBER_TYPE: + return kOtherInternal; case CPP_HEAP_EXTERNAL_OBJECT_TYPE: case CPP_GCMANAGED_BASE_TYPE: case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE: @@ -298,8 +300,6 @@ Type::bitset BitsetType::Lub(MapRefLike map, JSHeapBroker* broker) { case JS_SHADOW_REALM_TYPE: case JS_SHARED_ARRAY_TYPE: case JS_SHARED_STRUCT_TYPE: - case JS_ATOMICS_CONDITION_TYPE: - case JS_ATOMICS_MUTEX_TYPE: #ifdef V8_TEMPORAL_SUPPORT case JS_TEMPORAL_DURATION_TYPE: case JS_TEMPORAL_INSTANT_TYPE: diff --git a/deps/v8/src/compiler/turboshaft/assembler.h b/deps/v8/src/compiler/turboshaft/assembler.h index 6ab086ea3768..59f83f65f02f 100644 --- a/deps/v8/src/compiler/turboshaft/assembler.h +++ b/deps/v8/src/compiler/turboshaft/assembler.h @@ -2953,14 +2953,15 @@ class AssemblerOpInterface : public Next { // Load a trusted (indirect) pointer. Returns Smi or ExposedTrustedObject. V<Object> LoadTrustedPointer(V<HeapObject> base, LoadOp::Kind kind, - IndirectPointerTagRange tag_range, int offset) { + TrustedPointerTagRange tag_range, int offset) { #if V8_ENABLE_SANDBOX static_assert(COMPRESS_POINTERS_BOOL); + V<WordPtr> table_address = + IsolateField(IsolateFieldId::kTrustedPointerTable); V<WordPtr> table = - Load(LoadRootRegister(), LoadOp::Kind::RawAligned().Immutable(), + Load(table_address, LoadOp::Kind::RawAligned().Immutable(), MemoryRepresentation::UintPtr(), - IsolateData::trusted_pointer_table_offset() + - Internals::kExternalEntityTableBasePointerOffset); + Internals::kExternalEntityTableBasePointerOffset); return LoadTrustedPointer(base, table, kind, tag_range, offset); #else return Load(base, kind, MemoryRepresentation::TaggedPointer(), offset); @@ -2970,7 +2971,7 @@ class AssemblerOpInterface : public Next { #if V8_ENABLE_SANDBOX V<Object> LoadTrustedPointer(V<HeapObject> base, V<WordPtr> table, LoadOp::Kind kind, - IndirectPointerTagRange tag_range, + TrustedPointerTagRange tag_range, int32_t offset) { return ReduceIfReachableLoadTrustedPointer(base, table, kind, tag_range, offset); @@ -3101,31 +3102,31 @@ class AssemblerOpInterface : public Next { std::optional<AtomicMemoryOrder> memory_order, int32_t offset = 0, uint8_t element_size_log2 = 0, bool maybe_initializing_or_transitioning = false, - IndirectPointerTag maybe_indirect_pointer_tag = kIndirectPointerNullTag) { + TrustedPointerTag maybe_trusted_pointer_tag = kTrustedPointerNullTag) { DCHECK_EQ(kind.is_atomic, memory_order.has_value()); ReduceIfReachableStore(base, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } void Store( OpIndex base, OptionalOpIndex index, OpIndex value, StoreOp::Kind kind, MemoryRepresentation stored_rep, WriteBarrierKind write_barrier, int32_t offset = 0, uint8_t element_size_log2 = 0, bool maybe_initializing_or_transitioning = false, - IndirectPointerTag maybe_indirect_pointer_tag = kIndirectPointerNullTag) { + TrustedPointerTag maybe_trusted_pointer_tag = kTrustedPointerNullTag) { Store(base, index, value, kind, stored_rep, write_barrier, std::nullopt, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } void Store( OpIndex base, OpIndex value, StoreOp::Kind kind, MemoryRepresentation stored_rep, WriteBarrierKind write_barrier, int32_t offset = 0, bool maybe_initializing_or_transitioning = false, - IndirectPointerTag maybe_indirect_pointer_tag = kIndirectPointerNullTag) { + TrustedPointerTag maybe_trusted_pointer_tag = kTrustedPointerNullTag) { Store(base, OpIndex::Invalid(), value, kind, stored_rep, write_barrier, offset, 0, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } void Store( OpIndex base, OpIndex value, StoreOp::Kind kind, @@ -3133,10 +3134,10 @@ class AssemblerOpInterface : public Next { std::optional<AtomicMemoryOrder> memory_order, int32_t offset = 0, uint8_t element_size_log2 = 0, bool maybe_initializing_or_transitioning = false, - IndirectPointerTag maybe_indirect_pointer_tag = kIndirectPointerNullTag) { + TrustedPointerTag maybe_trusted_pointer_tag = kTrustedPointerNullTag) { Store(base, OpIndex::Invalid(), value, kind, stored_rep, write_barrier, memory_order, offset, 0, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } template <typename T> @@ -3178,12 +3179,6 @@ class AssemblerOpInterface : public Next { return LoadFieldImpl<T>(object, field); } - template <typename Obj, typename Field> - V<typename Field::field_type> LoadField(V<Obj> object, const Field& field) { - LoadOp::Kind kind = LoadOp::Kind::Aligned(BaseTaggedness::kTaggedBase); - return Load(object, kind, field.rep, static_cast<int32_t>(field.offset)); - } - template <typename Rep> V<Rep> LoadFieldImpl(OpIndex object, const compiler::FieldAccess& access) { MachineType machine_type = access.machine_type; @@ -3208,6 +3203,7 @@ class AssemblerOpInterface : public Next { if (access.is_immutable) { kind = kind.Immutable(); } + if (access.shared_base) kind = kind.SharedBase(); V<Rep> value = Load(object, kind, rep, access.offset); #ifdef V8_ENABLE_SANDBOX if (is_sandboxed_external) { @@ -3226,8 +3222,16 @@ class AssemblerOpInterface : public Next { // Helpers to read the most common fields. // TODO(nicohartmann@): Strengthen this to `V<HeapObject>`. - V<Map> LoadMapField(V<Object> object) { - return LoadField<Map>(object, AccessBuilder::ForMap()); + V<Map> LoadMapField(V<Object> object, + SharedFlag shared_base = SharedFlag{false}) { + return LoadField<Map>(object, + AccessBuilder::ForMap(kMapWriteBarrier, shared_base)); + } + + V<Map> LoadImmutableMapField(V<HeapObject> object) { + FieldAccessTS<Object, Map> access = AccessBuilderTS::ForMap(); + access.is_immutable = true; + return LoadField<Map>(object, access); } V<Word32> LoadInstanceTypeField(V<Map> map) { @@ -3240,8 +3244,9 @@ class AssemblerOpInterface : public Next { return DecodeWord32<Map::Bits2::ElementsKindBits>(bit_field2); } - V<Word32> HasInstanceType(V<Object> object, InstanceType instance_type) { - return Word32Equal(LoadInstanceTypeField(LoadMapField(object)), + V<Word32> HasInstanceType(V<Object> object, InstanceType instance_type, + SharedFlag shared_base) { + return Word32Equal(LoadInstanceTypeField(LoadMapField(object, shared_base)), instance_type); } @@ -3474,17 +3479,8 @@ class AssemblerOpInterface : public Next { #endif #if V8_ENABLE_WEBASSEMBLY - // {trusted_instance_data} must be provided when at least one of - // {memory_start} or {memory_size} are provided. - // Returns V<None> when no input values are provided. - // Returns a V<WordPtr> when *either* {memory_start} or {memory_size} is - // provided; the return value is the potentially-updated value. - // Returns a V<Tuple<WordPtr, WordPtr>> when *both* {memory_start} and - // {memory_size} are provided. - V<None> WasmStackCheck( - WasmStackCheckOp::Kind kind, - OptionalV<WasmTrustedInstanceData> trusted_instance_data = {}) { - return ReduceIfReachableWasmStackCheck(trusted_instance_data, kind); + void WasmStackCheck(WasmStackCheckOp::Kind kind) { + ReduceIfReachableWasmStackCheck(kind); } void MemoryCopy(V<WordPtr> dst_base, V<WordPtr> src_base, @@ -3646,9 +3642,8 @@ class AssemblerOpInterface : public Next { return Parameter(index, V<T>::rep, debug_name); } V<Object> OsrValue(int index) { return ReduceIfReachableOsrValue(index); } - void Return(V<Word32> pop_count, base::Vector<const OpIndex> return_values, - bool spill_caller_frame_slots = false) { - ReduceIfReachableReturn(pop_count, return_values, spill_caller_frame_slots); + void Return(V<Word32> pop_count, base::Vector<const OpIndex> return_values) { + ReduceIfReachableReturn(pop_count, return_values); } void Return(OpIndex result) { Return(Word32Constant(0), base::VectorOf({result})); @@ -4162,7 +4157,8 @@ class AssemblerOpInterface : public Next { // where appropriate. OpIndex WasmCallRuntime(Zone* zone, Runtime::FunctionId f, std::initializer_list<const OpIndex> args, - V<Context> context) { + V<Context> context, + CanThrow can_throw = CanThrow{true}) { const Runtime::Function* fun = Runtime::FunctionForId(f); OpIndex isolate_root = __ LoadRootRegister(); DCHECK_EQ(1, fun->result_size); @@ -4183,8 +4179,8 @@ class AssemblerOpInterface : public Next { __ graph_zone(), f, fun->nargs, Operator::kNoProperties, CallDescriptor::kNoFlags); const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create( - call_descriptor, compiler::CanThrow{true}, - compiler::LazyDeoptOnThrow{false}, __ graph_zone()); + call_descriptor, can_throw, compiler::LazyDeoptOnThrow{false}, + __ graph_zone()); return __ Call(centry_stub, OpIndex::Invalid(), base::VectorOf(centry_args), ts_call_descriptor); } @@ -4360,19 +4356,19 @@ class AssemblerOpInterface : public Next { ReduceIfReachableCheckMaglevType(input, type); } +#ifdef DEBUG // This is currently only usable during graph building on the main thread. - void Dcheck(V<Word32> condition, const char* message, const char* file, + template <typename Condition> + void Dcheck(Condition condition, const char* message, const char* file, int line, SourceLocation loc = SourceLocation::CurrentIfDebug()) { Isolate* isolate = Asm().data()->isolate(); - USE(isolate); DCHECK_NOT_NULL(isolate); DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); -#ifdef DEBUG if (v8_flags.debug_code) { - Check(condition, message, file, line, loc); + Check(condition(), message, file, line, loc); } -#endif } +#endif // This is currently only usable during graph building on the main thread. void Check(V<Word32> condition, const char* message, const char* file, @@ -4418,8 +4414,8 @@ class AssemblerOpInterface : public Next { DCHECK_NOT_NULL(isolate); DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); const std::string str = stream.str(); - Handle<String> internalized_string = isolate->factory()->InternalizeString( - base::OneByteVector(str.c_str(), str.length())); + Handle<String> internalized_string = + isolate->factory()->InternalizeString(str); CanonicalizeEmbeddedBuiltinsConstantIfNeeded(internalized_string); V<String> string_constant = __ HeapConstantNoHole(internalized_string); @@ -4662,8 +4658,7 @@ class AssemblerOpInterface : public Next { if (broker) { UnparkedScopeIfNeeded scope(broker); LocalIsolate* isolate = broker->local_isolate_or_isolate(); - internalized_string = isolate->factory()->InternalizeString( - base::OneByteVector(label.c_str(), label.length())); + internalized_string = isolate->factory()->InternalizeString(label); internalized_string = broker->CanonicalPersistentHandle(internalized_string); } else { @@ -4671,8 +4666,7 @@ class AssemblerOpInterface : public Next { // If we don't have a broker, we can only allocate the string on the // main thread. DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); - internalized_string = isolate->factory()->InternalizeString( - base::OneByteVector(label.c_str(), label.length())); + internalized_string = isolate->factory()->InternalizeString(label); CanonicalizeEmbeddedBuiltinsConstantIfNeeded(internalized_string); } label_string = __ HeapConstantNoHole(internalized_string); @@ -4690,8 +4684,7 @@ class AssemblerOpInterface : public Next { if (broker) { UnparkedScopeIfNeeded scope(broker); LocalIsolate* isolate = broker->local_isolate_or_isolate(); - internalized_string = isolate->factory()->InternalizeString( - base::OneByteVector(str.c_str(), str.length())); + internalized_string = isolate->factory()->InternalizeString(str); internalized_string = broker->CanonicalPersistentHandle(internalized_string); } else { @@ -4699,8 +4692,7 @@ class AssemblerOpInterface : public Next { // If we don't have a broker, we can only allocate the string on the main // thread. DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); - internalized_string = isolate->factory()->InternalizeString( - base::OneByteVector(str.c_str(), str.length())); + internalized_string = isolate->factory()->InternalizeString(str); CanonicalizeEmbeddedBuiltinsConstantIfNeeded(internalized_string); } V<String> string_constant = __ HeapConstantNoHole(internalized_string); @@ -5178,6 +5170,11 @@ class AssemblerOpInterface : public Next { return ReduceIfReachableRootConstant(index); } + template <RootIndex index> + V<root_type_t<index>> RootConstant() { + return V<root_type_t<index>>::Cast(RootConstant(index)); + } + V<Word32> IsRootConstant(V<Object> input, RootIndex index) { return ReduceIfReachableIsRootConstant(input, index); } @@ -5307,36 +5304,40 @@ class AssemblerOpInterface : public Next { V<Any> ArrayAtomicRMW(V<WasmArrayNullable> array, V<Word32> index, V<Any> value, OptionalV<Any> expected, ArrayAtomicRMWOp::BinOp bin_op, - wasm::ValueType element_type, + wasm::ValueType element_type, SharedFlag is_shared, AtomicMemoryOrder memory_order) { return ReduceIfReachableArrayAtomicRMW(array, index, value, expected, - bin_op, element_type, memory_order); + bin_op, element_type, is_shared, + memory_order); } V<Any> ArrayGet(V<WasmArrayNullable> array, V<Word32> index, const wasm::ArrayType* array_type, bool is_signed, - std::optional<AtomicMemoryOrder> memory_order) { + std::optional<AtomicMemoryOrder> memory_order, + SharedFlag shared_base) { return ReduceIfReachableArrayGet(array, index, array_type, is_signed, - memory_order); + memory_order, shared_base); } void ArraySet(V<WasmArrayNullable> array, V<Word32> index, V<Any> value, - wasm::ValueType element_type, + wasm::ValueType element_type, SharedFlag is_shared, std::optional<AtomicMemoryOrder> memory_order, WriteBarrierKind write_barrier, ArraySetOp::Kind kind) { - ReduceIfReachableArraySet(array, index, value, element_type, memory_order, - write_barrier, kind); + ReduceIfReachableArraySet(array, index, value, element_type, is_shared, + memory_order, write_barrier, kind); } - V<Word32> ArrayLength(V<WasmArrayNullable> array, CheckForNull null_check) { + V<Word32> ArrayLength(V<WasmArrayNullable> array, CheckForNull null_check, + SharedFlag shared_base) { return ReduceIfReachableArrayLength(array, OptionalV<EagerFrameState>{}, - null_check); + null_check, shared_base); } V<Word32> ArrayLength(V<WasmArrayNullable> array, OptionalV<EagerFrameState> frame_state, - CheckForNull null_check) { - return ReduceIfReachableArrayLength(array, frame_state, null_check); + CheckForNull null_check, SharedFlag shared_base) { + return ReduceIfReachableArrayLength(array, frame_state, null_check, + shared_base); } // Shared between the Wasm pipeline and the Wasm-in-JS body inlining. @@ -5349,10 +5350,11 @@ class AssemblerOpInterface : public Next { TrapId::kTrapNullDereference); } } else { - V<Word32> length = __ ArrayLength(array, frame_state, - array_type.is_nullable() - ? compiler::kWithNullCheck - : compiler::kWithoutNullCheck); + V<Word32> length = + __ ArrayLength(array, frame_state, + array_type.is_nullable() ? compiler::kWithNullCheck + : compiler::kWithoutNullCheck, + array_type.is_shared()); __ TrapIfNot(__ Uint32LessThan(index, length), frame_state, TrapId::kTrapArrayOutOfBounds); } @@ -5388,10 +5390,8 @@ class AssemblerOpInterface : public Next { } V<WasmArray> WasmAllocateArray(V<Map> rtt, ConstOrV<Word32> length, - const wasm::ArrayType* array_type, - SharedFlag is_shared) { - return ReduceIfReachableWasmAllocateArray(rtt, resolve(length), array_type, - is_shared); + const wasm::ArrayType* array_type) { + return ReduceIfReachableWasmAllocateArray(rtt, resolve(length), array_type); } V<WasmStruct> WasmAllocateStruct(V<Map> rtt, diff --git a/deps/v8/src/compiler/turboshaft/branch-elimination-reducer.h b/deps/v8/src/compiler/turboshaft/branch-elimination-reducer.h index 70ae78a8401f..e47c6cef5d37 100644 --- a/deps/v8/src/compiler/turboshaft/branch-elimination-reducer.h +++ b/deps/v8/src/compiler/turboshaft/branch-elimination-reducer.h @@ -376,12 +376,16 @@ class BranchEliminationReducer : public Next { goto no_change; } - // Do not clone blocks containing deoptimization points. These may have a - // significant metadata overhead. - for (const Operation& op : - __ input_graph().operations(*destination_origin)) { - if (op.Is<DeoptimizeIfOp>()) { - goto no_change; + if (__ data()->is_wasm()) { + // Wasm cannot handle it if too many deoptimization exits are created + // (kTooManyDeoptimizationBailouts in the CodeGenerator). In Wasm, + // DeoptimizeIfOps are rare and cloning them is probably not worth the + // metadata overhead. + for (const Operation& op : + __ input_graph().operations(*destination_origin)) { + if (op.Is<DeoptimizeIfOp>()) { + goto no_change; + } } } diff --git a/deps/v8/src/compiler/turboshaft/builtin-call-descriptors.h b/deps/v8/src/compiler/turboshaft/builtin-call-descriptors.h index 9a72d2862a68..cc0d5d69536f 100644 --- a/deps/v8/src/compiler/turboshaft/builtin-call-descriptors.h +++ b/deps/v8/src/compiler/turboshaft/builtin-call-descriptors.h @@ -1109,7 +1109,7 @@ struct BuiltinCallDescriptor { : public Descriptor<WasmAllocateDescriptorStruct> { static constexpr auto kFunction = Builtin::kWasmAllocateDescriptorStruct; using arguments_t = std::tuple<V<Map>, V<Word32>, V<Object>>; - using results_t = std::tuple<V<WasmStruct>>; + using results_t = std::tuple<V<WasmDescriptor>>; static constexpr bool kNeedsFrameState = false; static constexpr bool kNeedsContext = false; diff --git a/deps/v8/src/compiler/turboshaft/builtin-compiler.cc b/deps/v8/src/compiler/turboshaft/builtin-compiler.cc index f5aed12200d0..7ea26a81abc9 100644 --- a/deps/v8/src/compiler/turboshaft/builtin-compiler.cc +++ b/deps/v8/src/compiler/turboshaft/builtin-compiler.cc @@ -30,8 +30,7 @@ DirectHandle<Code> BuildWithTurboshaftAssemblerImpl( compiler::ZoneStats zone_stats(isolate->allocator()); ZoneWithName<kBuiltinCompilationZoneName> zone(&zone_stats, kBuiltinCompilationZoneName); - OptimizedCompilationInfo info(base::CStrVector(name), zone, code_kind, - builtin); + OptimizedCompilationInfo info(name, zone, code_kind, builtin); compiler::CallDescriptor* call_descriptor = call_descriptor_builder(zone); PipelineData data(&zone_stats, TurboshaftPipelineKind::kTSABuiltin, isolate, diff --git a/deps/v8/src/compiler/turboshaft/define-assembler-macros.inc b/deps/v8/src/compiler/turboshaft/define-assembler-macros.inc index e97226ae2b2e..aa523646888e 100644 --- a/deps/v8/src/compiler/turboshaft/define-assembler-macros.inc +++ b/deps/v8/src/compiler/turboshaft/define-assembler-macros.inc @@ -33,8 +33,13 @@ #define RE_UNUSED #endif -#define TSA_DCHECK(assembler, condition) \ - (assembler)->Asm().Dcheck(condition, #condition, __FILE__, __LINE__ ) +#ifdef DEBUG +#define TSA_DCHECK(assembler, ...) \ + (assembler)->Asm().Dcheck([&]() { return __VA_ARGS__; }, #__VA_ARGS__, \ + __FILE__, __LINE__) +#else +#define TSA_DCHECK(assembler, ...) ((void)0) +#endif #ifdef ENABLE_SLOW_DCHECKS #define TSA_SLOW_DCHECK(assembler, ...) \ do { \ diff --git a/deps/v8/src/compiler/turboshaft/duplication-optimization-reducer.h b/deps/v8/src/compiler/turboshaft/duplication-optimization-reducer.h index c8b0db665c09..8f7e6ec1fd29 100644 --- a/deps/v8/src/compiler/turboshaft/duplication-optimization-reducer.h +++ b/deps/v8/src/compiler/turboshaft/duplication-optimization-reducer.h @@ -62,6 +62,20 @@ namespace v8::internal::compiler::turboshaft { // conditions that are used more than once, so that they can be generated right // before each branch without worrying about breaking SSA. // +// Similarly, a comparison that is only used by a branch, but that was emitted +// in a previous block, is materialized in a register, since the +// InstructionSelector only combines a comparison with a branch in the same +// block. This typically happens after the BranchEliminationReducer has cloned a +// merge block ending with a branch on a Phi into each of its predecessors +// (CloneBlockAndGoto): the comparison stays in the predecessor, and the branch +// ends up alone in the cloned block. For instance, `if (a == b && c < d)` is +// built as a branch on a Phi of `c < d` and `0`. When the branch is the first +// use of the comparison, the comparison is re-emitted right before the branch +// (unless this would move it into a loop header, or extend the live ranges of +// its inputs too much); if the original comparison has no other uses, it is +// then not emitted (since both CopyingPhase and InstructionSelector skip unused +// operations). +// // 2. Load/Store flexible second operand duplication: on Arm64, it tries to // duplicate the "index" input of Loads/Stores when it's a shift by a constant. // This allows the Instruction Selector to compute said shift using a flexible @@ -130,20 +144,24 @@ class DuplicationOptimizationReducer : public Next { std::optional<AtomicMemoryOrder> memory_order, int32_t offset, uint8_t element_size_log2, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag) { + TrustedPointerTag maybe_trusted_pointer_tag) { if (offset == 0 && element_size_log2 == 0 && index.valid()) { index = MaybeDuplicateOutputGraphShift(index.value()); } return Next::ReduceStore( base, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } #endif private: bool MaybeDuplicateCond(const Operation& cond, OpIndex input_idx, V<Word32>* new_cond) { + if (const ComparisonOp* comp = cond.TryCast<ComparisonOp>()) { + *new_cond = MaybeSinkComparison(*comp, input_idx); + if (new_cond->valid()) return true; + } if (cond.saturated_use_count.Is(1)) return false; switch (cond.opcode) { @@ -164,6 +182,43 @@ class DuplicationOptimizationReducer : public Next { return new_cond->valid(); } + V<Word32> MaybeSinkComparison(const ComparisonOp& comp, OpIndex input_idx) { + // Only for the first use of the comparison in the output graph (further + // uses are handled by MaybeDuplicateComparison). We cannot require the + // comparison to have a single use in the input graph, since its other + // uses are often dead (for instance, a Phi that is not emitted). + OpIndex output_idx = __ MapToNewGraph(input_idx); + const Operation& output_op = __ Get(output_idx); + if (!output_op.Is<ComparisonOp>() || !output_op.saturated_use_count.Is(0)) { + return {}; + } + // Not if the comparison is in the current block: the InstructionSelector + // can then combine it with the branch. + const Block* current_block = __ current_block(); + if (output_idx.id() >= current_block->begin().id()) return {}; + // Not into a loop header, where the comparison would be recomputed at each + // iteration. (At this point, a loop header only has its forward + // predecessor: its back edge is added later.) + if (current_block->IsLoop()) return {}; + // If the comparison is in the single predecessor of the current block, the + // live ranges of its inputs are barely extended. Otherwise, as for + // duplication (see MaybeCanDuplicateGenericBinop), not if both inputs are + // only used by the comparison: this would keep 2 values alive instead of + // 1, possibly across a loop. + const Block* predecessor = current_block->LastPredecessor(); + bool in_predecessor = predecessor != nullptr && + predecessor->NeighboringPredecessor() == nullptr && + predecessor->Contains(output_idx); + if (!in_predecessor && + __ input_graph().Get(comp.left()).saturated_use_count.Is(1) && + __ input_graph().Get(comp.right()).saturated_use_count.Is(1)) { + return {}; + } + DisableValueNumbering disable_gvn(this); + return __ Comparison(__ MapToNewGraph(comp.left()), + __ MapToNewGraph(comp.right()), comp.kind, comp.rep); + } + bool MaybeCanDuplicateGenericBinop(OpIndex input_idx, OpIndex left, OpIndex right) { if (__ input_graph().Get(left).saturated_use_count.Is(1) && diff --git a/deps/v8/src/compiler/turboshaft/fast-api-call-lowering-reducer.h b/deps/v8/src/compiler/turboshaft/fast-api-call-lowering-reducer.h index c34b194d2e0b..da078c481d09 100644 --- a/deps/v8/src/compiler/turboshaft/fast-api-call-lowering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/fast-api-call-lowering-reducer.h @@ -114,7 +114,8 @@ class FastApiCallLoweringReducer : public Next { V<Object> exception = __ Load(__ IsolateField(IsolateFieldId::kException), - LoadOp::Kind::RawAligned(), MemoryRepresentation::UintPtr()); + LoadOp::Kind::RawAligned(), + MemoryRepresentation::AnyUncompressedTagged()); GOTO_IF_NOT( LIKELY(__ TaggedEqual( exception, __ template LoadRoot<RootIndex::kTheHoleValue>())), diff --git a/deps/v8/src/compiler/turboshaft/fast-hash.h b/deps/v8/src/compiler/turboshaft/fast-hash.h index 7a8dda1df874..ff14f0874b19 100644 --- a/deps/v8/src/compiler/turboshaft/fast-hash.h +++ b/deps/v8/src/compiler/turboshaft/fast-hash.h @@ -7,6 +7,7 @@ #include <array> #include <optional> +#include <span> #include <tuple> #include "src/base/hashing.h" @@ -87,6 +88,13 @@ struct fast_hash<base::Vector<T>> { } }; +template <typename T, size_t N> +struct fast_hash<std::span<T, N>> { + V8_INLINE size_t operator()(std::span<T, N> v) const { + return fast_hash_range(v.begin(), v.end()); + } +}; + template <typename T> struct fast_hash<IndirectHandle<T>> { V8_INLINE size_t operator()(IndirectHandle<T> v) const { diff --git a/deps/v8/src/compiler/turboshaft/graph-builder.cc b/deps/v8/src/compiler/turboshaft/graph-builder.cc index 5866bba154e0..6c28884a15ad 100644 --- a/deps/v8/src/compiler/turboshaft/graph-builder.cc +++ b/deps/v8/src/compiler/turboshaft/graph-builder.cc @@ -1402,7 +1402,6 @@ OpIndex GraphBuilder::Process( MemoryRepresentation::FromMachineType(LoadRepresentationOf(op)); Node* base = node->InputAt(0); Node* index = node->InputAt(1); - // It's ok to merge LoadImmutable into Load after scheduling. LoadOp::Kind kind = opcode == IrOpcode::kUnalignedLoad ? LoadOp::Kind::RawUnaligned() : LoadOp::Kind::RawAligned(); @@ -1410,6 +1409,9 @@ OpIndex GraphBuilder::Process( RegisterRepresentation::Tagged()) { kind = LoadOp::Kind::TaggedBase(); } + if (opcode == IrOpcode::kLoadImmutable) { + kind = kind.Immutable(); + } if (index->opcode() == IrOpcode::kInt32Constant) { int32_t offset = OpParameter<int32_t>(index->op()); if (kind.tagged_base) offset += kHeapObjectTag; @@ -1777,7 +1779,7 @@ OpIndex GraphBuilder::Process( __ Store(object, final_value, kind, final_rep, final_write_barrier, access.offset, initializing_transitioning, - access.indirect_pointer_tag); + access.trusted_pointer_tag); return OpIndex::Invalid(); } case IrOpcode::kLoadFromObject: diff --git a/deps/v8/src/compiler/turboshaft/graph.h b/deps/v8/src/compiler/turboshaft/graph.h index 6202826488e0..5b4eb60b2f80 100644 --- a/deps/v8/src/compiler/turboshaft/graph.h +++ b/deps/v8/src/compiler/turboshaft/graph.h @@ -1178,22 +1178,26 @@ class Graph { template <class Op> void IncrementInputUses(const Op& op) { + static_assert(!std::is_same_v<Op, Operation>); + // MakeTupleOp is a synthetic meta-operation used only to bundle + // multi-output projections during graph building; it does not represent a + // real dataflow use. + if (std::is_same_v<Op, MakeTupleOp>) return; + for (OpIndex input : op.inputs()) { - // Tuples should never be used as input, except in other tuples (which is - // used for instance in Int64Lowering::LowerCall). - DCHECK_IMPLIES(Get(input).Is<MakeTupleOp>(), - op.template Is<MakeTupleOp>()); + // Tuples should never be used as input (except inside other tuples, which + // returned early above). + DCHECK(!Get(input).Is<MakeTupleOp>()); Get(input).saturated_use_count.Incr(); } } - template <class Op> - void DecrementInputUses(const Op& op) { + void DecrementInputUses(const Operation& op) { + // Avoid underflow since synthetic MakeTupleOp inputs are not use-counted. + if (V8_UNLIKELY(op.Is<MakeTupleOp>())) return; + for (OpIndex input : op.inputs()) { - // Tuples should never be used as input, except in other tuples (which is - // used for instance in Int64Lowering::LowerCall). - DCHECK_IMPLIES(Get(input).Is<MakeTupleOp>(), - op.template Is<MakeTupleOp>()); + DCHECK(!Get(input).Is<MakeTupleOp>()); Get(input).saturated_use_count.Decr(); } } diff --git a/deps/v8/src/compiler/turboshaft/growable-stacks-reducer.h b/deps/v8/src/compiler/turboshaft/growable-stacks-reducer.h index cd0841d152ac..210a2a3c9fa5 100644 --- a/deps/v8/src/compiler/turboshaft/growable-stacks-reducer.h +++ b/deps/v8/src/compiler/turboshaft/growable-stacks-reducer.h @@ -13,6 +13,7 @@ #include "src/compiler/turboshaft/phase.h" #include "src/compiler/turboshaft/representations.h" #include "src/compiler/turboshaft/uniform-reducer-adapter.h" +#include "src/execution/isolate-data.h" namespace v8::internal::compiler::turboshaft { @@ -37,18 +38,16 @@ class GrowableStacksReducer : public Next { #endif } - V<None> REDUCE(WasmStackCheck)( - OptionalV<WasmTrustedInstanceData> trusted_instance_data, - WasmStackCheckOp::Kind kind) { + V<None> REDUCE(WasmStackCheck)(WasmStackCheckOp::Kind kind) { CHECK_EQ(kind, WasmStackCheckOp::Kind::kFunctionEntry); if (skip_reducer_) { - return Next::ReduceWasmStackCheck(trusted_instance_data, kind); + return Next::ReduceWasmStackCheck(kind); } // Loads of the stack limit should not be load-eliminated as it can be // modified by another thread. - V<WordPtr> limit = __ Load( - __ LoadRootRegister(), LoadOp::Kind::RawAligned().NotLoadEliminable(), - MemoryRepresentation::UintPtr(), IsolateData::jslimit_offset()); + V<WordPtr> limit = __ Load(__ IsolateField(IsolateFieldId::kJsLimit), + LoadOp::Kind::RawAligned().NotLoadEliminable(), + MemoryRepresentation::UintPtr()); IF_NOT (LIKELY(__ StackPointerGreaterThan(limit, StackCheckKind::kWasm))) { const int stack_parameter_count = 0; @@ -63,76 +62,22 @@ class GrowableStacksReducer : public Next { LazyDeoptOnThrow{false}, __ graph_zone()); V<WordPtr> builtin = __ RelocatableWasmBuiltinCallTarget(Builtin::kWasmGrowableStackGuard); - auto param_slots_size = __ IntPtrConstant( - call_descriptor_->ParameterSlotCount() * kSystemPointerSize); + auto stack_param_and_return_slots_size = + __ IntPtrConstant((call_descriptor_->ParameterSlotCount() + + call_descriptor_->ReturnSlotCount()) * + kSystemPointerSize); V<WordPtr> gap = __ ChangeInt32ToIntPtr(__ UntagSmi(__ StackCheckOffset())); - __ Call(builtin, {param_slots_size, gap}, ts_stub_call_descriptor); + auto parameter_slots_size = __ IntPtrConstant( + call_descriptor_->ParameterSlotCount() * kSystemPointerSize); + __ Call(builtin, + {stack_param_and_return_slots_size, gap, parameter_slots_size}, + ts_stub_call_descriptor); } return V<None>::Invalid(); } - OpIndex REDUCE(Return)(V<Word32> pop_count, - base::Vector<const OpIndex> return_values, - bool spill_caller_frame_slots) { - if (skip_reducer_ || !spill_caller_frame_slots || - call_descriptor_->ReturnSlotCount() == 0) { - return Next::ReduceReturn(pop_count, return_values, - spill_caller_frame_slots); - } - V<Word32> frame_marker = __ Load( - __ FramePointer(), LoadOp::Kind::RawAligned(), - MemoryRepresentation::Uint32(), WasmFrameConstants::kFrameTypeOffset); - - Label<WordPtr> done(this); - IF (UNLIKELY(__ Word32Equal( - frame_marker, - StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)))) { - auto sig = - FixedSizeSignature<MachineType>::Returns(MachineType::Pointer()) - .Params(MachineType::Pointer()); - const CallDescriptor* ccall_descriptor = - compiler::Linkage::GetSimplifiedCDescriptor(__ graph_zone(), &sig); - const TSCallDescriptor* ts_ccall_descriptor = TSCallDescriptor::Create( - ccall_descriptor, compiler::CanThrow{false}, - compiler::LazyDeoptOnThrow{false}, __ graph_zone()); - GOTO(done, __ template Call<WordPtr>( - __ ExternalConstant(ExternalReference::wasm_load_old_fp()), - OpIndex::Invalid(), - base::VectorOf({__ ExternalConstant( - ExternalReference::isolate_address())}), - ts_ccall_descriptor)); - } ELSE { - GOTO(done, __ FramePointer()); - } - BIND(done, old_fp); - - base::SmallVector<OpIndex, 8> register_return_values; - for (size_t i = 0; i < call_descriptor_->ReturnCount(); i++) { - LinkageLocation loc = call_descriptor_->GetReturnLocation(i); - if (!loc.IsCallerFrameSlot()) { - register_return_values.push_back(return_values[i]); - continue; - } - MemoryRepresentation mem_rep = - MemoryRepresentation::FromMachineType(loc.GetType()); - OpIndex ret_value = return_values[i]; - // Pointers are stored uncompressed on the stacks. - // Also, we don't need to mark the stack slot as a reference, because - // we are about to return from this frame, so it is the caller's - // responsibility to track the tagged return values using the signature. - if (mem_rep == MemoryRepresentation::AnyTagged()) { - mem_rep = MemoryRepresentation::UintPtr(); - ret_value = __ BitcastTaggedToWordPtr(ret_value); - } - __ StoreOffHeap(old_fp, ret_value, mem_rep, - FrameSlotToFPOffset(loc.GetLocation())); - } - return Next::ReduceReturn(pop_count, base::VectorOf(register_return_values), - spill_caller_frame_slots); - } - private: bool skip_reducer_ = false; CallDescriptor* call_descriptor_ = nullptr; diff --git a/deps/v8/src/compiler/turboshaft/index.h b/deps/v8/src/compiler/turboshaft/index.h index c392f17d2120..f98346c159c5 100644 --- a/deps/v8/src/compiler/turboshaft/index.h +++ b/deps/v8/src/compiler/turboshaft/index.h @@ -625,7 +625,12 @@ concept IsTagged = !std::is_same_v<T, Any> && #if V8_ENABLE_WEBASSEMBLY using WasmArrayNullable = Union<WasmArray, WasmNull>; -using WasmStructNullable = Union<WasmStruct, WasmNull>; +using WasmStructNullable = Union<WasmStruct, WasmCustomMap, WasmNull>; +using WasmStructNonNullable = Union<WasmStruct, WasmCustomMap>; +// TODO(jkummerow): This is a temporary type definition for objects whose +// type depends on v8_flags.wasm_merged_descriptors. When dropping that flag, +// replace this with plain `WasmCustomMap`. +using WasmDescriptor = Union<WasmStruct, WasmCustomMap>; // The type for a nullable ref.string (stringref proposal). For imported strings // use StringOrNull instead. using WasmStringRefNullable = Union<String, WasmNull>; diff --git a/deps/v8/src/compiler/turboshaft/instruction-selection-normalization-reducer.h b/deps/v8/src/compiler/turboshaft/instruction-selection-normalization-reducer.h index d8f2d73c46ce..6b9498f5baa2 100644 --- a/deps/v8/src/compiler/turboshaft/instruction-selection-normalization-reducer.h +++ b/deps/v8/src/compiler/turboshaft/instruction-selection-normalization-reducer.h @@ -5,12 +5,19 @@ #ifndef V8_COMPILER_TURBOSHAFT_INSTRUCTION_SELECTION_NORMALIZATION_REDUCER_H_ #define V8_COMPILER_TURBOSHAFT_INSTRUCTION_SELECTION_NORMALIZATION_REDUCER_H_ +#include <array> +#include <optional> +#include <tuple> +#include <utility> + #include "src/base/bits.h" +#include "src/codegen/cpu-features.h" #include "src/compiler/turboshaft/assembler.h" #include "src/compiler/turboshaft/copying-phase.h" #include "src/compiler/turboshaft/index.h" #include "src/compiler/turboshaft/operations.h" #include "src/compiler/turboshaft/representations.h" +#include "src/compiler/turboshaft/utils.h" namespace v8::internal::compiler::turboshaft { @@ -24,8 +31,18 @@ namespace v8::internal::compiler::turboshaft { // // * Replacing multiplications by small powers of 2 with shifts. // +// * Folding additions and subtractions of 0. +// // * Splitting widening SIMD loads into 64-bit zero-extending loads and // low-half extensions on ARM64. +// +// * Decomposing SIMD dot products of widening extensions into ExtMul +// operations and pairwise adds. +// +// * Combining SIMD multiply + pairwise add patterns into ARM64 dot products. +// +// * Canonicalizing SIMD multiplications of matching widening extensions into +// ExtMul operations. #include "src/compiler/turboshaft/define-assembler-macros.inc" @@ -45,6 +62,11 @@ class InstructionSelectionNormalizationReducer : public Next { } } + if (kind == any_of(WordBinopOp::Kind::kAdd, WordBinopOp::Kind::kSub) && + __ matcher().MatchIntegralZero(right)) { + return left; + } + // Transforming multiplications by power of two constants into shifts if (kind == WordBinopOp::Kind::kMul) { int64_t cst; @@ -109,7 +131,213 @@ class InstructionSelectionNormalizationReducer : public Next { } #endif // V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 +#if V8_ENABLE_SIMD128 + V<Simd128> REDUCE(Simd128Binop)(V<Simd128> left, V<Simd128> right, + Simd128BinopOp::Kind kind) { + LABEL_BLOCK(no_change) { + return Next::ReduceSimd128Binop(left, right, kind); + } + if (ShouldSkipOptimizationStep()) goto no_change; + +#if V8_TARGET_ARCH_ARM64 + if (std::optional<WideningMulMatch> match = + TryMatchMulOfExtends(left, right, kind)) { + return __ Simd128Binop(match->left, match->right, match->extmul_kind); + } + + if (CpuFeatures::IsSupported(DOTPROD) && + kind == Simd128BinopOp::Kind::kI32x4Add) { + // The following almost looks like a pairwise dot-product, except for the + // root addition: + // I32x4Add(I32xExtAddPairwise(I16x8ExtMulLowI8x16S(x, y)), + // I32x4ExtAddPairwise(I16x8ExtMulHighI8x16S(x, y))) + // To use the dot-product instruction, the root needs to be converted to + // I32x4AddPairwise. + // + // So, for input A and B: + // A = A0, A1, A2, A3, ... + // B = B0, B1, B2, B3, ... + // + // Two ExtMuls create two vector products: + // ExtMulLow(A, B) = AB0, AB1, AB2, AB3, ... + // ExtMulHigh(A, B) = AB8, AB9, AB10, AB11, ... + // + // Which are then partially reduced: + // ExtAddPairwise(ExtMulLow) = AB0 + AB1, AB2 + AB3, AB4 + AB5 + // ExtAddPairwise(ExtMulHigh) = AB8 + AB9, AB10 + AB11, AB12 + AB13 + // + // And then those two partial sums are combined: + // I32x4Add = AB0 + AB1 + AB8 + AB9, AB2 + AB3 + AB10 + AB11 + // + // But to use a pairwise add we need to ensure the correct elements are + // adjacent to each other: + // I32x4Add = AB0 + AB1 + AB8 + AB9, AB2 + AB3 + AB10 + AB11 + // ^ ^ + // keep 0 and 1 adjacent, but 8 and 9 need to be moved. + // We can shuffle the inputs to give the correct order using this pattern: + // 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, + // Which, with 16-bit lanes, is equivalent to: 0, 4, 1, 5, 2, 6, 3, 7 + + auto TryCastExtMul = [this](V<Simd128> node) -> const Simd128BinopOp* { + if (auto* unop = __ Get(node).template TryCast<Simd128UnaryOp>()) { + if (unop->kind == Simd128UnaryOp::Kind::kI32x4ExtAddPairwiseI16x8S) { + if (auto* binop = + __ Get(unop->input()).template TryCast<Simd128BinopOp>()) { + if (binop->kind == Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16S || + binop->kind == Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16S) { + return binop; + } + } + } + } + return nullptr; + }; + + const Simd128BinopOp* mul_left = TryCastExtMul(left); + const Simd128BinopOp* mul_right = TryCastExtMul(right); + if (mul_left && mul_right && mul_left->kind != mul_right->kind && + mul_left->left() == mul_right->left() && + mul_left->right() == mul_right->right()) { + // Using 16-bit elements, the top half is interleaved into the odd + // lanes and the bottom half is placed into the even lanes. So, when + // we perform the second pairwise addition it is equivalent to the + // original lane-wise addition. + uint8_t shuffle[16] = { + 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, + }; + auto shuffle_kind = Simd128ShuffleOp::Kind::kI8x16; + V<Simd128> shuffle_left = __ Simd128Shuffle( + mul_left->left(), mul_left->left(), shuffle_kind, shuffle); + V<Simd128> shuffle_right = __ Simd128Shuffle( + mul_right->right(), mul_right->right(), shuffle_kind, shuffle); + return __ Simd128Binop(shuffle_left, shuffle_right, + Simd128BinopOp::Kind::kI32x4DotI8x16S); + } + } +#endif // V8_TARGET_ARCH_ARM64 + + if (kind != Simd128BinopOp::Kind::kI32x4DotI16x8S) goto no_change; + + auto GetExtMul = + [this](OpIndex input) -> std::optional<Simd128BinopOp::Kind> { + using unop_extmul_pair = + std::pair<Simd128UnaryOp::Kind, Simd128BinopOp::Kind>; + std::array extend_muls = std::to_array<unop_extmul_pair>({ + {Simd128UnaryOp::Kind::kI16x8SConvertI8x16Low, + Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16S}, + {Simd128UnaryOp::Kind::kI16x8SConvertI8x16High, + Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16S}, + {Simd128UnaryOp::Kind::kI16x8UConvertI8x16Low, + Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16U}, + {Simd128UnaryOp::Kind::kI16x8UConvertI8x16High, + Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16U}, + }); + + if (const Simd128UnaryOp* unop = + __ Get(input).template TryCast<Simd128UnaryOp>()) { + for (const auto [unop_kind, extmul_kind] : extend_muls) { + if (unop->kind == unop_kind) { + return extmul_kind; + } + } + } + return {}; + }; + + if (std::optional<Simd128BinopOp::Kind> left_extmul = GetExtMul(left)) { + if (std::optional<Simd128BinopOp::Kind> right_extmul = GetExtMul(right)) { + OpIndex left_conv = __ Get(left).input(0); + OpIndex right_conv = __ Get(right).input(0); + if (left_extmul.value() == right_extmul.value()) { + Simd128BinopOp::Kind extmul_kind = left_extmul.value(); + Simd128UnaryOp::Kind extadd_kind = + extmul_kind == Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16S || + extmul_kind == + Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16S + ? Simd128UnaryOp::Kind::kI32x4ExtAddPairwiseI16x8S + : Simd128UnaryOp::Kind::kI32x4ExtAddPairwiseI16x8U; + return __ Simd128Unary( + __ Simd128Binop(left_conv, right_conv, extmul_kind), extadd_kind); + } +#if V8_TARGET_ARCH_ARM64 + OpIndex mul_low = __ Simd128Binop( + left, right, Simd128BinopOp::Kind::kI32x4ExtMulLowI16x8S); + OpIndex mul_high = __ Simd128Binop( + left, right, Simd128BinopOp::Kind::kI32x4ExtMulHighI16x8S); + return __ Simd128Binop(mul_low, mul_high, + Simd128BinopOp::Kind::kI32x4AddPairwise); +#endif // V8_TARGET_ARCH_ARM64 + } + } + + goto no_change; + } +#endif // V8_ENABLE_SIMD128 + private: +#if V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 + struct WideningMulMatch { + V<Simd128> left; + V<Simd128> right; + Simd128BinopOp::Kind extmul_kind; + }; + + std::optional<WideningMulMatch> TryMatchMulOfExtends( + V<Simd128> left, V<Simd128> right, Simd128BinopOp::Kind kind) { + using BinopKind = Simd128BinopOp::Kind; + using UnaryKind = Simd128UnaryOp::Kind; + using Mapping = std::tuple<BinopKind, UnaryKind, BinopKind>; + + if (kind != any_of(BinopKind::kI16x8Mul, BinopKind::kI32x4Mul, + BinopKind::kI64x2Mul)) { + return std::nullopt; + } + + static constexpr std::array mappings = { + Mapping{BinopKind::kI16x8Mul, UnaryKind::kI16x8SConvertI8x16Low, + BinopKind::kI16x8ExtMulLowI8x16S}, + Mapping{BinopKind::kI16x8Mul, UnaryKind::kI16x8SConvertI8x16High, + BinopKind::kI16x8ExtMulHighI8x16S}, + Mapping{BinopKind::kI16x8Mul, UnaryKind::kI16x8UConvertI8x16Low, + BinopKind::kI16x8ExtMulLowI8x16U}, + Mapping{BinopKind::kI16x8Mul, UnaryKind::kI16x8UConvertI8x16High, + BinopKind::kI16x8ExtMulHighI8x16U}, + Mapping{BinopKind::kI32x4Mul, UnaryKind::kI32x4SConvertI16x8Low, + BinopKind::kI32x4ExtMulLowI16x8S}, + Mapping{BinopKind::kI32x4Mul, UnaryKind::kI32x4SConvertI16x8High, + BinopKind::kI32x4ExtMulHighI16x8S}, + Mapping{BinopKind::kI32x4Mul, UnaryKind::kI32x4UConvertI16x8Low, + BinopKind::kI32x4ExtMulLowI16x8U}, + Mapping{BinopKind::kI32x4Mul, UnaryKind::kI32x4UConvertI16x8High, + BinopKind::kI32x4ExtMulHighI16x8U}, + Mapping{BinopKind::kI64x2Mul, UnaryKind::kI64x2SConvertI32x4Low, + BinopKind::kI64x2ExtMulLowI32x4S}, + Mapping{BinopKind::kI64x2Mul, UnaryKind::kI64x2SConvertI32x4High, + BinopKind::kI64x2ExtMulHighI32x4S}, + Mapping{BinopKind::kI64x2Mul, UnaryKind::kI64x2UConvertI32x4Low, + BinopKind::kI64x2ExtMulLowI32x4U}, + Mapping{BinopKind::kI64x2Mul, UnaryKind::kI64x2UConvertI32x4High, + BinopKind::kI64x2ExtMulHighI32x4U}, + }; + + const Simd128UnaryOp* left_extension = + __ Get(left).template TryCast<Simd128UnaryOp>(); + const Simd128UnaryOp* right_extension = + __ Get(right).template TryCast<Simd128UnaryOp>(); + if (left_extension == nullptr || right_extension == nullptr || + left_extension->kind != right_extension->kind) { + return std::nullopt; + } + for (const auto& [mul, extension, extmul] : mappings) { + if (mul == kind && extension == left_extension->kind) { + return WideningMulMatch{left_extension->input(), + right_extension->input(), extmul}; + } + } + return std::nullopt; + } +#endif // V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 + // Return true if {index} is a literal ConsantOp. bool IsSimpleConstant(V<Any> index) { return __ Get(index).template Is<ConstantOp>(); diff --git a/deps/v8/src/compiler/turboshaft/int64-lowering-reducer.h b/deps/v8/src/compiler/turboshaft/int64-lowering-reducer.h index 31a2575d79bb..2a13d7d3895a 100644 --- a/deps/v8/src/compiler/turboshaft/int64-lowering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/int64-lowering-reducer.h @@ -292,11 +292,9 @@ class Int64LoweringReducer : public Next { } V<None> REDUCE(Return)(V<Word32> pop_count, - base::Vector<const OpIndex> return_values, - bool spill_caller_frame_slots) { + base::Vector<const OpIndex> return_values) { if (!returns_i64_) { - return Next::ReduceReturn(pop_count, return_values, - spill_caller_frame_slots); + return Next::ReduceReturn(pop_count, return_values); } base::SmallVector<OpIndex, 8> lowered_values; for (size_t i = 0; i < sig_->return_count(); ++i) { @@ -308,8 +306,7 @@ class Int64LoweringReducer : public Next { lowered_values.push_back(return_values[i]); } } - return Next::ReduceReturn(pop_count, base::VectorOf(lowered_values), - spill_caller_frame_slots); + return Next::ReduceReturn(pop_count, base::VectorOf(lowered_values)); } Word32OrWord32Pair REDUCE(WordUnary)(Word32OrWord32Pair input, @@ -435,7 +432,7 @@ class Int64LoweringReducer : public Next { std::optional<AtomicMemoryOrder> memory_order, int32_t offset, uint8_t element_size_log2, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag) { + TrustedPointerTag maybe_trusted_pointer_tag) { if (stored_rep == MemoryRepresentation::Int64() || stored_rep == MemoryRepresentation::Uint64()) { auto [low, high] = Unpack(value); @@ -458,20 +455,20 @@ class Int64LoweringReducer : public Next { Next::ReduceStore(base, index, low, kind, MemoryRepresentation::Int32(), write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); // high store int32_t high_offset = base::bits::WraparoundAdd32(offset, sizeof(int32_t)); Next::ReduceStore(base, index, high, kind, MemoryRepresentation::Int32(), write_barrier, memory_order, high_offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); return V<None>::Invalid(); } return Next::ReduceStore( base, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } OpIndex REDUCE(AtomicRMW)(OpIndex base, OpIndex index, OpIndex value, diff --git a/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.cc b/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.cc index 1a3e7d73aa46..87a181cf2b5c 100644 --- a/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.cc @@ -259,6 +259,7 @@ void LateLoadEliminationAnalyzer::ProcessBlock(const Block& block, case Opcode::kDebugBreak: case Opcode::kJSStackCheck: #ifdef V8_ENABLE_WEBASSEMBLY + case Opcode::kWasmStackCheck: case Opcode::kSimd128LaneMemory: case Opcode::kGlobalSet: case Opcode::kArraySet: @@ -273,12 +274,6 @@ void LateLoadEliminationAnalyzer::ProcessBlock(const Block& block, // but don't actually write, or cannot interfere with load elimination. break; -#ifdef V8_ENABLE_WEBASSEMBLY - case Opcode::kWasmStackCheck: - ProcessWasmStackCheck(op_idx, op.Cast<WasmStackCheckOp>()); - break; -#endif // V8_ENABLE_WEBASSEMBLY - default: // Operations that `can_write` should invalidate the state. All such // operations should be already handled above, which means that we don't @@ -465,10 +460,11 @@ void LateLoadEliminationAnalyzer::ProcessStore(OpIndex op_idx, // eliminates more): We need to add a field allow_seq_cst_replacement to // keys. We set this field to true in the beginning. Only if this field is // true should a seq_cst load be eliminated. The DisallowSeqCstReplacement - // should iterate all valid keys, and set theirallow_seq_cst_replacement bit - // to false. - // memory_.DisallowSeqCstReplacement(); + // should iterate all valid keys, and set their allow_seq_cst_replacement + // bit to false. + // Updating aliases if the value stored was known as non-aliasing. + InvalidateIfAlias(store.value()); return; } #endif // V8_ENABLE_WEBASSEMBLY @@ -542,6 +538,9 @@ void LateLoadEliminationAnalyzer::ProcessAtomicRMW(OpIndex op_idx, // TODO(manoskouk): Can we fine-grain this? TRACE(">> Invalidating whole memory"); memory_.InvalidateEverything(); + + // Updating aliases if the value stored was known as non-aliasing. + InvalidateIfAlias(store.value()); #endif } @@ -722,19 +721,6 @@ void LateLoadEliminationAnalyzer::ProcessChange(OpIndex op_idx, InvalidateIfAlias(change.input()); } -#ifdef V8_ENABLE_WEBASSEMBLY -void LateLoadEliminationAnalyzer::ProcessWasmStackCheck( - OpIndex op_idx, const WasmStackCheckOp& op) { - TRACE("> ProcessWasmStackCheck(" << op_idx << ")"); - if (op.kind == WasmStackCheckOp::Kind::kLoop && - op.trusted_instance_data().valid()) { - OpIndex instance = op.trusted_instance_data().value(); - memory_.InvalidateAtOffset(WasmTrustedInstanceData::kMemory0SizeOffset, - instance); - } -} -#endif // V8_ENABLE_WEBASSEMBLY - void LateLoadEliminationAnalyzer::FinishBlock(const Block* block) { block_to_snapshot_mapping_[block->index()] = Snapshot{ non_aliasing_objects_.Seal(), object_maps_.Seal(), memory_.Seal()}; diff --git a/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.h b/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.h index 260dbae93ecd..298e2fdaf158 100644 --- a/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.h +++ b/deps/v8/src/compiler/turboshaft/late-load-elimination-reducer.h @@ -185,7 +185,7 @@ inline MapMaskAndOr CombineMinMax(MapMaskAndOr a, MapMaskAndOr b) { } // Returns true if {a} and {b} could have a map in common. inline bool CouldHaveSameMap(MapMaskAndOr a, MapMaskAndOr b) { - return ((a.and_ & b.or_) == a.and_) || ((b.and_ & a.or_) == b.and_); + return ((a.and_ & b.or_) == a.and_) && ((b.and_ & a.or_) == b.and_); } struct MemoryAddress { @@ -516,6 +516,12 @@ class MemoryContentTable } void Insert(const StoreOp& store) { + if (store.stored_rep == MemoryRepresentation::TrustedPointer()) { + // We do not track stores of trusted pointers in MemoryContentTable + // because LoadTrustedPointerOp expects any entry with + // MemoryRepresentation::TrustedPointer() to be a LoadTrustedPointerOp. + return; + } OpIndex base = ResolveBase(store.base()); OptionalOpIndex index = store.index(); int32_t offset = store.offset; @@ -608,32 +614,6 @@ class MemoryContentTable } } - void InvalidateAtOffset(int32_t offset, OpIndex base) { - MapMaskAndOr base_maps = object_maps_.Get(base); - auto offset_keys = offset_keys_.find(offset); - if (offset_keys == offset_keys_.end()) return; - for (auto it = offset_keys->second.begin(); - it != offset_keys->second.end();) { - Key key = *it; - DCHECK_EQ(offset, key.data().mem.offset); - // It can overwrite previous stores to any base (except non-aliasing - // ones). - if (non_aliasing_objects_.Get(key.data().mem.base)) { - ++it; - continue; - } - if (!BasesCouldAlias(base, base_maps, key)) { - TRACE(">>>> InvalidateAtOffset: not invalidating thanks for maps: " - << key.data().mem); - ++it; - continue; - } - it = offset_keys->second.RemoveAt(it); - TRACE(">>>> InvalidateAtOffset: invalidating " << key.data().mem); - Set(key, OpIndex::Invalid()); - } - } - private: // To avoid pathological execution times, we cap the maximum number of // keys we track. This is safe, because *not* tracking objects (even @@ -704,6 +684,32 @@ class MemoryContentTable SetNoNotify(key, value); } + void InvalidateAtOffset(int32_t offset, OpIndex base) { + MapMaskAndOr base_maps = object_maps_.Get(base); + auto offset_keys = offset_keys_.find(offset); + if (offset_keys == offset_keys_.end()) return; + for (auto it = offset_keys->second.begin(); + it != offset_keys->second.end();) { + Key key = *it; + DCHECK_EQ(offset, key.data().mem.offset); + // It can overwrite previous stores to any base (except non-aliasing + // ones). + if (non_aliasing_objects_.Get(key.data().mem.base)) { + ++it; + continue; + } + if (!BasesCouldAlias(base, base_maps, key)) { + TRACE(">>>> InvalidateAtOffset: not invalidating thanks for maps: " + << key.data().mem); + ++it; + continue; + } + it = offset_keys->second.RemoveAt(it); + TRACE(">>>> InvalidateAtOffset: invalidating " << key.data().mem); + Set(key, OpIndex::Invalid()); + } + } + bool BasesCouldAlias(OpIndex base, MapMaskAndOr base_maps, Key other) { return BasesCouldAlias(base, base_maps, other.data().mem.base); } @@ -840,9 +846,6 @@ class V8_EXPORT_PRIVATE LateLoadEliminationAnalyzer { void ProcessCall(OpIndex op_idx, const CallOp& op); void ProcessAssumeMap(OpIndex op_idx, const AssumeMapOp& op); void ProcessChange(OpIndex op_idx, const ChangeOp& change); -#ifdef V8_ENABLE_WEBASSEMBLY - void ProcessWasmStackCheck(OpIndex op_idx, const WasmStackCheckOp& op); -#endif void DcheckWordBinop(OpIndex op_idx, const WordBinopOp& binop); @@ -962,7 +965,11 @@ class V8_EXPORT_PRIVATE LateLoadEliminationReducer : public Next { Asm().output_graph().IsTurbolev())); } #if DEBUG - if (v8_flags.turboshaft_verify_load_elimination) { + // We cannot verify loads with a shared base: Although it is valid to + // eliminate them if there is no intervening atomic operation, another + // thread could still modify the loaded value between two loads. + if (v8_flags.turboshaft_verify_load_elimination && + !load.kind.shared_base) { // When the debug flag {turboshaft_verify_load_elimination} is used, // we perform the original load and assert that it's indeed equal to // the replacement that we are using. diff --git a/deps/v8/src/compiler/turboshaft/layered-hash-map.h b/deps/v8/src/compiler/turboshaft/layered-hash-map.h index e6145bee7eb8..9302cc9ba6ef 100644 --- a/deps/v8/src/compiler/turboshaft/layered-hash-map.h +++ b/deps/v8/src/compiler/turboshaft/layered-hash-map.h @@ -5,6 +5,7 @@ #ifndef V8_COMPILER_TURBOSHAFT_LAYERED_HASH_MAP_H_ #define V8_COMPILER_TURBOSHAFT_LAYERED_HASH_MAP_H_ +#include <bit> #include <cstddef> #include <iostream> #include <limits> @@ -82,7 +83,7 @@ LayeredHashMap<Key, Value>::LayeredHashMap(Zone* zone, initial_capacity = std::max<uint32_t>(initial_capacity, 16); // {initial_capacity} should be a power of 2, so that we can compute offset // in {table_} with a mask rather than a modulo. - initial_capacity = base::bits::RoundUpToPowerOfTwo32(initial_capacity); + initial_capacity = std::bit_ceil(initial_capacity); mask_ = initial_capacity - 1; // Allocating the table_ table_ = zone_->NewVector<Entry>(initial_capacity); diff --git a/deps/v8/src/compiler/turboshaft/load-store-simplification-reducer.h b/deps/v8/src/compiler/turboshaft/load-store-simplification-reducer.h index c05d12d960fc..a8585ee7d70c 100644 --- a/deps/v8/src/compiler/turboshaft/load-store-simplification-reducer.h +++ b/deps/v8/src/compiler/turboshaft/load-store-simplification-reducer.h @@ -82,7 +82,7 @@ class LoadStoreSimplificationReducer : public Next, std::optional<AtomicMemoryOrder> memory_order, int32_t offset, uint8_t element_size_log2, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag) { + TrustedPointerTag maybe_trusted_pointer_tag) { SimplifyLoadStore(base, index, kind, offset, element_size_log2, (write_barrier == WriteBarrierKind::kNoWriteBarrier && !kind.tagged_base)); @@ -103,7 +103,7 @@ class LoadStoreSimplificationReducer : public Next, return Next::ReduceStore( base, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } OpIndex REDUCE(AtomicWord32Pair)(V<WordPtr> base, OptionalV<WordPtr> index, diff --git a/deps/v8/src/compiler/turboshaft/load-store-verification-reducer.h b/deps/v8/src/compiler/turboshaft/load-store-verification-reducer.h index 3b7355141522..9bd6f21f5903 100644 --- a/deps/v8/src/compiler/turboshaft/load-store-verification-reducer.h +++ b/deps/v8/src/compiler/turboshaft/load-store-verification-reducer.h @@ -45,14 +45,14 @@ class StoreLoadVerificationReducer : public Next { std::optional<AtomicMemoryOrder> memory_order, int32_t offset, uint8_t element_size_log2, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag) { + TrustedPointerTag maybe_trusted_pointer_tag) { if (v8_flags.turboshaft_verify_load_store_taggedness) { AbortIfWrongRepresentation(value, stored_rep, "store"); } return Next::ReduceStore( base, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } private: diff --git a/deps/v8/src/compiler/turboshaft/loop-peeling-reducer.h b/deps/v8/src/compiler/turboshaft/loop-peeling-reducer.h index 838a4096edbe..d7e40b0863f1 100644 --- a/deps/v8/src/compiler/turboshaft/loop-peeling-reducer.h +++ b/deps/v8/src/compiler/turboshaft/loop-peeling-reducer.h @@ -79,7 +79,7 @@ class LoopPeelingReducer : public Next { #if V8_ENABLE_WEBASSEMBLY V<None> REDUCE_INPUT_GRAPH(WasmStackCheck)( - V<Any> ig_idx, const WasmStackCheckOp& stack_check) { + V<None> ig_idx, const WasmStackCheckOp& stack_check) { if (ShouldSkipOptimizationStep() || !IsEmittingPeeledIteration()) { return Next::ReduceInputGraphWasmStackCheck(ig_idx, stack_check); } diff --git a/deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h b/deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h index 3f4d343d2142..3cd0212aa381 100644 --- a/deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h +++ b/deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h @@ -338,7 +338,7 @@ class LoopStackCheckElisionReducer : public Next { #if V8_ENABLE_WEBASSEMBLY V<None> REDUCE_INPUT_GRAPH(WasmStackCheck)( - V<Any> ig_idx, const WasmStackCheckOp& stack_check) { + V<None> ig_idx, const WasmStackCheckOp& stack_check) { if (skip_next_stack_check_ && stack_check.kind == WasmStackCheckOp::Kind::kLoop) { skip_next_stack_check_ = false; @@ -448,7 +448,7 @@ class LoopUnrollingReducer : public Next { } #if V8_ENABLE_WEBASSEMBLY - V<None> REDUCE_INPUT_GRAPH(WasmStackCheck)(V<Any> ig_idx, + V<None> REDUCE_INPUT_GRAPH(WasmStackCheck)(V<None> ig_idx, const WasmStackCheckOp& check) { if (ShouldSkipOptimizationStep() || !skip_next_stack_check_) { return Next::ReduceInputGraphWasmStackCheck(ig_idx, check); diff --git a/deps/v8/src/compiler/turboshaft/machine-optimization-reducer.h b/deps/v8/src/compiler/turboshaft/machine-optimization-reducer.h index f31fc86cefac..2c1b5cece12b 100644 --- a/deps/v8/src/compiler/turboshaft/machine-optimization-reducer.h +++ b/deps/v8/src/compiler/turboshaft/machine-optimization-reducer.h @@ -1672,8 +1672,9 @@ class MachineOptimizationReducer : public Next { if (left == right && !(rep == any_of(RegisterRepresentation::Float32(), RegisterRepresentation::Float64())) && - kind == any_of(Kind::kSignedLessThanOrEqual, - Kind::kUnsignedLessThanOrEqual)) { + kind == any_of(Kind::kUnsignedLessThanOrEqual, + Kind::kSignedLessThanOrEqual, Kind::kUnsignedLessThan, + Kind::kSignedLessThan)) { switch (kind) { case Kind::kEqual: UNREACHABLE(); @@ -2235,12 +2236,12 @@ class MachineOptimizationReducer : public Next { std::optional<AtomicMemoryOrder> memory_order, int32_t offset, uint8_t element_scale, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag) { + TrustedPointerTag maybe_trusted_pointer_tag) { LABEL_BLOCK(no_change) { return Next::ReduceStore( base_idx, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_scale, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } if (ShouldSkipOptimizationStep()) goto no_change; #if V8_TARGET_ARCH_32_BIT @@ -2289,7 +2290,7 @@ class MachineOptimizationReducer : public Next { // {offset}, or just do other optimizations on this Store. __ Store(base_idx, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_scale, - maybe_initializing_or_transitioning, maybe_indirect_pointer_tag); + maybe_initializing_or_transitioning, maybe_trusted_pointer_tag); return V<None>::Invalid(); } @@ -2297,7 +2298,7 @@ class MachineOptimizationReducer : public Next { return Next::ReduceStore(base_idx, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_scale, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } OpIndex REDUCE(Load)(OpIndex base_idx, OptionalOpIndex index, @@ -2384,147 +2385,6 @@ class MachineOptimizationReducer : public Next { } #if V8_ENABLE_WEBASSEMBLY - V<Any> REDUCE(Simd128Binop)(V<Simd128> left, V<Simd128> right, - Simd128BinopOp::Kind kind) { - LABEL_BLOCK(no_change) { - return Next::ReduceSimd128Binop(left, right, kind); - } - if (ShouldSkipOptimizationStep()) goto no_change; - -#ifdef V8_TARGET_ARCH_ARM64 - if (CpuFeatures::IsSupported(DOTPROD) && - kind == Simd128BinopOp::Kind::kI32x4Add) { - // The following almost looks like a pairwise dot-product, except for the - // root addition: - // I32x4Add(I32xExtAddPairwise(I16x8ExtMulLowI8x16S(x, y)), - // I32x4ExtAddPairwise(I16x8ExtMulHighI8x16S(x, y))) - // To use the dot-product instruction, the root needs to be converted to - // I32x4AddPairwise. - // - // So, for input A and B: - // A = A0, A1, A2, A3, ... - // B = B0, B1, B2, B3, ... - // - // Two ExtMuls create two vector products: - // ExtMulLow(A, B) = AB0, AB1, AB2, AB3, ... - // ExtMulHigh(A, B) = AB8, AB9, AB10, AB11, ... - // - // Which are then partially reduced: - // ExtAddPairwise(ExtMulLow) = AB0 + AB1, AB2 + AB3, AB4 + AB5 - // ExtAddPairwise(ExtMulHigh) = AB8 + AB9, AB10 + AB11, AB12 + AB13 - // - // And then those two partial sums are combined: - // I32x4Add = AB0 + AB1 + AB8 + AB9, AB2 + AB3 + AB10 + AB11 - // - // But to use a pairwise add we need to ensure the correct elements are - // adjacent to each other: - // I32x4Add = AB0 + AB1 + AB8 + AB9, AB2 + AB3 + AB10 + AB11 - // ^ ^ - // keep 0 and 1 adjacent, but 8 and 9 need to be moved. - // We can shuffle the inputs to give the correct order using this pattern: - // 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, - // Which, with 16-bit lanes, is equivalent to: 0, 4, 1, 5, 2, 6, 3, 7 - - auto TryCastExtMul = [this](V<Simd128> node) -> const Simd128BinopOp* { - if (auto* unop = matcher_.template TryCast<Simd128UnaryOp>(node)) { - if (unop->kind == Simd128UnaryOp::Kind::kI32x4ExtAddPairwiseI16x8S) { - if (auto* binop = - matcher_.template TryCast<Simd128BinopOp>(unop->input())) { - if (binop->kind == Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16S || - binop->kind == Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16S) { - return binop; - } - } - } - } - return nullptr; - }; - - const Simd128BinopOp* mul_left = TryCastExtMul(left); - const Simd128BinopOp* mul_right = TryCastExtMul(right); - if (mul_left && mul_right && mul_left->kind != mul_right->kind && - mul_left->left() == mul_right->left() && - mul_left->right() == mul_right->right()) { - // Using 16-bit elements, the top half is interleaved into the odd - // lanes and the bottom half is placed into the even lanes. So, when - // we perform the second pairwise addition it is equivalent to the - // original lane-wise addition. - uint8_t shuffle[16] = { - 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, - }; - auto shuffle_kind = Simd128ShuffleOp::Kind::kI8x16; - V<Simd128> shuffle_left = __ Simd128Shuffle( - mul_left->left(), mul_left->left(), shuffle_kind, shuffle); - V<Simd128> shuffle_right = __ Simd128Shuffle( - mul_right->right(), mul_right->right(), shuffle_kind, shuffle); - return __ Simd128Binop(shuffle_left, shuffle_right, - Simd128BinopOp::Kind::kI32x4DotI8x16S); - } - } -#endif // V8_TARGET_ARCH_ARM64 - - if (kind != Simd128BinopOp::Kind::kI32x4DotI16x8S) goto no_change; - - // Check to see whether we're really performing the operation on - // i8x8 inputs. - auto GetExtMul = - [this](OpIndex input) -> std::optional<Simd128BinopOp::Kind> { - using unop_extmul_pair = - std::pair<Simd128UnaryOp::Kind, Simd128BinopOp::Kind>; - std::array extend_muls = std::to_array<unop_extmul_pair>({ - {Simd128UnaryOp::Kind::kI16x8SConvertI8x16Low, - Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16S}, - {Simd128UnaryOp::Kind::kI16x8SConvertI8x16High, - Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16S}, - {Simd128UnaryOp::Kind::kI16x8UConvertI8x16Low, - Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16U}, - {Simd128UnaryOp::Kind::kI16x8UConvertI8x16High, - Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16U}, - }); - - if (const Simd128UnaryOp* unop = - matcher_.TryCast<Simd128UnaryOp>(input)) { - for (const auto [unop_kind, extmul_kind] : extend_muls) { - if (unop->kind == unop_kind) { - return extmul_kind; - } - } - } - return {}; - }; - - if (std::optional<Simd128BinopOp::Kind> left_extmul = GetExtMul(left)) { - if (std::optional<Simd128BinopOp::Kind> right_extmul = GetExtMul(right)) { - OpIndex left_conv = matcher_.Get(left).input(0); - OpIndex right_conv = matcher_.Get(right).input(0); - if (left_extmul.value() == right_extmul.value()) { - // If both inputs are being extended in the same way, we can just use - // one extmul and one extadd_pairwise, instead. - Simd128BinopOp::Kind extmul_kind = left_extmul.value(); - Simd128UnaryOp::Kind extadd_kind = - extmul_kind == Simd128BinopOp::Kind::kI16x8ExtMulLowI8x16S || - extmul_kind == - Simd128BinopOp::Kind::kI16x8ExtMulHighI8x16S - ? Simd128UnaryOp::Kind::kI32x4ExtAddPairwiseI16x8S - : Simd128UnaryOp::Kind::kI32x4ExtAddPairwiseI16x8U; - return __ Simd128Unary( - __ Simd128Binop(left_conv, right_conv, extmul_kind), extadd_kind); -#ifdef V8_TARGET_ARCH_ARM64 - } else { - // Otherwise, just break the dot into its constituent parts. - OpIndex mul_low = __ Simd128Binop( - left, right, Simd128BinopOp::Kind::kI32x4ExtMulLowI16x8S); - OpIndex mul_high = __ Simd128Binop( - left, right, Simd128BinopOp::Kind::kI32x4ExtMulHighI16x8S); - return __ Simd128Binop(mul_low, mul_high, - Simd128BinopOp::Kind::kI32x4AddPairwise); -#endif // V8_TARGET_ARCH_ARM64 - } - } - } - - goto no_change; - } #ifdef V8_TARGET_ARCH_ARM64 V<Simd128> REDUCE(Simd128ReplaceLane)(V<Simd128> into, V<Any> new_lane, Simd128ReplaceLaneOp::Kind kind, diff --git a/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.cc b/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.cc index 2508840fd109..d4632e242dfb 100644 --- a/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.cc @@ -18,7 +18,7 @@ const TSCallDescriptor* CreateAllocateBuiltinDescriptor(Zone* zone, Linkage::GetStubCallDescriptor( zone, AllocateDescriptor{}, AllocateDescriptor{}.GetStackParameterCount(), - CallDescriptor::kCanUseRoots, Operator::kNoThrow, + CallDescriptor::kNoFlags, Operator::kNoThrow, isolate != nullptr ? StubCallMode::kCallCodeObject : StubCallMode::kCallBuiltinPointer), CanThrow{false}, LazyDeoptOnThrow{false}, zone); @@ -31,7 +31,7 @@ const TSCallDescriptor* CreateAllocateWasmSharedBuiltinDescriptor( Linkage::GetStubCallDescriptor( zone, WasmAllocateSharedDescriptor{}, AllocateDescriptor{}.GetStackParameterCount(), - CallDescriptor::kCanUseRoots, Operator::kNoThrow, + CallDescriptor::kNoFlags, Operator::kNoThrow, StubCallMode::kCallBuiltinPointer), CanThrow{false}, LazyDeoptOnThrow{false}, zone); } diff --git a/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.h b/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.h index 80ef96eccd53..f12f1ff6433e 100644 --- a/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.h +++ b/deps/v8/src/compiler/turboshaft/memory-optimization-reducer.h @@ -9,7 +9,6 @@ #include "src/base/template-utils.h" #include "src/builtins/builtins.h" -#include "src/codegen/external-reference.h" #include "src/compiler/turboshaft/assembler.h" #include "src/compiler/turboshaft/copying-phase.h" #include "src/compiler/turboshaft/operations.h" @@ -222,7 +221,7 @@ class MemoryOptimizationReducer : public Next { skipped_write_barrier_kind_, store.memory_order(), store.offset, store.element_size_log2, store.maybe_initializing_or_transitioning, - store.indirect_pointer_tag()); + store.trusted_pointer_tag()); return V<None>::Invalid(); } DCHECK_NE(store.write_barrier, WriteBarrierKind::kAssertNoWriteBarrier); @@ -240,7 +239,7 @@ class MemoryOptimizationReducer : public Next { WriteBarrierKind::kPointerWriteBarrier, store.memory_order(), store.offset, store.element_size_log2, store.maybe_initializing_or_transitioning, - store.indirect_pointer_tag()); + store.trusted_pointer_tag()); return V<None>::Invalid(); } @@ -423,51 +422,18 @@ class MemoryOptimizationReducer : public Next { V<WordPtr> REDUCE(LoadExternalPointer)(V<Word32> handle, ExternalPointerTagRange tag_range) { // Decode loaded external pointer. - V<WordPtr> table; - if (isolate_ != nullptr) { - // Here we access the external pointer table through an ExternalReference. - // Alternatively, we could also hardcode the address of the table since it - // is never reallocated. However, in that case we must be able to - // guarantee that the generated code is never executed under a different - // Isolate, as that would allow access to external objects from different - // Isolates. It also would break if the code is serialized/deserialized at - // some point. - V<WordPtr> table_address = - IsSharedExternalPointerType(tag_range) - ? __ - LoadOffHeap( - __ ExternalConstant( - ExternalReference:: - shared_external_pointer_table_address_address( - isolate_)), - MemoryRepresentation::UintPtr()) - : __ ExternalConstant( - ExternalReference::external_pointer_table_address( - isolate_)); - table = __ LoadOffHeap(table_address, - Internals::kExternalEntityTableBasePointerOffset, - MemoryRepresentation::UintPtr()); + V<WordPtr> table_address; + if (IsSharedExternalPointerType(tag_range)) { + V<WordPtr> table_address_address = + __ IsolateField(IsolateFieldId::kSharedExternalPointerTable); + table_address = __ LoadOffHeap(table_address_address, + MemoryRepresentation::UintPtr()); } else { -#if V8_ENABLE_WEBASSEMBLY - V<WordPtr> isolate_root = __ LoadRootRegister(); - if (IsSharedExternalPointerType(tag_range)) { - V<WordPtr> table_address = - __ Load(isolate_root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::shared_external_pointer_table_offset()); - table = __ Load(table_address, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - Internals::kExternalEntityTableBasePointerOffset); - } else { - table = __ Load(isolate_root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::external_pointer_table_offset() + - Internals::kExternalEntityTableBasePointerOffset); - } -#else - UNREACHABLE(); -#endif + table_address = __ IsolateField(IsolateFieldId::kExternalPointerTable); } + V<WordPtr> table = __ LoadOffHeap( + table_address, Internals::kExternalEntityTableBasePointerOffset, + MemoryRepresentation::UintPtr()); V<Word32> index = __ Word32ShiftRightLogical(handle, kExternalPointerIndexShift); diff --git a/deps/v8/src/compiler/turboshaft/operations.cc b/deps/v8/src/compiler/turboshaft/operations.cc index af0c5b0b3fcb..8ca48ae16d12 100644 --- a/deps/v8/src/compiler/turboshaft/operations.cc +++ b/deps/v8/src/compiler/turboshaft/operations.cc @@ -670,6 +670,7 @@ void LoadOp::PrintOptions(std::ostream& os) const { os << ", element size: 2^" << int{element_size_log2}; } if (offset != 0) os << ", offset: " << offset; + if (kind.shared_base) os << ", shared_base"; os << ']'; } @@ -760,8 +761,8 @@ void StoreOp::PrintOptions(std::ostream& os) const { } if (offset != 0) os << ", offset: " << offset; if (maybe_initializing_or_transitioning) os << ", initializing"; - if (indirect_pointer_tag() != kIndirectPointerNullTag) { - os << ", indirect pointer tag: " << indirect_pointer_tag(); + if (trusted_pointer_tag() != kTrustedPointerNullTag) { + os << ", trusted pointer tag: " << trusted_pointer_tag(); } os << ']'; } @@ -1228,9 +1229,9 @@ std::ostream& operator<<(std::ostream& os, base::Vector<EffectHandler> hs) { os << "effect handlers: "; for (auto& h : hs) { if (h.is_switch()) { - os << h.tag_index() << "[switch]" << (&h == &hs.last() ? "" : " "); + os << h.tag_index() << "[switch]" << (&h == &hs.back() ? "" : " "); } else { - os << h.tag_index() << ":" << h.block << (&h == &hs.last() ? "" : " "); + os << h.tag_index() << ":" << h.block << (&h == &hs.back() ? "" : " "); } } return os; @@ -2176,7 +2177,8 @@ std::ostream& operator<<(std::ostream& os, Simd256UnpackOp::Kind kind) { #if V8_ENABLE_WEBASSEMBLY void WasmAllocateArrayOp::PrintOptions(std::ostream& os) const { - os << '[' << array_type->element_type() << ", " << is_shared << ']'; + os << '[' << array_type->element_type() << ", " << array_type->is_shared() + << ']'; } void WasmAllocateStructOp::PrintOptions(std::ostream& os) const { @@ -2220,6 +2222,7 @@ void ArrayGetOp::PrintOptions(std::ostream& os) const { } else { os << "non-atomic"; } + if (shared_base) os << ", shared-base"; os << ']'; } diff --git a/deps/v8/src/compiler/turboshaft/operations.h b/deps/v8/src/compiler/turboshaft/operations.h index 4d62936f230e..223413701b7a 100644 --- a/deps/v8/src/compiler/turboshaft/operations.h +++ b/deps/v8/src/compiler/turboshaft/operations.h @@ -7,6 +7,7 @@ #include <array> #include <cmath> +#include <compare> #include <cstdint> #include <cstring> #include <limits> @@ -1044,7 +1045,8 @@ struct alignas(OpIndex) Operation { void PrintOptions(std::ostream& os) const; // Returns true if {this} is the only operation using {value}. - bool IsOnlyUserOf(const Operation& value, const Graph& graph) const; + V8_EXPORT_PRIVATE bool IsOnlyUserOf(const Operation& value, + const Graph& graph) const; void Print() const; @@ -3149,6 +3151,8 @@ struct LoadOp : OperationT<LoadOp> { bool is_immutable : 1; // The load should be atomic. bool is_atomic : 1; + // The `base` input *may* be a tagged pointer to a shared HeapObject. + bool shared_base : 1; static constexpr Kind Aligned(BaseTaggedness base_is_tagged) { switch (base_is_tagged) { @@ -3165,7 +3169,8 @@ struct LoadOp : OperationT<LoadOp> { .with_trap_handler = false, .load_eliminable = true, .is_immutable = false, - .is_atomic = false}; + .is_atomic = false, + .shared_base = false}; } static constexpr Kind RawAligned() { return {.tagged_base = false, @@ -3173,7 +3178,8 @@ struct LoadOp : OperationT<LoadOp> { .with_trap_handler = false, .load_eliminable = true, .is_immutable = false, - .is_atomic = false}; + .is_atomic = false, + .shared_base = false}; } static constexpr Kind RawUnaligned() { return {.tagged_base = false, @@ -3181,7 +3187,8 @@ struct LoadOp : OperationT<LoadOp> { .with_trap_handler = false, .load_eliminable = true, .is_immutable = false, - .is_atomic = false}; + .is_atomic = false, + .shared_base = false}; } static constexpr Kind Trapping() { return {.tagged_base = false, @@ -3189,7 +3196,8 @@ struct LoadOp : OperationT<LoadOp> { .with_trap_handler = true, .load_eliminable = true, .is_immutable = false, - .is_atomic = false}; + .is_atomic = false, + .shared_base = false}; } static constexpr Kind TrapOnNull() { return {.tagged_base = true, @@ -3197,7 +3205,8 @@ struct LoadOp : OperationT<LoadOp> { .with_trap_handler = true, .load_eliminable = true, .is_immutable = false, - .is_atomic = false}; + .is_atomic = false, + .shared_base = false}; } static constexpr Kind MaybeUnaligned(MemoryRepresentation rep) { return rep == MemoryRepresentation::Int8() || @@ -3225,13 +3234,13 @@ struct LoadOp : OperationT<LoadOp> { return new_kind; } - bool operator==(const Kind& other) const { - return tagged_base == other.tagged_base && - maybe_unaligned == other.maybe_unaligned && - with_trap_handler == other.with_trap_handler && - load_eliminable == other.load_eliminable && - is_immutable == other.is_immutable && is_atomic == other.is_atomic; + [[nodiscard]] constexpr Kind SharedBase() const { + Kind new_kind(*this); + new_kind.shared_base = true; + return new_kind; } + + auto operator<=>(const Kind& other) const = default; }; Kind kind; MemoryRepresentation loaded_rep; @@ -3243,7 +3252,12 @@ struct LoadOp : OperationT<LoadOp> { // Loads might depend on checks for pointer validity, object layout, bounds // checks, etc. // TODO(tebbi): Distinguish between on-heap and off-heap loads. - OpEffects effects = OpEffects().CanReadMemory().CanDependOnChecks(); + OpEffects effects = OpEffects().CanDependOnChecks(); + if (kind.is_immutable) { + effects = effects.CanReadImmutableMemory(); + } else { + effects = effects.CanReadMemory(); + } if (kind.with_trap_handler) effects = effects.CanLeaveCurrentFunction(); if (kind.is_atomic) { // Atomic load should not be reordered with other loads. @@ -3315,6 +3329,11 @@ struct LoadOp : OperationT<LoadOp> { auto options() const { return std::tuple{kind, loaded_rep, result_rep, offset, element_size_log2}; } + bool operator<(const LoadOp& other) const { + return std::tuple{base(), index().value_or_invalid(), options()} < + std::tuple{other.base(), other.index().value_or_invalid(), + other.options()}; + } }; V8_INLINE size_t hash_value(LoadOp::Kind kind) { @@ -3327,7 +3346,7 @@ V8_INLINE size_t hash_value(LoadOp::Kind kind) { #if V8_ENABLE_SANDBOX struct LoadTrustedPointerOp : FixedArityOperationT<2, LoadTrustedPointerOp> { LoadOp::Kind kind; - IndirectPointerTagRange tag_range; + TrustedPointerTagRange tag_range; const int offset; OpEffects Effects() const { @@ -3340,7 +3359,7 @@ struct LoadTrustedPointerOp : FixedArityOperationT<2, LoadTrustedPointerOp> { explicit LoadTrustedPointerOp(V<HeapObject> base, V<WordPtr> table, LoadOp::Kind kind, - IndirectPointerTagRange tag_range, int offset) + TrustedPointerTagRange tag_range, int offset) : Base(base, table), kind(kind), tag_range(tag_range), offset(offset) { DCHECK(kind.tagged_base); DCHECK(!kind.is_atomic); @@ -3716,7 +3735,7 @@ struct StoreOp : OperationT<StoreOp> { AtomicMemoryOrder memory_order_; // use the padding after prev field public: - uint16_t indirect_pointer_tag_; + uint16_t trusted_pointer_tag_; std::optional<AtomicMemoryOrder> memory_order() const { if (kind.is_atomic) return memory_order_; @@ -3768,16 +3787,15 @@ struct StoreOp : OperationT<StoreOp> { return input_count == 3 ? input(2) : OpIndex::Invalid(); } - IndirectPointerTag indirect_pointer_tag() const { - return static_cast<IndirectPointerTag>(indirect_pointer_tag_); + TrustedPointerTag trusted_pointer_tag() const { + return static_cast<TrustedPointerTag>(trusted_pointer_tag_); } - StoreOp( - OpIndex base, OptionalOpIndex index, OpIndex value, Kind kind, - MemoryRepresentation stored_rep, WriteBarrierKind write_barrier, - std::optional<AtomicMemoryOrder> memory_order, int32_t offset, - uint8_t element_size_log2, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag = kIndirectPointerNullTag) + StoreOp(OpIndex base, OptionalOpIndex index, OpIndex value, Kind kind, + MemoryRepresentation stored_rep, WriteBarrierKind write_barrier, + std::optional<AtomicMemoryOrder> memory_order, int32_t offset, + uint8_t element_size_log2, bool maybe_initializing_or_transitioning, + TrustedPointerTag maybe_trusted_pointer_tag = kTrustedPointerNullTag) : Base(2 + index.valid()), kind(kind), stored_rep(stored_rep), @@ -3787,9 +3805,8 @@ struct StoreOp : OperationT<StoreOp> { maybe_initializing_or_transitioning( maybe_initializing_or_transitioning), memory_order_(memory_order.value_or(AtomicMemoryOrder::kSeqCst)), - indirect_pointer_tag_( - static_cast<uint16_t>(maybe_indirect_pointer_tag)) { - DCHECK_EQ(indirect_pointer_tag(), maybe_indirect_pointer_tag); + trusted_pointer_tag_(static_cast<uint16_t>(maybe_trusted_pointer_tag)) { + DCHECK_EQ(trusted_pointer_tag(), maybe_trusted_pointer_tag); input(0) = base; input(1) = value; if (index.valid()) { @@ -3802,7 +3819,7 @@ struct StoreOp : OperationT<StoreOp> { return fn(mapper.Map(base()), mapper.Map(index()), mapper.Map(value()), kind, stored_rep, write_barrier, memory_order(), offset, element_size_log2, maybe_initializing_or_transitioning, - indirect_pointer_tag()); + trusted_pointer_tag()); } void Validate(const Graph& graph) const { @@ -3817,11 +3834,11 @@ struct StoreOp : OperationT<StoreOp> { WriteBarrierKind write_barrier, std::optional<AtomicMemoryOrder> memory_order, int32_t offset, uint8_t element_size_log2, bool maybe_initializing_or_transitioning, - IndirectPointerTag maybe_indirect_pointer_tag = kIndirectPointerNullTag) { + TrustedPointerTag maybe_trusted_pointer_tag = kTrustedPointerNullTag) { return Base::New(graph, 2 + index.valid(), base, index, value, kind, stored_rep, write_barrier, memory_order, offset, element_size_log2, maybe_initializing_or_transitioning, - maybe_indirect_pointer_tag); + maybe_trusted_pointer_tag); } void PrintInputs(std::ostream& os, const std::string& op_index_prefix) const; @@ -3834,7 +3851,7 @@ struct StoreOp : OperationT<StoreOp> { offset, element_size_log2, maybe_initializing_or_transitioning, - indirect_pointer_tag()}; + trusted_pointer_tag()}; } }; @@ -4221,9 +4238,7 @@ struct PrepareForLoopOp : FixedArityOperationT<1, PrepareForLoopOp> { #if V8_ENABLE_WEBASSEMBLY // A WebAssembly stack check operation. -// If input_count > 0: -// - input(0) is trusted_instance_data -struct WasmStackCheckOp : OperationT<WasmStackCheckOp> { +struct WasmStackCheckOp : FixedArityOperationT<0, WasmStackCheckOp> { using Kind = JSStackCheckOp::Kind; Kind kind; @@ -4231,7 +4246,8 @@ struct WasmStackCheckOp : OperationT<WasmStackCheckOp> { switch (kind) { case Kind::kLoop: // A loop stack check can have arbitrary side effects via debugger - // interrupt requests; in particular it can trigger memory growth. + // interrupt requests; in particular it can trigger shared memory + // growth. return OpEffects() .RequiredWhenUnused() .CanReadMemory() @@ -4247,55 +4263,17 @@ struct WasmStackCheckOp : OperationT<WasmStackCheckOp> { UNREACHABLE(); } - OptionalV<WasmTrustedInstanceData> trusted_instance_data() const { - return input_count > 0 ? input<WasmTrustedInstanceData>(0) - : V<WasmTrustedInstanceData>::Invalid(); - } - - WasmStackCheckOp(OptionalV<WasmTrustedInstanceData> trusted_instance_data, - Kind kind) - : Base(trusted_instance_data.valid() ? 1 : 0), kind(kind) { - if (trusted_instance_data.valid()) { - input(0) = trusted_instance_data.value(); - } - } - - static WasmStackCheckOp& New( - Graph* graph, OptionalV<WasmTrustedInstanceData> trusted_instance_data, - Kind kind) { - size_t input_count = trusted_instance_data.valid() ? 1 : 0; - return Base::New(graph, input_count, trusted_instance_data, kind); - } - - template <typename Fn, typename Mapper> - V8_INLINE auto Explode(Fn fn, Mapper& mapper) const { - return fn(mapper.Map(trusted_instance_data()), kind); - } + explicit WasmStackCheckOp(Kind kind) : Base(), kind(kind) {} base::Vector<const RegisterRepresentation> outputs_rep() const { return {}; } base::Vector<const MaybeRegisterRepresentation> inputs_rep( ZoneVector<MaybeRegisterRepresentation>& storage) const { - if (input_count == 0) { - return {}; - } - storage.resize(input_count); - storage[0] = MaybeRegisterRepresentation::Tagged(); - return base::VectorOf(storage); + return {}; } void Validate(const Graph& graph) const { - if (kind == Kind::kFunctionEntry) { - DCHECK_EQ(input_count, 0); - DCHECK(!trusted_instance_data().valid()); - } else if (kind == Kind::kLoop) { - DCHECK_LE(input_count, 1); - if (input_count > 0) { - DCHECK(trusted_instance_data().valid()); - } - } else { - UNREACHABLE(); - } + DCHECK(kind == Kind::kFunctionEntry || kind == Kind::kLoop); } auto options() const { return std::tuple{kind}; } @@ -4931,11 +4909,6 @@ struct UnreachableOp : FixedArityOperationT<0, UnreachableOp> { }; struct ReturnOp : OperationT<ReturnOp> { - // spill_caller_frame_slots signals that all caller stack located return - // values should be spilled before reaching the InstructionSelector. - // The growable stacks implementation does extra work to spill these values - // and it cannot be performed during InstructionSelector lowering efficiently. - bool spill_caller_frame_slots; static constexpr OpEffects effects = OpEffects().CanLeaveCurrentFunction(); base::Vector<const RegisterRepresentation> outputs_rep() const { return {}; } @@ -4953,10 +4926,8 @@ struct ReturnOp : OperationT<ReturnOp> { return inputs().SubVector(1, input_count); } - ReturnOp(V<Word32> pop_count, base::Vector<const OpIndex> return_values, - bool spill_caller_frame_slots) - : Base(1 + return_values.size()), - spill_caller_frame_slots(spill_caller_frame_slots) { + ReturnOp(V<Word32> pop_count, base::Vector<const OpIndex> return_values) + : Base(1 + return_values.size()) { base::Vector<OpIndex> inputs = this->inputs(); inputs[0] = pop_count; inputs.SubVector(1, inputs.size()).OverwriteWith(return_values); @@ -4966,17 +4937,14 @@ struct ReturnOp : OperationT<ReturnOp> { V8_INLINE auto Explode(Fn fn, Mapper& mapper) const { OpIndex mapped_pop_count = mapper.Map(pop_count()); auto mapped_return_values = mapper.template Map<4>(return_values()); - return fn(mapped_pop_count, base::VectorOf(mapped_return_values), - spill_caller_frame_slots); + return fn(mapped_pop_count, base::VectorOf(mapped_return_values)); } static ReturnOp& New(Graph* graph, V<Word32> pop_count, - base::Vector<const OpIndex> return_values, - bool spill_caller_frame_slots) { - return Base::New(graph, 1 + return_values.size(), pop_count, return_values, - spill_caller_frame_slots); + base::Vector<const OpIndex> return_values) { + return Base::New(graph, 1 + return_values.size(), pop_count, return_values); } - auto options() const { return std::tuple{spill_caller_frame_slots}; } + auto options() const { return std::tuple{}; } }; struct GotoOp : FixedArityOperationT<0, GotoOp> { @@ -7800,7 +7768,8 @@ struct RttCanonOp : FixedArityOperationT<1, RttCanonOp> { struct WasmTypeCheckOp : OperationT<WasmTypeCheckOp> { WasmTypeCheckConfig config; - static constexpr OpEffects effects = OpEffects().AssumesConsistentHeap(); + static constexpr OpEffects effects = + OpEffects().AssumesConsistentHeap().CanDependOnChecks(); WasmTypeCheckOp(V<Object> object, OptionalV<Map> rtt, WasmTypeCheckConfig config) @@ -8007,7 +7976,10 @@ struct AnyConvertExternOp : FixedArityOperationT<1, AnyConvertExternOp> { struct ExternConvertAnyOp : FixedArityOperationT<1, ExternConvertAnyOp> { bool is_nullable; - static constexpr OpEffects effects = OpEffects(); + // Cares about non-null values actually being non-null. We could eliminate + // the dependency on "checks" if we marked this as a trapping instruction + // when necessary. + static constexpr OpEffects effects = OpEffects().CanDependOnChecks(); explicit ExternConvertAnyOp(V<Object> object, bool is_nullable) : Base(object), is_nullable(is_nullable) {} @@ -8334,6 +8306,7 @@ struct ArrayGetOp : FixedArityOperationT<2, ArrayGetOp> { bool is_signed; const wasm::ArrayType* array_type; std::optional<AtomicMemoryOrder> memory_order; + SharedFlag shared_base; // Currently only used for TSAN. // ArrayGetOp may never trap as it is always protected by a length check. OpEffects Effects() const { @@ -8351,11 +8324,13 @@ struct ArrayGetOp : FixedArityOperationT<2, ArrayGetOp> { ArrayGetOp(V<WasmArrayNullable> array, V<Word32> index, const wasm::ArrayType* array_type, bool is_signed, - std::optional<AtomicMemoryOrder> memory_order) + std::optional<AtomicMemoryOrder> memory_order, + SharedFlag shared_base) : Base(array, index), is_signed(is_signed), array_type(array_type), - memory_order(memory_order) {} + memory_order(memory_order), + shared_base(shared_base) {} V<WasmArrayNullable> array() const { return input<WasmArrayNullable>(0); } V<Word32> index() const { return input<Word32>(1); } @@ -8371,7 +8346,7 @@ struct ArrayGetOp : FixedArityOperationT<2, ArrayGetOp> { } auto options() const { - return std::tuple{array_type, is_signed, memory_order}; + return std::tuple{array_type, is_signed, memory_order, shared_base}; } void PrintOptions(std::ostream& os) const; }; @@ -8379,8 +8354,9 @@ struct ArrayGetOp : FixedArityOperationT<2, ArrayGetOp> { struct ArraySetOp : FixedArityOperationT<3, ArraySetOp> { // Initialization has stricter OpEffects limiting e.g. the rescheduling of the // operation. - enum class Kind { kInitialize, kAssign }; + enum class Kind : bool { kInitialize, kAssign }; wasm::ValueType element_type; + SharedFlag is_shared; std::optional<AtomicMemoryOrder> memory_order; WriteBarrierKind write_barrier; Kind kind; @@ -8398,11 +8374,12 @@ struct ArraySetOp : FixedArityOperationT<3, ArraySetOp> { } ArraySetOp(V<WasmArrayNullable> array, V<Word32> index, V<Any> value, - wasm::ValueType element_type, + wasm::ValueType element_type, SharedFlag is_shared, std::optional<AtomicMemoryOrder> memory_order, WriteBarrierKind write_barrier, Kind kind) : Base(array, index, value), element_type(element_type), + is_shared(is_shared), memory_order(memory_order), write_barrier(write_barrier), kind(kind) {} @@ -8421,7 +8398,8 @@ struct ArraySetOp : FixedArityOperationT<3, ArraySetOp> { } auto options() const { - return std::tuple{element_type, memory_order, write_barrier, kind}; + return std::tuple{element_type, is_shared, memory_order, write_barrier, + kind}; } void PrintOptions(std::ostream& os) const; }; @@ -8429,8 +8407,9 @@ struct ArraySetOp : FixedArityOperationT<3, ArraySetOp> { struct ArrayAtomicRMWOp : OperationT<ArrayAtomicRMWOp> { using BinOp = AtomicRMWOp::BinOp; BinOp bin_op; - wasm::ValueType element_type; + SharedFlag is_shared; AtomicMemoryOrder memory_order; + wasm::ValueType element_type; OpEffects Effects() const { return OpEffects() @@ -8442,11 +8421,13 @@ struct ArrayAtomicRMWOp : OperationT<ArrayAtomicRMWOp> { ArrayAtomicRMWOp(V<WasmArrayNullable> array, V<Word32> index, OpIndex value, OptionalV<Any> expected, BinOp bin_op, - wasm::ValueType element_type, AtomicMemoryOrder memory_order) + wasm::ValueType element_type, SharedFlag is_shared, + AtomicMemoryOrder memory_order) : Base(3 + expected.valid()), bin_op(bin_op), - element_type(element_type), - memory_order(memory_order) { + is_shared(is_shared), + memory_order(memory_order), + element_type(element_type) { input(0) = array; input(1) = index; input(2) = value; @@ -8458,16 +8439,18 @@ struct ArrayAtomicRMWOp : OperationT<ArrayAtomicRMWOp> { template <typename Fn, typename Mapper> V8_INLINE auto Explode(Fn fn, Mapper& mapper) const { return fn(mapper.Map(array()), mapper.Map(index()), mapper.Map(value()), - mapper.Map(expected()), bin_op, element_type, memory_order); + mapper.Map(expected()), bin_op, element_type, is_shared, + memory_order); } static ArrayAtomicRMWOp& New(Graph* graph, V<WasmArrayNullable> array, V<Word32> index, OpIndex value, OptionalV<Any> expected, BinOp bin_op, wasm::ValueType element_type, + SharedFlag is_shared, AtomicMemoryOrder memory_order) { return Base::New(graph, 3 + expected.valid(), array, index, value, expected, - bin_op, element_type, memory_order); + bin_op, element_type, is_shared, memory_order); } V<WasmArrayNullable> array() const { return input<WasmArrayNullable>(0); } @@ -8502,12 +8485,13 @@ struct ArrayAtomicRMWOp : OperationT<ArrayAtomicRMWOp> { } auto options() const { - return std::tuple{bin_op, element_type, memory_order}; + return std::tuple{bin_op, element_type, is_shared, memory_order}; } }; struct ArrayLengthOp : OperationT<ArrayLengthOp> { CheckForNull null_check; + SharedFlag shared_base; // Currently only used for TSAN. OpEffects Effects() const { OpEffects result = @@ -8524,8 +8508,10 @@ struct ArrayLengthOp : OperationT<ArrayLengthOp> { explicit ArrayLengthOp(V<WasmArrayNullable> array, OptionalV<EagerFrameState> frame_state, - CheckForNull null_check) - : Base(1 + frame_state.valid()), null_check(null_check) { + CheckForNull null_check, SharedFlag shared_base) + : Base(1 + frame_state.valid()), + null_check(null_check), + shared_base(shared_base) { input(0) = array; if (frame_state.valid()) { input(1) = frame_state.value(); @@ -8549,17 +8535,18 @@ struct ArrayLengthOp : OperationT<ArrayLengthOp> { template <typename Fn, typename Mapper> V8_INLINE auto Explode(Fn fn, Mapper& mapper) const { - return fn(mapper.Map(array()), mapper.Map(frame_state()), null_check); + return fn(mapper.Map(array()), mapper.Map(frame_state()), null_check, + shared_base); } static ArrayLengthOp& New(Graph* graph, V<WasmArrayNullable> array, OptionalV<EagerFrameState> frame_state, - CheckForNull null_check) { + CheckForNull null_check, SharedFlag shared_base) { return Base::New(graph, 1 + frame_state.valid(), array, frame_state, - null_check); + null_check, shared_base); } - auto options() const { return std::tuple{null_check}; } + auto options() const { return std::tuple{null_check, shared_base}; } }; struct WasmAllocateArrayOp : FixedArityOperationT<2, WasmAllocateArrayOp> { @@ -8567,12 +8554,10 @@ struct WasmAllocateArrayOp : FixedArityOperationT<2, WasmAllocateArrayOp> { OpEffects().CanAllocate().CanDoRawHeapAccess().CanLeaveCurrentFunction(); const wasm::ArrayType* array_type; - SharedFlag is_shared; explicit WasmAllocateArrayOp(V<Map> rtt, V<Word32> length, - const wasm::ArrayType* array_type, - SharedFlag is_shared) - : Base(rtt, length), array_type(array_type), is_shared(is_shared) {} + const wasm::ArrayType* array_type) + : Base(rtt, length), array_type(array_type) {} V<Map> rtt() const { return Base::input<Map>(0); } V<Word32> length() const { return Base::input<Word32>(1); } @@ -8587,7 +8572,7 @@ struct WasmAllocateArrayOp : FixedArityOperationT<2, WasmAllocateArrayOp> { MaybeRegisterRepresentation::Word32()>(); } - auto options() const { return std::tuple{array_type, is_shared}; } + auto options() const { return std::tuple{array_type}; } void PrintOptions(std::ostream& os) const; }; @@ -9548,6 +9533,11 @@ struct Simd128ShiftOp : FixedArityOperationT<2, Simd128ShiftOp> { static constexpr OpEffects effects = OpEffects(); + static bool IsArithmeticShiftRight(Kind kind) { + return kind == any_of(Kind::kI8x16ShrS, Kind::kI16x8ShrS, Kind::kI32x4ShrS, + Kind::kI64x2ShrS); + } + static MachineRepresentation InputElementRep(Kind kind) { switch (kind) { default: @@ -9608,6 +9598,8 @@ struct Simd128ShiftOp : FixedArityOperationT<2, Simd128ShiftOp> { V<Simd128> input() const { return Base::input<Simd128>(0); } V<Word32> shift() const { return Base::input<Word32>(1); } + bool IsArithmeticShiftRight() const { return IsArithmeticShiftRight(kind); } + MachineRepresentation input_element_rep() const { return InputElementRep(kind); } @@ -11247,7 +11239,7 @@ constexpr size_t input_count(MemoryRepresentation) { return 0; } constexpr size_t input_count(OpEffects) { return 0; } constexpr size_t input_count(ExternalPointerTagRange) { return 0; } #if V8_ENABLE_SANDBOX -constexpr size_t input_count(IndirectPointerTagRange) { return 0; } +constexpr size_t input_count(TrustedPointerTagRange) { return 0; } #endif inline size_t input_count(const ElementsTransition) { return 0; } inline size_t input_count(const ElementsTransitionWithMultipleSources) { diff --git a/deps/v8/src/compiler/turboshaft/opmasks.h b/deps/v8/src/compiler/turboshaft/opmasks.h index 8a7a4cadb069..9d5dda1f9605 100644 --- a/deps/v8/src/compiler/turboshaft/opmasks.h +++ b/deps/v8/src/compiler/turboshaft/opmasks.h @@ -343,6 +343,7 @@ using Simd128BinopMask = MaskBuilder<Simd128BinopOp, FIELD(Simd128BinopOp, kind)>; using kSimd128I32x4Mul = Simd128BinopMask::For<Simd128BinopOp::Kind::kI32x4Mul>; using kSimd128I16x8Mul = Simd128BinopMask::For<Simd128BinopOp::Kind::kI16x8Mul>; +using kSimd128And = Simd128BinopMask::For<Simd128BinopOp::Kind::kS128And>; using kSimd128AndNot = Simd128BinopMask::For<Simd128BinopOp::Kind::kS128AndNot>; using kSimd128Xor = Simd128BinopMask::For<Simd128BinopOp::Kind::kS128Xor>; diff --git a/deps/v8/src/compiler/turboshaft/phase.h b/deps/v8/src/compiler/turboshaft/phase.h index fc75bebd082c..78316b76e635 100644 --- a/deps/v8/src/compiler/turboshaft/phase.h +++ b/deps/v8/src/compiler/turboshaft/phase.h @@ -83,12 +83,11 @@ struct HasProperRunMethod { }; template <typename Phase, typename... Args> -concept TurboshaftPhase = - HasProperRunMethod<Phase>::value && - requires(Phase p) { p.kKind == PhaseKind::kTurboshaft; }; +concept TurboshaftPhase = HasProperRunMethod<Phase>::value && + (Phase::kKind == PhaseKind::kTurboshaft); template <typename Phase> -concept TurbofanPhase = requires(Phase p) { p.kKind == PhaseKind::kTurbofan; }; +concept TurbofanPhase = (Phase::kKind == PhaseKind::kTurbofan); template <typename Phase> concept CompilerPhase = TurboshaftPhase<Phase> || TurbofanPhase<Phase>; diff --git a/deps/v8/src/compiler/turboshaft/pipelines.cc b/deps/v8/src/compiler/turboshaft/pipelines.cc index 3c773aeac12d..dfefd5348bc2 100644 --- a/deps/v8/src/compiler/turboshaft/pipelines.cc +++ b/deps/v8/src/compiler/turboshaft/pipelines.cc @@ -43,7 +43,7 @@ bool Pipeline::AllocateRegisters(const RegisterConfiguration* config, verifier_zone.reset( new Zone(allocator, kRegisterAllocatorVerifierZoneName)); verifier = verifier_zone->New<RegisterAllocatorVerifier>( - verifier_zone.get(), config, data()->sequence(), data()->frame()); + verifier_zone.get(), data()->sequence(), data()->frame()); } #ifdef DEBUG @@ -85,6 +85,21 @@ bool Pipeline::AllocateRegisters(const RegisterConfiguration* config, RUN_MAYBE_ABORT(DecideSpillingModePhase); RUN_MAYBE_ABORT(AssignSpillSlotsPhase); + + // The prologue grows the frame with a single stack pointer decrement, before + // the function entry stack check runs. A frame no larger than the smallest OS + // page cannot step over a guard page, so bail out rather than emit an + // unchecked stack pointer jump of arbitrary size. + // When replacing this bailout with a different strategy, consider doing the + // same in Maglev as well. + constexpr int kMaxStackSlots = 4 * KB / kSystemPointerSize; + if (data_->info()->IsOptimizing() && + data_->frame()->GetTotalFrameSlotCount() > kMaxStackSlots) { + data_->info()->AbortOptimization(BailoutReason::kFunctionTooBig); + data()->ClearRegisterComponent(); + return false; + } + RUN_MAYBE_ABORT(CommitAssignmentPhase); // TODO(chromium:725559): remove this check once diff --git a/deps/v8/src/compiler/turboshaft/pipelines.h b/deps/v8/src/compiler/turboshaft/pipelines.h index c20139a58fe5..7e8f7995ca86 100644 --- a/deps/v8/src/compiler/turboshaft/pipelines.h +++ b/deps/v8/src/compiler/turboshaft/pipelines.h @@ -470,6 +470,18 @@ class V8_EXPORT_PRIVATE Pipeline { data()->ClearInstructionComponent(); EndPhaseKind(); + + if (data()->broker() != nullptr) { + data()->broker()->DetachCanonicalHandles(info()); + if (!data()->code_generator()->has_background_code()) { + if (info()->bailout_reason() == BailoutReason::kNoReason) { + info()->AbortOptimization( + BailoutReason::kTurbofanCodeGenerationFailed); + } + return false; + } + } + return !info()->was_cancelled(); } diff --git a/deps/v8/src/compiler/turboshaft/register-allocation-phase.h b/deps/v8/src/compiler/turboshaft/register-allocation-phase.h index d81b7d563dee..09c7283dd0dd 100644 --- a/deps/v8/src/compiler/turboshaft/register-allocation-phase.h +++ b/deps/v8/src/compiler/turboshaft/register-allocation-phase.h @@ -217,6 +217,9 @@ struct AssembleCodePhase { CodeGenerator* code_generator = data->code_generator(); DCHECK_NOT_NULL(code_generator); code_generator->AssembleCode(); + if (data->broker() != nullptr) { + code_generator->PrepareCodeOnBackground(data->broker()->local_isolate()); + } } }; diff --git a/deps/v8/src/compiler/turboshaft/representations.cc b/deps/v8/src/compiler/turboshaft/representations.cc index 495af66dc704..c5d5ea97073e 100644 --- a/deps/v8/src/compiler/turboshaft/representations.cc +++ b/deps/v8/src/compiler/turboshaft/representations.cc @@ -68,8 +68,6 @@ std::ostream& operator<<(std::ostream& os, MemoryRepresentation rep) { return os << "UncompressedTaggedSigned"; case MemoryRepresentation::ProtectedPointer(): return os << "ProtectedPointer"; - case MemoryRepresentation::IndirectPointer(): - return os << "IndirectPointer"; case MemoryRepresentation::SandboxedPointer(): return os << "SandboxedPointer"; case MemoryRepresentation::TrustedPointer(): diff --git a/deps/v8/src/compiler/turboshaft/representations.h b/deps/v8/src/compiler/turboshaft/representations.h index a55d20e931e8..79642aefb2c0 100644 --- a/deps/v8/src/compiler/turboshaft/representations.h +++ b/deps/v8/src/compiler/turboshaft/representations.h @@ -5,6 +5,7 @@ #ifndef V8_COMPILER_TURBOSHAFT_REPRESENTATIONS_H_ #define V8_COMPILER_TURBOSHAFT_REPRESENTATIONS_H_ +#include <compare> #include <cstdint> #include "include/v8-internal.h" @@ -306,7 +307,7 @@ class RegisterRepresentation : public MaybeRegisterRepresentation { // Turboshaft does not support map packing. DCHECK(!V8_MAP_PACKING_BOOL); return RegisterRepresentation::Tagged(); - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kSandboxedPointer: // TODO(saelo/jkummerow): This is suspicious: after resolving the // indirection, we have a Tagged pointer. @@ -362,6 +363,10 @@ V8_INLINE constexpr bool operator!=(MaybeRegisterRepresentation a, MaybeRegisterRepresentation b) { return a.value() != b.value(); } +V8_INLINE constexpr auto operator<=>(MaybeRegisterRepresentation a, + MaybeRegisterRepresentation b) { + return a.value() <=> b.value(); +} V8_INLINE size_t hash_value(MaybeRegisterRepresentation rep) { return static_cast<size_t>(rep.value()); @@ -546,9 +551,8 @@ class MemoryRepresentation { kUncompressedTaggedPointer, kUncompressedTaggedSigned, kProtectedPointer, - kIndirectPointer, - kSandboxedPointer, kTrustedPointer, + kSandboxedPointer, kSimd128, kSimd256 }; @@ -625,15 +629,12 @@ class MemoryRepresentation { static constexpr MemoryRepresentation ProtectedPointer() { return MemoryRepresentation(Enum::kProtectedPointer); } - static constexpr MemoryRepresentation IndirectPointer() { - return MemoryRepresentation(Enum::kIndirectPointer); + static constexpr MemoryRepresentation TrustedPointer() { + return MemoryRepresentation(Enum::kTrustedPointer); } static constexpr MemoryRepresentation SandboxedPointer() { return MemoryRepresentation(Enum::kSandboxedPointer); } - static constexpr MemoryRepresentation TrustedPointer() { - return MemoryRepresentation(Enum::kTrustedPointer); - } static constexpr MemoryRepresentation Simd128() { return MemoryRepresentation(Enum::kSimd128); } @@ -663,9 +664,8 @@ class MemoryRepresentation { case UncompressedTaggedPointer(): case UncompressedTaggedSigned(): case ProtectedPointer(): - case IndirectPointer(): - case SandboxedPointer(): case TrustedPointer(): + case SandboxedPointer(): case Simd128(): case Simd256(): UNREACHABLE(); @@ -674,7 +674,7 @@ class MemoryRepresentation { } // This predicate is used in particular to decide which load/store ops - // have to deal with pointer compression. Indirect/sandboxed/trusted pointers, + // have to deal with pointer compression. Sandbox/trusted pointers, // while they resolve to tagged pointers, return {false} because they // use incompatible compression schemes. bool IsCompressibleTagged() const { @@ -697,10 +697,9 @@ class MemoryRepresentation { case AnyUncompressedTagged(): case UncompressedTaggedPointer(): case UncompressedTaggedSigned(): - case IndirectPointer(): + case TrustedPointer(): case ProtectedPointer(): case SandboxedPointer(): - case TrustedPointer(): case Simd128(): case Simd256(): return false; @@ -731,9 +730,8 @@ class MemoryRepresentation { case AnyUncompressedTagged(): case UncompressedTaggedPointer(): case UncompressedTaggedSigned(): - case IndirectPointer(): - case ProtectedPointer(): case TrustedPointer(): + case ProtectedPointer(): return RegisterRepresentation::Tagged(); case SandboxedPointer(): return RegisterRepresentation::Word64(); @@ -819,12 +817,10 @@ class MemoryRepresentation { return MachineType::TaggedSigned(); case ProtectedPointer(): return MachineType::ProtectedPointer(); - case IndirectPointer(): - return MachineType::IndirectPointer(); + case TrustedPointer(): + return MachineType::TrustedPointer(); case SandboxedPointer(): return MachineType::SandboxedPointer(); - case TrustedPointer(): - return MachineType::Uint32(); case Simd128(): return MachineType::Simd128(); case Simd256(): @@ -853,8 +849,8 @@ class MemoryRepresentation { return TaggedPointer(); case MachineRepresentation::kProtectedPointer: return ProtectedPointer(); - case MachineRepresentation::kIndirectPointer: - return IndirectPointer(); + case MachineRepresentation::kTrustedPointer: + return TrustedPointer(); case MachineRepresentation::kTagged: return AnyTagged(); case MachineRepresentation::kFloat16: @@ -914,7 +910,7 @@ class MemoryRepresentation { case MachineRepresentation::kCompressedPointer: case MachineRepresentation::kCompressed: case MachineRepresentation::kProtectedPointer: - case MachineRepresentation::kIndirectPointer: + case MachineRepresentation::kTrustedPointer: case MachineRepresentation::kFloat16RawBits: UNREACHABLE(); } @@ -937,7 +933,6 @@ class MemoryRepresentation { case Int32(): case Uint32(): case Float32(): - case IndirectPointer(): case TrustedPointer(): return 2; case Int64(): @@ -976,6 +971,10 @@ V8_INLINE constexpr bool operator!=(MemoryRepresentation a, MemoryRepresentation b) { return a.value() != b.value(); } +V8_INLINE constexpr auto operator<=>(MemoryRepresentation a, + MemoryRepresentation b) { + return a.value() <=> b.value(); +} V8_INLINE size_t hash_value(MemoryRepresentation rep) { return static_cast<size_t>(rep.value()); diff --git a/deps/v8/src/compiler/turboshaft/required-optimization-reducer.h b/deps/v8/src/compiler/turboshaft/required-optimization-reducer.h index 31bc03ca8b7f..db1ce6804581 100644 --- a/deps/v8/src/compiler/turboshaft/required-optimization-reducer.h +++ b/deps/v8/src/compiler/turboshaft/required-optimization-reducer.h @@ -31,7 +31,7 @@ class RequiredOptimizationReducer : public Next { RegisterRepresentation rep) { LABEL_BLOCK(no_change) { return Next::ReducePhi(inputs, rep); } DCHECK_GT(inputs.size(), 0); - OpIndex first = inputs.first(); + OpIndex first = inputs.front(); bool same_inputs = true; for (const OpIndex& input : inputs.SubVectorFrom(1)) { if (input != first) { diff --git a/deps/v8/src/compiler/turboshaft/runtime-call-descriptors.h b/deps/v8/src/compiler/turboshaft/runtime-call-descriptors.h index 735ee63e52e6..ddc5cb2c7b05 100644 --- a/deps/v8/src/compiler/turboshaft/runtime-call-descriptors.h +++ b/deps/v8/src/compiler/turboshaft/runtime-call-descriptors.h @@ -399,18 +399,6 @@ struct runtime : CallDescriptorBuilder { static constexpr Operator::Properties kProperties = Operator::kNoThrow; }; - struct NewClosure_Tenured : public Descriptor<NewClosure_Tenured> { - static constexpr auto kFunction = Runtime::kNewClosure_Tenured; - struct Arguments : ArgumentsBase { - ARG(V<SharedFunctionInfo>, shared_function_info) - ARG(V<FeedbackCell>, feedback_cell) - }; - using returns_t = V<JSFunction>; - - static constexpr bool kCanTriggerLazyDeopt = false; - static constexpr Operator::Properties kProperties = Operator::kNoThrow; - }; - struct HasInPrototypeChain : public Descriptor<HasInPrototypeChain> { static constexpr auto kFunction = Runtime::kHasInPrototypeChain; struct Arguments : ArgumentsBase { @@ -459,6 +447,21 @@ struct runtime : CallDescriptorBuilder { static constexpr bool kCanTriggerLazyDeopt = true; static constexpr Operator::Properties kProperties = Operator::kNoProperties; }; + +#if V8_ENABLE_WEBASSEMBLY + struct WasmExternConvertAny : public Descriptor<WasmExternConvertAny> { + static constexpr auto kFunction = Runtime::kWasmExternConvertAny; + struct Arguments : ArgumentsBase { + ARG(V<Object>, object) + }; + using returns_t = V<JSObject>; + + static constexpr bool kCanTriggerLazyDeopt = false; + static constexpr Operator::Properties kProperties = Operator::kEliminatable; + static constexpr OpEffects kEffects = + OpEffects().CanAllocate().CanReadHeapMemory().CanWriteHeapMemory(); + }; +#endif // V8_ENABLE_WEBASSEMBLY }; } // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/src/compiler/turboshaft/snapshot-table.h b/deps/v8/src/compiler/turboshaft/snapshot-table.h index 3ecc442b358c..4044e4ea4360 100644 --- a/deps/v8/src/compiler/turboshaft/snapshot-table.h +++ b/deps/v8/src/compiler/turboshaft/snapshot-table.h @@ -436,7 +436,7 @@ SnapshotTable<Value, KeyData>::MoveToNewSnapshot( if (predecessors.empty()) { common_ancestor = root_snapshot_; } else { - common_ancestor = predecessors.first().data_; + common_ancestor = predecessors.front().data_; for (Snapshot s : predecessors.SubVectorFrom(1)) { common_ancestor = common_ancestor->CommonAncestor(s.data_); } diff --git a/deps/v8/src/compiler/turboshaft/stack-check-lowering-reducer.h b/deps/v8/src/compiler/turboshaft/stack-check-lowering-reducer.h index 1d600186da4c..7d576dc225df 100644 --- a/deps/v8/src/compiler/turboshaft/stack-check-lowering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/stack-check-lowering-reducer.h @@ -39,8 +39,7 @@ class StackCheckLoweringReducer : public Next { // Loads of the stack limit should not be load-eliminated as it can be // modified by another thread. V<WordPtr> limit = - __ Load(__ ExternalConstant( - ExternalReference::address_of_jslimit(isolate())), + __ Load(__ IsolateField(IsolateFieldId::kJsLimit), LoadOp::Kind::RawAligned().NotLoadEliminable(), MemoryRepresentation::UintPtr()); @@ -53,10 +52,9 @@ class StackCheckLoweringReducer : public Next { break; } case JSStackCheckOp::Kind::kBuiltinEntry: { - V<WordPtr> stack_limit = __ LoadOffHeap( - __ ExternalConstant( - ExternalReference::address_of_jslimit(isolate())), - MemoryRepresentation::UintPtr()); + V<WordPtr> stack_limit = + __ LoadOffHeap(__ IsolateField(IsolateFieldId::kJsLimit), + MemoryRepresentation::UintPtr()); IF_NOT (LIKELY(__ StackPointerGreaterThan( stack_limit, StackCheckKind::kCodeStubAssembler))) { __ template CallRuntime<runtime::StackGuard>(context, {}); @@ -65,9 +63,7 @@ class StackCheckLoweringReducer : public Next { } case JSStackCheckOp::Kind::kLoop: { V<Word32> limit = __ Load( - __ ExternalConstant( - ExternalReference::address_of_no_heap_write_interrupt_request( - isolate())), + __ IsolateField(IsolateFieldId::kNoHeapWriteInterruptRequest), LoadOp::Kind::RawAligned().NotLoadEliminable(), MemoryRepresentation::Uint8()); @@ -83,9 +79,7 @@ class StackCheckLoweringReducer : public Next { } #ifdef V8_ENABLE_WEBASSEMBLY - V<None> REDUCE(WasmStackCheck)( - OptionalV<WasmTrustedInstanceData> trusted_instance_data, - WasmStackCheckOp::Kind kind) { + V<None> REDUCE(WasmStackCheck)(WasmStackCheckOp::Kind kind) { if (kind == WasmStackCheckOp::Kind::kFunctionEntry) { // As an optimization, skip stack checks in leaf functions. Rely on // their callers checking the stack height instead. @@ -112,7 +106,7 @@ class StackCheckLoweringReducer : public Next { if (v8_flags.wasm_growable_stacks) { // WasmStackCheck should be lowered by GrowableStacksReducer // in a special way. - return Next::ReduceWasmStackCheck(trusted_instance_data, kind); + return Next::ReduceWasmStackCheck(kind); } const CallDescriptor* entry_call_descriptor = @@ -130,9 +124,9 @@ class StackCheckLoweringReducer : public Next { // Loads of the stack limit should not be load-eliminated as it can be // modified by another thread. - V<WordPtr> limit = __ Load( - __ LoadRootRegister(), LoadOp::Kind::RawAligned().NotLoadEliminable(), - MemoryRepresentation::UintPtr(), IsolateData::jslimit_offset()); + V<WordPtr> limit = __ Load(__ IsolateField(IsolateFieldId::kJsLimit), + LoadOp::Kind::RawAligned().NotLoadEliminable(), + MemoryRepresentation::UintPtr()); IF_NOT (LIKELY( __ StackPointerGreaterThan(limit, StackCheckKind::kWasm))) { V<WordPtr> gap = @@ -159,10 +153,10 @@ class StackCheckLoweringReducer : public Next { loop_call_descriptor, compiler::CanThrow{false}, LazyDeoptOnThrow{false}, __ graph_zone()); - V<Word32> limit = __ Load( - __ LoadRootRegister(), LoadOp::Kind::RawAligned().NotLoadEliminable(), - MemoryRepresentation::Uint8(), - IsolateData::no_heap_write_interrupt_request_offset()); + V<Word32> limit = + __ Load(__ IsolateField(IsolateFieldId::kNoHeapWriteInterruptRequest), + LoadOp::Kind::RawAligned().NotLoadEliminable(), + MemoryRepresentation::Uint8()); IF_NOT (LIKELY(__ Word32Equal(limit, 0))) { V<WordPtr> target = @@ -172,14 +166,6 @@ class StackCheckLoweringReducer : public Next { return V<None>::Invalid(); } #endif // V8_ENABLE_WEBASSEMBLY - - private: - Isolate* isolate() { - if (!isolate_) isolate_ = __ data() -> isolate(); - return isolate_; - } - - Isolate* isolate_ = nullptr; }; #include "src/compiler/turboshaft/undef-assembler-macros.inc" diff --git a/deps/v8/src/compiler/turboshaft/turbolev-frontend-pipeline.cc b/deps/v8/src/compiler/turboshaft/turbolev-frontend-pipeline.cc index e79cbab4e435..ac6beb247020 100644 --- a/deps/v8/src/compiler/turboshaft/turbolev-frontend-pipeline.cc +++ b/deps/v8/src/compiler/turboshaft/turbolev-frontend-pipeline.cc @@ -400,6 +400,8 @@ auto TurbolevFrontendPipeline::Run(Args&&... args) { #endif Phase phase; SYNCHRONIZATION_POINT(Phase::synchronization_point_name()); + // Covers phases that don't go through maglev::GraphProcessor. + graph_->broker()->local_isolate_or_isolate()->heap()->Safepoint(); PhaseResult result = phase.Run(graph_, std::forward<Args>(args)...); if (result == PhaseResult::kContinue) { if (V8_UNLIKELY(ShouldPrintMaglevGraph(Phase::phase))) { diff --git a/deps/v8/src/compiler/turboshaft/turbolev-graph-builder.cc b/deps/v8/src/compiler/turboshaft/turbolev-graph-builder.cc index a6e00c86105e..811af262cddd 100644 --- a/deps/v8/src/compiler/turboshaft/turbolev-graph-builder.cc +++ b/deps/v8/src/compiler/turboshaft/turbolev-graph-builder.cc @@ -1217,9 +1217,8 @@ class GraphBuildingNodeProcessor { } maglev::ProcessResult Process(maglev::TaggedIndexConstant* node, const maglev::ProcessingState& state) { - // TODO(dmercadier): should this really be a SmiConstant, or rather a - // Word32Constant? - SetMap(node, __ SmiConstant(i::Tagged<Smi>(node->value().ptr()))); + SetMap(node, + __ TaggedIndexConstant(static_cast<int32_t>(node->value().value()))); return maglev::ProcessResult::kContinue; } maglev::ProcessResult Process(maglev::TrustedConstant* node, @@ -1609,7 +1608,7 @@ class GraphBuildingNodeProcessor { graph_zone(), false, std::max<int>(actual_parameter_count, node->expected_parameter_count()), - CallDescriptor::kNeedsFrameState | CallDescriptor::kCanUseRoots); + node->expected_parameter_count(), CallDescriptor::kNeedsFrameState); LazyDeoptOnThrow lazy_deopt_on_throw = ShouldLazyDeoptOnThrow(node); @@ -2012,16 +2011,9 @@ class GraphBuildingNodeProcessor { V<FeedbackCell> feedback_cell = __ HeapConstant(node->feedback_cell().object()); - V<JSFunction> closure; - if (node->pretenured()) { - closure = __ template CallRuntime<runtime::NewClosure_Tenured>( - context, {.shared_function_info = shared_function_info, - .feedback_cell = feedback_cell}); - } else { - closure = __ template CallRuntime<runtime::NewClosure>( - context, {.shared_function_info = shared_function_info, - .feedback_cell = feedback_cell}); - } + V<JSFunction> closure = __ template CallRuntime<runtime::NewClosure>( + context, {.shared_function_info = shared_function_info, + .feedback_cell = feedback_cell}); SetMap(node, closure); @@ -2109,7 +2101,7 @@ class GraphBuildingNodeProcessor { arguments.push_back(Map(node->NewTargetInput())); arguments.push_back(__ Word32Constant(node->num_args())); -#ifndef V8_TARGET_ARCH_ARM64 +#if !defined(V8_TARGET_ARCH_ARM64) && !V8_X64_16BYTE_STACK_ALIGNMENT_BOOL arguments.push_back(__ WordPtrConstant(node->feedback().index())); arguments.push_back(__ HeapConstant(node->feedback().vector)); #endif @@ -2120,16 +2112,17 @@ class GraphBuildingNodeProcessor { arguments.push_back(Map(node->ContextInput())); -#ifndef V8_TARGET_ARCH_ARM64 - // Construct_WithFeedback can't be called from Turbofan on Arm64, because of - // the stack alignment requirements: the feedback vector is dropped by - // Construct_WithFeedback while the other arguments are passed through to - // Construct. As a result, when the feedback vector is pushed on the stack, - // it should be padded to 16-bytes, but there is no way to express this in - // Turbofan. +#if !defined(V8_TARGET_ARCH_ARM64) && !V8_X64_16BYTE_STACK_ALIGNMENT_BOOL + // Construct_WithFeedback can't be called from Turboshaft when stack + // alignment is enforced, because of the stack alignment requirements: + // the feedback vector is dropped by Construct_WithFeedback while the other + // arguments are passed through to Construct. As a result, when the feedback + // vector is pushed on the stack, it should be padded to 16-bytes, but there + // is no way to express this in Turboshaft. // Anyways, long-term we'll want to feedback-specialize Construct in the // frontend (ie, probably in Maglev), so we don't really need to adapt - // Turbofan to be able to call Construct_WithFeedback on Arm64. + // Turboshaft to be able to call Construct_WithFeedback when stack alignment + // is enforced. static constexpr int kFeedbackVector = 1; int stack_arg_count = node->num_args() + kFeedbackVector; Builtin builtin = Builtin::kConstruct_WithFeedback; @@ -3645,8 +3638,8 @@ class GraphBuildingNodeProcessor { const maglev::ProcessingState& state) { __ Store(Map(node->ObjectInput()), Map(node->ValueInput()), StoreOp::Kind::TaggedBase(), - MemoryRepresentation::IndirectPointer(), - WriteBarrierKind::kIndirectPointerWriteBarrier, node->offset(), + MemoryRepresentation::TrustedPointer(), + WriteBarrierKind::kTrustedPointerWriteBarrier, node->offset(), node->initializing_or_transitioning(), node->tag()); return maglev::ProcessResult::kContinue; } @@ -4352,6 +4345,14 @@ class GraphBuildingNodeProcessor { return maglev::ProcessResult::kContinue; } + maglev::ProcessResult Process(maglev::BranchIfInt32BitwiseAndNonZero* node, + const maglev::ProcessingState& state) { + V<Word32> masked = + __ Word32BitwiseAnd(Map(node->ValueInput()), node->mask()); + __ Branch(masked, Map(node->if_true()), Map(node->if_false())); + return maglev::ProcessResult::kContinue; + } + maglev::ProcessResult Process(maglev::BranchIfIntPtrToBooleanTrue* node, const maglev::ProcessingState& state) { V<Word32> condition = @@ -5702,8 +5703,8 @@ class GraphBuildingNodeProcessor { maglev::ProcessResult Process(maglev::SetPendingMessage* node, const maglev::ProcessingState& state) { - V<WordPtr> message_address = __ ExternalConstant( - ExternalReference::address_of_pending_message(isolate_)); + V<WordPtr> message_address = + __ IsolateField(IsolateFieldId::kPendingMessage); V<Object> old_message = __ LoadMessage(message_address); __ StoreMessage(message_address, Map(node->ValueInput())); SetMap(node, old_message); @@ -6374,8 +6375,7 @@ class GraphBuildingNodeProcessor { case maglev::vobj::FieldType::kTrustedPointer: case maglev::vobj::FieldType::kFloat64: case maglev::vobj::FieldType::kInt32: - AddVirtualObjectNestedValue(builder, virtual_objects, vobj, - value_node); + AddVirtualObjectNestedValue(builder, virtual_objects, value_node); break; case maglev::vobj::FieldType::kNone: UNREACHABLE(); @@ -6387,7 +6387,7 @@ class GraphBuildingNodeProcessor { void AddVirtualObjectNestedValue( FrameStateData::Builder& builder, const maglev::VirtualObjectList& virtual_objects, - const maglev::VirtualObject* vobj, const maglev::ValueNode* value) { + const maglev::ValueNode* value) { if (maglev::IsConstantNode(value->opcode())) { switch (value->opcode()) { case maglev::Opcode::kHeapConstant: @@ -6398,29 +6398,17 @@ class GraphBuildingNodeProcessor { break; case maglev::Opcode::kFloat64Constant: - case maglev::Opcode::kHoleyFloat64Constant: { - i::Float64 value_as_float = - value->opcode() == maglev::Opcode::kFloat64Constant - ? value->Cast<maglev::Float64Constant>()->value() - : value->Cast<maglev::HoleyFloat64Constant>()->value(); - DCHECK(vobj->has_static_map()); - const bool is_fixed_double_array = - vobj->map()->IsFixedDoubleArrayMap(); - if (is_fixed_double_array && value_as_float.is_hole_nan()) { - builder.AddInput( - MachineType::AnyTagged(), - __ HeapConstantHole(local_factory_->the_hole_value())); -#ifdef V8_ENABLE_UNDEFINED_DOUBLE - } else if (is_fixed_double_array && - value_as_float.is_undefined_nan()) { - builder.AddInput(MachineType::AnyTagged(), undefined_value_); -#endif // V8_ENABLE_UNDEFINED_DOUBLE - } else { - builder.AddInput(MachineType::AnyTagged(), - __ NumberConstant(value_as_float)); - } + builder.AddInput( + MachineType::Float64(), + __ Float64Constant( + value->Cast<maglev::Float64Constant>()->value())); + break; + case maglev::Opcode::kHoleyFloat64Constant: + builder.AddInput( + MachineType::HoleyFloat64(), + __ Float64Constant( + value->Cast<maglev::HoleyFloat64Constant>()->value())); break; - } case maglev::Opcode::kInt32Constant: builder.AddInput( MachineType::AnyTagged(), @@ -6591,16 +6579,13 @@ class GraphBuildingNodeProcessor { FrameStateType type = maglev_frame.is_javascript() ? FrameStateType::kJavaScriptBuiltinContinuation : FrameStateType::kBuiltinContinuation; + DCHECK_IMPLIES( + maglev_frame.is_javascript(), + Builtins::CallInterfaceDescriptorFor(maglev_frame.builtin_id()) + .GetRegisterParameterCount() == + JSTrampolineDescriptor::GetRegisterParameterCount()); uint16_t parameter_count = - static_cast<uint16_t>(maglev_frame.parameters().length()); - if (maglev_frame.is_javascript()) { - constexpr int kExtraFixedJSFrameParameters = - V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL ? 4 : 3; - DCHECK_EQ(Builtins::CallInterfaceDescriptorFor(maglev_frame.builtin_id()) - .GetRegisterParameterCount(), - kExtraFixedJSFrameParameters); - parameter_count += kExtraFixedJSFrameParameters; - } + static_cast<uint16_t>(maglev_frame.translation_height()); Handle<SharedFunctionInfo> shared_info = GetSharedFunctionInfo(maglev_frame).object(); constexpr int kLocalCount = 0; diff --git a/deps/v8/src/compiler/turboshaft/typer.h b/deps/v8/src/compiler/turboshaft/typer.h index e83c0562c815..5047ca1aa1ff 100644 --- a/deps/v8/src/compiler/turboshaft/typer.h +++ b/deps/v8/src/compiler/turboshaft/typer.h @@ -424,9 +424,6 @@ struct FloatOperationTyper { static type_t Set(std::vector<float_t> elements, uint32_t special_values, Zone* zone) { - base::sort(elements); - elements.erase(std::unique(elements.begin(), elements.end()), - elements.end()); if (base::erase_if(elements, [](float_t v) { return std::isnan(v); }) > 0) { special_values |= type_t::kNaN; } @@ -434,10 +431,16 @@ struct FloatOperationTyper { 0) { special_values |= type_t::kMinusZero; } + base::sort(elements); + elements.erase(std::unique(elements.begin(), elements.end()), + elements.end()); if (elements.empty()) { DCHECK_NE(0, special_values); return type_t::OnlySpecialValues(special_values); } + if (elements.size() > type_t::kMaxSetSize) { + return Range(elements.front(), elements.back(), special_values, zone); + } return type_t::Set(elements, special_values, zone); } diff --git a/deps/v8/src/compiler/turboshaft/types.cc b/deps/v8/src/compiler/turboshaft/types.cc index 92af7a7d1c79..8e9e1977220b 100644 --- a/deps/v8/src/compiler/turboshaft/types.cc +++ b/deps/v8/src/compiler/turboshaft/types.cc @@ -260,7 +260,7 @@ WordType<Bits> LeastUpperBoundFromRanges(word_t l_from, word_t l_to, const auto to = std::max(l_to, r_to); if (to >= from) return WordType<Bits>::Any(); auto result = WordType<Bits>::Range(from, to, zone); - DCHECK(result.is_wrapping()); + DCHECK_IMPLIES(result.is_range(), result.is_wrapping()); return result; } @@ -279,7 +279,7 @@ WordType<Bits> LeastUpperBoundFromRanges(word_t l_from, word_t l_to, } if (r_to >= l_from) return WordType<Bits>::Any(); // ex3 auto result = WordType<Bits>::Range(l_from, r_to, zone); // ex 1 - DCHECK(result.is_wrapping()); + DCHECK_IMPLIES(result.is_range(), result.is_wrapping()); return result; } else if (r_to >= l_from) { if (r_from >= l_from) { @@ -287,7 +287,7 @@ WordType<Bits> LeastUpperBoundFromRanges(word_t l_from, word_t l_to, } DCHECK_GT(r_from, l_to); // handled above auto result = WordType<Bits>::Range(r_from, l_to, zone); // ex 2 - DCHECK(result.is_wrapping()); + DCHECK_IMPLIES(result.is_range(), result.is_wrapping()); return result; } else { const auto df = r_from - l_to; @@ -295,7 +295,7 @@ WordType<Bits> LeastUpperBoundFromRanges(word_t l_from, word_t l_to, WordType<Bits> result = df > dt ? WordType<Bits>::Range(r_from, l_to, zone) // ex 4 : WordType<Bits>::Range(l_from, r_to, zone); - DCHECK(result.is_wrapping()); + DCHECK_IMPLIES(result.is_range(), result.is_wrapping()); return result; } } @@ -381,11 +381,68 @@ Type WordType<Bits>::Intersect(const WordType<Bits>& lhs, } if (lhs_wrapping && rhs.is_wrapping()) { - const auto result_from = std::max(lhs.range_from(), rhs.range_from()); - const auto result_to = std::min(lhs.range_to(), rhs.range_to()); - auto result = WordType::Range(result_from, result_to, zone); - DCHECK(result.is_wrapping()); - return result; + // Intersection of wrapping ranges: + // Case 1: + // lhs: |-------| |-------------| + // lhs_to lhs_from + // + // rhs: |------------| |--------| + // rhs_to rhs_from + // + // res: |-------| |--------| + if (lhs.range_to() < rhs.range_from() && + rhs.range_to() < lhs.range_from()) { + const auto result_from = std::max(lhs.range_from(), rhs.range_from()); + const auto result_to = std::min(lhs.range_to(), rhs.range_to()); + auto result = WordType::Range(result_from, result_to, zone); + // The result might be optimized to be a Set instead of Range, if it has + // only a few elements. But if it's Range, then it's a wrapping range. + DCHECK_IMPLIES(result.is_range(), result.is_wrapping()); + return result; + } + + // Case 2: + // lhs: |-------------| |-------| + // lhs_to lhs_from + // + // rhs: |----| |-------------------| + // rhs_to rhs_from + // + // res: |----| |-| |-------| + // (not reprensentable as a wrapped range) + // + // Case 3: + // lhs: |----| |----------------| + // lhs_to lhs_from + // + // rhs: |------------------| |-----| + // rhs_to rhs_from + // + // res: |----| |---| |-----| + // (not reprensentable as a wrapped range) + + switch (resolution_mode) { + case ResolutionMode::kPreciseOrInvalid: + return Type::Invalid(); + case ResolutionMode::kOverApproximate: { + // Both lhs and rhs are valid overapproximations. Pick the smaller one. + const word_t lhs_size = + (std::numeric_limits<word_t>::max() - lhs.range_from() + 1) + + (lhs.range_to() + 1); + const word_t rhs_size = + (std::numeric_limits<word_t>::max() - rhs.range_from() + 1) + + (rhs.range_to() + 1); + if (lhs_size < rhs_size) return lhs; + if (rhs_size < lhs_size) return rhs; + return lhs.range_from() <= rhs.range_from() ? lhs : rhs; + } + case ResolutionMode::kGreatestLowerBound: + // The wrapping part [0, min(to1, to2)] U [max(from1, from2), max] is a + // valid maximal representable lower bound (under-approximation). + return WordType::Range(std::max(lhs.range_from(), rhs.range_from()), + std::min(lhs.range_to(), rhs.range_to()), zone); + } + UNREACHABLE(); } const auto& x = lhs_wrapping ? lhs : rhs; diff --git a/deps/v8/src/compiler/turboshaft/undef-assembler-macros.inc b/deps/v8/src/compiler/turboshaft/undef-assembler-macros.inc index 0704f08b6491..ff6acb455462 100644 --- a/deps/v8/src/compiler/turboshaft/undef-assembler-macros.inc +++ b/deps/v8/src/compiler/turboshaft/undef-assembler-macros.inc @@ -36,6 +36,7 @@ #undef REDUCE #undef REDUCE_INPUT_GRAPH #undef TSA_DCHECK +#undef TSA_SLOW_DCHECK #undef TYPESWITCH #undef UNLIKELY #undef WHILE diff --git a/deps/v8/src/compiler/turboshaft/use-map.cc b/deps/v8/src/compiler/turboshaft/use-map.cc index 08806fa36ce3..599033c58d2d 100644 --- a/deps/v8/src/compiler/turboshaft/use-map.cc +++ b/deps/v8/src/compiler/turboshaft/use-map.cc @@ -24,6 +24,12 @@ UseMap::UseMap(const Graph& graph, Zone* zone, FunctionType filter) auto block_ops = graph.OperationIndices(block); for (OpIndex op_index : block_ops) { const Operation& op = graph.Get(op_index); + // MakeTupleOp is a synthetic meta-operation that cannot have uses and is + // excluded from saturated_use_count (see Graph::IncrementInputUses). Skip + // it completely so UseMap neither allocates table entries for it nor + // records its inputs as used. + if (op.Is<MakeTupleOp>()) continue; + // When we see a definition, we allocate space in the {uses_}. DCHECK_EQ(table_[op_index].offset, 0); DCHECK_EQ(table_[op_index].count, 0); diff --git a/deps/v8/src/compiler/turboshaft/use-map.h b/deps/v8/src/compiler/turboshaft/use-map.h index aafc242543da..f3b0b8e60ce1 100644 --- a/deps/v8/src/compiler/turboshaft/use-map.h +++ b/deps/v8/src/compiler/turboshaft/use-map.h @@ -15,7 +15,7 @@ typedef bool (*FunctionType)(const Graph& graph, const Operation& op, // UseMap computes uses of all operations of the given turboshaft graph. It // provides a mapping from `OpIndex` to its `uses`. -class UseMap { +class V8_EXPORT_PRIVATE UseMap { struct PerOperationUses { // We encode offsets as follows: // offset < 0: -offset-1 indexes into {saturated_uses_}. @@ -60,11 +60,10 @@ class Simd128UseMap : public UseMap, public NON_EXPORTED_BASE(ZoneObject) { if (has_revectorizable_simd128_output(op)) return false; - // Identify input_reps of ReturnOp, FrameStateOp and MakeTupleOp - // (which doesn't track inputs_rep, except for the Word32 popcount - // input of ReturnOp). - if (op.TryCast<ReturnOp>() || op.TryCast<FrameStateOp>() || - op.TryCast<MakeTupleOp>()) { + // Identify input_reps of ReturnOp and FrameStateOp (which don't + // track inputs_rep, except for the Word32 popcount input of + // ReturnOp). + if (op.TryCast<ReturnOp>() || op.TryCast<FrameStateOp>()) { for (auto input : op.inputs()) { const Operation& input_op = graph.Get(input); if (has_revectorizable_simd128_output(input_op)) return false; diff --git a/deps/v8/src/compiler/turboshaft/value-numbering-reducer.h b/deps/v8/src/compiler/turboshaft/value-numbering-reducer.h index ec4ba4ae6f26..698efa9271ac 100644 --- a/deps/v8/src/compiler/turboshaft/value-numbering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/value-numbering-reducer.h @@ -5,6 +5,7 @@ #ifndef V8_COMPILER_TURBOSHAFT_VALUE_NUMBERING_REDUCER_H_ #define V8_COMPILER_TURBOSHAFT_VALUE_NUMBERING_REDUCER_H_ +#include <bit> #include <iostream> #include <limits> @@ -484,8 +485,8 @@ class ValueNumberingReducer : public Next { bool is_disabled() { return disabled_scope_.is_active(); } ZoneVector<Block*> dominator_path_{Asm().phase_zone()}; - base::Vector<Entry> table_ = Asm().phase_zone()->template NewVector<Entry>( - base::bits::RoundUpToPowerOfTwo( + base::Vector<Entry> table_ = + Asm().phase_zone()->template NewVector<Entry>(std::bit_ceil( std::max<size_t>(128, Asm().input_graph().op_id_capacity() / 2))); size_t mask_ = table_.size() - 1; size_t entry_count_ = 0; diff --git a/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.cc b/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.cc index 81f9b29529ce..521989c65bea 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.cc @@ -146,17 +146,16 @@ void WasmGCTypeAnalyzer::StartNewSnapshotFor(const Block& block) { const Block& predecessor = *block.LastPredecessor(); types_table_.StartNewSnapshot( block_to_snapshot_[predecessor.index()].value()); - if (IsReachable(predecessor)) { - const BranchOp* branch = - block.Predecessors()[0]->LastOperation(graph_).TryCast<BranchOp>(); - if (branch != nullptr) { - ProcessBranchOnTarget(*branch, block); - } - } else { + if (!IsReachable(predecessor)) { TRACE("[b%uu] Block unreachable as sole predecessor b%u is unreachable\n", block.index().id(), predecessor.index().id()); block_is_unreachable_.Add(block.index().id()); } + const BranchOp* branch = + block.Predecessors()[0]->LastOperation(graph_).TryCast<BranchOp>(); + if (branch != nullptr) { + ProcessBranchOnTarget(*branch, block); + } } else { DCHECK_EQ(block.kind(), Block::Kind::kMerge); CreateMergeSnapshot(block); @@ -197,12 +196,18 @@ void WasmGCTypeAnalyzer::ProcessOperations(const Block& block) { case Opcode::kStructSet: ProcessStructSet(op.Cast<StructSetOp>()); break; + case Opcode::kStructAtomicRMW: + ProcessStructAtomicRMW(op.Cast<StructAtomicRMWOp>()); + break; case Opcode::kArrayGet: ProcessArrayGet(op.Cast<ArrayGetOp>()); break; case Opcode::kArrayLength: ProcessArrayLength(op.Cast<ArrayLengthOp>()); break; + case Opcode::kArrayAtomicRMW: + ProcessArrayAtomicRMW(op.Cast<ArrayAtomicRMWOp>()); + break; case Opcode::kGlobalGet: ProcessGlobalGet(op.Cast<GlobalGetOp>()); break; @@ -324,7 +329,9 @@ void WasmGCTypeAnalyzer::ProcessStructGet(const StructGetOp& struct_get) { if (type.is_none_or_bottom()) { // Subsumption dictates that get_desc(none) <: get_desc(exact $s). exactness = wasm::kExact; - } else if (type.has_index() && type.ref_index() != struct_get.type_index) { + } else if (type.has_index() && + !wasm::EquivalentIndices(type.ref_index(), struct_get.type_index, + module_)) { exactness = wasm::kAnySubtype; } new_type = wasm::ValueType::Ref(module_->heap_type(type_def.descriptor)) @@ -343,6 +350,23 @@ void WasmGCTypeAnalyzer::ProcessStructSet(const StructSetOp& struct_set) { input_type_map_[graph_.Index(struct_set)] = type; } +void WasmGCTypeAnalyzer::ProcessStructAtomicRMW( + const StructAtomicRMWOp& struct_atomic_rmw) { + // Struct atomic-rmw operations perform a null check. + wasm::ValueType type = + RefineTypeKnowledgeNotNull(struct_atomic_rmw.object(), struct_atomic_rmw); + input_type_map_[graph_.Index(struct_atomic_rmw)] = type; + wasm::ValueType new_type; + if (type.is_uninhabited()) { + new_type = wasm::kWasmBottom; + } else { + new_type = + struct_atomic_rmw.type->field(struct_atomic_rmw.field_index).Unpacked(); + } + RefineTypeKnowledge(graph_.Index(struct_atomic_rmw), new_type, + struct_atomic_rmw); +} + void WasmGCTypeAnalyzer::ProcessArrayGet(const ArrayGetOp& array_get) { // array.get traps on null. (Typically already on the array length access // needed for the bounds check.) @@ -360,6 +384,17 @@ void WasmGCTypeAnalyzer::ProcessArrayLength(const ArrayLengthOp& array_length) { input_type_map_[graph_.Index(array_length)] = type; } +void WasmGCTypeAnalyzer::ProcessArrayAtomicRMW( + const ArrayAtomicRMWOp& array_atomic_rmw) { + // Array atomic-rmw operations trap on null. (Typically already on the array + // length access needed for the bounds check.) + RefineTypeKnowledgeNotNull(array_atomic_rmw.array(), array_atomic_rmw); + // The result type is at least the static array element type. + RefineTypeKnowledge(graph_.Index(array_atomic_rmw), + array_atomic_rmw.element_type.Unpacked(), + array_atomic_rmw); +} + void WasmGCTypeAnalyzer::ProcessGlobalGet(const GlobalGetOp& global_get) { RefineTypeKnowledge(graph_.Index(global_get), global_get.global->type, global_get); @@ -399,19 +434,23 @@ void WasmGCTypeAnalyzer::ProcessAllocateStruct( wasm::ValueType WasmGCTypeAnalyzer::GetTypeForPhiInput(const PhiOp& phi, int input_index) { OpIndex phi_id = graph_.Index(phi); - OpIndex input = ResolveAliases(phi.input(input_index)); - // If the input of the phi is in the same block as the phi and appears - // before the phi, don't use the predecessor value. - - if (current_block_->begin().id() <= input.id() && input.id() < phi_id.id()) { + OpIndex raw_input = phi.input(input_index); + // If the un-aliased input of the phi is in the same block as the phi and + // appears before the phi, don't use the predecessor value. Note that we must + // check the un-aliased input, as resolving aliases first could incorrectly + // map a backedge input (e.g. a cast in the loop body) to an operation in the + // loop header. + if (current_block_->begin().id() <= raw_input.id() && + raw_input.id() < phi_id.id()) { // Phi instructions have to be at the beginning of the block, so this can // only happen for inputs that are also phis. Furthermore, this is only // possible in loop headers of loops and only for the backedge-input. - DCHECK(graph_.Get(input).Is<PhiOp>()); + DCHECK(graph_.Get(raw_input).Is<PhiOp>()); DCHECK(current_block_->IsLoop()); DCHECK_EQ(input_index, 1); - return types_table_.Get(input); + return types_table_.Get(raw_input); } + OpIndex input = ResolveAliases(raw_input); return types_table_.GetPredecessorValue(input, input_index); } diff --git a/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.h b/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.h index 2d11e907afc5..a18b66e52521 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.h +++ b/deps/v8/src/compiler/turboshaft/wasm-gc-typed-optimization-reducer.h @@ -87,8 +87,10 @@ class WasmGCTypeAnalyzer { void ProcessParameter(const ParameterOp& parameter); void ProcessStructGet(const StructGetOp& struct_get); void ProcessStructSet(const StructSetOp& struct_set); + void ProcessStructAtomicRMW(const StructAtomicRMWOp& struct_atomic_rmw); void ProcessArrayGet(const ArrayGetOp& array_get); void ProcessArrayLength(const ArrayLengthOp& array_length); + void ProcessArrayAtomicRMW(const ArrayAtomicRMWOp& array_atomic_rmw); void ProcessGlobalGet(const GlobalGetOp& global_get); void ProcessRefFunc(const WasmRefFuncOp& ref_func); void ProcessAllocateArray(const WasmAllocateArrayOp& allocate_array); @@ -534,7 +536,7 @@ class WasmGCTypedOptimizationReducer : public Next { if (array_length.null_check == kWithNullCheck && type.is_non_nullable()) { return __ ArrayLength(__ MapToNewGraph(array_length.array()), __ MapToNewGraph(array_length.frame_state()), - kWithoutNullCheck); + kWithoutNullCheck, array_length.shared_base); } goto no_change; } diff --git a/deps/v8/src/compiler/turboshaft/wasm-in-js-inlining-reducer-inl.h b/deps/v8/src/compiler/turboshaft/wasm-in-js-inlining-reducer-inl.h index d582fe364050..0b59c43c4ea8 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-in-js-inlining-reducer-inl.h +++ b/deps/v8/src/compiler/turboshaft/wasm-in-js-inlining-reducer-inl.h @@ -706,9 +706,8 @@ class WasmInJsInliningInterface { } void AssertNotNullTypecheck(FullDecoder* decoder, const Value& obj, Value* result) { - __ TrapIf(__ IsNull(obj.get<Object>(), obj.type), frame_state_, - TrapId::kTrapIllegalCast); - Forward(decoder, obj, result); + result->op = __ AssertNotNull(obj.get<Object>(), frame_state_, obj.type, + TrapId::kTrapIllegalCast); } void StructGet(FullDecoder* decoder, const Value& struct_object, @@ -740,7 +739,7 @@ class WasmInJsInliningInterface { __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type, frame_state_); result->op = __ ArrayGet(array_value, index.get<Word32>(), imm.array_type, - is_signed, {}); + is_signed, {}, imm.heap_type().is_shared()); } void ArraySet(FullDecoder* decoder, const Value& array_obj, @@ -750,7 +749,7 @@ class WasmInJsInliningInterface { __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type, frame_state_); __ ArraySet(array_value, index.get<Word32>(), value.op, - imm.array_type->element_type(), {}, + imm.array_type->element_type(), imm.array_type->is_shared(), {}, wasm::ArrayIndexImmediateToWriteBarrier(imm), ArraySetOp::Kind::kAssign); } @@ -758,7 +757,8 @@ class WasmInJsInliningInterface { void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) { result->op = __ ArrayLength( array_obj.get<WasmArrayNullable>(), frame_state_, - array_obj.type.is_nullable() ? kWithNullCheck : kWithoutNullCheck); + array_obj.type.is_nullable() ? kWithNullCheck : kWithoutNullCheck, + array_obj.type.is_shared()); } V<FixedArray> managed_object_maps() { diff --git a/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.cc b/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.cc index f5de6b1b0fd2..db870dc6c375 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.cc @@ -332,6 +332,9 @@ void WasmLoadEliminationAnalyzer::ProcessStructAtomicRMW( memory_.Invalidate(op); // See ProcessStructGet/Set. memory_.InvalidateMutableSharedBase(); + + // Updating aliases if the value stored was known as non-aliasing. + InvalidateIfAlias(op.value()); } void WasmLoadEliminationAnalyzer::ProcessArrayAtomicRMW( @@ -340,6 +343,9 @@ void WasmLoadEliminationAnalyzer::ProcessArrayAtomicRMW( // the state because array atomic operations could be used to sync among // threads. memory_.InvalidateMutableSharedBase(); + + // Updating aliases if the value stored was known as non-aliasing. + InvalidateIfAlias(op.value()); } void WasmLoadEliminationAnalyzer::ProcessLoad(OpIndex op_idx, @@ -380,6 +386,9 @@ void WasmLoadEliminationAnalyzer::ProcessArraySet(OpIndex op_idx, // among threads. memory_.InvalidateMutableSharedBase(); } + + // Updating aliases if the value stored was known as non-aliasing. + InvalidateIfAlias(op.value()); } void WasmLoadEliminationAnalyzer::ProcessArrayLength( @@ -554,7 +563,7 @@ OpIndex WasmLoadEliminationAnalyzer::MaybeReplacePhi(const PhiOp& phi) { DCHECK_GT(inputs.size(), 0); bool same_inputs = true; - OpIndex first = memory_.ResolveBase(inputs.first()); + OpIndex first = memory_.ResolveBase(inputs.front()); for (const OpIndex& input : inputs.SubVectorFrom(1)) { if (memory_.ResolveBase(input) != first) { same_inputs = false; diff --git a/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.h b/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.h index 5b620c67013a..237dba39ff95 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.h +++ b/deps/v8/src/compiler/turboshaft/wasm-load-elimination-reducer.h @@ -13,6 +13,7 @@ #include "src/base/doubly-threaded-list.h" #include "src/compiler/turboshaft/assembler.h" +#include "src/compiler/turboshaft/builtin-call-descriptors.h" #include "src/compiler/turboshaft/graph.h" #include "src/compiler/turboshaft/phase.h" #include "src/compiler/turboshaft/snapshot-table-opindex.h" @@ -169,11 +170,12 @@ class WasmMemoryContentTable } void Invalidate(const StructSetOp& set) { - Invalidate(field_offset(set.type, set.field_index), set.type_index); + Invalidate(WasmStruct::FieldOffset(set.type, set.field_index), + set.type_index); } void Invalidate(const StructAtomicRMWOp& rmw_op) { - Invalidate(field_offset(rmw_op.type, rmw_op.field_index), + Invalidate(WasmStruct::FieldOffset(rmw_op.type, rmw_op.field_index), rmw_op.type_index); } @@ -230,17 +232,12 @@ class WasmMemoryContentTable } } - // TODO(jkummerow): Move this to the WasmStruct class? - int field_offset(const wasm::StructType* type, int field_index) { - return WasmStruct::kHeaderSize + type->field_offset(field_index); - } - OpIndex Find(const StructGetOp& get) { if (get.is_get_desc()) { return FindImpl(ResolveBase(get.object()), kGetDescIndex, get.type_index, kTaggedSize, false); } - int32_t offset = field_offset(get.type, get.field_index); + int32_t offset = WasmStruct::FieldOffset(get.type, get.field_index); uint8_t size = get.type->field(get.field_index).value_kind_size(); bool mutability = get.type->mutability(get.field_index); return FindImpl(ResolveBase(get.object()), offset, get.type_index, size, @@ -248,7 +245,7 @@ class WasmMemoryContentTable } bool HasValueWithIncorrectMutability(const StructSetOp& set) { - int32_t offset = field_offset(set.type, set.field_index); + int32_t offset = WasmStruct::FieldOffset(set.type, set.field_index); uint8_t size = set.type->field(set.field_index).value_kind_size(); bool mutability = set.type->mutability(set.field_index); WasmMemoryAddress mem{ResolveBase(set.object()), offset, set.type_index, @@ -280,7 +277,7 @@ class WasmMemoryContentTable void Insert(const StructSetOp& set) { OpIndex base = ResolveBase(set.object()); - int32_t offset = field_offset(set.type, set.field_index); + int32_t offset = WasmStruct::FieldOffset(set.type, set.field_index); uint8_t size = set.type->field(set.field_index).value_kind_size(); bool mutability = set.type->mutability(set.field_index); Insert(base, offset, set.type_index, size, mutability, set.value()); @@ -293,7 +290,7 @@ class WasmMemoryContentTable return; } OpIndex base = ResolveBase(get.object()); - int32_t offset = field_offset(get.type, get.field_index); + int32_t offset = WasmStruct::FieldOffset(get.type, get.field_index); uint8_t size = get.type->field(get.field_index).value_kind_size(); bool mutability = get.type->mutability(get.field_index); Insert(base, offset, get.type_index, size, mutability, get_idx); @@ -590,13 +587,31 @@ class V8_EXPORT_PRIVATE WasmLoadEliminationReducer : public Next { VerifySingleReplacement(actual_idx, replacement); } -#define VERIFY(Name, ig_index, op, replacement) \ - if (v8_flags.turboshaft_verify_load_elimination) { \ - OpIndex actual_idx = Next::ReduceInputGraph##Name(ig_index, op); \ - VerifyReplacement(actual_idx, replacement); \ + void VerifyStringAsWtf16(OpIndex actual_idx, OpIndex replacement) { + IF_NOT (__ Equal(actual_idx, replacement, + RegisterRepresentation::Tagged())) { + V<Word32> is_equal = __ template WasmCallBuiltinThroughJumptable< + deprecated::BuiltinCallDescriptor::WasmStringEqual>( + {actual_idx, replacement}); + IF_NOT (is_equal) { + EmitReportLoadEliminationError(); + } + } + } + +#define VERIFY(Name, ig_index, op, replacement, condition) \ + if (v8_flags.turboshaft_verify_load_elimination && condition) { \ + OpIndex actual_idx = Next::ReduceInputGraph##Name(ig_index, op); \ + if (!actual_idx.valid()) { \ + DCHECK(__ generating_unreachable_operations()); \ + } else if constexpr (std::is_same_v<Name##Op, StringAsWtf16Op>) { \ + VerifyStringAsWtf16(actual_idx, replacement); \ + } else { \ + VerifyReplacement(actual_idx, replacement); \ + } \ } #else -#define VERIFY(Name, ig_index, op, replacement) +#define VERIFY(Name, ig_index, op, replacement, condition) #endif // DEBUG #define EMIT_OP(Name) /* force 80 cols*/ \ @@ -605,7 +620,7 @@ class V8_EXPORT_PRIVATE WasmLoadEliminationReducer : public Next { OpIndex ig_replacement_index = analyzer_.Replacement(ig_index); \ if (ig_replacement_index.valid()) { \ OpIndex replacement = Asm().MapToNewGraph(ig_replacement_index); \ - VERIFY(Name, ig_index, op, replacement) \ + VERIFY(Name, ig_index, op, replacement, true) \ return replacement; \ } \ } \ @@ -624,7 +639,9 @@ class V8_EXPORT_PRIVATE WasmLoadEliminationReducer : public Next { OpIndex ig_replacement_index = analyzer_.Replacement(ig_index); if (ig_replacement_index.valid()) { OpIndex replacement = Asm().MapToNewGraph(ig_replacement_index); - VERIFY(StructGet, ig_index, op, replacement) + // We do not verify an eliminated struct.get on a shared base as another + // thread might have modified the struct field in the meantime. + VERIFY(StructGet, ig_index, op, replacement, !op.type->is_shared()); return replacement; } } diff --git a/deps/v8/src/compiler/turboshaft/wasm-lowering-reducer.h b/deps/v8/src/compiler/turboshaft/wasm-lowering-reducer.h index 2f99fa97edeb..5641b8436f49 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-lowering-reducer.h +++ b/deps/v8/src/compiler/turboshaft/wasm-lowering-reducer.h @@ -40,6 +40,7 @@ class WasmLoweringReducer : public Next { } OpIndex REDUCE(RootConstant)(RootIndex index) { + DCHECK(RootsTable::IsImmortalImmovable(index)); return __ Load(__ LoadRootRegister(), LoadOp::Kind::RawAligned().Immutable(), MemoryRepresentation::AnyUncompressedTagged(), @@ -87,8 +88,14 @@ class WasmLoweringReducer : public Next { module_) || !type.use_wasm_null(); if (!use_explicit_check) { - __ Load(object, LoadOp::Kind::TrapOnNull().Immutable(), - MemoryRepresentation::TaggedPointer(), + LoadOp::Kind load_kind = LoadOp::Kind::TrapOnNull(); + if (type.is_shared()) load_kind = load_kind.SharedBase(); + if (!v8_flags.wasm_stringref || + !wasm::IsSubtypeOf(wasm::kWasmStringRef.AsNonNull(), + type.AsNonShared(), module_)) { + load_kind = load_kind.Immutable(); + } + __ Load(object, load_kind, MemoryRepresentation::TaggedPointer(), offsetof(HeapObject, map_)); return object; } @@ -114,6 +121,34 @@ class WasmLoweringReducer : public Next { } } + // A type check whose only use is the branch ending its block (br_on_cast, + // br_on_cast_fail, or an `if` on a ref.test) is lowered directly into that + // branch, rather than into a Phi of the results of the different checks + // that the branch then tests: each comparison then ends up in the same block + // as the branch that uses it, which the InstructionSelector can combine. + V<Word32> REDUCE_INPUT_GRAPH(WasmTypeCheck)(V<Word32> ig_index, + const WasmTypeCheckOp& check) { + if (ShouldLowerIntoBranch(ig_index, check)) return V<Word32>::Invalid(); + return Next::ReduceInputGraphWasmTypeCheck(ig_index, check); + } + + V<None> REDUCE_INPUT_GRAPH(Branch)(V<None> ig_index, const BranchOp& branch) { + const WasmTypeCheckOp* check = __ input_graph() + .Get(branch.condition()) + .template TryCast<WasmTypeCheckOp>(); + if (check == nullptr || + !ShouldLowerIntoBranch(branch.condition(), *check)) { + return Next::ReduceInputGraphBranch(ig_index, branch); + } + // The type check was skipped when visiting it. + DCHECK(!__ template MapToNewGraph<true>(branch.condition()).valid()); + BranchOnWasmTypeCheckRtt(__ MapToNewGraph(check->object()), + __ MapToNewGraph(check->rtt().value()), + check->config, __ MapToNewGraph(branch.if_true), + __ MapToNewGraph(branch.if_false), branch.hint); + return V<None>::Invalid(); + } + V<Object> REDUCE(WasmTypeCast)(V<Object> object, OptionalV<Map> rtt, OptionalV<EagerFrameState> frame_state, WasmTypeCheckConfig config) { @@ -131,12 +166,19 @@ class WasmLoweringReducer : public Next { Label<> smi_label(&Asm()); Label<> int_to_smi_label(&Asm()); Label<> heap_number_label(&Asm()); + Label<> custom_map_wrapper_label(&Asm()); if (is_nullable) { GOTO_IF(__ IsNull(object, wasm::kWasmExternRef), null_label); } GOTO_IF(__ IsSmi(object), smi_label); - GOTO_IF(__ HasInstanceType(object, HEAP_NUMBER_TYPE), heap_number_label); + // We don't need to mark the object as potentially-shared because we put + // TSan annotations on the any->extern conversion. + GOTO_IF(__ HasInstanceType(object, HEAP_NUMBER_TYPE, SharedFlag{false}), + heap_number_label); + GOTO_IF(__ HasInstanceType(object, WASM_CUSTOM_MAP_WRAPPER_TYPE, + SharedFlag{false}), + custom_map_wrapper_label); // For anything else, just pass through the value. GOTO(end_label, object); @@ -207,19 +249,71 @@ class WasmLoweringReducer : public Next { BIND(int_to_smi_label); GOTO(end_label, __ TagSmi(int_value)); + BIND(custom_map_wrapper_label); + V<WasmCustomMap> custom_map = + __ Load(object, LoadOp::Kind::TaggedBase().Immutable(), + MemoryRepresentation::TaggedPointer(), + offsetof(WasmCustomMapWrapper, wrapped_)); +#if DEBUG + if (v8_flags.debug_code) { + IF_NOT (LIKELY(__ HasInstanceType(custom_map, WASM_CUSTOM_MAP_TYPE, + SharedFlag{false}))) { + if (__ data()->pipeline_kind() == TurboshaftPipelineKind::kWasm) { + OpIndex message_id = + __ SmiConstant(Smi::FromEnum(AbortReason::kOperandIsNotAMap)); + __ WasmCallRuntime(__ phase_zone(), Runtime::kAbort, {message_id}, + __ NoContextConstant()); + } else { + __ template CallRuntime<runtime::Abort>( + __ NoContextConstant(), + {.messageOrMessageId = __ SmiConstant( + Smi::FromEnum(AbortReason::kOperandIsNotAMap))}); + } + __ Unreachable(); + } + } +#endif // DEBUG + GOTO(end_label, custom_map); + BIND(end_label, result); return result; } V<Object> REDUCE(ExternConvertAny)(V<Object> object, bool is_nullable) { + Label<Object> end(&Asm()); if (is_nullable) { - Label<Object> end(&Asm()); - GOTO_IF_NOT(__ IsNull(object, wasm::kWasmAnyRef), end, object); - GOTO(end, __ Null(wasm::kWasmExternRef)); - BIND(end, result); - return result; + IF (__ IsNull(object, wasm::kWasmAnyRef)) { + GOTO(end, __ Null(wasm::kWasmExternRef)); + } } - return object; + // TODO(jkummerow): Would be nice if we had type information to decide + // which checks are necessary. + // Perhaps move this lowering to the WasmGCTypedOptimizationReducer? + GOTO_IF(__ IsSmi(object), end, object); + SharedFlag maybe_shared{v8_flags.wasm_shared}; + GOTO_IF_NOT(__ HasInstanceType(object, WASM_CUSTOM_MAP_TYPE, maybe_shared), + end, object); + + // For WasmCustomMaps, fetch or allocate their JS wrapper. + { + V<Object> maybe_wrapper = __ Load(object, LoadOp::Kind::TaggedBase(), + MemoryRepresentation::TaggedPointer(), + offsetof(WasmCustomMap, js_wrapper_)); + GOTO_IF_NOT(UNLIKELY(__ IsNull(maybe_wrapper, wasm::kWasmExternRef)), end, + maybe_wrapper); + V<JSObject> wrapper; + if (__ data()->pipeline_kind() == TurboshaftPipelineKind::kWasm) { + wrapper = + __ WasmCallRuntime(__ phase_zone(), Runtime::kWasmExternConvertAny, + {object}, __ NoContextConstant()); + } else { + wrapper = __ template CallRuntime<runtime::WasmExternConvertAny>( + __ NoContextConstant(), {.object = object}); + } + GOTO(end, wrapper); + } + BIND(end, result); + return result; } V<Object> REDUCE(WasmTypeAnnotation)(V<Object> value, wasm::ValueType type) { @@ -243,6 +337,8 @@ class WasmLoweringReducer : public Next { LoadOp::Kind load_kind = implicit_null_check ? LoadOp::Kind::TrapOnNull() : LoadOp::Kind::TaggedBase(); + if (type->is_shared()) load_kind = load_kind.SharedBase(); + if (field_index == StructGetOp::kDescFieldIndex) { // Can't use {LoadMapField} because that doesn't support specifying // {LoadOp::Kind::TrapOnNull}. @@ -252,6 +348,8 @@ class WasmLoweringReducer : public Next { #if V8_MAP_PACKING UNIMPLEMENTED(); #endif + if (type->is_shared()) UNIMPLEMENTED(); + if (v8_flags.wasm_merged_descriptors) return map; return __ Load(map, LoadOp::Kind::TaggedBase().Immutable(), MemoryRepresentation::TaggedPointer(), offsetof(Map, instance_descriptors_)); @@ -268,7 +366,8 @@ class WasmLoweringReducer : public Next { MemoryRepresentation repr = RepresentationFor(type->field(field_index), is_signed); - return __ Load(object, load_kind, repr, field_offset(type, field_index)); + return __ Load(object, load_kind, repr, + WasmStruct::FieldOffset(type, field_index)); } V<None> REDUCE(StructSet)(V<WasmStructNullable> object, V<Any> value, @@ -308,7 +407,7 @@ class WasmLoweringReducer : public Next { DCHECK_IMPLIES(write_barrier == kFullWriteBarrier, type->field(field_index).is_ref()); __ Store(object, value, store_kind, repr, write_barrier, memory_order, - field_offset(type, field_index), 0, + WasmStruct::FieldOffset(type, field_index), 0, kind == StructSetOp::Kind::kInitialize); return OpIndex::Invalid(); @@ -331,8 +430,8 @@ class WasmLoweringReducer : public Next { MemoryRepresentation repr = RepresentationFor(type->field(field_index), false); - V<WordPtr> offset = - __ WordPtrConstant(field_offset(type, field_index) - kHeapObjectTag); + V<WordPtr> offset = __ WordPtrConstant( + WasmStruct::FieldOffset(type, field_index) - kHeapObjectTag); MemoryAccessKind kind = implicit_null_check ? MemoryAccessKind::kTrapping : MemoryAccessKind::kNormal; if (bin_op == StructAtomicRMWOp::BinOp::kCompareExchange) { @@ -346,23 +445,37 @@ class WasmLoweringReducer : public Next { } } + // Converts the index of an array access for the address computation. + // The index is less than the array length, which is less than 2^30 (see + // {WasmArray::MaxLength}): the access passed its bounds check, or the + // check was removed because it was shown to succeed. So the zero and + // sign extensions of the index are equal (except with the test-only + // --wasm-skip-bounds-checks). We use the zero extension, as for memory32 + // accesses: on x64 and arm64, 32-bit operations clear the upper half of + // registers, so it is usually free. On riscv64, loong64 and mips64, which + // keep 32-bit values sign-extended, it can cost an instruction. + V<WordPtr> ArrayIndexToIntPtr(V<Word32> index) { + return __ ChangeUint32ToUintPtr(index); + } + V<Any> REDUCE(ArrayGet)(V<WasmArrayNullable> array, V<Word32> index, const wasm::ArrayType* array_type, bool is_signed, - std::optional<AtomicMemoryOrder> memory_order) { + std::optional<AtomicMemoryOrder> memory_order, + SharedFlag shared_base) { bool is_mutable = array_type->mutability(); LoadOp::Kind load_kind = LoadOp::Kind::TaggedBase(); if (!is_mutable) load_kind = load_kind.Immutable(); - if (memory_order.has_value()) { - load_kind = load_kind.Atomic(); - } - return __ Load(array, __ ChangeInt32ToIntPtr(index), load_kind, + if (memory_order.has_value()) load_kind = load_kind.Atomic(); + if (shared_base) load_kind = load_kind.SharedBase(); + return __ Load(array, ArrayIndexToIntPtr(index), load_kind, RepresentationFor(array_type->element_type(), is_signed), - WasmArray::kHeaderSize, + WasmArray::HeaderSize(array_type->is_shared()), array_type->element_type().value_kind_size_log2()); } V<None> REDUCE(ArraySet)(V<WasmArrayNullable> array, V<Word32> index, V<Any> value, wasm::ValueType element_type, + SharedFlag is_shared, std::optional<AtomicMemoryOrder> memory_order, WriteBarrierKind write_barrier, ArraySetOp::Kind kind) { @@ -376,9 +489,10 @@ class WasmLoweringReducer : public Next { store_kind = store_kind.Atomic(); } DCHECK_IMPLIES(write_barrier == kFullWriteBarrier, element_type.is_ref()); - __ Store(array, __ ChangeInt32ToIntPtr(index), value, store_kind, + __ Store(array, ArrayIndexToIntPtr(index), value, store_kind, RepresentationFor(element_type, true), write_barrier, memory_order, - WasmArray::kHeaderSize, element_type.value_kind_size_log2(), + WasmArray::HeaderSize(is_shared), + element_type.value_kind_size_log2(), kind == ArraySetOp::Kind::kInitialize); return {}; } @@ -387,12 +501,13 @@ class WasmLoweringReducer : public Next { OpIndex value, OptionalOpIndex expected, ArrayAtomicRMWOp::BinOp bin_op, wasm::ValueType element_type, + SharedFlag is_shared, AtomicMemoryOrder memory_order) { MemoryRepresentation repr = RepresentationFor(element_type, false); V<WordPtr> index_scaled = __ WordPtrShiftLeft( - __ ChangeInt32ToIntPtr(index), element_type.value_kind_size_log2()); - V<WordPtr> offset = - __ WordPtrAdd(index_scaled, WasmArray::kHeaderSize - kHeapObjectTag); + ArrayIndexToIntPtr(index), element_type.value_kind_size_log2()); + V<WordPtr> offset = __ WordPtrAdd( + index_scaled, WasmArray::HeaderSize(is_shared) - kHeapObjectTag); if (bin_op == StructAtomicRMWOp::BinOp::kCompareExchange) { return __ AtomicCompareExchange(array, offset, expected.value(), value, repr.ToRegisterRepresentation(), repr, @@ -407,7 +522,8 @@ class WasmLoweringReducer : public Next { V<Word32> REDUCE(ArrayLength)(V<WasmArrayNullable> array, OptionalV<EagerFrameState> frame_state, - CheckForNull null_check) { + CheckForNull null_check, + SharedFlag shared_base) { bool explicit_null_check = null_check == kWithNullCheck && null_check_strategy_ == NullCheckStrategy::kExplicit; @@ -423,18 +539,19 @@ class WasmLoweringReducer : public Next { LoadOp::Kind load_kind = implicit_null_check ? LoadOp::Kind::TrapOnNull().Immutable() : LoadOp::Kind::TaggedBase().Immutable(); + if (shared_base) load_kind = load_kind.SharedBase(); return __ Load(array, load_kind, RepresentationFor(wasm::kWasmI32, true), offsetof(WasmArray, length_)); } V<WasmArray> REDUCE(WasmAllocateArray)(V<Map> rtt, V<Word32> length, - const wasm::ArrayType* array_type, - SharedFlag is_shared) { + const wasm::ArrayType* array_type) { __ TrapIfNot( __ Uint32LessThanOrEqual(length, WasmArray::MaxLength(array_type)), TrapId::kTrapArrayTooLarge); wasm::ValueType element_type = array_type->element_type(); + SharedFlag is_shared = array_type->is_shared(); // RoundUp(length * value_size, kObjectAlignment) = // RoundDown(length * value_size + kObjectAlignment - 1, @@ -445,19 +562,20 @@ class WasmLoweringReducer : public Next { int32_t{-kObjectAlignment}); Uninitialized<WasmArray> a = __ template Allocate<WasmArray>( __ ChangeUint32ToUintPtr( - __ Word32Add(padded_length, WasmArray::kHeaderSize)), + __ Word32Add(padded_length, WasmArray::HeaderSize(is_shared))), is_shared ? AllocationType::kSharedOld : AllocationType::kYoung, - is_shared ? kDoubleUnaligned : kTaggedAligned); + is_shared ? kDoubleAligned : kTaggedAligned); // TODO(14108): The map and empty fixed array initialization should be an // immutable store. __ InitializeField( a, - AccessBuilder::ForMap(is_shared ? compiler::kMapWriteBarrier - : compiler::kNoWriteBarrier), + AccessBuilder::ForMap( + is_shared ? compiler::kMapWriteBarrier : compiler::kNoWriteBarrier, + is_shared /* not used for stores */), rtt); __ InitializeField(a, AccessBuilder::ForJSObjectPropertiesOrHash(), - __ template LoadRoot<RootIndex::kEmptyFixedArray>()); + __ RootConstant(RootIndex::kEmptyFixedArray)); __ InitializeField(a, AccessBuilder::ForWasmArrayLength(), length); // Note: Only the array header initialization is finished here, the elements @@ -469,6 +587,8 @@ class WasmLoweringReducer : public Next { V<WasmStruct> REDUCE(WasmAllocateStruct)(V<Map> rtt, const wasm::StructType* struct_type, wasm::ModuleTypeIndex type_index) { + // Only the WasmAllocateDescriptorStruct builtin can allocate descriptors. + DCHECK(!struct_type->is_descriptor()); int size = WasmStruct::Size(struct_type); Uninitialized<WasmStruct> s = __ template Allocate<WasmStruct>( size, @@ -477,12 +597,13 @@ class WasmLoweringReducer : public Next { struct_type->is_shared() ? kDoubleAligned : kTaggedAligned); // Objects allocated into old-space need a write barrier for initialization. __ InitializeField(s, - AccessBuilder::ForMap(struct_type->is_shared() - ? compiler::kMapWriteBarrier - : compiler::kNoWriteBarrier), + AccessBuilder::ForMap( + struct_type->is_shared() ? compiler::kMapWriteBarrier + : compiler::kNoWriteBarrier, + struct_type->is_shared() /* not used for stores */), rtt); __ InitializeField(s, AccessBuilder::ForJSObjectPropertiesOrHash(), - __ template LoadRoot<RootIndex::kEmptyFixedArray>()); + __ RootConstant(RootIndex::kEmptyFixedArray)); // Note: Struct initialization isn't finished here, the user defined fields // still need to be initialized by other operations. V<WasmStruct> struct_value = __ FinishInitialization(std::move(s)); @@ -702,6 +823,11 @@ class WasmLoweringReducer : public Next { wasm::IsSubtypeOf(wasm::kWasmI31Ref.AsNonNull(), config.from.AsNonShared(), module_) || config.from.is_reference_to(wasm::GenericKind::kExtern); + // anyref may contain shared objects. However, since we reject shared + // objects before accessing object fields in that case, we can just pass + // `config.from.is_shared()` as `shared_base`. + SharedFlag shared_base = + SharedFlag{v8_flags.wasm_shared && config.from.is_shared()}; V<Word32> result; Label<Word32> end_label(&Asm()); @@ -734,7 +860,12 @@ class WasmLoweringReducer : public Next { } RejectSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, end_label); - result = IsDataRefMap(__ LoadMapField(object)); + // TODO(jkummerow): Here and elsewhere in this file, use + // {LoadImmutableMapField} whenever the input is guaranteed to be a + // Wasm object (i.e. not a string). + RejectNonWasmObject(__ LoadMapField(V<HeapObject>::Cast(object)), + end_label); + GOTO(end_label, 1); break; } // array, struct, string: i31 fails. @@ -744,19 +875,26 @@ class WasmLoweringReducer : public Next { if (to_kind == wasm::GenericKind::kArray) { RejectSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, end_label); - result = __ HasInstanceType(object, WASM_ARRAY_TYPE); + result = __ HasInstanceType(object, WASM_ARRAY_TYPE, shared_base); break; } if (to_kind == wasm::GenericKind::kStruct) { RejectSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, end_label); - result = __ HasInstanceType(object, WASM_STRUCT_TYPE); + GOTO_IF( + LIKELY(__ HasInstanceType(object, WASM_STRUCT_TYPE, shared_base)), + end_label, 1); + // Only the first access to an object needs to set the right + // right {shared_base} as long as that's only used for TSan, but let's + // be consistent and future-proof. + result = __ HasInstanceType(object, WASM_CUSTOM_MAP_TYPE, shared_base); break; } if (to_kind == wasm::GenericKind::kString || to_kind == wasm::GenericKind::kExternString) { + // TODO(manoskouk): Refine `shared_base` if needed. V<Word32> instance_type = - __ LoadInstanceTypeField(__ LoadMapField(object)); + __ LoadInstanceTypeField(__ LoadMapField(object, shared_base)); result = __ Uint32LessThan(instance_type, FIRST_NONSTRING_TYPE); break; } @@ -787,6 +925,11 @@ class WasmLoweringReducer : public Next { wasm::IsSubtypeOf(wasm::kWasmI31Ref.AsNonNull(), config.from.AsNonShared(), module_) || config.from.is_reference_to(wasm::GenericKind::kExtern); + // anyref may contain shared objects. However, since we reject shared + // objects before accessing object fields in that case, we can just pass + // `config.from.is_shared()` as `shared_base`. + SharedFlag shared_base = + SharedFlag{v8_flags.wasm_shared && config.from.is_shared()}; Label<> end_label(&Asm()); @@ -827,8 +970,9 @@ class WasmLoweringReducer : public Next { } TrapOnSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, frame_state); - __ TrapIfNot(IsDataRefMap(__ LoadMapField(object)), frame_state, - TrapId::kTrapIllegalCast); + TrapOnNonWasmObject( + __ LoadMapField(V<HeapObject>::Cast(object), shared_base), + frame_state); break; } // array, struct, string: i31 fails. @@ -838,21 +982,30 @@ class WasmLoweringReducer : public Next { if (to_kind == wasm::GenericKind::kArray) { TrapOnSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, frame_state); - __ TrapIfNot(__ HasInstanceType(object, WASM_ARRAY_TYPE), frame_state, - TrapId::kTrapIllegalCast); + // Same as above. + __ TrapIfNot(__ HasInstanceType(object, WASM_ARRAY_TYPE, shared_base), + frame_state, TrapId::kTrapIllegalCast); break; } if (to_kind == wasm::GenericKind::kStruct) { TrapOnSharedWasmObjectsIfUnshared(V<HeapObject>::Cast(object), config, frame_state); - __ TrapIfNot(__ HasInstanceType(object, WASM_STRUCT_TYPE), frame_state, - TrapId::kTrapIllegalCast); + Label<> fallthrough(&Asm()); + GOTO_IF( + LIKELY(__ HasInstanceType(object, WASM_STRUCT_TYPE, shared_base)), + fallthrough); + __ TrapIfNot( + __ HasInstanceType(object, WASM_CUSTOM_MAP_TYPE, shared_base), + frame_state, TrapId::kTrapIllegalCast); + GOTO(fallthrough); + BIND(fallthrough); break; } if (to_kind == wasm::GenericKind::kString || to_kind == wasm::GenericKind::kExternString) { + // TODO(manoskouk): Refine `shared_base` if needed. V<Word32> instance_type = - __ LoadInstanceTypeField(__ LoadMapField(object)); + __ LoadInstanceTypeField(__ LoadMapField(object, shared_base)); __ TrapIfNot(__ Uint32LessThan(instance_type, FIRST_NONSTRING_TYPE), frame_state, TrapId::kTrapIllegalCast); break; @@ -875,87 +1028,32 @@ class WasmLoweringReducer : public Next { OptionalV<EagerFrameState> frame_state, WasmTypeCheckConfig config) { DCHECK(rtt.has_value()); - int rtt_depth = wasm::GetSubtypingDepth(module_, config.to.ref_index()); - bool object_can_be_i31 = wasm::IsSubtypeOf( - wasm::kWasmI31Ref.AsNonNull(), config.from.AsNonShared(), module_); - Label<> end_label(&Asm()); - bool is_cast_from_any = - config.from.is_reference_to(wasm::GenericKind::kAny); - - if (config.from.is_nullable()) { - V<Word32> is_null = __ IsNull(object, wasm::kWasmAnyRef); - if (config.to.is_nullable()) { - GOTO_IF(UNLIKELY(is_null), end_label); - } else if (!v8_flags.wasm_skip_null_checks) { - // TODO(jkummerow): Consider using a trapping map load instead, and - // adjusting its message to be "illegal cast" instead of "null deref". - __ TrapIf(is_null, frame_state, TrapId::kTrapIllegalCast); - } - } - - if (object_can_be_i31) { - __ TrapIf(__ IsSmi(object), frame_state, TrapId::kTrapIllegalCast); - } - - V<Map> map = __ LoadMapField(object); - - DCHECK_IMPLIES(module_->type(config.to.ref_index()).is_final, - config.exactness != kMayBeSubtype); - - if (config.exactness == kExactMatchOnly) { - __ TrapIfNot(__ TaggedEqual(map, rtt.value()), frame_state, - TrapId::kTrapIllegalCast); - GOTO(end_label); - } else if (config.exactness == kExactMatchLastSupertype) { - // This only used for custom descriptors, and only structs can have them. - DCHECK_EQ(config.to.ref_type_kind(), wasm::RefTypeKind::kStruct); - // Check if map instance type identifies a wasm object. - if (is_cast_from_any) { - V<Word32> is_wasm_obj = IsDataRefMap(map); - __ TrapIfNot(is_wasm_obj, frame_state, TrapId::kTrapIllegalCast); - } - V<Object> maybe_match = LoadImmediateSuperRTT(map); - __ TrapIfNot(__ TaggedEqual(maybe_match, rtt.value()), frame_state, - TrapId::kTrapIllegalCast); - GOTO(end_label); - } else { - DCHECK_EQ(config.exactness, kMayBeSubtype); - // First, check if types happen to be equal. This has been shown to give - // large speedups. - GOTO_IF(LIKELY(__ TaggedEqual(map, rtt.value())), end_label); - - // Check if map instance type identifies a wasm object. - if (is_cast_from_any) { - V<Word32> is_wasm_obj = IsDataRefMap(map); - __ TrapIfNot(is_wasm_obj, frame_state, TrapId::kTrapIllegalCast); - } - - V<Object> type_info = __ LoadWasmTypeInfo(map); - DCHECK_GE(rtt_depth, 0); - // If the depth of the rtt is known to be less that the minimum supertype - // array length, we can access the supertype without bounds-checking the - // supertype array. - if (static_cast<uint32_t>(rtt_depth) >= - wasm::kMinimumSupertypeArraySize) { - V<Word32> supertypes_length = __ UntagSmi( - __ Load(type_info, LoadOp::Kind::TaggedBase().Immutable(), - MemoryRepresentation::TaggedSigned(), - offsetof(WasmTypeInfo, supertypes_length_))); - __ TrapIfNot(__ Uint32LessThan(rtt_depth, supertypes_length), - frame_state, TrapId::kTrapIllegalCast); - } - - V<Object> maybe_match = - __ Load(type_info, LoadOp::Kind::TaggedBase().Immutable(), - MemoryRepresentation::TaggedPointer(), - WasmTypeInfo::kSupertypesOffset + kTaggedSize * rtt_depth); - - __ TrapIfNot(__ TaggedEqual(maybe_match, rtt.value()), frame_state, - TrapId::kTrapIllegalCast); - GOTO(end_label); - } - + // TODO(jkummerow): Consider using a trapping map load instead of the null + // check, and adjusting its message to be "illegal cast" instead of "null + // deref". + EmitWasmTypeCheckRtt( + object, rtt.value(), config, v8_flags.wasm_skip_null_checks, + [this, frame_state, &end_label](ConditionWithHint condition, + EarlyExitConfig early_exit) { + if (early_exit.result_value) { + if (early_exit.negated) { + GOTO_IF_NOT(condition, end_label); + } else { + GOTO_IF(condition, end_label); + } + } else if (early_exit.negated) { + __ TrapIfNot(condition.condition(), frame_state, + TrapId::kTrapIllegalCast); + } else { + __ TrapIf(condition.condition(), frame_state, + TrapId::kTrapIllegalCast); + } + }, + [this, frame_state, &end_label](V<Word32> condition) { + __ TrapIfNot(condition, frame_state, TrapId::kTrapIllegalCast); + GOTO(end_label); + }); BIND(end_label); return object; } @@ -963,51 +1061,112 @@ class WasmLoweringReducer : public Next { V<Word32> ReduceWasmTypeCheckRtt(V<Object> object, OptionalV<Map> rtt, WasmTypeCheckConfig config) { DCHECK(rtt.has_value()); + Label<Word32> end_label(&Asm()); + EmitWasmTypeCheckRtt( + object, rtt.value(), config, false, + [this, &end_label](ConditionWithHint condition, + EarlyExitConfig early_exit) { + if (early_exit.negated) { + GOTO_IF_NOT(condition, end_label, early_exit.result_value); + } else { + GOTO_IF(condition, end_label, early_exit.result_value); + } + }, + [this, &end_label](V<Word32> condition) { + GOTO(end_label, condition); + }); + BIND(end_label, result); + return result; + } + + // An early exit of a type check: when its condition is true (or false, if + // {negated}), the result of the type check is {result_value}. + struct EarlyExitConfig { + bool negated; + bool result_value; + }; + + // Checks that {map} is the map of a Wasm object (one of the Wasm object + // instance types, or a WasmCustomMap); otherwise, the type check fails: this + // early exit is passed to {early_exit_handler} (see EmitWasmTypeCheckRtt). + template <typename EarlyExitHandler> + void EmitWasmObjectCheck(V<Map> map, EarlyExitHandler&& early_exit_handler) { + V<Word32> instance_type = __ LoadInstanceTypeField(map); + // We're going to test a range of WasmObject instance types with a single + // unsigned comparison. + V<Word32> comparison_value = + __ Word32Sub(instance_type, FIRST_WASM_OBJECT_TYPE); + IF (UNLIKELY( + __ Uint32LessThan(LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE, + comparison_value))) { + early_exit_handler( + LIKELY(__ Word32Equal(comparison_value, + WASM_CUSTOM_MAP_TYPE - FIRST_WASM_OBJECT_TYPE)), + {.negated = true, .result_value = false}); + } + } + + // Emits the checks of a type check or cast against {rtt}. Each check that + // can determine the result early is passed to {early_exit_handler}, with its + // condition and an EarlyExitConfig. The last comparison, which determines + // the result otherwise, is passed to {result_handler}. + // With {skip_failing_null_check}, there is no check for null when null + // fails the type check (for casts with --wasm-skip-null-checks). + template <typename EarlyExitHandler, typename ResultHandler> + void EmitWasmTypeCheckRtt(V<Object> object, V<Map> rtt, + WasmTypeCheckConfig config, + bool skip_failing_null_check, + EarlyExitHandler early_exit_handler, + ResultHandler result_handler) { int rtt_depth = wasm::GetSubtypingDepth(module_, config.to.ref_index()); bool object_can_be_i31 = wasm::IsSubtypeOf( wasm::kWasmI31Ref.AsNonNull(), config.from.AsNonShared(), module_); bool is_cast_from_any = config.from.is_reference_to(wasm::GenericKind::kAny); - - Label<Word32> end_label(&Asm()); - - if (config.from.is_nullable()) { - const int kResult = config.to.is_nullable() ? 1 : 0; - GOTO_IF(UNLIKELY(__ IsNull(object, wasm::kWasmAnyRef)), end_label, - kResult); + // Non-shared anyref may contain shared objects. + SharedFlag shared_base = + SharedFlag{v8_flags.wasm_shared && + (config.from.is_shared() || + config.from.is_reference_to(wasm::GenericKind::kAny))}; + + if (config.from.is_nullable() && + (config.to.is_nullable() || !skip_failing_null_check)) { + early_exit_handler( + UNLIKELY(__ IsNull(object, wasm::kWasmAnyRef)), + {.negated = false, .result_value = config.to.is_nullable()}); } if (object_can_be_i31) { - GOTO_IF(__ IsSmi(object), end_label, 0); + early_exit_handler(__ IsSmi(object), + {.negated = false, .result_value = false}); } - V<Map> map = __ LoadMapField(object); + V<Map> map = __ LoadMapField(object, shared_base); DCHECK_IMPLIES(module_->type(config.to.ref_index()).is_final, config.exactness != kMayBeSubtype); if (config.exactness == kExactMatchOnly) { - GOTO(end_label, __ TaggedEqual(map, rtt.value())); + result_handler(__ TaggedEqual(map, rtt)); } else if (config.exactness == kExactMatchLastSupertype) { // This only used for custom descriptors, and only structs can have them. DCHECK_EQ(config.to.ref_type_kind(), wasm::RefTypeKind::kStruct); // Check if map instance type identifies a wasm object. if (is_cast_from_any) { - V<Word32> is_wasm_obj = IsDataRefMap(map); - GOTO_IF_NOT(LIKELY(is_wasm_obj), end_label, 0); + EmitWasmObjectCheck(map, early_exit_handler); } V<Object> maybe_match = LoadImmediateSuperRTT(map); - GOTO(end_label, __ TaggedEqual(maybe_match, rtt.value())); + result_handler(__ TaggedEqual(maybe_match, rtt)); } else { DCHECK_EQ(config.exactness, kMayBeSubtype); // First, check if types happen to be equal. This has been shown to give // large speedups. - GOTO_IF(LIKELY(__ TaggedEqual(map, rtt.value())), end_label, 1); + early_exit_handler(LIKELY(__ TaggedEqual(map, rtt)), + {.negated = false, .result_value = true}); // Check if map instance type identifies a wasm object. if (is_cast_from_any) { - V<Word32> is_wasm_obj = IsDataRefMap(map); - GOTO_IF_NOT(LIKELY(is_wasm_obj), end_label, 0); + EmitWasmObjectCheck(map, early_exit_handler); } V<Object> type_info = __ LoadWasmTypeInfo(map); @@ -1021,8 +1180,9 @@ class WasmLoweringReducer : public Next { __ Load(type_info, LoadOp::Kind::TaggedBase().Immutable(), MemoryRepresentation::TaggedSigned(), offsetof(WasmTypeInfo, supertypes_length_))); - GOTO_IF_NOT(LIKELY(__ Uint32LessThan(rtt_depth, supertypes_length)), - end_label, 0); + early_exit_handler( + LIKELY(__ Uint32LessThan(rtt_depth, supertypes_length)), + {.negated = true, .result_value = false}); } V<Object> maybe_match = @@ -1030,11 +1190,48 @@ class WasmLoweringReducer : public Next { MemoryRepresentation::TaggedPointer(), WasmTypeInfo::kSupertypesOffset + kTaggedSize * rtt_depth); - GOTO(end_label, __ TaggedEqual(maybe_match, rtt.value())); + result_handler(__ TaggedEqual(maybe_match, rtt)); } + } - BIND(end_label, result); - return result; + bool ShouldLowerIntoBranch(OpIndex ig_index, const WasmTypeCheckOp& check) { + if (!check.rtt().has_value() || !check.saturated_use_count.Is(1)) { + return false; + } + // The type check and the branch must be in the same block: this is the + // only case where the branch using the type check can be found cheaply (it + // ends the block). This function is called twice: when visiting the type + // check, to decide whether to skip it, and when visiting the branch, to + // decide whether to lower the type check into it. Without this condition, + // a type check in a previous block would be emitted twice: in value form + // when visited (a dead copy, left for dead-code elimination to remove), + // and again in the branch. + const Block* block = __ current_input_block(); + if (!block->Contains(ig_index)) return false; + const BranchOp* branch = + block->LastOperation(__ input_graph()).template TryCast<BranchOp>(); + return branch != nullptr && branch->condition() == ig_index; + } + + // Same checks as ReduceWasmTypeCheckRtt, jumping to {if_true} or {if_false} + // instead of producing a value. + void BranchOnWasmTypeCheckRtt(V<Object> object, V<Map> rtt, + WasmTypeCheckConfig config, Block* if_true, + Block* if_false, BranchHint hint) { + EmitWasmTypeCheckRtt( + object, rtt, config, false, + [this, if_true, if_false](ConditionWithHint condition, + EarlyExitConfig early_exit) { + Block* target = early_exit.result_value ? if_true : if_false; + if (early_exit.negated) { + __ GotoIfNot(condition, target); + } else { + __ GotoIf(condition, target); + } + }, + [this, if_true, if_false, hint](V<Word32> condition) { + __ Branch(ConditionWithHint(condition, hint), if_true, if_false); + }); } OpIndex LowerGlobalSetOrGet(V<WasmTrustedInstanceData> instance, V<Any> value, @@ -1110,14 +1307,21 @@ class WasmLoweringReducer : public Next { } } - V<Word32> IsDataRefMap(V<Map> map) { - V<Word32> instance_type = __ LoadInstanceTypeField(map); - // We're going to test a range of WasmObject instance types with a single - // unsigned comparison. - V<Word32> comparison_value = - __ Word32Sub(instance_type, FIRST_WASM_OBJECT_TYPE); - return __ Uint32LessThanOrEqual( - comparison_value, LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE); + void RejectNonWasmObject(V<Map> map, Label<Word32>& result_label) { + EmitWasmObjectCheck(map, [this, &result_label](ConditionWithHint condition, + EarlyExitConfig early_exit) { + DCHECK(early_exit.negated && !early_exit.result_value); + GOTO_IF_NOT(condition, result_label, 0); + }); + } + + void TrapOnNonWasmObject(V<Map> map, OptionalV<EagerFrameState> frame_state) { + EmitWasmObjectCheck(map, [this, frame_state](ConditionWithHint condition, + EarlyExitConfig early_exit) { + DCHECK(early_exit.negated && !early_exit.result_value); + __ TrapIfNot(condition.condition(), frame_state, + TrapId::kTrapIllegalCast); + }); } std::pair<bool, bool> null_checks_for_struct_op(CheckForNull null_check, @@ -1131,10 +1335,6 @@ class WasmLoweringReducer : public Next { return {explicit_null_check, implicit_null_check}; } - int field_offset(const wasm::StructType* type, int field_index) { - return WasmStruct::kHeaderSize + type->field_offset(field_index); - } - const wasm::WasmModule* module_ = __ data() -> wasm_module(); // Wasm-in-JS inlining runs in the JS pipeline where we cannot use the diff --git a/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.cc b/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.cc index 3ec9534bd356..e62e6c03cbe0 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.cc @@ -203,7 +203,17 @@ class StoreLoadInfo { std::optional<OffsetDiff> operator-(const StoreLoadInfo<Op>& rhs) const { DCHECK(is_valid() && rhs.is_valid()); - if (base_ != rhs.base_) return {}; + if (base_ != rhs.base_) { + const LoadOp* load_lhs = base_->template TryCast<LoadOp>(); + const LoadOp* load_rhs = rhs.base_->template TryCast<LoadOp>(); + // We consider two immutable base loads equivalent if they load the same + // offset from the same base. This in particular matches the load of the + // memory0 start pointer from the WasmTrustedInstanceData. + if (!load_lhs || !load_rhs || !load_lhs->kind.is_immutable || + *load_lhs != *load_rhs) { + return {}; + } + } if (index_ != rhs.index_) return {}; // Normally consecutive loads and stores will share or have identical // constant index. It's rare we need to fold the constant index into offset @@ -241,7 +251,21 @@ class StoreLoadInfo { // indexc comparison, stores with offset=0,indexc=0 and offset=0,indexc=64 // would compare equal and the second would be discarded from the set. bool operator<(const StoreLoadInfo<Op>& other) const { - if (base_ != other.base_) return base_ < other.base_; + if (base_ != other.base_) { + const LoadOp* load_lhs = base_->template TryCast<LoadOp>(); + const LoadOp* load_rhs = other.base_->template TryCast<LoadOp>(); + const bool lhs_imm_load = load_lhs && load_lhs->kind.is_immutable; + const bool rhs_imm_load = load_rhs && load_rhs->kind.is_immutable; + if (lhs_imm_load && rhs_imm_load) { + if (*load_lhs != *load_rhs) { + return *load_lhs < *load_rhs; + } + } else if (lhs_imm_load != rhs_imm_load) { + return !lhs_imm_load; + } else { + return base_ < other.base_; + } + } if (index_ != other.index_) return index_ < other.index_; if (indexc_ != other.indexc_) return indexc_ < other.indexc_; return offset_ < other.offset_; @@ -389,11 +413,8 @@ bool SLPTree::HasInputDependencies(const NodeGroup& node_group) { break; } - // Check side effect from input to start's previous node to simplify - // reducing of force-packing nodes. - OpIndex start_prev = graph().PreviousIndex(start); - DCHECK(start_prev.valid()); - if (!IsSideEffectFreeRange(start_prev, input)) { + // Check side effect from input to start node. + if (!IsSideEffectFreeRange(start, input)) { result = true; break; } @@ -1070,6 +1091,17 @@ PackNode* SLPTree::BuildTreeRec(const NodeGroup& node_group, if (is_intersected) { TRACE("Partial overlap at #%d,%s!\n", node0.id(), GetSimdOpcodeName(op0).c_str()); + // node0 already triggered intersection above, but node1 may + // independently belong to a PackNode that does not support + // intersecting (e.g. a DefaultPackNode). Reject that case instead of + // silently creating an IntersectPackNode that conflicts with it. + if (PackNode* pnode1 = GetPackNode(node1)) { + if (!pnode1->IsForcePackNode()) { + TRACE("Unsupported partial overlap at #%d,%s!\n", node1.id(), + GetSimdOpcodeName(op1).c_str()); + return nullptr; + } + } } else { // Match overlapped PackNode on the second node. if (PackNode* pnode = GetPackNode(node1)) { diff --git a/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.h b/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.h index e4dbd2bf091d..924be77f1ed8 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.h +++ b/deps/v8/src/compiler/turboshaft/wasm-revec-reducer.h @@ -924,7 +924,7 @@ class WasmRevecReducer : public UniformReducerAdapter<WasmRevecReducer, Next> { if (!og_index.valid()) { const LoadOp& start = analyzer_.GetStartOperation(pnode, ig_index, load) .template Cast<LoadOp>(); - DCHECK_EQ(start.base(), load.base()); + DCHECK(AreEquivalentBases(start.base(), load.base())); OpIndex base = __ MapToNewGraph(load.base()); // We need to use {load}'s index here because there could be different @@ -952,7 +952,7 @@ class WasmRevecReducer : public UniformReducerAdapter<WasmRevecReducer, Next> { const StoreOp& start = (analyzer_.GetStartOperation(pnode, ig_index, store)) .template Cast<StoreOp>(); - DCHECK_EQ(start.base(), store.base()); + DCHECK(AreEquivalentBases(start.base(), store.base())); // It's possible that an OOB is trapped at the higher 128-bit address // after the lower 128-bit store is executed. To ensure a consistent @@ -1311,7 +1311,9 @@ class WasmRevecReducer : public UniformReducerAdapter<WasmRevecReducer, Next> { // can have a block including operations {a1, a2, b1, b2}, and the // SLPTree can be pnode1: (a2, a1), pnode2: (b1, b2) if a2 is input // of b1, and a1 is input of b2. - for (size_t i = 0; i < pnode->nodes().size(); i++) { + const bool swap_order = pnode->nodes()[0] > pnode->nodes()[1]; + for (size_t idx = 0; idx < pnode->nodes().size(); idx++) { + const size_t i = swap_order ? 1 - idx : idx; OpIndex cur_index = pnode->nodes()[i]; if ((*og_index).valid() && cur_index == ig_index) { og_inputs[i] = *og_index; @@ -1484,6 +1486,15 @@ class WasmRevecReducer : public UniformReducerAdapter<WasmRevecReducer, Next> { } } + bool AreEquivalentBases(OpIndex base0, OpIndex base1) { + if (base0 == base1) return true; + const LoadOp* load0 = + __ input_graph().Get(base0).template TryCast<LoadOp>(); + const LoadOp* load1 = + __ input_graph().Get(base1).template TryCast<LoadOp>(); + return load0 && load1 && load0->kind.is_immutable && *load0 == *load1; + } + const wasm::WasmModule* module_{__ data()->wasm_module()}; WasmRevecAnalyzer& analyzer_{*__ data()->wasm_revec_analyzer()}; }; diff --git a/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.cc b/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.cc index 5938a6dd34ae..ab5d6c262706 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.cc +++ b/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.cc @@ -540,6 +540,7 @@ void WasmShuffleAnalyzer::ProcessUnary(const Simd128UnaryOp& unop) { void WasmShuffleAnalyzer::ProcessBinary(const Simd128BinopOp& binop) { demanded_byte_analysis_.AddOp(binop, DemandedBytes::All()); + ProcessNarrowShuffle(binop); } void WasmShuffleAnalyzer::ProcessReplaceLane( @@ -972,6 +973,115 @@ void WasmShuffleAnalyzer::ProcessShuffle(const Simd128ShuffleOp& shuffle) { } } +namespace { + +template <int kNarrowedLaneBytes> + requires(kNarrowedLaneBytes == kInt8Size || kNarrowedLaneBytes == kInt16Size) +std::array<uint8_t, kSimd128Size> GetNarrowShuffleMask( + const std::array<uint8_t, kSimd128HalfSize>& lower_lanes, + const std::array<uint8_t, kSimd128HalfSize>& upper_lanes) { + std::array<uint8_t, kSimd128Size> replacement_mask{}; + + auto write_mask_half = [&](const std::array<uint8_t, kSimd128HalfSize>& lanes, + const int output_byte_offset) { + // Number of lanes after both inputs' lowest eight bytes were widened. + constexpr int lanes_per_input = kSimd128HalfSize / kNarrowedLaneBytes; + + for (int output_lane = 0; output_lane < lanes_per_input; ++output_lane) { + const uint8_t source_lane = lanes[output_lane]; + + // Second widened vector's indices start after the first's indices. + const uint8_t source_offset = + source_lane < lanes_per_input + ? source_lane * kNarrowedLaneBytes + : kSimd128Size + + (source_lane - lanes_per_input) * kNarrowedLaneBytes; + + const int replacement_byte_offset = + output_byte_offset + (output_lane * kNarrowedLaneBytes); + + // Select each byte of the original lane. + for (int byte = 0; byte < kNarrowedLaneBytes; ++byte) { + replacement_mask[replacement_byte_offset + byte] = source_offset + byte; + } + } + }; + + write_mask_half(lower_lanes, 0); + write_mask_half(upper_lanes, kSimd128HalfSize); + + return replacement_mask; +} + +} // namespace + +// Reduce low-half widens, lower/upper-half shuffles and narrowing with the +// same signedness into one shuffle of the byte or half-word inputs. +void WasmShuffleAnalyzer::ProcessNarrowShuffle(const Simd128BinopOp& binop) { + Simd128UnaryOp::Kind low_widen_kind; + switch (binop.kind) { + case Simd128BinopOp::Kind::kI8x16SConvertI16x8: + low_widen_kind = Simd128UnaryOp::Kind::kI16x8SConvertI8x16Low; + break; + case Simd128BinopOp::Kind::kI8x16UConvertI16x8: + low_widen_kind = Simd128UnaryOp::Kind::kI16x8UConvertI8x16Low; + break; + case Simd128BinopOp::Kind::kI16x8SConvertI32x4: + low_widen_kind = Simd128UnaryOp::Kind::kI32x4SConvertI16x8Low; + break; + case Simd128BinopOp::Kind::kI16x8UConvertI32x4: + low_widen_kind = Simd128UnaryOp::Kind::kI32x4UConvertI16x8Low; + break; + default: + return; + } + + const Graph& graph = input_graph(); + const auto* lower = graph.Get(binop.left()).TryCast<Simd128ShuffleOp>(); + const auto* upper = graph.Get(binop.right()).TryCast<Simd128ShuffleOp>(); + if (!lower || !upper || lower->kind != Simd128ShuffleOp::Kind::kI8x16 || + upper->kind != Simd128ShuffleOp::Kind::kI8x16 || + lower->left() != upper->left() || lower->right() != upper->right()) { + return; + } + + const auto* ext1 = graph.Get(lower->left()).TryCast<Simd128UnaryOp>(); + const auto* ext2 = graph.Get(lower->right()).TryCast<Simd128UnaryOp>(); + // Check the low-half widens' width and signedness matches the narrowing op. + if (!ext1 || !ext2 || ext1->kind != low_widen_kind || + ext2->kind != low_widen_kind) { + return; + } + + const uint8_t* lower_indices = lower->shuffle.data(); + const uint8_t* upper_indices = upper->shuffle.data(); + + std::array<uint8_t, kSimd128HalfSize> lower_mask{}; + std::array<uint8_t, kSimd128HalfSize> upper_mask{}; + std::array<uint8_t, kSimd128Size> replacement_mask{}; + + if (low_widen_kind == Simd128UnaryOp::Kind::kI16x8SConvertI8x16Low || + low_widen_kind == Simd128UnaryOp::Kind::kI16x8UConvertI8x16Low) { + if (!SimdShuffle::TryMatch16x8Shuffle(lower_indices, lower_mask.data()) || + !SimdShuffle::TryMatch16x8Shuffle(upper_indices, upper_mask.data())) { + return; + } + + replacement_mask = GetNarrowShuffleMask<kInt8Size>(lower_mask, upper_mask); + } else { + if (!SimdShuffle::TryMatch32x4Shuffle(lower_indices, lower_mask.data()) || + !SimdShuffle::TryMatch32x4Shuffle(upper_indices, upper_mask.data())) { + return; + } + + replacement_mask = GetNarrowShuffleMask<kInt16Size>(lower_mask, upper_mask); + } + + narrow_shuffle_candidates_.push_back({input_graph().Index(binop), + ext1->input(), ext2->input(), + replacement_mask}); +} + #undef TRACE } // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h b/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h index a885df3530b6..f7e596a309eb 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h +++ b/deps/v8/src/compiler/turboshaft/wasm-shuffle-reducer.h @@ -39,6 +39,13 @@ using SmallShuffleVector = SmallZoneVector<const Simd128ShuffleOp*, 8>; // required width of the shuffle can be further reduced. // If a shuffle is only used by a shuffle which only uses half of a shuffle // input, that input shuffle can also reduced. +// If lower and upper shuffles are used between the widening and narrowing of +// two vectors whose elements are bytes or half-words, with equal shuffle and +// widening widths, equal signedness of the widening and narrowing instructions +// and the shuffles preserve whole widened lanes, this can be replaced with a +// mask operating on byte indices. The upper shuffle only operates on the upper +// half of the lanes that extend the signedness, causing the widen and narrow +// operations to be redundant too. // Used by the analysis to search back from uses to their defs, looking for // shuffles that could be reduced. @@ -307,6 +314,13 @@ class WasmShuffleAnalyzer { const Simd128ShuffleOp& odd_shfop; }; + struct NarrowShuffleCandidate { + OpIndex narrow; + OpIndex left; + OpIndex right; + std::array<uint8_t, kSimd128Size> shuffle; + }; + // To represent a shuffle that has one, or more, shuffles as inputs, or a // shuffle that is used by another shuffle. class ShuffleWindow { @@ -463,6 +477,14 @@ class WasmShuffleAnalyzer { return {}; } + std::optional<NarrowShuffleCandidate> GetNarrowShuffleCandidate( + OpIndex node) const { + for (auto& candidate : narrow_shuffle_candidates_) { + if (candidate.narrow == node) return candidate; + } + return {}; + } + WasmShuffleAnalyzer(Zone* phase_zone, const Graph& input_graph) : phase_zone_(phase_zone), input_graph_(input_graph) {} @@ -482,10 +504,12 @@ class WasmShuffleAnalyzer { bool ProcessShuffleOfShuffle(const Simd128ShuffleOp& shuffle_op, const Simd128ShuffleOp& shuffle, const ShuffleSide side); + void ProcessNarrowShuffle(const Simd128BinopOp& binop); bool ShouldReduce() const { return !demanded_byte_analysis_.demanded_bytes().empty() || - !dot_candidates_.empty() || !deinterleave_load_candidates_.empty() || + !dot_candidates_.empty() || !narrow_shuffle_candidates_.empty() || + !deinterleave_load_candidates_.empty() || !load_lane_candidates_.empty() || !shuffles_to_read_shifted_.empty() || !shuffles_to_shift_.empty(); } @@ -591,6 +615,7 @@ class WasmShuffleAnalyzer { base::SmallVector<DeinterleaveLoadCandidate, 8> deinterleave_load_candidates_; ZoneUnorderedSet<OpIndex> dot_candidate_nodes_{phase_zone_}; base::SmallVector<DotCandidate, 4> dot_candidates_; + base::SmallVector<NarrowShuffleCandidate, 4> narrow_shuffle_candidates_; }; template <class Next> @@ -668,6 +693,14 @@ class WasmShuffleReducer : public Next { Simd128BinopOp::Kind::kI32x4DotI8x16S); } + if (const std::optional<WasmShuffleAnalyzer::NarrowShuffleCandidate> + maybe_shuffle = analyzer_->GetNarrowShuffleCandidate(ig_index)) { + return __ Simd128Shuffle(__ MapToNewGraph(maybe_shuffle->left), + __ MapToNewGraph(maybe_shuffle->right), + Simd128ShuffleOp::Kind::kI8x16, + maybe_shuffle->shuffle); + } + goto no_change; } diff --git a/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h b/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h index 1e95485f25de..56a3d5d93b02 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h +++ b/deps/v8/src/compiler/turboshaft/wasm-wrappers-inl.h @@ -69,7 +69,7 @@ auto WasmWrapperTSGraphBuilder<Assembler>::BuildToJSFunctionRef( V<WasmFuncRef> ret, V<Context> context) -> V<Object> { V<WasmInternalFunction> internal = V<WasmInternalFunction>::Cast( __ LoadTrustedPointer(ret, LoadOp::Kind::TaggedBase(), - kWasmInternalFunctionIndirectPointerTag, + kWasmInternalFunctionTrustedPointerTag, offsetof(WasmFuncRef, trusted_internal_))); V<Object> maybe_external = __ Load(internal, LoadOp::Kind::TaggedBase(), MemoryRepresentation::TaggedPointer(), @@ -86,25 +86,6 @@ auto WasmWrapperTSGraphBuilder<Assembler>::BuildToJSFunctionRef( return result; } -template <typename Assembler> -void WasmWrapperTSGraphBuilder<Assembler>::CheckAndConvertSharedString( - V<Object> ret, ScopedVar<Object>& result) { - IF (__ IsSmi(ret)) { - result = ret; - } ELSE { - V<Word32> instance_type = __ LoadInstanceTypeField(__ LoadMapField(ret)); - V<Word32> is_string = __ Uint32LessThan( - instance_type, __ Word32Constant(FIRST_NONSTRING_TYPE)); - IF (is_string) { - // Since this is a shared externref, the string will be shared. - result = __ WasmCallRuntime(__ phase_zone(), Runtime::kWasmWasmToJSObject, - {ret}, __ NoContextConstant()); - } ELSE { - result = ret; - } - } -} - template <typename Assembler> auto WasmWrapperTSGraphBuilder<Assembler>::ToJS(OpIndex ret, CanonicalValueType type, @@ -150,39 +131,84 @@ auto WasmWrapperTSGraphBuilder<Assembler>::ToJS(OpIndex ret, // Always null. if (type.is_none_type()) return __ template LoadRoot<RootIndex::kNullValue>(); - if (wasm::IsSubtypeOf(type, wasm::kWasmSharedExternRef)) { - // We have to unshare shared strings before passing them to JS. - ScopedVar<Object> result(this, OpIndex::Invalid()); - CheckAndConvertSharedString(ret, result); - return result; + Label<Object> done(&Asm()); + Label<> runtime(&Asm()); + + bool is_abs = type.is_abstract_ref(); + bool is_any = is_abs && type.generic_kind() == GenericKind::kAny; + bool is_eq = is_abs && type.generic_kind() == GenericKind::kEq; + bool is_i31 = is_abs && type.generic_kind() == GenericKind::kI31; + bool is_struct = is_abs && type.generic_kind() == GenericKind::kStruct; + bool is_extern = is_abs && type.generic_kind() == GenericKind::kExtern; + + bool can_be_smi = is_any || is_eq || is_i31 || is_extern; + + bool can_be_shared_string = + wasm::IsSubtypeOf(type, wasm::kWasmSharedExternRef) || + (type.is_shared() && is_any); + + bool must_be_descriptor = + type.has_index() && + wasm::GetTypeCanonicalizer()->is_descriptor(type.ref_index()); + bool can_be_descriptor = must_be_descriptor || is_any || is_eq || is_struct; + + if (can_be_smi) { + GOTO_IF(__ IsSmi(ret), done, ret); + } + if (type.is_nullable() && type.use_wasm_null()) { + GOTO_IF(__ TaggedEqual(ret, __ template LoadRoot<RootIndex::kWasmNull>()), + done, __ template LoadRoot<RootIndex::kNullValue>()); + } + +#ifdef V8_IS_TSAN + if (v8_flags.wasm_shared) { + // Unshared anyref can hold shared objects. + // TODO(jkummerow): ...but only when they came from any.convert_extern, + // which means we would have previously applied the barrier on the + // preceding to-extern conversion; so "|| is_any" is unnecessary here? + if (type.is_shared() || is_any) { + __ WasmCallRuntime(__ phase_zone(), + Runtime::kTsanAcquireForInitializationFence, {ret}, + __ NoContextConstant(), CanThrow{false}); + } } +#endif // V8_IS_TSAN - if (type.is_reference_to(GenericKind::kAny) && type.is_shared()) { - ScopedVar<Object> result(this, OpIndex::Invalid()); - if (type.is_nullable()) { - IF (__ TaggedEqual(ret, __ template LoadRoot<RootIndex::kWasmNull>())) { - result = __ template LoadRoot<RootIndex::kNullValue>(); - } ELSE { - CheckAndConvertSharedString(ret, result); - } - } else { - CheckAndConvertSharedString(ret, result); + // If we don't need the instance type, the load will be eliminated. + V<Word32> instance_type = __ LoadInstanceTypeField(__ LoadMapField(ret)); + + // We have to unshare shared strings before passing them to JS. + if (can_be_shared_string) { + V<Word32> is_string = __ Uint32LessThan( + instance_type, __ Word32Constant(FIRST_NONSTRING_TYPE)); + GOTO_IF(is_string, runtime); + } + + // Indexed and generic types that could be a descriptor struct have to + // check for {ret} being a descriptor, and load its JS wrapper if so. + if (v8_flags.wasm_merged_descriptors && can_be_descriptor) { + if (!must_be_descriptor) { + GOTO_IF_NOT(__ Word32Equal(instance_type, WASM_CUSTOM_MAP_TYPE), done, + ret); } - return result; + // At this point, it's guaranteed that {ret} is a WasmCustomMap. + V<HeapObject> maybe_wrapper = __ Load(ret, LoadOp::Kind::TaggedBase(), + MemoryRepresentation::TaggedPointer(), + offsetof(WasmCustomMap, js_wrapper_)); + // The wrapper is lazily created on first use. + V<Word32> no_wrapper = __ TaggedEqual( + maybe_wrapper, __ template LoadRoot<RootIndex::kNullValue>()); + GOTO_IF(UNLIKELY(no_wrapper), runtime); + GOTO(done, maybe_wrapper); + } else { + GOTO(done, ret); } - // At this point, we only have to process WasmNull. - // These two cases are never WasmNull. - if (!type.is_nullable()) return ret; - if (!type.use_wasm_null()) return ret; + BIND(runtime); + GOTO(done, __ WasmCallRuntime(__ phase_zone(), Runtime::kWasmWasmToJSObject, + {ret}, __ NoContextConstant())); - // Nullable reference. Convert WasmNull if needed. - ScopedVar<Object> result(this, OpIndex::Invalid()); - IF_NOT (__ TaggedEqual(ret, __ template LoadRoot<RootIndex::kWasmNull>())) { - result = ret; - } ELSE { - result = __ template LoadRoot<RootIndex::kNullValue>(); - } + BIND(done, result); return result; } @@ -353,7 +379,7 @@ auto WasmWrapperTSGraphBuilder<Assembler>::BuildJSToWasmWrapper( V<WasmFunctionData> function_data = V<WasmFunctionData>::Cast(__ LoadTrustedPointer( sfi, LoadOp::Kind::TaggedBase().Immutable(), - kWasmExportedFunctionDataIndirectPointerTag, + kWasmExportedFunctionDataTrustedPointerTag, offsetof(SharedFunctionInfo, trusted_function_data_))); V<WasmInternalFunction> internal = V<WasmInternalFunction>::Cast(__ LoadProtectedPointerField( @@ -412,37 +438,12 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildWasmToJSWrapper( return; } - V<Undefined> undefined_node = - __ template LoadRoot<RootIndex::kUndefinedValue>(); - int pushed_count = std::max(expected_arity, wasm_count); - // 5 extra arguments: receiver, new target, arg count, dispatch handle and - // context. - bool has_dispatch_handle = kind == wasm::ImportCallKind::kUseCallBuiltin - ? false - : V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL; - base::SmallVector<OpIndex, 16> args(pushed_count + 4 + - (has_dispatch_handle ? 1 : 0)); - SBXCHECK_LT( - args.size(), - std::numeric_limits< - decltype(compiler::turboshaft::Operation::input_count)>::max()); - // Position of the first wasm argument in the JS arguments. - int pos = kind == wasm::ImportCallKind::kUseCallBuiltin ? 3 : 1; - pos = AddArgumentNodes(base::VectorOf(args), pos, wasm_params, sig_, - native_context); - for (int i = wasm_count; i < expected_arity; ++i) { - args[pos++] = undefined_node; - } - - V<JSFunction> callable_node = __ Load(ref, LoadOp::Kind::TaggedBase(), - MemoryRepresentation::TaggedPointer(), - offsetof(WasmImportData, callable_)); auto [old_sp, old_limit] = this->BuildSwitchToTheCentralStackIfNeeded(); OpIndex suspender = OpIndex::Invalid(); if (suspend == wasm::kSuspend) { - suspender = __ Load(__ LoadRootRegister(), LoadOp::Kind::RawAligned(), - MemoryRepresentation::AnyUncompressedTagged(), - IsolateData::active_suspender_offset()); + suspender = __ Load(__ IsolateField(IsolateFieldId::kActiveSuspender), + LoadOp::Kind::RawAligned(), + MemoryRepresentation::AnyUncompressedTagged()); if (v8_flags.stress_wasm_stack_switching) { V<Word32> for_stress_testing = __ TaggedEqual( @@ -482,6 +483,43 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildWasmToJSWrapper( } } + // Check that the central stack has enough space for the outgoing parameters. + V<WordPtr> stack_limit = + __ Load(__ IsolateField(IsolateFieldId::kRealJsLimit), + LoadOp::Kind::RawAligned().NotLoadEliminable(), + MemoryRepresentation::UintPtr()); + IF_NOT (LIKELY( + __ StackPointerGreaterThan(stack_limit, StackCheckKind::kWasm))) { + __ WasmCallRuntime(__ phase_zone(), Runtime::kThrowStackOverflow, {}, + native_context); + __ Unreachable(); + } + + V<Undefined> undefined_node = + __ template LoadRoot<RootIndex::kUndefinedValue>(); + int pushed_count = std::max(expected_arity, wasm_count); + // 5 extra arguments: receiver, new target, arg count, dispatch handle and + // context. + bool has_dispatch_handle = kind == wasm::ImportCallKind::kUseCallBuiltin + ? false + : V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL; + base::SmallVector<OpIndex, 16> args(pushed_count + 4 + + (has_dispatch_handle ? 1 : 0)); + SBXCHECK_LT( + args.size(), + std::numeric_limits< + decltype(compiler::turboshaft::Operation::input_count)>::max()); + // Position of the first wasm argument in the JS arguments. + int pos = kind == wasm::ImportCallKind::kUseCallBuiltin ? 3 : 1; + pos = AddArgumentNodes(base::VectorOf(args), pos, wasm_params, sig_, + native_context); + for (int i = wasm_count; i < expected_arity; ++i) { + args[pos++] = undefined_node; + } + + V<JSFunction> callable_node = __ Load(ref, LoadOp::Kind::TaggedBase(), + MemoryRepresentation::TaggedPointer(), + offsetof(WasmImportData, callable_)); OpIndex call = OpIndex::Invalid(); switch (kind) { // ======================================================================= @@ -489,7 +527,8 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildWasmToJSWrapper( // ======================================================================= case wasm::ImportCallKind::kJSFunction: { auto call_descriptor = compiler::Linkage::GetJSCallDescriptor( - __ graph_zone(), false, pushed_count + 1, CallDescriptor::kNoFlags); + __ graph_zone(), false, pushed_count + 1, + JSParameterCount(expected_arity), CallDescriptor::kNoFlags); const TSCallDescriptor* ts_call_descriptor = TSCallDescriptor::Create( call_descriptor, compiler::CanThrow{true}, compiler::LazyDeoptOnThrow{false}, __ graph_zone()); @@ -595,11 +634,14 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildWasmStackEntryWrapper() { __ Load(stack_metadata, LoadOp::Kind::RawAligned(), MemoryRepresentation::UncompressedTaggedPointer(), wasm::StackMemory::func_ref_offset()); - AbortIfNot(__ HasInstanceType(func_ref, WASM_FUNC_REF_TYPE), - AbortReason::kUnexpectedInstanceType); + // A a shared wasm object could flow here, but we don't need to mark it as + // shared for TSAN purposes, because we already did so when it flowed into JS. + AbortIfNot( + __ HasInstanceType(func_ref, WASM_FUNC_REF_TYPE, SharedFlag{false}), + AbortReason::kUnexpectedInstanceType); V<WasmInternalFunction> internal_function = V<WasmInternalFunction>::Cast( __ LoadTrustedPointer(func_ref, LoadOp::Kind::TaggedBase().Immutable(), - kWasmInternalFunctionIndirectPointerTag, + kWasmInternalFunctionTrustedPointerTag, offsetof(WasmFuncRef, trusted_internal_))); auto [target, instance] = this->BuildFunctionTargetAndImplicitArg(internal_function); @@ -686,16 +728,15 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildCapiCallWrapper() { V<WasmFunctionData> function_data = V<WasmFunctionData>::Cast(__ LoadTrustedPointer( shared, LoadOp::Kind::TaggedBase(), - kWasmCapiFunctionDataIndirectPointerTag, + kWasmCapiFunctionDataTrustedPointerTag, offsetof(SharedFunctionInfo, trusted_function_data_))); V<Object> host_data_foreign = __ LoadTaggedField( function_data, offsetof(WasmCapiFunctionData, embedder_data_)); - OpIndex isolate_root = __ LoadRootRegister(); + V<WordPtr> c_entry_fp = __ IsolateField(IsolateFieldId::kCEntryFP); OpIndex fp_value = __ FramePointer(); - __ Store(isolate_root, fp_value, StoreOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), compiler::kNoWriteBarrier, - Isolate::c_entry_fp_offset()); + __ Store(c_entry_fp, fp_value, StoreOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr(), compiler::kNoWriteBarrier); V<WordPtr> call_target = BuildLoadCallTargetFromExportedFunctionData(function_data); @@ -768,7 +809,7 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildCWasmEntryWrapper() { V<WasmTrustedInstanceData> instance_data = V<WasmTrustedInstanceData>::Cast( __ LoadTrustedPointer(V<HeapObject>::Cast(object_ref), LoadOp::Kind::TaggedBase().Immutable(), - kWasmTrustedInstanceDataIndirectPointerTag, + kWasmTrustedInstanceDataTrustedPointerTag, offsetof(WasmInstanceObject, trusted_data_))); args[pos++] = instance_data; @@ -831,9 +872,10 @@ void WasmWrapperTSGraphBuilder<Assembler>::BuildJSFastApiCallWrapper( V<NativeContext> native_context = __ template LoadTaggedField<NativeContext>( import_data, offsetof(WasmImportData, native_context_)); - __ StoreOffHeap(__ LoadRootRegister(), + V<WordPtr> context_address = __ IsolateField(IsolateFieldId::kContext); + __ StoreOffHeap(context_address, __ BitcastHeapObjectToWordPtr(native_context), - MemoryRepresentation::UintPtr(), Isolate::context_offset()); + MemoryRepresentation::UintPtr()); Tagged<JSFunction> target; V<JSFunction> target_node; diff --git a/deps/v8/src/compiler/turboshaft/wasm-wrappers.h b/deps/v8/src/compiler/turboshaft/wasm-wrappers.h index e4376ecfbc9e..ba2fdae2c90f 100644 --- a/deps/v8/src/compiler/turboshaft/wasm-wrappers.h +++ b/deps/v8/src/compiler/turboshaft/wasm-wrappers.h @@ -122,8 +122,6 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { V<Object> ConvertWasmResultsToJS(base::Vector<OpIndex> returns, V<Context> js_context); - void CheckAndConvertSharedString(V<Object> ret, ScopedVar<Object>& result); - // Overload for the inlined JS-to-Wasm wrapper. // Returns the result of the Wasm function converted to a JS value. V<Any> BuildJSToWasmWrapper(V<JSFunction> js_closure, V<Context> js_context, @@ -166,7 +164,10 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { __ Goto(done); __ Bind(not_null); } - V<Map> map = LoadMap(input); + // We might be passed a shared object. However, since such object can only + // originate from Wasm for now, and we (plan to) put a barrier on the + // Wasm->JS transition, we do not need another one here. + V<Map> map = LoadMap(input, SharedFlag{false}); V<Word32> instance_type = __ LoadInstanceTypeField(map); V<Word32> check = __ Uint32LessThan( instance_type, __ Word32Constant(FIRST_NONSTRING_TYPE)); @@ -185,6 +186,8 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { // otherwise jumps to `not_i31`. void CanonicalizeHeapNumber(V<HeapNumber> input, Block* not_i31, ScopedVar<Object>& result) { + // The heap number might be shared, but we already checked its map, so no + // need to mark the Load as shared here. V<Float64> float_value = __ LoadHeapNumberValue(input); // Check if value is integral. @@ -262,22 +265,20 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { } else { __ GotoIfNot(__ WordPtrEqual(page_flags, 0), type_error); } -#ifdef DEBUG #if CONTIGUOUS_COMPRESSED_READ_ONLY_SPACE_BOOL // Wasm GC objects (structs/arrays) are currently never allocated in // read-only space. Verify this invariant to guard against future changes // where constant Wasm objects might be placed in RO space. - V<Word32> lower32 = __ TruncateWordPtrToWord32( - __ BitcastTaggedToWordPtr(V<HeapObject>::Cast(input))); // TSA_DCHECK is only usable in isolate-dependent code. if (__ data()->isolate() != nullptr) { - TSA_DCHECK(this, __ Uint32LessThanOrEqual( - __ Word32Constant(static_cast<uint32_t>( - kContiguousReadOnlyReservationSize)), - lower32)); + TSA_DCHECK(this, + __ Uint32LessThanOrEqual( + __ Word32Constant(static_cast<uint32_t>( + kContiguousReadOnlyReservationSize)), + __ TruncateWordPtrToWord32(__ BitcastTaggedToWordPtr( + V<HeapObject>::Cast(input))))); } #endif // CONTIGUOUS_COMPRESSED_READ_ONLY_SPACE_BOOL -#endif // DEBUG } } @@ -352,7 +353,10 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { __ GotoIf(__ IsSmi(input), process_smi); - __ GotoIf(__ HasInstanceType(input, HEAP_NUMBER_TYPE), process_heap_number); + // A shared object could flow here. + __ GotoIf(__ HasInstanceType(input, HEAP_NUMBER_TYPE, + SharedFlag{v8_flags.wasm_shared}), + process_heap_number); __ Goto(ensure_sharedness); @@ -408,7 +412,8 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { __ GotoIf(__ IsSmi(input), check_number); - V<Map> map = LoadMap(input); + // We might be passed a shared object. + V<Map> map = LoadMap(input, SharedFlag{v8_flags.wasm_shared}); V<Word32> instance_type = __ LoadInstanceTypeField(map); V<Word32> is_wasm_object = __ Word32BitwiseOr(__ Word32Equal(instance_type, WASM_STRUCT_TYPE), @@ -440,7 +445,10 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { CheckSmiInI31Range(V<Smi>::Cast(input), done, type_error, result); __ Bind(is_heap_object); - __ GotoIfNot(__ HasInstanceType(input, HEAP_NUMBER_TYPE), type_error); + // A shared object could flow here. + __ GotoIfNot(__ HasInstanceType(input, HEAP_NUMBER_TYPE, + SharedFlag{v8_flags.wasm_shared}), + type_error); CanonicalizeHeapNumber(V<HeapNumber>::Cast(input), type_error, result); __ Goto(done); @@ -487,7 +495,7 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { done); } - V<Map> map = LoadMap(input); + V<Map> map = LoadMap(input, SharedFlag{v8_flags.wasm_shared}); V<Word32> is_wasm_object_of_instance_type = __ Word32Equal(__ LoadInstanceTypeField(map), instance_type); __ GotoIfNot(is_wasm_object_of_instance_type, type_error, @@ -523,7 +531,7 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { done); } - V<Map> object_map = LoadMap(input); + V<Map> object_map = LoadMap(input, SharedFlag{v8_flags.wasm_shared}); // Fetch the canonical-types array from isolate roots. V<WeakFixedArray> canonical_rtts = __ template LoadRoot<RootIndex::kWasmCanonicalRtts>(); @@ -610,7 +618,10 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { // is a valid optimization so we conservatively keep it. result = __ ChangeInt32ToFloat32(__ UntagSmi(V<Smi>::Cast(value))); } ELSE { - V<Map> map = LoadMap(value); + // A a shared wasm object could flow here, but we don't need to mark it as + // shared for TSAN purposes, because we already did so when it flowed into + // JS. + V<Map> map = LoadMap(value, SharedFlag{false}); // TODO(thibaudm): Handle map packing. V<Word32> is_heap_number = __ IsHeapNumberMap(map); if (caller_frame_state.valid()) { @@ -645,7 +656,10 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { IF (__ IsSmi(value)) { result = __ ChangeInt32ToFloat64(__ UntagSmi(V<Smi>::Cast(value))); } ELSE { - V<Map> map = LoadMap(value); + // A a shared wasm object could flow here, but we don't need to mark it as + // shared for TSAN purposes, because we already did so when it flowed into + // JS. + V<Map> map = LoadMap(value, SharedFlag{false}); // TODO(thibaudm): Handle map packing. V<Word32> is_heap_number = __ IsHeapNumberMap(map); if (caller_frame_state.valid()) { @@ -869,9 +883,9 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { inputs, context); } - V<Map> LoadMap(V<Object> object) { + V<Map> LoadMap(V<Object> object, SharedFlag shared_base) { // TODO(thibaudm): Handle map packing. - V<Map> map_word = __ LoadMapField(object); + V<Map> map_word = __ LoadMapField(object, shared_base); #ifdef V8_MAP_PACKING map_word = __ BitcastTaggedToWordPtrForTagAndSmiBits(map_word); // TODO(wenyuzhao): Clear header metadata. @@ -884,7 +898,6 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { #endif } - // Must be called in the first block to emit the Parameter ops. int AddArgumentNodes(base::Vector<OpIndex> args, int pos, base::SmallVector<OpIndex, 16> wasm_params, const wasm::CanonicalSig* sig, V<Context> context) { @@ -911,15 +924,16 @@ class WasmWrapperTSGraphBuilder : public wasm::WasmGraphBuilderBase<Assembler> { MemoryRepresentation::Int32(), offsetof(SharedFunctionInfo, flags_)); OpIndex strict_check = __ Word32BitwiseAnd( - flags, __ Word32Constant(SharedFunctionInfo::IsNativeBit::kMask | - SharedFunctionInfo::IsStrictBit::kMask)); + flags, + __ Word32Constant(SharedFunctionInfo::Flags::IsNativeBit::kMask | + SharedFunctionInfo::Flags::IsStrictBit::kMask)); // Load global receiver if sloppy else use undefined. ScopedVar<Object> strict_d(this, OpIndex::Invalid()); IF (strict_check) { strict_d = undefined_node; } ELSE { - V<Map> context_map = LoadMap(callee_context); + V<Map> context_map = LoadMap(callee_context, SharedFlag{false}); V<NativeContext> callee_native_context = __ template LoadField<NativeContext>( context_map, compiler::AccessBuilder::ForMapNativeContext()); diff --git a/deps/v8/src/compiler/verifier.cc b/deps/v8/src/compiler/verifier.cc index 39d2dbced497..8aab5f56cfde 100644 --- a/deps/v8/src/compiler/verifier.cc +++ b/deps/v8/src/compiler/verifier.cc @@ -1925,7 +1925,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { case IrOpcode::kStoreTrapOnNull: case IrOpcode::kStore: case IrOpcode::kStorePair: - case IrOpcode::kStoreIndirectPointer: + case IrOpcode::kStoreTrustedPointer: case IrOpcode::kStackSlot: case IrOpcode::kWord32And: case IrOpcode::kWord32Or: diff --git a/deps/v8/src/compiler/wasm-address-reassociation.cc b/deps/v8/src/compiler/wasm-address-reassociation.cc deleted file mode 100644 index 7f743a6f1c2a..000000000000 --- a/deps/v8/src/compiler/wasm-address-reassociation.cc +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2023 the V8 project 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 "src/compiler/wasm-address-reassociation.h" - -#include "src/compiler/common-operator.h" -#include "src/compiler/js-graph.h" -#include "src/compiler/machine-graph.h" -#include "src/compiler/machine-operator.h" -#include "src/compiler/node-matchers.h" -#include "src/compiler/node-properties.h" -#include "src/compiler/node.h" -#include "src/compiler/opcodes.h" -#include "src/compiler/operator.h" -#include "src/compiler/turbofan-graph.h" -#include "src/zone/zone.h" - -namespace v8 { -namespace internal { -namespace compiler { - -// Wasm address reassociation. -// -// wasm32 load and store operations use a 32-bit dynamic offset along with a -// 32-bit static index to create a 33-bit effective address. This means that -// to use a static index, greater than zero, the producer needs to prove that -// the addition of the index won't overflow. However, if we're performing -// address computations with 64-bits, we should be able to more readily use -// immediate indexes. -// -// So, the purpose of this transform is to pattern match certain address -// computations and reorganize the operands for more efficient code generation. -// -// Many addresses will be computed in the form like this: -// - TrappingLoad (IntPtrAdd (base_reg, immediate_offset), register_offset) -// - TrappingStore (IntPtrAdd (base_reg, immediate_offset), register_offset) - -// And this pass aims to transform this into: -// - TrappingLoad (IntPtrAdd (base_reg, register_offset), immediate_offset) -// - TrappingStore (IntPtrAdd (base_reg, register_offset), immediate_offset) -// -// This allows the reuse of a base pointer across multiple instructions, each of -// which then has the opportunity to use an immediate offset. - -WasmAddressReassociation::WasmAddressReassociation(JSGraph* jsgraph, Zone* zone) - : graph_(jsgraph->graph()), - common_(jsgraph->common()), - machine_(jsgraph->machine()), - candidate_base_addrs_(zone), - candidates_(zone), - zone_(zone) {} - -void WasmAddressReassociation::Optimize() { - for (auto& candidate : candidates_) { - const CandidateAddressKey& key = candidate.first; - if (!ShouldTryOptimize(key)) continue; - // We've found multiple instances of addresses in the form - // object(base + imm_offset), reg_offset - // So, create a new object for these operations to share and then use an - // immediate offset: - // object(base, reg_offset), imm_offset - Node* new_object = CreateNewBase(key); - CandidateMemOps& mem_ops = candidate.second; - size_t num_nodes = mem_ops.GetNumNodes(); - for (size_t i = 0; i < num_nodes; ++i) { - Node* mem_op = mem_ops.mem_op(i); - Node* imm_offset = - graph_->NewNode(common_->Int64Constant(mem_ops.imm_offset(i))); - ReplaceInputs(mem_op, new_object, imm_offset); - } - } -} - -bool WasmAddressReassociation::ShouldTryOptimize( - const CandidateAddressKey& key) const { - // We already process the graph in terms of effect chains in an attempt to - // reduce the risk of creating large live-ranges, but also set a lower - // bound for the number of required users so that the benefits are more - // likely to outweigh any detrimental affects, such as additions being shared - // and so the number of operations is increased. Benchmarking showed two or - // more was a good heuristic. - return candidates_.at(key).GetNumNodes() > 1; -} - -Node* WasmAddressReassociation::CreateNewBase(const CandidateAddressKey& key) { - CandidateBaseAddr& candidate_base_addr = candidate_base_addrs_.at(key); - Node* base = candidate_base_addr.base(); - Node* reg_offset = candidate_base_addr.offset(); - return graph_->NewNode(machine_->Int64Add(), base, reg_offset); -} - -void WasmAddressReassociation::ReplaceInputs(Node* mem_op, Node* base, - Node* offset) { - DCHECK_GT(mem_op->InputCount(), 1); - DCHECK(NodeProperties::IsConstant(offset)); - mem_op->ReplaceInput(0, base); - mem_op->ReplaceInput(1, offset); -} - -void WasmAddressReassociation::VisitTrappingMemOp(Node* node, - NodeId effect_chain) { - DCHECK(node->opcode() == IrOpcode::kTrappingLoad || - node->opcode() == IrOpcode::kTrappingStore); - - Node* base(node->InputAt(0)); - Node* offset(node->InputAt(1)); - - if (base->opcode() == IrOpcode::kInt64Add && - offset->opcode() == IrOpcode::kInt64Add) { - Int64BinopMatcher base_add(base); - Int64BinopMatcher offset_add(offset); - if (base_add.right().HasResolvedValue() && - !base_add.left().HasResolvedValue() && - offset_add.right().HasResolvedValue() && - !offset_add.left().HasResolvedValue()) { - Node* base_reg = base_add.left().node(); - Node* reg_offset = offset_add.left().node(); - int64_t imm_offset = - base_add.right().ResolvedValue() + offset_add.right().ResolvedValue(); - return AddCandidate(node, base_reg, reg_offset, imm_offset, effect_chain); - } - } - if (base->opcode() == IrOpcode::kInt64Add) { - Int64BinopMatcher base_add(base); - if (base_add.right().HasResolvedValue() && - !base_add.left().HasResolvedValue()) { - Node* base_reg = base_add.left().node(); - Node* reg_offset = node->InputAt(1); - int64_t imm_offset = base_add.right().ResolvedValue(); - return AddCandidate(node, base_reg, reg_offset, imm_offset, effect_chain); - } - } - if (offset->opcode() == IrOpcode::kInt64Add) { - Int64BinopMatcher offset_add(offset); - if (offset_add.right().HasResolvedValue() && - !offset_add.left().HasResolvedValue()) { - Node* base_reg = node->InputAt(0); - Node* reg_offset = offset_add.left().node(); - int64_t imm_offset = offset_add.right().ResolvedValue(); - return AddCandidate(node, base_reg, reg_offset, imm_offset, effect_chain); - } - } -} - -void WasmAddressReassociation::AddCandidate(Node* mem_op, Node* base, - Node* reg_offset, - int64_t imm_offset, - NodeId effect_chain) { - // Sort base and offset so that the key is the same for either permutation. - if (base->id() > reg_offset->id()) { - std::swap(base, reg_offset); - } - CandidateAddressKey key = - std::make_tuple(base->id(), reg_offset->id(), effect_chain); - bool is_new = - candidate_base_addrs_.emplace(key, CandidateBaseAddr(base, reg_offset)) - .second; - auto it = is_new ? candidates_.emplace(key, CandidateMemOps(zone_)).first - : candidates_.find(key); - it->second.AddCandidate(mem_op, imm_offset); -} - -bool WasmAddressReassociation::HasCandidateBaseAddr( - const CandidateAddressKey& key) const { - return candidate_base_addrs_.count(key); -} - -void WasmAddressReassociation::CandidateMemOps::AddCandidate( - Node* mem_op, int64_t imm_offset) { - DCHECK(mem_op->opcode() == IrOpcode::kTrappingLoad || - mem_op->opcode() == IrOpcode::kTrappingStore); - mem_ops_.push_back(mem_op); - imm_offsets_.push_back(imm_offset); -} - -size_t WasmAddressReassociation::CandidateMemOps::GetNumNodes() const { - DCHECK_EQ(mem_ops_.size(), imm_offsets_.size()); - return mem_ops_.size(); -} - -Node* WasmAddressReassociation::CandidateMemOps::mem_op(size_t i) const { - return mem_ops_[i]; -} - -int64_t WasmAddressReassociation::CandidateMemOps::imm_offset(size_t i) const { - return imm_offsets_[i]; -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/compiler/wasm-address-reassociation.h b/deps/v8/src/compiler/wasm-address-reassociation.h deleted file mode 100644 index ce153023f116..000000000000 --- a/deps/v8/src/compiler/wasm-address-reassociation.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2023 the V8 project 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 V8_COMPILER_WASM_ADDRESS_REASSOCIATION_H_ -#define V8_COMPILER_WASM_ADDRESS_REASSOCIATION_H_ - -#include "src/compiler/node-marker.h" -#include "src/zone/zone-containers.h" - -namespace v8 { -namespace internal { - -namespace compiler { - -// Forward declarations. -class CommonOperatorBuilder; -class TFGraph; -class JSGraph; -class MachineOperatorBuilder; -class Node; - -class V8_EXPORT_PRIVATE WasmAddressReassociation final { - public: - WasmAddressReassociation(JSGraph* jsgraph, Zone* zone); - WasmAddressReassociation(const WasmAddressReassociation&) = delete; - WasmAddressReassociation& operator=(const WasmAddressReassociation&) = delete; - - void Optimize(); - void VisitTrappingMemOp(Node* node, NodeId effect_chain); - - private: - // Use the ids of nodes that represent a base and offset, together with an - // effect-chain root node id, to create a key for our candidate maps. - using CandidateAddressKey = std::tuple<NodeId, NodeId, NodeId>; - - // Holds two nodes that could be summed to create a new base address. We - // store these in a map accessed with the above key. - class CandidateBaseAddr { - public: - CandidateBaseAddr(Node* base, Node* offset) - : base_reg_(base), offset_reg_(offset) {} - Node* base() const { return base_reg_; } - Node* offset() const { return offset_reg_; } - - private: - Node* base_reg_; - Node* offset_reg_; - }; - - // For a given CandidateBaseAddr, collect loads and stores that could use the - // shared object along an immediate index. These are collected in a map which - // is accessed with a CandidateAddressKey. - class CandidateMemOps : ZoneObject { - public: - explicit CandidateMemOps(Zone* zone) : mem_ops_(zone), imm_offsets_(zone) {} - void AddCandidate(Node* mem_op, int64_t imm_offset); - size_t GetNumNodes() const; - Node* mem_op(size_t i) const; - int64_t imm_offset(size_t i) const; - - private: - ZoneVector<Node*> mem_ops_; - ZoneVector<int64_t> imm_offsets_; - }; - - bool ShouldTryOptimize(const CandidateAddressKey& key) const; - Node* CreateNewBase(const CandidateAddressKey& key); - bool HasCandidateBaseAddr(const CandidateAddressKey& key) const; - void AddCandidate(Node* mem_op, Node* base, Node* reg_offset, - int64_t imm_offset, NodeId effect_chain); - void ReplaceInputs(Node* mem_op, Node* object, Node* index); - - TFGraph* const graph_; - CommonOperatorBuilder* common_; - MachineOperatorBuilder* machine_; - ZoneMap<CandidateAddressKey, CandidateBaseAddr> candidate_base_addrs_; - ZoneMap<CandidateAddressKey, CandidateMemOps> candidates_; - Zone* const zone_; -}; - -} // namespace compiler -} // namespace internal -} // namespace v8 - -#endif // V8_COMPILER_WASM_ADDRESS_REASSOCIATION_H_ diff --git a/deps/v8/src/compiler/wasm-compiler-definitions.cc b/deps/v8/src/compiler/wasm-compiler-definitions.cc index 1c5225d62b46..2cebd7653924 100644 --- a/deps/v8/src/compiler/wasm-compiler-definitions.cc +++ b/deps/v8/src/compiler/wasm-compiler-definitions.cc @@ -4,6 +4,7 @@ #include "src/compiler/wasm-compiler-definitions.h" +#include <array> #include <optional> #include "src/base/strings.h" @@ -38,10 +39,9 @@ SubtypeCheckExactness GetExactness(const wasm::WasmModule* module, return SubtypeCheckExactness::kMayBeSubtype; } -base::Vector<const char> GetDebugName(Zone* zone, - const wasm::WasmModule* module, - const wasm::WireBytesStorage* wire_bytes, - int index) { +std::string_view GetDebugName(Zone* zone, const wasm::WasmModule* module, + const wasm::WireBytesStorage* wire_bytes, + int index) { std::optional<wasm::ModuleWireBytes> module_bytes = wire_bytes->GetModuleBytes(); if (module_bytes.has_value() && @@ -57,19 +57,19 @@ base::Vector<const char> GetDebugName(Zone* zone, int name_len = name.length(); char* index_name = zone->AllocateArray<char>(name_len); memcpy(index_name, module_bytes->start() + name.offset(), name_len); - return base::Vector<const char>(index_name, name_len); + return std::string_view(index_name, name_len); } } constexpr int kBufferLength = 24; - base::EmbeddedVector<char, kBufferLength> name_vector; - int name_len = SNPrintF(name_vector, "wasm-function#%d", index); + std::array<char, kBufferLength> name_vector; + int name_len = base::SNPrintF(name_vector, "wasm-function#%d", index); DCHECK(name_len > 0 && static_cast<size_t>(name_len) < name_vector.size()); char* index_name = zone->AllocateArray<char>(name_len); - memcpy(index_name, name_vector.begin(), name_len); - return base::Vector<const char>(index_name, name_len); + memcpy(index_name, name_vector.data(), name_len); + return std::string_view(index_name, name_len); } TrapId GetTrapIdForTrap(wasm::TrapReason reason) { diff --git a/deps/v8/src/compiler/wasm-compiler-definitions.h b/deps/v8/src/compiler/wasm-compiler-definitions.h index c9a380ecd182..bea2da4d2ea2 100644 --- a/deps/v8/src/compiler/wasm-compiler-definitions.h +++ b/deps/v8/src/compiler/wasm-compiler-definitions.h @@ -10,10 +10,10 @@ #endif // !V8_ENABLE_WEBASSEMBLY #include <ostream> +#include <string_view> #include "src/base/hashing.h" #include "src/base/strong-alias.h" -#include "src/base/vector.h" #include "src/codegen/linkage-location.h" #include "src/codegen/signature.h" #include "src/wasm/signature-hashing.h" @@ -112,10 +112,9 @@ std::ostream& operator<<(std::ostream& os, CheckForNull null_check); V8_EXPORT_PRIVATE TrapId GetTrapIdForTrap(wasm::TrapReason reason); -base::Vector<const char> GetDebugName(Zone* zone, - const wasm::WasmModule* module, - const wasm::WireBytesStorage* wire_bytes, - int index); +std::string_view GetDebugName(Zone* zone, const wasm::WasmModule* module, + const wasm::WireBytesStorage* wire_bytes, + int index); enum WasmCallKind { kWasmFunction, kWasmIndirectFunction, diff --git a/deps/v8/src/compiler/wasm-compiler.cc b/deps/v8/src/compiler/wasm-compiler.cc index 970ec9a9317f..a7fc631ab256 100644 --- a/deps/v8/src/compiler/wasm-compiler.cc +++ b/deps/v8/src/compiler/wasm-compiler.cc @@ -67,23 +67,6 @@ namespace v8::internal::compiler { namespace { -// Use MachineType::Pointer() over Tagged() to load root pointers because they -// do not get compressed. -#define LOAD_ROOT(RootName, factory_name) \ - (isolate_ ? graph()->NewNode(mcgraph()->common()->HeapConstant( \ - isolate_->factory()->factory_name())) \ - : gasm_->LoadImmutable( \ - MachineType::Pointer(), BuildLoadIsolateRoot(), \ - IsolateData::root_slot_offset(RootIndex::k##RootName))) - -template <typename T> -bool ContainsSimd(const Signature<T>* sig) { - for (auto type : sig->all()) { - if (type == wasm::kWasmS128) return true; - } - return false; -} - bool ContainsInt64(const wasm::CanonicalSig* sig) { for (auto type : sig->all()) { if (type == wasm::kWasmI64) return true; @@ -93,56 +76,9 @@ bool ContainsInt64(const wasm::CanonicalSig* sig) { } // namespace -WasmGraphBuilder::WasmGraphBuilder( - wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph, - const wasm::FunctionSig* sig, - compiler::SourcePositionTable* source_position_table, - ParameterMode parameter_mode, Isolate* isolate, - wasm::WasmEnabledFeatures enabled_features, - const wasm::CanonicalSig* wrapper_sig) - : gasm_(std::make_unique<WasmGraphAssembler>(mcgraph, zone)), - zone_(zone), - mcgraph_(mcgraph), - env_(env), - enabled_features_(enabled_features), - has_simd_(sig ? ContainsSimd(sig) : ContainsSimd(wrapper_sig)), - function_sig_(sig), - wrapper_sig_(wrapper_sig), - source_position_table_(source_position_table), - parameter_mode_(parameter_mode), - isolate_(isolate), - null_check_strategy_(trap_handler::IsTrapHandlerEnabled() && - V8_STATIC_ROOTS_BOOL - ? NullCheckStrategy::kTrapHandler - : NullCheckStrategy::kExplicit) { - // This code is only used for inlining js-to-wasm wrappers into - // Turbofan-compiled JS functions. - CHECK(parameter_mode != ParameterMode::kInstanceParameterMode); - - // There are two kinds of isolate-specific code: JS-to-JS wrappers (passing - // kNoSpecialParameterMode) and JS-to-Wasm wrappers (passing - // kJSFunctionAbiMode). - DCHECK_IMPLIES(isolate != nullptr, - parameter_mode_ == kJSFunctionAbiMode || - parameter_mode_ == kNoSpecialParameterMode); - DCHECK_IMPLIES(env && env->module && - std::any_of(env->module->memories.begin(), - env->module->memories.end(), - [](auto& memory) { - return memory.bounds_checks == - wasm::kTrapHandler; - }), - trap_handler::IsTrapHandlerEnabled()); - DCHECK_NOT_NULL(mcgraph_); -} - -// Destructor define here where the definition of {WasmGraphAssembler} is -// available. -WasmGraphBuilder::~WasmGraphBuilder() = default; - -bool WasmGraphBuilder::TryWasmInlining(int fct_index, - wasm::NativeModule* native_module, - int inlining_id) { +bool TryWasmInlining(int fct_index, wasm::NativeModule* native_module, + int inlining_id, MachineGraph* mcgraph, + SourcePositionTable* spt) { #define TRACE(x) \ do { \ if (v8_flags.trace_turbo_inlining) { \ @@ -176,9 +112,9 @@ bool WasmGraphBuilder::TryWasmInlining(int fct_index, inlinee.code.offset(), inlinee.code.end_offset())); const wasm::FunctionBody inlinee_body(inlinee.sig, inlinee.code.offset(), bytes.begin(), bytes.end()); - bool result = WasmIntoJSInliner::TryInlining( - graph()->zone(), module, mcgraph_, inlinee_body, bytes, - source_position_table_, inlining_id); + bool result = + WasmIntoJSInliner::TryInlining(mcgraph->graph()->zone(), module, mcgraph, + inlinee_body, bytes, spt, inlining_id); TRACE(( result ? "- inlining Wasm function" @@ -187,307 +123,253 @@ bool WasmGraphBuilder::TryWasmInlining(int fct_index, #undef TRACE } -void WasmGraphBuilder::Start(unsigned params) { - Node* start = graph()->NewNode(mcgraph()->common()->Start(params)); - graph()->SetStart(start); - SetEffectControl(start); - // Initialize parameter nodes. - parameters_ = zone_->AllocateArray<Node*>(params); - for (unsigned i = 0; i < params; i++) { - parameters_[i] = nullptr; - } - // Initialize instance node. - switch (parameter_mode_) { - case kInstanceParameterMode: { - Node* param = Param(wasm::kWasmInstanceDataParameterIndex); - if (v8_flags.debug_code) { - Assert(gasm_->HasInstanceType(param, WASM_TRUSTED_INSTANCE_DATA_TYPE), - AbortReason::kUnexpectedInstanceType); - } - instance_data_node_ = param; - break; - } - case kWasmImportDataMode: { - Node* param = Param(0); - if (v8_flags.debug_code) { - Assert(gasm_->HasInstanceType(param, WASM_IMPORT_DATA_TYPE), - AbortReason::kUnexpectedInstanceType); - } - instance_data_node_ = gasm_->LoadProtectedPointerFromObject( - param, offsetof(WasmImportData, protected_importing_instance_data_) - - kHeapObjectTag); - break; - } - case kJSFunctionAbiMode: { - Node* param = Param(Linkage::kJSCallClosureParamIndex, "%closure"); - if (v8_flags.debug_code) { - Assert(gasm_->HasInstanceTypeInRange(param, FIRST_JS_FUNCTION_TYPE, - LAST_JS_FUNCTION_TYPE), - AbortReason::kUnexpectedInstanceType); - } - instance_data_node_ = gasm_->LoadExportedFunctionInstanceData( - gasm_->LoadFunctionDataFromJSFunction(param)); - break; +template <typename T> +Signature<MachineRepresentation>* CreateMachineSignature( + Zone* zone, const Signature<T>* sig, wasm::CallOrigin origin) { + Signature<MachineRepresentation>::Builder builder(zone, sig->return_count(), + sig->parameter_count()); + for (auto ret : sig->returns()) { + if (origin == wasm::kCalledFromJS) { + builder.AddReturn(MachineRepresentation::kTagged); + } else { + builder.AddReturn(ret.machine_representation()); } - case kNoSpecialParameterMode: - break; } - graph()->SetEnd(graph()->NewNode(mcgraph()->common()->End(0))); -} -Node* WasmGraphBuilder::Param(int index, const char* debug_name) { - DCHECK_NOT_NULL(graph()->start()); - // Turbofan allows negative parameter indices. - DCHECK_GE(index, kMinParameterIndex); - int array_index = index - kMinParameterIndex; - if (parameters_[array_index] == nullptr) { - parameters_[array_index] = graph()->NewNode( - mcgraph()->common()->Parameter(index, debug_name), graph()->start()); + for (auto param : sig->parameters()) { + if (origin == wasm::kCalledFromJS) { + // Parameters coming from JavaScript are always tagged values. Especially + // when the signature says that it's an I64 value, then a BigInt object is + // provided by JavaScript, and not two 32-bit parameters. + builder.AddParam(MachineRepresentation::kTagged); + } else { + builder.AddParam(param.machine_representation()); + } } - return parameters_[array_index]; -} - -void WasmGraphBuilder::TerminateThrow(Node* effect, Node* control) { - Node* terminate = - graph()->NewNode(mcgraph()->common()->Throw(), effect, control); - gasm_->MergeControlToEnd(terminate); - gasm_->InitializeEffectControl(nullptr, nullptr); + return builder.Get(); } -Node* WasmGraphBuilder::NoContextConstant() { - return mcgraph()->IntPtrConstant(0); -} +template Signature<MachineRepresentation>* CreateMachineSignature( + Zone*, const Signature<wasm::ValueType>*, wasm::CallOrigin); +template Signature<MachineRepresentation>* CreateMachineSignature( + Zone*, const Signature<wasm::CanonicalValueType>*, wasm::CallOrigin); -Node* WasmGraphBuilder::BuildLoadIsolateRoot() { - return isolate_ ? mcgraph()->IntPtrConstant(isolate_->isolate_root()) - : gasm_->LoadRootRegister(); -} +namespace { -Node* WasmGraphBuilder::Int32Constant(int32_t value) { - return mcgraph()->Int32Constant(value); -} +class WasmWrapperGraphBuilder { + public: + WasmWrapperGraphBuilder(Zone* zone, MachineGraph* mcgraph, + const wasm::CanonicalSig* wrapper_sig, + Isolate* isolate) + : gasm_(mcgraph, zone), + zone_(zone), + mcgraph_(mcgraph), + wrapper_sig_(wrapper_sig), + isolate_(isolate) { + DCHECK_NOT_NULL(mcgraph_); + DCHECK_NOT_NULL(isolate_); + } -Node* WasmGraphBuilder::UndefinedValue() { - return LOAD_ROOT(UndefinedValue, undefined_value); -} + void Start(unsigned params) { + Node* start = graph()->NewNode(mcgraph_->common()->Start(params)); + graph()->SetStart(start); + SetEffectControl(start); + // Initialize parameter nodes. + parameters_ = zone_->AllocateArray<Node*>(params); + for (unsigned i = 0; i < params; i++) { + parameters_[i] = nullptr; + } + // Initialize closure check. + Node* param = Param(Linkage::kJSCallClosureParamIndex, "%closure"); + if (v8_flags.debug_code) { + Assert(gasm_.HasInstanceTypeInRange(param, FIRST_JS_FUNCTION_TYPE, + LAST_JS_FUNCTION_TYPE), + AbortReason::kUnexpectedInstanceType); + } + graph()->SetEnd(graph()->NewNode(mcgraph_->common()->End(0))); + } -Node* WasmGraphBuilder::Return(base::Vector<Node*> vals) { - unsigned count = static_cast<unsigned>(vals.size()); - base::SmallVector<Node*, 8> buf(count + 3); + Node* Param(int index, const char* debug_name = nullptr) { + DCHECK_NOT_NULL(graph()->start()); + // Turbofan allows negative parameter indices. + DCHECK_GE(index, kMinParameterIndex); + int array_index = index - kMinParameterIndex; + if (parameters_[array_index] == nullptr) { + parameters_[array_index] = graph()->NewNode( + mcgraph_->common()->Parameter(index, debug_name), graph()->start()); + } + return parameters_[array_index]; + } - // TODOC: What is the meaning of the 0-constant? - buf[0] = Int32Constant(0); - if (count > 0) { - memcpy(buf.data() + 1, vals.begin(), sizeof(void*) * count); + void TerminateThrow(Node* effect, Node* control) { + Node* terminate = + graph()->NewNode(mcgraph_->common()->Throw(), effect, control); + gasm_.MergeControlToEnd(terminate); + gasm_.InitializeEffectControl(nullptr, nullptr); } - buf[count + 1] = effect(); - buf[count + 2] = control(); - Node* ret = graph()->NewNode(mcgraph()->common()->Return(count), count + 3, - buf.data()); - gasm_->MergeControlToEnd(ret); - return ret; -} + Node* NoContextConstant() { return mcgraph_->IntPtrConstant(0); } -Node* WasmGraphBuilder::effect() { return gasm_->effect(); } + Node* BuildLoadIsolateRoot() { + return mcgraph_->IntPtrConstant(isolate_->isolate_root()); + } -Node* WasmGraphBuilder::control() { return gasm_->control(); } + Node* Int32Constant(int32_t value) { return mcgraph_->Int32Constant(value); } -Node* WasmGraphBuilder::SetEffect(Node* node) { - SetEffectControl(node, control()); - return node; -} + Node* UndefinedValue() { + return graph()->NewNode(mcgraph_->common()->HeapConstant( + isolate_->factory()->undefined_value())); + } -Node* WasmGraphBuilder::SetControl(Node* node) { - SetEffectControl(effect(), node); - return node; -} + Node* Return(Node* val) { + Node* buf[] = {Int32Constant(0), val, effect(), control()}; + Node* ret = graph()->NewNode(mcgraph_->common()->Return(1), 4, buf); + gasm_.MergeControlToEnd(ret); + return ret; + } -void WasmGraphBuilder::SetEffectControl(Node* effect, Node* control) { - gasm_->InitializeEffectControl(effect, control); -} + Node* effect() { return gasm_.effect(); } + Node* control() { return gasm_.control(); } -Node* WasmGraphBuilder::BuildCallNode(size_t param_count, - base::Vector<Node*> args, - Node* implicit_first_arg, - const Operator* op, Node* frame_state) { - needs_stack_check_ = true; - const size_t has_frame_state = frame_state != nullptr ? 1 : 0; - const size_t extra = 3; // instance_node, effect, and control. - const size_t count = 1 + param_count + extra + has_frame_state; - - // Reallocate the buffer to make space for extra inputs. - base::SmallVector<Node*, 16 + extra> inputs(count); - DCHECK_EQ(1 + param_count, args.size()); - - // Make room for the first argument at index 1, just after code. - inputs[0] = args[0]; // code - inputs[1] = implicit_first_arg; - if (param_count > 0) { - memcpy(&inputs[2], &args[1], param_count * sizeof(Node*)); + Node* SetEffect(Node* node) { + SetEffectControl(node, control()); + return node; } - // Add effect and control inputs. - if (has_frame_state != 0) inputs[param_count + 2] = frame_state; - inputs[param_count + has_frame_state + 2] = effect(); - inputs[param_count + has_frame_state + 3] = control(); + Node* SetControl(Node* node) { + SetEffectControl(effect(), node); + return node; + } - Node* call = graph()->NewNode(op, static_cast<int>(count), inputs.begin()); - // Return calls have no effect output. Other calls are the new effect node. - if (op->EffectOutputCount() > 0) SetEffect(call); + void SetEffectControl(Node* effect, Node* control) { + gasm_.InitializeEffectControl(effect, control); + } - return call; -} + Node* SetEffectControl(Node* effect_and_control) { + SetEffectControl(effect_and_control, effect_and_control); + return effect_and_control; + } -template <typename T> -Node* WasmGraphBuilder::BuildWasmCall(const Signature<T>* sig, - base::Vector<Node*> args, - base::Vector<Node*> rets, - Node* implicit_first_arg, bool indirect, - Node* frame_state) { - WasmCallKind call_kind = indirect ? kWasmIndirectFunction : kWasmFunction; - CallDescriptor* call_descriptor = GetWasmCallDescriptor( - mcgraph()->zone(), sig, call_kind, frame_state != nullptr); - const Operator* op = mcgraph()->common()->Call(call_descriptor); - Node* call = BuildCallNode(sig->parameter_count(), args, implicit_first_arg, - op, frame_state); - // TODO(manoskouk): These assume the call has control and effect outputs. - DCHECK_GT(op->ControlOutputCount(), 0); - DCHECK_GT(op->EffectOutputCount(), 0); - SetEffectControl(call); - - size_t ret_count = sig->return_count(); - if (ret_count == 0) return call; // No return value. - - DCHECK_EQ(ret_count, rets.size()); - if (ret_count == 1) { - // Only a single return value. - rets[0] = call; - } else { - // Create projections for all return values. - for (size_t i = 0; i < ret_count; i++) { - rets[i] = graph()->NewNode(mcgraph()->common()->Projection(i), call, - graph()->start()); + Node* BuildCallNode(size_t param_count, base::Vector<Node*> args, + Node* implicit_first_arg, const Operator* op, + Node* frame_state) { + const size_t has_frame_state = frame_state != nullptr ? 1 : 0; + const size_t extra = 3; // instance_node, effect, and control. + const size_t count = 1 + param_count + extra + has_frame_state; + + // Reallocate the buffer to make space for extra inputs. + base::SmallVector<Node*, 16 + extra> inputs(count); + DCHECK_EQ(1 + param_count, args.size()); + + // Make room for the first argument at index 1, just after code. + inputs[0] = args[0]; // code + inputs[1] = implicit_first_arg; + if (param_count > 0) { + memcpy(&inputs[2], &args[1], param_count * sizeof(Node*)); } - } - return call; -} -// Only call this function for code which is not reused across instantiations, -// as we do not patch the embedded js_context. -Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, - Node* js_context, - Node** parameters, - int parameter_count) { - const Runtime::Function* fun = Runtime::FunctionForId(f); - auto call_descriptor = Linkage::GetRuntimeCallDescriptor( - mcgraph()->zone(), f, fun->nargs, Operator::kNoProperties, - CallDescriptor::kNoFlags); - // The CEntryStub is loaded from the IsolateRoot so that generated code is - // Isolate independent. At the moment this is only done for CEntryStub(1). - Node* isolate_root = BuildLoadIsolateRoot(); - DCHECK_EQ(1, fun->result_size); - auto centry_id = Builtin::kWasmCEntry; - int builtin_slot_offset = IsolateData::BuiltinSlotOffset(centry_id); - Node* centry_stub = - gasm_->Load(MachineType::Pointer(), isolate_root, builtin_slot_offset); - // TODO(titzer): allow arbitrary number of runtime arguments - // At the moment we only allow 5 parameters. If more parameters are needed, - // increase this constant accordingly. - static const int kMaxParams = 5; - DCHECK_GE(kMaxParams, parameter_count); - Node* inputs[kMaxParams + 6]; - int count = 0; - inputs[count++] = centry_stub; - for (int i = 0; i < parameter_count; i++) { - inputs[count++] = parameters[i]; - } - inputs[count++] = - mcgraph()->ExternalConstant(ExternalReference::Create(f)); // ref - inputs[count++] = Int32Constant(fun->nargs); // arity - inputs[count++] = js_context; // js_context - inputs[count++] = effect(); - inputs[count++] = control(); - - return gasm_->Call(call_descriptor, count, inputs); -} + // Add effect and control inputs. + if (has_frame_state != 0) inputs[param_count + 2] = frame_state; + inputs[param_count + has_frame_state + 2] = effect(); + inputs[param_count + has_frame_state + 3] = control(); -TFGraph* WasmGraphBuilder::graph() { return mcgraph()->graph(); } + Node* call = graph()->NewNode(op, static_cast<int>(count), inputs.begin()); + // Return calls have no effect output. Other calls are the new effect node. + if (op->EffectOutputCount() > 0) SetEffect(call); -Zone* WasmGraphBuilder::graph_zone() { return graph()->zone(); } + return call; + } -template <typename T> -Signature<MachineRepresentation>* CreateMachineSignature( - Zone* zone, const Signature<T>* sig, wasm::CallOrigin origin) { - Signature<MachineRepresentation>::Builder builder(zone, sig->return_count(), - sig->parameter_count()); - for (auto ret : sig->returns()) { - if (origin == wasm::kCalledFromJS) { - builder.AddReturn(MachineRepresentation::kTagged); + void BuildWasmCall(base::Vector<Node*> args, base::Vector<Node*> rets, + Node* implicit_first_arg, Node* frame_state) { + CallDescriptor* call_descriptor = + GetWasmCallDescriptor(mcgraph_->zone(), wrapper_sig_, + kWasmIndirectFunction, frame_state != nullptr); + const Operator* op = mcgraph_->common()->Call(call_descriptor); + Node* call = BuildCallNode(wrapper_sig_->parameter_count(), args, + implicit_first_arg, op, frame_state); + // TODO(manoskouk): These assume the call has control and effect outputs. + DCHECK_GT(op->ControlOutputCount(), 0); + DCHECK_GT(op->EffectOutputCount(), 0); + SetEffectControl(call); + + size_t ret_count = wrapper_sig_->return_count(); + if (ret_count == 0) return; // No return value. + + DCHECK_EQ(ret_count, rets.size()); + if (ret_count == 1) { + // Only a single return value. + rets[0] = call; } else { - builder.AddReturn(ret.machine_representation()); + // Create projections for all return values. + for (size_t i = 0; i < ret_count; i++) { + rets[i] = graph()->NewNode(mcgraph_->common()->Projection(i), call, + graph()->start()); + } } } - for (auto param : sig->parameters()) { - if (origin == wasm::kCalledFromJS) { - // Parameters coming from JavaScript are always tagged values. Especially - // when the signature says that it's an I64 value, then a BigInt object is - // provided by JavaScript, and not two 32-bit parameters. - builder.AddParam(MachineRepresentation::kTagged); - } else { - builder.AddParam(param.machine_representation()); + // Only call this function for code which is not reused across instantiations, + // as we do not patch the embedded js_context. + Node* BuildCallToRuntimeWithContext(Runtime::FunctionId f, Node* js_context, + Node** parameters, int parameter_count) { + const Runtime::Function* fun = Runtime::FunctionForId(f); + auto call_descriptor = Linkage::GetRuntimeCallDescriptor( + mcgraph_->zone(), f, fun->nargs, Operator::kNoProperties, + CallDescriptor::kNoFlags); + // The CEntryStub is loaded from the IsolateRoot so that generated code is + // Isolate independent. At the moment this is only done for CEntryStub(1). + Node* isolate_root = BuildLoadIsolateRoot(); + DCHECK_EQ(1, fun->result_size); + auto centry_id = Builtin::kWasmCEntry; + int builtin_slot_offset = IsolateData::BuiltinSlotOffset(centry_id); + Node* centry_stub = + gasm_.Load(MachineType::Pointer(), isolate_root, builtin_slot_offset); + // TODO(titzer): allow arbitrary number of runtime arguments + // At the moment we only allow 5 parameters. If more parameters are needed, + // increase this constant accordingly. + static const int kMaxParams = 5; + DCHECK_GE(kMaxParams, parameter_count); + Node* inputs[kMaxParams + 6]; + int count = 0; + inputs[count++] = centry_stub; + for (int i = 0; i < parameter_count; i++) { + inputs[count++] = parameters[i]; } + inputs[count++] = + mcgraph_->ExternalConstant(ExternalReference::Create(f)); // ref + inputs[count++] = Int32Constant(fun->nargs); // arity + inputs[count++] = js_context; // js_context + inputs[count++] = effect(); + inputs[count++] = control(); + + return gasm_.Call(call_descriptor, count, inputs); } - return builder.Get(); -} -template Signature<MachineRepresentation>* CreateMachineSignature( - Zone*, const Signature<wasm::ValueType>*, wasm::CallOrigin); -template Signature<MachineRepresentation>* CreateMachineSignature( - Zone*, const Signature<wasm::CanonicalValueType>*, wasm::CallOrigin); - -void WasmGraphBuilder::LowerInt64(Signature<MachineRepresentation>* sig) { - if (mcgraph()->machine()->Is64()) return; - Int64Lowering r(mcgraph()->graph(), mcgraph()->machine(), mcgraph()->common(), - gasm_->simplified(), mcgraph()->zone(), sig); - r.LowerGraph(); -} - -void WasmGraphBuilder::LowerInt64(wasm::CallOrigin origin) { - Signature<MachineRepresentation>* machine_sig = - function_sig_ != nullptr - ? CreateMachineSignature(mcgraph()->zone(), function_sig_, origin) - : CreateMachineSignature(mcgraph()->zone(), wrapper_sig_, origin); - LowerInt64(machine_sig); -} - -void WasmGraphBuilder::Assert(Node* condition, AbortReason abort_reason) { - if (!v8_flags.debug_code) return; - - Diamond check(graph(), mcgraph()->common(), condition, BranchHint::kTrue); - check.Chain(control()); - SetControl(check.if_false); - Node* message_id = gasm_->NumberConstant(static_cast<int32_t>(abort_reason)); - Node* old_effect = effect(); - Node* call = BuildCallToRuntimeWithContext( - Runtime::kAbort, NoContextConstant(), &message_id, 1); - check.merge->ReplaceInput(1, call); - SetEffectControl(check.EffectPhi(old_effect, effect()), check.merge); -} + TFGraph* graph() { return mcgraph_->graph(); } -namespace { + void LowerInt64() { + if (mcgraph_->machine()->Is64()) return; + Int64Lowering r(mcgraph_->graph(), mcgraph_->machine(), mcgraph_->common(), + gasm_.simplified(), mcgraph_->zone(), + CreateMachineSignature(mcgraph_->zone(), wrapper_sig_, + wasm::kCalledFromJS)); + r.LowerGraph(); + } -// A non-null {isolate} signifies that the generated code is treated as being in -// a JS frame for functions like BuildLoadIsolateRoot(). -class WasmWrapperGraphBuilder : public WasmGraphBuilder { - public: - WasmWrapperGraphBuilder(Zone* zone, MachineGraph* mcgraph, - const wasm::CanonicalSig* sig, - ParameterMode parameter_mode, Isolate* isolate, - compiler::SourcePositionTable* spt) - : WasmGraphBuilder(nullptr, zone, mcgraph, nullptr, spt, parameter_mode, - isolate, wasm::WasmEnabledFeatures::All(), sig) {} + void Assert(Node* condition, AbortReason abort_reason) { + if (!v8_flags.debug_code) return; + + Diamond check(graph(), mcgraph_->common(), condition, BranchHint::kTrue); + check.Chain(control()); + SetControl(check.if_false); + Node* message_id = gasm_.NumberConstant(static_cast<int32_t>(abort_reason)); + Node* old_effect = effect(); + Node* call = BuildCallToRuntimeWithContext( + Runtime::kAbort, NoContextConstant(), &message_id, 1); + check.merge->ReplaceInput(1, call); + SetEffectControl(check.EffectPhi(old_effect, effect()), check.merge); + } Node* BuildCallAndReturn(Node* js_context, Node* function_data, base::SmallVector<Node*, 16> args, @@ -499,17 +381,17 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { // The (cached) call target is the jump table slot for that function. // We do not use the imports dispatch table here so that the wrapper is // target independent, in particular for tier-up. - Node* internal = gasm_->LoadImmutableProtectedPointerFromObject( + Node* internal = gasm_.LoadImmutableProtectedPointerFromObject( function_data, offsetof(WasmFunctionData, protected_internal_) - kHeapObjectTag); - args[0] = gasm_->LoadFromObject( + args[0] = gasm_.LoadFromObject( MachineType::Uint32(), internal, offsetof(WasmInternalFunction, raw_call_target_) - kHeapObjectTag); - Node* implicit_arg = gasm_->LoadImmutableProtectedPointerFromObject( + Node* implicit_arg = gasm_.LoadImmutableProtectedPointerFromObject( internal, offsetof(WasmInternalFunction, protected_implicit_arg_) - kHeapObjectTag); - BuildWasmCall(wrapper_sig_, base::VectorOf(args), base::VectorOf(rets), - implicit_arg, true, frame_state); + BuildWasmCall(base::VectorOf(args), base::VectorOf(rets), implicit_arg, + frame_state); Node* jsval; if (wrapper_sig_->return_count() == 0) { @@ -538,7 +420,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { Node* js_closure = Param(Linkage::kJSCallClosureParamIndex, "%closure"); Node* js_context = Param( Linkage::GetJSCallContextParamIndex(wasm_param_count + 1), "%context"); - Node* function_data = gasm_->LoadFunctionDataFromJSFunction(js_closure); + Node* function_data = gasm_.LoadFunctionDataFromJSFunction(js_closure); if (!wasm::IsJSCompatibleSignature(wrapper_sig_)) { // Throw a TypeError. Use the js_context of the calling javascript @@ -568,7 +450,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { params[i] = Param(i + 1); // Skip the receiver. } - auto done = gasm_->MakeLabel(MachineRepresentation::kTagged); // Convert JS parameters to wasm numbers using the default transformation // and build the call. base::SmallVector<Node*, 16> args(args_count); @@ -580,7 +461,7 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { // simplified-lowering and we need to add here a conversion from Float64 // to Float32. if (wrapper_sig_->GetParam(i).kind() == wasm::kF32) { - wasm_param = gasm_->TruncateFloat64ToFloat32(wasm_param); + wasm_param = gasm_.TruncateFloat64ToFloat32(wasm_param); } args[i + 1] = wasm_param; @@ -599,27 +480,24 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { #endif // V8_ENABLE_DRUMBRAKE Return(jsval); - if (ContainsInt64(wrapper_sig_)) LowerInt64(wasm::kCalledFromJS); + if (ContainsInt64(wrapper_sig_)) LowerInt64(); } private: - SetOncePointer<const Operator> int32_to_heapnumber_operator_; - SetOncePointer<const Operator> tagged_non_smi_to_int32_operator_; - SetOncePointer<const Operator> float32_to_number_operator_; - SetOncePointer<const Operator> float64_to_number_operator_; - SetOncePointer<const Operator> tagged_to_float64_operator_; + WasmGraphAssembler gasm_; + Zone* const zone_; + MachineGraph* const mcgraph_; + Node** parameters_ = nullptr; + const wasm::CanonicalSig* const wrapper_sig_; + Isolate* const isolate_; }; } // namespace void BuildInlinedJSToWasmWrapper(Zone* zone, MachineGraph* mcgraph, const wasm::CanonicalSig* signature, - Isolate* isolate, - compiler::SourcePositionTable* spt, - Node* frame_state) { - WasmWrapperGraphBuilder builder(zone, mcgraph, signature, - WasmGraphBuilder::kJSFunctionAbiMode, isolate, - spt); + Isolate* isolate, Node* frame_state) { + WasmWrapperGraphBuilder builder(zone, mcgraph, signature, isolate); builder.BuildJSToWasmWrapper(frame_state); } @@ -770,6 +648,4 @@ AssemblerOptions WasmStubAssemblerOptions() { }; } -#undef LOAD_ROOT - } // namespace v8::internal::compiler diff --git a/deps/v8/src/compiler/wasm-compiler.h b/deps/v8/src/compiler/wasm-compiler.h index b61117e5cfde..0bbc31c72bbe 100644 --- a/deps/v8/src/compiler/wasm-compiler.h +++ b/deps/v8/src/compiler/wasm-compiler.h @@ -26,31 +26,19 @@ #include "src/wasm/wasm-result.h" #include "src/zone/zone.h" -namespace v8 { - -class CFunctionInfo; - -namespace internal { -enum class AbortReason : uint8_t; +namespace v8::internal { struct AssemblerOptions; namespace compiler { // Forward declarations for some compiler data structures. -class TFGraph; class MachineGraph; class Node; class NodeOriginTable; -class Operator; class SourcePositionTable; -struct WasmCompilationData; -class WasmGraphAssembler; } // namespace compiler namespace wasm { -struct DecodeStruct; -class WasmCode; class WireBytesStorage; -enum class LoadTransformationKind : uint8_t; enum Suspend : int; enum CallOrigin { kCalledFromWasm, kCalledFromJS }; } // namespace wasm @@ -95,19 +83,6 @@ constexpr const MachineSignature* CWasmEntrySignature() { return &kCWasmEntrySig; } -struct WasmLoopInfo { - Node* header; - uint32_t nesting_depth; - // This loop has, to our best knowledge, no other loops nested within it. A - // loop can obtain inner loops despite this after inlining. - bool can_be_innermost; - - WasmLoopInfo(Node* header, uint32_t nesting_depth, bool can_be_innermost) - : header(header), - nesting_depth(nesting_depth), - can_be_innermost(can_be_innermost) {} -}; - struct WasmCompilationData { explicit WasmCompilationData(const wasm::FunctionBody& func_body) : func_body(func_body) {} @@ -117,141 +92,19 @@ struct WasmCompilationData { const wasm::FunctionBody& func_body; const wasm::WireBytesStorage* wire_bytes_storage; NodeOriginTable* node_origins{nullptr}; - std::vector<WasmLoopInfo>* loop_infos{nullptr}; std::unique_ptr<wasm::AssumptionsJournal> assumptions{}; SourcePositionTable* source_positions{nullptr}; int func_index; wasm::Validation validate_callees{wasm::kAlreadyValidated}; }; -// Abstracts details of building TurboFan graph nodes for wasm to separate -// the wasm decoder from the internal details of TurboFan. -class WasmGraphBuilder { - public: - // ParameterMode specifies how the instance is passed. - enum ParameterMode { - // Normal wasm functions pass the instance as an implicit first parameter. - kInstanceParameterMode, - // For Wasm-to-JS and C-API wrappers, a {WasmImportData} object is - // passed as first parameter. - kWasmImportDataMode, - // For JS-to-Wasm wrappers (which are JS functions), we load the Wasm - // instance from the JS function data. The generated code objects live on - // the JS heap, so those compilation pass an isolate. - kJSFunctionAbiMode, - // The JS-to-JS wrapper does not have an associated instance. - // The C-entry stub uses a custom ABI (see {CWasmEntryParameters}). - kNoSpecialParameterMode - }; - - V8_EXPORT_PRIVATE WasmGraphBuilder( - wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph, - const wasm::FunctionSig* sig, compiler::SourcePositionTable* spt, - ParameterMode parameter_mode, Isolate* isolate, - wasm::WasmEnabledFeatures enabled_features, - const wasm::CanonicalSig* wrapper_sig = nullptr); - - V8_EXPORT_PRIVATE ~WasmGraphBuilder(); - - bool TryWasmInlining(int fct_index, wasm::NativeModule* native_module, - int inlining_id); - - //----------------------------------------------------------------------- - // Operations independent of {control} or {effect}. - //----------------------------------------------------------------------- - void Start(unsigned params); - Node* Param(int index, const char* debug_name = nullptr); - void TerminateThrow(Node* effect, Node* control); - Node* Int32Constant(int32_t value); - - //----------------------------------------------------------------------- - // Operations that read and/or write {control} and {effect}. - //----------------------------------------------------------------------- - - Node* Return(base::Vector<Node*> nodes); - template <typename... Nodes> - Node* Return(Node* fst, Nodes*... more) { - Node* arr[] = {fst, more...}; - return Return(base::ArrayVector(arr)); - } - - Node* effect(); - Node* control(); - Node* SetEffect(Node* node); - Node* SetControl(Node* node); - void SetEffectControl(Node* effect, Node* control); - Node* SetEffectControl(Node* effect_and_control) { - SetEffectControl(effect_and_control, effect_and_control); - return effect_and_control; - } - - // Overload for when we want to provide a specific signature, rather than - // build one using sig_, for example after scalar lowering. - V8_EXPORT_PRIVATE void LowerInt64(Signature<MachineRepresentation>* sig); - V8_EXPORT_PRIVATE void LowerInt64(wasm::CallOrigin origin); - - bool has_simd() const { return has_simd_; } - - MachineGraph* mcgraph() { return mcgraph_; } - TFGraph* graph(); - Zone* graph_zone(); - - protected: - Node* NoContextConstant(); - - Node* BuildLoadIsolateRoot(); - Node* UndefinedValue(); - - Node* BuildCallNode(size_t param_count, base::Vector<Node*> args, - Node* instance_node, const Operator* op, - Node* frame_state = nullptr); - template <typename T> - Node* BuildWasmCall(const Signature<T>* sig, base::Vector<Node*> args, - base::Vector<Node*> rets, Node* implicit_first_arg, - bool indirect, Node* frame_state = nullptr); - - //----------------------------------------------------------------------- - // Operations involving the CEntry, a dependency we want to remove - // to get off the GC heap. - //----------------------------------------------------------------------- - Node* BuildCallToRuntimeWithContext(Runtime::FunctionId f, Node* js_context, - Node** parameters, int parameter_count); - - void Assert(Node* condition, AbortReason abort_reason); - - std::unique_ptr<WasmGraphAssembler> gasm_; - Zone* const zone_; - MachineGraph* const mcgraph_; - wasm::CompilationEnv* const env_; - // For the main WasmGraphBuilder class, this is identical to the features - // field in {env_}, but the WasmWrapperGraphBuilder subclass doesn't have - // that, so common code should use this field instead. - wasm::WasmEnabledFeatures enabled_features_; - - Node** parameters_; - - SetOncePointer<Node> stack_check_code_node_; - SetOncePointer<const Operator> stack_check_call_operator_; - - bool has_simd_ = false; - bool needs_stack_check_ = false; - - const wasm::FunctionSig* const function_sig_; - const wasm::CanonicalSig* const wrapper_sig_{nullptr}; - - compiler::SourcePositionTable* const source_position_table_ = nullptr; - int inlining_id_ = -1; - const ParameterMode parameter_mode_; - Isolate* const isolate_; - SetOncePointer<Node> instance_data_node_; - NullCheckStrategy null_check_strategy_; - static constexpr int kNoCachedMemoryIndex = -1; - int cached_memory_index_ = kNoCachedMemoryIndex; -}; +bool TryWasmInlining(int fct_index, wasm::NativeModule* native_module, + int inlining_id, MachineGraph* mcgraph, + SourcePositionTable* spt); -V8_EXPORT_PRIVATE void BuildInlinedJSToWasmWrapper( - Zone* zone, MachineGraph* mcgraph, const wasm::CanonicalSig* signature, - Isolate* isolate, compiler::SourcePositionTable* spt, Node* frame_state); +void BuildInlinedJSToWasmWrapper(Zone* zone, MachineGraph* mcgraph, + const wasm::CanonicalSig* signature, + Isolate* isolate, Node* frame_state); AssemblerOptions WasmAssemblerOptions(); AssemblerOptions WasmStubAssemblerOptions(); @@ -261,7 +114,6 @@ Signature<MachineRepresentation>* CreateMachineSignature( Zone* zone, const Signature<T>* sig, wasm::CallOrigin origin); } // namespace compiler -} // namespace internal -} // namespace v8 +} // namespace v8::internal #endif // V8_COMPILER_WASM_COMPILER_H_ diff --git a/deps/v8/src/compiler/wasm-gc-lowering.cc b/deps/v8/src/compiler/wasm-gc-lowering.cc index 79aa92f271ec..c366ce7db3a0 100644 --- a/deps/v8/src/compiler/wasm-gc-lowering.cc +++ b/deps/v8/src/compiler/wasm-gc-lowering.cc @@ -244,7 +244,9 @@ Reduction WasmGCLowering::ReduceWasmTypeCheckAbstract(Node* node) { break; } if (to_kind == wasm::GenericKind::kStruct) { - result = gasm_.HasInstanceType(object, WASM_STRUCT_TYPE); + result = + gasm_.Word32Or(gasm_.HasInstanceType(object, WASM_STRUCT_TYPE), + gasm_.HasInstanceType(object, WASM_CUSTOM_MAP_TYPE)); break; } if (to_kind == wasm::GenericKind::kString || @@ -422,7 +424,9 @@ Reduction WasmGCLowering::ReduceWasmTypeCastAbstract(Node* node) { break; } if (to_kind == wasm::GenericKind::kStruct) { - gasm_.TrapUnless(gasm_.HasInstanceType(object, WASM_STRUCT_TYPE), + gasm_.GotoIf(gasm_.HasInstanceType(object, WASM_STRUCT_TYPE), &end_label, + BranchHint::kTrue); + gasm_.TrapUnless(gasm_.HasInstanceType(object, WASM_CUSTOM_MAP_TYPE), TrapId::kTrapIllegalCast); UpdateSourcePosition(gasm_.effect(), node); break; @@ -476,7 +480,8 @@ Reduction WasmGCLowering::ReduceAssertNotNull(Node* node) { UpdateSourcePosition(gasm_.effect(), node); } else { static_assert(WasmStruct::kHeaderSize > kTaggedSize); - static_assert(WasmArray::kHeaderSize > kTaggedSize); + static_assert(WasmCustomMap::kHeaderSize > kTaggedSize); + static_assert(WasmArray::HeaderSize(SharedFlag{false}) > kTaggedSize); static_assert(WasmInternalFunction::kHeaderSize > kTaggedSize); Node* trap_null = gasm_.LoadTrapOnNull( MachineType::Int32(), object, @@ -539,11 +544,14 @@ Reduction WasmGCLowering::ReduceWasmAnyConvertExtern(Node* node) { auto smi_label = gasm_.MakeLabel(); auto int_to_smi_label = gasm_.MakeLabel(); auto heap_number_label = gasm_.MakeLabel(); + auto custom_map_wrapper_label = gasm_.MakeLabel(); gasm_.GotoIf(IsNull(input, wasm::kWasmExternRef), &null_label); gasm_.GotoIf(gasm_.IsSmi(input), &smi_label); Node* is_heap_number = gasm_.HasInstanceType(input, HEAP_NUMBER_TYPE); gasm_.GotoIf(is_heap_number, &heap_number_label); + gasm_.GotoIf(gasm_.HasInstanceType(input, WASM_CUSTOM_MAP_WRAPPER_TYPE), + &custom_map_wrapper_label); // For anything else, just pass through the value. gasm_.Goto(&end_label, input); @@ -617,6 +625,12 @@ Reduction WasmGCLowering::ReduceWasmAnyConvertExtern(Node* node) { gasm_.Bind(&int_to_smi_label); gasm_.Goto(&end_label, gasm_.BuildChangeInt32ToSmi(int_value)); + gasm_.Bind(&custom_map_wrapper_label); + gasm_.Goto(&end_label, + gasm_.LoadFromObject( + MachineType::TaggedPointer(), input, + offsetof(WasmCustomMapWrapper, wrapped_) - kHeapObjectTag)); + gasm_.Bind(&end_label); ReplaceWithValue(node, end_label.PhiAt(0), gasm_.effect(), gasm_.control()); node->Kill(); @@ -628,13 +642,26 @@ Reduction WasmGCLowering::ReduceWasmExternConvertAny(Node* node) { Node* object = node->InputAt(0); gasm_.InitializeEffectControl(NodeProperties::GetEffectInput(node), NodeProperties::GetControlInput(node)); - auto label = gasm_.MakeLabel(MachineRepresentation::kTagged); - gasm_.GotoIfNot(IsNull(object, wasm::kWasmAnyRef), &label, object); - gasm_.Goto(&label, Null(wasm::kWasmExternRef)); - gasm_.Bind(&label); - ReplaceWithValue(node, label.PhiAt(0), gasm_.effect(), gasm_.control()); + auto done = gasm_.MakeLabel(MachineRepresentation::kTagged); + gasm_.GotoIf(IsNull(object, wasm::kWasmAnyRef), &done, + Null(wasm::kWasmExternRef)); + gasm_.GotoIf(gasm_.IsSmi(object), &done, object); + gasm_.GotoIfNot(gasm_.HasInstanceType(object, WASM_CUSTOM_MAP_TYPE), &done, + object); + + // {object} is a WasmCustomMap. + Node* maybe_wrapper = gasm_.LoadFromObject( + MachineType::TaggedPointer(), object, + offsetof(WasmCustomMap, js_wrapper_) - kHeapObjectTag); + gasm_.GotoIfNot(IsNull(maybe_wrapper, wasm::kWasmExternRef), &done, + maybe_wrapper); + gasm_.Goto(&done, gasm_.CallBuiltin(Builtin::kWasmExternConvertAny, + Operator::kEliminatable, object)); + + gasm_.Bind(&done); + ReplaceWithValue(node, done.PhiAt(0), gasm_.effect(), gasm_.control()); node->Kill(); - return Replace(label.PhiAt(0)); + return Replace(done.PhiAt(0)); } Reduction WasmGCLowering::ReduceWasmStructGet(Node* node) { @@ -734,7 +761,7 @@ Reduction WasmGCLowering::ReduceWasmArrayGet(Node* node) { gasm_.InitializeEffectControl(NodeProperties::GetEffectInput(node), NodeProperties::GetControlInput(node)); - Node* offset = gasm_.WasmArrayElementOffset(index, info.type->element_type()); + Node* offset = gasm_.WasmArrayElementOffset(index, info.type); MachineType type = MachineType::TypeForRepresentation( info.type->element_type().machine_representation(), info.is_signed); @@ -757,7 +784,7 @@ Reduction WasmGCLowering::ReduceWasmArraySet(Node* node) { gasm_.InitializeEffectControl(NodeProperties::GetEffectInput(node), NodeProperties::GetControlInput(node)); - Node* offset = gasm_.WasmArrayElementOffset(index, type->element_type()); + Node* offset = gasm_.WasmArrayElementOffset(index, type); ObjectAccess access = ObjectAccessForGCStores(type->element_type()); diff --git a/deps/v8/src/compiler/wasm-graph-assembler.cc b/deps/v8/src/compiler/wasm-graph-assembler.cc index f4e55a54a118..4c46921636a7 100644 --- a/deps/v8/src/compiler/wasm-graph-assembler.cc +++ b/deps/v8/src/compiler/wasm-graph-assembler.cc @@ -10,7 +10,7 @@ #include "src/compiler/node-matchers.h" #include "src/compiler/wasm-compiler-definitions.h" #include "src/objects/string.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" #include "src/wasm/wasm-objects.h" namespace v8::internal::compiler { @@ -360,7 +360,7 @@ Node* WasmGraphAssembler::LoadByteArrayElement(Node* byte_array, } Node* WasmGraphAssembler::LoadTrustedPointerFromObject( - Node* object, int field_offset, IndirectPointerTagRange tag) { + Node* object, int field_offset, TrustedPointerTagRange tag) { #ifdef V8_ENABLE_SANDBOX return AddNode(graph()->NewNode(common_.LoadTrustedPointer(field_offset, tag), object, effect(), control())); @@ -395,15 +395,7 @@ Node* WasmGraphAssembler::LoadFunctionDataFromJSFunction(Node* js_function) { return LoadTrustedPointerFromObject( shared, offsetof(SharedFunctionInfo, trusted_function_data_) - kHeapObjectTag, - kWasmExportedFunctionDataIndirectPointerTag); -} - -Node* WasmGraphAssembler::LoadExportedFunctionInstanceData( - Node* exported_function_data) { - return LoadImmutableProtectedPointerFromObject( - exported_function_data, - offsetof(WasmExportedFunctionData, protected_instance_data_) - - kHeapObjectTag); + kWasmExportedFunctionDataTrustedPointerTag); } // JavaScript objects. @@ -417,17 +409,18 @@ Node* WasmGraphAssembler::LoadJSArrayElements(Node* js_array) { Node* WasmGraphAssembler::FieldOffset(const wasm::StructType* type, uint32_t field_index) { - return IntPtrConstant(WasmStruct::kHeaderSize + - type->field_offset(field_index) - kHeapObjectTag); + return IntPtrConstant(WasmStruct::FieldOffset(type, field_index) - + kHeapObjectTag); } Node* WasmGraphAssembler::WasmArrayElementOffset(Node* index, - wasm::ValueType element_type) { + const wasm::ArrayType* type) { Node* index_intptr = mcgraph()->machine()->Is64() ? ChangeInt32ToInt64(index) : index; return IntAdd( - IntPtrConstant(WasmArray::kHeaderSize - kHeapObjectTag), - IntMul(index_intptr, IntPtrConstant(element_type.value_kind_size()))); + IntPtrConstant(WasmArray::HeaderSize(type->is_shared()) - kHeapObjectTag), + IntMul(index_intptr, + IntPtrConstant(type->element_type().value_kind_size()))); } Node* WasmGraphAssembler::IsDataRefMap(Node* map) { @@ -436,9 +429,15 @@ Node* WasmGraphAssembler::IsDataRefMap(Node* map) { // unsigned comparison. Node* comparison_value = Int32Sub(instance_type, Int32Constant(FIRST_WASM_OBJECT_TYPE)); - return Uint32LessThanOrEqual( - comparison_value, - Int32Constant(LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE)); + // Computing both conditions and OR-ing them isn't the most efficient + // approach, but this code is deprecated anyway (only used for Wasm-into-JS + // inlining currently, slated to be replaced by Turboshaft). + return Word32Or( + Uint32LessThanOrEqual( + comparison_value, + Int32Constant(LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE)), + Word32Equal(comparison_value, Int32Constant(WASM_CUSTOM_MAP_TYPE - + FIRST_WASM_OBJECT_TYPE))); } Node* WasmGraphAssembler::WasmTypeCheck(Node* object, Node* rtt, @@ -554,7 +553,7 @@ Node* WasmGraphAssembler::LoadTrustedDataFromInstanceObject( return LoadTrustedPointerFromObject( instance_object, offsetof(WasmInstanceObject, trusted_data_) - kHeapObjectTag, - kWasmTrustedInstanceDataIndirectPointerTag); + kWasmTrustedInstanceDataTrustedPointerTag); } // Generic HeapObject helpers. diff --git a/deps/v8/src/compiler/wasm-graph-assembler.h b/deps/v8/src/compiler/wasm-graph-assembler.h index 0737d7999e7d..00ec30a0d1ac 100644 --- a/deps/v8/src/compiler/wasm-graph-assembler.h +++ b/deps/v8/src/compiler/wasm-graph-assembler.h @@ -10,7 +10,7 @@ #endif // !V8_ENABLE_WEBASSEMBLY #include "src/compiler/graph-assembler.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" #include "src/wasm/wasm-code-manager.h" namespace v8 { @@ -179,7 +179,7 @@ class WasmGraphAssembler : public GraphAssembler { Node* isolate_root); Node* LoadTrustedPointerFromObject(Node* object, int offset, - IndirectPointerTagRange tag); + TrustedPointerTagRange tag); Node* IsSmi(Node* object); @@ -247,8 +247,6 @@ class WasmGraphAssembler : public GraphAssembler { Node* LoadFunctionDataFromJSFunction(Node* js_function); - Node* LoadExportedFunctionInstanceData(Node* exported_function_data); - // JavaScript objects. Node* LoadJSArrayElements(Node* js_array); @@ -257,7 +255,7 @@ class WasmGraphAssembler : public GraphAssembler { Node* FieldOffset(const wasm::StructType* type, uint32_t field_index); - Node* WasmArrayElementOffset(Node* index, wasm::ValueType element_type); + Node* WasmArrayElementOffset(Node* index, const wasm::ArrayType* type); Node* IsDataRefMap(Node* map); diff --git a/deps/v8/src/compiler/write-barrier-kind.h b/deps/v8/src/compiler/write-barrier-kind.h index 7623fa30950f..227acf3a3f6c 100644 --- a/deps/v8/src/compiler/write-barrier-kind.h +++ b/deps/v8/src/compiler/write-barrier-kind.h @@ -22,7 +22,7 @@ enum WriteBarrierKind : uint8_t { kSkippedWriteBarrier, kMapWriteBarrier, kPointerWriteBarrier, - kIndirectPointerWriteBarrier, + kTrustedPointerWriteBarrier, kEphemeronKeyWriteBarrier, kFullWriteBarrier }; @@ -43,8 +43,8 @@ inline std::ostream& operator<<(std::ostream& os, WriteBarrierKind kind) { return os << "MapWriteBarrier"; case kPointerWriteBarrier: return os << "PointerWriteBarrier"; - case kIndirectPointerWriteBarrier: - return os << "IndirectPointerWriteBarrier"; + case kTrustedPointerWriteBarrier: + return os << "TrustedPointerWriteBarrier"; case kEphemeronKeyWriteBarrier: return os << "EphemeronKeyWriteBarrier"; case kFullWriteBarrier: diff --git a/deps/v8/src/d8/d8-platforms.cc b/deps/v8/src/d8/d8-platforms.cc index c77a4cd8047f..a883086e99a9 100644 --- a/deps/v8/src/d8/d8-platforms.cc +++ b/deps/v8/src/d8/d8-platforms.cc @@ -246,8 +246,15 @@ class DelayedTasksPlatform final : public Platform { TaskRunner* original_runner = task_runner_.get(); base::MutexGuard lock_guard(&platform_->mutex_); auto& delayed_task_runners = platform_->delayed_task_runners_; - DCHECK_EQ(1, delayed_task_runners.count(original_runner)); - delayed_task_runners.erase(original_runner); + // The strong reference count drops to zero before this destructor + // acquires {platform_->mutex_}. In that window, a concurrent call to + // {GetForegroundTaskRunner} for the same {original_runner} may have + // already created a new {DelayedTaskRunner} (and possibly also destroyed + // it). Only erase the map entry if it still exists and is expired. + auto it = delayed_task_runners.find(original_runner); + if (it != delayed_task_runners.end() && it->second.expired()) { + delayed_task_runners.erase(it); + } } bool IdleTasksEnabled() final { return task_runner_->IdleTasksEnabled(); } @@ -256,6 +263,10 @@ class DelayedTasksPlatform final : public Platform { return task_runner_->NonNestableTasksEnabled(); } + bool NonNestableDelayedTasksEnabled() const final { + return task_runner_->NonNestableDelayedTasksEnabled(); + } + private: void PostTaskImpl(std::unique_ptr<Task> task, const SourceLocation& location) final { @@ -276,6 +287,14 @@ class DelayedTasksPlatform final : public Platform { delay_in_seconds, location); } + void PostNonNestableDelayedTaskImpl(std::unique_ptr<Task> task, + double delay_in_seconds, + const SourceLocation& location) final { + task_runner_->PostNonNestableDelayedTask( + platform_->MakeDelayedTask(std::move(task)), delay_in_seconds, + location); + } + void PostIdleTaskImpl(std::unique_ptr<IdleTask> task, const SourceLocation& location) final { task_runner_->PostIdleTask( diff --git a/deps/v8/src/d8/d8-posix.cc b/deps/v8/src/d8/d8-posix.cc index b8bc0ea2b8f2..e27b153cfdb0 100644 --- a/deps/v8/src/d8/d8-posix.cc +++ b/deps/v8/src/d8/d8-posix.cc @@ -24,6 +24,7 @@ #include "include/v8-container.h" #include "include/v8-template.h" #include "src/api/api.h" +#include "src/base/unique-array.h" namespace v8 { @@ -608,13 +609,14 @@ void Shell::UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& info) { unsetenv(*var); } -base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { +std::optional<base::UniqueArray<char>> Shell::ReadCharsFromTcpPort( + const char* name) { DCHECK_GE(Shell::options.read_from_tcp_port, 0); int sockfd = socket(PF_INET, SOCK_STREAM, 0); if (sockfd < 0) { fprintf(stderr, "Failed to create IPv4 socket\n"); - return {}; + return std::nullopt; } // Create an address for localhost:PORT where PORT is specified by the shell @@ -630,7 +632,7 @@ base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { fprintf(stderr, "Failed to connect to localhost:%d\n", Shell::options.read_from_tcp_port.get()); close(sockfd); - return {}; + return std::nullopt; } // The file server follows the simple protocol for requesting and receiving @@ -658,7 +660,7 @@ base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { fprintf(stderr, "Failed to send %s to localhost:%d\n", name, Shell::options.read_from_tcp_port.get()); close(sockfd); - return {}; + return std::nullopt; } sent_len += sent_now; } @@ -675,7 +677,7 @@ base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { fprintf(stderr, "Failed to receive %s's length from localhost:%d\n", name, Shell::options.read_from_tcp_port.get()); close(sockfd); - return {}; + return std::nullopt; } // Reinterpretet the received file length as a signed big-endian integer. int32_t file_length = base::bit_cast<int32_t>(htonl(big_endian_file_length)); @@ -684,29 +686,28 @@ base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { fprintf(stderr, "Received length %d for %s from localhost:%d\n", file_length, name, Shell::options.read_from_tcp_port.get()); close(sockfd); - return {}; + return std::nullopt; } // Allocate the output array. - char* chars = new char[file_length]; + auto chars = base::UniqueArray<char>::NewForOverwrite(file_length); // Now keep receiving and copying until the whole file is received. ssize_t total_received = 0; while (total_received < file_length) { - received = - recv(sockfd, chars + total_received, file_length - total_received, 0); + received = recv(sockfd, chars.data() + total_received, + file_length - total_received, 0); if (received < 0) { fprintf(stderr, "Failed to receive %s from localhost:%d\n", name, Shell::options.read_from_tcp_port.get()); close(sockfd); - delete[] chars; - return {}; + return std::nullopt; } total_received += received; } close(sockfd); - return base::OwnedVector<char>(std::unique_ptr<char[]>(chars), file_length); + return chars; } void Shell::AddOSMethods(Isolate* isolate, Local<ObjectTemplate> os_templ) { diff --git a/deps/v8/src/d8/d8-test.cc b/deps/v8/src/d8/d8-test.cc index 425f48a11661..da61c89c2a88 100644 --- a/deps/v8/src/d8/d8-test.cc +++ b/deps/v8/src/d8/d8-test.cc @@ -108,8 +108,7 @@ class FastCApiObject { "Invalid parameter, destination array is too small."); return; } - uint8_t* memory = - reinterpret_cast<uint8_t*>(out.As<Uint8Array>()->Buffer()->Data()); + uint8_t* memory = reinterpret_cast<uint8_t*>(array->GetBuffer()->Data()); memcpy(memory, source.data, source.length); } @@ -382,7 +381,7 @@ class FastCApiObject { return 0; } T* memory = reinterpret_cast<T*>( - typed_array_arg.As<TypedArray>()->Buffer()->Data()); + typed_array_arg.As<TypedArray>()->GetBuffer()->Data()); size_t length = typed_array_arg.As<TypedArray>()->ByteLength() / sizeof(T); double sum = 0; for (size_t i = 0; i < length; ++i) { @@ -415,7 +414,7 @@ class FastCApiObject { Local<TypedArray> typed_array_arg = info[0].As<TypedArray>(); size_t length = typed_array_arg->Length(); - void* data = typed_array_arg->Buffer()->GetBackingStore()->Data(); + void* data = typed_array_arg->GetBuffer()->GetBackingStore()->Data(); if (typed_array_arg->IsUint8Array() || typed_array_arg->IsInt32Array() || typed_array_arg->IsUint32Array() || typed_array_arg->IsBigInt64Array() || @@ -1094,7 +1093,7 @@ class FastCApiObject { v8::Local<v8::WasmMemoryObject> wasm_memory = mem.As<v8::WasmMemoryObject>(); - v8::Local<v8::ArrayBuffer> buffer = wasm_memory->Buffer(); + v8::Local<v8::ArrayBufferBase> buffer = wasm_memory->GetBuffer(); if (address >= buffer->ByteLength()) { isolate->ThrowError("Address out of bounds for Wasm memory."); return true; diff --git a/deps/v8/src/d8/d8-windows.cc b/deps/v8/src/d8/d8-windows.cc index b8958fc2da97..572da905856a 100644 --- a/deps/v8/src/d8/d8-windows.cc +++ b/deps/v8/src/d8/d8-windows.cc @@ -14,6 +14,7 @@ #include "src/api/api.h" #include "src/base/platform/platform-win32.h" #include "src/base/platform/platform.h" +#include "src/base/unique-array.h" #include "src/d8/d8.h" namespace v8 { @@ -43,9 +44,10 @@ void Shell::PreProcessUnicodeFilenameArg(char* argv[], int i) { void Shell::AddOSMethods(Isolate* isolate, Local<ObjectTemplate> os_templ) {} -base::OwnedVector<char> Shell::ReadCharsFromTcpPort(const char* name) { +std::optional<base::UniqueArray<char>> Shell::ReadCharsFromTcpPort( + const char* name) { // TODO(leszeks): No reason this shouldn't exist on windows. - return {}; + return std::nullopt; } void Shell::FileExists(const v8::FunctionCallbackInfo<v8::Value>& info) { diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc index 8d325f418e38..9ce0e0ce0743 100644 --- a/deps/v8/src/d8/d8.cc +++ b/deps/v8/src/d8/d8.cc @@ -43,7 +43,6 @@ #include "include/v8-wasm.h" #include "src/api/api-inl.h" #include "src/base/cpu/cpu.h" -#include "src/base/fpu.h" #include "src/base/hashing.h" #include "src/base/logging.h" #include "src/base/macros.h" @@ -54,6 +53,7 @@ #include "src/base/sanitizer/msan.h" #include "src/base/strong-alias.h" #include "src/base/sys-info.h" +#include "src/base/unique-array.h" #include "src/base/utils/random-number-generator.h" #include "src/codegen/compilation-cache.h" #include "src/codegen/compiler.h" @@ -158,7 +158,14 @@ thread_local Worker* current_worker_ = nullptr; constexpr v8::EmbedderDataTypeTag kInspectorClientTag = 1; +// Modules declared by all bundles executed in the current run. Worker threads +// read this map when importing modules, so accesses need to hold +// bundle_module_files_mutex. +base::LazyMutex bundle_module_files_mutex = LAZY_MUTEX_INITIALIZER; std::unordered_map<std::string, std::string> bundle_module_files; +// Used for naming anonymous bundle entrypoints. Only accessed on the main +// thread. +int bundle_anon_module_counter = 0; #ifdef V8_FUZZILLI bool fuzzilli_reprl = true; #else @@ -482,7 +489,12 @@ class PAInSandboxAllocator final : public v8::Allocator { } void* AllocateUninitializedOrCrash(size_t size) override { - return AllocateInternal<partition_alloc::AllocFlags::kNone>(size); + void* result = AllocateUninitialized(size); + if (!result) { + internal::V8::FatalProcessOutOfMemory( + nullptr, "PAInSandboxAllocator::AllocateUninitializedOrCrash()"); + } + return result; } void Free(void* ptr) override { @@ -1045,6 +1057,10 @@ class ModuleEmbedderData { // List of compiled JavaScript modules awaiting code cache production. std::vector<std::pair<Global<String>, Global<Module>>> modules_pending_code_cache; + + // Modules inserted during the current FetchModuleTree call, for rollback on + // failure. + std::vector<decltype(module_map)::iterator> inserted_modules; }; enum { kModuleEmbedderDataIndex, kInspectorClientIndex }; @@ -1059,7 +1075,7 @@ i::CppGCManaged<ModuleEmbedderData>::Ptr InitializeModuleEmbedderData( std::make_shared<ModuleEmbedderData>( reinterpret_cast<v8::Isolate*>(i_isolate))); v8::Local<v8::Data> module_data = Utils::ToLocal(module_data_managed); - context->SetEmbedderDataV2(kModuleEmbedderDataIndex, module_data); + context->SetEmbedderDataV3(kModuleEmbedderDataIndex, module_data); return module_data_managed->ptr(); } @@ -1519,11 +1535,15 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer, Isolate* isolate = Isolate::GetCurrent(); i::CppGCManaged<ModuleEmbedderData>::Ptr module_data = GetModuleDataFromContext(context); + DCHECK_IMPLIES(referrer.IsEmpty(), module_data->inserted_modules.empty()); MaybeLocal<String> source_text; std::unique_ptr<base::OS::MemoryMappedFile> raw_file; bool found_in_bundle = false; if (options.bundle) { + i::ParkedMutexGuard lock_guard( + reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(), + bundle_module_files_mutex.Pointer()); auto it = bundle_module_files.find(module_specifier); if (it != bundle_module_files.end()) { source_text = String::NewFromUtf8(isolate, it->second.c_str()); @@ -1656,6 +1676,7 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer, std::make_pair(std::make_pair(module_specifier, module_type), Global<Module>(isolate, module))); CHECK(module_map_inserted.second); + module_data->inserted_modules.push_back(module_map_inserted.first); auto module_to_specifier_map_inserted = module_data->module_to_specifier_map.insert( @@ -1712,10 +1733,14 @@ MaybeLocal<Module> Shell::FetchModuleTree(Local<Module> referrer, } } - if (result.IsEmpty()) { - module_data->module_map.erase(module_map_inserted.first); - module_data->module_to_specifier_map.erase( - module_to_specifier_map_inserted.first); + if (referrer.IsEmpty()) { + if (result.IsEmpty()) { + for (auto it : module_data->inserted_modules) { + module_data->module_to_specifier_map.erase(it->second); + module_data->module_map.erase(it); + } + } + module_data->inserted_modules.clear(); } return result; @@ -2337,13 +2362,14 @@ bool Shell::LoadJSON(Isolate* isolate, const char* file_name) { TryCatch try_catch(isolate); std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory()); - base::OwnedVector<char> data = ReadChars(absolute_path.c_str()); - if (data.data() == nullptr) { + std::optional<base::UniqueArray<char>> data = + ReadChars(absolute_path.c_str()); + if (!data) { printf("Error reading '%s'\n", file_name); base::OS::ExitProcess(1); } // TODO(C++23): Replace with std::ispanstream once Clang supports it. - std::stringstream stream(std::string(data.data(), data.size())); + std::stringstream stream(std::string(data->data(), data->size())); std::string line; while (std::getline(stream, line, '\n')) { for (int r = 0; r < DeserializationRunCount(); ++r) { @@ -2921,7 +2947,7 @@ MaybeLocal<Context> Shell::CreateRealm( TryCatch try_catch(isolate); PerIsolateData* data = PerIsolateData::Get(isolate); - Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate); + Local<ObjectTemplate> global_template = GetOrCreateGlobalTemplate(isolate); v8::MicrotaskQueue* microtask_queue = nullptr; if (create_own_microtask_queue) { @@ -3308,27 +3334,6 @@ void Shell::InstallConditionalFeatures( isolate->InstallConditionalFeatures(isolate->GetCurrentContext()); } -void Shell::SetFlushDenormals(const v8::FunctionCallbackInfo<v8::Value>& info) { - Isolate* isolate = info.GetIsolate(); - if (i::v8_flags.correctness_fuzzer_suppressions || i::v8_flags.fuzzing) { - // Setting denormals flushing in the middle of code is almost certain to - // cause correctness issues or crashes, in a way that isn't interesting to - // us. Make this a no-op instead. - return; - } - // Check if the argument is a valid function. - if (info.Length() != 1) { - ThrowError(isolate, "Expected single boolean argument."); - return; - } - Local<Value> arg = info[0]; - if (!arg->IsBoolean()) { - ThrowError(isolate, "Expected single boolean argument."); - return; - } - base::FPU::SetFlushDenormals(arg.As<Boolean>()->BooleanValue(isolate)); -} - // async_hooks.createHook() registers functions to be called for different // lifetime events of each async operation. void Shell::AsyncHooksCreateHook( @@ -3523,6 +3528,8 @@ void Shell::WasmDeserializeModule( i::wasm::CompileTimeImports compile_time_imports = i::WasmJs::CompileTimeImportsFromArgument( Utils::OpenDirectHandle(*info[2]), i_isolate, enabled_features); + // Evaluating compile-time imports calls into JS and can throw. + if (i_isolate->has_exception()) return; Local<ArrayBuffer> serialized_bytes_buffer = info[0].As<ArrayBuffer>(); Local<ArrayBufferView> wire_bytes_view = info[1].As<ArrayBufferView>(); @@ -3533,7 +3540,7 @@ void Shell::WasmDeserializeModule( ThrowError(isolate, "First argument is detached"); return; } - if (wire_bytes_view->Buffer()->WasDetached()) { + if (wire_bytes_view->GetBuffer()->WasDetached()) { ThrowError(isolate, "Second argument's buffer is detached"); return; } @@ -3542,13 +3549,13 @@ void Shell::WasmDeserializeModule( // deserialization. // For the wire bytes, we need a new copy anyway for storing in the new // NativeModule (if it does not come from the cache). - base::OwnedVector<const uint8_t> wire_bytes_vec = ([&] { + base::UniqueArray<const uint8_t> wire_bytes_vec = ([&] { size_t length = wire_bytes_view->ByteLength(); - auto vec = base::OwnedVector<uint8_t>::NewForOverwrite(length); + auto vec = base::UniqueArray<uint8_t>::NewForOverwrite(length); CHECK_EQ(length, wire_bytes_view->CopyContents(vec.data(), length)); - return vec; // `OwnedVector<uint8_t>` to `OwnedVector<const uint8_t>`. + return vec; // `UniqueArray<uint8_t>` to `UniqueArray<const uint8_t>`. })(); - base::OwnedVector<uint8_t> serialized_bytes_vec = base::OwnedCopyOf( + base::UniqueArray<uint8_t> serialized_bytes_vec = base::UniqueCopyOf( reinterpret_cast<uint8_t*>(serialized_bytes_buffer->Data()), serialized_bytes_buffer->ByteLength()); @@ -3560,8 +3567,8 @@ void Shell::WasmDeserializeModule( { size_t hash = base::Hasher{} .Add(wire_bytes_vec.size()) - .AddRange(wire_bytes_vec.as_vector()) - .AddRange(serialized_bytes_vec.as_vector()) + .AddRange(wire_bytes_vec.as_span()) + .AddRange(serialized_bytes_vec.as_span()) .hash(); base::MutexGuard mutex_guard(Shell::wasm_serialized_bytes_mutex_.Pointer()); if (!Shell::wasm_serialized_bytes_hashes_.count(hash)) { @@ -3574,21 +3581,26 @@ void Shell::WasmDeserializeModule( // For correctness fuzzing, the `serializeModule` function always returns an // empty buffer. We thus have to accept this empty buffer again here, and - // produce a valid module. + // compile the wire bytes directly. if (i::v8_flags.correctness_fuzzer_suppressions) { CHECK(serialized_bytes_vec.empty()); i::wasm::ErrorThrower thrower{i_isolate, "d8.wasm.deserializeModule"}; - module_object = - i::wasm::GetWasmEngine() - ->SyncCompile(i_isolate, enabled_features, compile_time_imports, - &thrower, std::move(wire_bytes_vec)) - .ToHandleChecked(); + if (!i::wasm::GetWasmEngine() + ->SyncCompile(i_isolate, enabled_features, + std::move(compile_time_imports), &thrower, + std::move(wire_bytes_vec)) + .ToHandle(&module_object)) { + // Compilation can still fail if compile-time imports do not match; + // `thrower` schedules the exception on destruction. + CHECK(thrower.error()); + return; + } DCHECK(!thrower.error()); } else { // Note that {wasm::DeserializeNativeModule} will allocate. We assume the // JSArrayBuffer backing store doesn't get relocated. if (!i::wasm::DeserializeNativeModule( - i_isolate, enabled_features, serialized_bytes_vec.as_vector(), + i_isolate, enabled_features, serialized_bytes_vec.as_span(), wire_bytes_vec, compile_time_imports, {}) .ToHandle(&module_object)) { // Deserialization failed, probably because of mismatched compile time @@ -3760,7 +3772,7 @@ void Shell::WriteFile(const v8::FunctionCallbackInfo<v8::Value>& info) { Local<v8::ArrayBufferView> buffer_view = Local<v8::ArrayBufferView>::Cast(info[1]); length = buffer_view->ByteLength(); - data = static_cast<uint8_t*>(buffer_view->Buffer()->Data()) + + data = static_cast<uint8_t*>(buffer_view->GetBuffer()->Data()) + buffer_view->ByteOffset(); } fwrite(data, 1, length, file); @@ -4123,20 +4135,6 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& info) { // early-out from the instance calls. info.This()->SetInternalField(0, v8::Integer::New(isolate, 0)); - // By default, propagate flush denormals state. - bool flush_denormals = base::FPU::GetFlushDenormals(); - if (info.Length() > 1 && info[1]->IsObject()) { - Local<Value> value; - if (!TryGetValue(isolate, isolate->GetCurrentContext(), - info[1].As<Object>(), "flushDenormals") - .ToLocal(&value)) { - return; - } - if (!value->IsUndefined()) { - flush_denormals = value->BooleanValue(isolate); - } - } - { // Don't allow workers to create more workers if the main thread // is waiting for existing running workers to terminate. @@ -4154,7 +4152,7 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& info) { // The C++ worker object's lifetime is shared between the // CppGCManaged<Worker> object on the heap, which the JavaScript object // points to, and an internal std::shared_ptr in the worker thread itself. - auto worker = std::make_shared<Worker>(isolate, *script, flush_denormals); + auto worker = std::make_shared<Worker>(isolate, *script); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); const size_t kWorkerSizeEstimate = 4 * 1024 * 1024; // stack + heap. i::DirectHandle<i::Object> managed = @@ -4763,6 +4761,8 @@ Local<FunctionTemplate> Shell::CreateNodeTemplates( return div_element; } +// Note: the result is cached per isolate (see GetOrCreateGlobalTemplate), so +// it must not depend on the context or on state that changes after startup. Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); global_template->Set(Symbol::GetToStringTag(isolate), @@ -4815,6 +4815,20 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { return global_template; } +Local<ObjectTemplate> Shell::GetOrCreateGlobalTemplate(Isolate* isolate) { + // Creating the global template is fairly expensive compared to the rest of + // the context setup, e.g. in REPRL mode, which creates a new context for + // every script. None of the templates depend on the context, so all contexts + // of an isolate (including realms) share one global template. In particular, + // all d8.dom objects of an isolate are instances of the same templates (see + // SetDomNodeCtor), no matter in which context they were created. + PerIsolateData* data = PerIsolateData::Get(isolate); + if (data->global_template_.IsEmpty()) { + data->global_template_.Reset(isolate, CreateGlobalTemplate(isolate)); + } + return data->global_template_.Get(isolate); +} + void Shell::ChangeDirectoryCallback( const v8::FunctionCallbackInfo<v8::Value>& info) { DCHECK(i::ValidateCallbackInfo(info)); @@ -4951,6 +4965,48 @@ Local<ObjectTemplate> Shell::CreateRealmTemplate(Isolate* isolate) { return realm_template; } +namespace { + +// Getter helper for lazily created function template properties: instantiates +// `templ` in the creation context of the holder, i.e. in the same context in +// which an eagerly instantiated template property would have been created. +// This is not necessarily the current context, e.g. when another realm +// accesses the property first. +void ReturnLazyTemplateFunction(const PropertyCallbackInfo<Value>& info, + Local<FunctionTemplate> templ) { + Isolate* isolate = info.GetIsolate(); + // The holder is an instance of an ObjectTemplate, so it always has a + // creation context. + Local<Context> context = info.Holder()->GetCreationContextChecked(isolate); + Local<Function> function; + if (templ->GetFunction(context).ToLocal(&function)) { + info.GetReturnValue().Set(function); + } +} + +} // namespace + +Local<FunctionTemplate> Shell::GetOrCreateTestFastCApiTemplate( + Isolate* isolate) { + // CreateTestFastCApiTemplate registers the template as the test API object + // constructor, which is_fast_c_api_object() checks against. Creating it only + // once per isolate makes that check consistent for all contexts. + Local<FunctionTemplate> templ = + PerIsolateData::Get(isolate)->GetTestApiObjectCtor(); + if (templ.IsEmpty()) templ = CreateTestFastCApiTemplate(isolate); + return templ; +} + +Local<FunctionTemplate> Shell::GetOrCreateLeafInterfaceTypeTemplate( + Isolate* isolate) { + PerIsolateData* data = PerIsolateData::Get(isolate); + if (data->leaf_interface_type_template_.IsEmpty()) { + data->leaf_interface_type_template_.Reset( + isolate, CreateLeafInterfaceTypeTemplate(isolate)); + } + return data->leaf_interface_type_template_.Get(isolate); +} + Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) { Local<ObjectTemplate> d8_template = ObjectTemplate::New(isolate); { @@ -5000,10 +5056,21 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) { // constructor when --correctness_fuzzer_suppressions is on. if (options.expose_fast_api && i::v8_flags.turbo_fast_api_calls && !i::v8_flags.correctness_fuzzer_suppressions) { - test_template->Set(isolate, "FastCAPI", - Shell::CreateTestFastCApiTemplate(isolate)); - test_template->Set(isolate, "LeafInterfaceType", - Shell::CreateLeafInterfaceTypeTemplate(isolate)); + // Instantiating these templates is fairly expensive compared to the rest + // of the context setup, and most scripts do not use them, so they are + // only instantiated on first access. + test_template->SetLazyDataProperty( + String::NewFromUtf8Literal(isolate, "FastCAPI"), + [](Local<Name> property, const PropertyCallbackInfo<Value>& info) { + ReturnLazyTemplateFunction( + info, GetOrCreateTestFastCApiTemplate(info.GetIsolate())); + }); + test_template->SetLazyDataProperty( + String::NewFromUtf8Literal(isolate, "LeafInterfaceType"), + [](Local<Name> property, const PropertyCallbackInfo<Value>& info) { + ReturnLazyTemplateFunction( + info, GetOrCreateLeafInterfaceTypeTemplate(info.GetIsolate())); + }); } // Allows testing code paths that are triggered when Origin Trials are // added in the browser. @@ -5011,10 +5078,6 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) { isolate, "installConditionalFeatures", FunctionTemplate::New(isolate, Shell::InstallConditionalFeatures)); - test_template->Set( - isolate, "setFlushDenormals", - FunctionTemplate::New(isolate, Shell::SetFlushDenormals)); - test_template->Set( isolate, "createInterceptorObject", FunctionTemplate::New(isolate, Shell::CreateInterceptorObject)); @@ -5248,7 +5311,7 @@ MaybeLocal<Context> Shell::CreateEvaluationContext(Isolate* isolate) { reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(), context_mutex_.Pointer()); // Initialize the global objects - Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate); + Local<ObjectTemplate> global_template = GetOrCreateGlobalTemplate(isolate); EscapableHandleScope handle_scope(isolate); Local<Context> context = Context::New(isolate, nullptr, global_template); if (context.IsEmpty()) { @@ -5673,7 +5736,9 @@ V8_NOINLINE void FuzzerMonitor::ControlFlowViolation() { V8_NOINLINE void FuzzerMonitor::DCheck() { // Caught in debug builds. - DCHECK(false); + constexpr bool kSimulatedDcheckError = false; + USE(kSimulatedDcheckError); + DCHECK(kSimulatedDcheckError); } V8_NOINLINE void FuzzerMonitor::Fatal() { @@ -5711,40 +5776,39 @@ V8_NOINLINE void FuzzerMonitor::UseOfUninitializedValue() { #endif } -base::OwnedVector<char> Shell::ReadChars(const char* name) { +std::optional<base::UniqueArray<char>> Shell::ReadChars(const char* name) { if (options.read_from_tcp_port >= 0) { return ReadCharsFromTcpPort(name); } FILE* file = base::OS::FOpen(name, "rb"); - if (file == nullptr) return {}; + if (file == nullptr) return std::nullopt; fseek(file, 0, SEEK_END); size_t size = ftell(file); rewind(file); - char* chars = new char[size]; + auto chars = base::UniqueArray<char>::NewForOverwrite(size); for (size_t i = 0; i < size;) { i += fread(&chars[i], 1, size - i, file); if (ferror(file)) { base::Fclose(file); - delete[] chars; - return {}; + return std::nullopt; } } base::Fclose(file); - return base::OwnedVector<char>(std::unique_ptr<char[]>(chars), size); + return chars; } MaybeLocal<PrimitiveArray> Shell::ReadLines(Isolate* isolate, const char* name) { - base::OwnedVector<char> data = ReadChars(name); + std::optional<base::UniqueArray<char>> data = ReadChars(name); - if (data.data() == nullptr) { + if (!data) { return MaybeLocal<PrimitiveArray>(); } // TODO(C++23): Replace with std::ispanstream once Clang supports it. - std::stringstream stream(std::string(data.data(), data.size())); + std::stringstream stream(std::string(data->data(), data->size())); std::string line; std::vector<std::string> lines; while (std::getline(stream, line, '\n')) { @@ -5774,8 +5838,8 @@ void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& info) { SafeUtf8Value filename(isolate, info[0]); if (!filename) return; - base::OwnedVector<char> data = ReadChars(*filename); - if (data.data() == nullptr) { + std::optional<base::UniqueArray<char>> data = ReadChars(*filename); + if (!data) { std::ostringstream error_msg; error_msg << "Error reading file \"" << std::string_view{*filename, @@ -5784,8 +5848,8 @@ void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& info) { ThrowError(isolate, error_msg.str()); return; } - Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data.size()); - memcpy(buffer->GetBackingStore()->Data(), data.data(), data.size()); + Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->size()); + base::MemCopy(buffer->GetBackingStore()->Data(), data->data(), data->size()); info.GetReturnValue().Set(buffer); } @@ -5949,7 +6013,7 @@ class InspectorFrontend final : public v8_inspector::V8Inspector::Channel { #ifdef DEBUG i::DirectHandle<i::Object> i_exception; if (maybe_exception.ToHandle(&i_exception) && - !try_catch.HasTerminated() && !i::v8_flags.fuzzing) { + !try_catch.HasTerminated()) { Local<Value> exception = Utils::ToLocal(i_exception); Local<Object> exception_obj = exception.As<Object>(); Local<String> key = v8::String::NewFromUtf8Literal( @@ -5980,8 +6044,11 @@ class InspectorClient : public v8_inspector::V8InspectorClient { inspector_->connect(1, channel_.get(), v8_inspector::StringView(), v8_inspector::V8Inspector::kFullyTrusted, v8_inspector::V8Inspector::kNotWaitingForDebugger); + // TODO(b/570436596): Migrate to V2. + START_ALLOW_USE_DEPRECATED() context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this, kInspectorClientTag); + END_ALLOW_USE_DEPRECATED() inspector_->contextCreated(v8_inspector::V8ContextInfo( context, kContextGroupId, v8_inspector::StringView())); @@ -6005,8 +6072,8 @@ class InspectorClient : public v8_inspector::V8InspectorClient { if (!isolate_) return; HandleScope scope(isolate_); Local<Context> context = context_.Get(isolate_); - context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, nullptr, - kInspectorClientTag); + context->SetAlignedPointerInEmbedderDataV2(kInspectorClientIndex, nullptr, + kInspectorClientTag); } void runMessageLoopOnPause(int contextGroupId) override { @@ -6104,6 +6171,18 @@ bool ends_with(const char* input, const char* suffix) { return false; } +bool AddBundleModule(Isolate* isolate, const std::string& name, + const std::string& content) { + { + i::ParkedMutexGuard lock_guard( + reinterpret_cast<i::Isolate*>(isolate)->main_thread_local_isolate(), + bundle_module_files_mutex.Pointer()); + if (bundle_module_files.emplace(name, content).second) return true; + } + std::cout << "Error: Duplicate bundle module: " << name << "\n"; + return false; +} + bool TryExecuteBundle(Isolate* isolate, const std::string& content, Local<String> file_name, bool* out_success) { // Find the first // JS_BUNDLE_ comment. It's either @@ -6152,15 +6231,12 @@ bool TryExecuteBundle(Isolate* isolate, const std::string& content, if (pos >= content.length()) return false; - bundle_module_files.clear(); - struct ExecutionItem { enum Type { kScript, kModuleEntrypoint }; Type type; std::string content_or_name; }; std::vector<ExecutionItem> execution_order; - int anon_module_counter = 0; while (pos < content.length()) { // We expect a marker at pos. @@ -6193,18 +6269,25 @@ bool TryExecuteBundle(Isolate* isolate, const std::string& content, std::string m_name = header.substr(module_marker_prefix.length()); std::string normalized_name = NormalizeModuleSpecifier(m_name, GetWorkingDirectory()); - bundle_module_files[normalized_name] = part_content; + if (!AddBundleModule(isolate, normalized_name, part_content)) { + *out_success = false; + return true; + } } else if (header.starts_with(entrypoint_marker_prefix)) { std::string m_name; if (header.length() > entrypoint_marker_prefix.length() && header[entrypoint_marker_prefix.length()] == ':') { m_name = header.substr(entrypoint_marker_prefix.length() + 1); } else { - m_name = "entrypoint_" + std::to_string(anon_module_counter++) + ".mjs"; + m_name = "entrypoint_" + std::to_string(bundle_anon_module_counter++) + + ".mjs"; } std::string normalized_name = NormalizeModuleSpecifier(m_name, GetWorkingDirectory()); - bundle_module_files[normalized_name] = part_content; + if (!AddBundleModule(isolate, normalized_name, part_content)) { + *out_success = false; + return true; + } execution_order.push_back( {ExecutionItem::kModuleEntrypoint, normalized_name}); } else { @@ -6230,7 +6313,6 @@ bool TryExecuteBundle(Isolate* isolate, const std::string& content, } } - bundle_module_files.clear(); return true; // Bundle handled successfully (even if execution failed) } @@ -6377,8 +6459,6 @@ SourceGroup::IsolateThread::IsolateThread(SourceGroup* group) : base::Thread(GetThreadOptions("IsolateThread")), group_(group) {} void SourceGroup::ExecuteInThread() { - base::FlushDenormalsScope denormals_scope(Shell::options.flush_denormals); - Isolate::CreateParams create_params = GetDefaultIsolateCreateParams(); Isolate* isolate = Isolate::New(create_params); @@ -6476,10 +6556,8 @@ void SerializationDataQueue::Clear() { data_.clear(); } -Worker::Worker(Isolate* parent_isolate, const char* script, - bool flush_denormals) +Worker::Worker(Isolate* parent_isolate, const char* script) : script_(i::StrDup(script)), - flush_denormals_(flush_denormals), parent_isolate_(parent_isolate), parent_task_runner_(g_platform->GetForegroundTaskRunner(parent_isolate)) { state_.store(State::kReady); @@ -6707,8 +6785,6 @@ constexpr v8::ExternalPointerTypeTag kWorkerTag = 8; Worker* Worker::GetCurrentWorker() { return current_worker_; } void Worker::ExecuteInThread() { - base::FlushDenormalsScope denormals_scope(flush_denormals_); - Isolate::CreateParams create_params = GetDefaultIsolateCreateParams(); isolate_ = Isolate::New(create_params); @@ -6904,9 +6980,45 @@ namespace { using KeepFlag = base::StrongAlias<struct KeepFlagTag, bool>; +// Match `arg` against `flag`, normalizing '_' to '-' and accepting both '-' +// and '--' for long flags (as well as "--nofoo" for "--no-foo"), matching +// FlagList::SetFlagsFromCommandLine. Returns a pointer to the remainder of +// `arg` after the matched flag name, or nullptr on mismatch. +char* MatchFlagPrefix(char* arg, const char* flag) { + if (arg == nullptr || arg[0] != '-') return nullptr; + DCHECK_EQ('-', flag[0]); + ++flag; + ++arg; + auto normalize_char = [](char ch) { return ch == '_' ? '-' : ch; }; + if (*flag == '-') { + ++flag; + // The "--" end-of-options separator requires a second '-'. + if (*flag == '\0') return *arg == '-' ? arg + 1 : nullptr; + // Long flags ("--foo") accept both "-" and "--" prefixes in `arg`. + if (*arg == '-') ++arg; + // Negated flags ("--no-foo") also accept "--nofoo" and "--no_foo". + if (flag[0] == 'n' && flag[1] == 'o' && flag[2] == '-' && arg[0] == 'n' && + arg[1] == 'o') { + flag += 3; + arg += 2; + if (normalize_char(*arg) == '-') ++arg; + } + } + DCHECK_NE('\0', *flag); + // Match the remaining characters, normalizing '_' in `arg` to '-'. + while (*flag != '\0') { + DCHECK_NE('_', *flag); + if (normalize_char(*arg) != *flag) return nullptr; + ++flag; + ++arg; + } + return arg; +} + bool FlagMatches(const char* flag, char** arg, KeepFlag keep_flag = KeepFlag{false}) { - if (strcmp(*arg, flag) == 0) { + const char* rest = MatchFlagPrefix(*arg, flag); + if (rest != nullptr && *rest == '\0') { if (!keep_flag) { *arg = nullptr; } @@ -6915,23 +7027,19 @@ bool FlagMatches(const char* flag, char** arg, return false; } -template <size_t N> -bool FlagWithArgMatches(const char (&flag)[N], char** flag_value, int argc, +bool FlagWithArgMatches(const char* flag, char** flag_value, int argc, char* argv[], int* i, KeepFlag keep_flag = KeepFlag{false}) { - char* current_arg = argv[*i]; - - // Compare the flag up to the last character of the flag name (not including - // the null terminator). - if (strncmp(current_arg, flag, N - 1) == 0) { + char* rest = MatchFlagPrefix(argv[*i], flag); + if (rest != nullptr) { // Match against --flag=value - if (current_arg[N - 1] == '=') { - *flag_value = argv[*i] + N; + if (*rest == '=') { + *flag_value = rest + 1; if (!keep_flag) argv[*i] = nullptr; return true; } // Match against --flag value - if (current_arg[N - 1] == '\0') { + if (*rest == '\0') { CHECK_LT(*i, argc - 1); if (!keep_flag) argv[*i] = nullptr; (*i)++; @@ -6941,16 +7049,27 @@ bool FlagWithArgMatches(const char (&flag)[N], char** flag_value, int argc, } } - flag_value = nullptr; + *flag_value = nullptr; return false; } +PRINTF_FORMAT(1, 2) +void ReportFlagWarning(const char* format, ...) { + base::OS::PrintError("Warning: "); + va_list args; + va_start(args, format); + base::OS::VPrintError(format, args); + va_end(args); + base::OS::PrintError("\n"); +} + } // namespace bool Shell::SetOptions(int argc, char* argv[]) { i::v8_flags.flag_processing_mode = "abort-on-error"; options.d8_path = argv[0]; bool disallow_unsafe_flags = false; + bool disallow_developer_only_features = false; bool flag_processing_mode_explicitly_set = false; for (int i = 0; i < argc; i++) { char* flag_value = nullptr; @@ -6980,15 +7099,23 @@ bool Shell::SetOptions(int argc, char* argv[]) { exit_on_flag_contradictions = false; } } + // LINT.IfChange(FuzzingImplications) } else if (FlagMatches("--fuzzing", &argv[i], KeepFlag{true}) || - FlagMatches("--sandbox-fuzzing", &argv[i], KeepFlag{true})) { - // Set v8_flags.fuzzing early because this is tested in some locations to - // decide how to handle conflicting flags (it would later be set by - // implications but we need it being set earlier). + FlagMatches("--sandbox-fuzzing", &argv[i], KeepFlag{true}) || + FlagMatches("--sandbox-trap-fuzzing", &argv[i], + KeepFlag{true}) || + FlagMatches("--allow-natives-for-differential-fuzzing", &argv[i], + KeepFlag{true})) { + // Match --fuzzing and all V8 flags that imply --fuzzing. V8 flag + // implications are only processed later in V8::Initialize(), so we need + // to manually mirror those implications (including --fuzzing implying + // --disallow-unsafe-flags) here for d8 option processing. i::v8_flags.fuzzing = true; + disallow_unsafe_flags = true; if (!flag_processing_mode_explicitly_set) { check_d8_flag_contradictions = false; } + // LINT.ThenChange(/src/flags/flag-definitions.h:FuzzingImplications) } else if (FlagMatches("--run-as-security-poc", &argv[i], KeepFlag{true}) || FlagMatches("--run-as-sandbox-security-poc", &argv[i], KeepFlag{true})) { @@ -7002,10 +7129,8 @@ bool Shell::SetOptions(int argc, char* argv[]) { // Flag implications are only processed much later, so we need to manually // establish this link here. disallow_unsafe_flags = true; - static constexpr char kFlagProcessingMode[] = - "--flag-processing-mode=exit-on-error"; - i::FlagList::SetFlagsFromString(kFlagProcessingMode, - strlen(kFlagProcessingMode)); + disallow_developer_only_features = true; + i::v8_flags.flag_processing_mode.Set("exit-on-error"); // We require `--run-as-security-poc`or `--run-as-sandbox-security-poc` as // first parameter to set the flag processing modes properly. The // configuration then consistently bails out with exit(-1) for flag @@ -7016,6 +7141,9 @@ bool Shell::SetOptions(int argc, char* argv[]) { } else if (FlagMatches("--disallow-unsafe-flags", &argv[i], KeepFlag{true})) { disallow_unsafe_flags = true; + } else if (FlagMatches("--disallow-developer-only-features", &argv[i], + KeepFlag{true})) { + disallow_developer_only_features = true; } else if (FlagMatches("--version", &argv[i])) { printf("V8 version %s\n", V8::GetVersion()); base::OS::ExitProcess(0); @@ -7023,8 +7151,7 @@ bool Shell::SetOptions(int argc, char* argv[]) { options.interactive_shell = true; } else if (FlagMatches("--test", &argv[i])) { options.test_shell = true; - } else if (FlagMatches("--notest", &argv[i]) || - FlagMatches("--no-test", &argv[i])) { + } else if (FlagMatches("--no-test", &argv[i])) { options.test_shell = false; } else if (FlagMatches("--send-idle-notification", &argv[i])) { options.send_idle_notification = true; @@ -7072,7 +7199,7 @@ bool Shell::SetOptions(int argc, char* argv[]) { &i)) { options.icu_locale = flag_value; #ifdef V8_USE_EXTERNAL_STARTUP_DATA - } else if (FlagWithArgMatches("--snapshot_blob", &flag_value, argc, argv, + } else if (FlagWithArgMatches("--snapshot-blob", &flag_value, argc, argv, &i)) { options.snapshot_blob = flag_value; #endif // V8_USE_EXTERNAL_STARTUP_DATA @@ -7099,8 +7226,7 @@ bool Shell::SetOptions(int argc, char* argv[]) { } } else if (FlagMatches("--streaming-compile", &argv[i])) { options.streaming_compile = true; - } else if ((FlagMatches("--no-streaming-compile", &argv[i])) || - (FlagMatches("--nostreaming-compile", &argv[i]))) { + } else if (FlagMatches("--no-streaming-compile", &argv[i])) { options.streaming_compile = false; } else if (FlagMatches("--enable-tracing", &argv[i])) { options.trace_enabled = true; @@ -7152,7 +7278,13 @@ bool Shell::SetOptions(int argc, char* argv[]) { options.quiet_load = true; } else if (FlagWithArgMatches("--thread-pool-size", &flag_value, argc, argv, &i)) { - options.thread_pool_size = atoi(flag_value); + int requested_size = atoi(flag_value); + int clamped_size = std::clamp(requested_size, 0, 16); + if (clamped_size != requested_size) { + ReportFlagWarning("clamping --thread-pool-size from %d to %d", + requested_size, clamped_size); + } + options.thread_pool_size = clamped_size; } else if (FlagMatches("--no-can-block", &argv[i])) { options.can_block = false; } else if (FlagMatches("--stress-delay-tasks", &argv[i])) { @@ -7212,8 +7344,6 @@ bool Shell::SetOptions(int argc, char* argv[]) { #endif // V8_ENABLE_WEBASSEMBLY } else if (FlagMatches("--expose-fast-api", &argv[i])) { options.expose_fast_api = true; - } else if (FlagMatches("--flush-denormals", &argv[i])) { - options.flush_denormals = true; } else { #ifdef V8_TARGET_OS_WIN Shell::PreProcessUnicodeFilenameArg(argv, i); @@ -7223,41 +7353,67 @@ bool Shell::SetOptions(int argc, char* argv[]) { DCHECK(options.num_isolates); - if (disallow_unsafe_flags) { - const auto check_flag_is_not_specified = - [&]<typename T>(const ShellOptions::DisallowReassignment<T>& flag) { - if (!flag.WasSpecified()) { - return; - } - ReportFlagError( - "Command-line provided flag --%s is prohibited by " - "--disallow-unsafe-flags", - flag.name()); - }; // NOLINT(readability/braces) - // The --disallow-unsafe-flags is meant to block known unsafe configurations - // and mitigate spurious reports due invalid flag combinations/values. To - // prevent AI agents and/or fuzzers from using a new unsafe flag, add it to - // the list below. - check_flag_is_not_specified(options.trace_enabled); - check_flag_is_not_specified(options.trace_config); - check_flag_is_not_specified(options.trace_path); - // Inspector security bugs must be shown through the embedder (i.e. Chrome, - // or content_shell). - check_flag_is_not_specified(options.enable_inspector); - check_flag_is_not_specified(options.lcov_file); - check_flag_is_not_specified(options.simulate_errors); - check_flag_is_not_specified(options.enable_os_system); - check_flag_is_not_specified(options.snapshot_blob); - check_flag_is_not_specified(options.thread_pool_size); - check_flag_is_not_specified(options.thread_pool_size); - check_flag_is_not_specified(options.dump_counters); - check_flag_is_not_specified(options.dump_counters_nvp); + const auto handle_unsafe_d8_flag = [&](auto& flag) { + if (!flag.WasSpecified()) return; + if (disallow_unsafe_flags) { + if (check_d8_flag_contradictions) { + ReportFlagError( + "Command-line provided flag --%s is prohibited by " + "--disallow-unsafe-flags", + flag.name()); + } else { + ReportFlagWarning( + "resetting d8 flag --%s due to --disallow-unsafe-flags", + flag.name()); + flag.Reset(); + } + } else { + i::v8_flags.test_only_unsafe.Set(true); + } + }; + // The flags below represent known unsafe configurations. They are blocked by + // --disallow-unsafe-flags or marked as test_only_unsafe to mitigate spurious + // reports due to invalid flag combinations/values. To prevent AI agents + // and/or fuzzers from using a new unsafe flag, add it to the list below. + handle_unsafe_d8_flag(options.trace_enabled); + handle_unsafe_d8_flag(options.trace_config); + handle_unsafe_d8_flag(options.trace_path); + // Inspector security bugs must be shown through the embedder (i.e. Chrome, + // or content_shell). + handle_unsafe_d8_flag(options.enable_inspector); + handle_unsafe_d8_flag(options.lcov_file); + handle_unsafe_d8_flag(options.enable_os_system); + handle_unsafe_d8_flag(options.snapshot_blob); + handle_unsafe_d8_flag(options.icu_data_file); #ifdef V8_OS_LINUX - check_flag_is_not_specified(options.perf_ctl_fd); - check_flag_is_not_specified(options.perf_ack_fd); - check_flag_is_not_specified(options.scope_linux_perf_to_mark_measure); + handle_unsafe_d8_flag(options.perf_ctl_fd); + handle_unsafe_d8_flag(options.perf_ack_fd); + handle_unsafe_d8_flag(options.scope_linux_perf_to_mark_measure); #endif - } + + const auto handle_developer_only_d8_flag = [&](auto& flag) { + if (!flag.WasSpecified()) return; + if (disallow_developer_only_features) { + if (check_d8_flag_contradictions) { + ReportFlagError( + "Command-line provided flag --%s is prohibited by " + "--disallow-developer-only-features", + flag.name()); + } else { + ReportFlagWarning( + "resetting d8 flag --%s due to --disallow-developer-only-features", + flag.name()); + flag.Reset(); + } + } else { + i::v8_flags.developer_only_features.Set(true); + } + }; + // Handle d8-only developer-only flags. + handle_developer_only_d8_flag(options.dump_counters); + handle_developer_only_d8_flag(options.dump_counters_nvp); + handle_developer_only_d8_flag(options.dump_system_memory_stats); + handle_developer_only_d8_flag(options.simulate_errors); #ifdef V8_OS_LINUX if (options.scope_linux_perf_to_mark_measure) { @@ -7297,20 +7453,11 @@ bool Shell::SetOptions(int argc, char* argv[]) { " -C set the current working directory before executing " "subsequent files\n"; using HelpOptions = i::FlagList::HelpOptions; - static constexpr char kStandaloneD8ShellFlag[] = "--is_standalone_d8_shell"; - i::FlagList::SetFlagsFromString(kStandaloneD8ShellFlag, - strlen(kStandaloneD8ShellFlag)); + i::v8_flags.is_standalone_d8_shell.Set(true); i::FlagList::SetFlagsFromCommandLine(&argc, argv, true, HelpOptions(HelpOptions::kExit, usage)); i::FlagList::ResolveContradictionsWhenFuzzing(); - options.mock_arraybuffer_allocator = i::v8_flags.mock_arraybuffer_allocator; - options.mock_arraybuffer_allocator_limit = - i::v8_flags.mock_arraybuffer_allocator_limit; -#ifdef V8_OS_LINUX - options.multi_mapped_mock_allocator = i::v8_flags.multi_mapped_mock_allocator; -#endif // V8_OS_LINUX - if (i::v8_flags.stress_snapshot && options.expose_fast_api && check_d8_flag_contradictions) { FATAL("Flag --expose-fast-api is incompatible with --stress-snapshot."); @@ -7320,9 +7467,8 @@ bool Shell::SetOptions(int argc, char* argv[]) { if (check_d8_flag_contradictions) { FATAL("Flag --enable-tracing is incompatible with --predictable."); } else { - fprintf(stderr, - "Warning: disabling flag --enable-tracing due to conflicting " - "flags\n"); + ReportFlagWarning( + "disabling flag --enable-tracing due to conflicting flags"); options.trace_enabled = false; } } @@ -7351,7 +7497,7 @@ bool Shell::SetOptions(int argc, char* argv[]) { // Pass on to SourceGroup, which understands these options. } else if (strncmp(str, "--", 2) == 0) { if (!i::v8_flags.correctness_fuzzer_suppressions) { - printf("Warning: unknown flag %s.\nTry --help for options\n", str); + ReportFlagWarning("unknown flag %s.\nTry --help for options", str); } } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { set_script_executed(); @@ -7419,6 +7565,15 @@ int Shell::RunMain(v8::Isolate* isolate, bool last_run) { WaitForAllWorkerAndIsolateThreads(isolate); } + // Workers created by the bundles have terminated, so no more bundle modules + // are needed. + { + i::ParkedMutexGuard lock_guard(i_isolate->main_thread_local_isolate(), + bundle_module_files_mutex.Pointer()); + bundle_module_files.clear(); + } + bundle_anon_module_counter = 0; + // Other threads have terminated, we can now run the artificial // serialize-deserialize pass (which destructively mutates heap state). if (success && last_run && i::v8_flags.stress_snapshot) { @@ -8028,11 +8183,14 @@ int Shell::Main(int argc, char* argv[]) { ConfigurePartitionAllocIfEnabled(); v8::base::EnsureConsoleOutput(); - // TODO(40925855): Enable this more broadly outside of d8. + // TODO(40925855): Enable this more broadly outside of d8. Android is + // disabled for now as test bots run OS versions <17 that do not support the + // user space zero segment. #if defined(V8_ENABLE_PARTITION_ALLOC) -#if PA_BUILDFLAG(ENABLE_USER_SPACE_ZERO_SEGMENT) +#if PA_BUILDFLAG(ENABLE_USER_SPACE_ZERO_SEGMENT) && !defined(V8_OS_ANDROID) i::v8_flags.sandbox_prohibit_insecure_mode = true; -#endif // PA_BUILDFLAG(ENABLE_USER_SPACE_ZERO_SEGMENT) +#endif // PA_BUILDFLAG(ENABLE_USER_SPACE_ZERO_SEGMENT) && + // !defined(V8_OS_ANDROID) #endif // defined(V8_ENABLE_PARTITION_ALLOC) if (!v8::Shell::SetOptions(argc, argv)) return 1; @@ -8047,8 +8205,6 @@ int Shell::Main(int argc, char* argv[]) { if (!i::v8_flags.fuzzing) d8_install_sigterm_handler(); - base::FlushDenormalsScope denormals_scope(options.flush_denormals); - if (!v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file)) { fprintf(stderr, "%s: Failed to initialize ICU\n", argv[0]); return 1; @@ -8166,6 +8322,18 @@ int Shell::Main(int argc, char* argv[]) { i::v8_flags.freeze_flags_after_init = false; } +#ifdef V8_FUZZILLI + // IMPORTANT: order-sensitive, see cov.cc. With inline-bool-flag coverage, + // the coverage of crashing executions has to be flushed from signal handlers. + // They must be installed after the in-process stack dumping handlers + // (installed when creating the platform above), which do not forward signals + // to previous handlers, before V8::Initialize(), which installs the sandbox + // crash filter in sandbox testing/fuzzing mode, and before the Wasm trap + // handler (installed below), which forwards non-Wasm faults to the previous + // handler. + sanitizer_cov_install_crash_flush_handlers(); +#endif // V8_FUZZILLI + v8::V8::Initialize(); if (options.snapshot_blob) { v8::V8::InitializeExternalStartupDataFromFile(options.snapshot_blob); @@ -8185,23 +8353,23 @@ int Shell::Main(int argc, char* argv[]) { v8::ArrayBuffer::Allocator::NewDefaultAllocator()); MockArrayBufferAllocator mock_arraybuffer_allocator(default_allocator.get()); const size_t memory_limit = - options.mock_arraybuffer_allocator_limit * options.num_isolates; + i::v8_flags.mock_arraybuffer_allocator_limit * options.num_isolates; MockArrayBufferAllocatorWithLimit mock_arraybuffer_allocator_with_limit( default_allocator.get(), - memory_limit >= options.mock_arraybuffer_allocator_limit + memory_limit >= i::v8_flags.mock_arraybuffer_allocator_limit ? memory_limit : std::numeric_limits<size_t>::max()); #ifdef V8_OS_LINUX MultiMappedAllocator multi_mapped_mock_allocator(default_allocator.get()); #endif // V8_OS_LINUX - if (options.mock_arraybuffer_allocator) { + if (i::v8_flags.mock_arraybuffer_allocator) { if (memory_limit) { Shell::array_buffer_allocator = &mock_arraybuffer_allocator_with_limit; } else { Shell::array_buffer_allocator = &mock_arraybuffer_allocator; } #ifdef V8_OS_LINUX - } else if (options.multi_mapped_mock_allocator) { + } else if (i::v8_flags.multi_mapped_mock_allocator) { Shell::array_buffer_allocator = &multi_mapped_mock_allocator; #endif // V8_OS_LINUX } else { @@ -8251,8 +8419,9 @@ int Shell::Main(int argc, char* argv[]) { if (i::v8_flags.test_only_unsafe) { fprintf(stderr, "V8 is running with an unsupported configuration. Important " - "subsystems are mocked or disabled. Bugs reported under this " - "configuration will be considered invalid.\n"); + "subsystems are mocked or disabled, or unsupported features / " + "modes are enabled. Bugs reported under this configuration will " + "be considered invalid.\n"); } if (i::v8_flags.developer_only_features) { @@ -8273,6 +8442,10 @@ int Shell::Main(int argc, char* argv[]) { } } + if (i::v8_flags.fuzzilli_enable_optimized_code_coverage) { + cov_init_optimized_code_edges(kFuzzilliNumOptimizedCodeEdges); + } + // Let the parent process (Fuzzilli) know we are ready. char helo[] = "HELO"; if (write(REPRL_CWFD, helo, 4) != 4 || read(REPRL_CRFD, helo, 4) != 4) { @@ -8302,9 +8475,11 @@ int Shell::Main(int argc, char* argv[]) { // Fuzzilli REPRL = read-eval-print-loop do { -#ifdef V8_FUZZILLI +#if defined(V8_FUZZILLI) || defined(V8_DUMPLING) v8::internal::Isolate* internal_isolate = reinterpret_cast<v8::internal::Isolate*>(isolate); +#endif // defined(V8_FUZZILLI) || defined(V8_DUMPLING) +#ifdef V8_FUZZILLI internal_isolate->descriptor_lookup_cache()->Clear(); internal_isolate->compilation_cache()->Clear(); if (fuzzilli_reprl) { @@ -8313,11 +8488,15 @@ int Shell::Main(int argc, char* argv[]) { if (nread != 4 || action != 'cexe') { FATAL("REPRL: Unknown action: %u", action); } + // With inline-bool-flag coverage, drop the edges hit since the last + // execution (e.g. during startup) so that they are not attributed to + // this one. (With trace-pc-guard, such edges are not reported either: + // their guards are disabled and the parent clears the bitmap before + // every execution.) + sanitizer_cov_discard_bool_flags(); } #endif // V8_FUZZILLI #ifdef V8_DUMPLING - v8::internal::Isolate* internal_isolate = - reinterpret_cast<v8::internal::Isolate*>(isolate); // TODO(mdanylo): ideally this should be a part of fd-based protocol // between Fuzzilli and V8. if (internal_isolate->dumpling_manager()->IsDumpingEnabled()) { @@ -8330,15 +8509,15 @@ int Shell::Main(int argc, char* argv[]) { if (options.trace_enabled) { platform::tracing::TraceConfig* trace_config; if (options.trace_config) { - base::OwnedVector<char> trace_config_json_str = + std::optional<base::UniqueArray<char>> trace_config_json_str = ReadChars(options.trace_config); - if (trace_config_json_str.data() == nullptr) { + if (!trace_config_json_str) { printf("Failed to read trace config from '%s'\n", options.trace_config.get()); base::OS::ExitProcess(1); } trace_config = tracing::CreateTraceConfigFromJSON( - isolate, trace_config_json_str.as_vector()); + isolate, trace_config_json_str->as_span()); } else { trace_config = platform::tracing::TraceConfig::CreateDefaultTraceConfig(); @@ -8462,6 +8641,18 @@ int Shell::Main(int argc, char* argv[]) { // Send result to parent (fuzzilli) and reset edge guards. if (fuzzilli_reprl) { int status = result << 8; + + size_t num_optimized_code_edges = 0; + if (i::v8_flags.fuzzilli_enable_optimized_code_coverage) { + num_optimized_code_edges = + cov_update_and_reset_optimized_code_coverage(); + } + + // With inline-bool-flag coverage, the edges are only written to the + // shared memory bitmap here (or when crashing), so this must happen + // before the bitmap is read, i.e. before the coverage statistics are + // computed and before the parent is notified. + sanitizer_cov_flush_bool_flags(); if (options.fuzzilli_coverage_statistics) { std::vector<bool> bitmap = i::BasicBlockProfiler::Get()->GetCoverageBitmap( @@ -8474,7 +8665,8 @@ int Shell::Main(int argc, char* argv[]) { std::ofstream covlog("covlog.txt", std::ios::app); covlog << iteration_counter << "\t" << tot << "\t" << sanitizer_cov_count_discovered_edges() << "\t" - << bitmap.size() << std::endl; + << bitmap.size() << "\t" << num_optimized_code_edges + << std::endl; iteration_counter++; } // This is run once per REPRL loop. In case of crash the coverage of diff --git a/deps/v8/src/d8/d8.h b/deps/v8/src/d8/d8.h index eae46fa9d05c..0c7ad50a1a9e 100644 --- a/deps/v8/src/d8/d8.h +++ b/deps/v8/src/d8/d8.h @@ -27,7 +27,7 @@ #include "src/base/platform/platform.h" #include "src/base/platform/time.h" #include "src/base/platform/wrappers.h" -#include "src/base/vector.h" +#include "src/base/unique-array.h" #include "src/d8/async-hooks-wrapper.h" // For V8_ENABLE_HARDWARE_WATCHPOINT_SUPPORT. #include "src/d8/hardware-watchpoints.h" @@ -267,8 +267,7 @@ class Worker : public std::enable_shared_from_this<Worker> { public: static constexpr i::ManagedTypeId kTypeID = i::ManagedTypeId::kD8Worker; - explicit Worker(Isolate* parent_isolate, const char* script, - bool flush_denormals); + explicit Worker(Isolate* parent_isolate, const char* script); ~Worker(); // Post a message to the worker. The worker will take ownership of the @@ -348,7 +347,6 @@ class Worker : public std::enable_shared_from_this<Worker> { base::Thread* thread_ = nullptr; char* script_; - bool flush_denormals_; std::atomic<State> state_; bool is_joined_ = false; // For signalling that the worker has started. @@ -459,6 +457,11 @@ class PerIsolateData { std::unordered_set<DynamicImportData*> import_data_; Global<FunctionTemplate> test_api_object_ctor_; Global<FunctionTemplate> dom_node_ctor_; + // See Shell::GetOrCreateLeafInterfaceTypeTemplate. + Global<FunctionTemplate> leaf_interface_type_template_; + // The template of the global object of all contexts that d8 creates in this + // isolate, see Shell::GetOrCreateGlobalTemplate. + Global<ObjectTemplate> global_template_; // Track workers and their callbacks separately, so that we know both which // workers are still registered, and which of them have callbacks. We can't // rely on Shell::running_workers_ or worker.IsTerminated(), because these are @@ -508,7 +511,7 @@ class ShellOptions { class DisallowReassignment { public: DisallowReassignment(const char* name, T value) - : name_(name), value_(value) {} + : name_(name), value_(value), default_value_(value) {} operator T() const { return value_; } T get() const { return value_; } @@ -529,6 +532,10 @@ class ShellOptions { return *this; } void Overwrite(T value) { value_ = value; } + void Reset() { + value_ = default_value_; + specified_ = false; + } bool WasSpecified() const { return specified_; } @@ -537,6 +544,7 @@ class ShellOptions { private: const char* name_; T value_; + const T default_value_; bool specified_ = false; }; DisallowReassignment<bool> can_block = {"can_block", true}; @@ -572,12 +580,6 @@ class ShellOptions { "dump-system-memory-stats", false}; DisallowReassignment<bool> ignore_unhandled_promises = { "ignore-unhandled-promises", false}; - DisallowReassignment<bool> mock_arraybuffer_allocator = { - "mock-arraybuffer-allocator", false}; - DisallowReassignment<size_t> mock_arraybuffer_allocator_limit = { - "mock-arraybuffer-allocator-limit", 0}; - DisallowReassignment<bool> multi_mapped_mock_allocator = { - "multi-mapped-mock-allocator", false}; // This flag enables a bare-bones InspectorClient implementation in the shell. // It is only a harness for basic tests in `test/debugger`, and not shipped // in production. `test/inspector` uses the `inspector-test` binary instead. @@ -637,7 +639,6 @@ class ShellOptions { DisallowReassignment<bool> wasm_trap_handler = {"wasm-trap-handler", true}; #endif // V8_ENABLE_WEBASSEMBLY DisallowReassignment<bool> expose_fast_api = {"expose-fast-api", false}; - DisallowReassignment<bool> flush_denormals = {"flush-denormals", false}; DisallowReassignment<size_t> max_serializer_memory = {"max-serializer-memory", 1 * i::MB}; DisallowReassignment<bool> bundle = {"bundle", false}; @@ -761,8 +762,6 @@ class Shell : public i::AllStatic { static void InstallConditionalFeatures( const v8::FunctionCallbackInfo<v8::Value>& info); - static void SetFlushDenormals( - const v8::FunctionCallbackInfo<v8::Value>& info); static void AsyncHooksCreateHook( const v8::FunctionCallbackInfo<v8::Value>& info); @@ -815,7 +814,7 @@ class Shell : public i::AllStatic { static void ReadFile(const v8::FunctionCallbackInfo<v8::Value>& info); static void CreateWasmMemoryMapDescriptor( const v8::FunctionCallbackInfo<v8::Value>& info); - static base::OwnedVector<char> ReadChars(const char* name); + static std::optional<base::UniqueArray<char>> ReadChars(const char* name); static MaybeLocal<PrimitiveArray> ReadLines(Isolate* isolate, const char* name); static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& info); @@ -929,7 +928,8 @@ class Shell : public i::AllStatic { static void SetWaitUntilDone(Isolate* isolate, bool value); - static base::OwnedVector<char> ReadCharsFromTcpPort(const char* name); + static std::optional<base::UniqueArray<char>> ReadCharsFromTcpPort( + const char* name); static void set_script_executed() { script_executed_.store(true); } static bool ChangeWorkingDirectory(const std::string& path, @@ -1004,6 +1004,7 @@ class Shell : public i::AllStatic { static Local<FunctionTemplate> CreateNodeTemplates( Isolate* isolate, Local<FunctionTemplate> event_target); static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate); + static Local<ObjectTemplate> GetOrCreateGlobalTemplate(Isolate* isolate); static Local<ObjectTemplate> CreateOSTemplate(Isolate* isolate); static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate); static Local<ObjectTemplate> CreateAsyncHookTemplate(Isolate* isolate); @@ -1013,6 +1014,10 @@ class Shell : public i::AllStatic { static Local<FunctionTemplate> CreateTestFastCApiTemplate(Isolate* isolate); static Local<FunctionTemplate> CreateLeafInterfaceTypeTemplate( Isolate* isolate); + static Local<FunctionTemplate> GetOrCreateTestFastCApiTemplate( + Isolate* isolate); + static Local<FunctionTemplate> GetOrCreateLeafInterfaceTypeTemplate( + Isolate* isolate); static void CreateInterceptorObject( const v8::FunctionCallbackInfo<v8::Value>& info); static void CreateAccessCheckedObject( diff --git a/deps/v8/src/debug/debug-block-list.cc b/deps/v8/src/debug/debug-block-list.cc index 7990fbc040d5..cb817217d195 100644 --- a/deps/v8/src/debug/debug-block-list.cc +++ b/deps/v8/src/debug/debug-block-list.cc @@ -66,11 +66,7 @@ Handle<StringSet> EnsureLocalsBlockList( } std::optional<DebugScriptScope> closure_scope = - closure_scope_info->scope_type() == FUNCTION_SCOPE - ? FindClosureScope(debug_scope_info, shared_info->StartPosition(), - shared_info->EndPosition(), - closure_scope_info->scope_type()) - : DebugScriptScope::FromIndex(debug_scope_info, 0); + FindClosureScope(debug_scope_info, *shared_info); DCHECK(closure_scope.has_value()); if (!closure_scope.has_value()) { return StringSet::New(isolate); diff --git a/deps/v8/src/debug/debug-coverage.cc b/deps/v8/src/debug/debug-coverage.cc index 9f041644d09e..95d7e04daf29 100644 --- a/deps/v8/src/debug/debug-coverage.cc +++ b/deps/v8/src/debug/debug-coverage.cc @@ -690,8 +690,8 @@ std::unique_ptr<Coverage> Coverage::CollectWasmData(Isolate* isolate) { size_t i_name = 0; for (CoverageScript& script : *result) { for (CoverageFunction& function : script.functions) { - function.name = isolate->factory()->InternalizeString( - function_names[i_name].c_str(), function_names[i_name].length()); + function.name = + isolate->factory()->InternalizeUtf8String(function_names[i_name]); i_name++; } } diff --git a/deps/v8/src/debug/debug-evaluate.cc b/deps/v8/src/debug/debug-evaluate.cc index 0ad559410946..0f27ba101f10 100644 --- a/deps/v8/src/debug/debug-evaluate.cc +++ b/deps/v8/src/debug/debug-evaluate.cc @@ -221,7 +221,7 @@ DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, evaluation_context_ = handle(frame_inspector_.GetFunction()->context(), isolate); } else { - evaluation_context_ = scope_iterator_.CurrentContext(); + evaluation_context_ = scope_iterator_.EvaluationContext(); } // To evaluate as if we were running eval at the point of the debug break, @@ -287,21 +287,26 @@ DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, element.wrapped_context); } - if (context_chain_.empty() && !IsNativeContext(*evaluation_context_)) { + std::optional<DebugScriptScope> target_scope = + scope_iterator_.CurrentDebugScope(); + const bool target_scope_is_contextless = + target_scope.has_value() && !target_scope->needs_context(); + if (context_chain_.empty() && + (!IsNativeContext(*evaluation_context_) || target_scope_is_contextless)) { // When evaluating in an outer scope (!InInnerScope()), context_chain_ is // empty. We must still wrap evaluation_context_ in a DebugEvaluateContext // so that Context::Lookup sets has_seen_debug_evaluate_context = true and // consults the blocklist stored in LocalsBlockListCache on outer contexts. // If the target outer scope does not have its own runtime Context, we also // calculate its [S_eval, K) blocklist on the fly and attach it to the - // synthetic scope_info. + // synthetic scope_info. This is also required if the closest outer + // context is the native context. EnsureLocalsBlockList(isolate_, outer_info()); scope_info = ScopeInfo::CreateForWithScope(isolate, scope_info); scope_info->SetIsDebugEvaluateScope(); - if (std::optional<DebugScriptScope> scope = - scope_iterator_.CurrentDebugScope(); - scope.has_value() && !scope->needs_context()) { - Handle<StringSet> block_list = CalculateScopeBlockList(isolate_, *scope); + if (target_scope_is_contextless) { + Handle<StringSet> block_list = + CalculateScopeBlockList(isolate_, *target_scope); isolate_->LocalsBlockListCacheSet(scope_info, DirectHandle<ScopeInfo>(), block_list); } @@ -327,9 +332,11 @@ void DebugEvaluate::ContextBuilder::UpdateValues() { for (uint32_t i = 0; i < keys_len; i++) { DCHECK(IsString(keys->get(i))); Handle<String> key(Cast<String>(keys->get(i)), isolate_); - DirectHandle<Object> value = JSReceiver::GetDataProperty( - isolate_, element.materialized_object, key); - scope_iterator_.SetVariableValue(key, value); + LookupIterator it(isolate_, element.materialized_object, + PropertyKey(isolate_, key), + LookupIterator::OWN_SKIP_INTERCEPTOR); + if (it.state() != LookupIterator::DATA) continue; + scope_iterator_.SetVariableValue(key, it.GetDataValue()); } } scope_iterator_.Next(); @@ -356,6 +363,7 @@ bool DebugEvaluate::IsSideEffectFreeIntrinsic(Runtime::FunctionId id) { V(LoadLookupSlotForCall) \ V(GetPrivateMember) \ V(GetProperty) \ + V(HasPrivateMember) \ /* Arrays */ \ V(ArraySpeciesConstructor) \ V(HasFastPackedElements) \ @@ -905,12 +913,10 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtin id) { case Builtin::kFastFunctionPrototypeBind: case Builtin::kFunctionPrototypeCall: case Builtin::kFunctionPrototypeApply: -#ifndef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS case Builtin::kFunctionPrototypeLegacyArgumentsGetter: case Builtin::kFunctionPrototypeLegacyArgumentsSetter: case Builtin::kFunctionPrototypeLegacyCallerGetter: case Builtin::kFunctionPrototypeLegacyCallerSetter: -#endif // !V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS // Error builtins. case Builtin::kErrorConstructor: // RegExp builtins. diff --git a/deps/v8/src/debug/debug-interface.cc b/deps/v8/src/debug/debug-interface.cc index 08deeaefdf47..73139be1933f 100644 --- a/deps/v8/src/debug/debug-interface.cc +++ b/deps/v8/src/debug/debug-interface.cc @@ -141,7 +141,7 @@ Local<String> GetDateDescription(Local<Date> date) { auto buffer = i::ToDateString(jsdate->value(), i_isolate->date_cache(), i::ToDateStringMode::kLocalDateAndTime); return Utils::ToLocal(i_isolate->factory() - ->NewStringFromUtf8(base::VectorOf(buffer)) + ->NewStringFromUtf8({buffer.data(), buffer.size()}) .ToHandleChecked()); } @@ -395,13 +395,14 @@ void SetBreakPointsActive(Isolate* v8_isolate, bool is_active) { isolate->debug()->set_break_points_active(is_active); } -void PrepareStep(Isolate* v8_isolate, StepAction action) { +void PrepareStep(Isolate* v8_isolate, StepAction action, bool enter_functions) { i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); EnterV8BasicScope api_scope(isolate); CHECK(isolate->debug()->CheckExecutionState()); // Clear all current stepping setup. isolate->debug()->ClearStepping(); // Prepare step. + isolate->debug()->set_step_over_enters_functions(enter_functions); isolate->debug()->PrepareStep(static_cast<i::StepAction>(action)); } @@ -432,6 +433,9 @@ void BreakRightNow(Isolate* v8_isolate, EnterV8BasicScope api_scope(isolate); isolate->debug()->HandleDebugBreak(i::kIgnoreIfAllFramesBlackboxed, break_reasons); + if (isolate->debug()->IsRestartFrameScheduled()) { + isolate->TerminateExecution(); + } } void SetTerminateOnResume(Isolate* v8_isolate) { @@ -1173,7 +1177,7 @@ Local<Function> GetBuiltin(Isolate* v8_isolate, Builtin requested_builtin) { info->set_language_mode(i::LanguageMode::kStrict); i::Handle<i::JSFunction> fun = i::Factory::JSFunctionBuilder{isolate, info, context} - .set_map(isolate->strict_function_without_prototype_map()) + .set_map(isolate->function_without_prototype_map()) .Build(); return Utils::ToLocal(handle_scope.CloseAndEscape(fun)); @@ -1372,6 +1376,22 @@ DisableBreakScope::DisableBreakScope(v8::Isolate* isolate) DisableBreakScope::~DisableBreakScope() = default; +SideEffectCheckScope::SideEffectCheckScope(v8::Isolate* isolate) + : isolate_(reinterpret_cast<i::Isolate*>(isolate)), + disable_break_scope_( + std::make_unique<i::DisableBreak>(isolate_->debug())) { + isolate_->debug()->StartSideEffectCheckMode(); +} + +SideEffectCheckScope::~SideEffectCheckScope() { + isolate_->debug()->StopSideEffectCheckMode(); +} + +// static +bool SideEffectCheckScope::IsActive(v8::Isolate* isolate) { + return reinterpret_cast<i::Isolate*>(isolate)->should_check_side_effects(); +} + int Coverage::BlockData::StartOffset() const { return block_->start; } int Coverage::BlockData::EndOffset() const { return block_->end; } diff --git a/deps/v8/src/debug/debug-interface.h b/deps/v8/src/debug/debug-interface.h index 83a4d79ac3a1..8a93af80423b 100644 --- a/deps/v8/src/debug/debug-interface.h +++ b/deps/v8/src/debug/debug-interface.h @@ -145,7 +145,10 @@ enum class BreakReason : uint8_t { }; typedef base::EnumSet<BreakReason> BreakReasons; -void PrepareStep(Isolate* isolate, StepAction action); +// If {enter_functions} is set, a StepOver also enters every function for +// which DebugDelegate::ShouldEnterFunction returns true. +V8_EXPORT_PRIVATE void PrepareStep(Isolate* isolate, StepAction action, + bool enter_functions = false); bool PrepareRestartFrame(Isolate* isolate, int callFrameOrdinal); void ClearStepping(Isolate* isolate); V8_EXPORT_PRIVATE void BreakRightNow( @@ -314,6 +317,13 @@ class DebugDelegate { int column) { return false; } + // Only called during a StepOver prepared with {enter_functions}. Returns + // whether the step should enter the function spanning [start, end). + virtual bool ShouldEnterFunction(v8::Local<debug::Script> script, + const debug::Location& start, + const debug::Location& end) { + return false; + } // Called every time a breakpoint condition is evaluated. This method is // called before `BreakProgramRequested` if the condition is truthy. @@ -483,6 +493,15 @@ class V8_EXPORT_PRIVATE ScopeIterator { ScopeTypeWasmExpressionStack }; + enum class VariableInfo { + // The scope does not declare any variables. + kEmpty, + // The scope declares variables, but none of their values are available. + kAllUnavailable, + // The scope declares at least one variable with an available value. + kAvailable, + }; + virtual bool Done() = 0; virtual void Advance() = 0; virtual ScopeType GetType() = 0; @@ -492,9 +511,9 @@ class V8_EXPORT_PRIVATE ScopeIterator { virtual bool HasLocationInfo() = 0; virtual debug::Location GetStartLocation() = 0; virtual debug::Location GetEndLocation() = 0; - // Whether the scope declares any variables (even if their values are not - // available). Scopes that don't are reported as empty. - virtual bool DeclaresLocals() = 0; + // Whether the scope declares any variables and whether their values are + // available. + virtual VariableInfo GetVariableInfo() = 0; virtual bool SetVariableValue(v8::Local<v8::String> name, v8::Local<v8::Value> value) = 0; @@ -598,6 +617,17 @@ class V8_NODISCARD DisableBreakScope { std::unique_ptr<i::DisableBreak> scope_; }; +class V8_NODISCARD SideEffectCheckScope { + public: + explicit SideEffectCheckScope(v8::Isolate* isolate); + ~SideEffectCheckScope(); + static bool IsActive(v8::Isolate* isolate); + + private: + i::Isolate* isolate_; + std::unique_ptr<i::DisableBreak> disable_break_scope_; +}; + class EphemeronTable : public v8::Object { public: EphemeronTable() = delete; diff --git a/deps/v8/src/debug/debug-property-iterator.cc b/deps/v8/src/debug/debug-property-iterator.cc index 3994a2ffbced..65c28e44bcbe 100644 --- a/deps/v8/src/debug/debug-property-iterator.cc +++ b/deps/v8/src/debug/debug-property-iterator.cc @@ -4,6 +4,8 @@ #include "src/debug/debug-property-iterator.h" +#include <array> + #include "src/api/api-inl.h" #include "src/base/flags.h" #include "src/objects/js-array-buffer-inl.h" @@ -133,13 +135,12 @@ v8::Maybe<v8::PropertyAttribute> DebugPropertyIterator::attributes() { // V8 will crash. #if DEBUG - auto property_message = base::OwnedVector<char>::NewForOverwrite(128); - auto name_buffer = base::OwnedVector<char>::NewForOverwrite(100); - raw_name()->NameShortPrint(name_buffer.as_vector()); - v8::base::SNPrintF(property_message.as_vector(), - "Invalid result for property \"%s\"\n", - name_buffer.begin()); - DCHECK_WITH_MSG(result.FromJust() != ABSENT, property_message.begin()); + std::array<char, 128> property_message; + std::array<char, 100> name_buffer; + raw_name()->NameShortPrint(name_buffer); + v8::base::SNPrintF(property_message, "Invalid result for property \"%s\"\n", + name_buffer.data()); + DCHECK_WITH_MSG(result.FromJust() != ABSENT, property_message.data()); #endif return Just(static_cast<v8::PropertyAttribute>(result.FromJust())); } diff --git a/deps/v8/src/debug/debug-scope-info.cc b/deps/v8/src/debug/debug-scope-info.cc index fcff84c47e06..2784bc27b052 100644 --- a/deps/v8/src/debug/debug-scope-info.cc +++ b/deps/v8/src/debug/debug-scope-info.cc @@ -745,6 +745,15 @@ std::optional<DebugScriptScope> FindClosureScope( return std::nullopt; } +std::optional<DebugScriptScope> FindClosureScope( + DirectHandle<DebugScriptScopeInfo> info, + Tagged<SharedFunctionInfo> shared) { + ScopeType scope_type = shared->scope_info()->scope_type(); + if (scope_type != FUNCTION_SCOPE) return DebugScriptScope::FromIndex(info, 0); + return FindClosureScope(info, shared->StartPosition(), shared->EndPosition(), + scope_type); +} + namespace { // Visits all descendants of `scope` and narrows `*best` down to the scope with @@ -753,6 +762,7 @@ void NarrowToInnermostScope(DebugScriptScope scope, int position, DebugScriptScope* best) { for (std::optional<DebugScriptScope> child = scope.first_child(); child.has_value(); child = child->next_sibling()) { + if (child->is_function_scope()) continue; // Update `*best` if `child` contains `position` and is a tighter fit than // the currently best scope. Generators have the same source position as // the scope they belong to, so we also check for equality. @@ -774,6 +784,28 @@ DebugScriptScope FindInnermostScope(DebugScriptScope closure_scope, return best; } +std::optional<DebugScriptScope> FindEvalOuterScope( + Isolate* isolate, DirectHandle<Script> script) { + if (script->compilation_kind() != Script::CompilationKind::kDirectEval || + !script->has_eval_from_shared()) { + return std::nullopt; + } + DirectHandle<SharedFunctionInfo> outer_shared(script->eval_from_shared(), + isolate); + if (!IsScript(outer_shared->script())) return std::nullopt; + DirectHandle<Script> outer_script(Cast<Script>(outer_shared->script()), + isolate); + Handle<DebugScriptScopeInfo> outer_info = + EnsureDebugScriptScopeInfo(isolate, outer_script); + if (outer_info.is_null()) return std::nullopt; + + std::optional<DebugScriptScope> closure_scope = + FindClosureScope(outer_info, *outer_shared); + if (!closure_scope.has_value()) return std::nullopt; + return FindInnermostScope(*closure_scope, + Script::GetEvalPosition(isolate, script)); +} + #ifdef VERIFY_HEAP // DebugScriptScopeInfo::DebugScriptScopeInfoVerify is placed here instead of in // objects-debug.cc to keep the exact layout of numeric_data local to diff --git a/deps/v8/src/debug/debug-scope-info.h b/deps/v8/src/debug/debug-scope-info.h index b34627e8c00f..50ce0d72a0f0 100644 --- a/deps/v8/src/debug/debug-scope-info.h +++ b/deps/v8/src/debug/debug-scope-info.h @@ -55,6 +55,7 @@ class V8_EXPORT_PRIVATE DebugScriptScope { std::optional<DebugScriptScope> next_sibling() const; // Position & Type Accessors + DirectHandle<DebugScriptScopeInfo> info() const { return info_; } int start_position() const; int end_position() const; int scope_index() const { return scope_index_; } @@ -164,6 +165,11 @@ V8_EXPORT_PRIVATE std::optional<DebugScriptScope> FindClosureScope( DirectHandle<DebugScriptScopeInfo> info, int start_position, int end_position, ScopeType scope_type); +// Returns the closure scope of `shared` in `info`: the matching function scope +// for functions, and the root scope for top-level code (script, eval, module). +V8_EXPORT_PRIVATE std::optional<DebugScriptScope> FindClosureScope( + DirectHandle<DebugScriptScopeInfo> info, Tagged<SharedFunctionInfo> shared); + // Returns the innermost scope around `position` at or below `closure_scope`, // i.e. the scope a debugger paused at `position` starts iterating from. // @@ -174,6 +180,14 @@ V8_EXPORT_PRIVATE std::optional<DebugScriptScope> FindClosureScope( V8_EXPORT_PRIVATE DebugScriptScope FindInnermostScope(DebugScriptScope closure_scope, int position); +// If `script` is a direct eval script, returns the innermost scope in the +// caller script's DebugScriptScopeInfo at the eval call site, i.e. the lexical +// parent of `script`'s root scope. Returns nullopt for all other scripts +// (including indirect eval, `new Function` and debug-evaluate code) or if the +// caller script can't be reparsed. +V8_EXPORT_PRIVATE std::optional<DebugScriptScope> FindEvalOuterScope( + Isolate* isolate, DirectHandle<Script> script); + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/debug/debug-scope-iterator.cc b/deps/v8/src/debug/debug-scope-iterator.cc index 8e2e30d745cc..204d8d4d0be8 100644 --- a/deps/v8/src/debug/debug-scope-iterator.cc +++ b/deps/v8/src/debug/debug-scope-iterator.cc @@ -105,9 +105,17 @@ debug::Location DebugScopeIterator::GetEndLocation() { ->GetSourceLocation(iterator_.end_position()); } -bool DebugScopeIterator::DeclaresLocals() { +v8::debug::ScopeIterator::VariableInfo DebugScopeIterator::GetVariableInfo() { DCHECK(!Done()); - return iterator_.DeclaresLocals(i::ScopeIterator::Mode::ALL); + switch (iterator_.GetVariableInfo(i::ScopeIterator::Mode::ALL)) { + case i::ScopeIterator::VariableInfo::kEmpty: + return VariableInfo::kEmpty; + case i::ScopeIterator::VariableInfo::kAllUnavailable: + return VariableInfo::kAllUnavailable; + case i::ScopeIterator::VariableInfo::kAvailable: + return VariableInfo::kAvailable; + } + UNREACHABLE(); } bool DebugScopeIterator::SetVariableValue(v8::Local<v8::String> name, diff --git a/deps/v8/src/debug/debug-scope-iterator.h b/deps/v8/src/debug/debug-scope-iterator.h index 8a3d0d1c7c04..e78fccc556e8 100644 --- a/deps/v8/src/debug/debug-scope-iterator.h +++ b/deps/v8/src/debug/debug-scope-iterator.h @@ -27,7 +27,7 @@ class DebugScopeIterator final : public debug::ScopeIterator { bool HasLocationInfo() override; debug::Location GetStartLocation() override; debug::Location GetEndLocation() override; - bool DeclaresLocals() override; + VariableInfo GetVariableInfo() override; bool SetVariableValue(v8::Local<v8::String> name, v8::Local<v8::Value> value) override; diff --git a/deps/v8/src/debug/debug-scopes.cc b/deps/v8/src/debug/debug-scopes.cc index efb792200478..2523dca7f4f9 100644 --- a/deps/v8/src/debug/debug-scopes.cc +++ b/deps/v8/src/debug/debug-scopes.cc @@ -45,6 +45,18 @@ DirectHandle<Object> ScopeIterator::GetFunctionDebugName() const { return JSFunction::GetDebugName(isolate_, function_); } + if (HasScope()) { + // If the enclosing function has no context, `context_->closure_context()` + // belongs to some further outer function and can't be used for the name. + std::optional<DebugScriptScope> scope = current_scope(); + while (scope.has_value() && !scope->is_function_scope()) { + scope = scope->parent(); + } + if (!scope.has_value() || !scope->needs_context()) { + return isolate_->factory()->undefined_value(); + } + } + if (!IsNativeContext(*context_)) { DisallowGarbageCollection no_gc; Tagged<ScopeInfo> closure_info = context_->closure_context()->scope_info(); @@ -81,8 +93,12 @@ void ScopeIterator::Restart() { DCHECK_NOT_NULL(frame_inspector_); function_ = frame_inspector_->GetFunction(); context_ = Cast<Context>(frame_inspector_->GetContext()); + // Iteration may have moved on to the caller's script of a direct eval. + script_ = frame_inspector_->GetScript(); + debug_scope_info_ = EnsureDebugScriptScopeInfo(isolate_, script_); current_scope_index_ = start_scope_index_; DCHECK_NE(current_scope_index_, -1); + if (ignore_nested_scopes_) UnwindToClosureContext(); UnwrapEvaluationContext(); seen_script_scope_ = false; } @@ -90,7 +106,6 @@ void ScopeIterator::Restart() { void ScopeIterator::TryParseAndRetrieveScopes() { // Catch the case when the debugger stops in an internal function. DirectHandle<SharedFunctionInfo> shared_info(function_->shared(), isolate_); - DirectHandle<ScopeInfo> scope_info(shared_info->scope_info(), isolate_); if (IsUndefined(shared_info->script())) { current_scope_index_ = closure_scope_index_ = start_scope_index_ = -1; context_ = handle(function_->context(), isolate_); @@ -125,15 +140,8 @@ void ScopeIterator::TryParseAndRetrieveScopes() { return; } - // For a FUNCTION_SCOPE we locate the paused function's scope in the - // serialized tree. For top-level scopes (EVAL_SCOPE, SCRIPT_SCOPE, - // MODULE_SCOPE) the closure scope is the root scope (index 0). std::optional<DebugScriptScope> debug_closure_scope = - scope_info->scope_type() == FUNCTION_SCOPE - ? FindClosureScope(debug_scope_info_, shared_info->StartPosition(), - shared_info->EndPosition(), - scope_info->scope_type()) - : DebugScriptScope::FromIndex(debug_scope_info_, 0); + FindClosureScope(debug_scope_info_, *shared_info); if (!debug_closure_scope.has_value()) { context_ = Handle<Context>(); return; @@ -145,19 +153,31 @@ void ScopeIterator::TryParseAndRetrieveScopes() { current_scope_index_ = start_scope_index_; if (ignore_nested_scopes) { + ignore_nested_scopes_ = true; current_scope_index_ = closure_scope_index_; start_scope_index_ = current_scope_index_; - // ignore_nested_scopes is only used for the return-position breakpoint, - // so we can safely assume that the closure context for the current - // function exists if it needs one. - if (closure_scope().needs_context()) { - context_ = handle(context_->closure_context(), isolate_); - } + UnwindToClosureContext(); } UnwrapEvaluationContext(); } +void ScopeIterator::UnwindToClosureContext() { + DCHECK(ignore_nested_scopes_); + DCHECK_EQ(current_scope_index_, closure_scope_index_); + // ignore_nested_scopes_ is only used for the return-position breakpoint, + // so we can safely assume that the closure context for the current + // function exists if it needs one. The `Return` bytecode does not pop + // block, catch or with contexts, so the frame's context may still be one + // of those. If the closure scope doesn't need a context, the scopes outside + // of it start with the function's context. + if (closure_scope().needs_context()) { + context_ = handle(context_->closure_context(), isolate_); + } else { + context_ = handle(function_->context(), isolate_); + } +} + void ScopeIterator::UnwrapEvaluationContext() { if (!context_->IsDebugEvaluateContext()) return; Tagged<Context> current = *context_; @@ -228,12 +248,38 @@ bool ScopeIterator::DeclaresLocals(Mode mode) const { return declares_local; } -bool ScopeIterator::ShouldIgnore() const { - if (Type() == ScopeTypeLocal || - (Type() == ScopeTypeModule && InInnerScope())) { - return false; +ScopeIterator::VariableInfo ScopeIterator::GetVariableInfo(Mode mode) const { + ScopeType type = Type(); + + // `with` and global scopes are backed by arbitrary objects. Consistent with + // DeclaresLocals(), we treat them as having available variables. + if (type == ScopeTypeWith || type == ScopeTypeGlobal) { + return mode == Mode::ALL ? VariableInfo::kAvailable : VariableInfo::kEmpty; } - return !DeclaresLocals(Mode::ALL); + + VariableInfo result = VariableInfo::kEmpty; + auto visitor = [&](DirectHandle<String> name, DirectHandle<Object> value, + ScopeType scope_type) { + // Keep in sync with ScopeObject(), which installs the "value unavailable" + // accessor for these values. + if (IsOptimizedOut(*value) || IsTdzHole(*value)) { + result = VariableInfo::kAllUnavailable; + return false; + } + result = VariableInfo::kAvailable; + return true; + }; + VisitScope(visitor, mode); + return result; +} + +bool ScopeIterator::ShouldIgnore() const { + // Empty scopes are reported (e.g. so that they can be matched against + // source maps), except for an empty script scope or eval scope. The latter + // is also the root scope of wrapped functions and Function() functions. + return (Type() == ScopeTypeScript || + (HasScope() && current_scope().scope_type() == EVAL_SCOPE)) && + !DeclaresLocals(Mode::ALL); } bool ScopeIterator::AdvanceToScopeNumber(int scope_number) { @@ -246,16 +292,45 @@ bool ScopeIterator::AdvanceToScopeNumber(int scope_number) { return scope_number == 0 && !Done(); } +bool ScopeIterator::InPausedFunctionScopes() const { + if (function_.is_null() || !HasScope()) return false; + // `function_` is only reset after Next() has moved past the closure scope, + // so explicitly check that the closure scope is (an ancestor of) the current + // scope. + for (std::optional<DebugScriptScope> scope = current_scope(); + scope.has_value(); scope = scope->parent()) { + if (scope->scope_index() == closure_scope_index_) return true; + } + return false; +} + bool ScopeIterator::HasContext() const { - // In rare cases we pause in a scope that doesn't have its context pushed yet. - // E.g. when pausing in for-of loop headers (see https://crbug.com/399002824). - // - // We can detect this by comparing the scope ID of the parsed scope and the - // runtime scope. - if (HasScope() && NeedsContext() && - current_scope().unique_id_in_script() != - context_->scope_info()->UniqueIdInScript()) { - return false; + if (HasScope() && NeedsContext()) { + // In rare cases we pause in a scope that doesn't have its context pushed + // yet. E.g. when pausing in for-of loop headers (see + // https://crbug.com/399002824). + // + // While we are still in the scopes of the paused function, the function's + // creation context means that none of the function's own contexts have + // been pushed. Check this first: the creation context can belong to a + // different script (the caller of a direct eval), so comparing scope IDs, + // which are only unique within a script, would be meaningless. + // Top-level script and module functions are the exception: they are + // created with the script/module context as their context. + const bool closure_created_in_own_context = + current_scope().is_script_scope() || current_scope().is_module_scope(); + if (!closure_created_in_own_context && InPausedFunctionScopes() && + *context_ == function_->context()) { + return false; + } + + // Otherwise, context_ belongs to the same script as current_scope() and + // we can detect a not-yet-pushed context by comparing the scope ID of the + // parsed scope and the runtime scope. + if (current_scope().unique_id_in_script() != + context_->scope_info()->UniqueIdInScript()) { + return false; + } } return !HasScope() || NeedsContext(); @@ -282,14 +357,6 @@ bool ScopeIterator::NeedsContext() const { return needs_context; } -bool ScopeIterator::AdvanceOneScope() { - if (!HasScope()) return false; - std::optional<DebugScriptScope> parent = current_scope().parent(); - if (!parent.has_value()) return false; - current_scope_index_ = parent->scope_index(); - return true; -} - void ScopeIterator::AdvanceOneContext() { DCHECK(!IsNativeContext(*context_)); DCHECK(!context_->previous().is_null()); @@ -306,7 +373,36 @@ void ScopeIterator::AdvanceScope() { AdvanceOneContext(); } - CHECK(AdvanceOneScope()); + if (std::optional<DebugScriptScope> parent = current_scope().parent()) { + current_scope_index_ = parent->scope_index(); + continue; + } + + if (std::optional<DebugScriptScope> outer = + FindEvalOuterScope(isolate_, script_)) { + // The root scope of the paused script is either the closure scope itself + // or one of its ancestors, so we have left the paused function by now. + // Reset `function_` right away: `closure_scope_index_` indexes into the + // paused script's scope tree, so comparing it with `current_scope_index_` + // in the caller's script tree is meaningless (e.g. both are 0 when + // pausing in the top-level code of a direct eval called from another + // eval's top-level code). + // Do not skip `outer` if `outer->is_hidden()` is true: like + // `TryParseAndRetrieveScopes()`, `FindEvalOuterScope()` lands on the + // innermost scope at the eval call site (such as the outer block scope + // of a `for (let ...)` loop when eval is called in the initializer). + function_ = Handle<JSFunction>(); + script_ = + handle(Cast<Script>(script_->eval_from_shared()->script()), isolate_); + debug_scope_info_ = handle(*outer->info(), isolate_); + current_scope_index_ = outer->scope_index(); + } else { + // We left the root of the outermost scope tree we can reach (e.g. the + // root of an indirect eval, a `new Function` or a wrapped function). + // Continue with the runtime context chain. + current_scope_index_ = -1; + } + break; } while (current_scope().is_hidden()); } @@ -328,32 +424,16 @@ void ScopeIterator::Next() { bool leaving_closure = current_scope_index_ == closure_scope_index_; if (scope_type == ScopeTypeScript) { - DCHECK_IMPLIES(InInnerScope() && !leaving_closure, - current_scope().is_script_scope()); + DCHECK_IMPLIES(HasScope(), current_scope().is_script_scope()); seen_script_scope_ = true; if (context_->IsScriptContext()) { context_ = handle(context_->previous(), isolate_); } - if (leaving_closure) { - current_scope_index_ = -1; - } - } else if (!InInnerScope()) { - AdvanceContext(); + current_scope_index_ = -1; + } else if (HasScope()) { + AdvanceScope(); } else { - DCHECK_NE(current_scope_index_, -1); - if (leaving_closure) { - // DebugScriptScope represents the entire script's scope tree, so calling - // AdvanceScope() here would step into the enclosing outer scope. Outside - // the paused closure, ScopeIterator iterates purely via runtime context_ - // (!InInnerScope()). Consume the closure's context if it had one and - // reset the scope cursor. - if (NeedsAndHasContext()) { - AdvanceOneContext(); - } - current_scope_index_ = -1; - } else { - AdvanceScope(); - } + AdvanceContext(); } UnwrapEvaluationContext(); @@ -439,6 +519,7 @@ Handle<JSObject> ScopeIterator::ScopeObject(Mode mode) { } if (type == ScopeTypeWith) { DCHECK_EQ(Mode::ALL, mode); + DCHECK(HasContext()); return WithContextExtension(); } @@ -518,11 +599,21 @@ bool ScopeIterator::SetVariableValue(Handle<String> name, case ScopeTypeBlock: case ScopeTypeCatch: case ScopeTypeModule: - if (HasScope()) return SetLocalVariableValue(name, value); - if (Type() == ScopeTypeModule && SetModuleVariableValue(name, value)) { - return true; + if (HasScope()) { + if (SetLocalVariableValue(name, value)) return true; + } else { + if (Type() == ScopeTypeModule && SetModuleVariableValue(name, value)) { + return true; + } + if (SetContextVariableValue(name, value)) return true; + } + // The varblock scope of a sloppy function with non-simple parameters + // can hold eval-introduced variables on its context extension object. + // Mirror VisitLocalScope, which lists them. + if (HasContext() && context_->scope_info()->SloppyEvalCanExtendVars()) { + return SetContextExtensionValue(name, value); } - return SetContextVariableValue(name, value); + return false; case ScopeTypeLocal: case ScopeTypeClosure: @@ -711,10 +802,12 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, } else { auto [fn_alloc, fn_index] = current_scope().function_variable_info(); if (fn_alloc == VariableAllocationInfo::CONTEXT && HasContext()) { + CHECK_LT(static_cast<unsigned>(fn_index), + static_cast<unsigned>(context_->length())); function_value = indirect_handle( Context::Get(context_, fn_index, isolate_), isolate_); } else { - function_value = isolate_->factory()->the_hole_value(); + function_value = isolate_->factory()->optimized_out(); } } if (visitor(name, function_value, scope_type)) return true; @@ -724,10 +817,14 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, auto [args_alloc, args_index] = scope.arguments_info(); for (int i = 0; i < scope.variable_count(); ++i) { DebugVariableInfo var = scope.variable(i); + // Create a handle for the name right away: computing the value below can + // allocate (e.g. Context::Get boxing a double ContextCell), and the GC may + // move the string. + DirectHandle<InternalizedString> name(var.name, isolate_); if (var.is_synthetic) { // We want to materialize "new.target" for debug-evaluate. if (mode != Mode::STACK || - !var.name->Equals(*isolate_->factory()->dot_new_target_string())) { + !name->Equals(*isolate_->factory()->dot_new_target_string())) { continue; } } @@ -745,7 +842,7 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, case VariableLocation::PARAMETER: { if (!InInnerScope()) { - value = isolate_->factory()->the_hole_value(); + value = isolate_->factory()->optimized_out(); } else if (frame_inspector_ == nullptr) { // Get the variable from the suspended generator. DCHECK(!generator_.is_null()); @@ -772,7 +869,7 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, case VariableLocation::LOCAL: if (!InInnerScope()) { - value = isolate_->factory()->the_hole_value(); + value = isolate_->factory()->optimized_out(); } else if (frame_inspector_ == nullptr) { // Get the variable from the suspended generator. DCHECK(!generator_.is_null()); @@ -818,7 +915,11 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, value = isolate_->factory()->tdz_hole_value(); break; } - DCHECK_EQ(context_->scope_info()->ContextSlotIndex(var.name), index); + DCHECK_EQ(context_->scope_info()->ContextSlotIndex(*name), index); + // Context::get() only DCHECKs the index. Make sure a context that is + // out of sync with the parsed scope can't cause an out-of-bounds read. + CHECK_LT(static_cast<unsigned>(index), + static_cast<unsigned>(context_->length())); value = indirect_handle(Context::Get(context_, index, isolate_), isolate_); break; @@ -832,7 +933,7 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, } } - if (visitor(direct_handle(var.name, isolate_), value, scope_type)) { + if (visitor(name, value, scope_type)) { return true; } } @@ -842,7 +943,7 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode, // Retrieve the with-context extension object. If the extension object is // a proxy, return an empty object. Handle<JSObject> ScopeIterator::WithContextExtension() { - DCHECK(context_->IsWithContext()); + CHECK(context_->IsWithContext()); if (!IsJSObject(context_->extension_receiver())) { DCHECK(IsJSProxy(context_->extension_receiver()) || IsWasmObject(context_->extension_receiver())); @@ -943,8 +1044,6 @@ bool ScopeIterator::SetLocalVariableValue(DirectHandle<String> variable_name, case VariableLocation::LOOKUP: case VariableLocation::UNALLOCATED: // Drop assignments to unallocated locals. - DCHECK(*variable_name == ReadOnlyRoots(isolate_).this_string() || - *variable_name == ReadOnlyRoots(isolate_).arguments_string()); return false; case VariableLocation::REPL_GLOBAL: diff --git a/deps/v8/src/debug/debug-scopes.h b/deps/v8/src/debug/debug-scopes.h index a03b3ae42359..cff3db4150e6 100644 --- a/deps/v8/src/debug/debug-scopes.h +++ b/deps/v8/src/debug/debug-scopes.h @@ -69,6 +69,19 @@ class V8_EXPORT_PRIVATE ScopeIterator { // Returns whether the current scope declares any variables. bool DeclaresLocals(Mode mode) const; + enum class VariableInfo { + // The scope does not declare any variables. + kEmpty, + // The scope declares variables, but none of their values are available + // (i.e. all of them are optimized out or in their TDZ). + kAllUnavailable, + // The scope declares at least one variable with an available value. + kAvailable, + }; + + // Classifies the variables declared by the current scope. + VariableInfo GetVariableInfo(Mode mode) const; + // Returns whether the current scope should be ignored by debugger scope // numbers. bool ShouldIgnore() const; @@ -106,6 +119,7 @@ class V8_EXPORT_PRIVATE ScopeIterator { return !function_.is_null() && HasScope(); } bool HasContext() const; + bool InPausedFunctionScopes() const; bool NeedsContext() const; bool NeedsAndHasContext() const { return NeedsContext() && HasContext(); } Handle<Context> CurrentContext() const { @@ -116,6 +130,9 @@ class V8_EXPORT_PRIVATE ScopeIterator { if (current_scope_index_ == -1) return std::nullopt; return current_scope(); } + // Returns the innermost runtime context at the current position. Unlike + // CurrentContext(), this is also valid for scopes without their own context. + Handle<Context> EvaluationContext() const { return context_; } private: Isolate* isolate_; @@ -127,15 +144,22 @@ class V8_EXPORT_PRIVATE ScopeIterator { Handle<JSFunction> function_; Handle<Context> context_; + // The script and serialized scope tree containing the current scope. These + // start out as the paused script and move on to the caller's script when + // iteration leaves the root scope of a direct eval script. + // `current_scope_index_` indexes into `debug_scope_info_` and is set to -1 + // once iteration leaves the outermost scope tree. + // `start_scope_index_` and `closure_scope_index_` always index into the + // paused script's scope tree. Handle<Script> script_; - // Serialized scope tree of the paused script and indices into it. - // `current_scope_index_` is set to -1 once iteration leaves - // `closure_scope_index_` (matching `function_` becoming null). Handle<DebugScriptScopeInfo> debug_scope_info_; int start_scope_index_ = -1; int closure_scope_index_ = -1; int current_scope_index_ = -1; bool seen_script_scope_ = false; + // Set when paused at a return position. Iteration then starts at the + // closure scope and nested block, catch and with scopes are skipped. + bool ignore_nested_scopes_ = false; DebugScriptScope current_scope() const { return DebugScriptScope::FromIndex(debug_scope_info_, current_scope_index_); @@ -148,7 +172,6 @@ class V8_EXPORT_PRIVATE ScopeIterator { return frame_inspector_->javascript_frame(); } - bool AdvanceOneScope(); void AdvanceOneContext(); void AdvanceScope(); void AdvanceContext(); @@ -156,6 +179,7 @@ class V8_EXPORT_PRIVATE ScopeIterator { int GetSourcePosition() const; void TryParseAndRetrieveScopes(); + void UnwindToClosureContext(); void UnwrapEvaluationContext(); diff --git a/deps/v8/src/debug/debug-wasm-objects.cc b/deps/v8/src/debug/debug-wasm-objects.cc index 0cf893b6c415..4fd47b699fa3 100644 --- a/deps/v8/src/debug/debug-wasm-objects.cc +++ b/deps/v8/src/debug/debug-wasm-objects.cc @@ -4,6 +4,7 @@ #include "src/debug/debug-wasm-objects.h" +#include <array> #include <optional> #include "src/api/api-inl.h" @@ -31,8 +32,8 @@ namespace { using StringBuilder = wasm::StringBuilder; DirectHandle<String> ToInternalString(StringBuilder& sb, Isolate* isolate) { - return isolate->factory()->InternalizeString( - base::VectorOf(sb.start(), sb.length())); + return isolate->factory()->InternalizeUtf8String( + {sb.start(), static_cast<size_t>(sb.length())}); } Address GetDebugBreakFp(WasmFrame* frame) { @@ -57,6 +58,7 @@ enum DebugProxyId { kLocalsProxy, kStackProxy, kStructProxy, + kCustomMapProxy, kArrayProxy, kLastProxyId = kArrayProxy, @@ -697,7 +699,7 @@ class DebugWasmScopeIterator final : public debug::ScopeIterator { ScopeType GetType() override { return type_; } - bool DeclaresLocals() override { return true; } + VariableInfo GetVariableInfo() override { return VariableInfo::kAvailable; } v8::Local<v8::Object> GetObject() override { Isolate* isolate = frame_->isolate(); @@ -798,6 +800,8 @@ class DebugWasmInterpreterScopeIterator final : public debug::ScopeIterator { ScopeType GetType() override { return type_; } + VariableInfo GetVariableInfo() override { return VariableInfo::kAvailable; } + v8::Local<v8::Object> GetObject() override { Isolate* isolate = frame_->isolate(); switch (type_) { @@ -867,10 +871,10 @@ class DebugWasmInterpreterScopeIterator final : public debug::ScopeIterator { DirectHandle<String> WasmSimd128ToString(Isolate* isolate, Simd128 s128) { // We use the canonical format as described in: // https://github.com/WebAssembly/simd/blob/master/proposals/simd/TextSIMD.md - base::EmbeddedVector<char, 50> buffer; + std::array<char, 50> buffer; auto i32x4 = s128.to_i32x4(); - SNPrintF(buffer, "i32x4 0x%08X 0x%08X 0x%08X 0x%08X", i32x4[0], i32x4[1], - i32x4[2], i32x4[3]); + base::SNPrintF(buffer, "i32x4 0x%08X 0x%08X 0x%08X 0x%08X", i32x4[0], + i32x4[1], i32x4[2], i32x4[3]); return isolate->factory()->NewStringFromAsciiChecked(buffer.data()); } @@ -897,18 +901,15 @@ DirectHandle<WasmValueObject> WasmValueObject::New(Isolate* isolate, map->SetConstructor(*isolate->object_function()); { // type Descriptor d = Descriptor::DataField( - isolate, - isolate->factory()->InternalizeString(base::StaticCharVector("type")), + isolate, isolate->factory()->InternalizeString("type"), WasmValueObject::kTypeOffset, FROZEN, Representation::Tagged(), true); map->AppendDescriptor(isolate, &d); } { // value - Descriptor d = - Descriptor::DataField(isolate, - isolate->factory()->InternalizeString( - base::StaticCharVector("value")), - WasmValueObject::kValueOffset, FROZEN, - Representation::Tagged(), true); + Descriptor d = Descriptor::DataField( + isolate, isolate->factory()->InternalizeString("value"), + WasmValueObject::kValueOffset, FROZEN, Representation::Tagged(), + true); map->AppendDescriptor(isolate, &d); } map->set_is_extensible(false); @@ -924,15 +925,16 @@ DirectHandle<WasmValueObject> WasmValueObject::New(Isolate* isolate, } // This class implements a proxy for a single inspectable Wasm struct. -struct StructProxy : NamedDebugProxy<StructProxy, kStructProxy, WasmStruct> { +template <typename Subclass, DebugProxyId id, typename Struct> +struct StructProxyImpl : NamedDebugProxy<Subclass, id, Struct> { static constexpr char const* kClassName = "Struct"; static DirectHandle<JSObject> Create(Isolate* isolate, - DirectHandle<WasmStruct> value) { - return NamedDebugProxy::Create(isolate, value); + DirectHandle<Struct> value) { + return NamedDebugProxy<Subclass, id, Struct>::Create(isolate, value); } - static uint32_t Count(Isolate* isolate, DirectHandle<WasmStruct> obj) { + static uint32_t Count(Isolate* isolate, DirectHandle<Struct> obj) { wasm::CanonicalTypeIndex type_index = obj->map()->wasm_type_info()->type().ref_index(); return wasm::GetTypeCanonicalizer() @@ -940,14 +942,13 @@ struct StructProxy : NamedDebugProxy<StructProxy, kStructProxy, WasmStruct> { ->field_count(); } - static DirectHandle<Object> Get(Isolate* isolate, - DirectHandle<WasmStruct> obj, + static DirectHandle<Object> Get(Isolate* isolate, DirectHandle<Struct> obj, uint32_t index) { return WasmValueObject::New(isolate, obj->GetFieldValue(index)); } static DirectHandle<String> GetName(Isolate* isolate, - DirectHandle<WasmStruct> obj, + DirectHandle<Struct> obj, uint32_t index) { wasm::CanonicalTypeIndex struct_index = obj->map()->wasm_type_info()->type().ref_index(); @@ -957,6 +958,9 @@ struct StructProxy : NamedDebugProxy<StructProxy, kStructProxy, WasmStruct> { return ToInternalString(sb, isolate); } }; +struct StructProxy : StructProxyImpl<StructProxy, kStructProxy, WasmStruct> {}; +struct CustomMapProxy + : StructProxyImpl<CustomMapProxy, kCustomMapProxy, WasmCustomMap> {}; // This class implements a proxy for a single inspectable Wasm array. struct ArrayProxy : IndexedDebugProxy<ArrayProxy, kArrayProxy, WasmArray> { @@ -1004,55 +1008,60 @@ DirectHandle<WasmValueObject> WasmValueObject::New( case wasm::kI8: { // This can't be reached for most "top-level" things, only via nested // calls for struct/array fields. - t = isolate->factory()->InternalizeString(base::StaticCharVector("i8")); + t = isolate->factory()->InternalizeString("i8"); v = isolate->factory()->NewNumber(value.to_i8_unchecked()); break; } case wasm::kI16: { // This can't be reached for most "top-level" things, only via nested // calls for struct/array fields. - t = isolate->factory()->InternalizeString(base::StaticCharVector("i16")); + t = isolate->factory()->InternalizeString("i16"); v = isolate->factory()->NewNumber(value.to_i16_unchecked()); break; } case wasm::kI32: { - t = isolate->factory()->InternalizeString(base::StaticCharVector("i32")); + t = isolate->factory()->InternalizeString("i32"); v = isolate->factory()->NewNumberFromInt(value.to_i32_unchecked()); break; } case wasm::kI64: { - t = isolate->factory()->InternalizeString(base::StaticCharVector("i64")); + t = isolate->factory()->InternalizeString("i64"); v = BigInt::FromInt64(isolate, value.to_i64_unchecked()); break; } case wasm::kF16: { // This can't be reached for most "top-level" things, only via nested // calls for struct/array fields. - t = isolate->factory()->InternalizeString(base::StaticCharVector("f16")); + t = isolate->factory()->InternalizeString("f16"); v = isolate->factory()->NewNumber(value.to_f16_unchecked()); break; } case wasm::kF32: { - t = isolate->factory()->InternalizeString(base::StaticCharVector("f32")); + t = isolate->factory()->InternalizeString("f32"); v = isolate->factory()->NewNumber(value.to_f32_unchecked()); break; } case wasm::kF64: { - t = isolate->factory()->InternalizeString(base::StaticCharVector("f64")); + t = isolate->factory()->InternalizeString("f64"); v = isolate->factory()->NewNumber(value.to_f64_unchecked()); break; } case wasm::kS128: { - t = isolate->factory()->InternalizeString(base::StaticCharVector("v128")); + t = isolate->factory()->InternalizeString("v128"); v = WasmSimd128ToString(isolate, value.to_s128_unchecked()); break; } case wasm::kRefNull: case wasm::kRef: { DirectHandle<Object> ref = value.to_ref(); +#ifdef V8_IS_TSAN + if (IsHeapObject(*ref) && + HeapLayout::InWritableSharedSpace(Cast<HeapObject>(*ref))) { + TSAN_ACQUIRE(Cast<HeapObject>(*ref).address()); + } +#endif if (value.type().is_reference_to(wasm::GenericKind::kExn)) { - t = isolate->factory()->InternalizeString( - base::StaticCharVector("exnref")); + t = isolate->factory()->InternalizeString("exnref"); v = ref; } else if (IsWasmNull(*ref)) { v = isolate->factory()->null_value(); @@ -1062,6 +1071,11 @@ DirectHandle<WasmValueObject> WasmValueObject::New( Cast<HeapObject>(*ref)->map()->wasm_type_info(); t = GetRefTypeName(isolate, type_info->type()); v = StructProxy::Create(isolate, Cast<WasmStruct>(ref)); + } else if (IsWasmCustomMap(*ref)) { + Tagged<WasmTypeInfo> type_info = + Cast<HeapObject>(*ref)->map()->wasm_type_info(); + t = GetRefTypeName(isolate, type_info->type()); + v = CustomMapProxy::Create(isolate, Cast<WasmCustomMap>(ref)); } else if (IsWasmArray(*ref)) { Tagged<WasmTypeInfo> type_info = Cast<HeapObject>(*ref)->map()->wasm_type_info(); @@ -1080,11 +1094,13 @@ DirectHandle<WasmValueObject> WasmValueObject::New( v = ref; } else { // Fail gracefully. - base::EmbeddedVector<char, 64> error; - int len = SNPrintF(error, "unimplemented object type: %d", + std::array<char, 64> error; + int len = + base::SNPrintF(error, "unimplemented object type: %d", Cast<HeapObject>(*ref)->map()->instance_type()); t = GetRefTypeName(isolate, value.type()); - v = isolate->factory()->InternalizeString(error.SubVector(0, len)); + v = isolate->factory()->InternalizeString( + {error.data(), static_cast<size_t>(len)}); } break; } diff --git a/deps/v8/src/debug/debug.cc b/deps/v8/src/debug/debug.cc index def10a51cd7f..328b7fe7a524 100644 --- a/deps/v8/src/debug/debug.cc +++ b/deps/v8/src/debug/debug.cc @@ -37,6 +37,7 @@ #include "src/objects/js-generator-inl.h" #include "src/objects/js-promise-inl.h" #include "src/objects/slots.h" +#include "src/sandbox/check.h" #include "src/snapshot/embedded/embedded-data.h" #if V8_ENABLE_WEBASSEMBLY @@ -233,6 +234,7 @@ BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, DirectHandle<AbstractCode> abstract_code = summary.abstract_code(); BreakIterator it(debug_info); it.SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); + if (it.Done()) return BreakLocation::Invalid(); return it.GetBreakLocation(); } @@ -341,6 +343,7 @@ bool BreakLocation::HasBreakPoint(Isolate* isolate, DCHECK(IsBytecodeArray(*abstract_code_)); BreakIterator it(debug_info); it.SkipToPosition(position_); + if (it.Done()) return false; return it.code_offset() == code_offset_; } } @@ -369,9 +372,7 @@ BreakIterator::BreakIterator(Handle<DebugInfo> debug_info) ->SourcePositionTable()) { position_ = debug_info->shared()->StartPosition(); statement_position_ = position_; - // There is at least one break location. - DCHECK(!Done()); - Next(); + if (!Done()) Next(); } int BreakIterator::BreakIndexFromPosition(int source_position) { @@ -467,6 +468,7 @@ void BreakIterator::ClearDebugBreak() { } BreakLocation BreakIterator::GetBreakLocation() { + DCHECK(!Done()); Isolate* isolate = Isolate::Current(); Handle<AbstractCode> code( Cast<AbstractCode>(debug_info_->DebugBytecodeArray(isolate)), isolate); @@ -505,6 +507,7 @@ void Debug::ThreadInit() { thread_local_.last_bytecode_offset_ = kFunctionEntryBytecodeOffset; thread_local_.last_frame_count_ = -1; thread_local_.fast_forward_to_return_ = false; + thread_local_.step_over_enters_functions_ = false; thread_local_.ignore_step_into_function_ = Smi::zero(); thread_local_.target_frame_count_ = -1; thread_local_.return_value_ = Smi::zero(); @@ -592,7 +595,8 @@ void DebugInfoCollection::Insert(Tagged<SharedFunctionInfo> sfi, HandleLocation location = isolate_->global_handles()->Create(debug_info).location(); list_.push_back(location); - map_.emplace(sfi->unique_id(), location); + auto [it, inserted] = map_.emplace(sfi->unique_id(), location); + SBXCHECK(inserted); DCHECK(Contains(sfi)); DCHECK_EQ(list_.size(), map_.size()); } @@ -600,7 +604,8 @@ void DebugInfoCollection::Insert(Tagged<SharedFunctionInfo> sfi, bool DebugInfoCollection::Contains(Tagged<SharedFunctionInfo> sfi) const { auto it = map_.find(sfi->unique_id()); if (it == map_.end()) return false; - DCHECK_EQ(TrustedCast<DebugInfo>(Tagged<Object>(*it->second))->shared(), sfi); + SBXCHECK_EQ(TrustedCast<DebugInfo>(Tagged<Object>(*it->second))->shared(), + sfi); return true; } @@ -609,7 +614,7 @@ std::optional<Tagged<DebugInfo>> DebugInfoCollection::Find( auto it = map_.find(sfi->unique_id()); if (it == map_.end()) return {}; Tagged<DebugInfo> di = TrustedCast<DebugInfo>(Tagged<Object>(*it->second)); - DCHECK_EQ(di->shared(), sfi); + SBXCHECK_EQ(di->shared(), sfi); return di; } @@ -637,8 +642,9 @@ void DebugInfoCollection::DeleteIndex(size_t index) { DCHECK(Contains(sfi)); auto it = map_.find(sfi->unique_id()); + SBXCHECK(it != map_.end()); HandleLocation location = it->second; - DCHECK_EQ(location, list_[index]); + SBXCHECK_EQ(location, list_[index]); map_.erase(it); list_[index] = list_.back(); @@ -678,7 +684,7 @@ void Debug::Break(JavaScriptFrame* frame, DirectHandle<JSFunction> break_target) { RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); // Just continue if breaks are disabled or debugger cannot be loaded. - if (break_disabled()) return; + if (break_disabled() || IsRestartFrameScheduled()) return; // Enter the debugger. DebugScope debug_scope(this); @@ -699,6 +705,7 @@ void Debug::Break(JavaScriptFrame* frame, if (hitInstrumentationBreak) { debug::DebugDelegate::ActionAfterInstrumentation action = OnInstrumentationBreak(); + if (IsRestartFrameScheduled()) return; switch (action) { case debug::DebugDelegate::ActionAfterInstrumentation::kPause: shouldPauseAfterInstrumentation = true; @@ -789,8 +796,12 @@ void Debug::Break(JavaScriptFrame* frame, step_break = true; break; case StepOver: - // StepOver should not break in a deeper frame than target frame. - if (current_frame_count > target_frame_count) return; + // StepOver should not break in a deeper frame than target frame, unless + // the function was entered (see PrepareStepIn). + if (current_frame_count > target_frame_count && + !(step_over_enters_functions() && ShouldEnterFunction(shared))) { + return; + } [[fallthrough]]; case StepInto: { // StepInto and StepOver should enter "generator stepping" mode, except @@ -837,6 +848,8 @@ void Debug::Break(JavaScriptFrame* frame, bool is_debugger_statement = IsBreakOnDebuggerStatement(shared, location); if (is_debugger_statement) { break_reasons.Add(debug::BreakReason::kDebuggerStatement); + } else if (ContinueSteppingIfSkipped(lastStepAction)) { + return; } // Notify the debug event listeners. OnDebugBreak(isolate_->factory()->empty_fixed_array(), lastStepAction, @@ -971,6 +984,11 @@ bool Debug::CheckBreakPoint(DirectHandle<BreakPoint> break_point, return false; } + // The condition of another break point at the same location might have + // disabled the debugger (see below). Don't evaluate any further conditions + // in that case, debug-evaluate requires an active debugger. + if (!debug_delegate_) return false; + if (!break_point->condition()->length()) return true; DirectHandle<String> condition(break_point->condition(), isolate_); MaybeDirectHandle<Object> maybe_result; @@ -998,6 +1016,13 @@ bool Debug::CheckBreakPoint(DirectHandle<BreakPoint> break_point, } CHECK(in_debug_scope()); + + // Evaluating the condition might have disabled the debugger (e.g. an + // embedder that dispatches `Debugger.disable` synchronously from within the + // condition), in which case there is no delegate anymore and the break point + // has been cleared. + if (!debug_delegate_) return false; + DisableBreak no_recursive_break(this); { @@ -1044,7 +1069,6 @@ bool Debug::SetBreakPointForScript(Handle<Script> script, isolate_->factory()->NewBreakPoint(*id, condition); #if V8_ENABLE_WEBASSEMBLY if (script->type() == Script::Type::kWasm) { - RecordWasmScriptWithBreakpoints(script); return WasmScript::SetBreakPoint(script, source_position, break_point); } #endif // V8_ENABLE_WEBASSEMBLY @@ -1099,6 +1123,7 @@ void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { DCHECK(debug_info->HasInstrumentedBytecodeArray()); BreakIterator it(debug_info); it.SkipToPosition(info->source_position()); + if (it.Done()) continue; it.SetDebugBreak(); } } @@ -1207,7 +1232,6 @@ void Debug::SetInstrumentationBreakpointForWasmScript( DirectHandle<BreakPoint> break_point = isolate_->factory()->NewBreakPoint( *id, isolate_->factory()->empty_string()); - RecordWasmScriptWithBreakpoints(script); WasmScript::SetInstrumentationBreakpoint(script, break_point); } @@ -1285,6 +1309,12 @@ void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared, bool returns_only) { RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); if (IsBlackboxed(shared)) return; + FloodWithOneShotIncludingBlackboxed(shared, returns_only); +} + +void Debug::FloodWithOneShotIncludingBlackboxed( + Handle<SharedFunctionInfo> shared, bool returns_only) { + RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); // Make sure the function is compiled and has set up the debug info. if (!EnsureBreakInfo(shared)) return; PrepareFunctionForDebugExecution(shared); @@ -1369,13 +1399,16 @@ void Debug::ClearBreakOnNextFunctionCall() { void Debug::PrepareStepIn(DirectHandle<JSFunction> function) { RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); - CHECK(last_step_action() >= StepInto || break_on_next_function_call() || - scheduled_break_on_function_call()); + const bool step_in = last_step_action() >= StepInto || + break_on_next_function_call() || + scheduled_break_on_function_call(); + CHECK(step_in || step_over_enters_functions()); if (ignore_events()) return; if (in_debug_scope()) return; if (break_disabled()) return; Handle<SharedFunctionInfo> shared(function->shared(), isolate_); if (IsBlackboxed(shared)) return; + if (!step_in && !ShouldEnterFunction(shared)) return; if (*function == thread_local_.ignore_step_into_function_) return; thread_local_.ignore_step_into_function_ = Smi::zero(); FloodWithOneShot(shared); @@ -2183,7 +2216,12 @@ Handle<SharedFunctionInfo> Debug::FindClosestSharedFunctionInfoFromPosition( const int end_position = outer_shared->EndPosition(); if (start_position == end_position) return outer_shared; - if (closest_position == 0) closest_position = end_position; + // If the outer function has no breakable position at or after the requested + // position, FindBreakablePosition() returns the last breakable position of + // the outer function (or its start position if it has no breakable positions + // at all), which comes before the requested position. In that case, search + // for nested functions until the end of the outer function instead. + if (closest_position < position) closest_position = end_position; std::vector<Handle<SharedFunctionInfo>> candidates; // Find all shared function infos of functions that are intersecting from // the requested position until the end of the enclosing function. @@ -2539,14 +2577,17 @@ std::optional<Tagged<Object>> Debug::OnThrow(DirectHandle<Object> exception, : v8::debug::kException, is_stack_overflow); } - PrepareStepOnThrow(); - // If the OnException handler requested termination, then indicated this to - // our caller Isolate::Throw so it can deal with it immediately instead of - // throwing the original exception. + // If the OnException handler requested frame restart or termination, then + // indicate this to our caller Isolate::Throw so it can deal with it + // immediately instead of throwing the original exception. + if (IsRestartFrameScheduled()) { + return isolate_->TerminateExecution(); + } if (isolate_->stack_guard()->CheckTerminateExecution()) { isolate_->stack_guard()->ClearTerminateExecution(); return isolate_->TerminateExecution(); } + PrepareStepOnThrow(); return {}; } @@ -2629,7 +2670,15 @@ void Debug::OnException(DirectHandle<Object> exception, for (; !it.done(); it.Advance()) { if (it.frame()->is_javascript()) { JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); - FrameSummary summary = FrameSummary::GetInnermost(frame); + FrameSummaries summaries = frame->Summarize(); +#if V8_ENABLE_WEBASSEMBLY + if (summaries.size() == 0) { + DCHECK_EQ(frame->function()->shared()->builtin_id(), + Builtin::kWasmMethodWrapper); + continue; + } +#endif // V8_ENABLE_WEBASSEMBLY + FrameSummary& summary = summaries.frames.back(); DirectHandle<SharedFunctionInfo> shared{ summary.AsJavaScript().function()->shared(), isolate_}; if (shared->IsSubjectToDebugging()) { @@ -2697,13 +2746,6 @@ void Debug::OnDebugBreak(DirectHandle<FixedArray> break_points_hit, HandleScope scope(isolate_); DisableBreak no_recursive_break(this); - if ((lastStepAction == StepAction::StepOver || - lastStepAction == StepAction::StepInto) && - ShouldBeSkipped()) { - PrepareStep(lastStepAction); - return; - } - std::vector<int> inspector_break_points_hit; // This array contains breakpoints installed using JS debug API. uint32_t break_points_hit_count = break_points_hit->ulength().value(); @@ -2722,6 +2764,21 @@ void Debug::OnDebugBreak(DirectHandle<FixedArray> break_points_hit, } } +bool Debug::ContinueSteppingIfSkipped(StepAction last_step_action) { + RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); + DCHECK(in_debug_scope()); + // The skip list only applies to StepInto and StepOver. + if (last_step_action != StepAction::StepOver && + last_step_action != StepAction::StepInto) { + return false; + } + if (ignore_events() || !debug_delegate_) return false; + HandleScope scope(isolate_); + if (!ShouldBeSkipped()) return false; + PrepareStep(last_step_action); + return true; +} + namespace { debug::Location GetDebugLocation(DirectHandle<Script> script, int source_position) { @@ -2745,6 +2802,24 @@ bool Debug::IsFunctionBlackboxed(DirectHandle<Script> script, const int start, ToApiHandle<debug::Script>(script), start_location, end_location); } +bool Debug::ShouldEnterFunction(DirectHandle<SharedFunctionInfo> shared) { + RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); + if (!debug_delegate_ || !shared->IsSubjectToDebugging() || + !IsScript(shared->script())) { + return false; + } + SuppressDebug while_processing(this); + HandleScope handle_scope(isolate_); + PostponeInterruptsScope no_interrupts(isolate_); + DisableBreak no_recursive_break(this); + DirectHandle<Script> script(Cast<Script>(shared->script()), isolate_); + RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback); + return debug_delegate_->ShouldEnterFunction( + ToApiHandle<debug::Script>(script), + GetDebugLocation(script, shared->StartPosition()), + GetDebugLocation(script, shared->EndPosition())); +} + bool Debug::IsBlackboxed(DirectHandle<SharedFunctionInfo> shared) { RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); if (!debug_delegate_) return !shared->IsSubjectToDebugging(); @@ -2893,6 +2968,7 @@ void Debug::UpdateHookOnFunctionCall() { static_assert(LastStepAction == StepInto); hook_on_function_call_ = thread_local_.last_step_action_ == StepInto || + step_over_enters_functions() || isolate_->debug_execution_mode() == DebugInfo::kSideEffects || thread_local_.break_on_next_function_call_; } @@ -2903,7 +2979,7 @@ void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode, // Ignore debug break during bootstrapping. if (isolate_->bootstrapper()->IsActive()) return; // Just continue if breaks are disabled. - if (break_disabled()) return; + if (break_disabled() || IsRestartFrameScheduled()) return; // Ignore debug break if debugger is not active. if (!is_active()) return; @@ -2937,24 +3013,35 @@ void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode, *function, LazyDeoptimizeReason::kDebugger, frame->LookupCode()); } + // Don't stop in builtin and blackboxed functions. The exception are OOM + // breaks: They are a last resort before the process dies and the + // inspector relies on them to happen (see + // V8Debugger::nearHeapLimitCallback). This mirrors the inspector, where + // OOM breaks also override "skip all pauses". + const bool ignore_break = + !break_reasons.contains(v8::debug::BreakReason::kOOM) && + (ignore_break_mode == kIgnoreIfTopFrameBlackboxed + ? IsBlackboxed(shared) + : AllFramesOnStackAreBlackboxed()); + if (ignore_break) return; + // kScheduled and kOOM breaks are triggered by the stack check. While we // could pause here, the JSFunction didn't have time yet to create and // push its context. Instead, we step into the function and pause at the // first official breakable position. - // This behavior mirrors "BreakOnNextFunctionCall". + // This behavior mirrors "BreakOnNextFunctionCall". Note that we flood + // the function directly instead of using PrepareStepIn: The step-in + // filters (e.g. blackboxing) must not drop an explicitly requested + // pause. Blackboxing was already taken into account above. if ((break_reasons.contains(v8::debug::BreakReason::kScheduled) || break_reasons.contains(v8::debug::BreakReason::kOOM)) && BreakLocation::IsPausedInJsFunctionEntry(frame)) { + if (ignore_events()) return; thread_local_.scheduled_break_on_next_function_call_.Add(break_reasons); - PrepareStepIn(function); + FloodWithOneShotIncludingBlackboxed(handle(*shared, isolate_)); return; } - // Don't stop in builtin and blackboxed functions. - bool ignore_break = ignore_break_mode == kIgnoreIfTopFrameBlackboxed - ? IsBlackboxed(shared) - : AllFramesOnStackAreBlackboxed(); - if (ignore_break) return; Handle<DebugInfo> debug_info; if (ToHandle(isolate_, TryGetDebugInfo(*shared), &debug_info) && debug_info->HasBreakInfo()) { @@ -3374,13 +3461,38 @@ bool Debug::PerformSideEffectCheckForInterceptor( return false; } +void Debug::FailSideEffectCheckForDeferredModuleEvaluation() { + RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); + DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects); + + // Evaluating a deferred module mutates the module graph (status, top-level + // capability) before any of its code runs, so it has to be rejected before + // Module::Evaluate is called. Terminating later, from inside the module + // body, would be recorded as the module's evaluation error. + if (v8_flags.trace_side_effect_free_debug_evaluate) { + PrintF( + "[debug-evaluate] Deferred module evaluation may cause side " + "effect.\n"); + } + + side_effect_check_failed_ = true; + // Throw an uncatchable termination exception. + isolate_->TerminateExecution(); +} + bool Debug::PerformSideEffectCheckAtBytecode(InterpretedFrame* frame) { RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger); using interpreter::Bytecode; DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects); Tagged<SharedFunctionInfo> shared = frame->function()->shared(); - Tagged<BytecodeArray> bytecode_array = shared->GetBytecodeArray(isolate_); + std::optional<Tagged<DebugInfo>> debug_info = TryGetDebugInfo(shared); + SBXCHECK(debug_info.has_value() && + debug_info.value()->HasInstrumentedBytecodeArray()); + SBXCHECK_EQ(debug_info.value()->DebugBytecodeArray(isolate_), + frame->GetBytecodeArray()); + Tagged<BytecodeArray> bytecode_array = + debug_info.value()->OriginalBytecodeArray(isolate_); int offset = frame->GetBytecodeOffset(); interpreter::BytecodeArrayIterator bytecode_iterator( handle(bytecode_array, isolate_), offset); diff --git a/deps/v8/src/debug/debug.h b/deps/v8/src/debug/debug.h index 4a093800e6d0..bb0f1b6e545f 100644 --- a/deps/v8/src/debug/debug.h +++ b/deps/v8/src/debug/debug.h @@ -257,6 +257,12 @@ class V8_EXPORT_PRIVATE Debug { void OnDebugBreak(DirectHandle<FixedArray> break_points_hit, StepAction stepAction, debug::BreakReasons break_reasons = {}); + // Must only be called for breaks that are caused purely by stepping (i.e. + // not by breakpoints, debugger statements, scheduled pauses, asserts, ...) + // after stepping was cleared. If the current location is covered by the skip + // list of the last StepInto/StepOver, stepping is re-armed and true is + // returned. In that case the caller must not pause. + bool ContinueSteppingIfSkipped(StepAction last_step_action); debug::DebugDelegate::ActionAfterInstrumentation OnInstrumentationBreak(); std::optional<Tagged<Object>> OnThrow(DirectHandle<Object> exception, @@ -309,6 +315,9 @@ class V8_EXPORT_PRIVATE Debug { void RemoveBreakpointForWasmScript(DirectHandle<Script> script, int id); void RecordWasmScriptWithBreakpoints(DirectHandle<Script> script); + DirectHandle<WeakArrayList> wasm_scripts_with_break_points() const { + return wasm_scripts_with_break_points_; + } #endif // V8_ENABLE_WEBASSEMBLY // Find breakpoints from the debug info and the break location and check @@ -345,6 +354,7 @@ class V8_EXPORT_PRIVATE Debug { const int end); bool IsBlackboxed(DirectHandle<SharedFunctionInfo> shared); bool ShouldBeSkipped(); + bool ShouldEnterFunction(DirectHandle<SharedFunctionInfo> shared); bool CanBreakAtEntry(DirectHandle<SharedFunctionInfo> shared); @@ -417,6 +427,7 @@ class V8_EXPORT_PRIVATE Debug { bool PerformSideEffectCheckForCallback(Handle<FunctionTemplateInfo> function); bool PerformSideEffectCheckForInterceptor( DirectHandle<InterceptorInfo> interceptor_info); + void FailSideEffectCheckForDeferredModuleEvaluation(); bool PerformSideEffectCheckAtBytecode(InterpretedFrame* frame); bool PerformSideEffectCheckForObject(DirectHandle<Object> object); @@ -457,6 +468,15 @@ class V8_EXPORT_PRIVATE Debug { return thread_local_.break_on_next_function_call_; } + void set_step_over_enters_functions(bool value) { + thread_local_.step_over_enters_functions_ = value; + } + // Whether the current StepOver enters functions selected by the delegate. + bool step_over_enters_functions() const { + return thread_local_.last_step_action_ == StepOver && + thread_local_.step_over_enters_functions_; + } + bool scheduled_break_on_function_call() const { return !thread_local_.scheduled_break_on_next_function_call_.empty(); } @@ -546,9 +566,12 @@ class V8_EXPORT_PRIVATE Debug { void ClearBreakPoints(Handle<DebugInfo> debug_info); // Clear all code from instrumentation. void ClearAllBreakPoints(); - // Instrument a function with one-shots. + // Instrument a function with one-shots. Blackboxed functions are ignored. void FloodWithOneShot(Handle<SharedFunctionInfo> function, bool returns_only = false); + // Same as {FloodWithOneShot}, but also instruments blackboxed functions. + void FloodWithOneShotIncludingBlackboxed(Handle<SharedFunctionInfo> function, + bool returns_only = false); // Clear all one-shot instrumentations, but restore break points. void ClearOneShot(); @@ -645,6 +668,11 @@ class V8_EXPORT_PRIVATE Debug { // If set then we need to repeat StepOut action at return. bool fast_forward_to_return_; + // If set, StepOver also enters functions selected by the delegate. Set by + // every step command and not reset by ClearStepping, so that re-prepared + // steps keep it. + bool step_over_enters_functions_; + // Source statement position from last step next action. int last_statement_position_; diff --git a/deps/v8/src/deoptimizer/deoptimizer.cc b/deps/v8/src/deoptimizer/deoptimizer.cc index 95bde97653fb..f042f904dff5 100644 --- a/deps/v8/src/deoptimizer/deoptimizer.cc +++ b/deps/v8/src/deoptimizer/deoptimizer.cc @@ -4,11 +4,13 @@ #include "src/deoptimizer/deoptimizer.h" +#include <array> #include <optional> #include "src/base/logging.h" #include "src/base/memory.h" #include "src/base/numerics/safe_conversions.h" +#include "src/builtins/builtins-inl.h" #include "src/codegen/interface-descriptors-inl.h" #include "src/codegen/register-configuration.h" #include "src/codegen/reloc-info.h" @@ -593,6 +595,10 @@ Address Deoptimizer::EnsureValidReturnAddress(Isolate* isolate, } #if V8_ENABLE_WEBASSEMBLY + if (v8_flags.wasm_growable_stacks && + Builtins::EntryOf(Builtin::kWasmReturnFromSegment, isolate) == address) { + return address; + } if (v8_flags.wasm_deopt && wasm::GetWasmCodeManager()->LookupCode(isolate, address) != nullptr) { // TODO(42204618): This does not check for the PC being a valid "deopt @@ -607,10 +613,6 @@ Address Deoptimizer::EnsureValidReturnAddress(Isolate* isolate, void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) { deoptimizer->DoComputeOutputFrames(); - // TODO(mliedtke,415707239): Ideally we'd only reset this when destroying this - // object, however when calling the WasmLiftoffDeoptFinish builtin, we read - // from the heap (probably in DEBUG-only code). - deoptimizer->disallow_sandbox_access_.reset(); } const char* Deoptimizer::MessageFor(DeoptimizeKind kind) { @@ -795,6 +797,7 @@ Deoptimizer::~Deoptimizer() { DCHECK_NULL(shadow_stack_); #endif DCHECK_NULL(disallow_garbage_collection_); + DCHECK(!disallow_sandbox_access_.has_value()); delete trace_scope_; } @@ -818,6 +821,7 @@ void Deoptimizer::DeleteFrameDescriptions() { delete disallow_garbage_collection_; disallow_garbage_collection_ = nullptr; #endif // DEBUG + disallow_sandbox_access_.reset(); } Builtin Deoptimizer::GetDeoptimizationEntry(DeoptimizeKind kind) { @@ -1015,6 +1019,7 @@ CompileWithLiftoffAndGetDeoptInfo(wasm::NativeModule* native_module, // WasmCodeManager as a deopt was reached. wasm::UnpublishedWasmCode compiled_code = native_module->AddCompiledCode(result); + compiled_code.for_deopt = true; wasm::WasmCodeRefScope code_ref_scope; // TODO(mliedtke): This might unoptimize functions because they were inlined // into a function that now needs to deopt them while the optimized function @@ -1229,19 +1234,10 @@ FrameDescription* Deoptimizer::DoComputeWasmLiftoffFrame( output_frame->SetSimd128Register(liftoff_iter->reg().simd128().code(), value.simd_value()); } else if (!Is64() && liftoff_iter->is_gp_reg_pair()) { - intptr_t reg_value = kZapValue; - switch (value.kind()) { - case TranslatedValue::Kind::kInt32: - CHECK_EQ(liftoff_iter->kind(), wasm::ValueKind::kI64); - // Ensure that the upper half is zeroed out. - reg_value = static_cast<uint32_t>(value.int32_value()); - break; - case TranslatedValue::Kind::kTagged: - reg_value = value.raw_literal().ptr(); - break; - default: - UNREACHABLE(); - } + CHECK_EQ(liftoff_iter->kind(), wasm::ValueKind::kI64); + CHECK_EQ(value.kind(), TranslatedValue::Kind::kInt32); + // Ensure that the upper half is zeroed out. + intptr_t reg_value = static_cast<uint32_t>(value.int32_value()); int8_t reg = int64_lowering_is_low ? liftoff_iter->reg().low_gp().code() : liftoff_iter->reg().high_gp().code(); @@ -1340,25 +1336,10 @@ FrameDescription* Deoptimizer::DoComputeWasmLiftoffFrame( } // Store frame kind. - // For growable stacks, the frame at the entry point of a new stack segment - // is marked as WASM_SEGMENT_START. Preserving this marker on the bottommost - // frame during deoptimization ensures that the return sequence will shrink - // the stack segment when returning to the caller. uint32_t frame_type_offset = base_offset + WasmLiftoffFrameConstants::kFrameTypeOffset; - StackFrame::Type frame_type = StackFrame::WASM; - if (is_bottommost) { - intptr_t input_frame_marker = - base::Memory<intptr_t>(input_->GetFramePointerAddress() + - TypedFrameConstants::kFrameTypeOffset); - if (StackFrame::MarkerToType(input_frame_marker) == - StackFrame::WASM_SEGMENT_START) { - DCHECK(v8_flags.wasm_growable_stacks); - frame_type = StackFrame::WASM_SEGMENT_START; - } - } output_frame->SetFrameSlot(frame_type_offset, - StackFrame::TypeToMarker(frame_type)); + StackFrame::TypeToMarker(StackFrame::WASM)); // Fill feedback vector stack slot. // Instead of storing the actual feedback vector, we simply store the declared // function index of the wasm function. This is done because the feedback @@ -2074,17 +2055,10 @@ void Deoptimizer::DoComputeUnoptimizedFrame(TranslatedFrame* translated_frame, { AllowSandboxAccess sandbox_access( - "Fetching DebugBytecodeArray via SFI. This is probably unsafe but we " - "only do it when debugging is enabled. Just in case the defence in " - "depth checks below should protect against swaps."); - std::optional<Tagged<DebugInfo>> debug_info = - translated_frame->raw_shared_info()->TryGetDebugInfo(isolate()); - if (debug_info.has_value() && debug_info.value()->HasBreakInfo()) { - bytecode_array = debug_info.value()->DebugBytecodeArray(isolate()); - // Defence-in-depth in case bytecode is swapped. - SBXCHECK_EQ(bytecode_array->parameter_count(), parameters_count); - SBXCHECK_EQ(bytecode_array->register_count(), locals_count); - } + "Fetching DebugBytecodeArray via SFI. This is safe because we verify " + "below that the SFI's original BytecodeArray matches the frame's " + "trusted BytecodeArray."); + bytecode_array = translated_frame->GetActiveBytecodeArray(isolate()); } // Allocate and store the output frame description. @@ -3086,21 +3060,21 @@ void Deoptimizer::DoComputeBuiltinContinuation( config->num_allocatable_general_registers(); for (int i = 0; i < allocatable_register_count; ++i) { int code = config->GetAllocatableGeneralCode(i); - auto str = base::OwnedVector<char>::NewForOverwrite(128); + std::array<char, 128> str; if (verbose_tracing_enabled()) { if (BuiltinContinuationModeIsJavaScript(mode) && code == kJavaScriptCallArgCountRegister.code()) { - SNPrintF( - str.as_vector(), + base::SNPrintF( + str, "tagged argument count %s (will be untagged by continuation)\n", RegisterName(Register::from_code(code))); } else { - SNPrintF(str.as_vector(), "builtin register argument %s\n", - RegisterName(Register::from_code(code))); + base::SNPrintF(str, "builtin register argument %s\n", + RegisterName(Register::from_code(code))); } } frame_writer.PushTranslatedValue( - register_values[code], verbose_tracing_enabled() ? str.begin() : ""); + register_values[code], verbose_tracing_enabled() ? str.data() : ""); } // Some architectures must pad the stack frame with extra stack slots diff --git a/deps/v8/src/deoptimizer/deoptimizer.h b/deps/v8/src/deoptimizer/deoptimizer.h index 87703aa4d565..53706dfa7bb6 100644 --- a/deps/v8/src/deoptimizer/deoptimizer.h +++ b/deps/v8/src/deoptimizer/deoptimizer.h @@ -15,9 +15,9 @@ #include "src/deoptimizer/translated-state.h" #include "src/diagnostics/code-tracer.h" #include "src/objects/js-function.h" +#include "src/sandbox/hardware-support.h" #if V8_ENABLE_WEBASSEMBLY -#include "src/sandbox/hardware-support.h" #include "src/wasm/value-type.h" #endif // V8_ENABLE_WEBASSEMBLY diff --git a/deps/v8/src/deoptimizer/frame-translation-builder.cc b/deps/v8/src/deoptimizer/frame-translation-builder.cc index dc337a5a162c..acc2218f64fe 100644 --- a/deps/v8/src/deoptimizer/frame-translation-builder.cc +++ b/deps/v8/src/deoptimizer/frame-translation-builder.cc @@ -484,6 +484,20 @@ void FrameTranslationBuilder::StoreLiteral(int literal_id) { Add(opcode, SignedOperand(literal_id)); } +void FrameTranslationBuilder::StoreDoubleLiteral(Float64 value) { + auto opcode = TranslationOpcode::DOUBLE_LITERAL; + uint64_t bits = value.get_bits(); + Add(opcode, UnsignedOperand(static_cast<uint32_t>(bits)), + UnsignedOperand(static_cast<uint32_t>(bits >> 32))); +} + +void FrameTranslationBuilder::StoreHoleyDoubleLiteral(Float64 value) { + auto opcode = TranslationOpcode::HOLEY_DOUBLE_LITERAL; + uint64_t bits = value.get_bits(); + Add(opcode, UnsignedOperand(static_cast<uint32_t>(bits)), + UnsignedOperand(static_cast<uint32_t>(bits >> 32))); +} + void FrameTranslationBuilder::StoreOptimizedOut() { auto opcode = TranslationOpcode::OPTIMIZED_OUT; Add(opcode); diff --git a/deps/v8/src/deoptimizer/frame-translation-builder.h b/deps/v8/src/deoptimizer/frame-translation-builder.h index cdabcb9166c5..9b2566d8bdb4 100644 --- a/deps/v8/src/deoptimizer/frame-translation-builder.h +++ b/deps/v8/src/deoptimizer/frame-translation-builder.h @@ -88,6 +88,8 @@ class FrameTranslationBuilder { void StoreSimd128StackSlot(int index); void StoreHoleyDoubleStackSlot(int index); void StoreLiteral(int literal_id); + void StoreDoubleLiteral(Float64 value); + void StoreHoleyDoubleLiteral(Float64 value); void StoreOptimizedOut(); void StoreJSFrameFunction(); diff --git a/deps/v8/src/deoptimizer/translated-state.cc b/deps/v8/src/deoptimizer/translated-state.cc index 634b0334e5c9..25cb3c205ab3 100644 --- a/deps/v8/src/deoptimizer/translated-state.cc +++ b/deps/v8/src/deoptimizer/translated-state.cc @@ -33,6 +33,7 @@ #include "src/objects/object-conversions-inl.h" #include "src/objects/oddball.h" #include "src/objects/string.h" +#include "src/sandbox/check.h" // Has to be the last include (doesn't have include guards) #include "src/objects/object-macros.h" @@ -333,6 +334,21 @@ void DeoptimizationFrameTranslationPrintSingleOpcode( break; } + case TranslationOpcode::DOUBLE_LITERAL: + case TranslationOpcode::HOLEY_DOUBLE_LITERAL: { + DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 2); + uint32_t low = iterator.NextOperandUnsigned(); + uint32_t high = iterator.NextOperandUnsigned(); + Float64 value = + Float64::FromBits((static_cast<uint64_t>(high) << 32) | low); + os << "{double_literal=" << value.get_scalar() << " (0x" << std::hex + << value.get_bits() << std::dec << ")" + << (opcode == TranslationOpcode::HOLEY_DOUBLE_LITERAL ? " (holey)" + : "") + << "}"; + break; + } + case TranslationOpcode::DUPLICATED_OBJECT: { DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1); int object_index = iterator.NextOperand(); @@ -738,7 +754,11 @@ Handle<Object> TranslatedValue::GetValue() { // We shouldn't have hole values by now, so treat holey double as normal // doubles. case TranslatedValue::kHoleyDouble: - number = double_value().get_scalar(); + if (double_value().is_nan()) { + number = std::numeric_limits<double>::quiet_NaN(); + } else { + number = double_value().get_scalar(); + } heap_object = isolate()->factory()->NewHeapNumber(number); break; default: @@ -750,6 +770,35 @@ Handle<Object> TranslatedValue::GetValue() { return storage_; } +Float64 TranslatedValue::GetDoubleValue() { + switch (kind()) { + case TranslatedValue::kDouble: + case TranslatedValue::kHoleyDouble: + return double_value(); + case TranslatedValue::kFloat: + return Float64::FromMaybeNaN(float_value().get_scalar()); + case TranslatedValue::kInt32: + return Float64(static_cast<double>(int32_value())); + case TranslatedValue::kUint32: + return Float64(static_cast<double>(uint32_value())); + default: { + DCHECK(!v8_flags.turbolev); + DirectHandle<Object> value = GetValue(); + if (IsNumber(*value)) { + return Float64::FromMaybeNaN(Object::NumberValue(*value)); +#ifdef V8_ENABLE_UNDEFINED_DOUBLE + } else if (value.is_identical_to( + isolate()->factory()->undefined_value())) { + return Float64::undefined_nan(); +#endif // V8_ENABLE_UNDEFINED_DOUBLE + } else { + CHECK(value.is_identical_to(isolate()->factory()->the_hole_value())); + return Float64::hole_nan(); + } + } + } +} + bool TranslatedValue::IsMaterializedObject() const { switch (kind()) { case kCapturedObject: @@ -961,6 +1010,13 @@ void TranslatedFrame::Handlify(Isolate* isolate) { handle_state_ = kHandles; } +Tagged<BytecodeArray> TranslatedFrame::GetActiveBytecodeArray( + Isolate* isolate) const { + auto bytecodes = raw_shared_info()->GetBytecodeArrays(isolate); + SBXCHECK_EQ(bytecodes.original, raw_bytecode_array()); + return bytecodes.active; +} + DeoptimizationLiteralProvider::DeoptimizationLiteralProvider( Tagged<DeoptimizationLiteralArray> literal_array) : literals_on_heap_(literal_array) {} @@ -1211,6 +1267,8 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame( case TranslationOpcode::SIMD128_STACK_SLOT: case TranslationOpcode::HOLEY_DOUBLE_STACK_SLOT: case TranslationOpcode::LITERAL: + case TranslationOpcode::DOUBLE_LITERAL: + case TranslationOpcode::HOLEY_DOUBLE_LITERAL: case TranslationOpcode::OPTIMIZED_OUT: case TranslationOpcode::MATCH_PREVIOUS_TRANSLATION: break; @@ -1775,6 +1833,50 @@ int TranslatedState::CreateNextTranslatedValue( return translated_value.GetChildrenCount(); } + case TranslationOpcode::DOUBLE_LITERAL: { + uint32_t low = iterator->NextOperandUnsigned(); + uint32_t high = iterator->NextOperandUnsigned(); + Float64 value = + Float64::FromBits((static_cast<uint64_t>(high) << 32) | low); + if constexpr (IsTracing) { + if (value.is_nan()) { + PrintF(trace_file, "(double literal %e 0x%" PRIx64 ")", + value.get_scalar(), value.get_bits()); + } else { + PrintF(trace_file, "(double literal %e)", value.get_scalar()); + } + } + TranslatedValue translated_value = + TranslatedValue::NewDouble(this, value); + frame.Add(translated_value); + return translated_value.GetChildrenCount(); + } + + case TranslationOpcode::HOLEY_DOUBLE_LITERAL: { + uint32_t low = iterator->NextOperandUnsigned(); + uint32_t high = iterator->NextOperandUnsigned(); + Float64 value = + Float64::FromBits((static_cast<uint64_t>(high) << 32) | low); + if constexpr (IsTracing) { + if (value.is_hole_nan()) { + PrintF(trace_file, "(holey double literal hole nan)"); +#ifdef V8_ENABLE_UNDEFINED_DOUBLE + } else if (value.is_undefined_nan()) { + PrintF(trace_file, "(holey double literal undefined nan)"); +#endif // V8_ENABLE_UNDEFINED_DOUBLE + } else if (value.is_nan()) { + PrintF(trace_file, "(holey double literal %e 0x%" PRIx64 ")", + value.get_scalar(), value.get_bits()); + } else { + PrintF(trace_file, "(holey double literal %e)", value.get_scalar()); + } + } + TranslatedValue translated_value = + TranslatedValue::NewHoleyDouble(this, value); + frame.Add(translated_value); + return translated_value.GetChildrenCount(); + } + case TranslationOpcode::LITERAL: { int literal_index = iterator->NextOperand(); TranslatedValue translated_value = literal_array.Get(this, literal_index); @@ -2109,6 +2211,7 @@ void TranslatedState::InitializeCapturedObjectAt( // Handle the special cases. switch (map->instance_type()) { case HEAP_NUMBER_TYPE: + case UNINITIALIZED_HEAP_NUMBER_TYPE: case FIXED_DOUBLE_ARRAY_TYPE: return; @@ -2192,8 +2295,10 @@ void TranslatedState::MaterializeFixedDoubleArray(TranslatedFrame* frame, int* value_index, TranslatedValue* slot, DirectHandle<Map> map) { + CHECK_GE(slot->GetChildrenCount(), 2); uint32_t length = base::checked_cast<uint32_t>(frame->values_[*value_index].GetSmiValue()); + SBXCHECK_EQ(length, slot->GetChildrenCount() - 2); (*value_index)++; Handle<FixedDoubleArray> array = Cast<FixedDoubleArray>(isolate()->factory()->NewFixedDoubleArray(length)); @@ -2201,17 +2306,8 @@ void TranslatedState::MaterializeFixedDoubleArray(TranslatedFrame* frame, for (uint32_t i = 0; i < length; i++) { CHECK_NE(TranslatedValue::kCapturedObject, frame->values_[*value_index].kind()); - DirectHandle<Object> value = frame->values_[*value_index].GetValue(); - if (IsNumber(*value)) { - array->set(i, Object::NumberValue(*value)); -#ifdef V8_ENABLE_UNDEFINED_DOUBLE - } else if (value.is_identical_to(isolate()->factory()->undefined_value())) { - array->set_undefined(i); -#endif // V8_ENABLE_UNDEFINED_DOUBLE - } else { - CHECK(value.is_identical_to(isolate()->factory()->the_hole_value())); - array->set_the_hole(isolate(), i); - } + Float64 value = frame->values_[*value_index].GetDoubleValue(); + array->set_raw(i, value); (*value_index)++; } slot->set_storage(array); @@ -2222,21 +2318,27 @@ void TranslatedState::MaterializeHeapNumber(TranslatedFrame* frame, TranslatedValue* slot) { CHECK_NE(TranslatedValue::kCapturedObject, frame->values_[*value_index].kind()); - DirectHandle<Object> value = frame->values_[*value_index].GetValue(); - Handle<HeapNumber> box; - if (value.is_identical_to(isolate()->factory()->the_hole_value())) { - // See is_hole_nan conversions in maglev-code-generator.cc and - // turbolev-graph-builder.cc. - box = isolate()->factory()->NewHeapNumber( - std::numeric_limits<double>::quiet_NaN()); - } else { - CHECK(IsNumber(*value)); - box = isolate()->factory()->NewHeapNumber(Object::NumberValue(*value)); + Float64 value = frame->values_[*value_index].GetDoubleValue(); + if (value.is_nan()) { + value = Float64::quiet_nan(); } + Handle<HeapNumber> box = + isolate()->factory()->NewHeapNumber(value.get_scalar()); (*value_index)++; slot->set_storage(box); } +void TranslatedState::MaterializeUninitializedHeapNumber( + TranslatedFrame* frame, int* value_index, TranslatedValue* slot) { + CHECK_NE(TranslatedValue::kCapturedObject, + frame->values_[*value_index].kind()); + DirectHandle<Object> value = frame->values_[*value_index].GetValue(); + Handle<HeapObject> box = isolate()->factory()->NewUninitializedHeapNumber(); + (*value_index)++; + slot->set_storage(box); + USE(value); +} + namespace { enum StorageKind : uint8_t { kStoreTagged, kStoreHeapObject }; @@ -2290,6 +2392,12 @@ void TranslatedState::EnsureCapturedObjectAllocatedAt( // There is no need to process the children. return MaterializeHeapNumber(frame, &value_index, slot); + case UNINITIALIZED_HEAP_NUMBER_TYPE: + // Materialize (i.e. allocate&initialize) the uninitialized heap number + // and return. + // There is no need to process the children. + return MaterializeUninitializedHeapNumber(frame, &value_index, slot); + case FIXED_ARRAY_TYPE: case SCRIPT_CONTEXT_TABLE_TYPE: case AWAIT_CONTEXT_TYPE: @@ -2619,10 +2727,10 @@ void TranslatedState::InitializeJSObjectAt( value = CheckedCast<RegExpData>(*field_value); } object_storage - ->RawIndirectPointerField(offset, kRegExpDataIndirectPointerTag) - .Relaxed_Store(value); - INDIRECT_POINTER_WRITE_BARRIER(*object_storage, offset, - kRegExpDataIndirectPointerTag, value); + ->RawTrustedPointerField(offset, kRegExpDataTrustedPointerTag) + .Release_Store(value); + TRUSTED_POINTER_WRITE_BARRIER(*object_storage, offset, + kRegExpDataTrustedPointerTag, value); continue; } #endif // V8_ENABLE_SANDBOX diff --git a/deps/v8/src/deoptimizer/translated-state.h b/deps/v8/src/deoptimizer/translated-state.h index 0032eb1f7712..b0e18fc3dfe7 100644 --- a/deps/v8/src/deoptimizer/translated-state.h +++ b/deps/v8/src/deoptimizer/translated-state.h @@ -67,6 +67,8 @@ class TranslatedValue { // possible. Handle<Object> GetValue(); + Float64 GetDoubleValue(); + bool IsMaterializedObject() const; bool IsMaterializableByDebugger() const; @@ -275,6 +277,11 @@ class TranslatedFrame { return raw_bytecode_array_; } + // Returns the active (potentially debug) BytecodeArray associated with this + // frame's SharedFunctionInfo after verifying that the frame's original + // BytecodeArray is consistent with it. + Tagged<BytecodeArray> GetActiveBytecodeArray(Isolate* isolate) const; + using ValuesContainer = base::SmallVector<TranslatedValue, 8>; class V8_GSL_POINTER iterator { @@ -553,6 +560,9 @@ class TranslatedState { DirectHandle<Map> map); void MaterializeHeapNumber(TranslatedFrame* frame, int* value_index, TranslatedValue* slot); + void MaterializeUninitializedHeapNumber(TranslatedFrame* frame, + int* value_index, + TranslatedValue* slot); void EnsureObjectAllocatedAt(TranslatedValue* slot); diff --git a/deps/v8/src/deoptimizer/translation-opcode.h b/deps/v8/src/deoptimizer/translation-opcode.h index 0bc7a1c202b9..5ee425458cf0 100644 --- a/deps/v8/src/deoptimizer/translation-opcode.h +++ b/deps/v8/src/deoptimizer/translation-opcode.h @@ -38,9 +38,11 @@ namespace internal { V(BOOL_STACK_SLOT, 1) \ V(CAPTURED_OBJECT, 1) \ V(STRING_CONCAT, 0) \ + V(DOUBLE_LITERAL, 2) \ V(DOUBLE_REGISTER, 1) \ V(DOUBLE_STACK_SLOT, 1) \ V(SIMD128_STACK_SLOT, 1) \ + V(HOLEY_DOUBLE_LITERAL, 2) \ V(HOLEY_DOUBLE_REGISTER, 1) \ V(HOLEY_DOUBLE_STACK_SLOT, 1) \ V(SIMD128_REGISTER, 1) \ diff --git a/deps/v8/src/diagnostics/arm/disasm-arm.cc b/deps/v8/src/diagnostics/arm/disasm-arm.cc index 2e21165e8326..bfaaeba5b258 100644 --- a/deps/v8/src/diagnostics/arm/disasm-arm.cc +++ b/deps/v8/src/diagnostics/arm/disasm-arm.cc @@ -11,7 +11,7 @@ // NameConverter converter; // Disassembler d(converter); // for (uint8_t* pc = begin; pc < end;) { -// v8::base::EmbeddedVector<char, 256> buffer; +// std::array<char, 256> buffer; // uint8_t* prev_pc = pc; // pc += d.InstructionDecode(buffer, pc); // printf("%p %08x %s\n", @@ -22,6 +22,8 @@ // of code into a FILE*, meaning that the above functionality could also be // achieved by just calling Disassembler::Disassemble(stdout, begin, end); +#include <array> +#include <bit> #include <cassert> #include <cinttypes> #include <cstdarg> @@ -2154,7 +2156,7 @@ void Decoder::DecodeAdvancedSIMDDataProcessing(Instruction* instr) { if (imm3H_L != 0 && opc == 0) { // vshr.s<size> Qd, Qm, shift int imm7 = (l << 6) | instr->Bits(21, 16); - int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int size = std::bit_floor<uint32_t>(imm7); int shift = 2 * size - imm7; if (q) { int Vd = instr->VFPDRegValue(kSimd128Precision); @@ -2173,7 +2175,7 @@ void Decoder::DecodeAdvancedSIMDDataProcessing(Instruction* instr) { // vsra.<type><size> Qd, Qm, shift // vsra.<type><size> Dd, Dm, shift int imm7 = (l << 6) | instr->Bits(21, 16); - int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int size = std::bit_floor<uint32_t>(imm7); int shift = 2 * size - imm7; if (q) { int Vd = instr->VFPDRegValue(kSimd128Precision); @@ -2200,7 +2202,7 @@ void Decoder::DecodeAdvancedSIMDDataProcessing(Instruction* instr) { } else if (!u && imm3H_L != 0 && opc == 0b0101) { // vshl.i<size> Qd, Qm, shift int imm7 = (l << 6) | instr->Bits(21, 16); - int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int size = std::bit_floor<uint32_t>(imm7); int shift = imm7 - size; int Vd = instr->VFPDRegValue(kSimd128Precision); int Vm = instr->VFPMRegValue(kSimd128Precision); @@ -2211,7 +2213,7 @@ void Decoder::DecodeAdvancedSIMDDataProcessing(Instruction* instr) { // vsli.<size> Dd, Dm, shift // vsri.<size> Dd, Dm, shift int imm7 = (l << 6) | instr->Bits(21, 16); - int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int size = std::bit_floor<uint32_t>(imm7); int shift; char direction; if (instr->Bit(8) == 1) { @@ -2592,7 +2594,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -2634,12 +2636,12 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), - *reinterpret_cast<int32_t*>(prev_pc), buffer.begin()); + *reinterpret_cast<int32_t*>(prev_pc), buffer.data()); } } diff --git a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc index 4b8f03a38b30..275ebe9f431a 100644 --- a/deps/v8/src/diagnostics/arm64/disasm-arm64.cc +++ b/deps/v8/src/diagnostics/arm64/disasm-arm64.cc @@ -977,6 +977,40 @@ void DisassemblingDecoder::VisitLoadStoreUnscaledOffset(Instruction* instr) { #undef LOAD_STORE_UNSCALED_LIST +#define LOAD_STORE_RCPC_UNSCALED_LIST(V) \ + V(STLURB, "stlurb", "'Wt") \ + V(STLURH, "stlurh", "'Wt") \ + V(STLUR_w, "stlur", "'Wt") \ + V(STLUR_x, "stlur", "'Xt") \ + V(LDAPURB, "ldapurb", "'Wt") \ + V(LDAPURH, "ldapurh", "'Wt") \ + V(LDAPUR_w, "ldapur", "'Wt") \ + V(LDAPUR_x, "ldapur", "'Xt") \ + V(LDAPURSB_x, "ldapursb", "'Xt") \ + V(LDAPURSH_x, "ldapursh", "'Xt") \ + V(LDAPURSW_x, "ldapursw", "'Xt") \ + V(LDAPURSB_w, "ldapursb", "'Wt") \ + V(LDAPURSH_w, "ldapursh", "'Wt") + +void DisassemblingDecoder::VisitLoadStoreRCpcUnscaledOffset( + Instruction* instr) { + const char* mnemonic = "unimplemented"; + const char* form = "(LoadStoreRCpcUnscaledOffset)"; + + switch (instr->Mask(LoadStoreRCpcUnscaledOffsetMask)) { +#define LS_RCPC_UNSCALEDOFFSET(A, B, C) \ + case A: \ + mnemonic = B; \ + form = C ", ['Xns'ILS]"; \ + break; + LOAD_STORE_RCPC_UNSCALED_LIST(LS_RCPC_UNSCALEDOFFSET) +#undef LS_RCPC_UNSCALEDOFFSET + } + Format(instr, mnemonic, form); +} + +#undef LOAD_STORE_RCPC_UNSCALED_LIST + void DisassemblingDecoder::VisitLoadLiteral(Instruction* instr) { const char* mnemonic = "ldr"; const char* form = "(LoadLiteral)"; @@ -3833,6 +3867,24 @@ void DisassemblingDecoder::VisitSVEBitPerm(Instruction* instr) { Format(instr, mnemonic, ssd.Substitute(form)); } +void DisassemblingDecoder::VisitSVE2Mul(Instruction* instr) { + const char* form = "'Zd.%s, 'Zn.%s, 'Zm.%s"; + const char* mnemonic = "unimplemented"; + SVESizeDecoder ssd(instr); + + DCHECK_EQ(instr->Mask(SVE2MulFMask), SVE2MulFixed); + + switch (instr->Mask(SVE2MulMask)) { + case SVE2_MUL: + mnemonic = "mul"; + break; + default: + UNREACHABLE(); + } + + Format(instr, mnemonic, ssd.Substitute(form)); +} + void DisassemblingDecoder::VisitUnimplemented(Instruction* instr) { Format(instr, "unimplemented", "(Unimplemented)"); } @@ -4718,7 +4770,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -4734,7 +4786,7 @@ const char* NameConverter::NameOfCPURegister(int reg) const { return "xzr"; } v8::base::SNPrintF(tmp_buffer_, "x%u", ureg); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfByteCPURegister(int reg) const { diff --git a/deps/v8/src/diagnostics/code-tracer.h b/deps/v8/src/diagnostics/code-tracer.h index e17bf47de04c..e468c494cdac 100644 --- a/deps/v8/src/diagnostics/code-tracer.h +++ b/deps/v8/src/diagnostics/code-tracer.h @@ -5,12 +5,12 @@ #ifndef V8_DIAGNOSTICS_CODE_TRACER_H_ #define V8_DIAGNOSTICS_CODE_TRACER_H_ +#include <array> #include <optional> #include "src/base/platform/platform.h" #include "src/base/platform/wrappers.h" #include "src/base/strings.h" -#include "src/base/vector.h" #include "src/flags/flags.h" #include "src/utils/allocation.h" #include "src/utils/ostreams.h" @@ -29,7 +29,7 @@ class CodeTracer final : public Malloced { if (v8_flags.redirect_code_traces_to != nullptr) { base::StrNCpy(filename_, v8_flags.redirect_code_traces_to, - filename_.size()); + base::checked_cast<uint32_t>(filename_.size())); } else if (isolate_id >= 0) { base::SNPrintF(filename_, "code-%d-%d.asm", base::OS::GetCurrentProcessId(), isolate_id); @@ -37,7 +37,7 @@ class CodeTracer final : public Malloced { base::SNPrintF(filename_, "code-%d.asm", base::OS::GetCurrentProcessId()); } - WriteChars(filename_.begin(), "", 0, false); + WriteChars(filename_.data(), "", 0, false); } class V8_NODISCARD Scope { @@ -79,7 +79,7 @@ class CodeTracer final : public Malloced { } if (file_ == nullptr) { - file_ = base::OS::FOpen(filename_.begin(), "ab"); + file_ = base::OS::FOpen(filename_.data(), "ab"); CHECK_WITH_MSG(file_ != nullptr, "could not open file. If on Android, try passing " "--redirect-code-traces-to=/sdcard/Download/<file-name>"); @@ -105,7 +105,7 @@ class CodeTracer final : public Malloced { private: static bool ShouldRedirect() { return v8_flags.redirect_code_traces; } - base::EmbeddedVector<char, 128> filename_; + std::array<char, 128> filename_; FILE* file_; int scope_depth_; }; diff --git a/deps/v8/src/diagnostics/disasm.h b/deps/v8/src/diagnostics/disasm.h index 089cf51893c7..3796b1bb7a26 100644 --- a/deps/v8/src/diagnostics/disasm.h +++ b/deps/v8/src/diagnostics/disasm.h @@ -5,6 +5,8 @@ #ifndef V8_DIAGNOSTICS_DISASM_H_ #define V8_DIAGNOSTICS_DISASM_H_ +#include <array> + #include "src/base/vector.h" namespace disasm { @@ -29,7 +31,7 @@ class V8_EXPORT_PRIVATE NameConverter { virtual const char* RootRelativeName(int offset) const { return nullptr; } protected: - mutable v8::base::EmbeddedVector<char, 128> tmp_buffer_; + mutable std::array<char, 128> tmp_buffer_; }; // A generic Disassembler interface diff --git a/deps/v8/src/diagnostics/disassembler.cc b/deps/v8/src/diagnostics/disassembler.cc index f879fd5a1f29..dff5f819bb1f 100644 --- a/deps/v8/src/diagnostics/disassembler.cc +++ b/deps/v8/src/diagnostics/disassembler.cc @@ -5,6 +5,7 @@ #include "src/diagnostics/disassembler.h" #include <algorithm> +#include <array> #include <iomanip> #include <memory> #include <sstream> @@ -56,7 +57,7 @@ class V8NameConverter : public disasm::NameConverter { Isolate* isolate_; CodeReference code_; - mutable base::EmbeddedVector<char, 128> v8_buffer_; + mutable std::array<char, 128> v8_buffer_; // Map from root-register relative offset of the external reference value to // the external reference name (stored in the external reference table). @@ -91,25 +92,25 @@ const char* V8NameConverter::NameOfAddress(uint8_t* pc) const { : nullptr; if (name != nullptr) { - SNPrintF(v8_buffer_, "%p (%s)", static_cast<void*>(pc), name); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "%p (%s)", static_cast<void*>(pc), name); + return v8_buffer_.data(); } int offs = static_cast<int>(reinterpret_cast<Address>(pc) - code_.instruction_start()); // print as code offset, if it seems reasonable if (0 <= offs && offs < code_.instruction_size()) { - SNPrintF(v8_buffer_, "%p <+0x%x>", static_cast<void*>(pc), offs); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "%p <+0x%x>", static_cast<void*>(pc), offs); + return v8_buffer_.data(); } #if V8_ENABLE_WEBASSEMBLY wasm::WasmCodeRefScope code_ref_scope; if (auto* wasm_code = wasm::GetWasmCodeManager()->LookupCode( reinterpret_cast<Address>(pc))) { - SNPrintF(v8_buffer_, "%p (%s)", static_cast<void*>(pc), - wasm::GetWasmCodeKindAsString(wasm_code->kind())); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "%p (%s)", static_cast<void*>(pc), + wasm::GetWasmCodeKindAsString(wasm_code->kind())); + return v8_buffer_.data(); } #endif // V8_ENABLE_WEBASSEMBLY } @@ -146,8 +147,8 @@ const char* V8NameConverter::RootRelativeName(int offset) const { RootIndex root_index = static_cast<RootIndex>(offset_in_roots_table / kSystemPointerSize); - SNPrintF(v8_buffer_, "root (%s)", RootsTable::name(root_index)); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "root (%s)", RootsTable::name(root_index)); + return v8_buffer_.data(); } else if (static_cast<unsigned>(offset - kExtRefsTableStart) < kExtRefsTableSize) { uint32_t offset_in_extref_table = offset - kExtRefsTableStart; @@ -162,10 +163,10 @@ const char* V8NameConverter::RootRelativeName(int offset) const { return nullptr; } - SNPrintF(v8_buffer_, "external reference (%s)", - isolate_->external_reference_table()->NameFromOffset( - offset_in_extref_table)); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "external reference (%s)", + isolate_->external_reference_table()->NameFromOffset( + offset_in_extref_table)); + return v8_buffer_.data(); } else if (static_cast<unsigned>(offset - kBuiltinTier0TableStart) < kBuiltinTier0TableSize) { uint32_t offset_in_builtins_table = (offset - kBuiltinTier0TableStart); @@ -173,8 +174,8 @@ const char* V8NameConverter::RootRelativeName(int offset) const { Builtin builtin = Builtins::FromInt(offset_in_builtins_table / kSystemPointerSize); const char* name = Builtins::name(builtin); - SNPrintF(v8_buffer_, "builtin (%s)", name); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "builtin (%s)", name); + return v8_buffer_.data(); } else if (static_cast<unsigned>(offset - kBuiltinTableStart) < kBuiltinTableSize) { uint32_t offset_in_builtins_table = (offset - kBuiltinTableStart); @@ -182,8 +183,8 @@ const char* V8NameConverter::RootRelativeName(int offset) const { Builtin builtin = Builtins::FromInt(offset_in_builtins_table / kSystemPointerSize); const char* name = Builtins::name(builtin); - SNPrintF(v8_buffer_, "builtin (%s)", name); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "builtin (%s)", name); + return v8_buffer_.data(); } else { // It must be a direct access to one of the external values. if (directly_accessed_external_refs_.empty()) { @@ -192,8 +193,8 @@ const char* V8NameConverter::RootRelativeName(int offset) const { auto iter = directly_accessed_external_refs_.find(offset); if (iter != directly_accessed_external_refs_.end()) { - SNPrintF(v8_buffer_, "external value (%s)", iter->second); - return v8_buffer_.begin(); + base::SNPrintF(v8_buffer_, "external value (%s)", iter->second); + return v8_buffer_.data(); } return nullptr; } @@ -260,7 +261,8 @@ static void PrintRelocInfo(std::ostringstream& out, Isolate* isolate, out << " ;; external reference (" << reference_name << ")"; } else if (rmode == RelocInfo::JS_DISPATCH_HANDLE) { JSDispatchHandle dispatch_handle = relocinfo->js_dispatch_handle(); - out << " ;; js dispatch handle:0x" << std::hex << dispatch_handle; + out << " ;; js dispatch handle:0x" << std::hex << dispatch_handle + << std::dec; if (dispatch_handle != kNullJSDispatchHandle) { Tagged<Code> code = isolate->js_dispatch_table().GetCode(relocinfo->js_dispatch_handle()); @@ -301,7 +303,7 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, const V8NameConverter& converter, uint8_t* begin, uint8_t* end, Address current_pc, size_t range_limit) { CHECK(!code.is_null()); - v8::base::EmbeddedVector<char, 128> decode_buffer; + std::array<char, 128> decode_buffer; std::ostringstream out; uint8_t* pc = begin; disasm::Disassembler d(converter, @@ -332,7 +334,7 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, uint8_t* prev_pc = pc; bool decoding_constant_pool = constants > 0; if (decoding_constant_pool) { - SNPrintF( + base::SNPrintF( decode_buffer, "%08x constant", base::ReadUnalignedValue<int32_t>(reinterpret_cast<Address>(pc))); constants--; @@ -340,7 +342,7 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, } else { int num_const = d.ConstantPoolSizeAt(pc); if (num_const >= 0) { - SNPrintF( + base::SNPrintF( decode_buffer, "%08x constant pool begin (num_const = %d)", base::ReadUnalignedValue<int32_t>(reinterpret_cast<Address>(pc)), num_const); @@ -352,9 +354,9 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, // A raw pointer embedded in code stream. uint8_t* ptr = base::ReadUnalignedValue<uint8_t*>(reinterpret_cast<Address>(pc)); - SNPrintF(decode_buffer, "%08" V8PRIxPTR " jump table entry %4zu", - reinterpret_cast<intptr_t>(ptr), - static_cast<size_t>(ptr - begin)); + base::SNPrintF( + decode_buffer, "%08" V8PRIxPTR " jump table entry %4zu", + reinterpret_cast<intptr_t>(ptr), static_cast<size_t>(ptr - begin)); pc += sizeof(ptr); } else if (table_info_it && table_info_it->HasCurrent() && table_info_it->GetPCOffset() == @@ -362,7 +364,8 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, int32_t target_pc_offset = table_info_it->GetTarget(); static_assert(sizeof(target_pc_offset) == JumpTableInfoEntry::kTargetSize); - SNPrintF(decode_buffer, "jump table entry %08x", target_pc_offset); + base::SNPrintF(decode_buffer, "jump table entry %08x", + target_pc_offset); pc += JumpTableInfoEntry::kTargetSize; table_info_it->Next(); } else { @@ -422,10 +425,10 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, out << "\033[33;1m"; } out << static_cast<void*>(prev_pc) << " " << std::setw(4) << std::hex - << prev_pc - begin << " "; + << prev_pc - begin << std::dec << " "; // Instruction. - out << decode_buffer.begin(); + out << decode_buffer.data(); // Print all the reloc info for this instruction which are not comments. for (size_t i = 0; i < pcs.size(); i++) { diff --git a/deps/v8/src/diagnostics/gdb-jit.cc b/deps/v8/src/diagnostics/gdb-jit.cc index db0c48f3b9dd..f64887a10d05 100644 --- a/deps/v8/src/diagnostics/gdb-jit.cc +++ b/deps/v8/src/diagnostics/gdb-jit.cc @@ -28,7 +28,7 @@ #include "src/objects/code-inl.h" #include "src/objects/objects.h" #include "src/utils/ostreams.h" -#include "src/zone/zone-chunk-list.h" +#include "src/zone/zone-containers.h" namespace v8 { namespace internal { @@ -579,7 +579,7 @@ class MachO { cmd->filesize = w->position() - (uintptr_t)cmd->fileoff; } - ZoneChunkList<MachOSection*> sections_; + ZoneVector<MachOSection*> sections_; }; #endif // defined(__MACH_O) @@ -597,7 +597,7 @@ class ELF { WriteSections(w); } - ELFSection* SectionAt(uint32_t index) { return *sections_.Find(index); } + ELFSection* SectionAt(uint32_t index) { return sections_[index]; } size_t AddSection(ELFSection* section) { sections_.push_back(section); @@ -715,7 +715,7 @@ class ELF { } } - ZoneChunkList<ELFSection*> sections_; + ZoneVector<ELFSection*> sections_; }; class ELFSymbol { @@ -855,7 +855,7 @@ class ELFSymbolTable : public ELFSection { } private: - void WriteSymbolsList(const ZoneChunkList<ELFSymbol>* src, + void WriteSymbolsList(const ZoneVector<ELFSymbol>* src, Writer::Slot<ELFSymbol::SerializedLayout> dst, ELFStringTable* strtab) { int i = 0; @@ -864,8 +864,8 @@ class ELFSymbolTable : public ELFSection { } } - ZoneChunkList<ELFSymbol> locals_; - ZoneChunkList<ELFSymbol> globals_; + ZoneVector<ELFSymbol> locals_; + ZoneVector<ELFSymbol> globals_; }; #endif // defined(__ELF) diff --git a/deps/v8/src/diagnostics/ia32/disasm-ia32.cc b/deps/v8/src/diagnostics/ia32/disasm-ia32.cc index 92929b09177a..ee9c1b356e66 100644 --- a/deps/v8/src/diagnostics/ia32/disasm-ia32.cc +++ b/deps/v8/src/diagnostics/ia32/disasm-ia32.cc @@ -8,6 +8,8 @@ #if V8_TARGET_ARCH_IA32 +#include <array> + #include "src/base/compiler-specific.h" #include "src/base/strings.h" #include "src/codegen/ia32/fma-instr.h" @@ -235,7 +237,7 @@ class DisassemblerIA32 { uint8_t vex_byte1_; uint8_t vex_byte2_; // only for 3 bytes vex prefix InstructionTable* instruction_table_; - v8::base::EmbeddedVector<char, 128> tmp_buffer_; + std::array<char, 128> tmp_buffer_; unsigned int tmp_buffer_pos_; Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action_; @@ -380,7 +382,8 @@ class DisassemblerIA32 { }; void DisassemblerIA32::AppendToBuffer(const char* format, ...) { - v8::base::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; + v8::base::Vector<char> buf = + v8::base::VectorOf(tmp_buffer_) + tmp_buffer_pos_; va_list args; va_start(args, format); int result = v8::base::VSNPrintF(buf, format, args); @@ -2850,7 +2853,7 @@ int DisassemblerIA32::InstructionDecode(v8::base::Vector<char> out_buffer, outp += v8::base::SNPrintF(out_buffer + outp, " "); } - outp += v8::base::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin()); + outp += v8::base::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.data()); return instr_len; } @@ -2867,7 +2870,7 @@ static const char* const xmm_regs[8] = {"xmm0", "xmm1", "xmm2", "xmm3", const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -2911,7 +2914,7 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); @@ -2924,7 +2927,7 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, for (int i = 6 - (pc - prev_pc); i >= 0; i--) { fprintf(f, " "); } - fprintf(f, " %s\n", buffer.begin()); + fprintf(f, " %s\n", buffer.data()); } } diff --git a/deps/v8/src/diagnostics/loong64/disasm-loong64.cc b/deps/v8/src/diagnostics/loong64/disasm-loong64.cc index 53e21f9e367e..8e1436071ac9 100644 --- a/deps/v8/src/diagnostics/loong64/disasm-loong64.cc +++ b/deps/v8/src/diagnostics/loong64/disasm-loong64.cc @@ -9,6 +9,8 @@ #if V8_TARGET_ARCH_LOONG64 +#include <array> + #include "src/base/platform/platform.h" #include "src/base/strings.h" #include "src/base/vector.h" @@ -2588,7 +2590,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -2628,12 +2630,12 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), - *reinterpret_cast<int32_t*>(prev_pc), buffer.begin()); + *reinterpret_cast<int32_t*>(prev_pc), buffer.data()); } } diff --git a/deps/v8/src/diagnostics/mips64/disasm-mips64.cc b/deps/v8/src/diagnostics/mips64/disasm-mips64.cc index fa80ad2519f8..80f97ffefdbd 100644 --- a/deps/v8/src/diagnostics/mips64/disasm-mips64.cc +++ b/deps/v8/src/diagnostics/mips64/disasm-mips64.cc @@ -11,7 +11,7 @@ // NameConverter converter; // Disassembler d(converter); // for (uint8_t* pc = begin; pc < end;) { -// v8::base::EmbeddedVector<char, 256> buffer; +// std::array<char, 256> buffer; // uint8_t* prev_pc = pc; // pc += d.InstructionDecode(buffer, pc); // printf("%p %08x %s\n", @@ -29,6 +29,8 @@ #if V8_TARGET_ARCH_MIPS64 +#include <array> + #include "src/base/platform/platform.h" #include "src/base/strings.h" #include "src/base/vector.h" @@ -2968,7 +2970,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -3009,12 +3011,12 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), - *reinterpret_cast<int32_t*>(prev_pc), buffer.begin()); + *reinterpret_cast<int32_t*>(prev_pc), buffer.data()); } } diff --git a/deps/v8/src/diagnostics/objects-debug.cc b/deps/v8/src/diagnostics/objects-debug.cc index 01d15aff5cc5..41130f049eb7 100644 --- a/deps/v8/src/diagnostics/objects-debug.cc +++ b/deps/v8/src/diagnostics/objects-debug.cc @@ -39,7 +39,6 @@ #include "src/objects/instance-type.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" #include "src/objects/js-disposable-stack.h" #include "src/objects/js-proxy-inl.h" #include "src/objects/literal-objects.h" @@ -329,9 +328,13 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) { Cast<HashSeedWrapper>(this)->HashSeedWrapperVerify(isolate); break; -#define MAKE_VERIFY_CASE(Name, TYPE) \ - case TYPE: \ - TrustedCast<Name>(this)->Name##Verify(isolate); \ +#define MAKE_VERIFY_CASE(Name, TYPE) \ + case TYPE: \ + if constexpr (is_subtype_v<Name, TrustedObject>) { \ + TrustedCast<Name>(this)->Name##Verify(isolate); \ + } else { \ + Cast<Name>(this)->Name##Verify(isolate); \ + } \ break; HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST(MAKE_VERIFY_CASE) #undef MAKE_VERIFY_CASE @@ -508,9 +511,7 @@ void VerifyJSObjectElements(Isolate* isolate, const JSObject* object) { void VerifyJSObjectElements(Isolate* isolate, Tagged<JSObject> object) { // Only TypedArrays can have these specialized elements. if (IsJSTypedArray(object)) { - // TODO(bmeurer,v8:4153): Fix CreateTypedArray to either not instantiate - // the object or properly initialize it on errors during construction. - /* CHECK(object->HasTypedArrayOrRabGsabTypedArrayElements()); */ + CHECK(object->HasTypedArrayOrRabGsabTypedArrayElements()); return; } CHECK(!IsByteArray(object->elements())); @@ -628,7 +629,8 @@ void JSObject::JSObjectVerify(Isolate* isolate) { continue; } Tagged<Object> value = RawFastPropertyAt(index); - CHECK_IMPLIES(r.IsDouble(), IsHeapNumber(value)); + CHECK_IMPLIES(r.IsDouble(), + IsHeapNumber(value) || IsUninitializedHeapNumber(value)); if (IsUninitializedHole(value)) continue; CHECK_IMPLIES(r.IsSmi(), IsSmi(value)); CHECK_IMPLIES(r.IsHeapObject(), IsHeapObject(value)); @@ -709,7 +711,8 @@ void Map::MapVerify(Isolate* isolate) { } #if V8_ENABLE_WEBASSEMBLY - bool is_wasm_struct = InstanceTypeChecker::IsWasmStruct(instance_type()); + bool is_wasm_struct = InstanceTypeChecker::IsWasmStruct(instance_type()) || + InstanceTypeChecker::IsWasmCustomMap(instance_type()); #else constexpr bool is_wasm_struct = false; #endif // V8_ENABLE_WEBASSEMBLY @@ -797,7 +800,8 @@ void Map::MapVerify(Isolate* isolate) { #if V8_ENABLE_WEBASSEMBLY if (instance_type() == WASM_STRUCT_TYPE || - instance_type() == WASM_ARRAY_TYPE) { + instance_type() == WASM_ARRAY_TYPE || + instance_type() == WASM_CUSTOM_MAP_TYPE) { // Wasm structs are sometimes shared. In this case, the meta map of this map // has to be the context-free RO meta map. if (HeapLayout::InAnySharedSpace(this)) { @@ -815,7 +819,9 @@ void Map::MapVerify(Isolate* isolate) { // Note: for each static type that has a descriptor, there is also a // canonical RTT that does not have one (and is not used by any actual // objects). - if (types->has_descriptor(index) && IsWasmStruct(custom_descriptor())) { + if (types->has_descriptor(index) && + ((IsWasmStructMap(this) && IsWasmStruct(custom_descriptor())) || + map()->instance_type() == WASM_CUSTOM_MAP_TYPE)) { CHECK_GT(wasm_type_info()->supertypes_length(), subtyping_depth); CHECK_EQ(immediate_supertype_map(), wasm_type_info()->supertypes(subtyping_depth)); @@ -836,8 +842,7 @@ void Map::MapVerify(Isolate* isolate) { JSObject::GetEmbedderFieldCount(this) * kEmbedderDataSlotSize, inobject_fields_start_offset); - if (IsJSSharedStructMap(this) || IsJSSharedArrayMap(this) || - Is<JSAtomicsMutex>(this) || Is<JSAtomicsCondition>(this)) { + if (IsJSSharedStructMap(this) || IsJSSharedArrayMap(this)) { if (COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL) { // TODO(v8:14089): Verify what should be checked in this configuration // and again merge with the else-branch below. @@ -1125,12 +1130,11 @@ void ScopeInfo::ScopeInfoVerify(Isolate* isolate) { CHECK(Is<ScopeInfo>(this)); CHECK(parameter_count_.load().IsSmi()); CHECK(context_local_count_.load().IsSmi()); - CHECK(position_info_start_.load().IsSmi()); - CHECK(position_info_end_.load().IsSmi()); + CHECK(position_info_.start_.load().IsSmi()); + CHECK(position_info_.end_.load().IsSmi()); - const uint32_t flags = Flags(); - const bool is_module = - ScopeTypeBits::decode(flags) == ScopeType::MODULE_SCOPE; + const Flags flags = this->flags(); + const bool is_module = flags.scope_type() == ScopeType::MODULE_SCOPE; const int local_count = context_local_count(); const bool has_hashtable = local_count >= kScopeInfoMaxInlinedLocalNamesSize; @@ -1155,23 +1159,23 @@ void ScopeInfo::ScopeInfoVerify(Isolate* isolate) { USE(context_local_infos(i)); } - if (HasSavedClassVariableBit::decode(flags)) { + if (flags.has_saved_class_variable()) { Tagged<Union<Name, Smi>> v = saved_class_variable_info(); CHECK(IsSmi(v) || IsName(v)); } - if (FunctionVariableBits::decode(flags) != VariableAllocationInfo::NONE) { + if (flags.function_variable() != VariableAllocationInfo::NONE) { Tagged<Union<Smi, String>> name = function_variable_info_name(); CHECK(IsString(name) || IsZero(name)); USE(function_variable_info_context_or_stack_slot_index()); } - if (HasInferredFunctionNameBit::decode(flags)) { + if (flags.has_inferred_function_name()) { Tagged<Union<String, Undefined>> n = inferred_function_name(); CHECK(IsString(n) || IsUndefined(n)); } - if (HasOuterScopeInfoBit::decode(flags)) { + if (flags.has_outer_scope_info()) { CHECK(IsScopeInfo(outer_scope_info())); } @@ -1185,11 +1189,11 @@ void ScopeInfo::ScopeInfoVerify(Isolate* isolate) { } } - if (SloppyEvalCanExtendVarsBit::decode(flags)) { + if (flags.sloppy_eval_can_extend_vars()) { CHECK(IsDependentCode(dependent_code())); } - if (ScopeTypeBits::decode(flags) == ScopeType::FUNCTION_SCOPE) { + if (flags.scope_type() == ScopeType::FUNCTION_SCOPE) { USE(unused_parameter_bits()); } } @@ -1793,8 +1797,7 @@ void SharedFunctionInfo::SharedFunctionInfoVerify(LocalIsolate* isolate) { } if (ShouldVerifySharedFunctionInfoFunctionIndex(this)) { - int expected_map_index = - Context::FunctionMapIndex(language_mode(), kind(), HasSharedName()); + int expected_map_index = Context::FunctionMapIndex(kind(), HasSharedName()); CHECK_EQ(expected_map_index, function_map_index()); } @@ -1871,6 +1874,10 @@ void HashSeedWrapper::HashSeedWrapperVerify(Isolate* isolate) { CHECK(Is<HashSeedWrapper>(this)); } +void UninitializedHeapNumber::UninitializedHeapNumberVerify(Isolate* isolate) { + CHECK(Is<UninitializedHeapNumber>(this)); +} + void Oddball::OddballVerify(Isolate* isolate) { PrimitiveHeapObjectVerify(isolate); CHECK(Is<Oddball>(this)); @@ -1972,26 +1979,26 @@ void ExposedTrustedObject::ExposedTrustedObjectVerify(Isolate* isolate) { #if defined(V8_ENABLE_SANDBOX) // Check that the self indirect pointer is consistent, i.e. points back to // this object. - IndirectPointerTag tag; + TrustedPointerTag tag; if (IsPublished(isolate)) { InstanceType instance_type = map()->instance_type(); SharedFlag shared = SharedFlag(HeapLayout::InAnySharedSpace(this)); - tag = IndirectPointerTagFromInstanceType(instance_type, shared); + tag = TrustedPointerTagFromInstanceType(instance_type, shared); } else { - tag = kUnpublishedIndirectPointerTag; + tag = kUnpublishedTrustedPointerTag; } - // We can't use ReadIndirectPointerField here because the tag is not a + // We can't use ReadTrustedPointerField here because the tag is not a // compile-time constant. - IndirectPointerSlot slot = RawIndirectPointerField( - offsetof(ExposedTrustedObject, self_indirect_pointer_), tag); + TrustedPointerSlot slot = RawTrustedPointerField( + offsetof(ExposedTrustedObject, self_trusted_pointer_), tag); Tagged<Object> self = slot.load(isolate); CHECK_EQ(self, this); // If the object is in the read-only space, the self indirect pointer entry // must be in the read-only segment, and vice versa. - if (tag == kCodeIndirectPointerTag) { + if (tag == kCodeTrustedPointerTag) { TrustedPointerTable::Space* space = IsolateForSandbox(isolate).GetTrustedPointerTableSpaceFor( - kCodeIndirectPointerTag, slot.address()); + kCodeTrustedPointerTag, slot.address()); // During snapshot creation, the code pointer space of the read-only heap is // not marked as an internal read-only space. const bool is_space_read_only = @@ -2239,8 +2246,7 @@ void JSPluralRules::JSPluralRulesVerify(Isolate* isolate) { JSObjectVerify(isolate); CHECK(IsString(locale())); CHECK(IsSmi(flags_.load())); - CHECK(IsForeign(icu_plural_rules_.load())); - CHECK(IsForeign(icu_number_formatter_.load())); + CHECK(IsCppGCManagedBase(internal_.load())); } void JSRelativeTimeFormat::JSRelativeTimeFormatVerify(Isolate* isolate) { @@ -2337,18 +2343,6 @@ void JSSharedStruct::JSSharedStructVerify(Isolate* isolate) { } } -void JSAtomicsMutex::JSAtomicsMutexVerify(Isolate* isolate) { - CHECK(Is<JSAtomicsMutex>(this)); - CHECK(HeapLayout::InWritableSharedSpace(Tagged<HeapObject>(this))); - JSObjectVerify(isolate); -} - -void JSAtomicsCondition::JSAtomicsConditionVerify(Isolate* isolate) { - CHECK(Is<JSAtomicsCondition>(this)); - CHECK(HeapLayout::InAnySharedSpace(Tagged<HeapObject>(this))); - JSObjectVerify(isolate); -} - void JSDisposableStackBase::JSDisposableStackBaseVerify(Isolate* isolate) { JSObjectVerify(isolate); const int len = length(); @@ -2611,7 +2605,7 @@ void PromiseReaction::PromiseReactionVerify(Isolate* isolate) { void JSPromise::JSPromiseVerify(Isolate* isolate) { JSObjectVerify(isolate); - CHECK(flags_.load().IsSmi()); + CHECK(flags_.IsSmi()); if (status() == Promise::kPending) { CHECK(IsSmi(reactions()) || IsPromiseReaction(reactions())); } @@ -2709,10 +2703,10 @@ void SwissNameDictionary::SwissNameDictionaryVerify(Isolate* isolate, meta_table()->ByteArrayVerify(isolate); - int seen_deleted = 0; - int seen_present = 0; + uint32_t seen_deleted = 0; + uint32_t seen_present = 0; - for (int i = 0; i < Capacity(); i++) { + for (uint32_t i = 0; i < Capacity(); i++) { ctrl_t ctrl = GetCtrl(i); if (IsFull(ctrl) || slow_checks) { @@ -2751,18 +2745,18 @@ void SwissNameDictionary::SwissNameDictionaryVerify(Isolate* isolate, // Verify copy of first group at end (= after Capacity() slots) of control // table. - for (int i = 0; i < std::min(static_cast<int>(Group::kWidth), Capacity()); - ++i) { + for (uint32_t i = 0; + i < std::min(static_cast<uint32_t>(Group::kWidth), Capacity()); ++i) { CHECK_EQ(CtrlTable()[i], CtrlTable()[Capacity() + i]); } // If 2 * capacity is smaller than the capacity plus group width, the slots // after that must be empty. - for (int i = 2 * Capacity(); i < Capacity() + kGroupWidth; ++i) { + for (uint32_t i = 2 * Capacity(); i < Capacity() + kGroupWidth; ++i) { CHECK_EQ(Ctrl::kEmpty, CtrlTable()[i]); } - for (int enum_index = 0; enum_index < UsedCapacity(); ++enum_index) { - int entry = EntryForEnumerationIndex(enum_index); + for (uint32_t enum_index = 0; enum_index < UsedCapacity(); ++enum_index) { + uint32_t entry = EntryForEnumerationIndex(enum_index); CHECK_LT(entry, Capacity()); ctrl_t ctrl = GetCtrl(entry); @@ -2931,6 +2925,8 @@ void JSArrayBuffer::JSArrayBufferVerify(Isolate* isolate) { (v.IsWeak() && IsJSArrayBufferView(v.GetHeapObjectAssumeWeak())) || v.IsCleared()); } + CHECK_IMPLIES(is_resizable_by_js() && !was_detached(), + GetBackingStore() != nullptr); } void JSArrayBufferView::JSArrayBufferViewVerify(Isolate* isolate) { @@ -3070,7 +3066,7 @@ void SourceTextModuleInfoEntry::SourceTextModuleInfoEntryVerify( } void Module::ModuleVerify(Isolate* isolate) { - CHECK_EQ(status() == Module::kErrored, !IsTheHole(exception())); + CHECK_EQ(status() == Module::kEvaluatedError, !IsTheHole(exception())); CHECK(IsUndefined(module_namespace()) || IsCell(module_namespace())); if (IsCell(module_namespace())) { @@ -3084,7 +3080,7 @@ void Module::ModuleVerify(Isolate* isolate) { } } - if (!(status() == kErrored || status() == kEvaluating || + if (!(status() == kEvaluatedError || status() == kEvaluating || status() == kEvaluatingAsync || status() == kEvaluated)) { CHECK(IsUndefined(top_level_capability())); } @@ -3122,16 +3118,20 @@ void JSDeferredModuleNamespace::JSDeferredModuleNamespaceVerify( } void SourceTextModule::SourceTextModuleVerify(Isolate* isolate) { - if (status() == kErrored) { + if (status() == kEvaluatedError) { CHECK(IsSharedFunctionInfo(code())); - } else if (status() == kEvaluating || status() == kEvaluatingAsync || - status() == kEvaluated) { + CHECK_EQ(!IsTheHole(cycle_root()), + async_evaluation_ordinal() == kAsyncEvaluateDidFinish); + } else if (status() == kEvaluated) { + CHECK(IsJSGeneratorObject(code())); + CHECK(!HasAsyncEvaluationOrdinal()); + } else if (status() == kEvaluating || status() == kEvaluatingAsync) { CHECK(IsJSGeneratorObject(code())); } else { if (status() == kLinked) { CHECK(IsJSGeneratorObject(code())); } else if (status() == kLinking) { - CHECK(IsJSFunction(code()) || IsJSGeneratorObject(code())); + CHECK(IsJSFunction(code())); } else if (status() == kPreLinking) { CHECK(IsSharedFunctionInfo(code())); } else if (status() == kUnlinked) { @@ -3302,6 +3302,35 @@ void WasmTrustedInstanceData::WasmTrustedInstanceDataVerify(Isolate* isolate) { if (i == 0) CHECK_EQ(table, dispatch_table0()); } if (num_dispatch_tables == 0) CHECK_EQ(0, dispatch_table0()->length()); + + // Verify that shared memory atomic byte length addresses point into a + // BackingStore kept alive in shared_memory_backing_stores. + const wasm::WasmModule* mod = module(); + uint32_t num_memories = static_cast<uint32_t>(mod->memories.size()); + CHECK_EQ(num_memories, memory_objects()->ulength().value()); + CHECK_EQ(2 * num_memories, memory_bases_and_sizes()->length().value()); + bool has_shared_memory = std::any_of( + mod->memories.begin(), mod->memories.end(), + [](const wasm::WasmMemory& mem) { return mem.is_shared.value(); }); + CHECK_EQ(has_shared_memory ? num_memories : 0, + shared_memory_backing_stores()->ulength().value()); + for (uint32_t i = 0; i < num_memories; ++i) { + Address size_or_address = memory_bases_and_sizes()->get(2 * i + 1); + // For non-shared memories, or shared memories that have not been attached + // via `WasmMemoryObject::UseInInstance` yet, the backing store slot is 0. + if (!mod->memories[i].is_shared || size_or_address == 0) { + if (has_shared_memory) { + CHECK_EQ(Smi::zero(), shared_memory_backing_stores()->get(i)); + } + continue; + } + Tagged<Object> backing_store_obj = shared_memory_backing_stores()->get(i); + CHECK_EQ(size_or_address, + reinterpret_cast<Address>( + TrustedCast<TrustedManaged<BackingStore>>(backing_store_obj) + ->raw(DisallowGarbageCollection{}) + ->byte_length_address())); + } } void WasmDispatchTable::WasmDispatchTableVerify(Isolate* isolate) { @@ -3516,7 +3545,12 @@ void WasmStruct::WasmStructVerify(Isolate* isolate) { CHECK(Is<WasmStruct>(this)); } -void WasmCustomMap::WasmCustomMapVerify(Isolate* isolate) { UNIMPLEMENTED(); } +void WasmCustomMap::WasmCustomMapVerify(Isolate* isolate) { + CHECK(Is<WasmCustomMap>(this)); + Object::VerifyPointer(isolate, js_wrapper()); + Object::VerifyPointer(isolate, native_context_for_wrapper()); + MapVerify(isolate); +} void WasmCustomMapWrapper::WasmCustomMapWrapperVerify(Isolate* isolate) { CHECK(Is<WasmCustomMapWrapper>(this)); @@ -3685,6 +3719,23 @@ void Tuple2::Tuple2Verify(Isolate* isolate) { Object::VerifyPointer(isolate, value2_.load()); } +void ForInEnumeratorHolder::ForInEnumeratorHolderVerify(Isolate* isolate) { + CHECK(Is<Struct>(this)); + CHECK(Is<ForInEnumeratorHolder>(this)); + Object::VerifyPointer(isolate, enum_cache_map_.load()); + CHECK(IsMap(enum_cache_map_.load())); + Object::VerifyPointer(isolate, named_keys_.load()); + CHECK(IsFixedArray(named_keys_.load())); + Object::VerifyPointer(isolate, elements_length_.load()); + CHECK(IsSmi(elements_length_.load())); + Object::VerifyPointer(isolate, cache_length_.load()); + CHECK(IsSmi(cache_length_.load())); + CHECK_GE(Smi::ToInt(elements_length()), 0); + CHECK_GE(Smi::ToInt(cache_length()), Smi::ToInt(elements_length())); + CHECK_LE(Smi::ToInt(cache_length()) - Smi::ToInt(elements_length()), + static_cast<int>(named_keys()->ulength().value())); +} + void AliasedArgumentsEntry::AliasedArgumentsEntryVerify(Isolate* isolate) { CHECK(Is<Struct>(this)); CHECK(Is<AliasedArgumentsEntry>(this)); diff --git a/deps/v8/src/diagnostics/objects-printer.cc b/deps/v8/src/diagnostics/objects-printer.cc index 96fb166732a6..f89b106d8835 100644 --- a/deps/v8/src/diagnostics/objects-printer.cc +++ b/deps/v8/src/diagnostics/objects-printer.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> #include <iomanip> #include <memory> #include <optional> @@ -421,9 +422,13 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { case JS_MAP_VALUE_ITERATOR_TYPE: Cast<JSMapIterator>(this)->JSMapIteratorPrint(os); break; -#define MAKE_PRINT_CASE(Name, TYPE) \ - case TYPE: \ - TrustedCast<Name>(this)->Name##Print(os); \ +#define MAKE_PRINT_CASE(Name, TYPE) \ + case TYPE: \ + if constexpr (is_subtype_v<Name, TrustedObject>) { \ + TrustedCast<Name>(this)->Name##Print(os); \ + } else { \ + Cast<Name>(this)->Name##Print(os); \ + } \ break; HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST(MAKE_PRINT_CASE) #undef MAKE_PRINT_CASE @@ -501,11 +506,12 @@ void PrintByteArrayElements(std::ostream& os, const T* array) { uint32_t length = array->ulength().value(); uint32_t i = 0; while (i < length) { - os << " 0x" << std::setfill('0') << std::setw(4) << std::hex << i << ":"; + os << " 0x" << std::setfill('0') << std::setw(4) << std::hex << i + << std::dec << ":"; uint32_t line_end = std::min(i + 16, length); for (; i < line_end; ++i) { os << " " << std::setfill('0') << std::setw(2) << std::hex - << static_cast<int>(array->get(i)); + << static_cast<int>(array->get(i)) << std::dec; } os << "\n"; } @@ -1773,7 +1779,7 @@ void OrderedNameDictionary::OrderedNameDictionaryPrint(std::ostream& os) { void print_hex_byte(std::ostream& os, int value) { os << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex - << (value & 0xff) << std::setfill(' '); + << (value & 0xff) << std::dec << std::setfill(' '); } void SwissNameDictionary::SwissNameDictionaryPrint(std::ostream& os) { @@ -1786,7 +1792,7 @@ void SwissNameDictionary::SwissNameDictionaryPrint(std::ostream& os) { std::ios_base::fmtflags sav_flags = os.flags(); os << "\n - ctrl table (omitting buckets where key is hole value): {"; - for (int i = 0; i < this->Capacity() + kGroupWidth; i++) { + for (uint32_t i = 0; i < this->Capacity() + kGroupWidth; i++) { ctrl_t ctrl = CtrlTable()[i]; if (ctrl == Ctrl::kEmpty) continue; @@ -1812,14 +1818,15 @@ void SwissNameDictionary::SwissNameDictionaryPrint(std::ostream& os) { os << "\n }"; os << "\n - enumeration table: {"; - for (int enum_index = 0; enum_index < this->UsedCapacity(); enum_index++) { - int entry = EntryForEnumerationIndex(enum_index); + for (uint32_t enum_index = 0; enum_index < this->UsedCapacity(); + enum_index++) { + uint32_t entry = EntryForEnumerationIndex(enum_index); os << "\n " << std::setw(12) << std::dec << enum_index << ": " << entry; } os << "\n }"; os << "\n - data table (omitting slots where key is the hole): {"; - for (int bucket = 0; bucket < this->Capacity(); ++bucket) { + for (uint32_t bucket = 0; bucket < this->Capacity(); ++bucket) { Tagged<Object> k; if (!this->ToKey(GetReadOnlyRoots(), bucket, &k)) continue; @@ -2311,16 +2318,16 @@ void JSDate::JSDatePrint(std::ostream& os) { os << "\n - time = NaN\n"; } else { // TODO(svenpanne) Add some basic formatting to our streams. - auto buf = base::OwnedVector<char>::NewForOverwrite(100); - SNPrintF(buf.as_vector(), "\n - time = %s %04d/%02d/%02d %02d:%02d:%02d\n", - weekdays[IsSmi(weekday()) ? Smi::ToInt(weekday()) + 1 : 0], - IsSmi(year()) ? Smi::ToInt(year()) : -1, - IsSmi(month()) ? Smi::ToInt(month()) : -1, - IsSmi(day()) ? Smi::ToInt(day()) : -1, - IsSmi(hour()) ? Smi::ToInt(hour()) : -1, - IsSmi(min()) ? Smi::ToInt(min()) : -1, - IsSmi(sec()) ? Smi::ToInt(sec()) : -1); - os << buf.begin(); + std::array<char, 100> buf; + base::SNPrintF(buf, "\n - time = %s %04d/%02d/%02d %02d:%02d:%02d\n", + weekdays[IsSmi(weekday()) ? Smi::ToInt(weekday()) + 1 : 0], + IsSmi(year()) ? Smi::ToInt(year()) : -1, + IsSmi(month()) ? Smi::ToInt(month()) : -1, + IsSmi(day()) ? Smi::ToInt(day()) : -1, + IsSmi(hour()) ? Smi::ToInt(hour()) : -1, + IsSmi(min()) ? Smi::ToInt(min()) : -1, + IsSmi(sec()) ? Smi::ToInt(sec()) : -1); + os << buf.data(); } JSObjectPrintBody(os, this); } @@ -2407,25 +2414,6 @@ void JSSharedStruct::JSSharedStructPrint(std::ostream& os) { JSObjectPrintBody(os, this); } -void JSAtomicsMutex::JSAtomicsMutexPrint(std::ostream& os) { - JSObjectPrintHeader(os, this, "JSAtomicsMutex"); - if (HeapLayout::InWritableSharedSpace(Tagged<HeapObject>(this))) { - os << " (shared)"; - } - os << "\n - state: " << this->state(); - os << "\n - owner_thread_id: " << this->owner_thread_id(); - JSObjectPrintBody(os, this); -} - -void JSAtomicsCondition::JSAtomicsConditionPrint(std::ostream& os) { - JSObjectPrintHeader(os, this, "JSAtomicsCondition"); - if (HeapLayout::InWritableSharedSpace(Tagged<HeapObject>(this))) { - os << " (shared)"; - } - os << "\n - state: " << this->state(); - JSObjectPrintBody(os, this); -} - std::ostream& operator<<(std::ostream& os, DisposableStackState state) { switch (state) { case DisposableStackState::kPending: @@ -2814,7 +2802,13 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { os << "\n - untrusted_function_data: " << Brief(GetUntrustedData()); os << "\n - code (from function_data): "; Isolate* isolate; - if (GetIsolateFromHeapObject(Tagged<SharedFunctionInfo>(this), &isolate)) { + if (GetIsolateFromHeapObject(Tagged<SharedFunctionInfo>(this), &isolate) +#if V8_ENABLE_WEBASSEMBLY + // WasmFunctionData does not store a Code object; see + // SharedFunctionInfo::GetCode(). + && !HasWasmFunctionData(isolate) +#endif // V8_ENABLE_WEBASSEMBLY + ) { os << Brief(GetCode(isolate)); } else { os << kUnavailableString; @@ -3301,6 +3295,9 @@ void WasmStruct::WasmStructPrint(std::ostream& os) { } void WasmCustomMap::WasmCustomMapPrint(std::ostream& os) { PrintHeader(os, "WasmCustomMap"); + MapPrint(os); + os << "\n - JS wrapper: " << Brief(js_wrapper()); + os << "\n - native context: " << Brief(native_context_for_wrapper()); WasmStructPrintImpl(os, this, WasmCustomMap::kHeaderSize); } @@ -3316,7 +3313,7 @@ void WasmArray::WasmArrayPrint(std::ostream& os) { uint32_t len = length(); os << "\n - element type: " << element_type.name(); os << "\n - length: " << len; - Address data_ptr = ptr() + WasmArray::kHeaderSize - kHeapObjectTag; + Address data_ptr = ElementAddress(0); switch (element_type.kind()) { case wasm::kI32: PrintTypedArrayElements(os, reinterpret_cast<int32_t*>(data_ptr), len, @@ -3464,7 +3461,7 @@ void WasmTrustedInstanceData::WasmTrustedInstanceDataPrint(std::ostream& os) { PRINT_WASM_INSTANCE_FIELD(feedback_vectors, Brief); PRINT_WASM_INSTANCE_FIELD(well_known_imports, Brief); PRINT_WASM_INSTANCE_FIELD(memory0_start, to_void_ptr); - PRINT_WASM_INSTANCE_FIELD(memory0_size, +); + PRINT_WASM_INSTANCE_FIELD(memory0_size_or_address, to_void_ptr); #if V8_ENABLE_DRUMBRAKE PRINT_WASM_INSTANCE_FIELD(imported_function_indices, Brief); #endif // V8_ENABLE_DRUMBRAKE @@ -3474,6 +3471,7 @@ void WasmTrustedInstanceData::WasmTrustedInstanceDataPrint(std::ostream& os) { PRINT_WASM_INSTANCE_FIELD(hook_on_function_call_address, to_void_ptr); PRINT_WASM_INSTANCE_FIELD(tiering_budget_array, to_void_ptr); PRINT_WASM_INSTANCE_FIELD(memory_bases_and_sizes, Brief); + PRINT_WASM_INSTANCE_FIELD(shared_memory_backing_stores, Brief); PRINT_WASM_INSTANCE_FIELD(break_on_entry, static_cast<int>); os << "\n"; @@ -3671,6 +3669,13 @@ void PrototypeSharedClosureInfo::PrototypeSharedClosureInfoPrint( os << '\n'; } +void UninitializedHeapNumber::UninitializedHeapNumberPrint(std::ostream& os) { + PrintHeader(os, "UninitializedHeapNumber"); + os << "\n - value: "; + PrintDouble(os, value()); + os << '\n'; +} + void Tuple2::Tuple2Print(std::ostream& os) { this->PrintHeader(os, "Tuple2"); os << "\n - value1: " << Brief(this->value1()); @@ -3678,6 +3683,15 @@ void Tuple2::Tuple2Print(std::ostream& os) { os << '\n'; } +void ForInEnumeratorHolder::ForInEnumeratorHolderPrint(std::ostream& os) { + this->PrintHeader(os, "ForInEnumeratorHolder"); + os << "\n - enum_cache_map: " << Brief(this->enum_cache_map()); + os << "\n - named_keys: " << Brief(this->named_keys()); + os << "\n - elements_length: " << this->elements_length(); + os << "\n - cache_length: " << this->cache_length(); + os << '\n'; +} + void AliasedArgumentsEntry::AliasedArgumentsEntryPrint(std::ostream& os) { PrintHeader(os, "AliasedArgumentsEntry"); os << "\n - aliased_context_slot: " << aliased_context_slot(); @@ -4080,8 +4094,7 @@ void JSPluralRules::JSPluralRulesPrint(std::ostream& os) { JSObjectPrintHeader(os, this, "JSPluralRules"); os << "\n - locale: " << Brief(locale()); os << "\n - type: " << TypeAsString(Isolate::Current()); - os << "\n - icu plural rules: " << Brief(icu_plural_rules()); - os << "\n - icu_number_formatter: " << Brief(icu_number_formatter()); + os << "\n - internal: " << Brief(internal()); JSObjectPrintBody(os, this); } @@ -4149,7 +4162,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { os << "\n - empty\n"; return; } - int flags = Flags(); + const Flags flags = this->flags(); os << "\n - parameters: " << ParameterCount(); os << "\n - context locals : " << ContextLocalCount(); @@ -4168,7 +4181,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { os << "\n - language mode: " << language_mode(); if (is_declaration_scope()) os << "\n - declaration scope"; if (HasReceiver()) { - os << "\n - receiver: " << ReceiverVariableBits::decode(flags); + os << "\n - receiver: " << flags.receiver_variable(); } if (ClassScopeHasPrivateBrand()) os << "\n - class scope has private brand"; if (HasSavedClassVariable()) os << "\n - has saved class variable"; @@ -4176,7 +4189,7 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) { os << "\n - can only access fixed formal parameters"; } if (HasFunctionName()) { - os << "\n - function name(" << FunctionVariableBits::decode(flags) << "): "; + os << "\n - function name(" << flags.function_variable() << "): "; ShortPrint(FunctionName(), os); } if (HasSimpleParameters()) os << "\n - simple parameters"; @@ -4548,6 +4561,10 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { break; } + case UNINITIALIZED_HEAP_NUMBER_TYPE: + os << "<UninitializedHeapNumber>"; + break; + case SHARED_FUNCTION_INFO_TYPE: { Tagged<SharedFunctionInfo> shared = Cast<SharedFunctionInfo>(this); std::unique_ptr<char[]> debug_name = shared->DebugNameCStr(); @@ -4696,6 +4713,11 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { break; } #if V8_ENABLE_WEBASSEMBLY + case WASM_CUSTOM_MAP_TYPE: + os << "<WasmCustomMap [canonical type " + << Cast<WasmCustomMap>(this)->wasm_type_info()->type_index().index + << "]>"; + break; case WASM_DISPATCH_TABLE_TYPE: os << "<WasmDispatchTable[" << TrustedCast<WasmDispatchTable>(this)->length() << "]>"; @@ -4731,17 +4753,17 @@ void Name::NameShortPrint() { } // TODO(cbruni): remove once the new maptracer is in place. -int Name::NameShortPrint(base::Vector<char> str) { +int Name::NameShortPrint(std::span<char> str) { if (Is<String>(this)) { - return SNPrintF(str, "%s", Cast<String>(this)->ToCString().get()); + return base::SNPrintF(str, "%s", Cast<String>(this)->ToCString().get()); } else { DCHECK(Is<Symbol>(this)); Tagged<Symbol> s = Cast<Symbol>(this); if (IsUndefined(s->description())) { - return SNPrintF(str, "#<%s>", s->PrivateSymbolToName()); + return base::SNPrintF(str, "#<%s>", s->PrivateSymbolToName()); } else { - return SNPrintF(str, "<%s>", - Cast<String>(s->description())->ToCString().get()); + return base::SNPrintF(str, "<%s>", + Cast<String>(s->description())->ToCString().get()); } } } @@ -4768,17 +4790,21 @@ void Map::MapPrint(std::ostream& os) { bool is_meta_map = IsMetaMap(this); bool is_extended_map = Is<ExtendedMap>(this); #if V8_ENABLE_WEBASSEMBLY - bool is_wasm_map = IsWasmObjectMap(this); + bool is_wasm_map = IsAnyWasmObjectMap(this); + bool is_custom_map = IsWasmCustomMap(Tagged<HeapObject>(this)); #else constexpr bool is_wasm_map = false; + constexpr bool is_custom_map = false; #endif // V8_ENABLE_WEBASSEMBLY #ifdef OBJECT_PRINT PrintHeader(os, is_meta_map ? "MetaMap" : is_extended_map ? "ExtendedMap" + : is_custom_map ? "WasmCustomMap" : "Map"); #else os << (is_meta_map ? "MetaMap=" : is_extended_map ? "ExtendedMap=" + : is_custom_map ? "WasmCustomMap=" : "Map=") << reinterpret_cast<void*>(ptr()); #endif @@ -4975,8 +5001,6 @@ void TransitionsAccessor::PrintOneTransition(std::ostream& os, Tagged<Name> key, } else if (key == roots.elements_transition_symbol()) { os << "(transition to " << ElementsKindToString(target->elements_kind()) << ")"; - } else if (key == roots.strict_function_transition_symbol()) { - os << " (transition to strict function)"; } else if (key == roots.detached_symbol()) { os << " (transition to detached array buffer view)"; } else { @@ -5087,8 +5111,6 @@ void TransitionsAccessor::PrintTransitionTree( os << "to frozen"; } else if (key == roots.elements_transition_symbol()) { os << "to " << ElementsKindToString(target->elements_kind()); - } else if (key == roots.strict_function_transition_symbol()) { - os << "to strict function"; } else if (key == roots.detached_symbol()) { os << "to detached array buffer view"; } else { diff --git a/deps/v8/src/diagnostics/perf-jit.cc b/deps/v8/src/diagnostics/perf-jit.cc index 59b34a87746c..ebeb02fec216 100644 --- a/deps/v8/src/diagnostics/perf-jit.cc +++ b/deps/v8/src/diagnostics/perf-jit.cc @@ -41,6 +41,7 @@ #include "include/v8config.h" #include "src/base/platform/wrappers.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler.h" #include "src/codegen/source-position-table.h" #include "src/diagnostics/eh-frame.h" @@ -140,9 +141,9 @@ FILE* PerfJitLogger::perf_output_handle_ = nullptr; void PerfJitLogger::OpenJitDumpFile() { size_t bufferSize = strlen(v8_flags.perf_prof_path) + sizeof(kFilenameFormatString) + kFilenameBufferPadding; - auto perf_dump_name = base::OwnedVector<char>::NewForOverwrite(bufferSize); - int size = SNPrintF(perf_dump_name.as_vector(), kFilenameFormatString, - v8_flags.perf_prof_path.value(), process_id_); + auto perf_dump_name = base::UniqueArray<char>::NewForOverwrite(bufferSize); + int size = base::SNPrintF(perf_dump_name.as_span(), kFilenameFormatString, + v8_flags.perf_prof_path.value(), process_id_); CHECK_NE(size, -1); int fd = open(perf_dump_name.begin(), O_RDWR | O_TRUNC | O_CREAT | O_NOFOLLOW, diff --git a/deps/v8/src/diagnostics/ppc/disasm-ppc.cc b/deps/v8/src/diagnostics/ppc/disasm-ppc.cc index f65f7907f057..69c82e6541cf 100644 --- a/deps/v8/src/diagnostics/ppc/disasm-ppc.cc +++ b/deps/v8/src/diagnostics/ppc/disasm-ppc.cc @@ -11,7 +11,7 @@ // NameConverter converter; // Disassembler d(converter); // for (uint8_t* pc = begin; pc < end;) { -// v8::base::EmbeddedVector<char, 256> buffer; +// std::array<char, 256> buffer; // uint8_t* prev_pc = pc; // pc += d.InstructionDecode(buffer, pc); // printf("%p %08x %s\n", @@ -29,6 +29,8 @@ #if V8_TARGET_ARCH_PPC64 +#include <array> + #include "src/base/platform/platform.h" #include "src/base/strings.h" #include "src/base/vector.h" @@ -1921,7 +1923,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -1962,12 +1964,12 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), - *reinterpret_cast<int32_t*>(prev_pc), buffer.begin()); + *reinterpret_cast<int32_t*>(prev_pc), buffer.data()); } } diff --git a/deps/v8/src/diagnostics/riscv/disasm-riscv.cc b/deps/v8/src/diagnostics/riscv/disasm-riscv.cc index 0f133e4d0b80..6b5f7897cfe4 100644 --- a/deps/v8/src/diagnostics/riscv/disasm-riscv.cc +++ b/deps/v8/src/diagnostics/riscv/disasm-riscv.cc @@ -11,7 +11,7 @@ // NameConverter converter; // Disassembler d(converter); // for (uint8_t* pc = begin; pc < end;) { -// v8::base::EmbeddedVector<char, 256> buffer; +// std::array<char, 256> buffer; // uint8_t* prev_pc = pc; // pc += d.InstructionDecode(buffer, pc); // printf("%p %08x %s\n", @@ -27,6 +27,7 @@ #include <stdio.h> #include <string.h> +#include <array> #include <cmath> #include "src/base/platform/platform.h" @@ -3507,7 +3508,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -3551,12 +3552,12 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), - *reinterpret_cast<uint32_t*>(prev_pc), buffer.begin()); + *reinterpret_cast<uint32_t*>(prev_pc), buffer.data()); } } diff --git a/deps/v8/src/diagnostics/s390/disasm-s390.cc b/deps/v8/src/diagnostics/s390/disasm-s390.cc index 0b5c58f04444..25c3e43c0b0f 100644 --- a/deps/v8/src/diagnostics/s390/disasm-s390.cc +++ b/deps/v8/src/diagnostics/s390/disasm-s390.cc @@ -11,7 +11,7 @@ // NameConverter converter; // Disassembler d(converter); // for (uint8_t* pc = begin; pc < end;) { -// v8::base::EmbeddedVector<char, 256> buffer; +// std::array<char, 256> buffer; // uint8_t* prev_pc = pc; // pc += d.InstructionDecode(buffer, pc); // printf("%p %08x %s\n", @@ -29,6 +29,8 @@ #if V8_TARGET_ARCH_S390X +#include <array> + #include "src/base/platform/platform.h" #include "src/base/strings.h" #include "src/base/vector.h" @@ -1043,7 +1045,7 @@ namespace disasm { const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -1086,12 +1088,12 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), - *reinterpret_cast<int32_t*>(prev_pc), buffer.begin()); + *reinterpret_cast<int32_t*>(prev_pc), buffer.data()); } } diff --git a/deps/v8/src/diagnostics/x64/disasm-x64.cc b/deps/v8/src/diagnostics/x64/disasm-x64.cc index 1306d60cbcba..8353ac8878ff 100644 --- a/deps/v8/src/diagnostics/x64/disasm-x64.cc +++ b/deps/v8/src/diagnostics/x64/disasm-x64.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> #include <cassert> #include <cinttypes> #include <cstdarg> @@ -322,7 +323,7 @@ class DisassemblerX64 { }; const NameConverter& converter_; - v8::base::EmbeddedVector<char, 128> tmp_buffer_; + std::array<char, 128> tmp_buffer_; unsigned int tmp_buffer_pos_ = 0; bool abort_on_unimplemented_; // Prefixes parsed. @@ -431,6 +432,8 @@ class DisassemblerX64 { bool evex_map2() const { return (evex_byte1_ & 0x07) == 2; } bool evex_map3() const { return (evex_byte1_ & 0x07) == 3; } bool evex_map4() const { return (evex_byte1_ & 0x07) == 4; } + bool evex_map5() const { return (evex_byte1_ & 0x07) == 5; } + bool evex_map6() const { return (evex_byte1_ & 0x07) == 6; } bool evex_w() const { return (evex_byte2_ & 0x80) != 0; } int evex_pp() const { return evex_byte2_ & 0x3; } @@ -656,7 +659,8 @@ class DisassemblerX64 { }; void DisassemblerX64::AppendToBuffer(const char* format, ...) { - v8::base::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; + v8::base::Vector<char> buf = + v8::base::VectorOf(tmp_buffer_) + tmp_buffer_pos_; va_list args; va_start(args, format); int result = v8::base::VSNPrintF(buf, format, args); @@ -1076,6 +1080,28 @@ int DisassemblerX64::AVXVectorInstruction(uint8_t* data) { if (evex_w()) synth_rex |= 0x08; setRex(synth_rex); } + if (is_evex() && (evex_map5() || evex_map6())) { + // Decode only the unmasked, non-broadcast XMM/YMM FP16 forms we emit. + // Require EVEX.z, L', b and aaa to be zero; L and V' may be set. + const char* mnemonic = nullptr; + if (evex_map5() && evex_pp_none()) { + if (opcode == 0x58) mnemonic = "vaddph"; + if (opcode == 0x5c) mnemonic = "vsubph"; + } else if (evex_map6() && evex_pp_66()) { + if (opcode == 0xa8) mnemonic = "vfmadd213ph"; + if (opcode == 0xac) mnemonic = "vfnmadd213ph"; + } + if (mnemonic != nullptr && !evex_w() && (evex_byte3_ & 0xd7) == 0) { + int mod, regop, rm; + get_modrm(*current, &mod, ®op, &rm); + AppendToBuffer("%s %s,%s,", mnemonic, NameOfAVXRegister(regop), + NameOfAVXRegister(get_vreg())); + current += PrintRightEVEXOperand(current, TupleType::kFull); + } else { + UnimplementedInstruction(); + } + return static_cast<int>(current - data); + } if (simd_prefix_66() && leading_0f38()) { int mod, regop, rm, vvvv = get_vreg(); get_modrm(*current, &mod, ®op, &rm); @@ -2456,6 +2482,9 @@ int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) { } else if (opcode == 0xAE && (data[2] & 0xF8) == 0xE8) { AppendToBuffer("lfence"); current = data + 3; + } else if (opcode == 0xAE && regop == 3 && mod != 3) { + AppendToBuffer("stmxcsr "); + current += PrintRightOperand(current); // clang-format off #define SSE_DISASM_CASE(instruction, unused, code) \ } else if (opcode == 0x##code) { \ @@ -3565,7 +3594,7 @@ int DisassemblerX64::InstructionDecode(v8::base::Vector<char> out_buffer, outp += v8::base::SNPrintF(out_buffer + outp, " "); } - outp += v8::base::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin()); + outp += v8::base::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.data()); return instr_len; } @@ -3601,7 +3630,7 @@ static_assert(arraysize(zmm_regs) == 32); const char* NameConverter::NameOfAddress(uint8_t* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); - return tmp_buffer_.begin(); + return tmp_buffer_.data(); } const char* NameConverter::NameOfConstant(uint8_t* addr) const { @@ -3656,7 +3685,7 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, NameConverter converter; Disassembler d(converter, unimplemented_action); for (uint8_t* pc = begin; pc < end;) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; uint8_t* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); @@ -3669,7 +3698,7 @@ void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end, for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) { fprintf(f, " "); } - fprintf(f, " %s\n", buffer.begin()); + fprintf(f, " %s\n", buffer.data()); } } diff --git a/deps/v8/src/dumpling/object-dumping.cc b/deps/v8/src/dumpling/object-dumping.cc index 6b479bc0994b..a2c1d837d3c9 100644 --- a/deps/v8/src/dumpling/object-dumping.cc +++ b/deps/v8/src/dumpling/object-dumping.cc @@ -5,6 +5,7 @@ #include "src/dumpling/object-dumping.h" #include <algorithm> +#include <array> #include <iostream> #include <vector> @@ -124,9 +125,9 @@ void JSObjectFuzzingPrintInternalIndexRange(Tagged<JSObject> obj, if (IsString(*key_name)) { FuzzingStringShortPrint(Cast<String>(*key_name), accumulator); } else { - auto name_buffer = base::OwnedVector<char>::NewForOverwrite(100); - key_name->NameShortPrint(name_buffer.as_vector()); - PrintSanitizedCString(name_buffer.begin(), accumulator); + std::array<char, 100> name_buffer; + key_name->NameShortPrint(name_buffer); + PrintSanitizedCString(name_buffer.data(), accumulator); } std::stringstream attributes_stream; @@ -513,6 +514,19 @@ void HeapObjectFuzzingPrint(Tagged<HeapObject> obj, int depth, os << "<FeedbackVector[" << Cast<FeedbackVector>(obj)->length() << "]>"; break; } + case UNINITIALIZED_HEAP_NUMBER_TYPE: + // Optimized code materializes the same uninitialized field as the + // uninitialized_value hole, so print it the same way. + os << "<uninitialized_value>"; + break; +#if V8_ENABLE_WEBASSEMBLY + case WASM_STRUCT_TYPE: + os << "<WasmStruct>"; + break; + case WASM_ARRAY_TYPE: + os << "<WasmArray>"; + break; +#endif // V8_ENABLE_WEBASSEMBLY default: // TODO(mdanylo): add more cases after a test run with Fuzzilli FATAL("Unexpected value in switch: %s\n", diff --git a/deps/v8/src/execution/arguments.h b/deps/v8/src/execution/arguments.h index bfd2265e5e81..927ebb622a60 100644 --- a/deps/v8/src/execution/arguments.h +++ b/deps/v8/src/execution/arguments.h @@ -75,9 +75,23 @@ class Arguments { // Corruption of certain heap objects (see e.g. crbug.com/1507223) can lead // to OOB arguments access, and therefore OOB stack access. This SBXCHECK // defends against that. - // Note: "LE" is intentional: it's okay to compute the address of the - // first nonexistent entry. + SBXCHECK_LT(static_cast<uint32_t>(index), static_cast<uint32_t>(length_)); + return address_of_arg_at_unchecked(index); + } + + // Allowed for callers that only compute a past-the-end address and do not + // dereference it (e.g. BuiltinArguments::address_of_first_argument). + V8_INLINE Address* address_of_arg_at_or_end(int index) const { SBXCHECK_LE(static_cast<uint32_t>(index), static_cast<uint32_t>(length_)); + return address_of_arg_at_unchecked(index); + } + + // Get the total number of arguments including the receiver. + V8_INLINE int length() const { return static_cast<int>(length_); } + V8_INLINE uint32_t ulength() const { return static_cast<uint32_t>(length_); } + + private: + V8_INLINE Address* address_of_arg_at_unchecked(int index) const { uintptr_t offset = index * kSystemPointerSize; if (arguments_type == ArgumentsType::kJS) { offset = (length_ - index - 1) * kSystemPointerSize; @@ -86,11 +100,6 @@ class Arguments { offset); } - // Get the total number of arguments including the receiver. - V8_INLINE int length() const { return static_cast<int>(length_); } - V8_INLINE uint32_t ulength() const { return static_cast<uint32_t>(length_); } - - private: intptr_t length_; Address* arguments_; }; diff --git a/deps/v8/src/execution/arm/simulator-arm.cc b/deps/v8/src/execution/arm/simulator-arm.cc index 2ca91992b121..1eb9ac974938 100644 --- a/deps/v8/src/execution/arm/simulator-arm.cc +++ b/deps/v8/src/execution/arm/simulator-arm.cc @@ -11,6 +11,8 @@ #include <stdarg.h> #include <stdlib.h> +#include <array> +#include <bit> #include <cmath> #include "src/base/bits.h" @@ -203,10 +205,10 @@ void ArmDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.begin()); + PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.data()); last_pc = sim_->get_pc(); } ArrayUniquePtr<char> line(ReadLine("sim> ")); @@ -377,7 +379,7 @@ bool ArmDebugger::ExecDebugCommand(ArrayUniquePtr<char> line_ptr) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* prev = nullptr; uint8_t* cur = nullptr; @@ -418,7 +420,7 @@ bool ArmDebugger::ExecDebugCommand(ArrayUniquePtr<char> line_ptr) { prev = cur; cur += dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev), - buffer.begin()); + buffer.data()); } } else if (strcmp(cmd, "gdb") == 0) { PrintF("relinquishing control to gdb\n"); @@ -5673,7 +5675,7 @@ void Simulator::DecodeAdvancedSIMDDataProcessing(Instruction* instr) { int imm3H_L = imm3H << 1 | l; int imm7 = instr->Bits(21, 16); imm7 += (l << 6); - int size = base::bits::RoundDownToPowerOfTwo32(imm7); + int size = std::bit_floor<uint32_t>(imm7); NeonSize ns = static_cast<NeonSize>(base::bits::WhichPowerOfTwo(size >> 3)); @@ -6253,10 +6255,10 @@ void Simulator::InstructionDecode(Instruction* instr) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr)); PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(instr), - buffer.begin()); + buffer.data()); } if (instr->ConditionField() == kSpecialCondition) { DecodeSpecialCondition(instr); diff --git a/deps/v8/src/execution/arm64/simulator-arm64.cc b/deps/v8/src/execution/arm64/simulator-arm64.cc index 1ce33ee118f8..955522f69292 100644 --- a/deps/v8/src/execution/arm64/simulator-arm64.cc +++ b/deps/v8/src/execution/arm64/simulator-arm64.cc @@ -2273,6 +2273,10 @@ void Simulator::VisitLoadStoreUnscaledOffset(Instruction* instr) { LoadStoreHelper(instr, instr->ImmLS(), Offset); } +void Simulator::VisitLoadStoreRCpcUnscaledOffset(Instruction* instr) { + LoadStoreHelper(instr, instr->ImmLS(), Offset, AcquireRelease(true)); +} + void Simulator::VisitLoadStorePreIndex(Instruction* instr) { LoadStoreHelper(instr, instr->ImmLS(), PreIndex); } @@ -2291,7 +2295,9 @@ void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) { } void Simulator::LoadStoreHelper(Instruction* instr, int64_t offset, - AddrMode addrmode) { + AddrMode addrmode, + AcquireRelease acquire_release) { + DCHECK_IMPLIES(acquire_release, addrmode == Offset); unsigned srcdst = instr->Rt(); unsigned addr_reg = instr->Rn(); uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); @@ -2331,73 +2337,83 @@ void Simulator::LoadStoreHelper(Instruction* instr, int64_t offset, // Use _no_log variants to suppress the register trace (LOG_REGS, // LOG_VREGS). We will print a more detailed log. case LDRB_w: - set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); + set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address, acquire_release)); break; case LDRH_w: - set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); + set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address, acquire_release)); break; case LDR_w: - set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); + set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address, acquire_release)); break; case LDR_x: - set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); + set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address, acquire_release)); break; case LDRSB_w: - set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); + set_wreg_no_log(srcdst, MemoryRead<int8_t>(address, acquire_release)); break; case LDRSH_w: - set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); + set_wreg_no_log(srcdst, MemoryRead<int16_t>(address, acquire_release)); break; case LDRSB_x: - set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); + set_xreg_no_log(srcdst, MemoryRead<int8_t>(address, acquire_release)); break; case LDRSH_x: - set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); + set_xreg_no_log(srcdst, MemoryRead<int16_t>(address, acquire_release)); break; case LDRSW_x: - set_xreg_no_log(srcdst, MemoryRead<int32_t>(address)); + set_xreg_no_log(srcdst, MemoryRead<int32_t>(address, acquire_release)); break; case LDR_b: + DCHECK(!acquire_release); set_breg_no_log(srcdst, MemoryRead<uint8_t>(address)); break; case LDR_h: + DCHECK(!acquire_release); set_hreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break; case LDR_s: + DCHECK(!acquire_release); set_sreg_no_log(srcdst, MemoryRead<float>(address)); break; case LDR_d: + DCHECK(!acquire_release); set_dreg_no_log(srcdst, MemoryRead<double>(address)); break; case LDR_q: + DCHECK(!acquire_release); set_qreg_no_log(srcdst, MemoryRead<qreg_t>(address)); break; case STRB_w: - MemoryWrite<uint8_t>(address, wreg(srcdst)); + MemoryWrite<uint8_t>(address, wreg(srcdst), acquire_release); break; case STRH_w: - MemoryWrite<uint16_t>(address, wreg(srcdst)); + MemoryWrite<uint16_t>(address, wreg(srcdst), acquire_release); break; case STR_w: - MemoryWrite<uint32_t>(address, wreg(srcdst)); + MemoryWrite<uint32_t>(address, wreg(srcdst), acquire_release); break; case STR_x: - MemoryWrite<uint64_t>(address, xreg(srcdst)); + MemoryWrite<uint64_t>(address, xreg(srcdst), acquire_release); break; case STR_b: + DCHECK(!acquire_release); MemoryWrite<uint8_t>(address, breg(srcdst)); break; case STR_h: + DCHECK(!acquire_release); MemoryWrite<uint16_t>(address, hreg(srcdst)); break; case STR_s: + DCHECK(!acquire_release); MemoryWrite<float>(address, sreg(srcdst)); break; case STR_d: + DCHECK(!acquire_release); MemoryWrite<double>(address, dreg(srcdst)); break; case STR_q: + DCHECK(!acquire_release); MemoryWrite<qreg_t>(address, qreg(srcdst)); break; @@ -6983,6 +6999,22 @@ void Simulator::VisitSVEBitPerm(Instruction* instr) { } } +void Simulator::VisitSVE2Mul(Instruction* instr) { + SimVRegister& rd = vreg(instr->Rd()); + SimVRegister& rm = vreg(instr->Rm()); + SimVRegister& rn = vreg(instr->Rn()); + SVESizeDecoder ssd(instr); + VectorFormat vf = ssd.GetVectorFormat(); + + DCHECK_EQ(instr->Mask(SVE2MulFMask), SVE2MulFixed); + + if (instr->Mask(SVE2MulMask) == SVE2_MUL) { + mul(vf, rd, rn, rm); + } else { + UNIMPLEMENTED(); + } +} + void Simulator::DoSwitchStackLimit(Instruction* instr) { const int64_t stack_limit = xreg(16); // stack_limit represents js limit and adjusted by extra runaway gap. diff --git a/deps/v8/src/execution/arm64/simulator-arm64.h b/deps/v8/src/execution/arm64/simulator-arm64.h index 72e1e35aec52..5e42e90bd65a 100644 --- a/deps/v8/src/execution/arm64/simulator-arm64.h +++ b/deps/v8/src/execution/arm64/simulator-arm64.h @@ -12,9 +12,11 @@ #include <stdarg.h> +#include <atomic> #include <vector> #include "src/base/compiler-specific.h" +#include "src/base/strong-alias.h" #include "src/codegen/arm64/assembler-arm64.h" #include "src/codegen/arm64/decoder-arm64.h" #include "src/codegen/assembler.h" @@ -251,6 +253,16 @@ class SimMemory { return value; } + template <typename T, typename A> + requires(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || + sizeof(T) == 8) + static T AcquireRead(A address) { + address = AddressUntag(address); + DCHECK(IsAligned(base::bit_cast<uintptr_t>(address), sizeof(T))); + return std::atomic_ref<T>(*reinterpret_cast<T*>(address)) + .load(std::memory_order_acquire); + } + template <typename T, typename A> requires(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8 || sizeof(T) == 16) @@ -258,6 +270,16 @@ class SimMemory { address = AddressUntag(address); memcpy(reinterpret_cast<char*>(address), &value, sizeof(value)); } + + template <typename T, typename A> + requires(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || + sizeof(T) == 8) + static void ReleaseWrite(A address, T value) { + address = AddressUntag(address); + DCHECK(IsAligned(base::bit_cast<uintptr_t>(address), sizeof(T))); + std::atomic_ref<T>(*reinterpret_cast<T*>(address)) + .store(value, std::memory_order_release); + } }; // The proper way to initialize a simulated system register (such as NZCV) is as @@ -1570,7 +1592,9 @@ class Simulator : public DecoderVisitor, public SimulatorBase { void LogicalHelper(Instruction* instr, T op2); template <typename T> void ConditionalCompareHelper(Instruction* instr, T op2); - void LoadStoreHelper(Instruction* instr, int64_t offset, AddrMode addrmode); + using AcquireRelease = base::StrongAlias<struct AcquireReleaseTag, bool>; + void LoadStoreHelper(Instruction* instr, int64_t offset, AddrMode addrmode, + AcquireRelease acquire_release = AcquireRelease(false)); void LoadStorePairHelper(Instruction* instr, AddrMode addrmode); template <typename T> void CompareAndSwapHelper(const Instruction* instr); @@ -1609,6 +1633,14 @@ class Simulator : public DecoderVisitor, public SimulatorBase { return SimMemory::Read<T>(address); } + template <typename T, typename A> + requires(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || + sizeof(T) == 8) + T MemoryRead(A address, AcquireRelease acquire_release) { + return acquire_release ? SimMemory::AcquireRead<T>(address) + : SimMemory::Read<T>(address); + } + // Memory write helpers. template <typename T, typename A> requires(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || @@ -1617,6 +1649,17 @@ class Simulator : public DecoderVisitor, public SimulatorBase { SimMemory::Write<T>(address, value); } + template <typename T, typename A> + requires(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || + sizeof(T) == 8) + void MemoryWrite(A address, T value, AcquireRelease acquire_release) { + if (acquire_release) { + SimMemory::ReleaseWrite<T>(address, value); + } else { + SimMemory::Write<T>(address, value); + } + } + template <typename T> T ShiftOperand(T value, Shift shift_type, unsigned amount); template <typename T> diff --git a/deps/v8/src/execution/arm64/simulator-logic-arm64.cc b/deps/v8/src/execution/arm64/simulator-logic-arm64.cc index a0a878fa0a39..3ab34e8e9d1a 100644 --- a/deps/v8/src/execution/arm64/simulator-logic-arm64.cc +++ b/deps/v8/src/execution/arm64/simulator-logic-arm64.cc @@ -24,6 +24,8 @@ class half { uint16_t bits() const { return bits_; } + half operator-() const { return half(static_cast<uint16_t>(bits_ ^ 0x8000)); } + private: uint16_t bits_; }; @@ -145,13 +147,9 @@ float Simulator::UFixedToFloat(uint64_t src, int fbits, FPRounding round) { } float16 Simulator::FixedToFloat16(int64_t src, int fbits, FPRounding round) { - if (src >= 0) { - return UFixedToFloat16(src, fbits, round); - } else if (src == INT64_MIN) { - return -UFixedToFloat16(src, fbits, round); - } else { - return -UFixedToFloat16(-src, fbits, round); - } + constexpr float16 kSignMask = 0x8000; + if (src >= 0) return UFixedToFloat16(src, fbits, round); + return UFixedToFloat16(-static_cast<uint64_t>(src), fbits, round) | kSignMask; } float16 Simulator::UFixedToFloat16(uint64_t src, int fbits, FPRounding round) { @@ -4361,6 +4359,7 @@ LogicVRegister Simulator::frecpx(VectorFormat vform, LogicVRegister dst, LogicVRegister Simulator::scvtf(VectorFormat vform, LogicVRegister dst, const LogicVRegister& src, int fbits, FPRounding round) { + dst.ClearForWrite(vform); for (int i = 0; i < LaneCountFromFormat(vform); i++) { if (LaneSizeInBytesFromFormat(vform) == kHRegSize) { float16 result = FixedToFloat16(src.Int(kFormatH, i), fbits, round); @@ -4380,6 +4379,7 @@ LogicVRegister Simulator::scvtf(VectorFormat vform, LogicVRegister dst, LogicVRegister Simulator::ucvtf(VectorFormat vform, LogicVRegister dst, const LogicVRegister& src, int fbits, FPRounding round) { + dst.ClearForWrite(vform); for (int i = 0; i < LaneCountFromFormat(vform); i++) { if (LaneSizeInBytesFromFormat(vform) == kHRegSize) { float16 result = UFixedToFloat16(src.Uint(kFormatH, i), fbits, round); diff --git a/deps/v8/src/execution/frame-constants.h b/deps/v8/src/execution/frame-constants.h index 3dbf91d6fe46..9ed09ae7d392 100644 --- a/deps/v8/src/execution/frame-constants.h +++ b/deps/v8/src/execution/frame-constants.h @@ -501,13 +501,15 @@ class BuiltinExitFrameConstants : public ExitFrameConstants { static constexpr int kTargetIndex = 1; static constexpr int kArgcIndex = 2; - // This padding is required only on arm64 to keep the SP 16-byte aligned. + // This padding is required on arm64 (and x64 with 16-byte stack alignment) to + // keep the SP 16-byte aligned. static constexpr int kOptionalPaddingIndex = 3; -#if V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || \ + (V8_TARGET_ARCH_X64 && V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) static constexpr int kNumExtraArgs = 4; #else static constexpr int kNumExtraArgs = 3; -#endif // V8_TARGET_ARCH_ARM64 +#endif static constexpr int kNumExtraArgsWithReceiver = kNumExtraArgs + 1; diff --git a/deps/v8/src/execution/frames-inl.h b/deps/v8/src/execution/frames-inl.h index f7277bac84bb..068ccaad85ce 100644 --- a/deps/v8/src/execution/frames-inl.h +++ b/deps/v8/src/execution/frames-inl.h @@ -385,10 +385,6 @@ inline BuiltinFrame::BuiltinFrame(StackFrameIteratorBase* iterator) inline WasmFrame::WasmFrame(StackFrameIteratorBase* iterator) : TypedFrame(iterator) {} -inline WasmSegmentStartFrame::WasmSegmentStartFrame( - StackFrameIteratorBase* iterator) - : WasmFrame(iterator) {} - inline WasmExitFrame::WasmExitFrame(StackFrameIteratorBase* iterator) : WasmFrame(iterator) {} @@ -500,7 +496,6 @@ inline bool StackFrameIteratorForProfiler::IsValidFrameType( #if V8_ENABLE_WEBASSEMBLY type == StackFrame::WASM || type == StackFrame::WASM_TO_JS || type == StackFrame::JS_TO_WASM || - type == StackFrame::WASM_SEGMENT_START || #if V8_ENABLE_DRUMBRAKE type == StackFrame::WASM_INTERPRETER_ENTRY || #endif // V8_ENABLE_DRUMBRAKE diff --git a/deps/v8/src/execution/frames.cc b/deps/v8/src/execution/frames.cc index 12cadd232723..6976158cf266 100644 --- a/deps/v8/src/execution/frames.cc +++ b/deps/v8/src/execution/frames.cc @@ -13,6 +13,7 @@ #include "src/api/api-natives.h" #include "src/base/bits.h" #include "src/base/strong-alias.h" +#include "src/builtins/builtins-inl.h" #include "src/codegen/interface-descriptors-inl.h" #include "src/codegen/linkage-location.h" #include "src/codegen/maglev-safepoint-table.h" @@ -32,6 +33,7 @@ #include "src/objects/smi.h" #include "src/objects/visitors.h" #include "src/roots/roots.h" +#include "src/sandbox/check.h" #include "src/snapshot/embedded/embedded-data-inl.h" #include "src/strings/string-stream.h" @@ -161,7 +163,15 @@ class StackHandlerIterator { // ------------------------------------------------------------------------- StackFrameIteratorBase::StackFrameIteratorBase(Isolate* isolate) - : isolate_(isolate), frame_(nullptr), handler_(nullptr) {} + : isolate_(isolate), + frame_(nullptr), + handler_(nullptr) +#if V8_ENABLE_WEBASSEMBLY + , + wasm_stack_(isolate->isolate_data()->active_stack()) +#endif +{ +} StackFrameIterator::StackFrameIterator(Isolate* isolate) : StackFrameIterator(isolate, isolate->thread_local_top()) {} @@ -461,11 +471,18 @@ std::optional<bool> IsInterpreterFramePc(Isolate* isolate, Address pc, } else if (!isolate->heap()->InSpaceSlow(pc, CODE_SPACE)) { return false; } - if (!ThreadIsolation::CanLookupStartOfJitAllocationAt(pc)) { + std::optional<Address> istream_address = + ThreadIsolation::TryLookupStartOfJitAllocationAt(pc); + if (!istream_address.has_value()) { + return {}; + } + Tagged<InstructionStream> istream = UncheckedCast<InstructionStream>( + HeapObject::FromAddress(*istream_address)); + Tagged<Code> interpreter_entry_trampoline; + if (!istream->TryGetCodeUnchecked(&interpreter_entry_trampoline, + kAcquireLoad)) { return {}; } - Tagged<Code> interpreter_entry_trampoline = - isolate->heap()->FindCodeForInnerPointer(pc); return interpreter_entry_trampoline->is_interpreter_trampoline_builtin(); } else { return false; @@ -507,12 +524,7 @@ StackFrameIteratorForProfiler::StackFrameIteratorForProfiler( high_bound_(js_entry_sp), top_frame_type_(StackFrame::NO_FRAME_TYPE), external_callback_scope_(isolate->external_callback_scope()), - top_link_register_(lr) -#if V8_ENABLE_WEBASSEMBLY - , - wasm_stacks_(isolate->wasm_stacks()) -#endif -{ + top_link_register_(lr) { if (!isolate->isolate_data()->stack_is_iterable()) { // The stack is not iterable in a short time interval during deoptimization. // See also: ExternalReference::stack_is_iterable_address. @@ -890,7 +902,6 @@ StackFrame::Type SafeStackFrameType(StackFrame::Type candidate) { case StackFrame::WASM_EXIT: case StackFrame::WASM_LIFTOFF_SETUP: case StackFrame::WASM_TO_JS: - case StackFrame::WASM_SEGMENT_START: case StackFrame::WASM_STACK_ENTRY: case StackFrame::WASM_STACK_EXIT: #if V8_ENABLE_DRUMBRAKE @@ -1833,8 +1844,7 @@ void WasmFrame::Iterate(RootVisitor* v) const { Memory<intptr_t>(fp() + CommonFrameConstants::kContextOrFrameTypeOffset); DCHECK(StackFrame::IsTypeMarker(marker)); StackFrame::Type type = StackFrame::MarkerToType(marker); - DCHECK(type == WASM_TO_JS || type == WASM || type == WASM_EXIT || - type == WASM_SEGMENT_START); + DCHECK(type == WASM_TO_JS || type == WASM || type == WASM_EXIT); #endif // Determine the fixed header and spill slot area size. @@ -3577,6 +3587,12 @@ void InterpretedFrame::PatchBytecodeArray( SetExpression(index, bytecode_array); } +Tagged<BytecodeArray> InterpretedFrame::GetOriginalBytecodeArray() const { + auto bytecodes = function()->shared()->GetBytecodeArrays(isolate()); + SBXCHECK_EQ(bytecodes.active, GetBytecodeArray()); + return bytecodes.original; +} + int BaselineFrame::GetBytecodeOffset() const { Tagged<Code> code = LookupCode(); return code->GetBytecodeOffsetForBaselinePC(this->pc(), GetBytecodeArray()); @@ -3605,6 +3621,34 @@ uint32_t BuiltinFrame::ComputeParametersCount() const { } #if V8_ENABLE_WEBASSEMBLY +void TypedFrame::UnwindWasmReturnFromSegment(State* state) const { + if (v8_flags.wasm_growable_stacks && iterator_->wasm_stack() != nullptr && + state->fp != kNullAddress && *state->pc_address != kNullAddress) { + Address raw_pc = PointerAuthentication::StripPAC(*state->pc_address); + Address trampoline = + Builtins::EntryOf(Builtin::kWasmReturnFromSegment, isolate()); + Address current_fp = fp(); + while (raw_pc == trampoline) { + Address old_fp = + iterator_->wasm_stack()->GetParentSegmentOldFP(current_fp); + CHECK_NE(old_fp, 0); + state->pc_address = + ResolveReturnAddressLocation(reinterpret_cast<Address*>( + old_fp + StandardFrameConstants::kCallerPCOffset)); + raw_pc = PointerAuthentication::StripPAC(*state->pc_address); + current_fp = old_fp; + } + if (current_fp != fp()) { + state->sp = current_fp + StandardFrameConstants::kCallerSPOffset; + } + } +} + +void WasmFrame::ComputeCallerState(State* state) const { + TypedFrame::ComputeCallerState(state); + UnwindWasmReturnFromSegment(state); +} + void WasmFrame::Print(StringStream* accumulator, PrintMode mode, int index, AllowAllocation allow_allocation) const { PrintIndex(accumulator, mode, index); @@ -3765,9 +3809,18 @@ int WasmFrame::LookupExceptionHandlerInTable() { void WasmDebugBreakFrame::Iterate(RootVisitor* v) const { DCHECK(caller_pc()); - auto pair = wasm::GetWasmCodeManager()->LookupCodeAndSafepoint(isolate(), - caller_pc()); - SafepointEntry& safepoint_entry = pair.second; + auto [code, safepoint_entry] = + wasm::GetWasmCodeManager()->LookupCodeAndSafepoint(isolate(), + caller_pc()); + if (!safepoint_entry.is_initialized()) { + // Trap handler traps from non-debugging code also enter a WASM_DEBUG_BREAK + // frame via kWasmTrapHandlerThrowTrap, but do not emit safepoints with + // callee-saved registers. In that case, there are no tagged registers to + // iterate. Debugging code, however, must always have an initialized + // safepoint. + DCHECK(!code || !code->for_debugging()); + return; + } uint32_t tagged_register_indexes = safepoint_entry.tagged_register_indexes(); while (tagged_register_indexes != 0) { @@ -4001,6 +4054,7 @@ Address WasmLiftoffSetupFrame::CallingPC() const { void WasmLiftoffSetupFrame::ComputeCallerState(State* state) const { TypedFrame::ComputeCallerState(state); + UnwindWasmReturnFromSegment(state); // Unlike {CallingPC}, which only runs at safepoints, this can run on a // profiler tick: the setup builtin sets the frame marker a few instructions // before it signs and spills the calling PC, so the slot can still be diff --git a/deps/v8/src/execution/frames.h b/deps/v8/src/execution/frames.h index f7662c656fea..c508d3ff0018 100644 --- a/deps/v8/src/execution/frames.h +++ b/deps/v8/src/execution/frames.h @@ -152,8 +152,7 @@ class StackHandler { IF_WASM(V, WASM_STACK_ENTRY, WasmStackEntryFrame) \ IF_WASM(V, WASM_STACK_EXIT, WasmStackExitFrame) \ IF_WASM(V, WASM_EXIT, WasmExitFrame) \ - IF_WASM(V, WASM_LIFTOFF_SETUP, WasmLiftoffSetupFrame) \ - IF_WASM(V, WASM_SEGMENT_START, WasmSegmentStartFrame) + IF_WASM(V, WASM_LIFTOFF_SETUP, WasmLiftoffSetupFrame) // Abstract base class for all stack frames. class StackFrame { @@ -255,7 +254,7 @@ class StackFrame { bool is_turbofan_js() const { return type() == TURBOFAN_JS; } #if V8_ENABLE_WEBASSEMBLY bool is_wasm() const { - return this->type() == WASM || this->type() == WASM_SEGMENT_START + return this->type() == WASM #ifdef V8_ENABLE_DRUMBRAKE || this->type() == WASM_INTERPRETER_ENTRY #endif // V8_ENABLE_DRUMBRAKE @@ -722,6 +721,9 @@ class TypedFrame : public CommonFrame { protected: inline explicit TypedFrame(StackFrameIteratorBase* iterator); +#if V8_ENABLE_WEBASSEMBLY + void UnwindWasmReturnFromSegment(State* state) const; +#endif }; class CommonFrameWithJSLinkage : public CommonFrame { @@ -1267,6 +1269,11 @@ class InterpretedFrame : public UnoptimizedJSFrame { // debugger to swap execution onto a BytecodeArray patched with breakpoints. void PatchBytecodeArray(Tagged<BytecodeArray> bytecode_array); + // Returns the original (non-debug) BytecodeArray associated with this frame's + // SharedFunctionInfo after verifying that the frame's current BytecodeArray + // is consistent with it. + Tagged<BytecodeArray> GetOriginalBytecodeArray() const; + static InterpretedFrame* cast(StackFrame* frame) { DCHECK(frame->is_interpreted()); return static_cast<InterpretedFrame*>(frame); @@ -1425,6 +1432,8 @@ class WasmFrame : public TypedFrame { protected: inline explicit WasmFrame(StackFrameIteratorBase* iterator); + void ComputeCallerState(State* state) const override; + private: friend class StackFrameIteratorBase; Tagged<WasmModuleObject> module_object() const; @@ -1432,23 +1441,6 @@ class WasmFrame : public TypedFrame { const; }; -// WasmSegmentStartFrame is a regular Wasm frame moved to the -// beginning of a new stack segment allocated for growable stack. -// It requires special handling on return. To indicate that, the WASM frame type -// is replaced by WASM_SEGMENT_START. -class WasmSegmentStartFrame : public WasmFrame { - public: - // type() intentionally returns WASM frame type because WasmSegmentStartFrame - // behaves exactly like regular WasmFrame in all scenarios. - Type type() const override { return WASM; } - - protected: - inline explicit WasmSegmentStartFrame(StackFrameIteratorBase* iterator); - - private: - friend class StackFrameIteratorBase; -}; - // Wasm to C-API exit frame. class WasmExitFrame : public WasmFrame { public: @@ -1824,7 +1816,7 @@ class StackFrameIteratorBase { #if V8_ENABLE_WEBASSEMBLY // Stop at the end of the topmost (wasm) stack. bool first_stack_only_ = false; - // // Current wasm stack being iterated. + // Current wasm stack being iterated. wasm::StackMemory* wasm_stack_ = nullptr; #endif @@ -1999,9 +1991,6 @@ class StackFrameIteratorForProfiler : public StackFrameIteratorBase { StackFrame::Type top_frame_type_; ExternalCallbackScope* external_callback_scope_; Address top_link_register_; -#if V8_ENABLE_WEBASSEMBLY - std::vector<std::unique_ptr<wasm::StackMemory>>& wasm_stacks_; -#endif }; // We cannot export 'StackFrameIteratorForProfiler' for cctests since the diff --git a/deps/v8/src/execution/isolate-data-fields.h b/deps/v8/src/execution/isolate-data-fields.h index c5c9ed09cb91..7a49bfa49ffc 100644 --- a/deps/v8/src/execution/isolate-data-fields.h +++ b/deps/v8/src/execution/isolate-data-fields.h @@ -90,6 +90,8 @@ static constexpr int kFastCCallAlignmentPaddingCount = 1; IF_WASM(V, ActiveSuspender, kSystemPointerSize, active_suspender) \ V(DateCacheStamp, kInt32Size, date_cache_stamp) \ V(IsDateCacheUsed, kUInt8Size, is_date_cache_used) \ + IF_INTL(V, DefaultLocaleMayRequireSpecialCaseMapping, kUInt8Size, \ + default_locale_may_require_special_case_mapping) \ /* This padding aligns next field to kDoubleSize bytes. */ \ PADDING_FIELD(kDoubleSize, V, RawArgumentsPadding, raw_arguments_padding) \ V(RawArguments, 2 * kDoubleSize, raw_arguments) \ @@ -140,6 +142,8 @@ static constexpr int kFastCCallAlignmentPaddingCount = 1; offsetof(ThreadLocalTop, last_entered_context_)) \ V(Exception, exception, thread_local_top, \ offsetof(ThreadLocalTop, exception_)) \ + V(PendingMessage, pending_message, thread_local_top, \ + offsetof(ThreadLocalTop, pending_message_)) \ V(TopmostScriptHavingContext, topmost_script_having_context, \ thread_local_top, \ offsetof(ThreadLocalTop, topmost_script_having_context_)) \ @@ -164,6 +168,10 @@ static constexpr int kFastCCallAlignmentPaddingCount = 1; offsetof(ThreadLocalTop, num_frames_above_pending_handler_)) \ V(IsOnCentralStackFlag, is_on_central_stack_flag, thread_local_top, \ offsetof(ThreadLocalTop, is_on_central_stack_flag_)) \ + V(CentralStackSP, central_stack_sp, thread_local_top, \ + offsetof(ThreadLocalTop, central_stack_sp_)) \ + V(CentralStackLimit, central_stack_limit, thread_local_top, \ + offsetof(ThreadLocalTop, central_stack_limit_)) \ V(JSEntrySP, js_entry_sp, thread_local_top, \ offsetof(ThreadLocalTop, js_entry_sp_)) \ \ diff --git a/deps/v8/src/execution/isolate-data.h b/deps/v8/src/execution/isolate-data.h index b11ebe2da80d..b27b94055c37 100644 --- a/deps/v8/src/execution/isolate-data.h +++ b/deps/v8/src/execution/isolate-data.h @@ -188,6 +188,10 @@ class IsolateData final { Tagged<Object> continuation_preserved_embedder_data() const { return continuation_preserved_embedder_data_; } + Handle<Object> continuation_preserved_embedder_data_handle() { + return Handle<Object>( + reinterpret_cast<Address*>(&continuation_preserved_embedder_data_)); + } void set_continuation_preserved_embedder_data(Tagged<Object> data) { continuation_preserved_embedder_data_ = data; } @@ -455,6 +459,9 @@ class IsolateData final { // Boolean value indicating that DateCache is used (i.e. JSDate instances // were created in this Isolate). uint8_t is_date_cache_used_ = false; +#ifdef V8_INTL_SUPPORT + uint8_t default_locale_may_require_special_case_mapping_ = true; +#endif // Padding for aligning raw_arguments_. V8_NO_UNIQUE_ADDRESS uint8_t raw_arguments_padding_[kRawArgumentsPaddingSize]; diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 7ef444669c8e..2834f8fbac67 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -28,7 +28,6 @@ #include "src/api/api-inl.h" #include "src/ast/ast-value-factory.h" #include "src/ast/scopes.h" -#include "src/base/fpu.h" #include "src/base/iterator.h" #include "src/base/logging.h" #include "src/base/platform/mutex.h" @@ -875,8 +874,6 @@ StackTraceFailureMessage::StackTraceFailureMessage( } } -bool NoExtension(const v8::FunctionCallbackInfo<v8::Value>&) { return false; } - namespace { bool IsBuiltinFunction(Isolate* isolate, Tagged<HeapObject> object, @@ -1409,7 +1406,9 @@ void CaptureAsyncStackTrace(Isolate* isolate, DirectHandle<JSPromise> promise, } else if (DirectHandle<WasmSuspenderObject> suspender; TryGetWasmSuspender(isolate, reaction->fulfill_handler()) .ToHandle(&suspender)) { - DCHECK_NOT_NULL(suspender->stack()); + SBXCHECK_NE(suspender->stack(), nullptr); + SBXCHECK_EQ(suspender->stack()->jmpbuf()->state, + wasm::JumpBuffer::Suspended); for (StackFrameIterator it(isolate, suspender->stack()); !it.done(); it.Advance()) { StackFrame* frame = it.frame(); @@ -1589,7 +1588,6 @@ void VisitStack(Isolate* isolate, Visitor* visitor, #if V8_ENABLE_WEBASSEMBLY case StackFrame::STUB: case StackFrame::WASM: - case StackFrame::WASM_SEGMENT_START: #if V8_ENABLE_DRUMBRAKE case StackFrame::WASM_INTERPRETER_ENTRY: #endif // V8_ENABLE_DRUMBRAKE @@ -1635,7 +1633,10 @@ void VisitStack_ForCallSiteBuilder(Isolate* isolate, CallSiteBuilder* visitor) { CallSiteInfo::kIsDeferredBaselineFrame)) { return; } - skipped_last_frame = true; + // Visibility (incl. security origin) is tracked by skipped_prev_frame_ + // in AppendDeferredFrame; count this frame as appended so the caller's + // inlined construct stub can still flag it. + skipped_last_frame = false; break; case StackFrame::API_CALLBACK_EXIT: case StackFrame::API_CONSTRUCT_EXIT: @@ -1649,7 +1650,6 @@ void VisitStack_ForCallSiteBuilder(Isolate* isolate, CallSiteBuilder* visitor) { #if V8_ENABLE_WEBASSEMBLY case StackFrame::STUB: case StackFrame::WASM: - case StackFrame::WASM_SEGMENT_START: #if V8_ENABLE_DRUMBRAKE case StackFrame::WASM_INTERPRETER_ENTRY: #endif // V8_ENABLE_DRUMBRAKE @@ -2078,7 +2078,9 @@ class CurrentScriptIdsAndContextsStackVisitor { Tagged<Object> maybe_script = Cast<SharedFunctionInfo>(maybe_sfi)->script(); if (!IsScript(maybe_script)) break; - cur = Cast<Script>(maybe_script); + Tagged<Script> eval_from_script = Cast<Script>(maybe_script); + if (!eval_from_script->IsUserJavaScript()) break; + cur = eval_from_script; } return cur->id(); } @@ -2128,7 +2130,9 @@ class CurrentScriptDataStackVisitor { Tagged<Object> maybe_script = Cast<SharedFunctionInfo>(maybe_sfi)->script(); if (!IsScript(maybe_script)) break; - cur = Cast<Script>(maybe_script); + Tagged<Script> eval_from_script = Cast<Script>(maybe_script); + if (!eval_from_script->IsUserJavaScript()) break; + cur = eval_from_script; } return cur->id(); } @@ -2525,7 +2529,7 @@ Tagged<Object> Isolate::StackOverflow() { #endif if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("Aborting on stack overflow"); + base::FatalNoSecurityImpact("Aborting on stack overflow"); } #if USE_SIMULATOR @@ -2927,9 +2931,9 @@ Tagged<Object> Isolate::UnwindAndFindHandler() { active_stack, parent, kNullAddress, kNullAddress, kNullAddress); if (suspender->has_parent() && parent == suspender->parent()->stack()) { // Exception escapes the current suspender, unwind to the parent. - // Clear the external stack pointer to avoid a UAF. - suspender->set_stack(this, nullptr); + DCHECK_NULL(suspender->stack()); suspender = suspender->parent(); + suspender->set_stack(nullptr); } RetireWasmStack(active_stack); active_stack = parent; @@ -3124,8 +3128,7 @@ Tagged<Object> Isolate::UnwindAndFindHandler() { } break; #endif // V8_ENABLE_DRUMBRAKE - case StackFrame::WASM: - case StackFrame::WASM_SEGMENT_START: { + case StackFrame::WASM: { if (!is_catchable_by_wasm(exception)) break; WasmFrame* wasm_frame = static_cast<WasmFrame*>(frame); @@ -3997,9 +4000,9 @@ PromiseMethod GetPromiseMethod( auto str = Cast<String>(object); if (str->Equals(ReadOnlyRoots(isolate).then_string())) { return kThen; - } else if (str->IsEqualTo(base::StaticCharVector("catch"))) { + } else if (str->IsEqualTo("catch")) { return kCatch; - } else if (str->IsEqualTo(base::StaticCharVector("finally"))) { + } else if (str->IsEqualTo("finally")) { return kFinally; } else { return kInvalid; @@ -4532,17 +4535,21 @@ void Isolate::IterateRegistersAndStackOfSimulator( #if V8_ENABLE_WEBASSEMBLY bool Isolate::IsOnCentralStack(Address addr) { auto stack = SimulatorStack::GetCentralStackView(this); + Address stack_base = reinterpret_cast<Address>(stack.end()); + if (addr > stack_base) return false; Address stack_top = reinterpret_cast<Address>(stack.begin()); + if (stack_top < addr) return true; #if !USE_SIMULATOR - // Try to use the stack limit reported by the system instead of V8's own - // conservative limit to avoid false positives. + // V8's stack limit is a conservative estimate. + // Try to use the real stack limit now to avoid false negatives. + // This is a slow operation on some configurations, so only use this as a + // fallback. Address real_stack_top = base::Stack::GetReservedStackLimit(); - if (real_stack_top) { - stack_top = real_stack_top; + if (real_stack_top != kNullAddress && real_stack_top < addr) { + return true; } #endif - Address stack_base = reinterpret_cast<Address>(stack.end()); - return stack_top < addr && addr <= stack_base; + return false; } bool Isolate::IsOnCentralStack() { @@ -5666,7 +5673,6 @@ void Isolate::NotifyExceptionPropagationCallback() { return; #if V8_ENABLE_WEBASSEMBLY case StackFrame::WASM: - case StackFrame::WASM_SEGMENT_START: // No more info. return; #endif // V8_ENABLE_WEBASSEMBLY @@ -5957,7 +5963,7 @@ bool Isolate::InitWithSnapshot(SnapshotData* startup_snapshot_data, namespace { static std::string ToHexString(uintptr_t address) { std::stringstream stream_address; - stream_address << "0x" << std::hex << address; + stream_address << "0x" << std::hex << address << std::dec; return stream_address.str(); } } // namespace @@ -6204,8 +6210,6 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, force_slow_path_ = v8_flags.force_slow_path; - flush_denormals_ = base::FPU::GetFlushDenormals(); - has_fatal_error_ = false; // The initialization process does not handle memory exhaustion. @@ -6636,29 +6640,9 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, } } -#ifdef V8_ENABLE_WEBASSEMBLY -#if V8_STATIC_ROOTS_BOOL - // Protect the payload of wasm null. - if (!page_allocator()->DecommitPages( - reinterpret_cast<void*>(factory()->wasm_null()->address()), - WasmNull::kSize)) { - V8::FatalProcessOutOfMemory(this, "decommitting WasmNull payload"); - } -#endif // V8_STATIC_ROOTS_BOOL -#endif // V8_ENABLE_WEBASSEMBLY - - if (v8_flags.unmap_holes) { -// Protect the payload of each hole. -#define UNMAP_HOLE(CamelName, snake_name, _) \ - if (!page_allocator()->DecommitPages( \ - reinterpret_cast<void*>(&factory()->snake_name()->payload_), \ - Hole::kPayloadSize)) { \ - V8::FatalProcessOutOfMemory(this, "decommitting " #CamelName " payload"); \ - } - - HOLE_LIST(UNMAP_HOLE) -#undef UNMAP_HOLE - } + // A read-only heap deserialized from a snapshot was already protected when + // it was set up. One created from scratch only has its holes now. + if (create_heap_objects) read_only_heap()->DecommitGuardRegions(this); // Isolate initialization allocates long living objects that should be // pretenured to old space. @@ -7266,7 +7250,6 @@ void Isolate::WasmInitJSPIFeature() { HandleScope scope(this); DirectHandle<WasmSuspenderObject> suspender = factory()->NewWasmSuspenderObject(); - suspender->set_stack(this, wasm_stacks()[0].get()); isolate_data_.set_active_suspender(*suspender); } } @@ -8184,8 +8167,16 @@ const std::string& Isolate::DefaultLocale() { return default_locale_; } +void Isolate::set_default_locale(const std::string& locale) { + DCHECK_EQ(default_locale_.length(), 0); + default_locale_ = locale; + isolate_data_.default_locale_may_require_special_case_mapping_ = + Intl::LocaleRequiresSpecialCaseMapping(default_locale_); +} + void Isolate::ResetDefaultLocale() { default_locale_.clear(); + isolate_data_.default_locale_may_require_special_case_mapping_ = true; clear_cached_icu_objects(); // We inline fast paths assuming certain locales. Since this path is rarely // taken, we deoptimize everything to keep things simple. diff --git a/deps/v8/src/execution/isolate.h b/deps/v8/src/execution/isolate.h index f8c0c95e78fd..c1917812619c 100644 --- a/deps/v8/src/execution/isolate.h +++ b/deps/v8/src/execution/isolate.h @@ -501,9 +501,13 @@ using DebugObjectCache = std::vector<Handle<HeapObject>>; V(LogEventCallback, event_logger, nullptr) \ V(ModifyCodeGenerationFromStringsCallback2, modify_code_gen_callback, \ nullptr) \ + V(DynamicScriptCompiledFromEmbedderCallback, dynamic_script_callback, \ + nullptr) \ V(AllowWasmCodeGenerationCallback, allow_wasm_code_gen_callback, nullptr) \ - V(ExtensionCallback, wasm_module_callback, &NoExtension) \ - V(ExtensionCallback, wasm_instance_callback, &NoExtension) \ + V(WasmModuleCallback, wasm_module_callback, nullptr) \ + V(ExtensionCallback, deprecated_wasm_module_callback, nullptr) \ + V(WasmInstanceCallback, wasm_instance_callback, nullptr) \ + V(ExtensionCallback, deprecated_wasm_instance_callback, nullptr) \ V(SharedArrayBufferConstructorEnabledCallback, \ sharedarraybuffer_constructor_enabled_callback, nullptr) \ V(WasmStreamingCallback, wasm_streaming_callback, nullptr) \ @@ -896,12 +900,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { inline Address* c_entry_fp_address() { return &thread_local_top()->c_entry_fp_; } - static uint32_t c_entry_fp_offset() { - return static_cast<uint32_t>(OFFSET_OF(Isolate, isolate_data_) + - OFFSET_OF(IsolateData, thread_local_top_) + - OFFSET_OF(ThreadLocalTop, c_entry_fp_) - - isolate_root_bias()); - } inline Address* handler_address() { return &thread_local_top()->handler_; } inline Address* c_function_address() { return &thread_local_top()->c_function_; @@ -1391,34 +1389,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { return &isolate_data_.thread_local_top_; } - constexpr static uint32_t context_offset() { - return static_cast<uint32_t>( - OFFSET_OF(Isolate, isolate_data_) + - OFFSET_OF(IsolateData, thread_local_top_) + - OFFSET_OF(ThreadLocalTop, context_) - - isolate_root_bias()); - } - - constexpr static uint32_t central_stack_sp_offset() { - return static_cast<uintptr_t>(OFFSET_OF(Isolate, isolate_data_) + - OFFSET_OF(IsolateData, thread_local_top_) + - OFFSET_OF(ThreadLocalTop, central_stack_sp_) - - isolate_root_bias()); - } - - constexpr static uint32_t central_stack_limit_offset() { - return static_cast<uintptr_t>( - OFFSET_OF(Isolate, isolate_data_) + - OFFSET_OF(IsolateData, thread_local_top_) + - OFFSET_OF(ThreadLocalTop, central_stack_limit_) - isolate_root_bias()); - } - - static uint32_t error_message_param_offset() { - return static_cast<uint32_t>(OFFSET_OF(Isolate, isolate_data_) + - OFFSET_OF(IsolateData, error_message_param_) - - isolate_root_bias()); - } - uint8_t error_message_param() { return isolate_data_.error_message_param_; } THREAD_LOCAL_TOP_ADDRESS(uint8_t, is_on_central_stack_flag) @@ -1700,12 +1670,13 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { const std::string& DefaultLocale(); + bool DefaultLocaleMayRequireSpecialCaseMapping() const { + return isolate_data_.default_locale_may_require_special_case_mapping_; + } + void ResetDefaultLocale(); - void set_default_locale(const std::string& locale) { - DCHECK_EQ(default_locale_.length(), 0); - default_locale_ = locale; - } + void set_default_locale(const std::string& locale); enum class ICUObjectCacheType{ kDefaultCollator, kDefaultNumberFormat, kDefaultSimpleDateFormat, @@ -2225,8 +2196,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { void set_allow_atomics_wait(bool set) { allow_atomics_wait_ = set; } bool allow_atomics_wait() { return allow_atomics_wait_; } - bool flush_denormals() const { return flush_denormals_; } - // Register a finalizer to be called at isolate teardown. void RegisterManagedPtrDestructor(ManagedPtrDestructor* finalizer); @@ -2294,10 +2263,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { return isolate_data_.external_pointer_table_; } - Address external_pointer_table_address() { - return reinterpret_cast<Address>(&isolate_data_.external_pointer_table_); - } - ExternalPointerTable& shared_external_pointer_table() { return *isolate_data_.shared_external_pointer_table_; } @@ -2334,10 +2299,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { return isolate_data_.trusted_pointer_table_; } - Address trusted_pointer_table_base_address() const { - return isolate_data_.trusted_pointer_table_.base_address(); - } - TrustedPointerTable& shared_trusted_pointer_table() { return *isolate_data_.shared_trusted_pointer_table_; } @@ -2354,11 +2315,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { return shared_trusted_pointer_space_; } - Address shared_trusted_pointer_table_base_address() { - return reinterpret_cast<Address>( - &isolate_data_.shared_trusted_pointer_table_); - } - TrustedPointerPublishingScope* trusted_pointer_publishing_scope() const { return isolate_data_.trusted_pointer_publishing_scope_; } @@ -2539,6 +2495,12 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { void Freeze(bool is_frozen) { is_frozen_ = is_frozen; + if (v8_flags.freeze_forces_marking_finalization && IsFrozen()) { + // We will either finalize an ongoing GC, or simply do a GC to reclaim + // any unreachable memory. + heap()->FinalizeIncrementalMarkingAtomicallyIfRunning( + i::GarbageCollectionReason::kFrozen); + } } static void IterateRegistersAndStackOfSimulator( @@ -2944,7 +2906,6 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory { abort_on_uncaught_exception_callback_ = nullptr; bool allow_atomics_wait_ = true; - bool flush_denormals_ = false; base::Mutex managed_ptr_destructors_mutex_; ManagedPtrDestructor* managed_ptr_destructors_head_ = nullptr; diff --git a/deps/v8/src/execution/local-isolate.cc b/deps/v8/src/execution/local-isolate.cc index f3838e8ac4ee..e5b8b342f48b 100644 --- a/deps/v8/src/execution/local-isolate.cc +++ b/deps/v8/src/execution/local-isolate.cc @@ -4,7 +4,6 @@ #include "src/execution/local-isolate.h" -#include "src/base/fpu.h" #include "src/bigint/bigint.h" #include "src/execution/isolate.h" #include "src/execution/thread-id.h" @@ -15,9 +14,10 @@ namespace v8 { namespace internal { -LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind) +LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind, + v8::base::Stack::StackSlot stack_start) : HiddenLocalFactory(isolate), - heap_(isolate->heap(), kind), + heap_(isolate->heap(), kind, nullptr, stack_start), isolate_(isolate), logger_(new LocalLogger(isolate)), thread_id_(ThreadId::Current()), @@ -29,9 +29,6 @@ LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind) default_locale_(isolate->DefaultLocale()) #endif { - // LocalIsolate owning threads need to make sure to match the isolate's FPU - // state. - DCHECK_EQ(base::FPU::GetFlushDenormals(), isolate->flush_denormals()); #ifdef V8_RUNTIME_CALL_STATS if (kind == ThreadKind::kMain) { runtime_call_stats_ = isolate->counters()->runtime_call_stats(); diff --git a/deps/v8/src/execution/local-isolate.h b/deps/v8/src/execution/local-isolate.h index 515a57b38999..45c4647d96ab 100644 --- a/deps/v8/src/execution/local-isolate.h +++ b/deps/v8/src/execution/local-isolate.h @@ -7,7 +7,6 @@ #include <optional> -#include "src/base/fpu.h" #include "src/base/macros.h" #include "src/execution/mutex-guard-if-off-thread.h" #include "src/execution/thread-id.h" @@ -47,7 +46,11 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory { public: using HandleScopeType = LocalHandleScope; - explicit LocalIsolate(Isolate* isolate, ThreadKind kind); + // The parameter `stack_start` is only used for stack-allocated instances, + // where `kind == ThreadKind::kBackground`. + explicit LocalIsolate(Isolate* isolate, ThreadKind kind, + v8::base::Stack::StackSlot stack_start = + v8::base::Stack::GetCurrentFrameAddress()); ~LocalIsolate(); // Kinda sketchy. diff --git a/deps/v8/src/execution/loong64/simulator-loong64.cc b/deps/v8/src/execution/loong64/simulator-loong64.cc index a66c446c5e00..c7d9aac861d2 100644 --- a/deps/v8/src/execution/loong64/simulator-loong64.cc +++ b/deps/v8/src/execution/loong64/simulator-loong64.cc @@ -11,6 +11,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <array> #include <cmath> #include "src/base/bits.h" @@ -320,10 +321,10 @@ void Loong64Debugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.begin()); + PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.data()); last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); @@ -482,7 +483,7 @@ void Loong64Debugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* cur = nullptr; uint8_t* end = nullptr; @@ -521,7 +522,7 @@ void Loong64Debugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), - buffer.begin()); + buffer.data()); cur += kInstrSize; } } else if (strcmp(cmd, "gdb") == 0) { @@ -611,7 +612,7 @@ void Loong64Debugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* cur = nullptr; uint8_t* end = nullptr; @@ -638,7 +639,7 @@ void Loong64Debugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), - buffer.begin()); + buffer.data()); cur += kInstrSize; } } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { @@ -5396,7 +5397,7 @@ void Simulator::InstructionDecode(Instruction* instr) { } pc_modified_ = false; - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; if (v8_flags.trace_sim) { base::SNPrintF(trace_buf_, " "); @@ -5444,8 +5445,7 @@ void Simulator::InstructionDecode(Instruction* instr) { if (v8_flags.trace_sim) { PrintF(" 0x%08" PRIxPTR " %-44s %s\n", - reinterpret_cast<intptr_t>(instr), buffer.begin(), - trace_buf_.begin()); + reinterpret_cast<intptr_t>(instr), buffer.data(), trace_buf_.data()); } if (!pc_modified_) { diff --git a/deps/v8/src/execution/loong64/simulator-loong64.h b/deps/v8/src/execution/loong64/simulator-loong64.h index 5cfa12eccbed..0e2209bb0a7a 100644 --- a/deps/v8/src/execution/loong64/simulator-loong64.h +++ b/deps/v8/src/execution/loong64/simulator-loong64.h @@ -33,6 +33,8 @@ T Nabs(T a) { #if defined(USE_SIMULATOR) // Running with a simulator. +#include <array> + #include "src/base/hashmap.h" #include "src/base/strings.h" #include "src/codegen/assembler.h" @@ -627,7 +629,7 @@ class Simulator : public SimulatorBase { bool pc_modified_; int64_t icount_; int break_count_; - base::EmbeddedVector<char, 128> trace_buf_; + std::array<char, 128> trace_buf_; // Debugger input. char* last_debugger_input_; diff --git a/deps/v8/src/execution/messages.cc b/deps/v8/src/execution/messages.cc index 2bd02475772b..1635529959a9 100644 --- a/deps/v8/src/execution/messages.cc +++ b/deps/v8/src/execution/messages.cc @@ -24,7 +24,7 @@ #include "src/parsing/parse-info.h" #include "src/parsing/parsing.h" #include "src/roots/roots.h" -#include "src/sandbox/indirect-pointer-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" #include "src/strings/string-builder-inl.h" namespace v8 { @@ -189,8 +189,10 @@ DirectHandle<String> MessageHandler::GetMessage(Isolate* isolate, DirectHandle<Object> data) { DirectHandle<JSMessageObject> message = Cast<JSMessageObject>(data); DirectHandle<Object> arg{message->argument(), isolate}; - return MessageFormatter::Format(isolate, message->type(), - base::VectorOf({arg})); + return MessageFormatter::Format( + isolate, message->type(), + IsTheHole(*arg) ? base::Vector<const DirectHandle<Object>>{} + : base::VectorOf({arg})); } std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage( @@ -420,8 +422,7 @@ DirectHandle<String> MessageFormatter::Format( Handle<String> result_string; if (!maybe_result_string.ToHandle(&result_string)) { DCHECK(isolate->has_exception()); - return isolate->factory()->InternalizeString( - base::StaticCharVector("<error>")); + return isolate->factory()->InternalizeString("<error>"); } // A string that has been obtained from JS code in this way is // likely to be a complicated ConsString of some sort. We flatten it @@ -451,52 +452,6 @@ MaybeHandle<String> MessageFormatter::TryFormat( IncrementalStringBuilder builder(isolate); - // TODO(14386): Get this list empty. - static constexpr MessageTemplate kTemplatesWithMismatchedArguments[] = { - MessageTemplate::kConstAssign, - MessageTemplate::kConstructorNotReceiver, - MessageTemplate::kDataCloneErrorDetachedArrayBuffer, - MessageTemplate::kDataCloneErrorOutOfMemory, - MessageTemplate::kIncompatibleMethodReceiver, - MessageTemplate::kInvalidArgument, - MessageTemplate::kInvalidArrayLength, - MessageTemplate::kInvalidAtomicAccessIndex, - MessageTemplate::kInvalidDataViewLength, - MessageTemplate::kInvalidIndex, - MessageTemplate::kInvalidLhsInAssignment, - MessageTemplate::kInvalidLhsInFor, - MessageTemplate::kInvalidLhsInPostfixOp, - MessageTemplate::kInvalidLhsInPrefixOp, - MessageTemplate::kInvalidPrivateBrandReinitialization, - MessageTemplate::kInvalidPrivateFieldReinitialization, - MessageTemplate::kInvalidPrivateMemberWrite, - MessageTemplate::kInvalidRegExpExecResult, - MessageTemplate::kInvalidTimeValue, - MessageTemplate::kInvalidWeakMapKey, - MessageTemplate::kInvalidWeakSetValue, - MessageTemplate::kIteratorReduceNoInitial, - MessageTemplate::kJsonParseShortString, - MessageTemplate::kJsonParseUnexpectedEOS, - MessageTemplate::kJsonParseUnexpectedTokenEndStringWithContext, - MessageTemplate::kJsonParseUnexpectedTokenShortString, - MessageTemplate::kJsonParseUnexpectedTokenStartStringWithContext, - MessageTemplate::kJsonParseUnexpectedTokenSurroundStringWithContext, - MessageTemplate::kMustBePositive, - MessageTemplate::kNotIterable, - MessageTemplate::kNotTypedArray, - MessageTemplate::kProxyNonObject, - MessageTemplate::kProxyPrivate, - MessageTemplate::kProxyRevoked, - MessageTemplate::kProxyTrapReturnedFalsishFor, - MessageTemplate::kReduceNoInitial, - MessageTemplate::kSpreadIteratorSymbolNonCallable, - MessageTemplate::kSymbolIteratorInvalid, - MessageTemplate::kTopLevelAwaitStalled, - MessageTemplate::kUndefinedOrNullToObject, - MessageTemplate::kUnexpectedStrictReserved, - MessageTemplate::kUnexpectedTokenIdentifier, - MessageTemplate::kWeakRefsCleanupMustBeCallable}; - base::Vector<const DirectHandle<String>> remaining_args = args; for (const char* c = template_string; *c != '\0'; c++) { if (*c == '%') { @@ -504,29 +459,19 @@ MaybeHandle<String> MessageFormatter::TryFormat( if (*(c + 1) == '%') { c++; builder.AppendCharacter('%'); + } else if (remaining_args.empty()) { + FATAL("Missing argument to template (got %zu): %s", args.size(), + template_string); } else { - // TODO(14386): Remove this fallback. - if (remaining_args.empty()) { - if (std::count(std::begin(kTemplatesWithMismatchedArguments), - std::end(kTemplatesWithMismatchedArguments), index)) { - builder.AppendCString("undefined"); - } else { - FATAL("Missing argument to template (got %zu): %s", args.size(), - template_string); - } - } else { - DirectHandle<String> arg = remaining_args[0]; - remaining_args += 1; - builder.AppendString(arg); - } + DirectHandle<String> arg = remaining_args[0]; + remaining_args += 1; + builder.AppendString(arg); } } else { builder.AppendCharacter(*c); } } - if (!remaining_args.empty() && - std::count(std::begin(kTemplatesWithMismatchedArguments), - std::end(kTemplatesWithMismatchedArguments), index) == 0) { + if (!remaining_args.empty()) { FATAL("Too many arguments to template (expected %zu, got %zu): %s", args.size() - remaining_args.size(), args.size(), template_string); } @@ -563,7 +508,7 @@ MaybeHandle<JSObject> ErrorUtils::Construct( // Abort range errors in correctness fuzzing, as their causes differ // across correctness-fuzzing scenarios. if (target.is_identical_to(isolate->range_error_function())) { - FATAL("Aborting on range error"); + base::FatalNoSecurityImpact("Aborting on range error"); } // Ignore error messages in correctness fuzzing, because the spec leaves // room for undefined behavior. @@ -839,6 +784,13 @@ bool ComputeLocation(Isolate* isolate, MessageLocation* target) { // baseline code. For optimized code this will use the deoptimization // information to get canonical location information. FrameSummaries summaries = it.frame()->Summarize(); +#if V8_ENABLE_WEBASSEMBLY + if (summaries.size() == 0) { + DCHECK_EQ(it.frame()->function()->shared()->builtin_id(), + Builtin::kWasmMethodWrapper); + return false; + } +#endif auto& summary = summaries.frames.back().AsJavaScript(); Handle<SharedFunctionInfo> shared(summary.function()->shared(), isolate); Handle<Object> script(shared->script(), isolate); @@ -979,8 +931,12 @@ Tagged<Object> ErrorUtils::ThrowSpreadArgError(Isolate* isolate, } } - isolate->ThrowAt(isolate->factory()->NewTypeError(id, callsite, object), - &location); + if (id == MessageTemplate::kSpreadIteratorSymbolNonCallable) { + isolate->ThrowAt(isolate->factory()->NewTypeError(id), &location); + } else { + isolate->ThrowAt(isolate->factory()->NewTypeError(id, callsite, object), + &location); + } return ReadOnlyRoots(isolate).exception(); } @@ -1151,6 +1107,13 @@ MaybeDirectHandle<Object> ErrorUtils::GetFormattedStack( TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.stack_trace"), perfetto::StaticString(__func__)); + if (IsAccessCheckNeeded(*maybe_error_object) && + !isolate->MayAccess(isolate->native_context(), maybe_error_object)) { + RETURN_ON_EXCEPTION(isolate, + isolate->ReportFailedAccessCheck(maybe_error_object)); + UNREACHABLE(); + } + ErrorUtils::StackPropertyLookupResult lookup = ErrorUtils::GetErrorStackProperty(isolate, maybe_error_object); @@ -1197,6 +1160,12 @@ MaybeDirectHandle<Object> ErrorUtils::GetFormattedStack( void ErrorUtils::SetFormattedStack(Isolate* isolate, DirectHandle<JSObject> maybe_error_object, DirectHandle<JSAny> formatted_stack) { + if (IsAccessCheckNeeded(*maybe_error_object) && + !isolate->MayAccess(isolate->native_context(), maybe_error_object)) { + USE(isolate->ReportFailedAccessCheck(maybe_error_object)); + return; + } + ErrorUtils::StackPropertyLookupResult lookup = ErrorUtils::GetErrorStackProperty(isolate, maybe_error_object); diff --git a/deps/v8/src/execution/mips64/simulator-mips64.cc b/deps/v8/src/execution/mips64/simulator-mips64.cc index 4849fdb635f9..819b1f69e406 100644 --- a/deps/v8/src/execution/mips64/simulator-mips64.cc +++ b/deps/v8/src/execution/mips64/simulator-mips64.cc @@ -11,6 +11,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <array> #include <cmath> #include "src/base/bits.h" @@ -308,10 +309,10 @@ void MipsDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.begin()); + PrintF(" 0x%016" PRIx64 " %s\n", sim_->get_pc(), buffer.data()); last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); @@ -470,7 +471,7 @@ void MipsDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* cur = nullptr; uint8_t* end = nullptr; @@ -509,7 +510,7 @@ void MipsDebugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), - buffer.begin()); + buffer.data()); cur += kInstrSize; } } else if (strcmp(cmd, "gdb") == 0) { @@ -599,7 +600,7 @@ void MipsDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* cur = nullptr; uint8_t* end = nullptr; @@ -626,7 +627,7 @@ void MipsDebugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), - buffer.begin()); + buffer.data()); cur += kInstrSize; } } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { @@ -7543,7 +7544,7 @@ void Simulator::InstructionDecode(Instruction* instr) { } pc_modified_ = false; - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; if (v8_flags.trace_sim) { base::SNPrintF(trace_buf_, " "); @@ -7570,8 +7571,7 @@ void Simulator::InstructionDecode(Instruction* instr) { if (v8_flags.trace_sim) { PrintF(" 0x%08" PRIxPTR " %-44s %s\n", - reinterpret_cast<intptr_t>(instr), buffer.begin(), - trace_buf_.begin()); + reinterpret_cast<intptr_t>(instr), buffer.data(), trace_buf_.data()); } if (!pc_modified_) { diff --git a/deps/v8/src/execution/mips64/simulator-mips64.h b/deps/v8/src/execution/mips64/simulator-mips64.h index ff686f57e7a7..4ac32a27456e 100644 --- a/deps/v8/src/execution/mips64/simulator-mips64.h +++ b/deps/v8/src/execution/mips64/simulator-mips64.h @@ -34,6 +34,8 @@ T Nabs(T a) { #if defined(USE_SIMULATOR) // Running with a simulator. +#include <array> + #include "src/base/hashmap.h" #include "src/base/strings.h" #include "src/codegen/assembler.h" @@ -653,7 +655,7 @@ class Simulator : public SimulatorBase { instr->OpcodeValue()); } InstructionDecode(instr); - SNPrintF(trace_buf_, " "); + base::SNPrintF(trace_buf_, " "); } // ICache. @@ -708,7 +710,7 @@ class Simulator : public SimulatorBase { bool pc_modified_; int64_t icount_; int break_count_; - base::EmbeddedVector<char, 128> trace_buf_; + std::array<char, 128> trace_buf_; // Debugger input. char* last_debugger_input_; diff --git a/deps/v8/src/execution/ppc/simulator-ppc.cc b/deps/v8/src/execution/ppc/simulator-ppc.cc index 2a96ed0400fc..4f9a86374adf 100644 --- a/deps/v8/src/execution/ppc/simulator-ppc.cc +++ b/deps/v8/src/execution/ppc/simulator-ppc.cc @@ -9,6 +9,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <array> #include <cmath> #include "src/base/bits.h" @@ -192,10 +193,10 @@ void PPCDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), buffer.begin()); + PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), buffer.data()); last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); @@ -233,11 +234,10 @@ void PPCDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), - buffer.begin()); + PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), buffer.data()); sim_->ExecuteInstruction( reinterpret_cast<Instruction*>(sim_->get_pc())); } @@ -414,7 +414,7 @@ void PPCDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* prev = nullptr; uint8_t* cur = nullptr; @@ -455,7 +455,7 @@ void PPCDebugger::Debug() { prev = cur; cur += dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev), - buffer.begin()); + buffer.data()); } } else if (strcmp(cmd, "gdb") == 0) { PrintF("relinquishing control to gdb\n"); @@ -5579,10 +5579,10 @@ void Simulator::Trace(Instruction* instr) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr)); PrintF("%05d %08" V8PRIxPTR " %s\n", icount_, - reinterpret_cast<intptr_t>(instr), buffer.begin()); + reinterpret_cast<intptr_t>(instr), buffer.data()); } // Executes the current instruction. diff --git a/deps/v8/src/execution/riscv/simulator-riscv.cc b/deps/v8/src/execution/riscv/simulator-riscv.cc index 2604e508b924..25af74faad29 100644 --- a/deps/v8/src/execution/riscv/simulator-riscv.cc +++ b/deps/v8/src/execution/riscv/simulator-riscv.cc @@ -50,6 +50,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <array> //<cfenv> is banned in Google style due to inconsistent compiler // support and potential interference with floating-point optimizations. // However, RISC-V only uses fenv.h in simulator on x64. @@ -57,6 +58,7 @@ #include "src/base/bits.h" #include "src/base/overflowing-math.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/constants-arch.h" @@ -297,7 +299,7 @@ struct type_sew_t<128> { #define VX_SLIDE1DOWN_PARAMS(x, off) \ auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \ - if ((i + off) == rvv_vlmax()) { \ + if ((i + off) == rvv_vl()) { \ type_sew_t<x>::type src = (type_sew_t<x>::type)(get_register(rs1_reg())); \ vd = src; \ } else { \ @@ -317,7 +319,7 @@ struct type_sew_t<128> { #define VF_SLIDE1DOWN_PARAMS(x, offset) \ auto& vd = Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), i, true); \ - if ((i + offset) == rvv_vlmax()) { \ + if ((i + offset) == rvv_vl()) { \ auto src = base::bit_cast<type_sew_t<x>::type>( \ get_fpu_register_Float##x(rs1_reg()).get_bits()); \ vd = src; \ @@ -1236,18 +1238,29 @@ struct type_sew_t<128> { Rvvelt<type_sew_t<x>::type>(rvv_vd_reg(), 0, true) = vd_0; \ } -#define RVV_VI_VFP_VV_LOOP_REDUCTION(BODY16, BODY32, BODY64) \ - if (rvv_vsew() == E16) { \ - UNIMPLEMENTED(); \ - } else if (rvv_vsew() == E32) { \ - VI_VFP_LOOP_REDUCTION_BASE(32) \ - BODY32; \ - VI_VFP_LOOP_REDUCTION_END(32) \ - } else if (rvv_vsew() == E64) { \ - VI_VFP_LOOP_REDUCTION_BASE(64) \ - BODY64; \ - VI_VFP_LOOP_REDUCTION_END(64) \ - } \ +#define RVV_VI_VFP_VV_LOOP_REDUCTION(BODY16, BODY32, BODY64) \ + if (rvv_vsew() == E16) { \ + uint16_t vd_0 = Rvvelt<uint16_t>(rvv_vd_reg(), 0); \ + uint16_t vs1_0 = Rvvelt<uint16_t>(rvv_vs1_reg(), 0); \ + vd_0 = vs1_0; \ + for (reg_t i = rvv_vstart(); i < rvv_vl(); ++i) { \ + RVV_VI_LOOP_MASK_SKIP(); \ + Float16 vs2 = Float16::FromBits(Rvvelt<uint16_t>(rvv_vs2_reg(), i)); \ + BODY16; \ + } \ + set_rvv_vstart(0); \ + if (rvv_vl() > 0) { \ + Rvvelt<uint16_t>(rvv_vd_reg(), 0, true) = vd_0; \ + } \ + } else if (rvv_vsew() == E32) { \ + VI_VFP_LOOP_REDUCTION_BASE(32) \ + BODY32; \ + VI_VFP_LOOP_REDUCTION_END(32) \ + } else if (rvv_vsew() == E64) { \ + VI_VFP_LOOP_REDUCTION_BASE(64) \ + BODY64; \ + VI_VFP_LOOP_REDUCTION_END(64) \ + } \ rvv_trace_vd(); // reduction loop - unsgied @@ -1327,10 +1340,10 @@ struct type_sew_t<128> { set_rvv_vstart(0); \ if (v8_flags.trace_sim) { \ int trace_offset = snprintf_vreg(rvv_vd_reg()); \ - SNPrintF(trace_buf_.SubVector(trace_offset, trace_buf_.size()), \ - " (%" PRId64 ") vlen:%" PRId64 " <-- [addr: %" REGIx_FORMAT \ - "]", \ - icount_, rvv_vlen(), (sreg_t)(get_register(rs1_reg()))); \ + SNPrintF( \ + base::VectorOf(trace_buf_).SubVector(trace_offset, trace_buf_.size()), \ + " (%" PRId64 ") vlen:%" PRId64 " <-- [addr: %" REGIx_FORMAT "]", \ + icount_, rvv_vlen(), (sreg_t)(get_register(rs1_reg()))); \ } #define RVV_VI_ST(stride, offset, elt_width, is_mask_ldst) \ @@ -1354,10 +1367,10 @@ struct type_sew_t<128> { set_rvv_vstart(0); \ if (v8_flags.trace_sim) { \ int trace_offset = snprintf_vreg(rvv_vd_reg()); \ - SNPrintF(trace_buf_.SubVector(trace_offset, trace_buf_.size()), \ - " (%" PRId64 ") vlen:%" PRId64 " --> [addr: %" REGIx_FORMAT \ - "]", \ - icount_, rvv_vlen(), (sreg_t)(get_register(rs1_reg()))); \ + SNPrintF( \ + base::VectorOf(trace_buf_).SubVector(trace_offset, trace_buf_.size()), \ + " (%" PRId64 ") vlen:%" PRId64 " --> [addr: %" REGIx_FORMAT "]", \ + icount_, rvv_vlen(), (sreg_t)(get_register(rs1_reg()))); \ } #define VI_VFP_LOOP_SCALE_BASE \ @@ -1727,13 +1740,13 @@ class RiscvDebugger { }; #define UNSUPPORTED() \ - v8::base::EmbeddedVector<char, 256> buffer; \ + std::array<char, 256> buffer; \ disasm::NameConverter converter; \ disasm::Disassembler dasm(converter); \ dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_)); \ printf("Sim: Unsupported inst. Func:%s Line:%d PC:0x%" REGIx_FORMAT, \ __FUNCTION__, __LINE__, get_pc()); \ - PrintF(" %-44s\n", buffer.begin()); \ + PrintF(" %-44s\n", buffer.data()); \ base::OS::Abort(); sreg_t RiscvDebugger::GetRegisterValue(int regnum) { @@ -1805,21 +1818,21 @@ bool RiscvDebugger::GetValue(const char* desc, sreg_t* value) { void RiscvDebugger::PrintRegs(char name_prefix, int start_index, int end_index) { - base::EmbeddedVector<char, 10> name1, name2; + std::array<char, 10> name1, name2; DCHECK(name_prefix == 'a' || name_prefix == 't' || name_prefix == 's'); DCHECK(start_index >= 0 && end_index <= 99); int num_registers = (end_index - start_index) + 1; for (int i = 0; i < num_registers / 2; i++) { - SNPrintF(name1, "%c%d", name_prefix, start_index + 2 * i); - SNPrintF(name2, "%c%d", name_prefix, start_index + 2 * i + 1); + base::SNPrintF(name1, "%c%d", name_prefix, start_index + 2 * i); + base::SNPrintF(name2, "%c%d", name_prefix, start_index + 2 * i + 1); PrintF("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \n", - REG_INFO(name1.begin()), REG_INFO(name2.begin())); + REG_INFO(name1.data()), REG_INFO(name2.data())); } if (num_registers % 2 == 1) { - SNPrintF(name1, "%c%d", name_prefix, end_index); + base::SNPrintF(name1, "%c%d", name_prefix, end_index); PrintF("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT " \n", - REG_INFO(name1.begin())); + REG_INFO(name1.data())); } } @@ -1887,14 +1900,14 @@ void RiscvDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; const char* name = sim_->builtins_.Lookup((Address)sim_->get_pc()); if (name != nullptr) { PrintF("Call builtin: %s\n", name); } dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%016" REGIx_FORMAT " %s\n", sim_->get_pc(), buffer.begin()); + PrintF(" 0x%016" REGIx_FORMAT " %s\n", sim_->get_pc(), buffer.data()); last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); @@ -2113,7 +2126,7 @@ void RiscvDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* cur = nullptr; uint8_t* end = nullptr; @@ -2152,7 +2165,7 @@ void RiscvDebugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), - buffer.begin()); + buffer.data()); cur += kInstrSize; } } else if (strcmp(cmd, "gdb") == 0) { @@ -2234,7 +2247,7 @@ void RiscvDebugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* cur = nullptr; uint8_t* end = nullptr; @@ -2261,7 +2274,7 @@ void RiscvDebugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" PRIxPTR " %s\n", reinterpret_cast<intptr_t>(cur), - buffer.begin()); + buffer.data()); cur += kInstrSize; } } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { @@ -2838,6 +2851,36 @@ T Simulator::FMaxMinHelper(T a, T b, MaxMinKind kind) { return result; } +uint16_t Simulator::F16FmaHelper(Float16 a, Float16 b, Float16 c) { + float fa = a.ToFloat32(); + float fb = b.ToFloat32(); + float fc = c.ToFloat32(); + // Any NaN operand yields the canonical quiet NaN; a signaling NaN raises + // the invalid operation flag. + if (std::isnan(fa) || std::isnan(fb) || std::isnan(fc)) { + if (isSnan(fa) || isSnan(fb) || isSnan(fc)) { + set_fflags(kInvalidOperation); + } + return kFP16DefaultNaN; + } + // Compute the exact product-sum in double precision and round once to + // Float16. This avoids the double rounding that a float intermediate would + // cause (see the declaration for the precision argument). + double result = std::fma(static_cast<double>(fa), static_cast<double>(fb), + static_cast<double>(fc)); + if (std::isnan(result)) { // e.g. Inf * 0. + set_fflags(kInvalidOperation); + return kFP16DefaultNaN; + } + return DoubleToFloat16(result); +} + +namespace { +inline Float16 NegateF16(Float16 value) { + return Float16::FromBits(static_cast<uint16_t>(value.get_bits() ^ 0x8000)); +} +} // namespace + // IEEE 754-2019 minimum/maximum for Zfa extension (fminm/fmaxm). // Like Fmax/Fmin except that if either input is NaN, the result // is the canonical NaN. @@ -2904,24 +2947,26 @@ void Simulator::TraceRegWr(int64_t value, TraceType t) { switch (t) { case WORD: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32 - " uint32:%" PRIu32, - v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32 + " uint32:%" PRIu32, + v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]); break; case DWORD: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" REGId_FORMAT - " uint64:%" PRIu64, - value, icount_, value, value); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") int64:%" REGId_FORMAT " uint64:%" PRIu64, + value, icount_, value, value); break; case FLOAT: - SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e", - v.fmt_int64, icount_, v.fmt_float[0]); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e", + v.fmt_int64, icount_, v.fmt_float[0]); break; case DOUBLE: - SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") dbl:%e", - v.fmt_int64, icount_, v.fmt_double); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 ") dbl:%e", + v.fmt_int64, icount_, v.fmt_double); break; default: UNREACHABLE(); @@ -2946,18 +2991,20 @@ void Simulator::TraceRegWr(T value, TraceType t) { } switch (t) { case WORD: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" REGId_FORMAT - " uint32:%" PRIu32, - v.fmt_int32, icount_, v.fmt_int32, v.fmt_int32); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") int32:%" REGId_FORMAT " uint32:%" PRIu32, + v.fmt_int32, icount_, v.fmt_int32, v.fmt_int32); break; case FLOAT: - SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e", - v.fmt_int32, icount_, v.fmt_float); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 ") flt:%e", + v.fmt_int32, icount_, v.fmt_float); break; case DOUBLE: - SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e", - static_cast<int64_t>(v.fmt_double), icount_, v.fmt_double); + base::SNPrintF(trace_buf_, "%016" PRIx64 " (%" PRId64 ") dbl:%e", + static_cast<int64_t>(v.fmt_double), icount_, + v.fmt_double); break; default: UNREACHABLE(); @@ -2973,46 +3020,49 @@ void Simulator::TraceMemRd(sreg_t addr, T value, sreg_t reg_value) { if (std::is_integral_v<T>) { switch (sizeof(T)) { case 1: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int8:%" PRId8 - " uint8:%" PRIu8 " <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<int8_t>(value), - static_cast<uint8_t>(value), addr); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 ") int8:%" PRId8 + " uint8:%" PRIu8 " <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<int8_t>(value), + static_cast<uint8_t>(value), addr); break; case 2: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int16:%" PRId16 - " uint16:%" PRIu16 " <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<int16_t>(value), - static_cast<uint16_t>(value), addr); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") int16:%" PRId16 " uint16:%" PRIu16 + " <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<int16_t>(value), + static_cast<uint16_t>(value), addr); break; case 4: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int32:%" PRId32 - " uint32:%" PRIu32 " <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<int32_t>(value), - static_cast<uint32_t>(value), addr); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") int32:%" PRId32 " uint32:%" PRIu32 + " <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<int32_t>(value), + static_cast<uint32_t>(value), addr); break; case 8: - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 ") int64:%" PRId64 - " uint64:%" PRIu64 " <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<int64_t>(value), - static_cast<uint64_t>(value), addr); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") int64:%" PRId64 " uint64:%" PRIu64 + " <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<int64_t>(value), + static_cast<uint64_t>(value), addr); break; default: UNREACHABLE(); } } else if (std::is_same_v<float, T>) { - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 - ") flt:%e <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<float>(value), addr); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") flt:%e <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<float>(value), addr); } else if (std::is_same_v<double, T>) { - SNPrintF(trace_buf_, - "%016" REGIx_FORMAT " (%" PRId64 - ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<double>(value), addr); + base::SNPrintF(trace_buf_, + "%016" REGIx_FORMAT " (%" PRId64 + ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<double>(value), addr); } else { UNREACHABLE(); } @@ -3021,29 +3071,31 @@ void Simulator::TraceMemRd(sreg_t addr, T value, sreg_t reg_value) { void Simulator::TraceMemRdFloat(sreg_t addr, Float32 value, int64_t reg_value) { if (v8_flags.trace_sim) { - SNPrintF(trace_buf_, - "%016" PRIx64 " (%" PRId64 - ") flt:%e <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<float>(value.get_scalar()), addr); + base::SNPrintF(trace_buf_, + "%016" PRIx64 " (%" PRId64 + ") flt:%e <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<float>(value.get_scalar()), + addr); } } void Simulator::TraceMemRdDouble(sreg_t addr, double value, int64_t reg_value) { if (v8_flags.trace_sim) { - SNPrintF(trace_buf_, - "%016" PRIx64 " (%" PRId64 - ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<double>(value), addr); + base::SNPrintF(trace_buf_, + "%016" PRIx64 " (%" PRId64 + ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<double>(value), addr); } } void Simulator::TraceMemRdDouble(sreg_t addr, Float64 value, int64_t reg_value) { if (v8_flags.trace_sim) { - SNPrintF(trace_buf_, - "%016" PRIx64 " (%" PRId64 - ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", - reg_value, icount_, static_cast<double>(value.get_scalar()), addr); + base::SNPrintF(trace_buf_, + "%016" PRIx64 " (%" PRId64 + ") dbl:%e <-- [addr: %" REGIx_FORMAT "]", + reg_value, icount_, static_cast<double>(value.get_scalar()), + addr); } } @@ -3052,47 +3104,48 @@ void Simulator::TraceMemWr(sreg_t addr, T value) { if (v8_flags.trace_sim) { switch (sizeof(T)) { case 1: - SNPrintF(trace_buf_, - " (%" PRIu64 ") int8:%" PRId8 - " uint8:%" PRIu8 " --> [addr: %" REGIx_FORMAT "]", - icount_, static_cast<int8_t>(value), - static_cast<uint8_t>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 ") int8:%" PRId8 + " uint8:%" PRIu8 " --> [addr: %" REGIx_FORMAT "]", + icount_, static_cast<int8_t>(value), + static_cast<uint8_t>(value), addr); break; case 2: - SNPrintF(trace_buf_, - " (%" PRIu64 ") int16:%" PRId16 - " uint16:%" PRIu16 " --> [addr: %" REGIx_FORMAT "]", - icount_, static_cast<int16_t>(value), - static_cast<uint16_t>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 ") int16:%" PRId16 + " uint16:%" PRIu16 " --> [addr: %" REGIx_FORMAT "]", + icount_, static_cast<int16_t>(value), + static_cast<uint16_t>(value), addr); break; case 4: if (std::is_integral_v<T>) { - SNPrintF(trace_buf_, - " (%" PRIu64 ") int32:%" PRId32 - " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]", - icount_, static_cast<int32_t>(value), - static_cast<uint32_t>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 ") int32:%" PRId32 + " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]", + icount_, static_cast<int32_t>(value), + static_cast<uint32_t>(value), addr); } else { - SNPrintF(trace_buf_, - " (%" PRIu64 - ") flt:%e bit:%x --> [addr: %" REGIx_FORMAT "]", - icount_, static_cast<float>(value), - base::bit_cast<int32_t, float>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 + ") flt:%e bit:%x --> [addr: %" REGIx_FORMAT "]", + icount_, static_cast<float>(value), + base::bit_cast<int32_t, float>(value), addr); } break; case 8: if (std::is_integral_v<T>) { - SNPrintF(trace_buf_, - " (%" PRIu64 ") int64:%" PRId64 - " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]", - icount_, static_cast<int64_t>(value), - static_cast<uint64_t>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 ") int64:%" PRId64 + " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]", + icount_, static_cast<int64_t>(value), + static_cast<uint64_t>(value), addr); } else { - SNPrintF(trace_buf_, - " (%" PRIu64 ") dbl:%e bit:%" PRIx64 - " --> [addr: %" REGIx_FORMAT "]", - icount_, static_cast<double>(value), - base::bit_cast<int64_t, double>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 + ") dbl:%e bit:%" PRIx64 " --> [addr: %" REGIx_FORMAT + "]", + icount_, static_cast<double>(value), + base::bit_cast<int64_t, double>(value), addr); } break; default: @@ -3103,10 +3156,11 @@ void Simulator::TraceMemWr(sreg_t addr, T value) { void Simulator::TraceMemWrDouble(sreg_t addr, double value) { if (v8_flags.trace_sim) { - SNPrintF(trace_buf_, - " (%" PRIu64 ") dbl:%e bit:%" PRIx64 - "--> [addr: %" REGIx_FORMAT "]", - icount_, value, base::bit_cast<int64_t, double>(value), addr); + base::SNPrintF(trace_buf_, + " (%" PRIu64 ") dbl:%e bit:%" PRIx64 + "--> [addr: %" REGIx_FORMAT "]", + icount_, value, base::bit_cast<int64_t, double>(value), + addr); } } // RISCV Memory Read/Write functions @@ -7226,15 +7280,15 @@ void Simulator::DecodeRvvIVV() { break; } default: - // v8::base::EmbeddedVector<char, 256> buffer; - // SNPrintF(trace_buf_, " "); + // std::array<char, 256> buffer; + // base::SNPrintF(trace_buf_, " "); // disasm::NameConverter converter; // disasm::Disassembler dasm(converter); // // Use a reasonably large buffer. // dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_)); // PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n", - // reinterpret_cast<intptr_t>(&instr_), buffer.begin()); + // reinterpret_cast<intptr_t>(&instr_), buffer.data()); UNIMPLEMENTED_RISCV(); break; } @@ -7813,12 +7867,12 @@ void Simulator::DecodeRvvMVV() { set_register(rd_reg(), index); rvv_trace_vd(); } else { - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; disasm::NameConverter converter; disasm::Disassembler dasm(converter); dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_)); PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n", - reinterpret_cast<intptr_t>(&instr_), buffer.begin()); + reinterpret_cast<intptr_t>(&instr_), buffer.data()); UNIMPLEMENTED_RISCV(); } } break; @@ -7909,12 +7963,12 @@ void Simulator::DecodeRvvMVV() { rvv_trace_vd(); } break; default: - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; disasm::NameConverter converter; disasm::Disassembler dasm(converter); dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_)); PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n", - reinterpret_cast<intptr_t>(&instr_), buffer.begin()); + reinterpret_cast<intptr_t>(&instr_), buffer.data()); UNIMPLEMENTED_RISCV(); break; } @@ -8018,12 +8072,12 @@ void Simulator::DecodeRvvMVX() { rvv_trace_vd(); } break; default: - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; disasm::NameConverter converter; disasm::Disassembler dasm(converter); dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(&instr_)); PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n", - reinterpret_cast<intptr_t>(&instr_), buffer.begin()); + reinterpret_cast<intptr_t>(&instr_), buffer.data()); UNIMPLEMENTED_RISCV(); break; } @@ -8481,8 +8535,10 @@ void Simulator::DecodeRvvFVV() { case RO_V_VFMAX_VV: { RVV_VI_VFP_VV_LOOP( { - vd = FMaxMinHelper(vs2.ToFloat32(), vs1.ToFloat32(), - MaxMinKind::kMax); + vd = Float16::FromFloat32(FMaxMinHelper(vs2.ToFloat32(), + vs1.ToFloat32(), + MaxMinKind::kMax)) + .get_bits(); }, { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMax); }, { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMax); }) @@ -8490,7 +8546,12 @@ void Simulator::DecodeRvvFVV() { } case RO_V_VFREDMAX_VV: { RVV_VI_VFP_VV_LOOP_REDUCTION( - { UNIMPLEMENTED(); }, + { + vd_0 = Float16::FromFloat32( + FMaxMinHelper(Float16::FromBits(vd_0).ToFloat32(), + vs2.ToFloat32(), MaxMinKind::kMax)) + .get_bits(); + }, { vd_0 = FMaxMinHelper(vd_0, vs2, MaxMinKind::kMax); }, { vd_0 = FMaxMinHelper(vd_0, vs2, MaxMinKind::kMax); }) break; @@ -8498,8 +8559,10 @@ void Simulator::DecodeRvvFVV() { case RO_V_VFMIN_VV: { RVV_VI_VFP_VV_LOOP( { - vd = FMaxMinHelper(vs2.ToFloat32(), vs1.ToFloat32(), - MaxMinKind::kMin); + vd = Float16::FromFloat32(FMaxMinHelper(vs2.ToFloat32(), + vs1.ToFloat32(), + MaxMinKind::kMin)) + .get_bits(); }, { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMin); }, { vd = FMaxMinHelper(vs2, vs1, MaxMinKind::kMin); }) @@ -8744,15 +8807,41 @@ void Simulator::DecodeRvvFVV() { case RO_V_VFWREDOSUM_VS: RVV_VI_CHECK_DSS(true); switch (rvv_vsew()) { - case E16: + case E16: { + float vs1 = Rvvelt<float>(rvv_vs1_reg(), 0); + float alu_out = vs1; + for (uint64_t i = rvv_vstart(); i < rvv_vl(); ++i) { + RVV_VI_LOOP_MASK_SKIP(); + float vs2 = Float16::FromBits(Rvvelt<uint16_t>(rvv_vs2_reg(), i)) + .ToFloat32(); + if (is_invalid_fadd(alu_out, vs2)) { + set_fflags(kInvalidOperation); + alu_out = std::numeric_limits<float>::quiet_NaN(); + break; + } + alu_out = alu_out + vs2; + if (std::isnan(alu_out) || std::isnan(vs2)) { + // signaling_nan sets kInvalidOperation bit + if (isSnan(alu_out) || isSnan(vs2)) set_fflags(kInvalidOperation); + alu_out = std::numeric_limits<float>::quiet_NaN(); + break; + } + } + // Only update the destination when at least one element is active, + // matching the RVV reduction semantics. + if (rvv_vl() > 0) { + Rvvelt<float>(rvv_vd_reg(), 0, true) = alu_out; + } + break; + } case E64: { UNIMPLEMENTED(); } case E32: { - double& vd = Rvvelt<double>(rvv_vd_reg(), 0, true); double vs1 = Rvvelt<double>(rvv_vs1_reg(), 0); double alu_out = vs1; for (uint64_t i = rvv_vstart(); i < rvv_vl(); ++i) { + RVV_VI_LOOP_MASK_SKIP(); double vs2 = static_cast<double>(Rvvelt<float>(rvv_vs2_reg(), i)); if (is_invalid_fadd(alu_out, vs2)) { set_fflags(kInvalidOperation); @@ -8767,7 +8856,9 @@ void Simulator::DecodeRvvFVV() { break; } } - vd = alu_out; + if (rvv_vl() > 0) { + Rvvelt<double>(rvv_vd_reg(), 0, true) = alu_out; + } break; } default: @@ -8778,56 +8869,28 @@ void Simulator::DecodeRvvFVV() { break; case RO_V_VFMADD_VV: RVV_VI_VFP_FMA_VV_LOOP( - { - float src1 = vs1.ToFloat32(); - float src2 = vs2.ToFloat32(); - float dst = Float16::FromBits(vd).ToFloat32(); - float alu_out = std::fma(dst, src1, src2); - - if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) || - std::isnan(dst)) { - // signaling_nan sets kInvalidOperation bit - if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || - isSnan(dst)) { - set_fflags(kInvalidOperation); - } - alu_out = std::numeric_limits<float>::quiet_NaN(); - } - vd = Float16::FromFloat32(alu_out).get_bits(); - }, + { vd = F16FmaHelper(Float16::FromBits(vd), vs1, vs2); }, {RVV_VI_VFP_FMA(float, vd, vs1, vs2)}, {RVV_VI_VFP_FMA(double, vd, vs1, vs2)}) break; case RO_V_VFNMADD_VV: RVV_VI_VFP_FMA_VV_LOOP( { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); + vd = F16FmaHelper(NegateF16(Float16::FromBits(vd)), vs1, + NegateF16(vs2)); }, {RVV_VI_VFP_FMA(float, -vd, vs1, -vs2)}, {RVV_VI_VFP_FMA(double, -vd, vs1, -vs2)}) break; case RO_V_VFMSUB_VV: RVV_VI_VFP_FMA_VV_LOOP( - { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); - }, + { vd = F16FmaHelper(Float16::FromBits(vd), vs1, NegateF16(vs2)); }, {RVV_VI_VFP_FMA(float, vd, vs1, -vs2)}, {RVV_VI_VFP_FMA(double, vd, vs1, -vs2)}) break; case RO_V_VFNMSUB_VV: RVV_VI_VFP_FMA_VV_LOOP( - { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); - }, + { vd = F16FmaHelper(NegateF16(Float16::FromBits(vd)), vs1, vs2); }, { float alu_out = std::fma(-vd, vs1, +vs2); @@ -8844,45 +8907,28 @@ void Simulator::DecodeRvvFVV() { break; case RO_V_VFMACC_VV: RVV_VI_VFP_FMA_VV_LOOP( - { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); - }, + { vd = F16FmaHelper(vs2, vs1, Float16::FromBits(vd)); }, {RVV_VI_VFP_FMA(float, vs2, vs1, vd)}, {RVV_VI_VFP_FMA(double, vs2, vs1, vd)}) break; case RO_V_VFNMACC_VV: RVV_VI_VFP_FMA_VV_LOOP( { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); + vd = F16FmaHelper(NegateF16(vs2), vs1, + NegateF16(Float16::FromBits(vd))); }, {RVV_VI_VFP_FMA(float, -vs2, vs1, -vd)}, {RVV_VI_VFP_FMA(double, -vs2, vs1, -vd)}) break; case RO_V_VFMSAC_VV: RVV_VI_VFP_FMA_VV_LOOP( - { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); - }, + { vd = F16FmaHelper(vs2, vs1, NegateF16(Float16::FromBits(vd))); }, {RVV_VI_VFP_FMA(float, vs2, vs1, -vd)}, {RVV_VI_VFP_FMA(double, vs2, vs1, -vd)}) break; case RO_V_VFNMSAC_VV: RVV_VI_VFP_FMA_VV_LOOP( - { - UNIMPLEMENTED(); - USE(vd); - USE(vs1); - USE(vs2); - }, + { vd = F16FmaHelper(NegateF16(vs2), vs1, Float16::FromBits(vd)); }, {RVV_VI_VFP_FMA(float, -vs2, vs1, +vd)}, {RVV_VI_VFP_FMA(double, -vs2, vs1, +vd)}) break; @@ -9362,17 +9408,17 @@ void Simulator::InstructionDecode(Instruction* instr) { } pc_modified_ = false; - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; if (v8_flags.trace_sim || v8_flags.debug_sim) { - SNPrintF(trace_buf_, " "); + base::SNPrintF(trace_buf_, " "); disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr)); // PrintF("EXECUTING 0x%08" PRIxPTR " %-44s\n", - // reinterpret_cast<intptr_t>(instr), buffer.begin()); + // reinterpret_cast<intptr_t>(instr), buffer.data()); } #ifdef CAN_USE_RVV_INSTRUCTIONS set_vill_ignore(false); @@ -9436,15 +9482,14 @@ void Simulator::InstructionDecode(Instruction* instr) { if (1) { std::cout << "Unrecognized instruction [@pc=0x" << std::hex << registers_[pc] << "]: 0x" << instr->InstructionBits() - << std::endl; + << std::dec << std::endl; } UNSUPPORTED(); } if (v8_flags.trace_sim) { PrintF(" 0x%012" PRIxPTR " %-44s\t%s\n", - reinterpret_cast<intptr_t>(instr), buffer.begin(), - trace_buf_.begin()); + reinterpret_cast<intptr_t>(instr), buffer.data(), trace_buf_.data()); } if (!pc_modified_) { @@ -9581,10 +9626,10 @@ void Simulator::PushShadowStack(uintptr_t value) { size_t old_size = shadow_stack_.size(); size_t new_size = old_size * 2; size_t new_ssp = new_size - old_size; - auto new_stack = base::Vector<uintptr_t>::New(new_size); - new_stack.SubVectorFrom(new_ssp).OverwriteWith(shadow_stack_); - shadow_stack_.Dispose(); - shadow_stack_ = new_stack; + auto new_stack = base::UniqueArray<uintptr_t>::New(new_size); + std::copy(shadow_stack_.begin(), shadow_stack_.end(), + new_stack.subspan(new_ssp).begin()); + shadow_stack_ = std::move(new_stack); csr_ssp_ = new_ssp; } csr_ssp_ = csr_ssp_ - 1; @@ -9594,8 +9639,8 @@ void Simulator::PushShadowStack(uintptr_t value) { ") ssp:%zu\n", value, icount_, csr_ssp_); } - SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") ssp:%zu", - value, icount_, csr_ssp_); + base::SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") ssp:%zu", + value, icount_, csr_ssp_); return; } @@ -9620,8 +9665,8 @@ uintptr_t Simulator::PopShadowStack(uintptr_t value) { PrintF("PopShadowStack %016" REGIx_FORMAT " (%" PRId64 ") ssp:%zu\n", temp, icount_, csr_ssp_ - 1); } - SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") ssp:%zu", temp, - icount_, csr_ssp_ - 1); + base::SNPrintF(trace_buf_, "%016" REGIx_FORMAT " (%" PRId64 ") ssp:%zu", + temp, icount_, csr_ssp_ - 1); return temp; } @@ -9666,7 +9711,7 @@ void Simulator::CallImpl(Address entry, CallArgument* args) { << " fa3 = 0x" << get_fpu_register(fa3) << " fa4 = 0x" << get_fpu_register(fa4) << " fa5 = 0x" << get_fpu_register(fa5) << " fa6 = 0x" << get_fpu_register(fa6) << " fa7 = 0x" - << get_fpu_register(fa7) << std::endl; + << get_fpu_register(fa7) << std::dec << std::endl; } // Remaining arguments passed on stack. int64_t original_stack = get_register(sp); @@ -9709,7 +9754,7 @@ intptr_t Simulator::CallImpl(Address entry, int argument_count, << " a2 (func/target) = 0x" << get_register(a2) << " a3 (receiver) = 0x" << get_register(a3) << " a4 (argc) = 0x" << get_register(a4) << " a5 (argv) = 0x" << get_register(a5) - << std::endl; + << std::dec << std::endl; } // Remaining arguments passed on stack. sreg_t original_stack = get_register(sp); diff --git a/deps/v8/src/execution/riscv/simulator-riscv.h b/deps/v8/src/execution/riscv/simulator-riscv.h index 879b447341f8..a9e7b9cec9a4 100644 --- a/deps/v8/src/execution/riscv/simulator-riscv.h +++ b/deps/v8/src/execution/riscv/simulator-riscv.h @@ -50,6 +50,7 @@ #define V8_EXECUTION_RISCV_SIMULATOR_RISCV_H_ // globals.h defines USE_SIMULATOR. +#include <array> #include <functional> #include "src/base/float16.h" @@ -77,6 +78,7 @@ typedef unsigned __uint128_t __attribute__((__mode__(__TI__))); // Running with a simulator. #include "src/base/hashmap.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler.h" #include "src/codegen/constants-arch.h" #include "src/execution/simulator-base.h" @@ -553,6 +555,14 @@ class Simulator : public SimulatorBase { template <typename T> T FMaxMinHelper(T a, T b, MaxMinKind kind); + // Fused multiply-add of three Float16 operands with a single rounding to + // Float16. The intermediate computation is done in double precision, whose + // 53-bit significand is far more than the 2*11+2 bits needed to make the + // additional rounding innocuous (avoids the double rounding that a float + // intermediate would introduce). Returns the canonical quiet NaN and raises + // the invalid operation flag for signaling NaNs / invalid operations. + uint16_t F16FmaHelper(Float16 a, Float16 b, Float16 c); + // IEEE 754-2019 minimum/maximum for Zfa extension (fminm/fmaxm). template <typename T> T FMaxMinMHelper(T a, T b, MaxMinKind kind); @@ -949,8 +959,9 @@ class Simulator : public SimulatorBase { for (int i = VRegisterValue::kChunks - 1; i >= 0; i--) { const char* format = i != VRegisterValue::kChunks - 1 ? "_%016" PRIx64 : "%016" PRIx64; - int written = SNPrintF(trace_buf_.SubVector(offset, trace_buf_.size()), - format, value.chunks[i]); + int written = SNPrintF( + base::VectorOf(trace_buf_).SubVector(offset, trace_buf_.size()), + format, value.chunks[i]); offset += written; } return offset; @@ -959,7 +970,7 @@ class Simulator : public SimulatorBase { inline void rvv_trace_vd() { if (v8_flags.trace_sim) { int offset = snprintf_vreg(rvv_vd_reg()); - SNPrintF(trace_buf_.SubVector(offset, trace_buf_.size()), + SNPrintF(base::VectorOf(trace_buf_).SubVector(offset, trace_buf_.size()), " (%" PRId64 ")", icount_); } } @@ -995,7 +1006,7 @@ class Simulator : public SimulatorBase { for (; i < trace_buf_.size(); i++) { if (trace_buf_[i] == '\0') break; } - SNPrintF(trace_buf_.SubVector(i, trace_buf_.size()), + SNPrintF(base::VectorOf(trace_buf_).SubVector(i, trace_buf_.size()), " sew:%s lmul:%s vstart:%" PRId64 " vl:%" PRId64, rvv_sew_s(), rvv_lmul_s(), rvv_vstart(), rvv_vl()); } @@ -1289,8 +1300,8 @@ class Simulator : public SimulatorBase { // Floating-point control and status register. uint32_t FCSR_; - base::Vector<uintptr_t> shadow_stack_ = - base::Vector<uintptr_t>::New(kInitialShadowStackSize); + base::UniqueArray<uintptr_t> shadow_stack_ = + base::UniqueArray<uintptr_t>::New(kInitialShadowStackSize); size_t csr_ssp_ = shadow_stack_.size(); // Shadow stack pointer int64_t ss_mismatch_count_ = 0; @@ -1333,7 +1344,7 @@ class Simulator : public SimulatorBase { sreg_t* watch_address_ = nullptr; sreg_t watch_value_ = 0; int break_count_; - base::EmbeddedVector<char, 256> trace_buf_; + std::array<char, 256> trace_buf_; // Debugger input. char* last_debugger_input_; diff --git a/deps/v8/src/execution/s390/simulator-s390.cc b/deps/v8/src/execution/s390/simulator-s390.cc index 47d1b9ef3a52..b9677b2649d7 100644 --- a/deps/v8/src/execution/s390/simulator-s390.cc +++ b/deps/v8/src/execution/s390/simulator-s390.cc @@ -10,6 +10,7 @@ #include <stdarg.h> #include <stdlib.h> +#include <array> #include <cmath> #include "src/base/bits.h" @@ -202,10 +203,10 @@ void S390Debugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), buffer.begin()); + PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), buffer.data()); last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); @@ -242,7 +243,7 @@ void S390Debugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; if (GetValue(arg1, &value)) { // Interpret a numeric argument as the number of instructions to @@ -251,7 +252,7 @@ void S390Debugger::Debug() { dasm.InstructionDecode( buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), - buffer.begin()); + buffer.data()); sim_->ExecuteInstruction( reinterpret_cast<Instruction*>(sim_->get_pc())); } @@ -261,14 +262,14 @@ void S390Debugger::Debug() { while (!sim_->has_bad_pc()) { dasm.InstructionDecode( buffer, reinterpret_cast<uint8_t*>(sim_->get_pc())); - char* mnemonicStart = buffer.begin(); + char* mnemonicStart = buffer.data(); while (*mnemonicStart != 0 && *mnemonicStart != ' ') mnemonicStart++; SScanF(mnemonicStart, "%s", mnemonic); if (!strcmp(arg1, mnemonic)) break; PrintF(" 0x%08" V8PRIxPTR " %s\n", sim_->get_pc(), - buffer.begin()); + buffer.data()); sim_->ExecuteInstruction( reinterpret_cast<Instruction*>(sim_->get_pc())); } @@ -443,7 +444,7 @@ void S390Debugger::Debug() { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; uint8_t* prev = nullptr; uint8_t* cur = nullptr; @@ -483,7 +484,7 @@ void S390Debugger::Debug() { prev = cur; cur += dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev), - buffer.begin()); + buffer.data()); numInstructions--; } } else if (strcmp(cmd, "gdb") == 0) { @@ -2501,10 +2502,10 @@ void Simulator::ExecuteInstruction(Instruction* instr, bool auto_incr_pc) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // use a reasonably large buffer - v8::base::EmbeddedVector<char, 256> buffer; + std::array<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr)); PrintF("%05" PRId64 " %08" V8PRIxPTR " %s\n", icount_, - reinterpret_cast<intptr_t>(instr), buffer.begin()); + reinterpret_cast<intptr_t>(instr), buffer.data()); // Flush stdout to prevent incomplete file output during abnormal exits // This is caused by the output being buffered before being written to file diff --git a/deps/v8/src/execution/stack-guard.cc b/deps/v8/src/execution/stack-guard.cc index 33f0a514e757..cf5d7f5f8aeb 100644 --- a/deps/v8/src/execution/stack-guard.cc +++ b/deps/v8/src/execution/stack-guard.cc @@ -383,6 +383,9 @@ Tagged<Object> StackGuard::HandleInterrupts(InterruptLevel level) { TRACE_EVENT("v8.execute", "V8.InvokeApiInterruptCallbacks"); // Callbacks must be invoked outside of ExecutionAccess lock. isolate_->InvokeApiInterruptCallbacks(); + if (isolate_->debug()->IsRestartFrameScheduled()) { + return isolate_->TerminateExecution(); + } } #ifdef V8_RUNTIME_CALL_STATS diff --git a/deps/v8/src/execution/x64/frame-constants-x64.cc b/deps/v8/src/execution/x64/frame-constants-x64.cc index df612a08cfd0..ea00b4e34b87 100644 --- a/deps/v8/src/execution/x64/frame-constants-x64.cc +++ b/deps/v8/src/execution/x64/frame-constants-x64.cc @@ -18,12 +18,15 @@ Register JavaScriptFrame::context_register() { return rsi; } Register JavaScriptFrame::constant_pool_pointer_register() { UNREACHABLE(); } int UnoptimizedFrameConstants::RegisterStackSlotCount(int register_count) { - return register_count; + return V8_X64_16BYTE_STACK_ALIGNMENT_BOOL ? RoundUp(register_count, 2) + : register_count; } int BuiltinContinuationFrameConstants::PaddingSlotCount(int register_count) { - USE(register_count); - return 0; + return V8_X64_16BYTE_STACK_ALIGNMENT_BOOL + ? (RoundUp(kFixedSlotCount + register_count, 2) - + (kFixedSlotCount + register_count)) + : 0; } // static diff --git a/deps/v8/src/extensions/cputracemark-extension.h b/deps/v8/src/extensions/cputracemark-extension.h index 43287fb43470..1ae5b58cbbbc 100644 --- a/deps/v8/src/extensions/cputracemark-extension.h +++ b/deps/v8/src/extensions/cputracemark-extension.h @@ -28,8 +28,7 @@ class CpuTraceMarkExtension : public v8::Extension { static void Mark(const v8::FunctionCallbackInfo<v8::Value>& info); static const char* BuildSource(char* buf, size_t size, const char* fun_name) { - base::SNPrintF(base::VectorOf(buf, size), "native function %s();", - fun_name); + base::SNPrintF({buf, size}, "native function %s();", fun_name); return buf; } diff --git a/deps/v8/src/extensions/gc-extension.h b/deps/v8/src/extensions/gc-extension.h index c6f4e5100132..178b1b66c65d 100644 --- a/deps/v8/src/extensions/gc-extension.h +++ b/deps/v8/src/extensions/gc-extension.h @@ -61,8 +61,7 @@ class GCExtension : public v8::Extension { private: static const char* BuildSource(char* buf, size_t size, const char* fun_name) { - base::SNPrintF(base::VectorOf(buf, size), "native function %s();", - fun_name); + base::SNPrintF({buf, size}, "native function %s();", fun_name); return buf; } diff --git a/deps/v8/src/flags/feature-flags.h b/deps/v8/src/flags/feature-flags.h index 5e9a1643f1ca..0f933cd05fba 100644 --- a/deps/v8/src/flags/feature-flags.h +++ b/deps/v8/src/flags/feature-flags.h @@ -67,9 +67,6 @@ \ JS_FEATURE(harmony_shadow_realm, "harmony ShadowRealm") \ \ - JS_FEATURE(harmony_struct, \ - "harmony structs, shared structs, and shared arrays") \ - \ IF_INTL_ENABLED(JS_FEATURE, harmony_intl_best_fit_matcher, \ "Intl BestFitMatcher") \ \ @@ -77,17 +74,10 @@ \ JS_FEATURE(js_source_phase_imports, "source phase imports") \ \ - JS_FEATURE(js_regexp_buffer_boundaries, \ - "RegExp \\A \\z \\Z buffer boundary assertions") \ - \ IF_SPARKPLUG_PLUS_ENABLED(INTERNAL_FEATURE, sparkplug_inline_smi, \ "inline the Smi fast path of embedded feedback " \ "operations into JS baseline code") \ \ - /* V8 side owner: leszeks */ \ - INTERNAL_FEATURE(always_specialize_for_script_context, \ - "always specialize for script contexts in optimized code") \ - \ /* Instruction Tracing tool convention (early prototype, might change) */ \ /* Tool convention: https://github.com/WebAssembly/tool-conventions */ \ /* V8 side owner: jabraham */ \ @@ -119,12 +109,7 @@ WASM_FEATURE(compilation_hints, "compilation hints") \ \ /* V8 side owner: thibaudm */ \ - WASM_FEATURE(growable_stacks, "growable stacks for jspi") \ - \ - /* Compact Import Section proposal. */ \ - /* https://github.com/WebAssembly/compact-import-section */ \ - /* V8 side owner: ryandiaz */ \ - WASM_FEATURE(compact_imports, "compact import section") + WASM_FEATURE(growable_stacks, "growable stacks for jspi") // ############################################################################# // Pre-staged features (disabled by default, but enabled via @@ -135,6 +120,15 @@ #define FOREACH_PRE_STAGED_FEATURE_FLAG(JS_FEATURE, WASM_FEATURE, \ INTERNAL_FEATURE) /* (80 columns) */ \ \ + /* V8 side owner: leszeks */ \ + INTERNAL_FEATURE(always_specialize_for_script_context, \ + "always specialize for script contexts in optimized code") \ + \ + /* V8 side owner: leszeks */ \ + INTERNAL_FEATURE( \ + code_cache_source_hash_sha256, \ + "hashing code cache source string with SHA256 instead of string length") \ + \ /* Reference-Typed Strings Proposal. */ \ /* https://github.com/WebAssembly/stringref */ \ /* V8 side owner: jkummerow */ \ @@ -149,7 +143,12 @@ /* proposal. */ \ /* Part of https://github.com/WebAssembly/shared-everything-threads */ \ /* V8 side owner: rezvan */ \ - WASM_FEATURE(acquire_release, "acquire_release memory ordering") + WASM_FEATURE(acquire_release, "acquire_release memory ordering") \ + \ + /* Compact Import Section proposal. */ \ + /* https://github.com/WebAssembly/compact-import-section */ \ + /* V8 side owner: ryandiaz */ \ + WASM_FEATURE(compact_imports, "compact import section") // ############################################################################# // Staged features (disabled by default, but enabled via --js-staging/--harmony, @@ -173,6 +172,9 @@ \ JS_FEATURE(js_defer_import_eval, "defer import eval") \ \ + JS_FEATURE(js_regexp_buffer_boundaries, \ + "RegExp \\A \\z \\Z buffer boundary assertions") \ + \ /* Custom Descriptors proposal. */ \ /* https://github.com/WebAssembly/custom-descriptors */ \ /* Note: the JS Interop part of the proposal is enabled by */ \ diff --git a/deps/v8/src/flags/flag-definitions.h b/deps/v8/src/flags/flag-definitions.h index 528cf0e9c059..100223f13fec 100644 --- a/deps/v8/src/flags/flag-definitions.h +++ b/deps/v8/src/flags/flag-definitions.h @@ -12,23 +12,31 @@ // // PRESUBMIT_INTENTIONALLY_MISSING_INCLUDE_GUARD +// Enforces that `thenflag` is set to `true` if `cond` holds. #define DEFINE_IMPLICATION(cond, thenflag) \ DEFINE_VALUE_IMPLICATION(cond, thenflag, true) -// A weak implication will be overwritten by a normal implication or by an -// explicit flag. +// Enforces that `thenflag` is weakly set to `true` if `cond` holds. A weak +// implication is overwritten by a normal implication or by an explicit flag. #define DEFINE_WEAK_IMPLICATION(cond, thenflag) \ DEFINE_WEAK_VALUE_IMPLICATION(cond, thenflag, true) +// Enforces that `thenflag` is weakly set to `false` if `cond` holds. A weak +// implication is overwritten by a normal implication or by an explicit flag. #define DEFINE_WEAK_NEG_IMPLICATION(cond, thenflag) \ DEFINE_WEAK_VALUE_IMPLICATION(cond, thenflag, false) +// Enforces that `thenflag` is set to `false` if `cond` holds. #define DEFINE_NEG_IMPLICATION(cond, thenflag) \ DEFINE_VALUE_IMPLICATION(cond, thenflag, false) +// Enforces that `thenflag` is set to `false` if `whenflag` is `false`. #define DEFINE_NEG_NEG_IMPLICATION(whenflag, thenflag) \ DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, false) +// Unconditionally marks `flag` as unsafe (see `DISALLOW_UNSAFE_FLAG_IF`). +#define DISALLOW_UNSAFE_FLAG(flag) DISALLOW_UNSAFE_FLAG_IF(true, flag) + // With FLAG_MODE_DECLARE we declare the fields in the {FlagValues} struct. // Read-only flags are static constants instead of fields. #if defined(FLAG_MODE_DECLARE) @@ -59,19 +67,22 @@ // We produce the code to set flags when it is implied by another flag. #elif defined(FLAG_MODE_DEFINE_IMPLICATIONS) +// Enforces that `thenflag` is set to `value` if `cond` holds. #define DEFINE_VALUE_IMPLICATION(cond, thenflag, value) \ changed |= TriggerImplication(cond, #cond, &v8_flags.thenflag, #thenflag, \ - value, false); + value, kStrongImplication); -// A weak implication will be overwritten by a normal implication or by an -// explicit flag. +// Enforces that `thenflag` is weakly set to `value` if `cond` holds. A weak +// implication is overwritten by a normal implication or by an explicit flag. #define DEFINE_WEAK_VALUE_IMPLICATION(cond, thenflag, value) \ changed |= TriggerImplication(cond, #cond, &v8_flags.thenflag, #thenflag, \ - value, true); + value, kWeakImplication); +// Executes `statement` if `cond` holds. #define DEFINE_GENERIC_IMPLICATION(cond, statement) \ if (cond) statement; +// Enforces that `statement` holds, reporting a flag error otherwise. #define DEFINE_REQUIREMENT(statement) \ do { \ if (V8_UNLIKELY(!(statement))) { \ @@ -80,31 +91,36 @@ } \ } while (false); -// Enforce that a flag was not explicitly set via command line. Setting a value -// via implications is still allowed. -#define DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(cond, thenflag) \ - TriggerNotExplicitlySetImplication(cond, #cond, #thenflag); - -#define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value) \ - changed |= TriggerImplication(!(whenflag), "!" #whenflag, \ - &v8_flags.thenflag, #thenflag, value, false); +// Enforces that `thenflag` is set to `value` if `whenflag` is `false`. +#define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value) \ + changed |= \ + TriggerImplication(!(whenflag), "!" #whenflag, &v8_flags.thenflag, \ + #thenflag, value, kStrongImplication); +// Enforces that `thenflag` is set to `thenvalue` if `whenflag != whenvalue`. #define DEFINE_NEG_VALUE_VALUE_IMPLICATION(whenflag, whenvalue, thenflag, \ thenvalue) \ - changed |= \ - TriggerImplication(v8_flags.whenflag != whenvalue, #whenflag, \ - &v8_flags.thenflag, #thenflag, thenvalue, false); - -#define DEFINE_MIN_VALUE_IMPLICATION(flag, min_value) \ - changed |= \ - TriggerImplication(v8_flags.flag < min_value, #flag "<" #min_value, \ - &v8_flags.flag, #flag, min_value, false); - -#define DEFINE_MAX_VALUE_IMPLICATION(flag, max_value) \ - changed |= \ - TriggerImplication(v8_flags.flag > max_value, #max_value "<" #flag, \ - &v8_flags.flag, #flag, max_value, false); - + changed |= TriggerImplication( \ + !FlagValueEquals(v8_flags.whenflag.value(), whenvalue), \ + NegValuePremiseName(whenvalue, #whenflag, "!" #whenflag), \ + &v8_flags.thenflag, #thenflag, thenvalue, kStrongImplication); + +// Enforces that `flag` is at least `min_value` (sets `flag = min_value` if +// `flag < min_value`). +#define DEFINE_MIN_VALUE_IMPLICATION(flag, min_value) \ + changed |= TriggerImplication(v8_flags.flag < min_value, \ + #flag "<" #min_value, &v8_flags.flag, #flag, \ + min_value, kStrongImplication); + +// Enforces that `flag` is at most `max_value` (sets `flag = max_value` if +// `flag > max_value`). +#define DEFINE_MAX_VALUE_IMPLICATION(flag, max_value) \ + changed |= TriggerImplication(v8_flags.flag > max_value, \ + #max_value "<" #flag, &v8_flags.flag, #flag, \ + max_value, kStrongImplication); + +// Enforces that `thenflag` is set to `false` if `whenflag` holds, printing a +// warning to stderr if both `whenflag` and `thenflag` are enabled. #define DEFINE_DISABLE_FLAG_IMPLICATION(whenflag, thenflag) \ if (whenflag && thenflag) { \ PrintF(stderr, "Warning: disabling flag --" #thenflag \ @@ -112,6 +128,17 @@ } \ DEFINE_VALUE_IMPLICATION(whenflag, thenflag, false) +// If `disallow_unsafe_flags` is enabled and `cond` holds, reset `flag` to its +// default value (or report a contradiction if contradictions are checked). +// Otherwise, if `flag` still has a non-default value while `cond` holds, imply +// `test_only_unsafe = true`. +#define DISALLOW_UNSAFE_FLAG_IF(cond, flag) \ + if (cond) { \ + DEFINE_VALUE_IMPLICATION(disallow_unsafe_flags, flag, FLAGDEFAULT_##flag) \ + DEFINE_NEG_VALUE_VALUE_IMPLICATION(flag, FLAGDEFAULT_##flag, \ + test_only_unsafe, true) \ + } + // We apply a generic macro to the flags. #elif defined(FLAG_MODE_APPLY) @@ -166,6 +193,11 @@ #define DEFINE_NEG_VALUE_IMPLICATION(whenflag, thenflag, value) #endif +#ifndef DEFINE_NEG_VALUE_VALUE_IMPLICATION +#define DEFINE_NEG_VALUE_VALUE_IMPLICATION(whenflag, whenvalue, thenflag, \ + thenvalue) +#endif + #ifndef DEFINE_MIN_VALUE_IMPLICATION #define DEFINE_MIN_VALUE_IMPLICATION(flag, min_value) #endif @@ -182,8 +214,8 @@ #define DEFINE_REQUIREMENT(statement) #endif -#ifndef DEFINE_NOT_EXPLICITLY_SET_IMPLICATION -#define DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(whenflag, thenflag) +#ifndef DISALLOW_UNSAFE_FLAG_IF +#define DISALLOW_UNSAFE_FLAG_IF(cond, flag) #endif #ifndef DEBUG_BOOL @@ -246,10 +278,10 @@ #define DEFINE_SMI(nam, def, cmt) \ DEFINE_INT(nam, def, cmt) \ - DEFINE_REQUIREMENT(Internals::IsValidSmi(v8_flags.nam.value())) + DEFINE_REQUIREMENT(Internals::IsValidSmi(nam.value())) #define DEFINE_POSITIVE_SMI(nam, def, cmt) \ DEFINE_UINT(nam, def, cmt) \ - DEFINE_REQUIREMENT(Internals::IsValidSmi(v8_flags.nam.value())) + DEFINE_REQUIREMENT(Internals::IsValidSmi(nam.value())) #ifdef DEBUG #define DEFINE_DEBUG_BOOL DEFINE_BOOL @@ -281,15 +313,39 @@ DEFINE_BOOL(experimental, false, DEFINE_EXPERIMENTAL_FEATURE(array_destructure_bytecode, "enable experimental ArrayDestructure bytecode") -// Test-only flags that expose unsafe and/or unsupported configurations. +// Test-only and unsafe flags: Flags that expose unsafe and/or unsupported +// configurations. Defining a flag with DEFINE_UNSAFE_FLAG or marking an +// existing flag with DISALLOW_UNSAFE_FLAG / DISALLOW_UNSAFE_FLAG_IF will: +// 1. Imply --test-only-unsafe when the flag is set to an unsafe value (which +// causes d8 to print a warning). +// 2. Prohibit/reset the flag when --disallow-unsafe-flags is set. DEFINE_BOOL(test_only_unsafe, false, "Indicates that V8 is running in an unsupported and unsafe " "configuration, e.g. used for internal testing. This flag is " "typically not set explicitly but instead enabled as an " - "implication of other flags") -#define DEFINE_TEST_ONLY_FLAG(nam, cmt) \ + "implication of other flags.") +DEFINE_BOOL(disallow_unsafe_flags, false, + "Prevents the use of flags that are considered unsafe. Setting " + "this flag will make V8 treat unsafe flags as flag contradictions " + "and either crash, exit gracefully with a message, or reset them " + "(depending on the current FlagProcessingMode).") +DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, test_only_unsafe) +// Enable sandbox test mode which allows for using memory corruption APIs and +// also installs the crash filter that determines whether issues are crashing +// inside or outside of the sandbox. +DEFINE_IMPLICATION(run_as_sandbox_security_poc, sandbox_testing) +DEFINE_IMPLICATION(run_as_sandbox_security_poc, run_as_security_poc) +DEFINE_IMPLICATION(run_as_security_poc, disallow_unsafe_flags) +// LINT.IfChange(FuzzingImplications) +DEFINE_IMPLICATION(sandbox_trap_fuzzing, sandbox_fuzzing) +DEFINE_IMPLICATION(sandbox_fuzzing, fuzzing) +DEFINE_IMPLICATION(allow_natives_for_differential_fuzzing, fuzzing) +DEFINE_IMPLICATION(fuzzing, disallow_unsafe_flags) +// LINT.ThenChange(/src/d8/d8.cc:FuzzingImplications) + +#define DEFINE_UNSAFE_FLAG(nam, cmt) \ FLAG(BOOL, bool, nam, false, cmt " (test-only / unsafe)") \ - DEFINE_IMPLICATION(nam, test_only_unsafe) + DISALLOW_UNSAFE_FLAG(nam) // Developer features: These flags expose features that are only meant to be // used by developers for diagnosing purposes. These features should be robust @@ -309,6 +365,12 @@ DEFINE_BOOL(disallow_developer_only_features, false, DEFINE_IMPLICATION(name, developer_only_features) \ DEFINE_NEG_IMPLICATION(disallow_developer_only_features, name) +// Verification flags turn potentially silent miscompilations into crashes, +// which in particular makes it easier for fuzzers to find those +// miscompilations. +#define DEFINE_VERIFICATION_FLAG(name, comment) \ + DEFINE_BOOL(name, false, comment) + DEFINE_STRING(flag_processing_mode, nullptr, "Control behavior for flag errors. Possible values: " "abort-on-error, exit-on-error, ignore-contradictions.") @@ -351,6 +413,10 @@ DEFINE_STRING(icu_datetime_compat_lang, "*", DEFINE_BOOL( intl_date_time_pattern_generator_cache_eviction, false, "enable 9-entry cache eviction in DateTimePatternGeneratorCache") +DEFINE_BOOL(use_icu4x_normalizer, false, "use ICU4X normalizer") +#ifdef V8_ENABLE_ECMA402_ICU4X +DEFINE_BOOL(ecma402_icu4x_plural_rules, false, "use ICU4X for Intl.PluralRules") +#endif // V8_ENABLE_ECMA402_ICU4X #endif #ifdef V8_ENABLE_DOUBLE_CONST_STORE_CHECK @@ -501,7 +567,7 @@ DEFINE_UINT( scavenger_chaos_mode_threshold, 50, "Percentage of non-large young objects that will be promoted during " "Scavenger in chaos mode") -DEFINE_REQUIREMENT(v8_flags.scavenger_chaos_mode_threshold <= 100) +DEFINE_MAX_VALUE_IMPLICATION(scavenger_chaos_mode_threshold, 100u) #ifdef V8_ENABLE_LOCAL_OFF_STACK_CHECK #define V8_ENABLE_LOCAL_OFF_STACK_CHECK_BOOL true @@ -555,12 +621,15 @@ DEFINE_BOOL(maglev_as_top_tier, false, DEFINE_IMPLICATION(maglev_as_top_tier, maglev) DEFINE_NEG_IMPLICATION(maglev_as_top_tier, turbofan) DEFINE_NEG_IMPLICATION(maglev_as_top_tier, turbolev) +DEFINE_NEG_IMPLICATION(maglev_as_top_tier, turbolev_future) +DEFINE_NEG_IMPLICATION(maglev_as_top_tier, stress_concurrent_inlining) DEFINE_BOOL(maglev_inlining, true, "enable inlining in the maglev optimizing compiler") DEFINE_BOOL( maglev_disable_builtin_reducers, false, - "disable eager builtin reducers in the maglev graph builder (for testing)") + "disable eager builtin reducers in the maglev graph builder to flush out " + "production bugs in post-inlining builtin reduction") DEFINE_BOOL(maglev_loop_peeling, true, "enable loop peeling in the maglev optimizing compiler") DEFINE_BOOL(maglev_optimistic_peeled_loops, true, @@ -688,7 +757,7 @@ DEFINE_DEVELOPER_FLAG(turbolev_trace_loop_peeling, DEFINE_STRING(maglev_filter, "*", "optimization filter for the maglev compiler") DEFINE_STRING(maglev_print_filter, "*", "filter for maglev's tracing/printing options") -DEFINE_BOOL(maglev_assert, false, "insert extra assertion in maglev code") +DEFINE_VERIFICATION_FLAG(maglev_assert, "insert extra assertion in maglev code") DEFINE_DEBUG_BOOL(maglev_assert_stack_size, true, "insert stack size checks before every IR node") DEFINE_EXPERIMENTAL_FEATURE( @@ -914,6 +983,9 @@ DEFINE_NEG_IMPLICATION(jitless, always_sparkplug) #endif // V8_ENABLE_SPARKPLUG #ifdef V8_ENABLE_MAGLEV DEFINE_NEG_IMPLICATION(jitless, maglev) +DEFINE_NEG_IMPLICATION(jitless, maglev_as_top_tier) +DEFINE_NEG_IMPLICATION(jitless, maglev_future) +DEFINE_NEG_IMPLICATION(jitless, stress_maglev) #endif // V8_ENABLE_MAGLEV DEFINE_NEG_IMPLICATION(jitless, turbolev) DEFINE_NEG_IMPLICATION(jitless, turbolev_future) @@ -930,6 +1002,9 @@ DEFINE_BOOL( DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, turbofan) DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, turboshaft) DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, maglev) +DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, maglev_as_top_tier) +DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, maglev_future) +DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, stress_maglev) DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, turbolev) DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, turbolev_future) DEFINE_NEG_IMPLICATION(disable_optimizing_compilers, wasm_in_js_inlining_body) @@ -952,8 +1027,8 @@ DEFINE_BOOL(force_memory_protection_keys, false, "fail if memory protection key support is not available") DEFINE_IMPLICATION(force_memory_protection_keys, memory_protection_keys) -DEFINE_BOOL(assert_types, false, - "generate runtime type assertions to test the typer") +DEFINE_VERIFICATION_FLAG(assert_types, + "generate runtime type assertions to test the typer") // TODO(tebbi): Support allocating types from background thread. DEFINE_NEG_IMPLICATION(assert_types, concurrent_recompilation) DEFINE_NEG_IMPLICATION(assert_types, concurrent_builtin_generation) @@ -964,8 +1039,8 @@ DEFINE_NEG_IMPLICATION(turboshaft_assert_types, concurrent_recompilation) DEFINE_NEG_IMPLICATION(turboshaft_assert_types, concurrent_builtin_generation) // Enable verification of SimplifiedLowering in debug builds. -DEFINE_BOOL(verify_simplified_lowering, false, - "verify graph generated by simplified lowering") +DEFINE_VERIFICATION_FLAG(verify_simplified_lowering, + "verify graph generated by simplified lowering") DEFINE_DEVELOPER_FLAG(trace_compilation_dependencies, "trace code dependencies") // Depend on --trace-deopt-verbose for reporting dependency invalidations. @@ -1242,25 +1317,17 @@ DEFINE_WEAK_IMPLICATION(trace_baseline, trace_baseline_batch_compilation) // Internalize into a shared string table in the shared isolate DEFINE_BOOL(shared_strings, false, "allow sharing of strings") DEFINE_IMPLICATION(shared_strings, shared_heap) -DEFINE_EXPERIMENTAL_FEATURE(shared_string_table, - "internalize strings into shared table") -DEFINE_IMPLICATION(shared_string_table, shared_strings) -DEFINE_IMPLICATION(harmony_struct, shared_string_table) +DEFINE_BOOL_READONLY( + harmony_struct, false, + "DEPRECATED. harmony structs, shared structs, and shared arrays") +DEFINE_BOOL_READONLY(shared_string_table, false, + "DEPRECATED. internalize strings into shared table") DEFINE_BOOL_READONLY(always_use_string_forwarding_table, false, "use string forwarding table instead of thin strings for " "all strings (experimental)") -DEFINE_IMPLICATION(always_use_string_forwarding_table, experimental) -// With --always-use-string-forwarding-table, we can have young generation -// string entries in the forwarding table, requiring table updates when these -// strings get promoted to old space. Parallel GCs in client isolates -// (enabled by --shared-heap) are not supported using a single shared -// forwarding table. -DEFINE_NEG_IMPLICATION(shared_heap, always_use_string_forwarding_table) DEFINE_BOOL(transition_strings_during_gc_with_stack, false, "Transition strings during a full GC with stack") -DEFINE_NEG_IMPLICATION(shared_string_table, - transition_strings_during_gc_with_stack) DEFINE_SIZE_T(initial_shared_heap_size, 0, "initial size of the shared heap (in Mbytes); " @@ -1473,6 +1540,8 @@ DEFINE_BOOL(turbo_stats_wasm, false, DEFINE_BOOL_READONLY(turbo_splitting, true, "split nodes during scheduling in TurboFan") DEFINE_BOOL(turbo_inlining, true, "enable inlining in TurboFan") +DEFINE_BOOL(forin_enumerator_holder, true, + "optimize for-in over packed elements using ForInEnumeratorHolder") DEFINE_BOOL(turbo_elide_frames, true, "enable frame elision in TurboFan") DEFINE_INT(max_inlined_bytecode_size, 460, "maximum size of bytecode for a single inlining") @@ -1731,6 +1800,9 @@ DEFINE_BOOL_READONLY(wasm_deinterleave_loads, false, DEFINE_BOOL(turbolev, false, "use Turbolev (≈ Maglev + Turboshaft combined) as the 4th tier " "compiler instead of Turbofan") +// ArrayDestructure bytecode is only supported in Turbolev, not Turbofan. +DEFINE_WEAK_IMPLICATION(array_destructure_bytecode, turbolev) +DEFINE_NEG_IMPLICATION(turbofan && !turbolev, array_destructure_bytecode) DEFINE_DEVELOPER_FLAG(print_turbolev_frontend, "print Turbolev frontend (Maglev graphs)") @@ -1744,6 +1816,7 @@ DEFINE_EXPERIMENTAL_FEATURE( turbolev_future, "enable Turbolev features that we want to ship in the not-too-far future") DEFINE_IMPLICATION(turbolev_future, turbolev) +DEFINE_NEG_IMPLICATION(turbofan && !turbolev, forin_enumerator_holder) #if TAGGED_SIZE_8_BYTES // The FixedArray length padding is not aligned with the other fields, which is @@ -1774,11 +1847,12 @@ DEFINE_BOOL( "avoid duplicated HeapNumber materializations in HeapNumberRequests") #ifdef DEBUG -DEFINE_BOOL(turboshaft_verify_load_elimination, false, - "insert runtime checks to verify Late Load Elimination") -DEFINE_BOOL(turboshaft_verify_load_store_taggedness, false, - "insert runtime checks to verify the representation of " - "loaded/stored values") +DEFINE_VERIFICATION_FLAG( + turboshaft_verify_load_elimination, + "insert runtime checks to verify Late Load Elimination") +DEFINE_VERIFICATION_FLAG(turboshaft_verify_load_store_taggedness, + "insert runtime checks to verify the representation " + "of loaded/stored values") DEFINE_IMPLICATION(turboshaft_verify_load_elimination, deduplicate_heap_number_requests) DEFINE_UINT64(turboshaft_opt_bisect_limit, std::numeric_limits<uint64_t>::max(), @@ -1787,9 +1861,9 @@ DEFINE_UINT64(turboshaft_opt_bisect_limit, std::numeric_limits<uint64_t>::max(), DEFINE_UINT64(turboshaft_opt_bisect_break, std::numeric_limits<uint64_t>::max(), "abort after a specified number of steps, useful for bisecting " "optimization bugs") -DEFINE_BOOL(turboshaft_verify_reductions, false, - "check that turboshaft reductions are correct with respect to " - "inferred types") +DEFINE_VERIFICATION_FLAG(turboshaft_verify_reductions, + "check that turboshaft reductions are correct with " + "respect to inferred types") DEFINE_DEVELOPER_FLAG(turboshaft_trace_typing, "print typing steps of turboshaft type inference") DEFINE_DEVELOPER_FLAG(turboshaft_trace_reduction, @@ -1817,8 +1891,8 @@ DEFINE_DEVELOPER_FLAG( "trace the translation from Maglev to Turboshaft in Turbolev") DEFINE_IMPLICATION(trace_turbolev_graph_building, turboshaft_trace_emitted) -DEFINE_BOOL(verify_turboshaft, false, - "enable various verifications on Turboshaft") +DEFINE_VERIFICATION_FLAG(verify_turboshaft, + "enable various verifications on Turboshaft") DEFINE_IMPLICATION(verify_turboshaft, turboshaft_verify_load_elimination) DEFINE_IMPLICATION(verify_turboshaft, turboshaft_verify_load_store_taggedness) DEFINE_IMPLICATION(verify_turboshaft, turboshaft) @@ -1979,8 +2053,8 @@ DEFINE_NEG_NEG_IMPLICATION(harmony_shipping, js_shipping) DEFINE_BOOL(wasm_generic_wrapper, true, "allow use of the generic js-to-wasm wrapper instead of " "per-signature wrappers") -DEFINE_BOOL(wasm_unsafe_fast_api_wrapper, false, "allow use of the unsafe fast " - "API wrapper") +DEFINE_UNSAFE_FLAG(wasm_unsafe_fast_api_wrapper, + "allow use of the unsafe fast API wrapper") DEFINE_INT(wasm_num_compilation_tasks, 128, "maximum number of parallel compilation tasks for wasm") DEFINE_VALUE_IMPLICATION(single_threaded, wasm_num_compilation_tasks, 0) @@ -2018,6 +2092,7 @@ DEFINE_INT(wasm_tiering_budget, 13'000'000, "budget for dynamic tiering (rough approximation of bytes executed") DEFINE_SMI(wasm_wrapper_tiering_budget, wasm::kGenericWrapperBudget, "budget for wrapper tierup (number of calls until tier-up)") +DEFINE_MIN_VALUE_IMPLICATION(wasm_wrapper_tiering_budget, 1) DEFINE_INT(max_wasm_functions, wasm::kV8MaxWasmDefinedFunctions, "maximum number of wasm functions defined in a module") DEFINE_INT( @@ -2057,7 +2132,7 @@ DEFINE_VALUE_IMPLICATION(wasm_growable_stacks, wasm_stack_switching_stack_size, 1) DEFINE_BOOL(liftoff, true, "enable Liftoff, the baseline compiler for WebAssembly") -DEFINE_BOOL(liftoff_only, false, +DEFINE_BOOL(liftoff_only, !V8_ENABLE_TURBOFAN_BOOL, "disallow TurboFan compilation for WebAssembly (for testing)") DEFINE_IMPLICATION(liftoff_only, liftoff) DEFINE_NEG_IMPLICATION(liftoff_only, wasm_tier_up) @@ -2086,13 +2161,11 @@ DEFINE_INT(wasm_tier_mask_for_testing, 0, DEFINE_INT(wasm_debug_mask_for_testing, 0, "bitmask of declared(!) function indices to compile for debugging, " "only applies if the tier is Liftoff") -DEFINE_DEVELOPER_FLAG( - wasm_pgo_to_file, - "experimental: dump Wasm PGO information to a local file (for testing)") +DEFINE_UNSAFE_FLAG(wasm_pgo_to_file, + "experimental: dump Wasm PGO information to a local file") DEFINE_NEG_IMPLICATION(wasm_pgo_to_file, single_threaded) -DEFINE_DEVELOPER_FLAG( - wasm_pgo_from_file, - "experimental: read and use Wasm PGO data from a local file (for testing)") +DEFINE_UNSAFE_FLAG(wasm_pgo_from_file, + "experimental: read and use Wasm PGO data from a local file") #if V8_ENABLE_DRUMBRAKE // Wasm is put into interpreter-only mode. We repeat flag implications down @@ -2130,15 +2203,14 @@ DEFINE_SIZE_T(wasm_deopts_per_function_limit, 10, "further deopt points are emitted in Turbofan") // Unsafe additions to the GC proposal for performance experiments. -DEFINE_TEST_ONLY_FLAG( +DEFINE_UNSAFE_FLAG( wasm_assume_ref_cast_succeeds, "assume ref.cast always succeeds and skip the related type check") -DEFINE_TEST_ONLY_FLAG(wasm_ref_cast_nop, - "enable unsafe ref.cast_nop instruction") -DEFINE_TEST_ONLY_FLAG( +DEFINE_UNSAFE_FLAG(wasm_ref_cast_nop, "enable unsafe ref.cast_nop instruction") +DEFINE_UNSAFE_FLAG( wasm_skip_null_checks, "skip null checks for call.ref and array and struct operations") -DEFINE_TEST_ONLY_FLAG(wasm_skip_bounds_checks, "skip array bounds checks") +DEFINE_UNSAFE_FLAG(wasm_skip_bounds_checks, "skip array bounds checks") // Experimental variants of the Custom Descriptors prototype implementation. DEFINE_EXPERIMENTAL_FEATURE( @@ -2148,17 +2220,16 @@ DEFINE_BOOL(wasm_custom_descriptors_permitted, true, "Emergency off-switch for Custom Descriptors Origin Trial") DEFINE_EXPERIMENTAL_FEATURE(wasm_merged_descriptors, "merge Custom Descriptor into v8::internal::Map") -DEFINE_IMPLICATION(wasm_merged_descriptors, wasm_custom_descriptors) DEFINE_DEBUG_BOOL( wasm_opt, true, "enable optimization when compiling Wasm functions with Turbofan") DEFINE_BOOL(wasm_bounds_checks, true, "enable bounds checks (disable for performance testing only)") -DEFINE_NEG_VALUE_IMPLICATION(wasm_bounds_checks, test_only_unsafe, true) +DISALLOW_UNSAFE_FLAG(wasm_bounds_checks) DEFINE_BOOL(wasm_stack_checks, true, "enable stack checks (disable for performance testing only)") -DEFINE_NEG_VALUE_IMPLICATION(wasm_stack_checks, test_only_unsafe, true) +DISALLOW_UNSAFE_FLAG(wasm_stack_checks) DEFINE_BOOL( wasm_enforce_bounds_checks, false, "enforce explicit bounds check even if the trap handler is available") @@ -2300,6 +2371,7 @@ DEFINE_BOOL_READONLY(wasm_memory64_trap_handling, false, // DrumBrake flags. DEFINE_EXPERIMENTAL_FEATURE(wasm_jitless, "Execute all wasm code in the Wasm interpreter") +DEFINE_IMPLICATION(wasm_jitless, jitless) #ifdef V8_OS_TVOS // Enable wasm_jitless on tvOS where jit is not available. DEFINE_IMPLICATION(jitless, wasm_jitless) @@ -2309,6 +2381,9 @@ DEFINE_BOOL(wasm_jitless_if_available_for_testing, false, "the 'v8_enable_drumbrake' flag is set.") DEFINE_IMPLICATION(wasm_jitless_if_available_for_testing, wasm_jitless) +DEFINE_BOOL_READONLY(drumbrake_exnref, false, + "enable new exception-handling support in the Wasm " + "interpreter") DEFINE_BOOL(drumbrake_compact_bytecode, false, "Compress the Wasm interpreter bytecode") DEFINE_DEVELOPER_FLAG(trace_drumbrake_compact_bytecode, @@ -2370,6 +2445,7 @@ DEFINE_BOOL_READONLY(wasm_jitless, false, "execute all Wasm code in the Wasm interpreter") DEFINE_BOOL(wasm_jitless_if_available_for_testing, false, "") DEFINE_NEG_IMPLICATION(wasm_jitless_if_available_for_testing, turbolev) +DEFINE_BOOL_READONLY(drumbrake_exnref, false, "") #endif // V8_ENABLE_DRUMBRAKE DEFINE_BOOL(wasm_allow_mixed_eh_for_testing, false, @@ -2400,11 +2476,11 @@ DEFINE_IMPLICATION(wasm_code_coverage, wasm_opt) DEFINE_DEVELOPER_FLAG(trace_wasm_compilation_hints, "trace compilation hints parsing and usage") -DEFINE_TEST_ONLY_FLAG( +DEFINE_UNSAFE_FLAG( wasm_generate_compilation_hints, "enable emitting compilation-hints sections for Wasm to a file") -DEFINE_TEST_ONLY_FLAG(trace_wasm_generate_compilation_hints, - "enable tracing wasm compilation hints generation") +DEFINE_UNSAFE_FLAG(trace_wasm_generate_compilation_hints, + "enable tracing wasm compilation hints generation") // Feedback collection is guarded by the --wasm-inlining flag. DEFINE_IMPLICATION(wasm_generate_compilation_hints, wasm_inlining) DEFINE_IMPLICATION(trace_wasm_generate_compilation_hints, wasm_inlining) @@ -2421,10 +2497,10 @@ DEFINE_IMPLICATION(trace_wasm_generate_compilation_hints, liftoff) DEFINE_IMPLICATION(wasm_generate_compilation_hints, wasm_tier_up) DEFINE_IMPLICATION(trace_wasm_generate_compilation_hints, wasm_tier_up) // Compilation hints generation is incompatible with eager tier-up. -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(wasm_generate_compilation_hints, - wasm_eager_tier_up_function) -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(trace_wasm_generate_compilation_hints, - wasm_eager_tier_up_function) +DEFINE_VALUE_IMPLICATION(wasm_generate_compilation_hints, + wasm_eager_tier_up_function, FLAGDEFAULT_wasm_eager_tier_up_function) +DEFINE_VALUE_IMPLICATION(trace_wasm_generate_compilation_hints, + wasm_eager_tier_up_function , FLAGDEFAULT_wasm_eager_tier_up_function ) // Compilation hints generation is not compatible with // --no-wasm-dynamic-tiering or --no-wasm-lazy-compilation. DEFINE_IMPLICATION(wasm_generate_compilation_hints, wasm_dynamic_tiering) @@ -2432,10 +2508,8 @@ DEFINE_IMPLICATION(trace_wasm_generate_compilation_hints, wasm_dynamic_tiering) DEFINE_IMPLICATION(wasm_generate_compilation_hints, wasm_lazy_compilation) DEFINE_IMPLICATION(trace_wasm_generate_compilation_hints, wasm_lazy_compilation) // --single-threaded implies --no-wasm-tier-up. -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(wasm_generate_compilation_hints, - single_threaded) -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(trace_wasm_generate_compilation_hints, - single_threaded) +DEFINE_NEG_IMPLICATION(wasm_generate_compilation_hints, single_threaded) +DEFINE_NEG_IMPLICATION(trace_wasm_generate_compilation_hints, single_threaded) // Wasm compilation hints generation is incompatible with features that are not // implemented in liftoff yet. DEFINE_NEG_IMPLICATION(wasm_generate_compilation_hints, wasm_wasmfx) @@ -2662,7 +2736,8 @@ DEFINE_DEVELOPER_FLAG( "trace native contexts that are expected to be garbage collected") DEFINE_IMPLICATION(trace_detached_contexts, track_detached_contexts) #ifdef VERIFY_HEAP -DEFINE_BOOL(verify_heap, false, "verify heap pointers before and after GC") +DEFINE_VERIFICATION_FLAG(verify_heap, + "verify heap pointers before and after GC") DEFINE_BOOL(verify_heap_skip_remembered_set, false, "disable remembered set verification") #else @@ -2679,18 +2754,24 @@ DEFINE_BOOL_READONLY(verify_write_barriers, V8_VERIFY_WRITE_BARRIERS_BOOL, #undef V8_VERIFY_WRITE_BARRIERS_BOOL DEFINE_BOOL(safepoint_bump_qos_class, true, "Bump priority for running threads to reach safepoint") +DEFINE_BOOL(freeze_forces_marking_finalization, false, + "Forces finalizing marking when frozen state is notified") DEFINE_BOOL(move_object_start, true, "enable moving of object starts") DEFINE_BOOL(memory_reducer, true, "use memory reducer") DEFINE_BOOL(memory_reducer_for_small_heaps, true, "use memory reducer for small heaps") -DEFINE_INT(memory_reducer_gc_count, 2, - "Maximum number of memory reducer GCs scheduled") -DEFINE_REQUIREMENT(v8_flags.memory_reducer_gc_count > 0) -DEFINE_INT(memory_reducer_delay_ms, 8'000, "Delay before memory reducer start") -DEFINE_REQUIREMENT(v8_flags.memory_reducer_delay_ms > 0) -DEFINE_INT(gc_memory_reducer_start_delay_ms, 30'000, - "Delay before memory reducer start") -DEFINE_REQUIREMENT(v8_flags.gc_memory_reducer_start_delay_ms > 0) +DEFINE_UINT(memory_reducer_gc_count, 2u, + "Maximum number of memory reducer GCs scheduled") +DEFINE_MIN_VALUE_IMPLICATION(memory_reducer_gc_count, 1u) +DEFINE_UINT(memory_reducer_delay_ms, 8'000u, + "Delay before memory reducer start") +DEFINE_MIN_VALUE_IMPLICATION(memory_reducer_delay_ms, 1u) +DEFINE_UINT(gc_memory_reducer_start_delay_ms, 30'000u, + "Delay before memory reducer start") +DEFINE_MIN_VALUE_IMPLICATION(gc_memory_reducer_start_delay_ms, 1u) +DEFINE_BOOL(memory_reducer_limit_based, false, + "Use the limit-based memory reducer that updates allocation limits " + "after a delay to trigger GC") DEFINE_FLOAT( external_memory_max_growing_factor, 1.1, "This is the upper bound for growing factor imposed on external memory.") @@ -2802,18 +2883,17 @@ DEFINE_NEG_NEG_IMPLICATION(memory_pool, managed_zone_memory) DEFINE_BOOL(fuzzer_gc_analysis, false, "prints number of allocations and enables analysis mode for gc " "fuzz testing, e.g. --stress-marking, --stress-scavenge") -DEFINE_INT(stress_marking, 0, - "force marking at random points between 0 and X (inclusive) percent " - "of the regular marking start limit") -DEFINE_REQUIREMENT(v8_flags.stress_marking >= 0) -DEFINE_REQUIREMENT(v8_flags.stress_marking <= 100) -DEFINE_INT(stress_scavenge, 0, - "force scavenge at random points between 0 and X (inclusive) " - "percent of the new space capacity") -DEFINE_REQUIREMENT(v8_flags.stress_scavenge >= 0) -DEFINE_REQUIREMENT(v8_flags.stress_scavenge <= 100) -DEFINE_VALUE_IMPLICATION(fuzzer_gc_analysis, stress_marking, 99) -DEFINE_VALUE_IMPLICATION(fuzzer_gc_analysis, stress_scavenge, 99) +DEFINE_UINT( + stress_marking, 0u, + "force marking at random points between 0 and X (inclusive) percent " + "of the regular marking start limit") +DEFINE_MAX_VALUE_IMPLICATION(stress_marking, 100u) +DEFINE_UINT(stress_scavenge, 0u, + "force scavenge at random points between 0 and X (inclusive) " + "percent of the new space capacity") +DEFINE_MAX_VALUE_IMPLICATION(stress_scavenge, 100u) +DEFINE_VALUE_IMPLICATION(fuzzer_gc_analysis, stress_marking, 99u) +DEFINE_VALUE_IMPLICATION(fuzzer_gc_analysis, stress_scavenge, 99u) DEFINE_BOOL( reclaim_unmodified_wrappers, true, "reclaim otherwise unreachable unmodified wrapper objects when possible") @@ -2886,8 +2966,6 @@ DEFINE_BOOL_READONLY(debug_code, false, "") DEFINE_BOOL_READONLY(trap_on_abort, true, "") DEFINE_BOOL_READONLY(slow_debug_code, false, "") #endif -DEFINE_BOOL(enforce_x64_16byte_alignment, false, - "enforce 16-byte stack alignment on x64 platforms") #ifdef V8_CODE_COMMENTS DEFINE_BOOL(code_comments, false, "emit comments in code disassembly; for more readable source " @@ -3043,10 +3121,8 @@ DEFINE_BOOL(force_slow_path, false, "always take the slow path for builtins") DEFINE_BOOL(test_small_max_function_context_stub_size, false, "enable testing the function context size overflow path " "by making the maximum size smaller") -DEFINE_WEAK_IMPLICATION(future, fast_api_indexof) -DEFINE_BOOL(fast_api_indexof, false, "enable using indexOf Api callbacks") -DEFINE_WEAK_IMPLICATION(future, fast_api_iterable_to_list) -DEFINE_BOOL(fast_api_iterable_to_list, false, +DEFINE_BOOL(fast_api_indexof, true, "enable using indexOf Api callbacks") +DEFINE_BOOL(fast_api_iterable_to_list, true, "enable fast path for IterableToList for indexed interceptors") DEFINE_BOOL(inline_new, true, "use fast inline allocation") @@ -3057,10 +3133,10 @@ DEFINE_INT(switch_table_spread_threshold, 3, "allow the jump table used for switch statements to span a range " "of integers roughly equal to this number times the number of " "clauses in the switch") -DEFINE_INT(switch_table_min_cases, 6, - "the number of Smi integer cases present in the switch statement " - "before using the jump table optimization") -DEFINE_REQUIREMENT(v8_flags.switch_table_min_cases > 0) +DEFINE_UINT(switch_table_min_cases, 6u, + "the number of Smi integer cases present in the switch statement " + "before using the jump table optimization") +DEFINE_MIN_VALUE_IMPLICATION(switch_table_min_cases, 1u) // Note that enabling this stress mode might result in a failure to compile // even a top-level code. DEFINE_UINT(stress_lazy_compilation, 0, @@ -3171,6 +3247,15 @@ DEFINE_NEG_IMPLICATION(fuzzing, hard_abort) DEFINE_NEG_IMPLICATION(hole_fuzzing, hard_abort) DEFINE_NEG_IMPLICATION(sandbox_fuzzing, hard_abort) +// fuzzilli +#if defined(V8_FUZZILLI) +DEFINE_BOOL(fuzzilli_enable_optimized_code_coverage, false, + "enable optimized code coverage for fuzzilli") +#else +DEFINE_BOOL_READONLY(fuzzilli_enable_optimized_code_coverage, false, + "enable optimized code coverage for fuzzilli") +#endif + // disassembler DEFINE_BOOL(log_colour, ENABLE_LOG_COLOUR, "When logging, try to use coloured output.") @@ -3277,8 +3362,7 @@ DEFINE_BOOL(super_ic, true, "use an IC for super property loads") DEFINE_EXPERIMENTAL_FEATURE(mega_dom_ic, "use MegaDOM IC state for API objects") DEFINE_UINT(homomorphic_ic_count, 8, "local cache size in homomorphic ICs") -DEFINE_REQUIREMENT( - base::bits::IsPowerOfTwo(v8_flags.homomorphic_ic_count.value())) +DEFINE_REQUIREMENT(base::bits::IsPowerOfTwo(homomorphic_ic_count.value())) // objects.cc DEFINE_DEVELOPER_FLAG(trace_prototype_users, @@ -3295,7 +3379,6 @@ DEFINE_BOOL(allow_natives_for_differential_fuzzing, false, "allow only natives explicitly allowlisted for differential " "fuzzers") DEFINE_IMPLICATION(allow_natives_for_differential_fuzzing, allow_natives_syntax) -DEFINE_IMPLICATION(allow_natives_for_differential_fuzzing, fuzzing) DEFINE_BOOL(parse_only, false, "only parse the sources") // simulator-arm.cc and simulator-arm64.cc. @@ -3308,17 +3391,17 @@ DEFINE_INT(stop_sim_at, 0, "Simulator stop after x number of instructions") #if defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_MIPS64) || \ defined(V8_TARGET_ARCH_PPC64) || defined(V8_TARGET_ARCH_RISCV64) || \ defined(V8_TARGET_ARCH_LOONG64) -DEFINE_INT(sim_stack_alignment, 16, - "Stack alignment in bytes in simulator. This must be a power of two " - "and it must be at least 16. 16 is default.") -DEFINE_REQUIREMENT( - v8_flags.sim_stack_alignment >= 16 && - base::bits::IsPowerOfTwo(v8_flags.sim_stack_alignment.value())) +DEFINE_UINT( + sim_stack_alignment, 16u, + "Stack alignment in bytes in simulator. This must be a power of two " + "and it must be at least 16. 16 is default.") +DEFINE_MIN_VALUE_IMPLICATION(sim_stack_alignment, 16u) +DEFINE_REQUIREMENT(base::bits::IsPowerOfTwo(sim_stack_alignment.value())) #else -DEFINE_INT(sim_stack_alignment, 8, +DEFINE_UINT(sim_stack_alignment, 8u, "Stack alingment in bytes in simulator (4 or 8, 8 is default)") -DEFINE_REQUIREMENT(v8_flags.sim_stack_alignment == 4 || - v8_flags.sim_stack_alignment == 8) +DEFINE_REQUIREMENT(sim_stack_alignment == 4u || + sim_stack_alignment == 8u) #endif DEFINE_INT(sim_stack_size, 2 * MB / KB, "Stack size of the ARM64, MIPS64 and PPC64 simulator " @@ -3341,11 +3424,15 @@ DEFINE_BOOL(stack_trace_on_illegal, false, "print stack trace when an illegal exception is thrown") DEFINE_BOOL(abort_on_uncaught_exception, false, "abort program (dump core) when an uncaught exception is thrown") -DEFINE_BOOL(correctness_fuzzer_suppressions, false, - "Suppress certain unspecified behaviors to ease correctness " - "fuzzing: Abort program when the stack overflows or a string " - "exceeds maximum length (as opposed to throwing RangeError). " - "Use a fixed suppression string for error messages.") +DEFINE_DEVELOPER_FLAG( + correctness_fuzzer_suppressions, + "Suppress certain unspecified behaviors to ease correctness " + "fuzzing: Abort program when the stack overflows or a string " + "exceeds maximum length (as opposed to throwing RangeError). " + "Use a fixed suppression string for error messages.") +DEFINE_DEVELOPER_FLAG( + correctness_fuzzer_cross_arch_suppressions, + "Minimize cross-architecture differences for correctness fuzzing.") DEFINE_BOOL(rehash_snapshot, false, "rehash strings from the snapshot to override the baked-in seed") DEFINE_UINT64(hash_seed, 0, @@ -3420,6 +3507,7 @@ DEFINE_DEVELOPER_FLAG(serialization_statistics, "Collect statistics on serialized objects.") // Regexp DEFINE_BOOL(regexp_optimization, true, "generate optimized regexp code") +DEFINE_BOOL(regexp_atomic_loop, true, "optimize atomic regexp loops") DEFINE_BOOL(regexp_unroll, true, "unroll small {} repeats when optimizing") DEFINE_BOOL(regexp_masked_dispatch, true, "dispatch disjoint regexp alternations on the masked quick-check " @@ -3450,7 +3538,7 @@ DEFINE_NEG_IMPLICATION(regexp_interpret_all, regexp_tier_up) DEFINE_SMI(regexp_tier_up_ticks, 0, "set the number of executions for the regexp interpreter before " "tiering-up to the compiler") -DEFINE_REQUIREMENT(v8_flags.regexp_tier_up_ticks >= 0) +DEFINE_MIN_VALUE_IMPLICATION(regexp_tier_up_ticks, 0) DEFINE_BOOL( regexp_jit_all, false, "compile all regexp patterns directly to native code, skipping the " @@ -3678,9 +3766,6 @@ DEFINE_BOOL_READONLY(sandbox_fuzzing, false, DEFINE_BOOL(sandbox_trap_fuzzing, false, "Enable the trap-based sandbox fuzzing mode.") -DEFINE_IMPLICATION(sandbox_trap_fuzzing, sandbox_fuzzing) - -DEFINE_IMPLICATION(sandbox_fuzzing, fuzzing) // Only one of these can be enabled. DEFINE_NEG_IMPLICATION(sandbox_fuzzing, sandbox_testing) @@ -3852,14 +3937,14 @@ DEFINE_BOOL(slow_histograms, false, DEFINE_BOOL(use_external_strings, false, "Use external strings for source code") DEFINE_STRING(map_counters, "", "Map counters to a file") -DEFINE_TEST_ONLY_FLAG(mock_arraybuffer_allocator, - "Use a mock ArrayBuffer allocator for testing.") +DEFINE_UNSAFE_FLAG(mock_arraybuffer_allocator, + "Use a mock ArrayBuffer allocator for testing.") DEFINE_SIZE_T(mock_arraybuffer_allocator_limit, 0, "Memory limit for mock ArrayBuffer allocator used to simulate " "OOM for testing.") #ifdef V8_OS_LINUX -DEFINE_BOOL(multi_mapped_mock_allocator, false, - "Use a multi-mapped mock ArrayBuffer allocator for testing.") +DEFINE_UNSAFE_FLAG(multi_mapped_mock_allocator, + "Use a multi-mapped mock ArrayBuffer allocator for testing.") #endif // @@ -4097,9 +4182,10 @@ DEFINE_STRING(redirect_code_traces_to, nullptr, DEFINE_DEVELOPER_FLAG(print_opt_source, "print source code of optimized and inlined functions") -DEFINE_BOOL(vtune_prof_annotate_wasm, false, - "Used when v8_enable_vtunejit is enabled, load wasm source map and " - "provide annotate support (experimental).") +DEFINE_DEVELOPER_FLAG( + vtune_prof_annotate_wasm, + "Used when v8_enable_vtunejit is enabled, load wasm source map and " + "provide annotate support (experimental).") DEFINE_BOOL(win64_unwinding_info, true, "Enable unwinding info for Windows/x64") @@ -4289,8 +4375,7 @@ DEFINE_EXPERIMENTAL_FEATURE( superspreading, "Allow arbitrary length spread arguments on supported builtins") -DEFINE_BOOL(fast_proxy_ic, false, "Support proxy traps in ICs") -DEFINE_WEAK_IMPLICATION(future, fast_proxy_ic) +DEFINE_BOOL(fast_proxy_ic, true, "Support proxy traps in ICs") DEFINE_BOOL(is_standalone_d8_shell, false, "Tells V8 it's running as part of the d8. This flag should not be " @@ -4301,96 +4386,55 @@ DEFINE_WEAK_VALUE_IMPLICATION(is_standalone_d8_shell, trace_turbo_cfg_file, DEFINE_WEAK_VALUE_IMPLICATION(is_standalone_d8_shell, redirect_code_traces_to, "code.asm") -// The --disallow-unsafe-flags is meant to block known unsafe configurations and -// mitigate spurious reports due invalid flag combinations/values. To prevent AI -// agents and/or fuzzers from using a new unsafe flag, add an implication from -// --disallow-unsafe-flags below. -// TODO(crbug.com/452607988): Enable on fuzzers and merge the -// --disallow-unsafe-flags with -// --test-only-unsafe once the list of flags below is stable. -DEFINE_BOOL(disallow_unsafe_flags, false, - "Prevents the use of flags that are considered unsafe. Setting " - "this flag will make V8 treat the unsafe flags below as flag " - "contradiction and either crash or exit gracefully with a message " - "(depending on the curreny AbortMode)") -// --disallow-unsafe-flags is intended to only be used with --fuzzing. -DEFINE_IMPLICATION(disallow_unsafe_flags, fuzzing) +// Flags that are disallowed when --disallow-unsafe-flags is set (in addition to +// flags defined via DEFINE_UNSAFE_FLAG). Each entry below also implies +// --test-only-unsafe when set to an unsafe value. // Profiling flags. -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, turbo_profiling) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, turbo_profiling_verbose) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, perf_prof) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, perf_prof_annotate_wasm) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, perf_prof_delete_file) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, perf_prof_unwinding_info) -// Experimental PGO/compilation-hints-generation flags. -#if V8_ENABLE_WEBASSEMBLY -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_pgo_to_file) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_pgo_from_file) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_generate_compilation_hints) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, - trace_wasm_generate_compilation_hints) -#endif // V8_ENABLE_WEBASSEMBLY +DISALLOW_UNSAFE_FLAG(turbo_profiling) +DISALLOW_UNSAFE_FLAG(turbo_profiling_verbose) +DISALLOW_UNSAFE_FLAG(perf_prof) +DISALLOW_UNSAFE_FLAG(perf_prof_annotate_wasm) +DISALLOW_UNSAFE_FLAG(vtune_prof_annotate_wasm) // Known-broken features/configuration. -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, feedback_normalization) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, harmony_struct) -DEFINE_IMPLICATION(disallow_unsafe_flags, script_context_cells) +DISALLOW_UNSAFE_FLAG(feedback_normalization) +DISALLOW_UNSAFE_FLAG(array_destructure_bytecode) +DISALLOW_UNSAFE_FLAG(turboshaft_random_rescheduling) // Disabled-by-default misc. "unsafe" flags that should not be enabled. -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, mock_arraybuffer_allocator) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, abort_on_bad_builtin_profile_data) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, abort_on_uncaught_exception) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, abort_on_far_code_range) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, correctness_fuzzer_suppressions) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, force_memory_protection_keys) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, expose_trigger_failure) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, redirect_code_traces) +DISALLOW_UNSAFE_FLAG(abort_on_bad_builtin_profile_data) +DISALLOW_UNSAFE_FLAG(abort_on_uncaught_exception) +DISALLOW_UNSAFE_FLAG(abort_on_far_code_range) +DISALLOW_UNSAFE_FLAG(force_memory_protection_keys) +DISALLOW_UNSAFE_FLAG(expose_trigger_failure) +DISALLOW_UNSAFE_FLAG(redirect_code_traces) #if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_DRUMBRAKE_TRACING -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, redirect_drumbrake_traces) +DISALLOW_UNSAFE_FLAG(redirect_drumbrake_traces) #endif // V8_ENABLE_DRUMBRAKE_TRACING -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_assume_ref_cast_succeeds) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_skip_null_checks) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_ref_cast_nop) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_skip_bounds_checks) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, wasm_unsafe_fast_api_wrapper) -// Enabled-by-default flags that should not be disabled. -DEFINE_IMPLICATION(disallow_unsafe_flags, wasm_bounds_checks) -DEFINE_IMPLICATION(disallow_unsafe_flags, wasm_stack_checks) // Flags that are unsafe if given unexpected invalid values. -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, max_wasm_functions) -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, - wasm_max_initial_code_space_reservation) -// Disable wasm_max_initial_code_space_reservation in fuzzing, as a wrong value -// can lead to crashes. -DEFINE_VALUE_IMPLICATION(fuzzing, wasm_max_initial_code_space_reservation, 0) -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, - wasm_wrapper_tiering_budget) -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, - wasm_eager_tier_up_function) +DISALLOW_UNSAFE_FLAG(max_wasm_functions) #endif // V8_ENABLE_WEBASSEMBLY -// Disabling CPU features can lead to DCHECK failures. -DEFINE_IMPLICATION(disallow_unsafe_flags, enable_avx) -DEFINE_IMPLICATION(disallow_unsafe_flags, enable_sse3) -DEFINE_IMPLICATION(disallow_unsafe_flags, enable_sse4_1) -DEFINE_IMPLICATION(disallow_unsafe_flags, enable_sse4_2) // Features we don't currently want to fuzz. -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, cppgc_young_generation) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, enforce_x64_16byte_alignment) -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, test_only_unsafe) +DISALLOW_UNSAFE_FLAG(cppgc_young_generation) // The memory corruption API is only allowed in sandbox testing/fuzzing mode. -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags && - !sandbox_testing && !sandbox_fuzzing, - expose_memory_corruption_api) +DISALLOW_UNSAFE_FLAG_IF(!sandbox_testing && !sandbox_fuzzing, + expose_memory_corruption_api) // Flags which trigger a breakpoint on purpose. -DEFINE_NEG_IMPLICATION(disallow_unsafe_flags, maglev_break_on_entry) +DISALLOW_UNSAFE_FLAG(maglev_break_on_entry) #ifdef USE_SIMULATOR -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, stop_sim_at) +DISALLOW_UNSAFE_FLAG(stop_sim_at) #endif -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, gc_fake_mmap) +DISALLOW_UNSAFE_FLAG(csa_trap_on_node) +#ifdef DEBUG +DISALLOW_UNSAFE_FLAG(turboshaft_opt_bisect_break) +DISALLOW_UNSAFE_FLAG(turboshaft_opt_bisect_limit) +#endif // DEBUG +DISALLOW_UNSAFE_FLAG(gc_fake_mmap) // Non-standard stack sizes can lead to stack overflows (signaled as segfaults) // and produce spurious bug reports. V8 should handle stack overflows gracefully // in default configurations. -DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, stack_size) +DISALLOW_UNSAFE_FLAG_IF(stack_size<54 || stack_size> V8_DEFAULT_STACK_SIZE_KB, + stack_size) // Runs a program as security POC. This mode is used to determine whether a bug // in a program is a security problem. V8 supports many different configurations @@ -4402,10 +4446,11 @@ DEFINE_NOT_EXPLICITLY_SET_IMPLICATION(disallow_unsafe_flags, stack_size) // not guarantee a bug will be classified as a valid vulnerability. The V8 team // reserves the right to make the final determination on security impact during // triage. See docs/security/triaging.md. +// Note: Unsafe-flag implications for `run_as_security_poc` and +// `run_as_sandbox_security_poc` are defined near `disallow_unsafe_flags` above +// so they take effect before `DISALLOW_UNSAFE_FLAG` implications. DEFINE_BOOL(run_as_security_poc, false, "Run programs as security proof of concept (POC).") -// Unsafe flags generally lead to unsupported configurations. -DEFINE_IMPLICATION(run_as_security_poc, disallow_unsafe_flags) // Developer-only flags are not used in production. These flags should be robust // but breakage is not generally a security issue. DEFINE_IMPLICATION(run_as_security_poc, disallow_developer_only_features) @@ -4431,12 +4476,6 @@ DEFINE_NEG_IMPLICATION(run_as_security_poc, experimental) DEFINE_BOOL( run_as_sandbox_security_poc, false, "Run programs as security proof of concept (POC) for the V8 sandbox") -// Use the same configuration as `--run-as-security-poc`. -DEFINE_IMPLICATION(run_as_sandbox_security_poc, run_as_security_poc) -// Enable sandbox test mode which allows for using memory corruption APIs and -// also installs the crash filter that determines whether issues are crashing -// inside or outside of the sandbox. -DEFINE_IMPLICATION(run_as_sandbox_security_poc, sandbox_testing) #undef FLAG @@ -4509,7 +4548,8 @@ DEFINE_IMPLICATION(gdbjit, log) #undef DEFINE_WEAK_VALUE_IMPLICATION #undef DEFINE_GENERIC_IMPLICATION #undef DEFINE_REQUIREMENT -#undef DEFINE_NOT_EXPLICITLY_SET_IMPLICATION +#undef DISALLOW_UNSAFE_FLAG +#undef DISALLOW_UNSAFE_FLAG_IF #undef DEFINE_ALIAS_BOOL #undef DEFINE_ALIAS_BOOL_WITH_COMMENT #undef DEFINE_ALIAS_INT diff --git a/deps/v8/src/flags/flags-impl.h b/deps/v8/src/flags/flags-impl.h index b1b7f6d57257..bca9743d3bac 100644 --- a/deps/v8/src/flags/flags-impl.h +++ b/deps/v8/src/flags/flags-impl.h @@ -39,6 +39,7 @@ class V8_EXPORT_PRIVATE FlagHelpers { }; struct Flag; +V8_EXPORT_PRIVATE Flag* FindFlagByPointer(const void* ptr); V8_EXPORT_PRIVATE Flag* FindFlagByName(const char* name); V8_EXPORT_PRIVATE Flag* FindImplicationFlagByName(const char* name); diff --git a/deps/v8/src/flags/flags.cc b/deps/v8/src/flags/flags.cc index 3a87e4c7e619..06a9d2f184c6 100644 --- a/deps/v8/src/flags/flags.cc +++ b/deps/v8/src/flags/flags.cc @@ -19,11 +19,11 @@ #include <unordered_map> #include <vector> -#include "src/base/fpu.h" #include "src/base/hashing.h" #include "src/base/lazy-instance.h" #include "src/base/logging.h" #include "src/base/platform/platform.h" +#include "src/base/unique-array.h" #include "src/codegen/cpu-features.h" #include "src/flags/flags-impl.h" #include "src/logging/tracing-flags.h" @@ -158,22 +158,16 @@ struct FlagError : public std::ostringstream { } }; -bool ShouldCheckDisallowUnsafeFlagContradictions(const char* implied_by) { - static constexpr char kDisallowUnsafeFlagsStr[] = "disallow_unsafe_flags"; - return implied_by && v8_flags.disallow_unsafe_flags && - !std::strcmp(implied_by, kDisallowUnsafeFlagsStr); -} - } // namespace bool Flag::CheckFlagChange(SetBy new_set_by, bool change_flag, const char* implied_by) { + CHECK_NE(SetBy::kDefault, new_set_by); if (new_set_by == SetBy::kWeakImplication && (set_by_ == SetBy::kImplication || set_by_ == SetBy::kCommandLine)) { return false; } - if (ShouldCheckFlagContradictions() || - ShouldCheckDisallowUnsafeFlagContradictions(implied_by)) { + if (ShouldCheckFlagContradictions()) { // Readonly flags cannot change value. if (change_flag && IsReadOnly()) { if (implied_by == nullptr) { @@ -290,34 +284,45 @@ bool Flag::IsDefault() const { void Flag::ReleaseDynamicAllocations() { if (type_ != TYPE_STRING) return; - if (owns_ptr_) DeleteArray(string_value()); + if (owns_ptr_) { + DeleteArray(string_value()); + owns_ptr_ = false; + } } void Flag::Reset() { + set_by_ = SetBy::kDefault; + implied_by_ = nullptr; +#ifdef DEBUG + implied_by_ptr_ = nullptr; +#endif + if (IsReadOnly()) return; switch (type_) { case TYPE_BOOL: - set_bool_variable(bool_default(), SetBy::kDefault); + *reinterpret_cast<FlagValue<bool>*>(valptr_) = bool_default(); break; case TYPE_MAYBE_BOOL: - set_maybe_bool_variable(std::nullopt, SetBy::kDefault); + *reinterpret_cast<FlagValue<std::optional<bool>>*>(valptr_) = + std::nullopt; break; case TYPE_INT: - set_int_variable(int_default(), SetBy::kDefault); + *reinterpret_cast<FlagValue<int>*>(valptr_) = int_default(); break; case TYPE_UINT: - set_uint_variable(uint_default(), SetBy::kDefault); + *reinterpret_cast<FlagValue<unsigned int>*>(valptr_) = uint_default(); break; case TYPE_UINT64: - set_uint64_variable(uint64_default(), SetBy::kDefault); + *reinterpret_cast<FlagValue<uint64_t>*>(valptr_) = uint64_default(); break; case TYPE_FLOAT: - set_float_variable(float_default(), SetBy::kDefault); + *reinterpret_cast<FlagValue<double>*>(valptr_) = float_default(); break; case TYPE_SIZE_T: - set_size_t_variable(size_t_default(), SetBy::kDefault); + *reinterpret_cast<FlagValue<size_t>*>(valptr_) = size_t_default(); break; case TYPE_STRING: - set_string_value(string_default(), false, SetBy::kDefault); + ReleaseDynamicAllocations(); + *reinterpret_cast<FlagValue<const char*>*>(valptr_) = string_default(); break; } } @@ -346,11 +351,6 @@ struct FlagMetadata { int canonical_index; }; -constexpr bool IsTestOnlyComment(const char* comment) { - return comment && - std::string_view{comment}.ends_with(" (test-only / unsafe)"); -} - constexpr auto kFlagsMetadata = []() { struct RawMetadata { const char* name; @@ -403,34 +403,6 @@ constexpr auto kFlagsMetadata = []() { return metadata; }(); -// Number of primary test-only flags. -constexpr size_t kNumTestOnlyFlags = []() { - size_t count = 0; - for (size_t i = 0; i < kFlagsMetadata.size(); ++i) { - if (static_cast<int>(i) == kFlagsMetadata[i].canonical_index && - IsTestOnlyComment(kFlagsMetadata[i].comment)) { - count++; - } - } - return count; -}(); - -// Indices of all test-only flags (primary flags only, no aliases). -constexpr std::array<int, kNumTestOnlyFlags> kTestOnlyFlagIndices = []() { - std::array<int, kNumTestOnlyFlags> indices{}; - size_t count = 0; - for (size_t i = 0; i < kFlagsMetadata.size(); ++i) { - if (static_cast<int>(i) == kFlagsMetadata[i].canonical_index && - IsTestOnlyComment(kFlagsMetadata[i].comment)) { - indices[count++] = kFlagsMetadata[i].flag_index; - } - } - DCHECK_EQ(count, kNumTestOnlyFlags); - return indices; -}(); - -static_assert(kNumTestOnlyFlags > 0, "Must have test-only flags"); - // Number of flags plus aliases. constexpr size_t kNumAllFlags = kFlagsMetadata.size(); @@ -515,6 +487,51 @@ Flag* FindImplicationFlagByName(const char* name) { // line flags). Flag* FindFlagByName(const char* name) { return GetFlagByName(name, false); } +// Optimized look-up of flags by pointer using binary search. The mutable +// entries in 'flags' are in the exact declaration order of 'FlagValues' +// ('v8_flags'), so their 'valptr_' addresses are strictly increasing. +Flag* FindFlagByPointer(const void* ptr) { + DCHECK_LE(&v8_flags, ptr); + DCHECK_LT(ptr, &v8_flags + 1); + Flag* flag = std::lower_bound(std::begin(flags), std::end(flags), ptr, + [](const Flag& flag, const void* ptr) { + // Read-only flags have a null 'valptr_'; scan + // back to the preceding mutable flag to + // preserve the monotonic pointer order. + const Flag* f = &flag; + while (f->IsReadOnly()) { + if (f == std::begin(flags)) return true; + --f; + } + return f->valptr_ < ptr; + }); + DCHECK_NE(flag, std::end(flags)); + DCHECK(flag->PointsTo(ptr)); + return flag; +} + +template <> +EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) +void FlagValue<bool>::Set(bool new_value) { + FindFlagByPointer(this)->set_bool_variable(new_value, + Flag::SetBy::kCommandLine); +} + +template <> +EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) +void FlagValue<int>::Set(int new_value) { + FindFlagByPointer(this)->set_int_variable(new_value, + Flag::SetBy::kCommandLine); +} + +template <> +EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) +void FlagValue<const char*>::Set(const char* new_value) { + FindFlagByPointer(this)->set_string_value( + new_value ? StrDup(new_value) : nullptr, new_value != nullptr, + Flag::SetBy::kCommandLine); +} + static const char* Type2String(Flag::FlagType type) { switch (type) { case Flag::TYPE_BOOL: @@ -593,8 +610,8 @@ uint32_t ComputeFlagListHash() { std::ostringstream modified_args_as_string; if (COMPRESS_POINTERS_BOOL) modified_args_as_string << "ptr-compr"; if (DEBUG_BOOL) modified_args_as_string << "debug"; - if (base::FPU::GetFlushDenormals()) { - modified_args_as_string << "flush-denormals"; + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + modified_args_as_string << "x64-stack-16"; } #ifdef DEBUG @@ -965,7 +982,7 @@ int FlagList::SetFlagsFromString(const char* str, size_t len) { } // Allocate argument array. - auto argv = base::OwnedVector<char*>::NewForOverwrite(argc); + auto argv = base::UniqueArray<char*>::NewForOverwrite(argc); // Split the flags string into arguments. argc = 1; // be compatible with SetFlagsFromCommandLine() @@ -1186,6 +1203,26 @@ void FlagList::PrintFeatureFlagsJSON() { namespace { +template <typename T> +bool FlagValueEquals(T a, T b) { + return a == b; +} +bool FlagValueEquals(const char* a, const char* b) { + if (a == b) return true; + if (a == nullptr || b == nullptr) return false; + return std::strcmp(a, b) == 0; +} + +template <typename T> +constexpr const char* NegValuePremiseName(T when_val, const char* name, + const char* neg_name) { + if constexpr (std::is_same_v<T, bool>) { + return when_val ? neg_name : name; + } else { + return name; + } +} + class ImplicationProcessor { public: // Returns {true} if any flag value was changed. @@ -1221,18 +1258,21 @@ class ImplicationProcessor { implied_by_map_.erase(implier_flag_name); } + enum ImplicationStrength { kStrongImplication, kWeakImplication }; + // Called from {DEFINE_*_IMPLICATION} in flag-definitions.h. template <class T> bool TriggerImplication(bool premise, const char* premise_name, FlagValue<T>* conclusion_value, const char* conclusion_name, T value, - bool weak_implication) { + ImplicationStrength strength) { if (!premise) return false; Flag* conclusion_flag = FindImplicationFlagByName(conclusion_name); - const bool is_conclusion_value_change = conclusion_value->value() != value; + const bool is_conclusion_value_change = + !FlagValueEquals(conclusion_value->value(), value); if (!conclusion_flag->CheckFlagChange( - weak_implication ? Flag::SetBy::kWeakImplication - : Flag::SetBy::kImplication, + strength == kWeakImplication ? Flag::SetBy::kWeakImplication + : Flag::SetBy::kImplication, is_conclusion_value_change, premise_name)) { return false; } @@ -1269,38 +1309,23 @@ class ImplicationProcessor { bool TriggerImplication(bool premise, const char* premise_name, const FlagValue<T>* conclusion_value, const char* conclusion_name, T value, - bool weak_implication) { + ImplicationStrength strength) { if (!premise) return false; Flag* conclusion_flag = FindImplicationFlagByName(conclusion_name); // Because this is the `const FlagValue*` overload: DCHECK(conclusion_flag->IsReadOnly()); if (!conclusion_flag->CheckFlagChange( - weak_implication ? Flag::SetBy::kWeakImplication - : Flag::SetBy::kImplication, - conclusion_value->value() != value, premise_name)) { + strength == kWeakImplication ? Flag::SetBy::kWeakImplication + : Flag::SetBy::kImplication, + !FlagValueEquals(conclusion_value->value(), value), premise_name)) { return false; } // Must equal the default value, otherwise CheckFlagChange should've // returned false. - DCHECK_EQ(value, conclusion_flag->GetDefaultValue<T>()); + DCHECK(FlagValueEquals(value, conclusion_flag->GetDefaultValue<T>())); return true; } - // Called from DEFINE_NOT_EXPLICITLY_SET_IMPLICATION in flag-definitions.h. - void TriggerNotExplicitlySetImplication(bool premise, - const char* premise_name, - const char* conclusion_name) { - if (!premise) { - return; - } - Flag* conclusion_flag = FindImplicationFlagByName(conclusion_name); - if (conclusion_flag->set_by_ != Flag::SetBy::kCommandLine) { - return; - } - FlagError{} << "Command-line provided flag " << FlagName{conclusion_name} - << " is prohibited by " << FlagName{premise_name}; - } - void CheckForCycle() { // Make sure flag implications reach a fixed point within // {kMaxNumIterations} iterations. @@ -1358,12 +1383,6 @@ void FlagList::ResolveContradictionsWhenFuzzing() { std::vector<std::tuple<Flag*, Flag*>> contradictions; - // Automatically reset all test-only flags. - static constexpr int fuzzing_flag_index = FindFlagIndexByName("fuzzing"); - for (int index : kTestOnlyFlagIndices) { - contradictions.emplace_back(&flags[index], &flags[fuzzing_flag_index]); - } - // List of flags that lead to known contradictory cycles when both // deviate from their defaults. One of them will be reset with precedence // left to right. @@ -1427,9 +1446,6 @@ void FlagList::ResolveContradictionsWhenFuzzing() { CONTRADICTION(single_threaded, stress_concurrent_inlining_attach_code); #if V8_ENABLE_WEBASSEMBLY CONTRADICTION(wasm_test_streaming, predictable); - CONTRADICTION(single_threaded, wasm_pgo_to_file); - CONTRADICTION(single_threaded, wasm_generate_compilation_hints); - CONTRADICTION(single_threaded, trace_wasm_generate_compilation_hints); #endif // V8_ENABLE_WEBASSEMBLY CONTRADICTION(stress_concurrent_inlining, turboshaft_assert_types); CONTRADICTION(stress_concurrent_inlining_attach_code, @@ -1478,11 +1494,6 @@ void FlagList::ResolveContradictionsWhenFuzzing() { // Not useful for differential fuzzing: https://crbug.com/496356383 RESET_WHEN_CORRECTNESS_FUZZING(heap_snapshot_on_gc); - // https://crbug.com/550629905 -#if V8_ENABLE_WEBASSEMBLY - RESET_WHEN_CORRECTNESS_FUZZING(wasm_pgo_to_file); -#endif // V8_ENABLE_WEBASSEMBLY - // https://crbug.com/369974230 RESET_WHEN_FUZZING(expose_async_hooks); @@ -1495,10 +1506,6 @@ void FlagList::ResolveContradictionsWhenFuzzing() { // https://crbug.com/393401455 RESET_WHEN_FUZZING(turboshaft); - if (v8_flags.turbofan && !v8_flags.turbolev) { - RESET_WHEN_FUZZING(array_destructure_bytecode); - } - #if V8_ENABLE_WEBASSEMBLY if (v8_flags.wasm_max_code_space_size_mb > kDefaultMaxWasmCodeSpaceSizeMb) { // Skip the warning on correctness (differential) fuzzing to prevent false @@ -1521,6 +1528,8 @@ void FlagList::ResolveContradictionsWhenFuzzing() { // Ensure we never reset the fuzzing or POC verification flags. CHECK(!flag1->PointsTo(&v8_flags.fuzzing)); CHECK(!flag1->PointsTo(&v8_flags.correctness_fuzzer_suppressions)); + CHECK( + !flag1->PointsTo(&v8_flags.correctness_fuzzer_cross_arch_suppressions)); CHECK(!flag1->PointsTo(&v8_flags.sandbox_fuzzing)); CHECK(!flag1->PointsTo(&v8_flags.sandbox_testing)); CHECK(!flag1->PointsTo(&v8_flags.run_as_security_poc)); diff --git a/deps/v8/src/flags/flags.h b/deps/v8/src/flags/flags.h index dcebca30819f..72ba408ac324 100644 --- a/deps/v8/src/flags/flags.h +++ b/deps/v8/src/flags/flags.h @@ -7,6 +7,7 @@ #include <optional> +#include "src/base/export-template.h" #include "src/common/globals.h" #if V8_ENABLE_WEBASSEMBLY @@ -50,9 +51,14 @@ class FlagValue { // use it for computing other constants. constexpr T value() const { return value_; } - // Assign a new value (defined below). + // Assign a new value (defined below). This does not update the Flag metadata + // or check for contradictions. inline FlagValue<T>& operator=(T new_value); + // Set a new value (updates Flag metadata and checks for flag contradictions). + EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) + void Set(T new_value); + private: T value_; }; diff --git a/deps/v8/src/fuzzilli/cov.cc b/deps/v8/src/fuzzilli/cov.cc index 1dc9ba72d25c..ee7eef2bab1b 100644 --- a/deps/v8/src/fuzzilli/cov.cc +++ b/deps/v8/src/fuzzilli/cov.cc @@ -6,6 +6,7 @@ #include <fcntl.h> #include <inttypes.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -14,9 +15,20 @@ #include <sys/wait.h> #include <unistd.h> +#include <algorithm> +#include <iterator> + #include "src/base/platform/memory.h" +#include "src/base/platform/mutex.h" +#include "src/base/platform/platform.h" #include "src/sandbox/hardware-support.h" +#if defined(V8_USE_ADDRESS_SANITIZER) || defined(V8_USE_MEMORY_SANITIZER) +// For __sanitizer_set_death_callback, see +// sanitizer_cov_install_crash_flush_handlers. +#include <sanitizer/common_interface_defs.h> +#endif + #define SHM_SIZE 0x200000 #define MAX_EDGES ((SHM_SIZE - 4) * 8) @@ -31,6 +43,12 @@ uint32_t *edges_start, *edges_stop; uint32_t builtins_start; uint32_t builtins_edge_count; +namespace { +// Number of registered inline-bool-flag regions, see +// __sanitizer_cov_bool_flag_init. +size_t num_bool_flag_regions = 0; +} // namespace + // We support two modes: // 1. Single-DSO mode (standard V8): // - Assumes all instrumented code is in a single DSO. @@ -83,10 +101,19 @@ __attribute__((visibility("default"))) void fuzzilli_cov_enable() { // file. } -__attribute__((visibility("default"))) void sanitizer_cov_reset_edgeguards() { - uint32_t N = 0; - for (uint32_t* x = edges_start; x < edges_stop && N < MAX_EDGES; x++) - *x = ++N; +// This runs after every REPRL execution and touches every guard, so it must +// not be instrumented itself: otherwise every loop iteration would invoke the +// coverage callback (~1.9M calls per execution). The loop bounds are copied to +// locals so that the compiler can vectorize the loop. +__attribute__((visibility("default"), no_sanitize("coverage"))) void +sanitizer_cov_reset_edgeguards() { + uint32_t* const start = edges_start; + uint32_t* const stop = edges_stop; + if (start == nullptr || stop == nullptr || stop < start) return; + const size_t count = std::min<size_t>(stop - start, MAX_EDGES); + for (size_t i = 0; i < count; i++) { + start[i] = static_cast<uint32_t>(i + 1); + } } __attribute__((visibility("default"))) extern "C" void @@ -101,6 +128,12 @@ __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) { return; } + if (num_bool_flag_regions > 0) { + fprintf(stderr, + "[COV] Cannot mix trace-pc-guard and inline-bool-flag coverage\n"); + _exit(-1); + } + if (!support_multi_dso && edges_start != nullptr) { // In single-DSO mode, we should initialize the shared memory region only // once. If we ever see a different region, we will overwrite the previous @@ -128,6 +161,245 @@ __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) { shm_key ? shm_key : "anonymous shmem", shmem->num_edges); } +// Support for -fsanitize-coverage=inline-bool-flag. +// +// With trace-pc-guard, every executed edge calls __sanitizer_cov_trace_pc_guard +// (even after the guard has been zeroed), which writes directly into the shared +// memory bitmap. These calls are expensive: avoiding them reduces the CPU time +// of a typical execution by ~40%. With inline-bool-flag, the compiler instead +// emits an inline `if (!flag) flag = true;` for every edge, where the flags are +// bytes in d8's own memory. (The check is emitted by the compiler, it avoids +// dirtying the cache line of a flag that is already set.) The flags are +// translated into the shared memory bitmap (and cleared) only once per +// execution by sanitizer_cov_flush_bool_flags(). Flag i of a region is reported +// as bitmap index `first_index + i`, exactly like the guard values in +// trace-pc-guard mode, so the coverage bitmap layout (and Fuzzilli) do not +// change. +// +// Since the bitmap is no longer updated in real time, the flags must also be +// flushed when the process crashes, because Fuzzilli uses the coverage of +// crashing executions to deduplicate crashes. See +// sanitizer_cov_install_crash_flush_handlers(). +namespace { + +struct BoolFlagRegion { + uint8_t* start; + uint8_t* stop; + // Bitmap index of the first flag of this region. + uint32_t first_index; +}; + +constexpr size_t kMaxBoolFlagRegions = 64; +BoolFlagRegion bool_flag_regions[kMaxBoolFlagRegions]; + +// Same as cov_set_edge, but guaranteed to not be instrumented (cov_set_edge +// would be if it was not inlined). +__attribute__((no_sanitize("coverage"))) inline void SetEdge(uint8_t* bitmap, + uint32_t index) { + bitmap[index >> 3] |= static_cast<uint8_t>(1 << (index & 7)); +} + +// Translates the set flags of a region into bitmap bits (unless `bitmap` is +// nullptr) and clears them. Must be async-signal-safe (it is also used from +// crash signal handlers). +__attribute__((no_sanitize("coverage"))) inline void FlushBoolFlagRegion( + const BoolFlagRegion& region, uint8_t* bitmap) { + uint8_t* p = region.start; + uint8_t* const stop = region.stop; + uint32_t index = region.first_index; + // Only a small fraction of all edges is hit by an execution, so scan eight + // flags at a time and only look at the individual flags of non-zero words. + // Flags are cleared individually (instead of zeroing the whole word) so that + // flags concurrently set by other threads are not lost. + while (p < stop && (reinterpret_cast<uintptr_t>(p) & 7) != 0) { + if (*p) { + *p = 0; + if (bitmap) SetEdge(bitmap, index); + } + p++; + index++; + } + for (; stop - p >= 8; p += 8, index += 8) { + uint64_t word; + memcpy(&word, p, sizeof(word)); + if (word == 0) continue; + for (int j = 0; j < 8; j++) { + if (p[j]) { + p[j] = 0; + if (bitmap) SetEdge(bitmap, index + j); + } + } + } + for (; p < stop; p++, index++) { + if (*p) { + *p = 0; + if (bitmap) SetEdge(bitmap, index); + } + } +} + +} // namespace + +// Called by the module constructors emitted by the compiler for +// -fsanitize-coverage=inline-bool-flag, once per instrumented DSO and before +// any instrumented code of that DSO runs. [start, stop) are the (zero +// initialized) edge flags of the DSO, which the instrumented code sets when the +// corresponding edge is executed. This reserves a range of bitmap indices for +// the flags of the region (after the edges of previously registered regions) +// and registers the region, so that sanitizer_cov_flush_bool_flags() can +// translate its flags into the coverage bitmap. +__attribute__((visibility("default"))) extern "C" void +__sanitizer_cov_bool_flag_init(bool* start, bool* stop) { +#ifdef V8_ENABLE_SANDBOX_HARDWARE_SUPPORT + // The inline flag stores cannot temporarily grant access to the default pkey + // like __sanitizer_cov_trace_pc_guard does, so they would fault in sandboxed + // execution mode. (This combination is also rejected by BUILD.gn.) + fprintf(stderr, + "[COV] inline-bool-flag coverage is not supported with sandbox " + "hardware support, use trace-pc-guard instead\n"); + _exit(-1); +#else + if (!shmem) { + initialize_shmem(); + } + + uint8_t* region_start = reinterpret_cast<uint8_t*>(start); + uint8_t* region_stop = reinterpret_cast<uint8_t*>(stop); + // As for trace-pc-guard, the same region may be reported multiple times. + for (size_t i = 0; i < num_bool_flag_regions; i++) { + if (bool_flag_regions[i].start == region_start) return; + } + + if (edges_start != nullptr) { + fprintf(stderr, + "[COV] Cannot mix trace-pc-guard and inline-bool-flag coverage\n"); + _exit(-1); + } + if (!support_multi_dso && num_bool_flag_regions > 0) { + fprintf(stderr, + "[COV] Multiple initialization of shmem!" + " This is probably not intended! Currently only one edge" + " region is supported\n"); + _exit(-1); + } + if (num_bool_flag_regions >= kMaxBoolFlagRegions) { + fprintf(stderr, "[COV] Too many edge flag regions (at most %zu)\n", + kMaxBoolFlagRegions); + _exit(-1); + } + + const size_t available = MAX_EDGES - shmem->num_edges; + if (static_cast<size_t>(region_stop - region_start) > available) { + // Like in trace-pc-guard mode, edges beyond MAX_EDGES are not reported. + // This does not happen for d8 (~1.9M edges, MAX_EDGES is ~16.8M), but may + // in multi-DSO mode. + region_stop = region_start + available; + } + // Fully initialize the region before making it visible to + // sanitizer_cov_flush_bool_flags(), which may run from a crash handler. + BoolFlagRegion& region = bool_flag_regions[num_bool_flag_regions]; + region.start = region_start; + region.stop = region_stop; + region.first_index = shmem->num_edges + 1; + shmem->num_edges += static_cast<uint32_t>(region_stop - region_start); + num_bool_flag_regions++; + + if (builtins_edge_count == 0) { + builtins_start = 1 + shmem->num_edges; + } + + const char* shm_key = getenv("SHM_ID"); + fprintf(stderr, + "[COV] edge flags initialized. Shared memory: %s with %u edges\n", + shm_key ? shm_key : "anonymous shmem", shmem->num_edges); +#endif // V8_ENABLE_SANDBOX_HARDWARE_SUPPORT +} + +__attribute__((visibility("default"), no_sanitize("coverage"))) void +sanitizer_cov_flush_bool_flags() { + if (shmem == nullptr) return; + for (size_t i = 0; i < num_bool_flag_regions; i++) { + FlushBoolFlagRegion(bool_flag_regions[i], shmem->edges); + } +} + +__attribute__((visibility("default"), no_sanitize("coverage"))) void +sanitizer_cov_discard_bool_flags() { + for (size_t i = 0; i < num_bool_flag_regions; i++) { + FlushBoolFlagRegion(bool_flag_regions[i], nullptr); + } +} + +namespace { + +constexpr int kCrashSignals[] = {SIGSEGV, SIGBUS, SIGILL, + SIGTRAP, SIGFPE, SIGABRT}; +struct sigaction previous_crash_handlers[std::size(kCrashSignals)]; + +__attribute__((no_sanitize("coverage"))) void CrashFlushSignalHandler( + int signal, siginfo_t* info, void* context) { + sanitizer_cov_flush_bool_flags(); + + // Reinstall the handler that was active before ours and let it handle the + // signal, so that the crash behaves exactly as before (same signal, same + // stack dump, same exit status). + for (size_t i = 0; i < std::size(kCrashSignals); i++) { + if (kCrashSignals[i] == signal) { + sigaction(signal, &previous_crash_handlers[i], nullptr); + break; + } + } + // For hardware faults, returning re-executes the faulting instruction, which + // then raises the signal again. Signals sent by software (e.g. by abort()) + // must be raised again explicitly. The same is true for SIGTRAP, as the + // program counter points after the trapping instruction (int3). The signal + // is blocked while this handler runs, so it is delivered once we return. + if (info->si_code <= 0 || signal == SIGTRAP || signal == SIGABRT) { + raise(signal); + } +} + +} // namespace + +// IMPORTANT: this is order-sensitive. The handlers defer to the handlers that +// were installed before them, so they must be installed after handlers that do +// not forward signals (e.g. V8's in-process stack dumper) and before handlers +// that forward unhandled signals to the previous handler (e.g. the Wasm trap +// handler). See Shell::Main. +__attribute__((visibility("default"))) void +sanitizer_cov_install_crash_flush_handlers() { + // Only required if the bitmap is not updated in real time. + if (num_bool_flag_regions == 0) return; + // Installing the handlers twice would make them defer to themselves. + static bool installed = false; + if (installed) return; + installed = true; +#if defined(V8_USE_ADDRESS_SANITIZER) || defined(V8_USE_MEMORY_SANITIZER) + // Errors detected by a sanitizer only end in a signal (SIGABRT) with + // abort_on_error=1, which Fuzzilli requires for sanitizer builds. Flush from + // the sanitizer's death callback as well, which runs in any case. + __sanitizer_set_death_callback(&sanitizer_cov_flush_bool_flags); +#endif + // Without an alternate signal stack, signal handlers cannot run after a + // native stack overflow, and the coverage of such crashes would be lost. + // (The stack dumping and Wasm trap handlers also use SA_ONSTACK, so they + // will then run on this stack as well.) Note that this only covers the main + // thread, so the coverage of a stack overflow in a Worker thread is lost. + v8::base::OS::EnsureAlternativeSignalStackIsAvailableForCurrentThread(); + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_sigaction = &CrashFlushSignalHandler; + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + sigemptyset(&action.sa_mask); + for (size_t i = 0; i < std::size(kCrashSignals); i++) { + if (sigaction(kCrashSignals[i], &action, &previous_crash_handlers[i]) != + 0) { + fprintf(stderr, "[COV] Failed to install crash signal handler\n"); + _exit(-1); + } + } +} + #ifdef V8_ENABLE_SANDBOX_HARDWARE_SUPPORT // We need to allow the coverage instrumentation to run in sandboxed execution // mode, for example to be able to run sandboxed C++ code. As the coverage @@ -248,3 +520,56 @@ bool cov_has_builtins_edges() { void cov_set_builtin_edge(uint32_t block_index) { cov_set_edge(shmem->edges, builtins_start + block_index); } + +uint32_t optimized_code_start = 0; +uint32_t optimized_code_edge_count = 0; + +struct PendingOptimizedCodeCoverage { + v8::base::Mutex mutex; + std::vector<uint32_t> edges; +}; + +PendingOptimizedCodeCoverage& GetPendingOptimizedCodeCoverage() { + static PendingOptimizedCodeCoverage* pending = + new PendingOptimizedCodeCoverage(); + return *pending; +} + +void cov_init_optimized_code_edges(uint32_t num_edges) { + if (!shmem) { + initialize_shmem(); + } + + CHECK_EQ(optimized_code_edge_count, 0); + if (num_edges + shmem->num_edges > MAX_EDGES) { + fprintf(stderr, + "[COV] Error: Insufficient amount of edges left for optimized code " + "coverage.\n"); + exit(-1); + } + optimized_code_edge_count = num_edges; + optimized_code_start = 1 + shmem->num_edges; + shmem->num_edges += optimized_code_edge_count; + fprintf(stderr, "[COV] Additional %d edges for optimized code initialized.\n", + num_edges); +} + +void cov_add_optimized_code_coverage_edges(const std::set<uint32_t>& hashes) { + if (optimized_code_edge_count == 0) return; + auto& pending = GetPendingOptimizedCodeCoverage(); + v8::base::MutexGuard lock(&pending.mutex); + pending.edges.insert(pending.edges.end(), hashes.begin(), hashes.end()); +} + +size_t cov_update_and_reset_optimized_code_coverage() { + if (optimized_code_edge_count == 0) return 0; + auto& pending = GetPendingOptimizedCodeCoverage(); + v8::base::MutexGuard lock(&pending.mutex); + for (uint32_t hash : pending.edges) { + cov_set_edge(shmem->edges, + (hash % optimized_code_edge_count) + optimized_code_start); + } + size_t count = pending.edges.size(); + pending.edges.clear(); + return count; +} diff --git a/deps/v8/src/fuzzilli/cov.h b/deps/v8/src/fuzzilli/cov.h index 74a59ceb3f06..e0ed576f006e 100644 --- a/deps/v8/src/fuzzilli/cov.h +++ b/deps/v8/src/fuzzilli/cov.h @@ -11,6 +11,7 @@ // https://clang.llvm.org/docs/SanitizerCoverage.html #include <cstdint> +#include <set> #include <vector> inline void cov_set_edge(uint8_t* edges, uint32_t index) { @@ -27,9 +28,28 @@ inline bool cov_is_edge_set(const uint8_t* edges, uint32_t index) { void fuzzilli_cov_enable(); void sanitizer_cov_reset_edgeguards(); +// Only does something when built with -fsanitize-coverage=inline-bool-flag: +// transfers the edge flags set since the last call into the coverage bitmap +// and clears them. Must be called before the coverage bitmap is read. +void sanitizer_cov_flush_bool_flags(); +// Only does something when built with -fsanitize-coverage=inline-bool-flag: +// clears the edge flags set since the last call without reporting them. Used +// to not attribute edges hit between two executions (e.g. during startup) to +// the next execution. +void sanitizer_cov_discard_bool_flags(); +// Only does something when built with -fsanitize-coverage=inline-bool-flag: +// installs signal handlers that flush the edge flags into the coverage bitmap +// when the process crashes and then defer to the previously installed handler. +void sanitizer_cov_install_crash_flush_handlers(); uint32_t sanitizer_cov_count_discovered_edges(); void cov_init_builtins_edges(uint32_t num_edges); bool cov_has_builtins_edges(); void cov_set_builtin_edge(uint32_t block_index); +constexpr uint32_t kFuzzilliNumOptimizedCodeEdges = 256 * 1024; + +void cov_init_optimized_code_edges(uint32_t num_edges); +void cov_add_optimized_code_coverage_edges(const std::set<uint32_t>& hashes); +size_t cov_update_and_reset_optimized_code_coverage(); + #endif // V8_FUZZILLI_COV_H_ diff --git a/deps/v8/src/fuzzilli/fuzzilli.h b/deps/v8/src/fuzzilli/fuzzilli.h index 89ef3e501172..125761575e3f 100644 --- a/deps/v8/src/fuzzilli/fuzzilli.h +++ b/deps/v8/src/fuzzilli/fuzzilli.h @@ -31,8 +31,7 @@ class FuzzilliExtension : public v8::Extension { private: static const char* BuildSource(char* buf, size_t size, const char* fun_name) { - base::SNPrintF(base::VectorOf(buf, size), "native function %s();", - fun_name); + base::SNPrintF({buf, size}, "native function %s();", fun_name); return buf; } diff --git a/deps/v8/src/gen/.clang-format b/deps/v8/src/gen/.clang-format new file mode 100644 index 000000000000..9d159247d518 --- /dev/null +++ b/deps/v8/src/gen/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: false diff --git a/deps/v8/src/gen/OWNERS b/deps/v8/src/gen/OWNERS new file mode 100644 index 000000000000..48d72aea5eec --- /dev/null +++ b/deps/v8/src/gen/OWNERS @@ -0,0 +1 @@ +file:../../COMMON_OWNERS diff --git a/deps/v8/src/gen/README.md b/deps/v8/src/gen/README.md new file mode 100644 index 000000000000..3c2d1c929634 --- /dev/null +++ b/deps/v8/src/gen/README.md @@ -0,0 +1,28 @@ +# Generated files + +This directory contains generated files committed to the repository. Do not +edit them manually. + +| Files | Generator | +| --- | --- | +| `<config>/static-roots.h` | mksnapshot | +| `intl-wasm/builtin-definitions.h` | Torque | +| `intl-wasm/class-forward-declarations.h` | Torque | +| `intl-wasm/interface-descriptors.inc` | Torque | +| `intl-wasm/bytecodes-builtins-list.h` | bytecode builtins list generator | +| `intl-wasm/instance-types.h` | metagen | + +Static roots have four configurations: `intl-wasm`, `intl-nowasm`, +`nointl-wasm`, and `nointl-nowasm`. + +Regenerate static roots: + +```sh +tools/dev/gen-static-roots.py +``` + +Regenerate the other headers using the default build configuration: + +```sh +tools/dev/gm.py gen-checked-in-headers +``` diff --git a/deps/v8/src/roots/static-roots-intl-nowasm.h b/deps/v8/src/gen/intl-nowasm/static-roots.h similarity index 99% rename from deps/v8/src/roots/static-roots-intl-nowasm.h rename to deps/v8/src/gen/intl-nowasm/static-roots.h index b1c5628998c4..375816ed328f 100644 --- a/deps/v8/src/roots/static-roots-intl-nowasm.h +++ b/deps/v8/src/gen/intl-nowasm/static-roots.h @@ -5,8 +5,8 @@ // This file is automatically generated by `tools/dev/gen-static-roots.py`. Do // not edit manually. -#ifndef V8_ROOTS_STATIC_ROOTS_INTL_NOWASM_H_ -#define V8_ROOTS_STATIC_ROOTS_INTL_NOWASM_H_ +#ifndef V8_GEN_INTL_NOWASM_STATIC_ROOTS_H_ +#define V8_GEN_INTL_NOWASM_STATIC_ROOTS_H_ // IWYU pragma: private "src/roots/static-roots.h" @@ -207,8 +207,9 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kCodeWrapperMap = kClassPositionsMap + 40; static constexpr Tagged_t kDebugScriptScopeInfoMap = kCodeWrapperMap + 40; static constexpr Tagged_t kErrorStackDataMap = kDebugScriptScopeInfoMap + 40; + static constexpr Tagged_t kForInEnumeratorHolderMap = kErrorStackDataMap + 40; static constexpr Tagged_t kFunctionTemplateRareDataMap = - kErrorStackDataMap + 40; + kForInEnumeratorHolderMap + 40; static constexpr Tagged_t kModuleRequestMap = kFunctionTemplateRareDataMap + 40; static constexpr Tagged_t kPromiseCapabilityMap = kModuleRequestMap + 40; @@ -246,8 +247,10 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kStoreHandler1Map = kStoreHandler0Map + 40; static constexpr Tagged_t kStoreHandler2Map = kStoreHandler1Map + 40; static constexpr Tagged_t kStoreHandler3Map = kStoreHandler2Map + 40; - static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + static constexpr Tagged_t kUninitializedHeapNumberMap = kStoreHandler3Map + 40; + static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + kUninitializedHeapNumberMap + 40; static constexpr Tagged_t kTurboshaftWord64SetTypeMap = kTurboshaftWord32SetTypeMap + 40; static constexpr Tagged_t kTurboshaftFloat64SetTypeMap = @@ -756,10 +759,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kas_string = kArrayIterator_string + 28; static constexpr Tagged_t kassert_string = kas_string + 16; static constexpr Tagged_t kasync_string = kassert_string + 20; - static constexpr Tagged_t kAtomicsCondition_string = kasync_string + 20; - static constexpr Tagged_t kAtomicsMutex_string = - kAtomicsCondition_string + 32; - static constexpr Tagged_t kauto_string = kAtomicsMutex_string + 28; + static constexpr Tagged_t kauto_string = kasync_string + 20; static constexpr Tagged_t kBigInt64Array_string = kauto_string + 16; static constexpr Tagged_t kBigInt_string = kBigInt64Array_string + 28; static constexpr Tagged_t kbigint_string = kBigInt_string + 20; @@ -1135,10 +1135,8 @@ struct StaticReadOnlyRoot { ksealed_symbol + 16; static constexpr Tagged_t kshared_struct_map_registry_key_symbol = kshared_struct_map_elements_template_symbol + 16; - static constexpr Tagged_t kstrict_function_transition_symbol = - kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_function_literal_id_symbol = - kstrict_function_transition_symbol + 16; + kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_slot_id_symbol = ktemplate_literal_function_literal_id_symbol + 16; static constexpr Tagged_t kwasm_cross_instance_call_symbol = @@ -1222,16 +1220,14 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kCppHeapExternalMap = 0x1a0051; static constexpr Tagged_t kCppGCManagedBaseMap = 0x1a0079; static constexpr Tagged_t kJSSharedArrayMap = 0x1a00a1; - static constexpr Tagged_t kJSAtomicsMutexMap = 0x1a00e5; - static constexpr Tagged_t kJSAtomicsConditionMap = 0x1a010d; - static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1a0135; - static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1a0189; + static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1a00e5; + static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1a0139; static constexpr Tagged_t kFirstAllocatedRoot = 0x11; - static constexpr Tagged_t kLastAllocatedRoot = 0x1a0189; + static constexpr Tagged_t kLastAllocatedRoot = 0x1a0139; }; -static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 1021> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1272,7 +1268,7 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kPropertyCellHoleValue, StaticReadOnlyRoot::kStaleRegister, StaticReadOnlyRoot::kTerminationException, -// TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. + // TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. #ifdef V8_ENABLE_TDZ_HOLE StaticReadOnlyRoot::kTdzHoleValue, #else @@ -1330,6 +1326,7 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -1376,8 +1373,6 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kBooleanMap, StaticReadOnlyRoot::kHoleMap, StaticReadOnlyRoot::kJSSharedArrayMap, - StaticReadOnlyRoot::kJSAtomicsMutexMap, - StaticReadOnlyRoot::kJSAtomicsConditionMap, StaticReadOnlyRoot::kDescriptorArrayMap, StaticReadOnlyRoot::kOnHeapBasicBlockProfilerDataMap, StaticReadOnlyRoot::kTurbofanBitsetTypeMap, @@ -1845,8 +1840,6 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kas_string, StaticReadOnlyRoot::kassert_string, StaticReadOnlyRoot::kasync_string, - StaticReadOnlyRoot::kAtomicsCondition_string, - StaticReadOnlyRoot::kAtomicsMutex_string, StaticReadOnlyRoot::kauto_string, StaticReadOnlyRoot::kBigInt64Array_string, StaticReadOnlyRoot::kBigInt_string, @@ -2178,7 +2171,6 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::ksealed_symbol, StaticReadOnlyRoot::kshared_struct_map_elements_template_symbol, StaticReadOnlyRoot::kshared_struct_map_registry_key_symbol, - StaticReadOnlyRoot::kstrict_function_transition_symbol, StaticReadOnlyRoot::ktemplate_literal_function_literal_id_symbol, StaticReadOnlyRoot::ktemplate_literal_slot_id_symbol, StaticReadOnlyRoot::kwasm_cross_instance_call_symbol, @@ -2218,6 +2210,7 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, @@ -2266,4 +2259,4 @@ static constexpr std::array<Tagged_t, 1024> StaticReadOnlyRootsPointerTable = { } // namespace internal } // namespace v8 #endif // V8_STATIC_ROOTS_BOOL -#endif // V8_ROOTS_STATIC_ROOTS_INTL_NOWASM_H_ +#endif // V8_GEN_INTL_NOWASM_STATIC_ROOTS_H_ diff --git a/deps/v8/src/gen/intl-wasm/builtin-definitions.h b/deps/v8/src/gen/intl-wasm/builtin-definitions.h new file mode 100644 index 000000000000..84d034a605be --- /dev/null +++ b/deps/v8/src/gen/intl-wasm/builtin-definitions.h @@ -0,0 +1,773 @@ +#ifndef V8_GEN_TORQUE_GENERATED_BUILTIN_DEFINITIONS_H_ +#define V8_GEN_TORQUE_GENERATED_BUILTIN_DEFINITIONS_H_ + + +#define BUILTIN_LIST_FROM_TORQUE(CPP, TFJ_TSA, TFJ, TFC_TSA, TFC, TFS, TFH, ASM) \ +TFJ(AggregateErrorConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeAt, JSParameterCount(1), kReceiver, kIndex) \ +TFJ(ArrayPrototypeConcat, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeCopyWithin, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayEveryLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kThisArg, kInitialK, kLength) \ +TFJ(ArrayEveryLoopLazyDeoptContinuation, JSParameterCount(5), kReceiver, kCallback, kThisArg, kInitialK, kLength, kResult) \ +TFC(ArrayEveryLoopContinuation, ArrayEveryLoopContinuation) \ +TFJ(ArrayEvery, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayFilterLoopEagerDeoptContinuation, JSParameterCount(6), kReceiver, kCallback, kThisArg, kArray, kInitialK, kLength, kInitialTo) \ +TFJ(ArrayFilterLoopLazyDeoptContinuation, JSParameterCount(8), kReceiver, kCallback, kThisArg, kArray, kInitialK, kLength, kValueK, kInitialTo, kResult) \ +TFC(ArrayFilterLoopContinuation, ArrayFilterLoopContinuation) \ +TFJ(ArrayFilter, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayFindLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kThisArg, kInitialK, kLength) \ +TFJ(ArrayFindLoopLazyDeoptContinuation, JSParameterCount(5), kReceiver, kCallback, kThisArg, kInitialK, kLength, kResult) \ +TFJ(ArrayFindLoopAfterCallbackLazyDeoptContinuation, JSParameterCount(6), kReceiver, kCallback, kThisArg, kInitialK, kLength, kFoundValue, kIsFound) \ +TFC(ArrayFindLoopContinuation, ArrayFindLoopContinuation) \ +TFJ(ArrayPrototypeFind, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayFindIndexLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kThisArg, kInitialK, kLength) \ +TFJ(ArrayFindIndexLoopLazyDeoptContinuation, JSParameterCount(5), kReceiver, kCallback, kThisArg, kInitialK, kLength, kResult) \ +TFJ(ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation, JSParameterCount(6), kReceiver, kCallback, kThisArg, kInitialK, kLength, kFoundValue, kIsFound) \ +TFC(ArrayFindIndexLoopContinuation, ArrayFindIndexLoopContinuation) \ +TFJ(ArrayPrototypeFindIndex, kDontAdaptArgumentsSentinel) \ +TFC(ArrayFindLastLoopContinuation, ArrayFindLastLoopContinuation) \ +TFJ(ArrayPrototypeFindLast, kDontAdaptArgumentsSentinel) \ +TFC(ArrayFindLastIndexLoopContinuation, ArrayFindLastIndexLoopContinuation) \ +TFJ(ArrayPrototypeFindLastIndex, kDontAdaptArgumentsSentinel) \ +TFC(FlattenIntoArrayWithoutMapFn, FlattenIntoArrayWithoutMapFn) \ +TFC(FlattenIntoArrayWithMapFn, FlattenIntoArrayWithMapFn) \ +TFJ(ArrayPrototypeFlat, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeFlatMap, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayForEachLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kThisArg, kInitialK, kLength) \ +TFJ(ArrayForEachLoopLazyDeoptContinuation, JSParameterCount(5), kReceiver, kCallback, kThisArg, kInitialK, kLength, kResult) \ +TFC(ArrayForEachLoopContinuation, ArrayForEachLoopContinuation) \ +TFJ(ArrayForEach, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayFromAsyncIterableOnFulfilled, JSParameterCount(1), kReceiver, kResult) \ +TFJ(ArrayFromAsyncIterableOnRejected, JSParameterCount(1), kReceiver, kResult) \ +TFJ(ArrayFromAsyncArrayLikeOnFulfilled, JSParameterCount(1), kReceiver, kResult) \ +TFJ(ArrayFromAsyncArrayLikeOnRejected, JSParameterCount(1), kReceiver, kResult) \ +TFJ(ArrayFromAsync, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayFrom, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayIsArray, JSParameterCount(1), kReceiver, kArg) \ +TFC(LoadJoinElement_DictionaryElements_0, LoadJoinElement_DictionaryElements_0) \ +TFC(LoadJoinElement_FastSmiOrObjectElements_0, LoadJoinElement_FastSmiOrObjectElements_0) \ +TFC(LoadJoinElement_FastDoubleElements_0, LoadJoinElement_FastDoubleElements_0) \ +TFC(ConvertToLocaleString, ConvertToLocaleString) \ +TFC(JoinStackPush, JoinStackPush) \ +TFC(JoinStackPop, JoinStackPop) \ +TFJ(ArrayPrototypeJoin, kDontAdaptArgumentsSentinel) \ +TFC(ArrayPrototypeJoinImpl, ArrayPrototypeJoinImpl) \ +TFJ(ArrayPrototypeToLocaleString, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeToString, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeJoin, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeToLocaleString, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeLastIndexOf, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayMapPreLoopLazyDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kThisArg, kLength, kResult) \ +TFJ(ArrayMapLoopEagerDeoptContinuation, JSParameterCount(5), kReceiver, kCallback, kThisArg, kArray, kInitialK, kLength) \ +TFJ(ArrayMapLoopLazyDeoptContinuation, JSParameterCount(6), kReceiver, kCallback, kThisArg, kArray, kInitialK, kLength, kResult) \ +TFC(ArrayMapLoopContinuation, ArrayMapLoopContinuation) \ +TFJ(ArrayMap, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayOf, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayReduceRightPreLoopEagerDeoptContinuation, JSParameterCount(2), kReceiver, kCallback, kLength) \ +TFJ(ArrayReduceRightLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kInitialK, kLength, kAccumulator) \ +TFJ(ArrayReduceRightLoopLazyDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kInitialK, kLength, kResult) \ +TFC(ArrayReduceRightLoopContinuation, ArrayReduceRightLoopContinuation) \ +TFJ(ArrayReduceRight, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayReducePreLoopEagerDeoptContinuation, JSParameterCount(2), kReceiver, kCallback, kLength) \ +TFJ(ArrayReduceLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kInitialK, kLength, kAccumulator) \ +TFJ(ArrayReduceLoopLazyDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kInitialK, kLength, kResult) \ +TFC(ArrayReduceLoopContinuation, ArrayReduceLoopContinuation) \ +TFJ(ArrayReduce, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeReverse, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeShift, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeSlice, kDontAdaptArgumentsSentinel) \ +TFJ(ArraySomeLoopEagerDeoptContinuation, JSParameterCount(4), kReceiver, kCallback, kThisArg, kInitialK, kLength) \ +TFJ(ArraySomeLoopLazyDeoptContinuation, JSParameterCount(5), kReceiver, kCallback, kThisArg, kInitialK, kLength, kResult) \ +TFC(ArraySomeLoopContinuation, ArraySomeLoopContinuation) \ +TFJ(ArraySome, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeSplice, kDontAdaptArgumentsSentinel) \ +TFC(GenericArrayToReversed, GenericArrayToReversed) \ +TFJ(ArrayPrototypeToReversed, kDontAdaptArgumentsSentinel) \ +TFC(ArrayPowerSortIntoCopy, ArrayPowerSortIntoCopy) \ +TFJ(ArrayPrototypeToSorted, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeToSpliced, kDontAdaptArgumentsSentinel) \ +TFJ(ArrayPrototypeUnshift, kDontAdaptArgumentsSentinel) \ +TFC(GenericArrayWith, GenericArrayWith) \ +TFJ(ArrayPrototypeWith, JSParameterCount(2), kReceiver, kIndex, kValue) \ +TFJ(ArraySortContinueFromSnapshotEagerDeoptContinuation, JSParameterCount(3), kReceiver, kComparefn, kTempArray, kOriginalLength) \ +TFJ(ArraySortContinueFromSnapshotLazyDeoptContinuation, JSParameterCount(4), kReceiver, kComparefn, kTempArray, kOriginalLength, kResult) \ +TFJ(ArrayBufferPrototypeGetByteLength, JSParameterCount(0), kReceiver) \ +TFJ(ArrayBufferPrototypeGetMaxByteLength, JSParameterCount(0), kReceiver) \ +TFJ(ArrayBufferPrototypeGetResizable, JSParameterCount(0), kReceiver) \ +TFJ(ArrayBufferPrototypeGetDetached, JSParameterCount(0), kReceiver) \ +TFJ(ArrayBufferPrototypeGetImmutable, JSParameterCount(0), kReceiver) \ +TFJ(SharedArrayBufferPrototypeGetMaxByteLength, JSParameterCount(0), kReceiver) \ +TFJ(SharedArrayBufferPrototypeGetGrowable, JSParameterCount(0), kReceiver) \ +TFJ(ArrayBufferIsView, JSParameterCount(1), kReceiver, kArg) \ +TFC(ToInteger, ToInteger) \ +TFC(FastCreateDataProperty, FastCreateDataProperty) \ +TFJ(BooleanConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(BooleanPrototypeToString, JSParameterCount(0), kReceiver) \ +TFJ(BooleanPrototypeValueOf, JSParameterCount(0), kReceiver) \ +TFC(BigIntAddNoThrow, BigIntAddNoThrow) \ +TFC(BigIntAdd, BigIntAdd) \ +TFC(BigIntSubtractNoThrow, BigIntSubtractNoThrow) \ +TFC(BigIntSubtract, BigIntSubtract) \ +TFC(BigIntMultiplyNoThrow, BigIntMultiplyNoThrow) \ +TFC(BigIntMultiply, BigIntMultiply) \ +TFC(BigIntDivideNoThrow, BigIntDivideNoThrow) \ +TFC(BigIntDivide, BigIntDivide) \ +TFC(BigIntModulusNoThrow, BigIntModulusNoThrow) \ +TFC(BigIntModulus, BigIntModulus) \ +TFC(BigIntBitwiseAndNoThrow, BigIntBitwiseAndNoThrow) \ +TFC(BigIntBitwiseAnd, BigIntBitwiseAnd) \ +TFC(BigIntBitwiseOrNoThrow, BigIntBitwiseOrNoThrow) \ +TFC(BigIntBitwiseOr, BigIntBitwiseOr) \ +TFC(BigIntBitwiseXorNoThrow, BigIntBitwiseXorNoThrow) \ +TFC(BigIntBitwiseXor, BigIntBitwiseXor) \ +TFC(BigIntShiftLeftNoThrow, BigIntShiftLeftNoThrow) \ +TFC(BigIntShiftLeft, BigIntShiftLeft) \ +TFC(BigIntShiftRightNoThrow, BigIntShiftRightNoThrow) \ +TFC(BigIntShiftRight, BigIntShiftRight) \ +TFC(BigIntEqual, BigIntEqual) \ +TFC(BigIntLessThan, BigIntLessThan) \ +TFC(BigIntGreaterThan, BigIntGreaterThan) \ +TFC(BigIntLessThanOrEqual, BigIntLessThanOrEqual) \ +TFC(BigIntGreaterThanOrEqual, BigIntGreaterThanOrEqual) \ +TFC(BigIntUnaryMinus, BigIntUnaryMinus) \ +TFC(ToString, ToString) \ +TFC(ToStringConvertSymbol, ToStringConvertSymbol) \ +TFJ(StringPrototypeToString, JSParameterCount(0), kReceiver) \ +TFJ(StringPrototypeValueOf, JSParameterCount(0), kReceiver) \ +TFC(StringToList, StringToList) \ +TFJ(StringPrototypeCharAt, JSParameterCount(1), kReceiver, kPosition) \ +TFJ(StringPrototypeCharCodeAt, JSParameterCount(1), kReceiver, kPosition) \ +TFJ(StringPrototypeCodePointAt, JSParameterCount(1), kReceiver, kPosition) \ +TFJ(StringPrototypeConcat, kDontAdaptArgumentsSentinel) \ +TFJ(StringConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(StringCreateLazyDeoptContinuation, JSParameterCount(1), kReceiver, kValue) \ +TFC(StringAddConvertLeft, StringAddConvertLeft) \ +TFC(StringAddConvertRight, StringAddConvertRight) \ +TFC(StringCharAt, StringCharAt) \ +TFC(FastNewClosureBaseline, FastNewClosureBaseline) \ +TFC(FastNewFunctionContextEval, FastNewFunctionContextEval) \ +TFC(FastNewFunctionContextFunction, FastNewFunctionContextFunction) \ +TFC(FastNewFunctionContextFunctionWithCells, FastNewFunctionContextFunctionWithCells) \ +TFC(CreateRegExpLiteral, CreateRegExpLiteral) \ +TFC(CreateShallowArrayLiteral, CreateShallowArrayLiteral) \ +TFC(CreateEmptyArrayLiteral, CreateEmptyArrayLiteral) \ +TFC(CreateShallowObjectLiteral, CreateShallowObjectLiteral) \ +TFJ(ObjectConstructor, kDontAdaptArgumentsSentinel) \ +TFC(CreateEmptyLiteralObject, CreateEmptyLiteralObject) \ +TFJ(NumberConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(GenericLazyDeoptContinuation, JSParameterCount(1), kReceiver, kResult) \ +TFC(StringToNumber, StringToNumber) \ +TFC(NonNumberToNumber, NonNumberToNumber) \ +TFC(NonNumberToNumeric, NonNumberToNumeric) \ +TFC(ToNumeric, ToNumeric) \ +TFC(NumberToString, NumberToString) \ +TFC(SmiToString, SmiToString) \ +TFC(Int32ToString, Int32ToString) \ +TFC(Float64ToString, Float64ToString) \ +TFC(ToBoolean, ToBoolean) \ +TFC(ToBooleanForBaselineJump, ToBooleanForBaselineJump) \ +TFC(ToLength, ToLength) \ +TFC(ToName, ToName) \ +TFC(ToObject, ToObject) \ +TFC(NonPrimitiveToPrimitive_Default, NonPrimitiveToPrimitive_Default) \ +TFC(NonPrimitiveToPrimitive_Number, NonPrimitiveToPrimitive_Number) \ +TFC(NonPrimitiveToPrimitive_String, NonPrimitiveToPrimitive_String) \ +TFC(OrdinaryToPrimitive_Number, OrdinaryToPrimitive_Number) \ +TFC(OrdinaryToPrimitive_Number_Inline, OrdinaryToPrimitive_Number_Inline) \ +TFC(OrdinaryToPrimitive_String, OrdinaryToPrimitive_String) \ +TFJ(FastConsoleAssert, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetBuffer, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetByteLength, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetByteOffset, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetUint8, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetInt8, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetUint16, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetInt16, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetUint32, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetInt32, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetFloat16, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetFloat32, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetFloat64, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetBigUint64, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeGetBigInt64, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetUint8, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetInt8, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetUint16, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetInt16, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetUint32, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetInt32, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetFloat16, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetFloat32, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetFloat64, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetBigUint64, kDontAdaptArgumentsSentinel) \ +TFJ(DataViewPrototypeSetBigInt64, kDontAdaptArgumentsSentinel) \ +TFJ(FinalizationRegistryConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(FinalizationRegistryRegister, kDontAdaptArgumentsSentinel) \ +TFJ(FunctionPrototypeHasInstance, JSParameterCount(1), kReceiver, kValue) \ +TFJ(FastFunctionPrototypeBind, kDontAdaptArgumentsSentinel) \ +TFJ(GeneratorPrototypeNextLazyDeoptContinuation, JSParameterCount(3), kReceiver, kGenerator, kException, kResult) \ +TFC(IncBlockCounter, IncBlockCounter) \ +TFC(GetTemplateObject, GetTemplateObject) \ +TFC(ForInNext, ForInNext) \ +TFC(GetImportMetaObjectBaseline, GetImportMetaObjectBaseline) \ +TFC(GetIteratorWithFeedback, GetIteratorWithFeedback) \ +TFC(GetIteratorBaseline, GetIteratorBaseline) \ +TFC(CreateAsyncFromSyncIteratorBaseline, CreateAsyncFromSyncIteratorBaseline) \ +TFC(ForOfNext, ForOfNext) \ +TFC(ForOfNextBaseline, ForOfNextBaseline) \ +TFC(CallIteratorWithFeedback, CallIteratorWithFeedback) \ +TFC(IteratorClose, IteratorClose) \ +TFJ(IteratorConstructor, JSParameterCount(0), kReceiver) \ +TFJ(IteratorPrototypeGetToStringTag, JSParameterCount(0), kReceiver) \ +TFJ(IteratorPrototypeSetToStringTag, JSParameterCount(1), kReceiver, kValue) \ +TFJ(IteratorPrototypeGetConstructor, JSParameterCount(0), kReceiver) \ +TFJ(IteratorPrototypeSetConstructor, JSParameterCount(1), kReceiver, kValue) \ +TFJ(IteratorPrototypeDispose, JSParameterCount(0), kReceiver) \ +TFJ(AsyncIteratorPrototypeAsyncDisposeResolveClosure, JSParameterCount(0), kReceiver) \ +TFJ(AsyncIteratorPrototypeAsyncDispose, JSParameterCount(0), kReceiver) \ +TFC(ArrayDestructure, ArrayDestructure) \ +TFC(ArrayDestructureLazyDeoptContinuation, ArrayDestructureLazyDeoptContinuation) \ +TFJ(IteratorFrom, JSParameterCount(1), kReceiver, kObjArg) \ +TFJ(WrapForValidIteratorPrototypeNext, JSParameterCount(0), kReceiver) \ +TFJ(WrapForValidIteratorPrototypeReturn, JSParameterCount(0), kReceiver) \ +TFJ(IteratorHelperPrototypeNext, JSParameterCount(0), kReceiver) \ +TFJ(IteratorHelperPrototypeReturn, JSParameterCount(0), kReceiver) \ +TFJ(IteratorPrototypeMap, JSParameterCount(1), kReceiver, kMapper) \ +TFC(IteratorMapHelperNext, IteratorMapHelperNext) \ +TFJ(IteratorPrototypeFilter, JSParameterCount(1), kReceiver, kPredicate) \ +TFC(IteratorFilterHelperNext, IteratorFilterHelperNext) \ +TFJ(IteratorPrototypeTake, JSParameterCount(1), kReceiver, kLimit) \ +TFC(IteratorTakeHelperNext, IteratorTakeHelperNext) \ +TFJ(IteratorPrototypeDrop, JSParameterCount(1), kReceiver, kLimit) \ +TFC(IteratorDropHelperNext, IteratorDropHelperNext) \ +TFJ(IteratorPrototypeFlatMap, JSParameterCount(1), kReceiver, kMapper) \ +TFC(IteratorFlatMapHelperNext, IteratorFlatMapHelperNext) \ +TFJ(IteratorPrototypeReduce, kDontAdaptArgumentsSentinel) \ +TFJ(IteratorPrototypeToArray, JSParameterCount(0), kReceiver) \ +TFJ(IteratorPrototypeForEach, JSParameterCount(1), kReceiver, kFn) \ +TFJ(IteratorPrototypeSome, JSParameterCount(1), kReceiver, kPredicate) \ +TFJ(IteratorPrototypeEvery, JSParameterCount(1), kReceiver, kPredicate) \ +TFJ(IteratorPrototypeFind, JSParameterCount(1), kReceiver, kPredicate) \ +TFJ(IteratorConcat, kDontAdaptArgumentsSentinel) \ +TFC(IteratorConcatHelperNext, IteratorConcatHelperNext) \ +TFJ(IteratorPrototypeJoin, JSParameterCount(1), kReceiver, kSeparator) \ +TFJ(IteratorZip, kDontAdaptArgumentsSentinel) \ +TFC(IteratorZipHelperNext, IteratorZipHelperNext) \ +TFJ(IteratorZipKeyed, kDontAdaptArgumentsSentinel) \ +TFC(IteratorZipKeyedHelperNext, IteratorZipKeyedHelperNext) \ +TFJ(IteratorPrototypeIncludes, kDontAdaptArgumentsSentinel) \ +TFJ(MapGroupBy, JSParameterCount(2), kReceiver, kItems, kCallback) \ +TFJ(MathAbs, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathCeil, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathFloor, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathRound, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathTrunc, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathPow, JSParameterCount(2), kReceiver, kBase, kExponent) \ +TFJ(MathMax, kDontAdaptArgumentsSentinel) \ +TFJ(MathMin, kDontAdaptArgumentsSentinel) \ +TFJ(MathAcos, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathAcosh, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathAsin, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathAsinh, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathAtan, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathAtan2, JSParameterCount(2), kReceiver, kY, kX) \ +TFJ(MathAtanh, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathCbrt, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathClz32, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathCos, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathCosh, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathExp, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathExpm1, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathFround, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathF16round, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathImul, JSParameterCount(2), kReceiver, kX, kY) \ +TFJ(MathLog, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathLog1p, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathLog10, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathLog2, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathSin, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathSign, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathSinh, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathSqrt, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathTan, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathTanh, JSParameterCount(1), kReceiver, kX) \ +TFJ(MathHypot, kDontAdaptArgumentsSentinel) \ +TFJ(MathRandom, JSParameterCount(0), kReceiver) \ +TFJ(NumberPrototypeToString, kDontAdaptArgumentsSentinel) \ +TFJ(NumberIsFinite, JSParameterCount(1), kReceiver, kValue) \ +TFJ(NumberIsInteger, JSParameterCount(1), kReceiver, kValue) \ +TFJ(NumberIsNaN, JSParameterCount(1), kReceiver, kValue) \ +TFJ(NumberIsSafeInteger, JSParameterCount(1), kReceiver, kValue) \ +TFJ(NumberPrototypeValueOf, JSParameterCount(0), kReceiver) \ +TFJ(NumberParseFloat, JSParameterCount(1), kReceiver, kValue) \ +TFC(ParseInt, ParseInt) \ +TFJ(NumberParseInt, JSParameterCount(2), kReceiver, kValue, kRadix) \ +TFC(Add, Add) \ +TFC(Subtract, Subtract) \ +TFC(Multiply, Multiply) \ +TFC(Divide, Divide) \ +TFC(Modulus, Modulus) \ +TFC(Exponentiate, Exponentiate) \ +TFC(Negate, Negate) \ +TFC(BitwiseNot, BitwiseNot) \ +TFC(Decrement, Decrement) \ +TFC(Increment, Increment) \ +TFC(ShiftLeft, ShiftLeft) \ +TFC(ShiftRight, ShiftRight) \ +TFC(ShiftRightLogical, ShiftRightLogical) \ +TFC(BitwiseAnd, BitwiseAnd) \ +TFC(BitwiseOr, BitwiseOr) \ +TFC(BitwiseXor, BitwiseXor) \ +TFC(LessThan, LessThan) \ +TFC(LessThanOrEqual, LessThanOrEqual) \ +TFC(GreaterThan, GreaterThan) \ +TFC(GreaterThanOrEqual, GreaterThanOrEqual) \ +TFC(Equal, Equal) \ +TFC(StrictEqual, StrictEqual) \ +TFJ(ObjectFromEntries, kDontAdaptArgumentsSentinel) \ +TFC(GroupByGeneric, GroupByGeneric) \ +TFJ(ObjectGroupBy, JSParameterCount(2), kReceiver, kItems, kCallback) \ +TFC(CreateObjectWithoutProperties, CreateObjectWithoutProperties) \ +TFJ(ObjectIsExtensible, JSParameterCount(1), kReceiver, kObject) \ +TFJ(ObjectPreventExtensions, JSParameterCount(1), kReceiver, kObject) \ +TFJ(ObjectGetPrototypeOf, JSParameterCount(1), kReceiver, kObject) \ +TFJ(ObjectSetPrototypeOf, JSParameterCount(2), kReceiver, kObject, kProto) \ +TFJ(ObjectPrototypeToString, JSParameterCount(0), kReceiver) \ +TFJ(ObjectPrototypeValueOf, JSParameterCount(0), kReceiver) \ +TFJ(ObjectPrototypeToLocaleString, JSParameterCount(0), kReceiver) \ +TFC(FulfillPromise, FulfillPromise) \ +TFC(RejectPromise, RejectPromise) \ +TFC(NewPromiseCapability, NewPromiseCapability) \ +TFJ(PromiseCapabilityDefaultReject, JSParameterCount(1), kReceiver, kReason) \ +TFJ(PromiseCapabilityDefaultResolve, JSParameterCount(1), kReceiver, kResolution) \ +TFJ(PerformPromiseThenFunction, JSParameterCount(3), kReceiver, kOnFulfilled, kOnRejected, kResultCapability) \ +TFC(PerformPromiseThen, PerformPromiseThen) \ +TFJ(PromiseReject, JSParameterCount(1), kReceiver, kReason) \ +TFJ(PromiseGetCapabilitiesExecutor, JSParameterCount(2), kReceiver, kResolve, kReject) \ +TFJ(PromiseConstructorLazyDeoptContinuation, JSParameterCount(4), kReceiver, kPromise, kReject, kException, kResult) \ +TFJ(PromiseAll, JSParameterCount(1), kReceiver, kIterable) \ +TFJ(PromiseAllSettled, JSParameterCount(1), kReceiver, kIterable) \ +TFJ(PromiseAllResolveElementClosure, JSParameterCount(1), kReceiver, kValue) \ +TFJ(PromiseAllSettledResolveElementClosure, JSParameterCount(1), kReceiver, kValue) \ +TFJ(PromiseAllSettledRejectElementClosure, JSParameterCount(1), kReceiver, kValue) \ +TFJ(PromiseAnyRejectElementClosure, JSParameterCount(1), kReceiver, kValue) \ +TFJ(PromiseAny, JSParameterCount(1), kReceiver, kIterable) \ +TFJ(PromiseConstructor, JSParameterCount(1), kReceiver, kExecutor) \ +TFJ(PromisePrototypeCatch, JSParameterCount(1), kReceiver, kOnRejected) \ +TFJ(PromiseValueThunkFinally, JSParameterCount(0), kReceiver) \ +TFJ(PromiseThrowerFinally, JSParameterCount(0), kReceiver) \ +TFJ(PromiseCatchFinally, JSParameterCount(1), kReceiver, kReason) \ +TFJ(PromiseThenFinally, JSParameterCount(1), kReceiver, kValue) \ +TFJ(PromisePrototypeFinally, JSParameterCount(1), kReceiver, kOnFinally) \ +TFC(PromiseResolveThenableJob, PromiseResolveThenableJob) \ +TFJ(GetContinuationPreservedEmbedderData, JSParameterCount(0), kReceiver) \ +TFJ(SetContinuationPreservedEmbedderData, JSParameterCount(1), kReceiver, kData) \ +TFC(AsyncAwaitNonThenableFastPath, AsyncAwaitNonThenableFastPath) \ +TFJ(PromiseRace, JSParameterCount(1), kReceiver, kIterable) \ +TFC(PromiseFulfillReactionJob, PromiseFulfillReactionJob) \ +TFC(PromiseRejectReactionJob, PromiseRejectReactionJob) \ +TFJ(PromiseResolveTrampoline, JSParameterCount(1), kReceiver, kValue) \ +TFC(PromiseResolve, PromiseResolve) \ +TFC(ResolvePromise, ResolvePromise) \ +TFJ(PromisePrototypeThen, JSParameterCount(2), kReceiver, kOnFulfilled, kOnRejected) \ +TFJ(PromiseTry, kDontAdaptArgumentsSentinel) \ +TFJ(PromiseWithResolvers, JSParameterCount(0), kReceiver) \ +TFJ(ProxyConstructor, JSParameterCount(2), kReceiver, kTarget, kHandler) \ +TFC(ProxyDeleteProperty, ProxyDeleteProperty) \ +TFC(ProxyGetProperty, ProxyGetProperty) \ +TFC(ProxyGetPrototypeOf, ProxyGetPrototypeOf) \ +TFC(ProxyHasProperty, ProxyHasProperty) \ +TFC(ProxyIsExtensible, ProxyIsExtensible) \ +TFC(ProxyPreventExtensions, ProxyPreventExtensions) \ +TFJ(ProxyRevocable, JSParameterCount(2), kReceiver, kTarget, kHandler) \ +TFJ(ProxyRevoke, JSParameterCount(0), kReceiver) \ +TFC(ProxySetProperty, ProxySetProperty) \ +TFC(ProxySetPrototypeOf, ProxySetPrototypeOf) \ +TFJ(ReflectIsExtensible, JSParameterCount(1), kReceiver, kObject) \ +TFJ(ReflectPreventExtensions, JSParameterCount(1), kReceiver, kObject) \ +TFJ(ReflectGetPrototypeOf, JSParameterCount(1), kReceiver, kObject) \ +TFJ(ReflectSetPrototypeOf, JSParameterCount(2), kReceiver, kObject, kProto) \ +TFJ(ReflectGet, kDontAdaptArgumentsSentinel) \ +TFJ(ReflectDeleteProperty, JSParameterCount(2), kReceiver, kObject, kKey) \ +TFJ(ReflectHas, JSParameterCount(2), kReceiver, kObject, kKey) \ +TFJ(ReflectGetOwnPropertyDescriptor, JSParameterCount(2), kReceiver, kTarget, kPropertyKey) \ +TFC(RegExpPrototypeExecSlow, RegExpPrototypeExecSlow) \ +TFJ(RegExpPrototypeExec, JSParameterCount(1), kReceiver, kString) \ +TFJ(RegExpPrototypeMatchAll, JSParameterCount(1), kReceiver, kString) \ +TFJ(RegExpStringIteratorPrototypeNext, JSParameterCount(0), kReceiver) \ +TFC(RegExpMatchFast, RegExpMatchFast) \ +TFJ(RegExpPrototypeMatch, JSParameterCount(1), kReceiver, kString) \ +TFC(RegExpReplace, RegExpReplace) \ +TFJ(RegExpPrototypeReplace, kDontAdaptArgumentsSentinel) \ +TFC(RegExpSearchFast, RegExpSearchFast) \ +TFJ(RegExpPrototypeSearch, JSParameterCount(1), kReceiver, kString) \ +TFJ(RegExpPrototypeSourceGetter, JSParameterCount(0), kReceiver) \ +TFC(RegExpSplit, RegExpSplit) \ +TFJ(RegExpPrototypeSplit, kDontAdaptArgumentsSentinel) \ +TFJ(RegExpPrototypeTest, JSParameterCount(1), kReceiver, kString) \ +TFC(RegExpPrototypeTestFast, RegExpPrototypeTestFast) \ +TFJ(RegExpPrototypeGlobalGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeIgnoreCaseGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeMultilineGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeHasIndicesGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeLinearGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeDotAllGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeStickyGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeUnicodeGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeUnicodeSetsGetter, JSParameterCount(0), kReceiver) \ +TFJ(RegExpPrototypeFlagsGetter, JSParameterCount(0), kReceiver) \ +TFJ(SetPrototypeDifference, JSParameterCount(1), kReceiver, kOther) \ +TFJ(SetPrototypeIntersection, JSParameterCount(1), kReceiver, kOther) \ +TFJ(SetPrototypeIsDisjointFrom, JSParameterCount(1), kReceiver, kOther) \ +TFJ(SetPrototypeIsSubsetOf, JSParameterCount(1), kReceiver, kOther) \ +TFJ(SetPrototypeIsSupersetOf, JSParameterCount(1), kReceiver, kOther) \ +TFJ(SetPrototypeSymmetricDifference, JSParameterCount(1), kReceiver, kOther) \ +TFJ(SetPrototypeUnion, JSParameterCount(1), kReceiver, kOther) \ +TFJ(StringPrototypeAt, JSParameterCount(1), kReceiver, kIndex) \ +TFJ(StringPrototypeEndsWith, kDontAdaptArgumentsSentinel) \ +TFC(CreateHTML, CreateHTML) \ +TFJ(StringPrototypeAnchor, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeBig, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeBlink, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeBold, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeFontcolor, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeFontsize, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeFixed, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeItalics, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeLink, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeSmall, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeStrike, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeSub, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeSup, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeIncludes, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeIndexOf, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeIsWellFormed, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeIterator, JSParameterCount(0), kReceiver) \ +TFJ(StringIteratorPrototypeNext, JSParameterCount(0), kReceiver) \ +TFJ(StringPrototypeMatch, JSParameterCount(1), kReceiver, kRegexp) \ +TFJ(StringPrototypeSearch, JSParameterCount(1), kReceiver, kRegexp) \ +TFJ(StringPrototypePadStart, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypePadEnd, kDontAdaptArgumentsSentinel) \ +TFC(StringRepeat, StringRepeat) \ +TFJ(StringPrototypeRepeat, JSParameterCount(1), kReceiver, kCount) \ +TFJ(StringPrototypeReplaceAll, JSParameterCount(2), kReceiver, kSearchValue, kReplaceValue) \ +TFJ(StringPrototypeSlice, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeStartsWith, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeSubstr, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeSubstring, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeToWellFormed, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeTrim, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeTrimStart, kDontAdaptArgumentsSentinel) \ +TFJ(StringPrototypeTrimEnd, kDontAdaptArgumentsSentinel) \ +TFJ(SuppressedErrorConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(SymbolPrototypeDescriptionGetter, JSParameterCount(0), kReceiver) \ +TFJ(SymbolPrototypeToPrimitive, JSParameterCount(1), kReceiver, kHint) \ +TFJ(SymbolPrototypeToString, JSParameterCount(0), kReceiver) \ +TFJ(SymbolPrototypeValueOf, JSParameterCount(0), kReceiver) \ +TFJ(TypedArrayPrototypeAt, JSParameterCount(1), kReceiver, kIndex) \ +TFC(CreateTypedArray, CreateTypedArray) \ +TFJ(TypedArrayPrototypeEvery, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeEntries, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeFilter, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeFind, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeFindIndex, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeFindLast, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeFindLastIndex, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeForEach, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayFrom, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeKeys, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayOf, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeReduce, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeReduceRight, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeSet, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeSlice, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeSome, kDontAdaptArgumentsSentinel) \ +TFC(TypedArrayMergeSort, TypedArrayMergeSort) \ +TFJ(TypedArrayPrototypeSort, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeSubArray, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeToReversed, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeToSorted, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeValues, kDontAdaptArgumentsSentinel) \ +TFJ(TypedArrayPrototypeWith, JSParameterCount(2), kReceiver, kIndex, kValueArg) \ +TFJ(WeakRefConstructor, kDontAdaptArgumentsSentinel) \ +TFJ(WeakRefDeref, JSParameterCount(0), kReceiver) \ +TFC(NewSloppyArgumentsElements, NewSloppyArgumentsElements) \ +TFC(NewStrictArgumentsElements, NewStrictArgumentsElements) \ +TFC(NewRestArgumentsElements, NewRestArgumentsElements) \ +TFC(FastNewSloppyArguments, FastNewSloppyArguments) \ +TFC(FastNewStrictArguments, FastNewStrictArguments) \ +TFC(FastNewRestArguments, FastNewRestArguments) \ +TFC(LoadFromContextCell, LoadFromContextCell) \ +TFC(StoreCurrentContextElementBaseline, StoreCurrentContextElementBaseline) \ +TFC(StoreContextElementBaseline, StoreContextElementBaseline) \ +TFC(DetachContextCell, DetachContextCell) \ +TFC(StringSlowFlatten, StringSlowFlatten) \ +TFC(StringIndexOf, StringIndexOf) \ +TFC(TestTurbofanType, TestTurbofanType) \ +TFC(CheckTurbofanType, CheckTurbofanType) \ +TFC(CheckTurboshaftWord32Type, CheckTurboshaftWord32Type) \ +TFC(CheckTurboshaftWord64Type, CheckTurboshaftWord64Type) \ +TFC(CheckTurboshaftFloat32Type, CheckTurboshaftFloat32Type) \ +TFC(CheckTurboshaftFloat64Type, CheckTurboshaftFloat64Type) \ +TFC(DebugPrintWord32, DebugPrintWord32) \ +TFC(DebugPrintWord64, DebugPrintWord64) \ +TFC(DebugPrintFloat32, DebugPrintFloat32) \ +TFC(DebugPrintFloat64, DebugPrintFloat64) \ +TFC(DebugPrintObject, DebugPrintObject) \ +TFC(GenericBuiltinTest_JSAny_0, GenericBuiltinTest_JSAny_0) \ +TFC(TestHelperPlus1, TestHelperPlus1) \ +TFC(TestHelperPlus2, TestHelperPlus2) \ +TFC(ReturnTwoValues, ReturnTwoValues) \ +TFC(ThrowAsBuiltin, ThrowAsBuiltin) \ +TFC(TestCallNever, TestCallNever) \ +TFC(TestIncrementArraySpeciesModified, TestIncrementArraySpeciesModified) \ +TFC(Load_FastSmiElements_0, Load_FastSmiElements_0) \ +TFC(Load_FastObjectElements_0, Load_FastObjectElements_0) \ +TFC(Load_FastDoubleElements_0, Load_FastDoubleElements_0) \ +TFC(Store_FastSmiElements_0, Store_FastSmiElements_0) \ +TFC(Store_FastObjectElements_0, Store_FastObjectElements_0) \ +TFC(Store_FastDoubleElements_0, Store_FastDoubleElements_0) \ +TFC(Delete_FastSmiElements_0, Delete_FastSmiElements_0) \ +TFC(Delete_FastObjectElements_0, Delete_FastObjectElements_0) \ +TFC(Delete_FastDoubleElements_0, Delete_FastDoubleElements_0) \ +TFC(SortCompareDefault, SortCompareDefault) \ +TFC(SortCompareUserFn, SortCompareUserFn) \ +TFC(CanUseSameAccessor_GenericElementsAccessor_0, CanUseSameAccessor_GenericElementsAccessor_0) \ +TFC(Copy, Copy) \ +TFC(MergeAt, MergeAt) \ +TFC(GallopLeft, GallopLeft) \ +TFC(GallopRight, GallopRight) \ +TFC(ArrayPowerSort, ArrayPowerSort) \ +TFJ(ArrayPrototypeSort, kDontAdaptArgumentsSentinel) \ +TFC(StringFastLocaleCompare, StringFastLocaleCompare) \ +TFJ(JSToWasmWrapper, kDontAdaptArgumentsSentinel) \ +TFJ(WasmPromising, kDontAdaptArgumentsSentinel) \ +TFJ(WasmStressSwitch, kDontAdaptArgumentsSentinel) \ +TFC(JSToWasmHandleReturns, JSToWasmHandleReturns) \ +TFC(WasmInt32ToHeapNumber, WasmInt32ToHeapNumber) \ +TFC(WasmInt32ToSharedHeapNumber, WasmInt32ToSharedHeapNumber) \ +TFC(WasmFuncRefToJS, WasmFuncRefToJS) \ +TFC(WasmTaggedNonSmiToInt32, WasmTaggedNonSmiToInt32) \ +TFC(WasmTaggedToFloat64, WasmTaggedToFloat64) \ +TFC(WasmTaggedToFloat32, WasmTaggedToFloat32) \ +TFC(WasmMemoryGrow, WasmMemoryGrow) \ +TFC(WasmTableInit, WasmTableInit) \ +TFC(WasmTableCopy, WasmTableCopy) \ +TFC(WasmTableFill, WasmTableFill) \ +TFC(WasmTableGrow, WasmTableGrow) \ +TFC(WasmTableGet, WasmTableGet) \ +TFC(WasmTableSet, WasmTableSet) \ +TFC(WasmTableGetFuncRef, WasmTableGetFuncRef) \ +TFC(WasmFunctionTableGet, WasmFunctionTableGet) \ +TFC(WasmTableSetFuncRef, WasmTableSetFuncRef) \ +TFC(WasmRefFunc, WasmRefFunc) \ +TFC(WasmInternalFunctionCreateExternal, WasmInternalFunctionCreateExternal) \ +TFC(WasmAllocateZeroedFixedArray, WasmAllocateZeroedFixedArray) \ +TFC(WasmAllocateFixedArray, WasmAllocateFixedArray) \ +TFC(WasmLiftoffDeoptFinish, WasmLiftoffDeoptFinish) \ +TFC(WasmThrow, WasmThrow) \ +TFC(WasmRethrow, WasmRethrow) \ +TFC(WasmThrowRef, WasmThrowRef) \ +TFC(WasmRethrowExplicitContext, WasmRethrowExplicitContext) \ +TFC(WasmTriggerTierUp, WasmTriggerTierUp) \ +TFC(WasmGrowableStackGuard, WasmGrowableStackGuard) \ +TFC(WasmStackGuard, WasmStackGuard) \ +TFC(WasmStackGuardLoop, WasmStackGuardLoop) \ +TFC(WasmStackOverflow, WasmStackOverflow) \ +TFC(WasmTraceGlobal, WasmTraceGlobal) \ +TFC(WasmTraceMemory, WasmTraceMemory) \ +TFC(WasmTraceEnter, WasmTraceEnter) \ +TFC(WasmTraceExit, WasmTraceExit) \ +TFC(WasmConfigureAllPrototypesOpt, WasmConfigureAllPrototypesOpt) \ +TFC(WasmAllocateJSArray, WasmAllocateJSArray) \ +TFC(WasmAllocateStructWithRtt, WasmAllocateStructWithRtt) \ +TFC(WasmAllocateDescriptorStruct, WasmAllocateDescriptorStruct) \ +TFC(WasmAllocateSharedStructWithRtt, WasmAllocateSharedStructWithRtt) \ +TFC(WasmAllocateArray_Uninitialized, WasmAllocateArray_Uninitialized) \ +TFC(WasmAllocateSharedArray_Uninitialized, WasmAllocateSharedArray_Uninitialized) \ +TFC(WasmArrayNewSegment, WasmArrayNewSegment) \ +TFC(WasmArrayInitSegment, WasmArrayInitSegment) \ +TFC(WasmArrayCopy, WasmArrayCopy) \ +TFC(WasmUint32ToNumber, WasmUint32ToNumber) \ +TFC(UintPtr53ToNumber, UintPtr53ToNumber) \ +TFC(WasmI32AtomicWait, WasmI32AtomicWait) \ +TFC(WasmI64AtomicWait, WasmI64AtomicWait) \ +TFC(WasmManagedObjectWait32, WasmManagedObjectWait32) \ +TFC(WasmManagedObjectWait64, WasmManagedObjectWait64) \ +TFC(WasmManagedObjectWaitRef, WasmManagedObjectWaitRef) \ +TFC(WasmWaitqueueNew, WasmWaitqueueNew) \ +TFC(CallRefIC, CallRefIC) \ +TFC(CallIndirectIC, CallIndirectIC) \ +TFC(WasmTrap, WasmTrap) \ +TFC(ThrowWasmTrapUnreachable, ThrowWasmTrapUnreachable) \ +TFC(WasmPropagateException, WasmPropagateException) \ +TFC(ThrowWasmTrapMemOutOfBounds, ThrowWasmTrapMemOutOfBounds) \ +TFC(ThrowWasmTrapUnalignedAccess, ThrowWasmTrapUnalignedAccess) \ +TFC(ThrowWasmTrapDivByZero, ThrowWasmTrapDivByZero) \ +TFC(ThrowWasmTrapDivUnrepresentable, ThrowWasmTrapDivUnrepresentable) \ +TFC(ThrowWasmTrapRemByZero, ThrowWasmTrapRemByZero) \ +TFC(ThrowWasmTrapFloatUnrepresentable, ThrowWasmTrapFloatUnrepresentable) \ +TFC(ThrowWasmTrapFuncSigMismatch, ThrowWasmTrapFuncSigMismatch) \ +TFC(ThrowWasmTrapNullFunc, ThrowWasmTrapNullFunc) \ +TFC(ThrowWasmTrapDataSegmentOutOfBounds, ThrowWasmTrapDataSegmentOutOfBounds) \ +TFC(ThrowWasmTrapElementSegmentOutOfBounds, ThrowWasmTrapElementSegmentOutOfBounds) \ +TFC(ThrowWasmTrapTableOutOfBounds, ThrowWasmTrapTableOutOfBounds) \ +TFC(ThrowWasmTrapRethrowNull, ThrowWasmTrapRethrowNull) \ +TFC(ThrowWasmTrapNullDereference, ThrowWasmTrapNullDereference) \ +TFC(ThrowWasmTrapIllegalCast, ThrowWasmTrapIllegalCast) \ +TFC(ThrowWasmTrapArrayOutOfBounds, ThrowWasmTrapArrayOutOfBounds) \ +TFC(ThrowWasmTrapArrayTooLarge, ThrowWasmTrapArrayTooLarge) \ +TFC(ThrowWasmTrapStringOffsetOutOfBounds, ThrowWasmTrapStringOffsetOutOfBounds) \ +TFC(WasmTypeAssertionFailed, WasmTypeAssertionFailed) \ +TFC(ThrowWasmTrapResume, ThrowWasmTrapResume) \ +TFC(ThrowWasmTrapSuspend, ThrowWasmTrapSuspend) \ +TFC(ThrowWasmTrapSwitch, ThrowWasmTrapSwitch) \ +TFC(WasmStringNewWtf8, WasmStringNewWtf8) \ +TFC(WasmStringNewWtf8Array, WasmStringNewWtf8Array) \ +TFC(WasmStringNewWtf16, WasmStringNewWtf16) \ +TFC(WasmStringNewWtf16Array, WasmStringNewWtf16Array) \ +TFC(WasmStringFromDataSegment, WasmStringFromDataSegment) \ +TFC(WasmStringAsWtf16, WasmStringAsWtf16) \ +TFC(WasmStringConst, WasmStringConst) \ +TFC(WasmStringMeasureUtf8, WasmStringMeasureUtf8) \ +TFC(WasmStringMeasureWtf8, WasmStringMeasureWtf8) \ +TFC(WasmStringEncodeWtf8, WasmStringEncodeWtf8) \ +TFC(WasmStringEncodeWtf8Array, WasmStringEncodeWtf8Array) \ +TFC(WasmStringToUtf8Array, WasmStringToUtf8Array) \ +TFC(WasmStringEncodeWtf16, WasmStringEncodeWtf16) \ +TFC(WasmStringEncodeWtf16Array, WasmStringEncodeWtf16Array) \ +TFC(ThrowToLowerCaseCalledOnNull, ThrowToLowerCaseCalledOnNull) \ +TFC(ThrowIndexOfCalledOnNull, ThrowIndexOfCalledOnNull) \ +TFC(ThrowDataViewTypeError, ThrowDataViewTypeError) \ +TFC(ThrowDataViewDetachedError, ThrowDataViewDetachedError) \ +TFC(ThrowDataViewOutOfBounds, ThrowDataViewOutOfBounds) \ +TFC(WasmStringConcat, WasmStringConcat) \ +TFC(WasmStringAdd_NoMapCheck_Shared, WasmStringAdd_NoMapCheck_Shared) \ +TFC(WasmStringEqual, WasmStringEqual) \ +TFC(WasmStringIsUSVSequence, WasmStringIsUSVSequence) \ +TFC(WasmStringAsWtf8, WasmStringAsWtf8) \ +TFC(WasmStringViewWtf8Advance, WasmStringViewWtf8Advance) \ +TFC(WasmStringViewWtf8Encode, WasmStringViewWtf8Encode) \ +TFC(WasmStringViewWtf8Slice, WasmStringViewWtf8Slice) \ +TFC(WasmStringViewWtf16GetCodeUnit, WasmStringViewWtf16GetCodeUnit) \ +TFC(WasmStringViewWtf16Encode, WasmStringViewWtf16Encode) \ +TFC(WasmStringViewWtf16Slice, WasmStringViewWtf16Slice) \ +TFC(WasmStringSliceShared, WasmStringSliceShared) \ +TFC(WasmStringAsIter, WasmStringAsIter) \ +TFC(WasmStringCodePointAt, WasmStringCodePointAt) \ +TFC(WasmStringViewIterNext, WasmStringViewIterNext) \ +TFC(WasmStringViewIterAdvance, WasmStringViewIterAdvance) \ +TFC(WasmStringViewIterRewind, WasmStringViewIterRewind) \ +TFC(WasmStringViewIterSlice, WasmStringViewIterSlice) \ +TFC(WasmIntToString, WasmIntToString) \ +TFC(WasmStringToDouble, WasmStringToDouble) \ +TFC(WasmStringFromCodePoint, WasmStringFromCodePoint) \ +TFC(WasmStringHash, WasmStringHash) \ +TFC(WasmAnyConvertExtern, WasmAnyConvertExtern) \ +TFC(WasmAnyConvertExternShared, WasmAnyConvertExternShared) \ +TFC(WasmExternConvertAny, WasmExternConvertAny) \ +TFC(WasmFastApiCallTypeCheckAndUpdateIC, WasmFastApiCallTypeCheckAndUpdateIC) \ +TFC(WasmStringIndexOf, WasmStringIndexOf) \ +TFC(WasmLiftoffIsEqRefUnshared, WasmLiftoffIsEqRefUnshared) \ +TFC(WasmLiftoffIsArrayRefUnshared, WasmLiftoffIsArrayRefUnshared) \ +TFC(WasmLiftoffIsStructRefUnshared, WasmLiftoffIsStructRefUnshared) \ +TFC(WasmLiftoffCastEqRefUnshared, WasmLiftoffCastEqRefUnshared) \ +TFC(WasmLiftoffCastArrayRefUnshared, WasmLiftoffCastArrayRefUnshared) \ +TFC(WasmLiftoffCastStructRefUnshared, WasmLiftoffCastStructRefUnshared) \ +TFJ(WebAssemblyStringCast, JSParameterCount(1), kReceiver, kArg) \ +TFJ(WebAssemblyStringTest, JSParameterCount(1), kReceiver, kArg) \ +TFJ(WebAssemblyStringFromWtf16Array, JSParameterCount(3), kReceiver, kArrayArg, kStartArg, kEndArg) \ +TFJ(WebAssemblyStringFromWtf16ArrayShared, JSParameterCount(3), kReceiver, kArrayArg, kStartArg, kEndArg) \ +TFJ(WebAssemblyStringFromUtf8Array, JSParameterCount(3), kReceiver, kArrayArg, kStartArg, kEndArg) \ +TFJ(WebAssemblyStringFromUtf8ArrayShared, JSParameterCount(3), kReceiver, kArrayArg, kStartArg, kEndArg) \ +TFJ(WebAssemblyStringIntoUtf8Array, JSParameterCount(3), kReceiver, kStringArg, kArrayArg, kStartArg) \ +TFJ(WebAssemblyStringIntoUtf8ArrayShared, JSParameterCount(3), kReceiver, kStringArg, kArrayArg, kStartArg) \ +TFJ(WebAssemblyStringToUtf8Array, JSParameterCount(1), kReceiver, kStringArg) \ +TFJ(WebAssemblyStringToUtf8ArrayShared, JSParameterCount(1), kReceiver, kStringArg) \ +TFJ(WebAssemblyStringToWtf16Array, JSParameterCount(3), kReceiver, kStringArg, kArrayArg, kStartArg) \ +TFJ(WebAssemblyStringToWtf16ArrayShared, JSParameterCount(3), kReceiver, kStringArg, kArrayArg, kStartArg) \ +TFJ(WebAssemblyStringFromCharCode, JSParameterCount(1), kReceiver, kCodeArg) \ +TFJ(WebAssemblyStringFromCharCodeShared, JSParameterCount(1), kReceiver, kCodeArg) \ +TFJ(WebAssemblyStringFromCodePoint, JSParameterCount(1), kReceiver, kCodeArg) \ +TFJ(WebAssemblyStringFromCodePointShared, JSParameterCount(1), kReceiver, kCodeArg) \ +TFJ(WebAssemblyStringCodePointAt, JSParameterCount(2), kReceiver, kStringArg, kIndexArg) \ +TFJ(WebAssemblyStringCharCodeAt, JSParameterCount(2), kReceiver, kStringArg, kIndexArg) \ +TFJ(WebAssemblyStringLength, JSParameterCount(1), kReceiver, kStringArg) \ +TFJ(WebAssemblyStringMeasureUtf8, JSParameterCount(1), kReceiver, kStringArg) \ +TFJ(WebAssemblyStringConcat, JSParameterCount(2), kReceiver, kFirstArg, kSecondArg) \ +TFJ(WebAssemblyStringSubstring, JSParameterCount(3), kReceiver, kStringArg, kStartArg, kEndArg) \ +TFJ(WebAssemblyStringEquals, JSParameterCount(2), kReceiver, kA, kB) \ +TFJ(WebAssemblyStringCompare, JSParameterCount(2), kReceiver, kFirstArg, kSecondArg) \ +TFJ(WebAssemblyConfigureAllPrototypes, JSParameterCount(4), kReceiver, kPrototypes, kFunctions, kData, kConstructors) \ +TFC(LoadJoinElement_GenericElementsAccessor_0, LoadJoinElement_GenericElementsAccessor_0) \ +TFC(LoadJoinTypedElement_Int32Elements_0, LoadJoinTypedElement_Int32Elements_0) \ +TFC(LoadJoinTypedElement_Float16Elements_0, LoadJoinTypedElement_Float16Elements_0) \ +TFC(LoadJoinTypedElement_Float32Elements_0, LoadJoinTypedElement_Float32Elements_0) \ +TFC(LoadJoinTypedElement_Float64Elements_0, LoadJoinTypedElement_Float64Elements_0) \ +TFC(LoadJoinTypedElement_Uint8ClampedElements_0, LoadJoinTypedElement_Uint8ClampedElements_0) \ +TFC(LoadJoinTypedElement_BigUint64Elements_0, LoadJoinTypedElement_BigUint64Elements_0) \ +TFC(LoadJoinTypedElement_BigInt64Elements_0, LoadJoinTypedElement_BigInt64Elements_0) \ +TFC(LoadJoinTypedElement_Uint8Elements_0, LoadJoinTypedElement_Uint8Elements_0) \ +TFC(LoadJoinTypedElement_Int8Elements_0, LoadJoinTypedElement_Int8Elements_0) \ +TFC(LoadJoinTypedElement_Uint16Elements_0, LoadJoinTypedElement_Uint16Elements_0) \ +TFC(LoadJoinTypedElement_Int16Elements_0, LoadJoinTypedElement_Int16Elements_0) \ +TFC(LoadJoinTypedElement_Uint32Elements_0, LoadJoinTypedElement_Uint32Elements_0) \ +TFC(GenericBuiltinTest_Smi_0, GenericBuiltinTest_Smi_0) \ +TFC(CanUseSameAccessor_FastDoubleElements_0, CanUseSameAccessor_FastDoubleElements_0) \ +TFC(CanUseSameAccessor_FastSmiElements_0, CanUseSameAccessor_FastSmiElements_0) \ +TFC(CanUseSameAccessor_FastObjectElements_0, CanUseSameAccessor_FastObjectElements_0) \ +TFC(LoadNoHasPropertyCheck_GenericElementsAccessor_0, LoadNoHasPropertyCheck_GenericElementsAccessor_0) \ +TFC(Load_GenericElementsAccessor_0, Load_GenericElementsAccessor_0) \ +TFC(Store_GenericElementsAccessor_0, Store_GenericElementsAccessor_0) \ +TFC(Delete_GenericElementsAccessor_0, Delete_GenericElementsAccessor_0) \ +TFC(LoadTypedElement_Int32Elements_0, LoadTypedElement_Int32Elements_0) \ +TFC(StoreTypedElementNumeric_Int32Elements_0, StoreTypedElementNumeric_Int32Elements_0) \ +TFC(StoreTypedElementJSAny_Int32Elements_0, StoreTypedElementJSAny_Int32Elements_0) \ +TFC(LoadTypedElement_Float16Elements_0, LoadTypedElement_Float16Elements_0) \ +TFC(StoreTypedElementNumeric_Float16Elements_0, StoreTypedElementNumeric_Float16Elements_0) \ +TFC(StoreTypedElementJSAny_Float16Elements_0, StoreTypedElementJSAny_Float16Elements_0) \ +TFC(LoadTypedElement_Float32Elements_0, LoadTypedElement_Float32Elements_0) \ +TFC(StoreTypedElementNumeric_Float32Elements_0, StoreTypedElementNumeric_Float32Elements_0) \ +TFC(StoreTypedElementJSAny_Float32Elements_0, StoreTypedElementJSAny_Float32Elements_0) \ +TFC(LoadTypedElement_Float64Elements_0, LoadTypedElement_Float64Elements_0) \ +TFC(StoreTypedElementNumeric_Float64Elements_0, StoreTypedElementNumeric_Float64Elements_0) \ +TFC(StoreTypedElementJSAny_Float64Elements_0, StoreTypedElementJSAny_Float64Elements_0) \ +TFC(LoadTypedElement_Uint8ClampedElements_0, LoadTypedElement_Uint8ClampedElements_0) \ +TFC(StoreTypedElementNumeric_Uint8ClampedElements_0, StoreTypedElementNumeric_Uint8ClampedElements_0) \ +TFC(StoreTypedElementJSAny_Uint8ClampedElements_0, StoreTypedElementJSAny_Uint8ClampedElements_0) \ +TFC(LoadTypedElement_BigUint64Elements_0, LoadTypedElement_BigUint64Elements_0) \ +TFC(StoreTypedElementNumeric_BigUint64Elements_0, StoreTypedElementNumeric_BigUint64Elements_0) \ +TFC(StoreTypedElementJSAny_BigUint64Elements_0, StoreTypedElementJSAny_BigUint64Elements_0) \ +TFC(LoadTypedElement_BigInt64Elements_0, LoadTypedElement_BigInt64Elements_0) \ +TFC(StoreTypedElementNumeric_BigInt64Elements_0, StoreTypedElementNumeric_BigInt64Elements_0) \ +TFC(StoreTypedElementJSAny_BigInt64Elements_0, StoreTypedElementJSAny_BigInt64Elements_0) \ +TFC(LoadTypedElement_Uint8Elements_0, LoadTypedElement_Uint8Elements_0) \ +TFC(StoreTypedElementNumeric_Uint8Elements_0, StoreTypedElementNumeric_Uint8Elements_0) \ +TFC(StoreTypedElementJSAny_Uint8Elements_0, StoreTypedElementJSAny_Uint8Elements_0) \ +TFC(LoadTypedElement_Int8Elements_0, LoadTypedElement_Int8Elements_0) \ +TFC(StoreTypedElementNumeric_Int8Elements_0, StoreTypedElementNumeric_Int8Elements_0) \ +TFC(StoreTypedElementJSAny_Int8Elements_0, StoreTypedElementJSAny_Int8Elements_0) \ +TFC(LoadTypedElement_Uint16Elements_0, LoadTypedElement_Uint16Elements_0) \ +TFC(StoreTypedElementNumeric_Uint16Elements_0, StoreTypedElementNumeric_Uint16Elements_0) \ +TFC(StoreTypedElementJSAny_Uint16Elements_0, StoreTypedElementJSAny_Uint16Elements_0) \ +TFC(LoadTypedElement_Int16Elements_0, LoadTypedElement_Int16Elements_0) \ +TFC(StoreTypedElementNumeric_Int16Elements_0, StoreTypedElementNumeric_Int16Elements_0) \ +TFC(StoreTypedElementJSAny_Int16Elements_0, StoreTypedElementJSAny_Int16Elements_0) \ +TFC(LoadTypedElement_Uint32Elements_0, LoadTypedElement_Uint32Elements_0) \ +TFC(StoreTypedElementNumeric_Uint32Elements_0, StoreTypedElementNumeric_Uint32Elements_0) \ +TFC(StoreTypedElementJSAny_Uint32Elements_0, StoreTypedElementJSAny_Uint32Elements_0) \ + +#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \ + V(0,LoadJoinElement_DictionaryElements_0)\ + V(1,LoadTypedElement_Int32Elements_0)\ + V(2,StoreTypedElementNumeric_Int32Elements_0)\ + V(3,StoreTypedElementJSAny_Int32Elements_0)\ + V(4,GenericArrayToReversed)\ + V(5,TestHelperPlus1)\ + V(6,WasmTraceGlobal)\ + V(7,CreateAsyncFromSyncIteratorBaseline)\ + V(8,Load_FastSmiElements_0)\ + V(9,Store_FastSmiElements_0)\ + V(10,Delete_FastSmiElements_0)\ + +#endif // V8_GEN_TORQUE_GENERATED_BUILTIN_DEFINITIONS_H_ diff --git a/deps/v8/src/gen/intl-wasm/bytecodes-builtins-list.h b/deps/v8/src/gen/intl-wasm/bytecodes-builtins-list.h new file mode 100644 index 000000000000..83b383826ad4 --- /dev/null +++ b/deps/v8/src/gen/intl-wasm/bytecodes-builtins-list.h @@ -0,0 +1,555 @@ +// Automatically generated from interpreter/bytecodes.h +// The following list macro is used to populate the builtins list +// with the bytecode handlers + +#ifndef V8_GEN_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST_H_ +#define V8_GEN_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST_H_ + +#include <stdint.h> + +#include "src/common/globals.h" + +namespace v8 { +namespace internal { + +#define BUILTIN_LIST_BYTECODE_HANDLERS(V_TSA, V) \ + V(WideHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kWide) \ + V(ExtraWideHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kExtraWide) \ + V(DebugBreakWideHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreakWide) \ + V(DebugBreakExtraWideHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreakExtraWide) \ + V(DebugBreak0Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak0) \ + V(DebugBreak1Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak1) \ + V(DebugBreak2Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak2) \ + V(DebugBreak3Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak3) \ + V(DebugBreak4Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak4) \ + V(DebugBreak5Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak5) \ + V(DebugBreak6Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugBreak6) \ + V(LdarHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdar) \ + V(LdaZeroHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaZero) \ + V(LdaSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaSmi) \ + V(LdaUndefinedHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaUndefined) \ + V(LdaNullHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaNull) \ + V(LdaTheHoleHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaTheHole) \ + V(LdaTdzHoleHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaTdzHole) \ + V(LdaTrueHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaTrue) \ + V(LdaFalseHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaFalse) \ + V(LdaConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaConstant) \ + V(LdaContextSlotNoCellHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaContextSlotNoCell) \ + V(LdaContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaContextSlot) \ + V(LdaImmutableContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaImmutableContextSlot) \ + V(LdaCurrentContextSlotNoCellHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaCurrentContextSlotNoCell) \ + V(LdaCurrentContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaCurrentContextSlot) \ + V(LdaImmutableCurrentContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaImmutableCurrentContextSlot) \ + V(StarHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStar) \ + V(MovHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kMov) \ + V(PushContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kPushContext) \ + V(PopContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kPopContext) \ + V(TestReferenceEqualHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestReferenceEqual) \ + V(TestUndetectableHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestUndetectable) \ + V(TestNullHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestNull) \ + V(TestUndefinedHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestUndefined) \ + V(TestTypeOfHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestTypeOf) \ + V(LdaGlobalHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaGlobal) \ + V(LdaGlobalInsideTypeofHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaGlobalInsideTypeof) \ + V(StaGlobalHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaGlobal) \ + V(StaContextSlotNoCellHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaContextSlotNoCell) \ + V(StaCurrentContextSlotNoCellHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaCurrentContextSlotNoCell) \ + V(StaContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaContextSlot) \ + V(StaCurrentContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaCurrentContextSlot) \ + V(LdaLookupSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupSlot) \ + V(LdaLookupContextSlotNoCellHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupContextSlotNoCell) \ + V(LdaLookupContextSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupContextSlot) \ + V(LdaLookupGlobalSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupGlobalSlot) \ + V(LdaLookupSlotInsideTypeofHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupSlotInsideTypeof) \ + V(LdaLookupContextSlotNoCellInsideTypeofHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupContextSlotNoCellInsideTypeof) \ + V(LdaLookupContextSlotInsideTypeofHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupContextSlotInsideTypeof) \ + V(LdaLookupGlobalSlotInsideTypeofHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaLookupGlobalSlotInsideTypeof) \ + V(StaLookupSlotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaLookupSlot) \ + V(GetNamedPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetNamedProperty) \ + V(GetNamedPropertyFromSuperHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetNamedPropertyFromSuper) \ + V(GetKeyedPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetKeyedProperty) \ + V(GetEnumeratedKeyedPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetEnumeratedKeyedProperty) \ + V(GetPrivateFieldHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetPrivateField) \ + V(LdaModuleVariableHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLdaModuleVariable) \ + V(StaModuleVariableHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaModuleVariable) \ + V(SetNamedPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSetNamedProperty) \ + V(DefineNamedOwnPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDefineNamedOwnProperty) \ + V(DefineNamedOwnPropertyInLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDefineNamedOwnPropertyInLiteral) \ + V(SetKeyedPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSetKeyedProperty) \ + V(DefineKeyedOwnPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDefineKeyedOwnProperty) \ + V(StaInArrayLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStaInArrayLiteral) \ + V(DefineKeyedOwnPropertyInLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDefineKeyedOwnPropertyInLiteral) \ + V(SetPrototypePropertiesHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSetPrototypeProperties) \ + V(SetPrivateFieldHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSetPrivateField) \ + V(AddHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kAdd) \ + V(SubHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSub) \ + V(MulHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kMul) \ + V(DivHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDiv) \ + V(ModHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kMod) \ + V(ExpHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kExp) \ + V(BitwiseOrHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseOr) \ + V(BitwiseXorHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseXor) \ + V(BitwiseAndHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseAnd) \ + V(ShiftLeftHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kShiftLeft) \ + V(ShiftRightHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kShiftRight) \ + V(ShiftRightLogicalHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kShiftRightLogical) \ + V(Add_StringConstant_InternalizeHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kAdd_StringConstant_Internalize) \ + V(AddSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kAddSmi) \ + V(SubSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSubSmi) \ + V(MulSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kMulSmi) \ + V(DivSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDivSmi) \ + V(ModSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kModSmi) \ + V(ExpSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kExpSmi) \ + V(BitwiseOrSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseOrSmi) \ + V(BitwiseXorSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseXorSmi) \ + V(BitwiseAndSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseAndSmi) \ + V(ShiftLeftSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kShiftLeftSmi) \ + V(ShiftRightSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kShiftRightSmi) \ + V(ShiftRightLogicalSmiHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kShiftRightLogicalSmi) \ + V(IncHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kInc) \ + V(DecHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDec) \ + V(NegateHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kNegate) \ + V(BitwiseNotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kBitwiseNot) \ + V(ToBooleanLogicalNotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToBooleanLogicalNot) \ + V(LogicalNotHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kLogicalNot) \ + V(TypeOfHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTypeOf) \ + V(DeletePropertyStrictHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDeletePropertyStrict) \ + V(DeletePropertySloppyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDeletePropertySloppy) \ + V(GetSuperConstructorHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetSuperConstructor) \ + V(FindNonDefaultConstructorOrConstructHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kFindNonDefaultConstructorOrConstruct) \ + V(CallAnyReceiverHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallAnyReceiver) \ + V(CallPropertyHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallProperty) \ + V(CallProperty0Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallProperty0) \ + V(CallProperty1Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallProperty1) \ + V(CallProperty2Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallProperty2) \ + V(CallUndefinedReceiverHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallUndefinedReceiver) \ + V(CallUndefinedReceiver0Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallUndefinedReceiver0) \ + V(CallUndefinedReceiver1Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallUndefinedReceiver1) \ + V(CallUndefinedReceiver2Handler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallUndefinedReceiver2) \ + V(CallWithSpreadHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallWithSpread) \ + V(CallRuntimeHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallRuntime) \ + V(CallRuntimeForPairHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallRuntimeForPair) \ + V(CallJSRuntimeHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCallJSRuntime) \ + V(InvokeIntrinsicHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kInvokeIntrinsic) \ + V(ConstructHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kConstruct) \ + V(ConstructWithSpreadHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kConstructWithSpread) \ + V(ConstructForwardAllArgsHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kConstructForwardAllArgs) \ + V(TestEqualHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestEqual) \ + V(TestEqualStrictHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestEqualStrict) \ + V(TestLessThanHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestLessThan) \ + V(TestGreaterThanHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestGreaterThan) \ + V(TestLessThanOrEqualHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestLessThanOrEqual) \ + V(TestGreaterThanOrEqualHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestGreaterThanOrEqual) \ + V(TestInstanceOfHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestInstanceOf) \ + V(TestInHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kTestIn) \ + V(ToNameHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToName) \ + V(ToNumberHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToNumber) \ + V(ToNumericHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToNumeric) \ + V(ToObjectHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToObject) \ + V(ToStringHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToString) \ + V(ToBooleanHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kToBoolean) \ + V(CreateRegExpLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateRegExpLiteral) \ + V(CreateArrayLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateArrayLiteral) \ + V(CreateArrayFromIterableHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateArrayFromIterable) \ + V(CreateEmptyArrayLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateEmptyArrayLiteral) \ + V(CreateObjectLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateObjectLiteral) \ + V(CreateEmptyObjectLiteralHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateEmptyObjectLiteral) \ + V(CloneObjectHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCloneObject) \ + V(GetTemplateObjectHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetTemplateObject) \ + V(CreateClosureHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateClosure) \ + V(CreateBlockContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateBlockContext) \ + V(CreateCatchContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateCatchContext) \ + V(CreateFunctionContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateFunctionContext) \ + V(CreateFunctionContextWithCellsHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateFunctionContextWithCells) \ + V(CreateEvalContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateEvalContext) \ + V(CreateWithContextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateWithContext) \ + V(CreateMappedArgumentsHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateMappedArguments) \ + V(CreateUnmappedArgumentsHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateUnmappedArguments) \ + V(CreateRestParameterHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kCreateRestParameter) \ + V(JumpLoopHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpLoop) \ + V(JumpHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJump) \ + V(JumpConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpConstant) \ + V(JumpIfNullConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfNullConstant) \ + V(JumpIfNotNullConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfNotNullConstant) \ + V(JumpIfUndefinedConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfUndefinedConstant) \ + V(JumpIfNotUndefinedConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfNotUndefinedConstant) \ + V(JumpIfUndefinedOrNullConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfUndefinedOrNullConstant) \ + V(JumpIfTrueConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfTrueConstant) \ + V(JumpIfFalseConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfFalseConstant) \ + V(JumpIfJSReceiverConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfJSReceiverConstant) \ + V(JumpIfForInDoneConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfForInDoneConstant) \ + V(JumpIfToBooleanTrueConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfToBooleanTrueConstant) \ + V(JumpIfToBooleanFalseConstantHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfToBooleanFalseConstant) \ + V(JumpIfToBooleanTrueHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfToBooleanTrue) \ + V(JumpIfToBooleanFalseHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfToBooleanFalse) \ + V(JumpIfTrueHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfTrue) \ + V(JumpIfFalseHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfFalse) \ + V(JumpIfNullHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfNull) \ + V(JumpIfNotNullHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfNotNull) \ + V(JumpIfUndefinedHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfUndefined) \ + V(JumpIfNotUndefinedHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfNotUndefined) \ + V(JumpIfUndefinedOrNullHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfUndefinedOrNull) \ + V(JumpIfJSReceiverHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfJSReceiver) \ + V(JumpIfForInDoneHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kJumpIfForInDone) \ + V(SwitchOnSmiNoFeedbackHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSwitchOnSmiNoFeedback) \ + V(ForInEnumerateHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kForInEnumerate) \ + V(ForInPrepareHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kForInPrepare) \ + V(ForInNextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kForInNext) \ + V(ForInStepHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kForInStep) \ + V(ForOfNextHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kForOfNext) \ + V(SetPendingMessageHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSetPendingMessage) \ + V(ThrowHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kThrow) \ + V(ReThrowHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kReThrow) \ + V(ReturnHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kReturn) \ + V(ThrowReferenceErrorIfTdzHoleHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kThrowReferenceErrorIfTdzHole) \ + V(ThrowSuperNotCalledIfTdzHoleHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kThrowSuperNotCalledIfTdzHole) \ + V(ThrowSuperAlreadyCalledIfNotTdzHoleHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kThrowSuperAlreadyCalledIfNotTdzHole) \ + V(ThrowIfNotSuperConstructorHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kThrowIfNotSuperConstructor) \ + V(SwitchOnGeneratorStateHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSwitchOnGeneratorState) \ + V(SuspendGeneratorHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kSuspendGenerator) \ + V(ResumeGeneratorHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kResumeGenerator) \ + V(GetIteratorHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kGetIterator) \ + V(ArrayDestructureHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kArrayDestructure) \ + V(DebuggerHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kDebugger) \ + V(IncBlockCounterHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kIncBlockCounter) \ + V(AbortHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kAbort) \ + V(ShortStarHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kStar0) \ + V(IllegalHandler, interpreter::OperandScale::kSingle, interpreter::Bytecode::kIllegal) \ + V(DebugBreak1WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDebugBreak1) \ + V(DebugBreak2WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDebugBreak2) \ + V(DebugBreak3WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDebugBreak3) \ + V(DebugBreak4WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDebugBreak4) \ + V(DebugBreak5WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDebugBreak5) \ + V(DebugBreak6WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDebugBreak6) \ + V(LdarWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdar) \ + V(LdaSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaSmi) \ + V(LdaConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaConstant) \ + V(LdaContextSlotNoCellWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaContextSlotNoCell) \ + V(LdaContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaContextSlot) \ + V(LdaImmutableContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaImmutableContextSlot) \ + V(LdaCurrentContextSlotNoCellWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaCurrentContextSlotNoCell) \ + V(LdaCurrentContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaCurrentContextSlot) \ + V(LdaImmutableCurrentContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaImmutableCurrentContextSlot) \ + V(StarWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStar) \ + V(MovWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kMov) \ + V(PushContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kPushContext) \ + V(PopContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kPopContext) \ + V(TestReferenceEqualWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestReferenceEqual) \ + V(LdaGlobalWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaGlobal) \ + V(LdaGlobalInsideTypeofWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaGlobalInsideTypeof) \ + V(StaGlobalWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaGlobal) \ + V(StaContextSlotNoCellWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaContextSlotNoCell) \ + V(StaCurrentContextSlotNoCellWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaCurrentContextSlotNoCell) \ + V(StaContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaContextSlot) \ + V(StaCurrentContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaCurrentContextSlot) \ + V(LdaLookupSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupSlot) \ + V(LdaLookupContextSlotNoCellWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupContextSlotNoCell) \ + V(LdaLookupContextSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupContextSlot) \ + V(LdaLookupGlobalSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupGlobalSlot) \ + V(LdaLookupSlotInsideTypeofWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupSlotInsideTypeof) \ + V(LdaLookupContextSlotNoCellInsideTypeofWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupContextSlotNoCellInsideTypeof) \ + V(LdaLookupContextSlotInsideTypeofWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupContextSlotInsideTypeof) \ + V(LdaLookupGlobalSlotInsideTypeofWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaLookupGlobalSlotInsideTypeof) \ + V(StaLookupSlotWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaLookupSlot) \ + V(GetNamedPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetNamedProperty) \ + V(GetNamedPropertyFromSuperWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetNamedPropertyFromSuper) \ + V(GetKeyedPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetKeyedProperty) \ + V(GetEnumeratedKeyedPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetEnumeratedKeyedProperty) \ + V(GetPrivateFieldWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetPrivateField) \ + V(LdaModuleVariableWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kLdaModuleVariable) \ + V(StaModuleVariableWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaModuleVariable) \ + V(SetNamedPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSetNamedProperty) \ + V(DefineNamedOwnPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDefineNamedOwnProperty) \ + V(DefineNamedOwnPropertyInLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDefineNamedOwnPropertyInLiteral) \ + V(SetKeyedPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSetKeyedProperty) \ + V(DefineKeyedOwnPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDefineKeyedOwnProperty) \ + V(StaInArrayLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kStaInArrayLiteral) \ + V(DefineKeyedOwnPropertyInLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDefineKeyedOwnPropertyInLiteral) \ + V(SetPrototypePropertiesWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSetPrototypeProperties) \ + V(SetPrivateFieldWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSetPrivateField) \ + V(AddWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kAdd) \ + V(SubWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSub) \ + V(MulWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kMul) \ + V(DivWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDiv) \ + V(ModWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kMod) \ + V(ExpWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kExp) \ + V(BitwiseOrWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kBitwiseOr) \ + V(BitwiseXorWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kBitwiseXor) \ + V(BitwiseAndWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kBitwiseAnd) \ + V(ShiftLeftWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kShiftLeft) \ + V(ShiftRightWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kShiftRight) \ + V(ShiftRightLogicalWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kShiftRightLogical) \ + V(Add_StringConstant_InternalizeWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kAdd_StringConstant_Internalize) \ + V(AddSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kAddSmi) \ + V(SubSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSubSmi) \ + V(MulSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kMulSmi) \ + V(DivSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDivSmi) \ + V(ModSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kModSmi) \ + V(ExpSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kExpSmi) \ + V(BitwiseOrSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kBitwiseOrSmi) \ + V(BitwiseXorSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kBitwiseXorSmi) \ + V(BitwiseAndSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kBitwiseAndSmi) \ + V(ShiftLeftSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kShiftLeftSmi) \ + V(ShiftRightSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kShiftRightSmi) \ + V(ShiftRightLogicalSmiWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kShiftRightLogicalSmi) \ + V(TypeOfWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTypeOf) \ + V(DeletePropertyStrictWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDeletePropertyStrict) \ + V(DeletePropertySloppyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kDeletePropertySloppy) \ + V(GetSuperConstructorWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetSuperConstructor) \ + V(FindNonDefaultConstructorOrConstructWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kFindNonDefaultConstructorOrConstruct) \ + V(CallAnyReceiverWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallAnyReceiver) \ + V(CallPropertyWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallProperty) \ + V(CallProperty0WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallProperty0) \ + V(CallProperty1WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallProperty1) \ + V(CallProperty2WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallProperty2) \ + V(CallUndefinedReceiverWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallUndefinedReceiver) \ + V(CallUndefinedReceiver0WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallUndefinedReceiver0) \ + V(CallUndefinedReceiver1WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallUndefinedReceiver1) \ + V(CallUndefinedReceiver2WideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallUndefinedReceiver2) \ + V(CallWithSpreadWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallWithSpread) \ + V(CallRuntimeWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallRuntime) \ + V(CallRuntimeForPairWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallRuntimeForPair) \ + V(CallJSRuntimeWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCallJSRuntime) \ + V(InvokeIntrinsicWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kInvokeIntrinsic) \ + V(ConstructWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kConstruct) \ + V(ConstructWithSpreadWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kConstructWithSpread) \ + V(ConstructForwardAllArgsWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kConstructForwardAllArgs) \ + V(TestEqualWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestEqual) \ + V(TestEqualStrictWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestEqualStrict) \ + V(TestLessThanWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestLessThan) \ + V(TestGreaterThanWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestGreaterThan) \ + V(TestLessThanOrEqualWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestLessThanOrEqual) \ + V(TestGreaterThanOrEqualWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestGreaterThanOrEqual) \ + V(TestInstanceOfWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestInstanceOf) \ + V(TestInWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kTestIn) \ + V(ToNumberWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kToNumber) \ + V(ToNumericWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kToNumeric) \ + V(ToObjectWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kToObject) \ + V(CreateRegExpLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateRegExpLiteral) \ + V(CreateArrayLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateArrayLiteral) \ + V(CreateEmptyArrayLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateEmptyArrayLiteral) \ + V(CreateObjectLiteralWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateObjectLiteral) \ + V(CloneObjectWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCloneObject) \ + V(GetTemplateObjectWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetTemplateObject) \ + V(CreateClosureWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateClosure) \ + V(CreateBlockContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateBlockContext) \ + V(CreateCatchContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateCatchContext) \ + V(CreateFunctionContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateFunctionContext) \ + V(CreateFunctionContextWithCellsWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateFunctionContextWithCells) \ + V(CreateEvalContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateEvalContext) \ + V(CreateWithContextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kCreateWithContext) \ + V(JumpLoopWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpLoop) \ + V(JumpWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJump) \ + V(JumpConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpConstant) \ + V(JumpIfNullConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfNullConstant) \ + V(JumpIfNotNullConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfNotNullConstant) \ + V(JumpIfUndefinedConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfUndefinedConstant) \ + V(JumpIfNotUndefinedConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfNotUndefinedConstant) \ + V(JumpIfUndefinedOrNullConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfUndefinedOrNullConstant) \ + V(JumpIfTrueConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfTrueConstant) \ + V(JumpIfFalseConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfFalseConstant) \ + V(JumpIfJSReceiverConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfJSReceiverConstant) \ + V(JumpIfForInDoneConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfForInDoneConstant) \ + V(JumpIfToBooleanTrueConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfToBooleanTrueConstant) \ + V(JumpIfToBooleanFalseConstantWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfToBooleanFalseConstant) \ + V(JumpIfToBooleanTrueWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfToBooleanTrue) \ + V(JumpIfToBooleanFalseWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfToBooleanFalse) \ + V(JumpIfTrueWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfTrue) \ + V(JumpIfFalseWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfFalse) \ + V(JumpIfNullWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfNull) \ + V(JumpIfNotNullWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfNotNull) \ + V(JumpIfUndefinedWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfUndefined) \ + V(JumpIfNotUndefinedWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfNotUndefined) \ + V(JumpIfUndefinedOrNullWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfUndefinedOrNull) \ + V(JumpIfJSReceiverWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfJSReceiver) \ + V(JumpIfForInDoneWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kJumpIfForInDone) \ + V(SwitchOnSmiNoFeedbackWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSwitchOnSmiNoFeedback) \ + V(ForInEnumerateWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kForInEnumerate) \ + V(ForInPrepareWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kForInPrepare) \ + V(ForInNextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kForInNext) \ + V(ForInStepWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kForInStep) \ + V(ForOfNextWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kForOfNext) \ + V(ThrowReferenceErrorIfTdzHoleWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kThrowReferenceErrorIfTdzHole) \ + V(ThrowIfNotSuperConstructorWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kThrowIfNotSuperConstructor) \ + V(SwitchOnGeneratorStateWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSwitchOnGeneratorState) \ + V(SuspendGeneratorWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kSuspendGenerator) \ + V(ResumeGeneratorWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kResumeGenerator) \ + V(GetIteratorWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kGetIterator) \ + V(ArrayDestructureWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kArrayDestructure) \ + V(IncBlockCounterWideHandler, interpreter::OperandScale::kDouble, interpreter::Bytecode::kIncBlockCounter) \ + V(DebugBreak1ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDebugBreak1) \ + V(DebugBreak2ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDebugBreak2) \ + V(DebugBreak3ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDebugBreak3) \ + V(DebugBreak4ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDebugBreak4) \ + V(DebugBreak5ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDebugBreak5) \ + V(DebugBreak6ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDebugBreak6) \ + V(LdarExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdar) \ + V(LdaSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaSmi) \ + V(LdaConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaConstant) \ + V(LdaContextSlotNoCellExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaContextSlotNoCell) \ + V(LdaContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaContextSlot) \ + V(LdaImmutableContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaImmutableContextSlot) \ + V(LdaCurrentContextSlotNoCellExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaCurrentContextSlotNoCell) \ + V(LdaCurrentContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaCurrentContextSlot) \ + V(LdaImmutableCurrentContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaImmutableCurrentContextSlot) \ + V(StarExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStar) \ + V(MovExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kMov) \ + V(PushContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kPushContext) \ + V(PopContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kPopContext) \ + V(TestReferenceEqualExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestReferenceEqual) \ + V(LdaGlobalExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaGlobal) \ + V(LdaGlobalInsideTypeofExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaGlobalInsideTypeof) \ + V(StaGlobalExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaGlobal) \ + V(StaContextSlotNoCellExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaContextSlotNoCell) \ + V(StaCurrentContextSlotNoCellExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaCurrentContextSlotNoCell) \ + V(StaContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaContextSlot) \ + V(StaCurrentContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaCurrentContextSlot) \ + V(LdaLookupSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupSlot) \ + V(LdaLookupContextSlotNoCellExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupContextSlotNoCell) \ + V(LdaLookupContextSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupContextSlot) \ + V(LdaLookupGlobalSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupGlobalSlot) \ + V(LdaLookupSlotInsideTypeofExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupSlotInsideTypeof) \ + V(LdaLookupContextSlotNoCellInsideTypeofExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupContextSlotNoCellInsideTypeof) \ + V(LdaLookupContextSlotInsideTypeofExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupContextSlotInsideTypeof) \ + V(LdaLookupGlobalSlotInsideTypeofExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaLookupGlobalSlotInsideTypeof) \ + V(StaLookupSlotExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaLookupSlot) \ + V(GetNamedPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetNamedProperty) \ + V(GetNamedPropertyFromSuperExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetNamedPropertyFromSuper) \ + V(GetKeyedPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetKeyedProperty) \ + V(GetEnumeratedKeyedPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetEnumeratedKeyedProperty) \ + V(GetPrivateFieldExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetPrivateField) \ + V(LdaModuleVariableExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kLdaModuleVariable) \ + V(StaModuleVariableExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaModuleVariable) \ + V(SetNamedPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSetNamedProperty) \ + V(DefineNamedOwnPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDefineNamedOwnProperty) \ + V(DefineNamedOwnPropertyInLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDefineNamedOwnPropertyInLiteral) \ + V(SetKeyedPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSetKeyedProperty) \ + V(DefineKeyedOwnPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDefineKeyedOwnProperty) \ + V(StaInArrayLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kStaInArrayLiteral) \ + V(DefineKeyedOwnPropertyInLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDefineKeyedOwnPropertyInLiteral) \ + V(SetPrototypePropertiesExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSetPrototypeProperties) \ + V(SetPrivateFieldExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSetPrivateField) \ + V(AddExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kAdd) \ + V(SubExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSub) \ + V(MulExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kMul) \ + V(DivExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDiv) \ + V(ModExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kMod) \ + V(ExpExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kExp) \ + V(BitwiseOrExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kBitwiseOr) \ + V(BitwiseXorExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kBitwiseXor) \ + V(BitwiseAndExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kBitwiseAnd) \ + V(ShiftLeftExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kShiftLeft) \ + V(ShiftRightExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kShiftRight) \ + V(ShiftRightLogicalExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kShiftRightLogical) \ + V(Add_StringConstant_InternalizeExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kAdd_StringConstant_Internalize) \ + V(AddSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kAddSmi) \ + V(SubSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSubSmi) \ + V(MulSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kMulSmi) \ + V(DivSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDivSmi) \ + V(ModSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kModSmi) \ + V(ExpSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kExpSmi) \ + V(BitwiseOrSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kBitwiseOrSmi) \ + V(BitwiseXorSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kBitwiseXorSmi) \ + V(BitwiseAndSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kBitwiseAndSmi) \ + V(ShiftLeftSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kShiftLeftSmi) \ + V(ShiftRightSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kShiftRightSmi) \ + V(ShiftRightLogicalSmiExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kShiftRightLogicalSmi) \ + V(TypeOfExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTypeOf) \ + V(DeletePropertyStrictExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDeletePropertyStrict) \ + V(DeletePropertySloppyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kDeletePropertySloppy) \ + V(GetSuperConstructorExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetSuperConstructor) \ + V(FindNonDefaultConstructorOrConstructExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kFindNonDefaultConstructorOrConstruct) \ + V(CallAnyReceiverExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallAnyReceiver) \ + V(CallPropertyExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallProperty) \ + V(CallProperty0ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallProperty0) \ + V(CallProperty1ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallProperty1) \ + V(CallProperty2ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallProperty2) \ + V(CallUndefinedReceiverExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallUndefinedReceiver) \ + V(CallUndefinedReceiver0ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallUndefinedReceiver0) \ + V(CallUndefinedReceiver1ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallUndefinedReceiver1) \ + V(CallUndefinedReceiver2ExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallUndefinedReceiver2) \ + V(CallWithSpreadExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallWithSpread) \ + V(CallRuntimeExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallRuntime) \ + V(CallRuntimeForPairExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallRuntimeForPair) \ + V(CallJSRuntimeExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCallJSRuntime) \ + V(InvokeIntrinsicExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kInvokeIntrinsic) \ + V(ConstructExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kConstruct) \ + V(ConstructWithSpreadExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kConstructWithSpread) \ + V(ConstructForwardAllArgsExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kConstructForwardAllArgs) \ + V(TestEqualExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestEqual) \ + V(TestEqualStrictExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestEqualStrict) \ + V(TestLessThanExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestLessThan) \ + V(TestGreaterThanExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestGreaterThan) \ + V(TestLessThanOrEqualExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestLessThanOrEqual) \ + V(TestGreaterThanOrEqualExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestGreaterThanOrEqual) \ + V(TestInstanceOfExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestInstanceOf) \ + V(TestInExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kTestIn) \ + V(ToNumberExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kToNumber) \ + V(ToNumericExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kToNumeric) \ + V(ToObjectExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kToObject) \ + V(CreateRegExpLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateRegExpLiteral) \ + V(CreateArrayLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateArrayLiteral) \ + V(CreateEmptyArrayLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateEmptyArrayLiteral) \ + V(CreateObjectLiteralExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateObjectLiteral) \ + V(CloneObjectExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCloneObject) \ + V(GetTemplateObjectExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetTemplateObject) \ + V(CreateClosureExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateClosure) \ + V(CreateBlockContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateBlockContext) \ + V(CreateCatchContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateCatchContext) \ + V(CreateFunctionContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateFunctionContext) \ + V(CreateFunctionContextWithCellsExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateFunctionContextWithCells) \ + V(CreateEvalContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateEvalContext) \ + V(CreateWithContextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kCreateWithContext) \ + V(JumpLoopExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpLoop) \ + V(JumpExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJump) \ + V(JumpConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpConstant) \ + V(JumpIfNullConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfNullConstant) \ + V(JumpIfNotNullConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfNotNullConstant) \ + V(JumpIfUndefinedConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfUndefinedConstant) \ + V(JumpIfNotUndefinedConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfNotUndefinedConstant) \ + V(JumpIfUndefinedOrNullConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfUndefinedOrNullConstant) \ + V(JumpIfTrueConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfTrueConstant) \ + V(JumpIfFalseConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfFalseConstant) \ + V(JumpIfJSReceiverConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfJSReceiverConstant) \ + V(JumpIfForInDoneConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfForInDoneConstant) \ + V(JumpIfToBooleanTrueConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfToBooleanTrueConstant) \ + V(JumpIfToBooleanFalseConstantExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfToBooleanFalseConstant) \ + V(JumpIfToBooleanTrueExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfToBooleanTrue) \ + V(JumpIfToBooleanFalseExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfToBooleanFalse) \ + V(JumpIfTrueExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfTrue) \ + V(JumpIfFalseExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfFalse) \ + V(JumpIfNullExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfNull) \ + V(JumpIfNotNullExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfNotNull) \ + V(JumpIfUndefinedExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfUndefined) \ + V(JumpIfNotUndefinedExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfNotUndefined) \ + V(JumpIfUndefinedOrNullExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfUndefinedOrNull) \ + V(JumpIfJSReceiverExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfJSReceiver) \ + V(JumpIfForInDoneExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kJumpIfForInDone) \ + V(SwitchOnSmiNoFeedbackExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSwitchOnSmiNoFeedback) \ + V(ForInEnumerateExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kForInEnumerate) \ + V(ForInPrepareExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kForInPrepare) \ + V(ForInNextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kForInNext) \ + V(ForInStepExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kForInStep) \ + V(ForOfNextExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kForOfNext) \ + V(ThrowReferenceErrorIfTdzHoleExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kThrowReferenceErrorIfTdzHole) \ + V(ThrowIfNotSuperConstructorExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kThrowIfNotSuperConstructor) \ + V(SwitchOnGeneratorStateExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSwitchOnGeneratorState) \ + V(SuspendGeneratorExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kSuspendGenerator) \ + V(ResumeGeneratorExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kResumeGenerator) \ + V(GetIteratorExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kGetIterator) \ + V(ArrayDestructureExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kArrayDestructure) \ + V(IncBlockCounterExtraWideHandler, interpreter::OperandScale::kQuadruple, interpreter::Bytecode::kIncBlockCounter) + +constexpr int kNumberOfBytecodeHandlers = 202; +constexpr int kNumberOfWideBytecodeHandlers = 162; + +constexpr uint8_t kIllegalBytecodeHandlerEncoding = 255; + +// Mapping from Bytecode to a dense form with all the illegal +// wide Bytecodes removed. Used to index into the builtins table. +constexpr uint8_t kWideBytecodeToBuiltinsMapping[217] = { +255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 255, 7, 255, 255, 255, 255, 255, 255, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 255, 255, 255, 255, 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, 255, 255, 255, 255, 255, 255, 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, 255, 107, 108, 109, 255, 255, 110, 111, 255, 112, 113, 255, 114, 115, 116, 117, 118, 119, 120, 121, 122, 255, 255, 255, 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, 255, 255, 255, 255, 154, 255, 255, 155, 156, 157, 158, 159, 160, 255, 161, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; + +} // namespace internal +} // namespace v8 +#endif // V8_GEN_BUILTINS_GENERATED_BYTECODES_BUILTINS_LIST_H_ diff --git a/deps/v8/src/gen/intl-wasm/class-forward-declarations.h b/deps/v8/src/gen/intl-wasm/class-forward-declarations.h new file mode 100644 index 000000000000..ae84306bf892 --- /dev/null +++ b/deps/v8/src/gen/intl-wasm/class-forward-declarations.h @@ -0,0 +1,313 @@ +#ifndef V8_GEN_TORQUE_GENERATED_CLASS_FORWARD_DECLARATIONS_H_ +#define V8_GEN_TORQUE_GENERATED_CLASS_FORWARD_DECLARATIONS_H_ + +namespace v8 { +namespace internal { +class AccessCheckInfo; +class AccessorInfo; +class AccessorPair; +class AliasedArgumentsEntry; +class AllocationMemento; +class AllocationSite; +class AlwaysSharedSpaceJSObject; +class ArrayBoilerplateDescription; +class ArrayList; +class AsyncGeneratorRequest; +class AsyncResumeTask; +class AtomRegExpData; +class BigInt; +class Boolean; +class BreakPoint; +class BreakPointInfo; +class ByteArray; +class BytecodeArray; +class BytecodeWrapper; +class CallSiteInfo; +class CallableTask; +class CallbackTask; +class Cell; +class ClassBoilerplate; +class ClassPositions; +class ClosureFeedbackCellArray; +class Code; +class CodeWrapper; +class ConsString; +class Context; +class ContextCell; +class CoverageInfo; +class CppGCManagedBase; +class CppHeapExternalObject; +class DataHandler; +class DebugInfo; +class DebugScriptScopeInfo; +class DescriptorArray; +class DictionaryTemplateInfo; +class DoubleStringCache; +class EmbedderDataArray; +class EnumCache; +class EphemeronHashTable; +class ErrorStackData; +class ExposedTrustedObject; +class ExtendedMap; +class ExternalOneByteString; +class ExternalString; +class ExternalTwoByteString; +class False; +class FeedbackCell; +class FeedbackMetadata; +class FeedbackVector; +class FixedArray; +class FixedArrayBase; +class FixedDoubleArray; +class ForInEnumeratorHolder; +class Foreign; +class FreeSpace; +class FunctionTemplateInfo; +class FunctionTemplateRareData; +class GlobalDictionary; +class HashSeedWrapper; +class HeapNumber; +class HeapObject; +class Hole; +class InstructionStream; +class InterceptorInfo; +class InternalizedString; +class InterpreterData; +class IrRegExpData; +class JSAPIObjectWithEmbedderSlots; +class JSArgumentsObject; +class JSArray; +class JSArrayBuffer; +class JSArrayBufferView; +class JSArrayIterator; +class JSAsyncDisposableStack; +class JSAsyncFromSyncIterator; +class JSAsyncFunctionObject; +class JSAsyncGeneratorObject; +class JSBoundFunction; +class JSCollator; +class JSCollection; +class JSCollectionIterator; +class JSCustomElementsObject; +class JSDataView; +class JSDataViewOrRabGsabDataView; +class JSDate; +class JSDateTimeFormat; +class JSDeferredModuleNamespace; +class JSDetachedTypedArray; +class JSDisplayNames; +class JSDisposableStackBase; +class JSDurationFormat; +class JSExternalObject; +class JSFinalizationRegistry; +class JSFunction; +class JSFunctionOrBoundFunctionOrWrappedFunction; +class JSFunctionWithPrototype; +class JSFunctionWithoutPrototype; +class JSGeneratorObject; +class JSGlobalObject; +class JSGlobalProxy; +class JSInterceptorMap; +class JSIteratorConcatHelper; +class JSIteratorDropHelper; +class JSIteratorFilterHelper; +class JSIteratorFlatMapHelper; +class JSIteratorHelper; +class JSIteratorHelperSimple; +class JSIteratorMapHelper; +class JSIteratorTakeHelper; +class JSIteratorZipHelper; +class JSIteratorZipKeyedHelper; +class JSListFormat; +class JSLocale; +class JSMap; +class JSMapIterator; +class JSMessageObject; +class JSModuleNamespace; +class JSNumberFormat; +class JSObject; +class JSObjectWithEmbedderSlots; +class JSPluralRules; +class JSPrimitiveWrapper; +class JSPromise; +class JSProxy; +class JSRabGsabDataView; +class JSRawJson; +class JSReceiver; +class JSRegExp; +class JSRegExpResult; +class JSRegExpStringIterator; +class JSRelativeTimeFormat; +class JSSegmentDataObject; +class JSSegmentDataObjectWithIsWordLike; +class JSSegmentIterator; +class JSSegmenter; +class JSSegments; +class JSSet; +class JSSetIterator; +class JSShadowRealm; +class JSSharedArray; +class JSSharedStruct; +class JSSpecialObject; +class JSStringIterator; +class JSSyncDisposableStack; +class JSTemporalDuration; +class JSTemporalInstant; +class JSTemporalPlainDate; +class JSTemporalPlainDateTime; +class JSTemporalPlainMonthDay; +class JSTemporalPlainTime; +class JSTemporalPlainYearMonth; +class JSTemporalZonedDateTime; +class JSTypedArray; +class JSV8BreakIterator; +class JSValidIteratorWrapper; +class JSWeakCollection; +class JSWeakMap; +class JSWeakRef; +class JSWeakSet; +class JSWrappedFunction; +class LoadHandler; +class Map; +class MegaDomHandler; +class Microtask; +class Module; +class ModuleRequest; +class Name; +class NameDictionary; +class NameToIndexHashTable; +class NativeContext; +class Null; +class NumberDictionary; +class ObjectBoilerplateDescription; +class ObjectTemplateInfo; +class Oddball; +class OnHeapBasicBlockProfilerData; +class OrderedHashMap; +class OrderedHashSet; +class OrderedNameDictionary; +class PreparseData; +class PrimitiveHeapObject; +class PromiseCapability; +class PromiseFulfillReactionJobTask; +class PromiseHole; +class PromiseReaction; +class PromiseReactionJobTask; +class PromiseRejectReactionJobTask; +class PromiseResolveThenableJobTask; +class PropertyArray; +class PropertyCell; +class PropertyDescriptorObject; +class ProtectedFixedArray; +class ProtectedWeakFixedArray; +class PrototypeInfo; +class PrototypeSharedClosureInfo; +class RegExpBoilerplateDescription; +class RegExpData; +class RegExpDataWrapper; +class RegExpMatchInfo; +class RegisteredSymbolTable; +class ScopeInfo; +class Script; +class ScriptContextTable; +class ScriptOrModule; +class SeqOneByteString; +class SeqString; +class SeqTwoByteString; +class SharedFunctionInfo; +class SharedFunctionInfoWrapper; +class SimpleNameDictionary; +class SimpleNumberDictionary; +class SlicedString; +class SloppyArgumentsElements; +class SmallOrderedHashMap; +class SmallOrderedHashSet; +class SmallOrderedNameDictionary; +class SortState; +class SourceTextModule; +class SourceTextModuleInfoEntry; +class StackFrameInfo; +class StackTraceInfo; +class StoreHandler; +class String; +class Struct; +class SwissNameDictionary; +class Symbol; +class SyntheticModule; +class TemplateInfo; +class TemplateInfoWithProperties; +class TemplateLiteralObject; +class TemplateObjectDescription; +class TheHole; +class ThinString; +class TransitionArray; +class True; +class TrustedByteArray; +class TrustedFixedArray; +class TrustedFixedArrayBase; +class TrustedForeign; +class TrustedObject; +class TrustedWeakFixedArray; +class Tuple2; +class TurbofanBitsetType; +class TurbofanHeapConstantType; +class TurbofanOtherNumberConstantType; +class TurbofanRangeType; +class TurbofanType; +class TurbofanUnionType; +class TurboshaftFloat64RangeType; +class TurboshaftFloat64SetType; +class TurboshaftFloat64Type; +class TurboshaftType; +class TurboshaftWord32RangeType; +class TurboshaftWord32SetType; +class TurboshaftWord32Type; +class TurboshaftWord64RangeType; +class TurboshaftWord64SetType; +class TurboshaftWord64Type; +class UncompiledData; +class UncompiledDataWithPreparseData; +class UncompiledDataWithPreparseDataAndJob; +class UncompiledDataWithoutPreparseData; +class UncompiledDataWithoutPreparseDataWithJob; +class Undefined; +class UninitializedHeapNumber; +class WasmArray; +class WasmCapiFunctionData; +class WasmContinuationObject; +class WasmCustomMap; +class WasmCustomMapWrapper; +class WasmDispatchTable; +class WasmDispatchTableForImports; +class WasmExceptionPackage; +class WasmExceptionTag; +class WasmExportedFunctionData; +class WasmFastApiCallData; +class WasmFuncRef; +class WasmFunctionData; +class WasmGlobalObject; +class WasmImportData; +class WasmInstanceObject; +class WasmInternalFunction; +class WasmMemoryObject; +class WasmModuleObject; +class WasmNull; +class WasmObject; +class WasmResumeData; +class WasmStackObject; +class WasmStringViewIter; +class WasmStruct; +class WasmSuspenderObject; +class WasmSuspendingObject; +class WasmTableObject; +class WasmTagObject; +class WasmTrustedInstanceData; +class WasmTypeInfo; +class WasmValueObject; +class WeakArrayList; +class WeakCell; +class WeakFixedArray; +class WeakHomomorphicFixedArray; +} // namespace internal +} // namespace v8 +#endif // V8_GEN_TORQUE_GENERATED_CLASS_FORWARD_DECLARATIONS_H_ diff --git a/deps/v8/src/gen/intl-wasm/instance-types.h b/deps/v8/src/gen/intl-wasm/instance-types.h new file mode 100644 index 000000000000..a4e9e4b77043 --- /dev/null +++ b/deps/v8/src/gen/intl-wasm/instance-types.h @@ -0,0 +1,1838 @@ +// This file is automatically generated by tools/metagen/metagen.py. +// Do not edit manually. + +#ifndef V8_GEN_METAGEN_INSTANCE_TYPES_H_ +#define V8_GEN_METAGEN_INSTANCE_TYPES_H_ + +// Instance types for all classes except for those that use InstanceType as flags. +#define TORQUE_ASSIGNED_INSTANCE_TYPES(V) \ + V(FIRST_HEAP_OBJECT_TYPE, 0) \ + V(FIRST_PRIMITIVE_HEAP_OBJECT_TYPE, 0) \ + V(FIRST_NAME_TYPE, 0) \ + V(FIRST_STRING_TYPE, 0) \ + V(FIRST_SYMBOL_TYPE, 128) \ + V(SYMBOL_TYPE, 128) \ + V(LAST_SYMBOL_TYPE, 128) \ + V(LAST_NAME_TYPE, 128) \ + V(FIRST_BIG_INT_BASE_TYPE, 129) \ + V(BIG_INT_BASE_TYPE, 129) \ + V(LAST_BIG_INT_BASE_TYPE, 129) \ + V(FIRST_HEAP_NUMBER_TYPE, 130) \ + V(HEAP_NUMBER_TYPE, 130) \ + V(LAST_HEAP_NUMBER_TYPE, 130) \ + V(FIRST_ODDBALL_TYPE, 131) \ + V(ODDBALL_TYPE, 131) \ + V(LAST_ODDBALL_TYPE, 131) \ + V(LAST_PRIMITIVE_HEAP_OBJECT_TYPE, 131) \ + V(FIRST_STRUCT_TYPE, 132) \ + V(FIRST_MICROTASK_TYPE, 132) \ + V(FIRST_PROMISE_REACTION_JOB_TASK_TYPE, 132) \ + V(FIRST_PROMISE_FULFILL_REACTION_JOB_TASK_TYPE, 132) \ + V(PROMISE_FULFILL_REACTION_JOB_TASK_TYPE, 132) \ + V(LAST_PROMISE_FULFILL_REACTION_JOB_TASK_TYPE, 132) \ + V(FIRST_PROMISE_REJECT_REACTION_JOB_TASK_TYPE, 133) \ + V(PROMISE_REJECT_REACTION_JOB_TASK_TYPE, 133) \ + V(LAST_PROMISE_REJECT_REACTION_JOB_TASK_TYPE, 133) \ + V(LAST_PROMISE_REACTION_JOB_TASK_TYPE, 133) \ + V(FIRST_ASYNC_RESUME_TASK_TYPE, 134) \ + V(ASYNC_RESUME_TASK_TYPE, 134) \ + V(LAST_ASYNC_RESUME_TASK_TYPE, 134) \ + V(FIRST_CALLABLE_TASK_TYPE, 135) \ + V(CALLABLE_TASK_TYPE, 135) \ + V(LAST_CALLABLE_TASK_TYPE, 135) \ + V(FIRST_CALLBACK_TASK_TYPE, 136) \ + V(CALLBACK_TASK_TYPE, 136) \ + V(LAST_CALLBACK_TASK_TYPE, 136) \ + V(FIRST_PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, 137) \ + V(PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, 137) \ + V(LAST_PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, 137) \ + V(LAST_MICROTASK_TYPE, 137) \ + V(FIRST_DATA_HANDLER_TYPE, 138) \ + V(FIRST_LOAD_HANDLER_TYPE, 138) \ + V(LOAD_HANDLER_TYPE, 138) \ + V(LAST_LOAD_HANDLER_TYPE, 138) \ + V(FIRST_STORE_HANDLER_TYPE, 139) \ + V(STORE_HANDLER_TYPE, 139) \ + V(LAST_STORE_HANDLER_TYPE, 139) \ + V(LAST_DATA_HANDLER_TYPE, 139) \ + V(FIRST_ACCESS_CHECK_INFO_TYPE, 140) \ + V(ACCESS_CHECK_INFO_TYPE, 140) \ + V(LAST_ACCESS_CHECK_INFO_TYPE, 140) \ + V(FIRST_ACCESSOR_PAIR_TYPE, 141) \ + V(ACCESSOR_PAIR_TYPE, 141) \ + V(LAST_ACCESSOR_PAIR_TYPE, 141) \ + V(FIRST_ALIASED_ARGUMENTS_ENTRY_TYPE, 142) \ + V(ALIASED_ARGUMENTS_ENTRY_TYPE, 142) \ + V(LAST_ALIASED_ARGUMENTS_ENTRY_TYPE, 142) \ + V(FIRST_ALLOCATION_MEMENTO_TYPE, 143) \ + V(ALLOCATION_MEMENTO_TYPE, 143) \ + V(LAST_ALLOCATION_MEMENTO_TYPE, 143) \ + V(FIRST_ARRAY_BOILERPLATE_DESCRIPTION_TYPE, 144) \ + V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE, 144) \ + V(LAST_ARRAY_BOILERPLATE_DESCRIPTION_TYPE, 144) \ + V(FIRST_ASYNC_GENERATOR_REQUEST_TYPE, 145) \ + V(ASYNC_GENERATOR_REQUEST_TYPE, 145) \ + V(LAST_ASYNC_GENERATOR_REQUEST_TYPE, 145) \ + V(FIRST_BREAK_POINT_TYPE, 146) \ + V(BREAK_POINT_TYPE, 146) \ + V(LAST_BREAK_POINT_TYPE, 146) \ + V(FIRST_BREAK_POINT_INFO_TYPE, 147) \ + V(BREAK_POINT_INFO_TYPE, 147) \ + V(LAST_BREAK_POINT_INFO_TYPE, 147) \ + V(FIRST_BYTECODE_WRAPPER_TYPE, 148) \ + V(BYTECODE_WRAPPER_TYPE, 148) \ + V(LAST_BYTECODE_WRAPPER_TYPE, 148) \ + V(FIRST_CALL_SITE_INFO_TYPE, 149) \ + V(CALL_SITE_INFO_TYPE, 149) \ + V(LAST_CALL_SITE_INFO_TYPE, 149) \ + V(FIRST_CLASS_BOILERPLATE_TYPE, 150) \ + V(CLASS_BOILERPLATE_TYPE, 150) \ + V(LAST_CLASS_BOILERPLATE_TYPE, 150) \ + V(FIRST_CLASS_POSITIONS_TYPE, 151) \ + V(CLASS_POSITIONS_TYPE, 151) \ + V(LAST_CLASS_POSITIONS_TYPE, 151) \ + V(FIRST_CODE_WRAPPER_TYPE, 152) \ + V(CODE_WRAPPER_TYPE, 152) \ + V(LAST_CODE_WRAPPER_TYPE, 152) \ + V(FIRST_DEBUG_SCRIPT_SCOPE_INFO_TYPE, 153) \ + V(DEBUG_SCRIPT_SCOPE_INFO_TYPE, 153) \ + V(LAST_DEBUG_SCRIPT_SCOPE_INFO_TYPE, 153) \ + V(FIRST_ENUM_CACHE_TYPE, 154) \ + V(ENUM_CACHE_TYPE, 154) \ + V(LAST_ENUM_CACHE_TYPE, 154) \ + V(FIRST_ERROR_STACK_DATA_TYPE, 155) \ + V(ERROR_STACK_DATA_TYPE, 155) \ + V(LAST_ERROR_STACK_DATA_TYPE, 155) \ + V(FIRST_FEEDBACK_CELL_TYPE, 156) \ + V(FEEDBACK_CELL_TYPE, 156) \ + V(LAST_FEEDBACK_CELL_TYPE, 156) \ + V(FIRST_FOR_IN_ENUMERATOR_HOLDER_TYPE, 157) \ + V(FOR_IN_ENUMERATOR_HOLDER_TYPE, 157) \ + V(LAST_FOR_IN_ENUMERATOR_HOLDER_TYPE, 157) \ + V(FIRST_FUNCTION_TEMPLATE_RARE_DATA_TYPE, 158) \ + V(FUNCTION_TEMPLATE_RARE_DATA_TYPE, 158) \ + V(LAST_FUNCTION_TEMPLATE_RARE_DATA_TYPE, 158) \ + V(FIRST_MODULE_REQUEST_TYPE, 159) \ + V(MODULE_REQUEST_TYPE, 159) \ + V(LAST_MODULE_REQUEST_TYPE, 159) \ + V(FIRST_PROMISE_CAPABILITY_TYPE, 160) \ + V(PROMISE_CAPABILITY_TYPE, 160) \ + V(LAST_PROMISE_CAPABILITY_TYPE, 160) \ + V(FIRST_PROMISE_REACTION_TYPE, 161) \ + V(PROMISE_REACTION_TYPE, 161) \ + V(LAST_PROMISE_REACTION_TYPE, 161) \ + V(FIRST_PROPERTY_DESCRIPTOR_OBJECT_TYPE, 162) \ + V(PROPERTY_DESCRIPTOR_OBJECT_TYPE, 162) \ + V(LAST_PROPERTY_DESCRIPTOR_OBJECT_TYPE, 162) \ + V(FIRST_PROTOTYPE_INFO_TYPE, 163) \ + V(PROTOTYPE_INFO_TYPE, 163) \ + V(LAST_PROTOTYPE_INFO_TYPE, 163) \ + V(FIRST_PROTOTYPE_SHARED_CLOSURE_INFO_TYPE, 164) \ + V(PROTOTYPE_SHARED_CLOSURE_INFO_TYPE, 164) \ + V(LAST_PROTOTYPE_SHARED_CLOSURE_INFO_TYPE, 164) \ + V(FIRST_REG_EXP_BOILERPLATE_DESCRIPTION_TYPE, 165) \ + V(REG_EXP_BOILERPLATE_DESCRIPTION_TYPE, 165) \ + V(LAST_REG_EXP_BOILERPLATE_DESCRIPTION_TYPE, 165) \ + V(FIRST_REG_EXP_DATA_WRAPPER_TYPE, 166) \ + V(REG_EXP_DATA_WRAPPER_TYPE, 166) \ + V(LAST_REG_EXP_DATA_WRAPPER_TYPE, 166) \ + V(FIRST_SCRIPT_TYPE, 167) \ + V(SCRIPT_TYPE, 167) \ + V(LAST_SCRIPT_TYPE, 167) \ + V(FIRST_SCRIPT_OR_MODULE_TYPE, 168) \ + V(SCRIPT_OR_MODULE_TYPE, 168) \ + V(LAST_SCRIPT_OR_MODULE_TYPE, 168) \ + V(FIRST_SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, 169) \ + V(SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, 169) \ + V(LAST_SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, 169) \ + V(FIRST_STACK_FRAME_INFO_TYPE, 170) \ + V(STACK_FRAME_INFO_TYPE, 170) \ + V(LAST_STACK_FRAME_INFO_TYPE, 170) \ + V(FIRST_STACK_TRACE_INFO_TYPE, 171) \ + V(STACK_TRACE_INFO_TYPE, 171) \ + V(LAST_STACK_TRACE_INFO_TYPE, 171) \ + V(FIRST_TEMPLATE_OBJECT_DESCRIPTION_TYPE, 172) \ + V(TEMPLATE_OBJECT_DESCRIPTION_TYPE, 172) \ + V(LAST_TEMPLATE_OBJECT_DESCRIPTION_TYPE, 172) \ + V(FIRST_TUPLE2_TYPE, 173) \ + V(TUPLE2_TYPE, 173) \ + V(LAST_TUPLE2_TYPE, 173) \ + V(FIRST_WASM_EXCEPTION_TAG_TYPE, 174) \ + V(WASM_EXCEPTION_TAG_TYPE, 174) \ + V(LAST_WASM_EXCEPTION_TAG_TYPE, 174) \ + V(LAST_STRUCT_TYPE, 174) \ + V(FIRST_TRUSTED_OBJECT_TYPE, 175) \ + V(FIRST_EXPOSED_TRUSTED_OBJECT_TYPE, 175) \ + V(FIRST_UNCOMPILED_DATA_TYPE, 175) \ + V(FIRST_UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE, 175) \ + V(UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE, 175) \ + V(FIRST_UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE, 176) \ + V(UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE, 176) \ + V(LAST_UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE, 176) \ + V(LAST_UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE, 176) \ + V(FIRST_UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE, 177) \ + V(UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE, 177) \ + V(FIRST_UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE, 178) \ + V(UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE, 178) \ + V(LAST_UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE, 178) \ + V(LAST_UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE, 178) \ + V(LAST_UNCOMPILED_DATA_TYPE, 178) \ + V(FIRST_REG_EXP_DATA_TYPE, 179) \ + V(REG_EXP_DATA_TYPE, 179) \ + V(FIRST_ATOM_REG_EXP_DATA_TYPE, 180) \ + V(ATOM_REG_EXP_DATA_TYPE, 180) \ + V(LAST_ATOM_REG_EXP_DATA_TYPE, 180) \ + V(FIRST_IR_REG_EXP_DATA_TYPE, 181) \ + V(IR_REG_EXP_DATA_TYPE, 181) \ + V(LAST_IR_REG_EXP_DATA_TYPE, 181) \ + V(LAST_REG_EXP_DATA_TYPE, 181) \ + V(FIRST_WASM_FUNCTION_DATA_TYPE, 182) \ + V(WASM_FUNCTION_DATA_TYPE, 182) \ + V(FIRST_WASM_CAPI_FUNCTION_DATA_TYPE, 183) \ + V(WASM_CAPI_FUNCTION_DATA_TYPE, 183) \ + V(LAST_WASM_CAPI_FUNCTION_DATA_TYPE, 183) \ + V(FIRST_WASM_EXPORTED_FUNCTION_DATA_TYPE, 184) \ + V(WASM_EXPORTED_FUNCTION_DATA_TYPE, 184) \ + V(LAST_WASM_EXPORTED_FUNCTION_DATA_TYPE, 184) \ + V(LAST_WASM_FUNCTION_DATA_TYPE, 184) \ + V(FIRST_BYTECODE_ARRAY_TYPE, 185) \ + V(BYTECODE_ARRAY_TYPE, 185) \ + V(LAST_BYTECODE_ARRAY_TYPE, 185) \ + V(FIRST_CODE_TYPE, 186) \ + V(CODE_TYPE, 186) \ + V(LAST_CODE_TYPE, 186) \ + V(FIRST_DEBUG_INFO_TYPE, 187) \ + V(DEBUG_INFO_TYPE, 187) \ + V(LAST_DEBUG_INFO_TYPE, 187) \ + V(FIRST_INTERPRETER_DATA_TYPE, 188) \ + V(INTERPRETER_DATA_TYPE, 188) \ + V(LAST_INTERPRETER_DATA_TYPE, 188) \ + V(FIRST_WASM_DISPATCH_TABLE_TYPE, 189) \ + V(WASM_DISPATCH_TABLE_TYPE, 189) \ + V(LAST_WASM_DISPATCH_TABLE_TYPE, 189) \ + V(FIRST_WASM_INTERNAL_FUNCTION_TYPE, 190) \ + V(WASM_INTERNAL_FUNCTION_TYPE, 190) \ + V(LAST_WASM_INTERNAL_FUNCTION_TYPE, 190) \ + V(FIRST_WASM_SUSPENDER_OBJECT_TYPE, 191) \ + V(WASM_SUSPENDER_OBJECT_TYPE, 191) \ + V(LAST_WASM_SUSPENDER_OBJECT_TYPE, 191) \ + V(FIRST_WASM_TRUSTED_INSTANCE_DATA_TYPE, 192) \ + V(WASM_TRUSTED_INSTANCE_DATA_TYPE, 192) \ + V(LAST_WASM_TRUSTED_INSTANCE_DATA_TYPE, 192) \ + V(LAST_EXPOSED_TRUSTED_OBJECT_TYPE, 192) \ + V(FIRST_TRUSTED_FIXED_ARRAY_BASE_TYPE, 193) \ + V(FIRST_PROTECTED_FIXED_ARRAY_TYPE, 193) \ + V(PROTECTED_FIXED_ARRAY_TYPE, 193) \ + V(LAST_PROTECTED_FIXED_ARRAY_TYPE, 193) \ + V(FIRST_PROTECTED_WEAK_FIXED_ARRAY_TYPE, 194) \ + V(PROTECTED_WEAK_FIXED_ARRAY_TYPE, 194) \ + V(LAST_PROTECTED_WEAK_FIXED_ARRAY_TYPE, 194) \ + V(FIRST_TRUSTED_BYTE_ARRAY_TYPE, 195) \ + V(TRUSTED_BYTE_ARRAY_TYPE, 195) \ + V(LAST_TRUSTED_BYTE_ARRAY_TYPE, 195) \ + V(FIRST_TRUSTED_FIXED_ARRAY_TYPE, 196) \ + V(TRUSTED_FIXED_ARRAY_TYPE, 196) \ + V(LAST_TRUSTED_FIXED_ARRAY_TYPE, 196) \ + V(FIRST_TRUSTED_WEAK_FIXED_ARRAY_TYPE, 197) \ + V(TRUSTED_WEAK_FIXED_ARRAY_TYPE, 197) \ + V(LAST_TRUSTED_WEAK_FIXED_ARRAY_TYPE, 197) \ + V(LAST_TRUSTED_FIXED_ARRAY_BASE_TYPE, 197) \ + V(FIRST_INSTRUCTION_STREAM_TYPE, 198) \ + V(INSTRUCTION_STREAM_TYPE, 198) \ + V(LAST_INSTRUCTION_STREAM_TYPE, 198) \ + V(FIRST_SHARED_FUNCTION_INFO_WRAPPER_TYPE, 199) \ + V(SHARED_FUNCTION_INFO_WRAPPER_TYPE, 199) \ + V(LAST_SHARED_FUNCTION_INFO_WRAPPER_TYPE, 199) \ + V(FIRST_TRUSTED_FOREIGN_TYPE, 200) \ + V(TRUSTED_FOREIGN_TYPE, 200) \ + V(LAST_TRUSTED_FOREIGN_TYPE, 200) \ + V(FIRST_WASM_DISPATCH_TABLE_FOR_IMPORTS_TYPE, 201) \ + V(WASM_DISPATCH_TABLE_FOR_IMPORTS_TYPE, 201) \ + V(LAST_WASM_DISPATCH_TABLE_FOR_IMPORTS_TYPE, 201) \ + V(FIRST_WASM_IMPORT_DATA_TYPE, 202) \ + V(WASM_IMPORT_DATA_TYPE, 202) \ + V(LAST_WASM_IMPORT_DATA_TYPE, 202) \ + V(LAST_TRUSTED_OBJECT_TYPE, 202) \ + V(FIRST_ACCESSOR_INFO_TYPE, 203) \ + V(ACCESSOR_INFO_TYPE, 203) \ + V(LAST_ACCESSOR_INFO_TYPE, 203) \ + V(FIRST_FOREIGN_TYPE, 204) \ + V(FOREIGN_TYPE, 204) \ + V(LAST_FOREIGN_TYPE, 204) \ + V(FIRST_FIXED_ARRAY_BASE_TYPE, 205) \ + V(FIRST_FIXED_ARRAY_TYPE, 205) \ + V(FIXED_ARRAY_TYPE, 205) \ + V(FIRST_HASH_TABLE_TYPE, 206) \ + V(HASH_TABLE_TYPE, 206) \ + V(FIRST_EPHEMERON_HASH_TABLE_TYPE, 207) \ + V(EPHEMERON_HASH_TABLE_TYPE, 207) \ + V(LAST_EPHEMERON_HASH_TABLE_TYPE, 207) \ + V(FIRST_GLOBAL_DICTIONARY_TYPE, 208) \ + V(GLOBAL_DICTIONARY_TYPE, 208) \ + V(LAST_GLOBAL_DICTIONARY_TYPE, 208) \ + V(FIRST_NAME_DICTIONARY_TYPE, 209) \ + V(NAME_DICTIONARY_TYPE, 209) \ + V(LAST_NAME_DICTIONARY_TYPE, 209) \ + V(FIRST_NAME_TO_INDEX_HASH_TABLE_TYPE, 210) \ + V(NAME_TO_INDEX_HASH_TABLE_TYPE, 210) \ + V(LAST_NAME_TO_INDEX_HASH_TABLE_TYPE, 210) \ + V(FIRST_NUMBER_DICTIONARY_TYPE, 211) \ + V(NUMBER_DICTIONARY_TYPE, 211) \ + V(LAST_NUMBER_DICTIONARY_TYPE, 211) \ + V(FIRST_REGISTERED_SYMBOL_TABLE_TYPE, 212) \ + V(REGISTERED_SYMBOL_TABLE_TYPE, 212) \ + V(LAST_REGISTERED_SYMBOL_TABLE_TYPE, 212) \ + V(FIRST_SIMPLE_NAME_DICTIONARY_TYPE, 213) \ + V(SIMPLE_NAME_DICTIONARY_TYPE, 213) \ + V(LAST_SIMPLE_NAME_DICTIONARY_TYPE, 213) \ + V(FIRST_SIMPLE_NUMBER_DICTIONARY_TYPE, 214) \ + V(SIMPLE_NUMBER_DICTIONARY_TYPE, 214) \ + V(LAST_SIMPLE_NUMBER_DICTIONARY_TYPE, 214) \ + V(LAST_HASH_TABLE_TYPE, 214) \ + V(FIRST_ORDERED_HASH_MAP_TYPE, 215) \ + V(ORDERED_HASH_MAP_TYPE, 215) \ + V(LAST_ORDERED_HASH_MAP_TYPE, 215) \ + V(FIRST_ORDERED_HASH_SET_TYPE, 216) \ + V(ORDERED_HASH_SET_TYPE, 216) \ + V(LAST_ORDERED_HASH_SET_TYPE, 216) \ + V(FIRST_ORDERED_NAME_DICTIONARY_TYPE, 217) \ + V(ORDERED_NAME_DICTIONARY_TYPE, 217) \ + V(LAST_ORDERED_NAME_DICTIONARY_TYPE, 217) \ + V(LAST_FIXED_ARRAY_TYPE, 217) \ + V(FIRST_WEAK_FIXED_ARRAY_TYPE, 218) \ + V(WEAK_FIXED_ARRAY_TYPE, 218) \ + V(FIRST_TRANSITION_ARRAY_TYPE, 219) \ + V(TRANSITION_ARRAY_TYPE, 219) \ + V(LAST_TRANSITION_ARRAY_TYPE, 219) \ + V(LAST_WEAK_FIXED_ARRAY_TYPE, 219) \ + V(FIRST_BYTE_ARRAY_TYPE, 220) \ + V(BYTE_ARRAY_TYPE, 220) \ + V(LAST_BYTE_ARRAY_TYPE, 220) \ + V(FIRST_CLOSURE_FEEDBACK_CELL_ARRAY_TYPE, 221) \ + V(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE, 221) \ + V(LAST_CLOSURE_FEEDBACK_CELL_ARRAY_TYPE, 221) \ + V(FIRST_FIXED_DOUBLE_ARRAY_TYPE, 222) \ + V(FIXED_DOUBLE_ARRAY_TYPE, 222) \ + V(LAST_FIXED_DOUBLE_ARRAY_TYPE, 222) \ + V(FIRST_OBJECT_BOILERPLATE_DESCRIPTION_TYPE, 223) \ + V(OBJECT_BOILERPLATE_DESCRIPTION_TYPE, 223) \ + V(LAST_OBJECT_BOILERPLATE_DESCRIPTION_TYPE, 223) \ + V(FIRST_REG_EXP_MATCH_INFO_TYPE, 224) \ + V(REG_EXP_MATCH_INFO_TYPE, 224) \ + V(LAST_REG_EXP_MATCH_INFO_TYPE, 224) \ + V(FIRST_SLOPPY_ARGUMENTS_ELEMENTS_TYPE, 225) \ + V(SLOPPY_ARGUMENTS_ELEMENTS_TYPE, 225) \ + V(LAST_SLOPPY_ARGUMENTS_ELEMENTS_TYPE, 225) \ + V(FIRST_WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE, 226) \ + V(WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE, 226) \ + V(LAST_WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE, 226) \ + V(LAST_FIXED_ARRAY_BASE_TYPE, 226) \ + V(FIRST_CONTEXT_TYPE, 227) \ + V(FIRST_AWAIT_CONTEXT_TYPE, 227) \ + V(AWAIT_CONTEXT_TYPE, 227) \ + V(LAST_AWAIT_CONTEXT_TYPE, 227) \ + V(FIRST_BLOCK_CONTEXT_TYPE, 228) \ + V(BLOCK_CONTEXT_TYPE, 228) \ + V(LAST_BLOCK_CONTEXT_TYPE, 228) \ + V(FIRST_CATCH_CONTEXT_TYPE, 229) \ + V(CATCH_CONTEXT_TYPE, 229) \ + V(LAST_CATCH_CONTEXT_TYPE, 229) \ + V(FIRST_DEBUG_EVALUATE_CONTEXT_TYPE, 230) \ + V(DEBUG_EVALUATE_CONTEXT_TYPE, 230) \ + V(LAST_DEBUG_EVALUATE_CONTEXT_TYPE, 230) \ + V(FIRST_EVAL_CONTEXT_TYPE, 231) \ + V(EVAL_CONTEXT_TYPE, 231) \ + V(LAST_EVAL_CONTEXT_TYPE, 231) \ + V(FIRST_FUNCTION_CONTEXT_TYPE, 232) \ + V(FUNCTION_CONTEXT_TYPE, 232) \ + V(LAST_FUNCTION_CONTEXT_TYPE, 232) \ + V(FIRST_MODULE_CONTEXT_TYPE, 233) \ + V(MODULE_CONTEXT_TYPE, 233) \ + V(LAST_MODULE_CONTEXT_TYPE, 233) \ + V(FIRST_NATIVE_CONTEXT_TYPE, 234) \ + V(NATIVE_CONTEXT_TYPE, 234) \ + V(LAST_NATIVE_CONTEXT_TYPE, 234) \ + V(FIRST_SCRIPT_CONTEXT_TYPE, 235) \ + V(SCRIPT_CONTEXT_TYPE, 235) \ + V(LAST_SCRIPT_CONTEXT_TYPE, 235) \ + V(FIRST_WITH_CONTEXT_TYPE, 236) \ + V(WITH_CONTEXT_TYPE, 236) \ + V(LAST_WITH_CONTEXT_TYPE, 236) \ + V(LAST_CONTEXT_TYPE, 236) \ + V(FIRST_TURBOSHAFT_TYPE_TYPE, 237) \ + V(FIRST_TURBOSHAFT_FLOAT64_TYPE_TYPE, 237) \ + V(FIRST_TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE, 237) \ + V(TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE, 237) \ + V(LAST_TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE, 237) \ + V(FIRST_TURBOSHAFT_FLOAT64_SET_TYPE_TYPE, 238) \ + V(TURBOSHAFT_FLOAT64_SET_TYPE_TYPE, 238) \ + V(LAST_TURBOSHAFT_FLOAT64_SET_TYPE_TYPE, 238) \ + V(LAST_TURBOSHAFT_FLOAT64_TYPE_TYPE, 238) \ + V(FIRST_TURBOSHAFT_WORD32_TYPE_TYPE, 239) \ + V(FIRST_TURBOSHAFT_WORD32_RANGE_TYPE_TYPE, 239) \ + V(TURBOSHAFT_WORD32_RANGE_TYPE_TYPE, 239) \ + V(LAST_TURBOSHAFT_WORD32_RANGE_TYPE_TYPE, 239) \ + V(FIRST_TURBOSHAFT_WORD32_SET_TYPE_TYPE, 240) \ + V(TURBOSHAFT_WORD32_SET_TYPE_TYPE, 240) \ + V(LAST_TURBOSHAFT_WORD32_SET_TYPE_TYPE, 240) \ + V(LAST_TURBOSHAFT_WORD32_TYPE_TYPE, 240) \ + V(FIRST_TURBOSHAFT_WORD64_TYPE_TYPE, 241) \ + V(FIRST_TURBOSHAFT_WORD64_RANGE_TYPE_TYPE, 241) \ + V(TURBOSHAFT_WORD64_RANGE_TYPE_TYPE, 241) \ + V(LAST_TURBOSHAFT_WORD64_RANGE_TYPE_TYPE, 241) \ + V(FIRST_TURBOSHAFT_WORD64_SET_TYPE_TYPE, 242) \ + V(TURBOSHAFT_WORD64_SET_TYPE_TYPE, 242) \ + V(LAST_TURBOSHAFT_WORD64_SET_TYPE_TYPE, 242) \ + V(LAST_TURBOSHAFT_WORD64_TYPE_TYPE, 242) \ + V(LAST_TURBOSHAFT_TYPE_TYPE, 242) \ + V(FIRST_TURBOFAN_TYPE_TYPE, 243) \ + V(FIRST_TURBOFAN_BITSET_TYPE_TYPE, 243) \ + V(TURBOFAN_BITSET_TYPE_TYPE, 243) \ + V(LAST_TURBOFAN_BITSET_TYPE_TYPE, 243) \ + V(FIRST_TURBOFAN_HEAP_CONSTANT_TYPE_TYPE, 244) \ + V(TURBOFAN_HEAP_CONSTANT_TYPE_TYPE, 244) \ + V(LAST_TURBOFAN_HEAP_CONSTANT_TYPE_TYPE, 244) \ + V(FIRST_TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE, 245) \ + V(TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE, 245) \ + V(LAST_TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE, 245) \ + V(FIRST_TURBOFAN_RANGE_TYPE_TYPE, 246) \ + V(TURBOFAN_RANGE_TYPE_TYPE, 246) \ + V(LAST_TURBOFAN_RANGE_TYPE_TYPE, 246) \ + V(FIRST_TURBOFAN_UNION_TYPE_TYPE, 247) \ + V(TURBOFAN_UNION_TYPE_TYPE, 247) \ + V(LAST_TURBOFAN_UNION_TYPE_TYPE, 247) \ + V(LAST_TURBOFAN_TYPE_TYPE, 247) \ + V(FIRST_SMALL_ORDERED_HASH_TABLE_TYPE, 248) \ + V(FIRST_SMALL_ORDERED_HASH_MAP_TYPE, 248) \ + V(SMALL_ORDERED_HASH_MAP_TYPE, 248) \ + V(LAST_SMALL_ORDERED_HASH_MAP_TYPE, 248) \ + V(FIRST_SMALL_ORDERED_HASH_SET_TYPE, 249) \ + V(SMALL_ORDERED_HASH_SET_TYPE, 249) \ + V(LAST_SMALL_ORDERED_HASH_SET_TYPE, 249) \ + V(FIRST_SMALL_ORDERED_NAME_DICTIONARY_TYPE, 250) \ + V(SMALL_ORDERED_NAME_DICTIONARY_TYPE, 250) \ + V(LAST_SMALL_ORDERED_NAME_DICTIONARY_TYPE, 250) \ + V(LAST_SMALL_ORDERED_HASH_TABLE_TYPE, 250) \ + V(FIRST_TEMPLATE_INFO_TYPE, 251) \ + V(FIRST_TEMPLATE_INFO_WITH_PROPERTIES_TYPE, 251) \ + V(FIRST_FUNCTION_TEMPLATE_INFO_TYPE, 251) \ + V(FUNCTION_TEMPLATE_INFO_TYPE, 251) \ + V(LAST_FUNCTION_TEMPLATE_INFO_TYPE, 251) \ + V(FIRST_OBJECT_TEMPLATE_INFO_TYPE, 252) \ + V(OBJECT_TEMPLATE_INFO_TYPE, 252) \ + V(LAST_OBJECT_TEMPLATE_INFO_TYPE, 252) \ + V(LAST_TEMPLATE_INFO_WITH_PROPERTIES_TYPE, 252) \ + V(FIRST_DICTIONARY_TEMPLATE_INFO_TYPE, 253) \ + V(DICTIONARY_TEMPLATE_INFO_TYPE, 253) \ + V(LAST_DICTIONARY_TEMPLATE_INFO_TYPE, 253) \ + V(LAST_TEMPLATE_INFO_TYPE, 253) \ + V(FIRST_MAP_TYPE, 254) \ + V(MAP_TYPE, 254) \ + V(FIRST_WASM_CUSTOM_MAP_TYPE, 255) \ + V(WASM_CUSTOM_MAP_TYPE, 255) \ + V(LAST_WASM_CUSTOM_MAP_TYPE, 255) \ + V(LAST_MAP_TYPE, 255) \ + V(FIRST_MODULE_TYPE, 256) \ + V(FIRST_SOURCE_TEXT_MODULE_TYPE, 256) \ + V(SOURCE_TEXT_MODULE_TYPE, 256) \ + V(LAST_SOURCE_TEXT_MODULE_TYPE, 256) \ + V(FIRST_SYNTHETIC_MODULE_TYPE, 257) \ + V(SYNTHETIC_MODULE_TYPE, 257) \ + V(LAST_SYNTHETIC_MODULE_TYPE, 257) \ + V(LAST_MODULE_TYPE, 257) \ + V(FIRST_ALLOCATION_SITE_TYPE, 258) \ + V(ALLOCATION_SITE_TYPE, 258) \ + V(LAST_ALLOCATION_SITE_TYPE, 258) \ + V(FIRST_ARRAY_LIST_TYPE, 259) \ + V(ARRAY_LIST_TYPE, 259) \ + V(LAST_ARRAY_LIST_TYPE, 259) \ + V(FIRST_CELL_TYPE, 260) \ + V(CELL_TYPE, 260) \ + V(LAST_CELL_TYPE, 260) \ + V(FIRST_CONTEXT_CELL_TYPE, 261) \ + V(CONTEXT_CELL_TYPE, 261) \ + V(LAST_CONTEXT_CELL_TYPE, 261) \ + V(FIRST_COVERAGE_INFO_TYPE, 262) \ + V(COVERAGE_INFO_TYPE, 262) \ + V(LAST_COVERAGE_INFO_TYPE, 262) \ + V(FIRST_CPP_GCMANAGED_BASE_TYPE, 263) \ + V(CPP_GCMANAGED_BASE_TYPE, 263) \ + V(LAST_CPP_GCMANAGED_BASE_TYPE, 263) \ + V(FIRST_CPP_HEAP_EXTERNAL_OBJECT_TYPE, 264) \ + V(CPP_HEAP_EXTERNAL_OBJECT_TYPE, 264) \ + V(LAST_CPP_HEAP_EXTERNAL_OBJECT_TYPE, 264) \ + V(FIRST_DESCRIPTOR_ARRAY_TYPE, 265) \ + V(DESCRIPTOR_ARRAY_TYPE, 265) \ + V(LAST_DESCRIPTOR_ARRAY_TYPE, 265) \ + V(FIRST_DOUBLE_STRING_CACHE_TYPE, 266) \ + V(DOUBLE_STRING_CACHE_TYPE, 266) \ + V(LAST_DOUBLE_STRING_CACHE_TYPE, 266) \ + V(FIRST_EMBEDDER_DATA_ARRAY_TYPE, 267) \ + V(EMBEDDER_DATA_ARRAY_TYPE, 267) \ + V(LAST_EMBEDDER_DATA_ARRAY_TYPE, 267) \ + V(FIRST_FEEDBACK_METADATA_TYPE, 268) \ + V(FEEDBACK_METADATA_TYPE, 268) \ + V(LAST_FEEDBACK_METADATA_TYPE, 268) \ + V(FIRST_FEEDBACK_VECTOR_TYPE, 269) \ + V(FEEDBACK_VECTOR_TYPE, 269) \ + V(LAST_FEEDBACK_VECTOR_TYPE, 269) \ + V(FIRST_FILLER_TYPE, 270) \ + V(FILLER_TYPE, 270) \ + V(LAST_FILLER_TYPE, 270) \ + V(FIRST_FREE_SPACE_TYPE, 271) \ + V(FREE_SPACE_TYPE, 271) \ + V(LAST_FREE_SPACE_TYPE, 271) \ + V(FIRST_HASH_SEED_WRAPPER_TYPE, 272) \ + V(HASH_SEED_WRAPPER_TYPE, 272) \ + V(LAST_HASH_SEED_WRAPPER_TYPE, 272) \ + V(FIRST_HOLE_TYPE, 273) \ + V(HOLE_TYPE, 273) \ + V(LAST_HOLE_TYPE, 273) \ + V(FIRST_INTERCEPTOR_INFO_TYPE, 274) \ + V(INTERCEPTOR_INFO_TYPE, 274) \ + V(LAST_INTERCEPTOR_INFO_TYPE, 274) \ + V(FIRST_MEGA_DOM_HANDLER_TYPE, 275) \ + V(MEGA_DOM_HANDLER_TYPE, 275) \ + V(LAST_MEGA_DOM_HANDLER_TYPE, 275) \ + V(FIRST_ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE, 276) \ + V(ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE, 276) \ + V(LAST_ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE, 276) \ + V(FIRST_PREPARSE_DATA_TYPE, 277) \ + V(PREPARSE_DATA_TYPE, 277) \ + V(LAST_PREPARSE_DATA_TYPE, 277) \ + V(FIRST_PROPERTY_ARRAY_TYPE, 278) \ + V(PROPERTY_ARRAY_TYPE, 278) \ + V(LAST_PROPERTY_ARRAY_TYPE, 278) \ + V(FIRST_PROPERTY_CELL_TYPE, 279) \ + V(PROPERTY_CELL_TYPE, 279) \ + V(LAST_PROPERTY_CELL_TYPE, 279) \ + V(FIRST_SCOPE_INFO_TYPE, 280) \ + V(SCOPE_INFO_TYPE, 280) \ + V(LAST_SCOPE_INFO_TYPE, 280) \ + V(FIRST_SCRIPT_CONTEXT_TABLE_TYPE, 281) \ + V(SCRIPT_CONTEXT_TABLE_TYPE, 281) \ + V(LAST_SCRIPT_CONTEXT_TABLE_TYPE, 281) \ + V(FIRST_SHARED_FUNCTION_INFO_TYPE, 282) \ + V(SHARED_FUNCTION_INFO_TYPE, 282) \ + V(LAST_SHARED_FUNCTION_INFO_TYPE, 282) \ + V(FIRST_SORT_STATE_TYPE, 283) \ + V(SORT_STATE_TYPE, 283) \ + V(LAST_SORT_STATE_TYPE, 283) \ + V(FIRST_SWISS_NAME_DICTIONARY_TYPE, 284) \ + V(SWISS_NAME_DICTIONARY_TYPE, 284) \ + V(LAST_SWISS_NAME_DICTIONARY_TYPE, 284) \ + V(FIRST_UNINITIALIZED_HEAP_NUMBER_TYPE, 285) \ + V(UNINITIALIZED_HEAP_NUMBER_TYPE, 285) \ + V(LAST_UNINITIALIZED_HEAP_NUMBER_TYPE, 285) \ + V(FIRST_WASM_CONTINUATION_OBJECT_TYPE, 286) \ + V(WASM_CONTINUATION_OBJECT_TYPE, 286) \ + V(LAST_WASM_CONTINUATION_OBJECT_TYPE, 286) \ + V(FIRST_WASM_FAST_API_CALL_DATA_TYPE, 287) \ + V(WASM_FAST_API_CALL_DATA_TYPE, 287) \ + V(LAST_WASM_FAST_API_CALL_DATA_TYPE, 287) \ + V(FIRST_WASM_FUNC_REF_TYPE, 288) \ + V(WASM_FUNC_REF_TYPE, 288) \ + V(LAST_WASM_FUNC_REF_TYPE, 288) \ + V(FIRST_WASM_NULL_TYPE, 289) \ + V(WASM_NULL_TYPE, 289) \ + V(LAST_WASM_NULL_TYPE, 289) \ + V(FIRST_WASM_RESUME_DATA_TYPE, 290) \ + V(WASM_RESUME_DATA_TYPE, 290) \ + V(LAST_WASM_RESUME_DATA_TYPE, 290) \ + V(FIRST_WASM_STACK_OBJECT_TYPE, 291) \ + V(WASM_STACK_OBJECT_TYPE, 291) \ + V(LAST_WASM_STACK_OBJECT_TYPE, 291) \ + V(FIRST_WASM_STRING_VIEW_ITER_TYPE, 292) \ + V(WASM_STRING_VIEW_ITER_TYPE, 292) \ + V(LAST_WASM_STRING_VIEW_ITER_TYPE, 292) \ + V(FIRST_WASM_TYPE_INFO_TYPE, 293) \ + V(WASM_TYPE_INFO_TYPE, 293) \ + V(LAST_WASM_TYPE_INFO_TYPE, 293) \ + V(FIRST_WEAK_ARRAY_LIST_TYPE, 294) \ + V(WEAK_ARRAY_LIST_TYPE, 294) \ + V(LAST_WEAK_ARRAY_LIST_TYPE, 294) \ + V(FIRST_WEAK_CELL_TYPE, 295) \ + V(WEAK_CELL_TYPE, 295) \ + V(LAST_WEAK_CELL_TYPE, 295) \ + V(FIRST_JS_RECEIVER_TYPE, 296) \ + V(FIRST_WASM_OBJECT_TYPE, 296) \ + V(FIRST_WASM_ARRAY_TYPE, 296) \ + V(WASM_ARRAY_TYPE, 296) \ + V(LAST_WASM_ARRAY_TYPE, 296) \ + V(FIRST_WASM_STRUCT_TYPE, 297) \ + V(WASM_STRUCT_TYPE, 297) \ + V(LAST_WASM_STRUCT_TYPE, 297) \ + V(LAST_WASM_OBJECT_TYPE, 297) \ + V(FIRST_JS_PROXY_TYPE, 298) \ + V(JS_PROXY_TYPE, 298) \ + V(LAST_JS_PROXY_TYPE, 298) \ + V(FIRST_JS_OBJECT_TYPE, 299) \ + V(JS_OBJECT_TYPE, 1057) \ + V(FIRST_JS_CUSTOM_ELEMENTS_OBJECT_TYPE, 299) \ + V(FIRST_JS_SPECIAL_OBJECT_TYPE, 299) \ + V(FIRST_JS_MODULE_NAMESPACE_TYPE, 299) \ + V(JS_MODULE_NAMESPACE_TYPE, 299) \ + V(FIRST_JS_DEFERRED_MODULE_NAMESPACE_TYPE, 300) \ + V(JS_DEFERRED_MODULE_NAMESPACE_TYPE, 300) \ + V(LAST_JS_DEFERRED_MODULE_NAMESPACE_TYPE, 300) \ + V(LAST_JS_MODULE_NAMESPACE_TYPE, 300) \ + V(FIRST_JS_GLOBAL_OBJECT_TYPE, 301) \ + V(JS_GLOBAL_OBJECT_TYPE, 301) \ + V(LAST_JS_GLOBAL_OBJECT_TYPE, 301) \ + V(FIRST_JS_GLOBAL_PROXY_TYPE, 302) \ + V(JS_GLOBAL_PROXY_TYPE, 302) \ + V(LAST_JS_GLOBAL_PROXY_TYPE, 302) \ + V(FIRST_JS_SPECIAL_API_OBJECT_TYPE, 1040) \ + V(JS_SPECIAL_API_OBJECT_TYPE, 1040) \ + V(LAST_JS_SPECIAL_API_OBJECT_TYPE, 1040) \ + V(LAST_JS_SPECIAL_OBJECT_TYPE, 1040) \ + V(FIRST_JS_PRIMITIVE_WRAPPER_TYPE, 1041) \ + V(JS_PRIMITIVE_WRAPPER_TYPE, 1041) \ + V(LAST_JS_PRIMITIVE_WRAPPER_TYPE, 1041) \ + V(LAST_JS_CUSTOM_ELEMENTS_OBJECT_TYPE, 1041) \ + V(FIRST_JS_APIOBJECT_WITH_EMBEDDER_SLOTS_TYPE, 1058) \ + V(FIRST_JS_API_OBJECT_TYPE, 1058) \ + V(JS_API_OBJECT_TYPE, 1058) \ + V(FIRST_JS_LAST_DUMMY_API_OBJECT_TYPE, 2058) \ + V(JS_LAST_DUMMY_API_OBJECT_TYPE, 2058) \ + V(LAST_JS_LAST_DUMMY_API_OBJECT_TYPE, 2058) \ + V(LAST_JS_API_OBJECT_TYPE, 2058) \ + V(FIRST_JS_ARRAY_BUFFER_VIEW_TYPE, 2059) \ + V(FIRST_JS_DATA_VIEW_OR_RAB_GSAB_DATA_VIEW_TYPE, 2059) \ + V(FIRST_JS_DATA_VIEW_TYPE, 2059) \ + V(JS_DATA_VIEW_TYPE, 2059) \ + V(LAST_JS_DATA_VIEW_TYPE, 2059) \ + V(FIRST_JS_RAB_GSAB_DATA_VIEW_TYPE, 2060) \ + V(JS_RAB_GSAB_DATA_VIEW_TYPE, 2060) \ + V(LAST_JS_RAB_GSAB_DATA_VIEW_TYPE, 2060) \ + V(LAST_JS_DATA_VIEW_OR_RAB_GSAB_DATA_VIEW_TYPE, 2060) \ + V(FIRST_JS_TYPED_ARRAY_TYPE, 2061) \ + V(JS_TYPED_ARRAY_TYPE, 2061) \ + V(FIRST_JS_DETACHED_TYPED_ARRAY_TYPE, 2062) \ + V(JS_DETACHED_TYPED_ARRAY_TYPE, 2062) \ + V(LAST_JS_DETACHED_TYPED_ARRAY_TYPE, 2062) \ + V(LAST_JS_TYPED_ARRAY_TYPE, 2062) \ + V(LAST_JS_ARRAY_BUFFER_VIEW_TYPE, 2062) \ + V(FIRST_JS_ARRAY_BUFFER_TYPE, 2063) \ + V(JS_ARRAY_BUFFER_TYPE, 2063) \ + V(LAST_JS_ARRAY_BUFFER_TYPE, 2063) \ + V(LAST_JS_APIOBJECT_WITH_EMBEDDER_SLOTS_TYPE, 2063) \ + V(FIRST_JS_FUNCTION_OR_BOUND_FUNCTION_OR_WRAPPED_FUNCTION_TYPE, 2064) \ + V(FIRST_JS_FUNCTION_TYPE, 2064) \ + V(FIRST_JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE, 2064) \ + V(JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE, 2064) \ + V(LAST_JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE, 2064) \ + V(FIRST_JS_FUNCTION_WITH_PROTOTYPE_TYPE, 2065) \ + V(JS_FUNCTION_WITH_PROTOTYPE_TYPE, 2065) \ + V(FIRST_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2066) \ + V(FIRST_BIGINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2066) \ + V(BIGINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2066) \ + V(LAST_BIGINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2066) \ + V(FIRST_BIGUINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2067) \ + V(BIGUINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2067) \ + V(LAST_BIGUINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2067) \ + V(FIRST_FLOAT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2068) \ + V(FLOAT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2068) \ + V(LAST_FLOAT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2068) \ + V(FIRST_FLOAT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2069) \ + V(FLOAT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2069) \ + V(LAST_FLOAT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2069) \ + V(FIRST_FLOAT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2070) \ + V(FLOAT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2070) \ + V(LAST_FLOAT64_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2070) \ + V(FIRST_INT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2071) \ + V(INT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2071) \ + V(LAST_INT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2071) \ + V(FIRST_INT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2072) \ + V(INT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2072) \ + V(LAST_INT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2072) \ + V(FIRST_INT8_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2073) \ + V(INT8_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2073) \ + V(LAST_INT8_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2073) \ + V(FIRST_UINT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2074) \ + V(UINT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2074) \ + V(LAST_UINT16_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2074) \ + V(FIRST_UINT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2075) \ + V(UINT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2075) \ + V(LAST_UINT32_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2075) \ + V(FIRST_UINT8_CLAMPED_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2076) \ + V(UINT8_CLAMPED_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2076) \ + V(LAST_UINT8_CLAMPED_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2076) \ + V(FIRST_UINT8_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2077) \ + V(UINT8_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2077) \ + V(LAST_UINT8_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2077) \ + V(LAST_TYPED_ARRAY_CONSTRUCTOR_TYPE, 2077) \ + V(FIRST_JS_ARRAY_CONSTRUCTOR_TYPE, 2078) \ + V(JS_ARRAY_CONSTRUCTOR_TYPE, 2078) \ + V(LAST_JS_ARRAY_CONSTRUCTOR_TYPE, 2078) \ + V(FIRST_JS_PROMISE_CONSTRUCTOR_TYPE, 2079) \ + V(JS_PROMISE_CONSTRUCTOR_TYPE, 2079) \ + V(LAST_JS_PROMISE_CONSTRUCTOR_TYPE, 2079) \ + V(FIRST_JS_REG_EXP_CONSTRUCTOR_TYPE, 2080) \ + V(JS_REG_EXP_CONSTRUCTOR_TYPE, 2080) \ + V(LAST_JS_REG_EXP_CONSTRUCTOR_TYPE, 2080) \ + V(FIRST_JS_CLASS_CONSTRUCTOR_TYPE, 2081) \ + V(JS_CLASS_CONSTRUCTOR_TYPE, 2081) \ + V(LAST_JS_CLASS_CONSTRUCTOR_TYPE, 2081) \ + V(LAST_JS_FUNCTION_WITH_PROTOTYPE_TYPE, 2081) \ + V(LAST_JS_FUNCTION_TYPE, 2081) \ + V(FIRST_JS_BOUND_FUNCTION_TYPE, 2082) \ + V(JS_BOUND_FUNCTION_TYPE, 2082) \ + V(LAST_JS_BOUND_FUNCTION_TYPE, 2082) \ + V(FIRST_JS_WRAPPED_FUNCTION_TYPE, 2083) \ + V(JS_WRAPPED_FUNCTION_TYPE, 2083) \ + V(LAST_JS_WRAPPED_FUNCTION_TYPE, 2083) \ + V(LAST_JS_FUNCTION_OR_BOUND_FUNCTION_OR_WRAPPED_FUNCTION_TYPE, 2083) \ + V(FIRST_JS_INTERNAL_PROTOTYPE_BASE_TYPE, 2084) \ + V(FIRST_JS_ARRAY_ITERATOR_PROTOTYPE_TYPE, 2084) \ + V(JS_ARRAY_ITERATOR_PROTOTYPE_TYPE, 2084) \ + V(LAST_JS_ARRAY_ITERATOR_PROTOTYPE_TYPE, 2084) \ + V(FIRST_JS_ITERATOR_PROTOTYPE_TYPE, 2085) \ + V(JS_ITERATOR_PROTOTYPE_TYPE, 2085) \ + V(LAST_JS_ITERATOR_PROTOTYPE_TYPE, 2085) \ + V(FIRST_JS_MAP_ITERATOR_PROTOTYPE_TYPE, 2086) \ + V(JS_MAP_ITERATOR_PROTOTYPE_TYPE, 2086) \ + V(LAST_JS_MAP_ITERATOR_PROTOTYPE_TYPE, 2086) \ + V(FIRST_JS_OBJECT_PROTOTYPE_TYPE, 2087) \ + V(JS_OBJECT_PROTOTYPE_TYPE, 2087) \ + V(LAST_JS_OBJECT_PROTOTYPE_TYPE, 2087) \ + V(FIRST_JS_PROMISE_PROTOTYPE_TYPE, 2088) \ + V(JS_PROMISE_PROTOTYPE_TYPE, 2088) \ + V(LAST_JS_PROMISE_PROTOTYPE_TYPE, 2088) \ + V(FIRST_JS_REG_EXP_PROTOTYPE_TYPE, 2089) \ + V(JS_REG_EXP_PROTOTYPE_TYPE, 2089) \ + V(LAST_JS_REG_EXP_PROTOTYPE_TYPE, 2089) \ + V(FIRST_JS_SET_ITERATOR_PROTOTYPE_TYPE, 2090) \ + V(JS_SET_ITERATOR_PROTOTYPE_TYPE, 2090) \ + V(LAST_JS_SET_ITERATOR_PROTOTYPE_TYPE, 2090) \ + V(FIRST_JS_SET_PROTOTYPE_TYPE, 2091) \ + V(JS_SET_PROTOTYPE_TYPE, 2091) \ + V(LAST_JS_SET_PROTOTYPE_TYPE, 2091) \ + V(FIRST_JS_STRING_ITERATOR_PROTOTYPE_TYPE, 2092) \ + V(JS_STRING_ITERATOR_PROTOTYPE_TYPE, 2092) \ + V(LAST_JS_STRING_ITERATOR_PROTOTYPE_TYPE, 2092) \ + V(FIRST_JS_TYPED_ARRAY_PROTOTYPE_TYPE, 2093) \ + V(JS_TYPED_ARRAY_PROTOTYPE_TYPE, 2093) \ + V(LAST_JS_TYPED_ARRAY_PROTOTYPE_TYPE, 2093) \ + V(LAST_JS_INTERNAL_PROTOTYPE_BASE_TYPE, 2093) \ + V(FIRST_JS_ITERATOR_HELPER_TYPE, 2094) \ + V(FIRST_JS_ITERATOR_HELPER_SIMPLE_TYPE, 2094) \ + V(FIRST_JS_ITERATOR_CONCAT_HELPER_TYPE, 2094) \ + V(JS_ITERATOR_CONCAT_HELPER_TYPE, 2094) \ + V(LAST_JS_ITERATOR_CONCAT_HELPER_TYPE, 2094) \ + V(FIRST_JS_ITERATOR_DROP_HELPER_TYPE, 2095) \ + V(JS_ITERATOR_DROP_HELPER_TYPE, 2095) \ + V(LAST_JS_ITERATOR_DROP_HELPER_TYPE, 2095) \ + V(FIRST_JS_ITERATOR_FILTER_HELPER_TYPE, 2096) \ + V(JS_ITERATOR_FILTER_HELPER_TYPE, 2096) \ + V(LAST_JS_ITERATOR_FILTER_HELPER_TYPE, 2096) \ + V(FIRST_JS_ITERATOR_FLAT_MAP_HELPER_TYPE, 2097) \ + V(JS_ITERATOR_FLAT_MAP_HELPER_TYPE, 2097) \ + V(LAST_JS_ITERATOR_FLAT_MAP_HELPER_TYPE, 2097) \ + V(FIRST_JS_ITERATOR_MAP_HELPER_TYPE, 2098) \ + V(JS_ITERATOR_MAP_HELPER_TYPE, 2098) \ + V(LAST_JS_ITERATOR_MAP_HELPER_TYPE, 2098) \ + V(FIRST_JS_ITERATOR_TAKE_HELPER_TYPE, 2099) \ + V(JS_ITERATOR_TAKE_HELPER_TYPE, 2099) \ + V(LAST_JS_ITERATOR_TAKE_HELPER_TYPE, 2099) \ + V(LAST_JS_ITERATOR_HELPER_SIMPLE_TYPE, 2099) \ + V(FIRST_JS_ITERATOR_ZIP_HELPER_TYPE, 2100) \ + V(JS_ITERATOR_ZIP_HELPER_TYPE, 2100) \ + V(FIRST_JS_ITERATOR_ZIP_KEYED_HELPER_TYPE, 2101) \ + V(JS_ITERATOR_ZIP_KEYED_HELPER_TYPE, 2101) \ + V(LAST_JS_ITERATOR_ZIP_KEYED_HELPER_TYPE, 2101) \ + V(LAST_JS_ITERATOR_ZIP_HELPER_TYPE, 2101) \ + V(LAST_JS_ITERATOR_HELPER_TYPE, 2101) \ + V(FIRST_JS_COLLECTION_ITERATOR_TYPE, 2102) \ + V(FIRST_JS_MAP_ITERATOR_TYPE, 2102) \ + V(FIRST_JS_MAP_KEY_ITERATOR_TYPE, 2102) \ + V(JS_MAP_KEY_ITERATOR_TYPE, 2102) \ + V(LAST_JS_MAP_KEY_ITERATOR_TYPE, 2102) \ + V(FIRST_JS_MAP_KEY_VALUE_ITERATOR_TYPE, 2103) \ + V(JS_MAP_KEY_VALUE_ITERATOR_TYPE, 2103) \ + V(LAST_JS_MAP_KEY_VALUE_ITERATOR_TYPE, 2103) \ + V(FIRST_JS_MAP_VALUE_ITERATOR_TYPE, 2104) \ + V(JS_MAP_VALUE_ITERATOR_TYPE, 2104) \ + V(LAST_JS_MAP_VALUE_ITERATOR_TYPE, 2104) \ + V(LAST_JS_MAP_ITERATOR_TYPE, 2104) \ + V(FIRST_JS_SET_ITERATOR_TYPE, 2105) \ + V(FIRST_JS_SET_KEY_VALUE_ITERATOR_TYPE, 2105) \ + V(JS_SET_KEY_VALUE_ITERATOR_TYPE, 2105) \ + V(LAST_JS_SET_KEY_VALUE_ITERATOR_TYPE, 2105) \ + V(FIRST_JS_SET_VALUE_ITERATOR_TYPE, 2106) \ + V(JS_SET_VALUE_ITERATOR_TYPE, 2106) \ + V(LAST_JS_SET_VALUE_ITERATOR_TYPE, 2106) \ + V(LAST_JS_SET_ITERATOR_TYPE, 2106) \ + V(LAST_JS_COLLECTION_ITERATOR_TYPE, 2106) \ + V(FIRST_JS_DISPOSABLE_STACK_BASE_TYPE, 2107) \ + V(JS_DISPOSABLE_STACK_BASE_TYPE, 2107) \ + V(FIRST_JS_ASYNC_DISPOSABLE_STACK_TYPE, 2108) \ + V(JS_ASYNC_DISPOSABLE_STACK_TYPE, 2108) \ + V(LAST_JS_ASYNC_DISPOSABLE_STACK_TYPE, 2108) \ + V(FIRST_JS_SYNC_DISPOSABLE_STACK_TYPE, 2109) \ + V(JS_SYNC_DISPOSABLE_STACK_TYPE, 2109) \ + V(LAST_JS_SYNC_DISPOSABLE_STACK_TYPE, 2109) \ + V(LAST_JS_DISPOSABLE_STACK_BASE_TYPE, 2109) \ + V(FIRST_JS_GENERATOR_OBJECT_TYPE, 2110) \ + V(JS_GENERATOR_OBJECT_TYPE, 2110) \ + V(FIRST_JS_ASYNC_FUNCTION_OBJECT_TYPE, 2111) \ + V(JS_ASYNC_FUNCTION_OBJECT_TYPE, 2111) \ + V(LAST_JS_ASYNC_FUNCTION_OBJECT_TYPE, 2111) \ + V(FIRST_JS_ASYNC_GENERATOR_OBJECT_TYPE, 2112) \ + V(JS_ASYNC_GENERATOR_OBJECT_TYPE, 2112) \ + V(LAST_JS_ASYNC_GENERATOR_OBJECT_TYPE, 2112) \ + V(LAST_JS_GENERATOR_OBJECT_TYPE, 2112) \ + V(FIRST_ALWAYS_SHARED_SPACE_JS_OBJECT_TYPE, 2113) \ + V(FIRST_JS_SHARED_ARRAY_TYPE, 2113) \ + V(JS_SHARED_ARRAY_TYPE, 2113) \ + V(LAST_JS_SHARED_ARRAY_TYPE, 2113) \ + V(FIRST_JS_SHARED_STRUCT_TYPE, 2114) \ + V(JS_SHARED_STRUCT_TYPE, 2114) \ + V(LAST_JS_SHARED_STRUCT_TYPE, 2114) \ + V(LAST_ALWAYS_SHARED_SPACE_JS_OBJECT_TYPE, 2114) \ + V(FIRST_JS_COLLECTION_TYPE, 2115) \ + V(FIRST_JS_MAP_TYPE, 2115) \ + V(JS_MAP_TYPE, 2115) \ + V(LAST_JS_MAP_TYPE, 2115) \ + V(FIRST_JS_SET_TYPE, 2116) \ + V(JS_SET_TYPE, 2116) \ + V(LAST_JS_SET_TYPE, 2116) \ + V(LAST_JS_COLLECTION_TYPE, 2116) \ + V(FIRST_JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE, 2117) \ + V(JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE, 2117) \ + V(FIRST_JS_PROMISE_TYPE, 2118) \ + V(JS_PROMISE_TYPE, 2118) \ + V(LAST_JS_PROMISE_TYPE, 2118) \ + V(LAST_JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE, 2118) \ + V(FIRST_JS_WEAK_COLLECTION_TYPE, 2119) \ + V(FIRST_JS_WEAK_MAP_TYPE, 2119) \ + V(JS_WEAK_MAP_TYPE, 2119) \ + V(LAST_JS_WEAK_MAP_TYPE, 2119) \ + V(FIRST_JS_WEAK_SET_TYPE, 2120) \ + V(JS_WEAK_SET_TYPE, 2120) \ + V(LAST_JS_WEAK_SET_TYPE, 2120) \ + V(LAST_JS_WEAK_COLLECTION_TYPE, 2120) \ + V(FIRST_JS_ARGUMENTS_OBJECT_TYPE, 2121) \ + V(JS_ARGUMENTS_OBJECT_TYPE, 2121) \ + V(LAST_JS_ARGUMENTS_OBJECT_TYPE, 2121) \ + V(FIRST_JS_ARRAY_TYPE, 2122) \ + V(JS_ARRAY_TYPE, 2122) \ + V(LAST_JS_ARRAY_TYPE, 2122) \ + V(FIRST_JS_ARRAY_ITERATOR_TYPE, 2123) \ + V(JS_ARRAY_ITERATOR_TYPE, 2123) \ + V(LAST_JS_ARRAY_ITERATOR_TYPE, 2123) \ + V(FIRST_JS_ASYNC_FROM_SYNC_ITERATOR_TYPE, 2124) \ + V(JS_ASYNC_FROM_SYNC_ITERATOR_TYPE, 2124) \ + V(LAST_JS_ASYNC_FROM_SYNC_ITERATOR_TYPE, 2124) \ + V(FIRST_JS_COLLATOR_TYPE, 2125) \ + V(JS_COLLATOR_TYPE, 2125) \ + V(LAST_JS_COLLATOR_TYPE, 2125) \ + V(FIRST_JS_CONTEXT_EXTENSION_OBJECT_TYPE, 2126) \ + V(JS_CONTEXT_EXTENSION_OBJECT_TYPE, 2126) \ + V(LAST_JS_CONTEXT_EXTENSION_OBJECT_TYPE, 2126) \ + V(FIRST_JS_DATE_TYPE, 2127) \ + V(JS_DATE_TYPE, 2127) \ + V(LAST_JS_DATE_TYPE, 2127) \ + V(FIRST_JS_DATE_TIME_FORMAT_TYPE, 2128) \ + V(JS_DATE_TIME_FORMAT_TYPE, 2128) \ + V(LAST_JS_DATE_TIME_FORMAT_TYPE, 2128) \ + V(FIRST_JS_DISPLAY_NAMES_TYPE, 2129) \ + V(JS_DISPLAY_NAMES_TYPE, 2129) \ + V(LAST_JS_DISPLAY_NAMES_TYPE, 2129) \ + V(FIRST_JS_DURATION_FORMAT_TYPE, 2130) \ + V(JS_DURATION_FORMAT_TYPE, 2130) \ + V(LAST_JS_DURATION_FORMAT_TYPE, 2130) \ + V(FIRST_JS_ERROR_TYPE, 2131) \ + V(JS_ERROR_TYPE, 2131) \ + V(LAST_JS_ERROR_TYPE, 2131) \ + V(FIRST_JS_EXTERNAL_OBJECT_TYPE, 2132) \ + V(JS_EXTERNAL_OBJECT_TYPE, 2132) \ + V(LAST_JS_EXTERNAL_OBJECT_TYPE, 2132) \ + V(FIRST_JS_FINALIZATION_REGISTRY_TYPE, 2133) \ + V(JS_FINALIZATION_REGISTRY_TYPE, 2133) \ + V(LAST_JS_FINALIZATION_REGISTRY_TYPE, 2133) \ + V(FIRST_JS_LIST_FORMAT_TYPE, 2134) \ + V(JS_LIST_FORMAT_TYPE, 2134) \ + V(LAST_JS_LIST_FORMAT_TYPE, 2134) \ + V(FIRST_JS_LOCALE_TYPE, 2135) \ + V(JS_LOCALE_TYPE, 2135) \ + V(LAST_JS_LOCALE_TYPE, 2135) \ + V(FIRST_JS_MESSAGE_OBJECT_TYPE, 2136) \ + V(JS_MESSAGE_OBJECT_TYPE, 2136) \ + V(LAST_JS_MESSAGE_OBJECT_TYPE, 2136) \ + V(FIRST_JS_NUMBER_FORMAT_TYPE, 2137) \ + V(JS_NUMBER_FORMAT_TYPE, 2137) \ + V(LAST_JS_NUMBER_FORMAT_TYPE, 2137) \ + V(FIRST_JS_PLURAL_RULES_TYPE, 2138) \ + V(JS_PLURAL_RULES_TYPE, 2138) \ + V(LAST_JS_PLURAL_RULES_TYPE, 2138) \ + V(FIRST_JS_RAW_JSON_TYPE, 2139) \ + V(JS_RAW_JSON_TYPE, 2139) \ + V(LAST_JS_RAW_JSON_TYPE, 2139) \ + V(FIRST_JS_REG_EXP_TYPE, 2140) \ + V(JS_REG_EXP_TYPE, 2140) \ + V(LAST_JS_REG_EXP_TYPE, 2140) \ + V(FIRST_JS_REG_EXP_STRING_ITERATOR_TYPE, 2141) \ + V(JS_REG_EXP_STRING_ITERATOR_TYPE, 2141) \ + V(LAST_JS_REG_EXP_STRING_ITERATOR_TYPE, 2141) \ + V(FIRST_JS_RELATIVE_TIME_FORMAT_TYPE, 2142) \ + V(JS_RELATIVE_TIME_FORMAT_TYPE, 2142) \ + V(LAST_JS_RELATIVE_TIME_FORMAT_TYPE, 2142) \ + V(FIRST_JS_SEGMENT_ITERATOR_TYPE, 2143) \ + V(JS_SEGMENT_ITERATOR_TYPE, 2143) \ + V(LAST_JS_SEGMENT_ITERATOR_TYPE, 2143) \ + V(FIRST_JS_SEGMENTER_TYPE, 2144) \ + V(JS_SEGMENTER_TYPE, 2144) \ + V(LAST_JS_SEGMENTER_TYPE, 2144) \ + V(FIRST_JS_SEGMENTS_TYPE, 2145) \ + V(JS_SEGMENTS_TYPE, 2145) \ + V(LAST_JS_SEGMENTS_TYPE, 2145) \ + V(FIRST_JS_SHADOW_REALM_TYPE, 2146) \ + V(JS_SHADOW_REALM_TYPE, 2146) \ + V(LAST_JS_SHADOW_REALM_TYPE, 2146) \ + V(FIRST_JS_STRING_ITERATOR_TYPE, 2147) \ + V(JS_STRING_ITERATOR_TYPE, 2147) \ + V(LAST_JS_STRING_ITERATOR_TYPE, 2147) \ + V(FIRST_JS_TEMPORAL_DURATION_TYPE, 2148) \ + V(JS_TEMPORAL_DURATION_TYPE, 2148) \ + V(LAST_JS_TEMPORAL_DURATION_TYPE, 2148) \ + V(FIRST_JS_TEMPORAL_INSTANT_TYPE, 2149) \ + V(JS_TEMPORAL_INSTANT_TYPE, 2149) \ + V(LAST_JS_TEMPORAL_INSTANT_TYPE, 2149) \ + V(FIRST_JS_TEMPORAL_PLAIN_DATE_TYPE, 2150) \ + V(JS_TEMPORAL_PLAIN_DATE_TYPE, 2150) \ + V(LAST_JS_TEMPORAL_PLAIN_DATE_TYPE, 2150) \ + V(FIRST_JS_TEMPORAL_PLAIN_DATE_TIME_TYPE, 2151) \ + V(JS_TEMPORAL_PLAIN_DATE_TIME_TYPE, 2151) \ + V(LAST_JS_TEMPORAL_PLAIN_DATE_TIME_TYPE, 2151) \ + V(FIRST_JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE, 2152) \ + V(JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE, 2152) \ + V(LAST_JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE, 2152) \ + V(FIRST_JS_TEMPORAL_PLAIN_TIME_TYPE, 2153) \ + V(JS_TEMPORAL_PLAIN_TIME_TYPE, 2153) \ + V(LAST_JS_TEMPORAL_PLAIN_TIME_TYPE, 2153) \ + V(FIRST_JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE, 2154) \ + V(JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE, 2154) \ + V(LAST_JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE, 2154) \ + V(FIRST_JS_TEMPORAL_ZONED_DATE_TIME_TYPE, 2155) \ + V(JS_TEMPORAL_ZONED_DATE_TIME_TYPE, 2155) \ + V(LAST_JS_TEMPORAL_ZONED_DATE_TIME_TYPE, 2155) \ + V(FIRST_JS_V8_BREAK_ITERATOR_TYPE, 2156) \ + V(JS_V8_BREAK_ITERATOR_TYPE, 2156) \ + V(LAST_JS_V8_BREAK_ITERATOR_TYPE, 2156) \ + V(FIRST_JS_VALID_ITERATOR_WRAPPER_TYPE, 2157) \ + V(JS_VALID_ITERATOR_WRAPPER_TYPE, 2157) \ + V(LAST_JS_VALID_ITERATOR_WRAPPER_TYPE, 2157) \ + V(FIRST_JS_WEAK_REF_TYPE, 2158) \ + V(JS_WEAK_REF_TYPE, 2158) \ + V(LAST_JS_WEAK_REF_TYPE, 2158) \ + V(FIRST_WASM_CUSTOM_MAP_WRAPPER_TYPE, 2159) \ + V(WASM_CUSTOM_MAP_WRAPPER_TYPE, 2159) \ + V(LAST_WASM_CUSTOM_MAP_WRAPPER_TYPE, 2159) \ + V(FIRST_WASM_EXCEPTION_PACKAGE_TYPE, 2160) \ + V(WASM_EXCEPTION_PACKAGE_TYPE, 2160) \ + V(LAST_WASM_EXCEPTION_PACKAGE_TYPE, 2160) \ + V(FIRST_WASM_GLOBAL_OBJECT_TYPE, 2161) \ + V(WASM_GLOBAL_OBJECT_TYPE, 2161) \ + V(LAST_WASM_GLOBAL_OBJECT_TYPE, 2161) \ + V(FIRST_WASM_INSTANCE_OBJECT_TYPE, 2162) \ + V(WASM_INSTANCE_OBJECT_TYPE, 2162) \ + V(LAST_WASM_INSTANCE_OBJECT_TYPE, 2162) \ + V(FIRST_WASM_MEMORY_OBJECT_TYPE, 2163) \ + V(WASM_MEMORY_OBJECT_TYPE, 2163) \ + V(LAST_WASM_MEMORY_OBJECT_TYPE, 2163) \ + V(FIRST_WASM_MODULE_OBJECT_TYPE, 2164) \ + V(WASM_MODULE_OBJECT_TYPE, 2164) \ + V(LAST_WASM_MODULE_OBJECT_TYPE, 2164) \ + V(FIRST_WASM_SUSPENDING_OBJECT_TYPE, 2165) \ + V(WASM_SUSPENDING_OBJECT_TYPE, 2165) \ + V(LAST_WASM_SUSPENDING_OBJECT_TYPE, 2165) \ + V(FIRST_WASM_TABLE_OBJECT_TYPE, 2166) \ + V(WASM_TABLE_OBJECT_TYPE, 2166) \ + V(LAST_WASM_TABLE_OBJECT_TYPE, 2166) \ + V(FIRST_WASM_TAG_OBJECT_TYPE, 2167) \ + V(WASM_TAG_OBJECT_TYPE, 2167) \ + V(LAST_WASM_TAG_OBJECT_TYPE, 2167) \ + V(FIRST_WASM_VALUE_OBJECT_TYPE, 2168) \ + V(WASM_VALUE_OBJECT_TYPE, 2168) \ + V(LAST_WASM_VALUE_OBJECT_TYPE, 2168) \ + V(LAST_JS_OBJECT_TYPE, 2168) \ + V(LAST_JS_RECEIVER_TYPE, 2168) \ + V(LAST_HEAP_OBJECT_TYPE, 2168) \ + +// Instance types for all classes except for those that use +// InstanceType as flags. +#define TORQUE_ASSIGNED_INSTANCE_TYPE_LIST(V) \ + V(SYMBOL_TYPE) \ + V(BIG_INT_BASE_TYPE) \ + V(HEAP_NUMBER_TYPE) \ + V(ODDBALL_TYPE) \ + V(PROMISE_FULFILL_REACTION_JOB_TASK_TYPE) \ + V(PROMISE_REJECT_REACTION_JOB_TASK_TYPE) \ + V(ASYNC_RESUME_TASK_TYPE) \ + V(CALLABLE_TASK_TYPE) \ + V(CALLBACK_TASK_TYPE) \ + V(PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \ + V(LOAD_HANDLER_TYPE) \ + V(STORE_HANDLER_TYPE) \ + V(ACCESS_CHECK_INFO_TYPE) \ + V(ACCESSOR_PAIR_TYPE) \ + V(ALIASED_ARGUMENTS_ENTRY_TYPE) \ + V(ALLOCATION_MEMENTO_TYPE) \ + V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \ + V(ASYNC_GENERATOR_REQUEST_TYPE) \ + V(BREAK_POINT_TYPE) \ + V(BREAK_POINT_INFO_TYPE) \ + V(BYTECODE_WRAPPER_TYPE) \ + V(CALL_SITE_INFO_TYPE) \ + V(CLASS_BOILERPLATE_TYPE) \ + V(CLASS_POSITIONS_TYPE) \ + V(CODE_WRAPPER_TYPE) \ + V(DEBUG_SCRIPT_SCOPE_INFO_TYPE) \ + V(ENUM_CACHE_TYPE) \ + V(ERROR_STACK_DATA_TYPE) \ + V(FEEDBACK_CELL_TYPE) \ + V(FOR_IN_ENUMERATOR_HOLDER_TYPE) \ + V(FUNCTION_TEMPLATE_RARE_DATA_TYPE) \ + V(MODULE_REQUEST_TYPE) \ + V(PROMISE_CAPABILITY_TYPE) \ + V(PROMISE_REACTION_TYPE) \ + V(PROPERTY_DESCRIPTOR_OBJECT_TYPE) \ + V(PROTOTYPE_INFO_TYPE) \ + V(PROTOTYPE_SHARED_CLOSURE_INFO_TYPE) \ + V(REG_EXP_BOILERPLATE_DESCRIPTION_TYPE) \ + V(REG_EXP_DATA_WRAPPER_TYPE) \ + V(SCRIPT_TYPE) \ + V(SCRIPT_OR_MODULE_TYPE) \ + V(SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE) \ + V(STACK_FRAME_INFO_TYPE) \ + V(STACK_TRACE_INFO_TYPE) \ + V(TEMPLATE_OBJECT_DESCRIPTION_TYPE) \ + V(TUPLE2_TYPE) \ + V(WASM_EXCEPTION_TAG_TYPE) \ + V(UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE) \ + V(UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE) \ + V(UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \ + V(UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE) \ + V(REG_EXP_DATA_TYPE) \ + V(ATOM_REG_EXP_DATA_TYPE) \ + V(IR_REG_EXP_DATA_TYPE) \ + V(WASM_FUNCTION_DATA_TYPE) \ + V(WASM_CAPI_FUNCTION_DATA_TYPE) \ + V(WASM_EXPORTED_FUNCTION_DATA_TYPE) \ + V(BYTECODE_ARRAY_TYPE) \ + V(CODE_TYPE) \ + V(DEBUG_INFO_TYPE) \ + V(INTERPRETER_DATA_TYPE) \ + V(WASM_DISPATCH_TABLE_TYPE) \ + V(WASM_INTERNAL_FUNCTION_TYPE) \ + V(WASM_SUSPENDER_OBJECT_TYPE) \ + V(WASM_TRUSTED_INSTANCE_DATA_TYPE) \ + V(PROTECTED_FIXED_ARRAY_TYPE) \ + V(PROTECTED_WEAK_FIXED_ARRAY_TYPE) \ + V(TRUSTED_BYTE_ARRAY_TYPE) \ + V(TRUSTED_FIXED_ARRAY_TYPE) \ + V(TRUSTED_WEAK_FIXED_ARRAY_TYPE) \ + V(INSTRUCTION_STREAM_TYPE) \ + V(SHARED_FUNCTION_INFO_WRAPPER_TYPE) \ + V(TRUSTED_FOREIGN_TYPE) \ + V(WASM_DISPATCH_TABLE_FOR_IMPORTS_TYPE) \ + V(WASM_IMPORT_DATA_TYPE) \ + V(ACCESSOR_INFO_TYPE) \ + V(FOREIGN_TYPE) \ + V(FIXED_ARRAY_TYPE) \ + V(HASH_TABLE_TYPE) \ + V(EPHEMERON_HASH_TABLE_TYPE) \ + V(GLOBAL_DICTIONARY_TYPE) \ + V(NAME_DICTIONARY_TYPE) \ + V(NAME_TO_INDEX_HASH_TABLE_TYPE) \ + V(NUMBER_DICTIONARY_TYPE) \ + V(REGISTERED_SYMBOL_TABLE_TYPE) \ + V(SIMPLE_NAME_DICTIONARY_TYPE) \ + V(SIMPLE_NUMBER_DICTIONARY_TYPE) \ + V(ORDERED_HASH_MAP_TYPE) \ + V(ORDERED_HASH_SET_TYPE) \ + V(ORDERED_NAME_DICTIONARY_TYPE) \ + V(WEAK_FIXED_ARRAY_TYPE) \ + V(TRANSITION_ARRAY_TYPE) \ + V(BYTE_ARRAY_TYPE) \ + V(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE) \ + V(FIXED_DOUBLE_ARRAY_TYPE) \ + V(OBJECT_BOILERPLATE_DESCRIPTION_TYPE) \ + V(REG_EXP_MATCH_INFO_TYPE) \ + V(SLOPPY_ARGUMENTS_ELEMENTS_TYPE) \ + V(WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE) \ + V(AWAIT_CONTEXT_TYPE) \ + V(BLOCK_CONTEXT_TYPE) \ + V(CATCH_CONTEXT_TYPE) \ + V(DEBUG_EVALUATE_CONTEXT_TYPE) \ + V(EVAL_CONTEXT_TYPE) \ + V(FUNCTION_CONTEXT_TYPE) \ + V(MODULE_CONTEXT_TYPE) \ + V(NATIVE_CONTEXT_TYPE) \ + V(SCRIPT_CONTEXT_TYPE) \ + V(WITH_CONTEXT_TYPE) \ + V(TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE) \ + V(TURBOSHAFT_FLOAT64_SET_TYPE_TYPE) \ + V(TURBOSHAFT_WORD32_RANGE_TYPE_TYPE) \ + V(TURBOSHAFT_WORD32_SET_TYPE_TYPE) \ + V(TURBOSHAFT_WORD64_RANGE_TYPE_TYPE) \ + V(TURBOSHAFT_WORD64_SET_TYPE_TYPE) \ + V(TURBOFAN_BITSET_TYPE_TYPE) \ + V(TURBOFAN_HEAP_CONSTANT_TYPE_TYPE) \ + V(TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE) \ + V(TURBOFAN_RANGE_TYPE_TYPE) \ + V(TURBOFAN_UNION_TYPE_TYPE) \ + V(SMALL_ORDERED_HASH_MAP_TYPE) \ + V(SMALL_ORDERED_HASH_SET_TYPE) \ + V(SMALL_ORDERED_NAME_DICTIONARY_TYPE) \ + V(FUNCTION_TEMPLATE_INFO_TYPE) \ + V(OBJECT_TEMPLATE_INFO_TYPE) \ + V(DICTIONARY_TEMPLATE_INFO_TYPE) \ + V(MAP_TYPE) \ + V(WASM_CUSTOM_MAP_TYPE) \ + V(SOURCE_TEXT_MODULE_TYPE) \ + V(SYNTHETIC_MODULE_TYPE) \ + V(ALLOCATION_SITE_TYPE) \ + V(ARRAY_LIST_TYPE) \ + V(CELL_TYPE) \ + V(CONTEXT_CELL_TYPE) \ + V(COVERAGE_INFO_TYPE) \ + V(CPP_GCMANAGED_BASE_TYPE) \ + V(CPP_HEAP_EXTERNAL_OBJECT_TYPE) \ + V(DESCRIPTOR_ARRAY_TYPE) \ + V(DOUBLE_STRING_CACHE_TYPE) \ + V(EMBEDDER_DATA_ARRAY_TYPE) \ + V(FEEDBACK_METADATA_TYPE) \ + V(FEEDBACK_VECTOR_TYPE) \ + V(FILLER_TYPE) \ + V(FREE_SPACE_TYPE) \ + V(HASH_SEED_WRAPPER_TYPE) \ + V(HOLE_TYPE) \ + V(INTERCEPTOR_INFO_TYPE) \ + V(MEGA_DOM_HANDLER_TYPE) \ + V(ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE) \ + V(PREPARSE_DATA_TYPE) \ + V(PROPERTY_ARRAY_TYPE) \ + V(PROPERTY_CELL_TYPE) \ + V(SCOPE_INFO_TYPE) \ + V(SCRIPT_CONTEXT_TABLE_TYPE) \ + V(SHARED_FUNCTION_INFO_TYPE) \ + V(SORT_STATE_TYPE) \ + V(SWISS_NAME_DICTIONARY_TYPE) \ + V(UNINITIALIZED_HEAP_NUMBER_TYPE) \ + V(WASM_CONTINUATION_OBJECT_TYPE) \ + V(WASM_FAST_API_CALL_DATA_TYPE) \ + V(WASM_FUNC_REF_TYPE) \ + V(WASM_NULL_TYPE) \ + V(WASM_RESUME_DATA_TYPE) \ + V(WASM_STACK_OBJECT_TYPE) \ + V(WASM_STRING_VIEW_ITER_TYPE) \ + V(WASM_TYPE_INFO_TYPE) \ + V(WEAK_ARRAY_LIST_TYPE) \ + V(WEAK_CELL_TYPE) \ + V(WASM_ARRAY_TYPE) \ + V(WASM_STRUCT_TYPE) \ + V(JS_PROXY_TYPE) \ + V(JS_OBJECT_TYPE) \ + V(JS_MODULE_NAMESPACE_TYPE) \ + V(JS_DEFERRED_MODULE_NAMESPACE_TYPE) \ + V(JS_GLOBAL_OBJECT_TYPE) \ + V(JS_GLOBAL_PROXY_TYPE) \ + V(JS_SPECIAL_API_OBJECT_TYPE) \ + V(JS_PRIMITIVE_WRAPPER_TYPE) \ + V(JS_API_OBJECT_TYPE) \ + V(JS_LAST_DUMMY_API_OBJECT_TYPE) \ + V(JS_DATA_VIEW_TYPE) \ + V(JS_RAB_GSAB_DATA_VIEW_TYPE) \ + V(JS_TYPED_ARRAY_TYPE) \ + V(JS_DETACHED_TYPED_ARRAY_TYPE) \ + V(JS_ARRAY_BUFFER_TYPE) \ + V(JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE) \ + V(JS_FUNCTION_WITH_PROTOTYPE_TYPE) \ + V(BIGINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(BIGUINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(FLOAT16_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(FLOAT32_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(FLOAT64_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(INT16_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(INT32_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(INT8_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(UINT16_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(UINT32_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(UINT8_CLAMPED_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(UINT8_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(JS_ARRAY_CONSTRUCTOR_TYPE) \ + V(JS_PROMISE_CONSTRUCTOR_TYPE) \ + V(JS_REG_EXP_CONSTRUCTOR_TYPE) \ + V(JS_CLASS_CONSTRUCTOR_TYPE) \ + V(JS_BOUND_FUNCTION_TYPE) \ + V(JS_WRAPPED_FUNCTION_TYPE) \ + V(JS_ARRAY_ITERATOR_PROTOTYPE_TYPE) \ + V(JS_ITERATOR_PROTOTYPE_TYPE) \ + V(JS_MAP_ITERATOR_PROTOTYPE_TYPE) \ + V(JS_OBJECT_PROTOTYPE_TYPE) \ + V(JS_PROMISE_PROTOTYPE_TYPE) \ + V(JS_REG_EXP_PROTOTYPE_TYPE) \ + V(JS_SET_ITERATOR_PROTOTYPE_TYPE) \ + V(JS_SET_PROTOTYPE_TYPE) \ + V(JS_STRING_ITERATOR_PROTOTYPE_TYPE) \ + V(JS_TYPED_ARRAY_PROTOTYPE_TYPE) \ + V(JS_ITERATOR_CONCAT_HELPER_TYPE) \ + V(JS_ITERATOR_DROP_HELPER_TYPE) \ + V(JS_ITERATOR_FILTER_HELPER_TYPE) \ + V(JS_ITERATOR_FLAT_MAP_HELPER_TYPE) \ + V(JS_ITERATOR_MAP_HELPER_TYPE) \ + V(JS_ITERATOR_TAKE_HELPER_TYPE) \ + V(JS_ITERATOR_ZIP_HELPER_TYPE) \ + V(JS_ITERATOR_ZIP_KEYED_HELPER_TYPE) \ + V(JS_MAP_KEY_ITERATOR_TYPE) \ + V(JS_MAP_KEY_VALUE_ITERATOR_TYPE) \ + V(JS_MAP_VALUE_ITERATOR_TYPE) \ + V(JS_SET_KEY_VALUE_ITERATOR_TYPE) \ + V(JS_SET_VALUE_ITERATOR_TYPE) \ + V(JS_DISPOSABLE_STACK_BASE_TYPE) \ + V(JS_ASYNC_DISPOSABLE_STACK_TYPE) \ + V(JS_SYNC_DISPOSABLE_STACK_TYPE) \ + V(JS_GENERATOR_OBJECT_TYPE) \ + V(JS_ASYNC_FUNCTION_OBJECT_TYPE) \ + V(JS_ASYNC_GENERATOR_OBJECT_TYPE) \ + V(JS_SHARED_ARRAY_TYPE) \ + V(JS_SHARED_STRUCT_TYPE) \ + V(JS_MAP_TYPE) \ + V(JS_SET_TYPE) \ + V(JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE) \ + V(JS_PROMISE_TYPE) \ + V(JS_WEAK_MAP_TYPE) \ + V(JS_WEAK_SET_TYPE) \ + V(JS_ARGUMENTS_OBJECT_TYPE) \ + V(JS_ARRAY_TYPE) \ + V(JS_ARRAY_ITERATOR_TYPE) \ + V(JS_ASYNC_FROM_SYNC_ITERATOR_TYPE) \ + V(JS_COLLATOR_TYPE) \ + V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \ + V(JS_DATE_TYPE) \ + V(JS_DATE_TIME_FORMAT_TYPE) \ + V(JS_DISPLAY_NAMES_TYPE) \ + V(JS_DURATION_FORMAT_TYPE) \ + V(JS_ERROR_TYPE) \ + V(JS_EXTERNAL_OBJECT_TYPE) \ + V(JS_FINALIZATION_REGISTRY_TYPE) \ + V(JS_LIST_FORMAT_TYPE) \ + V(JS_LOCALE_TYPE) \ + V(JS_MESSAGE_OBJECT_TYPE) \ + V(JS_NUMBER_FORMAT_TYPE) \ + V(JS_PLURAL_RULES_TYPE) \ + V(JS_RAW_JSON_TYPE) \ + V(JS_REG_EXP_TYPE) \ + V(JS_REG_EXP_STRING_ITERATOR_TYPE) \ + V(JS_RELATIVE_TIME_FORMAT_TYPE) \ + V(JS_SEGMENT_ITERATOR_TYPE) \ + V(JS_SEGMENTER_TYPE) \ + V(JS_SEGMENTS_TYPE) \ + V(JS_SHADOW_REALM_TYPE) \ + V(JS_STRING_ITERATOR_TYPE) \ + V(JS_TEMPORAL_DURATION_TYPE) \ + V(JS_TEMPORAL_INSTANT_TYPE) \ + V(JS_TEMPORAL_PLAIN_DATE_TYPE) \ + V(JS_TEMPORAL_PLAIN_DATE_TIME_TYPE) \ + V(JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE) \ + V(JS_TEMPORAL_PLAIN_TIME_TYPE) \ + V(JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE) \ + V(JS_TEMPORAL_ZONED_DATE_TIME_TYPE) \ + V(JS_V8_BREAK_ITERATOR_TYPE) \ + V(JS_VALID_ITERATOR_WRAPPER_TYPE) \ + V(JS_WEAK_REF_TYPE) \ + V(WASM_CUSTOM_MAP_WRAPPER_TYPE) \ + V(WASM_EXCEPTION_PACKAGE_TYPE) \ + V(WASM_GLOBAL_OBJECT_TYPE) \ + V(WASM_INSTANCE_OBJECT_TYPE) \ + V(WASM_MEMORY_OBJECT_TYPE) \ + V(WASM_MODULE_OBJECT_TYPE) \ + V(WASM_SUSPENDING_OBJECT_TYPE) \ + V(WASM_TABLE_OBJECT_TYPE) \ + V(WASM_TAG_OBJECT_TYPE) \ + V(WASM_VALUE_OBJECT_TYPE) \ + +// Pairs of (ClassName, INSTANCE_TYPE) for classes whose instance +// type is unique to them (no subclasses share it). +#define INSTANCE_TYPE_LIST_SINGLE(V) \ + V(Symbol, SYMBOL_TYPE) \ + V(BigIntBase, BIG_INT_BASE_TYPE) \ + V(HeapNumber, HEAP_NUMBER_TYPE) \ + V(Oddball, ODDBALL_TYPE) \ + V(PromiseFulfillReactionJobTask, PROMISE_FULFILL_REACTION_JOB_TASK_TYPE) \ + V(PromiseRejectReactionJobTask, PROMISE_REJECT_REACTION_JOB_TASK_TYPE) \ + V(AsyncResumeTask, ASYNC_RESUME_TASK_TYPE) \ + V(CallableTask, CALLABLE_TASK_TYPE) \ + V(CallbackTask, CALLBACK_TASK_TYPE) \ + V(PromiseResolveThenableJobTask, PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \ + V(LoadHandler, LOAD_HANDLER_TYPE) \ + V(StoreHandler, STORE_HANDLER_TYPE) \ + V(AccessCheckInfo, ACCESS_CHECK_INFO_TYPE) \ + V(AccessorPair, ACCESSOR_PAIR_TYPE) \ + V(AliasedArgumentsEntry, ALIASED_ARGUMENTS_ENTRY_TYPE) \ + V(AllocationMemento, ALLOCATION_MEMENTO_TYPE) \ + V(ArrayBoilerplateDescription, ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \ + V(AsyncGeneratorRequest, ASYNC_GENERATOR_REQUEST_TYPE) \ + V(BreakPoint, BREAK_POINT_TYPE) \ + V(BreakPointInfo, BREAK_POINT_INFO_TYPE) \ + V(BytecodeWrapper, BYTECODE_WRAPPER_TYPE) \ + V(CallSiteInfo, CALL_SITE_INFO_TYPE) \ + V(ClassBoilerplate, CLASS_BOILERPLATE_TYPE) \ + V(ClassPositions, CLASS_POSITIONS_TYPE) \ + V(CodeWrapper, CODE_WRAPPER_TYPE) \ + V(DebugScriptScopeInfo, DEBUG_SCRIPT_SCOPE_INFO_TYPE) \ + V(EnumCache, ENUM_CACHE_TYPE) \ + V(ErrorStackData, ERROR_STACK_DATA_TYPE) \ + V(FeedbackCell, FEEDBACK_CELL_TYPE) \ + V(ForInEnumeratorHolder, FOR_IN_ENUMERATOR_HOLDER_TYPE) \ + V(FunctionTemplateRareData, FUNCTION_TEMPLATE_RARE_DATA_TYPE) \ + V(ModuleRequest, MODULE_REQUEST_TYPE) \ + V(PromiseCapability, PROMISE_CAPABILITY_TYPE) \ + V(PromiseReaction, PROMISE_REACTION_TYPE) \ + V(PropertyDescriptorObject, PROPERTY_DESCRIPTOR_OBJECT_TYPE) \ + V(PrototypeInfo, PROTOTYPE_INFO_TYPE) \ + V(PrototypeSharedClosureInfo, PROTOTYPE_SHARED_CLOSURE_INFO_TYPE) \ + V(RegExpBoilerplateDescription, REG_EXP_BOILERPLATE_DESCRIPTION_TYPE) \ + V(RegExpDataWrapper, REG_EXP_DATA_WRAPPER_TYPE) \ + V(Script, SCRIPT_TYPE) \ + V(ScriptOrModule, SCRIPT_OR_MODULE_TYPE) \ + V(SourceTextModuleInfoEntry, SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE) \ + V(StackFrameInfo, STACK_FRAME_INFO_TYPE) \ + V(StackTraceInfo, STACK_TRACE_INFO_TYPE) \ + V(TemplateObjectDescription, TEMPLATE_OBJECT_DESCRIPTION_TYPE) \ + V(Tuple2, TUPLE2_TYPE) \ + V(WasmExceptionTag, WASM_EXCEPTION_TAG_TYPE) \ + V(UncompiledDataWithPreparseDataAndJob, UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE) \ + V(UncompiledDataWithoutPreparseDataWithJob, UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE) \ + V(AtomRegExpData, ATOM_REG_EXP_DATA_TYPE) \ + V(IrRegExpData, IR_REG_EXP_DATA_TYPE) \ + V(WasmCapiFunctionData, WASM_CAPI_FUNCTION_DATA_TYPE) \ + V(WasmExportedFunctionData, WASM_EXPORTED_FUNCTION_DATA_TYPE) \ + V(BytecodeArray, BYTECODE_ARRAY_TYPE) \ + V(Code, CODE_TYPE) \ + V(DebugInfo, DEBUG_INFO_TYPE) \ + V(InterpreterData, INTERPRETER_DATA_TYPE) \ + V(WasmDispatchTable, WASM_DISPATCH_TABLE_TYPE) \ + V(WasmInternalFunction, WASM_INTERNAL_FUNCTION_TYPE) \ + V(WasmSuspenderObject, WASM_SUSPENDER_OBJECT_TYPE) \ + V(WasmTrustedInstanceData, WASM_TRUSTED_INSTANCE_DATA_TYPE) \ + V(ProtectedFixedArray, PROTECTED_FIXED_ARRAY_TYPE) \ + V(ProtectedWeakFixedArray, PROTECTED_WEAK_FIXED_ARRAY_TYPE) \ + V(TrustedByteArray, TRUSTED_BYTE_ARRAY_TYPE) \ + V(TrustedFixedArray, TRUSTED_FIXED_ARRAY_TYPE) \ + V(TrustedWeakFixedArray, TRUSTED_WEAK_FIXED_ARRAY_TYPE) \ + V(InstructionStream, INSTRUCTION_STREAM_TYPE) \ + V(SharedFunctionInfoWrapper, SHARED_FUNCTION_INFO_WRAPPER_TYPE) \ + V(TrustedForeign, TRUSTED_FOREIGN_TYPE) \ + V(WasmDispatchTableForImports, WASM_DISPATCH_TABLE_FOR_IMPORTS_TYPE) \ + V(WasmImportData, WASM_IMPORT_DATA_TYPE) \ + V(AccessorInfo, ACCESSOR_INFO_TYPE) \ + V(Foreign, FOREIGN_TYPE) \ + V(EphemeronHashTable, EPHEMERON_HASH_TABLE_TYPE) \ + V(GlobalDictionary, GLOBAL_DICTIONARY_TYPE) \ + V(NameDictionary, NAME_DICTIONARY_TYPE) \ + V(NameToIndexHashTable, NAME_TO_INDEX_HASH_TABLE_TYPE) \ + V(NumberDictionary, NUMBER_DICTIONARY_TYPE) \ + V(RegisteredSymbolTable, REGISTERED_SYMBOL_TABLE_TYPE) \ + V(SimpleNameDictionary, SIMPLE_NAME_DICTIONARY_TYPE) \ + V(SimpleNumberDictionary, SIMPLE_NUMBER_DICTIONARY_TYPE) \ + V(OrderedHashMap, ORDERED_HASH_MAP_TYPE) \ + V(OrderedHashSet, ORDERED_HASH_SET_TYPE) \ + V(OrderedNameDictionary, ORDERED_NAME_DICTIONARY_TYPE) \ + V(TransitionArray, TRANSITION_ARRAY_TYPE) \ + V(ByteArray, BYTE_ARRAY_TYPE) \ + V(ClosureFeedbackCellArray, CLOSURE_FEEDBACK_CELL_ARRAY_TYPE) \ + V(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE) \ + V(ObjectBoilerplateDescription, OBJECT_BOILERPLATE_DESCRIPTION_TYPE) \ + V(RegExpMatchInfo, REG_EXP_MATCH_INFO_TYPE) \ + V(SloppyArgumentsElements, SLOPPY_ARGUMENTS_ELEMENTS_TYPE) \ + V(WeakHomomorphicFixedArray, WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE) \ + V(AwaitContext, AWAIT_CONTEXT_TYPE) \ + V(BlockContext, BLOCK_CONTEXT_TYPE) \ + V(CatchContext, CATCH_CONTEXT_TYPE) \ + V(DebugEvaluateContext, DEBUG_EVALUATE_CONTEXT_TYPE) \ + V(EvalContext, EVAL_CONTEXT_TYPE) \ + V(FunctionContext, FUNCTION_CONTEXT_TYPE) \ + V(ModuleContext, MODULE_CONTEXT_TYPE) \ + V(NativeContext, NATIVE_CONTEXT_TYPE) \ + V(ScriptContext, SCRIPT_CONTEXT_TYPE) \ + V(WithContext, WITH_CONTEXT_TYPE) \ + V(TurboshaftFloat64RangeType, TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE) \ + V(TurboshaftFloat64SetType, TURBOSHAFT_FLOAT64_SET_TYPE_TYPE) \ + V(TurboshaftWord32RangeType, TURBOSHAFT_WORD32_RANGE_TYPE_TYPE) \ + V(TurboshaftWord32SetType, TURBOSHAFT_WORD32_SET_TYPE_TYPE) \ + V(TurboshaftWord64RangeType, TURBOSHAFT_WORD64_RANGE_TYPE_TYPE) \ + V(TurboshaftWord64SetType, TURBOSHAFT_WORD64_SET_TYPE_TYPE) \ + V(TurbofanBitsetType, TURBOFAN_BITSET_TYPE_TYPE) \ + V(TurbofanHeapConstantType, TURBOFAN_HEAP_CONSTANT_TYPE_TYPE) \ + V(TurbofanOtherNumberConstantType, TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE) \ + V(TurbofanRangeType, TURBOFAN_RANGE_TYPE_TYPE) \ + V(TurbofanUnionType, TURBOFAN_UNION_TYPE_TYPE) \ + V(SmallOrderedHashMap, SMALL_ORDERED_HASH_MAP_TYPE) \ + V(SmallOrderedHashSet, SMALL_ORDERED_HASH_SET_TYPE) \ + V(SmallOrderedNameDictionary, SMALL_ORDERED_NAME_DICTIONARY_TYPE) \ + V(FunctionTemplateInfo, FUNCTION_TEMPLATE_INFO_TYPE) \ + V(ObjectTemplateInfo, OBJECT_TEMPLATE_INFO_TYPE) \ + V(DictionaryTemplateInfo, DICTIONARY_TEMPLATE_INFO_TYPE) \ + V(WasmCustomMap, WASM_CUSTOM_MAP_TYPE) \ + V(SourceTextModule, SOURCE_TEXT_MODULE_TYPE) \ + V(SyntheticModule, SYNTHETIC_MODULE_TYPE) \ + V(AllocationSite, ALLOCATION_SITE_TYPE) \ + V(ArrayList, ARRAY_LIST_TYPE) \ + V(Cell, CELL_TYPE) \ + V(ContextCell, CONTEXT_CELL_TYPE) \ + V(CoverageInfo, COVERAGE_INFO_TYPE) \ + V(CppGCManagedBase, CPP_GCMANAGED_BASE_TYPE) \ + V(CppHeapExternalObject, CPP_HEAP_EXTERNAL_OBJECT_TYPE) \ + V(DescriptorArray, DESCRIPTOR_ARRAY_TYPE) \ + V(DoubleStringCache, DOUBLE_STRING_CACHE_TYPE) \ + V(EmbedderDataArray, EMBEDDER_DATA_ARRAY_TYPE) \ + V(FeedbackMetadata, FEEDBACK_METADATA_TYPE) \ + V(FeedbackVector, FEEDBACK_VECTOR_TYPE) \ + V(Filler, FILLER_TYPE) \ + V(FreeSpace, FREE_SPACE_TYPE) \ + V(HashSeedWrapper, HASH_SEED_WRAPPER_TYPE) \ + V(Hole, HOLE_TYPE) \ + V(InterceptorInfo, INTERCEPTOR_INFO_TYPE) \ + V(MegaDomHandler, MEGA_DOM_HANDLER_TYPE) \ + V(OnHeapBasicBlockProfilerData, ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE) \ + V(PreparseData, PREPARSE_DATA_TYPE) \ + V(PropertyArray, PROPERTY_ARRAY_TYPE) \ + V(PropertyCell, PROPERTY_CELL_TYPE) \ + V(ScopeInfo, SCOPE_INFO_TYPE) \ + V(ScriptContextTable, SCRIPT_CONTEXT_TABLE_TYPE) \ + V(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) \ + V(SortState, SORT_STATE_TYPE) \ + V(SwissNameDictionary, SWISS_NAME_DICTIONARY_TYPE) \ + V(UninitializedHeapNumber, UNINITIALIZED_HEAP_NUMBER_TYPE) \ + V(WasmContinuationObject, WASM_CONTINUATION_OBJECT_TYPE) \ + V(WasmFastApiCallData, WASM_FAST_API_CALL_DATA_TYPE) \ + V(WasmFuncRef, WASM_FUNC_REF_TYPE) \ + V(WasmResumeData, WASM_RESUME_DATA_TYPE) \ + V(WasmStackObject, WASM_STACK_OBJECT_TYPE) \ + V(WasmStringViewIter, WASM_STRING_VIEW_ITER_TYPE) \ + V(WasmTypeInfo, WASM_TYPE_INFO_TYPE) \ + V(WeakArrayList, WEAK_ARRAY_LIST_TYPE) \ + V(WeakCell, WEAK_CELL_TYPE) \ + V(WasmArray, WASM_ARRAY_TYPE) \ + V(WasmStruct, WASM_STRUCT_TYPE) \ + V(JSProxy, JS_PROXY_TYPE) \ + V(JSDeferredModuleNamespace, JS_DEFERRED_MODULE_NAMESPACE_TYPE) \ + V(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE) \ + V(JSGlobalProxy, JS_GLOBAL_PROXY_TYPE) \ + V(JSSpecialApiObject, JS_SPECIAL_API_OBJECT_TYPE) \ + V(JSPrimitiveWrapper, JS_PRIMITIVE_WRAPPER_TYPE) \ + V(JSLastDummyApiObject, JS_LAST_DUMMY_API_OBJECT_TYPE) \ + V(JSDataView, JS_DATA_VIEW_TYPE) \ + V(JSRabGsabDataView, JS_RAB_GSAB_DATA_VIEW_TYPE) \ + V(JSDetachedTypedArray, JS_DETACHED_TYPED_ARRAY_TYPE) \ + V(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) \ + V(JSFunctionWithoutPrototype, JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE) \ + V(Bigint64TypedArrayConstructor, BIGINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Biguint64TypedArrayConstructor, BIGUINT64_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Float16TypedArrayConstructor, FLOAT16_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Float32TypedArrayConstructor, FLOAT32_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Float64TypedArrayConstructor, FLOAT64_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Int16TypedArrayConstructor, INT16_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Int32TypedArrayConstructor, INT32_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Int8TypedArrayConstructor, INT8_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Uint16TypedArrayConstructor, UINT16_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Uint32TypedArrayConstructor, UINT32_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Uint8ClampedTypedArrayConstructor, UINT8_CLAMPED_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(Uint8TypedArrayConstructor, UINT8_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(JSArrayConstructor, JS_ARRAY_CONSTRUCTOR_TYPE) \ + V(JSPromiseConstructor, JS_PROMISE_CONSTRUCTOR_TYPE) \ + V(JSRegExpConstructor, JS_REG_EXP_CONSTRUCTOR_TYPE) \ + V(JSClassConstructor, JS_CLASS_CONSTRUCTOR_TYPE) \ + V(JSBoundFunction, JS_BOUND_FUNCTION_TYPE) \ + V(JSWrappedFunction, JS_WRAPPED_FUNCTION_TYPE) \ + V(JSArrayIteratorPrototype, JS_ARRAY_ITERATOR_PROTOTYPE_TYPE) \ + V(JSIteratorPrototype, JS_ITERATOR_PROTOTYPE_TYPE) \ + V(JSMapIteratorPrototype, JS_MAP_ITERATOR_PROTOTYPE_TYPE) \ + V(JSObjectPrototype, JS_OBJECT_PROTOTYPE_TYPE) \ + V(JSPromisePrototype, JS_PROMISE_PROTOTYPE_TYPE) \ + V(JSRegExpPrototype, JS_REG_EXP_PROTOTYPE_TYPE) \ + V(JSSetIteratorPrototype, JS_SET_ITERATOR_PROTOTYPE_TYPE) \ + V(JSSetPrototype, JS_SET_PROTOTYPE_TYPE) \ + V(JSStringIteratorPrototype, JS_STRING_ITERATOR_PROTOTYPE_TYPE) \ + V(JSTypedArrayPrototype, JS_TYPED_ARRAY_PROTOTYPE_TYPE) \ + V(JSIteratorConcatHelper, JS_ITERATOR_CONCAT_HELPER_TYPE) \ + V(JSIteratorDropHelper, JS_ITERATOR_DROP_HELPER_TYPE) \ + V(JSIteratorFilterHelper, JS_ITERATOR_FILTER_HELPER_TYPE) \ + V(JSIteratorFlatMapHelper, JS_ITERATOR_FLAT_MAP_HELPER_TYPE) \ + V(JSIteratorMapHelper, JS_ITERATOR_MAP_HELPER_TYPE) \ + V(JSIteratorTakeHelper, JS_ITERATOR_TAKE_HELPER_TYPE) \ + V(JSIteratorZipKeyedHelper, JS_ITERATOR_ZIP_KEYED_HELPER_TYPE) \ + V(JSMapKeyIterator, JS_MAP_KEY_ITERATOR_TYPE) \ + V(JSMapKeyValueIterator, JS_MAP_KEY_VALUE_ITERATOR_TYPE) \ + V(JSMapValueIterator, JS_MAP_VALUE_ITERATOR_TYPE) \ + V(JSSetKeyValueIterator, JS_SET_KEY_VALUE_ITERATOR_TYPE) \ + V(JSSetValueIterator, JS_SET_VALUE_ITERATOR_TYPE) \ + V(JSAsyncDisposableStack, JS_ASYNC_DISPOSABLE_STACK_TYPE) \ + V(JSSyncDisposableStack, JS_SYNC_DISPOSABLE_STACK_TYPE) \ + V(JSAsyncFunctionObject, JS_ASYNC_FUNCTION_OBJECT_TYPE) \ + V(JSAsyncGeneratorObject, JS_ASYNC_GENERATOR_OBJECT_TYPE) \ + V(JSSharedArray, JS_SHARED_ARRAY_TYPE) \ + V(JSSharedStruct, JS_SHARED_STRUCT_TYPE) \ + V(JSMap, JS_MAP_TYPE) \ + V(JSSet, JS_SET_TYPE) \ + V(JSPromise, JS_PROMISE_TYPE) \ + V(JSWeakMap, JS_WEAK_MAP_TYPE) \ + V(JSWeakSet, JS_WEAK_SET_TYPE) \ + V(JSArgumentsObject, JS_ARGUMENTS_OBJECT_TYPE) \ + V(JSArray, JS_ARRAY_TYPE) \ + V(JSArrayIterator, JS_ARRAY_ITERATOR_TYPE) \ + V(JSAsyncFromSyncIterator, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE) \ + V(JSCollator, JS_COLLATOR_TYPE) \ + V(JSContextExtensionObject, JS_CONTEXT_EXTENSION_OBJECT_TYPE) \ + V(JSDate, JS_DATE_TYPE) \ + V(JSDateTimeFormat, JS_DATE_TIME_FORMAT_TYPE) \ + V(JSDisplayNames, JS_DISPLAY_NAMES_TYPE) \ + V(JSDurationFormat, JS_DURATION_FORMAT_TYPE) \ + V(JSError, JS_ERROR_TYPE) \ + V(JSExternalObject, JS_EXTERNAL_OBJECT_TYPE) \ + V(JSFinalizationRegistry, JS_FINALIZATION_REGISTRY_TYPE) \ + V(JSListFormat, JS_LIST_FORMAT_TYPE) \ + V(JSLocale, JS_LOCALE_TYPE) \ + V(JSMessageObject, JS_MESSAGE_OBJECT_TYPE) \ + V(JSNumberFormat, JS_NUMBER_FORMAT_TYPE) \ + V(JSPluralRules, JS_PLURAL_RULES_TYPE) \ + V(JSRawJson, JS_RAW_JSON_TYPE) \ + V(JSRegExp, JS_REG_EXP_TYPE) \ + V(JSRegExpStringIterator, JS_REG_EXP_STRING_ITERATOR_TYPE) \ + V(JSRelativeTimeFormat, JS_RELATIVE_TIME_FORMAT_TYPE) \ + V(JSSegmentIterator, JS_SEGMENT_ITERATOR_TYPE) \ + V(JSSegmenter, JS_SEGMENTER_TYPE) \ + V(JSSegments, JS_SEGMENTS_TYPE) \ + V(JSShadowRealm, JS_SHADOW_REALM_TYPE) \ + V(JSStringIterator, JS_STRING_ITERATOR_TYPE) \ + V(JSTemporalDuration, JS_TEMPORAL_DURATION_TYPE) \ + V(JSTemporalInstant, JS_TEMPORAL_INSTANT_TYPE) \ + V(JSTemporalPlainDate, JS_TEMPORAL_PLAIN_DATE_TYPE) \ + V(JSTemporalPlainDateTime, JS_TEMPORAL_PLAIN_DATE_TIME_TYPE) \ + V(JSTemporalPlainMonthDay, JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE) \ + V(JSTemporalPlainTime, JS_TEMPORAL_PLAIN_TIME_TYPE) \ + V(JSTemporalPlainYearMonth, JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE) \ + V(JSTemporalZonedDateTime, JS_TEMPORAL_ZONED_DATE_TIME_TYPE) \ + V(JSV8BreakIterator, JS_V8_BREAK_ITERATOR_TYPE) \ + V(JSValidIteratorWrapper, JS_VALID_ITERATOR_WRAPPER_TYPE) \ + V(JSWeakRef, JS_WEAK_REF_TYPE) \ + V(WasmCustomMapWrapper, WASM_CUSTOM_MAP_WRAPPER_TYPE) \ + V(WasmExceptionPackage, WASM_EXCEPTION_PACKAGE_TYPE) \ + V(WasmGlobalObject, WASM_GLOBAL_OBJECT_TYPE) \ + V(WasmInstanceObject, WASM_INSTANCE_OBJECT_TYPE) \ + V(WasmMemoryObject, WASM_MEMORY_OBJECT_TYPE) \ + V(WasmModuleObject, WASM_MODULE_OBJECT_TYPE) \ + V(WasmSuspendingObject, WASM_SUSPENDING_OBJECT_TYPE) \ + V(WasmTableObject, WASM_TABLE_OBJECT_TYPE) \ + V(WasmTagObject, WASM_TAG_OBJECT_TYPE) \ + V(WasmValueObject, WASM_VALUE_OBJECT_TYPE) \ + +// Pairs of (ClassName, INSTANCE_TYPE) for classes that have their +// own instance type and whose subclasses share that instance type +// (e.g. JSObject owns JS_OBJECT_TYPE; concrete leaves with the +// same IT are entered via INSTANCE_TYPE_LIST_SINGLE). +#define INSTANCE_TYPE_LIST_MULTIPLE(V) \ + V(UncompiledDataWithPreparseData, UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE) \ + V(UncompiledDataWithoutPreparseData, UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \ + V(RegExpData, REG_EXP_DATA_TYPE) \ + V(WasmFunctionData, WASM_FUNCTION_DATA_TYPE) \ + V(FixedArray, FIXED_ARRAY_TYPE) \ + V(HashTable, HASH_TABLE_TYPE) \ + V(WeakFixedArray, WEAK_FIXED_ARRAY_TYPE) \ + V(Map, MAP_TYPE) \ + V(JSObject, JS_OBJECT_TYPE) \ + V(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) \ + V(JSApiObject, JS_API_OBJECT_TYPE) \ + V(JSTypedArray, JS_TYPED_ARRAY_TYPE) \ + V(JSFunctionWithPrototype, JS_FUNCTION_WITH_PROTOTYPE_TYPE) \ + V(JSIteratorZipHelper, JS_ITERATOR_ZIP_HELPER_TYPE) \ + V(JSDisposableStackBase, JS_DISPOSABLE_STACK_BASE_TYPE) \ + V(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE) \ + V(JSObjectWithEmbedderSlots, JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE) \ + +// Triples of (ClassName, FIRST_TYPE, LAST_TYPE) for classes that +// span a contiguous range of instance types (typically abstract +// intermediates whose concrete subclasses get their own ITs). +#define INSTANCE_TYPE_LIST_RANGE(V) \ + V(String, FIRST_STRING_TYPE, LAST_STRING_TYPE) \ + V(Name, FIRST_NAME_TYPE, LAST_NAME_TYPE) \ + V(PrimitiveHeapObject, FIRST_PRIMITIVE_HEAP_OBJECT_TYPE, LAST_PRIMITIVE_HEAP_OBJECT_TYPE) \ + V(PromiseReactionJobTask, FIRST_PROMISE_REACTION_JOB_TASK_TYPE, LAST_PROMISE_REACTION_JOB_TASK_TYPE) \ + V(Microtask, FIRST_MICROTASK_TYPE, LAST_MICROTASK_TYPE) \ + V(DataHandler, FIRST_DATA_HANDLER_TYPE, LAST_DATA_HANDLER_TYPE) \ + V(Struct, FIRST_STRUCT_TYPE, LAST_STRUCT_TYPE) \ + V(UncompiledDataWithPreparseData, FIRST_UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE, LAST_UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE) \ + V(UncompiledDataWithoutPreparseData, FIRST_UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE, LAST_UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \ + V(UncompiledData, FIRST_UNCOMPILED_DATA_TYPE, LAST_UNCOMPILED_DATA_TYPE) \ + V(RegExpData, FIRST_REG_EXP_DATA_TYPE, LAST_REG_EXP_DATA_TYPE) \ + V(WasmFunctionData, FIRST_WASM_FUNCTION_DATA_TYPE, LAST_WASM_FUNCTION_DATA_TYPE) \ + V(ExposedTrustedObject, FIRST_EXPOSED_TRUSTED_OBJECT_TYPE, LAST_EXPOSED_TRUSTED_OBJECT_TYPE) \ + V(TrustedFixedArrayBase, FIRST_TRUSTED_FIXED_ARRAY_BASE_TYPE, LAST_TRUSTED_FIXED_ARRAY_BASE_TYPE) \ + V(TrustedObject, FIRST_TRUSTED_OBJECT_TYPE, LAST_TRUSTED_OBJECT_TYPE) \ + V(HashTable, FIRST_HASH_TABLE_TYPE, LAST_HASH_TABLE_TYPE) \ + V(FixedArray, FIRST_FIXED_ARRAY_TYPE, LAST_FIXED_ARRAY_TYPE) \ + V(WeakFixedArray, FIRST_WEAK_FIXED_ARRAY_TYPE, LAST_WEAK_FIXED_ARRAY_TYPE) \ + V(FixedArrayBase, FIRST_FIXED_ARRAY_BASE_TYPE, LAST_FIXED_ARRAY_BASE_TYPE) \ + V(Context, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE) \ + V(TurboshaftFloat64Type, FIRST_TURBOSHAFT_FLOAT64_TYPE_TYPE, LAST_TURBOSHAFT_FLOAT64_TYPE_TYPE) \ + V(TurboshaftWord32Type, FIRST_TURBOSHAFT_WORD32_TYPE_TYPE, LAST_TURBOSHAFT_WORD32_TYPE_TYPE) \ + V(TurboshaftWord64Type, FIRST_TURBOSHAFT_WORD64_TYPE_TYPE, LAST_TURBOSHAFT_WORD64_TYPE_TYPE) \ + V(TurboshaftType, FIRST_TURBOSHAFT_TYPE_TYPE, LAST_TURBOSHAFT_TYPE_TYPE) \ + V(TurbofanType, FIRST_TURBOFAN_TYPE_TYPE, LAST_TURBOFAN_TYPE_TYPE) \ + V(SmallOrderedHashTable, FIRST_SMALL_ORDERED_HASH_TABLE_TYPE, LAST_SMALL_ORDERED_HASH_TABLE_TYPE) \ + V(TemplateInfoWithProperties, FIRST_TEMPLATE_INFO_WITH_PROPERTIES_TYPE, LAST_TEMPLATE_INFO_WITH_PROPERTIES_TYPE) \ + V(TemplateInfo, FIRST_TEMPLATE_INFO_TYPE, LAST_TEMPLATE_INFO_TYPE) \ + V(Map, FIRST_MAP_TYPE, LAST_MAP_TYPE) \ + V(Module, FIRST_MODULE_TYPE, LAST_MODULE_TYPE) \ + V(WasmObject, FIRST_WASM_OBJECT_TYPE, LAST_WASM_OBJECT_TYPE) \ + V(JSModuleNamespace, FIRST_JS_MODULE_NAMESPACE_TYPE, LAST_JS_MODULE_NAMESPACE_TYPE) \ + V(JSSpecialObject, FIRST_JS_SPECIAL_OBJECT_TYPE, LAST_JS_SPECIAL_OBJECT_TYPE) \ + V(JSCustomElementsObject, FIRST_JS_CUSTOM_ELEMENTS_OBJECT_TYPE, LAST_JS_CUSTOM_ELEMENTS_OBJECT_TYPE) \ + V(JSApiObject, FIRST_JS_API_OBJECT_TYPE, LAST_JS_API_OBJECT_TYPE) \ + V(JSDataViewOrRabGsabDataView, FIRST_JS_DATA_VIEW_OR_RAB_GSAB_DATA_VIEW_TYPE, LAST_JS_DATA_VIEW_OR_RAB_GSAB_DATA_VIEW_TYPE) \ + V(JSTypedArray, FIRST_JS_TYPED_ARRAY_TYPE, LAST_JS_TYPED_ARRAY_TYPE) \ + V(JSArrayBufferView, FIRST_JS_ARRAY_BUFFER_VIEW_TYPE, LAST_JS_ARRAY_BUFFER_VIEW_TYPE) \ + V(JSAPIObjectWithEmbedderSlots, FIRST_JS_APIOBJECT_WITH_EMBEDDER_SLOTS_TYPE, LAST_JS_APIOBJECT_WITH_EMBEDDER_SLOTS_TYPE) \ + V(TypedArrayConstructor, FIRST_TYPED_ARRAY_CONSTRUCTOR_TYPE, LAST_TYPED_ARRAY_CONSTRUCTOR_TYPE) \ + V(JSFunctionWithPrototype, FIRST_JS_FUNCTION_WITH_PROTOTYPE_TYPE, LAST_JS_FUNCTION_WITH_PROTOTYPE_TYPE) \ + V(JSFunction, FIRST_JS_FUNCTION_TYPE, LAST_JS_FUNCTION_TYPE) \ + V(JSFunctionOrBoundFunctionOrWrappedFunction, FIRST_JS_FUNCTION_OR_BOUND_FUNCTION_OR_WRAPPED_FUNCTION_TYPE, LAST_JS_FUNCTION_OR_BOUND_FUNCTION_OR_WRAPPED_FUNCTION_TYPE) \ + V(JSInternalPrototypeBase, FIRST_JS_INTERNAL_PROTOTYPE_BASE_TYPE, LAST_JS_INTERNAL_PROTOTYPE_BASE_TYPE) \ + V(JSIteratorHelperSimple, FIRST_JS_ITERATOR_HELPER_SIMPLE_TYPE, LAST_JS_ITERATOR_HELPER_SIMPLE_TYPE) \ + V(JSIteratorZipHelper, FIRST_JS_ITERATOR_ZIP_HELPER_TYPE, LAST_JS_ITERATOR_ZIP_HELPER_TYPE) \ + V(JSIteratorHelper, FIRST_JS_ITERATOR_HELPER_TYPE, LAST_JS_ITERATOR_HELPER_TYPE) \ + V(JSMapIterator, FIRST_JS_MAP_ITERATOR_TYPE, LAST_JS_MAP_ITERATOR_TYPE) \ + V(JSSetIterator, FIRST_JS_SET_ITERATOR_TYPE, LAST_JS_SET_ITERATOR_TYPE) \ + V(JSCollectionIterator, FIRST_JS_COLLECTION_ITERATOR_TYPE, LAST_JS_COLLECTION_ITERATOR_TYPE) \ + V(JSDisposableStackBase, FIRST_JS_DISPOSABLE_STACK_BASE_TYPE, LAST_JS_DISPOSABLE_STACK_BASE_TYPE) \ + V(JSGeneratorObject, FIRST_JS_GENERATOR_OBJECT_TYPE, LAST_JS_GENERATOR_OBJECT_TYPE) \ + V(AlwaysSharedSpaceJSObject, FIRST_ALWAYS_SHARED_SPACE_JS_OBJECT_TYPE, LAST_ALWAYS_SHARED_SPACE_JS_OBJECT_TYPE) \ + V(JSCollection, FIRST_JS_COLLECTION_TYPE, LAST_JS_COLLECTION_TYPE) \ + V(JSObjectWithEmbedderSlots, FIRST_JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE, LAST_JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE) \ + V(JSWeakCollection, FIRST_JS_WEAK_COLLECTION_TYPE, LAST_JS_WEAK_COLLECTION_TYPE) \ + V(JSObject, FIRST_JS_OBJECT_TYPE, LAST_JS_OBJECT_TYPE) \ + V(JSReceiver, FIRST_JS_RECEIVER_TYPE, LAST_JS_RECEIVER_TYPE) \ + +// Pairs of (ClassName, INSTANCE_TYPE) for the HeapObject +// diagnostic dispatch: the switches in HeapObject::HeapObjectPrint +// (objects-printer.cc) and HeapObject::HeapObjectVerify +// (objects-debug.cc). Included iff the class has its own +// instance-type value, declares both Name##Print and +// Name##Verify, and does not carry V8_IT_NO_AUTO_DISPATCH +// (hand-written dispatch cases). +#define HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST(V) \ + V(Symbol, SYMBOL_TYPE) \ + V(HeapNumber, HEAP_NUMBER_TYPE) \ + V(Oddball, ODDBALL_TYPE) \ + V(PromiseFulfillReactionJobTask, PROMISE_FULFILL_REACTION_JOB_TASK_TYPE) \ + V(PromiseRejectReactionJobTask, PROMISE_REJECT_REACTION_JOB_TASK_TYPE) \ + V(AsyncResumeTask, ASYNC_RESUME_TASK_TYPE) \ + V(CallableTask, CALLABLE_TASK_TYPE) \ + V(CallbackTask, CALLBACK_TASK_TYPE) \ + V(PromiseResolveThenableJobTask, PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \ + V(AccessCheckInfo, ACCESS_CHECK_INFO_TYPE) \ + V(AliasedArgumentsEntry, ALIASED_ARGUMENTS_ENTRY_TYPE) \ + V(AllocationMemento, ALLOCATION_MEMENTO_TYPE) \ + V(ArrayBoilerplateDescription, ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \ + V(AsyncGeneratorRequest, ASYNC_GENERATOR_REQUEST_TYPE) \ + V(BreakPoint, BREAK_POINT_TYPE) \ + V(BreakPointInfo, BREAK_POINT_INFO_TYPE) \ + V(BytecodeWrapper, BYTECODE_WRAPPER_TYPE) \ + V(CallSiteInfo, CALL_SITE_INFO_TYPE) \ + V(ClassBoilerplate, CLASS_BOILERPLATE_TYPE) \ + V(DebugScriptScopeInfo, DEBUG_SCRIPT_SCOPE_INFO_TYPE) \ + V(EnumCache, ENUM_CACHE_TYPE) \ + V(ErrorStackData, ERROR_STACK_DATA_TYPE) \ + V(FeedbackCell, FEEDBACK_CELL_TYPE) \ + V(ForInEnumeratorHolder, FOR_IN_ENUMERATOR_HOLDER_TYPE) \ + V(FunctionTemplateRareData, FUNCTION_TEMPLATE_RARE_DATA_TYPE) \ + V(ModuleRequest, MODULE_REQUEST_TYPE) \ + V(PromiseCapability, PROMISE_CAPABILITY_TYPE) \ + V(PromiseReaction, PROMISE_REACTION_TYPE) \ + V(PropertyDescriptorObject, PROPERTY_DESCRIPTOR_OBJECT_TYPE) \ + V(PrototypeInfo, PROTOTYPE_INFO_TYPE) \ + V(PrototypeSharedClosureInfo, PROTOTYPE_SHARED_CLOSURE_INFO_TYPE) \ + V(RegExpBoilerplateDescription, REG_EXP_BOILERPLATE_DESCRIPTION_TYPE) \ + V(RegExpDataWrapper, REG_EXP_DATA_WRAPPER_TYPE) \ + V(Script, SCRIPT_TYPE) \ + V(ScriptOrModule, SCRIPT_OR_MODULE_TYPE) \ + V(SourceTextModuleInfoEntry, SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE) \ + V(StackFrameInfo, STACK_FRAME_INFO_TYPE) \ + V(StackTraceInfo, STACK_TRACE_INFO_TYPE) \ + V(TemplateObjectDescription, TEMPLATE_OBJECT_DESCRIPTION_TYPE) \ + V(WasmExceptionTag, WASM_EXCEPTION_TAG_TYPE) \ + V(UncompiledDataWithPreparseData, UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE) \ + V(UncompiledDataWithPreparseDataAndJob, UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE) \ + V(UncompiledDataWithoutPreparseData, UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \ + V(UncompiledDataWithoutPreparseDataWithJob, UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE) \ + V(RegExpData, REG_EXP_DATA_TYPE) \ + V(AtomRegExpData, ATOM_REG_EXP_DATA_TYPE) \ + V(IrRegExpData, IR_REG_EXP_DATA_TYPE) \ + V(WasmFunctionData, WASM_FUNCTION_DATA_TYPE) \ + V(WasmCapiFunctionData, WASM_CAPI_FUNCTION_DATA_TYPE) \ + V(WasmExportedFunctionData, WASM_EXPORTED_FUNCTION_DATA_TYPE) \ + V(BytecodeArray, BYTECODE_ARRAY_TYPE) \ + V(DebugInfo, DEBUG_INFO_TYPE) \ + V(InterpreterData, INTERPRETER_DATA_TYPE) \ + V(WasmInternalFunction, WASM_INTERNAL_FUNCTION_TYPE) \ + V(WasmSuspenderObject, WASM_SUSPENDER_OBJECT_TYPE) \ + V(ProtectedFixedArray, PROTECTED_FIXED_ARRAY_TYPE) \ + V(ProtectedWeakFixedArray, PROTECTED_WEAK_FIXED_ARRAY_TYPE) \ + V(TrustedByteArray, TRUSTED_BYTE_ARRAY_TYPE) \ + V(TrustedFixedArray, TRUSTED_FIXED_ARRAY_TYPE) \ + V(TrustedWeakFixedArray, TRUSTED_WEAK_FIXED_ARRAY_TYPE) \ + V(SharedFunctionInfoWrapper, SHARED_FUNCTION_INFO_WRAPPER_TYPE) \ + V(TrustedForeign, TRUSTED_FOREIGN_TYPE) \ + V(WasmImportData, WASM_IMPORT_DATA_TYPE) \ + V(AccessorInfo, ACCESSOR_INFO_TYPE) \ + V(Foreign, FOREIGN_TYPE) \ + V(FixedArray, FIXED_ARRAY_TYPE) \ + V(WeakFixedArray, WEAK_FIXED_ARRAY_TYPE) \ + V(ByteArray, BYTE_ARRAY_TYPE) \ + V(ClosureFeedbackCellArray, CLOSURE_FEEDBACK_CELL_ARRAY_TYPE) \ + V(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE) \ + V(ObjectBoilerplateDescription, OBJECT_BOILERPLATE_DESCRIPTION_TYPE) \ + V(RegExpMatchInfo, REG_EXP_MATCH_INFO_TYPE) \ + V(SloppyArgumentsElements, SLOPPY_ARGUMENTS_ELEMENTS_TYPE) \ + V(WeakHomomorphicFixedArray, WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE) \ + V(TurboshaftFloat64RangeType, TURBOSHAFT_FLOAT64_RANGE_TYPE_TYPE) \ + V(TurboshaftFloat64SetType, TURBOSHAFT_FLOAT64_SET_TYPE_TYPE) \ + V(TurboshaftWord32RangeType, TURBOSHAFT_WORD32_RANGE_TYPE_TYPE) \ + V(TurboshaftWord32SetType, TURBOSHAFT_WORD32_SET_TYPE_TYPE) \ + V(TurboshaftWord64RangeType, TURBOSHAFT_WORD64_RANGE_TYPE_TYPE) \ + V(TurboshaftWord64SetType, TURBOSHAFT_WORD64_SET_TYPE_TYPE) \ + V(TurbofanBitsetType, TURBOFAN_BITSET_TYPE_TYPE) \ + V(TurbofanHeapConstantType, TURBOFAN_HEAP_CONSTANT_TYPE_TYPE) \ + V(TurbofanOtherNumberConstantType, TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE) \ + V(TurbofanRangeType, TURBOFAN_RANGE_TYPE_TYPE) \ + V(TurbofanUnionType, TURBOFAN_UNION_TYPE_TYPE) \ + V(SmallOrderedHashMap, SMALL_ORDERED_HASH_MAP_TYPE) \ + V(SmallOrderedHashSet, SMALL_ORDERED_HASH_SET_TYPE) \ + V(SmallOrderedNameDictionary, SMALL_ORDERED_NAME_DICTIONARY_TYPE) \ + V(FunctionTemplateInfo, FUNCTION_TEMPLATE_INFO_TYPE) \ + V(ObjectTemplateInfo, OBJECT_TEMPLATE_INFO_TYPE) \ + V(DictionaryTemplateInfo, DICTIONARY_TEMPLATE_INFO_TYPE) \ + V(Map, MAP_TYPE) \ + V(WasmCustomMap, WASM_CUSTOM_MAP_TYPE) \ + V(SourceTextModule, SOURCE_TEXT_MODULE_TYPE) \ + V(SyntheticModule, SYNTHETIC_MODULE_TYPE) \ + V(ArrayList, ARRAY_LIST_TYPE) \ + V(Cell, CELL_TYPE) \ + V(ContextCell, CONTEXT_CELL_TYPE) \ + V(CoverageInfo, COVERAGE_INFO_TYPE) \ + V(CppGCManagedBase, CPP_GCMANAGED_BASE_TYPE) \ + V(CppHeapExternalObject, CPP_HEAP_EXTERNAL_OBJECT_TYPE) \ + V(DescriptorArray, DESCRIPTOR_ARRAY_TYPE) \ + V(EmbedderDataArray, EMBEDDER_DATA_ARRAY_TYPE) \ + V(FeedbackMetadata, FEEDBACK_METADATA_TYPE) \ + V(FeedbackVector, FEEDBACK_VECTOR_TYPE) \ + V(InterceptorInfo, INTERCEPTOR_INFO_TYPE) \ + V(MegaDomHandler, MEGA_DOM_HANDLER_TYPE) \ + V(OnHeapBasicBlockProfilerData, ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE) \ + V(PreparseData, PREPARSE_DATA_TYPE) \ + V(PropertyArray, PROPERTY_ARRAY_TYPE) \ + V(PropertyCell, PROPERTY_CELL_TYPE) \ + V(ScopeInfo, SCOPE_INFO_TYPE) \ + V(ScriptContextTable, SCRIPT_CONTEXT_TABLE_TYPE) \ + V(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) \ + V(SortState, SORT_STATE_TYPE) \ + V(SwissNameDictionary, SWISS_NAME_DICTIONARY_TYPE) \ + V(UninitializedHeapNumber, UNINITIALIZED_HEAP_NUMBER_TYPE) \ + V(WasmContinuationObject, WASM_CONTINUATION_OBJECT_TYPE) \ + V(WasmFastApiCallData, WASM_FAST_API_CALL_DATA_TYPE) \ + V(WasmFuncRef, WASM_FUNC_REF_TYPE) \ + V(WasmResumeData, WASM_RESUME_DATA_TYPE) \ + V(WasmStackObject, WASM_STACK_OBJECT_TYPE) \ + V(WasmStringViewIter, WASM_STRING_VIEW_ITER_TYPE) \ + V(WasmTypeInfo, WASM_TYPE_INFO_TYPE) \ + V(WeakArrayList, WEAK_ARRAY_LIST_TYPE) \ + V(WeakCell, WEAK_CELL_TYPE) \ + V(WasmArray, WASM_ARRAY_TYPE) \ + V(WasmStruct, WASM_STRUCT_TYPE) \ + V(JSProxy, JS_PROXY_TYPE) \ + V(JSObject, JS_OBJECT_TYPE) \ + V(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) \ + V(JSDeferredModuleNamespace, JS_DEFERRED_MODULE_NAMESPACE_TYPE) \ + V(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE) \ + V(JSGlobalProxy, JS_GLOBAL_PROXY_TYPE) \ + V(JSPrimitiveWrapper, JS_PRIMITIVE_WRAPPER_TYPE) \ + V(JSDataView, JS_DATA_VIEW_TYPE) \ + V(JSRabGsabDataView, JS_RAB_GSAB_DATA_VIEW_TYPE) \ + V(JSTypedArray, JS_TYPED_ARRAY_TYPE) \ + V(JSDetachedTypedArray, JS_DETACHED_TYPED_ARRAY_TYPE) \ + V(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) \ + V(JSFunctionWithoutPrototype, JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE) \ + V(JSFunctionWithPrototype, JS_FUNCTION_WITH_PROTOTYPE_TYPE) \ + V(JSBoundFunction, JS_BOUND_FUNCTION_TYPE) \ + V(JSWrappedFunction, JS_WRAPPED_FUNCTION_TYPE) \ + V(JSIteratorConcatHelper, JS_ITERATOR_CONCAT_HELPER_TYPE) \ + V(JSIteratorDropHelper, JS_ITERATOR_DROP_HELPER_TYPE) \ + V(JSIteratorFilterHelper, JS_ITERATOR_FILTER_HELPER_TYPE) \ + V(JSIteratorFlatMapHelper, JS_ITERATOR_FLAT_MAP_HELPER_TYPE) \ + V(JSIteratorMapHelper, JS_ITERATOR_MAP_HELPER_TYPE) \ + V(JSIteratorTakeHelper, JS_ITERATOR_TAKE_HELPER_TYPE) \ + V(JSIteratorZipHelper, JS_ITERATOR_ZIP_HELPER_TYPE) \ + V(JSIteratorZipKeyedHelper, JS_ITERATOR_ZIP_KEYED_HELPER_TYPE) \ + V(JSDisposableStackBase, JS_DISPOSABLE_STACK_BASE_TYPE) \ + V(JSAsyncDisposableStack, JS_ASYNC_DISPOSABLE_STACK_TYPE) \ + V(JSSyncDisposableStack, JS_SYNC_DISPOSABLE_STACK_TYPE) \ + V(JSGeneratorObject, JS_GENERATOR_OBJECT_TYPE) \ + V(JSAsyncFunctionObject, JS_ASYNC_FUNCTION_OBJECT_TYPE) \ + V(JSAsyncGeneratorObject, JS_ASYNC_GENERATOR_OBJECT_TYPE) \ + V(JSSharedArray, JS_SHARED_ARRAY_TYPE) \ + V(JSSharedStruct, JS_SHARED_STRUCT_TYPE) \ + V(JSMap, JS_MAP_TYPE) \ + V(JSSet, JS_SET_TYPE) \ + V(JSObjectWithEmbedderSlots, JS_OBJECT_WITH_EMBEDDER_SLOTS_TYPE) \ + V(JSPromise, JS_PROMISE_TYPE) \ + V(JSWeakMap, JS_WEAK_MAP_TYPE) \ + V(JSWeakSet, JS_WEAK_SET_TYPE) \ + V(JSArgumentsObject, JS_ARGUMENTS_OBJECT_TYPE) \ + V(JSArray, JS_ARRAY_TYPE) \ + V(JSArrayIterator, JS_ARRAY_ITERATOR_TYPE) \ + V(JSAsyncFromSyncIterator, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE) \ + V(JSCollator, JS_COLLATOR_TYPE) \ + V(JSDate, JS_DATE_TYPE) \ + V(JSDateTimeFormat, JS_DATE_TIME_FORMAT_TYPE) \ + V(JSDisplayNames, JS_DISPLAY_NAMES_TYPE) \ + V(JSDurationFormat, JS_DURATION_FORMAT_TYPE) \ + V(JSExternalObject, JS_EXTERNAL_OBJECT_TYPE) \ + V(JSFinalizationRegistry, JS_FINALIZATION_REGISTRY_TYPE) \ + V(JSListFormat, JS_LIST_FORMAT_TYPE) \ + V(JSLocale, JS_LOCALE_TYPE) \ + V(JSMessageObject, JS_MESSAGE_OBJECT_TYPE) \ + V(JSNumberFormat, JS_NUMBER_FORMAT_TYPE) \ + V(JSPluralRules, JS_PLURAL_RULES_TYPE) \ + V(JSRawJson, JS_RAW_JSON_TYPE) \ + V(JSRegExp, JS_REG_EXP_TYPE) \ + V(JSRegExpStringIterator, JS_REG_EXP_STRING_ITERATOR_TYPE) \ + V(JSRelativeTimeFormat, JS_RELATIVE_TIME_FORMAT_TYPE) \ + V(JSSegmentIterator, JS_SEGMENT_ITERATOR_TYPE) \ + V(JSSegmenter, JS_SEGMENTER_TYPE) \ + V(JSSegments, JS_SEGMENTS_TYPE) \ + V(JSShadowRealm, JS_SHADOW_REALM_TYPE) \ + V(JSStringIterator, JS_STRING_ITERATOR_TYPE) \ + V(JSTemporalDuration, JS_TEMPORAL_DURATION_TYPE) \ + V(JSTemporalInstant, JS_TEMPORAL_INSTANT_TYPE) \ + V(JSTemporalPlainDate, JS_TEMPORAL_PLAIN_DATE_TYPE) \ + V(JSTemporalPlainDateTime, JS_TEMPORAL_PLAIN_DATE_TIME_TYPE) \ + V(JSTemporalPlainMonthDay, JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE) \ + V(JSTemporalPlainTime, JS_TEMPORAL_PLAIN_TIME_TYPE) \ + V(JSTemporalPlainYearMonth, JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE) \ + V(JSTemporalZonedDateTime, JS_TEMPORAL_ZONED_DATE_TIME_TYPE) \ + V(JSV8BreakIterator, JS_V8_BREAK_ITERATOR_TYPE) \ + V(JSValidIteratorWrapper, JS_VALID_ITERATOR_WRAPPER_TYPE) \ + V(JSWeakRef, JS_WEAK_REF_TYPE) \ + V(WasmCustomMapWrapper, WASM_CUSTOM_MAP_WRAPPER_TYPE) \ + V(WasmGlobalObject, WASM_GLOBAL_OBJECT_TYPE) \ + V(WasmInstanceObject, WASM_INSTANCE_OBJECT_TYPE) \ + V(WasmMemoryObject, WASM_MEMORY_OBJECT_TYPE) \ + V(WasmModuleObject, WASM_MODULE_OBJECT_TYPE) \ + V(WasmSuspendingObject, WASM_SUSPENDING_OBJECT_TYPE) \ + V(WasmTableObject, WASM_TABLE_OBJECT_TYPE) \ + V(WasmTagObject, WASM_TAG_OBJECT_TYPE) \ + +#endif // V8_GEN_METAGEN_INSTANCE_TYPES_H_ diff --git a/deps/v8/src/gen/intl-wasm/interface-descriptors.inc b/deps/v8/src/gen/intl-wasm/interface-descriptors.inc new file mode 100644 index 000000000000..d1d2173e9d39 --- /dev/null +++ b/deps/v8/src/gen/intl-wasm/interface-descriptors.inc @@ -0,0 +1,3492 @@ +class ArrayEveryLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayEveryLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kArray, kO, kInitialK, kLength, kInitialTo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayEveryLoopContinuationDescriptor) +}; + +class ArrayFilterLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayFilterLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kArray, kO, kInitialK, kLength, kInitialTo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayFilterLoopContinuationDescriptor) +}; + +class ArrayFindLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayFindLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kO, kInitialK, kLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayFindLoopContinuationDescriptor) +}; + +class ArrayFindIndexLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayFindIndexLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kO, kInitialK, kLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayFindIndexLoopContinuationDescriptor) +}; + +class ArrayFindLastLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayFindLastLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPredicate, kThisArg, kO, kInitialK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayFindLastLoopContinuationDescriptor) +}; + +class ArrayFindLastIndexLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayFindLastIndexLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPredicate, kThisArg, kO, kInitialK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayFindLastIndexLoopContinuationDescriptor) +}; + +class FlattenIntoArrayWithoutMapFnDescriptor : public StaticCallInterfaceDescriptor<FlattenIntoArrayWithoutMapFnDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTarget, kSource, kSourceLength, kStart, kDepth) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(FlattenIntoArrayWithoutMapFnDescriptor) +}; + +class FlattenIntoArrayWithMapFnDescriptor : public StaticCallInterfaceDescriptor<FlattenIntoArrayWithMapFnDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTarget, kSource, kSourceLength, kStart, kDepth, kMapfn, kThisArgs) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(FlattenIntoArrayWithMapFnDescriptor) +}; + +class ArrayForEachLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayForEachLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kArray, kO, kInitialK, kLen, kTo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayForEachLoopContinuationDescriptor) +}; + +class LoadJoinElement_DictionaryElements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinElement_DictionaryElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinElement_DictionaryElements_0Descriptor) +}; + +class LoadJoinElement_FastSmiOrObjectElements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinElement_FastSmiOrObjectElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinElement_FastSmiOrObjectElements_0Descriptor) +}; + +class LoadJoinElement_FastDoubleElements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinElement_FastDoubleElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinElement_FastDoubleElements_0Descriptor) +}; + +class ConvertToLocaleStringDescriptor : public StaticCallInterfaceDescriptor<ConvertToLocaleStringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kElement, kLocales, kOptions) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ConvertToLocaleStringDescriptor) +}; + +class JoinStackPushDescriptor : public StaticCallInterfaceDescriptor<JoinStackPushDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kStack, kReceiver) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(JoinStackPushDescriptor) +}; + +class JoinStackPopDescriptor : public StaticCallInterfaceDescriptor<JoinStackPopDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kStack, kReceiver) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(JoinStackPopDescriptor) +}; + +class ArrayPrototypeJoinImplDescriptor : public StaticCallInterfaceDescriptor<ArrayPrototypeJoinImplDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kO, kLen, kSeparator) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayPrototypeJoinImplDescriptor) +}; + +class ArrayMapLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayMapLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kArray, kO, kInitialK, kLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayMapLoopContinuationDescriptor) +}; + +class ArrayReduceRightLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayReduceRightLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kInitialAccumulator, kO, kInitialK, kLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayReduceRightLoopContinuationDescriptor) +}; + +class ArrayReduceLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayReduceLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kInitialAccumulator, kO, kInitialK, kLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayReduceLoopContinuationDescriptor) +}; + +class ArraySomeLoopContinuationDescriptor : public StaticCallInterfaceDescriptor<ArraySomeLoopContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCallbackfn, kThisArg, kArray, kO, kInitialK, kLength, kInitialTo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArraySomeLoopContinuationDescriptor) +}; + +class GenericArrayToReversedDescriptor : public StaticCallInterfaceDescriptor<GenericArrayToReversedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GenericArrayToReversedDescriptor) +}; + +class ArrayPowerSortIntoCopyDescriptor : public StaticCallInterfaceDescriptor<ArrayPowerSortIntoCopyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayPowerSortIntoCopyDescriptor) +}; + +class GenericArrayWithDescriptor : public StaticCallInterfaceDescriptor<GenericArrayWithDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kLen, kActualIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GenericArrayWithDescriptor) +}; + +class ToIntegerDescriptor : public StaticCallInterfaceDescriptor<ToIntegerDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToIntegerDescriptor) +}; + +class FastCreateDataPropertyDescriptor : public StaticCallInterfaceDescriptor<FastCreateDataPropertyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kKey, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(FastCreateDataPropertyDescriptor) +}; + +class BigIntAddNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntAddNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntAddNoThrowDescriptor) +}; + +class BigIntAddDescriptor : public StaticCallInterfaceDescriptor<BigIntAddDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntAddDescriptor) +}; + +class BigIntSubtractNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntSubtractNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntSubtractNoThrowDescriptor) +}; + +class BigIntSubtractDescriptor : public StaticCallInterfaceDescriptor<BigIntSubtractDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntSubtractDescriptor) +}; + +class BigIntMultiplyNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntMultiplyNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntMultiplyNoThrowDescriptor) +}; + +class BigIntMultiplyDescriptor : public StaticCallInterfaceDescriptor<BigIntMultiplyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntMultiplyDescriptor) +}; + +class BigIntDivideNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntDivideNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntDivideNoThrowDescriptor) +}; + +class BigIntDivideDescriptor : public StaticCallInterfaceDescriptor<BigIntDivideDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntDivideDescriptor) +}; + +class BigIntModulusNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntModulusNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntModulusNoThrowDescriptor) +}; + +class BigIntModulusDescriptor : public StaticCallInterfaceDescriptor<BigIntModulusDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntModulusDescriptor) +}; + +class BigIntBitwiseAndNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntBitwiseAndNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntBitwiseAndNoThrowDescriptor) +}; + +class BigIntBitwiseAndDescriptor : public StaticCallInterfaceDescriptor<BigIntBitwiseAndDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntBitwiseAndDescriptor) +}; + +class BigIntBitwiseOrNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntBitwiseOrNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntBitwiseOrNoThrowDescriptor) +}; + +class BigIntBitwiseOrDescriptor : public StaticCallInterfaceDescriptor<BigIntBitwiseOrDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntBitwiseOrDescriptor) +}; + +class BigIntBitwiseXorNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntBitwiseXorNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntBitwiseXorNoThrowDescriptor) +}; + +class BigIntBitwiseXorDescriptor : public StaticCallInterfaceDescriptor<BigIntBitwiseXorDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntBitwiseXorDescriptor) +}; + +class BigIntShiftLeftNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntShiftLeftNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntShiftLeftNoThrowDescriptor) +}; + +class BigIntShiftLeftDescriptor : public StaticCallInterfaceDescriptor<BigIntShiftLeftDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntShiftLeftDescriptor) +}; + +class BigIntShiftRightNoThrowDescriptor : public StaticCallInterfaceDescriptor<BigIntShiftRightNoThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntShiftRightNoThrowDescriptor) +}; + +class BigIntShiftRightDescriptor : public StaticCallInterfaceDescriptor<BigIntShiftRightDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kXNum, kYNum) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntShiftRightDescriptor) +}; + +class BigIntEqualDescriptor : public StaticCallInterfaceDescriptor<BigIntEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntEqualDescriptor) +}; + +class BigIntLessThanDescriptor : public StaticCallInterfaceDescriptor<BigIntLessThanDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntLessThanDescriptor) +}; + +class BigIntGreaterThanDescriptor : public StaticCallInterfaceDescriptor<BigIntGreaterThanDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntGreaterThanDescriptor) +}; + +class BigIntLessThanOrEqualDescriptor : public StaticCallInterfaceDescriptor<BigIntLessThanOrEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntLessThanOrEqualDescriptor) +}; + +class BigIntGreaterThanOrEqualDescriptor : public StaticCallInterfaceDescriptor<BigIntGreaterThanOrEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntGreaterThanOrEqualDescriptor) +}; + +class BigIntUnaryMinusDescriptor : public StaticCallInterfaceDescriptor<BigIntUnaryMinusDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kBigint) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(BigIntUnaryMinusDescriptor) +}; + +class ToStringDescriptor : public StaticCallInterfaceDescriptor<ToStringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kO) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToStringDescriptor) +}; + +class ToStringConvertSymbolDescriptor : public StaticCallInterfaceDescriptor<ToStringConvertSymbolDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kO) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToStringConvertSymbolDescriptor) +}; + +class StringToListDescriptor : public StaticCallInterfaceDescriptor<StringToListDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(StringToListDescriptor) +}; + +class StringAddConvertLeftDescriptor : public StaticCallInterfaceDescriptor<StringAddConvertLeftDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(StringAddConvertLeftDescriptor) +}; + +class StringAddConvertRightDescriptor : public StaticCallInterfaceDescriptor<StringAddConvertRightDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StringAddConvertRightDescriptor) +}; + +class StringCharAtDescriptor : public StaticCallInterfaceDescriptor<StringCharAtDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kPosition) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(StringCharAtDescriptor) +}; + +class FastNewClosureBaselineDescriptor : public StaticCallInterfaceDescriptor<FastNewClosureBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kSharedFunctionInfo, kFeedbackCell) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(FastNewClosureBaselineDescriptor) +}; + +class FastNewFunctionContextEvalDescriptor : public StaticCallInterfaceDescriptor<FastNewFunctionContextEvalDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kScopeInfo, kSlots) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(FastNewFunctionContextEvalDescriptor) +}; + +class FastNewFunctionContextFunctionDescriptor : public StaticCallInterfaceDescriptor<FastNewFunctionContextFunctionDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kScopeInfo, kSlots) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(FastNewFunctionContextFunctionDescriptor) +}; + +class FastNewFunctionContextFunctionWithCellsDescriptor : public StaticCallInterfaceDescriptor<FastNewFunctionContextFunctionWithCellsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kScopeInfo, kSlots) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(FastNewFunctionContextFunctionWithCellsDescriptor) +}; + +class CreateRegExpLiteralDescriptor : public StaticCallInterfaceDescriptor<CreateRegExpLiteralDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kMaybeFeedbackVector, kSlot, kPattern, kFlags) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CreateRegExpLiteralDescriptor) +}; + +class CreateShallowArrayLiteralDescriptor : public StaticCallInterfaceDescriptor<CreateShallowArrayLiteralDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kMaybeFeedbackVector, kSlot, kConstantElements, kFlags) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CreateShallowArrayLiteralDescriptor) +}; + +class CreateEmptyArrayLiteralDescriptor : public StaticCallInterfaceDescriptor<CreateEmptyArrayLiteralDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kFeedbackVector, kSlot) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CreateEmptyArrayLiteralDescriptor) +}; + +class CreateShallowObjectLiteralDescriptor : public StaticCallInterfaceDescriptor<CreateShallowObjectLiteralDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kMaybeFeedbackVector, kSlot, kDesc, kFlags) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CreateShallowObjectLiteralDescriptor) +}; + +class CreateEmptyLiteralObjectDescriptor : public StaticCallInterfaceDescriptor<CreateEmptyLiteralObjectDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CreateEmptyLiteralObjectDescriptor) +}; + +class StringToNumberDescriptor : public StaticCallInterfaceDescriptor<StringToNumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(StringToNumberDescriptor) +}; + +class NonNumberToNumberDescriptor : public StaticCallInterfaceDescriptor<NonNumberToNumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(NonNumberToNumberDescriptor) +}; + +class NonNumberToNumericDescriptor : public StaticCallInterfaceDescriptor<NonNumberToNumericDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(NonNumberToNumericDescriptor) +}; + +class ToNumericDescriptor : public StaticCallInterfaceDescriptor<ToNumericDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToNumericDescriptor) +}; + +class NumberToStringDescriptor : public StaticCallInterfaceDescriptor<NumberToStringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(NumberToStringDescriptor) +}; + +class SmiToStringDescriptor : public StaticCallInterfaceDescriptor<SmiToStringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(SmiToStringDescriptor) +}; + +class Int32ToStringDescriptor : public StaticCallInterfaceDescriptor<Int32ToStringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(Int32ToStringDescriptor) +}; + +class ToBooleanDescriptor : public StaticCallInterfaceDescriptor<ToBooleanDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToBooleanDescriptor) +}; + +class ToBooleanForBaselineJumpDescriptor : public StaticCallInterfaceDescriptor<ToBooleanForBaselineJumpDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(2, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToBooleanForBaselineJumpDescriptor) +}; + +class ToLengthDescriptor : public StaticCallInterfaceDescriptor<ToLengthDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToLengthDescriptor) +}; + +class ToNameDescriptor : public StaticCallInterfaceDescriptor<ToNameDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToNameDescriptor) +}; + +class ToObjectDescriptor : public StaticCallInterfaceDescriptor<ToObjectDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ToObjectDescriptor) +}; + +class NonPrimitiveToPrimitive_DefaultDescriptor : public StaticCallInterfaceDescriptor<NonPrimitiveToPrimitive_DefaultDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(NonPrimitiveToPrimitive_DefaultDescriptor) +}; + +class NonPrimitiveToPrimitive_NumberDescriptor : public StaticCallInterfaceDescriptor<NonPrimitiveToPrimitive_NumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(NonPrimitiveToPrimitive_NumberDescriptor) +}; + +class NonPrimitiveToPrimitive_StringDescriptor : public StaticCallInterfaceDescriptor<NonPrimitiveToPrimitive_StringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(NonPrimitiveToPrimitive_StringDescriptor) +}; + +class OrdinaryToPrimitive_NumberDescriptor : public StaticCallInterfaceDescriptor<OrdinaryToPrimitive_NumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(OrdinaryToPrimitive_NumberDescriptor) +}; + +class OrdinaryToPrimitive_Number_InlineDescriptor : public StaticCallInterfaceDescriptor<OrdinaryToPrimitive_Number_InlineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(OrdinaryToPrimitive_Number_InlineDescriptor) +}; + +class OrdinaryToPrimitive_StringDescriptor : public StaticCallInterfaceDescriptor<OrdinaryToPrimitive_StringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(OrdinaryToPrimitive_StringDescriptor) +}; + +class IncBlockCounterDescriptor : public StaticCallInterfaceDescriptor<IncBlockCounterDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kFunction, kCoverageArraySlotIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(IncBlockCounterDescriptor) +}; + +class GetTemplateObjectDescriptor : public StaticCallInterfaceDescriptor<GetTemplateObjectDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kShared, kDescription, kSlot, kMaybeFeedbackVector) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(GetTemplateObjectDescriptor) +}; + +class ForInNextDescriptor : public StaticCallInterfaceDescriptor<ForInNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSlot, kReceiver, kCacheArray, kCacheType, kCacheIndex, kFeedbackVector) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<UintPtrT>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ForInNextDescriptor) +}; + +class GetImportMetaObjectBaselineDescriptor : public StaticCallInterfaceDescriptor<GetImportMetaObjectBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GetImportMetaObjectBaselineDescriptor) +}; + +class GetIteratorWithFeedbackDescriptor : public StaticCallInterfaceDescriptor<GetIteratorWithFeedbackDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kLoadSlot, kCallSlot, kMaybeFeedbackVector) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(GetIteratorWithFeedbackDescriptor) +}; + +class GetIteratorBaselineDescriptor : public StaticCallInterfaceDescriptor<GetIteratorBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kReceiver, kLoadSlot, kCallSlot) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GetIteratorBaselineDescriptor) +}; + +class CreateAsyncFromSyncIteratorBaselineDescriptor : public StaticCallInterfaceDescriptor<CreateAsyncFromSyncIteratorBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kSyncIterator) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CreateAsyncFromSyncIteratorBaselineDescriptor) +}; + +class ForOfNextDescriptor : public StaticCallInterfaceDescriptor<ForOfNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kIterator, kNext, kFeedbackVector, kCallSlot) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(ForOfNextDescriptor) +}; + +class ForOfNextBaselineDescriptor : public StaticCallInterfaceDescriptor<ForOfNextBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kIterator, kNext, kCallSlot) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(ForOfNextBaselineDescriptor) +}; + +class CallIteratorWithFeedbackDescriptor : public StaticCallInterfaceDescriptor<CallIteratorWithFeedbackDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kIteratorMethod, kCallSlot, kFeedback) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(CallIteratorWithFeedbackDescriptor) +}; + +class IteratorCloseDescriptor : public StaticCallInterfaceDescriptor<IteratorCloseDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kIterator) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorCloseDescriptor) +}; + +class ArrayDestructureDescriptor : public StaticCallInterfaceDescriptor<ArrayDestructureDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kCount, kFirstRegAddr) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineTypeOf<Int32T>::value, MachineTypeOf<RawPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(ArrayDestructureDescriptor) +}; + +class ArrayDestructureLazyDeoptContinuationDescriptor : public StaticCallInterfaceDescriptor<ArrayDestructureLazyDeoptContinuationDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kIteratorArg, kNextMethodArg, kIndex, kFirstReg, kCount, kDeoptValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayDestructureLazyDeoptContinuationDescriptor) +}; + +class IteratorMapHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorMapHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorMapHelperNextDescriptor) +}; + +class IteratorFilterHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorFilterHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorFilterHelperNextDescriptor) +}; + +class IteratorTakeHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorTakeHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorTakeHelperNextDescriptor) +}; + +class IteratorDropHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorDropHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorDropHelperNextDescriptor) +}; + +class IteratorFlatMapHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorFlatMapHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorFlatMapHelperNextDescriptor) +}; + +class IteratorConcatHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorConcatHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorConcatHelperNextDescriptor) +}; + +class IteratorZipHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorZipHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorZipHelperNextDescriptor) +}; + +class IteratorZipKeyedHelperNextDescriptor : public StaticCallInterfaceDescriptor<IteratorZipKeyedHelperNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kHelper) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(IteratorZipKeyedHelperNextDescriptor) +}; + +class ParseIntDescriptor : public StaticCallInterfaceDescriptor<ParseIntDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kInput, kRadix) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ParseIntDescriptor) +}; + +class AddDescriptor : public StaticCallInterfaceDescriptor<AddDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeftArg, kRightArg) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(AddDescriptor) +}; + +class SubtractDescriptor : public StaticCallInterfaceDescriptor<SubtractDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(SubtractDescriptor) +}; + +class MultiplyDescriptor : public StaticCallInterfaceDescriptor<MultiplyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(MultiplyDescriptor) +}; + +class DivideDescriptor : public StaticCallInterfaceDescriptor<DivideDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(DivideDescriptor) +}; + +class ModulusDescriptor : public StaticCallInterfaceDescriptor<ModulusDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ModulusDescriptor) +}; + +class ExponentiateDescriptor : public StaticCallInterfaceDescriptor<ExponentiateDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ExponentiateDescriptor) +}; + +class NegateDescriptor : public StaticCallInterfaceDescriptor<NegateDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(NegateDescriptor) +}; + +class BitwiseNotDescriptor : public StaticCallInterfaceDescriptor<BitwiseNotDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BitwiseNotDescriptor) +}; + +class DecrementDescriptor : public StaticCallInterfaceDescriptor<DecrementDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(DecrementDescriptor) +}; + +class IncrementDescriptor : public StaticCallInterfaceDescriptor<IncrementDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(IncrementDescriptor) +}; + +class ShiftLeftDescriptor : public StaticCallInterfaceDescriptor<ShiftLeftDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ShiftLeftDescriptor) +}; + +class ShiftRightDescriptor : public StaticCallInterfaceDescriptor<ShiftRightDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ShiftRightDescriptor) +}; + +class ShiftRightLogicalDescriptor : public StaticCallInterfaceDescriptor<ShiftRightLogicalDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ShiftRightLogicalDescriptor) +}; + +class BitwiseAndDescriptor : public StaticCallInterfaceDescriptor<BitwiseAndDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BitwiseAndDescriptor) +}; + +class BitwiseOrDescriptor : public StaticCallInterfaceDescriptor<BitwiseOrDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BitwiseOrDescriptor) +}; + +class BitwiseXorDescriptor : public StaticCallInterfaceDescriptor<BitwiseXorDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(BitwiseXorDescriptor) +}; + +class LessThanDescriptor : public StaticCallInterfaceDescriptor<LessThanDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(LessThanDescriptor) +}; + +class LessThanOrEqualDescriptor : public StaticCallInterfaceDescriptor<LessThanOrEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(LessThanOrEqualDescriptor) +}; + +class GreaterThanDescriptor : public StaticCallInterfaceDescriptor<GreaterThanDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GreaterThanDescriptor) +}; + +class GreaterThanOrEqualDescriptor : public StaticCallInterfaceDescriptor<GreaterThanOrEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GreaterThanOrEqualDescriptor) +}; + +class EqualDescriptor : public StaticCallInterfaceDescriptor<EqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(EqualDescriptor) +}; + +class StrictEqualDescriptor : public StaticCallInterfaceDescriptor<StrictEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLeft, kRight) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StrictEqualDescriptor) +}; + +class GroupByGenericDescriptor : public StaticCallInterfaceDescriptor<GroupByGenericDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kItems, kInitialGroups, kCallbackfn, kCoerceToProperty, kMethodName) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(GroupByGenericDescriptor) +}; + +class CreateObjectWithoutPropertiesDescriptor : public StaticCallInterfaceDescriptor<CreateObjectWithoutPropertiesDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPrototype) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CreateObjectWithoutPropertiesDescriptor) +}; + +class FulfillPromiseDescriptor : public StaticCallInterfaceDescriptor<FulfillPromiseDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPromise, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(FulfillPromiseDescriptor) +}; + +class RejectPromiseDescriptor : public StaticCallInterfaceDescriptor<RejectPromiseDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPromise, kReason, kDebugEvent) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(RejectPromiseDescriptor) +}; + +class NewPromiseCapabilityDescriptor : public StaticCallInterfaceDescriptor<NewPromiseCapabilityDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kMaybeConstructor, kDebugEvent) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(NewPromiseCapabilityDescriptor) +}; + +class PerformPromiseThenDescriptor : public StaticCallInterfaceDescriptor<PerformPromiseThenDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPromise, kOnFulfilled, kOnRejected, kResultPromise) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(PerformPromiseThenDescriptor) +}; + +class PromiseResolveThenableJobDescriptor : public StaticCallInterfaceDescriptor<PromiseResolveThenableJobDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPromiseToResolve, kThenable, kThen) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(PromiseResolveThenableJobDescriptor) +}; + +class AsyncAwaitNonThenableFastPathDescriptor : public StaticCallInterfaceDescriptor<AsyncAwaitNonThenableFastPathDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue, kOnResolve, kThrowaway) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(AsyncAwaitNonThenableFastPathDescriptor) +}; + +class PromiseFulfillReactionJobDescriptor : public StaticCallInterfaceDescriptor<PromiseFulfillReactionJobDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue, kHandler, kPromiseOrCapability) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(PromiseFulfillReactionJobDescriptor) +}; + +class PromiseRejectReactionJobDescriptor : public StaticCallInterfaceDescriptor<PromiseRejectReactionJobDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReason, kHandler, kPromiseOrCapability) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(PromiseRejectReactionJobDescriptor) +}; + +class PromiseResolveDescriptor : public StaticCallInterfaceDescriptor<PromiseResolveDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kConstructor, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(PromiseResolveDescriptor) +}; + +class ResolvePromiseDescriptor : public StaticCallInterfaceDescriptor<ResolvePromiseDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPromise, kResolution) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ResolvePromiseDescriptor) +}; + +class ProxyDeletePropertyDescriptor : public StaticCallInterfaceDescriptor<ProxyDeletePropertyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy, kName, kLanguageMode) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(ProxyDeletePropertyDescriptor) +}; + +class ProxyGetPropertyDescriptor : public StaticCallInterfaceDescriptor<ProxyGetPropertyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy, kName, kReceiverValue, kOnNonExistent) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(ProxyGetPropertyDescriptor) +}; + +class ProxyGetPrototypeOfDescriptor : public StaticCallInterfaceDescriptor<ProxyGetPrototypeOfDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ProxyGetPrototypeOfDescriptor) +}; + +class ProxyHasPropertyDescriptor : public StaticCallInterfaceDescriptor<ProxyHasPropertyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy, kName) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ProxyHasPropertyDescriptor) +}; + +class ProxyIsExtensibleDescriptor : public StaticCallInterfaceDescriptor<ProxyIsExtensibleDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ProxyIsExtensibleDescriptor) +}; + +class ProxyPreventExtensionsDescriptor : public StaticCallInterfaceDescriptor<ProxyPreventExtensionsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy, kDoThrow) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ProxyPreventExtensionsDescriptor) +}; + +class ProxySetPropertyDescriptor : public StaticCallInterfaceDescriptor<ProxySetPropertyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy, kName, kValue, kReceiverValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ProxySetPropertyDescriptor) +}; + +class ProxySetPrototypeOfDescriptor : public StaticCallInterfaceDescriptor<ProxySetPrototypeOfDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kProxy, kProto, kDoThrow) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ProxySetPrototypeOfDescriptor) +}; + +class RegExpPrototypeExecSlowDescriptor : public StaticCallInterfaceDescriptor<RegExpPrototypeExecSlowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kRegexp, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(RegExpPrototypeExecSlowDescriptor) +}; + +class RegExpMatchFastDescriptor : public StaticCallInterfaceDescriptor<RegExpMatchFastDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(RegExpMatchFastDescriptor) +}; + +class RegExpReplaceDescriptor : public StaticCallInterfaceDescriptor<RegExpReplaceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kRegexp, kString, kReplaceValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(RegExpReplaceDescriptor) +}; + +class RegExpSearchFastDescriptor : public StaticCallInterfaceDescriptor<RegExpSearchFastDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(RegExpSearchFastDescriptor) +}; + +class RegExpSplitDescriptor : public StaticCallInterfaceDescriptor<RegExpSplitDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kRegexp, kString, kLimit) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(RegExpSplitDescriptor) +}; + +class RegExpPrototypeTestFastDescriptor : public StaticCallInterfaceDescriptor<RegExpPrototypeTestFastDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(RegExpPrototypeTestFastDescriptor) +}; + +class CreateHTMLDescriptor : public StaticCallInterfaceDescriptor<CreateHTMLDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kMethodName, kTagName, kAttr, kAttrValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CreateHTMLDescriptor) +}; + +class StringRepeatDescriptor : public StaticCallInterfaceDescriptor<StringRepeatDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kString, kCount) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(StringRepeatDescriptor) +}; + +class CreateTypedArrayDescriptor : public StaticCallInterfaceDescriptor<CreateTypedArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTarget, kNewTarget, kArg1, kArg2, kArg3) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CreateTypedArrayDescriptor) +}; + +class TypedArrayMergeSortDescriptor : public StaticCallInterfaceDescriptor<TypedArrayMergeSortDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSource, kFrom, kTo, kTarget, kArray, kComparefn) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineTypeOf<UintPtrT>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(TypedArrayMergeSortDescriptor) +}; + +class NewSloppyArgumentsElementsDescriptor : public StaticCallInterfaceDescriptor<NewSloppyArgumentsElementsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kFrame, kFormalParameterCount, kArgumentCount) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<RawPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(NewSloppyArgumentsElementsDescriptor) +}; + +class NewStrictArgumentsElementsDescriptor : public StaticCallInterfaceDescriptor<NewStrictArgumentsElementsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kFrame, kFormalParameterCount, kArgumentCount) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<RawPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(NewStrictArgumentsElementsDescriptor) +}; + +class NewRestArgumentsElementsDescriptor : public StaticCallInterfaceDescriptor<NewRestArgumentsElementsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kFrame, kFormalParameterCount, kArgumentCount) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<RawPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(NewRestArgumentsElementsDescriptor) +}; + +class FastNewSloppyArgumentsDescriptor : public StaticCallInterfaceDescriptor<FastNewSloppyArgumentsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kF) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(FastNewSloppyArgumentsDescriptor) +}; + +class FastNewStrictArgumentsDescriptor : public StaticCallInterfaceDescriptor<FastNewStrictArgumentsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kF) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(FastNewStrictArgumentsDescriptor) +}; + +class FastNewRestArgumentsDescriptor : public StaticCallInterfaceDescriptor<FastNewRestArgumentsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kF) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(FastNewRestArgumentsDescriptor) +}; + +class LoadFromContextCellDescriptor : public StaticCallInterfaceDescriptor<LoadFromContextCellDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kN, kC, kI) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(LoadFromContextCellDescriptor) +}; + +class StoreCurrentContextElementBaselineDescriptor : public StaticCallInterfaceDescriptor<StoreCurrentContextElementBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kO, kI) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(StoreCurrentContextElementBaselineDescriptor) +}; + +class StoreContextElementBaselineDescriptor : public StaticCallInterfaceDescriptor<StoreContextElementBaselineDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kC, kO, kI, kD) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreContextElementBaselineDescriptor) +}; + +class DetachContextCellDescriptor : public StaticCallInterfaceDescriptor<DetachContextCellDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTheContext, kNewValue, kI) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(DetachContextCellDescriptor) +}; + +class StringSlowFlattenDescriptor : public StaticCallInterfaceDescriptor<StringSlowFlattenDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kCons) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(StringSlowFlattenDescriptor) +}; + +class StringIndexOfDescriptor : public StaticCallInterfaceDescriptor<StringIndexOfDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kS, kSearchString, kStart) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(StringIndexOfDescriptor) +}; + +class TestTurbofanTypeDescriptor : public StaticCallInterfaceDescriptor<TestTurbofanTypeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue, kExpectedType) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(TestTurbofanTypeDescriptor) +}; + +class CheckTurbofanTypeDescriptor : public StaticCallInterfaceDescriptor<CheckTurbofanTypeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue, kExpectedType, kNodeId) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CheckTurbofanTypeDescriptor) +}; + +class CheckTurboshaftWord32TypeDescriptor : public StaticCallInterfaceDescriptor<CheckTurboshaftWord32TypeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValue, kExpectedType, kNodeId) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CheckTurboshaftWord32TypeDescriptor) +}; + +class CheckTurboshaftWord64TypeDescriptor : public StaticCallInterfaceDescriptor<CheckTurboshaftWord64TypeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kValueHigh, kValueLow, kExpectedType, kNodeId) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CheckTurboshaftWord64TypeDescriptor) +}; + +class DebugPrintObjectDescriptor : public StaticCallInterfaceDescriptor<DebugPrintObjectDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kPrefix, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(DebugPrintObjectDescriptor) +}; + +class GenericBuiltinTest_JSAny_0Descriptor : public StaticCallInterfaceDescriptor<GenericBuiltinTest_JSAny_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kParam) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(GenericBuiltinTest_JSAny_0Descriptor) +}; + +class TestHelperPlus1Descriptor : public StaticCallInterfaceDescriptor<TestHelperPlus1Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kX) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(TestHelperPlus1Descriptor) +}; + +class TestHelperPlus2Descriptor : public StaticCallInterfaceDescriptor<TestHelperPlus2Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kX) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(TestHelperPlus2Descriptor) +}; + +class ReturnTwoValuesDescriptor : public StaticCallInterfaceDescriptor<ReturnTwoValuesDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(2, kValue, kObj) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ReturnTwoValuesDescriptor) +}; + +class ThrowAsBuiltinDescriptor : public StaticCallInterfaceDescriptor<ThrowAsBuiltinDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(0, kStr) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowAsBuiltinDescriptor) +}; + +class TestCallNeverDescriptor : public StaticCallInterfaceDescriptor<TestCallNeverDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kA) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(TestCallNeverDescriptor) +}; + +class TestIncrementArraySpeciesModifiedDescriptor : public StaticCallInterfaceDescriptor<TestIncrementArraySpeciesModifiedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(TestIncrementArraySpeciesModifiedDescriptor) +}; + +class Load_FastSmiElements_0Descriptor : public StaticCallInterfaceDescriptor<Load_FastSmiElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Load_FastSmiElements_0Descriptor) +}; + +class Load_FastObjectElements_0Descriptor : public StaticCallInterfaceDescriptor<Load_FastObjectElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Load_FastObjectElements_0Descriptor) +}; + +class Load_FastDoubleElements_0Descriptor : public StaticCallInterfaceDescriptor<Load_FastDoubleElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Load_FastDoubleElements_0Descriptor) +}; + +class Store_FastSmiElements_0Descriptor : public StaticCallInterfaceDescriptor<Store_FastSmiElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(Store_FastSmiElements_0Descriptor) +}; + +class Store_FastObjectElements_0Descriptor : public StaticCallInterfaceDescriptor<Store_FastObjectElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(Store_FastObjectElements_0Descriptor) +}; + +class Store_FastDoubleElements_0Descriptor : public StaticCallInterfaceDescriptor<Store_FastDoubleElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(Store_FastDoubleElements_0Descriptor) +}; + +class Delete_FastSmiElements_0Descriptor : public StaticCallInterfaceDescriptor<Delete_FastSmiElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Delete_FastSmiElements_0Descriptor) +}; + +class Delete_FastObjectElements_0Descriptor : public StaticCallInterfaceDescriptor<Delete_FastObjectElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Delete_FastObjectElements_0Descriptor) +}; + +class Delete_FastDoubleElements_0Descriptor : public StaticCallInterfaceDescriptor<Delete_FastDoubleElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Delete_FastDoubleElements_0Descriptor) +}; + +class SortCompareDefaultDescriptor : public StaticCallInterfaceDescriptor<SortCompareDefaultDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kComparefn, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(SortCompareDefaultDescriptor) +}; + +class SortCompareUserFnDescriptor : public StaticCallInterfaceDescriptor<SortCompareUserFnDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kComparefn, kX, kY) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(SortCompareUserFnDescriptor) +}; + +class CanUseSameAccessor_GenericElementsAccessor_0Descriptor : public StaticCallInterfaceDescriptor<CanUseSameAccessor_GenericElementsAccessor_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kInitialReceiverMap, kInitialReceiverLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CanUseSameAccessor_GenericElementsAccessor_0Descriptor) +}; + +class CopyDescriptor : public StaticCallInterfaceDescriptor<CopyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSource, kSrcPos, kTarget, kDstPos, kLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(CopyDescriptor) +}; + +class MergeAtDescriptor : public StaticCallInterfaceDescriptor<MergeAtDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kI) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(MergeAtDescriptor) +}; + +class GallopLeftDescriptor : public StaticCallInterfaceDescriptor<GallopLeftDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kArray, kKey, kBase, kLength, kHint) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(GallopLeftDescriptor) +}; + +class GallopRightDescriptor : public StaticCallInterfaceDescriptor<GallopRightDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kArray, kKey, kBase, kLength, kHint) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(GallopRightDescriptor) +}; + +class ArrayPowerSortDescriptor : public StaticCallInterfaceDescriptor<ArrayPowerSortDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(ArrayPowerSortDescriptor) +}; + +class StringFastLocaleCompareDescriptor : public StaticCallInterfaceDescriptor<StringFastLocaleCompareDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kLocaleCompareFn, kLeft, kRight, kLocales) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StringFastLocaleCompareDescriptor) +}; + +class JSToWasmHandleReturnsDescriptor : public StaticCallInterfaceDescriptor<JSToWasmHandleReturnsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kJsContext, kResultArray, kWrapperBuffer) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<RawPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(JSToWasmHandleReturnsDescriptor) +}; + +class WasmInt32ToHeapNumberDescriptor : public StaticCallInterfaceDescriptor<WasmInt32ToHeapNumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kVal) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmInt32ToHeapNumberDescriptor) +}; + +class WasmInt32ToSharedHeapNumberDescriptor : public StaticCallInterfaceDescriptor<WasmInt32ToSharedHeapNumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kVal) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmInt32ToSharedHeapNumberDescriptor) +}; + +class WasmFuncRefToJSDescriptor : public StaticCallInterfaceDescriptor<WasmFuncRefToJSDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kVal) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmFuncRefToJSDescriptor) +}; + +class WasmTaggedNonSmiToInt32Descriptor : public StaticCallInterfaceDescriptor<WasmTaggedNonSmiToInt32Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kVal) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTaggedNonSmiToInt32Descriptor) +}; + +class WasmTaggedToFloat64Descriptor : public StaticCallInterfaceDescriptor<WasmTaggedToFloat64Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kVal) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Float64T>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTaggedToFloat64Descriptor) +}; + +class WasmTaggedToFloat32Descriptor : public StaticCallInterfaceDescriptor<WasmTaggedToFloat32Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kVal) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Float32T>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTaggedToFloat32Descriptor) +}; + +class WasmMemoryGrowDescriptor : public StaticCallInterfaceDescriptor<WasmMemoryGrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kMemIndex, kNumPages) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineTypeOf<Int32T>::value, MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmMemoryGrowDescriptor) +}; + +class WasmTableInitDescriptor : public StaticCallInterfaceDescriptor<WasmTableInitDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kDstRaw, kSrcRaw, kSizeRaw, kTableIndex, kSegmentIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableInitDescriptor) +}; + +class WasmTableCopyDescriptor : public StaticCallInterfaceDescriptor<WasmTableCopyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kDstRaw, kSrcRaw, kSizeRaw, kDstTable, kSrcTable) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableCopyDescriptor) +}; + +class WasmTableFillDescriptor : public StaticCallInterfaceDescriptor<WasmTableFillDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kStartRaw, kCountRaw, kTable, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableFillDescriptor) +}; + +class WasmTableGrowDescriptor : public StaticCallInterfaceDescriptor<WasmTableGrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTable, kDeltaRaw, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineTypeOf<IntPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableGrowDescriptor) +}; + +class WasmTableGetDescriptor : public StaticCallInterfaceDescriptor<WasmTableGetDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTableIndex, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableGetDescriptor) +}; + +class WasmTableSetDescriptor : public StaticCallInterfaceDescriptor<WasmTableSetDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTableIndex, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableSetDescriptor) +}; + +class WasmTableGetFuncRefDescriptor : public StaticCallInterfaceDescriptor<WasmTableGetFuncRefDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTableIndex, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableGetFuncRefDescriptor) +}; + +class WasmFunctionTableGetDescriptor : public StaticCallInterfaceDescriptor<WasmFunctionTableGetDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTableIndex, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmFunctionTableGetDescriptor) +}; + +class WasmTableSetFuncRefDescriptor : public StaticCallInterfaceDescriptor<WasmTableSetFuncRefDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTableIndex, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTableSetFuncRefDescriptor) +}; + +class WasmRefFuncDescriptor : public StaticCallInterfaceDescriptor<WasmRefFuncDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInstance, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmRefFuncDescriptor) +}; + +class WasmInternalFunctionCreateExternalDescriptor : public StaticCallInterfaceDescriptor<WasmInternalFunctionCreateExternalDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kFunc) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmInternalFunctionCreateExternalDescriptor) +}; + +class WasmAllocateZeroedFixedArrayDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateZeroedFixedArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateZeroedFixedArrayDescriptor) +}; + +class WasmAllocateFixedArrayDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateFixedArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateFixedArrayDescriptor) +}; + +class WasmLiftoffDeoptFinishDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffDeoptFinishDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffDeoptFinishDescriptor) +}; + +class WasmThrowDescriptor : public StaticCallInterfaceDescriptor<WasmThrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kTag, kValues, kInstanceData) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmThrowDescriptor) +}; + +class WasmRethrowDescriptor : public StaticCallInterfaceDescriptor<WasmRethrowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kException) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmRethrowDescriptor) +}; + +class WasmThrowRefDescriptor : public StaticCallInterfaceDescriptor<WasmThrowRefDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kException) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmThrowRefDescriptor) +}; + +class WasmRethrowExplicitContextDescriptor : public StaticCallInterfaceDescriptor<WasmRethrowExplicitContextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kException, kExplicitContext) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmRethrowExplicitContextDescriptor) +}; + +class WasmTriggerTierUpDescriptor : public StaticCallInterfaceDescriptor<WasmTriggerTierUpDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTriggerTierUpDescriptor) +}; + +class WasmGrowableStackGuardDescriptor : public StaticCallInterfaceDescriptor<WasmGrowableStackGuardDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kStackParamAndReturnSlotsSize, kGap, kParameterSlotsSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value, MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmGrowableStackGuardDescriptor) +}; + +class WasmStackGuardDescriptor : public StaticCallInterfaceDescriptor<WasmStackGuardDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kGap) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<IntPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStackGuardDescriptor) +}; + +class WasmStackGuardLoopDescriptor : public StaticCallInterfaceDescriptor<WasmStackGuardLoopDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStackGuardLoopDescriptor) +}; + +class WasmStackOverflowDescriptor : public StaticCallInterfaceDescriptor<WasmStackOverflowDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStackOverflowDescriptor) +}; + +class WasmTraceGlobalDescriptor : public StaticCallInterfaceDescriptor<WasmTraceGlobalDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInfo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTraceGlobalDescriptor) +}; + +class WasmTraceMemoryDescriptor : public StaticCallInterfaceDescriptor<WasmTraceMemoryDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInfo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTraceMemoryDescriptor) +}; + +class WasmTraceEnterDescriptor : public StaticCallInterfaceDescriptor<WasmTraceEnterDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTraceEnterDescriptor) +}; + +class WasmTraceExitDescriptor : public StaticCallInterfaceDescriptor<WasmTraceExitDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kInfo) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTraceExitDescriptor) +}; + +class WasmConfigureAllPrototypesOptDescriptor : public StaticCallInterfaceDescriptor<WasmConfigureAllPrototypesOptDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kBuffer, kConstructors) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmConfigureAllPrototypesOptDescriptor) +}; + +class WasmAllocateJSArrayDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateJSArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateJSArrayDescriptor) +}; + +class WasmAllocateStructWithRttDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateStructWithRttDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kRtt, kInstanceSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateStructWithRttDescriptor) +}; + +class WasmAllocateDescriptorStructDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateDescriptorStructDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kMap, kTypeIndex, kFirstField) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateDescriptorStructDescriptor) +}; + +class WasmAllocateSharedStructWithRttDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateSharedStructWithRttDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kRtt, kInstanceSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateSharedStructWithRttDescriptor) +}; + +class WasmAllocateArray_UninitializedDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateArray_UninitializedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kRtt, kLength, kElementSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateArray_UninitializedDescriptor) +}; + +class WasmAllocateSharedArray_UninitializedDescriptor : public StaticCallInterfaceDescriptor<WasmAllocateSharedArray_UninitializedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kRtt, kLength, kElementSize) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmAllocateSharedArray_UninitializedDescriptor) +}; + +class WasmArrayNewSegmentDescriptor : public StaticCallInterfaceDescriptor<WasmArrayNewSegmentDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kSegmentIndex, kOffset, kLength, kIsElement, kRtt) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmArrayNewSegmentDescriptor) +}; + +class WasmArrayInitSegmentDescriptor : public StaticCallInterfaceDescriptor<WasmArrayInitSegmentDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArrayIndex, kSegmentOffset, kLength, kSegmentIndex, kIsElement, kArrayRaw) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmArrayInitSegmentDescriptor) +}; + +class WasmArrayCopyDescriptor : public StaticCallInterfaceDescriptor<WasmArrayCopyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kDstIndex, kSrcIndex, kLength, kDstObject, kSrcObject) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmArrayCopyDescriptor) +}; + +class WasmUint32ToNumberDescriptor : public StaticCallInterfaceDescriptor<WasmUint32ToNumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmUint32ToNumberDescriptor) +}; + +class UintPtr53ToNumberDescriptor : public StaticCallInterfaceDescriptor<UintPtr53ToNumberDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(UintPtr53ToNumberDescriptor) +}; + +class WasmI32AtomicWaitDescriptor : public StaticCallInterfaceDescriptor<WasmI32AtomicWaitDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kMemIndex, kOffset, kExpectedValue, kTimeout) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineTypeOf<Int32T>::value, MachineTypeOf<UintPtrT>::value, MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmI32AtomicWaitDescriptor) +}; + +class WasmI64AtomicWaitDescriptor : public StaticCallInterfaceDescriptor<WasmI64AtomicWaitDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kMemIndex, kOffset, kExpectedValue, kTimeout) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineTypeOf<Int32T>::value, MachineTypeOf<UintPtrT>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmI64AtomicWaitDescriptor) +}; + +class WasmManagedObjectWait32Descriptor : public StaticCallInterfaceDescriptor<WasmManagedObjectWait32Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObject, kFieldOffset, kExpectedValue, kWaitqueue, kTimeout) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineTypeOf<Int32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmManagedObjectWait32Descriptor) +}; + +class WasmManagedObjectWait64Descriptor : public StaticCallInterfaceDescriptor<WasmManagedObjectWait64Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObject, kFieldOffset, kExpectedValue, kWaitqueue, kTimeout) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmManagedObjectWait64Descriptor) +}; + +class WasmManagedObjectWaitRefDescriptor : public StaticCallInterfaceDescriptor<WasmManagedObjectWaitRefDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObject, kFieldOffset, kExpectedValue, kWaitqueue, kTimeout) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmManagedObjectWaitRefDescriptor) +}; + +class WasmWaitqueueNewDescriptor : public StaticCallInterfaceDescriptor<WasmWaitqueueNewDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmWaitqueueNewDescriptor) +}; + +class CallRefICDescriptor : public StaticCallInterfaceDescriptor<CallRefICDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(2, kVector, kVectorIndex, kFuncref) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(CallRefICDescriptor) +}; + +class CallIndirectICDescriptor : public StaticCallInterfaceDescriptor<CallIndirectICDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(2, kVector, kVectorIndex, kTarget, kImplicitArg) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(CallIndirectICDescriptor) +}; + +class WasmTrapDescriptor : public StaticCallInterfaceDescriptor<WasmTrapDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kError) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTrapDescriptor) +}; + +class ThrowWasmTrapUnreachableDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapUnreachableDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapUnreachableDescriptor) +}; + +class WasmPropagateExceptionDescriptor : public StaticCallInterfaceDescriptor<WasmPropagateExceptionDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmPropagateExceptionDescriptor) +}; + +class ThrowWasmTrapMemOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapMemOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapMemOutOfBoundsDescriptor) +}; + +class ThrowWasmTrapUnalignedAccessDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapUnalignedAccessDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapUnalignedAccessDescriptor) +}; + +class ThrowWasmTrapDivByZeroDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapDivByZeroDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapDivByZeroDescriptor) +}; + +class ThrowWasmTrapDivUnrepresentableDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapDivUnrepresentableDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapDivUnrepresentableDescriptor) +}; + +class ThrowWasmTrapRemByZeroDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapRemByZeroDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapRemByZeroDescriptor) +}; + +class ThrowWasmTrapFloatUnrepresentableDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapFloatUnrepresentableDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapFloatUnrepresentableDescriptor) +}; + +class ThrowWasmTrapFuncSigMismatchDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapFuncSigMismatchDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapFuncSigMismatchDescriptor) +}; + +class ThrowWasmTrapNullFuncDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapNullFuncDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapNullFuncDescriptor) +}; + +class ThrowWasmTrapDataSegmentOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapDataSegmentOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapDataSegmentOutOfBoundsDescriptor) +}; + +class ThrowWasmTrapElementSegmentOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapElementSegmentOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapElementSegmentOutOfBoundsDescriptor) +}; + +class ThrowWasmTrapTableOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapTableOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapTableOutOfBoundsDescriptor) +}; + +class ThrowWasmTrapRethrowNullDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapRethrowNullDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapRethrowNullDescriptor) +}; + +class ThrowWasmTrapNullDereferenceDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapNullDereferenceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapNullDereferenceDescriptor) +}; + +class ThrowWasmTrapIllegalCastDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapIllegalCastDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapIllegalCastDescriptor) +}; + +class ThrowWasmTrapArrayOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapArrayOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapArrayOutOfBoundsDescriptor) +}; + +class ThrowWasmTrapArrayTooLargeDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapArrayTooLargeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapArrayTooLargeDescriptor) +}; + +class ThrowWasmTrapStringOffsetOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapStringOffsetOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapStringOffsetOutOfBoundsDescriptor) +}; + +class WasmTypeAssertionFailedDescriptor : public StaticCallInterfaceDescriptor<WasmTypeAssertionFailedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmTypeAssertionFailedDescriptor) +}; + +class ThrowWasmTrapResumeDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapResumeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapResumeDescriptor) +}; + +class ThrowWasmTrapSuspendDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapSuspendDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapSuspendDescriptor) +}; + +class ThrowWasmTrapSwitchDescriptor : public StaticCallInterfaceDescriptor<ThrowWasmTrapSwitchDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowWasmTrapSwitchDescriptor) +}; + +class WasmStringNewWtf8Descriptor : public StaticCallInterfaceDescriptor<WasmStringNewWtf8Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kOffset, kSize, kMemory, kUtf8Config) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringNewWtf8Descriptor) +}; + +class WasmStringNewWtf8ArrayDescriptor : public StaticCallInterfaceDescriptor<WasmStringNewWtf8ArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kStart, kEnd, kArray, kUtf8Config) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringNewWtf8ArrayDescriptor) +}; + +class WasmStringNewWtf16Descriptor : public StaticCallInterfaceDescriptor<WasmStringNewWtf16Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kMemory, kOffset, kSize, kConfig) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<UintPtrT>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringNewWtf16Descriptor) +}; + +class WasmStringNewWtf16ArrayDescriptor : public StaticCallInterfaceDescriptor<WasmStringNewWtf16ArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kStart, kEnd, kConfig) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringNewWtf16ArrayDescriptor) +}; + +class WasmStringFromDataSegmentDescriptor : public StaticCallInterfaceDescriptor<WasmStringFromDataSegmentDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kSegmentLength, kArrayStart, kArrayEnd, kSegmentIndex, kSegmentOffset, kVariant) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned(), MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringFromDataSegmentDescriptor) +}; + +class WasmStringAsWtf16Descriptor : public StaticCallInterfaceDescriptor<WasmStringAsWtf16Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kStr) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringAsWtf16Descriptor) +}; + +class WasmStringConstDescriptor : public StaticCallInterfaceDescriptor<WasmStringConstDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringConstDescriptor) +}; + +class WasmStringMeasureUtf8Descriptor : public StaticCallInterfaceDescriptor<WasmStringMeasureUtf8Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringMeasureUtf8Descriptor) +}; + +class WasmStringMeasureWtf8Descriptor : public StaticCallInterfaceDescriptor<WasmStringMeasureWtf8Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringMeasureWtf8Descriptor) +}; + +class WasmStringEncodeWtf8Descriptor : public StaticCallInterfaceDescriptor<WasmStringEncodeWtf8Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kOffset, kMemory, kUtf8Variant, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineTypeOf<UintPtrT>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringEncodeWtf8Descriptor) +}; + +class WasmStringEncodeWtf8ArrayDescriptor : public StaticCallInterfaceDescriptor<WasmStringEncodeWtf8ArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kArray, kStart, kUtf8Variant) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringEncodeWtf8ArrayDescriptor) +}; + +class WasmStringToUtf8ArrayDescriptor : public StaticCallInterfaceDescriptor<WasmStringToUtf8ArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kShared) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringToUtf8ArrayDescriptor) +}; + +class WasmStringEncodeWtf16Descriptor : public StaticCallInterfaceDescriptor<WasmStringEncodeWtf16Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kOffset, kMemory) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringEncodeWtf16Descriptor) +}; + +class WasmStringEncodeWtf16ArrayDescriptor : public StaticCallInterfaceDescriptor<WasmStringEncodeWtf16ArrayDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kArray, kStart) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringEncodeWtf16ArrayDescriptor) +}; + +class ThrowToLowerCaseCalledOnNullDescriptor : public StaticCallInterfaceDescriptor<ThrowToLowerCaseCalledOnNullDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowToLowerCaseCalledOnNullDescriptor) +}; + +class ThrowIndexOfCalledOnNullDescriptor : public StaticCallInterfaceDescriptor<ThrowIndexOfCalledOnNullDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowIndexOfCalledOnNullDescriptor) +}; + +class ThrowDataViewTypeErrorDescriptor : public StaticCallInterfaceDescriptor<ThrowDataViewTypeErrorDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowDataViewTypeErrorDescriptor) +}; + +class ThrowDataViewDetachedErrorDescriptor : public StaticCallInterfaceDescriptor<ThrowDataViewDetachedErrorDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowDataViewDetachedErrorDescriptor) +}; + +class ThrowDataViewOutOfBoundsDescriptor : public StaticCallInterfaceDescriptor<ThrowDataViewOutOfBoundsDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(ThrowDataViewOutOfBoundsDescriptor) +}; + +class WasmStringConcatDescriptor : public StaticCallInterfaceDescriptor<WasmStringConcatDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kA, kB) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringConcatDescriptor) +}; + +class WasmStringAdd_NoMapCheck_SharedDescriptor : public StaticCallInterfaceDescriptor<WasmStringAdd_NoMapCheck_SharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kA, kB) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringAdd_NoMapCheck_SharedDescriptor) +}; + +class WasmStringEqualDescriptor : public StaticCallInterfaceDescriptor<WasmStringEqualDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kA, kB) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringEqualDescriptor) +}; + +class WasmStringIsUSVSequenceDescriptor : public StaticCallInterfaceDescriptor<WasmStringIsUSVSequenceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kStr) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringIsUSVSequenceDescriptor) +}; + +class WasmStringAsWtf8Descriptor : public StaticCallInterfaceDescriptor<WasmStringAsWtf8Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kStr) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringAsWtf8Descriptor) +}; + +class WasmStringViewWtf8AdvanceDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewWtf8AdvanceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kView, kPos, kBytes) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewWtf8AdvanceDescriptor) +}; + +class WasmStringViewWtf8EncodeDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewWtf8EncodeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(2, kAddr, kPos, kBytes, kView, kMemory, kUtf8Variant) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<UintPtrT>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewWtf8EncodeDescriptor) +}; + +class WasmStringViewWtf8SliceDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewWtf8SliceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kView, kStart, kEnd) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewWtf8SliceDescriptor) +}; + +class WasmStringViewWtf16GetCodeUnitDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewWtf16GetCodeUnitDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kOffset) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewWtf16GetCodeUnitDescriptor) +}; + +class WasmStringViewWtf16EncodeDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewWtf16EncodeDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kOffset, kStart, kLength, kString, kMemory) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineTypeOf<UintPtrT>::value, MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewWtf16EncodeDescriptor) +}; + +class WasmStringViewWtf16SliceDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewWtf16SliceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kStart, kEnd) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewWtf16SliceDescriptor) +}; + +class WasmStringSliceSharedDescriptor : public StaticCallInterfaceDescriptor<WasmStringSliceSharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kStart, kEnd) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringSliceSharedDescriptor) +}; + +class WasmStringAsIterDescriptor : public StaticCallInterfaceDescriptor<WasmStringAsIterDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringAsIterDescriptor) +}; + +class WasmStringCodePointAtDescriptor : public StaticCallInterfaceDescriptor<WasmStringCodePointAtDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString, kOffset) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringCodePointAtDescriptor) +}; + +class WasmStringViewIterNextDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewIterNextDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kView) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewIterNextDescriptor) +}; + +class WasmStringViewIterAdvanceDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewIterAdvanceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kView, kCodepoints) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewIterAdvanceDescriptor) +}; + +class WasmStringViewIterRewindDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewIterRewindDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kView, kCodepoints) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Uint32T>::value, MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewIterRewindDescriptor) +}; + +class WasmStringViewIterSliceDescriptor : public StaticCallInterfaceDescriptor<WasmStringViewIterSliceDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kView, kCodepoints) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringViewIterSliceDescriptor) +}; + +class WasmIntToStringDescriptor : public StaticCallInterfaceDescriptor<WasmIntToStringDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kX, kRadix) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Int32T>::value, MachineTypeOf<Int32T>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmIntToStringDescriptor) +}; + +class WasmStringToDoubleDescriptor : public StaticCallInterfaceDescriptor<WasmStringToDoubleDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kS) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Float64T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringToDoubleDescriptor) +}; + +class WasmStringFromCodePointDescriptor : public StaticCallInterfaceDescriptor<WasmStringFromCodePointDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kCodePoint, kShared) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineTypeOf<Uint32T>::value, MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringFromCodePointDescriptor) +}; + +class WasmStringHashDescriptor : public StaticCallInterfaceDescriptor<WasmStringHashDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kString) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringHashDescriptor) +}; + +class WasmAnyConvertExternDescriptor : public StaticCallInterfaceDescriptor<WasmAnyConvertExternDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kExternObject) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmAnyConvertExternDescriptor) +}; + +class WasmAnyConvertExternSharedDescriptor : public StaticCallInterfaceDescriptor<WasmAnyConvertExternSharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kExternObject) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmAnyConvertExternSharedDescriptor) +}; + +class WasmExternConvertAnyDescriptor : public StaticCallInterfaceDescriptor<WasmExternConvertAnyDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kWasmObject) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer()) + DECLARE_DEFAULT_DESCRIPTOR(WasmExternConvertAnyDescriptor) +}; + +class WasmFastApiCallTypeCheckAndUpdateICDescriptor : public StaticCallInterfaceDescriptor<WasmFastApiCallTypeCheckAndUpdateICDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kData, kReceiver) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(WasmFastApiCallTypeCheckAndUpdateICDescriptor) +}; + +class WasmStringIndexOfDescriptor : public StaticCallInterfaceDescriptor<WasmStringIndexOfDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kS, kSearchString, kStart) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(WasmStringIndexOfDescriptor) +}; + +class WasmLiftoffIsEqRefUnsharedDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffIsEqRefUnsharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObj, kNullSucceeds) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::AnyTagged(), MachineTypeOf<BoolT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffIsEqRefUnsharedDescriptor) +}; + +class WasmLiftoffIsArrayRefUnsharedDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffIsArrayRefUnsharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObj, kNullSucceeds) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::AnyTagged(), MachineTypeOf<BoolT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffIsArrayRefUnsharedDescriptor) +}; + +class WasmLiftoffIsStructRefUnsharedDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffIsStructRefUnsharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObj, kNullSucceeds) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineTypeOf<Int32T>::value, MachineType::AnyTagged(), MachineTypeOf<BoolT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffIsStructRefUnsharedDescriptor) +}; + +class WasmLiftoffCastEqRefUnsharedDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffCastEqRefUnsharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObj, kNullSucceeds) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineTypeOf<BoolT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffCastEqRefUnsharedDescriptor) +}; + +class WasmLiftoffCastArrayRefUnsharedDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffCastArrayRefUnsharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObj, kNullSucceeds) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineTypeOf<BoolT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffCastArrayRefUnsharedDescriptor) +}; + +class WasmLiftoffCastStructRefUnsharedDescriptor : public StaticCallInterfaceDescriptor<WasmLiftoffCastStructRefUnsharedDescriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kObj, kNullSucceeds) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::AnyTagged(), MachineTypeOf<BoolT>::value) + DECLARE_DEFAULT_DESCRIPTOR(WasmLiftoffCastStructRefUnsharedDescriptor) +}; + +class LoadJoinElement_GenericElementsAccessor_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinElement_GenericElementsAccessor_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinElement_GenericElementsAccessor_0Descriptor) +}; + +class LoadJoinTypedElement_Int32Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Int32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Int32Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Float16Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Float16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Float16Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Float32Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Float32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Float32Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Float64Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Float64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Float64Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Uint8ClampedElements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Uint8ClampedElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Uint8ClampedElements_0Descriptor) +}; + +class LoadJoinTypedElement_BigUint64Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_BigUint64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_BigUint64Elements_0Descriptor) +}; + +class LoadJoinTypedElement_BigInt64Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_BigInt64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_BigInt64Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Uint8Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Uint8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Uint8Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Int8Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Int8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Int8Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Uint16Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Uint16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Uint16Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Int16Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Int16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Int16Elements_0Descriptor) +}; + +class LoadJoinTypedElement_Uint32Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadJoinTypedElement_Uint32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kK) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadJoinTypedElement_Uint32Elements_0Descriptor) +}; + +class GenericBuiltinTest_Smi_0Descriptor : public StaticCallInterfaceDescriptor<GenericBuiltinTest_Smi_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kParam) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(GenericBuiltinTest_Smi_0Descriptor) +}; + +class CanUseSameAccessor_FastDoubleElements_0Descriptor : public StaticCallInterfaceDescriptor<CanUseSameAccessor_FastDoubleElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kInitialReceiverMap, kInitialReceiverLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CanUseSameAccessor_FastDoubleElements_0Descriptor) +}; + +class CanUseSameAccessor_FastSmiElements_0Descriptor : public StaticCallInterfaceDescriptor<CanUseSameAccessor_FastSmiElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kInitialReceiverMap, kInitialReceiverLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CanUseSameAccessor_FastSmiElements_0Descriptor) +}; + +class CanUseSameAccessor_FastObjectElements_0Descriptor : public StaticCallInterfaceDescriptor<CanUseSameAccessor_FastObjectElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kReceiver, kInitialReceiverMap, kInitialReceiverLength) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::TaggedPointer(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(CanUseSameAccessor_FastObjectElements_0Descriptor) +}; + +class LoadNoHasPropertyCheck_GenericElementsAccessor_0Descriptor : public StaticCallInterfaceDescriptor<LoadNoHasPropertyCheck_GenericElementsAccessor_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(LoadNoHasPropertyCheck_GenericElementsAccessor_0Descriptor) +}; + +class Load_GenericElementsAccessor_0Descriptor : public StaticCallInterfaceDescriptor<Load_GenericElementsAccessor_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Load_GenericElementsAccessor_0Descriptor) +}; + +class Store_GenericElementsAccessor_0Descriptor : public StaticCallInterfaceDescriptor<Store_GenericElementsAccessor_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned(), MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(Store_GenericElementsAccessor_0Descriptor) +}; + +class Delete_GenericElementsAccessor_0Descriptor : public StaticCallInterfaceDescriptor<Delete_GenericElementsAccessor_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kSortState, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineType::TaggedSigned()) + DECLARE_DEFAULT_DESCRIPTOR(Delete_GenericElementsAccessor_0Descriptor) +}; + +class LoadTypedElement_Int32Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Int32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Int32Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Int32Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Int32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Int32Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Int32Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Int32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Int32Elements_0Descriptor) +}; + +class LoadTypedElement_Float16Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Float16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Float16Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Float16Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Float16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Float16Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Float16Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Float16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Float16Elements_0Descriptor) +}; + +class LoadTypedElement_Float32Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Float32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Float32Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Float32Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Float32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Float32Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Float32Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Float32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Float32Elements_0Descriptor) +}; + +class LoadTypedElement_Float64Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Float64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Float64Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Float64Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Float64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Float64Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Float64Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Float64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Float64Elements_0Descriptor) +}; + +class LoadTypedElement_Uint8ClampedElements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Uint8ClampedElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Uint8ClampedElements_0Descriptor) +}; + +class StoreTypedElementNumeric_Uint8ClampedElements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Uint8ClampedElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Uint8ClampedElements_0Descriptor) +}; + +class StoreTypedElementJSAny_Uint8ClampedElements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Uint8ClampedElements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Uint8ClampedElements_0Descriptor) +}; + +class LoadTypedElement_BigUint64Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_BigUint64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_BigUint64Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_BigUint64Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_BigUint64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_BigUint64Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_BigUint64Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_BigUint64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_BigUint64Elements_0Descriptor) +}; + +class LoadTypedElement_BigInt64Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_BigInt64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_BigInt64Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_BigInt64Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_BigInt64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_BigInt64Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_BigInt64Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_BigInt64Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_BigInt64Elements_0Descriptor) +}; + +class LoadTypedElement_Uint8Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Uint8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Uint8Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Uint8Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Uint8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Uint8Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Uint8Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Uint8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Uint8Elements_0Descriptor) +}; + +class LoadTypedElement_Int8Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Int8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Int8Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Int8Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Int8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Int8Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Int8Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Int8Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Int8Elements_0Descriptor) +}; + +class LoadTypedElement_Uint16Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Uint16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Uint16Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Uint16Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Uint16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Uint16Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Uint16Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Uint16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Uint16Elements_0Descriptor) +}; + +class LoadTypedElement_Int16Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Int16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Int16Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Int16Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Int16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Int16Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Int16Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Int16Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Int16Elements_0Descriptor) +}; + +class LoadTypedElement_Uint32Elements_0Descriptor : public StaticCallInterfaceDescriptor<LoadTypedElement_Uint32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS_NO_CONTEXT(1, kArray, kIndex) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::AnyTagged(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value) + DECLARE_DEFAULT_DESCRIPTOR(LoadTypedElement_Uint32Elements_0Descriptor) +}; + +class StoreTypedElementNumeric_Uint32Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementNumeric_Uint32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementNumeric_Uint32Elements_0Descriptor) +}; + +class StoreTypedElementJSAny_Uint32Elements_0Descriptor : public StaticCallInterfaceDescriptor<StoreTypedElementJSAny_Uint32Elements_0Descriptor> { + public: + INTERNAL_DESCRIPTOR() + SANDBOXING_MODE(kSandboxed) + DEFINE_RESULT_AND_PARAMETERS(1, kTypedArray, kIndex, kValue) + DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedSigned(), MachineType::TaggedPointer(), MachineTypeOf<UintPtrT>::value, MachineType::AnyTagged()) + DECLARE_DEFAULT_DESCRIPTOR(StoreTypedElementJSAny_Uint32Elements_0Descriptor) +}; + diff --git a/deps/v8/src/roots/static-roots-intl-wasm.h b/deps/v8/src/gen/intl-wasm/static-roots.h similarity index 98% rename from deps/v8/src/roots/static-roots-intl-wasm.h rename to deps/v8/src/gen/intl-wasm/static-roots.h index 37f33f1c0370..9bafb8f91a7b 100644 --- a/deps/v8/src/roots/static-roots-intl-wasm.h +++ b/deps/v8/src/gen/intl-wasm/static-roots.h @@ -5,8 +5,8 @@ // This file is automatically generated by `tools/dev/gen-static-roots.py`. Do // not edit manually. -#ifndef V8_ROOTS_STATIC_ROOTS_INTL_WASM_H_ -#define V8_ROOTS_STATIC_ROOTS_INTL_WASM_H_ +#ifndef V8_GEN_INTL_WASM_STATIC_ROOTS_H_ +#define V8_GEN_INTL_WASM_STATIC_ROOTS_H_ // IWYU pragma: private "src/roots/static-roots.h" @@ -207,8 +207,9 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kCodeWrapperMap = kClassPositionsMap + 40; static constexpr Tagged_t kDebugScriptScopeInfoMap = kCodeWrapperMap + 40; static constexpr Tagged_t kErrorStackDataMap = kDebugScriptScopeInfoMap + 40; + static constexpr Tagged_t kForInEnumeratorHolderMap = kErrorStackDataMap + 40; static constexpr Tagged_t kFunctionTemplateRareDataMap = - kErrorStackDataMap + 40; + kForInEnumeratorHolderMap + 40; static constexpr Tagged_t kModuleRequestMap = kFunctionTemplateRareDataMap + 40; static constexpr Tagged_t kPromiseCapabilityMap = kModuleRequestMap + 40; @@ -248,8 +249,10 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kStoreHandler1Map = kStoreHandler0Map + 40; static constexpr Tagged_t kStoreHandler2Map = kStoreHandler1Map + 40; static constexpr Tagged_t kStoreHandler3Map = kStoreHandler2Map + 40; - static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + static constexpr Tagged_t kUninitializedHeapNumberMap = kStoreHandler3Map + 40; + static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + kUninitializedHeapNumberMap + 40; static constexpr Tagged_t kTurboshaftWord64SetTypeMap = kTurboshaftWord32SetTypeMap + 40; static constexpr Tagged_t kTurboshaftFloat64SetTypeMap = @@ -781,10 +784,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kas_string = kArrayIterator_string + 28; static constexpr Tagged_t kassert_string = kas_string + 16; static constexpr Tagged_t kasync_string = kassert_string + 20; - static constexpr Tagged_t kAtomicsCondition_string = kasync_string + 20; - static constexpr Tagged_t kAtomicsMutex_string = - kAtomicsCondition_string + 32; - static constexpr Tagged_t kauto_string = kAtomicsMutex_string + 28; + static constexpr Tagged_t kauto_string = kasync_string + 20; static constexpr Tagged_t kBigInt64Array_string = kauto_string + 16; static constexpr Tagged_t kBigInt_string = kBigInt64Array_string + 28; static constexpr Tagged_t kbigint_string = kBigInt_string + 20; @@ -1160,10 +1160,8 @@ struct StaticReadOnlyRoot { ksealed_symbol + 16; static constexpr Tagged_t kshared_struct_map_registry_key_symbol = kshared_struct_map_elements_template_symbol + 16; - static constexpr Tagged_t kstrict_function_transition_symbol = - kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_function_literal_id_symbol = - kstrict_function_transition_symbol + 16; + kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_slot_id_symbol = ktemplate_literal_function_literal_id_symbol + 16; static constexpr Tagged_t kwasm_cross_instance_call_symbol = @@ -1218,47 +1216,44 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kManyClosuresCell = kShadowRealmScopeInfo + 24; static constexpr Tagged_t kPreallocatedNumberStringTable = kManyClosuresCell + 16; - static constexpr Tagged_t kWasmNull = 0x10001; - static constexpr Tagged_t kTheHoleValue = 0x2fffd; + static constexpr Tagged_t kTheHoleValue = 0xfffd; + static constexpr Tagged_t kPropertyCellHoleValue = 0x2fffd; // -- End of page 0 -- - static constexpr Tagged_t kPropertyCellHoleValue = 0x4fffd; - static constexpr Tagged_t kHashTableHoleValue = 0x6fffd; + static constexpr Tagged_t kHashTableHoleValue = 0x4fffd; + static constexpr Tagged_t kPromiseHoleValue = 0x6fffd; // -- End of page 1 -- - static constexpr Tagged_t kPromiseHoleValue = 0x8fffd; // TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. #ifdef V8_ENABLE_TDZ_HOLE - static constexpr Tagged_t kTdzHoleValue = 0xafffd; + static constexpr Tagged_t kTdzHoleValue = 0x8fffd; #else - static constexpr Tagged_t kDisabledTdzHoleValue = 0xafffd; + static constexpr Tagged_t kDisabledTdzHoleValue = 0x8fffd; #endif + static constexpr Tagged_t kUninitializedValue = 0xafffd; // -- End of page 2 -- - static constexpr Tagged_t kUninitializedValue = 0xcfffd; - static constexpr Tagged_t kArgumentsMarker = 0xefffd; + static constexpr Tagged_t kArgumentsMarker = 0xcfffd; + static constexpr Tagged_t kTerminationException = 0xefffd; // -- End of page 3 -- - static constexpr Tagged_t kTerminationException = 0x10fffd; - static constexpr Tagged_t kException = 0x12fffd; + static constexpr Tagged_t kException = 0x10fffd; + static constexpr Tagged_t kOptimizedOut = 0x12fffd; // -- End of page 4 -- - static constexpr Tagged_t kOptimizedOut = 0x14fffd; - static constexpr Tagged_t kStaleRegister = 0x16fffd; + static constexpr Tagged_t kStaleRegister = 0x14fffd; + static constexpr Tagged_t kSelfReferenceMarker = 0x16fffd; // -- End of page 5 -- - static constexpr Tagged_t kSelfReferenceMarker = 0x18fffd; - static constexpr Tagged_t kBasicBlockCountersMarker = 0x1afffd; - // -- End of page 6 -- - static constexpr Tagged_t kJSMessageObjectMap = 0x1c0011; - static constexpr Tagged_t kExternalMap = 0x1c0039; - static constexpr Tagged_t kCppHeapExternalMap = 0x1c0061; - static constexpr Tagged_t kCppGCManagedBaseMap = 0x1c0089; - static constexpr Tagged_t kJSSharedArrayMap = 0x1c00b1; - static constexpr Tagged_t kJSAtomicsMutexMap = 0x1c00f5; - static constexpr Tagged_t kJSAtomicsConditionMap = 0x1c011d; - static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1c0145; - static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1c0199; + static constexpr Tagged_t kBasicBlockCountersMarker = 0x18fffd; + static constexpr Tagged_t kWasmNull = 0x1a0001; + static constexpr Tagged_t kJSMessageObjectMap = 0x1b0001; + static constexpr Tagged_t kExternalMap = 0x1b0029; + static constexpr Tagged_t kCppHeapExternalMap = 0x1b0051; + static constexpr Tagged_t kCppGCManagedBaseMap = 0x1b0079; + static constexpr Tagged_t kJSSharedArrayMap = 0x1b00a1; + static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1b00e5; + static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1b0139; static constexpr Tagged_t kFirstAllocatedRoot = 0x11; - static constexpr Tagged_t kLastAllocatedRoot = 0x1c0199; + static constexpr Tagged_t kLastAllocatedRoot = 0x1b0139; }; -static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 1039> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1299,7 +1294,7 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kPropertyCellHoleValue, StaticReadOnlyRoot::kStaleRegister, StaticReadOnlyRoot::kTerminationException, -// TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. + // TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. #ifdef V8_ENABLE_TDZ_HOLE StaticReadOnlyRoot::kTdzHoleValue, #else @@ -1363,6 +1358,7 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -1417,8 +1413,6 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kBooleanMap, StaticReadOnlyRoot::kHoleMap, StaticReadOnlyRoot::kJSSharedArrayMap, - StaticReadOnlyRoot::kJSAtomicsMutexMap, - StaticReadOnlyRoot::kJSAtomicsConditionMap, StaticReadOnlyRoot::kDescriptorArrayMap, StaticReadOnlyRoot::kOnHeapBasicBlockProfilerDataMap, StaticReadOnlyRoot::kTurbofanBitsetTypeMap, @@ -1889,8 +1883,6 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kas_string, StaticReadOnlyRoot::kassert_string, StaticReadOnlyRoot::kasync_string, - StaticReadOnlyRoot::kAtomicsCondition_string, - StaticReadOnlyRoot::kAtomicsMutex_string, StaticReadOnlyRoot::kauto_string, StaticReadOnlyRoot::kBigInt64Array_string, StaticReadOnlyRoot::kBigInt_string, @@ -2222,7 +2214,6 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::ksealed_symbol, StaticReadOnlyRoot::kshared_struct_map_elements_template_symbol, StaticReadOnlyRoot::kshared_struct_map_registry_key_symbol, - StaticReadOnlyRoot::kstrict_function_transition_symbol, StaticReadOnlyRoot::ktemplate_literal_function_literal_id_symbol, StaticReadOnlyRoot::ktemplate_literal_slot_id_symbol, StaticReadOnlyRoot::kwasm_cross_instance_call_symbol, @@ -2262,6 +2253,7 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, @@ -2311,4 +2303,4 @@ static constexpr std::array<Tagged_t, 1042> StaticReadOnlyRootsPointerTable = { } // namespace internal } // namespace v8 #endif // V8_STATIC_ROOTS_BOOL -#endif // V8_ROOTS_STATIC_ROOTS_INTL_WASM_H_ +#endif // V8_GEN_INTL_WASM_STATIC_ROOTS_H_ diff --git a/deps/v8/src/roots/static-roots-nointl-nowasm.h b/deps/v8/src/gen/nointl-nowasm/static-roots.h similarity index 98% rename from deps/v8/src/roots/static-roots-nointl-nowasm.h rename to deps/v8/src/gen/nointl-nowasm/static-roots.h index df5669009a4c..0402ff3bee96 100644 --- a/deps/v8/src/roots/static-roots-nointl-nowasm.h +++ b/deps/v8/src/gen/nointl-nowasm/static-roots.h @@ -5,8 +5,8 @@ // This file is automatically generated by `tools/dev/gen-static-roots.py`. Do // not edit manually. -#ifndef V8_ROOTS_STATIC_ROOTS_NOINTL_NOWASM_H_ -#define V8_ROOTS_STATIC_ROOTS_NOINTL_NOWASM_H_ +#ifndef V8_GEN_NOINTL_NOWASM_STATIC_ROOTS_H_ +#define V8_GEN_NOINTL_NOWASM_STATIC_ROOTS_H_ // IWYU pragma: private "src/roots/static-roots.h" @@ -207,8 +207,9 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kCodeWrapperMap = kClassPositionsMap + 40; static constexpr Tagged_t kDebugScriptScopeInfoMap = kCodeWrapperMap + 40; static constexpr Tagged_t kErrorStackDataMap = kDebugScriptScopeInfoMap + 40; + static constexpr Tagged_t kForInEnumeratorHolderMap = kErrorStackDataMap + 40; static constexpr Tagged_t kFunctionTemplateRareDataMap = - kErrorStackDataMap + 40; + kForInEnumeratorHolderMap + 40; static constexpr Tagged_t kModuleRequestMap = kFunctionTemplateRareDataMap + 40; static constexpr Tagged_t kPromiseCapabilityMap = kModuleRequestMap + 40; @@ -246,8 +247,10 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kStoreHandler1Map = kStoreHandler0Map + 40; static constexpr Tagged_t kStoreHandler2Map = kStoreHandler1Map + 40; static constexpr Tagged_t kStoreHandler3Map = kStoreHandler2Map + 40; - static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + static constexpr Tagged_t kUninitializedHeapNumberMap = kStoreHandler3Map + 40; + static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + kUninitializedHeapNumberMap + 40; static constexpr Tagged_t kTurboshaftWord64SetTypeMap = kTurboshaftWord32SetTypeMap + 40; static constexpr Tagged_t kTurboshaftFloat64SetTypeMap = @@ -600,10 +603,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kas_string = kArrayIterator_string + 28; static constexpr Tagged_t kassert_string = kas_string + 16; static constexpr Tagged_t kasync_string = kassert_string + 20; - static constexpr Tagged_t kAtomicsCondition_string = kasync_string + 20; - static constexpr Tagged_t kAtomicsMutex_string = - kAtomicsCondition_string + 32; - static constexpr Tagged_t kauto_string = kAtomicsMutex_string + 28; + static constexpr Tagged_t kauto_string = kasync_string + 20; static constexpr Tagged_t kBigInt64Array_string = kauto_string + 16; static constexpr Tagged_t kBigInt_string = kBigInt64Array_string + 28; static constexpr Tagged_t kbigint_string = kBigInt_string + 20; @@ -979,10 +979,8 @@ struct StaticReadOnlyRoot { ksealed_symbol + 16; static constexpr Tagged_t kshared_struct_map_registry_key_symbol = kshared_struct_map_elements_template_symbol + 16; - static constexpr Tagged_t kstrict_function_transition_symbol = - kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_function_literal_id_symbol = - kstrict_function_transition_symbol + 16; + kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_slot_id_symbol = ktemplate_literal_function_literal_id_symbol + 16; static constexpr Tagged_t kwasm_cross_instance_call_symbol = @@ -1066,16 +1064,14 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kCppHeapExternalMap = 0x1a0051; static constexpr Tagged_t kCppGCManagedBaseMap = 0x1a0079; static constexpr Tagged_t kJSSharedArrayMap = 0x1a00a1; - static constexpr Tagged_t kJSAtomicsMutexMap = 0x1a00e5; - static constexpr Tagged_t kJSAtomicsConditionMap = 0x1a010d; - static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1a0135; - static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1a0189; + static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1a00e5; + static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1a0139; static constexpr Tagged_t kFirstAllocatedRoot = 0x11; - static constexpr Tagged_t kLastAllocatedRoot = 0x1a0189; + static constexpr Tagged_t kLastAllocatedRoot = 0x1a0139; }; -static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 879> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1116,7 +1112,7 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kPropertyCellHoleValue, StaticReadOnlyRoot::kStaleRegister, StaticReadOnlyRoot::kTerminationException, -// TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. + // TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. #ifdef V8_ENABLE_TDZ_HOLE StaticReadOnlyRoot::kTdzHoleValue, #else @@ -1174,6 +1170,7 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -1220,8 +1217,6 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kBooleanMap, StaticReadOnlyRoot::kHoleMap, StaticReadOnlyRoot::kJSSharedArrayMap, - StaticReadOnlyRoot::kJSAtomicsMutexMap, - StaticReadOnlyRoot::kJSAtomicsConditionMap, StaticReadOnlyRoot::kDescriptorArrayMap, StaticReadOnlyRoot::kOnHeapBasicBlockProfilerDataMap, StaticReadOnlyRoot::kTurbofanBitsetTypeMap, @@ -1547,8 +1542,6 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kas_string, StaticReadOnlyRoot::kassert_string, StaticReadOnlyRoot::kasync_string, - StaticReadOnlyRoot::kAtomicsCondition_string, - StaticReadOnlyRoot::kAtomicsMutex_string, StaticReadOnlyRoot::kauto_string, StaticReadOnlyRoot::kBigInt64Array_string, StaticReadOnlyRoot::kBigInt_string, @@ -1880,7 +1873,6 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::ksealed_symbol, StaticReadOnlyRoot::kshared_struct_map_elements_template_symbol, StaticReadOnlyRoot::kshared_struct_map_registry_key_symbol, - StaticReadOnlyRoot::kstrict_function_transition_symbol, StaticReadOnlyRoot::ktemplate_literal_function_literal_id_symbol, StaticReadOnlyRoot::ktemplate_literal_slot_id_symbol, StaticReadOnlyRoot::kwasm_cross_instance_call_symbol, @@ -1920,6 +1912,7 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, @@ -1968,4 +1961,4 @@ static constexpr std::array<Tagged_t, 882> StaticReadOnlyRootsPointerTable = { } // namespace internal } // namespace v8 #endif // V8_STATIC_ROOTS_BOOL -#endif // V8_ROOTS_STATIC_ROOTS_NOINTL_NOWASM_H_ +#endif // V8_GEN_NOINTL_NOWASM_STATIC_ROOTS_H_ diff --git a/deps/v8/src/roots/static-roots-nointl-wasm.h b/deps/v8/src/gen/nointl-wasm/static-roots.h similarity index 97% rename from deps/v8/src/roots/static-roots-nointl-wasm.h rename to deps/v8/src/gen/nointl-wasm/static-roots.h index 346090858223..a3a7d8a8c191 100644 --- a/deps/v8/src/roots/static-roots-nointl-wasm.h +++ b/deps/v8/src/gen/nointl-wasm/static-roots.h @@ -5,8 +5,8 @@ // This file is automatically generated by `tools/dev/gen-static-roots.py`. Do // not edit manually. -#ifndef V8_ROOTS_STATIC_ROOTS_NOINTL_WASM_H_ -#define V8_ROOTS_STATIC_ROOTS_NOINTL_WASM_H_ +#ifndef V8_GEN_NOINTL_WASM_STATIC_ROOTS_H_ +#define V8_GEN_NOINTL_WASM_STATIC_ROOTS_H_ // IWYU pragma: private "src/roots/static-roots.h" @@ -207,8 +207,9 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kCodeWrapperMap = kClassPositionsMap + 40; static constexpr Tagged_t kDebugScriptScopeInfoMap = kCodeWrapperMap + 40; static constexpr Tagged_t kErrorStackDataMap = kDebugScriptScopeInfoMap + 40; + static constexpr Tagged_t kForInEnumeratorHolderMap = kErrorStackDataMap + 40; static constexpr Tagged_t kFunctionTemplateRareDataMap = - kErrorStackDataMap + 40; + kForInEnumeratorHolderMap + 40; static constexpr Tagged_t kModuleRequestMap = kFunctionTemplateRareDataMap + 40; static constexpr Tagged_t kPromiseCapabilityMap = kModuleRequestMap + 40; @@ -248,8 +249,10 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kStoreHandler1Map = kStoreHandler0Map + 40; static constexpr Tagged_t kStoreHandler2Map = kStoreHandler1Map + 40; static constexpr Tagged_t kStoreHandler3Map = kStoreHandler2Map + 40; - static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + static constexpr Tagged_t kUninitializedHeapNumberMap = kStoreHandler3Map + 40; + static constexpr Tagged_t kTurboshaftWord32SetTypeMap = + kUninitializedHeapNumberMap + 40; static constexpr Tagged_t kTurboshaftWord64SetTypeMap = kTurboshaftWord32SetTypeMap + 40; static constexpr Tagged_t kTurboshaftFloat64SetTypeMap = @@ -625,10 +628,7 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kas_string = kArrayIterator_string + 28; static constexpr Tagged_t kassert_string = kas_string + 16; static constexpr Tagged_t kasync_string = kassert_string + 20; - static constexpr Tagged_t kAtomicsCondition_string = kasync_string + 20; - static constexpr Tagged_t kAtomicsMutex_string = - kAtomicsCondition_string + 32; - static constexpr Tagged_t kauto_string = kAtomicsMutex_string + 28; + static constexpr Tagged_t kauto_string = kasync_string + 20; static constexpr Tagged_t kBigInt64Array_string = kauto_string + 16; static constexpr Tagged_t kBigInt_string = kBigInt64Array_string + 28; static constexpr Tagged_t kbigint_string = kBigInt_string + 20; @@ -1004,10 +1004,8 @@ struct StaticReadOnlyRoot { ksealed_symbol + 16; static constexpr Tagged_t kshared_struct_map_registry_key_symbol = kshared_struct_map_elements_template_symbol + 16; - static constexpr Tagged_t kstrict_function_transition_symbol = - kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_function_literal_id_symbol = - kstrict_function_transition_symbol + 16; + kshared_struct_map_registry_key_symbol + 16; static constexpr Tagged_t ktemplate_literal_slot_id_symbol = ktemplate_literal_function_literal_id_symbol + 16; static constexpr Tagged_t kwasm_cross_instance_call_symbol = @@ -1062,47 +1060,44 @@ struct StaticReadOnlyRoot { static constexpr Tagged_t kManyClosuresCell = kShadowRealmScopeInfo + 24; static constexpr Tagged_t kPreallocatedNumberStringTable = kManyClosuresCell + 16; - static constexpr Tagged_t kWasmNull = 0x10001; - static constexpr Tagged_t kTheHoleValue = 0x2fffd; + static constexpr Tagged_t kTheHoleValue = 0xfffd; + static constexpr Tagged_t kPropertyCellHoleValue = 0x2fffd; // -- End of page 0 -- - static constexpr Tagged_t kPropertyCellHoleValue = 0x4fffd; - static constexpr Tagged_t kHashTableHoleValue = 0x6fffd; + static constexpr Tagged_t kHashTableHoleValue = 0x4fffd; + static constexpr Tagged_t kPromiseHoleValue = 0x6fffd; // -- End of page 1 -- - static constexpr Tagged_t kPromiseHoleValue = 0x8fffd; // TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. #ifdef V8_ENABLE_TDZ_HOLE - static constexpr Tagged_t kTdzHoleValue = 0xafffd; + static constexpr Tagged_t kTdzHoleValue = 0x8fffd; #else - static constexpr Tagged_t kDisabledTdzHoleValue = 0xafffd; + static constexpr Tagged_t kDisabledTdzHoleValue = 0x8fffd; #endif + static constexpr Tagged_t kUninitializedValue = 0xafffd; // -- End of page 2 -- - static constexpr Tagged_t kUninitializedValue = 0xcfffd; - static constexpr Tagged_t kArgumentsMarker = 0xefffd; + static constexpr Tagged_t kArgumentsMarker = 0xcfffd; + static constexpr Tagged_t kTerminationException = 0xefffd; // -- End of page 3 -- - static constexpr Tagged_t kTerminationException = 0x10fffd; - static constexpr Tagged_t kException = 0x12fffd; + static constexpr Tagged_t kException = 0x10fffd; + static constexpr Tagged_t kOptimizedOut = 0x12fffd; // -- End of page 4 -- - static constexpr Tagged_t kOptimizedOut = 0x14fffd; - static constexpr Tagged_t kStaleRegister = 0x16fffd; + static constexpr Tagged_t kStaleRegister = 0x14fffd; + static constexpr Tagged_t kSelfReferenceMarker = 0x16fffd; // -- End of page 5 -- - static constexpr Tagged_t kSelfReferenceMarker = 0x18fffd; - static constexpr Tagged_t kBasicBlockCountersMarker = 0x1afffd; - // -- End of page 6 -- - static constexpr Tagged_t kJSMessageObjectMap = 0x1c0011; - static constexpr Tagged_t kExternalMap = 0x1c0039; - static constexpr Tagged_t kCppHeapExternalMap = 0x1c0061; - static constexpr Tagged_t kCppGCManagedBaseMap = 0x1c0089; - static constexpr Tagged_t kJSSharedArrayMap = 0x1c00b1; - static constexpr Tagged_t kJSAtomicsMutexMap = 0x1c00f5; - static constexpr Tagged_t kJSAtomicsConditionMap = 0x1c011d; - static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1c0145; - static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1c0199; + static constexpr Tagged_t kBasicBlockCountersMarker = 0x18fffd; + static constexpr Tagged_t kWasmNull = 0x1a0001; + static constexpr Tagged_t kJSMessageObjectMap = 0x1b0001; + static constexpr Tagged_t kExternalMap = 0x1b0029; + static constexpr Tagged_t kCppHeapExternalMap = 0x1b0051; + static constexpr Tagged_t kCppGCManagedBaseMap = 0x1b0079; + static constexpr Tagged_t kJSSharedArrayMap = 0x1b00a1; + static constexpr Tagged_t kNoOpNamedInterceptorInfo = 0x1b00e5; + static constexpr Tagged_t kNoOpIndexedInterceptorInfo = 0x1b0139; static constexpr Tagged_t kFirstAllocatedRoot = 0x11; - static constexpr Tagged_t kLastAllocatedRoot = 0x1c0199; + static constexpr Tagged_t kLastAllocatedRoot = 0x1b0139; }; -static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { +static constexpr std::array<Tagged_t, 897> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kUndefinedValue, StaticReadOnlyRoot::kTheHoleValue, StaticReadOnlyRoot::kNullValue, @@ -1143,7 +1138,7 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kPropertyCellHoleValue, StaticReadOnlyRoot::kStaleRegister, StaticReadOnlyRoot::kTerminationException, -// TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. + // TODO(leszeks): Remove DisabledTdzHole when v8_enable_tdz_hole is removed. #ifdef V8_ENABLE_TDZ_HOLE StaticReadOnlyRoot::kTdzHoleValue, #else @@ -1207,6 +1202,7 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kEphemeronHashTableMap, StaticReadOnlyRoot::kEmbedderDataArrayMap, StaticReadOnlyRoot::kWeakCellMap, + StaticReadOnlyRoot::kUninitializedHeapNumberMap, StaticReadOnlyRoot::kAtomRegExpDataMap, StaticReadOnlyRoot::kCodeMap, StaticReadOnlyRoot::kDebugInfoMap, @@ -1261,8 +1257,6 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kBooleanMap, StaticReadOnlyRoot::kHoleMap, StaticReadOnlyRoot::kJSSharedArrayMap, - StaticReadOnlyRoot::kJSAtomicsMutexMap, - StaticReadOnlyRoot::kJSAtomicsConditionMap, StaticReadOnlyRoot::kDescriptorArrayMap, StaticReadOnlyRoot::kOnHeapBasicBlockProfilerDataMap, StaticReadOnlyRoot::kTurbofanBitsetTypeMap, @@ -1591,8 +1585,6 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kas_string, StaticReadOnlyRoot::kassert_string, StaticReadOnlyRoot::kasync_string, - StaticReadOnlyRoot::kAtomicsCondition_string, - StaticReadOnlyRoot::kAtomicsMutex_string, StaticReadOnlyRoot::kauto_string, StaticReadOnlyRoot::kBigInt64Array_string, StaticReadOnlyRoot::kBigInt_string, @@ -1924,7 +1916,6 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::ksealed_symbol, StaticReadOnlyRoot::kshared_struct_map_elements_template_symbol, StaticReadOnlyRoot::kshared_struct_map_registry_key_symbol, - StaticReadOnlyRoot::kstrict_function_transition_symbol, StaticReadOnlyRoot::ktemplate_literal_function_literal_id_symbol, StaticReadOnlyRoot::ktemplate_literal_slot_id_symbol, StaticReadOnlyRoot::kwasm_cross_instance_call_symbol, @@ -1964,6 +1955,7 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { StaticReadOnlyRoot::kDebugScriptScopeInfoMap, StaticReadOnlyRoot::kEnumCacheMap, StaticReadOnlyRoot::kErrorStackDataMap, + StaticReadOnlyRoot::kForInEnumeratorHolderMap, StaticReadOnlyRoot::kFunctionTemplateRareDataMap, StaticReadOnlyRoot::kModuleRequestMap, StaticReadOnlyRoot::kPromiseCapabilityMap, @@ -2013,4 +2005,4 @@ static constexpr std::array<Tagged_t, 900> StaticReadOnlyRootsPointerTable = { } // namespace internal } // namespace v8 #endif // V8_STATIC_ROOTS_BOOL -#endif // V8_ROOTS_STATIC_ROOTS_NOINTL_WASM_H_ +#endif // V8_GEN_NOINTL_WASM_STATIC_ROOTS_H_ diff --git a/deps/v8/src/handles/global-handles-inl.h b/deps/v8/src/handles/global-handles-inl.h index b212c461e63c..2a06e99989b6 100644 --- a/deps/v8/src/handles/global-handles-inl.h +++ b/deps/v8/src/handles/global-handles-inl.h @@ -20,7 +20,11 @@ IndirectHandle<T> GlobalHandles::Create(Tagged<T> value) { static_assert(is_subtype_v<T, Object>, "static type violation"); // The compiler should only pick this method if T is not Object. static_assert(!std::is_same_v<Object, T>, "compiler error"); - return TrustedCast<T>(Create(Tagged<Object>(value))); + if constexpr (is_subtype_v<T, TrustedObject>) { + return TrustedCast<T>(Create(Tagged<Object>(value))); + } else { + return Cast<T>(Create(Tagged<Object>(value))); + } } template <typename T> @@ -38,6 +42,19 @@ template <typename T> GlobalHandleVector<T>::GlobalHandleVector(Heap* heap) : locations_(StrongRootAllocator<Address>(heap)) {} +template <typename T> +Tagged<T> GlobalHandleCircularQueue<T>::Dequeue() { + return Cast<T>(Tagged<Object>(locations_.Dequeue())); +} + +template <typename T> +GlobalHandleCircularQueue<T>::GlobalHandleCircularQueue(LocalHeap* local_heap) + : GlobalHandleCircularQueue(local_heap->AsHeap()) {} + +template <typename T> +GlobalHandleCircularQueue<T>::GlobalHandleCircularQueue(Heap* heap) + : locations_(StrongRootAllocator<Address>(heap)) {} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/handles/global-handles.h b/deps/v8/src/handles/global-handles.h index f53b1d87ccbb..3d67d36e12d3 100644 --- a/deps/v8/src/handles/global-handles.h +++ b/deps/v8/src/handles/global-handles.h @@ -13,6 +13,7 @@ #include "include/v8-callbacks.h" #include "include/v8-persistent-handle.h" #include "include/v8-profiler.h" +#include "src/base/growing-circular-queue.h" #include "src/handles/handles.h" #include "src/heap/heap.h" #include "src/objects/heap-object.h" @@ -281,6 +282,25 @@ class GlobalHandleVector { std::vector<Address, StrongRootAllocator<Address>> locations_; }; +// A circular queue of global Handles which automatically manages the backing of +// those Handles as a queue of strong-rooted addresses. +template <typename T> +class GlobalHandleCircularQueue { + public: + explicit inline GlobalHandleCircularQueue(Heap* heap); + // Usage with LocalHeap is safe. + explicit inline GlobalHandleCircularQueue(LocalHeap* local_heap); + + size_t size() const { return locations_.size(); } + bool empty() const { return locations_.empty(); } + + void Enqueue(Tagged<T> val) { locations_.Enqueue(val.ptr()); } + inline Tagged<T> Dequeue(); + + private: + base::GrowingCircularQueue<Address, StrongRootAllocator<Address>> locations_; +}; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/handles/handles-inl.h b/deps/v8/src/handles/handles-inl.h index a8a3bf01b693..a2aa2a38889a 100644 --- a/deps/v8/src/handles/handles-inl.h +++ b/deps/v8/src/handles/handles-inl.h @@ -84,20 +84,17 @@ V8_INLINE IndirectHandle<T> handle(Tagged<T> object, LocalHeap* local_heap) { } template <typename T> -V8_INLINE IndirectHandle<T> handle(T object, Isolate* isolate) { - static_assert(kTaggedCanConvertToRawObjects); +V8_INLINE IndirectHandle<T> handle(const T* object, Isolate* isolate) { return handle(Tagged<T>(object), isolate); } template <typename T> -V8_INLINE IndirectHandle<T> handle(T object, LocalIsolate* isolate) { - static_assert(kTaggedCanConvertToRawObjects); +V8_INLINE IndirectHandle<T> handle(const T* object, LocalIsolate* isolate) { return handle(Tagged<T>(object), isolate); } template <typename T> -V8_INLINE IndirectHandle<T> handle(T object, LocalHeap* local_heap) { - static_assert(kTaggedCanConvertToRawObjects); +V8_INLINE IndirectHandle<T> handle(const T* object, LocalHeap* local_heap) { return handle(Tagged<T>(object), local_heap); } diff --git a/deps/v8/src/handles/handles.h b/deps/v8/src/handles/handles.h index 0bbe40f806be..4597299a93fc 100644 --- a/deps/v8/src/handles/handles.h +++ b/deps/v8/src/handles/handles.h @@ -5,6 +5,7 @@ #ifndef V8_HANDLES_HANDLES_H_ #define V8_HANDLES_HANDLES_H_ +#include <span> #include <type_traits> #include <vector> @@ -1031,8 +1032,7 @@ class DirectHandleSmallVector { backing_.insert(backing_.end(), init.begin(), init.end()); } template <typename IsolateT> - explicit V8_INLINE DirectHandleSmallVector( - base::Vector<const value_type> init) + explicit V8_INLINE DirectHandleSmallVector(std::span<const value_type> init) : backing_() { if (init.size() == 0) return; backing_.reserve(init.size()); diff --git a/deps/v8/src/heap/WRITE_BARRIER.md b/deps/v8/src/heap/WRITE_BARRIER.md index 32e3c3827000..0e2fdd3e0528 100644 --- a/deps/v8/src/heap/WRITE_BARRIER.md +++ b/deps/v8/src/heap/WRITE_BARRIER.md @@ -81,7 +81,7 @@ This barrier is only active during incremental marking. Therefore the fast path of this barrier only jumps into the deferred code path if marking is active. Checking the host object flags is not necessary. -The Turbofan indirect pointer write barrier is implemented as a separate instruction opcode [kArchStoreIndirectWithWriteBarrier](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/compiler/backend/x64/code-generator-x64.cc?q=kArchStoreIndirectWithWriteBarrier). +The Turbofan indirect pointer write barrier is implemented as a separate instruction opcode [kArchStoreTrustedWithWriteBarrier](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/compiler/backend/x64/code-generator-x64.cc?q=kArchStoreTrustedWithWriteBarrier). The deferred code path is implemented in the [OutOfLineRecordWrite](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/compiler/backend/x64/code-generator-x64.cc?q=OutOfLineRecordWrite) class along with the regular write barrier. Assembler builtins can emit this barrier using [MacroAssembler::RecordWrite](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/codegen/x64/macro-assembler-x64.cc?q=MacroAssembler::RecordWrite%28). This method handles both the indirect pointer but also the regular write barrier. diff --git a/deps/v8/src/heap/array-buffer-sweeper.cc b/deps/v8/src/heap/array-buffer-sweeper.cc index 64184f76e1ab..67c3b1cabad7 100644 --- a/deps/v8/src/heap/array-buffer-sweeper.cc +++ b/deps/v8/src/heap/array-buffer-sweeper.cc @@ -489,7 +489,6 @@ bool ArrayBufferSweeper::SweepingState::SweepingJob::SweepListFull( size_t swept_extensions = 0; while (current) { - current->InitializationBarrier(); DCHECK_EQ(list.age_, current->age()); if ((swept_extensions++ & (kYieldCheckInterval - 1)) == 0) { if (delegate->ShouldYield()) break; @@ -535,7 +534,6 @@ bool ArrayBufferSweeper::SweepingState::SweepingJob::SweepYoung( size_t swept_extensions = 0; while (current) { - current->InitializationBarrier(); DCHECK_EQ(ArrayBufferExtension::Age::kYoung, current->age()); if ((swept_extensions++ & (kYieldCheckInterval - 1)) == 0) { if (delegate->ShouldYield()) break; diff --git a/deps/v8/src/heap/base/stack.cc b/deps/v8/src/heap/base/stack.cc index d348c569c8c6..cc87b0a524b1 100644 --- a/deps/v8/src/heap/base/stack.cc +++ b/deps/v8/src/heap/base/stack.cc @@ -38,7 +38,7 @@ bool Stack::IsOnStack(const void* slot) { } #endif // V8_USE_SAFE_STACK return v8::base::Stack::GetCurrentStackPosition() <= slot && - slot <= v8::base::Stack::GetStackStartUnchecked(); + slot <= v8::base::Stack::GetStackStart(); } namespace { @@ -207,7 +207,7 @@ void Stack::IterateBackgroundStacks(StackVisitor* visitor) const { // static bool Stack::IsOnCurrentStack(const void* ptr) { DCHECK_NOT_NULL(ptr); - const void* current_stack_start = v8::base::Stack::GetStackStartUnchecked(); + const void* current_stack_start = v8::base::Stack::GetStackStart(); const void* current_stack_top = v8::base::Stack::GetCurrentStackPosition(); return ptr <= current_stack_start && ptr >= current_stack_top; } diff --git a/deps/v8/src/heap/base/stack.h b/deps/v8/src/heap/base/stack.h index d03a5b2a5868..5efb7364a8e8 100644 --- a/deps/v8/src/heap/base/stack.h +++ b/deps/v8/src/heap/base/stack.h @@ -35,8 +35,10 @@ using StackVisitorCallback = void (*)(StackVisitor*); class V8_EXPORT_PRIVATE Stack final { public: // Sets the start of the stack to the provided stack start. - void SetStackStart(const void* stack_start) { + void SetStackStart(const void* stack_start, bool check_for_tls) { + v8::base::MutexGuard guard(&lock_); current_segment_.start = stack_start; + check_for_tls_ = check_for_tls; #ifdef V8_USE_ADDRESS_SANITIZER current_segment_.asan_fake_stack = __asan_get_current_fake_stack(); #endif // V8_USE_ADDRESS_SANITIZER @@ -178,6 +180,9 @@ class V8_EXPORT_PRIVATE Stack final { stack->current_segment_.unsafe_stack_top = __builtin___get_unsafe_stack_ptr(); #endif // V8_USE_SAFE_STACK + v8::base::Stack::ValidateStackSegment(stack->current_segment_.start, + stack->current_segment_.top, + stack->check_for_tls_); Callback* callback = static_cast<Callback*>(argument); (*callback)(); stack->current_segment_ = previous_segment; @@ -204,8 +209,10 @@ class V8_EXPORT_PRIVATE Stack final { // - asan_fake_start // - unsafe stack start // - unsafe stack top - background_stacks[thread] = - Segment(v8::base::Stack::GetStackStart(), stack_end); + Segment segment(v8::base::Stack::GetEffectiveStackStart(), stack_end); + v8::base::Stack::ValidateStackSegment(segment.start, segment.top, + stack->check_for_tls_); + background_stacks[thread] = segment; } (*callback)(); { @@ -221,6 +228,7 @@ class V8_EXPORT_PRIVATE Stack final { void IteratePointersInSegment(StackVisitor* visitor, Segment segment) const; Segment current_segment_; + bool check_for_tls_ = false; mutable v8::base::Mutex lock_; std::map<ThreadId, Segment> background_stacks_; diff --git a/deps/v8/src/heap/cppgc-internal/allocation.cc b/deps/v8/src/heap/cppgc-internal/allocation.cc index 4b21be8582ea..92b865bc4ae4 100644 --- a/deps/v8/src/heap/cppgc-internal/allocation.cc +++ b/deps/v8/src/heap/cppgc-internal/allocation.cc @@ -35,8 +35,8 @@ static_assert(api_constants::kMaxSupportedAlignment >= // static CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, GCInfoIndex index) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, index, ObjectAllocator::MayContainMixins::kNo); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kNo>(size, index); } // Using CPPGC_FORCE_ALWAYS_INLINE to guide LTO for inlining the allocation @@ -45,8 +45,9 @@ CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, AlignVal alignment, GCInfoIndex index) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, alignment, index, ObjectAllocator::MayContainMixins::kNo); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kNo>(size, alignment, + index); } // Using CPPGC_FORCE_ALWAYS_INLINE to guide LTO for inlining the allocation @@ -55,8 +56,9 @@ CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, GCInfoIndex index, CustomSpaceIndex space_index) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, index, space_index, ObjectAllocator::MayContainMixins::kNo); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kNo>(size, index, + space_index); } // Using CPPGC_FORCE_ALWAYS_INLINE to guide LTO for inlining the allocation @@ -65,15 +67,15 @@ CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, AlignVal alignment, GCInfoIndex index, CustomSpaceIndex space_index) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, alignment, index, space_index, - ObjectAllocator::MayContainMixins::kNo); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kNo>( + size, alignment, index, space_index); } CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, GCInfoIndex index, MixinTag) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, index, ObjectAllocator::MayContainMixins::kYes); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kYes>(size, index); } // Using CPPGC_FORCE_ALWAYS_INLINE to guide LTO for inlining the allocation @@ -82,8 +84,9 @@ CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, AlignVal alignment, GCInfoIndex index, MixinTag) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, alignment, index, ObjectAllocator::MayContainMixins::kYes); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kYes>(size, alignment, + index); } // Using CPPGC_FORCE_ALWAYS_INLINE to guide LTO for inlining the allocation @@ -92,8 +95,9 @@ CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, GCInfoIndex index, CustomSpaceIndex space_index, MixinTag) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, index, space_index, ObjectAllocator::MayContainMixins::kYes); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kYes>(size, index, + space_index); } // Using CPPGC_FORCE_ALWAYS_INLINE to guide LTO for inlining the allocation @@ -102,9 +106,9 @@ CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( CPPGC_FORCE_ALWAYS_INLINE void* MakeGarbageCollectedTraitInternal::Allocate( cppgc::AllocationHandle& handle, size_t size, AlignVal alignment, GCInfoIndex index, CustomSpaceIndex space_index, MixinTag) { - return static_cast<ObjectAllocator&>(handle).AllocateObject( - size, alignment, index, space_index, - ObjectAllocator::MayContainMixins::kYes); + return static_cast<ObjectAllocator&>(handle) + .AllocateObject<ObjectAllocator::MayContainMixins::kYes>( + size, alignment, index, space_index); } } // namespace internal diff --git a/deps/v8/src/heap/cppgc-internal/caged-heap.cc b/deps/v8/src/heap/cppgc-internal/caged-heap.cc index b2925026c25d..2899c76cb5e0 100644 --- a/deps/v8/src/heap/cppgc-internal/caged-heap.cc +++ b/deps/v8/src/heap/cppgc-internal/caged-heap.cc @@ -180,10 +180,10 @@ CagedHeap::CagedHeap(PageAllocator& platform_allocator, CageBaseGlobalUpdater::UpdateCageBase(CagedHeapBase::g_heap_base_); #endif // defined(CPPGC_POINTER_COMPRESSION) - const size_t total_heap_size = std::clamp<size_t>( - v8::base::bits::RoundUpToPowerOfTwo64(desired_heap_size), - api_constants::kCagedHeapDefaultReservationSize, - api_constants::kCagedHeapMaxReservationSize); + const size_t total_heap_size = + std::clamp<size_t>(std::bit_ceil(desired_heap_size), + api_constants::kCagedHeapDefaultReservationSize, + api_constants::kCagedHeapMaxReservationSize); const size_t commit_page_size = platform_allocator.CommitPageSize(); diff --git a/deps/v8/src/heap/cppgc-internal/explicit-management.cc b/deps/v8/src/heap/cppgc-internal/explicit-management.cc index 8f9b5efb04c7..eb3900299342 100644 --- a/deps/v8/src/heap/cppgc-internal/explicit-management.cc +++ b/deps/v8/src/heap/cppgc-internal/explicit-management.cc @@ -35,6 +35,7 @@ void ExplicitManagementImpl::FreeUnreferencedObject(HeapHandle& heap_handle, } auto& header = HeapObjectHeader::FromObject(object); + HeapBase::From(heap_handle).RemoveSampledObject(&header); header.Finalize(); // `object` is guaranteed to be of type GarbageCollected, so getting the @@ -178,9 +179,19 @@ bool ExplicitManagementImpl::Resize(void* object, size_t new_object_size) { const size_t new_size = RoundUp<kAllocationGranularity>( sizeof(HeapObjectHeader) + new_object_size); + // Size should not overflow. + static_assert(sizeof(HeapObjectHeader) >= kAllocationGranularity); + // On 64-bit systems, new_object_size can be at most 33 bits, so we know that + // adding sizeof(HeapObjectHeader) to it can't overflow. On 32-bit systems, we + // need to check it. +#if !defined(V8_HOST_ARCH_64_BIT) + if (new_size < new_object_size) { + return false; + } +#endif - if (new_size < sizeof(HeapObjectHeader) || - new_size >= kLargeObjectSizeThreshold) { + DCHECK_GT(new_size, sizeof(HeapObjectHeader)); + if (new_size >= kLargeObjectSizeThreshold) { return false; } diff --git a/deps/v8/src/heap/cppgc-internal/free-list.cc b/deps/v8/src/heap/cppgc-internal/free-list.cc index 9e2f9bff192e..7d3edd3888c6 100644 --- a/deps/v8/src/heap/cppgc-internal/free-list.cc +++ b/deps/v8/src/heap/cppgc-internal/free-list.cc @@ -5,6 +5,7 @@ #include "src/heap/cppgc-internal/free-list.h" #include <algorithm> +#include <bit> #include "include/cppgc/internal/logging.h" #include "src/base/bits.h" @@ -17,8 +18,7 @@ namespace internal { namespace { uint32_t BucketIndexForSize(uint32_t size) { - return v8::base::bits::WhichPowerOfTwo( - v8::base::bits::RoundDownToPowerOfTwo32(size)); + return v8::base::bits::WhichPowerOfTwo(std::bit_floor(size)); } } // namespace diff --git a/deps/v8/src/heap/cppgc-internal/heap-base.cc b/deps/v8/src/heap/cppgc-internal/heap-base.cc index 0c37f3645f6d..de79f62b6caa 100644 --- a/deps/v8/src/heap/cppgc-internal/heap-base.cc +++ b/deps/v8/src/heap/cppgc-internal/heap-base.cc @@ -4,6 +4,7 @@ #include "src/heap/cppgc-internal/heap-base.h" +#include <algorithm> #include <memory> #include "include/cppgc/heap-consistency.h" @@ -96,12 +97,33 @@ class AgeTableResetter final : protected HeapVisitor<AgeTableResetter> { } // namespace +size_t CheckedAllocationSampler::GetSampleInterval() const { + subtle::DisallowGarbageCollectionScope no_gc(heap_); + return sampler_.GetSampleInterval(); +} + +bool CheckedAllocationSampler::OnAllocated(void* address, size_t size) { + subtle::DisallowGarbageCollectionScope no_gc(heap_); + return sampler_.OnAllocated(address, size); +} + +void CheckedAllocationSampler::OnFreed(void* address) { + subtle::DisallowGarbageCollectionScope no_gc(heap_); + sampler_.OnFreed(address); +} + +bool CheckedAllocationSampler::OnMove(void* from, void* to, size_t size) { + subtle::DisallowGarbageCollectionScope no_gc(heap_); + return sampler_.OnMove(from, to, size); +} + HeapBase::HeapBase( std::shared_ptr<cppgc::Platform> platform, const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces, StackSupport stack_support, MarkingType marking_support, SweepingType sweeping_support, GarbageCollector& garbage_collector, - std::optional<cppgc::StackStartMarker> stack_start_marker) + std::optional<cppgc::StackStartMarker> stack_start_marker, + cppgc::AllocationSampler* allocation_sampler) : raw_heap_(this, custom_spaces), platform_(std::move(platform)), oom_handler_(std::make_unique<FatalOutOfMemoryHandler>(this)), @@ -113,10 +135,15 @@ HeapBase::HeapBase( stats_collector_(std::make_unique<StatsCollector>(platform_.get())), stack_(std::make_unique<heap::base::Stack>()), prefinalizer_handler_(std::make_unique<PreFinalizerHandler>(*this)), + allocation_sampler_(allocation_sampler + ? std::optional<CheckedAllocationSampler>( + std::in_place, *this, *allocation_sampler) + : std::nullopt), compactor_(raw_heap_), - object_allocator_(raw_heap_, *page_backend_, *stats_collector_, - *prefinalizer_handler_, *oom_handler_, - garbage_collector), + object_allocator_( + raw_heap_, *page_backend_, *stats_collector_, *prefinalizer_handler_, + *oom_handler_, garbage_collector, + allocation_sampler_ ? &allocation_sampler_.value() : nullptr), sweeper_(*this), strong_persistent_region_(*this, *oom_handler_), weak_persistent_region_(*this, *oom_handler_), @@ -131,14 +158,44 @@ HeapBase::HeapBase( sweeping_support_(sweeping_support) { stats_collector_->RegisterObserver( &allocation_observer_for_PROCESS_HEAP_STATISTICS_); + const bool check_for_tls = ShouldCheckForTLSOnStack(); if (stack_start_marker) { - stack_->SetStackStart(stack_start_marker->stack_start()); + stack_->SetStackStart(stack_start_marker->stack_start(), check_for_tls); } else { - stack_->SetStackStart(v8::base::Stack::GetStackStart()); + stack_->SetStackStart(v8::base::Stack::GetEffectiveStackStart(), + check_for_tls); + } + if (allocation_sampler_) { + RegisterMoveListener(this); } } -HeapBase::~HeapBase() = default; +HeapBase::~HeapBase() { + if (allocation_sampler_) { + UnregisterMoveListener(this); + for (HeapObjectHeader* header : sampled_objects_) { + allocation_sampler_->OnFreed(header->ObjectStart()); + } + } +} + +void HeapBase::RemoveSampledObject(HeapObjectHeader* header) { + if (allocation_sampler_ && sampled_objects_.erase(header)) { + allocation_sampler_->OnFreed(header->ObjectStart()); + } +} + +void HeapBase::FilterSampledObjects() { + if (allocation_sampler_) { + absl::erase_if(sampled_objects_, [this](HeapObjectHeader* header) { + if (!header->IsMarked()) { + allocation_sampler_->OnFreed(header->ObjectStart()); + return true; + } + return false; + }); + } +} PageAllocator* HeapBase::page_allocator() const { #if defined(LEAK_SANITIZER) @@ -273,6 +330,7 @@ void HeapBase::Terminate() { object_allocator().ResetLinearAllocationBuffers(); stats_collector()->NotifyMarkingCompleted(0); ExecutePreFinalizers(); + FilterSampledObjects(); // TODO(chromium:1029379): Prefinalizers may black-allocate objects (under a // compile-time option). Run sweeping with forced finalization here. sweeper().Start({SweepingConfig::SweepingType::kAtomic, @@ -325,6 +383,21 @@ HeapStatistics HeapBase::CollectStatistics( return HeapStatisticsCollector().CollectDetailedStatistics(this); } +void HeapBase::OnMove(Address from, Address to, size_t size_including_header) { + DCHECK(allocation_sampler_); + auto* header_from = reinterpret_cast<HeapObjectHeader*>(from); + auto it = sampled_objects_.find(header_from); + if (it != sampled_objects_.end()) { + sampled_objects_.erase(it); + auto* header_to = reinterpret_cast<HeapObjectHeader*>(to); + if (allocation_sampler_->OnMove(header_from->ObjectStart(), + header_to->ObjectStart(), + size_including_header)) { + sampled_objects_.insert(header_to); + } + } +} + void HeapBase::CallMoveListeners(Address from, Address to, size_t size_including_header) { for (const auto& listener : move_listeners_) { @@ -362,6 +435,19 @@ std::optional<cppgc::StackStartMarker> HeapBase::stack_start_marker() { return stack_start_marker_; } +bool HeapBase::ShouldCheckForTLSOnStack() const { + // TODO(540324230): + // 1. Remove `!stack_start_marker_` once embedders migrate to + // StackStartScope. + // 2. Remove this method entirely and always check for TLS, once Blink + // correctly sets the stack start for all non-main threads. + if (!stack_start_marker_ && + !v8::base::Stack::HasCustomCurrentThreadStackStart()) { + return false; + } + return true; +} + ClassNameAsHeapObjectNameScope::ClassNameAsHeapObjectNameScope(HeapBase& heap) : heap_(heap), saved_heap_object_name_value_(heap_.name_of_unnamed_object()) { diff --git a/deps/v8/src/heap/cppgc-internal/heap-base.h b/deps/v8/src/heap/cppgc-internal/heap-base.h index 70f2409703c2..ee24b869187c 100644 --- a/deps/v8/src/heap/cppgc-internal/heap-base.h +++ b/deps/v8/src/heap/cppgc-internal/heap-base.h @@ -8,6 +8,7 @@ #include <memory> #include <set> +#include "absl/container/flat_hash_set.h" #include "include/cppgc/heap-handle.h" #include "include/cppgc/heap-statistics.h" #include "include/cppgc/heap.h" @@ -53,6 +54,7 @@ namespace testing { class Heap; } // namespace testing +class AllocationSampler; class Platform; namespace internal { @@ -78,8 +80,24 @@ class MoveListener { size_t size_including_header) = 0; }; +class CheckedAllocationSampler final : public cppgc::AllocationSampler { + public: + CheckedAllocationSampler(HeapBase& heap, cppgc::AllocationSampler& sampler) + : heap_(heap), sampler_(sampler) {} + + size_t GetSampleInterval() const final; + bool OnAllocated(void* address, size_t size) final; + void OnFreed(void* address) final; + bool OnMove(void* from, void* to, size_t size) final; + + private: + HeapBase& heap_; + cppgc::AllocationSampler& sampler_; +}; + // Base class for heap implementations. -class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { +class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle, + public MoveListener { public: using StackSupport = cppgc::Heap::StackSupport; using MarkingType = cppgc::Heap::MarkingType; @@ -96,7 +114,8 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces, StackSupport stack_support, MarkingType marking_support, SweepingType sweeping_support, GarbageCollector& garbage_collector, - std::optional<cppgc::StackStartMarker> stack_start_marker); + std::optional<cppgc::StackStartMarker> stack_start_marker, + cppgc::AllocationSampler* allocation_sampler = nullptr); virtual ~HeapBase(); HeapBase(const HeapBase&) = delete; @@ -136,6 +155,12 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { ObjectAllocator& object_allocator() { return object_allocator_; } const ObjectAllocator& object_allocator() const { return object_allocator_; } + void AddSampledObject(HeapObjectHeader* header) { + sampled_objects_.insert(header); + } + void RemoveSampledObject(HeapObjectHeader* header); + void FilterSampledObjects(); + Sweeper& sweeper() { return sweeper_; } const Sweeper& sweeper() const { return sweeper_; } @@ -182,6 +207,8 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { std::optional<cppgc::StackStartMarker> stack_start_marker(); + bool ShouldCheckForTLSOnStack() const; + // Termination drops all roots (clears them out) and runs garbage collections // in a bounded fixed point loop until no new objects are created in // destructors. Exceeding the loop bound results in a crash. @@ -240,6 +267,9 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { name_for_unnamed_object_ = value; } + // MoveListener implementation: + void OnMove(Address from, Address to, size_t size_including_header) override; + // Callback support so that other components can listen to when objects are // moved. bool HasMoveListeners() const { return !move_listeners_.empty(); } @@ -311,6 +341,7 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { std::unique_ptr<heap::base::Stack> stack_; std::unique_ptr<PreFinalizerHandler> prefinalizer_handler_; std::unique_ptr<MarkerBase> marker_; + std::optional<CheckedAllocationSampler> allocation_sampler_; Compactor compactor_; ObjectAllocator object_allocator_; @@ -345,6 +376,7 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle { HeapObjectNameForUnnamedObject::kUseHiddenName; std::vector<MoveListener*> move_listeners_; + absl::flat_hash_set<HeapObjectHeader*> sampled_objects_; friend class MarkerBase::IncrementalMarkingTask; friend class cppgc::subtle::DisallowGarbageCollectionScope; diff --git a/deps/v8/src/heap/cppgc-internal/heap-page.cc b/deps/v8/src/heap/cppgc-internal/heap-page.cc index 160c116946d7..aa70d3ac52b0 100644 --- a/deps/v8/src/heap/cppgc-internal/heap-page.cc +++ b/deps/v8/src/heap/cppgc-internal/heap-page.cc @@ -119,8 +119,7 @@ const HeapObjectHeader* BasePage::TryObjectHeaderFromInnerAddress( .linear_allocation_buffer() .size()); - PlatformAwareObjectStartBitmap& bitmap = - NormalPage::From(this)->object_start_bitmap(); + ObjectStartBitmap& bitmap = NormalPage::From(this)->object_start_bitmap(); const HeapObjectHeader* header = bitmap.FindHeader<AccessMode::kNonAtomic>( static_cast<ConstAddress>(address)); diff --git a/deps/v8/src/heap/cppgc-internal/heap-page.h b/deps/v8/src/heap/cppgc-internal/heap-page.h index ad9c77d9ab61..10b6cd064ed0 100644 --- a/deps/v8/src/heap/cppgc-internal/heap-page.h +++ b/deps/v8/src/heap/cppgc-internal/heap-page.h @@ -253,7 +253,7 @@ class V8_EXPORT_PRIVATE NormalPage final : public BasePage { allocated_bytes_at_last_gc_ = bytes; } - PlatformAwareObjectStartBitmap& object_start_bitmap() const { + ObjectStartBitmap& object_start_bitmap() const { return object_start_bitmap_; } @@ -262,7 +262,7 @@ class V8_EXPORT_PRIVATE NormalPage final : public BasePage { ~NormalPage() = default; size_t allocated_bytes_at_last_gc_ = 0; - mutable PlatformAwareObjectStartBitmap object_start_bitmap_; + mutable ObjectStartBitmap object_start_bitmap_; }; class V8_EXPORT_PRIVATE LargePage final : public BasePage { @@ -354,8 +354,7 @@ const HeapObjectHeader& BasePage::ObjectHeaderFromInnerAddress( // We may find other headers (before this object) because not all object start // bits are initially set. The fixup then makes sure that we indeed find the // right one. - PlatformAwareObjectStartBitmap& bitmap = - NormalPage::From(this)->object_start_bitmap(); + ObjectStartBitmap& bitmap = NormalPage::From(this)->object_start_bitmap(); const HeapObjectHeader* header = bitmap.FindHeader<mode>(static_cast<ConstAddress>(address)); ConstAddress object_end = @@ -404,8 +403,7 @@ const HeapObjectHeader& BasePage::ObjectHeaderFromInnerAddressConcurrent( if (is_large()) { return *LargePage::From(this)->ObjectHeader(); } - PlatformAwareObjectStartBitmap& bitmap = - NormalPage::From(this)->object_start_bitmap(); + ObjectStartBitmap& bitmap = NormalPage::From(this)->object_start_bitmap(); const HeapObjectHeader* header = bitmap.FindHeader<mode>(static_cast<ConstAddress>(address)); // Make sure that the pointer is within the object bounds. diff --git a/deps/v8/src/heap/cppgc-internal/heap.cc b/deps/v8/src/heap/cppgc-internal/heap.cc index d1e5b01a26b9..55cdc3c5039c 100644 --- a/deps/v8/src/heap/cppgc-internal/heap.cc +++ b/deps/v8/src/heap/cppgc-internal/heap.cc @@ -76,7 +76,7 @@ Heap::Heap(std::shared_ptr<cppgc::Platform> platform, cppgc::Heap::HeapOptions options) : HeapBase(platform, options.custom_spaces, options.stack_support, options.marking_support, options.sweeping_support, gc_invoker_, - options.stack_start_marker), + options.stack_start_marker, options.allocation_sampler), gc_invoker_(this, platform_.get(), options.stack_support), growing_(&gc_invoker_, stats_collector_.get(), options.resource_constraints, options.marking_support, @@ -215,6 +215,8 @@ void Heap::FinalizeGarbageCollectionImpl(StackState stack_state) { ResetRememberedSet(); #endif // defined(CPPGC_YOUNG_GENERATION) + FilterSampledObjects(); + subtle::NoGarbageCollectionScope no_gc(*this); const SweepingConfig sweeping_config{ config_.sweeping_type, SweepingConfig::CompactableSpaceHandling::kSweep, diff --git a/deps/v8/src/heap/cppgc-internal/marker.h b/deps/v8/src/heap/cppgc-internal/marker.h index 84fec0712628..ad96e22f188b 100644 --- a/deps/v8/src/heap/cppgc-internal/marker.h +++ b/deps/v8/src/heap/cppgc-internal/marker.h @@ -10,6 +10,7 @@ #include "include/cppgc/heap.h" #include "include/cppgc/platform.h" #include "include/cppgc/visitor.h" +#include "src/base/logging.h" #include "src/base/macros.h" #include "src/base/platform/time.h" #include "src/heap/base/incremental-marking-schedule.h" @@ -238,20 +239,15 @@ class V8_EXPORT_PRIVATE Marker final : public MarkerBase { template <MarkerBase::WriteBarrierType type> void MarkerBase::WriteBarrierForObject(HeapObjectHeader& header) { - // The barrier optimizes for the bailout cases: - // - kDijkstra: Marked objects. - // - kSteele: Unmarked objects. - switch (type) { - case MarkerBase::WriteBarrierType::kDijkstra: - if (!header.TryMarkAtomic()) { - return; - } - break; - case MarkerBase::WriteBarrierType::kSteele: - if (!header.IsMarked<AccessMode::kAtomic>()) { - return; - } - break; + // The Dijkstra barrier bails out on marked objects. + // The Steele barrier marks the object regardless of its current state. + // It's important to make sure the object is marked here since unmarking + // below for in construction objects expects a marked object. + const bool was_already_marked = !header.TryMarkAtomic(); + if (type == MarkerBase::WriteBarrierType::kDijkstra) { + if (was_already_marked) { + return; + } } // The barrier fired. Filter out in-construction objects here. This possibly @@ -267,13 +263,18 @@ void MarkerBase::WriteBarrierForObject(HeapObjectHeader& header) { return; } - switch (type) { - case MarkerBase::WriteBarrierType::kDijkstra: - mutator_marking_state_.write_barrier_worklist().Push(&header); - break; - case MarkerBase::WriteBarrierType::kSteele: - mutator_marking_state_.retrace_marked_objects_worklist().Push(&header); - break; + DCHECK_IMPLIES(was_already_marked, + type == MarkerBase::WriteBarrierType::kSteele); + if ((type == MarkerBase::WriteBarrierType::kDijkstra) || + !was_already_marked) { + // Push previously unmarked objects to the write barrier worklist, even for + // the Steele barrier, since popping from that worklist would also update + // the marked bytes counter. + mutator_marking_state_.write_barrier_worklist().Push(&header); + } else { + DCHECK((type == MarkerBase::WriteBarrierType::kSteele) && + was_already_marked); + mutator_marking_state_.retrace_marked_objects_worklist().Push(&header); } } diff --git a/deps/v8/src/heap/cppgc-internal/object-allocator.cc b/deps/v8/src/heap/cppgc-internal/object-allocator.cc index 4f9b46c49cd5..51c2e023f30a 100644 --- a/deps/v8/src/heap/cppgc-internal/object-allocator.cc +++ b/deps/v8/src/heap/cppgc-internal/object-allocator.cc @@ -136,13 +136,15 @@ ObjectAllocator::ObjectAllocator(RawHeap& heap, PageBackend& page_backend, StatsCollector& stats_collector, PreFinalizerHandler& prefinalizer_handler, FatalOutOfMemoryHandler& oom_handler, - GarbageCollector& garbage_collector) + GarbageCollector& garbage_collector, + cppgc::AllocationSampler* allocation_sampler) : raw_heap_(heap), page_backend_(page_backend), stats_collector_(stats_collector), prefinalizer_handler_(prefinalizer_handler), oom_handler_(oom_handler), - garbage_collector_(garbage_collector) {} + garbage_collector_(garbage_collector), + allocation_sampler_(allocation_sampler) {} void ObjectAllocator::OutOfLineAllocateGCSafePoint( NormalPageSpace& space, size_t size, AlignVal alignment, GCInfoIndex gcinfo, @@ -196,6 +198,12 @@ void* ObjectAllocator::OutOfLineAllocateImpl( oom_handler_("Oilpan: Large allocation."); #endif } + if (result && allocation_sampler_) { + if (allocation_sampler_->OnAllocated(result, size)) { + raw_heap_.heap()->AddSampledObject( + &HeapObjectHeader::FromObject(result)); + } + } return result; } @@ -226,25 +234,52 @@ void* ObjectAllocator::OutOfLineAllocateImpl( } // The allocation must succeed, as we just refilled the LAB. - void* result = - (dynamic_alignment == kAllocationGranularity) - ? AllocateObjectOnSpace(space, size, gcinfo, may_contain_mixins) - : AllocateObjectOnSpace(space, size, alignment, gcinfo, - may_contain_mixins); + void* result = (dynamic_alignment == kAllocationGranularity) + ? (may_contain_mixins == MayContainMixins::kYes + ? AllocateObjectOnSpace<MayContainMixins::kYes>( + space, size, gcinfo) + : AllocateObjectOnSpace<MayContainMixins::kNo>( + space, size, gcinfo)) + : (may_contain_mixins == MayContainMixins::kYes + ? AllocateObjectOnSpace<MayContainMixins::kYes>( + space, size, alignment, gcinfo) + : AllocateObjectOnSpace<MayContainMixins::kNo>( + space, size, alignment, gcinfo)); CHECK(result); + if (allocation_sampler_) { + if (allocation_sampler_->OnAllocated(result, size)) { + raw_heap_.heap()->AddSampledObject(&HeapObjectHeader::FromObject(result)); + } + } return result; } +void ObjectAllocator::ClampAndReplaceLinearAllocationBuffer( + NormalPageSpace& space, Address start, size_t size, size_t requested_size) { + if (allocation_sampler_) { + const size_t sample_interval = RoundUp<kAllocationGranularity>( + allocation_sampler_->GetSampleInterval()); + const size_t target_size = std::max(sample_interval, requested_size); + DCHECK(IsAligned(target_size, kAllocationGranularity)); + if (sample_interval > 0 && size > target_size) { + // Use only the first `target_size` bytes as the LAB payload and return + // the remainder to the free list to trigger a sample on the next + // interval. + AddToFreeList(space, start + target_size, size - target_size); + size = target_size; + } + } + ReplaceLinearAllocationBuffer(space, stats_collector_, start, size); +} + bool ObjectAllocator::TryExpandAndRefillLinearAllocationBuffer( - NormalPageSpace& space) { + NormalPageSpace& space, size_t size) { auto* const new_page = NormalPage::TryCreate(page_backend_, space); if (!new_page) return false; space.AddPage(new_page); - // Set linear allocation buffer to new page. - ReplaceLinearAllocationBuffer(space, stats_collector_, - new_page->PayloadStart(), - new_page->PayloadSize()); + ClampAndReplaceLinearAllocationBuffer(space, new_page->PayloadStart(), + new_page->PayloadSize(), size); return true; } @@ -270,7 +305,7 @@ bool ObjectAllocator::TryRefillLinearAllocationBuffer(NormalPageSpace& space, // Sweeping was off or did not yield in any memory within limited // contributing. We expand at this point as that's cheaper than possibly // continuing sweeping the whole heap. - if (TryExpandAndRefillLinearAllocationBuffer(space)) return true; + if (TryExpandAndRefillLinearAllocationBuffer(space, size)) return true; // Expansion failed. Before finishing all sweeping, finish sweeping of a given // space which is cheaper. @@ -290,7 +325,7 @@ bool ObjectAllocator::TryRefillLinearAllocationBuffer(NormalPageSpace& space, if (TryRefillLinearAllocationBufferFromFreeList(space, size)) return true; // Sweeping may have freed pages completely. - if (TryExpandAndRefillLinearAllocationBuffer(space)) return true; + if (TryExpandAndRefillLinearAllocationBuffer(space, size)) return true; } return false; } @@ -307,8 +342,8 @@ bool ObjectAllocator::TryRefillLinearAllocationBufferFromFreeList( page.ResetDiscardedMemory(); } - ReplaceLinearAllocationBuffer( - space, stats_collector_, static_cast<Address>(entry.address), entry.size); + ClampAndReplaceLinearAllocationBuffer( + space, static_cast<Address>(entry.address), entry.size, size); return true; } diff --git a/deps/v8/src/heap/cppgc-internal/object-allocator.h b/deps/v8/src/heap/cppgc-internal/object-allocator.h index 7baf3e84ab77..780722ae9b93 100644 --- a/deps/v8/src/heap/cppgc-internal/object-allocator.h +++ b/deps/v8/src/heap/cppgc-internal/object-allocator.h @@ -5,6 +5,7 @@ #ifndef V8_HEAP_CPPGC_INTERNAL_OBJECT_ALLOCATOR_H_ #define V8_HEAP_CPPGC_INTERNAL_OBJECT_ALLOCATOR_H_ +#include <atomic> #include <optional> #include "include/cppgc/internal/gc-info.h" @@ -20,6 +21,8 @@ namespace cppgc { +class AllocationSampler; + namespace internal { class ObjectAllocator; class PreFinalizerHandler; @@ -47,17 +50,20 @@ class V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle { static constexpr size_t kSmallestSpaceSize = 32; ObjectAllocator(RawHeap&, PageBackend&, StatsCollector&, PreFinalizerHandler&, - FatalOutOfMemoryHandler&, GarbageCollector&); + FatalOutOfMemoryHandler&, GarbageCollector&, + cppgc::AllocationSampler* = nullptr); - inline void* AllocateObject(size_t size, GCInfoIndex gcinfo, - MayContainMixins); + template <MayContainMixins> + inline void* AllocateObject(size_t size, GCInfoIndex gcinfo); + template <MayContainMixins> inline void* AllocateObject(size_t size, AlignVal alignment, - GCInfoIndex gcinfo, MayContainMixins); + GCInfoIndex gcinfo); + template <MayContainMixins> inline void* AllocateObject(size_t size, GCInfoIndex gcinfo, - CustomSpaceIndex space_index, MayContainMixins); + CustomSpaceIndex space_index); + template <MayContainMixins> inline void* AllocateObject(size_t size, AlignVal alignment, - GCInfoIndex gcinfo, CustomSpaceIndex space_index, - MayContainMixins); + GCInfoIndex gcinfo, CustomSpaceIndex space_index); void ResetLinearAllocationBuffers(); void MarkAllPagesAsYoung(); @@ -77,10 +83,11 @@ class V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle { inline static RawHeap::RegularSpaceType GetInitialSpaceIndexForSize( size_t size); - inline void* AllocateObjectOnSpace(NormalPageSpace&, size_t, GCInfoIndex, - MayContainMixins); + template <MayContainMixins> + inline void* AllocateObjectOnSpace(NormalPageSpace&, size_t, GCInfoIndex); + template <MayContainMixins> inline void* AllocateObjectOnSpace(NormalPageSpace&, size_t, AlignVal, - GCInfoIndex, MayContainMixins); + GCInfoIndex); inline void* OutOfLineAllocate(NormalPageSpace&, size_t, AlignVal, GCInfoIndex, MayContainMixins); @@ -98,7 +105,9 @@ class V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle { bool TryRefillLinearAllocationBuffer(NormalPageSpace&, size_t); bool TryRefillLinearAllocationBufferFromFreeList(NormalPageSpace&, size_t); - bool TryExpandAndRefillLinearAllocationBuffer(NormalPageSpace&); + bool TryExpandAndRefillLinearAllocationBuffer(NormalPageSpace&, size_t); + void ClampAndReplaceLinearAllocationBuffer(NormalPageSpace&, Address, size_t, + size_t); #ifdef V8_ENABLE_ALLOCATION_TIMEOUT void TriggerGCOnAllocationTimeoutIfNeeded(); @@ -110,6 +119,7 @@ class V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle { PreFinalizerHandler& prefinalizer_handler_; FatalOutOfMemoryHandler& oom_handler_; GarbageCollector& garbage_collector_; + cppgc::AllocationSampler* allocation_sampler_ = nullptr; #ifdef V8_ENABLE_ALLOCATION_TIMEOUT // Specifies how many allocations should be performed until triggering a // garbage collection. @@ -117,63 +127,87 @@ class V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle { #endif // V8_ENABLE_ALLOCATION_TIMEOUT }; -void* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo, - MayContainMixins may_contain_mixins) { +template <ObjectAllocator::MayContainMixins may_contain_mixins> +void* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo) { DCHECK(!in_disallow_gc_scope()); #ifdef V8_ENABLE_ALLOCATION_TIMEOUT TriggerGCOnAllocationTimeoutIfNeeded(); #endif // V8_ENABLE_ALLOCATION_TIMEOUT const size_t allocation_size = RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); + // On 64-bit systems, size can be at most 33 bits, so we know that adding + // sizeof(HeapObjectHeader) to it can't overflow. On 32-bit systems, we need + // to check it. +#if !defined(V8_HOST_ARCH_64_BIT) + CHECK_GT(allocation_size, size); +#endif const RawHeap::RegularSpaceType type = GetInitialSpaceIndexForSize(allocation_size); - return AllocateObjectOnSpace(NormalPageSpace::From(*raw_heap_.Space(type)), - allocation_size, gcinfo, may_contain_mixins); + return AllocateObjectOnSpace<may_contain_mixins>( + NormalPageSpace::From(*raw_heap_.Space(type)), allocation_size, gcinfo); } +template <ObjectAllocator::MayContainMixins may_contain_mixins> void* ObjectAllocator::AllocateObject(size_t size, AlignVal alignment, - GCInfoIndex gcinfo, - MayContainMixins may_contain_mixins) { + GCInfoIndex gcinfo) { DCHECK(!in_disallow_gc_scope()); #ifdef V8_ENABLE_ALLOCATION_TIMEOUT TriggerGCOnAllocationTimeoutIfNeeded(); #endif // V8_ENABLE_ALLOCATION_TIMEOUT const size_t allocation_size = RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); + // On 64-bit systems, size can be at most 33 bits, so we know that adding + // sizeof(HeapObjectHeader) to it can't overflow. On 32-bit systems, we need + // to check it. +#if !defined(V8_HOST_ARCH_64_BIT) + CHECK_GT(allocation_size, size); +#endif const RawHeap::RegularSpaceType type = GetInitialSpaceIndexForSize(allocation_size); - return AllocateObjectOnSpace(NormalPageSpace::From(*raw_heap_.Space(type)), - allocation_size, alignment, gcinfo, - may_contain_mixins); + return AllocateObjectOnSpace<may_contain_mixins>( + NormalPageSpace::From(*raw_heap_.Space(type)), allocation_size, alignment, + gcinfo); } +template <ObjectAllocator::MayContainMixins may_contain_mixins> void* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo, - CustomSpaceIndex space_index, - MayContainMixins may_contain_mixins) { + CustomSpaceIndex space_index) { DCHECK(!in_disallow_gc_scope()); #ifdef V8_ENABLE_ALLOCATION_TIMEOUT TriggerGCOnAllocationTimeoutIfNeeded(); #endif // V8_ENABLE_ALLOCATION_TIMEOUT const size_t allocation_size = RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); - return AllocateObjectOnSpace( + // On 64-bit systems, size can be at most 33 bits, so we know that adding + // sizeof(HeapObjectHeader) to it can't overflow. On 32-bit systems, we need + // to check it. +#if !defined(V8_HOST_ARCH_64_BIT) + CHECK_GT(allocation_size, size); +#endif + return AllocateObjectOnSpace<may_contain_mixins>( NormalPageSpace::From(*raw_heap_.CustomSpace(space_index)), - allocation_size, gcinfo, may_contain_mixins); + allocation_size, gcinfo); } +template <ObjectAllocator::MayContainMixins may_contain_mixins> void* ObjectAllocator::AllocateObject(size_t size, AlignVal alignment, GCInfoIndex gcinfo, - CustomSpaceIndex space_index, - MayContainMixins may_contain_mixins) { + CustomSpaceIndex space_index) { DCHECK(!in_disallow_gc_scope()); #ifdef V8_ENABLE_ALLOCATION_TIMEOUT TriggerGCOnAllocationTimeoutIfNeeded(); #endif // V8_ENABLE_ALLOCATION_TIMEOUT const size_t allocation_size = RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); - return AllocateObjectOnSpace( + // On 64-bit systems, size can be at most 33 bits, so we know that adding + // sizeof(HeapObjectHeader) to it can't overflow. On 32-bit systems, we need + // to check it. +#if !defined(V8_HOST_ARCH_64_BIT) + CHECK_GT(allocation_size, size); +#endif + return AllocateObjectOnSpace<may_contain_mixins>( NormalPageSpace::From(*raw_heap_.CustomSpace(space_index)), - allocation_size, alignment, gcinfo, may_contain_mixins); + allocation_size, alignment, gcinfo); } // static @@ -198,9 +232,10 @@ void* ObjectAllocator::OutOfLineAllocate(NormalPageSpace& space, size_t size, return object; } -void* ObjectAllocator::AllocateObjectOnSpace( - NormalPageSpace& space, size_t size, AlignVal alignment, GCInfoIndex gcinfo, - MayContainMixins may_contain_mixins) { +template <ObjectAllocator::MayContainMixins may_contain_mixins> +void* ObjectAllocator::AllocateObjectOnSpace(NormalPageSpace& space, + size_t size, AlignVal alignment, + GCInfoIndex gcinfo) { // The APIs are set up to support general alignment. Since we want to keep // track of the actual usage there the alignment support currently only covers // double-world alignment (8 bytes on 32bit and 16 bytes on 64bit @@ -238,15 +273,15 @@ void* ObjectAllocator::AllocateObjectOnSpace( return OutOfLineAllocate(space, size, alignment, gcinfo, may_contain_mixins); } - void* object = AllocateObjectOnSpace(space, size, gcinfo, may_contain_mixins); + void* object = AllocateObjectOnSpace<may_contain_mixins>(space, size, gcinfo); DCHECK_NOT_NULL(object); DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(object) & kAlignmentMask); return object; } -void* ObjectAllocator::AllocateObjectOnSpace( - NormalPageSpace& space, size_t size, GCInfoIndex gcinfo, - MayContainMixins may_contain_mixins) { +template <ObjectAllocator::MayContainMixins may_contain_mixins> +void* ObjectAllocator::AllocateObjectOnSpace(NormalPageSpace& space, + size_t size, GCInfoIndex gcinfo) { DCHECK_LT(0u, gcinfo); NormalPageSpace::LinearAllocationBuffer& current_lab = @@ -268,12 +303,24 @@ void* ObjectAllocator::AllocateObjectOnSpace( #endif auto* header = new (raw) HeapObjectHeader(size, gcinfo); - if (may_contain_mixins == MayContainMixins::kYes) { + if constexpr (may_contain_mixins == MayContainMixins::kYes) { // Only set the bit for mixins to make sure the concurrent marker may find // them. NormalPage::From(BasePage::FromPayload(header)) ->object_start_bitmap() .SetBit<AccessMode::kAtomic>(reinterpret_cast<ConstAddress>(header)); + // Ensure that the header and object start bit writes are visible before the + // object is visible to other threads. "Publication" here may happen via + // relaxed stores (on e.g. `Member`) which otherwise can move around. +#if (defined(V8_HOST_ARCH_ARM64) || defined(V8_HOST_ARCH_ARM)) && \ + (defined(__clang__) || defined(V8_CC_GNU)) && !defined(THREAD_SANITIZER) + // On ARM/ARM64 we only need a Store-Store fence (`dmb ishst`) to order the + // header and bitmap stores before subsequent publishing stores, avoiding + // draining prior loads as a full `dmb ish` would. + __asm__ __volatile__("dmb ishst" ::: "memory"); +#else + std::atomic_thread_fence(std::memory_order_release); +#endif } return header->ObjectStart(); diff --git a/deps/v8/src/heap/cppgc-internal/object-start-bitmap.h b/deps/v8/src/heap/cppgc-internal/object-start-bitmap.h index 2aead53dfb7f..5f1ab62d3876 100644 --- a/deps/v8/src/heap/cppgc-internal/object-start-bitmap.h +++ b/deps/v8/src/heap/cppgc-internal/object-start-bitmap.h @@ -9,8 +9,8 @@ #include <stdint.h> #include <array> +#include <atomic> -#include "include/cppgc/internal/write-barrier.h" #include "src/base/atomic-utils.h" #include "src/base/bits.h" #include "src/base/macros.h" @@ -170,12 +170,21 @@ void ObjectStartBitmap::store(size_t cell_index, uint8_t value) { object_start_bit_map_[cell_index] = value; return; } - // Use acq rel rmw here to avoid a situation when a pointer write may be - // reordered before the setting of the mark bit, which may lead to the - // concurrent marker missing the right object (because the bit is not yet - // propagated). +#if defined(THREAD_SANITIZER) + // In non-TSAN builds, ordering is guaranteed by the release fence after + // setting the bit during mixin allocation and the address dependency chain on + // the concurrent marker (Member -> bitmap cell -> HeapObjectHeader). TSAN + // does not model hardware address dependencies (so the release fence paired + // with a relaxed Member load does not establish happens-before in TSAN), and + // still requires release/acquire here to avoid reporting races on + // HeapObjectHeader memory that was previously written non-atomically (e.g. + // during lazy sweeping or freelist unlinking). + constexpr auto kMemoryOrder = std::memory_order_release; +#else + constexpr auto kMemoryOrder = std::memory_order_relaxed; +#endif // defined(THREAD_SANITIZER) std::atomic_ref<uint8_t>(object_start_bit_map_[cell_index]) - .exchange(value, std::memory_order_acq_rel); + .store(value, kMemoryOrder); } template <AccessMode mode> @@ -183,9 +192,15 @@ uint8_t ObjectStartBitmap::load(size_t cell_index) const { if (mode == AccessMode::kNonAtomic) { return object_start_bit_map_[cell_index]; } +#if defined(THREAD_SANITIZER) + // See comment in store(). + constexpr auto kMemoryOrder = std::memory_order_acquire; +#else + constexpr auto kMemoryOrder = std::memory_order_relaxed; +#endif // defined(THREAD_SANITIZER) return std::atomic_ref<uint8_t>( const_cast<uint8_t&>(object_start_bit_map_[cell_index])) - .load(std::memory_order_acquire); + .load(kMemoryOrder); } void ObjectStartBitmap::ObjectStartIndexAndBit(ConstAddress header_address, @@ -231,51 +246,6 @@ void ObjectStartBitmap::Clear() { std::fill(object_start_bit_map_.begin(), object_start_bit_map_.end(), 0); } -// A platform aware version of ObjectStartBitmap to provide platform specific -// optimizations (e.g. Use non-atomic stores on ARMv7 when not marking). -class V8_EXPORT_PRIVATE PlatformAwareObjectStartBitmap - : public ObjectStartBitmap { - public: - template <AccessMode = AccessMode::kNonAtomic> - inline void SetBit(ConstAddress); - template <AccessMode = AccessMode::kNonAtomic> - inline void ClearBit(ConstAddress); - - private: - template <AccessMode> - static bool ShouldForceNonAtomic(); -}; - -// static -template <AccessMode mode> -bool PlatformAwareObjectStartBitmap::ShouldForceNonAtomic() { -#if defined(V8_HOST_ARCH_ARM) - // Use non-atomic accesses on ARMv7 when marking is not active. - if (mode == AccessMode::kAtomic) { - if (V8_LIKELY(!WriteBarrier::IsEnabled())) return true; - } -#endif // defined(V8_HOST_ARCH_ARM) - return false; -} - -template <AccessMode mode> -void PlatformAwareObjectStartBitmap::SetBit(ConstAddress header_address) { - if (ShouldForceNonAtomic<mode>()) { - ObjectStartBitmap::SetBit<AccessMode::kNonAtomic>(header_address); - return; - } - ObjectStartBitmap::SetBit<mode>(header_address); -} - -template <AccessMode mode> -void PlatformAwareObjectStartBitmap::ClearBit(ConstAddress header_address) { - if (ShouldForceNonAtomic<mode>()) { - ObjectStartBitmap::ClearBit<AccessMode::kNonAtomic>(header_address); - return; - } - ObjectStartBitmap::ClearBit<mode>(header_address); -} - } // namespace internal } // namespace cppgc diff --git a/deps/v8/src/heap/cppgc-internal/platform.cc b/deps/v8/src/heap/cppgc-internal/platform.cc index b3c23863f0dd..b966dc52c787 100644 --- a/deps/v8/src/heap/cppgc-internal/platform.cc +++ b/deps/v8/src/heap/cppgc-internal/platform.cc @@ -4,6 +4,7 @@ #include "include/cppgc/platform.h" +#include "include/cppgc/common.h" #include "src/base/lazy-instance.h" #include "src/base/logging.h" #include "src/base/macros.h" @@ -105,4 +106,18 @@ void InitializeProcess(PageAllocator* page_allocator, void ShutdownProcess() { internal::g_page_allocator = nullptr; } +StackStartScope::StackStartScope(void* stack_start) + : previous_stack_start_( + v8::base::Stack::SetCurrentThreadStackStart(stack_start)) { + CHECK_NOT_NULL(stack_start); + CHECK_IMPLIES(previous_stack_start_, stack_start <= previous_stack_start_); +} + +StackStartScope::~StackStartScope() { + void* stack_start = + v8::base::Stack::SetCurrentThreadStackStart(previous_stack_start_); + CHECK_NOT_NULL(stack_start); + CHECK_IMPLIES(previous_stack_start_, stack_start <= previous_stack_start_); +} + } // namespace cppgc diff --git a/deps/v8/src/heap/cppgc-internal/sweeper.cc b/deps/v8/src/heap/cppgc-internal/sweeper.cc index b771a1b52de3..510333649673 100644 --- a/deps/v8/src/heap/cppgc-internal/sweeper.cc +++ b/deps/v8/src/heap/cppgc-internal/sweeper.cc @@ -114,7 +114,7 @@ class ObjectStartBitmapVerifier final return true; } - PlatformAwareObjectStartBitmap* bitmap_ = nullptr; + ObjectStartBitmap* bitmap_ = nullptr; HeapObjectHeader* prev_ = nullptr; }; @@ -352,7 +352,7 @@ typename FinalizationBuilder::ResultType SweepNormalPage( constexpr auto kAtomicAccess = AccessMode::kAtomic; FinalizationBuilder builder(*page, page_allocator); - PlatformAwareObjectStartBitmap& bitmap = page->object_start_bitmap(); + ObjectStartBitmap& bitmap = page->object_start_bitmap(); size_t live_bytes = 0; diff --git a/deps/v8/src/heap/cppgc-js/cpp-heap.cc b/deps/v8/src/heap/cppgc-js/cpp-heap.cc index c1de0c1c279f..5da533d8c677 100644 --- a/deps/v8/src/heap/cppgc-js/cpp-heap.cc +++ b/deps/v8/src/heap/cppgc-js/cpp-heap.cc @@ -104,9 +104,12 @@ class MinorGCHeapGrowing // static std::unique_ptr<CppHeap> CppHeap::Create(v8::Platform* platform, const CppHeapCreateParams& params) { + START_ALLOW_USE_DEPRECATED() return std::make_unique<internal::CppHeap>( platform, params.custom_spaces, params.marking_support, - params.sweeping_support, params.stack_start_marker); + params.sweeping_support, params.stack_start_marker, + params.allocation_sampler); + END_ALLOW_USE_DEPRECATED() } cppgc::AllocationHandle& CppHeap::GetAllocationHandle() { @@ -527,12 +530,14 @@ CppHeap::CppHeap( const std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>& custom_spaces, cppgc::Heap::MarkingType marking_support, cppgc::Heap::SweepingType sweeping_support, - std::optional<cppgc::StackStartMarker> stack_start_marker) + std::optional<cppgc::StackStartMarker> stack_start_marker, + cppgc::AllocationSampler* allocation_sampler) : cppgc::internal::HeapBase( std::make_shared<CppgcPlatformAdapter>(platform), custom_spaces, cppgc::internal::HeapBase::StackSupport:: kSupportsConservativeStackScan, - marking_support, sweeping_support, *this, stack_start_marker), + marking_support, sweeping_support, *this, stack_start_marker, + allocation_sampler), minor_gc_heap_growing_( std::make_unique<MinorGCHeapGrowing>(*stats_collector())), cross_heap_remembered_set_(*this) { @@ -760,6 +765,19 @@ CppHeap::SweepingType CppHeap::SelectSweepingType() const { } void CppHeap::UpdateGCCapabilitiesFromFlags() { + // Runtime flags may only reduce what the embedder requested via + // CppHeapCreateParams; they must never grant more. The std::min calls below + // do that directly. The marking else-branch does it by assigning kAtomic, + // which is the least capable value. All of this depends on the enumerators + // being ordered from least to most capable; reordering them would silently + // grant more than was requested. + static_assert(MarkingType::kAtomic < MarkingType::kIncremental); + static_assert(MarkingType::kIncremental < + MarkingType::kIncrementalAndConcurrent); + static_assert(SweepingType::kAtomic < SweepingType::kIncremental); + static_assert(SweepingType::kIncremental < + SweepingType::kIncrementalAndConcurrent); + CHECK_IMPLIES(v8_flags.cppheap_concurrent_marking, v8_flags.cppheap_incremental_marking); if (v8_flags.cppheap_concurrent_marking) { @@ -772,9 +790,13 @@ void CppHeap::UpdateGCCapabilitiesFromFlags() { marking_support_ = MarkingType::kAtomic; } - sweeping_support_ = v8_flags.single_threaded_gc - ? CppHeap::SweepingType::kIncremental - : CppHeap::SweepingType::kIncrementalAndConcurrent; + // Assigning unconditionally here would raise an embedder-requested kAtomic + // back up, silently ignoring CppHeapCreateParams::sweeping_support. + sweeping_support_ = + std::min(sweeping_support_, + v8_flags.single_threaded_gc + ? CppHeap::SweepingType::kIncremental + : CppHeap::SweepingType::kIncrementalAndConcurrent); } void CppHeap::InitializeMarking( @@ -1050,6 +1072,8 @@ void CppHeap::CompactAndSweep() { ResetCrossHeapRememberedSet(); #endif // defined(CPPGC_YOUNG_GENERATION) + FilterSampledObjects(); + { cppgc::subtle::NoGarbageCollectionScope no_gc(*this); cppgc::internal::SweepingConfig::CompactableSpaceHandling diff --git a/deps/v8/src/heap/cppgc-js/cpp-heap.h b/deps/v8/src/heap/cppgc-js/cpp-heap.h index 106894d8a74b..aca6781f2f10 100644 --- a/deps/v8/src/heap/cppgc-js/cpp-heap.h +++ b/deps/v8/src/heap/cppgc-js/cpp-heap.h @@ -111,7 +111,8 @@ class V8_EXPORT_PRIVATE CppHeap final CppHeap(v8::Platform*, const std::vector<std::unique_ptr<cppgc::CustomSpaceBase>>&, cppgc::Heap::MarkingType, cppgc::Heap::SweepingType, - std::optional<cppgc::StackStartMarker>); + std::optional<cppgc::StackStartMarker>, + cppgc::AllocationSampler* = nullptr); ~CppHeap() final; CppHeap(const CppHeap&) = delete; diff --git a/deps/v8/src/heap/factory-base-inl.h b/deps/v8/src/heap/factory-base-inl.h index 92064a4ec8fe..97b681dac5e6 100644 --- a/deps/v8/src/heap/factory-base-inl.h +++ b/deps/v8/src/heap/factory-base-inl.h @@ -48,6 +48,66 @@ Handle<Boolean> FactoryBase<Impl>::ToBoolean(bool value) { : Cast<Boolean>(impl()->false_value()); } +namespace detail { +template <typename T> +struct is_safe_allocation_arg : std::true_type {}; +template <typename U> +struct is_safe_allocation_arg<Tagged<U>> + : std::bool_constant<is_subtype_v<U, Smi> || is_read_only_v<U>> {}; +template <typename U> + requires(std::is_base_of_v<HeapObject, U>) +struct is_safe_allocation_arg<U*> : std::false_type {}; + +template <typename Arg> +decltype(auto) UnwrapAllocationArg(Arg&& arg) { + using Decayed = std::decay_t<Arg>; + if constexpr (is_direct_handle_v<Decayed> || + std::is_base_of_v<HandleBase, Decayed>) { + return *arg; + } else { + static_assert( + is_safe_allocation_arg<Decayed>::value, + "Pass handles, not raw Tagged<HeapObject>, to Factory::New<T> " + "since allocation can trigger GC."); + return std::forward<Arg>(arg); + } +} +} // namespace detail + +template <typename Impl> +template <typename T, typename... Args> +DirectHandle<T> FactoryBase<Impl>::New(AllocationType allocation, + Args&&... args) { + static_assert( + !requires { &T::template OffsetOfDataStart<T>; }, + "Cannot use Factory::New<T> with variable-sized types " + "(FLEXIBLE_ARRAY_MEMBER)."); + static_assert(sizeof(T) <= kMaxRegularHeapObjectSize); + AllocationWitness witness = AllocateWithWitness(sizeof(T), allocation); + T* result = new (witness) + T(witness, detail::UnwrapAllocationArg(std::forward<Args>(args))...); + return direct_handle(result, isolate()); +} + +template <typename Impl> +template <typename T, AllocationType kAllocation, typename... Args> +DirectHandle<T> FactoryBase<Impl>::New(Args&&... args) { + return New<T>(kAllocation, std::forward<Args>(args)...); +} + +template <typename Impl> +template <AllocationType allocation> +Handle<UninitializedHeapNumber> +FactoryBase<Impl>::NewUninitializedHeapNumber() { + static_assert(sizeof(HeapNumber) == sizeof(UninitializedHeapNumber)); + static_assert(sizeof(HeapNumber) <= kMaxRegularHeapObjectSize); + AllocationWitness witness = AllocateWithWitness( + sizeof(UninitializedHeapNumber), allocation, + USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL ? kDoubleUnaligned + : kTaggedAligned); + return handle(new (witness) UninitializedHeapNumber(witness), isolate()); +} + template <typename Impl> template <AllocationType allocation> Handle<Number> FactoryBase<Impl>::NewNumber(double value) { @@ -103,66 +163,36 @@ DirectHandle<Number> FactoryBase<Impl>::NewNumberFromInt64(int64_t value) { template <typename Impl> template <AllocationType allocation> Handle<HeapNumber> FactoryBase<Impl>::NewHeapNumber(double value) { - Handle<HeapNumber> heap_number = NewHeapNumber<allocation>(); - heap_number->set_value(value); - return heap_number; + static_assert(sizeof(HeapNumber) <= kMaxRegularHeapObjectSize); + AllocationWitness witness = AllocateWithWitness( + sizeof(HeapNumber), allocation, + USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL ? kDoubleUnaligned + : kTaggedAligned); + std::optional<SharedObjectConditionalSafePublishGuard> publish_guard; + if constexpr (IsSharedAllocationType(allocation)) { + publish_guard.emplace(witness.object(), allocation); + } + return handle(new (witness) HeapNumber(witness, value), isolate()); } template <typename Impl> template <AllocationType allocation> Handle<HeapNumber> FactoryBase<Impl>::NewHeapNumberFromBits(uint64_t bits) { - Handle<HeapNumber> heap_number = NewHeapNumber<allocation>(); - heap_number->set_value_as_bits(bits); - return heap_number; -} - -template <typename Impl> -template <AllocationType allocation> -Handle<HeapNumber> FactoryBase<Impl>::NewHeapNumberWithHoleNaN() { - return NewHeapNumberFromBits<allocation>(kHoleNanInt64); + static_assert(sizeof(HeapNumber) <= kMaxRegularHeapObjectSize); + AllocationWitness witness = AllocateWithWitness( + sizeof(HeapNumber), allocation, + USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL ? kDoubleUnaligned + : kTaggedAligned); + return handle(new (witness) HeapNumber(witness, Float64::FromBits(bits)), + isolate()); } template <typename Impl> template <AllocationType allocation> Handle<HeapNumber> FactoryBase<Impl>::NewHeapInt32(int32_t value) { - Handle<HeapNumber> heap_number = NewHeapNumber<allocation>(); - heap_number->set_value_as_bits( - (static_cast<uint64_t>(kHoleNanUpper32) << 32) | value); - return heap_number; -} - -template <typename Impl> -template <typename StructType> -Tagged<StructType> FactoryBase<Impl>::NewStructInternal( - InstanceType type, AllocationType allocation, bool initialize_fields) { - static_assert(std::is_base_of_v<Struct, StructType>); - ReadOnlyRoots roots = read_only_roots(); - Tagged<Map> map = Map::GetMapFor(roots, type); - int size = sizeof(StructType); - return Cast<StructType>( - NewStructInternal(roots, map, size, allocation, initialize_fields)); -} - -template <typename Impl> -Tagged<Struct> FactoryBase<Impl>::NewStructInternal(ReadOnlyRoots roots, - Tagged<Map> map, int size, - AllocationType allocation, - bool initialize_fields) { - DCHECK_EQ(size, map->instance_size()); - Tagged<HeapObject> result = AllocateRawWithImmortalMap(size, allocation, map); - - const int length = (size >> kTaggedSizeLog2) - 1; - if (initialize_fields) { - MemsetTagged(result->RawField(sizeof(Struct)), roots.undefined_value(), - length); - - } else if (DEBUG_BOOL) { - // Zap the whole object in order to ensure that the caller initializes - // all fields. - MemsetTagged(result->RawField(sizeof(Struct)), - Tagged<Object>(kDebugZapValue), length); - } - return Cast<Struct>(result); + return NewHeapNumberFromBits<allocation>( + (static_cast<uint64_t>(kHoleNanUpper32) << 32) | + static_cast<uint32_t>(value)); } } // namespace internal diff --git a/deps/v8/src/heap/factory-base.cc b/deps/v8/src/heap/factory-base.cc index 23bc62755017..09670834866c 100644 --- a/deps/v8/src/heap/factory-base.cc +++ b/deps/v8/src/heap/factory-base.cc @@ -20,66 +20,32 @@ #include "src/heap/read-only-heap.h" #include "src/logging/log.h" #include "src/objects/arguments-inl.h" +#include "src/objects/bytecode-array-inl.h" +#include "src/objects/code-inl.h" #include "src/objects/instance-type.h" #include "src/objects/js-regexp-inl.h" #include "src/objects/literal-objects-inl.h" #include "src/objects/module-inl.h" #include "src/objects/oddball.h" +#include "src/objects/script-inl.h" #include "src/objects/shared-function-info-inl.h" #include "src/objects/shared-function-info.h" #include "src/objects/source-text-module.h" #include "src/objects/string-inl.h" #include "src/objects/string.h" +#include "src/objects/struct-inl.h" #include "src/objects/swiss-name-dictionary-inl.h" #include "src/objects/template-objects-inl.h" +#include "src/objects/templates-inl.h" #include "src/roots/roots.h" #include "src/sandbox/check.h" namespace v8 { namespace internal { -template <typename Impl> -template <AllocationType allocation> -Handle<HeapNumber> FactoryBase<Impl>::NewHeapNumber() { - static_assert(sizeof(HeapNumber) <= kMaxRegularHeapObjectSize); - Tagged<Map> map = read_only_roots().heap_number_map(); - Tagged<HeapObject> result = AllocateRawWithImmortalMap( - sizeof(HeapNumber), allocation, map, - USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL ? kDoubleUnaligned - : kTaggedAligned); - return handle(Cast<HeapNumber>(result), isolate()); -} - -template V8_EXPORT_PRIVATE Handle<HeapNumber> -FactoryBase<Factory>::NewHeapNumber<AllocationType::kYoung>(); -template V8_EXPORT_PRIVATE Handle<HeapNumber> -FactoryBase<Factory>::NewHeapNumber<AllocationType::kOld>(); -template V8_EXPORT_PRIVATE Handle<HeapNumber> -FactoryBase<Factory>::NewHeapNumber<AllocationType::kReadOnly>(); -template V8_EXPORT_PRIVATE Handle<HeapNumber> -FactoryBase<Factory>::NewHeapNumber<AllocationType::kSharedOld>(); - -template V8_EXPORT_PRIVATE Handle<HeapNumber> -FactoryBase<LocalFactory>::NewHeapNumber<AllocationType::kOld>(); - -template <typename Impl> -Handle<Struct> FactoryBase<Impl>::NewStruct(InstanceType type, - AllocationType allocation) { - ReadOnlyRoots roots = read_only_roots(); - Tagged<Map> map = Map::GetMapFor(roots, type); - int size = map->instance_size(); - return handle(NewStructInternal(roots, map, size, allocation, true), - isolate()); -} - template <typename Impl> Handle<AccessorPair> FactoryBase<Impl>::NewAccessorPair() { - auto accessors = NewStructInternal<AccessorPair>(ACCESSOR_PAIR_TYPE, - AllocationType::kOld, false); - DisallowGarbageCollection no_gc; - accessors->set_getter(read_only_roots().null_value(), SKIP_WRITE_BARRIER); - accessors->set_setter(read_only_roots().null_value(), SKIP_WRITE_BARRIER); - return handle(accessors, isolate()); + return indirect_handle(New<AccessorPair, AllocationType::kOld>(), isolate()); } template <typename Impl> @@ -173,15 +139,7 @@ Handle<Code> FactoryBase<Impl>::NewCode(const NewCodeOptions& options) { template <typename Impl> DirectHandle<CodeWrapper> FactoryBase<Impl>::NewCodeWrapper() { - DirectHandle<CodeWrapper> wrapper( - Cast<CodeWrapper>(NewWithImmortalMap(read_only_roots().code_wrapper_map(), - AllocationType::kOld)), - isolate()); - // The CodeWrapper is typically created before the Code object it wraps, so - // the code field cannot yet be set. However, as a heap verifier might see - // the wrapper before the field can be set, we need to clear the field here. - wrapper->clear_code(); - return wrapper; + return New<CodeWrapper, AllocationType::kOld>(); } template <typename Impl> @@ -385,17 +343,7 @@ DirectHandle<BytecodeWrapper> FactoryBase<Impl>::NewBytecodeWrapper( AllocationType allocation) { DCHECK(allocation == AllocationType::kOld || allocation == AllocationType::kSharedOld); - - DirectHandle<BytecodeWrapper> wrapper( - Cast<BytecodeWrapper>(NewWithImmortalMap( - read_only_roots().bytecode_wrapper_map(), allocation)), - isolate()); - // The BytecodeWrapper is typically created before the BytecodeArray it - // wraps, so the bytecode field cannot yet be set. However, as a heap - // verifier might see the wrapper before the field can be set, we need to - // clear the field here. - wrapper->clear_bytecode(); - return wrapper; + return New<BytecodeWrapper>(allocation); } template <typename Impl> @@ -412,34 +360,8 @@ Handle<Script> FactoryBase<Impl>::NewScriptWithId( ScriptEventType script_event_type) { DCHECK(IsString(*source) || IsUndefined(*source)); // Create and initialize script object. - ReadOnlyRoots roots = read_only_roots(); - Handle<Script> script = handle( - NewStructInternal<Script>(SCRIPT_TYPE, AllocationType::kOld), isolate()); - { - DisallowGarbageCollection no_gc; - Tagged<Script> raw = *script; - raw->set_source(*source); - raw->set_name(roots.undefined_value(), SKIP_WRITE_BARRIER); - raw->set_id(script_id); - raw->set_line_offset(0); - raw->set_column_offset(0); - raw->set_context_data(roots.undefined_value(), SKIP_WRITE_BARRIER); - raw->set_type(Script::Type::kNormal); - raw->set_line_ends(Smi::zero()); - raw->set_eval_from_shared_or_wrapped_arguments(roots.undefined_value(), - SKIP_WRITE_BARRIER); - raw->set_eval_from_position(0); - raw->set_infos(roots.empty_weak_fixed_array(), SKIP_WRITE_BARRIER); - raw->set_flags(0); - raw->set_host_defined_options(roots.empty_fixed_array(), - SKIP_WRITE_BARRIER); - raw->set_source_hash(roots.undefined_value(), SKIP_WRITE_BARRIER); - raw->set_compiled_lazy_function_positions(roots.undefined_value(), - SKIP_WRITE_BARRIER); -#ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME - raw->set_script_or_modules(roots.empty_array_list()); -#endif - } + Handle<Script> script = indirect_handle( + New<Script, AllocationType::kOld>(source, script_id), isolate()); impl()->ProcessNewScript(script, script_event_type); return script; } @@ -492,15 +414,9 @@ Handle<SharedFunctionInfo> FactoryBase<Impl>::NewSharedFunctionInfoForLiteral( template <typename Impl> Handle<SharedFunctionInfo> FactoryBase<Impl>::CloneSharedFunctionInfo( DirectHandle<SharedFunctionInfo> other) { - Tagged<Map> map = read_only_roots().shared_function_info_map(); - - Tagged<SharedFunctionInfo> shared = - Cast<SharedFunctionInfo>(NewWithImmortalMap(map, AllocationType::kOld)); - DisallowGarbageCollection no_gc; - - shared->CopyFrom(*other, isolate()); - - return handle(shared, isolate()); + return indirect_handle( + New<SharedFunctionInfo, AllocationType::kOld>(other, isolate()), + isolate()); } template <typename Impl> @@ -521,15 +437,10 @@ template <typename Impl> Handle<PreparseData> FactoryBase<Impl>::NewPreparseData(int data_length, int children_length) { int size = PreparseData::SizeFor(data_length, children_length); - Tagged<PreparseData> result = Cast<PreparseData>(AllocateRawWithImmortalMap( - size, AllocationType::kOld, read_only_roots().preparse_data_map())); - DisallowGarbageCollection no_gc; - result->set_data_length(data_length); - result->set_children_length(children_length); - MemsetTagged(ObjectSlot(result->children()), read_only_roots().null_value(), - children_length); - result->clear_padding(); - return handle(result, isolate()); + AllocationWitness witness = AllocateWithWitness(size, AllocationType::kOld); + return handle(new (witness) + PreparseData(witness, data_length, children_length), + isolate()); } template <typename Impl> @@ -682,34 +593,21 @@ template <typename Impl> Handle<ArrayBoilerplateDescription> FactoryBase<Impl>::NewArrayBoilerplateDescription( ElementsKind elements_kind, DirectHandle<FixedArrayBase> constant_values) { - auto result = NewStructInternal<ArrayBoilerplateDescription>( - ARRAY_BOILERPLATE_DESCRIPTION_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - result->set_elements_kind(elements_kind); - result->set_constant_elements(*constant_values); - return handle(result, isolate()); + return indirect_handle(New<ArrayBoilerplateDescription, AllocationType::kOld>( + elements_kind, constant_values), + isolate()); } template <typename Impl> DirectHandle<RegExpDataWrapper> FactoryBase<Impl>::NewRegExpDataWrapper() { - DirectHandle<RegExpDataWrapper> wrapper( - Cast<RegExpDataWrapper>(NewWithImmortalMap( - read_only_roots().regexp_data_wrapper_map(), AllocationType::kOld)), - isolate()); - wrapper->clear_data(); - return wrapper; + return New<RegExpDataWrapper, AllocationType::kOld>(); } template <typename Impl> DirectHandle<RegExpBoilerplateDescription> FactoryBase<Impl>::NewRegExpBoilerplateDescription( DirectHandle<RegExpData> data, Tagged<Smi> flags) { - auto result = NewStructInternal<RegExpBoilerplateDescription>( - REG_EXP_BOILERPLATE_DESCRIPTION_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - result->set_data(*data); - result->set_flags(flags.value()); - return direct_handle(result, isolate()); + return New<RegExpBoilerplateDescription, AllocationType::kOld>(data, flags); } template <typename Impl> @@ -723,12 +621,9 @@ FactoryBase<Impl>::NewTemplateObjectDescription( DCHECK_EQ(raw_strings_len, cooked_strings_len); DCHECK_LT(0, raw_strings_len); #endif - auto result = NewStructInternal<TemplateObjectDescription>( - TEMPLATE_OBJECT_DESCRIPTION_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - result->set_raw_strings(*raw_strings); - result->set_cooked_strings(*cooked_strings); - return handle(result, isolate()); + return indirect_handle(New<TemplateObjectDescription, AllocationType::kOld>( + raw_strings, cooked_strings), + isolate()); } template <typename Impl> @@ -736,19 +631,12 @@ Handle<FeedbackMetadata> FactoryBase<Impl>::NewFeedbackMetadata( int slot_count, int create_closure_slot_count, AllocationType allocation) { DCHECK_LE(0, slot_count); int size = FeedbackMetadata::SizeFor(slot_count, create_closure_slot_count); - Tagged<FeedbackMetadata> result = - Cast<FeedbackMetadata>(AllocateRawWithImmortalMap( - size, allocation, read_only_roots().feedback_metadata_map())); - result->set_slot_count(slot_count); - result->set_create_closure_slot_count(create_closure_slot_count); - - // Initialize the data section to 0. - int data_size = size - FeedbackMetadata::kHeaderSize; - Address data_start = result->address() + FeedbackMetadata::kHeaderSize; - memset(reinterpret_cast<uint8_t*>(data_start), 0, data_size); + AllocationWitness witness = AllocateWithWitness(size, allocation); // Fields have been zeroed out but not initialized, so this object will not // pass object verification at this point. - return handle(result, isolate()); + return handle(new (witness) FeedbackMetadata(witness, slot_count, + create_closure_slot_count), + isolate()); } template <typename Impl> @@ -757,15 +645,8 @@ Handle<CoverageInfo> FactoryBase<Impl>::NewCoverageInfo( const int slot_count = static_cast<int>(slots.size()); int size = CoverageInfo::SizeFor(slot_count); - Tagged<Map> map = read_only_roots().coverage_info_map(); - Tagged<CoverageInfo> info = Cast<CoverageInfo>( - AllocateRawWithImmortalMap(size, AllocationType::kOld, map)); - info->set_slot_count(slot_count); - for (int i = 0; i < slot_count; i++) { - SourceRange range = slots[i]; - info->InitializeSlot(i, range.start, range.end); - } - return handle(info, isolate()); + AllocationWitness witness = AllocateWithWitness(size, AllocationType::kOld); + return handle(new (witness) CoverageInfo(witness, slots), isolate()); } template <typename Impl> @@ -865,13 +746,13 @@ FactoryBase<Impl>::NewOneByteInternalizedStringFromTwoByte( template <typename Impl> template <typename SeqStringT> MaybeHandle<SeqStringT> FactoryBase<Impl>::NewRawStringWithMap( - int length, Tagged<Map> map, AllocationType allocation, + uint32_t length, Tagged<Map> map, AllocationType allocation, AllocationHint hint) { DCHECK(SeqStringT::IsCompatibleMap(map, read_only_roots())); DCHECK_IMPLIES(!StringShape(map).IsShared(), RefineAllocationTypeForInPlaceInternalizableString( allocation, map) == allocation); - if (length < 0 || static_cast<uint32_t>(length) > String::kMaxLength) { + if (length > String::kMaxLength) { THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); } DCHECK_GT(length, 0); // Use Factory::empty_string() instead. @@ -914,7 +795,7 @@ MaybeHandle<SeqTwoByteString> FactoryBase<Impl>::NewRawTwoByteString( template <typename Impl> MaybeHandle<SeqOneByteString> FactoryBase<Impl>::NewRawSharedOneByteString( - int length) { + uint32_t length) { return NewRawStringWithMap<SeqOneByteString>( length, read_only_roots().shared_seq_one_byte_string_map(), AllocationType::kSharedOld, AllocationHint()); @@ -922,7 +803,7 @@ MaybeHandle<SeqOneByteString> FactoryBase<Impl>::NewRawSharedOneByteString( template <typename Impl> MaybeHandle<SeqTwoByteString> FactoryBase<Impl>::NewRawSharedTwoByteString( - int length) { + uint32_t length) { return NewRawStringWithMap<SeqTwoByteString>( length, read_only_roots().shared_seq_two_byte_string_map(), AllocationType::kSharedOld, AllocationHint()); @@ -1063,12 +944,16 @@ template <typename Impl> MaybeHandle<String> FactoryBase<Impl>::NewStringFromOneByte( base::Vector<const uint8_t> string, AllocationType allocation) { DCHECK_NE(allocation, AllocationType::kReadOnly); - int length = string.length(); + size_t length = string.size(); if (length == 0) return empty_string(); if (length == 1) return LookupSingleCharacterStringFromCode(string[0]); + if (length > String::kMaxLength) { + THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); + } + uint32_t length_uint32 = static_cast<uint32_t>(length); Handle<SeqOneByteString> result; ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, - NewRawOneByteString(string.length(), allocation)); + NewRawOneByteString(length_uint32, allocation)); DisallowGarbageCollection no_gc; // Copy the characters into the new object. @@ -1259,13 +1144,9 @@ FactoryBase<Impl>::NewSourceTextModuleInfo() { template <typename Impl> Handle<SharedFunctionInfo> FactoryBase<Impl>::NewSharedFunctionInfo( AllocationType allocation) { - Tagged<Map> map = read_only_roots().shared_function_info_map(); - Tagged<SharedFunctionInfo> shared = - Cast<SharedFunctionInfo>(NewWithImmortalMap(map, allocation)); - - DisallowGarbageCollection no_gc; - shared->Init(read_only_roots(), isolate()->GetAndIncNextUniqueSfiId()); - return handle(shared, isolate()); + return indirect_handle(New<SharedFunctionInfo>( + allocation, isolate()->GetAndIncNextUniqueSfiId()), + isolate()); } template <typename Impl> @@ -1288,11 +1169,8 @@ Handle<DescriptorArray> FactoryBase<Impl>::NewDescriptorArray( template <typename Impl> Handle<ClassPositions> FactoryBase<Impl>::NewClassPositions(int start, int end) { - auto result = NewStructInternal<ClassPositions>(CLASS_POSITIONS_TYPE, - AllocationType::kOld); - result->set_start(start); - result->set_end(end); - return handle(result, isolate()); + return indirect_handle(New<ClassPositions, AllocationType::kOld>(start, end), + isolate()); } template <typename Impl> @@ -1412,6 +1290,14 @@ Tagged<HeapObject> FactoryBase<Impl>::AllocateRawWithImmortalMap( return result; } +template <typename Impl> +AllocationWitness FactoryBase<Impl>::AllocateWithWitness( + int size, AllocationType allocation, AllocationAlignment alignment, + AllocationHint hint) { + return AllocationWitness(AllocateRaw(size, allocation, alignment, hint), + read_only_roots(), allocation); +} + template <typename Impl> Tagged<HeapObject> FactoryBase<Impl>::AllocateRaw(int size, AllocationType allocation, @@ -1423,7 +1309,13 @@ Tagged<HeapObject> FactoryBase<Impl>::AllocateRaw(int size, template <typename Impl> Handle<SwissNameDictionary> FactoryBase<Impl>::NewSwissNameDictionaryWithCapacity( - int capacity, AllocationType allocation) { + uint32_t capacity, AllocationType allocation) { + if (capacity > SwissNameDictionary::MaxCapacity()) { + base::FatalNoSecurityImpact("Fatal JavaScript invalid size error %u", + capacity); + UNREACHABLE(); + } + DCHECK(SwissNameDictionary::IsValidCapacity(capacity)); if (capacity == 0) { @@ -1434,13 +1326,7 @@ FactoryBase<Impl>::NewSwissNameDictionaryWithCapacity( return empty_swiss_property_dictionary(); } - if (capacity < 0 || capacity > SwissNameDictionary::MaxCapacity()) { - base::FatalNoSecurityImpact("Fatal JavaScript invalid size error %d", - capacity); - UNREACHABLE(); - } - - int meta_table_length = SwissNameDictionary::MetaTableSizeFor(capacity); + uint32_t meta_table_length = SwissNameDictionary::MetaTableSizeFor(capacity); DirectHandle<ByteArray> meta_table = impl()->NewByteArray(meta_table_length, allocation); @@ -1455,7 +1341,7 @@ FactoryBase<Impl>::NewSwissNameDictionaryWithCapacity( template <typename Impl> Handle<SwissNameDictionary> FactoryBase<Impl>::NewSwissNameDictionary( - int at_least_space_for, AllocationType allocation) { + uint32_t at_least_space_for, AllocationType allocation) { return NewSwissNameDictionaryWithCapacity( SwissNameDictionary::CapacityFor(at_least_space_for), allocation); } @@ -1463,13 +1349,7 @@ Handle<SwissNameDictionary> FactoryBase<Impl>::NewSwissNameDictionary( template <typename Impl> DirectHandle<FunctionTemplateRareData> FactoryBase<Impl>::NewFunctionTemplateRareData() { - auto function_template_rare_data = - NewStructInternal<FunctionTemplateRareData>( - FUNCTION_TEMPLATE_RARE_DATA_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - function_template_rare_data->set_c_function_overloads( - *impl()->empty_fixed_array(), SKIP_WRITE_BARRIER); - return direct_handle(function_template_rare_data, isolate()); + return New<FunctionTemplateRareData, AllocationType::kOld>(); } template <typename Impl> diff --git a/deps/v8/src/heap/factory-base.h b/deps/v8/src/heap/factory-base.h index 64ca10b0aaaf..65db6fcafd08 100644 --- a/deps/v8/src/heap/factory-base.h +++ b/deps/v8/src/heap/factory-base.h @@ -5,6 +5,7 @@ #ifndef V8_HEAP_FACTORY_BASE_H_ #define V8_HEAP_FACTORY_BASE_H_ +#include <algorithm> #include <string_view> #include "src/base/export-template.h" @@ -19,8 +20,14 @@ #ifndef V8_METAGEN_GENERATION_PASS // Forward declarations only, and generated after the metagen harvest // parses this header. The harvest reads class definitions, so nothing -// it collects comes from here. -#include "torque-generated/class-forward-declarations.h" +// it collects comes from here. The checked-in copy under src/gen/ if +// v8_use_checked_in_generated_headers, the generated header otherwise. +// See src/gen/README.md. +#ifdef V8_USE_CHECKED_IN_GENERATED_HEADERS +#include "src/gen/intl-wasm/class-forward-declarations.h" // IWYU pragma: export +#else +#include "torque-generated/class-forward-declarations.h" // IWYU pragma: export, nogncheck +#endif #endif namespace v8 { @@ -98,6 +105,11 @@ struct NewCodeOptions { template <typename Impl> class FactoryBase { public: + template <typename T, typename... Args> + inline DirectHandle<T> New(AllocationType allocation, Args&&... args); + template <typename T, AllocationType kAllocation, typename... Args> + inline DirectHandle<T> New(Args&&... args); + Handle<Code> NewCode(const NewCodeOptions& options); DirectHandle<CodeWrapper> NewCodeWrapper(); @@ -129,17 +141,12 @@ class FactoryBase { inline Handle<HeapNumber> NewHeapNumber(double value); template <AllocationType allocation = AllocationType::kYoung> inline Handle<HeapNumber> NewHeapNumberFromBits(uint64_t bits); - template <AllocationType allocation = AllocationType::kYoung> - inline Handle<HeapNumber> NewHeapNumberWithHoleNaN(); template <AllocationType allocation = AllocationType::kYoung> inline Handle<HeapNumber> NewHeapInt32(int32_t value); - template <AllocationType allocation> - Handle<HeapNumber> NewHeapNumber(); - - Handle<Struct> NewStruct(InstanceType type, - AllocationType allocation = AllocationType::kYoung); + template <AllocationType allocation = AllocationType::kYoung> + inline Handle<UninitializedHeapNumber> NewUninitializedHeapNumber(); // Create a pre-tenured empty AccessorPair. Handle<AccessorPair> NewAccessorPair(); @@ -303,6 +310,14 @@ class FactoryBase { base::Vector<const uint8_t> string, bool convert_encoding = false); Handle<InternalizedString> InternalizeString( base::Vector<const uint16_t> string, bool convert_encoding = false); + Handle<InternalizedString> InternalizeString(std::string_view str, + bool convert_encoding = false) { + DCHECK(std::all_of(str.begin(), str.end(), [](char c) { + return static_cast<unsigned char>(c) <= 0x7f; + })); + return InternalizeString(base::OneByteVector(str.data(), str.size()), + convert_encoding); + } template <class StringTableKey> Handle<InternalizedString> InternalizeStringWithKey(StringTableKey* key); @@ -381,9 +396,9 @@ class FactoryBase { Tagged<Smi> number, NumberCacheMode mode = NumberCacheMode::kBoth); V8_WARN_UNUSED_RESULT MaybeHandle<SeqOneByteString> NewRawSharedOneByteString( - int length); + uint32_t length); V8_WARN_UNUSED_RESULT MaybeHandle<SeqTwoByteString> NewRawSharedTwoByteString( - int length); + uint32_t length); // Allocates a new BigInt with {length} digits. Only to be used by // MutableBigInt::New*. @@ -403,11 +418,11 @@ class FactoryBase { Handle<ClassPositions> NewClassPositions(int start, int end); Handle<SwissNameDictionary> NewSwissNameDictionary( - int at_least_space_for = kSwissNameDictionaryInitialCapacity, + uint32_t at_least_space_for = kSwissNameDictionaryInitialCapacity, AllocationType allocation = AllocationType::kYoung); Handle<SwissNameDictionary> NewSwissNameDictionaryWithCapacity( - int capacity, AllocationType allocation); + uint32_t capacity, AllocationType allocation); DirectHandle<FunctionTemplateRareData> NewFunctionTemplateRareData(); @@ -435,13 +450,10 @@ class FactoryBase { Tagged<HeapObject> AllocateRawWeakArrayList(uint32_t length, AllocationType allocation); - template <typename StructType> - inline Tagged<StructType> NewStructInternal(InstanceType type, - AllocationType allocation, - bool initialize_fields = true); - inline Tagged<Struct> NewStructInternal(ReadOnlyRoots roots, Tagged<Map> map, - int size, AllocationType allocation, - bool initialize_fields); + AllocationWitness AllocateWithWitness( + int size, AllocationType allocation, + AllocationAlignment alignment = kTaggedAligned, + AllocationHint hint = AllocationHint()); Tagged<HeapObject> AllocateRawWithImmortalMap( int size, AllocationType allocation, Tagged<Map> map, @@ -466,7 +478,7 @@ class FactoryBase { template <typename SeqStringT> MaybeHandle<SeqStringT> NewRawStringWithMap( - int length, Tagged<Map> map, AllocationType allocation, + uint32_t length, Tagged<Map> map, AllocationType allocation, AllocationHint hint = AllocationHint()); private: diff --git a/deps/v8/src/heap/factory-inl.h b/deps/v8/src/heap/factory-inl.h index 7b211ccc8eb5..8c3455441536 100644 --- a/deps/v8/src/heap/factory-inl.h +++ b/deps/v8/src/heap/factory-inl.h @@ -96,7 +96,8 @@ Handle<JSArray> Factory::NewJSArrayWithElements( Handle<JSObject> Factory::NewFastOrSlowJSObjectFromMap( DirectHandle<Map> map, int number_of_slow_properties, - AllocationType allocation, DirectHandle<AllocationSite> allocation_site, + AllocationType allocation, + MaybeDirectHandle<AllocationSite> allocation_site, NewJSObjectType new_js_object_type) { auto js_object = map->is_dictionary_map() diff --git a/deps/v8/src/heap/factory.cc b/deps/v8/src/heap/factory.cc index d2a5f284e01f..400a43dc58ae 100644 --- a/deps/v8/src/heap/factory.cc +++ b/deps/v8/src/heap/factory.cc @@ -5,6 +5,7 @@ #include "src/heap/factory.h" #include <algorithm> // For copy +#include <bit> #include <memory> // For shared_ptr<> #include <optional> #include <string> @@ -13,6 +14,7 @@ #include "src/ast/ast-source-ranges.h" #include "src/base/bits.h" #include "src/base/strong-alias.h" +#include "src/base/unique-array.h" #include "src/builtins/accessors.h" #include "src/builtins/builtins-promise.h" #include "src/builtins/constants-table-builder.h" @@ -20,6 +22,7 @@ #include "src/codegen/compiler.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" +#include "src/common/synchronization-point-support.h" #include "src/diagnostics/basic-block-profiler.h" #include "src/execution/isolate-inl.h" #include "src/execution/protectors-inl.h" @@ -41,13 +44,14 @@ #include "src/numbers/conversions.h" #include "src/numbers/hash-seed-inl.h" #include "src/objects/allocation-site-inl.h" -#include "src/objects/api-callbacks.h" +#include "src/objects/api-callbacks-inl.h" #include "src/objects/arguments-inl.h" #include "src/objects/bigint.h" #include "src/objects/call-site-info-inl.h" #include "src/objects/cell-inl.h" #include "src/objects/cpp-heap-object-wrapper-inl.h" #include "src/objects/debug-objects-inl.h" +#include "src/objects/descriptor-array-inl.h" #include "src/objects/embedder-data-array-inl.h" #include "src/objects/feedback-cell-inl.h" #include "src/objects/fixed-array-base-inl.h" @@ -61,7 +65,6 @@ #include "src/objects/instance-type-inl.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" #include "src/objects/js-collection-inl.h" #include "src/objects/js-disposable-stack-inl.h" #include "src/objects/js-generator-inl.h" @@ -81,7 +84,9 @@ #include "src/objects/pod-array-inl.h" #include "src/objects/promise-inl.h" #include "src/objects/property-descriptor-object-inl.h" +#include "src/objects/prototype-info-inl.h" #include "src/objects/scope-info.h" +#include "src/objects/script-inl.h" #include "src/objects/string-set-inl.h" #include "src/objects/struct-inl.h" #include "src/objects/synthetic-module-inl.h" @@ -308,7 +313,7 @@ Tagged<HeapObject> Factory::AllocateRaw(int size, AllocationType allocation, Tagged<HeapObject> Factory::AllocateRawWithAllocationSite( DirectHandle<Map> map, AllocationType allocation, - DirectHandle<AllocationSite> allocation_site) { + MaybeDirectHandle<AllocationSite> allocation_site) { DCHECK(!InstanceTypeChecker::IsMap(map->instance_type())); const auto [write_barrier_mode, should_allocate_memento] = allocation == AllocationType::kYoung @@ -329,7 +334,8 @@ Tagged<HeapObject> Factory::AllocateRawWithAllocationSite( const int aligned_size = ALIGN_TO_ALLOCATION_ALIGNMENT(instance_size); Tagged<AllocationMemento> alloc_memento = UncheckedCast<AllocationMemento>( Tagged<Object>(result.ptr() + aligned_size)); - InitializeAllocationMemento(alloc_memento, *allocation_site); + InitializeAllocationMemento(alloc_memento, + *allocation_site.ToHandleChecked()); } return result; } @@ -376,30 +382,15 @@ DirectHandle<HeapObject> Factory::NewFillerObject(int size, } DirectHandle<PrototypeInfo> Factory::NewPrototypeInfo() { - auto result = NewStructInternal<PrototypeInfo>(PROTOTYPE_INFO_TYPE, - AllocationType::kOld); - DisallowGarbageCollection no_gc; - result->set_prototype_users(Smi::zero()); - result->set_registry_slot(PrototypeInfo::UNREGISTERED); - result->set_bit_field(0); - result->set_module_namespace(*undefined_value(), SKIP_WRITE_BARRIER); - for (int i = 0; i < PrototypeInfo::kCachedHandlerCount; i++) { - result->set_cached_handler(i, Smi::zero(), SKIP_WRITE_BARRIER); - } - return direct_handle(result, isolate()); + return New<PrototypeInfo, AllocationType::kOld>(); } DirectHandle<PrototypeSharedClosureInfo> Factory::NewPrototypeSharedClosureInfo( DirectHandle<ObjectBoilerplateDescription> object_boilerplate_description, DirectHandle<Context> context, DirectHandle<ClosureFeedbackCellArray> feedback_array) { - auto result = NewStructInternal<PrototypeSharedClosureInfo>( - PROTOTYPE_SHARED_CLOSURE_INFO_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - result->set_boilerplate_description(*object_boilerplate_description); - result->set_context(*context); - result->set_closure_feedback_cell_array(*feedback_array); - return direct_handle(result, isolate()); + return New<PrototypeSharedClosureInfo, AllocationType::kOld>( + object_boilerplate_description, feedback_array, context); } DirectHandle<EnumCache> Factory::NewEnumCache(DirectHandle<FixedArray> keys, @@ -410,32 +401,28 @@ DirectHandle<EnumCache> Factory::NewEnumCache(DirectHandle<FixedArray> keys, DCHECK_EQ(allocation == AllocationType::kSharedOld, HeapLayout::InAnySharedSpace(*keys) && HeapLayout::InAnySharedSpace(*indices)); - auto result = NewStructInternal<EnumCache>(ENUM_CACHE_TYPE, allocation); - DisallowGarbageCollection no_gc; - result->set_keys(*keys); - result->set_indices(*indices); - return direct_handle(result, isolate()); + return New<EnumCache>(allocation, keys, indices); } DirectHandle<Tuple2> Factory::NewTuple2(DirectHandle<Object> value1, DirectHandle<Object> value2, AllocationType allocation) { - auto result = NewStructInternal<Tuple2>(TUPLE2_TYPE, allocation, false); - DisallowGarbageCollection no_gc; - result->set_value1(*value1); - result->set_value2(*value2); - return direct_handle(result, isolate()); + return New<Tuple2>(allocation, value1, value2); } DirectHandle<Tuple2> Factory::NewTuple2(DirectHandle<Object> value1, DirectHandle<Object> value2, RelaxedStoreTag tag, AllocationType allocation) { - auto result = NewStructInternal<Tuple2>(TUPLE2_TYPE, allocation, false); - DisallowGarbageCollection no_gc; - result->set_value1(*value1, tag); - result->set_value2(*value2, tag); - return direct_handle(result, isolate()); + return New<Tuple2>(allocation, value1, value2, tag); +} + +DirectHandle<ForInEnumeratorHolder> Factory::NewForInEnumeratorHolder( + DirectHandle<Map> enum_cache_map, DirectHandle<FixedArray> named_keys, + Tagged<Smi> elements_length, Tagged<Smi> cache_length, + AllocationType allocation) { + return New<ForInEnumeratorHolder>(allocation, enum_cache_map, named_keys, + elements_length, cache_length); } DirectHandle<Hole> Factory::NewHole() { @@ -491,22 +478,11 @@ Handle<FeedbackVector> Factory::NewFeedbackVector( DCHECK_LE(0, length); int size = FeedbackVector::SizeFor(length); - Tagged<FeedbackVector> vector = - Cast<FeedbackVector>(AllocateRawWithImmortalMap( - size, AllocationType::kOld, *feedback_vector_map())); - DisallowGarbageCollection no_gc; - vector->set_shared_function_info(*shared); - vector->set_length(length); - vector->set_invocation_count(0); - vector->set_invocation_count_before_stable(0); - vector->reset_osr_state(); - vector->reset_flags(); - vector->set_closure_feedback_cell_array(*closure_feedback_cell_array); - vector->set_parent_feedback_cell(*parent_feedback_cell); - - // TODO(leszeks): Initialize based on the feedback metadata. - MemsetTagged(ObjectSlot(vector->slots_start()), *undefined_value(), length); - return handle(vector, isolate()); + AllocationWitness witness = AllocateWithWitness(size, AllocationType::kOld); + return handle(new (witness) FeedbackVector(witness, length, *shared, + *closure_feedback_cell_array, + *parent_feedback_cell), + isolate()); } DirectHandle<EmbedderDataArray> Factory::NewEmbedderDataArray(int length) { @@ -704,8 +680,7 @@ Handle<T> Factory::AllocateSmallOrderedHashTable(DirectHandle<Map> map, // to something other than 2, capacity should be stored as another // field of this object. DCHECK_EQ(T::kLoadFactor, 2); - capacity = - base::bits::RoundUpToPowerOfTwo32(std::max({T::kMinCapacity, capacity})); + capacity = std::bit_ceil<uint32_t>(std::max({T::kMinCapacity, capacity})); capacity = std::min({capacity, T::kMaxCapacity}); DCHECK_LT(0, capacity); @@ -758,15 +733,7 @@ DirectHandle<NameDictionary> Factory::NewNameDictionary( } DirectHandle<PropertyDescriptorObject> Factory::NewPropertyDescriptorObject() { - auto object = NewStructInternal<PropertyDescriptorObject>( - PROPERTY_DESCRIPTOR_OBJECT_TYPE, AllocationType::kYoung); - DisallowGarbageCollection no_gc; - object->set_flags(0); - Tagged<TheHole> the_hole = read_only_roots().the_hole_value(); - object->set_value(the_hole, SKIP_WRITE_BARRIER); - object->set_get(the_hole, SKIP_WRITE_BARRIER); - object->set_set(the_hole, SKIP_WRITE_BARRIER); - return direct_handle(object, isolate()); + return New<PropertyDescriptorObject, AllocationType::kYoung>(); } DirectHandle<SwissNameDictionary> @@ -792,9 +759,9 @@ Factory::CreateCanonicalEmptySwissNameDictionary() { } // Internalized strings are created in the old generation (data space). -Handle<String> Factory::InternalizeUtf8String(base::Vector<const char> string) { +Handle<String> Factory::InternalizeUtf8String(std::string_view str) { base::Vector<const uint8_t> utf8_data = - base::Vector<const uint8_t>::cast(string); + base::OneByteVector(str.data(), str.size()); Utf8Decoder decoder(utf8_data); if (decoder.is_ascii()) return InternalizeString(utf8_data); if (decoder.is_one_byte()) { @@ -891,11 +858,16 @@ MaybeHandle<String> NewStringFromBytes(Isolate* isolate, PeekBytes peek_bytes, if (decoder.utf16_length() == 0) return isolate->factory()->empty_string(); + SYNCHRONIZATION_POINT("NewStringFromBytes"); if (decoder.is_one_byte()) { if (decoder.utf16_length() == 1) { - uint8_t codepoint; - decoder.Decode(&codepoint, peek_bytes()); - return isolate->factory()->LookupSingleCharacterStringFromCode(codepoint); + // A worker with in-sandbox corruption could be modifying the input + // data concurrently, causing {Decode()} below to write two bytes now. + // Appease sanitizers by allocating enough stack space. + uint8_t codepoint[4]; + decoder.Decode(codepoint, peek_bytes()); + return isolate->factory()->LookupSingleCharacterStringFromCode( + codepoint[0]); } // Allocate string. Handle<SeqOneByteString> result; @@ -969,18 +941,18 @@ MaybeHandle<String> NewStringFromUtf8Variant(Isolate* isolate, UNREACHABLE(); } -inline base::OwnedVector<uint8_t> CopyBytes(const base::Atomic8* src, +inline base::UniqueArray<uint8_t> CopyBytes(const base::Atomic8* src, size_t length) { - auto copy = base::OwnedVector<uint8_t>::NewForOverwrite(length); + auto copy = base::UniqueArray<uint8_t>::NewForOverwrite(length); base::Relaxed_Memcpy(reinterpret_cast<base::Atomic8*>(copy.data()), src, length); return copy; } #if V8_ENABLE_WEBASSEMBLY -inline base::OwnedVector<uint16_t> CopyCodeUnits(const base::Atomic16* src, +inline base::UniqueArray<uint16_t> CopyCodeUnits(const base::Atomic16* src, size_t length) { - auto copy = base::OwnedVector<uint16_t>::NewForOverwrite(length); + auto copy = base::UniqueArray<uint16_t>::NewForOverwrite(length); for (size_t i = 0; i < length; i++) { auto dest = reinterpret_cast<base::Atomic16*>(copy.data() + i); base::Relaxed_Store(dest, base::Relaxed_Load(src + i)); @@ -999,13 +971,14 @@ MaybeHandle<String> Factory::NewStringFromUtf8( // strings from them anyway. THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); } - base::OwnedVector<uint8_t> private_copy; + base::UniqueArray<uint8_t> private_copy; if (config.source_shared()) { private_copy = CopyBytes( reinterpret_cast<const base::Atomic8*>(string.data()), string.size()); } auto peek_bytes = [&]() -> base::Vector<const uint8_t> { - return config.source_shared() ? private_copy.as_vector() : string; + if (config.source_shared()) return private_copy.as_span(); + return string; }; if (config.dest_shared()) { return NewStringFromUtf8Variant(isolate(), peek_bytes, config.variant(), @@ -1016,11 +989,10 @@ MaybeHandle<String> Factory::NewStringFromUtf8( StringBuilder{}, allocation); } -MaybeHandle<String> Factory::NewStringFromUtf8(base::Vector<const char> string, +MaybeHandle<String> Factory::NewStringFromUtf8(std::string_view str, AllocationType allocation) { - return NewStringFromUtf8(base::Vector<const uint8_t>::cast(string), - UnicodeConfig(unibrow::Utf8Variant::kLossyUtf8), - allocation); + return NewStringFromUtf8(base::OneByteVector(str.data(), str.size()), + unibrow::Utf8Variant::kLossyUtf8, allocation); } #if V8_ENABLE_WEBASSEMBLY @@ -1034,7 +1006,7 @@ MaybeDirectHandle<String> Factory::NewStringFromUtf8( static_assert(WasmArray::MaxLength(sizeof(uint8_t)) <= kMaxInt); uint32_t length = end - start; - base::OwnedVector<uint8_t> private_copy; + base::UniqueArray<uint8_t> private_copy; if (config.source_shared()) { private_copy = CopyBytes( reinterpret_cast<const base::Atomic8*>(array->ElementAddress(start)), @@ -1042,7 +1014,7 @@ MaybeDirectHandle<String> Factory::NewStringFromUtf8( } auto peek_bytes = [&]() -> base::Vector<const uint8_t> { if (config.source_shared()) { - return private_copy.as_vector(); + return private_copy.as_span(); } const uint8_t* contents = reinterpret_cast<const uint8_t*>(array->ElementAddress(0)); @@ -1074,14 +1046,16 @@ MaybeHandle<String> Factory::NewStringFromUtf8( namespace { struct Wtf16Decoder { - int length_; + uint32_t length_; bool is_one_byte_; explicit Wtf16Decoder(base::Vector<const uint16_t> data) - : length_(data.length()), - is_one_byte_(String::IsOneByte(data.begin(), length_)) {} + : length_(static_cast<uint32_t>(data.size())), + is_one_byte_(String::IsOneByte(data.begin(), length_)) { + DCHECK_LE(data.size(), String::kMaxLength); + } bool is_invalid() const { return false; } bool is_one_byte() const { return is_one_byte_; } - int utf16_length() const { return length_; } + uint32_t utf16_length() const { return length_; } template <typename Char> void Decode(Char* out, base::Vector<const uint16_t> data) { CopyChars(out, data.begin(), length_); @@ -1100,7 +1074,10 @@ MaybeDirectHandle<String> Factory::NewStringFromUtf16( static_assert(WasmArray::MaxLength(sizeof(uint16_t)) <= kMaxInt); uint32_t length = end - start; - base::OwnedVector<uint16_t> private_copy; + if (length > String::kMaxLength) { + THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); + } + base::UniqueArray<uint16_t> private_copy; if (config.source_shared()) { private_copy = CopyCodeUnits( reinterpret_cast<const base::Atomic16*>(array->ElementAddress(start)), @@ -1108,7 +1085,7 @@ MaybeDirectHandle<String> Factory::NewStringFromUtf16( } auto peek_bytes = [&]() -> base::Vector<const uint16_t> { if (config.source_shared()) { - return private_copy.as_vector(); + return private_copy.as_span(); } const uint16_t* contents = reinterpret_cast<const uint16_t*>(array->ElementAddress(0)); @@ -1176,7 +1153,7 @@ MaybeDirectHandle<String> Factory::WasmStringAddShared( #endif // V8_ENABLE_WEBASSEMBLY MaybeHandle<String> Factory::NewStringFromTwoByte(const base::uc16* string, - int length, + uint32_t length, AllocationType allocation) { DCHECK_NE(allocation, AllocationType::kReadOnly); if (length == 0) return empty_string(); @@ -1200,27 +1177,37 @@ MaybeHandle<String> Factory::NewStringFromTwoByte(const base::uc16* string, MaybeHandle<String> Factory::NewStringFromTwoByte( base::Vector<const base::uc16> string, AllocationType allocation) { - return NewStringFromTwoByte(string.begin(), string.length(), allocation); + if (string.size() > String::kMaxLength) { + THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); + } + return NewStringFromTwoByte(string.begin(), + static_cast<uint32_t>(string.size()), allocation); } MaybeDirectHandle<String> Factory::NewStringFromTwoByte( const ZoneVector<base::uc16>* string, AllocationType allocation) { - return NewStringFromTwoByte(string->data(), static_cast<int>(string->size()), - allocation); + if (string->size() > String::kMaxLength) { + THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); + } + return NewStringFromTwoByte( + string->data(), static_cast<uint32_t>(string->size()), allocation); } #if V8_ENABLE_WEBASSEMBLY MaybeDirectHandle<String> Factory::NewStringFromTwoByteLittleEndian( base::Vector<const base::uc16> str, UnicodeConfig config) { #if defined(V8_TARGET_LITTLE_ENDIAN) - uint32_t length = static_cast<uint32_t>(str.length()); - base::OwnedVector<uint16_t> private_copy; + if (str.size() > String::kMaxLength) { + THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); + } + base::UniqueArray<uint16_t> private_copy; if (config.source_shared()) { private_copy = CopyCodeUnits( - reinterpret_cast<const base::Atomic16*>(str.data()), length); + reinterpret_cast<const base::Atomic16*>(str.data()), str.size()); } auto peek_bytes = [&]() -> base::Vector<const uint16_t> { - return config.source_shared() ? private_copy.as_vector() : str; + if (config.source_shared()) return private_copy.as_span(); + return str; }; if (config.dest_shared()) { return NewStringFromBytes<Wtf16Decoder, decltype(peek_bytes), @@ -1232,9 +1219,35 @@ MaybeDirectHandle<String> Factory::NewStringFromTwoByteLittleEndian( NonSharedStringPolicy>( isolate(), peek_bytes, AllocationType::kYoung, MessageTemplate::kNone); #elif defined(V8_TARGET_BIG_ENDIAN) - // TODO(12868): Duplicate the guts of NewStringFromTwoByte, so that - // copying and transcoding the data can be done in a single pass. - UNIMPLEMENTED(); + if (str.size() > String::kMaxLength) { + THROW_NEW_ERROR(isolate(), NewInvalidStringLengthError()); + } + base::UniqueArray<uint16_t> private_copy = + base::UniqueArray<uint16_t>::NewForOverwrite(str.size()); + if (config.source_shared()) { + const base::Atomic16* src = + reinterpret_cast<const base::Atomic16*>(str.data()); + for (size_t i = 0; i < str.size(); i++) { + private_copy[i] = base::bits::ByteReverse16( + static_cast<uint16_t>(base::Relaxed_Load(src + i))); + } + } else { + for (size_t i = 0; i < str.size(); i++) { + private_copy[i] = base::bits::ByteReverse16(str[i]); + } + } + auto peek_bytes = [&]() -> base::Vector<const uint16_t> { + return private_copy.as_span(); + }; + if (config.dest_shared()) { + return NewStringFromBytes<Wtf16Decoder, decltype(peek_bytes), + SharedStringPolicy>(isolate(), peek_bytes, + AllocationType::kSharedOld, + MessageTemplate::kNone); + } + return NewStringFromBytes<Wtf16Decoder, decltype(peek_bytes), + NonSharedStringPolicy>( + isolate(), peek_bytes, AllocationType::kYoung, MessageTemplate::kNone); #else #error Unknown endianness #endif @@ -1883,10 +1896,8 @@ DirectHandle<ContextCell> Factory::NewContextCell( DirectHandle<AliasedArgumentsEntry> Factory::NewAliasedArgumentsEntry( int aliased_context_slot) { - auto entry = NewStructInternal<AliasedArgumentsEntry>( - ALIASED_ARGUMENTS_ENTRY_TYPE, AllocationType::kYoung); - entry->set_aliased_context_slot(aliased_context_slot); - return direct_handle(entry, isolate()); + return New<AliasedArgumentsEntry, AllocationType::kYoung>( + aliased_context_slot); } DirectHandle<AccessorInfo> Factory::NewAccessorInfo() { @@ -1895,7 +1906,8 @@ DirectHandle<AccessorInfo> Factory::NewAccessorInfo() { DisallowGarbageCollection no_gc; info->set_data(*undefined_value(), SKIP_WRITE_BARRIER); info->set_name(*empty_string(), SKIP_WRITE_BARRIER); - info->set_flags(0); // Must clear the flags, it was initialized as undefined. + // Must clear the flags, it was initialized as undefined. + info->set_flags(AccessorInfo::Flags()); info->set_is_sloppy(true); info->set_initial_property_attributes(NONE); @@ -1907,6 +1919,10 @@ DirectHandle<AccessorInfo> Factory::NewAccessorInfo() { return direct_handle(info, isolate()); } +DirectHandle<AccessCheckInfo> Factory::NewAccessCheckInfo() { + return New<AccessCheckInfo, AllocationType::kOld>(); +} + DirectHandle<InterceptorInfo> Factory::NewInterceptorInfo( InterceptorKind kind, AllocationType allocation) { Tagged<InterceptorInfo> info = @@ -1914,7 +1930,7 @@ DirectHandle<InterceptorInfo> Factory::NewInterceptorInfo( DisallowGarbageCollection no_gc; info->set_data(*undefined_value()); info->set_flags( - InterceptorInfo::NamedBit::encode(kind == InterceptorKind::kNamed)); + InterceptorInfo::Flags().with_named(kind == InterceptorKind::kNamed)); info->clear_padding(); // Initialization of these lazy-initialized callback fields is the same @@ -1934,13 +1950,8 @@ DirectHandle<ErrorStackData> Factory::NewErrorStackData( DirectHandle<UnionOf<JSAny, FixedArray>> raw_data_for_call_site_infos_or_formatted_stack, DirectHandle<StackTraceInfo> stack_trace) { - Tagged<ErrorStackData> error_stack_data = NewStructInternal<ErrorStackData>( - ERROR_STACK_DATA_TYPE, AllocationType::kYoung); - DisallowGarbageCollection no_gc; - error_stack_data->set_raw_data_for_call_site_infos_or_formatted_stack( - *raw_data_for_call_site_infos_or_formatted_stack, SKIP_WRITE_BARRIER); - error_stack_data->set_stack_trace(*stack_trace, SKIP_WRITE_BARRIER); - return direct_handle(error_stack_data, isolate()); + return New<ErrorStackData, AllocationType::kYoung>( + raw_data_for_call_site_infos_or_formatted_stack, stack_trace); } void Factory::ProcessNewScript(DirectHandle<Script> script, @@ -1965,34 +1976,14 @@ Handle<Script> Factory::CloneScript(DirectHandle<Script> script, #ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME DirectHandle<ArrayList> list = ArrayList::New(isolate(), 0); #endif - Handle<Script> new_script_handle = - Cast<Script>(NewStruct(SCRIPT_TYPE, AllocationType::kOld)); - { - DisallowGarbageCollection no_gc; - Tagged<Script> new_script = *new_script_handle; - const Tagged<Script> old_script = *script; - new_script->set_source(*source); - new_script->set_name(old_script->name()); - new_script->set_id(script_id); - new_script->set_line_offset(old_script->line_offset()); - new_script->set_column_offset(old_script->column_offset()); - new_script->set_context_data(old_script->context_data()); - new_script->set_type(old_script->type()); - new_script->set_line_ends(Smi::zero()); - new_script->set_eval_from_shared_or_wrapped_arguments( - script->eval_from_shared_or_wrapped_arguments()); - new_script->set_infos(*empty_weak_fixed_array(), SKIP_WRITE_BARRIER); - new_script->set_eval_from_position(old_script->eval_from_position()); - new_script->set_eval_from_scope_info(old_script->eval_from_scope_info()); - new_script->set_flags(old_script->flags()); - new_script->set_host_defined_options(old_script->host_defined_options()); - new_script->set_source_hash(*undefined_value(), SKIP_WRITE_BARRIER); - new_script->set_compiled_lazy_function_positions(*undefined_value(), - SKIP_WRITE_BARRIER); + Handle<Script> new_script_handle = indirect_handle( + New<Script, AllocationType::kOld>(script, source, script_id #ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME - new_script->set_script_or_modules(*list); + , + list #endif - } + ), + isolate()); ProcessNewScript(new_script_handle, ScriptEventType::kCreate); return new_script_handle; } @@ -2000,32 +1991,24 @@ Handle<Script> Factory::CloneScript(DirectHandle<Script> script, DirectHandle<CallableTask> Factory::NewCallableTask( DirectHandle<JSReceiver> callable, DirectHandle<NativeContext> context) { DCHECK(IsCallable(*callable)); - auto microtask = NewStructInternal<CallableTask>(CALLABLE_TASK_TYPE, - AllocationType::kYoung); - DisallowGarbageCollection no_gc; - microtask->set_callable(*callable, SKIP_WRITE_BARRIER); - microtask->set_context(*context, SKIP_WRITE_BARRIER); + return New<CallableTask, AllocationType::kYoung>( + callable, context #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - microtask->set_continuation_preserved_embedder_data( - isolate()->isolate_data()->continuation_preserved_embedder_data(), - SKIP_WRITE_BARRIER); + , + isolate()->isolate_data()->continuation_preserved_embedder_data_handle() #endif // V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - return direct_handle(microtask, isolate()); + ); } DirectHandle<CallbackTask> Factory::NewCallbackTask( DirectHandle<Foreign> callback, DirectHandle<Object> data) { - auto microtask = NewStructInternal<CallbackTask>(CALLBACK_TASK_TYPE, - AllocationType::kYoung); - DisallowGarbageCollection no_gc; - microtask->set_callback(*callback, SKIP_WRITE_BARRIER); - microtask->set_data(*data, SKIP_WRITE_BARRIER); + return New<CallbackTask, AllocationType::kYoung>( + callback, data #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - microtask->set_continuation_preserved_embedder_data( - isolate()->isolate_data()->continuation_preserved_embedder_data(), - SKIP_WRITE_BARRIER); + , + isolate()->isolate_data()->continuation_preserved_embedder_data_handle() #endif // V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - return direct_handle(microtask, isolate()); + ); } DirectHandle<PromiseResolveThenableJobTask> @@ -2034,19 +2017,13 @@ Factory::NewPromiseResolveThenableJobTask( DirectHandle<JSReceiver> thenable, DirectHandle<JSReceiver> then, DirectHandle<Context> context) { DCHECK(IsCallable(*then)); - auto microtask = NewStructInternal<PromiseResolveThenableJobTask>( - PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, AllocationType::kYoung); - DisallowGarbageCollection no_gc; - microtask->set_promise_to_resolve(*promise_to_resolve, SKIP_WRITE_BARRIER); - microtask->set_thenable(*thenable, SKIP_WRITE_BARRIER); - microtask->set_then(*then, SKIP_WRITE_BARRIER); - microtask->set_context(*context, SKIP_WRITE_BARRIER); + return New<PromiseResolveThenableJobTask, AllocationType::kYoung>( + promise_to_resolve, thenable, then, context #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - microtask->set_continuation_preserved_embedder_data( - isolate()->isolate_data()->continuation_preserved_embedder_data(), - SKIP_WRITE_BARRIER); + , + isolate()->isolate_data()->continuation_preserved_embedder_data_handle() #endif // V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - return direct_handle(microtask, isolate()); + ); } #if V8_ENABLE_WEBASSEMBLY @@ -2156,6 +2133,7 @@ DirectHandle<WasmTypeInfo> Factory::NewWasmTypeInfo( WasmTypeInfo::SizeFor(actual_supertypes), shared ? AllocationType::kSharedOld : AllocationType::kOld, map)); DisallowGarbageCollection no_gc; + SharedObjectConditionalSafePublishGuard publish_guard(result, shared); result->set_supertypes_length(actual_supertypes); int i = 0; if (!opt_parent.is_null()) { @@ -2219,9 +2197,7 @@ DirectHandle<WasmInternalFunction> Factory::NewWasmInternalFunction( DisallowGarbageCollection no_gc; internal->set_call_target(call_target); - DCHECK(IsWasmTrustedInstanceData(*implicit_arg) || - IsWasmImportData(*implicit_arg)); - internal->set_implicit_arg(*implicit_arg); + internal->set_implicit_arg(TrustedCast<WasmImplicitArg>(*implicit_arg)); internal->set_function_index(function_index); internal->set_external(*undefined_value()); internal->set_sig(sig); @@ -2262,7 +2238,7 @@ DirectHandle<WasmSuspenderObject> Factory::NewWasmSuspenderObject() { TrustedCast<WasmSuspenderObject>(AllocateRawWithImmortalMap( map->instance_size(), AllocationType::kTrusted, map)); DisallowGarbageCollection no_gc; - suspender->init_stack(IsolateForSandbox(isolate()), nullptr); + suspender->set_stack(nullptr); suspender->clear_parent(); suspender->set_promise(*undefined_value()); suspender->set_resume(*undefined_value()); @@ -2379,13 +2355,13 @@ DirectHandle<WasmCapiFunctionData> Factory::NewWasmCapiFunctionData( Tagged<WasmArray> Factory::NewWasmArrayUninitialized( uint32_t length, DirectHandle<Map> map, AllocationType allocation) { - DCHECK_LE(length, static_cast<uint32_t>(WasmArray::MaxLength( - WasmArray::DecodeElementSizeFromMap(*map)))); + int element_size = WasmArray::DecodeElementSizeFromMap(*map); + DCHECK_LE(length, static_cast<uint32_t>(WasmArray::MaxLength(element_size))); const bool is_shared = allocation == AllocationType::kSharedOld; - DCHECK_EQ(is_shared, HeapLayout::InAnySharedSpace(*map)); - Tagged<HeapObject> raw = - AllocateRaw(WasmArray::SizeFor(*map, length), allocation, - is_shared ? kDoubleUnaligned : kTaggedAligned); + DCHECK_EQ(is_shared, HeapLayout::InWritableSharedSpace(*map)); + Tagged<HeapObject> raw = AllocateRaw( + WasmArray::SizeFor(element_size, length, SharedFlag{is_shared}), + allocation, is_shared ? kDoubleAligned : kTaggedAligned); DisallowGarbageCollection no_gc; raw->set_map_after_allocation(isolate(), *map); Tagged<WasmArray> result = Cast<WasmArray>(raw); @@ -2603,56 +2579,28 @@ Factory::NewSharedFunctionInfoForWasmCapiFunction( #endif // V8_ENABLE_WEBASSEMBLY Handle<Cell> Factory::NewCell(Tagged<Smi> value) { - static_assert(sizeof(Cell) <= kMaxRegularHeapObjectSize); - Tagged<Cell> result = Cast<Cell>(AllocateRawWithImmortalMap( - sizeof(Cell), AllocationType::kOld, *cell_map())); - DisallowGarbageCollection no_gc; - result->set_value(value, WriteBarrierMode::SKIP_WRITE_BARRIER); - return handle(result, isolate()); + return indirect_handle(New<Cell, AllocationType::kOld>(value), isolate()); } Handle<Cell> Factory::NewCell() { - static_assert(sizeof(Cell) <= kMaxRegularHeapObjectSize); - Tagged<Cell> result = Cast<Cell>(AllocateRawWithImmortalMap( - sizeof(Cell), AllocationType::kOld, *cell_map())); - result->set_value(read_only_roots().undefined_value(), - WriteBarrierMode::SKIP_WRITE_BARRIER); - return handle(result, isolate()); + return indirect_handle(New<Cell, AllocationType::kOld>(), isolate()); } DirectHandle<FeedbackCell> Factory::NewNoClosuresCell() { - Tagged<FeedbackCell> result = Cast<FeedbackCell>(AllocateRawWithImmortalMap( - sizeof(FeedbackCell), AllocationType::kOld, *no_closures_cell_map())); - DisallowGarbageCollection no_gc; - result->set_value(read_only_roots().undefined_value()); - result->clear_interrupt_budget(); - result->clear_dispatch_handle(); - result->clear_padding(); - return direct_handle(result, isolate()); + return New<FeedbackCell, AllocationType::kOld>( + read_only_roots().no_closures_cell_map()); } DirectHandle<FeedbackCell> Factory::NewOneClosureCell( DirectHandle<ClosureFeedbackCellArray> value) { - Tagged<FeedbackCell> result = Cast<FeedbackCell>(AllocateRawWithImmortalMap( - sizeof(FeedbackCell), AllocationType::kOld, *one_closure_cell_map())); - DisallowGarbageCollection no_gc; - result->set_value(*value); - result->clear_interrupt_budget(); - result->clear_dispatch_handle(); - result->clear_padding(); - return direct_handle(result, isolate()); + return New<FeedbackCell, AllocationType::kOld>( + read_only_roots().one_closure_cell_map(), value); } DirectHandle<FeedbackCell> Factory::NewManyClosuresCell( AllocationType allocation) { - Tagged<FeedbackCell> result = Cast<FeedbackCell>(AllocateRawWithImmortalMap( - sizeof(FeedbackCell), allocation, *many_closures_cell_map())); - DisallowGarbageCollection no_gc; - result->set_value(read_only_roots().undefined_value()); - result->clear_interrupt_budget(); - result->clear_dispatch_handle(); - result->clear_padding(); - return direct_handle(result, isolate()); + return New<FeedbackCell>(allocation, + read_only_roots().many_closures_cell_map()); } Handle<PropertyCell> Factory::NewPropertyCell(DirectHandle<Name> name, @@ -2823,7 +2771,7 @@ Handle<Map> Factory::NewMap(DirectHandle<HeapObject> meta_map_holder, auto meta_map_provider = [meta_map_holder] { // Tie new map to the same native context as given |meta_map_holder| object. Tagged<Map> meta_map = meta_map_holder->map(); - DCHECK(IsMapMap(meta_map)); + DCHECK(IsMetaMap(meta_map)); return meta_map; }; Handle<Map> map = @@ -2887,7 +2835,7 @@ DirectHandle<Map> Factory::NewContextfulMap( // Tie new map to the creation context of given |creation_context_holder| // object. Tagged<Map> meta_map = creation_context_holder->map()->map(); - DCHECK(IsMapMap(meta_map)); + DCHECK(IsMetaMap(meta_map)); return meta_map; }; DirectHandle<Map> map = @@ -3020,9 +2968,8 @@ Handle<JSObject> Factory::CopyJSObjectWithAllocationSite( DCHECK_NEWLY_ALLOCATED_OBJECT_IS_YOUNG(isolate(), raw_clone); - Heap::CopyBlock( - raw_clone.address(), source->address(), - SafeHeapObjectSize(static_cast<uint32_t>(object_size)).value()); + Heap::CopyBlock(raw_clone.address(), source->address(), + SafeHeapObjectSize(static_cast<uint32_t>(object_size))); Handle<JSObject> clone(Cast<JSObject>(raw_clone), isolate()); if constexpr (v8_flags.enable_unconditional_write_barriers.value()) { @@ -3133,7 +3080,12 @@ Handle<T> Factory::CopyArrayAndGrow(DirectHandle<T> src, uint32_t grow_by, DisallowGarbageCollection no_gc; new_object->set_map_after_allocation(isolate(), src->map(), SKIP_WRITE_BARRIER); - Tagged<T> result = TrustedCast<T>(new_object); + Tagged<T> result; + if constexpr (is_subtype_v<T, TrustedObject>) { + result = TrustedCast<T>(new_object); + } else { + result = Cast<T>(new_object); + } initialize_length(result, new_len); // Copy the content. WriteBarrierModeScope mode = result->GetWriteBarrierMode(no_gc); @@ -3282,8 +3234,9 @@ Handle<FixedDoubleArray> Factory::CopyFixedDoubleArray( Cast<FixedDoubleArray>(NewFixedDoubleArray(len)); Heap::CopyBlock(result->address() + offsetof(FixedDoubleArray, length_), array->address() + offsetof(FixedDoubleArray, length_), - static_cast<uint32_t>(FixedDoubleArray::SizeFor(len) - - offsetof(FixedDoubleArray, length_))); + SafeHeapObjectSize(static_cast<uint32_t>( + FixedDoubleArray::SizeFor(len) - + offsetof(FixedDoubleArray, length_)))); return result; } @@ -3329,7 +3282,7 @@ DirectHandle<JSObject> Factory::ShadowRealmNewTypeErrorCopy( DirectHandle<Object> Factory::NewInvalidStringLengthError() { if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("Aborting on invalid string length"); + base::FatalNoSecurityImpact("Aborting on invalid string length"); } // Invalidate the "string length" protector. if (Protectors::IsStringLengthOverflowLookupChainIntact(isolate())) { @@ -3677,7 +3630,7 @@ void Factory::InitializeJSObjectBody(Tagged<JSObject> obj, Tagged<Map> map, Handle<JSObject> Factory::NewJSObjectFromMap( DirectHandle<Map> map, AllocationType allocation, - DirectHandle<AllocationSite> allocation_site, + MaybeDirectHandle<AllocationSite> allocation_site, NewJSObjectType new_js_object_type) { // JSFunctions should be allocated using AllocateFunction to be // properly initialized. @@ -3706,7 +3659,7 @@ Handle<JSObject> Factory::NewJSObjectFromMap( Handle<JSObject> Factory::NewSlowJSObjectFromMap( DirectHandle<Map> map, int capacity, AllocationType allocation, - DirectHandle<AllocationSite> allocation_site, + MaybeDirectHandle<AllocationSite> allocation_site, NewJSObjectType new_js_object_type) { DCHECK(map->is_dictionary_map()); DirectHandle<HeapObject> object_properties; @@ -4005,15 +3958,15 @@ DirectHandle<SourceTextModule> Factory::NewSourceTextModule( New(source_text_module_map(), AllocationType::kOld)); DisallowGarbageCollection no_gc; module->set_code(*sfi); + module->set_status(Module::kUnlinked); + module->set_module_namespace(roots.undefined_value(), SKIP_WRITE_BARRIER); + module->set_deferred_module_namespace(roots.undefined_value(), + SKIP_WRITE_BARRIER); module->set_exports(*exports); module->set_regular_exports(*regular_exports); module->set_regular_imports(*regular_imports); module->set_hash(isolate()->GenerateIdentityHash(Smi::kMaxValue)); - module->set_module_namespace(roots.undefined_value(), SKIP_WRITE_BARRIER); - module->set_deferred_module_namespace(roots.undefined_value(), - SKIP_WRITE_BARRIER); module->set_requested_modules(*requested_modules); - module->set_status(Module::kUnlinked); module->set_exception(roots.the_hole_value(), SKIP_WRITE_BARRIER); module->set_top_level_capability(roots.undefined_value(), SKIP_WRITE_BARRIER); module->set_import_meta(roots.the_hole_value(), kReleaseStore, @@ -4456,7 +4409,11 @@ Handle<JSMessageObject> Factory::NewJSMessageObject( message_obj->initialize_elements(); message_obj->set_elements(*empty_fixed_array(), SKIP_WRITE_BARRIER); message_obj->set_type(message); - message_obj->set_argument(*argument, SKIP_WRITE_BARRIER); + if (argument.is_null()) { + message_obj->set_argument(*the_hole_value(), SKIP_WRITE_BARRIER); + } else { + message_obj->set_argument(*argument, SKIP_WRITE_BARRIER); + } message_obj->set_start_position(start_position); message_obj->set_end_position(end_position); message_obj->set_script(*script, SKIP_WRITE_BARRIER); @@ -4580,23 +4537,13 @@ Handle<DebugInfo> Factory::NewDebugInfo( } DirectHandle<BreakPointInfo> Factory::NewBreakPointInfo(int source_position) { - auto new_break_point_info = NewStructInternal<BreakPointInfo>( - BREAK_POINT_INFO_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - new_break_point_info->set_source_position(source_position); - new_break_point_info->set_break_points(*undefined_value(), - SKIP_WRITE_BARRIER); - return direct_handle(new_break_point_info, isolate()); + return New<BreakPointInfo, AllocationType::kOld>(source_position); } Handle<BreakPoint> Factory::NewBreakPoint(int id, DirectHandle<String> condition) { - auto new_break_point = - NewStructInternal<BreakPoint>(BREAK_POINT_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - new_break_point->set_id(id); - new_break_point->set_condition(*condition); - return handle(new_break_point, isolate()); + return indirect_handle(New<BreakPoint, AllocationType::kOld>(id, condition), + isolate()); } Handle<CallSiteInfo> Factory::NewCallSiteInfo( @@ -4604,15 +4551,10 @@ Handle<CallSiteInfo> Factory::NewCallSiteInfo( DirectHandle<UnionOf<Smi, JSFunction>> function, DirectHandle<Union<Code, BytecodeArray, Undefined>> code_object, int code_offset_or_source_position, int flags) { - auto info = NewStructInternal<CallSiteInfo>(CALL_SITE_INFO_TYPE, - AllocationType::kYoung); - DisallowGarbageCollection no_gc; - info->set_receiver_or_instance(*receiver_or_instance, SKIP_WRITE_BARRIER); - info->set_function(*function, SKIP_WRITE_BARRIER); - info->set_code_object(*code_object, SKIP_WRITE_BARRIER); - info->set_code_offset_or_source_position(code_offset_or_source_position); - info->set_flags(flags); - return handle(info, isolate()); + return indirect_handle(New<CallSiteInfo, AllocationType::kYoung>( + receiver_or_instance, function, code_object, + code_offset_or_source_position, flags), + isolate()); } DirectHandle<StackFrameInfo> Factory::NewStackFrameInfo( @@ -4620,37 +4562,24 @@ DirectHandle<StackFrameInfo> Factory::NewStackFrameInfo( int bytecode_offset_or_source_position, DirectHandle<String> function_name, bool is_constructor) { DCHECK_GE(bytecode_offset_or_source_position, 0); - Tagged<StackFrameInfo> info = NewStructInternal<StackFrameInfo>( - STACK_FRAME_INFO_TYPE, AllocationType::kYoung); - DisallowGarbageCollection no_gc; - info->set_flags(0); - info->set_shared_or_script(*shared_or_script, SKIP_WRITE_BARRIER); - info->set_bytecode_offset_or_source_position( - bytecode_offset_or_source_position); - info->set_function_name(*function_name, SKIP_WRITE_BARRIER); - info->set_is_constructor(is_constructor); - return direct_handle(info, isolate()); + return New<StackFrameInfo, AllocationType::kYoung>( + shared_or_script, bytecode_offset_or_source_position, function_name, + is_constructor); } Handle<StackTraceInfo> Factory::NewStackTraceInfo( DirectHandle<FixedArray> frames) { - Tagged<StackTraceInfo> info = NewStructInternal<StackTraceInfo>( - STACK_TRACE_INFO_TYPE, AllocationType::kYoung); - DisallowGarbageCollection no_gc; - info->set_id(isolate()->heap()->NextStackTraceId()); - info->set_frames(*frames, SKIP_WRITE_BARRIER); - return handle(info, isolate()); + return indirect_handle(New<StackTraceInfo, AllocationType::kYoung>( + isolate()->heap()->NextStackTraceId(), frames), + isolate()); } Handle<DebugScriptScopeInfo> Factory::NewDebugScriptScopeInfo( DirectHandle<ByteArray> numeric_data, DirectHandle<FixedArray> string_table) { - Tagged<DebugScriptScopeInfo> info = NewStructInternal<DebugScriptScopeInfo>( - DEBUG_SCRIPT_SCOPE_INFO_TYPE, AllocationType::kOld); - DisallowGarbageCollection no_gc; - info->set_numeric_data(*numeric_data); - info->set_string_table(*string_table); - return handle(info, isolate()); + return indirect_handle(New<DebugScriptScopeInfo, AllocationType::kOld>( + numeric_data, string_table), + isolate()); } Handle<JSObject> Factory::NewArgumentsObject(DirectHandle<JSFunction> callee, @@ -4924,11 +4853,9 @@ DirectHandle<String> Factory::ToPrimitiveHintString(ToPrimitiveHint hint) { UNREACHABLE(); } -DirectHandle<Map> Factory::CreateSloppyFunctionMap( +DirectHandle<Map> Factory::CreateFunctionMap( FunctionMode function_mode, MaybeDirectHandle<JSFunction> maybe_empty_function) { - // TODO(syg): Does sloppy/strict function map distinction need to exist - // anymore after V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS is removed? bool has_prototype = IsFunctionModeWithPrototype(function_mode); InstanceType instance_type; int header_size; @@ -4940,9 +4867,6 @@ DirectHandle<Map> Factory::CreateSloppyFunctionMap( header_size = JSFunctionWithoutPrototype::kHeaderSize; } int descriptors_count = has_prototype ? 3 : 2; -#ifdef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - descriptors_count += 2; -#endif int inobject_properties_count = 0; if (IsFunctionModeWithName(function_mode)) ++inobject_properties_count; @@ -5004,104 +4928,6 @@ DirectHandle<Map> Factory::CreateSloppyFunctionMap( name_string(), function_name_accessor(), roc_attribs); map->AppendDescriptor(isolate(), &d); } -#ifdef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - { // Add arguments accessor. - Descriptor d = Descriptor::AccessorConstant( - arguments_string(), function_arguments_accessor(), ro_attribs); - map->AppendDescriptor(isolate(), &d); - } - { // Add caller accessor. - Descriptor d = Descriptor::AccessorConstant( - caller_string(), function_caller_accessor(), ro_attribs); - map->AppendDescriptor(isolate(), &d); - } -#endif // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - if (IsFunctionModeWithPrototype(function_mode)) { - // Add prototype accessor. - PropertyAttributes attribs = - IsFunctionModeWithWritablePrototype(function_mode) ? rw_attribs - : ro_attribs; - Descriptor d = Descriptor::AccessorConstant( - prototype_string(), function_prototype_accessor(), attribs); - map->AppendDescriptor(isolate(), &d); - } - DCHECK_EQ(inobject_properties_count, field_index); - DCHECK_EQ(0, map->instance_descriptors()->number_of_slack_descriptors()); - LOG(isolate(), MapDetails(*map)); - return map; -} - -DirectHandle<Map> Factory::CreateStrictFunctionMap( - FunctionMode function_mode, DirectHandle<JSFunction> empty_function) { - bool has_prototype = IsFunctionModeWithPrototype(function_mode); - InstanceType instance_type; - int header_size; - if (has_prototype) { - instance_type = JS_FUNCTION_TYPE; - header_size = JSFunctionWithPrototype::kHeaderSize; - } else { - instance_type = JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE; - header_size = JSFunctionWithoutPrototype::kHeaderSize; - } - int inobject_properties_count = 0; - // length and prototype accessors or just length accessor. - int descriptors_count = IsFunctionModeWithPrototype(function_mode) ? 2 : 1; - if (IsFunctionModeWithName(function_mode)) { - ++inobject_properties_count; // name property. - } else { - ++descriptors_count; // name accessor. - } - descriptors_count += inobject_properties_count; - - DirectHandle<Map> map = NewContextfulMapForCurrentContext( - instance_type, header_size + inobject_properties_count * kTaggedSize, - TERMINAL_FAST_ELEMENTS_KIND, inobject_properties_count); - { - DisallowGarbageCollection no_gc; - Tagged<Map> raw_map = *map; - raw_map->set_is_constructor(has_prototype); - raw_map->set_is_callable(true); - // Temporarily set constructor to empty function to calm down map verifier. - raw_map->SetConstructor(*empty_function); - } - Map::SetPrototype(isolate(), map, empty_function); - - // - // Setup descriptors array. - // - Map::EnsureDescriptorSlack(isolate(), map, descriptors_count); - - PropertyAttributes rw_attribs = - static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); - PropertyAttributes ro_attribs = - static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY); - PropertyAttributes roc_attribs = - static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY); - - int field_index = 0; - static_assert(JSFunction::kLengthDescriptorIndex == 0); - { // Add length accessor. - Descriptor d = Descriptor::AccessorConstant( - length_string(), function_length_accessor(), roc_attribs); - map->AppendDescriptor(isolate(), &d); - } - - static_assert(JSFunction::kNameDescriptorIndex == 1); - if (IsFunctionModeWithName(function_mode)) { - // Add name field. - DirectHandle<Name> name = isolate()->factory()->name_string(); - Descriptor d = Descriptor::DataField( - isolate(), name, map->GetInObjectPropertyOffset(field_index++), - roc_attribs, Representation::Tagged(), true); - map->AppendDescriptor(isolate(), &d); - - } else { - // Add name accessor. - Descriptor d = Descriptor::AccessorConstant( - name_string(), function_name_accessor(), roc_attribs); - map->AppendDescriptor(isolate(), &d); - } - if (IsFunctionModeWithPrototype(function_mode)) { // Add prototype accessor. PropertyAttributes attribs = @@ -5165,7 +4991,7 @@ Handle<JSPromise> Factory::NewJSPromiseWithoutHook() { DisallowGarbageCollection no_gc; Tagged<JSPromise> raw = *promise; raw->set_reactions_or_result(Smi::zero(), SKIP_WRITE_BARRIER); - raw->set_flags(0); + raw->set_flags(JSPromise::Flags()); // TODO(v8) remove once embedder data slots are always zero-initialized. InitEmbedderFields(*promise, Smi::zero()); DCHECK_EQ(raw->GetEmbedderFieldCount(), v8::Promise::kEmbedderFieldCount); @@ -5230,12 +5056,8 @@ DirectHandle<JSFunction> Factory::CreatePromiseAllResolveElementFunction( DirectHandle<PromiseCapability> Factory::CreatePromiseCapabilityObject( DirectHandle<JSPromise> promise, DirectHandle<JSFunction> resolve, DirectHandle<JSFunction> reject) { - Handle<PromiseCapability> capability = Cast<PromiseCapability>( - NewStruct(PROMISE_CAPABILITY_TYPE, AllocationType::kYoung)); - capability->set_promise(*promise); - capability->set_resolve(*resolve); - capability->set_reject(*reject); - return capability; + return New<PromiseCapability, AllocationType::kYoung>(promise, resolve, + reject); } bool Factory::CanAllocateInReadOnlySpace() { @@ -5310,27 +5132,6 @@ DirectHandle<JSSharedArray> Factory::NewJSSharedArray( return instance; } -Handle<JSAtomicsMutex> Factory::NewJSAtomicsMutex() { - SharedObjectSafePublishGuard publish_guard; - DirectHandle<Map> map = js_atomics_mutex_map(); - auto mutex = - Cast<JSAtomicsMutex>(NewJSObjectFromMap(map, AllocationType::kSharedOld)); - mutex->set_state(JSAtomicsMutex::kUnlockedUncontended); - mutex->set_owner_thread_id(ThreadId::Invalid().ToInteger()); - mutex->SetNullWaiterQueueHead(); - return mutex; -} - -Handle<JSAtomicsCondition> Factory::NewJSAtomicsCondition() { - SharedObjectSafePublishGuard publish_guard; - DirectHandle<Map> map = js_atomics_condition_map(); - Handle<JSAtomicsCondition> cond = Cast<JSAtomicsCondition>( - NewJSObjectFromMap(map, AllocationType::kSharedOld)); - cond->set_state(JSAtomicsCondition::kEmptyState); - cond->SetNullWaiterQueueHead(); - return cond; -} - namespace { inline void InitializeTemplate(Tagged<TemplateInfo> that, bool is_cacheable) { that->set_template_info_flags(0); diff --git a/deps/v8/src/heap/factory.h b/deps/v8/src/heap/factory.h index ad5f09a08d98..11f91d9e926f 100644 --- a/deps/v8/src/heap/factory.h +++ b/deps/v8/src/heap/factory.h @@ -134,6 +134,18 @@ enum FunctionMode { kWithReadonlyPrototypeBit | kWithNameBit, }; +inline bool IsFunctionModeWithPrototype(FunctionMode function_mode) { + return (function_mode & kWithPrototypeBits) != 0; +} + +inline bool IsFunctionModeWithWritablePrototype(FunctionMode function_mode) { + return (function_mode & kWithWritablePrototypeBit) != 0; +} + +inline bool IsFunctionModeWithName(FunctionMode function_mode) { + return (function_mode & kWithNameBit) != 0; +} + enum class ArrayStorageAllocationMode { DONT_INITIALIZE_ARRAY_ELEMENTS, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE @@ -142,6 +154,8 @@ enum class ArrayStorageAllocationMode { // Interface for handle based allocation. class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { public: + using FactoryBase<Factory>::New; + inline ReadOnlyRoots read_only_roots() const; DirectHandle<Hole> NewHole(); @@ -251,30 +265,21 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { RelaxedStoreTag tag, AllocationType allocation); + DirectHandle<ForInEnumeratorHolder> NewForInEnumeratorHolder( + DirectHandle<Map> enum_cache_map, DirectHandle<FixedArray> named_keys, + Tagged<Smi> elements_length, Tagged<Smi> cache_length, + AllocationType allocation = AllocationType::kYoung); + // Create a new PropertyDescriptorObject struct. DirectHandle<PropertyDescriptorObject> NewPropertyDescriptorObject(); // Finds the internalized copy for string in the string table. // If not found, a new string is added to the table and returned. - Handle<String> InternalizeUtf8String(base::Vector<const char> str); - Handle<String> InternalizeUtf8String(const char* str) { - return InternalizeUtf8String(base::CStrVector(str)); - } + Handle<String> InternalizeUtf8String(std::string_view str); // Import InternalizeString overloads from base class. using FactoryBase::InternalizeString; - Handle<InternalizedString> InternalizeString(base::Vector<const char> str, - bool convert_encoding = false) { - return InternalizeString(base::Vector<const uint8_t>::cast(str), - convert_encoding); - } - - Handle<InternalizedString> InternalizeString(const char* str, - bool convert_encoding = false) { - return InternalizeString(base::OneByteVector(str), convert_encoding); - } - template <typename SeqString, template <typename> typename HandleType> requires( std::is_convertible_v<HandleType<SeqString>, DirectHandle<SeqString>>) @@ -334,14 +339,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { // UTF8 strings are pretenured when used for regexp literal patterns and // flags in the parser. V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromUtf8( - base::Vector<const char> str, - AllocationType allocation = AllocationType::kYoung); - - V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromUtf8( - std::string_view str, - AllocationType allocation = AllocationType::kYoung) { - return NewStringFromUtf8(base::StrVector(str), allocation); - } + std::string_view str, AllocationType allocation = AllocationType::kYoung); V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromUtf8( base::Vector<const uint8_t> str, UnicodeConfig config, @@ -528,6 +526,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { int aliased_context_slot); DirectHandle<AccessorInfo> NewAccessorInfo(); + DirectHandle<AccessCheckInfo> NewAccessCheckInfo(); DirectHandle<InterceptorInfo> NewInterceptorInfo( InterceptorKind kind, AllocationType allocation = AllocationType::kOld); @@ -761,15 +760,13 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { // runtime. Handle<JSObject> NewJSObjectFromMap( DirectHandle<Map> map, AllocationType allocation = AllocationType::kYoung, - DirectHandle<AllocationSite> allocation_site = - DirectHandle<AllocationSite>::null(), + MaybeDirectHandle<AllocationSite> allocation_site = kNullMaybeHandle, NewJSObjectType = NewJSObjectType::kMaybeEmbedderFieldsAndNoApiWrapper); // Like NewJSObjectFromMap, but includes allocating a properties dictionary.); Handle<JSObject> NewSlowJSObjectFromMap( DirectHandle<Map> map, int number_of_slow_properties, AllocationType allocation = AllocationType::kYoung, - DirectHandle<AllocationSite> allocation_site = - DirectHandle<AllocationSite>::null(), + MaybeDirectHandle<AllocationSite> allocation_site = kNullMaybeHandle, NewJSObjectType = NewJSObjectType::kMaybeEmbedderFieldsAndNoApiWrapper); Handle<JSObject> NewSlowJSObjectFromMap(DirectHandle<Map> map); // Calls NewJSObjectFromMap or NewSlowJSObjectFromMap depending on whether the @@ -777,8 +774,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { inline Handle<JSObject> NewFastOrSlowJSObjectFromMap( DirectHandle<Map> map, int number_of_slow_properties, AllocationType allocation = AllocationType::kYoung, - DirectHandle<AllocationSite> allocation_site = - DirectHandle<AllocationSite>::null(), + MaybeDirectHandle<AllocationSite> allocation_site = kNullMaybeHandle, NewJSObjectType = NewJSObjectType::kMaybeEmbedderFieldsAndNoApiWrapper); inline Handle<JSObject> NewFastOrSlowJSObjectFromMap(DirectHandle<Map> map); // Allocates and initializes a new JavaScript object with the given @@ -1126,24 +1122,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { DirectHandle<InterpreterData> NewInterpreterData( DirectHandle<BytecodeArray> bytecode_array, DirectHandle<Code> code); - static bool IsFunctionModeWithPrototype(FunctionMode function_mode) { - return (function_mode & kWithPrototypeBits) != 0; - } - - static bool IsFunctionModeWithWritablePrototype(FunctionMode function_mode) { - return (function_mode & kWithWritablePrototypeBit) != 0; - } - - static bool IsFunctionModeWithName(FunctionMode function_mode) { - return (function_mode & kWithNameBit) != 0; - } - - DirectHandle<Map> CreateSloppyFunctionMap( + DirectHandle<Map> CreateFunctionMap( FunctionMode function_mode, - MaybeDirectHandle<JSFunction> maybe_empty_function); - - DirectHandle<Map> CreateStrictFunctionMap( - FunctionMode function_mode, DirectHandle<JSFunction> empty_function); + MaybeDirectHandle<JSFunction> maybe_empty_function = {}); DirectHandle<Map> CreateClassFunctionMap( DirectHandle<JSFunction> empty_function); @@ -1242,10 +1223,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { DirectHandle<JSSharedArray> NewJSSharedArray( DirectHandle<JSFunction> constructor, int length); - Handle<JSAtomicsMutex> NewJSAtomicsMutex(); - - Handle<JSAtomicsCondition> NewJSAtomicsCondition(); - DirectHandle<FunctionTemplateInfo> NewFunctionTemplateInfo(int length, bool do_not_cache); @@ -1465,7 +1442,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { Tagged<HeapObject> AllocateRawWithAllocationSite( DirectHandle<Map> map, AllocationType allocation, - DirectHandle<AllocationSite> allocation_site); + MaybeDirectHandle<AllocationSite> allocation_site); Handle<JSArrayBufferView> NewJSArrayBufferView( DirectHandle<Map> map, DirectHandle<FixedArrayBase> elements, @@ -1498,7 +1475,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { Handle<T> CopyArrayAndGrow(DirectHandle<T> src, uint32_t grow_by, AllocationType allocation); - MaybeHandle<String> NewStringFromTwoByte(const base::uc16* string, int length, + MaybeHandle<String> NewStringFromTwoByte(const base::uc16* string, + uint32_t length, AllocationType allocation); // Creates a new JSArray with the given backing storage. Performs no diff --git a/deps/v8/src/heap/gc-tracer.h b/deps/v8/src/heap/gc-tracer.h index 453ab94e4b14..ffa5d7d0e68e 100644 --- a/deps/v8/src/heap/gc-tracer.h +++ b/deps/v8/src/heap/gc-tracer.h @@ -692,6 +692,7 @@ class V8_EXPORT_PRIVATE GCTracer { FRIEND_TEST(GCTracerTest, BackgroundMajorMCScope); FRIEND_TEST(GCTracerTest, CyclePriorities); FRIEND_TEST(GCTracerTest, EmbedderAllocationThroughput); + FRIEND_TEST(GCTracerTest, HighAllocationRateWithEmbedderAllocation); FRIEND_TEST(GCTracerTest, MultithreadedBackgroundScope); FRIEND_TEST(GCTracerTest, NewSpaceAllocationThroughput); FRIEND_TEST(GCTracerTest, PerGenerationAllocationThroughput); @@ -700,6 +701,7 @@ class V8_EXPORT_PRIVATE GCTracer { FRIEND_TEST(GCTracerTest, IncrementalMarkingDetails); FRIEND_TEST(GCTracerTest, IncrementalScope); FRIEND_TEST(GCTracerTest, IncrementalMarkingSpeed); + FRIEND_TEST(GCTracerTest, LowAllocationRateWithZeroEmbedderAllocation); FRIEND_TEST(GCTracerTest, MutatorUtilization); FRIEND_TEST(GCTracerTest, RecordMarkCompactHistograms); FRIEND_TEST(GCTracerTest, RecordScavengerHistograms); diff --git a/deps/v8/src/heap/heap-inl.h b/deps/v8/src/heap/heap-inl.h index 335a96f3c70c..a6942273a8b8 100644 --- a/deps/v8/src/heap/heap-inl.h +++ b/deps/v8/src/heap/heap-inl.h @@ -74,10 +74,12 @@ uint64_t Heap::external_memory() const { RootsTable& Heap::roots_table() { return isolate()->roots_table(); } -#define ROOT_ACCESSOR(Type, name, CamelName) \ - Tagged<Type> Heap::name() { \ - return TrustedCast<Type>( \ - Tagged<Object>(roots_table()[RootIndex::k##CamelName])); \ +#define ROOT_ACCESSOR(Type, name, CamelName) \ + Tagged<Type> Heap::name() { \ + Tagged<Object> obj = \ + Tagged<Object>(roots_table()[RootIndex::k##CamelName]); \ + DCHECK_WITH_SANDBOX_ACCESS(NullOrIs<Type>(obj)); \ + return UncheckedCast<Type>(obj); \ } MUTABLE_ROOT_LIST(ROOT_ACCESSOR) @@ -140,6 +142,13 @@ void Heap::SetFunctionsMarkedForManualOptimization(Tagged<Object> hash_table) { hash_table.ptr(); } +void Heap::SetFunctionsMarkedForDisabledEagerInlining( + Tagged<Object> hash_table) { + DCHECK(IsObjectHashTable(hash_table) || IsUndefined(hash_table)); + roots_table()[RootIndex::kFunctionsMarkedForDisabledEagerInlining] = + hash_table.ptr(); +} + void Heap::SetSmiStringCache(Tagged<SmiStringCache> cache) { set_smi_string_cache(cache); } @@ -294,9 +303,9 @@ Heap* Heap::FromWritableHeapObject(Tagged<HeapObject> obj) { return heap; } -void Heap::CopyBlock(Address dst, Address src, size_t byte_size) { - DCHECK(IsAligned(byte_size, kTaggedSize)); - CopyTagged(dst, src, byte_size / kTaggedSize); +void Heap::CopyBlock(Address dst, Address src, SafeHeapObjectSize byte_size) { + DCHECK(IsAligned(byte_size.value(), kTaggedSize)); + CopyTagged(dst, src, byte_size.value() / kTaggedSize); } bool Heap::IsPendingAllocationInternal(Tagged<HeapObject> object) { @@ -312,7 +321,7 @@ bool Heap::IsPendingAllocation(Tagged<HeapObject> object) { bool result = IsPendingAllocationInternal(object); if (v8_flags.trace_pending_allocations && result) { StdoutStream{} << "Pending allocation: " << std::hex << "0x" << object.ptr() - << "\n"; + << std::dec << "\n"; } return result; } diff --git a/deps/v8/src/heap/heap-layout-inl.h b/deps/v8/src/heap/heap-layout-inl.h index c99991e7f46d..891660158f83 100644 --- a/deps/v8/src/heap/heap-layout-inl.h +++ b/deps/v8/src/heap/heap-layout-inl.h @@ -21,6 +21,11 @@ bool HeapLayout::InReadOnlySpace(Tagged<HeapObject> object) { return MemoryChunk::FromHeapObject(object)->InReadOnlySpace(); } +template <typename T> +bool CastTraits<ReadOnly<T>>::AllowFrom(Tagged<HeapObject> value) { + return HeapLayout::InReadOnlySpace(value) && CastTraits<T>::AllowFrom(value); +} + // static bool HeapLayout::InYoungGeneration(const MemoryChunk* chunk, Tagged<HeapObject> object) { diff --git a/deps/v8/src/heap/heap-visitor-inl.h b/deps/v8/src/heap/heap-visitor-inl.h index bd108a60dbd8..afbe85f846e8 100644 --- a/deps/v8/src/heap/heap-visitor-inl.h +++ b/deps/v8/src/heap/heap-visitor-inl.h @@ -86,7 +86,11 @@ Tagged<T> HeapVisitor<ConcreteVisitor>::Cast(Tagged<HeapObject> object, if constexpr (ConcreteVisitor::ShouldUseUncheckedCast()) { return i::UncheckedCast<T>(object); } - return i::TrustedCast<T>(object); + if constexpr (is_subtype_v<T, TrustedObject>) { + return i::TrustedCast<T>(object); + } else { + return i::Cast<T>(object); + } } template <typename ConcreteVisitor> @@ -424,7 +428,11 @@ ConcurrentHeapVisitor<ConcreteVisitor>::ConcurrentHeapVisitor(Isolate* isolate) template <typename T> struct ConcurrentVisitorCastHelper { static V8_INLINE Tagged<T> Cast(Tagged<HeapObject> object) { - return i::TrustedCast<T>(object); + if constexpr (is_subtype_v<T, TrustedObject>) { + return i::TrustedCast<T>(object); + } else { + return i::Cast<T>(object); + } } }; @@ -447,7 +455,11 @@ Tagged<T> ConcurrentHeapVisitor<ConcreteVisitor>::Cast( if constexpr (ConcreteVisitor::EnableConcurrentVisitation()) { return ConcurrentVisitorCastHelper<T>::Cast(object); } - return i::TrustedCast<T>(object); + if constexpr (is_subtype_v<T, TrustedObject>) { + return i::TrustedCast<T>(object); + } else { + return i::Cast<T>(object); + } } #define VISIT_AS_LOCKED_STRING(VisitorId, TypeName) \ diff --git a/deps/v8/src/heap/heap-visitor.h b/deps/v8/src/heap/heap-visitor.h index 9830a6b8b22e..9cc1fa1fd334 100644 --- a/deps/v8/src/heap/heap-visitor.h +++ b/deps/v8/src/heap/heap-visitor.h @@ -72,6 +72,7 @@ class MaybeObjectSize final { V(Foreign) \ V(FunctionTemplateInfo) \ V(HeapNumber) \ + V(UninitializedHeapNumber) \ V(HashSeedWrapper) \ V(InterceptorInfo) \ V(Hole) \ @@ -141,7 +142,6 @@ class MaybeObjectSize final { V(JSGlobalProxy) \ V(JSObject) \ V(JSRegExp) \ - V(JSSynchronizationPrimitive) \ V(JSTypedArray) \ V(JSWeakCollection) \ V(JSWeakRef) \ diff --git a/deps/v8/src/heap/heap-write-barrier-inl.h b/deps/v8/src/heap/heap-write-barrier-inl.h index 5ca5b0a8d663..3cee8294a56f 100644 --- a/deps/v8/src/heap/heap-write-barrier-inl.h +++ b/deps/v8/src/heap/heap-write-barrier-inl.h @@ -248,10 +248,10 @@ void WriteBarrier::ForExternalPointer(Tagged<HeapObject> host, } // static -void WriteBarrier::ForIndirectPointer(Tagged<HeapObject> host, - IndirectPointerSlot slot, - Tagged<HeapObject> value, - WriteBarrierMode mode) { +void WriteBarrier::ForTrustedPointer(Tagged<HeapObject> host, + TrustedPointerSlot slot, + Tagged<HeapObject> value, + WriteBarrierMode mode) { // Indirect pointers are only used when the sandbox is enabled. #ifdef V8_ENABLE_SANDBOX if (mode == SKIP_WRITE_BARRIER) { @@ -274,17 +274,17 @@ void WriteBarrier::ForIndirectPointer(Tagged<HeapObject> host, } // static -template <typename T, IndirectPointerTagRange kTagRange> -void WriteBarrier::ForIndirectPointer(HeapObject* host, - TrustedPointerMember<T, kTagRange>* slot, - Tagged<T> value, WriteBarrierMode mode) { +template <typename T, TrustedPointerTagRange kTagRange> +void WriteBarrier::ForTrustedPointer(HeapObject* host, + TrustedPointerMember<T, kTagRange>* slot, + Tagged<T> value, WriteBarrierMode mode) { // Indirect pointers are only used when the sandbox is enabled. #ifdef V8_ENABLE_SANDBOX // TODO(leszeks): Avoid the cast to Address here, pass a pointer to the actual // handle field. - ForIndirectPointer( + ForTrustedPointer( Tagged(host), - IndirectPointerSlot(reinterpret_cast<Address>(slot), kTagRange), value, + TrustedPointerSlot(reinterpret_cast<Address>(slot), kTagRange), value, mode); #else UNREACHABLE(); @@ -434,7 +434,7 @@ void WriteBarrier::Marking(Tagged<HeapObject> host, ExternalPointerSlot slot, MarkingSlow(host, slot, handle); } -void WriteBarrier::Marking(Tagged<HeapObject> host, IndirectPointerSlot slot) { +void WriteBarrier::Marking(Tagged<HeapObject> host, TrustedPointerSlot slot) { if (!IsMarking(host)) [[likely]] { return; } diff --git a/deps/v8/src/heap/heap-write-barrier.cc b/deps/v8/src/heap/heap-write-barrier.cc index 7c38e745cd18..c3721920e3d4 100644 --- a/deps/v8/src/heap/heap-write-barrier.cc +++ b/deps/v8/src/heap/heap-write-barrier.cc @@ -169,7 +169,7 @@ void WriteBarrier::MarkingSlow(Tagged<HeapObject> host, } void WriteBarrier::MarkingSlow(Tagged<HeapObject> host, - IndirectPointerSlot slot) { + TrustedPointerSlot slot) { MarkingBarrier* marking_barrier = CurrentMarkingBarrier(host); marking_barrier->Write(host, slot); } @@ -243,13 +243,13 @@ int WriteBarrier::MarkingFromCode(Address raw_host, Address raw_slot) { return 0; } -int WriteBarrier::IndirectPointerMarkingFromCode(Address raw_host, - Address raw_slot, - Address raw_tag) { +int WriteBarrier::TrustedPointerMarkingFromCode(Address raw_host, + Address raw_slot, + Address raw_tag) { Tagged<HeapObject> host = Cast<HeapObject>(Tagged<Object>(raw_host)); - IndirectPointerTag tag = static_cast<IndirectPointerTag>(raw_tag); - DCHECK(IsValidIndirectPointerTag(tag)); - IndirectPointerSlot slot(raw_slot, tag); + TrustedPointerTag tag = static_cast<TrustedPointerTag>(raw_tag); + DCHECK(IsValidTrustedPointerTag(tag)); + TrustedPointerSlot slot(raw_slot, tag); #if DEBUG DCHECK(!HeapLayout::InWritableSharedSpace(host)); diff --git a/deps/v8/src/heap/heap-write-barrier.h b/deps/v8/src/heap/heap-write-barrier.h index 1928d0d64d96..6f8dd10afd7a 100644 --- a/deps/v8/src/heap/heap-write-barrier.h +++ b/deps/v8/src/heap/heap-write-barrier.h @@ -16,7 +16,7 @@ namespace v8::internal { -template <typename T, IndirectPointerTagRange kTag> +template <typename T, TrustedPointerTagRange kTag> class TrustedPointerMember; class ArrayBufferExtension; @@ -73,8 +73,8 @@ class V8_EXPORT_PRIVATE WriteBarrier final { Address key_slot_address, Isolate* isolate); static int MarkingFromCode(Address raw_host, Address raw_slot); - static int IndirectPointerMarkingFromCode(Address raw_host, Address raw_slot, - Address raw_tag); + static int TrustedPointerMarkingFromCode(Address raw_host, Address raw_slot, + Address raw_tag); static int SharedMarkingFromCode(Address raw_host, Address raw_slot); static int SharedFromCode(Address raw_host, Address raw_slot); @@ -103,11 +103,11 @@ class V8_EXPORT_PRIVATE WriteBarrier final { Tagged<HeapObject> host, ExternalPointerSlot slot, ExternalPointerHandle handle, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - static inline void ForIndirectPointer( - Tagged<HeapObject> host, IndirectPointerSlot slot, + static inline void ForTrustedPointer( + Tagged<HeapObject> host, TrustedPointerSlot slot, Tagged<HeapObject> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - template <typename T, IndirectPointerTagRange kTagRange> - static inline void ForIndirectPointer( + template <typename T, TrustedPointerTagRange kTagRange> + static inline void ForTrustedPointer( HeapObject* host, TrustedPointerMember<T, kTagRange>* slot, Tagged<T> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); static inline void ForProtectedPointer( @@ -166,6 +166,8 @@ class V8_EXPORT_PRIVATE WriteBarrier final { static constexpr bool kUninterestingPagesCanBeSkipped = true; private: + friend class AllocationWitness; + static inline bool IsSkipWriteBarrierMode(WriteBarrierMode mode) { static_assert(SKIP_WRITE_BARRIER == 0 && SKIP_WRITE_BARRIER_SCOPE == 1 && SKIP_WRITE_BARRIER_FOR_GC == 2 && @@ -201,7 +203,7 @@ class V8_EXPORT_PRIVATE WriteBarrier final { RelocInfo*, Tagged<HeapObject> value); static inline void Marking(Tagged<HeapObject> host, ExternalPointerSlot slot, ExternalPointerHandle handle); - static inline void Marking(Tagged<HeapObject> host, IndirectPointerSlot slot); + static inline void Marking(Tagged<HeapObject> host, TrustedPointerSlot slot); static inline void Marking(Tagged<TrustedObject> host, ProtectedPointerSlot slot, Tagged<TrustedObject> value); @@ -217,8 +219,8 @@ class V8_EXPORT_PRIVATE WriteBarrier final { V8_NOINLINE V8_PRESERVE_MOST static void MarkingSlow( Tagged<HeapObject> host, ExternalPointerSlot slot, ExternalPointerHandle handle); - V8_NOINLINE V8_PRESERVE_MOST static void MarkingSlow( - Tagged<HeapObject> host, IndirectPointerSlot slot); + V8_NOINLINE V8_PRESERVE_MOST static void MarkingSlow(Tagged<HeapObject> host, + TrustedPointerSlot slot); V8_NOINLINE V8_PRESERVE_MOST static void MarkingSlow( Tagged<TrustedObject> host, ProtectedPointerSlot slot, Tagged<TrustedObject> value); diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index 420c631486d5..c6c40398d4c5 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -6,6 +6,7 @@ #include <algorithm> #include <atomic> +#include <bit> #include <cinttypes> #include <iomanip> #include <memory> @@ -18,7 +19,6 @@ #include "include/v8-cppgc.h" #include "include/v8-locker.h" #include "src/api/api-inl.h" -#include "src/base/bits.h" #include "src/base/flags.h" #include "src/base/logging.h" #include "src/base/macros.h" @@ -123,6 +123,7 @@ #include "src/objects/heap-object-field-inl.h" #include "src/objects/heap-object-set-map-inl.h" #include "src/objects/instance-type.h" +#include "src/objects/js-struct.h" #include "src/objects/js-weak-refs-inl.h" #include "src/objects/maybe-object.h" #include "src/objects/objects.h" @@ -1937,19 +1938,22 @@ void Heap::StartIncrementalMarkingOnInterrupt() { void Heap::StartIncrementalMarkingIfAllocationLimitIsReached( LocalHeap* local_heap, GCFlags gc_flags, - const GCCallbackFlags gc_callback_flags) { + const GCCallbackFlags gc_callback_flags, + std::optional<GarbageCollectionReason> gc_reason) { if (incremental_marking()->IsStopped() && incremental_marking()->CanAndShouldBeStarted()) { auto [limit, reason] = IncrementalMarkingLimitReached(); switch (limit) { case IncrementalMarkingLimit::kHardLimit: if (local_heap->is_main_thread_for(this)) { - StartIncrementalMarking( - gc_flags, - OldGenerationSpaceAvailable() <= NewSpaceTargetCapacity() - ? GarbageCollectionReason::kAllocationLimit - : GarbageCollectionReason::kGlobalAllocationLimit, - gc_callback_flags, GarbageCollector::MARK_COMPACTOR, reason); + if (!gc_reason) { + gc_reason = + OldGenerationSpaceAvailable() <= NewSpaceTargetCapacity() + ? GarbageCollectionReason::kAllocationLimit + : GarbageCollectionReason::kGlobalAllocationLimit; + } + StartIncrementalMarking(gc_flags, *gc_reason, gc_callback_flags, + GarbageCollector::MARK_COMPACTOR, reason); } else { ExecutionAccess access(isolate()); isolate()->stack_guard()->RequestStartIncrementalMarking(); @@ -2631,11 +2635,6 @@ bool Heap::ExternalStringTable::Contains(Tagged<String> string) { return false; } -void Heap::UpdateExternalString(Tagged<String> string, size_t old_payload, - size_t new_payload) { - DCHECK(IsExternalString(string)); -} - void Heap::ExternalStringTable::Verify() { #ifdef DEBUG std::set<Tagged<String>> visited_map; @@ -3489,9 +3488,7 @@ namespace { double ComputeMutatorUtilizationImpl(double mutator_speed, std::optional<double> gc_speed) { - constexpr double kMinMutatorUtilization = 0.0; constexpr double kConservativeGcSpeedInBytesPerMillisecond = 200000; - if (mutator_speed == 0) return kMinMutatorUtilization; if (!gc_speed) gc_speed = kConservativeGcSpeedInBytesPerMillisecond; // Derivation: // mutator_utilization = mutator_time / (mutator_time + gc_time) @@ -3659,13 +3656,15 @@ void Heap::ActivateMemoryReducerIfNeeded() { } void Heap::ActivateMemoryReducerIfNeededOnMainThread() { + // Only trigger this if we are still backgrounded. + if (!isolate()->is_backgrounded()) return; // Activate memory reducer when switching to background if // - there was no mark compact since the start. // - the committed memory can be potentially reduced. // 2 pages for the old, code, and map space + 1 page for new space. const int kMinCommittedMemory = 7 * NormalPage::kPageSize; - if (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory && - isolate()->is_backgrounded()) { + if ((v8_flags.memory_reducer_limit_based) || + (ms_count_ == 0 && CommittedMemory() > kMinCommittedMemory)) { memory_reducer_->NotifyPossibleGarbage(); } } @@ -4581,12 +4580,14 @@ void Heap::IterateRoots(RootVisitor* v, base::EnumSet<SkipRoot> options, isolate_->compilation_cache()->Iterate(v); v->Synchronize(VisitorSynchronization::kCompilationCache); + Tagged<Object> first_builtin(isolate_->builtin_table()[0]); const bool skip_iterate_builtins = options.contains(SkipRoot::kOldGeneration) || (Builtins::kCodeObjectsAreInROSpace && options.contains(SkipRoot::kReadOnlyBuiltins) && // Prior to ReadOnlyPromotion, builtins may be on the mutable heap. - !isolate_->serializer_enabled()); + IsHeapObject(first_builtin) && + HeapLayout::InReadOnlySpace(Cast<HeapObject>(first_builtin))); if (!skip_iterate_builtins) { IterateBuiltins(v); v->Synchronize(VisitorSynchronization::kBuiltins); @@ -4903,9 +4904,7 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints, if (!v8_flags.minor_ms) { // TODO(dinfuehr): Rounding to a power of 2 is technically no longer // needed but yields best performance on Pixel2. - max_semi_space_size_ = - static_cast<size_t>(base::bits::RoundUpToPowerOfTwo64( - static_cast<uint64_t>(max_semi_space_size_))); + max_semi_space_size_ = std::bit_ceil(max_semi_space_size_); } max_semi_space_size_ = std::max(max_semi_space_size_, DefaultMinSemiSpaceSize()); @@ -5694,7 +5693,8 @@ Heap::IncrementalMarkingLimitReached() { if (old_generation_space_available > new_space_target_capacity && (global_memory_available > new_space_target_capacity)) { - if (gc_count_ == kInitialGCEpoch && limits()->using_initial_limit()) { + if (gc_count_ == kInitialGCEpoch && limits()->using_initial_limit() && + !v8_flags.memory_reducer_limit_based) { // At this point the embedder memory is above the activation // threshold. No GC happened so far and it's thus unlikely to get a // configured heap any time soon. Start a memory reducer in this case @@ -6064,7 +6064,7 @@ void Heap::SetUpSpaces() { tracer_.reset(new GCTracer(this, startup_time)); array_buffer_sweeper_.reset(new ArrayBufferSweeper(this)); memory_measurement_.reset(new MemoryMeasurement(isolate())); - if (v8_flags.memory_reducer) memory_reducer_.reset(new MemoryReducer(this)); + if (v8_flags.memory_reducer) memory_reducer_ = MemoryReducer::Create(this); if (V8_UNLIKELY(TracingFlags::is_gc_stats_enabled())) { live_object_stats_.reset(new ObjectStats(this)); dead_object_stats_.reset(new ObjectStats(this)); @@ -6221,7 +6221,8 @@ void Heap::SetStackStart() { // deserialization process), we don't need to set the stack start. if (main_thread_local_heap_ == nullptr) return; - void* actual_stack_start = v8::base::Stack::GetStackStart(); + void* actual_stack_start = v8::base::Stack::GetEffectiveStackStart(); + const bool check_for_tls = ShouldCheckForTLSOnStack(); // Because of v8::Locker an isolate might be migrated between threads. In such // situations the provided stack start marker should only be used on the right @@ -6229,9 +6230,9 @@ void Heap::SetStackStart() { if (stack_start_marker_ && actual_stack_start >= stack_start_marker_ && reinterpret_cast<uintptr_t>(stack_start_marker_) >= static_cast<uintptr_t>(GetCurrentStackPosition())) { - stack().SetStackStart(stack_start_marker_); + stack().SetStackStart(stack_start_marker_, check_for_tls); } else { - stack().SetStackStart(actual_stack_start); + stack().SetStackStart(actual_stack_start, check_for_tls); } } @@ -6245,6 +6246,16 @@ const ::heap::base::Stack& Heap::stack() const { return main_thread_local_heap_->stack_; } +bool Heap::ShouldCheckForTLSOnStack() const { +#ifdef VERIFY_HEAP + if (v8_flags.verify_heap) return true; +#endif // VERIFY_HEAP + if (const auto* cpp_heap = CppHeap::From(cpp_heap_)) { + return cpp_heap->ShouldCheckForTLSOnStack(); + } + return true; +} + void Heap::StartTearDown() { // This may invoke a GC in case marking is running to get us into a // well-defined state for tear down. @@ -6363,7 +6374,6 @@ void Heap::TearDown() { ephemeron_remembered_set_.reset(); if (memory_reducer_ != nullptr) { - memory_reducer_->TearDown(); memory_reducer_.reset(); } @@ -6515,13 +6525,21 @@ void Heap::CompactWeakArrayLists() { } void Heap::AddRetainedMaps(DirectHandle<NativeContext> context, - GlobalHandleVector<Map> maps) { + base::Vector<const IndirectHandle<Map>> maps) { + uint32_t number_of_new_maps = 0; + for (DirectHandle<Map> map : maps) { + DCHECK(!HeapLayout::InAnySharedSpace(*map)); + if (!map->is_in_retained_map_list()) { + number_of_new_maps++; + } + } + if (number_of_new_maps == 0) return; + Handle<WeakArrayList> array(Cast<WeakArrayList>(context->retained_maps()), isolate()); const uint32_t array_len = array->length().value(); const uint32_t array_cap = array->capacity().value(); - uint32_t new_maps_size = - static_cast<uint32_t>(maps.size()) * kRetainMapEntrySize; + uint32_t new_maps_size = number_of_new_maps * kRetainMapEntrySize; if (array_len + new_maps_size > array_cap) { CompactRetainedMaps(*array); } @@ -6536,8 +6554,6 @@ void Heap::AddRetainedMaps(DirectHandle<NativeContext> context, DisallowGarbageCollection no_gc; Tagged<WeakArrayList> raw_array = *array; for (DirectHandle<Map> map : maps) { - DCHECK(!HeapLayout::InAnySharedSpace(*map)); - if (map->is_in_retained_map_list()) { continue; } @@ -6666,7 +6682,7 @@ void Heap::VerifySkippedWriteBarrier(Address object, Address value) { } // static -void Heap::VerifySkippedIndirectWriteBarrier(Address object) { +void Heap::VerifySkippedTrustedWriteBarrier(Address object) { #if V8_VERIFY_WRITE_BARRIERS DCHECK(v8_flags.verify_write_barriers); LocalHeap* local_heap = LocalHeap::Current(); @@ -6827,6 +6843,7 @@ class UnreachableObjectsFilter : public HeapObjectsFilter { } V8_INLINE void MarkHeapObject(Tagged<HeapObject> heap_object) { + if (IsInaccessible(heap_object)) return; if (filter_->MarkAsReachable(heap_object)) { marking_stack_.push_back(heap_object); } @@ -7831,10 +7848,9 @@ ConservativePinningScope::ConservativePinningScope(Heap* heap) : heap_(heap) { // frame layouts). In such cases, we scan the stack either from the last // c_entry_fp or the whole stack. const Address c_entry_fp = *heap_->isolate()->c_entry_fp_address(); - const void* frame_address = - (c_entry_fp == kNullAddress) - ? static_cast<void*>(v8::base::Stack::GetStackStart()) - : reinterpret_cast<const void*>(c_entry_fp); + const void* frame_address = (c_entry_fp == kNullAddress) + ? heap_->stack().stack_start() + : reinterpret_cast<const void*>(c_entry_fp); // The stack segment covered by this scope should include the scope itself. DCHECK_NOT_NULL(frame_address); DCHECK_LE(this, frame_address); diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 39e2304d2a2e..0a763b72ed61 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -39,6 +39,7 @@ #include "src/heap/gc-callbacks.h" #include "src/heap/heap-allocator.h" #include "src/heap/marking-state.h" +#include "src/heap/memory-reducer.h" #include "src/heap/minor-gc-job.h" #include "src/heap/pretenuring-handler.h" #include "src/heap/sweeper.h" @@ -386,8 +387,9 @@ class Heap final { } // Copy block of memory from src to dst. Size of block should be aligned - // by pointer size. - static inline void CopyBlock(Address dst, Address src, size_t byte_size); + // by tagged size. + static inline void CopyBlock(Address dst, Address src, + SafeHeapObjectSize byte_size); perfetto::NamedTrack tracing_track() const { return tracing_track_; } @@ -681,8 +683,9 @@ class Heap final { void CompactWeakArrayLists(); - V8_EXPORT_PRIVATE void AddRetainedMaps(DirectHandle<NativeContext> context, - GlobalHandleVector<Map> maps); + V8_EXPORT_PRIVATE void AddRetainedMaps( + DirectHandle<NativeContext> context, + base::Vector<const IndirectHandle<Map>> maps); // This event is triggered after object is moved to a new place. void OnMoveEvent(Tagged<HeapObject> source, Tagged<HeapObject> target, @@ -695,7 +698,7 @@ class Heap final { // null. V8_INLINE bool CanSafepoint() const { return deserialization_complete(); } - bool HasLowAllocationRate(); + V8_EXPORT_PRIVATE bool HasLowAllocationRate(); bool HasHighFragmentation(); void ActivateMemoryReducerIfNeeded(); @@ -913,6 +916,8 @@ class Heap final { V8_INLINE void SetMessageListeners(Tagged<ArrayList> value); V8_INLINE void SetFunctionsMarkedForManualOptimization( Tagged<Object> bytecode); + V8_INLINE void SetFunctionsMarkedForDisabledEagerInlining( + Tagged<Object> hash_table); V8_INLINE void SetSmiStringCache(Tagged<SmiStringCache> cache); V8_INLINE void SetDoubleStringCache(Tagged<DoubleStringCache> cache); V8_INLINE void SetCachedBigIntDivisor(Tagged<BigInt> divisor); @@ -1087,7 +1092,7 @@ class Heap final { size_t slot_offset); static void VerifySkippedWriteBarrier(Address object, Address value); - static void VerifySkippedIndirectWriteBarrier(Address object); + static void VerifySkippedTrustedWriteBarrier(Address object); #ifdef DEBUG void VerifySlotRangeHasNoRecordedSlots(Address start, Address end); @@ -1114,7 +1119,8 @@ class Heap final { V8_EXPORT_PRIVATE void StartIncrementalMarkingIfAllocationLimitIsReached( LocalHeap* local_heap, GCFlags gc_flags, - GCCallbackFlags gc_callback_flags = GCCallbackFlags::kNoGCCallbackFlags); + GCCallbackFlags gc_callback_flags = GCCallbackFlags::kNoGCCallbackFlags, + std::optional<GarbageCollectionReason> gc_reason = std::nullopt); // Synchronously finalizes incremental marking. V8_EXPORT_PRIVATE void FinalizeIncrementalMarkingAtomically( @@ -1130,6 +1136,10 @@ class Heap final { // Ensures that sweeping is finished for that object's page. void EnsureSweepingCompletedForObject(Tagged<HeapObject> object); + HeapGrowingMode CurrentHeapGrowingMode(); + + MemoryReducerBase* memory_reducer() const { return memory_reducer_.get(); } + HeapLimits* limits() const { return limits_.get(); } IncrementalMarking* incremental_marking() const { @@ -1193,6 +1203,8 @@ class Heap final { V8_EXPORT_PRIVATE ::heap::base::Stack& stack(); V8_EXPORT_PRIVATE const ::heap::base::Stack& stack() const; + bool ShouldCheckForTLSOnStack() const; + // =========================================================================== // Embedder roots optimizations. ============================================= // =========================================================================== @@ -1209,12 +1221,6 @@ class Heap final { // Registers an external string. inline void RegisterExternalString(Tagged<String> string); - // Called when a string's resource is changed. The size of the payload is sent - // as argument of the method. - V8_EXPORT_PRIVATE void UpdateExternalString(Tagged<String> string, - size_t old_payload, - size_t new_payload); - // Finalizes an external string by deleting the associated external // data and clearing the resource pointer. inline void FinalizeExternalString(Tagged<String> string); @@ -1931,6 +1937,7 @@ class Heap final { // Performs a major collection in the whole heap. void MarkCompact(); + // Performs a minor collection of just the young generation. void MinorMarkSweep(); @@ -1966,8 +1973,6 @@ class Heap final { // Growing strategy. ========================================================= // =========================================================================== - MemoryReducer* memory_reducer() { return memory_reducer_.get(); } - // For some webpages NotifyLoadingEnded() is never called. // This constant limits the effect of load time on GC. // The value is arbitrary and chosen as the largest load time observed in @@ -2002,8 +2007,6 @@ class Heap final { AllocationOrigin origin); bool ShouldExpandYoungGenerationOnSlowAllocation(size_t allocation_size); - HeapGrowingMode CurrentHeapGrowingMode(); - double PercentToOldGenerationLimit() const; double PercentToGlobalMemoryLimit() const; enum class IncrementalMarkingLimit { @@ -2286,7 +2289,7 @@ class Heap final { std::unique_ptr<IncrementalMarking> incremental_marking_; std::unique_ptr<ConcurrentMarking> concurrent_marking_; std::unique_ptr<MemoryMeasurement> memory_measurement_; - std::unique_ptr<MemoryReducer> memory_reducer_; + std::unique_ptr<MemoryReducerBase> memory_reducer_; std::unique_ptr<ObjectStats> live_object_stats_; std::unique_ptr<ObjectStats> dead_object_stats_; std::unique_ptr<MinorGCJob> minor_gc_job_; diff --git a/deps/v8/src/heap/local-heap.cc b/deps/v8/src/heap/local-heap.cc index 10fb87960e20..2bf90536ffce 100644 --- a/deps/v8/src/heap/local-heap.cc +++ b/deps/v8/src/heap/local-heap.cc @@ -43,7 +43,8 @@ void LocalHeap::VerifyCurrent() const { DCHECK_EQ(this, LocalHeap::Current()); } #endif LocalHeap::LocalHeap(Heap* heap, ThreadKind kind, - std::unique_ptr<PersistentHandles> persistent_handles) + std::unique_ptr<PersistentHandles> persistent_handles, + v8::base::Stack::StackSlot stack_start) : heap_(heap), ptr_compr_cage_access_scope_(heap->isolate()), is_main_thread_(kind == ThreadKind::kMain), @@ -87,7 +88,19 @@ LocalHeap::LocalHeap(Heap* heap, ThreadKind kind, persistent_handles_->Attach(this); } if (!is_main_thread()) { + DCHECK(::heap::base::Stack::IsOnStack(this)); saved_current_local_heap_ = LocalHeap::TryGetCurrent(); + // Set the stack start for the outermost background `LocalHeap` on this + // thread. When `saved_current_local_heap_->is_main_thread()` is true, a + // parked main thread is constructing a background `LocalHeap` (whose + // segment in `Stack::background_stacks_` is separate from the main thread's + // `Stack::current_segment_`). For nested background `LocalHeap`s, keep the + // outermost stack start because `Stack::background_stacks_` only stores a + // single segment per thread. + if (!saved_current_local_heap_ || + saved_current_local_heap_->is_main_thread()) { + stack_start_scope_.emplace(stack_start); + } saved_current_isolate_ = Isolate::TryGetCurrent(); Isolate::SetCurrent(heap_->isolate()); LocalHeap::SetCurrent(this); diff --git a/deps/v8/src/heap/local-heap.h b/deps/v8/src/heap/local-heap.h index f8ab0c6db943..5f628c69e992 100644 --- a/deps/v8/src/heap/local-heap.h +++ b/deps/v8/src/heap/local-heap.h @@ -7,11 +7,13 @@ #include <atomic> #include <memory> +#include <optional> #if V8_OS_DARWIN #include "pthread.h" #endif +#include "include/v8-isolate.h" #include "src/base/logging.h" #include "src/base/macros.h" #include "src/base/platform/condition-variable.h" @@ -51,9 +53,13 @@ class V8_EXPORT_PRIVATE LocalHeap { public: using GCEpilogueCallback = void(void*); + // The parameter `stack_start` is only used for stack-allocated instances, + // where `kind == ThreadKind::kBackground`. explicit LocalHeap( Heap* heap, ThreadKind kind, - std::unique_ptr<PersistentHandles> persistent_handles = nullptr); + std::unique_ptr<PersistentHandles> persistent_handles = nullptr, + v8::base::Stack::StackSlot stack_start = + v8::base::Stack::GetCurrentFrameAddress()); ~LocalHeap(); // Frequently invoked by local thread to check whether safepoint was requested @@ -427,6 +433,9 @@ class V8_EXPORT_PRIVATE LocalHeap { // Stack information for the thread using this local heap. ::heap::base::Stack stack_; + CPPGC_STACK_ALLOCATED_IGNORE( + "Only emplaced for stack-allocated background LocalHeaps") + std::optional<StackStartScope> stack_start_scope_; #if V8_VERIFY_WRITE_BARRIERS Address write_barrier_mode_for_object_ = kNullAddress; diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 6712456d29aa..1cc7bad90562 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -80,6 +80,7 @@ #include "src/objects/instance-type.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-objects-inl.h" +#include "src/objects/js-struct.h" #include "src/objects/maybe-object.h" #include "src/objects/objects.h" #include "src/objects/slots-inl.h" @@ -87,8 +88,8 @@ #include "src/objects/string-forwarding-table-inl.h" #include "src/objects/transitions-inl.h" #include "src/objects/visitors.h" -#include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/trusted-pointer-table.h" +#include "src/sandbox/trusted-pointer-tag.h" #include "src/snapshot/shared-heap-serializer.h" #include "src/tasks/cancelable-task.h" #include "src/tracing/tracing-category-observer.h" @@ -1384,12 +1385,12 @@ class RecordMigratedSlotVisitor inline void VisitExternalPointer(Tagged<HeapObject> host, ExternalPointerSlot slot) final {} - inline void VisitIndirectPointer(Tagged<HeapObject> host, - IndirectPointerSlot slot, - IndirectPointerMode mode) final {} + inline void VisitTrustedPointer(Tagged<HeapObject> host, + TrustedPointerSlot slot, + TrustedPointerMode mode) final {} inline void VisitTrustedPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) final {} + TrustedPointerSlot slot) final {} inline void VisitProtectedPointer(Tagged<TrustedObject> host, ProtectedPointerSlot slot) final { @@ -1611,7 +1612,7 @@ class EvacuateVisitorBase : public HeapObjectVisitor { if (V8_LIKELY(dest != CODE_SPACE)) { DCHECK_VALID_REGULAR_OBJECT_SIZE(size); DCHECK(IsAligned(size, kTaggedSize)); - base->heap_->CopyBlock(dst_addr, src_addr, size); + Heap::CopyBlock(dst_addr, src_addr, object_size); if (mode != MigrationMode::kFast) { base->ExecuteMigrationObservers(dest, src, dst, size); } @@ -2539,17 +2540,7 @@ void MarkCompactCollector::RetainMaps() { MarkingHelper::WorklistTarget::kRegular, map); } } - Tagged<Object> prototype = map->prototype(); - if (age > 0 && IsHeapObject(prototype) && - MarkingHelper::IsUnmarkedAndNotAlwaysLive( - heap_, marking_state_, Cast<HeapObject>(prototype))) { - // The prototype is not marked, age the map. - new_age = age - 1; - } else { - // The prototype and the constructor are marked, this map keeps only - // transition tree alive, not JSObjects. Do not age the map. - new_age = age; - } + new_age = age > 0 ? age - 1 : 0; } else { new_age = v8_flags.retain_maps_for_n_gc; } @@ -3720,7 +3711,7 @@ void MarkCompactCollector::FlushBytecodeFromSFI( // Mark the new entry in the trusted pointer table as alive. TrustedPointerTable& table = heap_->isolate()->trusted_pointer_table(); TrustedPointerTable::Space* space = heap_->trusted_pointer_space(); - table.Mark(space, uncompiled_data->self_indirect_pointer_handle()); + table.Mark(space, uncompiled_data->self_trusted_pointer_handle()); #endif shared_info->set_uncompiled_data(uncompiled_data); @@ -3762,13 +3753,13 @@ void MarkCompactCollector::ProcessOldCodeCandidates() { bool is_unpublished = flushing_candidate->HasUnpublishedTrustedData(isolate); if (is_unpublished) { - IndirectPointerHandle handle = - flushing_candidate->Relaxed_ReadField<IndirectPointerHandle>( + TrustedPointerHandle handle = + flushing_candidate->Relaxed_ReadField<TrustedPointerHandle>( offsetof(SharedFunctionInfo, trusted_function_data_)); // Read the object from the table. It is now an UncompiledData. Address obj_addr = isolate->trusted_pointer_table().GetMaybeUnpublished( - handle, kBytecodeArrayIndirectPointerTag); + handle, kBytecodeArrayTrustedPointerTag); Tagged<TrustedObject> trusted_obj = UncheckedCast<TrustedObject>(Tagged<Object>(obj_addr)); Tagged<UncompiledData> uncompiled_data = @@ -4074,13 +4065,13 @@ void RightTrimDescriptorArray(Heap* heap, Tagged<DescriptorArray> array, array->GetDescriptorSlot(old_nof_all_descriptors).address(); MutablePage* chunk = MutablePage::FromHeapObject(heap->isolate(), array); RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, start, end, - SlotSet::FREE_EMPTY_BUCKETS); + SlotSet::KEEP_EMPTY_BUCKETS); RememberedSet<OLD_TO_NEW_BACKGROUND>::RemoveRange( - chunk, start, end, SlotSet::FREE_EMPTY_BUCKETS); + chunk, start, end, SlotSet::KEEP_EMPTY_BUCKETS); RememberedSet<OLD_TO_SHARED>::RemoveRange(chunk, start, end, - SlotSet::FREE_EMPTY_BUCKETS); + SlotSet::KEEP_EMPTY_BUCKETS); RememberedSet<OLD_TO_OLD>::RemoveRange(chunk, start, end, - SlotSet::FREE_EMPTY_BUCKETS); + SlotSet::KEEP_EMPTY_BUCKETS); const Address aligned_start = ALIGN_TO_ALLOCATION_ALIGNMENT(start); const Address aligned_end = ALIGN_TO_ALLOCATION_ALIGNMENT(end); if (aligned_start < aligned_end) { @@ -4133,6 +4124,10 @@ void MarkCompactCollector::TrimDescriptorArray( descriptors->set_number_of_descriptors(number_of_own_descriptors); if (can_trim) { RightTrimDescriptorArray(heap_, descriptors, to_trim); + } else { + MemsetTagged(descriptors->GetDescriptorSlot(number_of_own_descriptors), + ReadOnlyRoots(heap_).undefined_value(), + to_trim * DescriptorArray::kEntrySize); } TrimEnumCache(heap_, map, descriptors); descriptors->Sort(); @@ -5964,7 +5959,7 @@ void MarkCompactCollector::UpdatePointersInPointerTables() { Address content) { Tagged<ExposedTrustedObject> relocated_object = process_entry(content); if (relocated_object.is_null()) return; - DCHECK_EQ(handle, relocated_object->self_indirect_pointer_handle()); + DCHECK_EQ(handle, relocated_object->self_trusted_pointer_handle()); table.Update(handle, relocated_object.ptr()); }); }; diff --git a/deps/v8/src/heap/marking-barrier.cc b/deps/v8/src/heap/marking-barrier.cc index 9ecfabd6af22..43b856b76bcb 100644 --- a/deps/v8/src/heap/marking-barrier.cc +++ b/deps/v8/src/heap/marking-barrier.cc @@ -41,7 +41,7 @@ MarkingBarrier::MarkingBarrier(LocalHeap* local_heap) MarkingBarrier::~MarkingBarrier() { DCHECK(typed_slots_map_.empty()); } -void MarkingBarrier::Write(Tagged<HeapObject> host, IndirectPointerSlot slot) { +void MarkingBarrier::Write(Tagged<HeapObject> host, TrustedPointerSlot slot) { #ifdef V8_ENABLE_SANDBOX DCHECK(IsCurrentMarkingBarrier(host)); DCHECK(is_activated_ || shared_heap_worklists_.has_value()); diff --git a/deps/v8/src/heap/marking-barrier.h b/deps/v8/src/heap/marking-barrier.h index f67aa2d5e9d9..7d2c497d637f 100644 --- a/deps/v8/src/heap/marking-barrier.h +++ b/deps/v8/src/heap/marking-barrier.h @@ -47,7 +47,7 @@ class MarkingBarrier { template <typename TSlot, RecordYoungSlot kRecordYoung = RecordYoungSlot::kNo> void Write(Tagged<HeapObject> host, TSlot slot, Tagged<HeapObject> value); - void Write(Tagged<HeapObject> host, IndirectPointerSlot slot); + void Write(Tagged<HeapObject> host, TrustedPointerSlot slot); void Write(Tagged<InstructionStream> host, RelocInfo*, Tagged<HeapObject> value); void Write(Tagged<JSArrayBuffer> host, ArrayBufferExtension*); diff --git a/deps/v8/src/heap/marking-visitor-inl.h b/deps/v8/src/heap/marking-visitor-inl.h index 79473b3945a1..75a4eb9f93e2 100644 --- a/deps/v8/src/heap/marking-visitor-inl.h +++ b/deps/v8/src/heap/marking-visitor-inl.h @@ -32,8 +32,8 @@ #include "src/objects/string.h" #include "src/sandbox/check.h" #include "src/sandbox/external-pointer-inl.h" -#include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/js-dispatch-table-inl.h" +#include "src/sandbox/trusted-pointer-tag.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -279,7 +279,6 @@ void MarkingVisitorBase<ConcreteVisitor>::VisitExternalPointer( if (maybe_extension) { ArrayBufferExtension* extension = reinterpret_cast<ArrayBufferExtension*>(maybe_extension); - extension->InitializationBarrier(); #ifdef V8_COMPRESS_POINTERS SBXCHECK_EQ(space == heap_->young_external_pointer_space() ? ArrayBufferExtension::Age::kYoung @@ -314,11 +313,10 @@ void MarkingVisitorBase<ConcreteVisitor>::VisitCppHeapPointer( } template <typename ConcreteVisitor> -void MarkingVisitorBase<ConcreteVisitor>::VisitIndirectPointer( - Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) { +void MarkingVisitorBase<ConcreteVisitor>::VisitTrustedPointer( + Tagged<HeapObject> host, TrustedPointerSlot slot, TrustedPointerMode mode) { #ifdef V8_ENABLE_SANDBOX - if (mode == IndirectPointerMode::kStrong) { + if (mode == TrustedPointerMode::kStrong) { // Load the referenced object (if the slot is initialized) and mark it as // alive if necessary. Indirect pointers never have to be added to a // remembered set because the referenced object will update the pointer @@ -343,7 +341,7 @@ void MarkingVisitorBase<ConcreteVisitor>::VisitIndirectPointer( template <typename ConcreteVisitor> void MarkingVisitorBase<ConcreteVisitor>::VisitTrustedPointerTableEntry( - Tagged<HeapObject> host, IndirectPointerSlot slot) { + Tagged<HeapObject> host, TrustedPointerSlot slot) { concrete_visitor()->MarkPointerTableEntry(host, slot); } @@ -481,12 +479,12 @@ size_t MarkingVisitorBase<ConcreteVisitor>::VisitSharedFunctionInfo( // If the SharedFunctionInfo doesn't have old bytecode visit the function // data strongly. #ifdef V8_ENABLE_SANDBOX - VisitIndirectPointer( + VisitTrustedPointer( shared_info, - shared_info->RawIndirectPointerField( + shared_info->RawTrustedPointerField( offsetof(SharedFunctionInfo, trusted_function_data_), - SharedFunctionInfo::kTrustedDataIndirectPointerRange), - IndirectPointerMode::kStrong); + SharedFunctionInfo::kTrustedDataTrustedPointerRange), + TrustedPointerMode::kStrong); #else VisitPointer(shared_info, shared_info->RawField(offsetof( SharedFunctionInfo, trusted_function_data_))); @@ -847,15 +845,15 @@ size_t MarkingVisitorBase<ConcreteVisitor>::VisitTransitionArray( template <typename ConcreteVisitor> void FullMarkingVisitorBase<ConcreteVisitor>::MarkPointerTableEntry( - Tagged<HeapObject> host, IndirectPointerSlot slot) { + Tagged<HeapObject> host, TrustedPointerSlot slot) { #ifdef V8_ENABLE_SANDBOX - IndirectPointerTagRange tag_range = slot.tag_range(); + TrustedPointerTagRange tag_range = slot.tag_range(); - IndirectPointerHandle handle = slot.Relaxed_LoadHandle(); + TrustedPointerHandle handle = slot.Relaxed_LoadHandle(); // We must not see an uninitialized 'self' indirect pointer as we might // otherwise fail to mark the table entry as alive. - DCHECK_NE(handle, kNullIndirectPointerHandle); + DCHECK_NE(handle, kNullTrustedPointerHandle); const bool use_shared_table = IsSharedTrustedPointerType(tag_range); DCHECK_EQ(use_shared_table, HeapLayout::InWritableSharedSpace(host)); diff --git a/deps/v8/src/heap/marking-visitor.h b/deps/v8/src/heap/marking-visitor.h index ece93424e848..59f70406df58 100644 --- a/deps/v8/src/heap/marking-visitor.h +++ b/deps/v8/src/heap/marking-visitor.h @@ -143,12 +143,12 @@ class MarkingVisitorBase : public ConcurrentHeapVisitor<ConcreteVisitor> { ExternalPointerSlot slot) override; V8_INLINE void VisitCppHeapPointer(Tagged<HeapObject> host, CppHeapPointerSlot slot) override; - V8_INLINE void VisitIndirectPointer(Tagged<HeapObject> host, - IndirectPointerSlot slot, - IndirectPointerMode mode) final; + V8_INLINE void VisitTrustedPointer(Tagged<HeapObject> host, + TrustedPointerSlot slot, + TrustedPointerMode mode) final; void VisitTrustedPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) final; + TrustedPointerSlot slot) final; void VisitJSDispatchTableEntry(Tagged<HeapObject> host, JSDispatchHandle handle) override; @@ -272,7 +272,7 @@ class FullMarkingVisitorBase : public MarkingVisitorBase<ConcreteVisitor> { MarkingState* marking_state() const { return marking_state_; } - void MarkPointerTableEntry(Tagged<HeapObject> obj, IndirectPointerSlot slot); + void MarkPointerTableEntry(Tagged<HeapObject> obj, TrustedPointerSlot slot); private: MarkingState* marking_state_; diff --git a/deps/v8/src/heap/memory-measurement-inl.h b/deps/v8/src/heap/memory-measurement-inl.h index fe6fe9b5c724..3e3f2f1bb8c7 100644 --- a/deps/v8/src/heap/memory-measurement-inl.h +++ b/deps/v8/src/heap/memory-measurement-inl.h @@ -15,14 +15,26 @@ #include "src/objects/map-inl.h" #include "src/objects/map.h" +#if V8_ENABLE_WEBASSEMBLY +#include "src/wasm/wasm-objects-inl.h" +#endif // V8_ENABLE_WEBASSEMBLY + namespace v8 { namespace internal { bool NativeContextInferrer::Infer(PtrComprCageBase cage_base, Tagged<Map> map, Tagged<HeapObject> object, Address* native_context) { - Tagged<Object> maybe_native_context = - map->map()->raw_native_context_or_null(); + Tagged<Map> meta_map = map->map(); +#if V8_ENABLE_WEBASSEMBLY + if (!IsMetaMap(meta_map)) [[unlikely]] { + DCHECK(IsWasmCustomMap(map)); + *native_context = + Cast<WasmCustomMap>(map)->native_context_for_wrapper().ptr(); + return true; + } +#endif // V8_ENABLE_WEBASSEMBLY + Tagged<Object> maybe_native_context = meta_map->raw_native_context_or_null(); *native_context = maybe_native_context.ptr(); // The value might be equal to Smi::uninitialized_deserialization_value() // during NativeContext deserialization. diff --git a/deps/v8/src/heap/memory-measurement.cc b/deps/v8/src/heap/memory-measurement.cc index f110e01cc1a8..74a36096e1cc 100644 --- a/deps/v8/src/heap/memory-measurement.cc +++ b/deps/v8/src/heap/memory-measurement.cc @@ -394,7 +394,6 @@ void NativeContextStats::IncrementExternalSize(Address context, Tagged<Map> map, // buffer, detaching, or resizing a RAB). Instead, we use the atomically // updated accounting length from the extension. if (auto ext = js_array_buffer->extension()) { - ext->InitializationBarrier(); external_size = ext->accounting_length(); } } else { diff --git a/deps/v8/src/heap/memory-pool.cc b/deps/v8/src/heap/memory-pool.cc index aa8cc8050983..ac7d5f92faa7 100644 --- a/deps/v8/src/heap/memory-pool.cc +++ b/deps/v8/src/heap/memory-pool.cc @@ -182,9 +182,7 @@ size_t MemoryPool::PoolImpl<PoolEntry>::Size() const { for (const auto& entry : local_pools_) { count += entry.second.size(); } - for (const auto& entry : shared_pool_) { - count += entry.size(); - } + count += shared_pool_.size(); return count; } @@ -205,12 +203,10 @@ template <typename PoolEntry> MemoryPool::PoolReleaseStats MemoryPool::PoolImpl<PoolEntry>::ReleaseUpTo( Epoch release_epoch) { std::vector<PoolEntry> entries_to_free; - size_t freed = 0; bool pool_emptied = false; - const auto collect_entries = [&entries_to_free, &freed, + const auto collect_entries = [&entries_to_free, release_epoch](PoolEntry& entry) { if (entry.epoch() <= release_epoch) { - freed += entry.size(); entries_to_free.push_back(std::move(entry)); return true; } @@ -234,7 +230,7 @@ MemoryPool::PoolReleaseStats MemoryPool::PoolImpl<PoolEntry>::ReleaseUpTo( } } // Entries will be freed automatically here. - return {freed, pool_emptied}; + return {entries_to_free.size(), pool_emptied}; } bool MemoryPool::LargePagePoolImpl::Add(std::vector<LargePage*>& pages, @@ -301,7 +297,6 @@ MemoryPool::PoolReleaseStats MemoryPool::LargePagePoolImpl::ReleaseUpTo( Epoch release_epoch) { std::vector<PooledPage> entries_to_free; bool pool_emptied = false; - size_t freed = 0; { base::MutexGuard guard(&mutex_); std::erase_if(pages_, [this, &entries_to_free, release_epoch](auto& entry) { @@ -319,7 +314,7 @@ MemoryPool::PoolReleaseStats MemoryPool::LargePagePoolImpl::ReleaseUpTo( DCHECK_EQ(total_size_, ComputeTotalSize()); } // Entries will be freed automatically here. - return {freed, pool_emptied}; + return {entries_to_free.size(), pool_emptied}; } size_t MemoryPool::LargePagePoolImpl::ComputeTotalSize() const { @@ -339,8 +334,9 @@ PooledPage MemoryPool::CreatePooledPage(NormalPage* metadata) { current_epoch_.load(std::memory_order_relaxed)); } -MemoryPool::MemoryPool(Config config) - : config_(config), +MemoryPool::MemoryPool(IsolateGroup* isolate_group, Config config) + : isolate_group_(isolate_group), + config_(config), page_pool_(config), zone_pool_(config), large_pool_(config), @@ -471,12 +467,11 @@ class MemoryPool::ReleasePooledChunksTask final : public CancelableTask { if (config_.trace_gc_nvp) { // Run printing on *some* isolate. The isolate_ field may be destroyed - // it's only used for posting a task on the single threaded configuration. - IsolateGroup::current()->FindAnotherIsolateLocked( + pool_->isolate_group_->FindAnotherIsolateLocked( nullptr, [&stats](Isolate* isolate) { isolate->PrintWithTimestamp( - "Memory pool: Removed pages: %zu, removed large pages: %zu\n, " - "removed " - "zone reservations: %zu\n", + "Memory pool: Removed pages: %zu, removed large pages: %zu, " + "removed zone reservations: %zu\n", stats.pages_removed, stats.large_pages_removed, stats.zone_reservations_removed); }); diff --git a/deps/v8/src/heap/memory-pool.h b/deps/v8/src/heap/memory-pool.h index 89a460915060..1a2f40d9cb72 100644 --- a/deps/v8/src/heap/memory-pool.h +++ b/deps/v8/src/heap/memory-pool.h @@ -14,6 +14,7 @@ namespace v8::internal { class CancelableTaskManager; class Isolate; +class IsolateGroup; class LargePage; class BasePage; class MutablePage; @@ -86,7 +87,7 @@ class MemoryPool final { size_t timeout_in_sec = 8; }; - explicit MemoryPool(Config); + MemoryPool(IsolateGroup*, Config); ~MemoryPool(); MemoryPool(const MemoryPool&) = delete; @@ -235,6 +236,7 @@ class MemoryPool final { void PostDelayedReleaseTask(Isolate* isolate, base::TimeDelta delay); void PostDelayedReleaseTaskIfNeeded(Isolate* isolate); + IsolateGroup* const isolate_group_; const Config config_; std::atomic<bool> task_disabled_ = false; diff --git a/deps/v8/src/heap/memory-reducer.cc b/deps/v8/src/heap/memory-reducer.cc index 64d1023569b2..9d4308aefbe7 100644 --- a/deps/v8/src/heap/memory-reducer.cc +++ b/deps/v8/src/heap/memory-reducer.cc @@ -6,6 +6,7 @@ #include "src/flags/flags.h" #include "src/heap/gc-tracer.h" +#include "src/heap/heap-controller.h" #include "src/heap/heap-inl.h" #include "src/heap/incremental-marking.h" #include "src/heap/local-heap-inl.h" @@ -15,32 +16,43 @@ namespace v8 { namespace internal { +namespace { +size_t GetCommitedSize(Heap* heap) { + return heap->CommittedOldGenerationMemory() + heap->EmbedderSizeOfObjects() + + heap->external_memory(); +} +} // namespace + +MemoryReducerBase::MemoryReducerBase(Heap* heap) + : heap_(heap), + task_runner_(heap->GetForegroundTaskRunner(TaskPriority::kUserVisible)) { + DCHECK(v8_flags.incremental_marking); + DCHECK(v8_flags.memory_reducer); +} + +std::unique_ptr<MemoryReducerBase> MemoryReducerBase::Create(Heap* heap) { + if (v8_flags.memory_reducer_limit_based) { + return std::make_unique<LimitBasedMemoryReducer>(heap); + } else { + return std::make_unique<MemoryReducer>(heap); + } +} + const int MemoryReducer::kShortDelayMs = 500; const int MemoryReducer::kWatchdogDelayMs = 100000; const double MemoryReducer::kCommittedMemoryFactor = 1.1; const size_t MemoryReducer::kCommittedMemoryDelta = 10 * MB; MemoryReducer::MemoryReducer(Heap* heap) - : heap_(heap), - taskrunner_(heap->GetForegroundTaskRunner(TaskPriority::kUserVisible)), + : MemoryReducerBase(heap), state_(State::CreateUninitialized()), js_calls_counter_(0), - js_calls_sample_time_ms_(0.0) { - DCHECK(v8_flags.incremental_marking); - DCHECK(v8_flags.memory_reducer); -} + js_calls_sample_time_ms_(0.0) {} MemoryReducer::TimerTask::TimerTask(MemoryReducer* memory_reducer) : CancelableTask(memory_reducer->heap()->isolate()), memory_reducer_(memory_reducer) {} -namespace { -size_t GetCommitedSize(Heap* heap) { - return heap->CommittedOldGenerationMemory() + heap->EmbedderSizeOfObjects() + - heap->external_memory(); -} -} // namespace - void MemoryReducer::TimerTask::RunInternal() { Heap* heap = memory_reducer_->heap(); // Set the current isolate such that trusted pointer tables etc are @@ -77,7 +89,6 @@ void MemoryReducer::TimerTask::RunInternal() { memory_reducer_->NotifyTimer(event); } - void MemoryReducer::NotifyTimer(const Event& event) { if (state_.id() != kWait) return; DCHECK_EQ(kTimer, event.type); @@ -152,8 +163,8 @@ bool MemoryReducer::WatchdogGC(const State& state, const Event& event) { event.time_ms > state.last_gc_time_ms() + kWatchdogDelayMs; } - -// For specification of this function see the comment for MemoryReducer class. +// For specification of this function see the comment for MemoryReducer +// class. MemoryReducer::State MemoryReducer::Step(const State& state, const Event& event) { DCHECK(v8_flags.memory_reducer); @@ -234,17 +245,98 @@ void MemoryReducer::ScheduleTimer(double delay_ms) { if (heap()->IsTearingDown()) return; // Leave some room for precision error in task scheduler. const double kSlackMs = 100; - taskrunner_->PostDelayedTask(std::make_unique<MemoryReducer::TimerTask>(this), - (delay_ms + kSlackMs) / 1000.0); + task_runner_->PostDelayedTask( + std::make_unique<MemoryReducer::TimerTask>(this), + (delay_ms + kSlackMs) / 1000.0); } -void MemoryReducer::TearDown() { state_ = State::CreateUninitialized(); } - // static int MemoryReducer::MaxNumberOfGCs() { - DCHECK_GT(v8_flags.memory_reducer_gc_count, 0); + DCHECK_GT(v8_flags.memory_reducer_gc_count, 0u); return v8_flags.memory_reducer_gc_count; } +LimitBasedMemoryReducer::LimitBasedMemoryReducer(Heap* heap) + : MemoryReducerBase(heap) {} + +void LimitBasedMemoryReducer::NotifyMarkCompact( + size_t committed_memory_before) { + ScheduleTimer( + base::TimeDelta::FromMilliseconds(v8_flags.memory_reducer_delay_ms)); +} + +void LimitBasedMemoryReducer::NotifyPossibleGarbage() { + if (!desired_run_time_.has_value()) { + ScheduleTimer( + base::TimeDelta::FromMilliseconds(v8_flags.memory_reducer_delay_ms)); + } +} + +bool LimitBasedMemoryReducer::ShouldGrowHeapSlowly() { return false; } + +void LimitBasedMemoryReducer::ScheduleTimer(base::TimeDelta delay) { + DCHECK_LE(base::TimeDelta(), delay); + if (heap_->IsTearingDown()) return; + + if (!desired_run_time_.has_value()) { + task_runner_->PostDelayedTask( + std::make_unique<LimitBasedMemoryReducer::TimerTask>(this), + delay.InSecondsF()); + } + desired_run_time_ = base::TimeTicks::Now() + delay; +} + +LimitBasedMemoryReducer::TimerTask::TimerTask( + LimitBasedMemoryReducer* memory_reducer) + : CancelableTask(memory_reducer->heap()->isolate()), + memory_reducer_(memory_reducer) {} + +void LimitBasedMemoryReducer::TimerTask::RunInternal() { + const base::TimeTicks desired_run_time = *memory_reducer_->desired_run_time_; + memory_reducer_->desired_run_time_.reset(); + auto now = base::TimeTicks::Now(); + if (now < desired_run_time) { + // A GC since the task was posted may have pushed `desired_run_time_` + // forward without posting a new task. Reschedule for the remaining delay. + memory_reducer_->ScheduleTimer(desired_run_time - now); + return; + } + auto heap = memory_reducer_->heap(); + SetCurrentIsolateScope isolate_scope(heap->isolate()); + SetCurrentLocalHeapScope thread_local_scope(heap->isolate()); + + heap->allocator()->new_space_allocator()->FreeLinearAllocationArea(); + heap->tracer()->SampleAllocation(now, heap->NewSpaceAllocationCounter(), + heap->OldGenerationAllocationCounter(), + heap->EmbedderAllocationCounter(), + heap->ExternalAllocationCounter()); + if (!heap->incremental_marking()->CanAndShouldBeStarted() || + heap->incremental_marking()->IsMinorMarking()) { + memory_reducer_->NotifyPossibleGarbage(); + return; + } + if (heap->incremental_marking()->IsMarking()) { + // The task will be rescheduled when the GC is finalized through + // NotifyMarkCompact(). + return; + } + if (heap->limits()->using_initial_limit()) { + if (!heap->incremental_marking()->IsBelowActivationThresholds()) { + heap->StartIncrementalMarking(GCFlag::kReduceMemoryFootprint, + GarbageCollectionReason::kMemoryReducer, + kGCCallbackFlagCollectAllExternalMemory); + } + } else { + heap->limits()->UpdateAllocationLimits( + heap->CurrentHeapGrowingMode(), heap->limits()->AtMostCurrentLimits(), + "MemoryReducer"); + GCFlags gc_flags = GCFlag::kReduceMemoryFootprint; + heap->StartIncrementalMarkingIfAllocationLimitIsReached( + heap->main_thread_local_heap(), gc_flags, + kGCCallbackFlagCollectAllExternalMemory, + GarbageCollectionReason::kMemoryReducer); + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/heap/memory-reducer.h b/deps/v8/src/heap/memory-reducer.h index 3573e222c5bd..cad98d6f84cd 100644 --- a/deps/v8/src/heap/memory-reducer.h +++ b/deps/v8/src/heap/memory-reducer.h @@ -5,24 +5,39 @@ #ifndef V8_HEAP_MEMORY_REDUCER_H_ #define V8_HEAP_MEMORY_REDUCER_H_ +#include <optional> + #include "include/v8-platform.h" #include "src/base/macros.h" +#include "src/base/platform/time.h" #include "src/common/globals.h" #include "src/tasks/cancelable-task.h" namespace v8 { namespace internal { -namespace heap { -class HeapTester; -} // namespace heap - class Heap; +class V8_EXPORT_PRIVATE MemoryReducerBase { + public: + virtual ~MemoryReducerBase() = default; + static std::unique_ptr<MemoryReducerBase> Create(Heap* heap); + virtual void NotifyMarkCompact(size_t committed_memory_before) = 0; + virtual void NotifyPossibleGarbage() = 0; + virtual bool ShouldGrowHeapSlowly() = 0; + + protected: + explicit MemoryReducerBase(Heap* heap); -// The goal of the MemoryReducer class is to detect transition of the mutator -// from high allocation phase to low allocation phase and to collect potential -// garbage created in the high allocation phase. + Heap* heap() { return heap_; } + + Heap* heap_; + std::shared_ptr<v8::TaskRunner> task_runner_; +}; + +// The goal of the MemoryReducer class is to detect transition of the +// mutator from high allocation phase to low allocation phase and to collect +// potential garbage created in the high allocation phase. // // The class implements an automaton with the following states and transitions. // @@ -31,19 +46,20 @@ class Heap; // - WAIT <started_gcs> <next_gc_start_ms> <last_gc_time_ms> // - RUN <started_gcs> <last_gc_time_ms> // The <started_gcs> is an integer in range from 0..kMaxNumberOfGCs that stores -// the number of GCs initiated by the MemoryReducer since it left the DONE -// state. -// The <next_gc_start_ms> is a double that stores the earliest time the next GC -// can be initiated by the MemoryReducer. +// the number of GCs initiated by the MemoryReducer since it left the +// DONE state. +// The <next_gc_start_ms> is a double that stores the earliest time +// the next GC can be initiated by the MemoryReducer. // The <last_gc_start_ms> is a double that stores the time of the last full GC. // The DONE state means that the MemoryReducer is not active. -// The WAIT state means that the MemoryReducer is waiting for mutator allocation -// rate to drop. The check for the allocation rate happens in the timer task -// callback. If the allocation rate does not drop in watchdog_delay_ms since -// the last GC then transition to the RUN state is forced. -// The RUN state means that the MemoryReducer started incremental marking and is -// waiting for it to finish. Incremental marking steps are performed as usual -// in the idle notification and in the mutator. +// The WAIT state means that the MemoryReducer is waiting for mutator +// allocation rate to drop. The check for the allocation rate happens in the +// timer task callback. If the allocation rate does not drop in +// watchdog_delay_ms since the last GC then transition to the RUN state is +// forced. +// The RUN state means that the MemoryReducer started incremental +// marking and is waiting for it to finish. Incremental marking steps are +// performed as usual in the idle notification and in the mutator. // // Transitions: // DONE t -> WAIT 0 (now_ms + long_delay_ms) t' happens: @@ -59,8 +75,8 @@ class Heap; // WAIT n x t -> WAIT (n+1) t happens: // - on background idle notification, which signals that we can start // incremental marking even if the allocation rate is high. -// The MemoryReducer starts incremental marking on this transition but still -// has a pending timer task. +// The MemoryReducer starts incremental marking on this transition but +// still has a pending timer task. // // WAIT n x t -> DONE t happens: // - in the timer callback if n >= kMaxNumberOfGCs. @@ -84,7 +100,7 @@ class Heap; // now_ms is the current time, // t' is t if the current event is not a GC event and is now_ms otherwise, // long_delay_ms, short_delay_ms, and watchdog_delay_ms are constants. -class V8_EXPORT_PRIVATE MemoryReducer { +class V8_EXPORT_PRIVATE MemoryReducer final : public MemoryReducerBase { public: enum Id { kUninit, kDone, kWait, kRun }; @@ -158,14 +174,13 @@ class V8_EXPORT_PRIVATE MemoryReducer { MemoryReducer(const MemoryReducer&) = delete; MemoryReducer& operator=(const MemoryReducer&) = delete; // Callbacks. - void NotifyMarkCompact(size_t committed_memory_before); - void NotifyPossibleGarbage(); + void NotifyMarkCompact(size_t committed_memory_before) override; + void NotifyPossibleGarbage() override; // The step function that computes the next state from the current state and // the incoming event. static State Step(const State& state, const Event& event); // Posts a timer task that will call NotifyTimer after the given delay. void ScheduleTimer(double delay_ms); - void TearDown(); static const int kShortDelayMs; static const int kWatchdogDelayMs; // The committed memory has to increase by at least this factor since the @@ -175,9 +190,7 @@ class V8_EXPORT_PRIVATE MemoryReducer { // last run in order to trigger a new run after mark-compact. static const size_t kCommittedMemoryDelta; - Heap* heap() { return heap_; } - - bool ShouldGrowHeapSlowly() { return state_.id() == kDone; } + bool ShouldGrowHeapSlowly() override { return state_.id() == kDone; } static int MaxNumberOfGCs(); @@ -198,15 +211,37 @@ class V8_EXPORT_PRIVATE MemoryReducer { static bool WatchdogGC(const State& state, const Event& event); - Heap* heap_; - std::shared_ptr<v8::TaskRunner> taskrunner_; State state_; unsigned int js_calls_counter_; double js_calls_sample_time_ms_; int start_delay_ms_ = false; - // Used in cctest. - friend class heap::HeapTester; + // Used in tests. + friend class HeapInternalsBase; +}; + +class V8_EXPORT_PRIVATE LimitBasedMemoryReducer final + : public MemoryReducerBase { + public: + explicit LimitBasedMemoryReducer(Heap* heap); + void NotifyMarkCompact(size_t committed_memory_before) override; + void NotifyPossibleGarbage() override; + bool ShouldGrowHeapSlowly() override; + + bool is_scheduled() const { return desired_run_time_.has_value(); } + + private: + void ScheduleTimer(base::TimeDelta delay); + class TimerTask : public v8::internal::CancelableTask { + public: + TimerTask(LimitBasedMemoryReducer* memory_reducer); + void RunInternal() override; + + private: + LimitBasedMemoryReducer* memory_reducer_; + }; + + std::optional<base::TimeTicks> desired_run_time_; }; } // namespace internal diff --git a/deps/v8/src/heap/mutable-page.cc b/deps/v8/src/heap/mutable-page.cc index a63309718daa..f42fc18d54fc 100644 --- a/deps/v8/src/heap/mutable-page.cc +++ b/deps/v8/src/heap/mutable-page.cc @@ -261,9 +261,7 @@ int MutablePage::ComputeFreeListsLength() { int length = 0; for (int cat = kFirstCategory; cat <= owner()->free_list()->last_category(); cat++) { - if (categories_[cat] != nullptr) { - length += categories_[cat]->FreeListLength(); - } + length += categories_[cat].FreeListLength(); } return length; } diff --git a/deps/v8/src/heap/mutable-page.h b/deps/v8/src/heap/mutable-page.h index f1018aa5b045..b528085471ce 100644 --- a/deps/v8/src/heap/mutable-page.h +++ b/deps/v8/src/heap/mutable-page.h @@ -311,7 +311,7 @@ class MutablePage : public BasePage { heap::ListNode<MutablePage> list_node_; - FreeListCategory** categories_ = nullptr; + FreeListCategory* categories_ = nullptr; PossiblyEmptyBuckets possibly_empty_buckets_; diff --git a/deps/v8/src/heap/normal-page-inl.h b/deps/v8/src/heap/normal-page-inl.h index 74ccb2a1683f..670cce82e3ad 100644 --- a/deps/v8/src/heap/normal-page-inl.h +++ b/deps/v8/src/heap/normal-page-inl.h @@ -38,7 +38,7 @@ template <typename Callback> void NormalPage::ForAllFreeListCategories(Callback callback) { for (int i = kFirstCategory; i < owner()->free_list()->number_of_categories(); i++) { - callback(categories_[i]); + callback(&categories_[i]); } } diff --git a/deps/v8/src/heap/normal-page.cc b/deps/v8/src/heap/normal-page.cc index 67bfaf9c3724..59ea5b021f89 100644 --- a/deps/v8/src/heap/normal-page.cc +++ b/deps/v8/src/heap/normal-page.cc @@ -28,33 +28,19 @@ NormalPage::NormalPage(Heap* heap, BaseSpace* space, size_t size, void NormalPage::AllocateFreeListCategories() { DCHECK_NULL(categories_); categories_ = - new FreeListCategory*[owner()->free_list()->number_of_categories()](); - for (int i = kFirstCategory; i <= owner()->free_list()->last_category(); - i++) { - DCHECK_NULL(categories_[i]); - categories_[i] = new FreeListCategory(); - } + new FreeListCategory[owner()->free_list()->number_of_categories()]; } void NormalPage::InitializeFreeListCategories() { for (int i = kFirstCategory; i <= owner()->free_list()->last_category(); i++) { - categories_[i]->Initialize(static_cast<FreeListCategoryType>(i)); + categories_[i].Initialize(static_cast<FreeListCategoryType>(i)); } } void NormalPage::ReleaseFreeListCategories() { - if (categories_ != nullptr) { - for (int i = kFirstCategory; i <= owner()->free_list()->last_category(); - i++) { - if (categories_[i] != nullptr) { - delete categories_[i]; - categories_[i] = nullptr; - } - } - delete[] categories_; - categories_ = nullptr; - } + delete[] categories_; + categories_ = nullptr; } NormalPage* NormalPage::ConvertNewToOld(NormalPage* old_page, diff --git a/deps/v8/src/heap/normal-page.h b/deps/v8/src/heap/normal-page.h index 50b6daf60740..b82f98dd9238 100644 --- a/deps/v8/src/heap/normal-page.h +++ b/deps/v8/src/heap/normal-page.h @@ -83,7 +83,7 @@ class NormalPage final : public MutablePage { } FreeListCategory* free_list_category(FreeListCategoryType type) { - return categories_[type]; + return &categories_[type]; } V8_EXPORT_PRIVATE void CreateBlackArea(Address start, Address end); diff --git a/deps/v8/src/heap/object-stats.cc b/deps/v8/src/heap/object-stats.cc index 7a4e6a125408..e4404a33e7e0 100644 --- a/deps/v8/src/heap/object-stats.cc +++ b/deps/v8/src/heap/object-stats.cc @@ -879,15 +879,17 @@ void ObjectStatsCollectorImpl::CollectStatistics( DisallowGarbageCollection no_gc; Tagged<Map> map = obj->map(); InstanceType instance_type = map->instance_type(); + SBXCHECK_IMPLIES(InstanceTypeChecker::IsTrustedObject(instance_type), + OutsideSandboxOrInReadonlySpace(obj)); switch (phase) { case kPhase1: if (InstanceTypeChecker::IsFeedbackVector(instance_type)) { RecordVirtualFeedbackVectorDetails(Cast<FeedbackVector>(obj)); } else if (InstanceTypeChecker::IsMap(instance_type)) { RecordVirtualMapDetails(Cast<Map>(obj)); - } else if (Is<BytecodeArray>(obj)) { + } else if (InstanceTypeChecker::IsBytecodeArray(instance_type)) { RecordVirtualBytecodeArrayDetails(TrustedCast<BytecodeArray>(obj)); - } else if (Is<InstructionStream>(obj)) { + } else if (InstanceTypeChecker::IsInstructionStream(instance_type)) { RecordVirtualCodeDetails(TrustedCast<InstructionStream>(obj)); } else if (InstanceTypeChecker::IsFunctionTemplateInfo(instance_type)) { RecordVirtualFunctionTemplateInfoDetails( @@ -1029,7 +1031,7 @@ void ObjectStatsCollectorImpl::RecordVirtualMapDetails(Tagged<Map> map) { if (Tagged<DescriptorArray> array; map->owns_descriptors() && #if V8_ENABLE_WEBASSEMBLY - !IsWasmObjectMap(map) && + !IsAnyWasmObjectMap(map) && #endif // V8_ENABLE_WEBASSEMBLY (array = map->instance_descriptors()) != ReadOnlyRoots(heap_).empty_descriptor_array()) { diff --git a/deps/v8/src/heap/read-only-heap.cc b/deps/v8/src/heap/read-only-heap.cc index 73ec378499eb..71c9dadb7c29 100644 --- a/deps/v8/src/heap/read-only-heap.cc +++ b/deps/v8/src/heap/read-only-heap.cc @@ -5,8 +5,8 @@ #include "src/heap/read-only-heap.h" #include <cstddef> -#include <cstring> +#include "src/base/memcopy.h" #include "src/common/globals.h" #include "src/common/ptr-compr-inl.h" #include "src/heap/base-page.h" @@ -53,6 +53,7 @@ void ReadOnlyHeap::SetUp(Isolate* isolate, CreateInitialHeapForBootstrapping(isolate, artifacts); artifacts->read_only_heap()->DeserializeIntoIsolate( isolate, read_only_snapshot_data, can_rehash); + artifacts->read_only_heap()->DecommitGuardRegions(isolate); artifacts->set_initial_next_unique_sfi_id(isolate->next_unique_sfi_id()); read_only_heap_created = true; } else { @@ -65,7 +66,7 @@ void ReadOnlyHeap::SetUp(Isolate* isolate, isolate->trusted_pointer_table().SetUpFromReadOnlyArtifacts( isolate->heap()->read_only_trusted_pointer_space(), artifacts); #endif // V8_ENABLE_SANDBOX - artifacts->read_only_heap()->InitializeIsolateRoots(isolate); + artifacts->read_only_heap()->InitializeIsolateRootsAndBuiltins(isolate); } artifacts->VerifyChecksum(read_only_snapshot_data, read_only_heap_created); } else { @@ -104,6 +105,34 @@ void ReadOnlyHeap::DeserializeIntoIsolate(Isolate* isolate, } } +void ReadOnlyHeap::DecommitGuardRegions(Isolate* isolate) { +#ifdef V8_ENABLE_WEBASSEMBLY +#if V8_STATIC_ROOTS_BOOL + // Protect wasm null. + if (!isolate->page_allocator()->DecommitPages( + reinterpret_cast<void*>(isolate->factory()->wasm_null()->address()), + WasmNull::kSize)) { + V8::FatalProcessOutOfMemory(isolate, "decommitting WasmNull payload"); + } +#endif // V8_STATIC_ROOTS_BOOL +#endif // V8_ENABLE_WEBASSEMBLY + + if (v8_flags.unmap_holes) { +// Protect the payload of each hole. +#define UNMAP_HOLE(CamelName, snake_name, _) \ + if (!isolate->page_allocator()->DecommitPages( \ + reinterpret_cast<void*>( \ + &isolate->factory()->snake_name()->payload_), \ + Hole::kPayloadSize)) { \ + V8::FatalProcessOutOfMemory(isolate, \ + "decommitting " #CamelName " payload"); \ + } + + HOLE_LIST(UNMAP_HOLE) +#undef UNMAP_HOLE + } +} + void ReadOnlyHeap::OnCreateRootsComplete(Isolate* isolate) { DCHECK_NOT_NULL(isolate); DCHECK(!roots_init_complete_); @@ -145,22 +174,34 @@ void ReadOnlyHeap::CreateInitialHeapForBootstrapping( isolate->SetUpFromReadOnlyArtifacts(artifacts); } -void ReadOnlyHeap::InitializeIsolateRoots(Isolate* isolate) { +void ReadOnlyHeap::InitializeIsolateRootsAndBuiltins(Isolate* isolate) { void* const isolate_ro_roots = isolate->roots_table().read_only_roots_begin().location(); - std::memcpy(isolate_ro_roots, read_only_roots_, - kEntriesCount * sizeof(Address)); + base::MemCopy(isolate_ro_roots, read_only_roots_, + kEntriesCount * sizeof(Address)); + if (Builtins::kCodeObjectsAreInROSpace) { + base::MemCopy(isolate->builtin_table(), read_only_builtins_, + Builtins::kBuiltinCount * sizeof(Address)); + isolate->builtins()->MarkInitialized(); + } } void ReadOnlyHeap::InitializeFromIsolateRoots(Isolate* isolate) { void* const isolate_ro_roots = isolate->roots_table().read_only_roots_begin().location(); - std::memcpy(read_only_roots_, isolate_ro_roots, - kEntriesCount * sizeof(Address)); + base::MemCopy(read_only_roots_, isolate_ro_roots, + kEntriesCount * sizeof(Address)); } void ReadOnlyHeap::InitFromIsolate(Isolate* isolate) { DCHECK(roots_init_complete_); + if (Builtins::kCodeObjectsAreInROSpace) { + // Builtins are copied here rather than in InitializeFromIsolateRoots + // because in mksnapshot they are compiled and promoted to RO space after + // OnCreateRootsComplete. + base::MemCopy(read_only_builtins_, isolate->builtin_table(), + Builtins::kBuiltinCount * sizeof(Address)); + } read_only_space_->ShrinkPages(); #if V8_ENABLE_WEBASSEMBLY && V8_STATIC_ROOTS_BOOL diff --git a/deps/v8/src/heap/read-only-heap.h b/deps/v8/src/heap/read-only-heap.h index 329d0abeecb4..3b67d35805fb 100644 --- a/deps/v8/src/heap/read-only-heap.h +++ b/deps/v8/src/heap/read-only-heap.h @@ -10,6 +10,7 @@ #include <vector> #include "src/base/macros.h" +#include "src/builtins/builtins.h" #include "src/objects/heap-object.h" #include "src/objects/objects.h" #include "src/roots/roots.h" @@ -78,11 +79,16 @@ class ReadOnlyHeap final { ReadOnlySpace* read_only_space() const { return read_only_space_; } - void InitializeIsolateRoots(Isolate* isolate); + void InitializeIsolateRootsAndBuiltins(Isolate* isolate); void InitializeFromIsolateRoots(Isolate* isolate); bool roots_init_complete() const { return roots_init_complete_; } + // Decommits the payloads of WasmNull and the holes so that any access to + // them faults. The pages are shared by all isolates of the group, so this + // only needs to happen once per read-only heap. + void DecommitGuardRegions(Isolate* isolate); + protected: friend class ReadOnlyArtifacts; @@ -111,6 +117,7 @@ class ReadOnlyHeap final { private: friend ReadOnlyRoots GetReadOnlyRoots(); Address read_only_roots_[kEntriesCount]; + Address read_only_builtins_[Builtins::kBuiltinCount]; }; enum class SkipFreeSpaceOrFiller { diff --git a/deps/v8/src/heap/read-only-promotion.cc b/deps/v8/src/heap/read-only-promotion.cc index 35164f892ce2..4cdf28a9efd5 100644 --- a/deps/v8/src/heap/read-only-promotion.cc +++ b/deps/v8/src/heap/read-only-promotion.cc @@ -227,11 +227,15 @@ class Committee final { Isolate* isolate, Tagged<HeapObject> o) { const InstanceType itype = o->map()->instance_type(); -#define V(TYPE) \ - if (InstanceTypeChecker::Is##TYPE(itype)) { \ - return GetPromoRecommendation##TYPE(committee, isolate, \ - TrustedCast<TYPE>(o)); \ - /* NOLINTNEXTLINE(readability/braces) */ \ +#define V(TYPE) \ + if (InstanceTypeChecker::Is##TYPE(itype)) { \ + if constexpr (is_subtype_v<TYPE, TrustedObject>) { \ + return GetPromoRecommendation##TYPE(committee, isolate, \ + TrustedCast<TYPE>(o)); \ + } else { \ + return GetPromoRecommendation##TYPE(committee, isolate, Cast<TYPE>(o)); \ + } \ + /* NOLINTNEXTLINE(readability/braces) */ \ } else PROMO_CANDIDATE_TYPE_LIST(V) /* if { ... } else */ { @@ -370,11 +374,11 @@ class Committee final { VisitPointers(host, slot, slot + 1); } #ifdef V8_ENABLE_SANDBOX - void VisitIndirectPointer(Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) final { + void VisitTrustedPointer(Tagged<HeapObject> host, TrustedPointerSlot slot, + TrustedPointerMode mode) final { if (!all_slots_are_promo_candidates()) return; - IndirectPointerHandle handle = slot.Relaxed_LoadHandle(); - if (handle == kNullIndirectPointerHandle) return; + TrustedPointerHandle handle = slot.Relaxed_LoadHandle(); + if (handle == kNullTrustedPointerHandle) return; Isolate* isolate = committee_->isolate_; TrustedPointerTable* tpt = @@ -458,9 +462,9 @@ class ReadOnlyPromotionImpl final : public AllStatic { HeapObjectMap* moves) { ReadOnlySpace* rospace = isolate->heap()->read_only_space(); for (Tagged<HeapObject> src : promotees) { - const int size = src->Size(); + const SafeHeapObjectSize size = src->SafeSize(); Tagged<HeapObject> dst = - rospace->AllocateRaw(size, kTaggedAligned).ToObjectChecked(); + rospace->AllocateRaw(size.value(), kTaggedAligned).ToObjectChecked(); Heap::CopyBlock(dst.address(), src.address(), size); moves->emplace(src, dst); @@ -633,14 +637,14 @@ class ReadOnlyPromotionImpl final : public AllStatic { } #endif // V8_ENABLE_SANDBOX } - void VisitIndirectPointer(Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) final { + void VisitTrustedPointer(Tagged<HeapObject> host, TrustedPointerSlot slot, + TrustedPointerMode mode) final { #ifdef V8_ENABLE_SANDBOX VisitCodePointer(host, slot); #endif // V8_ENABLE_SANDBOX } void VisitTrustedPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) final { + TrustedPointerSlot slot) final { #ifdef V8_ENABLE_SANDBOX VisitCodePointer(host, slot); #endif // V8_ENABLE_SANDBOX @@ -662,7 +666,7 @@ class ReadOnlyPromotionImpl final : public AllStatic { void ZapOldCodePointerTableEntries() { TrustedPointerTable* tpt = &IsolateForSandbox(isolate_).GetTrustedPointerTableFor( - kCodeIndirectPointerTag); + kCodeTrustedPointerTag); for (auto [old_handle, _new_handle] : code_pointer_moves_) { tpt->Zap(old_handle); } @@ -686,21 +690,23 @@ class ReadOnlyPromotionImpl final : public AllStatic { } } void ProcessSlot(Tagged<HeapObject> host, MaybeObjectSlot slot) { + Tagged<MaybeObject> old_value = slot.load(isolate_); Tagged<HeapObject> old_slot_value; - if (!slot.load(isolate_).GetHeapObject(&old_slot_value)) return; + if (!old_value.GetHeapObject(&old_slot_value)) return; auto it = moves_->find(old_slot_value); if (it == moves_->end()) return; Tagged<HeapObject> new_slot_value = it->second; - slot.store(new_slot_value); + slot.store(old_value.IsWeak() ? MakeWeak(new_slot_value) + : Tagged<MaybeObject>(new_slot_value)); if (V8_UNLIKELY(v8_flags.trace_read_only_promotion_verbose)) { LogUpdatedPointer(host, slot, old_slot_value, new_slot_value); } } #ifdef V8_ENABLE_SANDBOX - void VisitCodePointer(Tagged<HeapObject> host, IndirectPointerSlot slot) { - IndirectPointerHandle old_handle = slot.Relaxed_LoadHandle(); - if (old_handle == kNullIndirectPointerHandle) return; + void VisitCodePointer(Tagged<HeapObject> host, TrustedPointerSlot slot) { + TrustedPointerHandle old_handle = slot.Relaxed_LoadHandle(); + if (old_handle == kNullTrustedPointerHandle) return; TrustedPointerTable* tpt = &IsolateForSandbox(isolate_).GetTrustedPointerTableFor( @@ -715,7 +721,7 @@ class ReadOnlyPromotionImpl final : public AllStatic { TrustedCast<ExposedTrustedObject>(it->second); auto it2 = promoted_code_to_handle_.find(promoted_obj.address()); if (it2 != promoted_code_to_handle_.end()) { - IndirectPointerHandle new_handle = it2->second; + TrustedPointerHandle new_handle = it2->second; RecordProcessedSlotIfDebug(slot.address()); slot.Relaxed_StoreHandle(new_handle); if (v8_flags.trace_read_only_promotion_verbose) [[unlikely]] { @@ -724,9 +730,9 @@ class ReadOnlyPromotionImpl final : public AllStatic { return; } } else if (HeapLayout::InReadOnlySpace(old_obj)) { - IndirectPointerHandle new_handle = + TrustedPointerHandle new_handle = TrustedCast<ExposedTrustedObject>(old_obj) - ->self_indirect_pointer_handle(); + ->self_trusted_pointer_handle(); slot.Relaxed_StoreHandle(new_handle); if (v8_flags.trace_read_only_promotion_verbose) [[unlikely]] { LogUpdatedCodePointerTableEntry(host, slot, old_handle, new_handle); @@ -742,14 +748,14 @@ class ReadOnlyPromotionImpl final : public AllStatic { InstanceType instance_type = obj->map()->instance_type(); SharedFlag shared = SharedFlag(HeapLayout::InAnySharedSpace(obj)); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, shared); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, shared); - IndirectPointerSlot slot = obj->RawIndirectPointerField( - offsetof(ExposedTrustedObject, self_indirect_pointer_), tag); + TrustedPointerSlot slot = obj->RawTrustedPointerField( + offsetof(ExposedTrustedObject, self_trusted_pointer_), tag); - IndirectPointerHandle old_handle = slot.Relaxed_LoadHandle(); - if (old_handle == kNullIndirectPointerHandle) return; + TrustedPointerHandle old_handle = slot.Relaxed_LoadHandle(); + if (old_handle == kNullTrustedPointerHandle) return; TrustedPointerTable* tpt = &IsolateForSandbox(isolate_).GetTrustedPointerTableFor(tag); @@ -764,7 +770,7 @@ class ReadOnlyPromotionImpl final : public AllStatic { DisallowJavascriptExecution no_js(isolate_); TrustedPointerPublishingScope scope(isolate_, no_js); SegmentedTableBase::UnsealReadOnlySegmentScope unseal_scope(tpt); - IndirectPointerHandle new_handle = + TrustedPointerHandle new_handle = tpt->AllocateAndInitializeEntry(space, obj.ptr(), tag, &scope); scope.MarkSuccess(); @@ -807,9 +813,9 @@ class ReadOnlyPromotionImpl final : public AllStatic { << reinterpret_cast<void*>(slot_value) << "}\n"; } void LogUpdatedCodePointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot, - IndirectPointerHandle old_handle, - IndirectPointerHandle new_handle) { + TrustedPointerSlot slot, + TrustedPointerHandle old_handle, + TrustedPointerHandle new_handle) { std::cout << "ro-promotion: updated code pointer table entry {host " << reinterpret_cast<void*>(host.address()) << " slot " << reinterpret_cast<void*>(slot.address()) << " from " @@ -839,10 +845,10 @@ class ReadOnlyPromotionImpl final : public AllStatic { // (see b/330450848). A new pointer table entry must be allocated for the // relocated object, in a RO segment of the table. - using IndirectPointerHandleMap = - std::unordered_map<IndirectPointerHandle, IndirectPointerHandle>; - IndirectPointerHandleMap code_pointer_moves_; - std::unordered_map<Address, IndirectPointerHandle> promoted_code_to_handle_; + using TrustedPointerHandleMap = + std::unordered_map<TrustedPointerHandle, TrustedPointerHandle>; + TrustedPointerHandleMap code_pointer_moves_; + std::unordered_map<Address, TrustedPointerHandle> promoted_code_to_handle_; #endif // V8_ENABLE_SANDBOX }; @@ -854,8 +860,8 @@ class ReadOnlyPromotionImpl final : public AllStatic { } static void LogPromotedCodePointerTableEntry( - Tagged<Code> code, IndirectPointerHandle old_handle, - IndirectPointerHandle new_handle) { + Tagged<Code> code, TrustedPointerHandle old_handle, + TrustedPointerHandle new_handle) { std::cout << "ro-promotion: promoted code pointer table entry {code " << reinterpret_cast<void*>(code.ptr()) << " slot " << AsHex(old_handle, 8, true) << " to " diff --git a/deps/v8/src/heap/read-only-spaces.h b/deps/v8/src/heap/read-only-spaces.h index f882577f95b4..b5cacb224a2c 100644 --- a/deps/v8/src/heap/read-only-spaces.h +++ b/deps/v8/src/heap/read-only-spaces.h @@ -135,11 +135,11 @@ class ReadOnlyArtifacts final { struct TrustedPointerRegistryEntry { TrustedPointerRegistryEntry(TrustedPointerHandle handle, Address value, - IndirectPointerTag tag) + TrustedPointerTag tag) : handle(handle), value(value), tag(tag) {} TrustedPointerHandle handle; Address value; - IndirectPointerTag tag; + TrustedPointerTag tag; }; void set_trusted_pointer_registry( std::vector<TrustedPointerRegistryEntry>&& registry) { diff --git a/deps/v8/src/heap/reference-summarizer.cc b/deps/v8/src/heap/reference-summarizer.cc index 017875fcdd06..4b73f4b8f16e 100644 --- a/deps/v8/src/heap/reference-summarizer.cc +++ b/deps/v8/src/heap/reference-summarizer.cc @@ -122,8 +122,8 @@ class ReferenceSummarizerMarkingVisitor return marking_state_; } - void MarkPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) {} + void MarkPointerTableEntry(Tagged<HeapObject> host, TrustedPointerSlot slot) { + } void VisitExternalPointer(Tagged<HeapObject> host, ExternalPointerSlot slot) override {} diff --git a/deps/v8/src/heap/scavenger.cc b/deps/v8/src/heap/scavenger.cc index 64d996f2b252..63169aa29d04 100644 --- a/deps/v8/src/heap/scavenger.cc +++ b/deps/v8/src/heap/scavenger.cc @@ -545,7 +545,6 @@ class ScavengerObjectVisitorBase : public NewSpaceVisitor<ConcreteVisitor> { : nullptr; #endif // !V8_COMPRESS_POINTERS if (array_buffer_extension) { - array_buffer_extension->InitializationBarrier(); if constexpr (kExpectedObjectAge == ObjectAge::kYoung) { array_buffer_extension->YoungMark(); } else { @@ -1989,9 +1988,9 @@ bool Scavenger::TryMigrateObject(Tagged<Map> map, THeapObjectSlot slot, // failure case. It also helps us to ensure that we do not rely on non-relaxed // memory ordering for the CAS above. target->set_map_word(map, kRelaxedStore); - heap()->CopyBlock(target.address() + kTaggedSize, - source.address() + kTaggedSize, - object_size.value() - kTaggedSize); + Heap::CopyBlock(target.address() + kTaggedSize, + source.address() + kTaggedSize, + SafeHeapObjectSize(object_size.value() - kTaggedSize)); if (is_logging_) [[unlikely]] { // TODO(425150995): We should have uint versions for allocation to avoid diff --git a/deps/v8/src/heap/setup-heap-internal.cc b/deps/v8/src/heap/setup-heap-internal.cc index 7a4e5c3e0bfc..16f43412efc6 100644 --- a/deps/v8/src/heap/setup-heap-internal.cc +++ b/deps/v8/src/heap/setup-heap-internal.cc @@ -23,14 +23,13 @@ #include "src/objects/contexts.h" #include "src/objects/data-handler-inl.h" #include "src/objects/debug-objects.h" -#include "src/objects/descriptor-array.h" +#include "src/objects/descriptor-array-inl.h" #include "src/objects/dictionary.h" #include "src/objects/foreign.h" #include "src/objects/hash-seed-wrapper.h" #include "src/objects/heap-number.h" #include "src/objects/heap-object-set-map-inl.h" #include "src/objects/instance-type-inl.h" -#include "src/objects/js-atomics-synchronization.h" #include "src/objects/js-generator.h" #include "src/objects/js-shared-array.h" #include "src/objects/js-weak-refs.h" @@ -108,7 +107,7 @@ bool IsMutableMap(InstanceType instance_type, ElementsKind elements_kind) { #endif struct ConstantStringInit { - base::Vector<const char> contents; + std::string_view contents; RootIndex index; }; @@ -460,21 +459,23 @@ bool Heap::CreateEarlyReadOnlyMapsAndObjects() { symbol_map->SetConstructorFunctionIndex(Context::SYMBOL_FUNCTION_INDEX); // Finally, initialise the non-map objects using those maps. - undefined_value->set_map_after_allocation(isolate(), undefined_map, - SKIP_WRITE_BARRIER); - undefined_value->set_kind(Oddball::kUndefined); - - null_value->set_map_after_allocation(isolate(), null_map, - SKIP_WRITE_BARRIER); - null_value->set_kind(Oddball::kNull); - - true_value->set_map_after_allocation(isolate(), boolean_map, - SKIP_WRITE_BARRIER); - true_value->set_kind(Oddball::kTrue); - - false_value->set_map_after_allocation(isolate(), boolean_map, - SKIP_WRITE_BARRIER); - false_value->set_kind(Oddball::kFalse); + { + AllocationWitness witness(undefined_value, roots, + AllocationType::kReadOnly); + new (witness) Undefined(witness); + } + { + AllocationWitness witness(null_value, roots, AllocationType::kReadOnly); + new (witness) Null(witness); + } + { + AllocationWitness witness(true_value, roots, AllocationType::kReadOnly); + new (witness) True(witness); + } + { + AllocationWitness witness(false_value, roots, AllocationType::kReadOnly); + new (witness) False(witness); + } // The empty string is initialised with an empty hash despite being // internalized -- this will be calculated once the hashseed is available. @@ -574,13 +575,13 @@ bool Heap::CreateEarlyReadOnlyMapsAndObjects() { // Allocate the empty enum cache. { - AllocationResult allocation = - Allocate(roots_table().enum_cache_map(), AllocationType::kReadOnly); - if (!allocation.To(&obj)) return false; + if (!AllocateRaw(sizeof(EnumCache), AllocationType::kReadOnly).To(&obj)) { + return false; + } + AllocationWitness witness(obj, roots, AllocationType::kReadOnly); + set_empty_enum_cache(new (witness) EnumCache( + witness, roots.empty_fixed_array(), roots.empty_fixed_array())); } - set_empty_enum_cache(Cast<EnumCache>(obj)); - Cast<EnumCache>(obj)->set_keys(roots.empty_fixed_array()); - Cast<EnumCache>(obj)->set_indices(roots.empty_fixed_array()); // Allocate the empty descriptor array. { @@ -681,11 +682,9 @@ bool Heap::CreateEarlyReadOnlyMapsAndObjects() { AllocationResult alloc = AllocateRaw(sizeof(Cell), AllocationType::kReadOnly); if (!alloc.To(&obj)) return false; - obj->set_map_after_allocation(isolate(), roots.cell_map(), - SKIP_WRITE_BARRIER); - Cast<Cell>(obj)->set_maybe_value(Map::kPrototypeChainInvalid, - SKIP_WRITE_BARRIER); - set_invalid_prototype_validity_cell(Cast<Cell>(obj)); + AllocationWitness witness(obj, roots, AllocationType::kReadOnly); + set_invalid_prototype_validity_cell( + new (witness) Cell(witness, Map::kPrototypeChainInvalid)); } ALLOCATE_MAP(PROPERTY_CELL_TYPE, sizeof(PropertyCell), global_property_cell) @@ -739,6 +738,8 @@ bool Heap::CreateLateReadOnlyNonJSReceiverMaps() { } // The DescriptorArray map is pre-allocated and initialized above. + ALLOCATE_MAP(UNINITIALIZED_HEAP_NUMBER_TYPE, sizeof(HeapNumber), + uninitialized_heap_number) ALLOCATE_VARSIZE_MAP(TURBOSHAFT_WORD32_SET_TYPE_TYPE, turboshaft_word32set_type) ALLOCATE_VARSIZE_MAP(TURBOSHAFT_WORD64_SET_TYPE_TYPE, @@ -873,19 +874,6 @@ bool Heap::CreateLateReadOnlyNonJSReceiverMaps() { } bool Heap::CreateLateReadOnlyJSReceiverMaps() { -#define ALLOCATE_ALWAYS_SHARED_SPACE_JSOBJECT_MAP(instance_type, size, \ - field_name) \ - { \ - Tagged<Map> map; \ - if (!AllocateMap(AllocationType::kReadOnly, (instance_type), size, \ - DICTIONARY_ELEMENTS) \ - .To(&map)) { \ - return false; \ - } \ - AlwaysSharedSpaceJSObject::PrepareMapNoEnumerableProperties(map); \ - set_##field_name##_map(map); \ - } - HandleScope late_jsreceiver_maps_handle_scope(isolate()); Factory* factory = isolate()->factory(); ReadOnlyRoots roots(this); @@ -934,13 +922,6 @@ bool Heap::CreateLateReadOnlyJSReceiverMaps() { set_js_shared_array_map(shared_array_map); } - ALLOCATE_ALWAYS_SHARED_SPACE_JSOBJECT_MAP( - JS_ATOMICS_MUTEX_TYPE, JSAtomicsMutex::kHeaderSize, js_atomics_mutex) - ALLOCATE_ALWAYS_SHARED_SPACE_JSOBJECT_MAP(JS_ATOMICS_CONDITION_TYPE, - JSAtomicsCondition::kHeaderSize, - js_atomics_condition) - -#undef ALLOCATE_ALWAYS_SHARED_SPACE_JSOBJECT_MAP #undef ALLOCATE_PRIMITIVE_MAP #undef ALLOCATE_VARSIZE_MAP #undef ALLOCATE_MAP @@ -989,7 +970,8 @@ bool Heap::CreateImportantReadOnlyObjects() { // the initial section. isolate()->string_table()->InsertEmptyStringForBootstrapping(isolate()); } else { - DirectHandle<String> str = factory->InternalizeString(entry.contents); + DirectHandle<String> str = factory->InternalizeString( + base::OneByteVector(entry.contents.data(), entry.contents.size())); roots_table()[entry.index] = str->ptr(); } } @@ -1037,10 +1019,11 @@ bool Heap::CreateImportantReadOnlyObjects() { obj->set_map_after_allocation(isolate(), roots.scope_info_map(), SKIP_WRITE_BARRIER); int flags = 0; - DCHECK_EQ(ScopeInfo::LanguageModeBit::decode(flags), LanguageMode::kSloppy); - DCHECK_EQ(ScopeInfo::ReceiverVariableBits::decode(flags), + DCHECK_EQ(ScopeInfo::Flags::LanguageModeBit::decode(flags), + LanguageMode::kSloppy); + DCHECK_EQ(ScopeInfo::Flags::ReceiverVariableBits::decode(flags), VariableAllocationInfo::NONE); - DCHECK_EQ(ScopeInfo::FunctionVariableBits::decode(flags), + DCHECK_EQ(ScopeInfo::Flags::FunctionVariableBits::decode(flags), VariableAllocationInfo::NONE); Cast<ScopeInfo>(obj)->set_flags(flags, kRelaxedStore); Cast<ScopeInfo>(obj)->set_context_local_count(0); @@ -1130,18 +1113,16 @@ bool Heap::CreateReadOnlyObjects() { { // Empty array boilerplate description - AllocationResult alloc = - Allocate(roots_table().array_boilerplate_description_map(), - AllocationType::kReadOnly); + AllocationResult alloc = AllocateRaw(sizeof(ArrayBoilerplateDescription), + AllocationType::kReadOnly); if (!alloc.To(&obj)) return false; - Cast<ArrayBoilerplateDescription>(obj)->set_constant_elements( - roots.empty_fixed_array()); - Cast<ArrayBoilerplateDescription>(obj)->set_elements_kind( - ElementsKind::PACKED_SMI_ELEMENTS); + AllocationWitness witness(obj, roots, AllocationType::kReadOnly); + set_empty_array_boilerplate_description( + new (witness) ArrayBoilerplateDescription( + witness, ElementsKind::PACKED_SMI_ELEMENTS, + roots.empty_fixed_array())); } - set_empty_array_boilerplate_description( - Cast<ArrayBoilerplateDescription>(obj)); // Empty arrays. { @@ -1169,7 +1150,8 @@ bool Heap::CreateReadOnlyObjects() { Context::BIGINT_FUNCTION_INDEX); for (const ConstantStringInit& entry : kNotImportantConstantStringTable) { - DirectHandle<String> str = factory->InternalizeString(entry.contents); + DirectHandle<String> str = factory->InternalizeString( + base::OneByteVector(entry.contents.data(), entry.contents.size())); roots_table()[entry.index] = str->ptr(); } @@ -1181,24 +1163,15 @@ bool Heap::CreateReadOnlyObjects() { #undef ENSURE_SINGLE_CHAR_STRINGS_ARE_SINGLE_CHAR // Finish initializing oddballs after creating the string table. - Oddball::Initialize(isolate(), factory->undefined_value(), "undefined", - factory->undefined_nan_value(), "undefined", - Oddball::kUndefined); - - // Initialize the null_value. - Oddball::Initialize(isolate(), factory->null_value(), "null", - direct_handle(Smi::zero(), isolate()), "object", - Oddball::kNull); - - // Initialize the true_value. - Oddball::Initialize(isolate(), factory->true_value(), "true", - direct_handle(Smi::FromInt(1), isolate()), "boolean", - Oddball::kTrue); - - // Initialize the false_value. - Oddball::Initialize(isolate(), factory->false_value(), "false", - direct_handle(Smi::zero(), isolate()), "boolean", - Oddball::kFalse); + roots.undefined_value()->FinishInitialization(roots.undefined_string(), + roots.undefined_nan_value(), + roots.undefined_string()); + roots.null_value()->FinishInitialization(roots.null_string(), Smi::zero(), + roots.object_string()); + roots.true_value()->FinishInitialization(roots.true_string(), Smi::FromInt(1), + roots.boolean_string()); + roots.false_value()->FinishInitialization(roots.false_string(), Smi::zero(), + roots.boolean_string()); { HandleScope handle_scope(isolate()); @@ -1350,8 +1323,7 @@ bool Heap::CreateReadOnlyObjects() { // This code duplicates FactoryBase::SmiToNumber. for (uint32_t i = 10; i < kPreallocatedNumberStringTableSize; ++i) { std::string_view string = IntToStringView(i, buffer); - Handle<String> str = factory->InternalizeString( - base::OneByteVector(string.data(), string.length())); + Handle<String> str = factory->InternalizeString(string); DCHECK(ReadOnlyHeap::Contains(*str)); preallocated_number_string_table->set(i, *str); @@ -1359,40 +1331,6 @@ bool Heap::CreateReadOnlyObjects() { set_preallocated_number_string_table(*preallocated_number_string_table); } - // Initialize the wasm null_value. - -#ifdef V8_ENABLE_WEBASSEMBLY - // Allocate the wasm-null object. It is a regular V8 heap object contained in - // a V8 page. - // In static-roots builds, it is large enough so that it can be mprotected on - // OS page granularity, so we fill up the rest of the current OS page with - // a filler. - // In non-static-roots builds, it is a regular object of size {kTaggedSize} - // and does not need padding. -#define V8_UNMAP_WASM_NULL_PAYLOAD \ - (V8_STATIC_ROOTS_BOOL || V8_STATIC_ROOTS_GENERATION_BOOL) - -#if V8_UNMAP_WASM_NULL_PAYLOAD - // Allocate an unmappable WasmNull. - { - Tagged<HeapObject> wasm_null_obj = - read_only_space_->AllocateRawUnmappableAllocation(0, WasmNull::kSize) - .ToObjectChecked(); - set_wasm_null(UncheckedCast<WasmNull>(wasm_null_obj)); - } -#else - // Allocate the WasmNull. - { - Tagged<HeapObject> wasm_null_obj; - CHECK(AllocateRaw(WasmNull::kSize, AllocationType::kReadOnly) - .To(&wasm_null_obj)); - wasm_null_obj->set_map_after_allocation(isolate(), roots.wasm_null_map(), - SKIP_WRITE_BARRIER); - set_wasm_null(Cast<WasmNull>(wasm_null_obj)); - } -#endif // V8_UNMAP_WASM_NULL_PAYLOAD -#endif // V8_ENABLE_WEBASSEMBLY - auto make_hole = [this, roots, factory]() { USE(factory); @@ -1432,6 +1370,40 @@ bool Heap::CreateReadOnlyObjects() { set_basic_block_counters_marker( UncheckedCast<BasicBlockCountersMarker>(make_hole())); + // Initialize the wasm null_value. + +#ifdef V8_ENABLE_WEBASSEMBLY + // Allocate the wasm-null object. It is a regular V8 heap object contained in + // a V8 page. + // In static-roots builds, it is large enough so that it can be mprotected on + // OS page granularity, so we fill up the rest of the current OS page with + // a filler. + // In non-static-roots builds, it is a regular object of size {kTaggedSize} + // and does not need padding. +#define V8_UNMAP_WASM_NULL_PAYLOAD \ + (V8_STATIC_ROOTS_BOOL || V8_STATIC_ROOTS_GENERATION_BOOL) + +#if V8_UNMAP_WASM_NULL_PAYLOAD + // Allocate an unmappable WasmNull. + { + Tagged<HeapObject> wasm_null_obj = + read_only_space_->AllocateRawUnmappableAllocation(0, WasmNull::kSize) + .ToObjectChecked(); + set_wasm_null(UncheckedCast<WasmNull>(wasm_null_obj)); + } +#else + // Allocate the WasmNull. + { + Tagged<HeapObject> wasm_null_obj; + CHECK(AllocateRaw(WasmNull::kSize, AllocationType::kReadOnly) + .To(&wasm_null_obj)); + wasm_null_obj->set_map_after_allocation(isolate(), roots.wasm_null_map(), + SKIP_WRITE_BARRIER); + set_wasm_null(Cast<WasmNull>(wasm_null_obj)); + } +#endif // V8_UNMAP_WASM_NULL_PAYLOAD +#endif // V8_ENABLE_WEBASSEMBLY + return true; } @@ -1499,6 +1471,7 @@ void Heap::CreateInitialMutableObjects() { set_feedback_vectors_for_profiling_tools(roots.undefined_value()); set_functions_marked_for_manual_optimization(roots.undefined_value()); + set_functions_marked_for_disabled_eager_inlining(roots.undefined_value()); set_shared_wasm_memories(roots.empty_weak_array_list()); set_locals_block_list_cache(roots.undefined_value()); #ifdef V8_ENABLE_WEBASSEMBLY @@ -1649,16 +1622,14 @@ void Heap::CreateInitialMutableObjects() { isolate_, Builtin::kPromiseCapabilityDefaultResolve, 1, FunctionKind::kConciseMethod); info->set_native(true); - info->set_function_map_index( - Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); + info->set_function_map_index(Context::FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); set_promise_capability_default_resolve_shared_fun(*info); info = CreateSharedFunctionInfo(isolate_, Builtin::kPromiseCapabilityDefaultReject, 1, FunctionKind::kConciseMethod); info->set_native(true); - info->set_function_map_index( - Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); + info->set_function_map_index(Context::FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); set_promise_capability_default_reject_shared_fun(*info); info = CreateSharedFunctionInfo( diff --git a/deps/v8/src/heap/sweeper.cc b/deps/v8/src/heap/sweeper.cc index 7195f390f59d..1fee90fa9b5d 100644 --- a/deps/v8/src/heap/sweeper.cc +++ b/deps/v8/src/heap/sweeper.cc @@ -527,7 +527,6 @@ class PromotedPageRecordMigratedSlotVisitor final MaybeObjectSize maybe_object_size) { ArrayBufferExtension* extension = object->extension(); if (extension) { - extension->InitializationBarrier(); extension->YoungMarkPromoted(); } return NewSpaceVisitor<PromotedPageRecordMigratedSlotVisitor>:: diff --git a/deps/v8/src/heap/visit-object.cc b/deps/v8/src/heap/visit-object.cc index 2eaba4656bca..40232f7438ed 100644 --- a/deps/v8/src/heap/visit-object.cc +++ b/deps/v8/src/heap/visit-object.cc @@ -98,9 +98,9 @@ class ObjectVisitorForwarder final visitor_->VisitEphemeron(host, index, key, value); } - void VisitIndirectPointer(Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) override { - visitor_->VisitIndirectPointer(host, slot, mode); + void VisitTrustedPointer(Tagged<HeapObject> host, TrustedPointerSlot slot, + TrustedPointerMode mode) override { + visitor_->VisitTrustedPointer(host, slot, mode); } void VisitProtectedPointer(Tagged<TrustedObject> host, @@ -114,7 +114,7 @@ class ObjectVisitorForwarder final } void VisitTrustedPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) override { + TrustedPointerSlot slot) override { visitor_->VisitTrustedPointerTableEntry(host, slot); } diff --git a/deps/v8/src/heap/young-generation-marking-visitor-inl.h b/deps/v8/src/heap/young-generation-marking-visitor-inl.h index 3f13c77d3f87..e28c8742a2f3 100644 --- a/deps/v8/src/heap/young-generation-marking-visitor-inl.h +++ b/deps/v8/src/heap/young-generation-marking-visitor-inl.h @@ -146,7 +146,6 @@ void YoungGenerationMarkingVisitor<marking_mode>::VisitExternalPointer( #endif // !V8_COMPRESS_POINTERS if (ArrayBufferExtension* extension = reinterpret_cast<ArrayBufferExtension*>(maybe_extension)) { - extension->InitializationBarrier(); extension->YoungMark(); } } diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc index c262e24e75fe..22b44ad9ce48 100644 --- a/deps/v8/src/ic/accessor-assembler.cc +++ b/deps/v8/src/ic/accessor-assembler.cc @@ -88,8 +88,8 @@ TNode<HeapObjectReference> AccessorAssembler::TryMonomorphicCase( // Try to quickly handle the monomorphic case without knowing for sure // if we have a weak reference in feedback. - CSA_DCHECK(this, - IsMap(GetHeapObjectAssumeWeak(weak_lookup_start_object_map))); + CSA_DCHECK(this, IsMapOrCustomMap( + GetHeapObjectAssumeWeak(weak_lookup_start_object_map))); GotoIfNot(TaggedEqual(feedback, weak_lookup_start_object_map), if_miss); TNode<MaybeObject> handler = UncheckedCast<MaybeObject>( @@ -126,8 +126,8 @@ void AccessorAssembler::HandlePolymorphicCase( TNode<IntPtrT> index = ChangePositiveInt32ToIntPtr(var_index.value()); TNode<MaybeObject> maybe_cached_map = LoadWeakFixedArrayElement(feedback, index); - CSA_DCHECK(this, - IsMap(GetHeapObjectAssumeWeak(weak_lookup_start_object_map))); + CSA_DCHECK(this, IsMapOrCustomMap(GetHeapObjectAssumeWeak( + weak_lookup_start_object_map))); GotoIfNot(TaggedEqual(maybe_cached_map, weak_lookup_start_object_map), &loop_next); @@ -464,6 +464,8 @@ void AccessorAssembler::TryEnumeratedKeyedLoad( TNode<HeapObject> double_field = CAST(field.value()); TNode<Map> field_map = LoadMap(double_field); + CSA_DCHECK(this, + Word32BinaryNot(IsUninitializedHeapNumberMap(field_map))); GotoIfNot(TaggedEqual(field_map, HeapNumberMapConstant()), &if_not_double); @@ -561,7 +563,7 @@ TNode<Code> AccessorAssembler::CastToCode(TNode<MaybeObject> code_candidate) { // TaggedMember<UnionOf<Smi,Code>> requires manual validation of the Code // object here. code = LoadCodePointerFromObject( - code, offsetof(ExposedTrustedObject, self_indirect_pointer_)); + code, offsetof(ExposedTrustedObject, self_trusted_pointer_)); #endif return code; } @@ -910,7 +912,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( TNode<IntPtrT> index_ptr = Signed(ChangeUint32ToWord(index)); if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { TNode<Uint32T> capacity = - Unsigned(LoadSwissNameDictionaryCapacity(CAST(properties))); + LoadSwissNameDictionaryCapacity(CAST(properties)); GotoIf(Uint32GreaterThanOrEqual(index, capacity), &lookup); TNode<Object> key = LoadSwissNameDictionaryKey(CAST(properties), index_ptr); @@ -1642,7 +1644,8 @@ void AccessorAssembler::HandleStoreICHandlerCase( BIND(&data); // Handle non-transitioning field stores. - HandleStoreICSmiHandlerCase(handler_word, CAST(holder), p->value(), miss); + HandleStoreICSmiHandlerCase(handler_word, CAST(holder), p->value(), + p->mode(), miss); } BIND(&if_proxy); @@ -1955,16 +1958,17 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( { TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value)); if (do_transitioning_store) { - TNode<Float64T> silenced_value = Float64SilenceNaN(double_value); TNode<HeapNumber> heap_number = - AllocateHeapNumberWithValue(silenced_value); + AllocateHeapNumberWithValue(double_value); StoreMap(object, object_map); StoreObjectField(object, field_offset, heap_number); } else { GotoIf(IsPropertyDetailsConst(details), slow); - TNode<HeapNumber> heap_number = + TNode<UnionOf<HeapNumber, UninitializedHeapNumber>> heap_number = CAST(LoadObjectField(object, field_offset)); StoreHeapNumberValue(heap_number, double_value); + // Migrate UninitializedHeapNumber to mutable HeapNumber. + StoreMapNoWriteBarrier(heap_number, RootIndex::kHeapNumberMap); } Goto(&done); } @@ -2002,8 +2006,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( &cont); { TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value)); - TNode<Float64T> silenced = Float64SilenceNaN(double_value); - var_value = AllocateHeapNumberWithValue(silenced); + var_value = AllocateHeapNumberWithValue(double_value); Goto(&cont); } BIND(&cont); @@ -2026,10 +2029,12 @@ void AccessorAssembler::OverwriteExistingFastDataProperty( BIND(&double_rep); { GotoIf(IsPropertyDetailsConst(details), slow); - TNode<HeapNumber> heap_number = + TNode<UnionOf<HeapNumber, UninitializedHeapNumber>> heap_number = CAST(LoadPropertyArrayElement(properties, backing_store_index)); TNode<Float64T> double_value = ChangeNumberToFloat64(CAST(value)); StoreHeapNumberValue(heap_number, double_value); + // Migrate UninitializedHeapNumber to mutable HeapNumber. + StoreMapNoWriteBarrier(heap_number, RootIndex::kHeapNumberMap); Goto(&done); } BIND(&tagged_rep); @@ -2356,6 +2361,7 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p, void AccessorAssembler::HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value, + StoreICMode mode, Label* miss) { Comment("field store"); #ifdef DEBUG @@ -2383,7 +2389,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word, { Comment("store tagged field"); HandleStoreFieldAndReturn(handler_word, holder, value, std::nullopt, - Representation::Tagged(), miss); + Representation::Tagged(), mode, miss); } BIND(&if_heap_object_field); @@ -2393,7 +2399,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word, Comment("store heap object field"); HandleStoreFieldAndReturn(handler_word, holder, value, std::nullopt, - Representation::HeapObject(), miss); + Representation::HeapObject(), mode, miss); } BIND(&if_smi_field); @@ -2403,7 +2409,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word, Comment("store smi field"); HandleStoreFieldAndReturn(handler_word, holder, value, std::nullopt, - Representation::Smi(), miss); + Representation::Smi(), mode, miss); } BIND(&if_double_field); @@ -2420,7 +2426,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word, Comment("store double field"); HandleStoreFieldAndReturn(handler_word, holder, value, double_value, - Representation::Double(), miss); + Representation::Double(), mode, miss); } } @@ -2512,11 +2518,17 @@ void AccessorAssembler::GotoIfNotSameNumberBitPattern(TNode<Float64T> left, void AccessorAssembler::HandleStoreFieldAndReturn( TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value, std::optional<TNode<Float64T>> double_value, Representation representation, - Label* miss) { + StoreICMode mode, Label* miss) { bool store_value_as_double = representation.IsDouble(); - - if (store_value_as_double) { - double_value = Float64SilenceNaN(*double_value); + bool maybe_initializing_store; + switch (mode) { + case StoreICMode::kDefineNamedOwn: + case StoreICMode::kDefineKeyedOwn: + maybe_initializing_store = true; + break; + case StoreICMode::kDefault: + maybe_initializing_store = false; + break; } TNode<BoolT> is_inobject = @@ -2540,7 +2552,12 @@ void AccessorAssembler::HandleStoreFieldAndReturn( // Store the double value directly into the mutable HeapNumber. TNode<Object> field = LoadObjectField(property_storage, offset); - CSA_DCHECK(this, IsHeapNumber(CAST(field))); + if (maybe_initializing_store) { + CSA_DCHECK(this, Word32Any(IsHeapNumber(CAST(field)), + IsUninitializedHeapNumber(CAST(field)))); + } else { + CSA_DCHECK(this, IsHeapNumber(CAST(field))); + } actual_property_storage = CAST(field); actual_offset = IntPtrConstant(offsetof(HeapNumber, value_)); Goto(&property_and_offset_ready); @@ -2557,6 +2574,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn( &do_store); { if (store_value_as_double) { + CSA_DCHECK(this, IsHeapNumber(property_storage)); TNode<Float64T> current_value = LoadObjectField<Float64T>(property_storage, offset); GotoIfNotSameNumberBitPattern(current_value, *double_value, miss); @@ -2572,6 +2590,10 @@ void AccessorAssembler::HandleStoreFieldAndReturn( // Do the store. if (store_value_as_double) { StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value); + if (maybe_initializing_store) { + // Migrate UninitializedHeapNumber to mutable HeapNumber. + StoreMapNoWriteBarrier(property_storage, RootIndex::kHeapNumberMap); + } } else if (representation.IsSmi()) { TNode<Smi> value_smi = CAST(value); StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi); diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h index ec33f43b1284..480f110df294 100644 --- a/deps/v8/src/ic/accessor-assembler.h +++ b/deps/v8/src/ic/accessor-assembler.h @@ -354,6 +354,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { bool receiver_is_null() const { return !receiver_; } bool flags_is_null() const { return !flags_.has_value(); } + StoreICMode mode() const { return mode_; } + bool IsDefineNamedOwn() const { return mode_ == StoreICMode::kDefineNamedOwn; } @@ -643,14 +645,15 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ElementSupport support_elements); void HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value, - Label* miss); + StoreICMode mode, Label* miss); void HandleStoreICSmiHandlerJSSharedStructFieldCase( TNode<Context> context, TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value); void HandleStoreFieldAndReturn(TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value, std::optional<TNode<Float64T>> double_value, - Representation representation, Label* miss); + Representation representation, + StoreICMode mode, Label* miss); TNode<MaybeObject> CheckPrototypeValidityCell( TNode<Object> maybe_validity_cell, Label* miss); diff --git a/deps/v8/src/ic/handler-configuration.cc b/deps/v8/src/ic/handler-configuration.cc index 63dbf68c790e..855b04c4cd35 100644 --- a/deps/v8/src/ic/handler-configuration.cc +++ b/deps/v8/src/ic/handler-configuration.cc @@ -257,6 +257,30 @@ Handle<LoadHandler> LoadHandler::LoadProxyFast( return handler; } +// static +bool DataHandler::AreEquivalent(const MaybeObjectDirectHandle& a, + const MaybeObjectDirectHandle& b) { + if (a.is_identical_to(b)) return true; + if (a.is_null() || b.is_null()) return false; + if (LoadHandler::IsFastProxyHandler(*a) && + LoadHandler::IsFastProxyHandler(*b)) { + Tagged<DataHandler> handler_a = + Cast<DataHandler>((*a).GetHeapObjectAssumeStrong()); + Tagged<DataHandler> handler_b = + Cast<DataHandler>((*b).GetHeapObjectAssumeStrong()); + // Compare all data fields except for the counter, which does not affect + // the behavior of the handler. Update this when changing the layout of + // fast proxy handlers (see LoadProxyFast above). + static_assert(LoadHandler::kProxyDataFieldCount == 5); + static_assert(LoadHandler::kProxyCounterDataIndex == 5); + return handler_a->data1() == handler_b->data1() && + handler_a->data2() == handler_b->data2() && + handler_a->data3() == handler_b->data3() && + handler_a->data4() == handler_b->data4(); + } + return false; +} + // static Handle<LoadHandler> LoadHandler::LoadInterceptorHolderIsLookupStartupObject( Isolate* isolate, DirectHandle<Map> lookup_start_object_map, diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index 681dac659f1f..68ff2da26041 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -42,6 +42,7 @@ #include "src/objects/property-descriptor.h" #include "src/objects/prototype.h" #include "src/runtime/runtime.h" +#include "src/sandbox/check.h" #include "src/tracing/trace-event.h" #include "src/tracing/tracing-category-observer.h" #include "src/utils/ostreams.h" @@ -187,7 +188,7 @@ void IC::TraceIC(const char* type, DirectHandle<Object> name, State old_state, ic_info.state += "->"; ic_info.state += TransitionMarkFromState(new_state); ic_info.state += modifier; - ic_info.state += ")"; + ic_info.state += ')'; if (!map.is_null()) { ic_info.map = reinterpret_cast<void*>(map->ptr()); ic_info.is_dictionary_map = map->is_dictionary_map(); @@ -712,7 +713,7 @@ bool IC::UpdateOneMapManyNamesIC(DirectHandle<Name> new_name) { // For JS objects, using the generic stub is faster. Wasm objects benefit // from collecting a map that the optimizing compiler can use. Tagged<Map> old_map = nexus()->GetFirstMap(); - if (old_map.is_null() || !IsWasmObjectMap(old_map)) return false; + if (old_map.is_null() || !IsAnyWasmObjectMap(old_map)) return false; if (old_map != *lookup_start_object_map()) return false; Tagged<Name> old_name = nexus()->GetName(); if (old_name.is_null()) return false; // Saw indexed access before. @@ -756,12 +757,22 @@ bool IC::UpdatePolymorphicIC(DirectHandle<Name> name, // Filter out deprecated maps to ensure their instances get migrated. deprecated_maps++; } else if (map.is_identical_to(existing_map)) { + if (LoadHandler::IsFastProxyHandler(*handler) && + !DataHandler::AreEquivalent(handler, existing_handler)) { + // Special case for FastProxy: if we are seeing the same map again, + // this means the inner loadIC or the inner callIC missed. We + // downgrade to a normal slow proxy handler and not directly to + // MEGAMORPHIC. + override_handler = + MaybeObjectDirectHandle(LoadHandler::LoadProxy(isolate())); + } + // If both map and handler stayed the same (and the name is also the // same as checked above, for keyed accesses), we're not progressing // in the lattice and need to go MEGAMORPHIC instead. There's one // exception to this rule, which is when we're in RECOMPUTE_HANDLER // state, there we allow to migrate to a new handler. - if (handler.is_identical_to(existing_handler) && + if (DataHandler::AreEquivalent(override_handler, existing_handler) && state() != RECOMPUTE_HANDLER) { if (v8_flags.sparkplug_plus && caller_frame_type() == CallerFrameType::kBaseline) { @@ -778,14 +789,7 @@ bool IC::UpdatePolymorphicIC(DirectHandle<Name> name, return false; } - if (LoadHandler::IsFastProxyHandler(*handler)) { - // Special case for FastProxy: if we are seeing the same map again, - // this means the inner loadIC or the inner callIC missed. We - // downgrade to a normal slow proxy handler and not directly to - // MEGAMORPHIC. - override_handler = - MaybeObjectDirectHandle(LoadHandler::LoadProxy(isolate())); - } else if (map->is_dictionary_map()) { + if (map->is_dictionary_map() && !IsJSProxyMap(*map)) { // If the receiver type is a dictionary map and the handler is // different, it means the dictionary rehashed. Go MEGAMORPHIC to // prevent deopt loops. @@ -850,10 +854,10 @@ Builtin CalculatePatchingTarget(Builtin current_builtin, Builtin handler) { static_assert(Builtin::kLastLoadICHandler == Builtin::kLoadICGenericBaseline); // Currently we only have LoadIC handlers. {current_builtin} should not be the // generic handler because we should be able to return early in that case. - DCHECK(current_builtin >= Builtin::kFirstLoadICHandler && - current_builtin < Builtin::kLastLoadICHandler); - DCHECK(handler > Builtin::kFirstLoadICHandler && - handler <= Builtin::kLastLoadICHandler); + SBXCHECK(current_builtin >= Builtin::kFirstLoadICHandler && + current_builtin < Builtin::kLastLoadICHandler); + SBXCHECK(handler > Builtin::kFirstLoadICHandler && + handler <= Builtin::kLastLoadICHandler); // No need to patch when the current and target handlers are the same. if (current_builtin == handler) return Builtin::kNoBuiltinId; // Uninitialized handler can be patch to any other handlers. @@ -978,7 +982,7 @@ bool IC::TryHealMonomorphicIC(const MaybeObjectHandle& handler) { MaybeObjectDirectHandle feedback_handler = nexus()->FindHandlerForMap(lookup_start_object_map()); if (feedback_handler.is_null()) return false; - if (!feedback_handler.is_identical_to(handler)) return false; + if (!DataHandler::AreEquivalent(feedback_handler, handler)) return false; Builtin current_builtin = GetCurrentBaselineBuiltin(); DCHECK(current_builtin == Builtin::kLoadICUninitializedBaseline || @@ -1651,14 +1655,8 @@ bool AllowConvertHoleElementToUndefined(Isolate* isolate, // the {receiver}s prototype is either the initial Object.prototype // or the initial Array.prototype, which are both guarded by the // "no elements" protector checked above. - DirectHandle<HeapObject> receiver_prototype(receiver_map->prototype(), - isolate); - InstanceType prototype_type = receiver_prototype->map()->instance_type(); - if (prototype_type == JS_OBJECT_PROTOTYPE_TYPE || - (prototype_type == JS_ARRAY_TYPE && - isolate->IsInCreationContext( - Cast<JSObject>(*receiver_prototype), - Context::INITIAL_ARRAY_PROTOTYPE_INDEX))) { + Tagged<HeapObject> receiver_prototype = receiver_map->prototype(); + if (receiver_prototype->map()->IsMapInArrayPrototypeChain(isolate)) { return true; } } @@ -1845,7 +1843,13 @@ void KeyedLoadIC::LoadElementPolymorphicHandlers( Tagged<Map> tmap = old_map->FindElementsKindTransitionedMap( isolate(), old_maps_and_handlers->maps(), ConcurrencyMode::kSynchronous); - if (!tmap.is_null()) { + // Do not transition on load for simple map-change transitions (such as + // PACKED_ELEMENTS -> HOLEY_ELEMENTS or SMI -> OBJECT), as they share the + // same backing store representation and optimized code + // (ConsolidateElementLoad) consolidates them without transitioning. + if (!tmap.is_null() && + !IsSimpleMapChangeTransition(old_map->elements_kind(), + tmap->elements_kind())) { // Mark all stable receiver maps that have elements kind transition map // among receiver_maps as unstable because the ICs and the optimizing // compilers may perform an elements kind transition for this kind of @@ -2160,7 +2164,7 @@ MaybeDirectHandle<Object> StoreGlobalIC::Store(Handle<Name> name, script_contexts->get(lookup_result.context_index); if (IsImmutableLexicalVariableMode(lookup_result.mode)) { AllowGarbageCollection yes_gc; - return TypeError(MessageTemplate::kConstAssign, global, name); + THROW_NEW_ERROR(isolate(), NewTypeError(MessageTemplate::kConstAssign)); } if (script_context->IsElementTdzHole(lookup_result.slot_index)) { @@ -2877,6 +2881,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( DirectHandle<Map> receiver_map, KeyedAccessStoreMode store_mode, MaybeDirectHandle<UnionOf<Smi, Cell>> prev_validity_cell) { if (!IsJSObjectMap(*receiver_map) || receiver_map->is_access_check_needed() || + receiver_map->has_indexed_interceptor() || receiver_map->IsMapInArrayPrototypeChain(isolate())) { // DefineKeyedOwnIC, which is used to define computed fields in instances, // should handled by the slow stub below instead of the proxy stub. @@ -2885,7 +2890,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler( } #if V8_ENABLE_WEBASSEMBLY - if (IsWasmObjectMap(*receiver_map)) { + if (IsAnyWasmObjectMap(*receiver_map)) { set_slow_stub_reason("wasm object"); } #endif // V8_ENABLE_WEBASSEMBLY @@ -3149,7 +3154,7 @@ MaybeDirectHandle<Object> KeyedStoreIC::Store(Handle<JSAny> object, if (old_receiver_map->is_abandoned_prototype_map()) { set_slow_stub_reason("receiver with prototype map"); #if V8_ENABLE_WEBASSEMBLY - } else if (IsWasmObjectMap(*old_receiver_map)) { + } else if (IsAnyWasmObjectMap(*old_receiver_map)) { // Handle object types for which we don't need to check for // read-only prototype elements because we'll use the slow handler // anyway. @@ -3313,8 +3318,8 @@ RUNTIME_FUNCTION(Runtime_PatchLoadICUninitializedBaseline) { // Get target builtin's address. FeedbackNexus nexus(isolate, vector, vector_slot); Builtin target_builtin = nexus.ic_handler(); - DCHECK(target_builtin > Builtin::kFirstLoadICHandler && - target_builtin <= Builtin::kLastLoadICHandler); + SBXCHECK(target_builtin > Builtin::kFirstLoadICHandler && + target_builtin <= Builtin::kLastLoadICHandler); Address target = Builtins::EntryOf(target_builtin, isolate); { @@ -3629,7 +3634,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { script_contexts->get(lookup_result.context_index), isolate); if (IsImmutableLexicalVariableMode(lookup_result.mode)) { THROW_NEW_ERROR_RETURN_FAILURE( - isolate, NewTypeError(MessageTemplate::kConstAssign, global, name)); + isolate, NewTypeError(MessageTemplate::kConstAssign)); } { diff --git a/deps/v8/src/init/bootstrapper.cc b/deps/v8/src/init/bootstrapper.cc index 7299c9561a94..617c53e20e23 100644 --- a/deps/v8/src/init/bootstrapper.cc +++ b/deps/v8/src/init/bootstrapper.cc @@ -46,7 +46,6 @@ #endif // V8_INTL_SUPPORT #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" -#include "src/objects/js-atomics-synchronization.h" #include "src/objects/js-disposable-stack.h" #include "src/objects/js-iterator-helpers.h" #ifdef V8_INTL_SUPPORT @@ -106,7 +105,7 @@ void SourceCodeCache::Iterate(RootVisitor* v) { v->VisitRootPointer(Root::kExtensions, nullptr, FullObjectSlot(&cache_)); } -bool SourceCodeCache::Lookup(Isolate* isolate, base::Vector<const char> name, +bool SourceCodeCache::Lookup(Isolate* isolate, std::string_view name, DirectHandle<SharedFunctionInfo>* handle) { uint32_t cache_len = cache_->ulength().value(); for (uint32_t i = 0; i < cache_len; i += 2) { @@ -120,7 +119,7 @@ bool SourceCodeCache::Lookup(Isolate* isolate, base::Vector<const char> name, return false; } -void SourceCodeCache::Add(Isolate* isolate, base::Vector<const char> name, +void SourceCodeCache::Add(Isolate* isolate, std::string_view name, DirectHandle<SharedFunctionInfo> shared) { Factory* factory = isolate->factory(); HandleScope scope(isolate); @@ -131,7 +130,7 @@ void SourceCodeCache::Add(Isolate* isolate, base::Vector<const char> name, cache_ = *new_array; DirectHandle<String> str = factory - ->NewStringFromOneByte(base::Vector<const uint8_t>::cast(name), + ->NewStringFromOneByte(base::OneByteVector(name.data(), name.size()), AllocationType::kOld) .ToHandleChecked(); DCHECK(!str.is_null()); @@ -213,17 +212,13 @@ class Genesis { // See https://tc39.es/ecma262/#sec-%throwtypeerror% for details. DirectHandle<JSFunction> GetThrowTypeErrorIntrinsic(); - void CreateSloppyModeFunctionMaps(DirectHandle<JSFunction> empty); - void CreateStrictModeFunctionMaps(DirectHandle<JSFunction> empty); + void CreateFunctionMaps(DirectHandle<JSFunction> empty); void CreateObjectFunction(DirectHandle<JSFunction> empty); void CreateIteratorMaps(DirectHandle<JSFunction> empty); void CreateAsyncIteratorMaps(DirectHandle<JSFunction> empty); void CreateAsyncFunctionMaps(DirectHandle<JSFunction> empty); void CreateJSProxyMaps(); - // Make the "arguments" and "caller" properties throw a TypeError on access. - void AddRestrictedFunctionProperties(DirectHandle<JSFunction> empty); - // Creates the global objects using the global proxy and the template passed // in through the API. We call this regardless of whether we are building a // context from scratch or using a deserialized one from the context snapshot @@ -267,6 +262,8 @@ class Genesis { #undef IGNORE_FEATURE void InitializeGlobal_regexp_linear_flag(); void InitializeGlobal_sharedarraybuffer(); + // TODO(572988458): Remove harmony_struct initialization. + void InitializeGlobal_harmony_struct(); #if V8_ENABLE_WEBASSEMBLY void InitializeWasmJSPI(); #endif @@ -404,12 +401,11 @@ namespace { bool IsFunctionMapOrSpecialBuiltin(DirectHandle<Map> map, Builtin builtin, DirectHandle<Context> context) { // During bootstrapping some of these maps could be not created yet. - return ((*map == context->GetNoCell(Context::STRICT_FUNCTION_MAP_INDEX)) || - (*map == context->GetNoCell( - Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)) || + return ((*map == context->GetNoCell(Context::FUNCTION_MAP_INDEX)) || (*map == - context->GetNoCell( - Context::STRICT_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX)) || + context->GetNoCell(Context::FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX)) || + (*map == context->GetNoCell( + Context::FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX)) || // Check if it's a creation of an empty or Proxy function during // bootstrapping. (builtin == Builtin::kEmptyFunction || @@ -457,10 +453,9 @@ V8_NOINLINE DirectHandle<JSFunction> CreateFunctionForBuiltinWithPrototype( MutableMode prototype_mutability, int len, AdaptArguments adapt) { Factory* factory = isolate->factory(); DirectHandle<NativeContext> context(isolate->native_context()); - DirectHandle<Map> map = - prototype_mutability == MUTABLE - ? isolate->strict_function_map() - : isolate->strict_function_with_readonly_prototype_map(); + DirectHandle<Map> map = prototype_mutability == MUTABLE + ? isolate->function_map() + : isolate->function_with_readonly_prototype_map(); DCHECK(IsFunctionMapOrSpecialBuiltin(map, builtin, context)); DirectHandle<SharedFunctionInfo> info = @@ -504,7 +499,7 @@ V8_NOINLINE Handle<JSFunction> CreateFunctionForBuiltinWithoutPrototype( Isolate* isolate, DirectHandle<String> name, Builtin builtin, int len, AdaptArguments adapt) { DirectHandle<NativeContext> context(isolate->native_context()); - DirectHandle<Map> map = isolate->strict_function_without_prototype_map(); + DirectHandle<Map> map = isolate->function_without_prototype_map(); DCHECK(IsFunctionMapOrSpecialBuiltin(map, builtin, context)); DirectHandle<SharedFunctionInfo> info = @@ -584,8 +579,8 @@ V8_NOINLINE void SetConstructorInstanceType( Tagged<Map> map = constructor->map(); // Check we don't accidentally change one of the existing maps. - DCHECK_NE(map, *isolate->strict_function_map()); - DCHECK_NE(map, *isolate->strict_function_with_readonly_prototype_map()); + DCHECK_NE(map, *isolate->function_map()); + DCHECK_NE(map, *isolate->function_with_readonly_prototype_map()); // Constructor function map is always a root map, and thus we don't have to // deal with updating the whole transition tree. DCHECK(IsUndefined(map->GetBackPointer())); @@ -640,7 +635,7 @@ V8_NOINLINE DirectHandle<JSFunction> CreateSharedObjectConstructor( info->set_language_mode(LanguageMode::kStrict); DirectHandle<JSFunction> constructor = Factory::JSFunctionBuilder{isolate, info, isolate->native_context()} - .set_map(isolate->strict_function_with_readonly_prototype_map()) + .set_map(isolate->function_with_readonly_prototype_map()) .Build(); constructor->set_prototype_or_initial_map(*instance_map, kReleaseStore); @@ -777,7 +772,7 @@ DirectHandle<Map> CreateLiteralObjectMapFromCache( DirectHandle<JSFunction> Genesis::CreateEmptyFunction() { // Allocate the function map first and then patch the prototype later. DirectHandle<Map> empty_function_map = - factory()->CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, {}); + factory()->CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE); empty_function_map->set_is_prototype_map(true); DCHECK(!empty_function_map->is_dictionary_map()); @@ -804,35 +799,6 @@ DirectHandle<JSFunction> Genesis::CreateEmptyFunction() { return empty_function; } -void Genesis::CreateSloppyModeFunctionMaps(DirectHandle<JSFunction> empty) { - Factory* factory = isolate_->factory(); - DirectHandle<Map> map; - - // - // Allocate maps for sloppy functions without prototype. - // - map = factory->CreateSloppyFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, empty); - native_context()->set_sloppy_function_without_prototype_map(*map); - - // - // Allocate maps for sloppy functions with readonly prototype. - // - map = - factory->CreateSloppyFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE, empty); - native_context()->set_sloppy_function_with_readonly_prototype_map(*map); - - // - // Allocate maps for sloppy functions with writable prototype. - // - map = factory->CreateSloppyFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE, - empty); - native_context()->set_sloppy_function_map(*map); - - map = factory->CreateSloppyFunctionMap( - FUNCTION_WITH_NAME_AND_WRITEABLE_PROTOTYPE, empty); - native_context()->set_sloppy_function_with_name_map(*map); -} - DirectHandle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic() { if (!restricted_properties_thrower_.is_null()) { return restricted_properties_thrower_; @@ -868,48 +834,40 @@ DirectHandle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic() { return function; } -void Genesis::CreateStrictModeFunctionMaps(DirectHandle<JSFunction> empty) { +void Genesis::CreateFunctionMaps(DirectHandle<JSFunction> empty) { Factory* factory = isolate_->factory(); DirectHandle<Map> map; // - // Allocate maps for strict functions without prototype. + // Allocate maps for functions without prototype. // - map = factory->CreateStrictFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, empty); - native_context()->set_strict_function_without_prototype_map(*map); + map = factory->CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, empty); + native_context()->set_function_without_prototype_map(*map); - map = factory->CreateStrictFunctionMap(METHOD_WITH_NAME, empty); + map = factory->CreateFunctionMap(METHOD_WITH_NAME, empty); native_context()->set_method_with_name_map(*map); // - // Allocate maps for strict functions with writable prototype. + // Allocate maps for functions with writable prototype. // - map = factory->CreateStrictFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE, - empty); - native_context()->set_strict_function_map(*map); + map = factory->CreateFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE, empty); + native_context()->set_function_map(*map); - map = factory->CreateStrictFunctionMap( - FUNCTION_WITH_NAME_AND_WRITEABLE_PROTOTYPE, empty); - native_context()->set_strict_function_with_name_map(*map); + map = factory->CreateFunctionMap(FUNCTION_WITH_NAME_AND_WRITEABLE_PROTOTYPE, + empty); + native_context()->set_function_with_name_map(*map); // - // Allocate maps for strict functions with readonly prototype. + // Allocate maps for functions with readonly prototype. // - map = - factory->CreateStrictFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE, empty); - native_context()->set_strict_function_with_readonly_prototype_map(*map); + map = factory->CreateFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE, empty); + native_context()->set_function_with_readonly_prototype_map(*map); // // Allocate map for class functions. // map = factory->CreateClassFunctionMap(empty); native_context()->set_class_function_map(*map); - -#ifdef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - // Now that the strict mode function map is available, set up the - // restricted "arguments" and "caller" getters. - AddRestrictedFunctionProperties(empty); -#endif // V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS } void Genesis::CreateObjectFunction(DirectHandle<JSFunction> empty_function) { @@ -972,24 +930,18 @@ void Genesis::CreateObjectFunction(DirectHandle<JSFunction> empty_function) { namespace { DirectHandle<Map> CreateNonConstructorMap(Isolate* isolate, - DirectHandle<Map> source_map, - DirectHandle<JSObject> prototype, - const char* reason) { - DirectHandle<Map> map = Map::Copy(isolate, source_map, reason); + FunctionMode function_mode, + DirectHandle<JSFunction> empty, + DirectHandle<JSObject> prototype) { // Ensure the resulting map has prototype slot (it is necessary for storing // initial map even when the prototype property is not required). - DCHECK(map->instance_type() == JS_FUNCTION_WITHOUT_PROTOTYPE_TYPE || - map->instance_type() == JS_FUNCTION_TYPE); - if (IsJSFunctionWithoutPrototypeMap(*map)) { - // Re-set the unused property fields after changing the instance size. - int unused_property_fields = map->UnusedPropertyFields(); - map->set_instance_type(JS_FUNCTION_TYPE); - map->set_instance_size(map->instance_size() + kTaggedSize); - // The prototype slot shifts the in-object properties area by one slot. - map->SetInObjectPropertiesStartInWords( - map->GetInObjectPropertiesStartInWords() + 1); - map->SetInObjectUnusedPropertyFields(unused_property_fields); - } + DCHECK(IsFunctionModeWithPrototype(function_mode)); + // Create a fresh function map instead of calling Map::Copy on an existing + // function map, as Map::Copy would call NotifyLeafMapLayoutChange and mark + // the source map as unstable. + DirectHandle<Map> map = + isolate->factory()->CreateFunctionMap(function_mode, empty); + DCHECK(IsJSFunctionWithPrototypeMap(*map)); map->set_is_constructor(false); Map::SetPrototype(isolate, map, prototype); return map; @@ -1079,14 +1031,13 @@ void Genesis::CreateIteratorMaps(DirectHandle<JSFunction> empty) { // 04-14-15, section 25.2.4.3). // Generator functions do not have "caller" or "arguments" accessors. DirectHandle<Map> map; - map = CreateNonConstructorMap(isolate(), isolate()->strict_function_map(), - generator_function_prototype, - "GeneratorFunction"); + map = CreateNonConstructorMap(isolate(), FUNCTION_WITH_WRITEABLE_PROTOTYPE, + empty, generator_function_prototype); native_context()->set_generator_function_map(*map); - map = CreateNonConstructorMap( - isolate(), isolate()->strict_function_with_name_map(), - generator_function_prototype, "GeneratorFunction with name"); + map = CreateNonConstructorMap(isolate(), + FUNCTION_WITH_NAME_AND_WRITEABLE_PROTOTYPE, + empty, generator_function_prototype); native_context()->set_generator_function_with_name_map(*map); DirectHandle<JSFunction> object_function(native_context()->object_function(), @@ -1187,14 +1138,13 @@ void Genesis::CreateAsyncIteratorMaps(DirectHandle<JSFunction> empty) { // 04-14-15, section 25.2.4.3). // Async Generator functions do not have "caller" or "arguments" accessors. DirectHandle<Map> map; - map = CreateNonConstructorMap(isolate(), isolate()->strict_function_map(), - async_generator_function_prototype, - "AsyncGeneratorFunction"); + map = CreateNonConstructorMap(isolate(), FUNCTION_WITH_WRITEABLE_PROTOTYPE, + empty, async_generator_function_prototype); native_context()->set_async_generator_function_map(*map); - map = CreateNonConstructorMap( - isolate(), isolate()->strict_function_with_name_map(), - async_generator_function_prototype, "AsyncGeneratorFunction with name"); + map = CreateNonConstructorMap(isolate(), + FUNCTION_WITH_NAME_AND_WRITEABLE_PROTOTYPE, + empty, async_generator_function_prototype); native_context()->set_async_generator_function_with_name_map(*map); DirectHandle<JSFunction> object_function(native_context()->object_function(), @@ -1216,13 +1166,11 @@ void Genesis::CreateAsyncFunctionMaps(DirectHandle<JSFunction> empty) { InstallToStringTag(isolate(), async_function_prototype, "AsyncFunction"); DirectHandle<Map> map = - Map::Copy(isolate(), isolate()->strict_function_without_prototype_map(), - "AsyncFunction"); + factory()->CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, empty); Map::SetPrototype(isolate(), map, async_function_prototype); native_context()->set_async_function_map(*map); - map = Map::Copy(isolate(), isolate()->method_with_name_map(), - "AsyncFunction with name"); + map = factory()->CreateFunctionMap(METHOD_WITH_NAME, empty); Map::SetPrototype(isolate(), map, async_function_prototype); native_context()->set_async_function_with_name_map(*map); } @@ -1278,15 +1226,6 @@ void Genesis::CreateJSProxyMaps() { } namespace { -void ReplaceAccessors(Isolate* isolate, DirectHandle<Map> map, - DirectHandle<String> name, PropertyAttributes attributes, - DirectHandle<AccessorPair> accessor_pair) { - Tagged<DescriptorArray> descriptors = map->instance_descriptors(); - InternalIndex entry = descriptors->SearchWithCache(isolate, *name, *map); - Descriptor d = Descriptor::AccessorConstant(name, accessor_pair, attributes); - descriptors->Replace(entry, &d); -} - void InitializeJSArrayMaps(Isolate* isolate, DirectHandle<Context> native_context, DirectHandle<Map> initial_map) { @@ -1320,20 +1259,6 @@ void InitializeJSArrayMaps(Isolate* isolate, } } // namespace -void Genesis::AddRestrictedFunctionProperties(DirectHandle<JSFunction> empty) { - PropertyAttributes rw_attribs = static_cast<PropertyAttributes>(DONT_ENUM); - DirectHandle<JSFunction> thrower = GetThrowTypeErrorIntrinsic(); - DirectHandle<AccessorPair> accessors = factory()->NewAccessorPair(); - accessors->set_getter(*thrower); - accessors->set_setter(*thrower); - - DirectHandle<Map> map(empty->map(), isolate()); - ReplaceAccessors(isolate(), map, factory()->arguments_string(), rw_attribs, - accessors); - ReplaceAccessors(isolate(), map, factory()->caller_string(), rw_attribs, - accessors); -} - void Genesis::CreateRoots() { // Allocate the native context FixedArray first and then patch the // closure and extension object later (we need the empty function @@ -2085,9 +2010,19 @@ Handle<JSObject> InitializeTemporal(Isolate* isolate) { return temporal; } +// The lazy Temporal accessors may be reached cross-realm, in which case the +// current context is the caller's. Initialize Temporal in the holder's realm, +// since the result is installed on the holder. +Tagged<NativeContext> GetHolderNativeContext( + const v8::PropertyCallbackInfo<v8::Value>& info) { + DirectHandle<JSReceiver> holder = Utils::OpenDirectHandle(*info.Holder()); + return holder->GetCreationContext().value(); +} + void LazyInitializeDateToTemporalInstant( v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + SaveAndSwitchContext save(isolate, GetHolderNativeContext(info)); InitializeTemporal(isolate); DirectHandle<JSFunction> function = SimpleCreateFunction( isolate, isolate->factory()->InternalizeUtf8String("toTemporalInstant"), @@ -2098,6 +2033,7 @@ void LazyInitializeDateToTemporalInstant( void LazyInitializeGlobalThisTemporal( v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + SaveAndSwitchContext save(isolate, GetHolderNativeContext(info)); DirectHandle<JSObject> temporal = InitializeTemporal(isolate); info.GetReturnValue().Set(v8::Utils::ToLocal(temporal)); } @@ -2312,8 +2248,7 @@ void Genesis::InitializeGlobal(DirectHandle<JSGlobalObject> global_object, InstallFunction(isolate_, global, "Function", JS_FUNCTION_TYPE, JSFunctionWithPrototype::kMinSize, 0, prototype, Builtin::kFunctionConstructor, 1, kDontAdapt); - // Function instances are sloppy by default. - function_fun->set_prototype_or_initial_map(*isolate_->sloppy_function_map(), + function_fun->set_prototype_or_initial_map(*isolate_->function_map(), kReleaseStore); InstallWithIntrinsicDefaultProto(isolate_, function_fun, Context::FUNCTION_FUNCTION_INDEX); @@ -2343,7 +2278,6 @@ void Genesis::InitializeGlobal(DirectHandle<JSGlobalObject> global_object, static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY)); native_context()->set_function_has_instance(*has_instance); -#ifndef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS // The .arguments and .caller getters are non-standard. SimpleInstallGetterSetter(isolate_, prototype, factory->arguments_string(), Builtin::kFunctionPrototypeLegacyArgumentsGetter, @@ -2351,23 +2285,14 @@ void Genesis::InitializeGlobal(DirectHandle<JSGlobalObject> global_object, SimpleInstallGetterSetter(isolate_, prototype, factory->caller_string(), Builtin::kFunctionPrototypeLegacyCallerGetter, Builtin::kFunctionPrototypeLegacyCallerSetter); -#endif // !V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS // Complete setting up function maps. { - isolate_->sloppy_function_map()->SetConstructor(*function_fun); - isolate_->sloppy_function_with_name_map()->SetConstructor(*function_fun); - isolate_->sloppy_function_with_readonly_prototype_map()->SetConstructor( - *function_fun); - isolate_->sloppy_function_without_prototype_map()->SetConstructor( - *function_fun); - - isolate_->strict_function_map()->SetConstructor(*function_fun); - isolate_->strict_function_with_name_map()->SetConstructor(*function_fun); - isolate_->strict_function_with_readonly_prototype_map()->SetConstructor( - *function_fun); - isolate_->strict_function_without_prototype_map()->SetConstructor( + isolate_->function_map()->SetConstructor(*function_fun); + isolate_->function_with_name_map()->SetConstructor(*function_fun); + isolate_->function_with_readonly_prototype_map()->SetConstructor( *function_fun); + isolate_->function_without_prototype_map()->SetConstructor(*function_fun); isolate_->class_function_map()->SetConstructor(*function_fun); } @@ -3456,7 +3381,7 @@ void Genesis::InitializeGlobal(DirectHandle<JSGlobalObject> global_object, // TODO(ishell): microtask queue pointer will be moved from native context // to the embedder data array so we don't need an empty embedder data array. DirectHandle<EmbedderDataArray> embedder_data = - factory->NewEmbedderDataArray(0); + factory->NewEmbedderDataArray(V8_EMBEDDER_DATA_ARRAY_SIZE); native_context()->set_embedder_data(*embedder_data); { // -- g l o b a l T h i s @@ -4869,8 +4794,9 @@ void Genesis::InitializeGlobal(DirectHandle<JSGlobalObject> global_object, CreateJSProxyMaps(); // Proxy function map has prototype slot for storing initial map but does // not have a prototype property. - DirectHandle<Map> proxy_function_map = Map::Copy( - isolate_, isolate_->strict_function_without_prototype_map(), "Proxy"); + DirectHandle<Map> proxy_function_map = + factory->CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, empty_function); + proxy_function_map->SetConstructor(native_context()->function_function()); proxy_function_map->set_is_constructor(true); DirectHandle<String> name = factory->Proxy_string(); @@ -5337,7 +5263,7 @@ bool Genesis::CompileExtension(Isolate* isolate, v8::Extension* extension) { // If we can't find the function in the cache, we compile a new // function and insert it into the cache. - base::Vector<const char> name = base::CStrVector(extension->name()); + std::string_view name(extension->name()); SourceCodeCache* cache = isolate->bootstrapper()->extensions_cache(); DirectHandle<Context> context(isolate->context(), isolate); DCHECK(IsNativeContext(*context)); @@ -5872,11 +5798,8 @@ void Genesis::InitializeGlobal_harmony_shadow_realm() { void Genesis::InitializeGlobal_harmony_struct() { if (!v8_flags.harmony_struct) return; - ReadOnlyRoots roots(isolate()); DirectHandle<JSGlobalObject> global(native_context()->global_object(), isolate()); - DirectHandle<JSObject> atomics_object = Cast<JSObject>( - JSReceiver::GetProperty(isolate(), global, "Atomics").ToHandleChecked()); { // Install shared objects @@hasInstance in the native context. @@ -5890,8 +5813,7 @@ void Genesis::InitializeGlobal_harmony_struct() { DirectHandle<String> name = isolate()->factory()->InternalizeUtf8String("SharedStructType"); DirectHandle<JSFunction> shared_struct_type_fun = CreateFunctionForBuiltin( - isolate(), name, - isolate()->strict_function_with_readonly_prototype_map(), + isolate(), name, isolate()->function_with_readonly_prototype_map(), Builtin::kSharedStructTypeConstructor, 1, kDontAdapt); JSObject::MakePrototypesFast(shared_struct_type_fun, kStartAtReceiver, isolate()); @@ -5918,43 +5840,6 @@ void Genesis::InitializeGlobal_harmony_struct() { SimpleInstallFunction(isolate(), shared_array_fun, "isSharedArray", Builtin::kSharedArrayIsSharedArray, 1, kAdapt); } - - { // Atomics.Mutex - DirectHandle<String> mutex_str = - isolate()->factory()->InternalizeUtf8String("Mutex"); - DirectHandle<JSFunction> mutex_fun = CreateSharedObjectConstructor( - isolate(), mutex_str, isolate()->factory()->js_atomics_mutex_map(), - Builtin::kAtomicsMutexConstructor, 0, kAdapt); - JSObject::AddProperty(isolate(), atomics_object, mutex_str, mutex_fun, - DONT_ENUM); - - SimpleInstallFunction(isolate(), mutex_fun, "lock", - Builtin::kAtomicsMutexLock, 2, kAdapt); - SimpleInstallFunction(isolate(), mutex_fun, "lockWithTimeout", - Builtin::kAtomicsMutexLockWithTimeout, 3, kAdapt); - SimpleInstallFunction(isolate(), mutex_fun, "tryLock", - Builtin::kAtomicsMutexTryLock, 2, kAdapt); - SimpleInstallFunction(isolate(), mutex_fun, "isMutex", - Builtin::kAtomicsMutexIsMutex, 1, kAdapt); - } - - { // Atomics.Condition - DirectHandle<String> condition_str = - isolate()->factory()->InternalizeUtf8String("Condition"); - DirectHandle<JSFunction> condition_fun = CreateSharedObjectConstructor( - isolate(), condition_str, - isolate()->factory()->js_atomics_condition_map(), - Builtin::kAtomicsConditionConstructor, 0, kAdapt); - JSObject::AddProperty(isolate(), atomics_object, condition_str, - condition_fun, DONT_ENUM); - - SimpleInstallFunction(isolate(), condition_fun, "wait", - Builtin::kAtomicsConditionWait, 2, kDontAdapt); - SimpleInstallFunction(isolate(), condition_fun, "notify", - Builtin::kAtomicsConditionNotify, 2, kDontAdapt); - SimpleInstallFunction(isolate(), condition_fun, "isCondition", - Builtin::kAtomicsConditionIsCondition, 1, kAdapt); - } } void Genesis::InitializeGlobal_sharedarraybuffer() { @@ -7089,8 +6974,7 @@ Genesis::Genesis(Isolate* isolate, CreateRoots(); MathRandom::InitializeContext(isolate, native_context()); DirectHandle<JSFunction> empty_function = CreateEmptyFunction(); - CreateSloppyModeFunctionMaps(empty_function); - CreateStrictModeFunctionMaps(empty_function); + CreateFunctionMaps(empty_function); CreateObjectFunction(empty_function); CreateIteratorMaps(empty_function); CreateAsyncIteratorMaps(empty_function); diff --git a/deps/v8/src/init/bootstrapper.h b/deps/v8/src/init/bootstrapper.h index 9a4e4d319d9b..d11c91a7f1b5 100644 --- a/deps/v8/src/init/bootstrapper.h +++ b/deps/v8/src/init/bootstrapper.h @@ -29,10 +29,10 @@ class SourceCodeCache final { void Iterate(RootVisitor* v); - bool Lookup(Isolate* isolate, base::Vector<const char> name, + bool Lookup(Isolate* isolate, std::string_view name, DirectHandle<SharedFunctionInfo>* handle); - void Add(Isolate* isolate, base::Vector<const char> name, + void Add(Isolate* isolate, std::string_view name, DirectHandle<SharedFunctionInfo> shared); private: diff --git a/deps/v8/src/init/heap-symbols.h b/deps/v8/src/init/heap-symbols.h index 45a1ee29de0c..922c9a709d48 100644 --- a/deps/v8/src/init/heap-symbols.h +++ b/deps/v8/src/init/heap-symbols.h @@ -583,8 +583,6 @@ V(_, as_string, "as") \ V(_, assert_string, "assert") \ V(_, async_string, "async") \ - V(_, AtomicsCondition_string, "Atomics.Condition") \ - V(_, AtomicsMutex_string, "Atomics.Mutex") \ V(_, auto_string, "auto") \ V(_, BigInt64Array_string, "BigInt64Array") \ V(_, BigInt_string, "BigInt") \ @@ -926,7 +924,6 @@ V(_, sealed_symbol) \ V(_, shared_struct_map_elements_template_symbol) \ V(_, shared_struct_map_registry_key_symbol) \ - V(_, strict_function_transition_symbol) \ V(_, template_literal_function_literal_id_symbol) \ V(_, template_literal_slot_id_symbol) \ V(_, wasm_cross_instance_call_symbol) \ diff --git a/deps/v8/src/init/icu_util.cc b/deps/v8/src/init/icu_util.cc index f210b1570320..acfe1fa28502 100644 --- a/deps/v8/src/init/icu_util.cc +++ b/deps/v8/src/init/icu_util.cc @@ -12,8 +12,11 @@ #include <stdio.h> #include <stdlib.h> +#include <memory> + #include "src/base/build_config.h" #include "src/base/file-utils.h" +#include "src/base/platform/platform.h" #include "src/base/platform/wrappers.h" #include "unicode/putil.h" #include "unicode/udata.h" @@ -29,9 +32,15 @@ namespace internal { #if defined(V8_INTL_SUPPORT) && (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) namespace { +#if V8_OS_POSIX && !V8_OS_ZOS +base::OS::MemoryMappedFile* g_icu_data_file = nullptr; + +void free_icu_data_file() { delete g_icu_data_file; } +#else char* g_icu_data_ptr = nullptr; void free_icu_data_ptr() { delete[] g_icu_data_ptr; } +#endif } // namespace #endif @@ -69,6 +78,22 @@ bool InitializeICU(const char* icu_data_file) { #elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE if (!icu_data_file) return false; +// On Windows MemoryMappedFile decodes the path as UTF-8 while fopen uses the +// ANSI code page, and on z/OS MemoryMappedFile::open mishandles a missing +// file, so both keep reading the file into a heap buffer. +#if V8_OS_POSIX && !V8_OS_ZOS + if (g_icu_data_file) return true; + + std::unique_ptr<base::OS::MemoryMappedFile> file( + base::OS::MemoryMappedFile::open( + icu_data_file, base::OS::MemoryMappedFile::FileMode::kReadOnly)); + // Empty files are opened but not mapped. + if (!file || !file->memory()) return false; + + g_icu_data_file = file.release(); + atexit(free_icu_data_file); + const void* data = g_icu_data_file->memory(); +#else if (g_icu_data_ptr) return true; FILE* inf = base::Fopen(icu_data_file, "rb"); @@ -93,9 +118,11 @@ bool InitializeICU(const char* icu_data_file) { base::Fclose(inf); atexit(free_icu_data_ptr); + const void* data = g_icu_data_ptr; +#endif UErrorCode err = U_ZERO_ERROR; - udata_setCommonData(reinterpret_cast<void*>(g_icu_data_ptr), &err); + udata_setCommonData(data, &err); // Never try to load ICU data from files. udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); return err == U_ZERO_ERROR; diff --git a/deps/v8/src/init/isolate-group.cc b/deps/v8/src/init/isolate-group.cc index 21f4929fa28e..9ca26dbd6c08 100644 --- a/deps/v8/src/init/isolate-group.cc +++ b/deps/v8/src/init/isolate-group.cc @@ -151,6 +151,20 @@ IsolateGroup::~IsolateGroup() { #ifdef V8_ENABLE_SANDBOX void IsolateGroup::Initialize(bool process_wide, Sandbox* sandbox) { + { + // metadata_pointer_table_ is a large array (~512K), which is initially + // zero-filled and is only partly used at runtime. + // Tell the OS to reclaim this memory for now and zero-fill on demand if we + // actually need more of the table. + v8::VirtualAddressSpace* as = GetPlatformVirtualAddressSpace(); + size_t page_size = as->page_size(); + uintptr_t start = reinterpret_cast<uintptr_t>(&metadata_pointer_table_); + uintptr_t start_aligned = RoundUp(start, page_size); + size_t discard_len = RoundDown( + sizeof(metadata_pointer_table_) - (start_aligned - start), page_size); + (void)as->DiscardSystemPages(start_aligned, discard_len); + } + DCHECK(!reservation_.IsReserved()); CHECK(sandbox->is_initialized()); process_wide_ = process_wide; @@ -195,13 +209,14 @@ void IsolateGroup::Initialize(bool process_wide, Sandbox* sandbox) { std::make_unique<OptimizingCompileTaskExecutor>(); if (v8_flags.memory_pool) { - memory_pool_ = std::make_unique<MemoryPool>(MemoryPool::Config{ - .single_threaded = v8_flags.single_threaded, - .share_memory_on_teardown = - v8_flags.memory_pool_share_memory_on_teardown, - .trace_gc_nvp = v8_flags.trace_gc_nvp, - .max_large_page_pool_size = v8_flags.max_large_page_pool_size, - .timeout_in_sec = v8_flags.memory_pool_timeout}); + memory_pool_ = std::make_unique<MemoryPool>( + this, MemoryPool::Config{ + .single_threaded = v8_flags.single_threaded, + .share_memory_on_teardown = + v8_flags.memory_pool_share_memory_on_teardown, + .trace_gc_nvp = v8_flags.trace_gc_nvp, + .max_large_page_pool_size = v8_flags.max_large_page_pool_size, + .timeout_in_sec = v8_flags.memory_pool_timeout}); } } #elif defined(V8_COMPRESS_POINTERS) @@ -235,12 +250,14 @@ void IsolateGroup::Initialize(bool process_wide) { trusted_pointer_compression_cage_ = &reservation_; optimizing_compile_task_executor_ = std::make_unique<OptimizingCompileTaskExecutor>(); - memory_pool_ = std::make_unique<MemoryPool>(MemoryPool::Config{ - .single_threaded = v8_flags.single_threaded, - .share_memory_on_teardown = v8_flags.memory_pool_share_memory_on_teardown, - .trace_gc_nvp = v8_flags.trace_gc_nvp, - .max_large_page_pool_size = v8_flags.max_large_page_pool_size, - .timeout_in_sec = v8_flags.memory_pool_timeout}); + memory_pool_ = std::make_unique<MemoryPool>( + this, MemoryPool::Config{ + .single_threaded = v8_flags.single_threaded, + .share_memory_on_teardown = + v8_flags.memory_pool_share_memory_on_teardown, + .trace_gc_nvp = v8_flags.trace_gc_nvp, + .max_large_page_pool_size = v8_flags.max_large_page_pool_size, + .timeout_in_sec = v8_flags.memory_pool_timeout}); } #else // !V8_COMPRESS_POINTERS void IsolateGroup::Initialize(bool process_wide) { @@ -248,12 +265,14 @@ void IsolateGroup::Initialize(bool process_wide) { page_allocator_ = GetPlatformPageAllocator(); optimizing_compile_task_executor_ = std::make_unique<OptimizingCompileTaskExecutor>(); - memory_pool_ = std::make_unique<MemoryPool>(MemoryPool::Config{ - .single_threaded = v8_flags.single_threaded, - .share_memory_on_teardown = v8_flags.memory_pool_share_memory_on_teardown, - .trace_gc_nvp = v8_flags.trace_gc_nvp, - .max_large_page_pool_size = v8_flags.max_large_page_pool_size, - .timeout_in_sec = v8_flags.memory_pool_timeout}); + memory_pool_ = std::make_unique<MemoryPool>( + this, MemoryPool::Config{ + .single_threaded = v8_flags.single_threaded, + .share_memory_on_teardown = + v8_flags.memory_pool_share_memory_on_teardown, + .trace_gc_nvp = v8_flags.trace_gc_nvp, + .max_large_page_pool_size = v8_flags.max_large_page_pool_size, + .timeout_in_sec = v8_flags.memory_pool_timeout}); } #endif // V8_ENABLE_SANDBOX diff --git a/deps/v8/src/inspector/custom-preview.cc b/deps/v8/src/inspector/custom-preview.cc index b9133b24b5f5..fdd3816927ad 100644 --- a/deps/v8/src/inspector/custom-preview.cc +++ b/deps/v8/src/inspector/custom-preview.cc @@ -18,6 +18,7 @@ #include "src/inspector/v8-debugger.h" #include "src/inspector/v8-inspector-impl.h" #include "src/inspector/v8-stack-trace-impl.h" +#include "src/inspector/value-mirror.h" namespace v8_inspector { @@ -27,43 +28,82 @@ namespace { void reportError(v8::Local<v8::Context> context, const v8::TryCatch& tryCatch) { DCHECK(tryCatch.HasCaught()); v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // Reporting the error calls into V8, which would clear a pending termination + // exception, so don't report anything when execution is terminating. + if (isolate->IsExecutionTerminating()) return; V8InspectorImpl* inspector = static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate)); int contextId = InspectedContext::contextId(context); int groupId = inspector->contextGroupId(contextId); + if (!groupId) return; v8::Local<v8::String> message = toV8String(isolate, "<no message available>"); if (!tryCatch.Message().IsEmpty()) message = tryCatch.Message()->Get(); v8::Local<v8::String> prefix = toV8String(isolate, "Custom Formatter Failed: "); message = v8::String::Concat(isolate, prefix, message); + if (message.IsEmpty()) { + // String::Concat() returns an empty handle if the resulting string would + // exceed v8::String::kMaxLength, so leave out the actual message then. + message = v8::String::Concat(isolate, prefix, + toV8String(isolate, "<message too long>")); + } v8::LocalVector<v8::Value> arguments(isolate); arguments.push_back(message); - V8ConsoleMessageStorage* storage = - inspector->ensureConsoleMessageStorage(groupId); - if (!storage) return; - storage->addMessage(V8ConsoleMessage::createForConsoleAPI( - context, contextId, groupId, inspector, - inspector->client()->currentTimeMS(), ConsoleAPIType::kError, arguments, - String16(), nullptr)); + std::unique_ptr<V8ConsoleMessage> consoleMessage = + V8ConsoleMessage::createForConsoleAPI( + context, contextId, groupId, inspector, + inspector->client()->currentTimeMS(), ConsoleAPIType::kError, + arguments, String16(), nullptr); + if (!inspector->contextGroupId(contextId)) return; + inspector->ensureConsoleMessageStorage(groupId)->addMessage( + std::move(consoleMessage)); } void reportError(v8::Local<v8::Context> context, const v8::TryCatch& tryCatch, const String16& message) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); + if (isolate->IsExecutionTerminating()) return; isolate->ThrowException(toV8String(isolate, message)); reportError(context, tryCatch); } +bool takeValues(CustomPreviewBudget* budget, uint32_t count) { + if (count > budget->values) { + budget->values = 0; + budget->exhausted = true; + return false; + } + budget->values -= count; + return true; +} + +bool takeCharacters(CustomPreviewBudget* budget, size_t count) { + if (count > budget->characters) { + budget->characters = 0; + budget->exhausted = true; + return false; + } + budget->characters -= static_cast<uint32_t>(count); + return true; +} + +bool takeCharacters(CustomPreviewBudget* budget, v8::Local<v8::String> string) { + return takeCharacters(budget, static_cast<size_t>(string->Length())); +} + bool substituteObjectTags(int sessionId, const String16& groupName, v8::Local<v8::Context> context, v8::Local<v8::Array> jsonML, int maxDepth, + CustomPreviewBudget* budget, std::unique_ptr<protocol::ListValue>* result); bool jsonMLValueToProtocolValue(int sessionId, const String16& groupName, v8::Local<v8::Context> context, v8::Local<v8::Value> value, int maxDepth, + CustomPreviewBudget* budget, std::unique_ptr<protocol::Value>* result) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handleScope(isolate); v8::TryCatch tryCatch(isolate); if (value->IsProxy()) { @@ -102,14 +142,19 @@ bool jsonMLValueToProtocolValue(int sessionId, const String16& groupName, return true; } if (value->IsString()) { - *result = protocol::StringValue::create( - toProtocolString(isolate, value.As<v8::String>())); + v8::Local<v8::String> string = value.As<v8::String>(); + if (!takeCharacters(budget, string)) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } + *result = protocol::StringValue::create(toProtocolString(isolate, string)); return true; } if (value->IsArray()) { std::unique_ptr<protocol::ListValue> listResult; if (!substituteObjectTags(sessionId, groupName, context, - value.As<v8::Array>(), maxDepth, &listResult)) { + value.As<v8::Array>(), maxDepth, budget, + &listResult)) { return false; } *result = std::move(listResult); @@ -129,7 +174,12 @@ bool jsonMLValueToProtocolValue(int sessionId, const String16& groupName, return false; } uint32_t length = propertyNames->Length(); + if (!takeValues(budget, length)) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } for (uint32_t i = 0; i < length; ++i) { + v8::HandleScope loopScope(isolate); v8::Local<v8::Value> name; if (!propertyNames->Get(context, i).ToLocal(&name)) { reportError(context, tryCatch); @@ -158,9 +208,14 @@ bool jsonMLValueToProtocolValue(int sessionId, const String16& groupName, property->IsSymbol()) { continue; } + if (!takeCharacters(budget, propertyName)) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } std::unique_ptr<protocol::Value> protocolProperty; if (!jsonMLValueToProtocolValue(sessionId, groupName, context, property, - maxDepth - 1, &protocolProperty)) { + maxDepth - 1, budget, + &protocolProperty)) { return false; } dict->setValue(toProtocolString(isolate, propertyName), @@ -176,10 +231,12 @@ bool jsonMLValueToProtocolValue(int sessionId, const String16& groupName, bool substituteObjectTags(int sessionId, const String16& groupName, v8::Local<v8::Context> context, v8::Local<v8::Array> jsonML, int maxDepth, + CustomPreviewBudget* budget, std::unique_ptr<protocol::ListValue>* result) { *result = protocol::ListValue::create(); if (!jsonML->Length()) return true; v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handleScope(isolate); v8::TryCatch tryCatch(isolate); if (maxDepth <= 0) { @@ -207,6 +264,10 @@ bool substituteObjectTags(int sessionId, const String16& groupName, reportError(context, tryCatch, "object tag should have 2 elements"); return false; } + if (!takeValues(budget, 1)) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } v8::Local<v8::Value> attributesValue; if (!jsonML->Get(context, 1).ToLocal(&attributesValue)) { reportError(context, tryCatch); @@ -232,6 +293,12 @@ bool substituteObjectTags(int sessionId, const String16& groupName, return false; } + if (originValue->IsString() && + !takeCharacters(budget, originValue.As<v8::String>())) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } + v8::Local<v8::Value> configValue; if (!attributes->Get(context, toV8String(isolate, "config")) .ToLocal(&configValue)) { @@ -256,11 +323,24 @@ bool substituteObjectTags(int sessionId, const String16& groupName, std::unique_ptr<protocol::Runtime::RemoteObject> wrapper; protocol::Response response = injectedScript->wrapObject( originValue, groupName, WrapOptions({WrapMode::kIdOnly}), configValue, - maxDepth - 1, &wrapper); + maxDepth - 1, budget, &wrapper); + // Wrapping the object runs the (nested) custom formatters, which might + // terminate execution. Don't call into V8 anymore in that case, since the + // next V8 API call would clear the pending termination exception. + if (isolate->IsExecutionTerminating() || budget->exhausted) return false; if (!response.IsSuccess() || !wrapper) { reportError(context, tryCatch, "cannot wrap value"); return false; } + if (!originValue->IsString()) { + size_t wrapperChars = + wrapper->getDescription(String16()).length() + + wrapper->getUnserializableValue(String16()).length(); + if (!takeCharacters(budget, wrapperChars)) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } + } std::vector<uint8_t> cbor = wrapper->Serialize(); std::unique_ptr<protocol::Value> protocolWrapper = protocol::Value::parseBinary(cbor.data(), cbor.size()); @@ -271,9 +351,19 @@ bool substituteObjectTags(int sessionId, const String16& groupName, (*result)->pushValue(protocol::StringValue::create("object")); (*result)->pushValue(std::move(protocolWrapper)); } else { + // Take all the child elements from the budget upfront, so that we fail + // early (before converting any of them) if they don't fit. + uint32_t length = jsonML->Length(); + uint32_t childCount = length > 0 ? length - 1 : 0; + if (!takeValues(budget, childCount) || + !takeCharacters(budget, firstValue.As<v8::String>())) { + reportError(context, tryCatch, "JSONML is too large"); + return false; + } (*result)->pushValue(protocol::StringValue::create( toProtocolString(isolate, firstValue.As<v8::String>()))); - for (uint32_t i = 1; i < jsonML->Length(); ++i) { + for (uint32_t i = 1; i < length; ++i) { + v8::HandleScope loopScope(isolate); v8::Local<v8::Value> value; if (!jsonML->Get(context, i).ToLocal(&value)) { reportError(context, tryCatch); @@ -288,7 +378,7 @@ bool substituteObjectTags(int sessionId, const String16& groupName, std::unique_ptr<protocol::ListValue> childList; if (value.As<v8::Array>()->Length() > 0) { if (!substituteObjectTags(sessionId, groupName, context, - value.As<v8::Array>(), maxDepth - 1, + value.As<v8::Array>(), maxDepth - 1, budget, &childList)) { return false; } @@ -299,7 +389,8 @@ bool substituteObjectTags(int sessionId, const String16& groupName, } else { std::unique_ptr<protocol::Value> protocolElement; if (!jsonMLValueToProtocolValue(sessionId, groupName, context, value, - maxDepth - 1, &protocolElement)) { + maxDepth - 1, budget, + &protocolElement)) { return false; } (*result)->pushValue(std::move(protocolElement)); @@ -400,18 +491,27 @@ void bodyCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { } v8::Local<v8::Array> jsonML = formattedValue.As<v8::Array>(); std::unique_ptr<protocol::ListValue> protocolJsonML; + CustomPreviewBudget budget; + uint32_t budgetBefore = budget.characters; if (!substituteObjectTags( sessionIdValue.As<v8::Int32>()->Value(), toProtocolString(isolate, groupNameValue.As<v8::String>()), context, - jsonML, kMaxCustomPreviewDepth, &protocolJsonML)) { + jsonML, kMaxCustomPreviewDepth, &budget, &protocolJsonML)) { return; } std::vector<uint8_t> json; v8_crdtp::json::ConvertCBORToJSON( v8_crdtp::SpanFrom(protocolJsonML->Serialize()), &json); + uint32_t charged = budgetBefore - budget.characters; + if (json.size() > charged && + !takeCharacters(&budget, json.size() - charged)) { + reportError(context, tryCatch, "JSONML is too large"); + return; + } v8::Local<v8::Value> detachedJsonML; v8_inspector::StringView serialized(json.data(), json.size()); - if (!v8::JSON::Parse(context, toV8String(isolate, serialized)) + if (serialized.length() >= v8::String::kMaxLength || + !v8::JSON::Parse(context, toV8String(isolate, serialized)) .ToLocal(&detachedJsonML)) { reportError(context, tryCatch, "cannot serialize body"); return; @@ -424,6 +524,7 @@ void generateCustomPreview(v8::Isolate* isolate, int sessionId, const String16& groupName, v8::Local<v8::Object> object, v8::MaybeLocal<v8::Value> maybeConfig, int maxDepth, + CustomPreviewBudget* budget, std::unique_ptr<CustomPreview>* preview) { v8::Local<v8::Context> context; if (!object->GetCreationContext(isolate).ToLocal(&context)) { @@ -433,6 +534,7 @@ void generateCustomPreview(v8::Isolate* isolate, int sessionId, v8::MicrotasksScope microtasksScope(context, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::TryCatch tryCatch(isolate); + v8::Isolate::SuppressMicrotaskExecutionScope suppress(isolate); v8::Local<v8::Value> configValue; if (!maybeConfig.ToLocal(&configValue)) configValue = v8::Undefined(isolate); @@ -499,15 +601,29 @@ void generateCustomPreview(v8::Isolate* isolate, int sessionId, bool hasBody = hasBodyValue->ToBoolean(isolate)->Value(); std::unique_ptr<protocol::ListValue> protocolJsonML; + CustomPreviewBudget defaultBudget; + if (!budget) budget = &defaultBudget; + uint32_t budgetBefore = budget->characters; if (!substituteObjectTags(sessionId, groupName, context, jsonML, maxDepth, - &protocolJsonML)) { + budget, &protocolJsonML)) { return; } std::vector<uint8_t> json; v8_crdtp::json::ConvertCBORToJSON( v8_crdtp::SpanFrom(protocolJsonML->Serialize()), &json); + uint32_t charged = budgetBefore - budget->characters; + if (json.size() > charged && + !takeCharacters(budget, json.size() - charged)) { + reportError(context, tryCatch, "JSONML is too large"); + return; + } v8_inspector::StringView serialized(json.data(), json.size()); + if (serialized.length() >= v8::String::kMaxLength) { + budget->exhausted = true; + reportError(context, tryCatch, "cannot serialize header"); + return; + } String16 header = toString16(serialized); v8::Local<v8::Function> bodyFunction; diff --git a/deps/v8/src/inspector/custom-preview.h b/deps/v8/src/inspector/custom-preview.h index d882215fadd8..043a81da83ab 100644 --- a/deps/v8/src/inspector/custom-preview.h +++ b/deps/v8/src/inspector/custom-preview.h @@ -5,19 +5,32 @@ #ifndef V8_INSPECTOR_CUSTOM_PREVIEW_H_ #define V8_INSPECTOR_CUSTOM_PREVIEW_H_ +#include <cstdint> #include <memory> #include "src/inspector/protocol/Protocol.h" #include "src/inspector/protocol/Runtime.h" +#include "src/inspector/value-mirror.h" namespace v8_inspector { const int kMaxCustomPreviewDepth = 20; +// Limits the total size of the JSONML that custom formatters can produce for a +// single preview (including nested ["object", {...}] tags). +struct CustomPreviewBudget { + // The remaining number of array elements and object properties. + uint32_t values = 100'000; + // The remaining number of characters in strings and property names. + uint32_t characters = kMaxArrayLength; + bool exhausted = false; +}; + void generateCustomPreview( v8::Isolate* isolate, int sessionId, const String16& groupName, v8::Local<v8::Object> object, v8::MaybeLocal<v8::Value> config, - int maxDepth, std::unique_ptr<protocol::Runtime::CustomPreview>* preview); + int maxDepth, CustomPreviewBudget* budget, + std::unique_ptr<protocol::Runtime::CustomPreview>* preview); } // namespace v8_inspector diff --git a/deps/v8/src/inspector/injected-script.cc b/deps/v8/src/inspector/injected-script.cc index 7dc58dc2813e..5d44cf36c82a 100644 --- a/deps/v8/src/inspector/injected-script.cc +++ b/deps/v8/src/inspector/injected-script.cc @@ -275,20 +275,19 @@ class InjectedScript::ProtocolPromiseHandler { } } - if (m_objectGroup == "console") { - scope.injectedScript()->setLastEvaluationResult(result); - } - std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue; - response = scope.injectedScript()->wrapObject( - result, m_objectGroup, *m_wrapOptions, &wrappedValue); + std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails; + response = scope.injectedScript()->wrapEvaluateResult( + result, scope.tryCatch(), m_objectGroup, *m_wrapOptions, + m_throwOnSideEffect, &wrappedValue, &exceptionDetails); if (!response.IsSuccess()) { EvaluateCallback::sendFailure(m_callback, scope.injectedScript(), response); return; } EvaluateCallback::sendSuccess(m_callback, scope.injectedScript(), - std::move(wrappedValue), nullptr); + std::move(wrappedValue), + std::move(exceptionDetails)); } void catchCallback(v8::Local<v8::Value> result) { @@ -304,9 +303,28 @@ class InjectedScript::ProtocolPromiseHandler { Response response = scope.initialize(); if (!response.IsSuccess()) return; std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue; - response = scope.injectedScript()->wrapObject( - result, m_objectGroup, *m_wrapOptions, &wrappedValue); + { + std::optional<v8::debug::SideEffectCheckScope> sideEffectCheckScope; + if (m_throwOnSideEffect) { + sideEffectCheckScope.emplace(m_inspector->isolate()); + } + response = scope.injectedScript()->wrapObject( + result, m_objectGroup, *m_wrapOptions, &wrappedValue); + } if (!response.IsSuccess()) { + if (m_throwOnSideEffect && scope.tryCatch().HasCaught()) { + std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails; + response = scope.injectedScript()->wrapEvaluateResult( + v8::MaybeLocal<v8::Value>(), scope.tryCatch(), m_objectGroup, + *m_wrapOptions, m_throwOnSideEffect, &wrappedValue, + &exceptionDetails); + if (response.IsSuccess()) { + EvaluateCallback::sendSuccess(m_callback, scope.injectedScript(), + std::move(wrappedValue), + std::move(exceptionDetails)); + return; + } + } EvaluateCallback::sendFailure(m_callback, scope.injectedScript(), response); return; @@ -461,7 +479,7 @@ Response InjectedScript::getProperties( if (mirror.value) { Response response = wrapObjectMirror( *mirror.value, groupName, wrapOptions, v8::MaybeLocal<v8::Value>(), - kMaxCustomPreviewDepth, &remoteObject); + kMaxCustomPreviewDepth, nullptr, &remoteObject); if (!response.IsSuccess()) return response; descriptor->setValue(std::move(remoteObject)); descriptor->setWritable(mirror.writable); @@ -616,26 +634,41 @@ Response InjectedScript::wrapObject( const WrapOptions& wrapOptions, std::unique_ptr<protocol::Runtime::RemoteObject>* result) { return wrapObject(value, groupName, wrapOptions, v8::MaybeLocal<v8::Value>(), - kMaxCustomPreviewDepth, result); + kMaxCustomPreviewDepth, nullptr, result); } Response InjectedScript::wrapObject( v8::Local<v8::Value> value, const String16& groupName, const WrapOptions& wrapOptions, v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth, + CustomPreviewBudget* budget, std::unique_ptr<protocol::Runtime::RemoteObject>* result) { v8::Local<v8::Context> context = m_context->context(); v8::Context::Scope contextScope(context); - std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value); - if (!mirror) return Response::InternalError(); - return wrapObjectMirror(*mirror, groupName, wrapOptions, customPreviewConfig, - maxCustomPreviewDepth, result); + v8::Isolate* isolate = m_context->isolate(); + bool terminated = false; + Response response = Response::InternalError(); + { + v8::TryCatch tryCatch(isolate); + std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value); + if (mirror) { + response = + wrapObjectMirror(*mirror, groupName, wrapOptions, customPreviewConfig, + maxCustomPreviewDepth, budget, result); + } + terminated = tryCatch.HasTerminated(); + } + if (terminated && !isolate->IsExecutionTerminating()) { + m_context->inspector()->debugger()->reportTermination(); + } + return response; } Response InjectedScript::wrapObjectMirror( const ValueMirror& mirror, const String16& groupName, const WrapOptions& wrapOptions, v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth, + CustomPreviewBudget* budget, std::unique_ptr<protocol::Runtime::RemoteObject>* result) { int customPreviewEnabled = m_customPreviewEnabled; int sessionId = m_sessionId; @@ -643,6 +676,12 @@ Response InjectedScript::wrapObjectMirror( v8::Context::Scope contextScope(context); Response response = mirror.buildRemoteObject(context, wrapOptions, result); if (!response.IsSuccess()) return response; + // Building the remote object (i.e. the preview) can run JavaScript, which + // might terminate execution. Don't call into V8 anymore in that case, since + // the next V8 API call would clear the pending termination exception. + if (m_context->isolate()->IsExecutionTerminating()) { + return Response::InternalError(); + } v8::Local<v8::Value> value = mirror.v8Value(v8::Isolate::GetCurrent()); response = bindRemoteObjectIfNeeded(sessionId, context, value, groupName, result->get()); @@ -656,7 +695,14 @@ Response InjectedScript::wrapObjectMirror( std::unique_ptr<protocol::Runtime::CustomPreview> customPreview; generateCustomPreview(m_context->isolate(), sessionId, groupName, value.As<v8::Object>(), customPreviewConfig, - maxCustomPreviewDepth, &customPreview); + maxCustomPreviewDepth, budget, &customPreview); + // Custom formatters might terminate execution. Don't call into V8 anymore + // in that case, since the next V8 API call would clear the pending + // termination exception. + if (m_context->isolate()->IsExecutionTerminating() || + (budget && budget->exhausted)) { + return Response::InternalError(); + } if (customPreview) (*result)->setCustomPreview(std::move(customPreview)); } if (wrapOptions.mode == WrapMode::kDeep) { @@ -718,12 +764,13 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable( int limit = 1000; mirror->buildObjectPreview(context, true /* generatePreviewForTable */, &limit, &limit, &preview); - if (!preview) return nullptr; + if (!preview || isolate->IsExecutionTerminating()) return nullptr; std::vector<String16> selectedColumns; std::unordered_set<String16> columnSet; v8::Local<v8::Array> v8Columns; if (maybeColumns.ToLocal(&v8Columns)) { + v8::TryCatch tryCatch(isolate); for (uint32_t i = 0; i < v8Columns->Length(); ++i) { v8::Local<v8::Value> column; if (v8Columns->Get(context, i).ToLocal(&column) && column->IsString()) { @@ -733,6 +780,7 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable( selectedColumns.push_back(name); } } + if (isolate->IsExecutionTerminating()) return nullptr; } } if (!selectedColumns.empty()) { @@ -842,11 +890,6 @@ v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const { return m_lastEvaluationResult.Get(m_context->isolate()); } -void InjectedScript::setLastEvaluationResult(v8::Local<v8::Value> result) { - m_lastEvaluationResult.Reset(m_context->isolate(), result); - m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel); -} - Response InjectedScript::resolveCallArgument( protocol::Runtime::CallArgument* callArgument, v8::Local<v8::Value>* result) { @@ -856,7 +899,7 @@ Response InjectedScript::resolveCallArgument( RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId); if (!response.IsSuccess()) return response; if (remoteObjectId->contextId() != m_context->contextId() || - remoteObjectId->isolateId() != m_context->inspector()->isolateId()) { + remoteObjectId->isolateId() != isolateId()) { return Response::ServerError( "Argument should belong to the same JavaScript world as target " "object"); @@ -977,33 +1020,44 @@ Response InjectedScript::wrapEvaluateResult( } return Response::InternalError(); } - Response response = - wrapObject(resultValue, objectGroup, wrapOptions, result); - if (!response.IsSuccess()) return response; - if (objectGroup == "console") { - m_lastEvaluationResult.Reset(m_context->isolate(), resultValue); - m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel); + Response response = Response::Success(); + { + std::optional<v8::debug::SideEffectCheckScope> sideEffectCheckScope; + if (throwOnSideEffect) { + sideEffectCheckScope.emplace(m_context->isolate()); + } + response = wrapObject(resultValue, objectGroup, wrapOptions, result); } - } else { - if (tryCatch.HasTerminated() || !tryCatch.CanContinue()) { - return Response::ServerError("Execution was terminated"); + if (response.IsSuccess()) { + if (objectGroup == "console") { + m_lastEvaluationResult.Reset(m_context->isolate(), resultValue); + m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel); + } + return Response::Success(); } - v8::Local<v8::Value> exception = tryCatch.Exception(); - if (!throwOnSideEffect) { - m_context->inspector()->client()->dispatchError( - m_context->context(), tryCatch.Message(), exception); + if (!tryCatch.HasTerminated() && + (!throwOnSideEffect || !tryCatch.HasCaught())) { + return response; } - Response response = wrapObject(exception, objectGroup, - exception->IsNativeError() - ? WrapOptions({WrapMode::kIdOnly}) - : WrapOptions({WrapMode::kPreview}), - result); - if (!response.IsSuccess()) return response; - // We send exception in result for compatibility reasons, even though it's - // accessible through exceptionDetails.exception. - response = createExceptionDetails(tryCatch, objectGroup, exceptionDetails); - if (!response.IsSuccess()) return response; } + if (tryCatch.HasTerminated() || !tryCatch.CanContinue()) { + return Response::ServerError("Execution was terminated"); + } + v8::Local<v8::Value> exception = tryCatch.Exception(); + if (!throwOnSideEffect) { + m_context->inspector()->client()->dispatchError( + m_context->context(), tryCatch.Message(), exception); + } + Response response = + wrapObject(exception, objectGroup, + exception->IsNativeError() ? WrapOptions({WrapMode::kIdOnly}) + : WrapOptions({WrapMode::kPreview}), + result); + if (!response.IsSuccess()) return response; + // We send exception in result for compatibility reasons, even though it's + // accessible through exceptionDetails.exception. + response = createExceptionDetails(tryCatch, objectGroup, exceptionDetails); + if (!response.IsSuccess()) return response; return Response::Success(); } @@ -1103,6 +1157,9 @@ void InjectedScript::Scope::cleanup() { } InjectedScript::Scope::~Scope() { + if (m_tryCatch.HasTerminated()) { + m_inspector->debugger()->reportTermination(); + } if (m_ignoreExceptionsAndMuteConsole) { setPauseOnExceptionsState(m_previousPauseOnExceptionsState); m_inspector->client()->unmuteMetrics(m_contextGroupId); @@ -1163,6 +1220,12 @@ Response InjectedScript::CallFrameScope::findInjectedScript( &m_inspectedContext); } +uint64_t InjectedScript::isolateId() const { + V8InspectorSessionImpl* session = m_context->inspector()->sessionById( + m_context->contextGroupId(), m_sessionId); + return session ? session->isolateId() : 0; +} + String16 InjectedScript::bindObject(v8::Local<v8::Value> value, const String16& groupName) { if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1; @@ -1173,8 +1236,7 @@ String16 InjectedScript::bindObject(v8::Local<v8::Value> value, m_idToObjectGroupName[id] = groupName; m_nameToObjectGroup[groupName].push_back(id); } - return RemoteObjectId::serialize(m_context->inspector()->isolateId(), - m_context->contextId(), id); + return RemoteObjectId::serialize(isolateId(), m_context->contextId(), id); } // static diff --git a/deps/v8/src/inspector/injected-script.h b/deps/v8/src/inspector/injected-script.h index d72d77daacae..ef593caa9ced 100644 --- a/deps/v8/src/inspector/injected-script.h +++ b/deps/v8/src/inspector/injected-script.h @@ -52,6 +52,7 @@ class RemoteObjectId; class V8InspectorImpl; class V8InspectorSessionImpl; class ValueMirror; +struct CustomPreviewBudget; using protocol::Response; @@ -110,12 +111,13 @@ class InjectedScript final { Response wrapObject(v8::Local<v8::Value>, const String16& groupName, const WrapOptions& wrapOptions, v8::MaybeLocal<v8::Value> customPreviewConfig, - int maxCustomPreviewDepth, + int maxCustomPreviewDepth, CustomPreviewBudget* budget, std::unique_ptr<protocol::Runtime::RemoteObject>* result); Response wrapObjectMirror( const ValueMirror& mirror, const String16& groupName, const WrapOptions& wrapOptions, v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth, + CustomPreviewBudget* budget, std::unique_ptr<protocol::Runtime::RemoteObject>* result); std::unique_ptr<protocol::Runtime::RemoteObject> wrapTable( v8::Local<v8::Object> table, v8::MaybeLocal<v8::Array> columns); @@ -149,7 +151,6 @@ class InjectedScript final { std::unique_ptr<protocol::Runtime::RemoteObject>* result, std::unique_ptr<protocol::Runtime::ExceptionDetails>*); v8::Local<v8::Value> lastEvaluationResult() const; - void setLastEvaluationResult(v8::Local<v8::Value> result); class Scope { CPPGC_STACK_ALLOCATED(); @@ -246,6 +247,7 @@ class InjectedScript final { friend class PromiseHandlerTracker; v8::Local<v8::Object> commandLineAPI(); + uint64_t isolateId() const; void unbindObject(int id); static Response bindRemoteObjectIfNeeded( diff --git a/deps/v8/src/inspector/v8-console-agent-impl.cc b/deps/v8/src/inspector/v8-console-agent-impl.cc index 3fd335d257bb..f512aa030756 100644 --- a/deps/v8/src/inspector/v8-console-agent-impl.cc +++ b/deps/v8/src/inspector/v8-console-agent-impl.cc @@ -75,6 +75,9 @@ void V8ConsoleAgentImpl::reportAllMessages() { } if (i >= storage->messages().size()) break; V8ConsoleMessage message = *storage->messages()[i]; + if (message.origin() != V8MessageOrigin::kConsole) { + continue; + } if (!reportMessage(&message, false)) { break; } diff --git a/deps/v8/src/inspector/v8-console-message.cc b/deps/v8/src/inspector/v8-console-message.cc index da35ae736e04..f65c04ddf016 100644 --- a/deps/v8/src/inspector/v8-console-message.cc +++ b/deps/v8/src/inspector/v8-console-message.cc @@ -125,6 +125,7 @@ class V8ValueStringBuilder { if (object->ObjectProtoToString(m_context).ToLocal(&stringValue)) { return append(stringValue); } + if (m_tryCatch.HasTerminated()) return false; } v8::Local<v8::String> stringValue; if (!value->ToString(m_context).ToLocal(&stringValue)) return false; @@ -145,8 +146,15 @@ class V8ValueStringBuilder { for (uint32_t i = 0; i < length; ++i) { if (i) m_builder.append(','); v8::Local<v8::Value> value; - if (!array->Get(m_context, i).ToLocal(&value)) continue; - if (!append(value, IgnoreNull | IgnoreUndefined)) { + if (!array->Get(m_context, i).ToLocal(&value)) { + if (m_tryCatch.HasTerminated()) { + result = false; + break; + } + continue; + } + if (!append(value, IgnoreNull | IgnoreUndefined) || + m_tryCatch.HasTerminated()) { result = false; break; } @@ -267,6 +275,11 @@ V8ConsoleMessage::wrapArguments(V8InspectorSessionImpl* session, if (!inspectedContext) return nullptr; v8::Isolate* isolate = inspectedContext->isolate(); + // Wrapping the arguments can run JavaScript (i.e. getters while building + // previews or custom formatters), which might terminate execution. Don't + // call into V8 anymore in that case, since the next V8 API call would clear + // the pending termination exception. + if (isolate->IsExecutionTerminating()) return nullptr; v8::HandleScope handles(isolate); v8::Local<v8::Context> context = inspectedContext->context(); @@ -287,6 +300,7 @@ V8ConsoleMessage::wrapArguments(V8InspectorSessionImpl* session, if (array->Set(context, 0, secondArgument).IsJust()) { columns = array; } + if (tryCatch.HasTerminated()) return nullptr; } } std::unique_ptr<protocol::Runtime::RemoteObject> wrapped = @@ -480,6 +494,7 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForConsoleAPI( } bool sep = false; for (v8::Local<v8::Value> arg : arguments) { + if (isolate->IsExecutionTerminating()) break; if (sep) { message->m_message += String16(" "); } else { @@ -606,6 +621,18 @@ void V8ConsoleMessageStorage::addMessage( return; } + // Notifying the sessions above can run arbitrary JavaScript (i.e. custom + // formatters when generating previews for the message arguments), which + // might destroy the context that the message belongs to. In that case + // contextDestroyed() was already called on this storage, but since the + // message is not yet in m_messages, its arguments were not released, and + // would keep objects from the destroyed context alive. So we release them + // here, just like contextDestroyed() would have done. + if (int contextId = message->contextId(); + contextId && inspector->contextGroupId(contextId) != contextGroupId) { + message->contextDestroyed(contextId); + } + DCHECK(m_messages.size() <= maxConsoleMessageCount); if (m_messages.size() == maxConsoleMessageCount) { m_estimatedSize -= m_messages.front()->estimatedSize(); diff --git a/deps/v8/src/inspector/v8-console-message.h b/deps/v8/src/inspector/v8-console-message.h index b3c40d8f3a68..4f74e8a931ea 100644 --- a/deps/v8/src/inspector/v8-console-message.h +++ b/deps/v8/src/inspector/v8-console-message.h @@ -71,6 +71,7 @@ class V8ConsoleMessage { void reportToFrontend(protocol::Runtime::Frontend*, V8InspectorSessionImpl*, bool generatePreview) const; ConsoleAPIType type() const; + int contextId() const { return m_contextId; } void contextDestroyed(int contextId); int estimatedSize() const { diff --git a/deps/v8/src/inspector/v8-console.cc b/deps/v8/src/inspector/v8-console.cc index 4679f5fe420f..ddb787f90cca 100644 --- a/deps/v8/src/inspector/v8-console.cc +++ b/deps/v8/src/inspector/v8-console.cc @@ -76,8 +76,16 @@ class ConsoleHelper { return m_inspector->sessionById(groupId(), sessionId); } + // Returns the console message storage for the current context group, or + // nullptr if the current context is not (or no longer) associated with any + // context group. The latter can happen for example when user JavaScript + // (i.e. a `toString()` method on a label argument) causes the embedder to + // destroy the current context. In that case we must not create a storage + // for the (invalid) context group 0, since that would never be cleaned up. V8ConsoleMessageStorage* consoleMessageStorage() { - return m_inspector->ensureConsoleMessageStorage(groupId()); + int contextGroupId = groupId(); + if (!contextGroupId) return nullptr; + return m_inspector->ensureConsoleMessageStorage(contextGroupId); } void reportCall(ConsoleAPIType type) { @@ -150,12 +158,13 @@ class ConsoleHelper { m_inspector->client()->currentTimeMS(), type, arguments, consoleContextToString(isolate(), m_consoleContext), std::move(stackTrace)); + if (!groupId()) return; consoleMessageStorage()->addMessage(std::move(message)); } void reportDeprecatedCall(const char* id, const String16& message) { - if (!consoleMessageStorage()->shouldReportDeprecationMessage(contextId(), - id)) { + V8ConsoleMessageStorage* storage = consoleMessageStorage(); + if (!storage || !storage->shouldReportDeprecationMessage(contextId(), id)) { return; } auto arguments = @@ -169,16 +178,16 @@ class ConsoleHelper { return m_info[0]->BooleanValue(m_inspector->isolate()); } - v8::Local<v8::String> firstArgToString() { + // Returns the first argument converted to a string, or "default" if the + // first argument is missing or undefined. Returns an empty MaybeLocal if + // the conversion throws an exception or terminates execution. + v8::MaybeLocal<v8::String> firstArgToString() { if (V8_LIKELY(m_info.Length() > 0)) { v8::Local<v8::Value> arg = m_info[0]; if (V8_LIKELY(arg->IsString())) { return arg.As<v8::String>(); } - v8::Local<v8::String> label; - if (!arg->IsUndefined() && arg->ToString(context()).ToLocal(&label)) { - return label; - } + if (!arg->IsUndefined()) return arg->ToString(context()); } return toV8StringInternalized(isolate(), "default"); } @@ -214,7 +223,7 @@ class ConsoleHelper { void createBoundFunctionProperty( v8::Local<v8::Context> context, v8::Local<v8::Object> console, - v8::Local<v8::Value> data, const char* name, v8::FunctionCallback callback, + v8::Local<v8::Data> data, const char* name, v8::FunctionCallback callback, v8::SideEffectType side_effect_type = v8::SideEffectType::kHasSideEffect) { v8::Local<v8::String> funcName = toV8StringInternalized(v8::Isolate::GetCurrent(), name); @@ -339,12 +348,20 @@ void V8Console::Count(const v8::debug::ConsoleCallArguments& info, TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::Count"); ConsoleHelper helper(info, consoleContext, m_inspector); - String16 label = - toProtocolString(m_inspector->isolate(), helper.firstArgToString()); - int count = helper.consoleMessageStorage()->count(helper.contextId(), - consoleContext.id(), label); - helper.reportCallWithArgument(ConsoleAPIType::kCount, - label + ": " + String16::fromInteger(count)); + v8::Local<v8::String> v8Label; + if (!helper.firstArgToString().ToLocal(&v8Label)) { + TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("v8.inspector")); + return; + } + String16 label = toProtocolString(m_inspector->isolate(), v8Label); + // Converting the label to a string above can run arbitrary JavaScript, + // which might destroy the current context. + int count = 0; + if (V8ConsoleMessageStorage* storage = helper.consoleMessageStorage()) { + count = storage->count(helper.contextId(), consoleContext.id(), label); + helper.reportCallWithArgument(ConsoleAPIType::kCount, + label + ": " + String16::fromInteger(count)); + } TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "label", label.utf8().c_str(), "count", count); } @@ -354,10 +371,17 @@ void V8Console::CountReset(const v8::debug::ConsoleCallArguments& info, TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::CountReset"); ConsoleHelper helper(info, consoleContext, m_inspector); - String16 label = - toProtocolString(m_inspector->isolate(), helper.firstArgToString()); - if (!helper.consoleMessageStorage()->countReset(helper.contextId(), - consoleContext.id(), label)) { + v8::Local<v8::String> v8Label; + if (!helper.firstArgToString().ToLocal(&v8Label)) { + TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("v8.inspector")); + return; + } + String16 label = toProtocolString(m_inspector->isolate(), v8Label); + // Converting the label to a string above can run arbitrary JavaScript, + // which might destroy the current context. + V8ConsoleMessageStorage* storage = helper.consoleMessageStorage(); + if (storage && + !storage->countReset(helper.contextId(), consoleContext.id(), label)) { helper.reportCallWithArgument(ConsoleAPIType::kWarning, "Count for '" + label + "' does not exist"); } @@ -378,6 +402,7 @@ void V8Console::Assert(const v8::debug::ConsoleCallArguments& info, arguments.push_back(toV8String(isolate, String16("console.assert"))); } helper.reportCall(ConsoleAPIType::kAssert, arguments); + if (!helper.groupId() || isolate->IsExecutionTerminating()) return; m_inspector->debugger()->breakProgramOnAssert(helper.groupId()); } @@ -386,8 +411,12 @@ void V8Console::Profile(const v8::debug::ConsoleCallArguments& info, TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::Profile"); ConsoleHelper helper(info, consoleContext, m_inspector); - String16 title = - toProtocolString(m_inspector->isolate(), helper.firstArgToString()); + v8::Local<v8::String> v8Title; + if (!helper.firstArgToString().ToLocal(&v8Title)) { + TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("v8.inspector")); + return; + } + String16 title = toProtocolString(m_inspector->isolate(), v8Title); helper.forEachSession([&title](V8InspectorSessionImpl* session) { if (session->profilerAgent()) { session->profilerAgent()->consoleProfile(title); @@ -402,8 +431,12 @@ void V8Console::ProfileEnd(const v8::debug::ConsoleCallArguments& info, TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::ProfileEnd"); ConsoleHelper helper(info, consoleContext, m_inspector); - String16 title = - toProtocolString(m_inspector->isolate(), helper.firstArgToString()); + v8::Local<v8::String> v8Title; + if (!helper.firstArgToString().ToLocal(&v8Title)) { + TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("v8.inspector")); + return; + } + String16 title = toProtocolString(m_inspector->isolate(), v8Title); helper.forEachSession([&title](V8InspectorSessionImpl* session) { if (session->profilerAgent()) { session->profilerAgent()->consoleProfileEnd(title); @@ -417,10 +450,14 @@ void V8Console::Time(const v8::debug::ConsoleCallArguments& info, const v8::debug::ConsoleContext& consoleContext) { TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::Time"); ConsoleHelper helper(info, consoleContext, m_inspector); - v8::Local<v8::String> label = helper.firstArgToString(); + v8::Local<v8::String> label; + if (!helper.firstArgToString().ToLocal(&label)) return; String16 protocolLabel = toProtocolString(m_inspector->isolate(), label); - if (!helper.consoleMessageStorage()->time( - helper.contextId(), consoleContext.id(), protocolLabel)) { + // Converting the label to a string above can run arbitrary JavaScript, + // which might destroy the current context. + V8ConsoleMessageStorage* storage = helper.consoleMessageStorage(); + if (!storage) return; + if (!storage->time(helper.contextId(), consoleContext.id(), protocolLabel)) { helper.reportCallWithArgument( ConsoleAPIType::kWarning, "Timer '" + protocolLabel + "' already exists"); @@ -433,10 +470,15 @@ void V8Console::TimeLog(const v8::debug::ConsoleCallArguments& info, const v8::debug::ConsoleContext& consoleContext) { TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::TimeLog"); ConsoleHelper helper(info, consoleContext, m_inspector); - v8::Local<v8::String> label = helper.firstArgToString(); + v8::Local<v8::String> label; + if (!helper.firstArgToString().ToLocal(&label)) return; String16 protocolLabel = toProtocolString(m_inspector->isolate(), label); - std::optional<double> elapsed = helper.consoleMessageStorage()->timeLog( - helper.contextId(), consoleContext.id(), protocolLabel); + // Converting the label to a string above can run arbitrary JavaScript, + // which might destroy the current context. + V8ConsoleMessageStorage* storage = helper.consoleMessageStorage(); + if (!storage) return; + std::optional<double> elapsed = + storage->timeLog(helper.contextId(), consoleContext.id(), protocolLabel); if (!elapsed.has_value()) { helper.reportCallWithArgument( ConsoleAPIType::kWarning, @@ -452,10 +494,15 @@ void V8Console::TimeEnd(const v8::debug::ConsoleCallArguments& info, const v8::debug::ConsoleContext& consoleContext) { TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::TimeEnd"); ConsoleHelper helper(info, consoleContext, m_inspector); - v8::Local<v8::String> label = helper.firstArgToString(); + v8::Local<v8::String> label; + if (!helper.firstArgToString().ToLocal(&label)) return; String16 protocolLabel = toProtocolString(m_inspector->isolate(), label); - std::optional<double> elapsed = helper.consoleMessageStorage()->timeEnd( - helper.contextId(), consoleContext.id(), protocolLabel); + // Converting the label to a string above can run arbitrary JavaScript, + // which might destroy the current context. + V8ConsoleMessageStorage* storage = helper.consoleMessageStorage(); + if (!storage) return; + std::optional<double> elapsed = + storage->timeEnd(helper.contextId(), consoleContext.id(), protocolLabel); if (!elapsed.has_value()) { helper.reportCallWithArgument( ConsoleAPIType::kWarning, @@ -473,7 +520,8 @@ void V8Console::TimeStamp(const v8::debug::ConsoleCallArguments& info, TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.inspector"), "V8Console::TimeStamp"); ConsoleHelper helper(info, consoleContext, m_inspector); - v8::Local<v8::String> label = helper.firstArgToString(); + v8::Local<v8::String> label; + if (!helper.firstArgToString().ToLocal(&label)) return; v8::Isolate* isolate = m_inspector->isolate(); v8::LocalVector<v8::Value> args(isolate); @@ -532,26 +580,6 @@ void V8Console::createTask(const v8::FunctionCallbackInfo<v8::Value>& info) { info.GetReturnValue().Set(task); } -v8::Local<v8::Object> V8Console::wrapConsole(v8::Local<v8::Context> context) { - v8::Isolate* isolate = m_inspector->isolate(); - if (!m_consoleWrapper.IsEmpty() && context == m_consoleContext) { - return m_consoleWrapper.Get(isolate); - } - if (m_consoleTemplate.IsEmpty()) { - v8::Local<v8::FunctionTemplate> consTemplate = - v8::FunctionTemplate::New(isolate); - m_consoleTemplate.Reset(isolate, consTemplate->InstanceTemplate()); - } - v8::Local<v8::Object> consoleWrapper = - m_consoleTemplate.Get(isolate)->NewInstance(context).ToLocalChecked(); - v8::Object::Wrap<kPointerTag>(isolate, consoleWrapper, this); - m_consoleWrapper.Reset(isolate, consoleWrapper); - m_consoleWrapper.SetWeak(); - m_consoleContext.Reset(isolate, context); - m_consoleContext.SetWeak(); - return consoleWrapper; -} - v8::Local<v8::ObjectTemplate> V8Console::taskTemplate() { v8::Isolate* isolate = m_inspector->isolate(); if (!m_taskTemplate.IsEmpty()) { @@ -563,9 +591,8 @@ v8::Local<v8::ObjectTemplate> V8Console::taskTemplate() { v8::Local<v8::ObjectTemplate> taskTemplate = consTemplate->InstanceTemplate(); v8::Local<v8::Signature> signature = v8::Signature::New(isolate, consTemplate); - v8::Local<v8::FunctionTemplate> funcTemplate = - v8::FunctionTemplate::New(isolate, &TaskInfo::runTask, - v8::Local<v8::Value>(), signature); + v8::Local<v8::FunctionTemplate> funcTemplate = v8::FunctionTemplate::New( + isolate, &TaskInfo::runTask, v8::Local<v8::Value>(), signature); taskTemplate->Set(isolate, "run", funcTemplate); m_taskTemplate.Reset(isolate, taskTemplate); @@ -633,11 +660,13 @@ void TaskInfo::runTask(const v8::FunctionCallbackInfo<v8::Value>& info) { console->m_inspector->asyncTaskFinished(taskInfo->Id()); } +void V8Console::CommandLineAPIData::Trace(cppgc::Visitor* visitor) const { + visitor->Trace(m_console); +} + void V8Console::Trace(cppgc::Visitor* visitor) const { visitor->Trace(m_taskTemplate); - visitor->Trace(m_consoleTemplate); v8::debug::ConsoleDelegate::Trace(visitor); - v8::Object::Wrappable::Trace(visitor); } void V8Console::keysCallback(const v8::FunctionCallbackInfo<v8::Value>& info, @@ -868,7 +897,8 @@ void V8Console::inspectedObject(const v8::FunctionCallbackInfo<v8::Value>& info, void V8Console::installMemoryGetter(v8::Local<v8::Context> context, v8::Local<v8::Object> console) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Local<v8::Object> data = wrapConsole(context); + v8::Local<v8::Data> data = + v8::CppHeapExternal::New<V8Console>(isolate, this, kPointerTag); console->SetAccessorProperty( toV8StringInternalized(isolate, "memory"), v8::Function::New( @@ -884,7 +914,9 @@ void V8Console::installMemoryGetter(v8::Local<v8::Context> context, void V8Console::installAsyncStackTaggingAPI(v8::Local<v8::Context> context, v8::Local<v8::Object> console) { - v8::Local<v8::Object> data = wrapConsole(context); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local<v8::Data> data = + v8::CppHeapExternal::New<V8Console>(isolate, this, kPointerTag); v8::MicrotasksScope microtasksScope(context, v8::MicrotasksScope::kDoNotRunMicrotasks); @@ -905,24 +937,28 @@ v8::Local<v8::Object> V8Console::createCommandLineAPI( DCHECK(success); USE(success); - v8::Local<v8::Array> data = v8::Array::New(isolate, 2); - data->CreateDataProperty(context, 0, wrapConsole(context)).Check(); - data->CreateDataProperty(context, 1, v8::Integer::New(isolate, sessionId)) - .Check(); + v8::Local<v8::Data> consoleData = + v8::CppHeapExternal::New<V8Console>(isolate, this, kPointerTag); - createBoundFunctionProperty(context, commandLineAPI, data, "dir", + createBoundFunctionProperty(context, commandLineAPI, consoleData, "dir", &V8Console::call<&V8Console::Dir>); - createBoundFunctionProperty(context, commandLineAPI, data, "dirxml", + createBoundFunctionProperty(context, commandLineAPI, consoleData, "dirxml", &V8Console::call<&V8Console::DirXml>); - createBoundFunctionProperty(context, commandLineAPI, data, "profile", + createBoundFunctionProperty(context, commandLineAPI, consoleData, "profile", &V8Console::call<&V8Console::Profile>); - createBoundFunctionProperty(context, commandLineAPI, data, "profileEnd", + createBoundFunctionProperty(context, commandLineAPI, consoleData, + "profileEnd", &V8Console::call<&V8Console::ProfileEnd>); - createBoundFunctionProperty(context, commandLineAPI, data, "clear", + createBoundFunctionProperty(context, commandLineAPI, consoleData, "clear", &V8Console::call<&V8Console::Clear>); - createBoundFunctionProperty(context, commandLineAPI, data, "table", + createBoundFunctionProperty(context, commandLineAPI, consoleData, "table", &V8Console::call<&V8Console::Table>); + auto* sessionData = cppgc::MakeGarbageCollected<CommandLineAPIData>( + isolate->GetCppHeap()->GetAllocationHandle(), this, sessionId); + v8::Local<v8::Data> data = v8::CppHeapExternal::New<CommandLineAPIData>( + isolate, sessionData, CommandLineAPIData::kPointerTag); + createBoundFunctionProperty(context, commandLineAPI, data, "keys", &V8Console::call<&V8Console::keysCallback>, v8::SideEffectType::kHasNoSideEffect); @@ -980,17 +1016,24 @@ static bool isCommandLineAPIGetter(const String16& name) { ((name[1] >= '0' && name[1] <= '4') || name[1] == '_'); } +void V8Console::CommandLineAPIScope::Data::Trace( + cppgc::Visitor* visitor) const { + visitor->Trace(m_commandLineAPI); + visitor->Trace(m_installedMethods); +} + void V8Console::CommandLineAPIScope::accessorGetterCallback( v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { - v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); - v8::Local<v8::Array> data = info.DataV2().As<v8::Value>().As<v8::Array>(); - v8::Local<v8::Value> data0; - if (!data->Get(context, kCommandLineAPIIndex).ToLocal(&data0) || - !data0->IsObject()) { + v8::Isolate* isolate = info.GetIsolate(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + Data* data = info.DataV2().As<v8::CppHeapExternal>()->Value<Data>( + isolate, {Data::kPointerTag, Data::kPointerTag}); + CHECK_NOT_NULL(data); + v8::Local<v8::Object> commandLineAPI = data->commandLineAPI(isolate); + if (commandLineAPI.IsEmpty()) { USE(info.Holder()->Delete(context, name).FromMaybe(false)); return; } - v8::Local<v8::Object> commandLineAPI = data0.As<v8::Object>(); v8::Local<v8::Value> value; if (!commandLineAPI->Get(context, name).ToLocal(&value)) return; @@ -1012,13 +1055,12 @@ void V8Console::CommandLineAPIScope::accessorGetterCallback( void V8Console::CommandLineAPIScope::accessorSetterCallback( v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Boolean>& info) { - v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); - v8::Local<v8::Array> data = info.DataV2().As<v8::Value>().As<v8::Array>(); - v8::Local<v8::Value> data0; - if (!data->Get(context, kCommandLineAPIIndex).ToLocal(&data0) || - !data0->IsObject()) { - return; - } + v8::Isolate* isolate = info.GetIsolate(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + Data* data = info.DataV2().As<v8::CppHeapExternal>()->Value<Data>( + isolate, {Data::kPointerTag, Data::kPointerTag}); + CHECK_NOT_NULL(data); + if (data->commandLineAPI(isolate).IsEmpty()) return; if (!info.Holder()->Delete(context, name).FromMaybe(false)) return; if (!info.Holder() @@ -1027,11 +1069,11 @@ void V8Console::CommandLineAPIScope::accessorSetterCallback( return; } - for (uint32_t i = kFirstInstalledMethodIndex; i < data->Length(); ++i) { - v8::Local<v8::Value> methodName; - if (!data->Get(context, i).ToLocal(&methodName)) continue; + v8::Local<v8::PrimitiveArray> methods = data->installedMethods(isolate); + for (int i = 0; i < methods->Length(); ++i) { + v8::Local<v8::Primitive> methodName = methods->Get(isolate, i); if (!name->StrictEquals(methodName)) continue; - data->Set(context, i, v8::Undefined(info.GetIsolate())).Check(); + methods->Set(isolate, i, v8::Undefined(isolate)); break; } } @@ -1077,20 +1119,27 @@ V8Console::CommandLineAPIScope::CommandLineAPIScope( v8::Local<v8::Object> global) : m_isolate(v8::Isolate::GetCurrent()), m_context(m_isolate, context), - m_data(m_isolate, v8::Array::New(isolate(), kHeaderLength)), - m_global(m_isolate, global) { + m_global(m_isolate, global), + m_data(cppgc::MakeGarbageCollected<Data>( + m_isolate->GetCppHeap()->GetAllocationHandle(), m_isolate, + commandLineAPI)) { v8::MicrotasksScope microtasksScope(context, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local<v8::Array> names; if (!commandLineAPI->GetOwnPropertyNames(context).ToLocal(&names)) return; - data() - ->CreateDataProperty(context, kCommandLineAPIIndex, commandLineAPI) - .Check(); + v8::Local<v8::PrimitiveArray> installedMethods = + v8::PrimitiveArray::New(m_isolate, names->Length()); + m_data->setInstalledMethods(m_isolate, installedMethods); + v8::Local<v8::Data> externalData = v8::CppHeapExternal::New<Data>( + m_isolate, m_data.Get(), Data::kPointerTag); for (uint32_t i = 0; i < names->Length(); ++i) { v8::Local<v8::Value> name; if (!names->Get(context, i).ToLocal(&name) || !name->IsName()) continue; - if (global->Has(context, name).FromMaybe(true)) continue; + if (global->HasRealNamedProperty(context, name.As<v8::Name>()) + .FromMaybe(true)) { + continue; + } const v8::SideEffectType get_accessor_side_effect_type = IsUnsafeCommandLineAPIFn(context, commandLineAPI, name.As<v8::Name>(), @@ -1101,30 +1150,30 @@ V8Console::CommandLineAPIScope::CommandLineAPIScope( ->SetNativeDataProperty( context, name.As<v8::Name>(), CommandLineAPIScope::accessorGetterCallback, - CommandLineAPIScope::accessorSetterCallback, data(), + CommandLineAPIScope::accessorSetterCallback, externalData, v8::DontEnum, get_accessor_side_effect_type) .FromMaybe(false)) { continue; } - data()->CreateDataProperty(context, data()->Length(), name).Check(); + installedMethods->Set(m_isolate, i, name.As<v8::Name>()); } } V8Console::CommandLineAPIScope::~CommandLineAPIScope() { + m_data->clearCommandLineAPI(); if (m_isolate->IsExecutionTerminating()) return; v8::MicrotasksScope microtasksScope(context(), v8::MicrotasksScope::kDoNotRunMicrotasks); - data() - ->CreateDataProperty(context(), kCommandLineAPIIndex, v8::Null(isolate())) - .Check(); - for (uint32_t i = kFirstInstalledMethodIndex; i < data()->Length(); ++i) { - v8::Local<v8::Value> name; - if (data()->Get(context(), i).ToLocal(&name) && name->IsString()) { + v8::Local<v8::PrimitiveArray> names = m_data->installedMethods(m_isolate); + if (names.IsEmpty()) return; + for (int i = 0; i < names->Length(); ++i) { + v8::Local<v8::Primitive> name = names->Get(m_isolate, i); + if (name->IsName()) { v8::Local<v8::Value> descriptor; - bool success = - global() - ->GetOwnPropertyDescriptor(context(), name.As<v8::String>()) - .ToLocal(&descriptor); + bool success = global() + ->GetOwnPropertyDescriptor(context(), + name.As<v8::Name>()) + .ToLocal(&descriptor); USE(success); } } diff --git a/deps/v8/src/inspector/v8-console.h b/deps/v8/src/inspector/v8-console.h index f6df378d2b9c..fb35ac86c556 100644 --- a/deps/v8/src/inspector/v8-console.h +++ b/deps/v8/src/inspector/v8-console.h @@ -7,11 +7,14 @@ #include "include/cppgc/garbage-collected.h" #include "include/cppgc/member.h" +#include "include/cppgc/persistent.h" #include "include/v8-array-buffer.h" #include "include/v8-container.h" +#include "include/v8-cpp-heap-external.h" #include "include/v8-external.h" #include "include/v8-local-handle.h" #include "include/v8-object.h" +#include "include/v8-primitive.h" #include "include/v8-traced-handle.h" #include "src/base/macros.h" #include "src/debug/interface-types.h" @@ -31,13 +34,12 @@ class V8InspectorImpl; // Console API // https://console.spec.whatwg.org/#console-namespace -class V8Console final : public v8::Object::Wrappable, +class V8Console final : public cppgc::GarbageCollected<V8Console>, public v8::debug::ConsoleDelegate { public: static constexpr v8::CppHeapPointerTag kPointerTag = v8::internal::kInspectorV8ConsoleTag; - v8::Local<v8::Object> wrapConsole(v8::Local<v8::Context> context); void Trace(cppgc::Visitor* visitor) const override; v8::Local<v8::Object> createCommandLineAPI(v8::Local<v8::Context> context, @@ -57,9 +59,35 @@ class V8Console final : public v8::Object::Wrappable, CommandLineAPIScope& operator=(const CommandLineAPIScope&) = delete; private: - constexpr static uint32_t kCommandLineAPIIndex = 0; - constexpr static uint32_t kFirstInstalledMethodIndex = 1; - constexpr static uint32_t kHeaderLength = kFirstInstalledMethodIndex; + class Data : public cppgc::GarbageCollected<Data> { + public: + static constexpr v8::CppHeapPointerTag kPointerTag = + v8::internal::kInspectorCommandLineAPIScopeDataTag; + + Data(v8::Isolate* isolate, v8::Local<v8::Object> commandLineAPI) + : m_commandLineAPI(isolate, commandLineAPI) {} + + void Trace(cppgc::Visitor* visitor) const; + + v8::Local<v8::Object> commandLineAPI(v8::Isolate* isolate) const { + return m_commandLineAPI.Get(isolate); + } + void clearCommandLineAPI() { m_commandLineAPI.Reset(); } + + v8::Local<v8::PrimitiveArray> installedMethods( + v8::Isolate* isolate) const { + return m_installedMethods.Get(isolate); + } + void setInstalledMethods( + v8::Isolate* isolate, + v8::Local<v8::PrimitiveArray> installedMethods) { + m_installedMethods.Reset(isolate, installedMethods); + } + + private: + v8::TracedReference<v8::Object> m_commandLineAPI; + v8::TracedReference<v8::PrimitiveArray> m_installedMethods; + }; static void accessorGetterCallback( v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>&); @@ -69,27 +97,42 @@ class V8Console final : public v8::Object::Wrappable, v8::Isolate* isolate() const { return m_isolate; } v8::Local<v8::Context> context() const { return m_context.Get(isolate()); } - v8::Local<v8::Array> data() const { return m_data.Get(isolate()); } v8::Local<v8::Object> global() const { return m_global.Get(isolate()); } v8::Isolate* m_isolate; v8::Global<v8::Context> m_context; - v8::Global<v8::Array> m_data; v8::Global<v8::Object> m_global; + cppgc::Persistent<Data> m_data; }; explicit V8Console(V8InspectorImpl* inspector); void clearInspector() { m_inspector = nullptr; m_taskTemplate.Reset(); - m_consoleTemplate.Reset(); - m_consoleWrapper.Reset(); - m_consoleContext.Reset(); } private: friend class TaskInfo; + class CommandLineAPIData + : public cppgc::GarbageCollected<CommandLineAPIData> { + public: + static constexpr v8::CppHeapPointerTag kPointerTag = + v8::internal::kInspectorCommandLineAPIDataTag; + + CommandLineAPIData(V8Console* console, int sessionId) + : m_console(console), m_sessionId(sessionId) {} + + void Trace(cppgc::Visitor* visitor) const; + + V8Console* console() const { return m_console.Get(); } + int sessionId() const { return m_sessionId; } + + private: + cppgc::Member<V8Console> m_console; + int m_sessionId; + }; + void Debug(const v8::debug::ConsoleCallArguments&, const v8::debug::ConsoleContext& consoleContext) override; void Error(const v8::debug::ConsoleCallArguments&, @@ -137,8 +180,9 @@ class V8Console final : public v8::Object::Wrappable, template <void (V8Console::*func)(const v8::FunctionCallbackInfo<v8::Value>&)> static void call(const v8::FunctionCallbackInfo<v8::Value>& info) { - V8Console* console = v8::Object::Unwrap<kPointerTag, V8Console>( - info.GetIsolate(), info.DataV2().As<v8::Value>().As<v8::Object>()); + V8Console* console = + info.DataV2().As<v8::CppHeapExternal>()->Value<V8Console>( + info.GetIsolate(), {kPointerTag, kPointerTag}); CHECK_NOT_NULL(console); CHECK_NOT_NULL(console->m_inspector); (console->*func)(info); @@ -146,38 +190,24 @@ class V8Console final : public v8::Object::Wrappable, template <void (V8Console::*func)(const v8::FunctionCallbackInfo<v8::Value>&, int)> static void call(const v8::FunctionCallbackInfo<v8::Value>& info) { - v8::Local<v8::Array> data = info.DataV2().As<v8::Value>().As<v8::Array>(); - v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); - v8::Local<v8::Value> console_value; - if (!data->Get(context, 0).ToLocal(&console_value) || - !console_value->IsObject()) { - return; - } - V8Console* console = v8::Object::Unwrap<kPointerTag, V8Console>( - info.GetIsolate(), console_value.As<v8::Object>()); + CommandLineAPIData* data = + info.DataV2().As<v8::CppHeapExternal>()->Value<CommandLineAPIData>( + info.GetIsolate(), + {CommandLineAPIData::kPointerTag, CommandLineAPIData::kPointerTag}); + CHECK_NOT_NULL(data); + V8Console* console = data->console(); CHECK_NOT_NULL(console); - v8::Local<v8::Value> session_value; - if (!data->Get(context, 1).ToLocal(&session_value) || - !session_value->IsInt32()) { - return; - } - int sessionId = session_value.As<v8::Int32>()->Value(); - (console->*func)(info, sessionId); + CHECK_NOT_NULL(console->m_inspector); + (console->*func)(info, data->sessionId()); } - template <void (V8Console::*func)(const v8::debug::ConsoleCallArguments&, const v8::debug::ConsoleContext&)> static void call(const v8::FunctionCallbackInfo<v8::Value>& info) { - v8::Local<v8::Array> data = info.DataV2().As<v8::Value>().As<v8::Array>(); - v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext(); - v8::Local<v8::Value> console_value; - if (!data->Get(context, 0).ToLocal(&console_value) || - !console_value->IsObject()) { - return; - } - V8Console* console = v8::Object::Unwrap<kPointerTag, V8Console>( - info.GetIsolate(), console_value.As<v8::Object>()); + V8Console* console = + info.DataV2().As<v8::CppHeapExternal>()->Value<V8Console>( + info.GetIsolate(), {kPointerTag, kPointerTag}); CHECK_NOT_NULL(console); + CHECK_NOT_NULL(console->m_inspector); v8::debug::ConsoleCallArguments args(info); (console->*func)(args, v8::debug::ConsoleContext()); } @@ -242,16 +272,6 @@ class V8Console final : public v8::Object::Wrappable, // instantiation. Use `taskTemplate()` to retrieve the lazily created // template. v8::TracedReference<v8::ObjectTemplate> m_taskTemplate; - v8::TracedReference<v8::ObjectTemplate> m_consoleTemplate; - - // Weak references: - // - // We cache the V8Console wrapper object for the current context in - // `m_consoleWrapper`. `m_consoleContext` holds a weak reference to the - // context for which `m_consoleWrapper` was created, ensuring we only reuse - // the cached wrapper if the context remains the same. - v8::Global<v8::Object> m_consoleWrapper; - v8::Global<v8::Context> m_consoleContext; }; /** diff --git a/deps/v8/src/inspector/v8-debugger-agent-impl.cc b/deps/v8/src/inspector/v8-debugger-agent-impl.cc index 1c7507ddda33..7af4d6f2c90b 100644 --- a/deps/v8/src/inspector/v8-debugger-agent-impl.cc +++ b/deps/v8/src/inspector/v8-debugger-agent-impl.cc @@ -178,6 +178,27 @@ bool positionComparator(const std::pair<int, int>& a, return a.second < b.second; } +// {ranges} is a sorted list of [start, end) pairs, flattened into a single +// vector: [ranges[0], ranges[1]), [ranges[2], ranges[3]), ... A trailing +// start without an end extends to the end of the script. +// Returns true, iff [start, end) lies within a single range of {ranges}. +bool isWithinOneRange(const std::vector<std::pair<int, int>>& ranges, + const v8::debug::Location& start, + const v8::debug::Location& end) { + // The first boundary strictly after {start}. Its index is odd iff {start} + // lies within [ranges[2k], ranges[2k+1]). + auto itStartRange = std::upper_bound( + ranges.begin(), ranges.end(), + std::make_pair(start.GetLineNumber(), start.GetColumnNumber()), + positionComparator); + auto itEndRange = std::lower_bound( + itStartRange, ranges.end(), + std::make_pair(end.GetLineNumber(), end.GetColumnNumber()), + positionComparator); + return itStartRange == itEndRange && + std::distance(ranges.begin(), itStartRange) % 2; +} + std::unique_ptr<protocol::DictionaryValue> breakpointHint( const V8DebuggerScript& script, int breakpointLineNumber, int breakpointColumnNumber, int actualLineNumber, int actualColumnNumber) { @@ -338,8 +359,6 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator, if (!injectedScript) return Response::Success(); if (iterator->Done()) return Response::Success(); - String16 scriptId = String16::fromInteger(iterator->GetScriptId()); - for (; !iterator->Done(); iterator->Advance()) { std::unique_ptr<RemoteObject> object; Response result = @@ -357,6 +376,7 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator, if (!name.isEmpty()) scope->setName(name); if (iterator->HasLocationInfo()) { + String16 scriptId = String16::fromInteger(iterator->GetScriptId()); v8::debug::Location start = iterator->GetStartLocation(); scope->setStartLocation(protocol::Debugger::Location::create() .setScriptId(scriptId) @@ -371,8 +391,15 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator, .setColumnNumber(end.GetColumnNumber()) .build()); } - if (!iterator->DeclaresLocals()) { - scope->setEmpty(true); + switch (iterator->GetVariableInfo()) { + case v8::debug::ScopeIterator::VariableInfo::kEmpty: + scope->setEmptyReason(Scope::EmptyReasonEnum::NoVariables); + break; + case v8::debug::ScopeIterator::VariableInfo::kAllUnavailable: + scope->setEmptyReason(Scope::EmptyReasonEnum::AllUnavailable); + break; + case v8::debug::ScopeIterator::VariableInfo::kAvailable: + break; } (*scopes)->emplace_back(std::move(scope)); } @@ -527,6 +554,7 @@ Response V8DebuggerAgentImpl::disable() { m_blackboxPattern.reset(); resetBlackboxedStateCache(); m_skipList.clear(); + m_enterRanges.clear(); m_scripts.clear(); m_cachedScripts.clear(); m_cachedScriptSize = 0; @@ -1031,6 +1059,7 @@ Response V8DebuggerAgentImpl::continueToLocation( if (!inspected) { return Response::ServerError("Cannot continue to specified location"); } + m_skipList.clear(); v8::HandleScope handleScope(m_isolate); v8::Context::Scope contextScope(inspected->context()); return m_debugger->continueToLocation( @@ -1105,21 +1134,7 @@ bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId, auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId); if (itBlackboxedPositions == m_blackboxedPositions.end()) return false; - const std::vector<std::pair<int, int>>& ranges = - itBlackboxedPositions->second; - auto itStartRange = std::lower_bound( - ranges.begin(), ranges.end(), - std::make_pair(start.GetLineNumber(), start.GetColumnNumber()), - positionComparator); - auto itEndRange = std::lower_bound( - itStartRange, ranges.end(), - std::make_pair(end.GetLineNumber(), end.GetColumnNumber()), - positionComparator); - // Ranges array contains positions in script where blackbox state is changed. - // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is - // blackboxed... - return itStartRange == itEndRange && - std::distance(ranges.begin(), itStartRange) % 2; + return isWithinOneRange(itBlackboxedPositions->second, start, end); } bool V8DebuggerAgentImpl::shouldBeSkipped(const String16& scriptId, int line, @@ -1149,6 +1164,13 @@ bool V8DebuggerAgentImpl::shouldBeSkipped(const String16& scriptId, int line, return shouldSkip; } +bool V8DebuggerAgentImpl::shouldEnterFunction(const String16& scriptId, + const v8::debug::Location& start, + const v8::debug::Location& end) { + auto it = m_enterRanges.find(scriptId); + return it != m_enterRanges.end() && isWithinOneRange(it->second, start, end); +} + bool V8DebuggerAgentImpl::acceptsPause(bool isOOMBreak) const { return enabled() && (isOOMBreak || !m_skipAllPauses); } @@ -1271,6 +1293,7 @@ Response V8DebuggerAgentImpl::restartFrame( callFrameOrdinal)) { return Response::ServerError("Restarting frame failed"); } + m_skipList.clear(); m_session->releaseObjectGroup(kBacktraceObjectGroup); *newCallFrames = std::make_unique<Array<CallFrame>>(); return Response::Success(); @@ -1554,6 +1577,12 @@ Response V8DebuggerAgentImpl::pause() { Response V8DebuggerAgentImpl::resume(std::optional<bool> terminateOnResume) { if (!isPaused()) return Response::ServerError(kDebuggerNotPaused); + if (terminateOnResume.value_or(false) && + m_session->clientTrustLevel() != V8Inspector::kFullyTrusted) { + return Response::ServerError( + "`terminateOnResume` is not allowed for untrusted clients"); + } + m_skipList.clear(); m_session->releaseObjectGroup(kBacktraceObjectGroup); m_instrumentationFinished = true; @@ -1564,18 +1593,28 @@ Response V8DebuggerAgentImpl::resume(std::optional<bool> terminateOnResume) { Response V8DebuggerAgentImpl::stepOver( std::unique_ptr<protocol::Array<protocol::Debugger::LocationRange>> - inSkipList) { + inSkipList, + std::unique_ptr<protocol::Array<protocol::Debugger::LocationRange>> + inEnterRanges) { if (!isPaused()) return Response::ServerError(kDebuggerNotPaused); + // Only update the lists once both are valid. + decltype(m_skipList) skipList; + decltype(m_enterRanges) enterRanges; if (inSkipList) { - const Response res = processSkipList(*inSkipList); + const Response res = processLocationRanges(*inSkipList, &skipList); if (res.IsError()) return res; - } else { - m_skipList.clear(); } + if (inEnterRanges) { + const Response res = processLocationRanges(*inEnterRanges, &enterRanges); + if (res.IsError()) return res; + } + m_skipList = std::move(skipList); + m_enterRanges = std::move(enterRanges); m_session->releaseObjectGroup(kBacktraceObjectGroup); - m_debugger->stepOverStatement(m_session->contextGroupId()); + m_debugger->stepOverStatement(m_session->contextGroupId(), + !m_enterRanges.empty()); return Response::Success(); } @@ -1586,7 +1625,7 @@ Response V8DebuggerAgentImpl::stepInto( if (!isPaused()) return Response::ServerError(kDebuggerNotPaused); if (inSkipList) { - const Response res = processSkipList(*inSkipList); + const Response res = processLocationRanges(*inSkipList, &m_skipList); if (res.IsError()) return res; } else { m_skipList.clear(); @@ -1600,6 +1639,7 @@ Response V8DebuggerAgentImpl::stepInto( Response V8DebuggerAgentImpl::stepOut() { if (!isPaused()) return Response::ServerError(kDebuggerNotPaused); + m_skipList.clear(); m_session->releaseObjectGroup(kBacktraceObjectGroup); m_debugger->stepOutOfFunction(m_session->contextGroupId()); return Response::Success(); @@ -1886,7 +1926,7 @@ Response V8DebuggerAgentImpl::currentCallFrames( &inspectedContext); } String16 callFrameId = RemoteCallFrameId::serialize( - m_inspector->isolateId(), contextId, frameOrdinal); + m_session->isolateId(), contextId, frameOrdinal); v8::debug::Location loc = iterator->GetSourceLocation(); @@ -2250,6 +2290,10 @@ void V8DebuggerAgentImpl::didPause( v8::debug::ExceptionType exceptionType, bool isUncaught, v8::debug::BreakReasons breakReasons) { v8::HandleScope handles(m_isolate); + // The step that owned the skip list and enter ranges is over. Every new step + // command supplies its own. + m_skipList.clear(); + m_enterRanges.clear(); std::vector<BreakReason> hitReasons; @@ -2426,6 +2470,7 @@ void V8DebuggerAgentImpl::reset() { m_blackboxedPositions.clear(); resetBlackboxedStateCache(); m_skipList.clear(); + m_enterRanges.clear(); m_scripts.clear(); m_cachedScripts.clear(); m_cachedScriptSize = 0; @@ -2464,10 +2509,11 @@ V8DebuggerScript* V8DebuggerAgentImpl::getScriptById( return it->second.get(); } -Response V8DebuggerAgentImpl::processSkipList( - protocol::Array<protocol::Debugger::LocationRange>& skipList) { +Response V8DebuggerAgentImpl::processLocationRanges( + protocol::Array<protocol::Debugger::LocationRange>& ranges, + std::unordered_map<String16, std::vector<std::pair<int, int>>>* result) { std::unordered_map<String16, std::vector<std::pair<int, int>>> skipListInit; - for (std::unique_ptr<protocol::Debugger::LocationRange>& range : skipList) { + for (std::unique_ptr<protocol::Debugger::LocationRange>& range : ranges) { protocol::Debugger::ScriptPosition* start = range->getStart(); protocol::Debugger::ScriptPosition* end = range->getEnd(); String16 scriptId = range->getScriptId(); @@ -2496,7 +2542,7 @@ Response V8DebuggerAgentImpl::processSkipList( if (res.IsError()) return res; } - m_skipList = std::move(skipListInit); + *result = std::move(skipListInit); return Response::Success(); } diff --git a/deps/v8/src/inspector/v8-debugger-agent-impl.h b/deps/v8/src/inspector/v8-debugger-agent-impl.h index f250803a00e6..ef1cb2815a52 100644 --- a/deps/v8/src/inspector/v8-debugger-agent-impl.h +++ b/deps/v8/src/inspector/v8-debugger-agent-impl.h @@ -140,7 +140,9 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { Response resume(std::optional<bool> terminateOnResume) override; Response stepOver( std::unique_ptr<protocol::Array<protocol::Debugger::LocationRange>> - inSkipList) override; + inSkipList, + std::unique_ptr<protocol::Array<protocol::Debugger::LocationRange>> + inEnterRanges) override; Response stepInto( std::optional<bool> inBreakOnAsyncCall, std::unique_ptr<protocol::Array<protocol::Debugger::LocationRange>> @@ -206,6 +208,9 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { const v8::debug::Location& start, const v8::debug::Location& end); bool shouldBeSkipped(const String16& scriptId, int line, int column); + bool shouldEnterFunction(const String16& scriptId, + const v8::debug::Location& start, + const v8::debug::Location& end); bool acceptsPause(bool isOOMBreak) const; @@ -245,8 +250,11 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { void setScriptInstrumentationBreakpointIfNeeded(V8DebuggerScript* script); - Response processSkipList( - protocol::Array<protocol::Debugger::LocationRange>& skipList); + // Validates {ranges} and converts them into a map from script id to sorted + // range boundaries (see isWithinOneRange) in {result}. + Response processLocationRanges( + protocol::Array<protocol::Debugger::LocationRange>& ranges, + std::unordered_map<String16, std::vector<std::pair<int, int>>>* result); V8DebuggerScript* getScriptById( const String16& scriptId, @@ -313,6 +321,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { std::unordered_map<String16, std::vector<std::pair<int, int>>> m_blackboxedPositions; std::unordered_map<String16, std::vector<std::pair<int, int>>> m_skipList; + std::unordered_map<String16, std::vector<std::pair<int, int>>> m_enterRanges; std::unordered_set<String16> m_blackboxedExecutionContexts; struct BreakpointInfo { int line_number; diff --git a/deps/v8/src/inspector/v8-debugger.cc b/deps/v8/src/inspector/v8-debugger.cc index e163778471ab..8eef42568ba3 100644 --- a/deps/v8/src/inspector/v8-debugger.cc +++ b/deps/v8/src/inspector/v8-debugger.cc @@ -281,11 +281,13 @@ void V8Debugger::continueProgram(int targetContextGroupId, } else if (terminateOnResume) { v8::debug::SetTerminateOnResume(m_isolate); - v8::HandleScope handles(m_isolate); - v8::Local<v8::Context> context = - m_inspector->client()->ensureDefaultContextInGroup( - targetContextGroupId); - installTerminateExecutionCallbacks(context); + if (m_terminateExecutionReported) { + v8::HandleScope handles(m_isolate); + v8::Local<v8::Context> context = + m_inspector->client()->ensureDefaultContextInGroup( + targetContextGroupId); + installTerminateExecutionCallbacks(context); + } m_inspector->client()->quitMessageLoopOnPause(); } else { @@ -297,6 +299,7 @@ void V8Debugger::continueProgram(int targetContextGroupId, void V8Debugger::breakProgramOnAssert(int targetContextGroupId) { if (!enabled()) return; if (m_pauseOnExceptionsState == v8::debug::NoBreakOnException) return; + if (m_isolate->IsExecutionTerminating()) return; // Don't allow nested breaks. if (isPaused()) return; if (!canBreakProgram()) return; @@ -316,11 +319,12 @@ void V8Debugger::stepIntoStatement(int targetContextGroupId, continueProgram(targetContextGroupId); } -void V8Debugger::stepOverStatement(int targetContextGroupId) { +void V8Debugger::stepOverStatement(int targetContextGroupId, + bool enterFunctions) { DCHECK(isPaused()); DCHECK(targetContextGroupId); m_targetContextGroupId = targetContextGroupId; - v8::debug::PrepareStep(m_isolate, v8::debug::StepOver); + v8::debug::PrepareStep(m_isolate, v8::debug::StepOver, enterFunctions); continueProgram(targetContextGroupId); } @@ -524,6 +528,11 @@ void V8Debugger::handleProgramBreak( DCHECK(contextGroupId); m_pausedContextGroupId = contextGroupId; + // Breaks scheduled through an API interrupt (Debugger.pause, OOM) arrive + // here with JavaScript execution disallowed. Like the pause message loop, + // the paused and resumed notifications can reach an embedder channel that + // runs JavaScript. + v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate); m_inspector->forEachSession( contextGroupId, [&pausedContext, &exception, &breakpointIds, &exceptionType, &isUncaught, @@ -535,7 +544,6 @@ void V8Debugger::handleProgramBreak( } }); { - v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate); v8::Context::Scope scope(pausedContext); m_inspector->forEachSession( @@ -735,6 +743,23 @@ bool V8Debugger::ShouldBeSkipped(v8::Local<v8::debug::Script> script, int line, return hasAgents && allShouldBeSkipped; } +bool V8Debugger::ShouldEnterFunction(v8::Local<v8::debug::Script> script, + const v8::debug::Location& start, + const v8::debug::Location& end) { + int contextId; + if (!script->ContextId().To(&contextId)) return false; + bool shouldEnter = false; + String16 scriptId = String16::fromInteger(script->Id()); + m_inspector->forEachSession( + m_inspector->contextGroupId(contextId), + [&](V8InspectorSessionImpl* session) { + V8DebuggerAgentImpl* agent = session->debuggerAgent(); + if (!agent->enabled()) return; + shouldEnter |= agent->shouldEnterFunction(scriptId, start, end); + }); + return shouldEnter; +} + void V8Debugger::BreakpointConditionEvaluated( v8::Local<v8::Context> context, v8::debug::BreakpointId breakpoint_id, bool exception_thrown, v8::Local<v8::Value> exception) { @@ -850,7 +875,8 @@ v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes( }; for (; iterator && !iterator->Done(); advance()) { if (iterator->GetType() != v8::debug::ScopeIterator::ScopeTypeLocal && - !iterator->DeclaresLocals()) { + iterator->GetVariableInfo() == + v8::debug::ScopeIterator::VariableInfo::kEmpty) { continue; } v8::Local<v8::Object> scope = v8::Object::New(m_isolate); diff --git a/deps/v8/src/inspector/v8-debugger.h b/deps/v8/src/inspector/v8-debugger.h index 0172067e82af..b4a35c96c723 100644 --- a/deps/v8/src/inspector/v8-debugger.h +++ b/deps/v8/src/inspector/v8-debugger.h @@ -75,7 +75,7 @@ class V8Debugger : public v8::debug::DebugDelegate, void setPauseOnNextCall(bool, int targetContextGroupId); void stepIntoStatement(int targetContextGroupId, bool breakOnAsyncCall); - void stepOverStatement(int targetContextGroupId); + void stepOverStatement(int targetContextGroupId, bool enterFunctions); void stepOutOfFunction(int targetContextGroupId); void terminateExecution(v8::Local<v8::Context> context, @@ -222,6 +222,9 @@ class V8Debugger : public v8::debug::DebugDelegate, bool ShouldBeSkipped(v8::Local<v8::debug::Script> script, int line, int column) override; + bool ShouldEnterFunction(v8::Local<v8::debug::Script> script, + const v8::debug::Location& start, + const v8::debug::Location& end) override; void BreakpointConditionEvaluated(v8::Local<v8::Context> context, v8::debug::BreakpointId breakpoint_id, bool exception_thrown, diff --git a/deps/v8/src/inspector/v8-deep-serializer.cc b/deps/v8/src/inspector/v8-deep-serializer.cc index 6ed8bb84c4dd..a32a12d0eaf4 100644 --- a/deps/v8/src/inspector/v8-deep-serializer.cc +++ b/deps/v8/src/inspector/v8-deep-serializer.cc @@ -56,9 +56,14 @@ Response SerializeRegexp(v8::Local<v8::RegExp> value, std::unique_ptr<protocol::DictionaryValue> resultValue = protocol::DictionaryValue::create(); + v8::Local<v8::String> source = value->GetSource(); + if (!duplicateTracker.takeCharacters(source)) { + return Response::ServerError("Object is too large to be returned by value"); + } + resultValue->setValue(protocol::String("pattern"), protocol::StringValue::create(toProtocolString( - v8::Isolate::GetCurrent(), value->GetSource()))); + v8::Isolate::GetCurrent(), source))); String16 flags = DescriptionForRegExpFlags(value); if (!flags.isEmpty()) { @@ -91,6 +96,10 @@ Response SerializeArrayValue(v8::Local<v8::Array> value, std::unique_ptr<protocol::ListValue> serializedValue = protocol::ListValue::create(); uint32_t length = value->Length(); + if (length > kMaxArrayLength) { + return Response::ServerError( + "Array length exceeds maximum limit for deep serialization"); + } serializedValue->reserve(length); for (uint32_t i = 0; i < length; i++) { v8::Local<v8::Value> elementValue; @@ -99,10 +108,14 @@ Response SerializeArrayValue(v8::Local<v8::Array> value, } std::unique_ptr<protocol::DictionaryValue> elementProtocolValue; - Response response = ValueMirror::create(context, elementValue) - ->buildDeepSerializedValue( - context, maxDepth - 1, additionalParameters, - duplicateTracker, &elementProtocolValue); + std::unique_ptr<ValueMirror> elementMirror = + ValueMirror::create(context, elementValue); + if (!elementMirror) { + return Response::ServerError("exception during deep serialization"); + } + Response response = elementMirror->buildDeepSerializedValue( + context, maxDepth - 1, additionalParameters, duplicateTracker, + &elementProtocolValue); if (!response.IsSuccess()) return response; serializedValue->pushValue(std::move(elementProtocolValue)); } @@ -157,23 +170,35 @@ Response SerializeMap(v8::Local<v8::Map> value, v8::Local<v8::Context> context, } if (keyV8Value->IsString()) { - keyProtocolValue = protocol::StringValue::create(toProtocolString( - v8::Isolate::GetCurrent(), keyV8Value.As<v8::String>())); + v8::Local<v8::String> keyString = keyV8Value.As<v8::String>(); + if (!duplicateTracker.takeCharacters(keyString)) { + return Response::ServerError( + "Object is too large to be returned by value"); + } + keyProtocolValue = protocol::StringValue::create( + toProtocolString(v8::Isolate::GetCurrent(), keyString)); } else { std::unique_ptr<protocol::DictionaryValue> keyDictionaryProtocolValue; - Response response = - ValueMirror::create(context, keyV8Value) - ->buildDeepSerializedValue( - context, maxDepth - 1, additionalParameters, - duplicateTracker, &keyDictionaryProtocolValue); + std::unique_ptr<ValueMirror> keyMirror = + ValueMirror::create(context, keyV8Value); + if (!keyMirror) { + return Response::ServerError("exception during deep serialization"); + } + Response response = keyMirror->buildDeepSerializedValue( + context, maxDepth - 1, additionalParameters, duplicateTracker, + &keyDictionaryProtocolValue); if (!response.IsSuccess()) return response; keyProtocolValue = std::move(keyDictionaryProtocolValue); } - Response response = ValueMirror::create(context, propertyV8Value) - ->buildDeepSerializedValue( - context, maxDepth - 1, additionalParameters, - duplicateTracker, &propertyProtocolValue); + std::unique_ptr<ValueMirror> propertyMirror = + ValueMirror::create(context, propertyV8Value); + if (!propertyMirror) { + return Response::ServerError("exception during deep serialization"); + } + Response response = propertyMirror->buildDeepSerializedValue( + context, maxDepth - 1, additionalParameters, duplicateTracker, + &propertyProtocolValue); if (!response.IsSuccess()) return response; std::unique_ptr<protocol::ListValue> keyValueList = @@ -251,17 +276,26 @@ Response SerializeObjectValue(v8::Local<v8::Object> value, if (!hasRealNamedProperty.FromJust()) { continue; } - keyProtocolValue = protocol::StringValue::create(toProtocolString( - v8::Isolate::GetCurrent(), keyV8Value.As<v8::String>())); + v8::Local<v8::String> keyString = keyV8Value.As<v8::String>(); + if (!duplicateTracker.takeCharacters(keyString)) { + return Response::ServerError( + "Object is too large to be returned by value"); + } + keyProtocolValue = protocol::StringValue::create( + toProtocolString(v8::Isolate::GetCurrent(), keyString)); if (!value->Get(context, keyV8Value).ToLocal(&propertyV8Value)) { return Response::ServerError("exception during deep serialization"); } - Response response = ValueMirror::create(context, propertyV8Value) - ->buildDeepSerializedValue( - context, maxDepth - 1, additionalParameters, - duplicateTracker, &propertyProtocolValue); + std::unique_ptr<ValueMirror> propertyMirror = + ValueMirror::create(context, propertyV8Value); + if (!propertyMirror) { + return Response::ServerError("exception during deep serialization"); + } + Response response = propertyMirror->buildDeepSerializedValue( + context, maxDepth - 1, additionalParameters, duplicateTracker, + &propertyProtocolValue); if (!response.IsSuccess()) return response; std::unique_ptr<protocol::ListValue> keyValueList = diff --git a/deps/v8/src/inspector/v8-inspector-session-impl.cc b/deps/v8/src/inspector/v8-inspector-session-impl.cc index 9ec526f64e96..e6825dd702ad 100644 --- a/deps/v8/src/inspector/v8-inspector-session-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-session-impl.cc @@ -244,11 +244,17 @@ Response V8InspectorSessionImpl::findInjectedScript( return Response::Success(); } +uint64_t V8InspectorSessionImpl::isolateId() const { + return m_clientTrustLevel == V8Inspector::kFullyTrusted + ? m_inspector->isolateId() + : 0; +} + Response V8InspectorSessionImpl::findInjectedScript( RemoteObjectIdBase* objectId, std::shared_ptr<InjectedScript>& injectedScript, std::shared_ptr<InspectedContext>* inspectedContext) { - if (objectId->isolateId() != m_inspector->isolateId()) { + if (objectId->isolateId() != isolateId()) { return Response::ServerError("Cannot find context with specified id"); } return findInjectedScript(objectId->contextId(), injectedScript, @@ -330,10 +336,15 @@ V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context, &inspectedContext); if (!injectedScript) return nullptr; std::unique_ptr<protocol::Runtime::RemoteObject> result; - injectedScript->wrapObject(value, groupName, - generatePreview ? WrapOptions({WrapMode::kPreview}) - : WrapOptions({WrapMode::kIdOnly}), - &result); + Response response = injectedScript->wrapObject( + value, groupName, + generatePreview ? WrapOptions({WrapMode::kPreview}) + : WrapOptions({WrapMode::kIdOnly}), + &result); + // Wrapping can fail after the remote object was partially built, e.g. when a + // custom formatter terminated execution. Don't return the partial result in + // that case, so that callers don't continue to call into V8. + if (!response.IsSuccess()) return nullptr; return result; } @@ -515,7 +526,7 @@ void V8InspectorSessionImpl::resume(bool terminateOnResume) { m_debuggerAgent->resume(terminateOnResume); } -void V8InspectorSessionImpl::stepOver() { m_debuggerAgent->stepOver({}); } +void V8InspectorSessionImpl::stepOver() { m_debuggerAgent->stepOver({}, {}); } std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> V8InspectorSessionImpl::searchInTextByLines(StringView text, StringView query, diff --git a/deps/v8/src/inspector/v8-inspector-session-impl.h b/deps/v8/src/inspector/v8-inspector-session-impl.h index 8a87b9512420..3afa6c76f428 100644 --- a/deps/v8/src/inspector/v8-inspector-session-impl.h +++ b/deps/v8/src/inspector/v8-inspector-session-impl.h @@ -127,9 +127,10 @@ class V8InspectorSessionImpl : public V8InspectorSession, bool includeCommandLineAPI = false) override; void stop() override; - V8Inspector::ClientTrustLevel clientTrustLevel() { + V8Inspector::ClientTrustLevel clientTrustLevel() const { return m_clientTrustLevel; } + uint64_t isolateId() const; void setWeakThis(std::weak_ptr<V8InspectorSessionImpl> weakThis) { m_weakThis = std::move(weakThis); diff --git a/deps/v8/src/inspector/v8-profiler-agent-impl.cc b/deps/v8/src/inspector/v8-profiler-agent-impl.cc index 6c5c0cae1219..bb72bc9bdf77 100644 --- a/deps/v8/src/inspector/v8-profiler-agent-impl.cc +++ b/deps/v8/src/inspector/v8-profiler-agent-impl.cc @@ -252,6 +252,9 @@ Response V8ProfilerAgentImpl::setSamplingInterval(int interval) { return Response::ServerError( "Cannot change sampling interval when profiling."); } + if (interval <= 0) { + return Response::ServerError("Invalid sampling interval"); + } m_state->setInteger(ProfilerAgentState::samplingInterval, interval); return Response::Success(); } diff --git a/deps/v8/src/inspector/v8-runtime-agent-impl.cc b/deps/v8/src/inspector/v8-runtime-agent-impl.cc index 0120bbd5cf4d..ac4cd7f119bb 100644 --- a/deps/v8/src/inspector/v8-runtime-agent-impl.cc +++ b/deps/v8/src/inspector/v8-runtime-agent-impl.cc @@ -856,6 +856,10 @@ Response V8RuntimeAgentImpl::globalLexicalScopeNames( } Response V8RuntimeAgentImpl::getIsolateId(String16* outIsolateId) { + if (m_session->clientTrustLevel() != V8Inspector::kFullyTrusted) { + return Response::ServerError( + "Runtime.getIsolateId is not allowed for untrusted clients"); + } char buf[40]; std::snprintf(buf, sizeof(buf), "%" PRIx64, m_inspector->isolateId()); *outIsolateId = buf; @@ -866,6 +870,10 @@ Response V8RuntimeAgentImpl::getHeapUsage(double* out_usedSize, double* out_totalSize, double* out_embedderHeapUsedSize, double* out_backingStorageSize) { + if (m_session->clientTrustLevel() != V8Inspector::kFullyTrusted) { + return Response::ServerError( + "Runtime.getHeapUsage is not allowed for untrusted clients"); + } v8::HeapStatistics stats; m_inspector->isolate()->GetHeapStatistics(&stats); *out_usedSize = stats.used_heap_size(); diff --git a/deps/v8/src/inspector/v8-serialization-duplicate-tracker.cc b/deps/v8/src/inspector/v8-serialization-duplicate-tracker.cc index f32af95d4daf..09e99599c93b 100644 --- a/deps/v8/src/inspector/v8-serialization-duplicate-tracker.cc +++ b/deps/v8/src/inspector/v8-serialization-duplicate-tracker.cc @@ -5,7 +5,8 @@ #include "src/inspector/v8-serialization-duplicate-tracker.h" #include "include/v8-context.h" -#include "include/v8-external.h" +#include "include/v8-isolate.h" +#include "include/v8-primitive.h" #include "src/base/logging.h" namespace v8_inspector { @@ -13,17 +14,24 @@ namespace v8_inspector { std::unique_ptr<protocol::DictionaryValue> V8SerializationDuplicateTracker::LinkExistingOrCreate( v8::Local<v8::Value> v8Value, bool* isKnown) { + // Look up whether this V8 value was already serialized. + protocol::DictionaryValue* maybeKnownSerializedValue = nullptr; + // Bail out if the V8 Map lookup failed (e.g. on stack overflow). + if (!FindKnownSerializedValue(v8Value, &maybeKnownSerializedValue)) { + return nullptr; + } + std::unique_ptr<protocol::DictionaryValue> result = protocol::DictionaryValue::create(); - protocol::DictionaryValue* maybeKnownSerializedValue = - FindKnownSerializedValue(v8Value); - if (maybeKnownSerializedValue == nullptr) { *isKnown = false; // Keep reference to the serialized value, so that // `weakLocalObjectReference` can be set later. - SetKnownSerializedValue(v8Value, result.get()); + if (!SetKnownSerializedValue(v8Value, result.get())) { + // Bail out if storing into the V8 Map failed (e.g. on stack overflow). + return nullptr; + } } else { *isKnown = true; @@ -46,28 +54,48 @@ V8SerializationDuplicateTracker::LinkExistingOrCreate( return result; } -void V8SerializationDuplicateTracker::SetKnownSerializedValue( +bool V8SerializationDuplicateTracker::SetKnownSerializedValue( v8::Local<v8::Value> v8Value, protocol::DictionaryValue* serializedValue) { - m_v8ObjectToSerializedDictionary = - m_v8ObjectToSerializedDictionary - ->Set(m_context, v8Value, - v8::External::New(v8::Isolate::GetCurrent(), serializedValue, - v8::kDictionaryValueTag)) - .ToLocalChecked(); + // Don't store the raw `serializedValue` pointer in the (in-sandbox) map, + // but only its index into `m_serializedValues`. + int32_t index = static_cast<int32_t>(m_serializedValues.size()); + v8::Local<v8::Map> map; + if (!m_v8ObjectToSerializedDictionary + ->Set(m_context, v8Value, + v8::Integer::New(v8::Isolate::GetCurrent(), index)) + .ToLocal(&map)) { + // Return false when Map::Set fails instead of aborting via ToLocalChecked. + return false; + } + // Record the serialized dictionary and update the map handle on success. + m_serializedValues.push_back(serializedValue); + m_v8ObjectToSerializedDictionary = map; + return true; } -protocol::DictionaryValue* -V8SerializationDuplicateTracker::FindKnownSerializedValue( - v8::Local<v8::Value> v8Value) { +bool V8SerializationDuplicateTracker::FindKnownSerializedValue( + v8::Local<v8::Value> v8Value, protocol::DictionaryValue** result) { v8::Local<v8::Value> knownValue; + // Abort lookup if Map::Get fails due to an exception or stack overflow. if (!m_v8ObjectToSerializedDictionary->Get(m_context, v8Value) - .ToLocal(&knownValue) || - knownValue->IsUndefined()) { - return nullptr; + .ToLocal(&knownValue)) { + return false; + } + // Treat a non-Int32 entry (e.g. undefined when absent) as not found. + if (!knownValue->IsInt32()) { + *result = nullptr; + return true; } - return static_cast<protocol::DictionaryValue*>( - knownValue.As<v8::External>()->Value(v8::kDictionaryValueTag)); + // The map lives in the sandbox and might have been corrupted, so the index + // must be treated as untrusted and bounds-checked. + int32_t index = knownValue.As<v8::Int32>()->Value(); + if (index < 0 || static_cast<size_t>(index) >= m_serializedValues.size()) { + *result = nullptr; + return true; + } + *result = m_serializedValues[index]; + return true; } V8SerializationDuplicateTracker::V8SerializationDuplicateTracker( diff --git a/deps/v8/src/inspector/v8-serialization-duplicate-tracker.h b/deps/v8/src/inspector/v8-serialization-duplicate-tracker.h index b6036e3ac45e..d742db2e113f 100644 --- a/deps/v8/src/inspector/v8-serialization-duplicate-tracker.h +++ b/deps/v8/src/inspector/v8-serialization-duplicate-tracker.h @@ -5,34 +5,74 @@ #ifndef V8_INSPECTOR_V8_SERIALIZATION_DUPLICATE_TRACKER_H_ #define V8_INSPECTOR_V8_SERIALIZATION_DUPLICATE_TRACKER_H_ +#include <vector> + #include "include/v8-container.h" +#include "include/v8-primitive.h" #include "src/base/vector.h" #include "src/debug/debug-interface.h" #include "src/inspector/protocol/Runtime.h" namespace v8_inspector { +struct ProtocolValueBudget { + // The remaining number of array elements and object properties. + uint32_t values = 10'000'000; + // The remaining number of characters in strings and property names. The + // serialized result has to fit into a single string anyway. + uint32_t characters = static_cast<uint32_t>(v8::String::kMaxLength); + + bool takeValues(uint32_t count) { + if (count > values) return false; + values -= count; + return true; + } + + bool takeCharacters(v8::Local<v8::String> string) { + uint32_t length = static_cast<uint32_t>(string->Length()); + if (length > characters) return false; + characters -= length; + return true; + } +}; + class V8SerializationDuplicateTracker { public: // Returns a `protocol::DictionaryValue` value either empty if the V8 value // was not serialized yet, or filled in as a reference to previousely - // serialized protocol value. + // serialized protocol value. Returns nullptr if a V8 exception occurs. V8_EXPORT std::unique_ptr<protocol::DictionaryValue> LinkExistingOrCreate( v8::Local<v8::Value> v8Value, bool* isKnown); V8_EXPORT explicit V8SerializationDuplicateTracker( v8::Local<v8::Context> context); + bool takeCharacters(v8::Local<v8::String> string) { + return m_budget.takeCharacters(string); + } + ProtocolValueBudget* budget() { return &m_budget; } + private: + ProtocolValueBudget m_budget; v8::Local<v8::Context> m_context; int m_counter; - // Maps v8 value to corresponding serialized value. + // Maps v8 value to the index of the corresponding serialized value in + // `m_serializedValues`. The map lives in sandbox-corruptible memory, so it + // must never hold raw (out-of-sandbox) pointers. Instead it holds indices + // that are range-checked on lookup, so that a corrupted or replayed map + // value can at worst alias another serialized value of the same + // serialization, but never produce a dangling pointer. v8::Local<v8::Map> m_v8ObjectToSerializedDictionary; + // Serialized values registered during this serialization. The values are + // owned by the resulting protocol tree, which outlives this tracker. + std::vector<protocol::DictionaryValue*> m_serializedValues; - V8_EXPORT protocol::DictionaryValue* FindKnownSerializedValue( - v8::Local<v8::Value> v8Value); + // Looks up a previously serialized value; returns false if Map::Get fails. + V8_EXPORT bool FindKnownSerializedValue(v8::Local<v8::Value> v8Value, + protocol::DictionaryValue** result); - V8_EXPORT void SetKnownSerializedValue( + // Records a newly serialized value; returns false if Map::Set fails. + V8_EXPORT bool SetKnownSerializedValue( v8::Local<v8::Value> v8Value, protocol::DictionaryValue* serializedValue); }; } // namespace v8_inspector diff --git a/deps/v8/src/inspector/value-mirror.cc b/deps/v8/src/inspector/value-mirror.cc index ac78cea16537..e4df20d97173 100644 --- a/deps/v8/src/inspector/value-mirror.cc +++ b/deps/v8/src/inspector/value-mirror.cc @@ -39,23 +39,41 @@ static const int kMaxProtocolDepth = 900; static const int kMaxProtocolDepth = 1000; #endif -Response toProtocolValue(v8::Local<v8::Context> context, - v8::Local<v8::Value> value, int maxDepth, - std::unique_ptr<protocol::Value>* result); +namespace { -Response arrayToProtocolValue(v8::Local<v8::Context> context, - v8::Local<v8::Array> array, int maxDepth, - std::unique_ptr<protocol::ListValue>* result) { +Response toProtocolValueImpl(v8::Local<v8::Context> context, + v8::Local<v8::Value> value, int maxDepth, + ProtocolValueBudget* budget, + std::unique_ptr<protocol::Value>* result); + +Response objectTooLargeError() { + return Response::ServerError("Object is too large to be returned by value"); +} + +Response arrayToProtocolValueImpl( + v8::Local<v8::Context> context, v8::Local<v8::Array> array, int maxDepth, + ProtocolValueBudget* budget, std::unique_ptr<protocol::ListValue>* result) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handles(isolate); std::unique_ptr<protocol::ListValue> inspectorArray = protocol::ListValue::create(); uint32_t length = array->Length(); + if (length > kMaxArrayLength) { + return Response::ServerError("Array length exceeds maximum limit"); + } + // Take all the elements from the budget upfront, so that we fail early + // (before serializing any of the elements) if they don't fit. + if (!budget->takeValues(length)) return objectTooLargeError(); + inspectorArray->reserve(length); for (uint32_t i = 0; i < length; i++) { + v8::HandleScope loopHandles(isolate); v8::Local<v8::Value> value; if (!array->Get(context, i).ToLocal(&value)) { return Response::InternalError(); } std::unique_ptr<protocol::Value> element; - Response response = toProtocolValue(context, value, maxDepth - 1, &element); + Response response = + toProtocolValueImpl(context, value, maxDepth - 1, budget, &element); if (!response.IsSuccess()) return response; inspectorArray->pushValue(std::move(element)); } @@ -63,9 +81,12 @@ Response arrayToProtocolValue(v8::Local<v8::Context> context, return Response::Success(); } -Response objectToProtocolValue( +Response objectToProtocolValueImpl( v8::Local<v8::Context> context, v8::Local<v8::Object> object, int maxDepth, + ProtocolValueBudget* budget, std::unique_ptr<protocol::DictionaryValue>* result) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handles(isolate); std::unique_ptr<protocol::DictionaryValue> jsonObject = protocol::DictionaryValue::create(); v8::Local<v8::Array> propertyNames; @@ -73,7 +94,9 @@ Response objectToProtocolValue( return Response::InternalError(); } uint32_t length = propertyNames->Length(); + if (!budget->takeValues(length)) return objectTooLargeError(); for (uint32_t i = 0; i < length; i++) { + v8::HandleScope loopHandles(isolate); v8::Local<v8::Value> name; if (!propertyNames->Get(context, i).ToLocal(&name)) { return Response::InternalError(); @@ -82,21 +105,26 @@ Response objectToProtocolValue( v8::Maybe<bool> hasRealNamedProperty = object->HasRealNamedProperty(context, name.As<v8::String>()); // Don't access properties with interceptors. - if (hasRealNamedProperty.IsNothing() || - !hasRealNamedProperty.FromJust()) { + if (hasRealNamedProperty.IsNothing()) { + return Response::InternalError(); + } + if (!hasRealNamedProperty.FromJust()) { continue; } } v8::Local<v8::String> propertyName; - if (!name->ToString(context).ToLocal(&propertyName)) continue; + if (!name->ToString(context).ToLocal(&propertyName)) { + return Response::InternalError(); + } v8::Local<v8::Value> property; if (!object->Get(context, name).ToLocal(&property)) { return Response::InternalError(); } if (property->IsUndefined()) continue; + if (!budget->takeCharacters(propertyName)) return objectTooLargeError(); std::unique_ptr<protocol::Value> propertyValue; - Response response = - toProtocolValue(context, property, maxDepth - 1, &propertyValue); + Response response = toProtocolValueImpl(context, property, maxDepth - 1, + budget, &propertyValue); if (!response.IsSuccess()) return response; jsonObject->setValue( toProtocolString(v8::Isolate::GetCurrent(), propertyName), @@ -106,6 +134,8 @@ Response objectToProtocolValue( return Response::Success(); } +} // namespace + std::unique_ptr<protocol::FundamentalValue> toProtocolValue( double doubleValue) { if (doubleValue >= std::numeric_limits<int>::min() && @@ -120,9 +150,12 @@ std::unique_ptr<protocol::FundamentalValue> toProtocolValue( return protocol::FundamentalValue::create(doubleValue); } -Response toProtocolValue(v8::Local<v8::Context> context, - v8::Local<v8::Value> value, int maxDepth, - std::unique_ptr<protocol::Value>* result) { +namespace { + +Response toProtocolValueImpl(v8::Local<v8::Context> context, + v8::Local<v8::Value> value, int maxDepth, + ProtocolValueBudget* budget, + std::unique_ptr<protocol::Value>* result) { if (maxDepth <= 0) { return Response::ServerError("Object reference chain is too long"); } @@ -142,23 +175,25 @@ Response toProtocolValue(v8::Local<v8::Context> context, return Response::Success(); } if (value->IsString()) { + v8::Local<v8::String> string = value.As<v8::String>(); + if (!budget->takeCharacters(string)) return objectTooLargeError(); *result = protocol::StringValue::create( - toProtocolString(v8::Isolate::GetCurrent(), value.As<v8::String>())); + toProtocolString(v8::Isolate::GetCurrent(), string)); return Response::Success(); } if (value->IsArray()) { v8::Local<v8::Array> array = value.As<v8::Array>(); std::unique_ptr<protocol::ListValue> list_result; - auto response = - arrayToProtocolValue(context, array, maxDepth, &list_result); + auto response = arrayToProtocolValueImpl(context, array, maxDepth, budget, + &list_result); *result = std::move(list_result); return response; } if (value->IsObject()) { v8::Local<v8::Object> object = value.As<v8::Object>(); std::unique_ptr<protocol::DictionaryValue> dict_result; - auto response = - objectToProtocolValue(context, object, maxDepth, &dict_result); + auto response = objectToProtocolValueImpl(context, object, maxDepth, budget, + &dict_result); *result = std::move(dict_result); return response; } @@ -166,6 +201,29 @@ Response toProtocolValue(v8::Local<v8::Context> context, return Response::ServerError("Object couldn't be returned by value"); } +} // namespace + +Response arrayToProtocolValue(v8::Local<v8::Context> context, + v8::Local<v8::Array> array, int maxDepth, + std::unique_ptr<protocol::ListValue>* result) { + ProtocolValueBudget budget; + return arrayToProtocolValueImpl(context, array, maxDepth, &budget, result); +} + +Response objectToProtocolValue( + v8::Local<v8::Context> context, v8::Local<v8::Object> object, int maxDepth, + std::unique_ptr<protocol::DictionaryValue>* result) { + ProtocolValueBudget budget; + return objectToProtocolValueImpl(context, object, maxDepth, &budget, result); +} + +Response toProtocolValue(v8::Local<v8::Context> context, + v8::Local<v8::Value> value, int maxDepth, + std::unique_ptr<protocol::Value>* result) { + ProtocolValueBudget budget; + return toProtocolValueImpl(context, value, maxDepth, &budget, result); +} + Response toProtocolValue(v8::Local<v8::Context> context, v8::Local<v8::Value> value, std::unique_ptr<protocol::Value>* result) { @@ -277,25 +335,29 @@ v8::MaybeLocal<v8::Value> getErrorProperty(v8::Local<v8::Context> context, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local<v8::Value> descriptor; if (!object->GetOwnPropertyDescriptor(context, name).ToLocal(&descriptor)) { - tryCatch.Reset(); - return object->Get(context, name); + return v8::MaybeLocal<v8::Value>(); } if (!descriptor->IsObject()) return object->Get(context, name); v8::Local<v8::Object> descriptorObject = descriptor.As<v8::Object>(); - v8::Local<v8::Value> getDescriptor; - if (!descriptorObject->HasOwnProperty(context, toV8String(isolate, "get")) - .FromJust()) { - tryCatch.Reset(); + v8::Maybe<bool> hasGet = + descriptorObject->HasOwnProperty(context, toV8String(isolate, "get")); + if (hasGet.IsNothing()) { + return v8::MaybeLocal<v8::Value>(); + } + if (!hasGet.FromJust()) { return object->Get(context, name); } + if (v8::debug::SideEffectCheckScope::IsActive(isolate)) { + return v8::MaybeLocal<v8::Value>(); + } + v8::Local<v8::Value> getDescriptor; if (!descriptorObject->Get(context, toV8String(isolate, "get")) .ToLocal(&getDescriptor)) { - tryCatch.Reset(); - return object->Get(context, name); + return v8::MaybeLocal<v8::Value>(); } - if (getDescriptor->IsFunction() && + if (!getDescriptor->IsFunction() || !isBuiltinGetter(getDescriptor.As<v8::Function>())) { return v8::MaybeLocal<v8::Value>(); } @@ -326,6 +388,7 @@ String16 descriptionForError(v8::Local<v8::Context> context, name = toProtocolString(isolate, nameString); } } + if (tryCatch.HasTerminated()) return String16(); } std::optional<String16> stack; @@ -341,6 +404,7 @@ String16 descriptionForError(v8::Local<v8::Context> context, stack = stackString.substring(pos); } } + if (tryCatch.HasTerminated()) return String16(); } std::optional<String16> message; @@ -352,6 +416,7 @@ String16 descriptionForError(v8::Local<v8::Context> context, String16 msg = toProtocolStringWithTypeCheck(isolate, messageValue); if (!msg.isEmpty()) message = msg; } + if (tryCatch.HasTerminated()) return String16(); } String16 description = name; @@ -421,6 +486,25 @@ String16 descriptionForWasmValueObject( String16 descriptionForEntry(v8::Local<v8::Context> context, v8::Local<v8::Object> object) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // Inspector clients can modify the "key" and "value" of entry wrappers, so + // they might form a cycle, either directly or indirectly (e.g. via properties + // of other objects). To avoid unbounded recursion between + // descriptionForEntry() and ValueMirror::create(), break cycles by describing + // already-active entry wrappers like regular objects instead. + struct ActiveEntry { + v8::Local<v8::Object> object; + const ActiveEntry* previous; + }; + static thread_local const ActiveEntry* activeEntries = nullptr; + for (const ActiveEntry* entry = activeEntries; entry != nullptr; + entry = entry->previous) { + if (entry->object->StrictEquals(object)) { + return descriptionForObject(isolate, object); + } + } + const ActiveEntry currentEntry = {object, activeEntries}; + activeEntries = ¤tEntry; + String16 key; v8::Local<v8::Value> tmp; if (object->GetRealNamedProperty(context, toV8String(isolate, "key")) @@ -439,8 +523,12 @@ String16 descriptionForEntry(v8::Local<v8::Context> context, } } + // Describing the key can terminate execution (e.g. when a side-effect check + // fails). Don't call into V8 again in that case, since the next V8 API call + // would clear the pending termination exception. String16 value; - if (object->GetRealNamedProperty(context, toV8String(isolate, "value")) + if (!isolate->IsExecutionTerminating() && + object->GetRealNamedProperty(context, toV8String(isolate, "value")) .ToLocal(&tmp)) { auto wrapper = ValueMirror::create(context, tmp); if (wrapper) { @@ -456,6 +544,7 @@ String16 descriptionForEntry(v8::Local<v8::Context> context, } } + activeEntries = currentEntry.previous; return key.length() ? ("{" + key + " => " + value + "}") : value; } @@ -479,7 +568,7 @@ String16 descriptionForPrivateMethod(v8::Local<v8::Context> context, .ToLocal(&value)) { return String16(); } - DCHECK(value->IsFunction()); + if (!value->IsFunction()) return String16(); return descriptionForFunction(value.As<v8::Function>()); } @@ -579,11 +668,15 @@ class PrimitiveValueMirror final : public ValueMirrorBase { return Response::Success(); } if (value->IsString()) { + v8::Local<v8::String> stringValue = value.As<v8::String>(); + if (!duplicateTracker.takeCharacters(stringValue)) { + return objectTooLargeError(); + } *result = protocol::DictionaryValue::create(); (*result)->setString( "type", protocol::Runtime::DeepSerializedValue::TypeEnum::String); - (*result)->setString("value", toProtocolString(v8::Isolate::GetCurrent(), - value.As<v8::String>())); + (*result)->setString( + "value", toProtocolString(v8::Isolate::GetCurrent(), stringValue)); return Response::Success(); } if (value->IsBoolean()) { @@ -597,6 +690,10 @@ class PrimitiveValueMirror final : public ValueMirrorBase { // Fallback in case of unexpected type. bool isKnown; *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown); + // Fail serialization if duplicate tracker Map operations threw. + if (!*result) { + return Response::ServerError("exception during deep serialization"); + } if (isKnown) { return Response::Success(); } @@ -742,6 +839,9 @@ class BigIntMirror final : public ValueMirrorBase { v8Value(v8::Isolate::GetCurrent()).As<v8::BigInt>(); v8::Local<v8::String> stringValue = v8::debug::GetBigIntStringValue(v8::Isolate::GetCurrent(), value); + if (!duplicateTracker.takeCharacters(stringValue)) { + return objectTooLargeError(); + } *result = protocol::DictionaryValue::create(); (*result)->setString( @@ -809,6 +909,10 @@ class SymbolMirror final : public ValueMirrorBase { v8::Local<v8::Value> value = v8Value(v8::Isolate::GetCurrent()); bool isKnown; *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown); + // Fail serialization if duplicate tracker Map operations threw. + if (!*result) { + return Response::ServerError("exception during deep serialization"); + } if (isKnown) { return Response::Success(); } @@ -866,6 +970,10 @@ class LocationMirror final : public ValueMirrorBase { bool isKnown; v8::Local<v8::Value> value = v8Value(v8::Isolate::GetCurrent()); *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown); + // Fail serialization if duplicate tracker Map operations threw. + if (!*result) { + return Response::ServerError("exception during deep serialization"); + } if (isKnown) { return Response::Success(); } @@ -961,6 +1069,10 @@ class FunctionMirror final : public ValueMirrorBase { bool isKnown; v8::Local<v8::Value> value = v8Value(v8::Isolate::GetCurrent()); *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown); + // Fail serialization if duplicate tracker Map operations threw. + if (!*result) { + return Response::ServerError("exception during deep serialization"); + } if (isKnown) { return Response::Success(); } @@ -1009,6 +1121,7 @@ struct EntryMirror { static bool getEntries(v8::Local<v8::Context> context, v8::Local<v8::Object> object, size_t limit, bool* overflow, std::vector<EntryMirror>* mirrors) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); bool isKeyValue = false; v8::Local<v8::Array> entries; if (!object->PreviewEntries(&isKeyValue).ToLocal(&entries)) return false; @@ -1018,13 +1131,17 @@ struct EntryMirror { std::unique_ptr<ValueMirror> keyMirror; if (isKeyValue && entries->Get(context, i).ToLocal(&tmp)) { keyMirror = ValueMirror::create(context, tmp); + // Creating the mirror can run JavaScript, which might terminate + // execution. Don't call into V8 anymore in that case, since the next + // V8 API call would clear the pending termination exception. + if (isolate->IsExecutionTerminating()) return false; } std::unique_ptr<ValueMirror> valueMirror; if (entries->Get(context, isKeyValue ? i + 1 : i).ToLocal(&tmp)) { valueMirror = ValueMirror::create(context, tmp); - } else { - continue; + if (isolate->IsExecutionTerminating()) return false; } + if (!valueMirror) continue; if (mirrors->size() == limit) { *overflow = true; return true; @@ -1273,6 +1390,10 @@ class ObjectMirror final : public ValueMirrorBase { maxDepth = std::min(kMaxProtocolDepth, maxDepth); bool isKnown; *result = duplicateTracker.LinkExistingOrCreate(value, &isKnown); + // Fail serialization if duplicate tracker Map operations threw. + if (!*result) { + return Response::ServerError("exception during deep serialization"); + } if (isKnown) { return Response::Success(); } @@ -1296,10 +1417,13 @@ class ObjectMirror final : public ValueMirrorBase { embedderDeepSerializedResult->serializedValue->type->string())); v8::Local<v8::Value> v8Value; if (embedderDeepSerializedResult->serializedValue->value.ToLocal( - &v8Value)) { + &v8Value) && + !v8Value->IsUndefined()) { // Embedder-implemented serialization has value. std::unique_ptr<protocol::Value> protocolValue; - Response response = toProtocolValue(context, v8Value, &protocolValue); + Response response = + toProtocolValueImpl(context, v8Value, kMaxProtocolDepth, + duplicateTracker.budget(), &protocolValue); if (!response.IsSuccess()) return response; (*result)->setValue("value", std::move(protocolValue)); } @@ -1317,11 +1441,17 @@ class ObjectMirror final : public ValueMirrorBase { v8::Local<v8::Context> context, bool forEntry, bool generatePreviewForTable, int* nameLimit, int* indexLimit, std::unique_ptr<ObjectPreview>* result) const { + // Building the preview can run JavaScript (e.g. getters on Error objects), + // which might terminate execution. Don't call into V8 anymore in that case, + // since the next V8 API call would clear the pending termination exception. + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + if (isolate->IsExecutionTerminating()) return; + auto properties = std::make_unique<protocol::Array<PropertyPreview>>(); std::unique_ptr<protocol::Array<EntryPreview>> entriesPreview; bool overflow = false; - v8::Local<v8::Value> value = v8Value(v8::Isolate::GetCurrent()); + v8::Local<v8::Value> value = v8Value(isolate); while (value->IsProxy()) value = value.As<v8::Proxy>()->GetTarget(); if (value->IsObject() && !value->IsProxy()) { @@ -1329,6 +1459,7 @@ class ObjectMirror final : public ValueMirrorBase { std::vector<InternalPropertyMirror> internalProperties; getInternalPropertiesForPreview(context, objectForPreview, nameLimit, &overflow, &internalProperties); + if (isolate->IsExecutionTerminating()) return; for (size_t i = 0; i < internalProperties.size(); ++i) { std::unique_ptr<PropertyPreview> propertyPreview; internalProperties[i].value->buildPropertyPreview( @@ -1340,6 +1471,7 @@ class ObjectMirror final : public ValueMirrorBase { getPrivatePropertiesForPreview(context, objectForPreview, nameLimit, &overflow, properties.get()); + if (isolate->IsExecutionTerminating()) return; std::vector<PropertyMirror> mirrors; if (getPropertiesForPreview(context, objectForPreview, nameLimit, @@ -1367,6 +1499,7 @@ class ObjectMirror final : public ValueMirrorBase { properties->emplace_back(std::move(preview)); } } + if (isolate->IsExecutionTerminating()) return; std::vector<EntryMirror> entries; if (EntryMirror::getEntries(context, objectForPreview, 5, &overflow, @@ -1395,6 +1528,7 @@ class ObjectMirror final : public ValueMirrorBase { } } } + if (isolate->IsExecutionTerminating()) return; } *result = ObjectPreview::create() .setType(RemoteObject::TypeEnum::Object) @@ -1506,7 +1640,10 @@ bool doesAttributeHaveObservableSideEffectOnGet(v8::Local<v8::Context> context, return true; } } - if (tryCatch.HasCaught()) tryCatch.Reset(); + if (tryCatch.HasCaught()) { + if (tryCatch.HasTerminated()) return true; + tryCatch.Reset(); + } v8::Local<v8::Value> response; if (context->Global() @@ -1518,7 +1655,7 @@ bool doesAttributeHaveObservableSideEffectOnGet(v8::Local<v8::Context> context, return true; } } - return false; + return tryCatch.HasTerminated(); } } // anonymous namespace @@ -1532,6 +1669,10 @@ bool ValueMirror::getProperties(v8::Local<v8::Context> context, bool nonIndexedPropertiesOnly, PropertyAccumulator* accumulator) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); + // Don't call into V8 when execution is terminating, since that would clear + // the pending termination exception (and PropertyIterator::Create() would + // fail without throwing). + if (isolate->IsExecutionTerminating()) return false; v8::TryCatch tryCatch(isolate); v8::Local<v8::Set> set = v8::Set::New(isolate); @@ -1656,6 +1797,10 @@ bool ValueMirror::getProperties(v8::Local<v8::Context> context, } } } + // Creating the mirrors can run JavaScript, which might terminate + // execution. Don't call into V8 anymore in that case, since the next V8 + // API call would clear the pending termination exception. + if (isolate->IsExecutionTerminating()) return false; if (accessorPropertiesOnly && !isAccessorProperty) continue; auto mirror = PropertyMirror{name, writable, @@ -1724,6 +1869,10 @@ void ValueMirror::getInternalProperties( continue; } auto wrapper = ValueMirror::create(context, value); + // Creating the mirror can run JavaScript, which might terminate + // execution. Don't call into V8 anymore in that case, since the next V8 + // API call would clear the pending termination exception. + if (isolate->IsExecutionTerminating()) return; if (wrapper) { mirrors->emplace_back(InternalPropertyMirror{ toProtocolStringWithTypeCheck(v8::Isolate::GetCurrent(), name), @@ -1778,6 +1927,11 @@ std::vector<PrivatePropertyMirror> ValueMirror::getPrivateProperties( valueMirror = ValueMirror::create(context, value); } + // Creating the mirrors can run JavaScript, which might terminate + // execution. Don't call into V8 anymore in that case, since the next V8 + // API call would clear the pending termination exception. + if (isolate->IsExecutionTerminating()) return {}; + mirrors.emplace_back(PrivatePropertyMirror{ toProtocolStringWithTypeCheck(v8::Isolate::GetCurrent(), name), std::move(valueMirror), std::move(getterMirror), @@ -1796,9 +1950,14 @@ std::unique_ptr<ValueMirror> clientMirror(v8::Local<v8::Context> context, value, subtype, toString16(descriptionForValueSubtype->string())); } if (subtype == "error") { - return std::make_unique<ObjectMirror>(value, - RemoteObject::SubtypeEnum::Error, - descriptionForError(context, value)); + String16 description = descriptionForError(context, value); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + if (isolate->IsExecutionTerminating() && + v8::debug::SideEffectCheckScope::IsActive(isolate)) { + return nullptr; + } + return std::make_unique<ObjectMirror>( + value, RemoteObject::SubtypeEnum::Error, description); } if (subtype == "array" && value->IsObject()) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); @@ -1813,6 +1972,10 @@ std::unique_ptr<ValueMirror> clientMirror(v8::Local<v8::Context> context, lengthValue.As<v8::Int32>()->Value())); } } + if (tryCatch.HasTerminated() && + v8::debug::SideEffectCheckScope::IsActive(isolate)) { + return nullptr; + } } return std::make_unique<ObjectMirror>( value, descriptionForObject(v8::Isolate::GetCurrent(), value)); @@ -1888,9 +2051,12 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context, descriptionForObject(isolate, promise)); } if (object->IsNativeError()) { - return std::make_unique<ObjectMirror>(object, - RemoteObject::SubtypeEnum::Error, - descriptionForError(context, object)); + String16 description = descriptionForError(context, object); + if (isolate->IsExecutionTerminating()) { + return nullptr; + } + return std::make_unique<ObjectMirror>( + object, RemoteObject::SubtypeEnum::Error, description); } if (object->IsMap()) { v8::Local<v8::Map> map = object.As<v8::Map>(); @@ -1954,7 +2120,8 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context, return std::make_unique<ObjectMirror>( memory, RemoteObject::SubtypeEnum::Webassemblymemory, descriptionForCollection( - isolate, memory, memory->Buffer()->ByteLength() / kWasmPageSize)); + isolate, memory, + memory->GetBuffer()->ByteLength() / kWasmPageSize)); } #if V8_ENABLE_WEBASSEMBLY if (v8::debug::WasmValueObject::IsWasmValueObject(object)) { @@ -1981,17 +2148,28 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context, descriptionForPrivateMethodList(array)); } if (internalType == V8InternalValueType::kEntry) { + String16 description = descriptionForEntry(context, object); + if (isolate->IsExecutionTerminating()) { + return nullptr; + } return std::make_unique<ObjectMirror>(object, "internal#entry", - descriptionForEntry(context, object)); + description); } if (internalType == V8InternalValueType::kScope) { + String16 description = descriptionForScope(context, object); + if (isolate->IsExecutionTerminating()) { + return nullptr; + } return std::make_unique<ObjectMirror>(object, "internal#scope", - descriptionForScope(context, object)); + description); } if (internalType == V8InternalValueType::kPrivateMethod) { - return std::make_unique<ObjectMirror>( - object, "internal#privateMethod", - descriptionForPrivateMethod(context, object)); + String16 description = descriptionForPrivateMethod(context, object); + if (isolate->IsExecutionTerminating()) { + return nullptr; + } + return std::make_unique<ObjectMirror>(object, "internal#privateMethod", + description); } size_t length = 0; if (isArrayLike(context, object, &length)) { @@ -1999,6 +2177,9 @@ std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context, object, RemoteObject::SubtypeEnum::Array, descriptionForCollection(isolate, object, length)); } + if (isolate->IsExecutionTerminating()) { + return nullptr; + } return std::make_unique<ObjectMirror>(object, descriptionForObject(isolate, object)); } diff --git a/deps/v8/src/inspector/value-mirror.h b/deps/v8/src/inspector/value-mirror.h index b75840196174..411d86725702 100644 --- a/deps/v8/src/inspector/value-mirror.h +++ b/deps/v8/src/inspector/value-mirror.h @@ -92,6 +92,8 @@ class ValueMirror { bool accessorPropertiesOnly); }; +static constexpr uint32_t kMaxArrayLength = 10'000'000; + protocol::Response toProtocolValue(v8::Local<v8::Context> context, v8::Local<v8::Value> value, int maxDepth, std::unique_ptr<protocol::Value>* result); diff --git a/deps/v8/src/interpreter/bytecode-array-builder.cc b/deps/v8/src/interpreter/bytecode-array-builder.cc index d50b594fe213..10402f29fce6 100644 --- a/deps/v8/src/interpreter/bytecode-array-builder.cc +++ b/deps/v8/src/interpreter/bytecode-array-builder.cc @@ -185,8 +185,7 @@ void BytecodeArrayBuilder::Write(BytecodeNode* node) { void BytecodeArrayBuilder::WriteJump(BytecodeNode* node, BytecodeLabel* label) { AttachOrEmitDeferredSourceInfo(node); - DCHECK(Bytecodes::IsWithoutExternalSideEffects(node->bytecode()) || - Bytecodes::IsJumpIfToBoolean(node->bytecode())); + DCHECK(Bytecodes::IsWithoutExternalSideEffects(node->bytecode())); bytecode_array_writer_.WriteJump(node, label); } @@ -1762,6 +1761,7 @@ SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER) BytecodeJumpTable* BytecodeArrayBuilder::AllocateJumpTable( int size, int case_value_base) { DCHECK_GT(size, 0); + DCHECK(!RemainderOfBlockIsDead()); size_t constant_pool_index = constant_array_builder()->InsertJumpTable(size); diff --git a/deps/v8/src/interpreter/bytecode-array-iterator.h b/deps/v8/src/interpreter/bytecode-array-iterator.h index 9825ed7ffdb4..f3eddf51b725 100644 --- a/deps/v8/src/interpreter/bytecode-array-iterator.h +++ b/deps/v8/src/interpreter/bytecode-array-iterator.h @@ -103,6 +103,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayIterator { BytecodeArrayIterator(const BytecodeArrayIterator&) = delete; BytecodeArrayIterator& operator=(const BytecodeArrayIterator&) = delete; + BytecodeArrayIterator Clone( + DisallowGarbageCollection& no_gc V8_LIFETIME_BOUND) const { + return BytecodeArrayIterator(*this, no_gc); + } + inline void Advance() { cursor_ += current_bytecode_size_without_prefix(); UpdateCurrentBytecode(); @@ -228,6 +233,17 @@ class V8_EXPORT_PRIVATE BytecodeArrayIterator { void SetOffsetUnchecked(int offset); private: + BytecodeArrayIterator(const BytecodeArrayIterator& other, + DisallowGarbageCollection& no_gc V8_LIFETIME_BOUND) + : bytecode_array_(other.bytecode_array_), + start_(other.start_), + end_(other.end_), + cursor_(other.cursor_), + current_bytecode_(other.current_bytecode_), + operand_scale_(other.operand_scale_), + prefix_size_(other.prefix_size_), + local_heap_(nullptr) {} + uint32_t GetUnsignedOperand(int operand_index, OperandType operand_type) const; int32_t GetSignedOperand(int operand_index, OperandType operand_type) const; diff --git a/deps/v8/src/interpreter/bytecode-array-writer.cc b/deps/v8/src/interpreter/bytecode-array-writer.cc index e9b93787ad74..de8f1b2c4995 100644 --- a/deps/v8/src/interpreter/bytecode-array-writer.cc +++ b/deps/v8/src/interpreter/bytecode-array-writer.cc @@ -170,8 +170,8 @@ void BytecodeArrayWriter::WriteJumpLoop(BytecodeNode* node, void BytecodeArrayWriter::WriteSwitch(BytecodeNode* node, BytecodeJumpTable* jump_table) { DCHECK(Bytecodes::IsSwitch(node->bytecode())); + CHECK(!exit_seen_in_block_); - if (exit_seen_in_block_) return; // Don't emit dead code. UpdateExitSeenInBlock(node->bytecode()); MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid()); diff --git a/deps/v8/src/interpreter/bytecode-flags-and-tokens.cc b/deps/v8/src/interpreter/bytecode-flags-and-tokens.cc index b4870d406b4a..14aadec83675 100644 --- a/deps/v8/src/interpreter/bytecode-flags-and-tokens.cc +++ b/deps/v8/src/interpreter/bytecode-flags-and-tokens.cc @@ -29,12 +29,8 @@ uint8_t CreateObjectLiteralFlags::Encode(int runtime_flags, } // static -uint8_t CreateClosureFlags::Encode(bool pretenure, bool is_function_scope) { - uint8_t result = PretenuredBit::encode(pretenure); - if (!pretenure && is_function_scope) { - result |= FastNewClosureBit::encode(true); - } - return result; +uint8_t CreateClosureFlags::Encode(bool is_function_scope) { + return FastNewClosureBit::encode(is_function_scope); } // static diff --git a/deps/v8/src/interpreter/bytecode-flags-and-tokens.h b/deps/v8/src/interpreter/bytecode-flags-and-tokens.h index 0adacdcd93d9..871270720834 100644 --- a/deps/v8/src/interpreter/bytecode-flags-and-tokens.h +++ b/deps/v8/src/interpreter/bytecode-flags-and-tokens.h @@ -39,12 +39,11 @@ class CreateObjectLiteralFlags { DISALLOW_IMPLICIT_CONSTRUCTORS(CreateObjectLiteralFlags); }; -class CreateClosureFlags { +class V8_EXPORT_PRIVATE CreateClosureFlags { public: - using PretenuredBit = base::BitField8<bool, 0, 1>; - using FastNewClosureBit = PretenuredBit::Next<bool, 1>; + using FastNewClosureBit = base::BitField8<bool, 0, 1>; - static uint8_t Encode(bool pretenure, bool is_function_scope); + static uint8_t Encode(bool is_function_scope); private: DISALLOW_IMPLICIT_CONSTRUCTORS(CreateClosureFlags); @@ -97,6 +96,23 @@ class StoreLookupSlotFlags { DISALLOW_IMPLICIT_CONSTRUCTORS(StoreLookupSlotFlags); }; +class ResolveEvalFlags { + public: + using LanguageModeBit = base::BitField<LanguageMode, 0, 1>; + using PrivateNameLookupSkipsOuterClassBit = LanguageModeBit::Next<bool, 1>; + static_assert(LanguageModeSize <= LanguageModeBit::kNumValues); + + static int Encode(LanguageMode language_mode, + bool private_name_lookup_skips_outer_class) { + return LanguageModeBit::encode(language_mode) | + PrivateNameLookupSkipsOuterClassBit::encode( + private_name_lookup_skips_outer_class); + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ResolveEvalFlags); +}; + enum class TryFinallyContinuationToken: int { // Fixed value tokens for paths we know we need. // Fallthrough is set to -1 to make it the fallthrough case of the jump table, diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index b6b593263013..186cca1a12f0 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -289,7 +289,7 @@ class V8_NODISCARD BytecodeGenerator::ControlScope::DeferredCommands final { // Applies all recorded control-flow commands after the finally-block again. // This generates a dynamic dispatch on the token from the entry point. void ApplyDeferredCommands() { - if (deferred_.empty()) return; + if (deferred_.empty() || builder()->RemainderOfBlockIsDead()) return; BytecodeLabel fall_through_from_try_block; @@ -2667,11 +2667,10 @@ bool IsSwitchOptimizable(SwitchStatement* stmt, SwitchInfo* info) { } // This flag is not allowed to be <= 0. - DCHECK_GT(v8_flags.switch_table_min_cases, 0); + DCHECK_GT(v8_flags.switch_table_min_cases, 0u); // GCC also jump-table optimizes switch statements with 6 cases or more. - if (static_cast<int>(info->covered_cases.size()) >= - v8_flags.switch_table_min_cases) { + if (info->covered_cases.size() >= v8_flags.switch_table_min_cases) { // Due to case spread will be used as the size of jump-table, // we need to check if it doesn't overflow by casting its // min and max bounds to int64_t, and calculate if the difference is less @@ -2763,10 +2762,16 @@ bool IsSwitchOptimizable(SwitchStatement* stmt, SwitchInfo* info) { // <out = 19, break> void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { + if (builder()->RemainderOfBlockIsDead()) return; + // We need this scope because we visit for register values. We have to // maintain an execution result scope where registers can be allocated. ZonePtrList<CaseClause>* clauses = stmt->cases(); + builder()->SetStatementPosition(stmt); + VisitForAccumulatorValue(stmt->tag()); + if (builder()->RemainderOfBlockIsDead()) return; + SwitchInfo info; BytecodeJumpTable* jump_table = nullptr; bool use_jump_table = IsSwitchOptimizable(stmt, &info); @@ -2790,9 +2795,6 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { SwitchBuilder switch_builder(builder(), block_coverage_builder_, stmt, n_comp_cases, jump_table); ControlScopeForBreakable scope(this, stmt, &switch_builder); - builder()->SetStatementPosition(stmt); - - VisitForAccumulatorValue(stmt->tag()); if (use_jump_table) { // Release temps so that they can be reused in clauses. @@ -3498,8 +3500,8 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { CHECK_LT(info_->literal()->function_literal_id(), expr->function_literal_id()); CHECK_EQ(expr->scope()->outer_scope(), current_scope()); - uint8_t flags = CreateClosureFlags::Encode( - expr->pretenure(), closure_scope()->is_function_scope()); + uint8_t flags = + CreateClosureFlags::Encode(closure_scope()->is_function_scope()); size_t entry = builder()->AllocateDeferredConstantPoolEntry(); builder()->CreateClosure(entry, GetNewClosureSlot(expr), flags); function_literals_.push_back(std::make_pair(expr, entry)); @@ -3691,7 +3693,10 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex, args.register_count()); - VisitForAccumulatorValueOrTheHole(expr->extends()); + { + ClassScope::HeritageParsingScope heritage(expr->scope()); + VisitForAccumulatorValueOrTheHole(expr->extends()); + } builder()->StoreAccumulatorInRegister(super_class); VisitFunctionLiteral(expr->constructor()); @@ -4058,7 +4063,7 @@ void BytecodeGenerator::VisitNativeFunctionLiteral( // kDontAdaptArgumentsSentinel as their parameter count. int index = feedback_spec()->AddCreateClosureParameterCount( kDontAdaptArgumentsSentinel); - uint8_t flags = CreateClosureFlags::Encode(false, false); + uint8_t flags = CreateClosureFlags::Encode(false); builder()->CreateClosure(entry, index, flags); native_function_literals_.push_back(std::make_pair(expr, entry)); } @@ -4286,13 +4291,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(property->value()); if (key->IsStringLiteral()) { FeedbackSlot slot = feedback_spec()->AddDefineNamedOwnICSlot(); - if (clone_object_spread) { - builder()->DefineNamedOwnProperty( - literal, key->AsRawPropertyName(), feedback_index(slot)); - } else { - builder()->DefineNamedOwnPropertyInLiteral( - literal, key->AsRawPropertyName(), feedback_index(slot)); - } + builder()->DefineNamedOwnPropertyInLiteral( + literal, key->AsRawPropertyName(), feedback_index(slot)); } else { FeedbackSlot slot = feedback_spec()->AddDefineKeyedOwnICSlot(); builder()->DefineKeyedOwnProperty( @@ -4811,8 +4811,8 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, default: { // Normally, private names should not be looked up dynamically, // but we make an exception in debug-evaluate, in that case the - // lookup will be done in %SetPrivateMember() and %GetPrivateMember() - // calls, not here. + // lookup will be done in %HasPrivateMember(), %SetPrivateMember(), + // and %GetPrivateMember() calls, not here. DCHECK(!variable->raw_name()->IsPrivateName()); builder()->LoadLookupSlot(variable->raw_name(), typeof_mode); break; @@ -5106,6 +5106,14 @@ void BytecodeGenerator::BuildVariableAssignment( BuildHoleCheckForVariableAssignment(variable, op); builder()->LoadAccumulatorWithRegister(value_temp); } + if (op == Token::kInit) { + if (variable->HasHoleCheckUseInSameClosureScope()) { + // After initializing a variable it won't be the hole anymore, so + // elide subsequent checks. + RememberHoleCheckInCurrentBlock(variable); + } + AddDisposableValue(mode); + } builder()->StoreModuleVariable(variable->index(), depth); break; } @@ -5133,6 +5141,10 @@ void BytecodeGenerator::BuildVariableAssignment( } else { if (mode == VariableMode::kConst) { builder()->CallRuntime(Runtime::kThrowConstAssignError); + } else if (mode == VariableMode::kUsing) { + builder()->CallRuntime(Runtime::kThrowUsingAssignError); + } else if (mode == VariableMode::kAwaitUsing) { + builder()->CallRuntime(Runtime::kThrowAwaitUsingAssignError); } else { BuildStoreGlobal(variable); } @@ -6124,6 +6136,7 @@ void BytecodeGenerator::BuildSuspendPoint(int position) { void BytecodeGenerator::VisitYield(Yield* expr) { builder()->SetExpressionPosition(expr); VisitForAccumulatorValue(expr->expression()); + if (builder()->RemainderOfBlockIsDead()) return; bool is_async = IsAsyncGeneratorFunction(function_kind()); // If this is not the first yield @@ -6291,6 +6304,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { RegisterAllocationScope register_scope(this); RegisterList iterator_and_input = register_allocator()->NewRegisterList(2); VisitForAccumulatorValue(expr->expression()); + if (builder()->RemainderOfBlockIsDead()) return; IteratorRecord iterator = BuildGetIteratorRecord( register_allocator()->NewRegister() /* next method */, iterator_and_input[0], iterator_type); @@ -6583,6 +6597,7 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { } case PRIVATE_GETTER_ONLY: case PRIVATE_GETTER_AND_SETTER: { + RegisterAllocationScope register_scope(this); Register key = VisitForRegisterValue(property->key()); BuildPrivateBrandCheck(property, obj); BuildPrivateGetterAccess(obj, key); @@ -6630,6 +6645,22 @@ void BytecodeGenerator::BuildPrivateDebugDynamicSet(Property* property, .CallRuntime(Runtime::kSetPrivateMember, args); } +void BytecodeGenerator::BuildPrivateDebugDynamicIn( + Variable* private_name, Expression* object_expression) { + DCHECK_EQ(private_name->mode(), VariableMode::kDynamic); + VisitForAccumulatorValue(object_expression); + + RegisterAllocationScope scope(this); + RegisterList args = register_allocator()->NewRegisterList(2); + builder()->SetExpressionPosition(object_expression); + builder() + ->StoreAccumulatorInRegister(args[0]) + .LoadLiteral(private_name->raw_name()) + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kHasPrivateMember, args); + execution_result()->SetResultIsBoolean(); +} + void BytecodeGenerator::BuildPrivateGetterAccess(Register object, Register accessor_pair) { RegisterAllocationScope scope(this); @@ -6869,7 +6900,7 @@ void BytecodeGenerator::VisitProperty(Property* expr) { void BytecodeGenerator::VisitArguments(const ZonePtrList<Expression>* args, RegisterList* arg_regs) { // Visit arguments. - builder()->UpdateMaxArguments(static_cast<uint16_t>(args->length())); + builder()->UpdateMaxArguments(args->length()); for (int i = 0; i < static_cast<int>(args->length()); i++) { VisitAndPushIntoRegisterList(args->at(i), arg_regs); } @@ -7061,16 +7092,24 @@ void BytecodeGenerator::VisitCall(Call* expr) { builder()->MoveRegister(args[receiver_arg_count], runtime_call_args[1]); } Scope* scope_with_context = current_scope(); + bool private_name_lookup_skips_outer_class = false; if (!scope_with_context->NeedsContext()) { + private_name_lookup_skips_outer_class = + scope_with_context->private_name_lookup_skips_outer_class(); scope_with_context = scope_with_context->GetOuterScopeWithContext(); + } else if (scope_with_context->is_class_scope()) { + private_name_lookup_skips_outer_class = + scope_with_context->AsClassScope()->IsParsingHeritage(); } if (scope_with_context) { eval_calls_.emplace_back(expr, scope_with_context); } + int eval_flags = ResolveEvalFlags::Encode( + language_mode(), private_name_lookup_skips_outer_class); builder() ->MoveRegister(callee, runtime_call_args[0]) .MoveRegister(Register::function_closure(), runtime_call_args[2]) - .LoadLiteral(Smi::FromEnum(language_mode())) + .LoadLiteral(Smi::FromInt(eval_flags)) .StoreAccumulatorInRegister(runtime_call_args[3]) .LoadLiteral(Smi::FromInt(expr->eval_scope_info_index())) .StoreAccumulatorInRegister(runtime_call_args[4]) @@ -7971,6 +8010,10 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { BuildPrivateMethodIn(var, expr->right()); return; } + if (var->mode() == VariableMode::kDynamic) { + BuildPrivateDebugDynamicIn(var, expr->right()); + return; + } // For private fields, the code below does the right thing. } diff --git a/deps/v8/src/interpreter/bytecode-generator.h b/deps/v8/src/interpreter/bytecode-generator.h index bdea0ba4fc68..6e6505ddc417 100644 --- a/deps/v8/src/interpreter/bytecode-generator.h +++ b/deps/v8/src/interpreter/bytecode-generator.h @@ -420,6 +420,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { void BuildPrivateDebugDynamicGet(Property* property, Register obj); void BuildPrivateDebugDynamicSet(Property* property, Register obj, Register value); + void BuildPrivateDebugDynamicIn(Variable* private_name, + Expression* object_expression); void BuildPrivateMethods(ClassLiteral* expr, bool is_static, Register home_object); void BuildClassProperty(ClassLiteral::Property* property); diff --git a/deps/v8/src/interpreter/bytecode-jump-table.h b/deps/v8/src/interpreter/bytecode-jump-table.h index 69012659ee87..f63a29594238 100644 --- a/deps/v8/src/interpreter/bytecode-jump-table.h +++ b/deps/v8/src/interpreter/bytecode-jump-table.h @@ -35,7 +35,10 @@ class V8_EXPORT_PRIVATE BytecodeJumpTable final : public ZoneObject { } size_t constant_pool_index() const { return constant_pool_index_; } - size_t switch_bytecode_offset() const { return switch_bytecode_offset_; } + size_t switch_bytecode_offset() const { + DCHECK_NE(switch_bytecode_offset_, kInvalidOffset); + return switch_bytecode_offset_; + } OperandScale switch_bytecode_operand_scale() const { return switch_bytecode_operand_scale_; } diff --git a/deps/v8/src/interpreter/bytecode-node.cc b/deps/v8/src/interpreter/bytecode-node.cc index dc8e4683d3b5..37b30c9634df 100644 --- a/deps/v8/src/interpreter/bytecode-node.cc +++ b/deps/v8/src/interpreter/bytecode-node.cc @@ -17,7 +17,8 @@ void BytecodeNode::Print(std::ostream& os) const { os << Bytecodes::ToString(bytecode_); for (int i = 0; i < operand_count(); ++i) { - os << ' ' << std::setw(8) << std::setfill('0') << std::hex << operands_[i]; + os << ' ' << std::setw(8) << std::setfill('0') << std::hex << operands_[i] + << std::dec; } os.copyfmt(saved_state); diff --git a/deps/v8/src/interpreter/bytecodes.h b/deps/v8/src/interpreter/bytecodes.h index 965fa710d215..9c6cbee504ab 100644 --- a/deps/v8/src/interpreter/bytecodes.h +++ b/deps/v8/src/interpreter/bytecodes.h @@ -859,12 +859,10 @@ class V8_EXPORT_PRIVATE Bytecodes final : public AllStatic { } // Return true if |bytecode| is a jump without effects, - // e.g. any jump excluding those that include type coercion like - // JumpIfToBooleanTrue/False, and JumpLoop due to having an implicit + // e.g. any jump excluding JumpLoop due to having an implicit // StackCheck. static constexpr bool IsJumpWithoutEffects(Bytecode bytecode) { - return IsJump(bytecode) && bytecode != Bytecode::kJumpLoop && - !IsJumpIfToBoolean(bytecode); + return IsJump(bytecode) && bytecode != Bytecode::kJumpLoop; } // Returns true if the bytecode is a switch. diff --git a/deps/v8/src/interpreter/interpreter-assembler.cc b/deps/v8/src/interpreter/interpreter-assembler.cc index b8fbf96e0b94..8ce10546173a 100644 --- a/deps/v8/src/interpreter/interpreter-assembler.cc +++ b/deps/v8/src/interpreter/interpreter-assembler.cc @@ -1553,9 +1553,10 @@ void InterpreterAssembler::OnStackReplacement( // Case 2). { - static_assert(FeedbackVector::OsrUrgencyBits::kShift == 0); + static_assert(FeedbackVector::OsrState::OsrUrgencyBits::kShift == 0); TNode<Int32T> osr_urgency = Word32And( - osr_state, Int32Constant(FeedbackVector::OsrUrgencyBits::kMask)); + osr_state, + Int32Constant(FeedbackVector::OsrState::OsrUrgencyBits::kMask)); GotoIf(Uint32LessThan(loop_depth, osr_urgency), &maybe_osr_to_opt); Goto(&baseline); @@ -1564,7 +1565,8 @@ void InterpreterAssembler::OnStackReplacement( TNode<Uint16T> flags = LoadObjectField<Uint16T>( feedback_vector, offsetof(FeedbackVector, flags_)); TNode<Word32T> in_progress = Word32And( - flags, Int32Constant(FeedbackVector::OsrTieringInProgressBit::kMask)); + flags, + Int32Constant(FeedbackVector::Flags::OsrTieringInProgressBit::kMask)); GotoIf(Word32Equal(in_progress, 0), &osr_to_opt); Goto(&baseline); } @@ -1599,40 +1601,12 @@ void InterpreterAssembler::OnStackReplacement( BIND(&osr_to_sparkplug); { - Label skip_osr_to_sparkplug(this); - // InterpreterEntryTrampoline only checks BytecodeArray::frame_size_, - // whereas baseline code requires BytecodeArray::max_frame_size() - // (frame_size_ + max_arguments_) so it can push outgoing call arguments - // without a stack check. Since frame_size_ is already allocated in the - // current interpreter frame, verify that there is enough remaining stack - // space for max_arguments_ before OSRing into baseline code. - // - // If there isn't enough space, we skip OSR and stay in the interpreter - // rather than throwing a StackOverflow here: exception handler lookup in - // the interpreter is keyed by bytecode offset, so throwing at JumpLoop - // could be caught by an inner try-catch wrapping the loop (and the call - // requiring max_arguments_ might not even be reached). Skipping means we - // will re-check on subsequent backedge interrupts while near the stack - // limit, which is an acceptable cost for this edge case. - TNode<Uint16T> max_arguments = LoadObjectField<Uint16T>( - BytecodeArrayTaggedPointer(), offsetof(BytecodeArray, max_arguments_)); - TNode<UintPtrT> max_arguments_bytes = - TimesSystemPointerSize(ChangeUint32ToWord(max_arguments)); - TNode<UintPtrT> stack_limit = - Load<UintPtrT>(IsolateField(IsolateFieldId::kRealJsLimit)); - GotoIfNot( - StackPointerGreaterThan(IntPtrAdd(stack_limit, max_arguments_bytes)), - &skip_osr_to_sparkplug); - // We already compiled the baseline code, so we don't need to handle failed // compilation as in the Ignition -> Turbofan case. Therefore we can just // tailcall to the OSR builtin. SaveBytecodeOffset(); TailCallBuiltin(Builtin::kInterpreterOnStackReplacement_ToBaseline, context); - - BIND(&skip_osr_to_sparkplug); - JumpBackward(relative_jump); } } diff --git a/deps/v8/src/interpreter/interpreter-generator.cc b/deps/v8/src/interpreter/interpreter-generator.cc index 73eee42791ae..09a8c737b1db 100644 --- a/deps/v8/src/interpreter/interpreter-generator.cc +++ b/deps/v8/src/interpreter/interpreter-generator.cc @@ -2499,10 +2499,10 @@ IGNITION_HANDLER(JumpLoop, InterpreterAssembler) { Label maybe_osr_because_osr_state(this, Label::kDeferred); // The quick initial OSR check. If it passes, we proceed on to more expensive // OSR logic. - static_assert(FeedbackVector::MaybeHasMaglevOsrCodeBit::encode(true) > - FeedbackVector::kMaxOsrUrgency); - static_assert(FeedbackVector::MaybeHasTurbofanOsrCodeBit::encode(true) > - FeedbackVector::kMaxOsrUrgency); + static_assert(FeedbackVector::OsrState::MaybeHasMaglevOsrCodeBit::encode( + true) > FeedbackVector::kMaxOsrUrgency); + static_assert(FeedbackVector::OsrState::MaybeHasTurbofanOsrCodeBit::encode( + true) > FeedbackVector::kMaxOsrUrgency); GotoIfNot(Uint32GreaterThanOrEqual(loop_depth, osr_state), &maybe_osr_because_osr_state); @@ -2887,14 +2887,14 @@ IGNITION_HANDLER(GetTemplateObject, InterpreterAssembler) { // CreateClosure <index> <slot> <flags> // // Creates a new closure for SharedFunctionInfo at position |index| in the -// constant pool and with pretenuring controlled by |flags|. +// constant pool. Uses the FastNewClosure builtin if FastNewClosureBit is set +// in |flags|, otherwise calls the runtime. IGNITION_HANDLER(CreateClosure, InterpreterAssembler) { TNode<Object> shared = LoadConstantPoolEntryAtOperandIndex(0); TNode<Uint32T> flags = BytecodeOperandFlag8(2); TNode<Context> context = GetContext(); TNode<UintPtrT> slot = BytecodeOperandFeedbackSlot(1); - Label if_undefined(this); TNode<ClosureFeedbackCellArray> feedback_cell_array = LoadClosureFeedbackArray(LoadFunctionClosure()); TNode<FeedbackCell> feedback_cell = @@ -2914,25 +2914,10 @@ IGNITION_HANDLER(CreateClosure, InterpreterAssembler) { BIND(&if_slow); { - Label if_newspace(this), if_oldspace(this); - Branch(IsSetWord32<CreateClosureFlags::PretenuredBit>(flags), &if_oldspace, - &if_newspace); - - BIND(&if_newspace); - { - TNode<Object> result = - CallRuntime(Runtime::kNewClosure, context, shared, feedback_cell); - SetAccumulator(result); - Dispatch(); - } - - BIND(&if_oldspace); - { - TNode<Object> result = CallRuntime(Runtime::kNewClosure_Tenured, context, - shared, feedback_cell); - SetAccumulator(result); - Dispatch(); - } + TNode<Object> result = + CallRuntime(Runtime::kNewClosure, context, shared, feedback_cell); + SetAccumulator(result); + Dispatch(); } } @@ -3034,7 +3019,7 @@ IGNITION_HANDLER(CreateMappedArguments, InterpreterAssembler) { TNode<Uint32T> flags = LoadObjectField<Uint32T>( shared_info, offsetof(SharedFunctionInfo, flags_)); TNode<BoolT> has_duplicate_parameters = - IsSetWord32<SharedFunctionInfo::HasDuplicateParametersBit>(flags); + IsSetWord32<SharedFunctionInfo::Flags::HasDuplicateParametersBit>(flags); Branch(has_duplicate_parameters, &if_duplicate_parameters, &if_not_duplicate_parameters); @@ -3343,14 +3328,14 @@ IGNITION_HANDLER(ForInEnumerate, InterpreterAssembler) { // |cache_info_triple + 2|, with the registers holding cache_type, cache_array, // and cache_length respectively. IGNITION_HANDLER(ForInPrepare, InterpreterAssembler) { - // The {enumerator} is either a Map or a FixedArray. + // The {enumerator} is either a Map, a FixedArray, or a ForInEnumeratorHolder. TNode<HeapObject> enumerator = CAST(GetAccumulator()); TNode<UintPtrT> vector_index = BytecodeOperandFeedbackSlot(1); TNode<Union<FeedbackVector, Undefined>> maybe_feedback_vector = LoadFeedbackVector(); TNode<HeapObject> cache_type = enumerator; // Just to clarify the rename. - TNode<FixedArray> cache_array; + TNode<Union<FixedArray, ForInEnumeratorHolder>> cache_array; TNode<Smi> cache_length; ForInPrepare(enumerator, vector_index, maybe_feedback_vector, &cache_array, &cache_length, UpdateFeedbackMode::kOptionalFeedback); @@ -3374,26 +3359,90 @@ IGNITION_HANDLER(ForInNext, InterpreterAssembler) { TNode<Union<FeedbackVector, Undefined>> maybe_feedback_vector = LoadFeedbackVector(); - // Load the next key from the enumeration array. - TNode<JSAny> key = CAST(LoadFixedArrayElement(CAST(cache_array), index, 0)); - - // Check if we can use the for-in fast path potentially using the enum cache. - Label if_fast(this), if_slow(this, Label::kDeferred); + // Check if the expected map still matches that of the {receiver}. If so, + // {cache_array} is the enum cache keys FixedArray. + Label if_fast_enum_cache(this), if_not_fast_enum_cache(this); TNode<Map> receiver_map = LoadMap(receiver); - Branch(TaggedEqual(receiver_map, cache_type), &if_fast, &if_slow); - BIND(&if_fast); + Branch(TaggedEqual(receiver_map, cache_type), &if_fast_enum_cache, + &if_not_fast_enum_cache); + + BIND(&if_fast_enum_cache); { - // Enum cache in use for {receiver}, the {key} is definitely valid. - SetAccumulator(key); + SetAccumulator(LoadFixedArrayElement(CAST(cache_array), index)); Dispatch(); } - BIND(&if_slow); + + BIND(&if_not_fast_enum_cache); { - TNode<Object> result = ForInNextSlow(GetContext(), vector_index, receiver, - key, cache_type, maybe_feedback_vector, - UpdateFeedbackMode::kOptionalFeedback); - SetAccumulator(result); - Dispatch(); + TVARIABLE(JSAny, var_key); + Label if_holder(this), if_fixed_array(this), + if_slow(this, Label::kDeferred); + + TNode<Uint16T> instance_type = LoadInstanceType(CAST(cache_array)); + Branch(InstanceTypeEqual(instance_type, FOR_IN_ENUMERATOR_HOLDER_TYPE), + &if_holder, &if_fixed_array); + + BIND(&if_holder); + { + TNode<ForInEnumeratorHolder> holder = CAST(cache_array); + TNode<Smi> elements_length = LoadObjectField<Smi>( + holder, ObjectTraits<ForInEnumeratorHolder>::kElementsLengthOffset); + + Label if_elements(this), if_named(this), check_validity(this); + Branch(SmiLessThan(index, elements_length), &if_elements, &if_named); + + BIND(&if_elements); + { + var_key = NumberToString(index); + Goto(&check_validity); + } + + BIND(&if_named); + { + TNode<FixedArray> named_keys = LoadObjectField<FixedArray>( + holder, ObjectTraits<ForInEnumeratorHolder>::kNamedKeysOffset); + TNode<Smi> named_index = SmiSub(index, elements_length); + var_key = CAST(LoadFixedArrayElement(named_keys, named_index)); + Goto(&check_validity); + } + + BIND(&check_validity); + { + Label if_holder_valid(this); + Branch(CheckHolderValidity(receiver, holder), &if_holder_valid, + &if_slow); + + BIND(&if_holder_valid); + { + // Record feedback in case the FeedbackVector was lazily allocated + // inside the loop (after ForInPrepare). This avoids a deopt on OSR + // or subsequent optimization, because Maglev assumes + // kEnumCacheKeys/kEnumCacheKeysAndIndices when feedback is missing + // (kNone). UpdateFeedback only writes to the slot if the feedback + // value actually changes. + UpdateFeedback(SmiConstant(ForInFeedback::kEnumeratorHolder), + maybe_feedback_vector, vector_index, + UpdateFeedbackMode::kOptionalFeedback); + SetAccumulator(var_key.value()); + Dispatch(); + } + } + } + + BIND(&if_fixed_array); + { + var_key = CAST(LoadFixedArrayElement(CAST(cache_array), index)); + Goto(&if_slow); + } + + BIND(&if_slow); + { + TNode<Object> result = ForInNextSlow( + GetContext(), vector_index, receiver, var_key.value(), cache_type, + maybe_feedback_vector, UpdateFeedbackMode::kOptionalFeedback); + SetAccumulator(result); + Dispatch(); + } } } diff --git a/deps/v8/src/interpreter/interpreter.cc b/deps/v8/src/interpreter/interpreter.cc index 3c3bcbaacada..fab55a744c51 100644 --- a/deps/v8/src/interpreter/interpreter.cc +++ b/deps/v8/src/interpreter/interpreter.cc @@ -7,9 +7,9 @@ #include <fstream> #include <memory> -#include "builtins-generated/bytecodes-builtins-list.h" #include "src/ast/prettyprinter.h" #include "src/ast/scopes.h" +#include "src/builtins/bytecodes-builtins-list.h" #include "src/codegen/compiler.h" #include "src/codegen/unoptimized-compilation-info.h" #include "src/common/globals.h" @@ -145,8 +145,7 @@ bool ShouldPrintBytecode(DirectHandle<SharedFunctionInfo> shared) { // Checks whether function passed the filter. if (shared->is_toplevel()) { - base::Vector<const char> filter = - base::CStrVector(v8_flags.print_bytecode_filter); + std::string_view filter(v8_flags.print_bytecode_filter); return filter.empty() || (filter.length() == 1 && filter[0] == '*'); } else { return shared->PassesFilter(v8_flags.print_bytecode_filter); diff --git a/deps/v8/src/json/json-parser.cc b/deps/v8/src/json/json-parser.cc index 9fb474514c55..cc719efd7c58 100644 --- a/deps/v8/src/json/json-parser.cc +++ b/deps/v8/src/json/json-parser.cc @@ -537,14 +537,17 @@ void JsonParser<Char>::ReportUnexpectedToken( ? Cast<SlicedString>(*original_source_)->offset() : 0; int pos = position() - offset; - DirectHandle<Object> arg(Smi::FromInt(pos), isolate()); + DirectHandle<Object> arg; DirectHandle<Object> arg2; DirectHandle<Object> arg3; - CalculateFileLocation(arg2, arg3); MessageTemplate message = errorMessage ? errorMessage.value() : LookUpErrorMessageForJsonToken(token, arg, arg2, pos); + if (arg.is_null() && message != MessageTemplate::kJsonParseUnexpectedEOS) { + arg = direct_handle(Smi::FromInt(pos), isolate()); + CalculateFileLocation(arg2, arg3); + } Handle<Script> script(factory->NewScript(original_source_)); DCHECK_IMPLIES(isolate_->NeedsSourcePositions(), script->has_line_ends()); @@ -571,8 +574,14 @@ void JsonParser<Char>::ReportUnexpectedToken( // separated source file. isolate()->debug()->OnCompileError(script); MessageLocation location(script, pos, pos + 1); - isolate()->ThrowAt(factory->NewSyntaxError(message, arg, arg2, arg3), - &location); + DirectHandle<Object> args[] = {arg, arg2, arg3}; + size_t num_args = 0; + while (num_args < arraysize(args) && !args[num_args].is_null()) { + ++num_args; + } + isolate()->ThrowAt( + factory->NewSyntaxError(message, base::VectorOf(args, num_args)), + &location); // Move the cursor to the end so we won't be able to proceed parsing. cursor_ = end_; @@ -885,11 +894,11 @@ Handle<JSObject> JsonParser<Char>::BuildJsonObject(const JsonContinuation& cont, PropertyDetails details = descriptors->GetDetails(InternalIndex(i)); if (details.representation().IsDouble()) { if (IsSmi(value)) { - value = hn_allocator.AllocateNext( - roots, Float64::FromMaybeNaN(Smi::ToInt(value))); + value = + hn_allocator.Allocate(Float64::FromMaybeNaN(Smi::ToInt(value))); } else if constexpr (should_track_json_source) { - value = hn_allocator.AllocateNext( - roots, Float64::FromMaybeNaN(Object::NumberValue(value))); + value = hn_allocator.Allocate( + Float64::FromMaybeNaN(Object::NumberValue(value))); } } FieldIndex index = FieldIndex::ForInObjectOffset( @@ -1460,11 +1469,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonArray() { template <typename Char> template <bool should_track_json_source> MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { - std::vector<JsonContinuation> cont_stack; - - cont_stack.reserve(16); - - JsonContinuation cont(isolate_, JsonContinuation::kReturn, 0); + JsonContinuations cont(isolate_); Handle<Object> value; @@ -1553,9 +1558,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { } // Start parsing an object with properties. - cont_stack.emplace_back(std::move(cont)); - cont = JsonContinuation(isolate_, JsonContinuation::kObjectProperty, - property_stack_.size()); + cont.New(JsonContinuation::kObjectProperty, property_stack_.size()); // Parse the property key. // GetNextNonWhitespaceToken was already performed by @@ -1563,7 +1566,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { EXPECT_RETURN_ON_ERROR( JsonToken::STRING, MessageTemplate::kJsonParseExpectedPropNameOrRBrace, {}); - property_stack_.emplace_back(ScanJsonPropertyKey(&cont)); + property_stack_.emplace_back(ScanJsonPropertyKey(&cont.current())); if constexpr (should_track_json_source) { property_val_node_stack.emplace_back(Handle<Object>()); } @@ -1587,9 +1590,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { } // Start parsing an array with elements. - cont_stack.emplace_back(std::move(cont)); - cont = JsonContinuation(isolate_, JsonContinuation::kArrayElement, - element_stack_.size()); + cont.New(JsonContinuation::kArrayElement, element_stack_.size()); // Continue to start producing the first array element. continue; @@ -1625,11 +1626,6 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { case JsonToken::RBRACK: case JsonToken::EOS: ReportUnexpectedCharacter(CurrentCharacter()); - // Pop the continuation stack to correctly tear down handle scopes. - while (!cont_stack.empty()) { - cont = std::move(cont_stack.back()); - cont_stack.pop_back(); - } return MaybeHandle<Object>(); case JsonToken::WHITESPACE: @@ -1646,15 +1642,15 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { while (true) { // The switch is immediately followed by 'break' so we can use 'break' to // break out of the loop, and 'continue' to continue the loop. - switch (cont.type()) { + switch (cont.current().type()) { case JsonContinuation::kReturn: if constexpr (should_track_json_source) { DCHECK(!val_node.is_null()); - Tagged<Object> raw_value = *value; - parsed_val_node_ = cont.scope.CloseAndEscape(val_node); - return cont.scope.CloseAndEscape(handle(raw_value, isolate_)); + std::tie(value, parsed_val_node_) = + cont.CloseAndEscape(value, val_node); + return value; } else { - return cont.scope.CloseAndEscape(value); + return cont.CloseAndEscape(value); } case JsonContinuation::kObjectProperty: { @@ -1671,7 +1667,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName, {}); - property_stack_.emplace_back(ScanJsonPropertyKey(&cont)); + property_stack_.emplace_back(ScanJsonPropertyKey(&cont.current())); if constexpr (should_track_json_source) { property_val_node_stack.emplace_back(Handle<Object>()); } @@ -1684,9 +1680,7 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { } Handle<Map> feedback; - if (cont_stack.size() > 0 && - cont_stack.back().type() == JsonContinuation::kArrayElement && - cont_stack.back().index() < element_stack_.size() && + if (cont.HasArrayFeedback(element_stack_.size()) && IsJSObject(*element_stack_.back())) { Tagged<Map> maybe_feedback = Cast<JSObject>(*element_stack_.back())->map(); @@ -1696,13 +1690,14 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { feedback = handle(maybe_feedback, isolate_); } } - value = BuildJsonObject<should_track_json_source>(cont, feedback); + value = BuildJsonObject<should_track_json_source>(cont.current(), + feedback); EXPECT_RETURN_ON_ERROR( JsonToken::RBRACE, MessageTemplate::kJsonParseExpectedCommaOrRBrace, {}); // Return the object. + size_t start = cont.current().index(); if constexpr (should_track_json_source) { - size_t start = cont.index(); int num_properties = static_cast<int>(property_stack_.size() - start); Handle<ObjectTwoHashTable> table = @@ -1722,20 +1717,13 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { isolate(), table, key, {property_val_node, property_snapshot}); } - property_val_node_stack.resize(cont.index()); - DisallowGarbageCollection no_gc; - Tagged<ObjectTwoHashTable> raw_table = *table; - value = cont.scope.CloseAndEscape(value); - val_node = cont.scope.CloseAndEscape(handle(raw_table, isolate_)); + property_val_node_stack.resize(start); + std::tie(value, val_node) = cont.PopAndEscape(value, table); } else { - value = cont.scope.CloseAndEscape(value); + value = cont.PopAndEscape(value); } - property_stack_.resize(cont.index()); - - // Pop the continuation. - cont = std::move(cont_stack.back()); - cont_stack.pop_back(); - // Consume to produced object. + property_stack_.resize(start); + // Consume the produced object. continue; } @@ -1748,13 +1736,13 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { // Break to start producing the subsequent element value. if (V8_LIKELY(Check<JsonToken::COMMA>())) break; - value = BuildJsonArray(cont.index()); + size_t start = cont.current().index(); + value = BuildJsonArray(start); EXPECT_RETURN_ON_ERROR( JsonToken::RBRACK, MessageTemplate::kJsonParseExpectedCommaOrRBrack, {}); // Return the array. if constexpr (should_track_json_source) { - size_t start = cont.index(); int num_elements = static_cast<int>(element_stack_.size() - start); DirectHandle<FixedArray> val_node_and_snapshot_array = factory()->NewFixedArray(num_elements * 2); @@ -1767,17 +1755,13 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { raw_val_node_and_snapshot_array->set(i * 2 + 1, *element_stack_[start + i]); } - element_val_node_stack.resize(cont.index()); - value = cont.scope.CloseAndEscape(value); - val_node = cont.scope.CloseAndEscape( - handle(raw_val_node_and_snapshot_array, isolate_)); + element_val_node_stack.resize(start); + std::tie(value, val_node) = + cont.PopAndEscape(value, val_node_and_snapshot_array); } else { - value = cont.scope.CloseAndEscape(value); + value = cont.PopAndEscape(value); } - element_stack_.resize(cont.index()); - // Pop the continuation. - cont = std::move(cont_stack.back()); - cont_stack.pop_back(); + element_stack_.resize(start); // Consume the produced array. continue; } @@ -2101,21 +2085,44 @@ JsonString JsonParser<Char>::ScanJsonString(bool needs_internalization) { bool has_escape = false; base::uc32 bits = 0; - // SIMD constants for one-byte string scanning, hoisted out of the loop. - // Only used in the sizeof(Char)==1 path; dead-store-eliminated for two-byte. - [[maybe_unused]] hw::FixedTag<uint8_t, 16> tag; - [[maybe_unused]] const size_t stride = hw::Lanes(tag); - [[maybe_unused]] const auto mask_0x20 = hw::Set(tag, 0x20); - [[maybe_unused]] const auto mask_quote = hw::Set(tag, '"'); - [[maybe_unused]] const auto mask_backslash = hw::Set(tag, '\\'); + // SIMD constants for string scanning, hoisted out of the loop. + hw::CappedTag<Char, 16 / sizeof(Char)> tag; + const size_t stride = hw::Lanes(tag); + const auto mask_0x20 = hw::Set(tag, 0x20); + const auto mask_quote = hw::Set(tag, '"'); + const auto mask_backslash = hw::Set(tag, '\\'); + [[maybe_unused]] const auto mask_0xff = + hw::Set(tag, unibrow::Latin1::kMaxChar); while (true) { - if constexpr (sizeof(Char) == 1) { - // SIMD fast path: scan 16 bytes at a time looking for characters that - // may terminate a JSON string: '"', '\', or control characters (< 0x20). + if constexpr (sizeof(Char) == 2) { + // While all characters seen so far are Latin1 (<= 0xff), also check for + // characters > 0xff so `bits` tracks whether the string can be one-byte + // converted. + if (V8_LIKELY(bits <= unibrow::Latin1::kMaxChar)) { + for (; cursor_ + (stride - 1) < end_; cursor_ += stride) { + const auto input = hw::LoadU(tag, cursor_); + // TODO(floitsch): use operators for the comparisons when they are + // available on RISC-V. + const auto result = hw::Or( + hw::Or(hw::Lt(input, mask_0x20), hw::Eq(input, mask_quote)), + hw::Or(hw::Eq(input, mask_backslash), hw::Gt(input, mask_0xff))); + if (V8_LIKELY(hw::AllFalse(tag, result))) continue; + cursor_ += hw::FindKnownFirstTrue(tag, result); + break; + } + if (cursor_ < end_ && + V8_UNLIKELY(*cursor_ > unibrow::Latin1::kMaxChar)) { + bits |= *cursor_; + ++cursor_; + } + } + } + // For one-byte strings, or two-byte strings already known to contain a + // non-Latin1 character (bits > 0xff), scan for '"', '\', or control chars. + if (sizeof(Char) == 1 || V8_UNLIKELY(bits > unibrow::Latin1::kMaxChar)) { for (; cursor_ + (stride - 1) < end_; cursor_ += stride) { - const auto input = - hw::LoadU(tag, reinterpret_cast<const uint8_t*>(cursor_)); + const auto input = hw::LoadU(tag, cursor_); // TODO(floitsch): use operators for the comparisons when they are // available on RISC-V. const auto result = @@ -2125,20 +2132,19 @@ JsonString JsonParser<Char>::ScanJsonString(bool needs_internalization) { cursor_ += hw::FindKnownFirstTrue(tag, result); break; } - // Scalar fallback for remaining tail bytes after the last full SIMD - // block. When the SIMD loop found a match, *cursor_ is already a - // special character and this immediately breaks. - for (; cursor_ < end_; ++cursor_) { - if (MayTerminateJsonString(character_json_scan_flags[*cursor_])) break; - } - } else { - cursor_ = std::find_if(cursor_, end_, [&bits](Char c) { + } + // Scalar fallback for remaining tail characters after the last full SIMD + // block. When the SIMD loop found a match, *cursor_ is already a special + // character and this immediately breaks. + for (; cursor_ < end_; ++cursor_) { + Char c = *cursor_; + if constexpr (sizeof(Char) == 2) { if (V8_UNLIKELY(c > unibrow::Latin1::kMaxChar)) { bits |= c; - return false; + continue; } - return MayTerminateJsonString(character_json_scan_flags[c]); - }); + } + if (MayTerminateJsonString(character_json_scan_flags[c])) break; } if (V8_UNLIKELY(is_at_end())) { diff --git a/deps/v8/src/json/json-parser.h b/deps/v8/src/json/json-parser.h index af58f3871ae1..ae2afb251584 100644 --- a/deps/v8/src/json/json-parser.h +++ b/deps/v8/src/json/json-parser.h @@ -261,6 +261,86 @@ class JsonParser final { uint32_t type_and_index_; }; + class JsonContinuations { + public: + explicit JsonContinuations(Isolate* isolate) + : isolate_(isolate), cont_(isolate, JsonContinuation::kReturn, 0) { + stack_.reserve(16); + } + ~JsonContinuations() { + while (!stack_.empty()) { + Pop(); + } + } + + JsonContinuations(const JsonContinuations&) = delete; + JsonContinuations& operator=(const JsonContinuations&) = delete; + + void New(JsonContinuation::Type type, size_t index) { + stack_.emplace_back(std::move(cont_)); + cont_ = JsonContinuation(isolate_, type, index); + } + + template <typename T> + Handle<T> CloseAndEscape(Handle<T> value) { + return cont_.scope.CloseAndEscape(value); + } + + template <typename T, typename U> + std::pair<Handle<T>, Handle<U>> CloseAndEscape(Handle<T> value, + Handle<U> val_node) { + DisallowGarbageCollection no_gc; + Tagged<U> raw_val_node = *val_node; + Handle<T> escaped_value = cont_.scope.CloseAndEscape(value); + Handle<U> escaped_val_node = + cont_.scope.CloseAndEscape(handle(raw_val_node, isolate_)); + return {escaped_value, escaped_val_node}; + } + + // Pops the current continuation (closing its HandleScope) and recreates the + // handle(s) in the restored parent HandleScope. Using CloseAndEscape + // followed by Pop would redundantly close the current HandleScope twice (or + // three times when escaping two handles). + template <typename T> + Handle<T> PopAndEscape(Handle<T> value) { + DisallowGarbageCollection no_gc; + Tagged<T> raw_value = *value; + Pop(); + return handle(raw_value, isolate_); + } + + template <typename T, typename U, template <typename> typename HandleType> + requires(std::is_convertible_v<HandleType<U>, DirectHandle<U>>) + std::pair<Handle<T>, Handle<U>> PopAndEscape(Handle<T> value, + HandleType<U> val_node) { + DisallowGarbageCollection no_gc; + Tagged<T> raw_value = *value; + Tagged<U> raw_val_node = *val_node; + Pop(); + return {handle(raw_value, isolate_), handle(raw_val_node, isolate_)}; + } + + JsonContinuation& current() { return cont_; } + const JsonContinuation& current() const { return cont_; } + + bool HasArrayFeedback(size_t element_stack_size) const { + return !stack_.empty() && + stack_.back().type() == JsonContinuation::kArrayElement && + stack_.back().index() < element_stack_size; + } + + private: + void Pop() { + DCHECK(!stack_.empty()); + cont_ = std::move(stack_.back()); + stack_.pop_back(); + } + + Isolate* isolate_; + std::vector<JsonContinuation> stack_; + JsonContinuation cont_; + }; + JsonParser(Isolate* isolate, Handle<String> source, std::optional<ScriptDetails> script_details); ~JsonParser(); @@ -519,10 +599,14 @@ class JsonParser final { // callable. MaybeHandle<Object> parsed_val_node_; - SmallVector<Handle<Object>> element_stack_; - SmallVector<JsonProperty> property_stack_; - SmallVector<double> double_elements_; - SmallVector<int> smi_elements_; + // Inline capacities sized to avoid heap reallocations on medium-sized JSON + // arrays and objects (~100 elements) while keeping the stack-allocated + // JsonParser modest (~2.5 KiB of inline buffers; JsonParser is not + // instantiated recursively). + base::SmallVector<Handle<Object>, 128> element_stack_; + base::SmallVector<JsonProperty, 32> property_stack_; + base::SmallVector<double, 64> double_elements_; + base::SmallVector<int, 64> smi_elements_; // Cached pointer to the raw chars in source. In case source is on-heap, we // register an UpdatePointers callback. For this reason, chars_, cursor_ and diff --git a/deps/v8/src/json/json-stringifier.cc b/deps/v8/src/json/json-stringifier.cc index c7f692aed1f8..cb1a6166e6d4 100644 --- a/deps/v8/src/json/json-stringifier.cc +++ b/deps/v8/src/json/json-stringifier.cc @@ -8,6 +8,7 @@ #include "absl/functional/overload.h" #include "hwy/highway.h" +#include "src/base/memory.h" #include "src/base/strings.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" @@ -520,22 +521,34 @@ constexpr bool DoNotEscape(uint16_t c) { (c >= 0x23 && c != 0x5C && (c < 0xD800 || c > 0xDFFF)); } -// Checks if characters need escaping in a packed input (4 bytes in uint32_t). -constexpr bool NeedsEscape(uint32_t input) { - constexpr uint32_t mask_0x20 = 0x20202020u; - constexpr uint32_t mask_0x22 = 0x22222222u; - constexpr uint32_t mask_0x5c = 0x5C5C5C5Cu; - constexpr uint32_t mask_0x01 = 0x01010101u; - constexpr uint32_t mask_msb = 0x80808080u; +// Checks if characters need escaping in a packed input. +template <typename SrcChar, typename PackedT> +constexpr bool NeedsEscape(PackedT input) { + static_assert(sizeof(PackedT) == sizeof(SrcChar) * 4); + constexpr PackedT mask_0x01 = + std::numeric_limits<PackedT>::max() / std::numeric_limits<SrcChar>::max(); + constexpr PackedT mask_0x20 = mask_0x01 * 0x20; + constexpr PackedT mask_0x22 = mask_0x01 * 0x22; + constexpr PackedT mask_0x5c = mask_0x01 * 0x5c; + constexpr PackedT mask_msb = mask_0x01 + << (sizeof(SrcChar) * kBitsPerByte - 1); // Escape control characters (< 0x20). - const uint32_t has_lt_0x20 = input - mask_0x20; + const PackedT has_lt_0x20 = input - mask_0x20; // Escape double quotation mark (0x22). - const uint32_t has_0x22 = (input ^ mask_0x22) - mask_0x01; + const PackedT has_0x22 = (input ^ mask_0x22) - mask_0x01; // Escape backslash (0x5C). - const uint32_t has_0x5c = (input ^ mask_0x5c) - mask_0x01; - // Chars >= 0x7F don't need escaping. - const uint32_t result_mask = ~input & mask_msb; - const uint32_t result = ((has_lt_0x20 | has_0x22 | has_0x5c) & result_mask); + const PackedT has_0x5c = (input ^ mask_0x5c) - mask_0x01; + // Chars with MSB set don't match ASCII escape characters. + const PackedT result_mask = ~input & mask_msb; + PackedT result = (has_lt_0x20 | has_0x22 | has_0x5c) & result_mask; + if constexpr (sizeof(SrcChar) == sizeof(base::uc16)) { + // Escape UTF-16 surrogates (0xD800 <= c <= 0xDFFF). + constexpr PackedT mask_0xd800 = mask_0x01 * 0xd800; + constexpr PackedT mask_0xf800 = mask_0x01 * 0xf800; + const PackedT has_surrogate = + (((input & mask_0xf800) ^ mask_0xd800) - mask_0x01) & input & mask_msb; + result |= has_surrogate; + } return result != 0; } // LINT.ThenChange(/src/objects/string.cc:StringDoesNotContainEscapeCharacters) @@ -549,8 +562,9 @@ bool DoNotEscape(const SrcChar* chars, size_t length, static constexpr size_t stride = sizeof(PackedT); size_t i = 0; for (; i + (stride - 1) < length; i += stride) { - PackedT packed = *reinterpret_cast<const PackedT*>(chars + i); - if (V8_UNLIKELY(NeedsEscape(packed))) break; + PackedT packed = + base::ReadUnalignedValue<PackedT>(reinterpret_cast<Address>(chars + i)); + if (V8_UNLIKELY(NeedsEscape<SrcChar>(packed))) break; } for (; i < length; i++) { no_escape = no_escape && DoNotEscape(chars[i]); @@ -559,14 +573,19 @@ bool DoNotEscape(const SrcChar* chars, size_t length, } bool IsFastKey(Tagged<String> key, const DisallowGarbageCollection& no_gc) { + uint32_t length = key->length(); + constexpr int kExtraLength = 4; /* optional comma + 2x double quote + colon */ + if (V8_UNLIKELY(length + kExtraLength > String::kMaxLength)) { + return false; + }; return key->DispatchToSpecificType( absl::Overload{[&](Tagged<SeqOneByteString> str) { const uint8_t* chars = str->GetChars(no_gc); - return DoNotEscape(chars, str->length(), no_gc); + return DoNotEscape(chars, length, no_gc); }, [&](Tagged<ExternalOneByteString> str) { const uint8_t* chars = str->GetChars(); - return DoNotEscape(chars, str->length(), no_gc); + return DoNotEscape(chars, length, no_gc); }, [&](Tagged<String> str) { return false; }}); } @@ -1845,13 +1864,15 @@ class OutBuffer { CopyChars(cur_, chars, length); cur_ += length; } - void EnsureCapacity(size_t size) { + V8_WARN_UNUSED_RESULT bool EnsureCapacity(size_t size) { #ifdef DEBUG current_requested_capacity_ = size; #endif - if (V8_LIKELY(size <= SegmentFreeChars())) return; + if (V8_LIKELY(size <= SegmentFreeChars())) return true; + if (V8_UNLIKELY(size > String::kMaxLength)) return false; Extend(size); DCHECK_GE(CurSegmentCapacity(), size); + return true; } size_t length() const { if (ZoneUsed()) { @@ -1968,7 +1989,8 @@ enum FastJsonStringifierResult { enum class FastJsonStringifierObjectKeyResult : uint8_t { kSuccess, kChangeEncoding, // Two-byte key in one-byte stringifier. - kSlow // Two-byte key (in two-byte stringifier) or requires escaping. + kSlowKey, // Two-byte key (in two-byte stringifier) or requires escaping. + kSlowPath // Extending the buffer failed. }; class ContinuationRecord { @@ -2245,14 +2267,18 @@ class FastJsonStringifier { V8_NOINLINE FastJsonStringifierResult HandleInterruptAndCheckCycle(); V8_NOINLINE bool CheckCycle(); - V8_INLINE void EnsureCapacity(size_t size) { buffer_.EnsureCapacity(size); } + V8_INLINE V8_PRESERVE_MOST bool EnsureCapacity(size_t size) { + return buffer_.EnsureCapacity(size); + } template <typename SrcChar> V8_INLINE void AppendCharacterUnchecked(SrcChar c) { buffer_.AppendCharacter(c); } template <typename SrcChar> V8_INLINE void AppendCharacter(SrcChar c) { - EnsureCapacity(1); + bool ok = EnsureCapacity(1); + DCHECK(ok); // Extending by 1 character will never fail. + USE(ok); AppendCharacterUnchecked(c); } template <size_t N> @@ -2269,7 +2295,10 @@ class FastJsonStringifier { // Note that the literal contains the zero char. constexpr size_t length = N - 1; static_assert(length > 0); - EnsureCapacity(length); + static_assert(length <= String::kMaxLength); + bool ok = EnsureCapacity(length); + DCHECK(ok); // Will never fail (static_asserted above). + USE(ok); AppendCStringLiteralUnchecked(literal); } @@ -2282,19 +2311,22 @@ class FastJsonStringifier { V8_INLINE void AppendStringUnchecked(std::string_view str) { AppendCStringUnchecked(str.data(), str.length()); } - V8_INLINE void AppendCString(const char* chars, size_t len) { - EnsureCapacity(len); + V8_INLINE V8_WARN_UNUSED_RESULT FastJsonStringifierResult + AppendCString(const char* chars, size_t len) { + if (V8_UNLIKELY(!EnsureCapacity(len))) return SLOW_PATH; AppendCStringUnchecked(chars, len); + return SUCCESS; } - V8_INLINE void AppendCString(const char* chars) { - AppendCString(chars, strlen(chars)); + V8_INLINE V8_WARN_UNUSED_RESULT FastJsonStringifierResult + AppendCString(const char* chars) { + return AppendCString(chars, strlen(chars)); } - V8_INLINE void AppendString(std::string_view str) { - AppendCString(str.data(), str.length()); + V8_INLINE V8_WARN_UNUSED_RESULT FastJsonStringifierResult + AppendString(std::string_view str) { + return AppendCString(str.data(), str.length()); } template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) V8_INLINE bool AppendString(const SrcChar* chars, size_t length, const DisallowGarbageCollection& no_gc); @@ -2303,27 +2335,23 @@ class FastJsonStringifier { const DisallowGarbageCollection& no_gc); template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) + V8_INLINE size_t AppendEscapedChar(const SrcChar* chars, size_t length, + size_t i, size_t uncopied_src_index); + + template <typename SrcChar> bool AppendStringScalar(const SrcChar* chars, size_t length, size_t start, size_t uncopied_src_index, const DisallowGarbageCollection& no_gc); template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) V8_INLINE bool AppendStringSWAR(const SrcChar* chars, size_t length, size_t start, size_t uncopied_src_index, const DisallowGarbageCollection& no_gc); template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) V8_INLINE bool AppendStringSIMD(const SrcChar* chars, size_t length, const DisallowGarbageCollection& no_gc); - template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(base::uc16)) - V8_INLINE bool AppendString(const SrcChar* chars, size_t length, - const DisallowGarbageCollection& no_gc); - using FastIterableState = DescriptorArray::FastIterableState; static constexpr uint32_t kGlobalInterruptBudget = 200000; static constexpr uint32_t kArrayInterruptLength = 4000; @@ -2386,7 +2414,9 @@ void FastJsonStringifier<Char>::SerializeSmi(Tagged<Smi> object) { char chars[kBufferSize]; base::Vector<char> buffer(chars, kBufferSize); std::string_view str = IntToStringView(object.value(), buffer); - AppendString(str); + FastJsonStringifierResult result = AppendString(str); + DCHECK_EQ(result, SUCCESS); // Extending for a Smi value will never fail. + USE(result); } template <typename Char> @@ -2399,7 +2429,9 @@ void FastJsonStringifier<Char>::SerializeDouble(double number) { char chars[kBufferSize]; base::Vector<char> buffer(chars, kBufferSize); std::string_view str = DoubleToStringView(number, buffer); - AppendString(str); + FastJsonStringifierResult result = AppendString(str); + DCHECK_EQ(result, SUCCESS); // Will never fail (max 100 byte extend). + USE(result); } template <typename Char> @@ -2507,7 +2539,9 @@ FastJsonStringifier<Char>::SerializeObjectKey( max_length = MaxEscapedStringLength(length); } max_length += 4 /* optional comma + 2x double quote + colon */; - EnsureCapacity(max_length); + if (V8_UNLIKELY(!EnsureCapacity(max_length))) { + return FastJsonStringifierObjectKeyResult::kSlowPath; + } SeparatorUnchecked(comma); AppendCharacterUnchecked('"'); FastJsonStringifierObjectKeyResult result; @@ -2523,7 +2557,7 @@ FastJsonStringifier<Char>::SerializeObjectKey( String::DoesNotContainEscapeCharacters(obj)); result = sizeof(StringChar) == 1 && !needs_escaping ? FastJsonStringifierObjectKeyResult::kSuccess - : FastJsonStringifierObjectKeyResult::kSlow; + : FastJsonStringifierObjectKeyResult::kSlowKey; } AppendCharacterUnchecked('"'); AppendCharacterUnchecked(':'); @@ -2547,7 +2581,9 @@ FastJsonStringifierResult FastJsonStringifier<Char>::SerializeString( chars = string->GetChars(); } const uint32_t length = string->length(); - EnsureCapacity(MaxEscapedStringLength(length) + 2 /* 2x double quote */); + size_t max_length = + MaxEscapedStringLength(length) + 2 /* 2x double quote */; + if (V8_UNLIKELY(!EnsureCapacity(max_length))) return SLOW_PATH; AppendCharacterUnchecked('"'); AppendString(chars, length, no_gc); AppendCharacterUnchecked('"'); @@ -2881,6 +2917,10 @@ FastJsonStringifierResult FastJsonStringifier<Char>::ResumeJSObject( if (V8_UNLIKELY(key_result != FastJsonStringifierObjectKeyResult::kSuccess)) { descriptors->set_fast_iterable(FastIterableState::kJsonSlow); + if (V8_UNLIKELY(key_result == + FastJsonStringifierObjectKeyResult::kSlowPath)) { + return SLOW_PATH; + } if constexpr (is_one_byte) { if (key_result == FastJsonStringifierObjectKeyResult::kChangeEncoding) { @@ -2889,7 +2929,7 @@ FastJsonStringifierResult FastJsonStringifier<Char>::ResumeJSObject( obj, descriptor_idx + 1, nof_descriptors, in_object_properties, in_object_properties_start, descriptors)); - if (IsJSObject(property)) { + if (IsJSObjectExact(property)) { stack_.emplace_back(ContinuationRecord::ForJSObject(property)); } else if (IsJSArray(property)) { stack_.emplace_back(ContinuationRecord::ForJSArray(property)); @@ -3060,7 +3100,9 @@ FastJsonStringifierResult FastJsonStringifier<Char>::SerializeFixedArrayElement( Tagged<T> elements, uint32_t i, uint32_t length) { if constexpr (IsHoleyElementsKind(kind)) { if (elements->is_the_hole(isolate_, i)) { - EnsureCapacity(5 /* "null" + optional comma */); + if (V8_UNLIKELY(!EnsureCapacity(5 /* "null" + optional comma */))) { + return SLOW_PATH; + } SeparatorUnchecked(i > 0); AppendCStringLiteralUnchecked("null"); return SUCCESS; @@ -3099,6 +3141,22 @@ FastJsonStringifierResult FastJsonStringifier<Char>::SerializeFixedArrayElement( stack_.push_back( ContinuationRecord::ForJSArrayResume<kind, with_interrupt_checks>( elements, i + 1, length)); + if constexpr (!with_interrupt_checks) { + if (result == JS_OBJECT) { + DisallowGarbageCollection no_gc; + FastJsonStringifierResult obj_result = + SerializeJSObject(Cast<JSObject>(obj), no_gc); + if (V8_LIKELY(obj_result == SUCCESS)) { + DCHECK( + ContinuationRecord::IsArrayResumeType(stack_.back().type())); + DCHECK_EQ(stack_.back().array_elements(), elements); + DCHECK_EQ(stack_.back().array_index(), i + 1); + DCHECK_EQ(stack_.back().array_length(), length); + stack_.pop_back(); + } + return obj_result; + } + } stack_.push_back(ContinuationRecord::ForJSAny(obj, result)); return result; case SUCCESS: @@ -3132,6 +3190,10 @@ FastJsonStringifierResult FastJsonStringifier<Char>::ResumeFrom( cont.object_key(), cont.object_key_comma(), no_gc); USE(key_result); DCHECK_NE(key_result, FastJsonStringifierObjectKeyResult::kChangeEncoding); + if (V8_UNLIKELY(key_result == + FastJsonStringifierObjectKeyResult::kSlowPath)) { + return SLOW_PATH; + } // Resuming due to encoding change of an object key guarantees that there // are at least two other objects on the stack (the value for that key, and // the continuation record for the object the key is a member of). @@ -3342,11 +3404,10 @@ bool FastJsonStringifier<Char>::CheckCycle() { template <typename Char> template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) bool FastJsonStringifier<Char>::AppendString( const SrcChar* chars, size_t length, const DisallowGarbageCollection& no_gc) { - constexpr int kUseSimdLengthThreshold = 32; + constexpr int kUseSimdLengthThreshold = 32 / sizeof(SrcChar); if (length >= kUseSimdLengthThreshold) { return AppendStringSIMD(chars, length, no_gc); } @@ -3363,18 +3424,55 @@ void FastJsonStringifier<Char>::AppendStringNoEscapes( template <typename Char> template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) +size_t FastJsonStringifier<Char>::AppendEscapedChar(const SrcChar* chars, + size_t length, size_t i, + size_t uncopied_src_index) { + SrcChar c = chars[i]; + buffer_.Append(chars + uncopied_src_index, i - uncopied_src_index); + if constexpr (sizeof(SrcChar) == sizeof(base::uc16)) { + if (base::IsInRange(c, static_cast<SrcChar>(0xD800), + static_cast<SrcChar>(0xDFFF))) { + char double_to_radix_chars[kDoubleToRadixMaxChars]; + base::Vector<char> double_to_radix_buffer = + base::ArrayVector(double_to_radix_chars); + if (c <= 0xDBFF && i + 1 < length) { + SrcChar next = chars[i + 1]; + if (base::IsInRange(next, static_cast<SrcChar>(0xDC00), + static_cast<SrcChar>(0xDFFF))) { + // The current and next characters form a surrogate pair. + AppendCharacterUnchecked(c); + AppendCharacterUnchecked(next); + return 2; + } + } + // Lone surrogate. + AppendCStringLiteralUnchecked("\\u"); + std::string_view hex = + DoubleToRadixStringView(c, 16, double_to_radix_buffer); + AppendStringUnchecked(hex); + return 1; + } + } + SBXCHECK_LT(c, 0x60); + AppendCStringUnchecked(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); + return 1; +} + +template <typename Char> +template <typename SrcChar> bool FastJsonStringifier<Char>::AppendStringScalar( const SrcChar* chars, size_t length, size_t start, size_t uncopied_src_index, const DisallowGarbageCollection& no_gc) { bool needs_escaping = false; - for (size_t i = start; i < length; i++) { - SrcChar c = chars[i]; - if (V8_LIKELY(DoNotEscape(c))) continue; + for (size_t i = start; i < length;) { + if (V8_LIKELY(DoNotEscape(chars[i]))) { + i++; + continue; + } needs_escaping = true; - buffer_.Append(chars + uncopied_src_index, i - uncopied_src_index); - AppendCStringUnchecked(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); - uncopied_src_index = i + 1; + size_t advance = AppendEscapedChar(chars, length, i, uncopied_src_index); + i += advance; + uncopied_src_index = i; } if (V8_LIKELY(uncopied_src_index < length)) { buffer_.Append(chars + uncopied_src_index, length - uncopied_src_index); @@ -3384,24 +3482,44 @@ bool FastJsonStringifier<Char>::AppendStringScalar( template <typename Char> template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) -V8_CLANG_NO_SANITIZE("alignment") bool FastJsonStringifier<Char>::AppendStringSWAR( const SrcChar* chars, size_t length, size_t start, size_t uncopied_src_index, const DisallowGarbageCollection& no_gc) { - using PackedT = uint32_t; - static constexpr size_t stride = sizeof(PackedT); + using PackedT = std::conditional_t<sizeof(SrcChar) == sizeof(uint8_t), + uint32_t, uint64_t>; + static constexpr size_t stride = sizeof(PackedT) / sizeof(SrcChar); size_t i = start; for (; i + (stride - 1) < length; i += stride) { - PackedT packed = *reinterpret_cast<const PackedT*>(chars + i); - if (V8_UNLIKELY(NeedsEscape(packed))) break; + PackedT packed = + base::ReadUnalignedValue<PackedT>(reinterpret_cast<Address>(chars + i)); + if (V8_UNLIKELY(NeedsEscape<SrcChar>(packed))) { + return AppendStringScalar(chars, length, i, uncopied_src_index, no_gc); + } + } + if (i < length) { + if (length - uncopied_src_index >= stride) { + PackedT tail = base::ReadUnalignedValue<PackedT>( + reinterpret_cast<Address>(chars + length - stride)); + if (V8_UNLIKELY(NeedsEscape<SrcChar>(tail))) { + return AppendStringScalar(chars, length, i, uncopied_src_index, no_gc); + } + } else { + for (; i < length; i++) { + if (V8_UNLIKELY(!DoNotEscape(chars[i]))) { + return AppendStringScalar(chars, length, i, uncopied_src_index, + no_gc); + } + } + } } - return AppendStringScalar(chars, length, i, uncopied_src_index, no_gc); + if (V8_LIKELY(uncopied_src_index < length)) { + buffer_.Append(chars + uncopied_src_index, length - uncopied_src_index); + } + return false; } template <typename Char> template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(uint8_t)) bool FastJsonStringifier<Char>::AppendStringSIMD( const SrcChar* chars, size_t length, const DisallowGarbageCollection& no_gc) { @@ -3411,37 +3529,43 @@ bool FastJsonStringifier<Char>::AppendStringSIMD( size_t uncopied_src_index = 0; // Index of first char not copied yet. const SrcChar* block = chars; const SrcChar* end = chars + length; - hw::FixedTag<SrcChar, 16> tag; + hw::CappedTag<SrcChar, 16 / sizeof(SrcChar)> tag; static const size_t stride = hw::Lanes(tag); const auto mask_0x20 = hw::Set(tag, 0x20); const auto mask_0x22 = hw::Set(tag, 0x22); const auto mask_0x5c = hw::Set(tag, 0x5c); + [[maybe_unused]] const auto mask_0xf800 = + hw::Set(tag, static_cast<SrcChar>(0xf800)); + [[maybe_unused]] const auto mask_0xd800 = + hw::Set(tag, static_cast<SrcChar>(0xd800)); for (; block + (stride - 1) < end; block += stride) { const auto input = hw::LoadU(tag, block); // TODO(floitsch): use operators for the comparisons when they are available // on RISC-V. - const auto has_lower_than_0x20 = hw::Lt(input, mask_0x20); + const auto has_lt_0x20 = hw::Lt(input, mask_0x20); const auto has_0x22 = hw::Eq(input, mask_0x22); const auto has_0x5c = hw::Eq(input, mask_0x5c); - const auto result = hw::Or(hw::Or(has_lower_than_0x20, has_0x22), has_0x5c); + auto result = hw::Or(hw::Or(has_lt_0x20, has_0x22), has_0x5c); + if constexpr (sizeof(SrcChar) == sizeof(base::uc16)) { + // Checks input >= 0xd800 && input <= 0xdfff. + const auto has_surrogate = + hw::Eq(hw::And(input, mask_0xf800), mask_0xd800); + result = hw::Or(result, has_surrogate); + } // No character that needs escaping found in block. if (V8_LIKELY(hw::AllFalse(tag, result))) continue; needs_escaping = true; size_t index = hw::FindKnownFirstTrue(tag, result); - Char found_char = block[index]; const size_t char_index = block - chars + index; - const size_t copy_length = char_index - uncopied_src_index; - buffer_.Append(chars + uncopied_src_index, copy_length); - SBXCHECK_LT(found_char, 0x60); - AppendCStringUnchecked( - &JsonEscapeTable[found_char * kJsonEscapeTableEntrySize]); - uncopied_src_index = char_index + 1; + const size_t advance = + AppendEscapedChar(chars, length, char_index, uncopied_src_index); + uncopied_src_index = char_index + advance; // Advance to character after the one that was found to need escaping. - block += index + 1; + block += index + advance; // Subtract stride as it will be added again at the beginning of the loop. block -= stride; } @@ -3453,78 +3577,6 @@ bool FastJsonStringifier<Char>::AppendStringSIMD( needs_escaping; } -template <typename Char> -template <typename SrcChar> - requires(sizeof(SrcChar) == sizeof(base::uc16)) -bool FastJsonStringifier<Char>::AppendString( - const SrcChar* chars, size_t length, - const DisallowGarbageCollection& no_gc) { - bool needs_escaping = false; - uint32_t uncopied_src_index = 0; // Index of first char not copied yet. - // TODO(pthier): Add SIMD version. - for (uint32_t i = 0; i < length; i++) { - SrcChar c = chars[i]; - if (V8_LIKELY(DoNotEscape(c))) continue; - needs_escaping = true; - if (sizeof(SrcChar) != 1 && base::IsInRange(c, static_cast<SrcChar>(0xD800), - static_cast<SrcChar>(0xDFFF))) { - // The current character is a surrogate. - buffer_.Append(chars + uncopied_src_index, i - uncopied_src_index); - char double_to_radix_chars[kDoubleToRadixMaxChars]; - base::Vector<char> double_to_radix_buffer = - base::ArrayVector(double_to_radix_chars); - if (c <= 0xDBFF) { - // The current character is a leading surrogate. - if (i + 1 < length) { - // There is a next character. - SrcChar next = chars[i + 1]; - if (base::IsInRange(next, static_cast<SrcChar>(0xDC00), - static_cast<SrcChar>(0xDFFF))) { - // The next character is a trailing surrogate, meaning this is a - // surrogate pair. - AppendCharacterUnchecked(c); - AppendCharacterUnchecked(next); - i++; - } else { - // The next character is not a trailing surrogate. Thus, the - // current character is a lone leading surrogate. - AppendCStringLiteralUnchecked("\\u"); - std::string_view hex = - DoubleToRadixStringView(c, 16, double_to_radix_buffer); - AppendStringUnchecked(hex); - } - } else { - // There is no next character. Thus, the current character is a lone - // leading surrogate. - AppendCStringLiteralUnchecked("\\u"); - std::string_view hex = - DoubleToRadixStringView(c, 16, double_to_radix_buffer); - AppendStringUnchecked(hex); - } - } else { - // The current character is a lone trailing surrogate. (If it had been - // preceded by a leading surrogate, we would've ended up in the other - // branch earlier on, and the current character would've been handled - // as part of the surrogate pair already.) - AppendCStringLiteralUnchecked("\\u"); - std::string_view hex = - DoubleToRadixStringView(c, 16, double_to_radix_buffer); - AppendStringUnchecked(hex); - } - uncopied_src_index = i + 1; - } else { - buffer_.Append(chars + uncopied_src_index, i - uncopied_src_index); - DCHECK_LT(c, 0x60); - AppendCStringUnchecked(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); - uncopied_src_index = i + 1; - } - } - if (uncopied_src_index < length) { - buffer_.Append(chars + uncopied_src_index, length - uncopied_src_index); - } - return needs_escaping; -} - namespace { bool CanUseFastStringifier(DirectHandle<JSAny> replacer, @@ -3560,9 +3612,9 @@ MaybeDirectHandle<Object> FastJsonStringify(Isolate* isolate, if (length > String::kMaxLength) { THROW_NEW_ERROR(isolate, NewInvalidStringLengthError()); } - ASSIGN_RETURN_ON_EXCEPTION( - isolate, ret, - isolate->factory()->NewRawOneByteString(static_cast<int>(length))); + ASSIGN_RETURN_ON_EXCEPTION(isolate, ret, + isolate->factory()->NewRawOneByteString( + static_cast<uint32_t>(length))); } one_byte_stringifier.CopyResultTo(ret->GetChars(no_gc)); return ret; @@ -3579,7 +3631,7 @@ MaybeDirectHandle<Object> FastJsonStringify(Isolate* isolate, } ASSIGN_RETURN_ON_EXCEPTION(isolate, ret, isolate->factory()->NewRawTwoByteString( - static_cast<int>(total_length))); + static_cast<uint32_t>(total_length))); } base::uc16* chars = ret->GetChars(no_gc); if (one_byte_length > 0) { diff --git a/deps/v8/src/libsampler/DEPS b/deps/v8/src/libsampler/DEPS index bdf1a82670b6..dd035e666532 100644 --- a/deps/v8/src/libsampler/DEPS +++ b/deps/v8/src/libsampler/DEPS @@ -3,4 +3,10 @@ include_rules = [ "-src", "+src/base", "+src/libsampler", -] \ No newline at end of file +] + +specific_include_rules = { + "sampler.cc": [ + "+absl/base/internal/sysinfo.h", + ], +} diff --git a/deps/v8/src/libsampler/sampler.cc b/deps/v8/src/libsampler/sampler.cc index 16cd153d58d4..53a128484ae6 100644 --- a/deps/v8/src/libsampler/sampler.cc +++ b/deps/v8/src/libsampler/sampler.cc @@ -23,11 +23,7 @@ #include <sys/syscall.h> #endif -#if V8_OS_AIX || V8_TARGET_ARCH_S390X - -#include "src/base/platform/time.h" - -#elif V8_OS_DARWIN +#if V8_OS_DARWIN #include <mach/mach.h> // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h> // and is a typedef for struct sigcontext. There is no uc_mcontext. @@ -68,6 +64,7 @@ using zx_thread_state_general_regs_t = zx_arm64_general_regs_t; #include <algorithm> #include <vector> +#include "absl/base/internal/sysinfo.h" #include "src/base/atomic-utils.h" #include "src/base/platform/mutex.h" #include "src/base/platform/platform.h" @@ -361,12 +358,15 @@ class SignalHandler { static void Restore() { if (signal_handler_installed_) { signal_handler_installed_ = false; -#if V8_OS_AIX || V8_TARGET_ARCH_S390X - // On Aix, IBMi & zLinux SIGPROF can sometimes arrive after the - // default signal handler is restored, resulting in intermittent test - // failure when profiling is enabled (https://crbug.com/v8/12952) - base::OS::Sleep(base::TimeDelta::FromMicroseconds(10)); -#endif + // Setting SIG_IGN discards any pending SIGPROF signals on all threads in + // the process (POSIX.1) before restoring the previous disposition, which + // may be SIG_DFL and would otherwise terminate the process if a signal + // sent by DoSample() is still pending. + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGPROF, &sa, nullptr); sigaction(SIGPROF, &old_signal_handler_, nullptr); } } @@ -579,6 +579,13 @@ Sampler::Sampler(Isolate* isolate) // Abseil's deadlock detection uses locks. If we end up taking a sample absl // internally holds this lock, we can end up deadlocking. SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore); + // Abseil's Mutex contention path lazily calibrates the nominal CPU frequency + // on first contention using a 1ms nanosleep loop. If SIGPROF signals arrive + // at high frequency during that calibration, Linux's timer slack on relative + // nanosleep restarts can cause the remaining sleep time to grow on every + // EINTR, livelocking the thread. Trigger the one-time initialization before + // sampling starts. + absl::base_internal::NominalCPUFrequency(); } Sampler::~Sampler() { DCHECK(!IsActive()); } diff --git a/deps/v8/src/logging/counters-definitions.h b/deps/v8/src/logging/counters-definitions.h index f5f58a98139a..62697832961b 100644 --- a/deps/v8/src/logging/counters-definitions.h +++ b/deps/v8/src/logging/counters-definitions.h @@ -140,6 +140,18 @@ namespace internal { HT(compile_serialize, V8.CompileSerializeMicroSeconds, 100000, MICROSECOND) \ HT(compile_deserialize, V8.CompileDeserializeMicroSeconds, 1000000, \ MICROSECOND) \ + HT(compile_deserialize_module, V8.CompileDeserializeMicroSeconds.Module, \ + 1000000, MICROSECOND) \ + HT(compile_deserialize_classic, V8.CompileDeserializeMicroSeconds.Classic, \ + 1000000, MICROSECOND) \ + HT(compile_deserialize_main_thread, \ + V8.CompileDeserializeMicroSeconds.MainThread, 1000000, MICROSECOND) \ + HT(compile_deserialize_main_thread_module, \ + V8.CompileDeserializeMicroSeconds.MainThread.Module, 1000000, \ + MICROSECOND) \ + HT(compile_deserialize_main_thread_classic, \ + V8.CompileDeserializeMicroSeconds.MainThread.Classic, 1000000, \ + MICROSECOND) \ /* Snapshot. */ \ HT(snapshot_decompress, V8.SnapshotDecompressMicroSeconds, 1000000, \ MICROSECOND) \ @@ -151,7 +163,17 @@ namespace internal { 1000000, MICROSECOND) \ /* ... and also see compile_deserialize above. */ \ /* Total compilation time incl. caching/parsing. */ \ - HT(compile_script, V8.CompileScriptMicroSeconds, 1000000, MICROSECOND) + HT(compile_script, V8.CompileScriptMicroSeconds, 1000000, MICROSECOND) \ + HT(compile_script_module, V8.CompileScriptMicroSeconds.Module, 1000000, \ + MICROSECOND) \ + HT(compile_script_classic, V8.CompileScriptMicroSeconds.Classic, 1000000, \ + MICROSECOND) \ + HT(compile_script_main_thread, V8.CompileScriptMicroSeconds.MainThread, \ + 1000000, MICROSECOND) \ + HT(compile_script_main_thread_module, \ + V8.CompileScriptMicroSeconds.MainThread.Module, 1000000, MICROSECOND) \ + HT(compile_script_main_thread_classic, \ + V8.CompileScriptMicroSeconds.MainThread.Classic, 1000000, MICROSECOND) #define NESTED_TIMED_HISTOGRAM_LIST_SLOW(HT) \ /* Total V8 time (including JS and runtime calls, exluding callbacks). */ \ @@ -269,8 +291,6 @@ namespace internal { V8.WasmCompileModuleStreamingMicroSeconds, 100000000, MICROSECOND) \ HT(wasm_streaming_finish_wasm_module_time, \ V8.WasmFinishModuleStreamingMicroSeconds, 100000000, MICROSECOND) \ - HT(wasm_deserialization_time, V8.WasmDeserializationTimeMilliSeconds, 10000, \ - MILLISECOND) \ HT(wasm_compile_asm_function_time, V8.WasmCompileFunctionMicroSeconds.asm, \ 1000000, MICROSECOND) \ HT(wasm_compile_wasm_function_time, V8.WasmCompileFunctionMicroSeconds.wasm, \ @@ -283,8 +303,6 @@ namespace internal { V8.WasmInstantiateModuleMicroSeconds.asm, 10000000, MICROSECOND) \ HT(wasm_lazy_compile_time, V8.WasmLazyCompileTimeMicroSeconds, 100000000, \ MICROSECOND) \ - HT(wasm_compile_after_deserialize, \ - V8.WasmCompileAfterDeserializeMilliSeconds, 1000000, MILLISECOND) \ /* Total compilation time incl. caching/parsing for various cache states. */ \ HT(compile_script_with_produce_cache, \ V8.CompileScriptMicroSeconds.ProduceCache, 1000000, MICROSECOND) \ @@ -307,11 +325,23 @@ namespace internal { V8.CompileScriptMicroSeconds.StreamingFinalization, 1000000, MICROSECOND) \ HT(compile_script_on_background, \ V8.CompileScriptMicroSeconds.BackgroundThread, 1000000, MICROSECOND) \ + HT(compile_script_on_background_module, \ + V8.CompileScriptMicroSeconds.BackgroundThread.Module, 1000000, \ + MICROSECOND) \ + HT(compile_script_on_background_classic, \ + V8.CompileScriptMicroSeconds.BackgroundThread.Classic, 1000000, \ + MICROSECOND) \ HT(compile_function_on_background, \ V8.CompileFunctionMicroSeconds.BackgroundThread, 1000000, MICROSECOND) \ HT(deserialize_script_on_background, \ V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread, 1000000, \ - MICROSECOND) + MICROSECOND) \ + HT(deserialize_script_on_background_module, \ + V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread.Module, \ + 1000000, MICROSECOND) \ + HT(deserialize_script_on_background_classic, \ + V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread.Classic, \ + 1000000, MICROSECOND) #define AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT) \ AHT(compile_lazy, V8.CompileLazyMicroSeconds) diff --git a/deps/v8/src/logging/counters-scopes.h b/deps/v8/src/logging/counters-scopes.h index db0bc6ebe1bb..1b774939d3c5 100644 --- a/deps/v8/src/logging/counters-scopes.h +++ b/deps/v8/src/logging/counters-scopes.h @@ -39,7 +39,7 @@ class BaseTimedHistogramScope { // a time of -1 microsecond. This behavior should match kTimeNotMeasured in // v8-script.h. V8_INLINE base::TimeDelta Stop() { - if (histogram_->Enabled()) return StopInternal(); + if (histogram_ && histogram_->Enabled()) return StopInternal(); return base::TimeDelta::FromMicroseconds(-1); } @@ -116,7 +116,7 @@ class V8_NODISCARD OptionalTimedHistogramScope // stop time rather than start time. class V8_NODISCARD LazyTimedHistogramScope : public BaseTimedHistogramScope { public: - explicit LazyTimedHistogramScope(int64_t* result_in_microseconds) + explicit LazyTimedHistogramScope(int64_t* result_in_microseconds = nullptr) : BaseTimedHistogramScope(nullptr), result_in_microseconds_(result_in_microseconds) { timer_.Start(); diff --git a/deps/v8/src/logging/log.cc b/deps/v8/src/logging/log.cc index c3dbfeb6833f..b97a34f6c2f4 100644 --- a/deps/v8/src/logging/log.cc +++ b/deps/v8/src/logging/log.cc @@ -17,6 +17,7 @@ #include "src/base/platform/mutex.h" #include "src/base/platform/platform.h" #include "src/base/platform/wrappers.h" +#include "src/base/unique-array.h" #include "src/codegen/bailout-reason.h" #include "src/codegen/compiler.h" #include "src/codegen/source-position-table.h" @@ -410,10 +411,10 @@ PerfBasicLogger::PerfBasicLogger(Isolate* isolate) : CodeEventLogger(isolate) { CHECK_NOT_NULL(v8_flags.perf_basic_prof_path); const char* base_dir = v8_flags.perf_basic_prof_path; // Open the perf JIT dump file. - auto perf_dump_name = base::OwnedVector<char>::NewForOverwrite( + auto perf_dump_name = base::UniqueArray<char>::NewForOverwrite( strlen(base_dir) + kFilenameBufferPadding); - int size = SNPrintF(perf_dump_name.as_vector(), "%s/perf-%d.map", base_dir, - process_id_); + int size = base::SNPrintF(perf_dump_name.as_span(), "%s/perf-%d.map", + base_dir, process_id_); CHECK_NE(size, -1); perf_output_handle_ = base::OS::FOpen(perf_dump_name.begin(), base::OS::LogFileOpenMode); @@ -725,7 +726,7 @@ LowLevelLogger::LowLevelLogger(Isolate* isolate, const char* name) // Open the low-level log file. size_t len = strlen(name); auto ll_name = - base::OwnedVector<char>::NewForOverwrite(len + sizeof(kLogExt)); + base::UniqueArray<char>::NewForOverwrite(len + sizeof(kLogExt)); MemCopy(ll_name.begin(), name, len); MemCopy(ll_name.begin() + len, kLogExt, sizeof(kLogExt)); ll_output_handle_ = @@ -2726,15 +2727,20 @@ void ExistingCodeLogger::LogCompiledFunctions( } #if V8_ENABLE_WEBASSEMBLY - HeapObjectIterator iterator(heap); - DisallowGarbageCollection no_gc; + DirectHandleVector<WasmModuleObject> module_objects(isolate_); + { + HeapObjectIterator iterator(heap); + DisallowGarbageCollection no_gc; - for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null(); - obj = iterator.Next()) { - if (!IsWasmModuleObject(obj)) continue; - auto module_object = Cast<WasmModuleObject>(obj); - module_object->native_module()->LogWasmCodes(isolate_, - module_object->script()); + for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null(); + obj = iterator.Next()) { + if (!IsWasmModuleObject(obj)) continue; + module_objects.emplace_back(Cast<WasmModuleObject>(obj), isolate_); + } + } + for (DirectHandle<WasmModuleObject> module_object : module_objects) { + module_object->native_module()->LogWasmCodes( + isolate_, direct_handle(module_object->script(), isolate_)); } wasm::GetWasmImportWrapperCache()->LogForIsolate(isolate_); wasm::GetWasmStackEntryWrapperCache()->LogForIsolate(isolate_); diff --git a/deps/v8/src/logging/runtime-call-stats.h b/deps/v8/src/logging/runtime-call-stats.h index 1ab0baba1b4b..f0f0c7b64529 100644 --- a/deps/v8/src/logging/runtime-call-stats.h +++ b/deps/v8/src/logging/runtime-call-stats.h @@ -143,6 +143,7 @@ namespace v8::internal { V(Object_ToPrimitive) \ V(Object_ToString) \ V(Object_ToUint32) \ + V(Object_TryGetWithNoSideEffects) \ V(Persistent_New) \ V(Private_New) \ V(Promise_Catch) \ @@ -264,7 +265,6 @@ namespace v8::internal { ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, LoopPeeling) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PairingOptimization) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MeetRegisterConstraints) \ - ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, MemoryOptimization) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, OptimizeMoves) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PopulateReferenceMaps) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PrintGraph) \ @@ -333,10 +333,7 @@ namespace v8::internal { ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Typer) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, Untyper) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, VerifyGraph) \ - ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmBaseOptimization) \ - ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmGCLowering) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmGCOptimization) \ - ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmInlining) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmOptimization) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, WasmTyping) \ \ @@ -381,8 +378,6 @@ namespace v8::internal { V(DeserializeIsolate) \ V(FinalizationRegistryCleanupFromTask) \ V(FunctionCallback) \ - V(FunctionArgumentsGetter) \ - V(FunctionCallerGetter) \ V(FunctionLengthGetter) \ V(FunctionPrototypeGetter) \ V(FunctionPrototypeSetter) \ diff --git a/deps/v8/src/maglev/arm64/maglev-assembler-arm64-inl.h b/deps/v8/src/maglev/arm64/maglev-assembler-arm64-inl.h index 1119721c60ac..6d0ba08c5d3c 100644 --- a/deps/v8/src/maglev/arm64/maglev-assembler-arm64-inl.h +++ b/deps/v8/src/maglev/arm64/maglev-assembler-arm64-inl.h @@ -103,10 +103,18 @@ inline MapCompare::MapCompare(MaglevAssembler* masm, Register object, void MapCompare::Generate(Handle<Map> map, Condition cond, Label* if_true, Label::Distance distance) { - MaglevAssembler::TemporaryRegisterScope temps(masm_); - Register temp = temps.AcquireScratch(); - masm_->Move(temp, map); - masm_->CmpTagged(map_, temp); + // A root map is compared through its root index, which under static roots + // makes a read-only map's compressed pointer an immediate, as + // CompareMapWithRoot does. Any other map is loaded from the constant pool. + RootIndex root_index; + if (masm_->isolate()->roots_table().IsRootHandle(map, &root_index)) { + masm_->CompareTaggedRoot(map_, root_index); + } else { + MaglevAssembler::TemporaryRegisterScope temps(masm_); + Register temp = temps.AcquireScratch(); + masm_->Move(temp, map); + masm_->CmpTagged(map_, temp); + } masm_->JumpIf(cond, if_true, distance); } @@ -162,6 +170,7 @@ inline Register ToRegister(MaglevAssembler* masm, MaglevAssembler::TemporaryRegisterScope* scratch, Input input) { if (input.operand().IsConstant()) { + if (input.node()->MaterializesToZero()) return xzr; Register reg = scratch->AcquireScratch(); input.node()->LoadToRegister(masm, reg); return reg; @@ -834,7 +843,7 @@ inline void MaglevAssembler::Move(Register dst, uint32_t i) { inline void MaglevAssembler::Move(Register dst, intptr_t p) { Mov(dst, Immediate(p)); } -inline void MaglevAssembler::Move(Register dst, IndirectPointerTag i) { +inline void MaglevAssembler::Move(Register dst, TrustedPointerTag i) { Mov(dst, Immediate(i)); } inline void MaglevAssembler::Move(DoubleRegister dst, double n) { @@ -1533,9 +1542,18 @@ inline void MaglevAssembler::CompareTaggedAndJumpIf(Register r1, Condition cond, Label* target, Label::Distance distance) { - CmpTagged(r1, Operand(obj, COMPRESS_POINTERS_BOOL - ? RelocInfo::COMPRESSED_EMBEDDED_OBJECT - : RelocInfo::FULL_EMBEDDED_OBJECT)); + // A root is compared through its root index: under static roots a read-only + // root's compressed pointer is an immediate, or a mov away when it does not + // encode, in place of a constant-pool load and a relocation for a value that + // never changes. Any other object is loaded from the constant pool. + RootIndex root_index; + if (isolate()->roots_table().IsRootHandle(obj, &root_index)) { + CompareTaggedRoot(r1, root_index); + } else { + CmpTagged(r1, Operand(obj, COMPRESS_POINTERS_BOOL + ? RelocInfo::COMPRESSED_EMBEDDED_OBJECT + : RelocInfo::FULL_EMBEDDED_OBJECT)); + } JumpIf(cond, target, distance); } @@ -1565,7 +1583,9 @@ inline void MaglevAssembler::CompareDoubleAndJumpIfZeroOrNaN( inline void MaglevAssembler::TestInt32AndJumpIfAnySet( Register r1, int32_t mask, Label* target, Label::Distance distance) { - TestAndBranchIfAnySet(r1.W(), mask, target); + // Zero-extend so a sign-bit mask (e.g. 0x80000000) tests the 32-bit register + // rather than a sign-extended 64-bit pattern. + TestAndBranchIfAnySet(r1.W(), static_cast<uint32_t>(mask), target); } inline void MaglevAssembler::TestInt32AndJumpIfAnySet( @@ -1586,7 +1606,9 @@ inline void MaglevAssembler::TestUint8AndJumpIfAnySet( inline void MaglevAssembler::TestInt32AndJumpIfAllClear( Register r1, int32_t mask, Label* target, Label::Distance distance) { - TestAndBranchIfAllClear(r1.W(), mask, target); + // Zero-extend so a sign-bit mask (e.g. 0x80000000) tests the 32-bit register + // rather than a sign-extended 64-bit pattern. + TestAndBranchIfAllClear(r1.W(), static_cast<uint32_t>(mask), target); } inline void MaglevAssembler::TestInt32AndJumpIfAllClear( diff --git a/deps/v8/src/maglev/loong64/maglev-assembler-loong64-inl.h b/deps/v8/src/maglev/loong64/maglev-assembler-loong64-inl.h index 5eb4bb54005d..0f915de03d67 100644 --- a/deps/v8/src/maglev/loong64/maglev-assembler-loong64-inl.h +++ b/deps/v8/src/maglev/loong64/maglev-assembler-loong64-inl.h @@ -159,6 +159,7 @@ inline Register ToRegister(MaglevAssembler* masm, MaglevAssembler::TemporaryRegisterScope* scratch, Input input) { if (input.operand().IsConstant()) { + if (input.node()->MaterializesToZero()) return zero_reg; Register reg = scratch->AcquireScratch(); input.node()->LoadToRegister(masm, reg); return reg; @@ -710,6 +711,22 @@ inline void MaglevAssembler::StoreTaggedFieldNoWriteBarrier(Register object, MacroAssembler::StoreTaggedField(value, FieldMemOperand(object, offset)); } +inline void MaglevAssembler::StoreTaggedFieldNoWriteBarrier( + Register object, int offset, ValueNode* constant) { + DCHECK(CanStoreTaggedConstant(constant)); + DCHECK_EQ(constant->Cast<SmiConstant>()->value(), Smi::zero()); + MacroAssembler::StoreTaggedField(zero_reg, FieldMemOperand(object, offset)); +} + +inline void MaglevAssembler::StoreTaggedFieldNoWriteBarrier( + Register object, int offset, Handle<HeapObject> constant) { + DCHECK(kSupportsStoreTaggedConstant); + TemporaryRegisterScope temps(this); + Register scratch = temps.AcquireScratch(); + MoveTagged(scratch, constant); + MacroAssembler::StoreTaggedField(scratch, FieldMemOperand(object, offset)); +} + inline void MaglevAssembler::StoreFixedArrayElementNoWriteBarrier( Register array, Register index, Register value) { MaglevAssembler::TemporaryRegisterScope temps(this); @@ -897,7 +914,7 @@ inline void MaglevAssembler::Move(Register dst, uint32_t i) { inline void MaglevAssembler::Move(Register dst, intptr_t p) { li(dst, Operand(p)); } -inline void MaglevAssembler::Move(Register dst, IndirectPointerTag i) { +inline void MaglevAssembler::Move(Register dst, TrustedPointerTag i) { li(dst, Operand(i)); } inline void MaglevAssembler::Move(DoubleRegister dst, double n) { @@ -911,6 +928,13 @@ inline void MaglevAssembler::Move(Register dst, Handle<HeapObject> obj) { } void MaglevAssembler::MoveTagged(Register dst, Handle<HeapObject> obj) { #ifdef V8_COMPRESS_POINTERS + RootIndex root_index; + if (isolate()->roots_table().IsRootHandle(obj, &root_index) && + CanBeImmediate(root_index)) { + li(dst, Operand(static_cast<int32_t>(ReadOnlyRootPtr(root_index)), + RelocInfo::NO_INFO)); + return; + } li(dst, Operand(obj, RelocInfo::COMPRESSED_EMBEDDED_OBJECT)); #else li(dst, obj); diff --git a/deps/v8/src/maglev/loong64/maglev-assembler-loong64.cc b/deps/v8/src/maglev/loong64/maglev-assembler-loong64.cc index 107f7453772b..da751a2da03a 100644 --- a/deps/v8/src/maglev/loong64/maglev-assembler-loong64.cc +++ b/deps/v8/src/maglev/loong64/maglev-assembler-loong64.cc @@ -462,6 +462,10 @@ void MaglevAssembler::StringCharCodeOrCodePointAt( offsetof(SlicedString, offset_)); LoadTaggedField(string, string, offsetof(SlicedString, parent_)); Add_w(index, index, Operand(offset)); + // Add_w yields a sign-extended Word32. Normalize it to its unsigned form + // so that a (corrupted) negative offset cannot be interpreted as a + // negative index by the subsequent address computation. + Bstrpick_d(index, index, 31, 0); MacroAssembler::Branch(&loop, Label::kNear); } @@ -506,7 +510,8 @@ void MaglevAssembler::StringCharCodeOrCodePointAt( bind(&two_byte_string); // {instance_type} is unused from this point, so we can use as scratch. Register scratch = scratch1; - slli_d(scratch, index, 1); + Bstrpick_d(scratch, index, 31, 0); + slli_d(scratch, scratch, 1); Add_d(scratch, scratch, Operand(OFFSET_OF_DATA_START(SeqTwoByteString) - kHeapObjectTag)); @@ -534,6 +539,7 @@ void MaglevAssembler::StringCharCodeOrCodePointAt( Label::kNear); Register second_code_point = scratch; + Bstrpick_d(index, index, 31, 0); slli_d(index, index, 1); Add_d(index, index, Operand(OFFSET_OF_DATA_START(SeqTwoByteString) - kHeapObjectTag)); @@ -596,8 +602,8 @@ void MaglevAssembler::SeqOneByteStringCharCodeAt(Register result, AbortReason::kUnexpectedValue); } - // TODO(loong64): is index an uint32 value? - Add_d(scratch, index, + Bstrpick_d(scratch, index, 31, 0); + Add_d(scratch, scratch, Operand(OFFSET_OF_DATA_START(SeqOneByteString) - kHeapObjectTag)); Ld_bu(result, MemOperand(string, scratch)); } diff --git a/deps/v8/src/maglev/maglev-assembler-inl.h b/deps/v8/src/maglev/maglev-assembler-inl.h index fa05f633704f..9e073a31c278 100644 --- a/deps/v8/src/maglev/maglev-assembler-inl.h +++ b/deps/v8/src/maglev/maglev-assembler-inl.h @@ -320,20 +320,20 @@ inline bool MaglevAssembler::CanStoreTaggedConstant(ValueNode* value) { if (!kSupportsStoreTaggedConstant) return false; switch (value->opcode()) { case Opcode::kSmiConstant: -#if V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_LOONG64 return value->Cast<SmiConstant>()->value() == Smi::zero(); #else case Opcode::kHeapConstant: return true; case Opcode::kRootConstant: return CanBeImmediate(value->Cast<RootConstant>()->index()); -#endif // V8_TARGET_ARCH_ARM64 +#endif // V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_LOONG64 default: return false; } } -#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM64 +#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_LOONG64 inline void MaglevAssembler::StoreTaggedFieldNoWriteBarrier( Register object, int offset, ValueNode* constant) { // See {kSupportsStoreTaggedConstant}. @@ -343,7 +343,8 @@ inline void MaglevAssembler::StoreTaggedFieldNoWriteBarrier( Register object, int offset, Handle<HeapObject> constant) { UNREACHABLE(); } -#endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM64 +#endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM64 && + // !V8_TARGET_ARCH_LOONG64 #if !defined(V8_TARGET_ARCH_RISCV64) && !defined(V8_TARGET_ARCH_LOONG64) diff --git a/deps/v8/src/maglev/maglev-assembler.cc b/deps/v8/src/maglev/maglev-assembler.cc index 915452aff1e9..b78e1fddebb4 100644 --- a/deps/v8/src/maglev/maglev-assembler.cc +++ b/deps/v8/src/maglev/maglev-assembler.cc @@ -632,22 +632,22 @@ void MaglevAssembler::CheckAndEmitDeferredWriteBarrier( #ifdef V8_ENABLE_SANDBOX -void MaglevAssembler::CheckAndEmitDeferredIndirectPointerWriteBarrier( +void MaglevAssembler::CheckAndEmitDeferredTrustedPointerWriteBarrier( Register object, int offset, Register value, - RegisterSnapshot register_snapshot, IndirectPointerTag tag) { + RegisterSnapshot register_snapshot, TrustedPointerTag tag) { ZoneLabelRef done(this); Label* deferred_write_barrier = MakeDeferredCode( [](MaglevAssembler* masm, ZoneLabelRef done, Register object, int offset, Register value, RegisterSnapshot register_snapshot, - IndirectPointerTag tag) { + TrustedPointerTag tag) { ASM_CODE_COMMENT_STRING(masm, "Write barrier slow path"); Register stub_object_reg = - IndirectPointerWriteBarrierDescriptor::ObjectRegister(); + TrustedPointerWriteBarrierDescriptor::ObjectRegister(); Register slot_reg = - IndirectPointerWriteBarrierDescriptor::SlotAddressRegister(); + TrustedPointerWriteBarrierDescriptor::SlotAddressRegister(); Register tag_reg = - IndirectPointerWriteBarrierDescriptor::IndirectPointerTagRegister(); + TrustedPointerWriteBarrierDescriptor::TrustedPointerTagRegister(); RegList saved; if (object != stub_object_reg && @@ -675,7 +675,7 @@ void MaglevAssembler::CheckAndEmitDeferredIndirectPointerWriteBarrier( ? SaveFPRegsMode::kSave : SaveFPRegsMode::kIgnore; - __ CallBuiltin(Builtins::IndirectPointerBarrier(save_fp_mode)); + __ CallBuiltin(Builtins::TrustedPointerBarrier(save_fp_mode)); __ PopAll(saved); __ Jump(*done); @@ -705,11 +705,11 @@ void MaglevAssembler::StoreTaggedFieldWithWriteBarrier( void MaglevAssembler::StoreTrustedPointerFieldWithWriteBarrier( Register object, int offset, Register value, - RegisterSnapshot register_snapshot, IndirectPointerTag tag) { + RegisterSnapshot register_snapshot, TrustedPointerTag tag) { AssertNotSmi(object); StoreTrustedPointerFieldNoWriteBarrier(object, offset, value); - CheckAndEmitDeferredIndirectPointerWriteBarrier(object, offset, value, - register_snapshot, tag); + CheckAndEmitDeferredTrustedPointerWriteBarrier(object, offset, value, + register_snapshot, tag); } #endif // V8_ENABLE_SANDBOX @@ -807,15 +807,17 @@ void AttemptOnStackReplacement(MaglevAssembler* masm, { __ LoadByte(scratch1, FieldMemOperand( scratch0, offsetof(FeedbackVector, osr_state_))); - __ DecodeField<FeedbackVector::OsrUrgencyBits>(scratch1); + __ DecodeField<FeedbackVector::OsrState::OsrUrgencyBits>(scratch1); __ JumpIfByte(kUnsignedLessThanEqual, scratch1, node->loop_depth(), *no_code_for_osr); // If tiering is already in progress wait. - static_assert(FeedbackVector::OsrTieringInProgressBit::kMask <= 0xff); + static_assert(FeedbackVector::Flags::OsrTieringInProgressBit::kMask <= + 0xff); __ TestUint8AndJumpIfAnySet( FieldMemOperand(scratch0, offsetof(FeedbackVector, flags_)), - FeedbackVector::OsrTieringInProgressBit::kMask, *no_code_for_osr); + FeedbackVector::Flags::OsrTieringInProgressBit::kMask, + *no_code_for_osr); { // The osr_urgency exceeds the current loop_depth, signaling an OSR @@ -874,16 +876,15 @@ void MaglevAssembler::TryOnStackReplacement(ReduceInterruptBudgetForLoop* node, // In case we use maglev_osr, we need to explicitly know if there is // turbofan code waiting for us (i.e., ignore the // MaybeHasMaglevOsrCodeBit). - DecodeField< - base::BitFieldUnion<FeedbackVector::OsrUrgencyBits, - FeedbackVector::MaybeHasTurbofanOsrCodeBit>>( - osr_state); + DecodeField<base::BitFieldUnion< + FeedbackVector::OsrState::OsrUrgencyBits, + FeedbackVector::OsrState::MaybeHasTurbofanOsrCodeBit>>(osr_state); } // The quick initial OSR check. If it passes, we proceed on to more // expensive OSR logic. - static_assert(FeedbackVector::MaybeHasTurbofanOsrCodeBit::encode(true) > - FeedbackVector::kMaxOsrUrgency); + static_assert(FeedbackVector::OsrState::MaybeHasTurbofanOsrCodeBit::encode( + true) > FeedbackVector::kMaxOsrUrgency); CompareInt32AndJumpIf( osr_state, node->loop_depth(), kUnsignedGreaterThan, MakeDeferredCode(AttemptOnStackReplacement, no_code_for_osr, node, diff --git a/deps/v8/src/maglev/maglev-assembler.h b/deps/v8/src/maglev/maglev-assembler.h index ab934b1ecba5..ac70fdca6d92 100644 --- a/deps/v8/src/maglev/maglev-assembler.h +++ b/deps/v8/src/maglev/maglev-assembler.h @@ -120,6 +120,26 @@ class V8_EXPORT_PRIVATE MaglevAssembler : public MacroAssembler { static constexpr Register GetFlagsRegister() { return kMaglevFlagsRegister; } #endif // V8_TARGET_ARCH_RISCV64 || V8_TARGET_ARCH_LOONG64 + // Whether the architecture has a register that always reads as zero, which + // can be stored instead of materializing a zero constant. + static constexpr bool HasZeroRegister() { +#if defined(V8_TARGET_ARCH_ARM64) || defined(V8_TARGET_ARCH_LOONG64) + return true; +#else + return false; +#endif + } + // The register that always reads as zero; only valid if HasZeroRegister(). + static Register ZeroRegister() { +#if defined(V8_TARGET_ARCH_ARM64) + return xzr; +#elif defined(V8_TARGET_ARCH_LOONG64) + return zero_reg; +#else + UNREACHABLE(); +#endif + } + static constexpr DoubleRegList GetAllocatableDoubleRegisters() { return kAllocatableDoubleRegisters; } @@ -241,9 +261,9 @@ class V8_EXPORT_PRIVATE MaglevAssembler : public MacroAssembler { ValueIsCompressed value_is_compressed, ValueCanBeSmi value_can_be_smi); - void CheckAndEmitDeferredIndirectPointerWriteBarrier( + void CheckAndEmitDeferredTrustedPointerWriteBarrier( Register object, int offset, Register value, - RegisterSnapshot register_snapshot, IndirectPointerTag tag); + RegisterSnapshot register_snapshot, TrustedPointerTag tag); inline void MemoryBarrier(AtomicMemoryOrder order); @@ -267,7 +287,7 @@ class V8_EXPORT_PRIVATE MaglevAssembler : public MacroAssembler { // Whether tagged constants (Smis, read-only roots and compressed heap // objects) can be stored as immediates, i.e. whether the overloads below are // implemented. -#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 +#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_LOONG64 static constexpr bool kSupportsStoreTaggedConstant = COMPRESS_POINTERS_BOOL; #else static constexpr bool kSupportsStoreTaggedConstant = false; @@ -301,7 +321,7 @@ class V8_EXPORT_PRIVATE MaglevAssembler : public MacroAssembler { void StoreTrustedPointerFieldWithWriteBarrier( Register object, int offset, Register value, - RegisterSnapshot register_snapshot, IndirectPointerTag tag); + RegisterSnapshot register_snapshot, TrustedPointerTag tag); inline void StoreTrustedPointerFieldNoWriteBarrier(Register object, int offset, Register value); @@ -512,7 +532,7 @@ class V8_EXPORT_PRIVATE MaglevAssembler : public MacroAssembler { #ifdef V8_TARGET_ARCH_64_BIT inline void Move(Register dst, intptr_t p); #endif - inline void Move(Register dst, IndirectPointerTag i); + inline void Move(Register dst, TrustedPointerTag i); inline void Move(DoubleRegister dst, double n); inline void Move(DoubleRegister dst, Float64 n); inline void Move(Register dst, Handle<HeapObject> obj); diff --git a/deps/v8/src/maglev/maglev-basic-block.cc b/deps/v8/src/maglev/maglev-basic-block.cc new file mode 100644 index 000000000000..41ff819576b9 --- /dev/null +++ b/deps/v8/src/maglev/maglev-basic-block.cc @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project 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 "src/maglev/maglev-basic-block.h" + +#include <algorithm> + +#include "src/maglev/maglev-ir-inl.h" + +namespace v8 { +namespace internal { +namespace maglev { + +ZoneVector<Node*> BasicBlock::Split(Node* node, Zone* zone) { + size_t split = 0; + for (; split < nodes_.size(); split++) { + if (nodes_[split] == node) break; + } + DCHECK_NE(split, nodes_.size()); + ZoneVector<Node*> result(nodes_.size() - split, zone); + for (size_t i = 0; i < result.size(); i++) { + result[i] = nodes_[i + split]; + } + nodes_.resize(split); + return result; +} + +void BasicBlock::TruncateAt(Node* node) { + auto it = std::find(nodes_.begin(), nodes_.end(), node); + DCHECK_NE(it, nodes_.end()); + for (auto cur = it; cur != nodes_.end(); ++cur) { + if (*cur != nullptr) (*cur)->set_owner(nullptr); + } + nodes_.resize(it - nodes_.begin()); +} + +void BasicBlock::OverwriteControlWithAbort(AbortReason reason) { + ControlNode* control = reset_control_node(); + RemovePredecessorFollowing(control); + control->OverwriteWith<Abort>(reason); + set_deferred(true); + set_control_node(control); +} + +} // namespace maglev +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/maglev/maglev-basic-block.h b/deps/v8/src/maglev/maglev-basic-block.h index 785b22f2a72a..9182d07680ca 100644 --- a/deps/v8/src/maglev/maglev-basic-block.h +++ b/deps/v8/src/maglev/maglev-basic-block.h @@ -82,19 +82,13 @@ class BasicBlock { // Moves all nodes after |node| to the resulting ZoneVector, while keeping all // nodes before |node| (inclusive) in the basic block. - ZoneVector<Node*> Split(Node* node, Zone* zone) { - size_t split = 0; - for (; split < nodes_.size(); split++) { - if (nodes_[split] == node) break; - } - DCHECK_NE(split, nodes_.size()); - ZoneVector<Node*> result(nodes_.size() - split, zone); - for (size_t i = 0; i < result.size(); i++) { - result[i] = nodes_[i + split]; - } - nodes_.resize(split); - return result; - } + ZoneVector<Node*> Split(Node* node, Zone* zone); + + // Truncates the basic block to end just before |node|, dropping |node| and + // all subsequent nodes. + void TruncateAt(Node* node); + + void OverwriteControlWithAbort(AbortReason reason); bool has_phi() const { return has_state() && state_->has_phi(); } diff --git a/deps/v8/src/maglev/maglev-code-generator.cc b/deps/v8/src/maglev/maglev-code-generator.cc index 273c56c6ecd6..6099e8e374e2 100644 --- a/deps/v8/src/maglev/maglev-code-generator.cc +++ b/deps/v8/src/maglev/maglev-code-generator.cc @@ -148,6 +148,13 @@ class ParallelMoveResolver { StartEmitMoveChain(moves_from_stack_slot_.begin()->first); } for (auto [stack_slot, node] : materializing_stack_slot_moves_) { + if constexpr (std::is_same_v<RegisterT, Register> && + MaglevAssembler::HasZeroRegister()) { + if (node->MaterializesToZero()) { + __ Move(StackSlot{stack_slot}, MaglevAssembler::ZeroRegister()); + continue; + } + } node->LoadToRegister(masm_, scratch_); __ Move(StackSlot{stack_slot}, scratch_); } @@ -1196,29 +1203,6 @@ class MaglevCodeGeneratingNodeProcessor { bool collect_source_positions_; }; -class SafepointingNodeProcessor { - public: - explicit SafepointingNodeProcessor(LocalIsolate* local_isolate) - : local_isolate_(local_isolate) {} - - void PreProcessGraph(Graph* graph) {} - void PostProcessGraph(Graph* graph) {} - BlockProcessResult PostProcessBasicBlock(BasicBlock* block) { - return BlockProcessResult::kContinue; - } - BlockProcessResult PreProcessBasicBlock(BasicBlock* block) { - return BlockProcessResult::kContinue; - } - void PostPhiProcessing() {} - ProcessResult Process(NodeBase* node, const ProcessingState& state) { - local_isolate_->heap()->Safepoint(); - return ProcessResult::kContinue; - } - - private: - LocalIsolate* local_isolate_; -}; - namespace { DeoptimizationFrameTranslation::FrameCount GetFrameCount( const DeoptFrame* deopt_frame) { @@ -1426,16 +1410,13 @@ class MaglevFrameTranslationBuilder { Builtins::GetContinuationBytecodeOffset(frame.builtin_id()); int literal_id = GetDeoptLiteral(frame.GetSharedFunctionInfo()); - constexpr int kFixedJSFrameRegisterParameters = - JSTrampolineDescriptor::GetRegisterParameterCount(); if (frame.is_javascript()) { translation_array_builder_->BeginJavaScriptBuiltinContinuationFrame( - bailout_id, literal_id, - frame.parameters().length() + kFixedJSFrameRegisterParameters); + bailout_id, literal_id, frame.translation_height()); } else { translation_array_builder_->BeginBuiltinContinuationFrame( - bailout_id, literal_id, frame.parameters().length()); + bailout_id, literal_id, frame.translation_height()); } // Closure @@ -1459,6 +1440,9 @@ class MaglevFrameTranslationBuilder { } if (frame.is_javascript()) { + constexpr int kFixedJSFrameRegisterParameters = + JSTrampolineDescriptor::GetRegisterParameterCount(); + // Fixed register parameters for JS frames. DCHECK_EQ(Builtins::CallInterfaceDescriptorFor(frame.builtin_id()) .GetRegisterParameterCount(), @@ -1564,7 +1548,7 @@ class MaglevFrameTranslationBuilder { return kNotDuplicated; } - void BuildNestedValue(const VirtualObject* object, const ValueNode* value, + void BuildNestedValue(const ValueNode* value, const InputLocation*& input_location, const VirtualObjectList& virtual_objects) { const Opcode opcode = value->opcode(); @@ -1573,22 +1557,14 @@ class MaglevFrameTranslationBuilder { DCHECK_NE(opcode, Opcode::kIdentity); if (IsConstantNode(opcode)) { if (opcode == Opcode::kFloat64Constant) { - DCHECK(object->has_static_map()); - if (object->map()->IsFixedDoubleArrayMap()) { - Float64 value_as_float = value->Cast<Float64Constant>()->value(); - if (value_as_float.is_hole_nan()) { - translation_array_builder_->StoreLiteral(GetDeoptLiteral( - ReadOnlyRoots{local_isolate_}.the_hole_value())); - return; - } -#ifdef V8_ENABLE_UNDEFINED_DOUBLE - if (value_as_float.is_undefined_nan()) { - translation_array_builder_->StoreLiteral(GetDeoptLiteral( - ReadOnlyRoots{local_isolate_}.undefined_value())); - return; - } -#endif // V8_ENABLE_UNDEFINED_DOUBLE - } + translation_array_builder_->StoreDoubleLiteral( + value->Cast<Float64Constant>()->value()); + return; + } + if (opcode == Opcode::kHoleyFloat64Constant) { + translation_array_builder_->StoreHoleyDoubleLiteral( + value->Cast<HoleyFloat64Constant>()->value()); + return; } translation_array_builder_->StoreLiteral( GetDeoptLiteral(*value->Reify(local_isolate_))); @@ -1654,7 +1630,7 @@ class MaglevFrameTranslationBuilder { translation_array_builder_->BeginCapturedObject(fields); } auto callback = [&](ValueNode* node, const vobj::Field& desc) -> bool { - BuildNestedValue(object, node, input_location, virtual_objects); + BuildNestedValue(node, input_location, virtual_objects); return true; }; object->ForEachSlot(callback, @@ -1675,8 +1651,16 @@ class MaglevFrameTranslationBuilder { } } if (input_location->operand().IsConstant()) { - translation_array_builder_->StoreLiteral( - GetDeoptLiteral(*value->Reify(local_isolate_))); + if (value->opcode() == Opcode::kFloat64Constant) { + translation_array_builder_->StoreDoubleLiteral( + value->Cast<Float64Constant>()->value()); + } else if (value->opcode() == Opcode::kHoleyFloat64Constant) { + translation_array_builder_->StoreHoleyDoubleLiteral( + value->Cast<HoleyFloat64Constant>()->value()); + } else { + translation_array_builder_->StoreLiteral( + GetDeoptLiteral(*value->Reify(local_isolate_))); + } } else { const compiler::AllocatedOperand& operand = compiler::AllocatedOperand::cast(input_location->operand()); @@ -1822,7 +1806,6 @@ MaglevCodeGenerator::MaglevCodeGenerator( deopt_literals_(isolate->heap()->heap()), protected_deopt_literals_vector_(compilation_info->zone()), deopt_literals_vector_(compilation_info->zone()), - retained_maps_(isolate->heap()), is_context_specialized_( compilation_info->specialize_to_function_context()), zone_(compilation_info->zone()) { @@ -1844,7 +1827,8 @@ bool MaglevCodeGenerator::Assemble() { BuildCodeObject(local_isolate_)); Handle<Code> code; if (code_.ToHandle(&code)) { - retained_maps_ = CollectRetainedMaps(code); + retained_maps_ = OptimizedCompilationJob::CollectRetainedMaps( + code, code_gen_state_.compilation_info()->DetachCanonicalHandles()); } } else if (v8_flags.maglev_deopt_data_on_background) { // Only do this if not --maglev-build-code-on-background, since that will do @@ -1867,19 +1851,8 @@ MaybeHandle<Code> MaglevCodeGenerator::Generate(Isolate* isolate) { return BuildCodeObject(isolate->main_thread_local_isolate()); } -GlobalHandleVector<Map> MaglevCodeGenerator::RetainedMaps(Isolate* isolate) { - DisallowGarbageCollection no_gc; - GlobalHandleVector<Map> maps(isolate->heap()); - maps.Reserve(retained_maps_.size()); - for (DirectHandle<Map> map : retained_maps_) maps.Push(*map); - return maps; -} - bool MaglevCodeGenerator::EmitCode() { - GraphProcessor<NodeMultiProcessor<SafepointingNodeProcessor, - MaglevCodeGeneratingNodeProcessor>> - processor(SafepointingNodeProcessor{local_isolate_}, - MaglevCodeGeneratingNodeProcessor{masm(), zone_}); + GraphProcessor<MaglevCodeGeneratingNodeProcessor> processor(masm(), zone_); RecordInlinedFunctions(); if (graph_->is_osr()) { @@ -1890,7 +1863,10 @@ bool MaglevCodeGenerator::EmitCode() { processor.ProcessGraph(graph_); EmitDeferredCode(); - if (!EmitDeopts()) return false; + bool deopts_emitted = EmitDeopts(); + protected_deopt_literals_.Clear(); + deopt_literals_.Clear(); + if (!deopts_emitted) return false; EmitExceptionHandlerTrampolines(); EmitRetainedObjects(); __ FinishCode(); @@ -2126,25 +2102,6 @@ MaybeHandle<Code> MaglevCodeGenerator::BuildCodeObject( return maybe_code; } -GlobalHandleVector<Map> MaglevCodeGenerator::CollectRetainedMaps( - DirectHandle<Code> code) { - DCHECK(code->is_optimized_code()); - - DisallowGarbageCollection no_gc; - GlobalHandleVector<Map> maps(local_isolate_->heap()); - int const mode_mask = RelocInfo::EmbeddedObjectModeMask(); - for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { - DCHECK(RelocInfo::IsEmbeddedObjectMode(it.rinfo()->rmode())); - Tagged<HeapObject> target_object = it.rinfo()->target_object(); - if (code->IsWeakObjectInOptimizedCode(target_object)) { - if (IsMap(target_object)) { - maps.Push(Cast<Map>(target_object)); - } - } - } - return maps; -} - Handle<DeoptimizationData> MaglevCodeGenerator::GenerateDeoptimizationData( LocalIsolate* local_isolate) { int eager_deopt_count = diff --git a/deps/v8/src/maglev/maglev-code-generator.h b/deps/v8/src/maglev/maglev-code-generator.h index b38547c244a2..bfde1984d522 100644 --- a/deps/v8/src/maglev/maglev-code-generator.h +++ b/deps/v8/src/maglev/maglev-code-generator.h @@ -5,6 +5,7 @@ #ifndef V8_MAGLEV_MAGLEV_CODE_GENERATOR_H_ #define V8_MAGLEV_MAGLEV_CODE_GENERATOR_H_ +#include "src/base/small-vector.h" #include "src/codegen/maglev-safepoint-table.h" #include "src/codegen/source-position-table.h" #include "src/common/globals.h" @@ -32,7 +33,9 @@ class MaglevCodeGenerator final { MaybeHandle<Code> Generate(Isolate* isolate); - GlobalHandleVector<Map> RetainedMaps(Isolate* isolate); + base::Vector<const IndirectHandle<Map>> retained_maps() const { + return base::VectorOf(retained_maps_); + } Graph* graph() const { return graph_; } @@ -45,7 +48,6 @@ class MaglevCodeGenerator final { void EmitMetadata(); void RecordInlinedFunctions(); - GlobalHandleVector<Map> CollectRetainedMaps(DirectHandle<Code> code); Handle<DeoptimizationData> GenerateDeoptimizationData( LocalIsolate* local_isolate); MaybeHandle<Code> BuildCodeObject(LocalIsolate* local_isolate); @@ -78,7 +80,7 @@ class MaglevCodeGenerator final { IndirectHandle<DeoptimizationData> deopt_data_; MaybeIndirectHandle<Code> code_; - GlobalHandleVector<Map> retained_maps_; + base::SmallVector<IndirectHandle<Map>, 8> retained_maps_; bool is_context_specialized_; Zone* zone_; }; diff --git a/deps/v8/src/maglev/maglev-compilation-info.cc b/deps/v8/src/maglev/maglev-compilation-info.cc index cf7073c99d4a..f227d4b8bf2f 100644 --- a/deps/v8/src/maglev/maglev-compilation-info.cc +++ b/deps/v8/src/maglev/maglev-compilation-info.cc @@ -65,43 +65,6 @@ static bool SpecializeToFunctionContext( } // namespace -void MaglevCompilationInfo::InitializeSpecializationContext() { -#ifdef DEBUG - specialization_context_initialized_ = true; -#endif - if (!v8_flags.always_specialize_for_script_context || toplevel_is_osr()) { - return; - } - compiler::JSFunctionRef func_ref = compiler::MakeRefAssumeMemoryFence( - broker_, broker_->CanonicalPersistentHandle(toplevel_function_)); - compiler::ContextRef current = func_ref.context(broker_); - if (current.map(broker_).instance_type() == NATIVE_CONTEXT_TYPE) { - return; - } - if (specialize_to_function_context_) { - specialization_context_ = current; - specialization_context_distance_ = 0; - return; - } - size_t distance = 0; - while (true) { - InstanceType instance_type = current.map(broker_).instance_type(); - if (instance_type == NATIVE_CONTEXT_TYPE) { - break; - } - if (instance_type == MODULE_CONTEXT_TYPE || - instance_type == SCRIPT_CONTEXT_TYPE) { - specialization_context_ = current; - specialization_context_distance_ = distance; - return; - } - size_t step = 1; - current = current.previous(broker_, &step); - if (step != 0) break; - distance++; - } -} - MaglevCompilationInfo::MaglevCompilationInfo( Isolate* isolate, IndirectHandle<JSFunction> function, BytecodeOffset osr_offset, std::optional<compiler::JSHeapBroker*> js_broker, @@ -239,7 +202,6 @@ bool MaglevCompilationInfo::is_detached() { std::unique_ptr<CanonicalHandlesMap> MaglevCompilationInfo::DetachCanonicalHandles() { - DCHECK_NOT_NULL(canonical_handles_); return std::move(canonical_handles_); } diff --git a/deps/v8/src/maglev/maglev-compilation-info.h b/deps/v8/src/maglev/maglev-compilation-info.h index 383defe276a5..b722b7b24491 100644 --- a/deps/v8/src/maglev/maglev-compilation-info.h +++ b/deps/v8/src/maglev/maglev-compilation-info.h @@ -194,17 +194,6 @@ class MaglevCompilationInfo final { return specialize_to_function_context_; } - void InitializeSpecializationContext(); - - compiler::OptionalContextRef specialization_context() const { - DCHECK(specialization_context_initialized_); - return specialization_context_; - } - size_t specialization_context_distance() const { - DCHECK(specialization_context_initialized_); - return specialization_context_distance_; - } - // Must be called from within a MaglevCompilationHandleScope. Transfers owned // handles (e.g. shared_, function_) to the new scope. void ReopenAndCanonicalizeHandlesInNewScope(Isolate* isolate); @@ -293,12 +282,6 @@ class MaglevCompilationInfo final { // contexts. const bool specialize_to_function_context_; - compiler::OptionalContextRef specialization_context_; - size_t specialization_context_distance_ = 0; -#ifdef DEBUG - bool specialization_context_initialized_ = false; -#endif - // 1) PersistentHandles created via PersistentHandlesScope inside of // CompilationHandleScope. // 2) Owned by MaglevCompilationInfo. diff --git a/deps/v8/src/maglev/maglev-compilation-unit.cc b/deps/v8/src/maglev/maglev-compilation-unit.cc index 91cb1ded4853..ae550cd331ad 100644 --- a/deps/v8/src/maglev/maglev-compilation-unit.cc +++ b/deps/v8/src/maglev/maglev-compilation-unit.cc @@ -8,6 +8,7 @@ #include "src/compiler/js-heap-broker.h" #include "src/maglev/maglev-compilation-info.h" #include "src/maglev/maglev-graph-labeller.h" +#include "src/maglev/maglev-ir.h" #include "src/objects/js-function-inl.h" namespace v8 { @@ -26,7 +27,8 @@ MaglevCompilationUnit::MaglevCompilationUnit(MaglevCompilationInfo* info, MaglevCompilationUnit::MaglevCompilationUnit( MaglevCompilationInfo* info, const MaglevCompilationUnit* caller, compiler::SharedFunctionInfoRef shared_function_info, - compiler::FeedbackCellRef feedback_cell) + compiler::FeedbackCellRef feedback_cell, ValueNode* context, + ValueNode* function) : info_(info), caller_(caller), shared_function_info_(shared_function_info), @@ -41,6 +43,159 @@ MaglevCompilationUnit::MaglevCompilationUnit( DCHECK_EQ(bytecode_->parameter_count(), shared_function_info .internal_formal_parameter_count_with_receiver_deprecated()); + if (caller != nullptr) { + InitializeSpecializationContextForInlined(context, function); + } +} + +namespace { +std::pair<compiler::ScopeInfoRef, bool> GetIncomingContextScopeInfo( + compiler::JSHeapBroker* broker, + compiler::SharedFunctionInfoRef shared_function_info) { + compiler::ScopeInfoRef scope_info = shared_function_info.scope_info(broker); + if (scope_info.HasOuterScopeInfo()) { + scope_info = scope_info.OuterScopeInfo(broker); + CHECK(scope_info.HasContext()); + return {scope_info, true}; + } + return {scope_info, + shared_function_info.is_toplevel() && scope_info.HasContext()}; +} + +std::optional<std::pair<compiler::ContextRef, size_t>> +FindModuleOrScriptContext(compiler::JSHeapBroker* broker, + compiler::ContextRef current) { + size_t dist = 0; + while (true) { + InstanceType instance_type = current.map(broker).instance_type(); + if (instance_type == NATIVE_CONTEXT_TYPE) { + return std::nullopt; + } + if (instance_type == MODULE_CONTEXT_TYPE || + instance_type == SCRIPT_CONTEXT_TYPE) { + return std::make_pair(current, dist); + } + size_t step = 1; + current = current.previous(broker, &step); + if (step != 0) return std::nullopt; + dist++; + } +} +} // namespace + +void MaglevCompilationUnit::InitializeSpecializationContextFromKnownContext( + compiler::ContextRef current, compiler::ScopeInfoRef scope_info, + bool has_incoming_context_scope, bool specialize_to_function_context) { + std::optional<size_t> distance; + if (has_incoming_context_scope) { + if (specialize_to_function_context) { + if (current.map(broker()).instance_type() != NATIVE_CONTEXT_TYPE) { + specialization_context_ = current; + distance = 0; + } + } else if (v8_flags.always_specialize_for_script_context) { + if (auto found = FindModuleOrScriptContext(broker(), current)) { + specialization_context_ = found->first; + distance = found->second; + } + } + } + incoming_context_scope_info_ = ContextScopeInfo(scope_info, distance); +} + +void MaglevCompilationUnit::InitializeSpecializationContextForTopLevel() { + DCHECK(!is_inline()); + DCHECK(!specialization_context_initialized_); +#ifdef DEBUG + specialization_context_initialized_ = true; +#endif + auto [scope_info, has_incoming_context_scope] = + GetIncomingContextScopeInfo(broker(), *shared_function_info_); + if (v8_flags.always_specialize_for_script_context) { + compiler::JSFunctionRef func_ref = compiler::MakeRefAssumeMemoryFence( + broker(), + broker()->CanonicalPersistentHandle(info_->toplevel_function())); + InitializeSpecializationContextFromKnownContext( + func_ref.context(broker()), scope_info, has_incoming_context_scope, + info_->specialize_to_function_context()); + } else { + incoming_context_scope_info_ = ContextScopeInfo(scope_info); + } +} + +void MaglevCompilationUnit::InitializeSpecializationContextForInlined( + ValueNode* context, ValueNode* function) { + DCHECK(is_inline()); + DCHECK_NOT_NULL(context); + DCHECK_NOT_NULL(function); + DCHECK(!specialization_context_initialized_); +#ifdef DEBUG + specialization_context_initialized_ = true; +#endif + auto [scope_info, has_incoming_context_scope] = + GetIncomingContextScopeInfo(broker(), *shared_function_info_); + if (!v8_flags.always_specialize_for_script_context || + !has_incoming_context_scope) { + incoming_context_scope_info_ = ContextScopeInfo(scope_info); + return; + } + + // Case 1: Inlined unit with a known constant context (e.g. a known constant + // JSFunctionRef, which could even be from another script). + if (HeapConstant* constant_context = context->TryCast<HeapConstant>()) { + InitializeSpecializationContextFromKnownContext( + constant_context->ref().AsContext(), scope_info, + has_incoming_context_scope, + v8_flags.maglev_function_context_specialization); + return; + } + + // Case 2: Closure created by us (`FastCreateClosure` / `CreateClosure`) + // inherits the specialization context and current scope info from its + // creation site. Note that `caller_` is the compilation unit where the + // closure is called, which may differ from the compilation unit where the + // closure was created (e.g. when a factory function is inlined into `caller_` + // and returns a fresh closure allocated in a new FunctionContext with the + // same ScopeInfo as `caller_->specialization_context()`). + if (FastCreateClosure* fast_closure = + function->TryCast<FastCreateClosure>()) { + DCHECK_EQ(fast_closure->shared_function_info(), *shared_function_info_); + DCHECK_EQ(fast_closure->context_scope_info().value(), scope_info); + specialization_context_ = fast_closure->specialization_context(); + incoming_context_scope_info_ = fast_closure->context_scope_info(); + return; + } + if (CreateClosure* slow_closure = function->TryCast<CreateClosure>()) { + DCHECK_EQ(slow_closure->shared_function_info(), *shared_function_info_); + DCHECK_EQ(slow_closure->context_scope_info().value(), scope_info); + specialization_context_ = slow_closure->specialization_context(); + incoming_context_scope_info_ = slow_closure->context_scope_info(); + return; + } + + // Case 3: Dynamic closure via `FeedbackCell` cannot specialize to a + // `FunctionContext`, so walk `caller_->specialization_context()` outward to + // find an enclosing `SCRIPT_CONTEXT_TYPE` or `MODULE_CONTEXT_TYPE`. + std::optional<size_t> distance; + if (caller_->specialization_context().has_value()) { + if (auto found = FindModuleOrScriptContext( + broker(), *caller_->specialization_context())) { + compiler::ScopeInfoRef outer_scope = found->first.scope_info(broker()); + compiler::ScopeInfoRef curr = scope_info; + size_t dist = 0; + while (true) { + if (curr.equals(outer_scope)) { + specialization_context_ = found->first; + distance = dist; + break; + } + if (!curr.HasOuterScopeInfo()) break; + curr = curr.OuterScopeInfo(broker()); + dist++; + } + } + } + incoming_context_scope_info_ = ContextScopeInfo(scope_info, distance); } MaglevCompilationUnit::MaglevCompilationUnit( diff --git a/deps/v8/src/maglev/maglev-compilation-unit.h b/deps/v8/src/maglev/maglev-compilation-unit.h index 5e7469af5ab8..c53ff35af819 100644 --- a/deps/v8/src/maglev/maglev-compilation-unit.h +++ b/deps/v8/src/maglev/maglev-compilation-unit.h @@ -5,6 +5,9 @@ #ifndef V8_MAGLEV_MAGLEV_COMPILATION_UNIT_H_ #define V8_MAGLEV_MAGLEV_COMPILATION_UNIT_H_ +#include <limits> +#include <optional> + #include "src/common/globals.h" #include "src/compiler/bytecode-analysis.h" #include "src/compiler/heap-refs.h" @@ -17,6 +20,88 @@ enum class ValueRepresentation : uint8_t; class MaglevCompilationInfo; class MaglevGraphLabeller; class Node; +class ValueNode; + +// Bundles a static ScopeInfoRef with the distance (in Context::previous() hops) +// from this scope to MaglevCompilationUnit::specialization_context(). +// - If specialization_context_distance() has a value, walking outward that many +// steps reaches the unit's specialization context. +// - If specialization_context_distance() is std::nullopt (stored compactly as +// kNoDistance to keep sizeof(ContextScopeInfo) == 16), either the unit has no +// specialization context, or we have walked outward past the specialization +// context. +class ContextScopeInfo { + public: + ContextScopeInfo() = default; + ContextScopeInfo(std::nullopt_t) {} // NOLINT(runtime/explicit) + ContextScopeInfo(compiler::OptionalScopeInfoRef scope_info, + std::optional<size_t> specialization_context_distance = + std::nullopt) // NOLINT(runtime/explicit) + : scope_info_(scope_info), + specialization_context_distance_( + scope_info.has_value() + ? specialization_context_distance.value_or(kNoDistance) + : kNoDistance) {} + + bool has_value() const { return scope_info_.has_value(); } + compiler::ScopeInfoRef value() const { return scope_info_.value(); } + operator compiler::ScopeInfoRef() const { return value(); } + compiler::OptionalScopeInfoRef scope_info() const { return scope_info_; } + + bool HasOuterScopeInfo() const { return scope_info_->HasOuterScopeInfo(); } + bool HasContextExtensionSlot() const { + return scope_info_->HasContextExtensionSlot(); + } + ScopeType scope_type() const { return scope_info_->scope_type(); } + + std::optional<size_t> specialization_context_distance() const { + if (!has_value() || specialization_context_distance_ == kNoDistance) { + return std::nullopt; + } + return specialization_context_distance_; + } + + V8_NODISCARD ContextScopeInfo Push(compiler::ScopeInfoRef inner_scope) const { + std::optional<size_t> inner_dist; + if (specialization_context_distance_ != kNoDistance) { + inner_dist = specialization_context_distance_ + 1; + } + return ContextScopeInfo(inner_scope, inner_dist); + } + + V8_NODISCARD ContextScopeInfo + OuterScopeInfo(compiler::JSHeapBroker* broker) const { + DCHECK(has_value()); + DCHECK(HasOuterScopeInfo()); + std::optional<size_t> outer_dist; + if (specialization_context_distance_ != kNoDistance) { + DCHECK_GT(specialization_context_distance_, 0); + outer_dist = specialization_context_distance_ - 1; + } + return ContextScopeInfo(scope_info_->OuterScopeInfo(broker), outer_dist); + } + + bool operator==(const ContextScopeInfo& other) const { + DCHECK_IMPLIES(scope_info_.equals(other.scope_info_), + specialization_context_distance_ == + other.specialization_context_distance_); + return scope_info_.equals(other.scope_info_); + } + + friend std::ostream& operator<<(std::ostream& os, + const ContextScopeInfo& info) { + if (info.has_value()) { + return os << info.value(); + } + return os << "<empty>"; + } + + private: + static constexpr size_t kNoDistance = std::numeric_limits<size_t>::max(); + + compiler::OptionalScopeInfoRef scope_info_; + size_t specialization_context_distance_ = kNoDistance; +}; // Per-unit data, i.e. once per top-level function and once per inlined // function. @@ -29,9 +114,11 @@ class MaglevCompilationUnit : public ZoneObject { static MaglevCompilationUnit* NewInner( Zone* zone, const MaglevCompilationUnit* caller, compiler::SharedFunctionInfoRef shared_function_info, - compiler::FeedbackCellRef feedback_cell) { - return zone->New<MaglevCompilationUnit>( - caller->info(), caller, shared_function_info, feedback_cell); + compiler::FeedbackCellRef feedback_cell, ValueNode* context, + ValueNode* function) { + return zone->New<MaglevCompilationUnit>(caller->info(), caller, + shared_function_info, feedback_cell, + context, function); } static MaglevCompilationUnit* NewDummy(Zone* zone, const MaglevCompilationUnit* caller, @@ -48,7 +135,9 @@ class MaglevCompilationUnit : public ZoneObject { MaglevCompilationUnit(MaglevCompilationInfo* info, const MaglevCompilationUnit* caller, compiler::SharedFunctionInfoRef shared_function_info, - compiler::FeedbackCellRef feedback_cell); + compiler::FeedbackCellRef feedback_cell, + ValueNode* context = nullptr, + ValueNode* function = nullptr); MaglevCompilationUnit(MaglevCompilationInfo* info, const MaglevCompilationUnit* caller, int register_count, @@ -79,16 +168,36 @@ class MaglevCompilationUnit : public ZoneObject { compiler::FeedbackVectorRef feedback() const { return feedback_cell().feedback_vector((broker())).value(); } + compiler::OptionalContextRef specialization_context() const { + DCHECK(specialization_context_initialized_); + return specialization_context_; + } + ContextScopeInfo incoming_context_scope_info() const { + DCHECK(specialization_context_initialized_); + return incoming_context_scope_info_; + } + void InitializeSpecializationContextForTopLevel(); void RegisterNodeInGraphLabeller(const Node* node); const MaglevCompilationUnit* GetTopLevelCompilationUnit() const; private: + void InitializeSpecializationContextForInlined(ValueNode* context, + ValueNode* function); + void InitializeSpecializationContextFromKnownContext( + compiler::ContextRef context, compiler::ScopeInfoRef scope_info, + bool has_incoming_context_scope, bool specialize_to_function_context); + MaglevCompilationInfo* const info_; const MaglevCompilationUnit* const caller_; const compiler::OptionalSharedFunctionInfoRef shared_function_info_; const compiler::OptionalBytecodeArrayRef bytecode_; const compiler::OptionalFeedbackCellRef feedback_cell_; + compiler::OptionalContextRef specialization_context_; + ContextScopeInfo incoming_context_scope_info_; +#ifdef DEBUG + bool specialization_context_initialized_ = false; +#endif const int register_count_; const uint16_t parameter_count_; const uint16_t max_arguments_; diff --git a/deps/v8/src/maglev/maglev-compiler.cc b/deps/v8/src/maglev/maglev-compiler.cc index 06dd7c5e3010..efea5470006e 100644 --- a/deps/v8/src/maglev/maglev-compiler.cc +++ b/deps/v8/src/maglev/maglev-compiler.cc @@ -41,6 +41,11 @@ #include "src/objects/code-inl.h" #include "src/objects/js-function.h" +#ifdef V8_FUZZILLI +#include "src/base/hashing.h" +#include "src/fuzzilli/cov.h" +#endif + #ifdef ALWAYS_MAGLEV_GRAPH_LABELLER #define ALWAYS_MAGLEV_GRAPH_LABELLER_BOOL true #else @@ -82,6 +87,45 @@ void PrintAndVerify(Graph* graph, bool printing_condition, MaglevPhase phase) { PrintGraph(graph, printing_condition, phase); VerifyGraph(graph, phase); } + +#ifdef V8_FUZZILLI +void CollectOptimizedCodeCoverageFromNode( + NodeBase* node, size_t steps_to_go, size_t hash_so_far, + std::set<uint32_t>& accumulated_hashes) { + v8::base::Hasher hasher(hash_so_far); + hasher.Add(node->opcode()); + + bool has_recursed = false; + if (steps_to_go > 0) { + int input_count = node->input_count(); + for (int i = 0; i < input_count; ++i) { + has_recursed = true; + ValueNode* input = node->input_node(i); + CollectOptimizedCodeCoverageFromNode(input, steps_to_go - 1, + hasher.hash(), accumulated_hashes); + } + } + if (!has_recursed) { + accumulated_hashes.insert(static_cast<uint32_t>(hasher.hash())); + } +} + +void ExtractOptimizedCodeCoverage(Graph* graph) { + // We extract information from each node and its input up to this depth: + constexpr size_t kMaxPathLength = 3; + std::set<uint32_t> hashes; + + for (BasicBlock* block : *graph) { + if (block->is_dead()) continue; + block->ForEachNodeAndControl([&](NodeBase* node) { + CollectOptimizedCodeCoverageFromNode(node, kMaxPathLength, 0, hashes); + }); + } + + cov_add_optimized_code_coverage_edges(hashes); +} +#endif + } // namespace // static @@ -285,6 +329,8 @@ bool MaglevCompiler::Compile(LocalIsolate* local_isolate, // FunctionEntryStackCheck runs. A frame no larger than the smallest OS page // cannot step over a guard page, so bail out rather than emit an unchecked // stack pointer jump of arbitrary size. + // When replacing this bailout with a different strategy, consider doing the + // same in Turboshaft as well. if (graph->tagged_stack_slots() + graph->untagged_stack_slots() > kMaxStackSlots) { return false; @@ -299,6 +345,9 @@ bool MaglevCompiler::Compile(LocalIsolate* local_isolate, std::make_unique<MaglevCodeGenerator>(local_isolate, compilation_info, graph); bool success = code_generator->Assemble(); + if (v8_flags.maglev_build_code_on_background || !success) { + compilation_info->broker()->DetachCanonicalHandles(compilation_info); + } if (!success) { return false; } @@ -307,6 +356,12 @@ bool MaglevCompiler::Compile(LocalIsolate* local_isolate, compilation_info->set_code_generator(std::move(code_generator)); } +#ifdef V8_FUZZILLI + if (v8_flags.fuzzilli_enable_optimized_code_coverage) { + ExtractOptimizedCodeCoverage(graph); + } +#endif + return true; } diff --git a/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc b/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc index 45bcecaa63ad..76df131bd728 100644 --- a/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc +++ b/deps/v8/src/maglev/maglev-concurrent-dispatcher.cc @@ -4,7 +4,6 @@ #include "src/maglev/maglev-concurrent-dispatcher.h" -#include "src/base/fpu.h" #include "src/codegen/compiler.h" #include "src/common/synchronization-point-support.h" #include "src/compiler/compilation-dependencies.h" @@ -179,28 +178,26 @@ CompilationJob::Status MaglevCompilationJob::FinalizeJobImpl(Isolate* isolate) { CachedTieringDecision::kNormal); } info()->set_code(code); - GlobalHandleVector<Map> maps = CollectRetainedMaps(isolate, code); - RegisterWeakObjectsInOptimizedCode( - isolate, info()->broker()->target_native_context().object(), code, - std::move(maps)); - EndPhaseKind(); - return CompilationJob::SUCCEEDED; -} - -GlobalHandleVector<Map> MaglevCompilationJob::CollectRetainedMaps( - Isolate* isolate, DirectHandle<Code> code) { if (v8_flags.maglev_build_code_on_background) { - return info()->code_generator()->RetainedMaps(isolate); + RegisterWeakObjectsInOptimizedCode( + isolate, info()->broker()->target_native_context().object(), code, + info()->code_generator()->retained_maps()); + } else { + RetainedMaps maps = OptimizedCompilationJob::CollectRetainedMaps( + code, info()->DetachCanonicalHandles()); + RegisterWeakObjectsInOptimizedCode( + isolate, info()->broker()->target_native_context().object(), code, + base::VectorOf(maps)); } - return OptimizedCompilationJob::CollectRetainedMaps(isolate, code); + EndPhaseKind(); + return CompilationJob::SUCCEEDED; } void MaglevCompilationJob::DisposeOnMainThread(Isolate* isolate) { - // Drop canonical handles on the main thread, to avoid (in the case of - // background job destruction) needing to unpark the local isolate on the - // background thread for unregistering the identity map's strong roots. DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); - info()->DetachCanonicalHandles()->Clear(); + if (auto canonical_handles = info()->DetachCanonicalHandles()) { + canonical_handles->Clear(); + } } MaybeIndirectHandle<Code> MaglevCompilationJob::code() const { @@ -287,8 +284,6 @@ class MaglevConcurrentDispatcher::JobTask final : public v8::JobTask { return; } TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.MaglevTask"); - base::FlushDenormalsScope flush_denormals_scope( - isolate()->flush_denormals()); LocalIsolate local_isolate(isolate(), ThreadKind::kBackground); DCHECK(local_isolate.heap()->IsParked()); @@ -320,7 +315,6 @@ class MaglevConcurrentDispatcher::JobTask final : public v8::JobTask { TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.MaglevDestructBackground", perfetto::TerminatingFlow::ProcessScoped(job->trace_id())); - UnparkedScope unparked_scope(&local_isolate); job.reset(); } else { break; diff --git a/deps/v8/src/maglev/maglev-concurrent-dispatcher.h b/deps/v8/src/maglev/maglev-concurrent-dispatcher.h index aa71cea3640f..5b090970890f 100644 --- a/deps/v8/src/maglev/maglev-concurrent-dispatcher.h +++ b/deps/v8/src/maglev/maglev-concurrent-dispatcher.h @@ -62,8 +62,6 @@ class MaglevCompilationJob final : public OptimizedCompilationJob { std::unique_ptr<MaglevCompilationInfo>&& info); void BeginPhaseKind(const char* name); void EndPhaseKind(); - GlobalHandleVector<Map> CollectRetainedMaps(Isolate* isolate, - DirectHandle<Code> code); MaglevCompilationInfo* info() const { return info_.get(); } diff --git a/deps/v8/src/maglev/maglev-graph-builder.cc b/deps/v8/src/maglev/maglev-graph-builder.cc index ca199bab0fab..ece949c1ddfb 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.cc +++ b/deps/v8/src/maglev/maglev-graph-builder.cc @@ -81,6 +81,7 @@ #include "src/objects/literal-objects-inl.h" #include "src/objects/name-inl.h" #include "src/objects/object-list-macros.h" +#include "src/objects/objects-inl.h" #include "src/objects/ordered-hash-table.h" #include "src/objects/property-cell.h" #include "src/objects/property-details.h" @@ -108,18 +109,21 @@ namespace { class FunctionContextSpecialization final : public AllStatic { public: static compiler::OptionalContextRef TryToRef( - const MaglevCompilationUnit* unit, ValueNode* context, size_t* depth) { + const MaglevCompilationUnit* unit, ValueNode* context, + const ContextScopeInfo& scope_info, size_t* depth) { if (HeapConstant* n = context->TryCast<HeapConstant>()) { return n->ref().AsContext().previous(unit->broker(), depth); } if (v8_flags.always_specialize_for_script_context) { - if (InitialValue* n = context->TryCast<InitialValue>()) { - if (!unit->info()->toplevel_is_osr() && - n->source() == interpreter::Register::current_context()) { - if (compiler::OptionalContextRef outer = - unit->info()->specialization_context()) { - if (*depth >= unit->info()->specialization_context_distance()) { - *depth -= unit->info()->specialization_context_distance(); + if (compiler::OptionalContextRef outer = unit->specialization_context()) { + if (scope_info.has_value()) { +#ifdef DEBUG + VerifySpecializationContextDistance(unit, *outer, scope_info, *depth); +#endif + if (std::optional<size_t> distance = + scope_info.specialization_context_distance()) { + if (*distance <= *depth) { + *depth -= *distance; return outer->previous(unit->broker(), depth); } } @@ -128,6 +132,32 @@ class FunctionContextSpecialization final : public AllStatic { } return {}; } + + private: +#ifdef DEBUG + static void VerifySpecializationContextDistance( + const MaglevCompilationUnit* unit, compiler::ContextRef outer, + const ContextScopeInfo& scope_info, size_t depth) { + std::optional<size_t> distance = + scope_info.specialization_context_distance(); + std::optional<size_t> walked_distance; + compiler::ScopeInfoRef outer_scope = outer.scope_info(unit->broker()); + compiler::ScopeInfoRef curr = scope_info.value(); + for (size_t dist = 0; dist <= depth; ++dist) { + if (curr.equals(outer_scope)) { + walked_distance = dist; + break; + } + if (!curr.HasOuterScopeInfo()) break; + curr = curr.OuterScopeInfo(unit->broker()); + } + if (distance.has_value() && *distance <= depth) { + DCHECK_EQ(distance, walked_distance); + } else { + DCHECK(!walked_distance.has_value()); + } + } +#endif }; NodeType NodeTypeFromAccessInfo(compiler::JSHeapBroker* broker, @@ -172,36 +202,12 @@ NodeType NodeTypeFromAccessInfo(compiler::JSHeapBroker* broker, } // namespace -ValueNode* MaglevGraphBuilder::TryGetParentContext(ValueNode* node) { - if (CreateFunctionContext* n = node->TryCast<CreateFunctionContext>()) { - return n->ContextInput().node(); - } - - if (InlinedAllocation* alloc = node->TryCast<InlinedAllocation>()) { - return alloc->object()->get( - Context::OffsetOfElementAt(Context::PREVIOUS_INDEX)); - } - - if (CallRuntime* n = node->TryCast<CallRuntime>()) { - switch (n->function_id()) { - case Runtime::kPushBlockContext: - case Runtime::kPushCatchContext: - case Runtime::kNewFunctionContext: - return n->ContextInput().node(); - default: - break; - } - } - - return nullptr; -} - // Attempts to walk up the context chain through the graph in order to reduce // depth and thus the number of runtime loads. void MaglevGraphBuilder::MinimizeContextChainDepth( ValueNode** context, size_t* depth, ContextScopeInfo* scope_info) { while (*depth > 0) { - ValueNode* parent_context = TryGetParentContext(*context); + ValueNode* parent_context = reducer_.TryGetParentContext(*context); if (parent_context == nullptr) return; *context = parent_context; (*depth)--; @@ -786,14 +792,6 @@ void MaglevGraphBuilder::BuildRegisterFrameInitialization( compilation_unit_->info()->toplevel_function())); closure = GetConstant(function); context = GetConstant(function.context(broker())); - } else if (v8_flags.always_specialize_for_script_context && - !compilation_unit_->info()->toplevel_is_osr() && - compilation_unit_->info()->specialization_context_distance() == - 0) { - if (compiler::OptionalContextRef outer = - compilation_unit_->info()->specialization_context()) { - context = GetConstant(*outer); - } } } @@ -1102,11 +1100,17 @@ MaglevGraphBuilder::GetDeoptFrameForLazyDeopt(bool can_throw) { } else { std::tie(result_location, result_size) = GetResultLocationAndSize(); } - return std::make_tuple( - GetDeoptFrameForLazyDeoptHelper(result_location, result_size, - reducer_.current_lazy_deopt_scope(), - false, can_throw), - result_location, result_size); + DeoptFrame* top_frame = GetDeoptFrameForLazyDeoptHelper( + result_location, result_size, reducer_.current_lazy_deopt_scope(), false, + can_throw); + if (top_frame->type() != DeoptFrame::FrameType::kInterpretedFrame) { + // Deopt continuation builtins don't consider the result location or size + // encoded in the deopt data; they behave like function calls and return + // into the accumulator. + return std::make_tuple(top_frame, + interpreter::Register::virtual_accumulator(), 1); + } + return std::make_tuple(top_frame, result_location, result_size); } void MaglevGraphBuilder::AddDeoptUseToScopeData( @@ -1783,7 +1787,11 @@ bool IsConsString(ValueNode* string) { uint32_t MaglevGraphBuilder::StringLengthStaticLowerBound(ValueNode* string, int max_depth) { - if (auto maybe_constant = TryGetConstant<String>(string)) { + string = string->UnwrapIdentities(); + // Only use static constant nodes, not path-sensitive KnownNodeAspects + // `checked_value` alternatives (`TryGetConstant<String>`), as the bound is + // cached on `StringConcat` nodes across control-flow merges. + if (auto maybe_constant = string->TryGetConstant(broker())) { if (maybe_constant->IsString()) { return maybe_constant->AsString().length(); } @@ -1793,6 +1801,9 @@ uint32_t MaglevGraphBuilder::StringLengthStaticLowerBound(ValueNode* string, } switch (string->opcode()) { case Opcode::kNumberToString: + case Opcode::kInt32ToString: + case Opcode::kFloat64ToString: + case Opcode::kSmiToString: return 1; case Opcode::kStringConcat: if (max_depth == 0) return 0; @@ -2635,47 +2646,12 @@ ReduceResult MaglevGraphBuilder::VisitLdaConstant() { SetAccumulator(GetConstant(GetRefOperand<HeapObject>(0))); return ReduceResult::Done(); } -MaybeReduceResult -MaglevGraphBuilder::TrySpecializeLoadContextSlotToFunctionContext( - ValueNode* context, int slot_index, VariableMode mode, - MaybeAssignedFlag assigned) { - if (assigned == kMaybeAssigned) return {}; - - auto context_ref = TryGetConstant<Context>(context); - if (!context_ref) return {}; - - compiler::OptionalObjectRef maybe_slot_value = - context_ref->get(broker(), slot_index); - if (!maybe_slot_value.has_value()) return {}; - - compiler::ObjectRef slot_value = maybe_slot_value.value(); - if (slot_value.IsHeapObject()) { - // Even though the context slot is immutable, the context might have escaped - // before the function to which it belongs has initialized the slot. We - // must be conservative and check if the value in the slot is currently the - // hole or undefined. Only if it is neither of these, can we be sure that it - // won't change anymore. - // - // See also: JSContextSpecialization::ReduceJSLoadContext. - if (slot_value.IsTdzHole()) return {}; - if (mode == VariableMode::kVar && slot_value.IsUndefined()) return {}; - if (IsPrivateMethodOrAccessorVariableMode(mode) && - slot_value.IsUndefined()) { - return {}; - } - } - - // Fold the load of the immutable slot. - - return GetConstant(slot_value); -} - ValueNode* MaglevGraphBuilder::TrySpecializeLoadContextCell( ValueNode* context_node, int index, MaybeAssignedFlag assigned) { - if (!context_node->Is<HeapConstant>()) return {}; - compiler::ContextRef context = - context_node->Cast<HeapConstant>()->ref().AsContext(); - auto maybe_value = context.get(broker(), index); + auto context = TryGetConstant<Context>(context_node); + if (!context) return {}; + DCHECK(context->scope_info(broker()).HasContextCells()); + auto maybe_value = context->get(broker(), index); if (!maybe_value || maybe_value->IsTdzHole() || maybe_value->IsUndefinedContextCell()) { return {}; @@ -2689,12 +2665,9 @@ ValueNode* MaglevGraphBuilder::TrySpecializeLoadContextCell( compiler::ContextCellRef slot_ref = maybe_value->AsContextCell(); ContextCell::State state = slot_ref.state(); switch (state) { - case ContextCell::kConst: { - auto constant = slot_ref.tagged_value(broker()); - if (!constant.has_value()) return {}; - broker()->dependencies()->DependOnContextCell(slot_ref, state); - return GetConstant(*constant); - } + case ContextCell::kConst: + // Handled by TryGetConstantContextValue. + return {}; case ContextCell::kSmi: { DCHECK_EQ(assigned, kMaybeAssigned); broker()->dependencies()->DependOnContextCell(slot_ref, state); @@ -2732,13 +2705,15 @@ bool HasContextCell(ContextMode context_mode, MaybeAssignedFlag assigned) { ReduceResult MaglevGraphBuilder::LoadAndCacheContextSlot( ValueNode* context, int index, ContextMode context_mode, compiler::ScopeInfoRef scope_info) { + DCHECK_IMPLIES(context_mode == ContextMode::kHasContextCells, + scope_info.HasContextCells()); VariableMode mode; MaybeAssignedFlag assigned = reducer_.GetContextMaybeAssigned(scope_info, index, &mode); - RETURN_IF_DONE(TrySpecializeLoadContextSlotToFunctionContext(context, index, - mode, assigned)); - if (mode == VariableMode::kVar) assigned = kMaybeAssigned; int offset = Context::OffsetOfElementAt(index); + RETURN_IF_DONE( + reducer_.TryGetConstantContextValue(context, offset, assigned, mode)); + if (mode == VariableMode::kVar) assigned = kMaybeAssigned; ValueNode*& cached_value = known_node_aspects().GetContextCachedValue(context, offset, assigned); @@ -2773,7 +2748,6 @@ bool MaglevGraphBuilder::ContextMayAlias( MaybeReduceResult MaglevGraphBuilder::TrySpecializeStoreContextCell( ValueNode* context, int index, ValueNode* value, MaybeAssignedFlag assigned) { - DCHECK(v8_flags.script_context_cells || v8_flags.function_context_cells); if (!context->Is<HeapConstant>()) { DCHECK_EQ(assigned, kMaybeAssigned); return AddNewNode<StoreContextSlotWithWriteBarrier>({context, value}, @@ -2786,6 +2760,7 @@ MaybeReduceResult MaglevGraphBuilder::TrySpecializeStoreContextCell( compiler::ContextRef context_ref = context->Cast<HeapConstant>()->ref().AsContext(); + DCHECK(context_ref.scope_info(broker()).HasContextCells()); auto maybe_value = context_ref.get(broker(), index); if (!maybe_value || maybe_value->IsTdzHole() || maybe_value->IsUndefinedContextCell()) { @@ -2850,6 +2825,8 @@ MaybeReduceResult MaglevGraphBuilder::TrySpecializeStoreContextCell( ReduceResult MaglevGraphBuilder::StoreAndCacheContextSlot( ValueNode* context, int index, ValueNode* value, ContextMode context_mode, compiler::ScopeInfoRef scope_info) { + DCHECK_IMPLIES(context_mode == ContextMode::kHasContextCells, + scope_info.HasContextCells()); VariableMode mode; MaybeAssignedFlag maybe_assigned = reducer_.GetContextMaybeAssigned(scope_info, index, &mode); @@ -2971,9 +2948,9 @@ ReduceResult MaglevGraphBuilder::VisitLdaCurrentContextSlotNoCell() { ValueNode* context = GetContext(); int slot_index = iterator_.GetContextSlotOperand(0); ValueNode* value; - GET_VALUE(value, LoadAndCacheContextSlot(context, slot_index, - ContextMode::kNoContextCells, - GetCurrentScopeInfo())); + GET_VALUE(value, BuildLoadContextSlot(context, 0, slot_index, + ContextMode::kNoContextCells, + GetCurrentScopeInfo())); SetAccumulator(value); return ReduceResult::Done(); @@ -2982,9 +2959,9 @@ ReduceResult MaglevGraphBuilder::VisitLdaCurrentContextSlot() { ValueNode* context = GetContext(); int slot_index = iterator_.GetContextSlotOperand(0); ValueNode* value; - GET_VALUE(value, LoadAndCacheContextSlot(context, slot_index, - ContextMode::kHasContextCells, - GetCurrentScopeInfo())); + GET_VALUE(value, BuildLoadContextSlot(context, 0, slot_index, + ContextMode::kHasContextCells, + GetCurrentScopeInfo())); SetAccumulator(value); return ReduceResult::Done(); @@ -2993,9 +2970,9 @@ ReduceResult MaglevGraphBuilder::VisitLdaImmutableCurrentContextSlot() { ValueNode* context = GetContext(); int slot_index = iterator_.GetContextSlotOperand(0); ValueNode* value; - GET_VALUE(value, LoadAndCacheContextSlot(context, slot_index, - ContextMode::kNoContextCells, - GetCurrentScopeInfo())); + GET_VALUE(value, BuildLoadContextSlot(context, 0, slot_index, + ContextMode::kNoContextCells, + GetCurrentScopeInfo())); SetAccumulator(value); return ReduceResult::Done(); @@ -3013,9 +2990,9 @@ ReduceResult MaglevGraphBuilder::VisitStaContextSlotNoCell() { ReduceResult MaglevGraphBuilder::VisitStaCurrentContextSlotNoCell() { ValueNode* context = GetContext(); int slot_index = iterator_.GetContextSlotOperand(0); - return StoreAndCacheContextSlot(context, slot_index, GetAccumulator(), - ContextMode::kNoContextCells, - GetCurrentScopeInfo()); + return BuildStoreContextSlot(context, 0, slot_index, GetAccumulator(), + ContextMode::kNoContextCells, + GetCurrentScopeInfo()); } ReduceResult MaglevGraphBuilder::VisitStaContextSlot() { @@ -3031,9 +3008,9 @@ ReduceResult MaglevGraphBuilder::VisitStaContextSlot() { ReduceResult MaglevGraphBuilder::VisitStaCurrentContextSlot() { ValueNode* context = GetContext(); int slot_index = iterator_.GetContextSlotOperand(0); - return StoreAndCacheContextSlot(context, slot_index, GetAccumulator(), - ContextMode::kHasContextCells, - GetCurrentScopeInfo()); + return BuildStoreContextSlot(context, 0, slot_index, GetAccumulator(), + ContextMode::kHasContextCells, + GetCurrentScopeInfo()); } ReduceResult MaglevGraphBuilder::VisitStar() { @@ -3213,24 +3190,25 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildScriptContextStore( const compiler::GlobalAccessFeedback& global_access_feedback) { DCHECK(global_access_feedback.IsScriptContextSlot()); if (global_access_feedback.immutable()) return {}; - auto script_context = GetConstant(global_access_feedback.script_context()); + auto script_context_ref = global_access_feedback.script_context(); + auto script_context = GetConstant(script_context_ref); + compiler::ScopeInfoRef scope_info = script_context_ref.scope_info(broker()); return StoreAndCacheContextSlot( script_context, global_access_feedback.slot_index(), GetAccumulator(), - ContextMode::kHasContextCells, - global_access_feedback.script_context().scope_info(broker())); + scope_info.HasContextCells() ? ContextMode::kHasContextCells + : ContextMode::kNoContextCells, + scope_info); } MaybeReduceResult MaglevGraphBuilder::TryBuildPropertyCellStore( - const compiler::GlobalAccessFeedback& global_access_feedback) { - DCHECK(global_access_feedback.IsPropertyCell()); - - compiler::PropertyCellRef property_cell = - global_access_feedback.property_cell(); + compiler::PropertyCellRef property_cell, + base::FunctionRef<ReduceResult()> check_maps) { if (!property_cell.Cache(broker())) return {}; compiler::ObjectRef property_cell_value = property_cell.value(broker()); if (property_cell_value.IsPropertyCellHole()) { // The property cell is no longer valid. + RETURN_IF_ABORT(check_maps()); return reducer_.EmitUnconditionalDeopt( DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); } @@ -3250,6 +3228,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPropertyCellStore( case PropertyCellType::kUndefined: return {}; case PropertyCellType::kConstant: { + RETURN_IF_ABORT(check_maps()); // Record a code dependency on the cell, and just deoptimize if the new // value doesn't match the previous value stored inside the cell. broker()->dependencies()->DependOnGlobalProperty(property_cell); @@ -3263,6 +3242,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPropertyCellStore( !property_cell_value.AsHeapObject().map(broker()).is_stable()) { return {}; } + RETURN_IF_ABORT(check_maps()); // Record a code dependency on the cell, and just deoptimize if the new // value's type doesn't match the type of the previous value in the cell. broker()->dependencies()->DependOnGlobalProperty(property_cell); @@ -3283,6 +3263,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPropertyCellStore( StoreTaggedMode::kDefault); } case PropertyCellType::kMutable: { + RETURN_IF_ABORT(check_maps()); // Record a code dependency on the cell, and just deoptimize if the // property ever becomes read-only. broker()->dependencies()->DependOnGlobalProperty(property_cell); @@ -3302,21 +3283,22 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildScriptContextLoad( DCHECK(global_access_feedback.IsScriptContextSlot()); auto script_context_ref = global_access_feedback.script_context(); auto script_context = GetConstant(script_context_ref); + compiler::ScopeInfoRef scope_info = script_context_ref.scope_info(broker()); return LoadAndCacheContextSlot( script_context, global_access_feedback.slot_index(), - ContextMode::kHasContextCells, script_context_ref.scope_info(broker())); + scope_info.HasContextCells() ? ContextMode::kHasContextCells + : ContextMode::kNoContextCells, + scope_info); } MaybeReduceResult MaglevGraphBuilder::TryBuildPropertyCellLoad( - const compiler::GlobalAccessFeedback& global_access_feedback) { + compiler::PropertyCellRef property_cell, + base::FunctionRef<ReduceResult()> check_maps) { // TODO(leszeks): A bunch of this is copied from // js-native-context-specialization.cc -- I wonder if we can unify it // somehow. - DCHECK(global_access_feedback.IsPropertyCell()); - - compiler::PropertyCellRef property_cell = - global_access_feedback.property_cell(); if (!property_cell.Cache(broker())) return {}; + RETURN_IF_ABORT(check_maps()); compiler::ObjectRef property_cell_value = property_cell.value(broker()); if (property_cell_value.IsPropertyCellHole()) { @@ -3373,7 +3355,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildGlobalStore( if (global_access_feedback.IsScriptContextSlot()) { return TryBuildScriptContextStore(global_access_feedback); } else if (global_access_feedback.IsPropertyCell()) { - return TryBuildPropertyCellStore(global_access_feedback); + return TryBuildPropertyCellStore(global_access_feedback.property_cell()); } else { DCHECK(global_access_feedback.IsMegamorphic()); return {}; @@ -3385,7 +3367,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildGlobalLoad( if (global_access_feedback.IsScriptContextSlot()) { return TryBuildScriptContextLoad(global_access_feedback); } else if (global_access_feedback.IsPropertyCell()) { - return TryBuildPropertyCellLoad(global_access_feedback); + return TryBuildPropertyCellLoad(global_access_feedback.property_cell()); } else { DCHECK(global_access_feedback.IsMegamorphic()); return {}; @@ -3999,9 +3981,8 @@ MaglevGraphBuilder::TryBuildLoadTaggedFieldFromAllocation(ValueNode* object, MaybeReduceResult MaglevGraphBuilder::TryBuildLoadFixedDoubleArrayElementFromAllocation( ValueNode* elements, int index) { - if (index < 0 || static_cast<uint32_t>(index) >= FixedArray::kMaxLength) { - return reducer_.BuildAbort(AbortReason::kUnreachable); - } + RETURN_IF_ABORT( + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(index)); if (!CanTrackObjectChanges(elements, TrackObjectMode::kLoad)) { return {}; } @@ -4082,8 +4063,19 @@ ReduceResult MaglevGraphBuilder::BuildLoadFixedArrayElement(ValueNode* elements, return AddNewNode<LoadFixedArrayElement>({elements, index}, type); } +// The argument forwarding fast paths in TryGetNonEscapingArgumentsOrArray copy +// the caller's stack frame rather than the heap backing store, so they must be +// disabled once we store into that backing store. +void MaglevGraphBuilder::MarkArgumentsElementsMaybeMutated( + ValueNode* elements) { + if (auto* arguments_elements = elements->TryCast<ArgumentsElements>()) { + arguments_elements->set_maybe_mutated(); + } +} + ReduceResult MaglevGraphBuilder::BuildStoreFixedArrayElement( ValueNode* elements, ValueNode* index, ValueNode* value) { + MarkArgumentsElementsMaybeMutated(elements); // TODO(victorgomes): Support storing element to a virtual object. If we // modify the elements array, we need to modify the original object to point // to the new elements array. @@ -4093,6 +4085,8 @@ ReduceResult MaglevGraphBuilder::BuildStoreFixedArrayElement( // test/mjsunit/maglev/regress-538884561-2.js. ABORT_IF_EMPTY_TYPE(value); + RETURN_IF_ABORT(reducer_.AbortIfInvalidFixedArrayIndex<FixedArray>(index)); + if (CanElideWriteBarrier(elements, value)) { return AddNewNode<StoreFixedArrayElementNoWriteBarrier>( {elements, index, value}); @@ -4105,8 +4099,11 @@ ReduceResult MaglevGraphBuilder::BuildStoreFixedArrayElement( ReduceResult MaglevGraphBuilder::BuildStoreFixedDoubleArrayElement( ElementsKind elements_kind, ValueNode* elements, ValueNode* index, ValueNode* value) { + MarkArgumentsElementsMaybeMutated(elements); // TODO(victorgomes): Support storing double element to a virtual object. DCHECK(value->is_float64_or_holey_float64()); + RETURN_IF_ABORT( + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(index)); if (value->is_holey_float64()) { if (value->MayBeHoleOrUndefinedNan()) { // The value can be undefined. Both NaN patterns mean undefined here, but @@ -4127,6 +4124,8 @@ ReduceResult MaglevGraphBuilder::BuildStoreFixedDoubleArrayElement( ReduceResult MaglevGraphBuilder::BuildLoadHoleyFixedDoubleArrayElement( ValueNode* elements, ValueNode* index, bool convert_hole) { + RETURN_IF_ABORT( + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(index)); ValueNode* load; GET_VALUE_OR_ABORT( load, AddNewNode<LoadHoleyFixedDoubleArrayElement>({elements, index})); @@ -4261,10 +4260,10 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPropertySetterCall( } namespace { -bool AccessInfoGuaranteedConst( +PropertyConstness AccessInfoGuaranteedConst( compiler::PropertyAccessInfo const& access_info) { if (!access_info.IsFastDataConstant() && !access_info.IsStringLength()) { - return false; + return PropertyConstness::kMutable; } // Even if we have a constant load, if the map is not stable, we cannot @@ -4274,10 +4273,10 @@ bool AccessInfoGuaranteedConst( // dependency on the stable end-maps of the entire tree. for (auto& map : access_info.lookup_start_object_maps()) { if (!map.is_stable()) { - return false; + return PropertyConstness::kMutable; } } - return true; + return PropertyConstness::kConst; } } // namespace @@ -4333,11 +4332,12 @@ ReduceResult MaglevGraphBuilder::BuildLoadField( // Do the load. if (field_index.is_double()) { ValueNode* heap_number; - GET_VALUE_OR_ABORT(heap_number, - AddNewNode<LoadTaggedField>( - {load_source}, field_index.offset(), - NodeType::kHeapNumber, false, PropertyKey::None(), - IsArrayLength::kNo, compiler::OptionalMapRef{})); + GET_VALUE_OR_ABORT( + heap_number, + AddNewNode<LoadTaggedField>( + {load_source}, field_index.offset(), NodeType::kHeapNumber, + PropertyConstness::kMutable, PropertyKey::None(), + IsArrayLength::kNo, compiler::OptionalMapRef{})); return AddNewNode<LoadFloat64>( {heap_number}, static_cast<int>(offsetof(HeapNumber, value_))); } @@ -4410,7 +4410,8 @@ ReduceResult MaglevGraphBuilder::BuildLoadJSFunctionFeedbackCell( // The feedback cell is only set when the JSFunction is allocated, or via // LiveEdit, but that doesn't concern optimized code, so treat it as const. return BuildLoadTaggedField(closure, offsetof(JSFunction, feedback_cell_), - NodeType::kAnyHeapObject, true); + NodeType::kAnyHeapObject, + PropertyConstness::kConst); } ReduceResult MaglevGraphBuilder::BuildLoadJSFunctionContext( @@ -4426,7 +4427,7 @@ ReduceResult MaglevGraphBuilder::BuildLoadJSFunctionContext( return slow_closure->ContextInput().node(); } return BuildLoadTaggedField(closure, offsetof(JSFunction, context_), - NodeType::kContext); + NodeType::kContext, PropertyConstness::kConst); } ReduceResult MaglevGraphBuilder::BuildExtendPropertiesBackingStore( @@ -4480,16 +4481,16 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildStoreField( ValueNode* value = GetAccumulator(); if (field_representation.IsSmi()) { RETURN_IF_ABORT(GetAccumulatorSmi(UseReprHintRecording::kDoNotRecord)); - } else { - if (field_representation.IsHeapObject()) { - // Emit a map check for the field type, if needed, otherwise just a - // HeapObject check. - if (access_info.field_map().has_value()) { - RETURN_IF_ABORT(BuildCheckMaps( - value, base::VectorOf({access_info.field_map().value()}))); - } else { - RETURN_IF_ABORT(BuildCheckHeapObject(value)); - } + } else if (field_representation.IsDouble()) { + GET_VALUE_OR_ABORT(value, GetFloat64(value)); + } else if (field_representation.IsHeapObject()) { + // Emit a map check for the field type, if needed, otherwise just a + // HeapObject check. + if (access_info.field_map().has_value()) { + RETURN_IF_ABORT(BuildCheckMaps( + value, base::VectorOf({access_info.field_map().value()}))); + } else { + RETURN_IF_ABORT(BuildCheckHeapObject(value)); } } @@ -4510,14 +4511,6 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildStoreField( } if (field_representation.IsDouble()) { - if (access_info.IsFastDataConstant()) { - // Force conversion to Float64 to ensure we can check for hole NaN. - GET_VALUE_OR_ABORT(value, GetFloat64(value)); - if (value->MayBeHoleOrUndefinedNan()) { - GET_VALUE_OR_ABORT(value, - AddNewNode<Float64ToSilencedFloat64>({value})); - } - } if (access_info.HasTransitionMap()) { // Allocate the mutable double box owned by the field. ValueNode* heapnumber_value; @@ -4532,13 +4525,23 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildStoreField( StoreMap::Kind::kTransitioning); } else { ValueNode* heap_number; - GET_VALUE_OR_ABORT(heap_number, - AddNewNode<LoadTaggedField>( - {store_target}, field_index.offset(), - NodeType::kHeapNumber, false, PropertyKey::None(), - IsArrayLength::kNo, compiler::OptionalMapRef{})); - return AddNewNode<StoreFloat64>( - {heap_number, value}, static_cast<int>(offsetof(HeapNumber, value_))); + GET_VALUE_OR_ABORT( + heap_number, + AddNewNode<LoadTaggedField>( + {store_target}, field_index.offset(), NodeType::kHeapNumber, + PropertyConstness::kMutable, PropertyKey::None(), + IsArrayLength::kNo, compiler::OptionalMapRef{})); + RETURN_IF_ABORT(AddNewNode<StoreFloat64>( + {heap_number, value}, + static_cast<int>(offsetof(HeapNumber, value_)))); + if (IsDefiningStore(access_mode)) { + // Use kInitializing since transitioning an UninitializedHeapNumber to + // HeapNumber cannot invalidate any unstable maps in KnownNodeAspects. + RETURN_IF_ABORT(reducer_.BuildStoreMap(heap_number, + broker()->heap_number_map(), + StoreMap::Kind::kInitializing)); + } + return ReduceResult::Done(); } } @@ -4794,6 +4797,39 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildNamedAccess( return reducer_.EmitUnconditionalDeopt(DeoptimizeReason::kWrongMap); } + // Check if we have an access o.x or o.x=v where o is the target native + // contexts' global proxy, and turn that into a direct access to the + // corresponding global object instead. + if (inferred_maps.size() == 1) { + compiler::MapRef lookup_start_object_map = inferred_maps[0]; + compiler::NativeContextRef native_context = + broker()->target_native_context(); + if (lookup_start_object_map.equals( + native_context.global_proxy_object(broker()).map(broker()))) { + if (!native_context.GlobalIsDetached(broker())) { + compiler::OptionalPropertyCellRef cell = + native_context.global_object(broker()).GetPropertyCell( + broker(), feedback.name()); + if (!cell.has_value()) return {}; + // Note: The map check generated below ensures that we will deopt + // when/if GlobalIsDetached becomes true. + auto check_maps = [&]() { + return BuildCheckMaps(lookup_start_object, + base::VectorOf({lookup_start_object_map}), {}, + has_deprecated_map_without_migration_target); + }; + if (access_mode == compiler::AccessMode::kLoad) { + return TryBuildPropertyCellLoad(*cell, check_maps); + } else if (access_mode == compiler::AccessMode::kStore) { + DCHECK_EQ(receiver, lookup_start_object); + return TryBuildPropertyCellStore(*cell, check_maps); + } else { + return {}; + } + } + } + } + ZoneVector<compiler::PropertyAccessInfo> access_infos(zone()); ZoneVector<compiler::PropertyAccessInfo> access_infos_for_feedback(zone()); @@ -5015,8 +5051,10 @@ ReduceResult MaglevGraphBuilder::BuildLoadTypedArrayLength( ValueNode* object, ElementsKind elements_kind) { DCHECK(IsTypedArrayOrRabGsabTypedArrayElementsKind(elements_kind)); bool is_variable_length = IsRabGsabTypedArrayElementsKind(elements_kind); - bool is_const_length = - !is_variable_length && !v8_flags.track_array_buffer_views; + PropertyConstness constness = + (!is_variable_length && !v8_flags.track_array_buffer_views) + ? PropertyConstness::kConst + : PropertyConstness::kMutable; if (!is_variable_length) { if (auto const_object = TryGetConstant<JSTypedArray>(object)) { @@ -5035,7 +5073,7 @@ ReduceResult MaglevGraphBuilder::BuildLoadTypedArrayLength( // conflict with redefinitions of the TypedArray length property. if (ValueNode* length = known_node_aspects().TryFindLoadedProperty( - object, PropertyKey::TypedArrayLength(), is_const_length)) { + object, PropertyKey::TypedArrayLength(), constness)) { return length; } } @@ -5045,7 +5083,7 @@ ReduceResult MaglevGraphBuilder::BuildLoadTypedArrayLength( AddNewNode<LoadTypedArrayLength>({object}, elements_kind)); if (!is_variable_length) { reducer_.RecordKnownProperty(object, PropertyKey::TypedArrayLength(), - result, is_const_length, + result, constness, compiler::AccessMode::kLoad); } return result; @@ -5541,7 +5579,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildElementStoreOnJSArrayOrJSObject( GET_VALUE_OR_ABORT(new_length, AddNewNode<UpdateJSArrayLength>( {length, object, index})); reducer_.RecordKnownProperty(object, broker()->length_string(), - new_length, false, + new_length, PropertyConstness::kMutable, compiler::AccessMode::kStore); } } else { @@ -6093,18 +6131,12 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPolymorphicPropertyAccess( } break; case MaybeReduceResult::kFail: + CHECK(!continuation); if (!generic_access.has_value()) { // Conservatively assume that all remaining branches can go into the // generic path, as we have to initialize the predecessors upfront. // TODO(pthier): Find a better way to do that. - if (continuation) { - int future_bind_offset = iterator_.current_offset(); - generic_access.emplace( - MaglevSubGraphBuilder::LabelForTrackingInterpreterFrameState( - &sub_graph, access_info_count - i, future_bind_offset)); - } else { - generic_access.emplace(&sub_graph, access_info_count - i); - } + generic_access.emplace(&sub_graph, access_info_count - i); } sub_graph.Goto(&*generic_access); break; @@ -6124,6 +6156,7 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPolymorphicPropertyAccess( } if (generic_access.has_value()) { + CHECK(!continuation); iterator_.SetOffset(start_offset); source_position_iterator_.RestoreState( start_source_position_iterator_state); @@ -6138,27 +6171,11 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildPolymorphicPropertyAccess( DCHECK(generic_result.IsDone()); DCHECK_EQ(generic_result.IsDoneWithValue(), !is_any_store); - if (continuation) { - DCHECK(!is_any_store); - SetAccumulator(generic_result.value()); - ReduceResult continuation_result = - BuildContinuationForPolymorphicPropertyLoad(*continuation); - if (!done.has_value()) { - return current_interpreter_frame_.get( - interpreter::Register::virtual_accumulator()); - } - if (!continuation_result.IsDoneWithAbort()) { - sub_graph.set(*ret_val, - current_interpreter_frame_.get( - interpreter::Register::virtual_accumulator())); - } - } else { - if (!done.has_value()) { - return is_any_store ? ReduceResult::Done() : generic_result.value(); - } - if (!is_any_store) { - sub_graph.set(*ret_val, generic_result.value()); - } + if (!done.has_value()) { + return is_any_store ? ReduceResult::Done() : generic_result.value(); + } + if (!is_any_store) { + sub_graph.set(*ret_val, generic_result.value()); } sub_graph.Goto(&*done); } @@ -6368,6 +6385,7 @@ void MaglevGraphBuilder::AdvanceThroughContinuationForPolymorphicPropertyLoad( while (iterator_.current_offset() < continuation.last_continuation) { iterator_.Advance(); UpdateSourceAndBytecodePosition(iterator_.current_offset()); + PrewalkBytecode(); } } @@ -6442,11 +6460,47 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildProxyPropertyAccess( CallArguments args(ConvertReceiverMode::kNotNullOrUndefined, {proxy_handler, proxy_target, argument_name, receiver}); - RETURN_IF_DONE( - TryReduceCallForConstant(trap_js_function_ref, args, feedback_source)); + ValueNode* result; + { + LazyDeoptFrameScope deopt_continuation( + &reducer_, GetContext(), + Builtin::kProxyGetPropertyTrapResultLazyDeoptContinuation, {}, + base::VectorOf<ValueNode*>( + {proxy_target, lookup_start_object, argument_name})); + MaybeReduceResult call_result = + TryReduceCallForConstant(trap_js_function_ref, args, feedback_source); + if (!call_result.IsDone()) { + call_result = BuildGenericCall(actual_trap, Call::TargetType::kJSFunction, + args, feedback_source); + } + GET_VALUE_OR_ABORT(result, call_result); + } + + // 4. Verify that the proxy target map didn't change during the trap call. + const NodeInfo* target_info = + known_node_aspects().TryGetInfoWithFreshMaps(proxy_target); + if (target_info == nullptr || target_info->possible_maps().size() != 1 || + target_info->possible_maps().at(0) != expected_target_map) { + ValueNode* target_map; + GET_VALUE_OR_ABORT( + target_map, + BuildLoadTaggedField(proxy_target, offsetof(HeapObject, map_))); + return Select( + [&](BranchBuilder& builder) { + return BuildBranchIfReferenceEqual(builder, target_map, + GetConstant(expected_target_map)); + }, + [&]() -> ReduceResult { return result; }, + [&]() -> ReduceResult { + // Return the runtime call's result (which forwards `result`) so that + // a lazy deopt during the check does not overwrite the load result. + return BuildCallRuntime(Runtime::kCheckProxyGetSetTrapResult, + {argument_name, proxy_target, result, + GetSmiConstant(JSProxy::kGet)}); + }); + } - return BuildGenericCall(actual_trap, Call::TargetType::kJSFunction, args, - feedback_source); + return result; } template <typename GenericAccessFunc> @@ -6738,9 +6792,13 @@ ValueNode* MaglevGraphBuilder::GetContextAtDepth(ValueNode* context, compiler::OptionalContextRef maybe_ref = FunctionContextSpecialization::TryToRef(compilation_unit_, context, - &depth); + *scope_info, &depth); if (maybe_ref.has_value()) { context = GetConstant(maybe_ref.value()); + // `context` is now a `HeapConstant`, so any subsequent `GetContextAtDepth` + // call on `context` (e.g. in `CheckContextExtensions`) will resolve + // directly via the `HeapConstant` fast path in `TryToRef` without + // consulting `scope_info->specialization_context_distance()`. *scope_info = ContextScopeInfo(maybe_ref.value().scope_info(broker())); } @@ -6853,19 +6911,11 @@ ReduceResult MaglevGraphBuilder::VisitGetPrivateField() { ValueNode* current_context = LoadRegister(0); int slot_index = iterator_.GetContextSlotOperand(1); size_t depth = iterator_.GetUnsignedImmediateOperand(2); - - ContextScopeInfo scope_info = - register_scope_infos_[iterator_.GetRegisterOperand(0)]; - ValueNode* context = GetContextAtDepth(current_context, depth, &scope_info); - VariableMode mode; - MaybeAssignedFlag assigned = - reducer_.GetContextMaybeAssigned(scope_info, slot_index, &mode); - MaybeReduceResult name = TrySpecializeLoadContextSlotToFunctionContext( - context, slot_index, mode, assigned); - if (!name.HasValue()) { - name = LoadAndCacheContextSlot(context, slot_index, - ContextMode::kNoContextCells, scope_info); - } + ValueNode* name; + GET_VALUE(name, BuildLoadContextSlot( + current_context, depth, slot_index, + ContextMode::kNoContextCells, + register_scope_infos_[iterator_.GetRegisterOperand(0)])); ValueNode* object = LoadRegister(3); FeedbackSlot slot = GetSlotOperand(4); @@ -6877,7 +6927,7 @@ ReduceResult MaglevGraphBuilder::VisitGetPrivateField() { auto build_generic_access = [this, object, name, &feedback_source]() { ValueNode* current_context = GetContext(); - return AddNewNode<GetKeyedGeneric>({current_context, object, name.value()}, + return AddNewNode<GetKeyedGeneric>({current_context, object, name}, feedback_source); }; @@ -6888,8 +6938,7 @@ ReduceResult MaglevGraphBuilder::VisitGetPrivateField() { case compiler::ProcessedFeedback::kNamedAccess: { RETURN_IF_ABORT(BuildCheckInternalizedStringValueOrByReference( - name.value(), - processed_feedback.AsNamedAccess().name(), + name, processed_feedback.AsNamedAccess().name(), DeoptimizeReason::kKeyedAccessChanged)); compiler::NameRef name_ref = processed_feedback.AsNamedAccess().name(); @@ -6913,19 +6962,11 @@ ReduceResult MaglevGraphBuilder::VisitSetPrivateField() { ValueNode* current_context = LoadRegister(0); int slot_index = iterator_.GetContextSlotOperand(1); size_t depth = iterator_.GetUnsignedImmediateOperand(2); - - ContextScopeInfo scope_info = - register_scope_infos_[iterator_.GetRegisterOperand(0)]; - ValueNode* context = GetContextAtDepth(current_context, depth, &scope_info); - VariableMode mode; - MaybeAssignedFlag assigned = - reducer_.GetContextMaybeAssigned(scope_info, slot_index, &mode); - MaybeReduceResult name = TrySpecializeLoadContextSlotToFunctionContext( - context, slot_index, mode, assigned); - if (!name.HasValue()) { - name = LoadAndCacheContextSlot(context, slot_index, - ContextMode::kNoContextCells, scope_info); - } + ValueNode* name; + GET_VALUE(name, BuildLoadContextSlot( + current_context, depth, slot_index, + ContextMode::kNoContextCells, + register_scope_infos_[iterator_.GetRegisterOperand(0)])); ValueNode* object = LoadRegister(3); FeedbackSlot slot = GetSlotOperand(4); @@ -6938,13 +6979,13 @@ ReduceResult MaglevGraphBuilder::VisitSetPrivateField() { auto build_generic_access = [this, object, name, &feedback_source]() { ValueNode* context = GetContext(); ValueNode* value = GetAccumulator(); - return AddNewNode<SetKeyedGeneric>({context, object, name.value(), value}, + return AddNewNode<SetKeyedGeneric>({context, object, name, value}, feedback_source); }; - return BuildSetKeyedProperty(object, name.value(), - compiler::AccessMode::kStore, feedback_source, - processed_feedback, build_generic_access); + return BuildSetKeyedProperty(object, name, compiler::AccessMode::kStore, + feedback_source, processed_feedback, + build_generic_access); } ReduceResult MaglevGraphBuilder::VisitSetPrototypeProperties() { @@ -7605,6 +7646,7 @@ ReduceResult MaglevGraphBuilder::BuildInlineFunction( bool MaglevGraphBuilder::IsFunctionCandidateForEagerInlining( compiler::SharedFunctionInfoRef shared, CallArguments& args) { + if (V8_UNLIKELY(shared.is_eager_inlining_disabled(broker()))) return false; compiler::BytecodeArrayRef bytecode = shared.GetBytecodeArray(broker()); if (bytecode.length() < flags_.max_eager_inlined_bytecode) { TRACE_INLINING(TraceInlineEager(shared) @@ -7728,6 +7770,10 @@ MaybeReduceResult MaglevGraphBuilder::TryBuildInlineCall( } if (!flags_.is_non_eager_inlining_enabled) { + if (V8_UNLIKELY(shared.is_eager_inlining_disabled(broker()))) { + TRACE_CANNOT_INLINE("eager inlining is disabled"); + return {}; + } if (graph()->total_inlined_bytecode_size() >= flags_.max_inlined_bytecode_size_cumulative) { compilation_unit_->info()->set_could_not_inline_all_candidates(); @@ -7799,7 +7845,7 @@ ReduceResult MaglevGraphBuilder::BuildEagerInlineCall( // Create a new compilation unit. MaglevCompilationUnit* inner_unit = MaglevCompilationUnit::NewInner( - zone(), compilation_unit_, shared, feedback_cell); + zone(), compilation_unit_, shared, feedback_cell, context, function); DeoptFrame* deopt_frame = GetDeoptFrameForEagerCall(inner_unit, function, arguments_vector); @@ -8144,9 +8190,9 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceArrayIteratingBuiltin( } } // Reset the cached loaded array length to the length var. - reducer_.RecordKnownProperty(receiver, broker()->length_string(), - sub_builder.get(var_length), false, - compiler::AccessMode::kLoad); + reducer_.RecordKnownProperty( + receiver, broker()->length_string(), sub_builder.get(var_length), + PropertyConstness::kMutable, compiler::AccessMode::kLoad); // ``` // if (index_int32 < length_int32) @@ -10339,7 +10385,7 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceArrayPrototypePush( sub_graph.Bind(&*do_return); } reducer_.RecordKnownProperty(receiver, broker()->length_string(), - new_array_length, false, + new_array_length, PropertyConstness::kMutable, compiler::AccessMode::kStore); return new_array_length; } @@ -10499,9 +10545,9 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceArrayPrototypePop( sub_graph.Goto(&*do_return); sub_graph.Bind(&*do_return); - reducer_.RecordKnownProperty(receiver, broker()->length_string(), - sub_graph.get(var_new_array_length), false, - compiler::AccessMode::kStore); + reducer_.RecordKnownProperty( + receiver, broker()->length_string(), sub_graph.get(var_new_array_length), + PropertyConstness::kMutable, compiler::AccessMode::kStore); return sub_graph.get(var_value); } @@ -11349,7 +11395,7 @@ ReduceResult MaglevGraphBuilder::BuildCheckNumericalValue( return reducer_.EmitUnconditionalDeopt(reason); } - if (NodeTypeIs(GetType(node), NodeType::kAnyHeapObject)) { + if (!NodeTypeCanBe(GetType(node), NodeType::kSmi)) { return reducer_.EmitUnconditionalDeopt(reason); } RETURN_IF_ABORT( @@ -11373,7 +11419,7 @@ ReduceResult MaglevGraphBuilder::BuildCheckNumericalValue( return reducer_.EmitUnconditionalDeopt(reason); } - if (!NodeTypeIs(NodeType::kNumber, GetType(node))) { + if (!NodeTypeCanBe(GetType(node), NodeType::kHeapNumber)) { return reducer_.EmitUnconditionalDeopt(reason); } RETURN_IF_ABORT( @@ -11627,11 +11673,6 @@ ReduceResult MaglevGraphBuilder::BuildCallWithFeedback( } ValueNode* context; GET_VALUE_OR_ABORT(context, BuildLoadJSFunctionContext(target_node)); - compiler::ScopeInfoRef scope_info = shared->scope_info(broker()); - if (scope_info.HasOuterScopeInfo()) { - scope_info = scope_info.OuterScopeInfo(broker()); - CHECK(scope_info.HasContext()); - } PROCESS_AND_RETURN_IF_DONE( TryBuildCallKnownJSFunction( context, target_node, @@ -11946,31 +11987,55 @@ MaglevGraphBuilder::TryGetNonEscapingArgumentsOrArray(ValueNode* value) { return {}; } compiler::MapRef map = *object->map(); - if (map.IsJSArrayMap()) { - if (!map.supports_fast_array_iteration(broker())) { + // TODO(victorgomes): We can loosen the IsSloppyMappedArgumentsObject + // requirement if there are no stores to the mapped arguments. + const bool is_unmapped_arguments = + map.IsJSArgumentsObjectMap() && + !IsSloppyMappedArgumentsObject(broker(), map); + if (!map.IsJSArrayMap() && !is_unmapped_arguments) { + return {}; + } + + ValueNode* elements = object->get(offsetof(JSObject, elements_)); + if (auto* arguments_elements = elements->TryCast<ArgumentsElements>()) { + if (ArgumentsElementsMaybeMutated(alloc, arguments_elements)) { return {}; } - ValueNode* elements = object->get(offsetof(JSObject, elements_)); - // Object is the rest parameter. - if (elements->Is<ArgumentsElements>()) { - return object; - } - if (try_get_non_escaping_alloc(elements)) { - return object; - } - if (elements->Is<RootConstant>() || elements->Is<HeapConstant>()) { - return object; - } } - // TODO(victorgomes): We can loosen the IsSloppyMappedArgumentsObject - // requirement if there is no stores to the mapped arguments. - if (map.IsJSArgumentsObjectMap() && - !IsSloppyMappedArgumentsObject(broker(), map)) { + + if (is_unmapped_arguments) { + return object; + } + if (!map.supports_fast_array_iteration(broker())) { + return {}; + } + // Object is the rest parameter. + if (elements->Is<ArgumentsElements>()) { + return object; + } + if (try_get_non_escaping_alloc(elements)) { + return object; + } + if (elements->Is<RootConstant>() || elements->Is<HeapConstant>()) { return object; } return {}; } +bool MaglevGraphBuilder::ArgumentsElementsMaybeMutated( + InlinedAllocation* allocation, ArgumentsElements* elements) { + // Argument forwarding reads the caller's stack rather than this backing + // store. The mutation mark only covers stores emitted so far. + // A store later in bytecode order can only be observed here inside a loop. + // The allocation must then have been created since the loop header. + DCHECK(!IsInsideLoop() || (is_loop_effect_tracking() && + loop_effects_->allocations.contains(allocation))); + // A store in a callee inlined after graph building requires passing the + // allocation to the pending call, making it escape here. + DCHECK(!IsEscaping(allocation)); + return elements->maybe_mutated(); +} + ReduceResult MaglevGraphBuilder::ReduceCallWithArrayLike( ValueNode* target_node, CallArguments& args, const compiler::FeedbackSource& feedback_source) { @@ -12045,6 +12110,10 @@ MaybeReduceResult MaglevGraphBuilder::TryReduceCallWithSpreadForArgumentsObject( ReduceResult MaglevGraphBuilder::ReduceCall( ValueNode* target_node, CallArguments& args, const compiler::FeedbackSource& feedback_source) { + if (broker()->StackHasOverflowed()) { + return BuildGenericCall(target_node, Call::TargetType::kAny, args, + feedback_source); + } if (args.mode() == CallArguments::kWithArrayLike) { return ReduceCallWithArrayLike(target_node, args, feedback_source); } @@ -12494,7 +12563,7 @@ ReduceResult MaglevGraphBuilder::VisitIntrinsicAsyncFunctionAwait( RETURN_IF_ABORT(BuildStoreTaggedFieldNoWriteBarrier( value, GetSmiConstant(static_cast<int>(Promise::kFulfilled) | - JSPromise::HasHandlerBit::kMask), + JSPromise::Flags::HasHandlerBit::kMask), offsetof(JSPromise, flags_), StoreTaggedMode::kDefault)); VirtualObject* task = reducer_.CreateAsyncResumeTask( @@ -13990,10 +14059,15 @@ MaglevGraphBuilder::TryReadBoilerplateForFastLiteral( if (!maybe_object_value.has_value()) return {}; fast_literal->set(offset, maybe_object_value.value()); } else if (property_details.representation().IsDouble()) { - fast_literal->set( - offset, - reducer_.CreateHeapNumber(GetFloat64Constant(Float64::FromBits( - boilerplate_value.AsHeapNumber().value_as_bits())))); + if (boilerplate_value.IsHeapNumber()) { + fast_literal->set( + offset, + reducer_.CreateHeapNumber(GetFloat64Constant(Float64::FromBits( + boilerplate_value.AsHeapNumber().value_as_bits())))); + } else { + DCHECK(boilerplate_value.IsUninitializedHeapNumber()); + fast_literal->set(offset, reducer_.CreateUninitializedHeapNumber()); + } } else { fast_literal->set(offset, GetConstant(boilerplate_value)); } @@ -14371,12 +14445,12 @@ ReduceResult MaglevGraphBuilder::VisitCreateClosure() { if (interpreter::CreateClosureFlags::FastNewClosureBit::decode(flags)) { return SetAccumulator(AddNewNode<FastCreateClosure>( - {GetContext()}, shared_function_info, feedback_cell)); + {GetContext()}, shared_function_info, feedback_cell, + compilation_unit_->specialization_context(), GetCurrentScopeInfo())); } else { - bool pretenured = - interpreter::CreateClosureFlags::PretenuredBit::decode(flags); return SetAccumulator(AddNewNode<CreateClosure>( - {GetContext()}, shared_function_info, feedback_cell, pretenured)); + {GetContext()}, shared_function_info, feedback_cell, + compilation_unit_->specialization_context(), GetCurrentScopeInfo())); } } @@ -14844,6 +14918,9 @@ void MaglevGraphBuilder::MergeIntoFrameState(BasicBlock* predecessor, } else { // If there already is a frame state, merge. + DCHECK_IMPLIES( + merge_states_[target]->has_context_scope_info(), + merge_states_[target]->context_scope_info() == GetCurrentScopeInfo()); merge_states_[target]->Merge(graph(), is_tracing(), *compilation_unit(), current_interpreter_frame_, predecessor, GetCurrentScopeInfo()); @@ -14851,14 +14928,11 @@ void MaglevGraphBuilder::MergeIntoFrameState(BasicBlock* predecessor, } void MaglevGraphBuilder::SetCurrentScopeInfo(ContextScopeInfo scope_info) { + DCHECK(scope_info.has_value()); if (v8_flags.trace_maglev_scope_info) { int offset = iterator_.done() ? -1 : iterator_.current_offset(); - if (scope_info.has_value()) { - TRACE(" [ScopeInfo] Activated " << scope_info.value() << " at offset " - << offset); - } else { - TRACE(" [ScopeInfo] Activated <empty> at offset " << offset); - } + TRACE(" [ScopeInfo] Activated " << scope_info.value() << " at offset " + << offset); } register_scope_infos_[interpreter::Register::current_context()] = scope_info; } @@ -14888,7 +14962,19 @@ void MaglevGraphBuilder::MergeDeadIntoFrameState(int target, << iterator_.current_offset()); } dead_scope_infos_.insert({target, GetCurrentScopeInfo()}); + } else { + // When inlining a generator, VisitSwitchOnGeneratorState marks all + // ResumeGenerator targets dead from offset 0 (before + // CreateFunctionContext or inner scopes), which can disagree with + // dead jumps after ResumeGenerator. + DCHECK_IMPLIES(!is_inline(), jump_it->second == GetCurrentScopeInfo()); } + } else if (merge_state->has_context_scope_info()) { + // At inline_exit_offset() (or after dead ResumeGenerator targets in + // inlined generators), dead returns from different inner scopes can merge + // with different ScopeInfos. + DCHECK_IMPLIES(!is_inline(), merge_state->context_scope_info() == + GetCurrentScopeInfo()); } } // If there is no merge state yet, don't create one, but just reduce the @@ -15122,8 +15208,8 @@ MaglevGraphBuilder::BranchResult MaglevGraphBuilder::BuildBranchIfRootConstant( if (node->Cast<Int32ToBoolean>()->flip()) { builder.SwapTargets(); } - return builder.template Build<BranchIfInt32ToBooleanTrue>( - {node->Cast<Int32ToBoolean>()->ValueInput().node()}); + return reducer_.BuildBranchIfInt32ToBooleanTrue( + builder, node->Cast<Int32ToBoolean>()->ValueInput().node()); case Opcode::kIntPtrToBoolean: if (node->Cast<IntPtrToBoolean>()->flip()) { builder.SwapTargets(); @@ -16420,30 +16506,14 @@ DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK) ReduceResult MaglevGraphBuilder::VisitIllegal() { UNREACHABLE(); } void MaglevGraphBuilder::InitializeScopeInfo() { - compiler::ScopeInfoRef scope_info = - compilation_unit_->shared_function_info().scope_info(broker()); - bool has_incoming_context_scope = false; - if (scope_info.HasOuterScopeInfo()) { - scope_info = scope_info.OuterScopeInfo(broker()); - CHECK(scope_info.HasContext()); - has_incoming_context_scope = true; - } else if (compilation_unit_->shared_function_info().is_toplevel() && - scope_info.HasContext()) { - has_incoming_context_scope = true; - } - std::optional<size_t> distance; - if (!is_inline() && has_incoming_context_scope && - compilation_unit_->info()->specialization_context().has_value()) { - distance = compilation_unit_->info()->specialization_context_distance(); - } - SetCurrentScopeInfo(ContextScopeInfo(scope_info, distance)); + SetCurrentScopeInfo(compilation_unit_->incoming_context_scope_info()); } bool MaglevGraphBuilder::Build() { DCHECK(!is_inline()); if (should_abort_compilation_) return false; - compilation_unit_->info()->InitializeSpecializationContext(); + compilation_unit_->InitializeSpecializationContextForTopLevel(); DCHECK_EQ(inlining_id_, SourcePosition::kNotInlined); reducer_.SetBytecodeOffset(entrypoint_); @@ -16558,6 +16628,7 @@ void MaglevGraphBuilder::PrewalkBytecode() { } void MaglevGraphBuilder::OsrPrewalk() { + if (!compilation_unit_->is_osr()) return; // Single forward pass reconstructing the context scope at each // reachable offset before the entrypoint. const int bytecode_length = bytecode().length(); @@ -16959,6 +17030,9 @@ void MaglevGraphBuilder::ProcessMergePoint(int offset, if (merge_state.is_loop() && !merge_state.has_context_scope_info()) { merge_state.set_context_scope_info(GetCurrentScopeInfo()); } + DCHECK_IMPLIES( + iterator_.current_bytecode() == interpreter::Bytecode::kResumeGenerator, + merge_state.context_scope_info() == GetCurrentScopeInfo()); current_interpreter_frame_.CopyFrom(*compilation_unit_, merge_state, preserve_known_node_aspects, zone()); SetCurrentScopeInfo(merge_state.context_scope_info()); diff --git a/deps/v8/src/maglev/maglev-graph-builder.h b/deps/v8/src/maglev/maglev-graph-builder.h index a439094bb6d8..7ddf07106252 100644 --- a/deps/v8/src/maglev/maglev-graph-builder.h +++ b/deps/v8/src/maglev/maglev-graph-builder.h @@ -178,7 +178,7 @@ class MaglevGraphBuilder { return graph()->GetConstant(ref); } ValueNode* GetTrustedConstant(compiler::HeapObjectRef ref, - IndirectPointerTag tag) { + TrustedPointerTag tag) { return graph()->GetTrustedConstant(ref, tag); } @@ -463,9 +463,6 @@ class MaglevGraphBuilder { bool ContextMayAlias(ValueNode* context, compiler::OptionalScopeInfoRef scope_info); - MaybeReduceResult TrySpecializeLoadContextSlotToFunctionContext( - ValueNode* context, int index, VariableMode mode, - MaybeAssignedFlag assigned); ValueNode* TrySpecializeLoadContextCell(ValueNode* context, int index, MaybeAssignedFlag assigned); ReduceResult LoadAndCacheContextSlot(ValueNode* context, int index, @@ -478,7 +475,6 @@ class MaglevGraphBuilder { ValueNode* value, ContextMode context_mode, compiler::ScopeInfoRef scope_info); - ValueNode* TryGetParentContext(ValueNode* node); void MinimizeContextChainDepth(ValueNode** context, size_t* depth, ContextScopeInfo* scope_info); void EscapeContext(); @@ -1168,14 +1164,20 @@ class MaglevGraphBuilder { MaybeReduceResult TryBuildScriptContextStore( const compiler::GlobalAccessFeedback& global_access_feedback); MaybeReduceResult TryBuildPropertyCellStore( - const compiler::GlobalAccessFeedback& global_access_feedback); + compiler::PropertyCellRef property_cell, + base::FunctionRef<ReduceResult()> check_maps = []() { + return ReduceResult::Done(); + }); MaybeReduceResult TryBuildGlobalStore( const compiler::GlobalAccessFeedback& global_access_feedback); MaybeReduceResult TryBuildScriptContextLoad( const compiler::GlobalAccessFeedback& global_access_feedback); MaybeReduceResult TryBuildPropertyCellLoad( - const compiler::GlobalAccessFeedback& global_access_feedback); + compiler::PropertyCellRef property_cell, + base::FunctionRef<ReduceResult()> check_maps = []() { + return ReduceResult::Done(); + }); MaybeReduceResult TryBuildGlobalLoad( const compiler::GlobalAccessFeedback& global_access_feedback); @@ -1268,10 +1270,11 @@ class MaglevGraphBuilder { ReduceResult BuildLoadTaggedField( ValueNode* object, uint32_t offset, NodeType type = NodeType::kUnknown, - bool is_const = false, PropertyKey key = PropertyKey::None(), + PropertyConstness constness = PropertyConstness::kMutable, + PropertyKey key = PropertyKey::None(), IsArrayLength is_array_length = IsArrayLength::kNo, compiler::OptionalMapRef stable_field_map = {}) { - return reducer_.BuildLoadTaggedField(object, offset, type, is_const, key, + return reducer_.BuildLoadTaggedField(object, offset, type, constness, key, is_array_length, stable_field_map); } @@ -1546,6 +1549,9 @@ class MaglevGraphBuilder { std::optional<VirtualObject*> TryGetNonEscapingArgumentsOrArray( ValueNode* value); + bool ArgumentsElementsMaybeMutated(InlinedAllocation* allocation, + ArgumentsElements* elements); + void MarkArgumentsElementsMaybeMutated(ValueNode* elements); MaybeReduceResult TryBuildFastCreateObjectOrArrayLiteral( const compiler::LiteralFeedback& feedback); diff --git a/deps/v8/src/maglev/maglev-graph-labeller.h b/deps/v8/src/maglev/maglev-graph-labeller.h index 3d1046beeca3..5eadaa5bb9ee 100644 --- a/deps/v8/src/maglev/maglev-graph-labeller.h +++ b/deps/v8/src/maglev/maglev-graph-labeller.h @@ -5,8 +5,7 @@ #ifndef V8_MAGLEV_MAGLEV_GRAPH_LABELLER_H_ #define V8_MAGLEV_MAGLEV_GRAPH_LABELLER_H_ -#include <map> - +#include "absl/container/flat_hash_map.h" #include "src/maglev/maglev-ir.h" #include "src/utils/utils.h" @@ -95,10 +94,12 @@ class MaglevGraphLabeller { os << ":" << input.operand(); } } - const std::map<const NodeBase*, NodeInfo>& nodes() const { return nodes_; } + const absl::flat_hash_map<const NodeBase*, NodeInfo>& nodes() const { + return nodes_; + } private: - std::map<const NodeBase*, NodeInfo> nodes_; + absl::flat_hash_map<const NodeBase*, NodeInfo> nodes_; int next_node_label_ = 1; }; diff --git a/deps/v8/src/maglev/maglev-graph-optimizer.cc b/deps/v8/src/maglev/maglev-graph-optimizer.cc index a78420a1338a..04ac39d138db 100644 --- a/deps/v8/src/maglev/maglev-graph-optimizer.cc +++ b/deps/v8/src/maglev/maglev-graph-optimizer.cc @@ -80,6 +80,8 @@ MaglevGraphOptimizer::GetDeoptFrameForLazyDeopt(bool can_throw) { frame = GetDeoptFrameForLazyDeoptHelper(graph()->zone(), reducer_.current_lazy_deopt_scope(), frame, frame->GetVirtualObjects()); + result_location = interpreter::Register::virtual_accumulator(); + result_size = 1; } return {frame, result_location, result_size}; } @@ -130,7 +132,7 @@ ValueNode* Value(ValueNode* node) { return node; } } else if (IsDoneWithAbort(res)) { \ return ProcessResult::kTruncateBlock; \ } \ - DCHECK(IsFail(result)); \ + DCHECK(IsFail(res)); \ } while (false) #define REMOVE_AND_RETURN_IF_DONE(result) \ @@ -591,6 +593,20 @@ bool MaglevGraphOptimizer::IsRangeLessEqual(ValueNode* lhs, ValueNode* rhs) { return ranges_->IsLessEqualConstraint(reducer_.current_block(), lhs, rhs); } +ProcessResult MaglevGraphOptimizer::OverwriteWith(Opcode opcode) { + TRACE(TraceColor::kDarkGreen << "Overwriting " + << PrintNodeLabel(current_node()) << " with " + << opcode); + + current_node()->OverwriteWith(opcode); + + // Since we've changed the type of the node, we need to trigger a revisit, + // otherwise the next processors would see a stale static type for this node + // and will thus wrongly treat it as a node of the old type instead of the new + // one. + return ProcessResult::kRevisit; +} + ProcessResult MaglevGraphOptimizer::ReplaceWith(ValueNode* node) { // If current node is not a value node, we shouldn't try to replace it. CHECK(current_node()->Cast<ValueNode>()); @@ -826,6 +842,9 @@ std::optional<ProcessResult> MaglevGraphOptimizer::TryFoldInt32Operation( node->input_node(0), node->input_node(1)); } if (!result.IsDone()) return {}; + if (result.IsDoneWithAbort()) { + return ProcessResult::kTruncateBlock; + } DCHECK(result.IsDoneWithValue()); if constexpr (kOperation == Operation::kShiftRightLogical) { // ShiftRightLogical returns an Uint32 instead of an Int32. We don't have @@ -928,6 +947,8 @@ void MaglevGraphOptimizer::AttachExceptionHandlerInfo(NodeBase* node) { template <typename NodeT> ProcessResult MaglevGraphOptimizer::ProcessLoadContextSlot(NodeT* node) { + REPLACE_AND_RETURN_IF_DONE(reducer_.TryGetConstantContextValue( + node->input_node(0), node->offset(), node->maybe_assigned())); REPLACE_AND_RETURN_IF_DONE(known_node_aspects().TryGetContextCachedValue( node->input_node(0), node->offset(), node->maybe_assigned())); return ProcessResult::kContinue; @@ -1179,11 +1200,8 @@ ProcessResult MaglevGraphOptimizer::VisitCheckValue( CheckValue* node, const ProcessingState& state) { ValueNode* input = node->input_node(0); if (HeapConstant* constant = input->TryCast<HeapConstant>()) { - if (constant->object() == node->value()) { - return RemoveCurrentNode(); - } - // TODO(victorgomes): Support soft deopting and killing the rest of the - // block. + return RemoveCheckOrDeopt(constant->object() == node->value(), + node->deoptimize_reason()); } return ProcessResult::kContinue; } @@ -1313,45 +1331,34 @@ ProcessResult MaglevGraphOptimizer::VisitStoreMap( return ProcessResult::kContinue; } -template <typename FixedArrayT, typename NodeT> -MaybeReduceResult MaglevGraphOptimizer::AbortIfInvalidFixedArrayIndex( - NodeT* node) { - if (std::optional<int32_t> index = - reducer_.TryGetInt32Constant(node->IndexInput().node())) { - if (*index < 0 || - static_cast<uint32_t>(*index) >= FixedArrayT::kMaxLength) { - // This is an out-of-bound store, which means that we have to be in - // unreachable code. - return reducer_.BuildAbort(AbortReason::kUnreachable); - } - } - return {}; -} - ProcessResult MaglevGraphOptimizer::VisitStoreFixedArrayElementWithWriteBarrier( StoreFixedArrayElementWithWriteBarrier* node, const ProcessingState& state) { - REMOVE_AND_RETURN_IF_DONE(AbortIfInvalidFixedArrayIndex<FixedArray>(node)); + REMOVE_AND_RETURN_IF_DONE(reducer_.AbortIfInvalidFixedArrayIndex<FixedArray>( + node->IndexInput().node())); return ProcessResult::kContinue; } ProcessResult MaglevGraphOptimizer::VisitStoreFixedArrayElementNoWriteBarrier( StoreFixedArrayElementNoWriteBarrier* node, const ProcessingState& state) { - REMOVE_AND_RETURN_IF_DONE(AbortIfInvalidFixedArrayIndex<FixedArray>(node)); + REMOVE_AND_RETURN_IF_DONE(reducer_.AbortIfInvalidFixedArrayIndex<FixedArray>( + node->IndexInput().node())); return ProcessResult::kContinue; } ProcessResult MaglevGraphOptimizer::VisitStoreFixedHoleyDoubleArrayElement( StoreFixedHoleyDoubleArrayElement* node, const ProcessingState& state) { REMOVE_AND_RETURN_IF_DONE( - AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(node)); + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>( + node->IndexInput().node())); return ProcessResult::kContinue; } ProcessResult MaglevGraphOptimizer::VisitStoreFixedDoubleArrayElement( StoreFixedDoubleArrayElement* node, const ProcessingState& state) { REMOVE_AND_RETURN_IF_DONE( - AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(node)); + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>( + node->IndexInput().node())); // A reduction can have replaced the value with one that carries the hole or // undefined NaN since the store chose not to canonicalize. ValueNode* value = node->ValueInput().node(); @@ -1367,7 +1374,8 @@ ProcessResult MaglevGraphOptimizer::VisitStoreFixedDoubleArrayElement( ProcessResult MaglevGraphOptimizer::VisitStoreFixedDoubleArrayHole( StoreFixedDoubleArrayHole* node, const ProcessingState& state) { REMOVE_AND_RETURN_IF_DONE( - AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(node)); + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>( + node->IndexInput().node())); return ProcessResult::kContinue; } @@ -2082,7 +2090,7 @@ ProcessResult MaglevGraphOptimizer::VisitLoadTaggedField( } if (!node->property_key().is_none()) { REPLACE_AND_RETURN_IF_DONE(known_node_aspects().TryFindLoadedProperty( - node->ValueInput().node(), node->property_key(), node->is_const())); + node->ValueInput().node(), node->property_key(), node->constness())); } return ProcessResult::kContinue; } @@ -2135,14 +2143,16 @@ ProcessResult MaglevGraphOptimizer::VisitLoadFixedArrayElement( ProcessResult MaglevGraphOptimizer::VisitLoadFixedDoubleArrayElement( LoadFixedDoubleArrayElement* node, const ProcessingState& state) { REMOVE_AND_RETURN_IF_DONE( - AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(node)); + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>( + node->IndexInput().node())); return ProcessResult::kContinue; } ProcessResult MaglevGraphOptimizer::VisitLoadHoleyFixedDoubleArrayElement( LoadHoleyFixedDoubleArrayElement* node, const ProcessingState& state) { REMOVE_AND_RETURN_IF_DONE( - AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(node)); + reducer_.AbortIfInvalidFixedArrayIndex<FixedDoubleArray>( + node->IndexInput().node())); return ProcessResult::kContinue; } @@ -2697,7 +2707,7 @@ UNTAGGING_CASE(UnsafeNumberOrOddballToHoleyFloat64, HoleyFloat64, REPLACE_AND_RETURN_IF_DONE(GetUntaggedValueWithRepresentation( \ node->input_node(0), UseRepresentation::k##Repr, ConvType)); \ if (reducer_.CheckType(node->input_node(0), ConvType)) { \ - node->OverwriteWith(Opcode::k##UnsafeNode); \ + return OverwriteWith(Opcode::k##UnsafeNode); \ } \ return ProcessResult::kContinue; \ } @@ -2749,7 +2759,7 @@ ProcessResult MaglevGraphOptimizer::VisitCheckedSmiUntag( // } // DCHECK(maybe_input.IsFail()); if (reducer_.CheckType(node->input_node(0), NodeType::kSmi)) { - node->OverwriteWith(Opcode::kUnsafeSmiUntag); + return OverwriteWith(Opcode::kUnsafeSmiUntag); } return ProcessResult::kContinue; } @@ -2771,7 +2781,7 @@ ProcessResult MaglevGraphOptimizer::VisitCheckedNumberToFloat64( return ProcessResult::kTruncateBlock; } if (reducer_.CheckType(node->input_node(0), NodeType::kNumber)) { - node->OverwriteWith(Opcode::kUnsafeNumberToFloat64); + return OverwriteWith(Opcode::kUnsafeNumberToFloat64); } return ProcessResult::kContinue; } @@ -2795,7 +2805,7 @@ ProcessResult MaglevGraphOptimizer::VisitUnsafeFloat64ToHoleyFloat64( // undefined NaN since the widen was chosen, and widening those would give // them back their meaning. if (node->ValueInput().node()->MayBeHoleOrUndefinedNan()) { - node->OverwriteWith(Opcode::kChangeFloat64ToHoleyFloat64); + return OverwriteWith(Opcode::kChangeFloat64ToHoleyFloat64); } return ProcessResult::kContinue; } @@ -3752,6 +3762,15 @@ ProcessResult MaglevGraphOptimizer::VisitBranchIfInt32ToBooleanTrue( return ProcessResult::kContinue; } +ProcessResult MaglevGraphOptimizer::VisitBranchIfInt32BitwiseAndNonZero( + BranchIfInt32BitwiseAndNonZero* node, const ProcessingState& state) { + if (auto cst = reducer_.TryGetInt32Constant(node->ValueInput().node())) { + FoldBranch(state.block(), node, (cst.value() & node->mask()) != 0); + return ProcessResult::kRevisit; + } + return ProcessResult::kContinue; +} + ProcessResult MaglevGraphOptimizer::VisitBranchIfIntPtrToBooleanTrue( BranchIfIntPtrToBooleanTrue* node, const ProcessingState& state) { if (auto cst = reducer_.TryGetIntPtrConstant(node->input_node(0))) { @@ -3975,7 +3994,7 @@ ProcessResult MaglevGraphOptimizer::VisitTruncateCheckedNumberAsSafeIntToInt32( return ReplaceWith(node->input_node(0)->input_node(0)); } if (reducer_.CheckType(node->input_node(0), NodeType::kNumber)) { - node->OverwriteWith(Opcode::kTruncateUnsafeNumberAsSafeIntToInt32); + return OverwriteWith(Opcode::kTruncateUnsafeNumberAsSafeIntToInt32); } return ProcessResult::kContinue; } diff --git a/deps/v8/src/maglev/maglev-graph-optimizer.h b/deps/v8/src/maglev/maglev-graph-optimizer.h index 7e98d1059f26..1155124d64f4 100644 --- a/deps/v8/src/maglev/maglev-graph-optimizer.h +++ b/deps/v8/src/maglev/maglev-graph-optimizer.h @@ -176,8 +176,7 @@ class V8_EXPORT_PRIVATE MaglevGraphOptimizer { Jump* FoldBranch(BasicBlock* current, BranchControlNode* branch_node, bool if_true); - template <typename FixedArrayT, typename NodeT> - MaybeReduceResult AbortIfInvalidFixedArrayIndex(NodeT* node); + ProcessResult OverwriteWith(Opcode opcode); ProcessResult ReplaceWith(ValueNode* node); diff --git a/deps/v8/src/maglev/maglev-graph-processor.h b/deps/v8/src/maglev/maglev-graph-processor.h index 92a76cd0fb57..e45fcc4d20e3 100644 --- a/deps/v8/src/maglev/maglev-graph-processor.h +++ b/deps/v8/src/maglev/maglev-graph-processor.h @@ -10,6 +10,9 @@ #include "src/base/logging.h" #include "src/base/macros.h" #include "src/compiler/bytecode-analysis.h" +#include "src/compiler/js-heap-broker.h" +#include "src/execution/local-isolate.h" +#include "src/heap/local-heap.h" #include "src/maglev/maglev-basic-block.h" #include "src/maglev/maglev-compilation-info.h" #include "src/maglev/maglev-graph.h" @@ -44,6 +47,13 @@ namespace maglev { // // overloading as appropriate to group node processing. // void Process(FooNode* node, const ProcessingState& state) {} // +// Safepoints: +// Long unparked compilation passes poll for safepoint requests before each +// block and node to avoid blocking GC. Consequently, a GC can trigger between +// Process() calls or synchronously inside the poll on the main thread. +// +// // Invariant: NodeProcessors must never hold raw Tagged<> values across +// // node visits template <typename NodeProcessor> class GraphProcessor; template <typename NodeProcessor> @@ -129,6 +139,12 @@ class ProcessingState { const int node_index_; // Index inside the basic block. }; +// The LocalHeap that graph walks poll for safepoint requests. Falls back to the +// main thread's LocalHeap for synchronous (main-thread) compilation. +inline LocalHeap* GetLocalHeapForSafepointPolling(Graph* graph) { + return graph->broker()->local_isolate_or_isolate()->heap(); +} + template <typename NodeProcessor> class GraphProcessor { public: @@ -138,6 +154,7 @@ class GraphProcessor { void ProcessGraph(Graph* graph) { graph_ = graph; + LocalHeap* local_heap = GetLocalHeapForSafepointPolling(graph); // Initializing {current_block_index_} to `graph->num_blocks()` so that // the ProcessingState can return nullptr as the block of the constant // nodes. @@ -185,6 +202,7 @@ class GraphProcessor { if (V8_UNLIKELY(block->is_dead())) continue; bool process_control_block = true; + local_heap->Safepoint(); BlockProcessResult preprocess_result = node_processor_.PreProcessBasicBlock(block); switch (preprocess_result) { @@ -231,6 +249,7 @@ class GraphProcessor { ++node_it_; continue; } + local_heap->Safepoint(); #ifdef DEBUG const Node* const* debug_nodes_data = nullptr; size_t debug_nodes_size = 0; @@ -279,7 +298,7 @@ class GraphProcessor { break; } } - TruncateBlockAtNode(block, node); + block->TruncateAt(node); node_it_ = block->nodes().end(); graph_->set_may_have_unreachable_blocks(true); break; @@ -374,18 +393,6 @@ class GraphProcessor { np->HasPendingSplice(); }; - // Truncates `block` to end just before `node`, dropping `node` and every - // node after it. The cut point is located by value rather than a cached - // iterator or index: a mid-block deopt or throw can emit an abrupt block - // end whose node flush reallocates block->nodes(), dangling any iterator - // taken before the flush. - void TruncateBlockAtNode(BasicBlock* block, Node* node) { - auto& nodes = block->nodes(); - auto it = std::find(nodes.begin(), nodes.end(), node); - DCHECK_NE(it, nodes.end()); - nodes.resize(it - nodes.begin()); - } - // Splices the subgraph recorded by the processor's reducer into the // graph at the visited node. If `truncate` is false, the tail (after the // visited node) moves to splice.exit; the visited node itself is expected @@ -402,7 +409,7 @@ class GraphProcessor { ZoneVector<Node*> tail_nodes(graph_->zone()); if (truncate) { // Drop the visited node and everything after it. - TruncateBlockAtNode(block, node); + block->TruncateAt(node); } else { // The visitor must have rewritten the visited node to an Identity // (typically to the spliced result Phi), so uses on the join-block @@ -480,10 +487,12 @@ class GraphBackwardProcessor { : node_processor_(std::forward<Args>(args)...) {} void ProcessGraph(Graph* graph) { + LocalHeap* local_heap = GetLocalHeapForSafepointPolling(graph); node_processor_.PreProcessGraph(graph); for (BasicBlock* block : base::Reversed(graph->blocks())) { if (V8_UNLIKELY(block->is_dead())) continue; + local_heap->Safepoint(); BlockProcessResult preprocess_result = node_processor_.PreProcessBasicBlock(block); switch (preprocess_result) { @@ -513,6 +522,7 @@ class GraphBackwardProcessor { for (Node* node : base::Reversed(block->nodes())) { if (node == nullptr) continue; + local_heap->Safepoint(); ProcessResult result = ProcessNodeBase(node); switch (result) { [[likely]] case ProcessResult::kContinue: diff --git a/deps/v8/src/maglev/maglev-graph-serializer.cc b/deps/v8/src/maglev/maglev-graph-serializer.cc index d956724920b5..be86e57b873b 100644 --- a/deps/v8/src/maglev/maglev-graph-serializer.cc +++ b/deps/v8/src/maglev/maglev-graph-serializer.cc @@ -5,6 +5,7 @@ #include "src/maglev/maglev-graph-serializer.h" #include <algorithm> +#include <array> #include <iomanip> #include <ostream> #include <sstream> @@ -60,7 +61,7 @@ const char* RepresentationSuperscript(ValueRepresentation repr) { std::unique_ptr<char[]> GetMaglevVisualizerLogFileName( MaglevCompilationInfo* info, const char* optional_base_dir, const char* phase, const char* suffix) { - base::EmbeddedVector<char, 256> filename(0); + std::array<char, 256> filename = {}; std::string debug_name = info->function_name(); const char* file_prefix = info->is_turbolev() ? v8_flags.trace_turbo_file_prefix.value() @@ -68,10 +69,10 @@ std::unique_ptr<char[]> GetMaglevVisualizerLogFileName( int optimization_id = info->optimization_id(); if (debug_name.length() > 0) { - SNPrintF(filename, "%s-%s-%i", file_prefix, debug_name.c_str(), - optimization_id); + base::SNPrintF(filename, "%s-%s-%i", file_prefix, debug_name.c_str(), + optimization_id); } else { - SNPrintF(filename, "%s-none-%i", file_prefix, optimization_id); + base::SNPrintF(filename, "%s-none-%i", file_prefix, optimization_id); } std::replace(filename.begin(), filename.begin() + filename.size(), '/', '_'); @@ -82,25 +83,25 @@ std::unique_ptr<char[]> GetMaglevVisualizerLogFileName( std::replace(filename.begin(), filename.begin() + filename.size(), '>', '}'); #endif - base::EmbeddedVector<char, 256> base_dir; + std::array<char, 256> base_dir; if (optional_base_dir != nullptr) { - SNPrintF(base_dir, "%s%c", optional_base_dir, - base::OS::DirectorySeparator()); + base::SNPrintF(base_dir, "%s%c", optional_base_dir, + base::OS::DirectorySeparator()); } else { base_dir[0] = '\0'; } - base::EmbeddedVector<char, 256> full_filename; + std::array<char, 256> full_filename; if (phase == nullptr) { - SNPrintF(full_filename, "%s%s.%s", base_dir.begin(), filename.begin(), - suffix); + base::SNPrintF(full_filename, "%s%s.%s", base_dir.data(), filename.data(), + suffix); } else { - SNPrintF(full_filename, "%s%s-%s.%s", base_dir.begin(), filename.begin(), - phase, suffix); + base::SNPrintF(full_filename, "%s%s-%s.%s", base_dir.data(), + filename.data(), phase, suffix); } char* buffer = new char[full_filename.size()]; - memcpy(buffer, full_filename.begin(), full_filename.size()); + memcpy(buffer, full_filename.data(), full_filename.size()); return std::unique_ptr<char[]>(buffer); } diff --git a/deps/v8/src/maglev/maglev-graph.cc b/deps/v8/src/maglev/maglev-graph.cc index c4817435d720..ccbf4a9bc26b 100644 --- a/deps/v8/src/maglev/maglev-graph.cc +++ b/deps/v8/src/maglev/maglev-graph.cc @@ -167,7 +167,7 @@ bool Graph::MayNeedContextPhis() const { #endif // DEBUG ValueNode* Graph::GetTrustedConstant(compiler::HeapObjectRef ref, - IndirectPointerTag tag) { + TrustedPointerTag tag) { #ifdef V8_ENABLE_SANDBOX auto it = trusted_constants_.find(ref); if (it == trusted_constants_.end()) { diff --git a/deps/v8/src/maglev/maglev-graph.h b/deps/v8/src/maglev/maglev-graph.h index 939d639b539c..7ffcdade7c5f 100644 --- a/deps/v8/src/maglev/maglev-graph.h +++ b/deps/v8/src/maglev/maglev-graph.h @@ -362,7 +362,7 @@ class Graph final : public ZoneObject { ValueNode* GetConstant(compiler::ObjectRef ref); ValueNode* GetTrustedConstant(compiler::HeapObjectRef ref, - IndirectPointerTag tag); + TrustedPointerTag tag); Zone* zone() const { return compilation_info_->zone(); } compiler::JSHeapBroker* broker() const { return compilation_info_->broker(); } diff --git a/deps/v8/src/maglev/maglev-inlining.cc b/deps/v8/src/maglev/maglev-inlining.cc index 94e3001675ad..e3ae2665c004 100644 --- a/deps/v8/src/maglev/maglev-inlining.cc +++ b/deps/v8/src/maglev/maglev-inlining.cc @@ -167,6 +167,32 @@ MaglevCallSiteInfo* MaglevInliner::ChooseNextCallSite() { return call_site; } +namespace { + +bool IsMatchingTarget(compiler::JSHeapBroker* broker, ValueNode* function, + compiler::FeedbackCellRef feedback_cell, + compiler::SharedFunctionInfoRef shared) { + if (FastCreateClosure* fast_closure = + function->TryCast<FastCreateClosure>()) { + return fast_closure->feedback_cell().equals(feedback_cell) && + fast_closure->shared_function_info().equals(shared); + } + if (CreateClosure* slow_closure = function->TryCast<CreateClosure>()) { + return slow_closure->feedback_cell().equals(feedback_cell) && + slow_closure->shared_function_info().equals(shared); + } + if (IsConstantNode(function->opcode())) { + HeapConstant* constant = function->TryCast<HeapConstant>(); + return constant != nullptr && constant->ref().IsJSFunction() && + constant->ref().AsJSFunction().raw_feedback_cell(broker).equals( + feedback_cell) && + constant->ref().AsJSFunction().shared(broker).equals(shared); + } + return true; +} + +} // namespace + MaglevInliner::InliningResult MaglevInliner::BuildInlineFunction( MaglevCallSiteInfo* call_site, bool is_small) { CallKnownJSFunction* call_node = call_site->generic_call_node; @@ -185,6 +211,19 @@ MaglevInliner::InliningResult MaglevInliner::BuildInlineFunction( return InliningResult::kFail; } + ValueNode* function = call_node->TargetInput().node()->Unwrap(); + if (!IsMatchingTarget(broker(), function, call_site->feedback_cell, shared)) { + TRACE_INLINING(TraceSkip(shared) + << "Target does not match call site; truncating block."); + // The preceding CheckInstanceType / CheckValue in call_block will + // unconditionally eager-deopt before reaching call_node, so call_node and + // the remainder of call_block are unreachable. + call_block->TruncateAt(call_node); + call_block->OverwriteControlWithAbort(AbortReason::kUnreachable); + graph_->set_may_have_unreachable_blocks(true); + return InliningResult::kDone; + } + TRACE_INLINING(TraceInline(shared)); // Check if the catch block might become unreachable, ie, the call is the @@ -216,8 +255,9 @@ MaglevInliner::InliningResult MaglevInliner::BuildInlineFunction( call_block->Split(call_node, zone()); // Create a new compilation unit. + ValueNode* context = call_node->ContextInput().node()->Unwrap(); MaglevCompilationUnit* inner_unit = MaglevCompilationUnit::NewInner( - zone(), caller_unit, shared, call_site->feedback_cell); + zone(), caller_unit, shared, call_site->feedback_cell, context, function); const int start_node_count = graph_->total_nodes(); @@ -258,9 +298,7 @@ MaglevInliner::InliningResult MaglevInliner::BuildInlineFunction( // remove the uses from the call node_inputs when overwriting the returned // value. ReduceResult result = inner_graph_builder.BuildInlineFunction( - caller_deopt_frame->GetSourcePosition(), - call_node->ContextInput().node()->Unwrap(), - call_node->TargetInput().node()->Unwrap(), + caller_deopt_frame->GetSourcePosition(), context, function, call_node->NewTargetInput().node()->Unwrap()); // Budget accounting. We distinguish between small and regular function diff --git a/deps/v8/src/maglev/maglev-interpreter-frame-state.h b/deps/v8/src/maglev/maglev-interpreter-frame-state.h index 195569e6d701..4e8e458204a6 100644 --- a/deps/v8/src/maglev/maglev-interpreter-frame-state.h +++ b/deps/v8/src/maglev/maglev-interpreter-frame-state.h @@ -32,87 +32,6 @@ class LoopMergePointInterpreterFrameState; class MergePointInterpreterFrameState; struct LoopEffects; -// Bundles a static ScopeInfoRef with the distance (in Context::previous() hops) -// from this scope to MaglevCompilationInfo::specialization_context(). -// - If specialization_context_distance() has a value, walking outward that many -// steps reaches the specialization context. -// - If specialization_context_distance() is std::nullopt (stored compactly as -// kNoDistance to keep sizeof(ContextScopeInfo) == 16), either there is no -// specialization context, this scope is inside an inlined compilation unit, -// or we have walked outward past the specialization context. -class ContextScopeInfo { - public: - ContextScopeInfo() = default; - ContextScopeInfo(std::nullopt_t) {} // NOLINT(runtime/explicit) - ContextScopeInfo(compiler::OptionalScopeInfoRef scope_info, - std::optional<size_t> specialization_context_distance = - std::nullopt) // NOLINT(runtime/explicit) - : scope_info_(scope_info), - specialization_context_distance_( - scope_info.has_value() - ? specialization_context_distance.value_or(kNoDistance) - : kNoDistance) {} - - bool has_value() const { return scope_info_.has_value(); } - compiler::ScopeInfoRef value() const { return scope_info_.value(); } - operator compiler::ScopeInfoRef() const { return value(); } - compiler::OptionalScopeInfoRef scope_info() const { return scope_info_; } - - bool HasOuterScopeInfo() const { return scope_info_->HasOuterScopeInfo(); } - bool HasContextExtensionSlot() const { - return scope_info_->HasContextExtensionSlot(); - } - ScopeType scope_type() const { return scope_info_->scope_type(); } - - std::optional<size_t> specialization_context_distance() const { - if (!has_value() || specialization_context_distance_ == kNoDistance) { - return std::nullopt; - } - return specialization_context_distance_; - } - - V8_NODISCARD ContextScopeInfo Push(compiler::ScopeInfoRef inner_scope) const { - std::optional<size_t> inner_dist; - if (specialization_context_distance_ != kNoDistance) { - inner_dist = specialization_context_distance_ + 1; - } - return ContextScopeInfo(inner_scope, inner_dist); - } - - V8_NODISCARD ContextScopeInfo - OuterScopeInfo(compiler::JSHeapBroker* broker) const { - DCHECK(has_value()); - DCHECK(HasOuterScopeInfo()); - std::optional<size_t> outer_dist; - if (specialization_context_distance_ != kNoDistance && - specialization_context_distance_ > 0) { - outer_dist = specialization_context_distance_ - 1; - } - return ContextScopeInfo(scope_info_->OuterScopeInfo(broker), outer_dist); - } - - bool operator==(const ContextScopeInfo& other) const { - DCHECK_IMPLIES(scope_info_.equals(other.scope_info_), - specialization_context_distance_ == - other.specialization_context_distance_); - return scope_info_.equals(other.scope_info_); - } - - friend std::ostream& operator<<(std::ostream& os, - const ContextScopeInfo& info) { - if (info.has_value()) { - return os << info.value(); - } - return os << "<empty>"; - } - - private: - static constexpr size_t kNoDistance = std::numeric_limits<size_t>::max(); - - compiler::OptionalScopeInfoRef scope_info_; - size_t specialization_context_distance_ = kNoDistance; -}; - class InterpreterFrameState { public: InterpreterFrameState(const MaglevCompilationUnit& info, diff --git a/deps/v8/src/maglev/maglev-ir.cc b/deps/v8/src/maglev/maglev-ir.cc index 499f75cb9a36..0fd92f2bfc20 100644 --- a/deps/v8/src/maglev/maglev-ir.cc +++ b/deps/v8/src/maglev/maglev-ir.cc @@ -533,9 +533,6 @@ DeoptInfo::DeoptInfo(Zone* zone, DeoptFrame* top_frame, : top_frame_(top_frame), feedback_to_update_(feedback_to_update) {} bool LazyDeoptInfo::IsResultRegister(interpreter::Register reg) const { - if (top_frame().type() == DeoptFrame::FrameType::kConstructInvokeStubFrame) { - return reg == interpreter::Register::virtual_accumulator(); - } if (V8_LIKELY(result_size() == 1)) { return reg == result_location_; } @@ -557,6 +554,14 @@ bool LazyDeoptInfo::InReturnValues(interpreter::Register reg, result_location.index() + result_size - 1); } +int BuiltinContinuationDeoptFrame::translation_height() const { + // parameters() in JS Continuation only holds the stack params as the JS + // trampoline's register ones are appended during translation. + return parameters().length() + + (is_javascript() ? JSTrampolineDescriptor::GetRegisterParameterCount() + : 0); +} + int InterpretedDeoptFrame::ComputeReturnOffset( interpreter::Register result_location, int result_size) const { // Return offsets are counted from the end of the translation frame, @@ -1171,17 +1176,12 @@ DirectHandle<Object> IntPtrConstant::DoReify(LocalIsolate* isolate) const { } DirectHandle<Object> Float64Constant::DoReify(LocalIsolate* isolate) const { - return isolate->factory()->NewNumber<AllocationType::kOld>( - value_.get_scalar()); + UNREACHABLE(); } DirectHandle<Object> HoleyFloat64Constant::DoReify( LocalIsolate* isolate) const { - if (value_.is_undefined_or_hole_nan()) { - return isolate->factory()->undefined_value(); - } - return isolate->factory()->NewNumber<AllocationType::kOld>( - value_.get_scalar()); + UNREACHABLE(); } DirectHandle<Object> HeapConstant::DoReify(LocalIsolate* isolate) const { @@ -1259,6 +1259,21 @@ void ValueNode::LoadToRegister(MaglevAssembler* masm, } } +bool ValueNode::MaterializesToZero() const { + switch (opcode()) { + case Opcode::kSmiConstant: + return Cast<SmiConstant>()->value() == Smi::zero(); + case Opcode::kInt32Constant: + return Cast<Int32Constant>()->value() == 0; + case Opcode::kUint32Constant: + return Cast<Uint32Constant>()->value() == 0; + case Opcode::kIntPtrConstant: + return Cast<IntPtrConstant>()->value() == 0; + default: + return false; + } +} + void SmiConstant::DoLoadToRegister(MaglevAssembler* masm, Register reg) const { __ Move(reg, value()); } @@ -4972,10 +4987,7 @@ void AllocationBlock::GenerateCode(MaglevAssembler* masm, } int CreateClosure::MaxCallStackArgs() const { - DCHECK_EQ(Runtime::FunctionForId(pretenured() ? Runtime::kNewClosure_Tenured - : Runtime::kNewClosure) - ->nargs, - 2); + DCHECK_EQ(Runtime::FunctionForId(Runtime::kNewClosure)->nargs, 2); return 2; } void CreateClosure::SetValueLocationConstraints() { @@ -4984,10 +4996,8 @@ void CreateClosure::SetValueLocationConstraints() { } void CreateClosure::GenerateCode(MaglevAssembler* masm, const ProcessingState& state) { - Runtime::FunctionId function_id = - pretenured() ? Runtime::kNewClosure_Tenured : Runtime::kNewClosure; __ Push(shared_function_info().object(), feedback_cell().object()); - __ CallRuntime(function_id); + __ CallRuntime(Runtime::kNewClosure); } int FastCreateClosure::MaxCallStackArgs() const { @@ -8600,6 +8610,25 @@ void BranchIfInt32ToBooleanTrue::GenerateCode(MaglevAssembler* masm, if_true(), if_false(), state.next_block()); } +void BranchIfInt32BitwiseAndNonZero::SetValueLocationConstraints() { + UseRegister(ValueInput()); +} +void BranchIfInt32BitwiseAndNonZero::GenerateCode( + MaglevAssembler* masm, const ProcessingState& state) { + Register value = ToRegister(ValueInput()); + BasicBlock* next_block = state.next_block(); + if (if_true() == next_block) { + // The true target is the fallthrough: branch to the false target when no + // masked bit is set, i.e. when (value & mask) == 0. + __ TestInt32AndJumpIfAllClear(value, mask_, if_false()->label()); + } else { + __ TestInt32AndJumpIfAnySet(value, mask_, if_true()->label()); + if (if_false() != next_block) { + __ Jump(if_false()->label()); + } + } +} + void BranchIfIntPtrToBooleanTrue::SetValueLocationConstraints() { // TODO(victorgomes): consider using any input instead. UseRegister(ConditionInput()); @@ -9077,11 +9106,7 @@ void FastCreateClosure::PrintParams(std::ostream& os) const { void CreateClosure::PrintParams(std::ostream& os) const { os << "(" << *shared_function_info().object() << ", " - << feedback_cell().object(); - if (pretenured()) { - os << " [pretenured]"; - } - os << ")"; + << feedback_cell().object() << ")"; } void AllocationBlock::PrintParams(std::ostream& os) const { @@ -9539,6 +9564,10 @@ void BranchIfInt32Compare::PrintParams(std::ostream& os) const { os << "(" << operation_ << ")"; } +void BranchIfInt32BitwiseAndNonZero::PrintParams(std::ostream& os) const { + os << "(0x" << std::hex << static_cast<uint32_t>(mask_) << std::dec << ")"; +} + void BranchIfUint32Compare::PrintParams(std::ostream& os) const { os << "(" << operation_ << ")"; } diff --git a/deps/v8/src/maglev/maglev-ir.h b/deps/v8/src/maglev/maglev-ir.h index c9adf3113aed..d94bbafda06a 100644 --- a/deps/v8/src/maglev/maglev-ir.h +++ b/deps/v8/src/maglev/maglev-ir.h @@ -5,6 +5,7 @@ #ifndef V8_MAGLEV_MAGLEV_IR_H_ #define V8_MAGLEV_MAGLEV_IR_H_ +#include <bit> #include <optional> #include <type_traits> @@ -513,6 +514,7 @@ class ExceptionHandlerInfo; V(BranchIfRootConstant) \ V(BranchIfToBooleanTrue) \ V(BranchIfInt32ToBooleanTrue) \ + V(BranchIfInt32BitwiseAndNonZero) \ V(BranchIfIntPtrToBooleanTrue) \ V(BranchIfFloat64ToBooleanTrue) \ V(BranchIfHoleyFloat64ToBooleanTrue) \ @@ -1677,6 +1679,9 @@ class BuiltinContinuationDeoptFrame : public DeoptFrame { return data().maybe_js_target.value(); } + // Number of parameters in the deopt translation. + int translation_height() const; + private: BuiltinContinuationFrameData& data() { return data_.get<BuiltinContinuationFrameData>(); @@ -1845,7 +1850,9 @@ class LazyDeoptInfo : public DeoptInfo { result_location_(result_location), bitfield_( DeoptingCallReturnPcField::encode(kUninitializedCallReturnPc) | - ResultSizeField::encode(result_size)) {} + ResultSizeField::encode(result_size)) { + DCHECK(IsConsideredForResultLocation()); + } interpreter::Register result_location() const { DCHECK(IsConsideredForResultLocation()); @@ -1895,31 +1902,12 @@ class LazyDeoptInfo : public DeoptInfo { private: #ifdef DEBUG bool IsConsideredForResultLocation() const { - switch (top_frame().type()) { - case DeoptFrame::FrameType::kInterpretedFrame: - // Interpreted frames obviously need a result location. - return true; - case DeoptFrame::FrameType::kInlinedArgumentsFrame: - case DeoptFrame::FrameType::kConstructInvokeStubFrame: - return false; - case DeoptFrame::FrameType::kBuiltinContinuationFrame: - // Normally if the function is going to be deoptimized then the top - // frame should be an interpreted one, except for LazyDeoptContinuation - // builtin. - switch (top_frame().as_builtin_continuation().builtin_id()) { - case Builtin::kGenericLazyDeoptContinuation: - case Builtin::kGetIteratorWithFeedbackLazyDeoptContinuation: - case Builtin::kCallIteratorWithFeedbackLazyDeoptContinuation: - case Builtin::kForOfNextLoadDoneLazyDeoptContinuation: - case Builtin::kForOfNextLoadValueLazyDeoptContinuation: - case Builtin::kArrayDestructureLazyDeoptContinuation: - case Builtin::kGeneratorPrototypeNextLazyDeoptContinuation: - return true; - default: - return false; - } - } - UNREACHABLE(); + // Deopt continuation builtins don't consider the result location or size + // encoded in the deopt data; they behave like function calls and return + // into the accumulator. + return top_frame().type() == DeoptFrame::FrameType::kInterpretedFrame || + (result_location_ == interpreter::Register::virtual_accumulator() && + ResultSizeField::decode(bitfield_) == 1); } #endif // DEBUG @@ -2026,16 +2014,16 @@ constexpr const T* ObjectPtrBeforeAddress(const void* address) { } // namespace detail -#define DEOPTIMIZE_REASON_FIELD \ - private: \ - using ReasonField = \ - NextBitField<DeoptimizeReason, base::bits::WhichPowerOfTwo<size_t>( \ - base::bits::RoundUpToPowerOfTwo32( \ - kDeoptimizeReasonCount))>; \ - \ - public: \ - DeoptimizeReason deoptimize_reason() const { \ - return ReasonField::decode(bitfield()); \ +#define DEOPTIMIZE_REASON_FIELD \ + private: \ + using ReasonField = \ + NextBitField<DeoptimizeReason, \ + base::bits::WhichPowerOfTwo<size_t>( \ + std::bit_ceil<uint32_t>(kDeoptimizeReasonCount))>; \ + \ + public: \ + DeoptimizeReason deoptimize_reason() const { \ + return ReasonField::decode(bitfield()); \ } class KnownNodeAspects; @@ -2682,6 +2670,10 @@ class ValueNode : public Node { // For constants only. void LoadToRegister(MaglevAssembler*, Register) const; void LoadToRegister(MaglevAssembler*, DoubleRegister) const; + // Whether loading this constant produces an all-zero bit pattern, so that + // an architecture with a zero register (MaglevAssembler::HasZeroRegister()) + // can store that register instead. + bool MaterializesToZero() const; DirectHandle<Object> Reify(LocalIsolate* isolate) const; bool has_valid_live_range() const { @@ -5379,7 +5371,7 @@ class TrustedConstant : public FixedInputValueNodeT<0, TrustedConstant> { using OutputRegister = Register; explicit TrustedConstant(uint64_t bitfield, compiler::HeapObjectRef object, - IndirectPointerTag tag) + TrustedPointerTag tag) : Base(bitfield), object_(object), tag_(tag) {} static constexpr OpProperties kProperties = OpProperties::TrustedPointer(); @@ -5391,14 +5383,14 @@ class TrustedConstant : public FixedInputValueNodeT<0, TrustedConstant> { void PrintParams(std::ostream&) const; compiler::HeapObjectRef object() const { return object_; } - IndirectPointerTag tag() const { return tag_; } + TrustedPointerTag tag() const { return tag_; } void DoLoadToRegister(MaglevAssembler*, OutputRegister) const; DirectHandle<Object> DoReify(LocalIsolate* isolate) const; private: const compiler::HeapObjectRef object_; - const IndirectPointerTag tag_; + const TrustedPointerTag tag_; }; class CreateArrayLiteral : public FixedInputValueNodeT<0, CreateArrayLiteral> { @@ -6736,8 +6728,14 @@ class ArgumentsElements : public FixedInputValueNodeT<1, ArgumentsElements> { int formal_parameter_count() const { return formal_parameter_count_; } private: + friend class MaglevGraphBuilder; + + bool maybe_mutated() const { return maybe_mutated_; } + void set_maybe_mutated() { maybe_mutated_ = true; } + CreateArgumentsType type_; int formal_parameter_count_; + bool maybe_mutated_ = false; }; // TODO(victorgomes): This node is currently not eliminated by the escape @@ -6809,15 +6807,23 @@ class FastCreateClosure : public FixedInputValueNodeT<1, FastCreateClosure> { public: explicit FastCreateClosure( uint64_t bitfield, compiler::SharedFunctionInfoRef shared_function_info, - compiler::FeedbackCellRef feedback_cell) + compiler::FeedbackCellRef feedback_cell, + compiler::OptionalContextRef specialization_context, + ContextScopeInfo context_scope_info) : Base(bitfield), shared_function_info_(shared_function_info), - feedback_cell_(feedback_cell) {} + feedback_cell_(feedback_cell), + specialization_context_(specialization_context), + context_scope_info_(context_scope_info) {} compiler::SharedFunctionInfoRef shared_function_info() const { return shared_function_info_; } compiler::FeedbackCellRef feedback_cell() const { return feedback_cell_; } + compiler::OptionalContextRef specialization_context() const { + return specialization_context_; + } + ContextScopeInfo context_scope_info() const { return context_scope_info_; } // The implementation currently calls runtime. static constexpr OpProperties kProperties = @@ -6836,6 +6842,8 @@ class FastCreateClosure : public FixedInputValueNodeT<1, FastCreateClosure> { private: const compiler::SharedFunctionInfoRef shared_function_info_; const compiler::FeedbackCellRef feedback_cell_; + const compiler::OptionalContextRef specialization_context_; + const ContextScopeInfo context_scope_info_; }; class CreateRegExpLiteral @@ -6870,17 +6878,22 @@ class CreateClosure : public FixedInputValueNodeT<1, CreateClosure> { explicit CreateClosure(uint64_t bitfield, compiler::SharedFunctionInfoRef shared_function_info, compiler::FeedbackCellRef feedback_cell, - bool pretenured) + compiler::OptionalContextRef specialization_context, + ContextScopeInfo context_scope_info) : Base(bitfield), shared_function_info_(shared_function_info), feedback_cell_(feedback_cell), - pretenured_(pretenured) {} + specialization_context_(specialization_context), + context_scope_info_(context_scope_info) {} compiler::SharedFunctionInfoRef shared_function_info() const { return shared_function_info_; } compiler::FeedbackCellRef feedback_cell() const { return feedback_cell_; } - bool pretenured() const { return pretenured_; } + compiler::OptionalContextRef specialization_context() const { + return specialization_context_; + } + ContextScopeInfo context_scope_info() const { return context_scope_info_; } // The implementation currently calls runtime. static constexpr OpProperties kProperties = OpProperties::Call() | @@ -6899,7 +6912,8 @@ class CreateClosure : public FixedInputValueNodeT<1, CreateClosure> { private: const compiler::SharedFunctionInfoRef shared_function_info_; const compiler::FeedbackCellRef feedback_cell_; - const bool pretenured_; + const compiler::OptionalContextRef specialization_context_; + const ContextScopeInfo context_scope_info_; }; #define ASSERT_CONDITION(V) \ @@ -7661,9 +7675,9 @@ class CheckInt32Condition : public FixedInputNodeT<2, CheckInt32Condition> { private: using ConditionField = - ReasonField::Next<AssertCondition, base::bits::WhichPowerOfTwo<size_t>( - base::bits::RoundUpToPowerOfTwo32( - kNumAssertConditions))>; + ReasonField::Next<AssertCondition, + base::bits::WhichPowerOfTwo<size_t>( + std::bit_ceil<uint32_t>(kNumAssertConditions))>; }; // AssumeMap is a hint for Turboshaft's LateLoadElimination: it tells it that @@ -8531,11 +8545,12 @@ enum class IsArrayLength { kNo, kYes }; class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> { public: explicit LoadTaggedField(uint64_t bitfield, const int offset, NodeType type, - bool is_const, PropertyKey property_key, + PropertyConstness constness, + PropertyKey property_key, IsArrayLength is_array_length, compiler::OptionalMapRef stable_field_map = {}) : Base( - bitfield | IsConstantLoadField::encode(is_const) | + bitfield | ConstnessField::encode(constness) | IsArrayLengthField::encode(is_array_length == IsArrayLength::kYes)), offset_(offset), type_(type), @@ -8547,7 +8562,10 @@ class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> { int offset() const { return offset_; } NodeType type() const { return type_; } - bool is_const() const { return IsConstantLoadField::decode(bitfield()); } + PropertyConstness constness() const { + return ConstnessField::decode(bitfield()); + } + bool is_const() const { return constness() == PropertyConstness::kConst; } PropertyKey property_key() const { return property_key_; } compiler::OptionalMapRef stable_field_map() const { return stable_field_map_; @@ -8570,7 +8588,7 @@ class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> { auto options() const { return std::tuple{offset(), type(), - is_const(), property_key(), + constness(), property_key(), is_array_length(), stable_field_map()}; } @@ -8579,8 +8597,8 @@ class LoadTaggedField : public FixedInputValueNodeT<1, LoadTaggedField> { const NodeType type_; PropertyKey property_key_; compiler::OptionalMapRef stable_field_map_; - using IsConstantLoadField = NextBitField<bool, 1>; - using IsArrayLengthField = IsConstantLoadField::Next<bool, 1>; + using ConstnessField = NextBitField<PropertyConstness, 1>; + using IsArrayLengthField = ConstnessField::Next<bool, 1>; }; class LoadContextSlotNoCells @@ -9214,7 +9232,7 @@ class StoreDoubleDataViewElement static constexpr OpProperties kProperties = OpProperties::CanWrite(); DECLARE_INPUTS(Object, DataPointer, Index, Value, IsLittleEndian) - DECLARE_INPUT_TYPES(Tagged, RawPtr, Int32, HoleyFloat64, Tagged) + DECLARE_INPUT_TYPES(Tagged, RawPtr, Int32, Float64, Tagged) void SetValueLocationConstraints(); void GenerateCode(MaglevAssembler*, const ProcessingState&); @@ -9582,7 +9600,7 @@ class StoreTrustedPointerFieldWithWriteBarrier public: explicit StoreTrustedPointerFieldWithWriteBarrier(uint64_t bitfield, int offset, - IndirectPointerTag tag, + TrustedPointerTag tag, StoreTaggedMode store_mode) : Base(bitfield | InitializingOrTransitioningField::encode( IsInitializingOrTransitioning(store_mode))), @@ -9595,7 +9613,7 @@ class StoreTrustedPointerFieldWithWriteBarrier DECLARE_INPUT_TYPES(Tagged, Tagged) int offset() const { return offset_; } - IndirectPointerTag tag() const { return tag_; } + TrustedPointerTag tag() const { return tag_; } bool initializing_or_transitioning() const { return InitializingOrTransitioningField::decode(bitfield()); } @@ -9616,7 +9634,7 @@ class StoreTrustedPointerFieldWithWriteBarrier using InitializingOrTransitioningField = NextBitField<bool, 1>; const int offset_; - const IndirectPointerTag tag_; + const TrustedPointerTag tag_; }; class LoadGlobal : public FixedInputValueNodeT<1, LoadGlobal> { @@ -11875,6 +11893,31 @@ class BranchIfInt32ToBooleanTrue void GenerateCode(MaglevAssembler*, const ProcessingState&); }; +// Fused form of BranchIfInt32ToBooleanTrue(Int32BitwiseAnd(value, mask)): +// branches to if_true when (value & mask) != 0. This lets the branch emit a +// single test-and-branch (tbnz/tst on arm64, test on x64) instead of a +// separate `and` and compare against zero. +class BranchIfInt32BitwiseAndNonZero + : public BranchControlNodeT<1, BranchIfInt32BitwiseAndNonZero> { + public: + explicit BranchIfInt32BitwiseAndNonZero(uint64_t bitfield, int32_t mask, + BasicBlockRef* if_true_refs, + BasicBlockRef* if_false_refs) + : Base(bitfield, if_true_refs, if_false_refs), mask_(mask) {} + + DECLARE_INPUTS(Value) + DECLARE_INPUT_TYPES(Int32) + + void SetValueLocationConstraints(); + void GenerateCode(MaglevAssembler*, const ProcessingState&); + void PrintParams(std::ostream&) const; + + int32_t mask() const { return mask_; } + + private: + int32_t mask_; +}; + class BranchIfIntPtrToBooleanTrue : public BranchControlNodeT<1, BranchIfIntPtrToBooleanTrue> { public: diff --git a/deps/v8/src/maglev/maglev-kna-map.h b/deps/v8/src/maglev/maglev-kna-map.h new file mode 100644 index 000000000000..3d3e6dce782d --- /dev/null +++ b/deps/v8/src/maglev/maglev-kna-map.h @@ -0,0 +1,230 @@ +// Copyright 2026 the V8 project 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 V8_MAGLEV_MAGLEV_KNA_MAP_H_ +#define V8_MAGLEV_MAGLEV_KNA_MAP_H_ + +#include <cstddef> +#include <type_traits> +#include <utility> + +#include "src/base/compiler-specific.h" +#include "src/maglev/maglev-ir.h" +#include "src/zone/zone-containers.h" +#include "src/zone/zone.h" + +namespace v8 { +namespace internal { +namespace maglev { + +struct DefaultMergeFunc { + template <typename Key, typename Value> + bool operator()(const Key&, const Value& lhs, const Value& rhs) const { + return lhs == rhs; + } +}; + +struct NeverKeepLhsOnly { + template <typename Key, typename Value> + bool operator()(const Key&, const Value&) const { + return false; + } +}; + +// Thin shim around ZoneMap<Key, Value> providing the KnaMap interface +// used by KnownNodeAspects. +template <typename Key, typename Value> +class KnaMap { + public: + using key_type = Key; + using mapped_type = Value; + using value_type = typename ZoneMap<Key, Value>::value_type; + using iterator = typename ZoneMap<Key, Value>::iterator; + using const_iterator = typename ZoneMap<Key, Value>::const_iterator; + + explicit KnaMap(Zone* zone) : map_(zone) {} + KnaMap(const KnaMap& other) V8_NOEXCEPT = default; + template <typename Func> + KnaMap(const KnaMap& other, Func&& mutate) : KnaMap(other) { + MutateValues(std::forward<Func>(mutate)); + } + KnaMap(KnaMap&& other) V8_NOEXCEPT = default; + KnaMap& operator=(const KnaMap& other) V8_NOEXCEPT = default; + KnaMap& operator=(KnaMap&& other) V8_NOEXCEPT = default; + ~KnaMap() = default; + + Zone* zone() const { return map_.get_allocator().zone(); } + + bool empty() const { return map_.empty(); } + size_t size() const { return map_.size(); } + + void clear() { map_.clear(); } + + const_iterator begin() const { return map_.begin(); } + const_iterator end() const { return map_.end(); } + + const_iterator find(const Key& k) const { return map_.find(k); } + iterator find(const Key& k) { return map_.find(k); } + bool contains(const Key& k) const { return map_.contains(k); } + + Value& operator[](const Key& k) { return map_[k]; } + + template <typename... Args> + std::pair<iterator, bool> try_emplace(const Key& k, Args&&... args) { + return map_.try_emplace(k, std::forward<Args>(args)...); + } + + template <typename... Args> + std::pair<iterator, bool> emplace(Args&&... args) { + return map_.emplace(std::forward<Args>(args)...); + } + + template <typename PairT = value_type> + std::pair<iterator, bool> insert(PairT&& entry) { + return map_.insert(std::forward<PairT>(entry)); + } + + size_t erase(const Key& k) { return map_.erase(k); } + iterator erase(const_iterator it) { return map_.erase(it); } + + // Visits entries in ascending key order, erasing those for which + // `pred(const Key&, Value&)` returns true. `pred` may mutate `Value&` in + // place for surviving entries. + template <typename Pred> + size_t EraseIf(Pred&& pred) { + return std::erase_if(map_, [&](value_type& entry) { + return pred(entry.first, entry.second); + }); + } + + // Visits all entries in ascending key order, allowing `fn(const Key&, + // Value&)` to mutate `Value&` in place without changing keys or erasing + // entries. + template <typename MutateFn> + void MutateValues(MutateFn&& fn) { + for (auto& [k, v] : map_) { + fn(k, v); + } + } + + // Rebuilds the map by applying `remap_key(const Key&)` to each key. If + // multiple keys map to the same normalized key, `combine(Value& dst, const + // Value& src)` merges subsequent colliding values into the first inserted + // value (visited in ascending original-key order). + template <typename RemapKeyFn, typename CombineFn> + void RemapKeys(RemapKeyFn&& remap_key, CombineFn&& combine) { + ZoneMap<Key, Value> remapped(zone()); + for (const auto& [k, v] : map_) { + auto [it, inserted] = remapped.try_emplace(remap_key(k), v); + if (!inserted) { + combine(it->second, v); + } + } + map_ = std::move(remapped); + } + + template <typename RemapKeyFn> + void RemapKeys(RemapKeyFn&& remap_key) { + RemapKeys(std::forward<RemapKeyFn>(remap_key), + [](Value& dst, const Value& src) { dst = src; }); + } + + // Destructively merges `rhs_map` into `*this` in ascending key order: + // - Keys in both maps: `merge(const Key&, Value& lhs, const Value& rhs)` may + // mutate `lhs` and returns true to keep the entry, or false to erase it. + // For `Value == ValueNode*`, if `merge` returns false and either value is + // an Identity wrapper, `lhs` is updated to `lhs->UnwrapIdentities()` and + // `merge` is retried with the unwrapped values. + // - Keys only in `*this`: `keep_lhs_only(const Key&, Value& lhs)` may mutate + // `lhs` and returns true to keep the entry, or false to erase it. + // - Keys only in `rhs_map`: dropped. + template <typename MergeFunc, typename KeepLhsOnlyFunc> + void DestructivelyMergeWith(const KnaMap& rhs_map, MergeFunc&& merge, + KeepLhsOnlyFunc&& keep_lhs_only) { + auto lhs_it = map_.begin(); + auto rhs_it = rhs_map.map_.begin(); + while (lhs_it != map_.end() && rhs_it != rhs_map.map_.end()) { + if (lhs_it->first < rhs_it->first) { + if (keep_lhs_only(lhs_it->first, lhs_it->second)) { + ++lhs_it; + } else { + lhs_it = map_.erase(lhs_it); + } + } else if (rhs_it->first < lhs_it->first) { + ++rhs_it; + } else { + bool keep_value = merge(lhs_it->first, lhs_it->second, rhs_it->second); + if constexpr (std::is_same_v<Value, ValueNode*>) { + if (!keep_value && lhs_it->second && rhs_it->second) { + auto l = lhs_it->second->UnwrapIdentities(); + auto r = rhs_it->second->UnwrapIdentities(); + if (l != lhs_it->second || r != rhs_it->second) { + lhs_it->second = l; + keep_value = merge(lhs_it->first, lhs_it->second, r); + } + } + } + if (keep_value) { + ++lhs_it; + } else { + lhs_it = map_.erase(lhs_it); + } + ++rhs_it; + } + } + if constexpr (std::is_same_v<std::decay_t<KeepLhsOnlyFunc>, + NeverKeepLhsOnly>) { + if (lhs_it != map_.end()) { + map_.erase(lhs_it, map_.end()); + } + } else { + while (lhs_it != map_.end()) { + if (keep_lhs_only(lhs_it->first, lhs_it->second)) { + ++lhs_it; + } else { + lhs_it = map_.erase(lhs_it); + } + } + } + } + + // Returns true iff every entry `(k, a_val)` in `*this` (excluding entries + // where `is_empty(a_val)` is true) has a matching key `k` in `bs` with + // `compare(a_val, b_val)` returning true. + template <typename CompareFunction, typename IsEmptyFunction = std::nullptr_t> + bool Includes(const KnaMap& bs, const CompareFunction& compare, + const IsEmptyFunction is_empty = nullptr) const { + const_iterator a = map_.begin(); + const_iterator b = bs.map_.begin(); + while (a != map_.end()) { + if constexpr (!std::is_same_v<IsEmptyFunction, std::nullptr_t>) { + if (is_empty(a->second)) { + ++a; + continue; + } + } + if (b == bs.map_.end()) return false; + while (b->first < a->first) { + ++b; + if (b == bs.map_.end()) return false; + } + if (!(a->first == b->first)) return false; + if (!compare(a->second, b->second)) { + return false; + } + ++a; + ++b; + } + return true; + } + + private: + ZoneMap<Key, Value> map_; +}; + +} // namespace maglev +} // namespace internal +} // namespace v8 + +#endif // V8_MAGLEV_MAGLEV_KNA_MAP_H_ diff --git a/deps/v8/src/maglev/maglev-kna-processor.h b/deps/v8/src/maglev/maglev-kna-processor.h index a94b42660821..70c0bea0db80 100644 --- a/deps/v8/src/maglev/maglev-kna-processor.h +++ b/deps/v8/src/maglev/maglev-kna-processor.h @@ -435,7 +435,7 @@ class RecomputeKnownNodeAspectsProcessor { } if (!node->property_key().is_none()) { auto& props_for_key = known_node_aspects().GetLoadedPropertiesForKey( - zone(), node->is_const(), node->property_key()); + zone(), node->constness(), node->property_key()); props_for_key[node->ValueInput().node()] = node; } return ProcessResult::kContinue; @@ -448,18 +448,22 @@ class RecomputeKnownNodeAspectsProcessor { } ProcessResult ProcessNode(LoadDataViewByteLength* node) { - bool is_const = !v8_flags.track_array_buffer_views; + PropertyConstness constness = v8_flags.track_array_buffer_views + ? PropertyConstness::kMutable + : PropertyConstness::kConst; auto& props_for_key = known_node_aspects().GetLoadedPropertiesForKey( - zone(), is_const, PropertyKey::ArrayBufferViewByteLength()); + zone(), constness, PropertyKey::ArrayBufferViewByteLength()); props_for_key[node->ValueInput().node()] = node; return ProcessResult::kContinue; } ProcessResult ProcessNode(LoadTypedArrayLength* node) { if (!IsRabGsabTypedArrayElementsKind(node->elements_kind())) { - bool is_const = !v8_flags.track_array_buffer_views; + PropertyConstness constness = v8_flags.track_array_buffer_views + ? PropertyConstness::kMutable + : PropertyConstness::kConst; auto& props_for_key = known_node_aspects().GetLoadedPropertiesForKey( - zone(), is_const, PropertyKey::TypedArrayLength()); + zone(), constness, PropertyKey::TypedArrayLength()); props_for_key[node->ValueInput().node()] = node; } return ProcessResult::kContinue; @@ -482,7 +486,7 @@ class RecomputeKnownNodeAspectsProcessor { // ... otherwise we try the properties cache. if (node->property_key().is_none()) return; auto& props_for_key = known_node_aspects().GetLoadedPropertiesForKey( - zone(), false, node->property_key()); + zone(), PropertyConstness::kMutable, node->property_key()); // We don't do any aliasing analysis, so stores clobber all other cached // loads of a property with that key. We only need to do this for // non-constant properties, since constant properties are known not to diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.cc b/deps/v8/src/maglev/maglev-known-node-aspects.cc index 63895d1f5f05..c1e990055163 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.cc +++ b/deps/v8/src/maglev/maglev-known-node-aspects.cc @@ -65,20 +65,6 @@ void TraceMerge(ValueNode* node, NodeInfo& lhs, const NodeInfo& rhs) { std::cout << " (stale=" << rhs.maps_are_stale() << ")" << std::endl; } -struct DefaultMergeFunc { - template <typename Key, typename Value> - bool operator()(const Key&, const Value& lhs, const Value& rhs) { - return lhs == rhs; - } -}; - -struct NeverKeepLhsOnly { - template <typename Key, typename Value> - bool operator()(const Key&, Value&) { - return false; - } -}; - // Destructively merges the right map into the left map, such that the left // map is mutated to become the result. Values that are in both maps are // passed to `merge` to be merged with each other -- the LHS here is expected @@ -88,60 +74,11 @@ struct NeverKeepLhsOnly { // ascending order. template <typename Key, typename Value, typename MergeFunc, typename KeepLhsOnlyFunc> -void DestructivelyMerge(ZoneMap<Key, Value>& lhs_map, - const ZoneMap<Key, Value>& rhs_map, MergeFunc&& merge, +void DestructivelyMerge(KnaMap<Key, Value>& lhs_map, + const KnaMap<Key, Value>& rhs_map, MergeFunc&& merge, KeepLhsOnlyFunc&& keep_lhs_only) { - // Walk the two maps in lock step. This relies on the fact that ZoneMaps are - // sorted. - typename ZoneMap<Key, Value>::iterator lhs_it = lhs_map.begin(); - typename ZoneMap<Key, Value>::const_iterator rhs_it = rhs_map.begin(); - while (lhs_it != lhs_map.end() && rhs_it != rhs_map.end()) { - if (lhs_it->first < rhs_it->first) { - if (keep_lhs_only(lhs_it->first, lhs_it->second)) { - ++lhs_it; - } else { - lhs_it = lhs_map.erase(lhs_it); - } - } else if (rhs_it->first < lhs_it->first) { - // Skip over elements that are only in RHS. - ++rhs_it; - } else { - // Apply the merge function to the values of the two iterators. If the - // function returns false, remove the value. - bool keep_value = merge(lhs_it->first, lhs_it->second, rhs_it->second); - if constexpr (std::is_same_v<decltype(lhs_it->second), ValueNode*>) { - if (!keep_value && lhs_it->second && rhs_it->second) { - auto l = lhs_it->second->UnwrapIdentities(); - auto r = rhs_it->second->UnwrapIdentities(); - if (l != lhs_it->second || r != rhs_it->second) { - lhs_it->second = l; - keep_value = merge(lhs_it->first, l, r); - } - } - } - if (keep_value) { - ++lhs_it; - } else { - lhs_it = lhs_map.erase(lhs_it); - } - ++rhs_it; - } - } - // The remaining LHS items have no RHS counterpart. - if constexpr (std::is_same_v<std::decay_t<KeepLhsOnlyFunc>, - NeverKeepLhsOnly>) { - if (lhs_it != lhs_map.end()) { - lhs_map.erase(lhs_it, lhs_map.end()); - } - } else { - while (lhs_it != lhs_map.end()) { - if (keep_lhs_only(lhs_it->first, lhs_it->second)) { - ++lhs_it; - } else { - lhs_it = lhs_map.erase(lhs_it); - } - } - } + lhs_map.DestructivelyMergeWith(rhs_map, std::forward<MergeFunc>(merge), + std::forward<KeepLhsOnlyFunc>(keep_lhs_only)); } // Destructively intersects the right map into the left map, such that the @@ -149,8 +86,8 @@ void DestructivelyMerge(ZoneMap<Key, Value>& lhs_map, // are in both maps are passed to the merging function to be merged with each // other -- again, the LHS here is expected to be mutated. template <typename Key, typename Value, typename MergeFunc = DefaultMergeFunc> -void DestructivelyIntersect(ZoneMap<Key, Value>& lhs_map, - const ZoneMap<Key, Value>& rhs_map, +void DestructivelyIntersect(KnaMap<Key, Value>& lhs_map, + const KnaMap<Key, Value>& rhs_map, MergeFunc&& func = DefaultMergeFunc()) { DestructivelyMerge(lhs_map, rhs_map, std::forward<MergeFunc>(func), NeverKeepLhsOnly()); @@ -241,28 +178,7 @@ template <typename As, typename Bs, typename CompareFunction, typename IsEmptyFunction = std::nullptr_t> bool AspectIncludes(const As& as, const Bs& bs, const CompareFunction& Compare, const IsEmptyFunction IsEmpty = nullptr) { - typename As::const_iterator a = as.begin(); - typename Bs::const_iterator b = bs.begin(); - while (a != as.end()) { - if constexpr (!std::is_same_v<IsEmptyFunction, std::nullptr_t>) { - if (IsEmpty(a->second)) { - ++a; - continue; - } - } - if (b == bs.end()) return false; - while (b->first < a->first) { - ++b; - if (b == bs.end()) return false; - } - if (!(a->first == b->first)) return false; - if (!Compare(a->second, b->second)) { - return false; - } - ++a; - ++b; - } - return true; + return as.Includes(bs, Compare, IsEmpty); } // Same as above but allows `as` to contain empty collections as values, which @@ -270,8 +186,8 @@ bool AspectIncludes(const As& as, const Bs& bs, const CompareFunction& Compare, template <typename As, typename Bs, typename Function> bool MaybeEmptyAspectIncludes(const As& as, const Bs& bs, const Function& Compare) { - return AspectIncludes<As, Bs, Function>(as, bs, Compare, - [](auto x) { return x.empty(); }); + return AspectIncludes<As, Bs, Function>( + as, bs, Compare, [](const auto& x) { return x.empty(); }); } template <typename As, typename Bs, typename Function> @@ -365,14 +281,13 @@ void KnownNodeAspects::Merge(const KnownNodeAspects& other, Zone* zone) { side_effects_require_invalidation_ = side_effects_require_invalidation; - auto merge_loaded_properties = - [](PropertyKey key, ZoneMap<ValueNode*, ValueNode*>& lhs, - const ZoneMap<ValueNode*, ValueNode*>& rhs) { - // Loaded properties are maps of maps, so just do the destructive - // intersection recursively. - DestructivelyIntersect(lhs, rhs); - return !lhs.empty(); - }; + auto merge_loaded_properties = [](PropertyKey key, PropertyObjectMap& lhs, + const PropertyObjectMap& rhs) { + // Loaded properties are maps of maps, so just do the destructive + // intersection recursively. + DestructivelyIntersect(lhs, rhs); + return !lhs.empty(); + }; DestructivelyIntersect(loaded_constant_properties_, other.loaded_constant_properties_, merge_loaded_properties); @@ -398,21 +313,15 @@ void KnownNodeAspects::MergeForLoop(const KnownNodeAspects& backedge, if (side_effects_require_invalidation_ && (loop_effects == nullptr || loop_effects->unstable_aspects_cleared || loop_effects->elements_kind_transitioned)) { - ZoneMap<ValueNode*, NodeInfo> cleared(zone); - for (auto& entry : node_infos_) { - cleared.emplace(entry.first, - NodeInfo::ClearUnstableMapsOnCopy{entry.second}); - } - node_infos_ = std::move(cleared); - side_effects_require_invalidation_ = false; + OnSideEffect(); } // TODO(jgruber): Recompute loop effects after lazy inlining, which can // replace effectful calls with pure operations. if (loop_has_effects) increment_effect_epoch(); - std::erase_if(available_expressions_, [&](const auto& entry) { - const AvailableExpression& expr = entry.second; + available_expressions_.EraseIf([&](uint32_t, + const AvailableExpression& expr) { DCHECK_NE(expr.effect_epoch, kEffectEpochOverflow); DCHECK_IMPLIES(!expr.node->Is<Identity>(), Node::needs_epoch_check(expr.node->opcode()) == @@ -432,15 +341,14 @@ void KnownNodeAspects::MergeForLoop(const KnownNodeAspects& backedge, lhs->UnwrapIdentities()->IsStructurallyEqualTo( rhs->UnwrapIdentities()); }; - auto merge_constant_properties = - [&](PropertyKey key, ZoneMap<ValueNode*, ValueNode*>& lhs, - const ZoneMap<ValueNode*, ValueNode*>& rhs) { - DestructivelyIntersect(lhs, rhs, - [&](ValueNode* obj, ValueNode* l, ValueNode* r) { - return l == r || same_load(l, r); - }); - return !lhs.empty(); - }; + auto merge_constant_properties = [&](PropertyKey key, PropertyObjectMap& lhs, + const PropertyObjectMap& rhs) { + DestructivelyIntersect(lhs, rhs, + [&](ValueNode* obj, ValueNode* l, ValueNode* r) { + return l == r || same_load(l, r); + }); + return !lhs.empty(); + }; ZoneSet<ValueNode*> objects_written(zone); if (keep_invariant_loads) { for (ValueNode* obj : loop_effects->objects_written) { @@ -464,25 +372,20 @@ void KnownNodeAspects::MergeForLoop(const KnownNodeAspects& backedge, if (!r) return l != nullptr && entry_invariant(obj); return l == r || (entry_invariant(obj) && same_load(l, r)); }; - auto merge_properties_of_key = - [&](PropertyKey key, ZoneMap<ValueNode*, ValueNode*>& lhs, - const ZoneMap<ValueNode*, ValueNode*>& rhs) { - if (filter) filter->StartKey(key); - DestructivelyMerge(lhs, rhs, merge_object_fact, keep_forward_fact); - return !lhs.empty(); - }; - auto keep_forward_properties_of_key = - [&](PropertyKey key, ZoneMap<ValueNode*, ValueNode*>& lhs) { - if (!filter || !filter->StartKey(key)) return false; - for (auto it = lhs.begin(); it != lhs.end();) { - if (keep_forward_fact(it->first, it->second)) { - ++it; - } else { - it = lhs.erase(it); - } - } - return !lhs.empty(); - }; + auto merge_properties_of_key = [&](PropertyKey key, PropertyObjectMap& lhs, + const PropertyObjectMap& rhs) { + if (filter) filter->StartKey(key); + DestructivelyMerge(lhs, rhs, merge_object_fact, keep_forward_fact); + return !lhs.empty(); + }; + auto keep_forward_properties_of_key = [&](PropertyKey key, + PropertyObjectMap& lhs) { + if (!filter || !filter->StartKey(key)) return false; + lhs.EraseIf([&](ValueNode* obj, ValueNode*& val) { + return !keep_forward_fact(obj, val); + }); + return !lhs.empty(); + }; DestructivelyIntersect(loaded_constant_properties_, backedge.loaded_constant_properties_, merge_constant_properties); @@ -530,56 +433,35 @@ void KnownNodeAspects::UnwrapIdentitiesAndPhisInKeys(Zone* zone) { }; // node_infos_ is keyed by value node. - NodeInfos remapped_infos(zone); - for (auto& entry : node_infos_) { - ValueNode* key = unwrap(entry.first); - auto it = remapped_infos.find(key); - if (it == remapped_infos.end()) { - remapped_infos.emplace(key, entry.second); - } else { - // A phi and its single input normalize to the same node; both entries - // then describe the same value, so combine their facts. - it->second.CombineSameValueFrom(entry.second); - } - } - node_infos_ = std::move(remapped_infos); + node_infos_.RemapKeys(unwrap, [](NodeInfo& dst, const NodeInfo& src) { + // A phi and its single input normalize to the same node; both entries + // then describe the same value, so combine their facts. + dst.CombineSameValueFrom(src); + }); // Cached property loads: key -> object -> value. Only the object is a node // key; values are left as-is (the merge already unwraps identities on value // comparison, and available_expressions_ is not remapped at all). auto remap_loaded_properties = [&](LoadedPropertyMap& map) { - LoadedPropertyMap remapped(zone); - for (auto& [property_key, objects] : map) { - ZoneMap<ValueNode*, ValueNode*> remapped_objects(zone); - for (auto& [object, value] : objects) { - remapped_objects[unwrap(object)] = value; - } - remapped.emplace(property_key, std::move(remapped_objects)); - } - map = std::move(remapped); + map.MutateValues([&](PropertyKey, PropertyObjectMap& objects) { + objects.RemapKeys(unwrap); + }); }; remap_loaded_properties(loaded_properties_); remap_loaded_properties(loaded_constant_properties_); - { - ZoneMap<std::pair<ValueNode*, ValueNode*>, ValueNode*> remapped(zone); - for (auto& [key, value] : loaded_tagged_keyed_properties_) { - remapped[{unwrap(key.first), unwrap(key.second)}] = value; - } - loaded_tagged_keyed_properties_ = std::move(remapped); - } + loaded_tagged_keyed_properties_.RemapKeys( + [&](std::pair<ValueNode*, ValueNode*> key) { + return std::make_pair(unwrap(key.first), unwrap(key.second)); + }); // Context slot loads: (context node, offset) -> value. Only the context node // in the key is remapped. - auto remap_context_slots = - [&](ZoneMap<LoadedContextSlotsKey, ValueNode*>& m) { - ZoneMap<LoadedContextSlotsKey, ValueNode*> remapped(zone); - for (auto& [key, value] : m) { - remapped[LoadedContextSlotsKey{unwrap(std::get<0>(key)), - std::get<1>(key)}] = value; - } - m = std::move(remapped); - }; + auto remap_context_slots = [&](LoadedContextSlots& m) { + m.RemapKeys([&](const LoadedContextSlotsKey& key) { + return LoadedContextSlotsKey{unwrap(std::get<0>(key)), std::get<1>(key)}; + }); + }; remap_context_slots(loaded_context_constants_); remap_context_slots(loaded_context_slots_); } @@ -589,22 +471,36 @@ void KnownNodeAspects::UpdateMayHaveAliasingContexts( ValueNode* context) { if (may_have_aliasing_contexts_ == ContextSlotLoadsAlias::kAlways) return; - while (true) { - if (auto load_prev_ctxt = context->TryCast<LoadContextSlotNoCells>()) { - DCHECK_EQ(load_prev_ctxt->offset(), - Context::OffsetOfElementAt(Context::PREVIOUS_INDEX)); - // Recurse until we find the root. - context = load_prev_ctxt->input(0).node(); - continue; - } - break; - } - switch (context->opcode()) { + case Opcode::kLoadContextSlotNoCells: + do { + LoadContextSlotNoCells* load_prev_ctxt = + context->Cast<LoadContextSlotNoCells>(); + DCHECK_EQ(load_prev_ctxt->offset(), + Context::OffsetOfElementAt(Context::PREVIOUS_INDEX)); + context = load_prev_ctxt->input(0).node(); + } while (context->Is<LoadContextSlotNoCells>()); + // Walking PREVIOUS_INDEX loads is only non-aliasing if rooted at the + // incoming context InitialValue, since any other root (such as an + // allocated context or a HeapConstant) can have its parent context + // represented directly by a distinct ValueNode in the graph. + if (!context->Is<InitialValue>()) { + may_have_aliasing_contexts_ = ContextSlotLoadsAlias::kAlways; + break; + } + [[fallthrough]]; case Opcode::kInitialValue: - may_have_aliasing_contexts_ = ContextSlotLoadsAliasMerge( - may_have_aliasing_contexts_, - ContextSlotLoadsAlias::kOnlyLoadsRelativeToCurrentContext); + // In OSR, local registers also start as InitialValues and may hold outer + // contexts saved by PushContext, which can alias PREVIOUS_INDEX loads + // from the incoming context. + if (context->Cast<InitialValue>()->source() == + interpreter::Register::current_context()) { + may_have_aliasing_contexts_ = ContextSlotLoadsAliasMerge( + may_have_aliasing_contexts_, + ContextSlotLoadsAlias::kOnlyLoadsRelativeToCurrentContext); + } else { + may_have_aliasing_contexts_ = ContextSlotLoadsAlias::kAlways; + } break; case Opcode::kHeapConstant: may_have_aliasing_contexts_ = ContextSlotLoadsAliasMerge( @@ -702,13 +598,12 @@ void KnownNodeAspects::ClearUnstableNodeAspectsForElementsTransition( // nodes whose map is unknown or already stale). auto it = loaded_properties_.find(PropertyKey::Elements()); if (it == loaded_properties_.end()) return; - bool dropped_any = - std::erase_if(it->second, [&](const auto& entry) { - const NodeInfo* info = TryGetInfoWithFreshMaps(entry.first); - if (!info) return true; - const auto& maps = info->possible_maps(); - return std::any_of(maps.begin(), maps.end(), MaybeAliases); - }) > 0; + bool dropped_any = it->second.EraseIf([&](ValueNode* obj, ValueNode* const&) { + const NodeInfo* info = TryGetInfoWithFreshMaps(obj); + if (!info) return true; + const auto& maps = info->possible_maps(); + return std::any_of(maps.begin(), maps.end(), MaybeAliases); + }) > 0; if (dropped_any && V8_UNLIKELY(v8_flags.trace_maglev_kna && is_tracing_enabled)) { std::cout << kRed << "[KNA] ElementsTransition: Drop aliased [Elements]" @@ -775,10 +670,9 @@ KnownNodeAspects::KnownNodeAspects(const KnownNodeAspects& other, side_effects_require_invalidation_ = other.side_effects_require_invalidation_; } else { - for (const auto& it : other.node_infos_) { - node_infos_.emplace(it.first, - NodeInfo::ClearUnstableMapsOnCopy{it.second}); - } + node_infos_ = NodeInfos(other.node_infos_, [](ValueNode*, NodeInfo& info) { + info.OnSideEffect(); + }); } // LINT.IfChange(CloneForLoopHeader) if (optimistic_initial_state && !loop_effects->unstable_aspects_cleared) { @@ -791,16 +685,15 @@ KnownNodeAspects::KnownNodeAspects(const KnownNodeAspects& other, } else { LoopInvariantPropertyFilter filter(loop_effects, loop_effects->objects_written, this); - for (auto loaded_key : other.loaded_properties_) { - if (!filter.StartKey(loaded_key.first)) continue; - auto& props_for_key = - loaded_properties_.try_emplace(loaded_key.first, zone) - .first->second; - for (auto loaded_obj : loaded_key.second) { - if (!filter.ObjectInvariant(loaded_obj.first)) continue; - props_for_key.emplace(loaded_obj); - } - } + loaded_properties_ = other.loaded_properties_; + loaded_properties_.EraseIf( + [&](const PropertyKey& key, PropertyObjectMap& props_for_key) { + if (!filter.StartKey(key)) return true; + props_for_key.EraseIf([&](ValueNode* obj, ValueNode* val) { + return !filter.ObjectInvariant(obj); + }); + return false; + }); } if (loop_effects->context_slot_written.empty()) { loaded_context_slots_ = other.loaded_context_slots_; @@ -915,9 +808,11 @@ bool KnownNodeAspects::IsCompatibleWithLoopHeader( return false; } - if (!MaybeEmptyAspectIncludes( - loop_header.loaded_properties_, loaded_properties_, - [](auto a, auto b) { return AspectIncludes(a, b, SameValue); })) { + if (!MaybeEmptyAspectIncludes(loop_header.loaded_properties_, + loaded_properties_, + [](const auto& a, const auto& b) { + return AspectIncludes(a, b, SameValue); + })) { if (V8_UNLIKELY(v8_flags.trace_maglev_loop_speeling)) { std::cout << "KNA after loop has incompatible loaded_properties\n"; } @@ -945,23 +840,21 @@ KnownNodeAspects::ClearAliasedContextSlotsFor(Graph* graph, ValueNode* context, UpdateMayHaveAliasingContexts(graph->broker(), graph->broker()->local_isolate(), context); if (may_have_aliasing_contexts() == ContextSlotLoadsAlias::kAlways) { - for (auto& cache : loaded_context_slots_) { - int cached_offset = std::get<int>(cache.first); - ValueNode* cached_context = std::get<ValueNode*>(cache.first); - if (cached_offset == offset && cached_context != context) { - if (graph->ContextMayAlias(cached_context, {}) && - cache.second != value) { - if (V8_UNLIKELY(v8_flags.trace_maglev_kna)) { - std::cout << kRed << "[KNA] Clear context slot: " - << PrintNodeLabel(std::get<ValueNode*>(cache.first)) - << "[" << offset << "] alias " << PrintNode(value) - << kReset << std::endl; - } - cache.second = nullptr; - aliased_slots_.push_back(cache.first); + loaded_context_slots_.MutateValues([&](const LoadedContextSlotsKey& key, + ValueNode*& cached_val) { + int cached_offset = std::get<int>(key); + ValueNode* cached_context = std::get<ValueNode*>(key); + if (cached_offset == offset && cached_context != context && + cached_val != value && graph->ContextMayAlias(cached_context, {})) { + if (V8_UNLIKELY(v8_flags.trace_maglev_kna)) { + std::cout << kRed << "[KNA] Clear context slot: " + << PrintNodeLabel(cached_context) << "[" << offset + << "] alias " << PrintNode(value) << kReset << std::endl; } + cached_val = nullptr; + aliased_slots_.push_back(key); } - } + }); } return aliased_slots_; } @@ -1032,7 +925,7 @@ bool KnownNodeAspects::MarkSingleMapAsStale(ValueNode* node, } #ifdef DEBUG -bool IsStringRootIndex(RootIndex index) { +V8_EXPORT_PRIVATE bool IsStringRootIndex(RootIndex index) { if (index > RootIndex::kLastReadOnlyRoot) return false; ReadOnlyRoots roots = GetReadOnlyRoots(); Tagged<Object> obj = roots.object_at(index); diff --git a/deps/v8/src/maglev/maglev-known-node-aspects.h b/deps/v8/src/maglev/maglev-known-node-aspects.h index dd1ce8cc3858..3e6b955c892e 100644 --- a/deps/v8/src/maglev/maglev-known-node-aspects.h +++ b/deps/v8/src/maglev/maglev-known-node-aspects.h @@ -11,6 +11,7 @@ #include "src/base/logging.h" #include "src/common/globals.h" #include "src/maglev/maglev-ir.h" +#include "src/maglev/maglev-kna-map.h" #include "src/maglev/maglev-node-type.h" #include "src/objects/contexts.h" @@ -23,14 +24,18 @@ struct LoopEffects; class KnownNodeAspects; class TraceLogger; -enum class EnsureTypeResult { kAlreadyHadType, kTypeUpdated, kContradiction }; +enum class V8_NODISCARD EnsureTypeResult { + kAlreadyHadType, + kTypeUpdated, + kContradiction +}; using UpdateTypeOnContradiction = base::StrongAlias<struct UpdateTypeOnContradictionTag, bool>; using PossibleMaps = compiler::ZoneRefSet<Map>; #ifdef DEBUG -bool IsStringRootIndex(RootIndex index); +V8_EXPORT_PRIVATE bool IsStringRootIndex(RootIndex index); inline bool IsInternalizedStringConstant(ValueNode* node) { if (auto constant = node->TryCast<HeapConstant>()) { @@ -57,20 +62,6 @@ class NodeInfo { public: NodeInfo() = default; - struct ClearUnstableMapsOnCopy { - const NodeInfo& val; - }; - explicit NodeInfo(ClearUnstableMapsOnCopy other) V8_NOEXCEPT { - type_ = other.val.type_; - alternative_ = other.val.alternative_; - if (other.val.possible_maps_are_known_) { - possible_maps_ = other.val.possible_maps_; - possible_maps_are_known_ = true; - any_map_is_unstable_ = other.val.any_map_is_unstable_; - OnSideEffect(); - } - } - NodeType type() const { return type_; } void set_type(NodeType type) { type_ = type; } NodeType IntersectType(NodeType other) { @@ -378,7 +369,7 @@ class NodeInfo { class KnownNodeAspects { public: // Permanently valid if checked in a dominator. - using NodeInfos = ZoneMap<ValueNode*, NodeInfo>; + using NodeInfos = KnaMap<ValueNode*, NodeInfo>; // Copy constructor is defaulted but private so that we explicitly call the // Clone method. @@ -428,9 +419,8 @@ class KnownNodeAspects { // same map. Unstable maps can also transition to stable ones, so we have to // clear _all_ maps for a node if it had _any_ unstable map. if (!side_effects_require_invalidation_) return; - for (auto& it : node_infos_) { - it.second.OnSideEffect(); - } + node_infos_.MutateValues( + [](ValueNode*, NodeInfo& info) { info.OnSideEffect(); }); side_effects_require_invalidation_ = false; } @@ -438,9 +428,9 @@ class KnownNodeAspects { bool MarkMapsStaleIfAny(const Function& condition) { if (!side_effects_require_invalidation_) return false; bool any_stale = false; - for (auto& it : node_infos_) { - any_stale |= it.second.MarkMapsStaleIfAny(condition); - } + node_infos_.MutateValues([&](ValueNode*, NodeInfo& info) { + any_stale |= info.MarkMapsStaleIfAny(condition); + }); return any_stale; } @@ -507,8 +497,8 @@ class KnownNodeAspects { return {}; } - bool CheckType(compiler::JSHeapBroker* broker, ValueNode* node, NodeType type, - NodeType* current_type = nullptr) { + V8_NODISCARD bool CheckType(compiler::JSHeapBroker* broker, ValueNode* node, + NodeType type, NodeType* current_type = nullptr) { NodeType static_type = node->GetStaticType(broker); if (current_type) *current_type = static_type; if (NodeTypeIs(static_type, type)) return true; @@ -519,8 +509,9 @@ class KnownNodeAspects { return NodeTypeIs(node_info->type(), type); } - NodeType CheckTypes(compiler::JSHeapBroker* broker, ValueNode* node, - std::initializer_list<NodeType> types) { + V8_NODISCARD NodeType CheckTypes(compiler::JSHeapBroker* broker, + ValueNode* node, + std::initializer_list<NodeType> types) { const NodeInfo* node_info = TryGetInfoFor(node); for (NodeType type : types) { if (node->StaticTypeIs(broker, type)) return type; @@ -587,11 +578,11 @@ class KnownNodeAspects { // Maps key->object->value, so that stores to a key can invalidate all loads // of that key (in case the objects are aliasing). - using LoadedPropertyMap = - ZoneMap<PropertyKey, ZoneMap<ValueNode*, ValueNode*>>; + using PropertyObjectMap = KnaMap<ValueNode*, ValueNode*>; + using LoadedPropertyMap = KnaMap<PropertyKey, PropertyObjectMap>; using LoadedContextSlotsKey = std::tuple<ValueNode*, int>; - using LoadedContextSlots = ZoneMap<LoadedContextSlotsKey, ValueNode*>; + using LoadedContextSlots = KnaMap<LoadedContextSlotsKey, ValueNode*>; ValueNode* TryFindLoadedProperty(ValueNode* lookup_start_object, PropertyKey name) { @@ -603,20 +594,24 @@ class KnownNodeAspects { lookup_start_object, name); } ValueNode* TryFindLoadedProperty(ValueNode* lookup_start_object, - PropertyKey name, bool is_const) { - if (is_const) { - return TryFindLoadedConstantProperty(lookup_start_object, name); + PropertyKey name, + PropertyConstness constness) { + switch (constness) { + case PropertyConstness::kConst: + return TryFindLoadedConstantProperty(lookup_start_object, name); + case PropertyConstness::kMutable: + return TryFindLoadedProperty(lookup_start_object, name); } - return TryFindLoadedProperty(lookup_start_object, name); } - ZoneMap<ValueNode*, ValueNode*>& GetLoadedPropertiesForKey(Zone* zone, - bool is_const, - PropertyKey key) { - LoadedPropertyMap& properties = - is_const ? loaded_constant_properties_ : loaded_properties_; + PropertyObjectMap& GetLoadedPropertiesForKey(Zone* zone, + PropertyConstness constness, + PropertyKey key) { + LoadedPropertyMap& properties = constness == PropertyConstness::kConst + ? loaded_constant_properties_ + : loaded_properties_; // Try to get loaded_properties[key] if it already exists, otherwise - // construct loaded_properties[key] = ZoneMap{zone()}. + // construct loaded_properties[key] = PropertyObjectMap{zone}. return properties.try_emplace(key, zone).first->second; } @@ -922,6 +917,9 @@ class KnownNodeAspects { NodeBase* node; uint32_t effect_epoch; }; + using AvailableExpressionsMap = KnaMap<uint32_t, AvailableExpression>; + using TaggedKeyedPropertiesMap = + KnaMap<std::pair<ValueNode*, ValueNode*>, ValueNode*>; // These can call GetTypeUnchecked directly. Other uses should ideally go // through MaglevReducer::GetType or similar and add type assertions if @@ -974,14 +972,13 @@ class KnownNodeAspects { // does not pass PreservesTaggedKeyedProperties. Bounded by // kMaxTaggedKeyedProperties, since the map is copied at every clone. static constexpr size_t kMaxTaggedKeyedProperties = 100; - ZoneMap<std::pair<ValueNode*, ValueNode*>, ValueNode*> - loaded_tagged_keyed_properties_; + TaggedKeyedPropertiesMap loaded_tagged_keyed_properties_; // Unconditionally valid across side-effecting calls. - ZoneMap<std::tuple<ValueNode*, int>, ValueNode*> loaded_context_constants_; + LoadedContextSlots loaded_context_constants_; // Flushed after side-effecting calls. LoadedContextSlots loaded_context_slots_; // For CSE. - ZoneMap<uint32_t, AvailableExpression> available_expressions_; + AvailableExpressionsMap available_expressions_; // This is an optimization. We track whether any NodeInfos require work on // side effects. If not, we don't even iterate over NodeInfos. bool side_effects_require_invalidation_; diff --git a/deps/v8/src/maglev/maglev-node-type.cc b/deps/v8/src/maglev/maglev-node-type.cc index 57fd2ca59bec..85b23c2fe53e 100644 --- a/deps/v8/src/maglev/maglev-node-type.cc +++ b/deps/v8/src/maglev/maglev-node-type.cc @@ -148,7 +148,7 @@ std::ostream& operator<<(std::ostream& out, const NodeType& type) { #undef CASE default: #define CASE(Name, _) \ - if (NodeTypeIsForPrinting(NodeType::k##Name, type)) { \ + if (NodeTypeCanBeForPrinting(type, NodeType::k##Name)) { \ if constexpr (NodeType::k##Name != NodeType::kUnknown) { \ out << #Name "|"; \ } \ diff --git a/deps/v8/src/maglev/maglev-node-type.h b/deps/v8/src/maglev/maglev-node-type.h index 3e46224b1bd9..cca3af6b94cb 100644 --- a/deps/v8/src/maglev/maglev-node-type.h +++ b/deps/v8/src/maglev/maglev-node-type.h @@ -135,19 +135,19 @@ inline constexpr bool NodeTypeIs( NodeTypeInt right = static_cast<NodeTypeInt>(to_check); return (static_cast<NodeTypeInt>(type) & (~right)) == 0; } -inline constexpr bool NodeTypeIsForPrinting(NodeType type, NodeType to_check) { - // Like NodeTypeIs, but without the DCHECKs, since non-standalone types can be - // part of larger types and we still need to print them individually, which - // will trigger the DCHECKs of NodeTypeIs. - NodeTypeInt right = static_cast<NodeTypeInt>(to_check); - return (static_cast<NodeTypeInt>(type) & (~right)) == 0; -} // TODO(dmercadier): similarly to NodeTypeIs, try to disallow kNone here because // it can lead to confusing results. -inline constexpr bool NodeTypeCanBe(NodeType type, NodeType to_check, - bool allow_standalone = false) { - DCHECK_IMPLIES(!allow_standalone, !NodeTypeIsNeverStandalone(type)); - DCHECK_IMPLIES(!allow_standalone, !NodeTypeIsNeverStandalone(to_check)); +inline constexpr bool NodeTypeCanBe(NodeType type, NodeType to_check) { + DCHECK(!NodeTypeIsNeverStandalone(type)); + DCHECK(!NodeTypeIsNeverStandalone(to_check)); + NodeTypeInt right = static_cast<NodeTypeInt>(to_check); + return (static_cast<NodeTypeInt>(type) & (right)) != 0; +} +inline constexpr bool NodeTypeCanBeForPrinting(NodeType type, + NodeType to_check) { + // Like NodeTypeCanBe, but without the DCHECKs, since non-standalone types can + // be part of larger types and we still need to print them individually, which + // will trigger the DCHECKs of NodeTypeCanBe. NodeTypeInt right = static_cast<NodeTypeInt>(to_check); return (static_cast<NodeTypeInt>(type) & (right)) != 0; } diff --git a/deps/v8/src/maglev/maglev-post-hoc-optimizations-processors.h b/deps/v8/src/maglev/maglev-post-hoc-optimizations-processors.h index 26245b115cba..f166c2e68fc2 100644 --- a/deps/v8/src/maglev/maglev-post-hoc-optimizations-processors.h +++ b/deps/v8/src/maglev/maglev-post-hoc-optimizations-processors.h @@ -675,11 +675,7 @@ class ReachableExceptionHandlerTracker { private: BlockProcessResult AbortBlock(BasicBlock* block) { - ControlNode* control = block->reset_control_node(); - block->RemovePredecessorFollowing(control); - control->OverwriteWith<Abort>()->set_reason(AbortReason::kUnreachable); - block->set_deferred(true); - block->set_control_node(control); + block->OverwriteControlWithAbort(AbortReason::kUnreachable); block->mark_dead(); graph_->set_may_have_unreachable_blocks(); return BlockProcessResult::kSkip; diff --git a/deps/v8/src/maglev/maglev-pre-regalloc-codegen-processors.h b/deps/v8/src/maglev/maglev-pre-regalloc-codegen-processors.h index e96618b302f4..668ef199a22f 100644 --- a/deps/v8/src/maglev/maglev-pre-regalloc-codegen-processors.h +++ b/deps/v8/src/maglev/maglev-pre-regalloc-codegen-processors.h @@ -163,12 +163,12 @@ class MaxCallDepthProcessor { } case DeoptFrame::FrameType::kBuiltinContinuationFrame: { // PC + FP + Closure + Params + Context - const RegisterConfiguration* config = RegisterConfiguration::Default(); + const BuiltinContinuationDeoptFrame& frame = + deopt_frame->as_builtin_continuation(); auto info = BuiltinContinuationFrameInfo::Conservative( - deopt_frame->as_builtin_continuation().parameters().length(), - Builtins::CallInterfaceDescriptorFor( - deopt_frame->as_builtin_continuation().builtin_id()), - config); + frame.translation_height(), + Builtins::CallInterfaceDescriptorFor(frame.builtin_id()), + RegisterConfiguration::Default()); return info.frame_size_in_bytes(); } } diff --git a/deps/v8/src/maglev/maglev-reducer-inl.h b/deps/v8/src/maglev/maglev-reducer-inl.h index 413713365738..4bb1704d2ae9 100644 --- a/deps/v8/src/maglev/maglev-reducer-inl.h +++ b/deps/v8/src/maglev/maglev-reducer-inl.h @@ -575,8 +575,8 @@ std::optional<ValueNode*> MaglevReducer<BaseT>::TryGetConstantAlternative( template <typename BaseT> ReduceResult MaglevReducer<BaseT>::BuildLoadTaggedField( - ValueNode* object, uint32_t offset, NodeType type, bool is_const, - PropertyKey key, IsArrayLength is_array_length, + ValueNode* object, uint32_t offset, NodeType type, + PropertyConstness constness, PropertyKey key, IsArrayLength is_array_length, compiler::OptionalMapRef stable_field_map) { if constexpr (ReducerBaseWithAllocationTracking<BaseT>) { if (std::optional<ValueNode*> val = @@ -584,7 +584,7 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadTaggedField( return *val; } } - return AddNewNode<LoadTaggedField>({object}, offset, type, is_const, key, + return AddNewNode<LoadTaggedField>({object}, offset, type, constness, key, is_array_length, stable_field_map); } @@ -594,6 +594,7 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadFixedDoubleArrayElement( // We won't try to reason about the type of the elements array and thus also // cannot end up with an empty type for it. DCHECK(!IsEmptyNodeType(GetType(elements))); + RETURN_IF_ABORT(AbortIfInvalidFixedArrayIndex<FixedDoubleArray>(index)); if constexpr (ReducerBaseWithAllocationTracking<BaseT>) { if (auto constant = TryGetInt32Constant(index)) { RETURN_IF_DONE(base_->TryBuildLoadFixedDoubleArrayElementFromAllocation( @@ -664,7 +665,7 @@ ReduceResult MaglevReducer<BaseT>::BuildStoreTaggedFieldNoWriteBarrier( template <typename BaseT> ReduceResult MaglevReducer<BaseT>::BuildStoreTrustedPointerField( - ValueNode* object, ValueNode* value, int offset, IndirectPointerTag tag, + ValueNode* object, ValueNode* value, int offset, TrustedPointerTag tag, StoreTaggedMode store_mode) { #ifdef V8_ENABLE_SANDBOX return AddNewNode<StoreTrustedPointerFieldWithWriteBarrier>( @@ -742,6 +743,83 @@ MaybeAssignedFlag MaglevReducer<BaseT>::GetContextMaybeAssigned( return scope_info.ContextLocalMaybeAssignedFlag(var_index); } +template <typename BaseT> +ValueNode* MaglevReducer<BaseT>::TryGetParentContext(ValueNode* node) { + if (CreateFunctionContext* n = node->TryCast<CreateFunctionContext>()) { + return n->ContextInput().node()->UnwrapIdentitiesAndPhis(); + } + + if (InlinedAllocation* alloc = node->TryCast<InlinedAllocation>()) { + return alloc->object() + ->get(Context::OffsetOfElementAt(Context::PREVIOUS_INDEX)) + ->UnwrapIdentitiesAndPhis(); + } + + if (CallRuntime* n = node->TryCast<CallRuntime>()) { + switch (n->function_id()) { + case Runtime::kPushBlockContext: + case Runtime::kPushCatchContext: + case Runtime::kNewFunctionContext: + return n->ContextInput().node()->UnwrapIdentitiesAndPhis(); + default: + break; + } + } + + return nullptr; +} + +template <typename BaseT> +MaybeReduceResult MaglevReducer<BaseT>::TryGetConstantContextValue( + ValueNode* context, int offset, MaybeAssignedFlag assigned, + VariableMode mode) { + if (offset == Context::OffsetOfElementAt(Context::PREVIOUS_INDEX)) { + if (ValueNode* parent = TryGetParentContext(context)) { + return parent; + } + } + + auto context_ref = TryGetConstant<Context>(context); + if (!context_ref) return {}; + + int index = (offset - Context::OffsetOfElementAt(0)) / kTaggedSize; + DCHECK_EQ(Context::OffsetOfElementAt(index), offset); + compiler::OptionalObjectRef maybe_slot_value = + context_ref->get(broker(), index); + if (!maybe_slot_value.has_value()) return {}; + + compiler::ObjectRef slot_value = maybe_slot_value.value(); + if (assigned == kMaybeAssigned) { + if (!slot_value.IsContextCell() || slot_value.IsUndefinedContextCell()) { + return {}; + } + compiler::ContextCellRef slot_ref = slot_value.AsContextCell(); + if (slot_ref.state() != ContextCell::kConst) return {}; + maybe_slot_value = slot_ref.tagged_value(broker()); + if (!maybe_slot_value.has_value()) return {}; + broker()->dependencies()->DependOnContextCell(slot_ref, + ContextCell::kConst); + slot_value = maybe_slot_value.value(); + } else if (slot_value.IsHeapObject()) { + // Even though the context slot is immutable, the context might have escaped + // before the function to which it belongs has initialized the slot. We + // must be conservative and check if the value in the slot is currently the + // hole or undefined. Only if it is neither of these, can we be sure that it + // won't change anymore. + // + // See also: JSContextSpecialization::ReduceJSLoadContextNoCell. + if (slot_value.IsTdzHole()) return {}; + if (mode == VariableMode::kVar && slot_value.IsUndefined()) return {}; + if (IsPrivateMethodOrAccessorVariableMode(mode) && + slot_value.IsUndefined()) { + return {}; + } + DCHECK(!slot_value.IsContextCell()); + } + + return GetConstant(slot_value); +} + template <typename BaseT> ReduceResult MaglevReducer<BaseT>::BuildStoreMap(ValueNode* object, compiler::MapRef map, @@ -1036,11 +1114,12 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadJSArrayLength( ValueNode* length; GET_VALUE_OR_ABORT( - length, BuildLoadTaggedField( - js_array, offsetof(JSArray, length_), length_type, false, - broker()->length_string(), IsArrayLength::kYes)); - RecordKnownProperty(js_array, broker()->length_string(), length, false, - compiler::AccessMode::kLoad); + length, + BuildLoadTaggedField(js_array, offsetof(JSArray, length_), length_type, + PropertyConstness::kMutable, + broker()->length_string(), IsArrayLength::kYes)); + RecordKnownProperty(js_array, broker()->length_string(), length, + PropertyConstness::kMutable, compiler::AccessMode::kLoad); return length; } @@ -1098,9 +1177,10 @@ MaybeReduceResult MaglevReducer<BaseT>::TryWithArrayIterationArgs( args.count() > 0 ? args[0] : GetRootConstant(RootIndex::kUndefinedValue); - ValueNode* from_index = GetInt32Constant(0); - if (args.count() > 1) { - GET_VALUE_OR_ABORT(from_index, GetInt32(args[1])); + ValueNode* from_index = GetValueOrZeroIfUndefined(args[1]); + if (!from_index->Is<Int32Constant>() || + from_index->Cast<Int32Constant>()->value() != 0) { + GET_VALUE_OR_ABORT(from_index, GetInt32(from_index)); GET_VALUE_OR_ABORT( from_index, Select( @@ -1245,13 +1325,13 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadElements( } ValueNode* elements; - GET_VALUE_OR_ABORT( - elements, - BuildLoadTaggedField(object, offsetof(JSObject, elements_), - NodeType::kAnyHeapObject, - /*is_const=*/false, PropertyKey::Elements())); - RecordKnownProperty(object, PropertyKey::Elements(), elements, false, - compiler::AccessMode::kLoad); + GET_VALUE_OR_ABORT(elements, + BuildLoadTaggedField(object, offsetof(JSObject, elements_), + NodeType::kAnyHeapObject, + PropertyConstness::kMutable, + PropertyKey::Elements())); + RecordKnownProperty(object, PropertyKey::Elements(), elements, + PropertyConstness::kMutable, compiler::AccessMode::kLoad); if (is_turbolev() && kind.has_value()) { // We record a map hint for Turbolev so that LateEscapeAnalysis knows that // we just loaded an elements array, which means that it can't alias with @@ -1285,22 +1365,20 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReduceArrayPrototypeAt( return TryWithFastArrayElements( "Array.prototype.at", args, [&](ElementsKind elements_kind, ValueNode* elements, ValueNode* length) { - ValueNode* index = nullptr; - if (args.count() == 0) { - // Index is the undefined object. ToIntegerOrInfinity(undefined) = 0. - index = GetInt32Constant(0); - } else { - GET_VALUE_OR_ABORT( - index, Select( - [&](auto& branch) -> BranchResult { - return BuildBranchIfInt32Compare( - branch, Operation::kLessThan, args[0], - GetInt32Constant(0)); - }, - [&]() -> ReduceResult { - return AddNewNode<Int32Add>({args[0], length}); - }, - [&]() -> ReduceResult { return args[0]; })); + ValueNode* index = GetValueOrZeroIfUndefined(args[0]); + if (!index->Is<Int32Constant>() || + index->Cast<Int32Constant>()->value() != 0) { + GET_VALUE_OR_ABORT(index, + Select( + [&](auto& branch) -> BranchResult { + return BuildBranchIfInt32Compare( + branch, Operation::kLessThan, index, + GetInt32Constant(0)); + }, + [&]() -> ReduceResult { + return AddNewNode<Int32Add>({index, length}); + }, + [&]() -> ReduceResult { return index; })); } return Select( @@ -1318,6 +1396,9 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReduceArrayPrototypeAt( [&]() -> ReduceResult { ValueNode* element; if (elements_kind == HOLEY_DOUBLE_ELEMENTS) { + RETURN_IF_ABORT( + AbortIfInvalidFixedArrayIndex<FixedDoubleArray>( + index)); GET_VALUE_OR_ABORT( element, AddNewNode<LoadHoleyFixedDoubleArrayElement>( {elements, index})); @@ -2101,11 +2182,11 @@ std::optional<Float64> MaglevReducer<BaseT>::TryGetFloatConstantImpl( case Opcode::kRootConstant: { Tagged<Object> root_object = broker()->local_isolate()->root(value->Cast<RootConstant>()->index()); - if (NodeTypeIs(NodeType::kBoolean, assumed_input_type) && + if (NodeTypeCanBe(assumed_input_type, NodeType::kBoolean) && IsBoolean(root_object)) { return Float64{Cast<Oddball>(root_object)->to_number_raw()}; } - if (NodeTypeIs(NodeType::kUndefined, assumed_input_type) && + if (NodeTypeCanBe(assumed_input_type, NodeType::kUndefined) && IsUndefined(root_object)) { #ifdef V8_ENABLE_UNDEFINED_DOUBLE // We use the undefined nan and silence it to produce the same result @@ -2120,7 +2201,7 @@ std::optional<Float64> MaglevReducer<BaseT>::TryGetFloatConstantImpl( Cast<Oddball>(root_object)->to_number_raw())); #endif } - if (NodeTypeIs(NodeType::kNull, assumed_input_type) && + if (NodeTypeCanBe(assumed_input_type, NodeType::kNull) && IsNull(root_object)) { return Float64::FromBits(base::double_to_uint64( Cast<Oddball>(root_object)->to_number_raw())); @@ -2200,6 +2281,11 @@ bool MaglevReducer<BaseT>::CanInlineCall( compiler::SharedFunctionInfoRef shared, float call_frequency, base::Vector<ValueNode*> arguments, UseRepresentationSet use_repr_hints) { auto tracer_ = tracer(); + if (broker()->StackHasOverflowed()) { + graph()->compilation_info()->set_could_not_inline_all_candidates(); + TRACE_CANNOT_INLINE("stack overflow"); + return false; + } if (static_cast<int>(graph()->inlined_functions().size()) >= SourcePosition::MaxInliningId()) { graph()->compilation_info()->set_could_not_inline_all_candidates(); @@ -2278,14 +2364,33 @@ MaybeReduceResult MaglevReducer<BaseT>::TryFoldCheckConstantMaps( return {}; } +template <typename BaseT> +template <typename FixedArrayT> +MaybeReduceResult MaglevReducer<BaseT>::AbortIfInvalidFixedArrayIndex( + int32_t index) { + if (index < 0 || static_cast<uint32_t>(index) >= FixedArrayT::kMaxLength) { + // This is an out-of-bound access, which means that we have to be in + // unreachable code. + return BuildAbort(AbortReason::kUnreachable); + } + return {}; +} + +template <typename BaseT> +template <typename FixedArrayT> +MaybeReduceResult MaglevReducer<BaseT>::AbortIfInvalidFixedArrayIndex( + ValueNode* index_node) { + if (std::optional<int32_t> index = TryGetInt32Constant(index_node)) { + return AbortIfInvalidFixedArrayIndex<FixedArrayT>(*index); + } + return {}; +} + template <typename BaseT> MaybeReduceResult MaglevReducer<BaseT>::TryBuildLoadFixedArrayElementConstantIndex( ValueNode* elements, int32_t index, LoadType type) { - if (index < 0 || static_cast<uint32_t>(index) >= FixedArray::kMaxLength) { - // Has to be unreachable because of an earlier check. - return BuildAbort(AbortReason::kUnreachable); - } + RETURN_IF_ABORT(AbortIfInvalidFixedArrayIndex<FixedArray>(index)); if (compiler::OptionalFixedArrayRef fixed_array_ref = TryGetConstant<FixedArray>(elements)) { if (static_cast<uint32_t>(index) < fixed_array_ref->length()) { @@ -2298,8 +2403,9 @@ MaglevReducer<BaseT>::TryBuildLoadFixedArrayElementConstantIndex( } int offset = FixedArray::OffsetOfElementAt(index); return AddNewNodeNoInputConversion<LoadTaggedField>( - {elements}, offset, NodeTypeFromLoadType(type), false, - PropertyKey::None(), IsArrayLength::kNo, compiler::OptionalMapRef{}); + {elements}, offset, NodeTypeFromLoadType(type), + PropertyConstness::kMutable, PropertyKey::None(), IsArrayLength::kNo, + compiler::OptionalMapRef{}); } template <typename BaseT> @@ -2377,7 +2483,7 @@ void MaglevReducer<BaseT>::SetKnownValue(ValueNode* node, DCHECK(IsInstanceOfNodeType(ref.AsHeapObject().map(broker()), known_info->type(), broker())); } else { - DCHECK(!NodeTypeIs(known_info->type(), NodeType::kAnyHeapObject)); + DCHECK(NodeTypeCanBe(known_info->type(), NodeType::kSmi)); } known_info->IntersectType(new_node_type); known_info->alternative().set_checked_value(GetConstant(ref)); @@ -3526,7 +3632,8 @@ MaybeReduceResult MaglevReducer<BaseT>::TryFoldInt32UnaryOperation( return {}; case Operation::kNegate: if (cst.value() == 0) { - return {}; + // Deopt since -0 is not representable as Int32. + return EmitUnconditionalDeopt(DeoptimizeReason::kMinusZero); } if (cst.value() != INT32_MIN) { return GetInt32Constant(-cst.value()); @@ -3691,20 +3798,23 @@ MaybeReduceResult MaglevReducer<BaseT>::TryFoldInt32BinaryOperation( if (base::bits::SignedMulOverflow32(cst_left, cst_right, &result)) { return {}; } - // The product is -0 if it is zero and either operand is negative (the - // other is then +0). -0 is not representable as an Int32 constant, so - // bail out and let Int32MultiplyWithOverflow handle it, as the -x fold - // above does. if (result == 0 && (cst_left < 0 || cst_right < 0)) { - return {}; + // Deopt since -0 is not representable as Int32. + return EmitUnconditionalDeopt(DeoptimizeReason::kMinusZero); } return GetInt32Constant(result); case Operation::kModulus: // TODO(v8:7700): Constant fold mod. return {}; case Operation::kDivide: - // TODO(v8:7700): Constant fold division. - return {}; + if (cst_right == 0) return {}; + if (cst_left == kMinInt && cst_right == -1) return {}; + if (cst_left == 0 && cst_right < 0) { + // Deopt since -0 is not representable as Int32. + return EmitUnconditionalDeopt(DeoptimizeReason::kMinusZero); + } + if (cst_left % cst_right != 0) return {}; + return GetInt32Constant(cst_left / cst_right); case Operation::kBitwiseAnd: return GetInt32Constant(cst_left & cst_right); case Operation::kBitwiseOr: @@ -4339,6 +4449,15 @@ template <typename BaseT> template <typename BranchBuilderT> BranchResult MaglevReducer<BaseT>::BuildBranchIfInt32ToBooleanTrue( BranchBuilderT& b, ValueNode* node) { + // Fuse `Int32BitwiseAnd(x, mask)` feeding a ToBoolean branch into a single + // test-and-branch, avoiding a separate `and` and compare against zero. + if (auto* and_node = node->TryCast<Int32BitwiseAnd>()) { + ValueNode* lhs = and_node->input_node(0); + ValueNode* rhs = and_node->input_node(1); + if (auto mask = TryGetInt32Constant(rhs); mask && *mask != 0) { + return b.template Build<BranchIfInt32BitwiseAndNonZero>({lhs}, *mask); + } + } return b.template Build<BranchIfInt32ToBooleanTrue>({node}); } @@ -4951,11 +5070,11 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReuseKnownPropertyLoad( template <typename BaseT> void MaglevReducer<BaseT>::RecordKnownProperty( ValueNode* lookup_start_object, PropertyKey key, ValueNode* value, - bool is_const, compiler::AccessMode access_mode) { + PropertyConstness constness, compiler::AccessMode access_mode) { DCHECK(!value->is_conversion()); auto& props_for_key = - known_node_aspects().GetLoadedPropertiesForKey(zone(), is_const, key); - if (!is_const && IsAnyStore(access_mode)) { + known_node_aspects().GetLoadedPropertiesForKey(zone(), constness, key); + if (constness == PropertyConstness::kMutable && IsAnyStore(access_mode)) { if constexpr (ReducerBaseWithLoopEffectTracking<BaseT>) { if (base_->loop_effects()) { base_->loop_effects()->keys_cleared.insert(key); @@ -4971,7 +5090,9 @@ void MaglevReducer<BaseT>::RecordKnownProperty( props_for_key.clear(); } - TRACE(" * Recording " << (is_const ? "constant" : "non-constant") + TRACE(" * Recording " << (constness == PropertyConstness::kConst + ? "constant" + : "non-constant") << " known property " << PrintNodeLabel(lookup_start_object) << ": " << PrintNode(lookup_start_object) << " [" << key @@ -4979,7 +5100,8 @@ void MaglevReducer<BaseT>::RecordKnownProperty( << PrintNode(value)); if constexpr (ReducerBaseWithLoopEffectTracking<BaseT>) { - if (IsAnyStore(access_mode) && !is_const && base_->loop_effects()) { + if (IsAnyStore(access_mode) && constness == PropertyConstness::kMutable && + base_->loop_effects()) { auto updated = props_for_key.emplace(lookup_start_object, value); if (updated.second) { base_->loop_effects()->objects_written.insert(lookup_start_object); @@ -4996,11 +5118,13 @@ void MaglevReducer<BaseT>::RecordKnownProperty( template <typename BaseT> ReduceResult MaglevReducer<BaseT>::BuildLoadJSDataViewByteLength( ValueNode* js_data_view) { - bool is_const = !v8_flags.track_array_buffer_views; + PropertyConstness constness = v8_flags.track_array_buffer_views + ? PropertyConstness::kMutable + : PropertyConstness::kConst; // Note: We can't use broker()->byte_length_string() here, because it could // conflict with redefinitions of the ArrayBufferView byteLength property. if (ValueNode* byte_length = known_node_aspects().TryFindLoadedProperty( - js_data_view, PropertyKey::ArrayBufferViewByteLength(), is_const)) { + js_data_view, PropertyKey::ArrayBufferViewByteLength(), constness)) { return byte_length; } @@ -5008,16 +5132,18 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadJSDataViewByteLength( GET_VALUE_OR_ABORT(result, AddNewNode<LoadDataViewByteLength>({js_data_view})); RecordKnownProperty(js_data_view, PropertyKey::ArrayBufferViewByteLength(), - result, is_const, compiler::AccessMode::kLoad); + result, constness, compiler::AccessMode::kLoad); return result; } template <typename BaseT> ReduceResult MaglevReducer<BaseT>::BuildLoadJSDataViewDataPointer( ValueNode* js_data_view) { - bool is_const = !v8_flags.track_array_buffer_views; + PropertyConstness constness = v8_flags.track_array_buffer_views + ? PropertyConstness::kMutable + : PropertyConstness::kConst; if (ValueNode* backing_store = known_node_aspects().TryFindLoadedProperty( - js_data_view, PropertyKey::ArrayBufferViewDataPointer(), is_const)) { + js_data_view, PropertyKey::ArrayBufferViewDataPointer(), constness)) { return backing_store; } @@ -5025,7 +5151,7 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadJSDataViewDataPointer( GET_VALUE_OR_ABORT(result, AddNewNode<LoadDataViewDataPointer>({js_data_view})); RecordKnownProperty(js_data_view, PropertyKey::ArrayBufferViewDataPointer(), - result, is_const, compiler::AccessMode::kLoad); + result, constness, compiler::AccessMode::kLoad); return result; } @@ -5117,8 +5243,8 @@ ReduceResult MaglevReducer<BaseT>::BuildLoadStringLength(ValueNode* string) { RETURN_IF_DONE(TryReduceStringLength(string)); ValueNode* result; GET_VALUE_OR_ABORT(result, AddNewNode<StringLength>({string})); - RecordKnownProperty(string, PropertyKey::StringLength(), result, true, - compiler::AccessMode::kLoad); + RecordKnownProperty(string, PropertyKey::StringLength(), result, + PropertyConstness::kConst, compiler::AccessMode::kLoad); return result; } @@ -5143,7 +5269,7 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReduceStringPrototypeIndexOfIncludes( : GetRootConstant(RootIndex::kundefined_string); RETURN_IF_ABORT(BuildCheckString(search_element)); - ValueNode* start = args.count() > 1 ? args[1] : GetInt32Constant(0); + ValueNode* start = GetValueOrZeroIfUndefined(args[1]); ValueNode* receiver_length; GET_VALUE_OR_ABORT(receiver_length, BuildLoadStringLength(receiver)); @@ -5700,6 +5826,7 @@ ReduceResult MaglevReducer<BaseT>::GetSmiValue( template <typename BaseT> VirtualObject* MaglevReducer<BaseT>::CreateHeapNumber(ValueNode* value) { + DCHECK(value->is_float64()); using Shape = VirtualHeapNumberShape; int slot_count = Shape::header_slot_count; SBXCHECK_EQ(slot_count, 2); @@ -5711,6 +5838,19 @@ VirtualObject* MaglevReducer<BaseT>::CreateHeapNumber(ValueNode* value) { return vobj; } +template <typename BaseT> +VirtualObject* MaglevReducer<BaseT>::CreateUninitializedHeapNumber() { + using Shape = VirtualHeapNumberShape; + int slot_count = Shape::header_slot_count; + SBXCHECK_EQ(slot_count, 2); + compiler::MapRef map = broker()->uninitialized_heap_number_map(); + VirtualObject* vobj = NodeBase::New<VirtualObject>( + zone(), 0, NewObjectId(), zone(), &Shape::kObjectLayout, map, slot_count); + vobj->set(offsetof(HeapObject, map_), GetConstant(map)); + vobj->set(offsetof(HeapNumber, value_), GetFloat64Constant(Float64(0.0))); + return vobj; +} + template <typename BaseT> VirtualObject* MaglevReducer<BaseT>::CreateConsString(ValueNode* map, ValueNode* length, @@ -6013,9 +6153,9 @@ VirtualObject* MaglevReducer<BaseT>::CreateRegExpLiteralObject( GetRootConstant(RootIndex::kEmptyFixedArray)); vobj->set(offsetof(JSObject, elements_), GetRootConstant(RootIndex::kEmptyFixedArray)); - vobj->set(offsetof(JSRegExp, data_), - GetTrustedConstant(literal.data(broker()), - kRegExpDataIndirectPointerTag)); + vobj->set( + offsetof(JSRegExp, data_), + GetTrustedConstant(literal.data(broker()), kRegExpDataTrustedPointerTag)); vobj->set(offsetof(JSRegExp, flags_), GetInt32Constant(literal.flags())); vobj->set(JSRegExp::kLastIndexOffset, GetInt32Constant(JSRegExp::kInitialLastIndexValue)); @@ -6645,13 +6785,8 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReduceStringPrototypeCharAt( } ValueNode* receiver = GetValueOrUndefined(args.receiver()); - ValueNode* index; - if (args.count() == 0) { - // Index is the undefined object. ToIntegerOrInfinity(undefined) = 0. - index = GetInt32Constant(0); - } else { - GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(args[0])); - } + ValueNode* index = GetValueOrZeroIfUndefined(args[0]); + GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(index)); // Any other argument is ignored. RETURN_IF_DONE( @@ -6701,13 +6836,8 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReduceStringPrototypeCharCodeAt( return {}; } ValueNode* receiver = GetValueOrUndefined(args.receiver()); - ValueNode* index; - if (args.count() == 0) { - // Index is the undefined object. ToIntegerOrInfinity(undefined) = 0. - index = GetInt32Constant(0); - } else { - GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(args[0])); - } + ValueNode* index = GetValueOrZeroIfUndefined(args[0]); + GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(index)); // Any other argument is ignored. // Try to constant-fold if receiver and index are constant @@ -6762,13 +6892,8 @@ MaybeReduceResult MaglevReducer<BaseT>::TryReduceStringPrototypeCodePointAt( return {}; } ValueNode* receiver = GetValueOrUndefined(args.receiver()); - ValueNode* index; - if (args.count() == 0) { - // Index is the undefined object. ToIntegerOrInfinity(undefined) = 0. - index = GetInt32Constant(0); - } else { - GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(args[0])); - } + ValueNode* index = GetValueOrZeroIfUndefined(args[0]); + GET_VALUE_OR_ABORT(index, GetInt32ElementIndex(index)); // Any other argument is ignored. // Ensure that {receiver} is actually a String. RETURN_IF_ABORT(BuildCheckString(receiver)); diff --git a/deps/v8/src/maglev/maglev-reducer.h b/deps/v8/src/maglev/maglev-reducer.h index ef286e3e6b14..9ca29cd10663 100644 --- a/deps/v8/src/maglev/maglev-reducer.h +++ b/deps/v8/src/maglev/maglev-reducer.h @@ -34,7 +34,7 @@ namespace v8 { namespace internal { namespace maglev { -enum class EnsureTypeResult; +enum class V8_NODISCARD EnsureTypeResult; struct MaglevCallSiteInfo; class MaglevGraphBuilder; template <typename BaseT> @@ -807,6 +807,11 @@ class MaglevReducer { MaybeReduceResult TryBuildLoadFixedArrayElementConstantIndex( ValueNode* elements, int32_t index, LoadType type); + template <typename FixedArrayT> + MaybeReduceResult AbortIfInvalidFixedArrayIndex(int32_t index); + template <typename FixedArrayT> + MaybeReduceResult AbortIfInvalidFixedArrayIndex(ValueNode* index); + // Add a new node with a dynamic set of inputs which are initialized by the // `post_create_input_initializer` function before the node is added to the // graph. @@ -1003,6 +1008,7 @@ class MaglevReducer { uint32_t NewObjectId() { return graph()->NewObjectId(); } VirtualObject* CreateHeapNumber(ValueNode* value); + VirtualObject* CreateUninitializedHeapNumber(); VirtualObject* CreateJSObject(compiler::MapRef map); VirtualObject* CreateConsString(ValueNode* map, ValueNode* length, ValueNode* first, ValueNode* second); @@ -1049,7 +1055,8 @@ class MaglevReducer { ReduceResult BuildLoadTaggedField( ValueNode* object, uint32_t offset, NodeType type = NodeType::kUnknown, - bool is_const = false, PropertyKey key = PropertyKey::None(), + PropertyConstness constness = PropertyConstness::kMutable, + PropertyKey key = PropertyKey::None(), IsArrayLength is_array_length = IsArrayLength::kNo, compiler::OptionalMapRef stable_field_map = {}); @@ -1069,7 +1076,7 @@ class MaglevReducer { ReduceResult BuildStoreTrustedPointerField(ValueNode* object, ValueNode* value, int offset, - IndirectPointerTag tag, + TrustedPointerTag tag, StoreTaggedMode store_mode); ReduceResult BuildStoreMap(ValueNode* object, compiler::MapRef map, @@ -1090,6 +1097,10 @@ class MaglevReducer { MaybeAssignedFlag GetContextMaybeAssigned(compiler::ScopeInfoRef scope_info, int index, VariableMode* mode); + ValueNode* TryGetParentContext(ValueNode* node); + MaybeReduceResult TryGetConstantContextValue( + ValueNode* context, int offset, MaybeAssignedFlag assigned, + VariableMode mode = VariableMode::kVar); bool CanElideWriteBarrier(ValueNode* object, ValueNode* value); @@ -1379,7 +1390,7 @@ class MaglevReducer { MaybeReduceResult TryReuseKnownPropertyLoad(ValueNode* lookup_start_object, compiler::NameRef name); void RecordKnownProperty(ValueNode* lookup_start_object, PropertyKey key, - ValueNode* value, bool is_const, + ValueNode* value, PropertyConstness constness, compiler::AccessMode access_mode); ValueNode* GetValueOrUndefined(ValueNode* maybe_value) { if (maybe_value == nullptr) { @@ -1388,6 +1399,12 @@ class MaglevReducer { return maybe_value; } + // Optional integer positions treat an omitted or known undefined value as 0. + ValueNode* GetValueOrZeroIfUndefined(ValueNode* maybe_value) { + ValueNode* value = GetValueOrUndefined(maybe_value); + return value->IsUndefinedValue() ? GetInt32Constant(0) : value; + } + ReduceResult BuildInt32Max(ValueNode* a, ValueNode* b); ReduceResult BuildInt32Min(ValueNode* a, ValueNode* b); ReduceResult BuildInt32Sign(ValueNode* value); @@ -1559,7 +1576,7 @@ class MaglevReducer { return graph()->GetConstant(ref); } ValueNode* GetTrustedConstant(compiler::HeapObjectRef ref, - IndirectPointerTag tag) { + TrustedPointerTag tag) { return graph()->GetTrustedConstant(ref, tag); } @@ -1638,10 +1655,12 @@ class MaglevReducer { MaybeReduceResult TryFoldTestTypeOf( ValueNode* input, interpreter::TestTypeOfFlags::LiteralFlag literal); - bool CheckType(ValueNode* node, NodeType type, NodeType* old = nullptr) { + V8_NODISCARD bool CheckType(ValueNode* node, NodeType type, + NodeType* old = nullptr) { return known_node_aspects().CheckType(broker(), node, type, old); } - NodeType CheckTypes(ValueNode* node, std::initializer_list<NodeType> types) { + V8_NODISCARD NodeType CheckTypes(ValueNode* node, + std::initializer_list<NodeType> types) { return known_node_aspects().CheckTypes(broker(), node, types); } diff --git a/deps/v8/src/maglev/maglev-regalloc.cc b/deps/v8/src/maglev/maglev-regalloc.cc index 9bec10cd9fde..78c938bf60e3 100644 --- a/deps/v8/src/maglev/maglev-regalloc.cc +++ b/deps/v8/src/maglev/maglev-regalloc.cc @@ -549,6 +549,9 @@ void StraightForwardRegisterAllocator::AllocateRegisters() { kSystemPointerSize + interpreter::Register::receiver().index())); phi->result().SetAllocated(phi->regalloc_info()->spill_slot()); +#ifdef V8_COMPRESS_POINTERS + phi->SetTaggedResultNeedsDecompress(); +#endif // Break once both accumulator and receiver have been processed. break; } diff --git a/deps/v8/src/maglev/maglev-truncation.h b/deps/v8/src/maglev/maglev-truncation.h index c78aabc42803..a13adb725f86 100644 --- a/deps/v8/src/maglev/maglev-truncation.h +++ b/deps/v8/src/maglev/maglev-truncation.h @@ -244,11 +244,7 @@ class PropagateTruncationProcessor { static int64_t GetMaxExactInputValue(Opcode user_opcode, ValueNode* node) { node = UnwrapForTruncation(node); if (auto constant = node->TryCast<Float64Constant>()) { - double value = std::abs(constant->value().get_scalar()); - if (!(value <= static_cast<double>(kMaxExactlyRepresentableValue))) { - return kMaxSaturatedValue; - } - return static_cast<int64_t>(std::ceil(value)); + return GetMaxExactValueOfRange(constant->GetStaticRange()); } // A multiply this pass truncates keeps only the low 32 bits of a product // that its own safe integer check bounds by 2^53, so charge the product. @@ -526,12 +522,12 @@ class TruncationProcessor { } void ProcessFloat64SpeculateSafeAdd(Float64SpeculateSafeAdd* node) { - if (!node->can_truncate_to_int32() || IsUnsafeIntConstant(node, 0) || - IsUnsafeIntConstant(node, 1)) { + if (!node->can_truncate_to_int32()) { // Don't truncate this node. node->OverwriteWith<Float64Add>(); return; } + DCHECK(!IsUnsafeIntConstant(node, 0) && !IsUnsafeIntConstant(node, 1)); if (node->range().IsSafeInt()) { // Non-speculating truncation. ProcessFloat64BinaryOp<Int32Add>(node); diff --git a/deps/v8/src/maglev/ppc/maglev-assembler-ppc-inl.h b/deps/v8/src/maglev/ppc/maglev-assembler-ppc-inl.h index 3b8afc64a8a7..aad5df9eacab 100644 --- a/deps/v8/src/maglev/ppc/maglev-assembler-ppc-inl.h +++ b/deps/v8/src/maglev/ppc/maglev-assembler-ppc-inl.h @@ -764,7 +764,11 @@ inline void MaglevAssembler::LoadFloat32(DoubleRegister dst, MemOperand src) { MacroAssembler::LoadF32(dst, src); } inline void MaglevAssembler::StoreFloat32(MemOperand dst, DoubleRegister src) { - MacroAssembler::StoreF32(src, dst); + // Turn sNaN to qNaN. + TemporaryRegisterScope temps(this); + DoubleRegister double_scratch = temps.AcquireScratchDouble(); + frsp(double_scratch, src); + MacroAssembler::StoreF32(double_scratch, dst); } inline void MaglevAssembler::LoadFloat64(DoubleRegister dst, MemOperand src) { MacroAssembler::LoadF64(dst, src); diff --git a/deps/v8/src/maglev/riscv/maglev-assembler-riscv-inl.h b/deps/v8/src/maglev/riscv/maglev-assembler-riscv-inl.h index cc6e4499c230..ca25f964f2ef 100644 --- a/deps/v8/src/maglev/riscv/maglev-assembler-riscv-inl.h +++ b/deps/v8/src/maglev/riscv/maglev-assembler-riscv-inl.h @@ -917,7 +917,7 @@ inline void MaglevAssembler::Move(Register dst, uint32_t i) { inline void MaglevAssembler::Move(Register dst, intptr_t p) { li(dst, Operand(p)); } -inline void MaglevAssembler::Move(Register dst, IndirectPointerTag i) { +inline void MaglevAssembler::Move(Register dst, TrustedPointerTag i) { li(dst, Operand(i)); } inline void MaglevAssembler::Move(DoubleRegister dst, double n) { diff --git a/deps/v8/src/maglev/turbolev-escape-analysis.cc b/deps/v8/src/maglev/turbolev-escape-analysis.cc index 5a32a92cc2ea..5a540e99a234 100644 --- a/deps/v8/src/maglev/turbolev-escape-analysis.cc +++ b/deps/v8/src/maglev/turbolev-escape-analysis.cc @@ -834,9 +834,6 @@ class CandidateAnalyzer { ProcessResult Process(LoadFixedArrayElement* node, const ProcessingState& state) { - // LoadFixedArrayElement should never be used for Int32Constant index, and - // thus should never be elided (for now). - DCHECK(!node->IndexInput().node()->Is<Int32Constant>()); // TODO(dmercadier): handle non-constant indices. This will require // stack-allocating the array. For now, we just go to the generic Process // overload. @@ -942,7 +939,7 @@ class CandidateAnalyzer { frame.as_builtin_continuation(); if (!continuation_frame.parameters().empty()) { data_.MarkAsEscapedIfCandidate( - continuation_frame.parameters().first()); + continuation_frame.parameters().front()); } break; } @@ -1044,6 +1041,15 @@ class FieldValuesTracker : public CandidateAnalyzer { bool all_predecessors_equal = true; for (ValueNode* pred : predecessors) { if (pred == nullptr) { + if (block->is_loop() && predecessors[0] != nullptr) { + // The allocation had a value for this field when entering the loop, + // but doesn't have one on the backedge (which can happen when a + // generator resume jumps into the middle of the loop, bypassing + // the allocation). + DCHECK(block->state()->is_resumable_loop()); + data_.MarkAsEscaped(key.data().base); + need_revisit = true; + } // This means that the allocation is not available on all predecessor // paths. This is not an issue: either it will flow into a phi, in // which case it will be invalidated, or it doesn't, in which case @@ -1522,39 +1528,9 @@ class DeoptFrameUpdater { DeoptFrame* new_frame_state = DeepClone(node->lazy_deopt_info()->top_frame(), zone()); - interpreter::Register result_location = - interpreter::Register::virtual_accumulator(); - int result_size = 1; - switch (node->lazy_deopt_info()->top_frame().type()) { - case DeoptFrame::FrameType::kInterpretedFrame: - // Interpreted frames obviously need a result location. - result_location = node->lazy_deopt_info()->result_location(); - result_size = node->lazy_deopt_info()->result_size(); - break; - case DeoptFrame::FrameType::kInlinedArgumentsFrame: - case DeoptFrame::FrameType::kConstructInvokeStubFrame: - break; - case DeoptFrame::FrameType::kBuiltinContinuationFrame: - // Normally if the function is going to be deoptimized then the top - // frame should be an interpreted one, except for LazyDeoptContinuation - // builtin. - switch (node->lazy_deopt_info() - ->top_frame() - .as_builtin_continuation() - .builtin_id()) { - case Builtin::kGenericLazyDeoptContinuation: - case Builtin::kGetIteratorWithFeedbackLazyDeoptContinuation: - case Builtin::kCallIteratorWithFeedbackLazyDeoptContinuation: - result_location = node->lazy_deopt_info()->result_location(); - result_size = node->lazy_deopt_info()->result_size(); - break; - default: - break; - } - } - - node->SetLazyDeoptInfo(zone(), new_frame_state, result_location, - result_size, + node->SetLazyDeoptInfo(zone(), new_frame_state, + node->lazy_deopt_info()->result_location(), + node->lazy_deopt_info()->result_size(), node->lazy_deopt_info()->feedback_to_update()); UpdateDeoptFrame(new_frame_state); } diff --git a/deps/v8/src/maglev/x64/maglev-assembler-x64-inl.h b/deps/v8/src/maglev/x64/maglev-assembler-x64-inl.h index 70f4aaa325ad..04f09d1a9892 100644 --- a/deps/v8/src/maglev/x64/maglev-assembler-x64-inl.h +++ b/deps/v8/src/maglev/x64/maglev-assembler-x64-inl.h @@ -738,7 +738,7 @@ inline void MaglevAssembler::Move(Register dst, uint32_t i) { MacroAssembler::Move(dst, i); } -inline void MaglevAssembler::Move(Register dst, IndirectPointerTag i) { +inline void MaglevAssembler::Move(Register dst, TrustedPointerTag i) { MacroAssembler::Move(dst, i); } @@ -1168,8 +1168,7 @@ void MaglevAssembler::JumpIfByte(Condition cc, Register value, int32_t byte, } void MaglevAssembler::Float64SilenceNan(DoubleRegister value) { - Xorpd(kScratchDoubleReg, kScratchDoubleReg); - Subsd(value, kScratchDoubleReg); + CanonicalizeNaN(value); } void MaglevAssembler::Float64ExtractHighWord32(Register dst, diff --git a/deps/v8/src/maglev/x64/maglev-ir-x64.cc b/deps/v8/src/maglev/x64/maglev-ir-x64.cc index 54d55f926bfc..306a90f915e8 100644 --- a/deps/v8/src/maglev/x64/maglev-ir-x64.cc +++ b/deps/v8/src/maglev/x64/maglev-ir-x64.cc @@ -1046,12 +1046,11 @@ void ChangeFloat64ToHoleyFloat64::SetValueLocationConstraints() { } void ChangeFloat64ToHoleyFloat64::GenerateCode(MaglevAssembler* masm, const ProcessingState& state) { - DoubleRegister value = ToDoubleRegister(ValueInput()); // A Float64 value could contain a NaN with the bit pattern that has a special // interpretation in the HoleyFloat64 representation, so we need to canicalize // those before changing representation. - __ Xorpd(kScratchDoubleReg, kScratchDoubleReg); - __ Subsd(value, kScratchDoubleReg); + __ CanonicalizeNaN(ToDoubleRegister(result()), + ToDoubleRegister(ValueInput())); } void Float64ToSilencedFloat64::SetValueLocationConstraints() { @@ -1060,11 +1059,10 @@ void Float64ToSilencedFloat64::SetValueLocationConstraints() { } void Float64ToSilencedFloat64::GenerateCode(MaglevAssembler* masm, const ProcessingState& state) { - DoubleRegister value = ToDoubleRegister(ValueInput()); // The hole value is a signalling NaN, so just silence it to get the // float64 value. - __ Xorpd(kScratchDoubleReg, kScratchDoubleReg); - __ Subsd(value, kScratchDoubleReg); + __ CanonicalizeNaN(ToDoubleRegister(this->result()), + ToDoubleRegister(ValueInput())); } void UnsafeFloat64ToHoleyFloat64::SetValueLocationConstraints() { diff --git a/deps/v8/src/numbers/conversions.cc b/deps/v8/src/numbers/conversions.cc index 3bdae78df64e..ea267d4f1227 100644 --- a/deps/v8/src/numbers/conversions.cc +++ b/deps/v8/src/numbers/conversions.cc @@ -12,9 +12,9 @@ #include <optional> #include "include/v8config.h" -#include "src/base/fpu.h" #include "src/base/numbers/dtoa.h" #include "src/base/numbers/strtod.h" +#include "src/base/unique-array.h" #include "src/bigint/bigint-inl.h" #include "src/common/assert-scope.h" #include "src/handles/handles.h" @@ -224,14 +224,6 @@ uint8_t SignificandToChars(uint64_t n, char* buffer) { // This simple base class does not allow formatted output. class SimpleStringBuilder final { public: - // Create a string builder with a buffer of the given size. The - // buffer is allocated through NewArray<char> and must be - // deallocated by the caller of Finalize(). - explicit SimpleStringBuilder(size_t size) { - buffer_ = base::Vector<char>::New(size); - cursor_ = buffer_.begin(); - } - SimpleStringBuilder(char* buffer, size_t size) : buffer_(buffer, size), cursor_(buffer) {} @@ -776,8 +768,7 @@ class NumberParseIntHelper : public StringToIntHelper { SLOW_DCHECK(buffer_pos < kBufferSize); buffer[buffer_pos] = '\0'; - base::Vector<const char> buffer_vector(buffer, buffer_pos); - result_ = Strtod(buffer_vector, 0); + result_ = base::Strtod({buffer, buffer_pos}, 0); set_state(State::kDone); } @@ -952,7 +943,7 @@ double InternalStringToDouble(const Char* current, const Char* end, double StringToDouble(const char* str, ConversionFlag flags, double empty_string_val) { - // We use {base::OneByteVector} instead of {base::CStrVector} to avoid + // We use {base::OneByteVector} instead of {std::string_view} to avoid // instantiating the InternalStringToDouble() template for {const char*} as // well. return StringToDouble(base::OneByteVector(str), flags, empty_string_val); @@ -1262,9 +1253,8 @@ std::string_view DoubleToFixedStringView(double value, int f, kDoubleToFixedMaxDigitsBeforePoint + kMaxFractionDigits + 1; char decimal_rep[kDecimalRepCapacity]; int decimal_rep_length; - base::DoubleToAscii(value, base::DTOA_FIXED, f, - base::Vector<char>(decimal_rep, kDecimalRepCapacity), - &sign, &decimal_rep_length, &decimal_point); + base::DoubleToAscii(value, base::DTOA_FIXED, f, decimal_rep, &sign, + &decimal_rep_length, &decimal_point); // Create a representation that is padded with zeros if needed. int zero_prefix_length = 0; @@ -1283,7 +1273,8 @@ std::string_view DoubleToFixedStringView(double value, int f, unsigned rep_length = zero_prefix_length + decimal_rep_length + zero_postfix_length; // TODO(pthier): Get rid of this intermediate string builder. - base::Vector<char> rep_buffer = base::Vector<char>::New(rep_length + 1); + base::UniqueArray<char> rep_buffer = + base::UniqueArray<char>::NewForOverwrite(rep_length + 1); SimpleStringBuilder rep_builder(rep_buffer.begin(), rep_buffer.size()); rep_builder.AddPadding('0', zero_prefix_length); rep_builder.AddString(decimal_rep, decimal_rep_length); @@ -1301,7 +1292,6 @@ std::string_view DoubleToFixedStringView(double value, int f, builder.AddCharacter('.'); builder.AddSubstring(rep_buffer.begin() + decimal_point, f); } - DeleteArray(rep_buffer.begin()); return {buffer.begin(), builder.Finalize()}; } @@ -1357,14 +1347,12 @@ std::string_view DoubleToExponentialStringView(double value, int f, int decimal_rep_length; if (f == -1) { - base::DoubleToAscii(value, base::DTOA_SHORTEST, 0, - base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity), - &sign, &decimal_rep_length, &decimal_point); + base::DoubleToAscii(value, base::DTOA_SHORTEST, 0, decimal_rep, &sign, + &decimal_rep_length, &decimal_point); f = decimal_rep_length - 1; } else { - base::DoubleToAscii(value, base::DTOA_PRECISION, f + 1, - base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity), - &sign, &decimal_rep_length, &decimal_point); + base::DoubleToAscii(value, base::DTOA_PRECISION, f + 1, decimal_rep, &sign, + &decimal_rep_length, &decimal_point); } DCHECK_GT(decimal_rep_length, 0); DCHECK(decimal_rep_length <= f + 1); @@ -1394,9 +1382,8 @@ std::string_view DoubleToPrecisionStringView(double value, int p, char decimal_rep[kV8DtoaBufferCapacity]; int decimal_rep_length; - base::DoubleToAscii(value, base::DTOA_PRECISION, p, - base::Vector<char>(decimal_rep, kV8DtoaBufferCapacity), - &sign, &decimal_rep_length, &decimal_point); + base::DoubleToAscii(value, base::DTOA_PRECISION, p, decimal_rep, &sign, + &decimal_rep_length, &decimal_point); DCHECK(decimal_rep_length <= p); int exponent = decimal_point - 1; @@ -1465,20 +1452,9 @@ std::string_view DoubleToRadixStringView(double value, int radix, double fraction = value - integer; // We only compute fractional digits up to the input double's precision. double delta = 0.5 * (base::Double(value).NextDouble() - value); - bool delta_is_positive = true; - // If the delta rounded down to zero, use the minimum (denormal) delta - // value. Be careful around denormal flushing when doing so. - if (delta <= 0) { - if (base::FPU::GetFlushDenormals()) { - // We're flushing the delta value to zero, so the loop below won't - // make progress. Skip it instead. - delta_is_positive = false; - } else { - static_assert(base::Double(0.0).NextDouble() > 0); - delta = base::Double(0.0).NextDouble(); - } - } - if (delta_is_positive && fraction >= delta) { + delta = std::max(base::Double(0.0).NextDouble(), delta); + DCHECK_GT(delta, 0.0); + if (fraction >= delta) { // Insert decimal point. buffer[fraction_cursor++] = '.'; do { diff --git a/deps/v8/src/numbers/ieee754.cc b/deps/v8/src/numbers/ieee754.cc index 1835062ab179..381c6c062ef3 100644 --- a/deps/v8/src/numbers/ieee754.cc +++ b/deps/v8/src/numbers/ieee754.cc @@ -45,6 +45,13 @@ double pow(double x, double y) { } if (v8_flags.use_std_math_pow) { + if (v8_flags.correctness_fuzzer_cross_arch_suppressions) { + if (y == 0) return 1; + if (std::isnan(x)) return x; + // Return a dummy value to avoid architecture-specific precision + // differences in std::pow during differential correctness fuzzing. + return 42; + } return std::pow(x, y); } return base::ieee754::legacy::pow(x, y); diff --git a/deps/v8/src/objects/DEPS b/deps/v8/src/objects/DEPS index c3b22691599d..da6c96c86586 100644 --- a/deps/v8/src/objects/DEPS +++ b/deps/v8/src/objects/DEPS @@ -1,6 +1,7 @@ include_rules = [ # See `include_dirs` from Chromium's `//third_party/rust/temporal_capi`. - "+temporal_rs" + "+temporal", + "+temporal_rs", ] specific_include_rules = { diff --git a/deps/v8/src/objects/all-objects-inl.h b/deps/v8/src/objects/all-objects-inl.h index f78c50656e01..105c34df93d8 100644 --- a/deps/v8/src/objects/all-objects-inl.h +++ b/deps/v8/src/objects/all-objects-inl.h @@ -42,7 +42,6 @@ #include "src/objects/instance-type-inl.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" #include "src/objects/js-collection-inl.h" #include "src/objects/js-disposable-stack-inl.h" #include "src/objects/js-function-inl.h" diff --git a/deps/v8/src/objects/all-objects.h b/deps/v8/src/objects/all-objects.h index 2f23535a30ab..14d35c8ed7d9 100644 --- a/deps/v8/src/objects/all-objects.h +++ b/deps/v8/src/objects/all-objects.h @@ -57,7 +57,6 @@ #include "src/objects/instruction-stream.h" #include "src/objects/js-array-buffer.h" #include "src/objects/js-array.h" -#include "src/objects/js-atomics-synchronization.h" #include "src/objects/js-collection-iterator.h" #include "src/objects/js-collection.h" #include "src/objects/js-disposable-stack.h" diff --git a/deps/v8/src/objects/allocation-site-inl.h b/deps/v8/src/objects/allocation-site-inl.h index c0dbebecb68d..4af0e5f008a6 100644 --- a/deps/v8/src/objects/allocation-site-inl.h +++ b/deps/v8/src/objects/allocation-site-inl.h @@ -130,12 +130,11 @@ inline bool AllocationSite::PointsToLiteral() const { return !IsSmi(raw_value); } -// Heuristic: We only need to create allocation site info if the boilerplate -// elements kind is the initial elements kind. +// We only need to create allocation site info if the boilerplate elements kind +// can transition to a more general fast elements kind. inline bool AllocationSite::ShouldTrack( ElementsKind boilerplate_elements_kind) { - if (!V8_ALLOCATION_SITE_TRACKING_BOOL) return false; - return IsSmiElementsKind(boilerplate_elements_kind); + return ShouldTrack(boilerplate_elements_kind, TERMINAL_FAST_ELEMENTS_KIND); } inline bool AllocationSite::CanTrack(InstanceType type) { diff --git a/deps/v8/src/objects/api-callbacks-inl.h b/deps/v8/src/objects/api-callbacks-inl.h index 9d5e062ef5de..88ca7fc1bbfe 100644 --- a/deps/v8/src/objects/api-callbacks-inl.h +++ b/deps/v8/src/objects/api-callbacks-inl.h @@ -17,6 +17,7 @@ #include "src/objects/js-objects-inl.h" #include "src/objects/name.h" #include "src/objects/oddball.h" +#include "src/objects/struct-inl.h" #include "src/objects/templates.h" #include "src/utils/memcopy.h" @@ -33,6 +34,13 @@ static_assert(Internals::kCallbackInfoDataOffset == static_assert(Internals::kCallbackInfoDataOffset == offsetof(InterceptorInfo, data_)); +AccessCheckInfo::AccessCheckInfo(const AllocationWitness& witness) + : Struct(witness.roots().access_check_info_map()), + callback_(witness.roots().undefined_value()), + named_interceptor_(Smi::zero()), + indexed_interceptor_(Smi::zero()), + data_(witness.roots().undefined_value()) {} + Tagged<UnionOf<Foreign, Smi, Undefined>> AccessCheckInfo::callback() const { return callback_.load(); } @@ -77,8 +85,8 @@ void AccessorInfo::set_name(Tagged<Name> value, WriteBarrierMode mode) { name_.store(this, value, mode); } -uint32_t AccessorInfo::flags() const { return flags_; } -void AccessorInfo::set_flags(uint32_t value) { flags_ = value; } +AccessorInfo::Flags AccessorInfo::flags() const { return flags_; } +void AccessorInfo::set_flags(Flags value) { flags_ = value; } // InterceptorInfo. Tagged<Object> InterceptorInfo::data() const { return data_.load(); } @@ -86,8 +94,8 @@ void InterceptorInfo::set_data(Tagged<Object> value, WriteBarrierMode mode) { data_.store(this, value, mode); } -uint32_t InterceptorInfo::flags() const { return flags_; } -void InterceptorInfo::set_flags(uint32_t value) { flags_ = value; } +InterceptorInfo::Flags InterceptorInfo::flags() const { return flags_; } +void InterceptorInfo::set_flags(Flags value) { flags_ = value; } REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST( AccessorInfo, getter, Address, offsetof(AccessorInfo, getter_), @@ -106,13 +114,14 @@ bool AccessorInfo::has_setter(Isolate* isolate) { } BIT_FIELD_ACCESSORS(AccessorInfo, flags, replace_on_access, - AccessorInfo::ReplaceOnAccessBit) -BIT_FIELD_ACCESSORS(AccessorInfo, flags, is_sloppy, AccessorInfo::IsSloppyBit) + AccessorInfo::Flags::ReplaceOnAccessBit) +BIT_FIELD_ACCESSORS(AccessorInfo, flags, is_sloppy, + AccessorInfo::Flags::IsSloppyBit) BIT_FIELD_ACCESSORS(AccessorInfo, flags, getter_side_effect_type, - AccessorInfo::GetterSideEffectTypeBits) + AccessorInfo::Flags::GetterSideEffectTypeBits) SideEffectType AccessorInfo::setter_side_effect_type() const { - return SetterSideEffectTypeBits::decode(flags()); + return flags().setter_side_effect_type(); } void AccessorInfo::set_setter_side_effect_type(SideEffectType value) { @@ -121,11 +130,11 @@ void AccessorInfo::set_setter_side_effect_type(SideEffectType value) { // support checking receivers for temporary objects, but still expect // the receiver to be written to. CHECK_NE(value, SideEffectType::kHasNoSideEffect); - set_flags(SetterSideEffectTypeBits::update(flags(), value)); + set_flags(flags().with_setter_side_effect_type(value)); } BIT_FIELD_ACCESSORS(AccessorInfo, flags, initial_property_attributes, - AccessorInfo::InitialAttributesBits) + AccessorInfo::Flags::InitialAttributesBits) void AccessorInfo::RemoveCallbackRedirectionForSerialization( IsolateForSandbox isolate) { @@ -237,17 +246,18 @@ LAZY_EXTERNAL_POINTER_ACCESSORS_MAYBE_READ_ONLY_HOST_CHECKED2( kApiIndexedPropertyIterableToListCallbackTag, !is_named(), !is_named() && (value != kNullAddress)) -BOOL_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols, - CanInterceptSymbolsBit::kShift) -BOOL_ACCESSORS(InterceptorInfo, flags, non_masking, NonMaskingBit::kShift) -BOOL_GETTER(InterceptorInfo, flags, is_named, NamedBit::kShift) -BOOL_ACCESSORS(InterceptorInfo, flags, has_no_side_effect, - HasNoSideEffectBit::kShift) +BIT_FIELD_ACCESSORS(InterceptorInfo, flags, can_intercept_symbols, + InterceptorInfo::Flags::CanInterceptSymbolsBit) +BIT_FIELD_ACCESSORS(InterceptorInfo, flags, non_masking, + InterceptorInfo::Flags::NonMaskingBit) +bool InterceptorInfo::is_named() const { return flags().named(); } +BIT_FIELD_ACCESSORS(InterceptorInfo, flags, has_no_side_effect, + InterceptorInfo::Flags::HasNoSideEffectBit) // TODO(ishell): remove once all the Api changes are done. -BOOL_ACCESSORS(InterceptorInfo, flags, has_new_callbacks_signature, - HasNewCallbacksSignatureBit::kShift) -BOOL_ACCESSORS(InterceptorInfo, flags, has_dont_delete_property, - HasDontDeletePropertyBit::kShift) +BIT_FIELD_ACCESSORS(InterceptorInfo, flags, has_new_callbacks_signature, + InterceptorInfo::Flags::HasNewCallbacksSignatureBit) +BIT_FIELD_ACCESSORS(InterceptorInfo, flags, has_dont_delete_property, + InterceptorInfo::Flags::HasDontDeletePropertyBit) void InterceptorInfo::RemoveCallbackRedirectionForSerialization( IsolateForSandbox isolate) { diff --git a/deps/v8/src/objects/api-callbacks.h b/deps/v8/src/objects/api-callbacks.h index 2cb4b5cb3317..abd0c83930e8 100644 --- a/deps/v8/src/objects/api-callbacks.h +++ b/deps/v8/src/objects/api-callbacks.h @@ -6,6 +6,7 @@ #define V8_OBJECTS_API_CALLBACKS_H_ #include "src/base/bit-field.h" +#include "src/objects/bit-field-group.h" #include "src/objects/struct.h" #include "src/sandbox/external-pointer.h" @@ -37,8 +38,27 @@ V8_OBJECT class AccessorInfo : public HeapObject { inline void set_name(Tagged<Name> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline uint32_t flags() const; - inline void set_flags(uint32_t value); + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using IsSloppyBit = First<bool, 1>; + using ReplaceOnAccessBit = IsSloppyBit::Next<bool, 1>; + using GetterSideEffectTypeBits = + ReplaceOnAccessBit::Next<SideEffectType, 2>; + using SetterSideEffectTypeBits = + GetterSideEffectTypeBits::Next<SideEffectType, 2>; + using InitialAttributesBits = + SetterSideEffectTypeBits::Next<PropertyAttributes, 3>; + + BIT_FIELD_GROUP_ACCESSORS(is_sloppy, IsSloppyBit) + BIT_FIELD_GROUP_ACCESSORS(replace_on_access, ReplaceOnAccessBit) + BIT_FIELD_GROUP_ACCESSORS(getter_side_effect_type, GetterSideEffectTypeBits) + BIT_FIELD_GROUP_ACCESSORS(setter_side_effect_type, SetterSideEffectTypeBits) + BIT_FIELD_GROUP_ACCESSORS(initial_attributes, InitialAttributesBits) + }; + + inline Flags flags() const; + inline void set_flags(Flags value); // C function pointer that can be called from native code. DECL_REDIRECTED_CALLBACK_ACCESSORS_MAYBE_READ_ONLY_HOST(getter, Address) @@ -92,24 +112,14 @@ V8_OBJECT class AccessorInfo : public HeapObject { static const int kSize; private: - // Bit positions in |flags|. - using IsSloppyBit = base::BitField<bool, 0, 1, uint32_t>; - using ReplaceOnAccessBit = IsSloppyBit::Next<bool, 1>; - using GetterSideEffectTypeBits = ReplaceOnAccessBit::Next<SideEffectType, 2>; - using SetterSideEffectTypeBits = - GetterSideEffectTypeBits::Next<SideEffectType, 2>; - using InitialAttributesBits = - SetterSideEffectTypeBits::Next<PropertyAttributes, 3>; - friend class TorqueGeneratedAccessorInfoAsserts; - friend class TorqueGeneratedBitFieldAsserts; public: TaggedMember<Object> data_; TaggedMember<Name> name_; ExternalPointerMember<kAccessorInfoGetterTag> getter_; ExternalPointerMember<kAccessorInfoSetterTag> setter_; - uint32_t flags_; + Flags flags_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TAGGED_SIZE_8_BYTES @@ -127,6 +137,8 @@ inline constexpr int AccessorInfo::kSize = sizeof(AccessorInfo); V8_OBJECT class AccessCheckInfo : public Struct { public: + inline explicit AccessCheckInfo(const AllocationWitness& witness); + static Tagged<AccessCheckInfo> Get(Isolate* isolate, DirectHandle<JSObject> receiver); @@ -158,9 +170,9 @@ V8_OBJECT class AccessCheckInfo : public Struct { private: friend class TorqueGeneratedAccessCheckInfoAsserts; - TaggedMember<UnionOf<Foreign, Smi, Undefined>> callback_; - TaggedMember<UnionOf<InterceptorInfo, Smi, Undefined>> named_interceptor_; - TaggedMember<UnionOf<InterceptorInfo, Smi, Undefined>> indexed_interceptor_; + TaggedMember<UnionOf<Foreign, Zero, Undefined>> callback_; + TaggedMember<UnionOf<InterceptorInfo, Zero, Undefined>> named_interceptor_; + TaggedMember<UnionOf<InterceptorInfo, Zero, Undefined>> indexed_interceptor_; TaggedMember<Object> data_; } V8_OBJECT_END; @@ -188,9 +200,6 @@ V8_OBJECT class InterceptorInfo : public HeapObject { inline void set_data(Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline uint32_t flags() const; - inline void set_flags(uint32_t value); - // Convenient predicates without named/indexed prefix. inline bool has_getter() const; inline bool has_setter() const; @@ -250,23 +259,28 @@ V8_OBJECT class InterceptorInfo : public HeapObject { DECL_BOOLEAN_ACCESSORS(has_new_callbacks_signature) DECL_BOOLEAN_ACCESSORS(has_dont_delete_property) - using CanInterceptSymbolsBit = base::BitField<bool, 0, 1, uint32_t>; - using NonMaskingBit = CanInterceptSymbolsBit::Next<bool, 1>; - using NamedBit = NonMaskingBit::Next<bool, 1>; - using HasNoSideEffectBit = NamedBit::Next<bool, 1>; - using HasNewCallbacksSignatureBit = HasNoSideEffectBit::Next<bool, 1>; - using HasDontDeletePropertyBit = HasNewCallbacksSignatureBit::Next<bool, 1>; - enum Flag : uint32_t { - kNone = 0, - kCanInterceptSymbols = CanInterceptSymbolsBit::kMask, - kNonMasking = NonMaskingBit::kMask, - kNamed = NamedBit::kMask, - kHasNoSideEffect = HasNoSideEffectBit::kMask, - kHasNewCallbacksSignature = HasNewCallbacksSignatureBit::kMask, - kHasDontDeleteProperty = HasDontDeletePropertyBit::kMask, + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using CanInterceptSymbolsBit = First<bool, 1>; + using NonMaskingBit = CanInterceptSymbolsBit::Next<bool, 1>; + using NamedBit = NonMaskingBit::Next<bool, 1>; + using HasNoSideEffectBit = NamedBit::Next<bool, 1>; + using HasNewCallbacksSignatureBit = HasNoSideEffectBit::Next<bool, 1>; + using HasDontDeletePropertyBit = HasNewCallbacksSignatureBit::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(can_intercept_symbols, CanInterceptSymbolsBit) + BIT_FIELD_GROUP_ACCESSORS(non_masking, NonMaskingBit) + BIT_FIELD_GROUP_ACCESSORS(named, NamedBit) + BIT_FIELD_GROUP_ACCESSORS(has_no_side_effect, HasNoSideEffectBit) + BIT_FIELD_GROUP_ACCESSORS(has_new_callbacks_signature, + HasNewCallbacksSignatureBit) + BIT_FIELD_GROUP_ACCESSORS(has_dont_delete_property, + HasDontDeletePropertyBit) }; - using Flags = base::Flags<Flag>; - static constexpr int kFlagCount = 6; + + inline Flags flags() const; + inline void set_flags(Flags value); DECL_PRINTER(InterceptorInfo) DECL_VERIFIER(InterceptorInfo) @@ -295,7 +309,7 @@ V8_OBJECT class InterceptorInfo : public HeapObject { public: TaggedMember<Object> data_; - uint32_t flags_; + Flags flags_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TAGGED_SIZE_8_BYTES diff --git a/deps/v8/src/objects/api-callbacks.tq b/deps/v8/src/objects/api-callbacks.tq index 1b88c22a6d0f..b0d2a1146143 100644 --- a/deps/v8/src/objects/api-callbacks.tq +++ b/deps/v8/src/objects/api-callbacks.tq @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@cppScope('InterceptorInfo') -bitfield struct InterceptorInfoFlags extends uint31 { +@cppScope('InterceptorInfo::Flags') +bitfield struct InterceptorInfoFlags extends uint32 { can_intercept_symbols: bool: 1 bit; non_masking: bool: 1 bit; named: bool: 1 bit; @@ -39,7 +39,7 @@ extern class AccessCheckInfo extends Struct { type SideEffectType extends int32 constexpr 'SideEffectType'; -@cppScope('AccessorInfo') +@cppScope('AccessorInfo::Flags') bitfield struct AccessorInfoFlags extends uint32 { is_sloppy: bool: 1 bit; replace_on_access: bool: 1 bit; diff --git a/deps/v8/src/objects/arguments-inl.h b/deps/v8/src/objects/arguments-inl.h index 11e3087612bc..31d035ed435e 100644 --- a/deps/v8/src/objects/arguments-inl.h +++ b/deps/v8/src/objects/arguments-inl.h @@ -10,6 +10,7 @@ #include "src/objects/contexts-inl.h" #include "src/objects/objects-inl.h" +#include "src/objects/struct-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -17,12 +18,14 @@ namespace v8 { namespace internal { +AliasedArgumentsEntry::AliasedArgumentsEntry(const AllocationWitness& witness, + int aliased_context_slot) + : Struct(witness.roots().aliased_arguments_entry_map()), + aliased_context_slot_(Smi::FromInt(aliased_context_slot)) {} + int AliasedArgumentsEntry::aliased_context_slot() const { return aliased_context_slot_.load().value(); } -void AliasedArgumentsEntry::set_aliased_context_slot(int value) { - aliased_context_slot_.store(this, Smi::FromInt(value)); -} Tagged<Context> SloppyArgumentsElements::context() const { return context_.load(); diff --git a/deps/v8/src/objects/arguments.h b/deps/v8/src/objects/arguments.h index e76baae75d88..9939b09fd29a 100644 --- a/deps/v8/src/objects/arguments.h +++ b/deps/v8/src/objects/arguments.h @@ -85,8 +85,10 @@ class JSStrictArgumentsObject : public JSArgumentsObject { // - all attributes are available as part if the property details V8_OBJECT class AliasedArgumentsEntry : public Struct { public: + inline AliasedArgumentsEntry(const AllocationWitness& witness, + int aliased_context_slot); + inline int aliased_context_slot() const; - inline void set_aliased_context_slot(int value); using BodyDescriptor = StructBodyDescriptor; @@ -94,7 +96,7 @@ V8_OBJECT class AliasedArgumentsEntry : public Struct { DECL_VERIFIER(AliasedArgumentsEntry) public: - TaggedMember<Smi> aliased_context_slot_; + const TaggedMember<Smi> aliased_context_slot_; } V8_OBJECT_END; // Helper class to access FAST_ and SLOW_SLOPPY_ARGUMENTS_ELEMENTS, dividing @@ -185,7 +187,9 @@ V8_OBJECT class SloppyArgumentsElements // length_ / optional_padding_ live in FixedArrayBase. TaggedMember<Context> context_; TaggedMember<UnionOf<FixedArray, NumberDictionary>> arguments_; - FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); + V8_TQ_TAIL_LENGTH(length); + FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects, + V8_TQ_TYPE(Smi | TheHole)); } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/arguments.tq b/deps/v8/src/objects/arguments.tq index 222e240a547d..8e98b1f6114c 100644 --- a/deps/v8/src/objects/arguments.tq +++ b/deps/v8/src/objects/arguments.tq @@ -29,7 +29,7 @@ extern shape JSStrictArgumentsObject extends JSArgumentsObject { extern class SloppyArgumentsElements extends FixedArrayBase { context: Context; arguments: FixedArray|NumberDictionary; - mapped_entries[length]: Smi|TheHole; + objects[length]: Smi|TheHole; } @if(TAGGED_SIZE_8_BYTES) @@ -42,7 +42,7 @@ extern class SloppyArgumentsElements extends FixedArrayBase { optional_padding: 0, context, arguments, - mapped_entries: ...it + objects: ...it }; } @@ -55,7 +55,7 @@ extern class SloppyArgumentsElements extends FixedArrayBase { length, context, arguments, - mapped_entries: ...it + objects: ...it }; } @@ -326,7 +326,7 @@ macro AccessSloppyArgumentsCommon( try { if (OutOfBounds(key, elements.length)) goto Unmapped; - const mappedIndex = elements.mapped_entries[key]; + const mappedIndex = elements.objects[key]; typeswitch (mappedIndex) { case (contextIndex: Smi): { return &(elements.context.elements[contextIndex]); diff --git a/deps/v8/src/objects/backing-store.cc b/deps/v8/src/objects/backing-store.cc index 74df6b3162c8..e7e41a4d9968 100644 --- a/deps/v8/src/objects/backing-store.cc +++ b/deps/v8/src/objects/backing-store.cc @@ -8,6 +8,7 @@ #include <optional> #include "src/base/bits.h" +#include "src/base/platform/mutex.h" #include "src/execution/isolate.h" #include "src/handles/global-handles.h" #include "src/logging/counters.h" @@ -102,8 +103,9 @@ size_t BackingStore::GetWasmReservationSize(HasGuardRegions has_guard_regions, } // The backing store for a Wasm shared memory remembers all the isolates -// with which it has been shared. +// with which it has been shared, and serializes concurrent grow operations. struct SharedWasmMemoryData { + base::Mutex grow_mutex_; std::vector<Isolate*> isolates_; }; @@ -325,6 +327,7 @@ std::unique_ptr<BackingStore> BackingStore::TryAllocateAndPartiallyCommitMemory( auto gc_retry = [&](const auto& fn) { if (fn()) return true; + if (isolate == nullptr) return false; // Collect garbage and retry. did_retry = true; return isolate->heap()->allocator()->RetryCustomAllocate( @@ -519,14 +522,12 @@ std::optional<size_t> BackingStore::GrowWasmMemoryInPlace(Isolate* isolate, // * changing the permissions of additional {delta_pages} pages to kReadWrite; // * increment {byte_length_}; // - // As this code is executed concurrently, the following steps are executed: - // 1) Read the current value of {byte_length_}; - // 2) Change the permission of all pages from {buffer_start_} to - // {byte_length_} + {delta_pages} * {page_size} to kReadWrite; - // * This operation may be executed racefully. The OS takes care of - // synchronization. - // 3) Try to update {byte_length_} with a compare_exchange; - // 4) Repeat 1) to 3) until the compare_exchange in 3) succeeds; + // Concurrent grows of shared Wasm memory are serialized via {grow_mutex_} in + // {SharedWasmMemoryData}. Without serialization, a racing grow could set + // {kReadWrite} permissions on pages beyond {byte_length_} and then fail if + // another grow succeeded in between and caused it to exceed {max_pages}, + // leaving out-of-bounds pages accessible to Wasm trap-handler loads/stores + // and potentially non-zeroed for subsequent grows. // // The result of this function is the {byte_length_} before growing in pages. // The result of this function appears like the result of an RMW-update on @@ -539,49 +540,41 @@ std::optional<size_t> BackingStore::GrowWasmMemoryInPlace(Isolate* isolate, // also have kReadWrite permission. // * {byte_length_} is always lower or equal than the amount of memory with // permissions set to kReadWrite; - // * This is guaranteed by incrementing {byte_length_} with a - // compare_exchange after changing the permissions. - // * This invariant is the reason why we cannot use a fetch_add. + // * This is guaranteed by incrementing {byte_length_} after changing the + // permissions. DCHECK(is_wasm_memory()); max_pages = std::min(max_pages, byte_capacity_ / wasm::kWasmPageSize); - // Do a compare-exchange loop, because we also need to adjust page - // permissions. Note that multiple racing grows both try to set page - // permissions for the entire range (to be RW), so the operating system - // should deal with that raciness. We know we succeeded when we can - // compare/swap the old length with the new length. - size_t old_length = byte_length_.load(std::memory_order_relaxed); - if (delta_pages == 0) { - return {old_length / wasm::kWasmPageSize}; // degenerate grow. + return {byte_length_.load(std::memory_order_seq_cst) / + wasm::kWasmPageSize}; // degenerate grow. } - if (delta_pages > max_pages) return {}; // would never work. + if (delta_pages > max_pages) return {}; // would never work. - size_t new_length = 0; - while (true) { - size_t current_pages = old_length / wasm::kWasmPageSize; + std::optional<base::MutexGuard> mutex_guard; + if (is_shared()) { + mutex_guard.emplace(&get_shared_wasm_memory_data()->grow_mutex_); + } - // Check if we have exceed the supplied maximum. - if (current_pages > (max_pages - delta_pages)) return {}; + size_t old_length = byte_length_.load(std::memory_order_seq_cst); + size_t current_pages = old_length / wasm::kWasmPageSize; - new_length = (current_pages + delta_pages) * wasm::kWasmPageSize; + // Check if we have exceeded the supplied maximum. + if (current_pages > (max_pages - delta_pages)) return {}; - // Try to adjust the permissions on the memory. - if (!i::SetPermissions(GetPlatformPageAllocator(), buffer_start_, - new_length, PageAllocator::kReadWrite)) { - // This is a nondeterministic failure; mark as such in the WasmEngine (for - // differential fuzzing). - wasm::WasmEngine::set_had_nondeterminism(); - return {}; - } - if (byte_length_.compare_exchange_weak(old_length, new_length, - std::memory_order_acq_rel)) { - // Successfully updated both the length and permissions. - break; - } + size_t new_length = (current_pages + delta_pages) * wasm::kWasmPageSize; + + // Try to adjust the permissions on the memory. + if (!i::SetPermissions(GetPlatformPageAllocator(), buffer_start_, new_length, + PageAllocator::kReadWrite)) { + // This is a nondeterministic failure; mark as such in the WasmEngine (for + // differential fuzzing). + wasm::WasmEngine::set_had_nondeterminism(); + return {}; } - return {old_length / wasm::kWasmPageSize}; + byte_length_.store(new_length, std::memory_order_seq_cst); + return {current_pages}; } void BackingStore::BroadcastSharedWasmMemoryGrow(Isolate* isolate) const { @@ -921,7 +914,6 @@ void GlobalBackingStoreRegistry::UpdateSharedWasmMemoryObjects( Tagged<WasmMemoryObject> memory_object = Cast<WasmMemoryObject>(obj); - memory_object->UpdateInstances(isolate); if (Tagged<JSArrayBuffer> shared_ab; TryCast<JSArrayBuffer>(memory_object->array_buffer(), &shared_ab) && !shared_ab->is_resizable_by_js()) { diff --git a/deps/v8/src/objects/backing-store.h b/deps/v8/src/objects/backing-store.h index 6e2eebcf10cf..a8ec690c3f23 100644 --- a/deps/v8/src/objects/backing-store.h +++ b/deps/v8/src/objects/backing-store.h @@ -107,6 +107,12 @@ class V8_EXPORT_PRIVATE BackingStore : public BackingStoreBase { std::memory_order memory_order = std::memory_order_relaxed) const { return byte_length_.load(memory_order); } + // Returns the address of the atomic byte length. Used by WebAssembly shared + // memories to observe dynamic growth directly from JIT code without writing + // to trusted space. + const std::atomic<size_t>* byte_length_address() const { + return &byte_length_; + } size_t max_byte_length() const { return max_byte_length_; } size_t byte_capacity() const { return byte_capacity_; } SharedFlag is_shared() const { return SharedFlag{has_flag(kIsShared)}; } diff --git a/deps/v8/src/objects/bigint.cc b/deps/v8/src/objects/bigint.cc index f3ade6235d09..4a2e327851cf 100644 --- a/deps/v8/src/objects/bigint.cc +++ b/deps/v8/src/objects/bigint.cc @@ -165,7 +165,7 @@ MaybeHandle<T> ThrowBigIntTooBig(Isolate* isolate) { // behavior is accepted. To prevent the correctness fuzzer from detecting this // difference, we crash the program. if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("Aborting on invalid BigInt length"); + base::FatalNoSecurityImpact("Aborting on invalid BigInt length"); } THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig)); } @@ -1391,12 +1391,14 @@ MaybeDirectHandle<BigInt> BigInt::AsUintN(Isolate* isolate, uint64_t n, return MutableBigInt::MakeImmutable(result); } -Handle<BigInt> BigInt::FromInt64(Isolate* isolate, int64_t n) { - if (n == 0) return MutableBigInt::Zero(isolate); +template <typename IsolateT> +Handle<BigInt> BigInt::FromInt64(IsolateT* isolate, int64_t n, + AllocationType allocation) { + if (n == 0) return MutableBigInt::Zero(isolate, allocation); static_assert(kDigitBits == 64 || kDigitBits == 32); uint32_t length = 64 / kDigitBits; Handle<MutableBigInt> result = - Cast<MutableBigInt>(isolate->factory()->NewBigInt(length)); + Cast<MutableBigInt>(isolate->factory()->NewBigInt(length, allocation)); bool sign = n < 0; result->initialize_bitfield(sign, length); uint64_t absolute; @@ -1412,17 +1414,31 @@ Handle<BigInt> BigInt::FromInt64(Isolate* isolate, int64_t n) { result->set_64_bits(absolute); return MutableBigInt::MakeImmutable(result); } +template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) + Handle<BigInt> BigInt::FromInt64(Isolate* isolate, int64_t n, + AllocationType allocation); +template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) + Handle<BigInt> BigInt::FromInt64(LocalIsolate* isolate, int64_t n, + AllocationType allocation); -Handle<BigInt> BigInt::FromUint64(Isolate* isolate, uint64_t n) { - if (n == 0) return MutableBigInt::Zero(isolate); +template <typename IsolateT> +Handle<BigInt> BigInt::FromUint64(IsolateT* isolate, uint64_t n, + AllocationType allocation) { + if (n == 0) return MutableBigInt::Zero(isolate, allocation); static_assert(kDigitBits == 64 || kDigitBits == 32); uint32_t length = 64 / kDigitBits; Handle<MutableBigInt> result = - Cast<MutableBigInt>(isolate->factory()->NewBigInt(length)); + Cast<MutableBigInt>(isolate->factory()->NewBigInt(length, allocation)); result->initialize_bitfield(false, length); result->set_64_bits(n); return MutableBigInt::MakeImmutable(result); } +template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) + Handle<BigInt> BigInt::FromUint64(Isolate* isolate, uint64_t n, + AllocationType allocation); +template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) + Handle<BigInt> BigInt::FromUint64(LocalIsolate* isolate, uint64_t n, + AllocationType allocation); MaybeDirectHandle<BigInt> BigInt::FromWords64(Isolate* isolate, int sign_bit, uint32_t words64_count, diff --git a/deps/v8/src/objects/bigint.h b/deps/v8/src/objects/bigint.h index 3ff1cfd5b466..4cb4835f08b8 100644 --- a/deps/v8/src/objects/bigint.h +++ b/deps/v8/src/objects/bigint.h @@ -255,10 +255,16 @@ V8_OBJECT class BigInt : public BigIntBase { static MaybeDirectHandle<BigInt> AsUintN(Isolate* isolate, uint64_t n, DirectHandle<BigInt> x); - V8_EXPORT_PRIVATE static Handle<BigInt> FromInt64(Isolate* isolate, - int64_t n); - V8_EXPORT_PRIVATE static Handle<BigInt> FromUint64(Isolate* isolate, - uint64_t n); + template <typename IsolateT> + EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) + static Handle<BigInt> FromInt64( + IsolateT* isolate, int64_t n, + AllocationType allocation = AllocationType::kYoung); + template <typename IsolateT> + EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) + static Handle<BigInt> FromUint64( + IsolateT* isolate, uint64_t n, + AllocationType allocation = AllocationType::kYoung); static MaybeDirectHandle<BigInt> FromWords64(Isolate* isolate, int sign_bit, uint32_t words64_count, const uint64_t* words); diff --git a/deps/v8/src/objects/bit-field-group.h b/deps/v8/src/objects/bit-field-group.h new file mode 100644 index 000000000000..2568b67fae70 --- /dev/null +++ b/deps/v8/src/objects/bit-field-group.h @@ -0,0 +1,81 @@ +// Copyright 2026 the V8 project 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 V8_OBJECTS_BIT_FIELD_GROUP_H_ +#define V8_OBJECTS_BIT_FIELD_GROUP_H_ + +#include <type_traits> + +#include "src/base/bit-field.h" +#include "src/base/macros.h" + +namespace v8::internal { + +// Base class for a struct that holds a base::BitField chain and is used as the +// type of the object member storing those bits: +// +// class Map { +// struct Bits1 : BitFieldGroup<Bits1, uint8_t> { +// using BitFieldGroup::BitFieldGroup; +// using IsCallableBit = First<bool, 1>; +// using IsUndetectableBit = IsCallableBit::Next<bool, 1>; +// BIT_FIELD_GROUP_ACCESSORS(is_callable, IsCallableBit) +// BIT_FIELD_GROUP_ACCESSORS(is_undetectable, IsUndetectableBit) +// }; +// std::atomic<Bits1> bit_field_; +// }; +// +// Metagen recognizes members of such types and records the chain in the +// layout JSON, from which Torque derives (or verifies) the corresponding +// bitfield struct. Naming and layout requirements: +// - Every type alias in the struct must be a base::BitField; they are read in +// declaration order. Fields may overlap, but must fit the storage. +// - The Torque field name is the alias name without its Bit/Bits suffix, in +// snake_case (IsCallableBit -> is_callable). The getter names follow the +// same convention. +// - The Torque struct name is the C++ name with the enclosing class names +// prepended (Map::Bits1 -> MapBits1). +// +// Implicit conversions to and from U support Bit::decode(bit_field()) and +// set_bit_field(Bit::update(bit_field(), v)). get<Bit>() reads a field; +// with<Bit>(v) returns a copy with that field updated. The caller must store +// the updated copy back to the member. value() returns the underlying integer. +// +// Use SmiBitFieldMember<Group> for groups stored as Smis. +template <typename Derived, typename U> +class BitFieldGroup { + public: + static_assert(std::is_unsigned_v<U>); + + using GroupType = Derived; + using UnderlyingType = U; + + template <typename T, int size> + using First = base::BitField<T, 0, size, U>; + + constexpr BitFieldGroup() = default; + // NOLINTNEXTLINE(runtime/explicit) + constexpr BitFieldGroup(U value) : value_(value) {} + constexpr operator U() const { return value_; } + constexpr U value() const { return value_; } + + template <typename Bit> + constexpr typename Bit::FieldType get() const { + static_assert(std::is_same_v<typename Bit::BaseType, U>); + return Bit::decode(value_); + } + + template <typename Bit> + V8_NODISCARD constexpr Derived with(typename Bit::FieldType value) const { + static_assert(std::is_same_v<typename Bit::BaseType, U>); + return Derived(Bit::update(value_, value)); + } + + private: + U value_ = 0; +}; + +} // namespace v8::internal + +#endif // V8_OBJECTS_BIT_FIELD_GROUP_H_ diff --git a/deps/v8/src/objects/bytecode-array-inl.h b/deps/v8/src/objects/bytecode-array-inl.h index 45f8387158f2..24cb98305fe4 100644 --- a/deps/v8/src/objects/bytecode-array-inl.h +++ b/deps/v8/src/objects/bytecode-array-inl.h @@ -12,7 +12,8 @@ #include "src/heap/heap-write-barrier-inl.h" #include "src/interpreter/bytecode-register.h" #include "src/objects/fixed-primitive-array-inl.h" -#include "src/objects/trusted-pointer-inl.h" +#include "src/objects/struct-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -244,6 +245,9 @@ void BytecodeArray::MarkVerified(IsolateForSandbox isolate) { wrapper()->set_bytecode(Tagged(this)); } +BytecodeWrapper::BytecodeWrapper(const AllocationWitness& witness) + : Struct(witness.roots().bytecode_wrapper_map()) {} + Tagged<BytecodeArray> BytecodeWrapper::bytecode( IsolateForSandbox isolate) const { return bytecode_.load(isolate); diff --git a/deps/v8/src/objects/bytecode-array.h b/deps/v8/src/objects/bytecode-array.h index 2546b616968a..c49d437c2f8c 100644 --- a/deps/v8/src/objects/bytecode-array.h +++ b/deps/v8/src/objects/bytecode-array.h @@ -7,7 +7,7 @@ #include "src/objects/struct.h" #include "src/objects/trusted-object.h" -#include "src/objects/trusted-pointer.h" +#include "src/sandbox/trusted-pointer.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -146,7 +146,7 @@ V8_OBJECT class BytecodeArray : public ExposedTrustedObject { inline void MarkVerified(IsolateForSandbox isolate); public: - TaggedMember<Smi> length_; + V8_TQ_CONST TaggedMember<Smi> length_; TaggedMember<BytecodeWrapper> wrapper_; ProtectedTaggedMember<TrustedByteArray> source_position_table_; ProtectedTaggedMember<TrustedByteArray> handler_table_; @@ -158,6 +158,7 @@ V8_OBJECT class BytecodeArray : public ExposedTrustedObject { #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(uint8_t, bytes); } V8_OBJECT_END; @@ -173,6 +174,8 @@ inline constexpr int BytecodeArray::kMaxLength = // stored along other tagged pointers inside an array or similar datastructure. V8_OBJECT class BytecodeWrapper : public Struct { public: + inline explicit BytecodeWrapper(const AllocationWitness& witness); + DECL_TRUSTED_POINTER_ACCESSORS(bytecode, BytecodeArray) DECL_PRINTER(BytecodeWrapper) @@ -181,7 +184,7 @@ V8_OBJECT class BytecodeWrapper : public Struct { class BodyDescriptor; public: - TrustedPointerMember<BytecodeArray, kBytecodeArrayIndirectPointerTag> + TrustedPointerMember<BytecodeArray, kBytecodeArrayTrustedPointerTag> bytecode_; } V8_OBJECT_END; diff --git a/deps/v8/src/objects/call-site-info-inl.h b/deps/v8/src/objects/call-site-info-inl.h index bdfbf46e7690..a3dba3e342e7 100644 --- a/deps/v8/src/objects/call-site-info-inl.h +++ b/deps/v8/src/objects/call-site-info-inl.h @@ -31,41 +31,35 @@ BOOL_GETTER(CallSiteInfo, flags, IsStrict, IsStrictBit::kShift) BOOL_GETTER(CallSiteInfo, flags, IsConstructor, IsConstructorBit::kShift) BOOL_GETTER(CallSiteInfo, flags, IsAsync, IsAsyncBit::kShift) +CallSiteInfo::CallSiteInfo( + const AllocationWitness& witness, Tagged<JSAny> receiver_or_instance, + Tagged<Union<JSFunction, Smi>> function, + Tagged<Union<Code, BytecodeArray, Undefined>> code_object, + int code_offset_or_source_position, int flags) + : Struct(witness.roots().call_site_info_map()), + code_object_(witness, code_object), + receiver_or_instance_(witness, receiver_or_instance), + function_(witness, function), + code_offset_or_source_position_( + Smi::FromInt(code_offset_or_source_position)), + flags_(Smi::FromInt(flags)) {} + Tagged<HeapObject> CallSiteInfo::code_object(IsolateForSandbox isolate) const { // The field can contain either a Code or a BytecodeArray, so we need to use - // the kUnknownIndirectPointerTag. Since we can then no longer rely on the + // the kUnknownTrustedPointerTag. Since we can then no longer rely on the // type-checking mechanism of trusted pointers we need to perform manual type // checks afterwards. Tagged<Object> object = code_object_.Acquire_Load_maybe_empty(isolate); return CheckedCast<Union<Code, BytecodeArray>>(object); } -void CallSiteInfo::set_code_object( - Tagged<Union<Code, BytecodeArray, Undefined>> maybe_code, - WriteBarrierMode mode) { - if (Tagged<Union<Code, BytecodeArray>> code; TryCast(maybe_code, &code)) { - code_object_.store(this, code, mode); - } else { - DCHECK(IsUndefined(maybe_code)); - code_object_.clear(this); - } -} - Tagged<JSAny> CallSiteInfo::receiver_or_instance() const { return receiver_or_instance_.load(); } -void CallSiteInfo::set_receiver_or_instance(Tagged<JSAny> value, - WriteBarrierMode mode) { - receiver_or_instance_.store(this, value, mode); -} Tagged<Union<JSFunction, Smi>> CallSiteInfo::function() const { return function_.load(); } -void CallSiteInfo::set_function(Tagged<Union<JSFunction, Smi>> value, - WriteBarrierMode mode) { - function_.store(this, value, mode); -} int CallSiteInfo::code_offset_or_source_position() const { return code_offset_or_source_position_.load().value(); diff --git a/deps/v8/src/objects/call-site-info.cc b/deps/v8/src/objects/call-site-info.cc index 2df214154400..9d2fcd664182 100644 --- a/deps/v8/src/objects/call-site-info.cc +++ b/deps/v8/src/objects/call-site-info.cc @@ -524,8 +524,7 @@ DirectHandle<Object> CallSiteInfo::GetMethodName( // ES2015 gives getters and setters name prefixes which must // be stripped to find the property name. - if (name->HasOneBytePrefix(base::CStrVector("get ")) || - name->HasOneBytePrefix(base::CStrVector("set "))) { + if (name->HasOneBytePrefix("get ") || name->HasOneBytePrefix("set ")) { name = isolate->factory()->NewProperSubString(name, 4, name->length()); } else if (name->length() == 0) { // The function doesn't have a meaningful "name" property, however diff --git a/deps/v8/src/objects/call-site-info.h b/deps/v8/src/objects/call-site-info.h index c4d226373e84..a6befcadc95b 100644 --- a/deps/v8/src/objects/call-site-info.h +++ b/deps/v8/src/objects/call-site-info.h @@ -10,7 +10,7 @@ #include "src/base/bit-field.h" #include "src/objects/objects-body-descriptors.h" #include "src/objects/struct.h" -#include "src/objects/trusted-pointer.h" +#include "src/sandbox/trusted-pointer.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -74,18 +74,17 @@ V8_OBJECT class CallSiteInfo : public Struct { bool IsPromiseAny() const; bool IsNative() const; + inline CallSiteInfo(const AllocationWitness& witness, + Tagged<JSAny> receiver_or_instance, + Tagged<Union<JSFunction, Smi>> function, + Tagged<Union<Code, BytecodeArray, Undefined>> code_object, + int code_offset_or_source_position, int flags); + inline Tagged<HeapObject> code_object(IsolateForSandbox isolate) const; - inline void set_code_object( - Tagged<Union<Code, BytecodeArray, Undefined>> code, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<JSAny> receiver_or_instance() const; - inline void set_receiver_or_instance( - Tagged<JSAny> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<Union<JSFunction, Smi>> function() const; - inline void set_function(Tagged<Union<JSFunction, Smi>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline int code_offset_or_source_position() const; inline void set_code_offset_or_source_position( @@ -174,17 +173,17 @@ V8_OBJECT class CallSiteInfo : public Struct { friend class TorqueGeneratedCallSiteInfoAsserts; friend struct ObjectTraits<CallSiteInfo>; - static constexpr IndirectPointerTagRange kCodeObjectTagRange = - IndirectPointerTagRange(kBytecodeArrayIndirectPointerTag, - kCodeIndirectPointerTag); + static constexpr TrustedPointerTagRange kCodeObjectTagRange = + TrustedPointerTagRange(kBytecodeArrayTrustedPointerTag, + kCodeTrustedPointerTag); static_assert(kCodeObjectTagRange.Size() == 2); - TrustedPointerMember<Union<Code, BytecodeArray>, kCodeObjectTagRange> + const TrustedPointerMember<Union<Code, BytecodeArray>, kCodeObjectTagRange> code_object_; - TaggedMember<JSAny> receiver_or_instance_; - TaggedMember<Union<JSFunction, Smi>> function_; + const TaggedMember<JSAny> receiver_or_instance_; + const TaggedMember<Union<JSFunction, Smi>> function_; TaggedMember<Smi> code_offset_or_source_position_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<CallSiteInfoFlags>); } V8_OBJECT_END; template <> diff --git a/deps/v8/src/objects/casting.h b/deps/v8/src/objects/casting.h index 9c5d50e52675..af6102b6081c 100644 --- a/deps/v8/src/objects/casting.h +++ b/deps/v8/src/objects/casting.h @@ -111,7 +111,9 @@ namespace v8::internal { // CastTraits<T> is a type trait that defines type checking behaviour for -// tagged object casting. The expected specialization is: +// tagged object casting. It only ever receives strong references or Smis; +// reference strength and structural targets (Union, Weak) are handled by +// CastTraitsImpl below. The expected specialization is: // // template<> // struct CastTraits<SomeObject> { @@ -126,7 +128,8 @@ namespace v8::internal { // HeapObjects and the Object implementation has additional overhead in Smi // checks. // -// struct CastTraits<Object> { +// template<> +// struct CastTraits<SomeObject> { // static bool AllowFrom(Tagged<HeapObject> value) { // return IsSomeObject(value); // } @@ -138,15 +141,62 @@ namespace v8::internal { template <typename To> struct CastTraits; +// CastTraitsImpl<T>::AllowFrom accepts any tagged source and checks membership +// in T, including reference strength. This is what Is<T> and the Cast family +// call. Do not specialize for object types; the primary template forwards to +// CastTraits<T>. Only structural targets (Weak, Union, ClearedWeakValue) +// specialize it. +// +// The static source type is kept as narrow as possible: Tagged<Union<...>> of +// heap objects only derives from Tagged<HeapObject>, so overload resolution +// picks the HeapObject overload of CastTraits<T>::AllowFrom and skips the Smi +// check. +template <typename T> +struct CastTraitsImpl { + // T is Smi or a strong HeapObject type; Weak, Union and ClearedWeakValue + // targets are handled by the specializations below. + static_assert(!is_maybe_weak_v<T> && !is_union_v<T> && + !std::is_same_v<T, ClearedWeakValue>); + + template <typename U> + static inline bool AllowFrom(Tagged<U> value) { + if constexpr (std::is_same_v<U, ClearedWeakValue>) { + // Always weak-tagged, and StrongOf<ClearedWeakValue> is not a strong + // type. + return false; + } else if constexpr (!is_maybe_weak_v<U>) { + return CastTraits<T>::AllowFrom(value); + } else { + // U is maybe-weak: Weak<X> or a Union with a weak member (e.g. + // MaybeWeak<X>, MaybeObject). T, on the other hand, is a strong target, + // so a weak reference is never a T. + if constexpr (std::is_same_v<T, Smi>) { + // A weak-tagged word is never Smi-tagged, so no strength check needed. + return value.IsSmi(); + } + if (!value.IsStrongOrSmi()) return false; + // Re-type the now strong value as StrongOf<U>, e.g. + // Union<A, Weak<B>> -> Union<A, B>. This keeps B even though a strong B + // cannot occur, but the Tagged base class (and thus the selected + // overload) is the same as for Union<A>. + // TODO(jgruber): Filter Weak members out of the Union instead of keeping + // their strong counterparts. + // The bits are already strong; do not use MakeStrong, whose tag masking + // clobbers Smi payload bit 1 under 31-bit Smi tagging. + return CastTraits<T>::AllowFrom(UncheckedCast<StrongOf<U>>(value)); + } + } +}; + class Oddball; template <typename T> concept NotGCedType = !std::is_base_of_v<HeapObject, T>; -// `Is<T>(value)` checks whether `value` is a tagged object of type `T`. +// `Is<T>(value)` checks membership in T, including reference strength. template <typename T, typename U> inline bool Is(Tagged<U> value) { - return CastTraits<T>::AllowFrom(value); + return CastTraitsImpl<T>::AllowFrom(value); } template <typename T> inline bool Is(const HeapObject* obj) { @@ -334,6 +384,9 @@ template <typename To, typename From, template <typename> class Holder> requires HasCastImplementation<Holder, To, From> inline Holder<To> TrustedCast( Holder<From> value, SourceLocation loc = SourceLocation::CurrentIfDebug()) { + static_assert(is_subtype_v<To, TrustedObject> || + is_subtype_v<To, ExposedTrustedObject> || + is_subtype_v<To, Union<Smi, TrustedObject>>); // Casting pointers to in-sandbox objects is allowed even with an active // DisallowSandboxAccess scope (as casting itself doesn't access any memory). // However, in debug builds the DCHECK below will need to access the Map of @@ -436,7 +489,9 @@ inline Holder<To> Cast(Holder<From> value, " Tagged<Trusted> t = " "TrustedCast<Trusted>(TrustedPointerField::ReadTrustedPointerField<" "kTrustedTag>(obj, ...));\n"); - return TrustedCast<To>(value, loc); + DCHECK_WITH_SANDBOX_ACCESS_AND_MSG_AND_LOC( + NullOrIs<To>(value), V8_PRETTY_FUNCTION_VALUE_OR("Cast type check"), loc); + return UncheckedCast<To>(value); } // TODO(leszeks): Figure out a way to make these cast to actual pointers rather @@ -486,72 +541,57 @@ inline Derived* Cast(Base* from, return static_cast<Derived*>(from); } -// `Is<T>(maybe_weak_value)` specialization for possible weak values and strong -// target `T`, that additionally first checks whether `maybe_weak_value` is -// actually a strong value (or a Smi, which can't be weak). -template <typename T, typename U> -inline bool Is(Tagged<MaybeWeak<U>> value) { - // Cast from maybe weak to strong needs to be strong or smi. - if constexpr (!is_maybe_weak_v<T>) { - if (!value.IsStrongOrSmi()) return false; - return CastTraits<T>::AllowFrom(Tagged<U>(value.ptr())); - } else { - // Dispatches to CastTraits<MaybeWeak<T>> below. - return CastTraits<T>::AllowFrom(value); - } -} -template <typename T, typename... U> -constexpr inline bool Is(Tagged<Union<U...>> value) { - using UnionU = Union<U...>; - if constexpr (is_weak_v<UnionU>) { - return Is<T>(Tagged<Weak<HeapObject>>(value)); - } else if constexpr (is_maybe_weak_v<UnionU>) { - // Cleared values are always ok. - if (value.IsCleared()) return true; - // TODO(leszeks): Skip Smi check for values that are known to not be Smi. - if (value.IsSmi()) { - return Is<T>(Tagged<Smi>(value.ptr())); - } - return Is<T>(MakeStrong(value)); - } else if constexpr (is_subtype_v<UnionU, HeapObject>) { - return Is<T>(Tagged<HeapObject>(value)); - } else { - static_assert(is_subtype_v<UnionU, Object>); - return Is<T>(Tagged<Object>(value)); - } -} - -// Specialization for weak cast targets, which first converts the incoming -// value to a strong reference and then checks if the cast to the strong T -// is allowed. Cleared weak references always return true. +// Cleared references belong to every Weak<T>, irrespective of payload type. template <typename T> -struct CastTraits<Weak<T>> { +struct CastTraitsImpl<Weak<T>> { template <typename U> static bool AllowFrom(Tagged<U> value) { - if constexpr (is_weak_v<U>) { - return CastTraits<T>::AllowFrom(MakeStrong(value)); - } - if constexpr (is_maybe_weak_v<U>) { - // Cleared values are always ok. - if (value.IsCleared()) return true; - // TODO(leszeks): Skip Smi check for values that are known to not be Smi. - if (value.IsSmi()) return false; - return CastTraits<T>::AllowFrom(MakeStrong(value)); - } else { - // Can't cast weak to non-weak. + if constexpr (std::is_same_v<U, ClearedWeakValue>) { + return true; + } else if constexpr (!is_maybe_weak_v<U>) { + // A strong reference is never a Weak<T>. return false; + } else { + if (value.IsCleared()) return true; + // Only sources that admit strong references need the tag test. + if constexpr (!is_weak_v<U>) { + if (!value.IsWeak()) return false; + } + // The reference is weak, hence not a Smi, but U may still have Smi + // members (e.g. MaybeObject), which MakeStrong rejects statically. Since + // there is no Weak<Smi>, Weak<HeapObject> is the tightest Smi-free type + // in that case; otherwise keep WeakOf<U> (MaybeWeak<Map> -> Weak<Map>). + using WeakU = + std::conditional_t<is_subtype_v<Smi, U>, Weak<HeapObject>, WeakOf<U>>; + return Is<T>(MakeStrong(UncheckedCast<WeakU>(value))); } } }; template <typename... T> -struct CastTraits<Union<T...>> { - static inline bool AllowFrom(Tagged<Object> value) { +struct CastTraitsImpl<Union<T...>> { + template <typename U> + static inline bool AllowFrom(Tagged<U> value) { return (Is<T>(value) || ...); } - static inline bool AllowFrom(Tagged<HeapObject> value) { - return (Is<T>(value) || ...); +}; + +template <> +struct CastTraitsImpl<ClearedWeakValue> { + template <typename U> + static inline bool AllowFrom(Tagged<U> value) { + return value.IsCleared(); + } +}; + +// ReadOnly<T> is a strong predicate on T, so it is a plain CastTraits +// specialization and goes through the primary CastTraitsImpl. +template <typename T> +struct CastTraits<ReadOnly<T>> { + static inline bool AllowFrom(Tagged<Object> value) { + return value.IsHeapObject() && AllowFrom(UncheckedCast<HeapObject>(value)); } + static inline bool AllowFrom(Tagged<HeapObject> value); }; template <> diff --git a/deps/v8/src/objects/cell-inl.h b/deps/v8/src/objects/cell-inl.h index aa80b2c90114..fe62f90e074a 100644 --- a/deps/v8/src/objects/cell-inl.h +++ b/deps/v8/src/objects/cell-inl.h @@ -10,6 +10,8 @@ #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/heap-object-inl.h" +#include "src/objects/heap-object-set-map-inl.h" +#include "src/roots/roots-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -17,6 +19,16 @@ namespace v8 { namespace internal { +Cell::Cell(const AllocationWitness& witness) + : HeapObject(witness.roots().cell_map()), + maybe_value_(witness.roots().undefined_value()) {} + +Cell::Cell(const AllocationWitness& witness, Tagged<Smi> value) + : HeapObject(witness.roots().cell_map()), maybe_value_(value) {} + +Cell::Cell(const AllocationWitness& witness, Tagged<ClearedWeakValue> value) + : HeapObject(witness.roots().cell_map()), maybe_value_(value) {} + Tagged<MaybeObject> Cell::maybe_value() const { return maybe_value_.load(); } Tagged<MaybeObject> Cell::maybe_value(RelaxedLoadTag) const { diff --git a/deps/v8/src/objects/cell.h b/deps/v8/src/objects/cell.h index 8d473a96922f..52a90eddd037 100644 --- a/deps/v8/src/objects/cell.h +++ b/deps/v8/src/objects/cell.h @@ -15,6 +15,10 @@ namespace internal { V8_OBJECT class Cell : public HeapObject { public: + inline explicit Cell(const AllocationWitness& witness); + inline Cell(const AllocationWitness& witness, Tagged<Smi> value); + inline Cell(const AllocationWitness& witness, Tagged<ClearedWeakValue> value); + // [maybe_value]: field containing a possibly weak reference to an object. inline Tagged<MaybeObject> maybe_value() const; inline Tagged<MaybeObject> maybe_value(RelaxedLoadTag) const; diff --git a/deps/v8/src/objects/code-inl.h b/deps/v8/src/objects/code-inl.h index afa21f63570e..32e98606640b 100644 --- a/deps/v8/src/objects/code-inl.h +++ b/deps/v8/src/objects/code-inl.h @@ -19,8 +19,9 @@ #include "src/objects/heap-object-field-inl.h" #include "src/objects/instance-type-inl.h" #include "src/objects/instruction-stream-inl.h" +#include "src/objects/struct-inl.h" #include "src/objects/trusted-object-inl.h" -#include "src/objects/trusted-pointer-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" #include "src/snapshot/embedded/embedded-data-inl.h" #include "src/utils/memcopy.h" @@ -852,9 +853,9 @@ void Code::SetInstructionStartForOffHeapBuiltin(IsolateForSandbox isolate, void Code::ClearInstructionStartForSerialization(IsolateForSandbox isolate) { #ifdef V8_ENABLE_SANDBOX // The instruction start is stored in this object's code pointer table. - WriteField<IndirectPointerHandle>( - offsetof(ExposedTrustedObject, self_indirect_pointer_), - kNullIndirectPointerHandle); + WriteField<TrustedPointerHandle>( + offsetof(ExposedTrustedObject, self_trusted_pointer_), + kNullTrustedPointerHandle); #endif // V8_ENABLE_SANDBOX set_instruction_start(isolate, kNullAddress); ExternalCodeField<Object>::Release_Store(this, Smi::zero()); @@ -934,6 +935,9 @@ inline void Code::set_js_dispatch_handle(JSDispatchHandle handle) { handle.value()); } +CodeWrapper::CodeWrapper(const AllocationWitness& witness) + : Struct(witness.roots().code_wrapper_map()) {} + Tagged<Code> CodeWrapper::code(IsolateForSandbox isolate) const { return code_.load(isolate); } diff --git a/deps/v8/src/objects/code.cc b/deps/v8/src/objects/code.cc index 20b4a9455917..8d06ea332167 100644 --- a/deps/v8/src/objects/code.cc +++ b/deps/v8/src/objects/code.cc @@ -4,6 +4,7 @@ #include "src/objects/code.h" +#include <array> #include <iomanip> #include "src/codegen/assembler-inl.h" @@ -287,11 +288,11 @@ void Disassemble(const char* name, std::ostream& os, Isolate* isolate, if (int pool_size = code->constant_pool_size()) { DCHECK_EQ(pool_size & kPointerAlignmentMask, 0); os << "\nConstant Pool (size = " << pool_size << ")\n"; - base::Vector<char> buf = base::Vector<char>::New(50); + std::array<char, 50> buf; intptr_t* ptr = reinterpret_cast<intptr_t*>(code->constant_pool()); for (int i = 0; i < pool_size; i += kSystemPointerSize, ptr++) { - SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr); - os << static_cast<const void*>(ptr) << " " << buf.begin() << "\n"; + base::SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr); + os << static_cast<const void*>(ptr) << " " << buf.data() << "\n"; } } } diff --git a/deps/v8/src/objects/code.h b/deps/v8/src/objects/code.h index 3f9ac591e9a6..30495433098d 100644 --- a/deps/v8/src/objects/code.h +++ b/deps/v8/src/objects/code.h @@ -9,8 +9,8 @@ #include "src/objects/code-kind.h" #include "src/objects/struct.h" #include "src/objects/trusted-object.h" -#include "src/objects/trusted-pointer.h" #include "src/sandbox/code-entrypoint-tag.h" +#include "src/sandbox/trusted-pointer.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -585,6 +585,8 @@ V8_OBJECT class CodeWrapper : public Struct { V8_IT_NO_AUTO_DISPATCH; public: + inline explicit CodeWrapper(const AllocationWitness& witness); + DECL_CODE_POINTER_ACCESSORS(code) DECL_PRINTER(CodeWrapper) @@ -593,7 +595,7 @@ V8_OBJECT class CodeWrapper : public Struct { class BodyDescriptor; public: - TrustedPointerMember<Code, kCodeIndirectPointerTag> code_; + TrustedPointerMember<Code, kCodeTrustedPointerTag> code_; } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/compressed-slots.h b/deps/v8/src/objects/compressed-slots.h index 3b921a05127b..df4db6a8b55d 100644 --- a/deps/v8/src/objects/compressed-slots.h +++ b/deps/v8/src/objects/compressed-slots.h @@ -51,7 +51,7 @@ class CompressedObjectSlot : public SlotBase<CompressedObjectSlot, Tagged_t> { // TODO(saelo): it would be nice if we could have two load variants: one that // takes no arguments (which should normally be used), and one that takes an // Isolate* or an IsolateForSandbox to be compatible with the - // IndirectPointerSlot. Then, all slots that contain HeapObject references + // TrustedPointerSlot. Then, all slots that contain HeapObject references // would have at least a `load(isolate)` variant, and so could that could be // used in cases where only the slots content matters. inline Tagged<Object> load() const; diff --git a/deps/v8/src/objects/contexts.cc b/deps/v8/src/objects/contexts.cc index 69e0506382f9..6927ae99e8eb 100644 --- a/deps/v8/src/objects/contexts.cc +++ b/deps/v8/src/objects/contexts.cc @@ -107,10 +107,9 @@ Handle<ScriptContextTable> ScriptContextTable::Add( #define CHECK_FOLLOWS2(v1, v2) static_assert((v1 + 1) == (v2)) -int Context::FunctionMapIndex(LanguageMode language_mode, FunctionKind kind, - bool has_shared_name) { +int Context::FunctionMapIndex(FunctionKind kind, bool has_shared_name) { if (IsClassConstructor(kind)) { - // Like the strict function map, but with no 'name' accessor. 'name' + // Like the function map, but with no 'name' accessor. 'name' // needs to be the last property and it is added during instantiation, // in case a static property with the same name exists" return CLASS_FUNCTION_MAP_INDEX; @@ -132,20 +131,16 @@ int Context::FunctionMapIndex(LanguageMode language_mode, FunctionKind kind, base = ASYNC_FUNCTION_MAP_INDEX; - } else if (IsStrictFunctionWithoutPrototype(kind)) { - CHECK_FOLLOWS2(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, + } else if (IsFunctionWithoutPrototype(kind)) { + CHECK_FOLLOWS2(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, METHOD_WITH_NAME_MAP_INDEX); - base = STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX; + base = FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX; } else { - CHECK_FOLLOWS2(SLOPPY_FUNCTION_MAP_INDEX, - SLOPPY_FUNCTION_WITH_NAME_MAP_INDEX); - CHECK_FOLLOWS2(STRICT_FUNCTION_MAP_INDEX, - STRICT_FUNCTION_WITH_NAME_MAP_INDEX); + CHECK_FOLLOWS2(FUNCTION_MAP_INDEX, FUNCTION_WITH_NAME_MAP_INDEX); - base = is_strict(language_mode) ? STRICT_FUNCTION_MAP_INDEX - : SLOPPY_FUNCTION_MAP_INDEX; + base = FUNCTION_MAP_INDEX; } int offset = static_cast<int>(!has_shared_name); DCHECK_EQ(0, offset & ~1); @@ -471,7 +466,8 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name, Handle<JSReceiver> extension(Cast<JSReceiver>(ext), isolate); LookupIterator it(isolate, extension, name, extension); Maybe<bool> found = JSReceiver::HasProperty(&it); - if (found.FromMaybe(false)) { + if (found.IsNothing()) return Handle<Object>(); + if (found.FromJust()) { *attributes = NONE; return extension; } @@ -485,6 +481,16 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name, Context::Lookup(wrapped_context, name, DONT_FOLLOW_CHAINS, index, attributes, init_flag, variable_mode); if (!result.is_null()) return result; + // The lookup in the wrapped context can throw, e.g. when the subject + // of a with statement is a proxy or a deferred module namespace. Stop + // walking the context chain instead of continuing with an exception + // pending. + if (isolate->has_exception()) { + if (v8_flags.trace_contexts) { + PrintF(" - name lookup causes exception. Aborting.\n"); + } + return Handle<Object>(); + } } } diff --git a/deps/v8/src/objects/contexts.h b/deps/v8/src/objects/contexts.h index 90a1efd85bd9..1859939e43f4 100644 --- a/deps/v8/src/objects/contexts.h +++ b/deps/v8/src/objects/contexts.h @@ -347,19 +347,12 @@ enum ContextLookupFlags { initial_array_prototype_validity_cell) \ /* All *_FUNCTION_MAP_INDEX definitions used by Context::FunctionMapIndex */ \ /* must remain together. */ \ - V(SLOPPY_FUNCTION_MAP_INDEX, Map, sloppy_function_map) \ - V(SLOPPY_FUNCTION_WITH_NAME_MAP_INDEX, Map, sloppy_function_with_name_map) \ - V(SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \ - sloppy_function_without_prototype_map) \ - V(SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \ - sloppy_function_with_readonly_prototype_map) \ - V(STRICT_FUNCTION_MAP_INDEX, Map, strict_function_map) \ - V(STRICT_FUNCTION_WITH_NAME_MAP_INDEX, Map, strict_function_with_name_map) \ - V(STRICT_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \ - strict_function_with_readonly_prototype_map) \ - V(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \ - strict_function_without_prototype_map) \ + V(FUNCTION_MAP_INDEX, Map, function_map) \ + V(FUNCTION_WITH_NAME_MAP_INDEX, Map, function_with_name_map) \ + V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, function_without_prototype_map) \ V(METHOD_WITH_NAME_MAP_INDEX, Map, method_with_name_map) \ + V(FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \ + function_with_readonly_prototype_map) \ V(ASYNC_FUNCTION_MAP_INDEX, Map, async_function_map) \ V(ASYNC_FUNCTION_WITH_NAME_MAP_INDEX, Map, async_function_with_name_map) \ V(GENERATOR_FUNCTION_MAP_INDEX, Map, generator_function_map) \ @@ -585,7 +578,7 @@ V8_OBJECT class Context : public HeapObject { // A region of native context entries containing maps for functions created // by Builtin::kFastNewClosure. - static const int FIRST_FUNCTION_MAP_INDEX = SLOPPY_FUNCTION_MAP_INDEX; + static const int FIRST_FUNCTION_MAP_INDEX = FUNCTION_MAP_INDEX; static const int LAST_FUNCTION_MAP_INDEX = CLASS_FUNCTION_MAP_INDEX; static const int FIRST_FIXED_TYPED_ARRAY_FUN_INDEX = UINT8_ARRAY_FUN_INDEX; @@ -687,8 +680,7 @@ V8_OBJECT class Context : public HeapObject { VariableMode* variable_mode, bool* is_sloppy_function_name = nullptr); - V8_EXPORT_PRIVATE static int FunctionMapIndex(LanguageMode language_mode, - FunctionKind kind, + V8_EXPORT_PRIVATE static int FunctionMapIndex(FunctionKind kind, bool has_shared_name); static int ArrayMapIndex(ElementsKind elements_kind) { @@ -742,7 +734,8 @@ V8_OBJECT class Context : public HeapObject { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); public: - TaggedMember<Smi> length_; + V8_TQ_CONST TaggedMember<Smi> length_; + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, elements); } V8_OBJECT_END; @@ -940,9 +933,10 @@ V8_OBJECT class ScriptContextTable (TAGGED_SIZE_8_BYTES ? kTaggedSize : kApiInt32Size); public: - uint32_t capacity_; + V8_TQ_CONST uint32_t capacity_; uint32_t length_; TaggedMember<NameToIndexHashTable> names_to_context_index_; + V8_TQ_TAIL_LENGTH(capacity); FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); } V8_OBJECT_END; @@ -996,7 +990,7 @@ V8_OBJECT class ContextCell : public HeapObject { TaggedMember<JSAny> tagged_value_; TaggedMember<DependentCode> dependent_code_; - std::atomic<State> state_; + std::atomic<State> state_ V8_TQ_TYPE(int32); #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TAGGED_SIZE_8_BYTES diff --git a/deps/v8/src/objects/contexts.tq b/deps/v8/src/objects/contexts.tq index 2fec4305baf8..816c42e2fadc 100644 --- a/deps/v8/src/objects/contexts.tq +++ b/deps/v8/src/objects/contexts.tq @@ -22,8 +22,7 @@ extern class ScriptContextTable extends HeapObject { @cppObjectLayoutDefinition extern class ContextCell extends HeapObject { - // TODO(victorgomes): Change the type of tagged_value to JSAny. - tagged_value: Object; + tagged_value: JSAny; dependent_code: DependentCode; state: int32; @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; @@ -205,7 +204,7 @@ extern enum ContextSlot extends intptr constexpr 'Context::Field' { PROMISE_FUNCTION_INDEX: Slot<NativeContext, JSFunction>, PROMISE_THEN_INDEX: Slot<NativeContext, JSFunction>, PROMISE_PROTOTYPE_INDEX: Slot<NativeContext, JSObject>, - STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX: Slot<NativeContext, Map>, + FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX: Slot<NativeContext, Map>, PROMISE_HOOK_INIT_FUNCTION_INDEX: Slot<NativeContext, Undefined|Callable>, PROMISE_HOOK_BEFORE_FUNCTION_INDEX: Slot<NativeContext, Undefined|Callable>, diff --git a/deps/v8/src/objects/data-handler.h b/deps/v8/src/objects/data-handler.h index 647b65367248..b094b8bac414 100644 --- a/deps/v8/src/objects/data-handler.h +++ b/deps/v8/src/objects/data-handler.h @@ -57,6 +57,12 @@ V8_OBJECT class DataHandler : public Struct { inline void set_data5(Tagged<MaybeObject> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + // Returns true if the IC handlers {a} and {b} are identical or known to + // behave the same way. Fast proxy handlers are freshly allocated on every IC + // miss and are therefore compared by content. + static bool AreEquivalent(const MaybeObjectDirectHandle& a, + const MaybeObjectDirectHandle& b); + DECL_VERIFIER(DataHandler) DECL_PRINTER(DataHandler) @@ -65,6 +71,7 @@ V8_OBJECT class DataHandler : public Struct { public: TaggedMember<UnionOf<Smi, Code>> smi_handler_; TaggedMember<UnionOf<Smi, Cell>> validity_cell_; + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, data); private: diff --git a/deps/v8/src/objects/debug-objects-inl.h b/deps/v8/src/objects/debug-objects-inl.h index 1137d91e06f7..2cbe90394a8c 100644 --- a/deps/v8/src/objects/debug-objects-inl.h +++ b/deps/v8/src/objects/debug-objects-inl.h @@ -12,10 +12,12 @@ #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/bytecode-array-inl.h" #include "src/objects/code-inl.h" +#include "src/objects/heap-object-set-map-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/shared-function-info.h" #include "src/objects/string.h" -#include "src/objects/trusted-pointer-inl.h" +#include "src/objects/struct-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" #include "src/torque/runtime-macro-shims.h" #include "src/torque/runtime-support.h" @@ -25,12 +27,15 @@ namespace v8 { namespace internal { +BreakPointInfo::BreakPointInfo(const AllocationWitness& witness, + int source_position) + : Struct(witness.roots().break_point_info_map()), + source_position_(Smi::FromInt(source_position)), + break_points_(witness.roots().undefined_value()) {} + int BreakPointInfo::source_position() const { return source_position_.load().value(); } -void BreakPointInfo::set_source_position(int value) { - source_position_.store(this, Smi::FromInt(value)); -} Tagged<UnionOf<FixedArray, BreakPoint, Undefined>> BreakPointInfo::break_points() const { @@ -42,13 +47,15 @@ void BreakPointInfo::set_break_points( break_points_.store(this, value, mode); } +BreakPoint::BreakPoint(const AllocationWitness& witness, int id, + Tagged<String> condition) + : Struct(witness.roots().break_point_map()), + id_(Smi::FromInt(id)), + condition_(witness, condition) {} + int BreakPoint::id() const { return id_.load().value(); } -void BreakPoint::set_id(int value) { id_.store(this, Smi::FromInt(value)); } Tagged<String> BreakPoint::condition() const { return condition_.load(); } -void BreakPoint::set_condition(Tagged<String> value, WriteBarrierMode mode) { - condition_.store(this, value, mode); -} Tagged<SharedFunctionInfo> DebugInfo::shared() const { return shared_.load(); } void DebugInfo::set_shared(Tagged<SharedFunctionInfo> value, @@ -157,6 +164,18 @@ Tagged<BytecodeArray> DebugInfo::DebugBytecodeArray(Isolate* isolate) { return result; } +StackFrameInfo::StackFrameInfo( + const AllocationWitness& witness, + Tagged<UnionOf<SharedFunctionInfo, Script>> shared_or_script, + int bytecode_offset_or_source_position, Tagged<String> function_name, + bool is_constructor) + : Struct(witness.roots().stack_frame_info_map()), + shared_or_script_(witness, shared_or_script), + function_name_(witness, function_name), + flags_(Smi::FromInt(IsConstructorBit::encode(is_constructor))), + bytecode_offset_or_source_position_( + Smi::FromInt(bytecode_offset_or_source_position)) {} + Tagged<UnionOf<SharedFunctionInfo, Script>> StackFrameInfo::shared_or_script() const { return shared_or_script_.load(); @@ -169,15 +188,8 @@ void StackFrameInfo::set_shared_or_script( Tagged<String> StackFrameInfo::function_name() const { return function_name_.load(); } -void StackFrameInfo::set_function_name(Tagged<String> value, - WriteBarrierMode mode) { - function_name_.store(this, value, mode); -} int StackFrameInfo::flags() const { return flags_.load().value(); } -void StackFrameInfo::set_flags(int value) { - flags_.store(this, Smi::FromInt(value)); -} Tagged<Script> StackFrameInfo::script() const { Tagged<HeapObject> object = shared_or_script(); @@ -193,17 +205,18 @@ int StackFrameInfo::bytecode_offset_or_source_position() const { void StackFrameInfo::set_bytecode_offset_or_source_position(int value) { bytecode_offset_or_source_position_.store(this, Smi::FromInt(value)); } -BIT_FIELD_ACCESSORS(StackFrameInfo, flags, is_constructor, - StackFrameInfo::IsConstructorBit) +BOOL_GETTER(StackFrameInfo, flags, is_constructor, + StackFrameInfo::IsConstructorBit::kShift) + +StackTraceInfo::StackTraceInfo(const AllocationWitness& witness, int id, + Tagged<FixedArray> frames) + : Struct(witness.roots().stack_trace_info_map()), + id_(Smi::FromInt(id)), + frames_(witness, frames) {} int StackTraceInfo::id() const { return id_.load().value(); } -void StackTraceInfo::set_id(int value) { id_.store(this, Smi::FromInt(value)); } Tagged<FixedArray> StackTraceInfo::frames() const { return frames_.load(); } -void StackTraceInfo::set_frames(Tagged<FixedArray> value, - WriteBarrierMode mode) { - frames_.store(this, value, mode); -} inline int StackTraceInfo::length() const { // TODO(375937549): Convert to uint32_t. @@ -214,6 +227,16 @@ inline Tagged<StackFrameInfo> StackTraceInfo::get(int index) const { return Cast<StackFrameInfo>(frames()->get(index)); } +ErrorStackData::ErrorStackData( + const AllocationWitness& witness, + Tagged<UnionOf<FixedArray, JSAny>> + raw_data_for_call_site_infos_or_formatted_stack, + Tagged<StackTraceInfo> stack_trace) + : Struct(witness.roots().error_stack_data_map()), + raw_data_for_call_site_infos_or_formatted_stack_( + witness, raw_data_for_call_site_infos_or_formatted_stack), + stack_trace_(witness, stack_trace) {} + bool ErrorStackData::HasFormattedStack() const { return !IsFixedArray(raw_data_for_call_site_infos_or_formatted_stack()); } @@ -256,51 +279,35 @@ void ErrorStackData::set_raw_data_for_call_site_infos_or_formatted_stack( Tagged<StackTraceInfo> ErrorStackData::stack_trace() const { return stack_trace_.load(); } -void ErrorStackData::set_stack_trace(Tagged<StackTraceInfo> value, - WriteBarrierMode mode) { - stack_trace_.store(this, value, mode); -} + +DebugScriptScopeInfo::DebugScriptScopeInfo(const AllocationWitness& witness, + Tagged<ByteArray> numeric_data, + Tagged<FixedArray> string_table) + : Struct(witness.roots().debug_script_scope_info_map()), + numeric_data_(witness, numeric_data), + string_table_(witness, string_table) {} Tagged<ByteArray> DebugScriptScopeInfo::numeric_data() const { return numeric_data_.load(); } -void DebugScriptScopeInfo::set_numeric_data(Tagged<ByteArray> value, - WriteBarrierMode mode) { - numeric_data_.store(this, value, mode); -} Tagged<FixedArray> DebugScriptScopeInfo::string_table() const { return string_table_.load(); } -void DebugScriptScopeInfo::set_string_table(Tagged<FixedArray> value, - WriteBarrierMode mode) { - string_table_.store(this, value, mode); -} // CoverageInfo. int32_t CoverageInfo::slot_count() const { return slot_count_; } -void CoverageInfo::set_slot_count(int32_t value) { slot_count_ = value; } int32_t CoverageInfo::slots_start_source_position(int i) const { DCHECK_GE(i, 0); DCHECK_LT(i, slot_count()); return slots()[i].start_source_position; } -void CoverageInfo::set_slots_start_source_position(int i, int32_t value) { - DCHECK_GE(i, 0); - DCHECK_LT(i, slot_count()); - slots()[i].start_source_position = value; -} int32_t CoverageInfo::slots_end_source_position(int i) const { DCHECK_GE(i, 0); DCHECK_LT(i, slot_count()); return slots()[i].end_source_position; } -void CoverageInfo::set_slots_end_source_position(int i, int32_t value) { - DCHECK_GE(i, 0); - DCHECK_LT(i, slot_count()); - slots()[i].end_source_position = value; -} int32_t CoverageInfo::slots_block_count(int i) const { DCHECK_GE(i, 0); DCHECK_LT(i, slot_count()); @@ -316,11 +323,6 @@ int32_t CoverageInfo::slots_padding(int i) const { DCHECK_LT(i, slot_count()); return slots()[i].padding; } -void CoverageInfo::set_slots_padding(int i, int32_t value) { - DCHECK_GE(i, 0); - DCHECK_LT(i, slot_count()); - slots()[i].padding = value; -} int CoverageInfo::AllocatedSize() const { return SizeFor(slot_count()); } } // namespace internal diff --git a/deps/v8/src/objects/debug-objects.cc b/deps/v8/src/objects/debug-objects.cc index dce8a7b7e713..d5b1ad37d4e4 100644 --- a/deps/v8/src/objects/debug-objects.cc +++ b/deps/v8/src/objects/debug-objects.cc @@ -4,11 +4,13 @@ #include "src/objects/debug-objects.h" +#include "src/ast/ast-source-ranges.h" #include "src/base/platform/mutex.h" #include "src/debug/debug-evaluate.h" #include "src/handles/handles-inl.h" #include "src/objects/call-site-info-inl.h" #include "src/objects/debug-objects-inl.h" +#include "src/objects/heap-object-set-map-inl.h" #include "src/utils/ostreams.h" namespace v8 { @@ -383,11 +385,14 @@ uint32_t BreakPointInfo::GetBreakPointCount(Isolate* isolate) { return Cast<FixedArray>(break_points())->ulength().value(); } -void CoverageInfo::InitializeSlot(int slot_index, int from_pos, int to_pos) { - set_slots_start_source_position(slot_index, from_pos); - set_slots_end_source_position(slot_index, to_pos); - ResetBlockCount(slot_index); - set_slots_padding(slot_index, 0); +CoverageInfo::CoverageInfo(const AllocationWitness& witness, + const ZoneVector<SourceRange>& slots) + : HeapObject(witness.roots().coverage_info_map()), + slot_count_(static_cast<int32_t>(slots.size())) { + for (int32_t i = 0; i < slot_count_; i++) { + SourceRange range = slots[i]; + new (&this->slots()[i]) CoverageInfoSlot{range.start, range.end}; + } } void CoverageInfo::ResetBlockCount(int slot_index) { diff --git a/deps/v8/src/objects/debug-objects.h b/deps/v8/src/objects/debug-objects.h index ce560b5d5311..7dfd76fe8d1b 100644 --- a/deps/v8/src/objects/debug-objects.h +++ b/deps/v8/src/objects/debug-objects.h @@ -11,7 +11,7 @@ #include "src/objects/fixed-array.h" #include "src/objects/objects.h" #include "src/objects/struct.h" -#include "src/objects/trusted-pointer.h" +#include "src/sandbox/trusted-pointer.h" #if V8_ENABLE_WEBASSEMBLY #include "src/wasm/wasm-limits.h" #endif // V8_ENABLE_WEBASSEMBLY @@ -29,7 +29,10 @@ class StackFrameInfo; class StackTraceInfo; class DebugScriptScopeInfo; class BytecodeArray; +struct SourceRange; class StructBodyDescriptor; +template <typename T> +class ZoneVector; // The DebugInfo class holds additional information for a function being // debugged. @@ -200,12 +203,14 @@ V8_OBJECT class DebugInfo : public ExposedTrustedObject { public: TaggedMember<SharedFunctionInfo> shared_; - TaggedMember<Smi> debugger_hints_; + TaggedMember<Smi> debugger_hints_ V8_TQ_TYPE(SmiTagged<DebuggerHints>); TaggedMember<FixedArray> break_points_; - TaggedMember<Smi> flags_; + V8_TQ_RELAXED TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<DebugInfoFlags>); TaggedMember<UnionOf<CoverageInfo, Undefined>> coverage_info_; - ProtectedTaggedMember<UnionOf<BytecodeArray, Zero>> original_bytecode_array_; - ProtectedTaggedMember<UnionOf<BytecodeArray, Zero>> debug_bytecode_array_; + ProtectedTaggedMember<UnionOf<BytecodeArray, Zero>> original_bytecode_array_ + V8_TQ_TYPE(ProtectedPointer<BytecodeArray>); + ProtectedTaggedMember<UnionOf<BytecodeArray, Zero>> debug_bytecode_array_ + V8_TQ_TYPE(ProtectedPointer<BytecodeArray>); } V8_OBJECT_END; // The BreakPointInfo class holds information for break points set in a @@ -213,9 +218,10 @@ V8_OBJECT class DebugInfo : public ExposedTrustedObject { // position with one or more break points. V8_OBJECT class BreakPointInfo : public Struct { public: + inline BreakPointInfo(const AllocationWitness& witness, int source_position); + // Accessors inline int source_position() const; - inline void set_source_position(int value); inline Tagged<UnionOf<FixedArray, BreakPoint, Undefined>> break_points() const; @@ -246,16 +252,16 @@ V8_OBJECT class BreakPointInfo : public Struct { DECL_PRINTER(BreakPointInfo) DECL_VERIFIER(BreakPointInfo) - TaggedMember<Smi> source_position_; + const TaggedMember<Smi> source_position_; TaggedMember<UnionOf<FixedArray, BreakPoint, Undefined>> break_points_; } V8_OBJECT_END; // Layout of a single slot within CoverageInfo. struct CoverageInfoSlot { - int32_t start_source_position; - int32_t end_source_position; - int32_t block_count; - int32_t padding; + const int32_t start_source_position; + const int32_t end_source_position; + int32_t block_count = 0; + const int32_t padding = 0; static const int kSize; }; @@ -266,19 +272,17 @@ inline constexpr int CoverageInfoSlot::kSize = sizeof(CoverageInfoSlot); // Holds information related to block code coverage. V8_OBJECT class CoverageInfo : public HeapObject { public: + CoverageInfo(const AllocationWitness& witness, + const ZoneVector<SourceRange>& slots); + inline int32_t slot_count() const; - inline void set_slot_count(int32_t value); inline int32_t slots_start_source_position(int i) const; - inline void set_slots_start_source_position(int i, int32_t value); inline int32_t slots_end_source_position(int i) const; - inline void set_slots_end_source_position(int i, int32_t value); inline int32_t slots_block_count(int i) const; inline void set_slots_block_count(int i, int32_t value); inline int32_t slots_padding(int i) const; - inline void set_slots_padding(int i, int32_t value); - void InitializeSlot(int slot_index, int start_pos, int end_pos); void ResetBlockCount(int slot_index); // Computes the size for a CoverageInfo instance of a given length. @@ -296,7 +300,8 @@ V8_OBJECT class CoverageInfo : public HeapObject { // Description of layout within each slot. using Slot = CoverageInfoSlot; - int32_t slot_count_; + V8_TQ_CONST const int32_t slot_count_; + V8_TQ_TAIL_LENGTH(slot_count); FLEXIBLE_ARRAY_MEMBER(CoverageInfoSlot, slots); } V8_OBJECT_END; @@ -309,25 +314,30 @@ constexpr int CoverageInfo::SizeFor(int slot_count) { // Holds breakpoint related information. This object is used by inspector. V8_OBJECT class BreakPoint : public Struct { public: + inline BreakPoint(const AllocationWitness& witness, int id, + Tagged<String> condition); + // Accessors inline int id() const; - inline void set_id(int value); - inline Tagged<String> condition() const; - inline void set_condition(Tagged<String> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); using BodyDescriptor = StructBodyDescriptor; DECL_PRINTER(BreakPoint) DECL_VERIFIER(BreakPoint) - TaggedMember<Smi> id_; - TaggedMember<String> condition_; + const TaggedMember<Smi> id_; + const TaggedMember<String> condition_; } V8_OBJECT_END; V8_OBJECT class StackFrameInfo : public Struct { public: + inline StackFrameInfo( + const AllocationWitness& witness, + Tagged<UnionOf<SharedFunctionInfo, Script>> shared_or_script, + int bytecode_offset_or_source_position, Tagged<String> function_name, + bool is_constructor); + static int GetSourcePosition(DirectHandle<StackFrameInfo> info); // The script for the stack frame. @@ -339,7 +349,6 @@ V8_OBJECT class StackFrameInfo : public Struct { // Indicates that the frame corresponds to a 'new' invocation. inline bool is_constructor() const; - inline void set_is_constructor(bool value); inline Tagged<UnionOf<SharedFunctionInfo, Script>> shared_or_script() const; inline void set_shared_or_script( @@ -347,11 +356,7 @@ V8_OBJECT class StackFrameInfo : public Struct { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<String> function_name() const; - inline void set_function_name(Tagged<String> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline int flags() const; - inline void set_flags(int value); // Bit positions in |flags|. using IsConstructorBit = base::BitField<bool, 0, 1, uint32_t>; @@ -362,8 +367,8 @@ V8_OBJECT class StackFrameInfo : public Struct { DECL_PRINTER(StackFrameInfo) TaggedMember<UnionOf<SharedFunctionInfo, Script>> shared_or_script_; - TaggedMember<String> function_name_; - TaggedMember<Smi> flags_; + const TaggedMember<String> function_name_; + const TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<StackFrameInfoFlags>); TaggedMember<Smi> bytecode_offset_or_source_position_; #if V8_ENABLE_WEBASSEMBLY // Wasm wire byte offsets are 0-indexed instruction positions within a module @@ -376,13 +381,12 @@ V8_OBJECT class StackFrameInfo : public Struct { V8_OBJECT class StackTraceInfo : public Struct { public: + inline StackTraceInfo(const AllocationWitness& witness, int id, + Tagged<FixedArray> frames); + // Accessors inline int id() const; - inline void set_id(int value); - inline Tagged<FixedArray> frames() const; - inline void set_frames(Tagged<FixedArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // Access to the stack frames. int length() const; @@ -394,12 +398,17 @@ V8_OBJECT class StackTraceInfo : public Struct { using BodyDescriptor = StructBodyDescriptor; - TaggedMember<Smi> id_; - TaggedMember<FixedArray> frames_; + const TaggedMember<Smi> id_; + const TaggedMember<FixedArray> frames_; } V8_OBJECT_END; V8_OBJECT class ErrorStackData : public Struct { public: + inline ErrorStackData(const AllocationWitness& witness, + Tagged<UnionOf<FixedArray, JSAny>> + raw_data_for_call_site_infos_or_formatted_stack, + Tagged<StackTraceInfo> stack_trace); + inline bool HasFormattedStack() const; inline Tagged<JSAny> formatted_stack() const; inline void set_formatted_stack(Tagged<JSAny> value, @@ -417,8 +426,6 @@ V8_OBJECT class ErrorStackData : public Struct { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<StackTraceInfo> stack_trace() const; - inline void set_stack_trace(Tagged<StackTraceInfo> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_VERIFIER(ErrorStackData) DECL_PRINTER(ErrorStackData) @@ -427,7 +434,7 @@ V8_OBJECT class ErrorStackData : public Struct { TaggedMember<UnionOf<FixedArray, JSAny>> raw_data_for_call_site_infos_or_formatted_stack_; - TaggedMember<StackTraceInfo> stack_trace_; + const TaggedMember<StackTraceInfo> stack_trace_; } V8_OBJECT_END; // DebugScriptScopeInfo holds the serialized scope tree of a Script for the @@ -438,21 +445,20 @@ V8_OBJECT class ErrorStackData : public Struct { // src/debug/debug-scope-info.cc. V8_OBJECT class DebugScriptScopeInfo : public Struct { public: - inline Tagged<ByteArray> numeric_data() const; - inline void set_numeric_data(Tagged<ByteArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline DebugScriptScopeInfo(const AllocationWitness& witness, + Tagged<ByteArray> numeric_data, + Tagged<FixedArray> string_table); + inline Tagged<ByteArray> numeric_data() const; inline Tagged<FixedArray> string_table() const; - inline void set_string_table(Tagged<FixedArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_VERIFIER(DebugScriptScopeInfo) DECL_PRINTER(DebugScriptScopeInfo) using BodyDescriptor = StructBodyDescriptor; - TaggedMember<ByteArray> numeric_data_; - TaggedMember<FixedArray> string_table_; + const TaggedMember<ByteArray> numeric_data_; + const TaggedMember<FixedArray> string_table_; } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/deoptimization-data.cc b/deps/v8/src/objects/deoptimization-data.cc index 7a24f4c57a6e..a5baa27a436f 100644 --- a/deps/v8/src/objects/deoptimization-data.cc +++ b/deps/v8/src/objects/deoptimization-data.cc @@ -17,20 +17,19 @@ namespace v8 { namespace internal { -DirectHandle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const { +template <typename IsolateT> +DirectHandle<Object> DeoptimizationLiteral::Reify(IsolateT* isolate) const { Validate(); switch (kind_) { case DeoptimizationLiteralKind::kObject: return object_; case DeoptimizationLiteralKind::kNumber: - return isolate->factory()->NewNumber(number_); + return isolate->factory()->template NewNumber<AllocationType::kOld>( + number_); case DeoptimizationLiteralKind::kSignedBigInt64: - return BigInt::FromInt64(isolate, int64_); + return BigInt::FromInt64(isolate, int64_, AllocationType::kOld); case DeoptimizationLiteralKind::kUnsignedBigInt64: - return BigInt::FromUint64(isolate, uint64_); - case DeoptimizationLiteralKind::kHoleNaN: - // Hole NaNs that made it to here represent the undefined value. - return isolate->factory()->undefined_value(); + return BigInt::FromUint64(isolate, uint64_, AllocationType::kOld); case DeoptimizationLiteralKind::kWasmI31Ref: case DeoptimizationLiteralKind::kWasmInt32: case DeoptimizationLiteralKind::kWasmFloat32: @@ -40,6 +39,10 @@ DirectHandle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const { } UNREACHABLE(); } +template DirectHandle<Object> DeoptimizationLiteral::Reify( + Isolate* isolate) const; +template DirectHandle<Object> DeoptimizationLiteral::Reify( + LocalIsolate* isolate) const; size_t DeoptimizationLiteral::SerializationSize() const { static constexpr size_t kSizeOfKind = 1; @@ -47,7 +50,6 @@ size_t DeoptimizationLiteral::SerializationSize() const { case DeoptimizationLiteralKind::kInvalid: case DeoptimizationLiteralKind::kObject: case DeoptimizationLiteralKind::kNumber: - case DeoptimizationLiteralKind::kHoleNaN: break; case DeoptimizationLiteralKind::kSignedBigInt64: return kSizeOfKind + sizeof(int64_); @@ -82,7 +84,6 @@ size_t DeoptimizationLiteral::Write(base::Vector<uint8_t> buffer) const { case DeoptimizationLiteralKind::kInvalid: case DeoptimizationLiteralKind::kObject: case DeoptimizationLiteralKind::kNumber: - case DeoptimizationLiteralKind::kHoleNaN: break; case DeoptimizationLiteralKind::kSignedBigInt64: return WriteValue(int64_); @@ -131,7 +132,6 @@ size_t DeoptimizationLiteral::Read(base::Vector<const uint8_t> buffer, case DeoptimizationLiteralKind::kInvalid: case DeoptimizationLiteralKind::kObject: case DeoptimizationLiteralKind::kNumber: - case DeoptimizationLiteralKind::kHoleNaN: break; case DeoptimizationLiteralKind::kSignedBigInt64: return Read.operator()<int64_t>(buffer, out); diff --git a/deps/v8/src/objects/deoptimization-data.h b/deps/v8/src/objects/deoptimization-data.h index bd9560282440..fccbe101ef64 100644 --- a/deps/v8/src/objects/deoptimization-data.h +++ b/deps/v8/src/objects/deoptimization-data.h @@ -46,7 +46,6 @@ enum class DeoptimizationLiteralKind : uint8_t { kNumber, kSignedBigInt64, kUnsignedBigInt64, - kHoleNaN, kInvalid, // These kinds are used by Wasm only (as unoptimized JS doesn't have these @@ -86,12 +85,6 @@ class DeoptimizationLiteral { explicit DeoptimizationLiteral(Tagged<Smi> smi) : kind_(DeoptimizationLiteralKind::kWasmI31Ref), int32_(smi.value()) {} - static DeoptimizationLiteral HoleNaN() { - DeoptimizationLiteral literal; - literal.kind_ = DeoptimizationLiteralKind::kHoleNaN; - return literal; - } - IndirectHandle<Object> object() const { return object_; } bool operator==(const DeoptimizationLiteral& other) const { @@ -111,8 +104,6 @@ class DeoptimizationLiteral { return int64_ == other.int64_; case DeoptimizationLiteralKind::kUnsignedBigInt64: return uint64_ == other.uint64_; - case DeoptimizationLiteralKind::kHoleNaN: - return other.kind() == DeoptimizationLiteralKind::kHoleNaN; case DeoptimizationLiteralKind::kInvalid: return true; case DeoptimizationLiteralKind::kWasmFloat32: @@ -123,7 +114,8 @@ class DeoptimizationLiteral { UNREACHABLE(); } - DirectHandle<Object> Reify(Isolate* isolate) const; + template <typename IsolateT> + DirectHandle<Object> Reify(IsolateT* isolate) const; #if V8_ENABLE_WEBASSEMBLY Float64 GetFloat64() const { diff --git a/deps/v8/src/objects/descriptor-array-inl.h b/deps/v8/src/objects/descriptor-array-inl.h index df3cc4ca9868..5a0b1467253b 100644 --- a/deps/v8/src/objects/descriptor-array-inl.h +++ b/deps/v8/src/objects/descriptor-array-inl.h @@ -33,6 +33,12 @@ namespace v8 { namespace internal { +EnumCache::EnumCache(const AllocationWitness& witness, Tagged<FixedArray> keys, + Tagged<FixedArray> indices) + : Struct(witness.roots().enum_cache_map()), + keys_(witness, keys), + indices_(witness, indices) {} + Tagged<FixedArray> EnumCache::keys() const { return keys_.load(); } void EnumCache::set_keys(Tagged<FixedArray> value, WriteBarrierMode mode) { keys_.store(this, value, mode); @@ -64,11 +70,11 @@ void DescriptorArray::set_number_of_descriptors(int16_t value) { std::memory_order_relaxed); } -uint32_t DescriptorArray::flags(RelaxedLoadTag) const { +DescriptorArray::Flags DescriptorArray::flags(RelaxedLoadTag) const { return flags_.load(std::memory_order_relaxed); } -void DescriptorArray::set_flags(uint32_t value, RelaxedStoreTag) { +void DescriptorArray::set_flags(Flags value, RelaxedStoreTag) { flags_.store(value, std::memory_order_relaxed); } @@ -90,21 +96,18 @@ void DescriptorArray::set_enum_cache(Tagged<EnumCache> value, } DescriptorArray::FastIterableState DescriptorArray::fast_iterable() const { - return FastIterableBits::decode(flags(kRelaxedLoad)); + return flags(kRelaxedLoad).fast_iterable(); } void DescriptorArray::set_fast_iterable(FastIterableState value) { - uint32_t f = flags(kRelaxedLoad); - f = FastIterableBits::update(f, value); - set_flags(f, kRelaxedStore); + set_flags(flags(kRelaxedLoad).with_fast_iterable(value), kRelaxedStore); } void DescriptorArray::set_fast_iterable_if(FastIterableState new_value, FastIterableState if_value) { - uint32_t f = flags(kRelaxedLoad); - if (FastIterableBits::decode(f) == if_value) { - f = FastIterableBits::update(f, new_value); - set_flags(f, kRelaxedStore); + Flags f = flags(kRelaxedLoad); + if (f.fast_iterable() == if_value) { + set_flags(f.with_fast_iterable(new_value), kRelaxedStore); } } diff --git a/deps/v8/src/objects/descriptor-array.h b/deps/v8/src/objects/descriptor-array.h index 8e020a8b4671..0d7ed7c2567d 100644 --- a/deps/v8/src/objects/descriptor-array.h +++ b/deps/v8/src/objects/descriptor-array.h @@ -9,6 +9,7 @@ #include "src/base/bit-field.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/fixed-array.h" #include "src/objects/internal-index.h" #include "src/objects/objects.h" @@ -38,6 +39,9 @@ class StructBodyDescriptor; // An EnumCache is a pair used to hold keys and indices caches. V8_OBJECT class EnumCache : public Struct { public: + inline EnumCache(const AllocationWitness& witness, Tagged<FixedArray> keys, + Tagged<FixedArray> indices); + inline Tagged<FixedArray> keys() const; inline void set_keys(Tagged<FixedArray> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); @@ -95,8 +99,6 @@ V8_OBJECT class DescriptorArray : public HeapObject { inline void set_number_of_all_descriptors(int16_t value, ReleaseStoreTag); inline int16_t number_of_descriptors() const; inline void set_number_of_descriptors(int16_t value); - inline uint32_t flags(RelaxedLoadTag) const; - inline void set_flags(uint32_t value, RelaxedStoreTag); inline int16_t number_of_slack_descriptors() const; inline int number_of_entries() const; @@ -113,8 +115,16 @@ V8_OBJECT class DescriptorArray : public HeapObject { kUnknown = 0b11 }; - using FastIterableBits = - base::BitField<DescriptorArray::FastIterableState, 0, 2, uint32_t>; + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using FastIterableBits = First<FastIterableState, 2>; + + BIT_FIELD_GROUP_ACCESSORS(fast_iterable, FastIterableBits) + }; + + inline Flags flags(RelaxedLoadTag) const; + inline void set_flags(Flags value, RelaxedStoreTag); inline FastIterableState fast_iterable() const; inline void set_fast_iterable(FastIterableState value); @@ -312,11 +322,12 @@ V8_OBJECT class DescriptorArray : public HeapObject { // Declared atomic so that concurrent readers (e.g. from the marker) see a // consistent value during trimming in mark-compact. - std::atomic<uint16_t> number_of_all_descriptors_; + V8_TQ_CONST std::atomic<uint16_t> number_of_all_descriptors_; std::atomic<uint16_t> number_of_descriptors_; - std::atomic<uint32_t> flags_; + std::atomic<Flags> flags_; TaggedMember<EnumCache> enum_cache_; - FLEXIBLE_ARRAY_MEMBER(Entry, entries); + V8_TQ_TAIL_LENGTH(number_of_all_descriptors); + FLEXIBLE_ARRAY_MEMBER(Entry, entries, V8_TQ_TYPE(DescriptorEntry)); } V8_OBJECT_END; static_assert(sizeof(DescriptorArray::Entry) == diff --git a/deps/v8/src/objects/descriptor-array.tq b/deps/v8/src/objects/descriptor-array.tq index 2655b30274cc..5b0253507e8c 100644 --- a/deps/v8/src/objects/descriptor-array.tq +++ b/deps/v8/src/objects/descriptor-array.tq @@ -16,12 +16,12 @@ struct DescriptorEntry { NumberDictionary; } -type FastIterableState extends uint8 +type DescriptorArrayFastIterableState extends uint8 constexpr 'DescriptorArray::FastIterableState'; -@cppScope('DescriptorArray') +@cppScope('DescriptorArray::Flags') bitfield struct DescriptorArrayFlags extends uint32 { - fast_iterable: FastIterableState: 2 bit; + fast_iterable: DescriptorArrayFastIterableState: 2 bit; } @cppObjectLayoutDefinition @@ -30,5 +30,5 @@ extern class DescriptorArray extends HeapObject { number_of_descriptors: uint16; flags: DescriptorArrayFlags; enum_cache: EnumCache; - descriptors[number_of_all_descriptors]: DescriptorEntry; + entries[number_of_all_descriptors]: DescriptorEntry; } diff --git a/deps/v8/src/objects/elements-kind.h b/deps/v8/src/objects/elements-kind.h index 99a7404dbe23..5d532e799e14 100644 --- a/deps/v8/src/objects/elements-kind.h +++ b/deps/v8/src/objects/elements-kind.h @@ -5,7 +5,8 @@ #ifndef V8_OBJECTS_ELEMENTS_KIND_H_ #define V8_OBJECTS_ELEMENTS_KIND_H_ -#include "src/base/bits.h" +#include <bit> + #include "src/base/bounds.h" #include "src/base/macros.h" #include "src/common/checks.h" @@ -192,7 +193,7 @@ constexpr size_t TypedArrayAndRabGsabTypedArrayElementsKindTableSize() { FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; size_t rab_gsab_count = LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND - FIRST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; - return base::bits::RoundUpToPowerOfTwo(ta_count + rab_gsab_count); + return std::bit_ceil(ta_count + rab_gsab_count); } const uint8_t* TypedArrayAndRabGsabTypedArrayElementsKindShifts(); diff --git a/deps/v8/src/objects/elements.cc b/deps/v8/src/objects/elements.cc index 410bd48dc1a6..d884b393931f 100644 --- a/deps/v8/src/objects/elements.cc +++ b/deps/v8/src/objects/elements.cc @@ -398,8 +398,7 @@ void CopyDoubleToDoubleElements(Tagged<FixedArrayBase> from_base, // access to double values in the arrays. This will no longed be necessary // once the allocations alignment issue is fixed. uint32_t words_per_double = (kDoubleSize / kTaggedSize); - CopyTagged(to_address, from_address, - static_cast<size_t>(words_per_double * copy_size)); + CopyTagged(to_address, from_address, words_per_double * copy_size); #else uint32_t words_per_double = (kDoubleSize / kSystemPointerSize); CopyWords(to_address, from_address, diff --git a/deps/v8/src/objects/embedder-data-array.h b/deps/v8/src/objects/embedder-data-array.h index 3164c34bddb3..d8032d296b86 100644 --- a/deps/v8/src/objects/embedder-data-array.h +++ b/deps/v8/src/objects/embedder-data-array.h @@ -52,6 +52,7 @@ V8_OBJECT class EmbedderDataArray : public HeapObject { // EmbedderDataSlots stored inline; each slot occupies // kEmbedderDataSlotSize bytes (1 or 2 Address words depending on // whether pointer compression is enabled). + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(Address, slots); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/feedback-cell-inl.h b/deps/v8/src/objects/feedback-cell-inl.h index c3032280c5fd..db33f1c66188 100644 --- a/deps/v8/src/objects/feedback-cell-inl.h +++ b/deps/v8/src/objects/feedback-cell-inl.h @@ -13,6 +13,7 @@ #include "src/execution/tiering-manager.h" #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/feedback-vector-inl.h" +#include "src/objects/heap-object-set-map-inl.h" #include "src/objects/object-predicates-inl.h" #include "src/objects/struct-inl.h" @@ -21,6 +22,15 @@ namespace v8::internal { +FeedbackCell::FeedbackCell(const AllocationWitness& witness, + Tagged<ReadOnly<Map>> map) + : Struct(map), value_(witness.roots().undefined_value()) {} + +FeedbackCell::FeedbackCell(const AllocationWitness& witness, + Tagged<ReadOnly<Map>> map, + Tagged<ClosureFeedbackCellArray> value) + : Struct(map), value_(witness, value) {} + Tagged<FeedbackCell::Value> FeedbackCell::value() const { return value_.load(); } @@ -51,11 +61,9 @@ JSDispatchHandle FeedbackCell::dispatch_handle() const { void FeedbackCell::set_dispatch_handle(JSDispatchHandle new_handle) { DCHECK_EQ(dispatch_handle(), kNullJSDispatchHandle); - dispatch_handle_.Relaxed_Store(this, new_handle); + dispatch_handle_.Release_Store(this, new_handle); } -void FeedbackCell::clear_padding() {} - void FeedbackCell::reset_feedback_vector( std::optional<std::function<void(Tagged<HeapObject> object, ObjectSlot slot, Tagged<HeapObject> target)>> @@ -80,8 +88,6 @@ void FeedbackCell::clear_interrupt_budget() { set_interrupt_budget(0); } -void FeedbackCell::clear_dispatch_handle() { dispatch_handle_.Relaxed_Clear(); } - FeedbackCell::ClosureCountTransition FeedbackCell::IncrementClosureCount( Isolate* isolate) { ReadOnlyRoots r(isolate); diff --git a/deps/v8/src/objects/feedback-cell.h b/deps/v8/src/objects/feedback-cell.h index cd872aeab088..d8f765a6161c 100644 --- a/deps/v8/src/objects/feedback-cell.h +++ b/deps/v8/src/objects/feedback-cell.h @@ -25,6 +25,12 @@ V8_OBJECT class FeedbackCell : public Struct { public: using Value = UnionOf<Undefined, FeedbackVector, ClosureFeedbackCellArray>; + inline FeedbackCell(const AllocationWitness& witness, + Tagged<ReadOnly<Map>> map); + inline FeedbackCell(const AllocationWitness& witness, + Tagged<ReadOnly<Map>> map, + Tagged<ClosureFeedbackCellArray> value); + // Accessors inline Tagged<Value> value() const; inline Tagged<Value> value(AcquireLoadTag) const; @@ -40,9 +46,7 @@ V8_OBJECT class FeedbackCell : public Struct { inline void set_dispatch_handle(JSDispatchHandle new_handle); inline void clear_interrupt_budget(); - inline void clear_dispatch_handle(); - inline void clear_padding(); inline void reset_feedback_vector( std::optional< std::function<void(Tagged<HeapObject> object, ObjectSlot slot, @@ -63,7 +67,7 @@ V8_OBJECT class FeedbackCell : public Struct { public: TaggedMember<Value> value_; JSDispatchHandleMember dispatch_handle_; - int32_t interrupt_budget_; + int32_t interrupt_budget_ = 0; } V8_OBJECT_END; static_assert(sizeof(FeedbackCell) == diff --git a/deps/v8/src/objects/feedback-vector-inl.h b/deps/v8/src/objects/feedback-vector-inl.h index 039d919757d6..73370d6964d6 100644 --- a/deps/v8/src/objects/feedback-vector-inl.h +++ b/deps/v8/src/objects/feedback-vector-inl.h @@ -15,8 +15,10 @@ #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/code-inl.h" #include "src/objects/feedback-cell-inl.h" +#include "src/objects/heap-object-set-map-inl.h" #include "src/objects/maybe-object-inl.h" #include "src/objects/shared-function-info.h" +#include "src/objects/slots-inl.h" #include "src/objects/smi.h" #include "src/objects/tagged.h" #include "src/roots/roots-inl.h" @@ -37,6 +39,21 @@ namespace v8::internal { static_cast<intptr_t>( \ Builtin::kLoadIC##Location##Representation##Kind##Index##Baseline)); +FeedbackMetadata::FeedbackMetadata(const AllocationWitness& witness, + int32_t slot_count, + int32_t create_closure_slot_count) + : HeapObject(witness.roots().feedback_metadata_map()), + slot_count_(slot_count), + create_closure_slot_count_(create_closure_slot_count) { + DCHECK_LE(0, slot_count); + DCHECK_LE(0, create_closure_slot_count); + // Initialize the data section to 0. + int size = SizeFor(slot_count, create_closure_slot_count); + int data_size = size - kHeaderSize; + Address data_start = address() + kHeaderSize; + memset(reinterpret_cast<uint8_t*>(data_start), 0, data_size); +} + int32_t FeedbackMetadata::slot_count(AcquireLoadTag) const { return base::AsAtomic32::Acquire_Load(&slot_count_); } @@ -110,6 +127,21 @@ int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) { UNREACHABLE(); } +FeedbackVector::FeedbackVector( + const AllocationWitness& witness, int32_t length, + Tagged<SharedFunctionInfo> shared_function_info, + Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array, + Tagged<FeedbackCell> parent_feedback_cell) + : HeapObject(witness.roots().feedback_vector_map()), + length_(length), + shared_function_info_(witness, shared_function_info), + closure_feedback_cell_array_(witness, closure_feedback_cell_array), + parent_feedback_cell_(witness, parent_feedback_cell) { + DCHECK_LE(0, length); + // TODO(leszeks): Initialize based on the feedback metadata. + MemsetTagged(slots_start(), witness.roots().undefined_value(), length); +} + bool FeedbackVector::is_empty() const { return length().value() == 0; } DEF_GETTER(FeedbackVector, has_metadata, bool) { @@ -127,7 +159,6 @@ DEF_ACQUIRE_GETTER(FeedbackVector, metadata, Tagged<FeedbackMetadata>) { SafeHeapObjectSize FeedbackVector::length() const { return SafeHeapObjectSize(length_); } -void FeedbackVector::set_length(int32_t value) { length_ = value; } int32_t FeedbackVector::invocation_count() const { return invocation_count_.load(std::memory_order_relaxed); @@ -159,35 +190,25 @@ void FeedbackVector::set_invocation_count_before_stable(uint8_t value, invocation_count_before_stable_.store(value, std::memory_order_relaxed); } -uint8_t FeedbackVector::osr_state() const { return osr_state_; } -void FeedbackVector::set_osr_state(uint8_t value) { osr_state_ = value; } -uint16_t FeedbackVector::flags() const { return flags_; } -void FeedbackVector::set_flags(uint16_t value) { flags_ = value; } +FeedbackVector::OsrState FeedbackVector::osr_state() const { + return osr_state_; +} +void FeedbackVector::set_osr_state(OsrState value) { osr_state_ = value; } +FeedbackVector::Flags FeedbackVector::flags() const { return flags_; } +void FeedbackVector::set_flags(Flags value) { flags_ = value; } Tagged<SharedFunctionInfo> FeedbackVector::shared_function_info() const { return shared_function_info_.load(); } -void FeedbackVector::set_shared_function_info(Tagged<SharedFunctionInfo> value, - WriteBarrierMode mode) { - shared_function_info_.store(this, value, mode); -} Tagged<ClosureFeedbackCellArray> FeedbackVector::closure_feedback_cell_array() const { return closure_feedback_cell_array_.load(); } -void FeedbackVector::set_closure_feedback_cell_array( - Tagged<ClosureFeedbackCellArray> value, WriteBarrierMode mode) { - closure_feedback_cell_array_.store(this, value, mode); -} Tagged<FeedbackCell> FeedbackVector::parent_feedback_cell() const { return parent_feedback_cell_.load(); } -void FeedbackVector::set_parent_feedback_cell(Tagged<FeedbackCell> value, - WriteBarrierMode mode) { - parent_feedback_cell_.store(this, value, mode); -} Tagged<MaybeObject> FeedbackVector::raw_feedback_slots(int i, RelaxedLoadTag) const { @@ -202,14 +223,13 @@ void FeedbackVector::set_raw_feedback_slots(int i, Tagged<MaybeObject> value, raw_feedback_slots()[i].Relaxed_Store(this, value, mode); } -int FeedbackVector::osr_urgency() const { - return OsrUrgencyBits::decode(osr_state()); -} +int FeedbackVector::osr_urgency() const { return osr_state().osr_urgency(); } void FeedbackVector::set_osr_urgency(int urgency) { DCHECK(0 <= urgency && urgency <= FeedbackVector::kMaxOsrUrgency); - static_assert(FeedbackVector::kMaxOsrUrgency <= OsrUrgencyBits::kMax); - set_osr_state(OsrUrgencyBits::update(osr_state(), urgency)); + static_assert(FeedbackVector::kMaxOsrUrgency <= + OsrState::OsrUrgencyBits::kMax); + set_osr_state(osr_state().with_osr_urgency(urgency)); } void FeedbackVector::reset_osr_urgency() { set_osr_urgency(0); } @@ -218,37 +238,35 @@ void FeedbackVector::RequestOsrAtNextOpportunity() { set_osr_urgency(kMaxOsrUrgency); } -void FeedbackVector::reset_osr_state() { set_osr_state(0); } - bool FeedbackVector::maybe_has_optimized_osr_code() const { return maybe_has_maglev_osr_code() || maybe_has_turbofan_osr_code(); } bool FeedbackVector::maybe_has_maglev_osr_code() const { - return MaybeHasMaglevOsrCodeBit::decode(osr_state()); + return osr_state().maybe_has_maglev_osr_code(); } bool FeedbackVector::maybe_has_turbofan_osr_code() const { - return MaybeHasTurbofanOsrCodeBit::decode(osr_state()); + return osr_state().maybe_has_turbofan_osr_code(); } void FeedbackVector::set_maybe_has_optimized_osr_code(bool value, CodeKind code_kind) { if (code_kind == CodeKind::MAGLEV) { CHECK(v8_flags.maglev_osr); - set_osr_state(MaybeHasMaglevOsrCodeBit::update(osr_state(), value)); + set_osr_state(osr_state().with_maybe_has_maglev_osr_code(value)); } else { CHECK_EQ(code_kind, CodeKind::TURBOFAN_JS); - set_osr_state(MaybeHasTurbofanOsrCodeBit::update(osr_state(), value)); + set_osr_state(osr_state().with_maybe_has_turbofan_osr_code(value)); } } bool FeedbackVector::interrupt_budget_reset_by_ic_change() const { - return InterruptBudgetResetByIcChangeBit::decode(flags()); + return flags().interrupt_budget_reset_by_ic_change(); } void FeedbackVector::set_interrupt_budget_reset_by_ic_change(bool value) { - set_flags(InterruptBudgetResetByIcChangeBit::update(flags(), value)); + set_flags(flags().with_interrupt_budget_reset_by_ic_change(value)); } bool FeedbackVector::was_once_deoptimized() const { @@ -262,7 +280,7 @@ void FeedbackVector::set_was_once_deoptimized() { } bool FeedbackVector::tiering_in_progress() const { - return TieringInProgressBit::decode(flags()); + return flags().tiering_in_progress(); } std::optional<Tagged<Code>> FeedbackVector::GetOptimizedOsrCode( @@ -491,7 +509,8 @@ ForInHint ForInHintFromFeedback(ForInFeedback type_feedback) { return ForInHint::kEnumCacheKeys; case ForInFeedback::kEnumCacheKeysAndIndices: return ForInHint::kEnumCacheKeysAndIndices; - default: + case ForInFeedback::kEnumeratorHolder: + case ForInFeedback::kAny: return ForInHint::kAny; } UNREACHABLE(); @@ -645,11 +664,11 @@ Builtin FeedbackNexus::GetLoadICHandlerForStorageOffset(int storage_offset, if (is_double) return Builtin::kLoadICDoubleFieldBaseline; if (is_inobject) { - int in_object_index = storage_offset - JSObject::kHeaderSize / kTaggedSize; - DCHECK_GE(in_object_index, 0); + uint32_t in_object_index = + storage_offset - JSObject::kHeaderSize / kTaggedSize; // Currently we have eight handlers that support loading in-object field // with fixed index 0~7. - int kMaxIndex = 7; + uint32_t kMaxIndex = 7; if (in_object_index > kMaxIndex) { return Builtin::kLoadICInObjectNonDoubleFieldBaseline; } @@ -661,12 +680,11 @@ Builtin FeedbackNexus::GetLoadICHandlerForStorageOffset(int storage_offset, in_object_index + 1; return static_cast<Builtin>(builtin_id); } else { - int out_of_object_index = + uint32_t out_of_object_index = storage_offset - OFFSET_OF_DATA_START(FixedArray) / kTaggedSize; - DCHECK_GE(out_of_object_index, 0); // Currently we have four handlers that support loading out-of-object // field with fixed index 0~3. - int kMaxIndex = 3; + uint32_t kMaxIndex = 3; if (out_of_object_index > kMaxIndex) { return Builtin::kLoadICOutOfObjectNonDoubleFieldBaseline; } diff --git a/deps/v8/src/objects/feedback-vector.cc b/deps/v8/src/objects/feedback-vector.cc index a90afb2f29d0..efa5a714c31b 100644 --- a/deps/v8/src/objects/feedback-vector.cc +++ b/deps/v8/src/objects/feedback-vector.cc @@ -392,15 +392,7 @@ void FeedbackVector::AddToVectorsForProfilingTools( } void FeedbackVector::set_tiering_in_progress(bool in_progress) { - set_flags(TieringInProgressBit::update(flags(), in_progress)); -} - -void FeedbackVector::reset_flags() { - set_flags( - TieringInProgressBit::encode(false) | - OsrTieringInProgressBit::encode(false) | - MaybeHasMaglevOsrCodeBit::encode(false) | - MaybeHasTurbofanOsrCodeBit::encode(false)); + set_flags(flags().with_tiering_in_progress(in_progress)); } void FeedbackVector::SetOptimizedOsrCode(Isolate* isolate, FeedbackSlot slot, @@ -423,11 +415,11 @@ void FeedbackVector::SetOptimizedOsrCode(Isolate* isolate, FeedbackSlot slot, } bool FeedbackVector::osr_tiering_in_progress() { - return OsrTieringInProgressBit::decode(flags()); + return flags().osr_tiering_in_progress(); } void FeedbackVector::set_osr_tiering_in_progress(bool osr_in_progress) { - set_flags(OsrTieringInProgressBit::update(flags(), osr_in_progress)); + set_flags(flags().with_osr_tiering_in_progress(osr_in_progress)); } bool FeedbackVector::ClearSlots(Isolate* isolate, ClearBehavior behavior) { @@ -1442,14 +1434,14 @@ KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const { bool FeedbackNexus::IsOneMapManyNames() const { // "1 map, many names" mode is currently only used for Wasm maps, and - // {IsWasmObjectMap} is currently only defined for Wasm-enabled builds. + // {IsAnyWasmObjectMap} is currently only defined for Wasm-enabled builds. #if V8_ENABLE_WEBASSEMBLY if (!IsKeyedLoadICKind(kind()) && !IsKeyedStoreICKind(kind())) return false; auto pair = GetFeedbackPair(); Tagged<HeapObject> heap_object; if (!pair.first.GetHeapObjectIfWeak(&heap_object)) return false; if (!IsMap(heap_object)) return false; - if (!IsWasmObjectMap(Cast<Map>(heap_object))) return false; + if (!IsAnyWasmObjectMap(Cast<Map>(heap_object))) return false; if (!IsSmi(pair.second)) return false; Tagged<Smi> handler = pair.second.ToSmi(); return handler == LoadHandler::LoadGeneric() || diff --git a/deps/v8/src/objects/feedback-vector.h b/deps/v8/src/objects/feedback-vector.h index 680605538cfd..7c07c6ac384b 100644 --- a/deps/v8/src/objects/feedback-vector.h +++ b/deps/v8/src/objects/feedback-vector.h @@ -16,6 +16,7 @@ #include "src/base/small-vector.h" #include "src/builtins/builtins.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/code-kind.h" #include "src/objects/feedback-cell.h" #include "src/objects/map.h" @@ -294,6 +295,7 @@ V8_OBJECT class ClosureFeedbackCellArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); } V8_OBJECT_END; @@ -303,19 +305,43 @@ class NexusConfig; // of length determined by the feedback metadata. V8_OBJECT class FeedbackVector : public HeapObject { public: - // Bit positions in |osr_state|. - using OsrUrgencyBits = base::BitField<uint32_t, 0, 3, uint8_t>; - using MaybeHasTurbofanOsrCodeBit = OsrUrgencyBits::Next<bool, 1>; - using MaybeHasMaglevOsrCodeBit = MaybeHasTurbofanOsrCodeBit::Next<bool, 1>; - using DontUseTheseBitsUnlessBeneficialBits = - MaybeHasMaglevOsrCodeBit::Next<uint32_t, 3>; - // Bit positions in |flags|. - using TieringInProgressBit = base::BitField<bool, 0, 1, uint16_t>; - using OsrTieringInProgressBit = TieringInProgressBit::Next<bool, 1>; - using InterruptBudgetResetByIcChangeBit = - OsrTieringInProgressBit::Next<bool, 1>; - using AllYourBitsAreBelongToJgruberBits = - InterruptBudgetResetByIcChangeBit::Next<uint32_t, 13>; + inline FeedbackVector( + const AllocationWitness& witness, int32_t length, + Tagged<SharedFunctionInfo> shared_function_info, + Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array, + Tagged<FeedbackCell> parent_feedback_cell); + + struct OsrState : BitFieldGroup<OsrState, uint8_t> { + using BitFieldGroup::BitFieldGroup; + + using OsrUrgencyBits = First<uint32_t, 3>; + using MaybeHasTurbofanOsrCodeBit = OsrUrgencyBits::Next<bool, 1>; + using MaybeHasMaglevOsrCodeBit = MaybeHasTurbofanOsrCodeBit::Next<bool, 1>; + using DontUseTheseBitsUnlessBeneficialBits = + MaybeHasMaglevOsrCodeBit::Next<uint32_t, 3>; + + BIT_FIELD_GROUP_ACCESSORS(osr_urgency, OsrUrgencyBits) + BIT_FIELD_GROUP_ACCESSORS(maybe_has_turbofan_osr_code, + MaybeHasTurbofanOsrCodeBit) + BIT_FIELD_GROUP_ACCESSORS(maybe_has_maglev_osr_code, + MaybeHasMaglevOsrCodeBit) + }; + + struct Flags : BitFieldGroup<Flags, uint16_t> { + using BitFieldGroup::BitFieldGroup; + + using TieringInProgressBit = First<bool, 1>; + using OsrTieringInProgressBit = TieringInProgressBit::Next<bool, 1>; + using InterruptBudgetResetByIcChangeBit = + OsrTieringInProgressBit::Next<bool, 1>; + using AllYourBitsAreBelongToJgruberBits = + InterruptBudgetResetByIcChangeBit::Next<uint32_t, 13>; + + BIT_FIELD_GROUP_ACCESSORS(tiering_in_progress, TieringInProgressBit) + BIT_FIELD_GROUP_ACCESSORS(osr_tiering_in_progress, OsrTieringInProgressBit) + BIT_FIELD_GROUP_ACCESSORS(interrupt_budget_reset_by_ic_change, + InterruptBudgetResetByIcChangeBit) + }; inline bool is_empty() const; @@ -325,7 +351,6 @@ V8_OBJECT class FeedbackVector : public HeapObject { DECL_ACQUIRE_GETTER(metadata, Tagged<FeedbackMetadata>) inline SafeHeapObjectSize length() const; - inline void set_length(int32_t value); inline int32_t invocation_count() const; inline int32_t invocation_count(RelaxedLoadTag) const; @@ -339,25 +364,17 @@ V8_OBJECT class FeedbackVector : public HeapObject { inline void set_invocation_count_before_stable(uint8_t value, RelaxedStoreTag); - inline uint8_t osr_state() const; - inline void set_osr_state(uint8_t value); + inline OsrState osr_state() const; + inline void set_osr_state(OsrState value); - inline uint16_t flags() const; - inline void set_flags(uint16_t value); + inline Flags flags() const; + inline void set_flags(Flags value); inline Tagged<SharedFunctionInfo> shared_function_info() const; - inline void set_shared_function_info( - Tagged<SharedFunctionInfo> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array() const; - inline void set_closure_feedback_cell_array( - Tagged<ClosureFeedbackCellArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<FeedbackCell> parent_feedback_cell() const; - inline void set_parent_feedback_cell( - Tagged<FeedbackCell> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // In case a function deoptimizes we set invocation_count_before_stable to // this sentinel. @@ -367,7 +384,7 @@ V8_OBJECT class FeedbackVector : public HeapObject { // the function becomes hotter. When the current loop depth is less than the // osr_urgency, JumpLoop calls into runtime to attempt OSR optimization. static constexpr int kMaxOsrUrgency = 6; - static_assert(OsrUrgencyBits::is_valid(kMaxOsrUrgency)); + static_assert(OsrState::OsrUrgencyBits::is_valid(kMaxOsrUrgency)); inline int osr_urgency() const; inline void set_osr_urgency(int urgency); inline void reset_osr_urgency(); @@ -382,9 +399,6 @@ V8_OBJECT class FeedbackVector : public HeapObject { inline bool maybe_has_optimized_osr_code() const; inline void set_maybe_has_optimized_osr_code(bool value, CodeKind code_kind); - // The `osr_state` contains the osr_urgency and maybe_has_optimized_osr_code. - inline void reset_osr_state(); - // Optimized OSR'd code is cached in JumpLoop feedback vector slots. The // slots either contain a Code object or the ClearedValue. // @@ -420,8 +434,6 @@ V8_OBJECT class FeedbackVector : public HeapObject { inline bool was_once_deoptimized() const; inline void set_was_once_deoptimized(); - void reset_flags(); - // Conversion from a slot to an integer index to the underlying array. static int GetIndex(FeedbackSlot slot) { return slot.ToInt(); } @@ -554,23 +566,25 @@ V8_OBJECT class FeedbackVector : public HeapObject { friend NexusConfig; public: - int32_t length_; - std::atomic<int32_t> invocation_count_; + V8_TQ_CONST const int32_t length_; + std::atomic<int32_t> invocation_count_ = 0; #if TAGGED_SIZE_8_BYTES - uint32_t optional_padding_; + const uint32_t optional_padding_ = 0; #endif - std::atomic<uint8_t> invocation_count_before_stable_; - uint8_t osr_state_; - uint16_t flags_; - TaggedMember<SharedFunctionInfo> shared_function_info_; - TaggedMember<ClosureFeedbackCellArray> closure_feedback_cell_array_; - TaggedMember<FeedbackCell> parent_feedback_cell_; + std::atomic<uint8_t> invocation_count_before_stable_ = 0; + OsrState osr_state_; + Flags flags_; + const TaggedMember<SharedFunctionInfo> shared_function_info_; + const TaggedMember<ClosureFeedbackCellArray> closure_feedback_cell_array_; + const TaggedMember<FeedbackCell> parent_feedback_cell_; private: // Variable-length tail: each slot is a maybe-weak feedback value. Access // goes through Get/SynchronizedGet/Set; callers should not reach the tail // directly. - FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, raw_feedback_slots); + V8_TQ_TAIL_LENGTH(length); + FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, raw_feedback_slots, + V8_TQ_RELAXED); } V8_OBJECT_END; inline constexpr int FeedbackVector::kHeaderSize = @@ -764,9 +778,11 @@ class SharedFeedbackSlot { // after the int32s of the slots. V8_OBJECT class FeedbackMetadata : public HeapObject { public: + inline FeedbackMetadata(const AllocationWitness& witness, int32_t slot_count, + int32_t create_closure_slot_count); + // The number of slots that this metadata contains. Stored as an int32. inline int32_t slot_count() const { return slot_count_; } - inline void set_slot_count(int32_t value) { slot_count_ = value; } // The number of feedback cells required for create closures. Stored as an // int32. @@ -775,9 +791,6 @@ V8_OBJECT class FeedbackMetadata : public HeapObject { inline int32_t create_closure_slot_count() const { return create_closure_slot_count_; } - inline void set_create_closure_slot_count(int32_t value) { - create_closure_slot_count_ = value; - } // Get slot_count using an acquire load. inline int32_t slot_count(AcquireLoadTag) const; @@ -850,8 +863,8 @@ V8_OBJECT class FeedbackMetadata : public HeapObject { kInt32Size * kBitsPerByte, uint32_t>; public: - int32_t slot_count_; - int32_t create_closure_slot_count_; + const int32_t slot_count_; + const int32_t create_closure_slot_count_; } V8_OBJECT_END; inline constexpr int FeedbackMetadata::kHeaderSize = sizeof(FeedbackMetadata); diff --git a/deps/v8/src/objects/feedback-vector.tq b/deps/v8/src/objects/feedback-vector.tq index a116ed20ef34..b0c2c0361c81 100644 --- a/deps/v8/src/objects/feedback-vector.tq +++ b/deps/v8/src/objects/feedback-vector.tq @@ -4,7 +4,7 @@ type TieringState extends uint16 constexpr 'TieringState'; -@cppScope('FeedbackVector') +@cppScope('FeedbackVector::Flags') bitfield struct FeedbackVectorFlags extends uint16 { tiering_in_progress: bool: 1 bit; osr_tiering_in_progress: bool: 1 bit; @@ -12,8 +12,8 @@ bitfield struct FeedbackVectorFlags extends uint16 { all_your_bits_are_belong_to_jgruber: uint32: 13 bit; } -@cppScope('FeedbackVector') -bitfield struct OsrState extends uint8 { +@cppScope('FeedbackVector::OsrState') +bitfield struct FeedbackVectorOsrState extends uint8 { // The layout is chosen s.t. osr_urgency and // maybe_has_(maglev|turbofan)_osr_code can be loaded with a single load // (i.e. no masking required). @@ -37,7 +37,7 @@ extern class FeedbackVector extends HeapObject { invocation_count: int32; @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; invocation_count_before_stable: uint8; - osr_state: OsrState; + osr_state: FeedbackVectorOsrState; flags: FeedbackVectorFlags; shared_function_info: SharedFunctionInfo; closure_feedback_cell_array: ClosureFeedbackCellArray; diff --git a/deps/v8/src/objects/field-index.h b/deps/v8/src/objects/field-index.h index f6f5773cb53b..9c3c66318feb 100644 --- a/deps/v8/src/objects/field-index.h +++ b/deps/v8/src/objects/field-index.h @@ -117,6 +117,14 @@ class FieldIndex final { static constexpr int kOffsetBitsSize = (kDescriptorIndexBitCount + 1 + kTaggedSizeLog2); + public: + // Maximum byte offset (inclusive of a kTaggedSize access) encodable in a + // FieldIndex. + static constexpr int kMaxOffset = 1 << kOffsetBitsSize; + static_assert(kMaxOffset == + (PropertyDetails::OffsetInWordsField::kMax + 1) * kTaggedSize); + + private: static constexpr int kPropertyArrayDataStartBitCount = 2 + kTaggedSizeLog2; // Index from beginning of object. diff --git a/deps/v8/src/objects/fixed-array-base.h b/deps/v8/src/objects/fixed-array-base.h index e0d27d33608c..803206cbb058 100644 --- a/deps/v8/src/objects/fixed-array-base.h +++ b/deps/v8/src/objects/fixed-array-base.h @@ -55,7 +55,7 @@ V8_OBJECT class FixedArrayBase : public HeapObject { DECL_VERIFIER(FixedArrayBase) public: - uint32_t length_; + V8_TQ_CONST uint32_t length_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif @@ -84,7 +84,7 @@ V8_OBJECT class TrustedFixedArrayBase : public TrustedObject { inline void set_length(uint32_t value, ReleaseStoreTag tag); public: - uint32_t length_; + V8_TQ_CONST uint32_t length_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif diff --git a/deps/v8/src/objects/fixed-array.h b/deps/v8/src/objects/fixed-array.h index b9519556b337..1c6926d75e86 100644 --- a/deps/v8/src/objects/fixed-array.h +++ b/deps/v8/src/objects/fixed-array.h @@ -318,6 +318,7 @@ V8_OBJECT class FixedArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; @@ -358,6 +359,7 @@ V8_OBJECT class TrustedFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; @@ -396,6 +398,7 @@ V8_OBJECT class ProtectedFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(ElementMemberT, objects); } V8_OBJECT_END; @@ -432,6 +435,7 @@ V8_OBJECT class WeakFixedArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -464,6 +468,7 @@ V8_OBJECT class WeakHomomorphicFixedArray public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -491,6 +496,7 @@ V8_OBJECT class TrustedWeakFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -521,6 +527,7 @@ V8_OBJECT class ProtectedWeakFixedArray public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(ElementMemberT, objects); } V8_OBJECT_END; @@ -639,8 +646,9 @@ V8_OBJECT class WeakArrayList } public: - uint32_t capacity_; + V8_TQ_CONST uint32_t capacity_; uint32_t length_; + V8_TQ_TAIL_LENGTH(capacity); FLEXIBLE_ARRAY_MEMBER(TaggedMember<MaybeObject>, objects); } V8_OBJECT_END; @@ -716,8 +724,9 @@ V8_OBJECT class ArrayList AllocationType allocation = AllocationType::kYoung); public: - uint32_t capacity_; + V8_TQ_CONST uint32_t capacity_; uint32_t length_; + V8_TQ_TAIL_LENGTH(capacity); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/fixed-array.tq b/deps/v8/src/objects/fixed-array.tq index af46fddf25e2..d8c7d9da73ac 100644 --- a/deps/v8/src/objects/fixed-array.tq +++ b/deps/v8/src/objects/fixed-array.tq @@ -16,7 +16,7 @@ extern class TrustedFixedArray extends TrustedFixedArrayBase { @cppObjectLayoutDefinition extern class ProtectedFixedArray extends TrustedFixedArrayBase { - objects[length]: TrustedObject|Smi; + objects[length]: ProtectedPointer<TrustedObject|Smi>; } @cppObjectLayoutDefinition @@ -36,9 +36,7 @@ extern class TrustedWeakFixedArray extends TrustedFixedArrayBase { @cppObjectLayoutDefinition extern class ProtectedWeakFixedArray extends TrustedFixedArrayBase { - // TODO(jkummerow): Define "TrustedMaybeObject" if we ever write Torque - // code accessing these values. - objects[length]: TrustedObject|Smi; + objects[length]: ProtectedPointer<TrustedObject|Weak<TrustedObject>|Smi>; } @cppObjectLayoutDefinition diff --git a/deps/v8/src/objects/fixed-primitive-array-inl.h b/deps/v8/src/objects/fixed-primitive-array-inl.h index edb27b85d258..5400ee03587b 100644 --- a/deps/v8/src/objects/fixed-primitive-array-inl.h +++ b/deps/v8/src/objects/fixed-primitive-array-inl.h @@ -192,6 +192,11 @@ void FixedDoubleArray::set(uint32_t index, double value) { DCHECK(!is_the_hole(index)); } +void FixedDoubleArray::set_raw(uint32_t index, Float64 value) { + DCHECK(IsInBounds(index)); + values()[index].set_value_as_bits(value.get_bits()); +} + #ifdef V8_ENABLE_UNDEFINED_DOUBLE void FixedDoubleArray::set_undefined(uint32_t index) { DCHECK(IsInBounds(index)); @@ -328,8 +333,13 @@ Handle<FixedIntegerArrayBase<T, Base>> FixedIntegerArrayBase<T, Base>::New( base::internal::CheckedNumeric<uint32_t> checked_byte_length = length; checked_byte_length *= sizeof(T); CHECK(checked_byte_length.AssignIfValid(&byte_length)); - return TrustedCast<FixedIntegerArrayBase<T, Base>>( - Base::New(isolate, byte_length, std::forward<MoreArgs>(more_args)...)); + if constexpr (is_subtype_v<Base, TrustedObject>) { + return TrustedCast<FixedIntegerArrayBase<T, Base>>( + Base::New(isolate, byte_length, std::forward<MoreArgs>(more_args)...)); + } else { + return Cast<FixedIntegerArrayBase<T, Base>>( + Base::New(isolate, byte_length, std::forward<MoreArgs>(more_args)...)); + } } template <typename T, typename Base> diff --git a/deps/v8/src/objects/fixed-primitive-array.h b/deps/v8/src/objects/fixed-primitive-array.h index 528c63e9e047..8b40f3603093 100644 --- a/deps/v8/src/objects/fixed-primitive-array.h +++ b/deps/v8/src/objects/fixed-primitive-array.h @@ -14,6 +14,7 @@ #include "src/objects/tagged.h" #include "src/objects/trusted-object.h" #include "src/roots/roots.h" +#include "src/utils/boxed-float.h" #include "src/utils/memcopy.h" // Has to be the last include (doesn't have include guards): @@ -135,6 +136,7 @@ V8_OBJECT class FixedDoubleArray static inline Handle<Object> get(Tagged<FixedDoubleArray> array, uint32_t index, Isolate* isolate); inline void set(uint32_t index, double value); + inline void set_raw(uint32_t index, Float64 value); #ifdef V8_ENABLE_UNDEFINED_DOUBLE inline void set_undefined(uint32_t index); inline bool is_undefined(uint32_t index); @@ -158,7 +160,9 @@ V8_OBJECT class FixedDoubleArray public: // length_ / optional_padding_ live in FixedArrayBase. - FLEXIBLE_ARRAY_MEMBER(ElementMemberT, values); + V8_TQ_TAIL_LENGTH(length); + FLEXIBLE_ARRAY_MEMBER(ElementMemberT, values, + V8_TQ_TYPE(float64_or_undefined_or_hole)); } V8_OBJECT_END; // ByteArray represents fixed sized arrays containing raw bytes that will not @@ -194,6 +198,7 @@ V8_OBJECT class ByteArray : public PrimitiveArrayBase<ByteArray, uint8_t> { public: // length_ / optional_padding_ live in FixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(uint8_t, values); } V8_OBJECT_END; @@ -231,6 +236,7 @@ class TrustedByteArray : public PrimitiveArrayBase<TrustedByteArray, uint8_t, public: // length_ / optional_padding_ live in TrustedFixedArrayBase. + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(uint8_t, values); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/function-kind.h b/deps/v8/src/objects/function-kind.h index 148109afa5c4..0329f44e2d46 100644 --- a/deps/v8/src/objects/function-kind.h +++ b/deps/v8/src/objects/function-kind.h @@ -112,7 +112,7 @@ inline bool IsConciseMethod(FunctionKind kind) { FunctionKind::kClassStaticInitializerFunctionPrecededByMember); } -inline bool IsStrictFunctionWithoutPrototype(FunctionKind kind) { +inline bool IsFunctionWithoutPrototype(FunctionKind kind) { return base::IsInRange(kind, FunctionKind::kGetterFunction, FunctionKind::kAsyncArrowFunction) || base::IsInRange(kind, FunctionKind::kAsyncConciseMethod, diff --git a/deps/v8/src/objects/hash-table-inl.h b/deps/v8/src/objects/hash-table-inl.h index 2d0edf63fc78..a96b3a2b8ad1 100644 --- a/deps/v8/src/objects/hash-table-inl.h +++ b/deps/v8/src/objects/hash-table-inl.h @@ -8,6 +8,8 @@ #include "src/objects/hash-table.h" // Include the non-inl header before the rest of the headers. +#include <bit> + #include "src/execution/isolate-utils-inl.h" #include "src/heap/heap.h" #include "src/objects/fixed-array-inl.h" @@ -88,7 +90,7 @@ constexpr uint32_t HashTableBase::ComputeCapacity(uint32_t at_least_space_for) { // See matching computation in HashTable::HasSufficientCapacityToAdd(). // Must be kept in sync with CodeStubAssembler::HashTableComputeCapacity(). uint32_t raw_cap = at_least_space_for + (at_least_space_for >> 1); - uint32_t capacity = base::bits::RoundUpToPowerOfTwo32(raw_cap); + uint32_t capacity = std::bit_ceil(raw_cap); return std::max({capacity, kMinCapacity}); } diff --git a/deps/v8/src/objects/hash-table.h b/deps/v8/src/objects/hash-table.h index e11548d5d5e1..ccec4c8cb6e3 100644 --- a/deps/v8/src/objects/hash-table.h +++ b/deps/v8/src/objects/hash-table.h @@ -5,6 +5,8 @@ #ifndef V8_OBJECTS_HASH_TABLE_H_ #define V8_OBJECTS_HASH_TABLE_H_ +#include <bit> + #include "src/base/compiler-specific.h" #include "src/base/export-template.h" #include "src/base/macros.h" @@ -206,7 +208,7 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) HashTable // Maximal capacity of HashTable. Based on maximal length of underlying // FixedArray. Staying below kMaxCapacity also ensures that EntryToIndex // cannot overflow. - static const uint32_t kMaxCapacity = base::bits::RoundDownToPowerOfTwo32( + static const uint32_t kMaxCapacity = std::bit_floor( (FixedArray::kMaxLength - kElementsStartIndex) / kEntrySize); // Don't shrink a HashTable below this capacity. diff --git a/deps/v8/src/objects/heap-number-inl.h b/deps/v8/src/objects/heap-number-inl.h index 7d2b256fc6f0..6ef5c560e92e 100644 --- a/deps/v8/src/objects/heap-number-inl.h +++ b/deps/v8/src/objects/heap-number-inl.h @@ -8,9 +8,18 @@ #include "src/objects/heap-number.h" // Include the non-inl header before the rest of the headers. +#include "src/objects/heap-object-set-map-inl.h" +#include "src/roots/roots-inl.h" + namespace v8 { namespace internal { +HeapNumber::HeapNumber(const AllocationWitness& witness, double value) + : PrimitiveHeapObject(witness.roots().heap_number_map()), value_(value) {} + +HeapNumber::HeapNumber(const AllocationWitness& witness, Float64 value) + : PrimitiveHeapObject(witness.roots().heap_number_map()), value_(value) {} + double HeapNumber::value() const { return value_.value(); } void HeapNumber::set_value(double value) { value_.set_value(value); @@ -22,9 +31,10 @@ void HeapNumber::set_value_as_bits(uint64_t bits) { value_.set_value_as_bits(bits); } -bool HeapNumber::is_the_hole() const { - return value_as_bits() == kHoleNanInt64; -} +UninitializedHeapNumber::UninitializedHeapNumber( + const AllocationWitness& witness) + : HeapObject(witness.roots().uninitialized_heap_number_map()), + value_(0.0) {} } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/heap-number.h b/deps/v8/src/objects/heap-number.h index a380dd50df87..1e8d4ae7a805 100644 --- a/deps/v8/src/objects/heap-number.h +++ b/deps/v8/src/objects/heap-number.h @@ -29,15 +29,15 @@ class JSContextSpecialization; // represented in a Smi (small integer). V8_OBJECT class HeapNumber : public PrimitiveHeapObject { public: + inline HeapNumber(const AllocationWitness& witness, double value); + inline HeapNumber(const AllocationWitness& witness, Float64 value); + inline double value() const; inline void set_value(double value); inline uint64_t value_as_bits() const; inline void set_value_as_bits(uint64_t bits); - // Returns true if the heap number contains the hole NaN bit pattern. - inline bool is_the_hole() const; - static const uint32_t kSignMask = 0x80000000u; static const uint32_t kExponentMask = 0x7ff00000u; static const uint32_t kMantissaMask = 0xfffffu; @@ -76,6 +76,37 @@ V8_OBJECT class HeapNumber : public PrimitiveHeapObject { UnalignedDoubleMember value_; } V8_OBJECT_END; +// Represents mutable HeapNumber in uninitialized state. +V8_OBJECT class UninitializedHeapNumber : public HeapObject { + public: + static constexpr int kSize = sizeof(HeapNumber); + + inline explicit UninitializedHeapNumber(const AllocationWitness& witness); + + inline double value() const { return value_.value(); } + inline void set_value(double value) { value_.set_value(value); } + + inline uint64_t value_as_bits() const { + return base::bit_cast<uint64_t>(value_.value()); + } + inline void set_value_as_bits(uint64_t bits) { + value_.set_value(base::bit_cast<double>(bits)); + } + + DECL_PRINTER(UninitializedHeapNumber) + DECL_VERIFIER(UninitializedHeapNumber) + + class BodyDescriptor; + + private: + friend struct OffsetsForDebug; + friend class TorqueGeneratedHeapNumberAsserts; + friend AllocationAlignment HeapObject::RequiredAlignment( + InSharedSpace in_shared_space, Tagged<Map> map); + + public: + UnalignedDoubleMember value_; +} V8_OBJECT_END; } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/heap-number.tq b/deps/v8/src/objects/heap-number.tq index 498a89c767c5..0b9f17a1f9ad 100644 --- a/deps/v8/src/objects/heap-number.tq +++ b/deps/v8/src/objects/heap-number.tq @@ -11,3 +11,12 @@ extern class HeapNumber extends PrimitiveHeapObject { // The HeapNumber value NaN type NaN extends HeapNumber; + +// This object is used for reserving space for mutable HeapNumber and for +// representing an uninitialized state of a double field, so it's layout must +// be equal to the layout of HeapNumber for simple transition from +// uninitialized to initialized state. +@cppObjectLayoutDefinition +extern class UninitializedHeapNumber extends HeapObject { + value: float64; +} diff --git a/deps/v8/src/objects/heap-object-field-inl.h b/deps/v8/src/objects/heap-object-field-inl.h index 591dfc7f395a..55770f5eb4a1 100644 --- a/deps/v8/src/objects/heap-object-field-inl.h +++ b/deps/v8/src/objects/heap-object-field-inl.h @@ -14,8 +14,8 @@ #include "src/sandbox/bounded-size-inl.h" #include "src/sandbox/cppheap-pointer-inl.h" #include "src/sandbox/external-pointer-inl.h" -#include "src/sandbox/indirect-pointer-inl.h" #include "src/sandbox/sandboxed-pointer-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -197,9 +197,9 @@ CppHeapPointerSlot HeapObject::RawCppHeapPointerField(int byte_offset) const { return CppHeapPointerSlot(field_address(byte_offset)); } -IndirectPointerSlot HeapObject::RawIndirectPointerField( - int byte_offset, IndirectPointerTagRange tag_range) const { - return IndirectPointerSlot(field_address(byte_offset), tag_range); +TrustedPointerSlot HeapObject::RawTrustedPointerField( + int byte_offset, TrustedPointerTagRange tag_range) const { + return TrustedPointerSlot(field_address(byte_offset), tag_range); } } // namespace internal diff --git a/deps/v8/src/objects/heap-object-set-map-inl.h b/deps/v8/src/objects/heap-object-set-map-inl.h index e6a705cfcd54..35b8caa8ebd3 100644 --- a/deps/v8/src/objects/heap-object-set-map-inl.h +++ b/deps/v8/src/objects/heap-object-set-map-inl.h @@ -16,6 +16,7 @@ #include "src/heap/read-only-heap-inl.h" #include "src/objects/instance-type-inl.h" #include "src/objects/map-word-inl.h" +#include "src/objects/primitive-heap-object.h" #include "src/objects/slots-inl.h" #include "src/objects/tagged-field-inl.h" @@ -111,6 +112,48 @@ void HeapObject::set_map(IsolateT* isolate, Tagged<Map> value, #endif } +// static +WriteBarrierMode AllocationWitness::WriteBarrierModeForAllocation( + Tagged<HeapObject> object, AllocationType allocation) { + if (v8_flags.disable_write_barriers) return SKIP_WRITE_BARRIER; + if (allocation == AllocationType::kReadOnly) return SKIP_WRITE_BARRIER; + if (allocation == AllocationType::kYoung && + !v8_flags.single_generation.value()) { +#if V8_VERIFY_WRITE_BARRIERS + DCHECK(WriteBarrier::IsMostRecentYoungAllocation(object.address())); +#endif + return SKIP_WRITE_BARRIER; + } + return UPDATE_WRITE_BARRIER; +} + +AllocationWitness::AllocationWitness(Tagged<HeapObject> object, + ReadOnlyRoots roots, + AllocationType allocation) + : AllocationWitness(object, roots, + WriteBarrierModeForAllocation(object, allocation)) {} + +AllocationWitness::AllocationWitness(Tagged<HeapObject> object, + ReadOnlyRoots roots, + WriteBarrierMode write_barrier_mode) + : object_(object), roots_(roots), write_barrier_mode_(write_barrier_mode) {} + +HeapObject::HeapObject(Tagged<ReadOnly<Map>> map) { + DCHECK(!map.is_null()); + set_map_after_allocation(static_cast<Isolate*>(nullptr), map, + SKIP_WRITE_BARRIER); +} + +HeapObject::HeapObject(const AllocationWitness& witness, Tagged<Map> map) { + DCHECK_EQ(witness.object(), this); + DCHECK(!map.is_null()); + set_map_after_allocation(static_cast<Isolate*>(nullptr), map, + witness.write_barrier_mode()); +} + +PrimitiveHeapObject::PrimitiveHeapObject(Tagged<ReadOnly<Map>> map) + : HeapObject(map) {} + template <typename IsolateT> void HeapObject::set_map_after_allocation(IsolateT* isolate, Tagged<Map> value, WriteBarrierMode mode) { diff --git a/deps/v8/src/objects/heap-object.h b/deps/v8/src/objects/heap-object.h index 60f64116d4e3..063646a32ee3 100644 --- a/deps/v8/src/objects/heap-object.h +++ b/deps/v8/src/objects/heap-object.h @@ -7,13 +7,15 @@ #include "src/base/macros.h" #include "src/base/strong-alias.h" +#include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/objects/casting.h" #include "src/objects/instance-type.h" #include "src/objects/slots.h" #include "src/objects/tagged-field.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/roots/roots.h" #include "src/sandbox/isolate.h" +#include "src/sandbox/trusted-pointer-tag.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -24,12 +26,11 @@ namespace internal { class Heap; class PrimitiveHeapObject; class ExternalPointerSlot; -class IndirectPointerSlot; +class TrustedPointerSlot; class ExposedTrustedObject; class ObjectVisitor; class WritableFreeSpace; class WriteBarrierModeScope; -class EarlyReadOnlyRoots; // A safe HeapObject size is a uint32_t that's guaranteed to yield in OOB within // the sandbox. The alias exists to force appropriate conversions at the @@ -58,6 +59,30 @@ struct ObjectTraits { using InSharedSpace = base::StrongAlias<struct InSharedSpaceTag, bool>; +class V8_NODISCARD AllocationWitness { + public: + inline AllocationWitness(Tagged<HeapObject> object, ReadOnlyRoots roots, + AllocationType allocation); + inline AllocationWitness(Tagged<HeapObject> object, ReadOnlyRoots roots, + WriteBarrierMode write_barrier_mode); + + AllocationWitness(const AllocationWitness&) = delete; + AllocationWitness& operator=(const AllocationWitness&) = delete; + + HeapObject* object() const { return &*object_; } + ReadOnlyRoots roots() const { return roots_; } + WriteBarrierMode write_barrier_mode() const { return write_barrier_mode_; } + + private: + static inline WriteBarrierMode WriteBarrierModeForAllocation( + Tagged<HeapObject> object, AllocationType allocation); + + DISALLOW_GARBAGE_COLLECTION(no_gc_) + const Tagged<HeapObject> object_; + const ReadOnlyRoots roots_; + const WriteBarrierMode write_barrier_mode_; +}; + // HeapObject is the superclass for all classes describing heap allocated // objects. V8_OBJECT class HeapObject { @@ -297,8 +322,8 @@ V8_OBJECT class HeapObject { inline ExternalPointerSlot RawExternalPointerField( int byte_offset, ExternalPointerTagRange tag_range) const; inline CppHeapPointerSlot RawCppHeapPointerField(int byte_offset) const; - inline IndirectPointerSlot RawIndirectPointerField( - int byte_offset, IndirectPointerTagRange tag_range) const; + inline TrustedPointerSlot RawTrustedPointerField( + int byte_offset, TrustedPointerTagRange tag_range) const; // Return the write barrier mode for this. Callers of this function // must be able to present a reference to an DisallowGarbageCollection @@ -385,6 +410,24 @@ V8_OBJECT class HeapObject { friend class Heap; friend class CodeStubAssembler; + public: + inline explicit HeapObject(Tagged<ReadOnly<Map>> map); + inline HeapObject(const AllocationWitness& witness, Tagged<Map> map); + + public: + void* operator new(size_t) = delete; + void* operator new[](size_t) = delete; + void* operator new(size_t size, const AllocationWitness& witness) { + return witness.object(); + } + void operator delete(void*) { + FATAL("Manually deleting a garbage collected object is not allowed"); + } + void operator delete[](void*) = delete; + void operator delete(void*, const AllocationWitness&) { + FATAL("Manually deleting a garbage collected object is not allowed"); + } + // HeapObjects shouldn't be copied or moved by C++ code, only by the GC. // TODO(leszeks): Consider making these non-deleted if the GC starts using // HeapObject rather than manual per-byte access. @@ -393,8 +436,7 @@ V8_OBJECT class HeapObject { HeapObject& operator=(HeapObject&&) V8_NOEXCEPT = delete; HeapObject& operator=(const HeapObject&) V8_NOEXCEPT = delete; - public: - TaggedMember<Map> map_; + V8_TQ_CONST TaggedMember<Map> map_; } V8_OBJECT_END; static_assert(offsetof(HeapObject, map_) == Internals::kHeapObjectMapOffset); diff --git a/deps/v8/src/objects/hole.h b/deps/v8/src/objects/hole.h index 71c463931c7e..9bdb4a395d74 100644 --- a/deps/v8/src/objects/hole.h +++ b/deps/v8/src/objects/hole.h @@ -25,7 +25,7 @@ V8_OBJECT class Hole : public HeapObject { private: friend class Heap; - friend class Isolate; + friend class ReadOnlyHeap; // TODO(leszeks): Make it smaller if able and needed. static constexpr int kPayloadSize = 64 * KB; diff --git a/deps/v8/src/objects/instance-type-checker.h b/deps/v8/src/objects/instance-type-checker.h index c562d961dcf1..eeeeb6ddbba6 100644 --- a/deps/v8/src/objects/instance-type-checker.h +++ b/deps/v8/src/objects/instance-type-checker.h @@ -21,6 +21,7 @@ class Map; #define INSTANCE_TYPE_CHECKERS_SINGLE(V) \ INSTANCE_TYPE_LIST_SINGLE(V) \ V(BigInt, BIGINT_TYPE) \ + V(JSObjectExact, JS_OBJECT_TYPE) \ V(FixedArrayExact, FIXED_ARRAY_TYPE) #define INSTANCE_TYPE_CHECKERS_RANGE(V) \ diff --git a/deps/v8/src/objects/instance-type-inl.h b/deps/v8/src/objects/instance-type-inl.h index d814b90edcac..9d2b11273aa4 100644 --- a/deps/v8/src/objects/instance-type-inl.h +++ b/deps/v8/src/objects/instance-type-inl.h @@ -720,6 +720,15 @@ V8_INLINE bool IsCppHeapPointerWrapperObject(Tagged<Map> map_object) { INSTANCE_TYPE_CHECKERS(TYPE_CHECKER) #undef TYPE_CHECKER +#if V8_ENABLE_WEBASSEMBLY + +inline bool IsAnyWasmObjectMap(Tagged<Map> map) { + // Most Wasm object types form a contiguous range and can be covered by a + // single generated range-based check, but WASM_CUSTOM_MAP_TYPE is separate. + return IsWasmObjectMap(map) || IsWasmCustomMapMap(map); +} +#endif // V8_ENABLE_WEBASSEMBLY + } // namespace v8::internal #include "src/objects/object-macros-undef.h" diff --git a/deps/v8/src/objects/instance-type.h b/deps/v8/src/objects/instance-type.h index f1cdcf99f7bf..9b74b05fcc51 100644 --- a/deps/v8/src/objects/instance-type.h +++ b/deps/v8/src/objects/instance-type.h @@ -73,13 +73,7 @@ constexpr uint32_t kExternalTwoByteStringTag = const uint32_t kUncachedExternalStringMask = 1 << 4; const uint32_t kUncachedExternalStringTag = 1 << 4; -// For strings, bit 5 indicates that the string is internalized (if not set) or -// isn't (if set). -const uint32_t kIsNotInternalizedMask = 1 << 5; -const uint32_t kNotInternalizedTag = 1 << 5; -const uint32_t kInternalizedTag = 0; - -// For strings, bit 6 indicates that the string is accessible by more than one +// For strings, bit 5 indicates that the string is accessible by more than one // thread. Note that a string that is allocated in the shared heap is not // accessible by more than one thread until it is explicitly shared (e.g. by // postMessage). @@ -93,8 +87,18 @@ const uint32_t kInternalizedTag = 0; // are either always shared or always not shared depending on // v8_flags.shared_string_table. This will be hardcoded once // v8_flags.shared_string_table is removed. -const uint32_t kSharedStringMask = 1 << 6; -const uint32_t kSharedStringTag = 1 << 6; +const uint32_t kSharedStringMask = 1 << 5; +const uint32_t kSharedStringTag = 1 << 5; + +// For strings, bit 6 indicates that the string is internalized (if not set) or +// isn't (if set). It is the highest string bit so that it forms a contiguous +// run with kIsNotStringMask: the combined "is not an internalized string" mask +// is then a logical immediate on arm64. +const uint32_t kIsNotInternalizedMask = 1 << 6; +const uint32_t kNotInternalizedTag = 1 << 6; +const uint32_t kInternalizedTag = 0; +static_assert((kIsNotStringMask | kIsNotInternalizedMask) == + ~(kIsNotInternalizedMask - 1)); constexpr uint32_t kStringRepresentationEncodingAndSharedMask = kStringRepresentationAndEncodingMask | kSharedStringMask; @@ -348,6 +352,8 @@ V8_EXPORT_PRIVATE std::string ToString(InstanceType instance_type); V(_, GlobalDictionaryMap, global_dictionary_map, GlobalDictionary) \ V(_, GlobalPropertyCellMap, global_property_cell_map, PropertyCell) \ V(_, HeapNumberMap, heap_number_map, HeapNumber) \ + V(_, UninitializedHeapNumberMap, uninitialized_heap_number_map, \ + UninitializedHeapNumber) \ V(_, WeakFixedArrayMap, weak_fixed_array_map, WeakFixedArray) \ V(_, WeakHomomorphicFixedArrayMap, weak_homomorphic_fixed_array_map, \ WeakHomomorphicFixedArray) \ diff --git a/deps/v8/src/objects/instance-types-gen.h b/deps/v8/src/objects/instance-types-gen.h index e708f32ecb93..85b1cda62362 100644 --- a/deps/v8/src/objects/instance-types-gen.h +++ b/deps/v8/src/objects/instance-types-gen.h @@ -7,14 +7,14 @@ // Selects which instance-type generator's output is compiled into V8: // metagen (tools/metagen/) or Torque's emission. Controlled by the build arg -// v8_use_metagen_instance_types (GN and Bazel): when off, the build sets -// V8_USE_METAGEN_INSTANCE_TYPES=0 (the "features" config in BUILD.gn, +// v8_use_metagen (GN and Bazel): when off, the build sets +// V8_USE_METAGEN=0 (the "features" config in BUILD.gn, // ":define_flags" in BUILD.bazel); when on it is left undefined and the // fallback below selects metagen, so every translation unit agrees regardless // of which configs it picks up. Torque runs either way; the metagen harvest is // only in the build graph when the arg is on. -#if !defined(V8_USE_METAGEN_INSTANCE_TYPES) -#define V8_USE_METAGEN_INSTANCE_TYPES 1 +#if !defined(V8_USE_METAGEN) +#define V8_USE_METAGEN 1 #endif // The harvest pass is checked before the switch, not inside it: the @@ -32,20 +32,24 @@ #define INSTANCE_TYPE_LIST_SINGLE(V) #define INSTANCE_TYPE_LIST_MULTIPLE(V) #define INSTANCE_TYPE_LIST_RANGE(V) -#elif V8_USE_METAGEN_INSTANCE_TYPES +#elif V8_USE_METAGEN +#ifdef V8_USE_CHECKED_IN_GENERATED_HEADERS +#include "src/gen/intl-wasm/instance-types.h" +#else #include "metagen/instance-types.h" +#endif #else #include "torque-generated/instance-types.h" // metagen emits the INSTANCE_TYPE_LIST_{SINGLE,MULTIPLE,RANGE} buckets // inside metagen/instance-types.h; on the Torque path they come from this // separate generated header. Remove with the -// V8_USE_METAGEN_INSTANCE_TYPES switch. +// V8_USE_METAGEN switch. #include "torque-generated/instance-type-checker-lists.h" // metagen derives HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST from Name##Print / // Name##Verify declarations, which Torque knows nothing about. The debug- // reader lists (classes with a Torque body) are the exact set that carried // the Print/Verify dispatch before the metagen cutover, so alias them here. -// Remove with the V8_USE_METAGEN_INSTANCE_TYPES switch. +// Remove with the V8_USE_METAGEN switch. #include "torque-generated/debug-reader-classes-list.h" #define HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST(V) \ TORQUE_DEBUG_READER_CLASSES_SINGLE(V) \ diff --git a/deps/v8/src/objects/intl-objects.cc b/deps/v8/src/objects/intl-objects.cc index 705ce2d6f623..ebbaa56eb8b2 100644 --- a/deps/v8/src/objects/intl-objects.cc +++ b/deps/v8/src/objects/intl-objects.cc @@ -23,6 +23,7 @@ #include "src/execution/local-isolate.h" #include "src/handles/global-handles.h" #include "src/heap/factory.h" +#include "src/init/v8.h" #include "src/objects/js-collator-inl.h" #include "src/objects/js-date-time-format-inl.h" #include "src/objects/js-locale-inl.h" @@ -261,7 +262,9 @@ void IcuBreakIteratorWithText::SetText(Isolate* isolate, DirectHandle<String> string) { string = String::Flatten(isolate, string); text_.reset(Intl::ToICUUnicodeString(isolate, string).clone()); - DCHECK_NOT_NULL(text_); + if (V8_UNLIKELY(text_ == nullptr)) { + V8::FatalProcessOutOfMemory(isolate, "IcuBreakIteratorWithText::SetText"); + } iterator_->setText(*text_); } @@ -951,6 +954,15 @@ Maybe<std::vector<std::string>> Intl::CanonicalizeLocaleList( // https://tc39.es/ecma402/#sup-string.prototype.tolocalelowercase // https://tc39.es/ecma402/#sup-string.prototype.tolocaleuppercase +bool Intl::LocaleRequiresSpecialCaseMapping(std::string_view locale) { + size_t dash = locale.find('-'); + std::string_view language = locale.substr(0, dash); + for (std::string_view special_locale : kCaseMappingSpecialLocales) { + if (language == special_locale) return true; + } + return false; +} + MaybeDirectHandle<String> Intl::StringLocaleConvertCase( Isolate* isolate, DirectHandle<String> s, bool to_upper, DirectHandle<Object> locales) { @@ -985,8 +997,7 @@ MaybeDirectHandle<String> Intl::StringLocaleConvertCase( // in the root locale needs to be adjusted for az, lt and tr because even case // mapping of ASCII range characters are different in those locales. // Greek (el) does not require any adjustment. - if (V8_UNLIKELY((requested_locale == "tr") || (requested_locale == "el") || - (requested_locale == "lt") || (requested_locale == "az"))) { + if (V8_UNLIKELY(LocaleRequiresSpecialCaseMapping(requested_locale))) { return LocaleConvertCase(isolate, s, to_upper, std::string(requested_locale).c_str()); } else { @@ -2105,7 +2116,7 @@ std::string BestFitMatcher(Isolate* isolate, const std::vector<std::string>& requested_locales) { UErrorCode status = U_ZERO_ERROR; std::vector<icu::Locale> locales; - for (std::string locale_str : requested_locales) { + for (const std::string& locale_str : requested_locales) { icu::Locale locale = icu::Locale::forLanguageTag(locale_str, status); if (U_SUCCESS(status)) { locales.push_back(locale); @@ -2168,8 +2179,7 @@ MaybeDirectHandle<JSArray> CreateArrayFromList( // a. Let status be CreateDataProperty(array, ! ToString(n), e). const std::string& part = elements[i]; DirectHandle<String> value = - factory->NewStringFromUtf8(base::CStrVector(part.c_str())) - .ToHandleChecked(); + factory->NewStringFromUtf8(part).ToHandleChecked(); MAYBE_RETURN(JSObject::AddDataElement(isolate, array, i, value, attr), {}); } // 5. Return array. diff --git a/deps/v8/src/objects/intl-objects.h b/deps/v8/src/objects/intl-objects.h index 6ea9427d1f49..7991a5cd8a07 100644 --- a/deps/v8/src/objects/intl-objects.h +++ b/deps/v8/src/objects/intl-objects.h @@ -10,6 +10,7 @@ #include <optional> #include <set> #include <string> +#include <string_view> #include "include/v8-internal.h" #include "src/base/compiler-specific.h" @@ -33,7 +34,6 @@ class ListFormatter; class RelativeDateTimeFormatter; class SimpleDateFormat; class DateIntervalFormat; -class PluralRules; class Collator; class FormattedValue; class StringEnumeration; @@ -55,7 +55,6 @@ namespace v8::internal { V(icu::RelativeDateTimeFormatter, kIcuRelativeDateTimeFormatterTag) \ V(icu::ListFormatter, kIcuListFormatterTag) \ V(icu::Collator, kIcuCollatorTag) \ - V(icu::PluralRules, kIcuPluralRulesTag) \ V(icu::number::LocalizedNumberFormatter, kIcuLocalizedNumberFormatterTag) ICU_EXTERNAL_POINTER_TAG_LIST(ASSIGN_EXTERNAL_POINTER_TAG_FOR_MANAGED) #undef ICU_EXTERNAL_POINTER_TAG_LIST @@ -198,6 +197,10 @@ class Intl { Isolate* isolate, DirectHandle<Object> key); // For locale sensitive functions + static constexpr std::string_view kCaseMappingSpecialLocales[] = {"az", "el", + "lt", "tr"}; + static bool LocaleRequiresSpecialCaseMapping(std::string_view locale); + V8_WARN_UNUSED_RESULT static MaybeDirectHandle<String> StringLocaleConvertCase(Isolate* isolate, DirectHandle<String> s, bool is_upper, DirectHandle<Object> locales); diff --git a/deps/v8/src/objects/js-array-buffer-inl.h b/deps/v8/src/objects/js-array-buffer-inl.h index ca6ca483ba95..63e47dc6458b 100644 --- a/deps/v8/src/objects/js-array-buffer-inl.h +++ b/deps/v8/src/objects/js-array-buffer-inl.h @@ -26,12 +26,14 @@ namespace internal { // JSArrayBuffer. // -Tagged<MaybeObject> JSArrayBuffer::views_or_detach_key() const { +Tagged<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>> +JSArrayBuffer::views_or_detach_key() const { return views_or_detach_key_.load(); } -void JSArrayBuffer::set_views_or_detach_key(Tagged<MaybeObject> value, - WriteBarrierMode mode) { +void JSArrayBuffer::set_views_or_detach_key( + Tagged<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>> value, + WriteBarrierMode mode) { views_or_detach_key_.store(this, value, mode); } @@ -94,7 +96,6 @@ size_t JSArrayBuffer::GetByteLength() const { if (ext == nullptr) { return 0; } - ext->InitializationBarrier(); SBXCHECK(ext->is_shared() && ext->is_resizable_by_js()); return ext->backing_store()->byte_length(std::memory_order_seq_cst); } @@ -129,7 +130,7 @@ ArrayBufferExtension* JSArrayBuffer::extension() const { return reinterpret_cast<ArrayBufferExtension*>( isolate->external_pointer_table().Get(handle, kArrayBufferExtensionTag)); #else - return base::AsAtomicPointer::Relaxed_Load(extension_location()); + return base::AsAtomicPointer::Acquire_Load(extension_location()); #endif // V8_COMPRESS_POINTERS } @@ -154,7 +155,7 @@ void JSArrayBuffer::set_extension(ArrayBufferExtension* extension) { table.Set(current_handle, value, tag); } #else - base::AsAtomicPointer::Relaxed_Store(extension_location(), extension); + base::AsAtomicPointer::Release_Store(extension_location(), extension); #endif // V8_COMPRESS_POINTERS WriteBarrier::ForArrayBufferExtension(this, extension); } @@ -204,7 +205,8 @@ void JSArrayBuffer::set_views(Tagged<MaybeObject> value, WriteBarrierMode mode) { DCHECK(!has_detach_key()); DCHECK(value.IsWeak() || value == kNoView || value == kManyViews); - set_views_or_detach_key(value, mode); + set_views_or_detach_key( + Cast<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>>(value), mode); } Tagged<Cell> JSArrayBuffer::detach_key() const { @@ -241,35 +243,33 @@ inline void JSArrayBuffer::AttachView(Tagged<JSArrayBufferView> new_view) { set_views(kManyViews); } -void JSArrayBuffer::set_bit_field(uint32_t bits) { - base::AsAtomic32::Relaxed_Store(&bit_field_, bits); +void JSArrayBuffer::set_bit_field(Bits bits) { + bit_field_.store(bits, std::memory_order_relaxed); } -uint32_t JSArrayBuffer::bit_field() const { - return base::AsAtomic32::Relaxed_Load(&bit_field_); +JSArrayBuffer::Bits JSArrayBuffer::bit_field() const { + return bit_field_.load(std::memory_order_relaxed); } // |bit_field| fields. BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_external, - JSArrayBuffer::IsExternalBit) + JSArrayBuffer::Bits::IsExternalBit) BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, is_detachable, - JSArrayBuffer::IsDetachableBit) + JSArrayBuffer::Bits::IsDetachableBit) BIT_FIELD_ACCESSORS(JSArrayBuffer, bit_field, was_detached, - JSArrayBuffer::WasDetachedBit) -SharedFlag JSArrayBuffer::is_shared() const { - return IsSharedBit::decode(bit_field()); -} + JSArrayBuffer::Bits::WasDetachedBit) +SharedFlag JSArrayBuffer::is_shared() const { return bit_field().is_shared(); } void JSArrayBuffer::set_is_shared(SharedFlag value) { - set_bit_field(IsSharedBit::update(bit_field(), value)); + set_bit_field(bit_field().with_is_shared(value)); } ResizableFlag JSArrayBuffer::is_resizable_by_js() const { - return IsResizableByJsBit::decode(bit_field()); + return bit_field().is_resizable_by_js(); } void JSArrayBuffer::set_is_resizable_by_js(ResizableFlag value) { - set_bit_field(IsResizableByJsBit::update(bit_field(), value)); + set_bit_field(bit_field().with_is_resizable_by_js(value)); if (ArrayBufferExtension* extension = this->extension()) { extension->set_is_resizable_by_js(value); @@ -277,22 +277,20 @@ void JSArrayBuffer::set_is_resizable_by_js(ResizableFlag value) { } bool JSArrayBuffer::is_immutable() const { - return IsImmutableBit::decode(bit_field()).value(); + return bit_field().is_immutable().value(); } void JSArrayBuffer::set_is_immutable(ImmutableFlag value) { - set_bit_field(IsImmutableBit::update(bit_field(), value)); + set_bit_field(bit_field().with_is_immutable(value)); } bool JSArrayBuffer::was_detached(AcquireLoadTag) const { - uint32_t bits = base::AsAtomic32::Acquire_Load(&bit_field_); - return WasDetachedBit::decode(bits); + return bit_field_.load(std::memory_order_acquire).was_detached(); } void JSArrayBuffer::set_was_detached(bool value, ReleaseStoreTag) { - uint32_t bits = bit_field(); - bits = WasDetachedBit::update(bits, value); - base::AsAtomic32::Release_Store(&bit_field_, bits); + bit_field_.store(bit_field().with_was_detached(value), + std::memory_order_release); } bool JSArrayBuffer::IsEmpty() const { @@ -315,12 +313,12 @@ void JSArrayBufferView::set_buffer(Tagged<JSArrayBuffer> value, buffer_.store(this, value, mode); } -uint32_t JSArrayBufferView::bit_field() const { - return base::AsAtomic32::Relaxed_Load(&bit_field_); +JSArrayBufferView::Bits JSArrayBufferView::bit_field() const { + return bit_field_.load(std::memory_order_relaxed); } -void JSArrayBufferView::set_bit_field(uint32_t value) { - base::AsAtomic32::Relaxed_Store(&bit_field_, value); +void JSArrayBufferView::set_bit_field(Bits value) { + bit_field_.store(value, std::memory_order_relaxed); } size_t JSArrayBufferView::byte_offset() const { @@ -360,9 +358,9 @@ bool JSArrayBufferView::IsDetachedOrOutOfBounds() const { } BIT_FIELD_ACCESSORS(JSArrayBufferView, bit_field, is_length_tracking, - JSArrayBufferView::IsLengthTrackingBit) + JSArrayBufferView::Bits::IsLengthTrackingBit) BIT_FIELD_ACCESSORS(JSArrayBufferView, bit_field, is_backed_by_rab, - JSArrayBufferView::IsBackedByRabBit) + JSArrayBufferView::Bits::IsBackedByRabBit) bool JSArrayBufferView::IsVariableLength() const { return is_length_tracking() || is_backed_by_rab(); @@ -397,21 +395,22 @@ void JSTypedArray::set_length(size_t value) { WriteBoundedSizeField(offsetof(JSTypedArray, raw_length_), value); } -Tagged<Object> JSTypedArray::base_pointer() const { +Tagged<UnionOf<ByteArray, Smi>> JSTypedArray::base_pointer() const { return base_pointer_.load(); } -Tagged<Object> JSTypedArray::base_pointer(AcquireLoadTag) const { +Tagged<UnionOf<ByteArray, Smi>> JSTypedArray::base_pointer( + AcquireLoadTag) const { return base_pointer_.Acquire_Load(); } -void JSTypedArray::set_base_pointer(Tagged<Object> value, +void JSTypedArray::set_base_pointer(Tagged<UnionOf<ByteArray, Smi>> value, WriteBarrierMode mode) { base_pointer_.store(this, value, mode); } -void JSTypedArray::set_base_pointer(Tagged<Object> value, ReleaseStoreTag, - WriteBarrierMode mode) { +void JSTypedArray::set_base_pointer(Tagged<UnionOf<ByteArray, Smi>> value, + ReleaseStoreTag, WriteBarrierMode mode) { base_pointer_.Release_Store(this, value, mode); } diff --git a/deps/v8/src/objects/js-array-buffer.cc b/deps/v8/src/objects/js-array-buffer.cc index 1007cf568869..394947aa5615 100644 --- a/deps/v8/src/objects/js-array-buffer.cc +++ b/deps/v8/src/objects/js-array-buffer.cc @@ -61,7 +61,8 @@ void JSArrayBuffer::Setup(SharedFlag shared, ResizableFlag resizable, }; clear_padding(); init_extension(); - set_views_or_detach_key(views); + set_views_or_detach_key( + Cast<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>>(views)); set_bit_field(0); set_is_shared(shared); set_is_resizable_by_js(resizable); @@ -71,6 +72,7 @@ void JSArrayBuffer::Setup(SharedFlag shared, ResizableFlag resizable, SetEmbedderField(i, Smi::zero()); } if (!backing_store) { + DCHECK(!resizable); set_backing_store(isolate, EmptyBackingStoreBuffer()); set_byte_length(0); set_max_byte_length(0); @@ -251,7 +253,7 @@ void JSArrayBuffer::DetachInternal(DirectHandle<JSArrayBuffer> array_buffer, HandleScope scope(isolate); isolate->array_buffer_detach_callback()( reinterpret_cast<v8::Isolate*>(isolate), - Utils::ToLocal(array_buffer)); + Utils::ToLocalUnshared(array_buffer)); } } } diff --git a/deps/v8/src/objects/js-array-buffer.h b/deps/v8/src/objects/js-array-buffer.h index a63e91d3b989..60c22c3b4d54 100644 --- a/deps/v8/src/objects/js-array-buffer.h +++ b/deps/v8/src/objects/js-array-buffer.h @@ -10,6 +10,7 @@ #include "src/base/bit-field.h" #include "src/handles/maybe-handles.h" #include "src/objects/backing-store.h" +#include "src/objects/bit-field-group.h" #include "src/objects/js-function.h" #include "src/objects/js-objects.h" #include "src/sandbox/check.h" @@ -63,31 +64,41 @@ V8_OBJECT class JSArrayBuffer : public JSAPIObjectWithEmbedderSlots { Isolate* isolate, const DisallowGarbageCollection& disallow_gc V8_LIFETIME_BOUND); - // [bit_field]: boolean flags - inline uint32_t bit_field() const; - inline void set_bit_field(uint32_t value); - // Clear uninitialized padding space. This ensures that the snapshot content // is deterministic. Depending on the V8 build mode there could be no padding. V8_INLINE void clear_padding(); // Bit positions for [bit_field]. - using IsExternalBit = base::BitField<bool, 0, 1, uint32_t>; - using IsDetachableBit = IsExternalBit::Next<bool, 1>; - using WasDetachedBit = IsDetachableBit::Next<bool, 1>; - using IsSharedBit = WasDetachedBit::Next<SharedFlag, 1>; - using IsResizableByJsBit = IsSharedBit::Next<ResizableFlag, 1>; - using IsImmutableBit = IsResizableByJsBit::Next<ImmutableFlag, 1>; + struct Bits : BitFieldGroup<Bits, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using IsExternalBit = First<bool, 1>; + using IsDetachableBit = IsExternalBit::Next<bool, 1>; + using WasDetachedBit = IsDetachableBit::Next<bool, 1>; + using IsSharedBit = WasDetachedBit::Next<SharedFlag, 1>; + using IsResizableByJsBit = IsSharedBit::Next<ResizableFlag, 1>; + using IsImmutableBit = IsResizableByJsBit::Next<ImmutableFlag, 1>; + + BIT_FIELD_GROUP_ACCESSORS(is_external, IsExternalBit) + BIT_FIELD_GROUP_ACCESSORS(is_detachable, IsDetachableBit) + BIT_FIELD_GROUP_ACCESSORS(was_detached, WasDetachedBit) + BIT_FIELD_GROUP_ACCESSORS(is_shared, IsSharedBit) + BIT_FIELD_GROUP_ACCESSORS(is_resizable_by_js, IsResizableByJsBit) + BIT_FIELD_GROUP_ACCESSORS(is_immutable, IsImmutableBit) + }; + + inline Bits bit_field() const; + inline void set_bit_field(Bits value); + enum Flag : uint32_t { kNone = 0, - kIsExternal = IsExternalBit::kMask, - kIsDetachable = IsDetachableBit::kMask, - kWasDetached = WasDetachedBit::kMask, - kIsShared = IsSharedBit::kMask, - kIsResizableByJs = IsResizableByJsBit::kMask, - kIsImmutable = IsImmutableBit::kMask, + kIsExternal = Bits::IsExternalBit::kMask, + kIsDetachable = Bits::IsDetachableBit::kMask, + kWasDetached = Bits::WasDetachedBit::kMask, + kIsShared = Bits::IsSharedBit::kMask, + kIsResizableByJs = Bits::IsResizableByJsBit::kMask, + kIsImmutable = Bits::IsImmutableBit::kMask, }; - using Flags = base::Flags<Flag>; static constexpr int kFlagCount = 6; // [is_external]: true indicates that the embedder is in charge of freeing the @@ -126,9 +137,11 @@ V8_OBJECT class JSArrayBuffer : public JSAPIObjectWithEmbedderSlots { // An ArrayBuffer with a size greater than zero is never empty. inline bool IsEmpty() const; - inline Tagged<MaybeObject> views_or_detach_key() const; + inline Tagged<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>> + views_or_detach_key() const; inline void set_views_or_detach_key( - Tagged<MaybeObject> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + Tagged<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<MaybeObject> views() const; inline void set_views(Tagged<MaybeObject> value, @@ -198,10 +211,10 @@ V8_OBJECT class JSArrayBuffer : public JSAPIObjectWithEmbedderSlots { static uint32_t NotValidMask(TypedArrayAccessMode mode) { switch (mode) { case TypedArrayAccessMode::kRead: - return JSArrayBuffer::WasDetachedBit::kMask; + return JSArrayBuffer::Bits::WasDetachedBit::kMask; case TypedArrayAccessMode::kWrite: - return JSArrayBuffer::WasDetachedBit::kMask | - JSArrayBuffer::IsImmutableBit::kMask; + return JSArrayBuffer::Bits::WasDetachedBit::kMask | + JSArrayBuffer::Bits::IsImmutableBit::kMask; } UNREACHABLE(); } @@ -238,12 +251,13 @@ V8_OBJECT class JSArrayBuffer : public JSAPIObjectWithEmbedderSlots { #endif // V8_COMPRESS_POINTERS public: - TaggedMember<MaybeObject> views_or_detach_key_; + TaggedMember<UnionOf<Cell, Smi, Weak<JSArrayBufferView>>> + views_or_detach_key_; UnalignedValueMember<uintptr_t> raw_byte_length_; UnalignedValueMember<uintptr_t> raw_max_byte_length_; UnalignedValueMember<Address> backing_store_; ExternalPointerMember<kArrayBufferExtensionTag> extension_; - uint32_t bit_field_; + std::atomic<Bits> bit_field_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif @@ -294,18 +308,7 @@ class ArrayBufferExtension final backing_store_->PerIsolateAccountingLength())) | AgeField::encode(static_cast<uint8_t>(age))), is_shared_(is_shared), - is_resizable_by_js_(is_resizable_by_js) { - initialized_for_gc_.store(true, std::memory_order_release); - } - - // Barrier used for publishing the object. This barrier must be used whenever - // the extension is accessed off the main thread. - // - // The constructor sets a value with release that is read with acquire in this - // varrier. - void InitializationBarrier() const { - std::ignore = initialized_for_gc_.load(std::memory_order_acquire); - } + is_resizable_by_js_(is_resizable_by_js) {} void Mark() { marked_.store(true, std::memory_order_relaxed); } void Unmark() { marked_.store(false, std::memory_order_relaxed); } @@ -406,7 +409,6 @@ class ArrayBufferExtension final std::shared_ptr<BackingStore> backing_store_; ArrayBufferExtension* next_ = nullptr; std::atomic<uint64_t> accounting_state_; - std::atomic<bool> initialized_for_gc_{false}; std::atomic<bool> marked_{false}; std::atomic<GcState> young_gc_state_{GcState::Dead}; @@ -435,21 +437,27 @@ V8_OBJECT class JSArrayBufferView : public JSAPIObjectWithEmbedderSlots { inline size_t byte_length() const; inline void set_byte_length(size_t value); - // [bit_field]: boolean flags - inline uint32_t bit_field() const; - inline void set_bit_field(uint32_t value); - DECL_VERIFIER(JSArrayBufferView) // Bit positions for [bit_field]. - using IsLengthTrackingBit = base::BitField<bool, 0, 1, uint32_t>; - using IsBackedByRabBit = IsLengthTrackingBit::Next<bool, 1>; + struct Bits : BitFieldGroup<Bits, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using IsLengthTrackingBit = First<bool, 1>; + using IsBackedByRabBit = IsLengthTrackingBit::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(is_length_tracking, IsLengthTrackingBit) + BIT_FIELD_GROUP_ACCESSORS(is_backed_by_rab, IsBackedByRabBit) + }; + + inline Bits bit_field() const; + inline void set_bit_field(Bits value); + enum Flag : uint32_t { kNone = 0, - kIsLengthTracking = IsLengthTrackingBit::kMask, - kIsBackedByRab = IsBackedByRabBit::kMask, + kIsLengthTracking = Bits::IsLengthTrackingBit::kMask, + kIsBackedByRab = Bits::IsBackedByRabBit::kMask, }; - using Flags = base::Flags<Flag>; static constexpr int kFlagCount = 2; inline bool WasDetached() const; @@ -465,7 +473,7 @@ V8_OBJECT class JSArrayBufferView : public JSAPIObjectWithEmbedderSlots { public: TaggedMember<JSArrayBuffer> buffer_; - uint32_t bit_field_; + std::atomic<Bits> bit_field_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif @@ -495,8 +503,8 @@ V8_OBJECT class JSTypedArray : public JSArrayBufferView { // [base_pointer]: the ByteArray containing the backing store, if it is // on-heap, or Smi::zero() if it is off-heap. - inline Tagged<Object> base_pointer() const; - inline Tagged<Object> base_pointer(AcquireLoadTag) const; + inline Tagged<UnionOf<ByteArray, Smi>> base_pointer() const; + inline Tagged<UnionOf<ByteArray, Smi>> base_pointer(AcquireLoadTag) const; // ES6 9.4.5.3 V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty( @@ -587,9 +595,10 @@ V8_OBJECT class JSTypedArray : public JSArrayBufferView { inline Address external_pointer() const; inline Address external_pointer(PtrComprCageBase cage_base) const; - inline void set_base_pointer(Tagged<Object> value, + inline void set_base_pointer(Tagged<UnionOf<ByteArray, Smi>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline void set_base_pointer(Tagged<Object> value, ReleaseStoreTag, + inline void set_base_pointer(Tagged<UnionOf<ByteArray, Smi>> value, + ReleaseStoreTag, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline void set_external_pointer(Isolate* isolate, Address value); @@ -597,7 +606,7 @@ V8_OBJECT class JSTypedArray : public JSArrayBufferView { public: UnalignedValueMember<uintptr_t> raw_length_; UnalignedValueMember<Address> external_pointer_; - TaggedMember<Object> base_pointer_; + TaggedMember<UnionOf<ByteArray, Smi>> base_pointer_; } V8_OBJECT_END; inline constexpr int JSTypedArray::kHeaderSize = sizeof(JSTypedArray); @@ -615,6 +624,10 @@ V8_OBJECT class JSDetachedTypedArray : public JSTypedArray { DECL_VERIFIER(JSDetachedTypedArray) } V8_OBJECT_END; +V8_OBJECT class Uint8JSTypedArray : public JSTypedArray { + V8_IT_NO_AUTO_CHECKER; +} V8_OBJECT_END; + V8_OBJECT class JSDataViewOrRabGsabDataView : public JSArrayBufferView { V8_IT_ABSTRACT; diff --git a/deps/v8/src/objects/js-array-buffer.tq b/deps/v8/src/objects/js-array-buffer.tq index 742f7e2b28cf..3102d9ecf89f 100644 --- a/deps/v8/src/objects/js-array-buffer.tq +++ b/deps/v8/src/objects/js-array-buffer.tq @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@cppScope('JSArrayBuffer') -bitfield struct JSArrayBufferFlags extends uint32 { +@cppScope('JSArrayBuffer::Bits') +bitfield struct JSArrayBufferBits extends uint32 { is_external: bool: 1 bit; is_detachable: bool: 1 bit; was_detached: bool: 1 bit; @@ -25,7 +25,7 @@ extern class JSArrayBuffer extends JSAPIObjectWithEmbedderSlots { // A SandboxedPtr if the sandbox is enabled backing_store: RawPtr; extension: ExternalPointer; - bit_field: JSArrayBufferFlags; + bit_field: JSArrayBufferBits; // Pads header size to be a multiple of kTaggedSize on 64-bit targets. @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; } @@ -64,8 +64,8 @@ macro IsImmutableArrayBuffer(buffer: JSArrayBuffer): bool { // 2) Non-length tracking backed by RAB (can go oob once constructed) // 3) Length-tracking backed by RAB (JSArrayBuffer stores the length) // 4) Length-tracking backed by GSAB (BackingStore stores the length) -@cppScope('JSArrayBufferView') -bitfield struct JSArrayBufferViewFlags extends uint32 { +@cppScope('JSArrayBufferView::Bits') +bitfield struct JSArrayBufferViewBits extends uint32 { is_length_tracking: bool: 1 bit; is_backed_by_rab: bool: 1 bit; } @@ -74,7 +74,7 @@ bitfield struct JSArrayBufferViewFlags extends uint32 { @cppObjectLayoutDefinition extern class JSArrayBufferView extends JSAPIObjectWithEmbedderSlots { buffer: JSArrayBuffer; - bit_field: JSArrayBufferViewFlags; // 32bit + bit_field: JSArrayBufferViewBits; // 32bit @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; // A BoundedSize if the sandbox is enabled raw_byte_offset: uintptr; diff --git a/deps/v8/src/objects/js-array.h b/deps/v8/src/objects/js-array.h index 5a9ed5b625f0..e20c784ecc53 100644 --- a/deps/v8/src/objects/js-array.h +++ b/deps/v8/src/objects/js-array.h @@ -194,7 +194,7 @@ V8_OBJECT class JSArrayIterator : public JSObject { TaggedMember<JSReceiver> iterated_object_; TaggedMember<Number> next_index_; // SmiTagged<IterationKind>. - TaggedMember<Smi> kind_; + TaggedMember<Smi> kind_ V8_TQ_TYPE(SmiTagged<IterationKind>); } V8_OBJECT_END; // Helper class for JSArrays that are template literal objects diff --git a/deps/v8/src/objects/js-atomics-synchronization-inl.h b/deps/v8/src/objects/js-atomics-synchronization-inl.h deleted file mode 100644 index 9b1f508781a4..000000000000 --- a/deps/v8/src/objects/js-atomics-synchronization-inl.h +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2022 the V8 project 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 V8_OBJECTS_JS_ATOMICS_SYNCHRONIZATION_INL_H_ -#define V8_OBJECTS_JS_ATOMICS_SYNCHRONIZATION_INL_H_ - -#include "src/objects/js-atomics-synchronization.h" -// Include the non-inl header before the rest of the headers. - -#include "src/common/assert-scope.h" -#include "src/common/globals.h" -#include "src/heap/heap-write-barrier-inl.h" -#include "src/objects/js-struct.h" -#include "src/objects/objects-inl.h" - -// Has to be the last include (doesn't have include guards): -#include "src/objects/object-macros.h" - -namespace v8 { -namespace internal { - -uint32_t JSSynchronizationPrimitive::state() const { - return state_.load(std::memory_order_relaxed); -} - -void JSSynchronizationPrimitive::set_state(uint32_t value) { - state_.store(value, std::memory_order_relaxed); -} - -int32_t JSAtomicsMutex::owner_thread_id() const { - return owner_thread_id_.load(std::memory_order_relaxed); -} - -void JSAtomicsMutex::set_owner_thread_id(int32_t value) { - owner_thread_id_.store(value, std::memory_order_relaxed); -} - -std::atomic<JSSynchronizationPrimitive::StateT>* -JSSynchronizationPrimitive::AtomicStatePtr() { - DCHECK(IsAligned(reinterpret_cast<uintptr_t>(&state_), sizeof(StateT))); - return &state_; -} - -void JSSynchronizationPrimitive::SetNullWaiterQueueHead() { -#if V8_COMPRESS_POINTERS - base::AsAtomic32::Relaxed_Store(waiter_queue_head_handle_location(), - kNullExternalPointerHandle); -#else - base::AsAtomicPointer::Relaxed_Store(waiter_queue_head_location(), nullptr); -#endif // V8_COMPRESS_POINTERS -} - -#if V8_COMPRESS_POINTERS -ExternalPointerHandle* -JSSynchronizationPrimitive::waiter_queue_head_handle_location() const { - return reinterpret_cast<ExternalPointerHandle*>( - waiter_queue_head_.storage_address()); -} -#else -WaiterQueueNode** JSSynchronizationPrimitive::waiter_queue_head_location() - const { - return reinterpret_cast<WaiterQueueNode**>( - waiter_queue_head_.storage_address()); -} -#endif // V8_COMPRESS_POINTERS - -WaiterQueueNode* JSSynchronizationPrimitive::DestructivelyGetWaiterQueueHead( - Isolate* requester) { - if (V8_UNLIKELY(DEBUG_BOOL)) { - StateT state = AtomicStatePtr()->load(std::memory_order_relaxed); - DCHECK(IsWaiterQueueLockedField::decode(state)); - USE(state); - } -#if V8_COMPRESS_POINTERS - ExternalPointerHandle handle = - base::AsAtomic32::Relaxed_Load(waiter_queue_head_handle_location()); - if (handle == kNullExternalPointerHandle) return nullptr; - // Clear external pointer after decoding as a safeguard, no other thread - // should be trying to access though the same non-null handle. - WaiterQueueNode* waiter_head = reinterpret_cast<WaiterQueueNode*>( - requester->shared_external_pointer_table().Exchange(handle, kNullAddress, - kWaiterQueueNodeTag)); - return waiter_head; -#else - return base::AsAtomicPointer::Relaxed_Load(waiter_queue_head_location()); -#endif // V8_COMPRESS_POINTERS -} - -JSSynchronizationPrimitive::StateT -JSSynchronizationPrimitive::SetWaiterQueueHead(Isolate* requester, - WaiterQueueNode* waiter_head, - StateT new_state) { - if (V8_UNLIKELY(DEBUG_BOOL)) { - StateT state = AtomicStatePtr()->load(std::memory_order_relaxed); - DCHECK(IsWaiterQueueLockedField::decode(state)); - USE(state); - } -#if V8_COMPRESS_POINTERS - ExternalPointerHandle handle = - base::AsAtomic32::Relaxed_Load(waiter_queue_head_handle_location()); - if (waiter_head) { - new_state = HasWaitersField::update(new_state, true); - ExternalPointerTable& table = requester->shared_external_pointer_table(); - if (handle == kNullExternalPointerHandle) { - handle = table.AllocateAndInitializeEntry( - requester->shared_external_pointer_space(), - reinterpret_cast<Address>(waiter_head), kWaiterQueueNodeTag); - // Use a Release_Store to ensure that the store of the pointer into the - // table is not reordered after the store of the handle. Otherwise, other - // threads may access an uninitialized table entry and crash. - base::AsAtomic32::Release_Store(waiter_queue_head_handle_location(), - handle); - WriteBarrier::ForExternalPointer( - this, - RawExternalPointerField( - offsetof(JSSynchronizationPrimitive, waiter_queue_head_), - kWaiterQueueNodeTag), - handle); - return new_state; - } - if (DEBUG_BOOL) { - Address old = requester->shared_external_pointer_table().Exchange( - handle, reinterpret_cast<Address>(waiter_head), kWaiterQueueNodeTag); - DCHECK_EQ(kNullAddress, old); - USE(old); - } else { - requester->shared_external_pointer_table().Set( - handle, reinterpret_cast<Address>(waiter_head), kWaiterQueueNodeTag); - } - } else { - new_state = HasWaitersField::update(new_state, false); - if (handle) { - requester->shared_external_pointer_table().Set(handle, kNullAddress, - kWaiterQueueNodeTag); - } - } -#else - new_state = HasWaitersField::update(new_state, waiter_head); - base::AsAtomicPointer::Relaxed_Store(waiter_queue_head_location(), - waiter_head); -#endif // V8_COMPRESS_POINTERS - return new_state; -} - -JSAtomicsMutex::LockGuardBase::LockGuardBase(Isolate* isolate, - DirectHandle<JSAtomicsMutex> mutex, - bool locked) - : isolate_(isolate), mutex_(mutex), locked_(locked) {} - -JSAtomicsMutex::LockGuardBase::~LockGuardBase() { - if (locked_) mutex_->Unlock(isolate_); -} - -JSAtomicsMutex::LockGuard::LockGuard(Isolate* isolate, - DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout) - : LockGuardBase(isolate, mutex, - JSAtomicsMutex::Lock(isolate, mutex, timeout)) {} - -JSAtomicsMutex::TryLockGuard::TryLockGuard(Isolate* isolate, - DirectHandle<JSAtomicsMutex> mutex) - : LockGuardBase(isolate, mutex, mutex->TryLock()) {} - -// static -template <typename LockSlowPathWrapper, typename> -bool JSAtomicsMutex::LockImpl(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout, - LockSlowPathWrapper slow_path_wrapper) { - DisallowGarbageCollection no_gc; - // First try to lock an uncontended mutex, which should be the common case. If - // this fails, then go to the slow path to possibly put the current thread to - // sleep. - // - // The fast path is done using a weak CAS which may fail spuriously on - // architectures with load-link/store-conditional instructions. - std::atomic<StateT>* state = mutex->AtomicStatePtr(); - StateT expected = kUnlockedUncontended; - bool locked; - if (V8_LIKELY(state->compare_exchange_weak(expected, kLockedUncontended, - std::memory_order_acquire, - std::memory_order_relaxed))) { - locked = true; - } else { - locked = slow_path_wrapper(state); - } - if (V8_LIKELY(locked)) { - mutex->SetCurrentThreadAsOwner(); - } - return locked; -} - -// static -bool JSAtomicsMutex::Lock(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout) { - return LockImpl(requester, mutex, timeout, [=](std::atomic<StateT>* state) { - return LockSlowPath(requester, mutex, state, timeout); - }); -} - -bool JSAtomicsMutex::TryLock() { - DisallowGarbageCollection no_gc; - StateT expected = kUnlockedUncontended; - if (V8_LIKELY(AtomicStatePtr()->compare_exchange_strong( - expected, kLockedUncontended, std::memory_order_acquire, - std::memory_order_relaxed))) { - SetCurrentThreadAsOwner(); - return true; - } - return false; -} - -void JSAtomicsMutex::Unlock(Isolate* requester) { - DisallowGarbageCollection no_gc; - // First try to unlock an uncontended mutex, which should be the common - // case. If this fails, then go to the slow path to wake a waiting thread. - // - // In contrast to Lock, the fast path is done using a strong CAS which does - // not fail spuriously. This simplifies the slow path by guaranteeing that - // there is at least one waiter to be notified. - DCHECK(IsCurrentThreadOwner()); - ClearOwnerThread(); - std::atomic<StateT>* state = AtomicStatePtr(); - StateT expected = kLockedUncontended; - if (V8_LIKELY(state->compare_exchange_strong(expected, kUnlockedUncontended, - std::memory_order_release, - std::memory_order_relaxed))) { - return; - } - UnlockSlowPath(requester, state); -} - -bool JSAtomicsMutex::IsHeld() { - return IsLockedField::decode( - AtomicStatePtr()->load(std::memory_order_relaxed)); -} - -bool JSAtomicsMutex::IsCurrentThreadOwner() { - bool result = AtomicOwnerThreadIdPtr()->load(std::memory_order_relaxed) == - ThreadId::Current().ToInteger(); - DCHECK_IMPLIES(result, IsHeld()); - return result; -} - -void JSAtomicsMutex::SetCurrentThreadAsOwner() { - AtomicOwnerThreadIdPtr()->store(ThreadId::Current().ToInteger(), - std::memory_order_relaxed); -} - -void JSAtomicsMutex::ClearOwnerThread() { - AtomicOwnerThreadIdPtr()->store(ThreadId::Invalid().ToInteger(), - std::memory_order_relaxed); -} - -std::atomic<int32_t>* JSAtomicsMutex::AtomicOwnerThreadIdPtr() { - return &owner_thread_id_; -} - -} // namespace internal -} // namespace v8 - -#include "src/objects/object-macros-undef.h" - -#endif // V8_OBJECTS_JS_ATOMICS_SYNCHRONIZATION_INL_H_ diff --git a/deps/v8/src/objects/js-atomics-synchronization.cc b/deps/v8/src/objects/js-atomics-synchronization.cc deleted file mode 100644 index c4288b9c37e9..000000000000 --- a/deps/v8/src/objects/js-atomics-synchronization.cc +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright 2022 the V8 project 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 "src/objects/js-atomics-synchronization.h" - -#include "src/base/macros.h" -#include "src/base/platform/yield-processor.h" -#include "src/base/sanitizer/tsan.h" -#include "src/execution/isolate-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" -#include "src/objects/js-promise-inl.h" -#include "src/objects/waiter-queue-node.h" -#include "src/sandbox/external-pointer-inl.h" - -namespace v8 { -namespace internal { - -namespace detail { -class WaiterQueueNode; -} - -namespace { -} // namespace - -namespace detail { - -// The waiter queue lock guard provides a RAII-style mechanism for locking the -// waiter queue. It is a non copyable and non movable object and a new state -// must be set before destroying the guard. -class V8_NODISCARD WaiterQueueLockGuard final { - using StateT = JSSynchronizationPrimitive::StateT; - - public: - // Spinlock to acquire the IsWaiterQueueLockedField bit. current_state is - // updated to the last value of the state before the waiter queue lock was - // acquired. - explicit WaiterQueueLockGuard(std::atomic<StateT>* state, - StateT& current_state) - : state_(state), new_state_(kInvalidState) { - while (!JSSynchronizationPrimitive::TryLockWaiterQueueExplicit( - state, current_state)) { - YIELD_PROCESSOR; - } - } - - // Constructor for creating a wrapper around a state whose waiter queue - // is already locked and owned by this thread. - explicit WaiterQueueLockGuard(std::atomic<StateT>* state, bool is_locked) - : state_(state), new_state_(kInvalidState) { - CHECK(is_locked); - DCHECK(JSSynchronizationPrimitive::IsWaiterQueueLockedField::decode( - state->load())); - } - - WaiterQueueLockGuard(const WaiterQueueLockGuard&) = delete; - WaiterQueueLockGuard() = delete; - - ~WaiterQueueLockGuard() { - DCHECK_NOT_NULL(state_); - DCHECK_NE(new_state_, kInvalidState); - DCHECK(JSSynchronizationPrimitive::IsWaiterQueueLockedField::decode( - state_->load())); - new_state_ = JSSynchronizationPrimitive::IsWaiterQueueLockedField::update( - new_state_, false); - TSAN_RELEASE(state_); - state_->store(new_state_, std::memory_order_release); - } - - void set_new_state(StateT new_state) { new_state_ = new_state; } - - static std::optional<WaiterQueueLockGuard> - NewAlreadyLockedWaiterQueueLockGuard(std::atomic<StateT>* state) { - return std::optional<WaiterQueueLockGuard>(std::in_place, state, true); - } - - private: - static constexpr StateT kInvalidState = - ~JSSynchronizationPrimitive::kEmptyState; - std::atomic<StateT>* state_; - StateT new_state_; -}; - -} // namespace detail - -// static -bool JSSynchronizationPrimitive::TryLockWaiterQueueExplicit( - std::atomic<StateT>* state, StateT& expected) { - // Try to acquire the queue lock. - expected = IsWaiterQueueLockedField::update(expected, false); - bool success = state->compare_exchange_weak( - expected, IsWaiterQueueLockedField::update(expected, true), - std::memory_order_acquire, std::memory_order_relaxed); - if (success) { - TSAN_ACQUIRE(state); - } - return success; -} - -// static -void JSSynchronizationPrimitive::SetWaiterQueueStateOnly( - std::atomic<StateT>* state, StateT new_state) { - // Set the new state changing only the waiter queue bits. - DCHECK_EQ(new_state & ~kWaiterQueueMask, 0); - StateT expected = state->load(std::memory_order_relaxed); - StateT desired; - do { - desired = new_state | (expected & ~kWaiterQueueMask); - TSAN_RELEASE(state); - } while (!state->compare_exchange_weak( - expected, desired, std::memory_order_release, std::memory_order_relaxed)); -} - -Tagged<Object> JSSynchronizationPrimitive::NumWaitersForTesting( - Isolate* requester) { - DisallowGarbageCollection no_gc; - std::atomic<StateT>* state = AtomicStatePtr(); - StateT current_state = state->load(std::memory_order_acquire); - - // There are no waiters. - if (!HasWaitersField::decode(current_state)) return Smi::FromInt(0); - - int num_waiters; - { - // If this is counting the number of waiters on a mutex, the js mutex - // can be taken by another thread without acquiring the queue lock. We - // handle the state manually to release the queue lock without changing the - // "is locked" bit. - while (!TryLockWaiterQueueExplicit(state, current_state)) { - YIELD_PROCESSOR; - } - - if (!HasWaitersField::decode(current_state)) { - // The queue was emptied while waiting for the queue lock. - SetWaiterQueueStateOnly(state, kEmptyState); - return Smi::FromInt(0); - } - - // Get the waiter queue head. - WaiterQueueNode* waiter_head = DestructivelyGetWaiterQueueHead(requester); - DCHECK_NOT_NULL(waiter_head); - num_waiters = WaiterQueueNode::LengthFromHead(waiter_head); - - // Release the queue lock and reinstall the same queue head by creating a - // new state. - DCHECK_EQ(state->load() & kWaiterQueueMask, - IsWaiterQueueLockedField::update(current_state, true) & - kWaiterQueueMask); - StateT new_state = SetWaiterQueueHead(requester, waiter_head, kEmptyState); - new_state = IsWaiterQueueLockedField::update(new_state, false); - SetWaiterQueueStateOnly(state, new_state); - } - - return Smi::FromInt(num_waiters); -} - -// TODO(https://crbug.com/42202493): Consider making and caching a canonical map -// for this result object, like we do for the iterator result object. static -DirectHandle<JSObject> JSAtomicsMutex::CreateResultObject( - Isolate* isolate, DirectHandle<Object> value, bool success) { - DirectHandle<JSObject> result = - isolate->factory()->NewJSObject(isolate->object_function()); - DirectHandle<Object> success_value = isolate->factory()->ToBoolean(success); - JSObject::AddProperty(isolate, result, "value", value, - PropertyAttributes::NONE); - JSObject::AddProperty(isolate, result, "success", success_value, - PropertyAttributes::NONE); - return result; -} - -// static -bool JSAtomicsMutex::TryLockExplicit(std::atomic<StateT>* state, - StateT& expected) { - // Try to lock a possibly contended mutex. - expected = IsLockedField::update(expected, false); - return state->compare_exchange_weak( - expected, IsLockedField::update(expected, true), - std::memory_order_acquire, std::memory_order_relaxed); -} - -bool JSAtomicsMutex::BackoffTryLock(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state) { - // The backoff algorithm is copied from PartitionAlloc's SpinningMutex. - constexpr int kSpinCount = 64; - constexpr int kMaxBackoff = 16; - - int tries = 0; - int backoff = 1; - StateT current_state = state->load(std::memory_order_relaxed); - do { - if (JSAtomicsMutex::TryLockExplicit(state, current_state)) return true; - - for (int yields = 0; yields < backoff; yields++) { - YIELD_PROCESSOR; - tries++; - } - - backoff = std::min(kMaxBackoff, backoff << 1); - } while (tries < kSpinCount); - return false; -} - -bool JSAtomicsMutex::MaybeEnqueueNode(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state, - WaiterQueueNode* this_waiter) { - DCHECK_NOT_NULL(this_waiter); - // Try to acquire the queue lock, which is itself a spinlock. - StateT current_state = state->load(std::memory_order_relaxed); - std::optional<WaiterQueueLockGuard> waiter_queue_lock_guard = - LockWaiterQueueOrJSMutex(state, current_state); - if (!waiter_queue_lock_guard.has_value()) { - // There is no waiter queue lock guard, so the lock was acquired. - DCHECK(IsLockedField::decode(state->load())); - return false; - } - - // With the queue lock held, enqueue the requester onto the waiter queue. - WaiterQueueNode* waiter_head = - mutex->DestructivelyGetWaiterQueueHead(requester); - WaiterQueueNode::Enqueue(&waiter_head, this_waiter); - - // Enqueue a new waiter queue head and release the queue lock. - DCHECK_EQ(state->load(), - IsWaiterQueueLockedField::update(current_state, true)); - StateT new_state = - mutex->SetWaiterQueueHead(requester, waiter_head, current_state); - // The lock is held, just not by us, so don't set the current thread id as - // the owner. - DCHECK(IsLockedField::decode(current_state)); - new_state = IsLockedField::update(new_state, true); - waiter_queue_lock_guard->set_new_state(new_state); - return true; -} - -// static -std::optional<WaiterQueueLockGuard> JSAtomicsMutex::LockWaiterQueueOrJSMutex( - std::atomic<StateT>* state, StateT& current_state) { - for (;;) { - if (IsLockedField::decode(current_state) && - TryLockWaiterQueueExplicit(state, current_state)) { - return WaiterQueueLockGuard::NewAlreadyLockedWaiterQueueLockGuard(state); - } - // Also check for the lock having been released by another thread during - // attempts to acquire the queue lock. - if (TryLockExplicit(state, current_state)) return std::nullopt; - YIELD_PROCESSOR; - } -} - -bool JSAtomicsMutex::LockJSMutexOrDequeueTimedOutWaiter( - Isolate* requester, std::atomic<StateT>* state, - WaiterQueueNode* timed_out_waiter) { - // First acquire the queue lock, which is itself a spinlock. - StateT current_state = state->load(std::memory_order_acquire); - // There are no waiters, but the js mutex lock may be held by another thread. - if (!HasWaitersField::decode(current_state)) return false; - - // The details of updating the state in this function are too complicated - // for the waiter queue lock guard to manage, so handle the state manually. - while (!TryLockWaiterQueueExplicit(state, current_state)) { - YIELD_PROCESSOR; - } - - WaiterQueueNode* waiter_head = DestructivelyGetWaiterQueueHead(requester); - - if (waiter_head == nullptr) { - // The queue is empty but the js mutex lock may be held by another thread, - // release the waiter queue bit without changing the "is locked" bit. - DCHECK(!HasWaitersField::decode(current_state)); - SetWaiterQueueStateOnly(state, kUnlockedUncontended); - return false; - } - - WaiterQueueNode* dequeued_node = WaiterQueueNode::DequeueMatching( - &waiter_head, - [&](WaiterQueueNode* node) { return node == timed_out_waiter; }); - - // Release the queue lock and install the new waiter queue head. - DCHECK_EQ( - state->load() & kWaiterQueueMask, - IsWaiterQueueLockedField::update(current_state, true) & kWaiterQueueMask); - StateT new_state = kUnlockedUncontended; - new_state = SetWaiterQueueHead(requester, waiter_head, new_state); - - if (!dequeued_node) { - // The timed out waiter was not in the queue, so it must have been dequeued - // and notified between the time this thread woke up and the time it - // acquired the queue lock, so there is a risk that the next queue head is - // never notified. Try to take the js mutex lock here, if we succeed, the - // next node will be notified by this thread, otherwise, it will be notified - // by the thread holding the lock now. - - // Since we use strong CAS below, we know that the js mutex lock will be - // held by either this thread or another thread that can't go through the - // unlock fast path because this thread is holding the waiter queue lock. - // Hence, it is safe to always set the "is locked" bit in new_state. - current_state = IsLockedField::update(current_state, false); - new_state = IsLockedField::update(new_state, true); - - // We also need to unlock the waiter queue lock. - current_state = IsWaiterQueueLockedField::update(current_state, true); - DCHECK(!IsWaiterQueueLockedField::decode(new_state)); - TSAN_RELEASE(state); - if (state->compare_exchange_strong(current_state, new_state, - std::memory_order_acq_rel, - std::memory_order_relaxed)) { - // The CAS atomically released the waiter queue lock and acquired the js - // mutex lock. - return true; - } - - DCHECK(IsLockedField::decode(state->load())); - TSAN_RELEASE(state); - state->store(new_state, std::memory_order_release); - return false; - } - - SetWaiterQueueStateOnly(state, new_state); - return false; -} - -// static -bool JSAtomicsMutex::LockSlowPath(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state, - std::optional<base::TimeDelta> timeout) { - for (;;) { - // Spin for a little bit to try to acquire the lock, so as to be fast under - // microcontention. - if (BackoffTryLock(requester, mutex, state)) return true; - - // At this point the lock is considered contended, so try to go to sleep and - // put the requester thread on the waiter queue. - - // Allocate a waiter queue node on-stack, since this thread is going to - // sleep and will be blocked anyway. - WaiterQueueNode this_waiter(requester); - if (!MaybeEnqueueNode(requester, mutex, state, &this_waiter)) return true; - - bool rv; - // Wait for another thread to release the lock and wake us up. - if (timeout) { - rv = this_waiter.WaitFor(*timeout); - // Reload the state pointer after wake up in case of shared GC while - // blocked. - state = mutex->AtomicStatePtr(); - if (!rv) { - // If timed out, remove ourself from the waiter list, which is usually - // done by the thread performing the notifying. - rv = mutex->LockJSMutexOrDequeueTimedOutWaiter(requester, state, - &this_waiter); - return rv; - } - } else { - this_waiter.Wait(); - // Reload the state pointer after wake up in case of shared GC while - // blocked. - state = mutex->AtomicStatePtr(); - } - - // After wake up we try to acquire the lock again by spinning, as the - // contention at the point of going to sleep should not be correlated with - // contention at the point of waking up. - } -} - -void JSAtomicsMutex::UnlockSlowPath(Isolate* requester, - std::atomic<StateT>* state) { - // The fast path unconditionally cleared the owner thread. - DCHECK_EQ(ThreadId::Invalid().ToInteger(), - AtomicOwnerThreadIdPtr()->load(std::memory_order_relaxed)); - - // To wake a sleeping thread, first acquire the queue lock, which is itself - // a spinlock. - StateT current_state = state->load(std::memory_order_relaxed); - WaiterQueueLockGuard waiter_queue_lock_guard(state, current_state); - - if (!HasWaitersField::decode(current_state)) { - // All waiters were removed while waiting for the queue lock, possibly by - // timing out. Release both the lock and the queue lock. - StateT new_state = IsLockedField::update(current_state, false); - waiter_queue_lock_guard.set_new_state(new_state); - return; - } - - WaiterQueueNode* waiter_head = DestructivelyGetWaiterQueueHead(requester); - DCHECK_NOT_NULL(waiter_head); - WaiterQueueNode* old_head = WaiterQueueNode::Dequeue(&waiter_head); - - // Notify the node before releasing the lock, so that there is no risk of a - // race between this notify and another thread timing out and clearing up the - // node. - old_head->Notify(); - - // Release both the lock and the queue lock, and install the new waiter queue - // head. - StateT new_state = IsLockedField::update(current_state, false); - new_state = SetWaiterQueueHead(requester, waiter_head, new_state); - waiter_queue_lock_guard.set_new_state(new_state); -} - -// static -void JSAtomicsCondition::QueueWaiter(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - WaiterQueueNode* waiter) { - // The state pointer should not be used outside of this block as a shared GC - // may reallocate it after waiting. - std::atomic<StateT>* state = cv->AtomicStatePtr(); - - // Try to acquire the queue lock, which is itself a spinlock. - StateT current_state = state->load(std::memory_order_relaxed); - WaiterQueueLockGuard waiter_queue_lock_guard(state, current_state); - - // With the queue lock held, enqueue the requester onto the waiter queue. - WaiterQueueNode* waiter_head = cv->DestructivelyGetWaiterQueueHead(requester); - WaiterQueueNode::Enqueue(&waiter_head, waiter); - - // Release the queue lock and install the new waiter queue head. - DCHECK_EQ(state->load(), - IsWaiterQueueLockedField::update(current_state, true)); - StateT new_state = - cv->SetWaiterQueueHead(requester, waiter_head, current_state); - waiter_queue_lock_guard.set_new_state(new_state); -} - -// static -bool JSAtomicsCondition::WaitFor(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout) { - DisallowGarbageCollection no_gc; - - bool rv; - { - // Allocate a waiter queue node on-stack, since this thread is going to - // sleep and will be blocked anyway. - WaiterQueueNode this_waiter(requester); - - JSAtomicsCondition::QueueWaiter(requester, cv, &this_waiter); - - // Release the mutex and wait for another thread to wake us up, reacquiring - // the mutex upon wakeup. - mutex->Unlock(requester); - if (timeout) { - rv = this_waiter.WaitFor(*timeout); - if (!rv) { - // If timed out, remove ourself from the waiter list, which is usually - // done by the thread performing the notifying. - std::atomic<StateT>* state = cv->AtomicStatePtr(); - DequeueExplicit( - requester, cv, state, [&](WaiterQueueNode** waiter_head) { - WaiterQueueNode* dequeued = WaiterQueueNode::DequeueMatching( - waiter_head, - [&](WaiterQueueNode* node) { return node == &this_waiter; }); - return dequeued ? 1 : 0; - }); - } - } else { - this_waiter.Wait(); - rv = true; - } - } - JSAtomicsMutex::Lock(requester, mutex); - return rv; -} - -// static -uint32_t JSAtomicsCondition::DequeueExplicit( - Isolate* requester, DirectHandle<JSAtomicsCondition> cv, - std::atomic<StateT>* state, const DequeueAction& action_under_lock) { - // First acquire the queue lock, which is itself a spinlock. - StateT current_state = state->load(std::memory_order_acquire); - - if (!HasWaitersField::decode(current_state)) return 0; - WaiterQueueLockGuard waiter_queue_lock_guard(state, current_state); - - // Get the waiter queue head. - WaiterQueueNode* waiter_head = cv->DestructivelyGetWaiterQueueHead(requester); - - // There's no waiter to wake up, release the queue lock by setting it to the - // empty state. - if (waiter_head == nullptr) { - StateT new_state = kEmptyState; - waiter_queue_lock_guard.set_new_state(new_state); - return 0; - } - - uint32_t num_dequeued_waiters = action_under_lock(&waiter_head); - - // Release the queue lock and install the new waiter queue head. - DCHECK_EQ(state->load(), - IsWaiterQueueLockedField::update(current_state, true)); - StateT new_state = - cv->SetWaiterQueueHead(requester, waiter_head, current_state); - waiter_queue_lock_guard.set_new_state(new_state); - - return num_dequeued_waiters; -} - -// static -uint32_t JSAtomicsCondition::Notify(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - uint32_t count) { - std::atomic<StateT>* state = cv->AtomicStatePtr(); - - // Dequeue count waiters. - return DequeueExplicit( - requester, cv, state, [=](WaiterQueueNode** waiter_head) -> uint32_t { - WaiterQueueNode* old_head; - if (count == 1) { - old_head = WaiterQueueNode::Dequeue(waiter_head); - if (!old_head) return 0; - old_head->Notify(); - return 1; - } - if (count == kAllWaiters) { - old_head = *waiter_head; - *waiter_head = nullptr; - } else { - old_head = WaiterQueueNode::Split(waiter_head, count); - } - if (!old_head) return 0; - // Notify while holding the queue lock to avoid notifying - // waiters that have been deleted in other threads. - return old_head->NotifyAllInList(); - }); -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/objects/js-atomics-synchronization.h b/deps/v8/src/objects/js-atomics-synchronization.h deleted file mode 100644 index 906102e7df64..000000000000 --- a/deps/v8/src/objects/js-atomics-synchronization.h +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2022 the V8 project 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 V8_OBJECTS_JS_ATOMICS_SYNCHRONIZATION_H_ -#define V8_OBJECTS_JS_ATOMICS_SYNCHRONIZATION_H_ - -#include <atomic> - -#include "src/base/platform/time.h" -#include "src/execution/thread-id.h" -#include "src/objects/contexts.h" -#include "src/objects/js-objects.h" -#include "src/objects/js-struct.h" -#include "src/objects/struct.h" -#include "src/sandbox/external-pointer.h" - -// Has to be the last include (doesn't have include guards): -#include "src/objects/object-macros.h" - -namespace v8 { -namespace internal { - -namespace detail { -class WaiterQueueLockGuard; -class WaiterQueueNode; -} // namespace detail - -using detail::WaiterQueueLockGuard; -using detail::WaiterQueueNode; - -// JSSynchronizationPrimitive is the base class for JSAtomicsMutex and -// JSAtomicsCondition. It contains a 32-bit state field and a pointer to a -// waiter queue head, used to manage the queue of waiting threads for both: the -// mutex and the condition variable. - -V8_OBJECT class JSSynchronizationPrimitive : public AlwaysSharedSpaceJSObject { - V8_IT_ABSTRACT; - - public: - class BodyDescriptor; - - static void IsolateDeinit(Isolate* isolate); - Tagged<Object> NumWaitersForTesting(Isolate* requester); - - inline uint32_t state() const; - inline void set_state(uint32_t value); - - inline void SetNullWaiterQueueHead(); - - static const int kEndOfTaggedFieldsOffset; - static const int kHeaderSize; - - protected: - using StateT = uint32_t; - - // The `HasWaitersField` bitfield has the following properties: - // - It isn't a lock bit, meaning that if this bit is 1, - // that doesn't imply that some thread has exclusive write access to the - // lock state. - // - It is a metadata bit that's only written with the queue lock bit held. - // - It is set iff the external pointer is non-null. - // - It can be read without holding any lock bit. - // - It allows for fast and threadsafe checking if there is a waiter, - // as dereferencing the waiter queue should be done only when the - // `IsWaiterQueueLockedField` bit is set. - using HasWaitersField = base::BitField<bool, 0, 1>; - - // The `IsWaiterQueueLockedField` bitfield protects the waiter queue head from - // concurrent modification. It is set through as CAS operation in a spinlock. - using IsWaiterQueueLockedField = HasWaitersField::Next<bool, 1>; - - template <class T, int size> - using NextBitField = IsWaiterQueueLockedField::Next<T, size>; - - inline std::atomic<StateT>* AtomicStatePtr(); - inline WaiterQueueNode* DestructivelyGetWaiterQueueHead(Isolate* requester); - - // Store the waiter queue head in the synchronization primitive. If the head - // is not null, the returned state has the kHasWaitersBit set. - // In case of pointer compression, the waiter queue head is encoded as an - // `ExternalPointerHandle`. - inline StateT SetWaiterQueueHead(Isolate* requester, - WaiterQueueNode* waiter_head, - StateT new_state); - - // Set the new state without modifying bits outside the waiter queue mask. - static void SetWaiterQueueStateOnly(std::atomic<StateT>* state, - StateT new_state); - - static bool TryLockWaiterQueueExplicit(std::atomic<StateT>* state, - StateT& expected); - - using DequeueMatcher = std::function<bool(WaiterQueueNode*)>; - - static constexpr StateT kEmptyState = 0; - static constexpr StateT kWaiterQueueMask = - base::BitFieldUnion<HasWaitersField, IsWaiterQueueLockedField>::kMask; - - private: - friend class WaiterQueueLockGuard; - -#if V8_COMPRESS_POINTERS - // When pointer compression is enabled, the pointer to the waiter queue head - // is stored in the external pointer table and the object itself only contains - // a 32-bit external pointer handles. - inline ExternalPointerHandle* waiter_queue_head_handle_location() const; -#else - inline WaiterQueueNode** waiter_queue_head_location() const; -#endif - - public: - ExternalPointerMember<kWaiterQueueNodeTag> waiter_queue_head_; - std::atomic<uint32_t> state_; -} V8_OBJECT_END; - -// Synchronization primitives only store raw data past JSObject; no tagged -// fields beyond the inherited JSObject header. -inline constexpr int JSSynchronizationPrimitive::kEndOfTaggedFieldsOffset = - AlwaysSharedSpaceJSObject::kHeaderSize; -inline constexpr int JSSynchronizationPrimitive::kHeaderSize = - sizeof(JSSynchronizationPrimitive); - -// A non-recursive mutex that is exposed to JS. -// -// It has the following properties: -// - Slim: 12-16 bytes. Lock state is 4 bytes, waiter queue head is 4 bytes -// when V8_COMPRESS_POINTERS, and sizeof(void*) otherwise. Owner thread is -// an additional 4 bytes. -// - Fast when uncontended: a single weak CAS. -// - Possibly unfair under contention. -// - Moving GC safe. It uses an index into the shared Isolate's external -// pointer table to store a queue of sleeping threads. -// - Parks the main thread LocalHeap when the thread is blocked on acquiring -// the lock. Unparks the main thread LocalHeap when unblocked. This means -// that the lock can only be used with main thread isolates (including -// workers) but not with helper threads that have their own LocalHeap. -// -// This mutex manages its own queue of waiting threads under contention, i.e. -// it implements a futex in userland. The algorithm is inspired by WebKit's -// ParkingLot. -// -// The state variable encodes the locking state as a single word: 0bLQW. -// - W: Whether there are waiter threads in the queue. -// - Q: Whether the waiter queue is locked. -// - L: Whether the lock itself is locked. - -// The locking algorithm is as follows: -// 1. Fast Path. Unlocked+Uncontended(0b000) -> Locked+Uncontended(0b100). -// 2. Otherwise, slow path. -// a. Attempt to acquire the L bit (set current state | 0b100) on the state -// using a CAS spin loop bounded to some number of iterations. -// b. If L bit cannot be acquired, park the current thread: -// i. Acquire the Q bit (set current state | 0b010) in a spinlock. -// ii. Destructively get the waiter queue head. -// iii. Enqueue this thread's WaiterQueueNode to the tail of the list -// pointed to by the head, possibly creating a new list. -// iv. Release the Q bit and set the W bit -// (set (current state | 0b001) & ~0b010 in a single CAS operation). -// iv. Put the thread to sleep. -// v. Upon wake up, go to i. - -// The unlocking algorithm is as follows: -// 1. Fast Path. Locked+Uncontended(0b100) -> Unlocked+Uncontended(0b000). -// 2. Otherwise, slow path. -// a. Acquire the Q bit (set current state | 0b010) in a spinlock. -// b. Destructively get the waiter queue head. -// c. If the head is not null, dequeue the head. -// d. Store the new waiter queue head (possibly null). -// f. If the list is empty, clear the W bit (set current state & ~0b001). -// g. Release the Q bit and clear the L bit (set current state & ~0b100). -// (The W and Q bits must be set in a single CAS operation). -// h. If the list was not empty, notify the dequeued head. -V8_OBJECT class JSAtomicsMutex : public JSSynchronizationPrimitive { - public: - // A non-copyable wrapper class that provides an RAII-style mechanism for - // owning the `JSAtomicsMutex`. - V8_OBJECT_INNER_CLASS class V8_NODISCARD LockGuardBase { - public: - LockGuardBase(const LockGuardBase&) = delete; - LockGuardBase& operator=(const LockGuardBase&) = delete; - inline ~LockGuardBase(); - bool locked() const { return locked_; } - - protected: - inline LockGuardBase(Isolate* isolate, DirectHandle<JSAtomicsMutex> mutex, - bool locked); - - private: - Isolate* isolate_; - DirectHandle<JSAtomicsMutex> mutex_; - bool locked_; - } V8_OBJECT_INNER_CLASS_END; - - // The mutex is attempted to be locked via `Lock` when a `LockGuard` - // object is created, the lock will be acquired unless the timeout is reached. - // If the mutex was acquired, then it is released when the `LockGuard` object - // is destructed. - V8_OBJECT_INNER_CLASS class V8_NODISCARD LockGuard final - : public LockGuardBase { - public: - inline LockGuard(Isolate* isolate, DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout = std::nullopt); - } V8_OBJECT_INNER_CLASS_END; - - // The mutex is attempted to be locked via `TryLock` when a `TryLockGuard` - // object is created. If the mutex was acquired, then it is released when the - // `TryLockGuard` object is destructed. - V8_OBJECT_INNER_CLASS class V8_NODISCARD TryLockGuard final - : public LockGuardBase { - public: - inline TryLockGuard(Isolate* isolate, DirectHandle<JSAtomicsMutex> mutex); - } V8_OBJECT_INNER_CLASS_END; - - DECL_PRINTER(JSAtomicsMutex) - EXPORT_DECL_VERIFIER(JSAtomicsMutex) - - // Lock the mutex, blocking if it's currently owned by another thread. - // Returns false if the lock times out, true otherwise. - static inline bool Lock( - Isolate* requester, DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout = std::nullopt); - - V8_WARN_UNUSED_RESULT inline bool TryLock(); - - inline void Unlock(Isolate* requester); - - inline bool IsHeld(); - inline bool IsCurrentThreadOwner(); - - V8_EXPORT_PRIVATE static DirectHandle<JSObject> CreateResultObject( - Isolate* isolate, DirectHandle<Object> value, bool success); - - inline int32_t owner_thread_id() const; - inline void set_owner_thread_id(int32_t value); - - private: - friend class Factory; - - // There are 3 state bits: whether there are waiter threads in the queue, - // whether the waiter queue is locked (both inherited from the base class), - // and whether the lock itself is locked (IsLockedField). - using IsLockedField = JSSynchronizationPrimitive::NextBitField<bool, 1>; - - static constexpr StateT kUnlockedUncontended = kEmptyState; - static constexpr StateT kLockedUncontended = IsLockedField::encode(true); - - inline void SetCurrentThreadAsOwner(); - inline void ClearOwnerThread(); - - inline std::atomic<int32_t>* AtomicOwnerThreadIdPtr(); - - V8_EXPORT_PRIVATE static bool LockSlowPath( - Isolate* requester, DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state, std::optional<base::TimeDelta> timeout); - - V8_EXPORT_PRIVATE void UnlockSlowPath(Isolate* requester, - std::atomic<StateT>* state); - - // Returns true if the JS mutex was taken and false otherwise. - bool LockJSMutexOrDequeueTimedOutWaiter(Isolate* requester, - std::atomic<StateT>* state, - WaiterQueueNode* timed_out_waiter); - - static bool TryLockExplicit(std::atomic<StateT>* state, StateT& expected); - // Returns nullopt if the JS mutex is acquired, otherwise return an optional - // with a `WaiterQueueLockGuard` object. - static std::optional<WaiterQueueLockGuard> LockWaiterQueueOrJSMutex( - std::atomic<StateT>* state, StateT& current_state); - V8_EXPORT_PRIVATE static bool MutexTryLock(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state); - V8_INLINE static bool BackoffTryLock(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state); - - V8_EXPORT_PRIVATE static bool MaybeEnqueueNode( - Isolate* requester, DirectHandle<JSAtomicsMutex> mutex, - std::atomic<StateT>* state, WaiterQueueNode* this_waiter); - - template <typename LockSlowPathWrapper, - typename = std::enable_if<std::is_invocable_r_v< - bool, LockSlowPathWrapper, std::atomic<StateT>*>>> - static inline bool LockImpl(Isolate* requester, - DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout, - LockSlowPathWrapper slow_path_wrapper); - - public: - std::atomic<int32_t> owner_thread_id_; - - static const int kHeaderSize; -} V8_OBJECT_END; - -inline constexpr int JSAtomicsMutex::kHeaderSize = sizeof(JSAtomicsMutex); - -// A condition variable that is exposed to JS. -// -// It has the following properties: -// - Slim: 8-12 bytes. Lock state is 4 bytes, waiter queue head is 4 bytes -// when V8_COMPRESS_POINTERS, and sizeof(void*) otherwise. -// - Moving GC safe. It uses an index into the shared Isolate's external -// pointer table to store a queue of sleeping threads. -// - Parks the main thread LocalHeap when waiting. Unparks the main thread -// LocalHeap after waking up. -// -// This condition variable manages its own queue of waiting threads, like -// JSAtomicsMutex. The algorithm is inspired by WebKit's ParkingLot. -// -// The state variable encodes the locking state as a single word: 0bQW. -// - W: Whether there are waiter threads in the queue. -// - Q: Whether the waiter queue is locked. -// -// The waiting algorithm is as follows: -// 1. Acquire the Q bit (set current state | 0b010) in a spinlock. -// 2. Destructively get the waiter queue head. -// 3. Enqueue this thread's WaiterQueueNode to the tail of the list pointed to -// by the head, possibly creating a new list. -// 4. Release the Q bit and set the W bit (set (current state | 0b001) & ~0b010 -// in a single CAS operation). -// 5. Put the thread to sleep. -// -// The notification algorithm is as follows: -// 1. Acquire the Q bit (set current state | 0b010) in a spinlock. -// 2. Destructively get the waiter queue head. -// 3. If the head is not null, dequeue the head. -// 4. Store the new waiter queue head (possibly null). -// 5. If the list is empty, clear the W bit (set current state & ~0b001). -// 6. Release the Q bit (set current state & ~0b010). -// (The W and Q bits must be set in a single CAS operation). -// 7. If the list was not empty, notify the dequeued head. - -V8_OBJECT class JSAtomicsCondition : public JSSynchronizationPrimitive { - public: - DECL_PRINTER(JSAtomicsCondition) - EXPORT_DECL_VERIFIER(JSAtomicsCondition) - - V8_EXPORT_PRIVATE static bool WaitFor(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - DirectHandle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout); - - static constexpr uint32_t kAllWaiters = UINT32_MAX; - - // Notify {count} waiters. Returns the number of waiters woken up. - static V8_EXPORT_PRIVATE uint32_t Notify(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - uint32_t count); - - private: - friend class Factory; - - static void QueueWaiter(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - WaiterQueueNode* waiter); - - using DequeueAction = std::function<uint32_t(WaiterQueueNode**)>; - static uint32_t DequeueExplicit(Isolate* requester, - DirectHandle<JSAtomicsCondition> cv, - std::atomic<StateT>* state, - const DequeueAction& dequeue_action); - - public: -#if TAGGED_SIZE_8_BYTES - uint32_t optional_padding_; -#endif // TAGGED_SIZE_8_BYTES - - static const int kHeaderSize; -} V8_OBJECT_END; - -inline constexpr int JSAtomicsCondition::kHeaderSize = - sizeof(JSAtomicsCondition); - -} // namespace internal -} // namespace v8 - -#include "src/objects/object-macros-undef.h" - -#endif // V8_OBJECTS_JS_ATOMICS_SYNCHRONIZATION_H_ diff --git a/deps/v8/src/objects/js-atomics-synchronization.tq b/deps/v8/src/objects/js-atomics-synchronization.tq deleted file mode 100644 index c867cd87b89d..000000000000 --- a/deps/v8/src/objects/js-atomics-synchronization.tq +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@abstract -@cppObjectLayoutDefinition -extern class JSSynchronizationPrimitive extends AlwaysSharedSpaceJSObject { - waiter_queue_head: ExternalPointer; - state: uint32; -} - -@cppObjectLayoutDefinition -extern class JSAtomicsMutex extends JSSynchronizationPrimitive { - owner_thread_id: int32; -} - -@cppObjectLayoutDefinition -extern class JSAtomicsCondition extends JSSynchronizationPrimitive { - @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; -} diff --git a/deps/v8/src/objects/js-data-object-builder-inl.h b/deps/v8/src/objects/js-data-object-builder-inl.h index 48fedddb965a..23115f36b8fb 100644 --- a/deps/v8/src/objects/js-data-object-builder-inl.h +++ b/deps/v8/src/objects/js-data-object-builder-inl.h @@ -82,20 +82,27 @@ class FoldedMutableHeapNumberAllocator { raw_bytes_->set_length(0); } - Tagged<HeapNumber> AllocateNext(ReadOnlyRoots roots, Float64 value) { + Tagged<HeapNumber> Allocate(Float64 value) { + AllocationWitness witness = AllocateRaw(); + return new (witness) HeapNumber(witness, value); + } + + Tagged<UninitializedHeapNumber> AllocateUninitialized() { + AllocationWitness witness = AllocateRaw(); + return new (witness) UninitializedHeapNumber(witness); + } + + private: + AllocationWitness AllocateRaw() { DCHECK_GE(mutable_double_address_, reinterpret_cast<Address>(raw_bytes_->begin())); - Tagged<HeapObject> hn = HeapObject::FromAddress(mutable_double_address_); - hn->set_map_after_allocation(isolate_, roots.heap_number_map()); - Cast<HeapNumber>(hn)->set_value_as_bits(value.get_bits()); + Tagged<HeapObject> obj = HeapObject::FromAddress(mutable_double_address_); mutable_double_address_ += ALIGN_TO_ALLOCATION_ALIGNMENT(sizeof(HeapNumber)); DCHECK_LE(mutable_double_address_, reinterpret_cast<Address>(raw_bytes_->end())); - return Cast<HeapNumber>(hn); + return AllocationWitness(obj, roots_, UPDATE_WRITE_BARRIER); } - - private: Isolate* isolate_; ReadOnlyRoots roots_; Handle<ByteArray> raw_bytes_ = {}; @@ -356,8 +363,6 @@ inline void JSDataObjectBuilder::CreateAndInitialiseObject( FoldedMutableHeapNumberAllocator hn_allocator(isolate_, &hn_allocation, no_gc); - ReadOnlyRoots roots(isolate_); - // Initialize the in-object properties up to the last added property. int current_property_offset = raw_object->GetInObjectPropertyOffset(0); for (int i = 0; i < current_property_index_; ++i) { @@ -371,11 +376,13 @@ inline void JSDataObjectBuilder::CreateAndInitialiseObject( IsSmi(value)) { PropertyDetails details = descriptors->GetDetails(descriptor_index); if (details.representation().IsDouble()) { - Float64 d = Float64::hole_nan(); if (IsNumber(value)) { - d = Float64::FromMaybeNaN(Object::NumberValue(value)); + value = hn_allocator.Allocate( + Float64::FromMaybeNaN(Object::NumberValue(value))); + } else { + DCHECK(IsUninitializedHole(value)); + value = hn_allocator.AllocateUninitialized(); } - value = hn_allocator.AllocateNext(roots, d); } } @@ -522,13 +529,12 @@ bool JSDataObjectBuilder::TryAddFastPropertyTransitionForValue( return false; } - auto [representation, constness] = - Object::OptimalRepresentation(*value, PropertyConstness::kConst); + Representation representation = Object::OptimalRepresentation(*value); DirectHandle<FieldType> type = Object::OptimalType(*value, isolate_, representation); - MaybeHandle<Map> maybe_map = - Map::CopyWithField(isolate_, map_, key, type, NONE, constness, - representation, INSERT_TRANSITION); + MaybeHandle<Map> maybe_map = Map::CopyWithField( + isolate_, map_, key, type, NONE, PropertyConstness::kConst, + representation, INSERT_TRANSITION); DirectHandle<Map> next_map; if (!maybe_map.ToHandle(&next_map)) return false; if (next_map->is_dictionary_map()) return false; @@ -573,8 +579,7 @@ bool JSDataObjectBuilder::TryGeneralizeFieldToValue( return true; } - auto [representation, constness] = - Object::OptimalRepresentation(*value, current_details.constness()); + Representation representation = Object::OptimalRepresentation(*value); representation = representation.generalize(expected_representation); if (!expected_representation.CanBeInPlaceChangedTo(representation)) { // Reconfigure the map for the value, deprecating if necessary. This @@ -595,8 +600,9 @@ bool JSDataObjectBuilder::TryGeneralizeFieldToValue( } MapUpdater mu(isolate_, map_); Handle<Map> new_map = mu.ReconfigureToDataField( - descriptor_index, current_details.attributes(), constness, - representation, FieldType::Any(isolate_)); + descriptor_index, current_details.attributes(), + current_details.constness(), representation, + FieldType::Any(isolate_)); // We only want to stay on the fast path if we got a fast map. if (new_map->is_dictionary_map()) return false; @@ -609,8 +615,9 @@ bool JSDataObjectBuilder::TryGeneralizeFieldToValue( DCHECK(!representation.IsDouble() || expected_representation.IsDouble()); DirectHandle<FieldType> value_type = Object::OptimalType(*value, isolate_, representation); - MapUpdater::GeneralizeField(isolate_, map_, descriptor_index, constness, - representation, value_type); + MapUpdater::GeneralizeField(isolate_, map_, descriptor_index, + current_details.constness(), representation, + value_type); } } else if (expected_representation.IsHeapObject() && !FieldType::NowContains( diff --git a/deps/v8/src/objects/js-date-time-format.cc b/deps/v8/src/objects/js-date-time-format.cc index 05999c6ad9f4..28e4da9b0cd6 100644 --- a/deps/v8/src/objects/js-date-time-format.cc +++ b/deps/v8/src/objects/js-date-time-format.cc @@ -23,8 +23,13 @@ #include "src/objects/js-date-time-format-inl.h" #ifdef V8_TEMPORAL_SUPPORT #include "src/objects/js-temporal-objects-inl.h" +#if __has_include("temporal/AnyCalendarKind.hpp") +#include "temporal/AnyCalendarKind.hpp" +#include "temporal/Instant.hpp" +#else #include "temporal_rs/AnyCalendarKind.hpp" #include "temporal_rs/Instant.hpp" +#endif #endif // V8_TEMPORAL_SUPPORT #include "src/objects/managed-inl.h" #include "src/objects/object-conversions-inl.h" @@ -1366,7 +1371,10 @@ icu::UnicodeString GetDateTimeFormat(const icu::UnicodeString& options, } format_options.append(ch); // ii. Set needDefaults to false. - need_defaults = false; + // The [[era]] option does not suppress defaults. + if (ch != 'G') { + need_defaults = false; + } } last_ch = ch; } @@ -2157,7 +2165,7 @@ class CalendarCache { tz->getID(tz_id); std::string key; tz_id.toUTF8String<std::string>(key); - key += ":"; + key += ':'; key += locale.getName(); base::MutexGuard guard(&mutex_); @@ -2292,7 +2300,7 @@ class DateFormatCache { JSDateTimeFormat::HourCycle hc) { std::string key; skeleton.toUTF8String<std::string>(key); - key += ":"; + key += ':'; key += icu_locale.getName(); base::MutexGuard guard(&mutex_); @@ -2846,7 +2854,7 @@ MaybeDirectHandle<JSDateTimeFormat> JSDateTimeFormat::CreateDateTimeFormat( } // Convert fractionalSecondDigits to skeleton. for (int i = 0; i < fsd; i++) { - skeleton += "S"; + skeleton += 'S'; } } // i. Let prop be the name given in the Property column of the row. diff --git a/deps/v8/src/objects/js-date-time-format.h b/deps/v8/src/objects/js-date-time-format.h index 700c2e973667..488ee6c1999a 100644 --- a/deps/v8/src/objects/js-date-time-format.h +++ b/deps/v8/src/objects/js-date-time-format.h @@ -205,7 +205,7 @@ V8_OBJECT class JSDateTimeFormat : public JSObject { TaggedMember<Foreign> icu_simple_date_format_; TaggedMember<Foreign> icu_date_interval_format_; TaggedMember<UnionOf<JSFunction, Undefined>> bound_format_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSDateTimeFormatFlags>); } V8_OBJECT_END; inline constexpr int JSDateTimeFormat::kHeaderSize = sizeof(JSDateTimeFormat); diff --git a/deps/v8/src/objects/js-display-names.h b/deps/v8/src/objects/js-display-names.h index d3f308aa864a..b48ec13f91db 100644 --- a/deps/v8/src/objects/js-display-names.h +++ b/deps/v8/src/objects/js-display-names.h @@ -105,7 +105,7 @@ V8_OBJECT class JSDisplayNames : public JSObject { public: TaggedMember<CppGCManaged<DisplayNamesInternal>> internal_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSDisplayNamesFlags>); } V8_OBJECT_END; inline constexpr int JSDisplayNames::kHeaderSize = sizeof(JSDisplayNames); diff --git a/deps/v8/src/objects/js-disposable-stack.cc b/deps/v8/src/objects/js-disposable-stack.cc index baad5bba2574..79fee6e6e074 100644 --- a/deps/v8/src/objects/js-disposable-stack.cc +++ b/deps/v8/src/objects/js-disposable-stack.cc @@ -289,6 +289,10 @@ Maybe<bool> JSAsyncDisposableStack::NextDisposeAsyncIteration( isolate->clear_internal_exception(); isolate->clear_pending_message(); JSPromise::Reject(outer_promise, exception); + if (isolate->debug()->IsRestartFrameScheduled()) { + isolate->TerminateExecution(); + return Nothing<bool>(); + } } } while (!done); diff --git a/deps/v8/src/objects/js-disposable-stack.h b/deps/v8/src/objects/js-disposable-stack.h index a55c5f00950c..7206419d6ccc 100644 --- a/deps/v8/src/objects/js-disposable-stack.h +++ b/deps/v8/src/objects/js-disposable-stack.h @@ -108,7 +108,7 @@ V8_OBJECT class JSDisposableStackBase : public JSObject { public: TaggedMember<FixedArray> stack_; // SmiTagged<DisposableStackStatus>. - TaggedMember<Smi> status_; + TaggedMember<Smi> status_ V8_TQ_TYPE(SmiTagged<DisposableStackStatus>); TaggedMember<UnionOf<Object, Hole>> error_; TaggedMember<UnionOf<Object, Hole>> error_message_; } V8_OBJECT_END; diff --git a/deps/v8/src/objects/js-duration-format.h b/deps/v8/src/objects/js-duration-format.h index ca42ec1c886e..9aad11b692df 100644 --- a/deps/v8/src/objects/js-duration-format.h +++ b/deps/v8/src/objects/js-duration-format.h @@ -225,8 +225,10 @@ V8_OBJECT class JSDurationFormat : public JSObject { static const int kHeaderSize; public: - TaggedMember<Smi> style_flags_; - TaggedMember<Smi> display_flags_; + TaggedMember<Smi> style_flags_ + V8_TQ_TYPE(SmiTagged<JSDurationFormatStyleFlags>); + TaggedMember<Smi> display_flags_ + V8_TQ_TYPE(SmiTagged<JSDurationFormatDisplayFlags>); TaggedMember<Foreign> icu_locale_; TaggedMember<Foreign> icu_number_formatter_; } V8_OBJECT_END; diff --git a/deps/v8/src/objects/js-function-inl.h b/deps/v8/src/objects/js-function-inl.h index 6adb79672420..8d8a8f337458 100644 --- a/deps/v8/src/objects/js-function-inl.h +++ b/deps/v8/src/objects/js-function-inl.h @@ -42,11 +42,11 @@ void JSBoundFunction::set_bound_target_function(Tagged<JSCallable> value, WriteBarrierMode mode) { bound_target_function_.store(this, value, mode); } -Tagged<Object> JSBoundFunction::bound_this() const { +Tagged<UnionOf<JSAny, SourceTextModule>> JSBoundFunction::bound_this() const { return bound_this_.load(); } -void JSBoundFunction::set_bound_this(Tagged<Object> value, - WriteBarrierMode mode) { +void JSBoundFunction::set_bound_this( + Tagged<UnionOf<JSAny, SourceTextModule>> value, WriteBarrierMode mode) { bound_this_.store(this, value, mode); } Tagged<FixedArray> JSBoundFunction::bound_arguments() const { @@ -214,7 +214,7 @@ JSDispatchHandle JSFunction::AllocateDispatchHandle( void JSFunction::clear_dispatch_handle() { dispatch_handle_.Relaxed_Clear(); } void JSFunction::set_dispatch_handle(JSDispatchHandle handle, WriteBarrierMode mode) { - dispatch_handle_.Relaxed_Store(this, handle, mode); + dispatch_handle_.Release_Store(this, handle, mode); } void JSFunction::UpdateDispatchEntry(Isolate* isolate, Tagged<Code> new_code, WriteBarrierMode mode) { @@ -584,7 +584,7 @@ bool JSFunction::is_compiled(IsolateForSandbox isolate) const { bool JSFunction::NeedsResetDueToFlushedBytecode(Isolate* isolate) { // The function is only used sequentially. Concurrent cases need to take care // of loading the fields themselves. - Tagged<SharedFunctionInfo> sfi = TrustedCast<SharedFunctionInfo>(shared()); + Tagged<SharedFunctionInfo> sfi = Cast<SharedFunctionInfo>(shared()); Tagged<Code> code = TrustedCast<Code>(raw_code(isolate)); return NeedsResetDueToFlushedBytecode(isolate, sfi, code); } diff --git a/deps/v8/src/objects/js-function.cc b/deps/v8/src/objects/js-function.cc index 585d97d436c3..472856e90216 100644 --- a/deps/v8/src/objects/js-function.cc +++ b/deps/v8/src/objects/js-function.cc @@ -1484,7 +1484,8 @@ DirectHandle<String> JSFunction::ToString(Isolate* isolate, } // Check if we have source code for the {function}. - if (!shared_info->HasSourceCode()) { + if (!shared_info->HasSourceCode() || + shared_info->StartPosition() == shared_info->EndPosition()) { return NativeCodeFunctionSourceString(isolate, shared_info); } diff --git a/deps/v8/src/objects/js-function.h b/deps/v8/src/objects/js-function.h index f07734c116cc..abc8e5669d32 100644 --- a/deps/v8/src/objects/js-function.h +++ b/deps/v8/src/objects/js-function.h @@ -56,8 +56,8 @@ V8_OBJECT class JSBoundFunction inline void set_bound_target_function( Tagged<JSCallable> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> bound_this() const; - inline void set_bound_this(Tagged<Object> value, + inline Tagged<UnionOf<JSAny, SourceTextModule>> bound_this() const; + inline void set_bound_this(Tagged<UnionOf<JSAny, SourceTextModule>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<FixedArray> bound_arguments() const; @@ -77,7 +77,7 @@ V8_OBJECT class JSBoundFunction public: TaggedMember<JSCallable> bound_target_function_; - TaggedMember<Object> bound_this_; + TaggedMember<UnionOf<JSAny, SourceTextModule>> bound_this_; TaggedMember<FixedArray> bound_arguments_; } V8_OBJECT_END; @@ -591,7 +591,8 @@ V8_OBJECT class JSFunctionWithPrototype : public JSFunction { DECL_VERIFIER(JSFunctionWithPrototype) public: - TaggedMember<Object> prototype_or_initial_map_; + TaggedMember<UnionOf<JSReceiver, Map, Tuple2, TheHole>> + prototype_or_initial_map_; } V8_OBJECT_END; inline constexpr int JSFunctionWithPrototype::kHeaderSize = diff --git a/deps/v8/src/objects/js-function.tq b/deps/v8/src/objects/js-function.tq index 63e2913cdb68..97090af6de1d 100644 --- a/deps/v8/src/objects/js-function.tq +++ b/deps/v8/src/objects/js-function.tq @@ -36,7 +36,7 @@ extern class JSWrappedFunction extends @cppObjectLayoutDefinition extern class JSFunction extends JSFunctionOrBoundFunctionOrWrappedFunction { dispatch_handle: int32; - @if(TAGGED_SIZE_8_BYTES) padding: int32; + @if(TAGGED_SIZE_8_BYTES) padding: uint32; shared_function_info: SharedFunctionInfo; context: Context; feedback_cell: FeedbackCell; diff --git a/deps/v8/src/objects/js-generator.tq b/deps/v8/src/objects/js-generator.tq index 77ca66a81672..96f367e6183f 100644 --- a/deps/v8/src/objects/js-generator.tq +++ b/deps/v8/src/objects/js-generator.tq @@ -51,7 +51,7 @@ extern class JSAsyncFunctionObject extends JSGeneratorObject { extern class JSAsyncGeneratorObject extends JSGeneratorObject { // Pointer to the head of a singly linked list of AsyncGeneratorRequest, or // undefined. - queue: HeapObject; + queue: AsyncGeneratorRequest|Undefined; // Whether or not the generator is currently awaiting. is_awaiting: Smi; } diff --git a/deps/v8/src/objects/js-iterator-helpers-inl.h b/deps/v8/src/objects/js-iterator-helpers-inl.h index 68dd9e3e6eb0..822cdcdcea37 100644 --- a/deps/v8/src/objects/js-iterator-helpers-inl.h +++ b/deps/v8/src/objects/js-iterator-helpers-inl.h @@ -27,28 +27,28 @@ void JSIteratorHelper::set_state(JSIteratorHelperState value) { } Tagged<JSReceiver> JSIteratorHelperSimple::underlying_iterator_object() const { - return underlying_iterator_object_.load(); + return underlying_iterator_.object_.load(); } void JSIteratorHelperSimple::set_underlying_iterator_object( Tagged<JSReceiver> value, WriteBarrierMode mode) { - underlying_iterator_object_.store(this, value, mode); + underlying_iterator_.object_.store(this, value, mode); } Tagged<JSAny> JSIteratorHelperSimple::underlying_iterator_next() const { - return underlying_iterator_next_.load(); + return underlying_iterator_.next_.load(); } void JSIteratorHelperSimple::set_underlying_iterator_next( Tagged<JSAny> value, WriteBarrierMode mode) { - underlying_iterator_next_.store(this, value, mode); + underlying_iterator_.next_.store(this, value, mode); } -Tagged<JSReceiver> JSIteratorMapHelper::mapper() const { +Tagged<JSCallable> JSIteratorMapHelper::mapper() const { return mapper_.load(); } -void JSIteratorMapHelper::set_mapper(Tagged<JSReceiver> value, +void JSIteratorMapHelper::set_mapper(Tagged<JSCallable> value, WriteBarrierMode mode) { mapper_.store(this, value, mode); } @@ -60,11 +60,11 @@ void JSIteratorMapHelper::set_counter(Tagged<Number> value, counter_.store(this, value, mode); } -Tagged<JSReceiver> JSIteratorFilterHelper::predicate() const { +Tagged<JSCallable> JSIteratorFilterHelper::predicate() const { return predicate_.load(); } -void JSIteratorFilterHelper::set_predicate(Tagged<JSReceiver> value, +void JSIteratorFilterHelper::set_predicate(Tagged<JSCallable> value, WriteBarrierMode mode) { predicate_.store(this, value, mode); } @@ -96,11 +96,11 @@ void JSIteratorDropHelper::set_remaining(Tagged<Number> value, remaining_.store(this, value, mode); } -Tagged<JSReceiver> JSIteratorFlatMapHelper::mapper() const { +Tagged<JSCallable> JSIteratorFlatMapHelper::mapper() const { return mapper_.load(); } -void JSIteratorFlatMapHelper::set_mapper(Tagged<JSReceiver> value, +void JSIteratorFlatMapHelper::set_mapper(Tagged<JSCallable> value, WriteBarrierMode mode) { mapper_.store(this, value, mode); } @@ -115,21 +115,21 @@ void JSIteratorFlatMapHelper::set_counter(Tagged<Number> value, } Tagged<JSReceiver> JSIteratorFlatMapHelper::inner_iterator_object() const { - return inner_iterator_object_.load(); + return inner_iterator_.object_.load(); } void JSIteratorFlatMapHelper::set_inner_iterator_object( Tagged<JSReceiver> value, WriteBarrierMode mode) { - inner_iterator_object_.store(this, value, mode); + inner_iterator_.object_.store(this, value, mode); } Tagged<JSAny> JSIteratorFlatMapHelper::inner_iterator_next() const { - return inner_iterator_next_.load(); + return inner_iterator_.next_.load(); } void JSIteratorFlatMapHelper::set_inner_iterator_next(Tagged<JSAny> value, WriteBarrierMode mode) { - inner_iterator_next_.store(this, value, mode); + inner_iterator_.next_.store(this, value, mode); } Tagged<FixedArray> JSIteratorConcatHelper::iterables() const { diff --git a/deps/v8/src/objects/js-iterator-helpers.h b/deps/v8/src/objects/js-iterator-helpers.h index 048a509ab48c..e1584bf3bc8f 100644 --- a/deps/v8/src/objects/js-iterator-helpers.h +++ b/deps/v8/src/objects/js-iterator-helpers.h @@ -82,7 +82,7 @@ V8_OBJECT class JSIteratorHelper : public JSObject { public: // SmiTagged<JSIteratorHelperState>. - TaggedMember<Smi> state_; + TaggedMember<Smi> state_ V8_TQ_TYPE(SmiTagged<JSIteratorHelperState>); } V8_OBJECT_END; // The superclass of iterator helpers that have a single underlying iterator. @@ -90,6 +90,13 @@ V8_OBJECT class JSIteratorHelperSimple : public JSIteratorHelper { V8_IT_ABSTRACT; public: + // Match iterator::IteratorRecord as one struct-typed field. Keep it nested + // because the CSA record already uses v8::internal::IteratorRecord. + struct IteratorRecord { + TaggedMember<JSReceiver> object_; + TaggedMember<JSAny> next_; + }; + inline Tagged<JSReceiver> underlying_iterator_object() const; inline void set_underlying_iterator_object( Tagged<JSReceiver> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); @@ -104,15 +111,14 @@ V8_OBJECT class JSIteratorHelperSimple : public JSIteratorHelper { DECL_VERIFIER(JSIteratorHelperSimple) public: - TaggedMember<JSReceiver> underlying_iterator_object_; - TaggedMember<JSAny> underlying_iterator_next_; + IteratorRecord underlying_iterator_; } V8_OBJECT_END; // The iterator helper returned by Iterator.prototype.map. V8_OBJECT class JSIteratorMapHelper final : public JSIteratorHelperSimple { public: - inline Tagged<JSReceiver> mapper() const; - inline void set_mapper(Tagged<JSReceiver> value, + inline Tagged<JSCallable> mapper() const; + inline void set_mapper(Tagged<JSCallable> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<Number> counter() const; @@ -123,15 +129,15 @@ V8_OBJECT class JSIteratorMapHelper final : public JSIteratorHelperSimple { DECL_VERIFIER(JSIteratorMapHelper) public: - TaggedMember<JSReceiver> mapper_; + TaggedMember<JSCallable> mapper_; TaggedMember<Number> counter_; } V8_OBJECT_END; // The iterator helper returned by Iterator.prototype.filter. V8_OBJECT class JSIteratorFilterHelper final : public JSIteratorHelperSimple { public: - inline Tagged<JSReceiver> predicate() const; - inline void set_predicate(Tagged<JSReceiver> value, + inline Tagged<JSCallable> predicate() const; + inline void set_predicate(Tagged<JSCallable> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<Number> counter() const; @@ -142,7 +148,7 @@ V8_OBJECT class JSIteratorFilterHelper final : public JSIteratorHelperSimple { DECL_VERIFIER(JSIteratorFilterHelper) public: - TaggedMember<JSReceiver> predicate_; + TaggedMember<JSCallable> predicate_; TaggedMember<Number> counter_; } V8_OBJECT_END; @@ -177,8 +183,8 @@ V8_OBJECT class JSIteratorDropHelper final : public JSIteratorHelperSimple { // The iterator helper returned by Iterator.prototype.flatMap. V8_OBJECT class JSIteratorFlatMapHelper final : public JSIteratorHelperSimple { public: - inline Tagged<JSReceiver> mapper() const; - inline void set_mapper(Tagged<JSReceiver> value, + inline Tagged<JSCallable> mapper() const; + inline void set_mapper(Tagged<JSCallable> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<Number> counter() const; @@ -197,10 +203,9 @@ V8_OBJECT class JSIteratorFlatMapHelper final : public JSIteratorHelperSimple { DECL_VERIFIER(JSIteratorFlatMapHelper) public: - TaggedMember<JSReceiver> mapper_; + TaggedMember<JSCallable> mapper_; TaggedMember<Number> counter_; - TaggedMember<JSReceiver> inner_iterator_object_; - TaggedMember<JSAny> inner_iterator_next_; + IteratorRecord inner_iterator_; } V8_OBJECT_END; // The iterator helper returned by Iterator.concat. @@ -249,7 +254,7 @@ V8_OBJECT class JSIteratorZipHelper : public JSIteratorHelper { public: TaggedMember<FixedArray> underlying_iterators_; // SmiTagged<JSIteratorZipHelperMode>. - TaggedMember<Smi> mode_; + TaggedMember<Smi> mode_ V8_TQ_TYPE(SmiTagged<JSIteratorZipHelperMode>); TaggedMember<Smi> active_count_; TaggedMember<FixedArray> padding_; } V8_OBJECT_END; diff --git a/deps/v8/src/objects/js-list-format.h b/deps/v8/src/objects/js-list-format.h index c4ea672eeb76..a8030799b8da 100644 --- a/deps/v8/src/objects/js-list-format.h +++ b/deps/v8/src/objects/js-list-format.h @@ -110,7 +110,7 @@ V8_OBJECT class JSListFormat : public JSObject { public: TaggedMember<String> locale_; TaggedMember<Foreign> icu_formatter_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSListFormatFlags>); } V8_OBJECT_END; inline constexpr int JSListFormat::kHeaderSize = sizeof(JSListFormat); diff --git a/deps/v8/src/objects/js-locale.cc b/deps/v8/src/objects/js-locale.cc index 35b1919f3fb0..cb39d27470f7 100644 --- a/deps/v8/src/objects/js-locale.cc +++ b/deps/v8/src/objects/js-locale.cc @@ -287,8 +287,14 @@ bool JSLocale::StartsWithUnicodeLanguageId(std::string_view value) { } namespace { -// Return false if variants contain duplicate elements or invalid delimiters. +// Return false if variants contain duplicate elements, invalid delimiters, or +// exceed ICU's maximum variants length (MAX_VARIANTS_LENGTH = 179 in uloc.cpp). +// TODO(olivf, 557076207): Remove once mitigated upstream. bool IsValidVariants(std::string_view variants) { + constexpr size_t kMaxVariantsLength = 179; + if (variants.empty() || variants.length() > kMaxVariantsLength) { + return false; + } // The length of one unicode_variant_subtag is between 4-8. To have // duplicate or multiple subtags, the length of the variants need to be >= // 4+1+4 = 9. @@ -407,25 +413,27 @@ Maybe<bool> ApplyOptionsToTag(Isolate* isolate, DirectHandle<String> tag, // a. If variants is the empty String, throw a RangeError exception. // b. Let lowerVariants be the ASCII-lowercase of variants. std::string variants_stdstr = variants_str->ToStdString(); + // e. If variantSubtags contains any duplicate elements, throw a + // RangeError exception. + // Check IsValidVariants before builder->setVariant() so overlong variants + // do not produce a bogus icu::Locale inside LocaleBuilder::build(). + if (!IsValidVariants(variants_stdstr)) { + return Just(false); + } // c. Let variantSubtags be StringSplitToList(lowerVariants, "-"). // d. For each element variant of variantSubtags, do // i. If variant cannot be matched by the unicode_variant_subtag Unicode // locale nonterminal, throw a RangeError exception. builder->setVariant(variants_stdstr); - builder->build(status); - if (U_FAILURE(status) || variants_stdstr.empty()) { - return Just(false); - } - // e. If variantSubtags contains any duplicate elements, throw a - // RangeError exception. - if (!IsValidVariants(variants_stdstr)) { + icu::Locale built = builder->build(status); + if (U_FAILURE(status) || built.isBogus()) { return Just(false); } } // 9. Set tag to CanonicalizeLanguageTag(tag). // 10. If language is not undefined, - // a. Assert: tag matches the unicode_locale_id production. + // a. Assert: tag matches the unicode_language_id production. // b. Set tag to tag with the substring corresponding to the // unicode_language_subtag production replaced by the string language. // 11. If script is not undefined, then @@ -471,7 +479,7 @@ MaybeDirectHandle<JSLocale> JSLocale::New(Isolate* isolate, icu_locale.canonicalize(status); - if (!maybe_insert.FromJust() || U_FAILURE(status)) { + if (!maybe_insert.FromJust() || U_FAILURE(status) || icu_locale.isBogus()) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kLocaleBadParameters)); } diff --git a/deps/v8/src/objects/js-number-format.cc b/deps/v8/src/objects/js-number-format.cc index f772782e6404..7b638b586d0f 100644 --- a/deps/v8/src/objects/js-number-format.cc +++ b/deps/v8/src/objects/js-number-format.cc @@ -1054,7 +1054,8 @@ MaybeDirectHandle<JSNumberFormat> JSNumberFormat::UnwrapNumberFormat( THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, isolate->factory()->NewStringFromAsciiChecked( - "UnwrapNumberFormat"))); + "UnwrapNumberFormat"), + format_holder)); } // 5. Return nf. return Cast<JSNumberFormat>(object); @@ -1483,6 +1484,13 @@ MaybeDirectHandle<JSNumberFormat> JSNumberFormat::New( namespace { +// TODO(567827593): Remove once fixed in ICU. +constexpr uint32_t kMaxIcuFormattedDigits = 999'000; + +bool ExceedsMaxIcuFormattedDigits(DirectHandle<String> string) { + return string->length() > kMaxIcuFormattedDigits; +} + template <typename StringHandle> int32_t SignedStringLength(StringHandle string) { uint32_t unsigned_length = string->length(); @@ -1495,6 +1503,10 @@ icu::number::FormattedNumber FormatDecimalString( Isolate* isolate, const icu::number::LocalizedNumberFormatter* lfmt, Handle<String> string, UErrorCode& status) { string = String::Flatten(isolate, string); + if (ExceedsMaxIcuFormattedDigits(string)) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return {}; + } DisallowGarbageCollection no_gc; const String::FlatContent& flat = string->GetFlatContent(no_gc); int32_t length = SignedStringLength(string); @@ -1535,6 +1547,9 @@ Maybe<icu::number::FormattedNumber> IcuFormatNumber( Handle<String> big_int_string; ASSIGN_RETURN_ON_EXCEPTION(isolate, big_int_string, BigInt::ToString(isolate, big_int)); + if (ExceedsMaxIcuFormattedDigits(big_int_string)) { + THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError)); + } big_int_string = String::Flatten(isolate, big_int_string); DisallowGarbageCollection no_gc; const String::FlatContent& flat = big_int_string->GetFlatContent(no_gc); @@ -1549,6 +1564,9 @@ Maybe<icu::number::FormattedNumber> IcuFormatNumber( // https://github.com/tc39/proposal-intl-numberformat-v3/pull/82 DirectHandle<String> string = String::Flatten(isolate, Cast<String>(numeric_obj)); + if (ExceedsMaxIcuFormattedDigits(string)) { + THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError)); + } DisallowGarbageCollection no_gc; const String::FlatContent& flat = string->GetFlatContent(no_gc); int32_t length = SignedStringLength(string); @@ -1769,6 +1787,9 @@ Maybe<icu::Formattable> IntlMathematicalValue::ToFormattable( } DirectHandle<String> string; ASSIGN_RETURN_ON_EXCEPTION(isolate, string, ToString(isolate)); + if (ExceedsMaxIcuFormattedDigits(string)) { + THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError)); + } UErrorCode status = U_ZERO_ERROR; { DisallowGarbageCollection no_gc; diff --git a/deps/v8/src/objects/js-objects-inl.h b/deps/v8/src/objects/js-objects-inl.h index c715995c87ff..f3610bf71dc2 100644 --- a/deps/v8/src/objects/js-objects-inl.h +++ b/deps/v8/src/objects/js-objects-inl.h @@ -508,6 +508,10 @@ void JSObject::WriteToField(InternalIndex descriptor, PropertyDetails details, DisallowGarbageCollection no_gc; FieldIndex index = FieldIndex::ForDetails(map(), details); if (details.representation().IsDouble()) { + DCHECK(!IsUninitializedHole(value)); + auto box = Cast<UnionOf<HeapNumber, UninitializedHeapNumber>>( + RawFastPropertyAt(index)); + DCHECK_NE(box, value); // Manipulating the signaling NaN used for the hole and uninitialized // double field sentinel in C++, e.g. with base::bit_cast or // value()/set_value(), will change its value on ia32 (the x87 stack is used @@ -516,14 +520,18 @@ void JSObject::WriteToField(InternalIndex descriptor, PropertyDetails details, uint64_t bits; if (IsSmi(value)) { bits = base::bit_cast<uint64_t>(static_cast<double>(Smi::ToInt(value))); - } else if (IsUninitializedHole(value)) { - bits = kHoleNanInt64; } else { DCHECK(IsHeapNumber(value)); bits = Cast<HeapNumber>(value)->value_as_bits(); } - auto box = Cast<HeapNumber>(RawFastPropertyAt(index)); - box->set_value_as_bits(bits); + if (IsUninitializedHeapNumber(box)) { + Cast<UninitializedHeapNumber>(box)->set_value_as_bits(bits); + Isolate* isolate = Isolate::Current(); + box->set_map_safe_transition_no_write_barrier( + isolate, ReadOnlyRoots(isolate).heap_number_map(), kRelaxedStore); + } else { + Cast<HeapNumber>(box)->set_value_as_bits(bits); + } } else { FastPropertyAtPut(index, value); } @@ -748,21 +756,21 @@ void JSPrimitiveWrapper::set_value(Tagged<JSAny> value, WriteBarrierMode mode) { } Tagged<JSReceiver> JSValidIteratorWrapper::underlying_object() const { - return underlying_object_.load(); + return underlying_.object_.load(); } void JSValidIteratorWrapper::set_underlying_object(Tagged<JSReceiver> value, WriteBarrierMode mode) { - underlying_object_.store(this, value, mode); + underlying_.object_.store(this, value, mode); } Tagged<JSAny> JSValidIteratorWrapper::underlying_next() const { - return underlying_next_.load(); + return underlying_.next_.load(); } void JSValidIteratorWrapper::set_underlying_next(Tagged<JSAny> value, WriteBarrierMode mode) { - underlying_next_.store(this, value, mode); + underlying_.next_.store(this, value, mode); } double JSDate::value() const { return value_.value(); } @@ -870,11 +878,11 @@ void JSMessageObject::set_script(Tagged<Script> value, WriteBarrierMode mode) { script_.store(this, value, mode); } -Tagged<UnionOf<StackTraceInfo, Hole>> JSMessageObject::stack_trace() const { +Tagged<UnionOf<StackTraceInfo, TheHole>> JSMessageObject::stack_trace() const { return stack_trace_.load(); } void JSMessageObject::set_stack_trace( - Tagged<UnionOf<StackTraceInfo, Hole>> value, WriteBarrierMode mode) { + Tagged<UnionOf<StackTraceInfo, TheHole>> value, WriteBarrierMode mode) { stack_trace_.store(this, value, mode); } @@ -1125,7 +1133,12 @@ void JSObject::EnsureWritableFastElements(Isolate* isolate, std::optional<Tagged<NativeContext>> JSReceiver::GetCreationContext() const { DisallowGarbageCollection no_gc; Tagged<Map> meta_map = map()->map(); - DCHECK(IsMapMap(meta_map)); +#if V8_ENABLE_WEBASSEMBLY + if (!IsMetaMap(meta_map)) { + return GetCreationContext_Slow(map()); + } +#endif // V8_ENABLE_WEBASSEMBLY + DCHECK(IsMetaMap(meta_map)); Tagged<Object> maybe_native_context = meta_map->native_context_or_null(); if (V8_UNLIKELY(IsNull(maybe_native_context))) return {}; DCHECK(IsNativeContext(maybe_native_context)); diff --git a/deps/v8/src/objects/js-objects.cc b/deps/v8/src/objects/js-objects.cc index 69e7d3101a5d..21e47230fd38 100644 --- a/deps/v8/src/objects/js-objects.cc +++ b/deps/v8/src/objects/js-objects.cc @@ -42,7 +42,6 @@ #include "src/objects/heap-object.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-inl.h" -#include "src/objects/js-atomics-synchronization.h" #include "src/objects/js-collection.h" #include "src/objects/js-disposable-stack.h" #include "src/objects/js-generator-inl.h" @@ -84,7 +83,7 @@ #if V8_ENABLE_WEBASSEMBLY #include "src/debug/debug-wasm-objects.h" -#include "src/wasm/wasm-objects.h" +#include "src/wasm/wasm-objects-inl.h" #endif // V8_ENABLE_WEBASSEMBLY #ifdef V8_INTL_SUPPORT @@ -234,6 +233,52 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it, } } +// static +MaybeHandle<Object> JSReceiver::TryGetDataProperty(LookupIterator* it) { + for (;; it->Next()) { + switch (it->state()) { + case LookupIterator::TRANSITION: + case LookupIterator::STRING_LOOKUP_START_OBJECT: + UNREACHABLE(); + case LookupIterator::ACCESS_CHECK: + if (it->HasAccess()) continue; + return {}; + case LookupIterator::INTERCEPTOR: + case LookupIterator::JSPROXY: + return {}; + case LookupIterator::WASM_OBJECT: + continue; // Continue to the prototype, if present. + case LookupIterator::MODULE_NAMESPACE: + if (JSDeferredModuleNamespace::TriggersEvaluation(it)) return {}; + continue; + case LookupIterator::ACCESSOR: { + // Only AccessorInfos can behave like data properties. Getters of + // AccessorPairs are never called, not even API functions declared + // side-effect free, as script can install them on arbitrary objects. + DirectHandle<Object> accessors = it->GetAccessors(); + if (!IsAccessorInfo(*accessors) || + Cast<AccessorInfo>(*accessors)->getter_side_effect_type() != + SideEffectType::kHasNoSideEffect) { + return {}; + } + v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(it->isolate())); + try_catch.SetVerbose(false); + try_catch.SetCaptureMessage(false); + Handle<Object> result; + if (!Object::GetPropertyWithAccessor(it).ToHandle(&result)) return {}; + return result; + } + case LookupIterator::DATA: + // Unlike GetDataValue(), this also instantiates lazy closures. + return Object::GetProperty(it); + case LookupIterator::TYPED_ARRAY_INDEX_NOT_FOUND: + case LookupIterator::NOT_FOUND: + return {}; + } + UNREACHABLE(); + } +} + // static Maybe<bool> JSReceiver::HasInPrototypeChain(Isolate* isolate, DirectHandle<JSReceiver> object, @@ -282,7 +327,7 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it, : MessageTemplate::kInvalidPrivateFieldReinitialization; RETURN_FAILURE(isolate, GetShouldThrow(isolate, Nothing<ShouldThrow>()), - NewTypeError(message, name_string, it->GetReceiver())); + NewTypeError(message, name_string)); } return Just(true); case LookupIterator::WASM_OBJECT: @@ -293,7 +338,7 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it, RETURN_FAILURE( isolate, GetShouldThrow(isolate, Nothing<ShouldThrow>()), NewTypeError(MessageTemplate::kInvalidPrivateMemberWrite, - name_string, it->GetReceiver())); + name_string)); } else if (it->ExtendingNonExtensible( it->GetStoreTarget<JSReceiver>())) { @@ -597,8 +642,6 @@ Tagged<String> JSReceiver::class_name() { if (IsShared(this)) { if (Is<JSSharedStruct>(this)) return roots.SharedStruct_string(); if (Is<JSSharedArray>(this)) return roots.SharedArray_string(); - if (Is<JSAtomicsMutex>(this)) return roots.AtomicsMutex_string(); - if (Is<JSAtomicsCondition>(this)) return roots.AtomicsCondition_string(); #if V8_ENABLE_WEBASSEMBLY if (Is<WasmObject>(this)) return roots.Object_string(); #endif @@ -719,6 +762,17 @@ DirectHandle<String> JSReceiver::GetConstructorName( return GetConstructorHelper(isolate, receiver).second; } +// static +Tagged<NativeContext> JSReceiver::GetCreationContext_Slow(Tagged<Map> map) { + // Currently only WasmCustomMaps use this slow path. +#if V8_ENABLE_WEBASSEMBLY + DCHECK(IsWasmCustomMap(map)); + return Cast<WasmCustomMap>(map)->native_context_for_wrapper(); +#else + UNREACHABLE(); +#endif // V8_ENABLE_WEBASSEMBLY +} + // static MaybeDirectHandle<NativeContext> JSReceiver::GetFunctionRealm( DirectHandle<JSReceiver> receiver) { @@ -735,7 +789,10 @@ MaybeDirectHandle<NativeContext> JSReceiver::GetFunctionRealm( Tagged<JSProxy> proxy = Cast<JSProxy>(current); if (proxy->IsRevoked()) { AllowGarbageCollection allow_allocating_errors; - THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyRevoked)); + THROW_NEW_ERROR( + isolate, NewTypeError(MessageTemplate::kProxyRevoked, + isolate->factory()->NewStringFromAsciiChecked( + "GetFunctionRealm"))); } current = Cast<JSReceiver>(proxy->target()); continue; @@ -2524,8 +2581,6 @@ MaybeDirectHandle<JSObject> JSObject::ObjectCreate( Isolate* isolate, DirectHandle<JSPrototype> prototype) { // Generate the map with the specified {prototype} based on the Object // function's initial map from the current native context. - // TODO(bmeurer): Use a dedicated cache for Object.create; think about - // slack tracking for Object.create. DirectHandle<Map> map = Map::GetObjectCreateMap(isolate, prototype); // Actually allocate the object. @@ -2692,10 +2747,6 @@ int JSObject::GetHeaderSize(InstanceType type) { return JSSharedArray::kHeaderSize; case JS_SHARED_STRUCT_TYPE: return JSSharedStruct::kHeaderSize; - case JS_ATOMICS_MUTEX_TYPE: - return JSAtomicsMutex::kHeaderSize; - case JS_ATOMICS_CONDITION_TYPE: - return JSAtomicsCondition::kHeaderSize; #ifdef V8_TEMPORAL_SUPPORT case JS_TEMPORAL_DURATION_TYPE: return sizeof(JSTemporalDuration); @@ -3037,12 +3088,6 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) { case JS_SHARED_STRUCT_TYPE: accumulator->Add("<JSSharedStruct>"); break; - case JS_ATOMICS_MUTEX_TYPE: - accumulator->Add("<JSAtomicsMutex>"); - break; - case JS_ATOMICS_CONDITION_TYPE: - accumulator->Add("<JSAtomicsCondition>"); - break; case JS_MESSAGE_OBJECT_TYPE: accumulator->Add("<JSMessageObject>"); break; @@ -3253,7 +3298,7 @@ void MigrateFastToFast(Isolate* isolate, DirectHandle<JSObject> object, object->property_array()->length().value()) { // Allocate HeapNumbers for double fields. if (index.is_double()) { - auto value = isolate->factory()->NewHeapNumberWithHoleNaN(); + auto value = isolate->factory()->NewUninitializedHeapNumber(); object->FastPropertyAtPut(index, *value); } object->set_map(isolate, *new_map, kReleaseStore); @@ -3272,7 +3317,7 @@ void MigrateFastToFast(Isolate* isolate, DirectHandle<JSObject> object, // Properly initialize newly added property. DirectHandle<Object> value; if (details.representation().IsDouble()) { - value = isolate->factory()->NewHeapNumberWithHoleNaN(); + value = isolate->factory()->NewUninitializedHeapNumber(); } else { value = isolate->factory()->uninitialized_value(); } @@ -3333,14 +3378,14 @@ void MigrateFastToFast(Isolate* isolate, DirectHandle<JSObject> object, PropertyDetails old_details = old_descriptors->GetDetails(i); Representation old_representation = old_details.representation(); Representation representation = details.representation(); - Handle<UnionOf<JSAny, Hole>> value; + Handle<UnionOf<JSAny, Hole, UninitializedHeapNumber>> value; if (old_details.location() == PropertyLocation::kDescriptor) { if (old_details.kind() == PropertyKind::kAccessor) { // In case of kAccessor -> kData property reconfiguration, the property // must already be prepared for data of certain type. DCHECK(!details.representation().IsNone()); if (details.representation().IsDouble()) { - value = isolate->factory()->NewHeapNumberWithHoleNaN(); + value = isolate->factory()->NewUninitializedHeapNumber(); } else { value = isolate->factory()->uninitialized_value(); } @@ -3359,8 +3404,12 @@ void MigrateFastToFast(Isolate* isolate, DirectHandle<JSObject> object, IsUninitializedHole(*value)); value = Object::NewStorageFor(isolate, value, representation); } else if (old_representation.IsDouble() && !representation.IsDouble()) { - value = Object::WrapForRead(isolate, Cast<JSAny>(value), - old_representation); + if (IsUninitializedHeapNumber(*value)) { + value = isolate->factory()->uninitialized_value(); + } else { + value = Object::WrapForRead(isolate, Cast<JSAny>(value), + old_representation); + } } } DCHECK(!(representation.IsDouble() && IsSmi(*value))); @@ -3381,7 +3430,7 @@ void MigrateFastToFast(Isolate* isolate, DirectHandle<JSObject> object, DCHECK_EQ(PropertyKind::kData, details.kind()); DirectHandle<Object> value; if (details.representation().IsDouble()) { - value = isolate->factory()->NewHeapNumberWithHoleNaN(); + value = isolate->factory()->NewUninitializedHeapNumber(); } else { value = isolate->factory()->uninitialized_value(); } @@ -3471,9 +3520,16 @@ void MigrateFastToSlow(Isolate* isolate, DirectHandle<JSObject> object, if (details.kind() == PropertyKind::kData) { value = direct_handle(object->RawFastPropertyAt(index), isolate); if (details.representation().IsDouble()) { - DCHECK(IsHeapNumber(*value)); - double old_value = Cast<HeapNumber>(value)->value(); - value = isolate->factory()->NewHeapNumber(old_value); + if (IsUninitializedHeapNumber(*value)) { + // This might happen when we are migrating a half-initialized + // object literal in order to replace this property with an + // accessor pair. + value = isolate->factory()->uninitialized_value(); + } else { + DCHECK(IsHeapNumber(*value)); + double old_value = Cast<HeapNumber>(value)->value(); + value = isolate->factory()->NewHeapNumber(old_value); + } } } else { DCHECK_EQ(PropertyKind::kAccessor, details.kind()); @@ -3665,7 +3721,8 @@ void JSObject::AllocateStorageForMap(Isolate* isolate, Representation representation = details.representation(); if (!representation.IsDouble()) continue; FieldIndex index = FieldIndex::ForDetails(*map, details); - auto box = isolate->factory()->NewHeapNumberWithHoleNaN(); + auto box = isolate->factory()->NewUninitializedHeapNumber(); + if (index.is_inobject()) { storage->set(index.property_index(), *box); } else { @@ -3746,12 +3803,6 @@ bool TryFastAddDataProperty(Isolate* isolate, DirectHandle<JSObject> object, // loaded in PrepareForDataProperty. PropertyDetails details = new_map->instance_descriptors()->GetDetails(descriptor); - if (details.representation().IsDouble()) { - if (Tagged<HeapNumber> heap_number; - TryCast(*value, &heap_number) && std::isnan(heap_number->value())) { - value = isolate->factory()->nan_value(); - } - } object->WriteToField(descriptor, details, *value); return true; } @@ -5205,7 +5256,7 @@ void JSObject::LazyRegisterPrototypeUser(DirectHandle<Map> user, // Contract: In line with InvalidatePrototypeChains()'s requirements, // leaf maps don't need to register as users, only prototypes do. #if V8_ENABLE_WEBASSEMBLY - DCHECK(user->is_prototype_map() || IsWasmObjectMap(*user)); + DCHECK(user->is_prototype_map() || IsAnyWasmObjectMap(*user)); #else DCHECK(user->is_prototype_map()); #endif // V8_ENABLE_WEBASSEMBLY @@ -5281,7 +5332,7 @@ bool JSObject::UnregisterPrototypeUser(DirectHandle<Map> user, if (slot == PrototypeInfo::UNREGISTERED) return false; #if V8_ENABLE_WEBASSEMBLY DCHECK(prototype->map()->is_prototype_map() || - IsWasmObjectMap(prototype->map())); + IsAnyWasmObjectMap(prototype->map())); #else DCHECK(prototype->map()->is_prototype_map()); #endif // V8_ENABLE_WEBASSEMBLY @@ -5310,7 +5361,7 @@ namespace { // before jumping here. void InvalidateOnePrototypeValidityCellInternal(Tagged<Map> map) { #if V8_ENABLE_WEBASSEMBLY - DCHECK(map->is_prototype_map() || IsWasmObjectMap(map)); + DCHECK(map->is_prototype_map() || IsAnyWasmObjectMap(map)); #else DCHECK(map->is_prototype_map()); #endif // V8_ENABLE_WEBASSEMBLY diff --git a/deps/v8/src/objects/js-objects.h b/deps/v8/src/objects/js-objects.h index 558c07231460..3a7a2cb5a2c6 100644 --- a/deps/v8/src/objects/js-objects.h +++ b/deps/v8/src/objects/js-objects.h @@ -48,8 +48,8 @@ V8_OBJECT class JSReceiver : public HeapObject { public: using Properties = UnionOf<SwissNameDictionary, FixedArrayBase, PropertyArray>; - using PropertiesOrHash = UnionOf<SwissNameDictionary, FixedArrayBase, - PropertyArray, Smi, GlobalDictionary>; + using PropertiesOrHash = + UnionOf<SwissNameDictionary, FixedArrayBase, PropertyArray, Smi>; // Returns true if there is no slow (ie, dictionary) backing store. DECL_GETTER(HasFastProperties, bool) @@ -302,6 +302,8 @@ V8_OBJECT class JSReceiver : public HeapObject { GetCreationContext() const; V8_EXPORT_PRIVATE inline MaybeDirectHandle<NativeContext> GetCreationContext( Isolate* isolate) const; + V8_EXPORT_PRIVATE static Tagged<NativeContext> GetCreationContext_Slow( + Tagged<Map> map); V8_WARN_UNUSED_RESULT static inline Maybe<PropertyAttributes> GetPropertyAttributes(Isolate* isolate, DirectHandle<JSReceiver> object, @@ -337,6 +339,12 @@ V8_OBJECT class JSReceiver : public HeapObject { LookupIterator* it, AllowAllocation allow_allocation = AllowAllocation{true}); + // Like GetDataProperty, but returns an empty handle (without throwing) if + // the lookup doesn't end at a data property, or if completing it would + // require calling an interceptor, a proxy trap or any getter other than a + // side-effect free AccessorInfo getter. + static MaybeHandle<Object> TryGetDataProperty(LookupIterator* it); + // Retrieves a permanent object identity hash code. The undefined value might // be returned in case no hash was created yet. V8_EXPORT_PRIVATE Tagged<Object> GetIdentityHash(); @@ -1059,6 +1067,14 @@ static_assert(JSObject::kHeaderSize + JSObject::kMaxEmbedderFields * kEmbedderDataSlotSizeInTaggedSlots <= JSObject::kMaxInstanceSize); +// JSObject alias added only because of IsJSObjectExact() predicate, which +// checks for the exact instance type JS_OBJECT_TYPE instead of a range check: +// [FIRST_JS_OBJECT_TYPE, LAST_JS_OBJECT_TYPE]. +V8_OBJECT +class JSObjectExact final : public JSObject { + V8_IT_NO_AUTO_CHECKER; +} V8_OBJECT_END; + // An abstract superclass for JSObjects that may contain EmbedderDataSlots. // Carries no fields itself; the in-instance tail ([embedder fields] followed // by [in-object properties]) is managed by the Map + BodyDescriptor and never @@ -1431,14 +1447,14 @@ V8_OBJECT class JSDate : public JSObject { public: UnalignedDoubleMember value_; - TaggedMember<UnionOf<Smi, HeapNumber>> year_; - TaggedMember<UnionOf<Smi, HeapNumber>> month_; - TaggedMember<UnionOf<Smi, HeapNumber>> day_; - TaggedMember<UnionOf<Smi, HeapNumber>> weekday_; - TaggedMember<UnionOf<Smi, HeapNumber>> hour_; - TaggedMember<UnionOf<Smi, HeapNumber>> min_; - TaggedMember<UnionOf<Smi, HeapNumber>> sec_; - TaggedMember<UnionOf<Smi, HeapNumber>> cache_stamp_; + TaggedMember<UnionOf<Smi, NaN>> year_; + TaggedMember<UnionOf<Smi, NaN>> month_; + TaggedMember<UnionOf<Smi, NaN>> day_; + TaggedMember<UnionOf<Smi, NaN>> weekday_; + TaggedMember<UnionOf<Smi, NaN>> hour_; + TaggedMember<UnionOf<Smi, NaN>> min_; + TaggedMember<UnionOf<Smi, NaN>> sec_; + TaggedMember<UnionOf<Smi, NaN>> cache_stamp_; } V8_OBJECT_END; // Representation of message objects used for error reporting through @@ -1490,8 +1506,8 @@ V8_OBJECT class JSMessageObject : public JSObject { inline void set_script(Tagged<Script> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<UnionOf<StackTraceInfo, Hole>> stack_trace() const; - inline void set_stack_trace(Tagged<UnionOf<StackTraceInfo, Hole>> value, + inline Tagged<UnionOf<StackTraceInfo, TheHole>> stack_trace() const; + inline void set_stack_trace(Tagged<UnionOf<StackTraceInfo, TheHole>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline int error_level() const; @@ -1536,7 +1552,7 @@ V8_OBJECT class JSMessageObject : public JSObject { TaggedMember<Smi> message_type_; TaggedMember<Object> argument_; TaggedMember<Script> script_; - TaggedMember<UnionOf<StackTraceInfo, Hole>> stack_trace_; + TaggedMember<UnionOf<StackTraceInfo, TheHole>> stack_trace_; TaggedMember<UnionOf<SharedFunctionInfo, Smi>> shared_info_; // Raw data fields below (treated as non-pointers by BodyDescriptor). TaggedMember<Smi> bytecode_offset_; @@ -1598,6 +1614,13 @@ V8_OBJECT class JSStringIterator : public JSObject { // actual iterator with %Iterator.prototype%. V8_OBJECT class JSValidIteratorWrapper : public JSObject { public: + // Match iterator::IteratorRecord as one struct-typed field. Keep it nested + // because the CSA record already uses v8::internal::IteratorRecord. + struct IteratorRecord { + TaggedMember<JSReceiver> object_; + TaggedMember<JSAny> next_; + }; + // The [[Iterated]] slot, modelled as the two fields of an // iterator::IteratorRecord struct (object + next). inline Tagged<JSReceiver> underlying_object() const; @@ -1612,8 +1635,7 @@ V8_OBJECT class JSValidIteratorWrapper : public JSObject { DECL_VERIFIER(JSValidIteratorWrapper) public: - TaggedMember<JSReceiver> underlying_object_; - TaggedMember<JSAny> underlying_next_; + IteratorRecord underlying_; } V8_OBJECT_END; // JSPromiseWithResolversResult is just a JSObject with a specific initial map. diff --git a/deps/v8/src/objects/js-plural-rules-inl.h b/deps/v8/src/objects/js-plural-rules-inl.h index 6d395097d9b8..360b8020c8ae 100644 --- a/deps/v8/src/objects/js-plural-rules-inl.h +++ b/deps/v8/src/objects/js-plural-rules-inl.h @@ -13,6 +13,7 @@ // Include the non-inl header before the rest of the headers. #include "src/api/api-inl.h" +#include "src/objects/managed-inl.h" #include "src/objects/objects-inl.h" // Has to be the last include (doesn't have include guards): @@ -31,23 +32,12 @@ void JSPluralRules::set_flags(int value) { flags_.store(this, Smi::FromInt(value)); } -Tagged<Managed<icu::PluralRules>> JSPluralRules::icu_plural_rules() const { - return Cast<Managed<icu::PluralRules>>(icu_plural_rules_.load()); +Tagged<CppGCManaged<PluralRulesInternal>> JSPluralRules::internal() const { + return Cast<CppGCManaged<PluralRulesInternal>>(internal_.load()); } -void JSPluralRules::set_icu_plural_rules( - Tagged<Managed<icu::PluralRules>> value, WriteBarrierMode mode) { - icu_plural_rules_.store(this, value, mode); -} - -Tagged<Managed<icu::number::LocalizedNumberFormatter>> -JSPluralRules::icu_number_formatter() const { - return Cast<Managed<icu::number::LocalizedNumberFormatter>>( - icu_number_formatter_.load()); -} -void JSPluralRules::set_icu_number_formatter( - Tagged<Managed<icu::number::LocalizedNumberFormatter>> value, - WriteBarrierMode mode) { - icu_number_formatter_.store(this, value, mode); +void JSPluralRules::set_internal( + Tagged<CppGCManaged<PluralRulesInternal>> value, WriteBarrierMode mode) { + internal_.store(this, value, mode); } inline void JSPluralRules::set_type(Type type) { diff --git a/deps/v8/src/objects/js-plural-rules-internal.cc b/deps/v8/src/objects/js-plural-rules-internal.cc new file mode 100644 index 000000000000..98325fccffba --- /dev/null +++ b/deps/v8/src/objects/js-plural-rules-internal.cc @@ -0,0 +1,293 @@ +// Copyright 2026 the V8 project 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 V8_INTL_SUPPORT +#error Internationalization is expected to be enabled. +#endif // V8_INTL_SUPPORT + +#include "src/objects/js-plural-rules-internal.h" + +#include "src/execution/isolate-inl.h" +#include "src/objects/intl-objects.h" +#include "src/objects/js-number-format.h" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#include "unicode/locid.h" +#include "unicode/numberformatter.h" +#include "unicode/numberrangeformatter.h" +#include "unicode/plurrule.h" +#include "unicode/unumberformatter.h" +#pragma GCC diagnostic pop + + +namespace v8 { +namespace internal { + +namespace { + +bool CreateICUPluralRules(Isolate* isolate, const icu::Locale& icu_locale, + JSPluralRules::Type type, + std::unique_ptr<icu::PluralRules>* pl) { + // Make formatter from options. Numbering system is added + // to the locale as Unicode extension (if it was specified at all). + UErrorCode status = U_ZERO_ERROR; + + UPluralType icu_type = UPLURAL_TYPE_CARDINAL; + if (type == JSPluralRules::Type::ORDINAL) { + icu_type = UPLURAL_TYPE_ORDINAL; + } else { + DCHECK_EQ(JSPluralRules::Type::CARDINAL, type); + } + + std::unique_ptr<icu::PluralRules> plural_rules( + icu::PluralRules::forLocale(icu_locale, icu_type, status)); + if (U_FAILURE(status)) { + return false; + } + DCHECK_NOT_NULL(plural_rules.get()); + + *pl = std::move(plural_rules); + return true; +} + +icu::number::LocalizedNumberFormatter CreateICUNumberFormatter( + const icu::Locale& icu_locale, Intl::Notation notation, + Intl::CompactDisplay compact_display, + const Intl::NumberFormatDigitOptions& digit_options) { + icu::number::UnlocalizedNumberFormatter settings = + icu::number::UnlocalizedNumberFormatter().roundingMode(UNUM_ROUND_HALFUP); + // The default notation in ICU is Simple, which mapped from STANDARD + // so we can skip setting it. + if (notation != Intl::Notation::STANDARD) { + settings = + settings.notation(Intl::ToICUNotation(notation, compact_display)); + } + settings = + JSNumberFormat::SetDigitOptionsToFormatter(settings, digit_options); + return settings.locale(icu_locale); +} + +void CreateDataPropertyForOptions(Isolate* isolate, + DirectHandle<JSObject> options, + DirectHandle<Object> value, const char* key) { + DirectHandle<String> key_str = + isolate->factory()->NewStringFromAsciiChecked(key); + + // This is a brand new JSObject that shouldn't already have the same + // key so this shouldn't fail. + Maybe<bool> maybe = JSReceiver::CreateDataProperty(isolate, options, key_str, + value, Just(kDontThrow)); + DCHECK(maybe.FromJust()); + USE(maybe); +} + +void CreateDataPropertyForOptions(Isolate* isolate, + DirectHandle<JSObject> options, int value, + const char* key) { + DirectHandle<Smi> value_smi(Smi::FromInt(value), isolate); + CreateDataPropertyForOptions(isolate, options, value_smi, key); +} + +void PopulateResolvedOptionsFromSkeleton( + Isolate* isolate, DirectHandle<JSObject> options, + const icu::UnicodeString& skeleton, + DirectHandle<FixedArray> plural_categories) { + Factory* factory = isolate->factory(); + Intl::Notation notation = Intl::NotationFromSkeleton(skeleton); + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->notation_string(), + Intl::NotationAsString(isolate, notation), Just(kDontThrow)) + .FromJust()); + if (notation == Intl::Notation::COMPACT) { + // https://github.com/tc39/ecma402/issues/1031 + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->compactDisplay_string(), + Intl::CompactDisplayString(isolate, skeleton), Just(kDontThrow)) + .FromJust()); + } + + CreateDataPropertyForOptions( + isolate, options, + JSNumberFormat::MinimumIntegerDigitsFromSkeleton(skeleton), + "minimumIntegerDigits"); + int32_t min = 0, max = 0; + + if (JSNumberFormat::SignificantDigitsFromSkeleton(skeleton, &min, &max)) { + CreateDataPropertyForOptions(isolate, options, min, + "minimumSignificantDigits"); + CreateDataPropertyForOptions(isolate, options, max, + "maximumSignificantDigits"); + } else { + JSNumberFormat::FractionDigitsFromSkeleton(skeleton, &min, &max); + CreateDataPropertyForOptions(isolate, options, min, + "minimumFractionDigits"); + CreateDataPropertyForOptions(isolate, options, max, + "maximumFractionDigits"); + } + + // 7. Perform ! CreateDataProperty(options, "pluralCategories", + // CreateArrayFromList(pluralCategories)). + DirectHandle<JSArray> plural_categories_value = + factory->NewJSArrayWithElements(plural_categories); + CreateDataPropertyForOptions(isolate, options, plural_categories_value, + "pluralCategories"); + + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->roundingIncrement_string(), + JSNumberFormat::RoundingIncrement(isolate, skeleton), + Just(kDontThrow)) + .FromJust()); + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->roundingMode_string(), + JSNumberFormat::RoundingModeString(isolate, skeleton), + Just(kDontThrow)) + .FromJust()); + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->roundingPriority_string(), + JSNumberFormat::RoundingPriorityString(isolate, skeleton), + Just(kDontThrow)) + .FromJust()); + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->trailingZeroDisplay_string(), + JSNumberFormat::TrailingZeroDisplayString(isolate, skeleton), + Just(kDontThrow)) + .FromJust()); +} + +class ICU4CPluralRulesBackend final : public PluralRulesInternal { + public: + ICU4CPluralRulesBackend( + std::unique_ptr<icu::PluralRules> icu_plural_rules, + icu::number::LocalizedNumberFormatter icu_number_formatter) + : icu_plural_rules_(std::move(icu_plural_rules)), + icu_number_formatter_(std::move(icu_number_formatter)) {} + + static std::unique_ptr<ICU4CPluralRulesBackend> Create( + Isolate* isolate, const Intl::ResolvedLocale& resolved_locale, + JSPluralRules::Type type, Intl::Notation notation, + Intl::CompactDisplay compact_display, + const Intl::NumberFormatDigitOptions& digit_options) { + icu::Locale icu_locale = resolved_locale.icu_locale; + std::unique_ptr<icu::PluralRules> icu_plural_rules; + bool success = CreateICUPluralRules(isolate, icu_locale, type, + &icu_plural_rules); + if (!success || icu_plural_rules == nullptr) { + // Remove extensions and try again. + icu::Locale no_extension_locale(icu_locale.getBaseName()); + success = CreateICUPluralRules(isolate, no_extension_locale, type, + &icu_plural_rules); + icu_locale = no_extension_locale; + if (!success || icu_plural_rules == nullptr) { + return nullptr; + } + } + + icu::number::LocalizedNumberFormatter icu_number_formatter = + CreateICUNumberFormatter(icu_locale, notation, compact_display, + digit_options); + + return std::make_unique<ICU4CPluralRulesBackend>( + std::move(icu_plural_rules), std::move(icu_number_formatter)); + } + + MaybeDirectHandle<String> Select(Isolate* isolate, + double number) const override { + UErrorCode status = U_ZERO_ERROR; + icu::number::FormattedNumber formatted_number = + icu_number_formatter_.formatDouble(number, status); + DCHECK(U_SUCCESS(status)); + + icu::UnicodeString result = + icu_plural_rules_->select(formatted_number, status); + DCHECK(U_SUCCESS(status)); + + return Intl::ToString(isolate, result); + } + + MaybeDirectHandle<String> SelectRange(Isolate* isolate, + Tagged<String> locale_str, double x, + double y) const override { + Maybe<icu::number::LocalizedNumberRangeFormatter> maybe_range_formatter = + JSNumberFormat::GetRangeFormatter(isolate, locale_str, + icu_number_formatter_); + MAYBE_RETURN(maybe_range_formatter, MaybeDirectHandle<String>()); + + icu::number::LocalizedNumberRangeFormatter nrfmt = + maybe_range_formatter.FromJust(); + + UErrorCode status = U_ZERO_ERROR; + icu::number::FormattedNumberRange formatted = nrfmt.formatFormattableRange( + icu::Formattable(x), icu::Formattable(y), status); + + DCHECK(U_SUCCESS(status)); + icu::UnicodeString result = icu_plural_rules_->select(formatted, status); + DCHECK(U_SUCCESS(status)); + + return Intl::ToString(isolate, result); + } + + void PopulateResolvedOptions(Isolate* isolate, + DirectHandle<JSObject> options) const override { + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString skeleton = icu_number_formatter_.toSkeleton(status); + DCHECK(U_SUCCESS(status)); + + // 6. Let pluralCategories be a List of Strings containing all possible + // results of PluralRuleSelect for the selected locale pr.[[Locale]], sorted + // according to the following order: "zero", "one", "two", "few", "many", + // "other". + std::unique_ptr<icu::StringEnumeration> categories( + icu_plural_rules_->getKeywords(status)); + DCHECK(U_SUCCESS(status)); + int32_t count = categories->count(status); + DCHECK(U_SUCCESS(status)); + + Factory* factory = isolate->factory(); + DirectHandle<FixedArray> plural_categories = factory->NewFixedArray(count); + const std::vector<const char*> kCategories = {"zero", "one", "two", + "few", "many", "other"}; + int32_t index = 0; + std::for_each( + kCategories.cbegin(), kCategories.cend(), [&](const char* val) { + categories->reset(status); + DCHECK(U_SUCCESS(status)); + for (int32_t i = 0; i < count; i++) { + int32_t len; + const char* cat = categories->next(&len, status); + DCHECK(U_SUCCESS(status)); + if (cat == nullptr) break; + if (std::strcmp(val, cat) == 0) { + DirectHandle<String> value_string = + factory->NewStringFromAsciiChecked(val); + plural_categories->set(index++, *value_string); + break; + } + } + }); + DCHECK(count == index); + + PopulateResolvedOptionsFromSkeleton(isolate, options, skeleton, + plural_categories); + } + + private: + std::unique_ptr<icu::PluralRules> icu_plural_rules_; + icu::number::LocalizedNumberFormatter icu_number_formatter_; +}; + + +} // namespace + +// static +std::unique_ptr<PluralRulesInternal> PluralRulesInternal::Create( + Isolate* isolate, const Intl::ResolvedLocale& resolved_locale, + JSPluralRules::Type type, Intl::Notation notation, + Intl::CompactDisplay compact_display, + const Intl::NumberFormatDigitOptions& digit_options) { + return ICU4CPluralRulesBackend::Create( + isolate, resolved_locale, type, notation, compact_display, digit_options); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/objects/js-plural-rules-internal.h b/deps/v8/src/objects/js-plural-rules-internal.h new file mode 100644 index 000000000000..7698030cfcd1 --- /dev/null +++ b/deps/v8/src/objects/js-plural-rules-internal.h @@ -0,0 +1,51 @@ +// Copyright 2026 the V8 project 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 V8_OBJECTS_JS_PLURAL_RULES_INTERNAL_H_ +#define V8_OBJECTS_JS_PLURAL_RULES_INTERNAL_H_ + +#ifndef V8_INTL_SUPPORT +#error Internationalization is expected to be enabled. +#endif // V8_INTL_SUPPORT + +#include <memory> + +#include "include/v8-internal.h" +#include "src/objects/intl-objects.h" +#include "src/objects/js-plural-rules.h" + +namespace v8 { +namespace internal { + +// Abstract backend interface for Intl.PluralRules (ICU4C vs ICU4X). +// The active backend is selected once at construction time in +// PluralRulesInternal::Create so callers of JSPluralRules do not need to +// branch on backend flags. +class PluralRulesInternal { + public: + static constexpr ManagedTypeId kTypeID = + ManagedTypeId::kPluralRulesInternal; + + PluralRulesInternal() = default; + virtual ~PluralRulesInternal() = default; + + static std::unique_ptr<PluralRulesInternal> Create( + Isolate* isolate, const Intl::ResolvedLocale& resolved_locale, + JSPluralRules::Type type, Intl::Notation notation, + Intl::CompactDisplay compact_display, + const Intl::NumberFormatDigitOptions& digit_options); + + virtual MaybeDirectHandle<String> Select(Isolate* isolate, + double number) const = 0; + virtual MaybeDirectHandle<String> SelectRange(Isolate* isolate, + Tagged<String> locale_str, + double x, double y) const = 0; + virtual void PopulateResolvedOptions( + Isolate* isolate, DirectHandle<JSObject> options) const = 0; +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_OBJECTS_JS_PLURAL_RULES_INTERNAL_H_ diff --git a/deps/v8/src/objects/js-plural-rules.cc b/deps/v8/src/objects/js-plural-rules.cc index 6e7cccf3f20f..a6fec3275d73 100644 --- a/deps/v8/src/objects/js-plural-rules.cc +++ b/deps/v8/src/objects/js-plural-rules.cc @@ -10,51 +10,20 @@ #include "src/execution/isolate-inl.h" #include "src/objects/intl-objects.h" -#include "src/objects/js-number-format.h" #include "src/objects/js-plural-rules-inl.h" +#include "src/objects/js-plural-rules-internal.h" #include "src/objects/managed-inl.h" #include "src/objects/option-utils.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #include "unicode/locid.h" -#include "unicode/numberformatter.h" -#include "unicode/numberrangeformatter.h" #include "unicode/plurrule.h" -#include "unicode/unumberformatter.h" +#include "unicode/strenum.h" #pragma GCC diagnostic pop namespace v8 { namespace internal { -namespace { - -bool CreateICUPluralRules(Isolate* isolate, const icu::Locale& icu_locale, - JSPluralRules::Type type, - std::unique_ptr<icu::PluralRules>* pl) { - // Make formatter from options. Numbering system is added - // to the locale as Unicode extension (if it was specified at all). - UErrorCode status = U_ZERO_ERROR; - - UPluralType icu_type = UPLURAL_TYPE_CARDINAL; - if (type == JSPluralRules::Type::ORDINAL) { - icu_type = UPLURAL_TYPE_ORDINAL; - } else { - DCHECK_EQ(JSPluralRules::Type::CARDINAL, type); - } - - std::unique_ptr<icu::PluralRules> plural_rules( - icu::PluralRules::forLocale(icu_locale, icu_type, status)); - if (U_FAILURE(status)) { - return false; - } - DCHECK_NOT_NULL(plural_rules.get()); - - *pl = std::move(plural_rules); - return true; -} - -} // namespace - Handle<String> JSPluralRules::TypeAsString(Isolate* isolate) const { switch (type()) { case Type::CARDINAL: @@ -140,54 +109,23 @@ MaybeDirectHandle<JSPluralRules> JSPluralRules::New( DirectHandle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); - icu::Locale icu_locale = r.icu_locale; - icu::number::UnlocalizedNumberFormatter settings = - icu::number::UnlocalizedNumberFormatter().roundingMode(UNUM_ROUND_HALFUP); - - std::unique_ptr<icu::PluralRules> icu_plural_rules; - bool success = - CreateICUPluralRules(isolate, r.icu_locale, type, &icu_plural_rules); - if (!success || icu_plural_rules == nullptr) { - // Remove extensions and try again. - icu::Locale no_extension_locale(icu_locale.getBaseName()); - success = CreateICUPluralRules(isolate, no_extension_locale, type, - &icu_plural_rules); - icu_locale = no_extension_locale; - - if (!success || icu_plural_rules == nullptr) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); - } - } - - // The default notation in ICU is Simple, which mapped from STANDARD - // so we can skip setting it. - if (notation != Intl::Notation::STANDARD) { - settings = - settings.notation(Intl::ToICUNotation(notation, compact_display)); - } - - // 11. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3, + // 11. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3, // notation). Maybe<Intl::NumberFormatDigitOptions> maybe_digit_options = Intl::SetNumberFormatDigitOptions( isolate, options, 0, 3, notation == Intl::Notation::COMPACT, service); MAYBE_RETURN(maybe_digit_options, MaybeDirectHandle<JSPluralRules>()); Intl::NumberFormatDigitOptions digit_options = maybe_digit_options.FromJust(); - settings = - JSNumberFormat::SetDigitOptionsToFormatter(settings, digit_options); - icu::number::LocalizedNumberFormatter icu_number_formatter = - settings.locale(icu_locale); - - DirectHandle<Managed<icu::PluralRules>> managed_plural_rules = - Managed<icu::PluralRules>::From(isolate, 0, std::move(icu_plural_rules)); + std::unique_ptr<PluralRulesInternal> internal = PluralRulesInternal::Create( + isolate, r, type, notation, compact_display, digit_options); + if (internal == nullptr) { + THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); + } - DirectHandle<Managed<icu::number::LocalizedNumberFormatter>> - managed_number_formatter = - Managed<icu::number::LocalizedNumberFormatter>::From( - isolate, 0, - std::make_shared<icu::number::LocalizedNumberFormatter>( - icu_number_formatter)); + DirectHandle<CppGCManaged<PluralRulesInternal>> managed_internal = + CppGCManaged<PluralRulesInternal>::Create(isolate, 0, + std::move(internal)); // Now all properties are ready, so we can allocate the result object. DirectHandle<JSPluralRules> plural_rules = Cast<JSPluralRules>( @@ -201,8 +139,7 @@ MaybeDirectHandle<JSPluralRules> JSPluralRules::New( // 12. Set pluralRules.[[Locale]] to the value of r.[[locale]]. plural_rules->set_locale(*locale_str); - plural_rules->set_icu_plural_rules(*managed_plural_rules); - plural_rules->set_icu_number_formatter(*managed_number_formatter); + plural_rules->set_internal(*managed_internal); // 13. Return pluralRules. return plural_rules; @@ -210,51 +147,19 @@ MaybeDirectHandle<JSPluralRules> JSPluralRules::New( MaybeDirectHandle<String> JSPluralRules::ResolvePlural( Isolate* isolate, DirectHandle<JSPluralRules> plural_rules, double number) { - Managed<icu::PluralRules>::Ptr icu_plural_rules = - plural_rules->icu_plural_rules()->ptr(); - DCHECK_NOT_NULL(icu_plural_rules); - - Managed<icu::number::LocalizedNumberFormatter>::Ptr fmt = - plural_rules->icu_number_formatter()->ptr(); - DCHECK_NOT_NULL(fmt); - - UErrorCode status = U_ZERO_ERROR; - icu::number::FormattedNumber formatted_number = - fmt->formatDouble(number, status); - DCHECK(U_SUCCESS(status)); - - icu::UnicodeString result = - icu_plural_rules->select(formatted_number, status); - DCHECK(U_SUCCESS(status)); - - return Intl::ToString(isolate, result); + CppGCManaged<PluralRulesInternal>::Ptr internal = + plural_rules->internal()->ptr(); + DCHECK_NOT_NULL(internal.raw()); + return internal->Select(isolate, number); } MaybeDirectHandle<String> JSPluralRules::ResolvePluralRange( Isolate* isolate, DirectHandle<JSPluralRules> plural_rules, double x, double y) { - Managed<icu::PluralRules>::Ptr icu_plural_rules = - plural_rules->icu_plural_rules()->ptr(); - DCHECK_NOT_NULL(icu_plural_rules); - - Maybe<icu::number::LocalizedNumberRangeFormatter> maybe_range_formatter = - JSNumberFormat::GetRangeFormatter( - isolate, plural_rules->locale(), - *plural_rules->icu_number_formatter()->ptr()); - MAYBE_RETURN(maybe_range_formatter, MaybeDirectHandle<String>()); - - icu::number::LocalizedNumberRangeFormatter nrfmt = - maybe_range_formatter.FromJust(); - - UErrorCode status = U_ZERO_ERROR; - icu::number::FormattedNumberRange formatted = nrfmt.formatFormattableRange( - icu::Formattable(x), icu::Formattable(y), status); - - DCHECK(U_SUCCESS(status)); - icu::UnicodeString result = icu_plural_rules->select(formatted, status); - DCHECK(U_SUCCESS(status)); - - return Intl::ToString(isolate, result); + CppGCManaged<PluralRulesInternal>::Ptr internal = + plural_rules->internal()->ptr(); + DCHECK_NOT_NULL(internal.raw()); + return internal->SelectRange(isolate, plural_rules->locale(), x, y); } namespace { @@ -273,13 +178,6 @@ void CreateDataPropertyForOptions(Isolate* isolate, USE(maybe); } -void CreateDataPropertyForOptions(Isolate* isolate, - DirectHandle<JSObject> options, int value, - const char* key) { - DirectHandle<Smi> value_smi(Smi::FromInt(value), isolate); - CreateDataPropertyForOptions(isolate, options, value_smi, key); -} - } // namespace DirectHandle<JSObject> JSPluralRules::ResolvedOptions( @@ -293,108 +191,10 @@ DirectHandle<JSObject> JSPluralRules::ResolvedOptions( CreateDataPropertyForOptions(isolate, options, plural_rules->TypeAsString(isolate), "type"); - UErrorCode status = U_ZERO_ERROR; - Managed<icu::number::LocalizedNumberFormatter>::Ptr icu_number_formatter = - plural_rules->icu_number_formatter()->ptr(); - icu::UnicodeString skeleton = icu_number_formatter->toSkeleton(status); - DCHECK(U_SUCCESS(status)); - - Factory* factory = isolate->factory(); - Intl::Notation notation = Intl::NotationFromSkeleton(skeleton); - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->notation_string(), - Intl::NotationAsString(isolate, notation), Just(kDontThrow)) - .FromJust()); - if (notation == Intl::Notation::COMPACT) { - // https://github.com/tc39/ecma402/issues/1031 - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->compactDisplay_string(), - Intl::CompactDisplayString(isolate, skeleton), Just(kDontThrow)) - .FromJust()); - } - - CreateDataPropertyForOptions( - isolate, options, - JSNumberFormat::MinimumIntegerDigitsFromSkeleton(skeleton), - "minimumIntegerDigits"); - int32_t min = 0, max = 0; - - if (JSNumberFormat::SignificantDigitsFromSkeleton(skeleton, &min, &max)) { - CreateDataPropertyForOptions(isolate, options, min, - "minimumSignificantDigits"); - CreateDataPropertyForOptions(isolate, options, max, - "maximumSignificantDigits"); - } else { - JSNumberFormat::FractionDigitsFromSkeleton(skeleton, &min, &max); - CreateDataPropertyForOptions(isolate, options, min, - "minimumFractionDigits"); - CreateDataPropertyForOptions(isolate, options, max, - "maximumFractionDigits"); - } - - // 6. Let pluralCategories be a List of Strings containing all possible - // results of PluralRuleSelect for the selected locale pr.[[Locale]], sorted - // according to the following order: "zero", "one", "two", "few", "many", - // "other". - Managed<icu::PluralRules>::Ptr icu_plural_rules = - plural_rules->icu_plural_rules()->ptr(); - DCHECK_NOT_NULL(icu_plural_rules); - - std::unique_ptr<icu::StringEnumeration> categories( - icu_plural_rules->getKeywords(status)); - DCHECK(U_SUCCESS(status)); - int32_t count = categories->count(status); - DCHECK(U_SUCCESS(status)); - - DirectHandle<FixedArray> plural_categories = factory->NewFixedArray(count); - const std::vector<const char*> kCategories = {"zero", "one", "two", - "few", "many", "other"}; - int32_t index = 0; - std::for_each(kCategories.cbegin(), kCategories.cend(), [&](const char* val) { - categories->reset(status); - DCHECK(U_SUCCESS(status)); - for (int32_t i = 0; i < count; i++) { - int32_t len; - const char* cat = categories->next(&len, status); - DCHECK(U_SUCCESS(status)); - if (cat == nullptr) break; - if (std::strcmp(val, cat) == 0) { - DirectHandle<String> value_string = - factory->NewStringFromAsciiChecked(val); - plural_categories->set(index++, *value_string); - break; - } - } - }); - DCHECK(count == index); - - // 7. Perform ! CreateDataProperty(options, "pluralCategories", - // CreateArrayFromList(pluralCategories)). - DirectHandle<JSArray> plural_categories_value = - factory->NewJSArrayWithElements(plural_categories); - CreateDataPropertyForOptions(isolate, options, plural_categories_value, - "pluralCategories"); - - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->roundingIncrement_string(), - JSNumberFormat::RoundingIncrement(isolate, skeleton), - Just(kDontThrow)) - .FromJust()); - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->roundingMode_string(), - JSNumberFormat::RoundingModeString(isolate, skeleton), - Just(kDontThrow)) - .FromJust()); - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->roundingPriority_string(), - JSNumberFormat::RoundingPriorityString(isolate, skeleton), - Just(kDontThrow)) - .FromJust()); - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->trailingZeroDisplay_string(), - JSNumberFormat::TrailingZeroDisplayString(isolate, skeleton), - Just(kDontThrow)) - .FromJust()); + CppGCManaged<PluralRulesInternal>::Ptr internal = + plural_rules->internal()->ptr(); + DCHECK_NOT_NULL(internal.raw()); + internal->PopulateResolvedOptions(isolate, options); return options; } diff --git a/deps/v8/src/objects/js-plural-rules.h b/deps/v8/src/objects/js-plural-rules.h index e66c3014b202..2860ffc3466b 100644 --- a/deps/v8/src/objects/js-plural-rules.h +++ b/deps/v8/src/objects/js-plural-rules.h @@ -22,17 +22,11 @@ // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" -namespace U_ICU_NAMESPACE { -class PluralRules; -namespace number { -class LocalizedNumberFormatter; -class LocalizedNumberRangeFormatter; -} // namespace number -} // namespace U_ICU_NAMESPACE - namespace v8 { namespace internal { +class PluralRulesInternal; + V8_OBJECT class JSPluralRules : public JSObject { public: V8_WARN_UNUSED_RESULT static MaybeDirectHandle<JSPluralRules> New( @@ -74,16 +68,9 @@ V8_OBJECT class JSPluralRules : public JSObject { inline int flags() const; inline void set_flags(int value); - inline Tagged<Managed<icu::PluralRules>> icu_plural_rules() const; - inline void set_icu_plural_rules( - Tagged<Managed<icu::PluralRules>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - - inline Tagged<Managed<icu::number::LocalizedNumberFormatter>> - icu_number_formatter() const; - inline void set_icu_number_formatter( - Tagged<Managed<icu::number::LocalizedNumberFormatter>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline Tagged<CppGCManaged<PluralRulesInternal>> internal() const; + inline void set_internal(Tagged<CppGCManaged<PluralRulesInternal>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_VERIFIER(JSPluralRules) @@ -91,9 +78,8 @@ V8_OBJECT class JSPluralRules : public JSObject { public: TaggedMember<String> locale_; - TaggedMember<Smi> flags_; - TaggedMember<Foreign> icu_plural_rules_; - TaggedMember<Foreign> icu_number_formatter_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSPluralRulesFlags>); + TaggedMember<CppGCManaged<PluralRulesInternal>> internal_; } V8_OBJECT_END; inline constexpr int JSPluralRules::kHeaderSize = sizeof(JSPluralRules); diff --git a/deps/v8/src/objects/js-plural-rules.tq b/deps/v8/src/objects/js-plural-rules.tq index ed81e5016220..89c30b22d7a2 100644 --- a/deps/v8/src/objects/js-plural-rules.tq +++ b/deps/v8/src/objects/js-plural-rules.tq @@ -14,7 +14,5 @@ bitfield struct JSPluralRulesFlags extends uint31 { extern class JSPluralRules extends JSObject { locale: String; flags: SmiTagged<JSPluralRulesFlags>; - icu_plural_rules: Foreign; // Managed<icu::PluralRules> - icu_number_formatter: - Foreign; // Managed<icu::number::LocalizedNumberFormatter> + internal: CppGCManagedBase; // CppGCManaged<PluralRulesInternal> } diff --git a/deps/v8/src/objects/js-promise-inl.h b/deps/v8/src/objects/js-promise-inl.h index 464b9c0712de..6526e792e6b1 100644 --- a/deps/v8/src/objects/js-promise-inl.h +++ b/deps/v8/src/objects/js-promise-inl.h @@ -29,22 +29,20 @@ void JSPromise::set_reactions_or_result( reactions_or_result_.store(this, value, mode); } -int JSPromise::flags() const { return flags_.load().value(); } +JSPromise::Flags JSPromise::flags() const { return flags_.load(); } -void JSPromise::set_flags(int value) { - flags_.store(this, Smi::From31BitPattern(value)); -} +void JSPromise::set_flags(Flags value) { flags_.store(value); } BOOL_ACCESSORS(JSPromise, flags, is_native_resolver_invoked, - IsNativeResolverInvokedBit::kShift) -BOOL_ACCESSORS(JSPromise, flags, has_handler, HasHandlerBit::kShift) -BOOL_ACCESSORS(JSPromise, flags, is_silent, IsSilentBit::kShift) + Flags::IsNativeResolverInvokedBit::kShift) +BOOL_ACCESSORS(JSPromise, flags, has_handler, Flags::HasHandlerBit::kShift) +BOOL_ACCESSORS(JSPromise, flags, is_silent, Flags::IsSilentBit::kShift) // static uint32_t JSPromise::GetNextAsyncTaskId(uint32_t async_task_id) { do { ++async_task_id; - async_task_id &= AsyncTaskIdBits::kMax; + async_task_id &= Flags::AsyncTaskIdBits::kMax; } while (async_task_id == kInvalidAsyncTaskId); return async_task_id; } @@ -53,12 +51,10 @@ bool JSPromise::has_async_task_id() const { return async_task_id() != kInvalidAsyncTaskId; } -uint32_t JSPromise::async_task_id() const { - return AsyncTaskIdBits::decode(flags()); -} +uint32_t JSPromise::async_task_id() const { return flags().async_task_id(); } void JSPromise::set_async_task_id(uint32_t id) { - set_flags(AsyncTaskIdBits::update(flags(), id)); + set_flags(flags().with_async_task_id(id)); } Tagged<Object> JSPromise::result() const { diff --git a/deps/v8/src/objects/js-promise.h b/deps/v8/src/objects/js-promise.h index b76ea162d9f7..9c6f404386aa 100644 --- a/deps/v8/src/objects/js-promise.h +++ b/deps/v8/src/objects/js-promise.h @@ -8,6 +8,7 @@ #include "include/v8-promise.h" #include "src/base/bit-field.h" #include "src/handles/handles.h" +#include "src/objects/bit-field-group.h" #include "src/objects/js-function.h" #include "src/objects/js-objects.h" #include "src/objects/promise.h" @@ -37,8 +38,29 @@ V8_OBJECT class JSPromise : public JSObjectWithEmbedderSlots { Tagged<UnionOf<PromiseReaction, JSAny>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline int flags() const; - inline void set_flags(int value); + // Flags layout. + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + using StatusBits = First<Promise::PromiseState, 2>; + using IsNativeResolverInvokedBit = StatusBits::Next<bool, 1>; + using HasHandlerBit = IsNativeResolverInvokedBit::Next<bool, 1>; + using IsSilentBit = HasHandlerBit::Next<bool, 1>; + using AsyncTaskIdBits = IsSilentBit::Next<uint32_t, 26>; + + BIT_FIELD_GROUP_ACCESSORS(status, StatusBits) + BIT_FIELD_GROUP_ACCESSORS(is_native_resolver_invoked, + IsNativeResolverInvokedBit) + BIT_FIELD_GROUP_ACCESSORS(has_handler, HasHandlerBit) + BIT_FIELD_GROUP_ACCESSORS(is_silent, IsSilentBit) + BIT_FIELD_GROUP_ACCESSORS(async_task_id, AsyncTaskIdBits) + }; + + static_assert(v8::Promise::kPending == 0); + static_assert(v8::Promise::kFulfilled == 1); + static_assert(v8::Promise::kRejected == 2); + + inline Flags flags() const; + inline void set_flags(Flags value); // [result]: Checks that the promise is settled and returns the result. inline Tagged<Object> result() const; @@ -98,23 +120,11 @@ V8_OBJECT class JSPromise : public JSObjectWithEmbedderSlots { DECL_PRINTER(JSPromise) DECL_VERIFIER(JSPromise) - // Flags layout. - using StatusBits = base::BitField<Promise::PromiseState, 0, 2, uint32_t>; - using IsNativeResolverInvokedBit = StatusBits::Next<bool, 1>; - using HasHandlerBit = IsNativeResolverInvokedBit::Next<bool, 1>; - using IsSilentBit = HasHandlerBit::Next<bool, 1>; - using AsyncTaskIdBits = IsSilentBit::Next<uint32_t, 26>; - - static_assert(v8::Promise::kPending == 0); - static_assert(v8::Promise::kFulfilled == 1); - static_assert(v8::Promise::kRejected == 2); - public: // Smi 0 terminated list of PromiseReaction objects in case the JSPromise // was not settled yet, otherwise the result. TaggedMember<UnionOf<PromiseReaction, JSAny>> reactions_or_result_; - // SmiTagged<JSPromiseFlags>. - TaggedMember<Smi> flags_; + SmiBitFieldMember<Flags> flags_; private: // https://tc39.es/ecma262/#sec-triggerpromisereactions diff --git a/deps/v8/src/objects/js-promise.tq b/deps/v8/src/objects/js-promise.tq index 2e498caeb9a4..7bc9aed26d50 100644 --- a/deps/v8/src/objects/js-promise.tq +++ b/deps/v8/src/objects/js-promise.tq @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@cppScope('JSPromise') +@cppScope('JSPromise::Flags') bitfield struct JSPromiseFlags extends uint31 { - status: PromiseState: 2 bit; + status: PromisePromiseState: 2 bit; is_native_resolver_invoked: bool: 1 bit; has_handler: bool: 1 bit; is_silent: bool: 1 bit; @@ -13,13 +13,13 @@ bitfield struct JSPromiseFlags extends uint31 { @cppObjectLayoutDefinition extern class JSPromise extends JSObjectWithEmbedderSlots { - macro Status(): PromiseState { + macro Status(): PromisePromiseState { return this.flags.status; } - macro SetStatus(status: constexpr PromiseState): void { - dcheck(this.Status() == PromiseState::kPending); - dcheck(status != PromiseState::kPending); + macro SetStatus(status: constexpr PromisePromiseState): void { + dcheck(this.Status() == PromisePromiseState::kPending); + dcheck(status != PromisePromiseState::kPending); this.flags.status = status; } @@ -34,7 +34,7 @@ extern class JSPromise extends JSObjectWithEmbedderSlots { // Smi 0 terminated list of PromiseReaction objects in case the JSPromise was // not settled yet, otherwise the result. - reactions_or_result: Zero|PromiseReaction|JSAny; + reactions_or_result: PromiseReaction|JSAny; flags: SmiTagged<JSPromiseFlags>; } diff --git a/deps/v8/src/objects/js-proxy.h b/deps/v8/src/objects/js-proxy.h index a950e2da43bf..fb45a1f98170 100644 --- a/deps/v8/src/objects/js-proxy.h +++ b/deps/v8/src/objects/js-proxy.h @@ -89,7 +89,7 @@ V8_OBJECT class JSProxy : public JSReceiver { enum AccessKind { kGet, kSet }; - static MaybeHandle<JSAny> CheckGetSetTrapResult( + static MaybeDirectHandle<JSAny> CheckGetSetTrapResult( Isolate* isolate, DirectHandle<Name> name, DirectHandle<JSReceiver> target, DirectHandle<Object> trap_result, AccessKind access_kind); diff --git a/deps/v8/src/objects/js-regexp-inl.h b/deps/v8/src/objects/js-regexp-inl.h index b5e85bab236f..1a895956aaf4 100644 --- a/deps/v8/src/objects/js-regexp-inl.h +++ b/deps/v8/src/objects/js-regexp-inl.h @@ -15,7 +15,7 @@ #include "src/objects/string-inl.h" #include "src/objects/struct-inl.h" #include "src/objects/tagged-field-inl.h" -#include "src/objects/trusted-pointer-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -61,7 +61,7 @@ bool JSRegExp::has_data() const { return !data_.is_empty(); } bool JSRegExp::has_data_unpublished(IsolateForSandbox isolate) const { return TrustedPointerField::IsTrustedPointerFieldUnpublished( Tagged<HeapObject>(this), offsetof(JSRegExp, data_), - kRegExpDataIndirectPointerTag, isolate); + kRegExpDataTrustedPointerTag, isolate); } void JSRegExp::clear_data() { data_.clear(this); } @@ -74,7 +74,7 @@ const char* JSRegExp::FlagsToString(Flags flags, FlagsBuffer* out_buffer) { REGEXP_FLAG_LIST(V) #undef V buffer[cursor++] = '\0'; - return buffer.begin(); + return buffer.data(); } RegExpData::Type RegExpData::type_tag() const { @@ -163,6 +163,9 @@ int RegExpData::capture_count() const { UNREACHABLE(); } +RegExpDataWrapper::RegExpDataWrapper(const AllocationWitness& witness) + : Struct(witness.roots().regexp_data_wrapper_map()) {} + Tagged<RegExpData> RegExpDataWrapper::data(IsolateForSandbox isolate) const { return data_.load(isolate); } diff --git a/deps/v8/src/objects/js-regexp-string-iterator.h b/deps/v8/src/objects/js-regexp-string-iterator.h index 4abe84ece4a0..e6d0523c74e6 100644 --- a/deps/v8/src/objects/js-regexp-string-iterator.h +++ b/deps/v8/src/objects/js-regexp-string-iterator.h @@ -48,7 +48,7 @@ V8_OBJECT class JSRegExpStringIterator : public JSObject { TaggedMember<JSReceiver> iterating_reg_exp_; TaggedMember<String> iterated_string_; // SmiTagged<JSRegExpStringIteratorFlags>. - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSRegExpStringIteratorFlags>); } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/js-regexp.h b/deps/v8/src/objects/js-regexp.h index faf301817891..95a4a453f1dd 100644 --- a/deps/v8/src/objects/js-regexp.h +++ b/deps/v8/src/objects/js-regexp.h @@ -5,6 +5,7 @@ #ifndef V8_OBJECTS_JS_REGEXP_H_ #define V8_OBJECTS_JS_REGEXP_H_ +#include <array> #include <optional> #include <utility> @@ -80,10 +81,10 @@ V8_OBJECT class JSRegExp : public JSObject { return static_cast<Flag>(f); } static constexpr Flags AsJSRegExpFlags(regexp::Flags f) { - return Flags{static_cast<int>(f)}; + return Flags{static_cast<Flags::mask_type>(f)}; } static constexpr regexp::Flags AsRegExpFlags(Flags f) { - return regexp::Flags{static_cast<int>(f)}; + return regexp::Flags{static_cast<regexp::Flags::mask_type>(f)}; } static std::optional<regexp::Flag> FlagFromChar(char c) { @@ -162,7 +163,7 @@ V8_OBJECT class JSRegExp : public JSObject { // Maximum number of captures allowed. static constexpr int kMaxCaptures = 1 << 16; - using FlagsBuffer = base::EmbeddedVector<char, kFlagCount + 1>; + using FlagsBuffer = std::array<char, kFlagCount + 1>; inline static const char* FlagsToString(Flags flags, FlagsBuffer* out_buffer); class BodyDescriptor; @@ -174,8 +175,8 @@ V8_OBJECT class JSRegExp : public JSObject { friend class TorqueGeneratedJSRegExpAsserts; public: - TrustedPointerMember<RegExpData, kRegExpDataIndirectPointerTag> data_; - TaggedMember<Object> flags_; + TrustedPointerMember<RegExpData, kRegExpDataTrustedPointerTag> data_; + TaggedMember<Object> flags_ V8_TQ_TYPE(SmiTagged<JSRegExpFlags> | Undefined); } V8_OBJECT_END; inline constexpr int JSRegExp::kHeaderSize = sizeof(JSRegExp); @@ -292,6 +293,8 @@ V8_OBJECT class RegExpData : public ExposedTrustedObject { V8_OBJECT class RegExpDataWrapper : public Struct { public: + inline explicit RegExpDataWrapper(const AllocationWitness& witness); + DECL_TRUSTED_POINTER_ACCESSORS(data, RegExpData) DECL_PRINTER(RegExpDataWrapper) @@ -299,7 +302,7 @@ V8_OBJECT class RegExpDataWrapper : public Struct { class BodyDescriptor; - TrustedPointerMember<RegExpData, kRegExpDataIndirectPointerTag> data_; + TrustedPointerMember<RegExpData, kRegExpDataTrustedPointerTag> data_; } V8_OBJECT_END; V8_OBJECT class AtomRegExpData : public RegExpData { @@ -379,7 +382,7 @@ V8_OBJECT class IrRegExpData : public RegExpData { TaggedMember<Smi> capture_count_; TaggedMember<Smi> ticks_until_tier_up_; TaggedMember<Smi> backtrack_limit_; - TaggedMember<Smi> bit_field_; + TaggedMember<Smi> bit_field_ V8_TQ_TYPE(SmiTagged<IrRegExpDataBitField>); } V8_OBJECT_END; // JSRegExpResult is just a JSArray with a specific initial map. diff --git a/deps/v8/src/objects/js-regexp.tq b/deps/v8/src/objects/js-regexp.tq index 0ba458fcc4e1..241b0c144230 100644 --- a/deps/v8/src/objects/js-regexp.tq +++ b/deps/v8/src/objects/js-regexp.tq @@ -87,8 +87,8 @@ extern operator '.lastIndex=' macro RegExpBuiltinsAssembler::FastStoreLastIndex( const kJSRegExpRegExpDataOffset: constexpr int31 generates 'static_cast<int>(offsetof(JSRegExp, data_))'; -const kRegExpDataIndirectPointerTag: - constexpr uint64 generates 'kRegExpDataIndirectPointerTag'; +const kRegExpDataTrustedPointerTag: + constexpr uint64 generates 'kRegExpDataTrustedPointerTag'; extern macro RegExpBuiltinsAssembler::LoadRegExpDataFromObject( HeapObject, constexpr int31): RegExpData; diff --git a/deps/v8/src/objects/js-relative-time-format.h b/deps/v8/src/objects/js-relative-time-format.h index f7d67d95a440..6d012b89a0aa 100644 --- a/deps/v8/src/objects/js-relative-time-format.h +++ b/deps/v8/src/objects/js-relative-time-format.h @@ -101,7 +101,7 @@ V8_OBJECT class JSRelativeTimeFormat : public JSObject { TaggedMember<String> locale_; TaggedMember<String> numberingSystem_; TaggedMember<Foreign> icu_formatter_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSRelativeTimeFormatFlags>); } V8_OBJECT_END; inline constexpr int JSRelativeTimeFormat::kHeaderSize = diff --git a/deps/v8/src/objects/js-segment-iterator.h b/deps/v8/src/objects/js-segment-iterator.h index 9ea69716d4be..25438d11912b 100644 --- a/deps/v8/src/objects/js-segment-iterator.h +++ b/deps/v8/src/objects/js-segment-iterator.h @@ -72,7 +72,7 @@ V8_OBJECT class JSSegmentIterator : public JSObject { public: TaggedMember<CppGCManaged<IcuBreakIteratorWithText>> icu_iterator_with_text_; TaggedMember<String> raw_string_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSSegmentIteratorFlags>); } V8_OBJECT_END; inline constexpr int JSSegmentIterator::kHeaderSize = sizeof(JSSegmentIterator); diff --git a/deps/v8/src/objects/js-segmenter.h b/deps/v8/src/objects/js-segmenter.h index 0689d93bf0e0..9e4df8e227fe 100644 --- a/deps/v8/src/objects/js-segmenter.h +++ b/deps/v8/src/objects/js-segmenter.h @@ -87,7 +87,7 @@ V8_OBJECT class JSSegmenter : public JSObject { public: TaggedMember<String> locale_; TaggedMember<Foreign> icu_break_iterator_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSSegmenterFlags>); } V8_OBJECT_END; inline constexpr int JSSegmenter::kHeaderSize = sizeof(JSSegmenter); diff --git a/deps/v8/src/objects/js-segments.h b/deps/v8/src/objects/js-segments.h index 4a34b053f1d1..7675e562e695 100644 --- a/deps/v8/src/objects/js-segments.h +++ b/deps/v8/src/objects/js-segments.h @@ -83,7 +83,7 @@ V8_OBJECT class JSSegments : public JSObject { public: TaggedMember<CppGCManaged<IcuBreakIteratorWithText>> icu_iterator_with_text_; TaggedMember<String> raw_string_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSSegmentsFlags>); } V8_OBJECT_END; inline constexpr int JSSegments::kHeaderSize = sizeof(JSSegments); diff --git a/deps/v8/src/objects/js-temporal-objects-inl.h b/deps/v8/src/objects/js-temporal-objects-inl.h index 1cf3e0585561..4bc7d80805c5 100644 --- a/deps/v8/src/objects/js-temporal-objects-inl.h +++ b/deps/v8/src/objects/js-temporal-objects-inl.h @@ -14,6 +14,16 @@ #include "src/objects/objects-inl.h" // Rust includes to transitively include +#if __has_include("temporal/Duration.hpp") +#include "temporal/Duration.hpp" +#include "temporal/Instant.hpp" +#include "temporal/PlainDate.hpp" +#include "temporal/PlainDateTime.hpp" +#include "temporal/PlainMonthDay.hpp" +#include "temporal/PlainTime.hpp" +#include "temporal/PlainYearMonth.hpp" +#include "temporal/ZonedDateTime.hpp" +#else #include "temporal_rs/Duration.hpp" #include "temporal_rs/Instant.hpp" #include "temporal_rs/PlainDate.hpp" @@ -22,6 +32,7 @@ #include "temporal_rs/PlainTime.hpp" #include "temporal_rs/PlainYearMonth.hpp" #include "temporal_rs/ZonedDateTime.hpp" +#endif // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" diff --git a/deps/v8/src/objects/js-temporal-objects.cc b/deps/v8/src/objects/js-temporal-objects.cc index 8b2b0a7a39d3..cbe7fed5754e 100644 --- a/deps/v8/src/objects/js-temporal-objects.cc +++ b/deps/v8/src/objects/js-temporal-objects.cc @@ -28,9 +28,15 @@ #include "src/objects/property-descriptor.h" #include "src/objects/string-set.h" #include "src/strings/string-builder-inl.h" +#if __has_include("temporal/I128Nanoseconds.hpp") +#include "temporal/I128Nanoseconds.hpp" +#include "temporal/OwnedRelativeTo.hpp" +#include "temporal/Unit.hpp" +#else #include "temporal_rs/I128Nanoseconds.hpp" #include "temporal_rs/OwnedRelativeTo.hpp" #include "temporal_rs/Unit.hpp" +#endif #ifdef V8_INTL_SUPPORT #include "src/objects/intl-objects.h" #include "src/objects/js-date-time-format.h" diff --git a/deps/v8/src/objects/js-temporal-objects.h b/deps/v8/src/objects/js-temporal-objects.h index cb056823e562..a40cd24eea6f 100644 --- a/deps/v8/src/objects/js-temporal-objects.h +++ b/deps/v8/src/objects/js-temporal-objects.h @@ -10,6 +10,15 @@ #include "src/objects/js-temporal-helpers.h" #include "src/objects/managed.h" #include "src/objects/objects.h" +#if __has_include("temporal/Instant.d.hpp") +#include "temporal/Instant.d.hpp" +#include "temporal/PlainDate.d.hpp" +#include "temporal/PlainDateTime.d.hpp" +#include "temporal/PlainMonthDay.d.hpp" +#include "temporal/PlainTime.d.hpp" +#include "temporal/PlainYearMonth.d.hpp" +#include "temporal/TimeZone.d.hpp" +#else #include "temporal_rs/Instant.d.hpp" #include "temporal_rs/PlainDate.d.hpp" #include "temporal_rs/PlainDateTime.d.hpp" @@ -17,10 +26,16 @@ #include "temporal_rs/PlainTime.d.hpp" #include "temporal_rs/PlainYearMonth.d.hpp" #include "temporal_rs/TimeZone.d.hpp" +#endif // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" +namespace temporal {} +namespace temporal_rs { +using namespace ::temporal; +} // namespace temporal_rs + namespace v8 { namespace internal { diff --git a/deps/v8/src/objects/js-temporal-zoneinfo64.cc b/deps/v8/src/objects/js-temporal-zoneinfo64.cc index 007d63589c50..d4a36e52e23e 100644 --- a/deps/v8/src/objects/js-temporal-zoneinfo64.cc +++ b/deps/v8/src/objects/js-temporal-zoneinfo64.cc @@ -7,8 +7,13 @@ #include <iostream> #include "src/base/logging.h" +#if __has_include("temporal/Provider.hpp") +#include "temporal/Provider.hpp" +#include "temporal/TimeZone.hpp" +#else #include "temporal_rs/Provider.hpp" #include "temporal_rs/TimeZone.hpp" +#endif #ifdef V8_INTL_SUPPORT #ifndef V8_ENABLE_TEMPORAL_SYSTEMICU diff --git a/deps/v8/src/objects/js-temporal-zoneinfo64.h b/deps/v8/src/objects/js-temporal-zoneinfo64.h index 723f2162a82d..9610d397b7eb 100644 --- a/deps/v8/src/objects/js-temporal-zoneinfo64.h +++ b/deps/v8/src/objects/js-temporal-zoneinfo64.h @@ -5,7 +5,11 @@ #ifndef V8_OBJECTS_JS_TEMPORAL_ZONEINFO64_H_ #define V8_OBJECTS_JS_TEMPORAL_ZONEINFO64_H_ +#if __has_include("temporal/Provider.d.hpp") +#include "temporal/Provider.d.hpp" +#else #include "temporal_rs/Provider.d.hpp" +#endif #ifdef V8_INTL_SUPPORT #include "unicode/udata.h" @@ -13,6 +17,11 @@ #include <vector> #endif +namespace temporal {} +namespace temporal_rs { +using namespace ::temporal; +} // namespace temporal_rs + namespace v8::internal { // This class wraps timezone data, either loaded from ICU4C or static data, diff --git a/deps/v8/src/objects/js-weak-refs-inl.h b/deps/v8/src/objects/js-weak-refs-inl.h index e15fdc663d69..baa55b9b85e1 100644 --- a/deps/v8/src/objects/js-weak-refs-inl.h +++ b/deps/v8/src/objects/js-weak-refs-inl.h @@ -29,10 +29,10 @@ void JSFinalizationRegistry::set_native_context(Tagged<NativeContext> value, native_context_.store(this, value, mode); } -Tagged<JSReceiver> JSFinalizationRegistry::cleanup() const { +Tagged<JSCallable> JSFinalizationRegistry::cleanup() const { return cleanup_.load(); } -void JSFinalizationRegistry::set_cleanup(Tagged<JSReceiver> value, +void JSFinalizationRegistry::set_cleanup(Tagged<JSCallable> value, WriteBarrierMode mode) { cleanup_.store(this, value, mode); } diff --git a/deps/v8/src/objects/js-weak-refs.h b/deps/v8/src/objects/js-weak-refs.h index 136276a5ada9..ee827c740565 100644 --- a/deps/v8/src/objects/js-weak-refs.h +++ b/deps/v8/src/objects/js-weak-refs.h @@ -27,8 +27,8 @@ V8_OBJECT class JSFinalizationRegistry : public JSObject { inline void set_native_context(Tagged<NativeContext> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<JSReceiver> cleanup() const; - inline void set_cleanup(Tagged<JSReceiver> value, + inline Tagged<JSCallable> cleanup() const; + inline void set_cleanup(Tagged<JSCallable> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline Tagged<UnionOf<WeakCell, Undefined>> active_cells() const; @@ -115,12 +115,12 @@ V8_OBJECT class JSFinalizationRegistry : public JSObject { public: TaggedMember<NativeContext> native_context_; - TaggedMember<JSReceiver> cleanup_; + TaggedMember<JSCallable> cleanup_; TaggedMember<UnionOf<WeakCell, Undefined>> active_cells_; TaggedMember<UnionOf<WeakCell, Undefined>> cleared_cells_; TaggedMember<Object> key_map_; TaggedMember<UnionOf<JSFinalizationRegistry, Undefined>> next_dirty_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<FinalizationRegistryFlags>); friend class Heap; friend class TorqueGeneratedJSFinalizationRegistryAsserts; diff --git a/deps/v8/src/objects/keys.cc b/deps/v8/src/objects/keys.cc index d4aa5f6155d1..2b22a2de091d 100644 --- a/deps/v8/src/objects/keys.cc +++ b/deps/v8/src/objects/keys.cc @@ -189,11 +189,10 @@ ExceptionStatus KeyAccumulator::AddKeys(DirectHandle<FixedArray> array, return ExceptionStatus::kSuccess; } -ExceptionStatus KeyAccumulator::AddKeys(DirectHandle<JSObject> array_like, +ExceptionStatus KeyAccumulator::AddKeys(DirectHandle<JSArray> array, AddKeyConversion convert) { - DCHECK(IsJSArray(*array_like) || array_like->HasSloppyArgumentsElements()); - ElementsAccessor* accessor = array_like->GetElementsAccessor(); - return accessor->AddElementsToKeyAccumulator(array_like, this, convert); + ElementsAccessor* accessor = array->GetElementsAccessor(); + return accessor->AddElementsToKeyAccumulator(array, this, convert); } MaybeDirectHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator, @@ -452,11 +451,11 @@ MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, ONLY_ENUMERABLE); } - if (v8_flags.trace_for_in_enumerate) { - PrintF( - "| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n", - keys->ulength().value(), - result.ToHandleChecked()->ulength().value() - keys->ulength().value()); + Handle<FixedArray> result_array; + if (v8_flags.trace_for_in_enumerate && result.ToHandle(&result_array)) { + PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n", + keys->ulength().value(), + result_array->ulength().value() - keys->ulength().value()); } return result; } @@ -529,7 +528,7 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( // Do not try to use the enum-cache for dict-mode objects. if (map->is_dictionary_map()) { return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion, - skip_indices_); + skip_indices_ || !may_have_elements_); } int enum_length = receiver_->map()->EnumLength(); if (enum_length == kInvalidEnumCacheSentinel) { @@ -548,7 +547,7 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( // The properties-only case failed because there were probably elements on the // receiver. return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion, - skip_indices_); + skip_indices_ || !may_have_elements_); } // static @@ -747,8 +746,7 @@ bool FastKeyAccumulator::TryPrototypeInfoCache( V8_WARN_UNUSED_RESULT ExceptionStatus KeyAccumulator::FilterForEnumerableProperties( PropertyCallbackArguments& args, DirectHandle<InterceptorInfo> interceptor, - DirectHandle<JSObject> result, IndexedOrNamed type) { - DCHECK(IsJSArray(*result) || result->HasSloppyArgumentsElements()); + DirectHandle<JSArray> result, IndexedOrNamed type) { ElementsAccessor* accessor = result->GetElementsAccessor(); size_t length = accessor->GetCapacity(*result, result->elements()); @@ -791,7 +789,7 @@ Maybe<bool> KeyAccumulator::CollectInterceptorKeysInternal( if (!interceptor->has_enumerator()) { return Just(true); } - DirectHandle<JSObject> result; + DirectHandle<JSArray> result; { DirectHandle<JSObjectOrUndefined> maybe_result; if (type == kIndexed) { @@ -803,8 +801,7 @@ Maybe<bool> KeyAccumulator::CollectInterceptorKeysInternal( // An exception was thrown in the interceptor. Propagate. RETURN_VALUE_IF_EXCEPTION_DETECTOR(isolate_, args, Nothing<bool>()); if (IsUndefined(*maybe_result)) return Just(true); - DCHECK(IsJSObject(*maybe_result)); - result = Cast<JSObject>(maybe_result); + result = Cast<JSArray>(maybe_result); } // Request was successfully intercepted, so accept potential side effects // happened up to this point. @@ -813,7 +810,7 @@ Maybe<bool> KeyAccumulator::CollectInterceptorKeysInternal( if ((filter_ & ONLY_ENUMERABLE) && interceptor->has_query()) { // Create a new handle for the result object, since we are going to reuse // |args| object where |result| handle is currently located. - result = direct_handle(Cast<JSObject>(*result), isolate_); + result = direct_handle(*result, isolate_); RETURN_NOTHING_IF_NOT_SUCCESSFUL( FilterForEnumerableProperties(args, interceptor, result, type)); } else { diff --git a/deps/v8/src/objects/keys.h b/deps/v8/src/objects/keys.h index 9c3393713d84..d46ef7390f2c 100644 --- a/deps/v8/src/objects/keys.h +++ b/deps/v8/src/objects/keys.h @@ -119,15 +119,15 @@ class KeyAccumulator final { V8_WARN_UNUSED_RESULT ExceptionStatus FilterForEnumerableProperties( PropertyCallbackArguments& args, - DirectHandle<InterceptorInfo> interceptor, DirectHandle<JSObject> result, + DirectHandle<InterceptorInfo> interceptor, DirectHandle<JSArray> result, IndexedOrNamed type); Maybe<bool> AddKeysFromJSProxy(DirectHandle<JSProxy> proxy, DirectHandle<FixedArray> keys); V8_WARN_UNUSED_RESULT ExceptionStatus AddKeys(DirectHandle<FixedArray> array, AddKeyConversion convert); - V8_WARN_UNUSED_RESULT ExceptionStatus - AddKeys(DirectHandle<JSObject> array_like, AddKeyConversion convert); + V8_WARN_UNUSED_RESULT ExceptionStatus AddKeys(DirectHandle<JSArray> array, + AddKeyConversion convert); bool IsShadowed(DirectHandle<Object> key); bool HasShadowingKeys(); diff --git a/deps/v8/src/objects/literal-objects-inl.h b/deps/v8/src/objects/literal-objects-inl.h index 62b00c74bde1..f5e3dc353594 100644 --- a/deps/v8/src/objects/literal-objects-inl.h +++ b/deps/v8/src/objects/literal-objects-inl.h @@ -10,6 +10,7 @@ #include <optional> +#include "src/objects/heap-object-set-map-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/trusted-object-inl.h" @@ -90,87 +91,72 @@ int ObjectBoilerplateDescription::boilerplate_properties_count() const { // ClassBoilerplate // +ClassBoilerplate::ClassBoilerplate( + const AllocationWitness& witness, int arguments_count, + Tagged<Object> static_properties_template, + Tagged<Object> static_elements_template, + Tagged<FixedArray> static_computed_properties, + Tagged<Object> instance_properties_template, + Tagged<Object> instance_elements_template, + Tagged<FixedArray> instance_computed_properties) + : Struct(witness.roots().class_boilerplate_map()), + arguments_count_(Smi::FromInt(arguments_count)), + static_properties_template_(witness, static_properties_template), + static_elements_template_(witness, static_elements_template), + static_computed_properties_(witness, static_computed_properties), + instance_properties_template_(witness, instance_properties_template), + instance_elements_template_(witness, instance_elements_template), + instance_computed_properties_(witness, instance_computed_properties) {} + int ClassBoilerplate::arguments_count() const { return arguments_count_.load().value(); } -void ClassBoilerplate::set_arguments_count(int value) { - arguments_count_.store(this, Smi::FromInt(value)); -} Tagged<Object> ClassBoilerplate::static_properties_template() const { return static_properties_template_.load(); } -void ClassBoilerplate::set_static_properties_template(Tagged<Object> value, - WriteBarrierMode mode) { - static_properties_template_.store(this, value, mode); -} Tagged<Object> ClassBoilerplate::static_elements_template() const { return static_elements_template_.load(); } -void ClassBoilerplate::set_static_elements_template(Tagged<Object> value, - WriteBarrierMode mode) { - static_elements_template_.store(this, value, mode); -} Tagged<FixedArray> ClassBoilerplate::static_computed_properties() const { return static_computed_properties_.load(); } -void ClassBoilerplate::set_static_computed_properties(Tagged<FixedArray> value, - WriteBarrierMode mode) { - static_computed_properties_.store(this, value, mode); -} Tagged<Object> ClassBoilerplate::instance_properties_template() const { return instance_properties_template_.load(); } -void ClassBoilerplate::set_instance_properties_template(Tagged<Object> value, - WriteBarrierMode mode) { - instance_properties_template_.store(this, value, mode); -} Tagged<Object> ClassBoilerplate::instance_elements_template() const { return instance_elements_template_.load(); } -void ClassBoilerplate::set_instance_elements_template(Tagged<Object> value, - WriteBarrierMode mode) { - instance_elements_template_.store(this, value, mode); -} Tagged<FixedArray> ClassBoilerplate::instance_computed_properties() const { return instance_computed_properties_.load(); } -void ClassBoilerplate::set_instance_computed_properties( - Tagged<FixedArray> value, WriteBarrierMode mode) { - instance_computed_properties_.store(this, value, mode); -} // // ArrayBoilerplateDescription // +ArrayBoilerplateDescription::ArrayBoilerplateDescription( + const AllocationWitness& witness, ElementsKind elements_kind, + Tagged<FixedArrayBase> constant_values) + : Struct(witness.roots().array_boilerplate_description_map()), + flags_(Smi::FromInt(elements_kind)), + constant_elements_(witness, constant_values) {} + Tagged<Smi> ArrayBoilerplateDescription::flags() const { return flags_.load(); } -void ArrayBoilerplateDescription::set_flags(Tagged<Smi> value, - WriteBarrierMode mode) { - flags_.store(this, value, mode); -} Tagged<FixedArrayBase> ArrayBoilerplateDescription::constant_elements() const { return constant_elements_.load(); } -void ArrayBoilerplateDescription::set_constant_elements( - Tagged<FixedArrayBase> value, WriteBarrierMode mode) { - constant_elements_.store(this, value, mode); -} ElementsKind ArrayBoilerplateDescription::elements_kind() const { return static_cast<ElementsKind>(flags().value()); } -void ArrayBoilerplateDescription::set_elements_kind(ElementsKind kind) { - set_flags(Smi::FromInt(kind)); -} - bool ArrayBoilerplateDescription::is_empty() const { return constant_elements()->ulength().value() == 0; } @@ -179,48 +165,45 @@ bool ArrayBoilerplateDescription::is_empty() const { // RegExpBoilerplateDescription // +RegExpBoilerplateDescription::RegExpBoilerplateDescription( + const AllocationWitness& witness, Tagged<RegExpData> data, + Tagged<Smi> flags) + : Struct(witness.roots().regexp_boilerplate_description_map()), + data_(witness, data), + flags_(flags) {} + Tagged<RegExpData> RegExpBoilerplateDescription::data( IsolateForSandbox isolate) const { return data_.load(isolate); } -void RegExpBoilerplateDescription::set_data(Tagged<RegExpData> value, - WriteBarrierMode mode) { - data_.store(this, value, mode); -} - int RegExpBoilerplateDescription::flags() const { return flags_.load().value(); } -void RegExpBoilerplateDescription::set_flags(int value) { - flags_.store(this, Smi::FromInt(value)); -} + +PrototypeSharedClosureInfo::PrototypeSharedClosureInfo( + const AllocationWitness& witness, + Tagged<ObjectBoilerplateDescription> boilerplate_description, + Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array, + Tagged<Context> context) + : Struct(witness.roots().prototype_shared_closure_info_map()), + boilerplate_description_(witness, boilerplate_description), + closure_feedback_cell_array_(witness, closure_feedback_cell_array), + context_(witness, context) {} Tagged<ObjectBoilerplateDescription> PrototypeSharedClosureInfo::boilerplate_description() const { return boilerplate_description_.load(); } -void PrototypeSharedClosureInfo::set_boilerplate_description( - Tagged<ObjectBoilerplateDescription> value, WriteBarrierMode mode) { - boilerplate_description_.store(this, value, mode); -} Tagged<ClosureFeedbackCellArray> PrototypeSharedClosureInfo::closure_feedback_cell_array() const { return closure_feedback_cell_array_.load(); } -void PrototypeSharedClosureInfo::set_closure_feedback_cell_array( - Tagged<ClosureFeedbackCellArray> value, WriteBarrierMode mode) { - closure_feedback_cell_array_.store(this, value, mode); -} Tagged<Context> PrototypeSharedClosureInfo::context() const { return context_.load(); } -void PrototypeSharedClosureInfo::set_context(Tagged<Context> value, - WriteBarrierMode mode) { - context_.store(this, value, mode); -} } // namespace v8::internal diff --git a/deps/v8/src/objects/literal-objects.cc b/deps/v8/src/objects/literal-objects.cc index d80b23203b8a..969c2dbe8687 100644 --- a/deps/v8/src/objects/literal-objects.cc +++ b/deps/v8/src/objects/literal-objects.cc @@ -9,7 +9,7 @@ #include "src/builtins/accessors.h" #include "src/common/globals.h" #include "src/execution/isolate.h" -#include "src/heap/factory.h" +#include "src/heap/factory-inl.h" #include "src/heap/local-factory-inl.h" #include "src/objects/dictionary-inl.h" #include "src/objects/hash-table-inl.h" @@ -807,20 +807,14 @@ Handle<ClassBoilerplate> ClassBoilerplate::New(IsolateT* isolate, static_desc.Finalize(isolate); instance_desc.Finalize(isolate); - auto result = Cast<ClassBoilerplate>( - factory->NewStruct(CLASS_BOILERPLATE_TYPE, allocation)); - - result->set_arguments_count(dynamic_argument_index); - - result->set_static_properties_template(*static_desc.properties_template()); - result->set_static_elements_template(*static_desc.elements_template()); - result->set_static_computed_properties(*static_desc.computed_properties()); - - result->set_instance_properties_template( - *instance_desc.properties_template()); - result->set_instance_elements_template(*instance_desc.elements_template()); - result->set_instance_computed_properties( - *instance_desc.computed_properties()); + Handle<ClassBoilerplate> result = indirect_handle( + factory->template New<ClassBoilerplate>( + allocation, dynamic_argument_index, static_desc.properties_template(), + static_desc.elements_template(), static_desc.computed_properties(), + instance_desc.properties_template(), + instance_desc.elements_template(), + instance_desc.computed_properties()), + isolate); return scope.CloseAndEscape(result); } diff --git a/deps/v8/src/objects/literal-objects.h b/deps/v8/src/objects/literal-objects.h index 27b5bf5b0ddc..1f5bf2f96b89 100644 --- a/deps/v8/src/objects/literal-objects.h +++ b/deps/v8/src/objects/literal-objects.h @@ -11,7 +11,7 @@ #include "src/objects/fixed-array.h" #include "src/objects/objects-body-descriptors.h" #include "src/objects/struct.h" -#include "src/objects/trusted-pointer.h" +#include "src/sandbox/trusted-pointer.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -21,22 +21,19 @@ namespace internal { class ClassLiteral; class StructBodyDescriptor; +class SandboxTesting; V8_OBJECT class PrototypeSharedClosureInfo : public Struct { public: - inline Tagged<ObjectBoilerplateDescription> boilerplate_description() const; - inline void set_boilerplate_description( - Tagged<ObjectBoilerplateDescription> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline PrototypeSharedClosureInfo( + const AllocationWitness& witness, + Tagged<ObjectBoilerplateDescription> boilerplate_description, + Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array, + Tagged<Context> context); + inline Tagged<ObjectBoilerplateDescription> boilerplate_description() const; inline Tagged<ClosureFeedbackCellArray> closure_feedback_cell_array() const; - inline void set_closure_feedback_cell_array( - Tagged<ClosureFeedbackCellArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Context> context() const; - inline void set_context(Tagged<Context> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_PRINTER(PrototypeSharedClosureInfo) DECL_VERIFIER(PrototypeSharedClosureInfo) @@ -44,9 +41,9 @@ V8_OBJECT class PrototypeSharedClosureInfo : public Struct { using BodyDescriptor = StructBodyDescriptor; public: - TaggedMember<ObjectBoilerplateDescription> boilerplate_description_; - TaggedMember<ClosureFeedbackCellArray> closure_feedback_cell_array_; - TaggedMember<Context> context_; + const TaggedMember<ObjectBoilerplateDescription> boilerplate_description_; + const TaggedMember<ClosureFeedbackCellArray> closure_feedback_cell_array_; + const TaggedMember<Context> context_; } V8_OBJECT_END; // ObjectBoilerplateDescription is a list of properties consisting of name @@ -104,13 +101,17 @@ V8_OBJECT class ObjectBoilerplateDescription // length_ / optional_padding_ live in FixedArrayBase. TaggedMember<Smi> backing_store_size_; TaggedMember<Smi> flags_; + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); } V8_OBJECT_END; V8_OBJECT class ArrayBoilerplateDescription : public Struct { public: + inline ArrayBoilerplateDescription(const AllocationWitness& witness, + ElementsKind elements_kind, + Tagged<FixedArrayBase> constant_values); + inline ElementsKind elements_kind() const; - inline void set_elements_kind(ElementsKind kind); inline bool is_empty() const; @@ -122,34 +123,28 @@ V8_OBJECT class ArrayBoilerplateDescription : public Struct { using BodyDescriptor = StructBodyDescriptor; inline Tagged<Smi> flags() const; - inline void set_flags(Tagged<Smi> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<FixedArrayBase> constant_elements() const; - inline void set_constant_elements( - Tagged<FixedArrayBase> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); private: friend class Factory; friend class TorqueGeneratedArrayBoilerplateDescriptionAsserts; friend class V8HeapExplorer; - TaggedMember<Smi> flags_; - TaggedMember<FixedArrayBase> constant_elements_; + const TaggedMember<Smi> flags_; + const TaggedMember<FixedArrayBase> constant_elements_; } V8_OBJECT_END; V8_OBJECT class RegExpBoilerplateDescription : public Struct { public: + inline RegExpBoilerplateDescription(const AllocationWitness& witness, + Tagged<RegExpData> data, + Tagged<Smi> flags); + // Dispatched behavior. void BriefPrintDetails(std::ostream& os); inline Tagged<RegExpData> data(IsolateForSandbox isolate) const; - inline void set_data(Tagged<RegExpData> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline int flags() const; - inline void set_flags(int value); DECL_PRINTER(RegExpBoilerplateDescription) DECL_VERIFIER(RegExpBoilerplateDescription) @@ -161,8 +156,8 @@ V8_OBJECT class RegExpBoilerplateDescription : public Struct { friend class ConstructorBuiltinsAssembler; friend struct ObjectTraits<RegExpBoilerplateDescription>; - TrustedPointerMember<RegExpData, kRegExpDataIndirectPointerTag> data_; - TaggedMember<Smi> flags_; + const TrustedPointerMember<RegExpData, kRegExpDataTrustedPointerTag> data_; + const TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<JSRegExpFlags>); } V8_OBJECT_END; template <> @@ -172,7 +167,7 @@ struct ObjectTraits<RegExpBoilerplateDescription> { sizeof(RegExpBoilerplateDescription), sizeof(RegExpBoilerplateDescription)>, WithStrongTrustedPointer<offsetof(RegExpBoilerplateDescription, data_), - kRegExpDataIndirectPointerTag>>; + kRegExpDataTrustedPointerTag>>; }; V8_OBJECT class ClassBoilerplate : public Struct { @@ -199,37 +194,26 @@ V8_OBJECT class ClassBoilerplate : public Struct { static const int kMinimumClassPropertiesCount = 6; static const int kMinimumPrototypePropertiesCount = 1; + inline ClassBoilerplate(const AllocationWitness& witness, int arguments_count, + Tagged<Object> static_properties_template, + Tagged<Object> static_elements_template, + Tagged<FixedArray> static_computed_properties, + Tagged<Object> instance_properties_template, + Tagged<Object> instance_elements_template, + Tagged<FixedArray> instance_computed_properties); + template <typename IsolateT> static Handle<ClassBoilerplate> New( IsolateT* isolate, ClassLiteral* expr, AllocationType allocation = AllocationType::kYoung); inline int arguments_count() const; - inline void set_arguments_count(int value); - inline Tagged<Object> static_properties_template() const; - inline void set_static_properties_template( - Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> static_elements_template() const; - inline void set_static_elements_template( - Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<FixedArray> static_computed_properties() const; - inline void set_static_computed_properties( - Tagged<FixedArray> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> instance_properties_template() const; - inline void set_instance_properties_template( - Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> instance_elements_template() const; - inline void set_instance_elements_template( - Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<FixedArray> instance_computed_properties() const; - inline void set_instance_computed_properties( - Tagged<FixedArray> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); template <typename IsolateT, typename Dictionary> static void AddToPropertiesTemplate(IsolateT* isolate, @@ -251,14 +235,15 @@ V8_OBJECT class ClassBoilerplate : public Struct { private: friend class Factory; friend class TorqueGeneratedClassBoilerplateAsserts; - - TaggedMember<Smi> arguments_count_; - TaggedMember<Object> static_properties_template_; - TaggedMember<Object> static_elements_template_; - TaggedMember<FixedArray> static_computed_properties_; - TaggedMember<Object> instance_properties_template_; - TaggedMember<Object> instance_elements_template_; - TaggedMember<FixedArray> instance_computed_properties_; + friend class SandboxTesting; + + const TaggedMember<Smi> arguments_count_; + const TaggedMember<Object> static_properties_template_; + const TaggedMember<Object> static_elements_template_; + const TaggedMember<FixedArray> static_computed_properties_; + const TaggedMember<Object> instance_properties_template_; + const TaggedMember<Object> instance_elements_template_; + const TaggedMember<FixedArray> instance_computed_properties_; } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/literal-objects.tq b/deps/v8/src/objects/literal-objects.tq index faff8fb2f76d..ee0b85728139 100644 --- a/deps/v8/src/objects/literal-objects.tq +++ b/deps/v8/src/objects/literal-objects.tq @@ -6,7 +6,7 @@ extern class ObjectBoilerplateDescription extends FixedArrayBase { backing_store_size: Smi; flags: Smi; - raw_entries[length]: Object; + objects[length]: Object; } @cppObjectLayoutDefinition diff --git a/deps/v8/src/objects/lookup-inl.h b/deps/v8/src/objects/lookup-inl.h index c3413668255e..a9311e30783b 100644 --- a/deps/v8/src/objects/lookup-inl.h +++ b/deps/v8/src/objects/lookup-inl.h @@ -296,7 +296,7 @@ bool LookupIterator::ExtendingNonExtensible(DirectHandle<JSReceiver> receiver) { } #if V8_ENABLE_WEBASSEMBLY // Wasm objects have a fixed layout and must never transition their map. - if (IsWasmObjectMap(receiver_map)) { + if (IsAnyWasmObjectMap(receiver_map)) { return true; } #endif // V8_ENABLE_WEBASSEMBLY diff --git a/deps/v8/src/objects/lookup.cc b/deps/v8/src/objects/lookup.cc index 872d78cc45bd..27bd8794c838 100644 --- a/deps/v8/src/objects/lookup.cc +++ b/deps/v8/src/objects/lookup.cc @@ -480,12 +480,6 @@ void LookupIterator::PrepareForDataProperty(DirectHandle<Object> value) { // Check that current value matches new value otherwise we should make // the property mutable. if (holder->HasFastProperties()) { - if (property_details_.representation().IsDouble() && IsNumber(*value)) { - double v = Object::NumberValue(*value); - if (std::isnan(v)) { - value = isolate_->factory()->nan_value(); - } - } if (!CanStayConst(*value)) new_constness = PropertyConstness::kMutable; } else if (V8_DICT_PROPERTY_CONST_TRACKING_BOOL) { if (!DictCanStayConst(*value)) { @@ -1057,13 +1051,12 @@ bool LookupIterator::CanStayConst(Tagged<Object> value) const { FieldIndex::ForDetails(holder->map(), property_details_); if (property_details_.representation().IsDouble()) { if (!IsNumber(value)) return false; - // Attempt to store HeapNumber with the hole NaN pattern should have - // already generalized field constness to kMutable. - DCHECK_IMPLIES(!IsSmi(value), !Cast<HeapNumber>(value)->is_the_hole()); Tagged<Object> current_value = holder->RawFastPropertyAt(field_index); + // Only allow initializing stores to uninitialized heap numbers + // to stay constant. + if (IsUninitializedHeapNumber(current_value)) return true; DCHECK(IsHeapNumber(current_value)); - // Only allow initializing stores to double to stay constant. - return Cast<HeapNumber>(current_value)->is_the_hole(); + return false; } Tagged<Object> current_value = holder->RawFastPropertyAt(field_index); @@ -1195,12 +1188,6 @@ void LookupIterator::WriteDataValue(DirectHandle<Object> value, } else if (holder->HasFastProperties()) { DCHECK(IsJSObject(*holder)); if (property_details_.location() == PropertyLocation::kField) { - if (property_details_.representation().IsDouble() && IsNumber(*value)) { - double v = Object::NumberValue(*value); - if (std::isnan(v)) { - value = isolate_->factory()->nan_value(); - } - } // Check that in case of VariableMode::kConst field the existing value is // equal to |value|. DCHECK_IMPLIES(!initializing_store && property_details_.constness() == @@ -1383,7 +1370,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder( if (is_element || !name_->IsAnyPrivate()) return MODULE_NAMESPACE; } #if V8_ENABLE_WEBASSEMBLY - if (IsWasmObjectMap(map)) return WASM_OBJECT; + if (IsAnyWasmObjectMap(map)) return WASM_OBJECT; #endif // V8_ENABLE_WEBASSEMBLY if (map->is_access_check_needed()) { if (is_element || !name_->IsPrivateInternal()) return ACCESS_CHECK; diff --git a/deps/v8/src/objects/managed-type-id.h b/deps/v8/src/objects/managed-type-id.h index 766019d15385..4acfb2cbf5ca 100644 --- a/deps/v8/src/objects/managed-type-id.h +++ b/deps/v8/src/objects/managed-type-id.h @@ -47,6 +47,8 @@ constexpr const char* ToString(ManagedTypeId type_id) { return "TemporalZonedDateTime"; case ManagedTypeId::kDisplayNamesInternal: return "DisplayNamesInternal"; + case ManagedTypeId::kPluralRulesInternal: + return "PluralRulesInternal"; case ManagedTypeId::kD8Worker: return "D8Worker"; case ManagedTypeId::kD8ModuleEmbedderData: diff --git a/deps/v8/src/objects/managed.h b/deps/v8/src/objects/managed.h index a4e40d239c64..043057e6ab87 100644 --- a/deps/v8/src/objects/managed.h +++ b/deps/v8/src/objects/managed.h @@ -402,11 +402,20 @@ class TrustedManaged : public TrustedForeign { TrustedManaged* operator->() { return this; } const TrustedManaged* operator->() const { return this; } - // Get a raw pointer to the C++ object. - V8_INLINE CppType* raw() { return GetSharedPtrPtr()->get(); } + // Get a raw pointer to the C++ object. The returned pointer is only valid as + // long as no GC happens. + V8_INLINE CppType* raw( + const DisallowGarbageCollection& no_gc V8_LIFETIME_BOUND) const { + return GetSharedPtrPtr()->get(); + } + + // Get a raw pointer to the C++ object without a DisallowGarbageCollection + // scope. The caller must ensure that the TrustedManaged object stays alive + // while the returned pointer is in use. + V8_INLINE CppType* unsafe_raw() const { return GetSharedPtrPtr()->get(); } - // Get a reference to the shared pointer to the C++ object. - V8_INLINE const std::shared_ptr<CppType>& get() { return *GetSharedPtrPtr(); } + // Get a copy of the shared pointer to the C++ object. + V8_INLINE std::shared_ptr<CppType> get() const { return *GetSharedPtrPtr(); } // Create a {Managed<CppType>} from an existing {std::shared_ptr} or // {std::unique_ptr} (which will implicitly convert to {std::shared_ptr}). diff --git a/deps/v8/src/objects/map-inl.h b/deps/v8/src/objects/map-inl.h index 1cbddb0d9879..8aad6095ae33 100644 --- a/deps/v8/src/objects/map-inl.h +++ b/deps/v8/src/objects/map-inl.h @@ -97,7 +97,7 @@ void Map::set_instance_descriptors(Tagged<DescriptorArray> value, // consumers dispatch on the runtime type (see // TransitionsAccessor::GetEncoding). The `prototype_info` accessors are // a separate narrower view restricted by is_prototype_map() / -// IsWasmObjectMap() DCHECKs at the call site. +// IsAnyWasmObjectMap() DCHECKs at the call site. Tagged<Map::RawTransitionsT> Map::raw_transitions() const { return transitions_or_prototype_info_.load(); } @@ -124,7 +124,7 @@ void Map::set_prototype(Tagged<JSPrototype> value, WriteBarrierMode mode) { Tagged<UnionOf<Smi, PrototypeInfo, PrototypeSharedClosureInfo>> Map::prototype_info() const { #if V8_ENABLE_WEBASSEMBLY - DCHECK(this->is_prototype_map() || IsWasmObjectMap(this)); + DCHECK(this->is_prototype_map() || IsAnyWasmObjectMap(this)); #else DCHECK(this->is_prototype_map()); #endif // V8_ENABLE_WEBASSEMBLY @@ -229,9 +229,7 @@ BIT_FIELD_ACCESSORS(Map, bit_field3, may_have_interesting_properties, BIT_FIELD_ACCESSORS(Map, relaxed_bit_field3, construction_counter, Map::Bits3::ConstructionCounterBits) -bool IsMetaMap(Tagged<Map> map) { - return InstanceTypeChecker::IsMap(map->instance_type()); -} +bool IsMetaMap(Tagged<Map> map) { return map->map() == map; } DEF_HEAP_OBJECT_PREDICATE(IsMetaMap) { if (!IsMap(obj)) return false; @@ -343,8 +341,7 @@ InternalIndex Map::LastAdded() const { // TODO(375937549): Convert to uint32_t. int Map::NumberOfOwnDescriptors() const { - return Bits3::NumberOfOwnDescriptorsBits::decode( - release_acquire_bit_field3()); + return release_acquire_bit_field3().number_of_own_descriptors(); } void Map::SetNumberOfOwnDescriptors(int number) { @@ -352,16 +349,14 @@ void Map::SetNumberOfOwnDescriptors(int number) { CHECK_LE(static_cast<unsigned>(number), static_cast<unsigned>(kMaxNumberOfDescriptors)); set_release_acquire_bit_field3( - Bits3::NumberOfOwnDescriptorsBits::update(bit_field3(), number)); + bit_field3().with_number_of_own_descriptors(number)); } InternalIndex::Range Map::IterateOwnDescriptors() const { return InternalIndex::Range(NumberOfOwnDescriptors()); } -int Map::EnumLength() const { - return Bits3::EnumLengthBits::decode(bit_field3()); -} +int Map::EnumLength() const { return bit_field3().enum_length(); } void Map::SetEnumLength(int length) { if (length != kInvalidEnumCacheSentinel) { @@ -369,7 +364,7 @@ void Map::SetEnumLength(int length) { CHECK_LE(static_cast<unsigned>(length), static_cast<unsigned>(kMaxNumberOfDescriptors)); } - set_relaxed_bit_field3(Bits3::EnumLengthBits::update(bit_field3(), length)); + set_relaxed_bit_field3(bit_field3().with_enum_length(length)); } Tagged<FixedArrayBase> Map::GetInitialElements() const { @@ -506,7 +501,7 @@ int Map::AllocatedSize() const { int Map::UnusedPropertyFields() const { #if V8_ENABLE_WEBASSEMBLY - DCHECK(!IsWasmObjectMap(this)); + DCHECK(!IsAnyWasmObjectMap(this)); #endif // V8_ENABLE_WEBASSEMBLY int value = used_or_unused_instance_size_in_words(); DCHECK_IMPLIES(!IsJSObjectMap(this), value == 0); @@ -525,7 +520,7 @@ int Map::UnusedInObjectProperties() const { // Like Map::UnusedPropertyFields(), but returns 0 for out of object // properties. #if V8_ENABLE_WEBASSEMBLY - DCHECK(!IsWasmObjectMap(this)); + DCHECK(!IsAnyWasmObjectMap(this)); #endif // V8_ENABLE_WEBASSEMBLY int value = used_or_unused_instance_size_in_words(); DCHECK_IMPLIES(!IsJSObjectMap(this), value == 0); @@ -547,7 +542,7 @@ void Map::set_used_or_unused_instance_size_in_words(int value) { int Map::UsedInstanceSize() const { #if V8_ENABLE_WEBASSEMBLY - DCHECK(!IsWasmObjectMap(this)); + DCHECK(!IsAnyWasmObjectMap(this)); #endif // V8_ENABLE_WEBASSEMBLY int words = used_or_unused_instance_size_in_words(); if (words < JSObject::kFieldsAdded) { @@ -633,75 +628,75 @@ void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) { #if V8_ENABLE_WEBASSEMBLY uint8_t Map::WasmByte1() const { - DCHECK(IsWasmObjectMap(this)); + DCHECK(IsAnyWasmObjectMap(this)); return inobject_properties_start_or_constructor_function_index(); } uint8_t Map::WasmByte2() const { - DCHECK(IsWasmObjectMap(this)); + DCHECK(IsAnyWasmObjectMap(this)); return used_or_unused_instance_size_in_words(); } void Map::SetWasmByte1(uint8_t value) { - CHECK(IsWasmObjectMap(this)); + CHECK(IsAnyWasmObjectMap(this)); set_inobject_properties_start_or_constructor_function_index(value); } void Map::SetWasmByte2(uint8_t value) { - CHECK(IsWasmObjectMap(this)); + CHECK(IsAnyWasmObjectMap(this)); set_used_or_unused_instance_size_in_words(value); } #endif // V8_ENABLE_WEBASSEMBLY -uint8_t Map::bit_field() const { +Map::Bits1 Map::bit_field() const { // TODO(solanes, v8:7790, v8:11353): Make this non-atomic when TSAN sees the // map's store synchronization. return relaxed_bit_field(); } -void Map::set_bit_field(uint8_t value) { +void Map::set_bit_field(Bits1 value) { // TODO(solanes, v8:7790, v8:11353): Make this non-atomic when TSAN sees the // map's store synchronization. set_relaxed_bit_field(value); } -uint8_t Map::relaxed_bit_field() const { +Map::Bits1 Map::relaxed_bit_field() const { return bit_field_.load(std::memory_order_relaxed); } -void Map::set_relaxed_bit_field(uint8_t value) { +void Map::set_relaxed_bit_field(Bits1 value) { bit_field_.store(value, std::memory_order_relaxed); } -uint8_t Map::bit_field2() const { return bit_field2_; } +Map::Bits2 Map::bit_field2() const { return bit_field2_; } -void Map::set_bit_field2(uint8_t value) { bit_field2_ = value; } +void Map::set_bit_field2(Bits2 value) { bit_field2_ = value; } -uint32_t Map::bit_field3() const { +Map::Bits3 Map::bit_field3() const { // TODO(solanes, v8:7790, v8:11353): Make this and the setter non-atomic // when TSAN sees the map's store synchronization. return relaxed_bit_field3(); } -void Map::set_bit_field3(uint32_t value) { +void Map::set_bit_field3(Bits3 value) { // TODO(solanes, v8:7790, v8:11353): Make this non-atomic when TSAN sees the // map's store synchronization. set_relaxed_bit_field3(value); } -uint32_t Map::relaxed_bit_field3() const { +Map::Bits3 Map::relaxed_bit_field3() const { return bit_field3_.load(std::memory_order_relaxed); } -void Map::set_relaxed_bit_field3(uint32_t value) { +void Map::set_relaxed_bit_field3(Bits3 value) { bit_field3_.store(value, std::memory_order_relaxed); } -uint32_t Map::release_acquire_bit_field3() const { +Map::Bits3 Map::release_acquire_bit_field3() const { return bit_field3_.load(std::memory_order_acquire); } -void Map::set_release_acquire_bit_field3(uint32_t value) { +void Map::set_release_acquire_bit_field3(Bits3 value) { bit_field3_.store(value, std::memory_order_release); } @@ -722,7 +717,7 @@ bool Map::has_prototype_info() const { bool Map::TryGetPrototypeInfo(Tagged<PrototypeInfo>* result) const { #if V8_ENABLE_WEBASSEMBLY - DCHECK(is_prototype_map() || IsWasmObjectMap(this)); + DCHECK(is_prototype_map() || IsAnyWasmObjectMap(this)); #else DCHECK(is_prototype_map()); #endif // V8_ENABLE_WEBASSEMBLY @@ -782,13 +777,10 @@ bool Map::TryGetValidityCellHolderMap( void Map::set_elements_kind(ElementsKind elements_kind) { CHECK_LT(static_cast<int>(elements_kind), kElementsKindCount); - set_bit_field2( - Map::Bits2::ElementsKindBits::update(bit_field2(), elements_kind)); + set_bit_field2(bit_field2().with_elements_kind(elements_kind)); } -ElementsKind Map::elements_kind() const { - return Map::Bits2::ElementsKindBits::decode(bit_field2()); -} +ElementsKind Map::elements_kind() const { return bit_field2().elements_kind(); } bool Map::has_fast_smi_elements() const { return IsSmiElementsKind(elements_kind()); @@ -864,23 +856,20 @@ bool Map::has_shared_array_elements() const { } void Map::set_is_dictionary_map(bool value) { - uint32_t new_bit_field3 = - Bits3::IsDictionaryMapBit::update(bit_field3(), value); - new_bit_field3 = Bits3::IsUnstableBit::update(new_bit_field3, value); - set_bit_field3(new_bit_field3); + set_bit_field3( + bit_field3().with_is_dictionary_map(value).with_is_unstable(value)); } bool Map::is_dictionary_map() const { - return Bits3::IsDictionaryMapBit::decode(relaxed_bit_field3()); + return relaxed_bit_field3().is_dictionary_map(); } void Map::mark_unstable() { - set_release_acquire_bit_field3( - Bits3::IsUnstableBit::update(bit_field3(), true)); + set_release_acquire_bit_field3(bit_field3().with_is_unstable(true)); } bool Map::is_stable() const { - return !Bits3::IsUnstableBit::decode(release_acquire_bit_field3()); + return !release_acquire_bit_field3().is_unstable(); } bool Map::CanBeDeprecated() const { @@ -1034,12 +1023,6 @@ void Map::SetBackPointer(Tagged<HeapObject> value, WriteBarrierMode mode) { set_constructor_or_back_pointer(value, mode); } -// static -Tagged<Map> Map::GetMapFor(ReadOnlyRoots roots, InstanceType type) { - RootIndex map_idx = TryGetMapRootIdxFor(type).value(); - return UncheckedCast<Map>(roots.object_at(map_idx)); -} - // static Tagged<Map> Map::ElementsTransitionMap(Isolate* isolate, ConcurrencyMode cmode) { @@ -1051,7 +1034,7 @@ Tagged<Map> Map::ElementsTransitionMap(Isolate* isolate, Tagged<DependentCode> Map::dependent_code() const { Tagged<Object> value = dependent_code_.load(); if (!IsDependentCode(value)) { - DCHECK(IsWasmStructMap(this)); + DCHECK(IsWasmStructMap(this) || IsWasmCustomMap(Tagged<Map>(this))); return DependentCode::empty_dependent_code(GetReadOnlyRoots()); } return Cast<DependentCode>(value); @@ -1060,21 +1043,21 @@ void Map::set_dependent_code(Tagged<DependentCode> value, WriteBarrierMode mode) { // Only the Factory may call this for Wasm object maps, when default- // initializing them. Use the WB mode as a sentinel for that situation. - DCHECK(mode == SKIP_WRITE_BARRIER || !IsWasmObjectMap(this)); + DCHECK(mode == SKIP_WRITE_BARRIER || !IsAnyWasmObjectMap(this)); dependent_code_.store(this, value, mode); } Tagged<Map> Map::immediate_supertype_map() const { - DCHECK(IsWasmObjectMap(this)); + DCHECK(IsAnyWasmObjectMap(this)); // dependent_code_ slot is reused for the supertype map on Wasm maps. return Cast<Map>(dependent_code_.load()); } bool Map::has_immediate_supertype_map() const { - DCHECK(IsWasmObjectMap(this)); + DCHECK(IsAnyWasmObjectMap(this)); return Is<Map>(dependent_code_.load()); } void Map::set_immediate_supertype_map(Tagged<Map> value, WriteBarrierMode mode) { - DCHECK(IsWasmObjectMap(this)); + DCHECK(IsAnyWasmObjectMap(this)); dependent_code_.store(this, value, mode); } #else // V8_ENABLE_WEBASSEMBLY @@ -1119,26 +1102,26 @@ void Map::set_constructor_or_back_pointer(Tagged<Object> value, RelaxedStoreTag, } Tagged<NativeContext> Map::native_context() const { - DCHECK(IsContextMap(this) || IsMapMap(this)); + DCHECK(IsContextMap(this) || IsMetaMap(this)); return Cast<NativeContext>( constructor_or_back_pointer_or_native_context_.load()); } void Map::set_native_context(Tagged<NativeContext> value, WriteBarrierMode mode) { - DCHECK(IsContextMap(this) || IsMapMap(this)); + DCHECK(IsContextMap(this) || IsMetaMap(this)); constructor_or_back_pointer_or_native_context_.store(this, value, mode); } Tagged<Object> Map::native_context_or_null() const { Tagged<Object> value = constructor_or_back_pointer_or_native_context_.load(); DCHECK((IsNull(value) || IsNativeContext(value)) && - (IsContextMap(this) || IsMapMap(this))); + (IsContextMap(this) || IsMetaMap(this))); return value; } void Map::set_native_context_or_null(Tagged<Object> value, WriteBarrierMode mode) { DCHECK((IsNull(value) || IsNativeContext(value)) && - (IsContextMap(this) || IsMapMap(this))); + (IsContextMap(this) || IsMetaMap(this))); constructor_or_back_pointer_or_native_context_.store(this, value, mode); } @@ -1148,21 +1131,23 @@ Tagged<Object> Map::raw_native_context_or_null() const { Tagged<Object> value = constructor_or_back_pointer_or_native_context_.load(); DCHECK(IsNull(value) || IsNativeContext(value) || value == Smi::uninitialized_deserialization_value()); - DCHECK(IsContextMap(this) || IsMapMap(this)); + DCHECK(IsContextMap(this) || IsMetaMap(this)); return value; } #if V8_ENABLE_WEBASSEMBLY Tagged<WasmTypeInfo> Map::wasm_type_info() const { DCHECK(IsWasmStructMap(this) || IsWasmArrayMap(this) || - IsWasmFuncRefMap(this) || IsWasmContinuationObjectMap(this)); + IsWasmFuncRefMap(this) || IsWasmContinuationObjectMap(this) || + IsWasmCustomMapMap(this)); return Cast<WasmTypeInfo>( constructor_or_back_pointer_or_native_context_.load()); } void Map::set_wasm_type_info(Tagged<WasmTypeInfo> value, WriteBarrierMode mode) { DCHECK(IsWasmStructMap(this) || IsWasmArrayMap(this) || - IsWasmFuncRefMap(this) || IsWasmContinuationObjectMap(this)); + IsWasmFuncRefMap(this) || IsWasmContinuationObjectMap(this) || + IsWasmCustomMapMap(this)); constructor_or_back_pointer_or_native_context_.store(this, value, mode); } #endif // V8_ENABLE_WEBASSEMBLY @@ -1286,32 +1271,32 @@ constexpr int ExtendedMapSizeForKind(ExtendedMapKind kind) { UNREACHABLE(); } -uint8_t ExtendedMap::relaxed_bit_field_ex() const { +ExtendedMap::BitsEx ExtendedMap::relaxed_bit_field_ex() const { return bit_field_ex_.load(std::memory_order_relaxed); } -void ExtendedMap::set_relaxed_bit_field_ex(uint8_t value) { +void ExtendedMap::set_relaxed_bit_field_ex(BitsEx value) { bit_field_ex_.store(value, std::memory_order_relaxed); } -uint8_t ExtendedMap::bit_field_ex() const { +ExtendedMap::BitsEx ExtendedMap::bit_field_ex() const { // TODO(solanes, v8:7790, v8:11353): Make this non-atomic when TSAN sees the // map's store synchronization. return relaxed_bit_field_ex(); } -void ExtendedMap::set_bit_field_ex(uint8_t value) { +void ExtendedMap::set_bit_field_ex(BitsEx value) { // TODO(solanes, v8:7790, v8:11353): Make this non-atomic when TSAN sees the // map's store synchronization. set_relaxed_bit_field_ex(value); } ExtendedMapKind ExtendedMap::map_kind() const { - return BitsEx::MapKindBits::decode(relaxed_bit_field_ex()); + return relaxed_bit_field_ex().map_kind(); } uint8_t ExtendedMap::map_size_in_words() const { - return BitsEx::MapSizeInWordsBits::decode(relaxed_bit_field_ex()); + return relaxed_bit_field_ex().map_size_in_words(); } int ExtendedMap::map_size() const { @@ -1324,14 +1309,10 @@ void ExtendedMap::set_map_kind_and_size(ExtendedMapKind kind, int size_in_words = size_in_bytes >> kTaggedSizeLog2; CHECK_LE(static_cast<unsigned>(size_in_words), kMaxUInt8); - uint8_t field = - BitsEx::MapKindBits::encode(kind) | - BitsEx::MapSizeInWordsBits::encode(static_cast<uint8_t>(size_in_words)); - set_relaxed_bit_field_ex(field); + set_relaxed_bit_field_ex(BitsEx().with_map_kind(kind).with_map_size_in_words( + static_cast<uint8_t>(size_in_words))); } - - int NormalizedMapCache::GetIndex(Isolate* isolate, Tagged<Map> map, Tagged<HeapObject> prototype) { DisallowGarbageCollection no_gc; diff --git a/deps/v8/src/objects/map.cc b/deps/v8/src/objects/map.cc index a6f6a26a9451..34431ba50135 100644 --- a/deps/v8/src/objects/map.cc +++ b/deps/v8/src/objects/map.cc @@ -4,6 +4,7 @@ #include "src/objects/map.h" +#include <array> #include <optional> #include "src/base/hashing.h" @@ -33,6 +34,10 @@ #include "src/objects/transitions-inl.h" #include "src/roots/roots.h" +#if V8_ENABLE_WEBASSEMBLY +#include "src/wasm/wasm-objects-inl.h" +#endif // V8_ENABLE_WEBASSEMBLY + namespace v8::internal { Tagged<Map> Map::GetPrototypeChainRootMap(Isolate* isolate) const { @@ -419,16 +424,15 @@ VisitorId Map::GetVisitorId(Tagged<Map> map) { case JS_FINALIZATION_REGISTRY_TYPE: return kVisitJSFinalizationRegistry; - case JS_ATOMICS_MUTEX_TYPE: - case JS_ATOMICS_CONDITION_TYPE: - return kVisitJSSynchronizationPrimitive; - case HEAP_NUMBER_TYPE: return kVisitHeapNumber; case HASH_SEED_WRAPPER_TYPE: return kVisitHashSeedWrapper; + case UNINITIALIZED_HEAP_NUMBER_TYPE: + return kVisitUninitializedHeapNumber; + case FOREIGN_TYPE: return kVisitForeign; @@ -470,6 +474,7 @@ VisitorId Map::GetVisitorId(Tagged<Map> map) { case STACK_FRAME_INFO_TYPE: case STACK_TRACE_INFO_TYPE: case TEMPLATE_OBJECT_DESCRIPTION_TYPE: + case FOR_IN_ENUMERATOR_HOLDER_TYPE: case TUPLE2_TYPE: #if V8_ENABLE_WEBASSEMBLY case WASM_EXCEPTION_TAG_TYPE: @@ -619,12 +624,11 @@ MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, DirectHandle<Map> map, return MaybeHandle<Map>(); } - auto [representation, constness] = - Object::OptimalRepresentation(*constant, PropertyConstness::kConst); + Representation representation = Object::OptimalRepresentation(*constant); DirectHandle<FieldType> type = Object::OptimalType(*constant, isolate, representation); - return CopyWithField(isolate, map, name, type, attributes, constness, - representation, flag); + return CopyWithField(isolate, map, name, type, attributes, + PropertyConstness::kConst, representation, flag); } bool Map::InstancesNeedRewriting(Tagged<Map> target, @@ -1113,14 +1117,19 @@ Tagged<Map> Map::LookupElementsTransitionMap(Isolate* isolate, } bool Map::IsMapInArrayPrototypeChain(Isolate* isolate) const { - if (isolate->initial_array_prototype()->map() == this) { + DisallowGarbageCollection no_gc; + InstanceType type = instance_type(); + if (type == JS_OBJECT_PROTOTYPE_TYPE) { return true; } - - if (isolate->initial_object_prototype()->map() == this) { - return true; + if (type == JS_ARRAY_TYPE) { + // Keep in sync with Isolate::IsInCreationContext. + Tagged<Map> metamap = map(); + // Filter out native-context independent objects. + if (metamap == ReadOnlyRoots(isolate).meta_map()) return false; + Tagged<NativeContext> native_context = metamap->native_context(); + return native_context->initial_array_prototype()->map() == this; } - return false; } @@ -1321,20 +1330,17 @@ Handle<Map> Map::RawCopy(Isolate* isolate, DirectHandle<Map> src_handle, raw->set_constructor_or_back_pointer(src->GetConstructorRaw()); raw->set_bit_field(src->bit_field()); raw->set_bit_field2(src->bit_field2()); - int new_bit_field3 = src->bit_field3(); - new_bit_field3 = Bits3::OwnsDescriptorsBit::update(new_bit_field3, true); - new_bit_field3 = - Bits3::NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); - new_bit_field3 = Bits3::EnumLengthBits::update(new_bit_field3, - kInvalidEnumCacheSentinel); - new_bit_field3 = Bits3::IsDeprecatedBit::update(new_bit_field3, false); - new_bit_field3 = - Bits3::IsInRetainedMapListBit::update(new_bit_field3, false); - if (!src->is_dictionary_map()) { - new_bit_field3 = Bits3::IsUnstableBit::update(new_bit_field3, false); + Bits3 bits3 = src->bit_field3() + .with_owns_descriptors(true) + .with_number_of_own_descriptors(0) + .with_enum_length(kInvalidEnumCacheSentinel) + .with_is_deprecated(false) + .with_is_in_retained_map_list(false); + if (!bits3.is_dictionary_map()) { + bits3 = bits3.with_is_unstable(false); } // Same as bit_field comment above. - raw->set_bit_field3(new_bit_field3); + raw->set_bit_field3(bits3); if (v8_flags.proto_assign_seq_lazy_func_opt) { if (Tagged<PrototypeSharedClosureInfo> infos; src_handle->TryGetPrototypeSharedClosureInfo(&infos)) { @@ -1516,12 +1522,10 @@ void EnsureInitialMap(Isolate* isolate, DirectHandle<Map> map) { DCHECK((IsJSFunction(maybe_constructor) && *map == Cast<JSFunction>(maybe_constructor)->initial_map()) || // Below are the exceptions to the check above. - // |Function|'s initial map is a |sloppy_function_map| but - // other function map variants such as sloppy with name or readonly - // prototype or various strict function maps variants, etc. also - // have Function as a constructor. - *map == *isolate->strict_function_map() || - *map == *isolate->strict_function_with_name_map() || + // |Function|'s initial map is a |function_map| but other function map + // variants such as function with name or readonly prototype also have + // Function as a constructor. + *map == *isolate->function_with_name_map() || // Same applies to |GeneratorFunction|'s initial map and generator // function map variants. *map == *isolate->generator_function_with_name_map() || @@ -1858,51 +1862,6 @@ Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, DirectHandle<Map> map, return new_map; } -DirectHandle<Map> Map::AsLanguageMode( - Isolate* isolate, DirectHandle<Map> initial_map, - DirectHandle<SharedFunctionInfo> shared_info) { - DCHECK(InstanceTypeChecker::IsJSFunction(initial_map->instance_type())); -#ifndef V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS - return initial_map; -#else - // Initial map for sloppy mode function is stored in the function - // constructor. Initial maps for strict mode are cached as special transitions - // using |strict_function_transition_symbol| as a key. - if (is_sloppy(shared_info->language_mode())) return initial_map; - - DirectHandle<Map> function_map(Cast<Map>(isolate->native_context()->GetNoCell( - shared_info->function_map_index())), - isolate); - - static_assert(LanguageModeSize == 2); - DCHECK_EQ(LanguageMode::kStrict, shared_info->language_mode()); - DirectHandle<Symbol> transition_symbol = - isolate->factory()->strict_function_transition_symbol(); - MaybeDirectHandle<Map> maybe_transition = TransitionsAccessor::SearchSpecial( - isolate, initial_map, *transition_symbol); - if (!maybe_transition.is_null()) { - return maybe_transition.ToHandleChecked(); - } - initial_map->NotifyLeafMapLayoutChange(isolate); - - // Create new map taking descriptors from the |function_map| and all - // the other details from the |initial_map|. - DirectHandle<Map> map = - Map::CopyInitialMap(isolate, function_map, initial_map->instance_size(), - initial_map->GetInObjectProperties(), - initial_map->UnusedPropertyFields()); - map->SetConstructor(initial_map->GetConstructor()); - map->set_prototype(initial_map->prototype()); - map->set_construction_counter(initial_map->construction_counter()); - - if (TransitionsAccessor::CanHaveMoreTransitions(isolate, initial_map)) { - Map::ConnectTransition(isolate, initial_map, map, transition_symbol, - SPECIAL_TRANSITION); - } - return map; -#endif // !V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS -} - Handle<Map> Map::CopyForElementsTransition(Isolate* isolate, DirectHandle<Map> map) { DCHECK(!map->IsDetached(isolate)); @@ -2093,9 +2052,7 @@ DirectHandle<Map> UpdateDescriptorForValue(Isolate* isolate, PropertyAttributes attributes = map->instance_descriptors()->GetDetails(descriptor).attributes(); - Representation representation; - std::tie(representation, constness) = - Object::OptimalRepresentation(*value, constness); + Representation representation = Object::OptimalRepresentation(*value); DirectHandle<FieldType> type = Object::OptimalType(*value, isolate, representation); @@ -2151,9 +2108,7 @@ DirectHandle<Map> Map::TransitionToDataProperty( isolate->bootstrapper()->IsActive() ? OMIT_TRANSITION : INSERT_TRANSITION; MaybeDirectHandle<Map> maybe_map; if (!map->TooManyFastProperties(store_origin)) { - Representation representation; - std::tie(representation, constness) = - Object::OptimalRepresentation(*value, constness); + Representation representation = Object::OptimalRepresentation(*value); DirectHandle<FieldType> type = Object::OptimalType(*value, isolate, representation); maybe_map = Map::CopyWithField(isolate, map, name, type, attributes, @@ -2164,14 +2119,12 @@ DirectHandle<Map> Map::TransitionToDataProperty( if (!maybe_map.ToHandle(&result)) { const char* reason = "TooManyFastProperties"; #if V8_TRACE_MAPS - base::OwnedVector<char> buffer; + std::array<char, 128> buffer; if (v8_flags.log_maps) { - auto name_buffer = base::OwnedVector<char>::NewForOverwrite(100); - name->NameShortPrint(name_buffer.as_vector()); - buffer = base::OwnedVector<char>::NewForOverwrite(128); - SNPrintF(buffer.as_vector(), "TooManyFastProperties %s", - name_buffer.begin()); - reason = buffer.begin(); + std::array<char, 100> name_buffer; + name->NameShortPrint(name_buffer); + base::SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.data()); + reason = buffer.data(); } #endif DirectHandle<Object> maybe_constructor(map->GetConstructor(), isolate); @@ -2428,19 +2381,6 @@ bool Map::EquivalentToForTransition( if (*new_prototype != other->prototype()) return false; } if (new_target_is_base() != other->new_target_is_base()) return false; - if (InstanceTypeChecker::IsJSFunction(instance_type())) { - // JSFunctions require more checks to ensure that sloppy function is - // not equivalent to strict function. - int nof = - std::min(NumberOfOwnDescriptors(), other->NumberOfOwnDescriptors()); - Tagged<DescriptorArray> this_descriptors = - IsConcurrent(cmode) ? instance_descriptors(kAcquireLoad) - : instance_descriptors(); - Tagged<DescriptorArray> that_descriptors = - IsConcurrent(cmode) ? other->instance_descriptors(kAcquireLoad) - : other->instance_descriptors(); - return this_descriptors->IsEqualUpTo(that_descriptors, nof); - } return true; } @@ -2474,10 +2414,9 @@ bool Map::EquivalentToForNormalization(const Tagged<Map> other, int properties = mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other->GetInObjectProperties(); // Make sure the elements_kind bits are in bit_field2. - DCHECK_EQ(this->elements_kind(), - Map::Bits2::ElementsKindBits::decode(bit_field2())); - int adjusted_other_bit_field2 = - Map::Bits2::ElementsKindBits::update(other->bit_field2(), elements_kind); + DCHECK_EQ(this->elements_kind(), bit_field2().elements_kind()); + Bits2 adjusted_other_bit_field2 = + other->bit_field2().with_elements_kind(elements_kind); return CheckEquivalentModuloProto(this, other) && prototype() == other_prototype && bit_field2() == adjusted_other_bit_field2 && @@ -2643,9 +2582,18 @@ Handle<UnionOf<Smi, Cell>> Map::GetOrCreatePrototypeChainValidityCell( } // Otherwise create a new cell. Handle<Cell> cell = isolate->factory()->NewCell(); - { + do { Tagged<Map> meta_map = validity_cell_holder_map->map(); - DCHECK(IsMapMap(meta_map)); +#if V8_ENABLE_WEBASSEMBLY + if (!IsMetaMap(meta_map)) { + DCHECK(IsWasmCustomMap(*validity_cell_holder_map)); + cell->set_maybe_value( + MakeWeak(Cast<WasmCustomMap>(validity_cell_holder_map) + ->native_context_for_wrapper())); + break; + } +#endif // V8_ENABLE_WEBASSEMBLY + DCHECK(IsMetaMap(meta_map)); // The meta map's context slot is Null for the RO meta map (shared // across all contexts). Legacy code reinterpret-loaded the slot as // NativeContext and MakeWeak'd it; since Null is immortal the @@ -2662,7 +2610,7 @@ Handle<UnionOf<Smi, Cell>> Map::GetOrCreatePrototypeChainValidityCell( DCHECK(IsNull(maybe_context)); cell->set_maybe_value(maybe_context); } - } + } while (false); validity_cell_holder_map->set_prototype_validity_cell(*cell, kRelaxedStore); return cell; } diff --git a/deps/v8/src/objects/map.h b/deps/v8/src/objects/map.h index a33c7f01ac16..e4ed13a84047 100644 --- a/deps/v8/src/objects/map.h +++ b/deps/v8/src/objects/map.h @@ -11,6 +11,7 @@ #include "src/base/bit-field.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/fixed-array-base.h" #include "src/objects/fixed-array.h" #include "src/objects/heap-object.h" @@ -37,6 +38,7 @@ enum InstanceType : uint16_t; V(Filler) \ V(HeapNumber) \ V(HashSeedWrapper) \ + V(UninitializedHeapNumber) \ V(Hole) \ V(SeqOneByteString) \ V(SeqTwoByteString) \ @@ -87,7 +89,6 @@ enum InstanceType : uint16_t; V(JSObjectFast) \ V(JSProxy) \ V(JSRegExp) \ - V(JSSynchronizationPrimitive) \ V(JSTypedArray) \ V(JSWeakCollection) \ V(JSWeakRef) \ @@ -202,10 +203,10 @@ using MapHandlesSpan = std::span<DirectHandle<Map>>; // +----------+-------------------------------------------------+ // | Byte | [bit_field] | // | | - is_callable (bit 0) | -// | | - has_named_interceptor (bit 1) | -// | | - has_indexed_interceptor (bit 2) | -// | | - is_undetectable (bit 3) | -// | | - is_access_check_needed (bit 4) | +// | | - is_undetectable (bit 1) | +// | | - has_named_interceptor (bit 2) | +// | | - is_access_check_needed (bit 3) | +// | | - has_indexed_interceptor (bit 4) | // | | - is_constructor (bit 5) | // | | - is_extended_map (bit 6) | // +----------+-------------------------------------------------+ @@ -326,58 +327,70 @@ V8_OBJECT class Map : public HeapObject { int unused_in_property_array); // + // Bit positions for |bit_field|. The order must match MapBits1 in + // map.tq. + // + // The compilers test is_callable | is_undetectable (typeof checks) and + // has_named_interceptor | is_access_check_needed (special receiver checks) + // as one mask each. Keeping the bits of each pair adjacent makes those masks + // contiguous, so they encode as arm64 logical immediates. + struct Bits1 : BitFieldGroup<Bits1, uint8_t> { + using BitFieldGroup::BitFieldGroup; + + using IsCallableBit = First<bool, 1>; + using IsUndetectableBit = IsCallableBit::Next<bool, 1>; + using HasNamedInterceptorBit = IsUndetectableBit::Next<bool, 1>; + using IsAccessCheckNeededBit = HasNamedInterceptorBit::Next<bool, 1>; + using HasIndexedInterceptorBit = IsAccessCheckNeededBit::Next<bool, 1>; + using IsConstructorBit = HasIndexedInterceptorBit::Next<bool, 1>; + using IsExtendedMapBit = IsConstructorBit::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(is_callable, IsCallableBit) + BIT_FIELD_GROUP_ACCESSORS(is_undetectable, IsUndetectableBit) + BIT_FIELD_GROUP_ACCESSORS(has_named_interceptor, HasNamedInterceptorBit) + BIT_FIELD_GROUP_ACCESSORS(is_access_check_needed, IsAccessCheckNeededBit) + BIT_FIELD_GROUP_ACCESSORS(has_indexed_interceptor, HasIndexedInterceptorBit) + BIT_FIELD_GROUP_ACCESSORS(is_constructor, IsConstructorBit) + BIT_FIELD_GROUP_ACCESSORS(is_extended_map, IsExtendedMapBit) + }; + // Bit field. // // The setter in this pair calls the relaxed setter if concurrent marking is // on, or performs the write non-atomically if it's off. The read is always // non-atomically. This is done to have wider TSAN coverage on the cases where // it's possible. - DECL_PRIMITIVE_ACCESSORS(bit_field, uint8_t) + DECL_PRIMITIVE_ACCESSORS(bit_field, Bits1) // Atomic accessors, used for allowlisting legitimate concurrent accesses. - DECL_PRIMITIVE_ACCESSORS(relaxed_bit_field, uint8_t) - - // Bit positions for |bit_field|. - struct Bits1 { - using IsCallableBit = base::BitField<bool, 0, 1, uint8_t>; - using HasNamedInterceptorBit = IsCallableBit::Next<bool, 1>; - using HasIndexedInterceptorBit = HasNamedInterceptorBit::Next<bool, 1>; - using IsUndetectableBit = HasIndexedInterceptorBit::Next<bool, 1>; - using IsAccessCheckNeededBit = IsUndetectableBit::Next<bool, 1>; - using IsConstructorBit = IsAccessCheckNeededBit::Next<bool, 1>; - using IsExtendedMapBit = IsConstructorBit::Next<bool, 1>; - }; + DECL_PRIMITIVE_ACCESSORS(relaxed_bit_field, Bits1) // // Bit field 2. // - DECL_PRIMITIVE_ACCESSORS(bit_field2, uint8_t) - // Bit positions for |bit_field2|. - struct Bits2 { - using NewTargetIsBaseBit = base::BitField<bool, 0, 1, uint8_t>; + struct Bits2 : BitFieldGroup<Bits2, uint8_t> { + using BitFieldGroup::BitFieldGroup; + + using NewTargetIsBaseBit = First<bool, 1>; using IsImmutablePrototypeBit = NewTargetIsBaseBit::Next<bool, 1>; using ElementsKindBits = IsImmutablePrototypeBit::Next<ElementsKind, 6>; + + BIT_FIELD_GROUP_ACCESSORS(new_target_is_base, NewTargetIsBaseBit) + BIT_FIELD_GROUP_ACCESSORS(is_immutable_prototype, IsImmutablePrototypeBit) + BIT_FIELD_GROUP_ACCESSORS(elements_kind, ElementsKindBits) }; + DECL_PRIMITIVE_ACCESSORS(bit_field2, Bits2) + // // Bit field 3. // - // {bit_field3} calls the relaxed accessors if concurrent marking is on, or - // performs the read/write non-atomically if it's off. This is done to have - // wider TSAN coverage on the cases where it's possible. - DECL_PRIMITIVE_ACCESSORS(bit_field3, uint32_t) - - DECL_PRIMITIVE_ACCESSORS(relaxed_bit_field3, uint32_t) - DECL_PRIMITIVE_ACCESSORS(release_acquire_bit_field3, uint32_t) - - // Clear uninitialized padding space. This ensures that the snapshot content - // is deterministic. Depending on the V8 build mode there could be no padding. - V8_INLINE void clear_padding(); - // Bit positions for |bit_field3|. - struct Bits3 { - using EnumLengthBits = base::BitField<int32_t, 0, 10, uint32_t>; + struct Bits3 : BitFieldGroup<Bits3, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using EnumLengthBits = First<int32_t, 10>; using NumberOfOwnDescriptorsBits = EnumLengthBits::Next<int32_t, 10>; using IsPrototypeMapBit = NumberOfOwnDescriptorsBits::Next<bool, 1>; using IsDictionaryMapBit = IsPrototypeMapBit::Next<bool, 1>; @@ -390,6 +403,21 @@ V8_OBJECT class Map : public HeapObject { using MayHaveInterestingPropertiesBit = IsExtensibleBit::Next<bool, 1>; using ConstructionCounterBits = MayHaveInterestingPropertiesBit::Next<int32_t, 3>; + + BIT_FIELD_GROUP_ACCESSORS(enum_length, EnumLengthBits) + BIT_FIELD_GROUP_ACCESSORS(number_of_own_descriptors, + NumberOfOwnDescriptorsBits) + BIT_FIELD_GROUP_ACCESSORS(is_prototype_map, IsPrototypeMapBit) + BIT_FIELD_GROUP_ACCESSORS(is_dictionary_map, IsDictionaryMapBit) + BIT_FIELD_GROUP_ACCESSORS(owns_descriptors, OwnsDescriptorsBit) + BIT_FIELD_GROUP_ACCESSORS(is_in_retained_map_list, IsInRetainedMapListBit) + BIT_FIELD_GROUP_ACCESSORS(is_deprecated, IsDeprecatedBit) + BIT_FIELD_GROUP_ACCESSORS(is_unstable, IsUnstableBit) + BIT_FIELD_GROUP_ACCESSORS(is_migration_target, IsMigrationTargetBit) + BIT_FIELD_GROUP_ACCESSORS(is_extensible, IsExtensibleBit) + BIT_FIELD_GROUP_ACCESSORS(may_have_interesting_properties, + MayHaveInterestingPropertiesBit) + BIT_FIELD_GROUP_ACCESSORS(construction_counter, ConstructionCounterBits) }; // Ensure that Torque-defined bit widths for |bit_field3| are as expected. @@ -400,6 +428,18 @@ V8_OBJECT class Map : public HeapObject { static_assert(Bits3::NumberOfOwnDescriptorsBits::kMax >= kMaxNumberOfDescriptors); + // {bit_field3} calls the relaxed accessors if concurrent marking is on, or + // performs the read/write non-atomically if it's off. This is done to have + // wider TSAN coverage on the cases where it's possible. + DECL_PRIMITIVE_ACCESSORS(bit_field3, Bits3) + + DECL_PRIMITIVE_ACCESSORS(relaxed_bit_field3, Bits3) + DECL_PRIMITIVE_ACCESSORS(release_acquire_bit_field3, Bits3) + + // Clear uninitialized padding space. This ensures that the snapshot content + // is deterministic. Depending on the V8 build mode there could be no padding. + V8_INLINE void clear_padding(); + static const int kSlackTrackingCounterStart = 7; static const int kSlackTrackingCounterEnd = 1; static const int kNoSlackTracking = 0; @@ -907,10 +947,6 @@ V8_OBJECT class Map : public HeapObject { V8_EXPORT_PRIVATE static Handle<Map> AsDetachedTypedArray( Isolate* isolate, DirectHandle<Map> map); - static DirectHandle<Map> AsLanguageMode( - Isolate* isolate, DirectHandle<Map> initial_map, - DirectHandle<SharedFunctionInfo> shared_info); - V8_EXPORT_PRIVATE static Handle<Map> CopyForPreventExtensions( Isolate* isolate, DirectHandle<Map> map, PropertyAttributes attrs_to_add, DirectHandle<Symbol> transition_marker, const char* reason, @@ -989,8 +1025,10 @@ V8_OBJECT class Map : public HeapObject { static constexpr std::optional<RootIndex> TryGetMapRootIdxFor( InstanceType type); - static inline Tagged<Map> GetMapFor(ReadOnlyRoots roots, InstanceType type); + // Returns true if this map belongs to the initial Array.prototype or + // Object.prototype of any native context (i.e. objects guarded by the + // isolate-wide "no elements" protector). bool IsMapInArrayPrototypeChain(Isolate* isolate) const; // Dispatched behavior. @@ -1185,10 +1223,10 @@ V8_OBJECT class Map : public HeapObject { std::atomic<uint8_t> inobject_properties_start_or_constructor_function_index_; std::atomic<uint8_t> used_or_unused_instance_size_in_words_; std::atomic<uint8_t> visitor_id_; - std::atomic<uint16_t> instance_type_; - std::atomic<uint8_t> bit_field_; - uint8_t bit_field2_; - std::atomic<uint32_t> bit_field3_; + std::atomic<uint16_t> instance_type_ V8_TQ_TYPE(InstanceType); + std::atomic<Bits1> bit_field_; + Bits2 bit_field2_; + std::atomic<Bits3> bit_field3_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif @@ -1201,8 +1239,8 @@ V8_OBJECT class Map : public HeapObject { TaggedMember<DescriptorArray> instance_descriptors_; TaggedMember<DependentCode> dependent_code_; #endif - TaggedMember<UnionOf<Smi, Cell>> prototype_validity_cell_; - TaggedMember<UnionOf<Smi, MaybeWeak<Map>, TransitionArray, PrototypeInfo, + TaggedMember<UnionOf<Zero, Cell>> prototype_validity_cell_; + TaggedMember<UnionOf<Zero, MaybeWeak<Map>, TransitionArray, PrototypeInfo, PrototypeSharedClosureInfo>> transitions_or_prototype_info_; } V8_OBJECT_END; @@ -1227,16 +1265,21 @@ V8_ABSTRACT_OBJECT class ExtendedMap : public Map { public: // Bit positions for |bit_field_ex|. - struct BitsEx { - using MapKindBits = base::BitField<ExtendedMapKind, 0, 3, uint8_t>; + struct BitsEx : BitFieldGroup<BitsEx, uint8_t> { + using BitFieldGroup::BitFieldGroup; + + using MapKindBits = First<ExtendedMapKind, 3>; using MapSizeInWordsBits = MapKindBits::Next<uint8_t, 5>; + + BIT_FIELD_GROUP_ACCESSORS(map_kind, MapKindBits) + BIT_FIELD_GROUP_ACCESSORS(map_size_in_words, MapSizeInWordsBits) }; - inline uint8_t bit_field_ex() const; - inline void set_bit_field_ex(uint8_t value); + inline BitsEx bit_field_ex() const; + inline void set_bit_field_ex(BitsEx value); - inline uint8_t relaxed_bit_field_ex() const; - inline void set_relaxed_bit_field_ex(uint8_t value); + inline BitsEx relaxed_bit_field_ex() const; + inline void set_relaxed_bit_field_ex(BitsEx value); inline ExtendedMapKind map_kind() const; inline uint8_t map_size_in_words() const; @@ -1248,7 +1291,7 @@ V8_ABSTRACT_OBJECT class ExtendedMap : public Map { static const int kMinimumSize; static const int kStartOfStrongExtendedFieldsOffset; - std::atomic<uint8_t> bit_field_ex_; + std::atomic<BitsEx> bit_field_ex_; // Leaves kTaggedSize-1 unused bytes, they will be used by subclasses. } V8_OBJECT_END; diff --git a/deps/v8/src/objects/map.tq b/deps/v8/src/objects/map.tq index cb85e7788e6a..cc90e8ae94f3 100644 --- a/deps/v8/src/objects/map.tq +++ b/deps/v8/src/objects/map.tq @@ -2,26 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// The compilers test is_callable | is_undetectable (typeof checks) and +// has_named_interceptor | is_access_check_needed (special receiver checks) +// as one mask each. Keeping the bits of each pair adjacent makes those masks +// contiguous, so they encode as arm64 logical immediates. @cppScope('Map::Bits1') -bitfield struct MapBitFields1 extends uint8 { +bitfield struct MapBits1 extends uint8 { is_callable: bool: 1 bit; - has_named_interceptor: bool: 1 bit; - has_indexed_interceptor: bool: 1 bit; is_undetectable: bool: 1 bit; + has_named_interceptor: bool: 1 bit; is_access_check_needed: bool: 1 bit; + has_indexed_interceptor: bool: 1 bit; is_constructor: bool: 1 bit; is_extended_map: bool: 1 bit; } @cppScope('Map::Bits2') -bitfield struct MapBitFields2 extends uint8 { +bitfield struct MapBits2 extends uint8 { new_target_is_base: bool: 1 bit; is_immutable_prototype: bool: 1 bit; elements_kind: ElementsKind: 6 bit; } @cppScope('Map::Bits3') -bitfield struct MapBitFields3 extends uint32 { +bitfield struct MapBits3 extends uint32 { enum_length: int32: 10 bit; number_of_own_descriptors: int32: 10 bit; is_prototype_map: bool: 1 bit; @@ -76,13 +80,13 @@ extern class Map extends HeapObject { used_or_unused_instance_size_in_words: uint8; visitor_id: uint8; instance_type: InstanceType; - bit_field: MapBitFields1; - bit_field2: MapBitFields2; - bit_field3: MapBitFields3; + bit_field: MapBits1; + bit_field2: MapBits2; + bit_field3: MapBits3; @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; - prototype: JSReceiver|Null; + prototype: JSPrototype; constructor_or_back_pointer_or_native_context: Object; @if(V8_ENABLE_WEBASSEMBLY) instance_descriptors: DescriptorArray @@ -102,7 +106,7 @@ extern class Map extends HeapObject { extern enum ExtendedMapKind extends uint8 { kJSInterceptorMap, ...} @cppScope('ExtendedMap::BitsEx') -bitfield struct ExtendedMapBitFields extends uint8 { +bitfield struct ExtendedMapBitsEx extends uint8 { map_kind: ExtendedMapKind: 3 bit; // The extended map size should be computable via map_kind, // this field just stores the size value for convenience. @@ -115,7 +119,7 @@ bitfield struct ExtendedMapBitFields extends uint8 { @hasSameInstanceTypeAsParent @doNotGenerateCast extern class ExtendedMap extends Map { - bit_field_ex: ExtendedMapBitFields; + bit_field_ex: ExtendedMapBitsEx; // Leaves kTaggedSize-1 unused bytes, they will be used by subclasses. } diff --git a/deps/v8/src/objects/microtask-inl.h b/deps/v8/src/objects/microtask-inl.h index fdc166138bfb..952320826017 100644 --- a/deps/v8/src/objects/microtask-inl.h +++ b/deps/v8/src/objects/microtask-inl.h @@ -13,6 +13,7 @@ #include "src/objects/foreign-inl.h" #include "src/objects/js-generator-inl.h" #include "src/objects/js-objects-inl.h" +#include "src/objects/struct-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -20,37 +21,70 @@ namespace v8 { namespace internal { +Microtask::Microtask(const AllocationWitness& witness, Tagged<ReadOnly<Map>> map +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ) + : Struct(map) +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + continuation_preserved_embedder_data_( + witness, continuation_preserved_embedder_data) +#endif +{ + USE(witness); +} + #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA Tagged<Object> Microtask::continuation_preserved_embedder_data() const { return continuation_preserved_embedder_data_.load(); } -void Microtask::set_continuation_preserved_embedder_data( - Tagged<Object> value, WriteBarrierMode mode) { - continuation_preserved_embedder_data_.store(this, value, mode); -} #endif // V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA -Tagged<Foreign> CallbackTask::callback() const { return callback_.load(); } -void CallbackTask::set_callback(Tagged<Foreign> value, WriteBarrierMode mode) { - callback_.store(this, value, mode); +CallbackTask::CallbackTask(const AllocationWitness& witness, + Tagged<Foreign> callback, Tagged<Object> data +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ) + : Microtask(witness, witness.roots().callback_task_map() +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + continuation_preserved_embedder_data +#endif + ), + callback_(witness, callback), + data_(witness, data) { } +Tagged<Foreign> CallbackTask::callback() const { return callback_.load(); } + Tagged<Object> CallbackTask::data() const { return data_.load(); } -void CallbackTask::set_data(Tagged<Object> value, WriteBarrierMode mode) { - data_.store(this, value, mode); + +CallableTask::CallableTask(const AllocationWitness& witness, + Tagged<JSReceiver> callable, + Tagged<NativeContext> context +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ) + : Microtask(witness, witness.roots().callable_task_map() +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + continuation_preserved_embedder_data +#endif + ), + callable_(witness, callable), + context_(witness, context) { } Tagged<JSReceiver> CallableTask::callable() const { return callable_.load(); } -void CallableTask::set_callable(Tagged<JSReceiver> value, - WriteBarrierMode mode) { - callable_.store(this, value, mode); -} Tagged<NativeContext> CallableTask::context() const { return context_.load(); } -void CallableTask::set_context(Tagged<NativeContext> value, - WriteBarrierMode mode) { - context_.store(this, value, mode); -} Tagged<JSGeneratorObject> AsyncResumeTask::generator() const { return generator_.load(); diff --git a/deps/v8/src/objects/microtask.h b/deps/v8/src/objects/microtask.h index a2c981324a4a..eac567c195b4 100644 --- a/deps/v8/src/objects/microtask.h +++ b/deps/v8/src/objects/microtask.h @@ -25,10 +25,15 @@ V8_OBJECT class Microtask : public Struct { V8_IT_ABSTRACT; public: + inline Microtask(const AllocationWitness& witness, Tagged<ReadOnly<Map>> map +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ); + #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA inline Tagged<Object> continuation_preserved_embedder_data() const; - inline void set_continuation_preserved_embedder_data( - Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); #endif DECL_PRINTER(Microtask) @@ -42,7 +47,7 @@ V8_OBJECT class Microtask : public Struct { friend struct ObjectTraits<Microtask>; #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA - TaggedMember<Object> continuation_preserved_embedder_data_; + const TaggedMember<Object> continuation_preserved_embedder_data_; #endif } V8_OBJECT_END; @@ -51,13 +56,16 @@ V8_OBJECT class Microtask : public Struct { // used by Blink for example. V8_OBJECT class CallbackTask : public Microtask { public: - inline Tagged<Foreign> callback() const; - inline void set_callback(Tagged<Foreign> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline CallbackTask(const AllocationWitness& witness, + Tagged<Foreign> callback, Tagged<Object> data +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ); + inline Tagged<Foreign> callback() const; inline Tagged<Object> data() const; - inline void set_data(Tagged<Object> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_VERIFIER(CallbackTask) DECL_PRINTER(CallbackTask) @@ -66,8 +74,8 @@ V8_OBJECT class CallbackTask : public Microtask { friend class TorqueGeneratedCallbackTaskAsserts; friend class MicrotaskQueueBuiltinsAssembler; - TaggedMember<Foreign> callback_; - TaggedMember<Object> data_; + const TaggedMember<Foreign> callback_; + const TaggedMember<Object> data_; } V8_OBJECT_END; // A CallableTask is a special (internal) Microtask that allows us to @@ -75,13 +83,16 @@ V8_OBJECT class CallbackTask : public Microtask { // for various tests of the microtask queue. V8_OBJECT class CallableTask : public Microtask { public: - inline Tagged<JSReceiver> callable() const; - inline void set_callable(Tagged<JSReceiver> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline CallableTask(const AllocationWitness& witness, + Tagged<JSReceiver> callable, Tagged<NativeContext> context +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ); + inline Tagged<JSReceiver> callable() const; inline Tagged<NativeContext> context() const; - inline void set_context(Tagged<NativeContext> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // Dispatched behavior. DECL_VERIFIER(CallableTask) @@ -93,8 +104,8 @@ V8_OBJECT class CallableTask : public Microtask { friend class MicrotaskQueueBuiltinsAssembler; friend class GlobalQueueMicrotaskAssembler; - TaggedMember<JSReceiver> callable_; - TaggedMember<NativeContext> context_; + const TaggedMember<JSReceiver> callable_; + const TaggedMember<NativeContext> context_; } V8_OBJECT_END; // Specialized microtask for resuming async generators/functions when the diff --git a/deps/v8/src/objects/microtask.tq b/deps/v8/src/objects/microtask.tq index d9dd27f71c9c..e94d15f0e069 100644 --- a/deps/v8/src/objects/microtask.tq +++ b/deps/v8/src/objects/microtask.tq @@ -6,7 +6,7 @@ @abstract extern class Microtask extends Struct { @if(V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA) - continuation_preserved_embedder_data: Object|Undefined; + continuation_preserved_embedder_data: Object; } @cppObjectLayoutDefinition diff --git a/deps/v8/src/objects/module-inl.h b/deps/v8/src/objects/module-inl.h index fb9d42c9ba85..a780b973b7e7 100644 --- a/deps/v8/src/objects/module-inl.h +++ b/deps/v8/src/objects/module-inl.h @@ -8,6 +8,7 @@ #include "src/objects/module.h" // Include the non-inl header before the rest of the headers. +#include "src/objects/cell-inl.h" #include "src/objects/js-promise-inl.h" #include "src/objects/oddball-predicates-inl.h" #include "src/objects/scope-info.h" @@ -43,13 +44,8 @@ BOOL_ACCESSORS(SourceTextModule, flags, has_toplevel_await, BIT_FIELD_ACCESSORS(SourceTextModule, flags, async_evaluation_ordinal, SourceTextModule::AsyncEvaluationOrdinalBits) -BIT_FIELD_ACCESSORS(ModuleRequest, flags, position, ModuleRequest::PositionBits) - -inline void ModuleRequest::set_phase(ModuleImportPhase phase) { - DCHECK(PhaseBits::is_valid(phase)); - uint32_t hints = flags(); - hints = PhaseBits::update(hints, phase); - set_flags(hints); +inline unsigned ModuleRequest::position() const { + return PositionBits::decode(flags()); } inline ModuleImportPhase ModuleRequest::phase() const { @@ -124,17 +120,167 @@ class UnorderedModuleSet ZoneAllocator<Handle<Module>>(zone)) {} }; -Handle<SourceTextModule> SourceTextModule::GetCycleRoot( - Isolate* isolate) const { - CHECK_GE(status(), kEvaluatingAsync); - DCHECK(!IsTheHole(cycle_root())); - Handle<SourceTextModule> root(Cast<SourceTextModule>(cycle_root()), isolate); - return root; +template <template <typename> class Holder, typename ModuleT, + typename... Handlers> + requires(std::is_base_of_v<Module, ModuleT> && + (std::is_same_v<Holder<ModuleT>, Handle<ModuleT>> || + std::is_same_v<Holder<ModuleT>, DirectHandle<ModuleT>>)) +decltype(auto) Module::MatchState(Holder<ModuleT> module, + Handlers&&... handlers) { + static_assert(sizeof...(Handlers) > 0); + static_assert( + (HandlesAnyState<Holder, ModuleT, Handlers>(AllStatuses{}) && ...), + "Every handler in MatchState must accept a " + "Handle/DirectHandle<InState<ModuleT, kStates...>> parameter"); + static_assert( + NoDuplicateHandlers<Holder, ModuleT, Handlers...>(AllStatuses{}), + "Duplicate state handler in MatchState"); + constexpr uint32_t kHandledMask = + HandledStatusMask<Holder, ModuleT, Handlers...>(AllStatuses{}); + Overloaded overloaded{std::forward<Handlers>(handlers)...}; + const Status status = module->status(); +#define DISPATCH_STATE(State) \ + case State: \ + if constexpr (std::is_invocable_v<decltype(overloaded)&, \ + Holder<InState<ModuleT, State>>>) { \ + return overloaded(UncheckedCast<InState<ModuleT, State>>(module)); \ + } else { \ + break; \ + } + switch (status) { + DISPATCH_STATE(kUnlinked) + DISPATCH_STATE(kPreLinking) + DISPATCH_STATE(kLinking) + DISPATCH_STATE(kLinked) + DISPATCH_STATE(kEvaluating) + DISPATCH_STATE(kEvaluatingAsync) + DISPATCH_STATE(kEvaluated) + DISPATCH_STATE(kEvaluatedError) + } +#undef DISPATCH_STATE + FatalUnexpectedStatus(status, kHandledMask); +} + +template <typename ModuleT, Module::Status... kStates> +void Module::InState<ModuleT, kStates...>::set_exports( + Tagged<ObjectHashTable> value, WriteBarrierMode mode) + requires(IsModuleAllowed<kPreLinking, kLinking>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + DCHECK(!Module::ExportsFinalized()); + Module::set_exports(value, mode); +} + +template <typename ModuleT, Module::Status... kStates> +void Module::InState<ModuleT, kStates...>::set_star_exports( + Tagged<ObjectHashTable> value, WriteBarrierMode mode) + requires(IsAllowed<kLinking, kLinked, kEvaluating, kEvaluatingAsync, + kEvaluated, kEvaluatedError>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + Module::set_exports(value, mode); +} + +template <typename ModuleT, Module::Status... kStates> +bool Module::InState<ModuleT, kStates...>::ExportsFinalized() const + requires(IsModuleAllowed<kLinking, kLinked, kEvaluating, kEvaluatingAsync, + kEvaluated, kEvaluatedError>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return Module::ExportsFinalized(); +} + +template <typename ModuleT, Module::Status... kStates> +Tagged<SourceTextModule> Module::InState<ModuleT, kStates...>::GetCycleRoot() + const + requires(IsAllowed<kEvaluatingAsync, kEvaluated>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return CheckedCast<SourceTextModule>(this->cycle_root()); +} + +template <typename ModuleT, Module::Status... kStates> +Handle<SourceTextModule> Module::InState<ModuleT, kStates...>::GetCycleRoot( + Isolate* isolate) const + requires(IsAllowed<kEvaluatingAsync, kEvaluated>()) +{ + return v8::internal::handle(GetCycleRoot(), isolate); +} + +template <typename ModuleT, Module::Status... kStates> +MaybeHandle<SourceTextModule> +Module::InState<ModuleT, kStates...>::TryGetCycleRoot(Isolate* isolate) const + requires(IsAllowed<kEvaluatedError>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + Tagged<UnionOf<SourceTextModule, TheHole>> root = this->cycle_root(); + if (IsTheHole(root)) return {}; + return v8::internal::handle(Cast<SourceTextModule>(root), isolate); +} + +template <typename ModuleT, Module::Status... kStates> +int Module::InState<ModuleT, kStates...>::dfs_index() const + requires(IsAllowed<kLinking, kEvaluating>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return SourceTextModule::dfs_index(); +} + +template <typename ModuleT, Module::Status... kStates> +int Module::InState<ModuleT, kStates...>::dfs_ancestor_index() const + requires(IsAllowed<kLinking, kEvaluating>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return SourceTextModule::dfs_ancestor_index(); +} + +template <typename ModuleT, Module::Status... kStates> +void Module::InState<ModuleT, kStates...>::UpdateDfsAncestorIndex( + DirectHandle<InState<SourceTextModule, kLinking>> child) + requires(IsAllowed<kLinking>()) +{ + this->set_dfs_ancestor_index( + std::min(dfs_ancestor_index(), child->dfs_ancestor_index())); +} + +template <typename ModuleT, Module::Status... kStates> +void Module::InState<ModuleT, kStates...>::UpdateDfsAncestorIndex( + DirectHandle<InState<SourceTextModule, kEvaluating>> child) + requires(IsAllowed<kEvaluating>()) +{ + this->set_dfs_ancestor_index( + std::min(dfs_ancestor_index(), child->dfs_ancestor_index())); +} + +template <typename ModuleT, Module::Status... kStates> +bool Module::InState<ModuleT, kStates...>::HasPendingAsyncDependencies() + requires(IsAllowed<kEvaluating, kEvaluatingAsync>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return SourceTextModule::HasPendingAsyncDependencies(); +} + +template <typename ModuleT, Module::Status... kStates> +void Module::InState<ModuleT, kStates...>::IncrementPendingAsyncDependencies() + requires(IsAllowed<kEvaluating>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + SourceTextModule::IncrementPendingAsyncDependencies(); +} + +template <typename ModuleT, Module::Status... kStates> +void Module::InState<ModuleT, kStates...>::DecrementPendingAsyncDependencies() + requires(IsAllowed<kEvaluatingAsync>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + SourceTextModule::DecrementPendingAsyncDependencies(); } void SourceTextModule::AddAsyncParentModule( - Isolate* isolate, DirectHandle<SourceTextModule> module, - DirectHandle<SourceTextModule> parent) { + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module, + DirectHandle<InState<kEvaluating>> parent) { + DCHECK(module->HasAsyncEvaluationOrdinal()); DirectHandle<ArrayList> async_parent_modules(module->async_parent_modules(), isolate); DirectHandle<ArrayList> new_array_list = @@ -172,13 +318,16 @@ void SourceTextModule::DecrementPendingAsyncDependencies() { Tagged<ObjectHashTable> Module::exports() const { return exports_.load(); } void Module::set_exports(Tagged<ObjectHashTable> value, WriteBarrierMode mode) { + CHECK(!ExportsFinalized()); exports_.store(this, value, mode); } int Module::hash() const { return hash_.load().value(); } void Module::set_hash(int value) { hash_.store(this, Smi::FromInt(value)); } -int Module::status() const { return status_.load().value(); } +Module::Status Module::status() const { + return static_cast<Status>(status_.load().value()); +} void Module::set_status(int value) { status_.store(this, Smi::FromInt(value)); } Tagged<UnionOf<Cell, Undefined>> Module::module_namespace() const { @@ -197,6 +346,16 @@ void Module::set_deferred_module_namespace( deferred_module_namespace_.store(this, value, mode); } +bool Module::ExportsFinalized() const { + bool res = + (!IsUndefined(module_namespace()) && + IsJSModuleNamespace(Cast<Cell>(module_namespace())->value())) || + (!IsUndefined(deferred_module_namespace()) && + IsJSModuleNamespace(Cast<Cell>(deferred_module_namespace())->value())); + DCHECK_IMPLIES(res, status() >= kLinking); + return res; +} + Tagged<Module> JSModuleNamespace::module() const { return module_.load(); } void JSModuleNamespace::set_module(Tagged<Module> value, diff --git a/deps/v8/src/objects/module.cc b/deps/v8/src/objects/module.cc index 46c4748a66ce..c5cfc72599a7 100644 --- a/deps/v8/src/objects/module.cc +++ b/deps/v8/src/objects/module.cc @@ -4,14 +4,21 @@ #include "src/objects/module.h" +#include <array> +#include <istream> +#include <sstream> +#include <strstream> #include <unordered_map> #include <unordered_set> #include "include/v8-template.h" #include "src/api/api-inl.h" #include "src/ast/modules.h" +#include "src/base/strings.h" +#include "src/base/vector.h" #include "src/builtins/accessors.h" #include "src/common/assert-scope.h" +#include "src/debug/debug.h" #include "src/heap/heap-inl.h" #include "src/logging/counters.h" #include "src/objects/cell-inl.h" @@ -20,7 +27,7 @@ #include "src/objects/module-inl.h" #include "src/objects/object-predicates-inl.h" #include "src/objects/property-descriptor.h" -#include "src/objects/source-text-module.h" +#include "src/objects/source-text-module-inl.h" #include "src/objects/synthetic-module-inl.h" #include "src/utils/ostreams.h" @@ -59,20 +66,8 @@ void PrintStatusMessage(Tagged<Module> module, const char* message) { } #endif // DEBUG -void SetStatusInternal(Tagged<Module> module, Module::Status new_status) { - DisallowGarbageCollection no_gc; -#ifdef DEBUG - Module::Status old_status = static_cast<Module::Status>(module->status()); - module->set_status(new_status); - PrintStatusTransition(module, old_status); -#else - module->set_status(new_status); -#endif // DEBUG -} - } // end namespace -#ifdef DEBUG // static const char* Module::StatusString(Module::Status status) { switch (status) { @@ -90,33 +85,52 @@ const char* Module::StatusString(Module::Status status) { return "EvaluatingAsync"; case Module::kEvaluated: return "Evaluated"; - case Module::kErrored: - return "Errored"; + case Module::kEvaluatedError: + return "EvaluatedError"; } - UNREACHABLE(); + // Reached only with a corrupted status; this function is used to report + // exactly that, so it must not crash itself. + return "<invalid>"; } -#endif // DEBUG -void Module::SetStatus(Status new_status) { +// static +void Module::FatalUnexpectedStatus(Status status, uint32_t status_mask) { + std::stringstream expected; + for (int s = kFirst; s <= kLast; ++s) { + if ((status_mask & (uint32_t{1} << s)) == 0) continue; + if (!expected.str().empty()) { + expected << ", "; + } + expected << StatusString(static_cast<Status>(s)); + } + // Multi-argument FATAL keeps its message in all build modes, so the crash + // signature names the offending state. + FATAL("Module in unexpected status %s (%d), expected one of {%s}", + StatusString(status), static_cast<int>(status), expected.str().data()); +} + +void Module::SetStatusInternal(Status new_status) { DisallowGarbageCollection no_gc; - DCHECK_LE(status(), new_status); - DCHECK_NE(new_status, Module::kErrored); - SetStatusInternal(this, new_status); +#ifdef DEBUG + Status old_status = status(); + DCHECK(IsValidTransition(old_status, new_status)); + set_status(new_status); + PrintStatusTransition(this, old_status); +#else + set_status(new_status); +#endif // DEBUG } -void Module::RecordError(Isolate* isolate, Tagged<Object> error) { +void Module::RecordErrorInternal(Isolate* isolate, Tagged<Object> error) { DisallowGarbageCollection no_gc; - // Allow overriding exceptions with termination exceptions. - DCHECK_IMPLIES(isolate->is_catchable_by_javascript(error), - IsTheHole(exception())); + DCHECK(IsTheHole(exception())); DCHECK(!IsTheHole(error)); - if (Is<SourceTextModule>(this)) { + if (Tagged<SourceTextModule> self; TryCast(Tagged(this), &self)) { // Revert to minimal SFI in case we have already been instantiating or // evaluating. - auto self = Cast<SourceTextModule>(this); self->set_code(self->GetSharedFunctionInfo()); } - SetStatusInternal(this, Module::kErrored); + SetStatusInternal(Module::kEvaluatedError); if (isolate->is_catchable_by_javascript(error)) { set_exception(error); } else { @@ -125,70 +139,73 @@ void Module::RecordError(Isolate* isolate, Tagged<Object> error) { } } -void Module::ResetGraph(Isolate* isolate, DirectHandle<Module> module) { - DCHECK_NE(module->status(), kEvaluating); - if (module->status() != kPreLinking && module->status() != kLinking) { +void Module::ResetGraph(Isolate* isolate, Handle<Module> module) { + MatchState( + module, + [](DirectHandle<InState<Module, kUnlinked, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + m) { #ifdef DEBUG - if (IsSourceTextModule(*module)) { - Cast<SourceTextModule>(*module)->VerifyRequestedModules(); - } + if (Tagged<SourceTextModule> stm; TryCast(*m, &stm)) { + stm->VerifyRequestedModules(); + } #endif // DEBUG - return; - } - - DirectHandle<FixedArray> requested_modules = - IsSourceTextModule(*module) - ? DirectHandle<FixedArray>( - Cast<SourceTextModule>(*module)->requested_modules(), isolate) - : DirectHandle<FixedArray>(); - Reset(isolate, module); - - if (!IsSourceTextModule(*module)) { - DCHECK(IsSyntheticModule(*module)); - return; - } - const uint32_t requested_modules_len = requested_modules->ulength().value(); - for (uint32_t i = 0; i < requested_modules_len; ++i) { - DirectHandle<Object> descendant(requested_modules->get(i), isolate); - if (IsModule(*descendant)) { - ResetGraph(isolate, Cast<Module>(descendant)); - } else { - // Source phase imports store a JSReceiver (e.g. WasmModuleObject) in - // requested_modules. Pre-linking entries are Undefined. - CHECK(IsUndefined(*descendant) || IsJSReceiver(*descendant)); - } - } + }, + [&](DirectHandle<InState<Module, kPreLinking, kLinking>> m) { + DirectHandle<SourceTextModule> stm; + if (!TryCast(m, &stm)) { + Reset(isolate, m); + return; + } + // Reset() clears requested_modules, so read it beforehand. + DirectHandle<FixedArray> requested_modules(stm->requested_modules(), + isolate); + Reset(isolate, m); + + const uint32_t requested_modules_len = + requested_modules->ulength().value(); + for (uint32_t i = 0; i < requested_modules_len; ++i) { + Handle<Object> descendant(requested_modules->get(i), isolate); + if (Handle<Module> requested_module; + TryCast(descendant, &requested_module)) { + ResetGraph(isolate, requested_module); + } else { + // Source phase imports store a JSReceiver (e.g. WasmModuleObject) + // in requested_modules. Pre-linking entries are Undefined. + CHECK(IsUndefined(*descendant) || IsJSReceiver(*descendant)); + } + } + }); } -void Module::Reset(Isolate* isolate, DirectHandle<Module> module) { - DCHECK(module->status() == kPreLinking || module->status() == kLinking); +void Module::Reset( + Isolate* isolate, + DirectHandle<InState<Module, kPreLinking, kLinking>> module) { DCHECK(IsTheHole(module->exception())); // The namespace cells could have been created during ResolveExport for // 'export * as ns', reset them here. module->set_module_namespace(ReadOnlyRoots(isolate).undefined_value()); module->set_deferred_module_namespace( ReadOnlyRoots(isolate).undefined_value()); - const uint32_t export_count = - IsSourceTextModule(*module) - ? Cast<SourceTextModule>(*module) - ->regular_exports() - ->ulength() - .value() - : Cast<SyntheticModule>(*module)->export_names()->ulength().value(); - DirectHandle<ObjectHashTable> exports = - ObjectHashTable::New(isolate, export_count); - - if (IsSourceTextModule(*module)) { - SourceTextModule::Reset(isolate, Cast<SourceTextModule>(module)); + DirectHandle<InState<SourceTextModule, kPreLinking, kLinking>> stm; + if (!TryCast(module, &stm)) { + DirectHandle<ObjectHashTable> exports = ObjectHashTable::New( + isolate, + Cast<SyntheticModule>(*module)->export_names()->ulength().value()); + module->set_exports(*exports); + TransitionStatus<kUnlinked>(module); + return; } - + DirectHandle<ObjectHashTable> exports = + ObjectHashTable::New(isolate, stm->regular_exports()->ulength().value()); + SourceTextModule::Reset(isolate, stm); module->set_exports(*exports); - SetStatusInternal(*module, kUnlinked); + TransitionStatus<kUnlinked>(module); } Tagged<Object> Module::GetException() { DisallowGarbageCollection no_gc; - DCHECK_EQ(status(), Module::kErrored); + DCHECK_EQ(status(), Module::kEvaluatedError); DCHECK(!IsTheHole(exception())); return exception(); } @@ -198,17 +215,20 @@ MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module, Handle<String> export_name, MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) { - DCHECK_GE(module->status(), kPreLinking); - DCHECK_NE(module->status(), kEvaluating); - - if (IsSourceTextModule(*module)) { + if (Handle<SourceTextModule> stm; TryCast(module, &stm)) { return SourceTextModule::ResolveExport( - isolate, Cast<SourceTextModule>(module), module_specifier, export_name, - loc, must_resolve, resolve_set); + isolate, + CheckedCast<InState<SourceTextModule, kPreLinking, kLinking, kLinked, + kEvaluatingAsync, kEvaluated, kEvaluatedError>>( + stm), + module_specifier, export_name, loc, must_resolve, resolve_set); } else { return SyntheticModule::ResolveExport( - isolate, CheckedCast<SyntheticModule>(module), module_specifier, - export_name, loc, must_resolve); + isolate, + CheckedCast<InState<SyntheticModule, kPreLinking, kLinking, kLinked, + kEvaluatingAsync, kEvaluated, kEvaluatedError>>( + module), + module_specifier, export_name, loc, must_resolve); } } @@ -225,7 +245,7 @@ bool Module::Instantiate(Isolate* isolate, Handle<Module> module, return false; } Zone zone(isolate->allocator(), ZONE_NAME); - ZoneForwardList<Handle<SourceTextModule>> stack(&zone); + ZoneForwardList<Handle<SourceTextModule::InState<kLinking>>> stack(&zone); unsigned dfs_index = 0; unsigned max_depth = 0; if (!FinishInstantiate(isolate, module, &stack, &dfs_index, &zone, 1, @@ -241,100 +261,225 @@ bool Module::Instantiate(Isolate* isolate, Handle<Module> module, return true; } -bool Module::PrepareInstantiate(Isolate* isolate, DirectHandle<Module> module, +bool Module::PrepareInstantiate(Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context, const UserResolveCallbacks& callbacks) { - DCHECK_NE(module->status(), kEvaluating); - DCHECK_NE(module->status(), kLinking); - if (module->status() >= kPreLinking) return true; - module->SetStatus(kPreLinking); - STACK_CHECK(isolate, false); - - if (IsSourceTextModule(*module)) { - return SourceTextModule::PrepareInstantiate( - isolate, Cast<SourceTextModule>(module), context, callbacks); - } else { - return SyntheticModule::PrepareInstantiate( - isolate, Cast<SyntheticModule>(module), context); - } + return MatchState( + module, + [](DirectHandle<InState<Module, kPreLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>>) { return true; }, + [&](Handle<InState<Module, kUnlinked>> unlinked) { + Handle<InState<Module, kPreLinking>> pre_linking = + TransitionStatus<kPreLinking>(unlinked); + STACK_CHECK(isolate, false); + if (Handle<InState<SourceTextModule, kPreLinking>> stm; + TryCast(pre_linking, &stm)) { + return SourceTextModule::PrepareInstantiate(isolate, stm, context, + callbacks); + } else { + return SyntheticModule::PrepareInstantiate( + isolate, Cast<InState<SyntheticModule, kPreLinking>>(pre_linking), + context); + } + }); } -bool Module::FinishInstantiate(Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, - unsigned* dfs_index, Zone* zone, unsigned depth, - unsigned* max_depth) { - DCHECK_NE(module->status(), kEvaluating); +bool Module::FinishInstantiate( + Isolate* isolate, Handle<Module> module, + ZoneForwardList<Handle<InState<SourceTextModule, kLinking>>>* stack, + unsigned* dfs_index, Zone* zone, unsigned depth, unsigned* max_depth) { if (max_depth) *max_depth = std::max(*max_depth, depth); - if (module->status() >= kLinking) return true; - DCHECK_EQ(module->status(), kPreLinking); - STACK_CHECK(isolate, false); - - if (IsSourceTextModule(*module)) { - return SourceTextModule::FinishInstantiate( - isolate, Cast<SourceTextModule>(module), stack, dfs_index, zone, depth, - max_depth); - } else { - return SyntheticModule::FinishInstantiate(isolate, - Cast<SyntheticModule>(module)); - } + return MatchState( + module, + [](DirectHandle<InState<Module, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>>) { return true; }, + [&](Handle<InState<Module, kPreLinking>> pre_linking) { + STACK_CHECK(isolate, false); + if (Handle<InState<SourceTextModule, kPreLinking>> stm; + TryCast(pre_linking, &stm)) { + return SourceTextModule::FinishInstantiate( + isolate, stm, stack, dfs_index, zone, depth, max_depth); + } else { + return SyntheticModule::FinishInstantiate( + isolate, + Cast<InState<SyntheticModule, kPreLinking>>(pre_linking)); + } + }); } +// https://tc39.es/ecma262/#sec-moduleevaluation MaybeDirectHandle<JSPromise> Module::Evaluate(Isolate* isolate, Handle<Module> module) { #ifdef DEBUG PrintStatusMessage(*module, "Evaluating module "); #endif // DEBUG - int module_status = module->status(); - - // In the event of errored evaluation, return a rejected promise. - if (module_status == kErrored) { - // If we have a top level capability we assume it has already been - // rejected, and return it here. Otherwise create a new promise and - // reject it with the module's exception. - if (IsJSPromise(module->top_level_capability())) { - DirectHandle<JSPromise> top_level_capability( - Cast<JSPromise>(module->top_level_capability()), isolate); - DCHECK(top_level_capability->status() == Promise::kRejected && - top_level_capability->result() == module->exception()); - return top_level_capability; - } - DirectHandle<JSPromise> capability = isolate->factory()->NewJSPromise(); - JSPromise::Reject(capability, direct_handle(module->exception(), isolate)); - return capability; - } - // Start of Evaluate () Concrete Method // 2. Assert: module.[[Status]] is one of LINKED, EVALUATING-ASYNC, or // EVALUATED. - CHECK(module_status == kLinked || module_status == kEvaluatingAsync || - module_status == kEvaluated); + DCHECK(module->status() == kLinked || module->status() == kEvaluatingAsync || + module->status() == kEvaluated || module->status() == kEvaluatedError); // 3. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, then - // a. If module.[[CycleRoot]] is not empty, then - // i. Set module to module.[[CycleRoot]]. - // b. Else, - // i. Assert: module.[[Status]] is EVALUATED and - // module.[[EvaluationError]] is a throw completion. - // (The early return for kErrored above handles the case where CycleRoot is - // empty.) - // A Synthetic Module has no children so it is its own cycle root. - if (module_status >= kEvaluatingAsync && IsSourceTextModule(*module)) { - module = Cast<SourceTextModule>(module)->GetCycleRoot(isolate); + // A synthetic module has no dependencies, so it is its own cycle root. + if (Handle<SourceTextModule> stm; TryCast(module, &stm)) { + module = MatchState( + stm, + [](Handle<InState<SourceTextModule, kLinked>> m) -> Handle<Module> { + DCHECK(IsTheHole(m->cycle_root())); + return m; + }, + [&](DirectHandle< + InState<SourceTextModule, kEvaluatingAsync, kEvaluated>> + m) -> Handle<Module> { + // a. If module.[[CycleRoot]] is not EMPTY, then + // i. Set module to module.[[CycleRoot]]. + return m->GetCycleRoot(isolate); + }, + [&](Handle<InState<SourceTextModule, kEvaluatedError>> m) + -> Handle<Module> { + // a. If module.[[CycleRoot]] is not EMPTY, then + // i. Set module to module.[[CycleRoot]]. + if (Handle<SourceTextModule> cycle_root; + m->TryGetCycleRoot(isolate).ToHandle(&cycle_root)) { + return cycle_root; + } + // b. Else, + // i. Assert: module.[[Status]] is EVALUATED and + // module.[[EvaluationError]] is a throw completion. + DCHECK_EQ(m->status(), kEvaluatedError); + DCHECK(!IsTheHole(m->exception())); + return m; + }); } // 4. If module.[[TopLevelCapability]] is not EMPTY, then // a. Return module.[[TopLevelCapability]].[[Promise]]. if (IsJSPromise(module->top_level_capability())) { - return direct_handle(Cast<JSPromise>(module->top_level_capability()), - isolate); + DirectHandle<JSPromise> capability( + Cast<JSPromise>(module->top_level_capability()), isolate); + DCHECK_IMPLIES(module->status() == kEvaluatedError, + capability->status() == Promise::kRejected && + capability->result() == module->exception()); + return capability; } DCHECK(IsUndefined(module->top_level_capability())); - if (IsSourceTextModule(*module)) { - return SourceTextModule::Evaluate(isolate, Cast<SourceTextModule>(module)); - } else { - return SyntheticModule::Evaluate(isolate, Cast<SyntheticModule>(module)); + // If module.[[TopLevelCapability]] is EMPTY for an already-evaluating or + // already-evaluated module, steps 6-11 of #sec-moduleevaluation allocate and + // store a new capability on `module` and call InnerModuleEvaluation(module, + // stack, 0), which immediately returns in step 2 (#sec-innermoduleevaluation) + // without modifying `stack`: + // - EVALUATING-ASYNC: step 2.a returns NormalCompletion(0); step 10.c is + // skipped; step 11 returns the pending capability. + // - EVALUATED (no error): step 2.a returns NormalCompletion(0); step + // 10.c.iii resolves the capability with undefined; step 11 returns it. + // - EVALUATED (errored): step 2.b returns module.[[EvaluationError]] with + // `stack` empty; step 9.d rejects the capability with the error; step 11 + // returns it. + return MatchState( + module, + [&](DirectHandle<InState<Module, kEvaluatingAsync>> m) + -> MaybeDirectHandle<JSPromise> { + // 6. Let capability be ! NewPromiseCapability(%Promise%). + DirectHandle<JSPromise> capability = isolate->factory()->NewJSPromise(); + // 7. Set module.[[TopLevelCapability]] to capability. + m->set_top_level_capability(*capability); + // 8. InnerModuleEvaluation step 2.a returns 0. + // 11. Return capability.[[Promise]]. + return capability; + }, + [&](DirectHandle<InState<Module, kEvaluated>> m) + -> MaybeDirectHandle<JSPromise> { + // 6. Let capability be ! NewPromiseCapability(%Promise%). + DirectHandle<JSPromise> capability = isolate->factory()->NewJSPromise(); + // 7. Set module.[[TopLevelCapability]] to capability. + m->set_top_level_capability(*capability); + // 8. InnerModuleEvaluation step 2.a returns 0. + // 10.c.iii. Perform ! Call(capability.[[Resolve]], undefined, + // « undefined »). + JSPromise::Resolve(capability, isolate->factory()->undefined_value()) + .ToHandleChecked(); + // 11. Return capability.[[Promise]]. + return capability; + }, + [&](DirectHandle<InState<Module, kEvaluatedError>> m) + -> MaybeDirectHandle<JSPromise> { + // 6. Let capability be ! NewPromiseCapability(%Promise%). + DirectHandle<JSPromise> capability = isolate->factory()->NewJSPromise(); + // 7. Set module.[[TopLevelCapability]] to capability. + m->set_top_level_capability(*capability); + // 8. InnerModuleEvaluation step 2.b returns module.[[EvaluationError]]. + // 9.d. Perform ! Call(capability.[[Reject]], undefined, + // « result.[[Value]] »). + JSPromise::Reject(capability, + direct_handle(m->GetException(), isolate)); + if (isolate->debug()->IsRestartFrameScheduled()) { + m->set_top_level_capability(ReadOnlyRoots(isolate).undefined_value()); + isolate->TerminateExecution(); + return {}; + } + // 11. Return capability.[[Promise]]. + return capability; + }, + [&](Handle<InState<Module, kLinked>> linked) + -> MaybeDirectHandle<JSPromise> { + if (Handle<InState<SourceTextModule, kLinked>> stm; + TryCast(linked, &stm)) { + return SourceTextModule::Evaluate(isolate, stm); + } else { + return SyntheticModule::Evaluate( + isolate, Cast<InState<SyntheticModule, kLinked>>(linked)); + } + }); +} + +// https://tc39.es/proposal-defer-import-eval/#sec-EvaluateModuleSync +bool Module::EvaluateModuleSync(Isolate* isolate, Handle<Module> module) { + // 2. If ReadyForSyncExecution(module) is false, throw a TypeError exception. + { + Zone zone(isolate->allocator(), ZONE_NAME); + UnorderedModuleSet seen_modules(&zone); + if (!SourceTextModule::ReadyForSyncExecution(isolate, module, + &seen_modules)) { + isolate->Throw(*isolate->factory()->NewTypeError( + MessageTemplate::kNotReadyForSyncExec)); + return false; + } + } + + // A side-effect-free debug-evaluate must not start the evaluation. + if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) { + isolate->debug()->FailSideEffectCheckForDeferredModuleEvaluation(); + return false; + } + + // 3. Let promise be module.Evaluate(). + DirectHandle<JSPromise> promise; + if (!Module::Evaluate(isolate, module).ToHandle(&promise)) { + DCHECK(isolate->has_exception()); + return false; + } + + // 4. Assert: promise.[[PromiseState]] is either FULFILLED or REJECTED. + DCHECK(promise->status() == Promise::kFulfilled || + promise->status() == Promise::kRejected); + // 5. If promise.[[PromiseState]] is REJECTED, then + if (promise->status() == Promise::kRejected) { + // a. If promise.[[PromiseIsHandled]] is false, perform + // HostPromiseRejectionTracker(promise, "handle"). + if (!promise->has_handler()) { + isolate->ReportPromiseReject(promise, DirectHandle<Object>(), + v8::kPromiseHandlerAddedAfterReject); + } + // b. Set promise.[[PromiseIsHandled]] to true. + promise->set_has_handler(true); + // c. Throw promise.[[PromiseResult]]. + isolate->Throw(promise->result()); + return false; } + DCHECK_EQ(promise->status(), Promise::kFulfilled); + // 6. Return UNUSED. + return true; } Handle<Cell> Module::GetModuleNamespaceCell(Isolate* isolate, @@ -376,20 +521,33 @@ DirectHandle<JSModuleNamespace> Module::GetModuleNamespace( Zone zone(isolate->allocator(), ZONE_NAME); UnorderedModuleSet visited(&zone); - if (IsSourceTextModule(*module)) { - SourceTextModule::FetchStarExports(isolate, Cast<SourceTextModule>(module), - &zone, &visited); + if (Handle<SourceTextModule> stm; TryCast(module, &stm)) { + SourceTextModule::FetchStarExports( + isolate, + CheckedCast<InState<SourceTextModule, kLinking, kLinked, kEvaluating, + kEvaluatingAsync, kEvaluated, kEvaluatedError>>( + stm), + &zone, &visited); } DirectHandle<ObjectHashTable> exports(module->exports(), isolate); ZoneVector<IndirectHandle<String>> names(&zone); names.reserve(exports->NumberOfElements()); + [[maybe_unused]] bool skipped_then = false; for (InternalIndex i : exports->IterateEntries()) { Tagged<Object> key; if (!exports->ToKey(roots, i, &key)) continue; + // https://tc39.es/proposal-defer-import-eval/#sec-getmodulenamespace + // Deferred namespaces never expose a "then" export, so that awaiting + // import.defer() resolves to the namespace itself. + if (phase == ModuleImportPhase::kDefer && key == roots.then_string()) { + skipped_then = true; + continue; + } names.push_back(handle(Cast<String>(key), isolate)); } - DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements()); + DCHECK_EQ(static_cast<int>(names.size()), + exports->NumberOfElements() - (skipped_then ? 1 : 0)); // Sort them alphabetically. std::sort(names.begin(), names.end(), @@ -524,40 +682,11 @@ Maybe<PropertyAttributes> JSModuleNamespace::GetPropertyAttributes( } } -// https://tc39.es/proposal-defer-import-eval/#sec-EvaluateModuleSync +// https://tc39.es/proposal-defer-import-eval/#sec-GetModuleExportsList void JSDeferredModuleNamespace::EvaluateModuleSync( Isolate* isolate, DirectHandle<JSDeferredModuleNamespace> holder) { - Handle<Module> module = handle(holder->module(), isolate); - - // https://tc39.es/proposal-defer-import-eval/#sec-GetModuleExportsList - Zone zone(isolate->allocator(), ZONE_NAME); - UnorderedModuleSet seenModules(&zone); - if (!SourceTextModule::ReadyForSyncExecution(isolate, module, &seenModules)) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kNotReadyForSyncExec)); - return; - } - - MaybeDirectHandle<JSPromise> maybe_result = Module::Evaluate(isolate, module); - DirectHandle<JSPromise> promise; - if (!maybe_result.ToHandle(&promise)) { - return; - } - - // The result is always the module's top-level capability promise. - // 5. If promise.[[PromiseState]] is rejected, then - if (promise->status() == Promise::kRejected) { - // a. If promise.[[PromiseIsHandled]] is false, perform - // HostPromiseRejectionTracker(promise, "handle"). - if (!promise->has_handler()) { - isolate->ReportPromiseReject(promise, DirectHandle<Object>(), - v8::kPromiseHandlerAddedAfterReject); - } - promise->set_has_handler(true); - isolate->Throw(promise->result()); - return; - } - DCHECK_EQ(promise->status(), Promise::kFulfilled); + // Callers check isolate->has_exception(). + USE(Module::EvaluateModuleSync(isolate, handle(holder->module(), isolate))); } bool JSDeferredModuleNamespace::TriggersEvaluation(LookupIterator* it) { diff --git a/deps/v8/src/objects/module.h b/deps/v8/src/objects/module.h index 925b7d361666..23042404d9d6 100644 --- a/deps/v8/src/objects/module.h +++ b/deps/v8/src/objects/module.h @@ -17,10 +17,13 @@ namespace v8 { namespace internal { +class JSAsyncFunctionObject; class JSModuleNamespace; +class SourceTextModule; class SourceTextModuleDescriptor; class SourceTextModuleInfo; class SourceTextModuleInfoEntry; +class SyntheticModule; class Zone; template <typename T> class ZoneForwardList; @@ -35,24 +38,103 @@ V8_OBJECT class Module : public HeapObject { DECL_VERIFIER(Module) DECL_PRINTER(Module) - enum Status { + // A module only ever moves forward through these states (see + // IsValidTransition, TransitionStatus, and RecordError): + // + // kUnlinked -> kPreLinking -> kLinking -> kLinked -> kEvaluating + // + // kPreLinking -> kLinked (synthetic modules skip kLinking) + // kPreLinking -> kUnlinked (failed link resets the graph) + // kLinking -> kUnlinked (failed link resets the graph) + // + // kEvaluating -> kEvaluatingAsync -> kEvaluated + // kEvaluating -> kEvaluated + // kEvaluating -> kEvaluatedError + // kEvaluatingAsync -> kEvaluatedError + // + // kEvaluating means the module is on the DFS stack of an in-progress + // Evaluate() call. kEvaluatedError is the spec's EVALUATED with a non-empty + // [[EvaluationError]]: {exception} holds the error, or null if a termination + // exception aborted evaluation. When Evaluate() fails, every module on its + // DFS stack becomes kEvaluatedError. + // + // {top_level_capability} is the promise returned by Evaluate(). Evaluate() + // redirects to the cycle root of an already evaluated strongly connected + // component, so the capability lives on cycle roots (and on synthetic + // modules) and mirrors their status: pending while kEvaluating or + // kEvaluatingAsync, fulfilled when kEvaluated, and rejected with {exception} + // when kEvaluatedError (dropped to undefined if termination prevented + // rejecting it, in which case a later Evaluate() materializes a fresh + // capability rejected with null). These are steady-state invariants: + // JSPromise resolution runs embedder hooks before the promise changes state, + // so they are asserted where the capability is used, not in the heap + // verifier. + enum Status : int { + kFirst, + // Order matters! - kUnlinked, + kUnlinked = kFirst, kPreLinking, kLinking, kLinked, kEvaluating, kEvaluatingAsync, kEvaluated, - kErrored + kEvaluatedError, + + kLast = kEvaluatedError }; -#ifdef DEBUG + template <Status... kStatuses> + struct StatusList { + static constexpr size_t kSize = sizeof...(kStatuses); + }; + // The single source of truth for "every status" used by the compile-time + // checks and the dispatch in MatchState. + using AllStatuses = + StatusList<kUnlinked, kPreLinking, kLinking, kLinked, kEvaluating, + kEvaluatingAsync, kEvaluated, kEvaluatedError>; + static_assert(AllStatuses::kSize == kEvaluatedError + 1); + + static constexpr bool IsValidTransition(Status from, Status to) { + switch (from) { + case kUnlinked: + return to == kPreLinking; + case kPreLinking: + return to == kLinking || to == kLinked || to == kUnlinked; + case kLinking: + return to == kLinked || to == kUnlinked; + case kLinked: + return to == kEvaluating; + case kEvaluating: + return to == kEvaluatingAsync || to == kEvaluated || + to == kEvaluatedError; + case kEvaluatingAsync: + return to == kEvaluated || to == kEvaluatedError; + case kEvaluated: + case kEvaluatedError: + return false; + } + } + + template <Status... kAllowed> + static constexpr bool IsStateIn(Status s) { + return ((s == kAllowed) || ...); + } + + // Typestate handle proving at compile time that [handle] is in one + // of [kStates...] and restricting state-dependent operations, transitions, + // and fields to the states where they are valid. Obtained only by branching + // via MatchState or as the result of a checked transition. + template <typename ModuleT, Status... kStates> + class InState; + + // Human-readable name of [status]; "<invalid>" for out-of-range values. static const char* StatusString(Module::Status status); -#endif // DEBUG - // The exception in the case {status} is kErrored. + // The exception in the case {status} is kEvaluatedError. Tagged<Object> GetException(); + inline Tagged<Object> exception() const; // Returns if this module or any transitively requested module is [[Async]], // i.e. has a top-level await. @@ -73,10 +155,19 @@ V8_OBJECT class Module : public HeapObject { Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context, const UserResolveCallbacks& callbacks); - // Implementation of spec operation ModuleEvaluation. + // Implementation of spec operation ModuleEvaluation. Returns the module's + // top-level capability promise, or an empty handle with the exception + // pending if evaluation was aborted by a termination exception or a + // synthetic module's evaluation steps threw. static V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSPromise> Evaluate( Isolate* isolate, Handle<Module> module); + // Implementation of spec abstract operation EvaluateModuleSync. Throws and + // returns false if the module is not ready for synchronous execution or if + // evaluation rejects. + static V8_WARN_UNUSED_RESULT bool EvaluateModuleSync(Isolate* isolate, + Handle<Module> module); + // Get the namespace object for [module]. If it doesn't exist yet, it is // created. static Handle<Cell> GetModuleNamespaceCell( @@ -87,14 +178,11 @@ V8_OBJECT class Module : public HeapObject { ModuleImportPhase phase = ModuleImportPhase::kEvaluation); inline Tagged<ObjectHashTable> exports() const; - inline void set_exports(Tagged<ObjectHashTable> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline int hash() const; inline void set_hash(int value); - inline int status() const; - inline void set_status(int value); + inline Status status() const; inline Tagged<UnionOf<Cell, Undefined>> module_namespace() const; inline void set_module_namespace( @@ -106,19 +194,61 @@ V8_OBJECT class Module : public HeapObject { Tagged<UnionOf<Cell, Undefined>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> exception() const; - inline void set_exception(Tagged<Object> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<UnionOf<JSPromise, Undefined>> top_level_capability() const; - inline void set_top_level_capability( - Tagged<UnionOf<JSPromise, Undefined>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); struct Hash; protected: friend class Factory; + template <typename ModuleT, Status... kStates> + friend class InState; + + inline void set_top_level_capability( + Tagged<UnionOf<JSPromise, Undefined>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + + // Checked state transitions; the allowed edges are statically verified + // against IsValidTransition. + template <Status kTo, template <typename> class Holder, typename ModuleT, + Status... kStates> + requires((IsValidTransition(kStates, kTo) && ...) && + (std::is_same_v<Holder<ModuleT>, Handle<ModuleT>> || + std::is_same_v<Holder<ModuleT>, DirectHandle<ModuleT>>)) + static inline Holder<InState<ModuleT, kTo>> TransitionStatus( + Holder<InState<ModuleT, kStates...>> module) { + CHECK(((module->status() == kStates) || ...)); + module->SetStatusInternal(kTo); + return UncheckedCast<InState<ModuleT, kTo>>(module); + } + + // Transitions from kEvaluating or kEvaluatingAsync to kEvaluatedError. + // Records [error] as {exception} (null for a termination exception) and, for + // source text modules, drops the generator and ends async evaluation. + template <template <typename> class Holder, typename ModuleT, + Status... kStates> + requires((IsValidTransition(kStates, kEvaluatedError) && ...) && + (std::is_same_v<Holder<ModuleT>, Handle<ModuleT>> || + std::is_same_v<Holder<ModuleT>, DirectHandle<ModuleT>>)) + static inline Holder<InState<ModuleT, kEvaluatedError>> RecordError( + Isolate* isolate, Holder<InState<ModuleT, kStates...>> module, + DirectHandle<Object> error) { + CHECK(((module->status() == kStates) || ...)); + module->RecordErrorInternal(isolate, *error); + return UncheckedCast<InState<ModuleT, kEvaluatedError>>(module); + } + + // Dispatches [module] to the handler in [handlers...] whose + // Handle/DirectHandle<InState<ModuleT, kStates...>> parameter matches + // module->status(). Any status not handled by [handlers...] (including + // out-of-range values from heap corruption) crashes reliably, naming the + // actual and expected statuses in all build modes. + template <template <typename> class Holder, typename ModuleT, + typename... Handlers> + requires(std::is_base_of_v<Module, ModuleT> && + (std::is_same_v<Holder<ModuleT>, Handle<ModuleT>> || + std::is_same_v<Holder<ModuleT>, DirectHandle<ModuleT>>)) + static inline decltype(auto) MatchState(Holder<ModuleT> module, + Handlers&&... handlers); // The [must_resolve] argument indicates whether or not an exception should be // thrown in case the module does not provide an export named [name] @@ -135,23 +265,85 @@ V8_OBJECT class Module : public HeapObject { MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( - Isolate* isolate, DirectHandle<Module> module, - v8::Local<v8::Context> context, const UserResolveCallbacks& callbacks); + Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context, + const UserResolveCallbacks& callbacks); static V8_WARN_UNUSED_RESULT bool FinishInstantiate( Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, - Zone* zone, unsigned depth, unsigned* max_depth); + ZoneForwardList<Handle<InState<SourceTextModule, kLinking>>>* stack, + unsigned* dfs_index, Zone* zone, unsigned depth, unsigned* max_depth); // Set module's status back to kUnlinked and reset other internal state. // This is used when instantiation fails. - static void Reset(Isolate* isolate, DirectHandle<Module> module); - static void ResetGraph(Isolate* isolate, DirectHandle<Module> module); + static void Reset( + Isolate* isolate, + DirectHandle<InState<Module, kPreLinking, kLinking>> module); + static void ResetGraph(Isolate* isolate, Handle<Module> module); - // To set status to kErrored, RecordError should be used. - void SetStatus(Status status); - void RecordError(Isolate* isolate, Tagged<Object> error); + private: + inline void set_exports(Tagged<ObjectHashTable> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + // Once a module namespace (normal or deferred) has been created in + // GetModuleNamespace, all star exports have been fetched and {exports} is + // finalized (must not be mutated or rehashed as ICs index into it). + inline bool ExportsFinalized() const; + inline void set_status(int value); + inline void set_exception(Tagged<Object> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + + template <typename... Ts> + struct Overloaded : Ts... { + using Ts::operator()...; + }; + + // Compile-time helpers for MatchState, all enumerating AllStatuses so that + // adding a status cannot silently leave a check incomplete. + template <template <typename> class Holder, typename ModuleT, Status kState, + typename... Handlers> + static consteval size_t MatchingHandlerCount() { + return ( + static_cast<size_t>( + std::is_invocable_v<Handlers&, Holder<InState<ModuleT, kState>>>) + + ...); + } + + template <template <typename> class Holder, typename ModuleT, + typename Handler, Status... kAll> + static consteval bool HandlesAnyState(StatusList<kAll...>) { + return !std::is_invocable_v<Handler&, Holder<ModuleT>> && + (std::is_invocable_v<Handler&, Holder<InState<ModuleT, kAll>>> || + ...); + } + + template <template <typename> class Holder, typename ModuleT, + typename... Handlers, Status... kAll> + static consteval bool NoDuplicateHandlers(StatusList<kAll...>) { + return ((MatchingHandlerCount<Holder, ModuleT, kAll, Handlers...>() <= 1) && + ...); + } + + // Bit mask over Status of the states some handler accepts. + template <template <typename> class Holder, typename ModuleT, + typename... Handlers, Status... kAll> + static consteval uint32_t HandledStatusMask(StatusList<kAll...>) { + return ((MatchingHandlerCount<Holder, ModuleT, kAll, Handlers...>() > 0 + ? uint32_t{1} << kAll + : uint32_t{0}) | + ...); + } + + // Crashes with a message naming [status] and the statuses in [handled_mask], + // in release builds too, so that a module reaching a MatchState in an + // unexpected state produces a diagnosable crash signature. + [[noreturn]] static void FatalUnexpectedStatus(Status status, + uint32_t handled_mask); + + void SetStatusInternal(Status new_status); + void RecordErrorInternal(Isolate* isolate, Tagged<Object> error); + + friend class TorqueGeneratedModuleAsserts; + friend struct ObjectTraits<Module>; + friend class AccessorAssembler; - public: TaggedMember<ObjectHashTable> exports_; TaggedMember<Smi> hash_; TaggedMember<Smi> status_; @@ -161,6 +353,97 @@ V8_OBJECT class Module : public HeapObject { TaggedMember<UnionOf<JSPromise, Undefined>> top_level_capability_; } V8_OBJECT_END; +V8_OBJECT +template <typename ModuleT, Module::Status... kStates> +class Module::InState : public ModuleT { + public: + static_assert(sizeof...(kStates) > 0); + static_assert(std::is_base_of_v<Module, ModuleT>); + + template <Status... kAllowed> + static consteval bool IsModuleAllowed() { + return (IsStateIn<kAllowed...>(kStates) && ...); + } + + template <Status... kAllowed> + static consteval bool IsAllowed() { + return std::is_same_v<ModuleT, SourceTextModule> && + IsModuleAllowed<kAllowed...>(); + } + + inline void set_exports(Tagged<ObjectHashTable> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER) + requires(IsModuleAllowed<kPreLinking, kLinking>()); + inline void set_star_exports(Tagged<ObjectHashTable> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER) + requires(IsAllowed<kLinking, kLinked, kEvaluating, kEvaluatingAsync, + kEvaluated, kEvaluatedError>()); + inline bool ExportsFinalized() const + requires(IsModuleAllowed<kLinking, kLinked, kEvaluating, kEvaluatingAsync, + kEvaluated, kEvaluatedError>()); + + inline Tagged<SharedFunctionInfo> sfi() const + requires(IsAllowed<kUnlinked, kPreLinking, kEvaluatedError>()); + inline Tagged<JSFunction> function() const + requires(IsAllowed<kLinking>()); + inline Tagged<JSGeneratorObject> generator() const + requires(IsAllowed<kLinked, kEvaluating, kEvaluatingAsync, kEvaluated>()); + inline Tagged<JSAsyncFunctionObject> async_function_object() const + requires(IsAllowed<kEvaluating, kEvaluatingAsync>()); + + inline Tagged<SourceTextModule> GetCycleRoot() const + requires(IsAllowed<kEvaluatingAsync, kEvaluated>()); + inline Handle<SourceTextModule> GetCycleRoot(Isolate* isolate) const + requires(IsAllowed<kEvaluatingAsync, kEvaluated>()); + inline MaybeHandle<SourceTextModule> TryGetCycleRoot(Isolate* isolate) const + requires(IsAllowed<kEvaluatedError>()); + + inline int dfs_index() const + requires(IsAllowed<kLinking, kEvaluating>()); + inline int dfs_ancestor_index() const + requires(IsAllowed<kLinking, kEvaluating>()); + inline void UpdateDfsAncestorIndex( + DirectHandle<InState<SourceTextModule, kLinking>> child) + requires(IsAllowed<kLinking>()); + inline void UpdateDfsAncestorIndex( + DirectHandle<InState<SourceTextModule, kEvaluating>> child) + requires(IsAllowed<kEvaluating>()); + + inline bool HasPendingAsyncDependencies() + requires(IsAllowed<kEvaluating, kEvaluatingAsync>()); + inline void IncrementPendingAsyncDependencies() + requires(IsAllowed<kEvaluating>()); + inline void DecrementPendingAsyncDependencies() + requires(IsAllowed<kEvaluatingAsync>()); + + private: + InState() = delete; +} V8_OBJECT_END; + +template <typename ModuleT, Module::Status... kStates> +struct CastTraits<Module::InState<ModuleT, kStates...>> { + template <typename From> + requires(std::is_base_of_v<Module, From>) + static inline bool AllowFrom(Tagged<From> value) { + if (!Module::IsStateIn<kStates...>(value->status())) return false; + if constexpr (std::is_base_of_v<ModuleT, From>) { + return true; + } else { + return Is<ModuleT>(value); + } + } +}; + +namespace detail { +template <typename ModuleT, Module::Status kS1, Module::Status kS2, + Module::Status... kRest> +struct normalize_type<Module::InState<ModuleT, kS1, kS2, kRest...>> { + using type = + Union<Module::InState<ModuleT, kS1>, Module::InState<ModuleT, kS2>, + Module::InState<ModuleT, kRest>...>; +}; +} // namespace detail + template <> struct ObjectTraits<Module> { using BodyDescriptor = FixedBodyDescriptor<offsetof(Module, exports_), diff --git a/deps/v8/src/objects/module.tq b/deps/v8/src/objects/module.tq index 90175d074564..f1e06a4c3045 100644 --- a/deps/v8/src/objects/module.tq +++ b/deps/v8/src/objects/module.tq @@ -12,7 +12,7 @@ extern class Module extends HeapObject { status: Smi; module_namespace: Cell|Undefined; deferred_module_namespace: Cell|Undefined; - // The exception in the case {status} is kErrored. + // The exception in the case {status} is kEvaluatedError. exception: Object; // The top level promise capability of this module. Will only be defined // for cycle roots. diff --git a/deps/v8/src/objects/name-inl.h b/deps/v8/src/objects/name-inl.h index 823d7664b49b..e5ad47934a35 100644 --- a/deps/v8/src/objects/name-inl.h +++ b/deps/v8/src/objects/name-inl.h @@ -25,49 +25,44 @@ namespace v8 { namespace internal { - -Tagged<PrimitiveHeapObject> Symbol::description() const { +Tagged<UnionOf<String, Undefined>> Symbol::description() const { return description_.load(); } -void Symbol::set_description(Tagged<PrimitiveHeapObject> value, +void Symbol::set_description(Tagged<UnionOf<String, Undefined>> value, WriteBarrierMode mode) { SLOW_DCHECK(IsString(value) || IsUndefined(value)); description_.store(this, value, mode); } BIT_FIELD_ACCESSORS(Symbol, flags, is_well_known_symbol, - Symbol::IsWellKnownSymbolBit) + Symbol::Flags::IsWellKnownSymbolBit) BIT_FIELD_ACCESSORS(Symbol, flags, is_in_public_symbol_table, - Symbol::IsInPublicSymbolTableBit) + Symbol::Flags::IsInPublicSymbolTableBit) BIT_FIELD_ACCESSORS(Symbol, flags, is_interesting_symbol, - Symbol::IsInterestingSymbolBit) + Symbol::Flags::IsInterestingSymbolBit) bool Symbol::is_any_private() const { - return Symbol::PrivateSymbolKindBits::decode(flags()) != - PrivateSymbolKind::kPublic; + return private_symbol_kind() != PrivateSymbolKind::kPublic; } void Symbol::set_private_symbol_kind(PrivateSymbolKind kind) { - set_flags(Symbol::PrivateSymbolKindBits::update(flags(), kind)); + set_flags(flags().with_private_symbol_kind(kind)); } bool Symbol::is_private_internal() const { - return Symbol::PrivateSymbolKindBits::decode(flags()) == - PrivateSymbolKind::kInternal; + return private_symbol_kind() == PrivateSymbolKind::kInternal; } bool Symbol::is_private_brand() const { - return Symbol::PrivateSymbolKindBits::decode(flags()) == - PrivateSymbolKind::kBrand; + return private_symbol_kind() == PrivateSymbolKind::kBrand; } PrivateSymbolKind Symbol::private_symbol_kind() const { - return Symbol::PrivateSymbolKindBits::decode(flags()); + return flags().private_symbol_kind(); } bool Symbol::is_any_private_name() const { - return Symbol::PrivateSymbolKindBits::decode(flags()) >= - PrivateSymbolKind::kFieldName; + return private_symbol_kind() >= PrivateSymbolKind::kFieldName; } bool IsPublicSymbol(Tagged<Object> obj) { diff --git a/deps/v8/src/objects/name.h b/deps/v8/src/objects/name.h index ad2c6d438a59..3c76c973ca0d 100644 --- a/deps/v8/src/objects/name.h +++ b/deps/v8/src/objects/name.h @@ -7,9 +7,11 @@ #include <atomic> #include <iosfwd> +#include <span> #include "src/base/bit-field.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/objects.h" #include "src/objects/primitive-heap-object.h" #include "src/utils/utils.h" @@ -20,12 +22,9 @@ namespace v8 { namespace internal { -namespace compiler { -class WasmGraphBuilder; -namespace turboshaft { +namespace compiler::turboshaft { class AccessBuilderTS; -} -} +} // namespace compiler::turboshaft namespace maglev { class MaglevGraphBuilder; @@ -159,7 +158,7 @@ V8_OBJECT class Name : public PrimitiveHeapObject { DECL_VERIFIER(Name) DECL_PRINTER(Name) void NameShortPrint(); - int NameShortPrint(base::Vector<char> str); + int NameShortPrint(std::span<char> str); // Mask constant for checking if a name has a computed hash code and the type // of information stored in the hash field. The least significant bit @@ -172,28 +171,6 @@ V8_OBJECT class Name : public PrimitiveHeapObject { kEmpty = 0b11 }; - using HashFieldTypeBits = base::BitField<HashFieldType, 0, 2>; - using HashBits = - HashFieldTypeBits::Next<uint32_t, kBitsPerInt - HashFieldTypeBits::kSize>; - - static constexpr int kHashNotComputedMask = 1; - // Value of empty hash field indicating that the hash is not computed. - static constexpr int kEmptyHashField = - HashFieldTypeBits::encode(HashFieldType::kEmpty); - - // Empty hash and forwarding indices can not be used as hash. - static_assert((kEmptyHashField & kHashNotComputedMask) != 0); - static_assert((HashFieldTypeBits::encode(HashFieldType::kForwardingIndex) & - kHashNotComputedMask) != 0); - - using IsInternalizedForwardingIndexBit = HashFieldTypeBits::Next<bool, 1>; - using IsExternalForwardingIndexBit = - IsInternalizedForwardingIndexBit::Next<bool, 1>; - using ForwardingIndexValueBits = IsExternalForwardingIndexBit::Next< - unsigned int, kBitsPerInt - HashFieldTypeBits::kSize - - IsInternalizedForwardingIndexBit::kSize - - IsExternalForwardingIndexBit::kSize>; - // Array index strings this short can keep their index in the hash field. static const int kMaxCachedArrayIndexLength = 7; @@ -227,17 +204,64 @@ V8_OBJECT class Name : public PrimitiveHeapObject { "kArrayIndexHashShift must be at least half of " "kArrayIndexValueBits"); #endif // V8_ENABLE_SEEDED_ARRAY_INDEX_HASH + + struct Hash : BitFieldGroup<Hash, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using HashFieldTypeBits = First<HashFieldType, 2>; + + // Hash code view (kHash). + using HashBits = + HashFieldTypeBits::Next<uint32_t, + kBitsPerInt - HashFieldTypeBits::kSize>; + + // Array index view (kIntegerIndex). + using ArrayIndexValueBits = + HashFieldTypeBits::Next<unsigned int, kArrayIndexValueBits>; + using ArrayIndexLengthBits = + ArrayIndexValueBits::Next<unsigned int, kBitsPerInt - + kArrayIndexValueBits - + HashFieldTypeBits::kSize>; + + // String forwarding table view (kForwardingIndex). + using IsInternalizedForwardingIndexBit = HashFieldTypeBits::Next<bool, 1>; + using IsExternalForwardingIndexBit = + IsInternalizedForwardingIndexBit::Next<bool, 1>; + using ForwardingIndexValueBits = IsExternalForwardingIndexBit::Next< + unsigned int, kBitsPerInt - HashFieldTypeBits::kSize - + IsInternalizedForwardingIndexBit::kSize - + IsExternalForwardingIndexBit::kSize>; + + BIT_FIELD_GROUP_ACCESSORS(hash_field_type, HashFieldTypeBits) + BIT_FIELD_GROUP_ACCESSORS(array_index_value, ArrayIndexValueBits) + BIT_FIELD_GROUP_ACCESSORS(array_index_length, ArrayIndexLengthBits) + }; + // TODO(jgruber): Remove these aliases after migrating callers to Hash. + using HashFieldTypeBits = Hash::HashFieldTypeBits; + using HashBits = Hash::HashBits; + using IsInternalizedForwardingIndexBit = + Hash::IsInternalizedForwardingIndexBit; + using IsExternalForwardingIndexBit = Hash::IsExternalForwardingIndexBit; + using ForwardingIndexValueBits = Hash::ForwardingIndexValueBits; + using ArrayIndexValueBits = Hash::ArrayIndexValueBits; + using ArrayIndexLengthBits = Hash::ArrayIndexLengthBits; + + static constexpr int kHashNotComputedMask = 1; + // Value of empty hash field indicating that the hash is not computed. + static constexpr int kEmptyHashField = + HashFieldTypeBits::encode(HashFieldType::kEmpty); + + // Empty hash and forwarding indices can not be used as hash. + static_assert((kEmptyHashField & kHashNotComputedMask) != 0); + static_assert((HashFieldTypeBits::encode(HashFieldType::kForwardingIndex) & + kHashNotComputedMask) != 0); + static const int kArrayIndexLengthBits = kBitsPerInt - kArrayIndexValueBits - HashFieldTypeBits::kSize; static_assert(kArrayIndexLengthBits > 0); static_assert(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits)); - using ArrayIndexValueBits = - HashFieldTypeBits::Next<unsigned int, kArrayIndexValueBits>; - using ArrayIndexLengthBits = - ArrayIndexValueBits::Next<unsigned int, kArrayIndexLengthBits>; - // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we // could use a mask to test if the length of string is less than or equal to // kMaxCachedArrayIndexLength. @@ -292,6 +316,7 @@ V8_OBJECT class Name : public PrimitiveHeapObject { private: friend class V8HeapExplorer; + friend class Serializer; friend class CodeStubAssembler; friend class StringBuiltinsAssembler; friend class SandboxTesting; @@ -301,12 +326,11 @@ V8_OBJECT class Name : public PrimitiveHeapObject { friend class maglev::MaglevAssembler; friend struct maglev::VirtualNameShape; friend class compiler::AccessBuilder; - friend class compiler::WasmGraphBuilder; friend class TorqueGeneratedNameAsserts; inline uint32_t GetRawHashFromForwardingTable(uint32_t raw_hash) const; - std::atomic_uint32_t raw_hash_field_; + std::atomic<Hash> raw_hash_field_; } V8_OBJECT_END; inline bool IsUniqueName(Tagged<Name> obj); @@ -314,13 +338,23 @@ inline bool IsUniqueName(Tagged<Name> obj); // ES6 symbols. V8_OBJECT class Symbol : public Name { public: - using PrivateSymbolKindBits = base::BitField<PrivateSymbolKind, 0, 2>; - using IsWellKnownSymbolBit = PrivateSymbolKindBits::Next<bool, 1>; - using IsInPublicSymbolTableBit = IsWellKnownSymbolBit::Next<bool, 1>; - using IsInterestingSymbolBit = IsInPublicSymbolTableBit::Next<bool, 1>; + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using PrivateSymbolKindBits = First<PrivateSymbolKind, 2>; + using IsWellKnownSymbolBit = PrivateSymbolKindBits::Next<bool, 1>; + using IsInPublicSymbolTableBit = IsWellKnownSymbolBit::Next<bool, 1>; + using IsInterestingSymbolBit = IsInPublicSymbolTableBit::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(private_symbol_kind, PrivateSymbolKindBits) + BIT_FIELD_GROUP_ACCESSORS(is_well_known_symbol, IsWellKnownSymbolBit) + BIT_FIELD_GROUP_ACCESSORS(is_in_public_symbol_table, + IsInPublicSymbolTableBit) + BIT_FIELD_GROUP_ACCESSORS(is_interesting_symbol, IsInterestingSymbolBit) + }; - inline Tagged<PrimitiveHeapObject> description() const; - inline void set_description(Tagged<PrimitiveHeapObject> value, + inline Tagged<UnionOf<String, Undefined>> description() const; + inline void set_description(Tagged<UnionOf<String, Undefined>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline void set_private_symbol_kind(PrivateSymbolKind kind); @@ -377,15 +411,13 @@ V8_OBJECT class Symbol : public Name { // TODO(cbruni): remove once the new maptracer is in place. friend class Name; // For PrivateSymbolToName. - uint32_t flags() const { return flags_; } - void set_flags(uint32_t value) { flags_ = value; } + Flags flags() const { return flags_; } + void set_flags(Flags value) { flags_ = value; } const char* PrivateSymbolToName() const; - uint32_t flags_; - // String|Undefined - // TODO(leszeks): Introduce a union type for this. - TaggedMember<PrimitiveHeapObject> description_; + Flags flags_; + TaggedMember<UnionOf<String, Undefined>> description_; } V8_OBJECT_END; template <> diff --git a/deps/v8/src/objects/name.tq b/deps/v8/src/objects/name.tq index 4ef347029204..8cb572573ad0 100644 --- a/deps/v8/src/objects/name.tq +++ b/deps/v8/src/objects/name.tq @@ -8,10 +8,21 @@ extern class Name extends PrimitiveHeapObject { raw_hash_field: NameHash; } +@cppScope('Name::Hash') bitfield struct NameHash extends uint32 { - hash_field_type: HashFieldType: 2 bit; - array_index_value: uint32: 24 bit; + hash_field_type: NameHashFieldType: 2 bit; + + // hash_field_type: kHash + hash: uint32: 30 bit at 2; + + // hash_field_type: kIntegerIndex + array_index_value: uint32: 24 bit at 2; array_index_length: uint32: 6 bit; + + // hash_field_type: kForwardingIndex + is_internalized_forwarding_index: bool: 1 bit at 2; + is_external_forwarding_index: bool: 1 bit; + forwarding_index_value: uint32: 28 bit; } // This is the same as Name, but with the information that there are no other @@ -25,7 +36,7 @@ extern enum PrivateSymbolKind extends uint8 { kBrand } -@cppScope('Symbol') +@cppScope('Symbol::Flags') bitfield struct SymbolFlags extends uint32 { private_symbol_kind: PrivateSymbolKind: 2 bit; is_well_known_symbol: bool: 1 bit; @@ -52,11 +63,8 @@ const kArrayIndexValueBits: constexpr int31 generates 'Name::kArrayIndexValueBits'; const kDoesNotContainCachedArrayIndexMask: constexpr uint32 generates 'Name::kDoesNotContainCachedArrayIndexMask'; -const kNameEmptyHashField: NameHash = NameHash{ - hash_field_type: HashFieldType::kEmpty, - array_index_value: 0, - array_index_length: 0 -}; +const kNameEmptyHashField: NameHash = +NameHash{hash_field_type: NameHashFieldType::kEmpty}; macro ContainsCachedArrayIndex(hash: uint32): bool { return (hash & kDoesNotContainCachedArrayIndexMask) == 0; @@ -81,7 +89,7 @@ macro TenToThe(exponent: uint32): uint32 { } macro IsIntegerIndex(hash: NameHash): bool { - return hash.hash_field_type == HashFieldType::kIntegerIndex; + return hash.hash_field_type == NameHashFieldType::kIntegerIndex; } // This is in sync with the private StringHasher::MakeArrayIndexHash without diff --git a/deps/v8/src/objects/number-string-cache-inl.h b/deps/v8/src/objects/number-string-cache-inl.h index adcce70cfa5b..228a261d6d5d 100644 --- a/deps/v8/src/objects/number-string-cache-inl.h +++ b/deps/v8/src/objects/number-string-cache-inl.h @@ -8,7 +8,8 @@ #include "src/objects/number-string-cache.h" // Include the non-inl header before the rest of the headers. -#include "src/base/bits.h" +#include <bit> + #include "src/common/globals.h" #include "src/handles/handles-inl.h" #include "src/heap/factory-inl.h" @@ -79,8 +80,7 @@ void SmiStringCache::Set(Isolate* isolate, InternalIndex entry, !isolate->MemorySaverModeEnabled()) { // Allocate full-size cache, recompute the entry and proceed with adding // the entry. - uint32_t full_size = - base::bits::RoundUpToPowerOfTwo32(v8_flags.smi_string_cache_size); + uint32_t full_size = std::bit_ceil(v8_flags.smi_string_cache_size.value()); CHECK_LT(kInitialSize, full_size); CHECK_LE(full_size, kMaxCapacity); // TODO(ishell): consider copying entries from previous table. @@ -173,7 +173,7 @@ void DoubleStringCache::Set(Isolate* isolate, InternalIndex entry_index, // Allocate full-size cache, recompute the entry and proceed with adding // the entry. uint32_t full_size = - base::bits::RoundUpToPowerOfTwo32(v8_flags.double_string_cache_size); + std::bit_ceil(v8_flags.double_string_cache_size.value()); CHECK_LT(kInitialSize, full_size); CHECK_LE(full_size, kMaxCapacity); cache = DoubleStringCache::New(isolate, full_size); diff --git a/deps/v8/src/objects/object-list-macros.h b/deps/v8/src/objects/object-list-macros.h index fda3b330e967..d60bc2fff26b 100644 --- a/deps/v8/src/objects/object-list-macros.h +++ b/deps/v8/src/objects/object-list-macros.h @@ -144,6 +144,7 @@ namespace internal { V(GlobalDictionary) \ V(HashSeedWrapper) \ V(HeapNumber) \ + V(UninitializedHeapNumber) \ V(InterceptorInfo) \ V(InternalizedString) \ V(JSArgumentsObject) \ @@ -154,8 +155,6 @@ namespace internal { V(JSAsyncFromSyncIterator) \ V(JSAsyncFunctionObject) \ V(JSAsyncGeneratorObject) \ - V(JSAtomicsCondition) \ - V(JSAtomicsMutex) \ V(JSBoundFunction) \ V(JSCollection) \ V(JSCollectionIterator) \ @@ -208,7 +207,6 @@ namespace internal { V(JSSharedStruct) \ V(JSSpecialObject) \ V(JSStringIterator) \ - V(JSSynchronizationPrimitive) \ V(JSDetachedTypedArray) \ V(JSTypedArray) \ V(JSValidIteratorWrapper) \ @@ -494,6 +492,7 @@ namespace internal { V(JSSetIteratorPrototype) \ V(JSStringIteratorPrototype) \ V(TypedArrayConstructor) \ + V(Uint8JSTypedArray) \ V(Uint8TypedArrayConstructor) \ V(Int8TypedArrayConstructor) \ V(Uint16TypedArrayConstructor) \ @@ -550,11 +549,13 @@ namespace internal { V(Numeric) // These forward-declarations expose heap object types to most of our codebase. -#define DEF_FWD_DECLARATION(Type) class Type; +#define DEF_FWD_DECLARATION(Type, ...) class Type; HEAP_OBJECT_ORDINARY_TYPE_LIST(DEF_FWD_DECLARATION) HEAP_OBJECT_TRUSTED_TYPE_LIST(DEF_FWD_DECLARATION) HEAP_OBJECT_SPECIALIZED_TYPE_LIST(DEF_FWD_DECLARATION) VIRTUAL_OBJECT_TYPE_LIST(DEF_FWD_DECLARATION) +ODDBALL_LIST(DEF_FWD_DECLARATION) +HOLE_LIST(DEF_FWD_DECLARATION) #undef DEF_FWD_DECLARATION #ifndef V8_ENABLE_TDZ_HOLE diff --git a/deps/v8/src/objects/object-macros-undef.h b/deps/v8/src/objects/object-macros-undef.h index ebfbe17948d8..63ed83b1eeb9 100644 --- a/deps/v8/src/objects/object-macros-undef.h +++ b/deps/v8/src/objects/object-macros-undef.h @@ -22,6 +22,16 @@ #undef V8_IT_NO_AUTO_CHECKER #undef V8_IT_NO_AUTO_DISPATCH #undef V8_IT_MARK +#undef V8_TQ_FIELD_MARK +#undef V8_TQ_TAIL_LENGTH +#undef V8_TQ_NO_TAIL +#undef V8_TQ_CONST +#undef V8_TQ_RELAXED +#undef V8_TQ_ACQ_REL +#undef V8_TQ_CUSTOM_WEAK +#undef V8_TQ_TYPE +#undef V8_TQ_NAME +#undef V8_TQ_EXTENT_NAME #undef DECL_PRIMITIVE_GETTER #undef DECL_PRIMITIVE_SETTER #undef DECL_PRIMITIVE_ACCESSORS @@ -104,6 +114,7 @@ #undef PROTECTED_POINTER_ACCESSORS #undef DECL_RELEASE_ACQUIRE_PROTECTED_POINTER_ACCESSORS #undef RELEASE_ACQUIRE_PROTECTED_POINTER_ACCESSORS +#undef BIT_FIELD_GROUP_ACCESSORS #undef BIT_FIELD_ACCESSORS2 #undef BIT_FIELD_ACCESSORS #undef RELAXED_INT16_ACCESSORS @@ -121,11 +132,10 @@ #undef SEQ_CST_COMPARE_AND_SWAP_FIELD #undef WRITE_BARRIER #undef EXTERNAL_POINTER_WRITE_BARRIER -#undef INDIRECT_POINTER_WRITE_BARRIER +#undef TRUSTED_POINTER_WRITE_BARRIER #undef JS_DISPATCH_HANDLE_WRITE_BARRIER #undef CONDITIONAL_WRITE_BARRIER #undef CONDITIONAL_EXTERNAL_POINTER_WRITE_BARRIER -#undef CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER #undef CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER #undef CONDITIONAL_CODE_POINTER_WRITE_BARRIER #undef CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER diff --git a/deps/v8/src/objects/object-macros.h b/deps/v8/src/objects/object-macros.h index 9ef97ab09344..c6fce4574bb9 100644 --- a/deps/v8/src/objects/object-macros.h +++ b/deps/v8/src/objects/object-macros.h @@ -145,6 +145,34 @@ #define V8_IT_NO_AUTO_DISPATCH \ V8_IT_MARK(NoAutoDispatch, "V8_IT_NO_AUTO_DISPATCH") +// Metagen exports the layouts defined in C++ to Torque. These annotations +// describe properties not encoded in C++ types, such as Torque accessor +// semantics, custom weak marking, semantic types, and field names. +// Class annotations omit the flexible tail (V8_TQ_NO_TAIL) or specify its +// Torque length expression (V8_TQ_TAIL_LENGTH). +// Field annotations apply to the flexible array member. +// +// Metagen passes each optional annotation argument to Torque without parsing +// it. +// +// Ordinary compilation removes these annotations. +#ifdef V8_METAGEN_GENERATION_PASS +#define V8_TQ_FIELD_MARK(PAYLOAD) [[clang::annotate(PAYLOAD)]] +#else +#define V8_TQ_FIELD_MARK(PAYLOAD) +#endif +#define V8_TQ_TAIL_LENGTH(...) \ + V8_IT_MARK(TqTailLength, "V8_TQ_TAIL_LENGTH(" #__VA_ARGS__ ")") +#define V8_TQ_NO_TAIL V8_IT_MARK(TqNoTail, "V8_TQ_NO_TAIL") +#define V8_TQ_CONST V8_TQ_FIELD_MARK("V8_TQ_CONST") +#define V8_TQ_RELAXED V8_TQ_FIELD_MARK("V8_TQ_RELAXED") +#define V8_TQ_ACQ_REL V8_TQ_FIELD_MARK("V8_TQ_ACQ_REL") +#define V8_TQ_CUSTOM_WEAK V8_TQ_FIELD_MARK("V8_TQ_CUSTOM_WEAK") +#define V8_TQ_TYPE(...) V8_TQ_FIELD_MARK("V8_TQ_TYPE(" #__VA_ARGS__ ")") +#define V8_TQ_NAME(...) V8_TQ_FIELD_MARK("V8_TQ_NAME(" #__VA_ARGS__ ")") +#define V8_TQ_EXTENT_NAME(...) \ + V8_TQ_FIELD_MARK("V8_TQ_EXTENT_NAME(" #__VA_ARGS__ ")") + #define DECL_PRIMITIVE_GETTER(name, type) inline type name() const; #define DECL_PRIMITIVE_SETTER(name, type) inline void set_##name(type value); @@ -786,7 +814,7 @@ #define DECL_CODE_POINTER_ACCESSORS(name) \ DECL_TRUSTED_POINTER_ACCESSORS(name, Code) #define CODE_POINTER_ACCESSORS(holder, name, offset) \ - TRUSTED_POINTER_ACCESSORS(holder, name, Code, offset, kCodeIndirectPointerTag) + TRUSTED_POINTER_ACCESSORS(holder, name, Code, offset, kCodeTrustedPointerTag) // Accessors for "protected" pointers, i.e. references from one trusted object // to another trusted object. For these pointers it can be assumed that neither @@ -839,6 +867,14 @@ return ClearProtectedPointerField(offset, tag); \ } +// Defines accessors for one bit field of a BitFieldGroup. +#define BIT_FIELD_GROUP_ACCESSORS(name, Bit) \ + constexpr typename Bit::FieldType name() const { return get<Bit>(); } \ + V8_NODISCARD constexpr GroupType with_##name(typename Bit::FieldType value) \ + const { \ + return with<Bit>(value); \ + } + #define BIT_FIELD_ACCESSORS2(holder, get_field, set_field, name, BitField) \ typename BitField::FieldType holder::name() const { \ return BitField::decode(get_field()); \ @@ -920,14 +956,14 @@ #endif #ifdef V8_DISABLE_WRITE_BARRIERS -#define INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value) +#define TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value) #else -#define INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value) \ - do { \ - DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object)); \ - WriteBarrier::ForIndirectPointer( \ - object, Tagged(object)->RawIndirectPointerField(offset, tag), value, \ - UPDATE_WRITE_BARRIER); \ +#define TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value) \ + do { \ + DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object)); \ + WriteBarrier::ForTrustedPointer( \ + object, Tagged(object)->RawTrustedPointerField(offset, tag), value, \ + UPDATE_WRITE_BARRIER); \ } while (false) #endif @@ -970,24 +1006,19 @@ mode); \ } while (false) #endif -#ifdef V8_DISABLE_WRITE_BARRIERS -#define CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value, \ - mode) -#else -#define CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value, \ - mode) \ - do { \ - DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object)); \ - WriteBarrier::ForIndirectPointer( \ - object, Tagged(object)->RawIndirectPointerField(offset, tag), value, \ - mode); \ - } while (false) -#endif -#ifdef V8_ENABLE_SANDBOX +#ifdef V8_DISABLE_WRITE_BARRIERS +#define CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value, \ + mode) +#elif defined(V8_ENABLE_SANDBOX) #define CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value, \ mode) \ - CONDITIONAL_INDIRECT_POINTER_WRITE_BARRIER(object, offset, tag, value, mode) + do { \ + DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(object)); \ + WriteBarrier::ForTrustedPointer( \ + object, Tagged(object)->RawTrustedPointerField(offset, tag), value, \ + mode); \ + } while (false) #else #define CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER(object, offset, tag, value, \ mode) \ @@ -995,7 +1026,7 @@ #endif // V8_ENABLE_SANDBOX #define CONDITIONAL_CODE_POINTER_WRITE_BARRIER(object, offset, value, mode) \ CONDITIONAL_TRUSTED_POINTER_WRITE_BARRIER( \ - object, offset, kCodeIndirectPointerTag, value, mode) + object, offset, kCodeTrustedPointerTag, value, mode) #define CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER(object, offset, value, \ mode) \ diff --git a/deps/v8/src/objects/objects-body-descriptors-inl.h b/deps/v8/src/objects/objects-body-descriptors-inl.h index eeaa90ad3214..18807c13d2ec 100644 --- a/deps/v8/src/objects/objects-body-descriptors-inl.h +++ b/deps/v8/src/objects/objects-body-descriptors-inl.h @@ -33,7 +33,6 @@ #include "src/objects/heap-number.h" #include "src/objects/instance-type.h" #include "src/objects/js-array-buffer.h" -#include "src/objects/js-atomics-synchronization-inl.h" #include "src/objects/js-collection.h" #include "src/objects/js-objects.h" #include "src/objects/js-proxy.h" @@ -280,12 +279,12 @@ void BodyDescriptorBase::IterateCustomWeakPointer(Tagged<HeapObject> obj, template <typename ObjectVisitor> void BodyDescriptorBase::IterateTrustedPointer( Tagged<HeapObject> obj, int offset, ObjectVisitor* v, - IndirectPointerMode mode, IndirectPointerTagRange tag_range) { + TrustedPointerMode mode, TrustedPointerTagRange tag_range) { #ifdef V8_ENABLE_SANDBOX - v->VisitIndirectPointer(obj, obj->RawIndirectPointerField(offset, tag_range), - mode); + v->VisitTrustedPointer(obj, obj->RawTrustedPointerField(offset, tag_range), + mode); #else - if (mode == IndirectPointerMode::kStrong) { + if (mode == TrustedPointerMode::kStrong) { IteratePointer(obj, offset, v); } else { IterateCustomWeakPointer(obj, offset, v); @@ -293,14 +292,14 @@ void BodyDescriptorBase::IterateTrustedPointer( #endif } -template <typename ObjectVisitor, typename T, IndirectPointerTagRange kTagRange> +template <typename ObjectVisitor, typename T, TrustedPointerTagRange kTagRange> void BodyDescriptorBase::IterateTrustedPointer( Tagged<HeapObject> obj, TrustedPointerMember<T, kTagRange>* member, - ObjectVisitor* v, IndirectPointerMode mode) { + ObjectVisitor* v, TrustedPointerMode mode) { #ifdef V8_ENABLE_SANDBOX - v->VisitIndirectPointer(obj, IndirectPointerSlot(member), mode); + v->VisitTrustedPointer(obj, TrustedPointerSlot(member), mode); #else - if (mode == IndirectPointerMode::kStrong) { + if (mode == TrustedPointerMode::kStrong) { v->VisitPointer(obj, ObjectSlot(member)); } else { v->VisitCustomWeakPointer(obj, ObjectSlot(member)); @@ -311,27 +310,27 @@ void BodyDescriptorBase::IterateTrustedPointer( template <typename ObjectVisitor> void BodyDescriptorBase::IterateCodePointer(Tagged<HeapObject> obj, int offset, ObjectVisitor* v, - IndirectPointerMode mode) { - IterateTrustedPointer(obj, offset, v, mode, kCodeIndirectPointerTag); + TrustedPointerMode mode) { + IterateTrustedPointer(obj, offset, v, mode, kCodeTrustedPointerTag); } template <typename ObjectVisitor> void BodyDescriptorBase::IterateCodePointer( Tagged<HeapObject> obj, - TrustedPointerMember<Code, kCodeIndirectPointerTag>* member, - ObjectVisitor* v, IndirectPointerMode mode) { + TrustedPointerMember<Code, kCodeTrustedPointerTag>* member, + ObjectVisitor* v, TrustedPointerMode mode) { IterateTrustedPointer(obj, member, v, mode); } template <typename ObjectVisitor> -void BodyDescriptorBase::IterateSelfIndirectPointer( - Tagged<HeapObject> obj, IndirectPointerTagRange tag_range, +void BodyDescriptorBase::IterateSelfTrustedPointer( + Tagged<HeapObject> obj, TrustedPointerTagRange tag_range, ObjectVisitor* v) { #ifdef V8_ENABLE_SANDBOX v->VisitTrustedPointerTableEntry( obj, - obj->RawIndirectPointerField( - offsetof(ExposedTrustedObject, self_indirect_pointer_), tag_range)); + obj->RawTrustedPointerField( + offsetof(ExposedTrustedObject, self_trusted_pointer_), tag_range)); #endif } @@ -358,6 +357,14 @@ class HeapNumber::BodyDescriptor final : public DataOnlyBodyDescriptor { } }; +class UninitializedHeapNumber::BodyDescriptor final + : public DataOnlyBodyDescriptor { + public: + static constexpr int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { + return sizeof(UninitializedHeapNumber); + } +}; + class HashSeedWrapper::BodyDescriptor final : public DataOnlyBodyDescriptor { public: static constexpr int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { @@ -537,7 +544,7 @@ class JSRegExp::BodyDescriptor final : public BodyDescriptorBase { Tagged<JSRegExp> regexp = UncheckedCast<JSRegExp>(obj); IteratePointers(obj, offsetof(JSReceiver, properties_or_hash_), JSObject::kHeaderSize, v); - IterateTrustedPointer(obj, ®exp->data_, v, IndirectPointerMode::kStrong); + IterateTrustedPointer(obj, ®exp->data_, v, TrustedPointerMode::kStrong); IteratePointer(obj, offsetof(JSRegExp, flags_), v); IterateJSObjectBodyImpl(map, obj, JSRegExp::kHeaderSize, object_size, v); } @@ -555,10 +562,10 @@ class RegExpData::BodyDescriptor final : public BodyDescriptorBase { // If new pointers are added to RegExpData, make sure to also add them to // the subclasses descriptors (AtomRegExpData and IrRegExpData). // We don't directly call the base class IterateBody, as in the future - // the subclasses will have a different indirect pointer tag from the base + // the subclasses will have a different trusted pointer tag from the base // class (once inheritance hierarchies are supported for indirect pointer // tags). - IterateSelfIndirectPointer(obj, kRegExpDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kRegExpDataTrustedPointerTag, v); IteratePointer(obj, offsetof(RegExpData, original_source_), v); IteratePointer(obj, offsetof(RegExpData, escaped_source_), v); IteratePointer(obj, offsetof(RegExpData, wrapper_), v); @@ -574,7 +581,7 @@ class AtomRegExpData::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kRegExpDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kRegExpDataTrustedPointerTag, v); IteratePointer(obj, offsetof(AtomRegExpData, original_source_), v); IteratePointer(obj, offsetof(AtomRegExpData, escaped_source_), v); @@ -593,7 +600,7 @@ class IrRegExpData::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kRegExpDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kRegExpDataTrustedPointerTag, v); IteratePointer(obj, offsetof(IrRegExpData, original_source_), v); IteratePointer(obj, offsetof(IrRegExpData, escaped_source_), v); @@ -603,9 +610,9 @@ class IrRegExpData::BodyDescriptor final : public BodyDescriptorBase { IterateProtectedPointer(obj, offsetof(IrRegExpData, uc16_bytecode_), v); IterateProtectedPointer(obj, offsetof(IrRegExpData, capture_name_map_), v); IterateCodePointer(obj, &TrustedCast<IrRegExpData>(obj)->latin1_code_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); IterateCodePointer(obj, &TrustedCast<IrRegExpData>(obj)->uc16_code_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> obj) { @@ -619,7 +626,7 @@ class RegExpDataWrapper::BodyDescriptor final : public BodyDescriptorBase { static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { IterateTrustedPointer(obj, &Cast<RegExpDataWrapper>(obj)->data_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> obj) { @@ -1031,7 +1038,7 @@ class BytecodeArray::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kBytecodeArrayIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kBytecodeArrayTrustedPointerTag, v); IteratePointer(obj, offsetof(BytecodeArray, wrapper_), v); IterateProtectedPointer(obj, offsetof(BytecodeArray, source_position_table_), v); @@ -1051,7 +1058,7 @@ class BytecodeWrapper::BodyDescriptor final : public BodyDescriptorBase { int object_size, ObjectVisitor* v) { Tagged<BytecodeWrapper> wrapper = UncheckedCast<BytecodeWrapper>(obj); IterateTrustedPointer(obj, &wrapper->bytecode_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> obj) { @@ -1102,7 +1109,7 @@ class InterpreterData::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kInterpreterDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kInterpreterDataTrustedPointerTag, v); IterateProtectedPointer(obj, offsetof(InterpreterData, bytecode_array_), v); IterateProtectedPointer( obj, offsetof(InterpreterData, interpreter_trampoline_), v); @@ -1119,7 +1126,7 @@ class UncompiledDataWithoutPreparseData::BodyDescriptor final template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kUncompiledDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kUncompiledDataTrustedPointerTag, v); IteratePointer( obj, offsetof(UncompiledDataWithoutPreparseData, inferred_name_), v); } @@ -1135,7 +1142,7 @@ class UncompiledDataWithPreparseData::BodyDescriptor final template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kUncompiledDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kUncompiledDataTrustedPointerTag, v); IteratePointer(obj, offsetof(UncompiledDataWithPreparseData, inferred_name_), v); IteratePointer(obj, @@ -1153,7 +1160,7 @@ class UncompiledDataWithoutPreparseDataWithJob::BodyDescriptor final template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kUncompiledDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kUncompiledDataTrustedPointerTag, v); IteratePointer( obj, offsetof(UncompiledDataWithoutPreparseDataWithJob, inferred_name_), v); @@ -1170,7 +1177,7 @@ class UncompiledDataWithPreparseDataAndJob::BodyDescriptor final template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kUncompiledDataIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kUncompiledDataTrustedPointerTag, v); IteratePointer( obj, offsetof(UncompiledDataWithPreparseDataAndJob, inferred_name_), v); IteratePointer( @@ -1189,7 +1196,7 @@ class SharedFunctionInfo::BodyDescriptor final : public BodyDescriptorBase { int object_size, ObjectVisitor* v) { IterateTrustedPointer( obj, offsetof(SharedFunctionInfo, trusted_function_data_), v, - IndirectPointerMode::kCustom, kTrustedDataIndirectPointerRange); + TrustedPointerMode::kCustom, kTrustedDataTrustedPointerRange); IteratePointers(obj, offsetof(SharedFunctionInfo, untrusted_function_data_), kEndOfStrongFieldsOffset, v); } @@ -1204,7 +1211,7 @@ class DebugInfo::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kDebugInfoIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kDebugInfoTrustedPointerTag, v); IteratePointers(obj, offsetof(DebugInfo, shared_), offsetof(DebugInfo, coverage_info_) + kTaggedSize, v); IterateProtectedPointer(obj, offsetof(DebugInfo, debug_bytecode_array_), v); @@ -1248,26 +1255,6 @@ class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase { } }; -class JSSynchronizationPrimitive::BodyDescriptor final - : public BodyDescriptorBase { - public: - template <typename ObjectVisitor> - static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, - int object_size, ObjectVisitor* v) { - IteratePointers(obj, - offsetof(JSSynchronizationPrimitive, properties_or_hash_), - kEndOfTaggedFieldsOffset, v); - v->VisitExternalPointer( - obj, obj->RawExternalPointerField( - offsetof(JSSynchronizationPrimitive, waiter_queue_head_), - kWaiterQueueNodeTag)); - } - - static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { - return map->instance_size(); - } -}; - class Hole::BodyDescriptor : public DataOnlyBodyDescriptor { public: static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { @@ -1297,7 +1284,7 @@ class WasmFuncRef::BodyDescriptor final : public BodyDescriptorBase { int object_size, ObjectVisitor* v) { Tagged<WasmFuncRef> func_ref = UncheckedCast<WasmFuncRef>(obj); IterateTrustedPointer(obj, &func_ref->trusted_internal_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { @@ -1313,7 +1300,7 @@ class WasmResumeData::BodyDescriptor final : public BodyDescriptorBase { Tagged<WasmResumeData> data = UncheckedCast<WasmResumeData>(obj); IteratePointer(obj, offsetof(WasmResumeData, on_resume_), v); IterateTrustedPointer(obj, &data->trusted_suspender_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { @@ -1378,7 +1365,7 @@ class WasmInstanceObject::BodyDescriptor final : public BodyDescriptorBase { IteratePointers(obj, offsetof(JSReceiver, properties_or_hash_), offsetof(WasmInstanceObject, trusted_data_), v); IterateTrustedPointer(obj, &instance->trusted_data_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); IteratePointers(obj, offsetof(WasmInstanceObject, module_object_), WasmInstanceObject::kHeaderSize, v); IterateJSObjectBodyImpl(map, obj, WasmInstanceObject::kHeaderSize, @@ -1399,7 +1386,7 @@ class WasmTagObject::BodyDescriptor final : public BodyDescriptorBase { IteratePointers(obj, offsetof(JSReceiver, properties_or_hash_), offsetof(WasmTagObject, trusted_data_), v); IterateTrustedPointer(obj, &tag_object->trusted_data_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); IterateJSObjectBodyImpl(map, obj, WasmTagObject::kHeaderSize, object_size, v); } @@ -1433,7 +1420,7 @@ class WasmInternalFunction::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kWasmInternalFunctionIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kWasmInternalFunctionTrustedPointerTag, v); IterateProtectedPointer( obj, offsetof(WasmInternalFunction, protected_implicit_arg_), v); IteratePointer(obj, offsetof(WasmInternalFunction, external_), v); @@ -1450,8 +1437,7 @@ class WasmFunctionData::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kWasmFunctionDataIndirectPointerTagRange, - v); + IterateSelfTrustedPointer(obj, kWasmFunctionDataTrustedPointerTagRange, v); IteratePointer(obj, offsetof(WasmFunctionData, func_ref_), v); IteratePointer(obj, offsetof(WasmFunctionData, js_promise_flags_), v); IterateProtectedPointer(obj, @@ -1479,7 +1465,7 @@ class WasmExportedFunctionData::BodyDescriptor final IteratePointer(obj, offsetof(WasmExportedFunctionData, packed_args_size_), v); IterateCodePointer(obj, &data->c_wrapper_code_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { @@ -1506,10 +1492,7 @@ class WasmSuspenderObject::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kWasmSuspenderIndirectPointerTag, v); - v->VisitExternalPointer( - obj, obj->RawExternalPointerField(offsetof(WasmSuspenderObject, stack_), - kWasmStackMemoryTag)); + IterateSelfTrustedPointer(obj, kWasmSuspenderTrustedPointerTag, v); IterateProtectedPointer(obj, offsetof(WasmSuspenderObject, parent_), v); IteratePointer(obj, offsetof(WasmSuspenderObject, promise_), v); IteratePointer(obj, offsetof(WasmSuspenderObject, resume_), v); @@ -1528,10 +1511,10 @@ class WasmTrustedInstanceData::BodyDescriptor final static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { bool shared = HeapLayout::InAnySharedSpace(obj); - IndirectPointerTag tag = - shared ? kSharedWasmTrustedInstanceDataIndirectPointerTag - : kWasmTrustedInstanceDataIndirectPointerTag; - IterateSelfIndirectPointer(obj, tag, v); + TrustedPointerTag tag = + shared ? kSharedWasmTrustedInstanceDataTrustedPointerTag + : kWasmTrustedInstanceDataTrustedPointerTag; + IterateSelfTrustedPointer(obj, tag, v); for (uint16_t offset : kTaggedFieldOffsets) { IteratePointer(obj, offset, v); } @@ -1555,9 +1538,9 @@ class WasmTableObject::BodyDescriptor final : public BodyDescriptorBase { IteratePointers(obj, JSObject::BodyDescriptor::kStartOffset, offsetof(WasmTableObject, trusted_dispatch_table_), v); IterateTrustedPointer(obj, &table->trusted_dispatch_table_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); IterateTrustedPointer(obj, &table->trusted_data_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); IterateJSObjectBodyImpl(map, obj, WasmTableObject::kHeaderSize, object_size, v); } @@ -1576,7 +1559,7 @@ class WasmGlobalObject::BodyDescriptor final : public BodyDescriptorBase { IteratePointers(obj, JSObject::BodyDescriptor::kStartOffset, offsetof(WasmGlobalObject, trusted_data_), v); IterateTrustedPointer(obj, &global->trusted_data_, v, - IndirectPointerMode::kStrong); + TrustedPointerMode::kStrong); IteratePointers(obj, offsetof(WasmGlobalObject, buffer_), WasmGlobalObject::kHeaderSize, v); IterateJSObjectBodyImpl(map, obj, WasmGlobalObject::kHeaderSize, @@ -1594,9 +1577,9 @@ class WasmDispatchTable::BodyDescriptor final : public BodyDescriptorBase { static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { bool shared = HeapLayout::InAnySharedSpace(obj); - IndirectPointerTag tag = shared ? kSharedWasmDispatchTableIndirectPointerTag - : kWasmDispatchTableIndirectPointerTag; - IterateSelfIndirectPointer(obj, tag, v); + TrustedPointerTag tag = shared ? kSharedWasmDispatchTableTrustedPointerTag + : kWasmDispatchTableTrustedPointerTag; + IterateSelfTrustedPointer(obj, tag, v); IterateProtectedPointer(obj, kProtectedOffheapDataOffset, v); IterateProtectedPointer(obj, kProtectedUsesOffset, v); int length = TrustedCast<WasmDispatchTable>(obj)->length(kAcquireLoad); @@ -1638,7 +1621,7 @@ class WasmArray::BodyDescriptor final : public BodyDescriptorBase { static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { if (!WasmArray::GcSafeElementType(map).is_ref()) return; - IteratePointers(obj, WasmArray::kHeaderSize, object_size, v); + IteratePointers(obj, WasmArray::HeaderSize(map), object_size, v); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) { @@ -1795,8 +1778,10 @@ class WasmCustomMap::BodyDescriptor final : public BodyDescriptorBase { public: static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - Map::BodyDescriptor::IterateBody(map, obj, object_size, v); - IteratePointer(obj, offsetof(WasmCustomMap, js_wrapper_), v); + static_assert(Map::kSize == offsetof(WasmCustomMap, js_wrapper_)); + Map::BodyDescriptor::IterateBody(map, obj, Map::kSize, v); + IteratePointers(obj, offsetof(WasmCustomMap, js_wrapper_), + WasmCustomMap::kHeaderSize, v); Tagged<WasmCustomMap> wasm_struct = UncheckedCast<WasmCustomMap>(obj); // Not a typo: WasmCustomMap reuses some WasmStruct infrastructure. @@ -1872,7 +1857,7 @@ class Code::BodyDescriptor final : public BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - IterateSelfIndirectPointer(obj, kCodeIndirectPointerTag, v); + IterateSelfTrustedPointer(obj, kCodeTrustedPointerTag, v); IterateProtectedPointer( obj, Code::kDeoptimizationDataOrInterpreterDataOffset, v); IterateProtectedPointer(obj, Code::kPositionTableOffset, v); @@ -1900,7 +1885,7 @@ class CodeWrapper::BodyDescriptor final : public BodyDescriptorBase { static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { Tagged<CodeWrapper> wrapper = UncheckedCast<CodeWrapper>(obj); - IterateCodePointer(obj, &wrapper->code_, v, IndirectPointerMode::kStrong); + IterateCodePointer(obj, &wrapper->code_, v, TrustedPointerMode::kStrong); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> obj) { diff --git a/deps/v8/src/objects/objects-body-descriptors.h b/deps/v8/src/objects/objects-body-descriptors.h index 3aafaf2d8566..e48fc8731df0 100644 --- a/deps/v8/src/objects/objects-body-descriptors.h +++ b/deps/v8/src/objects/objects-body-descriptors.h @@ -56,28 +56,28 @@ class BodyDescriptorBase { template <typename ObjectVisitor> static inline void IterateTrustedPointer(Tagged<HeapObject> obj, int offset, ObjectVisitor* visitor, - IndirectPointerMode mode, - IndirectPointerTagRange tag_range); + TrustedPointerMode mode, + TrustedPointerTagRange tag_range); template <typename ObjectVisitor, typename T, - IndirectPointerTagRange kTagRange> + TrustedPointerTagRange kTagRange> static inline void IterateTrustedPointer( Tagged<HeapObject> obj, TrustedPointerMember<T, kTagRange>* member, - ObjectVisitor* v, IndirectPointerMode mode); + ObjectVisitor* v, TrustedPointerMode mode); template <typename ObjectVisitor> static inline void IterateCodePointer(Tagged<HeapObject> obj, int offset, ObjectVisitor* visitor, - IndirectPointerMode mode); + TrustedPointerMode mode); template <typename ObjectVisitor> static inline void IterateCodePointer( Tagged<HeapObject> obj, - TrustedPointerMember<Code, kCodeIndirectPointerTag>* member, - ObjectVisitor* v, IndirectPointerMode mode); + TrustedPointerMember<Code, kCodeTrustedPointerTag>* member, + ObjectVisitor* v, TrustedPointerMode mode); template <typename ObjectVisitor> - static inline void IterateSelfIndirectPointer( - Tagged<HeapObject> obj, IndirectPointerTagRange tag_range, - ObjectVisitor* v); + static inline void IterateSelfTrustedPointer(Tagged<HeapObject> obj, + TrustedPointerTagRange tag_range, + ObjectVisitor* v); template <typename ObjectVisitor> static inline void IterateProtectedPointer(Tagged<HeapObject> obj, int offset, @@ -286,7 +286,7 @@ class SubclassBodyDescriptor : public BodyDescriptorBase { // Visitor for exposed trusted objects with fixed layout according to // FixedBodyDescriptor. -template <typename T, IndirectPointerTagRange kTagRange> +template <typename T, TrustedPointerTagRange kTagRange> class FixedExposedTrustedObjectBodyDescriptor : public FixedBodyDescriptorFor<T> { static_assert(std::is_base_of_v<ExposedTrustedObject, T>); @@ -296,13 +296,13 @@ class FixedExposedTrustedObjectBodyDescriptor template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { - Base::IterateSelfIndirectPointer(obj, kTagRange, v); + Base::IterateSelfTrustedPointer(obj, kTagRange, v); Base::IterateBody(map, obj, object_size, v); } }; // A mix-in for visiting a trusted pointer field. -template <size_t kFieldOffset, IndirectPointerTagRange kTagRange> +template <size_t kFieldOffset, TrustedPointerTagRange kTagRange> struct WithStrongTrustedPointer { template <typename Base> class BodyDescriptor : public Base { @@ -312,14 +312,14 @@ struct WithStrongTrustedPointer { int object_size, ObjectVisitor* v) { Base::IterateBody(map, obj, object_size, v); Base::IterateTrustedPointer(obj, kFieldOffset, v, - IndirectPointerMode::kStrong, kTagRange); + TrustedPointerMode::kStrong, kTagRange); } }; }; template <size_t kFieldOffset> using WithStrongCodePointer = - WithStrongTrustedPointer<kFieldOffset, kCodeIndirectPointerTag>; + WithStrongTrustedPointer<kFieldOffset, kCodeTrustedPointerTag>; // A mix-in for visiting an external pointer field. template <size_t kFieldOffset, ExternalPointerTagRange kTagRange> diff --git a/deps/v8/src/objects/objects-definitions.h b/deps/v8/src/objects/objects-definitions.h index ef25f49c7050..285d2a707855 100644 --- a/deps/v8/src/objects/objects-definitions.h +++ b/deps/v8/src/objects/objects-definitions.h @@ -165,6 +165,8 @@ namespace internal { debug_script_scope_info) \ V(_, ENUM_CACHE_TYPE, EnumCache, enum_cache) \ V(_, ERROR_STACK_DATA_TYPE, ErrorStackData, error_stack_data) \ + V(_, FOR_IN_ENUMERATOR_HOLDER_TYPE, ForInEnumeratorHolder, \ + for_in_enumerator_holder) \ V(_, FUNCTION_TEMPLATE_RARE_DATA_TYPE, FunctionTemplateRareData, \ function_template_rare_data) \ V(_, MODULE_REQUEST_TYPE, ModuleRequest, module_request) \ @@ -215,7 +217,8 @@ namespace internal { #define ALLOCATION_SITE_MAPS_LIST_ADAPTER(V, TYPE, Name, Size, name_size) \ V(Map, name_size##_map, Name##Size##Map) -// Produces (Map, allocation_site_name_map, AllocationSiteNameMap) entries +// Produces (Map, allocation_site_name_map, AllocationSiteNameMap) +// entries #define ALLOCATION_SITE_MAPS_LIST(V) \ ALLOCATION_SITE_LIST(ALLOCATION_SITE_MAPS_LIST_ADAPTER, V) diff --git a/deps/v8/src/objects/objects-inl.h b/deps/v8/src/objects/objects-inl.h index d77f5622b838..b1f8a9d913c4 100644 --- a/deps/v8/src/objects/objects-inl.h +++ b/deps/v8/src/objects/objects-inl.h @@ -60,9 +60,9 @@ #include "src/objects/tagged-impl-inl.h" #include "src/objects/tagged-index.h" #include "src/objects/templates-inl.h" -#include "src/objects/trusted-pointer-inl.h" #include "src/roots/roots.h" #include "src/sandbox/isolate-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -116,8 +116,6 @@ DEF_CAST_TRAITS(JSArrayIterator) DEF_CAST_TRAITS(JSAsyncFromSyncIterator) DEF_CAST_TRAITS(JSAsyncFunctionObject) DEF_CAST_TRAITS(JSAsyncGeneratorObject) -DEF_CAST_TRAITS(JSAtomicsCondition) -DEF_CAST_TRAITS(JSAtomicsMutex) DEF_CAST_TRAITS(JSBoundFunction) DEF_CAST_TRAITS(JSCollection) DEF_CAST_TRAITS(JSCollectionIterator) @@ -169,9 +167,9 @@ DEF_CAST_TRAITS(JSSharedArray) DEF_CAST_TRAITS(JSSharedStruct) DEF_CAST_TRAITS(JSSpecialObject) DEF_CAST_TRAITS(JSStringIterator) -DEF_CAST_TRAITS(JSSynchronizationPrimitive) DEF_CAST_TRAITS(JSDetachedTypedArray) DEF_CAST_TRAITS(JSTypedArray) +DEF_CAST_TRAITS(Uint8JSTypedArray) DEF_CAST_TRAITS(JSValidIteratorWrapper) DEF_CAST_TRAITS(JSWeakCollection) DEF_CAST_TRAITS(JSWeakRef) @@ -316,6 +314,7 @@ DEF_CAST_TRAITS(ScriptWrapper) DEF_CAST_TRAITS(StringWrapper) DEF_CAST_TRAITS(SymbolWrapper) DEF_CAST_TRAITS(UniqueName) +DEF_CAST_TRAITS(UninitializedHeapNumber) DEF_CAST_TRAITS(Undetectable) template <> @@ -517,6 +516,13 @@ DEF_HEAP_OBJECT_PREDICATE(IsSourceTextModuleInfo) { DEF_HEAP_OBJECT_PREDICATE(IsTemplateLiteralObject) { return IsJSArray(obj); } +DEF_HEAP_OBJECT_PREDICATE(IsUint8JSTypedArray) { + if (!IsJSTypedArray(obj)) return false; + ElementsKind elements_kind = obj->map()->elements_kind(); + return elements_kind == UINT8_ELEMENTS || + elements_kind == RAB_GSAB_UINT8_ELEMENTS; +} + #if V8_INTL_SUPPORT DEF_HEAP_OBJECT_PREDICATE(IsJSSegmentDataObject) { return IsJSObject(obj); } DEF_HEAP_OBJECT_PREDICATE(IsJSSegmentDataObjectWithIsWordLike) { @@ -675,27 +681,18 @@ bool Object::FilterKey(Tagged<Object> obj, PropertyFilter filter) { } // static -std::pair<Representation, PropertyConstness> Object::OptimalRepresentation( - Tagged<Object> obj, PropertyConstness constness) { +Representation Object::OptimalRepresentation(Tagged<Object> obj) { if (IsSmi(obj)) { - return {Representation::Smi(), constness}; + return Representation::Smi(); } Tagged<HeapObject> heap_object = Cast<HeapObject>(obj); if (IsUninitializedHole(heap_object)) { - return {Representation::None(), constness}; + return Representation::None(); } if (IsHeapNumber(heap_object)) { - if (constness == PropertyConstness::kConst && - Cast<HeapNumber>(heap_object)->is_the_hole()) { - // Make sure that even an initializing store of a double value with - // the hole NaN pattern removes constness, otherwise it wouldn't be - // possible to distinguish whether subsequent stores to a double field - // is initializing or not. - constness = PropertyConstness::kMutable; - } - return {Representation::Double(), constness}; + return Representation::Double(); } - return {Representation::HeapObject(), constness}; + return Representation::HeapObject(); } // static @@ -808,10 +805,7 @@ template <typename T, template <typename> typename HandleType> requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>) typename HandleType<Number>::MaybeType Object::ToUint32(Isolate* isolate, HandleType<T> input) { - if (IsSmi(*input)) { - return typename HandleType<Number>::MaybeType( - Smi::ToUint32Smi(Cast<Smi>(*input)), isolate); - } + if (IsSmi(*input) && Smi::ToInt(*input) >= 0) return Cast<Smi>(input); return ConvertToUint32(isolate, Cast<Object>(input)); } @@ -964,20 +958,19 @@ AllocationAlignment HeapObject::RequiredAlignment(InSharedSpace in_shared_space, static_assert(!USE_ALLOCATION_ALIGNMENT_HEAP_NUMBER_BOOL || (offsetof(HeapNumber, value_) & kDoubleAlignmentMask) == kTaggedSize); - if (instance_type == HEAP_NUMBER_TYPE) return kDoubleUnaligned; + if (instance_type == HEAP_NUMBER_TYPE || + instance_type == UNINITIALIZED_HEAP_NUMBER_TYPE) { + return kDoubleUnaligned; + } } #if V8_ENABLE_WEBASSEMBLY - if (in_shared_space && v8_flags.wasm_shared) [[unlikely]] { + if (in_shared_space) [[unlikely]] { int instance_type = map->instance_type(); - if (instance_type == WASM_STRUCT_TYPE || + if (instance_type == WASM_STRUCT_TYPE || instance_type == WASM_ARRAY_TYPE || instance_type == WASM_CUSTOM_MAP_TYPE) { - // The map of a shared wasm struct needs to be in the shared space. + // The map of a shared wasm object needs to be in the shared space. DCHECK(HeapLayout::InWritableSharedSpace(map)); return kDoubleAligned; - } else if (instance_type == WASM_ARRAY_TYPE) { - // The map of a shared wasm array needs to be in the shared space. - DCHECK(HeapLayout::InWritableSharedSpace(map)); - return kDoubleUnaligned; } } #endif diff --git a/deps/v8/src/objects/objects.cc b/deps/v8/src/objects/objects.cc index 3ff2dd2f8d52..20327c5b7066 100644 --- a/deps/v8/src/objects/objects.cc +++ b/deps/v8/src/objects/objects.cc @@ -231,14 +231,18 @@ DirectHandle<FieldType> Object::OptimalType(Tagged<Object> obj, return FieldType::Any(isolate); } -Handle<UnionOf<JSAny, Hole>> Object::NewStorageFor( - Isolate* isolate, Handle<UnionOf<JSAny, Hole>> object, +Handle<UnionOf<JSAny, Hole, UninitializedHeapNumber>> Object::NewStorageFor( + Isolate* isolate, + Handle<UnionOf<JSAny, Hole, UninitializedHeapNumber>> object, Representation representation) { if (!representation.IsDouble()) return object; - Handle<HeapNumber> result = isolate->factory()->NewHeapNumberWithHoleNaN(); + DCHECK(!IsUninitializedHeapNumber(*object)); + if (IsUninitializedHeapNumber(*object)) return object; if (IsUninitializedHole(*object)) { - result->set_value_as_bits(kHoleNanInt64); - } else if (IsHeapNumber(*object)) { + return isolate->factory()->NewUninitializedHeapNumber(); + } + Handle<HeapNumber> result = isolate->factory()->NewHeapNumberFromBits(0); + if (IsHeapNumber(*object)) { // Ensure that all bits of the double value are preserved. result->set_value_as_bits(Cast<HeapNumber>(*object)->value_as_bits()); } else { @@ -410,17 +414,14 @@ template <template <typename> typename HandleType> typename HandleType<Number>::MaybeType Object::ConvertToUint32( Isolate* isolate, HandleType<Object> input) { ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input)); - if (IsSmi(*input)) { - return typename HandleType<Number>::MaybeType( - Smi::ToUint32Smi(Cast<Smi>(*input)), isolate); - } + if (IsSmi(*input) && Smi::ToInt(*input) >= 0) return Cast<Smi>(input); return isolate->factory()->NewNumberFromUint( - DoubleToUint32(Cast<HeapNumber>(*input)->value())); + DoubleToUint32(Object::NumberValue(Cast<Number>(*input)))); } -template MaybeDirectHandle<Number> Object::ConvertToUint32( +template V8_EXPORT_PRIVATE MaybeDirectHandle<Number> Object::ConvertToUint32( Isolate* isolate, DirectHandle<Object> input); -template MaybeIndirectHandle<Number> Object::ConvertToUint32( +template V8_EXPORT_PRIVATE MaybeIndirectHandle<Number> Object::ConvertToUint32( Isolate* isolate, IndirectHandle<Object> input); // static @@ -1461,10 +1462,10 @@ MaybeHandle<JSAny> JSProxy::GetProperty(Isolate* isolate, isolate, trap_result, Execution::Call(isolate, trap, handler, base::VectorOf(args))); - MaybeHandle<JSAny> result = + MaybeDirectHandle<JSAny> result = JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet); if (result.is_null()) { - return result; + return {}; } // 11. Return trap_result @@ -1472,7 +1473,7 @@ MaybeHandle<JSAny> JSProxy::GetProperty(Isolate* isolate, } // static -MaybeHandle<JSAny> JSProxy::CheckGetSetTrapResult( +MaybeDirectHandle<JSAny> JSProxy::CheckGetSetTrapResult( Isolate* isolate, DirectHandle<Name> name, DirectHandle<JSReceiver> target, DirectHandle<Object> trap_result, AccessKind access_kind) { // 9. Let targetDesc be ? target.[[GetOwnProperty]](P). @@ -1527,7 +1528,7 @@ MaybeHandle<JSAny> JSProxy::CheckGetSetTrapResult( } } } - return isolate->factory()->undefined_value(); + return Cast<JSAny>(trap_result); } // static @@ -2025,7 +2026,7 @@ int HeapObject::SizeFromMap(Tagged<Map> map) const { if (instance_size != kVariableSizeSentinel) return instance_size; // Only inline the most frequent cases. InstanceType instance_type = map->instance_type(); - if (InstanceTypeChecker::IsMap(instance_type)) { + if (instance_type == MAP_TYPE) { return UncheckedCast<Map>(this)->AllocatedSize(); } if (base::IsInRange(instance_type, FIRST_FIXED_ARRAY_TYPE, @@ -3198,7 +3199,7 @@ Maybe<bool> JSProxy::SetProperty(DirectHandle<JSProxy> proxy, trap_name, name)); } - MaybeDirectHandle<Object> result = + MaybeDirectHandle<JSAny> result = JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet); if (result.is_null()) { @@ -4088,7 +4089,7 @@ void DescriptorArray::Initialize(Tagged<EnumCache> empty_enum_cache, set_number_of_all_descriptors(nof_descriptors + slack, kReleaseStore); set_number_of_descriptors(nof_descriptors); set_enum_cache(empty_enum_cache, SKIP_WRITE_BARRIER); - set_flags(FastIterableBits::encode(FastIterableState::kUnknown), + set_flags(Flags().with_fast_iterable(FastIterableState::kUnknown), kRelaxedStore); MemsetTagged(GetDescriptorSlot(0), undefined_value, number_of_all_descriptors() * kEntrySize); @@ -4503,25 +4504,6 @@ Address JSArray::ArrayJoinConcatToSequentialString( END_PROHIBIT_SIGN_CONVERSION() -void Oddball::Initialize(Isolate* isolate, DirectHandle<Oddball> oddball, - const char* to_string, DirectHandle<Number> to_number, - const char* type_of, uint8_t kind) { - DirectHandle<String> internalized_to_string = - isolate->factory()->InternalizeUtf8String(to_string); - DirectHandle<String> internalized_type_of = - isolate->factory()->InternalizeUtf8String(type_of); - if (IsHeapNumber(*to_number)) { - oddball->set_to_number_raw_as_bits( - Cast<HeapNumber>(to_number)->value_as_bits()); - } else { - oddball->set_to_number_raw(Object::NumberValue(*to_number)); - } - oddball->set_to_number(*to_number); - oddball->set_to_string(*internalized_to_string); - oddball->set_type_of(*internalized_type_of); - oddball->set_kind(kind); -} - // static @@ -4683,14 +4665,13 @@ const char* Symbol::PrivateSymbolToName() const { } v8::Promise::PromiseState JSPromise::status() const { - int value = flags() & StatusBits::kMask; + v8::Promise::PromiseState value = flags().status(); DCHECK(value == 0 || value == 1 || value == 2); - return static_cast<v8::Promise::PromiseState>(value); + return value; } void JSPromise::set_status(Promise::PromiseState status) { - int value = flags() & ~StatusBits::kMask; - set_flags(value | status); + set_flags(flags().with_status(status)); } // static @@ -4767,7 +4748,12 @@ Handle<Object> JSPromise::Reject(DirectHandle<JSPromise> promise, MoveMessageToPromise(isolate, promise); - if (debug_event) isolate->debug()->OnPromiseReject(promise, reason); + if (debug_event) { + isolate->debug()->OnPromiseReject(promise, reason); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->factory()->undefined_value(); + } + } isolate->RunAllPromiseHooks(PromiseHookType::kResolve, promise, isolate->factory()->undefined_value()); @@ -5062,9 +5048,9 @@ MaybeHandle<JSPromise> JSPromise::PerformPromiseAll( DirectHandle<JSArray> empty_array = factory->NewJSArrayWithElements(factory->empty_fixed_array()); DirectHandle<Object> resolve_args[] = {empty_array}; - Execution::Call(isolate, capability_resolve, factory->undefined_value(), - base::VectorOf(resolve_args)) - .ToHandleChecked(); + RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, capability_resolve, + factory->undefined_value(), + base::VectorOf(resolve_args))); return capability_promise; } @@ -5072,9 +5058,9 @@ MaybeHandle<JSPromise> JSPromise::PerformPromiseAll( DirectHandle<Object> error = factory->NewRangeError( MessageTemplate::kTooManyElementsInPromiseCombinator, factory->NewStringFromAsciiChecked("all")); - Execution::Call(isolate, capability_reject, factory->undefined_value(), - base::VectorOf(&error, 1)) - .ToHandleChecked(); + RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, capability_reject, + factory->undefined_value(), + base::VectorOf(&error, 1))); return capability_promise; } @@ -5098,19 +5084,9 @@ MaybeHandle<JSPromise> JSPromise::PerformPromiseAll( i + 1); DirectHandle<Object> args[] = {resolve_element, capability_reject, factory->undefined_value()}; - if (V8_UNLIKELY(Execution::CallBuiltin(isolate, - isolate->perform_promise_then(), - promise, base::VectorOf(args)) - .is_null())) { - CHECK(isolate->has_exception()); - DirectHandle<Object> reject_args[] = { - direct_handle(isolate->exception(), isolate)}; - isolate->clear_exception(); - Execution::Call(isolate, capability_reject, factory->undefined_value(), - base::VectorOf(reject_args)) - .ToHandleChecked(); - return capability_promise; - } + RETURN_ON_EXCEPTION(isolate, Execution::CallBuiltin( + isolate, isolate->perform_promise_then(), + promise, base::VectorOf(args))); // For catch prediction, mark that rejections here are // semantically handled by the combined Promise. if (isolate->debug()->is_active()) { diff --git a/deps/v8/src/objects/objects.h b/deps/v8/src/objects/objects.h index 91258503a2cb..a6073e5f8e74 100644 --- a/deps/v8/src/objects/objects.h +++ b/deps/v8/src/objects/objects.h @@ -166,12 +166,7 @@ class Object : public AllStatic { V8_WARN_UNUSED_RESULT static inline Maybe<double> IntegerValue( Isolate* isolate, HandleType<T> input); - // Selects optimal representation and constness for a given value. - // Usually, the constness stays unmodified unless the value is a HeapNumber - // with the hole NaN pattern. This is necessary to distinguish between - // initialized and non-initialized double fields. - static inline std::pair<Representation, PropertyConstness> - OptimalRepresentation(Tagged<Object> obj, PropertyConstness constness); + static inline Representation OptimalRepresentation(Tagged<Object> obj); static inline ElementsKind OptimalElementsKind(Tagged<Object> obj); @@ -188,9 +183,10 @@ class Object : public AllStatic { Isolate* isolate, Representation representation); - V8_EXPORT_PRIVATE static Handle<UnionOf<JSAny, Hole>> NewStorageFor( - Isolate* isolate, Handle<UnionOf<JSAny, Hole>> object, - Representation representation); + V8_EXPORT_PRIVATE static Handle<UnionOf<JSAny, Hole, UninitializedHeapNumber>> + NewStorageFor(Isolate* isolate, + Handle<UnionOf<JSAny, Hole, UninitializedHeapNumber>> object, + Representation representation); template <AllocationType allocation_type = AllocationType::kYoung, typename IsolateT> @@ -639,8 +635,9 @@ class Object : public AllStatic { Isolate* isolate, HandleType<Object> input); template <template <typename> typename HandleType> requires(std::is_convertible_v<HandleType<Object>, DirectHandle<Object>>) - V8_WARN_UNUSED_RESULT static HandleType<Number>::MaybeType ConvertToUint32( - Isolate* isolate, HandleType<Object> input); + EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) + V8_WARN_UNUSED_RESULT static typename HandleType<Number>::MaybeType + ConvertToUint32(Isolate* isolate, HandleType<Object> input); V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Number> ConvertToLength(Isolate* isolate, DirectHandle<Object> input); template <template <typename> typename HandleType> diff --git a/deps/v8/src/objects/oddball-inl.h b/deps/v8/src/objects/oddball-inl.h index 5cd317b01fc5..2d6ed18e4651 100644 --- a/deps/v8/src/objects/oddball-inl.h +++ b/deps/v8/src/objects/oddball-inl.h @@ -10,10 +10,13 @@ #include "src/handles/handles-inl.h" #include "src/heap/heap-write-barrier-inl.h" -#include "src/objects/heap-number.h" +#include "src/objects/heap-number-inl.h" #include "src/objects/heap-object-inl.h" +#include "src/objects/heap-object-set-map-inl.h" +#include "src/objects/objects-inl.h" #include "src/objects/oddball-predicates-inl.h" #include "src/objects/tagged-field-inl.h" +#include "src/roots/roots-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -24,6 +27,37 @@ namespace internal { DEF_CAST_TRAITS(Oddball) ODDBALL_LIST(DEF_CAST_TRAITS) +Oddball::Oddball(Tagged<ReadOnly<Map>> map, uint8_t kind) + : PrimitiveHeapObject(map), kind_(Smi::FromInt(kind)) {} + +void Oddball::FinishInitialization(Tagged<String> to_string, + Tagged<Number> to_number, + Tagged<String> type_of) { + if (IsHeapNumber(to_number)) { + set_to_number_raw_as_bits(Cast<HeapNumber>(to_number)->value_as_bits()); + } else { + set_to_number_raw(Object::NumberValue(to_number)); + } + set_to_number(to_number, SKIP_WRITE_BARRIER); + set_to_string(to_string, SKIP_WRITE_BARRIER); + set_type_of(type_of, SKIP_WRITE_BARRIER); +} + +Null::Null(const AllocationWitness& witness) + : Oddball(witness.roots().null_map(), Oddball::kNull) {} + +Undefined::Undefined(const AllocationWitness& witness) + : Oddball(witness.roots().undefined_map(), Oddball::kUndefined) {} + +Boolean::Boolean(const AllocationWitness& witness, uint8_t kind) + : Oddball(witness.roots().boolean_map(), kind) {} + +True::True(const AllocationWitness& witness) + : Boolean(witness, Oddball::kTrue) {} + +False::False(const AllocationWitness& witness) + : Boolean(witness, Oddball::kFalse) {} + double Oddball::to_number_raw() const { return to_number_raw_.value(); } void Oddball::set_to_number_raw(double value) { to_number_raw_.set_value(value); @@ -51,10 +85,6 @@ void Oddball::set_type_of(Tagged<String> value, WriteBarrierMode mode) { uint8_t Oddball::kind() const { return kind_.load().value(); } -void Oddball::set_kind(uint8_t value) { - kind_.store(this, Smi::FromInt(value)); -} - // static Handle<Number> Oddball::ToNumber(Isolate* isolate, DirectHandle<Oddball> input) { diff --git a/deps/v8/src/objects/oddball-predicates-inl.h b/deps/v8/src/objects/oddball-predicates-inl.h index d0394f669d20..d7c9fc096a81 100644 --- a/deps/v8/src/objects/oddball-predicates-inl.h +++ b/deps/v8/src/objects/oddball-predicates-inl.h @@ -82,6 +82,8 @@ inline bool IsAnyHoleNoSpaceCheck(Tagged<HeapObject> obj) { inline bool IsWasmNullNoSpaceCheck(Tagged<HeapObject> obj) { #if V8_STATIC_ROOTS_BOOL && V8_ENABLE_WEBASSEMBLY return static_cast<Tagged_t>(obj.ptr()) == StaticReadOnlyRoot::kWasmNull; +#elif V8_STATIC_ROOTS_GENERATION_BOOL && V8_ENABLE_WEBASSEMBLY + return obj == GetReadOnlyRoots().wasm_null(); #elif V8_ENABLE_WEBASSEMBLY return obj->map()->instance_type() == WASM_NULL_TYPE; #else diff --git a/deps/v8/src/objects/oddball.h b/deps/v8/src/objects/oddball.h index d3e3a210c1ce..fee3ed86f91a 100644 --- a/deps/v8/src/objects/oddball.h +++ b/deps/v8/src/objects/oddball.h @@ -39,7 +39,6 @@ V8_OBJECT class Oddball : public PrimitiveHeapObject { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline uint8_t kind() const; - inline void set_kind(uint8_t kind); // ES6 section 7.1.3 ToNumber for Boolean, Null, Undefined. V8_WARN_UNUSED_RESULT static inline Handle<Number> ToNumber( @@ -48,10 +47,13 @@ V8_OBJECT class Oddball : public PrimitiveHeapObject { // Dispatched behavior. DECL_VERIFIER(Oddball) - // Initialize the fields. - static void Initialize(Isolate* isolate, DirectHandle<Oddball> oddball, - const char* to_string, DirectHandle<Number> to_number, - const char* type_of, uint8_t kind); + inline Oddball(Tagged<ReadOnly<Map>> map, uint8_t kind); + + // Finish initializing the oddball's string and number fields once the read- + // only string table and HeapNumbers have been created. + inline void FinishInitialization(Tagged<String> to_string, + Tagged<Number> to_number, + Tagged<String> type_of); static constexpr uint8_t kFalse = 0; static constexpr uint8_t kTrue = 1; @@ -77,7 +79,7 @@ V8_OBJECT class Oddball : public PrimitiveHeapObject { TaggedMember<String> to_string_; TaggedMember<Number> to_number_; TaggedMember<String> type_of_; - TaggedMember<Smi> kind_; + const TaggedMember<Smi> kind_; } V8_OBJECT_END; template <> @@ -93,10 +95,16 @@ struct ObjectTraits<Oddball> { V8_OBJECT class Null : public Oddball { V8_IT_REUSE_PARENT; + + public: + inline explicit Null(const AllocationWitness& witness); } V8_OBJECT_END; V8_OBJECT class Undefined : public Oddball { V8_IT_REUSE_PARENT; + + public: + inline explicit Undefined(const AllocationWitness& witness); } V8_OBJECT_END; V8_OBJECT class Boolean : public Oddball { @@ -104,15 +112,23 @@ V8_OBJECT class Boolean : public Oddball { V8_IT_NO_AUTO_CHECKER; public: + inline Boolean(const AllocationWitness& witness, uint8_t kind); + V8_INLINE bool ToBool(Isolate* isolate) const; } V8_OBJECT_END; V8_OBJECT class True : public Boolean { V8_IT_REUSE_PARENT; + + public: + inline explicit True(const AllocationWitness& witness); } V8_OBJECT_END; V8_OBJECT class False : public Boolean { V8_IT_REUSE_PARENT; + + public: + inline explicit False(const AllocationWitness& witness); } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/off-heap-hash-table-inl.h b/deps/v8/src/objects/off-heap-hash-table-inl.h index 28450b93e8a1..aff1e6ab6f34 100644 --- a/deps/v8/src/objects/off-heap-hash-table-inl.h +++ b/deps/v8/src/objects/off-heap-hash-table-inl.h @@ -8,6 +8,8 @@ #include "src/objects/off-heap-hash-table.h" // Include the non-inl header before the rest of the headers. +#include <bit> + #include "src/objects/compressed-slots-inl.h" namespace v8 { @@ -90,7 +92,7 @@ int OffHeapHashTableBase<Derived>::ComputeCapacity(int at_least_space_for) { // Add 50% slack to make slot collisions sufficiently unlikely. // See matching computation in HasSufficientCapacityToAdd(). int raw_capacity = at_least_space_for + (at_least_space_for >> 1); - int capacity = base::bits::RoundUpToPowerOfTwo32(raw_capacity); + int capacity = std::bit_ceil<uint32_t>(raw_capacity); return std::max(capacity, Derived::kMinCapacity); } diff --git a/deps/v8/src/objects/ordered-hash-table.cc b/deps/v8/src/objects/ordered-hash-table.cc index 170c9f174572..8a54044b3d82 100644 --- a/deps/v8/src/objects/ordered-hash-table.cc +++ b/deps/v8/src/objects/ordered-hash-table.cc @@ -4,6 +4,8 @@ #include "src/objects/ordered-hash-table.h" +#include <bit> + #include "src/execution/isolate.h" #include "src/heap/heap-inl.h" #include "src/objects/heap-object-set-map-inl.h" @@ -25,8 +27,7 @@ MaybeHandle<Derived> OrderedHashTable<Derived, entrysize>::Allocate( // from number of buckets. If we decide to change kLoadFactor // to something other than 2, capacity should be stored as another // field of this object. - capacity = - base::bits::RoundUpToPowerOfTwo32(std::max({kInitialCapacity, capacity})); + capacity = std::bit_ceil<uint32_t>(std::max({kInitialCapacity, capacity})); if (capacity > MaxCapacity()) { // Throw RangeError with a generic message. THROW_NEW_ERROR(isolate, diff --git a/deps/v8/src/objects/ordered-hash-table.h b/deps/v8/src/objects/ordered-hash-table.h index 617d6dc5c629..17aa6577c2dc 100644 --- a/deps/v8/src/objects/ordered-hash-table.h +++ b/deps/v8/src/objects/ordered-hash-table.h @@ -710,12 +710,17 @@ V8_OBJECT class SmallOrderedHashSet public: uint8_t number_of_elements_; uint8_t number_of_deleted_elements_; - uint8_t number_of_buckets_; + V8_TQ_CONST uint8_t number_of_buckets_; #if TAGGED_SIZE_8_BYTES uint8_t padding_[5]; #else uint8_t padding_[1]; #endif + // The tail holds the data table (capacity entries), the uint8 hash table + // (number_of_buckets) and the uint8 chain table (capacity); see + // DataTableStartOffset(), GetBucketsStartOffset() and + // GetChainTableOffset(). Torque never accesses it. + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; @@ -753,12 +758,17 @@ V8_OBJECT class SmallOrderedHashMap public: uint8_t number_of_elements_; uint8_t number_of_deleted_elements_; - uint8_t number_of_buckets_; + V8_TQ_CONST uint8_t number_of_buckets_; #if TAGGED_SIZE_8_BYTES uint8_t padding_[5]; #else uint8_t padding_[1]; #endif + // The tail holds the data table (capacity entries), the uint8 hash table + // (number_of_buckets) and the uint8 chain table (capacity); see + // DataTableStartOffset(), GetBucketsStartOffset() and + // GetChainTableOffset(). Torque never accesses it. + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; @@ -997,12 +1007,17 @@ V8_OBJECT class SmallOrderedNameDictionary #endif uint8_t number_of_elements_; uint8_t number_of_deleted_elements_; - uint8_t number_of_buckets_; + V8_TQ_CONST uint8_t number_of_buckets_; #if TAGGED_SIZE_8_BYTES uint8_t padding_1_[5]; #else uint8_t padding_1_[1]; #endif + // The tail holds the data table (capacity entries of key, value, details), + // the uint8 hash table (number_of_buckets) and the uint8 chain table + // (capacity); see DataTableStartOffset(), GetBucketsStartOffset() and + // GetChainTableOffset(). Torque never accesses it. + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/ordered-hash-table.tq b/deps/v8/src/objects/ordered-hash-table.tq index d55ff28c36bf..e1758b8950a3 100644 --- a/deps/v8/src/objects/ordered-hash-table.tq +++ b/deps/v8/src/objects/ordered-hash-table.tq @@ -4,20 +4,14 @@ #include 'src/objects/ordered-hash-table.h' -const kSmallOrderedHashTableMaxCapacity: constexpr int31 - generates 'SmallOrderedHashTable::kMaxCapacity'; -const kSmallOrderedHashTableNotFound: constexpr int31 - generates 'SmallOrderedHashTable::kNotFound'; -const kSmallOrderedHashTableLoadFactor: constexpr int31 - generates 'SmallOrderedHashTable::kLoadFactor'; - @abstract @cppObjectLayoutDefinition extern class SmallOrderedHashTable extends HeapObject generates 'HeapObject' {} -extern macro SmallOrderedHashSetMapConstant(): Map; -const kSmallOrderedHashSetMap: Map = SmallOrderedHashSetMapConstant(); +// The small ordered hash tables are allocated and accessed from C++ only; +// their variable-length tails (data table, hash table, chain table) are laid +// out by the offset helpers in ordered-hash-table.h and not visible to Torque. @cppObjectLayoutDefinition extern class SmallOrderedHashSet extends SmallOrderedHashTable { @@ -26,38 +20,8 @@ extern class SmallOrderedHashSet extends SmallOrderedHashTable { const number_of_buckets: uint8; @if(TAGGED_SIZE_8_BYTES) padding[5]: uint8; @ifnot(TAGGED_SIZE_8_BYTES) padding[1]: uint8; - data_table[Convert<intptr>(number_of_buckets) * kSmallOrderedHashTableLoadFactor]: - JSAny|TheHole; - hash_table[number_of_buckets]: uint8; - chain_table[Convert<intptr>(number_of_buckets) * kSmallOrderedHashTableLoadFactor]: - uint8; -} - -@export -macro AllocateSmallOrderedHashSet(capacity: intptr): SmallOrderedHashSet { - const hashTableSize = capacity / kSmallOrderedHashTableLoadFactor; - dcheck( - 0 <= hashTableSize && hashTableSize <= kSmallOrderedHashTableMaxCapacity); - return new SmallOrderedHashSet{ - map: kSmallOrderedHashSetMap, - number_of_elements: 0, - number_of_deleted_elements: 0, - number_of_buckets: (Convert<uint8>(hashTableSize)), - padding: ...ConstantIterator<uint8>(0), - data_table: ...ConstantIterator(TheHole), - hash_table: ...ConstantIterator<uint8>(kSmallOrderedHashTableNotFound), - chain_table: ...ConstantIterator<uint8>(kSmallOrderedHashTableNotFound) - }; -} - -struct HashMapEntry { - key: JSAny|TheHole; - value: JSAny|TheHole; } -extern macro SmallOrderedHashMapMapConstant(): Map; -const kSmallOrderedHashMapMap: Map = SmallOrderedHashMapMapConstant(); - @cppObjectLayoutDefinition extern class SmallOrderedHashMap extends SmallOrderedHashTable { number_of_elements: uint8; @@ -65,34 +29,6 @@ extern class SmallOrderedHashMap extends SmallOrderedHashTable { const number_of_buckets: uint8; @if(TAGGED_SIZE_8_BYTES) padding[5]: uint8; @ifnot(TAGGED_SIZE_8_BYTES) padding[1]: uint8; - data_table[Convert<intptr>(number_of_buckets) * kSmallOrderedHashTableLoadFactor]: - HashMapEntry; - hash_table[number_of_buckets]: uint8; - chain_table[Convert<intptr>(number_of_buckets) * kSmallOrderedHashTableLoadFactor]: - uint8; -} - -@export -macro AllocateSmallOrderedHashMap(capacity: intptr): SmallOrderedHashMap { - const hashTableSize = capacity / kSmallOrderedHashTableLoadFactor; - dcheck( - 0 <= hashTableSize && hashTableSize <= kSmallOrderedHashTableMaxCapacity); - return new SmallOrderedHashMap{ - map: kSmallOrderedHashMapMap, - number_of_elements: 0, - number_of_deleted_elements: 0, - number_of_buckets: (Convert<uint8>(hashTableSize)), - padding: ...ConstantIterator<uint8>(0), - data_table: ...ConstantIterator(HashMapEntry{key: TheHole, value: TheHole}), - hash_table: ...ConstantIterator<uint8>(kSmallOrderedHashTableNotFound), - chain_table: ...ConstantIterator<uint8>(kSmallOrderedHashTableNotFound) - }; -} - -struct NameDictionaryEntry { - key: JSAny|TheHole; - value: JSAny|TheHole; - property_details: Smi|TheHole; } @cppObjectLayoutDefinition @@ -105,8 +41,4 @@ extern class SmallOrderedNameDictionary extends SmallOrderedHashTable { const number_of_buckets: uint8; @if(TAGGED_SIZE_8_BYTES) padding_1[5]: uint8; @ifnot(TAGGED_SIZE_8_BYTES) padding_1[1]: uint8; - data_table[Convert<intptr>(number_of_buckets) * kSmallOrderedHashTableLoadFactor]: - NameDictionaryEntry; - hash_table[number_of_buckets]: uint8; - chain_table[number_of_buckets]: uint8; } diff --git a/deps/v8/src/objects/primitive-heap-object.h b/deps/v8/src/objects/primitive-heap-object.h index 8c55977e65cd..a7693ae77e76 100644 --- a/deps/v8/src/objects/primitive-heap-object.h +++ b/deps/v8/src/objects/primitive-heap-object.h @@ -20,6 +20,8 @@ V8_OBJECT class PrimitiveHeapObject : public HeapObject { V8_IT_ABSTRACT; public: + inline explicit PrimitiveHeapObject(Tagged<ReadOnly<Map>> map); + DECL_VERIFIER(PrimitiveHeapObject) } V8_OBJECT_END; diff --git a/deps/v8/src/objects/promise-inl.h b/deps/v8/src/objects/promise-inl.h index c5e471a11414..13211f99228e 100644 --- a/deps/v8/src/objects/promise-inl.h +++ b/deps/v8/src/objects/promise-inl.h @@ -51,58 +51,60 @@ void PromiseReactionJobTask::set_promise_or_capability( promise_or_capability_.store(this, value, mode); } +PromiseResolveThenableJobTask::PromiseResolveThenableJobTask( + const AllocationWitness& witness, Tagged<JSPromise> promise_to_resolve, + Tagged<JSReceiver> thenable, Tagged<JSReceiver> then, + Tagged<Context> context +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ) + : Microtask(witness, witness.roots().promise_resolve_thenable_job_task_map() +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + continuation_preserved_embedder_data +#endif + ), + context_(witness, context), + promise_to_resolve_(witness, promise_to_resolve), + thenable_(witness, thenable), + then_(witness, then) { +} + Tagged<Context> PromiseResolveThenableJobTask::context() const { return context_.load(); } -void PromiseResolveThenableJobTask::set_context(Tagged<Context> value, - WriteBarrierMode mode) { - context_.store(this, value, mode); -} Tagged<JSPromise> PromiseResolveThenableJobTask::promise_to_resolve() const { return promise_to_resolve_.load(); } -void PromiseResolveThenableJobTask::set_promise_to_resolve( - Tagged<JSPromise> value, WriteBarrierMode mode) { - promise_to_resolve_.store(this, value, mode); -} Tagged<JSReceiver> PromiseResolveThenableJobTask::thenable() const { return thenable_.load(); } -void PromiseResolveThenableJobTask::set_thenable(Tagged<JSReceiver> value, - WriteBarrierMode mode) { - thenable_.store(this, value, mode); -} Tagged<JSReceiver> PromiseResolveThenableJobTask::then() const { return then_.load(); } -void PromiseResolveThenableJobTask::set_then(Tagged<JSReceiver> value, - WriteBarrierMode mode) { - then_.store(this, value, mode); -} // PromiseCapability +PromiseCapability::PromiseCapability( + const AllocationWitness& witness, + Tagged<UnionOf<JSReceiver, Undefined>> promise, Tagged<JSAny> resolve, + Tagged<JSAny> reject) + : Struct(witness.roots().promise_capability_map()), + promise_(witness, promise), + resolve_(witness, resolve), + reject_(witness, reject) {} + Tagged<UnionOf<JSReceiver, Undefined>> PromiseCapability::promise() const { return promise_.load(); } -void PromiseCapability::set_promise( - Tagged<UnionOf<JSReceiver, Undefined>> value, WriteBarrierMode mode) { - promise_.store(this, value, mode); -} -Tagged<Object> PromiseCapability::resolve() const { return resolve_.load(); } -void PromiseCapability::set_resolve(Tagged<Object> value, - WriteBarrierMode mode) { - resolve_.store(this, value, mode); -} +Tagged<JSAny> PromiseCapability::resolve() const { return resolve_.load(); } -Tagged<Object> PromiseCapability::reject() const { return reject_.load(); } -void PromiseCapability::set_reject(Tagged<Object> value, - WriteBarrierMode mode) { - reject_.store(this, value, mode); -} +Tagged<JSAny> PromiseCapability::reject() const { return reject_.load(); } #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA Tagged<Object> PromiseReaction::continuation_preserved_embedder_data() const { diff --git a/deps/v8/src/objects/promise.h b/deps/v8/src/objects/promise.h index 94f50bad7d23..7d05058d5e90 100644 --- a/deps/v8/src/objects/promise.h +++ b/deps/v8/src/objects/promise.h @@ -70,7 +70,7 @@ V8_OBJECT class PromiseReactionJobTask : public Microtask { TaggedMember<Object> argument_; TaggedMember<Context> context_; - TaggedMember<PromiseReactionHandler> handler_; + TaggedMember<UnionOf<Undefined, JSGeneratorObject, JSCallable>> handler_; TaggedMember<UnionOf<JSPromise, PromiseCapability, Undefined>> promise_or_capability_; } V8_OBJECT_END; @@ -96,21 +96,20 @@ V8_OBJECT class PromiseRejectReactionJobTask : public PromiseReactionJobTask { // A container struct to hold state required for PromiseResolveThenableJob. V8_OBJECT class PromiseResolveThenableJobTask : public Microtask { public: - inline Tagged<Context> context() const; - inline void set_context(Tagged<Context> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline PromiseResolveThenableJobTask( + const AllocationWitness& witness, Tagged<JSPromise> promise_to_resolve, + Tagged<JSReceiver> thenable, Tagged<JSReceiver> then, + Tagged<Context> context +#ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA + , + Tagged<Object> continuation_preserved_embedder_data +#endif + ); + inline Tagged<Context> context() const; inline Tagged<JSPromise> promise_to_resolve() const; - inline void set_promise_to_resolve( - Tagged<JSPromise> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<JSReceiver> thenable() const; - inline void set_thenable(Tagged<JSReceiver> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<JSReceiver> then() const; - inline void set_then(Tagged<JSReceiver> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); using BodyDescriptor = StructBodyDescriptor; @@ -121,24 +120,22 @@ V8_OBJECT class PromiseResolveThenableJobTask : public Microtask { friend class TorqueGeneratedPromiseResolveThenableJobTaskAsserts; friend class MicrotaskQueueBuiltinsAssembler; - TaggedMember<Context> context_; - TaggedMember<JSPromise> promise_to_resolve_; - TaggedMember<JSReceiver> thenable_; - TaggedMember<JSReceiver> then_; + const TaggedMember<Context> context_; + const TaggedMember<JSPromise> promise_to_resolve_; + const TaggedMember<JSReceiver> thenable_; + const TaggedMember<JSReceiver> then_; } V8_OBJECT_END; // Struct to hold the state of a PromiseCapability. V8_OBJECT class PromiseCapability : public Struct { public: + inline PromiseCapability(const AllocationWitness& witness, + Tagged<UnionOf<JSReceiver, Undefined>> promise, + Tagged<JSAny> resolve, Tagged<JSAny> reject); + inline Tagged<UnionOf<JSReceiver, Undefined>> promise() const; - inline void set_promise(Tagged<UnionOf<JSReceiver, Undefined>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> resolve() const; - inline void set_resolve(Tagged<Object> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> reject() const; - inline void set_reject(Tagged<Object> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline Tagged<JSAny> resolve() const; + inline Tagged<JSAny> reject() const; using BodyDescriptor = StructBodyDescriptor; @@ -149,9 +146,9 @@ V8_OBJECT class PromiseCapability : public Struct { friend class TorqueGeneratedPromiseCapabilityAsserts; friend class MicrotaskQueueBuiltinsAssembler; - TaggedMember<UnionOf<JSReceiver, Undefined>> promise_; - TaggedMember<Object> resolve_; - TaggedMember<Object> reject_; + const TaggedMember<UnionOf<JSReceiver, Undefined>> promise_; + const TaggedMember<JSAny> resolve_; + const TaggedMember<JSAny> reject_; } V8_OBJECT_END; // A representation of promise reaction. This differs from the specification @@ -218,10 +215,10 @@ V8_OBJECT class PromiseReaction : public Struct { #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA TaggedMember<Object> continuation_preserved_embedder_data_; #endif - TaggedMember<UnionOf<PromiseReaction, Smi>> next_; - TaggedMember<UnionOf<JSCallable, JSGeneratorObject, Undefined>> + TaggedMember<UnionOf<PromiseReaction, Zero>> next_; + TaggedMember<UnionOf<Undefined, JSGeneratorObject, JSCallable>> reject_handler_; - TaggedMember<UnionOf<JSCallable, JSGeneratorObject, Undefined>> + TaggedMember<UnionOf<Undefined, JSGeneratorObject, JSCallable>> fulfill_handler_; TaggedMember<UnionOf<JSPromise, PromiseCapability, Undefined>> promise_or_capability_; diff --git a/deps/v8/src/objects/promise.tq b/deps/v8/src/objects/promise.tq index 519e9940eae8..b774efa67b0d 100644 --- a/deps/v8/src/objects/promise.tq +++ b/deps/v8/src/objects/promise.tq @@ -34,7 +34,7 @@ const kPromiseReactionContinuationPreservedEmbedderDataOffset: constexpr int31 @cppObjectLayoutDefinition extern class PromiseReaction extends Struct { @if(V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA) - continuation_preserved_embedder_data: Object|Undefined; + continuation_preserved_embedder_data: Object; next: PromiseReaction|Zero; reject_handler: Callable|JSGeneratorObject|Undefined; fulfill_handler: Callable|JSGeneratorObject|Undefined; diff --git a/deps/v8/src/objects/property-array.h b/deps/v8/src/objects/property-array.h index 0d4c91a5c6fc..02b7676a9018 100644 --- a/deps/v8/src/objects/property-array.h +++ b/deps/v8/src/objects/property-array.h @@ -83,6 +83,7 @@ V8_OBJECT class PropertyArray : public HeapObject { // for class metadata, and the uninitialized_value Hole for not-yet-assigned // slots (see MigrateFastToFast in js-objects.cc). The actual element kind // is dispatched by the descriptor; callers know what to expect. + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, objects); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/property-cell.tq b/deps/v8/src/objects/property-cell.tq index c21877bfbda2..43bdce9d6d00 100644 --- a/deps/v8/src/objects/property-cell.tq +++ b/deps/v8/src/objects/property-cell.tq @@ -5,7 +5,7 @@ // TODOC: Document what this class is used for. @cppObjectLayoutDefinition extern class PropertyCell extends HeapObject { - name: AnyName; + name: Name; property_details_raw: Smi; value: Object; dependent_code: DependentCode; diff --git a/deps/v8/src/objects/property-descriptor-object-inl.h b/deps/v8/src/objects/property-descriptor-object-inl.h index cb507abf437e..9aef9dc822c0 100644 --- a/deps/v8/src/objects/property-descriptor-object-inl.h +++ b/deps/v8/src/objects/property-descriptor-object-inl.h @@ -9,6 +9,7 @@ // Include the non-inl header before the rest of the headers. #include "src/objects/objects-inl.h" +#include "src/objects/struct-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -16,26 +17,44 @@ namespace v8 { namespace internal { +PropertyDescriptorObject::PropertyDescriptorObject( + const AllocationWitness& witness) + : Struct(witness.roots().property_descriptor_object_map()), + flags_(Smi::zero()), + value_(witness.roots().the_hole_value()), + get_(witness.roots().the_hole_value()), + set_(witness.roots().the_hole_value()) {} + int PropertyDescriptorObject::flags() const { return flags_.load().value(); } void PropertyDescriptorObject::set_flags(int value) { flags_.store(this, Smi::FromInt(value)); } -Tagged<Object> PropertyDescriptorObject::value() const { return value_.load(); } -void PropertyDescriptorObject::set_value(Tagged<Object> value, +Tagged<UnionOf<JSAny, TheHole>> PropertyDescriptorObject::value() const { + return value_.load(); +} +void PropertyDescriptorObject::set_value(Tagged<UnionOf<JSAny, TheHole>> value, WriteBarrierMode mode) { value_.store(this, value, mode); } -Tagged<Object> PropertyDescriptorObject::get() const { return get_.load(); } -void PropertyDescriptorObject::set_get(Tagged<Object> value, - WriteBarrierMode mode) { +Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> +PropertyDescriptorObject::get() const { + return get_.load(); +} +void PropertyDescriptorObject::set_get( + Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> value, + WriteBarrierMode mode) { get_.store(this, value, mode); } -Tagged<Object> PropertyDescriptorObject::set() const { return set_.load(); } -void PropertyDescriptorObject::set_set(Tagged<Object> value, - WriteBarrierMode mode) { +Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> +PropertyDescriptorObject::set() const { + return set_.load(); +} +void PropertyDescriptorObject::set_set( + Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> value, + WriteBarrierMode mode) { set_.store(this, value, mode); } diff --git a/deps/v8/src/objects/property-descriptor-object.h b/deps/v8/src/objects/property-descriptor-object.h index f36c50f49396..ff3bdb3d5f34 100644 --- a/deps/v8/src/objects/property-descriptor-object.h +++ b/deps/v8/src/objects/property-descriptor-object.h @@ -53,20 +53,24 @@ V8_OBJECT class PropertyDescriptorObject : public Struct { HasWritableBit::kMask | HasValueBit::kMask | HasGetBit::kMask | HasSetBit::kMask; + inline explicit PropertyDescriptorObject(const AllocationWitness& witness); + inline int flags() const; inline void set_flags(int value); - inline Tagged<Object> value() const; - inline void set_value(Tagged<Object> value, + inline Tagged<UnionOf<JSAny, TheHole>> value() const; + inline void set_value(Tagged<UnionOf<JSAny, TheHole>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> get() const; - inline void set_get(Tagged<Object> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> get() const; + inline void set_get( + Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<Object> set() const; - inline void set_set(Tagged<Object> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> set() const; + inline void set_set( + Tagged<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); using BodyDescriptor = StructBodyDescriptor; @@ -80,10 +84,10 @@ V8_OBJECT class PropertyDescriptorObject : public Struct { friend class ObjectBuiltinsAssembler; friend class MacroAssembler; - TaggedMember<Smi> flags_; - TaggedMember<Object> value_; - TaggedMember<Object> get_; - TaggedMember<Object> set_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<PropertyDescriptorObjectFlags>); + TaggedMember<UnionOf<JSAny, TheHole>> value_; + TaggedMember<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> get_; + TaggedMember<UnionOf<FunctionTemplateInfo, JSAny, TheHole>> set_; } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/property.cc b/deps/v8/src/objects/property.cc index ce805384a607..26c0d6982c16 100644 --- a/deps/v8/src/objects/property.cc +++ b/deps/v8/src/objects/property.cc @@ -104,11 +104,10 @@ Descriptor Descriptor::DataField( Descriptor Descriptor::DataConstant(DirectHandle<Name> key, DirectHandle<Object> value, PropertyAttributes attributes) { - auto [representation, constness] = - Object::OptimalRepresentation(*value, PropertyConstness::kConst); return Descriptor(key, MaybeObjectDirectHandle(value), PropertyKind::kData, - attributes, PropertyLocation::kDescriptor, constness, - representation, 0, false); + attributes, PropertyLocation::kDescriptor, + PropertyConstness::kConst, + Object::OptimalRepresentation(*value), 0, false); } Descriptor Descriptor::AccessorConstant(DirectHandle<Name> key, diff --git a/deps/v8/src/objects/prototype-info-inl.h b/deps/v8/src/objects/prototype-info-inl.h index eacf6bcfd881..be329f588257 100644 --- a/deps/v8/src/objects/prototype-info-inl.h +++ b/deps/v8/src/objects/prototype-info-inl.h @@ -22,6 +22,20 @@ namespace v8 { namespace internal { +PrototypeInfo::PrototypeInfo(const AllocationWitness& witness) + : Struct(witness.roots().prototype_info_map()), + module_namespace_(witness.roots().undefined_value()), + prototype_users_(Smi::zero()), + prototype_chain_enum_cache_(witness.roots().undefined_value()), + registry_slot_(Smi::FromInt(UNREGISTERED)), + bit_field_(Smi::zero()), + derived_maps_(witness.roots().undefined_value()), + prototype_shared_closure_info_(witness.roots().undefined_value()) { + for (int i = 0; i < kCachedHandlerCount; i++) { + cached_handler_[i].store_no_write_barrier(Smi::zero()); + } +} + Tagged<UnionOf<JSModuleNamespace, Undefined>> PrototypeInfo::module_namespace() const { return module_namespace_.load(); diff --git a/deps/v8/src/objects/prototype-info.h b/deps/v8/src/objects/prototype-info.h index e89c7753126e..dfad726542b9 100644 --- a/deps/v8/src/objects/prototype-info.h +++ b/deps/v8/src/objects/prototype-info.h @@ -21,6 +21,8 @@ class PrototypeSharedClosureInfo; // Container for metadata stored on each prototype map. V8_OBJECT class PrototypeInfo : public Struct { public: + inline explicit PrototypeInfo(const AllocationWitness& witness); + // Accessors inline Tagged<UnionOf<JSModuleNamespace, Undefined>> module_namespace() const; inline void set_module_namespace( @@ -102,11 +104,12 @@ V8_OBJECT class PrototypeInfo : public Struct { TaggedMember<UnionOf<FixedArray, Zero, Undefined>> prototype_chain_enum_cache_; TaggedMember<Smi> registry_slot_; - TaggedMember<Smi> bit_field_; + TaggedMember<Smi> bit_field_ V8_TQ_TYPE(SmiTagged<PrototypeInfoFlags>); TaggedMember<UnionOf<WeakArrayList, Undefined>> derived_maps_; TaggedMember<UnionOf<PrototypeSharedClosureInfo, Undefined>> prototype_shared_closure_info_; - TaggedMember<UnionOf<LoadHandler, Zero>> cached_handler_[kCachedHandlerCount]; + TaggedMember<UnionOf<LoadHandler, Zero>> cached_handler_ + V8_TQ_EXTENT_NAME(kPrototypeInfoCachedHandlerCount)[kCachedHandlerCount]; } V8_OBJECT_END; // A growing array with an additional API for marking slots "empty". When adding diff --git a/deps/v8/src/objects/regexp-match-info.h b/deps/v8/src/objects/regexp-match-info.h index 76a621aaf3db..02d4c44b4c0a 100644 --- a/deps/v8/src/objects/regexp-match-info.h +++ b/deps/v8/src/objects/regexp-match-info.h @@ -80,6 +80,7 @@ V8_OBJECT class RegExpMatchInfo TaggedMember<Smi> number_of_capture_registers_; TaggedMember<String> last_subject_; TaggedMember<Object> last_input_; + V8_TQ_TAIL_LENGTH(length); FLEXIBLE_ARRAY_MEMBER(typename Super::ElementMemberT, objects); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/scope-info-inl.h b/deps/v8/src/objects/scope-info-inl.h index d4d690e17d94..b64cdf727b1e 100644 --- a/deps/v8/src/objects/scope-info-inl.h +++ b/deps/v8/src/objects/scope-info-inl.h @@ -25,29 +25,27 @@ namespace v8 { namespace internal { bool ScopeInfo::HasSimpleParameters() const { - return HasSimpleParametersBit::decode(Flags()); + return flags().has_simple_parameters(); } -bool ScopeInfo::HasContextCells() const { - return HasContextCellsBit::decode(Flags()); -} +bool ScopeInfo::HasContextCells() const { return flags().has_context_cells(); } bool ScopeInfo::is_hoisted_in_context() const { - return IsHoistedInContextBit::decode(Flags()); + return flags().is_hoisted_in_context(); } -uint32_t ScopeInfo::Flags() const { return flags(kRelaxedLoad); } +ScopeInfo::Flags ScopeInfo::flags() const { return flags(kRelaxedLoad); } int ScopeInfo::ParameterCount() const { return parameter_count(); } int ScopeInfo::ContextLocalCount() const { return context_local_count(); } // ----------------------------------------------------------------------- // Named field accessors. -uint32_t ScopeInfo::flags(RelaxedLoadTag) const { +ScopeInfo::Flags ScopeInfo::flags(RelaxedLoadTag) const { return flags_.load(std::memory_order_relaxed); } -void ScopeInfo::set_flags(uint32_t value, RelaxedStoreTag) { +void ScopeInfo::set_flags(Flags value, RelaxedStoreTag) { flags_.store(value, std::memory_order_relaxed); } @@ -68,19 +66,19 @@ void ScopeInfo::set_context_local_count(int value) { } int ScopeInfo::position_info_start() const { - return position_info_start_.load().value(); + return position_info_.start_.load().value(); } void ScopeInfo::set_position_info_start(int value) { - position_info_start_.store(this, Smi::FromInt(value)); + position_info_.start_.store(this, Smi::FromInt(value)); } int ScopeInfo::position_info_end() const { - return position_info_end_.load().value(); + return position_info_.end_.load().value(); } void ScopeInfo::set_position_info_end(int value) { - position_info_end_.store(this, Smi::FromInt(value)); + position_info_.end_.store(this, Smi::FromInt(value)); } // ----------------------------------------------------------------------- @@ -89,6 +87,7 @@ void ScopeInfo::set_position_info_end(int value) { // (context_local_count, module_variable_count). Each returned offset is // the byte offset from the start of the object. +// LINT.IfChange(ContextLocalOffsets) int ScopeInfo::ModuleVariableCountOffset() const { // ModuleVariableCount is the first slot of the variable tail. It's // always at OFFSET_OF_DATA_START(ScopeInfo) regardless of whether the @@ -97,8 +96,7 @@ int ScopeInfo::ModuleVariableCountOffset() const { } int ScopeInfo::ContextLocalNamesOffset() const { - const bool is_module = - ScopeTypeBits::decode(Flags()) == ScopeType::MODULE_SCOPE; + const bool is_module = flags().scope_type() == ScopeType::MODULE_SCOPE; return ModuleVariableCountOffset() + (is_module ? kTaggedSize : 0); } @@ -114,44 +112,42 @@ int ScopeInfo::ContextLocalInfosOffset() const { const bool has_hashtable = local_count >= kScopeInfoMaxInlinedLocalNamesSize; return ContextLocalNamesHashtableOffset() + (has_hashtable ? kTaggedSize : 0); } +// LINT.ThenChange(/src/codegen/code-stub-assembler.cc:ScopeInfoContextLocalOffsets) int ScopeInfo::SavedClassVariableInfoOffset() const { return ContextLocalInfosOffset() + context_local_count() * kTaggedSize; } int ScopeInfo::FunctionVariableInfoOffset() const { - const bool has_saved_class_variable = - HasSavedClassVariableBit::decode(Flags()); + const bool has_saved_class_variable = flags().has_saved_class_variable(); return SavedClassVariableInfoOffset() + (has_saved_class_variable ? kTaggedSize : 0); } int ScopeInfo::InferredFunctionNameOffset() const { const bool has_function_variable = - FunctionVariableBits::decode(Flags()) != VariableAllocationInfo::NONE; + flags().function_variable() != VariableAllocationInfo::NONE; return FunctionVariableInfoOffset() + (has_function_variable ? sizeof(FunctionVariableInfo) : 0); } int ScopeInfo::OuterScopeInfoOffset() const { - const bool has_inferred_name = HasInferredFunctionNameBit::decode(Flags()); + const bool has_inferred_name = flags().has_inferred_function_name(); return InferredFunctionNameOffset() + (has_inferred_name ? kTaggedSize : 0); } int ScopeInfo::ModuleInfoOffset() const { - const bool has_outer = HasOuterScopeInfoBit::decode(Flags()); + const bool has_outer = flags().has_outer_scope_info(); return OuterScopeInfoOffset() + (has_outer ? kTaggedSize : 0); } int ScopeInfo::ModuleVariablesOffset() const { - const bool is_module = - ScopeTypeBits::decode(Flags()) == ScopeType::MODULE_SCOPE; + const bool is_module = flags().scope_type() == ScopeType::MODULE_SCOPE; return ModuleInfoOffset() + (is_module ? kTaggedSize : 0); } int ScopeInfo::ModuleVariablesHashtableOffset() const { - const bool is_module = - ScopeTypeBits::decode(Flags()) == ScopeType::MODULE_SCOPE; + const bool is_module = flags().scope_type() == ScopeType::MODULE_SCOPE; const int mod_var_count = is_module ? module_variable_count() : 0; return ModuleVariablesOffset() + mod_var_count * sizeof(ModuleVariableInfo); } @@ -162,13 +158,12 @@ int ScopeInfo::DependentCodeOffset() const { } int ScopeInfo::UnusedParameterBitsOffset() const { - const bool has_dependent_code = SloppyEvalCanExtendVarsBit::decode(Flags()); + const bool has_dependent_code = flags().sloppy_eval_can_extend_vars(); return DependentCodeOffset() + (has_dependent_code ? kTaggedSize : 0); } int ScopeInfo::AllocatedSize() const { - const bool is_function = - ScopeTypeBits::decode(Flags()) == ScopeType::FUNCTION_SCOPE; + const bool is_function = flags().scope_type() == ScopeType::FUNCTION_SCOPE; return UnusedParameterBitsOffset() + (is_function ? kTaggedSize : 0); } @@ -185,12 +180,12 @@ constexpr int DataSlotIndex(int byte_offset) { int ScopeInfo::module_variable_count() const { // Only valid when scope_type == MODULE_SCOPE. - DCHECK_EQ(ScopeTypeBits::decode(Flags()), ScopeType::MODULE_SCOPE); + DCHECK_EQ(flags().scope_type(), ScopeType::MODULE_SCOPE); return Cast<Smi>(data()[0].load()).value(); } void ScopeInfo::set_module_variable_count(int value) { - DCHECK_EQ(ScopeTypeBits::decode(Flags()), ScopeType::MODULE_SCOPE); + DCHECK_EQ(flags().scope_type(), ScopeType::MODULE_SCOPE); data()[0].store(this, Smi::FromInt(value)); } @@ -245,7 +240,7 @@ void ScopeInfo::set_context_local_infos(int i, int value) { } Tagged<Union<Name, Smi>> ScopeInfo::saved_class_variable_info() const { - DCHECK(HasSavedClassVariableBit::decode(Flags())); + DCHECK(flags().has_saved_class_variable()); const int slot = scope_info_internal::DataSlotIndex(SavedClassVariableInfoOffset()); return Cast<Union<Name, Smi>>(data()[slot].load()); @@ -253,15 +248,14 @@ Tagged<Union<Name, Smi>> ScopeInfo::saved_class_variable_info() const { void ScopeInfo::set_saved_class_variable_info(Tagged<Union<Name, Smi>> value, WriteBarrierMode mode) { - DCHECK(HasSavedClassVariableBit::decode(Flags())); + DCHECK(flags().has_saved_class_variable()); const int slot = scope_info_internal::DataSlotIndex(SavedClassVariableInfoOffset()); data()[slot].store(this, value, mode); } Tagged<Union<Smi, String>> ScopeInfo::function_variable_info_name() const { - DCHECK_NE(FunctionVariableBits::decode(Flags()), - VariableAllocationInfo::NONE); + DCHECK_NE(flags().function_variable(), VariableAllocationInfo::NONE); const int slot = scope_info_internal::DataSlotIndex( FunctionVariableInfoOffset() + offsetof(FunctionVariableInfo, name)); return Cast<Union<Smi, String>>(data()[slot].load()); @@ -269,16 +263,14 @@ Tagged<Union<Smi, String>> ScopeInfo::function_variable_info_name() const { void ScopeInfo::set_function_variable_info_name( Tagged<Union<Smi, String>> value, WriteBarrierMode mode) { - DCHECK_NE(FunctionVariableBits::decode(Flags()), - VariableAllocationInfo::NONE); + DCHECK_NE(flags().function_variable(), VariableAllocationInfo::NONE); const int slot = scope_info_internal::DataSlotIndex( FunctionVariableInfoOffset() + offsetof(FunctionVariableInfo, name)); data()[slot].store(this, value, mode); } int ScopeInfo::function_variable_info_context_or_stack_slot_index() const { - DCHECK_NE(FunctionVariableBits::decode(Flags()), - VariableAllocationInfo::NONE); + DCHECK_NE(flags().function_variable(), VariableAllocationInfo::NONE); const int slot = scope_info_internal::DataSlotIndex( FunctionVariableInfoOffset() + offsetof(FunctionVariableInfo, context_or_stack_slot_index)); @@ -287,8 +279,7 @@ int ScopeInfo::function_variable_info_context_or_stack_slot_index() const { void ScopeInfo::set_function_variable_info_context_or_stack_slot_index( int value) { - DCHECK_NE(FunctionVariableBits::decode(Flags()), - VariableAllocationInfo::NONE); + DCHECK_NE(flags().function_variable(), VariableAllocationInfo::NONE); const int slot = scope_info_internal::DataSlotIndex( FunctionVariableInfoOffset() + offsetof(FunctionVariableInfo, context_or_stack_slot_index)); @@ -296,7 +287,7 @@ void ScopeInfo::set_function_variable_info_context_or_stack_slot_index( } Tagged<Union<String, Undefined>> ScopeInfo::inferred_function_name() const { - DCHECK(HasInferredFunctionNameBit::decode(Flags())); + DCHECK(flags().has_inferred_function_name()); const int slot = scope_info_internal::DataSlotIndex(InferredFunctionNameOffset()); return Cast<Union<String, Undefined>>(data()[slot].load()); @@ -304,34 +295,34 @@ Tagged<Union<String, Undefined>> ScopeInfo::inferred_function_name() const { void ScopeInfo::set_inferred_function_name( Tagged<Union<String, Undefined>> value, WriteBarrierMode mode) { - DCHECK(HasInferredFunctionNameBit::decode(Flags())); + DCHECK(flags().has_inferred_function_name()); const int slot = scope_info_internal::DataSlotIndex(InferredFunctionNameOffset()); data()[slot].store(this, value, mode); } Tagged<ScopeInfo> ScopeInfo::outer_scope_info() const { - DCHECK(HasOuterScopeInfoBit::decode(Flags())); + DCHECK(flags().has_outer_scope_info()); const int slot = scope_info_internal::DataSlotIndex(OuterScopeInfoOffset()); return Cast<ScopeInfo>(data()[slot].load()); } void ScopeInfo::set_outer_scope_info(Tagged<ScopeInfo> value, WriteBarrierMode mode) { - DCHECK(HasOuterScopeInfoBit::decode(Flags())); + DCHECK(flags().has_outer_scope_info()); const int slot = scope_info_internal::DataSlotIndex(OuterScopeInfoOffset()); data()[slot].store(this, value, mode); } Tagged<FixedArray> ScopeInfo::module_info() const { - DCHECK_EQ(ScopeTypeBits::decode(Flags()), ScopeType::MODULE_SCOPE); + DCHECK_EQ(flags().scope_type(), ScopeType::MODULE_SCOPE); const int slot = scope_info_internal::DataSlotIndex(ModuleInfoOffset()); return Cast<FixedArray>(data()[slot].load()); } void ScopeInfo::set_module_info(Tagged<FixedArray> value, WriteBarrierMode mode) { - DCHECK_EQ(ScopeTypeBits::decode(Flags()), ScopeType::MODULE_SCOPE); + DCHECK_EQ(flags().scope_type(), ScopeType::MODULE_SCOPE); const int slot = scope_info_internal::DataSlotIndex(ModuleInfoOffset()); data()[slot].store(this, value, mode); } @@ -392,7 +383,7 @@ void ScopeInfo::set_module_variables_properties(int i, int value) { } bool ScopeInfo::HasModuleVariablesHashtable() const { - return ScopeTypeBits::decode(Flags()) == ScopeType::MODULE_SCOPE && + return flags().scope_type() == ScopeType::MODULE_SCOPE && module_variable_count() >= kScopeInfoMaxInlinedLocalNamesSize; } @@ -412,27 +403,27 @@ void ScopeInfo::set_module_variables_hashtable( } Tagged<DependentCode> ScopeInfo::dependent_code() const { - DCHECK(SloppyEvalCanExtendVarsBit::decode(Flags())); + DCHECK(flags().sloppy_eval_can_extend_vars()); const int slot = scope_info_internal::DataSlotIndex(DependentCodeOffset()); return Cast<DependentCode>(data()[slot].load()); } void ScopeInfo::set_dependent_code(Tagged<DependentCode> value, WriteBarrierMode mode) { - DCHECK(SloppyEvalCanExtendVarsBit::decode(Flags())); + DCHECK(flags().sloppy_eval_can_extend_vars()); const int slot = scope_info_internal::DataSlotIndex(DependentCodeOffset()); data()[slot].store(this, value, mode); } uint32_t ScopeInfo::unused_parameter_bits() const { - DCHECK_EQ(ScopeTypeBits::decode(Flags()), ScopeType::FUNCTION_SCOPE); + DCHECK_EQ(flags().scope_type(), ScopeType::FUNCTION_SCOPE); const int slot = scope_info_internal::DataSlotIndex(UnusedParameterBitsOffset()); return Smi::To31BitPattern(data()[slot].load()); } void ScopeInfo::set_unused_parameter_bits(uint32_t value) { - DCHECK_EQ(ScopeTypeBits::decode(Flags()), ScopeType::FUNCTION_SCOPE); + DCHECK_EQ(flags().scope_type(), ScopeType::FUNCTION_SCOPE); const int slot = scope_info_internal::DataSlotIndex(UnusedParameterBitsOffset()); data()[slot].store(this, Smi::From31BitPattern(static_cast<int>(value))); diff --git a/deps/v8/src/objects/scope-info.cc b/deps/v8/src/objects/scope-info.cc index 4986c640a57f..864513bef97a 100644 --- a/deps/v8/src/objects/scope-info.cc +++ b/deps/v8/src/objects/scope-info.cc @@ -11,10 +11,13 @@ #include "src/ast/scopes.h" #include "src/ast/variables.h" +#include "src/heap/factory-inl.h" +#include "src/heap/local-factory-inl.h" #include "src/init/bootstrapper.h" #include "src/objects/module-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/scope-info-inl.h" +#include "src/objects/source-text-module-inl.h" #include "src/objects/string-set-inl.h" #include "src/roots/roots.h" @@ -51,7 +54,7 @@ bool ScopeInfo::Equals(Tagged<ScopeInfo> other, int* out_last_checked_field) const { if (length() != other->length()) return false; // Fixed header fields. - if (Flags() != other->Flags()) return false; + if (flags() != other->flags()) return false; if (out_last_checked_field) *out_last_checked_field = kFlags; if (parameter_count() != other->parameter_count()) return false; if (out_last_checked_field) *out_last_checked_field = kParameterCount; @@ -271,30 +274,30 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope, } // Encode the flags. - uint32_t flags = - ScopeTypeBits::encode(scope->scope_type()) | - SloppyEvalCanExtendVarsBit::encode(sloppy_eval_can_extend_vars) | - LanguageModeBit::encode(scope->language_mode()) | - DeclarationScopeBit::encode(scope->is_declaration_scope()) | - ReceiverVariableBits::encode(receiver_info) | - ClassScopeHasPrivateBrandBit::encode(has_brand) | - HasSavedClassVariableBit::encode(should_save_class_variable) | - AllocatesArgumentsBit::encode(allocates_arguments) | - FunctionVariableBits::encode(function_name_info) | - HasInferredFunctionNameBit::encode(has_inferred_function_name) | - HasSimpleParametersBit::encode(has_simple_parameters) | - FunctionKindBits::encode(function_kind) | - HasOuterScopeInfoBit::encode(has_outer_scope_info) | - IsDebugEvaluateScopeBit::encode(false) | - ForceContextAllocationBit::encode( - scope->ForceContextForLanguageMode()) | - PrivateNameLookupSkipsOuterClassBit::encode( - scope->private_name_lookup_skips_outer_class()) | - HasContextExtensionSlotBit::encode(scope->HasContextExtensionSlot()) | - IsHiddenBit::encode(scope->is_hidden()) | - IsWrappedFunctionBit::encode(scope->is_wrapped_function()) | - HasContextCellsBit::encode(scope->has_context_cells()) | - IsHoistedInContextBit::encode(scope->is_hoisted_in_context()); + const Flags flags = + Flags{} + .with_scope_type(scope->scope_type()) + .with_sloppy_eval_can_extend_vars(sloppy_eval_can_extend_vars) + .with_language_mode(scope->language_mode()) + .with_declaration_scope(scope->is_declaration_scope()) + .with_receiver_variable(receiver_info) + .with_class_scope_has_private_brand(has_brand) + .with_has_saved_class_variable(should_save_class_variable) + .with_allocates_arguments(allocates_arguments) + .with_function_variable(function_name_info) + .with_has_inferred_function_name(has_inferred_function_name) + .with_has_simple_parameters(has_simple_parameters) + .with_function_kind(function_kind) + .with_has_outer_scope_info(has_outer_scope_info) + .with_is_debug_evaluate_scope(false) + .with_force_context_allocation(scope->ForceContextForLanguageMode()) + .with_private_name_lookup_skips_outer_class( + scope->private_name_lookup_skips_outer_class()) + .with_has_context_extension_slot(scope->HasContextExtensionSlot()) + .with_is_hidden(scope->is_hidden()) + .with_is_wrapped_function(scope->is_wrapped_function()) + .with_has_context_cells(scope->has_context_cells()) + .with_is_hoisted_in_context(scope->is_hoisted_in_context()); scope_info->set_flags(flags, kRelaxedStore); scope_info->set_parameter_count(parameter_count); @@ -533,25 +536,26 @@ DirectHandle<ScopeInfo> ScopeInfo::CreateForWithScope( DirectHandle<ScopeInfo> scope_info = factory->NewScopeInfo(length); // Encode the flags. - uint32_t flags = ScopeTypeBits::encode(WITH_SCOPE) | - SloppyEvalCanExtendVarsBit::encode(false) | - LanguageModeBit::encode(LanguageMode::kSloppy) | - DeclarationScopeBit::encode(false) | - ReceiverVariableBits::encode(VariableAllocationInfo::NONE) | - ClassScopeHasPrivateBrandBit::encode(false) | - HasSavedClassVariableBit::encode(false) | - AllocatesArgumentsBit::encode(false) | - FunctionVariableBits::encode(VariableAllocationInfo::NONE) | - HasSimpleParametersBit::encode(true) | - FunctionKindBits::encode(FunctionKind::kNormalFunction) | - HasOuterScopeInfoBit::encode(has_outer_scope_info) | - IsDebugEvaluateScopeBit::encode(false) | - ForceContextAllocationBit::encode(false) | - PrivateNameLookupSkipsOuterClassBit::encode(false) | - HasContextExtensionSlotBit::encode(true) | - IsHiddenBit::encode(false) | - IsWrappedFunctionBit::encode(false) | - IsHoistedInContextBit::encode(false); + const Flags flags = Flags{} + .with_scope_type(WITH_SCOPE) + .with_sloppy_eval_can_extend_vars(false) + .with_language_mode(LanguageMode::kSloppy) + .with_declaration_scope(false) + .with_receiver_variable(VariableAllocationInfo::NONE) + .with_class_scope_has_private_brand(false) + .with_has_saved_class_variable(false) + .with_allocates_arguments(false) + .with_function_variable(VariableAllocationInfo::NONE) + .with_has_simple_parameters(true) + .with_function_kind(FunctionKind::kNormalFunction) + .with_has_outer_scope_info(has_outer_scope_info) + .with_is_debug_evaluate_scope(false) + .with_force_context_allocation(false) + .with_private_name_lookup_skips_outer_class(false) + .with_has_context_extension_slot(true) + .with_is_hidden(false) + .with_is_wrapped_function(false) + .with_is_hoisted_in_context(false); scope_info->set_flags(flags, kRelaxedStore); scope_info->set_parameter_count(0); @@ -591,8 +595,8 @@ DirectHandle<ScopeInfo> ScopeInfo::CreateForEmptyFunction(Isolate* isolate) { // set to true for all function scopes with the number of context locals (in // this case zero) below the threshold // v8_flags.function_context_cells_max_size. - scope_info->set_flags( - scope_info->Flags() | HasContextCellsBit::encode(true), kRelaxedStore); + scope_info->set_flags(scope_info->flags().with_has_context_cells(true), + kRelaxedStore); } return scope_info; } @@ -632,34 +636,37 @@ DirectHandle<ScopeInfo> ScopeInfo::CreateForBootstrapping( DisallowGarbageCollection _nogc; // Encode the flags. DCHECK_IMPLIES(is_shadow_realm || is_script, !is_empty_function); - uint32_t flags = - ScopeTypeBits::encode( - is_empty_function - ? FUNCTION_SCOPE - : (is_shadow_realm ? SHADOW_REALM_SCOPE : SCRIPT_SCOPE)) | - SloppyEvalCanExtendVarsBit::encode(false) | - LanguageModeBit::encode(LanguageMode::kSloppy) | - DeclarationScopeBit::encode(true) | - ReceiverVariableBits::encode(is_script ? VariableAllocationInfo::CONTEXT - : VariableAllocationInfo::UNUSED) | - ClassScopeHasPrivateBrandBit::encode(false) | - HasSavedClassVariableBit::encode(false) | - // We don't know the value of this flag, so set defensively. - AllocatesArgumentsBit::encode(type == BootstrappingType::kFunction && - !is_empty_function) | - FunctionVariableBits::encode(is_empty_function - ? VariableAllocationInfo::UNUSED - : VariableAllocationInfo::NONE) | - HasInferredFunctionNameBit::encode(has_inferred_function_name) | - HasSimpleParametersBit::encode(true) | - FunctionKindBits::encode(FunctionKind::kNormalFunction) | - HasOuterScopeInfoBit::encode(false) | - IsDebugEvaluateScopeBit::encode(false) | - ForceContextAllocationBit::encode(false) | - PrivateNameLookupSkipsOuterClassBit::encode(false) | - HasContextExtensionSlotBit::encode(is_native_context) | - IsHiddenBit::encode(false) | IsWrappedFunctionBit::encode(false) | - HasContextCellsBit::encode(false) | IsHoistedInContextBit::encode(false); + const Flags flags = + Flags{} + .with_scope_type( + is_empty_function + ? FUNCTION_SCOPE + : (is_shadow_realm ? SHADOW_REALM_SCOPE : SCRIPT_SCOPE)) + .with_sloppy_eval_can_extend_vars(false) + .with_language_mode(LanguageMode::kSloppy) + .with_declaration_scope(true) + .with_receiver_variable(is_script ? VariableAllocationInfo::CONTEXT + : VariableAllocationInfo::UNUSED) + .with_class_scope_has_private_brand(false) + .with_has_saved_class_variable(false) + // We don't know the value of this flag, so set defensively. + .with_allocates_arguments(type == BootstrappingType::kFunction && + !is_empty_function) + .with_function_variable(is_empty_function + ? VariableAllocationInfo::UNUSED + : VariableAllocationInfo::NONE) + .with_has_inferred_function_name(has_inferred_function_name) + .with_has_simple_parameters(true) + .with_function_kind(FunctionKind::kNormalFunction) + .with_has_outer_scope_info(false) + .with_is_debug_evaluate_scope(false) + .with_force_context_allocation(false) + .with_private_name_lookup_skips_outer_class(false) + .with_has_context_extension_slot(is_native_context) + .with_is_hidden(false) + .with_is_wrapped_function(false) + .with_has_context_cells(false) + .with_is_hoisted_in_context(false); Tagged<ScopeInfo> raw_scope_info = *scope_info; raw_scope_info->set_flags(flags, kRelaxedStore); raw_scope_info->set_parameter_count(parameter_count); @@ -766,7 +773,7 @@ bool ScopeInfo::IsEmpty() const { ScopeType ScopeInfo::scope_type() const { DCHECK(!this->IsEmpty()); - return ScopeTypeBits::decode(Flags()); + return flags().scope_type(); } bool ScopeInfo::is_script_scope() const { @@ -774,25 +781,24 @@ bool ScopeInfo::is_script_scope() const { } bool ScopeInfo::SloppyEvalCanExtendVars() const { - bool sloppy_eval_can_extend_vars = - SloppyEvalCanExtendVarsBit::decode(Flags()); + bool sloppy_eval_can_extend_vars = flags().sloppy_eval_can_extend_vars(); DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_sloppy(language_mode())); DCHECK_IMPLIES(sloppy_eval_can_extend_vars, is_declaration_scope()); return sloppy_eval_can_extend_vars; } LanguageMode ScopeInfo::language_mode() const { - return LanguageModeBit::decode(Flags()); + return flags().language_mode(); } bool ScopeInfo::is_declaration_scope() const { - return DeclarationScopeBit::decode(Flags()); + return flags().declaration_scope(); } int ScopeInfo::ContextLength() const { int context_locals = ContextLocalCount(); bool function_name_context_slot = HasContextAllocatedFunctionName(); - bool force_context = ForceContextAllocationBit::decode(Flags()); + bool force_context = flags().force_context_allocation(); bool has_context = context_locals > 0 || force_context || function_name_context_slot || scope_type() == WITH_SCOPE || scope_type() == CLASS_SCOPE || @@ -826,15 +832,15 @@ int ScopeInfo::UniqueIdInScript() const { } bool ScopeInfo::HasContextExtensionSlot() const { - return HasContextExtensionSlotBit::decode(Flags()); + return flags().has_context_extension_slot(); } bool ScopeInfo::SomeContextHasExtension() const { - return SomeContextHasExtensionBit::decode(Flags()); + return flags().some_context_has_extension(); } void ScopeInfo::mark_some_context_has_extension() { - set_flags(SomeContextHasExtensionBit::update(Flags(), true), kRelaxedStore); + set_flags(flags().with_some_context_has_extension(true), kRelaxedStore); } int ScopeInfo::ContextHeaderLength() const { @@ -843,7 +849,7 @@ int ScopeInfo::ContextHeaderLength() const { } bool ScopeInfo::HasReceiver() const { - return VariableAllocationInfo::NONE != ReceiverVariableBits::decode(Flags()); + return VariableAllocationInfo::NONE != flags().receiver_variable(); } bool ScopeInfo::HasAllocatedReceiver() const { @@ -856,18 +862,18 @@ bool ScopeInfo::HasAllocatedReceiver() const { // 2. The scope is created as a debug evaluate scope, so this is not // an actual reparse, we are not sure if the inner scope will access // this, but the receiver should be allocated just in case. - VariableAllocationInfo allocation = ReceiverVariableBits::decode(Flags()); + VariableAllocationInfo allocation = flags().receiver_variable(); return allocation == VariableAllocationInfo::STACK || allocation == VariableAllocationInfo::CONTEXT || IsDebugEvaluateScope(); } bool ScopeInfo::ClassScopeHasPrivateBrand() const { - return ClassScopeHasPrivateBrandBit::decode(Flags()); + return flags().class_scope_has_private_brand(); } bool ScopeInfo::HasSavedClassVariable() const { - return HasSavedClassVariableBit::decode(Flags()); + return flags().has_saved_class_variable(); } bool ScopeInfo::IsSloppyNormalJSFunction() const { @@ -888,22 +894,21 @@ bool ScopeInfo::CanOnlyAccessFixedFormalParameters() const { function_kind == FunctionKind::kArrowFunction) && // Can't have arguments allocated in the frame for any reason since this // indicates potential reachability. - !AllocatesArgumentsBit::decode(Flags()) && + !flags().allocates_arguments() && // Can't have rest parameters. HasSimpleParameters(); } bool ScopeInfo::HasFunctionName() const { - return VariableAllocationInfo::NONE != FunctionVariableBits::decode(Flags()); + return VariableAllocationInfo::NONE != flags().function_variable(); } bool ScopeInfo::HasContextAllocatedFunctionName() const { - return VariableAllocationInfo::CONTEXT == - FunctionVariableBits::decode(Flags()); + return VariableAllocationInfo::CONTEXT == flags().function_variable(); } bool ScopeInfo::HasInferredFunctionName() const { - return HasInferredFunctionNameBit::decode(Flags()); + return flags().has_inferred_function_name(); } bool ScopeInfo::HasSharedFunctionName() const { @@ -923,21 +928,21 @@ void ScopeInfo::SetInferredFunctionName(Tagged<String> name) { } bool ScopeInfo::HasOuterScopeInfo() const { - return HasOuterScopeInfoBit::decode(Flags()); + return flags().has_outer_scope_info(); } bool ScopeInfo::IsDebugEvaluateScope() const { - return IsDebugEvaluateScopeBit::decode(Flags()); + return flags().is_debug_evaluate_scope(); } void ScopeInfo::SetIsDebugEvaluateScope() { CHECK(!this->IsEmpty()); DCHECK_EQ(scope_type(), WITH_SCOPE); - set_flags(Flags() | IsDebugEvaluateScopeBit::encode(true), kRelaxedStore); + set_flags(flags().with_is_debug_evaluate_scope(true), kRelaxedStore); } bool ScopeInfo::PrivateNameLookupSkipsOuterClass() const { - return PrivateNameLookupSkipsOuterClassBit::decode(Flags()); + return flags().private_name_lookup_skips_outer_class(); } bool ScopeInfo::IsReplModeScope() const { @@ -945,9 +950,8 @@ bool ScopeInfo::IsReplModeScope() const { } bool ScopeInfo::IsWrappedFunctionScope() const { - DCHECK_IMPLIES(IsWrappedFunctionBit::decode(Flags()), - scope_type() == FUNCTION_SCOPE); - return IsWrappedFunctionBit::decode(Flags()); + DCHECK_IMPLIES(flags().is_wrapped_function(), scope_type() == FUNCTION_SCOPE); + return flags().is_wrapped_function(); } bool ScopeInfo::HasContext() const { return ContextLength() > 0; } @@ -1146,7 +1150,7 @@ int ScopeInfo::ContextSlotIndex(Tagged<String> name) { } std::pair<Tagged<String>, int> ScopeInfo::SavedClassVariable() const { - DCHECK(HasSavedClassVariableBit::decode(Flags())); + DCHECK(flags().has_saved_class_variable()); auto class_variable_info = saved_class_variable_info(); if (HasInlinedLocalNames()) { // The saved class variable info corresponds to the context slot index. @@ -1169,16 +1173,14 @@ std::pair<Tagged<String>, int> ScopeInfo::SavedClassVariable() const { } int ScopeInfo::ReceiverContextSlotIndex() const { - if (ReceiverVariableBits::decode(Flags()) == - VariableAllocationInfo::CONTEXT) { + if (flags().receiver_variable() == VariableAllocationInfo::CONTEXT) { return ContextHeaderLength(); } return -1; } int ScopeInfo::ParametersStartIndex() const { - if (ReceiverVariableBits::decode(Flags()) == - VariableAllocationInfo::CONTEXT) { + if (flags().receiver_variable() == VariableAllocationInfo::CONTEXT) { return ContextHeaderLength() + 1; } return ContextHeaderLength(); @@ -1203,7 +1205,7 @@ int ScopeInfo::FunctionContextSlotIndex(Tagged<String> name) const { } FunctionKind ScopeInfo::function_kind() const { - return FunctionKindBits::decode(Flags()); + return flags().function_kind(); } int ScopeInfo::ContextLocalNamesIndex() const { @@ -1314,18 +1316,10 @@ template <typename IsolateT> Handle<ModuleRequest> ModuleRequest::New( IsolateT* isolate, DirectHandle<String> specifier, ModuleImportPhase phase, DirectHandle<FixedArray> import_attributes, int position) { - auto result = Cast<ModuleRequest>( - isolate->factory()->NewStruct(MODULE_REQUEST_TYPE, AllocationType::kOld)); - DisallowGarbageCollection no_gc; - Tagged<ModuleRequest> raw = *result; - raw->set_specifier(*specifier); - raw->set_import_attributes(*import_attributes); - raw->set_flags(0); - - raw->set_phase(phase); - DCHECK_GE(position, 0); - raw->set_position(position); - return result; + return indirect_handle( + isolate->factory()->template New<ModuleRequest, AllocationType::kOld>( + specifier, phase, import_attributes, position), + isolate); } template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) @@ -1345,18 +1339,12 @@ Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New( DirectHandle<UnionOf<String, Undefined>> local_name, DirectHandle<UnionOf<String, Undefined>> import_name, int module_request, int cell_index, int beg_pos, int end_pos) { - auto result = Cast<SourceTextModuleInfoEntry>(isolate->factory()->NewStruct( - SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, AllocationType::kOld)); - DisallowGarbageCollection no_gc; - Tagged<SourceTextModuleInfoEntry> raw = *result; - raw->set_export_name(*export_name); - raw->set_local_name(*local_name); - raw->set_import_name(*import_name); - raw->set_module_request(module_request); - raw->set_cell_index(cell_index); - raw->set_beg_pos(beg_pos); - raw->set_end_pos(end_pos); - return result; + return indirect_handle( + isolate->factory() + ->template New<SourceTextModuleInfoEntry, AllocationType::kOld>( + export_name, local_name, import_name, module_request, cell_index, + beg_pos, end_pos), + isolate); } template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) diff --git a/deps/v8/src/objects/scope-info.h b/deps/v8/src/objects/scope-info.h index e4e517439067..c4a101f5ca44 100644 --- a/deps/v8/src/objects/scope-info.h +++ b/deps/v8/src/objects/scope-info.h @@ -7,6 +7,7 @@ #include "src/base/bit-field.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/dependent-code.h" #include "src/objects/fixed-array.h" #include "src/objects/function-kind.h" @@ -44,7 +45,8 @@ struct VariableLookupResult { int initializer_position; }; -// LINT.IfChange(ScopeInfoStructs) +// Layout of the function_variable_info / module_variables sections of the +// ScopeInfo tail (see the layout comment at the end of the class). struct FunctionVariableInfo { TaggedMember<Object> name; TaggedMember<Smi> context_or_stack_slot_index; @@ -55,7 +57,6 @@ struct ModuleVariableInfo { TaggedMember<Smi> index; TaggedMember<Smi> properties; }; -// LINT.ThenChange(src/objects/scope-info.tq) // ScopeInfo represents information about different scopes of a source // program and the allocation of the scope's variables. Scope information @@ -66,33 +67,69 @@ struct ModuleVariableInfo { // routines. V8_OBJECT class ScopeInfo : public HeapObject { public: - // Bit positions in |flags|. - using ScopeTypeBits = base::BitField<ScopeType, 0, 4, uint32_t>; - using SloppyEvalCanExtendVarsBit = ScopeTypeBits::Next<bool, 1>; - using LanguageModeBit = SloppyEvalCanExtendVarsBit::Next<LanguageMode, 1>; - using DeclarationScopeBit = LanguageModeBit::Next<bool, 1>; - using ReceiverVariableBits = - DeclarationScopeBit::Next<VariableAllocationInfo, 2>; - using ClassScopeHasPrivateBrandBit = ReceiverVariableBits::Next<bool, 1>; - using HasSavedClassVariableBit = ClassScopeHasPrivateBrandBit::Next<bool, 1>; - using AllocatesArgumentsBit = HasSavedClassVariableBit::Next<bool, 1>; - using FunctionVariableBits = - AllocatesArgumentsBit::Next<VariableAllocationInfo, 2>; - using HasInferredFunctionNameBit = FunctionVariableBits::Next<bool, 1>; - using HasSimpleParametersBit = HasInferredFunctionNameBit::Next<bool, 1>; - using FunctionKindBits = HasSimpleParametersBit::Next<FunctionKind, 5>; - using HasOuterScopeInfoBit = FunctionKindBits::Next<bool, 1>; - using IsDebugEvaluateScopeBit = HasOuterScopeInfoBit::Next<bool, 1>; - using ForceContextAllocationBit = IsDebugEvaluateScopeBit::Next<bool, 1>; - using PrivateNameLookupSkipsOuterClassBit = - ForceContextAllocationBit::Next<bool, 1>; - using HasContextExtensionSlotBit = - PrivateNameLookupSkipsOuterClassBit::Next<bool, 1>; - using SomeContextHasExtensionBit = HasContextExtensionSlotBit::Next<bool, 1>; - using IsHiddenBit = SomeContextHasExtensionBit::Next<bool, 1>; - using IsWrappedFunctionBit = IsHiddenBit::Next<bool, 1>; - using HasContextCellsBit = IsWrappedFunctionBit::Next<bool, 1>; - using IsHoistedInContextBit = HasContextCellsBit::Next<bool, 1>; + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using ScopeTypeBits = base::BitField<ScopeType, 0, 4, uint32_t>; + using SloppyEvalCanExtendVarsBit = ScopeTypeBits::Next<bool, 1>; + using LanguageModeBit = SloppyEvalCanExtendVarsBit::Next<LanguageMode, 1>; + using DeclarationScopeBit = LanguageModeBit::Next<bool, 1>; + using ReceiverVariableBits = + DeclarationScopeBit::Next<VariableAllocationInfo, 2>; + using ClassScopeHasPrivateBrandBit = ReceiverVariableBits::Next<bool, 1>; + using HasSavedClassVariableBit = + ClassScopeHasPrivateBrandBit::Next<bool, 1>; + using AllocatesArgumentsBit = HasSavedClassVariableBit::Next<bool, 1>; + using FunctionVariableBits = + AllocatesArgumentsBit::Next<VariableAllocationInfo, 2>; + using HasInferredFunctionNameBit = FunctionVariableBits::Next<bool, 1>; + using HasSimpleParametersBit = HasInferredFunctionNameBit::Next<bool, 1>; + using FunctionKindBits = HasSimpleParametersBit::Next<FunctionKind, 5>; + using HasOuterScopeInfoBit = FunctionKindBits::Next<bool, 1>; + using IsDebugEvaluateScopeBit = HasOuterScopeInfoBit::Next<bool, 1>; + using ForceContextAllocationBit = IsDebugEvaluateScopeBit::Next<bool, 1>; + using PrivateNameLookupSkipsOuterClassBit = + ForceContextAllocationBit::Next<bool, 1>; + using HasContextExtensionSlotBit = + PrivateNameLookupSkipsOuterClassBit::Next<bool, 1>; + using SomeContextHasExtensionBit = + HasContextExtensionSlotBit::Next<bool, 1>; + using IsHiddenBit = SomeContextHasExtensionBit::Next<bool, 1>; + using IsWrappedFunctionBit = IsHiddenBit::Next<bool, 1>; + using HasContextCellsBit = IsWrappedFunctionBit::Next<bool, 1>; + using IsHoistedInContextBit = HasContextCellsBit::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(scope_type, ScopeTypeBits) + BIT_FIELD_GROUP_ACCESSORS(sloppy_eval_can_extend_vars, + SloppyEvalCanExtendVarsBit) + BIT_FIELD_GROUP_ACCESSORS(language_mode, LanguageModeBit) + BIT_FIELD_GROUP_ACCESSORS(declaration_scope, DeclarationScopeBit) + BIT_FIELD_GROUP_ACCESSORS(receiver_variable, ReceiverVariableBits) + BIT_FIELD_GROUP_ACCESSORS(class_scope_has_private_brand, + ClassScopeHasPrivateBrandBit) + BIT_FIELD_GROUP_ACCESSORS(has_saved_class_variable, + HasSavedClassVariableBit) + BIT_FIELD_GROUP_ACCESSORS(allocates_arguments, AllocatesArgumentsBit) + BIT_FIELD_GROUP_ACCESSORS(function_variable, FunctionVariableBits) + BIT_FIELD_GROUP_ACCESSORS(has_inferred_function_name, + HasInferredFunctionNameBit) + BIT_FIELD_GROUP_ACCESSORS(has_simple_parameters, HasSimpleParametersBit) + BIT_FIELD_GROUP_ACCESSORS(function_kind, FunctionKindBits) + BIT_FIELD_GROUP_ACCESSORS(has_outer_scope_info, HasOuterScopeInfoBit) + BIT_FIELD_GROUP_ACCESSORS(is_debug_evaluate_scope, IsDebugEvaluateScopeBit) + BIT_FIELD_GROUP_ACCESSORS(force_context_allocation, + ForceContextAllocationBit) + BIT_FIELD_GROUP_ACCESSORS(private_name_lookup_skips_outer_class, + PrivateNameLookupSkipsOuterClassBit) + BIT_FIELD_GROUP_ACCESSORS(has_context_extension_slot, + HasContextExtensionSlotBit) + BIT_FIELD_GROUP_ACCESSORS(some_context_has_extension, + SomeContextHasExtensionBit) + BIT_FIELD_GROUP_ACCESSORS(is_hidden, IsHiddenBit) + BIT_FIELD_GROUP_ACCESSORS(is_wrapped_function, IsWrappedFunctionBit) + BIT_FIELD_GROUP_ACCESSORS(has_context_cells, HasContextCellsBit) + BIT_FIELD_GROUP_ACCESSORS(is_hoisted_in_context, IsHoistedInContextBit) + }; DECL_PRINTER(ScopeInfo) DECL_VERIFIER(ScopeInfo) @@ -319,7 +356,7 @@ V8_OBJECT class ScopeInfo : public HeapObject { // Serializes empty scope info. V8_EXPORT_PRIVATE static Tagged<ScopeInfo> Empty(Isolate* isolate); - inline uint32_t Flags() const; + inline Flags flags() const; inline int ParameterCount() const; inline int ContextLocalCount() const; @@ -336,12 +373,13 @@ V8_OBJECT class ScopeInfo : public HeapObject { kVariablePartStart }; - static_assert(LanguageModeSize == 1 << LanguageModeBit::kSize); - static_assert(FunctionKindBits::is_valid(FunctionKind::kLastFunctionKind)); + static_assert(LanguageModeSize == 1 << Flags::LanguageModeBit::kSize); + static_assert( + Flags::FunctionKindBits::is_valid(FunctionKind::kLastFunctionKind)); // Named field accessors. - inline uint32_t flags(RelaxedLoadTag) const; - inline void set_flags(uint32_t value, RelaxedStoreTag); + inline Flags flags(RelaxedLoadTag) const; + inline void set_flags(Flags value, RelaxedStoreTag); inline int parameter_count() const; inline void set_parameter_count(int value); @@ -552,19 +590,52 @@ V8_OBJECT class ScopeInfo : public HeapObject { friend class TorqueGeneratedBitFieldAsserts; public: - // Relaxed-atomic flags word (ScopeFlags bit layout). - std::atomic<uint32_t> flags_; + V8_TQ_CONST V8_TQ_RELAXED std::atomic<Flags> flags_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TODO(jgruber): Consider plain uint32_t (or similar) for these. TaggedMember<Smi> parameter_count_; - TaggedMember<Smi> context_local_count_; - TaggedMember<Smi> position_info_start_; - TaggedMember<Smi> position_info_end_; + V8_TQ_CONST TaggedMember<Smi> context_local_count_; + // Match the Torque PositionInfo struct as one struct-typed field. + struct PositionInfo { + TaggedMember<Smi> start_; + TaggedMember<Smi> end_; + }; + PositionInfo position_info_; // Variable-length tagged tail. The presence and position of each - // sub-section is determined by flags and by header counts; see the - // Foo...Offset() accessors below. + // sub-section is determined by flags and by header counts; the layout is + // defined by the Foo...Offset() accessors above (scope-info-inl.h). In + // order: + // + // module_variable_count [scope_type == MODULE_SCOPE]: Smi + // context_local_names [context_local_count < kMax ? count : 0]: + // String + // context_local_names_hashtable [kMax <= context_local_count]: + // NameToIndexHashTable + // context_local_infos [context_local_count]: + // SmiTagged<VariableProperties> + // saved_class_variable_info [has_saved_class_variable]: Smi|Name + // function_variable_info [function_variable != NONE]: + // {name: String|Zero, slot_index: Smi} + // inferred_function_name [has_inferred_function_name]: + // String|Undefined + // outer_scope_info [has_outer_scope_info]: ScopeInfo + // module_info [scope_type == MODULE_SCOPE]: + // SourceTextModuleInfo + // module_variables [module_variable_count]: + // {name: String, index: Smi, + // properties: SmiTagged<VariableProperties>} + // module_variables_hashtable [MODULE_SCOPE && kMax <= module_var_count]: + // NameToIndexHashTable + // dependent_code [sloppy_eval_can_extend_vars]: DependentCode + // unused_parameter_bits [scope_type == FUNCTION_SCOPE]: Smi + // + // where kMax is kScopeInfoMaxInlinedLocalNamesSize. Torque only sees the + // fixed header; CSA reaches context_local_names / _hashtable / + // context_local_infos through CodeStubAssembler::IndexOfLocalName and + // GetFunctionContextSlotInitialValue. + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/scope-info.tq b/deps/v8/src/objects/scope-info.tq index 64647912f393..8e5223d4d4f5 100644 --- a/deps/v8/src/objects/scope-info.tq +++ b/deps/v8/src/objects/scope-info.tq @@ -57,8 +57,8 @@ extern enum IsStaticFlag extends uint32 { kNotStatic, kStatic } extern enum MaybeAssignedFlag extends uint32 { kNotAssigned, kMaybeAssigned } // Properties of scopes. -@cppScope('ScopeInfo') -bitfield struct ScopeFlags extends uint32 { +@cppScope('ScopeInfo::Flags') +bitfield struct ScopeInfoFlags extends uint32 { scope_type: ScopeType: 4 bit; sloppy_eval_can_extend_vars: bool: 1 bit; language_mode: LanguageMode: 1 bit; @@ -97,11 +97,6 @@ struct PositionInfo { } // LINT.IfChange(ScopeInfoStructs) -struct FunctionVariableInfo { - name: String|Zero; - context_or_stack_slot_index: Smi; -} - @cppScope('ScopeInfo') bitfield struct VariableProperties extends uint31 { variable_mode: VariableMode: 4 bit; @@ -111,20 +106,19 @@ bitfield struct VariableProperties extends uint31 { parameter_number_or_position: uint32: 16 bit; is_static_flag: IsStaticFlag: 1 bit; } - -struct ModuleVariable { - name: String; - index: Smi; - properties: SmiTagged<VariableProperties>; -} // LINT.ThenChange(src/objects/scope-info.h) const kMaxInlinedLocalNamesSize: constexpr int32 generates 'kScopeInfoMaxInlinedLocalNamesSize'; +// Only the fixed header is visible to Torque. The variable-length tail +// (context local names and infos, function variable info, module data, ...) +// is laid out by the Foo...Offset() accessors in scope-info-inl.h; see the +// layout comment in scope-info.h. CSA reaches the context locals through +// CodeStubAssembler::IndexOfLocalName / GetFunctionContextSlotInitialValue. @cppObjectLayoutDefinition extern class ScopeInfo extends HeapObject { - @cppRelaxedLoad @cppRelaxedStore const flags: ScopeFlags; + @cppRelaxedLoad @cppRelaxedStore const flags: ScopeInfoFlags; @if(TAGGED_SIZE_8_BYTES) optional_padding: uint32; @@ -137,107 +131,4 @@ extern class ScopeInfo extends HeapObject { // Contains two slots with a) the startPosition and b) the endPosition. position_info: PositionInfo; - - // This value must be before any object values, so that the GC can correctly - // determine the size of a partially initialized object during - // deserialization. - const module_variable_count? - [flags.scope_type == ScopeType::MODULE_SCOPE]: Smi; - - // Contains the names of inlined local variables and parameters that are - // allocated in the context. They are stored in increasing order of the - // context slot index starting with Context::MIN_CONTEXT_SLOTS. - context_local_names[Convert<intptr>(context_local_count) < kMaxInlinedLocalNamesSize ? context_local_count : 0]: - String; - - // Contains a hash_map from local names to context slot index. - // This is only used when local names are not inlined in the scope info. - context_local_names_hashtable? - [kMaxInlinedLocalNamesSize <= Convert<intptr>(context_local_count)]: - NameToIndexHashTable; - - // Contains the variable modes and initialization flags corresponding to - // the context locals in ContextLocalNames. - context_local_infos[context_local_count]: SmiTagged<VariableProperties>; - - // If the scope is a class scope and it has static private methods that - // may be accessed directly or through eval, one slot is reserved to hold - // the name of the class variable or the slot index if locals are inlined. - saved_class_variable_info?[flags.has_saved_class_variable]: Smi|Name; - - // If the scope belongs to a named function expression this part contains - // information about the function variable. It always occupies two array - // slots: a. The name of the function variable. - // b. The context or stack slot index for the variable. - function_variable_info? - [flags.function_variable != - FromConstexpr<VariableAllocationInfo>(VariableAllocationInfo::NONE)]: - FunctionVariableInfo; - - inferred_function_name?[flags.has_inferred_function_name]: String|Undefined; - - outer_scope_info?[flags.has_outer_scope_info]: ScopeInfo; - - // For a module scope, this part contains the SourceTextModuleInfo and the - // metadata of module-allocated variables. For non-module scopes it is empty. - module_info? - [flags.scope_type == ScopeType::MODULE_SCOPE]: SourceTextModuleInfo; - module_variables[flags.scope_type == ScopeType::MODULE_SCOPE ? module_variable_count : 0]: - ModuleVariable; - - // Maps a module variable's name to its index in module_variables. Only - // present when a module scope has enough module variables that a linear - // scan in ModuleIndex() would be costly (same threshold as the context - // local names hashtable). - module_variables_hashtable? - [flags.scope_type == ScopeType::MODULE_SCOPE ? - kMaxInlinedLocalNamesSize <= Convert<intptr>(module_variable_count) : - false]: NameToIndexHashTable; - - // EmptyContextExtension-dependent code objects. - dependent_code?[flags.sloppy_eval_can_extend_vars]: DependentCode; - - // For the first 31 formal parameters, these bits will be set if they are - // explicitly unused within the body of the function. - const unused_parameter_bits? - [flags.scope_type == ScopeType::FUNCTION_SCOPE]: Smi; -} - -extern macro NameToIndexHashTableLookup( - NameToIndexHashTable, Name): intptr labels NotFound; - -macro IndexOfInlinedLocalName( - scopeInfo: ScopeInfo, name: Name): intptr labels NotFound { - const count: intptr = Convert<intptr>(scopeInfo.context_local_count); - for (let i: intptr = 0; i < count; ++i) { - if (TaggedEqual(name, scopeInfo.context_local_names[i])) { - return i; - } - } - goto NotFound; -} - -// Returns the index of the named local in a ScopeInfo. -// Assumes that the given name is internalized; uses pointer comparisons. -@export -macro IndexOfLocalName( - scopeInfo: ScopeInfo, name: Name): intptr labels NotFound { - const count: intptr = Convert<intptr>(scopeInfo.context_local_count); - if (count < kMaxInlinedLocalNamesSize) { - return IndexOfInlinedLocalName(scopeInfo, name) otherwise goto NotFound; - } else { - return NameToIndexHashTableLookup( - scopeInfo.context_local_names_hashtable, name) otherwise goto NotFound; - } -} - -@export -macro GetFunctionContextSlotInitialValue( - scopeInfo: ScopeInfo, index: intptr): Object { - dcheck(index < Convert<intptr>(scopeInfo.context_local_count)); - const info = scopeInfo.context_local_infos[index]; - if (info.maybe_assigned_flag != MaybeAssignedFlag::kNotAssigned) { - return UndefinedContextCellConstant(); - } - return Undefined; } diff --git a/deps/v8/src/objects/script-inl.h b/deps/v8/src/objects/script-inl.h index 9b241848d93e..21203684d891 100644 --- a/deps/v8/src/objects/script-inl.h +++ b/deps/v8/src/objects/script-inl.h @@ -12,6 +12,7 @@ #include "src/objects/managed-inl.h" #include "src/objects/scope-info.h" #include "src/objects/smi-inl.h" +#include "src/objects/struct-inl.h" #include "src/objects/tagged-field-inl.h" #include "src/roots/roots-inl.h" @@ -21,6 +22,66 @@ namespace v8 { namespace internal { +Script::Script(const AllocationWitness& witness, + Tagged<UnionOf<String, Undefined>> source, int script_id) + : Struct(witness.roots().script_map()), + source_(witness, source), + name_(witness.roots().undefined_value()), + line_offset_(Smi::zero()), + column_offset_(Smi::zero()), + context_data_(witness.roots().undefined_value()), + script_type_(Smi::FromEnum(Script::Type::kNormal)), + line_ends_(Smi::zero()), + id_(Smi::FromInt(script_id)), + eval_from_shared_or_wrapped_arguments_(witness.roots().undefined_value()), + eval_from_position_(Smi::zero()), + eval_from_scope_info_(witness.roots().undefined_value()), + infos_(witness.roots().empty_weak_fixed_array()), + compiled_lazy_function_positions_(witness.roots().undefined_value()), + flags_(Smi::zero(), kRelaxedStore), + source_url_(witness.roots().undefined_value()), + source_mapping_url_(witness.roots().undefined_value()), + debug_id_(witness.roots().undefined_value()), + host_defined_options_(witness.roots().empty_fixed_array()), +#ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME + script_or_modules_(witness.roots().empty_array_list()), +#endif + source_hash_(witness.roots().undefined_value()) { +} + +Script::Script(const AllocationWitness& witness, Tagged<Script> old_script, + Tagged<String> source, int script_id +#ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME + , + Tagged<ArrayList> script_or_modules +#endif + ) + : Struct(witness.roots().script_map()), + source_(witness, source), + name_(witness, old_script->name()), + line_offset_(Smi::FromInt(old_script->line_offset())), + column_offset_(Smi::FromInt(old_script->column_offset())), + context_data_(witness, old_script->context_data()), + script_type_(Smi::FromEnum(old_script->type())), + line_ends_(Smi::zero()), + id_(Smi::FromInt(script_id)), + eval_from_shared_or_wrapped_arguments_( + witness, old_script->eval_from_shared_or_wrapped_arguments()), + eval_from_position_(Smi::FromInt(old_script->eval_from_position())), + eval_from_scope_info_(witness, old_script->eval_from_scope_info_.load()), + infos_(witness.roots().empty_weak_fixed_array()), + compiled_lazy_function_positions_(witness.roots().undefined_value()), + flags_(Smi::FromInt(old_script->flags()), kRelaxedStore), + source_url_(witness.roots().undefined_value()), + source_mapping_url_(witness.roots().undefined_value()), + debug_id_(witness.roots().undefined_value()), + host_defined_options_(witness, old_script->host_defined_options()), +#ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME + script_or_modules_(witness, script_or_modules), +#endif + source_hash_(witness.roots().undefined_value()) { +} + Tagged<UnionOf<String, Undefined>> Script::source() const { return source_.load(); } @@ -70,11 +131,13 @@ void Script::set_line_ends(Tagged<UnionOf<FixedArray, Smi>> value, int Script::id() const { return id_.load().value(); } void Script::set_id(int value) { id_.store(this, Smi::FromInt(value)); } -Tagged<Object> Script::eval_from_shared_or_wrapped_arguments() const { +Tagged<UnionOf<FixedArray, SharedFunctionInfo, Undefined>> +Script::eval_from_shared_or_wrapped_arguments() const { return eval_from_shared_or_wrapped_arguments_.load(); } -void Script::set_eval_from_shared_or_wrapped_arguments(Tagged<Object> value, - WriteBarrierMode mode) { +void Script::set_eval_from_shared_or_wrapped_arguments( + Tagged<UnionOf<FixedArray, SharedFunctionInfo, Undefined>> value, + WriteBarrierMode mode) { eval_from_shared_or_wrapped_arguments_.store(this, value, mode); } diff --git a/deps/v8/src/objects/script.h b/deps/v8/src/objects/script.h index 453a593ff427..16e4867f7a1f 100644 --- a/deps/v8/src/objects/script.h +++ b/deps/v8/src/objects/script.h @@ -36,6 +36,16 @@ class NativeModule; // Script describes a script which has been added to the VM. V8_OBJECT class Script : public Struct { public: + inline Script(const AllocationWitness& witness, + Tagged<UnionOf<String, Undefined>> source, int script_id); + inline Script(const AllocationWitness& witness, Tagged<Script> old_script, + Tagged<String> source, int script_id +#ifdef V8_SCRIPTORMODULE_LEGACY_LIFETIME + , + Tagged<ArrayList> script_or_modules +#endif + ); + // Script ID used for temporary scripts, which shouldn't be added to the // script list. static constexpr int kTemporaryScriptId = -2; @@ -100,13 +110,15 @@ V8_OBJECT class Script : public Struct { inline int id() const; inline void set_id(int value); - inline Tagged<Object> eval_from_shared_or_wrapped_arguments() const; + inline Tagged<UnionOf<FixedArray, SharedFunctionInfo, Undefined>> + eval_from_shared_or_wrapped_arguments() const; inline void set_eval_from_shared_or_wrapped_arguments( - Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + Tagged<UnionOf<FixedArray, SharedFunctionInfo, Undefined>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // [eval_from_shared]: for eval scripts the shared function info for the // function from which eval was called. - Tagged<SharedFunctionInfo> eval_from_shared() const; + V8_EXPORT_PRIVATE Tagged<SharedFunctionInfo> eval_from_shared() const; void set_eval_from_shared(Tagged<SharedFunctionInfo> shared, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); @@ -387,12 +399,13 @@ V8_OBJECT class Script : public Struct { TaggedMember<Smi> script_type_; TaggedMember<UnionOf<FixedArray, Smi>> line_ends_; TaggedMember<Smi> id_; - TaggedMember<Object> eval_from_shared_or_wrapped_arguments_; + TaggedMember<UnionOf<FixedArray, SharedFunctionInfo, Undefined>> + eval_from_shared_or_wrapped_arguments_; TaggedMember<UnionOf<Smi, CppGCManagedBase>> eval_from_position_; TaggedMember<UnionOf<ScopeInfo, Undefined>> eval_from_scope_info_; TaggedMember<UnionOf<WeakFixedArray, WeakArrayList>> infos_; TaggedMember<UnionOf<ArrayList, Undefined>> compiled_lazy_function_positions_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<ScriptFlags>); TaggedMember<UnionOf<String, Undefined>> source_url_; TaggedMember<Object> source_mapping_url_; TaggedMember<UnionOf<String, Undefined>> debug_id_; diff --git a/deps/v8/src/objects/shared-function-info-inl.h b/deps/v8/src/objects/shared-function-info-inl.h index c4504c0f58b5..89954731d145 100644 --- a/deps/v8/src/objects/shared-function-info-inl.h +++ b/deps/v8/src/objects/shared-function-info-inl.h @@ -31,6 +31,7 @@ #include "src/objects/oddball-predicates-inl.h" #include "src/objects/scope-info-inl.h" #include "src/objects/script-inl.h" +#include "src/objects/slots-inl.h" #include "src/objects/string.h" #include "src/objects/templates-inl.h" @@ -43,6 +44,18 @@ namespace v8::internal { +PreparseData::PreparseData(const AllocationWitness& witness, int data_length, + int children_length) + : HeapObject(witness.roots().preparse_data_map()), + data_length_(data_length), + children_length_(children_length) { + DCHECK_LE(0, data_length); + DCHECK_LE(0, children_length); + MemsetTagged(ObjectSlot(children()), witness.roots().null_value(), + children_length); + clear_padding(); +} + // static int PreparseData::SizeFor(int data_length, int children_length) { return OFFSET_OF_DATA_START(PreparseData) + @@ -202,9 +215,9 @@ bool SharedFunctionInfo::HasUnpublishedTrustedData( bool SharedFunctionInfo::HasUntrustedData() const { return !HasTrustedData(); } -template <typename T, IndirectPointerTagRange tag_range> +template <typename T, TrustedPointerTagRange tag_range> Tagged<T> SharedFunctionInfo::GetTrustedData(IsolateForSandbox isolate) const { - static_assert(tag_range != kAllIndirectPointerTags); + static_assert(tag_range != kAllTrustedPointerTags); return Cast<T>(TrustedPointerField::ReadTrustedPointerField<tag_range>( Tagged<HeapObject>(this), offsetof(SharedFunctionInfo, trusted_function_data_), isolate, @@ -330,11 +343,11 @@ void SharedFunctionInfo::set_raw_function_token_offset(uint16_t value) { set_function_token_offset(value); } -int32_t SharedFunctionInfo::flags(RelaxedLoadTag) const { - return static_cast<int32_t>(flags_.load(std::memory_order_relaxed)); +SharedFunctionInfo::Flags SharedFunctionInfo::flags(RelaxedLoadTag) const { + return flags_.load(std::memory_order_relaxed); } -void SharedFunctionInfo::set_flags(int32_t value, RelaxedStoreTag) { - flags_.store(static_cast<uint32_t>(value), std::memory_order_relaxed); +void SharedFunctionInfo::set_flags(Flags value, RelaxedStoreTag) { + flags_.store(value, std::memory_order_relaxed); } int32_t SharedFunctionInfo::function_literal_id(RelaxedLoadTag) const { return function_literal_id_.load(std::memory_order_relaxed); @@ -343,15 +356,17 @@ void SharedFunctionInfo::set_function_literal_id(int32_t value, RelaxedStoreTag) { function_literal_id_.store(value, std::memory_order_relaxed); } -int32_t SharedFunctionInfo::relaxed_flags() const { +SharedFunctionInfo::Flags SharedFunctionInfo::relaxed_flags() const { return flags(kRelaxedLoad); } -void SharedFunctionInfo::set_relaxed_flags(int32_t flags) { +void SharedFunctionInfo::set_relaxed_flags(Flags flags) { return set_flags(flags, kRelaxedStore); } -uint8_t SharedFunctionInfo::flags2() const { return flags2_; } -void SharedFunctionInfo::set_flags2(uint8_t value) { flags2_ = value; } +SharedFunctionInfo::Flags2 SharedFunctionInfo::flags2() const { + return flags2_; +} +void SharedFunctionInfo::set_flags2(Flags2 value) { flags2_ = value; } bool SharedFunctionInfo::HasSharedName() const { Tagged<Object> value = name_or_scope_info(kAcquireLoad); @@ -465,55 +480,55 @@ SharedFunctionInfo::Inlineability SharedFunctionInfo::GetInlineability( } BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags2, class_scope_has_private_brand, - SharedFunctionInfo::ClassScopeHasPrivateBrandBit) + SharedFunctionInfo::Flags2::ClassScopeHasPrivateBrandBit) -BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags2, - has_static_private_methods_or_accessors, - SharedFunctionInfo::HasStaticPrivateMethodsOrAccessorsBit) +BIT_FIELD_ACCESSORS( + SharedFunctionInfo, flags2, has_static_private_methods_or_accessors, + SharedFunctionInfo::Flags2::HasStaticPrivateMethodsOrAccessorsBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags2, is_sparkplug_compiling, - SharedFunctionInfo::IsSparkplugCompilingBit) + SharedFunctionInfo::Flags2::IsSparkplugCompilingBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags2, maglev_compilation_failed, - SharedFunctionInfo::MaglevCompilationFailedBit) + SharedFunctionInfo::Flags2::MaglevCompilationFailedBit) -BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags2, - function_context_independent_compiled, - SharedFunctionInfo::FunctionContextIndependentCompiledBit) +BIT_FIELD_ACCESSORS( + SharedFunctionInfo, flags2, function_context_independent_compiled, + SharedFunctionInfo::Flags2::FunctionContextIndependentCompiledBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, syntax_kind, - SharedFunctionInfo::FunctionSyntaxKindBits) + SharedFunctionInfo::Flags::FunctionSyntaxKindBits) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, allows_lazy_compilation, - SharedFunctionInfo::AllowLazyCompilationBit) + SharedFunctionInfo::Flags::AllowLazyCompilationBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, has_duplicate_parameters, - SharedFunctionInfo::HasDuplicateParametersBit) + SharedFunctionInfo::Flags::HasDuplicateParametersBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, native, - SharedFunctionInfo::IsNativeBit) -BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, - requires_instance_members_initializer, - SharedFunctionInfo::RequiresInstanceMembersInitializerBit) + SharedFunctionInfo::Flags::IsNativeBit) +BIT_FIELD_ACCESSORS( + SharedFunctionInfo, relaxed_flags, requires_instance_members_initializer, + SharedFunctionInfo::Flags::RequiresInstanceMembersInitializerBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, name_should_print_as_anonymous, - SharedFunctionInfo::NameShouldPrintAsAnonymousBit) + SharedFunctionInfo::Flags::NameShouldPrintAsAnonymousBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, has_reported_binary_coverage, - SharedFunctionInfo::HasReportedBinaryCoverageBit) + SharedFunctionInfo::Flags::HasReportedBinaryCoverageBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, is_toplevel, - SharedFunctionInfo::IsTopLevelBit) + SharedFunctionInfo::Flags::IsTopLevelBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, properties_are_final, - SharedFunctionInfo::PropertiesAreFinalBit) -BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, - private_name_lookup_skips_outer_class, - SharedFunctionInfo::PrivateNameLookupSkipsOuterClassBit) + SharedFunctionInfo::Flags::PropertiesAreFinalBit) +BIT_FIELD_ACCESSORS( + SharedFunctionInfo, relaxed_flags, private_name_lookup_skips_outer_class, + SharedFunctionInfo::Flags::PrivateNameLookupSkipsOuterClassBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, is_hoisted_in_context, - SharedFunctionInfo::IsHoistedInContextBit) + SharedFunctionInfo::Flags::IsHoistedInContextBit) BIT_FIELD_ACCESSORS(SharedFunctionInfo, relaxed_flags, class_initializer_allows_await, - SharedFunctionInfo::ClassInitializerAllowsAwaitBit) + SharedFunctionInfo::Flags::ClassInitializerAllowsAwaitBit) bool SharedFunctionInfo::optimization_disabled(CodeKind kind) const { switch (kind) { @@ -531,12 +546,12 @@ bool SharedFunctionInfo::all_optimization_disabled() const { } BailoutReason SharedFunctionInfo::disabled_optimization_reason() const { - return DisabledOptimizationReasonBits::decode(flags(kRelaxedLoad)); + return flags(kRelaxedLoad).disabled_optimization_reason(); } LanguageMode SharedFunctionInfo::language_mode() const { static_assert(LanguageModeSize == 2); - return construct_language_mode(IsStrictBit::decode(flags(kRelaxedLoad))); + return construct_language_mode(flags(kRelaxedLoad).is_strict()); } void SharedFunctionInfo::set_language_mode(LanguageMode language_mode) { @@ -544,22 +559,20 @@ void SharedFunctionInfo::set_language_mode(LanguageMode language_mode) { // We only allow language mode transitions that set the same language mode // again or go up in the chain: DCHECK(is_sloppy(this->language_mode()) || is_strict(language_mode)); - int hints = flags(kRelaxedLoad); - hints = IsStrictBit::update(hints, is_strict(language_mode)); - set_flags(hints, kRelaxedStore); - UpdateFunctionMapIndex(); + set_flags(flags(kRelaxedLoad).with_is_strict(is_strict(language_mode)), + kRelaxedStore); } FunctionKind SharedFunctionInfo::kind() const { - static_assert(FunctionKindBits::kSize == kFunctionKindBitSize); - return FunctionKindBits::decode(flags(kRelaxedLoad)); + static_assert(Flags::FunctionKindBits::kSize == kFunctionKindBitSize); + return flags(kRelaxedLoad).function_kind(); } void SharedFunctionInfo::set_kind(FunctionKind kind) { - int hints = flags(kRelaxedLoad); - hints = FunctionKindBits::update(hints, kind); - hints = IsClassConstructorBit::update(hints, IsClassConstructor(kind)); - set_flags(hints, kRelaxedStore); + set_flags(flags(kRelaxedLoad) + .with_function_kind(kind) + .with_is_class_constructor(IsClassConstructor(kind)), + kRelaxedStore); UpdateFunctionMapIndex(); } @@ -568,7 +581,7 @@ bool SharedFunctionInfo::is_wrapped() const { } bool SharedFunctionInfo::construct_as_builtin() const { - return ConstructAsBuiltinBit::decode(flags(kRelaxedLoad)); + return flags(kRelaxedLoad).construct_as_builtin(); } void SharedFunctionInfo::CalculateConstructAsBuiltin() { @@ -586,9 +599,9 @@ void SharedFunctionInfo::CalculateConstructAsBuiltin() { uses_builtins_construct_stub = true; } - int f = flags(kRelaxedLoad); - f = ConstructAsBuiltinBit::update(f, uses_builtins_construct_stub); - set_flags(f, kRelaxedStore); + set_flags(flags(kRelaxedLoad) + .with_construct_as_builtin(uses_builtins_construct_stub), + kRelaxedStore); } uint16_t SharedFunctionInfo::age() const { @@ -609,24 +622,23 @@ uint16_t SharedFunctionInfo::CompareExchangeAge(uint16_t expected_age, int SharedFunctionInfo::function_map_index() const { // Note: Must be kept in sync with the FastNewClosure builtin. int index = Context::FIRST_FUNCTION_MAP_INDEX + - FunctionMapIndexBits::decode(flags(kRelaxedLoad)); + flags(kRelaxedLoad).function_map_index(); DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); return index; } void SharedFunctionInfo::set_function_map_index(int index) { static_assert(Context::LAST_FUNCTION_MAP_INDEX <= - Context::FIRST_FUNCTION_MAP_INDEX + FunctionMapIndexBits::kMax); + Context::FIRST_FUNCTION_MAP_INDEX + + Flags::FunctionMapIndexBits::kMax); DCHECK_LE(Context::FIRST_FUNCTION_MAP_INDEX, index); DCHECK_LE(index, Context::LAST_FUNCTION_MAP_INDEX); index -= Context::FIRST_FUNCTION_MAP_INDEX; - set_flags(FunctionMapIndexBits::update(flags(kRelaxedLoad), index), - kRelaxedStore); + set_flags(flags(kRelaxedLoad).with_function_map_index(index), kRelaxedStore); } void SharedFunctionInfo::UpdateFunctionMapIndex() { - int map_index = - Context::FunctionMapIndex(language_mode(), kind(), HasSharedName()); + int map_index = Context::FunctionMapIndex(kind(), HasSharedName()); set_function_map_index(map_index); } @@ -949,17 +961,24 @@ Tagged<BytecodeArray> SharedFunctionInfo::GetBytecodeArrayForGC( return GetBytecodeArrayInternal(isolate); } -Tagged<BytecodeArray> SharedFunctionInfo::GetBytecodeArrayInternal( +SharedFunctionInfo::BytecodeArrays SharedFunctionInfo::GetBytecodeArrays( Isolate* isolate) const { DCHECK(HasBytecodeArray()); std::optional<Tagged<DebugInfo>> debug_info = TryGetDebugInfo(isolate); if (debug_info.has_value() && debug_info.value()->HasInstrumentedBytecodeArray()) { - return debug_info.value()->OriginalBytecodeArray(isolate); + return {debug_info.value()->OriginalBytecodeArray(isolate), + debug_info.value()->DebugBytecodeArray(isolate)}; } - return GetActiveBytecodeArray(isolate); + Tagged<BytecodeArray> active = GetActiveBytecodeArray(isolate); + return {active, active}; +} + +Tagged<BytecodeArray> SharedFunctionInfo::GetBytecodeArrayInternal( + Isolate* isolate) const { + return GetBytecodeArrays(isolate).original; } Tagged<BytecodeArray> SharedFunctionInfo::GetActiveBytecodeArray( @@ -1046,7 +1065,7 @@ DEF_GETTER(SharedFunctionInfo, HasBaselineCode, bool) { DEF_ACQUIRE_GETTER(SharedFunctionInfo, baseline_code, Tagged<Code>) { DCHECK(HasBaselineCode()); IsolateForSandbox isolate = GetCurrentIsolateForSandbox(); - auto code = GetTrustedData<Code, kCodeIndirectPointerTag>(isolate); + auto code = GetTrustedData<Code, kCodeTrustedPointerTag>(isolate); SBXCHECK_EQ(code->kind(), CodeKind::BASELINE); return code; } @@ -1091,7 +1110,7 @@ DEF_GETTER(SharedFunctionInfo, wasm_function_data, Tagged<WasmFunctionData>) { IsolateForSandbox isolate = GetCurrentIsolateForSandbox(); DCHECK(HasWasmFunctionData(isolate)); return GetTrustedData<WasmFunctionData, - kWasmFunctionDataIndirectPointerTagRange>(isolate); + kWasmFunctionDataTrustedPointerTagRange>(isolate); } DEF_GETTER(SharedFunctionInfo, wasm_exported_function_data, @@ -1099,7 +1118,7 @@ DEF_GETTER(SharedFunctionInfo, wasm_exported_function_data, IsolateForSandbox isolate = GetCurrentIsolateForSandbox(); DCHECK(HasWasmExportedFunctionData(isolate)); return GetTrustedData<WasmExportedFunctionData, - kWasmExportedFunctionDataIndirectPointerTag>(isolate); + kWasmExportedFunctionDataTrustedPointerTag>(isolate); } DEF_GETTER(SharedFunctionInfo, wasm_capi_function_data, @@ -1107,7 +1126,7 @@ DEF_GETTER(SharedFunctionInfo, wasm_capi_function_data, IsolateForSandbox isolate = GetCurrentIsolateForSandbox(); DCHECK(HasWasmCapiFunctionData(isolate)); return GetTrustedData<WasmCapiFunctionData, - kWasmCapiFunctionDataIndirectPointerTag>(isolate); + kWasmCapiFunctionDataTrustedPointerTag>(isolate); } DEF_GETTER(SharedFunctionInfo, wasm_resume_data, Tagged<WasmResumeData>) { @@ -1144,7 +1163,7 @@ bool SharedFunctionInfo::HasUncompiledData(IsolateForSandbox isolate) const { Tagged<UncompiledData> SharedFunctionInfo::uncompiled_data( IsolateForSandbox isolate) const { DCHECK(HasUncompiledData(isolate)); - return GetTrustedData<UncompiledData, kUncompiledDataIndirectPointerTag>( + return GetTrustedData<UncompiledData, kUncompiledDataTrustedPointerTag>( isolate); } @@ -1298,7 +1317,7 @@ bool SharedFunctionInfo::CanDiscardCompiled( } bool SharedFunctionInfo::is_class_constructor() const { - return IsClassConstructorBit::decode(flags(kRelaxedLoad)); + return flags(kRelaxedLoad).is_class_constructor(); } void SharedFunctionInfo::set_are_properties_final(bool value) { diff --git a/deps/v8/src/objects/shared-function-info.cc b/deps/v8/src/objects/shared-function-info.cc index 0f4078ec21bc..51c1bdfe4b2d 100644 --- a/deps/v8/src/objects/shared-function-info.cc +++ b/deps/v8/src/objects/shared-function-info.cc @@ -32,7 +32,7 @@ Tagged<Union<Smi, TrustedObject>> SharedFunctionInfo::GetTrustedData( IsolateForSandbox isolate) const { if (HasUnpublishedTrustedData(isolate)) return Smi::zero(); return TrustedPointerField::ReadMaybeEmptyTrustedPointerField< - kTrustedDataIndirectPointerRange>( + kTrustedDataTrustedPointerRange>( Tagged<HeapObject>(this), offsetof(SharedFunctionInfo, trusted_function_data_), isolate, kAcquireLoad); @@ -47,42 +47,23 @@ uint32_t SharedFunctionInfo::Hash() { return static_cast<uint32_t>(base::hash_combine(start_pos, script_id)); } -void SharedFunctionInfo::Init(ReadOnlyRoots ro_roots, int unique_id) { - DisallowGarbageCollection no_gc; - - // Set the function data to the "illegal" builtin. Ideally we'd use some sort - // of "uninitialized" marker here, but it's cheaper to use a valid builtin and - // avoid having to do uninitialized checks elsewhere. - set_builtin_id(Builtin::kIllegal); - - // Set the name to the no-name sentinel, this can be updated later. - set_name_or_scope_info(SharedFunctionInfo::kNoSharedNameSentinel, - kReleaseStore, SKIP_WRITE_BARRIER); - - // Generally functions won't have feedback, unless they have been created - // from a FunctionLiteral. Those can just reset this field to keep the - // SharedFunctionInfo in a consistent state. - set_raw_outer_scope_info_or_feedback_metadata(ro_roots.the_hole_value(), - SKIP_WRITE_BARRIER); - set_script(ro_roots.undefined_value(), kReleaseStore, SKIP_WRITE_BARRIER); - set_function_literal_id(kInvalidInfoId, kRelaxedStore); - set_unique_id(unique_id); - - // Set integer fields (smi or int, depending on the architecture). - set_length(0); - set_internal_formal_parameter_count(JSParameterCount(0)); - set_expected_nof_properties(0); - set_raw_function_token_offset(0); - - // All flags default to false or 0, except ConstructAsBuiltinBit just because - // we're using the kIllegal builtin. - set_flags(ConstructAsBuiltinBit::encode(true), kRelaxedStore); - set_flags2(0); - +SharedFunctionInfo::SharedFunctionInfo(const AllocationWitness& witness, + int unique_id) + : HeapObject(witness.roots().shared_function_info_map()), + // Generally functions won't have feedback, unless they have been created + // from a FunctionLiteral. Those can just reset this field to keep the + // SharedFunctionInfo in a consistent state. + outer_scope_info_or_feedback_metadata_(witness.roots().the_hole_value()), + script_(witness.roots().undefined_value()), + unique_id_(unique_id) { UpdateFunctionMapIndex(); +} - set_age(0); - set_feedback_slot(0); +SharedFunctionInfo::SharedFunctionInfo(const AllocationWitness& witness, + Tagged<SharedFunctionInfo> other, + IsolateForSandbox isolate) + : HeapObject(witness.roots().shared_function_info_map()) { + CopyFrom(other, isolate); } // LINT.IfChange(GetSharedFunctionInfoCode) @@ -350,7 +331,7 @@ Handle<String> SharedFunctionInfo::DebugName( #if V8_ENABLE_WEBASSEMBLY if (shared->HasWasmExportedFunctionData(isolate) && allow_allocation) { return isolate->factory() - ->NewStringFromUtf8(base::CStrVector(shared->DebugNameCStr().get())) + ->NewStringFromUtf8(shared->DebugNameCStr().get()) .ToHandleChecked(); } #endif // V8_ENABLE_WEBASSEMBLY @@ -371,9 +352,7 @@ bool SharedFunctionInfo::PassesFilter(const char* raw_filter) { if (V8_LIKELY(raw_filter[0] == '*' && raw_filter[1] == '\0')) { return true; } - base::Vector<const char> filter = base::CStrVector(raw_filter); - return v8::internal::PassesFilter(base::CStrVector(DebugNameCStr().get()), - filter); + return v8::internal::PassesFilter(DebugNameCStr().get(), raw_filter); } bool SharedFunctionInfo::HasSourceCode() const { @@ -544,7 +523,7 @@ void SharedFunctionInfo::DisableOptimization(Isolate* isolate, BailoutReason reason) { DCHECK_NE(reason, BailoutReason::kNoReason); - set_flags(DisabledOptimizationReasonBits::update(flags(kRelaxedLoad), reason), + set_flags(flags(kRelaxedLoad).with_disabled_optimization_reason(reason), kRelaxedStore); // Code should be the lazy compilation stub or else interpreted. if constexpr (DEBUG_BOOL) { @@ -815,12 +794,12 @@ int SharedFunctionInfo::EndPosition() const { } CachedTieringDecision SharedFunctionInfo::cached_tiering_decision() { - return CachedTieringDecisionBits::decode(flags2()); + return flags2().cached_tiering_decision(); } void SharedFunctionInfo::set_cached_tiering_decision( CachedTieringDecision decision) { - set_flags2(CachedTieringDecisionBits::update(flags2(), decision)); + set_flags2(flags2().with_cached_tiering_decision(decision)); } // static diff --git a/deps/v8/src/objects/shared-function-info.h b/deps/v8/src/objects/shared-function-info.h index dd0e0bcb5a45..30270816962e 100644 --- a/deps/v8/src/objects/shared-function-info.h +++ b/deps/v8/src/objects/shared-function-info.h @@ -14,6 +14,7 @@ #include "src/builtins/builtins.h" #include "src/codegen/bailout-reason.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/compressed-slots.h" #include "src/objects/function-kind.h" #include "src/objects/function-syntax-kind.h" @@ -78,11 +79,12 @@ using CreateSourcePositions = // +-------------------------------+ V8_OBJECT class PreparseData : public HeapObject { public: + inline PreparseData(const AllocationWitness& witness, int data_length, + int children_length); + int32_t data_length() const { return data_length_; } - void set_data_length(int32_t value) { data_length_ = value; } int32_t children_length() const { return children_length_; } - void set_children_length(int32_t value) { children_length_ = value; } inline uint8_t get(int index) const; inline void set(int index, uint8_t value); @@ -126,8 +128,9 @@ V8_OBJECT class PreparseData : public HeapObject { inline int children_start_offset() const; - int32_t data_length_; - int32_t children_length_; + const int32_t data_length_; + const int32_t children_length_; + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(char, data_and_children); } V8_OBJECT_END; @@ -265,42 +268,87 @@ using NameOrScopeInfoT = UnionOf<Smi, String, ScopeInfo>; // shared by multiple instances of the function. V8_OBJECT class SharedFunctionInfo : public HeapObject { public: - // Bit positions in |flags|. - using FunctionKindBits = base::BitField<FunctionKind, 0, 5, uint32_t>; - using IsNativeBit = FunctionKindBits::Next<bool, 1>; - using IsStrictBit = IsNativeBit::Next<bool, 1>; - using FunctionSyntaxKindBits = IsStrictBit::Next<FunctionSyntaxKind, 3>; - using IsClassConstructorBit = FunctionSyntaxKindBits::Next<bool, 1>; - using HasDuplicateParametersBit = IsClassConstructorBit::Next<bool, 1>; - using AllowLazyCompilationBit = HasDuplicateParametersBit::Next<bool, 1>; - using FunctionMapIndexBits = AllowLazyCompilationBit::Next<uint32_t, 5>; - using DisabledOptimizationReasonBits = - FunctionMapIndexBits::Next<BailoutReason, 4>; - using RequiresInstanceMembersInitializerBit = - DisabledOptimizationReasonBits::Next<bool, 1>; - using ConstructAsBuiltinBit = - RequiresInstanceMembersInitializerBit::Next<bool, 1>; - using NameShouldPrintAsAnonymousBit = ConstructAsBuiltinBit::Next<bool, 1>; - using HasReportedBinaryCoverageBit = - NameShouldPrintAsAnonymousBit::Next<bool, 1>; - using IsTopLevelBit = HasReportedBinaryCoverageBit::Next<bool, 1>; - using PropertiesAreFinalBit = IsTopLevelBit::Next<bool, 1>; - using PrivateNameLookupSkipsOuterClassBit = - PropertiesAreFinalBit::Next<bool, 1>; - using IsHoistedInContextBit = - PrivateNameLookupSkipsOuterClassBit::Next<bool, 1>; - using ClassInitializerAllowsAwaitBit = IsHoistedInContextBit::Next<bool, 1>; - // Bit positions in |flags2|. - using ClassScopeHasPrivateBrandBit = base::BitField<bool, 0, 1, uint8_t>; - using HasStaticPrivateMethodsOrAccessorsBit = - ClassScopeHasPrivateBrandBit::Next<bool, 1>; - using IsSparkplugCompilingBit = - HasStaticPrivateMethodsOrAccessorsBit::Next<bool, 1>; - using MaglevCompilationFailedBit = IsSparkplugCompilingBit::Next<bool, 1>; - using CachedTieringDecisionBits = - MaglevCompilationFailedBit::Next<CachedTieringDecision, 3>; - using FunctionContextIndependentCompiledBit = - CachedTieringDecisionBits::Next<bool, 1>; + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using FunctionKindBits = base::BitField<FunctionKind, 0, 5, uint32_t>; + using IsNativeBit = FunctionKindBits::Next<bool, 1>; + using IsStrictBit = IsNativeBit::Next<bool, 1>; + using FunctionSyntaxKindBits = IsStrictBit::Next<FunctionSyntaxKind, 3>; + using IsClassConstructorBit = FunctionSyntaxKindBits::Next<bool, 1>; + using HasDuplicateParametersBit = IsClassConstructorBit::Next<bool, 1>; + using AllowLazyCompilationBit = HasDuplicateParametersBit::Next<bool, 1>; + using FunctionMapIndexBits = AllowLazyCompilationBit::Next<uint32_t, 5>; + using DisabledOptimizationReasonBits = + FunctionMapIndexBits::Next<BailoutReason, 4>; + using RequiresInstanceMembersInitializerBit = + DisabledOptimizationReasonBits::Next<bool, 1>; + using ConstructAsBuiltinBit = + RequiresInstanceMembersInitializerBit::Next<bool, 1>; + using NameShouldPrintAsAnonymousBit = ConstructAsBuiltinBit::Next<bool, 1>; + using HasReportedBinaryCoverageBit = + NameShouldPrintAsAnonymousBit::Next<bool, 1>; + using IsTopLevelBit = HasReportedBinaryCoverageBit::Next<bool, 1>; + using PropertiesAreFinalBit = IsTopLevelBit::Next<bool, 1>; + using PrivateNameLookupSkipsOuterClassBit = + PropertiesAreFinalBit::Next<bool, 1>; + using IsHoistedInContextBit = + PrivateNameLookupSkipsOuterClassBit::Next<bool, 1>; + using ClassInitializerAllowsAwaitBit = IsHoistedInContextBit::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(function_kind, FunctionKindBits) + BIT_FIELD_GROUP_ACCESSORS(is_native, IsNativeBit) + BIT_FIELD_GROUP_ACCESSORS(is_strict, IsStrictBit) + BIT_FIELD_GROUP_ACCESSORS(function_syntax_kind, FunctionSyntaxKindBits) + BIT_FIELD_GROUP_ACCESSORS(is_class_constructor, IsClassConstructorBit) + BIT_FIELD_GROUP_ACCESSORS(has_duplicate_parameters, + HasDuplicateParametersBit) + BIT_FIELD_GROUP_ACCESSORS(allow_lazy_compilation, AllowLazyCompilationBit) + BIT_FIELD_GROUP_ACCESSORS(function_map_index, FunctionMapIndexBits) + BIT_FIELD_GROUP_ACCESSORS(disabled_optimization_reason, + DisabledOptimizationReasonBits) + BIT_FIELD_GROUP_ACCESSORS(requires_instance_members_initializer, + RequiresInstanceMembersInitializerBit) + BIT_FIELD_GROUP_ACCESSORS(construct_as_builtin, ConstructAsBuiltinBit) + BIT_FIELD_GROUP_ACCESSORS(name_should_print_as_anonymous, + NameShouldPrintAsAnonymousBit) + BIT_FIELD_GROUP_ACCESSORS(has_reported_binary_coverage, + HasReportedBinaryCoverageBit) + BIT_FIELD_GROUP_ACCESSORS(is_top_level, IsTopLevelBit) + BIT_FIELD_GROUP_ACCESSORS(properties_are_final, PropertiesAreFinalBit) + BIT_FIELD_GROUP_ACCESSORS(private_name_lookup_skips_outer_class, + PrivateNameLookupSkipsOuterClassBit) + BIT_FIELD_GROUP_ACCESSORS(is_hoisted_in_context, IsHoistedInContextBit) + BIT_FIELD_GROUP_ACCESSORS(class_initializer_allows_await, + ClassInitializerAllowsAwaitBit) + }; + + struct Flags2 : BitFieldGroup<Flags2, uint8_t> { + using BitFieldGroup::BitFieldGroup; + + using ClassScopeHasPrivateBrandBit = base::BitField<bool, 0, 1, uint8_t>; + using HasStaticPrivateMethodsOrAccessorsBit = + ClassScopeHasPrivateBrandBit::Next<bool, 1>; + using IsSparkplugCompilingBit = + HasStaticPrivateMethodsOrAccessorsBit::Next<bool, 1>; + using MaglevCompilationFailedBit = IsSparkplugCompilingBit::Next<bool, 1>; + using CachedTieringDecisionBits = + MaglevCompilationFailedBit::Next<CachedTieringDecision, 3>; + using FunctionContextIndependentCompiledBit = + CachedTieringDecisionBits::Next<bool, 1>; + + BIT_FIELD_GROUP_ACCESSORS(class_scope_has_private_brand, + ClassScopeHasPrivateBrandBit) + BIT_FIELD_GROUP_ACCESSORS(has_static_private_methods_or_accessors, + HasStaticPrivateMethodsOrAccessorsBit) + BIT_FIELD_GROUP_ACCESSORS(is_sparkplug_compiling, IsSparkplugCompilingBit) + BIT_FIELD_GROUP_ACCESSORS(maglev_compilation_failed, + MaglevCompilationFailedBit) + BIT_FIELD_GROUP_ACCESSORS(cached_tiering_decision, + CachedTieringDecisionBits) + BIT_FIELD_GROUP_ACCESSORS(function_context_independent_compiled, + FunctionContextIndependentCompiledBit) + }; // Primitive header accessors (equivalents of the previously Torque- // generated inline getters/setters). Kept in the same order as the @@ -334,12 +382,14 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline uint16_t feedback_slot() const; inline void set_feedback_slot(uint16_t value); - // This initializes the SharedFunctionInfo after allocation. It must - // initialize all fields, and leave the SharedFunctionInfo in a state where - // it is safe for the GC to visit it. + // Initializes the SharedFunctionInfo after allocation. Leaves the + // SharedFunctionInfo in a state where it is safe for the GC to visit it. // - // Important: This function MUST not allocate. - void Init(ReadOnlyRoots roots, int unique_id); + // Important: These constructors MUST not allocate. + SharedFunctionInfo(const AllocationWitness& witness, int unique_id); + SharedFunctionInfo(const AllocationWitness& witness, + Tagged<SharedFunctionInfo> other, + IsolateForSandbox isolate); V8_EXPORT_PRIVATE static constexpr Tagged<Smi> const kNoSharedNameSentinel = Smi::zero(); @@ -483,7 +533,7 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline Tagged<Object> GetUntrustedData() const; // Helper function for use when a specific data type is expected. - template <typename T, IndirectPointerTagRange tag_range> + template <typename T, TrustedPointerTagRange tag_range> inline Tagged<T> GetTrustedData(IsolateForSandbox isolate) const; // Some code may encounter unreachable unusable objects and needs to skip @@ -498,7 +548,7 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { // "trusted" part containing a trusted pointer and the regular/untrusted part // containing a tagged pointer. In that case, code accessing the data field // will first load the trusted data field. If that is empty (i.e. - // kNullIndirectPointerHandle), it will then load the regular field. With + // kNullTrustedPointerHandle), it will then load the regular field. With // that, the only racy transition would be a tagged -> trusted transition // (one thread may first read the empty trusted pointer, then another thread // transitions to the trusted field, clearing the tagged field, and then the @@ -520,8 +570,8 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline bool HasUntrustedData() const; public: - static constexpr IndirectPointerTagRange kTrustedDataIndirectPointerRange = - kSFITrustedDataIndirectPointerRange; + static constexpr TrustedPointerTagRange kTrustedDataTrustedPointerRange = + kSFITrustedDataTrustedPointerRange; inline bool IsApiFunction() const; inline bool is_class_constructor() const; @@ -548,6 +598,11 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { DECL_GETTER(HasBaselineCode, bool) DECL_RELEASE_ACQUIRE_ACCESSORS(baseline_code, Tagged<Code>) inline void FlushBaselineCode(); + struct BytecodeArrays { + Tagged<BytecodeArray> original; + Tagged<BytecodeArray> active; + }; + inline BytecodeArrays GetBytecodeArrays(Isolate* isolate) const; inline Tagged<BytecodeArray> GetActiveBytecodeArray(Isolate* isolate) const; inline void SetActiveBytecodeArray(Tagged<BytecodeArray> bytecode, IsolateForSandbox isolate); @@ -646,9 +701,9 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline bool HasSharedName() const; // [flags] Bit field containing various flags about the function. - DECL_RELAXED_INT32_ACCESSORS(flags) + DECL_RELAXED_PRIMITIVE_ACCESSORS(flags, Flags) DECL_RELAXED_INT32_ACCESSORS(function_literal_id) - DECL_UINT8_ACCESSORS(flags2) + DECL_PRIMITIVE_ACCESSORS(flags2, Flags2) DECL_UINT16_ACCESSORS(age) @@ -907,11 +962,12 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { class BodyDescriptor; // Bailout reasons must fit in the DisabledOptimizationReason bitfield. - static_assert(DisabledOptimizationReasonBits::is_valid( + static_assert(Flags::DisabledOptimizationReasonBits::is_valid( BailoutReason::kLastErrorMessage)); - static_assert(FunctionKindBits::is_valid(FunctionKind::kLastFunctionKind)); - static_assert(FunctionSyntaxKindBits::is_valid( + static_assert( + Flags::FunctionKindBits::is_valid(FunctionKind::kLastFunctionKind)); + static_assert(Flags::FunctionSyntaxKindBits::is_valid( FunctionSyntaxKind::kLastFunctionSyntaxKind)); // Sets the bytecode in {shared}'s DebugInfo as the bytecode to @@ -953,8 +1009,8 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline uint16_t get_property_estimate_from_literal(FunctionLiteral* literal); // For ease of use of the BITFIELD macro. - inline int32_t relaxed_flags() const; - inline void set_relaxed_flags(int32_t flags); + inline Flags relaxed_flags() const; + inline void set_relaxed_flags(Flags flags); template <typename Impl> friend class FactoryBase; @@ -965,23 +1021,32 @@ V8_OBJECT class SharedFunctionInfo : public HeapObject { inline Tagged<BytecodeArray> GetBytecodeArrayInternal(Isolate* isolate) const; public: - TrustedPointerMember<ExposedTrustedObject, kTrustedDataIndirectPointerRange> + V8_TQ_CUSTOM_WEAK + TrustedPointerMember<ExposedTrustedObject, kTrustedDataTrustedPointerRange> trusted_function_data_; - TaggedMember<Object> untrusted_function_data_; - TaggedMember<NameOrScopeInfoT> name_or_scope_info_; + // Set the function data to the "illegal" builtin by default. Ideally we'd use + // some sort of "uninitialized" marker here, but it's cheaper to use a valid + // builtin and avoid having to do uninitialized checks elsewhere. + TaggedMember<Object> untrusted_function_data_{ + Smi::FromEnum(Builtin::kIllegal)}; + // Set the name to the no-name sentinel, this can be updated later. + TaggedMember<UnionOf<Smi, String, ScopeInfo>> name_or_scope_info_{ + kNoSharedNameSentinel}; TaggedMember<UnionOf<ScopeInfo, FeedbackMetadata, TheHole>> outer_scope_info_or_feedback_metadata_; - TaggedMember<HeapObject> script_; - uint16_t length_; - uint16_t formal_parameter_count_; - uint16_t function_token_offset_; - uint8_t expected_nof_properties_; - uint8_t flags2_; - std::atomic<uint32_t> flags_; - std::atomic<int32_t> function_literal_id_; + TaggedMember<HeapObject> script_ V8_TQ_TYPE(Script | Undefined); + uint16_t length_ = 0; + uint16_t formal_parameter_count_ = JSParameterCount(0); + uint16_t function_token_offset_ = 0; + uint8_t expected_nof_properties_ = 0; + Flags2 flags2_; + // All flags default to false or 0, except ConstructAsBuiltinBit just because + // we're using the kIllegal builtin. + std::atomic<Flags> flags_ = Flags().with_construct_as_builtin(true); + std::atomic<int32_t> function_literal_id_ = kInvalidInfoId; int32_t unique_id_; - std::atomic<uint16_t> age_; - std::atomic<uint16_t> feedback_slot_; + std::atomic<uint16_t> age_ = 0; + std::atomic<uint16_t> feedback_slot_ = 0; } V8_OBJECT_END; inline constexpr int SharedFunctionInfo::kEndOfStrongFieldsOffset = @@ -1105,9 +1170,9 @@ V8_OBJECT class OnHeapBasicBlockProfilerData : public HeapObject { return sizeof(OnHeapBasicBlockProfilerData); } - TaggedMember<ByteArray> block_ids_; - TaggedMember<ByteArray> counts_; - TaggedMember<ByteArray> branches_; + TaggedMember<ByteArray> block_ids_ V8_TQ_TYPE(FixedInt32Array); + TaggedMember<ByteArray> counts_ V8_TQ_TYPE(FixedUInt32Array); + TaggedMember<ByteArray> branches_ V8_TQ_TYPE(PodArrayOfIntegerPairs); TaggedMember<String> name_; TaggedMember<String> schedule_; TaggedMember<String> code_; diff --git a/deps/v8/src/objects/shared-function-info.tq b/deps/v8/src/objects/shared-function-info.tq index b46945f2c385..b53ecd4ae328 100644 --- a/deps/v8/src/objects/shared-function-info.tq +++ b/deps/v8/src/objects/shared-function-info.tq @@ -22,7 +22,7 @@ type FunctionSyntaxKind extends uint8 constexpr 'FunctionSyntaxKind'; type BailoutReason extends uint8 constexpr 'BailoutReason'; type CachedTieringDecision extends uint8 constexpr 'CachedTieringDecision'; -@cppScope('SharedFunctionInfo') +@cppScope('SharedFunctionInfo::Flags') bitfield struct SharedFunctionInfoFlags extends uint32 { // Have FunctionKind first to make it cheaper to access. function_kind: FunctionKind: 5 bit; @@ -45,7 +45,7 @@ bitfield struct SharedFunctionInfoFlags extends uint32 { class_initializer_allows_await: bool: 1 bit; } -@cppScope('SharedFunctionInfo') +@cppScope('SharedFunctionInfo::Flags2') bitfield struct SharedFunctionInfoFlags2 extends uint8 { class_scope_has_private_brand: bool: 1 bit; has_static_private_methods_or_accessors: bool: 1 bit; @@ -77,7 +77,7 @@ extern class SharedFunctionInfo extends HeapObject { // trusted_function_data in the future (see TODO above), then maybe consider // renaming this field as untrusted_function_data may be a bit awkward. untrusted_function_data: Object; - name_or_scope_info: String|NoSharedNameSentinel|ScopeInfo; + name_or_scope_info: Smi|String|ScopeInfo; outer_scope_info_or_feedback_metadata: ScopeInfo|FeedbackMetadata|TheHole; script: Script|Undefined; // [length]: The function length - usually the number of declared parameters diff --git a/deps/v8/src/objects/simd.cc b/deps/v8/src/objects/simd.cc index 3ce30aa7fd79..336bc03e8203 100644 --- a/deps/v8/src/objects/simd.cc +++ b/deps/v8/src/objects/simd.cc @@ -1185,7 +1185,7 @@ bool Uint8ArrayFromHexWithSSE(const base::Vector<T>& input_vector, // Check if it is {} (includes invalid hex values) if (!maybe_uint8_low_nibbles.has_value()) { - return false; + break; } __m128i uint8_low_nibbles = maybe_uint8_low_nibbles.value(); @@ -1197,7 +1197,7 @@ bool Uint8ArrayFromHexWithSSE(const base::Vector<T>& input_vector, // Check if it is {} (includes invalid hex values) if (!maybe_uint8_high_nibbles.has_value()) { - return false; + break; } __m128i uint8_high_nibbles = maybe_uint8_high_nibbles.value(); @@ -1309,8 +1309,9 @@ bool Uint8ArrayFromHexWithNeon(const base::Vector<T>& input_vector, if constexpr (std::is_same_v<T, const base::uc16>) { uint8x16_t second_part_first_batch = vld1q_u8(reinterpret_cast<const uint8_t*>(&input_vector[i + 8])); + // Saturate non-Latin-1 code units so hex validation rejects them. first_batch = - vmovn_high_u16(vmovn_u16(first_batch), second_part_first_batch); + vqmovn_high_u16(vqmovn_u16(first_batch), second_part_first_batch); } // Load second batch of 16 hex characters into a Neon register @@ -1322,8 +1323,9 @@ bool Uint8ArrayFromHexWithNeon(const base::Vector<T>& input_vector, if constexpr (std::is_same_v<T, const base::uc16>) { uint8x16_t second_part_second_batch = vld1q_u8(reinterpret_cast<const uint8_t*>(&input_vector[i + 24])); + // Saturate non-Latin-1 code units so hex validation rejects them. second_batch = - vmovn_high_u16(vmovn_u16(second_batch), second_part_second_batch); + vqmovn_high_u16(vqmovn_u16(second_batch), second_part_second_batch); } // low nibbles are values with even indexes in fist_batch. @@ -1359,7 +1361,7 @@ bool Uint8ArrayFromHexWithNeon(const base::Vector<T>& input_vector, // Check if it is {} (includes invalid hex values) if (!maybe_uint8_low_nibbles.has_value()) { - return false; + break; } uint8x16_t uint8_low_nibbles = maybe_uint8_low_nibbles.value(); @@ -1371,7 +1373,7 @@ bool Uint8ArrayFromHexWithNeon(const base::Vector<T>& input_vector, // Check if it is {} (includes invalid hex values) if (!maybe_uint8_high_nibbles.has_value()) { - return false; + break; } uint8x16_t uint8_high_nibbles = maybe_uint8_high_nibbles.value(); diff --git a/deps/v8/src/objects/slots-inl.h b/deps/v8/src/objects/slots-inl.h index 77e9d7027774..833e9cf7825f 100644 --- a/deps/v8/src/objects/slots-inl.h +++ b/deps/v8/src/objects/slots-inl.h @@ -239,6 +239,9 @@ Address ExternalPointerSlot::load(IsolateForSandbox isolate) { isolate.GetExternalPointerTableFor(tag_range_); ExternalPointerHandle handle = Relaxed_LoadHandle(); return table.Get(handle, tag_range_); +#elif !defined(V8_COMPRESS_POINTERS) + return static_cast<Address>(base::AsAtomicPointer::Acquire_Load( + reinterpret_cast<Address*>(address()))); #else return ReadMaybeUnalignedValue<Address>(address()); #endif // V8_ENABLE_SANDBOX @@ -329,11 +332,11 @@ void CppHeapPointerSlot::Relaxed_StoreHandle( #else void CppHeapPointerSlot::store(Address value) const { - base::AsAtomicPointer::Relaxed_Store(location(), value); + base::AsAtomicPointer::Release_Store(location(), value); } Address CppHeapPointerSlot::load() const { - return static_cast<Address>(base::AsAtomicPointer::Relaxed_Load(location())); + return static_cast<Address>(base::AsAtomicPointer::Acquire_Load(location())); } #endif // V8_COMPRESS_POINTERS @@ -369,96 +372,97 @@ void CppHeapPointerSlot::RestoreContentAfterSerialization( #endif // V8_COMPRESS_POINTERS } -Tagged<Object> IndirectPointerSlot::load(IsolateForSandbox isolate) const { +Tagged<Object> TrustedPointerSlot::load(IsolateForSandbox isolate) const { return Relaxed_Load(isolate); } -void IndirectPointerSlot::store(Tagged<ExposedTrustedObject> value) const { - return Relaxed_Store(value); +void TrustedPointerSlot::store(Tagged<ExposedTrustedObject> value) const { + return Release_Store(value); } -Tagged<Object> IndirectPointerSlot::Relaxed_Load( +Tagged<Object> TrustedPointerSlot::Relaxed_Load( IsolateForSandbox isolate) const { - IndirectPointerHandle handle = Relaxed_LoadHandle(); + TrustedPointerHandle handle = Relaxed_LoadHandle(); return ResolveHandle(handle, isolate); } -Tagged<Object> IndirectPointerSlot::Relaxed_Load_AllowUnpublished( +Tagged<Object> TrustedPointerSlot::Relaxed_Load_AllowUnpublished( IsolateForSandbox isolate) const { - IndirectPointerHandle handle = Relaxed_LoadHandle(); + TrustedPointerHandle handle = Relaxed_LoadHandle(); return ResolveHandle<kAllowUnpublishedEntries>(handle, isolate); } -Tagged<Object> IndirectPointerSlot::Acquire_Load( +Tagged<Object> TrustedPointerSlot::Acquire_Load( IsolateForSandbox isolate) const { - IndirectPointerHandle handle = Acquire_LoadHandle(); + TrustedPointerHandle handle = Acquire_LoadHandle(); return ResolveHandle(handle, isolate); } -void IndirectPointerSlot::Relaxed_Store( +void TrustedPointerSlot::Relaxed_Store( Tagged<ExposedTrustedObject> value) const { #ifdef V8_ENABLE_SANDBOX - IndirectPointerHandle handle = value->ReadField<IndirectPointerHandle>( - offsetof(ExposedTrustedObject, self_indirect_pointer_)); - DCHECK_NE(handle, kNullIndirectPointerHandle); + TrustedPointerHandle handle = value->ReadField<TrustedPointerHandle>( + offsetof(ExposedTrustedObject, self_trusted_pointer_)); + DCHECK_NE(handle, kNullTrustedPointerHandle); Relaxed_StoreHandle(handle); #else UNREACHABLE(); #endif // V8_ENABLE_SANDBOX } -void IndirectPointerSlot::Release_Store( +void TrustedPointerSlot::Release_Store( Tagged<ExposedTrustedObject> value) const { #ifdef V8_ENABLE_SANDBOX - IndirectPointerHandle handle = value->ReadField<IndirectPointerHandle>( - offsetof(ExposedTrustedObject, self_indirect_pointer_)); + TrustedPointerHandle handle = value->ReadField<TrustedPointerHandle>( + offsetof(ExposedTrustedObject, self_trusted_pointer_)); + DCHECK_NE(handle, kNullTrustedPointerHandle); Release_StoreHandle(handle); #else UNREACHABLE(); #endif // V8_ENABLE_SANDBOX } -IndirectPointerHandle IndirectPointerSlot::Relaxed_LoadHandle() const { +TrustedPointerHandle TrustedPointerSlot::Relaxed_LoadHandle() const { return base::AsAtomic32::Relaxed_Load(location()); } -IndirectPointerHandle IndirectPointerSlot::Acquire_LoadHandle() const { +TrustedPointerHandle TrustedPointerSlot::Acquire_LoadHandle() const { return base::AsAtomic32::Acquire_Load(location()); } -void IndirectPointerSlot::Relaxed_StoreHandle( - IndirectPointerHandle handle) const { +void TrustedPointerSlot::Relaxed_StoreHandle( + TrustedPointerHandle handle) const { return base::AsAtomic32::Relaxed_Store(location(), handle); } -void IndirectPointerSlot::Release_StoreHandle( - IndirectPointerHandle handle) const { +void TrustedPointerSlot::Release_StoreHandle( + TrustedPointerHandle handle) const { return base::AsAtomic32::Release_Store(location(), handle); } -bool IndirectPointerSlot::IsEmpty() const { - return Relaxed_LoadHandle() == kNullIndirectPointerHandle; +bool TrustedPointerSlot::IsEmpty() const { + return Relaxed_LoadHandle() == kNullTrustedPointerHandle; } -template <IndirectPointerSlot::TagCheckStrictness allow_unpublished> -Tagged<Object> IndirectPointerSlot::ResolveHandle( - IndirectPointerHandle handle, IsolateForSandbox isolate) const { +template <TrustedPointerSlot::TagCheckStrictness allow_unpublished> +Tagged<Object> TrustedPointerSlot::ResolveHandle( + TrustedPointerHandle handle, IsolateForSandbox isolate) const { #ifdef V8_ENABLE_SANDBOX // TODO(saelo) Maybe come up with a different entry encoding scheme that // returns Smi::zero for kNullCodePointerHandle? if (!handle) return Smi::zero(); - return ResolveIndirectPointerHandle<allow_unpublished>(handle, isolate); + return ResolveTrustedPointerHandle<allow_unpublished>(handle, isolate); #else UNREACHABLE(); #endif // V8_ENABLE_SANDBOX } #ifdef V8_ENABLE_SANDBOX -template <IndirectPointerSlot::TagCheckStrictness allow_unpublished> -Tagged<Object> IndirectPointerSlot::ResolveIndirectPointerHandle( - IndirectPointerHandle handle, IsolateForSandbox isolate) const { - DCHECK_NE(handle, kNullIndirectPointerHandle); +template <TrustedPointerSlot::TagCheckStrictness allow_unpublished> +Tagged<Object> TrustedPointerSlot::ResolveTrustedPointerHandle( + TrustedPointerHandle handle, IsolateForSandbox isolate) const { + DCHECK_NE(handle, kNullTrustedPointerHandle); const TrustedPointerTable& table = isolate.GetTrustedPointerTableFor(tag_range_); if constexpr (allow_unpublished == kAllowUnpublishedEntries) { diff --git a/deps/v8/src/objects/slots.h b/deps/v8/src/objects/slots.h index 5705a3b14c4d..e618def56448 100644 --- a/deps/v8/src/objects/slots.h +++ b/deps/v8/src/objects/slots.h @@ -12,14 +12,14 @@ #include "src/sandbox/cppheap-pointer.h" #include "src/sandbox/external-pointer-table.h" #include "src/sandbox/external-pointer.h" -#include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/isolate.h" +#include "src/sandbox/trusted-pointer-tag.h" namespace v8::internal { class Object; class ExposedTrustedObject; -template <typename T, IndirectPointerTagRange kTagRange> +template <typename T, TrustedPointerTagRange kTagRange> class TrustedPointerMember; using TaggedBase = TaggedImpl<HeapObjectReferenceType::STRONG, Address>; @@ -347,8 +347,7 @@ class ExternalPointerSlot // TODO(wingo): Remove if we switch to use the EPT for all external pointers // when pointer compression is enabled. bool HasExternalPointerHandle() const { - return V8_ENABLE_SANDBOX_BOOL || tag_range() == kArrayBufferExtensionTag || - tag_range() == kWaiterQueueNodeTag; + return V8_ENABLE_SANDBOX_BOOL || tag_range() == kArrayBufferExtensionTag; } inline ExternalPointerHandle Relaxed_LoadHandle() const; inline void Relaxed_StoreHandle(ExternalPointerHandle handle) const; @@ -444,16 +443,16 @@ class CppHeapPointerSlot RawContent content, const DisallowGarbageCollection& no_gc); }; -// An IndirectPointerSlot instance describes a 32-bit field ("slot") containing -// an IndirectPointerHandle, i.e. an index to an entry in a pointer table which +// An TrustedPointerSlot instance describes a 32-bit field ("slot") containing +// an TrustedPointerHandle, i.e. an index to an entry in a pointer table which // contains the "real" pointer to the referenced HeapObject. These slots are // used when the sandbox is enabled to securely reference HeapObjects outside // of the sandbox. -class IndirectPointerSlot - : public SlotBase<IndirectPointerSlot, IndirectPointerHandle, +class TrustedPointerSlot + : public SlotBase<TrustedPointerSlot, TrustedPointerHandle, kTaggedSize /* slot alignment */> { public: - IndirectPointerSlot() + TrustedPointerSlot() : SlotBase(kNullAddress) #ifdef V8_ENABLE_SANDBOX , @@ -462,7 +461,7 @@ class IndirectPointerSlot { } - explicit IndirectPointerSlot(Address ptr, IndirectPointerTagRange tag_range) + explicit TrustedPointerSlot(Address ptr, TrustedPointerTagRange tag_range) : SlotBase(ptr) #ifdef V8_ENABLE_SANDBOX , @@ -471,8 +470,8 @@ class IndirectPointerSlot { } - template <typename T, IndirectPointerTagRange kTagRange> - explicit IndirectPointerSlot(TrustedPointerMember<T, kTagRange>* member) + template <typename T, TrustedPointerTagRange kTagRange> + explicit TrustedPointerSlot(TrustedPointerMember<T, kTagRange>* member) #ifdef V8_ENABLE_SANDBOX : SlotBase(member->storage_address()), tag_range_(kTagRange) @@ -482,8 +481,8 @@ class IndirectPointerSlot { } - // Even though only HeapObjects can be stored into an IndirectPointerSlot, - // these slots can be empty (containing kNullIndirectPointerHandle), in which + // Even though only HeapObjects can be stored into an TrustedPointerSlot, + // these slots can be empty (containing kNullTrustedPointerHandle), in which // case load() will return Smi::zero(). inline Tagged<Object> load(IsolateForSandbox isolate) const; inline void store(Tagged<ExposedTrustedObject> value) const; @@ -501,17 +500,15 @@ class IndirectPointerSlot inline void Relaxed_Store(Tagged<ExposedTrustedObject> value) const; inline void Release_Store(Tagged<ExposedTrustedObject> value) const; - inline IndirectPointerHandle Relaxed_LoadHandle() const; - inline IndirectPointerHandle Acquire_LoadHandle() const; - inline void Relaxed_StoreHandle(IndirectPointerHandle handle) const; - inline void Release_StoreHandle(IndirectPointerHandle handle) const; + inline TrustedPointerHandle Relaxed_LoadHandle() const; + inline TrustedPointerHandle Acquire_LoadHandle() const; + inline void Relaxed_StoreHandle(TrustedPointerHandle handle) const; + inline void Release_StoreHandle(TrustedPointerHandle handle) const; #ifdef V8_ENABLE_SANDBOX - IndirectPointerTagRange tag_range() const { return tag_range_; } + TrustedPointerTagRange tag_range() const { return tag_range_; } #else - IndirectPointerTagRange tag_range() const { - return IndirectPointerTagRange(); - } + TrustedPointerTagRange tag_range() const { return TrustedPointerTagRange(); } #endif // Whether this slot is empty, i.e. contains a null handle. @@ -525,7 +522,7 @@ class IndirectPointerSlot // tag specified by the slot. enum TagCheckStrictness { kRequireExactMatch, kAllowUnpublishedEntries }; template <TagCheckStrictness allow_unpublished = kRequireExactMatch> - inline Tagged<Object> ResolveHandle(IndirectPointerHandle handle, + inline Tagged<Object> ResolveHandle(TrustedPointerHandle handle, IsolateForSandbox isolate) const; private: @@ -533,11 +530,11 @@ class IndirectPointerSlot // Retrieve the object referenced through the given trusted pointer handle // from the trusted pointer table. template <TagCheckStrictness allow_unpublished = kRequireExactMatch> - inline Tagged<Object> ResolveIndirectPointerHandle( - IndirectPointerHandle handle, IsolateForSandbox isolate) const; + inline Tagged<Object> ResolveTrustedPointerHandle( + TrustedPointerHandle handle, IsolateForSandbox isolate) const; // The tag associated with this slot. - IndirectPointerTagRange tag_range_; + TrustedPointerTagRange tag_range_; #endif // V8_ENABLE_SANDBOX }; @@ -566,7 +563,7 @@ class WriteProtectedSlot : public SlotT { // Copies tagged words from |src| to |dst|. The data spans must not overlap. // |src| and |dst| must be kTaggedSize-aligned. -inline void CopyTagged(Address dst, const Address src, size_t num_tagged); +inline void CopyTagged(Address dst, const Address src, uint32_t num_tagged); // Fills `start` with `count` `value`s. inline void MemsetTagged(Tagged_t* start, Tagged<MaybeObject> value, diff --git a/deps/v8/src/objects/smi.h b/deps/v8/src/objects/smi.h index 40428aad8fa8..62892a9c3ce8 100644 --- a/deps/v8/src/objects/smi.h +++ b/deps/v8/src/objects/smi.h @@ -27,11 +27,6 @@ class Smi : public AllStatic { static constexpr int kMinValue = kSmiMinValue; static constexpr int kMaxValue = kSmiMaxValue; - static inline constexpr Tagged<Smi> ToUint32Smi(Tagged<Smi> smi) { - if (smi.value() <= 0) return Smi::FromInt(0); - return Smi::FromInt(static_cast<uint32_t>(smi.value())); - } - // Convert a Smi object to an int. static inline constexpr int ToInt(const Tagged<Object> object) { return Tagged<Smi>(object.ptr()).value(); diff --git a/deps/v8/src/objects/sort-state.h b/deps/v8/src/objects/sort-state.h index 5ba129ca48da..8904afef8c5e 100644 --- a/deps/v8/src/objects/sort-state.h +++ b/deps/v8/src/objects/sort-state.h @@ -32,7 +32,7 @@ V8_OBJECT class SortState : public HeapObject { TaggedMember<JSReceiver> receiver_; TaggedMember<Map> initial_receiver_map_; TaggedMember<Number> initial_receiver_length_; - TaggedMember<Object> user_cmp_fn_; // Undefined|Callable + TaggedMember<UnionOf<JSCallable, Undefined>> user_cmp_fn_; TaggedMember<Boolean> is_reset_to_generic_; TaggedMember<Smi> min_gallop_; TaggedMember<Smi> pending_runs_size_; diff --git a/deps/v8/src/objects/source-text-module-inl.h b/deps/v8/src/objects/source-text-module-inl.h index 5c166bf69aae..f8fe8d75c5ed 100644 --- a/deps/v8/src/objects/source-text-module-inl.h +++ b/deps/v8/src/objects/source-text-module-inl.h @@ -14,6 +14,7 @@ #include "src/objects/objects-inl.h" #include "src/objects/oddball-predicates-inl.h" #include "src/objects/shared-function-info-inl.h" +#include "src/objects/struct-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -21,80 +22,72 @@ namespace v8 { namespace internal { -Tagged<String> ModuleRequest::specifier() const { return specifier_.load(); } -void ModuleRequest::set_specifier(Tagged<String> value, WriteBarrierMode mode) { - specifier_.store(this, value, mode); +ModuleRequest::ModuleRequest(const AllocationWitness& witness, + Tagged<String> specifier, ModuleImportPhase phase, + Tagged<FixedArray> import_attributes, int position) + : Struct(witness.roots().module_request_map()), + specifier_(witness, specifier), + import_attributes_(witness, import_attributes), + flags_(Smi::From31BitPattern(PhaseBits::encode(phase) | + PositionBits::encode(position))) { + DCHECK_GE(position, 0); } +Tagged<String> ModuleRequest::specifier() const { return specifier_.load(); } + Tagged<FixedArray> ModuleRequest::import_attributes() const { return import_attributes_.load(); } -void ModuleRequest::set_import_attributes(Tagged<FixedArray> value, - WriteBarrierMode mode) { - import_attributes_.store(this, value, mode); -} uint32_t ModuleRequest::flags() const { return static_cast<uint32_t>(flags_.load().value()); } -void ModuleRequest::set_flags(uint32_t value) { - flags_.store(this, Smi::From31BitPattern(value)); -} + +SourceTextModuleInfoEntry::SourceTextModuleInfoEntry( + const AllocationWitness& witness, + Tagged<UnionOf<String, Undefined>> export_name, + Tagged<UnionOf<String, Undefined>> local_name, + Tagged<UnionOf<String, Undefined>> import_name, int module_request, + int cell_index, int beg_pos, int end_pos) + : Struct(witness.roots().module_info_entry_map()), + export_name_(witness, export_name), + local_name_(witness, local_name), + import_name_(witness, import_name), + module_request_(Smi::FromInt(module_request)), + cell_index_(Smi::FromInt(cell_index)), + beg_pos_(Smi::FromInt(beg_pos)), + end_pos_(Smi::FromInt(end_pos)) {} Tagged<UnionOf<String, Undefined>> SourceTextModuleInfoEntry::export_name() const { return export_name_.load(); } -void SourceTextModuleInfoEntry::set_export_name( - Tagged<UnionOf<String, Undefined>> value, WriteBarrierMode mode) { - export_name_.store(this, value, mode); -} Tagged<UnionOf<String, Undefined>> SourceTextModuleInfoEntry::local_name() const { return local_name_.load(); } -void SourceTextModuleInfoEntry::set_local_name( - Tagged<UnionOf<String, Undefined>> value, WriteBarrierMode mode) { - local_name_.store(this, value, mode); -} Tagged<UnionOf<String, Undefined>> SourceTextModuleInfoEntry::import_name() const { return import_name_.load(); } -void SourceTextModuleInfoEntry::set_import_name( - Tagged<UnionOf<String, Undefined>> value, WriteBarrierMode mode) { - import_name_.store(this, value, mode); -} int SourceTextModuleInfoEntry::module_request() const { return module_request_.load().value(); } -void SourceTextModuleInfoEntry::set_module_request(int value) { - module_request_.store(this, Smi::FromInt(value)); -} int SourceTextModuleInfoEntry::cell_index() const { return cell_index_.load().value(); } -void SourceTextModuleInfoEntry::set_cell_index(int value) { - cell_index_.store(this, Smi::FromInt(value)); -} int SourceTextModuleInfoEntry::beg_pos() const { return beg_pos_.load().value(); } -void SourceTextModuleInfoEntry::set_beg_pos(int value) { - beg_pos_.store(this, Smi::FromInt(value)); -} int SourceTextModuleInfoEntry::end_pos() const { return end_pos_.load().value(); } -void SourceTextModuleInfoEntry::set_end_pos(int value) { - end_pos_.store(this, Smi::FromInt(value)); -} Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> SourceTextModule::code() const { @@ -180,6 +173,41 @@ uint32_t SourceTextModule::flags() const { return flags_.load().value(); } void SourceTextModule::set_flags(uint32_t value) { flags_.store(this, Smi::FromInt(value)); } + +template <typename ModuleT, Module::Status... kStates> +Tagged<SharedFunctionInfo> Module::InState<ModuleT, kStates...>::sfi() const + requires(IsAllowed<kUnlinked, kPreLinking, kEvaluatedError>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return CheckedCast<SharedFunctionInfo>(this->code()); +} + +template <typename ModuleT, Module::Status... kStates> +Tagged<JSFunction> Module::InState<ModuleT, kStates...>::function() const + requires(IsAllowed<kLinking>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return CheckedCast<JSFunction>(this->code()); +} + +template <typename ModuleT, Module::Status... kStates> +Tagged<JSGeneratorObject> Module::InState<ModuleT, kStates...>::generator() + const + requires(IsAllowed<kLinked, kEvaluating, kEvaluatingAsync, kEvaluated>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + return CheckedCast<JSGeneratorObject>(this->code()); +} + +template <typename ModuleT, Module::Status... kStates> +Tagged<JSAsyncFunctionObject> +Module::InState<ModuleT, kStates...>::async_function_object() const + requires(IsAllowed<kEvaluating, kEvaluatingAsync>()) +{ + DCHECK(IsStateIn<kStates...>(this->status())); + DCHECK(this->has_toplevel_await()); + return CheckedCast<JSAsyncFunctionObject>(this->code()); +} } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/source-text-module.cc b/deps/v8/src/objects/source-text-module.cc index 0c50a5139d6c..0789144c9420 100644 --- a/deps/v8/src/objects/source-text-module.cc +++ b/deps/v8/src/objects/source-text-module.cc @@ -94,15 +94,13 @@ Tagged<SharedFunctionInfo> SourceTextModule::GetSharedFunctionInfo() const { case kPreLinking: return Cast<SharedFunctionInfo>(code()); case kLinking: - return IsJSGeneratorObject(code()) - ? Cast<JSGeneratorObject>(code())->function()->shared() - : Cast<JSFunction>(code())->shared(); + return Cast<JSFunction>(code())->shared(); case kLinked: case kEvaluating: case kEvaluatingAsync: case kEvaluated: return Cast<JSGeneratorObject>(code())->function()->shared(); - case kErrored: + case kEvaluatedError: return Cast<SharedFunctionInfo>(code()); } UNREACHABLE(); @@ -146,7 +144,7 @@ int SourceTextModule::ImportIndex(int cell_index) { } void SourceTextModule::CreateIndirectExport( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, DirectHandle<InState<kPreLinking>> module, DirectHandle<String> name, DirectHandle<SourceTextModuleInfoEntry> entry) { Handle<ObjectHashTable> exports(module->exports(), isolate); DCHECK(IsTheHole(exports->Lookup(name))); @@ -155,7 +153,7 @@ void SourceTextModule::CreateIndirectExport( } void SourceTextModule::CreateExport(Isolate* isolate, - DirectHandle<SourceTextModule> module, + DirectHandle<InState<kPreLinking>> module, int cell_index, DirectHandle<FixedArray> names) { const uint32_t names_len = names->ulength().value(); @@ -210,7 +208,10 @@ void SourceTextModule::StoreVariable(DirectHandle<SourceTextModule> module, } MaybeHandle<Cell> SourceTextModule::ResolveExport( - Isolate* isolate, Handle<SourceTextModule> module, + Isolate* isolate, + Handle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, kEvaluated, + kEvaluatedError>> + module, DirectHandle<String> module_specifier, Handle<String> export_name, MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) { DCHECK(!export_name.is_null()); @@ -250,6 +251,7 @@ MaybeHandle<Cell> SourceTextModule::ResolveExport( resolve_set); } + auto linking_module = CheckedCast<InState<kPreLinking, kLinking>>(module); DCHECK(IsSourceTextModuleInfoEntry(*object)); // Not yet resolved indirect export. auto entry = Cast<SourceTextModuleInfoEntry>(object); @@ -258,28 +260,32 @@ MaybeHandle<Cell> SourceTextModule::ResolveExport( ? MaybeHandle<String>() : handle(Cast<String>(entry->import_name()), isolate); - Handle<Script> script(module->GetScript(), isolate); + Handle<Script> script(linking_module->GetScript(), isolate); MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); Handle<Cell> cell; - if (!ResolveImport(isolate, module, import_name, entry->module_request(), - new_loc, must_resolve, resolve_set) + if (!ResolveImport(isolate, linking_module, import_name, + entry->module_request(), new_loc, must_resolve, + resolve_set) .ToHandle(&cell)) { return MaybeHandle<Cell>(); } // The export table may have changed but the entry in question should be // unchanged. - Handle<ObjectHashTable> exports(module->exports(), isolate); + Handle<ObjectHashTable> exports(linking_module->exports(), isolate); DCHECK(IsSourceTextModuleInfoEntry(exports->Lookup(export_name))); exports = ObjectHashTable::Put(isolate, exports, export_name, cell); - module->set_exports(*exports); + linking_module->set_exports(*exports); return cell; } MaybeHandle<Cell> SourceTextModule::ResolveImport( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, MaybeHandle<String> maybe_name, int module_request_index, MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) { DirectHandle<ModuleRequest> module_request( @@ -331,7 +337,10 @@ MaybeHandle<Cell> SourceTextModule::ResolveImport( } MaybeHandle<Cell> SourceTextModule::ResolveExportUsingStarExports( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, DirectHandle<String> module_specifier, Handle<String> export_name, MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) { if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) { @@ -371,11 +380,14 @@ MaybeHandle<Cell> SourceTextModule::ResolveExportUsingStarExports( if (!unique_cell.is_null()) { // Found a unique star export for this name. - Handle<ObjectHashTable> exports(module->exports(), isolate); - DCHECK(IsTheHole(exports->Lookup(export_name))); - exports = - ObjectHashTable::Put(isolate, exports, export_name, unique_cell); - module->set_exports(*exports); + if (DirectHandle<InState<kPreLinking, kLinking>> linking_module; + TryCast(module, &linking_module)) { + Handle<ObjectHashTable> exports(linking_module->exports(), isolate); + DCHECK(IsTheHole(exports->Lookup(export_name))); + exports = + ObjectHashTable::Put(isolate, exports, export_name, unique_cell); + linking_module->set_exports(*exports); + } return unique_cell; } } @@ -392,7 +404,7 @@ MaybeHandle<Cell> SourceTextModule::ResolveExportUsingStarExports( } bool SourceTextModule::PrepareInstantiate( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, DirectHandle<InState<kPreLinking>> module, v8::Local<v8::Context> context, const Module::UserResolveCallbacks& callbacks) { // One of the callbacks must be set, otherwise we cannot resolve. @@ -420,7 +432,7 @@ bool SourceTextModule::PrepareInstantiate( .module_callback( context, v8::Utils::ToLocal(specifier), v8::Utils::FixedArrayToLocal(import_attributes), - v8::Utils::ToLocal(Cast<Module>(module))) + v8::Utils::ToLocal(DirectHandle<Module>(module))) .ToLocal(&api_requested_module)) { return false; } @@ -428,7 +440,8 @@ bool SourceTextModule::PrepareInstantiate( DCHECK_NOT_NULL(callbacks.module_callback_by_index); if (!callbacks .module_callback_by_index( - context, i, v8::Utils::ToLocal(Cast<Module>(module))) + context, i, + v8::Utils::ToLocal(DirectHandle<Module>(module))) .ToLocal(&api_requested_module)) { return false; } @@ -446,7 +459,7 @@ bool SourceTextModule::PrepareInstantiate( .source_callback( context, v8::Utils::ToLocal(specifier), v8::Utils::FixedArrayToLocal(import_attributes), - v8::Utils::ToLocal(Cast<Module>(module))) + v8::Utils::ToLocal(DirectHandle<Module>(module))) .ToLocal(&api_requested_module_source)) { return false; } @@ -454,7 +467,8 @@ bool SourceTextModule::PrepareInstantiate( DCHECK_NOT_NULL(callbacks.source_callback_by_index); if (!callbacks .source_callback_by_index( - context, i, v8::Utils::ToLocal(Cast<Module>(module))) + context, i, + v8::Utils::ToLocal(DirectHandle<Module>(module))) .ToLocal(&api_requested_module_source)) { return false; } @@ -477,8 +491,8 @@ bool SourceTextModule::PrepareInstantiate( if (module_request->phase() == ModuleImportPhase::kSource) { continue; } - DirectHandle<Module> requested_module( - Cast<Module>(requested_modules->get(i)), isolate); + Handle<Module> requested_module(Cast<Module>(requested_modules->get(i)), + isolate); if (!Module::PrepareInstantiate(isolate, requested_module, context, callbacks)) { return false; @@ -514,11 +528,26 @@ bool SourceTextModule::PrepareInstantiate( return true; } -bool SourceTextModule::RunInitializationCode( - Isolate* isolate, DirectHandle<SourceTextModule> module) { - DCHECK_EQ(module->status(), kLinking); - DirectHandle<JSFunction> function(CheckedCast<JSFunction>(module->code()), - isolate); +Handle<SourceTextModule::InState<Module::kLinking>> +SourceTextModule::TransitionToLinking( + Isolate* isolate, Handle<InState<kPreLinking>> module, + ZoneForwardList<Handle<InState<kLinking>>>* stack, unsigned* dfs_index) { + DirectHandle<SharedFunctionInfo> shared(module->sfi(), isolate); + DirectHandle<JSFunction> function = + Factory::JSFunctionBuilder{isolate, shared, isolate->native_context()} + .Build(); + module->set_code(*function); + Handle<InState<kLinking>> linking = TransitionStatus<kLinking>(module); + linking->set_dfs_index(*dfs_index); + linking->set_dfs_ancestor_index(*dfs_index); + (*dfs_index)++; + stack->push_front(linking); + return linking; +} + +MaybeDirectHandle<JSGeneratorObject> SourceTextModule::RunInitializationCode( + Isolate* isolate, DirectHandle<InState<kLinking>> module) { + DirectHandle<JSFunction> function(module->function(), isolate); DCHECK_EQ(MODULE_SCOPE, function->shared()->scope_info()->scope_type()); DirectHandle<Object> receiver = isolate->factory()->undefined_value(); @@ -532,125 +561,58 @@ bool SourceTextModule::RunInitializationCode( DirectHandle<Object> generator; if (!maybe_generator.ToHandle(&generator)) { DCHECK(isolate->has_exception()); - return false; + return {}; } DCHECK_EQ(*function, Cast<JSGeneratorObject>(generator)->function()); - module->set_code(Cast<JSGeneratorObject>(*generator)); - return true; + return Cast<JSGeneratorObject>(generator); } -// https://tc39.es/ecma262/#sec-innermoduleevaluation and -// https://tc39.es/ecma262/#sec-innermodulelinking -bool SourceTextModule::MaybeTransitionComponent( - Isolate* isolate, DirectHandle<SourceTextModule> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status) { - DCHECK(new_status == kLinked || new_status == kEvaluated); - +// https://tc39.es/ecma262/#sec-innermodulelinking and +// https://tc39.es/ecma262/#sec-innermoduleevaluation +template <Module::Status kFromState, typename TransitionFn> +void SourceTextModule::TransitionComponent( + DirectHandle<InState<kFromState>> module, + ZoneForwardList<Handle<InState<kFromState>>>* stack, Status trace_status, + TransitionFn&& transition_ancestor) { #ifdef DEBUG if (v8_flags.trace_module_status) { StdoutStream os; os << "Transitioning strongly connected module graph component to " - << Module::StatusString(new_status) << " {\n"; + << Module::StatusString(trace_status) << " {\n"; } #endif // DEBUG - // Below, N/M means step N in InnerModuleEvaluation and step M in - // InnerModuleLinking. + // Below, N/M means step N in InnerModuleLinking and step M in + // InnerModuleEvaluation. - // 14/11. Assert: module occurs exactly once in stack. - SLOW_DCHECK( - // {module} is on the {stack}. - std::count_if(stack->begin(), stack->end(), [&](DirectHandle<Module> m) { - return *m == *module; - }) == 1); + // 11/14. Assert: module occurs exactly once in stack. + SLOW_DCHECK(std::count_if(stack->begin(), stack->end(), + [&](DirectHandle<InState<kFromState>> m) { + return *m == *module; + }) == 1); - // 15/12. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]]. + // 12/15. Assert: module.[[DFSAncestorIndex]] ≤ module.[[DFSIndex]]. DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index()); - // 16/13. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then + // 13/16. If module.[[DFSAncestorIndex]] = module.[[DFSIndex]], then if (module->dfs_ancestor_index() == module->dfs_index()) { // This is the root of its strongly connected component. - DirectHandle<SourceTextModule> cycle_root = module; - DirectHandle<SourceTextModule> ancestor; - // This loop handles the loops in both InnerModuleEvaluation and - // InnerModuleLinking. - // - // InnerModuleEvaluation - // - // a. Let done be false. - // b. Repeat, while done is false, - // i. Let requiredModule be the last element of stack. - // ii. Remove the last element of stack. - // iii. Assert: requiredModule is a Cyclic Module Record. - // iv. Assert: requiredModule.[[AsyncEvaluationOrder]] is either an - // integer or unset. - // v. If requiredModule.[[AsyncEvaluation]] is false, set - // requiredModule.[[Status]] to EVALUATED. - // vi. Else, set requiredModule.[[Status]] to EVALUATING-ASYNC. - // vii. If requiredModule and module are the same Module Record, set done - // to true. - // viii. Assert: requiredModule.[[CycleRoot]] is empty. - // ix. Set requiredModule.[[CycleRoot]] to module. - // - // InnerModuleLinking - // https://tc39.es/ecma262/#sec-InnerModuleLinking - // + DisallowGarbageCollection no_gc; // a. Let done be false. + bool done; // b. Repeat, while done is false, - // i. Let requiredModule be the last element of stack. - // ii. Remove the last element of stack. - // iii. Assert: requiredModule is a Cyclic Module Record. - // iv. Set requiredModule.[[Status]] to LINKED. - // v. If requiredModule and module are the same Module Record, set done - // to true. - if (new_status == kLinked) { - // In the spec, InnerModuleLinking step 10 performs - // ? module.InitializeEnvironment() for every module in the strongly - // connected component (SCC) before the SCC root reaches the infallible - // status-transition loop at step 13, ensuring that all modules in an SCC - // transition to ~linked~ atomically and that on abrupt completion every - // module on stack still has [[Status]] == ~linking~ (Link step 4.a.i, - // https://tc39.es/ecma262/#sec-moduledeclarationlinking). - // - // V8 splits InitializeEnvironment() into two parts: static import and - // indirect-export resolution runs at the step-10 position in - // FinishInstantiate, while environment and namespace instantiation - // (RunInitializationCode) is deferred until all imports and indirect - // exports across the SCC have been resolved. Because - // RunInitializationCode can fail (e.g. stack overflow or termination), it - // must complete for every module in the SCC before any module in the SCC - // transitions to kLinked below. - bool found = false; - for (DirectHandle<SourceTextModule> required_module : *stack) { - DCHECK_EQ(required_module->status(), kLinking); - if (!SourceTextModule::RunInitializationCode(isolate, - required_module)) { - return false; - } - if (*required_module == *module) { - found = true; - break; - } - } - CHECK(found); - } do { - ancestor = stack->front(); + // i. Let requiredModule be the last element of stack. + Handle<InState<kFromState>> ancestor = stack->front(); + // ii. Remove the last element of stack. stack->pop_front(); - DCHECK_EQ(ancestor->status(), - new_status == kLinked ? kLinking : kEvaluating); - if (new_status == kLinked) { - ancestor->SetStatus(kLinked); - } else { - DCHECK(ancestor->async_evaluation_ordinal() == kNotAsyncEvaluated || - ancestor->HasAsyncEvaluationOrdinal()); - DCHECK(IsTheHole(ancestor->cycle_root())); - ancestor->set_cycle_root(*cycle_root); - ancestor->SetStatus(ancestor->HasAsyncEvaluationOrdinal() - ? kEvaluatingAsync - : kEvaluated); - } - } while (*ancestor != *module); + // iii. Assert: requiredModule is a Cyclic Module Record. + DCHECK(IsSourceTextModule(*ancestor)); + // v/vii. If requiredModule and module are the same Module Record, set + // done to true. + done = *ancestor == *module; + transition_ancestor(ancestor); + } while (!done); } #ifdef DEBUG if (v8_flags.trace_module_status) { @@ -658,26 +620,90 @@ bool SourceTextModule::MaybeTransitionComponent( os << "}\n"; } #endif // DEBUG +} + +// https://tc39.es/ecma262/#sec-innermodulelinking +bool SourceTextModule::TransitionComponentToLinked( + Isolate* isolate, DirectHandle<InState<kLinking>> module, + ZoneForwardList<Handle<InState<kLinking>>>* stack) { + // In the spec, InnerModuleLinking step 10 performs + // ? module.InitializeEnvironment() for every module in the strongly + // connected component (SCC) before the SCC root reaches the infallible + // status-transition loop at step 13, ensuring that all modules in an SCC + // transition to ~linked~ atomically and that on abrupt completion every + // module on stack still has [[Status]] == ~linking~ (Link step 4.a.i, + // https://tc39.es/ecma262/#sec-moduledeclarationlinking). + // + // V8 splits InitializeEnvironment() into two parts: static import and + // indirect-export resolution runs at the step-10 position in + // FinishInstantiate, while environment and namespace instantiation + // (RunInitializationCode) is deferred until all imports and indirect + // exports across the SCC have been resolved. Because + // RunInitializationCode can fail (e.g. stack overflow or termination), it + // must complete for every module in the SCC before any module in the SCC + // transitions to kLinked below. + DirectHandleSmallVector<JSGeneratorObject, 4> generators(isolate); + if (module->dfs_ancestor_index() == module->dfs_index()) { + bool found = false; + for (DirectHandle<InState<kLinking>> required_module : *stack) { + DirectHandle<JSGeneratorObject> generator; + if (!SourceTextModule::RunInitializationCode(isolate, required_module) + .ToHandle(&generator)) { + return false; + } + generators.push_back(generator); + if (*required_module == *module) { + found = true; + break; + } + } + CHECK(found); + } + + auto gen_it = generators.begin(); + TransitionComponent(module, stack, kLinked, + [&](Handle<InState<kLinking>> ancestor) { + // iv. Set requiredModule.[[Status]] to LINKED. + ancestor->set_code(**gen_it++); + TransitionStatus<kLinked>(ancestor); + }); + DCHECK_EQ(gen_it, generators.end()); return true; } +// https://tc39.es/ecma262/#sec-innermoduleevaluation +void SourceTextModule::TransitionComponentAfterEvaluation( + DirectHandle<InState<kEvaluating>> module, + ZoneForwardList<Handle<InState<kEvaluating>>>* stack) { + TransitionComponent( + module, stack, kEvaluated, [&](Handle<InState<kEvaluating>> ancestor) { + // iv. Assert: requiredModule.[[AsyncEvaluationOrder]] is either an + // integer or unset. + DCHECK(ancestor->async_evaluation_ordinal() == kNotAsyncEvaluated || + ancestor->HasAsyncEvaluationOrdinal()); + // viii. Assert: requiredModule.[[CycleRoot]] is empty. + DCHECK(IsTheHole(ancestor->cycle_root())); + // ix. Set requiredModule.[[CycleRoot]] to module. + ancestor->set_cycle_root(*module); + // v. If requiredModule.[[AsyncEvaluation]] is false, set + // requiredModule.[[Status]] to EVALUATED. + // vi. Else, set requiredModule.[[Status]] to EVALUATING-ASYNC. + if (ancestor->HasAsyncEvaluationOrdinal()) { + TransitionStatus<kEvaluatingAsync>(ancestor); + } else { + TransitionStatus<kEvaluated>(ancestor); + } + }); +} + bool SourceTextModule::FinishInstantiate( - Isolate* isolate, Handle<SourceTextModule> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, + Isolate* isolate, Handle<InState<kPreLinking>> pre_linking_module, + ZoneForwardList<Handle<InState<kLinking>>>* stack, unsigned* dfs_index, Zone* zone, unsigned depth, unsigned* max_depth) { // Instantiate SharedFunctionInfo and mark module as instantiating for // the recursion. - DirectHandle<SharedFunctionInfo> shared( - Cast<SharedFunctionInfo>(module->code()), isolate); - DirectHandle<JSFunction> function = - Factory::JSFunctionBuilder{isolate, shared, isolate->native_context()} - .Build(); - module->set_code(*function); - module->SetStatus(kLinking); - module->set_dfs_index(*dfs_index); - module->set_dfs_ancestor_index(*dfs_index); - stack->push_front(module); - (*dfs_index)++; + Handle<InState<kLinking>> module = + TransitionToLinking(isolate, pre_linking_module, stack, dfs_index); // Recurse. DirectHandle<FixedArray> module_requests(module->info()->module_requests(), @@ -698,22 +724,23 @@ bool SourceTextModule::FinishInstantiate( return false; } - DCHECK_NE(requested_module->status(), kEvaluating); - DCHECK_GE(requested_module->status(), kLinking); SLOW_DCHECK( // {requested_module} is instantiating iff it's on the {stack}. (requested_module->status() == kLinking) == - std::count_if( - stack->begin(), stack->end(), - [&](DirectHandle<Module> m) { return *m == *requested_module; })); - - if (requested_module->status() == kLinking) { - // SyntheticModules go straight to kLinked so this must be a - // SourceTextModule - module->set_dfs_ancestor_index(std::min( - module->dfs_ancestor_index(), - Cast<SourceTextModule>(*requested_module)->dfs_ancestor_index())); - } + std::count_if(stack->begin(), stack->end(), + [&](DirectHandle<InState<kLinking>> m) { + return *m == *requested_module; + })); + + MatchState( + requested_module, + [&](DirectHandle<Module::InState<Module, kLinking>> m) { + // SyntheticModules go straight to kLinked so this must be a + // SourceTextModule. + module->UpdateDfsAncestorIndex(Cast<InState<kLinking>>(m)); + }, + [](DirectHandle<Module::InState<Module, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>>) {}); } Handle<Script> script(module->GetScript(), isolate); @@ -724,7 +751,7 @@ bool SourceTextModule::FinishInstantiate( // // Note: Environment and namespace creation (InitializeEnvironment steps 5-6 // and 7.b-26) is performed by RunInitializationCode in - // MaybeTransitionComponent once all imports and indirect exports in the + // TransitionComponentToLinked once all imports and indirect exports in the // strongly connected component are resolved. DirectHandle<FixedArray> regular_imports(module_info->regular_imports(), isolate); @@ -736,7 +763,6 @@ bool SourceTextModule::FinishInstantiate( MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); ResolveSet resolve_set(zone); DirectHandle<Cell> cell; - DCHECK_EQ(module->status(), Module::kLinking); if (!ResolveImport(isolate, module, name, entry->module_request(), loc, true, &resolve_set) .ToHandle(&cell)) { @@ -763,18 +789,17 @@ bool SourceTextModule::FinishInstantiate( } } - return MaybeTransitionComponent(isolate, module, stack, kLinked); + return TransitionComponentToLinked(isolate, module, stack); } -void SourceTextModule::FetchStarExports(Isolate* isolate, - Handle<SourceTextModule> module, - Zone* zone, - UnorderedModuleSet* visited) { - DCHECK_GE(module->status(), Module::kLinking); - +void SourceTextModule::FetchStarExports( + Isolate* isolate, + Handle<InState<kLinking, kLinked, kEvaluating, kEvaluatingAsync, kEvaluated, + kEvaluatedError>> + module, + Zone* zone, UnorderedModuleSet* visited) { // Shortcut. - if (!IsUndefined(module->module_namespace()) && - IsJSModuleNamespace(Cast<Cell>(module->module_namespace())->value())) { + if (module->ExportsFinalized()) { return; } @@ -811,9 +836,13 @@ void SourceTextModule::FetchStarExports(Isolate* isolate, isolate); // Recurse. - if (IsSourceTextModule(*requested_module)) { - FetchStarExports(isolate, Cast<SourceTextModule>(requested_module), zone, - visited); + if (Handle<SourceTextModule> requested_stm; + TryCast(requested_module, &requested_stm)) { + FetchStarExports( + isolate, + CheckedCast<InState<kLinking, kLinked, kEvaluating, kEvaluatingAsync, + kEvaluated, kEvaluatedError>>(requested_stm), + zone, visited); } // Collect all of [requested_module]'s exports that must be added to @@ -854,19 +883,19 @@ void SourceTextModule::FetchStarExports(Isolate* isolate, DCHECK(IsCell(*elem.second)); exports = ObjectHashTable::Put(isolate, exports, elem.first, elem.second); } - module->set_exports(*exports); + module->set_star_exports(*exports); } void SourceTextModule::GatherAvailableAncestors( - Isolate* isolate, Zone* zone, Handle<SourceTextModule> start, + Isolate* isolate, Zone* zone, Handle<InState<kEvaluated>> start, AvailableAncestorsSet* exec_list) { // The spec algorithm is recursive. It is transformed to an equivalent // iterative one here. - ZoneStack<Handle<SourceTextModule>> worklist(zone); + ZoneStack<Handle<InState<kEvaluatingAsync, kEvaluated>>> worklist(zone); worklist.push(start); while (!worklist.empty()) { - DirectHandle<SourceTextModule> module = worklist.top(); + Handle<InState<kEvaluatingAsync, kEvaluated>> module = worklist.top(); worklist.pop(); // 1. For each Cyclic Module Record m of module.[[AsyncParentModules]], do @@ -876,30 +905,38 @@ void SourceTextModule::GatherAvailableAncestors( Handle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i); // a. If execList does not contain m and m.[[EvaluationError]] is empty, // then - if (m->status() != kErrored && exec_list->find(m) == exec_list->end()) { - // i. Assert: m.[[Status]] is EVALUATING-ASYNC. - DCHECK_EQ(m->status(), kEvaluatingAsync); - // ii. Assert: m.[[CycleRoot]] is not empty. - DCHECK(!IsTheHole(m->cycle_root())); - // iii. If m.[[CycleRoot]].[[EvaluationError]] is empty, then - if (m->GetCycleRoot(isolate)->status() != kErrored) { - // 1. Assert: m.[[AsyncEvaluation]] is true. - DCHECK(m->HasAsyncEvaluationOrdinal()); - // 2. Assert: m.[[PendingAsyncDependencies]] > 0. - DCHECK(m->HasPendingAsyncDependencies()); - // 3. Set m.[[PendingAsyncDependencies]] to - // m.[[PendingAsyncDependencies]] - 1. - m->DecrementPendingAsyncDependencies(); - // 4. If m.[[PendingAsyncDependencies]] = 0, then - if (!m->HasPendingAsyncDependencies()) { - // a. Append m to execList. - exec_list->insert(m); - // b. If m.[[HasTLA]] is false, - // perform ! GatherAvailableAncestors(m, execList). - if (!m->has_toplevel_await()) worklist.push(m); - } - } - } + MatchState( + m, [](DirectHandle<InState<kEvaluatedError>>) {}, + [&](Handle<InState<kEvaluatingAsync>> evaluating_parent) { + // i. Assert: m.[[Status]] is EVALUATING-ASYNC. + DCHECK_EQ(evaluating_parent->status(), kEvaluatingAsync); + if (exec_list->find(evaluating_parent) != exec_list->end()) { + return; + } + // ii. Assert: m.[[CycleRoot]] is not empty. + DCHECK(!IsTheHole(evaluating_parent->cycle_root())); + // iii. If m.[[CycleRoot]].[[EvaluationError]] is empty, then + if (evaluating_parent->GetCycleRoot(isolate)->status() != + kEvaluatedError) { + // 1. Assert: m.[[AsyncEvaluation]] is true. + DCHECK(evaluating_parent->HasAsyncEvaluationOrdinal()); + // 2. Assert: m.[[PendingAsyncDependencies]] > 0. + DCHECK(evaluating_parent->HasPendingAsyncDependencies()); + // 3. Set m.[[PendingAsyncDependencies]] to + // m.[[PendingAsyncDependencies]] - 1. + evaluating_parent->DecrementPendingAsyncDependencies(); + // 4. If m.[[PendingAsyncDependencies]] = 0, then + if (!evaluating_parent->HasPendingAsyncDependencies()) { + // a. Append m to execList. + exec_list->insert(evaluating_parent); + // b. If m.[[HasTLA]] is false, + // perform ! GatherAvailableAncestors(m, execList). + if (!evaluating_parent->has_toplevel_await()) { + worklist.push(evaluating_parent); + } + } + } + }); } } @@ -938,58 +975,45 @@ MaybeHandle<JSObject> SourceTextModule::GetImportMeta( return Cast<JSObject>(import_meta); } -// https://tc39.es/ecma262/#sec-moduleevaluation -bool SourceTextModule::MaybeHandleEvaluationException( - Isolate* isolate, ZoneForwardList<Handle<SourceTextModule>>* stack) { - DisallowGarbageCollection no_gc; - Tagged<Object> exception = isolate->exception(); - // Step 9. - if (isolate->is_catchable_by_javascript(exception)) { - // a. For each Cyclic Module Record m in stack, do - for (DirectHandle<SourceTextModule> descendant : *stack) { - // i. Assert: m.[[Status]] is EVALUATING. - CHECK_EQ(descendant->status(), kEvaluating); - // ii. Set m.[[Status]] to EVALUATED. - // iii. Set m.[[EvaluationError]] to result. - descendant->RecordError(isolate, exception); - } - // A stack overflow at the InnerModuleEvaluation entry STACK_CHECK can throw - // before this module was appended to `stack`, leaving its - // [[EvaluationError]] empty. Record it directly so the top-level capability - // rejects with the actual exception rather than the EMPTY (TheHole) - // sentinel. - if (IsTheHole(this->exception())) { - RecordError(isolate, exception); - } - return true; - } - // If the exception was a termination exception, rejecting the promise - // would resume execution, and our API contract is to return an empty - // handle. The module's status should be set to kErrored and the - // exception field should be set to `null`. - RecordError(isolate, exception); - for (DirectHandle<SourceTextModule> descendant : *stack) { - descendant->RecordError(isolate, exception); +// https://tc39.es/ecma262/#sec-async-module-execution-fulfilled +// Steps 2-7 (for the fulfilled module itself) and steps 12.c.iii.1-3 (for each +// available synchronous ancestor whose execution succeeded). +Handle<SourceTextModule::InState<Module::kEvaluated>> +SourceTextModule::TransitionAsyncToEvaluated( + Isolate* isolate, Handle<InState<kEvaluatingAsync>> module) { + // 2. Assert: module.[[Status]] is EVALUATING-ASYNC. + DCHECK_EQ(module->status(), kEvaluatingAsync); + // 3. Assert: module.[[AsyncEvaluationOrder]] is an integer. + DCHECK(module->HasAsyncEvaluationOrdinal()); + DCHECK(!module->HasPendingAsyncDependencies()); + // 4. Assert: module.[[EvaluationError]] is EMPTY. + DCHECK(IsTheHole(module->exception())); + // 5. (12.c.iii.1.) Set module.[[AsyncEvaluationOrder]] to DONE. + module->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish); + // 6. (12.c.iii.2.) Set module.[[Status]] to EVALUATED. + Handle<InState<kEvaluated>> evaluated = TransitionStatus<kEvaluated>(module); + // 7. (12.c.iii.3.) If module.[[TopLevelCapability]] is not EMPTY, then + if (!IsUndefined(evaluated->top_level_capability())) { + // a. Assert: module.[[CycleRoot]] and module are the same Module Record. + DCHECK_EQ(*evaluated->GetCycleRoot(isolate), *evaluated); + // b. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], + // undefined, « undefined »). + DirectHandle<JSPromise> capability( + Cast<JSPromise>(evaluated->top_level_capability()), isolate); + JSPromise::Resolve(capability, isolate->factory()->undefined_value()) + .ToHandleChecked(); } - CHECK_EQ(status(), kErrored); - CHECK_EQ(this->exception(), *isolate->factory()->null_value()); - return false; + return evaluated; } // https://tc39.es/ecma262/#sec-moduleevaluation MaybeDirectHandle<JSPromise> SourceTextModule::Evaluate( - Isolate* isolate, Handle<SourceTextModule> module) { - CHECK(module->status() == kLinked || module->status() == kEvaluatingAsync || - module->status() == kEvaluated || module->status() == kErrored); - // An errored module can only reach here if it was never an evaluation - // entry point; otherwise Module::Evaluate would have returned its - // already-rejected top-level capability. - CHECK_IMPLIES(module->status() == kErrored, - IsUndefined(module->top_level_capability())); + Isolate* isolate, Handle<InState<kLinked>> module) { + DCHECK(IsUndefined(module->top_level_capability())); // 5. Let stack be a new empty List. Zone zone(isolate->allocator(), ZONE_NAME); - ZoneForwardList<Handle<SourceTextModule>> stack(&zone); + ZoneForwardList<Handle<InState<kEvaluating>>> stack(&zone); unsigned dfs_index = 0; // 6. Let capability be ! NewPromiseCapability(%Promise%). @@ -997,16 +1021,41 @@ MaybeDirectHandle<JSPromise> SourceTextModule::Evaluate( // 7. Set module.[[TopLevelCapability]] to capability. module->set_top_level_capability(*capability); - DCHECK(IsJSPromise(module->top_level_capability())); // 8. Let result be InnerModuleEvaluation(module, stack, 0). // 9. If result is an abrupt completion, then v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); try_catch.SetVerbose(false); try_catch.SetCaptureMessage(false); - // TODO(verwaest): Return a bool from InnerModuleEvaluation instead? - if (InnerModuleEvaluation(isolate, module, &stack, &dfs_index).is_null()) { - if (!module->MaybeHandleEvaluationException(isolate, &stack)) return {}; + if (!InnerModuleEvaluation(isolate, module, &stack, &dfs_index)) { + DirectHandle<Object> exception(isolate->exception(), isolate); + // a. For each Cyclic Module Record m in stack, do + DirectHandle<InState<kEvaluatedError>> errored_module; + for (DirectHandle<InState<kEvaluating>> m : stack) { + // i. Assert: m.[[Status]] is EVALUATING. + DCHECK_EQ(m->status(), kEvaluating); + // ii. Set m.[[Status]] to EVALUATED. + // iii. Set m.[[EvaluationError]] to result. + const bool is_root = *m == *module; + DirectHandle<InState<kEvaluatedError>> errored = + RecordError(isolate, m, exception); + if (is_root) errored_module = errored; + } + // b. Assert: module.[[Status]] is EVALUATED. + CHECK(!errored_module.is_null()); + DCHECK_EQ(errored_module->status(), kEvaluatedError); + + // A termination exception cannot reject the capability: that would run + // embedder code (see Isolate::ReportPromiseReject). Drop the capability + // instead; Module::Evaluate materializes a rejected one for an errored + // module. + if (isolate->is_execution_terminating()) { + CHECK_EQ(errored_module->exception(), + ReadOnlyRoots(isolate).null_value()); + errored_module->set_top_level_capability( + ReadOnlyRoots(isolate).undefined_value()); + return {}; + } CHECK(try_catch.HasCaught()); // We are clearing the internal exception here because JSPromise::Reject can @@ -1019,22 +1068,30 @@ MaybeDirectHandle<JSPromise> SourceTextModule::Evaluate( isolate->clear_internal_exception(); // d. Perform ! Call(capability.[[Reject]], undefined, // «result.[[Value]]»). - - JSPromise::Reject(capability, direct_handle(module->exception(), isolate)); + JSPromise::Reject(capability, exception); + if (isolate->debug()->IsRestartFrameScheduled()) { + errored_module->set_top_level_capability( + ReadOnlyRoots(isolate).undefined_value()); + isolate->TerminateExecution(); + return {}; + } } else { // 10. Else, // a. Assert: module.[[Status]] is either EVALUATING-ASYNC or EVALUATED. - CHECK_GE(module->status(), kEvaluatingAsync); - - // c. If module.[[AsyncEvaluation]] is false, then - if (!module->HasAsyncEvaluationOrdinal()) { - // i. Assert: module.[[Status]] is EVALUATED. - DCHECK_EQ(module->status(), kEvaluated); - - // ii. Perform ! Call(capability.[[Resolve]], undefined, - // «undefined»). - JSPromise::Resolve(capability, isolate->factory()->undefined_value()) - .ToHandleChecked(); - } + DCHECK(module->status() == kEvaluatingAsync || + module->status() == kEvaluated); + MatchState( + Handle<SourceTextModule>(module), + [](DirectHandle<InState<kEvaluatingAsync>> m) { + DCHECK(m->HasAsyncEvaluationOrdinal()); + }, + [&](DirectHandle<InState<kEvaluated>> m) { + // c. If module.[[AsyncEvaluation]] is false, then + DCHECK(!m->HasAsyncEvaluationOrdinal()); + // ii. Perform ! Call(capability.[[Resolve]], undefined, + // «undefined»). + JSPromise::Resolve(capability, isolate->factory()->undefined_value()) + .ToHandleChecked(); + }); // d. Assert: stack is empty. DCHECK(stack.empty()); @@ -1047,173 +1104,161 @@ MaybeDirectHandle<JSPromise> SourceTextModule::Evaluate( // https://tc39.es/ecma262/#sec-async-module-execution-fulfilled Maybe<bool> SourceTextModule::AsyncModuleExecutionFulfilled( Isolate* isolate, Handle<SourceTextModule> module) { - // 1. If module.[[Status]] is EVALUATED, then - if (module->status() == kErrored) { - // a. Assert: module.[[EvaluationError]] is not EMPTY. - DCHECK(!IsTheHole(module->exception())); - // b. Return UNUSED. - return Just(true); - } - - // 2. Assert: module.[[Status]] is EVALUATING-ASYNC. - DCHECK_EQ(module->status(), kEvaluatingAsync); - - // 3. Assert: module.[[AsyncEvaluation]] is true. - DCHECK(module->HasAsyncEvaluationOrdinal()); - - // 4. Assert: module.[[EvaluationError]] is EMPTY. - // (Done by step 2.) - - // 5. Set module.[[AsyncEvaluation]] to false. - module->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish); - - // 6. Set module.[[Status]] to EVALUATED. - module->SetStatus(kEvaluated); - - // 7. If module.[[TopLevelCapability]] is not EMPTY, then - if (!IsUndefined(module->top_level_capability())) { - // a. Assert: module.[[CycleRoot]] is equal to module. - DCHECK_EQ(*module->GetCycleRoot(isolate), *module); - - // i. Perform ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, - // «undefined»). - DirectHandle<JSPromise> capability( - Cast<JSPromise>(module->top_level_capability()), isolate); - JSPromise::Resolve(capability, isolate->factory()->undefined_value()) - .ToHandleChecked(); - } - - // 8. Let execList be a new empty List. - Zone zone(isolate->allocator(), ZONE_NAME); - AvailableAncestorsSet exec_list(&zone); - - // 9. Perform GatherAvailableAncestors(module, execList). - GatherAvailableAncestors(isolate, &zone, module, &exec_list); - - // 10. Let sortedExecList be a List of elements that are the elements of - // execList, in the order in which they had their [[AsyncEvaluation]] - // fields set to true in InnerModuleEvaluation. - // - // This step is implemented by AvailableAncestorsSet, which is a set - // ordered on async_evaluation_ordinal. + return MatchState( + module, + [](DirectHandle<InState<kEvaluatedError>> errored) -> Maybe<bool> { + // 1. If module.[[Status]] is EVALUATED, then + // a. Assert: module.[[EvaluationError]] is not EMPTY. + DCHECK(!IsTheHole(errored->exception())); + // b. Return UNUSED. + return Just(true); + }, + [&](Handle<InState<kEvaluatingAsync>> evaluating_async) -> Maybe<bool> { + // Steps 2-7. + Handle<InState<kEvaluated>> evaluated_module = + TransitionAsyncToEvaluated(isolate, evaluating_async); + + // 8. Let execList be a new empty List. + Zone zone(isolate->allocator(), ZONE_NAME); + AvailableAncestorsSet exec_set(&zone); + + // 9. Perform GatherAvailableAncestors(module, execList). + GatherAvailableAncestors(isolate, &zone, evaluated_module, &exec_set); + + // 10. Let sortedExecList be a List of elements that are the elements of + // execList, in the order in which they had their [[AsyncEvaluation]] + // fields set to true in InnerModuleEvaluation. + // + // This step is implemented by AvailableAncestorsSet, which is a set + // ordered on async_evaluation_ordinal. - // 11. Assert: All elements of sortedExecList have their [[AsyncEvaluation]] - // field set to true, [[PendingAsyncDependencies]] field set to 0 and - // [[EvaluationError]] field set to undefined. + // 11. Assert: All elements of sortedExecList have their + // [[AsyncEvaluation]] field set to true, + // [[PendingAsyncDependencies]] field set to 0 and + // [[EvaluationError]] field set to undefined. #ifdef DEBUG - for (DirectHandle<SourceTextModule> m : exec_list) { - DCHECK(m->HasAsyncEvaluationOrdinal()); - DCHECK(!m->HasPendingAsyncDependencies()); - DCHECK_NE(m->status(), kErrored); - } + for (DirectHandle<SourceTextModule> m : exec_set) { + DCHECK(m->HasAsyncEvaluationOrdinal()); + DCHECK(!m->HasPendingAsyncDependencies()); + DCHECK_NE(m->status(), kEvaluatedError); + } #endif - // 12. For each Module m of sortedExecList, do - for (DirectHandle<SourceTextModule> m : exec_list) { - if (m->status() == kErrored) { // a. If m.[[Status]] is EVALUATED, then - // i. Assert: m.[[EvaluationError]] is not EMPTY. - DCHECK(!IsTheHole(m->exception())); - } else if (m->has_toplevel_await()) { // b. Else if m.[[HasTLA]] is true, - // then - // i. Perform ExecuteAsyncModule(m). - // - // The execution may have been terminated and can not be resumed, so just - // raise the exception. - MAYBE_RETURN(ExecuteAsyncModule(isolate, m), Nothing<bool>()); - } else { // c. Else, - // i. Let result be m.ExecuteModule(). - DirectHandle<Object> unused_result; - MaybeDirectHandle<Object> exception; - // ii. If result is an abrupt completion, then - if (!ExecuteModule(isolate, m, &exception).ToHandle(&unused_result)) { - DCHECK_IMPLIES(exception.IsEmpty(), - isolate->is_execution_terminating()); - if (isolate->is_execution_terminating()) return {}; - // 1. Perform AsyncModuleExecutionRejected(m, result.[[Value]]). - AsyncModuleExecutionRejected(isolate, m, exception.ToHandleChecked()); - } else { // iii. Else, - // 1. Set m.[[AsyncEvaluation]] to false. - m->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish); - - // 2. Set m.[[Status]] to EVALUATED. - m->SetStatus(kEvaluated); - - // 3. If m.[[TopLevelCapability]] is not EMPTY, then - if (!IsUndefined(m->top_level_capability())) { - // a. Assert: m.[[CycleRoot]] and m are the same Module Record. - DCHECK_EQ(*m->GetCycleRoot(isolate), *m); - - // b. Perform ! Call(m.[[TopLevelCapability]].[[Resolve]], undefined, - // « undefined »). - DirectHandle<JSPromise> capability( - Cast<JSPromise>(m->top_level_capability()), isolate); - JSPromise::Resolve(capability, isolate->factory()->undefined_value()) - .ToHandleChecked(); + // 12. For each Module m of sortedExecList, do + for (Handle<SourceTextModule> m : exec_set) { + MatchState( + m, + [](DirectHandle<InState<kEvaluatedError>> errored_m) { + // a. If m.[[Status]] is EVALUATED, then + // i. Assert: m.[[EvaluationError]] is not EMPTY. + DCHECK(!IsTheHole(errored_m->exception())); + }, + [&](Handle<InState<kEvaluatingAsync>> evaluating_m) { + if (!isolate->is_execution_terminating()) { + // b. Else if m.[[HasTLA]] is true, then + if (evaluating_m->has_toplevel_await()) { + // i. Perform ExecuteAsyncModule(m). + USE(ExecuteAsyncModule(isolate, evaluating_m)); + } else { // c. Else, + // i. Let result be m.ExecuteModule(). + MaybeDirectHandle<Object> exception; + // ii. If result is an abrupt completion, then + if (ExecuteModule(isolate, evaluating_m, &exception)) { + // iii. Else, steps 12.c.iii.1-3. + TransitionAsyncToEvaluated(isolate, evaluating_m); + } else if (!isolate->is_execution_terminating()) { + // 1. Perform AsyncModuleExecutionRejected( + // m, result.[[Value]]). + AsyncModuleExecutionRejected(isolate, evaluating_m, + exception.ToHandleChecked()); + } + } + } + if (isolate->is_execution_terminating()) { + AsyncModuleExecutionRejected( + isolate, evaluating_m, + isolate->factory()->termination_exception()); + } + }); } - } - } - } - // Return UNUSED. - return Just(true); + if (isolate->is_execution_terminating()) return Nothing<bool>(); + // Return UNUSED. + return Just(true); + }); } // https://tc39.es/ecma262/#sec-async-module-execution-rejected void SourceTextModule::AsyncModuleExecutionRejected( Isolate* isolate, DirectHandle<SourceTextModule> module, DirectHandle<Object> exception) { - // 1. If module.[[Status]] is EVALUATED, then - if (module->status() == kErrored) { - // a. Assert: module.[[EvaluationError]] is not empty. - DCHECK(!IsTheHole(module->exception())); - // b. Return UNUSED. - return; - } - - DCHECK(isolate->is_catchable_by_javascript(*exception)); - // 2. Assert: module.[[Status]] is EVALUATING-ASYNC. - CHECK_EQ(module->status(), kEvaluatingAsync); - // 3. Assert: module.[[AsyncEvaluation]] is true. - DCHECK(module->HasAsyncEvaluationOrdinal()); - // 4. Assert: module.[[EvaluationError]] is EMPTY. - DCHECK(IsTheHole(module->exception())); - - // 5. Set module.[[EvaluationError]] to ThrowCompletion(error). - module->RecordError(isolate, *exception); - - // 6. Set module.[[Status]] to EVALUATED. - // (We have a status for kErrored, so don't set to kEvaluated.) - module->set_async_evaluation_ordinal(kAsyncEvaluateDidFinish); - - // 7. If module.[[TopLevelCapability]] is not EMPTY, then - if (!IsUndefined(module->top_level_capability())) { - // a. Assert: module.[[CycleRoot]] and module are the same Module Record. - DCHECK_EQ(*module->GetCycleRoot(isolate), *module); - - // b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], - // undefined, «error»). - DirectHandle<JSPromise> capability( - Cast<JSPromise>(module->top_level_capability()), isolate); - JSPromise::Reject(capability, exception); - } + MatchState( + module, + [](DirectHandle<InState<kEvaluatedError>> errored) { + // 1. If module.[[Status]] is EVALUATED, then + // a. Assert: module.[[EvaluationError]] is not empty. + DCHECK(!IsTheHole(errored->exception())); + // b. Return UNUSED. + }, + [&](DirectHandle<InState<kEvaluatingAsync>> evaluating_module) { + // 2. Assert: module.[[Status]] is EVALUATING-ASYNC. + DCHECK_EQ(evaluating_module->status(), kEvaluatingAsync); + // 3. Assert: module.[[AsyncEvaluationOrder]] is an integer. + DCHECK(evaluating_module->HasAsyncEvaluationOrdinal()); + // 4. Assert: module.[[EvaluationError]] is EMPTY. + DCHECK(IsTheHole(evaluating_module->exception())); + + // 7. Set module.[[AsyncEvaluationOrder]] to DONE. + evaluating_module->set_async_evaluation_ordinal( + kAsyncEvaluateDidFinish); + // 5. Set module.[[EvaluationError]] to ThrowCompletion(error). + // 6. Set module.[[Status]] to EVALUATED. + DirectHandle<InState<kEvaluatedError>> errored_module = + RecordError(isolate, evaluating_module, exception); + + // 8. If module.[[TopLevelCapability]] is not EMPTY, then + if (!IsUndefined(errored_module->top_level_capability())) { + // a. Assert: module.[[CycleRoot]] and module are the same Module + // Record. + DCHECK_EQ(errored_module->cycle_root(), *errored_module); + if (isolate->is_catchable_by_javascript(*exception)) { + // b. Perform ! Call(module.[[TopLevelCapability]].[[Reject]], + // undefined, «error»). + DirectHandle<JSPromise> capability( + Cast<JSPromise>(errored_module->top_level_capability()), + isolate); + JSPromise::Reject(capability, exception); + if (isolate->debug()->IsRestartFrameScheduled()) { + errored_module->set_top_level_capability( + ReadOnlyRoots(isolate).undefined_value()); + isolate->TerminateExecution(); + } + } else { + errored_module->set_top_level_capability( + ReadOnlyRoots(isolate).undefined_value()); + } + } - // 8. For each Cyclic Module Record m of module.[[AsyncParentModules]], do - const uint32_t module_count = module->AsyncParentModuleCount(); - for (uint32_t i = 0; i < module_count; i++) { - // a. Perform AsyncModuleExecutionRejected(m, error). - DirectHandle<SourceTextModule> m = module->GetAsyncParentModule(isolate, i); - AsyncModuleExecutionRejected(isolate, m, exception); - } - // 9. Return UNUSED. + // 9. For each Cyclic Module Record m of module.[[AsyncParentModules]], + // do + const uint32_t module_count = errored_module->AsyncParentModuleCount(); + for (uint32_t i = 0; i < module_count; i++) { + // a. Perform AsyncModuleExecutionRejected(m, error). + DirectHandle<SourceTextModule> m = + errored_module->GetAsyncParentModule(isolate, i); + AsyncModuleExecutionRejected(isolate, m, exception); + } + // 10. Return UNUSED. + }); } // static Maybe<bool> SourceTextModule::ExecuteAsyncModule( - Isolate* isolate, DirectHandle<SourceTextModule> module) { + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module) { // 1. Assert: module.[[Status]] is either EVALUATING or EVALUATING-ASYNC. CHECK(module->status() == kEvaluating || module->status() == kEvaluatingAsync); - // 2. Assert: module.[[HasTLA]] is true. DCHECK(module->has_toplevel_await()); @@ -1284,13 +1329,14 @@ Maybe<bool> SourceTextModule::ExecuteAsyncModule( } MaybeDirectHandle<Object> SourceTextModule::InnerExecuteAsyncModule( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module, DirectHandle<JSPromise> capability) { // If we have an async module, then it has an associated // JSAsyncFunctionObject, which we then evaluate with the passed in promise // capability. DirectHandle<JSAsyncFunctionObject> async_function_object( - Cast<JSAsyncFunctionObject>(module->code()), isolate); + module->async_function_object(), isolate); async_function_object->set_promise(*capability); DirectHandle<JSFunction> resume( isolate->native_context()->async_module_evaluate_internal(), isolate); @@ -1298,12 +1344,12 @@ MaybeDirectHandle<Object> SourceTextModule::InnerExecuteAsyncModule( Execution::MessageHandling::kKeepPending, nullptr); } -MaybeDirectHandle<Object> SourceTextModule::ExecuteModule( - Isolate* isolate, DirectHandle<SourceTextModule> module, +bool SourceTextModule::ExecuteModule( + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module, MaybeDirectHandle<Object>* exception_out) { // Synchronous modules have an associated JSGeneratorObject. - DirectHandle<JSGeneratorObject> generator( - Cast<JSGeneratorObject>(module->code()), isolate); + DirectHandle<JSGeneratorObject> generator(module->generator(), isolate); DirectHandle<JSFunction> resume( isolate->native_context()->generator_next_internal(), isolate); DirectHandle<Object> result; @@ -1312,241 +1358,243 @@ MaybeDirectHandle<Object> SourceTextModule::ExecuteModule( Execution::MessageHandling::kKeepPending, exception_out) .ToHandle(&result)) { - return {}; + return false; } DCHECK( Object::BooleanValue(Cast<JSIteratorResult>(*result)->done(), isolate)); - return direct_handle(Cast<JSIteratorResult>(*result)->value(), isolate); + return true; } -MaybeDirectHandle<Object> SourceTextModule::InnerModuleEvaluation( +bool SourceTextModule::InnerModuleEvaluation( Isolate* isolate, Handle<SourceTextModule> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index) { - STACK_CHECK(isolate, MaybeDirectHandle<Object>()); - int module_status = module->status(); + ZoneForwardList<Handle<InState<kEvaluating>>>* stack, unsigned* dfs_index) { // InnerModuleEvaluation(module, stack, index) + // The spec returns the module index for proper numbering of dependencies; + // we pass it by pointer instead and return a bool for success/failure. + return MatchState( + module, + [](DirectHandle<InState<kEvaluatingAsync, kEvaluating, kEvaluated>>) { + // 2. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, then + // a. If module.[[EvaluationError]] is undefined, return index. + // 3. If module.[[Status]] is EVALUATING, return index. + return true; + }, + [&](DirectHandle<InState<kEvaluatedError>> errored) { + // b. Otherwise return module.[[EvaluationError]]. + isolate->Throw(errored->exception()); + return false; + }, + [&](Handle<InState<kLinked>> linked_module) { + // 4. Assert: module.[[Status]] is LINKED. + DCHECK_EQ(linked_module->status(), kLinked); + // 5. Set module.[[Status]] to EVALUATING. + Handle<InState<kEvaluating>> evaluating_module = + TransitionStatus<kEvaluating>(linked_module); + // 6. Set module.[[DFSIndex]] to index. + evaluating_module->set_dfs_index(*dfs_index); + // 7. Set module.[[DFSAncestorIndex]] to index. + evaluating_module->set_dfs_ancestor_index(*dfs_index); + // 8. Set module.[[PendingAsyncDependencies]] to 0. + DCHECK(!evaluating_module->HasPendingAsyncDependencies()); + // 9. Set index to index + 1. + (*dfs_index)++; + // 10. Append module to stack. + stack->push_front(evaluating_module); + + // Check for stack overflow or interrupts after pushing + // {evaluating_module} onto {stack} so that if STACK_CHECK throws and + // returns false, {evaluating_module} is already on {stack} and will be + // transitioned to kEvaluatedError by SourceTextModule::Evaluate. + STACK_CHECK(isolate, false); + + DirectHandle<FixedArray> module_requests( + evaluating_module->info()->module_requests(), isolate); + DirectHandle<FixedArray> requested_modules( + evaluating_module->requested_modules(), isolate); + + Zone zone(isolate->allocator(), ZONE_NAME); + // There's an evaluation set to perform optimized check if a module is + // already in evaluation_list. It's necessary to keep evaluation order + // as it's seen to be spec compliant. + UnorderedModuleSet evaluation_set(&zone); + ZoneVector<Handle<Module>> evaluation_list(&zone); + UnorderedModuleSet seen_modules(&zone); + const uint32_t requested_modules_len = + requested_modules->ulength().value(); + for (uint32_t i = 0; i < requested_modules_len; ++i) { + DirectHandle<ModuleRequest> module_request( + Cast<ModuleRequest>(module_requests->get(i)), isolate); + + if (module_request->phase() == ModuleImportPhase::kSource) { + continue; + } - // 2. If module.[[Status]] is either EVALUATING-ASYNC or EVALUATED, then - if (module_status == kEvaluatingAsync || module_status == kEvaluating || - module_status == kEvaluated) { - // a. If module.[[EvaluationError]] is undefined, return index. - // (We return undefined instead) - // - // 3. If module.[[Status]] is EVALUATING, return index. - // (Out of order) - return isolate->factory()->undefined_value(); - } else if (module_status == kErrored) { - // b. Otherwise return module.[[EvaluationError]]. - // (We throw on isolate and return a MaybeHandle<Object> instead) - isolate->Throw(module->exception()); - return MaybeDirectHandle<Object>(); - } - - // 4. Assert: module.[[Status]] is LINKED. - CHECK_EQ(module_status, kLinked); - - DirectHandle<FixedArray> module_requests; - DirectHandle<FixedArray> requested_modules; - - { - DisallowGarbageCollection no_gc; - Tagged<SourceTextModule> raw_module = *module; - // 5. Set module.[[Status]] to EVALUATING. - raw_module->SetStatus(kEvaluating); - - // 6. Set module.[[DFSIndex]] to index. - raw_module->set_dfs_index(*dfs_index); - - // 7. Set module.[[DFSAncestorIndex]] to index. - raw_module->set_dfs_ancestor_index(*dfs_index); - - // 8. Set module.[[PendingAsyncDependencies]] to 0. - DCHECK(!raw_module->HasPendingAsyncDependencies()); - - // 9. Set index to index + 1. - (*dfs_index)++; - - // 10. Append module to stack. - stack->push_front(module); - - // Recursion. - module_requests = - direct_handle(raw_module->info()->module_requests(), isolate); - requested_modules = direct_handle(raw_module->requested_modules(), isolate); - } - - Zone zone(isolate->allocator(), ZONE_NAME); - // There's an evaluation set to perform optimized check if a module is already - // in evaluation_list. It's necessary to keep evaluation order as it's seen to - // be spec compliant. - UnorderedModuleSet evaluation_set(&zone); - ZoneVector<Handle<Module>> evaluation_list(&zone); - UnorderedModuleSet seen_modules(&zone); - const uint32_t requested_modules_len = requested_modules->ulength().value(); - for (uint32_t i = 0; i < requested_modules_len; ++i) { - DirectHandle<ModuleRequest> module_request( - Cast<ModuleRequest>(module_requests->get(i)), isolate); - - if (module_request->phase() == ModuleImportPhase::kSource) { - continue; - } - - Handle<Module> requested_module( - CheckedCast<Module>(requested_modules->get(i)), isolate); - if (module_request->phase() == ModuleImportPhase::kDefer) { - ZoneVector<Handle<SourceTextModule>> async_evaluation_list(&zone); - GatherAsynchronousTransitiveDependencies( - isolate, requested_module, &evaluation_set, &async_evaluation_list, - &seen_modules); - for (auto async_module : async_evaluation_list) { - evaluation_list.push_back(async_module); - } - } else if (evaluation_set.insert(requested_module).second) { - evaluation_list.push_back(requested_module); - } - } + Handle<Module> requested_module( + CheckedCast<Module>(requested_modules->get(i)), isolate); + if (module_request->phase() == ModuleImportPhase::kDefer) { + ZoneVector<Handle<SourceTextModule>> async_evaluation_list(&zone); + GatherAsynchronousTransitiveDependencies( + isolate, requested_module, &evaluation_set, + &async_evaluation_list, &seen_modules); + for (auto async_module : async_evaluation_list) { + evaluation_list.push_back(async_module); + } + } else if (evaluation_set.insert(requested_module).second) { + evaluation_list.push_back(requested_module); + } + } - // 11. For each ModuleRequest Record required of module.[[RequestedModules]], - for (size_t i = 0, length = evaluation_list.size(); i < length; ++i) { - // b. If requiredModule.[[Phase]] is evaluation, then - Handle<Module> requested_module = evaluation_list[i]; - // c. If requiredModule is a Cyclic Module Record, then - if (IsSourceTextModule(*requested_module)) { - // b. Set index to ? InnerModuleEvaluation(requiredModule, stack, index). - // (Out of order because InnerModuleEvaluation is type-driven.) - Handle<SourceTextModule> required_module( - Cast<SourceTextModule>(*requested_module), isolate); - RETURN_ON_EXCEPTION( - isolate, - InnerModuleEvaluation(isolate, required_module, stack, dfs_index)); - int required_module_status = required_module->status(); - - // i. Assert: requiredModule.[[Status]] is one of EVALUATING, - // EVALUATING-ASYNC, or EVALUATED. - // (We also assert the module cannot be errored, because if it was - // we would have already returned from InnerModuleEvaluation) - CHECK_GE(required_module_status, kEvaluating); - CHECK_NE(required_module_status, kErrored); - - // ii. Assert: requiredModule.[[Status]] is EVALUATING if and only if - // requiredModule is in stack. - SLOW_DCHECK((requested_module->status() == kEvaluating) == - std::count_if(stack->begin(), stack->end(), - [&](DirectHandle<Module> m) { - return *m == *requested_module; - })); - - // iii. If requiredModule.[[Status]] is EVALUATING, then - if (required_module_status == kEvaluating) { - // 1. Set module.[[DFSAncestorIndex]] to - // min(module.[[DFSAncestorIndex]], - // requiredModule.[[DFSAncestorIndex]]). - module->set_dfs_ancestor_index( - std::min(module->dfs_ancestor_index(), - required_module->dfs_ancestor_index())); - } else { // iv. Else, - // 1. Assert: requiredModule.[[CycleRoot]] is not empty. - DCHECK(!IsTheHole(required_module->cycle_root())); - - // 2. Set requiredModule to requiredModule.[[CycleRoot]]. - required_module = required_module->GetCycleRoot(isolate); - required_module_status = required_module->status(); - - // 3. Assert: requiredModule.[[Status]] is either EVALUATING-ASYNC or - // EVALUATED. - CHECK_GE(required_module_status, kEvaluatingAsync); - - // 4. If requiredModule.[[EvaluationError]] is not EMPTY, - // return ? module.[[EvaluationError]]. - - // (If there was an exception on the original required module we would - // have already returned. This check handles the case where the - // AsyncCycleRoot has an error. Instead of returning the exception, we - // throw on isolate and return a MaybeHandle<Object>.) - if (required_module_status == kErrored) { - isolate->Throw(required_module->exception()); - return MaybeDirectHandle<Object>(); + // 11. For each ModuleRequest Record required of + // module.[[RequestedModules]], + for (size_t i = 0, length = evaluation_list.size(); i < length; ++i) { + // b. If requiredModule.[[Phase]] is evaluation, then + Handle<Module> requested_module = evaluation_list[i]; + // c. If requiredModule is a Cyclic Module Record, then + if (Handle<SourceTextModule> required_source_module; + TryCast(requested_module, &required_source_module)) { + // b. Set index to ? InnerModuleEvaluation(requiredModule, stack, + // index). + // (Out of order because InnerModuleEvaluation is type-driven.) + if (!InnerModuleEvaluation(isolate, required_source_module, stack, + dfs_index)) { + return false; + } + + // ii. Assert: requiredModule.[[Status]] is EVALUATING if and only + // if requiredModule is in stack. + SLOW_DCHECK( + (required_source_module->status() == kEvaluating) == + std::count_if(stack->begin(), stack->end(), + [&](DirectHandle<InState<kEvaluating>> m) { + return *m == *required_source_module; + })); + + // i. Assert: requiredModule.[[Status]] is one of EVALUATING, + // EVALUATING-ASYNC, or EVALUATED. + // (kEvaluatedError already returned false from + // InnerModuleEvaluation above.) + DCHECK(required_source_module->status() == kEvaluating || + required_source_module->status() == kEvaluatingAsync || + required_source_module->status() == kEvaluated); + const bool ok = MatchState( + required_source_module, + [&](DirectHandle<InState<kEvaluating>> evaluating_req) { + // iii. If requiredModule.[[Status]] is EVALUATING, then + // 1. Set module.[[DFSAncestorIndex]] to + // min(module.[[DFSAncestorIndex]], + // requiredModule.[[DFSAncestorIndex]]). + evaluating_module->UpdateDfsAncestorIndex(evaluating_req); + // v. If requiredModule.[[AsyncEvaluation]] is true, then + if (evaluating_req->HasAsyncEvaluationOrdinal()) { + // 1. Set module.[[PendingAsyncDependencies]] to + // module.[[PendingAsyncDependencies]] + 1. + evaluating_module->IncrementPendingAsyncDependencies(); + // 2. Append module to + // requiredModule.[[AsyncParentModules]]. + AddAsyncParentModule(isolate, evaluating_req, + evaluating_module); + } + return true; + }, + [&](DirectHandle<InState<kEvaluatingAsync, kEvaluated>> + finished_req) { + // iv. Else, + // 1. Assert: requiredModule.[[CycleRoot]] is not empty. + DCHECK(!IsTheHole(finished_req->cycle_root())); + // 2. Set requiredModule to requiredModule.[[CycleRoot]]. + DirectHandle<SourceTextModule> cycle_root = + finished_req->GetCycleRoot(isolate); + // 3. Assert: requiredModule.[[Status]] is either + // EVALUATING-ASYNC or EVALUATED. + DCHECK(cycle_root->status() == kEvaluatingAsync || + cycle_root->status() == kEvaluated || + cycle_root->status() == kEvaluatedError); + return MatchState( + cycle_root, + [&](DirectHandle<InState<kEvaluatingAsync>> async_root) { + // v. If requiredModule.[[AsyncEvaluation]] is true, + // then + DCHECK(async_root->HasAsyncEvaluationOrdinal()); + // 1. Set module.[[PendingAsyncDependencies]] to + // module.[[PendingAsyncDependencies]] + 1. + evaluating_module->IncrementPendingAsyncDependencies(); + // 2. Append module to + // requiredModule.[[AsyncParentModules]]. + AddAsyncParentModule(isolate, async_root, + evaluating_module); + return true; + }, + [](DirectHandle<InState<kEvaluated>> evaluated_root) { + DCHECK(!evaluated_root->HasAsyncEvaluationOrdinal()); + return true; + }, + [&](DirectHandle<InState<kEvaluatedError>> errored_root) { + // 4. If requiredModule.[[EvaluationError]] is not + // EMPTY, return ? module.[[EvaluationError]]. + isolate->Throw(errored_root->exception()); + return false; + }); + }); + if (!ok) return false; + } else { + // 1. If module is not a Cyclic Module Record, then + // a. Perform ? EvaluateModuleSync(module). + // (Out of order because InnerModuleEvaluation is type-driven.) + if (!Module::EvaluateModuleSync(isolate, requested_module)) { + return false; + } + } } - } - // v. If requiredModule.[[AsyncEvaluation]] is true, then - if (required_module->HasAsyncEvaluationOrdinal()) { - // 1. Set module.[[PendingAsyncDependencies]] to - // module.[[PendingAsyncDependencies]] + 1. - module->IncrementPendingAsyncDependencies(); - - // 2. Append module to requiredModule.[[AsyncParentModules]]. - AddAsyncParentModule(isolate, required_module, module); - } - } else { - // b. Set index to ? InnerModuleEvaluation(requiredModule, stack, index). - // (Out of order because InnerModuleEvaluation is type-driven.) - RETURN_ON_EXCEPTION(isolate, Module::Evaluate(isolate, requested_module)); - } - } - // The spec returns the module index for proper numbering of dependencies. - // However, we pass the module index by pointer instead. - // - // Before async modules v8 returned the value result from calling next - // on the module's implicit iterator. We preserve this behavior for - // synchronous modules, but return undefined for AsyncModules. - DirectHandle<Object> result = isolate->factory()->undefined_value(); - - // 12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] is - // true, then - if (module->HasPendingAsyncDependencies() || module->has_toplevel_await()) { - // a. Assert: module.[[AsyncEvaluation]] is false and was never previously - // set to true. - DCHECK_EQ(module->async_evaluation_ordinal(), kNotAsyncEvaluated); - - // b. Set module.[[AsyncEvaluation]] to true. - // c. NOTE: The order in which module records have their [[AsyncEvaluation]] - // fields transition to true is significant. - module->set_async_evaluation_ordinal( - isolate->NextModuleAsyncEvaluationOrdinal()); - - // c. If module.[[PendingAsyncDependencies]] = 0, perform - // ExecuteAsyncModule(module). - // The execution may have been terminated and can not be resumed, so just - // raise the exception. - if (!module->HasPendingAsyncDependencies()) { - MAYBE_RETURN(SourceTextModule::ExecuteAsyncModule(isolate, module), - MaybeDirectHandle<Object>()); - } - } else { // 13. Else, - // a. Perform ? module.ExecuteModule(). - MaybeDirectHandle<Object> exception; - DirectHandle<Object> maybe_result; - if (!ExecuteModule(isolate, module, &exception).ToHandle(&maybe_result)) { - if (!isolate->is_execution_terminating()) { - isolate->Throw(*exception.ToHandleChecked()); - } - return maybe_result; - } - } + // 12. If module.[[PendingAsyncDependencies]] > 0 or module.[[HasTLA]] + // is true, then + if (evaluating_module->HasPendingAsyncDependencies() || + evaluating_module->has_toplevel_await()) { + // a. Assert: module.[[AsyncEvaluation]] is false and was never + // previously set to true. + DCHECK_EQ(evaluating_module->async_evaluation_ordinal(), + kNotAsyncEvaluated); + // b. Set module.[[AsyncEvaluation]] to true. + // c. NOTE: The order in which module records have their + // [[AsyncEvaluation]] fields transition to true is significant. + evaluating_module->set_async_evaluation_ordinal( + isolate->NextModuleAsyncEvaluationOrdinal()); + + // d. If module.[[PendingAsyncDependencies]] = 0, perform + // ExecuteAsyncModule(module). + // The execution may have been terminated and can not be resumed, so + // just raise the exception. + if (!evaluating_module->HasPendingAsyncDependencies()) { + MAYBE_RETURN(SourceTextModule::ExecuteAsyncModule( + isolate, evaluating_module), + false); + } + } else { // 13. Else, + // a. Perform ? module.ExecuteModule(). + MaybeDirectHandle<Object> exception; + if (!ExecuteModule(isolate, evaluating_module, &exception)) { + if (!isolate->is_execution_terminating()) { + isolate->Throw(*exception.ToHandleChecked()); + } + return false; + } + } - CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated)); - return result; + TransitionComponentAfterEvaluation(evaluating_module, stack); + return true; + }); } -bool SourceTextModule::IsModuleSCCEvaluated(Handle<SourceTextModule> module) { - // It's necessary to check if [[CycleRoot]] is not empty here because: - // 1. A module starts with its [[CycleRoot]] as `TheHole` and it's set - // once the cycle is detected, or when the module finishes its evaluation - // without errors. - // 2. GatherAsynchronousTransitiveDependencies can be called with a module - // where it's `[[CycleRoot]]` is not set yet, and since it depends on - // `IsModuleSCCEvaluated`, we need such guard. A later call from - // `ReadyForSyncExecution` for the same module will have its `[[CycleRoot]]` - // set, unless its evaluation errored. - if (!IsTheHole(module->cycle_root())) { - Tagged<SourceTextModule> cycle_root = - Cast<SourceTextModule>(module->cycle_root()); - return cycle_root->status() == Module::kEvaluated || - cycle_root->status() == Module::kErrored; - } - return module->status() == Module::kEvaluated || - module->status() == Module::kErrored; +bool SourceTextModule::IsModuleSCCEvaluated( + DirectHandle<SourceTextModule> module) { + return MatchState( + module, [](DirectHandle<InState<kLinked, kEvaluating>>) { return false; }, + [](DirectHandle<InState<kEvaluatingAsync, kEvaluated>> m) { + Tagged<SourceTextModule> cycle_root = m->GetCycleRoot(); + return cycle_root->status() == Module::kEvaluated || + cycle_root->status() == Module::kEvaluatedError; + }, + [](DirectHandle<InState<kEvaluatedError>>) { return true; }); } // https://tc39.es/proposal-defer-import-eval/#sec-GatherAsynchronousTransitiveDependencies @@ -1606,7 +1654,15 @@ bool SourceTextModule::ReadyForSyncExecution(Isolate* isolate, } if (!IsSourceTextModule(*module)) { - return true; + return MatchState( + module, + [](DirectHandle< + Module::InState<Module, kLinked, kEvaluated, kEvaluatedError>>) { + return true; + }, + [](DirectHandle<Module::InState<Module, kEvaluating>>) { + return false; + }); } Handle<SourceTextModule> source_text_module = Cast<SourceTextModule>(module); @@ -1614,37 +1670,40 @@ bool SourceTextModule::ReadyForSyncExecution(Isolate* isolate, return true; } - if (source_text_module->status() == kEvaluating || - source_text_module->status() == kEvaluatingAsync) { - return false; - } - - if (source_text_module->has_toplevel_await()) { - return false; - } + return MatchState( + source_text_module, + [](DirectHandle<InState<kEvaluating, kEvaluatingAsync>>) { + return false; + }, + [&](DirectHandle<InState<kLinked, kEvaluated>> m) { + if (m->has_toplevel_await()) { + return false; + } - DirectHandle<FixedArray> module_requests( - source_text_module->info()->module_requests(), isolate); - DirectHandle<FixedArray> requested_modules( - source_text_module->requested_modules(), isolate); - const uint32_t requested_modules_len = requested_modules->ulength().value(); - for (uint32_t i = 0; i < requested_modules_len; ++i) { - DirectHandle<ModuleRequest> module_request( - Cast<ModuleRequest>(module_requests->get(i)), isolate); - if (module_request->phase() == ModuleImportPhase::kSource) { - continue; - } - Handle<Module> requested_module(Cast<Module>(requested_modules->get(i)), - isolate); - if (!ReadyForSyncExecution(isolate, requested_module, seen)) { - return false; - } - } - return true; + DirectHandle<FixedArray> module_requests(m->info()->module_requests(), + isolate); + DirectHandle<FixedArray> requested_modules(m->requested_modules(), + isolate); + const uint32_t requested_modules_len = + requested_modules->ulength().value(); + for (uint32_t i = 0; i < requested_modules_len; ++i) { + DirectHandle<ModuleRequest> module_request( + Cast<ModuleRequest>(module_requests->get(i)), isolate); + if (module_request->phase() == ModuleImportPhase::kSource) { + continue; + } + Handle<Module> requested_module( + Cast<Module>(requested_modules->get(i)), isolate); + if (!ReadyForSyncExecution(isolate, requested_module, seen)) { + return false; + } + } + return true; + }); } -void SourceTextModule::Reset(Isolate* isolate, - DirectHandle<SourceTextModule> module) { +void SourceTextModule::Reset( + Isolate* isolate, DirectHandle<InState<kPreLinking, kLinking>> module) { Factory* factory = isolate->factory(); DCHECK(IsTheHole(module->import_meta(kAcquireLoad))); @@ -1659,12 +1718,7 @@ void SourceTextModule::Reset(Isolate* isolate, DisallowGarbageCollection no_gc; Tagged<SourceTextModule> raw_module = *module; if (raw_module->status() == kLinking) { - // A kLinking module on stack (Link step 4.a, - // https://tc39.es/ecma262/#sec-moduledeclarationlinking) holds either a - // JSFunction (before RunInitializationCode) or a JSGeneratorObject (if a - // later module in the same SCC failed RunInitializationCode). Restore the - // underlying SharedFunctionInfo for kUnlinked. - raw_module->set_code(raw_module->GetSharedFunctionInfo()); + raw_module->set_code(Cast<JSFunction>(raw_module->code())->shared()); } raw_module->set_regular_exports(*regular_exports); raw_module->set_regular_imports(*regular_imports); @@ -1686,17 +1740,17 @@ SourceTextModule::GetStalledTopLevelAwaitMessages(Isolate* isolate) { messages.reserve(stalled_modules_size); for (DirectHandle<SourceTextModule> found : stalled_modules) { - CHECK(IsJSGeneratorObject(found->code())); - DirectHandle<JSGeneratorObject> code(Cast<JSGeneratorObject>(found->code()), - isolate); - Handle<SharedFunctionInfo> shared(found->GetSharedFunctionInfo(), isolate); - Handle<Object> script(shared->script(), isolate); - MessageLocation location = - MessageLocation(Cast<Script>(script), shared, code->code_offset()); - DirectHandle<JSMessageObject> message = MessageHandler::MakeMessageObject( - isolate, MessageTemplate::kTopLevelAwaitStalled, &location, - isolate->factory()->null_value()); - messages.push_back(message); + MatchState(found, [&](DirectHandle<InState<kEvaluatingAsync>> stalled) { + DirectHandle<JSGeneratorObject> code(stalled->generator(), isolate); + Handle<SharedFunctionInfo> shared(stalled->GetSharedFunctionInfo(), + isolate); + Handle<Object> script(shared->script(), isolate); + MessageLocation location = + MessageLocation(Cast<Script>(script), shared, code->code_offset()); + DirectHandle<JSMessageObject> message = MessageHandler::MakeMessageObject( + isolate, MessageTemplate::kTopLevelAwaitStalled, &location, {}); + messages.push_back(message); + }); } return {stalled_modules, messages}; } @@ -1705,11 +1759,13 @@ void SourceTextModule::InnerGetStalledTopLevelAwaitModule( Isolate* isolate, UnorderedModuleSet* visited, DirectHandleVector<SourceTextModule>* result) { DisallowGarbageCollection no_gc; - // If it's a module that is waiting for no other modules but itself, - // it's what we are looking for. Add it to the results. - if (!HasPendingAsyncDependencies() && HasAsyncEvaluationOrdinal()) { + // A module that is async-evaluating but not waiting for any dependency is + // waiting on its own top-level await: it is what we are looking for. + if (status() == kEvaluatingAsync && !HasPendingAsyncDependencies()) { DCHECK(HasAsyncEvaluationOrdinal()); - result->push_back(direct_handle(Tagged<SourceTextModule>(this), isolate)); + if (Cast<JSGeneratorObject>(code())->is_suspended()) { + result->push_back(direct_handle(Tagged<SourceTextModule>(this), isolate)); + } return; } // The module isn't what we are looking for, continue looking in the graph. diff --git a/deps/v8/src/objects/source-text-module.h b/deps/v8/src/objects/source-text-module.h index d473613ec20d..0624b340dc75 100644 --- a/deps/v8/src/objects/source-text-module.h +++ b/deps/v8/src/objects/source-text-module.h @@ -32,9 +32,9 @@ V8_OBJECT class SourceTextModule : public Module { void VerifyRequestedModules() const; #endif - // The shared function info in case {status} is not kEvaluating, kEvaluated or - // kErrored. - Tagged<SharedFunctionInfo> GetSharedFunctionInfo() const; + // The shared function info of the module body, retrieved through {code} + // according to {status}. Valid in every status. + V8_EXPORT_PRIVATE Tagged<SharedFunctionInfo> GetSharedFunctionInfo() const; Tagged<Script> GetScript() const; @@ -90,7 +90,7 @@ V8_OBJECT class SourceTextModule : public Module { // https://tc39.es/proposal-defer-import-eval/#sec-IsModuleSCCEvaluated // This function checks if the Strongly Connected Component (SCC) that the // module participates is evaluated. - static bool IsModuleSCCEvaluated(Handle<SourceTextModule> module); + static bool IsModuleSCCEvaluated(DirectHandle<SourceTextModule> module); static void GatherAsynchronousTransitiveDependencies( Isolate* isolate, Handle<Module> module, @@ -101,11 +101,8 @@ V8_OBJECT class SourceTextModule : public Module { static bool ReadyForSyncExecution(Isolate* isolate, Handle<Module> module, UnorderedModuleSet* seen); - inline Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> - code() const; - inline void set_code( - Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + template <Status... kStates> + using InState = Module::InState<SourceTextModule, kStates...>; inline Tagged<FixedArray> regular_exports() const; inline void set_regular_exports(Tagged<FixedArray> value, @@ -124,6 +121,25 @@ V8_OBJECT class SourceTextModule : public Module { ReleaseStoreTag, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + private: + inline uint32_t flags() const; + inline void set_flags(uint32_t value); + + friend class Factory; + friend class Module; + template <typename ModuleT, Status... kStates> + friend class Module::InState; + + inline Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> + code() const; + inline void set_code( + Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> value, + WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + + // [[CycleRoot]]: the root of this module's strongly connected component, set + // when the component transitions out of kEvaluating. It stays TheHole if the + // component fails synchronously; a module that fails asynchronously keeps + // it, and its cycle root fails as well. inline Tagged<UnionOf<SourceTextModule, TheHole>> cycle_root() const; inline void set_cycle_root(Tagged<UnionOf<SourceTextModule, TheHole>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); @@ -134,32 +150,21 @@ V8_OBJECT class SourceTextModule : public Module { inline int dfs_index() const; inline void set_dfs_index(int value); - inline int dfs_ancestor_index() const; inline void set_dfs_ancestor_index(int value); - inline int pending_async_dependencies() const; inline void set_pending_async_dependencies(int value); - inline uint32_t flags() const; - inline void set_flags(uint32_t value); - - private: - friend class Factory; - friend class Module; - struct AsyncEvaluationOrdinalCompare; using AvailableAncestorsSet = ZoneSet<Handle<SourceTextModule>, AsyncEvaluationOrdinalCompare>; - // Appends a tuple of module and generator to the async parent modules - // ArrayList. + // Appends a parent module to the async parent modules ArrayList of an + // async-evaluating module. inline static void AddAsyncParentModule( - Isolate* isolate, DirectHandle<SourceTextModule> module, - DirectHandle<SourceTextModule> parent); - - // Get the non-hole cycle root. Only valid when status >= kEvaluated. - inline Handle<SourceTextModule> GetCycleRoot(Isolate* isolate) const; + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module, + DirectHandle<InState<kEvaluating>> parent); // Returns a SourceTextModule, the // ith parent in depth first traversal order of a given async child. @@ -199,101 +204,137 @@ V8_OBJECT class SourceTextModule : public Module { static_assert(kAsyncEvaluateDidFinish < kFirstAsyncEvaluationOrdinal); DECL_PRIMITIVE_ACCESSORS(async_evaluation_ordinal, unsigned) + // Atomic state transitions: + static Handle<InState<kLinking>> TransitionToLinking( + Isolate* isolate, Handle<InState<kPreLinking>> module, + ZoneForwardList<Handle<InState<kLinking>>>* stack, unsigned* dfs_index); + template <Status kFromState, typename TransitionFn> + static void TransitionComponent( + DirectHandle<InState<kFromState>> module, + ZoneForwardList<Handle<InState<kFromState>>>* stack, Status trace_status, + TransitionFn&& transition_ancestor); + static V8_WARN_UNUSED_RESULT bool TransitionComponentToLinked( + Isolate* isolate, DirectHandle<InState<kLinking>> module, + ZoneForwardList<Handle<InState<kLinking>>>* stack); + static void TransitionComponentAfterEvaluation( + DirectHandle<InState<kEvaluating>> module, + ZoneForwardList<Handle<InState<kEvaluating>>>* stack); + static Handle<InState<kEvaluated>> TransitionAsyncToEvaluated( + Isolate* isolate, Handle<InState<kEvaluatingAsync>> module); + // Helpers for Instantiate and Evaluate. static void CreateExport(Isolate* isolate, - DirectHandle<SourceTextModule> module, + DirectHandle<InState<kPreLinking>> module, int cell_index, DirectHandle<FixedArray> names); static void CreateIndirectExport( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, DirectHandle<InState<kPreLinking>> module, DirectHandle<String> name, DirectHandle<SourceTextModuleInfoEntry> entry); static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport( - Isolate* isolate, Handle<SourceTextModule> module, + Isolate* isolate, + Handle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, DirectHandle<String> module_specifier, Handle<String> export_name, MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, MaybeHandle<String> name, int module_request_index, MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, DirectHandle<String> module_specifier, Handle<String> export_name, MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( - Isolate* isolate, DirectHandle<SourceTextModule> module, + Isolate* isolate, DirectHandle<InState<kPreLinking>> module, v8::Local<v8::Context> context, const Module::UserResolveCallbacks& callbacks); static V8_WARN_UNUSED_RESULT bool FinishInstantiate( - Isolate* isolate, Handle<SourceTextModule> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, + Isolate* isolate, Handle<InState<kPreLinking>> module, + ZoneForwardList<Handle<InState<kLinking>>>* stack, unsigned* dfs_index, Zone* zone, unsigned depth, unsigned* max_depth); - static V8_WARN_UNUSED_RESULT bool RunInitializationCode( - Isolate* isolate, DirectHandle<SourceTextModule> module); + static V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSGeneratorObject> + RunInitializationCode(Isolate* isolate, + DirectHandle<InState<kLinking>> module); - static void FetchStarExports(Isolate* isolate, - Handle<SourceTextModule> module, Zone* zone, - UnorderedModuleSet* visited); + static void FetchStarExports( + Isolate* isolate, + Handle<InState<kLinking, kLinked, kEvaluating, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, + Zone* zone, UnorderedModuleSet* visited); static void GatherAvailableAncestors(Isolate* isolate, Zone* zone, - Handle<SourceTextModule> start, + Handle<InState<kEvaluated>> start, AvailableAncestorsSet* exec_list); // Implementation of spec concrete method Evaluate. static V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSPromise> Evaluate( - Isolate* isolate, Handle<SourceTextModule> module); + Isolate* isolate, Handle<InState<kLinked>> module); // Implementation of spec abstract operation InnerModuleEvaluation. - static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> InnerModuleEvaluation( + static V8_WARN_UNUSED_RESULT bool InnerModuleEvaluation( Isolate* isolate, Handle<SourceTextModule> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index); - - // Returns true if the evaluation exception was catchable by js, and false - // for termination exceptions. - bool MaybeHandleEvaluationException( - Isolate* isolate, ZoneForwardList<Handle<SourceTextModule>>* stack); - - static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent( - Isolate* isolate, DirectHandle<SourceTextModule> module, - ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status); + ZoneForwardList<Handle<InState<kEvaluating>>>* stack, + unsigned* dfs_index); // Implementation of spec ExecuteModule is broken up into // InnerExecuteAsyncModule for asynchronous modules and ExecuteModule // for synchronous modules. static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> - InnerExecuteAsyncModule(Isolate* isolate, - DirectHandle<SourceTextModule> module, - DirectHandle<JSPromise> capability); - - static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> ExecuteModule( - Isolate* isolate, DirectHandle<SourceTextModule> module, + InnerExecuteAsyncModule( + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module, + DirectHandle<JSPromise> capability); + + static V8_WARN_UNUSED_RESULT bool ExecuteModule( + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module, MaybeDirectHandle<Object>* exception_out); // Implementation of spec ExecuteAsyncModule. Return Nothing if the execution // is been terminated. static V8_WARN_UNUSED_RESULT Maybe<bool> ExecuteAsyncModule( - Isolate* isolate, DirectHandle<SourceTextModule> module); + Isolate* isolate, + DirectHandle<InState<kEvaluating, kEvaluatingAsync>> module); - static void Reset(Isolate* isolate, DirectHandle<SourceTextModule> module); + static void Reset(Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking>> module); V8_EXPORT_PRIVATE void InnerGetStalledTopLevelAwaitModule( Isolate* isolate, UnorderedModuleSet* visited, DirectHandleVector<SourceTextModule>* result); - public: + friend class TorqueGeneratedSourceTextModuleAsserts; + friend struct ObjectTraits<SourceTextModule>; + friend class CodeStubAssembler; + TaggedMember<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> code_; + + public: + // Public for offsetof() in interpreter/baseline/compiler assemblers (some in + // anonymous namespaces that cannot be friended). TaggedMember<FixedArray> regular_exports_; TaggedMember<FixedArray> regular_imports_; + + private: TaggedMember<FixedArray> requested_modules_; - TaggedMember<UnionOf<TheHole, JSObject>> import_meta_; + V8_TQ_ACQ_REL TaggedMember<UnionOf<TheHole, JSObject>> import_meta_; TaggedMember<UnionOf<SourceTextModule, TheHole>> cycle_root_; TaggedMember<ArrayList> async_parent_modules_; TaggedMember<Smi> dfs_index_; TaggedMember<Smi> dfs_ancestor_index_; TaggedMember<Smi> pending_async_dependencies_; - TaggedMember<Smi> flags_; + TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<SourceTextModuleFlags>); } V8_OBJECT_END; template <> @@ -353,16 +394,13 @@ class SourceTextModuleInfo : public FixedArray { V8_OBJECT class ModuleRequest : public Struct { public: - inline Tagged<String> specifier() const; - inline void set_specifier(Tagged<String> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline ModuleRequest(const AllocationWitness& witness, + Tagged<String> specifier, ModuleImportPhase phase, + Tagged<FixedArray> import_attributes, int position); + inline Tagged<String> specifier() const; inline Tagged<FixedArray> import_attributes() const; - inline void set_import_attributes( - Tagged<FixedArray> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline uint32_t flags() const; - inline void set_flags(uint32_t value); DECL_VERIFIER(ModuleRequest) DECL_PRINTER(ModuleRequest) @@ -382,43 +420,33 @@ V8_OBJECT class ModuleRequest : public Struct { using PositionBits = PhaseBits::Next<uint32_t, 29>; static_assert(PositionBits::kMax >= String::kMaxLength, "String::kMaxLength should fit in PositionBits::kMax"); - DECL_PRIMITIVE_ACCESSORS(position, unsigned) - inline void set_phase(ModuleImportPhase phase); + inline unsigned position() const; inline ModuleImportPhase phase() const; using BodyDescriptor = StructBodyDescriptor; public: - TaggedMember<String> specifier_; - TaggedMember<FixedArray> import_attributes_; - TaggedMember<Smi> flags_; + const TaggedMember<String> specifier_; + const TaggedMember<FixedArray> import_attributes_; + const TaggedMember<Smi> flags_ V8_TQ_TYPE(SmiTagged<ModuleRequestFlags>); } V8_OBJECT_END; V8_OBJECT class SourceTextModuleInfoEntry : public Struct { public: - inline Tagged<UnionOf<String, Undefined>> export_name() const; - inline void set_export_name(Tagged<UnionOf<String, Undefined>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline SourceTextModuleInfoEntry( + const AllocationWitness& witness, + Tagged<UnionOf<String, Undefined>> export_name, + Tagged<UnionOf<String, Undefined>> local_name, + Tagged<UnionOf<String, Undefined>> import_name, int module_request, + int cell_index, int beg_pos, int end_pos); + inline Tagged<UnionOf<String, Undefined>> export_name() const; inline Tagged<UnionOf<String, Undefined>> local_name() const; - inline void set_local_name(Tagged<UnionOf<String, Undefined>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<UnionOf<String, Undefined>> import_name() const; - inline void set_import_name(Tagged<UnionOf<String, Undefined>> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline int module_request() const; - inline void set_module_request(int value); - inline int cell_index() const; - inline void set_cell_index(int value); - inline int beg_pos() const; - inline void set_beg_pos(int value); - inline int end_pos() const; - inline void set_end_pos(int value); DECL_VERIFIER(SourceTextModuleInfoEntry) DECL_PRINTER(SourceTextModuleInfoEntry) @@ -433,13 +461,13 @@ V8_OBJECT class SourceTextModuleInfoEntry : public Struct { using BodyDescriptor = StructBodyDescriptor; public: - TaggedMember<UnionOf<String, Undefined>> export_name_; - TaggedMember<UnionOf<String, Undefined>> local_name_; - TaggedMember<UnionOf<String, Undefined>> import_name_; - TaggedMember<Smi> module_request_; - TaggedMember<Smi> cell_index_; - TaggedMember<Smi> beg_pos_; - TaggedMember<Smi> end_pos_; + const TaggedMember<UnionOf<String, Undefined>> export_name_; + const TaggedMember<UnionOf<String, Undefined>> local_name_; + const TaggedMember<UnionOf<String, Undefined>> import_name_; + const TaggedMember<Smi> module_request_; + const TaggedMember<Smi> cell_index_; + const TaggedMember<Smi> beg_pos_; + const TaggedMember<Smi> end_pos_; } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/string-inl.h b/deps/v8/src/objects/string-inl.h index 00a15364dd46..9fe0c9cbc63a 100644 --- a/deps/v8/src/objects/string-inl.h +++ b/deps/v8/src/objects/string-inl.h @@ -715,6 +715,11 @@ bool String::IsEqualTo(base::Vector<const Char> str) const { SharedStringAccessGuardIfNeeded::NotNeeded()); } +template <String::EqualityType kEqType> +bool String::IsEqualTo(std::string_view str) const { + return IsEqualTo<kEqType>(base::Vector<const char>(str.data(), str.size())); +} + template <String::EqualityType kEqType, typename Char> bool String::IsEqualTo(base::Vector<const Char> str, LocalIsolate* isolate) const { @@ -814,9 +819,7 @@ bool String::IsConsStringEqualToImpl( return true; } -bool String::IsOneByteEqualTo(base::Vector<const char> str) { - return IsEqualTo(str); -} +bool String::IsOneByteEqualTo(std::string_view str) { return IsEqualTo(str); } template <typename Char> const Char* String::GetDirectStringChars( @@ -1541,10 +1544,6 @@ void ExternalOneByteString::update_data_cache( void ExternalOneByteString::SetResource( Isolate* isolate, const ExternalOneByteString::Resource* resource) { set_resource(isolate, resource); - size_t new_payload = resource == nullptr ? 0 : resource->length(); - if (new_payload > 0) { - isolate->heap()->UpdateExternalString(this, 0, new_payload); - } } void ExternalOneByteString::set_resource( @@ -1609,10 +1608,6 @@ void ExternalTwoByteString::update_data_cache( void ExternalTwoByteString::SetResource( Isolate* isolate, const ExternalTwoByteString::Resource* resource) { set_resource(isolate, resource); - size_t new_payload = resource == nullptr ? 0 : resource->length() * 2; - if (new_payload > 0) { - isolate->heap()->UpdateExternalString(this, 0, new_payload); - } } void ExternalTwoByteString::set_resource( diff --git a/deps/v8/src/objects/string-table.cc b/deps/v8/src/objects/string-table.cc index f4a6a0451904..b432f6bfb651 100644 --- a/deps/v8/src/objects/string-table.cc +++ b/deps/v8/src/objects/string-table.cc @@ -820,14 +820,10 @@ void StringTable::InsertForIsolateDeserialization( Data* const data = EnsureCapacity(isolate, length); for (const DirectHandle<InternalizedString>& s : strings) { - StringTableInsertionKey key( - isolate, s, DeserializingUserCodeOption::kNotDeserializingUserCode); InternalIndex entry = - data->table().FindEntryOrInsertionEntry(isolate, &key, key.hash()); - - DirectHandle<String> inserted_string = key.GetHandleForInsertion(isolate); - DCHECK_IMPLIES(v8_flags.shared_string_table, inserted_string->IsShared()); - data->table().AddAt(isolate, entry, *inserted_string); + data->table().FindInsertionEntry(isolate, s->EnsureHash()); + DCHECK_IMPLIES(v8_flags.shared_string_table, s->IsShared()); + data->table().AddAt(isolate, entry, *s); } } diff --git a/deps/v8/src/objects/string.cc b/deps/v8/src/objects/string.cc index 429cf2d21345..7302ac66e2e6 100644 --- a/deps/v8/src/objects/string.cc +++ b/deps/v8/src/objects/string.cc @@ -9,6 +9,7 @@ #include "include/v8config.h" #include "src/base/small-vector.h" #include "src/base/strong-alias.h" +#include "src/base/unique-array.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/common/synchronization-point-support.h" @@ -95,13 +96,11 @@ void MigrateExternalStringResource(Isolate* isolate, if (to_resource_address == kNullAddress) { Tagged<StringClass> cast_from = Cast<StringClass>(from); // |to| is a just-created internalized copy of |from|. Migrate the resource. + // Zap |from|'s resource pointer to reflect the fact that |from| has + // relinquished ownership of its resource. const typename StringClass::Resource* resource = cast_from->ExchangeResource(isolate, nullptr); to->SetResource(isolate, resource); - // Zap |from|'s resource pointer to reflect the fact that |from| has - // relinquished ownership of its resource. - isolate->heap()->UpdateExternalString( - from, Cast<ExternalString>(from)->ExternalPayloadSize(), 0); } else if (to_resource_address != from->resource_as_address(isolate)) { // |to| already existed and has its own resource. Finalize |from|. isolate->heap()->FinalizeExternalString(from); @@ -368,7 +367,7 @@ bool String::MakeExternal(Isolate* isolate, uint32_t str_length = this->length(); DCHECK(static_cast<size_t>(str_length) == resource->length()); auto smart_chars = - base::OwnedVector<base::uc16>::NewForOverwrite(str_length); + base::UniqueArray<base::uc16>::NewForOverwrite(str_length); String::WriteToFlat(this, smart_chars.begin(), 0, str_length); DCHECK_EQ(0, memcmp(smart_chars.begin(), resource->data(), resource->length() * sizeof(smart_chars[0]))); @@ -462,11 +461,11 @@ bool String::MakeExternal(Isolate* isolate, DCHECK(static_cast<size_t>(str_length) == resource->length()); if (this->IsTwoByteRepresentation()) { auto smart_chars = - base::OwnedVector<uint16_t>::NewForOverwrite(str_length); + base::UniqueArray<uint16_t>::NewForOverwrite(str_length); String::WriteToFlat(this, smart_chars.begin(), 0, str_length); DCHECK(String::IsOneByte(smart_chars.begin(), str_length)); } - auto smart_chars = base::OwnedVector<char>::NewForOverwrite(str_length); + auto smart_chars = base::UniqueArray<char>::NewForOverwrite(str_length); String::WriteToFlat(this, smart_chars.begin(), 0, str_length); DCHECK_EQ(0, memcmp(smart_chars.begin(), resource->data(), resource->length() * sizeof(smart_chars[0]))); @@ -1186,7 +1185,7 @@ static void CalculateLineEndsImpl(String::LineEndsVector* line_ends, } const uint8_t* data = src.begin(); - hw::FixedTag<uint8_t, 16> tag; + hw::CappedTag<uint8_t, 16> tag; const size_t stride = hw::Lanes(tag); const auto v_lf = hw::Set(tag, 0x0A); const auto v_cr = hw::Set(tag, 0x0D); @@ -1860,10 +1859,8 @@ Tagged<Object> String::LastIndexOf(Isolate* isolate, return Smi::FromInt(last_index); } -bool String::HasOneBytePrefix(base::Vector<const char> str) { - DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(this)); - return IsEqualToImpl<EqualityType::kPrefix>( - str, SharedStringAccessGuardIfNeeded::NotNeeded()); +bool String::HasOneBytePrefix(std::string_view str) { + return IsEqualTo<EqualityType::kPrefix>(str); } namespace { @@ -1941,7 +1938,7 @@ uint32_t String::ComputeAndSetRawHash(bool* out_one_byte_content) { // only used right below, so putting it here keeps headers leaner and still // allows the compiler to inline it. void Name::set_raw_hash_field_if_empty(uint32_t hash) { - uint32_t field_value = kEmptyHashField; + Hash field_value = kEmptyHashField; bool result = raw_hash_field_.compare_exchange_strong(field_value, hash); USE(result); // CAS can only fail if the string is shared or we use the forwarding table @@ -2426,8 +2423,8 @@ using RepresentationBits = base::BitField<StringRepresentationTag, 0, 3, uint16_t>; using IsOneByteBit = base::BitField<bool, 3, 1, uint16_t>; using IsUncachedBit = base::BitField<bool, 4, 1, uint16_t>; -using IsNotInternalizedBit = base::BitField<bool, 5, 1, uint16_t>; -using IsSharedBit = base::BitField<bool, 6, 1, uint16_t>; +using IsSharedBit = base::BitField<bool, 5, 1, uint16_t>; +using IsNotInternalizedBit = base::BitField<bool, 6, 1, uint16_t>; static_assert(kStringRepresentationMask == RepresentationBits::kMask); @@ -2441,6 +2438,9 @@ static_assert(kUncachedExternalStringTag == IsUncachedBit::encode(true)); static_assert(kIsNotInternalizedMask == IsNotInternalizedBit::kMask); static_assert(kNotInternalizedTag == IsNotInternalizedBit::encode(true)); static_assert(kInternalizedTag == IsNotInternalizedBit::encode(false)); + +static_assert(kSharedStringMask == IsSharedBit::kMask); +static_assert(kSharedStringTag == IsSharedBit::encode(true)); } // namespace } // namespace internal diff --git a/deps/v8/src/objects/string.h b/deps/v8/src/objects/string.h index c23650b0a5f7..3261d76d84ae 100644 --- a/deps/v8/src/objects/string.h +++ b/deps/v8/src/objects/string.h @@ -441,6 +441,10 @@ V8_OBJECT class String : public Name { template <EqualityType kEqType = EqualityType::kWholeString, typename Char> inline bool IsEqualTo(base::Vector<const Char> str) const; + // Convenience method for the above using std::string_view instead. + template <EqualityType kEqType = EqualityType::kWholeString> + inline bool IsEqualTo(std::string_view str) const; + // Check if this string matches the given vector of characters, either as a // whole string or just a prefix. // @@ -450,8 +454,8 @@ V8_OBJECT class String : public Name { inline bool IsEqualTo(base::Vector<const Char> str, LocalIsolate* isolate) const; - V8_EXPORT_PRIVATE bool HasOneBytePrefix(base::Vector<const char> str); - V8_EXPORT_PRIVATE inline bool IsOneByteEqualTo(base::Vector<const char> str); + V8_EXPORT_PRIVATE bool HasOneBytePrefix(std::string_view str); + V8_EXPORT_PRIVATE inline bool IsOneByteEqualTo(std::string_view str); // Returns true if the |str| is a valid ECMAScript identifier. static bool IsIdentifier(Isolate* isolate, DirectHandle<String> str); @@ -807,7 +811,7 @@ V8_OBJECT class String : public Name { bool* out_one_byte_content = nullptr); public: - uint32_t length_; + V8_TQ_CONST uint32_t length_ V8_TQ_TYPE(int32); } V8_OBJECT_END; template <> @@ -961,7 +965,8 @@ V8_OBJECT class SeqOneByteString : public SeqString { friend class compiler::AccessBuilder; friend class TorqueGeneratedSeqOneByteStringAsserts; - FLEXIBLE_ARRAY_MEMBER(Char, chars); + V8_TQ_TAIL_LENGTH(length); + FLEXIBLE_ARRAY_MEMBER(Char, chars, V8_TQ_CONST V8_TQ_TYPE(char8)); } V8_OBJECT_END; template <> @@ -1036,7 +1041,8 @@ V8_OBJECT class SeqTwoByteString : public SeqString { friend class compiler::AccessBuilder; friend class TorqueGeneratedSeqTwoByteStringAsserts; - FLEXIBLE_ARRAY_MEMBER(Char, chars); + V8_TQ_TAIL_LENGTH(length); + FLEXIBLE_ARRAY_MEMBER(Char, chars, V8_TQ_CONST V8_TQ_TYPE(char16)); } V8_OBJECT_END; template <> diff --git a/deps/v8/src/objects/string.tq b/deps/v8/src/objects/string.tq index 2ac2c80f7fb2..94c1329fb666 100644 --- a/deps/v8/src/objects/string.tq +++ b/deps/v8/src/objects/string.tq @@ -63,8 +63,8 @@ bitfield struct StringInstanceType extends uint16 { representation: StringRepresentationTag: 3 bit; is_one_byte: bool: 1 bit; is_uncached: bool: 1 bit; - is_not_internalized: bool: 1 bit; is_shared: bool: 1 bit; + is_not_internalized: bool: 1 bit; } @doNotGenerateCast @@ -157,7 +157,7 @@ extern class SlicedString extends String { @doNotGenerateCast @cppObjectLayoutDefinition extern class ThinString extends String { - actual: String; + actual: InternalizedString; } // A direct string can be accessed directly through CSA without going into the diff --git a/deps/v8/src/objects/struct-inl.h b/deps/v8/src/objects/struct-inl.h index 2d5e54724202..3655b9a52852 100644 --- a/deps/v8/src/objects/struct-inl.h +++ b/deps/v8/src/objects/struct-inl.h @@ -9,6 +9,7 @@ // Include the non-inl header before the rest of the headers. #include "src/heap/heap-write-barrier-inl.h" +#include "src/objects/heap-object-set-map-inl.h" #include "src/objects/oddball-predicates-inl.h" #include "src/objects/tagged-field-inl.h" #include "src/roots/roots-inl.h" @@ -19,6 +20,20 @@ namespace v8 { namespace internal { +Struct::Struct(Tagged<ReadOnly<Map>> map) : HeapObject(map) {} + +Tuple2::Tuple2(const AllocationWitness& witness, Tagged<Object> value1, + Tagged<Object> value2) + : Struct(witness.roots().tuple2_map()), + value1_(witness, value1), + value2_(witness, value2) {} + +Tuple2::Tuple2(const AllocationWitness& witness, Tagged<Object> value1, + Tagged<Object> value2, RelaxedStoreTag tag) + : Struct(witness.roots().tuple2_map()), + value1_(witness, value1, tag), + value2_(witness, value2, tag) {} + Tagged<Object> Tuple2::value1() const { return value1_.load(); } void Tuple2::set_value1(Tagged<Object> value, WriteBarrierMode mode) { value1_.store(this, value, mode); @@ -50,6 +65,11 @@ void Tuple2::set_value2(Tagged<Object> value, RelaxedStoreTag, value2_.Relaxed_Store(this, value, mode); } +AccessorPair::AccessorPair(const AllocationWitness& witness) + : Struct(witness.roots().accessor_pair_map()), + getter_(witness.roots().null_value()), + setter_(witness.roots().null_value()) {} + Tagged<Object> AccessorPair::get(AccessorComponent component) { return component == ACCESSOR_GETTER ? getter() : setter(); } @@ -107,14 +127,41 @@ bool AccessorPair::Equals(Tagged<Object> getter_value, return (getter() == getter_value) && (setter() == setter_value); } +ClassPositions::ClassPositions(const AllocationWitness& witness, int start, + int end) + : Struct(witness.roots().class_positions_map()), + start_(Smi::FromInt(start)), + end_(Smi::FromInt(end)) {} + int ClassPositions::start() const { return start_.load().value(); } -void ClassPositions::set_start(int value) { - start_.store(this, Smi::FromInt(value)); -} int ClassPositions::end() const { return end_.load().value(); } -void ClassPositions::set_end(int value) { - end_.store(this, Smi::FromInt(value)); + +ForInEnumeratorHolder::ForInEnumeratorHolder(const AllocationWitness& witness, + Tagged<Map> enum_cache_map, + Tagged<FixedArray> named_keys, + Tagged<Smi> elements_length, + Tagged<Smi> cache_length) + : Struct(witness.roots().for_in_enumerator_holder_map()), + enum_cache_map_(witness, enum_cache_map), + named_keys_(witness, named_keys), + elements_length_(elements_length), + cache_length_(cache_length) {} + +Tagged<Map> ForInEnumeratorHolder::enum_cache_map() const { + return enum_cache_map_.load(); +} + +Tagged<FixedArray> ForInEnumeratorHolder::named_keys() const { + return named_keys_.load(); +} + +Tagged<Smi> ForInEnumeratorHolder::elements_length() const { + return elements_length_.load(); +} + +Tagged<Smi> ForInEnumeratorHolder::cache_length() const { + return cache_length_.load(); } } // namespace internal diff --git a/deps/v8/src/objects/struct.h b/deps/v8/src/objects/struct.h index dd17c72c40f0..e36111986699 100644 --- a/deps/v8/src/objects/struct.h +++ b/deps/v8/src/objects/struct.h @@ -23,6 +23,8 @@ V8_OBJECT class Struct : public HeapObject { V8_IT_ABSTRACT; public: + inline explicit Struct(Tagged<ReadOnly<Map>> map); + void BriefPrintDetails(std::ostream& os); using BodyDescriptor = StructBodyDescriptor; @@ -33,6 +35,11 @@ V8_OBJECT class Tuple2 : public Struct { V8_IT_NO_AUTO_DISPATCH; public: + inline Tuple2(const AllocationWitness& witness, Tagged<Object> value1, + Tagged<Object> value2); + inline Tuple2(const AllocationWitness& witness, Tagged<Object> value1, + Tagged<Object> value2, RelaxedStoreTag tag); + void BriefPrintDetails(std::ostream& os); inline Tagged<Object> value1() const; @@ -72,6 +79,8 @@ V8_OBJECT class AccessorPair : public Struct { V8_IT_NO_AUTO_DISPATCH; public: + inline explicit AccessorPair(const AllocationWitness& witness); + static DirectHandle<AccessorPair> Copy(Isolate* isolate, DirectHandle<AccessorPair> pair); @@ -121,11 +130,10 @@ V8_OBJECT class ClassPositions : public Struct { V8_IT_NO_AUTO_DISPATCH; public: - inline int start() const; - inline void set_start(int value); + inline ClassPositions(const AllocationWitness& witness, int start, int end); + inline int start() const; inline int end() const; - inline void set_end(int value); // Dispatched behavior. void BriefPrintDetails(std::ostream& os); @@ -136,10 +144,50 @@ V8_OBJECT class ClassPositions : public Struct { private: friend class TorqueGeneratedClassPositionsAsserts; - TaggedMember<Smi> start_; - TaggedMember<Smi> end_; + const TaggedMember<Smi> start_; + const TaggedMember<Smi> end_; +} V8_OBJECT_END; + +V8_OBJECT class ForInEnumeratorHolder : public Struct { + public: + inline ForInEnumeratorHolder(const AllocationWitness& witness, + Tagged<Map> enum_cache_map, + Tagged<FixedArray> named_keys, + Tagged<Smi> elements_length, + Tagged<Smi> cache_length); + + inline Tagged<Map> enum_cache_map() const; + inline Tagged<FixedArray> named_keys() const; + inline Tagged<Smi> elements_length() const; + inline Tagged<Smi> cache_length() const; + + DECL_PRINTER(ForInEnumeratorHolder) + DECL_VERIFIER(ForInEnumeratorHolder) + + using BodyDescriptor = StructBodyDescriptor; + + private: + friend class TorqueGeneratedForInEnumeratorHolderAsserts; + friend struct ObjectTraits<ForInEnumeratorHolder>; + + const TaggedMember<Map> enum_cache_map_; + const TaggedMember<FixedArray> named_keys_; + const TaggedMember<Smi> elements_length_; + const TaggedMember<Smi> cache_length_; } V8_OBJECT_END; +template <> +struct ObjectTraits<ForInEnumeratorHolder> { + static constexpr int kEnumCacheMapOffset = + offsetof(ForInEnumeratorHolder, enum_cache_map_); + static constexpr int kNamedKeysOffset = + offsetof(ForInEnumeratorHolder, named_keys_); + static constexpr int kElementsLengthOffset = + offsetof(ForInEnumeratorHolder, elements_length_); + static constexpr int kCacheLengthOffset = + offsetof(ForInEnumeratorHolder, cache_length_); +}; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/struct.tq b/deps/v8/src/objects/struct.tq index d43e8365f192..e709031190ee 100644 --- a/deps/v8/src/objects/struct.tq +++ b/deps/v8/src/objects/struct.tq @@ -11,3 +11,10 @@ extern class Tuple2 extends Struct; extern class ClassPositions extends Struct; extern class AccessorPair extends Struct; + +extern class ForInEnumeratorHolder extends Struct { + enum_cache_map: Map; + named_keys: FixedArray; + elements_length: Smi; + cache_length: Smi; +} diff --git a/deps/v8/src/objects/swiss-name-dictionary-inl.h b/deps/v8/src/objects/swiss-name-dictionary-inl.h index 800a05288af2..cd332f754582 100644 --- a/deps/v8/src/objects/swiss-name-dictionary-inl.h +++ b/deps/v8/src/objects/swiss-name-dictionary-inl.h @@ -8,6 +8,7 @@ #include "src/objects/swiss-name-dictionary.h" // Include the non-inl header before the rest of the headers. +#include <bit> #include <optional> #include "src/base/logging.h" @@ -35,54 +36,59 @@ uint8_t* SwissNameDictionary::PropertyDetailsTable() { field_address(PropertyDetailsTableStartOffset(Capacity()))); } -int SwissNameDictionary::Capacity() { return capacity_; } +uint32_t SwissNameDictionary::Capacity() { + DCHECK(IsValidCapacity(capacity_)); + return capacity_; +} -void SwissNameDictionary::SetCapacity(int capacity) { +void SwissNameDictionary::SetCapacity(uint32_t capacity) { DCHECK(IsValidCapacity(capacity)); capacity_ = capacity; } -int SwissNameDictionary::NumberOfElements() { +uint32_t SwissNameDictionary::NumberOfElements() { return GetMetaTableField(kMetaTableElementCountFieldIndex); } -int SwissNameDictionary::NumberOfDeletedElements() { +uint32_t SwissNameDictionary::NumberOfDeletedElements() { return GetMetaTableField(kMetaTableDeletedElementCountFieldIndex); } -void SwissNameDictionary::SetNumberOfElements(int elements) { +void SwissNameDictionary::SetNumberOfElements(uint32_t elements) { SetMetaTableField(kMetaTableElementCountFieldIndex, elements); } -void SwissNameDictionary::SetNumberOfDeletedElements(int deleted_elements) { +void SwissNameDictionary::SetNumberOfDeletedElements( + uint32_t deleted_elements) { SetMetaTableField(kMetaTableDeletedElementCountFieldIndex, deleted_elements); } -int SwissNameDictionary::UsedCapacity() { +uint32_t SwissNameDictionary::UsedCapacity() { return NumberOfElements() + NumberOfDeletedElements(); } // static -constexpr bool SwissNameDictionary::IsValidCapacity(int capacity) { - return capacity == 0 || (capacity >= kInitialCapacity && - // Must be power of 2. - ((capacity & (capacity - 1)) == 0)); +constexpr bool SwissNameDictionary::IsValidCapacity(uint32_t capacity) { + return capacity == 0 || + (capacity >= kInitialCapacity && capacity <= MaxCapacity() && + // Must be power of 2. + ((capacity & (capacity - 1)) == 0)); } // static -constexpr int SwissNameDictionary::DataTableSize(int capacity) { +constexpr uint32_t SwissNameDictionary::DataTableSize(uint32_t capacity) { return capacity * kTaggedSize * kDataTableEntryCount; } // static -constexpr int SwissNameDictionary::CtrlTableSize(int capacity) { +constexpr uint32_t SwissNameDictionary::CtrlTableSize(uint32_t capacity) { // Doing + |kGroupWidth| due to the copy of first group at the end of control // table. return (capacity + kGroupWidth) * kOneByteSize; } // static -constexpr int SwissNameDictionary::SizeFor(int capacity) { +constexpr uint32_t SwissNameDictionary::SizeFor(uint32_t capacity) { DCHECK(IsValidCapacity(capacity)); return PropertyDetailsTableStartOffset(capacity) + capacity; } @@ -91,7 +97,7 @@ constexpr int SwissNameDictionary::SizeFor(int capacity) { // For 16-wide groups, that gives an average of two empty slots per group. // Similar to Abseil's CapacityToGrowth. // static -constexpr int SwissNameDictionary::MaxUsableCapacity(int capacity) { +constexpr uint32_t SwissNameDictionary::MaxUsableCapacity(uint32_t capacity) { DCHECK(IsValidCapacity(capacity)); if (Group::kWidth == 8 && capacity == 4) { @@ -105,7 +111,7 @@ constexpr int SwissNameDictionary::MaxUsableCapacity(int capacity) { // Returns |at_least_space_for| * 8/7 for non-special cases. Similar to Abseil's // GrowthToLowerboundCapacity. // static -int SwissNameDictionary::CapacityFor(int at_least_space_for) { +uint32_t SwissNameDictionary::CapacityFor(uint32_t at_least_space_for) { if (at_least_space_for <= 4) { if (at_least_space_for == 0) { return 0; @@ -120,20 +126,21 @@ int SwissNameDictionary::CapacityFor(int at_least_space_for) { } } - int non_normalized = at_least_space_for + at_least_space_for / 7; - return base::bits::RoundUpToPowerOfTwo32(non_normalized); + uint32_t non_normalized = at_least_space_for + at_least_space_for / 7; + return std::bit_ceil<uint32_t>(non_normalized); } -int SwissNameDictionary::EntryForEnumerationIndex(int enumeration_index) { +uint32_t SwissNameDictionary::EntryForEnumerationIndex( + uint32_t enumeration_index) { DCHECK_LT(enumeration_index, UsedCapacity()); return GetMetaTableField(kMetaTableEnumerationDataStartIndex + enumeration_index); } -void SwissNameDictionary::SetEntryForEnumerationIndex(int enumeration_index, - int entry) { +void SwissNameDictionary::SetEntryForEnumerationIndex( + uint32_t enumeration_index, uint32_t entry) { DCHECK_LT(enumeration_index, UsedCapacity()); - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(Capacity())); + DCHECK_LT(entry, Capacity()); DCHECK(IsFull(GetCtrl(entry))); SetMetaTableField(kMetaTableEnumerationDataStartIndex + enumeration_index, @@ -173,7 +180,7 @@ InternalIndex SwissNameDictionary::FindEntry(IsolateT* isolate, while (true) { Group g{ctrl + seq.offset()}; for (int i : g.Match(swiss_table::H2(hash))) { - int candidate_entry = seq.offset(i); + uint32_t candidate_entry = seq.offset(i); Tagged<Object> candidate_key = KeyAt(candidate_entry); // This key matching is SwissNameDictionary specific! if (candidate_key == key) return InternalIndex(candidate_entry); @@ -212,66 +219,69 @@ InternalIndex SwissNameDictionary::FindEntry(IsolateT* isolate, return FindEntry(isolate, *key); } -Tagged<Object> SwissNameDictionary::LoadFromDataTable(int entry, - int data_offset) { - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(Capacity())); +Tagged<Object> SwissNameDictionary::LoadFromDataTable(uint32_t entry, + uint32_t data_offset) { + DCHECK_LT(entry, Capacity()); return data_table()[entry * kDataTableEntryCount + data_offset] .Relaxed_Load(); } -void SwissNameDictionary::StoreToDataTable(int entry, int data_offset, +void SwissNameDictionary::StoreToDataTable(uint32_t entry, uint32_t data_offset, Tagged<Object> data) { - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(Capacity())); + DCHECK_LT(entry, Capacity()); data_table()[entry * kDataTableEntryCount + data_offset].Relaxed_Store(this, data); } -void SwissNameDictionary::StoreToDataTableNoBarrier(int entry, int data_offset, +void SwissNameDictionary::StoreToDataTableNoBarrier(uint32_t entry, + uint32_t data_offset, Tagged<Object> data) { - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(Capacity())); + DCHECK_LT(entry, Capacity()); data_table()[entry * kDataTableEntryCount + data_offset] .Relaxed_Store_no_write_barrier(data); } -void SwissNameDictionary::ClearDataTableEntry(Isolate* isolate, int entry) { +void SwissNameDictionary::ClearDataTableEntry(Isolate* isolate, + uint32_t entry) { ReadOnlyRoots roots(isolate); StoreToDataTable(entry, kDataTableKeyEntryIndex, roots.the_hole_value()); StoreToDataTable(entry, kDataTableValueEntryIndex, roots.the_hole_value()); } -void SwissNameDictionary::ValueAtPut(int entry, Tagged<Object> value) { +void SwissNameDictionary::ValueAtPut(uint32_t entry, Tagged<Object> value) { DCHECK(!IsTheHole(value)); StoreToDataTable(entry, kDataTableValueEntryIndex, value); } void SwissNameDictionary::ValueAtPut(InternalIndex entry, Tagged<Object> value) { - ValueAtPut(entry.as_int(), value); + ValueAtPut(entry.as_uint32(), value); } -void SwissNameDictionary::SetKey(int entry, Tagged<Object> key) { +void SwissNameDictionary::SetKey(uint32_t entry, Tagged<Object> key) { DCHECK(!IsTheHole(key)); StoreToDataTable(entry, kDataTableKeyEntryIndex, key); } -void SwissNameDictionary::DetailsAtPut(int entry, PropertyDetails details) { - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(Capacity())); +void SwissNameDictionary::DetailsAtPut(uint32_t entry, + PropertyDetails details) { + DCHECK_LT(entry, Capacity()); uint8_t encoded_details = details.ToByte(); PropertyDetailsTable()[entry] = encoded_details; } void SwissNameDictionary::DetailsAtPut(InternalIndex entry, PropertyDetails details) { - DetailsAtPut(entry.as_int(), details); + DetailsAtPut(entry.as_uint32(), details); } -Tagged<Object> SwissNameDictionary::KeyAt(int entry) { +Tagged<Object> SwissNameDictionary::KeyAt(uint32_t entry) { return LoadFromDataTable(entry, kDataTableKeyEntryIndex); } Tagged<Object> SwissNameDictionary::KeyAt(InternalIndex entry) { - return KeyAt(entry.as_int()); + return KeyAt(entry.as_uint32()); } Tagged<Name> SwissNameDictionary::NameAt(InternalIndex entry) { @@ -279,13 +289,13 @@ Tagged<Name> SwissNameDictionary::NameAt(InternalIndex entry) { } // This version can be called on empty buckets. -Tagged<Object> SwissNameDictionary::ValueAtRaw(int entry) { +Tagged<Object> SwissNameDictionary::ValueAtRaw(uint32_t entry) { return LoadFromDataTable(entry, kDataTableValueEntryIndex); } Tagged<Object> SwissNameDictionary::ValueAt(InternalIndex entry) { - DCHECK(IsFull(GetCtrl(entry.as_int()))); - return ValueAtRaw(entry.as_int()); + DCHECK(IsFull(GetCtrl(entry.as_uint32()))); + return ValueAtRaw(entry.as_uint32()); } std::optional<Tagged<Object>> SwissNameDictionary::TryValueAt( @@ -294,14 +304,13 @@ std::optional<Tagged<Object>> SwissNameDictionary::TryValueAt( SLOW_DCHECK(Isolate::Current()->heap()->IsPendingAllocation(Tagged(this))); // We can read Capacity() in a non-atomic way since we are reading an // initialized object which is not pending allocation. - if (static_cast<unsigned>(entry.as_int()) >= - static_cast<unsigned>(Capacity())) { + if (entry.as_uint32() >= Capacity()) { return {}; } - return ValueAtRaw(entry.as_int()); + return ValueAtRaw(entry.as_uint32()); } -PropertyDetails SwissNameDictionary::DetailsAt(int entry) { +PropertyDetails SwissNameDictionary::DetailsAt(uint32_t entry) { // GetCtrl(entry) does a bounds check for |entry| value. DCHECK(IsFull(GetCtrl(entry))); @@ -310,7 +319,7 @@ PropertyDetails SwissNameDictionary::DetailsAt(int entry) { } PropertyDetails SwissNameDictionary::DetailsAt(InternalIndex entry) { - return DetailsAt(entry.as_int()); + return DetailsAt(entry.as_uint32()); } // static @@ -319,26 +328,26 @@ template <typename IsolateT, template <typename> typename HandleType> DirectHandle<SwissNameDictionary>>) HandleType<SwissNameDictionary> SwissNameDictionary::EnsureGrowable( IsolateT* isolate, HandleType<SwissNameDictionary> table) { - int capacity = table->Capacity(); + uint32_t capacity = table->Capacity(); if (table->UsedCapacity() < MaxUsableCapacity(capacity)) { // We have room for at least one more entry, nothing to do. return table; } - int new_capacity = capacity == 0 ? kInitialCapacity : capacity * 2; + uint32_t new_capacity = capacity == 0 ? kInitialCapacity : capacity * 2; return Rehash(isolate, table, new_capacity); } -swiss_table::ctrl_t SwissNameDictionary::GetCtrl(int entry) { - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(Capacity())); +swiss_table::ctrl_t SwissNameDictionary::GetCtrl(uint32_t entry) { + DCHECK_LT(entry, Capacity()); return CtrlTable()[entry]; } -void SwissNameDictionary::SetCtrl(int entry, ctrl_t h) { - int capacity = Capacity(); - DCHECK_LT(static_cast<unsigned>(entry), static_cast<unsigned>(capacity)); +void SwissNameDictionary::SetCtrl(uint32_t entry, ctrl_t h) { + uint32_t capacity = Capacity(); + DCHECK_LT(entry, capacity); ctrl_t* ctrl = CtrlTable(); ctrl[entry] = h; @@ -356,17 +365,16 @@ void SwissNameDictionary::SetCtrl(int entry, ctrl_t h) { // from above). If we do need to do some actual copying, we set {copy_entry = // Capacity() + entry}. - int mask = capacity - 1; - int copy_entry = + uint32_t mask = capacity - 1; + uint32_t copy_entry = ((entry - Group::kWidth) & mask) + 1 + ((Group::kWidth - 1) & mask); - DCHECK_IMPLIES(entry < static_cast<int>(Group::kWidth), - copy_entry == capacity + entry); - DCHECK_IMPLIES(entry >= static_cast<int>(Group::kWidth), copy_entry == entry); + DCHECK_IMPLIES(entry < Group::kWidth, copy_entry == capacity + entry); + DCHECK_IMPLIES(entry >= Group::kWidth, copy_entry == entry); ctrl[copy_entry] = h; } // static -inline int SwissNameDictionary::FindFirstEmpty(uint32_t hash) { +inline uint32_t SwissNameDictionary::FindFirstEmpty(uint32_t hash) { // See SwissNameDictionary::FindEntry for description of probing algorithm. auto seq = probe(hash, Capacity()); @@ -384,11 +392,12 @@ inline int SwissNameDictionary::FindFirstEmpty(uint32_t hash) { } } -void SwissNameDictionary::SetMetaTableField(int field_index, int value) { +void SwissNameDictionary::SetMetaTableField(uint32_t field_index, + uint32_t value) { // See the STATIC_ASSERTs on |kMax1ByteMetaTableCapacity| and // |kMax2ByteMetaTableCapacity| in the .cc file for an explanation of these // constants. - int capacity = Capacity(); + uint32_t capacity = Capacity(); Tagged<ByteArray> meta_table = this->meta_table(); if (capacity <= kMax1ByteMetaTableCapacity) { SetMetaTableField<uint8_t>(meta_table, field_index, value); @@ -399,11 +408,11 @@ void SwissNameDictionary::SetMetaTableField(int field_index, int value) { } } -int SwissNameDictionary::GetMetaTableField(int field_index) { +uint32_t SwissNameDictionary::GetMetaTableField(uint32_t field_index) { // See the STATIC_ASSERTs on |kMax1ByteMetaTableCapacity| and // |kMax2ByteMetaTableCapacity| in the .cc file for an explanation of these // constants. - int capacity = Capacity(); + uint32_t capacity = Capacity(); Tagged<ByteArray> meta_table = this->meta_table(); if (capacity <= kMax1ByteMetaTableCapacity) { return GetMetaTableField<uint8_t>(meta_table, field_index); @@ -417,7 +426,8 @@ int SwissNameDictionary::GetMetaTableField(int field_index) { // static template <typename T> void SwissNameDictionary::SetMetaTableField(Tagged<ByteArray> meta_table, - int field_index, int value) { + uint32_t field_index, + uint32_t value) { static_assert((std::is_same_v<T, uint8_t>) || (std::is_same_v<T, uint16_t>) || (std::is_same_v<T, uint32_t>)); DCHECK_LE(value, std::numeric_limits<T>::max()); @@ -428,8 +438,8 @@ void SwissNameDictionary::SetMetaTableField(Tagged<ByteArray> meta_table, // static template <typename T> -int SwissNameDictionary::GetMetaTableField(Tagged<ByteArray> meta_table, - int field_index) { +uint32_t SwissNameDictionary::GetMetaTableField(Tagged<ByteArray> meta_table, + uint32_t field_index) { static_assert((std::is_same_v<T, uint8_t>) || (std::is_same_v<T, uint16_t>) || (std::is_same_v<T, uint32_t>)); DCHECK_LT(meta_table->begin() + field_index * sizeof(T), meta_table->end()); @@ -437,7 +447,8 @@ int SwissNameDictionary::GetMetaTableField(Tagged<ByteArray> meta_table, return raw_data[field_index]; } -constexpr int SwissNameDictionary::MetaTableSizePerEntryFor(int capacity) { +constexpr uint32_t SwissNameDictionary::MetaTableSizePerEntryFor( + uint32_t capacity) { DCHECK(IsValidCapacity(capacity)); // See the STATIC_ASSERTs on |kMax1ByteMetaTableCapacity| and @@ -452,10 +463,10 @@ constexpr int SwissNameDictionary::MetaTableSizePerEntryFor(int capacity) { } } -constexpr int SwissNameDictionary::MetaTableSizeFor(int capacity) { +constexpr uint32_t SwissNameDictionary::MetaTableSizeFor(uint32_t capacity) { DCHECK(IsValidCapacity(capacity)); - int per_entry_size = MetaTableSizePerEntryFor(capacity); + uint32_t per_entry_size = MetaTableSizePerEntryFor(capacity); // The enumeration table only needs to have as many slots as there can be // present + deleted entries in the hash table (= maximum load factor * @@ -469,7 +480,7 @@ bool SwissNameDictionary::IsKey(ReadOnlyRoots roots, return key_candidate != roots.the_hole_value(); } -bool SwissNameDictionary::ToKey(ReadOnlyRoots roots, int entry, +bool SwissNameDictionary::ToKey(ReadOnlyRoots roots, uint32_t entry, Tagged<Object>* out_key) { Tagged<Object> k = KeyAt(entry); if (!IsKey(roots, k)) return false; @@ -479,7 +490,7 @@ bool SwissNameDictionary::ToKey(ReadOnlyRoots roots, int entry, bool SwissNameDictionary::ToKey(ReadOnlyRoots roots, InternalIndex entry, Tagged<Object>* out_key) { - return ToKey(roots, entry.as_int(), out_key); + return ToKey(roots, entry.as_uint32(), out_key); } // static @@ -496,11 +507,11 @@ HandleType<SwissNameDictionary> SwissNameDictionary::Add( EnsureGrowable(isolate, original_table); DisallowGarbageCollection no_gc; Tagged<SwissNameDictionary> raw_table = *table; - int nof = raw_table->NumberOfElements(); - int nod = raw_table->NumberOfDeletedElements(); - int new_enum_index = nof + nod; + uint32_t nof = raw_table->NumberOfElements(); + uint32_t nod = raw_table->NumberOfDeletedElements(); + uint32_t new_enum_index = nof + nod; - int new_entry = raw_table->AddInternal(*key, *value, details); + uint32_t new_entry = raw_table->AddInternal(*key, *value, details); raw_table->SetNumberOfElements(nof + 1); raw_table->SetEntryForEnumerationIndex(new_enum_index, new_entry); @@ -512,8 +523,9 @@ HandleType<SwissNameDictionary> SwissNameDictionary::Add( return table; } -int SwissNameDictionary::AddInternal(Tagged<Name> key, Tagged<Object> value, - PropertyDetails details) { +uint32_t SwissNameDictionary::AddInternal(Tagged<Name> key, + Tagged<Object> value, + PropertyDetails details) { DisallowHeapAllocation no_gc; DCHECK(IsUniqueName(key)); @@ -524,7 +536,7 @@ int SwissNameDictionary::AddInternal(Tagged<Name> key, Tagged<Object> value, // For now we don't reuse deleted buckets (due to enumeration table // complications), which is why we only look for empty buckets here, not // deleted ones. - int target = FindFirstEmpty(hash); + uint32_t target = FindFirstEmpty(hash); SetCtrl(target, swiss_table::H2(hash)); SetKey(target, key); @@ -540,7 +552,7 @@ int SwissNameDictionary::AddInternal(Tagged<Name> key, Tagged<Object> value, template <typename IsolateT> void SwissNameDictionary::Initialize(IsolateT* isolate, Tagged<ByteArray> meta_table, - int capacity) { + uint32_t capacity) { DCHECK(IsValidCapacity(capacity)); DisallowHeapAllocation no_gc; ReadOnlyRoots roots(isolate); @@ -564,7 +576,7 @@ void SwissNameDictionary::Initialize(IsolateT* isolate, } SwissNameDictionary::IndexIterator::IndexIterator( - DirectHandle<SwissNameDictionary> dict, int start) + DirectHandle<SwissNameDictionary> dict, uint32_t start) : enum_index_{start}, dict_{dict} { if (dict.is_null()) { used_capacity_ = 0; @@ -645,48 +657,53 @@ void SwissNameDictionary::SetHash(int32_t hash) { hash_ = hash; } int SwissNameDictionary::Hash() { return hash_; } // static -constexpr int SwissNameDictionary::PrefixOffset() { return sizeof(HeapObject); } +constexpr SwissNameDictionary::Offset SwissNameDictionary::PrefixOffset() { + return sizeof(HeapObject); +} // static -constexpr int SwissNameDictionary::CapacityOffset() { +constexpr SwissNameDictionary::Offset SwissNameDictionary::CapacityOffset() { return PrefixOffset() + sizeof(uint32_t); } // static -constexpr int SwissNameDictionary::MetaTablePointerOffset() { - return CapacityOffset() + sizeof(int32_t); +constexpr SwissNameDictionary::Offset +SwissNameDictionary::MetaTablePointerOffset() { + return CapacityOffset() + sizeof(uint32_t); } // static -constexpr int SwissNameDictionary::DataTableStartOffset() { +constexpr SwissNameDictionary::Offset +SwissNameDictionary::DataTableStartOffset() { return MetaTablePointerOffset() + kTaggedSize; } // static -constexpr int SwissNameDictionary::DataTableEndOffset(int capacity) { +constexpr SwissNameDictionary::Offset SwissNameDictionary::DataTableEndOffset( + uint32_t capacity) { return CtrlTableStartOffset(capacity); } // static -constexpr int SwissNameDictionary::CtrlTableStartOffset(int capacity) { +constexpr SwissNameDictionary::Offset SwissNameDictionary::CtrlTableStartOffset( + uint32_t capacity) { return DataTableStartOffset() + DataTableSize(capacity); } // static -constexpr int SwissNameDictionary::PropertyDetailsTableStartOffset( - int capacity) { +constexpr SwissNameDictionary::Offset +SwissNameDictionary::PropertyDetailsTableStartOffset(uint32_t capacity) { return CtrlTableStartOffset(capacity) + CtrlTableSize(capacity); } // static -constexpr int SwissNameDictionary::MaxCapacity() { - // TODO(375937549): Convert to uint32_t. - constexpr int kConstSize = +constexpr uint32_t SwissNameDictionary::MaxCapacity() { + constexpr uint32_t kConstSize = SwissNameDictionary::DataTableStartOffset() + OFFSET_OF_DATA_START(ByteArray) + // Size for present and deleted element count at max capacity: 2 * sizeof(uint32_t); - constexpr int kPerEntrySize = + constexpr uint32_t kPerEntrySize = // size of data table entries: kDataTableEntryCount * kTaggedSize + // ctrl table entry size: @@ -696,9 +713,8 @@ constexpr int SwissNameDictionary::MaxCapacity() { // Enumeration table entry size at maximum capacity: sizeof(uint32_t); - constexpr int result = - (static_cast<int>(kMaxFixedArrayCapacity) * kTaggedSize - kConstSize) / - kPerEntrySize; + constexpr uint32_t result = + (kMaxFixedArrayCapacity * kTaggedSize - kConstSize) / kPerEntrySize; static_assert(Smi::kMaxValue >= result); return result; @@ -728,12 +744,12 @@ bool SwissNameDictionary::IsEmptyOrDeleted(ctrl_t c) { // static swiss_table::ProbeSequence<SwissNameDictionary::kGroupWidth> -SwissNameDictionary::probe(uint32_t hash, int capacity) { +SwissNameDictionary::probe(uint32_t hash, uint32_t capacity) { // If |capacity| is 0, we must produce 1 here, such that the - 1 below // yields 0, which is the correct modulo mask for a table of capacity 0. - int non_zero_capacity = capacity | (capacity == 0); + uint32_t non_zero_capacity = capacity | (capacity == 0); return swiss_table::ProbeSequence<SwissNameDictionary::kGroupWidth>( - swiss_table::H1(hash), static_cast<uint32_t>(non_zero_capacity - 1)); + swiss_table::H1(hash), non_zero_capacity - 1); } Tagged<ByteArray> SwissNameDictionary::meta_table() const { diff --git a/deps/v8/src/objects/swiss-name-dictionary.cc b/deps/v8/src/objects/swiss-name-dictionary.cc index 33e75f54556f..8f58212d7a95 100644 --- a/deps/v8/src/objects/swiss-name-dictionary.cc +++ b/deps/v8/src/objects/swiss-name-dictionary.cc @@ -19,18 +19,18 @@ HandleType<SwissNameDictionary> SwissNameDictionary::DeleteEntry( Isolate* isolate, HandleType<SwissNameDictionary> table, InternalIndex entry) { // GetCtrl() does the bounds check. - DCHECK(IsFull(table->GetCtrl(entry.as_int()))); + DCHECK(IsFull(table->GetCtrl(entry.as_uint32()))); - int i = entry.as_int(); + uint32_t i = entry.as_uint32(); table->SetCtrl(i, Ctrl::kDeleted); table->ClearDataTableEntry(isolate, i); // We leave the PropertyDetails unchanged because they are not relevant for // GC. - int nof = table->NumberOfElements(); + uint32_t nof = table->NumberOfElements(); table->SetNumberOfElements(nof - 1); - int nod = table->NumberOfDeletedElements(); + uint32_t nod = table->NumberOfDeletedElements(); table->SetNumberOfDeletedElements(nod + 1); // TODO(v8:11388) Abseil's flat_hash_map doesn't shrink on deletion, but may @@ -47,7 +47,7 @@ template <typename IsolateT, template <typename> typename HandleType> DirectHandle<SwissNameDictionary>>) HandleType<SwissNameDictionary> SwissNameDictionary::Rehash( IsolateT* isolate, HandleType<SwissNameDictionary> table, - int new_capacity) { + uint32_t new_capacity) { DCHECK(IsValidCapacity(new_capacity)); DCHECK_LE(table->NumberOfElements(), MaxUsableCapacity(new_capacity)); ReadOnlyRoots roots(isolate); @@ -60,10 +60,11 @@ HandleType<SwissNameDictionary> SwissNameDictionary::Rehash( DisallowHeapAllocation no_gc; - int new_enum_index = 0; + uint32_t new_enum_index = 0; new_table->SetNumberOfElements(table->NumberOfElements()); - for (int enum_index = 0; enum_index < table->UsedCapacity(); ++enum_index) { - int entry = table->EntryForEnumerationIndex(enum_index); + for (uint32_t enum_index = 0; enum_index < table->UsedCapacity(); + ++enum_index) { + uint32_t entry = table->EntryForEnumerationIndex(enum_index); Tagged<Object> key; @@ -71,7 +72,8 @@ HandleType<SwissNameDictionary> SwissNameDictionary::Rehash( Tagged<Object> value = table->ValueAtRaw(entry); PropertyDetails details = table->DetailsAt(entry); - int new_entry = new_table->AddInternal(Cast<Name>(key), value, details); + uint32_t new_entry = + new_table->AddInternal(Cast<Name>(key), value, details); // TODO(v8::11388) Investigate ways of hoisting the branching needed to // select the correct meta table entry size (based on the capacity of the @@ -93,12 +95,12 @@ bool SwissNameDictionary::EqualsForTesting(Tagged<SwissNameDictionary> other) { return false; } - for (int i = 0; i < Capacity() + kGroupWidth; i++) { + for (uint32_t i = 0; i < Capacity() + kGroupWidth; i++) { if (CtrlTable()[i] != other->CtrlTable()[i]) { return false; } } - for (int i = 0; i < Capacity(); i++) { + for (uint32_t i = 0; i < Capacity(); i++) { if (KeyAt(i) != other->KeyAt(i) || ValueAtRaw(i) != other->ValueAtRaw(i)) { return false; } @@ -106,7 +108,7 @@ bool SwissNameDictionary::EqualsForTesting(Tagged<SwissNameDictionary> other) { if (DetailsAt(i) != other->DetailsAt(i)) return false; } } - for (int i = 0; i < UsedCapacity(); i++) { + for (uint32_t i = 0; i < UsedCapacity(); i++) { if (EntryForEnumerationIndex(i) != other->EntryForEnumerationIndex(i)) { return false; } @@ -126,8 +128,8 @@ DirectHandle<SwissNameDictionary> SwissNameDictionary::ShallowCopy( return table; } - int capacity = table->Capacity(); - int used_capacity = table->UsedCapacity(); + uint32_t capacity = table->Capacity(); + uint32_t used_capacity = table->UsedCapacity(); DirectHandle<SwissNameDictionary> new_table = isolate->factory()->NewSwissNameDictionaryWithCapacity( @@ -153,7 +155,7 @@ DirectHandle<SwissNameDictionary> SwissNameDictionary::ShallowCopy( DCHECK_EQ(UPDATE_WRITE_BARRIER, *mode); // We may have to trigger write barriers when copying the data table. - for (int i = 0; i < capacity; ++i) { + for (uint32_t i = 0; i < capacity; ++i) { Tagged<Object> key = table->KeyAt(i); Tagged<Object> value = table->ValueAtRaw(i); @@ -169,7 +171,7 @@ DirectHandle<SwissNameDictionary> SwissNameDictionary::ShallowCopy( } // PropertyDetails table may contain uninitialized data for unused slots. - for (int i = 0; i < capacity; ++i) { + for (uint32_t i = 0; i < capacity; ++i) { if (IsFull(table->GetCtrl(i))) { new_table->DetailsAtPut(i, table->DetailsAt(i)); } @@ -177,8 +179,9 @@ DirectHandle<SwissNameDictionary> SwissNameDictionary::ShallowCopy( // Meta table is only initialized for the first 2 + UsedCapacity() entries, // where size of each entry depends on table capacity. - int size_per_meta_table_entry = MetaTableSizePerEntryFor(capacity); - int meta_table_used_bytes = (2 + used_capacity) * size_per_meta_table_entry; + uint32_t size_per_meta_table_entry = MetaTableSizePerEntryFor(capacity); + uint32_t meta_table_used_bytes = + (2 + used_capacity) * size_per_meta_table_entry; MemCopy(new_table->meta_table()->begin(), table->meta_table()->begin(), meta_table_used_bytes); @@ -198,10 +201,10 @@ HandleType<SwissNameDictionary> SwissNameDictionary::Shrink( // table. Abseil's heuristic doesn't take the number of deleted elements into // account, because it doesn't track that. - int nof = table->NumberOfElements(); - int capacity = table->Capacity(); + uint32_t nof = table->NumberOfElements(); + uint32_t capacity = table->Capacity(); if (nof >= (capacity >> 2)) return table; - int new_capacity = std::max(capacity / 2, kInitialCapacity); + uint32_t new_capacity = std::max(capacity / 2, kInitialCapacity); return Rehash(isolate, table, new_capacity); } @@ -235,9 +238,9 @@ void SwissNameDictionary::Rehash(IsolateT* isolate) { std::vector<Entry> data(NumberOfElements(), dummy); ReadOnlyRoots roots(isolate); - int data_index = 0; - for (int enum_index = 0; enum_index < UsedCapacity(); ++enum_index) { - int entry = EntryForEnumerationIndex(enum_index); + uint32_t data_index = 0; + for (uint32_t enum_index = 0; enum_index < UsedCapacity(); ++enum_index) { + uint32_t entry = EntryForEnumerationIndex(enum_index); Tagged<Object> key; if (!ToKey(roots, entry, &key)) continue; @@ -247,10 +250,10 @@ void SwissNameDictionary::Rehash(IsolateT* isolate) { Initialize(isolate, meta_table(), Capacity()); - int new_enum_index = 0; - SetNumberOfElements(static_cast<int>(data.size())); + uint32_t new_enum_index = 0; + SetNumberOfElements(static_cast<uint32_t>(data.size())); for (Entry& e : data) { - int new_entry = AddInternal(e.key, e.value, e.details); + uint32_t new_entry = AddInternal(e.key, e.value, e.details); // TODO(v8::11388) Investigate ways of hoisting the branching needed to // select the correct meta table entry size (based on the capacity of the @@ -309,9 +312,9 @@ static_assert(SwissNameDictionary::MaxUsableCapacity( std::numeric_limits<uint16_t>::max()); template V8_EXPORT_PRIVATE void SwissNameDictionary::Initialize( - Isolate* isolate, Tagged<ByteArray> meta_table, int capacity); + Isolate* isolate, Tagged<ByteArray> meta_table, uint32_t capacity); template V8_EXPORT_PRIVATE void SwissNameDictionary::Initialize( - LocalIsolate* isolate, Tagged<ByteArray> meta_table, int capacity); + LocalIsolate* isolate, Tagged<ByteArray> meta_table, uint32_t capacity); template V8_EXPORT_PRIVATE DirectHandle<SwissNameDictionary> SwissNameDictionary::DeleteEntry(Isolate* isolate, @@ -325,19 +328,19 @@ SwissNameDictionary::DeleteEntry(Isolate* isolate, template V8_EXPORT_PRIVATE DirectHandle<SwissNameDictionary> SwissNameDictionary::Rehash(LocalIsolate* isolate, DirectHandle<SwissNameDictionary> table, - int new_capacity); + uint32_t new_capacity); template V8_EXPORT_PRIVATE DirectHandle<SwissNameDictionary> SwissNameDictionary::Rehash(Isolate* isolate, DirectHandle<SwissNameDictionary> table, - int new_capacity); + uint32_t new_capacity); template V8_EXPORT_PRIVATE IndirectHandle<SwissNameDictionary> SwissNameDictionary::Rehash(LocalIsolate* isolate, IndirectHandle<SwissNameDictionary> table, - int new_capacity); + uint32_t new_capacity); template V8_EXPORT_PRIVATE IndirectHandle<SwissNameDictionary> SwissNameDictionary::Rehash(Isolate* isolate, IndirectHandle<SwissNameDictionary> table, - int new_capacity); + uint32_t new_capacity); template V8_EXPORT_PRIVATE void SwissNameDictionary::Rehash( LocalIsolate* isolate); @@ -350,8 +353,8 @@ template V8_EXPORT_PRIVATE IndirectHandle<SwissNameDictionary> SwissNameDictionary::Shrink(Isolate* isolate, IndirectHandle<SwissNameDictionary> table); -constexpr int SwissNameDictionary::kInitialCapacity; -constexpr int SwissNameDictionary::kGroupWidth; +constexpr uint32_t SwissNameDictionary::kInitialCapacity; +constexpr uint32_t SwissNameDictionary::kGroupWidth; } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/swiss-name-dictionary.h b/deps/v8/src/objects/swiss-name-dictionary.h index a66d8c765aa6..bdc89639f42b 100644 --- a/deps/v8/src/objects/swiss-name-dictionary.h +++ b/deps/v8/src/objects/swiss-name-dictionary.h @@ -118,11 +118,11 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { inline void ValueAtPut(InternalIndex entry, Tagged<Object> value); inline void DetailsAtPut(InternalIndex entry, PropertyDetails value); - inline int NumberOfElements(); - inline int NumberOfDeletedElements(); + inline uint32_t NumberOfElements(); + inline uint32_t NumberOfDeletedElements(); - inline int Capacity(); - inline int UsedCapacity(); + inline uint32_t Capacity(); + inline uint32_t UsedCapacity(); int NumberOfEnumerableProperties(); @@ -141,14 +141,14 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { template <typename IsolateT> void Initialize(IsolateT* isolate, Tagged<ByteArray> meta_table, - int capacity); + uint32_t capacity); template <typename IsolateT, template <typename> typename HandleType> requires(std::is_convertible_v<HandleType<SwissNameDictionary>, DirectHandle<SwissNameDictionary>>) static HandleType<SwissNameDictionary> Rehash( IsolateT* isolate, HandleType<SwissNameDictionary> table, - int new_capacity); + uint32_t new_capacity); template <typename IsolateT> void Rehash(IsolateT* isolate); @@ -159,7 +159,8 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { class IndexIterator { public: - inline IndexIterator(DirectHandle<SwissNameDictionary> dict, int start); + inline IndexIterator(DirectHandle<SwissNameDictionary> dict, + uint32_t start); inline IndexIterator& operator++(); @@ -169,8 +170,8 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { inline InternalIndex operator*(); private: - int used_capacity_; - int enum_index_; + uint32_t used_capacity_; + uint32_t enum_index_; // This may be an empty handle, but only if the capacity of the table is // 0 and pointer compression is disabled. @@ -196,25 +197,25 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { // For the given enumeration index, returns the entry (= bucket of the Swiss // Table) containing the data for the mapping with that enumeration index. // The returned bucket may be deleted. - inline int EntryForEnumerationIndex(int enumeration_index); + inline uint32_t EntryForEnumerationIndex(uint32_t enumeration_index); - inline static constexpr bool IsValidCapacity(int capacity); - inline static int CapacityFor(int at_least_space_for); + inline static constexpr bool IsValidCapacity(uint32_t capacity); + inline static uint32_t CapacityFor(uint32_t at_least_space_for); // Given a capacity, how much of it can we fill before resizing? - inline static constexpr int MaxUsableCapacity(int capacity); + inline static constexpr uint32_t MaxUsableCapacity(uint32_t capacity); // The maximum allowed capacity for any SwissNameDictionary. - inline static constexpr int MaxCapacity(); + inline static constexpr uint32_t MaxCapacity(); // Returns total size in bytes required for a table of given capacity. - inline static constexpr int SizeFor(int capacity); + inline static constexpr uint32_t SizeFor(uint32_t capacity); - inline static constexpr int MetaTableSizePerEntryFor(int capacity); - inline static constexpr int MetaTableSizeFor(int capacity); + inline static constexpr uint32_t MetaTableSizePerEntryFor(uint32_t capacity); + inline static constexpr uint32_t MetaTableSizeFor(uint32_t capacity); - inline static constexpr int DataTableSize(int capacity); - inline static constexpr int CtrlTableSize(int capacity); + inline static constexpr uint32_t DataTableSize(uint32_t capacity); + inline static constexpr uint32_t CtrlTableSize(uint32_t capacity); // Indicates that IterateEntries() returns entries ordered. static constexpr bool kIsOrderedDictionaryType = true; @@ -223,20 +224,22 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { // InternalIndex::NotFound() is always used instead. static constexpr int kNotFoundSentinel = -1; - static const int kGroupWidth = Group::kWidth; + static const uint32_t kGroupWidth = Group::kWidth; static const bool kUseSIMD = kGroupWidth == 16; class BodyDescriptor; // Note that 0 is also a valid capacity. Changing this value to a smaller one // may make some padding necessary in the data layout. - static constexpr int kInitialCapacity = kSwissNameDictionaryInitialCapacity; + static constexpr uint32_t kInitialCapacity = + kSwissNameDictionaryInitialCapacity; // Defines how many kTaggedSize sized values are associcated which each entry // in the data table. - static constexpr int kDataTableEntryCount = 2; - static constexpr int kDataTableKeyEntryIndex = 0; - static constexpr int kDataTableValueEntryIndex = kDataTableKeyEntryIndex + 1; + static constexpr uint32_t kDataTableEntryCount = 2; + static constexpr uint32_t kDataTableKeyEntryIndex = 0; + static constexpr uint32_t kDataTableValueEntryIndex = + kDataTableKeyEntryIndex + 1; // Field indices describing the layout of the meta table: A field index of i // means that the corresponding meta table entry resides at an offset of {i * @@ -244,31 +247,32 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { // uintX_t can be 8, 16, or 32, and depends on the capacity of the overall // SwissNameDictionary. See the section "Meta table" in the comment at the // beginning of the SwissNameDictionary class in this file. - static constexpr int kMetaTableElementCountFieldIndex = 0; - static constexpr int kMetaTableDeletedElementCountFieldIndex = 1; + static constexpr uint32_t kMetaTableElementCountFieldIndex = 0; + static constexpr uint32_t kMetaTableDeletedElementCountFieldIndex = 1; // Field index of the first entry of the enumeration table (which is part of // the meta table). - static constexpr int kMetaTableEnumerationDataStartIndex = 2; + static constexpr uint32_t kMetaTableEnumerationDataStartIndex = 2; // The maximum capacity of any SwissNameDictionary whose meta table can use 1 // byte per entry. - static constexpr int kMax1ByteMetaTableCapacity = (1 << 8); + static constexpr uint32_t kMax1ByteMetaTableCapacity = (1 << 8); // The maximum capacity of any SwissNameDictionary whose meta table can use 2 // bytes per entry. - static constexpr int kMax2ByteMetaTableCapacity = (1 << 16); + static constexpr uint32_t kMax2ByteMetaTableCapacity = (1 << 16); // TODO(v8:11388) We would like to use Torque-generated constants here, but // those are currently incorrect. // Offset into the overall table, starting at HeapObject standard fields, // in bytes. This means that the map is stored at offset 0. - using Offset = int; + using Offset = uint32_t; inline static constexpr Offset PrefixOffset(); inline static constexpr Offset CapacityOffset(); inline static constexpr Offset MetaTablePointerOffset(); inline static constexpr Offset DataTableStartOffset(); - inline static constexpr Offset DataTableEndOffset(int capacity); - inline static constexpr Offset CtrlTableStartOffset(int capacity); - inline static constexpr Offset PropertyDetailsTableStartOffset(int capacity); + inline static constexpr Offset DataTableEndOffset(uint32_t capacity); + inline static constexpr Offset CtrlTableStartOffset(uint32_t capacity); + inline static constexpr Offset PropertyDetailsTableStartOffset( + uint32_t capacity); #if VERIFY_HEAP void SwissNameDictionaryVerify(Isolate* isolate, bool slow_checks); @@ -291,25 +295,26 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { inline uint8_t* PropertyDetailsTable(); // Sets key and value to the hole for the given entry. - inline void ClearDataTableEntry(Isolate* isolate, int entry); - inline void SetKey(int entry, Tagged<Object> key); + inline void ClearDataTableEntry(Isolate* isolate, uint32_t entry); + inline void SetKey(uint32_t entry, Tagged<Object> key); - inline void DetailsAtPut(int entry, PropertyDetails value); - inline void ValueAtPut(int entry, Tagged<Object> value); + inline void DetailsAtPut(uint32_t entry, PropertyDetails value); + inline void ValueAtPut(uint32_t entry, Tagged<Object> value); - inline PropertyDetails DetailsAt(int entry); - inline Tagged<Object> ValueAtRaw(int entry); - inline Tagged<Object> KeyAt(int entry); + inline PropertyDetails DetailsAt(uint32_t entry); + inline Tagged<Object> ValueAtRaw(uint32_t entry); + inline Tagged<Object> KeyAt(uint32_t entry); - inline bool ToKey(ReadOnlyRoots roots, int entry, Tagged<Object>* out_key); + inline bool ToKey(ReadOnlyRoots roots, uint32_t entry, + Tagged<Object>* out_key); - inline int FindFirstEmpty(uint32_t hash); + inline uint32_t FindFirstEmpty(uint32_t hash); // Adds |key| -> (|value|, |details|) as a new mapping to the table, which // must have sufficient room. Returns the entry (= bucket) used by the new // mapping. Does not update the number of present entries or the // enumeration table. - inline int AddInternal(Tagged<Name> key, Tagged<Object> value, - PropertyDetails details); + inline uint32_t AddInternal(Tagged<Name> key, Tagged<Object> value, + PropertyDetails details); // Use |set_ctrl| for modifications whenever possible, since that function // correctly maintains the copy of the first group at the end of the ctrl @@ -323,44 +328,48 @@ V8_OBJECT class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject { // Sets the a control byte, taking the necessary copying of the first group // into account. - inline void SetCtrl(int entry, ctrl_t h); - inline ctrl_t GetCtrl(int entry); + inline void SetCtrl(uint32_t entry, ctrl_t h); + inline ctrl_t GetCtrl(uint32_t entry); - inline Tagged<Object> LoadFromDataTable(int entry, int data_offset); - inline void StoreToDataTable(int entry, int data_offset, Tagged<Object> data); - inline void StoreToDataTableNoBarrier(int entry, int data_offset, + inline Tagged<Object> LoadFromDataTable(uint32_t entry, uint32_t data_offset); + inline void StoreToDataTable(uint32_t entry, uint32_t data_offset, + Tagged<Object> data); + inline void StoreToDataTableNoBarrier(uint32_t entry, uint32_t data_offset, Tagged<Object> data); - inline void SetCapacity(int capacity); - inline void SetNumberOfElements(int elements); - inline void SetNumberOfDeletedElements(int deleted_elements); + inline void SetCapacity(uint32_t capacity); + inline void SetNumberOfElements(uint32_t elements); + inline void SetNumberOfDeletedElements(uint32_t deleted_elements); - static inline swiss_table::ProbeSequence<Group::kWidth> probe(uint32_t hash, - int capacity); + static inline swiss_table::ProbeSequence<Group::kWidth> probe( + uint32_t hash, uint32_t capacity); // Sets that the entry with the given |enumeration_index| is stored at the // given bucket of the data table. - inline void SetEntryForEnumerationIndex(int enumeration_index, int entry); + inline void SetEntryForEnumerationIndex(uint32_t enumeration_index, + uint32_t entry); DECL_ACCESSORS(meta_table, Tagged<ByteArray>) - inline void SetMetaTableField(int field_index, int value); - inline int GetMetaTableField(int field_index); + inline void SetMetaTableField(uint32_t field_index, uint32_t value); + inline uint32_t GetMetaTableField(uint32_t field_index); template <typename T> inline static void SetMetaTableField(Tagged<ByteArray> meta_table, - int field_index, int value); + uint32_t field_index, uint32_t value); template <typename T> - inline static int GetMetaTableField(Tagged<ByteArray> meta_table, - int field_index); + inline static uint32_t GetMetaTableField(Tagged<ByteArray> meta_table, + uint32_t field_index); public: uint32_t hash_; - int32_t capacity_; + V8_TQ_CONST uint32_t capacity_; TaggedMember<ByteArray> meta_table_; // The data_table is followed by ctrl_table and property_details_table. // Their start offsets are computed by CtrlTableStartOffset(capacity) / // PropertyDetailsTableStartOffset(capacity) since FLEXIBLE_ARRAY_MEMBER - // can only model a single trailing variable-length section. + // can only model a single trailing variable-length section. Torque (and + // CSA) only ever reach the tail through these C++ offset helpers. + V8_TQ_NO_TAIL; FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, data_table); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/swiss-name-dictionary.tq b/deps/v8/src/objects/swiss-name-dictionary.tq index e2539d9b52f7..fc4b4911478a 100644 --- a/deps/v8/src/objects/swiss-name-dictionary.tq +++ b/deps/v8/src/objects/swiss-name-dictionary.tq @@ -4,14 +4,13 @@ #include 'src/objects/swiss-name-dictionary.h' +// The variable-length tail (data table, ctrl table, property details table) +// is only reached through C++ offset helpers; see swiss-name-dictionary.h. @cppObjectLayoutDefinition extern class SwissNameDictionary extends HeapObject { hash: uint32; - const capacity: int32; + const capacity: uint32; meta_table: ByteArray; - data_table[Convert<intptr>(capacity) * 2]: JSAny|TheHole; - ctrl_table[Convert<intptr>(capacity) + swiss_table::kGroupWidth]: uint8; - property_details_table[Convert<intptr>(capacity)]: uint8; } namespace swiss_table { @@ -153,9 +152,10 @@ macro FindEntry<GroupLoader: type>(table: SwissNameDictionary, key: Name): never labels Found(intptr), NotFound { const hash: uint32 = LoadNameHashAssumeComputed(key); - const capacity: int32 = table.capacity; - const nonZeroCapacity: int32 = capacity | Convert<int32>(capacity == 0); - const mask: uint32 = Unsigned(nonZeroCapacity - 1); + const capacity: uint32 = table.capacity; + const nonZeroCapacity: uint32 = + capacity | Unsigned(Convert<int32>(capacity == 0)); + const mask: uint32 = nonZeroCapacity - 1; const ctrlTableStart: intptr = SwissNameDictionaryCtrlTableStartOffsetMT(Convert<intptr>(capacity)) + diff --git a/deps/v8/src/objects/synthetic-module.cc b/deps/v8/src/objects/synthetic-module.cc index d9018debc871..c4917ab86370 100644 --- a/deps/v8/src/objects/synthetic-module.cc +++ b/deps/v8/src/objects/synthetic-module.cc @@ -53,7 +53,10 @@ void SyntheticModule::SetExportStrict(Isolate* isolate, // Implements Synthetic Module Record's ResolveExport concrete method: // https://heycam.github.io/webidl/#smr-resolveexport MaybeHandle<Cell> SyntheticModule::ResolveExport( - Isolate* isolate, DirectHandle<SyntheticModule> module, + Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, DirectHandle<String> module_specifier, DirectHandle<String> export_name, MessageLocation loc, bool must_resolve) { Handle<Object> object(module->exports()->Lookup(export_name), isolate); @@ -70,9 +73,9 @@ MaybeHandle<Cell> SyntheticModule::ResolveExport( // Implements Synthetic Module Record's Instantiate concrete method : // https://heycam.github.io/webidl/#smr-instantiate -bool SyntheticModule::PrepareInstantiate(Isolate* isolate, - DirectHandle<SyntheticModule> module, - v8::Local<v8::Context> context) { +bool SyntheticModule::PrepareInstantiate( + Isolate* isolate, DirectHandle<InState<kPreLinking>> module, + v8::Local<v8::Context> context) { Handle<ObjectHashTable> exports(module->exports(), isolate); DirectHandle<FixedArray> export_names(module->export_names(), isolate); // Spec step 7: For each export_name in module->export_names... @@ -93,13 +96,13 @@ bool SyntheticModule::PrepareInstantiate(Isolate* isolate, // as there are no imports or indirect exports to resolve; // just update status. bool SyntheticModule::FinishInstantiate(Isolate* isolate, - DirectHandle<SyntheticModule> module) { - module->SetStatus(kLinked); + Handle<InState<kPreLinking>> module) { + Handle<InState<kLinked>> linked = TransitionStatus<kLinked>(module); // Ensure that if the namespace binding was created it is not empty. - if (!IsUndefined(module->module_namespace())) { - Module::GetModuleNamespace(isolate, handle(*module, isolate)); - DCHECK(!IsUndefined(Cast<Cell>(module->module_namespace())->value())); + if (!IsUndefined(linked->module_namespace())) { + Module::GetModuleNamespace(isolate, linked); + DCHECK(!IsUndefined(Cast<Cell>(linked->module_namespace())->value())); } return true; @@ -117,28 +120,36 @@ bool SyntheticModule::FinishInstantiate(Isolate* isolate, // deprecated overload is gone. DISABLE_CFI_ICALL MaybeDirectHandle<JSPromise> SyntheticModule::Evaluate( - Isolate* isolate, DirectHandle<SyntheticModule> module) { - module->SetStatus(kEvaluating); + Isolate* isolate, DirectHandle<InState<kLinked>> module) { + // Module::Evaluate returns the top-level capability of an already evaluated + // or errored synthetic module. + DirectHandle<InState<kEvaluating>> evaluating = + TransitionStatus<kEvaluating>(module); v8::Module::SyntheticModuleEvaluationSteps evaluation_steps = FUNCTION_CAST<v8::Module::SyntheticModuleEvaluationSteps>( - module->evaluation_steps()->foreign_address<kSyntheticModuleTag>()); + evaluating->evaluation_steps() + ->foreign_address<kSyntheticModuleTag>()); // Deliberately received as a v8::Local<v8::Value>: the deprecated callback // signature only promises a Promise, it doesn't guarantee one. v8::Local<v8::Value> result; if (!evaluation_steps(Utils::ToLocal(isolate->native_context()), - Utils::ToLocal(Cast<Module>(module))) + Utils::ToLocal(DirectHandle<Module>(evaluating))) .ToLocal(&result)) { - module->RecordError(isolate, isolate->exception()); + RecordError(isolate, evaluating, + direct_handle(isolate->exception(), isolate)); return MaybeDirectHandle<JSPromise>(); } - module->SetStatus(kEvaluated); - DirectHandle<Object> result_from_callback = Utils::OpenDirectHandle(*result); CHECK(IsJSPromise(*result_from_callback)); DirectHandle<JSPromise> capability = Cast<JSPromise>(result_from_callback); - module->set_top_level_capability(*capability); + // The API contract is that the evaluation steps return a resolved promise on + // success; the module's capability must settle with its status. + DCHECK_EQ(capability->status(), Promise::kFulfilled); + DirectHandle<InState<kEvaluated>> evaluated = + TransitionStatus<kEvaluated>(evaluating); + evaluated->set_top_level_capability(*capability); return capability; } diff --git a/deps/v8/src/objects/synthetic-module.h b/deps/v8/src/objects/synthetic-module.h index 0a2cef18d9d9..1ac399d43206 100644 --- a/deps/v8/src/objects/synthetic-module.h +++ b/deps/v8/src/objects/synthetic-module.h @@ -59,19 +59,25 @@ V8_OBJECT class SyntheticModule : public Module { private: friend class Module; + template <Status... kStates> + using InState = Module::InState<SyntheticModule, kStates...>; + static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport( - Isolate* isolate, DirectHandle<SyntheticModule> module, + Isolate* isolate, + DirectHandle<InState<kPreLinking, kLinking, kLinked, kEvaluatingAsync, + kEvaluated, kEvaluatedError>> + module, DirectHandle<String> module_specifier, DirectHandle<String> export_name, MessageLocation loc, bool must_resolve); static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( - Isolate* isolate, DirectHandle<SyntheticModule> module, + Isolate* isolate, DirectHandle<InState<kPreLinking>> module, v8::Local<v8::Context> context); static V8_WARN_UNUSED_RESULT bool FinishInstantiate( - Isolate* isolate, DirectHandle<SyntheticModule> module); + Isolate* isolate, Handle<InState<kPreLinking>> module); static V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSPromise> Evaluate( - Isolate* isolate, DirectHandle<SyntheticModule> module); + Isolate* isolate, DirectHandle<InState<kLinked>> module); public: TaggedMember<String> name_; diff --git a/deps/v8/src/objects/tagged-field-inl.h b/deps/v8/src/objects/tagged-field-inl.h index 099ed0b78608..8dccf33b599e 100644 --- a/deps/v8/src/objects/tagged-field-inl.h +++ b/deps/v8/src/objects/tagged-field-inl.h @@ -13,6 +13,7 @@ #include "src/common/globals.h" #include "src/common/ptr-compr-inl.h" #include "src/heap/heap-write-barrier-inl.h" +#include "src/objects/smi.h" #include "src/objects/tagged.h" namespace v8 { @@ -51,6 +52,55 @@ Tagged_t TaggedMember<T, CompressionScheme>::full_to_tagged(Address value) { #endif } +template <typename T, typename CompressionScheme> +TaggedMember<T, CompressionScheme>::TaggedMember(Tagged<Smi> value) { + static_assert(is_subtype_v<Smi, T>); + store_no_write_barrier(value); +} + +template <typename T, typename CompressionScheme> +TaggedMember<T, CompressionScheme>::TaggedMember(Tagged<Smi> value, + RelaxedStoreTag) { + static_assert(is_subtype_v<Smi, T>); + Relaxed_Store_no_write_barrier(value); +} + +template <typename T, typename CompressionScheme> +TaggedMember<T, CompressionScheme>::TaggedMember( + Tagged<ClearedWeakValue> value) { + static_assert(is_subtype_v<ClearedWeakValue, T>); + store_no_write_barrier(value); +} + +template <typename T, typename CompressionScheme> +template <typename U> +TaggedMember<T, CompressionScheme>::TaggedMember(Tagged<ReadOnly<U>> value) + requires(is_subtype_v<ReadOnly<U>, T>) +{ + store_no_write_barrier(value); +} + +template <typename T, typename CompressionScheme> +template <typename U> +TaggedMember<T, CompressionScheme>::TaggedMember(Tagged<ReadOnly<U>> value, + RelaxedStoreTag) + requires(is_subtype_v<ReadOnly<U>, T>) +{ + Relaxed_Store_no_write_barrier(value); +} + +template <typename T, typename CompressionScheme> +TaggedMember<T, CompressionScheme>::TaggedMember( + const AllocationWitness& witness, Tagged<T> value) { + store(witness.object(), value, witness.write_barrier_mode()); +} + +template <typename T, typename CompressionScheme> +TaggedMember<T, CompressionScheme>::TaggedMember( + const AllocationWitness& witness, Tagged<T> value, RelaxedStoreTag) { + Relaxed_Store(witness.object(), value, witness.write_barrier_mode()); +} + template <typename T, typename CompressionScheme> Tagged<T> TaggedMember<T, CompressionScheme>::load() const { return Tagged<T>(tagged_to_full(ptr())); @@ -184,6 +234,28 @@ void TaggedMember<T, CompressionScheme>::WriteBarrier(HeapObject* host, #endif } +template <typename Group> +Group SmiBitFieldMember<Group>::load() const { + return Group(Smi::To31BitPattern(TaggedMember<Smi>::load())); +} + +template <typename Group> +void SmiBitFieldMember<Group>::store(Group value) { + store_no_write_barrier( + Smi::From31BitPattern(static_cast<int>(value.value()))); +} + +template <typename Group> +Group SmiBitFieldMember<Group>::Relaxed_Load() const { + return Group(Smi::To31BitPattern(TaggedMember<Smi>::Relaxed_Load())); +} + +template <typename Group> +void SmiBitFieldMember<Group>::Relaxed_Store(Group value) { + Relaxed_Store_no_write_barrier( + Smi::From31BitPattern(static_cast<int>(value.value()))); +} + // static template <typename T, int kFieldOffset, typename CompressionScheme> Address TaggedField<T, kFieldOffset, CompressionScheme>::address( @@ -443,10 +515,10 @@ void JSDispatchHandleMember::Relaxed_Clear() { storage_.store(0, std::memory_order_relaxed); } -void JSDispatchHandleMember::Relaxed_Store(HeapObject* host, +void JSDispatchHandleMember::Release_Store(HeapObject* host, JSDispatchHandle handle, WriteBarrierMode mode) { - storage_.store(handle.value(), std::memory_order_relaxed); + storage_.store(handle.value(), std::memory_order_release); WriteBarrier::ForJSDispatchHandle(host, handle, mode); } diff --git a/deps/v8/src/objects/tagged-field.h b/deps/v8/src/objects/tagged-field.h index d0057ef827d4..e32f685500ae 100644 --- a/deps/v8/src/objects/tagged-field.h +++ b/deps/v8/src/objects/tagged-field.h @@ -11,10 +11,14 @@ #include "src/base/template-meta-programming/functional.h" #include "src/common/globals.h" #include "src/common/ptr-compr.h" +#include "src/objects/bit-field-group.h" #include "src/objects/tagged-value.h" +#include "src/utils/boxed-float.h" namespace v8::internal { +class AllocationWitness; + // TaggedMember<T> represents an potentially compressed V8 tagged pointer, which // is intended to be used as a member of a V8 object class. // @@ -38,6 +42,18 @@ template <typename T, typename CompressionScheme> class V8_GSL_POINTER TaggedMember : public TaggedMemberBase { public: constexpr TaggedMember() = default; + inline explicit TaggedMember(Tagged<Smi> value); + inline TaggedMember(Tagged<Smi> value, RelaxedStoreTag); + inline explicit TaggedMember(Tagged<ClearedWeakValue> value); + template <typename U> + inline explicit TaggedMember(Tagged<ReadOnly<U>> value) + requires(is_subtype_v<ReadOnly<U>, T>); + template <typename U> + inline TaggedMember(Tagged<ReadOnly<U>> value, RelaxedStoreTag) + requires(is_subtype_v<ReadOnly<U>, T>); + inline TaggedMember(const AllocationWitness& witness, Tagged<T> value); + inline TaggedMember(const AllocationWitness& witness, Tagged<T> value, + RelaxedStoreTag); inline Tagged<T> load() const; inline void store(HeapObject* host, Tagged<T> value, @@ -75,10 +91,30 @@ class V8_GSL_POINTER TaggedMember : public TaggedMemberBase { static_assert(alignof(TaggedMember<Object>) == alignof(Tagged_t)); static_assert(sizeof(TaggedMember<Object>) == sizeof(Tagged_t)); +// Stores a BitFieldGroup<Group, uint32_t> as a Smi. The bits must fit in +// 31 bits. Torque uses SmiTagged<GroupName>, where GroupName extends uint31. +template <typename Group> +class SmiBitFieldMember : private TaggedMember<Smi> { + public: + static_assert(std::is_base_of_v<BitFieldGroup<Group, uint32_t>, Group>); + + constexpr SmiBitFieldMember() = default; + + inline Group load() const; + inline void store(Group value); + + inline Group Relaxed_Load() const; + inline void Relaxed_Store(Group value); + + // Used by heap verification. + using TaggedMember<Smi>::IsSmi; +}; + template <typename T> class UnalignedValueMember { public: UnalignedValueMember() = default; + explicit UnalignedValueMember(T value) { set_value(value); } T value() const { return base::ReadUnalignedValue<T>(storage_); } void set_value(T value) { base::WriteUnalignedValue(storage_, value); } @@ -100,15 +136,25 @@ class UnalignedValueMember { alignas(alignof(Tagged_t)) char storage_[sizeof(T)]; }; -class UnalignedDoubleMember : public UnalignedValueMember<double> { +class UnalignedDoubleMember : public UnalignedValueMember<Float64> { public: UnalignedDoubleMember() = default; + explicit UnalignedDoubleMember(Float64 value) + : UnalignedValueMember<Float64>(value) {} + explicit UnalignedDoubleMember(double value) + : UnalignedValueMember<Float64>(Float64::FromMaybeNaN(value)) {} + double value() const { + return UnalignedValueMember<Float64>::value().get_scalar(); + } + void set_value(double value) { + UnalignedValueMember<Float64>::set_value(Float64::FromMaybeNaN(value)); + } uint64_t value_as_bits() const { - return base::ReadUnalignedValue<uint64_t>(storage_); + return UnalignedValueMember<Float64>::value().get_bits(); } void set_value_as_bits(uint64_t value) { - base::WriteUnalignedValue(storage_, value); + UnalignedValueMember<Float64>::set_value(Float64::FromBits(value)); } }; static_assert(alignof(UnalignedDoubleMember) == alignof(Tagged_t)); @@ -134,7 +180,7 @@ class JSDispatchHandleMember { inline void Relaxed_Clear(); // Stores a new handle and emits the JSDispatchHandle write barrier. - inline void Relaxed_Store(HeapObject* host, JSDispatchHandle handle, + inline void Release_Store(HeapObject* host, JSDispatchHandle handle, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); private: @@ -164,13 +210,16 @@ static_assert(sizeof(JSDispatchHandleMember) == sizeof(uint32_t)); // only used on classes with a FAM) on clang. // Return the zero length array by reference, to avoid array-to-pointer decay // which can lose aliasing information. -#define FLEXIBLE_ARRAY_MEMBER(Type, name) \ +// Place V8_TQ_* annotations before the member. After the [0] declarator, an +// attribute would apply to the type instead. +#define FLEXIBLE_ARRAY_MEMBER(Type, name, ...) \ using FlexibleDataReturnType = Type[0]; \ FlexibleDataReturnType& name() { return flexible_array_member_data_; } \ const FlexibleDataReturnType& name() const { \ return flexible_array_member_data_; \ } \ - Type flexible_array_member_data_[0]; \ + V8_TQ_FIELD_MARK("V8_TQ_NAME(" #name ")") \ + __VA_ARGS__ Type flexible_array_member_data_[0]; \ \ public: \ template <typename Class> \ diff --git a/deps/v8/src/objects/tagged.h b/deps/v8/src/objects/tagged.h index 207fb1999906..fb7a022a768e 100644 --- a/deps/v8/src/objects/tagged.h +++ b/deps/v8/src/objects/tagged.h @@ -113,6 +113,41 @@ struct is_maybe_weak<Union<T...>> template <typename T> static constexpr bool is_maybe_weak_v = is_maybe_weak<T>::value; +template <typename T> +class ReadOnly; + +template <typename T> +struct is_read_only : public std::false_type {}; +template <typename T> +struct is_read_only<ReadOnly<T>> : public std::true_type {}; +template <typename... T> +struct is_read_only<Union<T...>> : public std::conjunction<is_read_only<T>...> { +}; +template <typename T> +static constexpr bool is_read_only_v = is_read_only<T>::value; + +// ReadOnly<T> represents a reference to T that is known to live in +// ReadOnlySpace. +// +// Like Weak<T>, ReadOnly<T> is a sentinel type for templates on tagged +// interfaces (like Tagged and Handle). Because every read-only T is also a +// valid T, ReadOnly<T> is a subtype of T (as well as ReadOnly<U> for any U +// that T is a subtype of). +template <typename T> +class ReadOnly { + public: + // Smis don't live in ReadOnlySpace. + static_assert(!std::is_same_v<T, Smi>); + // Generic Objects can't be ReadOnly; use a HeapObject subtype instead. + static_assert(!std::is_same_v<T, Object>); + // "ReadOnly" should be inside unions, not outside of them. + static_assert(!is_union_v<T>); + static_assert(!is_maybe_weak_v<T>); + static_assert(!is_read_only_v<T>); + + using value_type = T; +}; + namespace detail { template <typename T> struct weak_of_helper { @@ -130,6 +165,10 @@ template <typename T> struct weak_of_helper<Weak<T>> { using type = Weak<T>; }; +template <typename T> +struct weak_of_helper<ReadOnly<T>> { + using type = Weak<T>; +}; template <typename... Ts> struct weak_of_helper<Union<Ts...>> { using type = UnionOf<typename weak_of_helper<Ts>::type...>; @@ -290,6 +329,19 @@ consteval bool is_subtype_helper() { // Weak<T> cannot be a subtype of a non-weak Base (unless // matched exactly earlier by a union) return false; + } else if constexpr (is_read_only_v<Base>) { + // Base = ReadOnly<T> + if constexpr (is_read_only_v<Derived>) { + // ReadOnly<T> < ReadOnly<U> <=> T < U + return is_subtype_helper<typename Derived::value_type, + typename Base::value_type>(); + } else { + // non-readonly < ReadOnly<U> is always false. + return false; + } + } else if constexpr (is_read_only_v<Derived>) { + // ReadOnly<T> < U <=> T < U + return is_subtype_helper<typename Derived::value_type, Base>(); } else { // Fallback to base_of. return is_base_of_v<Base, Derived>; @@ -300,6 +352,10 @@ consteval bool is_subtype_helper() { static_assert(is_subtype_v<Smi, Object>); static_assert(is_subtype_v<HeapObject, Object>); static_assert(is_subtype_v<HeapObject, HeapObject>); +static_assert(is_subtype_v<ReadOnly<HeapObject>, ReadOnly<HeapObject>>); +static_assert(is_subtype_v<ReadOnly<HeapObject>, HeapObject>); +static_assert(is_subtype_v<ReadOnly<HeapObject>, Object>); +static_assert(!is_subtype_v<HeapObject, ReadOnly<HeapObject>>); static_assert(is_subtype_v<Smi, MaybeObject>); static_assert( is_subtype_v<Union<HeapObject, Weak<HeapObject>, Smi>, MaybeObject>); @@ -716,6 +772,9 @@ class V8_GSL_POINTER Tagged : public detail::BaseForTagged<T>::type { V8_INLINE T& operator*() const { return *ToRawPtr(); } V8_INLINE T* operator->() const { return ToRawPtr(); } + protected: + V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {} + private: friend T; // Handles of the same type are allowed to access the Address constructor. @@ -733,8 +792,6 @@ class V8_GSL_POINTER Tagged : public detail::BaseForTagged<T>::type { template <typename U> friend Tagged<StrongOf<U>> MakeStrong(Tagged<U> value); - V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {} - V8_INLINE T* ToRawPtr() const { // Check whether T is taggable on raw ptr access rather than top-level, to // allow forward declarations. @@ -743,6 +800,55 @@ class V8_GSL_POINTER Tagged : public detail::BaseForTagged<T>::type { } }; +// Specialized Tagged<T> for read-only references to T, which are known to be +// subclasses of HeapObject in ReadOnlySpace. +template <typename T> +class V8_GSL_POINTER Tagged<ReadOnly<T>> : public Tagged<T> { + using Base = Tagged<T>; + + public: + V8_INLINE constexpr Tagged() = default; + + // Implicit conversion for subclasses. + template <typename U> + V8_INLINE constexpr Tagged& operator=(Tagged<U> other) + requires(detail::is_tagged_convertible<U, ReadOnly<T>>) + { + *this = Tagged(other); + return *this; + } + + // Implicit conversion for subclasses. + template <typename U> + // NOLINTNEXTLINE + V8_INLINE constexpr Tagged(Tagged<U> other) + requires(detail::is_tagged_convertible<U, ReadOnly<T>>) + : Base(other) {} + + private: + friend T; + // Handles of the same type are allowed to access the Address constructor. + friend class Handle<ReadOnly<T>>; +#ifdef V8_ENABLE_DIRECT_HANDLE + friend class DirectHandle<ReadOnly<T>>; +#endif + template <typename TFieldType, int kFieldOffset, typename CompressionScheme> + friend class TaggedField; + template <typename TFieldType, typename CompressionScheme> + friend class TaggedMember; + template <typename To, typename From> + friend inline Tagged<To> UncheckedCast(Tagged<From> value); + + template <typename U> + friend Tagged<WeakOf<U>> MakeWeak(Tagged<U> value); + template <typename U> + friend Tagged<WeakOf<U>> MakeWeakOrSmi(Tagged<U> value); + template <typename U> + friend Tagged<StrongOf<U>> MakeStrong(Tagged<U> value); + + V8_INLINE constexpr explicit Tagged(Address ptr) : Base(ptr) {} +}; + // Specialized Tagged<T> for cleared weak values. This is only used, in // practice, for conversions from Tagged<ClearedWeakValue> to a // Tagged<MaybeWeak<T>>, where subtyping rules mean that this works for @@ -818,7 +924,9 @@ inline Tagged<WeakOf<T>> MakeWeakOrSmi(Tagged<T> value) { template <typename T> inline Tagged<StrongOf<T>> MakeStrong(Tagged<T> value) { - // This works with Smis. + // Clearing the weak tag bit would clobber Smi payload bit 1 under 31-bit Smi + // tagging. + static_assert(!is_subtype_v<Smi, T>, "Not allowed to make Smis strong."); return Tagged<StrongOf<T>>(value.ptr() & (~kWeakHeapObjectTag | kHeapObjectTag)); } diff --git a/deps/v8/src/objects/template-objects-inl.h b/deps/v8/src/objects/template-objects-inl.h index 449f87429ab9..642c9aa95934 100644 --- a/deps/v8/src/objects/template-objects-inl.h +++ b/deps/v8/src/objects/template-objects-inl.h @@ -8,6 +8,7 @@ #include "src/objects/template-objects.h" // Include the non-inl header before the rest of the headers. +#include "src/objects/heap-object-set-map-inl.h" #include "src/objects/js-array-inl.h" // Has to be the last include (doesn't have include guards): @@ -16,21 +17,20 @@ namespace v8 { namespace internal { +TemplateObjectDescription::TemplateObjectDescription( + const AllocationWitness& witness, Tagged<FixedArray> raw_strings, + Tagged<FixedArray> cooked_strings) + : Struct(witness.roots().template_object_description_map()), + raw_strings_(witness, raw_strings), + cooked_strings_(witness, cooked_strings) {} + Tagged<FixedArray> TemplateObjectDescription::raw_strings() const { return raw_strings_.load(); } -void TemplateObjectDescription::set_raw_strings(Tagged<FixedArray> value, - WriteBarrierMode mode) { - raw_strings_.store(this, value, mode); -} Tagged<FixedArray> TemplateObjectDescription::cooked_strings() const { return cooked_strings_.load(); } -void TemplateObjectDescription::set_cooked_strings(Tagged<FixedArray> value, - WriteBarrierMode mode) { - cooked_strings_.store(this, value, mode); -} } // namespace internal } // namespace v8 diff --git a/deps/v8/src/objects/template-objects.h b/deps/v8/src/objects/template-objects.h index b1b730bb8837..165d4d3a87ac 100644 --- a/deps/v8/src/objects/template-objects.h +++ b/deps/v8/src/objects/template-objects.h @@ -23,18 +23,17 @@ class StructBodyDescriptor; // object creation within the {Runtime_GetTemplateObject} method. V8_OBJECT class TemplateObjectDescription final : public Struct { public: + inline TemplateObjectDescription(const AllocationWitness& witness, + Tagged<FixedArray> raw_strings, + Tagged<FixedArray> cooked_strings); + static DirectHandle<JSArray> GetTemplateObject( Isolate* isolate, DirectHandle<NativeContext> native_context, DirectHandle<TemplateObjectDescription> description, DirectHandle<SharedFunctionInfo> shared_info, int slot_id); inline Tagged<FixedArray> raw_strings() const; - inline void set_raw_strings(Tagged<FixedArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<FixedArray> cooked_strings() const; - inline void set_cooked_strings(Tagged<FixedArray> value, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); using BodyDescriptor = StructBodyDescriptor; @@ -45,8 +44,8 @@ V8_OBJECT class TemplateObjectDescription final : public Struct { friend class Factory; friend class TorqueGeneratedTemplateObjectDescriptionAsserts; - TaggedMember<FixedArray> raw_strings_; - TaggedMember<FixedArray> cooked_strings_; + const TaggedMember<FixedArray> raw_strings_; + const TaggedMember<FixedArray> cooked_strings_; } V8_OBJECT_END; } // namespace internal diff --git a/deps/v8/src/objects/templates-inl.h b/deps/v8/src/objects/templates-inl.h index 1cc85747432e..faddcc9d6108 100644 --- a/deps/v8/src/objects/templates-inl.h +++ b/deps/v8/src/objects/templates-inl.h @@ -15,6 +15,7 @@ #include "src/objects/oddball-predicates-inl.h" #include "src/objects/oddball.h" #include "src/objects/shared-function-info.h" +#include "src/objects/struct-inl.h" #include "src/sandbox/external-pointer-inl.h" // Has to be the last include (doesn't have include guards): @@ -23,6 +24,19 @@ namespace v8 { namespace internal { +FunctionTemplateRareData::FunctionTemplateRareData( + const AllocationWitness& witness) + : Struct(witness.roots().function_template_rare_data_map()), + prototype_template_(witness.roots().undefined_value()), + prototype_provider_template_(witness.roots().undefined_value()), + parent_template_(witness.roots().undefined_value()), + named_property_handler_(witness.roots().undefined_value()), + indexed_property_handler_(witness.roots().undefined_value()), + instance_template_(witness.roots().undefined_value()), + instance_call_handler_(witness.roots().undefined_value()), + access_check_info_(witness.roots().undefined_value()), + c_function_overloads_(witness.roots().empty_fixed_array()) {} + Tagged<UnionOf<Undefined, ObjectTemplateInfo>> FunctionTemplateRareData::prototype_template() const { return prototype_template_.load(); @@ -108,67 +122,71 @@ void FunctionTemplateRareData::set_c_function_overloads( c_function_overloads_.store(this, value, mode); } -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, - is_object_template_call_handler, - IsObjectTemplateCallHandlerBit::kShift) -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, has_side_effects, - HasSideEffectsBit::kShift) -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, undetectable, - UndetectableBit::kShift) -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, needs_access_check, - NeedsAccessCheckBit::kShift) -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, read_only_prototype, - ReadOnlyPrototypeBit::kShift) -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, remove_prototype, - RemovePrototypeBit::kShift) -BOOL_ACCESSORS(FunctionTemplateInfo, relaxed_flag, accept_any_receiver, - AcceptAnyReceiverBit::kShift) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, + is_object_template_call_handler, + FunctionTemplateInfo::Flags::IsObjectTemplateCallHandlerBit) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, has_side_effects, + FunctionTemplateInfo::Flags::HasSideEffectsBit) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, undetectable, + FunctionTemplateInfo::Flags::UndetectableBit) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, needs_access_check, + FunctionTemplateInfo::Flags::NeedsAccessCheckBit) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, read_only_prototype, + FunctionTemplateInfo::Flags::ReadOnlyPrototypeBit) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, remove_prototype, + FunctionTemplateInfo::Flags::RemovePrototypeBit) +BIT_FIELD_ACCESSORS(FunctionTemplateInfo, relaxed_flag, accept_any_receiver, + FunctionTemplateInfo::Flags::AcceptAnyReceiverBit) bool FunctionTemplateInfo::published() const { - return BooleanBit::get(relaxed_flag(), PublishedBit::kShift); + return relaxed_flag().published(); } void FunctionTemplateInfo::set_published(bool value) { DCHECK(value); if (published()) return; CHECK(!HeapLayout::InReadOnlySpace(this)); - set_relaxed_flag( - BooleanBit::set(relaxed_flag(), PublishedBit::kShift, value)); + set_relaxed_flag(relaxed_flag().with_published(value)); } InstanceType FunctionTemplateInfo::allowed_receiver_instance_type_range_start() const { - return AllowedReceiverInstanceTypeRangeStartBits::decode(relaxed_flag()); + return relaxed_flag().allowed_receiver_instance_type_range_start(); } void FunctionTemplateInfo::set_allowed_receiver_instance_type_range_start( InstanceType value) { set_relaxed_flag( - AllowedReceiverInstanceTypeRangeStartBits::update(relaxed_flag(), value)); + relaxed_flag().with_allowed_receiver_instance_type_range_start(value)); } InstanceType FunctionTemplateInfo::allowed_receiver_instance_type_range_end() const { - return AllowedReceiverInstanceTypeRangeEndBits::decode(relaxed_flag()); + return relaxed_flag().allowed_receiver_instance_type_range_end(); } void FunctionTemplateInfo::set_allowed_receiver_instance_type_range_end( InstanceType value) { set_relaxed_flag( - AllowedReceiverInstanceTypeRangeEndBits::update(relaxed_flag(), value)); + relaxed_flag().with_allowed_receiver_instance_type_range_end(value)); } -uint32_t FunctionTemplateInfo::flag() const { return flag_; } -void FunctionTemplateInfo::set_flag(uint32_t value) { flag_ = value; } -uint32_t FunctionTemplateInfo::flag(RelaxedLoadTag tag) const { - return base::AsAtomic32::Relaxed_Load(&flag_); +FunctionTemplateInfo::Flags FunctionTemplateInfo::flag() const { + return flag_.load(std::memory_order_relaxed); +} +void FunctionTemplateInfo::set_flag(Flags value) { + flag_.store(value, std::memory_order_relaxed); +} +FunctionTemplateInfo::Flags FunctionTemplateInfo::flag( + RelaxedLoadTag tag) const { + return flag_.load(std::memory_order_relaxed); } -void FunctionTemplateInfo::set_flag(uint32_t value, RelaxedStoreTag tag) { - base::AsAtomic32::Relaxed_Store(&flag_, value); +void FunctionTemplateInfo::set_flag(Flags value, RelaxedStoreTag tag) { + flag_.store(value, std::memory_order_relaxed); } -int32_t FunctionTemplateInfo::relaxed_flag() const { +FunctionTemplateInfo::Flags FunctionTemplateInfo::relaxed_flag() const { return flag(kRelaxedLoad); } -void FunctionTemplateInfo::set_relaxed_flag(int32_t flags) { +void FunctionTemplateInfo::set_relaxed_flag(Flags flags) { return set_flag(flags, kRelaxedStore); } @@ -291,11 +309,11 @@ void FunctionTemplateInfo::SetAllowedReceiverInstanceTypeRange( // Ensure that instance type fields in FunctionTemplateInfo are big enough // to fit the whole JSApiObject type range. static_assert( - FunctionTemplateInfo::AllowedReceiverInstanceTypeRangeStartBits::is_valid( - LAST_JS_API_OBJECT_TYPE)); + FunctionTemplateInfo::Flags::AllowedReceiverInstanceTypeRangeStartBits:: + is_valid(LAST_JS_API_OBJECT_TYPE)); static_assert( - FunctionTemplateInfo::AllowedReceiverInstanceTypeRangeEndBits::is_valid( - LAST_JS_API_OBJECT_TYPE)); + FunctionTemplateInfo::Flags::AllowedReceiverInstanceTypeRangeEndBits:: + is_valid(LAST_JS_API_OBJECT_TYPE)); bool FunctionTemplateInfo::instantiated() { return IsSharedFunctionInfo(shared_function_info()); diff --git a/deps/v8/src/objects/templates.cc b/deps/v8/src/objects/templates.cc index 87a5b463b253..a5a7d7f474f1 100644 --- a/deps/v8/src/objects/templates.cc +++ b/deps/v8/src/objects/templates.cc @@ -204,8 +204,7 @@ DirectHandle<DictionaryTemplateInfo> DictionaryTemplateInfo::Create( uint32_t unused_array_index; for (const std::string_view& name : names) { DirectHandle<String> internalized_name = - isolate->factory()->InternalizeString( - base::Vector<const char>(name.data(), name.length())); + isolate->factory()->InternalizeString(name); // Check that property name cannot be used as index. CHECK(!internalized_name->AsArrayIndex(&unused_array_index)); property_names->set(index, *internalized_name); @@ -292,12 +291,9 @@ DirectHandle<JSObject> DictionaryTemplateInfo::NewInstance( if (details.representation().Equals(Representation::Double())) { // We allowed coercion in `FitsRepresentation` above which means that // we may deal with a Smi here. - double value_as_double = Object::NumberValue(Cast<Number>(*value)); - if (std::isnan(value_as_double)) { - value_as_double = std::numeric_limits<double>::quiet_NaN(); - } - property_values[i] = ToApiHandle<v8::Object>( - isolate->factory()->NewHeapNumber(value_as_double)); + property_values[i] = + ToApiHandle<v8::Number>(isolate->factory()->NewHeapNumber( + Object::NumberValue(Cast<Number>(*value)))); } } if (V8_LIKELY(can_use_cached_map)) { diff --git a/deps/v8/src/objects/templates.h b/deps/v8/src/objects/templates.h index 2f7c880c1f1f..7619866b9533 100644 --- a/deps/v8/src/objects/templates.h +++ b/deps/v8/src/objects/templates.h @@ -14,6 +14,7 @@ #include "include/v8-exception.h" #include "src/base/bit-field.h" #include "src/handles/handles.h" +#include "src/objects/bit-field-group.h" #include "src/objects/contexts.h" #include "src/objects/struct.h" @@ -102,7 +103,8 @@ V8_OBJECT class TemplateInfo : public HeapObject { using ShouldPromoteToReadOnlyBit = IsCacheableBit::Next<bool, 1>; using SerialNumberBits = ShouldPromoteToReadOnlyBit::Next<uint32_t, 29>; - TaggedMember<Smi> template_info_flags_; + TaggedMember<Smi> template_info_flags_ + V8_TQ_TYPE(SmiTagged<TemplateInfoFlags>); } V8_OBJECT_END; V8_OBJECT class TemplateInfoWithProperties : public TemplateInfo { @@ -129,6 +131,8 @@ V8_OBJECT class TemplateInfoWithProperties : public TemplateInfo { // Contains data members that are rarely set on a FunctionTemplateInfo. V8_OBJECT class FunctionTemplateRareData : public Struct { public: + inline explicit FunctionTemplateRareData(const AllocationWitness& witness); + inline Tagged<UnionOf<Undefined, ObjectTemplateInfo>> prototype_template() const; inline void set_prototype_template( @@ -251,8 +255,39 @@ V8_OBJECT class FunctionTemplateInfo : public TemplateInfoWithProperties { DECL_RARE_ACCESSORS(c_function_overloads, CFunctionOverloads, FixedArray) #undef DECL_RARE_ACCESSORS - DECL_PRIMITIVE_ACCESSORS(flag, uint32_t) - DECL_RELAXED_UINT32_ACCESSORS(flag) + struct Flags : BitFieldGroup<Flags, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using IsObjectTemplateCallHandlerBit = First<bool, 1>; + using HasSideEffectsBit = IsObjectTemplateCallHandlerBit::Next<bool, 1>; + using UndetectableBit = HasSideEffectsBit::Next<bool, 1>; + using NeedsAccessCheckBit = UndetectableBit::Next<bool, 1>; + using ReadOnlyPrototypeBit = NeedsAccessCheckBit::Next<bool, 1>; + using RemovePrototypeBit = ReadOnlyPrototypeBit::Next<bool, 1>; + using AcceptAnyReceiverBit = RemovePrototypeBit::Next<bool, 1>; + using PublishedBit = AcceptAnyReceiverBit::Next<bool, 1>; + using AllowedReceiverInstanceTypeRangeStartBits = + PublishedBit::Next<InstanceType, 12>; + using AllowedReceiverInstanceTypeRangeEndBits = + AllowedReceiverInstanceTypeRangeStartBits::Next<InstanceType, 12>; + + BIT_FIELD_GROUP_ACCESSORS(is_object_template_call_handler, + IsObjectTemplateCallHandlerBit) + BIT_FIELD_GROUP_ACCESSORS(has_side_effects, HasSideEffectsBit) + BIT_FIELD_GROUP_ACCESSORS(undetectable, UndetectableBit) + BIT_FIELD_GROUP_ACCESSORS(needs_access_check, NeedsAccessCheckBit) + BIT_FIELD_GROUP_ACCESSORS(read_only_prototype, ReadOnlyPrototypeBit) + BIT_FIELD_GROUP_ACCESSORS(remove_prototype, RemovePrototypeBit) + BIT_FIELD_GROUP_ACCESSORS(accept_any_receiver, AcceptAnyReceiverBit) + BIT_FIELD_GROUP_ACCESSORS(published, PublishedBit) + BIT_FIELD_GROUP_ACCESSORS(allowed_receiver_instance_type_range_start, + AllowedReceiverInstanceTypeRangeStartBits) + BIT_FIELD_GROUP_ACCESSORS(allowed_receiver_instance_type_range_end, + AllowedReceiverInstanceTypeRangeEndBits) + }; + + DECL_PRIMITIVE_ACCESSORS(flag, Flags) + DECL_RELAXED_PRIMITIVE_ACCESSORS(flag, Flags) // Begin flag bits --------------------- @@ -333,20 +368,6 @@ V8_OBJECT class FunctionTemplateInfo : public TemplateInfoWithProperties { uint32_t GetCFunctionsCount() const; CFunctionWithSignature GetCFunction(uint32_t index) const; - // Bit position in the flag, from least significant bit position. - using IsObjectTemplateCallHandlerBit = base::BitField<bool, 0, 1, uint32_t>; - using HasSideEffectsBit = IsObjectTemplateCallHandlerBit::Next<bool, 1>; - using UndetectableBit = HasSideEffectsBit::Next<bool, 1>; - using NeedsAccessCheckBit = UndetectableBit::Next<bool, 1>; - using ReadOnlyPrototypeBit = NeedsAccessCheckBit::Next<bool, 1>; - using RemovePrototypeBit = ReadOnlyPrototypeBit::Next<bool, 1>; - using AcceptAnyReceiverBit = RemovePrototypeBit::Next<bool, 1>; - using PublishedBit = AcceptAnyReceiverBit::Next<bool, 1>; - using AllowedReceiverInstanceTypeRangeStartBits = - PublishedBit::Next<InstanceType, 12>; - using AllowedReceiverInstanceTypeRangeEndBits = - AllowedReceiverInstanceTypeRangeStartBits::Next<InstanceType, 12>; - // C function pointer that can be called from native code. inline Address callback(IsolateForSandbox isolate) const; inline void set_callback(IsolateForSandbox isolate, Address value); @@ -367,8 +388,8 @@ V8_OBJECT class FunctionTemplateInfo : public TemplateInfoWithProperties { private: // For ease of use of the BITFIELD macro. - inline int32_t relaxed_flag() const; - inline void set_relaxed_flag(int32_t flags); + inline Flags relaxed_flag() const; + inline void set_relaxed_flag(Flags flags); // Enforce using SetInstanceType() and SetAllowedReceiverInstanceTypeRange() // instead of raw accessors. @@ -439,11 +460,12 @@ V8_OBJECT class FunctionTemplateInfo : public TemplateInfoWithProperties { TaggedMember<UnionOf<String, Undefined>> class_name_; TaggedMember<UnionOf<String, Undefined>> interface_name_; TaggedMember<UnionOf<FunctionTemplateInfo, Undefined>> signature_; - TaggedMember<UnionOf<FunctionTemplateRareData, Undefined>> rare_data_; + V8_TQ_ACQ_REL TaggedMember<UnionOf<FunctionTemplateRareData, Undefined>> + rare_data_; TaggedMember<UnionOf<SharedFunctionInfo, Undefined>> shared_function_info_; TaggedMember<Object> cached_property_name_; - TaggedMember<Object> callback_data_; - uint32_t flag_; + V8_TQ_ACQ_REL TaggedMember<Object> callback_data_; + std::atomic<Flags> flag_; int16_t length_; InstanceType instance_type_; uint32_t exception_context_; @@ -480,7 +502,7 @@ V8_OBJECT class ObjectTemplateInfo : public TemplateInfoWithProperties { inline void set_data(int value); TaggedMember<UnionOf<FunctionTemplateInfo, Undefined>> constructor_; - TaggedMember<Smi> data_; + TaggedMember<Smi> data_ V8_TQ_TYPE(SmiTagged<ObjectTemplateInfoFlags>); private: using IsImmutablePrototypeBit = base::BitField<bool, 0, 1, uint32_t>; diff --git a/deps/v8/src/objects/templates.tq b/deps/v8/src/objects/templates.tq index d2b5d9c7f58a..4ccdd78e3c35 100644 --- a/deps/v8/src/objects/templates.tq +++ b/deps/v8/src/objects/templates.tq @@ -37,7 +37,7 @@ extern class FunctionTemplateRareData extends Struct { c_function_overloads: FixedArray; } -@cppScope('FunctionTemplateInfo') +@cppScope('FunctionTemplateInfo::Flags') bitfield struct FunctionTemplateInfoFlags extends uint32 { // True in case this FunctionTemplateInfo object is used as a call handler // for callable ObjectTemplateInfo. diff --git a/deps/v8/src/objects/transitions.cc b/deps/v8/src/objects/transitions.cc index 0c0ac419f30d..f20dde60a068 100644 --- a/deps/v8/src/objects/transitions.cc +++ b/deps/v8/src/objects/transitions.cc @@ -279,7 +279,6 @@ bool TransitionsAccessor::IsSpecialTransition(ReadOnlyRoots roots, return name == roots.nonextensible_symbol() || name == roots.sealed_symbol() || name == roots.frozen_symbol() || name == roots.elements_transition_symbol() || - name == roots.strict_function_transition_symbol() || name == roots.detached_symbol(); } diff --git a/deps/v8/src/objects/trusted-object-inl.h b/deps/v8/src/objects/trusted-object-inl.h index fa361c967986..8657e04a506c 100644 --- a/deps/v8/src/objects/trusted-object-inl.h +++ b/deps/v8/src/objects/trusted-object-inl.h @@ -12,8 +12,7 @@ #include "src/objects/heap-object-inl.h" #include "src/objects/instance-type-inl.h" #include "src/objects/map-inl.h" -#include "src/objects/trusted-pointer-inl.h" -#include "src/sandbox/indirect-pointer-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -85,8 +84,8 @@ void TrustedObject::VerifyProtectedPointerField(Isolate* isolate, int offset) { void ExposedTrustedObject::InitAndPublish(Isolate* isolate) { #ifdef V8_ENABLE_SANDBOX - InitSelfIndirectPointerField(&self_indirect_pointer_, isolate, - isolate->trusted_pointer_publishing_scope()); + InitSelfTrustedPointerField(&self_trusted_pointer_, isolate, + isolate->trusted_pointer_publishing_scope()); #endif #ifdef VERIFY_HEAP if (!isolate->has_active_deserializer() && !Is<Code>(this)) { @@ -99,24 +98,24 @@ void ExposedTrustedObject::InitAndPublish(LocalIsolate* isolate) { #ifdef V8_ENABLE_SANDBOX // Background threads using LocalIsolates don't use // TrustedPointerPublishingScopes. - InitSelfIndirectPointerField(&self_indirect_pointer_, isolate, nullptr); + InitSelfTrustedPointerField(&self_trusted_pointer_, isolate, nullptr); #endif } void ExposedTrustedObject::InitDontPublish(Isolate* isolate) { #ifdef V8_ENABLE_SANDBOX - i::InitSelfIndirectPointerField( - reinterpret_cast<Address>(&self_indirect_pointer_), isolate, this, - kUnpublishedIndirectPointerTag, + i::InitSelfTrustedPointerField( + reinterpret_cast<Address>(&self_trusted_pointer_), isolate, this, + kUnpublishedTrustedPointerTag, isolate->trusted_pointer_publishing_scope()); #endif } void ExposedTrustedObject::InitDontPublish(LocalIsolate* isolate) { #ifdef V8_ENABLE_SANDBOX - i::InitSelfIndirectPointerField( - reinterpret_cast<Address>(&self_indirect_pointer_), isolate, this, - kUnpublishedIndirectPointerTag, nullptr); + i::InitSelfTrustedPointerField( + reinterpret_cast<Address>(&self_trusted_pointer_), isolate, this, + kUnpublishedTrustedPointerTag, nullptr); #endif } @@ -137,10 +136,10 @@ void ExposedTrustedObject::Publish(IsolateForSandbox isolate) { DCHECK(!HeapLayout::InAnySharedSpace(this)); InstanceType instance_type = map()->instance_type(); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, SharedFlag{false}); - IndirectPointerHandle handle = - self_indirect_pointer_.load(std::memory_order::acquire); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, SharedFlag{false}); + TrustedPointerHandle handle = + self_trusted_pointer_.load(std::memory_order::acquire); TrustedPointerTable& table = isolate.GetTrustedPointerTableFor(tag); return table.Publish(handle, tag); #endif @@ -154,10 +153,10 @@ void ExposedTrustedObject::Unpublish(IsolateForSandbox isolate) { DCHECK(!HeapLayout::InAnySharedSpace(this)); InstanceType instance_type = map()->instance_type(); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, SharedFlag{false}); - IndirectPointerHandle handle = - self_indirect_pointer_.load(std::memory_order::acquire); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, SharedFlag{false}); + TrustedPointerHandle handle = + self_trusted_pointer_.load(std::memory_order::acquire); TrustedPointerTable& table = isolate.GetTrustedPointerTableFor(tag); table.Unpublish(handle); #endif // V8_ENABLE_SANDBOX @@ -166,35 +165,34 @@ void ExposedTrustedObject::Unpublish(IsolateForSandbox isolate) { bool ExposedTrustedObject::IsPublished(IsolateForSandbox isolate) const { #ifdef V8_ENABLE_SANDBOX InstanceType instance_type = map()->instance_type(); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, SharedFlag{false}); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, SharedFlag{false}); return !TrustedPointerField::IsTrustedPointerFieldUnpublished( - this, offsetof(ExposedTrustedObject, self_indirect_pointer_), tag, + this, offsetof(ExposedTrustedObject, self_trusted_pointer_), tag, isolate); #else return true; #endif } -IndirectPointerHandle ExposedTrustedObject::self_indirect_pointer_handle() - const { +TrustedPointerHandle ExposedTrustedObject::self_trusted_pointer_handle() const { #ifdef V8_ENABLE_SANDBOX - return self_indirect_pointer_.load(std::memory_order::relaxed); + return self_trusted_pointer_.load(std::memory_order::relaxed); #else UNREACHABLE(); #endif } #if V8_ENABLE_SANDBOX -void ExposedTrustedObject::InitSelfIndirectPointerField( - std::atomic<IndirectPointerHandle>* field_ptr, IsolateForSandbox isolate, +void ExposedTrustedObject::InitSelfTrustedPointerField( + std::atomic<TrustedPointerHandle>* field_ptr, IsolateForSandbox isolate, TrustedPointerPublishingScope* opt_publishing_scope) { InstanceType instance_type = map()->instance_type(); SharedFlag shared = SharedFlag(HeapLayout::InAnySharedSpace(this)); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, shared); - i::InitSelfIndirectPointerField(reinterpret_cast<Address>(field_ptr), isolate, - this, tag, opt_publishing_scope); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, shared); + i::InitSelfTrustedPointerField(reinterpret_cast<Address>(field_ptr), isolate, + this, tag, opt_publishing_scope); } #endif // V8_ENABLE_SANDBOX diff --git a/deps/v8/src/objects/trusted-object.h b/deps/v8/src/objects/trusted-object.h index 26a21cf5615b..5605f3cfe3c8 100644 --- a/deps/v8/src/objects/trusted-object.h +++ b/deps/v8/src/objects/trusted-object.h @@ -143,11 +143,11 @@ V8_OBJECT class ExposedTrustedObject : public TrustedObject { // This indirect pointer references a pointer table entry (either in the // trusted pointer table or the code pointer table for Code objects) through // which this object can be referenced from inside the sandbox. - inline IndirectPointerHandle self_indirect_pointer_handle() const; + inline TrustedPointerHandle self_trusted_pointer_handle() const; #if V8_ENABLE_SANDBOX - inline void InitSelfIndirectPointerField( - std::atomic<IndirectPointerHandle>* field_ptr, IsolateForSandbox isolate, + inline void InitSelfTrustedPointerField( + std::atomic<TrustedPointerHandle>* field_ptr, IsolateForSandbox isolate, TrustedPointerPublishingScope* opt_publishing_scope); #endif // V8_ENABLE_SANDBOX @@ -164,7 +164,7 @@ V8_OBJECT class ExposedTrustedObject : public TrustedObject { #ifdef V8_ENABLE_SANDBOX // The 'self' indirect pointer is only available when the sandbox is enabled. // Otherwise, these objects are referenced through direct pointers. - std::atomic<IndirectPointerHandle> self_indirect_pointer_; + std::atomic<TrustedPointerHandle> self_trusted_pointer_; #endif // V8_ENABLE_SANDBOX } V8_OBJECT_END; diff --git a/deps/v8/src/objects/trusted-object.tq b/deps/v8/src/objects/trusted-object.tq index 7df5e60f1d60..6a2c6969393b 100644 --- a/deps/v8/src/objects/trusted-object.tq +++ b/deps/v8/src/objects/trusted-object.tq @@ -9,5 +9,5 @@ extern class TrustedObject extends HeapObject {} @abstract @cppObjectLayoutDefinition extern class ExposedTrustedObject extends TrustedObject { - @if(V8_ENABLE_SANDBOX) self_indirect_pointer: TrustedPointer; + @if(V8_ENABLE_SANDBOX) self_trusted_pointer: TrustedPointer; } diff --git a/deps/v8/src/objects/trusted-pointer-inl.h b/deps/v8/src/objects/trusted-pointer-inl.h deleted file mode 100644 index de5dae748a0c..000000000000 --- a/deps/v8/src/objects/trusted-pointer-inl.h +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2025 the V8 project 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 V8_OBJECTS_TRUSTED_POINTER_INL_H_ -#define V8_OBJECTS_TRUSTED_POINTER_INL_H_ - -#include "src/objects/trusted-pointer.h" -// Include the non-inl header before the rest of the headers. - -#include <atomic> - -#include "src/heap/heap-write-barrier-inl.h" -#include "src/objects/heap-object.h" -#include "src/objects/tagged-field-inl.h" -#include "src/objects/trusted-object.h" -#include "src/sandbox/indirect-pointer-inl.h" -#include "src/sandbox/trusted-pointer-table-inl.h" - -namespace v8 { -namespace internal { - -template <IndirectPointerTagRange tag_range> -Tagged<TrustedTypeFor<tag_range>> TrustedPointerField::ReadTrustedPointerField( - Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate) { - // Currently, trusted pointer loads always use acquire semantics as the - // under-the-hood indirect pointer loads use acquire loads anyway. - return ReadTrustedPointerField<tag_range>(host, offset, isolate, - kAcquireLoad); -} - -template <IndirectPointerTagRange tag_range> -Tagged<TrustedTypeFor<tag_range>> TrustedPointerField::ReadTrustedPointerField( - Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate, - AcquireLoadTag acquire_load) { - Tagged<Object> object = ReadMaybeEmptyTrustedPointerField<tag_range>( - host, offset, isolate, acquire_load); - using ReturnType = TrustedTypeFor<tag_range>; - return TrustedCast<ReturnType>(object); -} - -template <IndirectPointerTagRange tag_range> -Tagged<Union<Smi, TrustedTypeFor<tag_range>>> -TrustedPointerField::ReadMaybeEmptyTrustedPointerField( - Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate, - AcquireLoadTag) { -#ifdef V8_ENABLE_SANDBOX - // Reading a TrustedPointer field is just a ReadIndirectPointerField with the - // proper tag. - Address field_address = host->ptr() + offset - kHeapObjectTag; - Tagged<Object> object = - ReadIndirectPointerField<tag_range>(field_address, isolate, kAcquireLoad); -#else - Tagged<Object> object = - TaggedField<Object>::Acquire_Load(host, static_cast<int>(offset)); -#endif - return TrustedCast<Union<Smi, TrustedTypeFor<tag_range>>>(object); -} - -template <IndirectPointerTagRange tag_range> -void TrustedPointerField::WriteTrustedPointerField( - Tagged<HeapObject> host, size_t offset, - Tagged<ExposedTrustedObject> value) { -#ifdef V8_ENABLE_SANDBOX - Address field_address = host->ptr() + offset - kHeapObjectTag; - WriteIndirectPointerField<tag_range>(field_address, value, kReleaseStore); -#else - TaggedField<ExposedTrustedObject>::Release_Store( - host, static_cast<int>(offset), value); -#endif -} - -bool TrustedPointerField::IsTrustedPointerFieldEmpty(Tagged<HeapObject> host, - size_t offset) { -#ifdef V8_ENABLE_SANDBOX - Address field_address = host->ptr() + offset - kHeapObjectTag; - IndirectPointerHandle handle = base::AsAtomic32::Acquire_Load( - reinterpret_cast<IndirectPointerHandle*>(field_address)); - return handle == kNullIndirectPointerHandle; -#else - return IsSmi( - TaggedField<Object>::Acquire_Load(host, static_cast<int>(offset))); -#endif -} - -template <typename IsolateT> -bool TrustedPointerField::IsTrustedPointerFieldUnpublished( - Tagged<HeapObject> host, size_t offset, IndirectPointerTagRange tag_range, - IsolateT isolate) { -#ifdef V8_ENABLE_SANDBOX - IndirectPointerHandle handle = - base::AsAtomic32::Acquire_Load(reinterpret_cast<IndirectPointerHandle*>( - host->ptr() + offset - kHeapObjectTag)); - if (handle == kNullIndirectPointerHandle) return false; - const TrustedPointerTable& table = - isolate.GetTrustedPointerTableFor(tag_range); - return table.IsUnpublished(handle); -#else - return false; -#endif -} - -void TrustedPointerField::ClearTrustedPointerField(Tagged<HeapObject> host, - size_t offset) { - ClearTrustedPointerField(host, offset, kReleaseStore); -} - -void TrustedPointerField::ClearTrustedPointerField(Tagged<HeapObject> host, - size_t offset, - ReleaseStoreTag) { -#ifdef V8_ENABLE_SANDBOX - Address field_address = host->ptr() + offset - kHeapObjectTag; - base::AsAtomic32::Release_Store( - reinterpret_cast<IndirectPointerHandle*>(field_address), - kNullIndirectPointerHandle); -#else - TaggedField<Smi>::Release_Store(host, static_cast<int>(offset), Smi::zero()); -#endif -} - -// Currently, trusted pointer loads/stores always use acquire/release -// semantics as the under-the-hood indirect pointer loads/stores use -// acquire/release loads/stores anyway. -template <typename T, IndirectPointerTagRange kTagRange> -Tagged<T> TrustedPointerMember<T, kTagRange>::load( - IsolateForSandbox isolate) const { - return Acquire_Load(isolate); -} -template <typename T, IndirectPointerTagRange kTagRange> -Tagged<Object> TrustedPointerMember<T, kTagRange>::load_maybe_empty( - IsolateForSandbox isolate) const { - return Acquire_Load_maybe_empty(isolate); -} -template <typename T, IndirectPointerTagRange kTagRange> -void TrustedPointerMember<T, kTagRange>::store(HeapObject* host, - Tagged<T> value, - WriteBarrierMode mode) { - Release_Store(host, value, mode); -} -template <typename T, IndirectPointerTagRange kTagRange> -void TrustedPointerMember<T, kTagRange>::store_no_write_barrier( - HeapObject* host, Tagged<T> value) { - Release_Store_no_write_barrier(host, value); -} - -template <typename T, IndirectPointerTagRange kTagRange> -Tagged<T> TrustedPointerMember<T, kTagRange>::Acquire_Load( - IsolateForSandbox isolate) const { -#ifdef V8_ENABLE_SANDBOX - return TrustedCast<T>(ReadIndirectPointerHandle<kTagRange>( - handle_.load(std::memory_order::acquire), isolate)); -#else - return Base::Acquire_Load(); -#endif -} - -template <typename T, IndirectPointerTagRange kTagRange> -Tagged<Object> TrustedPointerMember<T, kTagRange>::Acquire_Load_maybe_empty( - IsolateForSandbox isolate) const { -#ifdef V8_ENABLE_SANDBOX - IndirectPointerHandle handle = handle_.load(std::memory_order::acquire); - if (handle == kNullIndirectPointerHandle) return Smi::zero(); - return ReadIndirectPointerHandle<kTagRange>(handle, isolate); -#else - return Base::Acquire_Load(); -#endif -} - -template <typename T, IndirectPointerTagRange kTagRange> -void TrustedPointerMember<T, kTagRange>::Release_Store(HeapObject* host, - Tagged<T> value, - WriteBarrierMode mode) { -#ifdef V8_ENABLE_SANDBOX - handle_.store( - Cast<ExposedTrustedObject>(value)->self_indirect_pointer_handle(), - std::memory_order_release); - WriteBarrier::ForIndirectPointer(host, this, value, mode); -#else - Base::Release_Store(host, value, mode); -#endif -} - -template <typename T, IndirectPointerTagRange kTagRange> -void TrustedPointerMember<T, kTagRange>::Release_Store_no_write_barrier( - HeapObject* host, Tagged<T> value) { -#ifdef V8_ENABLE_SANDBOX - store(host, value, SKIP_WRITE_BARRIER); -#else - Base::Release_Store_no_write_barrier(value); -#endif -} - -template <typename T, IndirectPointerTagRange kTagRange> -bool TrustedPointerMember<T, kTagRange>::is_empty() const { -#ifdef V8_ENABLE_SANDBOX - return handle_.load(std::memory_order_acquire) == kNullIndirectPointerHandle; -#else - return Base::Acquire_Load().is_null(); -#endif -} - -template <typename T, IndirectPointerTagRange kTagRange> -bool TrustedPointerMember<T, kTagRange>::is_unpublished( - IsolateForSandbox isolate) const { -#ifdef V8_ENABLE_SANDBOX - IndirectPointerHandle handle = handle_.load(std::memory_order_acquire); - if (handle == kNullIndirectPointerHandle) return false; - const TrustedPointerTable& table = - isolate.GetTrustedPointerTableFor(kTagRange); - return table.IsUnpublished(handle); -#else - return false; -#endif -} - -template <typename T, IndirectPointerTagRange kTagRange> -void TrustedPointerMember<T, kTagRange>::clear(HeapObject* host) { -#ifdef V8_ENABLE_SANDBOX - handle_.store(kNullIndirectPointerHandle, std::memory_order_release); -#else - Base::Release_Store_no_write_barrier(Tagged<T>()); -#endif -} - -#ifdef V8_ENABLE_SANDBOX -template <typename T, IndirectPointerTagRange kTagRange> -Address TrustedPointerMember<T, kTagRange>::storage_address() const { - return reinterpret_cast<Address>(&handle_); -} -#endif - -} // namespace internal -} // namespace v8 - -#endif // V8_OBJECTS_TRUSTED_POINTER_INL_H_ diff --git a/deps/v8/src/objects/turbofan-types-inl.h b/deps/v8/src/objects/turbofan-types-inl.h index f5abda4ce679..4b92d9f72bbb 100644 --- a/deps/v8/src/objects/turbofan-types-inl.h +++ b/deps/v8/src/objects/turbofan-types-inl.h @@ -19,10 +19,16 @@ namespace v8 { namespace internal { // TurbofanBitsetType -uint32_t TurbofanBitsetType::bitset_low() const { return bitset_low_; } -void TurbofanBitsetType::set_bitset_low(uint32_t value) { bitset_low_ = value; } -uint32_t TurbofanBitsetType::bitset_high() const { return bitset_high_; } -void TurbofanBitsetType::set_bitset_high(uint32_t value) { +TurbofanTypeLowBits TurbofanBitsetType::bitset_low() const { + return bitset_low_; +} +void TurbofanBitsetType::set_bitset_low(TurbofanTypeLowBits value) { + bitset_low_ = value; +} +TurbofanTypeHighBits TurbofanBitsetType::bitset_high() const { + return bitset_high_; +} +void TurbofanBitsetType::set_bitset_high(TurbofanTypeHighBits value) { bitset_high_ = value; } diff --git a/deps/v8/src/objects/turbofan-types.h b/deps/v8/src/objects/turbofan-types.h index e3e40914ecb7..5b8efbd64882 100644 --- a/deps/v8/src/objects/turbofan-types.h +++ b/deps/v8/src/objects/turbofan-types.h @@ -7,6 +7,7 @@ #include "src/base/bit-field.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/heap-object.h" #include "src/objects/objects.h" #include "src/objects/tagged.h" @@ -17,9 +18,10 @@ namespace v8 { namespace internal { -class TurbofanTypeLowBits { - public: - using UnusedPaddingField1Bit = base::BitField<bool, 0, 1, uint32_t>; +struct TurbofanTypeLowBits : BitFieldGroup<TurbofanTypeLowBits, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using UnusedPaddingField1Bit = First<bool, 1>; using OtherUnsigned31Bit = UnusedPaddingField1Bit::Next<bool, 1>; using OtherUnsigned32Bit = OtherUnsigned31Bit::Next<bool, 1>; using OtherSigned32Bit = OtherUnsigned32Bit::Next<bool, 1>; @@ -31,8 +33,8 @@ class TurbofanTypeLowBits { using BooleanBit = UndefinedBit::Next<bool, 1>; using Unsigned30Bit = BooleanBit::Next<bool, 1>; using MinusZeroBit = Unsigned30Bit::Next<bool, 1>; - using NaNBit = MinusZeroBit::Next<bool, 1>; - using SymbolBit = NaNBit::Next<bool, 1>; + using NanBit = MinusZeroBit::Next<bool, 1>; + using SymbolBit = NanBit::Next<bool, 1>; using InternalizedStringBit = SymbolBit::Next<bool, 1>; using OtherCallableBit = InternalizedStringBit::Next<bool, 1>; using OtherObjectBit = OtherCallableBit::Next<bool, 1>; @@ -65,7 +67,7 @@ class TurbofanTypeLowBits { kBoolean = BooleanBit::kMask, kUnsigned30 = Unsigned30Bit::kMask, kMinusZero = MinusZeroBit::kMask, - kNaN = NaNBit::kMask, + kNaN = NanBit::kMask, kSymbol = SymbolBit::kMask, kInternalizedString = InternalizedStringBit::kMask, kOtherCallable = OtherCallableBit::kMask, @@ -86,13 +88,13 @@ class TurbofanTypeLowBits { kWasmObject = WasmObjectBit::kMask, kSandboxedPointer = SandboxedPointerBit::kMask, }; - using Flags = base::Flags<Flag>; static constexpr int kFlagCount = 32; }; -class TurbofanTypeHighBits { - public: - using MachineBit = base::BitField<bool, 0, 1, uint32_t>; +struct TurbofanTypeHighBits : BitFieldGroup<TurbofanTypeHighBits, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using MachineBit = First<bool, 1>; using HoleBit = MachineBit::Next<bool, 1>; using StringWrapperBit = HoleBit::Next<bool, 1>; using TypedArrayBit = StringWrapperBit::Next<bool, 1>; @@ -103,7 +105,6 @@ class TurbofanTypeHighBits { kStringWrapper = StringWrapperBit::kMask, kTypedArray = TypedArrayBit::kMask, }; - using Flags = base::Flags<Flag>; static constexpr int kFlagCount = 4; }; @@ -113,10 +114,10 @@ V8_OBJECT class TurbofanType : public HeapObject { V8_OBJECT class TurbofanBitsetType : public TurbofanType { public: - inline uint32_t bitset_low() const; - inline void set_bitset_low(uint32_t value); - inline uint32_t bitset_high() const; - inline void set_bitset_high(uint32_t value); + inline TurbofanTypeLowBits bitset_low() const; + inline void set_bitset_low(TurbofanTypeLowBits value); + inline TurbofanTypeHighBits bitset_high() const; + inline void set_bitset_high(TurbofanTypeHighBits value); static constexpr int SizeFor() { return sizeof(TurbofanBitsetType); } @@ -128,8 +129,8 @@ V8_OBJECT class TurbofanBitsetType : public TurbofanType { private: friend class TorqueGeneratedTurbofanBitsetTypeAsserts; - uint32_t bitset_low_; - uint32_t bitset_high_; + TurbofanTypeLowBits bitset_low_; + TurbofanTypeHighBits bitset_high_; } V8_OBJECT_END; V8_OBJECT class TurbofanUnionType : public TurbofanType { @@ -192,7 +193,7 @@ V8_OBJECT class TurbofanHeapConstantType : public TurbofanType { private: friend class TorqueGeneratedTurbofanHeapConstantTypeAsserts; - TaggedMember<Object> constant_; + TaggedMember<HeapObject> constant_; } V8_OBJECT_END; V8_OBJECT class TurbofanOtherNumberConstantType : public TurbofanType { diff --git a/deps/v8/src/objects/turbofan-types.tq b/deps/v8/src/objects/turbofan-types.tq index 9ee47fd52541..6d0a3240942c 100644 --- a/deps/v8/src/objects/turbofan-types.tq +++ b/deps/v8/src/objects/turbofan-types.tq @@ -18,7 +18,7 @@ extern class TurbofanType extends HeapObject {} // of 64 bit bitsets. @cppScope('TurbofanTypeLowBits') bitfield struct TurbofanTypeLowBits extends uint32 { - _unused_padding_field_1: bool: 1 bit; + unused_padding_field1: bool: 1 bit; other_unsigned31: bool: 1 bit; other_unsigned32: bool: 1 bit; other_signed32: bool: 1 bit; @@ -30,7 +30,7 @@ bitfield struct TurbofanTypeLowBits extends uint32 { boolean: bool: 1 bit; unsigned30: bool: 1 bit; minus_zero: bool: 1 bit; - naN: bool: 1 bit; + nan: bool: 1 bit; symbol: bool: 1 bit; internalized_string: bool: 1 bit; other_callable: bool: 1 bit; @@ -44,9 +44,9 @@ bitfield struct TurbofanTypeLowBits extends uint32 { other_internal: bool: 1 bit; external_pointer: bool: 1 bit; array: bool: 1 bit; - unsigned_big_int_63: bool: 1 bit; - other_unsigned_big_int_64: bool: 1 bit; - negative_big_int_63: bool: 1 bit; + unsigned_big_int63: bool: 1 bit; + other_unsigned_big_int64: bool: 1 bit; + negative_big_int63: bool: 1 bit; other_big_int: bool: 1 bit; wasm_object: bool: 1 bit; sandboxed_pointer: bool: 1 bit; @@ -119,7 +119,7 @@ macro TestTurbofanBitsetType( return bitsetLow.other_number; } } else if (Float64IsNaN(valueF)) { - return bitsetLow.naN; + return bitsetLow.nan; } else { return bitsetLow.other_number; } @@ -164,12 +164,11 @@ macro TestTurbofanBitsetType( return bitsetLow.array; } case (bi: BigInt): { - dcheck(!bitsetLow.other_big_int || bitsetLow.other_unsigned_big_int_64); - dcheck(!bitsetLow.other_big_int || bitsetLow.negative_big_int_63); + dcheck(!bitsetLow.other_big_int || bitsetLow.other_unsigned_big_int64); + dcheck(!bitsetLow.other_big_int || bitsetLow.negative_big_int63); dcheck( - !bitsetLow.other_unsigned_big_int_64 || - bitsetLow.unsigned_big_int_63); - dcheck(!bitsetLow.negative_big_int_63 || bitsetLow.unsigned_big_int_63); + !bitsetLow.other_unsigned_big_int64 || bitsetLow.unsigned_big_int63); + dcheck(!bitsetLow.negative_big_int63 || bitsetLow.unsigned_big_int63); // On 32 bit architectures, [Un]signedBigInt64 types are not used, yet. if (!Is64()) { @@ -180,19 +179,19 @@ macro TestTurbofanBitsetType( if (length > 1) { return bitsetLow.other_big_int; } else if (length == 0) { - return bitsetLow.unsigned_big_int_63; + return bitsetLow.unsigned_big_int63; } dcheck(length == 1); const sign = bigint::ReadBigIntSign(bi); const digit = bigint::LoadBigIntDigit(bi, 0); if (sign == bigint::kPositiveSign) { - return bitsetLow.other_unsigned_big_int_64 || + return bitsetLow.other_unsigned_big_int64 || (digit <= Convert<uintptr>(kMaxIntPtr) && - bitsetLow.unsigned_big_int_63); + bitsetLow.unsigned_big_int63); } else { return bitsetLow.other_big_int || (digit <= Convert<uintptr>(kMinIntPtr) && - bitsetLow.negative_big_int_63); + bitsetLow.negative_big_int63); } } case (wrapper: JSPrimitiveWrapper): { diff --git a/deps/v8/src/objects/turboshaft-types-inl.h b/deps/v8/src/objects/turboshaft-types-inl.h index 2de378d8e255..b561a4db4277 100644 --- a/deps/v8/src/objects/turboshaft-types-inl.h +++ b/deps/v8/src/objects/turboshaft-types-inl.h @@ -80,10 +80,11 @@ void TurboshaftWord64SetType::set_elements_low(int i, uint32_t value) { } // TurboshaftFloat64Type -uint32_t TurboshaftFloat64Type::special_values() const { +TurboshaftFloatSpecialValues TurboshaftFloat64Type::special_values() const { return special_values_; } -void TurboshaftFloat64Type::set_special_values(uint32_t value) { +void TurboshaftFloat64Type::set_special_values( + TurboshaftFloatSpecialValues value) { special_values_ = value; } diff --git a/deps/v8/src/objects/turboshaft-types.h b/deps/v8/src/objects/turboshaft-types.h index 6a69afa9b0da..06303ca921f4 100644 --- a/deps/v8/src/objects/turboshaft-types.h +++ b/deps/v8/src/objects/turboshaft-types.h @@ -7,6 +7,7 @@ #include "src/base/bit-field.h" #include "src/common/globals.h" +#include "src/objects/bit-field-group.h" #include "src/objects/heap-object.h" // Has to be the last include (doesn't have include guards): @@ -14,11 +15,16 @@ namespace v8::internal { -class TurboshaftFloatSpecialValues { - public: - using NanBit = base::BitField<bool, 0, 1, uint32_t>; +struct TurboshaftFloatSpecialValues + : BitFieldGroup<TurboshaftFloatSpecialValues, uint32_t> { + using BitFieldGroup::BitFieldGroup; + + using NanBit = First<bool, 1>; using MinusZeroBit = NanBit::Next<bool, 1>; using UnusedBits = MinusZeroBit::Next<uint32_t, 30>; + + BIT_FIELD_GROUP_ACCESSORS(nan, NanBit) + BIT_FIELD_GROUP_ACCESSORS(minus_zero, MinusZeroBit) }; V8_OBJECT class TurboshaftType : public HeapObject { @@ -70,7 +76,8 @@ V8_OBJECT class TurboshaftWord32SetType : public TurboshaftWord32Type { private: friend class TorqueGeneratedTurboshaftWord32SetTypeAsserts; - uint32_t set_size_; + V8_TQ_CONST uint32_t set_size_; + V8_TQ_TAIL_LENGTH(set_size); FLEXIBLE_ARRAY_MEMBER(uint32_t, elements); } V8_OBJECT_END; @@ -132,9 +139,10 @@ V8_OBJECT class TurboshaftWord64SetType : public TurboshaftWord64Type { private: friend class TorqueGeneratedTurboshaftWord64SetTypeAsserts; - uint32_t set_size_; + V8_TQ_CONST uint32_t set_size_; // Layout: elements_[0..set_size) is the high-32-bit array; the following // set_size slots hold the low-32-bit array. + V8_TQ_TAIL_LENGTH(Convert<intptr>(set_size) * 2); FLEXIBLE_ARRAY_MEMBER(uint32_t, elements); } V8_OBJECT_END; @@ -147,15 +155,15 @@ V8_OBJECT class TurboshaftFloat64Type : public TurboshaftType { V8_IT_ABSTRACT; public: - inline uint32_t special_values() const; - inline void set_special_values(uint32_t value); + inline TurboshaftFloatSpecialValues special_values() const; + inline void set_special_values(TurboshaftFloatSpecialValues value); DECL_VERIFIER(TurboshaftFloat64Type) private: friend class TorqueGeneratedTurboshaftFloat64TypeAsserts; - uint32_t special_values_; + TurboshaftFloatSpecialValues special_values_; } V8_OBJECT_END; V8_OBJECT class TurboshaftFloat64RangeType : public TurboshaftFloat64Type { @@ -201,7 +209,8 @@ V8_OBJECT class TurboshaftFloat64SetType : public TurboshaftFloat64Type { private: friend class TorqueGeneratedTurboshaftFloat64SetTypeAsserts; - uint32_t set_size_; + V8_TQ_CONST uint32_t set_size_; + V8_TQ_TAIL_LENGTH(set_size); FLEXIBLE_ARRAY_MEMBER(UnalignedDoubleMember, elements); } V8_OBJECT_END; diff --git a/deps/v8/src/objects/turboshaft-types.tq b/deps/v8/src/objects/turboshaft-types.tq index bf8dd4ac5c66..d08467cb5dd4 100644 --- a/deps/v8/src/objects/turboshaft-types.tq +++ b/deps/v8/src/objects/turboshaft-types.tq @@ -12,7 +12,7 @@ extern macro Abort(constexpr AbortReason): never; bitfield struct TurboshaftFloatSpecialValues extends uint32 { nan: bool: 1 bit; minus_zero: bool: 1 bit; - _unused: uint32: 30 bit; + unused: uint32: 30 bit; } @abstract @@ -50,8 +50,8 @@ extern class TurboshaftWord64RangeType extends TurboshaftWord64Type { @cppObjectLayoutDefinition extern class TurboshaftWord64SetType extends TurboshaftWord64Type { const set_size: uint32; - elements_high[set_size]: uint32; - elements_low[set_size]: uint32; + // The high 32 bits of all set elements, followed by the low 32 bits. + elements[Convert<intptr>(set_size) * 2]: uint32; } @abstract @@ -124,7 +124,7 @@ macro TestTurboshaftWord64Type( case (set: TurboshaftWord64SetType): { for (let i: uint32 = 0; i < set.set_size; ++i) { if (CompareUint64HighLow( - set.elements_high[i], set.elements_low[i], valueHigh, + set.elements[i], set.elements[set.set_size + i], valueHigh, valueLow) == 0) { return true; } diff --git a/deps/v8/src/objects/value-serializer.cc b/deps/v8/src/objects/value-serializer.cc index 36a784bcbf5a..28316b0ef0f4 100644 --- a/deps/v8/src/objects/value-serializer.cc +++ b/deps/v8/src/objects/value-serializer.cc @@ -529,6 +529,15 @@ Maybe<bool> ValueSerializer::WriteObject(DirectHandle<Object> object) { } return WriteJSReceiver(view); } +#if V8_ENABLE_WEBASSEMBLY + case WASM_CUSTOM_MAP_TYPE: + // Like WASM_STRUCT_TYPE in WriteJSReceiver: possibly shared, otherwise + // not serializable. + if (HeapLayout::InAnySharedSpace(Cast<HeapObject>(*object))) { + return WriteSharedObject(Cast<HeapObject>(object)); + } + return ThrowDataCloneError(MessageTemplate::kDataCloneError, object); +#endif // V8_ENABLE_WEBASSEMBLY default: if (InstanceTypeChecker::IsString(instance_type)) { WriteString(Cast<String>(object)); @@ -695,9 +704,6 @@ Maybe<bool> ValueSerializer::WriteJSReceiver( return WriteJSSharedArray(Cast<JSSharedArray>(receiver)); case JS_SHARED_STRUCT_TYPE: return WriteJSSharedStruct(Cast<JSSharedStruct>(receiver)); - case JS_ATOMICS_MUTEX_TYPE: - case JS_ATOMICS_CONDITION_TYPE: - return WriteSharedObject(receiver); #if V8_ENABLE_WEBASSEMBLY case WASM_MODULE_OBJECT_TYPE: return WriteWasmModule(Cast<WasmModuleObject>(receiver)); @@ -1171,17 +1177,17 @@ Maybe<bool> ValueSerializer::WriteJSError(DirectHandle<JSObject> error) { return Nothing<bool>(); } - if (name->IsOneByteEqualTo(base::CStrVector("EvalError"))) { + if (name->IsOneByteEqualTo("EvalError")) { WriteVarint(static_cast<uint8_t>(ErrorTag::kEvalErrorPrototype)); - } else if (name->IsOneByteEqualTo(base::CStrVector("RangeError"))) { + } else if (name->IsOneByteEqualTo("RangeError")) { WriteVarint(static_cast<uint8_t>(ErrorTag::kRangeErrorPrototype)); - } else if (name->IsOneByteEqualTo(base::CStrVector("ReferenceError"))) { + } else if (name->IsOneByteEqualTo("ReferenceError")) { WriteVarint(static_cast<uint8_t>(ErrorTag::kReferenceErrorPrototype)); - } else if (name->IsOneByteEqualTo(base::CStrVector("SyntaxError"))) { + } else if (name->IsOneByteEqualTo("SyntaxError")) { WriteVarint(static_cast<uint8_t>(ErrorTag::kSyntaxErrorPrototype)); - } else if (name->IsOneByteEqualTo(base::CStrVector("TypeError"))) { + } else if (name->IsOneByteEqualTo("TypeError")) { WriteVarint(static_cast<uint8_t>(ErrorTag::kTypeErrorPrototype)); - } else if (name->IsOneByteEqualTo(base::CStrVector("URIError"))) { + } else if (name->IsOneByteEqualTo("URIError")) { WriteVarint(static_cast<uint8_t>(ErrorTag::kUriErrorPrototype)); } else { // The default prototype in the deserialization side is Error.prototype, so @@ -1365,14 +1371,15 @@ Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() { Maybe<bool> ValueSerializer::ThrowDataCloneError( MessageTemplate template_index) { - return ThrowDataCloneError(template_index, - isolate_->factory()->empty_string()); + return ThrowDataCloneError(template_index, {}); } Maybe<bool> ValueSerializer::ThrowDataCloneError(MessageTemplate index, DirectHandle<Object> arg0) { - DirectHandle<String> message = - MessageFormatter::Format(isolate_, index, base::VectorOf({arg0})); + DirectHandle<String> message = MessageFormatter::Format( + isolate_, index, + arg0.is_null() ? base::Vector<const DirectHandle<Object>>{} + : base::VectorOf({arg0})); if (delegate_) { delegate_->ThrowDataCloneError(Utils::ToLocal(message)); } else { @@ -1838,7 +1845,7 @@ MaybeDirectHandle<String> ValueDeserializer::ReadUtf8String( base::Vector<const uint8_t> utf8_bytes; if (!ReadRawBytes(utf8_length).To(&utf8_bytes)) return {}; return isolate_->factory()->NewStringFromUtf8( - base::Vector<const char>::cast(utf8_bytes), allocation); + utf8_bytes, unibrow::Utf8Variant::kLossyUtf8, allocation); } MaybeDirectHandle<String> ValueDeserializer::ReadOneByteString( @@ -1875,7 +1882,7 @@ MaybeDirectHandle<String> ValueDeserializer::ReadTwoByteString( // Copy the bytes directly into the new string. // Warning: this uses host endianness. DisallowGarbageCollection no_gc; - memcpy(string->GetChars(no_gc), bytes.begin(), bytes.length()); + memcpy(string->GetChars(no_gc), bytes.begin(), bytes.size()); return string; } @@ -2542,6 +2549,11 @@ MaybeDirectHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() { return {}; } + // A shared JSArrayBuffer is required and can only be deserialized via a + // delegate. Check this before allocating an incomplete WasmMemoryObject and + // adding it to the ID map. + if (delegate_ == nullptr) return {}; + // To break a cycle on deserialization, we first allocate the // `WasmMemoryObject`, then read the `JSArrayBuffer`, then link the two. DirectHandle<WasmMemoryObject> result = WasmMemoryObject::New( @@ -2729,8 +2741,12 @@ Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( } } else if (tag == SerializationTag::kUtf8String) { base::Vector<const uint8_t> key_chars; - if (ReadRawBytes(byte_length).To(&key_chars) && - String::IsAscii(key_chars.begin(), key_chars.length())) { + // For ASCII strings, the UTF-8 byte length equals the character + // length, so an ASCII string cannot exceed String::kMaxLength. + // Non-ASCII or overly long strings fall back to ReadObject() below. + if (byte_length <= String::kMaxLength && + ReadRawBytes(byte_length).To(&key_chars) && + String::IsAscii(key_chars.begin(), byte_length)) { expected_transition = transitions.ExpectedTransition(key_chars); } } diff --git a/deps/v8/src/objects/visitors.h b/deps/v8/src/objects/visitors.h index 7460ec6949d0..b306bd4ff6f2 100644 --- a/deps/v8/src/objects/visitors.h +++ b/deps/v8/src/objects/visitors.h @@ -197,9 +197,9 @@ class ObjectVisitor { virtual void VisitCppHeapPointer(Tagged<HeapObject> host, CppHeapPointerSlot slot) {} - virtual void VisitIndirectPointer(Tagged<HeapObject> host, - IndirectPointerSlot slot, - IndirectPointerMode mode) {} + virtual void VisitTrustedPointer(Tagged<HeapObject> host, + TrustedPointerSlot slot, + TrustedPointerMode mode) {} virtual void VisitProtectedPointer(Tagged<TrustedObject> host, ProtectedPointerSlot slot) {} @@ -207,7 +207,7 @@ class ObjectVisitor { ProtectedMaybeObjectSlot slot) {} virtual void VisitTrustedPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) {} + TrustedPointerSlot slot) {} virtual void VisitJSDispatchTableEntry(Tagged<HeapObject> host, JSDispatchHandle handle) {} diff --git a/deps/v8/src/objects/waiter-queue-node.cc b/deps/v8/src/objects/waiter-queue-node.cc deleted file mode 100644 index 92dbbcd8ef24..000000000000 --- a/deps/v8/src/objects/waiter-queue-node.cc +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2024 the V8 project 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 "src/objects/waiter-queue-node.h" - -#include "src/base/macros.h" -#include "src/base/platform/time.h" -#include "src/heap/local-heap-inl.h" - -namespace v8 { -namespace internal { -namespace detail { - -WaiterQueueNode::WaiterQueueNode(Isolate* requester) - : requester_(requester), should_wait_(true) {} - -WaiterQueueNode::~WaiterQueueNode() { - // Since waiter queue nodes are allocated on the stack, they must be removed - // from the intrusive linked list once they go out of scope, otherwise there - // will be dangling pointers. - SbxCheckNotInList(); -} - -// static -void WaiterQueueNode::Enqueue(WaiterQueueNode** head, - WaiterQueueNode* new_tail) { - DCHECK_NOT_NULL(head); - new_tail->SbxCheckNotInList(); - WaiterQueueNode* current_head = *head; - if (current_head == nullptr) { - new_tail->next_ = new_tail; - new_tail->prev_ = new_tail; - *head = new_tail; - } else { - WaiterQueueNode* current_tail = current_head->prev_; - current_tail->next_ = new_tail; - current_head->prev_ = new_tail; - new_tail->next_ = current_head; - new_tail->prev_ = current_tail; - } -} - -WaiterQueueNode* WaiterQueueNode::DequeueMatching( - WaiterQueueNode** head, const DequeueMatcher& matcher) { - DCHECK_NOT_NULL(head); - DCHECK_NOT_NULL(*head); - WaiterQueueNode* const original_head = *head; - WaiterQueueNode* cur = *head; - do { - if (matcher(cur)) { - WaiterQueueNode* const next = cur->next_; - if (next == cur) { - // The queue contains exactly 1 node. - DCHECK_EQ(cur, original_head); - *head = nullptr; - } else { - // The queue contains >1 nodes. - if (cur == original_head) { - // The matched node is the original head, so next is the new head. - WaiterQueueNode* tail = original_head->prev_; - next->prev_ = tail; - tail->next_ = next; - *head = next; - } else { - // The matched node is in the middle of the queue, so the head does - // not need to be updated. - cur->prev_->next_ = next; - next->prev_ = cur->prev_; - } - } - cur->SetNotInListForVerification(); - return cur; - } - cur = cur->next_; - } while (cur != original_head); - return nullptr; -} - -// static -WaiterQueueNode* WaiterQueueNode::Dequeue(WaiterQueueNode** head) { - return DequeueMatching(head, [](WaiterQueueNode* node) { return true; }); -} - -// static -WaiterQueueNode* WaiterQueueNode::Split(WaiterQueueNode** head, - uint32_t count) { - DCHECK_GT(count, 0); - DCHECK_NOT_NULL(head); - DCHECK_NOT_NULL(*head); - WaiterQueueNode* front_head = *head; - WaiterQueueNode* back_head = front_head; - uint32_t actual_count = 0; - while (actual_count < count) { - back_head = back_head->next_; - // The queue is shorter than the requested count, return the whole queue. - if (back_head == front_head) { - *head = nullptr; - return front_head; - } - actual_count++; - } - WaiterQueueNode* front_tail = back_head->prev_; - WaiterQueueNode* back_tail = front_head->prev_; - - // Fix up the back list (i.e. remainder of the list). - back_head->prev_ = back_tail; - back_tail->next_ = back_head; - *head = back_head; - - // Fix up and return the front list (i.e. the dequeued list). - front_head->prev_ = front_tail; - front_tail->next_ = front_head; - return front_head; -} - -// static -int WaiterQueueNode::LengthFromHead(WaiterQueueNode* head) { - WaiterQueueNode* cur = head; - int len = 0; - do { - len++; - cur = cur->next_; - } while (cur != head); - return len; -} - -void WaiterQueueNode::Wait() { - AllowGarbageCollection allow_before_parking; - requester_->main_thread_local_heap()->ExecuteWhileParked([this]() { - base::MutexGuard guard(&wait_lock_); - while (should_wait_) { - wait_cond_var_.Wait(&wait_lock_); - } - }); -} - -// Returns false if timed out, true otherwise. -bool WaiterQueueNode::WaitFor(const base::TimeDelta& rel_time) { - bool result; - AllowGarbageCollection allow_before_parking; - requester_->main_thread_local_heap()->ExecuteWhileParked([this, rel_time, - &result]() { - base::MutexGuard guard(&wait_lock_); - base::TimeTicks current_time = base::TimeTicks::Now(); - base::TimeTicks timeout_time = current_time + rel_time; - for (;;) { - if (!should_wait_) { - result = true; - return; - } - current_time = base::TimeTicks::Now(); - if (current_time >= timeout_time) { - result = false; - return; - } - base::TimeDelta time_until_timeout = timeout_time - current_time; - bool wait_res = wait_cond_var_.WaitFor(&wait_lock_, time_until_timeout); - USE(wait_res); - // The wake up may have been spurious, so loop again. - } - }); - return result; -} - -void WaiterQueueNode::Notify() { - base::MutexGuard guard(&wait_lock_); - should_wait_ = false; - wait_cond_var_.NotifyOne(); - SetNotInListForVerification(); -} - -uint32_t WaiterQueueNode::NotifyAllInList() { - WaiterQueueNode* cur = this; - uint32_t count = 0; - do { - WaiterQueueNode* next = cur->next_; - cur->Notify(); - cur = next; - count++; - } while (cur != this); - return count; -} - -void WaiterQueueNode::SbxCheckNotInList() const { - SBXCHECK_EQ(nullptr, next_); - SBXCHECK_EQ(nullptr, prev_); -} - -void WaiterQueueNode::SetNotInListForVerification() { - next_ = prev_ = nullptr; -} - -} // namespace detail -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/objects/waiter-queue-node.h b/deps/v8/src/objects/waiter-queue-node.h deleted file mode 100644 index f58723d8aba9..000000000000 --- a/deps/v8/src/objects/waiter-queue-node.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2024 the V8 project 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 V8_OBJECTS_WAITER_QUEUE_NODE_H_ -#define V8_OBJECTS_WAITER_QUEUE_NODE_H_ - -#include "src/base/platform/condition-variable.h" - -namespace v8 { - -namespace base { -class TimeDelta; -} // namespace base - -namespace internal { - -class Isolate; - -namespace detail { - -// To manage waiting threads inside JSSynchronizationPrimitives, there is a -// process-wide doubly-linked intrusive list per waiter (i.e. mutex or condition -// variable). There is a per-thread node allocated on the stack when the thread -// goes to sleep during waiting. -// -// When compressing pointers (including when sandboxing), the access to the -// on-stack node is indirected through the shared external pointer table. -// -// TODO(https://crbug.com/42202493): Unittest this. -class V8_NODISCARD WaiterQueueNode final { - public: - explicit WaiterQueueNode(Isolate* requester); - - ~WaiterQueueNode(); - - // Enqueues {new_tail}, mutating {head} to be the new head. - static void Enqueue(WaiterQueueNode** head, WaiterQueueNode* new_tail); - - using DequeueMatcher = std::function<bool(WaiterQueueNode*)>; - // Dequeues the first waiter for which {matcher} returns true and returns it; - // mutating {head} to be the new head. - // - // The queue lock must be held in the synchronization primitive that owns - // this waiter queue when calling this method. - static WaiterQueueNode* DequeueMatching(WaiterQueueNode** head, - const DequeueMatcher& matcher); - - static WaiterQueueNode* Dequeue(WaiterQueueNode** head); - - // Splits at most {count} nodes of the waiter list of into its own list and - // returns it, mutating {head} to be the head of the back list. - static WaiterQueueNode* Split(WaiterQueueNode** head, uint32_t count); - - // This method must be called from a known waiter queue head. Incorrectly - // encoded lists can cause this method to infinitely loop. - static int LengthFromHead(WaiterQueueNode* head); - - void Wait(); - - // Returns false if timed out, true otherwise. - bool WaitFor(const base::TimeDelta& rel_time); - - void Notify(); - - uint32_t NotifyAllInList(); - - private: - void SetNotInListForVerification(); - - Isolate* requester_; - // The queue wraps around, e.g. the head's prev is the tail, and the tail's - // next is the head. - WaiterQueueNode* next_ = nullptr; - WaiterQueueNode* prev_ = nullptr; - - bool should_wait_ = false; - - base::Mutex wait_lock_; - base::ConditionVariable wait_cond_var_; - void SbxCheckNotInList() const; -}; - -} // namespace detail -} // namespace internal -} // namespace v8 - -#endif // V8_OBJECTS_WAITER_QUEUE_NODE_H_ diff --git a/deps/v8/src/parsing/expression-scope.h b/deps/v8/src/parsing/expression-scope.h index a448a4e50682..335e8e95cc07 100644 --- a/deps/v8/src/parsing/expression-scope.h +++ b/deps/v8/src/parsing/expression-scope.h @@ -128,12 +128,29 @@ class ExpressionScope { AsExpressionParsingScope()->MarkIdentifierAsAssigned(); } - void ValidateAsPattern(ExpressionT expression, int begin, int end) { + void RemoveAsyncKeyword() { if (!CanBeExpression()) return; - AsExpressionParsingScope()->ValidatePattern(expression, begin, end); + AsExpressionParsingScope()->RemoveAsyncKeyword(); + } + + void ValidateAsPattern(ExpressionT expression, int begin, int end, + int variable_index) { + if (!CanBeExpression()) return; + AsExpressionParsingScope()->ValidatePattern(expression, begin, end, + variable_index); AsExpressionParsingScope()->ClearExpressionError(); } + int variable_list_length() { + if (!CanBeExpression()) return 0; + return AsExpressionParsingScope()->variable_list()->length(); + } + + void DiscardVariablesSince(int variable_index) { + if (!CanBeExpression()) return; + AsExpressionParsingScope()->DiscardVariablesSince(variable_index); + } + void ValidateAsExpression() { if (!CanBeExpression()) return; AsExpressionParsingScope()->ValidateExpression(); @@ -157,7 +174,7 @@ class ExpressionScope { MessageTemplate message) { ExpressionScope* scope = this; while (!scope->IsCertainlyParameterDeclaration()) { - if (!has_possible_parameter_in_scope_chain_) return; + if (!scope->has_possible_parameter_in_scope_chain_) return; if (scope->CanBeParameterDeclaration()) { scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); } @@ -197,7 +214,10 @@ class ExpressionScope { } else { parser_->parameters_->set_strict_parameter_error(loc, message); } - } else { + } else if (is_strict(parser_->language_mode())) { + AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); + } else if (!parser_->next_arrow_function_info_ + .strict_parameter_error_location.IsValid()) { parser_->next_arrow_function_info_.strict_parameter_error_location = loc; parser_->next_arrow_function_info_.strict_parameter_error_message = message; @@ -232,7 +252,7 @@ class ExpressionScope { } int SetInitializers(int variable_index, int peek_position) { - if (CanBeExpression()) { + if (CanBeArrowParameterDeclaration()) { return AsExpressionParsingScope()->SetInitializers(variable_index, peek_position); } @@ -243,6 +263,11 @@ class ExpressionScope { return has_possible_arrow_parameter_in_scope_chain_; } + bool CanBeArrowParameterDeclaration() const { + return base::IsInRange(type_, kMaybeArrowParameterDeclaration, + kMaybeAsyncArrowParameterDeclaration); + } + protected: enum ScopeType : uint8_t { // Expression or assignment target. @@ -290,9 +315,7 @@ class ExpressionScope { return static_cast<ExpressionParsingScope<Types>*>(this); } -#ifdef DEBUG bool has_error() const { return parser_->has_error(); } -#endif bool CanBeExpression() const { return base::IsInRange(type_, kExpression, @@ -341,10 +364,6 @@ class ExpressionScope { return base::IsInRange(type_, kMaybeArrowParameterDeclaration, kParameterDeclaration); } - bool CanBeArrowParameterDeclaration() const { - return base::IsInRange(type_, kMaybeArrowParameterDeclaration, - kMaybeAsyncArrowParameterDeclaration); - } bool IsCertainlyParameterDeclaration() const { return type_ == kParameterDeclaration; } @@ -505,7 +524,10 @@ class ExpressionParsingScope : public ExpressionScope<Types> { MessageTemplate message) { for (ExpressionScopeT* scope = this; scope != nullptr; scope = scope->parent()) { - if (!has_async_arrow_in_scope_chain_) break; + if (!scope->CanBeExpression() || + !scope->AsExpressionParsingScope()->has_async_arrow_in_scope_chain_) { + break; + } if (scope->type_ == ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration) { scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); @@ -525,7 +547,7 @@ class ExpressionParsingScope : public ExpressionScope<Types> { ValidateExpression(); return expression; } - this->mark_verified(); + ValidateExpression(); const bool early_error = false; return this->parser()->RewriteInvalidReferenceExpression( expression, beg_pos, end_pos, MessageTemplate::kInvalidLhsInFor, @@ -544,17 +566,27 @@ class ExpressionParsingScope : public ExpressionScope<Types> { void ValidateExpression() { Validate(kExpressionIndex); } - void ValidatePattern(ExpressionT expression, int begin, int end) { + void ValidatePattern(ExpressionT expression, int begin, int end, + int variable_index = 0) { Validate(kPatternIndex); if (expression->is_parenthesized()) { ExpressionScopeT::Report(Scanner::Location(begin, end), MessageTemplate::kInvalidDestructuringTarget); } - for (auto& variable_initializer_pair : variable_list_) { - variable_initializer_pair.first->set_is_assigned(); + for (int i = variable_index; i < variable_list_.length(); ++i) { + variable_list_.at(i).first->set_is_assigned(); } } + void DiscardVariablesSince(int variable_index) { + if (this->CanBeDeclaration()) { + for (int i = variable_index; i < variable_list_.length(); ++i) { + this->parser()->scope()->AddUnresolved(variable_list_.at(i).first); + } + } + variable_list_.Rewind(variable_index); + } + void ClearExpressionError() { DCHECK(verified_); #ifdef DEBUG @@ -578,6 +610,17 @@ class ExpressionParsingScope : public ExpressionScope<Types> { variable_list_.Add({variable, kNoSourcePosition}); } + void RemoveAsyncKeyword() { + DCHECK_GT(variable_list_.length(), 0); + VariableProxy* proxy = variable_list_.at(variable_list_.length() - 1).first; + DCHECK_EQ(proxy->raw_name(), + this->parser()->ast_value_factory()->async_string()); + if (!this->CanBeDeclaration()) { + this->parser()->scope()->DeleteUnresolved(proxy); + } + variable_list_.DropLast(); + } + void MarkIdentifierAsAssigned() { // It's possible we're parsing a syntax error. In that case it's not // guaranteed that there's a variable in the list. @@ -590,15 +633,12 @@ class ExpressionParsingScope : public ExpressionScope<Types> { if (len == 0) return 0; int end = len - 1; - // Loop backwards and abort as soon as we see one that's already set to - // avoid a loop on expressions like a,b,c,d,e,f,g (outside of an arrowhead). - // TODO(delphick): Look into removing this loop. for (int i = end; i >= first_variable_index && variable_list_.at(i).second == kNoSourcePosition; --i) { variable_list_.at(i).second = position; } - return end; + return len; } ScopedList<std::pair<VariableProxy*, int>>* variable_list() { @@ -724,6 +764,24 @@ class AccumulationScope { #endif } + void ValidateDeclaration() { + if (scope_ == nullptr) return; + if (!scope_->IsArrowHeadParsingScope()) { + ValidateExpression(); + return; + } + DCHECK(!scope_->is_verified()); + Accumulate(); + copy_back(ExpressionParsingScope<Types>::kPatternIndex); + scope_->AsArrowHeadParsingScope()->ValidateDeclaration(); +#ifdef DEBUG + scope_->clear_verified(); +#endif + scope_->clear(ExpressionParsingScope<Types>::kPatternIndex); + clear(ExpressionParsingScope<Types>::kExpressionIndex); + clear(ExpressionParsingScope<Types>::kPatternIndex); + } + ~AccumulationScope() { if (scope_ == nullptr) return; Accumulate(); @@ -742,6 +800,11 @@ class AccumulationScope { scope_->locations_[entry] = locations_[entry]; } + void clear(int entry) { + messages_[entry] = MessageTemplate::kNone; + locations_[entry] = Scanner::Location::invalid(); + } + ExpressionParsingScope<Types>* scope_; MessageTemplate messages_[2]; Scanner::Location locations_[2]; @@ -786,15 +849,19 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { this->parent()->MergeVariableList(this->variable_list()); } - DeclarationScope* ValidateAndCreateScope() { + void ValidateDeclaration() { DCHECK(!this->is_verified()); - DeclarationScope* result = this->parser()->NewFunctionScope(kind()); if (declaration_error_location.IsValid()) { ExpressionScope<Types>::Report(declaration_error_location, declaration_error_message); - return result; } this->ValidatePattern(); + } + + DeclarationScope* ValidateAndCreateScope() { + DeclarationScope* result = this->parser()->NewFunctionScope(kind()); + ValidateDeclaration(); + if (this->has_error()) return result; if (!has_simple_parameter_list_) result->SetHasNonSimpleParameters(); VariableKind kind = PARAMETER_VARIABLE; @@ -836,6 +903,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { void RecordDeclarationError(const Scanner::Location& loc, MessageTemplate message) { DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); + if (declaration_error_location.IsValid()) return; declaration_error_location = loc; declaration_error_message = message; } diff --git a/deps/v8/src/parsing/literal-buffer.cc b/deps/v8/src/parsing/literal-buffer.cc index 32ff27eb10a8..f5b7b727f254 100644 --- a/deps/v8/src/parsing/literal-buffer.cc +++ b/deps/v8/src/parsing/literal-buffer.cc @@ -5,29 +5,12 @@ #include "src/parsing/literal-buffer.h" #include "src/base/strings.h" -#include "src/execution/isolate.h" -#include "src/execution/local-isolate.h" -#include "src/heap/factory.h" -#include "src/objects/objects.h" -#include "src/objects/string.h" +#include "src/base/unique-array.h" #include "src/utils/memcopy.h" namespace v8 { namespace internal { -template <typename IsolateT> -DirectHandle<String> LiteralBuffer::Internalize(IsolateT* isolate) const { - if (is_one_byte()) { - return isolate->factory()->InternalizeString(one_byte_literal()); - } - return isolate->factory()->InternalizeString(two_byte_literal()); -} - -template DirectHandle<String> LiteralBuffer::Internalize( - Isolate* isolate) const; -template DirectHandle<String> LiteralBuffer::Internalize( - LocalIsolate* isolate) const; - size_t LiteralBuffer::NewCapacity(size_t min_capacity) { return min_capacity < (kMaxGrowth / (kGrowthFactor - 1)) ? min_capacity * kGrowthFactor @@ -36,13 +19,12 @@ size_t LiteralBuffer::NewCapacity(size_t min_capacity) { void LiteralBuffer::ExpandBuffer() { size_t min_capacity = std::max(kInitialCapacity, backing_store_.size()); - base::Vector<uint8_t> new_store = - base::Vector<uint8_t>::New(NewCapacity(min_capacity)); + base::UniqueArray<uint8_t> new_store = + base::UniqueArray<uint8_t>::NewForOverwrite(NewCapacity(min_capacity)); if (position_ > 0) { MemCopy(new_store.begin(), backing_store_.begin(), position_); } - backing_store_.Dispose(); - backing_store_ = new_store; + backing_store_ = std::move(new_store); } void LiteralBuffer::ExpandBufferAndAddOneByteChar(uint8_t one_byte_char) { @@ -58,35 +40,33 @@ void LiteralBuffer::ExpandBufferTo(size_t min_size) { size_t min_capacity = RoundUp<2>(min_size); min_capacity = std::max({kInitialCapacity, backing_store_.size(), min_capacity}); - base::Vector<uint8_t> new_store = - base::Vector<uint8_t>::New(NewCapacity(min_capacity)); + base::UniqueArray<uint8_t> new_store = + base::UniqueArray<uint8_t>::NewForOverwrite(NewCapacity(min_capacity)); if (position_ > 0) { MemCopy(new_store.begin(), backing_store_.begin(), position_); } - backing_store_.Dispose(); - backing_store_ = new_store; + backing_store_ = std::move(new_store); } void LiteralBuffer::ConvertToTwoByte() { DCHECK(is_one_byte()); - base::Vector<uint8_t> new_store; + base::UniqueArray<uint8_t> new_store; + uint8_t* dst_bytes = backing_store_.begin(); size_t new_content_size = position_ * base::kUC16Size; if (new_content_size >= backing_store_.size()) { // Ensure room for all currently read code units as UC16 as well // as the code unit about to be stored. - new_store = base::Vector<uint8_t>::New(NewCapacity(new_content_size)); - } else { - new_store = backing_store_; + new_store = base::UniqueArray<uint8_t>::NewForOverwrite( + NewCapacity(new_content_size)); + dst_bytes = new_store.begin(); } - CHECK_LE(position_, new_store.size()); uint8_t* src = backing_store_.begin(); - uint16_t* dst = reinterpret_cast<uint16_t*>(new_store.begin()); + uint16_t* dst = reinterpret_cast<uint16_t*>(dst_bytes); for (size_t i = position_; i > 0; i--) { dst[i - 1] = src[i - 1]; } - if (new_store.begin() != backing_store_.begin()) { - backing_store_.Dispose(); - backing_store_ = new_store; + if (!new_store.empty()) { + backing_store_ = std::move(new_store); } position_ = new_content_size; is_one_byte_ = false; diff --git a/deps/v8/src/parsing/literal-buffer.h b/deps/v8/src/parsing/literal-buffer.h index b6d7c9e00d09..6470b6e89b01 100644 --- a/deps/v8/src/parsing/literal-buffer.h +++ b/deps/v8/src/parsing/literal-buffer.h @@ -7,6 +7,7 @@ #include "include/v8config.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/strings/unicode-decoder.h" #include "src/utils/memcopy.h" @@ -18,7 +19,7 @@ namespace internal { class LiteralBuffer final { public: LiteralBuffer() = default; - ~LiteralBuffer() { backing_store_.Dispose(); } + ~LiteralBuffer() = default; LiteralBuffer(const LiteralBuffer&) = delete; LiteralBuffer& operator=(const LiteralBuffer&) = delete; @@ -98,9 +99,6 @@ class LiteralBuffer final { is_one_byte_ = true; } - template <typename IsolateT> - DirectHandle<String> Internalize(IsolateT* isolate) const; - private: static constexpr size_t kInitialCapacity = 256; static constexpr size_t kGrowthFactor = 4; @@ -135,7 +133,7 @@ class LiteralBuffer final { uint8_t one_byte_char); void ConvertToTwoByte(); - base::Vector<uint8_t> backing_store_; + base::UniqueArray<uint8_t> backing_store_; size_t position_ = 0; bool is_one_byte_ = true; }; diff --git a/deps/v8/src/parsing/parser-base.h b/deps/v8/src/parsing/parser-base.h index 1df1fa026f5b..0aa6bf06f802 100644 --- a/deps/v8/src/parsing/parser-base.h +++ b/deps/v8/src/parsing/parser-base.h @@ -30,7 +30,6 @@ #include "src/parsing/scanner.h" #include "src/parsing/token.h" #include "src/regexp/regexp.h" -#include "src/zone/zone-chunk-list.h" namespace v8::internal { @@ -728,6 +727,7 @@ class ParserBase { return true; case Token::kMul: case Token::kSemicolon: + case Token::kEos: kind = ParsePropertyKind::kClassField; return true; default: @@ -1017,10 +1017,6 @@ class ParserBase { scanner()->NextSymbol(ast_value_factory()) == name; } - bool PeekContextualKeyword(Token::Value token) { - return peek() == token && !scanner()->next_literal_contains_escapes(); - } - bool CheckContextualKeyword(const AstRawString* name) { if (PeekContextualKeyword(name)) { Consume(Token::kIdentifier); @@ -1029,14 +1025,6 @@ class ParserBase { return false; } - bool CheckContextualKeyword(Token::Value token) { - if (PeekContextualKeyword(token)) { - Consume(token); - return true; - } - return false; - } - void ExpectContextualKeyword(const AstRawString* name, const char* fullname = nullptr, int pos = -1) { Expect(Token::kIdentifier); @@ -1054,32 +1042,18 @@ class ParserBase { } } - void ExpectContextualKeyword(Token::Value token) { - // Token Should be in range of Token::kIdentifier + 1 to Token::kAsync - DCHECK(base::IsInRange(token, Token::kGet, Token::kAsync)); - Token::Value next = Next(); - if (V8_UNLIKELY(next != token)) { - ReportUnexpectedToken(next); - } - if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { - impl()->ReportUnexpectedToken(Token::kEscapedKeyword); - } - } - bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode) { if (Check(Token::kIn)) { *visit_mode = ForEachStatement::ENUMERATE; return true; - } else if (CheckContextualKeyword(Token::kOf)) { + } else if (Check(Token::kOf)) { *visit_mode = ForEachStatement::ITERATE; return true; } return false; } - bool PeekInOrOf() { - return peek() == Token::kIn || PeekContextualKeyword(Token::kOf); - } + bool PeekInOrOf() { return peek() == Token::kIn || peek() == Token::kOf; } // Checks whether an octal literal was last seen between beg_pos and end_pos. // Only called for strict mode strings. @@ -1184,7 +1158,8 @@ class ParserBase { original_scope_) && IsModule(function_state_->kind()))); return IsAsyncFunction(kind) || - IsClassStaticInitializerFunction(kind); + (IsClassStaticInitializerFunction(kind) && + GetDeclarationScope()->scope_type() == BLOCK_SCOPE); } bool is_using_allowed() const { // UsingDeclaration and AwaitUsingDeclaration are Syntax Errors if the goal @@ -1301,12 +1276,11 @@ class ParserBase { DeclarationScope* receiver_scope = closure_scope->GetReceiverScope(); Variable* var = receiver_scope->receiver(); var->set_is_used(); - if (closure_scope == receiver_scope) { - // It's possible that we're parsing the head of an arrow function, in - // which case we haven't realized yet that closure_scope != - // receiver_scope. Mark through the ExpressionScope for now. - expression_scope()->RecordThisUse(); - } else { + // It's possible that we're parsing the head of an arrow function, in + // which case the arrow function's DeclarationScope hasn't been created yet. + // Mark through the ExpressionScope for now. + expression_scope()->RecordThisUse(); + if (closure_scope != receiver_scope) { closure_scope->set_has_this_reference(true); var->ForceContextAllocation(); } @@ -1335,7 +1309,8 @@ class ParserBase { // become destructuring identifiers. V8_INLINE IdentifierT ParsePropertyName(); - ExpressionT ParsePropertyOrPrivatePropertyName(); + ExpressionT ParsePropertyOrPrivatePropertyName( + bool is_property_access = true); const AstRawString* GetNextSymbolForRegExpLiteral() const { return scanner()->NextSymbol(ast_value_factory()); @@ -1352,7 +1327,8 @@ class ParserBase { // a pattern. V8_INLINE ExpressionT ParseExpression(); V8_INLINE ExpressionT ParseAssignmentExpression(); - V8_INLINE ExpressionT ParseConditionalChainAssignmentExpression(); + V8_INLINE ExpressionT + ParseConditionalChainAssignmentExpression(bool* else_found); // These methods do not wrap the parsing of the expression inside a new // expression_scope; they use the outer expression_scope instead. They should @@ -1364,8 +1340,9 @@ class ParserBase { ExpressionT ParseExpressionCoverGrammar(); ExpressionT ParseAssignmentExpressionCoverGrammar(); ExpressionT ParseAssignmentExpressionCoverGrammarContinuation( - int lhs_beg_pos, ExpressionT expression); - ExpressionT ParseConditionalChainAssignmentExpressionCoverGrammar(); + int lhs_beg_pos, int lhs_variable_index, ExpressionT expression); + ExpressionT ParseConditionalChainAssignmentExpressionCoverGrammar( + bool* else_found); ExpressionT ParseArrowParametersWithRest(ExpressionListT* list, AccumulationScope* scope, @@ -1407,7 +1384,6 @@ class ParserBase { V8_INLINE ExpressionT ParseConditionalExpression(); ExpressionT ParseConditionalChainExpression(ExpressionT condition, int condition_pos); - ExpressionT ParseConditionalContinuation(ExpressionT expression, int pos); ExpressionT ParseLogicalExpression(); ExpressionT ParseCoalesceExpression(ExpressionT expression); ExpressionT ParseBinaryContinuation(ExpressionT x, int prec, int prec1); @@ -1897,7 +1873,7 @@ bool ParserBase<Impl>::ClassifyPropertyIdentifier( if (next == Token::kAwait) { DCHECK(!is_async_function()); expression_scope()->RecordAsyncArrowParametersError( - scanner()->peek_location(), MessageTemplate::kAwaitBindingIdentifier); + scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); } return true; } @@ -2014,11 +1990,14 @@ bool ParserBase<Impl>::IsExtraordinaryPrivateNameAccessAllowed() const { template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParsePropertyOrPrivatePropertyName() { +ParserBase<Impl>::ParsePropertyOrPrivatePropertyName(bool is_property_access) { int pos = position(); IdentifierT name; ExpressionT key; Token::Value next = Next(); + if (!is_property_access) { + pos = position(); + } if (V8_LIKELY(Token::IsPropertyName(next))) { name = impl()->GetSymbol(); key = factory()->NewStringLiteral(name, pos); @@ -2048,7 +2027,9 @@ ParserBase<Impl>::ParsePropertyOrPrivatePropertyName() { ReportUnexpectedToken(next); return impl()->FailureExpression(); } - impl()->PushLiteralName(name); + if (is_property_access) { + impl()->PushLiteralName(name); + } return key; } @@ -2121,12 +2102,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern() { if (Token::IsAnyIdentifier(token)) { IdentifierT name = ParseAndClassifyIdentifier(Next()); - if (V8_UNLIKELY(is_strict(language_mode()) && - impl()->IsEvalOrArguments(name))) { - impl()->ReportMessageAt(scanner()->location(), - MessageTemplate::kStrictEvalArguments); - return impl()->FailureExpression(); - } return impl()->ExpressionFromIdentifier(name, beg_pos); } @@ -2175,8 +2150,7 @@ ParserBase<Impl>::ParsePrimaryExpression() { FunctionKind kind = FunctionKind::kArrowFunction; if (V8_UNLIKELY(token == Token::kAsync && - !scanner()->HasLineTerminatorBeforeNext() && - !scanner()->literal_contains_escapes())) { + !scanner()->HasLineTerminatorBeforeNext())) { // async function ... if (peek() == Token::kFunction) return ParseAsyncFunctionLiteral(); @@ -2326,9 +2300,10 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression() { template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseConditionalChainAssignmentExpression() { +ParserBase<Impl>::ParseConditionalChainAssignmentExpression(bool* else_found) { ExpressionParsingScope expression_scope(impl()); - ExpressionT result = ParseConditionalChainAssignmentExpressionCoverGrammar(); + ExpressionT result = + ParseConditionalChainAssignmentExpressionCoverGrammar(else_found); expression_scope.ValidateExpression(); return result; } @@ -2354,7 +2329,8 @@ ParserBase<Impl>::ParseExpressionCoverGrammar() { AccumulationScope accumulation_scope(expression_scope()); int variable_index = 0; while (true) { - if (V8_UNLIKELY(peek() == Token::kEllipsis)) { + if (V8_UNLIKELY(peek() == Token::kEllipsis && + expression_scope()->CanBeArrowParameterDeclaration())) { return ParseArrowParametersWithRest(&list, &accumulation_scope, variable_index); } @@ -2363,14 +2339,16 @@ ParserBase<Impl>::ParseExpressionCoverGrammar() { expression = ParseAssignmentExpressionCoverGrammar(); ClassifyArrowParameter(&accumulation_scope, expr_pos, expression); + if (V8_UNLIKELY(expression_scope()->CanBeArrowParameterDeclaration())) { + variable_index = + expression_scope()->SetInitializers(variable_index, peek_position()); + } list.Add(expression); - variable_index = - expression_scope()->SetInitializers(variable_index, peek_position()); - if (!Check(Token::kComma)) break; - if (peek() == Token::kRightParen && PeekAhead() == Token::kArrow) { + if (expression_scope()->CanBeArrowParameterDeclaration() && + peek() == Token::kRightParen && PeekAhead() == Token::kArrow) { // a trailing comma is allowed at the end of an arrow parameter list break; } @@ -2401,21 +2379,24 @@ ParserBase<Impl>::ParseArrowParametersWithRest( Scanner::Location ellipsis = scanner()->location(); int pattern_pos = peek_position(); ExpressionT pattern = ParseBindingPattern(); - ClassifyArrowParameter(accumulation_scope, pattern_pos, pattern); + if (!pattern->IsFailureExpression()) { + ClassifyArrowParameter(accumulation_scope, pattern_pos, pattern); + } expression_scope()->RecordNonSimpleParameter(); if (V8_UNLIKELY(peek() == Token::kAssign)) { ReportMessage(MessageTemplate::kRestDefaultInitializer); + } else if (V8_UNLIKELY(peek() == Token::kComma)) { + ReportMessage(MessageTemplate::kParamAfterRest); + } + if (has_error()) { + accumulation_scope->ValidateDeclaration(); return impl()->FailureExpression(); } ExpressionT spread = factory()->NewSpread(pattern, ellipsis.beg_pos, pattern_pos); - if (V8_UNLIKELY(peek() == Token::kComma)) { - ReportMessage(MessageTemplate::kParamAfterRest); - return impl()->FailureExpression(); - } expression_scope()->SetInitializers(seen_variables, peek_position()); @@ -2450,7 +2431,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral() { } else if (Check(Token::kEllipsis)) { int start_pos = position(); int expr_pos = peek_position(); - AcceptINScope scope(this, true); ExpressionT argument = ParsePossibleDestructuringSubPattern(&accumulation_scope); elem = factory()->NewSpread(argument, start_pos, expr_pos); @@ -2470,8 +2450,14 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral() { Scanner::Location(start_pos, end_position()), MessageTemplate::kElementAfterRest); } + } else if (Token::IsLiteral(peek()) && + scanner()->HasImmediateCommaOrRightBracket()) { + int begin = peek_position(); + elem = impl()->ExpressionFromLiteral(Next(), begin); + expression_scope()->RecordPatternError( + Scanner::Location(begin, end_position()), + MessageTemplate::kInvalidDestructuringTarget); } else { - AcceptINScope scope(this, true); elem = ParsePossibleDestructuringSubPattern(&accumulation_scope); } values.Add(elem); @@ -2500,9 +2486,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( impl()->PushLiteralName(prop_info->name); return factory()->NewStringLiteral(prop_info->name, position()); } - if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { - impl()->ReportUnexpectedToken(Token::kEscapedKeyword); - } prop_info->function_flags = ParseFunctionFlag::kIsAsync; prop_info->kind = ParsePropertyKind::kMethod; } @@ -2515,8 +2498,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( if (prop_info->kind == ParsePropertyKind::kNotSet && base::IsInRange(peek(), Token::kGet, Token::kSet)) { Token::Value token = Next(); - if (prop_info->ParsePropertyKindFromToken(peek()) || - V8_UNLIKELY(scanner()->literal_contains_escapes())) { + if (prop_info->ParsePropertyKindFromToken(peek())) { prop_info->name = impl()->GetIdentifier(); impl()->PushLiteralName(prop_info->name); return factory()->NewStringLiteral(prop_info->name, position()); @@ -2605,13 +2587,15 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( if (prop_info->kind == ParsePropertyKind::kNotSet) { prop_info->name = impl()->NullIdentifier(); Consume(Token::kEllipsis); - AcceptINScope scope(this, true); int start_pos = peek_position(); ExpressionT expression = ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope); prop_info->kind = ParsePropertyKind::kSpread; - if (!IsValidReferenceExpression(expression)) { + if (!impl()->IsIdentifier(expression) && !expression->IsProperty()) { + if (prop_info->accumulation_scope != nullptr) { + prop_info->accumulation_scope->ValidateExpression(); + } expression_scope()->RecordDeclarationError( Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidRestBindingPattern); @@ -2620,7 +2604,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseProperty( MessageTemplate::kInvalidRestAssignmentPattern); } - if (peek() != Token::kRightBrace) { + if (peek() == Token::kComma) { expression_scope()->RecordPatternError( scanner()->location(), MessageTemplate::kElementAfterRest); } @@ -2673,8 +2657,7 @@ bool ParserBase<Impl>::ParseCurrentSymbolAsClassFieldOrMethod( *name_expression = factory()->NewStringLiteral(prop_info->name, position()); return true; } - if (peek() == Token::kAssign || peek() == Token::kSemicolon || - peek() == Token::kRightBrace) { + if (peek() == Token::kAssign || Token::IsAutoSemicolon(peek())) { prop_info->name = impl()->GetIdentifier(); *name_expression = factory()->NewStringLiteral(prop_info->name, position()); return true; @@ -2970,7 +2953,6 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, *has_seen_proto = true; } Consume(Token::kColon); - AcceptINScope scope(this, true); ExpressionT value = ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope); @@ -3208,14 +3190,18 @@ void ParserBase<Impl>::ParseArguments( if (is_spread) { expression_scope()->RecordNonSimpleParameter(); if (argument->IsAssignment()) { - expression_scope()->RecordAsyncArrowParametersError( + expression_scope()->RecordDeclarationError( scanner()->location(), MessageTemplate::kRestDefaultInitializer); } if (peek() == Token::kComma) { - expression_scope()->RecordAsyncArrowParametersError( + expression_scope()->RecordDeclarationError( scanner()->peek_location(), MessageTemplate::kParamAfterRest); } } + variable_index = + expression_scope()->SetInitializers(variable_index, peek_position()); + } else { + accumulation_scope.ValidateExpression(); } if (is_spread) { *has_spread = true; @@ -3223,9 +3209,6 @@ void ParserBase<Impl>::ParseArguments( } args->Add(argument); - variable_index = - expression_scope()->SetInitializers(variable_index, peek_position()); - if (!Check(Token::kComma)) break; } @@ -3242,7 +3225,8 @@ void ParserBase<Impl>::ParseArguments( template <typename Impl> typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar() { +ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar( + bool* else_found) { // AssignmentExpression :: // ArrowFunction // YieldExpression @@ -3250,6 +3234,7 @@ ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar() { int lhs_beg_pos = peek_position(); if (peek() == Token::kYield && is_generator()) { + *else_found = true; return ParseYieldExpression(); } @@ -3257,16 +3242,19 @@ ParserBase<Impl>::ParseConditionalChainAssignmentExpressionCoverGrammar() { DCHECK_IMPLIES(!has_error(), next_arrow_function_info_.HasInitialState()); + int lhs_variable_index = expression_scope()->variable_list_length(); ExpressionT expression = ParseLogicalExpression(); Token::Value op = peek(); - if (!Token::IsArrowOrAssignmentOp(op) || peek() == Token::kConditional) { + if (!Token::IsArrowOrAssignmentOp(op)) { + *else_found = (op != Token::kConditional); return expression; } - return ParseAssignmentExpressionCoverGrammarContinuation(lhs_beg_pos, - expression); + *else_found = true; + return ParseAssignmentExpressionCoverGrammarContinuation( + lhs_beg_pos, lhs_variable_index, expression); } // Precedence = 2 @@ -3288,21 +3276,22 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammar() { DCHECK_IMPLIES(!has_error(), next_arrow_function_info_.HasInitialState()); + int lhs_variable_index = expression_scope()->variable_list_length(); ExpressionT expression = ParseConditionalExpression(); Token::Value op = peek(); if (!Token::IsArrowOrAssignmentOp(op)) return expression; - return ParseAssignmentExpressionCoverGrammarContinuation(lhs_beg_pos, - expression); + return ParseAssignmentExpressionCoverGrammarContinuation( + lhs_beg_pos, lhs_variable_index, expression); } // Precedence = 2 template <typename Impl> typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAssignmentExpressionCoverGrammarContinuation( - int lhs_beg_pos, ExpressionT expression) { + int lhs_beg_pos, int lhs_variable_index, ExpressionT expression) { // AssignmentExpression :: // ConditionalExpression // ArrowFunction @@ -3366,6 +3355,7 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammarContinuation( Scanner::Location(lhs_beg_pos, end_position()), MessageTemplate::kInvalidPropertyBindingPattern); expression_scope()->ValidateAsExpression(); + expression_scope()->DiscardVariablesSince(lhs_variable_index); } else if (expression->IsPattern() && op == Token::kAssign) { // Destructuring assignmment. if (expression->is_parenthesized()) { @@ -3382,9 +3372,10 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammarContinuation( } } expression_scope()->ValidateAsPattern(expression, lhs_beg_pos, - end_position()); + end_position(), lhs_variable_index); } else { DCHECK(!IsValidReferenceExpression(expression)); + expression_scope()->ValidateAsExpression(); // For web compatibility reasons, throw early errors only for logical // assignment, not for regular assignment. const bool early_error = Token::IsLogicalAssignmentOp(op); @@ -3400,8 +3391,6 @@ ParserBase<Impl>::ParseAssignmentExpressionCoverGrammarContinuation( // Anonymous function name inference applies to =, ||=, &&=, and ??=. if (op == Token::kAssign || Token::IsLogicalAssignmentOp(op)) { - impl()->CheckAssigningFunctionLiteralToProperty(expression, right); - // Check if the right hand side is a call to avoid inferring a // name if we're dealing with "a = function(){...}();"-like // expression. @@ -3472,7 +3461,7 @@ ParserBase<Impl>::ParseYieldExpression() { // Delegating yields require an RHS; fall through. [[fallthrough]]; default: - expression = ParseAssignmentExpressionCoverGrammar(); + expression = ParseAssignmentExpression(); break; } } @@ -3609,11 +3598,9 @@ ParserBase<Impl>::ParseConditionalChainExpression(ExpressionT condition, &condition_or_else_range); Expect(Token::kColon); condition_or_else_expression = - ParseConditionalChainAssignmentExpression(); + ParseConditionalChainAssignmentExpression(&else_found); } - else_found = (peek() != Token::kConditional); - if (else_found) { else_expression = condition_or_else_expression; @@ -3653,33 +3640,6 @@ ParserBase<Impl>::ParseConditionalChainExpression(ExpressionT condition, return expr; } -template <typename Impl> -typename ParserBase<Impl>::ExpressionT -ParserBase<Impl>::ParseConditionalContinuation(ExpressionT expression, - int pos) { - SourceRange then_range, else_range; - - ExpressionT left; - { - SourceRangeScope range_scope(scanner(), &then_range); - Consume(Token::kConditional); - // In parsing the first assignment expression in conditional - // expressions we always accept the 'in' keyword; see ECMA-262, - // section 11.12, page 58. - AcceptINScope scope(this, true); - left = ParseAssignmentExpression(); - } - ExpressionT right; - { - SourceRangeScope range_scope(scanner(), &else_range); - Expect(Token::kColon); - right = ParseAssignmentExpression(); - } - ExpressionT expr = factory()->NewConditional(expression, left, right, pos); - impl()->RecordConditionalSourceRange(expr, then_range, else_range); - return expr; -} - // Precedence >= 4 template <typename Impl> typename ParserBase<Impl>::ExpressionT @@ -3744,7 +3704,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression( // "#foo in ShiftExpression" needs to be parsed separately, since private // identifiers are not valid PrimaryExpressions. if (V8_UNLIKELY(peek() == Token::kPrivateName)) { - ExpressionT x = ParsePropertyOrPrivatePropertyName(); + ExpressionT x = ParsePropertyOrPrivatePropertyName(false); int prec1 = Token::Precedence(peek(), accept_IN_); if (peek() != Token::kIn || prec1 < prec) { ReportUnexpectedToken(Token::kPrivateName); @@ -3809,6 +3769,7 @@ ParserBase<Impl>::ParseUnaryOrPrefixExpression() { expression_scope()->MarkIdentifierAsAssigned(); } } else { + expression_scope()->ValidateAsExpression(); const bool early_error = false; expression = RewriteInvalidReferenceExpression( expression, expression_position, end_position(), @@ -3898,6 +3859,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixContinuation(ExpressionT expression, int lhs_beg_pos) { if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) { + expression_scope()->ValidateAsExpression(); const bool early_error = false; expression = RewriteInvalidReferenceExpression( expression, lhs_beg_pos, end_position(), @@ -3930,24 +3892,31 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { if (V8_UNLIKELY(peek() == Token::kLeftParen && impl()->IsIdentifier(result) && scanner()->current_token() == Token::kAsync && - !scanner()->HasLineTerminatorBeforeNext() && - !scanner()->literal_contains_escapes())) { + !scanner()->HasLineTerminatorBeforeNext())) { DCHECK(impl()->IsAsync(impl()->AsIdentifier(result))); int pos = position(); - - ArrowHeadParsingScope maybe_arrow(impl(), FunctionKind::kAsyncArrowFunction, - PeekNextInfoId()); - Scope::Snapshot scope_snapshot(scope()); - ExpressionListT args(pointer_buffer()); bool has_spread; - ParseArguments(&args, &has_spread, kMaybeArrowHead); + { + ArrowHeadParsingScope maybe_arrow( + impl(), FunctionKind::kAsyncArrowFunction, PeekNextInfoId()); + Scope::Snapshot scope_snapshot(scope()); + + ParseArguments(&args, &has_spread, kMaybeArrowHead); + if (V8_LIKELY(peek() == Token::kArrow)) { + fni_.RemoveAsyncKeywordFromEnd(); + next_arrow_function_info_.scope = maybe_arrow.ValidateAndCreateScope(); + next_arrow_function_info_.function_literal_id = + maybe_arrow.function_literal_id(); + scope_snapshot.Reparent(next_arrow_function_info_.scope); + } else { + result = factory()->NewCall(result, args, pos, has_spread); + maybe_arrow.ValidateExpression(); + fni_.RemoveLastFunction(); + } + } if (V8_LIKELY(peek() == Token::kArrow)) { - fni_.RemoveAsyncKeywordFromEnd(); - next_arrow_function_info_.scope = maybe_arrow.ValidateAndCreateScope(); - next_arrow_function_info_.function_literal_id = - maybe_arrow.function_literal_id(); - scope_snapshot.Reparent(next_arrow_function_info_.scope); + expression_scope()->RemoveAsyncKeyword(); // async () => ... if (!args.length()) return factory()->NewEmptyParentheses(pos); // async ( Arguments ) => ... @@ -3955,12 +3924,6 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { result->mark_parenthesized(); return result; } - - result = factory()->NewCall(result, args, pos, has_spread); - - maybe_arrow.ValidateExpression(); - - fni_.RemoveLastFunction(); if (!Token::IsPropertyOrCall(peek())) return result; } @@ -3990,8 +3953,7 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) { case Token::kLeftBracket: { Consume(Token::kLeftBracket); int pos = position(); - AcceptINScope scope(this, true); - ExpressionT index = ParseExpressionCoverGrammar(); + ExpressionT index = ParseExpression(); result = factory()->NewProperty(result, index, pos, is_optional); Expect(Token::kRightBracket); break; @@ -4244,7 +4206,7 @@ ParserBase<Impl>::ParseImportExpressions() { } else { ExpectContextualKeyword(ast_value_factory()->meta_string(), "import.meta", pos); - if (!flags().is_module() && !IsParsingWhileDebugging()) { + if (!has_module_in_scope_chain() && !IsParsingWhileDebugging()) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kImportMetaOutsideModule); return impl()->FailureExpression(); @@ -4271,7 +4233,7 @@ ParserBase<Impl>::ParseImportExpressions() { } AcceptINScope scope(this, true); - ExpressionT specifier = ParseAssignmentExpressionCoverGrammar(); + ExpressionT specifier = ParseAssignmentExpression(); DCHECK_IMPLIES(phase == ModuleImportPhase::kSource, v8_flags.js_source_phase_imports); @@ -4283,7 +4245,7 @@ ParserBase<Impl>::ParseImportExpressions() { // A trailing comma allowed after the specifier. return factory()->NewImportCallExpression(specifier, phase, pos); } else { - ExpressionT import_options = ParseAssignmentExpressionCoverGrammar(); + ExpressionT import_options = ParseAssignmentExpression(); Check(Token::kComma); // A trailing comma is allowed after the import // attributes. Expect(Token::kRightParen); @@ -4314,25 +4276,34 @@ ParserBase<Impl>::ParseSuperExpression() { impl()->ReportMessage(MessageTemplate::kUnexpectedPrivateField); return impl()->FailureExpression(); } - if (peek() == Token::kQuestionPeriod) { - Consume(Token::kQuestionPeriod); - impl()->ReportMessage(MessageTemplate::kOptionalChainingNoSuper); - return impl()->FailureExpression(); - } scope->RecordSuperPropertyUsage(); UseThis(); return impl()->NewSuperPropertyReference(pos); } + if (peek() == Token::kQuestionPeriod) { + Consume(Token::kQuestionPeriod); + impl()->ReportMessage(MessageTemplate::kOptionalChainingNoSuper); + return impl()->FailureExpression(); + } // super() is only allowed in derived constructor. new super() is never // allowed; it's reported as an error by // ParseMemberWithPresentNewPrefixesExpression. - if (peek() == Token::kLeftParen && IsDerivedConstructor(kind)) { + if (peek() == Token::kLeftParen && + (IsDerivedConstructor(kind) || + this->scope()->GetClosureScope()->from_scope_info())) { // TODO(rossberg): This might not be the correct FunctionState for the // method here. expression_scope()->RecordThisUse(); UseThis(); return impl()->NewSuperCallReference(pos); } + } else if (this->scope()->GetClosureScope()->from_scope_info()) { + if (Token::IsProperty(peek())) { + return impl()->NewSuperPropertyReference(pos); + } + if (peek() == Token::kLeftParen) { + return impl()->NewSuperCallReference(pos); + } } impl()->ReportMessageAt(scanner()->location(), @@ -4348,7 +4319,8 @@ ParserBase<Impl>::ParseNewTargetExpression() { ExpectContextualKeyword(ast_value_factory()->target_string(), "new.target", pos); - if (!GetReceiverScope()->is_function_scope()) { + if (!GetReceiverScope()->is_function_scope() && + !this->scope()->GetClosureScope()->from_scope_info()) { impl()->ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedNewTarget); return impl()->FailureExpression(); @@ -4368,8 +4340,7 @@ ParserBase<Impl>::DoParseMemberExpressionContinuation(ExpressionT expression) { case Token::kLeftBracket: { Consume(Token::kLeftBracket); int pos = position(); - AcceptINScope scope(this, true); - ExpressionT index = ParseExpressionCoverGrammar(); + ExpressionT index = ParseExpression(); expression = factory()->NewProperty(expression, index, pos); impl()->PushPropertyName(index); Expect(Token::kRightBracket); @@ -4434,20 +4405,7 @@ void ParserBase<Impl>::ParseFormalParameter(FormalParametersT* parameters) { auto declaration_end = scope()->declarations()->end(); int initializer_end = end_position(); for (; declaration_it != declaration_end; ++declaration_it) { - Variable* var = declaration_it->var(); - - // The first time a variable is initialized (i.e. when the initializer - // position is unset), clear its maybe_assigned flag as it is not a true - // assignment. Since this is done directly on the Variable objects, it has - // no effect on VariableProxy objects appearing on the left-hand side of - // true assignments, so x will be still be marked as maybe_assigned for: - // (x = 1, y = (x = 2)) => {} - // and even: - // (x = (x = 2)) => {}. - if (var->initializer_position() == kNoSourcePosition) { - var->clear_maybe_assigned(); - } - var->set_initializer_position(initializer_end); + declaration_it->var()->set_initializer_position(initializer_end); } impl()->AddFormalParameter(parameters, pattern, initializer, end_position(), @@ -4551,6 +4509,9 @@ void ParserBase<Impl>::ParseVariableDeclarations( // CoverAwaitExpressionAndAwaitUsingDeclarationHead[?Yield] [no // LineTerminator here] BindingList[?In, ?Yield, +Await, ~Pattern]; Consume(Token::kAwait); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::kEscapedKeyword); + } DCHECK_NE(var_context, kStatement); DCHECK(is_using_allowed()); DCHECK(is_await_allowed()); @@ -4884,9 +4845,6 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration( // async [no LineTerminator here] function BindingIdentifier[Await] // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::kAsync); - if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { - impl()->ReportUnexpectedToken(Token::kEscapedKeyword); - } int pos = position(); DCHECK(!scanner()->HasLineTerminatorBeforeNext()); Consume(Token::kFunction); @@ -4926,7 +4884,7 @@ void ParserBase<Impl>::ParseFunctionBody( ExpressionT expression = ParseAssignmentExpression(); inner_body.Add(BuildReturnStatement(expression, expression->position())); } else { - DCHECK(accept_IN_); + AcceptINScope scope(this, true); DCHECK_EQ(FunctionBodyType::kBlock, body_type); // If we are parsing the source as if it is wrapped in a function, the // source ends without a closing brace. @@ -4952,6 +4910,10 @@ void ParserBase<Impl>::ParseFunctionBody( UseThis(); expression_scope.ValidateExpression(); } + if (is_strict(language_mode())) { + CheckStrictOctalLiteral(function_scope->start_position(), + peek_end_position()); + } Expect(closing_token); } } @@ -5183,11 +5145,16 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( if (has_error()) return impl()->FailureExpression(); DeclarationScope* function_scope = next_arrow_function_info_.scope; + function_scope->set_start_position( + formal_parameters.scope->start_position()); FunctionState inner_function_state(&function_state_, &scope_, function_scope); Scanner::Location loc(function_scope->start_position(), end_position()); FormalParametersT parameters(function_scope); + parameters.set_strict_parameter_error( + next_arrow_function_info_.strict_parameter_error_location, + next_arrow_function_info_.strict_parameter_error_message); parameters.is_simple = function_scope->has_simple_parameters(); impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc); @@ -5196,7 +5163,6 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( Consume(Token::kArrow); Consume(Token::kLeftBrace); - AcceptINScope scope(this, true); FunctionParsingScope body_parsing_scope(impl()); ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition, parameters, kind, @@ -5207,7 +5173,6 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( } } else { Consume(Token::kLeftBrace); - AcceptINScope scope(this, true); FunctionParsingScope body_parsing_scope(impl()); ParseFunctionBody(&body, impl()->NullIdentifier(), kNoSourcePosition, formal_parameters, kind, @@ -5472,6 +5437,9 @@ void ParserBase<Impl>::ParseClassLiteralBody(ClassInfo& class_info, impl()->InferFunctionName(); } + if (end_token == Token::kRightBrace) { + CheckStrictOctalLiteral(scope()->start_position(), peek_end_position()); + } Expect(end_token); scope()->set_end_position(end_position()); } @@ -5486,9 +5454,6 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral() { // async [no LineTerminator here] function BindingIdentifier[Await] // ( FormalParameters[Await] ) { AsyncFunctionBody } DCHECK_EQ(scanner()->current_token(), Token::kAsync); - if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { - impl()->ReportUnexpectedToken(Token::kEscapedKeyword); - } int pos = position(); Consume(Token::kFunction); IdentifierT name = impl()->NullIdentifier(); @@ -5573,8 +5538,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral( next = peek(); int expr_pos = peek_position(); - AcceptINScope scope(this, true); - ExpressionT expression = ParseExpressionCoverGrammar(); + ExpressionT expression = ParseExpression(); arguments_count++; if (tagged && arguments_count + 1 /* receiver */ > Code::kMaxArguments) { @@ -5622,17 +5586,14 @@ ParserBase<Impl>::RewriteInvalidReferenceExpression(ExpressionT expression, return impl()->FailureExpression(); } if (expression->IsCall() && !expression->AsCall()->is_tagged_template() && - !early_error) { + !early_error && is_sloppy(language_mode())) { expression_scope()->RecordPatternError( Scanner::Location(beg_pos, end_pos), MessageTemplate::kInvalidDestructuringTarget); // If it is a call, make it a runtime error for legacy web compatibility. // Bug: https://bugs.chromium.org/p/v8/issues/detail?id=4480 // Rewrite `expr' to `expr[throw ReferenceError]'. - impl()->CountUsage( - is_strict(language_mode()) - ? v8::Isolate::kAssigmentExpressionLHSIsCallInStrict - : v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy); + impl()->CountUsage(v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy); ExpressionT error = impl()->NewThrowReferenceError(message, beg_pos); return factory()->NewProperty(expression, error, beg_pos); } @@ -5656,14 +5617,17 @@ template <typename Impl> void ParserBase<Impl>::ClassifyArrowParameter( AccumulationScope* accumulation_scope, int position, ExpressionT parameter) { - accumulation_scope->Accumulate(); if (parameter->is_parenthesized() || !(impl()->IsIdentifier(parameter) || parameter->IsPattern() || parameter->IsAssignment())) { + accumulation_scope->ValidateExpression(); expression_scope()->RecordDeclarationError( Scanner::Location(position, end_position()), MessageTemplate::kInvalidDestructuringTarget); - } else if (impl()->IsIdentifier(parameter)) { + return; + } + accumulation_scope->Accumulate(); + if (impl()->IsIdentifier(parameter)) { ClassifyParameter(impl()->AsIdentifier(parameter), position, end_position()); } else { @@ -5682,30 +5646,36 @@ ParserBase<Impl>::ParsePossibleDestructuringSubPattern( AccumulationScope* scope) { if (scope) scope->Accumulate(); int begin = peek_position(); + AcceptINScope accept_in_scope(this, true); + int variable_index = expression_scope()->variable_list_length(); ExpressionT result = ParseAssignmentExpressionCoverGrammar(); - if (IsValidReferenceExpression(result)) { - // Parenthesized identifiers and property references are allowed as part of - // a larger assignment pattern, even though parenthesized patterns - // themselves are not allowed, e.g., "[(x)] = []". Only accumulate - // assignment pattern errors if the parsed expression is more complex. - if (impl()->IsIdentifier(result)) { - if (result->is_parenthesized()) { - expression_scope()->RecordDeclarationError( - Scanner::Location(begin, end_position()), - MessageTemplate::kInvalidDestructuringTarget); - } - IdentifierT identifier = impl()->AsIdentifier(result); - ClassifyParameter(identifier, begin, end_position()); - } else { - DCHECK(result->IsProperty()); + // Parenthesized identifiers and property references are allowed as part of + // a larger assignment pattern, even though parenthesized patterns + // themselves are not allowed, e.g., "[(x)] = []". Only accumulate + // assignment pattern errors if the parsed expression is more complex. + if (impl()->IsIdentifier(result)) { + if (result->is_parenthesized()) { expression_scope()->RecordDeclarationError( Scanner::Location(begin, end_position()), - MessageTemplate::kInvalidPropertyBindingPattern); - if (scope != nullptr) scope->ValidateExpression(); + MessageTemplate::kInvalidDestructuringTarget); } + if (!IsAssignableIdentifier(result)) { + expression_scope()->RecordPatternError( + Scanner::Location(begin, end_position()), + MessageTemplate::kStrictEvalArguments); + } + IdentifierT identifier = impl()->AsIdentifier(result); + ClassifyParameter(identifier, begin, end_position()); + } else if (result->IsProperty()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(begin, end_position()), + MessageTemplate::kInvalidPropertyBindingPattern); + if (scope != nullptr) scope->ValidateExpression(); + expression_scope()->DiscardVariablesSince(variable_index); } else if (result->is_parenthesized() || (!result->IsPattern() && !result->IsAssignment())) { + if (scope != nullptr) scope->ValidateExpression(); expression_scope()->RecordPatternError( Scanner::Location(begin, end_position()), MessageTemplate::kInvalidDestructuringTarget); @@ -6454,7 +6424,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement( { BlockState cases_block_state(zone(), &scope_); - scope()->set_start_position(switch_pos); + scope()->set_start_position(peek_position()); scope()->SetNonlinear(); Target target(this, switch_statement, labels, nullptr, Target::TARGET_FOR_ANONYMOUS); @@ -6740,8 +6710,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( expression = ParseExpressionCoverGrammar(); // `for (async of` is disallowed but `for (async.x of` is allowed, so // check if the token is kAsync after parsing the expression. - bool expression_is_async = scanner()->current_token() == Token::kAsync && - !scanner()->literal_contains_escapes(); + bool expression_is_async = impl()->IsIdentifier(expression) && + scanner()->current_token() == Token::kAsync; // Initializer is reference followed by in/of. lhs_end_pos = end_position(); is_for_each = CheckInOrOf(&for_info.mode); @@ -6823,7 +6793,6 @@ ParserBase<Impl>::ParseForEachStatementWithDeclarations( BlockState block_state(&scope_, enumerable_block_scope); if (for_info->mode == ForEachStatement::ITERATE) { - AcceptINScope scope(this, true); enumerable = ParseAssignmentExpression(); } else { enumerable = ParseExpression(); @@ -6885,7 +6854,6 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { - AcceptINScope scope(this, true); enumerable = ParseAssignmentExpression(); } else { enumerable = ParseExpression(); @@ -6912,31 +6880,41 @@ ParserBase<Impl>::ParseStandardForLoopWithLexicalDeclarations( ZonePtrList<const AstRawString>* labels, ZonePtrList<const AstRawString>* own_labels) { // The condition and the next statement of the for loop must be parsed - // in a new scope. - Scope* inner_scope = NewScope(BLOCK_SCOPE); + // in a new scope when desugaring per-iteration let bindings. + const bool is_let_with_bound_names = + for_info->parsing_result.descriptor.mode == VariableMode::kLet && + for_info->bound_names.length() > 0; + Scope* inner_scope = nullptr; ForStatementT loop = impl()->NullStatement(); ExpressionT cond = impl()->NullExpression(); StatementT next = impl()->NullStatement(); StatementT body = impl()->NullStatement(); { - BlockState block_state(&scope_, inner_scope); - scope()->set_start_position(scanner()->location().beg_pos); + std::optional<BlockState> block_state; + if (is_let_with_bound_names) { + inner_scope = NewScope(BLOCK_SCOPE); + block_state.emplace(&scope_, inner_scope); + scope()->set_start_position(scanner()->location().beg_pos); + } loop = ParseStandardForLoop(stmt_pos, labels, own_labels, &cond, &next, &body); RETURN_IF_PARSE_ERROR; - scope()->set_end_position(end_position()); + if (is_let_with_bound_names) { + scope()->set_end_position(end_position()); + } } scope()->set_end_position(end_position()); - if (for_info->bound_names.length() > 0 && - function_state_->contains_function_or_eval()) { - scope()->set_is_hidden(); - return impl()->DesugarLexicalBindingsInForStatement( - loop, init, cond, next, body, inner_scope, *for_info); - } else { - inner_scope = inner_scope->FinalizeBlockScope(); - DCHECK_NULL(inner_scope); - USE(inner_scope); + if (is_let_with_bound_names) { + if (function_state_->contains_function_or_eval()) { + scope()->set_is_hidden(); + return impl()->DesugarLetBindingsInForStatement( + loop, init, cond, next, body, inner_scope, *for_info); + } else { + inner_scope = inner_scope->FinalizeBlockScope(); + DCHECK_NULL(inner_scope); + USE(inner_scope); + } } Scope* for_scope = scope()->FinalizeBlockScope(); @@ -7011,6 +6989,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( BlockState for_state(zone(), &scope_); Expect(Token::kFor); Expect(Token::kAwait); + if (V8_UNLIKELY(scanner()->literal_contains_escapes())) { + impl()->ReportUnexpectedToken(Token::kEscapedKeyword); + return impl()->NullStatement(); + } Expect(Token::kLeftParen); scope()->set_start_position(position()); scope()->set_is_hidden(); @@ -7084,9 +7066,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( } } - ExpectContextualKeyword(Token::kOf); + Expect(Token::kOf); - const bool kAllowIn = true; ExpressionT iterable = impl()->NullExpression(); Scope* iterable_block_scope = NewScope(BLOCK_SCOPE); iterable_block_scope->set_start_position(position()); @@ -7094,7 +7075,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForAwaitStatement( { BlockState block_state(&scope_, iterable_block_scope); - AcceptINScope scope(this, kAllowIn); iterable = ParseAssignmentExpression(); } iterable_block_scope->set_end_position(end_position()); diff --git a/deps/v8/src/parsing/parser.cc b/deps/v8/src/parsing/parser.cc index 388e4f1c96e7..0b44c114386d 100644 --- a/deps/v8/src/parsing/parser.cc +++ b/deps/v8/src/parsing/parser.cc @@ -20,6 +20,7 @@ #include "src/common/message-template.h" #include "src/common/scoped-modification.h" #include "src/compiler-dispatcher/lazy-compile-dispatcher.h" +#include "src/heap/factory-inl.h" #include "src/heap/local-heap-inl.h" #include "src/heap/parked-scope.h" #include "src/logging/counters.h" @@ -93,8 +94,8 @@ FunctionLiteral* Parser::MakeAutoAccessorGetter(VariableProxy* name_proxy, bool is_static, int pos) { ScopedPtrList<Statement> body(pointer_buffer()); DeclarationScope* function_scope = - NewFunctionScope(is_static ? FunctionKind::kGetterFunction - : FunctionKind::kStaticGetterFunction); + NewFunctionScope(is_static ? FunctionKind::kStaticGetterFunction + : FunctionKind::kGetterFunction); SetLanguageMode(function_scope, LanguageMode::kStrict); function_scope->set_start_position(pos); function_scope->set_end_position(pos); @@ -121,8 +122,8 @@ FunctionLiteral* Parser::MakeAutoAccessorSetter(VariableProxy* name_proxy, bool is_static, int pos) { ScopedPtrList<Statement> body(pointer_buffer()); DeclarationScope* function_scope = - NewFunctionScope(is_static ? FunctionKind::kSetterFunction - : FunctionKind::kStaticSetterFunction); + NewFunctionScope(is_static ? FunctionKind::kStaticSetterFunction + : FunctionKind::kSetterFunction); SetLanguageMode(function_scope, LanguageMode::kStrict); function_scope->set_start_position(pos); function_scope->set_end_position(pos); @@ -209,11 +210,13 @@ void Parser::ReportUnexpectedTokenAt(Scanner::Location location, case Token::kStatic: case Token::kYield: case Token::kFutureStrictReservedWord: - message = is_strict(language_mode()) - ? MessageTemplate::kUnexpectedStrictReserved - : MessageTemplate::kUnexpectedTokenIdentifier; - arg = Token::String(token); - break; + if (is_strict(language_mode())) { + message = MessageTemplate::kUnexpectedStrictReserved; + break; + } + ReportMessageAt(location, MessageTemplate::kUnexpectedTokenIdentifier, + GetIdentifier()); + return; case Token::kTemplateSpan: case Token::kTemplateTail: message = MessageTemplate::kUnexpectedTemplateString; @@ -454,11 +457,9 @@ Expression* Parser::BuildUnaryExpression(Expression* expression, } Expression* Parser::NewThrowError(Runtime::FunctionId id, - MessageTemplate message, - const AstRawString* arg, int pos) { + MessageTemplate message, int pos) { ScopedPtrList<Expression> args(pointer_buffer()); args.Add(factory()->NewSmiLiteral(static_cast<int>(message), pos)); - args.Add(factory()->NewStringLiteral(arg, pos)); CallRuntime* call_constructor = factory()->NewCallRuntime(id, args, pos); return factory()->NewThrow(call_constructor, pos); } @@ -520,6 +521,7 @@ Expression* Parser::ExpressionFromLiteral(Token::Value token, int pos) { return factory()->NewNumberLiteral(value, pos); } case Token::kBigInt: + CountUsage(v8::Isolate::kBigInt); return factory()->NewBigIntLiteral( AstBigInt(scanner()->CurrentLiteralAsCString(zone())), pos); case Token::kString: { @@ -744,12 +746,20 @@ void Parser::ParseProgram(Isolate* isolate, DirectHandle<Script> script, } scanner_.Initialize(); + std::optional<ClassScope::HeritageParsingScope> heritage; + if (V8_UNLIKELY(flags().private_name_lookup_skips_outer_class() && + original_scope_->is_class_scope())) { + heritage.emplace(original_scope_->AsClassScope()); + } FunctionLiteral* result = DoParseProgram(isolate, info, script->eval_from_position()); if (flags().allow_heap_allocation()) { HandleDebugMagicComments(isolate, script); } if (result == nullptr) return; + if (V8_UNLIKELY(flags().private_name_lookup_skips_outer_class())) { + result->scope()->RecordNeedsPrivateNameContextChainRecalc(); + } result->scope()->set_is_hoisted_in_context( info->flags().is_hoisted_in_context()); if (flags().allow_heap_allocation()) { @@ -859,6 +869,11 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info, info->ast_value_factory()->Internalize(isolate); } CheckConflictingVarDeclarations(scope); + if (flags().is_eval() && !has_error() && + scope->HasConflictingArgumentsVarDeclaration(ast_value_factory())) { + ReportVarRedeclarationIn(ast_value_factory()->arguments_string(), + scope); + } } // For sloppy eval though, we clear dynamic variables created for toplevel @@ -1204,7 +1219,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, // Parsing patterns as variable reference expression creates // NewUnresolved references in current scope. Enter arrow function // scope for formal parameter parsing. - BlockState inner_block_state(&scope_, scope); + FunctionState inner_function_state(&function_state_, &scope_, scope); if (Check(Token::kLeftParen)) { // '(' StrictFormalParameters ')' ParseFormalParameterList(&formals); @@ -1252,6 +1267,9 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, } if (has_error()) return nullptr; + if (V8_UNLIKELY(flags().private_name_lookup_skips_outer_class())) { + result->scope()->RecordNeedsPrivateNameContextChainRecalc(); + } result->set_requires_instance_members_initializer( flags().requires_instance_members_initializer()); result->set_class_scope_has_private_brand( @@ -1290,7 +1308,8 @@ FunctionLiteral* Parser::ParseClassForMemberInitialization( // We preparse the class members that are not fields with initializers // in order to collect the function literal ids. - ScopedModification<Mode> mode_scope(&mode_, PARSE_LAZILY); + ScopedModification<Mode> mode_scope( + &mode_, allow_lazy_ ? PARSE_LAZILY : PARSE_EAGERLY); ExpressionParsingScope no_expression_scope(impl()); @@ -1375,7 +1394,6 @@ FunctionLiteral* Parser::ParseClassForMemberInitialization( DCHECK_EQ(class_info.static_elements_function_id, initializer_id); initializer = CreateStaticElementsInitializer(class_name, &class_info); } - initializer->scope()->TakeUnresolvedReferencesFromParent(); } if (has_error()) return nullptr; @@ -1443,7 +1461,7 @@ const AstRawString* Parser::ParseModuleSpecifier() { return GetSymbol(); } -ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause( +SmallZoneVector<Parser::ExportClauseData, 8> Parser::ParseExportClause( Scanner::Location* reserved_loc, Scanner::Location* string_literal_local_name_loc) { // ExportClause : @@ -1464,8 +1482,7 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause( // // ModuleExportName : // StringLiteral - ZoneChunkList<ExportClauseData>* export_data = - zone()->New<ZoneChunkList<ExportClauseData>>(zone()); + SmallZoneVector<ExportClauseData, 8> export_data(zone()); Expect(Token::kLeftBrace); @@ -1494,7 +1511,7 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause( } else { export_name = local_name; } - export_data->push_back({export_name, local_name, location}); + export_data.push_back({export_name, local_name, location}); if (peek() == Token::kRightBrace) break; if (V8_UNLIKELY(!Check(Token::kComma))) { ReportUnexpectedToken(Next()); @@ -1682,7 +1699,7 @@ void Parser::ParseImportDeclaration() { if (tok != Token::kMul && tok != Token::kLeftBrace) { if (v8_flags.js_source_phase_imports && PeekContextualKeyword(ast_value_factory()->source_string()) && - PeekAhead() == Token::kIdentifier && + Token::IsAnyIdentifier(PeekAhead()) && PeekAheadAhead() == Token::kIdentifier) { Consume(Token::kIdentifier); import_phase = ModuleImportPhase::kSource; @@ -1824,7 +1841,6 @@ Statement* Parser::ParseExportDefault() { default: { int pos = position(); - AcceptINScope scope(this, true); Expression* value = ParseAssignmentExpression(); SetFunctionName(value, ast_value_factory()->default_string()); @@ -1968,7 +1984,7 @@ Statement* Parser::ParseExportDeclaration() { Scanner::Location reserved_loc = Scanner::Location::invalid(); Scanner::Location string_literal_local_name_loc = Scanner::Location::invalid(); - ZoneChunkList<ExportClauseData>* export_data = + SmallZoneVector<ExportClauseData, 8> export_data = ParseExportClause(&reserved_loc, &string_literal_local_name_loc); if (CheckContextualKeyword(ast_value_factory()->from_string())) { Scanner::Location specifier_loc = scanner()->peek_location(); @@ -1977,11 +1993,11 @@ Statement* Parser::ParseExportDeclaration() { ParseImportWithOrAssertClause(); ExpectSemicolon(); - if (export_data->empty()) { + if (export_data.empty()) { module()->AddEmptyImport(module_specifier, import_attributes, specifier_loc, zone()); } else { - for (const ExportClauseData& data : *export_data) { + for (const ExportClauseData& data : export_data) { module()->AddExport(data.local_name, data.export_name, module_specifier, import_attributes, data.location, specifier_loc, zone()); @@ -2000,7 +2016,7 @@ Statement* Parser::ParseExportDeclaration() { ExpectSemicolon(); - for (const ExportClauseData& data : *export_data) { + for (const ExportClauseData& data : export_data) { module()->AddExport(data.local_name, data.export_name, data.location, zone()); } @@ -2212,7 +2228,7 @@ Statement* Parser::RewriteSwitchStatement(SwitchStatement* switch_statement, // } DCHECK_NOT_NULL(scope); DCHECK(scope->is_block_scope()); - DCHECK_GE(switch_statement->position(), scope->start_position()); + DCHECK_LT(switch_statement->position(), scope->start_position()); DCHECK_LT(switch_statement->position(), scope->end_position()); Block* switch_block = factory()->NewBlock(2, false); @@ -2369,6 +2385,7 @@ Block* Parser::RewriteForVarInLegacy(const ForInfo& for_info) { ++use_counts_[v8::Isolate::kForInInitializer]; const AstRawString* name = decl.pattern->AsVariableProxy()->raw_name(); VariableProxy* single_var = NewUnresolved(name); + single_var->set_is_assigned(); Block* init_block = factory()->NewBlock(2, true); init_block->statements()->Add( factory()->NewExpressionStatement( @@ -2434,7 +2451,7 @@ Block* Parser::CreateForEachStatementTDZ(Block* init_block, return init_block; } -Statement* Parser::DesugarLexicalBindingsInForStatement( +Statement* Parser::DesugarLetBindingsInForStatement( ForStatement* loop, Statement* init, Expression* cond, Statement* next, Statement* body, Scope* inner_scope, const ForInfo& for_info) { // ES6 13.7.4.8 specifies that on each loop iteration the let variables are @@ -2445,18 +2462,18 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // // We are given a for statement of the form // - // labels: for (let/const x = i; cond; next) body + // labels: for (let x = i; cond; next) body // // and rewrite it as follows. Here we write {{ ... }} for init-blocks, ie., // blocks whose ignore_completion_value_ flag is set. // // { - // let/const x = i; + // let x = i; // temp_x = x; // first = 1; // undefined; // outer: for (;;) { - // let/const x = temp_x; + // let x = temp_x; // {{ if (first == 1) { // first = 0; // } else { @@ -2475,17 +2492,18 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( // } DCHECK_GT(for_info.bound_names.length(), 0); + DCHECK_EQ(for_info.parsing_result.descriptor.mode, VariableMode::kLet); ScopedPtrList<Variable> temps(pointer_buffer()); Block* outer_block = factory()->NewBlock(for_info.bound_names.length() + 4, false); - // Add statement: let/const x = i. + // Add statement: let x = i. outer_block->statements()->Add(init, zone()); const AstRawString* temp_name = ast_value_factory()->dot_for_string(); - // For each lexical variable x: + // For each let variable x: // make statement: temp_x = x. for (const AstRawString* bound_name : for_info.bound_names) { VariableProxy* proxy = NewUnresolved(bound_name); @@ -2535,14 +2553,10 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( factory()->NewBlock(for_info.bound_names.length() + 3, true); ScopedPtrList<Variable> inner_vars(pointer_buffer()); // For each let variable x: - // make statement: let/const x = temp_x. + // make statement: let x = temp_x. for (int i = 0; i < for_info.bound_names.length(); i++) { VariableProxy* proxy = DeclareBoundVariable( - for_info.bound_names[i], - IsResourceManagedVariableMode(for_info.parsing_result.descriptor.mode) - ? VariableMode::kConst - : for_info.parsing_result.descriptor.mode, - kNoSourcePosition); + for_info.bound_names[i], VariableMode::kLet, kNoSourcePosition); inner_vars.Add(proxy->var()); VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i)); Assignment* assignment = factory()->NewAssignment( @@ -2949,7 +2963,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral( DeclarationScope* scope = NewFunctionScope(kind, parse_zone); SetLanguageMode(scope, language_mode); if (function_syntax_kind == FunctionSyntaxKind::kDeclaration) { - if (flags().is_reparse()) { + if (flags().is_reparse() && !flags().is_toplevel() && + scope->outer_scope() == original_scope_) { scope->set_is_hoisted_in_context(flags().is_hoisted_in_context()); } else { scope->set_is_hoisted_in_context(true); @@ -2988,6 +3003,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral( &num_parameters, &function_length, &has_duplicate_parameters, &expected_property_count, &suspend_count, arguments_for_wrapped_function); + if (should_preparse) { + CHECK(has_error()); + return nullptr; + } } if (V8_UNLIKELY(v8_flags.log_function_events)) { @@ -3273,7 +3292,6 @@ void Parser::ParseFunction( *num_parameters = formals.num_parameters(); *function_length = formals.function_length; - AcceptINScope scope(this, true); ParseFunctionBody(body, function_name, pos, formals, kind, function_syntax_kind, FunctionBodyType::kBlock); @@ -3549,6 +3567,7 @@ void Parser::InsertShadowingVarBindingInitializers(Block* inner_block) { } const AstRawString* name = decl.first->raw_name(); VariableProxy* to = NewUnresolved(name); + to->set_is_assigned(); VariableProxy* from = factory()->NewVariableProxy(decl.second); Expression* assignment = factory()->NewAssignment(Token::kAssign, to, from, kNoSourcePosition); @@ -3572,32 +3591,50 @@ void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) { // ---------------------------------------------------------------------------- // Parser support -template <typename IsolateT> -void Parser::HandleDebugMagicComments(IsolateT* isolate, +void Parser::HandleDebugMagicComments(Isolate* isolate, DirectHandle<Script> script) { - DirectHandle<String> source_url = scanner_.SourceUrl(isolate); - if (!source_url.is_null()) { + // On the main thread, the scanned source is the script source. + DirectHandle<String> source(Cast<String>(script->source()), isolate); + SetDebugMagicCommentFields(isolate, script, source, + scanner_.debug_magic_comment_locations()); +} + +// static +void Parser::SetDebugMagicCommentFields( + Isolate* isolate, DirectHandle<Script> script, DirectHandle<String> source, + const Scanner::DebugMagicCommentLocations& locations) { + source = String::Flatten(isolate, source); + auto is_valid = [&](Scanner::Location location) { + return location.IsValid() && location.length() != 0 && + static_cast<uint32_t>(location.end_pos) <= source->length(); + }; + if (is_valid(locations.source_url)) { + // The source URL is used as the script name (e.g. in stack traces, + // profiles and heap snapshots), so it is a sequential copy rather than a + // substring of the source. + DirectHandle<String> source_url = isolate->factory()->NewCopiedSubstring( + source, locations.source_url.beg_pos, locations.source_url.length()); script->set_source_url(*source_url); } - DirectHandle<String> source_mapping_url = scanner_.SourceMappingUrl(isolate); // The API can provide a source map URL and the API should take precedence. // Let's make sure we do not override the API with the magic comment. - if (!source_mapping_url.is_null() && - IsUndefined(script->source_mapping_url())) { + if (IsUndefined(script->source_mapping_url()) && + is_valid(locations.source_mapping_url)) { + // The source map URL can be arbitrarily large (e.g. an inline source map), + // so it is a substring of the source rather than a copy. + DirectHandle<String> source_mapping_url = isolate->factory()->NewSubString( + source, locations.source_mapping_url.beg_pos, + locations.source_mapping_url.end_pos); script->set_source_mapping_url(*source_mapping_url); } - - DirectHandle<String> debug_id = scanner_.DebugId(isolate); - if (!debug_id.is_null()) { + if (is_valid(locations.debug_id)) { + // Debug IDs are short, so they are copied like the source URL. + DirectHandle<String> debug_id = isolate->factory()->NewCopiedSubstring( + source, locations.debug_id.beg_pos, locations.debug_id.length()); script->set_debug_id(*debug_id); } } -template void Parser::HandleDebugMagicComments(Isolate* isolate, - DirectHandle<Script> script); -template void Parser::HandleDebugMagicComments(LocalIsolate* isolate, - DirectHandle<Script> script); - void Parser::UpdateStatistics(Isolate* isolate, DirectHandle<Script> script) { CHECK_NOT_NULL(isolate); @@ -3697,12 +3734,11 @@ void Parser::ParseOnBackground(LocalIsolate* isolate, ParseInfo* info, info->function_name()); } if (result == nullptr) return; + result->scope()->set_is_hoisted_in_context( + info->flags().is_hoisted_in_context()); MaybeProcessSourceRanges(info, result, stack_limit_); }); // We need to unpark by now though, to be able to internalize. - if (flags().is_toplevel()) { - HandleDebugMagicComments(isolate, script); - } if (result == nullptr) return; PostProcessParseResult(isolate, info, result); } diff --git a/deps/v8/src/parsing/parser.h b/deps/v8/src/parsing/parser.h index 5226a2ccea66..f6c42cdebdba 100644 --- a/deps/v8/src/parsing/parser.h +++ b/deps/v8/src/parsing/parser.h @@ -22,7 +22,6 @@ #include "src/parsing/parser-base.h" #include "src/parsing/parsing.h" #include "src/parsing/preparser.h" -#include "src/zone/zone-chunk-list.h" namespace v8 { @@ -79,6 +78,7 @@ struct ParserFormalParameters : FormalParametersBase { void set_strict_parameter_error(const Scanner::Location& loc, MessageTemplate message) { + if (strict_error_loc.IsValid()) return; strict_error_loc = loc; strict_error_message = message; } @@ -170,8 +170,19 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { DirectHandle<Script> script, base::SmallVector<v8::Isolate::UseCounterFeature, 8>* use_counters, int* preparse_skipped); - template <typename IsolateT> - void HandleDebugMagicComments(IsolateT* isolate, DirectHandle<Script> script); + void HandleDebugMagicComments(Isolate* isolate, DirectHandle<Script> script); + const Scanner::DebugMagicCommentLocations& debug_magic_comment_locations() + const { + return scanner_.debug_magic_comment_locations(); + } + // Sets the debug magic comment fields of {script} to the values in {source} + // at the given locations: the source map URL is a substring of {source}, the + // source URL and debug ID are sequential copies. Locations that are empty, + // invalid or out of bounds are ignored. + static void SetDebugMagicCommentFields( + Isolate* isolate, DirectHandle<Script> script, + DirectHandle<String> source, + const Scanner::DebugMagicCommentLocations& locations); private: friend class ParserBase<Parser>; @@ -258,6 +269,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { pending_error_handler(), runtime_call_stats_, v8_file_logger_, flags(), parsing_on_main_thread_); reusable_preparser_->set_allow_eval_cache(allow_eval_cache()); + if (has_module_in_scope_chain()) { + reusable_preparser_->set_has_module_in_scope_chain(); + } preparse_data_buffer_.reserve(128); } return reusable_preparser_; @@ -275,7 +289,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { const AstRawString* local_name; Scanner::Location location; }; - ZoneChunkList<ExportClauseData>* ParseExportClause( + SmallZoneVector<ExportClauseData, 8> ParseExportClause( Scanner::Location* reserved_loc, Scanner::Location* string_literal_local_name_loc); struct NamedImport : public ZoneObject { @@ -383,7 +397,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { Expression** each_variable); Block* CreateForEachStatementTDZ(Block* init_block, const ForInfo& for_info); - Statement* DesugarLexicalBindingsInForStatement( + Statement* DesugarLetBindingsInForStatement( ForStatement* loop, Statement* init, Expression* cond, Statement* next, Statement* body, Scope* inner_scope, const ForInfo& for_info); @@ -529,8 +543,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // Generic AST generator for throwing errors from compiled code. Expression* NewThrowError(Runtime::FunctionId function_id, - MessageTemplate message, const AstRawString* arg, - int pos); + MessageTemplate message, int pos); void AddArrowFunctionFormalParameters(ParserFormalParameters* parameters, Expression* params, int end_pos); @@ -660,16 +673,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { V8_INLINE void InferFunctionName() { fni_.Infer(); } - // If we assign a function literal to a property we pretenure the - // literal so it can be added as a constant function property. - V8_INLINE static void CheckAssigningFunctionLiteralToProperty( - Expression* left, Expression* right) { - DCHECK_NOT_NULL(left); - if (left->IsProperty() && right->IsFunctionLiteral()) { - right->AsFunctionLiteral()->set_pretenure(); - } - } - // Returns true if we have a binary expression between two literals. In that // case, *x will be changed to an expression which is the computed value. bool ShortcutLiteralBinaryExpression(Expression** x, Expression* y, @@ -704,8 +707,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { // Generate AST node that throws a ReferenceError with the given type. V8_INLINE Expression* NewThrowReferenceError(MessageTemplate message, int pos) { - return NewThrowError(Runtime::kNewReferenceError, message, - ast_value_factory()->empty_string(), pos); + return NewThrowError(Runtime::kNewReferenceError, message, pos); } // Dummy implementation. The parser should never have a unidentifiable diff --git a/deps/v8/src/parsing/pending-compilation-error-handler.cc b/deps/v8/src/parsing/pending-compilation-error-handler.cc index f8b65ad6e0b7..5dc16bf3024b 100644 --- a/deps/v8/src/parsing/pending-compilation-error-handler.cc +++ b/deps/v8/src/parsing/pending-compilation-error-handler.cc @@ -64,8 +64,7 @@ DirectHandle<String> PendingCompilationErrorHandler::MessageDetails::ArgString( return Handle<String>::null(); case kConstCharString: return isolate->factory() - ->NewStringFromUtf8(base::CStrVector(args_[index].c_string), - AllocationType::kOld) + ->NewStringFromUtf8(args_[index].c_string, AllocationType::kOld) .ToHandleChecked(); case kAstRawString: UNREACHABLE(); diff --git a/deps/v8/src/parsing/preparse-data.cc b/deps/v8/src/parsing/preparse-data.cc index 451f557198ec..1397ddde6dfd 100644 --- a/deps/v8/src/parsing/preparse-data.cc +++ b/deps/v8/src/parsing/preparse-data.cc @@ -595,7 +595,7 @@ BaseConsumedPreparseData<Data>::GetDataForSkippableFunction( int start_position_from_data = scope_data_->ReadVarint32(); CHECK_EQ(start_position, start_position_from_data); *end_position = scope_data_->ReadVarint32(); - DCHECK_GT(*end_position, start_position); + CHECK_GT(*end_position, start_position); uint32_t has_data_and_num_parameters = scope_data_->ReadVarint32(); bool has_data = HasDataField::decode(has_data_and_num_parameters); diff --git a/deps/v8/src/parsing/preparse-data.h b/deps/v8/src/parsing/preparse-data.h index b419bb3c0f10..ae89656903a3 100644 --- a/deps/v8/src/parsing/preparse-data.h +++ b/deps/v8/src/parsing/preparse-data.h @@ -12,7 +12,6 @@ #include "src/handles/handles.h" #include "src/handles/maybe-handles.h" #include "src/utils/scoped-list.h" -#include "src/zone/zone-chunk-list.h" #include "src/zone/zone-containers.h" namespace v8 { diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc index 997657fba13e..95990fba0085 100644 --- a/deps/v8/src/parsing/preparser.cc +++ b/deps/v8/src/parsing/preparser.cc @@ -161,20 +161,21 @@ PreParser::PreParseResult PreParser::PreParseFunction( bool allow_duplicate_parameters = false; CheckConflictingVarDeclarations(inner_scope); - if (!has_error()) { - if (formals.is_simple) { - if (is_sloppy(function_scope->language_mode())) { - function_scope->HoistSloppyBlockFunctions(nullptr); - } + if (formals.is_simple) { + if (!has_error() && is_sloppy(function_scope->language_mode())) { + function_scope->HoistSloppyBlockFunctions(nullptr); + } + + allow_duplicate_parameters = + is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind); + } else { + SetLanguageMode(function_scope, inner_scope->language_mode()); - allow_duplicate_parameters = - is_sloppy(function_scope->language_mode()) && !IsConciseMethod(kind); - } else { + if (!has_error()) { if (is_sloppy(inner_scope->language_mode())) { inner_scope->HoistSloppyBlockFunctions(nullptr); } - SetLanguageMode(function_scope, inner_scope->language_mode()); inner_scope->set_end_position(scanner()->peek_location().end_pos); if (inner_scope->FinalizeBlockScope() != nullptr) { const AstRawString* conflict = inner_scope->FindVariableDeclaredIn( @@ -190,7 +191,14 @@ PreParser::PreParseResult PreParser::PreParseFunction( if (stack_overflow()) { return kPreParseStackOverflow; - } else if (pending_error_handler()->has_error_unidentifiable_by_preparser()) { + } + if (!IsArrowFunction(kind)) { + // Validate parameter names. We can do this only after parsing the + // function, since the function can declare itself strict. + ValidateFormalParameters(language_mode(), formals, + allow_duplicate_parameters); + } + if (pending_error_handler()->has_error_unidentifiable_by_preparser()) { return kPreParseNotIdentifiableError; } else if (has_error()) { DCHECK(pending_error_handler()->has_pending_error()); @@ -198,18 +206,6 @@ PreParser::PreParseResult PreParser::PreParseFunction( DCHECK_EQ(Token::kRightBrace, scanner()->peek()); if (!IsArrowFunction(kind)) { - // Validate parameter names. We can do this only after parsing the - // function, since the function can declare itself strict. - ValidateFormalParameters(language_mode(), formals, - allow_duplicate_parameters); - if (has_error()) { - if (pending_error_handler()->has_error_unidentifiable_by_preparser()) { - return kPreParseNotIdentifiableError; - } else { - return kPreParseSuccess; - } - } - // Declare arguments after parsing the function since lexical // 'arguments' masks the arguments object. Declare arguments before // declaring the function var since the arguments object masks 'function @@ -228,11 +224,11 @@ PreParser::PreParseResult PreParser::PreParseFunction( if (pending_error_handler()->has_error_unidentifiable_by_preparser()) { return kPreParseNotIdentifiableError; } + } - if (is_strict(function_scope->language_mode())) { - int end_pos = scanner()->location().end_pos; - CheckStrictOctalLiteral(function_scope->start_position(), end_pos); - } + if (is_strict(function_scope->language_mode())) { + int end_pos = scanner()->location().end_pos; + CheckStrictOctalLiteral(function_scope->start_position(), end_pos); } DCHECK(!pending_error_handler()->has_error_unidentifiable_by_preparser()); @@ -312,7 +308,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral( PreParserScopedStatementList body(pointer_buffer()); int pos = function_token_pos == kNoSourcePosition ? peek_position() : function_token_pos; - AcceptINScope scope(this, true); ParseFunctionBody(&body, function_name, pos, formals, kind, function_syntax_kind, FunctionBodyType::kBlock); @@ -374,23 +369,6 @@ PreParserBlock PreParser::BuildParameterInitializationBlock( const PreParserFormalParameters& parameters) { DCHECK(!parameters.is_simple); DCHECK(scope()->is_function_scope()); - if (scope()->AsDeclarationScope()->sloppy_eval_can_extend_vars() && - preparse_data_builder_ != nullptr) { - // We cannot replicate the Scope structure constructed by the Parser, - // because we've lost information whether each individual parameter was - // simple or not. Give up trying to produce data to skip inner functions. - if (preparse_data_builder_->parent() != nullptr) { - // Lazy parsing started before the current function; the function which - // cannot contain skippable functions is the parent function. (Its inner - // functions cannot either; they are implicitly bailed out.) - preparse_data_builder_->parent()->Bailout(); - } else { - // Lazy parsing started at the current function; it cannot contain - // skippable functions. - preparse_data_builder_->Bailout(); - } - } - return PreParserBlock::Default(); } diff --git a/deps/v8/src/parsing/preparser.h b/deps/v8/src/parsing/preparser.h index beef2b93234e..fc6d80037957 100644 --- a/deps/v8/src/parsing/preparser.h +++ b/deps/v8/src/parsing/preparser.h @@ -90,7 +90,8 @@ class PreParserExpression { } static PreParserExpression Default() { - return PreParserExpression(TypeField::encode(kExpression)); + return PreParserExpression(TypeField::encode(kExpression) | + ExpressionTypeField::encode(kDefaultExpression)); } static PreParserExpression FromIdentifier(const PreParserIdentifier& id) { @@ -146,6 +147,12 @@ class PreParserExpression { ExpressionTypeField::encode(kPrivateReferenceExpression)); } + static PreParserExpression OptionalChainPrivateReference() { + return PreParserExpression( + TypeField::encode(kExpression) | + ExpressionTypeField::encode(kOptionalChainPrivateReferenceExpression)); + } + static PreParserExpression Call() { return PreParserExpression(TypeField::encode(kExpression) | ExpressionTypeField::encode(kCallExpression)); @@ -221,7 +228,9 @@ class PreParserExpression { return TypeField::decode(code_) == kExpression && (ExpressionTypeField::decode(code_) == kPrivateReferenceExpression || ExpressionTypeField::decode(code_) == - kThisPrivateReferenceExpression); + kThisPrivateReferenceExpression || + ExpressionTypeField::decode(code_) == + kOptionalChainPrivateReferenceExpression); } bool IsCall() const { @@ -280,11 +289,13 @@ class PreParserExpression { }; enum ExpressionType { + kDefaultExpression, kThisExpression, kThisPropertyExpression, kThisPrivateReferenceExpression, kPropertyExpression, kPrivateReferenceExpression, + kOptionalChainPrivateReferenceExpression, kCallExpression, kCallEvalExpression, kSuperCallReference, @@ -521,7 +532,7 @@ class PreParserFactory { PreParserExpression NewOptionalChain(const PreParserExpression& expr) { // Needed to track `delete a?.#b` early errors if (expr.IsPrivateReference()) { - return PreParserExpression::PrivateReference(); + return PreParserExpression::OptionalChainPrivateReference(); } return PreParserExpression::Default(); } @@ -1198,7 +1209,7 @@ class PreParser : public ParserBase<PreParser> { bool has_default_constructor = !class_info->has_seen_constructor; // Account for the default constructor. if (has_default_constructor) { - bool has_extends = class_info->extends.IsNull(); + bool has_extends = !class_info->extends.IsNull(); FunctionKind kind = has_extends ? FunctionKind::kDefaultDerivedConstructor : FunctionKind::kDefaultBaseConstructor; AddSyntheticFunctionDeclaration(kind, pos); @@ -1297,9 +1308,6 @@ class PreParser : public ParserBase<PreParser> { const PreParserExpression& expression) {} V8_INLINE static void InferFunctionName() {} - V8_INLINE static void CheckAssigningFunctionLiteralToProperty( - const PreParserExpression& left, const PreParserExpression& right) {} - V8_INLINE bool ShortcutLiteralBinaryExpression(PreParserExpression* x, const PreParserExpression& y, Token::Value op, int pos) { @@ -1356,15 +1364,16 @@ class PreParser : public ParserBase<PreParser> { return init_block; } - V8_INLINE StatementT DesugarLexicalBindingsInForStatement( + V8_INLINE StatementT DesugarLetBindingsInForStatement( PreParserStatement loop, PreParserStatement init, const PreParserExpression& cond, PreParserStatement next, PreParserStatement body, Scope* inner_scope, const ForInfo& for_info) { - // See Parser::DesugarLexicalBindingsInForStatement. + // See Parser::DesugarLetBindingsInForStatement. + DCHECK_GT(for_info.bound_names.length(), 0); + DCHECK_EQ(for_info.parsing_result.descriptor.mode, VariableMode::kLet); for (auto name : for_info.bound_names) { bool was_added; - DeclareVariableName(name, for_info.parsing_result.descriptor.mode, - inner_scope, &was_added); + DeclareVariableName(name, VariableMode::kLet, inner_scope, &was_added); } return loop; } @@ -1547,11 +1556,11 @@ class PreParser : public ParserBase<PreParser> { class_info->autoaccessor_count++), VariableMode::kConst, scope, &was_added); DCHECK(was_added); - FunctionKind kind = is_static ? FunctionKind::kGetterFunction - : FunctionKind::kStaticGetterFunction; + FunctionKind kind = is_static ? FunctionKind::kStaticGetterFunction + : FunctionKind::kGetterFunction; AddSyntheticFunctionDeclaration(kind, pos + 1); - kind = is_static ? FunctionKind::kSetterFunction - : FunctionKind::kStaticSetterFunction; + kind = is_static ? FunctionKind::kStaticSetterFunction + : FunctionKind::kSetterFunction; AddSyntheticFunctionDeclaration(kind, pos + 2); return factory()->NewClassLiteralProperty( key, value, ClassLiteralProperty::Kind::AUTO_ACCESSOR, is_static, diff --git a/deps/v8/src/parsing/rewriter.cc b/deps/v8/src/parsing/rewriter.cc index 905eac437ccd..2e58fa2a9f32 100644 --- a/deps/v8/src/parsing/rewriter.cc +++ b/deps/v8/src/parsing/rewriter.cc @@ -233,7 +233,14 @@ void Processor::VisitTryCatchStatement(TryCatchStatement* node) { VISIT_AND_RETURN_IF_STACK_OVERFLOW(node->catch_block()); node->set_catch_block(static_cast<Block*>(replacement_)); - replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node); + if (!is_set_) { + Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); + Expression* assignment = SetResult(undef); + node->catch_block()->statements()->InsertAt( + 0, factory()->NewExpressionStatement(assignment, kNoSourcePosition), + zone()); + } + replacement_ = set_in_try ? node : AssignUndefinedBefore(node); is_set_ = true; } @@ -247,39 +254,34 @@ void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { VISIT_AND_RETURN_IF_STACK_OVERFLOW(node->finally_block()); node->set_finally_block(replacement_->AsBlock()); CHECK_NOT_NULL(closure_scope()); - if (is_set_) { - // Save .result value at the beginning of the finally block and restore it - // at the end again: ".backup = .result; ...; .result = .backup" This is - // necessary because the finally block does not normally contribute to the - // completion value. - Variable* backup = closure_scope()->NewTemporary( - factory()->ast_value_factory()->dot_result_string()); - Expression* backup_proxy = factory()->NewVariableProxy(backup); - Expression* result_proxy = factory()->NewVariableProxy(result_); - Expression* save = factory()->NewAssignment( - Token::kAssign, backup_proxy, result_proxy, kNoSourcePosition); - Expression* restore = factory()->NewAssignment( - Token::kAssign, result_proxy, backup_proxy, kNoSourcePosition); - node->finally_block()->statements()->InsertAt( - 0, factory()->NewExpressionStatement(save, kNoSourcePosition), - zone()); - node->finally_block()->statements()->Add( - factory()->NewExpressionStatement(restore, kNoSourcePosition), - zone()); - } else { + if (!is_set_) { // If is_set_ is false, it means the finally block has a 'break' or a // 'continue' and was not preceded by a statement that assigned to // .result. Try-finally statements return the abrupt completions from the // finally block, meaning this case should get an undefined. - // - // Since the finally block will definitely result in an abrupt completion, - // there's no need to save and restore the .result. Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); Expression* assignment = SetResult(undef); node->finally_block()->statements()->InsertAt( 0, factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); } + // Save .result value at the beginning of the finally block and restore it + // at the end again: ".backup = .result; ...; .result = .backup". This is + // necessary because the finally block does not contribute to the completion + // value on normal completion (even if it contained a labeled break whose + // target is inside the finally block). + Variable* backup = closure_scope()->NewTemporary( + factory()->ast_value_factory()->dot_result_string()); + Expression* backup_proxy = factory()->NewVariableProxy(backup); + Expression* result_proxy = factory()->NewVariableProxy(result_); + Expression* save = factory()->NewAssignment( + Token::kAssign, backup_proxy, result_proxy, kNoSourcePosition); + Expression* restore = factory()->NewAssignment( + Token::kAssign, result_proxy, backup_proxy, kNoSourcePosition); + node->finally_block()->statements()->InsertAt( + 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone()); + node->finally_block()->statements()->Add( + factory()->NewExpressionStatement(restore, kNoSourcePosition), zone()); // We can't tell whether the finally-block is guaranteed to set .result, so // reset is_set_ before visiting the try-block. is_set_ = false; @@ -334,8 +336,6 @@ void Processor::VisitWithStatement(WithStatement* node) { void Processor::VisitSloppyBlockFunctionStatement( SloppyBlockFunctionStatement* node) { - VISIT_AND_RETURN_IF_STACK_OVERFLOW(node->statement()); - node->set_statement(replacement_); replacement_ = node; } diff --git a/deps/v8/src/parsing/scanner.cc b/deps/v8/src/parsing/scanner.cc index 374fc4616e14..38e9dbfe4467 100644 --- a/deps/v8/src/parsing/scanner.cc +++ b/deps/v8/src/parsing/scanner.cc @@ -277,6 +277,27 @@ void ProcessPerFunctionCompileHints(const base::Vector<const uint8_t>& data, } // namespace +template <typename CharCallback> +Scanner::Location Scanner::ScanMagicCommentValue(CharCallback on_char) { + DCHECK_EQ(c0_, '='); + Advance(); + while (IsWhiteSpace(c0_)) { + Advance(); + } + int value_beg_pos = source_pos(); + while (c0_ != kEndOfInput && !IsWhiteSpaceOrLineTerminator(c0_)) { + on_char(c0_); + Advance(); + } + Location value_location(value_beg_pos, source_pos()); + // Allow whitespace at the end. + while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { + if (!IsWhiteSpace(c0_)) return Location::invalid(); + Advance(); + } + return value_location; +} + void Scanner::TryToParseMagicComment(base::uc32 hash_or_at_sign) { // Magic comments are of the form: //[#@]\s<name>=\s*<value>\s*.* and this // function will just return if it cannot parse a magic comment. @@ -293,12 +314,14 @@ void Scanner::TryToParseMagicComment(base::uc32 hash_or_at_sign) { } if (!name.is_one_byte()) return; base::Vector<const uint8_t> name_literal = name.one_byte_literal(); - LiteralBuffer* value; - LiteralBuffer per_function_compile_hints_value; + // The debug magic comment values are recorded as source locations, so that + // they can be created as substrings of the source instead of being copied. + Location* value_location = nullptr; + bool is_compile_hints = false; if (name_literal == base::StaticOneByteVector("sourceURL")) { - value = &source_url_; + value_location = &debug_magic_comment_locations_.source_url; } else if (name_literal == base::StaticOneByteVector("sourceMappingURL")) { - value = &source_mapping_url_; + value_location = &debug_magic_comment_locations_.source_mapping_url; DCHECK(hash_or_at_sign == '#' || hash_or_at_sign == '@'); saw_source_mapping_url_magic_comment_at_sign_ = hash_or_at_sign == '@'; } else if (!saw_non_comment_ && @@ -309,45 +332,33 @@ void Scanner::TryToParseMagicComment(base::uc32 hash_or_at_sign) { } else if (name_literal == base::StaticOneByteVector("functionsCalledOnLoad") && hash_or_at_sign == '#') { - value = &per_function_compile_hints_value; + is_compile_hints = true; } else if (name_literal == base::StaticOneByteVector("debugId") && hash_or_at_sign == '#') { - value = &debug_id_; + value_location = &debug_magic_comment_locations_.debug_id; } else { return; } if (c0_ != '=') { return; } - value->Start(); - Advance(); - while (IsWhiteSpace(c0_)) { - Advance(); - } - while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { - if (IsWhiteSpace(c0_)) { - break; - } - value->AddChar(c0_); - Advance(); - } - // Allow whitespace at the end. - while (c0_ != kEndOfInput && !unibrow::IsLineTerminator(c0_)) { - if (!IsWhiteSpace(c0_)) { - value->Start(); - break; - } - Advance(); - } - if (value == &per_function_compile_hints_value && - per_function_compile_hints_value.is_one_byte()) { - base::Vector<const uint8_t> value_literal = - per_function_compile_hints_value.one_byte_literal(); - per_function_compile_hint_positions_.clear(); - per_function_compile_hint_positions_idx_ = 0; - ProcessPerFunctionCompileHints(value_literal, source_pos(), - per_function_compile_hint_positions_); + if (!is_compile_hints) { + DCHECK_NOT_NULL(value_location); + *value_location = ScanMagicCommentValue([](base::uc32) {}); + return; } + LiteralBuffer value; + value.Start(); + Location value_location_in_source = + ScanMagicCommentValue([&value](base::uc32 c) { value.AddChar(c); }); + // A value followed by trailing garbage is treated as empty, which clears + // the previously recorded compile hints. + if (!value_location_in_source.IsValid()) value.Start(); + if (!value.is_one_byte()) return; + per_function_compile_hint_positions_.clear(); + per_function_compile_hint_positions_idx_ = 0; + ProcessPerFunctionCompileHints(value.one_byte_literal(), source_pos(), + per_function_compile_hint_positions_); } bool Scanner::HasPerFunctionCompileHint(int position) { @@ -457,7 +468,7 @@ void Scanner::SeekForward(int pos) { int current_pos = source_pos(); DCHECK_EQ(next().location.end_pos, current_pos); // Positions inside the lookahead token aren't supported. - DCHECK(pos >= current_pos); + CHECK_GE(pos, current_pos); if (pos != current_pos) { source_->Seek(pos); Advance(); @@ -689,43 +700,6 @@ Token::Value Scanner::ScanTemplateSpan() { return result; } -template <typename IsolateT> -DirectHandle<String> Scanner::SourceUrl(IsolateT* isolate) const { - DirectHandle<String> tmp; - if (source_url_.length() > 0) { - tmp = source_url_.Internalize(isolate); - } - return tmp; -} - -template DirectHandle<String> Scanner::SourceUrl(Isolate* isolate) const; -template DirectHandle<String> Scanner::SourceUrl(LocalIsolate* isolate) const; - -template <typename IsolateT> -DirectHandle<String> Scanner::SourceMappingUrl(IsolateT* isolate) const { - DirectHandle<String> tmp; - if (source_mapping_url_.length() > 0) { - tmp = source_mapping_url_.Internalize(isolate); - } - return tmp; -} - -template DirectHandle<String> Scanner::SourceMappingUrl(Isolate* isolate) const; -template DirectHandle<String> Scanner::SourceMappingUrl( - LocalIsolate* isolate) const; - -template <typename IsolateT> -DirectHandle<String> Scanner::DebugId(IsolateT* isolate) const { - DirectHandle<String> tmp; - if (debug_id_.length() > 0) { - tmp = debug_id_.Internalize(isolate); - } - return tmp; -} - -template DirectHandle<String> Scanner::DebugId(Isolate* isolate) const; -template DirectHandle<String> Scanner::DebugId(LocalIsolate* isolate) const; - bool Scanner::ScanDigitsWithNumericSeparators(bool (*predicate)(base::uc32 ch), bool is_check_first_digit) { // we must have at least one digit after 'x'/'b'/'o' @@ -1042,17 +1016,16 @@ Token::Value Scanner::ScanIdentifierOrKeywordInnerSlow(bool escaped, base::Vector<const uint8_t> chars = next().literal_chars.one_byte_literal(); Token::Value token = KeywordOrIdentifierToken(chars.begin(), chars.length()); - if (base::IsInRange(token, Token::kIdentifier, Token::kYield)) return token; + if (!escaped) return token; - if (token == Token::kFutureStrictReservedWord) { - if (escaped) return Token::kEscapedStrictReservedWord; - return token; + if (base::IsInRange(token, Token::kIdentifier, Token::kAsync)) { + return Token::kIdentifier; } - - if (!escaped) return token; + if (base::IsInRange(token, Token::kAwait, Token::kYield)) return token; static_assert(Token::kLet + 1 == Token::kStatic); - if (base::IsInRange(token, Token::kLet, Token::kStatic)) { + static_assert(Token::kStatic + 1 == Token::kFutureStrictReservedWord); + if (base::IsInRange(token, Token::kLet, Token::kFutureStrictReservedWord)) { return Token::kEscapedStrictReservedWord; } return Token::kEscapedKeyword; diff --git a/deps/v8/src/parsing/scanner.h b/deps/v8/src/parsing/scanner.h index 087963d1ad35..c5de316bfef4 100644 --- a/deps/v8/src/parsing/scanner.h +++ b/deps/v8/src/parsing/scanner.h @@ -322,6 +322,11 @@ class V8_EXPORT_PRIVATE Scanner { Token::Value Next(); // Returns the token following peek() Token::Value PeekAhead(); + // Checks the character after peek(); declines if lookahead is buffered. + bool HasImmediateCommaOrRightBracket() const { + return next_next().token == Token::kUninitialized && + (c0_ == ',' || c0_ == ']'); + } // Returns the token following PeekAhead() Token::Value PeekAheadAhead(); // Returns the current token again. @@ -459,12 +464,18 @@ class V8_EXPORT_PRIVATE Scanner { return ScanTemplateSpan(); } - template <typename IsolateT> - DirectHandle<String> SourceUrl(IsolateT* isolate) const; - template <typename IsolateT> - DirectHandle<String> SourceMappingUrl(IsolateT* isolate) const; - template <typename IsolateT> - DirectHandle<String> DebugId(IsolateT* isolate) const; + // Source locations of the values of the debug magic comments. A location is + // invalid if there was no such comment, or if the last one was malformed; it + // is empty if the last one had an empty value. In both cases there is no + // value. + struct DebugMagicCommentLocations { + Location source_url = Location::invalid(); + Location source_mapping_url = Location::invalid(); + Location debug_id = Location::invalid(); + }; + const DebugMagicCommentLocations& debug_magic_comment_locations() const { + return debug_magic_comment_locations_; + } bool SawSourceMappingUrlMagicCommentAtSign() const { return saw_source_mapping_url_magic_comment_at_sign_; @@ -717,6 +728,12 @@ class V8_EXPORT_PRIVATE Scanner { Token::Value SkipSingleLineComment(); Token::Value SkipMagicComment(base::uc32 hash_or_at_sign); void TryToParseMagicComment(base::uc32 hash_or_at_sign); + // Scans the value of a magic comment, starting at the '=', calling on_char + // for each value character. Returns the value's location, or + // Location::invalid() if anything but whitespace follows the value on the + // line. + template <typename CharCallback> + Location ScanMagicCommentValue(CharCallback on_char); Token::Value SkipMultiLineComment(); // Scans a possible HTML comment -- begins with '<!'. Token::Value ScanHtmlComment(); @@ -802,10 +819,7 @@ class V8_EXPORT_PRIVATE Scanner { // Whether this scanner encountered an HTML comment. bool found_html_comment_; - // Values parsed from magic comments. - LiteralBuffer source_url_; - LiteralBuffer source_mapping_url_; - LiteralBuffer debug_id_; + DebugMagicCommentLocations debug_magic_comment_locations_; bool saw_source_mapping_url_magic_comment_at_sign_ = false; bool saw_magic_comment_compile_hints_all_ = false; bool saw_non_comment_ = false; diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc index 0204463acb2f..953a91dc2e17 100644 --- a/deps/v8/src/profiler/cpu-profiler.cc +++ b/deps/v8/src/profiler/cpu-profiler.cc @@ -59,7 +59,9 @@ class CpuSampler : public sampler::Sampler { // the sample is created in the buffer. sample->Init(isolate, regs, TickSample::kIncludeCEntryFrame, /* update_stats */ true, - /* use_simulator_reg_state */ true, processor_->period()); + /* use_simulator_reg_state */ true, processor_->period(), + /* trace_id */ std::nullopt, + processor_->ExtractSampleContext()); if (is_counting_samples_ && !sample->timestamp.IsNull()) { if (sample->state == JS) ++js_sample_count_; if (sample->state == EXTERNAL) ++external_sample_count_; @@ -107,14 +109,16 @@ ProfilingScope::~ProfilingScope() { ProfilerEventsProcessor::ProfilerEventsProcessor( Isolate* isolate, Symbolizer* symbolizer, - ProfilerCodeObserver* code_observer, CpuProfilesCollection* profiles) + ProfilerCodeObserver* code_observer, CpuProfilesCollection* profiles, + SampleContextExtractor sample_context_extractor) : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), symbolizer_(symbolizer), code_observer_(code_observer), profiles_(profiles), last_code_event_id_(0), last_processed_code_event_id_(0), - isolate_(isolate) { + isolate_(isolate), + sample_context_extractor_(sample_context_extractor) { DCHECK(!code_observer_->processor()); code_observer_->set_processor(this); } @@ -122,8 +126,10 @@ ProfilerEventsProcessor::ProfilerEventsProcessor( SamplingEventsProcessor::SamplingEventsProcessor( Isolate* isolate, Symbolizer* symbolizer, ProfilerCodeObserver* code_observer, CpuProfilesCollection* profiles, - base::TimeDelta period, bool use_precise_sampling) - : ProfilerEventsProcessor(isolate, symbolizer, code_observer, profiles), + base::TimeDelta period, bool use_precise_sampling, + SampleContextExtractor sample_context_extractor) + : ProfilerEventsProcessor(isolate, symbolizer, code_observer, profiles, + sample_context_extractor), sampler_(new CpuSampler(isolate, this)), period_(period), use_precise_sampling_(use_precise_sampling) { @@ -146,6 +152,11 @@ ProfilerEventsProcessor::~ProfilerEventsProcessor() { code_observer_->clear_processor(); } +void* ProfilerEventsProcessor::ExtractSampleContext() const { + if (sample_context_extractor_ == nullptr) return nullptr; + return sample_context_extractor_(reinterpret_cast<v8::Isolate*>(isolate_)); +} + void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { event.generic.order = ++last_code_event_id_; events_buffer_.Enqueue(event); @@ -158,8 +169,10 @@ void ProfilerEventsProcessor::AddDeoptStack(Address from, int fp_to_sp_delta) { regs.sp = reinterpret_cast<void*>(fp - fp_to_sp_delta); regs.fp = reinterpret_cast<void*>(fp); regs.pc = reinterpret_cast<void*>(from); - record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, false, - false); + record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, + /* update_stats */ false, + /* use_simulator_reg_state */ false, base::TimeDelta(), + /* trace_id */ std::nullopt, ExtractSampleContext()); ticks_from_vm_buffer_.Enqueue(record); } @@ -175,7 +188,8 @@ void ProfilerEventsProcessor::AddCurrentStack( regs.pc = reinterpret_cast<void*>(frame->pc()); } record.sample.Init(isolate_, regs, TickSample::kSkipCEntryFrame, update_stats, - false, base::TimeDelta(), trace_id); + /* use_simulator_reg_state */ false, base::TimeDelta(), + trace_id, ExtractSampleContext()); ticks_from_vm_buffer_.Enqueue(record); } @@ -251,7 +265,7 @@ void SamplingEventsProcessor::SymbolizeAndAddToProfiles( tick_sample.state, tick_sample.embedder_state, reinterpret_cast<Address>(tick_sample.context), reinterpret_cast<Address>(tick_sample.embedder_context), - tick_sample.trace_id_); + tick_sample.trace_id_, tick_sample.sample_context_); } ProfilerEventsProcessor::SampleProcessingResult @@ -648,6 +662,7 @@ CpuProfilingResult CpuProfiler::StartProfiling( CpuProfilingResult CpuProfiler::StartProfiling( const char* title, CpuProfilingOptions options, std::unique_ptr<DiscardedSamplesDelegate> delegate) { + auto sample_context_extractor = options.sample_context_extractor(); CpuProfilingResult result = profiles_->StartProfiling(title, std::move(options), std::move(delegate)); @@ -657,7 +672,9 @@ CpuProfilingResult CpuProfiler::StartProfiling( result.status == CpuProfilingStatus::kAlreadyStarted) { TRACE_EVENT0("v8", "CpuProfiler::StartProfiling"); AdjustSamplingInterval(); - StartProcessorIfNotStarted(); + StartProcessorIfNotStarted(sample_context_extractor); + // after StartProcessorIfNotStarted processor_ must exist. + DCHECK(processor_); // Collect script rundown at the start of profiling if trace category is // turned on @@ -696,7 +713,8 @@ CpuProfilingResult CpuProfiler::StartProfiling( std::move(delegate)); } -void CpuProfiler::StartProcessorIfNotStarted() { +void CpuProfiler::StartProcessorIfNotStarted( + ProfilerEventsProcessor::SampleContextExtractor sample_context_extractor) { if (processor_) { processor_->AddCurrentStack(); return; @@ -715,7 +733,7 @@ void CpuProfiler::StartProcessorIfNotStarted() { base::TimeDelta sampling_interval = ComputeSamplingInterval(); processor_.reset(new SamplingEventsProcessor( isolate_, symbolizer_.get(), code_observer_.get(), profiles_.get(), - sampling_interval, use_precise_sampling_)); + sampling_interval, use_precise_sampling_, sample_context_extractor)); is_profiling_ = true; // Enable stack sampling. diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h index bbfc6432533e..519fe9662cc4 100644 --- a/deps/v8/src/profiler/cpu-profiler.h +++ b/deps/v8/src/profiler/cpu-profiler.h @@ -188,10 +188,15 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread, virtual void SetSamplingInterval(base::TimeDelta) {} + using SampleContextExtractor = void* (*)(v8::Isolate*); + + void* ExtractSampleContext() const; + protected: ProfilerEventsProcessor(Isolate* isolate, Symbolizer* symbolizer, ProfilerCodeObserver* code_observer, - CpuProfilesCollection* profiles); + CpuProfilesCollection* profiles, + SampleContextExtractor sample_context_extractor); // Called from events processing thread (Run() method.) bool ProcessCodeEvent(); @@ -214,6 +219,9 @@ class V8_EXPORT_PRIVATE ProfilerEventsProcessor : public base::Thread, std::atomic<unsigned> last_code_event_id_; unsigned last_processed_code_event_id_; Isolate* isolate_; + + private: + const SampleContextExtractor sample_context_extractor_; }; class V8_EXPORT_PRIVATE SamplingEventsProcessor @@ -222,7 +230,8 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor SamplingEventsProcessor(Isolate* isolate, Symbolizer* symbolizer, ProfilerCodeObserver* code_observer, CpuProfilesCollection* profiles, - base::TimeDelta period, bool use_precise_sampling); + base::TimeDelta period, bool use_precise_sampling, + SampleContextExtractor sample_context_extractor); ~SamplingEventsProcessor() override; // SamplingCircularQueue has stricter alignment requirements than a normal new @@ -389,7 +398,8 @@ class V8_EXPORT_PRIVATE CpuProfiler { } private: - void StartProcessorIfNotStarted(); + void StartProcessorIfNotStarted( + ProfilerEventsProcessor::SampleContextExtractor sample_context_extractor); void StopProcessor(); void ResetProfiles(); diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc index 603fd18e877a..fb865b56dbd3 100644 --- a/deps/v8/src/profiler/heap-profiler.cc +++ b/deps/v8/src/profiler/heap-profiler.cc @@ -221,10 +221,12 @@ std::string HeapProfiler::TakeSnapshotToString( bool HeapProfiler::StartSamplingHeapProfiler( uint64_t sample_interval, int stack_depth, - v8::HeapProfiler::SamplingFlags flags) { + v8::HeapProfiler::SamplingFlags flags, + v8::SampleContextExtractor sample_context_extractor) { if (sampling_heap_profiler_) return false; - sampling_heap_profiler_.reset(new SamplingHeapProfiler( - heap(), names_.get(), sample_interval, stack_depth, flags)); + sampling_heap_profiler_.reset( + new SamplingHeapProfiler(heap(), names_.get(), sample_interval, + stack_depth, flags, sample_context_extractor)); return true; } @@ -339,6 +341,10 @@ DirectHandle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) { for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null(); obj = iterator.Next()) { if (ids_->FindEntry(obj.address()) == id) { + if (IsInaccessible(obj)) { + DCHECK(IsWasmNull(obj)); // Currently the only inaccessible object. + return isolate()->factory()->null_value(); + } return DirectHandle<HeapObject>(obj, isolate()); } } diff --git a/deps/v8/src/profiler/heap-profiler.h b/deps/v8/src/profiler/heap-profiler.h index 031f32762fac..39f2e226ad39 100644 --- a/deps/v8/src/profiler/heap-profiler.h +++ b/deps/v8/src/profiler/heap-profiler.h @@ -80,8 +80,10 @@ class HeapProfiler : public HeapObjectAllocationTracker { V8_EXPORT_PRIVATE std::string TakeSnapshotToString( const v8::HeapProfiler::HeapSnapshotOptions options); - bool StartSamplingHeapProfiler(uint64_t sample_interval, int stack_depth, - v8::HeapProfiler::SamplingFlags); + bool StartSamplingHeapProfiler( + uint64_t sample_interval, int stack_depth, + v8::HeapProfiler::SamplingFlags, + v8::SampleContextExtractor sample_context_extractor = nullptr); void StopSamplingHeapProfiler(); void SetSamplingHeapProfilerInterval(uint64_t sample_interval); std::vector<v8::AllocationProfile::Sample> GetSamplingHeapProfilerSamples(); diff --git a/deps/v8/src/profiler/heap-snapshot-generator.cc b/deps/v8/src/profiler/heap-snapshot-generator.cc index 30994012c4b5..1403701e8d94 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.cc +++ b/deps/v8/src/profiler/heap-snapshot-generator.cc @@ -4,6 +4,7 @@ #include "src/profiler/heap-snapshot-generator.h" +#include <array> #include <optional> #include <utility> @@ -11,6 +12,7 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/ast/variables.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/builtins/builtins.h" #include "src/codegen/assembler-inl.h" @@ -95,7 +97,11 @@ void CollectScopeTree(Scope* scope, int depth, HeapEntry* script_entry, std::vector<Variable*> context_vars; - if (scope->is_class_scope()) { + if (scope->is_script_scope()) { + // Script scopes contain global lexical variables (let/const) that can be + // accessed across different scripts, for which uses are not tracked. Omit + // context variables to disable dead context analysis. + } else if (scope->is_class_scope()) { // Class scopes contain private fields and methods for which uses across // closures are currently not tracked. Omit context variables to disable // dead context analysis. @@ -520,15 +526,15 @@ void HeapEntry::Print(const char* prefix, const char* edge_name, int max_depth, for (auto i = children_begin(); i != children_end(); ++i) { HeapGraphEdge& edge = **i; const char* edge_prefix = ""; - base::EmbeddedVector<char, 64> index; - edge_name = index.begin(); + std::array<char, 64> index; + edge_name = index.data(); switch (edge.type()) { case HeapGraphEdge::kContextVariable: edge_prefix = "#"; edge_name = edge.name(); break; case HeapGraphEdge::kElement: - SNPrintF(index, "%d", edge.index()); + base::SNPrintF(index, "%d", edge.index()); break; case HeapGraphEdge::kInternal: edge_prefix = "$"; @@ -539,7 +545,7 @@ void HeapEntry::Print(const char* prefix, const char* edge_name, int max_depth, break; case HeapGraphEdge::kHidden: edge_prefix = "$"; - SNPrintF(index, "%d", edge.index()); + base::SNPrintF(index, "%d", edge.index()); break; case HeapGraphEdge::kShortcut: edge_prefix = "^"; @@ -550,7 +556,7 @@ void HeapEntry::Print(const char* prefix, const char* edge_name, int max_depth, edge_name = edge.name(); break; default: - SNPrintF(index, "!!! unknown edge type: %d ", edge.type()); + base::SNPrintF(index, "!!! unknown edge type: %d ", edge.type()); } edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2); } @@ -1519,8 +1525,8 @@ class IndexedReferencesExtractor : public ObjectVisitorWithCageBases { VisitSlotImpl(code_cage_base(), slot); } - void VisitIndirectPointer(Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) override { + void VisitTrustedPointer(Tagged<HeapObject> host, TrustedPointerSlot slot, + TrustedPointerMode mode) override { VisitSlotImpl(generator_->isolate(), slot); } @@ -1637,6 +1643,11 @@ void V8HeapExplorer::ExtractReferences(HeapEntry* entry, ExtractStringReferences(entry, Cast<String>(obj)); } else if (IsSymbol(obj)) { ExtractSymbolReferences(entry, Cast<Symbol>(obj)); +#if V8_ENABLE_WEBASSEMBLY + } else if (IsWasmCustomMap(obj)) { + // Must check this before {IsMap} below due to instance type ranges. + ExtractWasmCustomMapReferences(Cast<WasmCustomMap>(obj), entry); +#endif // V8_ENABLE_WEBASSEMBLY } else if (IsMap(obj)) { ExtractMapReferences(entry, Cast<Map>(obj)); } else if (IsSharedFunctionInfo(obj)) { @@ -1891,6 +1902,7 @@ void V8HeapExplorer::ExtractStringReferences(HeapEntry* entry, Tagged<SlicedString> ss = Cast<SlicedString>(string); SetInternalReference(entry, "parent", ss->parent(), offsetof(SlicedString, parent_)); + AddIntEdge(entry, HeapGraphEdge::kInternal, "offset", ss->offset()); } else if (IsThinString(string)) { Tagged<ThinString> ts = Cast<ThinString>(string); SetInternalReference(entry, "actual", ts->actual(), @@ -2070,7 +2082,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Tagged<Map> map) { } SetInternalReference(entry, "prototype", map->prototype(), offsetof(Map, prototype_)); - if (IsContextMap(map) || IsMapMap(map)) { + if (IsContextMap(map) || IsMetaMap(map)) { Tagged<Object> native_context = map->native_context_or_null(); TagObject(native_context, "(native context)"); SetInternalReference( @@ -2089,6 +2101,13 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Tagged<Map> map) { SetInternalReference( entry, "constructor_function_data", constructor_or_back_pointer, offsetof(Map, constructor_or_back_pointer_or_native_context_)); +#if V8_ENABLE_WEBASSEMBLY + } else if (IsWasmTypeInfo(constructor_or_back_pointer)) { + TagObject(constructor_or_back_pointer, "(wasm type info)"); + SetInternalReference( + entry, "wasm_type_info", constructor_or_back_pointer, + offsetof(Map, constructor_or_back_pointer_or_native_context_)); +#endif // V8_ENABLE_WEBASSEMBLY } else { SetInternalReference( entry, "constructor", constructor_or_back_pointer, @@ -2102,7 +2121,7 @@ void V8HeapExplorer::ExtractMapReferences(HeapEntry* entry, Tagged<Map> map) { // Wasm object maps overload the dependent_code field to store the // immediate supertype map. Emit without field offset to avoid // double-marking the slot. - if (IsWasmObjectMap(map) && map->has_immediate_supertype_map()) { + if (IsAnyWasmObjectMap(map) && map->has_immediate_supertype_map()) { TagObject(map->immediate_supertype_map(), "(immediate supertype map)"); SetInternalReference(entry, "immediate_supertype_map", map->immediate_supertype_map()); @@ -2868,6 +2887,64 @@ void V8HeapExplorer::ExtractWasmStructReferences(Tagged<WasmStruct> obj, } } +void V8HeapExplorer::ExtractWasmCustomMapReferences(Tagged<WasmCustomMap> obj, + HeapEntry* entry) { + // Inherited from ExtractMapReferences: + ExtractMapReferences(entry, obj); + + // Inherited from ExtractWasmStructReferences: + // TODO(jkummerow): Deduplicate. + Tagged<WasmTypeInfo> info = obj->map()->wasm_type_info(); + const wasm::CanonicalStructType* type = + wasm::GetTypeCanonicalizer()->LookupStruct(info->type_index()); + wasm::CanonicalTypeNamesProvider* names = + wasm::GetCanonicalTypeNamesProvider(); + Isolate* isolate = heap_->isolate(); + for (uint32_t i = 0; i < type->field_count(); i++) { + wasm::StringBuilder sb; + names->PrintFieldName(sb, info->type_index(), i); + sb << '\0'; + const char* field_name = names_->GetCopy(sb.start()); + switch (type->field(i).kind()) { + case wasm::kI8: + case wasm::kI16: + case wasm::kI32: + case wasm::kI64: + case wasm::kF16: + case wasm::kF32: + case wasm::kF64: + case wasm::kS128: { + std::string value_string = obj->GetFieldValue(i).to_string(); + const char* value_name = names_->GetCopy(value_string.c_str()); + SnapshotObjectId id = heap_object_map_->get_next_id(); + HeapEntry* child_entry = + snapshot_->AddEntry(HeapEntry::kString, value_name, id, 0, 0); + entry->SetNamedReference(HeapGraphEdge::kInternal, field_name, + child_entry, generator_); + break; + } + case wasm::kRef: + case wasm::kRefNull: { + int field_offset = type->field_offset(i); + Tagged<Object> value = obj->RawField(field_offset).load(isolate); + // We could consider hiding {null} fields by default (like we do for + // arrays, see below), but for now we always include them, in the hope + // that they might help identify opportunities for struct size + // reductions. + HeapEntry* value_entry = GetEntry(value); + entry->SetNamedReference(HeapGraphEdge::kProperty, field_name, + value_entry, generator_); + MarkVisitedField(WasmCustomMap::kHeaderSize + field_offset); + break; + } + case wasm::kVoid: + case wasm::kTop: + case wasm::kBottom: + UNREACHABLE(); + } + } +} + void V8HeapExplorer::ExtractWasmArrayReferences(Tagged<WasmArray> obj, HeapEntry* entry) { const wasm::CanonicalValueType element_type = @@ -4307,7 +4384,7 @@ void HeapSnapshotJSONSerializer::SerializeSamples() { void HeapSnapshotJSONSerializer::SerializeStrings() { auto sorted_strings = - base::OwnedVector<const unsigned char*>::NewForOverwrite( + base::UniqueArray<const unsigned char*>::NewForOverwrite( strings_.occupancy() + 1); for (base::HashMap::Entry* entry = strings_.Start(); entry != nullptr; entry = strings_.Next(entry)) { diff --git a/deps/v8/src/profiler/heap-snapshot-generator.h b/deps/v8/src/profiler/heap-snapshot-generator.h index d1ff451eb477..46441a3a0f2d 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.h +++ b/deps/v8/src/profiler/heap-snapshot-generator.h @@ -633,6 +633,8 @@ class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator { #if V8_ENABLE_WEBASSEMBLY void ExtractWasmStructReferences(Tagged<WasmStruct> obj, HeapEntry* entry); + void ExtractWasmCustomMapReferences(Tagged<WasmCustomMap> obj, + HeapEntry* entry); void ExtractWasmArrayReferences(Tagged<WasmArray> obj, HeapEntry* entry); void ExtractWasmTrustedInstanceDataReferences( Tagged<WasmTrustedInstanceData> obj, HeapEntry* entry); diff --git a/deps/v8/src/profiler/output-stream-writer.h b/deps/v8/src/profiler/output-stream-writer.h index 0b776f959676..fcd4effd1f51 100644 --- a/deps/v8/src/profiler/output-stream-writer.h +++ b/deps/v8/src/profiler/output-stream-writer.h @@ -13,7 +13,7 @@ #include "include/v8-profiler.h" #include "include/v8config.h" #include "src/base/logging.h" -#include "src/base/vector.h" +#include "src/base/unique-array.h" #include "src/utils/memcopy.h" namespace v8 { @@ -24,7 +24,7 @@ class OutputStreamWriter { explicit OutputStreamWriter(v8::OutputStream* stream) : stream_(stream), chunk_size_(stream->GetChunkSize()), - chunk_(base::OwnedVector<char>::NewForOverwrite(chunk_size_)), + chunk_(base::UniqueArray<char>::NewForOverwrite(chunk_size_)), chunk_pos_(0), aborted_(false) { DCHECK_GT(chunk_size_, 0); @@ -98,7 +98,7 @@ class OutputStreamWriter { v8::OutputStream* stream_; int chunk_size_; - base::OwnedVector<char> chunk_; + base::UniqueArray<char> chunk_; int chunk_pos_; bool aborted_; }; diff --git a/deps/v8/src/profiler/profile-generator.cc b/deps/v8/src/profiler/profile-generator.cc index bb7aea18dafa..2f7681573c70 100644 --- a/deps/v8/src/profiler/profile-generator.cc +++ b/deps/v8/src/profiler/profile-generator.cc @@ -657,7 +657,8 @@ void CpuProfile::AddPath(base::TimeTicks timestamp, bool update_stats, base::TimeDelta sampling_interval, StateTag state_tag, EmbedderStateTag embedder_state_tag, - const std::optional<uint64_t> trace_id) { + const std::optional<uint64_t> trace_id, + void* sample_context) { if (!CheckSubsample(sampling_interval)) return; ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path, src_pos, update_stats, options_.mode()); @@ -670,7 +671,7 @@ void CpuProfile::AddPath(base::TimeTicks timestamp, if (should_record_sample) { samples_.push_back({top_frame_node, timestamp, src_pos, state_tag, - embedder_state_tag, trace_id}); + embedder_state_tag, trace_id, sample_context}); } else if (is_buffer_full && delegate_ != nullptr) { const auto task_runner = V8::GetCurrentPlatform()->GetForegroundTaskRunner( reinterpret_cast<v8::Isolate*>(profiler_->isolate())); @@ -1243,7 +1244,7 @@ void CpuProfilesCollection::AddPathToCurrentProfiles( LineAndColumn src_pos, bool update_stats, base::TimeDelta sampling_interval, StateTag state, EmbedderStateTag embedder_state_tag, Address native_context_address, Address embedder_native_context_address, - const std::optional<uint64_t> trace_id) { + const std::optional<uint64_t> trace_id, void* sample_context) { // As starting / stopping profiles is rare relatively to this // method, we don't bother minimizing the duration of lock holding, // e.g. copying contents of the list to a local vector. @@ -1267,7 +1268,7 @@ void CpuProfilesCollection::AddPathToCurrentProfiles( timestamp, accepts_context ? path : empty_path, src_pos, update_stats, sampling_interval, state, accepts_embedder_context ? embedder_state_tag : EmbedderStateTag::EMPTY, - trace_id); + trace_id, sample_context); } } diff --git a/deps/v8/src/profiler/profile-generator.h b/deps/v8/src/profiler/profile-generator.h index d2abfd4c555b..b5d6e58437d4 100644 --- a/deps/v8/src/profiler/profile-generator.h +++ b/deps/v8/src/profiler/profile-generator.h @@ -424,6 +424,7 @@ class CpuProfile { StateTag state_tag; EmbedderStateTag embedder_state_tag; const std::optional<uint64_t> trace_id; + void* sample_context; }; V8_EXPORT_PRIVATE CpuProfile( @@ -441,7 +442,8 @@ class CpuProfile { LineAndColumn src_pos, bool update_stats, base::TimeDelta sampling_interval, StateTag state, EmbedderStateTag embedder_state, - const std::optional<uint64_t> trace_id = std::nullopt); + const std::optional<uint64_t> trace_id = std::nullopt, + void* sample_context = nullptr); void FinishProfile(); const char* title() const { return title_; } @@ -588,7 +590,8 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection { EmbedderStateTag embedder_state_tag, Address native_context_address = kNullAddress, Address native_embedder_context_address = kNullAddress, - const std::optional<uint64_t> trace_id = std::nullopt); + const std::optional<uint64_t> trace_id = std::nullopt, + void* sample_context = nullptr); // Called from profile generator thread. void UpdateNativeContextAddressForCurrentProfiles(Address from, Address to); diff --git a/deps/v8/src/profiler/profiler-listener.cc b/deps/v8/src/profiler/profiler-listener.cc index c009abae52eb..95d3276773a9 100644 --- a/deps/v8/src/profiler/profiler-listener.cc +++ b/deps/v8/src/profiler/profiler-listener.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/codegen/reloc-info.h" #include "src/codegen/source-position-table.h" @@ -366,8 +367,8 @@ void ProfilerListener::CodeSweepEvent() { weak_code_registry_.Sweep(this); } const char* ProfilerListener::GetName(base::Vector<const char> name) { // TODO(all): Change {StringsStorage} to accept non-null-terminated strings. - base::OwnedVector<char> null_terminated = - base::OwnedVector<char>::New(name.size() + 1); + base::UniqueArray<char> null_terminated = + base::UniqueArray<char>::New(name.size() + 1); #if defined(__GNUC__) && !defined(__clang__) // Work around a spurious GCC-12 warning (-Werror=array-bounds). if (name.end() < name.begin()) return nullptr; diff --git a/deps/v8/src/profiler/sampling-heap-profiler.cc b/deps/v8/src/profiler/sampling-heap-profiler.cc index ea6a85243d4c..c6e49a42ec3d 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.cc +++ b/deps/v8/src/profiler/sampling-heap-profiler.cc @@ -55,7 +55,8 @@ v8::AllocationProfile::Allocation SamplingHeapProfiler::ScaleSample( SamplingHeapProfiler::SamplingHeapProfiler( Heap* heap, StringsStorage* names, uint64_t rate, int stack_depth, - v8::HeapProfiler::SamplingFlags flags) + v8::HeapProfiler::SamplingFlags flags, + v8::SampleContextExtractor sample_context_extractor) : isolate_(Isolate::FromHeap(heap)), heap_(heap), allocation_observer_(heap_, static_cast<intptr_t>(rate), this, @@ -65,7 +66,8 @@ SamplingHeapProfiler::SamplingHeapProfiler( next_node_id()), stack_depth_(stack_depth), interval_(rate), - flags_(flags) { + flags_(flags), + sample_context_extractor_(sample_context_extractor) { CHECK_GT(interval_.load(std::memory_order_relaxed), 0u); heap_->AddAllocationObserversToAllSpaces(&allocation_observer_, &allocation_observer_); @@ -99,10 +101,16 @@ void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { // with the exact weight in effect at draw time. const uint64_t interval_at_sample = interval_.load(std::memory_order_relaxed); + void* context = nullptr; + if (sample_context_extractor_ != nullptr) { + DisallowJavascriptExecutionDebugOnly no_js(isolate_); + context = + sample_context_extractor_(reinterpret_cast<v8::Isolate*>(isolate_)); + } AllocationNode* node = AddStack(); node->allocations_[{size, interval_at_sample}]++; - auto sample = std::make_unique<Sample>(size, node, loc, this, - next_sample_id(), interval_at_sample); + auto sample = std::make_unique<Sample>( + size, node, loc, this, next_sample_id(), interval_at_sample, context); sample->global.SetWeak(sample.get(), OnWeakCallback, WeakCallbackType::kParameter); samples_.emplace(sample.get(), std::move(sample)); @@ -335,7 +343,7 @@ SamplingHeapProfiler::BuildSamples() const { samples.emplace_back(v8::AllocationProfile::Sample{ sample->owner->id_, sample->size, ScaleSample(sample->size, 1, sample->sample_interval).count, - sample->sample_id, is_live, sample->sample_interval}); + sample->sample_id, is_live, sample->sample_interval, sample->context}); } return samples; } diff --git a/deps/v8/src/profiler/sampling-heap-profiler.h b/deps/v8/src/profiler/sampling-heap-profiler.h index 6a4f7d861928..55ba717eefef 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.h +++ b/deps/v8/src/profiler/sampling-heap-profiler.h @@ -107,13 +107,14 @@ class SamplingHeapProfiler { struct Sample { Sample(size_t size_, AllocationNode* owner_, Local<Value> local_, SamplingHeapProfiler* profiler_, uint64_t sample_id_, - uint64_t sample_interval_) + uint64_t sample_interval_, void* context_) : size(size_), owner(owner_), global(reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_), profiler(profiler_), sample_id(sample_id_), - sample_interval(sample_interval_) {} + sample_interval(sample_interval_), + context(context_) {} Sample(const Sample&) = delete; Sample& operator=(const Sample&) = delete; const size_t size; @@ -122,10 +123,12 @@ class SamplingHeapProfiler { SamplingHeapProfiler* const profiler; const uint64_t sample_id; const uint64_t sample_interval; + void* const context; }; SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate, - int stack_depth, v8::HeapProfiler::SamplingFlags flags); + int stack_depth, v8::HeapProfiler::SamplingFlags flags, + v8::SampleContextExtractor sample_context_extractor); ~SamplingHeapProfiler(); SamplingHeapProfiler(const SamplingHeapProfiler&) = delete; SamplingHeapProfiler& operator=(const SamplingHeapProfiler&) = delete; @@ -206,6 +209,7 @@ class SamplingHeapProfiler { const int stack_depth_; std::atomic<uint64_t> interval_; v8::HeapProfiler::SamplingFlags flags_; + const v8::SampleContextExtractor sample_context_extractor_; }; } // namespace internal diff --git a/deps/v8/src/profiler/strings-storage.cc b/deps/v8/src/profiler/strings-storage.cc index d43e039ab6e7..40a0d2b6a307 100644 --- a/deps/v8/src/profiler/strings-storage.cc +++ b/deps/v8/src/profiler/strings-storage.cc @@ -10,6 +10,7 @@ #include "src/base/bits.h" #include "src/base/small-vector.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/objects/objects-inl.h" #include "src/strings/unicode-inl.h" #include "src/utils/allocation.h" @@ -37,10 +38,11 @@ const char* StringsStorage::GetCopy(const char* src) { int len = static_cast<int>(strlen(src)); base::HashMap::Entry* entry = GetEntry(src, len); if (entry->value == nullptr) { - base::Vector<char> dst = base::Vector<char>::New(len + 1); - base::StrNCpy(dst, src, len); + base::UniqueArray<char> dst = + base::UniqueArray<char>::NewForOverwrite(len + 1); + base::StrNCpy(dst.as_span(), src, len); dst[len] = '\0'; - entry->key = dst.begin(); + entry->key = dst.ReleaseData().release(); string_size_ += len; } entry->value = @@ -78,10 +80,12 @@ const char* StringsStorage::GetCopy(const AstRawString* src) { base::MutexGuard guard(&mutex_); base::HashMap::Entry* entry = GetEntry(utf8_buffer.data(), bytes_written); if (entry->value == nullptr) { - base::Vector<char> dst = base::Vector<char>::New(bytes_written + 1); - base::StrNCpy(dst, utf8_buffer.data(), bytes_written); + base::UniqueArray<char> dst = + base::UniqueArray<char>::NewForOverwrite(bytes_written + 1); + base::StrNCpy(dst.as_span(), utf8_buffer.data(), + base::checked_cast<uint32_t>(bytes_written)); dst[bytes_written] = '\0'; - entry->key = dst.begin(); + entry->key = dst.ReleaseData().release(); string_size_ += bytes_written; } entry->value = @@ -113,12 +117,10 @@ const char* StringsStorage::AddOrDisposeString(char* str, size_t len) { } const char* StringsStorage::GetVFormatted(const char* format, va_list args) { - base::Vector<char> str = base::Vector<char>::New(4096); - int len = base::VSNPrintF(str, format, args); - if (len == -1) { - return AddOrDisposeString(str.begin(), strlen(str.begin())); - } - return AddOrDisposeString(str.begin(), len); + base::UniqueArray<char> str = base::UniqueArray<char>::NewForOverwrite(4096); + int len = base::VSNPrintF(str.as_span(), format, args); + size_t str_len = (len == -1) ? strlen(str.begin()) : static_cast<size_t>(len); + return AddOrDisposeString(str.ReleaseData().release(), str_len); } const char* StringsStorage::GetSymbol(Tagged<Symbol> sym) { diff --git a/deps/v8/src/profiler/tick-sample.cc b/deps/v8/src/profiler/tick-sample.cc index 1a1455f21b76..62e540cb040e 100644 --- a/deps/v8/src/profiler/tick-sample.cc +++ b/deps/v8/src/profiler/tick-sample.cc @@ -164,13 +164,11 @@ bool SimulatorHelper::FillRegisters(Isolate* isolate, } // namespace -DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate, - const RegisterState& reg_state, - RecordCEntryFrame record_c_entry_frame, - bool update_stats, - bool use_simulator_reg_state, - base::TimeDelta sampling_interval, - const std::optional<uint64_t> trace_id) { +DISABLE_ASAN void TickSample::Init( + Isolate* v8_isolate, const RegisterState& reg_state, + RecordCEntryFrame record_c_entry_frame, bool update_stats, + bool use_simulator_reg_state, base::TimeDelta sampling_interval, + const std::optional<uint64_t> trace_id, void* sample_context) { update_stats_ = update_stats; SampleInfo info; RegisterState regs = reg_state; @@ -212,6 +210,7 @@ DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate, } sampling_interval_ = sampling_interval; trace_id_ = trace_id; + sample_context_ = sample_context; timestamp = base::TimeTicks::Now(); } diff --git a/deps/v8/src/profiler/tick-sample.h b/deps/v8/src/profiler/tick-sample.h index b02400777d04..f5c06cb78ea0 100644 --- a/deps/v8/src/profiler/tick-sample.h +++ b/deps/v8/src/profiler/tick-sample.h @@ -39,7 +39,8 @@ struct V8_EXPORT TickSample { RecordCEntryFrame record_c_entry_frame, bool update_stats, bool use_simulator_reg_state = true, base::TimeDelta sampling_interval = base::TimeDelta(), - const std::optional<uint64_t> trace_id = std::nullopt); + const std::optional<uint64_t> trace_id = std::nullopt, + void* sample_context = nullptr); /** * Get a call stack sample from the isolate. * \param isolate The isolate. @@ -100,6 +101,8 @@ struct V8_EXPORT TickSample { bool update_stats_ = true; // An identifier to associate the sample with a trace event. std::optional<uint64_t> trace_id_; + // Embedder-supplied opaque value captured by SampleContextExtractor. + void* sample_context_ = nullptr; void* stack[kMaxFramesCount]; // Call stack. }; diff --git a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc index 034078fd4b43..9f899e1f7b7c 100644 --- a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.cc @@ -28,7 +28,8 @@ namespace regexp { * - r7 : Currently loaded character. Must be loaded using * LoadCurrentCharacter before using any of the dispatch methods. * - r8 : Points to tip of backtrack stack - * - r9 : Unused, might be used by C code and expected unchanged. + * - r9 : Address of the regexp stack's thread-local block, which holds the + * stack limit, memory top and saved stack pointer. * - r10 : End of input (points to byte after last character in input). * - r11 : Frame pointer. Used to access arguments, local variables and * RegExp registers. @@ -644,40 +645,27 @@ void RegExpMacroAssemblerARM::Fail() { } void RegExpMacroAssemblerARM::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(dst, Operand(ref)); - __ ldr(dst, MemOperand(dst)); + __ ldr(dst, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerARM::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(scratch, Operand(ref)); - __ str(src, MemOperand(scratch)); +void RegExpMacroAssemblerARM::StoreRegExpStackPointerToMemory(Register src) { + __ str(src, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerARM::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(scratch, Operand(ref)); - __ ldr(scratch, MemOperand(scratch)); + __ ldr(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ sub(scratch, stack_pointer, scratch); __ str(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); } void RegExpMacroAssemblerARM::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ ldr(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ mov(scratch, Operand(ref)); - __ ldr(scratch, MemOperand(scratch)); + __ ldr(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ add(stack_pointer_out, stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerARM::GetCode( @@ -731,6 +719,10 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM::GetCode( kBacktrackCountOffset - kSystemPointerSize); __ push(r0); // The regexp stack base ptr. + __ mov(regexp_stack(), + Operand(ExternalReference::address_of_regexp_stack_thread_local( + isolate()))); + // Initialize backtrack stack pointer. It must not be clobbered from here on. // Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == r8); @@ -763,7 +755,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM::GetCode( __ jmp(&return_r0); __ bind(&stack_limit_hit); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(extra_space_for_variables); __ cmp(r0, Operand::Zero()); // If returned value is non-zero, we exit with the returned value as result. @@ -953,7 +945,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM::GetCode( if (check_preempt_label_.is_linked()) { SafeCallTarget(&check_preempt_label_); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(); __ cmp(r0, Operand::Zero()); @@ -976,7 +968,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM::GetCode( // Call GrowStack(isolate). - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); static constexpr int kNumArguments = 1; __ PrepareCallCFunction(kNumArguments); @@ -1081,19 +1073,13 @@ void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) { } void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(r1, Operand(ref)); - __ ldr(r1, MemOperand(r1)); + __ ldr(r1, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ sub(r0, backtrack_stackpointer(), r1); __ str(r0, register_location(reg)); } void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(r0, Operand(ref)); - __ ldr(r0, MemOperand(r0)); + __ ldr(r0, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ ldr(backtrack_stackpointer(), register_location(reg)); __ add(backtrack_stackpointer(), backtrack_stackpointer(), r0); } @@ -1302,10 +1288,7 @@ void RegExpMacroAssemblerARM::CheckPreemption() { } void RegExpMacroAssemblerARM::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(r0, Operand(stack_limit)); - __ ldr(r0, MemOperand(r0)); + __ ldr(r0, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ cmp(backtrack_stackpointer(), Operand(r0)); SafeCall(&stack_overflow_label_, ls); } @@ -1314,9 +1297,7 @@ void RegExpMacroAssemblerARM::AssertAboveStackLimitMinusSlack() { DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(r0, Operand(l)); - __ ldr(r0, MemOperand(r0)); + __ ldr(r0, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ sub(r0, r0, Operand(Stack::kStackLimitSlackSize)); __ cmp(backtrack_stackpointer(), Operand(r0)); __ b(hi, &no_stack_overflow); diff --git a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h index 67d537359cfb..281f42e5a43b 100644 --- a/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/regexp/arm/regexp-macro-assembler-arm.h @@ -191,6 +191,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM // Register holding pointer to the current code object. static constexpr Register code_pointer() { return r5; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return r9; } + // Equivalent to a conditional branch to the label, unless the label // is nullptr, in which case it is a conditional Backtrack. void BranchOrBacktrack(Condition condition, Label* to); @@ -210,7 +215,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM inline void Pop(Register target); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); diff --git a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc index be8451c3a164..2ef8e623d78e 100644 --- a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc +++ b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.cc @@ -23,8 +23,8 @@ namespace regexp { /* * This assembler uses the following register assignment convention: - * - w19 : Used to temporarely store a value before a call to C code. - * See CheckNotBackReferenceIgnoreCase. + * - x19 : Address of the regexp stack's thread-local block, which holds + * the stack limit, memory top and saved stack pointer. * - x20 : Pointer to the current InstructionStream object, * it includes the heap object tag. * - w21 : Current position in input, as negative offset from @@ -312,10 +312,8 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( Label fallthrough; Register capture_start_offset = w10; - // Save the capture length in a callee-saved register so it will - // be preserved if we call a C helper. - Register capture_length = w19; - DCHECK(kCalleeSaved.IncludesAliasOf(capture_length)); + // The capture length is pushed around the call to the C helper below. + Register capture_length = w15; // Find length of back-referenced capture. DCHECK_EQ(0, start_reg % 2); @@ -412,6 +410,7 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( int argument_count = 4; PushCachedRegisters(); + __ Push(padreg, capture_length.X()); // Put arguments into arguments registers. // Parameters are @@ -445,6 +444,7 @@ void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase( // x0 is one of the registers used as a cache so it must be tested before // the cache is restored. __ Cmp(x0, 0); + __ Pop(capture_length.X(), padreg); PopCachedRegisters(); BranchOrBacktrack(eq, on_no_match); @@ -731,14 +731,8 @@ void RegExpMacroAssemblerARM64::EmitSkipUntilBitInTableSimdHelper( __ Umov(x9, result.V1D(), 0); __ Cbz(x9, &advance_vector); - auto extract_lowest_set_bit_index = [this](Register dst, Register src) { - // .. by reversing the bit order and counting leading zeroes. - __ Rbit(dst, src); - __ Clz(dst, dst); - }; - __ Bind(&process_next_bit); - extract_lowest_set_bit_index(x8, x9); + CountTrailingZeros(x8, x9); // Calculate character index = bit index / 4. __ Lsr(x8, x8, 2); @@ -755,7 +749,7 @@ void RegExpMacroAssemblerARM64::EmitSkipUntilBitInTableSimdHelper( on_match(w8, x9); // Clear the lowest set nibble. - extract_lowest_set_bit_index(x8, x9); + CountTrailingZeros(x8, x9); __ Mov(x10, 0xF); __ Lsl(x10, x10, x8); __ Bic(x9, x9, x10); @@ -811,6 +805,7 @@ void RegExpMacroAssemblerARM64::SkipUntilBitInTable( [&](Register index, Register callee_saved) { // No need to push callee_saved since we never fall through. __ Add(current_input_offset(), current_input_offset(), index); + LoadCurrentCharacterUnchecked(cp_offset, 1); __ B(on_match); }); Bind(&scalar); @@ -887,8 +882,7 @@ void RegExpMacroAssemblerARM64::SkipUntilCharAndSimd( // Match found. Calculate index and jump to on_match. __ Bind(&found); - __ Rbit(x8, x9); - __ Clz(x8, x8); + CountTrailingZeros(x8, x9); __ Lsr(x8, x8, 2); __ Add(current_input_offset(), current_input_offset(), w8); LoadCurrentCharacterUnchecked(cp_offset, 1); @@ -948,8 +942,7 @@ void RegExpMacroAssemblerARM64::SkipUntilCharSimd(int cp_offset, int advance_by, __ B(&simd_loop); __ Bind(&found); - __ Rbit(x8, x9); - __ Clz(x8, x8); + CountTrailingZeros(x8, x9); __ Lsr(x8, x8, 2); __ Add(current_input_offset(), current_input_offset(), w8); @@ -1017,8 +1010,7 @@ void RegExpMacroAssemblerARM64::SkipUntilCharOrCharSimd( __ B(&simd_loop); __ Bind(&found); - __ Rbit(x8, x9); - __ Clz(x8, x8); + CountTrailingZeros(x8, x9); __ Lsr(x8, x8, 2); __ Add(current_input_offset(), current_input_offset(), w8); @@ -1430,40 +1422,27 @@ void RegExpMacroAssemblerARM64::Fail() { } void RegExpMacroAssemblerARM64::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ Mov(dst, ref); - __ Ldr(dst, MemOperand(dst)); + __ Ldr(dst, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerARM64::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ Mov(scratch, ref); - __ Str(src, MemOperand(scratch)); +void RegExpMacroAssemblerARM64::StoreRegExpStackPointerToMemory(Register src) { + __ Str(src, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerARM64::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ Mov(scratch, ref); - __ Ldr(scratch, MemOperand(scratch)); + __ Ldr(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Sub(scratch, stack_pointer, scratch); __ Str(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); } void RegExpMacroAssemblerARM64::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ Ldr(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ Mov(scratch, ref); - __ Ldr(scratch, MemOperand(scratch)); + __ Ldr(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Add(stack_pointer_out, stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerARM64::GetCode( @@ -1530,6 +1509,9 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM64::GetCode( // pointer. Patterns that never do skip the backtrack stack setup, the fail // label, and the teardown below. if (backtrack_stack_used()) { + __ Mov(regexp_stack(), + ExternalReference::address_of_regexp_stack_thread_local(isolate())); + // Initialize backtrack stack pointer. It must not be clobbered from here // on. Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == x23); @@ -1588,7 +1570,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM64::GetCode( // initialized above; storing it would corrupt the saved stack pointer // (regexp::StackScope verifies it is unchanged across the exec call). if (backtrack_stack_used()) { - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); } CallCheckStackGuardState(x10, extra_space_for_variables); // If returned value is non-zero, we exit with the returned value as result. @@ -1863,7 +1845,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM64::GetCode( // so a linked preempt target implies the backtrack stack is live and its // pointer is initialized for the store/reload below. DCHECK(backtrack_stack_used()); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); SaveLinkRegister(); PushCachedRegisters(); @@ -1883,7 +1865,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerARM64::GetCode( if (stack_overflow_label_.is_linked()) { __ Bind(&stack_overflow_label_); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); SaveLinkRegister(); PushCachedRegisters(); @@ -2014,10 +1996,7 @@ void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) { void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) { set_backtrack_stack_used(); - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ Mov(x10, ref); - __ Ldr(x10, MemOperand(x10)); + __ Ldr(x10, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Sub(x10, backtrack_stackpointer(), x10); if (v8_flags.debug_code) { __ Cmp(x10, Operand(w10, SXTW)); @@ -2029,11 +2008,8 @@ void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) { void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(int reg) { set_backtrack_stack_used(); - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); Register read_from = GetRegister(reg, w10); - __ Mov(x11, ref); - __ Ldr(x11, MemOperand(x11)); + __ Ldr(x11, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW)); } @@ -2288,6 +2264,17 @@ void RegExpMacroAssemblerARM64::TestBitAndBranchOrBacktrack(Register reg, } } +void RegExpMacroAssemblerARM64::CountTrailingZeros(Register dst, Register src) { + if (CpuFeatures::IsSupported(CSSC)) { + CpuFeatureScope scope(masm_.get(), CSSC); + __ Ctz(dst, src); + } else { + // Reverse the bit order and count leading zeroes. + __ Rbit(dst, src); + __ Clz(dst, dst); + } +} + void RegExpMacroAssemblerARM64::CallCFunctionFromIrregexpCode( ExternalReference function, int num_arguments) { // Irregexp code must not set fast_c_call_caller_fp and fast_c_call_caller_pc @@ -2314,21 +2301,18 @@ void RegExpMacroAssemblerARM64::CheckPreemption() { } void RegExpMacroAssemblerARM64::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ Mov(x10, stack_limit); - __ Ldr(x10, MemOperand(x10)); + DCHECK(backtrack_stack_used()); + __ Ldr(x10, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ Cmp(backtrack_stackpointer(), x10); CallIf(&stack_overflow_label_, ls); } void RegExpMacroAssemblerARM64::AssertAboveStackLimitMinusSlack() { + DCHECK(backtrack_stack_used()); DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ Mov(x10, l); - __ Ldr(x10, MemOperand(x10)); + __ Ldr(x10, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ Sub(x10, x10, Stack::kStackLimitSlackSize); __ Cmp(backtrack_stackpointer(), x10); __ B(hi, &no_stack_overflow); diff --git a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h index b62d736000f3..b6692de3b151 100644 --- a/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h +++ b/deps/v8/src/regexp/arm64/regexp-macro-assembler-arm64.h @@ -255,6 +255,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 // Register holding pointer to the current code object. static constexpr Register code_pointer() { return x20; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return x19; } + // Register holding the value used for clearing capture registers. static constexpr Register string_start_minus_one() { return w24; } // The top 32 bit of this register is used to store this value @@ -283,6 +288,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 void TestBitAndBranchOrBacktrack(Register reg, int bit, bool jump_if_set, Label* to); + // Sets dst to the index of the lowest set bit in src (64 for zero). + void CountTrailingZeros(Register dst, Register src); + inline void CallIf(Label* to, Condition condition); // Save and restore the link register on the stack in a way that @@ -337,7 +345,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 inline Register GetCachedRegister(int register_index); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); diff --git a/deps/v8/src/regexp/experimental/experimental-bytecode.cc b/deps/v8/src/regexp/experimental/experimental-bytecode.cc index ffc73142405b..948031a94b0b 100644 --- a/deps/v8/src/regexp/experimental/experimental-bytecode.cc +++ b/deps/v8/src/regexp/experimental/experimental-bytecode.cc @@ -17,7 +17,7 @@ std::ostream& PrintAsciiOrHex(std::ostream& os, base::uc16 c) { if (c < 128 && std::isprint(c)) { os << static_cast<char>(c); } else { - os << "0x" << std::hex << static_cast<int>(c); + os << "0x" << std::hex << static_cast<int>(c) << std::dec; } return os; } diff --git a/deps/v8/src/regexp/gen-regexp-special-case.cc b/deps/v8/src/regexp/gen-regexp-special-case.cc index db408405ba59..7c05a7b07500 100644 --- a/deps/v8/src/regexp/gen-regexp-special-case.cc +++ b/deps/v8/src/regexp/gen-regexp-special-case.cc @@ -10,6 +10,7 @@ #include "src/base/strings.h" #include "src/regexp/special-case.h" #include "unicode/locid.h" +#include "unicode/uchar.h" #include "unicode/unistr.h" namespace v8 { @@ -52,6 +53,19 @@ UChar32 Canonicalize(UChar32 ch) { return cu; } +// Removes supplementary code points from |set| and returns whether any were +// present. Since Unicode 18, the case closure of a BMP character can contain +// supplementary code points (U+1DF95 LATIN SMALL LIGATURE LONG S WITH +// DESCENDER S case-folds to U+00DF LATIN SMALL LETTER SHARP S). Non-unicode +// ignoreCase matching compares UTF-16 code units, so a supplementary code +// point never matches a BMP character and does not take part in Canonicalize. +bool RemoveSupplementary(icu::UnicodeSet& set) { + constexpr UChar32 kFirstSupplementary = static_cast<UChar32>(kNonBmpStart); + if (!set.containsSome(kFirstSupplementary, UCHAR_MAX_VALUE)) return false; + set.remove(kFirstSupplementary, UCHAR_MAX_VALUE); + return true; +} + // The following code generates "src/regexp/special-case.cc". void PrintSet(std::ofstream& out, const char* name, const icu::UnicodeSet& set) { @@ -86,6 +100,7 @@ void PrintSpecial(std::ofstream& out) { icu::UnicodeSet current; icu::UnicodeSet special_add; icu::UnicodeSet ignore; + icu::UnicodeSet supplementary_equivalents; UErrorCode status = U_ZERO_ERROR; icu::UnicodeSet upper("[\\p{Lu}]", status); CHECK(U_SUCCESS(status)); @@ -98,6 +113,7 @@ void PrintSpecial(std::ofstream& out) { } current.set(i, i); current.closeOver(USET_SIMPLE_CASE_INSENSITIVE); + if (RemoveSupplementary(current)) supplementary_equivalents.add(i); // Check to see if all characters in the case-folding equivalence // class as defined by UnicodeSet::closeOver all map to the same @@ -147,6 +163,7 @@ void PrintSpecial(std::ofstream& out) { UChar32 canonical = Canonicalize(c); current.set(c, c); current.closeOver(USET_SIMPLE_CASE_INSENSITIVE); + RemoveSupplementary(current); current.removeAll(ignore); for (int32_t j = 0; j < current.getRangeCount(); j++) { for (UChar32 c2 = current.getRangeStart(j); @@ -158,6 +175,7 @@ void PrintSpecial(std::ofstream& out) { } PrintSet(out, "IgnoreSet", ignore); + PrintSet(out, "SupplementaryEquivalentsSet", supplementary_equivalents); } void WriteHeader(const char* header_filename) { @@ -181,6 +199,7 @@ void WriteHeader(const char* header_filename) { << "namespace regexp {\n\n"; PrintSpecial(out); + out << std::dec; out << "\n" << "} // namespace regexp\n" diff --git a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc index 030f1cbbf47a..b434056479bb 100644 --- a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc +++ b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.cc @@ -707,36 +707,26 @@ void RegExpMacroAssemblerIA32::Fail() { } void RegExpMacroAssemblerIA32::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(dst, __ ExternalReferenceAsOperand(ref, dst)); + __ mov(dst, RegExpStackField(Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerIA32::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(__ ExternalReferenceAsOperand(ref, scratch), src); +void RegExpMacroAssemblerIA32::StoreRegExpStackPointerToMemory(Register src) { + __ mov(RegExpStackField(Stack::kStackPointerOffset), src); } void RegExpMacroAssemblerIA32::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(scratch, __ ExternalReferenceAsOperand(ref, scratch)); + __ mov(scratch, RegExpStackField(Stack::kMemoryTopOffset)); __ sub(scratch, stack_pointer); __ mov(Operand(ebp, kRegExpStackBasePointerOffset), scratch); } void RegExpMacroAssemblerIA32::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ mov(scratch, Operand(ebp, kRegExpStackBasePointerOffset)); - __ mov(stack_pointer_out, - __ ExternalReferenceAsOperand(ref, stack_pointer_out)); + __ mov(stack_pointer_out, RegExpStackField(Stack::kMemoryTopOffset)); __ sub(stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerIA32::GetCode( @@ -808,7 +798,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerIA32::GetCode( __ jmp(&return_eax); __ bind(&stack_limit_hit); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(ebx, extra_space_for_variables); __ or_(eax, eax); // If returned value is non-zero, we exit with the returned value as result. @@ -1006,7 +996,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerIA32::GetCode( if (check_preempt_label_.is_linked()) { SafeCallTarget(&check_preempt_label_); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); __ push(edi); @@ -1034,7 +1024,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerIA32::GetCode( __ push(esi); __ push(edi); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); // Call GrowStack(isolate). static const int kNumArguments = 1; @@ -1139,19 +1129,13 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { } void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { - ExternalReference stack_top_address = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(eax, __ ExternalReferenceAsOperand(stack_top_address, eax)); + __ mov(eax, RegExpStackField(Stack::kMemoryTopOffset)); __ sub(eax, backtrack_stackpointer()); __ mov(register_location(reg), eax); } void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { - ExternalReference stack_top_address = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(backtrack_stackpointer(), - __ ExternalReferenceAsOperand(stack_top_address, - backtrack_stackpointer())); + __ mov(backtrack_stackpointer(), RegExpStackField(Stack::kMemoryTopOffset)); __ sub(backtrack_stackpointer(), register_location(reg)); } @@ -1219,6 +1203,14 @@ Operand RegExpMacroAssemblerIA32::StaticVariable(const ExternalReference& ext) { return Operand(ext.address(), RelocInfo::EXTERNAL_REFERENCE); } +Operand RegExpMacroAssemblerIA32::RegExpStackField(int offset) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_thread_local(isolate()); + // Not an external reference of its own: the field address is derived from + // one, and regexp code is never serialized. + return Operand(ref.address() + offset, RelocInfo::NO_INFO); +} + // Helper function for reading a value out of a stack frame. template <typename T> static T& frame_entry(Address re_frame, int frame_offset) { @@ -1325,9 +1317,7 @@ void RegExpMacroAssemblerIA32::CheckPreemption() { void RegExpMacroAssemblerIA32::CheckStackLimit() { Label no_stack_overflow; - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ cmp(backtrack_stackpointer(), StaticVariable(stack_limit)); + __ cmp(backtrack_stackpointer(), RegExpStackField(Stack::kLimitOffset)); __ j(above, &no_stack_overflow, Label::kNear); SafeCall(&stack_overflow_label_); @@ -1339,8 +1329,7 @@ void RegExpMacroAssemblerIA32::AssertAboveStackLimitMinusSlack() { DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(eax, __ ExternalReferenceAsOperand(l, eax)); + __ mov(eax, RegExpStackField(Stack::kLimitOffset)); __ sub(eax, Immediate(Stack::kStackLimitSlackSize)); __ cmp(backtrack_stackpointer(), eax); __ j(above, &no_stack_overflow, Label::kNear); diff --git a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h index 000725e4cb18..063db39b1296 100644 --- a/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h +++ b/deps/v8/src/regexp/ia32/regexp-macro-assembler-ia32.h @@ -103,6 +103,9 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 private: Operand StaticVariable(const ExternalReference& ext); + // The field at the given offset of the regexp stack's thread-local block, + // addressed absolutely. + Operand RegExpStackField(int offset); // Offsets from ebp of function parameters and stored registers. static constexpr int kFramePointerOffset = 0; // Above the frame pointer - function parameters and return address. @@ -207,7 +210,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 inline void Pop(Register target); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); diff --git a/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.cc b/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.cc index df7e96afffe4..8068383420ad 100644 --- a/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.cc +++ b/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.cc @@ -20,7 +20,8 @@ namespace regexp { /* clang-format off * * This assembler uses the following register assignment convention - * - s0 : Unused. + * - s0 : Address of the regexp stack's thread-local block, which holds the + * stack limit, memory top and saved stack pointer. * - s1 : Pointer to current InstructionStream object including heap object tag. * - s2 : Current position in input, as negative offset from end of string. * Please notice that this is the byte offset, not the character offset! @@ -622,40 +623,28 @@ void RegExpMacroAssemblerLOONG64::Fail() { void RegExpMacroAssemblerLOONG64::LoadRegExpStackPointerFromMemory( Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ li(dst, ref); - __ Ld_d(dst, MemOperand(dst, 0)); + __ Ld_d(dst, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerLOONG64::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ li(scratch, ref); - __ St_d(src, MemOperand(scratch, 0)); + Register src) { + __ St_d(src, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerLOONG64::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(scratch, ref); - __ Ld_d(scratch, MemOperand(scratch, 0)); + __ Ld_d(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Sub_d(scratch, stack_pointer, scratch); __ St_d(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); } void RegExpMacroAssemblerLOONG64::PopRegExpBasePointer( Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ Ld_d(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ li(scratch, ref); - __ Ld_d(scratch, MemOperand(scratch, 0)); + __ Ld_d(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Add_d(stack_pointer_out, stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode( @@ -726,6 +715,9 @@ DirectHandle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode( // pointer. Patterns that never do skip the backtrack stack setup, the fail // label, and the teardown below. if (backtrack_stack_used()) { + __ li(regexp_stack(), + ExternalReference::address_of_regexp_stack_thread_local(isolate())); + // Initialize backtrack stack pointer. It must not be clobbered from here // on. Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == s7); @@ -776,7 +768,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode( // initialized above; storing it would corrupt the saved stack pointer // (regexp::StackScope verifies it is unchanged across the exec call). if (backtrack_stack_used()) { - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); } CallCheckStackGuardState(a0, extra_space_for_variables); // If returned value is non-zero, we exit with the returned value as @@ -1000,7 +992,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode( // pointer is initialized for the store/reload below. DCHECK(backtrack_stack_used()); // Put regexp engine registers on stack. - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(a0); // If returning non-zero, we should end execution with the given @@ -1019,7 +1011,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode( // Backtrack stack overflow code. if (stack_overflow_label_.is_linked()) { SafeCallTarget(&stack_overflow_label_); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); // Reached if the backtrack-stack limit has been hit. // Call GrowStack(isolate). @@ -1150,20 +1142,15 @@ void RegExpMacroAssemblerLOONG64::ReadCurrentPositionFromRegister(int reg) { void RegExpMacroAssemblerLOONG64::WriteStackPointerToRegister(int reg) { set_backtrack_stack_used(); - ExternalReference stack_top_address = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(a0, stack_top_address); - __ Ld_d(a0, MemOperand(a0, 0)); + __ Ld_d(a0, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Sub_d(a0, backtrack_stackpointer(), a0); __ St_d(a0, register_location(reg)); } void RegExpMacroAssemblerLOONG64::ReadStackPointerFromRegister(int reg) { set_backtrack_stack_used(); - ExternalReference stack_top_address = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(backtrack_stackpointer(), stack_top_address); - __ Ld_d(backtrack_stackpointer(), MemOperand(backtrack_stackpointer(), 0)); + __ Ld_d(backtrack_stackpointer(), + MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Ld_d(a0, register_location(reg)); __ Add_d(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0)); } @@ -1379,30 +1366,17 @@ void RegExpMacroAssemblerLOONG64::CheckPreemption() { } void RegExpMacroAssemblerLOONG64::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address( - masm_->isolate()); - - __ li(a0, Operand(stack_limit)); - __ Ld_d(a0, MemOperand(a0, 0)); + DCHECK(backtrack_stack_used()); + __ Ld_d(a0, MemOperand(regexp_stack(), Stack::kLimitOffset)); SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0)); } void RegExpMacroAssemblerLOONG64::AssertAboveStackLimitMinusSlack() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address( - masm_->isolate()); - - __ li(a0, Operand(stack_limit)); - __ Ld_d(a0, MemOperand(a0, 0)); - SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0)); - + DCHECK(backtrack_stack_used()); DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ li(a0, l); - __ Ld_d(a0, MemOperand(a0, 0)); + __ Ld_d(a0, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ Sub_d(a0, a0, Operand(Stack::kStackLimitSlackSize)); __ Branch(&no_stack_overflow, hi, backtrack_stackpointer(), Operand(a0)); __ DebugBreak(); diff --git a/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.h b/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.h index 655e2ae2b21b..132d71bd24af 100644 --- a/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.h +++ b/deps/v8/src/regexp/loong64/regexp-macro-assembler-loong64.h @@ -202,6 +202,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerLOONG64 // Register holding pointer to the current code object. static constexpr Register code_pointer() { return s1; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return s0; } + // The real backtrack dispatch (pop a code offset and jump to it), emitted // once in GetCode at backtrack_label_ when the backtrack stack is used. // Backtrack() itself only jumps there, so emitting it does not by itself @@ -229,7 +234,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerLOONG64 inline void Pop(Register target); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); diff --git a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc index f98a5286fdf5..ce5956a8c531 100644 --- a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc +++ b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.cc @@ -21,7 +21,8 @@ namespace regexp { /* clang-format off * * This assembler uses the following register assignment convention - * - s0 : Unused. + * - s0 : Address of the regexp stack's thread-local block, which holds the + * stack limit, memory top and saved stack pointer. * - s1 : Pointer to current InstructionStream object including heap object tag. * - s2 : Current position in input, as negative offset from end of string. * Please notice that this is the byte offset, not the character offset! @@ -138,6 +139,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone, backtrack_label_(), exit_label_(), internal_failure_label_() { + masm()->GetScratchRegisterList()->clear(s0); + DCHECK_EQ(0, registers_to_save % 2); __ jmp(&entry_label_); // We'll write the entry code later. // If the code gets too big or corrupted, an internal exception will be @@ -159,6 +162,7 @@ RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() { stack_overflow_label_.Unuse(); internal_failure_label_.Unuse(); fallback_label_.Unuse(); + masm()->GetScratchRegisterList()->set(s0); } void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) { @@ -656,40 +660,27 @@ void RegExpMacroAssemblerMIPS::Fail() { } void RegExpMacroAssemblerMIPS::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ li(dst, Operand(ref)); - __ Ld(dst, MemOperand(dst)); + __ Ld(dst, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerMIPS::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ li(scratch, Operand(ref)); - __ Sd(src, MemOperand(scratch)); +void RegExpMacroAssemblerMIPS::StoreRegExpStackPointerToMemory(Register src) { + __ Sd(src, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerMIPS::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(scratch, Operand(ref)); - __ Ld(scratch, MemOperand(scratch)); + __ Ld(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Dsubu(scratch, stack_pointer, scratch); __ Sd(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); } void RegExpMacroAssemblerMIPS::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ Ld(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ li(scratch, Operand(ref)); - __ Ld(scratch, MemOperand(scratch)); + __ Ld(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Daddu(stack_pointer_out, stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerMIPS::GetCode( @@ -760,6 +751,10 @@ DirectHandle<HeapObject> RegExpMacroAssemblerMIPS::GetCode( // pointer. Patterns that never do skip the backtrack stack setup, the fail // label, and the teardown below. if (backtrack_stack_used()) { + __ li(regexp_stack(), + Operand(ExternalReference::address_of_regexp_stack_thread_local( + isolate()))); + // Initialize backtrack stack pointer. It must not be clobbered from here // on. Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == s7); @@ -810,7 +805,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerMIPS::GetCode( // initialized above; storing it would corrupt the saved stack pointer // (regexp::StackScope verifies it is unchanged across the exec call). if (backtrack_stack_used()) { - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a0); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); } CallCheckStackGuardState(a0, extra_space_for_variables); // If returned value is non-zero, we exit with the returned value as @@ -1032,7 +1027,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerMIPS::GetCode( // so a linked preempt target implies the backtrack stack is live and its // pointer is initialized for the store/reload below. DCHECK(backtrack_stack_used()); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a0); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(a0); // If returning non-zero, we should end execution with the given @@ -1050,7 +1045,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerMIPS::GetCode( // Backtrack stack overflow code. if (stack_overflow_label_.is_linked()) { SafeCallTarget(&stack_overflow_label_); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a0); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); // Reached if the backtrack-stack limit has been hit. // Call GrowStack(isolate) @@ -1180,20 +1175,14 @@ void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) { void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) { set_backtrack_stack_used(); - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(a0, Operand(ref)); - __ Ld(a0, MemOperand(a0)); + __ Ld(a0, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Dsubu(a0, backtrack_stackpointer(), a0); __ Sd(a0, register_location(reg)); } void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) { set_backtrack_stack_used(); - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(a0, Operand(ref)); - __ Ld(a0, MemOperand(a0)); + __ Ld(a0, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Ld(backtrack_stackpointer(), register_location(reg)); __ Daddu(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0)); } @@ -1412,30 +1401,17 @@ void RegExpMacroAssemblerMIPS::CheckPreemption() { } void RegExpMacroAssemblerMIPS::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address( - masm_->isolate()); - - __ li(a0, Operand(stack_limit)); - __ Ld(a0, MemOperand(a0)); + DCHECK(backtrack_stack_used()); + __ Ld(a0, MemOperand(regexp_stack(), Stack::kLimitOffset)); SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0)); } void RegExpMacroAssemblerMIPS::AssertAboveStackLimitMinusSlack() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address( - masm_->isolate()); - - __ li(a0, Operand(stack_limit)); - __ Ld(a0, MemOperand(a0)); - SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0)); - + DCHECK(backtrack_stack_used()); DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ li(a0, l); - __ Ld(a0, MemOperand(a0)); + __ Ld(a0, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ Dsubu(a0, a0, Operand(Stack::kStackLimitSlackSize)); __ Branch(&no_stack_overflow, hi, backtrack_stackpointer(), Operand(a0)); __ DebugBreak(); diff --git a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h index c633cf081241..4fe2eb807eab 100644 --- a/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h +++ b/deps/v8/src/regexp/mips64/regexp-macro-assembler-mips64.h @@ -201,6 +201,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerMIPS // Register holding pointer to the current code object. static constexpr Register code_pointer() { return s1; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return s0; } + // The real backtrack dispatch (pop a code offset and jump to it), emitted // once in GetCode at backtrack_label_ when the backtrack stack is used. // Backtrack() itself only jumps there, so emitting it does not by itself @@ -232,7 +237,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerMIPS inline void Pop(Register target); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); diff --git a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc index e73af0865161..febc24dce907 100644 --- a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc +++ b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.cc @@ -20,6 +20,8 @@ namespace regexp { /* * This assembler uses the following register assignment convention + * - r24: Address of the regexp stack's thread-local block, which holds the + * stack limit, memory top and saved stack pointer. * - r25: Temporarily stores the index of capture start after a matching pass * for a global regexp. * - r26: Pointer to current InstructionStream object including heap object tag. @@ -47,7 +49,7 @@ namespace regexp { * --- sp when called --- * - fp[28] return address (lr). * - fp[24] old frame pointer (r31). - * - fp[0..20] backup of registers r25..r30 + * - fp[0..24] backup of registers r24..r30 * --- frame pointer ---- * - fp[-4] frame marker * - fp[-8] isolate @@ -681,26 +683,16 @@ void RegExpMacroAssemblerPPC::Fail() { } void RegExpMacroAssemblerPPC::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(dst, Operand(ref)); - __ LoadU64(dst, MemOperand(dst)); + __ LoadU64(dst, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerPPC::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(scratch, Operand(ref)); - __ StoreU64(src, MemOperand(scratch)); +void RegExpMacroAssemblerPPC::StoreRegExpStackPointerToMemory(Register src) { + __ StoreU64(src, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerPPC::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(scratch, Operand(ref)); - __ LoadU64(scratch, MemOperand(scratch)); + __ LoadU64(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ SubS64(scratch, stack_pointer, scratch); __ StoreU64(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); @@ -708,14 +700,11 @@ void RegExpMacroAssemblerPPC::PushRegExpBasePointer(Register stack_pointer, void RegExpMacroAssemblerPPC::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ LoadU64(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ mov(scratch, Operand(ref)); - __ LoadU64(scratch, MemOperand(scratch)); + __ LoadU64(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ AddS64(stack_pointer_out, stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( @@ -740,6 +729,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( // Ensure register assigments are consistent with callee save mask DCHECK(kRegExpCalleeSaved.has(r25)); + DCHECK(kRegExpCalleeSaved.has(regexp_stack())); DCHECK(kRegExpCalleeSaved.has(code_pointer())); DCHECK(kRegExpCalleeSaved.has(current_input_offset())); DCHECK(kRegExpCalleeSaved.has(current_character())); @@ -775,6 +765,10 @@ DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( kBacktrackCountOffset - kSystemPointerSize); __ push(r3); // The regexp stack base ptr. + __ mov(regexp_stack(), + Operand(ExternalReference::address_of_regexp_stack_thread_local( + isolate()))); + // Initialize backtrack stack pointer. It must not be clobbered from here // on. Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == r29); @@ -816,7 +810,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( __ b(&return_r3); __ bind(&stack_limit_hit); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r4); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(r3, extra_space_for_variables); __ cmpi(r3, Operand::Zero()); // If returned value is non-zero, we exit with the returned value as @@ -1003,7 +997,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( // Skip sp past regexp registers and local variables.. __ mr(sp, frame_pointer()); - // Restore registers r25..r31 and return (restoring lr to pc). + // Restore registers r24..r31 and return (restoring lr to pc). __ MultiPop(registers_to_retain); __ PopLR(); __ blr(); @@ -1020,7 +1014,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( if (check_preempt_label_.is_linked()) { SafeCallTarget(&check_preempt_label_); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r4); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(r3); __ cmpi(r3, Operand::Zero()); @@ -1042,7 +1036,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerPPC::GetCode( // Call GrowStack(isolate). - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r4); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); static constexpr int kNumArguments = 1; __ PrepareCallCFunction(kNumArguments); @@ -1148,19 +1142,13 @@ void RegExpMacroAssemblerPPC::ReadCurrentPositionFromRegister(int reg) { } void RegExpMacroAssemblerPPC::WriteStackPointerToRegister(int reg) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(r4, Operand(ref)); - __ LoadU64(r4, MemOperand(r4)); + __ LoadU64(r4, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ SubS64(r3, backtrack_stackpointer(), r4); __ StoreU64(r3, register_location(reg)); } void RegExpMacroAssemblerPPC::ReadStackPointerFromRegister(int reg) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(r3, Operand(ref)); - __ LoadU64(r3, MemOperand(r3)); + __ LoadU64(r3, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ LoadU64(backtrack_stackpointer(), register_location(reg)); __ AddS64(backtrack_stackpointer(), backtrack_stackpointer(), r3); } @@ -1403,10 +1391,7 @@ void RegExpMacroAssemblerPPC::CheckPreemption() { } void RegExpMacroAssemblerPPC::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(r3, Operand(stack_limit)); - __ LoadU64(r3, MemOperand(r3)); + __ LoadU64(r3, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ CmpU64(backtrack_stackpointer(), r3); SafeCall(&stack_overflow_label_, le); } @@ -1415,9 +1400,7 @@ void RegExpMacroAssemblerPPC::AssertAboveStackLimitMinusSlack() { DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(r3, Operand(l)); - __ LoadU64(r3, MemOperand(r3)); + __ LoadU64(r3, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ SubS64(r3, r3, Operand(Stack::kStackLimitSlackSize)); __ CmpU64(backtrack_stackpointer(), r3); __ bgt(&no_stack_overflow); diff --git a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h index a96caa4cc776..c6efc8ed03b8 100644 --- a/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h +++ b/deps/v8/src/regexp/ppc/regexp-macro-assembler-ppc.h @@ -108,7 +108,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerPPC static constexpr int kStoredRegistersOffset = kFramePointerOffset; // Return address (stored from link register, read into pc on return). static constexpr int kReturnAddressOffset = - kStoredRegistersOffset + 7 * kSystemPointerSize; + kStoredRegistersOffset + 8 * kSystemPointerSize; static constexpr int kCallerFrameOffset = kReturnAddressOffset + kSystemPointerSize; @@ -193,6 +193,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerPPC // Register holding pointer to the current code object. static constexpr Register code_pointer() { return r26; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return r24; } + // Equivalent to a conditional branch to the label, unless the label // is nullptr, in which case it is a conditional Backtrack. void BranchOrBacktrack(Condition condition, Label* to, CRegister cr = cr0); @@ -212,7 +217,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerPPC inline void Pop(Register target); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); @@ -241,7 +246,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerPPC }; // Set of non-volatile registers saved/restored by generated regexp code. -const RegList kRegExpCalleeSaved = {r25, r26, r27, r28, r29, r30, fp}; +const RegList kRegExpCalleeSaved = {r24, r25, r26, r27, r28, r29, r30, fp}; } // namespace regexp } // namespace internal diff --git a/deps/v8/src/regexp/regexp-ast.h b/deps/v8/src/regexp/regexp-ast.h index 4f4aad14e00e..602406ab550b 100644 --- a/deps/v8/src/regexp/regexp-ast.h +++ b/deps/v8/src/regexp/regexp-ast.h @@ -656,8 +656,8 @@ class Capture final : public Tree { DECL_BOILERPLATE(Capture); - static Node* ToNode(Tree* body, int index, Compiler* compiler, - Node* on_success); + static Node* ToNode(Tree* body, Compiler* compiler, Node* on_success, + const Capture* capture); bool IsCertainlyAnchoredAtStart(int budget) override; bool IsCertainlyAnchoredAtEnd(int budget) override; Interval CaptureRegisters(StackLimiter limiter) override; @@ -670,6 +670,8 @@ class Capture final : public Tree { max_match_ = body->max_match(); } int index() const { return index_; } + bool is_backreferenced() const { return is_backreferenced_; } + void set_is_backreferenced() { is_backreferenced_ = true; } const ZoneVector<base::uc16>* name() const { return name_; } void set_name(const ZoneVector<base::uc16>* name) { name_ = name; } static int StartRegister(int index) { return index * 2; } @@ -681,6 +683,8 @@ class Capture final : public Tree { int min_match_ = 0; int max_match_ = 0; const ZoneVector<base::uc16>* name_ = nullptr; + // Set during backreference lowering; queried after lowering is complete. + bool is_backreferenced_ = false; }; class Group final : public Tree { diff --git a/deps/v8/src/regexp/regexp-bytecode-generator-inl.h b/deps/v8/src/regexp/regexp-bytecode-generator-inl.h index 62ece53f0752..8e310e7396c9 100644 --- a/deps/v8/src/regexp/regexp-bytecode-generator-inl.h +++ b/deps/v8/src/regexp/regexp-bytecode-generator-inl.h @@ -8,6 +8,8 @@ #include "src/regexp/regexp-bytecode-generator.h" // Include the non-inl header before the rest of the headers. +#include <bit> + #include "src/regexp/regexp-bytecodes-inl.h" namespace v8 { @@ -56,7 +58,7 @@ void BytecodeWriter::EnsureCapacity(size_t size_delta) { size = kInitialBufferSizeInBytes; } else if (required_size <= kMaxBufferGrowthInBytes) { // We use a doubling strategy until hitting the limit. - size = base::bits::RoundUpToPowerOfTwo(required_size); + size = std::bit_ceil(required_size); } else { // .. and kMaxBufferGrowthInBytes chunks afterwards. size = RoundUp<kMaxBufferGrowthInBytes>(required_size); diff --git a/deps/v8/src/regexp/regexp-compiler-tonode.cc b/deps/v8/src/regexp/regexp-compiler-tonode.cc index 2ae70c3fe7ed..87ec716f21fa 100644 --- a/deps/v8/src/regexp/regexp-compiler-tonode.cc +++ b/deps/v8/src/regexp/regexp-compiler-tonode.cc @@ -1376,6 +1376,7 @@ Node* BackReference::ToNodeImpl(Compiler* compiler, Node* on_success) { // back-references to unmatched captures are treated as empty, we can simply // create back-references to all possible captures. for (auto capture : *captures()) { + capture->set_is_backreferenced(); backref_node = compiler->zone()->New<BackReferenceNode>( Capture::StartRegister(capture->index()), Capture::EndRegister(capture->index()), compiler->read_backward(), @@ -1485,23 +1486,24 @@ Node* Lookaround::ToNodeImpl(Compiler* compiler, Node* on_success) { } Node* Capture::ToNodeImpl(Compiler* compiler, Node* on_success) { - return ToNode(body(), index(), compiler, on_success); + return ToNode(body(), compiler, on_success, this); } // static -Node* Capture::ToNode(Tree* body, int index, Compiler* compiler, - Node* on_success) { +Node* Capture::ToNode(Tree* body, Compiler* compiler, Node* on_success, + const Capture* capture) { DCHECK_NOT_NULL(body); + int index = capture == nullptr ? 0 : capture->index(); int start_reg = Capture::StartRegister(index); int end_reg = Capture::EndRegister(index); if (compiler->read_backward()) std::swap(start_reg, end_reg); - Node* store_end = - ActionNode::StorePosition(end_reg, on_success, compiler->flags()); + Node* store_end = ActionNode::StorePosition(end_reg, on_success, + compiler->flags(), capture); REGISTER_NODE(store_end); Node* body_node = body->ToNode(compiler, store_end); if (body_node->IsBacktrack()) return body_node; - Node* node = - ActionNode::StorePosition(start_reg, body_node, compiler->flags()); + Node* node = ActionNode::StorePosition(start_reg, body_node, + compiler->flags(), capture); REGISTER_NODE(node); return node; } diff --git a/deps/v8/src/regexp/regexp-compiler.cc b/deps/v8/src/regexp/regexp-compiler.cc index 8d2c947bd186..9acc16700627 100644 --- a/deps/v8/src/regexp/regexp-compiler.cc +++ b/deps/v8/src/regexp/regexp-compiler.cc @@ -369,6 +369,17 @@ Compiler::CompilationResult Compiler::Assemble( // the pattern never backtracks and drop the push (and the stack) entirely. macro_assembler_->PushBacktrack(&fail); } + const bool may_step_back = + !one_byte() && ShouldOptionallyStepBackToLeadSurrogate(flags()); + NonAssertingLabel check_lead_surrogate(this); + Label not_in_surrogate_pair; + if (may_step_back) { + // Normalize the starting position before matching. + macro_assembler_->LoadCurrentCharacter(0, ¬_in_surrogate_pair); + macro_assembler_->CheckCharacterInRange( + kTrailSurrogateStart, kTrailSurrogateEnd, &check_lead_surrogate); + macro_assembler_->Bind(¬_in_surrogate_pair); + } Trace new_trace; if (start->Emit(this, &new_trace).IsError()) { work_list_ = nullptr; @@ -376,6 +387,14 @@ Compiler::CompilationResult Compiler::Assemble( } macro_assembler_->BindJumpTarget(&fail); macro_assembler_->Fail(); + if (may_step_back) { + macro_assembler_->Bind(&check_lead_surrogate); + macro_assembler_->LoadCurrentCharacter(-1, ¬_in_surrogate_pair); + macro_assembler_->CheckCharacterNotInRange( + kLeadSurrogateStart, kLeadSurrogateEnd, ¬_in_surrogate_pair); + macro_assembler_->AdvanceCurrentPosition(-1); + macro_assembler_->GoTo(¬_in_surrogate_pair); + } while (!work_list.empty()) { WorkItem item = work_list.back(); Node* node = item.node; @@ -389,10 +408,8 @@ Compiler::CompilationResult Compiler::Assemble( } } } - if (IsRegExpTooBig()) { - work_list_ = nullptr; - return ReportError(); - } + // Emit must report every code generation error. + CHECK(!IsRegExpTooBig()); DirectHandle<HeapObject> code = macro_assembler_->GetCode(re_data, flags_); work_list_ = nullptr; @@ -463,6 +480,19 @@ class DynamicBitSet : public ZoneObject { ZoneList<unsigned>* remaining_ = nullptr; }; +void Trace::add_action(ActionNode* new_action) { + DCHECK(action_ == nullptr); // Otherwise we lose an action. + action_ = new_action; + flags_ = HasAnyActionsField::update(flags_, true); + // A later search start can change this capture and let a backreference + // succeed even when the loop reaches the same greedy extent. + // For /(A+)9\1/ on "AA9A", start 0 captures "AA" and fails; start 1 + // captures "A" and matches. Both loops stop at the same '9'. + if (new_action->stores_backreferenced_capture()) { + reset_parked_grant(); + } +} + int Trace::FindAffectedRegisters(DynamicBitSet* affected_registers, Zone* zone) { int max_register = Compiler::kNoRegister; @@ -929,9 +959,17 @@ ActionNode* ActionNode::IncrementRegister(int reg, Node* on_success, flags, reg); } -ActionNode* ActionNode::StorePosition(int reg, Node* on_success, Flags flags) { - return on_success->zone()->New<ActionNode>(STORE_POSITION, on_success, flags, - reg); +ActionNode* ActionNode::StorePosition(int reg, Node* on_success, Flags flags, + const Capture* capture) { + ActionNode* node = on_success->zone()->New<ActionNode>( + STORE_POSITION, on_success, flags, reg); + node->data_.u_simple.capture = capture; + return node; +} + +bool ActionNode::stores_backreferenced_capture() const { + return action_type() == STORE_POSITION && data_.u_simple.capture != nullptr && + data_.u_simple.capture->is_backreferenced(); } ActionNode* ActionNode::RestorePosition(int reg, Node* on_success, @@ -1725,9 +1763,9 @@ Node::LimitResult Node::LimitVersions(Compiler* compiler, Trace* trace) { TRACE("* Limit Versions: Switch to generic version"); bool was_limiting = compiler->limiting_recursion(); compiler->set_limiting_recursion(true); - trace->Flush(compiler, this); + EmitResult result = trace->Flush(compiler, this); compiler->set_limiting_recursion(was_limiting); - return DONE; + return result.IsError() ? FAILED : DONE; } bool Node::KeepRecursing(Compiler* compiler) { @@ -2773,6 +2811,7 @@ EmitResult TextNode::Emit(Compiler* compiler, Trace* trace) { TRACE_EMIT("TextNode"); LimitResult limit_result = LimitVersions(compiler, trace); if (limit_result == DONE) return EmitResult::Success(); + if (limit_result == FAILED) return EmitResult::Error(); DCHECK(limit_result == CONTINUE); const int max_offset = read_backward() ? trace->cp_offset() - Length() @@ -3541,6 +3580,7 @@ AtomicLoopKind ClassifyAtomicLoop(LoopChoiceNode* loop) { } AtomicLoopKind LoopChoiceNode::atomic_loop_kind() { + if (!v8_flags.regexp_atomic_loop) return AtomicLoopKind::kNone; if (!atomic_loop_kind_valid_) { atomic_loop_kind_ = ClassifyAtomicLoop(this); atomic_loop_kind_valid_ = true; @@ -3602,8 +3642,8 @@ DrainMode ChooseFixedLengthLoopDrainMode(ChoiceNode* choice, Trace* trace) { // enclosing quantifier would wrongly match at a park), so parking needs a // grant. With a grant and a single-unit body every skipped restart // re-consumes the run and stops at the old extent, where the continuation - // re-fails (its outcome depends only on input position; the failed - // attempt's register writes are undone by the flush undo frames). + // re-fails. Stores to backreferenced captures revoke the grant in + // Trace::add_action. return (parkable && trace->backtrack() != nullptr && trace->parked_grant() != ParkedGrant::kNone) ? DrainMode::kOmit @@ -3953,9 +3993,9 @@ bool BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm) { for (int i = min_lookahead; i <= max_lookahead; i++) { BoyerMoorePositionInfo* map = bitmaps_->at(i); if (map->map_count() == 0) { - // If we have a position where no characters can match then we just can't - // match. - masm->Fail(); + // No character can match at this position, but another alternative or + // search position may still match. + masm->Backtrack(); return true; } @@ -4201,6 +4241,7 @@ EmitResult ChoiceNode::Emit(Compiler* compiler, Trace* trace) { LimitResult limit_result = LimitVersions(compiler, trace); if (limit_result == DONE) return EmitResult::Success(); + if (limit_result == FAILED) return EmitResult::Error(); DCHECK(limit_result == CONTINUE); // For loop nodes we already flushed (see LoopChoiceNode::Emit), but for @@ -4499,6 +4540,29 @@ bool AlternativeMatchesOnlyAtStart(Node* node) { return false; } +// A parked loop can skip positions when it fails. If another alternative +// could match there, clear the grant: /:|\w*\s/ on "c:" must still match +// ":" at index 1. Alternatives requiring input start cannot match at skipped +// positions, so exclude them. +struct FloatingAlternatives { + FloatingAlternatives(ZoneList<GuardedAlternative>* alternatives, + bool has_parked_grant) { + if (!has_parked_grant) return; + for (int i = 0; i < alternatives->length(); i++) { + if (AlternativeMatchesOnlyAtStart(alternatives->at(i).node())) continue; + count++; + last = i; + } + } + + bool HasSibling(int i) const { + return count > 1 || (count == 1 && last != i); + } + + int count = 0; + int last = -1; +}; + } // namespace // The grant the search-loop body carries (kNone off the search loop). The @@ -5429,6 +5493,9 @@ std::optional<EmitResult> ChoiceNode::TryEmitMaskedValueDispatch( TRACE("* Emit masked-value dispatch"); + FloatingAlternatives floating(alternatives_, + trace->parked_grant() != ParkedGrant::kNone); + // Preload the word if the trace has not already; the bounds check covers // the minimum any alternative eats (mirrors Node::EmitQuickCheck). if (trace->characters_preloaded() != preload_characters) { @@ -5587,6 +5654,7 @@ std::optional<EmitResult> ChoiceNode::TryEmitMaskedValueDispatch( for (int i = 0; i < choice_count; i++) { if (group_of_alt[i] != g) continue; Trace new_trace(*trace); + if (floating.HasSibling(i)) new_trace.reset_parked_grant(); new_trace.set_characters_preloaded(preload_characters); new_trace.set_bound_checked_up_to(preload_characters); // The dispatch compare already established this alternative's @@ -5655,21 +5723,8 @@ EmitResult ChoiceNode::EmitChoices(Compiler* compiler, // emission; see its use below and the binding after the loop. NonAssertingLabel parked_reentry(compiler); - // An inherited parked-position grant may flow into an alternative only if no - // sibling can match at a position the park skips (/:|\w*\s/ on "c:" must - // still match ":" at index 1). "Floating" = an alternative that can match - // away from the input start; a start-anchored sibling matches only at - // position 0, which a park never skips (see AlternativeMatchesOnlyAtStart), - // so the grant is safe exactly when at most the current alternative floats. - int floating_alternatives = 0; - int last_floating = -1; - if (trace->parked_grant() != ParkedGrant::kNone) { - for (int i = 0; i < choice_count; i++) { - if (AlternativeMatchesOnlyAtStart(alternatives_->at(i).node())) continue; - floating_alternatives++; - last_floating = i; - } - } + FloatingAlternatives floating(alternatives_, + trace->parked_grant() != ParkedGrant::kNone); for (int i = first_choice; i < choice_count; i++) { bool is_last = i == choice_count - 1; @@ -5680,10 +5735,7 @@ EmitResult ChoiceNode::EmitChoices(Compiler* compiler, const ZoneList<Guard*>* guards = alternative.guards(); int guard_count = (guards == nullptr) ? 0 : guards->length(); Trace new_trace(*trace); - const bool siblings_all_anchored = - floating_alternatives == 0 || - (floating_alternatives == 1 && last_floating == i); - if (!siblings_all_anchored) new_trace.reset_parked_grant(); + if (floating.HasSibling(i)) new_trace.reset_parked_grant(); new_trace.set_characters_preloaded( preload->preload_is_current_ ? preload->preload_characters_ : 0); if (preload->preload_has_checked_bounds_) { @@ -5850,6 +5902,7 @@ EmitResult ActionNode::Emit(Compiler* compiler, Trace* trace) { RegExpMacroAssembler* assembler = compiler->macro_assembler(); LimitResult limit_result = LimitVersions(compiler, trace); if (limit_result == DONE) return EmitResult::Success(); + if (limit_result == FAILED) return EmitResult::Error(); DCHECK(limit_result == CONTINUE); RecursionCheck rc(compiler); @@ -5878,7 +5931,7 @@ EmitResult ActionNode::Emit(Compiler* compiler, Trace* trace) { // Complex situation: Flush the trace state to the assembler and // generate a generic version of this action. This call will // recurse back to the else clause here. - trace->Flush(compiler, this); + return trace->Flush(compiler, this); } else { assembler->WriteCurrentPositionToRegister( data_.u_submatch.current_position_register, 0); @@ -5902,7 +5955,7 @@ EmitResult ActionNode::Emit(Compiler* compiler, Trace* trace) { // immediately. RETURN_IF_ERROR(on_success()->Emit(compiler, trace)); } else if (!trace->is_trivial()) { - trace->Flush(compiler, this); + return trace->Flush(compiler, this); } else { Label skip_empty_check; // If we have a minimum number of repetitions we check the current @@ -5991,6 +6044,7 @@ EmitResult BackReferenceNode::Emit(Compiler* compiler, Trace* trace) { LimitResult limit_result = LimitVersions(compiler, trace); if (limit_result == DONE) return EmitResult::Success(); + if (limit_result == FAILED) return EmitResult::Error(); DCHECK(limit_result == CONTINUE); RecursionCheck rc(compiler); @@ -6412,35 +6466,6 @@ void TextNode::FillInBMInfo(Isolate* isolate, int initial_offset, int budget, if (initial_offset == 0) set_bm_info(not_at_start, bm); } -Node* Compiler::OptionallyStepBackToLeadSurrogate(Node* on_success) { - TRACE_COMPILER(this, "* Optionally step back to lead surrogate"); - DCHECK(!read_backward()); - ZoneList<CharacterRange>* lead_surrogates = CharacterRange::List( - zone(), CharacterRange::Range(kLeadSurrogateStart, kLeadSurrogateEnd)); - ZoneList<CharacterRange>* trail_surrogates = CharacterRange::List( - zone(), CharacterRange::Range(kTrailSurrogateStart, kTrailSurrogateEnd)); - - ChoiceNode* optional_step_back = zone()->New<ChoiceNode>(2, flags(), zone()); - - int stack_register = UnicodeLookaroundStackRegister(); - int position_register = UnicodeLookaroundPositionRegister(); - Node* step_back = TextNode::CreateForCharacterRanges( - zone(), lead_surrogates, true, on_success, flags()); - Lookaround::Builder builder(true, step_back, this, stack_register, - position_register); - REGISTER_NODE(step_back); - Node* match_trail = TextNode::CreateForCharacterRanges( - zone(), trail_surrogates, false, builder.on_match_success(), flags()); - REGISTER_NODE(match_trail); - - optional_step_back->AddAlternative( - GuardedAlternative(builder.ForMatch(this, match_trail))); - optional_step_back->AddAlternative(GuardedAlternative(on_success)); - - REGISTER_NODE(optional_step_back); - return optional_step_back; -} - Node* Compiler::PreprocessRegExp(CompileData* data, bool is_one_byte) { #ifdef V8_ENABLE_REGEXP_DIAGNOSTICS TraceTreeScope trace_tree_scope(diagnostics()); @@ -6448,7 +6473,7 @@ Node* Compiler::PreprocessRegExp(CompileData* data, bool is_one_byte) { TRACE_GRAPH_WITH_NODE("* Preprocess RegExp ", data->tree); REGISTER_NODE(accept()); // Wrap the body of the regexp in capture #0. - Node* captured_body = Capture::ToNode(data->tree, 0, this, accept()); + Node* captured_body = Capture::ToNode(data->tree, this, accept(), nullptr); Node* node = captured_body; if (!data->tree->IsCertainlyAnchoredAtStart(Node::kRecursionBudget) && !IsSticky(flags())) { @@ -6467,20 +6492,18 @@ Node* Compiler::PreprocessRegExp(CompileData* data, bool is_one_byte) { TRACE_GRAPH("* Unroll loop once"); ChoiceNode* first_step_node = zone()->New<ChoiceNode>(2, flags(), zone()); first_step_node->AddAlternative(GuardedAlternative(captured_body)); - first_step_node->AddAlternative(GuardedAlternative(zone()->New<TextNode>( - zone()->New<ClassRanges>(StandardCharacterSet::kEverything), false, - loop_node, flags()))); + // Use code point advancement in Unicode mode to avoid matching between + // surrogate halves. + Node* step = zone() + ->New<ClassRanges>(StandardCharacterSet::kEverything) + ->ToNode(this, loop_node); + first_step_node->AddAlternative(GuardedAlternative(step)); REGISTER_NODE(first_step_node); node = first_step_node; } else { node = loop_node; } } - if (!is_one_byte && IsEitherUnicode(flags()) && - (IsGlobal(flags()) || IsSticky(flags()))) { - node = OptionallyStepBackToLeadSurrogate(node); - } - // We can run out of registers during preprocessing, or we can recurse too // deep during ToNode. Indicate an error in either case. if (reg_exp_too_big_) { diff --git a/deps/v8/src/regexp/regexp-compiler.h b/deps/v8/src/regexp/regexp-compiler.h index d029f9ee6a48..cce049927e75 100644 --- a/deps/v8/src/regexp/regexp-compiler.h +++ b/deps/v8/src/regexp/regexp-compiler.h @@ -406,11 +406,7 @@ class Trace { bool GetStoredPosition(int reg, int* cp_offset) const; // These set methods and AdvanceCurrentPositionInTrace should be used only on // new traces - the intention is that traces are immutable after creation. - void add_action(ActionNode* new_action) { - DCHECK(action_ == nullptr); // Otherwise we lose an action. - action_ = new_action; - flags_ = HasAnyActionsField::update(flags_, true); - } + void add_action(ActionNode* new_action); // Clears any inherited parked-position grant; see parked_grant() for when // an alternative must do this. void reset_parked_grant() { @@ -644,13 +640,8 @@ class V8_EXPORT_PRIVATE Compiler { // - Wrapping the body of the regexp in capture 0. // - Inserting the implicit .* before/after the regexp if necessary. // - If the input is a one-byte string, filtering out nodes that can't match. - // - Fixing up regexp matches that start within a surrogate pair. Node* PreprocessRegExp(CompileData* data, bool is_one_byte); - // If the regexp matching starts within a surrogate pair, step back to the - // lead surrogate and start matching from there. - Node* OptionallyStepBackToLeadSurrogate(Node* on_success); - struct WorkItem { Node* node; }; diff --git a/deps/v8/src/regexp/regexp-flags.h b/deps/v8/src/regexp/regexp-flags.h index 031cfe2c940d..422b15bfe9d6 100644 --- a/deps/v8/src/regexp/regexp-flags.h +++ b/deps/v8/src/regexp/regexp-flags.h @@ -61,7 +61,7 @@ constexpr bool IsEitherUnicode(Flags f) { } // Whether to rewind the index when it initially points into the middle of a -// surrogate pair. See also OptionallyStepBackToLeadSurrogate(). +// surrogate pair. constexpr bool ShouldOptionallyStepBackToLeadSurrogate(Flags f) { return IsEitherUnicode(f) && (IsGlobal(f) || IsSticky(f)); } diff --git a/deps/v8/src/regexp/regexp-interpreter.cc b/deps/v8/src/regexp/regexp-interpreter.cc index cae8f3eef529..7b999d6df888 100644 --- a/deps/v8/src/regexp/regexp-interpreter.cc +++ b/deps/v8/src/regexp/regexp-interpreter.cc @@ -6,6 +6,7 @@ #include "src/regexp/regexp-interpreter.h" +#include <bit> #include <limits> #include "src/base/logging.h" @@ -514,7 +515,7 @@ IrregexpInterpreter::Result RawMatch( // filled with kBreaks, indicating an invalid operation. This way using // kBytecodeMask guarantees no OOB access to the dispatch table. constexpr int kPaddedBytecodeCount = - base::bits::RoundUpToPowerOfTwo32(Bytecodes::kCount); + std::bit_ceil<uint32_t>(Bytecodes::kCount); constexpr int kBytecodeMask = kPaddedBytecodeCount - 1; static_assert(std::numeric_limits<uint8_t>::max() >= kBytecodeMask); diff --git a/deps/v8/src/regexp/regexp-nodes.h b/deps/v8/src/regexp/regexp-nodes.h index 82d79366d4f0..f0dc7025cd8c 100644 --- a/deps/v8/src/regexp/regexp-nodes.h +++ b/deps/v8/src/regexp/regexp-nodes.h @@ -19,6 +19,7 @@ namespace regexp { class AlternativeGenerationList; class BoyerMooreLookahead; +class Capture; class Compiler; class NegativeSubmatchSuccess; template <typename T> @@ -137,7 +138,7 @@ struct EatsAtLeastInfo final { uint8_t from_not_start; }; -class EmitResult final { +class V8_NODISCARD EmitResult final { public: static EmitResult Success() { return EmitResult(kSuccess); } static EmitResult Error() { return EmitResult(kError); } @@ -402,7 +403,7 @@ class V8_EXPORT_PRIVATE Node : public ZoneObject { virtual bool IsBacktrack() const { return false; } protected: - enum LimitResult { DONE, CONTINUE }; + enum LimitResult { DONE, CONTINUE, FAILED }; Node* replacement_; LimitResult LimitVersions(Compiler* compiler, Trace* trace); @@ -467,7 +468,8 @@ class ActionNode : public SeqNode { static ActionNode* SetRegisterForLoop(int reg, int val, Node* on_success, Flags flags); static ActionNode* IncrementRegister(int reg, Node* on_success, Flags flags); - static ActionNode* StorePosition(int reg, Node* on_success, Flags flags); + static ActionNode* StorePosition(int reg, Node* on_success, Flags flags, + const Capture* capture); static ActionNode* RestorePosition(int reg, Node* on_success, Flags flags); static ActionNode* ClearCaptures(Interval range, Node* on_success, Flags flags); @@ -498,6 +500,7 @@ class ActionNode : public SeqNode { void FillInBMInfo(Isolate* isolate, int offset, int budget, BoyerMooreLookahead* bm, bool not_at_start) override; ActionType action_type() const { return action_type_; } + bool stores_backreferenced_capture() const; // TODO(erikcorry): We should allow some action nodes in fixed length loops. int FixedLengthLoopLength() override { return kNodeIsTooComplexForFixedLengthLoops; @@ -563,6 +566,8 @@ class ActionNode : public SeqNode { int register_from; int register_to; int value; + // Only used for STORE_POSITION; null for implicit capture 0. + const Capture* capture; } u_simple; struct { int stack_pointer_register; diff --git a/deps/v8/src/regexp/regexp-parser.cc b/deps/v8/src/regexp/regexp-parser.cc index 34aad759d589..25c2fa4abe34 100644 --- a/deps/v8/src/regexp/regexp-parser.cc +++ b/deps/v8/src/regexp/regexp-parser.cc @@ -12,6 +12,7 @@ #include "src/regexp/regexp-ast.h" #include "src/regexp/regexp-macro-assembler.h" #include "src/regexp/regexp.h" +#include "src/regexp/special-case.h" #include "src/strings/char-predicates-inl.h" #include "src/utils/ostreams.h" #include "src/utils/utils.h" @@ -62,20 +63,14 @@ class TextBuilder { : zone_(zone), flags_(flags), terms_(terms_storage), text_(zone) {} void AddCharacter(base::uc16 character); void AddUnicodeCharacter(base::uc32 character); - void AddEscapedUnicodeCharacter(base::uc32 character); void AddAtom(Tree* atom); void AddTerm(Tree* term); void AddClassRanges(ClassRanges* cc); - void FlushPendingSurrogate(); void FlushText(); Tree* PopLastAtom(); Tree* ToRegExp(); private: - static const base::uc16 kNoPendingSurrogate = 0; - - void AddLeadSurrogate(base::uc16 lead_surrogate); - void AddTrailSurrogate(base::uc16 trail_surrogate); void FlushCharacters(); bool NeedsDesugaringForUnicode(ClassRanges* cc); bool NeedsDesugaringForIgnoreCase(base::uc32 c); @@ -91,7 +86,6 @@ class TextBuilder { Zone* const zone_; const Flags flags_; ZoneList<base::uc16>* characters_ = nullptr; - base::uc16 pending_surrogate_ = kNoPendingSurrogate; SmallTreeVector* terms_; SmallTreeVector text_; }; @@ -105,61 +99,16 @@ class TextBuilder<ParseMode::kVerifySyntax> { TextBuilder(Zone* zone, SmallTreeVector* terms_storage, Flags flags) {} void AddCharacter(base::uc16 character) {} void AddUnicodeCharacter(base::uc32 character) {} - void AddEscapedUnicodeCharacter(base::uc32 character) {} void AddAtom(Tree* atom) {} void AddTerm(Tree* term) {} void AddClassRanges(ClassRanges* cc) {} - void FlushPendingSurrogate() {} void FlushText() {} Tree* PopLastAtom() { return nullptr; } Tree* ToRegExp() { return nullptr; } }; -template <ParseMode mode> -void TextBuilder<mode>::AddLeadSurrogate(base::uc16 lead_surrogate) { - DCHECK(unibrow::Utf16::IsLeadSurrogate(lead_surrogate)); - FlushPendingSurrogate(); - // Hold onto the lead surrogate, waiting for a trail surrogate to follow. - pending_surrogate_ = lead_surrogate; -} - -template <ParseMode mode> -void TextBuilder<mode>::AddTrailSurrogate(base::uc16 trail_surrogate) { - DCHECK(unibrow::Utf16::IsTrailSurrogate(trail_surrogate)); - if (pending_surrogate_ != kNoPendingSurrogate) { - base::uc16 lead_surrogate = pending_surrogate_; - pending_surrogate_ = kNoPendingSurrogate; - DCHECK(unibrow::Utf16::IsLeadSurrogate(lead_surrogate)); - base::uc32 combined = - unibrow::Utf16::CombineSurrogatePair(lead_surrogate, trail_surrogate); - if (NeedsDesugaringForIgnoreCase(combined)) { - AddClassRangesForDesugaring(combined); - } else { - ZoneList<base::uc16> surrogate_pair(2, zone()); - surrogate_pair.Add(lead_surrogate, zone()); - surrogate_pair.Add(trail_surrogate, zone()); - Atom* atom = zone()->template New<Atom>(surrogate_pair.ToConstVector()); - AddAtom(atom); - } - } else { - pending_surrogate_ = trail_surrogate; - FlushPendingSurrogate(); - } -} - -template <ParseMode mode> -void TextBuilder<mode>::FlushPendingSurrogate() { - if (pending_surrogate_ != kNoPendingSurrogate) { - DCHECK(IsUnicodeMode()); - base::uc32 c = pending_surrogate_; - pending_surrogate_ = kNoPendingSurrogate; - AddClassRangesForDesugaring(c); - } -} - template <ParseMode mode> void TextBuilder<mode>::FlushCharacters() { - FlushPendingSurrogate(); if (characters_ != nullptr) { Tree* atom = zone()->template New<Atom>(characters_->ToConstVector()); characters_ = nullptr; @@ -187,7 +136,10 @@ void TextBuilder<mode>::FlushText() { template <ParseMode mode> void TextBuilder<mode>::AddCharacter(base::uc16 c) { - FlushPendingSurrogate(); + if (NeedsDesugaringForIgnoreCase(c)) { + AddClassRangesForDesugaring(c); + return; + } if (characters_ == nullptr) { characters_ = zone()->template New<ZoneList<base::uc16>>(4, zone()); } @@ -198,26 +150,23 @@ template <ParseMode mode> void TextBuilder<mode>::AddUnicodeCharacter(base::uc32 c) { if (c > static_cast<base::uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) { DCHECK(IsUnicodeMode()); - AddLeadSurrogate(unibrow::Utf16::LeadSurrogate(c)); - AddTrailSurrogate(unibrow::Utf16::TrailSurrogate(c)); - } else if (IsUnicodeMode() && unibrow::Utf16::IsLeadSurrogate(c)) { - AddLeadSurrogate(c); - } else if (IsUnicodeMode() && unibrow::Utf16::IsTrailSurrogate(c)) { - AddTrailSurrogate(c); + if (NeedsDesugaringForIgnoreCase(c)) { + AddClassRangesForDesugaring(c); + } else { + ZoneList<base::uc16> surrogate_pair(2, zone()); + surrogate_pair.Add(unibrow::Utf16::LeadSurrogate(c), zone()); + surrogate_pair.Add(unibrow::Utf16::TrailSurrogate(c), zone()); + Atom* atom = zone()->template New<Atom>(surrogate_pair.ToConstVector()); + AddAtom(atom); + } + } else if (IsUnicodeMode() && (unibrow::Utf16::IsLeadSurrogate(c) || + unibrow::Utf16::IsTrailSurrogate(c))) { + AddClassRangesForDesugaring(c); } else { AddCharacter(static_cast<base::uc16>(c)); } } -template <ParseMode mode> -void TextBuilder<mode>::AddEscapedUnicodeCharacter(base::uc32 character) { - // A lead or trail surrogate parsed via escape sequence will not - // pair up with any preceding lead or following trail surrogate. - FlushPendingSurrogate(); - AddUnicodeCharacter(character); - FlushPendingSurrogate(); -} - template <ParseMode mode> void TextBuilder<mode>::AddClassRanges(ClassRanges* cr) { if (NeedsDesugaringForUnicode(cr)) { @@ -278,16 +227,19 @@ bool TextBuilder<mode>::NeedsDesugaringForUnicode(ClassRanges* cc) { return false; } -// We only use this for characters made of surrogate pairs. All other -// characters outside of character classes are made case independent in the -// code generation. +// Desugar supplementary characters with case equivalents and BMP characters +// with supplementary equivalents. Other atoms are folded during code +// generation. template <ParseMode mode> bool TextBuilder<mode>::NeedsDesugaringForIgnoreCase(base::uc32 c) { #ifdef V8_INTL_SUPPORT if (IsUnicodeMode() && ignore_case()) { + if (c <= unibrow::Utf16::kMaxNonSurrogateCharCode) { + return CaseFolding::HasSupplementaryEquivalents( + static_cast<base::uc16>(c)); + } icu::UnicodeSet set(c, c); - set.closeOver(USET_CASE_INSENSITIVE); - set.removeAllStrings(); + CaseFolding::CloseOver(set, CaseFolding::Mode::kUnicode); return set.size() > 1; } // In the case where ICU is not included, we act as if the unicode flag is @@ -298,7 +250,6 @@ bool TextBuilder<mode>::NeedsDesugaringForIgnoreCase(base::uc32 c) { template <ParseMode mode> Tree* TextBuilder<mode>::PopLastAtom() { - FlushPendingSurrogate(); Tree* atom; if (characters_ != nullptr) { base::Vector<const base::uc16> char_vector = characters_->ToConstVector(); @@ -398,7 +349,6 @@ class Builder { text_builder_(TextBuilder<mode>{zone, &terms_, flags}) {} void AddCharacter(base::uc16 character); void AddUnicodeCharacter(base::uc32 character); - void AddEscapedUnicodeCharacter(base::uc32 character); // "Adds" an empty expression. Does nothing except consume a // following quantifier void AddEmpty(); @@ -451,9 +401,6 @@ class Builder<ParseMode::kVerifySyntax> { void AddUnicodeCharacter(base::uc32 character) { last_term_is_lookaround_ = false; } - void AddEscapedUnicodeCharacter(base::uc32 character) { - last_term_is_lookaround_ = false; - } void AddEmpty() { last_term_is_lookaround_ = false; } void AddClassRanges(ClassRanges* cc) { last_term_is_lookaround_ = false; } void AddAtom(Tree* term) { @@ -667,6 +614,9 @@ class ParserImpl final { base::uc32 next, InClassEscapeState in_class_escape_state, ZoneList<CharacterRange>* ranges, CharacterClassStrings* strings, Zone* zone, bool add_unicode_case_equivalents); + bool AddClassString(ZoneList<base::uc32>* normalized_string, + Tree* regexp_string, ZoneList<CharacterRange>* ranges, + CharacterClassStrings* strings); ClassSetResult<mode> ParseClassStringDisjunction( ZoneList<CharacterRange>* ranges, CharacterClassStrings* strings); ClassSetResult<mode> ParseClassSetOperand(const Builder<mode>* builder, @@ -678,8 +628,7 @@ class ParserImpl final { base::uc32* character); base::uc32 ParseClassSetCharacter(); // Parses and returns a single escaped character. - base::uc32 ParseCharacterEscape(InClassEscapeState in_class_escape_state, - bool* is_escaped_unicode_character); + base::uc32 ParseCharacterEscape(InClassEscapeState in_class_escape_state); void AddMaybeSimpleCaseFoldedRange(ZoneList<CharacterRange>* ranges, CharacterRange new_range); @@ -1480,15 +1429,9 @@ Tree* ParserImpl<CharT, mode>::ParseDisjunction() { // AtomEscape :: // CharacterEscape default: { - bool is_escaped_unicode_character = false; base::uc32 c = ParseCharacterEscape( - InClassEscapeState::kNotInClass, - &is_escaped_unicode_character CHECK_FAILED); - if (is_escaped_unicode_character) { - builder->AddEscapedUnicodeCharacter(c); - } else { - builder->AddCharacter(c); - } + InClassEscapeState::kNotInClass CHECK_FAILED); + builder->AddUnicodeCharacter(c); break; } } @@ -2276,6 +2219,22 @@ void ExtractStringsFromUnicodeSet(const icu::UnicodeSet& set, } } +// Appends the ranges of |set| to |result_ranges|. In /vi mode, the set is +// closed over simple case folding first; this must precede the complement. +void AddUnicodeSetRanges(icu::UnicodeSet* set, bool negate, Flags flags, + ZoneList<CharacterRange>* result_ranges, Zone* zone) { + DCHECK_NOT_NULL(result_ranges); + const bool needs_case_folding = IsUnicodeSets(flags) && IsIgnoreCase(flags); + if (needs_case_folding) set->closeOver(USET_SIMPLE_CASE_INSENSITIVE); + set->removeAllStrings(); + if (negate) set->complement(); + for (int i = 0; i < set->getRangeCount(); i++) { + result_ranges->Add( + CharacterRange::Range(set->getRangeStart(i), set->getRangeEnd(i)), + zone); + } +} + template <ParseMode mode> ClassSetResult<mode> LookupPropertyValueName( UProperty property, const char* property_value_name, bool negate, @@ -2315,15 +2274,7 @@ ClassSetResult<mode> LookupPropertyValueName( if (contains_strings) { ExtractStringsFromUnicodeSet(set, result_strings, flags, zone); } - const bool needs_case_folding = IsUnicodeSets(flags) && IsIgnoreCase(flags); - if (needs_case_folding) set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); - set.removeAllStrings(); - if (negate) set.complement(); - DCHECK_NOT_NULL(result_ranges); - for (int i = 0; i < set.getRangeCount(); i++) { - result_ranges->Add( - CharacterRange::Range(set.getRangeStart(i), set.getRangeEnd(i)), zone); - } + AddUnicodeSetRanges(&set, negate, flags, result_ranges, zone); return ClassSetResult<mode>(nullptr, contains_strings); } @@ -2347,9 +2298,8 @@ bool LookupSpecialPropertyValueName(const char* name, } } else if (NameEquals(name, "ASCII")) { if constexpr (mode == ParseMode::kBuildAST) { - result->Add(negate ? CharacterRange::Range(0x80, String::kMaxCodePoint) - : CharacterRange::Range(0x0, 0x7F), - zone); + icu::UnicodeSet set(0x0, 0x7F); + AddUnicodeSetRanges(&set, negate, flags, result, zone); } } else if (NameEquals(name, "Assigned")) { return LookupPropertyValueName<mode>(UCHAR_GENERAL_CATEGORY, "Unassigned", @@ -2610,8 +2560,7 @@ bool ParserImpl<CharT, mode>::ParseUnlimitedLengthHexNumber(int max_value, // https://tc39.es/ecma262/#prod-CharacterEscape template <class CharT, ParseMode mode> base::uc32 ParserImpl<CharT, mode>::ParseCharacterEscape( - InClassEscapeState in_class_escape_state, - bool* is_escaped_unicode_character) { + InClassEscapeState in_class_escape_state) { DCHECK_EQ('\\', current()); DCHECK(has_next()); @@ -2715,10 +2664,7 @@ base::uc32 ParserImpl<CharT, mode>::ParseCharacterEscape( case 'u': { Advance(); base::uc32 value; - if (ParseUnicodeEscape(&value)) { - *is_escaped_unicode_character = true; - return value; - } + if (ParseUnicodeEscape(&value)) return value; if (IsUnicodeMode()) { // With /u or /v, invalid escapes are not treated as identity escapes. ReportError(Error::kInvalidUnicodeEscape); @@ -2876,8 +2822,7 @@ void ParserImpl<CharT, mode>::ParseClassEscape( if (failed()) return; if (*is_class_escape) return; - bool dummy = false; // Unused. - *char_out = ParseCharacterEscape(kInClassEscape, &dummy); + *char_out = ParseCharacterEscape(kInClassEscape); } // https://tc39.es/ecma262/#prod-CharacterClassEscape @@ -2931,28 +2876,25 @@ ClassSetResult<mode> ParserImpl<CharT, mode>::TryParseCharacterClassEscape( } } -namespace { - // Add |string| to |ranges| if length of |string| == 1, otherwise add |string| // to |strings|. Returns true if a string (length != 1) was added. -template <ParseMode mode> -bool AddClassString(ZoneList<base::uc32>* normalized_string, - Tree* regexp_string, ZoneList<CharacterRange>* ranges, - CharacterClassStrings* strings, Zone* zone) { +template <class CharT, ParseMode mode> +bool ParserImpl<CharT, mode>::AddClassString( + ZoneList<base::uc32>* normalized_string, Tree* regexp_string, + ZoneList<CharacterRange>* ranges, CharacterClassStrings* strings) { const bool is_string = normalized_string->length() != 1; if constexpr (mode == ParseMode::kVerifySyntax) return is_string; DCHECK_NOT_NULL(ranges); DCHECK_NOT_NULL(strings); if (!is_string) { - ranges->Add(CharacterRange::Singleton(normalized_string->at(0)), zone); + AddMaybeSimpleCaseFoldedRange( + ranges, CharacterRange::Singleton(normalized_string->at(0))); } else { strings->emplace(normalized_string->ToVector(), regexp_string); } return is_string; } -} // namespace - // https://tc39.es/ecma262/#prod-ClassStringDisjunction template <class CharT, ParseMode mode> ClassSetResult<mode> ParserImpl<CharT, mode>::ParseClassStringDisjunction( @@ -2975,8 +2917,8 @@ ClassSetResult<mode> ParserImpl<CharT, mode>::ParseClassStringDisjunction( bool contains_strings = false; while (has_more() && current() != '}') { if (current() == '|') { - contains_strings |= AddClassString<mode>( - string, string_builder.ToRegExp(), ranges, strings, zone()); + contains_strings |= + AddClassString(string, string_builder.ToRegExp(), ranges, strings); string = zone()->template New<ZoneList<base::uc32>>(4, zone()); string_storage.clear(); Advance(); @@ -2994,11 +2936,8 @@ ClassSetResult<mode> ParserImpl<CharT, mode>::ParseClassStringDisjunction( } } - contains_strings |= AddClassString<mode>(string, string_builder.ToRegExp(), - ranges, strings, zone()); - if constexpr (mode == ParseMode::kBuildAST) { - CharacterRange::Canonicalize(ranges); - } + contains_strings |= + AddClassString(string, string_builder.ToRegExp(), ranges, strings); // We don't need to handle missing closing '}' here. // If the character class is correctly closed, ParseClassSetCharacter will @@ -3112,8 +3051,7 @@ base::uc32 ParserImpl<CharT, mode>::ParseClassSetCharacter() { static constexpr InClassEscapeState kInClassEscape = InClassEscapeState::kInClass; - bool dummy = false; // Unused. - return ParseCharacterEscape(kInClassEscape, &dummy); + return ParseCharacterEscape(kInClassEscape); } if (IsClassSetSyntaxCharacter(c)) { ReportError(Error::kInvalidCharacterInClass); @@ -3430,8 +3368,11 @@ ClassSetResult<mode> ParserImpl<CharT, mode>::ParseCharacterClass( if (!ignore_case()) { character_class_flags |= ClassRanges::NO_CASE_FOLDING_NEEDED; } - if (sizeof(CharT) == 1 && !is_negated) { - // No surrogate pairs. + if (!IsUnicodeMode()) { + // Outside of unicode mode, a character class always matches exactly + // one code unit. In unicode mode, even a one-byte pattern source can + // describe supplementary code points (e.g. \u{1F600}, \uD83D\uDE00, + // \p{...}, or /iu case closure), which match a surrogate pair. character_class_flags |= ClassRanges::IS_CERTAINLY_ONE_CODE_POINT; } tree = zone()->template New<ClassRanges>(zone(), ranges, @@ -3540,15 +3481,8 @@ void Builder<mode>::AddUnicodeCharacter(base::uc32 c) { text_builder().AddUnicodeCharacter(c); } -template <ParseMode mode> -void Builder<mode>::AddEscapedUnicodeCharacter(base::uc32 character) { - pending_empty_ = false; - text_builder().AddEscapedUnicodeCharacter(character); -} - template <ParseMode mode> void Builder<mode>::AddEmpty() { - text_builder().FlushPendingSurrogate(); pending_empty_ = true; } diff --git a/deps/v8/src/regexp/regexp-stack.h b/deps/v8/src/regexp/regexp-stack.h index cae82b072422..3da00b6c23f7 100644 --- a/deps/v8/src/regexp/regexp-stack.h +++ b/deps/v8/src/regexp/regexp-stack.h @@ -13,6 +13,15 @@ namespace v8 { namespace internal { namespace regexp { +class RegExpMacroAssemblerARM; +class RegExpMacroAssemblerARM64; +class RegExpMacroAssemblerIA32; +class RegExpMacroAssemblerLOONG64; +class RegExpMacroAssemblerMIPS; +class RegExpMacroAssemblerPPC; +class RegExpMacroAssemblerRISCV; +class RegExpMacroAssemblerS390; +class RegExpMacroAssemblerX64; class Stack; // Maintains a per-v8thread stack area that can be used by irregexp @@ -73,13 +82,6 @@ class Stack final { size_t memory_size() const { return thread_local_.memory_size_; } - // If the stack pointer gets below the limit, we should react and - // either grow the stack or report an out-of-stack exception. - // There is only a limited number of locations below the stack limit, - // so users of the stack should check the stack limit during any - // sequence of pushes longer that this. - Address* limit_address_address() { return &thread_local_.limit_; } - // Ensures that there is a memory area with at least the specified size. // If passing zero, the default/minimum size buffer is allocated. V8_EXPORT_PRIVATE Address EnsureCapacity(size_t size); @@ -158,12 +160,19 @@ class Stack final { }; static constexpr size_t kThreadLocalSize = sizeof(ThreadLocal); - Address memory_top_address_address() { - return reinterpret_cast<Address>(&thread_local_.memory_top_); - } - - Address stack_pointer_address() { - return reinterpret_cast<Address>(&thread_local_.stack_pointer_); + // Generated code reaches the fields of the thread-local block through + // these offsets from its address. + static constexpr int kMemoryTopOffset = offsetof(ThreadLocal, memory_top_); + static constexpr int kStackPointerOffset = + offsetof(ThreadLocal, stack_pointer_); + // If the stack pointer gets below the limit, the code must grow the stack + // or report an out-of-stack exception. There is only a limited number of + // locations below the limit, so the code checks it during any sequence of + // pushes longer than that. + static constexpr int kLimitOffset = offsetof(ThreadLocal, limit_); + + Address thread_local_address() { + return reinterpret_cast<Address>(&thread_local_); } // A position-independent representation of the stack pointer. @@ -186,6 +195,16 @@ class Stack final { friend class internal::ExternalReference; friend class StackScope; + // The regexp macro assemblers use the ThreadLocal offsets above. + friend class RegExpMacroAssemblerARM; + friend class RegExpMacroAssemblerARM64; + friend class RegExpMacroAssemblerIA32; + friend class RegExpMacroAssemblerLOONG64; + friend class RegExpMacroAssemblerMIPS; + friend class RegExpMacroAssemblerPPC; + friend class RegExpMacroAssemblerRISCV; + friend class RegExpMacroAssemblerS390; + friend class RegExpMacroAssemblerX64; }; } // namespace regexp diff --git a/deps/v8/src/regexp/regexp.cc b/deps/v8/src/regexp/regexp.cc index feb4d60f4f8b..2e62116a33a4 100644 --- a/deps/v8/src/regexp/regexp.cc +++ b/deps/v8/src/regexp/regexp.cc @@ -165,14 +165,10 @@ MaybeDirectHandle<Object> RegExp::ThrowRegExpException( regexp::Error error) { if (V8_UNLIKELY(v8_flags.correctness_fuzzer_suppressions && regexp::ErrorIsStackOverflow(error))) { - FATAL("Aborting on stack overflow"); + base::FatalNoSecurityImpact("Aborting on stack overflow"); } - base::Vector<const char> error_data = - base::CStrVector(regexp::ErrorString(error)); DirectHandle<String> error_text = - isolate->factory() - ->NewStringFromOneByte(base::Vector<const uint8_t>::cast(error_data)) - .ToHandleChecked(); + isolate->factory()->NewStringFromAsciiChecked(regexp::ErrorString(error)); DirectHandle<String> flag_string = JSRegExp::StringFromFlags(isolate, JSRegExp::AsJSRegExpFlags(flags)); THROW_NEW_ERROR(isolate, diff --git a/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.cc b/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.cc index 5bb72cf147ac..050079258935 100644 --- a/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.cc +++ b/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.cc @@ -26,6 +26,8 @@ namespace regexp { * LoadCurrentCharacter before using any of the dispatch methods. * - s6 : Points to tip of backtrack stack * - s8 : End of input (points to byte after last character in input). + * - s10: Address of the regexp stack's thread-local block, which holds the + * stack limit, memory top and saved stack pointer. * - fp : Frame pointer. Used to access arguments, local variables and * RegExp registers. * - sp : Points to tip of C stack. @@ -606,6 +608,7 @@ void RegExpMacroAssemblerRISCV::SkipUntilBitInTable( __ And(t0, t0, Operand(0xfffe)); } __ AddWord(current_input_offset(), current_input_offset(), t0); + LoadCurrentCharacterUnchecked(cp_offset, 1); __ Branch(on_match); Bind(&scalar); } @@ -755,26 +758,16 @@ void RegExpMacroAssemblerRISCV::Fail() { } void RegExpMacroAssemblerRISCV::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ li(dst, Operand(ref)); - __ LoadWord(dst, MemOperand(dst)); + __ LoadWord(dst, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerRISCV::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ li(scratch, Operand(ref)); - __ StoreWord(src, MemOperand(scratch)); +void RegExpMacroAssemblerRISCV::StoreRegExpStackPointerToMemory(Register src) { + __ StoreWord(src, MemOperand(regexp_stack(), Stack::kStackPointerOffset)); } void RegExpMacroAssemblerRISCV::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(scratch, Operand(ref)); - __ LoadWord(scratch, MemOperand(scratch)); + __ LoadWord(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ SubWord(scratch, stack_pointer, scratch); __ StoreWord(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); @@ -782,14 +775,11 @@ void RegExpMacroAssemblerRISCV::PushRegExpBasePointer(Register stack_pointer, void RegExpMacroAssemblerRISCV::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ LoadWord(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ li(scratch, Operand(ref)); - __ LoadWord(scratch, MemOperand(scratch)); + __ LoadWord(scratch, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ AddWord(stack_pointer_out, stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerRISCV::GetCode( @@ -862,6 +852,10 @@ DirectHandle<HeapObject> RegExpMacroAssemblerRISCV::GetCode( // pointer. Patterns that never do skip the backtrack stack setup, the fail // label, and the teardown below. if (backtrack_stack_used()) { + __ li(regexp_stack(), + Operand(ExternalReference::address_of_regexp_stack_thread_local( + isolate()))); + // Initialize backtrack stack pointer. It must not be clobbered from here // on. Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == s8); @@ -910,7 +904,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerRISCV::GetCode( // initialized above; storing it would corrupt the saved stack pointer // (regexp::StackScope verifies it is unchanged across the exec call). if (backtrack_stack_used()) { - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); } CallCheckStackGuardState(a0, extra_space_for_variables); // If returned value is non-zero, we exit with the returned value as @@ -1134,7 +1128,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerRISCV::GetCode( // pointer is initialized for the store/reload below. DCHECK(backtrack_stack_used()); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); // Put regexp engine registers on stack. CallCheckStackGuardState(a0); // If returning non-zero, we should end execution with the given @@ -1151,7 +1145,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerRISCV::GetCode( if (stack_overflow_label_.is_linked()) { SafeCallTarget(&stack_overflow_label_); // Call GrowStack(isolate). - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); static constexpr int kNumArguments = 1; __ PrepareCallCFunction(kNumArguments, 0, a0); @@ -1270,20 +1264,14 @@ void RegExpMacroAssemblerRISCV::ReadCurrentPositionFromRegister(int reg) { void RegExpMacroAssemblerRISCV::WriteStackPointerToRegister(int reg) { set_backtrack_stack_used(); - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(a0, ref); - __ LoadWord(a0, MemOperand(a0)); + __ LoadWord(a0, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ SubWord(a0, backtrack_stackpointer(), a0); __ Sw(a0, register_location(reg)); } void RegExpMacroAssemblerRISCV::ReadStackPointerFromRegister(int reg) { set_backtrack_stack_used(); - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ li(a1, ref); - __ LoadWord(a1, MemOperand(a1)); + __ LoadWord(a1, MemOperand(regexp_stack(), Stack::kMemoryTopOffset)); __ Lw(backtrack_stackpointer(), register_location(reg)); __ AddWord(backtrack_stackpointer(), backtrack_stackpointer(), a1); } @@ -1504,30 +1492,18 @@ void RegExpMacroAssemblerRISCV::CheckPreemption() { } void RegExpMacroAssemblerRISCV::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address( - masm_->isolate()); - - __ li(a0, Operand(stack_limit)); - __ LoadWord(a0, MemOperand(a0)); + DCHECK(backtrack_stack_used()); + __ LoadWord(a0, MemOperand(regexp_stack(), Stack::kLimitOffset)); SafeCall(&stack_overflow_label_, Uless_equal, backtrack_stackpointer(), Operand(a0)); } void RegExpMacroAssemblerRISCV::AssertAboveStackLimitMinusSlack() { - // ExternalReference stack_limit = - // ExternalReference::address_of_regexp_stack_limit_address( - // masm_->isolate()); - // __ li(a0, Operand(stack_limit)); - // __ LoadWord(a0, MemOperand(a0, 0)); - // SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), - // Operand(a0)); + DCHECK(backtrack_stack_used()); DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ li(a0, l); - __ LoadWord(a0, MemOperand(a0, 0)); + __ LoadWord(a0, MemOperand(regexp_stack(), Stack::kLimitOffset)); __ SubWord(a0, a0, Operand(Stack::kStackLimitSlackSize)); __ Branch(&no_stack_overflow, Ugreater, backtrack_stackpointer(), Operand(a0)); diff --git a/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.h b/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.h index 406d693933b5..c15e255efa0e 100644 --- a/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.h +++ b/deps/v8/src/regexp/riscv/regexp-macro-assembler-riscv.h @@ -207,6 +207,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerRISCV // Register holding pointer to the current code object. static constexpr Register code_pointer() { return s1; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return s10; } + // The real backtrack dispatch (pop a code offset and jump to it), emitted // once in GetCode at backtrack_label_ when the backtrack stack is used. // Backtrack() itself only jumps there, so emitting it does not by itself @@ -234,7 +239,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerRISCV inline void Pop(Register target); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register stack_pointer, Register scratch); void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); diff --git a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc index 5488181e8469..a04980ac0728 100644 --- a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc +++ b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.cc @@ -668,26 +668,20 @@ void RegExpMacroAssemblerS390::Fail() { } void RegExpMacroAssemblerS390::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(dst, Operand(ref)); - __ LoadU64(dst, MemOperand(dst)); + __ mov(dst, Operand(regexp_stack_thread_local())); + __ LoadU64(dst, MemOperand(dst, Stack::kStackPointerOffset)); } void RegExpMacroAssemblerS390::StoreRegExpStackPointerToMemory( Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ mov(scratch, Operand(ref)); - __ StoreU64(src, MemOperand(scratch)); + __ mov(scratch, Operand(regexp_stack_thread_local())); + __ StoreU64(src, MemOperand(scratch, Stack::kStackPointerOffset)); } void RegExpMacroAssemblerS390::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(scratch, Operand(ref)); - __ LoadU64(scratch, MemOperand(scratch)); + __ mov(scratch, Operand(regexp_stack_thread_local())); + __ LoadU64(scratch, MemOperand(scratch, Stack::kMemoryTopOffset)); __ SubS64(scratch, stack_pointer, scratch); __ StoreU64(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); @@ -695,12 +689,10 @@ void RegExpMacroAssemblerS390::PushRegExpBasePointer(Register stack_pointer, void RegExpMacroAssemblerS390::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ LoadU64(stack_pointer_out, MemOperand(frame_pointer(), kRegExpStackBasePointerOffset)); - __ mov(scratch, Operand(ref)); - __ LoadU64(scratch, MemOperand(scratch)); + __ mov(scratch, Operand(regexp_stack_thread_local())); + __ LoadU64(scratch, MemOperand(scratch, Stack::kMemoryTopOffset)); __ AddS64(stack_pointer_out, stack_pointer_out, scratch); StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); } @@ -1206,19 +1198,15 @@ void RegExpMacroAssemblerS390::ReadCurrentPositionFromRegister(int reg) { } void RegExpMacroAssemblerS390::WriteStackPointerToRegister(int reg) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(r3, Operand(ref)); - __ LoadU64(r3, MemOperand(r3)); + __ mov(r3, Operand(regexp_stack_thread_local())); + __ LoadU64(r3, MemOperand(r3, Stack::kMemoryTopOffset)); __ SubS64(r2, backtrack_stackpointer(), r3); __ StoreU64(r2, register_location(reg)); } void RegExpMacroAssemblerS390::ReadStackPointerFromRegister(int reg) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ mov(r2, Operand(ref)); - __ LoadU64(r2, MemOperand(r2)); + __ mov(r2, Operand(regexp_stack_thread_local())); + __ LoadU64(r2, MemOperand(r2, Stack::kMemoryTopOffset)); __ LoadU64(backtrack_stackpointer(), register_location(reg), r0); __ AddS64(backtrack_stackpointer(), backtrack_stackpointer(), r2); } @@ -1467,10 +1455,8 @@ void RegExpMacroAssemblerS390::CheckPreemption() { } void RegExpMacroAssemblerS390::CheckStackLimit() { - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(r2, Operand(stack_limit)); - __ CmpU64(backtrack_stackpointer(), MemOperand(r2)); + __ mov(r2, Operand(regexp_stack_thread_local())); + __ CmpU64(backtrack_stackpointer(), MemOperand(r2, Stack::kLimitOffset)); SafeCall(&stack_overflow_label_, le); } @@ -1478,9 +1464,8 @@ void RegExpMacroAssemblerS390::AssertAboveStackLimitMinusSlack() { DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ mov(r2, Operand(l)); - __ LoadU64(r2, MemOperand(r2)); + __ mov(r2, Operand(regexp_stack_thread_local())); + __ LoadU64(r2, MemOperand(r2, Stack::kLimitOffset)); __ SubS64(r2, r2, Operand(Stack::kStackLimitSlackSize)); __ CmpU64(backtrack_stackpointer(), r2); __ bgt(&no_stack_overflow); diff --git a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h index 73a50d33c232..fb3adfc70407 100644 --- a/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h +++ b/deps/v8/src/regexp/s390/regexp-macro-assembler-s390.h @@ -210,6 +210,12 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerS390 Isolate* isolate() const { return masm_->isolate(); } + // Address of the regexp stack's thread-local block, whose stack limit, + // memory top and saved stack pointer sit at Stack::k*Offset. + ExternalReference regexp_stack_thread_local() const { + return ExternalReference::address_of_regexp_stack_thread_local(isolate()); + } + const std::unique_ptr<MacroAssembler> masm_; const NoRootArrayScope no_root_array_scope_; diff --git a/deps/v8/src/regexp/special-case.h b/deps/v8/src/regexp/special-case.h index 3279be6df310..977a3284e74b 100644 --- a/deps/v8/src/regexp/special-case.h +++ b/deps/v8/src/regexp/special-case.h @@ -7,8 +7,8 @@ #ifdef V8_INTL_SUPPORT #include "src/base/logging.h" +#include "src/base/strings.h" #include "src/common/globals.h" - #include "unicode/uchar.h" #include "unicode/uniset.h" @@ -53,6 +53,12 @@ namespace regexp { // another character. Characters that match no other characters in // their equivalence class are added to IgnoreSet. The generator verifies // that each Unicode class has at most one non-trivial JS class. +// Supplementary code points are ignored throughout: non-unicode matching +// compares UTF-16 code units, so they can never match a BMP character. +// +// The generator additionally emits SupplementaryEquivalentsSet, the BMP +// characters whose Unicode case closure contains supplementary code points. +// This set is used for unicode-mode matching, see HasSupplementaryEquivalents. class V8_EXPORT_PRIVATE CaseFolding final : public AllStatic { public: @@ -75,9 +81,9 @@ class V8_EXPORT_PRIVATE CaseFolding final : public AllStatic { set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); return; } + DCHECK(!set.containsSome(0x10000, 0x10ffff)); if (IgnoreSet().containsNone(set)) { - set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); - set.removeAll(IgnoreSet()); + CloseOverNonUnicode(set); return; } if (IgnoreSet().containsAll(set)) return; @@ -86,13 +92,25 @@ class V8_EXPORT_PRIVATE CaseFolding final : public AllStatic { icu::UnicodeSet ignored(set); ignored.retainAll(IgnoreSet()); set.removeAll(IgnoreSet()); - set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); - set.removeAll(IgnoreSet()); + CloseOverNonUnicode(set); set.addAll(ignored); } + // Whether c has supplementary Unicode case equivalents. + static bool HasSupplementaryEquivalents(base::uc16 c) { + return SupplementaryEquivalentsSet().contains(c); + } + private: static const icu::UnicodeSet& IgnoreSet(); + static const icu::UnicodeSet& SupplementaryEquivalentsSet(); + + // Requires a set containing no IgnoreSet characters. + static void CloseOverNonUnicode(icu::UnicodeSet& set) { + set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); + set.removeAll(IgnoreSet()); + set.remove(0x10000, 0x10ffff); + } }; } // namespace regexp diff --git a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc index 769d2d5ff0f9..8e68e54eabc2 100644 --- a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc +++ b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.cc @@ -40,8 +40,10 @@ namespace regexp { * pointer). * - r8 : InstructionStream object pointer. Used to convert between absolute * and code-object-relative addresses. + * - r12 : Address of the regexp stack's thread-local block, which holds the + * stack limit, memory top and saved stack pointer. * - * The registers rax, rcx, r9, r11, and r12 are free to use for computations. + * The registers rax, rcx, r9, and r11 are free to use for computations. * If changed to use r13+, they should be saved as callee-save registers. * The macro assembler special register r13 (kRootRegister) isn't special * during execution of RegExp code (it doesn't hold the value assumed when @@ -347,12 +349,12 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase( } else { DCHECK(mode() == UC16); PushCallerSavedRegisters(); + // Save the byte length; it is popped back into rcx after the call. + __ pushq(rcx); static const int num_arguments = 4; __ PrepareCallCFunction(num_arguments); - static const Register kSavedByteLength = r12; - // Put arguments into parameter registers. Parameters are // Address byte_offset1 - Address captured substring's start. // Address byte_offset2 - Address of current character position. @@ -364,8 +366,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase( DCHECK(r8 == kCArgRegs[2]); DCHECK(r9 == kCArgRegs[3]); __ movq(r8, rcx); // Length of capture argument. - __ movq(kSavedByteLength, - rcx); // Save byte_length in callee-saved register. // Compute and set byte_offset1 (start of capture). __ leaq(rcx, Operand(rsi, rdx, times_1, 0)); // Set byte_offset2. @@ -383,8 +383,6 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase( // Compute and set byte_offset1 (start of capture). __ leaq(rdi, Operand(rsi, rdx, times_1, 0)); __ movq(rdx, rcx); // Length of capture argument. - __ movq(kSavedByteLength, - rcx); // Save byte_length in callee-saved register. // Set byte_offset2. __ movq(rsi, rax); if (read_backward) { @@ -406,6 +404,7 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase( // Restore original values before reacting on result value. __ Move(code_object_pointer(), masm_.CodeObject()); + __ popq(rcx); // Byte length. PopCallerSavedRegisters(); // Check if function returned non-zero for success or zero for failure. @@ -413,9 +412,9 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase( BranchOrBacktrack(zero, on_no_match); // On success, advance position by length of capture. if (read_backward) { - __ subq(rdi, kSavedByteLength); + __ subq(rdi, rcx); } else { - __ addq(rdi, kSavedByteLength); + __ addq(rdi, rcx); } } __ bind(&fallthrough); @@ -757,6 +756,7 @@ void RegExpMacroAssemblerX64::SkipUntilBitInTable( [&](Register index, Register callee_saved) { // No need to push callee_saved since we never fall through. __ addq(rdi, index); + LoadCurrentCharacterUnchecked(cp_offset, 1); __ jmp(on_match); }); Bind(&scalar); @@ -1482,36 +1482,26 @@ void RegExpMacroAssemblerX64::Fail() { } void RegExpMacroAssemblerX64::LoadRegExpStackPointerFromMemory(Register dst) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ movq(dst, __ ExternalReferenceAsOperand(ref, dst)); + __ movq(dst, Operand(regexp_stack(), Stack::kStackPointerOffset)); } -void RegExpMacroAssemblerX64::StoreRegExpStackPointerToMemory( - Register src, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); - __ movq(__ ExternalReferenceAsOperand(ref, scratch), src); +void RegExpMacroAssemblerX64::StoreRegExpStackPointerToMemory(Register src) { + __ movq(Operand(regexp_stack(), Stack::kStackPointerOffset), src); } void RegExpMacroAssemblerX64::PushRegExpBasePointer(Register stack_pointer, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ movq(scratch, __ ExternalReferenceAsOperand(ref, scratch)); + __ movq(scratch, Operand(regexp_stack(), Stack::kMemoryTopOffset)); __ subq(scratch, stack_pointer); __ movq(Operand(rbp, kRegExpStackBasePointerOffset), scratch); } void RegExpMacroAssemblerX64::PopRegExpBasePointer(Register stack_pointer_out, Register scratch) { - ExternalReference ref = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ movq(scratch, Operand(rbp, kRegExpStackBasePointerOffset)); - __ movq(stack_pointer_out, - __ ExternalReferenceAsOperand(ref, stack_pointer_out)); + __ movq(stack_pointer_out, Operand(regexp_stack(), Stack::kMemoryTopOffset)); __ subq(stack_pointer_out, scratch); - StoreRegExpStackPointerToMemory(stack_pointer_out, scratch); + StoreRegExpStackPointerToMemory(stack_pointer_out); } DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( @@ -1596,6 +1586,9 @@ DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( __ Push(Immediate(0)); // The backtrack counter. __ Push(Immediate(0)); // The regexp stack base ptr. + __ Move(regexp_stack(), + ExternalReference::address_of_regexp_stack_thread_local(isolate())); + // Initialize backtrack stack pointer. It must not be clobbered from here // on. Note the backtrack_stackpointer is callee-saved. static_assert(backtrack_stackpointer() == rbx); @@ -1659,8 +1652,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( // initialized above; storing it would corrupt the saved stack pointer // (regexp::StackScope verifies it is unchanged across the exec call). if (backtrack_stack_used()) { - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), - kScratchRegister); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); } // CallCheckStackGuardState preserves no registers beside rbp and rsp. CallCheckStackGuardState(extra_space_for_variables); @@ -1930,7 +1922,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( __ pushq(rdi); - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); CallCheckStackGuardState(); __ testq(rax, rax); @@ -1958,7 +1950,7 @@ DirectHandle<HeapObject> RegExpMacroAssemblerX64::GetCode( // Call GrowStack(isolate). - StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); + StoreRegExpStackPointerToMemory(backtrack_stackpointer()); static constexpr int kNumArguments = 1; __ PrepareCallCFunction(kNumArguments); @@ -2072,20 +2064,15 @@ void RegExpMacroAssemblerX64::ReadPositionFromRegister(Register dst, int reg) { // reg = top - sp. void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) { set_backtrack_stack_used(); - ExternalReference stack_top_address = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); - __ movq(rax, __ ExternalReferenceAsOperand(stack_top_address, rax)); + __ movq(rax, Operand(regexp_stack(), Stack::kMemoryTopOffset)); __ subq(rax, backtrack_stackpointer()); __ movq(register_location(reg), rax); } void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) { set_backtrack_stack_used(); - ExternalReference stack_top_address = - ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); __ movq(backtrack_stackpointer(), - __ ExternalReferenceAsOperand(stack_top_address, - backtrack_stackpointer())); + Operand(regexp_stack(), Stack::kMemoryTopOffset)); __ subq(backtrack_stackpointer(), register_location(reg)); } @@ -2265,7 +2252,7 @@ void RegExpMacroAssemblerX64::FixupCodeRelativePositions() { patch_position, offset + position + InstructionStream::kHeaderSize - kHeapObjectTag); } - code_relative_fixup_positions_.Rewind(0); + code_relative_fixup_positions_.clear(); } void RegExpMacroAssemblerX64::Push(Label* backtrack_target) { @@ -2303,11 +2290,10 @@ void RegExpMacroAssemblerX64::CheckPreemption() { } void RegExpMacroAssemblerX64::CheckStackLimit() { + DCHECK(backtrack_stack_used()); Label no_stack_overflow; - ExternalReference stack_limit = - ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ load_rax(stack_limit); - __ cmpq(backtrack_stackpointer(), rax); + __ cmpq(backtrack_stackpointer(), + Operand(regexp_stack(), Stack::kLimitOffset)); __ j(above, &no_stack_overflow, Label::kNear); SafeCall(&stack_overflow_label_); @@ -2316,11 +2302,11 @@ void RegExpMacroAssemblerX64::CheckStackLimit() { } void RegExpMacroAssemblerX64::AssertAboveStackLimitMinusSlack() { + DCHECK(backtrack_stack_used()); DCHECK(v8_flags.slow_debug_code); Label no_stack_overflow; ASM_CODE_COMMENT_STRING(&masm_, "AssertAboveStackLimitMinusSlack"); - auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate()); - __ load_rax(l); + __ movq(rax, Operand(regexp_stack(), Stack::kLimitOffset)); __ subq(rax, Immediate(Stack::kStackLimitSlackSize)); __ cmpq(backtrack_stackpointer(), rax); __ j(above, &no_stack_overflow, Label::kNear); diff --git a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h index d0eae065f023..70d26b4ebc92 100644 --- a/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h +++ b/deps/v8/src/regexp/x64/regexp-macro-assembler-x64.h @@ -8,7 +8,7 @@ #include "src/base/functional/function-ref.h" #include "src/codegen/macro-assembler.h" #include "src/regexp/regexp-macro-assembler.h" -#include "src/zone/zone-chunk-list.h" +#include "src/zone/zone-containers.h" namespace v8 { namespace internal { @@ -259,6 +259,11 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 // object. static constexpr Register code_object_pointer() { return r8; } + // Register holding the address of the regexp stack's thread-local block, + // from which the stack limit, memory top and saved stack pointer are + // loaded at Stack::k*Offset. + static constexpr Register regexp_stack() { return r12; } + inline ScaleFactor CharSizeScaleFactor() { switch (mode()) { case LATIN1: @@ -314,7 +319,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 inline void Drop(); void LoadRegExpStackPointerFromMemory(Register dst); - void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void StoreRegExpStackPointerToMemory(Register src); void PushRegExpBasePointer(Register scratch_pointer, Register scratch); void PopRegExpBasePointer(Register scratch_pointer_out, Register scratch); @@ -340,7 +345,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 // consistency, we also keep it uninitialized here. const NoRootArrayScope no_root_array_scope_; - ZoneChunkList<int> code_relative_fixup_positions_; + ZoneVector<int> code_relative_fixup_positions_; // One greater than maximal register index actually used. int num_registers_; diff --git a/deps/v8/src/roots/roots-inl.h b/deps/v8/src/roots/roots-inl.h index fbbbe97807b8..7b0e28fdd3dd 100644 --- a/deps/v8/src/roots/roots-inl.h +++ b/deps/v8/src/roots/roots-inl.h @@ -12,6 +12,7 @@ #include "src/execution/isolate.h" #include "src/execution/local-isolate.h" #include "src/handles/handles.h" +#include "src/objects/map.h" #include "src/objects/oddball.h" #include "src/objects/slots.h" #include "src/objects/string.h" @@ -54,16 +55,24 @@ bool RootsTable::IsRootHandle(IndirectHandle<T> handle, } #define ROOT_ACCESSOR(Type, name, CamelName) \ - IndirectHandle<Type> RootsTable::name() { \ - return IndirectHandle<Type>( \ + IndirectHandle<ReadOnly<Type>> RootsTable::name() { \ + return IndirectHandle<ReadOnly<Type>>( \ handle_at(RootIndex::k##CamelName).location()); \ } -ROOT_LIST(ROOT_ACCESSOR) +READ_ONLY_ROOT_LIST(ROOT_ACCESSOR) #ifndef V8_ENABLE_TDZ_HOLE ROOT_ACCESSOR(TdzHole, tdz_hole_value, TdzHoleValue) #endif #undef ROOT_ACCESSOR +#define ROOT_ACCESSOR(Type, name, CamelName) \ + IndirectHandle<Type> RootsTable::name() { \ + return IndirectHandle<Type>( \ + handle_at(RootIndex::k##CamelName).location()); \ + } +MUTABLE_ROOT_LIST(ROOT_ACCESSOR) +#undef ROOT_ACCESSOR + IndirectHandle<Object> RootsTable::handle_at(RootIndex index) { return IndirectHandle<Object>(&(*this)[index]); } @@ -91,12 +100,12 @@ ReadOnlyRoots::ReadOnlyRoots(LocalIsolate* isolate) // have the right type, and to avoid the heavy #includes that would be // required for checked casts. -#define ROOT_ACCESSOR(Type, name, CamelName) \ - V8_RO_CONST Tagged<Type> ReadOnlyRoots::name() const { \ - return unchecked_##name(); \ - } \ - V8_RO_CONST Tagged<Type> ReadOnlyRoots::unchecked_##name() const { \ - return UncheckedCast<Type>(object_at(RootIndex::k##CamelName)); \ +#define ROOT_ACCESSOR(Type, name, CamelName) \ + V8_RO_CONST Tagged<ReadOnly<Type>> ReadOnlyRoots::name() const { \ + return unchecked_##name(); \ + } \ + V8_RO_CONST Tagged<ReadOnly<Type>> ReadOnlyRoots::unchecked_##name() const { \ + return UncheckedCast<ReadOnly<Type>>(object_at(RootIndex::k##CamelName)); \ } READ_ONLY_ROOT_LIST(ROOT_ACCESSOR) #ifndef V8_ENABLE_TDZ_HOLE @@ -104,13 +113,15 @@ ROOT_ACCESSOR(TdzHole, tdz_hole_value, TdzHoleValue) #endif #undef ROOT_ACCESSOR -V8_RO_CONST Tagged<Boolean> ReadOnlyRoots::boolean_value(bool value) const { - return value ? Tagged<Boolean>(true_value()) : Tagged<Boolean>(false_value()); +V8_RO_CONST Tagged<ReadOnly<Boolean>> ReadOnlyRoots::boolean_value( + bool value) const { + return value ? Tagged<ReadOnly<Boolean>>(true_value()) + : Tagged<ReadOnly<Boolean>>(false_value()); } -V8_RO_CONST Tagged<String> ReadOnlyRoots::single_character_string( +V8_RO_CONST Tagged<ReadOnly<String>> ReadOnlyRoots::single_character_string( int code) const { - return UncheckedCast<String>( + return UncheckedCast<ReadOnly<String>>( object_at(RootsTable::SingleCharacterStringIndex(code))); } diff --git a/deps/v8/src/roots/roots.cc b/deps/v8/src/roots/roots.cc index 00f2916056b0..4a5d464d0969 100644 --- a/deps/v8/src/roots/roots.cc +++ b/deps/v8/src/roots/roots.cc @@ -86,7 +86,7 @@ void ReadOnlyRoots::VerifyNameForProtectors() { namespace { #define ROOT_TYPE_CHECK(Type, name, CamelName) \ - bool CheckType_##name(Tagged<Type> value) { \ + bool CheckType_##name(Tagged<ReadOnly<Type>> value) { \ /* For the oddball subtypes, the "IsFoo" checks only check for address in \ * the RORoots, which is trivially true here. So, do a slow check of the \ * oddball kind instead. Do the casts via Tagged<Object> to satisfy cast \ @@ -104,7 +104,7 @@ namespace { /* Skip verification of individual holes, just check for holeness */ \ return IsAnyHole(value); \ } else { \ - return Is##Type(value); \ + return Is<ReadOnly<Type>>(value); \ } \ } @@ -113,7 +113,7 @@ READ_ONLY_ROOT_LIST(ROOT_TYPE_CHECK) template <typename T> void CheckTrustedMapHelper(RootIndex index, Tagged<T> obj) { - if constexpr (std::is_same_v<T, Map>) { + if constexpr (is_subtype_v<T, Map>) { CHECK_EQ(RootsTable::IsInTrustedObjectMapList(index), InstanceTypeChecker::IsTrustedObject(obj->instance_type())); } diff --git a/deps/v8/src/roots/roots.h b/deps/v8/src/roots/roots.h index b995b4bffd6c..1abe1280bd9a 100644 --- a/deps/v8/src/roots/roots.h +++ b/deps/v8/src/roots/roots.h @@ -196,6 +196,7 @@ class RootVisitor; V(Map, ephemeron_hash_table_map, EphemeronHashTableMap) \ V(Map, embedder_data_array_map, EmbedderDataArrayMap) \ V(Map, weak_cell_map, WeakCellMap) \ + V(Map, uninitialized_heap_number_map, UninitializedHeapNumberMap) \ TRUSTED_OBJECT_MAP_ROOT_LIST(V) \ /* String maps */ \ V(Map, seq_two_byte_string_map, SeqTwoByteStringMap) \ @@ -235,8 +236,6 @@ class RootVisitor; V(Map, hole_map, HoleMap) \ /* Shared space object maps */ \ V(Map, js_shared_array_map, JSSharedArrayMap) \ - V(Map, js_atomics_mutex_map, JSAtomicsMutexMap) \ - V(Map, js_atomics_condition_map, JSAtomicsConditionMap) \ V(Map, descriptor_array_map, DescriptorArrayMap) \ V(Map, on_heap_basic_block_profiler_data_map, \ OnHeapBasicBlockProfilerDataMap) \ @@ -452,6 +451,8 @@ class RootVisitor; V(HeapObject, weak_refs_keep_during_job, WeakRefsKeepDuringJob) \ V(Object, functions_marked_for_manual_optimization, \ FunctionsMarkedForManualOptimization) \ + V(Object, functions_marked_for_disabled_eager_inlining, \ + FunctionsMarkedForDisabledEagerInlining) \ V(ArrayList, basic_block_profiling_data, BasicBlockProfilingData) \ V(WeakArrayList, shared_wasm_memories, SharedWasmMemories) \ /* EphemeronHashTable for debug scopes (local debug evaluate) */ \ @@ -655,9 +656,9 @@ static_assert(RootIndex::kFirstSerializableTrustedObjectMap <= SERIALIZABLE_TRUSTED_OBJECT_MAP_ROOT_LIST(FOR_SERIALIZABLE_TRUSTED_MAP_CHECK) #undef FOR_SERIALIZABLE_TRUSTED_MAP_CHECK -#define ROOT_TYPE_FWD_DECL(Type, name, CamelName) class Type; -ROOT_LIST(ROOT_TYPE_FWD_DECL) -#undef ROOT_TYPE_FWD_DECL +#define DEF_STRUCT_FWD_DECLARATION(NAME, Name, name) class Name; +STRUCT_LIST(DEF_STRUCT_FWD_DECLARATION) +#undef DEF_STRUCT_FWD_DECLARATION // Represents a storage of V8 heap roots. class RootsTable { @@ -678,13 +679,18 @@ class RootsTable { IndirectHandle<HeapNumber> FindHeapNumber(double value); #define ROOT_ACCESSOR(Type, name, CamelName) \ - V8_INLINE IndirectHandle<Type> name(); - ROOT_LIST(ROOT_ACCESSOR) + V8_NODISCARD V8_INLINE IndirectHandle<ReadOnly<Type>> name(); + READ_ONLY_ROOT_LIST(ROOT_ACCESSOR) #ifndef V8_ENABLE_TDZ_HOLE ROOT_ACCESSOR(TdzHole, tdz_hole_value, TdzHoleValue) #endif #undef ROOT_ACCESSOR +#define ROOT_ACCESSOR(Type, name, CamelName) \ + V8_NODISCARD V8_INLINE IndirectHandle<Type> name(); + MUTABLE_ROOT_LIST(ROOT_ACCESSOR) +#undef ROOT_ACCESSOR + V8_INLINE IndirectHandle<Object> handle_at(RootIndex root_index); Address const& operator[](RootIndex root_index) const { @@ -841,9 +847,10 @@ class ReadOnlyRoots { // map-word instead of a tagged heap pointer. MapWord one_pointer_filler_map_word(); -#define ROOT_ACCESSOR(Type, name, CamelName) \ - V8_RO_CONST V8_INLINE Tagged<Type> name() const; \ - V8_RO_CONST V8_INLINE Tagged<Type> unchecked_##name() const; +#define ROOT_ACCESSOR(Type, name, CamelName) \ + V8_NODISCARD V8_RO_CONST V8_INLINE Tagged<ReadOnly<Type>> name() const; \ + V8_NODISCARD V8_RO_CONST V8_INLINE Tagged<ReadOnly<Type>> unchecked_##name() \ + const; READ_ONLY_ROOT_LIST(ROOT_ACCESSOR) #ifndef V8_ENABLE_TDZ_HOLE @@ -858,9 +865,11 @@ class ReadOnlyRoots { void VerifyTypes(); #endif - V8_RO_CONST V8_INLINE Tagged<Boolean> boolean_value(bool value) const; + V8_RO_CONST V8_INLINE + Tagged<ReadOnly<Boolean>> boolean_value(bool value) const; - V8_RO_CONST V8_INLINE Tagged<String> single_character_string(int code) const; + V8_RO_CONST V8_INLINE Tagged<ReadOnly<String>> single_character_string( + int code) const; V8_RO_CONST V8_INLINE Address address_at(RootIndex root_index) const; V8_RO_CONST V8_INLINE Tagged<Object> object_at(RootIndex root_index) const; diff --git a/deps/v8/src/roots/static-roots.h b/deps/v8/src/roots/static-roots.h index 0950405633ad..14cad3e2f179 100644 --- a/deps/v8/src/roots/static-roots.h +++ b/deps/v8/src/roots/static-roots.h @@ -9,15 +9,15 @@ #ifdef V8_ENABLE_WEBASSEMBLY #ifdef V8_INTL_SUPPORT -#include "src/roots/static-roots-intl-wasm.h" // IWYU pragma: export +#include "src/gen/intl-wasm/static-roots.h" // IWYU pragma: export #else -#include "src/roots/static-roots-nointl-wasm.h" // IWYU pragma: export +#include "src/gen/nointl-wasm/static-roots.h" // IWYU pragma: export #endif #else #ifdef V8_INTL_SUPPORT -#include "src/roots/static-roots-intl-nowasm.h" // IWYU pragma: export +#include "src/gen/intl-nowasm/static-roots.h" // IWYU pragma: export #else -#include "src/roots/static-roots-nointl-nowasm.h" // IWYU pragma: export +#include "src/gen/nointl-nowasm/static-roots.h" // IWYU pragma: export #endif #endif diff --git a/deps/v8/src/runtime/runtime-array.cc b/deps/v8/src/runtime/runtime-array.cc index b65cd7ce87e8..f19659383c4d 100644 --- a/deps/v8/src/runtime/runtime-array.cc +++ b/deps/v8/src/runtime/runtime-array.cc @@ -43,11 +43,10 @@ RUNTIME_FUNCTION(Runtime_NewArray) { JavaScriptArguments argv(argc, args.address_of_arg_at(0)); DirectHandle<JSFunction> constructor = args.at<JSFunction>(argc); DirectHandle<JSReceiver> new_target = args.at<JSReceiver>(argc + 1); - Handle<HeapObject> type_info = args.at<HeapObject>(argc + 2); - // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite. - DirectHandle<AllocationSite> site = IsAllocationSite(*type_info) - ? Cast<AllocationSite>(type_info) - : Handle<AllocationSite>::null(); + DirectHandle<HeapObject> type_info = args.at<HeapObject>(argc + 2); + MaybeDirectHandle<AllocationSite> site = + IsAllocationSite(*type_info) ? Cast<AllocationSite>(type_info) + : MaybeDirectHandle<AllocationSite>(); Factory* factory = isolate->factory(); @@ -99,7 +98,7 @@ RUNTIME_FUNCTION(Runtime_NewArray) { JSFunction::GetDerivedMap(isolate, constructor, new_target)); ElementsKind initial_kind = can_use_type_feedback - ? site->GetElementsKind() + ? site.ToHandleChecked()->GetElementsKind() : initial_map->elements_kind(); ElementsKind to_kind = holey ? GetHoleyElementsKind(initial_kind) : initial_kind; @@ -112,7 +111,8 @@ RUNTIME_FUNCTION(Runtime_NewArray) { if (to_kind != initial_kind) { // Update the allocation site info to reflect the advice alteration. - if (!site.is_null()) site->SetElementsKind(to_kind); + DirectHandle<AllocationSite> site_handle; + if (site.ToHandle(&site_handle)) site_handle->SetElementsKind(to_kind); } // We should allocate with an initial map that reflects the allocation site @@ -122,7 +122,7 @@ RUNTIME_FUNCTION(Runtime_NewArray) { // If we don't care to track arrays of to_kind ElementsKind, then // don't emit a memento for them. - DirectHandle<AllocationSite> allocation_site; + MaybeDirectHandle<AllocationSite> allocation_site; if (AllocationSite::ShouldTrack(to_kind)) { allocation_site = site; } @@ -137,7 +137,8 @@ RUNTIME_FUNCTION(Runtime_NewArray) { RETURN_FAILURE_ON_EXCEPTION( isolate, ArrayConstructInitializeElements(isolate, array, &argv)); - if (!site.is_null() && + DirectHandle<AllocationSite> site_handle; + if (site.ToHandle(&site_handle) && (old_kind != array->GetElementsKind() || !can_use_type_feedback || !can_inline_array_constructor)) { // Protect against deopt loops by disabling speculating optimizations in @@ -145,7 +146,7 @@ RUNTIME_FUNCTION(Runtime_NewArray) { // eventually optimistically try to inline and worst case will deopt and // set the allocation site itself, or set the CallIC disable speculation // bit. - site->SetSpeculationDisabled(); + site_handle->SetSpeculationDisabled(); } return *array; diff --git a/deps/v8/src/runtime/runtime-classes.cc b/deps/v8/src/runtime/runtime-classes.cc index c07310cba6d6..11f8b689ce03 100644 --- a/deps/v8/src/runtime/runtime-classes.cc +++ b/deps/v8/src/runtime/runtime-classes.cc @@ -325,10 +325,8 @@ bool AddDescriptorsByTemplate( if (IsSmi(value)) { value = GetMethodWithSharedName(isolate, args, value); } - auto [representation, constness] = - Object::OptimalRepresentation(value, details.constness()); - details = details.CopyWithRepresentation(representation) - .CopyWithConstness(constness); + details = details.CopyWithRepresentation( + Object::OptimalRepresentation(value)); } else { DCHECK_EQ(PropertyKind::kAccessor, details.kind()); if (IsAccessorPair(value)) { diff --git a/deps/v8/src/runtime/runtime-compiler.cc b/deps/v8/src/runtime/runtime-compiler.cc index e998c4d59f4f..05c6c8f7a148 100644 --- a/deps/v8/src/runtime/runtime-compiler.cc +++ b/deps/v8/src/runtime/runtime-compiler.cc @@ -13,6 +13,7 @@ #include "src/execution/arguments-inl.h" #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" +#include "src/interpreter/bytecode-flags-and-tokens.h" #include "src/objects/abstract-code-inl.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/objects-inl.h" @@ -39,7 +40,7 @@ void LogExecution(Isolate* isolate, DirectHandle<JSFunction> function) { CodeKind kind = function->abstract_code(isolate)->kind(); // Not adding "-interpreter" for tooling backwards compatibility. if (kind != CodeKind::INTERPRETED_FUNCTION) { - event_name += "-"; + event_name += '-'; event_name += CodeKindToString(kind); } LOG(isolate, FunctionEvent( @@ -154,11 +155,20 @@ Builtin GetTypedBuiltinForUnary(int hint, Builtin current_builtin) noexcept { #undef TYPED_UNOP_DISPATCH_CASE } -V8_INLINE void UpdateEmbeddedFeedback(Tagged<BytecodeArray> bytecode_array, - int feedback_offset, - int current_feedback) { +// Merges {new_feedback} into the embedded feedback byte and returns the +// result. Typed stubs report Combine(stub type, observed type), which can be +// narrower than the byte if the interpreter widened it since the stub was +// patched in, so the byte must never simply be overwritten. +template <typename Feedback> +V8_INLINE int UpdateEmbeddedFeedback(Tagged<BytecodeArray> bytecode_array, + int feedback_offset, int new_feedback) { + using TypeIndex = typename Feedback::TypeIndex; feedback_offset -= BytecodeArray::kHeaderSize - kHeapObjectTag; - bytecode_array->set(feedback_offset, static_cast<uint8_t>(current_feedback)); + TypeIndex merged = Feedback::CombineTypeIndex( + static_cast<TypeIndex>(bytecode_array->get(feedback_offset)), + static_cast<TypeIndex>(new_feedback)); + bytecode_array->set(feedback_offset, static_cast<uint8_t>(merged)); + return static_cast<int>(merged); } using GetTypedBuiltinFn = Builtin (*)(int, Builtin); @@ -203,14 +213,14 @@ V8_INLINE void TryPatchUnaryOpBaselineCode(Isolate* isolate, TryPatchBaselineCodeImpl(isolate, current_feedback, GetTypedBuiltinForUnary); } +template <typename Feedback> V8_INLINE int UpdateEmbeddedFeedbackAndGetCurrent(RuntimeArguments args) { - int current_feedback = args.smi_value_at(0); - DCHECK_LE(current_feedback, std::numeric_limits<uint8_t>::max()); - DCHECK_GE(current_feedback, 0); - UpdateEmbeddedFeedback(TrustedCast<BytecodeArray>(args[2]), - static_cast<int>(args.number_value_at(3)), - current_feedback); - return current_feedback; + int new_feedback = args.smi_value_at(0); + DCHECK_LT(new_feedback, static_cast<int>(Feedback::kNumTypeIndices)); + DCHECK_GE(new_feedback, 0); + return UpdateEmbeddedFeedback<Feedback>( + TrustedCast<BytecodeArray>(args[2]), + static_cast<int>(args.number_value_at(3)), new_feedback); } #endif // V8_ENABLE_SPARKPLUG_PLUS } // namespace @@ -826,7 +836,8 @@ RUNTIME_FUNCTION(Runtime_LogOrTraceOptimizedOSREntry) { static Tagged<Object> CompileGlobalEval( Isolate* isolate, Handle<i::Object> source_object, DirectHandle<SharedFunctionInfo> outer_info, LanguageMode language_mode, - int eval_scope_info_index, int eval_position) { + int eval_scope_info_index, int eval_position, + bool private_name_lookup_skips_outer_class) { DirectHandle<NativeContext> native_context = isolate->native_context(); // Check if native context allows code generation from @@ -865,7 +876,8 @@ static Tagged<Object> CompileGlobalEval( isolate, compiled, Compiler::GetFunctionFromEval( isolate, source.ToHandleChecked(), outer_info, context, language_mode, - restriction, kNoSourcePosition, eval_position), + restriction, kNoSourcePosition, eval_position, + ParsingWhileDebugging::kNo, private_name_lookup_skips_outer_class), ReadOnlyRoots(isolate).exception()); return *compiled; } @@ -882,13 +894,17 @@ RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) { return *callee; } - DCHECK(is_valid_language_mode(args.smi_value_at(3))); - LanguageMode language_mode = static_cast<LanguageMode>(args.smi_value_at(3)); + int eval_flags = args.smi_value_at(3); + LanguageMode language_mode = + interpreter::ResolveEvalFlags::LanguageModeBit::decode(eval_flags); + bool private_name_lookup_skips_outer_class = interpreter::ResolveEvalFlags:: + PrivateNameLookupSkipsOuterClassBit::decode(eval_flags); DirectHandle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(), isolate); return CompileGlobalEval(isolate, args.at<Object>(1), outer_info, language_mode, args.smi_value_at(4), - args.smi_value_at(5)); + args.smi_value_at(5), + private_name_lookup_skips_outer_class); } #ifdef V8_ENABLE_SPARKPLUG_PLUS @@ -898,8 +914,9 @@ RUNTIME_FUNCTION(Runtime_PatchCompareOpBaselineCode) { DCHECK_EQ(4, args.length()); DirectHandle<Boolean> compare_result = args.at<Boolean>(1); - TryPatchCompareOpBaselineCode(isolate, - UpdateEmbeddedFeedbackAndGetCurrent(args)); + TryPatchCompareOpBaselineCode( + isolate, + UpdateEmbeddedFeedbackAndGetCurrent<CompareOperationFeedback>(args)); return *compare_result; } @@ -909,8 +926,9 @@ RUNTIME_FUNCTION(Runtime_PatchCompareOpBaselineCodeAndThrow) { DCHECK_EQ(4, args.length()); DirectHandle<Object> exception = args.at<Object>(1); - TryPatchCompareOpBaselineCode(isolate, - UpdateEmbeddedFeedbackAndGetCurrent(args)); + TryPatchCompareOpBaselineCode( + isolate, + UpdateEmbeddedFeedbackAndGetCurrent<CompareOperationFeedback>(args)); return isolate->ReThrow(*exception); } @@ -920,8 +938,9 @@ RUNTIME_FUNCTION(Runtime_PatchBinopBaselineCode) { DCHECK_EQ(4, args.length()); DirectHandle<Object> result = args.at<Object>(1); - TryPatchBinaryOpBaselineCode(isolate, - UpdateEmbeddedFeedbackAndGetCurrent(args)); + TryPatchBinaryOpBaselineCode( + isolate, + UpdateEmbeddedFeedbackAndGetCurrent<BinaryOperationFeedback>(args)); return *result; } @@ -931,8 +950,9 @@ RUNTIME_FUNCTION(Runtime_PatchBinopBaselineCodeAndThrow) { DCHECK_EQ(4, args.length()); DirectHandle<Object> exception = args.at<Object>(1); - TryPatchBinaryOpBaselineCode(isolate, - UpdateEmbeddedFeedbackAndGetCurrent(args)); + TryPatchBinaryOpBaselineCode( + isolate, + UpdateEmbeddedFeedbackAndGetCurrent<BinaryOperationFeedback>(args)); return isolate->ReThrow(*exception); } @@ -942,8 +962,9 @@ RUNTIME_FUNCTION(Runtime_PatchUnaryOpBaselineCode) { DCHECK_EQ(4, args.length()); DirectHandle<Object> result = args.at<Object>(1); - TryPatchUnaryOpBaselineCode(isolate, - UpdateEmbeddedFeedbackAndGetCurrent(args)); + TryPatchUnaryOpBaselineCode( + isolate, + UpdateEmbeddedFeedbackAndGetCurrent<BinaryOperationFeedback>(args)); return *result; } @@ -953,8 +974,9 @@ RUNTIME_FUNCTION(Runtime_PatchUnaryOpBaselineCodeAndThrow) { DCHECK_EQ(4, args.length()); DirectHandle<Object> exception = args.at<Object>(1); - TryPatchUnaryOpBaselineCode(isolate, - UpdateEmbeddedFeedbackAndGetCurrent(args)); + TryPatchUnaryOpBaselineCode( + isolate, + UpdateEmbeddedFeedbackAndGetCurrent<BinaryOperationFeedback>(args)); return isolate->ReThrow(*exception); } #endif // V8_ENABLE_SPARKPLUG_PLUS diff --git a/deps/v8/src/runtime/runtime-debug.cc b/deps/v8/src/runtime/runtime-debug.cc index af91478fd5e3..9e22a8468c8e 100644 --- a/deps/v8/src/runtime/runtime-debug.cc +++ b/deps/v8/src/runtime/runtime-debug.cc @@ -79,7 +79,6 @@ RUNTIME_FUNCTION(Runtime_IterableForEach) { RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) { using interpreter::Bytecode; using interpreter::Bytecodes; - using interpreter::OperandScale; SealHandleScope shs(isolate); DCHECK_EQ(1, args.length()); @@ -111,16 +110,25 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) { InterpretedFrame* interpreted_frame = reinterpret_cast<InterpretedFrame*>(it.frame()); - bool side_effect_check_failed = false; if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) { - side_effect_check_failed = + bool side_effect_check_failed = !isolate->debug()->PerformSideEffectCheckAtBytecode(interpreted_frame); + if (side_effect_check_failed) { + return MakePair(ReadOnlyRoots(isolate).exception(), + Smi::FromInt(static_cast<uint8_t>(Bytecode::kIllegal))); + } } - // Make sure to only access these objects after the side effect check, as the - // check can allocate on failure. - Tagged<SharedFunctionInfo> shared = interpreted_frame->function()->shared(); - Tagged<BytecodeArray> bytecode_array = shared->GetBytecodeArray(isolate); + Tagged<Object> interrupt_object = isolate->stack_guard()->HandleInterrupts(); + if (IsExceptionHole(interrupt_object)) { + return MakePair(interrupt_object, + Smi::FromInt(static_cast<uint8_t>(Bytecode::kIllegal))); + } + + // Make sure to only access these objects after the side effect check and + // interrupt handling, as both can allocate or modify debugger state. + Tagged<BytecodeArray> bytecode_array = + interpreted_frame->GetOriginalBytecodeArray(); int bytecode_offset = interpreted_frame->GetBytecodeOffset(); Bytecode bytecode = Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); @@ -132,23 +140,6 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) { interpreted_frame->PatchBytecodeArray(bytecode_array); } - // We do not have to deal with operand scale here. If the bytecode at the - // break is prefixed by operand scaling, we would have patched over the - // scaling prefix. We now simply dispatch to the handler for the prefix. - // We need to deserialize now to ensure we don't hit the debug break again - // after deserializing. - OperandScale operand_scale = OperandScale::kSingle; - isolate->interpreter()->GetBytecodeHandler(bytecode, operand_scale); - - if (side_effect_check_failed) { - return MakePair(ReadOnlyRoots(isolate).exception(), - Smi::FromInt(static_cast<uint8_t>(bytecode))); - } - Tagged<Object> interrupt_object = isolate->stack_guard()->HandleInterrupts(); - if (IsExceptionHole(interrupt_object)) { - return MakePair(interrupt_object, - Smi::FromInt(static_cast<uint8_t>(bytecode))); - } return MakePair(isolate->debug()->return_value(), Smi::FromInt(static_cast<uint8_t>(bytecode))); } @@ -170,6 +161,9 @@ RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) { if (!it.done() && it.frame()->fp() < isolate->thread_local_top()->last_api_entry_) { isolate->debug()->Break(it.frame(), function); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } } return function->shared()->GetCode(isolate); @@ -378,7 +372,7 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties( case Module::kEvaluated: status = "evaluated"; break; - case Module::kErrored: + case Module::kEvaluatedError: status = "errored"; break; } @@ -780,15 +774,19 @@ RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) { // Ensure that the callee will perform debug check on function call too. DirectHandle<SharedFunctionInfo> shared(fun->shared(), isolate); isolate->debug()->DeoptimizeFunction(shared); - if (isolate->debug()->last_step_action() >= StepInto || - isolate->debug()->break_on_next_function_call()) { - DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints); + if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) { + // Side-effect free evaluation always runs with breaks disabled, so + // there is no need to prepare stepping, even if stepping or a pause on + // the next function call was requested before the evaluation started. + DCHECK(isolate->debug()->break_disabled()); + if (!isolate->debug()->PerformSideEffectCheck(fun, receiver)) { + return ReadOnlyRoots(isolate).exception(); + } + } else if (isolate->debug()->last_step_action() >= StepInto || + isolate->debug()->step_over_enters_functions() || + isolate->debug()->break_on_next_function_call()) { isolate->debug()->PrepareStepIn(fun); } - if (isolate->debug_execution_mode() == DebugInfo::kSideEffects && - !isolate->debug()->PerformSideEffectCheck(fun, receiver)) { - return ReadOnlyRoots(isolate).exception(); - } } return ReadOnlyRoots(isolate).undefined_value(); } diff --git a/deps/v8/src/runtime/runtime-forin.cc b/deps/v8/src/runtime/runtime-forin.cc index d0e1fcf0687b..7fa6bbedcaa8 100644 --- a/deps/v8/src/runtime/runtime-forin.cc +++ b/deps/v8/src/runtime/runtime-forin.cc @@ -14,10 +14,72 @@ namespace internal { namespace { -// Returns either a FixedArray or, if the given {receiver} has an enum cache -// that contains all enumerable properties of the {receiver} and its prototypes -// have none, the map of the {receiver}. This is used to speed up the check for -// deletions during a for-in. +MaybeDirectHandle<ForInEnumeratorHolder> TryCreateEnumeratorHolder( + Isolate* isolate, DirectHandle<JSReceiver> receiver, + FastKeyAccumulator* accumulator) { + if (!v8_flags.forin_enumerator_holder) return {}; + if (!IsJSObject(*receiver)) return {}; + DirectHandle<JSObject> object = Cast<JSObject>(receiver); + + if (!accumulator->has_empty_prototype()) return {}; + + ElementsKind elements_kind = object->GetElementsKind(); + if (!IsFastPackedElementsKind(elements_kind)) return {}; + + uint32_t elem_len; + if (IsJSArray(*object)) { + Tagged<Object> length = Cast<JSArray>(*object)->length(); + if (!IsSmi(length) || Smi::ToInt(length) <= 0) return {}; + elem_len = static_cast<uint32_t>(Smi::ToInt(length)); + } else { + elem_len = object->elements()->ulength().value(); + if (elem_len == 0 || !Smi::IsValid(elem_len)) return {}; + } + + DirectHandle<Map> map(object->map(), isolate); + if (!map->OnlyHasSimpleProperties()) return {}; + DCHECK(!map->is_dictionary_map()); + + int enum_length = map->EnumLength(); + if (enum_length == kInvalidEnumCacheSentinel) { + enum_length = map->NumberOfEnumerableProperties(); + if (enum_length > 0) { + DirectHandle<DescriptorArray> descriptors(map->instance_descriptors(), + isolate); + DirectHandle<FixedArray> keys(descriptors->enum_cache()->keys(), isolate); + if (static_cast<uint32_t>(enum_length) <= keys->ulength().value()) { + map->SetEnumLength(enum_length); + } else { + FastKeyAccumulator::InitializeFastPropertyEnumCache(isolate, map, + enum_length); + } + } else { + map->SetEnumLength(0); + } + } + + if (elem_len > static_cast<uint32_t>(FixedArray::kMaxLength - enum_length)) { + return {}; + } + + DirectHandle<FixedArray> named_keys = + enum_length > 0 + ? direct_handle(map->instance_descriptors()->enum_cache()->keys(), + isolate) + : isolate->factory()->empty_fixed_array(); + + int int_elem_len = static_cast<int>(elem_len); + return isolate->factory()->NewForInEnumeratorHolder( + map, named_keys, Smi::FromInt(int_elem_len), + Smi::FromInt(int_elem_len + enum_length)); +} + +// Returns either a FixedArray of keys, a ForInEnumeratorHolder (if {receiver} +// has fast packed elements, simple properties, and an empty prototype chain), +// or, if the given {receiver} has an enum cache that contains all enumerable +// properties of the {receiver} and its prototypes have none, the map of the +// {receiver}. This is used to speed up the check for deletions during a +// for-in. MaybeDirectHandle<HeapObject> Enumerate(Isolate* isolate, DirectHandle<JSReceiver> receiver) { JSObject::MakePrototypesFast(receiver, kStartAtReceiver, isolate); @@ -26,6 +88,11 @@ MaybeDirectHandle<HeapObject> Enumerate(Isolate* isolate, ENUMERABLE_STRINGS, true); // Test if we have an enum cache for {receiver}. if (!accumulator.is_receiver_simple_enum()) { + if (DirectHandle<ForInEnumeratorHolder> holder; + TryCreateEnumeratorHolder(isolate, receiver, &accumulator) + .ToHandle(&holder)) { + return holder; + } DirectHandle<FixedArray> keys; ASSIGN_RETURN_ON_EXCEPTION( isolate, keys, diff --git a/deps/v8/src/runtime/runtime-internal.cc b/deps/v8/src/runtime/runtime-internal.cc index d11f4cac1913..b0d9523d6b97 100644 --- a/deps/v8/src/runtime/runtime-internal.cc +++ b/deps/v8/src/runtime/runtime-internal.cc @@ -161,7 +161,8 @@ Tagged<Object> NewError(Isolate* isolate, RuntimeArguments args, DirectHandle<Object> message_args[kMaxMessageArgs]; int num_message_args = 0; while (num_message_args < kMaxMessageArgs && - args.length() > num_message_args + 1) { + args.length() > num_message_args + 1 && + !IsTheHole(args[num_message_args + 1])) { message_args[num_message_args] = args.at(num_message_args + 1); ++num_message_args; } @@ -193,7 +194,7 @@ RUNTIME_FUNCTION(Runtime_ThrowRangeError) { // this difference, we crash the program. if (MessageTemplateFromInt(message_id_smi) == MessageTemplate::kBigIntTooBig) { - FATAL("Aborting on invalid BigInt length"); + base::FatalNoSecurityImpact("Aborting on invalid BigInt length"); } } @@ -298,11 +299,10 @@ RUNTIME_FUNCTION(Runtime_NewTypeError) { RUNTIME_FUNCTION(Runtime_NewReferenceError) { HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); + DCHECK_EQ(1, args.length()); int template_index = args.smi_value_at(0); - Handle<Object> arg0 = args.at(1); MessageTemplate message_template = MessageTemplateFromInt(template_index); - return *isolate->factory()->NewReferenceError(message_template, arg0); + return *isolate->factory()->NewReferenceError(message_template); } RUNTIME_FUNCTION(Runtime_ThrowInvalidStringLength) { diff --git a/deps/v8/src/runtime/runtime-literals.cc b/deps/v8/src/runtime/runtime-literals.cc index 312f5ddcf904..a85050143ed2 100644 --- a/deps/v8/src/runtime/runtime-literals.cc +++ b/deps/v8/src/runtime/runtime-literals.cc @@ -132,8 +132,13 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( VisitElementOrProperty(copy, value)); if (copying) copy->FastPropertyAtPut(index, *value); } else if (copying && details.representation().IsDouble()) { - uint64_t double_value = Cast<HeapNumber>(raw)->value_as_bits(); - auto value = isolate->factory()->NewHeapNumberFromBits(double_value); + Handle<UnionOf<HeapNumber, UninitializedHeapNumber>> value; + if (IsUninitializedHeapNumber(raw)) { + value = isolate->factory()->NewUninitializedHeapNumber(); + } else { + uint64_t bits = Cast<HeapNumber>(raw)->value_as_bits(); + value = isolate->factory()->NewHeapNumberFromBits(bits); + } copy->FastPropertyAtPut(index, *value); } } diff --git a/deps/v8/src/runtime/runtime-object.cc b/deps/v8/src/runtime/runtime-object.cc index ec2e3e8cf393..96c1c2f434f3 100644 --- a/deps/v8/src/runtime/runtime-object.cc +++ b/deps/v8/src/runtime/runtime-object.cc @@ -1462,6 +1462,21 @@ Maybe<bool> FindPrivateMembersFromReceiver(Isolate* isolate, } } // namespace +MaybeDirectHandle<Object> Runtime::HasPrivateMember( + Isolate* isolate, DirectHandle<JSReceiver> receiver, + DirectHandle<String> desc) { + std::vector<PrivateMember> results; + MAYBE_RETURN_NULL( + CollectPrivateMembersFromReceiver(isolate, receiver, desc, &results)); + + if (results.size() > 1) { + THROW_NEW_ERROR(isolate, + NewError(MessageTemplate::kConflictingPrivateName, desc)); + } + + return isolate->factory()->ToBoolean(!results.empty()); +} + MaybeDirectHandle<Object> Runtime::GetPrivateMember( Isolate* isolate, DirectHandle<JSReceiver> receiver, DirectHandle<String> desc) { @@ -1530,6 +1545,23 @@ MaybeDirectHandle<Object> Runtime::SetPrivateMember( UNREACHABLE(); } +RUNTIME_FUNCTION(Runtime_HasPrivateMember) { + HandleScope scope(isolate); + // TODO(chromium:1381806) support specifying scopes, or selecting the right + // one from the conflicting names. + DCHECK_EQ(args.length(), 2); + DirectHandle<Object> receiver = args.at<Object>(0); + Handle<String> desc = args.at<String>(1); + if (IsJSReceiver(*receiver)) { + RETURN_RESULT_OR_FAILURE( + isolate, + Runtime::HasPrivateMember(isolate, Cast<JSReceiver>(receiver), desc)); + } + THROW_NEW_ERROR_RETURN_FAILURE( + isolate, + NewTypeError(MessageTemplate::kInvalidInOperatorUse, desc, receiver)); +} + RUNTIME_FUNCTION(Runtime_GetPrivateMember) { HandleScope scope(isolate); // TODO(chromium:1381806) support specifying scopes, or selecting the right @@ -1747,7 +1779,7 @@ RUNTIME_FUNCTION(Runtime_CheckFastIterableToListPrototype) { // Switch prototype to fast mode in order to ensure that constness tracking // will invalidate the prototype's validity cell in case of modification. - JSObject::OptimizeAsPrototype(prototype); + JSObject::MakePrototypesFast(prototype, kStartAtReceiver, isolate); // 1. Check if the prototype has expected [Symbol.iterator] property (kData // and kConst). diff --git a/deps/v8/src/runtime/runtime-promise.cc b/deps/v8/src/runtime/runtime-promise.cc index 169d48bd4567..af84ed30bf4e 100644 --- a/deps/v8/src/runtime/runtime-promise.cc +++ b/deps/v8/src/runtime/runtime-promise.cc @@ -20,6 +20,9 @@ RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) { isolate->RunAllPromiseHooks(PromiseHookType::kResolve, promise, isolate->factory()->undefined_value()); isolate->debug()->OnPromiseReject(promise, value); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } // Report only if we don't actually have a handler. if (!promise->has_handler()) { @@ -153,8 +156,12 @@ RUNTIME_FUNCTION(Runtime_RejectPromise) { DirectHandle<JSPromise> promise = args.at<JSPromise>(0); DirectHandle<Object> reason = args.at(1); DirectHandle<Boolean> debug_event = args.at<Boolean>(2); - return *JSPromise::Reject(promise, reason, - Object::BooleanValue(*debug_event, isolate)); + DirectHandle<Object> result = JSPromise::Reject( + promise, reason, Object::BooleanValue(*debug_event, isolate)); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } + return *result; } RUNTIME_FUNCTION(Runtime_ResolvePromise) { @@ -165,6 +172,9 @@ RUNTIME_FUNCTION(Runtime_ResolvePromise) { DirectHandle<Object> result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSPromise::Resolve(promise, resolution)); + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } return *result; } diff --git a/deps/v8/src/runtime/runtime-regexp.cc b/deps/v8/src/runtime/runtime-regexp.cc index 2a1ba0758cba..ec17453cda41 100644 --- a/deps/v8/src/runtime/runtime-regexp.cc +++ b/deps/v8/src/runtime/runtime-regexp.cc @@ -1308,6 +1308,21 @@ DirectHandle<FixedArray> CopyMatches(Isolate* isolate, return copy; } +// Returns whether the argument arrays in the cached {matches} were created in +// {native_context}. +bool CachedMatchesBelongTo(Tagged<FixedArray> matches, + Tagged<NativeContext> native_context) { + DisallowGarbageCollection no_gc; + const uint32_t length = matches->ulength().value(); + for (uint32_t i = 0; i < length; i++) { + Tagged<Object> match = matches->get(i); + if (!IsJSArray(match)) continue; + return Cast<JSArray>(match)->GetCreationContext() == native_context; + } + // Entries are only created when there is at least one match. + UNREACHABLE(); +} + // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain // separate last match info. See comment on that function. template <bool has_capture> @@ -1349,23 +1364,30 @@ static Tagged<UnionOf<ExceptionHole, Null, FixedArray>> SearchRegExpMultiple( isolate->heap(), *subject, regexp_data->wrapper(), &last_match_cache, regexp::ResultsCache::REGEXP_MULTIPLE_INDICES); if (IsFixedArray(cached_answer)) { - int capture_registers = JSRegExp::RegistersForCaptureCount(capture_count); - std::unique_ptr<int32_t[]> last_match(new int32_t[capture_registers]); - int32_t* raw_last_match = last_match.get(); - for (int i = 0; i < capture_registers; i++) { - raw_last_match[i] = Smi::ToInt(last_match_cache->get(i)); + Tagged<FixedArray> cached_answer_array = Cast<FixedArray>(cached_answer); + // An entry from another native context is a miss. + if (!has_capture || + CachedMatchesBelongTo(cached_answer_array, + isolate->raw_native_context())) { + int capture_registers = + JSRegExp::RegistersForCaptureCount(capture_count); + std::unique_ptr<int32_t[]> last_match(new int32_t[capture_registers]); + int32_t* raw_last_match = last_match.get(); + for (int i = 0; i < capture_registers; i++) { + raw_last_match[i] = Smi::ToInt(last_match_cache->get(i)); + } + DirectHandle<FixedArray> cached_fixed_array(cached_answer_array, + isolate); + // The cache FixedArray is a COW-array and we need to return a copy. A + // cache hit implies an earlier run compiled the pattern, so the capture + // name map is populated. + DirectHandle<FixedArray> copied_fixed_array = CopyMatches( + isolate, cached_fixed_array, + has_capture && re_data->has_capture_name_map(), capture_count); + RegExp::SetLastMatchInfo(isolate, last_match_array, subject, + capture_count, raw_last_match); + return *copied_fixed_array; } - DirectHandle<FixedArray> cached_fixed_array( - Cast<FixedArray>(cached_answer), isolate); - // The cache FixedArray is a COW-array and we need to return a copy. A - // cache hit implies an earlier run compiled the pattern, so the capture - // name map is populated. - DirectHandle<FixedArray> copied_fixed_array = CopyMatches( - isolate, cached_fixed_array, - has_capture && re_data->has_capture_name_map(), capture_count); - RegExp::SetLastMatchInfo(isolate, last_match_array, subject, - capture_count, raw_last_match); - return *copied_fixed_array; } } diff --git a/deps/v8/src/runtime/runtime-scopes.cc b/deps/v8/src/runtime/runtime-scopes.cc index e3da91b80779..8327e0e7b647 100644 --- a/deps/v8/src/runtime/runtime-scopes.cc +++ b/deps/v8/src/runtime/runtime-scopes.cc @@ -720,20 +720,6 @@ RUNTIME_FUNCTION(Runtime_NewClosure) { .Build(); } -RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) { - HandleScope scope(isolate); - DCHECK_EQ(2, args.length()); - DirectHandle<SharedFunctionInfo> shared = args.at<SharedFunctionInfo>(0); - DirectHandle<FeedbackCell> feedback_cell = args.at<FeedbackCell>(1); - DirectHandle<Context> context(isolate->context(), isolate); - // The caller ensures that we pretenure closures that are assigned - // directly to properties. - return *Factory::JSFunctionBuilder{isolate, shared, context} - .set_feedback_cell(feedback_cell) - .set_allocation_type(AllocationType::kOld) - .Build(); -} - RUNTIME_FUNCTION(Runtime_NewFunctionContext) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); @@ -950,8 +936,7 @@ MaybeDirectHandle<Object> StoreLookupSlot( SourceTextModule::StoreVariable(Cast<SourceTextModule>(holder), index, value); } else { - THROW_NEW_ERROR(isolate, - NewTypeError(MessageTemplate::kConstAssign, name)); + THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kConstAssign)); } return value; } @@ -966,8 +951,7 @@ MaybeDirectHandle<Object> StoreLookupSlot( if ((attributes & READ_ONLY) == 0) { Context::Set(holder_context, index, value, isolate); } else if (!is_sloppy_function_name || is_strict(language_mode)) { - THROW_NEW_ERROR(isolate, - NewTypeError(MessageTemplate::kConstAssign, name)); + THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kConstAssign)); } return value; } diff --git a/deps/v8/src/runtime/runtime-test-wasm.cc b/deps/v8/src/runtime/runtime-test-wasm.cc index 1c55008f80dd..802b3f92b208 100644 --- a/deps/v8/src/runtime/runtime-test-wasm.cc +++ b/deps/v8/src/runtime/runtime-test-wasm.cc @@ -9,6 +9,7 @@ #include "src/api/api.h" #include "src/base/memory.h" #include "src/base/platform/mutex.h" +#include "src/base/unique-array.h" #include "src/builtins/builtins-inl.h" #include "src/execution/arguments-inl.h" #include "src/execution/frames-inl.h" @@ -96,17 +97,15 @@ void ThrowRangeException(v8::Isolate* isolate, const char* message) { isolate->ThrowException(NewRangeException(isolate, message)); } -bool WasmModuleOverride(const v8::FunctionCallbackInfo<v8::Value>& info) { - DCHECK(ValidateCallbackInfo(info)); - if (IsWasmCompileAllowed(info.GetIsolate(), info[0], false)) return false; - ThrowRangeException(info.GetIsolate(), "Sync compile not allowed"); +bool WasmModuleOverride(v8::Isolate* isolate, v8::Local<v8::Value> source) { + if (IsWasmCompileAllowed(isolate, source, false)) return false; + ThrowRangeException(isolate, "Sync compile not allowed"); return true; } -bool WasmInstanceOverride(const v8::FunctionCallbackInfo<v8::Value>& info) { - DCHECK(ValidateCallbackInfo(info)); - if (IsWasmInstantiateAllowed(info.GetIsolate(), info[0], false)) return false; - ThrowRangeException(info.GetIsolate(), "Sync instantiate not allowed"); +bool WasmInstanceOverride(v8::Isolate* isolate, v8::Local<v8::Value> source) { + if (IsWasmInstantiateAllowed(isolate, source, false)) return false; + ThrowRangeException(isolate, "Sync instantiate not allowed"); return true; } @@ -548,7 +547,7 @@ RUNTIME_FUNCTION(Runtime_GetWasmExceptionValues) { IsWasmStringViewIter(*value) || IsForeign(*value)) { return CrashUnlessFuzzing(isolate); } - value = wasm::WasmToJSObject(isolate, value); + value = wasm::WasmToJSObject(isolate, value, wasm::kUnshareStrings); DCHECK(IsPrimitiveHeapObject(*value) || IsJSReceiver(*value)); } externalized_values->set(i, *value); @@ -778,7 +777,7 @@ static Tagged<Object> CreateWasmObject(Isolate* isolate, } // Create and compile the wasm module. wasm::ErrorThrower thrower(isolate, "CreateWasmObject"); - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(module_bytes); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(module_bytes); wasm::WasmEngine* engine = wasm::GetWasmEngine(); MaybeDirectHandle<WasmModuleObject> maybe_module_object = engine->SyncCompile( isolate, wasm::WasmEnabledFeatures(), wasm::CompileTimeImports(), @@ -1171,7 +1170,7 @@ RUNTIME_FUNCTION(Runtime_WasmGenerateRandomModule) { wasm::GetWasmEngine()->SyncCompile(isolate, wasm::WasmEnabledFeatures::FromFlags(), wasm::CompileTimeImports{}, &thrower, - base::OwnedCopyOf(module_bytes)); + base::UniqueCopyOf(module_bytes)); if (thrower.error()) { FATAL( "wasm::GenerateRandomWasmModule produced a module which did not " diff --git a/deps/v8/src/runtime/runtime-test.cc b/deps/v8/src/runtime/runtime-test.cc index 9deff853cde6..0ea1d1c01be1 100644 --- a/deps/v8/src/runtime/runtime-test.cc +++ b/deps/v8/src/runtime/runtime-test.cc @@ -45,7 +45,6 @@ #include "src/maglev/maglev-concurrent-dispatcher.h" #endif // V8_ENABLE_MAGLEV #include "src/objects/js-array-buffer-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" #include "src/objects/js-function-inl.h" #include "src/objects/js-regexp-inl.h" #include "src/objects/smi.h" @@ -157,6 +156,14 @@ RUNTIME_FUNCTION(Runtime_StringIsFlat) { return isolate->heap()->ToBoolean(s->IsFlat()); } +RUNTIME_FUNCTION(Runtime_StringIsOneByteRepresentation) { + HandleScope scope(isolate); + CHECK_UNLESS_FUZZING(args.length() == 1); + CHECK_UNLESS_FUZZING(IsString(args[0])); + DirectHandle<String> s = args.at<String>(0); + return isolate->heap()->ToBoolean(s->IsOneByteRepresentation()); +} + RUNTIME_FUNCTION(Runtime_ConstructConsString) { HandleScope scope(isolate); CHECK_UNLESS_FUZZING(args.length() == 2); @@ -271,6 +278,10 @@ RUNTIME_FUNCTION(Runtime_DeoptimizeNow) { if (!it.done()) function = direct_handle(it.frame()->function(), isolate); CHECK_UNLESS_FUZZING(!function.is_null()); + if (it.frame()->is_optimized()) { + Deoptimizer::DeoptimizeFunction(*function, LazyDeoptimizeReason::kTesting, + it.frame()->LookupCode()); + } if (function->HasAttachedOptimizedCode(isolate)) { Deoptimizer::DeoptimizeFunction(*function, LazyDeoptimizeReason::kTesting, function->code(isolate)); @@ -391,8 +402,7 @@ Tagged<Object> OptimizeFunctionOnNextCall(RuntimeArguments& args, if (args.length() == 2) { DirectHandle<Object> type = args.at(1); CHECK_UNLESS_FUZZING(IsString(*type)); - if (Cast<String>(type)->IsOneByteEqualTo( - base::StaticCharVector("concurrent")) && + if (Cast<String>(type)->IsOneByteEqualTo("concurrent") && isolate->concurrent_recompilation_enabled()) { concurrency_mode = ConcurrencyMode::kConcurrent; } @@ -871,6 +881,18 @@ RUNTIME_FUNCTION(Runtime_BaselineOsr) { return ReadOnlyRoots(isolate).undefined_value(); } +RUNTIME_FUNCTION(Runtime_DisableEagerInlining) { + HandleScope scope(isolate); + CHECK_UNLESS_FUZZING(args.length() == 1); + Handle<Object> function_object = args.at(0); + CHECK_UNLESS_FUZZING(IsJSFunction(*function_object)); + auto function = Cast<JSFunction>(function_object); + + ManualOptimizationTable::MarkFunctionForDisabledEagerInlining(isolate, + function); + return ReadOnlyRoots(isolate).undefined_value(); +} + RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { HandleScope scope(isolate); CHECK_UNLESS_FUZZING(args.length() == 1); @@ -878,6 +900,9 @@ RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { CHECK_UNLESS_FUZZING(IsJSFunction(*function_object)); auto function = Cast<JSFunction>(function_object); DirectHandle<SharedFunctionInfo> sfi(function->shared(), isolate); +#if V8_ENABLE_WEBASSEMBLY + CHECK_UNLESS_FUZZING(!sfi->HasWasmFunctionData(isolate)); +#endif // V8_ENABLE_WEBASSEMBLY CodeKind code_kind = sfi->abstract_code(isolate)->kind(); switch (code_kind) { case CodeKind::INTERPRETED_FUNCTION: @@ -1226,7 +1251,6 @@ int FixedArrayLenFromSize(int size) { void FillUpOneNewSpacePage(Isolate* isolate, Heap* heap, SemiSpaceNewSpace* space) { - DCHECK(!v8_flags.single_generation); heap->FreeMainThreadLinearAllocationAreas(); PauseAllocationObserversScope pause_observers(heap); while (space->GetSpaceRemainingOnCurrentPageForTesting() > 0) { @@ -1248,6 +1272,12 @@ void FillUpOneNewSpacePage(Isolate* isolate, Heap* heap, } // namespace RUNTIME_FUNCTION(Runtime_SimulateNewspaceFull) { + if (v8_flags.single_generation) { + PrintF( + "Warning: %%SimulateNewspaceFull does nothing in single-generation " + "mode\n"); + return ReadOnlyRoots(isolate).undefined_value(); + } HandleScope scope(isolate); Heap* heap = isolate->heap(); heap->FreeMainThreadLinearAllocationAreas(); @@ -2318,15 +2348,6 @@ RUNTIME_FUNCTION(Runtime_SharedGC) { return ReadOnlyRoots(isolate).undefined_value(); } -RUNTIME_FUNCTION(Runtime_AtomicsSynchronizationPrimitiveNumWaitersForTesting) { - HandleScope scope(isolate); - CHECK_UNLESS_FUZZING(args.length() == 1); - CHECK_UNLESS_FUZZING(IsJSSynchronizationPrimitive(*args.at(0))); - DirectHandle<JSSynchronizationPrimitive> primitive = - args.at<JSSynchronizationPrimitive>(0); - return primitive->NumWaitersForTesting(isolate); -} - RUNTIME_FUNCTION(Runtime_GetWeakCollectionSize) { HandleScope scope(isolate); CHECK_UNLESS_FUZZING(args.length() == 1); diff --git a/deps/v8/src/runtime/runtime-typedarray.cc b/deps/v8/src/runtime/runtime-typedarray.cc index 5b664a18d583..8dbb237a06a7 100644 --- a/deps/v8/src/runtime/runtime-typedarray.cc +++ b/deps/v8/src/runtime/runtime-typedarray.cc @@ -4,6 +4,7 @@ #include "src/base/atomicops.h" #include "src/common/message-template.h" +#include "src/common/synchronization-point-support.h" #include "src/execution/arguments-inl.h" #include "src/heap/factory.h" #include "src/objects/elements.h" @@ -73,7 +74,10 @@ RUNTIME_FUNCTION(Runtime_GrowableSharedArrayBufferByteLength) { CHECK_EQ(0, array_buffer->byte_length_unchecked()); size_t byte_length = array_buffer->GetBackingStore()->byte_length(); - return *isolate->factory()->NewNumberFromSize(byte_length); + DirectHandle<Number> result = + isolate->factory()->NewNumberFromSize(byte_length); + SYNCHRONIZATION_POINT("GrowableSharedArrayBufferByteLength"); + return *result; } namespace { diff --git a/deps/v8/src/runtime/runtime-wasm.cc b/deps/v8/src/runtime/runtime-wasm.cc index c7a5cfee4b12..eca7272f5b26 100644 --- a/deps/v8/src/runtime/runtime-wasm.cc +++ b/deps/v8/src/runtime/runtime-wasm.cc @@ -4,6 +4,8 @@ #include <optional> +#include "src/base/bits.h" +#include "src/base/unique-array.h" #include "src/builtins/builtins-inl.h" #include "src/builtins/data-view-ops.h" #include "src/common/assert-scope.h" @@ -120,7 +122,15 @@ RUNTIME_FUNCTION(Runtime_WasmWasmToJSObject) { HandleScope handle_scope(isolate); DCHECK_EQ(1, args.length()); DirectHandle<Object> value(args[0], isolate); - return *wasm::WasmToJSObject(isolate, value); + return *wasm::WasmToJSObject(isolate, value, wasm::kUnshareStrings); +} + +// Identical to Runtime_WasmWasmToJSObject, except it keeps shared strings. +RUNTIME_FUNCTION(Runtime_WasmExternConvertAny) { + HandleScope handle_scope(isolate); + DCHECK_EQ(1, args.length()); + DirectHandle<Object> value(args[0], isolate); + return *wasm::WasmToJSObject(isolate, value, wasm::kKeepSharedStrings); } // Parameters: @@ -169,10 +179,13 @@ RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) { return Smi::FromInt(ret); } -RUNTIME_FUNCTION(Runtime_TrapHandlerThrowWasmError) { - CHECK(isolate->IsOnCentralStack()); - HandleScope scope(isolate); - FrameFinder<WasmFrame> frame_finder(isolate, {StackFrame::EXIT}); +namespace { +// Determines the trap message for trap handler traps by decoding the +// instruction at the faulting bytecode position when MessageTemplate::kNone is +// passed. +MessageTemplate DetermineTrapHandlerMessage(Isolate* isolate) { + FrameFinder<WasmFrame> frame_finder( + isolate, {StackFrame::EXIT, StackFrame::WASM_DEBUG_BREAK}); WasmFrame* frame = frame_finder.frame(); int pos = frame->position(); @@ -199,15 +212,19 @@ RUNTIME_FUNCTION(Runtime_TrapHandlerThrowWasmError) { false FOREACH_ATOMIC_GC_OPCODE(CASE)); #undef CASE } - return ThrowWasmError(isolate, message); + return message; } +} // namespace RUNTIME_FUNCTION(Runtime_ThrowWasmError) { - DCHECK(isolate->IsOnCentralStack()); + CHECK(isolate->IsOnCentralStack()); HandleScope scope(isolate); DCHECK_EQ(1, args.length()); - int message_id = args.smi_value_at(0); - return ThrowWasmError(isolate, MessageTemplateFromInt(message_id)); + MessageTemplate message = MessageTemplateFromInt(args.smi_value_at(0)); + if (message == MessageTemplate::kNone) { + message = DetermineTrapHandlerMessage(isolate); + } + return ThrowWasmError(isolate, message); } RUNTIME_FUNCTION(Runtime_ThrowWasmStackOverflow) { @@ -416,9 +433,7 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateFeedbackVector) { RUNTIME_FUNCTION(Runtime_WasmLiftoffDeoptFinish) { HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - DirectHandle<WasmTrustedInstanceData> trusted_instance_data( - TrustedCast<WasmTrustedInstanceData>(args[0]), isolate); + DCHECK_EQ(0, args.length()); // Destroy the Deoptimizer object stored on the isolate. size_t deopt_frame_count = Deoptimizer::DeleteForWasm(isolate); size_t i = 0; @@ -430,8 +445,11 @@ RUNTIME_FUNCTION(Runtime_WasmLiftoffDeoptFinish) { for (StackFrameIterator it(isolate); !it.done(); it.Advance()) { StackFrame* frame = it.frame(); if (frame->is_wasm() && WasmFrame::cast(frame)->wasm_code()->is_liftoff()) { + WasmFrame* wasm_frame = WasmFrame::cast(frame); + DirectHandle<WasmTrustedInstanceData> trusted_instance_data( + wasm_frame->trusted_instance_data(), isolate); Address vector_address = - frame->fp() - WasmLiftoffFrameConstants::kFeedbackVectorOffset; + wasm_frame->fp() - WasmLiftoffFrameConstants::kFeedbackVectorOffset; Tagged<Object> feedback_slot_value(Memory<intptr_t>(vector_address)); CHECK(feedback_slot_value.IsSmi()); int declared_func_index = Cast<Smi>(feedback_slot_value).value(); @@ -1018,6 +1036,7 @@ bool ExecuteWasmDebugBreaks( DCHECK(!trusted_instance_data->break_on_entry()); if (!maybe_on_entry_breakpoints.is_null()) { isolate->debug()->OnInstrumentationBreak(); + if (isolate->debug()->IsRestartFrameScheduled()) return true; paused_on_instrumentation = true; } } @@ -1026,6 +1045,7 @@ bool ExecuteWasmDebugBreaks( debug_info->ClearStepping(isolate); StepAction step_action = isolate->debug()->last_step_action(); isolate->debug()->ClearStepping(); + if (isolate->debug()->ContinueSteppingIfSkipped(step_action)) return true; isolate->debug()->OnDebugBreak(isolate->factory()->empty_fixed_array(), step_action); return true; @@ -1068,6 +1088,10 @@ RUNTIME_FUNCTION(Runtime_WasmDebugBreak) { debug_info->ClearStepping(frame); } + if (isolate->debug()->IsRestartFrameScheduled()) { + return isolate->TerminateExecution(); + } + // Execute a stack check before leaving this function. This is to handle any // interrupts set by the debugger (e.g. termination), but also to execute Wasm // code GC to get rid of temporarily created Wasm code. @@ -1143,19 +1167,24 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateDescriptorStruct) { DirectHandle<Map> map{Cast<Map>(args[1]), isolate}; wasm::ModuleTypeIndex type_index{args.positive_smi_value_at(2)}; DirectHandle<Object> first_field{args[3], isolate}; + if (v8_flags.wasm_merged_descriptors) { + return *WasmCustomMap::AllocateUninitialized(isolate, trusted_data, + type_index, map, first_field); + } return *WasmStruct::AllocateDescriptorUninitialized( isolate, trusted_data, type_index, map, first_field); } RUNTIME_FUNCTION(Runtime_WasmArrayNewSegment) { HandleScope scope(isolate); - DCHECK_EQ(5, args.length()); + DCHECK_EQ(6, args.length()); DirectHandle<WasmTrustedInstanceData> trusted_instance_data( TrustedCast<WasmTrustedInstanceData>(args[0]), isolate); - uint32_t segment_index = args.positive_smi_value_at(1); - uint32_t offset = args.positive_smi_value_at(2); - uint32_t length = args.positive_smi_value_at(3); - DirectHandle<Map> rtt(Cast<Map>(args[4]), isolate); + bool is_numeric = args.positive_smi_value_at(1) == 0; + uint32_t segment_index = args.positive_smi_value_at(2); + uint32_t offset = args.positive_smi_value_at(3); + uint32_t length = args.positive_smi_value_at(4); + DirectHandle<Map> rtt(Cast<Map>(args[5]), isolate); Tagged<WasmTypeInfo> type_info = rtt->wasm_type_info(); wasm::CanonicalValueType element_type = type_info->element_type(); @@ -1169,8 +1198,9 @@ RUNTIME_FUNCTION(Runtime_WasmArrayNewSegment) { return ThrowWasmError(isolate, MessageTemplate::kWasmTrapArrayTooLarge); } - if (element_type.is_numeric()) { - // No chance of overflow due to the check above. + if (is_numeric) { + DCHECK(element_type.is_numeric()); + // No chance of overflow due to the check a few lines above. uint32_t length_in_bytes = length * element_size; wasm::WireBytesRef segment_source = @@ -1187,6 +1217,7 @@ RUNTIME_FUNCTION(Runtime_WasmArrayNewSegment) { return *isolate->factory()->NewWasmArrayFromMemory(length, rtt, allocation, element_type, source); } else { + DCHECK(element_type.is_ref()); DirectHandle<Object> elem_segment_raw( trusted_instance_data->element_segments()->get(segment_index), isolate); const wasm::WasmElemSegment* module_elem_segment = @@ -1219,12 +1250,13 @@ namespace { DISABLE_TSAN Tagged<Object> WasmArrayInitSegmentImpl( Isolate* isolate, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, - uint32_t segment_index, DirectHandle<WasmArray> array, uint32_t array_index, - uint32_t segment_offset, uint32_t length) { + bool is_numeric, uint32_t segment_index, DirectHandle<WasmArray> array, + uint32_t array_index, uint32_t segment_offset, uint32_t length) { wasm::CanonicalValueType element_type = array->map()->wasm_type_info()->element_type(); - if (element_type.is_numeric()) { + if (is_numeric) { + DCHECK(element_type.is_numeric()); if (!base::IsInBounds<uint32_t>(array_index, length, array->length())) { return ThrowWasmError(isolate, MessageTemplate::kWasmTrapArrayOutOfBounds); @@ -1255,6 +1287,7 @@ DISABLE_TSAN Tagged<Object> WasmArrayInitSegmentImpl( #endif return *isolate->factory()->undefined_value(); } else { + DCHECK(element_type.is_ref()); DirectHandle<Object> elem_segment_raw( trusted_instance_data->element_segments()->get(segment_index), isolate); const wasm::WasmElemSegment* module_elem_segment = @@ -1299,16 +1332,18 @@ DISABLE_TSAN Tagged<Object> WasmArrayInitSegmentImpl( RUNTIME_FUNCTION(Runtime_WasmArrayInitSegment) { HandleScope scope(isolate); - DCHECK_EQ(6, args.length()); + DCHECK_EQ(7, args.length()); DirectHandle<WasmTrustedInstanceData> trusted_instance_data( TrustedCast<WasmTrustedInstanceData>(args[0]), isolate); - uint32_t segment_index = args.positive_smi_value_at(1); - DirectHandle<WasmArray> array(Cast<WasmArray>(args[2]), isolate); - uint32_t array_index = args.positive_smi_value_at(3); - uint32_t segment_offset = args.positive_smi_value_at(4); - uint32_t length = args.positive_smi_value_at(5); - return WasmArrayInitSegmentImpl(isolate, trusted_instance_data, segment_index, - array, array_index, segment_offset, length); + bool is_numeric = args.positive_smi_value_at(1) == 0; + uint32_t segment_index = args.positive_smi_value_at(2); + DirectHandle<WasmArray> array(Cast<WasmArray>(args[3]), isolate); + uint32_t array_index = args.positive_smi_value_at(4); + uint32_t segment_offset = args.positive_smi_value_at(5); + uint32_t length = args.positive_smi_value_at(6); + return WasmArrayInitSegmentImpl(isolate, trusted_instance_data, is_numeric, + segment_index, array, array_index, + segment_offset, length); } // Allocate a new suspender, and prepare for stack switching by updating the @@ -1330,15 +1365,6 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateSuspender) { if (v8_flags.wasm_wasmfx) { // For now JSPI does not use the WasmStackObject, and it is only set here // because it is expected by WasmFX. - // TODO(thibaudm): We could consider using this object for JSPI too as an - // indirection between the WasmSuspenderObjects and the StackMemory. This - // would have roughly the same benefits as for WasmFX: - // - We would only need to allocate and manage a single EPT entry per - // StackMemory, - // - It would be easier to track ownership of the StackMemory and ensure - // that there is no UAF. In particular the StackMemory could track its - // (unique) EPT entry via {EPT::ManagedResource} and zap it when the - // resource is freed. target_stack->set_stack_obj( *isolate->factory()->NewWasmStackObject(target_stack.get())); } @@ -1346,15 +1372,12 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateSuspender) { // Update the suspender state. Tagged<WasmSuspenderObject> active_suspender = isolate->isolate_data()->active_suspender(); - if (v8_flags.wasm_wasmfx) { - // The active suspender is about to become inactive. Record the currently - // active stack (which may have changed due to WasmFX) for when we - // return to this suspender. - active_suspender->set_stack(isolate, - isolate->isolate_data()->active_stack()); - } + // The active suspender is about to become inactive. Record the currently + // active stack for when we return to this suspender. + DCHECK_NULL(active_suspender->stack()); + active_suspender->set_stack(isolate->isolate_data()->active_stack()); suspender->set_parent(active_suspender); - suspender->set_stack(isolate, target_stack.get()); + suspender->set_stack(target_stack.get()); // The active stack is updated in {Isolate::SwitchStacks}. isolate->isolate_data()->set_active_suspender(*suspender); @@ -1497,8 +1520,6 @@ class PrototypesSetup : public wasm::Decoder { return ReadOnlyRoots(isolate()).exception(); } - bool fast_path = CheckFastPathEligibility(prototype); - uint32_t has_constructor = consume_u32v("constructor"); if (!ok()) break; @@ -1566,13 +1587,40 @@ class PrototypesSetup : public wasm::Decoder { "too many methods in configureAll"))); return ReadOnlyRoots(isolate()).exception(); } + // Important: installing {constructor} on {constructors} can invoke + // user code. Only determine fast path eligibility after that. + bool fast_path = false; DirectHandle<NameDictionary> dictionary; if (!prototype_is_null) { if (IsJSObject(*prototype)) { DirectHandle<JSObject> proto = Cast<JSObject>(prototype); + if (!proto->map()->is_prototype_map()) { + // Important for correctness: switch to a non-shared map. + // Important for performance: switch to dictionary mode. + JSObject::OptimizeAsPrototype(proto); + } else { + // Prepare the fast path by invalidating any ICs that might already + // rely on this prototype. + JSObject::InvalidatePrototypeChains(proto->map()); + } ToDictionaryMode(proto, num_methods); - if (fast_path) { + DisallowGarbageCollection using_plain_tagged_values; + Tagged<Map> map = proto->map(); + if (map->instance_type() == JS_OBJECT_TYPE) { + if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { + // Support for swiss name dictionaries isn't implemented here yet. + UNIMPLEMENTED(); + } + // JS_OBJECT_TYPE implies no access checks or interceptors. + DCHECK(!map->is_access_check_needed()); + DCHECK(!map->has_indexed_interceptor()); + DCHECK(!map->has_named_interceptor()); + DCHECK(!IsJSGlobalObject(*proto)); + DCHECK(map->is_dictionary_map()); dictionary = handle(proto->property_dictionary(), isolate_); + if (map->is_extensible() && dictionary->NumberOfElements() == 0) { + fast_path = true; + } } } } else if (num_methods > 0) { @@ -1601,8 +1649,7 @@ class PrototypesSetup : public wasm::Decoder { context->SetNoCell(wasm::kMethodWrapperContextSlot, *function); function = Factory::JSFunctionBuilder{isolate_, method_wrapper(), context} - .set_map( - isolate_->strict_function_with_readonly_prototype_map()) + .set_map(isolate_->function_with_readonly_prototype_map()) .Build(); // For nicer stack traces, we could call // JSFunction::SetName(..., function, name, ...); @@ -1610,7 +1657,7 @@ class PrototypesSetup : public wasm::Decoder { // to hide the wrappers on stack traces instead. // Note to our future selves: if we wanted names, the most performant // way would likely be to add a pre-created - // strict_function_with_NAME_AND_readonly_prototype_map + // function_with_NAME_AND_readonly_prototype_map // and use that for these wrappers, to avoid needing individual SFIs // for storing their names. @@ -1709,11 +1756,10 @@ class PrototypesSetup : public wasm::Decoder { if (HasMorePrototypes()) error("unconsumed prototypes"); if (more()) error("unconsumed data"); if (!ok()) { - DirectHandle<String> message = - isolate() - ->factory() - ->NewStringFromUtf8(base::VectorOf(error().message())) - .ToHandleChecked(); + DirectHandle<String> message = isolate() + ->factory() + ->NewStringFromUtf8(error().message()) + .ToHandleChecked(); DirectHandle<JSObject> error = isolate()->factory()->NewError( isolate()->wasm_runtime_error_function(), message); return isolate()->Throw(*error); @@ -1773,17 +1819,7 @@ class PrototypesSetup : public wasm::Decoder { ThrowWasmError(isolate_, MessageTemplate::kWasmTrapIllegalCast); return {}; } - DirectHandle<JSObject> proto = Cast<JSObject>(heap_proto); - if (!proto->map()->is_prototype_map()) { - // Important for correctness: switch to a non-shared map. - // Important for performance: switch to dictionary mode. - JSObject::OptimizeAsPrototype(proto); - } else { - // Prepare the fast path by invalidating any ICs that might already - // rely on this prototype. - JSObject::InvalidatePrototypeChains(proto->map()); - } - return proto; + return Cast<JSObject>(heap_proto); } if (IsJSReceiver(*heap_proto)) { return Cast<JSReceiver>(heap_proto); @@ -1857,7 +1893,7 @@ class PrototypesSetup : public wasm::Decoder { sfi->set_language_mode(LanguageMode::kStrict); DirectHandle<JSFunction> constructor = Factory::JSFunctionBuilder{isolate_, sfi, context} - .set_map(isolate_->strict_function_with_readonly_prototype_map()) + .set_map(isolate_->function_with_readonly_prototype_map()) .Build(); constructor->set_prototype_or_initial_map(*prototype, kReleaseStore); @@ -1887,33 +1923,6 @@ class PrototypesSetup : public wasm::Decoder { return constructor; } - // Fast path, skipping the LookupIterator. - bool CheckFastPathEligibility(DirectHandle<JSReceiver> prototype) { - if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) { - // Support for swiss name dictionaries isn't implemented here yet. - UNIMPLEMENTED(); - } - if (prototype.is_null()) return false; - Tagged<Map> map = prototype->map(); - if (map->instance_type() != JS_OBJECT_TYPE) return false; - if (!map->is_extensible()) return false; - // JS_OBJECT_TYPE implies no access checks or interceptors. - DCHECK(!map->is_access_check_needed()); - DCHECK(!map->has_indexed_interceptor()); - DCHECK(!map->has_named_interceptor()); - DCHECK(!IsJSGlobalObject(*prototype)); - if (map->is_dictionary_map()) { - if (Cast<JSObject>(prototype) - ->property_dictionary() - ->NumberOfElements() != 0) { - return false; - } - } else { - if (map->NumberOfOwnDescriptors() != 0) return false; - } - return true; - } - bool MayBeArrayIndex(base::Vector<const uint8_t> name) { // The fast path can't handle elements (i.e. names that are string // representations of array indices). To save time, we approximate @@ -2131,6 +2140,14 @@ MaybeDirectHandle<FixedArray> GetElementSegment( isolate}; } +// Returns the canonical rtt map at `index`, or an arbitrary non-map value if +// the weak slot is cleared or was never set. +Tagged<Object> CanonicalRttMap(Isolate* isolate, uint32_t index) { + // Slots hold a weak Map, undefined, or a cleared reference; never a Smi. + return MakeStrong(Cast<MaybeWeak<HeapObject>>( + isolate->heap()->wasm_canonical_rtts()->get(index))); +} + } // namespace RUNTIME_FUNCTION(Runtime_WasmConfigureAllPrototypes) { @@ -2146,15 +2163,12 @@ RUNTIME_FUNCTION(Runtime_WasmConfigureAllPrototypes) { DirectHandle<WasmArray> data(Cast<WasmArray>(args[2]), isolate); DirectHandle<Object> constructors(args[3], isolate); { - Tagged<Object> expected_prototypes_map = - MakeStrong(isolate->heap()->wasm_canonical_rtts()->get( - wasm::TypeCanonicalizer::kPredefinedArrayExternRefIndex.index)); - Tagged<Object> expected_functions_map = - MakeStrong(isolate->heap()->wasm_canonical_rtts()->get( - wasm::TypeCanonicalizer::kPredefinedArrayFuncRefIndex.index)); - Tagged<Object> expected_data_map = - MakeStrong(isolate->heap()->wasm_canonical_rtts()->get( - wasm::TypeCanonicalizer::kPredefinedArrayI8Index.index)); + Tagged<Object> expected_prototypes_map = CanonicalRttMap( + isolate, wasm::TypeCanonicalizer::kPredefinedArrayExternRefIndex.index); + Tagged<Object> expected_functions_map = CanonicalRttMap( + isolate, wasm::TypeCanonicalizer::kPredefinedArrayFuncRefIndex.index); + Tagged<Object> expected_data_map = CanonicalRttMap( + isolate, wasm::TypeCanonicalizer::kPredefinedArrayI8Index.index); if (prototypes->map() != expected_prototypes_map || functions->map() != expected_functions_map || data->map() != expected_data_map) { @@ -2165,14 +2179,14 @@ RUNTIME_FUNCTION(Runtime_WasmConfigureAllPrototypes) { // Arrays on the heap can move on GC, so we create an immovable copy of // the data we'll need to decode. uint32_t length = data->length(); - base::OwnedVector<uint8_t> immovable_data; + base::UniqueArray<uint8_t> immovable_data; if (length) { - immovable_data = base::OwnedCopyOf( + immovable_data = base::UniqueCopyOf( reinterpret_cast<const uint8_t*>(data->ElementAddress(0)), length); } - PrototypesSetup_Arrays decoder(isolate, immovable_data.as_vector(), - prototypes, functions); + PrototypesSetup_Arrays decoder(isolate, immovable_data.as_span(), prototypes, + functions); return decoder.SetupPrototypes(constructors); } @@ -2282,8 +2296,7 @@ RUNTIME_FUNCTION(Runtime_WasmCastToSpecialPrimitiveArray) { : wasm::TypeCanonicalizer::kPredefinedArrayI8Index) : (shared ? wasm::TypeCanonicalizer::kPredefinedArrayI16SharedIndex : wasm::TypeCanonicalizer::kPredefinedArrayI16Index); - Tagged<Object> expected_map = - MakeStrong(isolate->heap()->wasm_canonical_rtts()->get(expected.index)); + Tagged<Object> expected_map = CanonicalRttMap(isolate, expected.index); // If the expected_map has been cleared or never even created, then there's // no chance of a match anyway. if (obj->map() != expected_map) { @@ -2760,21 +2773,16 @@ RUNTIME_FUNCTION(Runtime_WasmStringEncodeWtf16) { return ThrowWasmError(isolate, MessageTemplate::kWasmTrapUnalignedAccess); } -#if defined(V8_TARGET_LITTLE_ENDIAN) uint16_t* dst = reinterpret_cast<uint16_t*>( trusted_instance_data->memory_base(memory) + offset); String::WriteToFlat(string, dst, start, length); +#if defined(V8_TARGET_BIG_ENDIAN) + for (uint32_t i = 0; i < length; i++) { + dst[i] = base::bits::ByteReverse16(dst[i]); + } +#endif return Smi::zero(); // Unused. -#elif defined(V8_TARGET_BIG_ENDIAN) - // TODO(12868): The host is big-endian but we need to write the string - // contents as little-endian. - USE(string); - USE(start); - UNIMPLEMENTED(); -#else -#error Unknown endianness -#endif } RUNTIME_FUNCTION(Runtime_WasmStringAsWtf8) { @@ -2990,9 +2998,16 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) { alignment = RoundUp(alignment, 2 * kSystemPointerSize); #endif stack->jmpbuf()->fp = kNullAddress; - stack->jmpbuf()->sp = RoundDown(stack->base() - arg_buffer_size, alignment); - Address arg_buffer = stack->jmpbuf()->sp; + Address arg_buffer = RoundDown(stack->base() - arg_buffer_size, alignment); stack->set_arg_buffer(arg_buffer); + stack->jmpbuf()->sp = arg_buffer; +#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 + // Return address slot. The wrapper returns by switching to the parent + // jump buffer and does not actually use this slot, but it is read by the + // profiler. + stack->jmpbuf()->sp -= kSystemPointerSize; + base::Memory<Address>(stack->jmpbuf()->sp) = kNullAddress; +#endif stack->jmpbuf()->state = wasm::JumpBuffer::Suspended; stack->jmpbuf()->stack_limit = stack->jslimit(); stack->jmpbuf()->is_on_central_stack = false; @@ -3029,12 +3044,18 @@ RUNTIME_FUNCTION(Runtime_WasmTypeAssertionFailed) { // Since TSAN does not know about release fences, we must manually define the // synchronization between object initialization and reads from that object. We // add a TSAN_RELEASE after the object-initialization release fence, and a -// TSAN_ACQUIRE at the beginning of each read-only builtin (future work: also, -// before every read of a shared object in generated code). Explainer: +// TSAN_ACQUIRE +// - at the beginning of each read-only builtin, +// - before every read of a shared object in generated code, and +// - whenever an object crosses the Wasm->JS boundary. +// Explainer: // https://docs.google.com/document/d/17RLOdAFJ2HFA4hE83wSsTYdRwHV4ZBiX_jtOUp0qatw/edit?usp=sharing RUNTIME_FUNCTION(Runtime_TsanAcquireForInitializationFence) { DCHECK_EQ(1, args.length()); - TSAN_ACQUIRE(Cast<HeapObject>(args[0]).address()); + SealHandleScope shs(isolate); + DisallowGarbageCollection no_gc; + Tagged<HeapObject> arg = Cast<HeapObject>(args[0]); + if (HeapLayout::InWritableSharedSpace(arg)) TSAN_ACQUIRE(arg.address()); return ReadOnlyRoots(isolate).undefined_value(); } #endif // V8_IS_TSAN diff --git a/deps/v8/src/runtime/runtime.cc b/deps/v8/src/runtime/runtime.cc index e01124b9833a..970abd0708c2 100644 --- a/deps/v8/src/runtime/runtime.cc +++ b/deps/v8/src/runtime/runtime.cc @@ -219,6 +219,8 @@ bool Runtime::IsEnabledForFuzzing(FunctionId id) { case Runtime::kArrayBufferDetach: case Runtime::kDeoptimizeFunction: case Runtime::kDeoptimizeNow: + case Runtime::kInlineDeoptimizeNow: + case Runtime::kDisableEagerInlining: case Runtime::kDisableOptimizationFinalization: case Runtime::kEnableCodeLoggingForTesting: case Runtime::kFinalizeOptimization: @@ -329,9 +331,11 @@ bool Runtime::IsEnabledForFuzzing(FunctionId id) { // Functions used in testing and outside case Runtime::kArrayBufferDetach: #define F(name, nargs, ressize, ...) case k##name: -#define I(name, nargs, ressize, ...) case kInline##name: - FOR_EACH_INTRINSIC_TEST(F, I) - IF_WASM(FOR_EACH_INTRINSIC_WASM_TEST, F, I) +#define I(name, nargs, ressize, ...) \ + case k##name: \ + case kInline##name: + FOR_EACH_INTRINSIC_TEST(F, I) + IF_WASM(FOR_EACH_INTRINSIC_WASM_TEST, F, I) #undef I #undef F return true; diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h index 9c9dfa45a44e..1b4e76d9f239 100644 --- a/deps/v8/src/runtime/runtime.h +++ b/deps/v8/src/runtime/runtime.h @@ -74,8 +74,7 @@ constexpr bool CanTriggerGC(T... properties) { F(AtomicsLoadSharedStructOrArray, 2, 1) \ F(AtomicsStoreSharedStructOrArray, 3, 1) \ F(AtomicsExchangeSharedStructOrArray, 3, 1) \ - F(AtomicsCompareExchangeSharedStructOrArray, 4, 1) \ - F(AtomicsSynchronizationPrimitiveNumWaitersForTesting, 1, 1) + F(AtomicsCompareExchangeSharedStructOrArray, 4, 1) #define FOR_EACH_INTRINSIC_BIGINT(F, I) \ F(BigIntCompareToNumber, 3, 1) \ @@ -305,7 +304,7 @@ constexpr bool CanTriggerGC(T... properties) { F(NotifyContextCellStateWillChange, 1, 1, \ RuntimeCallProperty::kCannotTriggerGC) \ F(NewError, 2, 1) \ - F(NewReferenceError, 2, 1) \ + F(NewReferenceError, 1, 1) \ F(NewTypeError, -1 /* [1, 4] */, 1) \ F(OrdinaryHasInstance, 2, 1) \ F(PropagateException, 0, 1) \ @@ -374,6 +373,7 @@ constexpr bool CanTriggerGC(T... properties) { F(HandleExceptionsInDisposeDisposableStack, 3, 1) \ F(HasFastPackedElements, 1, 1) \ F(HasInPrototypeChain, 2, 1) \ + F(HasPrivateMember, 2, 1) \ F(HasProperty, 2, 1) \ F(InitializeDisposableStack, 0, 1) \ F(InternalSetPrototype, 2, 1) \ @@ -453,7 +453,7 @@ constexpr bool CanTriggerGC(T... properties) { F(ConstructInternalAggregateErrorHelper, -1 /* <= 5*/, 1) #define FOR_EACH_INTRINSIC_PROXY(F, I) \ - F(CheckProxyGetSetTrapResult, 2, 1) \ + F(CheckProxyGetSetTrapResult, 4, 1) \ F(CheckProxyHasTrapResult, 2, 1) \ F(CheckProxyDeleteTrapResult, 2, 1) \ F(GetPropertyWithReceiver, 3, 1) \ @@ -493,7 +493,6 @@ constexpr bool CanTriggerGC(T... properties) { F(LoadLookupSlotForCall_Baseline, 2, 1) \ \ F(NewClosure, 2, 1) \ - F(NewClosure_Tenured, 2, 1) \ F(NewFunctionContext, 1, 1) \ F(NewRestParameter, 1, 1) \ F(NewSloppyArguments, 1, 1) \ @@ -583,6 +582,7 @@ constexpr bool CanTriggerGC(T... properties) { F(DebugTrace, 0, 1) \ F(DebugTraceMinimal, 0, 1) \ F(DeoptimizeFunction, 1, 1) \ + F(DisableEagerInlining, 1, 1) \ F(DisableOptimizationFinalization, 0, 1) \ F(DisallowCodegenFromStrings, 1, 1) \ F(DisassembleFunction, 1, 1) \ @@ -686,6 +686,7 @@ constexpr bool CanTriggerGC(T... properties) { F(ShareObject, 1, 1) \ F(SimulateNewspaceFull, 0, 1) \ F(StringIsFlat, 1, 1) \ + F(StringIsOneByteRepresentation, 1, 1) \ F(StringIteratorProtector, 0, 1) \ F(StringWrapperToPrimitiveProtector, 0, 1) \ F(SystemBreak, 0, 1) \ @@ -724,7 +725,6 @@ constexpr bool CanTriggerGC(T... properties) { F(ThrowWasmJSPISuspendError, 0, 1) \ F(ThrowWasmFXSuspendError, 0, 1) \ F(ThrowWasmError, 1, 1) \ - F(TrapHandlerThrowWasmError, 0, 1) \ F(ThrowWasmStackOverflow, 0, 1) \ F(WasmI32AtomicWait, 4, 1) \ F(WasmI64AtomicWait, 5, 1) \ @@ -752,9 +752,10 @@ constexpr bool CanTriggerGC(T... properties) { F(WasmTableFill, 5, 1) \ F(WasmJSToWasmObject, 2, 1) \ F(WasmWasmToJSObject, 1, 1) \ + F(WasmExternConvertAny, 1, 1) \ F(WasmCompileLazy, 2, 1) \ F(WasmAllocateFeedbackVector, 3, 1) \ - F(WasmLiftoffDeoptFinish, 1, 1) \ + F(WasmLiftoffDeoptFinish, 0, 1) \ F(TierUpJSToWasmWrapper, 1, 1) \ F(IsWasmExternalFunction, 1, 1) \ F(TierUpWasmToJSWrapper, 1, 1) \ @@ -762,8 +763,8 @@ constexpr bool CanTriggerGC(T... properties) { F(WasmDebugBreak, 0, 1) \ F(WasmAllocateDescriptorStruct, 4, 1) \ F(WasmArrayCopy, 5, 1) \ - F(WasmArrayNewSegment, 5, 1) \ - F(WasmArrayInitSegment, 6, 1) \ + F(WasmArrayNewSegment, 6, 1) \ + F(WasmArrayInitSegment, 7, 1) \ F(WasmAllocateSuspender, 0, 1) \ F(WasmSuspended, 2, 1) \ F(WasmAllocateContinuation, 3, 1) \ @@ -1053,6 +1054,15 @@ class Runtime : public AllStatic { DirectHandle<Object> key, DirectHandle<JSAny> receiver = {}, bool* is_found = nullptr); + // Look up for a private member with a name matching "desc" and return + // whether it exists on "receiver". "desc" should be a #-prefixed string, in + // the case of private fields, it should match the description of the private + // name symbol. Throw an error if there are more than one matching private + // member (which would be ambiguous). + V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeDirectHandle<Object> + HasPrivateMember(Isolate* isolate, DirectHandle<JSReceiver> receiver, + DirectHandle<String> desc); + // Look up for a private member with a name matching "desc" and return its // value. "desc" should be a #-prefixed string, in the case of private fields, // it should match the description of the private name symbol. Throw an error diff --git a/deps/v8/src/sandbox/bytecode-verifier.cc b/deps/v8/src/sandbox/bytecode-verifier.cc index 059ef6707e36..d23f59c843dd 100644 --- a/deps/v8/src/sandbox/bytecode-verifier.cc +++ b/deps/v8/src/sandbox/bytecode-verifier.cc @@ -172,7 +172,13 @@ void BytecodeVerifier::VerifyFull(IsolateForSandbox isolate, switch (operand_type) { case interpreter::OperandType::kReg: case interpreter::OperandType::kRegOut: - case interpreter::OperandType::kRegInOut: + case interpreter::OperandType::kRegInOut: { + interpreter::Register reg = iterator.GetRegisterOperand(i); + bool is_output = + interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type); + VerifyRegister(reg, is_output); + break; + } case interpreter::OperandType::kRegPair: case interpreter::OperandType::kRegOutPair: case interpreter::OperandType::kRegOutTriple: @@ -181,17 +187,22 @@ void BytecodeVerifier::VerifyFull(IsolateForSandbox isolate, bool is_output = interpreter::Bytecodes::IsRegisterOutputOperandType(operand_type); uint32_t count = iterator.GetRegisterOperandRange(i); - if (count > 0) { - interpreter::Register start = iterator.GetRegisterOperand(i); + interpreter::Register start = iterator.GetRegisterOperand(i); + if (count == 0) { + Check(start == interpreter::Register(0), + "Invalid empty register list"); + } else { VerifyRegister(start, is_output); + if (is_output || count > 1) { + Check(!start.is_parameter(), + "Register list cannot use parameter registers"); + } if (count > 1) { base::internal::CheckedNumeric<int> end_index = start.index(); end_index += count - 1; Check(end_index.IsValid(), "Register range end overflows"); interpreter::Register end(end_index.ValueOrDie()); VerifyRegister(end, is_output); - Check(start.is_parameter() == end.is_parameter(), - "Register range crosses parameter/local boundary"); } } break; @@ -236,6 +247,14 @@ void BytecodeVerifier::VerifyFull(IsolateForSandbox isolate, interpreter::Register reg = iterator.GetStarTargetRegister(); VerifyRegister(reg, true); } + + if (current_bytecode == interpreter::Bytecode::kSuspendGenerator || + current_bytecode == interpreter::Bytecode::kResumeGenerator || + current_bytecode == interpreter::Bytecode::kSwitchOnGeneratorState) { + interpreter::Register generator = iterator.GetRegisterOperand(0); + Check(!generator.is_parameter(), + "Generator register cannot be a parameter"); + } } Check(previous_bytecode_end == bytecode->length(), diff --git a/deps/v8/src/sandbox/bytecode-verifier.h b/deps/v8/src/sandbox/bytecode-verifier.h index 4e947474ed54..66e1709dfe45 100644 --- a/deps/v8/src/sandbox/bytecode-verifier.h +++ b/deps/v8/src/sandbox/bytecode-verifier.h @@ -13,6 +13,17 @@ namespace v8::internal { // Bytecode verifier to ensure bytecode is safe to execute. // +// The verifier's scope is sandbox safety only: it guarantees that executing +// the bytecode cannot escape the sandbox. Light verification covers +// control-flow integrity, full verification additionally covers that +// registers and parameters don't refer to memory outside of the sandbox. +// Bytecode that is semantically incorrect but still cannot escape the +// sandbox (for example a register that the bytecode generator would never +// emit at that place) is intentionally accepted if it can never be generated +// in production, i.e. if it can only be constructed by installing arbitrary +// bytecode. Semantically incorrect bytecode that our own code can generate +// is a bug and should be fixed, even if it is sandbox-safe. +// // See the design document for more details: // https://docs.google.com/document/d/1UUooVKUvf1zDobG34VDVuLsjoKZd-CeSuhvBcLysc7U/edit?usp=sharing class V8_EXPORT_PRIVATE BytecodeVerifier { diff --git a/deps/v8/src/sandbox/code-entrypoint-tag.h b/deps/v8/src/sandbox/code-entrypoint-tag.h index 7f4d16730525..5c604502eaca 100644 --- a/deps/v8/src/sandbox/code-entrypoint-tag.h +++ b/deps/v8/src/sandbox/code-entrypoint-tag.h @@ -32,7 +32,13 @@ namespace internal { // match, the resulting pointer will be invalid and cause a safe crash. // TODO(saelo): on Arm64, we could probably use PAC instead of XORing the tag // into the pointer. This may be more efficient. +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 +constexpr int kCodeEntrypointTagShift = 57; +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) constexpr int kCodeEntrypointTagShift = 48; +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) +constexpr uint64_t kCodeEntrypointTagMask = uint64_t{0x7f} + << kCodeEntrypointTagShift; enum CodeEntrypointTag : uint64_t { kJSEntrypointTag = 0, kWasmEntrypointTag = uint64_t{1} << kCodeEntrypointTagShift, @@ -53,15 +59,20 @@ enum CodeEntrypointTag : uint64_t { // TODO(saelo): create more of these tags. // Tag to use for Code objects with stub linkage created by unittests. - kCodeEntrypointTagForTesting = uint64_t{0xfc} << kCodeEntrypointTagShift, + kCodeEntrypointTagForTesting = uint64_t{0x7c} << kCodeEntrypointTagShift, // Tag to use for Code objects corresponding to currently disabled builtins. - kDisabledBuiltinEntrypointTag = uint64_t{0xfd} << kCodeEntrypointTagShift, + kDisabledBuiltinEntrypointTag = uint64_t{0x7d} << kCodeEntrypointTagShift, // Sentinel tag to use for code that should never be called. - kInvalidEntrypointTag = uint64_t{0xff} << kCodeEntrypointTagShift, + kInvalidEntrypointTag = uint64_t{0x7f} << kCodeEntrypointTagShift, }; +#ifdef V8_ENABLE_SANDBOX +// All tags must fit into the 7 tag bits of an x64 entry on LA57. +static_assert(kCodeEntrypointTagShift + 7 <= kBitsPerSystemPointer); +#endif // V8_ENABLE_SANDBOX + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/sandbox/cppheap-pointer-table-inl.h b/deps/v8/src/sandbox/cppheap-pointer-table-inl.h index d1a445d3d843..b8b6947ae1c3 100644 --- a/deps/v8/src/sandbox/cppheap-pointer-table-inl.h +++ b/deps/v8/src/sandbox/cppheap-pointer-table-inl.h @@ -28,12 +28,12 @@ void CppHeapPointerTableEntry::MakePointerEntry(Address value, if (V8_UNLIKELY(mark_as_alive)) { new_payload.SetMarkBit(); } - payload_.store(new_payload, std::memory_order_relaxed); + payload_.store(new_payload, std::memory_order_release); } Address CppHeapPointerTableEntry::GetPointer( CppHeapPointerTagRange tag_range) const { - auto payload = payload_.load(std::memory_order_relaxed); + auto payload = payload_.load(std::memory_order_acquire); DCHECK(payload.ContainsPointer()); return payload.Untag(tag_range); } @@ -52,6 +52,7 @@ void CppHeapPointerTableEntry::SetPointer(Address value, new_payload.SetMarkBit(); } if (payload_.compare_exchange_weak(old_payload, new_payload, + std::memory_order_release, std::memory_order_relaxed)) { break; } diff --git a/deps/v8/src/sandbox/cppheap-pointer-table.h b/deps/v8/src/sandbox/cppheap-pointer-table.h index fda7cea52bc5..955603d924ec 100644 --- a/deps/v8/src/sandbox/cppheap-pointer-table.h +++ b/deps/v8/src/sandbox/cppheap-pointer-table.h @@ -110,6 +110,10 @@ struct CppHeapPointerTableEntry { }; using Payload = TaggedPayload<CppHeapPointerTablePayloadTaggingScheme>; + public: + static constexpr uint64_t kTagAndMarkBitMask = Payload::kTagAndMarkBitMask; + + private: inline Payload GetRawPayload() const { return payload_.load(std::memory_order_relaxed); } diff --git a/deps/v8/src/sandbox/cppheap-pointer-tag.h b/deps/v8/src/sandbox/cppheap-pointer-tag.h index e24e1b6c6b6a..a4e5279b11df 100644 --- a/deps/v8/src/sandbox/cppheap-pointer-tag.h +++ b/deps/v8/src/sandbox/cppheap-pointer-tag.h @@ -12,7 +12,6 @@ namespace v8::internal { // Tags for V8-internal CppHeap objects that inherit from v8::Object::Wrappable. #define V8_WRAPPABLE_CPP_HEAP_POINTER_TAGS_LIST(V) \ V(kTagForTesting) \ - V(kInspectorV8ConsoleTag) \ V(kInspectorTaskInfoTag) \ V(kWasmMemoryMapDescriptorTag) @@ -21,7 +20,10 @@ namespace v8::internal { #define V8_NON_WRAPPABLE_CPP_HEAP_POINTER_TAGS_LIST(V) \ V(kMicrotaskQueueTag) \ V(kCppGCManagedTag) \ - V(kEmbedderDataSlotTag) + V(kEmbedderDataSlotTag) \ + V(kInspectorV8ConsoleTag) \ + V(kInspectorCommandLineAPIDataTag) \ + V(kInspectorCommandLineAPIScopeDataTag) enum class WrappableCppHeapPointerTag : uint16_t { kFirst = diff --git a/deps/v8/src/sandbox/external-entity-table-inl.h b/deps/v8/src/sandbox/external-entity-table-inl.h index c6c047597219..c7392e83949a 100644 --- a/deps/v8/src/sandbox/external-entity-table-inl.h +++ b/deps/v8/src/sandbox/external-entity-table-inl.h @@ -13,6 +13,7 @@ #include "src/base/iterator.h" #include "src/common/assert-scope.h" #include "src/sandbox/external-pointer-table.h" +#include "src/sandbox/sandbox.h" #include "src/sandbox/segmented-table-inl.h" #include "src/utils/allocation.h" @@ -47,6 +48,7 @@ bool ExternalEntityTable<Entry, size>::Space::Contains(uint32_t index) { template <typename Entry, size_t size> void ExternalEntityTable<Entry, size>::Initialize() { + CHECK(IsTaggingMaskCompatible(kTagAndMarkBitMask)); Base::Initialize(size, kSegmentSize * kNumReadOnlySegments, Entry::IsWriteProtected); } diff --git a/deps/v8/src/sandbox/external-entity-table.h b/deps/v8/src/sandbox/external-entity-table.h index 77eb0b2af43d..054b9e090b8f 100644 --- a/deps/v8/src/sandbox/external-entity-table.h +++ b/deps/v8/src/sandbox/external-entity-table.h @@ -234,6 +234,8 @@ class V8_EXPORT_PRIVATE ExternalEntityTable // on a table (not) supporting compaction. static constexpr bool kSupportsCompaction = false; + static constexpr uint64_t kTagAndMarkBitMask = Entry::kTagAndMarkBitMask; + // Initializes the table by reserving the backing memory, allocating an // initial segment, and populating the freelist. void Initialize(); diff --git a/deps/v8/src/sandbox/external-pointer-table-inl.h b/deps/v8/src/sandbox/external-pointer-table-inl.h index a6ba845a9a09..26b12a2cad67 100644 --- a/deps/v8/src/sandbox/external-pointer-table-inl.h +++ b/deps/v8/src/sandbox/external-pointer-table-inl.h @@ -29,37 +29,17 @@ void ExternalPointerTableEntry::MakeExternalPointerEntry(Address value, if (V8_UNLIKELY(mark_as_alive)) { new_payload.SetMarkBit(); } - payload_.store(new_payload, std::memory_order_relaxed); + payload_.store(new_payload, std::memory_order_release); MaybeUpdateRawPointerForLSan(value); } Address ExternalPointerTableEntry::GetExternalPointer( ExternalPointerTagRange tag_range) const { - auto payload = payload_.load(std::memory_order_relaxed); + auto payload = payload_.load(std::memory_order_acquire); DCHECK(payload.ContainsPointer()); return payload.Untag(tag_range); } -void ExternalPointerTableEntry::SetExternalPointer(Address value, - ExternalPointerTag tag) { - // The 2nd most significant byte must be empty as we store the tag in int. - DCHECK_EQ(0, value & kExternalPointerTagAndMarkbitMask); - DCHECK(payload_.load(std::memory_order_relaxed).ContainsPointer()); - - auto old_payload = payload_.load(std::memory_order_relaxed); - while (true) { - Payload new_payload(value, tag); - if (old_payload.HasMarkBitSet()) { - new_payload.SetMarkBit(); - } - if (payload_.compare_exchange_weak(old_payload, new_payload, - std::memory_order_relaxed)) { - break; - } - } - MaybeUpdateRawPointerForLSan(value); -} - bool ExternalPointerTableEntry::HasExternalPointer( ExternalPointerTagRange tag_range) const { auto payload = payload_.load(std::memory_order_relaxed); @@ -72,6 +52,7 @@ Address ExternalPointerTableEntry::ExchangeExternalPointer( Address value, ExternalPointerTag tag) { // The 2nd most significant byte must be empty as we store the tag in int. DCHECK_EQ(0, value & kExternalPointerTagAndMarkbitMask); + DCHECK(payload_.load(std::memory_order_relaxed).ContainsPointer()); auto old_payload = payload_.load(std::memory_order_relaxed); while (true) { @@ -81,6 +62,7 @@ Address ExternalPointerTableEntry::ExchangeExternalPointer( new_payload.SetMarkBit(); } if (payload_.compare_exchange_weak(old_payload, new_payload, + std::memory_order_release, std::memory_order_relaxed)) { MaybeUpdateRawPointerForLSan(value); return old_payload.Untag(tag); @@ -88,6 +70,11 @@ Address ExternalPointerTableEntry::ExchangeExternalPointer( } } +void ExternalPointerTableEntry::SetExternalPointer(Address value, + ExternalPointerTag tag) { + ExchangeExternalPointer(value, tag); +} + ExternalPointerTag ExternalPointerTableEntry::GetExternalPointerTag() const { auto payload = payload_.load(std::memory_order_relaxed); DCHECK(payload.ContainsPointer()); @@ -278,6 +265,14 @@ void ExternalPointerTable::Mark(Space* space, ExternalPointerHandle handle, if (handle == kNullExternalPointerHandle) return; uint32_t index = HandleToIndex(handle); + + // In legitimate execution, host objects only reference handles allocated in + // their own EPT space (e.g. young host -> young space, old host -> old + // space). + // + // Space membership is not security-critical for the sandbox as it merely + // creates corruptions that can already appear by swapping around untrusted + // handles. DCHECK(space->Contains(index)); // Bail out in case the entry was already marked. diff --git a/deps/v8/src/sandbox/external-pointer-table.h b/deps/v8/src/sandbox/external-pointer-table.h index d7be42911378..9946f3fa7dec 100644 --- a/deps/v8/src/sandbox/external-pointer-table.h +++ b/deps/v8/src/sandbox/external-pointer-table.h @@ -125,6 +125,10 @@ struct ExternalPointerTableEntry { }; using Payload = TaggedPayload<ExternalPointerTablePayloadTaggingScheme>; + public: + static constexpr uint64_t kTagAndMarkBitMask = Payload::kTagAndMarkBitMask; + + private: inline Payload GetRawPayload() const { return payload_.load(std::memory_order_relaxed); } diff --git a/deps/v8/src/sandbox/generated-code-validator-arm64.cc b/deps/v8/src/sandbox/generated-code-validator-arm64.cc index ad4694d3b291..de4d2f9cff9b 100644 --- a/deps/v8/src/sandbox/generated-code-validator-arm64.cc +++ b/deps/v8/src/sandbox/generated-code-validator-arm64.cc @@ -114,7 +114,7 @@ static bool Da64OpEquals(const Da64Op& op1, const Da64Op& op2) { } \ } while (false) -class InstructionChecker { +class InstructionHandler { static_assert(kPtrComprCageBaseRegister != no_reg); static constexpr int cage_base_register = kPtrComprCageBaseRegister.code(); static_assert(kRootRegister != no_reg); @@ -124,35 +124,99 @@ class InstructionChecker { using ViolationsReporter = GeneratedCodeValidator::ViolationsReporter; using Utils = GeneratedCodeValidator::Utils; using State = GeneratedCodeValidator::State; + using BoolValue = State::BoolValue; + using Node = GeneratedCodeValidator::ControlFlowGraph<Da64Inst>::Node; public: - InstructionChecker(Isolate* isolate, Tagged<Code> code, + InstructionHandler(Isolate* isolate, Tagged<Code> code, ViolationsReporter& violations_reporter) - : isolate_(isolate), - code_(code), + : code_(code), violations_reporter_(violations_reporter), - state_(code_), - root_reg_init_state_(isolate_) {} + expected_root_reg_value_( + ExternalReference::isolate_root(isolate).raw()) { + CHECK_NE(expected_root_reg_value_, kNullAddress); + } - void Check(const uint8_t* pc, const Da64Inst& instr) { + void CheckStateDataFlowIndependent(const uint8_t* pc, const Da64Inst& instr) { static_assert(kMaxOperands == (sizeof(instr.ops) / sizeof(Da64Op))); + CheckNoSystemRegisterWrites(pc, instr); + } + + State UpdateState(const Node& node) { + State state = node.input_state(); // REGEXP code doesn't follow the V8 ABI and instead uses standard C ABI. if (code_->kind() != CodeKind::REGEXP) { - CheckNoWritesToCageBaseRegister(pc, instr); - CheckNoWritesToRootRegister(pc, instr); + const Da64Inst& instr = node.instr(); + UpdateCageBaseRegisterState(instr, state); + UpdateRootRegisterState(instr, state); + } + return state; + } + + void CheckState(const Node& node) { + const uint8_t* pc = node.pc(); + const Da64Inst& instr = node.instr(); + const State& state = node.input_state(); + // REGEXP code doesn't follow the V8 ABI and instead uses standard C ABI. + if (code_->kind() != CodeKind::REGEXP) { + CheckNoWritesToCageBaseRegister(pc, instr, state); + CheckNoWritesToRootRegister(pc, instr, state); } - CheckNoSystemRegisterWrites(pc, instr); } private: + void UpdateCageBaseRegisterState(const Da64Inst& instr, State& state) { + switch (instr.mnem) { + case DA64I_LDPX: + case DA64I_LDPX_PRE: + case DA64I_LDPX_POST: + if ((Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_)) && + (IsCageBaseReg(instr.ops[0]) || IsCageBaseReg(instr.ops[1]))) { + state.is_cage_base_reg_valid_ = BoolValue::kFalse; + } + break; + case DA64I_LDURX: + if (IsCageBaseReg(instr.ops[0]) && + IsValidCageBaseRegInitialization(instr)) { + state.is_cage_base_reg_valid_ = BoolValue::kTrue; + } + break; + default: + break; + } + } + + void UpdateRootRegisterState(const Da64Inst& instr, State& state) { + switch (instr.mnem) { + case DA64I_LDPX: + case DA64I_LDPX_PRE: + case DA64I_LDPX_POST: + if ((Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_)) && + (IsRootReg(instr.ops[0]) || IsRootReg(instr.ops[1]))) { + state.is_root_reg_valid_ = BoolValue::kFalse; + state.root_reg_init_state_ = {}; + } + break; + case DA64I_ORR_SHIFT: + case DA64I_MOVZ: + case DA64I_MOVK: + if (IsRootReg(instr.ops[0])) { + UpdateRootRegInitialization(instr, state); + } + break; + default: + break; + } + } + // Verifies whether the instruction accesses the pointer compression cage base // register (x28) directly or modifies it via writeback. The cage base // register must remain read-only across all generated code to preserve // sandbox integrity and prevent pointer corruption. This will not block using // the cage base register as a base address for a memory operand without // writeback. - void CheckNoWritesToCageBaseRegister(const uint8_t* pc, - const Da64Inst& instr) { + void CheckNoWritesToCageBaseRegister(const uint8_t* pc, const Da64Inst& instr, + const State& state) { switch (instr.mnem) { // Subs is used as a comparison to assert that a register holds a heap // object in the main cage. @@ -201,13 +265,9 @@ class InstructionChecker { // register so that the deoptimizer can update register values as // needed. Since the cage base register is callee saved and should not // change, can we avoid saving and restoring it? - if (Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_)) { - if ((IsCageBaseReg(instr.ops[0]) || IsCageBaseReg(instr.ops[1]))) { - state_.is_cage_base_reg_valid_ = false; - } - if (!IsCageBaseWritebackReg(instr.ops[2])) { - return; - } + if ((Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_)) && + !IsCageBaseWritebackReg(instr.ops[2])) { + return; } break; // Ldur is used by entry builtins to initialize the cage base register. @@ -215,17 +275,12 @@ class InstructionChecker { if (!IsCageBaseReg(instr.ops[0])) { return; } - VALIDATOR_CHECK(!state_.is_cage_base_reg_valid_, + VALIDATOR_CHECK(state.is_cage_base_reg_valid_ == BoolValue::kFalse, "Instruction overwrites a valid cage base register"); - if (Utils::IsEntryCode(code_) && - IsExpectedOperand(instr.ops[1], - {.type = DA_OP_MEMSOFF, - .reg = root_register, - .simm16 = IsolateData::cage_base_offset()})) { + if (IsValidCageBaseRegInitialization(instr)) { VALIDATOR_CHECK( - state_.is_root_reg_valid_, + state.is_root_reg_valid_ == BoolValue::kTrue, "Cage base register initialization uses invalid root register"); - state_.is_cage_base_reg_valid_ = true; return; } break; @@ -249,8 +304,10 @@ class InstructionChecker { // across all generated code to preserve sandbox integrity and prevent pointer // corruption. This will not block using the root register as a base address // for a memory operand without writeback. - void CheckNoWritesToRootRegister(const uint8_t* pc, const Da64Inst& instr) { - const bool expecting_init = root_reg_init_state_.in_progress; + void CheckNoWritesToRootRegister(const uint8_t* pc, const Da64Inst& instr, + const State& state) { + const bool expecting_init = + state.root_reg_init_state_.in_progress != BoolValue::kFalse; bool was_init = false; // Flag to skip the generic validation at the end of this method. Used to // prevent accidentally skipping the `expecting_init && !was_init` check @@ -263,19 +320,24 @@ class InstructionChecker { case DA64I_ADD_IMM: case DA64I_ADD_EXT: case DA64I_SUB_IMM: + // Check that the target is not the root register. + if (!IsRootReg(instr.ops[0])) { + // Arithmetic instructions do not support writeback operands. + is_validated = true; + } + break; // Orr is used for copying the root register value and by entry builtins // to initialize the root register. case DA64I_ORR_SHIFT: - // Check that the target is not the cage base register or root register. + // Check that the target is not the root register. if (!IsRootReg(instr.ops[0])) { - // Arithmetic and logical instructions do not support writeback - // operands. + // Logical instructions do not support writeback operands. is_validated = true; break; } - VALIDATOR_CHECK(!state_.is_root_reg_valid_, + VALIDATOR_CHECK(state.is_root_reg_valid_ == BoolValue::kFalse, "Instruction overwrites a valid root register"); - if (Utils::IsEntryCode(code_) && IsValidRootRegInitialization(instr)) { + if (IsValidRootRegInitialization(instr, state)) { is_validated = true; } break; @@ -304,13 +366,9 @@ class InstructionChecker { // register so that the deoptimizer can update register values as // needed. Since the root register is callee saved and should not // change, can we avoid saving and restoring it? - if (Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_)) { - if ((IsRootReg(instr.ops[0]) || IsRootReg(instr.ops[1]))) { - state_.is_root_reg_valid_ = false; - } - if (!IsRootWritebackReg(instr.ops[2])) { - is_validated = true; - } + if ((Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_)) && + !IsRootWritebackReg(instr.ops[2])) { + is_validated = true; } break; // Mov is used by entry builtins to initialize the root register. @@ -320,10 +378,10 @@ class InstructionChecker { is_validated = true; break; } - VALIDATOR_CHECK(!state_.is_root_reg_valid_, + VALIDATOR_CHECK(state.is_root_reg_valid_ == BoolValue::kFalse, "Instruction overwrites a valid root register"); was_init = true; - if (Utils::IsEntryCode(code_) && IsValidRootRegInitialization(instr)) { + if (IsValidRootRegInitialization(instr, state)) { is_validated = true; } break; @@ -398,69 +456,183 @@ class InstructionChecker { return Da64OpEquals(op, expected); } - bool IsValidRootRegInitialization(const Da64Inst& instr) { - DCHECK(IsRootReg(instr.ops[0])); + bool IsValidCageBaseRegInitialization(const Da64Inst& instr) const { + DCHECK(IsCageBaseReg(instr.ops[0])); + return Utils::IsEntryCode(code_) && (instr.mnem == DA64I_LDURX) && + IsExpectedOperand(instr.ops[1], + {.type = DA_OP_MEMSOFF, + .reg = root_register, + .simm16 = IsolateData::cage_base_offset()}); + } + + void UpdateRootRegInitialization(const Da64Inst& instr, State& state) const { + if (!IsValidRootRegInitialization(instr, state)) { + state.is_root_reg_valid_ = BoolValue::kFalse; + state.root_reg_init_state_ = {}; + return; + } + auto& root_reg_init_state = state.root_reg_init_state_; switch (instr.mnem) { case DA64I_MOVZ: - // Movz is the first in a sequence of movs to initialize the root - // register. - DCHECK_EQ(root_reg_init_state_.current_value, kNullAddress); - DCHECK(!root_reg_init_state_.in_progress); + DCHECK_EQ(root_reg_init_state.current_value, kNullAddress); [[fallthrough]]; case DA64I_MOVK: { - // Movk and Movz are used to construct the expected root register value. const Da64Op& op = instr.ops[1]; DCHECK_EQ(DA_OP_UIMMSHIFT, op.type); DCHECK_EQ(0, op.immshift.mask); - const Address previous_value = root_reg_init_state_.current_value; - root_reg_init_state_.current_value |= + const uint64_t mask = 0xFFFFULL << op.immshift.shift; + root_reg_init_state.current_value = + (root_reg_init_state.current_value & ~mask) | (static_cast<uint64_t>(op.uimm16) << op.immshift.shift); - state_.is_root_reg_valid_ = root_reg_init_state_.current_value == - root_reg_init_state_.expected_value_; - root_reg_init_state_.in_progress = !state_.is_root_reg_valid_; - // This is a valid initialization as long as it's making progress - // towards the expected value. - return (previous_value != root_reg_init_state_.current_value) && - ((root_reg_init_state_.current_value & - root_reg_init_state_.expected_value_) == - root_reg_init_state_.current_value); + const bool is_complete = + root_reg_init_state.current_value == expected_root_reg_value_; + state.is_root_reg_valid_ = + is_complete ? BoolValue::kTrue : BoolValue::kFalse; + if (is_complete) { + state.root_reg_init_state_ = {}; + } else { + root_reg_init_state.in_progress = BoolValue::kTrue; + } + break; + } + case DA64I_ORR_SHIFT: + state.is_root_reg_valid_ = BoolValue::kTrue; + break; + default: + UNREACHABLE(); + } + } + + // `state` is the node's input state before executing `instr`. + bool IsValidRootRegInitialization(const Da64Inst& instr, + const State& state) const { + DCHECK(IsRootReg(instr.ops[0])); + if (!Utils::IsEntryCode(code_)) { + return false; + } + switch (instr.mnem) { + case DA64I_MOVZ: + case DA64I_MOVK: { + // Movz is the first in a sequence of movs to initialize the root + // register, followed by Movk instructions to construct the expected + // root register value. + const BoolValue expected_in_progress = + instr.mnem == DA64I_MOVZ ? BoolValue::kFalse : BoolValue::kTrue; + if (state.root_reg_init_state_.in_progress != expected_in_progress) { + return false; + } + const Da64Op& op = instr.ops[1]; + DCHECK_EQ(DA_OP_UIMMSHIFT, op.type); + DCHECK_EQ(0, op.immshift.mask); + const uint64_t mask = 0xFFFFULL << op.immshift.shift; + const uint64_t value = static_cast<uint64_t>(op.uimm16) + << op.immshift.shift; + return ((state.root_reg_init_state_.current_value & mask) == 0) && + ((expected_root_reg_value_ & mask) == value); } case DA64I_ORR_SHIFT: - DCHECK(!root_reg_init_state_.in_progress); // Assumes builtins receive the correct value as their first // argument. - state_.is_root_reg_valid_ = (code_->kind() == CodeKind::BUILTIN) && - IsExpectedReg(instr.ops[2], x0.code()) && - IsExpectedReg(instr.ops[1], xzr.code()); - break; + return (code_->kind() == CodeKind::BUILTIN) && + IsExpectedReg(instr.ops[2], x0.code()) && + IsExpectedReg(instr.ops[1], xzr.code()); default: - break; + UNREACHABLE(); } - return state_.is_root_reg_valid_; } - Isolate* const isolate_; const Tagged<Code> code_; ViolationsReporter& violations_reporter_; - State state_; - struct RootRegisterInitializationState { - explicit RootRegisterInitializationState(Isolate* isolate) - : expected_value_(ExternalReference::isolate_root(isolate).raw()) { - CHECK_NE(expected_value_, kNullAddress); - } - - const Address expected_value_; - Address current_value = kNullAddress; - bool in_progress = false; - } root_reg_init_state_; + const Address expected_root_reg_value_; }; +namespace { + +// TODO(523128533): Handle jump tables, indirect calls, and tail calls. +base::SmallVector<const uint8_t*, 2> GetSuccessors(const uint8_t* pc, + const Da64Inst& instr, + const uint8_t* next_pc) { + bool falls_through = true; + const uint8_t* jump_target = nullptr; + switch (instr.mnem) { + // Unconditional direct branch. + case DA64I_B: + falls_through = false; + jump_target = pc + static_cast<int64_t>(instr.imm64); + break; + // Conditional direct branches. + case DA64I_BCOND: + case DA64I_BCCOND: + DCHECK_EQ(instr.ops[0].type, DA_OP_COND); + if (instr.ops[0].cond == DA_AL || instr.ops[0].cond == DA_NV) { + falls_through = false; + } + jump_target = pc + static_cast<int64_t>(instr.imm64); + break; + case DA64I_CBZ: + case DA64I_CBNZ: + case DA64I_TBZ: + case DA64I_TBNZ: + jump_target = pc + static_cast<int64_t>(instr.imm64); + break; + // Indirect branches. + case DA64I_BR: + case DA64I_BRAA: + case DA64I_BRAB: + case DA64I_BRAAZ: + case DA64I_BRABZ: + // TODO(523128533): Handle jump tables and indirect jumps. + falls_through = false; + break; + // Return instructions. + case DA64I_RET: + case DA64I_RETAA: + case DA64I_RETAB: + case DA64I_ERET: + case DA64I_ERETAA: + case DA64I_ERETAB: + case DA64I_DRPS: + falls_through = false; + break; + // Call instructions are treated as non-control-flow to keep the graph + // intra-procedural. + // TODO(523128533): Properly handle calls, including handling of register + // values across calls. + case DA64I_BL: + case DA64I_BLR: + case DA64I_BLRAA: + case DA64I_BLRAB: + case DA64I_BLRAAZ: + case DA64I_BLRABZ: + DCHECK(falls_through); + break; + default: + break; + } + base::SmallVector<const uint8_t*, 2> successors; + if (falls_through && next_pc != nullptr) { + successors.push_back(next_pc); + } + if (jump_target != nullptr && (!falls_through || jump_target != next_pc)) { + successors.push_back(jump_target); + } + return successors; +} + +} // namespace + +// static +size_t GeneratedCodeValidator::EstimateInstructionCount(Tagged<Code> code) { + DCHECK_EQ(code->instruction_size() % kInstrSize, 0); + return code->instruction_size() / kInstrSize; +} + void GeneratedCodeValidator::ValidateImpl(Isolate* isolate, Tagged<Code> code) { DCHECK_EQ(code->instruction_size() % kInstrSize, 0); ViolationsReporter reporter(code); - - InstructionChecker instruction_checker(isolate, code, reporter); + InstructionHandler instruction_handler(isolate, code, reporter); + ControlFlowGraph<Da64Inst> graph(code); InstructionIteratorSkippingData it(code); @@ -477,9 +649,13 @@ void GeneratedCodeValidator::ValidateImpl(Isolate* isolate, Tagged<Code> code) { reporter.RecordDisassembledInstruction(pc, kInstrSize, Da64InstFormatter::Format(instr)); } - instruction_checker.Check(pc, instr); + instruction_handler.CheckStateDataFlowIndependent(pc, instr); it.Advance(kInstrSize); + const uint8_t* next_pc = it.IsDone() ? nullptr : it.GetCurrent(); + graph.AddNode(pc, instr, GetSuccessors(pc, instr, next_pc)); } + + graph.Validate(instruction_handler); } } // namespace v8::internal diff --git a/deps/v8/src/sandbox/generated-code-validator-x64.cc b/deps/v8/src/sandbox/generated-code-validator-x64.cc index ef22f718d156..41b3dda8495c 100644 --- a/deps/v8/src/sandbox/generated-code-validator-x64.cc +++ b/deps/v8/src/sandbox/generated-code-validator-x64.cc @@ -38,7 +38,7 @@ struct FdInstrFormatter { } \ } while (false) -class InstructionChecker { +class InstructionHandler { static_assert(kPtrComprCageBaseRegister != no_reg); static constexpr int cage_base_register = kPtrComprCageBaseRegister.code(); static_assert(kRootRegister != no_reg); @@ -48,33 +48,91 @@ class InstructionChecker { using ViolationsReporter = GeneratedCodeValidator::ViolationsReporter; using Utils = GeneratedCodeValidator::Utils; using State = GeneratedCodeValidator::State; + using BoolValue = State::BoolValue; + using Node = GeneratedCodeValidator::ControlFlowGraph<FdInstr>::Node; public: - InstructionChecker(Isolate* isolate, Tagged<Code> code, - ViolationsReporter& violations_reproter) + InstructionHandler(Isolate* isolate, Tagged<Code> code, + ViolationsReporter& violations_reporter) : isolate_(isolate), code_(code), - violations_reporter_(violations_reproter), - state_(code_) {} + violations_reporter_(violations_reporter) {} - void Check(const uint8_t* pc, const FdInstr& instr) { + void CheckStateDataFlowIndependent(const uint8_t* pc, const FdInstr& instr) { static_assert(kMaxOperands == (sizeof(instr.operands) / sizeof(FdOp))); + CheckNoSegmentRegisters(pc, instr); + } + + State UpdateState(const Node& node) { + State state = node.input_state(); // REGEXP code doesn't follow the V8 ABI and instead uses standard C ABI. if (code_->kind() != CodeKind::REGEXP) { - CheckNoWritesToCageBaseRegister(pc, instr); - CheckNoWritesToRootRegister(pc, instr); + const FdInstr& instr = node.instr(); + UpdateCageBaseRegisterState(instr, state); + UpdateRootRegisterState(instr, state); + } + return state; + } + + void CheckState(const Node& node) { + const uint8_t* pc = node.pc(); + const FdInstr& instr = node.instr(); + const State& state = node.input_state(); + // REGEXP code doesn't follow the V8 ABI and instead uses standard C ABI. + if (code_->kind() != CodeKind::REGEXP) { + CheckNoWritesToCageBaseRegister(pc, instr, state); + CheckNoWritesToRootRegister(pc, instr, state); } - CheckNoSegmentRegisters(pc, instr); } private: + void UpdateCageBaseRegisterState(const FdInstr& instr, State& state) { + switch (FD_TYPE(&instr)) { + case FDI_POP: + if (IsCageBaseReg(instr, 0) && + (Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_))) { + state.is_cage_base_reg_valid_ = BoolValue::kFalse; + } + break; + case FDI_MOV: + if (IsCageBaseReg(instr, 0) && + IsValidCageBaseRegInitialization(instr)) { + state.is_cage_base_reg_valid_ = BoolValue::kTrue; + } + break; + default: + break; + } + } + + void UpdateRootRegisterState(const FdInstr& instr, State& state) { + switch (FD_TYPE(&instr)) { + case FDI_POP: + if (IsRootReg(instr, 0) && + (Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_))) { + state.is_root_reg_valid_ = BoolValue::kFalse; + } + break; + case FDI_MOV: + case FDI_MOVABS: + if (IsRootReg(instr, 0) && Utils::IsEntryCode(code_)) { + state.is_root_reg_valid_ = IsValidRootRegInitialization(instr) + ? BoolValue::kTrue + : BoolValue::kFalse; + } + break; + default: + break; + } + } + // Verifies whether the instruction accesses the pointer compression cage base // register (r14) directly. The cage base register must remain read-only // across all generated code to preserve sandbox integrity and prevent pointer // corruption. This will not block using the case base register as a // base address for a memory operand. - void CheckNoWritesToCageBaseRegister(const uint8_t* pc, - const FdInstr& instr) { + void CheckNoWritesToCageBaseRegister(const uint8_t* pc, const FdInstr& instr, + const State& state) { switch (FD_TYPE(&instr)) { // Cmp is used to assert that a register holds a heap object in the main // cage. @@ -110,7 +168,6 @@ class InstructionChecker { // register so that the deoptimizer can update register values as // needed. Since the cage base register is callee saved and should not // change, can we avoid saving and restoring it? - state_.is_cage_base_reg_valid_ = false; return; } break; @@ -120,15 +177,12 @@ class InstructionChecker { if (!IsCageBaseReg(instr, 0)) { return; } - VALIDATOR_CHECK(!state_.is_cage_base_reg_valid_, + VALIDATOR_CHECK(state.is_cage_base_reg_valid_ == BoolValue::kFalse, "Instruction overwrites a valid cage base register"); - if (Utils::IsEntryCode(code_) && - IsExpectedMemoryOperand(instr, 1, root_register, FD_REG_NONE, 0, - IsolateData::cage_base_offset())) { + if (IsValidCageBaseRegInitialization(instr)) { VALIDATOR_CHECK( - state_.is_root_reg_valid_, + state.is_root_reg_valid_ == BoolValue::kTrue, "Cage base register initialization uses invalid root register"); - state_.is_cage_base_reg_valid_ = true; return; } break; @@ -151,7 +205,8 @@ class InstructionChecker { // directly. The root register must remain read-only across all generated code // to preserve sandbox integrity and prevent pointer corruption. This will not // block using the root register as a base address for a memory operand. - void CheckNoWritesToRootRegister(const uint8_t* pc, const FdInstr& instr) { + void CheckNoWritesToRootRegister(const uint8_t* pc, const FdInstr& instr, + const State& state) { switch (FD_TYPE(&instr)) { // Push is used by entry and deopt builtins to save the root register's // value in C++ code. @@ -173,7 +228,6 @@ class InstructionChecker { // change, can we avoid saving and restoring it? if (IsRootReg(instr, 0) && (Utils::IsEntryCode(code_) || Utils::IsDeoptCode(code_))) { - state_.is_root_reg_valid_ = false; return; } break; @@ -183,9 +237,9 @@ class InstructionChecker { if (!IsRootReg(instr, 0)) { return; } - VALIDATOR_CHECK(!state_.is_root_reg_valid_, + VALIDATOR_CHECK(state.is_root_reg_valid_ == BoolValue::kFalse, "Instruction overwrites a valid root register"); - if (Utils::IsEntryCode(code_) && IsValidRootRegInitialization(instr)) { + if (IsValidRootRegInitialization(instr)) { return; } break; @@ -245,44 +299,136 @@ class InstructionChecker { (FD_OP_DISP(&instr, op_idx) == displacement); } - bool IsValidRootRegInitialization(const FdInstr& instr) { + bool IsValidCageBaseRegInitialization(const FdInstr& instr) const { + DCHECK(IsCageBaseReg(instr, 0)); + return Utils::IsEntryCode(code_) && (FD_TYPE(&instr) == FDI_MOV) && + IsExpectedMemoryOperand(instr, 1, root_register, FD_REG_NONE, 0, + IsolateData::cage_base_offset()); + } + + bool IsValidRootRegInitialization(const FdInstr& instr) const { DCHECK(IsRootReg(instr, 0)); + if (!Utils::IsEntryCode(code_)) { + return false; + } switch (FD_TYPE(&instr)) { case FDI_MOVABS: { DCHECK_EQ(FD_OT_IMM, FD_OP_TYPE(&instr, 1)); const int64_t imm_value = FD_OP_IMM(&instr, 1); - state_.is_root_reg_valid_ = - static_cast<const uint64_t>(imm_value) == - ExternalReference::isolate_root(isolate_).raw(); - break; + return static_cast<const uint64_t>(imm_value) == + ExternalReference::isolate_root(isolate_).raw(); } case FDI_MOV: // Assumes builtins receive the correct value as their first // argument. - state_.is_root_reg_valid_ = - (code_->kind() == CodeKind::BUILTIN) && - IsExpectedReg(instr, 1, kCArgRegs[0].code()); - break; + return (code_->kind() == CodeKind::BUILTIN) && + IsExpectedReg(instr, 1, kCArgRegs[0].code()); default: UNREACHABLE(); } - return state_.is_root_reg_valid_; } Isolate* const isolate_; const Tagged<Code> code_; ViolationsReporter& violations_reporter_; - State state_; }; +namespace { + +// TODO(523128533): Handle jump tables, indirect calls, and tail calls. +base::SmallVector<const uint8_t*, 2> GetSuccessors(const uint8_t* pc, + const FdInstr& instr, + const uint8_t* next_pc) { + bool falls_through = true; + const uint8_t* jump_target = nullptr; + switch (FD_TYPE(&instr)) { + // Unconditional jumps. + case FDI_JMP: + falls_through = false; + if (FD_OP_TYPE(&instr, 0) == FD_OT_OFF) { + jump_target = pc + FD_SIZE(&instr) + FD_OP_IMM(&instr, 0); + } else { + // TODO(523128533): Handle jump tables and indirect jumps. + } + break; + case FDI_JMPF: + // TODO(523128533): Handle indirect jumps. + falls_through = false; + break; + // Conditional direct jumps. + case FDI_JA: + case FDI_JBE: + case FDI_JC: + case FDI_JCXZ: + case FDI_JG: + case FDI_JGE: + case FDI_JL: + case FDI_JLE: + case FDI_JNC: + case FDI_JNO: + case FDI_JNP: + case FDI_JNS: + case FDI_JNZ: + case FDI_JO: + case FDI_JP: + case FDI_JS: + case FDI_JZ: + case FDI_LOOP: + case FDI_LOOPNZ: + case FDI_LOOPZ: + DCHECK_EQ(FD_OP_TYPE(&instr, 0), FD_OT_OFF); + jump_target = pc + FD_SIZE(&instr) + FD_OP_IMM(&instr, 0); + break; + // Return instructions. + case FDI_RET: + case FDI_RETF: + case FDI_IRET: + case FDI_UIRET: + case FDI_ERETS: + case FDI_ERETU: + case FDI_SYSRET: + case FDI_SYSEXIT: + case FDI_RSM: + case FDI_SEAMRET: + falls_through = false; + break; + // Call instructions are treated as non-control-flow to keep the graph + // intra-procedural. + // TODO(523128533): Properly handle calls, including handling of register + // values across calls. + case FDI_CALL: + case FDI_CALLF: + DCHECK(falls_through); + break; + default: + break; + } + base::SmallVector<const uint8_t*, 2> successors; + if (falls_through && next_pc != nullptr) { + successors.push_back(next_pc); + } + if (jump_target != nullptr && (!falls_through || jump_target != next_pc)) { + successors.push_back(jump_target); + } + return successors; +} + +} // namespace + +// static +size_t GeneratedCodeValidator::EstimateInstructionCount(Tagged<Code> code) { + static constexpr size_t kAverageInstructionSize = 4; + return code->instruction_size() / kAverageInstructionSize; +} + void GeneratedCodeValidator::ValidateImpl(Isolate* isolate, Tagged<Code> code) { const uint8_t* const code_start = reinterpret_cast<const uint8_t*>(code->instruction_start()); const uint8_t* const code_end = code_start + code->instruction_size(); ViolationsReporter reporter(code); - - InstructionChecker instruction_checker(isolate, code, reporter); + InstructionHandler instruction_handler(isolate, code, reporter); + ControlFlowGraph<FdInstr> graph(code); InstructionIteratorSkippingData it(code); @@ -302,9 +448,13 @@ void GeneratedCodeValidator::ValidateImpl(Isolate* isolate, Tagged<Code> code) { reporter.RecordDisassembledInstruction(pc, res, FdInstrFormatter::Format(instr)); } - instruction_checker.Check(pc, instr); + instruction_handler.CheckStateDataFlowIndependent(pc, instr); it.Advance(res); + const uint8_t* next_pc = it.IsDone() ? nullptr : it.GetCurrent(); + graph.AddNode(pc, instr, GetSuccessors(pc, instr, next_pc)); } + + graph.Validate(instruction_handler); } } // namespace v8::internal diff --git a/deps/v8/src/sandbox/generated-code-validator.cc b/deps/v8/src/sandbox/generated-code-validator.cc index 536ffd7a0219..b09b676436a9 100644 --- a/deps/v8/src/sandbox/generated-code-validator.cc +++ b/deps/v8/src/sandbox/generated-code-validator.cc @@ -7,6 +7,7 @@ #ifdef V8_ENABLE_GENERATED_CODE_VALIDATOR #include <algorithm> +#include <queue> #include "src/objects/code-inl.h" #include "src/objects/code-kind.h" @@ -256,9 +257,168 @@ bool GeneratedCodeValidator::Utils::IsDeoptCode(const Tagged<Code> code) { code->builtin_id()) != std::end(entry_builtins); } -GeneratedCodeValidator::State::State(const Tagged<Code> code) - : is_root_reg_valid_(!Utils::IsEntryCode(code)), - is_cage_base_reg_valid_(!Utils::IsEntryCode(code)) {} +// static +GeneratedCodeValidator::State GeneratedCodeValidator::State::CreateNewState( + const Tagged<Code> code) { + const BoolValue initial_reg_state = + Utils::IsEntryCode(code) ? BoolValue::kFalse : BoolValue::kTrue; + return { + .is_root_reg_valid_ = initial_reg_state, + .is_cage_base_reg_valid_ = initial_reg_state, +#if V8_TARGET_ARCH_ARM64 + .root_reg_init_state_ = {}, +#endif // V8_TARGET_ARCH_ARM64 + }; +} + +#if V8_TARGET_ARCH_ARM64 +// static +GeneratedCodeValidator::State::RootRegisterInitState +GeneratedCodeValidator::State::RootRegisterInitState::Merge( + const RootRegisterInitState& state1, const RootRegisterInitState& state2) { + return { + .current_value = state1.current_value & state2.current_value, + .in_progress = MergeBoolValues(state1.in_progress, state2.in_progress), + }; +} +#endif // V8_TARGET_ARCH_ARM64 + +// static +GeneratedCodeValidator::State GeneratedCodeValidator::State::Merge( + const State& state1, const State& state2) { + return { + .is_root_reg_valid_ = + MergeBoolValues(state1.is_root_reg_valid_, state2.is_root_reg_valid_), + .is_cage_base_reg_valid_ = MergeBoolValues( + state1.is_cage_base_reg_valid_, state2.is_cage_base_reg_valid_), +#if V8_TARGET_ARCH_ARM64 + .root_reg_init_state_ = RootRegisterInitState::Merge( + state1.root_reg_init_state_, state2.root_reg_init_state_), +#endif // V8_TARGET_ARCH_ARM64 + }; +} + +bool GeneratedCodeValidator::ControlFlowGraphBase::NodeBase::MergeInputState( + const State& state) { + if (!input_state_.has_value()) { + input_state_ = state; + return true; + } + if (*input_state_ == state) { + return false; + } + State merged = State::Merge(*input_state_, state); + if (*input_state_ == merged) { + return false; + } + input_state_ = merged; + return true; +} + +bool GeneratedCodeValidator::ControlFlowGraphBase::NodeBase::UpdateOutputState( + const State& state) { + if (output_state_.has_value() && *output_state_ == state) { + return false; + } + output_state_ = state; + return true; +} + +GeneratedCodeValidator::ControlFlowGraphBase::ControlFlowGraphBase( + Tagged<Code> code) + : code_(code), + code_start_(reinterpret_cast<const uint8_t*>(code->instruction_start())), + code_end_(code_start_ + code->instruction_size()) { + recorded_pcs_.reserve(EstimateInstructionCount(code)); +} + +void GeneratedCodeValidator::ControlFlowGraphBase::ValidateNodes( + base::FunctionRef<State(const NodeBase&)> update_state, + base::FunctionRef<void(const NodeBase&)> check_state) { + // TODO(523128533): Enable successor checks once tail calls are properly + // handled. + // #ifdef DEBUG + // for (const uint8_t* pc : recorded_pcs_) { + // const NodeBase* node = GetNodeAt(pc); + // DCHECK_NOT_NULL(node); + // for (const uint8_t* successor_pc : node->successors()) { + // DCHECK_NOT_NULL(GetNodeAt(successor_pc)); + // } + // } + // #endif // DEBUG + + // Validation is split into two passes: + // 1. Data-flow analysis propagates and merges validation states along CFG + // edges until a fixed point is reached for all reachable nodes. + // 2. Violation checking iterates over all nodes in ascending PC order and + // validates each instruction against its converged input state. + // Separating the two passes ensures that nodes visited multiple times during + // fixed-point iteration are not checked against transient pre-convergence + // states or reported multiple times, and that violations are reported + // deterministically in PC order. + PropagateStates(update_state); + CheckStates(check_state); +} + +void GeneratedCodeValidator::ControlFlowGraphBase::PropagateStates( + base::FunctionRef<State(const NodeBase&)> update_state) { + NodeBase* entry_node = GetNodeAt(code_start_); + if (entry_node == nullptr) return; + + std::queue<NodeBase*> worklist; + + auto push_node = [&worklist](NodeBase* node) { + if (!node->is_pending()) { + node->set_is_pending(true); + worklist.push(node); + } + }; + + entry_node->MergeInputState(State::CreateNewState(code_)); + push_node(entry_node); + + while (!worklist.empty()) { + NodeBase* node = worklist.front(); + worklist.pop(); + DCHECK(node->is_pending()); + node->set_is_pending(false); + State output_state = update_state(*node); + if (node->UpdateOutputState(output_state)) { + for (const uint8_t* successor_pc : node->successors()) { + if (!IsPcInBounds(successor_pc)) { + // TODO(523128533): Handle tail calls. + continue; + } + NodeBase* successor = GetNodeAt(successor_pc); + // TODO(523128533): In simulator builds, ASM_LOCATION embeds inline + // metadata in the instruction stream that is skipped during + // disassembly, but can still be the target of a jump (when a label is + // bound right before ASM_LOCATION). Once ASM_LOCATION is properly + // handled in the CFG, replace this check with + // `DCHECK_NOT_NULL(successor)`. + if (successor == nullptr) { + continue; + } + if (successor->MergeInputState(output_state)) { + push_node(successor); + } + } + } + } +} + +void GeneratedCodeValidator::ControlFlowGraphBase::CheckStates( + base::FunctionRef<void(const NodeBase&)> check_state) { + for (const uint8_t* pc : recorded_pcs_) { + const NodeBase* node = GetNodeAt(pc); + DCHECK_NOT_NULL(node); + // TODO(523128533): Check that all instructions have an input state once + // jump tables and indirect jumps are handled. + if (node->has_input_state()) { + check_state(*node); + } + } +} } // namespace v8::internal diff --git a/deps/v8/src/sandbox/generated-code-validator.h b/deps/v8/src/sandbox/generated-code-validator.h index 23143b41eabb..608a2e1bacc9 100644 --- a/deps/v8/src/sandbox/generated-code-validator.h +++ b/deps/v8/src/sandbox/generated-code-validator.h @@ -7,8 +7,13 @@ #ifdef V8_ENABLE_GENERATED_CODE_VALIDATOR +#include <algorithm> #include <optional> +#include <vector> +#include "absl/container/flat_hash_map.h" +#include "src/base/functional/function-ref.h" +#include "src/base/small-vector.h" #include "src/codegen/jump-table-info.h" #include "src/codegen/reloc-info.h" #include "src/diagnostics/disasm.h" @@ -16,7 +21,7 @@ namespace v8::internal { -class InstructionChecker; +class InstructionHandler; class GeneratedCodeValidator { public: @@ -86,18 +91,149 @@ class GeneratedCodeValidator { static bool IsDeoptCode(const Tagged<Code> code); }; - // TODO(523128533): Propagate `State` between instructions based on data flow. struct State { - explicit State(const Tagged<Code> code); + enum class BoolValue : uint8_t { + kFalse, + kTrue, + kMixed, + }; + + static State CreateNewState(const Tagged<Code> code); + static State Merge(const State& state1, const State& state2); + static BoolValue MergeBoolValues(BoolValue v1, BoolValue v2) { + return v1 == v2 ? v1 : BoolValue::kMixed; + } + + bool operator==(const State& other) const = default; - bool is_root_reg_valid_; + BoolValue is_root_reg_valid_; // TODO(523128533): Check this field when checking memory writes to sandbox. - bool is_cage_base_reg_valid_; + BoolValue is_cage_base_reg_valid_; +#if V8_TARGET_ARCH_ARM64 + struct RootRegisterInitState { + static RootRegisterInitState Merge(const RootRegisterInitState& state1, + const RootRegisterInitState& state2); + + bool operator==(const RootRegisterInitState& other) const = default; + + Address current_value = kNullAddress; + BoolValue in_progress = BoolValue::kFalse; + } root_reg_init_state_; +#endif // V8_TARGET_ARCH_ARM64 + }; + + class ControlFlowGraphBase { + public: + class NodeBase { + public: + NodeBase(const uint8_t* pc, + base::SmallVector<const uint8_t*, 2> successors) + : pc_(pc), successors_(std::move(successors)) {} + + const uint8_t* pc() const { return pc_; } + const base::SmallVector<const uint8_t*, 2>& successors() const { + return successors_; + } + + bool has_input_state() const { return input_state_.has_value(); } + const State& input_state() const { + DCHECK(input_state_.has_value()); + return *input_state_; + } + bool MergeInputState(const State& state); + bool UpdateOutputState(const State& state); + + bool is_pending() const { return is_pending_; } + void set_is_pending(bool is_pending) { is_pending_ = is_pending; } + + private: + const uint8_t* const pc_; + base::SmallVector<const uint8_t*, 2> successors_; + std::optional<State> input_state_; + std::optional<State> output_state_; + bool is_pending_ = false; + }; + + explicit ControlFlowGraphBase(Tagged<Code> code); + virtual ~ControlFlowGraphBase() = default; + + protected: + void RecordNodePc(const uint8_t* pc) { + DCHECK(recorded_pcs_.empty() || pc > recorded_pcs_.back()); + recorded_pcs_.push_back(pc); + } + virtual NodeBase* GetNodeAt(const uint8_t* pc) = 0; + void ValidateNodes(base::FunctionRef<State(const NodeBase&)> update_state, + base::FunctionRef<void(const NodeBase&)> check_state); + bool IsPcInBounds(const uint8_t* pc) const { + return pc >= code_start_ && pc < code_end_; + } + + private: + void PropagateStates( + base::FunctionRef<State(const NodeBase&)> update_state); + void CheckStates(base::FunctionRef<void(const NodeBase&)> check_state); + + const Tagged<Code> code_; + const uint8_t* const code_start_; + const uint8_t* const code_end_; + std::vector<const uint8_t*> recorded_pcs_; + }; + + template <typename Instr> + class ControlFlowGraph : public ControlFlowGraphBase { + public: + class Node : public NodeBase { + public: + Node(const uint8_t* pc, const Instr& instr, + base::SmallVector<const uint8_t*, 2> successors) + : NodeBase(pc, std::move(successors)), instr_(instr) {} + + const Instr& instr() const { return instr_; } + + private: + const Instr instr_; + }; + + explicit ControlFlowGraph(Tagged<Code> code) : ControlFlowGraphBase(code) { + nodes_.reserve(EstimateInstructionCount(code)); + } + + void AddNode(const uint8_t* pc, const Instr& instr, + base::SmallVector<const uint8_t*, 2> successors) { + auto [it, inserted] = + nodes_.try_emplace(pc, pc, instr, std::move(successors)); + DCHECK(inserted); + USE(inserted); + RecordNodePc(pc); + } + + template <typename InstructionHandler> + void Validate(InstructionHandler& instruction_handler) { + ValidateNodes( + [&](const NodeBase& node) { + return instruction_handler.UpdateState( + static_cast<const Node&>(node)); + }, + [&](const NodeBase& node) { + instruction_handler.CheckState(static_cast<const Node&>(node)); + }); + } + + protected: + NodeBase* GetNodeAt(const uint8_t* pc) override { + auto it = nodes_.find(pc); + return it != nodes_.end() ? &it->second : nullptr; + } + + private: + absl::flat_hash_map<const uint8_t*, Node> nodes_; }; + static size_t EstimateInstructionCount(Tagged<Code> code); static void ValidateImpl(Isolate* isolate, Tagged<Code> code); - friend class InstructionChecker; + friend class InstructionHandler; }; } // namespace v8::internal diff --git a/deps/v8/src/sandbox/indirect-pointer-inl.h b/deps/v8/src/sandbox/indirect-pointer-inl.h deleted file mode 100644 index d43be20a9b14..000000000000 --- a/deps/v8/src/sandbox/indirect-pointer-inl.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2023 the V8 project 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 V8_SANDBOX_INDIRECT_POINTER_INL_H_ -#define V8_SANDBOX_INDIRECT_POINTER_INL_H_ - -#include "src/sandbox/indirect-pointer.h" -// Include the non-inl header before the rest of the headers. - -#include "include/v8-internal.h" -#include "src/base/atomic-utils.h" -#include "src/heap/heap-write-barrier.h" -#include "src/sandbox/isolate-inl.h" -#include "src/sandbox/trusted-pointer-table-inl.h" - -namespace v8 { -namespace internal { - -V8_INLINE void InitSelfIndirectPointerField( - Address field_address, IsolateForSandbox isolate, Tagged<HeapObject> host, - IndirectPointerTag tag, - TrustedPointerPublishingScope* opt_publishing_scope) { -#ifdef V8_ENABLE_SANDBOX - DCHECK_NE(tag, kIndirectPointerNullTag); - - TrustedPointerTable::Space* space = - isolate.GetTrustedPointerTableSpaceFor(tag, host.address()); - IndirectPointerHandle handle = - isolate.GetTrustedPointerTableFor(tag).AllocateAndInitializeEntry( - space, host.ptr(), tag, opt_publishing_scope); - - // Use a Release_Store to ensure that the store of the pointer into the table - // is not reordered after the store of the handle. Otherwise, other threads - // may access an uninitialized table entry and crash. - auto location = reinterpret_cast<IndirectPointerHandle*>(field_address); - base::AsAtomic32::Release_Store(location, handle); -#else - UNREACHABLE(); -#endif -} - -#ifdef V8_ENABLE_SANDBOX -template <IndirectPointerTagRange tag_range> -V8_INLINE Tagged<Object> ResolveIndirectPointerHandle( - IndirectPointerHandle handle, IsolateForSandbox isolate) { - const TrustedPointerTable& table = - isolate.GetTrustedPointerTableFor(tag_range); - return Tagged<Object>(table.Get(handle, tag_range)); -} - -template <IndirectPointerTagRange tag_range> -V8_INLINE Tagged<Object> ReadIndirectPointerHandle(IndirectPointerHandle handle, - IsolateForSandbox isolate) { - return ResolveIndirectPointerHandle<tag_range>(handle, isolate); -} - -#endif // V8_ENABLE_SANDBOX - -template <IndirectPointerTagRange tag_range> -V8_INLINE Tagged<Object> ReadIndirectPointerField(Address field_address, - IsolateForSandbox isolate, - AcquireLoadTag) { -#ifdef V8_ENABLE_SANDBOX - // Load the indirect pointer handle from the object. - // Technically, we could use memory_order_consume here as the loads are - // dependent, but that appears to be deprecated in favor of acquire ordering. - auto location = reinterpret_cast<IndirectPointerHandle*>(field_address); - IndirectPointerHandle handle = base::AsAtomic32::Acquire_Load(location); - if (handle == kNullIndirectPointerHandle) return Smi::zero(); - return ReadIndirectPointerHandle<tag_range>(handle, isolate); -#else - return Tagged<Object>(*reinterpret_cast<Address*>(field_address)); -#endif -} - -template <IndirectPointerTagRange tag_range> -V8_INLINE void WriteIndirectPointerField(Address field_address, - Tagged<ExposedTrustedObject> value, - ReleaseStoreTag) { -#ifdef V8_ENABLE_SANDBOX - static_assert(!tag_range.IsEmpty()); - IndirectPointerHandle handle = value->self_indirect_pointer_handle(); - DCHECK_NE(handle, kNullIndirectPointerHandle); - auto location = reinterpret_cast<IndirectPointerHandle*>(field_address); - base::AsAtomic32::Release_Store(location, handle); -#else - UNREACHABLE(); -#endif -} - -} // namespace internal -} // namespace v8 - -#endif // V8_SANDBOX_INDIRECT_POINTER_INL_H_ diff --git a/deps/v8/src/sandbox/indirect-pointer.h b/deps/v8/src/sandbox/indirect-pointer.h deleted file mode 100644 index 04069eef96b8..000000000000 --- a/deps/v8/src/sandbox/indirect-pointer.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2023 the V8 project 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 V8_SANDBOX_INDIRECT_POINTER_H_ -#define V8_SANDBOX_INDIRECT_POINTER_H_ - -#include "src/common/globals.h" -#include "src/objects/objects.h" -#include "src/sandbox/indirect-pointer-tag.h" -#include "src/sandbox/isolate.h" - -namespace v8 { -namespace internal { - -class TrustedPointerPublishingScope; - -// Indirect pointers. -// -// An indirect pointer references a HeapObject (like a tagged pointer), but -// does so through a pointer table indirection. Indirect pointers are used when -// the sandbox is enabled to reference objects _outside_ of the sandbox in a -// memory-safe way. For that, each indirect pointer has an associated -// IndirectPointerTag which encodes the type of the referenced object. The -// pointer table indirection then ensures that the tag of the entry in the -// table matches the type of the referenced object, or else the pointer will be -// invalid (it cannot be dereferenced). - -// Initialize the 'self' indirect pointer that contains a reference back to the -// owning object through its pointer table entry. For Code objects, this will -// allocate an entry in the code pointer table. For all other trusted objects, -// this will allocate an entry in the trusted pointer table. -// -// Only available when the sandbox is enabled. -V8_INLINE void InitSelfIndirectPointerField( - Address field_address, IsolateForSandbox isolate, Tagged<HeapObject> host, - IndirectPointerTag tag, - TrustedPointerPublishingScope* opt_publishing_scope); - -// Reads the IndirectPointerHandle from the field and loads the Object -// referenced by this handle from the appropriate pointer table. The given -// IndirectPointerTag specifies the expected type of object and determines -// which pointer table is used: the code pointer table for Code objects and the -// trusted pointer table for all other trusted objects. -// -// Only available when the sandbox is enabled. -template <IndirectPointerTagRange tag_range> -V8_INLINE Tagged<Object> ReadIndirectPointerField(Address field_address, - IsolateForSandbox isolate, - AcquireLoadTag); - -// Loads the 'self' IndirectPointerHandle from the given object and stores it -// into the indirect pointer field. In this way, the field becomes a (indirect) -// reference to the given object. -// -// Only available when the sandbox is enabled. -template <IndirectPointerTagRange tag_range> -V8_INLINE void WriteIndirectPointerField(Address field_address, - Tagged<ExposedTrustedObject> value, - ReleaseStoreTag); - -} // namespace internal -} // namespace v8 - -#endif // V8_SANDBOX_INDIRECT_POINTER_H_ diff --git a/deps/v8/src/sandbox/isolate-inl.h b/deps/v8/src/sandbox/isolate-inl.h index 5b99f11aeef3..32a9cfed9d1a 100644 --- a/deps/v8/src/sandbox/isolate-inl.h +++ b/deps/v8/src/sandbox/isolate-inl.h @@ -12,7 +12,7 @@ #include "src/heap/heap-layout-inl.h" #include "src/objects/heap-object.h" #include "src/sandbox/external-pointer-table-inl.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" namespace v8::internal { @@ -35,14 +35,14 @@ JSDispatchTable& IsolateForSandbox::GetJSDispatchTable() { } TrustedPointerTable& IsolateForSandbox::GetTrustedPointerTableFor( - IndirectPointerTagRange tag_range) { + TrustedPointerTagRange tag_range) { return IsSharedTrustedPointerType(tag_range) ? isolate_->shared_trusted_pointer_table() : isolate_->trusted_pointer_table(); } TrustedPointerTable::Space* IsolateForSandbox::GetTrustedPointerTableSpaceFor( - IndirectPointerTagRange tag_range, Address host) { + TrustedPointerTagRange tag_range, Address host) { if (V8_UNLIKELY(IsSharedTrustedPointerType(tag_range))) { DCHECK(!ReadOnlyHeap::Contains(host)); return isolate_->shared_trusted_pointer_space(); diff --git a/deps/v8/src/sandbox/isolate.h b/deps/v8/src/sandbox/isolate.h index 835998d023b5..981da68b0fa0 100644 --- a/deps/v8/src/sandbox/isolate.h +++ b/deps/v8/src/sandbox/isolate.h @@ -7,9 +7,9 @@ #include "src/sandbox/cppheap-pointer-table.h" #include "src/sandbox/external-pointer-table.h" -#include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/js-dispatch-table.h" #include "src/sandbox/trusted-pointer-table.h" +#include "src/sandbox/trusted-pointer-tag.h" namespace v8::internal { @@ -32,9 +32,9 @@ class V8_EXPORT_PRIVATE IsolateForSandbox final { ExternalPointerTagRange tag_range, Address host); inline TrustedPointerTable& GetTrustedPointerTableFor( - IndirectPointerTagRange tag_range); + TrustedPointerTagRange tag_range); inline TrustedPointerTable::Space* GetTrustedPointerTableSpaceFor( - IndirectPointerTagRange tag_range, Address host); + TrustedPointerTagRange tag_range, Address host); inline JSDispatchTable& GetJSDispatchTable(); diff --git a/deps/v8/src/sandbox/js-dispatch-table-inl.h b/deps/v8/src/sandbox/js-dispatch-table-inl.h index e9d2b88b2707..c43dd402967f 100644 --- a/deps/v8/src/sandbox/js-dispatch-table-inl.h +++ b/deps/v8/src/sandbox/js-dispatch-table-inl.h @@ -29,7 +29,10 @@ void JSDispatchEntry::MakeJSDispatchEntry(Address object, Address entrypoint, bool mark_as_alive) { DCHECK_NE(entrypoint, kNullAddress); DCHECK_EQ(object & kHeapObjectTag, 0); -#if !defined(__illumos__) || !defined(V8_TARGET_ARCH_64_BIT) +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + DCHECK_EQ(parameter_count & ~kParameterCountMask, 0); + Address payload = parameter_count; +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) DCHECK_EQ((((object - kObjectPointerOffset) << kObjectPointerShift) >> kObjectPointerShift) + kObjectPointerOffset, @@ -37,18 +40,23 @@ void JSDispatchEntry::MakeJSDispatchEntry(Address object, Address entrypoint, DCHECK_EQ((object - kObjectPointerOffset) + kObjectPointerOffset, object); DCHECK_LT((object - kObjectPointerOffset), 1ULL << ((sizeof(encoded_word_) * 8) - kObjectPointerShift)); -#endif /* __illumos__ & 64-bit */ Address payload = ((object - kObjectPointerOffset) << kObjectPointerShift) | (parameter_count & kParameterCountMask); - DCHECK(!(payload & kMarkingBit)); - if (mark_as_alive) payload |= kMarkingBit; +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) #ifdef V8_TARGET_ARCH_32_BIT parameter_count_.store(parameter_count, std::memory_order_relaxed); next_free_entry_.store(0, std::memory_order_relaxed); -#endif +#endif // V8_TARGET_ARCH_32_BIT + DCHECK(!(payload & kMarkingBit)); + if (mark_as_alive) payload |= kMarkingBit; entrypoint_.store(entrypoint, std::memory_order_relaxed); +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + encoded_word_.store(payload, std::memory_order_relaxed); + code_object_.store(object | kHeapObjectTag, std::memory_order_release); +#else encoded_word_.store(payload, std::memory_order_release); +#endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 DCHECK(!IsFreelistEntry()); } @@ -59,21 +67,16 @@ Address JSDispatchEntry::GetEntrypoint() const { Address JSDispatchEntry::GetCodePointer() const { DCHECK(!IsFreelistEntry()); +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + return code_object_.load(std::memory_order_acquire); +#else // The pointer tag bit (LSB) of the object pointer is used as marking bit, // and so may be 0 or 1 here. As the return value is a tagged pointer, the // bit must be 1 when returned, so we need to set it here. Address payload = encoded_word_.load(std::memory_order_acquire); -#if defined(__illumos__) && defined(V8_TARGET_ARCH_64_BIT) - // Unsigned types won't sign-extend on shift-right, but we need to do - // this with illumos VA48 addressing. - DCHECK_EQ(kObjectPointerOffset, 0); - return (Address)(static_cast<intptr_t>(payload) >> - static_cast<int>(kObjectPointerShift)) | - kHeapObjectTag; -#else return ((payload >> kObjectPointerShift) + kObjectPointerOffset) | kHeapObjectTag; -#endif /* __illumos__ & 64-bit */ +#endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 } Tagged<Code> JSDispatchEntry::GetCode() const { @@ -233,6 +236,11 @@ void JSDispatchEntry::SetCodeAndEntrypointPointer(Address new_object, Address new_entrypoint, Isolate* isolate) { DCHECK_NE(new_entrypoint, kNullAddress); +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + DCHECK(Internals::HasHeapObjectTag(new_object)); + entrypoint_.store(new_entrypoint, std::memory_order_relaxed); + code_object_.store(new_object, std::memory_order_release); +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) Address old_payload = encoded_word_.load(std::memory_order_relaxed); Address marking_bit = old_payload & kMarkingBit; Address parameter_count = old_payload & kParameterCountMask; @@ -257,6 +265,7 @@ void JSDispatchEntry::SetCodeAndEntrypointPointer(Address new_object, new_payload = object | marking_bit | parameter_count; } } +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) DCHECK(!IsFreelistEntry()); } @@ -274,18 +283,16 @@ void JSDispatchEntry::MakeFreelistEntry(uint32_t next_entry_index) { next_free_entry_.store(next_entry_index + 1, std::memory_order_relaxed); entrypoint_.store(kNullAddress, std::memory_order_relaxed); #endif +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + code_object_.store(kNullAddress, std::memory_order_relaxed); +#endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 encoded_word_.store(kNullAddress, std::memory_order_relaxed); DCHECK(IsFreelistEntry()); } #ifdef V8_TARGET_ARCH_64_BIT bool JSDispatchEntry::IsFreelistEntry(Address entrypoint) const { -#ifdef __illumos__ - // See the illumos definition of kFreeEntryTag for why we have to do this. - return (entrypoint & 0xffff000000000000ull) == kFreeEntryTag; -#else return (entrypoint & kFreeEntryTag) == kFreeEntryTag; -#endif /* __illumos__ */ } #endif diff --git a/deps/v8/src/sandbox/js-dispatch-table.cc b/deps/v8/src/sandbox/js-dispatch-table.cc index cc21c21a05de..fcefe86ae742 100644 --- a/deps/v8/src/sandbox/js-dispatch-table.cc +++ b/deps/v8/src/sandbox/js-dispatch-table.cc @@ -18,8 +18,13 @@ namespace internal { void JSDispatchEntry::CheckFieldOffsets() { static_assert(JSDispatchEntry::kEntrypointOffset == offsetof(JSDispatchEntry, entrypoint_)); +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + static_assert(JSDispatchEntry::kCodeObjectOffset == + offsetof(JSDispatchEntry, code_object_)); +#else static_assert(JSDispatchEntry::kCodeObjectOffset == offsetof(JSDispatchEntry, encoded_word_)); +#endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 #if defined(V8_TARGET_ARCH_64_BIT) #ifdef V8_TARGET_BIG_ENDIAN // 2-byte parameter count is on the least significant side of encoded_word_. diff --git a/deps/v8/src/sandbox/js-dispatch-table.h b/deps/v8/src/sandbox/js-dispatch-table.h index 830fa95fd3e4..ee58c6b4367a 100644 --- a/deps/v8/src/sandbox/js-dispatch-table.h +++ b/deps/v8/src/sandbox/js-dispatch-table.h @@ -94,24 +94,19 @@ struct JSDispatchEntry { #endif #if defined(V8_TARGET_ARCH_64_BIT) + static constexpr uint32_t kMaxParameterCountBits = 16; + static constexpr uint32_t kParameterCountMask = + (1 << kMaxParameterCountBits) - 1; // Freelist entries contain the index of the next free entry in their lower 32 // bits and are tagged with this tag. -#ifdef __illumos__ - // In illumos 64-bit apps, pointers are allocated both the bottom 2^47 range - // AND the top 2^47 range in the 64-bit space. Instead of 47 bits of VA space - // we have 48 bits. This means, however, the top 16-bits may be 0xffff. We - // therefore pick a different value for the kFreeEntryTag. If/when we go to - // VA57, aka 5-level paging, we'll need to revisit this again, as will node - // by default, since the fixed-bits on the high end will shrink from top - // 16-bits to top 8-bits. - // - // Unless illumos ships an Oracle-Solaris-like VA47 link-time options to - // restrict pointers from allocating from above the Virtual Address hole, - // we need to be mindful of this. - static constexpr Address kFreeEntryTag = 0xfeed000000000000ull; -#else +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + // On x64, only the top byte is set so that it does not overlap with 57-bit + // user-space addresses (LA57). + static constexpr Address kFreeEntryTag = 0xff00000000000000ull; + static constexpr uintptr_t kParameterCountOffset = 2 * kSystemPointerSize; + static constexpr uint32_t kObjectPointerShift = 0; +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) static constexpr Address kFreeEntryTag = 0xffff000000000000ull; -#endif /* __illumos__ */ #ifdef V8_TARGET_BIG_ENDIAN // 2-byte parameter count is on the least significant side of encoded_word_. static constexpr int kBigEndianParamCountOffset = @@ -121,13 +116,15 @@ struct JSDispatchEntry { #else static constexpr uintptr_t kParameterCountOffset = kCodeObjectOffset; #endif // V8_TARGET_BIG_ENDIAN - static constexpr uint32_t kObjectPointerShift = 16; - static constexpr uint32_t kParameterCountMask = 0xffff; + static constexpr uint32_t kObjectPointerShift = kMaxParameterCountBits; +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) + static constexpr uint64_t kTagAndMarkBitMask = kFreeEntryTag; #elif defined(V8_TARGET_ARCH_32_BIT) static constexpr uintptr_t kParameterCountOffset = kCodeObjectOffset + kSystemPointerSize; static constexpr uint32_t kObjectPointerShift = 0; static constexpr uint32_t kParameterCountMask = 0x0; + static constexpr uint64_t kTagAndMarkBitMask = 0; #else #error "Unsupported Architecture" #endif @@ -140,12 +137,28 @@ struct JSDispatchEntry { // The first word contains the pointer to the (executable) entrypoint. std::atomic<Address> entrypoint_; - // On 64 bit architectures the second word of the entry contains (1) the - // pointer to the code object associated with this entry, (2) the marking bit - // of the entry in the LSB of the object pointer (which must be unused as the - // address must be aligned), and (3) the 16-bit parameter count. The parameter - // count is stored in the lower 16 bits and therefore the pointer is shifted - // to the left. The final format therefore looks as follows: + // On x64, the entry is 32 bytes to support full 57-bit (LA57) pointers. + // Following the entrypoint word, the second word contains the tagged Code + // object pointer, the third word contains the marking bit and 16-bit + // parameter count, and the fourth word is unused padding: + // + // +----------------------------------------------------------+ + // | Bits 63 ... 0 | + // | HeapObject pointer | + // +----------------------+---------------+-------------------+ + // | Bits 63 ... 17 | Bit 16 | Bits 15 ... 0 | + // | Unused | Marking bit | Parameter count | + // +----------------------+---------------+-------------------+ + // | Bits 63 ... 0 | + // | Padding (unused) | + // +----------------------------------------------------------+ + // + // On the other 64 bit architectures the second word of the entry contains (1) + // the pointer to the code object associated with this entry, (2) the marking + // bit of the entry in the LSB of the object pointer (which must be unused as + // the address must be aligned), and (3) the 16-bit parameter count. The + // parameter count is stored in the lower 16 bits and therefore the pointer is + // shifted to the left. The final format therefore looks as follows: // // +----------------------+---------------+-------------------+ // | Bits 63 ... 17 | Bit 16 | Bits 15 ... 0 | @@ -163,16 +176,23 @@ struct JSDispatchEntry { // individual parts and unify with 32 bit. For instance we could try to store // the code pointer in some compressd format, such that it fits into 32 bits. +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + std::atomic<Address> code_object_; + static constexpr Address kMarkingBit = 1 << kMaxParameterCountBits; +#else static constexpr Address kMarkingBit = 1 << kObjectPointerShift; +#endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 std::atomic<Address> encoded_word_; -#ifdef V8_TARGET_ARCH_32_BIT +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + [[maybe_unused]] uint64_t padding_; +#elif defined(V8_TARGET_ARCH_32_BIT) // TODO(olivf): Investigate if we could shrink the entry size on 32bit // platforms to 12 bytes. std::atomic<uint16_t> parameter_count_; // 16 bits of padding std::atomic<uint32_t> next_free_entry_; -#endif // V8_TARGET_ARCH_32_BIT +#endif // defined(V8_TARGET_ARCH_32_BIT) }; static_assert(sizeof(JSDispatchEntry) == kJSDispatchTableEntrySize); diff --git a/deps/v8/src/sandbox/sandbox-malloc.h b/deps/v8/src/sandbox/sandbox-malloc.h index eb396af147b8..84f98d4d89a0 100644 --- a/deps/v8/src/sandbox/sandbox-malloc.h +++ b/deps/v8/src/sandbox/sandbox-malloc.h @@ -24,7 +24,7 @@ namespace internal { // for example generally unsafe to store any pointers in the returned memory. template <typename T> -T* SandboxAlloc() { +T* SandboxAllocArray(size_t num_elements) { // It is generally unsafe to allocate non-trivial objects inside the sandbox, // in particular anything containing pointers. The static_assert is a // best-effort attempt to catch such cases, but it doesn't work for all @@ -33,40 +33,26 @@ T* SandboxAlloc() { static_assert(std::is_trivial_v<T>, "Must only allocate trivial C++ types inside the sandbox"); - size_t size = sizeof(T); + size_t size = base::CheckMul(num_elements, sizeof(T)).ValueOrDie(); #ifdef V8_ENABLE_SANDBOX auto* allocator = IsolateGroup::current()->GetInSandboxAllocator(); - void* raw_memory = allocator->Allocate(size); + void* raw_memory = allocator->AllocateUninitialized(size); #else void* raw_memory = base::Malloc(size); #endif // V8_ENABLE_SANDBOX + if (!raw_memory) { + internal::V8::FatalProcessOutOfMemory(nullptr, "SandboxAllocArray"); + } + memset(raw_memory, 0, size); return static_cast<T*>(raw_memory); } template <typename T> -T* SandboxAllocArray(size_t num_elements) { - // It is generally unsafe to allocate non-trivial objects inside the sandbox, - // in particular anything containing pointers. The static_assert is a - // best-effort attempt to catch such cases, but it doesn't work for all - // unsafe cases, for example raw pointer fields or Address values. - // TODO(427464384): this is a little too strict, e.g. for std::atomic. - static_assert(std::is_trivial_v<T>, - "Must only allocate trivial C++ types inside the sandbox"); - - size_t size = base::CheckMul(num_elements, sizeof(T)).ValueOrDie(); - -#ifdef V8_ENABLE_SANDBOX - auto* allocator = IsolateGroup::current()->GetInSandboxAllocator(); - void* raw_memory = allocator->Allocate(size); -#else - void* raw_memory = base::Malloc(size); -#endif // V8_ENABLE_SANDBOX - - memset(raw_memory, 0, size); - return static_cast<T*>(raw_memory); +T* SandboxAlloc() { + return SandboxAllocArray<T>(1); } inline void SandboxFree(void* ptr) { diff --git a/deps/v8/src/sandbox/sandbox-zero-segment.h b/deps/v8/src/sandbox/sandbox-zero-segment.h new file mode 100644 index 000000000000..ba226c6ffddc --- /dev/null +++ b/deps/v8/src/sandbox/sandbox-zero-segment.h @@ -0,0 +1,65 @@ +// Copyright 2026 the V8 project 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 V8_SANDBOX_SANDBOX_ZERO_SEGMENT_H_ +#define V8_SANDBOX_SANDBOX_ZERO_SEGMENT_H_ + +#ifdef V8_ENABLE_SANDBOX + +#include <algorithm> + +#include "include/v8config.h" +#include "src/common/globals.h" +#include "src/objects/field-index.h" +#include "src/objects/js-objects.h" + +#if V8_ENABLE_WEBASSEMBLY +#include "src/wasm/wasm-objects.h" +#endif // V8_ENABLE_WEBASSEMBLY + +namespace v8::internal { + +// The first 4GB of the process' address space are reserved by the +// platform/allocator as an inaccessible or read-only zero segment to mitigate +// Smi<->HeapObject (and Wasm i31ref<->WasmStruct/WasmCustomMap) confusion bugs +// in which a 32-bit value is treated as a pointer and dereferenced. +inline constexpr size_t kZeroSegmentBaseSize = 4UL * GB; + +// Smi<->HeapObject confusion in JS can lead to property accesses at an offset +// from a Smi value near 4GB: +// - Regular in-object properties are bounded by JSObject::kMaxInstanceSize. +// - Corrupted PropertyDetails/FieldIndex metadata can encode offsets up to +// FieldIndex::kMaxOffset (https://crbug.com/574732380). +inline constexpr size_t kJSMaxInObjectPropertyOffset = + JSObject::kMaxInstanceSize; +inline constexpr size_t kJSMaxCorruptedPropertyOffset = FieldIndex::kMaxOffset; +inline constexpr size_t kJSZeroSegmentPadding = + std::max(kJSMaxInObjectPropertyOffset, kJSMaxCorruptedPropertyOffset); + +#if V8_ENABLE_WEBASSEMBLY +// i31ref<->WasmStruct/WasmCustomMap confusion in Wasm can lead to struct +// field accesses up to WasmCustomMap::kMaxInstanceSize +// (https://crbug.com/558640961). +inline constexpr size_t kWasmZeroSegmentPadding = + std::max(WasmStruct::kMaxInstanceSize, WasmCustomMap::kMaxInstanceSize); +#else +inline constexpr size_t kWasmZeroSegmentPadding = 0; +#endif // V8_ENABLE_WEBASSEMBLY + +inline constexpr size_t kZeroSegmentPadding = + std::max(kJSZeroSegmentPadding, kWasmZeroSegmentPadding); + +inline constexpr size_t kMinZeroSegmentSize = + kZeroSegmentBaseSize + kZeroSegmentPadding; + +// PartitionAlloc reserves 4GB + 1MB by default +// (user_space_zero_segment_size_mb = 4097). +static_assert(kZeroSegmentPadding <= 1 * MB); +static_assert(kMinZeroSegmentSize <= size_t{4097} * MB); + +} // namespace v8::internal + +#endif // V8_ENABLE_SANDBOX + +#endif // V8_SANDBOX_SANDBOX_ZERO_SEGMENT_H_ diff --git a/deps/v8/src/sandbox/sandbox.cc b/deps/v8/src/sandbox/sandbox.cc index 894029b6e923..717b7213ffb0 100644 --- a/deps/v8/src/sandbox/sandbox.cc +++ b/deps/v8/src/sandbox/sandbox.cc @@ -15,13 +15,15 @@ #include "src/base/emulated-virtual-address-subspace.h" #include "src/base/lazy-instance.h" #include "src/base/macros.h" +#include "src/base/platform/platform.h" #include "src/base/sys-info.h" #include "src/base/utils/random-number-generator.h" #include "src/base/virtual-address-space-page-allocator.h" #include "src/base/virtual-address-space.h" #include "src/flags/flags.h" -#include "src/objects/js-objects.h" +#include "src/sandbox/code-entrypoint-tag.h" #include "src/sandbox/hardware-support.h" +#include "src/sandbox/sandbox-zero-segment.h" #include "src/sandbox/sandboxed-pointer.h" #include "src/sandbox/testing.h" #include "src/utils/allocation.h" @@ -413,8 +415,10 @@ void Sandbox::Initialize(v8::Platform* platform, v8::VirtualAddressSpace* vas) { "Failed to reserve the virtual address space for the V8 sandbox"); } + CHECK(IsTaggingMaskCompatible(kCodeEntrypointTagMask)); + if (v8_flags.sandbox_prohibit_insecure_mode) { - if (is_partially_reserved() || !smi_address_range_is_inaccessible()) { + if (is_partially_reserved() || !has_zero_segment()) { V8::FatalProcessOutOfMemory( nullptr, "Failed to initialize sandbox in a secure mode which is required by " @@ -582,15 +586,10 @@ bool Sandbox::InitializeAsPartiallyReservedSandbox(v8::Platform* platform, } void Sandbox::FinishInitialization(v8::Platform* platform) { - // Check whether the first 4GB of the process' address space are reserved. - // This mitigates Smi<->HeapObject confusion bugs in which we end up treating - // a Smi value as a pointer. - // Make the guard region extend a little past the first 4GB to also catch - // accesses to in-object properties which are bounded by the JSObject - // instance size. - static_assert(kSmiAddressRangePadding > JSObject::kMaxInstanceSize); - constexpr Address kRangeEnd = kSmiAddressRange + kSmiAddressRangePadding; - smi_address_range_reserved_ = platform->GetZeroSegmentSize() >= kRangeEnd; + // Check whether the first 4GB of the process' address space (plus padding for + // JS/Wasm object field accesses) are reserved. This mitigates Smi/i31ref + // confusion bugs in which we end up treating a 32-bit value as a pointer. + has_zero_segment_ = platform->GetZeroSegmentSize() >= kMinZeroSegmentSize; #ifdef V8_ENABLE_MEMORY_CORRUPTION_API // We do this even for the case of partially-reserved sandbox because, while // being an unsafe setup, tests and fuzzers shouldn't report crashes in this @@ -649,7 +648,7 @@ void Sandbox::TearDown() { reservation_base_ = kNullAddress; reservation_size_ = 0; initialized_ = false; - smi_address_range_reserved_ = false; + has_zero_segment_ = false; constants_.Reset(); } } diff --git a/deps/v8/src/sandbox/sandbox.h b/deps/v8/src/sandbox/sandbox.h index a5f97a979423..860dc2be54fd 100644 --- a/deps/v8/src/sandbox/sandbox.h +++ b/deps/v8/src/sandbox/sandbox.h @@ -9,6 +9,7 @@ #include "include/v8-platform.h" #include "include/v8config.h" #include "src/base/bounds.h" +#include "src/base/platform/platform.h" #include "src/common/globals.h" #if V8_ENABLE_WEBASSEMBLY @@ -74,18 +75,15 @@ class V8_EXPORT_PRIVATE Sandbox { // The name for the virtual address space reservation backing the sandbox. static constexpr const char* kSandboxAddressSpaceName = "v8-sandbox"; - static constexpr size_t kSmiAddressRange = 4UL * GB; - - // We assume that the Smi<->HeapObject corruption can lead to accesses of - // in-object properties. We add some padding to also catch these kinds of - // accesses. - static constexpr size_t kSmiAddressRangePadding = 4 * KB; - // A heuristic used by the sandbox crash filter to identify crashes on // unaddressable accesses (e.g. on ARM64). Note that this is only a testing // heuristic and does not reflect the actual virtual address space size, // which is determined dynamically during sandbox initialization. +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 + static constexpr int kMaxVirtualAddressBitsForCrashFilter = 57; +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) static constexpr int kMaxVirtualAddressBitsForCrashFilter = 48; +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) /** * Initializes this sandbox. @@ -133,9 +131,7 @@ class V8_EXPORT_PRIVATE Sandbox { * address space. This is useful to mitigate Smi<->HeapObject confusion * issues, in which a (32-bit) Smi is treated as a pointer and dereferenced. */ - bool smi_address_range_is_inaccessible() const { - return smi_address_range_reserved_; - } + bool has_zero_segment() const { return has_zero_segment_; } /** * The base address of the sandbox. @@ -358,7 +354,7 @@ class V8_EXPORT_PRIVATE Sandbox { // platform/allocator as an inaccessible zero segment. This for example // mitigates Smi<->HeapObject confusion bugs in which we treat a Smi value as // a pointer and access it. - bool smi_address_range_reserved_ = false; + bool has_zero_segment_ = false; #ifdef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES thread_local static Sandbox* current_; @@ -400,6 +396,13 @@ V8_INLINE void* EmptyBackingStoreBuffer() { #endif } +// Hardware address tagging features on x64 (such as Intel LAM or AMD UAI) +// mask out upper pointer bits during memory accesses. Returns true if the OS +// untag mask does not clash with the given tagging mask. +V8_INLINE bool IsTaggingMaskCompatible(uint64_t mask) { + return (base::OS::GetAddressUntagMask() & mask) == mask; +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/sandbox/tagged-payload.h b/deps/v8/src/sandbox/tagged-payload.h index ac0d39c16188..75b0158d0dea 100644 --- a/deps/v8/src/sandbox/tagged-payload.h +++ b/deps/v8/src/sandbox/tagged-payload.h @@ -8,7 +8,7 @@ #include "include/v8-sandbox.h" #include "src/common/globals.h" #include "src/sandbox/check.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/trusted-pointer-tag.h" namespace v8 { namespace internal { @@ -28,6 +28,7 @@ struct TaggedPayload { static constexpr uint64_t kPayloadMask = PayloadTaggingScheme::kPayloadMask; static constexpr uint64_t kTagMask = PayloadTaggingScheme::kTagMask; static constexpr uint64_t kMarkBit = PayloadTaggingScheme::kMarkBit; + static constexpr uint64_t kTagAndMarkBitMask = kTagMask | kMarkBit; static constexpr TagType kFreeEntryTag = PayloadTaggingScheme::kFreeEntryTag; static constexpr TagType kEvacuationEntryTag = PayloadTaggingScheme::kEvacuationEntryTag; diff --git a/deps/v8/src/sandbox/testing.cc b/deps/v8/src/sandbox/testing.cc index c459abf81560..67a065d2a2f9 100644 --- a/deps/v8/src/sandbox/testing.cc +++ b/deps/v8/src/sandbox/testing.cc @@ -25,11 +25,14 @@ #include "src/objects/fixed-array.h" #include "src/objects/fixed-primitive-array-inl.h" #include "src/objects/foreign.h" +#include "src/objects/heap-number.h" #include "src/objects/instance-type.h" #include "src/objects/js-array-buffer.h" #include "src/objects/js-objects.h" +#include "src/objects/literal-objects.h" #include "src/objects/tagged-field-inl.h" #include "src/objects/templates.h" +#include "src/sandbox/sandbox-zero-segment.h" #include "src/sandbox/sandbox.h" #include "src/sandbox/trusted-pointer-table-inl.h" @@ -40,6 +43,8 @@ #ifdef V8_OS_LINUX #include <signal.h> #include <sys/mman.h> +// sys/mman.h defines MAP_TYPE, which conflicts with V8's MAP_TYPE InstanceType. +#undef MAP_TYPE #include <sys/ucontext.h> #include <unistd.h> @@ -505,8 +510,7 @@ void SandboxUnpublishTrustedHandle( return; } - IndirectPointerHandle handle = - static_cast<IndirectPointerHandle>(handle_value); + TrustedPointerHandle handle = static_cast<TrustedPointerHandle>(handle_value); i_isolate->trusted_pointer_table().Unpublish(handle); } @@ -1096,6 +1100,12 @@ struct sigaction g_old_handlers[NSIG]; constexpr int kSignalsToHandle[] = {SIGABRT, SIGTRAP, SIGBUS, SIGILL, SIGSEGV}; std::atomic<bool> g_is_sandbox_violation{false}; + +void ReportSandboxViolation() { + if (g_is_sandbox_violation.exchange(true)) return; + PrintToStderr("\n## V8 sandbox violation detected!\n\n"); +} + #ifdef V8_USE_ADDRESS_SANITIZER bool g_is_asan_fault_harmless = false; #endif @@ -1249,8 +1259,7 @@ void CrashFilter(int signal, siginfo_t* info, void* context) { "Caught harmless memory access violation (nullptr dereference)."); } - if (faultaddr < - (Sandbox::kSmiAddressRange + Sandbox::kSmiAddressRangePadding)) { + if (faultaddr < kMinZeroSegmentSize) { // Currently we also ignore access violations in the first 4GB of the // virtual address space. See crbug.com/1470641 for more details. // We need to add some "padding" to the 4GB since we might access a @@ -1328,9 +1337,7 @@ void CrashFilter(int signal, siginfo_t* info, void* context) { } // If we get here, we've detected a sandbox violation. - PrintToStderr("\n## V8 sandbox violation detected!\n\n"); - - g_is_sandbox_violation = true; + ReportSandboxViolation(); if (access_type == MemoryAccessType::kRead) { PrintToStderr( @@ -1428,7 +1435,7 @@ extern "C" V8_EXPORT_PRIVATE void __asan_on_error() { if (!__asan_report_present()) { // Should not occur normally, but falling back to treating this as an error // as defense-in-depth. - g_is_sandbox_violation = true; + ReportSandboxViolation(); return; } @@ -1445,7 +1452,7 @@ extern "C" V8_EXPORT_PRIVATE void __asan_on_error() { if (IsHarmlessASanFault(description, faultaddr, access_type)) { g_is_asan_fault_harmless = true; } else { - g_is_sandbox_violation = true; + ReportSandboxViolation(); } } #endif // V8_USE_ADDRESS_SANITIZER @@ -1473,7 +1480,7 @@ void SanitizerFaultHandler() { // In case of a sanitizer issue we opt for conservatively reporting a sandbox // violation that needs to be investigated. - PrintToStderr("\n## V8 sandbox violation detected!\n\n"); + ReportSandboxViolation(); } #endif // V8_USE_ANY_SANITIZER @@ -1557,6 +1564,7 @@ SandboxTesting::InstanceTypeMap& SandboxTesting::GetInstanceTypeMap() { types["JS_BOUND_FUNCTION_TYPE"] = JS_BOUND_FUNCTION_TYPE; types["JS_ARRAY_TYPE"] = JS_ARRAY_TYPE; types["JS_ARRAY_BUFFER_TYPE"] = JS_ARRAY_BUFFER_TYPE; + types["HEAP_NUMBER_TYPE"] = HEAP_NUMBER_TYPE; types["FOREIGN_TYPE"] = FOREIGN_TYPE; types["JS_REG_EXP_TYPE"] = JS_REG_EXP_TYPE; types["JS_TYPED_ARRAY_TYPE"] = JS_TYPED_ARRAY_TYPE; @@ -1579,14 +1587,18 @@ SandboxTesting::InstanceTypeMap& SandboxTesting::GetInstanceTypeMap() { types["WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE"] = WEAK_HOMOMORPHIC_FIXED_ARRAY_TYPE; types["NATIVE_CONTEXT_TYPE"] = NATIVE_CONTEXT_TYPE; + types["MAP_TYPE"] = MAP_TYPE; + types["CLASS_BOILERPLATE_TYPE"] = CLASS_BOILERPLATE_TYPE; #ifdef V8_ENABLE_WEBASSEMBLY - types["WASM_MODULE_OBJECT_TYPE"] = WASM_MODULE_OBJECT_TYPE; - types["WASM_INSTANCE_OBJECT_TYPE"] = WASM_INSTANCE_OBJECT_TYPE; types["WASM_FUNC_REF_TYPE"] = WASM_FUNC_REF_TYPE; - types["WASM_TABLE_OBJECT_TYPE"] = WASM_TABLE_OBJECT_TYPE; + types["WASM_GLOBAL_OBJECT_TYPE"] = WASM_GLOBAL_OBJECT_TYPE; + types["WASM_INSTANCE_OBJECT_TYPE"] = WASM_INSTANCE_OBJECT_TYPE; + types["WASM_MEMORY_OBJECT_TYPE"] = WASM_MEMORY_OBJECT_TYPE; + types["WASM_MODULE_OBJECT_TYPE"] = WASM_MODULE_OBJECT_TYPE; types["WASM_RESUME_DATA"] = WASM_RESUME_DATA_TYPE; + types["WASM_STACK_OBJECT_TYPE"] = WASM_STACK_OBJECT_TYPE; + types["WASM_TABLE_OBJECT_TYPE"] = WASM_TABLE_OBJECT_TYPE; types["WASM_TAG_OBJECT_TYPE"] = WASM_TAG_OBJECT_TYPE; - types["WASM_GLOBAL_OBJECT_TYPE"] = WASM_GLOBAL_OBJECT_TYPE; #endif // V8_ENABLE_WEBASSEMBLY } return types; @@ -1601,6 +1613,8 @@ SandboxTesting::FieldOffsetMap& SandboxTesting::GetFieldOffsetMap() { auto& fields = *g_known_fields.get(); bool is_initialized = fields.size() != 0; if (!is_initialized) { + fields[MAP_TYPE]["instance_type"] = offsetof(Map, instance_type_); + fields[HEAP_NUMBER_TYPE]["value"] = offsetof(HeapNumber, value_); fields[FIXED_DOUBLE_ARRAY_TYPE]["length"] = offsetof(FixedDoubleArray, length_); fields[FIXED_DOUBLE_ARRAY_TYPE]["data"] = @@ -1656,6 +1670,8 @@ SandboxTesting::FieldOffsetMap& SandboxTesting::GetFieldOffsetMap() { offsetof(SharedFunctionInfo, untrusted_function_data_); fields[SHARED_FUNCTION_INFO_TYPE]["script"] = offsetof(SharedFunctionInfo, script_); + fields[SHARED_FUNCTION_INFO_TYPE]["unique_id"] = + offsetof(SharedFunctionInfo, unique_id_); fields[SCRIPT_TYPE]["wasm_managed_native_module"] = offsetof(Script, eval_from_position_); fields[JS_PROMISE_TYPE]["reactions_or_result"] = @@ -1674,40 +1690,49 @@ SandboxTesting::FieldOffsetMap& SandboxTesting::GetFieldOffsetMap() { offsetof(WeakFixedArray, length_); fields[NATIVE_CONTEXT_TYPE]["microtask_queue"] = NativeContext::kMicrotaskQueueOffset; + fields[CLASS_BOILERPLATE_TYPE]["instance_properties_template"] = + offsetof(ClassBoilerplate, instance_properties_template_); #ifdef V8_INTL_SUPPORT fields[JS_SEGMENTS_TYPE]["icu_iterator_with_text"] = offsetof(JSSegments, icu_iterator_with_text_); #endif // V8_INTL_SUPPORT #ifdef V8_ENABLE_WEBASSEMBLY - fields[WASM_MODULE_OBJECT_TYPE]["managed_native_module"] = - offsetof(WasmModuleObject, managed_native_module_); - fields[WASM_MODULE_OBJECT_TYPE]["script"] = - offsetof(WasmModuleObject, script_); + fields[WASM_FUNC_REF_TYPE]["trusted_internal"] = + offsetof(WasmFuncRef, trusted_internal_); + fields[WASM_GLOBAL_OBJECT_TYPE]["buffer"] = + offsetof(WasmGlobalObject, buffer_); + fields[WASM_GLOBAL_OBJECT_TYPE]["raw_type"] = + offsetof(WasmGlobalObject, raw_type_); fields[WASM_INSTANCE_OBJECT_TYPE]["module_object"] = offsetof(WasmInstanceObject, module_object_); fields[WASM_INSTANCE_OBJECT_TYPE]["trusted_data"] = offsetof(WasmInstanceObject, trusted_data_); - fields[WASM_FUNC_REF_TYPE]["trusted_internal"] = - offsetof(WasmFuncRef, trusted_internal_); - fields[WASM_TABLE_OBJECT_TYPE]["entries"] = - offsetof(WasmTableObject, entries_); + fields[WASM_MEMORY_OBJECT_TYPE]["array_buffer"] = + offsetof(WasmMemoryObject, array_buffer_); + fields[WASM_MEMORY_OBJECT_TYPE]["instances"] = + offsetof(WasmMemoryObject, instances_); + fields[WASM_MEMORY_OBJECT_TYPE]["managed_backing_store"] = + offsetof(WasmMemoryObject, managed_backing_store_); + fields[WASM_MODULE_OBJECT_TYPE]["managed_native_module"] = + offsetof(WasmModuleObject, managed_native_module_); + fields[WASM_MODULE_OBJECT_TYPE]["script"] = + offsetof(WasmModuleObject, script_); + fields[WASM_RESUME_DATA_TYPE]["trusted_suspender"] = + offsetof(WasmResumeData, trusted_suspender_); + fields[WASM_STACK_OBJECT_TYPE]["stack"] = offsetof(WasmStackObject, stack_); fields[WASM_TABLE_OBJECT_TYPE]["current_length"] = offsetof(WasmTableObject, current_length_); + fields[WASM_TABLE_OBJECT_TYPE]["entries"] = + offsetof(WasmTableObject, entries_); fields[WASM_TABLE_OBJECT_TYPE]["maximum_length"] = offsetof(WasmTableObject, maximum_length_); fields[WASM_TABLE_OBJECT_TYPE]["raw_type"] = offsetof(WasmTableObject, raw_type_); - fields[WASM_TABLE_OBJECT_TYPE]["trusted_dispatch_table"] = - offsetof(WasmTableObject, trusted_dispatch_table_); fields[WASM_TABLE_OBJECT_TYPE]["trusted_data"] = offsetof(WasmTableObject, trusted_data_); + fields[WASM_TABLE_OBJECT_TYPE]["trusted_dispatch_table"] = + offsetof(WasmTableObject, trusted_dispatch_table_); fields[WASM_TAG_OBJECT_TYPE]["tag"] = offsetof(WasmTagObject, tag_); - fields[WASM_GLOBAL_OBJECT_TYPE]["buffer"] = - offsetof(WasmGlobalObject, buffer_); - fields[WASM_GLOBAL_OBJECT_TYPE]["raw_type"] = - offsetof(WasmGlobalObject, raw_type_); - fields[WASM_RESUME_DATA_TYPE]["trusted_suspender"] = - offsetof(WasmResumeData, trusted_suspender_); #endif // V8_ENABLE_WEBASSEMBLY } return fields; diff --git a/deps/v8/src/sandbox/trusted-pointer-inl.h b/deps/v8/src/sandbox/trusted-pointer-inl.h new file mode 100644 index 000000000000..5fa97b33db18 --- /dev/null +++ b/deps/v8/src/sandbox/trusted-pointer-inl.h @@ -0,0 +1,337 @@ +// Copyright 2023 the V8 project 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 V8_SANDBOX_TRUSTED_POINTER_INL_H_ +#define V8_SANDBOX_TRUSTED_POINTER_INL_H_ + +#include "src/sandbox/trusted-pointer.h" +// Include the non-inl header before the rest of the headers. + +#include <atomic> + +#include "include/v8-internal.h" +#include "src/base/atomic-utils.h" +#include "src/heap/heap-write-barrier-inl.h" +#include "src/heap/heap-write-barrier.h" +#include "src/objects/heap-object.h" +#include "src/objects/tagged-field-inl.h" +#include "src/objects/trusted-object.h" +#include "src/sandbox/isolate-inl.h" +#include "src/sandbox/trusted-pointer-table-inl.h" + +namespace v8 { +namespace internal { + +V8_INLINE void InitSelfTrustedPointerField( + Address field_address, IsolateForSandbox isolate, Tagged<HeapObject> host, + TrustedPointerTag tag, + TrustedPointerPublishingScope* opt_publishing_scope) { +#ifdef V8_ENABLE_SANDBOX + DCHECK_NE(tag, kTrustedPointerNullTag); + + TrustedPointerTable::Space* space = + isolate.GetTrustedPointerTableSpaceFor(tag, host.address()); + TrustedPointerHandle handle = + isolate.GetTrustedPointerTableFor(tag).AllocateAndInitializeEntry( + space, host.ptr(), tag, opt_publishing_scope); + + // Use a Release_Store to ensure that the store of the pointer into the table + // is not reordered after the store of the handle. Otherwise, other threads + // may access an uninitialized table entry and crash. + auto location = reinterpret_cast<TrustedPointerHandle*>(field_address); + base::AsAtomic32::Release_Store(location, handle); +#else + UNREACHABLE(); +#endif +} + +#ifdef V8_ENABLE_SANDBOX +template <TrustedPointerTagRange tag_range> +V8_INLINE Tagged<Object> ResolveTrustedPointerHandle( + TrustedPointerHandle handle, IsolateForSandbox isolate) { + const TrustedPointerTable& table = + isolate.GetTrustedPointerTableFor(tag_range); + return Tagged<Object>(table.Get(handle, tag_range)); +} + +template <TrustedPointerTagRange tag_range> +V8_INLINE Tagged<Object> ReadTrustedPointerHandle(TrustedPointerHandle handle, + IsolateForSandbox isolate) { + return ResolveTrustedPointerHandle<tag_range>(handle, isolate); +} + +#endif // V8_ENABLE_SANDBOX + +template <TrustedPointerTagRange tag_range> +V8_INLINE Tagged<Object> ReadTrustedPointerField(Address field_address, + IsolateForSandbox isolate, + AcquireLoadTag) { +#ifdef V8_ENABLE_SANDBOX + // Load the trusted pointer handle from the object. + // Technically, we could use memory_order_consume here as the loads are + // dependent, but that appears to be deprecated in favor of acquire ordering. + auto location = reinterpret_cast<TrustedPointerHandle*>(field_address); + TrustedPointerHandle handle = base::AsAtomic32::Acquire_Load(location); + if (handle == kNullTrustedPointerHandle) return Smi::zero(); + return ReadTrustedPointerHandle<tag_range>(handle, isolate); +#else + return Tagged<Object>(*reinterpret_cast<Address*>(field_address)); +#endif +} + +template <TrustedPointerTagRange tag_range> +V8_INLINE void WriteTrustedPointerField(Address field_address, + Tagged<ExposedTrustedObject> value, + ReleaseStoreTag) { +#ifdef V8_ENABLE_SANDBOX + static_assert(!tag_range.IsEmpty()); + TrustedPointerHandle handle = value->self_trusted_pointer_handle(); + DCHECK_NE(handle, kNullTrustedPointerHandle); + auto location = reinterpret_cast<TrustedPointerHandle*>(field_address); + base::AsAtomic32::Release_Store(location, handle); +#else + UNREACHABLE(); +#endif +} + +template <TrustedPointerTagRange tag_range> +Tagged<TrustedTypeFor<tag_range>> TrustedPointerField::ReadTrustedPointerField( + Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate) { + // Currently, trusted pointer loads always use acquire semantics as the + // under-the-hood indirect pointer loads use acquire loads anyway. + return ReadTrustedPointerField<tag_range>(host, offset, isolate, + kAcquireLoad); +} + +template <TrustedPointerTagRange tag_range> +Tagged<TrustedTypeFor<tag_range>> TrustedPointerField::ReadTrustedPointerField( + Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate, + AcquireLoadTag acquire_load) { + Tagged<Object> object = ReadMaybeEmptyTrustedPointerField<tag_range>( + host, offset, isolate, acquire_load); + using ReturnType = TrustedTypeFor<tag_range>; + return TrustedCast<ReturnType>(object); +} + +template <TrustedPointerTagRange tag_range> +Tagged<Union<Smi, TrustedTypeFor<tag_range>>> +TrustedPointerField::ReadMaybeEmptyTrustedPointerField( + Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate, + AcquireLoadTag) { +#ifdef V8_ENABLE_SANDBOX + // Reading a TrustedPointer field is just a ReadTrustedPointerField with the + // proper tag. + Address field_address = host->ptr() + offset - kHeapObjectTag; + Tagged<Object> object = i::ReadTrustedPointerField<tag_range>( + field_address, isolate, kAcquireLoad); +#else + Tagged<Object> object = + TaggedField<Object>::Acquire_Load(host, static_cast<int>(offset)); +#endif + return TrustedCast<Union<Smi, TrustedTypeFor<tag_range>>>(object); +} + +template <TrustedPointerTagRange tag_range> +void TrustedPointerField::WriteTrustedPointerField( + Tagged<HeapObject> host, size_t offset, + Tagged<ExposedTrustedObject> value) { +#ifdef V8_ENABLE_SANDBOX + Address field_address = host->ptr() + offset - kHeapObjectTag; + i::WriteTrustedPointerField<tag_range>(field_address, value, kReleaseStore); +#else + TaggedField<ExposedTrustedObject>::Release_Store( + host, static_cast<int>(offset), value); +#endif +} + +bool TrustedPointerField::IsTrustedPointerFieldEmpty(Tagged<HeapObject> host, + size_t offset) { +#ifdef V8_ENABLE_SANDBOX + Address field_address = host->ptr() + offset - kHeapObjectTag; + TrustedPointerHandle handle = base::AsAtomic32::Acquire_Load( + reinterpret_cast<TrustedPointerHandle*>(field_address)); + return handle == kNullTrustedPointerHandle; +#else + return IsSmi( + TaggedField<Object>::Acquire_Load(host, static_cast<int>(offset))); +#endif +} + +template <typename IsolateT> +bool TrustedPointerField::IsTrustedPointerFieldUnpublished( + Tagged<HeapObject> host, size_t offset, TrustedPointerTagRange tag_range, + IsolateT isolate) { +#ifdef V8_ENABLE_SANDBOX + TrustedPointerHandle handle = + base::AsAtomic32::Acquire_Load(reinterpret_cast<TrustedPointerHandle*>( + host->ptr() + offset - kHeapObjectTag)); + if (handle == kNullTrustedPointerHandle) return false; + const TrustedPointerTable& table = + isolate.GetTrustedPointerTableFor(tag_range); + return table.IsUnpublished(handle); +#else + return false; +#endif +} + +void TrustedPointerField::ClearTrustedPointerField(Tagged<HeapObject> host, + size_t offset) { + ClearTrustedPointerField(host, offset, kReleaseStore); +} + +void TrustedPointerField::ClearTrustedPointerField(Tagged<HeapObject> host, + size_t offset, + ReleaseStoreTag) { +#ifdef V8_ENABLE_SANDBOX + Address field_address = host->ptr() + offset - kHeapObjectTag; + base::AsAtomic32::Release_Store( + reinterpret_cast<TrustedPointerHandle*>(field_address), + kNullTrustedPointerHandle); +#else + TaggedField<Smi>::Release_Store(host, static_cast<int>(offset), Smi::zero()); +#endif +} + +// Currently, trusted pointer loads/stores always use acquire/release +// semantics as the under-the-hood indirect pointer loads/stores use +// acquire/release loads/stores anyway. +template <typename T, TrustedPointerTagRange kTagRange> +TrustedPointerMember<T, kTagRange>::TrustedPointerMember( + const AllocationWitness& witness, Tagged<T> value) + : TrustedPointerMember(witness, value, witness.write_barrier_mode()) {} + +template <typename T, TrustedPointerTagRange kTagRange> +TrustedPointerMember<T, kTagRange>::TrustedPointerMember( + const AllocationWitness& witness, Tagged<T> value, WriteBarrierMode mode) { + store(witness.object(), value, mode); +} +template <typename T, TrustedPointerTagRange kTagRange> +TrustedPointerMember<T, kTagRange>::TrustedPointerMember( + const AllocationWitness& witness, Tagged<UnionOf<T, Undefined>> maybe_value) + : TrustedPointerMember(witness, maybe_value, witness.write_barrier_mode()) { +} + +template <typename T, TrustedPointerTagRange kTagRange> +TrustedPointerMember<T, kTagRange>::TrustedPointerMember( + const AllocationWitness& witness, Tagged<UnionOf<T, Undefined>> maybe_value, + WriteBarrierMode mode) { + if (Tagged<T> value; TryCast(maybe_value, &value)) { + store(witness.object(), value, mode); + } else { + DCHECK(IsUndefined(maybe_value)); + clear(witness.object()); + } +} +template <typename T, TrustedPointerTagRange kTagRange> +Tagged<T> TrustedPointerMember<T, kTagRange>::load( + IsolateForSandbox isolate) const { + return Acquire_Load(isolate); +} +template <typename T, TrustedPointerTagRange kTagRange> +Tagged<Object> TrustedPointerMember<T, kTagRange>::load_maybe_empty( + IsolateForSandbox isolate) const { + return Acquire_Load_maybe_empty(isolate); +} +template <typename T, TrustedPointerTagRange kTagRange> +void TrustedPointerMember<T, kTagRange>::store(HeapObject* host, + Tagged<T> value, + WriteBarrierMode mode) { + Release_Store(host, value, mode); +} +template <typename T, TrustedPointerTagRange kTagRange> +void TrustedPointerMember<T, kTagRange>::store_no_write_barrier( + HeapObject* host, Tagged<T> value) { + Release_Store_no_write_barrier(host, value); +} + +template <typename T, TrustedPointerTagRange kTagRange> +Tagged<T> TrustedPointerMember<T, kTagRange>::Acquire_Load( + IsolateForSandbox isolate) const { +#ifdef V8_ENABLE_SANDBOX + return TrustedCast<T>(ReadTrustedPointerHandle<kTagRange>( + handle_.load(std::memory_order::acquire), isolate)); +#else + return Base::Acquire_Load(); +#endif +} + +template <typename T, TrustedPointerTagRange kTagRange> +Tagged<Object> TrustedPointerMember<T, kTagRange>::Acquire_Load_maybe_empty( + IsolateForSandbox isolate) const { +#ifdef V8_ENABLE_SANDBOX + TrustedPointerHandle handle = handle_.load(std::memory_order::acquire); + if (handle == kNullTrustedPointerHandle) return Smi::zero(); + return ReadTrustedPointerHandle<kTagRange>(handle, isolate); +#else + return Base::Acquire_Load(); +#endif +} + +template <typename T, TrustedPointerTagRange kTagRange> +void TrustedPointerMember<T, kTagRange>::Release_Store(HeapObject* host, + Tagged<T> value, + WriteBarrierMode mode) { +#ifdef V8_ENABLE_SANDBOX + handle_.store( + Cast<ExposedTrustedObject>(value)->self_trusted_pointer_handle(), + std::memory_order_release); + WriteBarrier::ForTrustedPointer(host, this, value, mode); +#else + Base::Release_Store(host, value, mode); +#endif +} + +template <typename T, TrustedPointerTagRange kTagRange> +void TrustedPointerMember<T, kTagRange>::Release_Store_no_write_barrier( + HeapObject* host, Tagged<T> value) { +#ifdef V8_ENABLE_SANDBOX + store(host, value, SKIP_WRITE_BARRIER); +#else + Base::Release_Store_no_write_barrier(value); +#endif +} + +template <typename T, TrustedPointerTagRange kTagRange> +bool TrustedPointerMember<T, kTagRange>::is_empty() const { +#ifdef V8_ENABLE_SANDBOX + return handle_.load(std::memory_order_acquire) == kNullTrustedPointerHandle; +#else + return Base::Acquire_Load().is_null(); +#endif +} + +template <typename T, TrustedPointerTagRange kTagRange> +bool TrustedPointerMember<T, kTagRange>::is_unpublished( + IsolateForSandbox isolate) const { +#ifdef V8_ENABLE_SANDBOX + TrustedPointerHandle handle = handle_.load(std::memory_order_acquire); + if (handle == kNullTrustedPointerHandle) return false; + const TrustedPointerTable& table = + isolate.GetTrustedPointerTableFor(kTagRange); + return table.IsUnpublished(handle); +#else + return false; +#endif +} + +template <typename T, TrustedPointerTagRange kTagRange> +void TrustedPointerMember<T, kTagRange>::clear(HeapObject* host) { +#ifdef V8_ENABLE_SANDBOX + handle_.store(kNullTrustedPointerHandle, std::memory_order_release); +#else + Base::Release_Store_no_write_barrier(Tagged<T>()); +#endif +} + +#ifdef V8_ENABLE_SANDBOX +template <typename T, TrustedPointerTagRange kTagRange> +Address TrustedPointerMember<T, kTagRange>::storage_address() const { + return reinterpret_cast<Address>(&handle_); +} +#endif + +} // namespace internal +} // namespace v8 + +#endif // V8_SANDBOX_TRUSTED_POINTER_INL_H_ diff --git a/deps/v8/src/sandbox/trusted-pointer-table-inl.h b/deps/v8/src/sandbox/trusted-pointer-table-inl.h index 410c3c940827..19fb4eeb59ed 100644 --- a/deps/v8/src/sandbox/trusted-pointer-table-inl.h +++ b/deps/v8/src/sandbox/trusted-pointer-table-inl.h @@ -18,7 +18,7 @@ namespace v8 { namespace internal { void TrustedPointerTableEntry::MakeTrustedPointerEntry(Address pointer, - IndirectPointerTag tag, + TrustedPointerTag tag, bool mark_as_alive) { auto payload = Payload(pointer, tag); if (mark_as_alive) payload.SetMarkBit(); @@ -26,23 +26,23 @@ void TrustedPointerTableEntry::MakeTrustedPointerEntry(Address pointer, } void TrustedPointerTableEntry::MakeFreelistEntry(uint32_t next_entry_index) { - auto payload = Payload(next_entry_index, kIndirectPointerFreeEntryTag); + auto payload = Payload(next_entry_index, kTrustedPointerFreeEntryTag); payload_.store(payload, std::memory_order_relaxed); } void TrustedPointerTableEntry::MakeZappedEntry() { - auto payload = Payload(kNullAddress, kIndirectPointerZappedEntryTag); + auto payload = Payload(kNullAddress, kTrustedPointerZappedEntryTag); payload_.store(payload, std::memory_order_relaxed); } Address TrustedPointerTableEntry::GetPointer( - IndirectPointerTagRange tag_range) const { + TrustedPointerTagRange tag_range) const { DCHECK(!IsFreelistEntry()); return payload_.load(std::memory_order_acquire).Untag(tag_range); } void TrustedPointerTableEntry::SetPointer(Address pointer, - IndirectPointerTag tag) { + TrustedPointerTag tag) { DCHECK(!IsFreelistEntry()); // Currently, this method is only used when the mark bit is unset. If this // ever changes, we'd need to check the marking state of the old entry and @@ -54,22 +54,22 @@ void TrustedPointerTableEntry::SetPointer(Address pointer, } bool TrustedPointerTableEntry::HasPointer( - IndirectPointerTagRange tag_range) const { + TrustedPointerTagRange tag_range) const { auto payload = payload_.load(std::memory_order_acquire); if (!payload.ContainsPointer()) return false; return payload.IsTaggedWithTagIn(tag_range); } Address TrustedPointerTableEntry::GetMaybeUnpublished( - IndirectPointerTagRange tag_range) const { + TrustedPointerTagRange tag_range) const { auto payload = payload_.load(std::memory_order_acquire); - if (payload.IsTaggedWithTagIn(kUnpublishedIndirectPointerTag)) { - return payload.Untag(kUnpublishedIndirectPointerTag); + if (payload.IsTaggedWithTagIn(kUnpublishedTrustedPointerTag)) { + return payload.Untag(kUnpublishedTrustedPointerTag); } return payload.Untag(tag_range); } -IndirectPointerTag TrustedPointerTableEntry::GetTag() const { +TrustedPointerTag TrustedPointerTableEntry::GetTag() const { return payload_.load(std::memory_order_relaxed).ExtractTag(); } @@ -78,17 +78,17 @@ void TrustedPointerTableEntry::Unpublish() { auto new_payload = old_payload; do { new_payload = old_payload; - new_payload.SetTag(kUnpublishedIndirectPointerTag); + new_payload.SetTag(kUnpublishedTrustedPointerTag); } while (!payload_.compare_exchange_weak(old_payload, new_payload, std::memory_order_release, std::memory_order_relaxed)); } -void TrustedPointerTableEntry::Publish(IndirectPointerTag tag) { +void TrustedPointerTableEntry::Publish(TrustedPointerTag tag) { auto old_payload = payload_.load(std::memory_order_relaxed); auto new_payload = old_payload; do { - CHECK(old_payload.IsTaggedWith(kUnpublishedIndirectPointerTag)); + CHECK(old_payload.IsTaggedWith(kUnpublishedTrustedPointerTag)); new_payload = old_payload; new_payload.SetTag(tag); } while (!payload_.compare_exchange_weak(old_payload, new_payload, @@ -130,21 +130,21 @@ bool TrustedPointerTableEntry::IsMarked() const { } Address TrustedPointerTable::Get(TrustedPointerHandle handle, - IndirectPointerTagRange tag_range) const { + TrustedPointerTagRange tag_range) const { uint32_t index = HandleToIndex(handle); DCHECK(index == 0 || at(index).HasPointer(tag_range)); return at(index).GetPointer(tag_range); } Address TrustedPointerTable::GetMaybeUnpublished( - TrustedPointerHandle handle, IndirectPointerTagRange tag_range) const { + TrustedPointerHandle handle, TrustedPointerTagRange tag_range) const { uint32_t index = HandleToIndex(handle); const TrustedPointerTableEntry& entry = at(index); return entry.GetMaybeUnpublished(tag_range); } void TrustedPointerTable::Set(TrustedPointerHandle handle, Address pointer, - IndirectPointerTag tag) { + TrustedPointerTag tag) { DCHECK_NE(kNullTrustedPointerHandle, handle); Validate(pointer, tag); uint32_t index = HandleToIndex(handle); @@ -160,7 +160,7 @@ void TrustedPointerTable::Update(TrustedPointerHandle handle, Address pointer) { } TrustedPointerHandle TrustedPointerTable::AllocateAndInitializeEntry( - Space* space, Address pointer, IndirectPointerTag tag, + Space* space, Address pointer, TrustedPointerTag tag, TrustedPointerPublishingScope* scope) { DCHECK(space->BelongsTo(this)); Validate(pointer, tag); @@ -187,7 +187,7 @@ void TrustedPointerTable::Zap(TrustedPointerHandle handle) { } void TrustedPointerTable::Publish(TrustedPointerHandle handle, - IndirectPointerTag tag) { + TrustedPointerTag tag) { uint32_t index = HandleToIndex(handle); at(index).Publish(tag); } @@ -199,7 +199,7 @@ void TrustedPointerTable::Unpublish(TrustedPointerHandle handle) { bool TrustedPointerTable::IsUnpublished(TrustedPointerHandle handle) const { uint32_t index = HandleToIndex(handle); - return at(index).HasPointer(kUnpublishedIndirectPointerTag); + return at(index).HasPointer(kUnpublishedTrustedPointerTag); } template <typename Callback> @@ -209,7 +209,7 @@ void TrustedPointerTable::IterateActiveEntriesIn(Space* space, if (!at(index).IsFreelistEntry()) { // We might see unpublished entries here and also need to handle them. Address pointer = - at(index).GetPointer(kAllIndirectPointerTagsIncludingUnpublished); + at(index).GetPointer(kAllTrustedPointerTagsIncludingUnpublished); callback(IndexToHandle(index), pointer); } }); @@ -227,7 +227,7 @@ TrustedPointerHandle TrustedPointerTable::IndexToHandle(uint32_t index) const { return handle; } -void TrustedPointerTable::Validate(Address pointer, IndirectPointerTag tag) { +void TrustedPointerTable::Validate(Address pointer, TrustedPointerTag tag) { if (IsTrustedSpaceMigrationInProgressForObjectsWithTag(tag)) { // This CHECK is mostly just here to force tags to be taken out of the // IsTrustedSpaceMigrationInProgressForObjectsWithTag function once the @@ -238,8 +238,8 @@ void TrustedPointerTable::Validate(Address pointer, IndirectPointerTag tag) { if (ReadOnlyHeap::Contains(pointer)) { // Only Code and UncompiledData are allowed to reside in the Read-Only Heap // and have entries in the Trusted Pointer Table. - CHECK(tag == kCodeIndirectPointerTag || - tag == kUncompiledDataIndirectPointerTag); + CHECK(tag == kCodeTrustedPointerTag || + tag == kUncompiledDataTrustedPointerTag); return; } diff --git a/deps/v8/src/sandbox/trusted-pointer-table.cc b/deps/v8/src/sandbox/trusted-pointer-table.cc index aba4cbd46f15..72ccc3f52524 100644 --- a/deps/v8/src/sandbox/trusted-pointer-table.cc +++ b/deps/v8/src/sandbox/trusted-pointer-table.cc @@ -33,10 +33,10 @@ uint32_t TrustedPointerTable::Sweep(Space* space, Counters* counters) { void TrustedPointerTable::Verify(Isolate* isolate, Space* space) { IterateEntriesIn(space, [&](uint32_t index) { auto& entry = at(index); - IndirectPointerTag tag = entry.GetTag(); - if (tag == kIndirectPointerNullTag || tag == kIndirectPointerFreeEntryTag || - tag == kIndirectPointerZappedEntryTag || - tag == kUnpublishedIndirectPointerTag) { + TrustedPointerTag tag = entry.GetTag(); + if (tag == kTrustedPointerNullTag || tag == kTrustedPointerFreeEntryTag || + tag == kTrustedPointerZappedEntryTag || + tag == kUnpublishedTrustedPointerTag) { return; } @@ -45,8 +45,8 @@ void TrustedPointerTable::Verify(Isolate* isolate, Space* space) { // 1. The pointer must point outside of the sandbox or be write-protected in // Read-Only space. if (ReadOnlyHeap::Contains(pointer)) { - CHECK(tag == kCodeIndirectPointerTag || - tag == kUncompiledDataIndirectPointerTag); + CHECK(tag == kCodeTrustedPointerTag || + tag == kUncompiledDataTrustedPointerTag); } else { CHECK(OutsideSandbox(pointer) || IsTrustedSpaceMigrationInProgressForObjectsWithTag(tag)); @@ -55,7 +55,7 @@ void TrustedPointerTable::Verify(Isolate* isolate, Space* space) { // 2. The object must be a valid HeapObject. Tagged<Object> obj_ptr(pointer); CHECK(Is<HeapObject>(obj_ptr)); - Tagged<HeapObject> obj = TrustedCast<HeapObject>(obj_ptr); + Tagged<HeapObject> obj = Cast<HeapObject>(obj_ptr); #ifdef VERIFY_HEAP Object::ObjectVerify(obj, isolate); #endif @@ -63,7 +63,7 @@ void TrustedPointerTable::Verify(Isolate* isolate, Space* space) { // 3. The tag must match the object's instance type. SharedFlag is_shared = SharedFlag(this == &isolate->shared_trusted_pointer_table()); - IndirectPointerTag expected_tag = IndirectPointerTagFromInstanceType( + TrustedPointerTag expected_tag = TrustedPointerTagFromInstanceType( obj->map()->instance_type(), is_shared); CHECK_EQ(tag, expected_tag); }); diff --git a/deps/v8/src/sandbox/trusted-pointer-table.h b/deps/v8/src/sandbox/trusted-pointer-table.h index 977268c621d1..54b6c4593d7b 100644 --- a/deps/v8/src/sandbox/trusted-pointer-table.h +++ b/deps/v8/src/sandbox/trusted-pointer-table.h @@ -10,8 +10,8 @@ #include "src/base/memory.h" #include "src/common/globals.h" #include "src/sandbox/external-entity-table.h" -#include "src/sandbox/indirect-pointer-tag.h" #include "src/sandbox/tagged-payload.h" +#include "src/sandbox/trusted-pointer-tag.h" #ifdef V8_ENABLE_SANDBOX @@ -31,7 +31,7 @@ class TrustedPointerPublishingScope; struct TrustedPointerTableEntry { // Make this entry a "regular" entry, containing an absolute pointer to a // TrustedObject. - inline void MakeTrustedPointerEntry(Address pointer, IndirectPointerTag tag, + inline void MakeTrustedPointerEntry(Address pointer, TrustedPointerTag tag, bool mark_as_alive); // Make this entry a freelist entry, containing the index of the next entry @@ -44,29 +44,29 @@ struct TrustedPointerTableEntry { // Retrieve the pointer stored in this entry. This entry must be tagged with // the given tag, otherwise an inaccessible pointer will be returned. // This entry must not be a freelist entry. - inline Address GetPointer(IndirectPointerTagRange tag_range) const; + inline Address GetPointer(TrustedPointerTagRange tag_range) const; // Store the given pointer in this entry while preserving the marking state. // This entry must not be a freelist entry. - inline void SetPointer(Address pointer, IndirectPointerTag tag); + inline void SetPointer(Address pointer, TrustedPointerTag tag); // Returns true if this entry contains a pointer with the given tag. - inline bool HasPointer(IndirectPointerTagRange tag_range) const; + inline bool HasPointer(TrustedPointerTagRange tag_range) const; // Returns the payload if the tag matches either {tag_range} or - // {kUnpublishedIndirectPointerTag}. - inline Address GetMaybeUnpublished(IndirectPointerTagRange tag_range) const; + // {kUnpublishedTrustedPointerTag}. + inline Address GetMaybeUnpublished(TrustedPointerTagRange tag_range) const; // Returns the tag of this entry. - inline IndirectPointerTag GetTag() const; + inline TrustedPointerTag GetTag() const; - // Unpublish this entry by setting its tag to kUnpublishedIndirectPointerTag. + // Unpublish this entry by setting its tag to kUnpublishedTrustedPointerTag. // This way, the entry (and the object referenced by it) will not be // accessible from within the sandbox. inline void Unpublish(); // Publish a currently unpublished entry by setting its tag to the given one. - inline void Publish(IndirectPointerTag tag); + inline void Publish(TrustedPointerTag tag); // Returns true if this entry is a freelist entry. inline bool IsFreelistEntry() const; @@ -94,19 +94,23 @@ struct TrustedPointerTableEntry { // TrustedPointerTable entries consist of a single pointer-sized word // containing a tag and marking bit together with the actual pointer. struct TrustedPointerTaggingScheme { - using TagType = IndirectPointerTag; + using TagType = TrustedPointerTag; static constexpr uint64_t kMarkBit = kTrustedPointerTableMarkBit; static constexpr uint64_t kTagShift = kTrustedPointerTableTagShift; static constexpr uint64_t kTagMask = kTrustedPointerTableTagMask; static constexpr uint64_t kPayloadMask = kTrustedPointerTablePayloadMask; static constexpr uint64_t kPayloadShift = kTrustedPointerTablePayloadShift; - static constexpr TagType kFreeEntryTag = kIndirectPointerFreeEntryTag; + static constexpr TagType kFreeEntryTag = kTrustedPointerFreeEntryTag; static constexpr TagType kEvacuationEntryTag = - kIndirectPointerEvacuationEntryTag; + kTrustedPointerEvacuationEntryTag; }; using Payload = TaggedPayload<TrustedPointerTaggingScheme>; + public: + static constexpr uint64_t kTagAndMarkBitMask = Payload::kTagAndMarkBitMask; + + private: std::atomic<Payload> payload_; }; @@ -150,17 +154,17 @@ class V8_EXPORT_PRIVATE TrustedPointerTable // // This method is atomic and can be called from background threads. inline Address Get(TrustedPointerHandle handle, - IndirectPointerTagRange tag_range) const; + TrustedPointerTagRange tag_range) const; - // Allows kUnpublishedIndirectPointerTag in addition to the specified {tag}. + // Allows kUnpublishedTrustedPointerTag in addition to the specified {tag}. inline Address GetMaybeUnpublished(TrustedPointerHandle handle, - IndirectPointerTagRange tag_range) const; + TrustedPointerTagRange tag_range) const; // Sets the content of the entry referenced by the given handle. // // This method is atomic and can be called from background threads. inline void Set(TrustedPointerHandle handle, Address pointer, - IndirectPointerTag tag); + TrustedPointerTag tag); // Sets the content of the entry referenced by the given handle. Will preserve // the currently set tag. @@ -172,7 +176,7 @@ class V8_EXPORT_PRIVATE TrustedPointerTable // // This method is atomic and can be called from background threads. inline TrustedPointerHandle AllocateAndInitializeEntry( - Space* space, Address pointer, IndirectPointerTag tag, + Space* space, Address pointer, TrustedPointerTag tag, TrustedPointerPublishingScope* scope); // Marks the specified entry as alive. @@ -198,7 +202,7 @@ class V8_EXPORT_PRIVATE TrustedPointerTable // The specified entry must currently be unpublished, and is therefore // inaccessible from within the sandbox. Calling this method will make the // entry accessible. - inline void Publish(TrustedPointerHandle handle, IndirectPointerTag tag); + inline void Publish(TrustedPointerHandle handle, TrustedPointerTag tag); // Undo earlier publishing, making the entry inaccessible. inline void Unpublish(TrustedPointerHandle handle); @@ -230,7 +234,7 @@ class V8_EXPORT_PRIVATE TrustedPointerTable inline TrustedPointerHandle IndexToHandle(uint32_t index) const; // Ensure that the value is valid before storing it into this table. - inline void Validate(Address pointer, IndirectPointerTag tag); + inline void Validate(Address pointer, TrustedPointerTag tag); }; } // namespace internal diff --git a/deps/v8/src/sandbox/indirect-pointer-tag.h b/deps/v8/src/sandbox/trusted-pointer-tag.h similarity index 50% rename from deps/v8/src/sandbox/indirect-pointer-tag.h rename to deps/v8/src/sandbox/trusted-pointer-tag.h index 725bc2fa966c..2b9e9fe2da28 100644 --- a/deps/v8/src/sandbox/indirect-pointer-tag.h +++ b/deps/v8/src/sandbox/trusted-pointer-tag.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef V8_SANDBOX_INDIRECT_POINTER_TAG_H_ -#define V8_SANDBOX_INDIRECT_POINTER_TAG_H_ +#ifndef V8_SANDBOX_TRUSTED_POINTER_TAG_H_ +#define V8_SANDBOX_TRUSTED_POINTER_TAG_H_ #include "src/base/strong-alias.h" #include "src/common/globals.h" @@ -12,9 +12,9 @@ namespace v8 { namespace internal { -// Defines the list of valid indirect pointer tags. +// Defines the list of valid trusted pointer tags. // -// When accessing a trusted/indirect pointer, an IndirectPointerTag must be +// When accessing a trusted pointer, a TrustedPointerTag must be // provided which indicates the expected instance type of the pointed-to // object. When the sandbox is enabled, this tag is used to ensure type-safe // access to objects referenced via trusted pointers: if the provided tag @@ -23,64 +23,82 @@ namespace internal { // // A trusted pointer table entry has the following layout: // -// +------------+----------+-----------------+ -// | 15-bit tag | mark bit | 48-bit payload | -// +------------+----------+-----------------+ +// On x64, the payload must be able to hold 57-bit addresses (LA57): +// +// +-----------+----------+----------------+ +// | 7-bit tag | mark bit | 56-bit payload | +// +-----------+----------+----------------+ +// +// On the other 64-bit architectures (e.g. Arm64), addresses are at most 48 +// bits wide. The tag field is 15 bits wide there, but as tags are limited to +// 7 bits, its top 8 bits are currently unused and left for TBI/MTE: +// +// +---------------+-----------+----------+----------------+ +// | 8 unused bits | 7-bit tag | mark bit | 48-bit payload | +// +---------------+-----------+----------+----------------+ // // This format ensures that both the tag and the payload can be extracted // efficiently, and thereby helps keep the performance overhead low. +#if V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 +constexpr uint64_t kTrustedPointerTableTagMask = 0xfe00'0000'0000'0000; +constexpr uint64_t kTrustedPointerTableMarkBit = 0x0100'0000'0000'0000; +constexpr uint64_t kTrustedPointerTablePayloadMask = 0x00ff'ffff'ffff'ffff; +constexpr uint64_t kTrustedPointerTableTagShift = 57; +#else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) constexpr uint64_t kTrustedPointerTableTagMask = 0xfffe'0000'0000'0000; constexpr uint64_t kTrustedPointerTableMarkBit = 0x0001'0000'0000'0000; constexpr uint64_t kTrustedPointerTablePayloadMask = 0x0000'ffff'ffff'ffff; constexpr uint64_t kTrustedPointerTableTagShift = 49; +#endif // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) constexpr uint64_t kTrustedPointerTablePayloadShift = 0; -// The tag is currently in practice limited to maximum 15 bits since it needs -// to fit together with a marking bit into the unused parts of a pointer. -enum IndirectPointerTag : uint16_t { - kIndirectPointerNullTag = 0, +// The tag is limited to 7 bits since it needs to fit together with a marking +// bit into the unused parts of a pointer on x64 (see the layout above). +enum TrustedPointerTag : uint16_t { + kTrustedPointerNullTag = 0, // Shared trusted pointers are owned by the shared Isolate and stored in the // shared trusted pointer table associated with that Isolate. - kFirstSharedTrustedPointerTag = 1, - kSharedWasmTrustedInstanceDataIndirectPointerTag = + kFirstSharedTrustedPointerTag, + kSharedWasmTrustedInstanceDataTrustedPointerTag = kFirstSharedTrustedPointerTag, - kSharedWasmDispatchTableIndirectPointerTag, - kLastSharedTrustedPointerTag = kSharedWasmDispatchTableIndirectPointerTag, + kSharedWasmDispatchTableTrustedPointerTag, + kLastSharedTrustedPointerTag = kSharedWasmDispatchTableTrustedPointerTag, // Trusted pointers using these tags are kept in a per-Isolate trusted // pointer table and can only be accessed when this Isolate is active. - kFirstPerIsolateTrustedPointerTag = kLastSharedTrustedPointerTag + 1, - kWasmInternalFunctionIndirectPointerTag = kFirstPerIsolateTrustedPointerTag, + kFirstPerIsolateTrustedPointerTag, + kWasmInternalFunctionTrustedPointerTag = kFirstPerIsolateTrustedPointerTag, + // Untagging performance matters for this tag, so it should be "fast". + kWasmTrustedInstanceDataTrustedPointerTag, // 4 + kWasmDispatchTableTrustedPointerTag, + kWasmSuspenderTrustedPointerTag, + kRegExpDataTrustedPointerTag, + + kFirstSFITrustedDataTag, // Untagging performance matters for this tag, so it should be "fast". - kWasmTrustedInstanceDataIndirectPointerTag = 4, - kWasmDispatchTableIndirectPointerTag, - kWasmSuspenderIndirectPointerTag, - kRegExpDataIndirectPointerTag, - kDebugInfoIndirectPointerTag, - - kFirstSFITrustedDataTag = kDebugInfoIndirectPointerTag + 1, - kWasmExportedFunctionDataIndirectPointerTag = kFirstSFITrustedDataTag, - kWasmCapiFunctionDataIndirectPointerTag, - kInterpreterDataIndirectPointerTag, - kUncompiledDataIndirectPointerTag, - kBytecodeArrayIndirectPointerTag, + kWasmExportedFunctionDataTrustedPointerTag = kFirstSFITrustedDataTag, // 8 + kWasmCapiFunctionDataTrustedPointerTag, + kInterpreterDataTrustedPointerTag, + kUncompiledDataTrustedPointerTag, + kBytecodeArrayTrustedPointerTag, // All code pointers share the same tag (pointing to Code objects). Their // instruction stream start is guarded by another tag (CodeEntrypointTag). - kCodeIndirectPointerTag, - kLastSFITrustedDataTag = kCodeIndirectPointerTag, - kLastPerIsolateTrustedPointerTag = kLastSFITrustedDataTag, + kCodeTrustedPointerTag, + kLastSFITrustedDataTag = kCodeTrustedPointerTag, + kDebugInfoTrustedPointerTag, + kLastPerIsolateTrustedPointerTag = kDebugInfoTrustedPointerTag, - // The maximum tag in kAllIndirectPointerTags. Padded to a (pow2-1) to enable + // The maximum tag in kAllTrustedPointerTags. Padded to a (pow2-1) to enable // fast, single-instruction bitwise untagging (see - // IsFastIndirectPointerTagRange). - kLastIndirectPointerFastTag = 0x0f, + // IsFastTrustedPointerTagRange). + kLastTrustedPointerFastTag = 0x0f, // Special tags. // - // Currently we only use 8 bits (plus one marking bit) so we have spare bits - // in the pointers if we ever need them (e.g. for something like MTE). - // If we ever need more tags, we could go up to 15 bits though. + // Currently we only use 7 bits (plus one marking bit), which is all that is + // available on x64. On the other architectures we have spare bits in the + // pointers if we ever need them (e.g. for something like MTE). // // A special tag for objects that should not (yet) be exposed to the sandbox. @@ -95,17 +113,20 @@ enum IndirectPointerTag : uint16_t { // accessible from within the sandbox (for example, bytecode arrays), then // these objects can first be created in an unpublished state and then // only be published after successful validation. - kUnpublishedIndirectPointerTag = 0xfc, + kUnpublishedTrustedPointerTag = 0x7c, // Tag for zapped entries in the trusted pointer table. - kIndirectPointerZappedEntryTag = 0xfd, + kTrustedPointerZappedEntryTag = 0x7d, // Not currently used for the trusted pointer table. - kIndirectPointerEvacuationEntryTag = 0xfe, + kTrustedPointerEvacuationEntryTag = 0x7e, // Tag for free entries in the trusted pointer table. - kIndirectPointerFreeEntryTag = 0xff, - kLastIndirectPointerTag = 0xff, + kTrustedPointerFreeEntryTag = 0x7f, + kLastTrustedPointerTag = 0x7f, }; -using IndirectPointerTagRange = TagRange<IndirectPointerTag>; +// All tags must fit into the 7 tag bits of an x64 trusted pointer table entry. +static_assert(kLastTrustedPointerTag <= 0x7f); + +using TrustedPointerTagRange = TagRange<TrustedPointerTag>; #if V8_TARGET_ARCH_ARM64 // On ARM64 with TBI we must not have fast tags that set bits in the top byte @@ -114,7 +135,7 @@ using IndirectPointerTagRange = TagRange<IndirectPointerTag>; // masks, it sets bits exactly up to 54, keeping bit 55 (the kernel address // switch) and bits 56-63 (the TBI ignored byte) fully set. To prevent clearing // bit 55 or higher, tags must not exceed 0x3f (63). -constexpr uint16_t kMaxFastIndirectPointerTagForARM64 = 0x3f; +constexpr uint16_t kMaxFastTrustedPointerTagForARM64 = 0x3f; #endif // "Fast" tags are those that are powers of two. In that case, we can simply @@ -122,10 +143,10 @@ constexpr uint16_t kMaxFastIndirectPointerTagForARM64 = 0x3f; // pointer. If the tags don't match, we'll be left with a non-canonical pointer // which is guaranteed to crash on use. This is slightly more efficient than // the generic tag-extract-and-compare approach. -V8_INLINE constexpr bool IsFastIndirectPointerTag(IndirectPointerTag tag) { - DCHECK_NE(tag, kIndirectPointerNullTag); +V8_INLINE constexpr bool IsFastTrustedPointerTag(TrustedPointerTag tag) { + DCHECK_NE(tag, kTrustedPointerNullTag); #if V8_TARGET_ARCH_ARM64 - if (static_cast<uint16_t>(tag) > kMaxFastIndirectPointerTagForARM64) { + if (static_cast<uint16_t>(tag) > kMaxFastTrustedPointerTagForARM64) { return false; } #endif @@ -133,9 +154,9 @@ V8_INLINE constexpr bool IsFastIndirectPointerTag(IndirectPointerTag tag) { } // Tag ranges are "fast" if they can be untagged with a single AND operation. -V8_INLINE constexpr bool IsFastIndirectPointerTagRange( - IndirectPointerTagRange tag_range) { - DCHECK_NE(tag_range.first, kIndirectPointerNullTag); +V8_INLINE constexpr bool IsFastTrustedPointerTagRange( + TrustedPointerTagRange tag_range) { + DCHECK_NE(tag_range.first, kTrustedPointerNullTag); // A tag range is "fast" (i.e. can be untagged via a single mask) if either: // 1. It contains a single tag which is "fast" (a power of two). // 2. It starts at 1 and ends at a power-of-two minus one. @@ -145,150 +166,152 @@ V8_INLINE constexpr bool IsFastIndirectPointerTagRange( // least one bit set in the tag area and will therefore be non-canonical, // which is guaranteed to crash on use. if (tag_range.Size() == 1) { - return IsFastIndirectPointerTag(tag_range.first); + return IsFastTrustedPointerTag(tag_range.first); } else { uint16_t first = static_cast<uint16_t>(tag_range.first); uint16_t last = static_cast<uint16_t>(tag_range.last); #if V8_TARGET_ARCH_ARM64 - if (last > kMaxFastIndirectPointerTagForARM64) return false; + if (last > kMaxFastTrustedPointerTagForARM64) return false; #endif return first == 1 && base::bits::IsPowerOfTwo(last + 1); } } -V8_INLINE constexpr uint64_t ComputeUntaggingMaskForFastIndirectPointerTag( - IndirectPointerTagRange tag_range) { - DCHECK(IsFastIndirectPointerTagRange(tag_range)); +V8_INLINE constexpr uint64_t ComputeUntaggingMaskForFastTrustedPointerTag( + TrustedPointerTagRange tag_range) { + DCHECK(IsFastTrustedPointerTagRange(tag_range)); return ~( (static_cast<uint64_t>(tag_range.last) << kTrustedPointerTableTagShift) | kTrustedPointerTableMarkBit); } -constexpr IndirectPointerTagRange kAllSharedIndirectPointerTags( +constexpr TrustedPointerTagRange kAllSharedTrustedPointerTags( kFirstSharedTrustedPointerTag, kLastSharedTrustedPointerTag); -constexpr IndirectPointerTagRange kAllPerIsolateIndirectPointerTags( +constexpr TrustedPointerTagRange kAllPerIsolateTrustedPointerTags( kFirstPerIsolateTrustedPointerTag, kLastPerIsolateTrustedPointerTag); -constexpr IndirectPointerTagRange kAllIndirectPointerTags( - kFirstSharedTrustedPointerTag, kLastIndirectPointerFastTag); -constexpr IndirectPointerTagRange kAllIndirectPointerTagsIncludingUnpublished( - kFirstSharedTrustedPointerTag, kUnpublishedIndirectPointerTag); +constexpr TrustedPointerTagRange kAllTrustedPointerTags( + kFirstSharedTrustedPointerTag, kLastTrustedPointerFastTag); +constexpr TrustedPointerTagRange kAllTrustedPointerTagsIncludingUnpublished( + kFirstSharedTrustedPointerTag, kUnpublishedTrustedPointerTag); -constexpr IndirectPointerTagRange kWasmFunctionDataIndirectPointerTagRange( - kWasmExportedFunctionDataIndirectPointerTag, - kWasmCapiFunctionDataIndirectPointerTag); +constexpr TrustedPointerTagRange kWasmFunctionDataTrustedPointerTagRange( + kWasmExportedFunctionDataTrustedPointerTag, + kWasmCapiFunctionDataTrustedPointerTag); -constexpr IndirectPointerTagRange kSFITrustedDataIndirectPointerRange( +constexpr TrustedPointerTagRange kSFITrustedDataTrustedPointerRange( kFirstSFITrustedDataTag, kLastSFITrustedDataTag); -// The kAllIndirectPointerTags contains all regular tags including the code tag. -static_assert(kAllIndirectPointerTags.Contains(kAllSharedIndirectPointerTags)); +// The kAllTrustedPointerTags contains all regular tags including the code tag. +static_assert(kAllTrustedPointerTags.Contains(kAllSharedTrustedPointerTags)); static_assert( - kAllIndirectPointerTags.Contains(kAllPerIsolateIndirectPointerTags)); -static_assert(kAllIndirectPointerTags.Contains(kCodeIndirectPointerTag)); + kAllTrustedPointerTags.Contains(kAllPerIsolateTrustedPointerTags)); +static_assert(kAllTrustedPointerTags.Contains(kCodeTrustedPointerTag)); // None of the above must contain any special entries though. -static_assert( - !kAllIndirectPointerTags.Contains(kUnpublishedIndirectPointerTag)); +static_assert(!kAllTrustedPointerTags.Contains(kUnpublishedTrustedPointerTag)); // The range is expected to be fast. -static_assert(IsFastIndirectPointerTagRange(kAllIndirectPointerTags)); +static_assert(IsFastTrustedPointerTagRange(kAllTrustedPointerTags)); -// These are only included in kAllIndirectPointerTagsIncludingUnpublished. -static_assert(kAllIndirectPointerTagsIncludingUnpublished.Contains( - kUnpublishedIndirectPointerTag)); -static_assert(kAllIndirectPointerTagsIncludingUnpublished.Contains( - kAllIndirectPointerTags)); +// These are only included in kAllTrustedPointerTagsIncludingUnpublished. +static_assert(kAllTrustedPointerTagsIncludingUnpublished.Contains( + kUnpublishedTrustedPointerTag)); +static_assert(kAllTrustedPointerTagsIncludingUnpublished.Contains( + kAllTrustedPointerTags)); // We expect certain tags to be "fast" as their untagging performance matters. -// See crbug.com/476810009 for why this tag should be fast. +// See crbug.com/476810009 and crbug.com/562056770 for why these tags should be +// fast. +static_assert( + IsFastTrustedPointerTag(kWasmTrustedInstanceDataTrustedPointerTag)); static_assert( - IsFastIndirectPointerTag(kWasmTrustedInstanceDataIndirectPointerTag)); + IsFastTrustedPointerTag(kWasmExportedFunctionDataTrustedPointerTag)); V8_INLINE static constexpr bool IsSharedTrustedPointerType( - IndirectPointerTag tag) { - return kAllSharedIndirectPointerTags.Contains(tag); + TrustedPointerTag tag) { + return kAllSharedTrustedPointerTags.Contains(tag); } V8_INLINE static constexpr bool IsSharedTrustedPointerType( - IndirectPointerTagRange tag_range) { - DCHECK(tag_range == kAllIndirectPointerTags || + TrustedPointerTagRange tag_range) { + DCHECK(tag_range == kAllTrustedPointerTags || IsSharedTrustedPointerType(tag_range.first) == IsSharedTrustedPointerType(tag_range.last)); - return kAllSharedIndirectPointerTags.Contains(tag_range); + return kAllSharedTrustedPointerTags.Contains(tag_range); } V8_INLINE static constexpr bool IsPerIsolateTrustedPointerType( - IndirectPointerTag tag) { - return kAllPerIsolateIndirectPointerTags.Contains(tag); + TrustedPointerTag tag) { + return kAllPerIsolateTrustedPointerTags.Contains(tag); } -V8_INLINE constexpr bool IsValidIndirectPointerTag(IndirectPointerTag tag) { - return kAllIndirectPointerTags.Contains(tag); +V8_INLINE constexpr bool IsValidTrustedPointerTag(TrustedPointerTag tag) { + return kAllTrustedPointerTags.Contains(tag); } // Migrating objects into trusted space is typically performed in multiple // steps, where all references to the object from inside the sandbox are first -// changed to indirect pointers before actually moving the object out of the +// changed to trusted pointers before actually moving the object out of the // sandbox. As we have CHECKs that trusted pointer table entries point outside // of the sandbox, we need this helper function to disable that CHECK for // objects that are in the process of being migrated into trusted space. V8_INLINE constexpr bool IsTrustedSpaceMigrationInProgressForObjectsWithTag( - IndirectPointerTag tag) { + TrustedPointerTag tag) { return false; } // TODO(saelo): Refactor TaggedPayload to not require this workaround. V8_INLINE static constexpr bool ExternalPointerCanBeEmpty( - IndirectPointerTagRange tag_range) { + TrustedPointerTagRange tag_range) { return false; } -// The null tag is also considered an invalid tag since no indirect pointer +// The null tag is also considered an invalid tag since no trusted pointer // field should be using this tag. -static_assert(!IsValidIndirectPointerTag(kIndirectPointerNullTag)); +static_assert(!IsValidTrustedPointerTag(kTrustedPointerNullTag)); -V8_INLINE IndirectPointerTag IndirectPointerTagFromInstanceType( +V8_INLINE TrustedPointerTag TrustedPointerTagFromInstanceType( InstanceType instance_type, SharedFlag shared) { switch (instance_type) { case CODE_TYPE: - return kCodeIndirectPointerTag; + return kCodeTrustedPointerTag; case BYTECODE_ARRAY_TYPE: - return kBytecodeArrayIndirectPointerTag; + return kBytecodeArrayTrustedPointerTag; case INTERPRETER_DATA_TYPE: - return kInterpreterDataIndirectPointerTag; + return kInterpreterDataTrustedPointerTag; case DEBUG_INFO_TYPE: - return kDebugInfoIndirectPointerTag; + return kDebugInfoTrustedPointerTag; case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE: case UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE: // TODO(saelo): Consider adding support for inheritance hierarchies in // our tag checking mechanism. - return kUncompiledDataIndirectPointerTag; + return kUncompiledDataTrustedPointerTag; case ATOM_REG_EXP_DATA_TYPE: case IR_REG_EXP_DATA_TYPE: // TODO(saelo): Consider adding support for inheritance hierarchies in // our tag checking mechanism. - return kRegExpDataIndirectPointerTag; + return kRegExpDataTrustedPointerTag; #if V8_ENABLE_WEBASSEMBLY case WASM_DISPATCH_TABLE_TYPE: - return shared ? kSharedWasmDispatchTableIndirectPointerTag - : kWasmDispatchTableIndirectPointerTag; + return shared ? kSharedWasmDispatchTableTrustedPointerTag + : kWasmDispatchTableTrustedPointerTag; case WASM_TRUSTED_INSTANCE_DATA_TYPE: - return shared ? kSharedWasmTrustedInstanceDataIndirectPointerTag - : kWasmTrustedInstanceDataIndirectPointerTag; + return shared ? kSharedWasmTrustedInstanceDataTrustedPointerTag + : kWasmTrustedInstanceDataTrustedPointerTag; case WASM_INTERNAL_FUNCTION_TYPE: - return kWasmInternalFunctionIndirectPointerTag; + return kWasmInternalFunctionTrustedPointerTag; case WASM_SUSPENDER_OBJECT_TYPE: - return kWasmSuspenderIndirectPointerTag; + return kWasmSuspenderTrustedPointerTag; case WASM_FUNCTION_DATA_TYPE: // WasmFunctionData is effectively an abstract base class, so we shouldn't // have instances of this type. UNREACHABLE(); case WASM_EXPORTED_FUNCTION_DATA_TYPE: - return kWasmExportedFunctionDataIndirectPointerTag; + return kWasmExportedFunctionDataTrustedPointerTag; case WASM_CAPI_FUNCTION_DATA_TYPE: - return kWasmCapiFunctionDataIndirectPointerTag; + return kWasmCapiFunctionDataTrustedPointerTag; #endif // V8_ENABLE_WEBASSEMBLY default: UNREACHABLE(); @@ -298,4 +321,4 @@ V8_INLINE IndirectPointerTag IndirectPointerTagFromInstanceType( } // namespace internal } // namespace v8 -#endif // V8_SANDBOX_INDIRECT_POINTER_TAG_H_ +#endif // V8_SANDBOX_TRUSTED_POINTER_TAG_H_ diff --git a/deps/v8/src/objects/trusted-pointer.h b/deps/v8/src/sandbox/trusted-pointer.h similarity index 57% rename from deps/v8/src/objects/trusted-pointer.h rename to deps/v8/src/sandbox/trusted-pointer.h index ebee854b11a4..236c040cb115 100644 --- a/deps/v8/src/objects/trusted-pointer.h +++ b/deps/v8/src/sandbox/trusted-pointer.h @@ -1,16 +1,17 @@ -// Copyright 2025 the V8 project authors. All rights reserved. +// Copyright 2023 the V8 project 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 V8_OBJECTS_TRUSTED_POINTER_H_ -#define V8_OBJECTS_TRUSTED_POINTER_H_ +#ifndef V8_SANDBOX_TRUSTED_POINTER_H_ +#define V8_SANDBOX_TRUSTED_POINTER_H_ #include "src/common/globals.h" #include "src/objects/heap-object.h" #include "src/objects/objects.h" #include "src/objects/tagged-field.h" #include "src/objects/tagged.h" -#include "src/sandbox/indirect-pointer-tag.h" +#include "src/sandbox/isolate.h" +#include "src/sandbox/trusted-pointer-tag.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -18,7 +19,7 @@ namespace v8 { namespace internal { -class IsolateForSandbox; +class TrustedPointerPublishingScope; class Code; class BytecodeArray; class InterpreterData; @@ -32,31 +33,31 @@ class WasmFunctionData; class WasmExportedFunctionData; class WasmCapiFunctionData; -template <typename T, IndirectPointerTagRange kTagRange> +template <typename T, TrustedPointerTagRange kTagRange> class TrustedPointerMember; namespace detail { -#define TRUSTED_POINTER_TAG_TO_TYPE_MAP(V) \ - V(kCodeIndirectPointerTag, Code) \ - V(kBytecodeArrayIndirectPointerTag, BytecodeArray) \ - V(kInterpreterDataIndirectPointerTag, InterpreterData) \ - V(kUncompiledDataIndirectPointerTag, UncompiledData) \ - V(kRegExpDataIndirectPointerTag, RegExpData) \ - IF_WASM(V, kWasmDispatchTableIndirectPointerTag, WasmDispatchTable) \ - IF_WASM(V, kSharedWasmDispatchTableIndirectPointerTag, WasmDispatchTable) \ - IF_WASM(V, kWasmTrustedInstanceDataIndirectPointerTag, \ - WasmTrustedInstanceData) \ - IF_WASM(V, kSharedWasmTrustedInstanceDataIndirectPointerTag, \ - WasmTrustedInstanceData) \ - IF_WASM(V, kWasmInternalFunctionIndirectPointerTag, WasmInternalFunction) \ - IF_WASM(V, kWasmSuspenderIndirectPointerTag, WasmSuspenderObject) \ - IF_WASM(V, kWasmFunctionDataIndirectPointerTagRange, WasmFunctionData) \ - IF_WASM(V, kWasmExportedFunctionDataIndirectPointerTag, \ - WasmExportedFunctionData) \ - IF_WASM(V, kWasmCapiFunctionDataIndirectPointerTag, WasmCapiFunctionData) - -template <IndirectPointerTagRange tag_range> +#define TRUSTED_POINTER_TAG_TO_TYPE_MAP(V) \ + V(kCodeTrustedPointerTag, Code) \ + V(kBytecodeArrayTrustedPointerTag, BytecodeArray) \ + V(kInterpreterDataTrustedPointerTag, InterpreterData) \ + V(kUncompiledDataTrustedPointerTag, UncompiledData) \ + V(kRegExpDataTrustedPointerTag, RegExpData) \ + IF_WASM(V, kWasmDispatchTableTrustedPointerTag, WasmDispatchTable) \ + IF_WASM(V, kSharedWasmDispatchTableTrustedPointerTag, WasmDispatchTable) \ + IF_WASM(V, kWasmTrustedInstanceDataTrustedPointerTag, \ + WasmTrustedInstanceData) \ + IF_WASM(V, kSharedWasmTrustedInstanceDataTrustedPointerTag, \ + WasmTrustedInstanceData) \ + IF_WASM(V, kWasmInternalFunctionTrustedPointerTag, WasmInternalFunction) \ + IF_WASM(V, kWasmSuspenderTrustedPointerTag, WasmSuspenderObject) \ + IF_WASM(V, kWasmFunctionDataTrustedPointerTagRange, WasmFunctionData) \ + IF_WASM(V, kWasmExportedFunctionDataTrustedPointerTag, \ + WasmExportedFunctionData) \ + IF_WASM(V, kWasmCapiFunctionDataTrustedPointerTag, WasmCapiFunctionData) + +template <TrustedPointerTagRange tag_range> struct TrustedPointerType { using type = ExposedTrustedObject; }; @@ -72,7 +73,7 @@ TRUSTED_POINTER_TAG_TO_TYPE_MAP(DEFINE_TRUSTED_POINTER_TYPE) } // namespace detail -template <IndirectPointerTagRange tag_range> +template <TrustedPointerTagRange tag_range> using TrustedTypeFor = typename detail::TrustedPointerType<tag_range>::type; // TrustedPointerField provides static methods for reading and writing trusted @@ -85,23 +86,23 @@ using TrustedTypeFor = typename detail::TrustedPointerType<tag_range>::type; // trusted pointer table. class TrustedPointerField { public: - template <IndirectPointerTagRange tag_range> + template <TrustedPointerTagRange tag_range> static inline Tagged<TrustedTypeFor<tag_range>> ReadTrustedPointerField( Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate); - template <IndirectPointerTagRange tag_range> + template <TrustedPointerTagRange tag_range> static inline Tagged<TrustedTypeFor<tag_range>> ReadTrustedPointerField( Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate, AcquireLoadTag acquire_load); // Like ReadTrustedPointerField, but if the field is cleared, this will // return Smi::zero(). - template <IndirectPointerTagRange tag_range> + template <TrustedPointerTagRange tag_range> static inline Tagged<Union<Smi, TrustedTypeFor<tag_range>>> ReadMaybeEmptyTrustedPointerField(Tagged<HeapObject> host, size_t offset, IsolateForSandbox isolate, AcquireLoadTag); - template <IndirectPointerTagRange tag_range> + template <TrustedPointerTagRange tag_range> static inline void WriteTrustedPointerField( Tagged<HeapObject> host, size_t offset, Tagged<ExposedTrustedObject> value); @@ -116,7 +117,7 @@ class TrustedPointerField { template <typename IsolateT> static inline bool IsTrustedPointerFieldUnpublished( - Tagged<HeapObject> host, size_t offset, IndirectPointerTagRange tag_range, + Tagged<HeapObject> host, size_t offset, TrustedPointerTagRange tag_range, IsolateT isolate); static inline void ClearTrustedPointerField(Tagged<HeapObject> host, @@ -133,7 +134,7 @@ class TrustedPointerField { // // TODO(leszeks): Remove TrustedPointerField (and update these comments) when // all objects are ported. -template <typename T, IndirectPointerTagRange kTagRange> +template <typename T, TrustedPointerTagRange kTagRange> class TrustedPointerMember #ifndef V8_ENABLE_SANDBOX // On non-sandbox builds, TrustedPointerMember is just a TaggedMember with @@ -144,6 +145,15 @@ class TrustedPointerMember { public: constexpr TrustedPointerMember() = default; + inline TrustedPointerMember(const AllocationWitness& witness, + Tagged<T> value); + inline TrustedPointerMember(const AllocationWitness& witness, Tagged<T> value, + WriteBarrierMode mode); + inline TrustedPointerMember(const AllocationWitness& witness, + Tagged<UnionOf<T, Undefined>> maybe_value); + inline TrustedPointerMember(const AllocationWitness& witness, + Tagged<UnionOf<T, Undefined>> maybe_value, + WriteBarrierMode mode); inline Tagged<T> load(IsolateForSandbox isolate) const; inline Tagged<Object> load_maybe_empty(IsolateForSandbox isolate) const; @@ -164,21 +174,48 @@ class TrustedPointerMember private: #ifdef V8_ENABLE_SANDBOX - friend class IndirectPointerSlot; + friend class TrustedPointerSlot; inline Address storage_address() const; - std::atomic<IndirectPointerHandle> handle_; + std::atomic<TrustedPointerHandle> handle_{kNullTrustedPointerHandle}; #else using Base = TaggedMember<T>; #endif }; -using CodePointerMember = TrustedPointerMember<Code, kCodeIndirectPointerTag>; +using CodePointerMember = TrustedPointerMember<Code, kCodeTrustedPointerTag>; + +// Initialize the 'self' trusted pointer that contains a reference back to the +// owning object through its trusted pointer table entry. +// +// Only available when the sandbox is enabled. +V8_INLINE void InitSelfTrustedPointerField( + Address field_address, IsolateForSandbox isolate, Tagged<HeapObject> host, + TrustedPointerTag tag, TrustedPointerPublishingScope* opt_publishing_scope); + +// Reads the TrustedPointerHandle from the field and loads the Object +// referenced by this handle from the trusted pointer table. The given +// TrustedPointerTagRange specifies the expected type of object. +// +// Only available when the sandbox is enabled. +template <TrustedPointerTagRange tag_range> +V8_INLINE Tagged<Object> ReadTrustedPointerField(Address field_address, + IsolateForSandbox isolate, + AcquireLoadTag); + +// Loads the 'self' TrustedPointerHandle from the given object and stores it +// into the trusted pointer field. +// +// Only available when the sandbox is enabled. +template <TrustedPointerTagRange tag_range> +V8_INLINE void WriteTrustedPointerField(Address field_address, + Tagged<ExposedTrustedObject> value, + ReleaseStoreTag); } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" -#endif // V8_OBJECTS_TRUSTED_POINTER_H_ +#endif // V8_SANDBOX_TRUSTED_POINTER_H_ diff --git a/deps/v8/src/snapshot/code-serializer.cc b/deps/v8/src/snapshot/code-serializer.cc index 78ba29eeca3e..b8a3a507d5cb 100644 --- a/deps/v8/src/snapshot/code-serializer.cc +++ b/deps/v8/src/snapshot/code-serializer.cc @@ -7,8 +7,9 @@ #include <algorithm> #include <memory> -#include "src/base/fpu.h" +#include "src/base/container-utils.h" #include "src/base/logging.h" +#include "src/base/numerics/safe_conversions.h" #include "src/base/platform/elapsed-timer.h" #include "src/base/platform/platform.h" #include "src/baseline/baseline-batch-compiler.h" @@ -17,14 +18,17 @@ #include "src/handles/maybe-handles.h" #include "src/handles/persistent-handles.h" #include "src/heap/heap-inl.h" -#include "src/heap/parked-scope.h" +#include "src/heap/parked-scope-inl.h" #include "src/logging/counters-scopes.h" #include "src/logging/log.h" #include "src/logging/runtime-call-stats-scope.h" #include "src/objects/objects-inl.h" #include "src/objects/shared-function-info.h" #include "src/objects/slots.h" +#include "src/objects/string-inl.h" #include "src/objects/visitors.h" +#include "src/sandbox/check.h" +#include "src/sandbox/sandbox.h" #include "src/snapshot/object-deserializer.h" #include "src/snapshot/snapshot-utils.h" #include "src/snapshot/snapshot.h" @@ -45,9 +49,10 @@ AlignedCachedData::AlignedCachedData(const uint8_t* data, int length) } } -CodeSerializer::CodeSerializer(Isolate* isolate, uint32_t source_hash) +CodeSerializer::CodeSerializer(Isolate* isolate, SourceHash source_hash) : Serializer(isolate, Snapshot::kDefaultSerializerFlags), - source_hash_(source_hash) {} + source_hash_(source_hash), + trusted_serializer_(isolate, this) {} // static ScriptCompiler::CachedData* CodeSerializer::Serialize( @@ -76,9 +81,9 @@ ScriptCompiler::CachedData* CodeSerializer::Serialize( } HandleScope scope(isolate); - CodeSerializer cs(isolate, - SerializedCodeData::SourceHash(source, wrapped_arguments, - script->origin_options())); + CodeSerializer cs(isolate, SerializedCodeData::SourceHash( + source, wrapped_arguments, + script->origin_options(), isolate)); DisallowGarbageCollection no_gc; #ifndef DEBUG @@ -108,35 +113,101 @@ AlignedCachedData* CodeSerializer::SerializeSharedFunctionInfo( VisitRootPointer(Root::kHandleScope, nullptr, FullObjectSlot(info.location())); SerializeDeferredObjects(); - Pad(); + trusted_serializer_.SerializeExports(); + trusted_serializer_.FinishSection(); + FinishSection(); - SerializedCodeData data(sink_.data(), this); + SerializedCodeData data(Payload(), + trusted_serializer_.ExternalReferencesPayload(), + trusted_serializer_.Payload(), this); return data.GetScriptData(); } +// The untrusted section can only reach exposed trusted objects, and exports +// all of them. Which trusted objects a code cache may contain is decided by +// SERIALIZABLE_TRUSTED_OBJECT_MAP_ROOT_LIST (see Serializer::PutRoot). +bool CodeSerializer::SerializeTrustedExport(Tagged<HeapObject> obj) { + if (!V8_ENABLE_SANDBOX_BOOL || !IsExposedTrustedObject(obj)) return false; + if (v8_flags.trace_serializer) { + PrintF(" Encoding trusted export reference to: "); + ShortPrint(obj); + PrintF("\n"); + } + sink_.Put(kTrustedExportRef, "TrustedExportRef"); + sink_.PutUint30(trusted_serializer_.Export(obj), "TrustedExportIndex"); + return true; +} + +// The untrusted section must not contain external pointers or their tags, so +// it refers to them by index into a table in the trusted section. +bool CodeSerializer::SerializeTrustedExternalReference( + ExternalReferenceEncoder::Value reference, ExternalPointerTag tag) { + // The tag is read from the external pointer table entry that an in-sandbox + // object refers to, so it can be the tag of any entry. + SBXCHECK(base::contains(kSerializableExternalPointerTags, tag)); + sink_.Put(kTrustedExternalRef, "TrustedExternalRef"); + sink_.PutUint30(trusted_serializer_.AddExternalReference(reference, tag), + "TrustedExternalRefIndex"); + return true; +} + void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj, SlotType slot_type) { - ReadOnlyRoots roots(isolate()); + // NOTE(mmarchini): If we try to serialize an InterpreterData our process + // will crash since it stores a code object. Instead, we serialize the + // bytecode array stored within the InterpreterData, which is the important + // information. On deserialization we'll create our code objects again, if + // --interpreted-frames-native-stack is on. See v8:9122 for more context + if (V8_UNLIKELY(isolate()->interpreted_frames_native_stack()) && + IsInterpreterData(*obj)) { + SBXCHECK(OutsideSandbox(obj->address())); + obj = + handle(TrustedCast<InterpreterData>(*obj)->bytecode_array(), isolate()); + } + InstanceType instance_type; { DisallowGarbageCollection no_gc; Tagged<HeapObject> raw = *obj; - if (SerializeHotObject(raw)) return; + if (SerializeTrustedExport(raw)) return; if (SerializeRoot(raw)) return; - if (SerializeBackReference(raw)) return; if (SerializeReadOnlyObjectReference(raw, &sink_)) return; + if (SerializeBackReference(raw)) return; + DCHECK(!trusted_serializer_.ReferenceMapContains(obj)); instance_type = raw->map()->instance_type(); CHECK(!InstanceTypeChecker::IsInstructionStream(instance_type)); } + // Past this point we should not see any (context-specific) maps anymore. + CHECK(!InstanceTypeChecker::IsMap(instance_type)); + // There should be no references to the global object embedded. + CHECK(!InstanceTypeChecker::IsJSGlobalProxy(instance_type) && + !InstanceTypeChecker::IsJSGlobalObject(instance_type)); + // Embedded FixedArrays that need rehashing must support rehashing. + CHECK_IMPLIES(obj->NeedsRehashing(), obj->CanBeRehashed()); + // We expect no instantiated function objects or contexts. + CHECK(!InstanceTypeChecker::IsJSFunction(instance_type) && + !InstanceTypeChecker::IsContext(instance_type)); + + SerializeGeneric(obj, slot_type); +} + +void CodeSerializer::SerializeDeferredObject(Handle<HeapObject> obj) { + SerializeGeneric(obj, SlotType::kAnySlot); +} + +void CodeSerializer::SerializeGeneric(Handle<HeapObject> heap_object, + SlotType slot_type) { + ReadOnlyRoots roots(isolate()); + InstanceType instance_type = heap_object->map()->instance_type(); if (InstanceTypeChecker::IsScript(instance_type)) { DirectHandle<FixedArray> host_options; DirectHandle<UnionOf<Smi, Symbol, Undefined>> context_data; { DisallowGarbageCollection no_gc; - Tagged<Script> script_obj = Cast<Script>(*obj); + Tagged<Script> script_obj = Cast<Script>(*heap_object); DCHECK(!script_obj->has_eval_origin()); // We want to differentiate between undefined and uninitialized_symbol for // context_data for now. It is hack to allow debugging for scripts that @@ -155,10 +226,13 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj, direct_handle(script_obj->host_defined_options(), isolate()); script_obj->set_host_defined_options(roots.empty_fixed_array()); } - SerializeGeneric(obj, slot_type); + { + ObjectSerializer serializer(this, heap_object, &sink_); + serializer.Serialize(slot_type); + } { DisallowGarbageCollection no_gc; - Tagged<Script> script_obj = Cast<Script>(*obj); + Tagged<Script> script_obj = Cast<Script>(*heap_object); script_obj->set_host_defined_options(*host_options); script_obj->set_context_data(*context_data); } @@ -169,7 +243,7 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj, bool restore_bytecode = false; { DisallowGarbageCollection no_gc; - Tagged<SharedFunctionInfo> sfi = Cast<SharedFunctionInfo>(*obj); + Tagged<SharedFunctionInfo> sfi = Cast<SharedFunctionInfo>(*heap_object); DCHECK(!sfi->IsApiFunction()); if (auto maybe_debug_info = sfi->TryGetDebugInfo(isolate())) { @@ -189,9 +263,12 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj, } } } - SerializeGeneric(obj, slot_type); + { + ObjectSerializer serializer(this, heap_object, &sink_); + serializer.Serialize(slot_type); + } DisallowGarbageCollection no_gc; - Tagged<SharedFunctionInfo> sfi = Cast<SharedFunctionInfo>(*obj); + Tagged<SharedFunctionInfo> sfi = Cast<SharedFunctionInfo>(*heap_object); if (restore_bytecode) { sfi->SetActiveBytecodeArray(debug_info->debug_bytecode_array(), isolate()); @@ -201,30 +278,12 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj, sfi->set_cached_tiering_decision(cached_tiering_decision); } return; - } else if (InstanceTypeChecker::IsUncompiledDataWithoutPreparseDataWithJob( - instance_type)) { - Handle<UncompiledDataWithoutPreparseDataWithJob> data = - TrustedCast<UncompiledDataWithoutPreparseDataWithJob>(obj); - Address job = data->job(); - data->set_job(kNullAddress); - SerializeGeneric(data, slot_type); - data->set_job(job); - return; - } else if (InstanceTypeChecker::IsUncompiledDataWithPreparseDataAndJob( - instance_type)) { - Handle<UncompiledDataWithPreparseDataAndJob> data = - TrustedCast<UncompiledDataWithPreparseDataAndJob>(obj); - Address job = data->job(); - data->set_job(kNullAddress); - SerializeGeneric(data, slot_type); - data->set_job(job); - return; } else if (InstanceTypeChecker::IsScopeInfo(instance_type)) { // TODO(ishell): define a dedicated instance type for DependentCode and // serialize DependentCode objects as an empty_dependent_code instead // of customizing ScopeInfo serialization. static_assert(DEPENDENT_CODE_TYPE == WEAK_ARRAY_LIST_TYPE); - Handle<ScopeInfo> scope_info = Cast<ScopeInfo>(obj); + Handle<ScopeInfo> scope_info = Cast<ScopeInfo>(heap_object); DirectHandle<DependentCode> dependent_code; bool restore_dependent_code = false; if (scope_info->SloppyEvalCanExtendVars()) { @@ -239,40 +298,16 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj, scope_info->set_dependent_code(empty_dependent_code); } } - SerializeGeneric(scope_info, slot_type); + { + ObjectSerializer serializer(this, scope_info, &sink_); + serializer.Serialize(slot_type); + } if (restore_dependent_code) { scope_info->set_dependent_code(*dependent_code); } return; } - // NOTE(mmarchini): If we try to serialize an InterpreterData our process - // will crash since it stores a code object. Instead, we serialize the - // bytecode array stored within the InterpreterData, which is the important - // information. On deserialization we'll create our code objects again, if - // --interpreted-frames-native-stack is on. See v8:9122 for more context - if (V8_UNLIKELY(isolate()->interpreted_frames_native_stack()) && - IsInterpreterData(*obj)) { - obj = - handle(TrustedCast<InterpreterData>(*obj)->bytecode_array(), isolate()); - } - - // Past this point we should not see any (context-specific) maps anymore. - CHECK(!InstanceTypeChecker::IsMap(instance_type)); - // There should be no references to the global object embedded. - CHECK(!InstanceTypeChecker::IsJSGlobalProxy(instance_type) && - !InstanceTypeChecker::IsJSGlobalObject(instance_type)); - // Embedded FixedArrays that need rehashing must support rehashing. - CHECK_IMPLIES(obj->NeedsRehashing(), obj->CanBeRehashed()); - // We expect no instantiated function objects or contexts. - CHECK(!InstanceTypeChecker::IsJSFunction(instance_type) && - !InstanceTypeChecker::IsContext(instance_type)); - - SerializeGeneric(obj, slot_type); -} - -void CodeSerializer::SerializeGeneric(Handle<HeapObject> heap_object, - SlotType slot_type) { // Object has not yet been serialized. Serialize it here. ObjectSerializer serializer(this, heap_object, &sink_); serializer.Serialize(slot_type); @@ -331,17 +366,16 @@ void CreateInterpreterDataForDeserializedCode( } } -class StressOffThreadDeserializeThread final : public base::Thread { +class StressOffThreadDeserializeThread final : public ParkingThread { public: explicit StressOffThreadDeserializeThread(Isolate* isolate, AlignedCachedData* cached_data) - : Thread( + : ParkingThread( base::Thread::Options("StressOffThreadDeserializeThread", 2 * MB)), isolate_(isolate), cached_data_(cached_data) {} void Run() final { - base::FlushDenormalsScope denormals_scope(isolate_->flush_denormals()); LocalIsolate local_isolate(isolate_, ThreadKind::kBackground); UnparkedScope unparked_scope(&local_isolate); LocalHandleScope handle_scope(&local_isolate); @@ -480,7 +514,7 @@ MaybeDirectHandle<SharedFunctionInfo> CodeSerializer::Deserialize( if (v8_flags.stress_background_compile) { StressOffThreadDeserializeThread thread(isolate, cached_data); CHECK(thread.Start()); - thread.Join(); + thread.ParkedJoin(isolate->main_thread_local_isolate()); return thread.Finalize(isolate, source, script_details); // TODO(leszeks): Compare off-thread deserialized data to on-thread. } @@ -502,7 +536,7 @@ MaybeDirectHandle<SharedFunctionInfo> CodeSerializer::Deserialize( const SerializedCodeData scd = SerializedCodeData::FromCachedData( isolate, cached_data, SerializedCodeData::SourceHash(source, wrapped_arguments, - script_details.origin_options), + script_details.origin_options, isolate), &sanity_check_result); if (sanity_check_result != SerializedCodeSanityCheckResult::kSuccess) { if (v8_flags.profile_deserialization) { @@ -731,13 +765,21 @@ CodeSerializer::FinishOffThreadDeserialize( return scope.CloseAndEscape(result); } -SerializedCodeData::SerializedCodeData(const std::vector<uint8_t>* payload, - const CodeSerializer* cs) { +SerializedCodeData::SerializedCodeData( + const std::vector<uint8_t>* untrusted_payload, + const std::vector<uint8_t>* external_references_payload, + const std::vector<uint8_t>* trusted_payload, const CodeSerializer* cs) { DisallowGarbageCollection no_gc; + size_t trusted_length = + external_references_payload->size() + trusted_payload->size(); + size_t payload_length = trusted_length + untrusted_payload->size(); + // Calculate sizes. - uint32_t size = kHeaderSize + static_cast<uint32_t>(payload->size()); + uint32_t size = base::checked_cast<uint32_t>(kHeaderSize + payload_length); + CHECK_LE(size, kMaxInt); DCHECK(IsAligned(size, kPointerAlignment)); + DCHECK(IsAligned(trusted_length, kPointerAlignment)); // Allocate backing store and create result data. AllocateData(size); @@ -748,20 +790,28 @@ SerializedCodeData::SerializedCodeData(const std::vector<uint8_t>* payload, // Set header values. SetMagicNumber(); SetHeaderValue(kVersionHashOffset, Version::Hash()); - SetHeaderValue(kSourceHashOffset, cs->source_hash()); + SetHeaderSourceHash(cs->source_hash()); SetHeaderValue(kFlagHashOffset, FlagList::Hash()); SetHeaderValue(kReadOnlySnapshotChecksumOffset, Snapshot::ExtractReadOnlySnapshotChecksum( cs->isolate()->snapshot_blob())); - SetHeaderValue(kPayloadLengthOffset, static_cast<uint32_t>(payload->size())); + SetHeaderValue(kPayloadLengthOffset, + base::checked_cast<uint32_t>(payload_length)); + SetHeaderValue(kTrustedPayloadLengthOffset, + base::checked_cast<uint32_t>(trusted_length)); // Zero out any padding in the header. + static_assert(kUnalignedHeaderSize <= kHeaderSize); std::fill_n(data_ + kUnalignedHeaderSize, kHeaderSize - kUnalignedHeaderSize, 0); // Copy serialized data. - CopyBytes(data_ + kHeaderSize, payload->data(), - static_cast<size_t>(payload->size())); + CopyBytes(data_ + kHeaderSize, external_references_payload->data(), + external_references_payload->size()); + CopyBytes(data_ + kHeaderSize + external_references_payload->size(), + trusted_payload->data(), trusted_payload->size()); + CopyBytes(data_ + kHeaderSize + trusted_length, untrusted_payload->data(), + untrusted_payload->size()); uint32_t checksum = v8_flags.verify_snapshot_checksum ? Checksum(ChecksummedContent()) : 0; SetHeaderValue(kChecksumOffset, checksum); @@ -769,7 +819,7 @@ SerializedCodeData::SerializedCodeData(const std::vector<uint8_t>* payload, SerializedCodeSanityCheckResult SerializedCodeData::SanityCheck( uint32_t expected_ro_snapshot_checksum, - uint32_t expected_source_hash) const { + SourceHash expected_source_hash) const { SerializedCodeSanityCheckResult result = SanityCheckWithoutSource(expected_ro_snapshot_checksum); if (result != SerializedCodeSanityCheckResult::kSuccess) return result; @@ -783,16 +833,16 @@ SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckJustSource( if (!script_details.wrapped_arguments.is_null()) { wrapped_arguments = script_details.wrapped_arguments.ToHandleChecked(); } - return SanityCheckJustSource( - SourceHash(source, wrapped_arguments, script_details.origin_options)); + return SanityCheckJustSource(SourceHash( + source, wrapped_arguments, script_details.origin_options, isolate)); } SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckJustSource( - uint32_t expected_source_hash) const { + SourceHash expected_source_hash) const { if (size_ < kHeaderSize) { return SerializedCodeSanityCheckResult::kInvalidHeader; } - uint32_t source_hash = GetHeaderValue(kSourceHashOffset); + SourceHash source_hash = GetHeaderSourceHash(); if (source_hash != expected_source_hash) { return SerializedCodeSanityCheckResult::kSourceMismatch; } @@ -826,6 +876,9 @@ SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckWithoutSource( if (payload_length > max_payload_length) { return SerializedCodeSanityCheckResult::kLengthMismatch; } + if (GetHeaderValue(kTrustedPayloadLengthOffset) > payload_length) { + return SerializedCodeSanityCheckResult::kLengthMismatch; + } if (v8_flags.verify_snapshot_checksum) { uint32_t checksum = GetHeaderValue(kChecksumOffset); if (Checksum(ChecksummedContent()) != checksum) { @@ -835,20 +888,84 @@ SerializedCodeSanityCheckResult SerializedCodeData::SanityCheckWithoutSource( return SerializedCodeSanityCheckResult::kSuccess; } -uint32_t SerializedCodeData::SourceHash( +void SerializedCodeData::SetHeaderSourceHash(const SourceHash& hash) { + memcpy(data_ + kSourceHashOffset, hash.data(), SourceHash::kSize); +} + +SerializedCodeData::SourceHash SerializedCodeData::GetHeaderSourceHash() const { + return SourceHash(data_ + kSourceHashOffset); +} + +namespace { + +void HashString(LITE_SHA256_CTX* ctx, Isolate* isolate, + DirectHandle<String> string) { + string = String::Flatten(isolate, string); + DisallowGarbageCollection no_gc; + uint32_t length = string->length(); + SHA256_update(ctx, &length, sizeof(length)); + SharedStringAccessGuardIfNeeded access_guard(isolate); + String::FlatContent flat = string->GetFlatContent(no_gc, access_guard); + if (flat.IsOneByte()) { + base::Vector<const uint8_t> chars = flat.ToOneByteVector(); + SHA256_update(ctx, chars.begin(), chars.length()); + } else { + DCHECK(flat.IsTwoByte()); + base::Vector<const base::uc16> chars = flat.ToUC16Vector(); + SHA256_update(ctx, chars.begin(), chars.length() * sizeof(base::uc16)); + } +} + +} // namespace + +SerializedCodeData::SourceHash::SourceHash( DirectHandle<String> source, DirectHandle<FixedArray> wrapped_arguments, - ScriptOriginOptions origin_options) { - using LengthField = base::BitField<uint32_t, 0, 29>; - static_assert(String::kMaxLength <= LengthField::kMax, - "String length must fit into a LengthField"); - using HasWrappedArgumentsField = LengthField::Next<bool, 1>; - using IsModuleField = HasWrappedArgumentsField::Next<bool, 1>; + ScriptOriginOptions origin_options, Isolate* isolate) { + if (v8_flags.code_cache_source_hash_sha256) { + LITE_SHA256_CTX ctx; + SHA256_init(&ctx); + + // Hash compilation-affecting metadata bits into the SHA-256 context. + // Only IsModule() in ScriptOriginOptions affects how JS source text is + // parsed and compiled into bytecode. + uint8_t flags = 0; + if (!wrapped_arguments.is_null()) flags |= 1; + if (origin_options.IsModule()) flags |= 2; + SHA256_update(&ctx, &flags, sizeof(flags)); + + // For CompileFunction, wrapped_arguments holds the parameter names (while + // source only holds the function body). Hash the argument count and each + // length-prefixed parameter string so parameter changes invalidate the + // cache. + if (!wrapped_arguments.is_null()) { + uint32_t argc = wrapped_arguments->ulength().value(); + SHA256_update(&ctx, &argc, sizeof(argc)); + for (uint32_t i = 0; i < argc; ++i) { + DirectHandle<String> arg(Cast<String>(wrapped_arguments->get(i)), + isolate); + HashString(&ctx, isolate, arg); + } + } - uint32_t hash = 0; - hash = LengthField::update(hash, source->length()); - hash = HasWrappedArgumentsField::update(hash, !wrapped_arguments.is_null()); - hash = IsModuleField::update(hash, origin_options.IsModule()); - return hash; + HashString(&ctx, isolate, source); + + const uint8_t* digest = SHA256_final(&ctx); + std::copy_n(digest, kSizeOfSha256Digest, data_.data()); + } else { + data_.fill(0); + using LengthField = base::BitField<uint32_t, 0, 29>; + static_assert(String::kMaxLength <= LengthField::kMax, + "String length must fit into a LengthField"); + using HasWrappedArgumentsField = LengthField::Next<bool, 1>; + using IsModuleField = HasWrappedArgumentsField::Next<bool, 1>; + + uint32_t hash = 0; + hash = LengthField::update(hash, source->length()); + hash = HasWrappedArgumentsField::update(hash, !wrapped_arguments.is_null()); + hash = IsModuleField::update(hash, origin_options.IsModule()); + base::WriteLittleEndianValue<uint32_t>( + reinterpret_cast<Address>(data_.data()), hash); + } } // Return ScriptData object and relinquish ownership over it to the caller. @@ -861,20 +978,28 @@ AlignedCachedData* SerializedCodeData::GetScriptData() { return result; } -base::Vector<const uint8_t> SerializedCodeData::Payload() const { - const uint8_t* payload = data_ + kHeaderSize; +base::Vector<const uint8_t> SerializedCodeData::UntrustedPayload() const { + uint32_t trusted_length = GetHeaderValue(kTrustedPayloadLengthOffset); + const uint8_t* payload = data_ + kHeaderSize + trusted_length; DCHECK(IsAligned(reinterpret_cast<intptr_t>(payload), kPointerAlignment)); - int length = GetHeaderValue(kPayloadLengthOffset); + uint32_t length = GetHeaderValue(kPayloadLengthOffset) - trusted_length; DCHECK_EQ(data_ + size_, payload + length); return base::Vector<const uint8_t>(payload, length); } +base::Vector<const uint8_t> SerializedCodeData::TrustedPayload() const { + const uint8_t* payload = data_ + kHeaderSize; + DCHECK(IsAligned(reinterpret_cast<intptr_t>(payload), kPointerAlignment)); + uint32_t length = GetHeaderValue(kTrustedPayloadLengthOffset); + return base::Vector<const uint8_t>(payload, length); +} + SerializedCodeData::SerializedCodeData(const AlignedCachedData* data) : SerializedData(const_cast<uint8_t*>(data->data()), data->length()) {} SerializedCodeData SerializedCodeData::FromCachedData( Isolate* isolate, AlignedCachedData* cached_data, - uint32_t expected_source_hash, + SourceHash expected_source_hash, SerializedCodeSanityCheckResult* rejection_result) { DisallowGarbageCollection no_gc; SerializedCodeData scd(cached_data); diff --git a/deps/v8/src/snapshot/code-serializer.h b/deps/v8/src/snapshot/code-serializer.h index 6cfafc4d26b1..a665c3ad6fe7 100644 --- a/deps/v8/src/snapshot/code-serializer.h +++ b/deps/v8/src/snapshot/code-serializer.h @@ -5,12 +5,16 @@ #ifndef V8_SNAPSHOT_CODE_SERIALIZER_H_ #define V8_SNAPSHOT_CODE_SERIALIZER_H_ +#include <array> #include <optional> #include "src/base/macros.h" #include "src/codegen/script-details.h" #include "src/snapshot/serializer.h" #include "src/snapshot/snapshot-data.h" +#include "src/snapshot/snapshot-source-sink.h" +#include "src/snapshot/trusted-section-serializer.h" +#include "src/utils/sha-256.h" namespace v8 { namespace internal { @@ -77,71 +81,58 @@ struct OffThreadDeserializeData { std::optional<SerializedCodeSanityCheckResult> source_sanity_check_result; }; -class CodeSerializer : public Serializer { - public: - CodeSerializer(const CodeSerializer&) = delete; - CodeSerializer& operator=(const CodeSerializer&) = delete; - V8_EXPORT_PRIVATE static ScriptCompiler::CachedData* Serialize( - Isolate* isolate, Handle<SharedFunctionInfo> info); - - AlignedCachedData* SerializeSharedFunctionInfo( - Handle<SharedFunctionInfo> info); - - V8_WARN_UNUSED_RESULT static MaybeDirectHandle<SharedFunctionInfo> - Deserialize(Isolate* isolate, AlignedCachedData* cached_data, - DirectHandle<String> source, const ScriptDetails& script_details, - MaybeDirectHandle<Script> maybe_cached_script = {}); - - static void StartDeserializeOffThread(LocalIsolate* isolate, - AlignedCachedData* cached_data, - OffThreadDeserializeData* data); - - V8_WARN_UNUSED_RESULT static bool NotifySourceTextAvailable( - Isolate* isolate, OffThreadDeserializeData* data, - const AlignedCachedData* cached_data, DirectHandle<String> source, - const ScriptDetails& script_details); - - V8_WARN_UNUSED_RESULT static MaybeDirectHandle<SharedFunctionInfo> - FinishOffThreadDeserialize( - Isolate* isolate, OffThreadDeserializeData&& data, - AlignedCachedData* cached_data, DirectHandle<String> source, - const ScriptDetails& script_details, - BackgroundMergeTask* background_merge_task = nullptr); - - uint32_t source_hash() const { return source_hash_; } - - protected: - CodeSerializer(Isolate* isolate, uint32_t source_hash); - ~CodeSerializer() override { OutputStatistics("CodeSerializer"); } - - void SerializeGeneric(Handle<HeapObject> heap_object, SlotType slot_type); - - private: - void SerializeObjectImpl(Handle<HeapObject> o, SlotType slot_type) override; - - DISALLOW_GARBAGE_COLLECTION(no_gc_) - uint32_t source_hash_; -}; - // Wrapper around ScriptData to provide code-serializer-specific functionality. class SerializedCodeData : public SerializedData { public: - // The data header consists of uint32_t-sized entries: - static const uint32_t kVersionHashOffset = kMagicNumberOffset + kUInt32Size; - static const uint32_t kSourceHashOffset = kVersionHashOffset + kUInt32Size; - static const uint32_t kFlagHashOffset = kSourceHashOffset + kUInt32Size; - static const uint32_t kReadOnlySnapshotChecksumOffset = + class SourceHash { + public: + V8_EXPORT_PRIVATE SourceHash(DirectHandle<String> source, + DirectHandle<FixedArray> wrapped_arguments, + ScriptOriginOptions origin_options, + Isolate* isolate); + + static constexpr uint32_t kSize = kSizeOfSha256Digest; + const uint8_t* data() const { return data_.data(); } + + bool operator==(const SourceHash& other) const { + return data_ == other.data_; + } + bool operator!=(const SourceHash& other) const { return !(*this == other); } + + private: + friend class SerializedCodeData; + explicit SourceHash(const uint8_t* bytes) { + std::copy_n(bytes, kSizeOfSha256Digest, data_.data()); + } + + std::array<uint8_t, kSizeOfSha256Digest> data_; + }; + + // The data header consists of uint32_t-sized entries (except for the 256-bit + // source hash): + static constexpr uint32_t kVersionHashOffset = + kMagicNumberOffset + kUInt32Size; + static constexpr uint32_t kSourceHashOffset = + kVersionHashOffset + kUInt32Size; + static constexpr uint32_t kFlagHashOffset = + kSourceHashOffset + kSizeOfSha256Digest; + static constexpr uint32_t kReadOnlySnapshotChecksumOffset = kFlagHashOffset + kUInt32Size; - static const uint32_t kPayloadLengthOffset = + static constexpr uint32_t kPayloadLengthOffset = kReadOnlySnapshotChecksumOffset + kUInt32Size; - static const uint32_t kChecksumOffset = kPayloadLengthOffset + kUInt32Size; - static const uint32_t kUnalignedHeaderSize = kChecksumOffset + kUInt32Size; - static const uint32_t kHeaderSize = POINTER_SIZE_ALIGN(kUnalignedHeaderSize); + static constexpr uint32_t kTrustedPayloadLengthOffset = + kPayloadLengthOffset + kUInt32Size; + static constexpr uint32_t kChecksumOffset = + kTrustedPayloadLengthOffset + kUInt32Size; + static constexpr uint32_t kUnalignedHeaderSize = + kChecksumOffset + kUInt32Size; + static constexpr uint32_t kHeaderSize = + POINTER_SIZE_ALIGN(kUnalignedHeaderSize); // Used when consuming. static SerializedCodeData FromCachedData( Isolate* isolate, AlignedCachedData* cached_data, - uint32_t expected_source_hash, + SourceHash expected_source_hash, SerializedCodeSanityCheckResult* rejection_result); // For cached data which is consumed before the source is available (e.g. // off-thread). @@ -157,18 +148,18 @@ class SerializedCodeData : public SerializedData { const ScriptDetails& script_details, SerializedCodeSanityCheckResult* rejection_result); - // Used when producing. - SerializedCodeData(const std::vector<uint8_t>* payload, + // Used when producing. The trusted section starts with the external + // references. + SerializedCodeData(const std::vector<uint8_t>* untrusted_payload, + const std::vector<uint8_t>* external_references_payload, + const std::vector<uint8_t>* trusted_payload, const CodeSerializer* cs); // Return ScriptData object and relinquish ownership over it to the caller. AlignedCachedData* GetScriptData(); - base::Vector<const uint8_t> Payload() const; - - static uint32_t SourceHash(DirectHandle<String> source, - DirectHandle<FixedArray> wrapped_arguments, - ScriptOriginOptions origin_options); + base::Vector<const uint8_t> UntrustedPayload() const; + base::Vector<const uint8_t> TrustedPayload() const; private: friend class CodeSerializer; @@ -176,6 +167,9 @@ class SerializedCodeData : public SerializedData { SerializedCodeData(const uint8_t* data, int size) : SerializedData(const_cast<uint8_t*>(data), size) {} + void SetHeaderSourceHash(const SourceHash& hash); + SourceHash GetHeaderSourceHash() const; + base::Vector<const uint8_t> ChecksummedContent() const { return base::Vector<const uint8_t>(data_ + kHeaderSize, size_ - kHeaderSize); @@ -183,16 +177,85 @@ class SerializedCodeData : public SerializedData { SerializedCodeSanityCheckResult SanityCheck( uint32_t expected_ro_snapshot_checksum, - uint32_t expected_source_hash) const; + SourceHash expected_source_hash) const; SerializedCodeSanityCheckResult SanityCheckJustSource( Isolate* isolate, DirectHandle<String> source, const ScriptDetails& script_details) const; SerializedCodeSanityCheckResult SanityCheckJustSource( - uint32_t expected_source_hash) const; + SourceHash expected_source_hash) const; SerializedCodeSanityCheckResult SanityCheckWithoutSource( uint32_t expected_ro_snapshot_checksum) const; }; +class CodeSerializer : public Serializer { + public: + using SourceHash = SerializedCodeData::SourceHash; + + // The external pointer tags that a code cache may contain. + static constexpr ExternalPointerTag kSerializableExternalPointerTags[] = { + kExternalStringResourceTag}; + + CodeSerializer(const CodeSerializer&) = delete; + CodeSerializer& operator=(const CodeSerializer&) = delete; + V8_EXPORT_PRIVATE static ScriptCompiler::CachedData* Serialize( + Isolate* isolate, Handle<SharedFunctionInfo> info); + + AlignedCachedData* SerializeSharedFunctionInfo( + Handle<SharedFunctionInfo> info); + + V8_WARN_UNUSED_RESULT static MaybeDirectHandle<SharedFunctionInfo> + Deserialize(Isolate* isolate, AlignedCachedData* cached_data, + DirectHandle<String> source, const ScriptDetails& script_details, + MaybeDirectHandle<Script> maybe_cached_script = {}); + + static void StartDeserializeOffThread(LocalIsolate* isolate, + AlignedCachedData* cached_data, + OffThreadDeserializeData* data); + + V8_WARN_UNUSED_RESULT static bool NotifySourceTextAvailable( + Isolate* isolate, OffThreadDeserializeData* data, + const AlignedCachedData* cached_data, DirectHandle<String> source, + const ScriptDetails& script_details); + + V8_WARN_UNUSED_RESULT static MaybeDirectHandle<SharedFunctionInfo> + FinishOffThreadDeserialize( + Isolate* isolate, OffThreadDeserializeData&& data, + AlignedCachedData* cached_data, DirectHandle<String> source, + const ScriptDetails& script_details, + BackgroundMergeTask* background_merge_task = nullptr); + + SourceHash source_hash() const { return source_hash_; } + + protected: + CodeSerializer(Isolate* isolate, SourceHash source_hash); + ~CodeSerializer() override { OutputStatistics("CodeSerializer"); } + + void SerializeGeneric(Handle<HeapObject> heap_object, SlotType slot_type); + + private: + void SerializeObjectImpl(Handle<HeapObject> o, SlotType slot_type) override; + void SerializeDeferredObject(Handle<HeapObject> obj) override; + bool SerializeTrustedExport(Tagged<HeapObject> obj); + bool SerializeTrustedExternalReference( + ExternalReferenceEncoder::Value reference, + ExternalPointerTag tag) override; + void FinishSection() { + sink_.Put(kSynchronize, "EndOfUntrustedSection"); + OptimizeBackReferences(); + Pad(); + } + // Slices usually refer to the script source (e.g. debug magic comment + // values), which is an attached object: off-thread deserialization attaches + // a placeholder instead of the source. + bool SerializeSlicedStringsAsSequentialStrings() const override { + return true; + } + + DISALLOW_GARBAGE_COLLECTION(no_gc_) + SourceHash source_hash_; + TrustedSectionSerializer trusted_serializer_; +}; + } // namespace internal } // namespace v8 diff --git a/deps/v8/src/snapshot/context-deserializer.h b/deps/v8/src/snapshot/context-deserializer.h index 92181ef0d7a5..11256bd14ca1 100644 --- a/deps/v8/src/snapshot/context-deserializer.h +++ b/deps/v8/src/snapshot/context-deserializer.h @@ -27,8 +27,9 @@ class V8_EXPORT_PRIVATE ContextDeserializer final private: explicit ContextDeserializer(Isolate* isolate, const SnapshotData* data, bool can_rehash) - : Deserializer(isolate, data->Payload(), data->GetMagicNumber(), false, - can_rehash) {} + : Deserializer(isolate, data->Payload(), /* trusted_payload */ {}, + data->GetMagicNumber(), + /* deserializing_user_code */ false, can_rehash) {} // Deserialize a single object and the objects reachable from it. MaybeDirectHandle<Object> Deserialize( diff --git a/deps/v8/src/snapshot/context-serializer.cc b/deps/v8/src/snapshot/context-serializer.cc index b3bf4b8975ee..5c1996d0ea2d 100644 --- a/deps/v8/src/snapshot/context-serializer.cc +++ b/deps/v8/src/snapshot/context-serializer.cc @@ -79,6 +79,7 @@ void ContextSerializer::Serialize(Tagged<Context>* o, sink_.Put(kSynchronize, "Finished with api wrapper fields data"); } + OptimizeBackReferences(); Pad(); } @@ -127,10 +128,9 @@ void ContextSerializer::SerializeObjectImpl(Handle<HeapObject> obj, { DisallowGarbageCollection no_gc; Tagged<HeapObject> raw = *obj; - if (SerializeHotObject(raw)) return; if (SerializeRoot(raw)) return; - if (SerializeBackReference(raw)) return; if (SerializeReadOnlyObjectReference(raw, &sink_)) return; + if (SerializeBackReference(raw)) return; } if (startup_serializer_->SerializeUsingSharedHeapObjectCache(&sink_, obj)) { diff --git a/deps/v8/src/snapshot/deserializer.cc b/deps/v8/src/snapshot/deserializer.cc index 99d934927d49..3aea8fa8643d 100644 --- a/deps/v8/src/snapshot/deserializer.cc +++ b/deps/v8/src/snapshot/deserializer.cc @@ -9,6 +9,7 @@ #include "src/base/logging.h" #include "src/base/strong-alias.h" #include "src/codegen/assembler-inl.h" +#include "src/codegen/external-reference-encoder.h" #include "src/codegen/reloc-info-inl.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" @@ -33,6 +34,7 @@ #include "src/objects/trusted-object-inl.h" #include "src/roots/roots.h" #include "src/sandbox/bytecode-verifier.h" +#include "src/sandbox/check.h" #include "src/sandbox/js-dispatch-table-inl.h" #include "src/snapshot/embedded/embedded-data-inl.h" #include "src/snapshot/references.h" @@ -100,7 +102,7 @@ class SlotAccessorForHeapObject { return Write(*value, ref_type, slot_offset, mode); } - int WriteIndirectPointerTo(Tagged<HeapObject> value, WriteBarrierMode mode) { + int WriteTrustedPointerTo(Tagged<HeapObject> value, WriteBarrierMode mode) { // Only ExposedTrustedObjects can be referenced via indirect pointers, so // we must have one of these objects here. See the comments in // trusted-object.h for more details. @@ -110,12 +112,12 @@ class SlotAccessorForHeapObject { InstanceType instance_type = value->map()->instance_type(); SharedFlag shared = SharedFlag(HeapLayout::InAnySharedSpace(value)); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, shared); - IndirectPointerSlot dest = object_->RawIndirectPointerField(offset_, tag); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, shared); + TrustedPointerSlot dest = object_->RawTrustedPointerField(offset_, tag); dest.store(object); - WriteBarrier::ForIndirectPointer(*object_, dest, value, mode); + WriteBarrier::ForTrustedPointer(*object_, dest, value, mode); return 1; } @@ -165,7 +167,7 @@ class SlotAccessorForRootSlots { int slot_offset, WriteBarrierMode mode) { return Write(*value, ref_type, slot_offset, mode); } - int WriteIndirectPointerTo(Tagged<HeapObject> value, WriteBarrierMode mode) { + int WriteTrustedPointerTo(Tagged<HeapObject> value, WriteBarrierMode mode) { UNREACHABLE(); } int WriteProtectedPointerTo(Tagged<TrustedObject> value, @@ -209,7 +211,7 @@ class SlotAccessorForHandle { *handle_ = value; return 1; } - int WriteIndirectPointerTo(Tagged<HeapObject> value, WriteBarrierMode mode) { + int WriteTrustedPointerTo(Tagged<HeapObject> value, WriteBarrierMode mode) { UNREACHABLE(); } int WriteProtectedPointerTo(Tagged<TrustedObject> value, @@ -228,8 +230,8 @@ int Deserializer<IsolateT>::WriteHeapPointer(SlotAccessor slot_accessor, Tagged<HeapObject> heap_object, ReferenceDescriptor descr, WriteBarrierMode mode) { - if (descr.is_indirect_pointer) { - return slot_accessor.WriteIndirectPointerTo(heap_object, mode); + if (descr.is_trusted_pointer) { + return slot_accessor.WriteTrustedPointerTo(heap_object, mode); } else { return slot_accessor.Write(heap_object, descr.type, 0, mode); } @@ -240,8 +242,8 @@ template <typename SlotAccessor> int Deserializer<IsolateT>::WriteHeapPointer( SlotAccessor slot_accessor, DirectHandle<HeapObject> heap_object, ReferenceDescriptor descr, WriteBarrierMode mode) { - if (descr.is_indirect_pointer) { - return slot_accessor.WriteIndirectPointerTo(*heap_object, mode); + if (descr.is_trusted_pointer) { + return slot_accessor.WriteTrustedPointerTo(*heap_object, mode); } else if (descr.is_protected_pointer) { DCHECK(IsTrustedObject(*heap_object)); return slot_accessor.WriteProtectedPointerTo( @@ -256,10 +258,10 @@ int Deserializer<IsolateT>::WriteExternalPointer(Tagged<HeapObject> host, ExternalPointerSlot dest, Address value, ExternalPointerTag tag) { - DCHECK(!next_reference_is_weak_ && !next_reference_is_indirect_pointer_ && + DCHECK(!next_reference_is_weak_ && !next_reference_is_trusted_pointer_ && !next_reference_is_protected_pointer); - #ifdef V8_ENABLE_SANDBOX +#ifdef V8_ENABLE_SANDBOX ExternalPointerTable::ManagedResource* managed_resource = nullptr; ExternalPointerTable* owning_table = nullptr; ExternalPointerHandle original_handle = kNullExternalPointerHandle; @@ -322,14 +324,13 @@ int GetNumApiReferences(LocalIsolate* isolate) { return 0; } } // namespace template <typename IsolateT> -Deserializer<IsolateT>::Deserializer(IsolateT* isolate, - base::Vector<const uint8_t> payload, - uint32_t magic_number, - bool deserializing_user_code, - bool can_rehash) +Deserializer<IsolateT>::Deserializer( + IsolateT* isolate, base::Vector<const uint8_t> untrusted_payload, + base::Vector<const uint8_t> trusted_payload, uint32_t magic_number, + bool deserializing_user_code, bool can_rehash) : isolate_(isolate), attached_objects_(isolate), - source_(payload), + source_(untrusted_payload), magic_number_(magic_number), new_maps_(isolate), new_allocation_sites_(isolate), @@ -339,6 +340,11 @@ Deserializer<IsolateT>::Deserializer(IsolateT* isolate, function_template_infos_(isolate), new_scripts_(isolate), new_exposed_trusted_objects_(isolate), + trusted_payload_(trusted_payload), + // Without the sandbox, trusted objects are part of the untrusted section. + section_(deserializing_user_code && V8_ENABLE_SANDBOX_BOOL + ? Section::kUntrusted + : Section::kCombined), deserializing_user_code_(deserializing_user_code), should_rehash_((v8_flags.rehash_snapshot && can_rehash) || deserializing_user_code), @@ -419,12 +425,64 @@ void Deserializer<IsolateT>::DeserializeDeferredObjects() { if (v8_flags.trace_deserialization) { PrintF("-- Deferred objects\n"); } - for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) { + for (uint8_t code = source_.Get(); code != kSynchronize; + code = source_.Get()) { SnapshotSpace space = NewObject::Decode(code); ReadObject(space); } } +template <typename IsolateT> +DirectHandle<HeapObject> Deserializer<IsolateT>::DeserializeUntrustedSection() { + // The trusted section starts with the external references that the untrusted + // section refers to by index. + SnapshotByteSource table(trusted_payload_); + external_references_.resize(table.GetUint30()); + if (!external_references_.empty()) { + table.CopyRaw( + external_references_.data(), + external_references_.size() * sizeof(EncodedExternalReference)); + } + trusted_payload_ += table.position(); + DirectHandle<HeapObject> result = ReadObject(); + DeserializeDeferredObjects(); + while (source_.Peek() != kSynchronize) { + ReadObject(); + DeserializeDeferredObjects(); + } +#ifdef DEBUG + DCHECK_EQ(kSynchronize, source_.Get()); + while (source_.HasMore()) DCHECK_EQ(kNop, source_.Get()); + DCHECK_EQ(num_unresolved_forward_refs_, 0); + DCHECK(unresolved_forward_refs_.empty()); +#endif + return result; +} + +template <typename IsolateT> +void Deserializer<IsolateT>::DeserializeTrustedSection() { + if (v8_flags.trace_deserialization) { + PrintF("-- Trusted section\n"); + } + source_.Reset(trusted_payload_); + section_ = Section::kTrusted; + untrusted_back_refs_ = std::exchange(back_refs_, {}); + num_fixed_back_refs_ = 0; + DirectHandleVector<HeapObject> trusted_exports(isolate()); + while (source_.Peek() != kSynchronize) { + trusted_exports.push_back(ReadObject()); + } + DCHECK_EQ(kSynchronize, source_.Get()); + for (const auto& [index, ref] : trusted_export_refs_) { + // TODO(573671140): With CSS off-thread direct handles can only be + // dereferenced on the stack. + DirectHandle<HeapObject> target = trusted_exports[index]; + WriteHeapPointer( + SlotAccessorForHeapObject::ForSlotOffset(ref.object, ref.offset), + *target, ref.descr); + } +} + template <typename IsolateT> void Deserializer<IsolateT>::LogNewMapEvents() { if (V8_LIKELY(!v8_flags.log_maps)) return; @@ -513,8 +571,6 @@ void PostProcessExternalString(Tagged<ExternalString> string, Isolate* isolate) { DisallowGarbageCollection no_gc; string->InitResourceDataAfterDeserialization(isolate); - isolate->heap()->UpdateExternalString(string, 0, - string->ExternalPayloadSize()); isolate->heap()->RegisterExternalString(string); } @@ -716,13 +772,13 @@ void Deserializer<IsolateT>::PostProcessNewObject(DirectHandle<Map> map, template <typename IsolateT> typename Deserializer<IsolateT>::ReferenceDescriptor Deserializer<IsolateT>::GetAndResetNextReferenceDescriptor() { - DCHECK(!(next_reference_is_weak_ && next_reference_is_indirect_pointer_)); + DCHECK(!(next_reference_is_weak_ && next_reference_is_trusted_pointer_)); ReferenceDescriptor desc; desc.type = next_reference_is_weak_ ? HeapObjectReferenceType::WEAK : HeapObjectReferenceType::STRONG; next_reference_is_weak_ = false; - desc.is_indirect_pointer = next_reference_is_indirect_pointer_; - next_reference_is_indirect_pointer_ = false; + desc.is_trusted_pointer = next_reference_is_trusted_pointer_; + next_reference_is_trusted_pointer_ = false; desc.is_protected_pointer = next_reference_is_protected_pointer; next_reference_is_protected_pointer = false; return desc; @@ -742,7 +798,6 @@ Handle<HeapObject> Deserializer<IsolateT>::GetBackReferencedObject( // a thin string, then it should also update the backref handle. DCHECK(!IsThinString(*obj)); - hot_objects_.Add(obj); DCHECK(!HasWeakHeapObjectTag(*obj)); return obj; } @@ -774,15 +829,20 @@ AllocationType SpaceToAllocation(SnapshotSpace space) { template <typename IsolateT> Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) { - const int size_in_tagged = source_.GetUint30(); - const int size_in_bytes = size_in_tagged * kTaggedSize; - // The map can't be a forward ref. If you want the map to be a forward ref, // then you're probably serializing the meta-map, in which case you want to // use the kNewContextlessMetaMap/kNewContextfulMetaMap bytecode. DCHECK_NE(source()->Peek(), kRegisterPendingForwardRef); DirectHandle<Map> map = Cast<Map>(ReadObject()); + // Fixed-size objects don't serialize their size, see SerializePrologue. + const int instance_size_in_words = map->instance_size_in_words(); + const uint32_t size_in_tagged = + instance_size_in_words == kVariableSizeSentinel + ? source_.GetUint30() + : static_cast<uint32_t>(instance_size_in_words); + const uint32_t size_in_bytes = size_in_tagged * kTaggedSize; + AllocationType allocation = SpaceToAllocation(space); // When sharing a string table, all in-place internalizable and internalized @@ -895,8 +955,8 @@ Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) { template <typename IsolateT> Handle<HeapObject> Deserializer<IsolateT>::ReadMetaMap(SnapshotSpace space) { - const int size_in_tagged = source_.GetUint30(); - const int size_in_bytes = size_in_tagged * kTaggedSize; + const uint32_t size_in_bytes = Map::kSize; + const uint32_t size_in_tagged = size_in_bytes / kTaggedSize; const InstanceType instance_type = static_cast<InstanceType>(source_.GetUint30()); @@ -929,7 +989,7 @@ template <typename SlotAccessor> int Deserializer<IsolateT>::ReadRepeatedRoot(SlotAccessor slot_accessor, int repeat_count) { DCHECK(!next_reference_is_weak_); - DCHECK(!next_reference_is_indirect_pointer_); + DCHECK(!next_reference_is_trusted_pointer_); DCHECK(!next_reference_is_protected_pointer); CHECK_LE(2, repeat_count); @@ -974,6 +1034,8 @@ constexpr uint8_t VerifyBytecodeCount(uint8_t bytecode) { #define CASE_R8(byte_code) CASE_R4(byte_code) : case CASE_R4(byte_code + 4) #define CASE_R16(byte_code) CASE_R8(byte_code) : case CASE_R8(byte_code + 8) #define CASE_R32(byte_code) CASE_R16(byte_code) : case CASE_R16(byte_code + 16) +#define CASE_R64(byte_code) CASE_R32(byte_code) : case CASE_R32(byte_code + 32) +#define CASE_R128(byte_code) CASE_R64(byte_code) : case CASE_R64(byte_code + 64) // This generates a case range for all the spaces. // clang-format off @@ -1064,24 +1126,32 @@ int Deserializer<IsolateT>::ReadSingleBytecodeData(uint8_t data, return ReadClearedWeakReference(data, slot_accessor); case kWeakPrefix: return ReadWeakPrefix(data, slot_accessor); - case kIndirectPointerPrefix: - return ReadIndirectPointerPrefix(data, slot_accessor); - case kInitializeSelfIndirectPointer: - return ReadInitializeSelfIndirectPointer(data, slot_accessor); + case kTrustedPointerPrefix: + return ReadTrustedPointerPrefix(data, slot_accessor); + case kInitializeSelfTrustedPointer: + return ReadInitializeSelfTrustedPointer(data, slot_accessor); case kAllocateJSDispatchEntry: return ReadAllocateJSDispatchEntry(data, slot_accessor); case kJSDispatchEntry: return ReadJSDispatchEntry(data, slot_accessor); case kProtectedPointerPrefix: return ReadProtectedPointerPrefix(data, slot_accessor); + case kTrustedExportRef: + return ReadTrustedExportRef(data, slot_accessor); + case kUntrustedRef: + return ReadUntrustedRef(data, slot_accessor); + case kTrustedExternalRef: + return ReadTrustedExternalRef(data, slot_accessor); + case kRegisterFixedBackref: + return ReadRegisterFixedBackref(data, slot_accessor); case CASE_RANGE(kRootArrayConstants, 32): return ReadRootArrayConstants(data, slot_accessor); - case CASE_RANGE(kHotObject, 8): - return ReadHotObject(data, slot_accessor); case CASE_RANGE(kFixedRawData, 32): return ReadFixedRawData(data, slot_accessor); case CASE_RANGE(kFixedRepeatRoot, 16): return ReadFixedRepeatRoot(data, slot_accessor); + case CASE_RANGE(kFixedBackref, 128): + return ReadFixedBackref(data, slot_accessor); #ifdef DEBUG #define UNUSED_CASE(byte_code) \ @@ -1154,13 +1224,30 @@ int Deserializer<IsolateT>::ReadBackref(uint8_t data, GetAndResetNextReferenceDescriptor()); } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadRegisterFixedBackref( + uint8_t data, SlotAccessor slot_accessor) { + uint32_t index = source_.GetUint30(); + Handle<HeapObject> heap_object = GetBackReferencedObject(index); + SBXCHECK_LT(num_fixed_back_refs_, kFixedBackrefCount); + fixed_back_refs_[num_fixed_back_refs_++] = heap_object.location(); + if (v8_flags.trace_deserialization) { + PrintF("%*sRegisterFixedBackref [%u]\n", depth_, "", index); + } + return WriteHeapPointer(slot_accessor, heap_object, + GetAndResetNextReferenceDescriptor()); +} + // Reference an object in the read-only heap. template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadReadOnlyHeapRef(uint8_t data, SlotAccessor slot_accessor) { - uint32_t chunk_index = source_.GetUint30(); - uint32_t chunk_offset = source_.GetUint30(); + uint32_t encoded = source_.GetUint30(); + uint32_t chunk_index = encoded >> kReadOnlyHeapRefOffsetBits; + uint32_t chunk_offset = (encoded & ((1u << kReadOnlyHeapRefOffsetBits) - 1)) + << kObjectAlignmentBits; ReadOnlySpace* read_only_space = isolate()->heap()->read_only_space(); ReadOnlyPage* page = read_only_space->pages()[chunk_index]; @@ -1185,7 +1272,8 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadRootArray(uint8_t data, SlotAccessor slot_accessor) { - int id = source_.GetUint30(); + uint32_t id = source_.GetUint30(); + SBXCHECK_LT(id, RootsTable::kEntriesCount); RootIndex root_index = static_cast<RootIndex>(id); DirectHandle<HeapObject> heap_object = Cast<HeapObject>(isolate()->root_handle(root_index)); @@ -1194,7 +1282,6 @@ int Deserializer<IsolateT>::ReadRootArray(uint8_t data, PrintF("%*sRootArray [%u] : %s\n", depth_, "", id, RootsTable::name(root_index)); } - hot_objects_.Add(heap_object); return WriteHeapPointer( slot_accessor, heap_object, GetAndResetNextReferenceDescriptor(), RootsTable::IsReadOnly(root_index) ? SKIP_WRITE_BARRIER @@ -1207,7 +1294,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadStartupObjectCache(uint8_t data, SlotAccessor slot_accessor) { - int cache_index = source_.GetUint30(); + uint32_t cache_index = source_.GetUint30(); // TODO(leszeks): Could we use the address of the startup_object_cache // entry as a Handle backing? Tagged<HeapObject> heap_object = Cast<HeapObject>( @@ -1227,7 +1314,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadSharedHeapObjectCache( uint8_t data, SlotAccessor slot_accessor) { - int cache_index = source_.GetUint30(); + uint32_t cache_index = source_.GetUint30(); // TODO(leszeks): Could we use the address of the // shared_heap_object_cache entry as a Handle backing? Tagged<HeapObject> heap_object = Cast<HeapObject>( @@ -1260,6 +1347,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadExternalReference(uint8_t data, SlotAccessor slot_accessor) { + SBXCHECK(InTrustedSection()); DCHECK_IMPLIES(data == kSandboxedExternalReference, V8_ENABLE_SANDBOX_BOOL); Address address = ReadExternalReferenceCase(); ExternalPointerTag tag = kExternalPointerNullTag; @@ -1279,6 +1367,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadRawExternalReference( uint8_t data, SlotAccessor slot_accessor) { + SBXCHECK(InTrustedSection()); DCHECK_IMPLIES(data == kSandboxedExternalReference, V8_ENABLE_SANDBOX_BOOL); Address address; source_.CopyRaw(&address, kSystemPointerSize); @@ -1301,7 +1390,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadAttachedReference(uint8_t data, SlotAccessor slot_accessor) { - int index = source_.GetUint30(); + uint32_t index = source_.GetUint30(); DirectHandle<HeapObject> heap_object = attached_objects_[index]; if (v8_flags.trace_deserialization) { PrintF("%*sAttachedReference [%u] : ", depth_, "", index); @@ -1333,7 +1422,7 @@ int Deserializer<IsolateT>::ReadResolvePendingForwardRef( DCHECK(slot_accessor.offset() == sizeof(HeapObject) || slot_accessor.offset() == ExposedTrustedObject::kHeaderSize); DirectHandle<HeapObject> obj = slot_accessor.object(); - int index = source_.GetUint30(); + uint32_t index = source_.GetUint30(); auto& forward_ref = unresolved_forward_refs_[index]; auto slot = SlotAccessorForHeapObject::ForSlotOffset(forward_ref.object, forward_ref.offset); @@ -1358,10 +1447,10 @@ int Deserializer<IsolateT>::ReadVariableRawData(uint8_t data, // This operation is only supported for tagged-size slots, else we might // become misaligned. DCHECK_EQ(decltype(slot_accessor.slot())::kSlotDataSize, kTaggedSize); - int size_in_tagged = source_.GetUint30(); + uint32_t size_in_tagged = source_.GetUint30(); if (v8_flags.trace_deserialization) { PrintF("%*sVariableRawData [%u] :", depth_, "", size_in_tagged); - for (int i = 0; i < size_in_tagged; ++i) { + for (uint32_t i = 0; i < size_in_tagged; ++i) { PrintF(" %0*" PRIxTAGGED, kTaggedSize / 2, reinterpret_cast<const Tagged_t*>(source_.data())[i]); } @@ -1416,6 +1505,7 @@ int Deserializer<IsolateT>::ReadOffHeapBackingStore( initial_pages, max_pages, WasmMemoryFlag::kNotWasm, SharedFlag{false}); } CHECK_NOT_NULL(backing_store); + SBXCHECK_LE(source_.position() + byte_length, source_.length()); source_.CopyRaw(backing_store->buffer_start(), byte_length); backing_stores_.push_back(std::move(backing_store)); return 0; @@ -1425,17 +1515,9 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadApiReference(uint8_t data, SlotAccessor slot_accessor) { + SBXCHECK(InTrustedSection()); DCHECK_IMPLIES(data == kSandboxedApiReference, V8_ENABLE_SANDBOX_BOOL); - uint32_t reference_id = static_cast<uint32_t>(source_.GetUint30()); - Address address; - if (main_thread_isolate()->api_external_references()) { - DCHECK_WITH_MSG(reference_id < num_api_references_, - "too few external references provided through the API"); - address = static_cast<Address>( - main_thread_isolate()->api_external_references()[reference_id]); - } else { - address = reinterpret_cast<Address>(NoExternalReferencesCallback); - } + Address address = GetApiReferenceAddress(source_.GetUint30()); ExternalPointerTag tag = kExternalPointerNullTag; if (data == kSandboxedApiReference) { tag = ReadExternalPointerTag(); @@ -1475,28 +1557,29 @@ int Deserializer<IsolateT>::ReadWeakPrefix(uint8_t data, template <typename IsolateT> template <typename SlotAccessor> -int Deserializer<IsolateT>::ReadIndirectPointerPrefix( +int Deserializer<IsolateT>::ReadTrustedPointerPrefix( uint8_t data, SlotAccessor slot_accessor) { if (v8_flags.trace_deserialization) { - PrintF("%*sIndirectPointerPrefix\n", depth_, ""); + PrintF("%*sTrustedPointerPrefix\n", depth_, ""); } // We shouldn't have two indirect pointer prefixes in a row. - DCHECK(!next_reference_is_indirect_pointer_); + DCHECK(!next_reference_is_trusted_pointer_); // We shouldn't have a indirect pointer prefix without a current object. DCHECK_NE(slot_accessor.object()->address(), kNullAddress); - next_reference_is_indirect_pointer_ = true; + next_reference_is_trusted_pointer_ = true; return 0; } template <typename IsolateT> template <typename SlotAccessor> -int Deserializer<IsolateT>::ReadInitializeSelfIndirectPointer( +int Deserializer<IsolateT>::ReadInitializeSelfTrustedPointer( uint8_t data, SlotAccessor slot_accessor) { #ifdef V8_ENABLE_SANDBOX + SBXCHECK(InTrustedSection()); DCHECK_NE(slot_accessor.object()->address(), kNullAddress); DCHECK(IsExposedTrustedObject(*slot_accessor.object())); DCHECK_EQ(slot_accessor.offset(), - offsetof(ExposedTrustedObject, self_indirect_pointer_)); + offsetof(ExposedTrustedObject, self_trusted_pointer_)); Tagged<ExposedTrustedObject> host = TrustedCast<ExposedTrustedObject>(*slot_accessor.object()); @@ -1514,6 +1597,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadAllocateJSDispatchEntry( uint8_t data, SlotAccessor slot_accessor) { + SBXCHECK(InTrustedSection()); DCHECK_NE(slot_accessor.object()->address(), kNullAddress); DirectHandle<HeapObject> host = slot_accessor.object(); @@ -1565,6 +1649,7 @@ template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadProtectedPointerPrefix( uint8_t data, SlotAccessor slot_accessor) { + SBXCHECK(InTrustedSection()); // We shouldn't have two protected pointer prefixes in a row. DCHECK(!next_reference_is_protected_pointer); // We shouldn't have a protected pointer prefix without a current object. @@ -1573,6 +1658,57 @@ int Deserializer<IsolateT>::ReadProtectedPointerPrefix( return 0; } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadTrustedExportRef(uint8_t data, + SlotAccessor slot_accessor) { + DCHECK(InUntrustedSection()); + uint32_t index = source_.GetUint30(); + if (v8_flags.trace_deserialization) { + PrintF("%*sTrustedExportRef [%u]\n", depth_, "", index); + } + ReferenceDescriptor descr = GetAndResetNextReferenceDescriptor(); + DCHECK(descr.is_trusted_pointer); + trusted_export_refs_.emplace_back( + index, UnresolvedForwardRef(slot_accessor.object(), + slot_accessor.offset(), descr)); + return 1; +} + +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadUntrustedRef(uint8_t data, + SlotAccessor slot_accessor) { + DCHECK(InTrustedSection()); + uint32_t index = source_.GetUint30(); + if (v8_flags.trace_deserialization) { + PrintF("%*sUntrustedRef [%u]\n", depth_, "", index); + } + return WriteHeapPointer(slot_accessor, *untrusted_back_refs_[index], + GetAndResetNextReferenceDescriptor()); +} + +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadTrustedExternalRef(uint8_t data, + SlotAccessor slot_accessor) { + DCHECK(InUntrustedSection()); + uint32_t index = source_.GetUint30(); + EncodedExternalReference entry = external_references_[index]; + Address address = + entry.reference.is_from_api() + ? GetApiReferenceAddress(entry.reference.index()) + : main_thread_isolate()->external_reference_table()->address( + entry.reference.index()); + if (v8_flags.trace_deserialization) { + PrintF("%*sTrustedExternalRef [%u] : %" PRIxPTR ", %i\n", depth_, "", index, + address, entry.tag); + } + return WriteExternalPointer(*slot_accessor.object(), + slot_accessor.external_pointer_slot(entry.tag), + address, entry.tag); +} + template <typename IsolateT> template <typename SlotAccessor> int Deserializer<IsolateT>::ReadRootArrayConstants(uint8_t data, @@ -1583,31 +1719,21 @@ int Deserializer<IsolateT>::ReadRootArrayConstants(uint8_t data, static_assert(kRootArrayConstantsCount <= static_cast<int>(RootIndex::kLastImmortalImmovableRoot)); + DCHECK(!next_reference_is_trusted_pointer_); + DCHECK(!next_reference_is_protected_pointer); + RootIndex root_index = RootArrayConstant::Decode(data); - DirectHandle<HeapObject> heap_object = - Cast<HeapObject>(isolate()->root_handle(root_index)); + Tagged<HeapObject> heap_object = + Cast<HeapObject>(isolate()->root(root_index)); if (v8_flags.trace_deserialization) { PrintF("%*sRootArrayConstants [%u] : %s\n", depth_, "", static_cast<int>(root_index), RootsTable::name(root_index)); } - return WriteHeapPointer(slot_accessor, heap_object, - GetAndResetNextReferenceDescriptor(), - SKIP_WRITE_BARRIER); -} - -template <typename IsolateT> -template <typename SlotAccessor> -int Deserializer<IsolateT>::ReadHotObject(uint8_t data, - SlotAccessor slot_accessor) { - int index = HotObject::Decode(data); - DirectHandle<HeapObject> hot_object = hot_objects_.Get(index); - if (v8_flags.trace_deserialization) { - PrintF("%*sHotObject [%u] : ", depth_, "", index); - ShortPrint(*hot_object); - PrintF("\n"); - } - return WriteHeapPointer(slot_accessor, hot_object, - GetAndResetNextReferenceDescriptor()); + HeapObjectReferenceType ref_type = next_reference_is_weak_ + ? HeapObjectReferenceType::WEAK + : HeapObjectReferenceType::STRONG; + next_reference_is_weak_ = false; + return slot_accessor.Write(heap_object, ref_type, 0, SKIP_WRITE_BARRIER); } template <typename IsolateT> @@ -1617,17 +1743,18 @@ int Deserializer<IsolateT>::ReadFixedRawData(uint8_t data, using TSlot = decltype(slot_accessor.slot()); // Deserialize raw data of fixed length from 1 to 32 times kTaggedSize. - int size_in_tagged = FixedRawDataWithSize::Decode(data); + uint32_t size_in_tagged = FixedRawDataWithSize::Decode(data); static_assert(TSlot::kSlotDataSize == kTaggedSize || TSlot::kSlotDataSize == 2 * kTaggedSize); - int size_in_slots = size_in_tagged / (TSlot::kSlotDataSize / kTaggedSize); + uint32_t size_in_slots = + size_in_tagged / (TSlot::kSlotDataSize / kTaggedSize); // kFixedRawData can have kTaggedSize != TSlot::kSlotDataSize when // serializing Smi roots in pointer-compressed builds. In this case, the // size in bytes is unconditionally the (full) slot size. DCHECK_IMPLIES(kTaggedSize != TSlot::kSlotDataSize, size_in_slots == 1); if (v8_flags.trace_deserialization) { PrintF("%*sFixedRawData [%u] :", depth_, "", size_in_tagged); - for (int i = 0; i < size_in_tagged; ++i) { + for (uint32_t i = 0; i < size_in_tagged; ++i) { PrintF(" %0*" PRIxTAGGED, kTaggedSize / 2, reinterpret_cast<const Tagged_t*>(source_.data())[i]); } @@ -1670,8 +1797,24 @@ int Deserializer<IsolateT>::ReadFixedRepeatRoot(uint8_t data, return ret; } +template <typename IsolateT> +template <typename SlotAccessor> +int Deserializer<IsolateT>::ReadFixedBackref(uint8_t data, + SlotAccessor slot_accessor) { + uint32_t index = FixedBackref::Decode(data); + SBXCHECK_LT(index, num_fixed_back_refs_); + Handle<HeapObject> heap_object(fixed_back_refs_[index]); + if (v8_flags.trace_deserialization) { + PrintF("%*sFixedBackref [%u]\n", depth_, "", index); + } + return WriteHeapPointer(slot_accessor, heap_object, + GetAndResetNextReferenceDescriptor()); +} + #undef CASE_RANGE_ALL_SPACES #undef CASE_RANGE +#undef CASE_R128 +#undef CASE_R64 #undef CASE_R32 #undef CASE_R16 #undef CASE_R8 @@ -1682,24 +1825,44 @@ int Deserializer<IsolateT>::ReadFixedRepeatRoot(uint8_t data, template <typename IsolateT> Address Deserializer<IsolateT>::ReadExternalReferenceCase() { + DCHECK(InTrustedSection()); uint32_t reference_id = static_cast<uint32_t>(source_.GetUint30()); return main_thread_isolate()->external_reference_table()->address( reference_id); } +template <typename IsolateT> +Address Deserializer<IsolateT>::GetApiReferenceAddress(uint32_t reference_id) { + if (main_thread_isolate()->api_external_references()) { + DCHECK_WITH_MSG(reference_id < num_api_references_, + "too few external references provided through the API"); + return static_cast<Address>( + main_thread_isolate()->api_external_references()[reference_id]); + } + return reinterpret_cast<Address>(NoExternalReferencesCallback); +} + template <typename IsolateT> ExternalPointerTag Deserializer<IsolateT>::ReadExternalPointerTag() { + DCHECK(InTrustedSection()); return static_cast<ExternalPointerTag>(source_.GetUint30()); } template <typename IsolateT> Tagged<HeapObject> Deserializer<IsolateT>::Allocate( - AllocationType allocation, int size, AllocationAlignment alignment) { + AllocationType allocation, uint32_t size, AllocationAlignment alignment) { + // The untrusted section can only allocate inside the sandbox. Strings can be + // allocated in the shared heap, see ReadObject. + SBXCHECK_IMPLIES(InUntrustedSection(), + allocation == AllocationType::kOld || + allocation == AllocationType::kSharedOld); + DCHECK_IMPLIES(section_ == Section::kTrusted, + allocation == AllocationType::kTrusted); #ifdef DEBUG if (!previous_allocation_obj_.is_null()) { // Make sure that the previous object is initialized sufficiently to // be iterated over by the GC. - int object_size = previous_allocation_obj_->Size(); + uint32_t object_size = previous_allocation_obj_->SafeSize().value(); DCHECK_LE(object_size, previous_allocation_size_); } #endif diff --git a/deps/v8/src/snapshot/deserializer.h b/deps/v8/src/snapshot/deserializer.h index 12c74d5e9e83..a94e622e4f17 100644 --- a/deps/v8/src/snapshot/deserializer.h +++ b/deps/v8/src/snapshot/deserializer.h @@ -50,11 +50,15 @@ class Deserializer : public SerializerDeserializer { protected: // Create a deserializer from a snapshot byte source. - Deserializer(IsolateT* isolate, base::Vector<const uint8_t> payload, + Deserializer(IsolateT* isolate, base::Vector<const uint8_t> untrusted_payload, + base::Vector<const uint8_t> trusted_payload, uint32_t magic_number, bool deserializing_user_code, bool can_rehash); void DeserializeDeferredObjects(); + // For code caches. The untrusted section has the root and is read first. + DirectHandle<HeapObject> DeserializeUntrustedSection(); + void DeserializeTrustedSection(); // Create Log events for newly deserialized objects. void LogNewObjectEvents(); @@ -127,38 +131,9 @@ class Deserializer : public SerializerDeserializer { DirectHandle<HeapObject> ReadObject(); private: - // A circular queue of hot objects. This is added to in the same order as in - // Serializer::HotObjectsList, but this stores the objects as a vector of - // existing handles. This allows us to add Handles to the queue without having - // to create new handles. Note that this depends on those Handles staying - // valid as long as the HotObjectsList is alive. - class HotObjectsList { - public: - HotObjectsList() = default; - HotObjectsList(const HotObjectsList&) = delete; - HotObjectsList& operator=(const HotObjectsList&) = delete; - - void Add(DirectHandle<HeapObject> object) { - circular_queue_[index_] = object; - index_ = (index_ + 1) & kSizeMask; - } - - DirectHandle<HeapObject> Get(int index) { - DCHECK(!circular_queue_[index].is_null()); - return circular_queue_[index]; - } - - private: - static const int kSize = kHotObjectCount; - static const int kSizeMask = kSize - 1; - static_assert(base::bits::IsPowerOfTwo(kSize)); - DirectHandle<HeapObject> circular_queue_[kSize]; - int index_ = 0; - }; - struct ReferenceDescriptor { HeapObjectReferenceType type; - bool is_indirect_pointer; + bool is_trusted_pointer; bool is_protected_pointer; }; @@ -181,8 +156,8 @@ class Deserializer : public SerializerDeserializer { inline int WriteExternalPointer(Tagged<HeapObject> host, ExternalPointerSlot dest, Address value, ExternalPointerTag tag); - inline int WriteIndirectPointer(IndirectPointerSlot dest, - Tagged<HeapObject> value); + inline int WriteTrustedPointer(TrustedPointerSlot dest, + Tagged<HeapObject> value); // Fills in a heap object's data from start to end (exclusive). Start and end // are slot indices within the object. @@ -236,10 +211,10 @@ class Deserializer : public SerializerDeserializer { template <typename SlotAccessor> int ReadWeakPrefix(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> - int ReadIndirectPointerPrefix(uint8_t data, SlotAccessor slot_accessor); + int ReadTrustedPointerPrefix(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> - int ReadInitializeSelfIndirectPointer(uint8_t data, - SlotAccessor slot_accessor); + int ReadInitializeSelfTrustedPointer(uint8_t data, + SlotAccessor slot_accessor); template <typename SlotAccessor> int ReadAllocateJSDispatchEntry(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> @@ -247,18 +222,27 @@ class Deserializer : public SerializerDeserializer { template <typename SlotAccessor> int ReadProtectedPointerPrefix(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> - int ReadRootArrayConstants(uint8_t data, SlotAccessor slot_accessor); + int ReadTrustedExportRef(uint8_t data, SlotAccessor slot_accessor); + template <typename SlotAccessor> + int ReadUntrustedRef(uint8_t data, SlotAccessor slot_accessor); + template <typename SlotAccessor> + int ReadTrustedExternalRef(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> - int ReadHotObject(uint8_t data, SlotAccessor slot_accessor); + int ReadRegisterFixedBackref(uint8_t data, SlotAccessor slot_accessor); + template <typename SlotAccessor> + int ReadRootArrayConstants(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> int ReadFixedRawData(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> int ReadExtendedMapBitfieldEx(uint8_t data, SlotAccessor slot_accessor); template <typename SlotAccessor> int ReadFixedRepeatRoot(uint8_t data, SlotAccessor slot_accessor); + template <typename SlotAccessor> + int ReadFixedBackref(uint8_t data, SlotAccessor slot_accessor); // A helper function for ReadData for reading external references. inline Address ReadExternalReferenceCase(); + Address GetApiReferenceAddress(uint32_t reference_id); // A helper function for reading external pointer tags. ExternalPointerTag ReadExternalPointerTag(); @@ -278,7 +262,7 @@ class Deserializer : public SerializerDeserializer { InstanceType instance_type, SnapshotSpace space); - Tagged<HeapObject> Allocate(AllocationType allocation, int size, + Tagged<HeapObject> Allocate(AllocationType allocation, uint32_t size, AllocationAlignment alignment); // Cached current isolate. @@ -290,7 +274,6 @@ class Deserializer : public SerializerDeserializer { SnapshotByteSource source_; uint32_t magic_number_; - HotObjectsList hot_objects_; DirectHandleVector<Map> new_maps_; DirectHandleVector<AllocationSite> new_allocation_sites_; DirectHandleVector<InstructionStream> new_instruction_stream_objects_; @@ -303,6 +286,8 @@ class Deserializer : public SerializerDeserializer { // Vector of allocated objects that can be accessed by a backref, by index. std::vector<IndirectHandle<HeapObject>> back_refs_; + Address* fixed_back_refs_[kFixedBackrefCount]; + uint32_t num_fixed_back_refs_ = 0; // Vector of already allocated JSDispatchTable entries. std::vector<JSDispatchHandle> js_dispatch_entries_; @@ -325,10 +310,32 @@ class Deserializer : public SerializerDeserializer { std::vector<UnresolvedForwardRef> unresolved_forward_refs_; int num_unresolved_forward_refs_ = 0; + base::Vector<const uint8_t> trusted_payload_; + std::vector<EncodedExternalReference> external_references_; + std::vector<IndirectHandle<HeapObject>> untrusted_back_refs_; + std::vector<std::pair<uint32_t, UnresolvedForwardRef>> trusted_export_refs_; + + // With the sandbox, a code cache has an untrusted and a trusted section. + // Snapshots and code caches without the sandbox have a single section that + // combines both and is trusted as a whole. + enum class Section : uint8_t { + kUntrusted = 1 << 0, + kTrusted = 1 << 1, + kCombined = kUntrusted | kTrusted, + }; + // Bytecodes that could corrupt memory outside the sandbox are only allowed in + // the trusted and the combined section. + V8_INLINE bool InTrustedSection() const { + return static_cast<uint8_t>(section_) & + static_cast<uint8_t>(Section::kTrusted); + } + V8_INLINE bool InUntrustedSection() const { return !InTrustedSection(); } + Section section_; + const bool deserializing_user_code_; bool next_reference_is_weak_ = false; - bool next_reference_is_indirect_pointer_ = false; + bool next_reference_is_trusted_pointer_ = false; bool next_reference_is_protected_pointer = false; // TODO(6593): generalize rehashing, and remove this flag. @@ -357,7 +364,7 @@ class Deserializer : public SerializerDeserializer { // Record the previous object allocated for DCHECKs. DirectHandle<HeapObject> previous_allocation_obj_; - int previous_allocation_size_ = 0; + uint32_t previous_allocation_size_ = 0; #endif // DEBUG }; diff --git a/deps/v8/src/snapshot/embedded/embedded-file-writer.cc b/deps/v8/src/snapshot/embedded/embedded-file-writer.cc index 7ac3b6c8819e..a8db1d8e21d2 100644 --- a/deps/v8/src/snapshot/embedded/embedded-file-writer.cc +++ b/deps/v8/src/snapshot/embedded/embedded-file-writer.cc @@ -5,6 +5,7 @@ #include "src/snapshot/embedded/embedded-file-writer.h" #include <algorithm> +#include <array> #include <cinttypes> #include "src/codegen/code-comments.h" @@ -54,7 +55,7 @@ void EmbeddedFileWriter::WriteBuiltin(PlatformEmbeddedFileWriterBase* w, const bool is_default_variant = std::strcmp(embedded_variant_, kDefaultEmbeddedVariant) == 0; - base::EmbeddedVector<char, kTemporaryStringLength> builtin_symbol; + std::array<char, kTemporaryStringLength> builtin_symbol; if (is_default_variant) { // Create nicer symbol names for the default mode. base::SNPrintF(builtin_symbol, "Builtins_%s", i::Builtins::name(builtin)); @@ -67,7 +68,7 @@ void EmbeddedFileWriter::WriteBuiltin(PlatformEmbeddedFileWriterBase* w, // Isolate::SetEmbeddedBlob that the blob layout remains unchanged, i.e. // that labels do not insert bytes into the middle of the blob byte // stream. - w->DeclareFunctionBegin(builtin_symbol.begin(), + w->DeclareFunctionBegin(builtin_symbol.data(), blob->InstructionSizeOf(builtin)); if (builtin_marker_sources_id_ != 0) { @@ -157,7 +158,7 @@ void EmbeddedFileWriter::WriteBuiltin(PlatformEmbeddedFileWriterBase* w, i = next_offset; } - w->DeclareFunctionEnd(builtin_symbol.begin()); + w->DeclareFunctionEnd(builtin_symbol.data()); } void EmbeddedFileWriter::WriteBuiltinLabels(PlatformEmbeddedFileWriterBase* w, @@ -311,34 +312,32 @@ void EmbeddedFileWriter::WriteDebugSection(PlatformEmbeddedFileWriterBase* w, void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w, const i::EmbeddedData* blob) const { { - base::EmbeddedVector<char, kTemporaryStringLength> - embedded_blob_code_size_symbol; + std::array<char, kTemporaryStringLength> embedded_blob_code_size_symbol; base::SNPrintF(embedded_blob_code_size_symbol, "v8_%s_embedded_blob_code_size_", embedded_variant_); w->Comment("The size of the embedded blob code in bytes."); w->SectionRoData(); w->AlignToDataAlignment(); - w->DeclareUint32(embedded_blob_code_size_symbol.begin(), blob->code_size()); + w->DeclareUint32(embedded_blob_code_size_symbol.data(), blob->code_size()); w->Newline(); - base::EmbeddedVector<char, kTemporaryStringLength> - embedded_blob_data_size_symbol; + std::array<char, kTemporaryStringLength> embedded_blob_data_size_symbol; base::SNPrintF(embedded_blob_data_size_symbol, "v8_%s_embedded_blob_data_size_", embedded_variant_); w->Comment("The size of the embedded blob data section in bytes."); - w->DeclareUint32(embedded_blob_data_size_symbol.begin(), blob->data_size()); + w->DeclareUint32(embedded_blob_data_size_symbol.data(), blob->data_size()); w->Newline(); } #if defined(V8_OS_WIN64) { - base::EmbeddedVector<char, kTemporaryStringLength> unwind_info_symbol; + std::array<char, kTemporaryStringLength> unwind_info_symbol; base::SNPrintF(unwind_info_symbol, "%s_Builtins_UnwindInfo", embedded_variant_); - w->MaybeEmitUnwindData(unwind_info_symbol.begin(), + w->MaybeEmitUnwindData(unwind_info_symbol.data(), EmbeddedBlobCodeSymbol().c_str(), blob, reinterpret_cast<const void*>(&unwind_infos_[0])); } diff --git a/deps/v8/src/snapshot/embedded/embedded-file-writer.h b/deps/v8/src/snapshot/embedded/embedded-file-writer.h index 9b3b852e9225..99c939404762 100644 --- a/deps/v8/src/snapshot/embedded/embedded-file-writer.h +++ b/deps/v8/src/snapshot/embedded/embedded-file-writer.h @@ -5,6 +5,7 @@ #ifndef V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_ #define V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_ +#include <array> #include <cinttypes> #include <cstdio> #include <cstring> @@ -125,19 +126,17 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { static constexpr int kTemporaryStringLength = 256; std::string EmbeddedBlobCodeSymbol() const { - base::EmbeddedVector<char, kTemporaryStringLength> - embedded_blob_code_symbol; + std::array<char, kTemporaryStringLength> embedded_blob_code_symbol; base::SNPrintF(embedded_blob_code_symbol, "v8_%s_embedded_blob_code_", embedded_variant_); - return std::string{embedded_blob_code_symbol.begin()}; + return std::string{embedded_blob_code_symbol.data()}; } std::string EmbeddedBlobDataSymbol() const { - base::EmbeddedVector<char, kTemporaryStringLength> - embedded_blob_data_symbol; + std::array<char, kTemporaryStringLength> embedded_blob_data_symbol; base::SNPrintF(embedded_blob_data_symbol, "v8_%s_embedded_blob_data_", embedded_variant_); - return std::string{embedded_blob_data_symbol.begin()}; + return std::string{embedded_blob_data_symbol.data()}; } void WriteDataSection(PlatformEmbeddedFileWriterBase* w, diff --git a/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc b/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc index bf76435717cf..08adc77d4865 100644 --- a/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc +++ b/deps/v8/src/snapshot/embedded/platform-embedded-file-writer-win.cc @@ -5,6 +5,7 @@ #include "src/snapshot/embedded/platform-embedded-file-writer-win.h" #include <algorithm> +#include <array> #include "src/common/globals.h" // For V8_OS_WIN64 @@ -186,7 +187,7 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, // Fairly arbitrary but should fit all symbol names. static constexpr int kTemporaryStringLength = 256; - base::EmbeddedVector<char, kTemporaryStringLength> unwind_info_full_symbol; + std::array<char, kTemporaryStringLength> unwind_info_full_symbol; // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as // documented here: @@ -235,7 +236,7 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, code_chunks.size()); w->DeclareRvaToSymbol(embedded_blob_data_symbol, builtin_start_offset + chunk_start); - w->DeclareRvaToSymbol(unwind_info_full_symbol.begin()); + w->DeclareRvaToSymbol(unwind_info_full_symbol.data()); } } } @@ -250,7 +251,7 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, for (size_t i = 0; i < code_chunks.size(); i++) { base::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol, i + 1); - w->DeclareLabel(unwind_info_full_symbol.begin()); + w->DeclareLabel(unwind_info_full_symbol.data()); std::vector<uint8_t> xdata = win64_unwindinfo::GetUnwindInfoForBuiltinFunction(code_chunks[i], fp_adjustments[i]); diff --git a/deps/v8/src/snapshot/object-deserializer.cc b/deps/v8/src/snapshot/object-deserializer.cc index 6411f966431b..e3cb09d1bc7d 100644 --- a/deps/v8/src/snapshot/object-deserializer.cc +++ b/deps/v8/src/snapshot/object-deserializer.cc @@ -21,8 +21,9 @@ namespace internal { ObjectDeserializer::ObjectDeserializer(Isolate* isolate, const SerializedCodeData* data) - : Deserializer(isolate, data->Payload(), data->GetMagicNumber(), true, - false) {} + : Deserializer(isolate, data->UntrustedPayload(), data->TrustedPayload(), + data->GetMagicNumber(), /* deserializing_user_code */ true, + /* can_rehash */ false) {} MaybeDirectHandle<SharedFunctionInfo> ObjectDeserializer::DeserializeSharedFunctionInfo( @@ -43,8 +44,8 @@ MaybeDirectHandle<HeapObject> ObjectDeserializer::Deserialize() { HandleScope scope(isolate()); DirectHandle<HeapObject> result; { - result = ReadObject(); - DeserializeDeferredObjects(); + result = DeserializeUntrustedSection(); + DeserializeTrustedSection(); CHECK(new_instruction_stream_objects().empty()); LinkAllocationSites(); CHECK(new_maps().empty()); @@ -94,8 +95,9 @@ void ObjectDeserializer::LinkAllocationSites() { OffThreadObjectDeserializer::OffThreadObjectDeserializer( LocalIsolate* isolate, const SerializedCodeData* data) - : Deserializer(isolate, data->Payload(), data->GetMagicNumber(), true, - false) {} + : Deserializer(isolate, data->UntrustedPayload(), data->TrustedPayload(), + data->GetMagicNumber(), /* deserializing_user_code */ true, + /* can_rehash */ false) {} MaybeDirectHandle<SharedFunctionInfo> OffThreadObjectDeserializer::DeserializeSharedFunctionInfo( @@ -119,8 +121,8 @@ MaybeDirectHandle<HeapObject> OffThreadObjectDeserializer::Deserialize( LocalHandleScope scope(isolate()); DirectHandle<HeapObject> result; { - result = ReadObject(); - DeserializeDeferredObjects(); + result = DeserializeUntrustedSection(); + DeserializeTrustedSection(); CHECK(new_instruction_stream_objects().empty()); CHECK(new_allocation_sites().empty()); CHECK(new_maps().empty()); diff --git a/deps/v8/src/snapshot/read-only-deserializer.cc b/deps/v8/src/snapshot/read-only-deserializer.cc index ed0b1d90021b..4e03c368c4d2 100644 --- a/deps/v8/src/snapshot/read-only-deserializer.cc +++ b/deps/v8/src/snapshot/read-only-deserializer.cc @@ -156,7 +156,8 @@ class ReadOnlyHeapImageDeserializer final { ReadOnlyDeserializer::ReadOnlyDeserializer(Isolate* isolate, const SnapshotData* data, bool can_rehash) - : Deserializer(isolate, data->Payload(), data->GetMagicNumber(), false, + : Deserializer(isolate, data->Payload(), /* trusted_payload */ {}, + data->GetMagicNumber(), /* deserializing_user_code */ false, can_rehash) {} void ReadOnlyDeserializer::DeserializeIntoIsolate() { @@ -167,6 +168,9 @@ void ReadOnlyDeserializer::DeserializeIntoIsolate() { HandleScope scope(isolate()); ReadOnlyHeapImageDeserializer::Deserialize(isolate(), source()); + if (should_rehash()) { + HashSeed::InitializeRoots(isolate()); + } PostProcessNewObjects(); ReadOnlyRoots roots(isolate()); @@ -177,7 +181,6 @@ void ReadOnlyDeserializer::DeserializeIntoIsolate() { #endif if (should_rehash()) { - HashSeed::InitializeRoots(isolate()); Rehash(); } @@ -204,6 +207,9 @@ class ObjectPostProcessor final { : isolate_(isolate), embedded_data_(EmbeddedData::FromBlob(isolate_)) {} void Finalize() { + if (Builtins::kCodeObjectsAreInROSpace) { + isolate_->builtins()->MarkInitialized(); + } #ifdef V8_ENABLE_SANDBOX std::vector<ReadOnlyArtifacts::ExternalPointerRegistryEntry> registry; registry.reserve(external_pointer_slots_.size()); @@ -226,9 +232,13 @@ class ObjectPostProcessor final { V8_INLINE void PostProcessIfNeeded(Tagged<HeapObject> o, InstanceType instance_type) { DCHECK_EQ(o->map()->instance_type(), instance_type); -#define V(TYPE) \ - if (InstanceTypeChecker::Is##TYPE(instance_type)) { \ - return PostProcess##TYPE(TrustedCast<TYPE>(o)); \ +#define V(TYPE) \ + if (InstanceTypeChecker::Is##TYPE(instance_type)) { \ + if constexpr (is_subtype_v<TYPE, TrustedObject>) { \ + return PostProcess##TYPE(TrustedCast<TYPE>(o)); \ + } else { \ + return PostProcess##TYPE(Cast<TYPE>(o)); \ + } \ } POST_PROCESS_TYPE_LIST(V) #undef V @@ -390,13 +400,14 @@ class ObjectPostProcessor final { DCHECK(o->is_builtin()); DCHECK(!o->has_instruction_stream()); Builtin builtin = o->builtin_id(); + isolate_->builtins()->set_code(builtin, o); // Mark disabled builtins as such (RO space serializer resets this flag). DCHECK(!o->is_disabled_builtin()); if (Builtins::IsDisabled(builtin)) { o->set_is_disabled_builtin(true); } o->SetInstructionStartForOffHeapBuiltin( - isolate_, EmbeddedData::FromBlob(isolate_).InstructionStartOf(builtin)); + isolate_, embedded_data_.InstructionStartOf(builtin)); #if V8_ENABLE_GEARBOX UpdateGearboxPlaceholderBuiltin(o); @@ -438,6 +449,7 @@ void ReadOnlyDeserializer::PostProcessNewObjects() { #ifdef V8_ENABLE_SANDBOX std::vector<ReadOnlyArtifacts::TrustedPointerRegistryEntry> trusted_pointer_entries; + trusted_pointer_entries.reserve(Builtins::kBuiltinCount); #endif // V8_ENABLE_SANDBOX for (Tagged<HeapObject> o = it.Next(); !o.is_null(); o = it.Next()) { if (IsInaccessible(o)) continue; @@ -446,7 +458,7 @@ void ReadOnlyDeserializer::PostProcessNewObjects() { if (InstanceTypeChecker::IsString(instance_type)) { Tagged<String> str = Cast<String>(o); str->set_raw_hash_field(Name::kEmptyHashField); - PushObjectToRehash(direct_handle(str, isolate())); + str->EnsureHash(); } else if (o->NeedsRehashing(instance_type)) { PushObjectToRehash(direct_handle(o, isolate())); } @@ -457,11 +469,11 @@ void ReadOnlyDeserializer::PostProcessNewObjects() { #ifdef V8_ENABLE_SANDBOX if (IsExposedTrustedObject(o)) { SharedFlag shared = SharedFlag(HeapLayout::InAnySharedSpace(o)); - IndirectPointerTag tag = - IndirectPointerTagFromInstanceType(instance_type, shared); + TrustedPointerTag tag = + TrustedPointerTagFromInstanceType(instance_type, shared); Tagged<ExposedTrustedObject> exposed = TrustedCast<ExposedTrustedObject>(o); - TrustedPointerHandle handle = exposed->self_indirect_pointer_handle(); + TrustedPointerHandle handle = exposed->self_trusted_pointer_handle(); trusted_pointer_entries.emplace_back(handle, exposed.ptr(), tag); } #endif // V8_ENABLE_SANDBOX diff --git a/deps/v8/src/snapshot/read-only-serializer.cc b/deps/v8/src/snapshot/read-only-serializer.cc index 027e181673da..2d7462952b59 100644 --- a/deps/v8/src/snapshot/read-only-serializer.cc +++ b/deps/v8/src/snapshot/read-only-serializer.cc @@ -35,9 +35,13 @@ class ObjectPreProcessor final { void PreProcessIfNeeded(Tagged<HeapObject> o) { const InstanceType itype = o->map()->instance_type(); -#define V(TYPE) \ - if (InstanceTypeChecker::Is##TYPE(itype)) { \ - return PreProcess##TYPE(TrustedCast<TYPE>(o)); \ +#define V(TYPE) \ + if (InstanceTypeChecker::Is##TYPE(itype)) { \ + if constexpr (is_subtype_v<TYPE, TrustedObject>) { \ + return PreProcess##TYPE(TrustedCast<TYPE>(o)); \ + } else { \ + return PreProcess##TYPE(Cast<TYPE>(o)); \ + } \ } PRE_PROCESS_TYPE_LIST(V) #undef V diff --git a/deps/v8/src/snapshot/serializer-deserializer.h b/deps/v8/src/snapshot/serializer-deserializer.h index 477d239fa015..68a7541078cc 100644 --- a/deps/v8/src/snapshot/serializer-deserializer.h +++ b/deps/v8/src/snapshot/serializer-deserializer.h @@ -5,6 +5,9 @@ #ifndef V8_SNAPSHOT_SERIALIZER_DESERIALIZER_H_ #define V8_SNAPSHOT_SERIALIZER_DESERIALIZER_H_ +#include <type_traits> + +#include "src/codegen/external-reference-encoder.h" #include "src/objects/visitors.h" #include "src/snapshot/references.h" @@ -32,32 +35,9 @@ class SerializerDeserializer : public RootVisitor { // clang-format off #define UNUSED_SERIALIZER_BYTE_CODES(V) \ - /* Free range 0x22..0x2f */ \ - V(0x23) V(0x24) V(0x25) V(0x26) V(0x27) \ - V(0x28) V(0x29) V(0x2a) V(0x2b) V(0x2c) V(0x2d) V(0x2e) V(0x2f) \ - /* Free range 0x30..0x3f */ \ - V(0x30) V(0x31) V(0x32) V(0x33) V(0x34) V(0x35) V(0x36) V(0x37) \ - V(0x38) V(0x39) V(0x3a) V(0x3b) V(0x3c) V(0x3d) V(0x3e) V(0x3f) \ - /* Free range 0x97..0x9f */ \ - V(0x98) V(0x99) V(0x9a) V(0x9b) V(0x9c) V(0x9d) V(0x9e) V(0x9f) \ - /* Free range 0xa0..0xaf */ \ - V(0xa0) V(0xa1) V(0xa2) V(0xa3) V(0xa4) V(0xa5) V(0xa6) V(0xa7) \ - V(0xa8) V(0xa9) V(0xaa) V(0xab) V(0xac) V(0xad) V(0xae) V(0xaf) \ - /* Free range 0xb0..0xbf */ \ - V(0xb0) V(0xb1) V(0xb2) V(0xb3) V(0xb4) V(0xb5) V(0xb6) V(0xb7) \ - V(0xb8) V(0xb9) V(0xba) V(0xbb) V(0xbc) V(0xbd) V(0xbe) V(0xbf) \ - /* Free range 0xc0..0xcf */ \ - V(0xc0) V(0xc1) V(0xc2) V(0xc3) V(0xc4) V(0xc5) V(0xc6) V(0xc7) \ - V(0xc8) V(0xc9) V(0xca) V(0xcb) V(0xcc) V(0xcd) V(0xce) V(0xcf) \ - /* Free range 0xd0..0xdf */ \ - V(0xd0) V(0xd1) V(0xd2) V(0xd3) V(0xd4) V(0xd5) V(0xd6) V(0xd7) \ - V(0xd8) V(0xd9) V(0xda) V(0xdb) V(0xdc) V(0xdd) V(0xde) V(0xdf) \ - /* Free range 0xe0..0xef */ \ - V(0xe0) V(0xe1) V(0xe2) V(0xe3) V(0xe4) V(0xe5) V(0xe6) V(0xe7) \ - V(0xe8) V(0xe9) V(0xea) V(0xeb) V(0xec) V(0xed) V(0xee) V(0xef) \ - /* Free range 0xf0..0xff */ \ - V(0xf0) V(0xf1) V(0xf2) V(0xf3) V(0xf4) V(0xf5) V(0xf6) V(0xf7) \ - V(0xf8) V(0xf9) V(0xfa) V(0xfb) V(0xfc) V(0xfd) V(0xfe) V(0xff) + /* Free range 0x27..0x2f */ \ + V(0x27) \ + V(0x28) V(0x29) V(0x2a) V(0x2b) V(0x2c) V(0x2d) V(0x2e) V(0x2f) // clang-format on // The static assert below will trigger when the number of preallocated spaces @@ -73,12 +53,12 @@ class SerializerDeserializer : public RootVisitor { // 16 repeats lengths. static const int kFixedRepeatRootCount = 0x10; - // 8 hot (recently seen or back-referenced) objects with optional skip. - static const int kHotObjectCount = 8; + // Top 128 back-referenced objects. + static const int kFixedBackrefCount = 0x80; enum Bytecode : uint8_t { // - // ---------- byte code range 0x00..0x22 ---------- + // ---------- byte code range 0x00..0x26 ---------- // // 0x00..0x03 Allocate new object, in specified space. @@ -151,14 +131,14 @@ class SerializerDeserializer : public RootVisitor { // When the sandbox is enabled, a prefix indicating that the following // object is referenced through an indirect pointer, i.e. through an entry // in a pointer table. - kIndirectPointerPrefix, + kTrustedPointerPrefix, // When the sandbox is enabled, this bytecode instructs the deserializer to // initialize the "self" indirect pointer of trusted objects, which // references the object's pointer table entry. As the "self" indirect // pointer is always the first field after the map word, it is guaranteed // that it will be deserialized before any inner objects, which may require // the pointer table entry for back reference to the trusted object. - kInitializeSelfIndirectPointer, + kInitializeSelfTrustedPointer, // This bytecode instructs the deserializer to allocate an entry in the // JSDispatchTable for the host object and store the corresponding dispatch // handle into the current slot. @@ -168,11 +148,23 @@ class SerializerDeserializer : public RootVisitor { // A prefix indicating that the following object is referenced through a // protected pointer, i.e. a pointer from one trusted object to another. kProtectedPointerPrefix, + // Reference to the n-th object exported by the trusted section. + kTrustedExportRef, + // Back reference to an object in the untrusted section. + kUntrustedRef, + // Reference to the n-th external reference in the trusted section. + kTrustedExternalRef, + // Reference to previously allocated object, also registering it in the + // fixed backref table for subsequent 1-byte kFixedBackref references. + kRegisterFixedBackref, // - // ---------- byte code range 0x40..0x7f ---------- + // ---------- byte code range 0x30..0x7f ---------- // + // 0x30..0x3f + kFixedRepeatRoot = 0x30, + // 0x40..0x5f kRootArrayConstants = 0x40, @@ -180,16 +172,65 @@ class SerializerDeserializer : public RootVisitor { kFixedRawData = 0x60, // - // ---------- byte code range 0x80..0x9f ---------- + // ---------- byte code range 0x80..0xff ---------- // - // 0x80..0x8f - kFixedRepeatRoot = 0x80, - - // 0x90..0x97 - kHotObject = 0x90, + // 0x80..0xff + kFixedBackref = 0x80, }; + // Bytecodes that could corrupt memory outside the sandbox, which the + // deserializer only accepts in trusted sections. There is no default case, + // so that every new bytecode has to be classified here. + static constexpr bool IsTrustedBytecode(Bytecode bytecode) { + switch (bytecode) { + case kApiReference: + case kExternalReference: + case kSandboxedApiReference: + case kSandboxedExternalReference: + case kSandboxedRawExternalReference: + case kInitializeSelfTrustedPointer: + case kAllocateJSDispatchEntry: + case kProtectedPointerPrefix: + return true; + case kNewObject: + case kBackref: + case kReadOnlyHeapRef: + case kStartupObjectCache: + case kRootArray: + case kAttachedReference: + case kSharedHeapObjectCache: + case kNop: + case kSynchronize: + case kVariableRepeatRoot: + case kOffHeapBackingStore: + case kOffHeapResizableBackingStore: + case kEmbedderFieldsData: + case kApiWrapperFieldsData: + case kVariableRawData: + case kClearedWeakReference: + case kWeakPrefix: + case kRegisterPendingForwardRef: + case kResolvePendingForwardRef: + case kNewContextlessMetaMap: + case kNewContextfulMetaMap: + case kExtendedMapBitFieldEx: + case kTrustedPointerPrefix: + case kJSDispatchEntry: + case kTrustedExportRef: + case kUntrustedRef: + case kTrustedExternalRef: + case kRegisterFixedBackref: + case kRootArrayConstants: + case kFixedRawData: + case kFixedRepeatRoot: + case kFixedBackref: + return false; + } + // The rest of a bytecode range, or an unused bytecode. + return false; + } + // Helper class for encoding and decoding a value into and from a bytecode. // // The value is encoded by allocating an entire bytecode range, and encoding @@ -275,11 +316,28 @@ class SerializerDeserializer : public RootVisitor { using RootArrayConstant = BytecodeValueEncoder<kRootArrayConstants, 0, kRootArrayConstantsCount - 1, RootIndex>; - using HotObject = BytecodeValueEncoder<kHotObject, 0, kHotObjectCount - 1>; + using FixedBackref = + BytecodeValueEncoder<kFixedBackref, 0, kFixedBackrefCount - 1>; // This backing store reference value represents empty backing stores during // serialization/deserialization. static const uint32_t kEmptyBackingStoreRefSentinel = 0; + + // Number of bits used to encode the aligned chunk offset in kReadOnlyHeapRef. + static constexpr int kReadOnlyHeapRefOffsetBits = + kPageSizeBits - kObjectAlignmentBits; + + // An entry in the table of external references at the start of the trusted + // section of a code cache, see kTrustedExternalRef. + struct EncodedExternalReference { + ExternalReferenceEncoder::Value reference; + ExternalPointerTag tag; + // Explicit padding, so that code caches are deterministic. + uint16_t padding = 0; + }; + static_assert(sizeof(EncodedExternalReference) == sizeof(uint64_t)); + static_assert( + std::has_unique_object_representations_v<EncodedExternalReference>); }; struct SerializeEmbedderFieldsCallback { diff --git a/deps/v8/src/snapshot/serializer.cc b/deps/v8/src/snapshot/serializer.cc index 337fc8b243ed..01401869d6ab 100644 --- a/deps/v8/src/snapshot/serializer.cc +++ b/deps/v8/src/snapshot/serializer.cc @@ -4,8 +4,12 @@ #include "src/snapshot/serializer.h" +#include <algorithm> +#include <cstring> + #include "include/v8-internal.h" #include "src/base/logging.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" #include "src/common/globals.h" #include "src/handles/global-handles-inl.h" @@ -26,6 +30,7 @@ #include "src/objects/smi.h" #include "src/sandbox/check.h" #include "src/sandbox/js-dispatch-table-inl.h" +#include "src/sandbox/sandbox.h" #include "src/snapshot/embedded/embedded-data.h" #include "src/snapshot/serializer-deserializer.h" #include "src/snapshot/serializer-inl.h" @@ -35,7 +40,6 @@ namespace internal { Serializer::Serializer(Isolate* isolate, Snapshot::SerializerFlags flags) : isolate_(isolate), - hot_objects_(isolate->heap()), reference_map_(isolate), external_reference_encoder_(isolate), root_index_map_(isolate), @@ -152,13 +156,38 @@ void Serializer::SerializeDeferredObjects() { WHILE_WITH_HANDLE_SCOPE(isolate(), !deferred_objects_.empty()) { Handle<HeapObject> obj = handle(deferred_objects_.Pop(), isolate()); - ObjectSerializer obj_serializer(this, obj, &sink_); - obj_serializer.SerializeDeferred(); + const SerializerReference* back_reference = + reference_map()->LookupReference(obj); + if (back_reference != nullptr) { + if (v8_flags.trace_serializer) { + PrintF(" Deferred heap object "); + ShortPrint(*obj); + PrintF(" was already serialized\n"); + } + continue; + } + + if (v8_flags.trace_serializer) { + PrintF(" Encoding deferred heap object\n"); + } + SerializeDeferredObject(obj); } sink_.Put(kSynchronize, "Finished with deferred objects"); } +void Serializer::SerializeDeferredObject(Handle<HeapObject> obj) { + ObjectSerializer obj_serializer(this, obj, &sink_); + obj_serializer.Serialize(SlotType::kAnySlot); +} + void Serializer::SerializeObject(Handle<HeapObject> obj, SlotType slot_type) { + if (IsInaccessible(*obj)) { + // Only some roots are inaccessible. + bool result = SerializeRoot(*obj); + DCHECK(result); + USE(result); + return; + } if (IsThinString(*obj)) { // ThinStrings are just an indirection to an internalized string, so elide // the indirection and serialize the actual string directly. @@ -170,6 +199,7 @@ void Serializer::SerializeObject(Handle<HeapObject> obj, SlotType slot_type) { // For now just serialize the BytecodeArray instead of baseline code. // TODO(v8:11429,pthier): Handle Baseline code in cases we want to // serialize it. + SBXCHECK(OutsideSandbox(code.address())); obj = handle(code->bytecode_or_interpreter_data(), isolate()); } else { CHECK(code->is_builtin()); @@ -218,21 +248,6 @@ bool Serializer::SerializeRoot(Tagged<HeapObject> obj) { return false; } -bool Serializer::SerializeHotObject(Tagged<HeapObject> obj) { - DisallowGarbageCollection no_gc; - // Encode a reference to a hot object by its index in the working set. - int index = hot_objects_.Find(obj); - if (index == HotObjectsList::kNotFound) return false; - DCHECK(index >= 0 && index < kHotObjectCount); - if (v8_flags.trace_serializer) { - PrintF(" Encoding hot object %d:", index); - ShortPrint(obj); - PrintF("\n"); - } - sink_.Put(HotObject::Encode(index), "HotObject"); - return true; -} - bool Serializer::SerializeBackReference(Tagged<HeapObject> obj) { DisallowGarbageCollection no_gc; const SerializerReference* reference = reference_map_.LookupReference(obj); @@ -255,7 +270,6 @@ bool Serializer::SerializeBackReference(Tagged<HeapObject> obj) { PrintF("\n"); } - sink_.Put(kBackref, "Backref"); PutBackReference(obj, *reference); } return true; @@ -303,7 +317,6 @@ void Serializer::PutRoot(RootIndex root) { } else { sink_.Put(kRootArray, "RootSerialization"); sink_.PutUint30(root_index, "root_index"); - hot_objects_.Add(object); } } @@ -325,9 +338,17 @@ void Serializer::PutSmiRoot(FullObjectSlot slot) { void Serializer::PutBackReference(Tagged<HeapObject> object, SerializerReference reference) { - DCHECK_EQ(object, *back_refs_[reference.back_ref_index()]); - sink_.PutUint30(reference.back_ref_index(), "BackRefIndex"); - hot_objects_.Add(object); + uint32_t index = reference.back_ref_index(); + DCHECK_EQ(object, *back_refs_[index]); + uint32_t pos = static_cast<uint32_t>(sink_.Position()); + sink_.Put(kBackref, "Backref"); + sink_.PutUint30(index, "BackRefIndex"); + uint8_t len = static_cast<uint8_t>(sink_.Position() - pos); + backref_locations_.push_back({pos, index, len}); + if (index >= backref_counts_.size()) { + backref_counts_.resize(num_back_refs_, 0); + } + backref_counts_[index]++; } void Serializer::PutAttachedReference(SerializerReference reference) { @@ -426,7 +447,74 @@ void Serializer::ResolvePendingObject(Tagged<HeapObject> obj) { } } +void Serializer::OptimizeBackReferences() { + std::vector<uint32_t> candidates; + for (uint32_t i = 0; i < backref_counts_.size(); i++) { + if (backref_counts_[i] >= 2) { + candidates.push_back(i); + } + } + if (candidates.empty()) { + backref_locations_.clear(); + backref_counts_.clear(); + return; + } + + if (candidates.size() > kFixedBackrefCount) { + std::partial_sort(candidates.begin(), + candidates.begin() + kFixedBackrefCount, candidates.end(), + [this](uint32_t a, uint32_t b) { + if (backref_counts_[a] != backref_counts_[b]) { + return backref_counts_[a] > backref_counts_[b]; + } + return a > b; + }); + candidates.resize(kFixedBackrefCount); + } + + // -1: not selected; -2: selected, awaiting 1st occurrence; >= 0: fixed slot. + std::vector<int16_t> fixed_slot(backref_counts_.size(), -1); + for (uint32_t index : candidates) { + fixed_slot[index] = -2; + } + + uint8_t* data = sink_.MutableData(); + size_t read_pos = 0; + size_t write_pos = 0; + int16_t next_slot = 0; + + for (const BackrefLocation& loc : backref_locations_) { + int16_t slot = fixed_slot[loc.index]; + if (slot == -1) continue; + if (slot == -2) { + DCHECK_EQ(data[loc.position], kBackref); + data[loc.position] = kRegisterFixedBackref; + fixed_slot[loc.index] = next_slot++; + continue; + } + size_t span = loc.position - read_pos; + if (write_pos != read_pos && span > 0) { + std::memmove(data + write_pos, data + read_pos, span); + } + write_pos += span; + data[write_pos++] = FixedBackref::Encode(slot); + read_pos = loc.position + loc.length; + } + + if (write_pos != read_pos) { + size_t tail = sink_.Position() - read_pos; + if (tail > 0) { + std::memmove(data + write_pos, data + read_pos, tail); + } + write_pos += tail; + sink_.Resize(write_pos); + } + backref_locations_.clear(); + backref_counts_.clear(); +} + void Serializer::Pad(int padding_offset) { + DCHECK(backref_locations_.empty()); // The non-branching GetInt will read up to 3 bytes too far, so we need // to pad the snapshot to make sure we don't read over the end. for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) { @@ -472,17 +560,18 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space, code_name)); } + SBXCHECK_GT(size, kTaggedSize); + SBXCHECK(IsAligned(size, kTaggedSize)); + if (IsMetaMap(*object_)) { if (map == ReadOnlyRoots(isolate()).meta_map()) { DCHECK_EQ(space, SnapshotSpace::kReadOnlyHeap); sink_->Put(kNewContextlessMetaMap, "NewContextlessMetaMap"); - sink_->PutUint30(size >> kObjectAlignmentBits, "ObjectSizeInWords"); sink_->PutUint30(map->instance_type(), "MetaMapInstanceType"); } else { DCHECK_EQ(space, SnapshotSpace::kOld); DCHECK(IsContext(map->native_context_or_null())); sink_->Put(kNewContextfulMetaMap, "NewContextfulMetaMap"); - sink_->PutUint30(size >> kObjectAlignmentBits, "ObjectSizeInWords"); sink_->PutUint30(map->instance_type(), "MetaMapInstanceType"); // Defer serialization of the native context in order to break @@ -508,9 +597,6 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space, } else { sink_->Put(NewObject::Encode(space), "NewObject"); - // TODO(leszeks): Skip this when the map has a fixed size. - sink_->PutUint30(size >> kObjectAlignmentBits, "ObjectSizeInWords"); - // Until the space for the object is allocated, it is considered "pending". serializer_->RegisterObjectIsPending(*object_); @@ -520,6 +606,10 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space, // deferred. DCHECK(IsMap(map)); serializer_->SerializeObject(handle(map, isolate()), SlotType::kMapSlot); + // The deserializer reads the size of fixed-size objects from their map. + if (map->instance_size_in_words() == kVariableSizeSentinel) { + sink_->PutUint30(size >> kObjectAlignmentBits, "ObjectSizeInWords"); + } if (IsExtendedMap(*object_)) { // Extended maps store their actual size in bit_field_ex_, write it // upfront to make sure the ExtendedMap size can be fully initialized, @@ -542,8 +632,7 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space, // object cannot be referenced. if (V8_ENABLE_SANDBOX_BOOL && IsExposedTrustedObject(*object_)) { SBXCHECK_EQ(space, SnapshotSpace::kTrusted); - sink_->Put(kInitializeSelfIndirectPointer, - "InitializeSelfIndirectPointer"); + sink_->Put(kInitializeSelfTrustedPointer, "InitializeSelfTrustedPointer"); } // Now that the object is allocated, we can resolve pending references to @@ -705,30 +794,71 @@ void Serializer::ObjectSerializer::SerializeExternalString() { void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() { // Instead of serializing this as an external string, we serialize // an imaginary sequential string with the same content. - ReadOnlyRoots roots(isolate()); DCHECK(IsExternalString(*object_)); DirectHandle<ExternalString> string = Cast<ExternalString>(object_); uint32_t length = string->length(); + bool one_byte = IsExternalOneByteString(*object_); + const uint8_t* content; + if (one_byte) { + const auto* ext_resource = Cast<ExternalOneByteString>(string)->resource(); + SBXCHECK_EQ(length, ext_resource->length()); + content = reinterpret_cast<const uint8_t*>(ext_resource->data()); + } else { + const auto* ext_resource = Cast<ExternalTwoByteString>(string)->resource(); + SBXCHECK_EQ(length, ext_resource->length()); + content = reinterpret_cast<const uint8_t*>(ext_resource->data()); + } + SerializeStringAsSequentialString(one_byte, length, content); +} + +void Serializer::ObjectSerializer::SerializeSlicedStringAsSequentialString() { + // Instead of serializing this as a sliced string, we serialize an imaginary + // sequential string with the same content, so that it does not depend on its + // parent. + DCHECK(IsSlicedString(*object_)); + DisallowGarbageCollection no_gc; + String::FlatContent flat = Cast<String>(*object_)->GetFlatContent(no_gc); + DCHECK(flat.IsFlat()); + uint32_t length = flat.length(); + if (flat.IsOneByte()) { + SerializeStringAsSequentialString(true, length, + flat.ToOneByteVector().begin()); + return; + } + base::Vector<const base::uc16> chars = flat.ToUC16Vector(); + if (String::IsOneByte(chars.begin(), length)) { + // The parent of the slice is two-byte, but its contents are one-byte, so + // serialize a one-byte string (which is also what copying them would + // create). + base::UniqueArray<uint8_t> one_byte = + base::UniqueArray<uint8_t>::NewForOverwrite(length); + CopyChars(one_byte.begin(), chars.begin(), length); + SerializeStringAsSequentialString(true, length, one_byte.begin()); + return; + } + SerializeStringAsSequentialString( + false, length, reinterpret_cast<const uint8_t*>(chars.begin())); +} + +void Serializer::ObjectSerializer::SerializeStringAsSequentialString( + bool one_byte, uint32_t length, const uint8_t* content) { + ReadOnlyRoots roots(isolate()); + DirectHandle<String> string = Cast<String>(object_); Tagged<Map> map; int content_size; int allocation_size; - const uint8_t* resource; // Find the map and size for the imaginary sequential string. bool internalized = IsInternalizedString(*object_); - if (IsExternalOneByteString(*object_)) { + if (one_byte) { map = internalized ? roots.internalized_one_byte_string_map() : roots.seq_one_byte_string_map(); allocation_size = SeqOneByteString::SizeFor(length); content_size = length * kCharSize; - resource = reinterpret_cast<const uint8_t*>( - Cast<ExternalOneByteString>(string)->resource()->data()); } else { map = internalized ? roots.internalized_two_byte_string_map() : roots.seq_two_byte_string_map(); allocation_size = SeqTwoByteString::SizeFor(length); content_size = length * kShortSize; - resource = reinterpret_cast<const uint8_t*>( - Cast<ExternalTwoByteString>(string)->resource()->data()); } SnapshotSpace space = SnapshotSpace::kOld; @@ -744,13 +874,16 @@ void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() { sink_->PutUint30(slots_to_output, "length"); // Serialize string header (except for map). - uint8_t* string_start = reinterpret_cast<uint8_t*>(string->address()); - for (size_t i = sizeof(HeapObject); i < sizeof(SeqString); i++) { - sink_->Put(string_start[i], "StringHeader"); - } + static_assert(offsetof(SeqString, raw_hash_field_) == sizeof(HeapObject)); + static_assert(offsetof(SeqString, length_) == + offsetof(SeqString, raw_hash_field_) + sizeof(uint32_t)); + static_assert(sizeof(SeqString) == + sizeof(HeapObject) + sizeof(uint32_t) + sizeof(uint32_t)); + sink_->PutUint32(string->raw_hash_field(), "StringHash"); + sink_->PutUint32(length, "StringLength"); // Serialize string content. - sink_->PutRaw(resource, content_size, "StringContent"); + sink_->PutRaw(content, content_size, "StringContent"); // Since the allocation size is rounded up to object alignment, there // maybe left-over bytes that need to be padded. @@ -830,6 +963,11 @@ void Serializer::ObjectSerializer::Serialize(SlotType slot_type) { SerializeExternalString(); return; } + if (InstanceTypeChecker::IsSlicedString(instance_type) && + serializer_->SerializeSlicedStringsAsSequentialStrings()) { + SerializeSlicedStringAsSequentialString(); + return; + } if (InstanceTypeChecker::IsJSTypedArray(instance_type)) { SerializeJSTypedArray(); return; @@ -913,25 +1051,6 @@ void Serializer::ObjectSerializer::SerializeObject() { SerializeContent(map, size); } -void Serializer::ObjectSerializer::SerializeDeferred() { - const SerializerReference* back_reference = - serializer_->reference_map()->LookupReference(object_); - - if (back_reference != nullptr) { - if (v8_flags.trace_serializer) { - PrintF(" Deferred heap object "); - ShortPrint(*object_); - PrintF(" was already serialized\n"); - } - return; - } - - if (v8_flags.trace_serializer) { - PrintF(" Encoding deferred heap object\n"); - } - Serialize(SlotType::kAnySlot); -} - void Serializer::ObjectSerializer::SerializeContent(Tagged<Map> map, int size) { Tagged<HeapObject> raw = *object_; UnlinkWeakNextScope unlink_weak_next(isolate()->heap(), raw); @@ -954,9 +1073,42 @@ void Serializer::ObjectSerializer::VisitPointers(Tagged<HeapObject> host, PtrComprCageBase cage_base(isolate()); DisallowGarbageCollection no_gc; + auto IsRawCopyable = [&](MaybeObjectSlot slot) { + Tagged<MaybeObject> value = slot.load(cage_base); + if (value.IsSmi()) return true; +#if V8_STATIC_ROOTS_BOOL + Tagged<HeapObject> obj; + RootIndex root_index; + if (value.GetHeapObjectIfStrong(&obj) && HeapLayout::InReadOnlySpace(obj) && + !serializer_->root_index_map()->Lookup(obj, &root_index)) { + return true; + } +#endif // V8_STATIC_ROOTS_BOOL + return false; + }; + + // Advance `current` across contiguous slots that can be emitted as a single + // raw-data memcpy (`FixedRawData` / `VariableRawData`). Smis are always raw. + // On static-roots builds, non-root read-only strong pointers also reside at + // fixed cage offsets and need no relocation or write barriers, so they can be + // raw-copied too. However, RO refs only *join* a run and never start a + // one-slot run, since an isolated ref is cheaper as `kReadOnlyHeapRef` than + // as `FixedRawData`. + const Address object_end = object_->address() + object_->Size(); MaybeObjectSlot current = start; while (current < end) { - while (current < end && current.load(cage_base).IsSmi()) { + const Address raw_start = object_->address() + bytes_processed_so_far_; + while (current < end && IsRawCopyable(current)) { + if (!current.load(cage_base).IsSmi()) { + MaybeObjectSlot next = current + 1; + const bool run_already_open = current.address() > raw_start; + const bool followed_by_raw_payload = + next == end && end.address() < object_end; + const bool next_is_raw = next < end && IsRawCopyable(next); + if (!run_already_open && !followed_by_raw_payload && !next_is_raw) { + break; + } + } ++current; } if (current < end) { @@ -1088,6 +1240,9 @@ void Serializer::ObjectSerializer::OutputExternalReference( sink_->PutRaw(reinterpret_cast<uint8_t*>(&target), target_size, "raw pointer"); } + } else if (sandboxify && serializer_->SerializeTrustedExternalReference( + encoded_reference, tag)) { + return; } else if (encoded_reference.is_from_api()) { if (sandboxify) { sink_->Put(kSandboxedApiReference, "SandboxedApiRef"); @@ -1163,31 +1318,30 @@ void Serializer::ObjectSerializer::VisitExternalPointer( // resource_data_ is initialized in PostProcessExternalString, and // extension_ in PostProcessNewJSReceiver. Serializing them as null also // keeps the snapshot deterministic, as both hold values that are only - // meaningful within the serializing isolate. - value = kNullAddress; - tag = kExternalPointerNullTag; + // meaningful within the serializing isolate. They are written as raw + // data, so that they need no external reference. + static_assert(kExternalPointerSlotSize % kTaggedSize == 0); + sink_->Put(FixedRawDataWithSize::Encode(kExternalPointerSlotSize >> + kTaggedSizeLog2), + "FixedRawData"); + sink_->PutRaw(reinterpret_cast<const uint8_t*>(&kNullExternalPointer), + kExternalPointerSlotSize, "null external pointer"); + } else { + const bool sandboxify = V8_ENABLE_SANDBOX_BOOL; + OutputExternalReference(value, kSystemPointerSize, sandboxify, tag); } - const bool sandboxify = V8_ENABLE_SANDBOX_BOOL; - OutputExternalReference(value, kSystemPointerSize, sandboxify, tag); bytes_processed_so_far_ += kExternalPointerSlotSize; } else { // Serialization of external references in other objects is handled // elsewhere or not supported. - DCHECK( - // Serialization of external pointers stored in - // JSSynchronizationPrimitive is not supported. - // TODO(v8:12547): JSSynchronizationPrimitives should also be sanitized - // to always be serialized in an unlocked state. - InstanceTypeChecker::IsJSSynchronizationPrimitive(instance_type) || - // See ContextSerializer::SerializeObjectWithEmbedderFields(). - (InstanceTypeChecker::IsJSObject(instance_type) && - Cast<JSObject>(host)->GetEmbedderFieldCount() > 0)); + // See ContextSerializer::SerializeObjectWithEmbedderFields(). + DCHECK(InstanceTypeChecker::IsJSObject(instance_type) && + Cast<JSObject>(host)->GetEmbedderFieldCount() > 0); } } -void Serializer::ObjectSerializer::VisitIndirectPointer( - Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) { +void Serializer::ObjectSerializer::VisitTrustedPointer( + Tagged<HeapObject> host, TrustedPointerSlot slot, TrustedPointerMode mode) { #ifdef V8_ENABLE_SANDBOX // If the slot is empty (i.e. contains a null handle), then we can just skip // it since in that case the correct action is to encode the null handle as @@ -1202,12 +1356,12 @@ void Serializer::ObjectSerializer::VisitIndirectPointer( Handle<HeapObject> slot_value(Cast<HeapObject>(slot.load(isolate())), isolate()); CHECK(IsHeapObject(*slot_value)); - bytes_processed_so_far_ += kIndirectPointerSize; + bytes_processed_so_far_ += kTrustedPointerSize; // Currently we cannot see pending objects here, but we may need to support // them in the future. They should already be supported by the deserializer. CHECK(!serializer_->SerializePendingObject(*slot_value)); - sink_->Put(kIndirectPointerPrefix, "IndirectPointer"); + sink_->Put(kTrustedPointerPrefix, "TrustedPointer"); serializer_->SerializeObject(slot_value, SlotType::kAnySlot); #else UNREACHABLE(); @@ -1215,16 +1369,16 @@ void Serializer::ObjectSerializer::VisitIndirectPointer( } void Serializer::ObjectSerializer::VisitTrustedPointerTableEntry( - Tagged<HeapObject> host, IndirectPointerSlot slot) { + Tagged<HeapObject> host, TrustedPointerSlot slot) { #ifdef V8_ENABLE_SANDBOX // These fields only exist on the ExposedTrustedObject class, and they are // located directly after the Map word. DCHECK_EQ(bytes_processed_so_far_, - offsetof(ExposedTrustedObject, self_indirect_pointer_)); + offsetof(ExposedTrustedObject, self_trusted_pointer_)); - // Nothing to do here. We already emitted the kInitializeSelfIndirectPointer + // Nothing to do here. We already emitted the kInitializeSelfTrustedPointer // after processing the Map word in SerializePrologue. - bytes_processed_so_far_ += kIndirectPointerSize; + bytes_processed_so_far_ += kTrustedPointerSize; #else UNREACHABLE(); #endif @@ -1232,6 +1386,7 @@ void Serializer::ObjectSerializer::VisitTrustedPointerTableEntry( void Serializer::ObjectSerializer::VisitProtectedPointer( Tagged<TrustedObject> host, ProtectedPointerSlot slot) { + SBXCHECK(OutsideSandbox(host.address())); Tagged<Object> content = slot.load(isolate()); // Similar to the indirect pointer case, if the slot is empty (i.e. contains @@ -1254,6 +1409,7 @@ void Serializer::ObjectSerializer::VisitProtectedPointer( void Serializer::ObjectSerializer::VisitProtectedPointer( Tagged<TrustedObject> host, ProtectedMaybeObjectSlot slot) { + SBXCHECK(OutsideSandbox(host.address())); Tagged<MaybeObject> maybe_content = slot.load(); // Empty slots (Smi::zero()) and Smi slots can be skipped here. if (maybe_content.IsSmi()) return; @@ -1327,7 +1483,7 @@ void OutputRawWithCustomField(SnapshotByteSink* sink, Address object_start, const uint8_t* field_value) { int offset = field_offset - written_so_far; if (0 <= offset && offset < bytes_to_write) { - DCHECK_GE(bytes_to_write, offset + field_size); + SBXCHECK_GE(bytes_to_write, offset + field_size); sink->PutRaw(reinterpret_cast<uint8_t*>(object_start + written_so_far), offset, "Bytes"); sink->PutRaw(field_value, field_size, "Bytes"); @@ -1348,10 +1504,10 @@ void Serializer::ObjectSerializer::OutputRawData(Address up_to) { int up_to_offset = static_cast<int>(up_to - object_start); int to_skip = up_to_offset - bytes_processed_so_far_; int bytes_to_output = to_skip; - DCHECK(IsAligned(bytes_to_output, kTaggedSize)); + SBXCHECK(IsAligned(bytes_to_output, kTaggedSize)); int tagged_to_output = bytes_to_output / kTaggedSize; bytes_processed_so_far_ += to_skip; - DCHECK_GE(to_skip, 0); + SBXCHECK_GE(to_skip, 0); if (bytes_to_output != 0) { DCHECK(to_skip == bytes_to_output); if (tagged_to_output <= kFixedRawDataCount) { @@ -1399,6 +1555,20 @@ void Serializer::ObjectSerializer::OutputRawData(Address up_to) { OutputRawWithCustomField(sink_, object_start, base, bytes_to_output, offsetof(JSArrayBuffer, backing_store_), sizeof(field_value), field_value); + } else if (IsUncompiledDataWithoutPreparseDataWithJob(*object_)) { + // The job field contains a raw pointer that is not valid after + // deserialization, so write zeros instead. + static uint8_t field_value[kSystemPointerSize] = {0}; + OutputRawWithCustomField( + sink_, object_start, base, bytes_to_output, + offsetof(UncompiledDataWithoutPreparseDataWithJob, job_), + sizeof(field_value), field_value); + } else if (IsUncompiledDataWithPreparseDataAndJob(*object_)) { + static uint8_t field_value[kSystemPointerSize] = {0}; + OutputRawWithCustomField( + sink_, object_start, base, bytes_to_output, + offsetof(UncompiledDataWithPreparseDataAndJob, job_), + sizeof(field_value), field_value); } else if (IsSeqString(*object_)) { // SeqStrings may contain padding. Serialize the padding bytes as 0s to // make the snapshot content deterministic. @@ -1418,15 +1588,6 @@ void Serializer::ObjectSerializer::OutputRawData(Address up_to) { } } -Serializer::HotObjectsList::HotObjectsList(Heap* heap) : heap_(heap) { - strong_roots_entry_ = heap->RegisterStrongRoots( - "Serializer::HotObjectsList", FullObjectSlot(&circular_queue_[0]), - FullObjectSlot(&circular_queue_[kSize])); -} -Serializer::HotObjectsList::~HotObjectsList() { - heap_->UnregisterStrongRoots(strong_roots_entry_); -} - DirectHandle<FixedArray> ObjectCacheIndexMap::Values(Isolate* isolate) { if (size() == 0) { return isolate->factory()->empty_fixed_array(); @@ -1446,11 +1607,11 @@ DirectHandle<FixedArray> ObjectCacheIndexMap::Values(Isolate* isolate) { bool Serializer::SerializeReadOnlyObjectReference(Tagged<HeapObject> obj, SnapshotByteSink* sink) { - if (!ReadOnlyHeap::Contains(obj)) return false; + if (!HeapLayout::InReadOnlySpace(obj)) return false; // For objects on the read-only heap, never serialize the object, but instead // create a back reference that encodes the page number as the chunk_index and - // the offset within the page as the chunk_offset. + // the aligned offset within the page. Address address = obj.address(); BasePage* chunk = BasePage::FromAddress(isolate(), address); uint32_t chunk_index = 0; @@ -1461,9 +1622,12 @@ bool Serializer::SerializeReadOnlyObjectReference(Tagged<HeapObject> obj, ++chunk_index; } uint32_t chunk_offset = static_cast<uint32_t>(chunk->Offset(address)); + DCHECK(IsAligned(chunk_offset, kObjectAlignment)); + DCHECK_LT(chunk_offset, kRegularPageSize); + uint32_t encoded = (chunk_index << kReadOnlyHeapRefOffsetBits) | + (chunk_offset >> kObjectAlignmentBits); sink->Put(kReadOnlyHeapRef, "ReadOnlyHeapRef"); - sink->PutUint30(chunk_index, "ReadOnlyHeapRefChunkIndex"); - sink->PutUint30(chunk_offset, "ReadOnlyHeapRefChunkOffset"); + sink->PutUint30(encoded, "ReadOnlyHeapRef"); return true; } diff --git a/deps/v8/src/snapshot/serializer.h b/deps/v8/src/snapshot/serializer.h index 85d3556be70e..6ec335017fde 100644 --- a/deps/v8/src/snapshot/serializer.h +++ b/deps/v8/src/snapshot/serializer.h @@ -223,11 +223,17 @@ class Serializer : public SerializerDeserializer { V8_INLINE bool IsNotMappedSymbol(Tagged<HeapObject> obj) const; void SerializeDeferredObjects(); + virtual void SerializeDeferredObject(Handle<HeapObject> obj); void SerializeObject(Handle<HeapObject> o, SlotType slot_type); virtual void SerializeObjectImpl(Handle<HeapObject> o, SlotType slot_type) = 0; virtual bool MustBeDeferred(Tagged<HeapObject> object); + // Whether sliced strings are serialized as sequential strings, so that the + // deserialized strings do not depend on their parents. + virtual bool SerializeSlicedStringsAsSequentialStrings() const { + return false; + } void VisitRootPointers(Root root, const char* description, FullObjectSlot start, FullObjectSlot end) override; @@ -251,9 +257,6 @@ class Serializer : public SerializerDeserializer { // Returns true if the object was successfully serialized as a root. bool SerializeRoot(Tagged<HeapObject> obj); - // Returns true if the object was successfully serialized as hot object. - bool SerializeHotObject(Tagged<HeapObject> obj); - // Returns true if the object was successfully serialized as back reference. bool SerializeBackReference(Tagged<HeapObject> obj); @@ -270,9 +273,18 @@ class Serializer : public SerializerDeserializer { return external_reference_encoder_.TryEncode(addr); } + // Returns true if the sandboxed external reference was serialized as a + // reference into the trusted section. + virtual bool SerializeTrustedExternalReference( + ExternalReferenceEncoder::Value reference, ExternalPointerTag tag) { + return false; + } + bool SerializeReadOnlyObjectReference(Tagged<HeapObject> obj, SnapshotByteSink* sink); + void OptimizeBackReferences(); + // GetInt reads 4 bytes at once, requiring padding at the end. // Use padding_offset to specify the space you want to use after padding. void Pad(int padding_offset = 0); @@ -338,46 +350,12 @@ class Serializer : public SerializerDeserializer { } private: - // A circular queue of hot objects. This is added to in the same order as in - // Deserializer::HotObjectsList, but this stores the objects as an array of - // raw addresses that are considered strong roots. This allows objects to be - // added to the list without having to extend their handle's lifetime. - // - // We should never allow this class to return Handles to objects in the queue, - // as the object in the queue may change if kSize other objects are added to - // the queue during that Handle's lifetime. - class HotObjectsList { - public: - explicit HotObjectsList(Heap* heap); - ~HotObjectsList(); - HotObjectsList(const HotObjectsList&) = delete; - HotObjectsList& operator=(const HotObjectsList&) = delete; - - void Add(Tagged<HeapObject> object) { - circular_queue_[index_] = object.ptr(); - index_ = (index_ + 1) & kSizeMask; - } - - static const int kNotFound = -1; - - int Find(Tagged<HeapObject> object) { - DCHECK(!AllowGarbageCollection::IsAllowed()); - for (int i = 0; i < kSize; i++) { - if (circular_queue_[i] == object.ptr()) { - return i; - } - } - return kNotFound; - } + friend class TrustedSectionSerializer; - private: - static const int kSize = kHotObjectCount; - static const int kSizeMask = kSize - 1; - static_assert(base::bits::IsPowerOfTwo(kSize)); - Heap* heap_; - StrongRootsEntry* strong_roots_entry_; - Address circular_queue_[kSize] = {kNullAddress}; - int index_ = 0; + struct BackrefLocation { + uint32_t position; + uint32_t index; + uint8_t length; }; // Disallow GC during serialization. @@ -385,7 +363,6 @@ class Serializer : public SerializerDeserializer { DISALLOW_GARBAGE_COLLECTION(no_gc_) Isolate* isolate_; - HotObjectsList hot_objects_; SerializerReferenceMap reference_map_; ExternalReferenceEncoder external_reference_encoder_; RootIndexMap root_index_map_; @@ -394,6 +371,8 @@ class Serializer : public SerializerDeserializer { GlobalHandleVector<HeapObject> deferred_objects_; // To handle stack overflow. int num_back_refs_ = 0; + std::vector<BackrefLocation> backref_locations_; + std::vector<uint32_t> backref_counts_; // Used to provide deterministic IDs to the serialized dispatch handles. std::unordered_map<JSDispatchHandle, uint32_t> dispatch_handle_map_; @@ -462,7 +441,6 @@ class Serializer::ObjectSerializer : public ObjectVisitor { } void Serialize(SlotType slot_type); void SerializeObject(); - void SerializeDeferred(); void VisitPointers(Tagged<HeapObject> host, ObjectSlot start, ObjectSlot end) override; void VisitPointers(Tagged<HeapObject> host, MaybeObjectSlot start, @@ -482,10 +460,10 @@ class Serializer::ObjectSerializer : public ObjectVisitor { void VisitExternalPointer(Tagged<HeapObject> host, ExternalPointerSlot slot) override; - void VisitIndirectPointer(Tagged<HeapObject> host, IndirectPointerSlot slot, - IndirectPointerMode mode) override; + void VisitTrustedPointer(Tagged<HeapObject> host, TrustedPointerSlot slot, + TrustedPointerMode mode) override; void VisitTrustedPointerTableEntry(Tagged<HeapObject> host, - IndirectPointerSlot slot) override; + TrustedPointerSlot slot) override; void VisitProtectedPointer(Tagged<TrustedObject> host, ProtectedPointerSlot slot) override; void VisitProtectedPointer(Tagged<TrustedObject> host, @@ -513,6 +491,9 @@ class Serializer::ObjectSerializer : public ObjectVisitor { void SerializeNativeContext(); void SerializeExternalString(); void SerializeExternalStringAsSequentialString(); + void SerializeSlicedStringAsSequentialString(); + void SerializeStringAsSequentialString(bool one_byte, uint32_t length, + const uint8_t* content); Isolate* isolate_; Serializer* serializer_; diff --git a/deps/v8/src/snapshot/shared-heap-deserializer.cc b/deps/v8/src/snapshot/shared-heap-deserializer.cc index bc302869d69c..94ad2cbe4de2 100644 --- a/deps/v8/src/snapshot/shared-heap-deserializer.cc +++ b/deps/v8/src/snapshot/shared-heap-deserializer.cc @@ -4,6 +4,7 @@ #include "src/snapshot/shared-heap-deserializer.h" +#include "src/base/platform/elapsed-timer.h" #include "src/heap/heap-inl.h" namespace v8 { @@ -20,6 +21,8 @@ void SharedHeapDeserializer::DeserializeIntoIsolate() { return; } + base::ElapsedTimer timer; + if (V8_UNLIKELY(v8_flags.profile_deserialization)) timer.Start(); DCHECK(isolate()->shared_heap_object_cache()->empty()); HandleScope scope(isolate()); @@ -33,6 +36,15 @@ void SharedHeapDeserializer::DeserializeIntoIsolate() { // there is no need to call `HashSeed::InitializeRoots(isolate());`. Rehash(); } + + if (V8_UNLIKELY(v8_flags.profile_deserialization)) { + // ATTENTION: The Memory.json benchmark greps for this exact output. Do not + // change it without also updating Memory.json. + const size_t bytes = source()->length(); + const double ms = timer.Elapsed().InMillisecondsF(); + PrintF("[Deserializing shared heap (%zu bytes) took %0.3f ms]\n", bytes, + ms); + } } void SharedHeapDeserializer::DeserializeStringTable() { diff --git a/deps/v8/src/snapshot/shared-heap-deserializer.h b/deps/v8/src/snapshot/shared-heap-deserializer.h index 15492d938d8f..024017cfbfc0 100644 --- a/deps/v8/src/snapshot/shared-heap-deserializer.h +++ b/deps/v8/src/snapshot/shared-heap-deserializer.h @@ -19,7 +19,9 @@ class SharedHeapDeserializer final : public Deserializer<Isolate> { const SnapshotData* shared_heap_data, bool can_rehash) : Deserializer(isolate, shared_heap_data->Payload(), - shared_heap_data->GetMagicNumber(), false, can_rehash) {} + /* trusted_payload */ {}, + shared_heap_data->GetMagicNumber(), + /* deserializing_user_code */ false, can_rehash) {} // Depending on runtime flags, deserialize shared heap objects into the // Isolate. diff --git a/deps/v8/src/snapshot/shared-heap-serializer.cc b/deps/v8/src/snapshot/shared-heap-serializer.cc index 212d41a1edda..c0ccb2aa7b99 100644 --- a/deps/v8/src/snapshot/shared-heap-serializer.cc +++ b/deps/v8/src/snapshot/shared-heap-serializer.cc @@ -63,6 +63,7 @@ void SharedHeapSerializer::FinalizeSerialization() { // internalizable-in-place strings are in the shared heap. SerializeStringTable(isolate()->string_table()); SerializeDeferredObjects(); + OptimizeBackReferences(); Pad(); #ifdef DEBUG @@ -167,7 +168,6 @@ void SharedHeapSerializer::SerializeObjectImpl(Handle<HeapObject> obj, { DisallowGarbageCollection no_gc; Tagged<HeapObject> raw = *obj; - if (SerializeHotObject(raw)) return; if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return; } if (SerializeReadOnlyObjectReference(*obj, &sink_)) return; diff --git a/deps/v8/src/snapshot/snapshot-compression.cc b/deps/v8/src/snapshot/snapshot-compression.cc index 935312cfecc9..a4bbaae6281e 100644 --- a/deps/v8/src/snapshot/snapshot-compression.cc +++ b/deps/v8/src/snapshot/snapshot-compression.cc @@ -4,6 +4,7 @@ #include "src/snapshot/snapshot-compression.h" +#include "src/base/numerics/safe_conversions.h" #include "src/base/platform/elapsed-timer.h" #include "src/utils/memcopy.h" #include "src/utils/utils.h" @@ -28,13 +29,13 @@ SnapshotData SnapshotCompression::Compress( const uLongf input_size = static_cast<uLongf>(uncompressed_data->RawData().size()); uint32_t payload_length = - static_cast<uint32_t>(uncompressed_data->RawData().size()); + base::checked_cast<uint32_t>(uncompressed_data->RawData().size()); uLongf compressed_data_size = compressBound(input_size); // Allocating >= the final amount we will need. - snapshot_data.AllocateData( - static_cast<uint32_t>(sizeof(payload_length) + compressed_data_size)); + snapshot_data.AllocateData(base::checked_cast<uint32_t>( + sizeof(payload_length) + compressed_data_size)); uint8_t* compressed_data = const_cast<uint8_t*>(snapshot_data.RawData().begin()); @@ -51,8 +52,8 @@ SnapshotData SnapshotCompression::Compress( Z_OK); // Reallocating to exactly the size we need. - snapshot_data.Resize(static_cast<uint32_t>(compressed_data_size) + - sizeof(payload_length)); + snapshot_data.Resize(base::checked_cast<uint32_t>(sizeof(payload_length) + + compressed_data_size)); DCHECK_EQ(payload_length, GetUncompressedSize(snapshot_data.RawData().begin())); diff --git a/deps/v8/src/snapshot/snapshot-data.cc b/deps/v8/src/snapshot/snapshot-data.cc index 08da9c03da32..17949e624c6c 100644 --- a/deps/v8/src/snapshot/snapshot-data.cc +++ b/deps/v8/src/snapshot/snapshot-data.cc @@ -4,8 +4,7 @@ #include "src/snapshot/snapshot-data.h" -#include <limits> - +#include "src/base/numerics/safe_conversions.h" #include "src/common/assert-scope.h" #include "src/snapshot/serializer.h" @@ -27,7 +26,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) { const std::vector<uint8_t>* payload = serializer->Payload(); // Calculate sizes. - uint32_t size = kHeaderSize + static_cast<uint32_t>(payload->size()); + uint32_t size = base::checked_cast<uint32_t>(payload->size() + kHeaderSize); // Allocate backing store and create result data. AllocateData(size); @@ -37,7 +36,6 @@ SnapshotData::SnapshotData(const Serializer* serializer) { // Set header values. SetMagicNumber(); - CHECK_LE(payload->size(), std::numeric_limits<uint32_t>::max()); SetHeaderValue(kPayloadLengthOffset, static_cast<uint32_t>(payload->size())); // Copy serialized data. diff --git a/deps/v8/src/snapshot/snapshot-source-sink.h b/deps/v8/src/snapshot/snapshot-source-sink.h index f915e1dfaa8b..b82238830b73 100644 --- a/deps/v8/src/snapshot/snapshot-source-sink.h +++ b/deps/v8/src/snapshot/snapshot-source-sink.h @@ -36,6 +36,12 @@ class SnapshotByteSource final { SnapshotByteSource(const SnapshotByteSource&) = delete; SnapshotByteSource& operator=(const SnapshotByteSource&) = delete; + void Reset(base::Vector<const uint8_t> payload) { + data_ = payload.begin(); + length_ = payload.length(); + position_ = 0; + } + bool HasMore() { return position_ < length_; } uint8_t Get() { @@ -56,7 +62,7 @@ class SnapshotByteSource final { position_ += number_of_bytes; } - void CopySlots(Address* dest, int number_of_slots) { + void CopySlots(Address* dest, uint32_t number_of_slots) { base::AtomicWord* start = reinterpret_cast<base::AtomicWord*>(dest); base::AtomicWord* end = start + number_of_slots; for (base::AtomicWord* p = start; p < end; @@ -68,7 +74,7 @@ class SnapshotByteSource final { } #ifdef V8_COMPRESS_POINTERS - void CopySlots(Tagged_t* dest, int number_of_slots) { + void CopySlots(Tagged_t* dest, uint32_t number_of_slots) { AtomicTagged_t* start = reinterpret_cast<AtomicTagged_t*>(dest); AtomicTagged_t* end = start + number_of_slots; for (AtomicTagged_t* p = start; p < end; @@ -125,7 +131,7 @@ class SnapshotByteSource final { * * Users must implement actual storage or i/o. */ -class SnapshotByteSink { +class V8_EXPORT_PRIVATE SnapshotByteSink { public: SnapshotByteSink() = default; explicit SnapshotByteSink(int initial_size) : data_(initial_size) {} @@ -147,6 +153,8 @@ class SnapshotByteSink { size_t Position() const { return data_.size(); } const std::vector<uint8_t>* data() const { return &data_; } + uint8_t* MutableData() { return data_.data(); } + void Resize(size_t size) { data_.resize(size); } private: std::vector<uint8_t> data_; diff --git a/deps/v8/src/snapshot/snapshot.cc b/deps/v8/src/snapshot/snapshot.cc index 90b6076caba9..4e8e1b44f76c 100644 --- a/deps/v8/src/snapshot/snapshot.cc +++ b/deps/v8/src/snapshot/snapshot.cc @@ -7,6 +7,7 @@ #include "src/snapshot/snapshot.h" #include "src/api/api-inl.h" // For OpenHandle. +#include "src/base/numerics/safe_conversions.h" #include "src/baseline/baseline-batch-compiler.h" #include "src/common/assert-scope.h" #include "src/execution/local-isolate-inl.h" @@ -309,6 +310,8 @@ void Snapshot::ClearReconstructableDataForSerialization( ReadOnlyRoots roots(isolate); isolate->heap()->SetFunctionsMarkedForManualOptimization( roots.undefined_value()); + isolate->heap()->SetFunctionsMarkedForDisabledEagerInlining( + roots.undefined_value()); #if V8_ENABLE_WEBASSEMBLY { @@ -410,41 +413,60 @@ v8::StartupData Snapshot::Create( HandleScope scope(isolate); flags |= Snapshot::kAllowSerializingAllTrustedObjects; + const int num_contexts = static_cast<int>(contexts->size()); + const bool profile = v8_flags.profile_deserialization; + base::ElapsedTimer timer; + double ro_ms = 0; + double startup_ms = 0; + double shared_heap_ms = 0; + std::vector<double> context_ms(num_contexts, 0.0); + + if (profile) timer.Start(); ReadOnlySerializer read_only_serializer(isolate, flags); read_only_serializer.Serialize(); + if (profile) ro_ms += timer.Elapsed().InMillisecondsF(); // TODO(v8:6593): generalize rehashing, and remove this flag. bool can_be_rehashed = read_only_serializer.can_be_rehashed(); SharedHeapSerializer shared_heap_serializer(isolate, flags); + if (profile) timer.Restart(); StartupSerializer startup_serializer(isolate, flags, &shared_heap_serializer); startup_serializer.SerializeStrongReferences(no_gc); + if (profile) startup_ms += timer.Elapsed().InMillisecondsF(); // Serialize each context with a new serializer. - const int num_contexts = static_cast<int>(contexts->size()); std::vector<SnapshotData*> context_snapshots; context_snapshots.reserve(num_contexts); std::vector<int> context_allocation_sizes; for (int i = 0; i < num_contexts; i++) { + if (profile) timer.Restart(); ContextSerializer context_serializer(isolate, flags, &startup_serializer, embedder_fields_serializers[i]); context_serializer.Serialize(&contexts->at(i), no_gc); can_be_rehashed = can_be_rehashed && context_serializer.can_be_rehashed(); context_snapshots.push_back(new SnapshotData(&context_serializer)); + if (profile) context_ms[i] = timer.Elapsed().InMillisecondsF(); if (v8_flags.serialization_statistics) { context_allocation_sizes.push_back( context_serializer.TotalAllocationSize()); } } + if (profile) timer.Restart(); startup_serializer.SerializeWeakReferencesAndDeferred(); can_be_rehashed = can_be_rehashed && startup_serializer.can_be_rehashed(); startup_serializer.CheckNoDirtyFinalizationRegistries(); + if (profile) { + startup_ms += timer.Elapsed().InMillisecondsF(); + timer.Restart(); + } shared_heap_serializer.FinalizeSerialization(); can_be_rehashed = can_be_rehashed && shared_heap_serializer.can_be_rehashed(); + if (profile) shared_heap_ms += timer.Elapsed().InMillisecondsF(); if (v8_flags.serialization_statistics) { DCHECK_NE(read_only_serializer.TotalAllocationSize(), 0); @@ -470,9 +492,31 @@ v8::StartupData Snapshot::Create( PrintF("\n"); } + if (profile) timer.Restart(); SnapshotData read_only_snapshot(&read_only_serializer); + if (profile) { + ro_ms += timer.Elapsed().InMillisecondsF(); + timer.Restart(); + } SnapshotData shared_heap_snapshot(&shared_heap_serializer); + if (profile) { + shared_heap_ms += timer.Elapsed().InMillisecondsF(); + timer.Restart(); + } SnapshotData startup_snapshot(&startup_serializer); + if (profile) { + startup_ms += timer.Elapsed().InMillisecondsF(); + PrintF("[Serializing read-only space (%d bytes) took %0.3f ms]\n", + read_only_snapshot.RawData().length(), ro_ms); + PrintF("[Serializing isolate (%d bytes) took %0.3f ms]\n", + startup_snapshot.RawData().length(), startup_ms); + PrintF("[Serializing shared heap (%d bytes) took %0.3f ms]\n", + shared_heap_snapshot.RawData().length(), shared_heap_ms); + for (int i = 0; i < num_contexts; i++) { + PrintF("[Serializing context #%d (%d bytes) took %0.3f ms]\n", i, + context_snapshots[i]->RawData().length(), context_ms[i]); + } + } v8::StartupData result = SnapshotImpl::CreateSnapshotBlob( &startup_snapshot, &read_only_snapshot, &shared_heap_snapshot, context_snapshots, can_be_rehashed); @@ -526,16 +570,16 @@ v8::StartupData SnapshotImpl::CreateSnapshotBlob( uint32_t num_contexts = static_cast<uint32_t>(context_snapshots->size()); uint32_t read_only_offset = SnapshotImpl::ReadOnlySnapshotOffset(num_contexts); - uint32_t total_length = read_only_offset; - total_length += static_cast<uint32_t>(read_only_snapshot->RawData().length()); - total_length += static_cast<uint32_t>(startup_snapshot->RawData().length()); - total_length += - static_cast<uint32_t>(shared_heap_snapshot->RawData().length()); + size_t total_length = read_only_offset; + total_length += read_only_snapshot->RawData().length(); + total_length += startup_snapshot->RawData().length(); + total_length += shared_heap_snapshot->RawData().length(); for (const auto context_snapshot : *context_snapshots) { - total_length += static_cast<uint32_t>(context_snapshot->RawData().length()); + total_length += context_snapshot->RawData().length(); } - char* data = new char[total_length]; + int total_length_int = base::checked_cast<int>(total_length); + char* data = new char[total_length_int]; // Zero out pre-payload data. Part of that is only used for padding. memset(data, 0, read_only_offset); @@ -619,7 +663,7 @@ v8::StartupData SnapshotImpl::CreateSnapshotBlob( if (v8_flags.serialization_statistics) PrintF("\n"); DCHECK_EQ(total_length, payload_offset); - v8::StartupData result = {data, static_cast<int>(total_length)}; + v8::StartupData result = {data, total_length_int}; SnapshotImpl::SetHeaderValue( data, SnapshotImpl::kChecksumOffset, diff --git a/deps/v8/src/snapshot/startup-deserializer.cc b/deps/v8/src/snapshot/startup-deserializer.cc index c2c1e0adbd1c..65a61c607faa 100644 --- a/deps/v8/src/snapshot/startup-deserializer.cc +++ b/deps/v8/src/snapshot/startup-deserializer.cc @@ -34,17 +34,18 @@ void StartupDeserializer::DeserializeIntoIsolate() { DCHECK(isolate()->handle_scope_implementer()->blocks()->empty()); // Startup object cache is not yet populated. DCHECK(isolate()->startup_object_cache()->empty()); - // Builtins are not yet created. - DCHECK(!isolate()->builtins()->is_initialized()); + // Builtins are already initialized if Code objects are in RO space. + DCHECK_EQ(isolate()->builtins()->is_initialized(), + Builtins::kCodeObjectsAreInROSpace); { DeserializeAndCheckExternalReferenceTable(); isolate()->heap()->IterateSmiRoots(this); isolate()->heap()->IterateRoots( - this, - base::EnumSet<SkipRoot>{SkipRoot::kUnserializable, SkipRoot::kWeak, - SkipRoot::kTracedHandles}); + this, base::EnumSet<SkipRoot>{SkipRoot::kUnserializable, + SkipRoot::kWeak, SkipRoot::kTracedHandles, + SkipRoot::kReadOnlyBuiltins}); IterateStartupObjectCache(isolate(), this); isolate()->heap()->IterateWeakRoots( @@ -81,7 +82,9 @@ void StartupDeserializer::DeserializeIntoIsolate() { isolate()->heap()->set_dirty_js_finalization_registries_list_tail( ReadOnlyRoots(isolate()).undefined_value()); - isolate()->builtins()->MarkInitialized(); + if (!Builtins::kCodeObjectsAreInROSpace) { + isolate()->builtins()->MarkInitialized(); + } LogNewMapEvents(); diff --git a/deps/v8/src/snapshot/startup-deserializer.h b/deps/v8/src/snapshot/startup-deserializer.h index 60ad43d5b54c..2d0af17b16b3 100644 --- a/deps/v8/src/snapshot/startup-deserializer.h +++ b/deps/v8/src/snapshot/startup-deserializer.h @@ -18,7 +18,8 @@ class StartupDeserializer final : public Deserializer<Isolate> { const SnapshotData* startup_data, bool can_rehash) : Deserializer(isolate, startup_data->Payload(), - startup_data->GetMagicNumber(), false, can_rehash) {} + /* trusted_payload */ {}, startup_data->GetMagicNumber(), + /* deserializing_user_code */ false, can_rehash) {} // Deserialize the snapshot into an empty heap. void DeserializeIntoIsolate(); diff --git a/deps/v8/src/snapshot/startup-serializer.cc b/deps/v8/src/snapshot/startup-serializer.cc index 4a40ef5e3373..fec4496e08a3 100644 --- a/deps/v8/src/snapshot/startup-serializer.cc +++ b/deps/v8/src/snapshot/startup-serializer.cc @@ -120,7 +120,6 @@ void StartupSerializer::SerializeObjectImpl(Handle<HeapObject> obj, DisallowGarbageCollection no_gc; Tagged<HeapObject> raw = *obj; DCHECK(!IsInstructionStream(raw)); - if (SerializeHotObject(raw)) return; if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return; } @@ -174,6 +173,7 @@ void StartupSerializer::SerializeWeakReferencesAndDeferred() { isolate()->heap()->IterateWeakRoots( this, base::EnumSet<SkipRoot>{SkipRoot::kUnserializable}); SerializeDeferredObjects(); + OptimizeBackReferences(); Pad(); } @@ -191,7 +191,8 @@ void StartupSerializer::SerializeStrongReferences( isolate->heap()->IterateSmiRoots(this); isolate->heap()->IterateRoots( this, base::EnumSet<SkipRoot>{SkipRoot::kUnserializable, SkipRoot::kWeak, - SkipRoot::kTracedHandles}); + SkipRoot::kTracedHandles, + SkipRoot::kReadOnlyBuiltins}); } SerializedHandleChecker::SerializedHandleChecker( diff --git a/deps/v8/src/snapshot/static-roots-gen.cc b/deps/v8/src/snapshot/static-roots-gen.cc index 0ed189cc975e..0be3d3822d0b 100644 --- a/deps/v8/src/snapshot/static-roots-gen.cc +++ b/deps/v8/src/snapshot/static-roots-gen.cc @@ -58,15 +58,21 @@ void StaticRootsTableGen::write(Isolate* isolate, const char* file) { CHECK(file); static_assert(static_cast<int>(RootIndex::kFirstReadOnlyRoot) == 0); - std::string file_str(file); - std::string defname = file_str.substr(file_str.find_last_of("/\\") + 1); - std::for_each(defname.begin(), defname.end(), [](char& c) { - if (c == '.' || c == '-') { - c = '_'; - } else { - c = std::toupper(c); - } - }); + // The include guard follows the checked-in path, + // src/gen/<intl>-<wasm>/static-roots.h. The configuration is the one + // this binary was built with, which is also what determines the table. + std::string defname = +#ifdef V8_INTL_SUPPORT + "INTL_" +#else + "NOINTL_" +#endif +#if V8_ENABLE_WEBASSEMBLY + "WASM_" +#else + "NOWASM_" +#endif + "STATIC_ROOTS_H"; std::ofstream out(file, std::ios::binary); @@ -78,8 +84,8 @@ void StaticRootsTableGen::write(Isolate* isolate, const char* file) { << "// This file is automatically generated by " "`tools/dev/gen-static-roots.py`. Do\n// not edit manually.\n" << "\n" - << "#ifndef V8_ROOTS_" << defname << "_\n" - << "#define V8_ROOTS_" << defname << "_\n" + << "#ifndef V8_GEN_" << defname << "_\n" + << "#define V8_GEN_" << defname << "_\n" << "\n" << "// IWYU pragma: private \"src/roots/static-roots.h\"\n" << "\n" @@ -200,7 +206,7 @@ void StaticRootsTableGen::write(Isolate* isolate, const char* file) { << "} // namespace internal\n" << "} // namespace v8\n" << "#endif // V8_STATIC_ROOTS_BOOL\n" - << "#endif // V8_ROOTS_" << defname << "_\n"; + << "#endif // V8_GEN_" << defname << "_\n"; } void StaticRootsTableGen::write_text(Isolate* isolate, const char* file) { @@ -215,7 +221,8 @@ void StaticRootsTableGen::write_text(Isolate* isolate, const char* file) { const std::list<RootIndex>& roots = entry.second; for (RootIndex root : roots) { - out << "0x" << std::hex << ptr << " = k" << gen.camel_name(root) << "\n"; + out << "0x" << std::hex << ptr << std::dec << " = k" + << gen.camel_name(root) << "\n"; } } #endif diff --git a/deps/v8/src/snapshot/trusted-section-serializer.cc b/deps/v8/src/snapshot/trusted-section-serializer.cc new file mode 100644 index 000000000000..cceab1efc816 --- /dev/null +++ b/deps/v8/src/snapshot/trusted-section-serializer.cc @@ -0,0 +1,113 @@ +// Copyright 2026 the V8 project 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 "src/snapshot/trusted-section-serializer.h" + +#include "src/base/numerics/safe_conversions.h" +#include "src/handles/global-handles-inl.h" +#include "src/objects/objects-inl.h" +#include "src/sandbox/check.h" +#include "src/sandbox/sandbox.h" + +namespace v8 { +namespace internal { + +TrustedSectionSerializer::TrustedSectionSerializer( + Isolate* isolate, Serializer* untrusted_serializer) + : Serializer(isolate, untrusted_serializer->flags_), + untrusted_serializer_(untrusted_serializer), + exports_(isolate->heap()), + export_queue_(isolate->heap()) {} + +uint32_t TrustedSectionSerializer::Export(Tagged<HeapObject> obj) { + SBXCHECK(OutsideSandbox(obj.address())); + int index; + if (!exports_.LookupOrInsert(obj, &index)) export_queue_.Enqueue(obj); + return base::checked_cast<uint32_t>(index); +} + +uint32_t TrustedSectionSerializer::AddExternalReference( + ExternalReferenceEncoder::Value reference, ExternalPointerTag tag) { + external_references_.push_back({reference, tag}); + return base::checked_cast<uint32_t>(external_references_.size() - 1); +} + +void TrustedSectionSerializer::SerializeExports() { + if (v8_flags.trace_serializer) { + PrintF("Serializing trusted exports\n"); + } + // Serializing an export can add untrusted objects to the untrusted section, + // and those can export more trusted objects. Export() appends them to the + // queue, so keep going until it is drained. + while (!export_queue_.empty()) { + HandleScope scope(isolate()); + Handle<HeapObject> obj = handle(export_queue_.Dequeue(), isolate()); + SerializeObject(obj, SlotType::kAnySlot); + } + DCHECK(deferred_objects_empty()); +} + +void TrustedSectionSerializer::FinishSection() { + sink_.Put(kSynchronize, "EndOfTrustedSection"); + // The external references are read before the untrusted section, so they + // precede Payload() in the trusted section, which is padded as a whole. + external_references_sink_.PutUint30( + base::checked_cast<uint32_t>(external_references_.size()), + "ExternalReferenceCount"); + external_references_sink_.PutRaw( + reinterpret_cast<const uint8_t*>(external_references_.data()), + external_references_.size() * sizeof(EncodedExternalReference), + "ExternalReferences"); + OptimizeBackReferences(); + Pad(base::checked_cast<int>(external_references_sink_.Position())); +} + +bool TrustedSectionSerializer::SerializeUntrustedReference( + Handle<HeapObject> obj) { + if (OutsideSandbox(obj->address())) return false; + if (!untrusted_serializer_->ReferenceMapContains(obj)) { + untrusted_serializer_->SerializeObject(obj, SlotType::kAnySlot); + untrusted_serializer_->SerializeDeferredObjects(); + } + const SerializerReference* reference = + untrusted_serializer_->reference_map()->LookupReference(*obj); + DCHECK_NOT_NULL(reference); + if (v8_flags.trace_serializer) { + PrintF(" Encoding untrusted reference to: "); + ShortPrint(*obj); + PrintF("\n"); + } + if (reference->is_attached_reference()) { + PutAttachedReference(*reference); + } else { + sink_.Put(kUntrustedRef, "UntrustedRef"); + sink_.PutUint30(reference->back_ref_index(), "UntrustedRefIndex"); + } + return true; +} + +void TrustedSectionSerializer::SerializeObjectImpl(Handle<HeapObject> obj, + SlotType slot_type) { + { + DisallowGarbageCollection no_gc; + Tagged<HeapObject> raw = *obj; + if (SerializeRoot(raw)) return; + if (SerializeReadOnlyObjectReference(raw, &sink_)) return; + if (SerializeUntrustedReference(obj)) return; + if (SerializeBackReference(raw)) return; +#ifdef DEBUG + DCHECK(!untrusted_serializer_->ReferenceMapContains(obj)); + if (IsExposedTrustedObject(raw)) { + int index; + DCHECK(exports_.Lookup(raw, &index)); + DCHECK_GE(index, 0); + } +#endif + } + ObjectSerializer serializer(this, obj, &sink_); + serializer.Serialize(slot_type); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/snapshot/trusted-section-serializer.h b/deps/v8/src/snapshot/trusted-section-serializer.h new file mode 100644 index 000000000000..19fe8a893dd9 --- /dev/null +++ b/deps/v8/src/snapshot/trusted-section-serializer.h @@ -0,0 +1,56 @@ +// Copyright 2026 the V8 project 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 V8_SNAPSHOT_TRUSTED_SECTION_SERIALIZER_H_ +#define V8_SNAPSHOT_TRUSTED_SECTION_SERIALIZER_H_ + +#include <vector> + +#include "src/snapshot/serializer.h" + +namespace v8 { +namespace internal { + +// Serializes the trusted section of a snapshot that is split in two: +// - The untrusted section holds the objects inside the sandbox. It is written +// by |untrusted_serializer| and deserialized in a mode that can't write +// outside the sandbox. It refers to the trusted section only by index, see +// Export and AddExternalReference. +// - The trusted section holds the objects outside the sandbox and the table of +// external references. It is written by this class. +class TrustedSectionSerializer final : public Serializer { + public: + TrustedSectionSerializer(Isolate* isolate, Serializer* untrusted_serializer); + ~TrustedSectionSerializer() override { + OutputStatistics("TrustedSectionSerializer"); + } + + // Returns the index of |obj| in the exports, adding it if it is new. + uint32_t Export(Tagged<HeapObject> obj); + // Adds an entry to the table of external references and returns its index. + uint32_t AddExternalReference(ExternalReferenceEncoder::Value reference, + ExternalPointerTag tag); + + void SerializeExports(); + void FinishSection(); + const std::vector<uint8_t>* ExternalReferencesPayload() const { + return external_references_sink_.data(); + } + + private: + void SerializeObjectImpl(Handle<HeapObject> o, SlotType slot_type) override; + // Puts in-sandbox objects into the untrusted section and refers to them. + bool SerializeUntrustedReference(Handle<HeapObject> obj); + + Serializer* const untrusted_serializer_; + ObjectCacheIndexMap exports_; + GlobalHandleCircularQueue<HeapObject> export_queue_; + std::vector<EncodedExternalReference> external_references_; + SnapshotByteSink external_references_sink_; +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_SNAPSHOT_TRUSTED_SECTION_SERIALIZER_H_ diff --git a/deps/v8/src/strings/string-hasher.cc b/deps/v8/src/strings/string-hasher.cc index bea067c6f03f..6708f121980a 100644 --- a/deps/v8/src/strings/string-hasher.cc +++ b/deps/v8/src/strings/string-hasher.cc @@ -77,7 +77,7 @@ uint64_t HashConvertingTo8Bit(const uint16_t* chars, uint32_t length, bool IsOnly8BitSIMD(const uint16_t* chars, unsigned len) { namespace hw = hwy::HWY_NAMESPACE; - hw::FixedTag<uint16_t, 8> tag; + hw::CappedTag<uint16_t, 8> tag; const size_t stride = hw::Lanes(tag); const auto high_byte_mask = hw::Set(tag, static_cast<uint16_t>(0xFF00)); const auto zero = hw::Zero(tag); diff --git a/deps/v8/src/strings/string-search.h b/deps/v8/src/strings/string-search.h index 01326900990f..b8876ed4f0c2 100644 --- a/deps/v8/src/strings/string-search.h +++ b/deps/v8/src/strings/string-search.h @@ -300,26 +300,30 @@ int StringSearch<PatternChar, SubjectChar>::BoyerMooreSearch( base::Vector<const PatternChar> pattern = search->pattern_; int subject_length = subject.length(); int pattern_length = pattern.length(); + CHECK_GE(start_index, 0); + CHECK_GE(pattern_length, kBMMinPatternLength); + const PatternChar* pattern_data = pattern.data(); + const SubjectChar* subject_data = subject.data(); // Only preprocess at most kBMMaxShift last characters of pattern. int start = search->start_; int* bad_char_occurence = search->bad_char_table(); int* good_suffix_shift = search->good_suffix_shift_table(); - PatternChar last_char = pattern[pattern_length - 1]; + PatternChar last_char = pattern_data[pattern_length - 1]; int index = start_index; // Continue search from i. while (index <= subject_length - pattern_length) { int j = pattern_length - 1; int c; - while (last_char != (c = subject[index + j])) { + while (last_char != (c = subject_data[index + j])) { int shift = j - CharOccurrence(bad_char_occurence, c); index += shift; if (index > subject_length - pattern_length) { return -1; } } - while (j >= 0 && pattern[j] == (c = subject[index + j])) j--; + while (j >= 0 && pattern_data[j] == (c = subject_data[index + j])) j--; if (j < 0) { return index; } else if (j < start) { @@ -345,10 +349,11 @@ int StringSearch<PatternChar, SubjectChar>::BoyerMooreSearch( template <typename PatternChar, typename SubjectChar> void StringSearch<PatternChar, SubjectChar>::PopulateBoyerMooreTable() { int pattern_length = pattern_.length(); - const PatternChar* pattern = pattern_.begin(); + const PatternChar* pattern = pattern_.data(); // Only look at the last kBMMaxShift characters of pattern (from start_ // to pattern_length). int start = start_; + CHECK_GE(start, 0); int length = pattern_length - start; // Biased tables so that we can use pattern indices as table indices, @@ -419,11 +424,15 @@ int StringSearch<PatternChar, SubjectChar>::BoyerMooreHorspoolSearch( base::Vector<const PatternChar> pattern = search->pattern_; int subject_length = subject.length(); int pattern_length = pattern.length(); + CHECK_GE(start_index, 0); + CHECK_GE(pattern_length, kBMMinPatternLength); + const PatternChar* pattern_data = pattern.data(); + const SubjectChar* subject_data = subject.data(); int* char_occurrences = search->bad_char_table(); int badness = -pattern_length; // How bad we are doing without a good-suffix table. - PatternChar last_char = pattern[pattern_length - 1]; + PatternChar last_char = pattern_data[pattern_length - 1]; int last_char_shift = pattern_length - 1 - CharOccurrence(char_occurrences, static_cast<SubjectChar>(last_char)); @@ -432,7 +441,7 @@ int StringSearch<PatternChar, SubjectChar>::BoyerMooreHorspoolSearch( while (index <= subject_length - pattern_length) { int j = pattern_length - 1; int subject_char; - while (last_char != (subject_char = subject[index + j])) { + while (last_char != (subject_char = subject_data[index + j])) { int bc_occ = CharOccurrence(char_occurrences, subject_char); int shift = j - bc_occ; index += shift; @@ -442,7 +451,7 @@ int StringSearch<PatternChar, SubjectChar>::BoyerMooreHorspoolSearch( } } j--; - while (j >= 0 && pattern[j] == (subject[index + j])) j--; + while (j >= 0 && pattern_data[j] == (subject_data[index + j])) j--; if (j < 0) { return index; } else { @@ -465,11 +474,13 @@ int StringSearch<PatternChar, SubjectChar>::BoyerMooreHorspoolSearch( template <typename PatternChar, typename SubjectChar> void StringSearch<PatternChar, SubjectChar>::PopulateBoyerMooreHorspoolTable() { int pattern_length = pattern_.length(); + const PatternChar* pattern = pattern_.data(); int* bad_char_occurrence = bad_char_table(); // Only preprocess at most kBMMaxShift last characters of pattern. int start = start_; + CHECK_GE(start, 0); // Run forwards to populate bad_char_table, so that *last* instance // of character equivalence class is the one registered. // Notice: Doesn't include the last character. @@ -482,7 +493,7 @@ void StringSearch<PatternChar, SubjectChar>::PopulateBoyerMooreHorspoolTable() { } } for (int i = start; i < pattern_length - 1; i++) { - PatternChar c = pattern_[i]; + PatternChar c = pattern[i]; int bucket = (sizeof(PatternChar) == 1) ? c : c % AlphabetSize(); bad_char_occurrence[bucket] = i; } @@ -500,6 +511,10 @@ int StringSearch<PatternChar, SubjectChar>::InitialSearch( base::Vector<const SubjectChar> subject, int index) { base::Vector<const PatternChar> pattern = search->pattern_; int pattern_length = pattern.length(); + CHECK_GE(index, 0); + CHECK_GE(pattern_length, kBMMinPatternLength); + const PatternChar* pattern_data = pattern.data(); + const SubjectChar* subject_data = subject.data(); // Badness is a count of how much work we have done. When we have // done enough work we decide it's probably worth switching to a better // algorithm. @@ -515,7 +530,7 @@ int StringSearch<PatternChar, SubjectChar>::InitialSearch( DCHECK_LE(i, n); int j = 1; do { - if (pattern[j] != subject[i + j]) { + if (pattern_data[j] != subject_data[i + j]) { break; } j++; diff --git a/deps/v8/src/strings/string-stream.cc b/deps/v8/src/strings/string-stream.cc index edfa98f7d71d..c6bf940f0195 100644 --- a/deps/v8/src/strings/string-stream.cc +++ b/deps/v8/src/strings/string-stream.cc @@ -4,6 +4,7 @@ #include "src/strings/string-stream.h" +#include <array> #include <memory> #include "src/base/vector.h" @@ -87,20 +88,19 @@ static bool IsControlChar(char c) { } } -void StringStream::Add(base::Vector<const char> format, - base::Vector<FmtElm> elms) { +void StringStream::Add(std::string_view format, std::span<const FmtElm> elms) { // If we already ran out of space then return immediately. if (full()) return; - int offset = 0; - int elm = 0; + size_t offset = 0; + size_t elm = 0; while (offset < format.length()) { - if (format[offset] != '%' || elm == elms.length()) { + if (format[offset] != '%' || elm == elms.size()) { Put(format[offset]); offset++; continue; } // Read this formatting directive into a temporary buffer - base::EmbeddedVector<char, 24> temp; + std::array<char, 24> temp; int format_length = 0; // Skip over the whole control character sequence until the // format element type @@ -154,9 +154,9 @@ void StringStream::Add(base::Vector<const char> format, case 'c': case 'X': { int value = current.data_.u_int_; - base::EmbeddedVector<char, 24> formatted; - int length = SNPrintF(formatted, temp.begin(), value); - Add(base::Vector<const char>(formatted.begin(), length)); + std::array<char, 24> formatted; + int length = base::SNPrintF(formatted, temp.data(), value); + Add(std::string_view(formatted.data(), length)); break; } case 'f': @@ -170,17 +170,17 @@ void StringStream::Add(base::Vector<const char> format, } else if (std::isnan(value)) { Add("nan"); } else { - base::EmbeddedVector<char, 28> formatted; - SNPrintF(formatted, temp.begin(), value); - Add(formatted.begin()); + std::array<char, 28> formatted; + base::SNPrintF(formatted, temp.data(), value); + Add(formatted.data()); } break; } case 'p': { void* value = current.data_.u_pointer_; - base::EmbeddedVector<char, 20> formatted; - SNPrintF(formatted, temp.begin(), value); - Add(formatted.begin()); + std::array<char, 20> formatted; + base::SNPrintF(formatted, temp.data(), value); + Add(formatted.data()); break; } default: @@ -250,7 +250,7 @@ void StringStream::OutputToFile(FILE* out) { DirectHandle<String> StringStream::ToString(Isolate* isolate) { return isolate->factory() - ->NewStringFromUtf8(base::Vector<const char>(buffer_, length_)) + ->NewStringFromUtf8(std::string_view(buffer_, length_)) .ToHandleChecked(); } diff --git a/deps/v8/src/strings/string-stream.h b/deps/v8/src/strings/string-stream.h index 233aec0e46af..058ef4a1e2c5 100644 --- a/deps/v8/src/strings/string-stream.h +++ b/deps/v8/src/strings/string-stream.h @@ -6,6 +6,8 @@ #define V8_STRINGS_STRING_STREAM_H_ #include <memory> +#include <span> +#include <string_view> #include "src/base/small-vector.h" #include "src/base/strings.h" @@ -153,20 +155,12 @@ class StringStream final { bool Put(char c); bool Put(Tagged<String> str); bool Put(Tagged<String> str, int start, int end); - void Add(const char* format) { Add(base::CStrVector(format)); } - void Add(base::Vector<const char> format) { - Add(format, base::Vector<FmtElm>()); - } - - template <typename... Args> - void Add(const char* format, Args... args) { - Add(base::CStrVector(format), args...); - } + void Add(std::string_view format) { Add(format, std::span<const FmtElm>{}); } template <typename... Args> - void Add(base::Vector<const char> format, Args... args) { + void Add(std::string_view format, Args... args) { FmtElm elems[]{args...}; - Add(format, base::ArrayVector(elems)); + Add(format, std::span<const FmtElm>(elems)); } // Getting the message out. @@ -205,7 +199,7 @@ class StringStream final { static const int kInitialCapacity = 16; private: - void Add(base::Vector<const char> format, base::Vector<FmtElm> elms); + void Add(std::string_view format, std::span<const FmtElm> elms); void PrintObject(Tagged<Object> obj); StringAllocator* allocator_; diff --git a/deps/v8/src/strings/uri.cc b/deps/v8/src/strings/uri.cc index ac595714966f..234db370711b 100644 --- a/deps/v8/src/strings/uri.cc +++ b/deps/v8/src/strings/uri.cc @@ -191,13 +191,13 @@ MaybeDirectHandle<String> Uri::Decode(Isolate* isolate, } if (two_byte_buffer.empty()) { - return isolate->factory()->NewStringFromOneByte(base::Vector<const uint8_t>( - one_byte_buffer.data(), static_cast<int>(one_byte_buffer.size()))); + return isolate->factory()->NewStringFromOneByte( + base::VectorOf(one_byte_buffer)); } DirectHandle<SeqTwoByteString> result; - int result_length = - static_cast<int>(one_byte_buffer.size() + two_byte_buffer.size()); + uint32_t result_length = + static_cast<uint32_t>(one_byte_buffer.size() + two_byte_buffer.size()); ASSIGN_RETURN_ON_EXCEPTION( isolate, result, isolate->factory()->NewRawTwoByteString(result_length)); diff --git a/deps/v8/src/torque/ast.h b/deps/v8/src/torque/ast.h index 06ff51adcf63..0f96d176594c 100644 --- a/deps/v8/src/torque/ast.h +++ b/deps/v8/src/torque/ast.h @@ -936,6 +936,7 @@ struct StructFieldExpression { struct BitFieldDeclaration { NameAndTypeExpression name_and_type; int num_bits; + std::optional<int> offset = std::nullopt; }; enum class ConditionalAnnotationType { diff --git a/deps/v8/src/torque/cpp-builder.cc b/deps/v8/src/torque/cpp-builder.cc index 986e33873c98..0f19249fb72d 100644 --- a/deps/v8/src/torque/cpp-builder.cc +++ b/deps/v8/src/torque/cpp-builder.cc @@ -24,7 +24,14 @@ void Function::PrintDeclarationHeader(std::ostream& stream, } if (IsStatic()) stream << "static "; if (IsConstexpr()) stream << "constexpr "; - stream << return_type_ << " " << name_ << "("; + stream << return_type_ << " "; + std::streampos begin = stream.tellp(); + stream << name_; + std::streampos end = stream.tellp(); + if (kythe_cb_ && end != std::streampos(-1)) { + kythe_cb_(stream, static_cast<size_t>(begin), static_cast<size_t>(end)); + } + stream << "("; bool first = true; for (const auto& p : parameters_) { if (!first) stream << ", "; @@ -77,7 +84,7 @@ void Function::PrintBeginDefinition(std::ostream& stream, if (!class_template_parameters.empty()) { stream << std::string(indentation, ' '); stream << "template<"; - scope += "<"; + scope += '<'; bool first = true; for (const auto& p : class_template_parameters) { if (!first) { @@ -93,12 +100,18 @@ void Function::PrintBeginDefinition(std::ostream& stream, first = false; } stream << ">\n"; - scope += ">"; + scope += '>'; } scope += "::"; } - stream << std::string(indentation, ' ') << return_type_ << " " << scope - << name_ << "("; + stream << std::string(indentation, ' ') << return_type_ << " " << scope; + std::streampos begin = stream.tellp(); + stream << name_; + std::streampos end = stream.tellp(); + if (kythe_cb_ && end != std::streampos(-1)) { + kythe_cb_(stream, static_cast<size_t>(begin), static_cast<size_t>(end)); + } + stream << "("; bool first = true; for (const auto& p : parameters_) { if (!first) stream << ", "; diff --git a/deps/v8/src/torque/cpp-builder.h b/deps/v8/src/torque/cpp-builder.h index 0ab4659fbf4f..9209a4f8eb80 100644 --- a/deps/v8/src/torque/cpp-builder.h +++ b/deps/v8/src/torque/cpp-builder.h @@ -156,6 +156,9 @@ class Function { int indentation = 2) const; void PrintBeginDefinition(std::ostream& stream, int indentation = 0) const; void PrintEndDefinition(std::ostream& stream, int indentation = 0) const; + void SetKytheCallback(std::function<void(std::ostream&, size_t, size_t)> cb) { + kythe_cb_ = std::move(cb); + } protected: void PrintDeclarationHeader(std::ostream& stream, int indentation) const; @@ -168,6 +171,7 @@ class Function { std::string return_type_; std::vector<Parameter> parameters_; base::Flags<FunctionFlag> flags_; + std::function<void(std::ostream&, size_t, size_t)> kythe_cb_; }; DEFINE_OPERATORS_FOR_FLAGS(base::Flags<Function::FunctionFlag>) diff --git a/deps/v8/src/torque/declaration-visitor.cc b/deps/v8/src/torque/declaration-visitor.cc index e98f7efef4a5..336e79764f0e 100644 --- a/deps/v8/src/torque/declaration-visitor.cc +++ b/deps/v8/src/torque/declaration-visitor.cc @@ -233,6 +233,9 @@ void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl) { signature, decl->use_counter_name, decl->body); builtin->SetIdentifierPosition(decl->name->pos); builtin->SetPosition(decl->pos); + if (GlobalContext::collect_kythe_data()) { + KytheData::AddFunctionDefinition(builtin); + } Declarations::Declare(decl->name->value, builtin); } @@ -456,6 +459,13 @@ Callable* DeclarationVisitor::Specialize( builtin, GlobalContext::MakeUniqueName(generated_name), readable_name.str(), type_signature, use_counter_name, *body); } + callable->SetIdentifierPosition(explicit_specialization + ? (*explicit_specialization)->name->pos + : declaration->name->pos); + if (GlobalContext::collect_kythe_data() && + Intrinsic::DynamicCast(callable) == nullptr) { + KytheData::AddFunctionDefinition(callable); + } key.generic->AddSpecialization(key.specialized_types, callable); return callable; } diff --git a/deps/v8/src/torque/earley-parser.cc b/deps/v8/src/torque/earley-parser.cc index fe4fb4ee92ef..69b7253158fd 100644 --- a/deps/v8/src/torque/earley-parser.cc +++ b/deps/v8/src/torque/earley-parser.cc @@ -20,6 +20,7 @@ namespace v8::internal::torque { namespace { struct LineAndColumnTracker { + SourceId source = CurrentSourceFile::Get(); LineAndColumn previous{0, 0, 0}; LineAndColumn current{0, 0, 0}; @@ -37,9 +38,7 @@ struct LineAndColumnTracker { } } - SourcePosition ToSourcePosition() { - return {CurrentSourceFile::Get(), previous, current}; - } + SourcePosition ToSourcePosition() { return {source, previous, current}; } }; } // namespace @@ -118,12 +117,18 @@ void Item::CheckAmbiguity(const Item& other, const LexerResult& tokens) const { } LexerResult Lexer::RunLexer(const std::string& input) { + LineAndColumn zero{0, 0, 0}; + return RunLexer(input, {CurrentSourceFile::Get(), zero, zero}); +} + +LexerResult Lexer::RunLexer(const std::string& input, SourcePosition origin) { LexerResult result; InputPosition const begin = input.c_str(); InputPosition const end = begin + input.size(); InputPosition pos = begin; InputPosition token_start = pos; - LineAndColumnTracker line_column_tracker; + LineAndColumnTracker line_column_tracker{origin.source, origin.start, + origin.start}; match_whitespace_(&pos); line_column_tracker.Advance(token_start, pos); diff --git a/deps/v8/src/torque/earley-parser.h b/deps/v8/src/torque/earley-parser.h index 73e300c84bd5..5ac216a42949 100644 --- a/deps/v8/src/torque/earley-parser.h +++ b/deps/v8/src/torque/earley-parser.h @@ -43,6 +43,7 @@ enum class ParseResultHolderBase::TypeId { kStdString, kBool, kInt32, + kOptionalInt32, kDouble, kIntegerLiteral, kStdVectorOfString, @@ -403,6 +404,8 @@ class Lexer { Symbol* Pattern(PatternFunction pattern) { return &patterns_[pattern]; } Symbol* Token(const std::string& keyword) { return &keywords_[keyword]; } V8_EXPORT_PRIVATE LexerResult RunLexer(const std::string& input); + V8_EXPORT_PRIVATE LexerResult RunLexer(const std::string& input, + SourcePosition origin); private: PatternFunction match_whitespace_ = [](InputPosition*) { return false; }; @@ -425,6 +428,12 @@ class Grammar { return ParseTokens(start_, tokens); } + std::optional<ParseResult> Parse(Symbol* start, const std::string& input, + SourcePosition origin) { + LexerResult tokens = lexer().RunLexer(input, origin); + return ParseTokens(start, tokens); + } + protected: Symbol* Token(const std::string& s) { return lexer_.Token(s); } Symbol* Pattern(PatternFunction pattern) { return lexer_.Pattern(pattern); } diff --git a/deps/v8/src/torque/global-context.cc b/deps/v8/src/torque/global-context.cc index a0bafed92aa0..0cc16e16d750 100644 --- a/deps/v8/src/torque/global-context.cc +++ b/deps/v8/src/torque/global-context.cc @@ -14,6 +14,8 @@ GlobalContext::GlobalContext(Ast ast) force_assert_statements_(false), annotate_ir_(false), torque_dwarf_(false), + has_kythe_inline_metadata_(false), + kythe_default_corpus_(""), ast_(std::move(ast)) { CurrentScope::Scope current_scope(nullptr); CurrentSourcePosition::Scope current_source_position( diff --git a/deps/v8/src/torque/global-context.h b/deps/v8/src/torque/global-context.h index b9c4c210b8a5..cb7c08b6554c 100644 --- a/deps/v8/src/torque/global-context.h +++ b/deps/v8/src/torque/global-context.h @@ -84,11 +84,48 @@ class GlobalContext : public base::ContextualClass<GlobalContext> { static void SetAnnotateIR() { Get().annotate_ir_ = true; } static void SetTorqueDwarf() { Get().torque_dwarf_ = true; } static bool annotate_ir() { return Get().annotate_ir_; } + static void SetKytheInlineMetadata() { + Get().has_kythe_inline_metadata_ = true; + } + static bool has_kythe_inline_metadata() { + return Get().has_kythe_inline_metadata_; + } + static void SetKytheDefaultCorpus(std::string corpus) { + Get().kythe_default_corpus_ = std::move(corpus); + } + static const std::string& kythe_default_corpus() { + return Get().kythe_default_corpus_; + } static Ast* ast() { return &Get().ast_; } static std::string MakeUniqueName(const std::string& base) { return base + "_" + std::to_string(Get().fresh_ids_[base]++); } + struct KytheInlineMetadata { + size_t begin; + size_t end; + std::string vname_sig; + std::string vname_path = ""; + size_t source_begin = 0; + size_t source_end = 0; + bool is_call_anchor = false; + + static KytheInlineMetadata Generates(size_t begin, size_t end, + std::string vname_sig, + std::string vname_path) { + return {begin, end, std::move(vname_sig), std::move(vname_path), 0, + 0, false}; + } + + static KytheInlineMetadata CallAnchor(size_t begin, size_t end, + size_t source_begin, + size_t source_end, + std::string vname_path) { + return {begin, end, "", std::move(vname_path), + source_begin, source_end, true}; + } + }; + struct PerFileStreams { PerFileStreams() : file(SourceId::Invalid()), @@ -98,8 +135,10 @@ class GlobalContext : public base::ContextualClass<GlobalContext> { SourceId file; std::stringstream csa_headerfile; cpp::File csa_header; + std::vector<KytheInlineMetadata> csa_header_rules; std::stringstream csa_ccfile; cpp::File csa_cc; + std::vector<KytheInlineMetadata> csa_cc_rules; std::stringstream class_definition_ccfile; cpp::File class_definition_cc; @@ -138,6 +177,8 @@ class GlobalContext : public base::ContextualClass<GlobalContext> { bool force_assert_statements_; bool annotate_ir_; bool torque_dwarf_; + bool has_kythe_inline_metadata_; + std::string kythe_default_corpus_; Namespace* default_namespace_; Ast ast_; std::vector<std::unique_ptr<Declarable>> declarables_; diff --git a/deps/v8/src/torque/implementation-visitor.cc b/deps/v8/src/torque/implementation-visitor.cc index ecfd37f1ff3d..f796a3f0487b 100644 --- a/deps/v8/src/torque/implementation-visitor.cc +++ b/deps/v8/src/torque/implementation-visitor.cc @@ -7,8 +7,11 @@ #include <algorithm> #include <iomanip> #include <optional> +#include <set> #include <string> +#include <string_view> +#include "simdutf.h" #include "src/common/globals.h" #include "src/numbers/integer-literal-inl.h" #include "src/torque/cc-generator.h" @@ -33,6 +36,87 @@ uint64_t next_unique_binding_index = 0; namespace { const char* BuiltinIncludesMarker = "// __BUILTIN_INCLUDES_MARKER__\n"; + +std::string Base64Encode(std::string_view input) { + std::string output(simdutf::base64_length_from_binary(input.size()), '\0'); + size_t written = + simdutf::binary_to_base64(input.data(), input.size(), output.data()); + DCHECK_EQ(written, output.size()); + USE(written); + return output; +} + +// Returns the path of `file` as recorded in the Torque CLI invocation (with any +// relative `../` or `./` prefixes stripped), preserving the repository root +// prefix passed via `-v8-root` (e.g. `third_party/v8/HEAD/...`) so that +// generated Kythe VNames match the paths indexed by Kythe extractors. +std::string KytheSourceFilePath(SourceId file) { + std::string abs_path = SourceFileMap::AbsolutePath(file); + std::string_view path(abs_path); + while (true) { + if (path.starts_with("../")) { + path.remove_prefix(3); + } else if (path.starts_with("./")) { + path.remove_prefix(2); + } else if (path.starts_with("/")) { + path.remove_prefix(1); + } else { + break; + } + } + return std::string(path); +} + +void EmitKytheInlineMetadata( + std::ostream& stream, + const std::vector<GlobalContext::KytheInlineMetadata>& rules) { + if (!GlobalContext::has_kythe_inline_metadata() || rules.empty()) return; + const std::string& corpus = GlobalContext::kythe_default_corpus(); + std::stringstream json; + json << "{\n" + << " \"type\": \"kythe0\",\n" + << " \"meta\": [\n"; + for (size_t i = 0; i < rules.size(); ++i) { + const std::string& rule_path = rules[i].vname_path; + if (i > 0) json << ",\n"; + if (rules[i].is_call_anchor) { + json << " {\n" + << " \"type\": \"anchor_anchor\",\n" + << " \"target_begin\": " << rules[i].begin << ",\n" + << " \"target_end\": " << rules[i].end << ",\n" + << " \"source_begin\": " << rules[i].source_begin << ",\n" + << " \"source_end\": " << rules[i].source_end << ",\n" + << " \"edge\": \"/kythe/edge/ref/call\",\n" + << " \"source_vname\": {\n" + << " \"signature\": \"\",\n" + << " \"corpus\": \"" << corpus << "\",\n" + << " \"path\": \"" << rule_path << "\",\n" + << " \"language\": \"torque\",\n" + << " \"root\": \"\"\n" + << " }\n" + << " }"; + } else { + json << " {\n" + << " \"type\": \"anchor_defines\",\n" + << " \"begin\": " << rules[i].begin << ",\n" + << " \"end\": " << rules[i].end << ",\n" + << " \"edge\": \"%/kythe/edge/generates\",\n" + << " \"vname\": {\n" + << " \"signature\": \"" << rules[i].vname_sig << "\",\n" + << " \"corpus\": \"" << corpus << "\",\n" + << " \"path\": \"" << rule_path << "\",\n" + << " \"language\": \"torque\",\n" + << " \"root\": \"\"\n" + << " }\n" + << " }"; + } + } + json << "\n ]\n}\n"; + stream << "\n#ifdef KYTHE_IS_RUNNING\n" + << "#pragma kythe_inline_metadata \"v8_torque_metadata\"\n" + << "#endif\n" + << "// v8_torque_metadata " << Base64Encode(json.str()) << "\n"; +} } // namespace VisitResult ImplementationVisitor::Visit(Expression* expr) { @@ -148,6 +232,7 @@ void ImplementationVisitor::EndGeneratedFiles() { streams.csa_header.EndNamespace("v8", "internal"); streams.csa_headerfile << "\n"; + EmitKytheInlineMetadata(streams.csa_headerfile, streams.csa_header_rules); streams.csa_header.EndIncludeGuard(header_define); } @@ -578,7 +663,23 @@ void ImplementationVisitor::Visit(Builtin* builtin) { const std::string& name = builtin->ExternalName(); const Signature& signature = builtin->signature(); - csa_ccfile() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n" + csa_ccfile() << "TF_BUILTIN("; + size_t begin = static_cast<size_t>(csa_ccfile().tellp()); + csa_ccfile() << name; + size_t end = static_cast<size_t>(csa_ccfile().tellp()); + if (GlobalContext::has_kythe_inline_metadata() && + CurrentFileStreams::HasScope()) { + const SourcePosition ident_pos = builtin->IdentifierPosition(); + if (auto* streams = CurrentFileStreams::Get(); + streams && ident_pos.IsValid()) { + streams->csa_cc_rules.push_back( + GlobalContext::KytheInlineMetadata::CallAnchor( + begin, end, static_cast<size_t>(ident_pos.start.offset), + static_cast<size_t>(ident_pos.end.offset), + KytheSourceFilePath(ident_pos.source))); + } + } + csa_ccfile() << ", CodeStubAssembler) {\n" << " compiler::CodeAssemblerState* state_ = state();" << " compiler::CodeAssembler ca_(state());\n"; @@ -1827,14 +1928,33 @@ void ImplementationVisitor::GenerateImplementation(const std::string& dir) { CHECK_NE(pos, std::string::npos); std::string includes; for (const SourceId& include : streams.required_builtin_includes) { + // A field built from the layout JSON is positioned at the C++ + // header that declares it, which has no generated counterpart to + // include. + if (!StringEndsWith(SourceFileMap::PathFromV8Root(include), ".tq")) { + continue; + } std::string include_file = SourceFileMap::PathFromV8RootWithoutExtension(include); includes += "#include \"torque-generated/"; includes += include_file; includes += "-tq-csa.h\"\n"; } + int64_t diff = static_cast<int64_t>(includes.size()) - + static_cast<int64_t>(strlen(BuiltinIncludesMarker)); + for (auto& rule : streams.csa_cc_rules) { + if (static_cast<int64_t>(rule.begin) >= static_cast<int64_t>(pos)) { + rule.begin += diff; + rule.end += diff; + } + } csa_cc.replace(pos, strlen(BuiltinIncludesMarker), std::move(includes)); } + if (GlobalContext::has_kythe_inline_metadata()) { + std::stringstream ss; + EmitKytheInlineMetadata(ss, streams.csa_cc_rules); + csa_cc += ss.str(); + } // TODO(torque-builder): Pass file directly. WriteFile(base_filename + "-tq-csa.cc", std::move(csa_cc)); @@ -1849,11 +1969,43 @@ void ImplementationVisitor::GenerateImplementation(const std::string& dir) { cpp::Function ImplementationVisitor::GenerateMacroFunctionDeclaration( Macro* macro) { - return GenerateFunction(nullptr, - output_type_ == OutputType::kCCDebug - ? macro->CCDebugName() - : macro->ExternalName(), - macro->signature(), macro->parameter_names()); + cpp::Function f = GenerateFunction( + nullptr, + output_type_ == OutputType::kCCDebug ? macro->CCDebugName() + : macro->ExternalName(), + macro->signature(), macro->parameter_names(), + /*pass_code_assembler_state=*/true, + /*generated_parameter_names=*/nullptr); + // Emit `anchor_anchor` (`/kythe/edge/ref/call`) metadata on standalone + // `*-tq-csa.{h,cc}` macro declarations/definitions rather than + // `anchor_defines` (`%/kythe/edge/generates`) because Kythe's `generates` + // collapsing currently only merges `defines` and incoming calls, not outgoing + // `ref/call` edges where the generated C++ function is the caller + // (b/541055917). + const SourcePosition ident_pos = macro->IdentifierPosition(); + if (GlobalContext::has_kythe_inline_metadata() && + output_type_ == OutputType::kCSA && ident_pos.IsValid()) { + size_t src_begin = static_cast<size_t>(ident_pos.start.offset); + size_t src_end = static_cast<size_t>(ident_pos.end.offset); + std::string vname_path = KytheSourceFilePath(ident_pos.source); + f.SetKytheCallback([src_begin, src_end, vname_path = std::move(vname_path)]( + std::ostream& stream, size_t begin, size_t end) { + if (CurrentFileStreams::HasScope()) { + if (auto* streams = CurrentFileStreams::Get()) { + if (&stream == &streams->csa_headerfile) { + streams->csa_header_rules.push_back( + GlobalContext::KytheInlineMetadata::CallAnchor( + begin, end, src_begin, src_end, vname_path)); + } else if (&stream == &streams->csa_ccfile) { + streams->csa_cc_rules.push_back( + GlobalContext::KytheInlineMetadata::CallAnchor( + begin, end, src_begin, src_end, vname_path)); + } + } + } + }); + } + return f; } cpp::Function ImplementationVisitor::GenerateFunction( @@ -2218,8 +2370,6 @@ VisitResult ImplementationVisitor::Visit(StructExpression* expr) { return stack_scope.Yield(VisitResult(struct_type, struct_range)); } else { const auto* bitfield_struct_type = BitFieldStructType::cast(type); - CheckInitializersWellformed(bitfield_struct_type->name(), - bitfield_struct_type->fields(), initializers); // Create a zero and cast it to the desired bitfield struct type. VisitResult result{TypeOracle::GetConstInt32Type(), "0"}; @@ -2231,11 +2381,19 @@ VisitResult ImplementationVisitor::Visit(StructExpression* expr) { // Set each field in the result. If these fields are constexpr, then all of // this initialization will end up reduced to a single value during TurboFan // optimization. - auto& fields = bitfield_struct_type->fields(); + uint64_t initialized_bits = 0; for (size_t i = 0; i < values.size(); i++) { - values[i] = - GenerateImplicitConvert(fields[i].name_and_type.type, values[i]); - result = GenerateSetBitField(bitfield_struct_type, fields[i], result, + CurrentSourcePosition::Scope position_scope(initializers[i].name->pos); + const BitField& field = + bitfield_struct_type->LookupField(initializers[i].name->value); + uint64_t mask = (~uint64_t{0} >> (64 - field.num_bits)) << field.offset; + if (initialized_bits & mask) { + ReportError("Overlapping bitfield initializer: ", + initializers[i].name->value); + } + initialized_bits |= mask; + values[i] = GenerateImplicitConvert(field.name_and_type.type, values[i]); + result = GenerateSetBitField(bitfield_struct_type, field, result, values[i], /*starts_as_zero=*/true); } @@ -4144,11 +4302,17 @@ void ImplementationVisitor::GenerateClassDefinitions( NamespaceScope forward_declarations_namespaces(forward_declarations, {"v8", "internal"}); - // Emit forward declarations. + // Emit forward declarations. Several class types can share a + // generated name, and the order TypeOracle creates them in follows + // type resolution, which is not stable across host platforms. Sort + // and deduplicate so the file only depends on the set of classes. + std::set<std::string> generated_names; for (const ClassType* type : TypeOracle::GetClasses()) { CurrentSourcePosition::Scope position_activator(type->GetPosition()); - forward_declarations << "class " << type->GetGeneratedTNodeTypeName() - << ";\n"; + generated_names.insert(type->GetGeneratedTNodeTypeName()); + } + for (const std::string& name : generated_names) { + forward_declarations << "class " << name << ";\n"; } for (const ClassType* type : TypeOracle::GetClasses()) { @@ -4216,6 +4380,8 @@ void ImplementationVisitor::GenerateExportedMacrosAssembler( std::string file_name = "exported-macros-assembler"; std::stringstream h_contents; std::stringstream cc_contents; + std::vector<GlobalContext::KytheInlineMetadata> h_rules; + std::vector<GlobalContext::KytheInlineMetadata> cc_rules; { IncludeGuardScope include_guard(h_contents, file_name + ".h"); @@ -4237,42 +4403,65 @@ void ImplementationVisitor::GenerateExportedMacrosAssembler( "-tq-csa.h\"\n"; } - NamespaceScope h_namespaces(h_contents, {"v8", "internal"}); - NamespaceScope cc_namespaces(cc_contents, {"v8", "internal"}); + { + NamespaceScope h_namespaces(h_contents, {"v8", "internal"}); + NamespaceScope cc_namespaces(cc_contents, {"v8", "internal"}); + + h_contents << "class V8_EXPORT_PRIVATE " + "TorqueGeneratedExportedMacrosAssembler {\n" + << " public:\n" + << " explicit TorqueGeneratedExportedMacrosAssembler" + "(compiler::CodeAssemblerState* state) : state_(state) {\n" + << " USE(state_);\n" + << " }\n"; + + for (auto& declarable : GlobalContext::AllDeclarables()) { + TorqueMacro* macro = TorqueMacro::DynamicCast(declarable.get()); + if (!(macro && macro->IsExportedToCSA())) continue; + CurrentSourcePosition::Scope position_activator(macro->Position()); + + cpp::Class assembler("TorqueGeneratedExportedMacrosAssembler"); + std::vector<std::string> generated_parameter_names; + cpp::Function f = GenerateFunction( + &assembler, macro->ReadableName(), macro->signature(), + macro->parameter_names(), false, &generated_parameter_names); + const SourcePosition ident_pos = macro->IdentifierPosition(); + if (GlobalContext::has_kythe_inline_metadata() && + ident_pos.source.IsValid()) { + std::string vname_sig = macro->ExternalName(); + std::string vname_path = KytheSourceFilePath(ident_pos.source); + f.SetKytheCallback([&h_contents, &cc_contents, &h_rules, &cc_rules, + vname_sig = std::move(vname_sig), + vname_path = std::move(vname_path)]( + std::ostream& stream, size_t begin, + size_t end) { + if (&stream == &h_contents) { + h_rules.push_back(GlobalContext::KytheInlineMetadata::Generates( + begin, end, vname_sig, vname_path)); + } else if (&stream == &cc_contents) { + cc_rules.push_back(GlobalContext::KytheInlineMetadata::Generates( + begin, end, vname_sig, vname_path)); + } + }); + } - h_contents << "class V8_EXPORT_PRIVATE " - "TorqueGeneratedExportedMacrosAssembler {\n" - << " public:\n" - << " explicit TorqueGeneratedExportedMacrosAssembler" - "(compiler::CodeAssemblerState* state) : state_(state) {\n" - << " USE(state_);\n" - << " }\n"; + f.PrintDeclaration(h_contents); + f.PrintDefinition(cc_contents, [&](std::ostream& stream) { + stream << "return " << macro->ExternalName() << "(state_"; + for (const auto& name : generated_parameter_names) { + stream << ", " << name; + } + stream << ");"; + }); + } - for (auto& declarable : GlobalContext::AllDeclarables()) { - TorqueMacro* macro = TorqueMacro::DynamicCast(declarable.get()); - if (!(macro && macro->IsExportedToCSA())) continue; - CurrentSourcePosition::Scope position_activator(macro->Position()); - - cpp::Class assembler("TorqueGeneratedExportedMacrosAssembler"); - std::vector<std::string> generated_parameter_names; - cpp::Function f = GenerateFunction( - &assembler, macro->ReadableName(), macro->signature(), - macro->parameter_names(), false, &generated_parameter_names); - - f.PrintDeclaration(h_contents); - f.PrintDefinition(cc_contents, [&](std::ostream& stream) { - stream << "return " << macro->ExternalName() << "(state_"; - for (const auto& name : generated_parameter_names) { - stream << ", " << name; - } - stream << ");"; - }); + h_contents << " private:\n" + << " compiler::CodeAssemblerState* state_;\n" + << "};\n"; } - - h_contents << " private:\n" - << " compiler::CodeAssemblerState* state_;\n" - << "};\n"; + EmitKytheInlineMetadata(h_contents, h_rules); } + EmitKytheInlineMetadata(cc_contents, cc_rules); WriteFile(output_directory + "/" + file_name + ".h", h_contents.str()); WriteFile(output_directory + "/" + file_name + ".cc", cc_contents.str()); } diff --git a/deps/v8/src/torque/instance-type-generator.cc b/deps/v8/src/torque/instance-type-generator.cc index 376984a4a39a..e16137c8c2c5 100644 --- a/deps/v8/src/torque/instance-type-generator.cc +++ b/deps/v8/src/torque/instance-type-generator.cc @@ -302,12 +302,12 @@ std::unique_ptr<InstanceTypeTree> AssignInstanceTypes() { // in the debug-reader lists -- Torque emits no TqClass for them. // The `it_list_*` streams below reproduce metagen's // INSTANCE_TYPE_LIST_{SINGLE,MULTIPLE,RANGE} buckets (instance_types.py) -// so the torque path (V8_USE_METAGEN_INSTANCE_TYPES=0) can drive the same +// so the torque path (V8_USE_METAGEN=0) can drive the same // instance-type-checker.h / instance-type-inl.h consumers as metagen. // Unlike the debug-reader lists, these include body-less declarations // (HasUndefinedLayout()), because the checkers map IT -> class for every // IT-bearing class, not just those Torque has a layout for. -// TODO(jgruber): remove together with the V8_USE_METAGEN_INSTANCE_TYPES switch +// TODO(jgruber): remove together with the V8_USE_METAGEN switch // once metagen is the sole instance-type generator. void PrintInstanceTypes(InstanceTypeTree* root, std::ostream& definitions, std::ostream& values, @@ -406,7 +406,7 @@ void ImplementationVisitor::GenerateInstanceTypes( // Emit `torque-generated/instance-types.h`: IT enum + IT-name list. Pure // IT concern; consumed via src/objects/instance-types-gen.h's forwarder - // when V8_USE_METAGEN_INSTANCE_TYPES is 0. + // when V8_USE_METAGEN is 0. std::stringstream header; const std::string file_name = "instance-types.h"; { @@ -468,7 +468,7 @@ void ImplementationVisitor::GenerateInstanceTypes( // Emit `torque-generated/instance-type-checker-lists.h`: the // INSTANCE_TYPE_LIST_{SINGLE,MULTIPLE,RANGE} buckets that metagen emits // into metagen/instance-types.h. Provided here so the torque path - // (V8_USE_METAGEN_INSTANCE_TYPES=0) can satisfy the same consumers. It is + // (V8_USE_METAGEN=0) can satisfy the same consumers. It is // included only from src/objects/instance-types-gen.h's #else (torque) // branch and is additionally guarded below, so the metagen path never // sees it. Remove this file (and the #else include) once metagen is the @@ -477,7 +477,7 @@ void ImplementationVisitor::GenerateInstanceTypes( const std::string it_lists_file = "instance-type-checker-lists.h"; { IncludeGuardScope it_lists_guard(it_lists_header, it_lists_file); - it_lists_header << "#if !V8_USE_METAGEN_INSTANCE_TYPES\n"; + it_lists_header << "#if !V8_USE_METAGEN\n"; it_lists_header << "// Pairs of (ClassName, INSTANCE_TYPE) for classes whose instance\n" "// type is unique to them (no subclasses share it).\n"; @@ -498,7 +498,7 @@ void ImplementationVisitor::GenerateInstanceTypes( it_lists_header << "#define INSTANCE_TYPE_LIST_RANGE(V) \\\n"; it_lists_header << it_list_range.str(); it_lists_header << "\n"; - it_lists_header << "#endif // !V8_USE_METAGEN_INSTANCE_TYPES\n"; + it_lists_header << "#endif // !V8_USE_METAGEN\n"; } WriteFile(output_directory + "/" + it_lists_file, it_lists_header.str()); diff --git a/deps/v8/src/torque/kythe-data.cc b/deps/v8/src/torque/kythe-data.cc index afdc1ab24dd3..e90af3fcc186 100644 --- a/deps/v8/src/torque/kythe-data.cc +++ b/deps/v8/src/torque/kythe-data.cc @@ -60,7 +60,8 @@ kythe_entity_t KytheData::AddFunctionDefinition(Callable* callable) { auto ident_pos = callable->IdentifierPosition(); kythe_entity_t callable_id = that->consumer_->AddDefinition( KytheConsumer::Kind::Function, callable->ExternalName(), - MakeKythePosition(ident_pos)); + MakeKythePosition(ident_pos), callable->IsExternal(), + callable->ReadableName()); that->callables_.insert(it, std::make_pair(callable, callable_id)); return callable_id; } diff --git a/deps/v8/src/torque/kythe-data.h b/deps/v8/src/torque/kythe-data.h index e8738ead5fa2..d3fe90e6177d 100644 --- a/deps/v8/src/torque/kythe-data.h +++ b/deps/v8/src/torque/kythe-data.h @@ -36,7 +36,14 @@ class KytheConsumer { virtual ~KytheConsumer() = 0; virtual kythe_entity_t AddDefinition(Kind kind, std::string name, - KythePosition pos) = 0; + KythePosition pos) { + return 0; + } + virtual kythe_entity_t AddDefinition(Kind kind, std::string name, + KythePosition pos, bool is_extern, + std::string readable_name) { + return AddDefinition(kind, std::move(name), pos); + } virtual void AddUse(Kind kind, kythe_entity_t entity, KythePosition use_pos) = 0; diff --git a/deps/v8/src/torque/layout-loader.cc b/deps/v8/src/torque/layout-loader.cc new file mode 100644 index 000000000000..19b9e1c0f6c7 --- /dev/null +++ b/deps/v8/src/torque/layout-loader.cc @@ -0,0 +1,1831 @@ +// Copyright 2026 the V8 project 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 "src/torque/layout-loader.h" + +#include <algorithm> +#include <cctype> +#include <cmath> +#include <fstream> +#include <limits> +#include <map> +#include <optional> +#include <sstream> +#include <string_view> + +#include "src/torque/ast.h" +#include "src/torque/global-context.h" +#include "src/torque/ls/json-parser.h" +#include "src/torque/torque-parser.h" +#include "src/torque/type-oracle.h" +#include "src/torque/types.h" +#include "src/torque/utils.h" + +namespace v8::internal::torque { + +namespace { + +constexpr int kSupportedSchemaVersion = 1; + +using ls::JsonArray; +using ls::JsonObject; +using ls::JsonValue; + +const JsonValue* Lookup(const JsonObject& object, const std::string& key) { + auto it = object.find(key); + return it == object.end() ? nullptr : &it->second; +} + +// A malformed layout JSON aborts compilation instead of diagnosing one class. +const JsonValue& Require(const JsonObject& object, const std::string& key, + const std::string& context) { + const JsonValue* value = Lookup(object, key); + if (value == nullptr) { + ReportError("layout JSON: ", context, ": missing key \"", key, "\""); + } + return *value; +} + +size_t RequireSize(const JsonObject& object, const std::string& key, + const std::string& context) { + const JsonValue& value = Require(object, key, context); + // JSON numbers above 2^53 are not exact. Casting a value outside size_t's + // range is undefined, including in 32-bit Torque builds. + constexpr double kMaxExactInteger = 9007199254740992.0; // 2^53 + constexpr double kBound = + std::min(kMaxExactInteger, + static_cast<double>(std::numeric_limits<size_t>::max())); + if (!value.IsNumber() || value.ToNumber() < 0 || value.ToNumber() > kBound || + value.ToNumber() != std::trunc(value.ToNumber())) { + ReportError("layout JSON: ", context, ": key \"", key, + "\" is not a non-negative integer"); + } + return static_cast<size_t>(value.ToNumber()); +} + +const std::string& RequireString(const JsonObject& object, + const std::string& key, + const std::string& context) { + const JsonValue& value = Require(object, key, context); + if (!value.IsString()) { + ReportError("layout JSON: ", context, ": key \"", key, + "\" is not a string"); + } + return value.ToString(); +} + +std::string TorqueClassNameFromCppName(const std::string& cpp_name, + const std::string& context) { + size_t separator = cpp_name.rfind("::"); + if (separator == std::string::npos || separator + 2 == cpp_name.size()) { + ReportError("layout JSON: ", context, ": C++ class name \"", cpp_name, + "\" is not fully qualified"); + } + return cpp_name.substr(separator + 2); +} + +// Torque has no nested types: the C++ type Foo::Bar is FooBar in Torque. +std::string TorqueNameFromClassScopedName(std::string name) { + size_t pos; + while ((pos = name.find("::")) != std::string::npos) { + name.erase(pos, 2); + } + return name; +} + +std::string TorqueBitFieldStructName(const JsonObject& storage, + const std::string& context) { + return TorqueNameFromClassScopedName(RequireString(storage, "name", context)); +} + +// Map primitive C++ types to their Torque representation. Torque already knows +// all other class, struct, and namespace-scope alias names. +struct PrimitiveTypeName { + const char* cpp; + const char* torque; +}; + +constexpr PrimitiveTypeName kPrimitiveTypeNames[] = { + {"double", "float64"}, {"float", "float32"}, {"intptr_t", "intptr"}, + {"ptrdiff_t", "intptr"}, {"uintptr_t", "uintptr"}, {"size_t", "uintptr"}, + {"int8_t", "int8"}, {"uint8_t", "uint8"}, {"int16_t", "int16"}, + {"uint16_t", "uint16"}, {"int32_t", "int32"}, {"uint32_t", "uint32"}, + {"int64_t", "int64"}, {"uint64_t", "uint64"}, {"Address", "RawPtr"}, +}; + +// Class templates the layout JSON may name a tagged slot by, mapped to the +// Torque type of their instantiations. Torque has no generic class types, so +// the mapping targets the common base class: every CppGCManaged<T> is a +// CppGCManagedBase, and T is a C++ payload type rather than a heap object. +// Must be kept in sync with _CLASS_TEMPLATE_ARGUMENTS in +// tools/metagen/layout_extract.py; both sides error on an unknown name. +constexpr PrimitiveTypeName kClassTemplateNames[] = { + {"CppGCManaged", "CppGCManagedBase"}, +}; + +// Instantiations Torque refines past that base class, keyed by the +// fully-qualified payload. An instantiation with no entry here falls back to +// kClassTemplateNames. +constexpr PrimitiveTypeName kClassTemplateInstantiations[] = { + {"CppGCManaged<v8::internal::wasm::NativeModule>", + "ManagedWasmNativeModule"}, + {"CppGCManaged<v8::internal::BackingStore>", "ManagedBackingStore"}, +}; + +// Tagged types the two languages agree on but spell differently. The Torque +// spelling may be namespace-qualified. +// +// JSCallable is the widest C++ approximation of Torque's Callable: C++ cannot +// say "a JSProxy or JSObject with the callable bit set", so it names JSProxy +// and JSObject outright. A slot typed JSCallable holds a Callable. +// TODO(jgruber): Give C++ a precise Callable type (with the appropriate +// subtyping and cast helpers) so this entry can go away. +// +// IteratorRecord is nested in its owning class because the CSA struct already +// claims v8::internal::IteratorRecord. +// TODO(jgruber): Resolve the name clash with the CSA struct so the C++ and +// Torque IteratorRecord can share a name and this entry can go away. +constexpr PrimitiveTypeName kTaggedTypeNames[] = { + {"JSCallable", "Callable"}, + {"IteratorRecord", "iterator::IteratorRecord"}, +}; + +// Convert a base::BitField alias name to a Torque field name. +// +// Torque derives the C++ alias name from the Torque field name: CamelifyString +// plus "Bit" for a single bit and "Bits" for more (see +// ImplementationVisitor::GenerateBitFields). The layout JSON records the C++ +// name, so reverse that conversion and check that converting back produces +// the original C++ name (e.g. "IsJSObjectBit" fails this check). +std::string TorqueBitFieldName(const std::string& cpp_name, size_t num_bits, + const std::string& context) { + const std::string suffix = num_bits == 1 ? "Bit" : "Bits"; + if (cpp_name.size() <= suffix.size() || + cpp_name.compare(cpp_name.size() - suffix.size(), suffix.size(), + suffix) != 0) { + ReportError("layout JSON: ", context, ": bit field \"", cpp_name, "\" of ", + num_bits, " bit(s) does not end in \"", suffix, "\""); + } + std::string name = + SnakeifyString(cpp_name.substr(0, cpp_name.size() - suffix.size())); + if (CamelifyString(name) + suffix != cpp_name) { + ReportError("layout JSON: ", context, ": bit field \"", cpp_name, + "\" cannot be derived from a Torque field name; \"", name, + "\" would be written \"", CamelifyString(name), suffix, "\""); + } + return name; +} + +std::string TorqueTypeName(const std::string& cpp_name) { + for (const PrimitiveTypeName& entry : kPrimitiveTypeNames) { + if (cpp_name == entry.cpp) return entry.torque; + } + for (const PrimitiveTypeName& entry : kClassTemplateNames) { + if (cpp_name == entry.cpp) return entry.torque; + } + for (const PrimitiveTypeName& entry : kTaggedTypeNames) { + if (cpp_name == entry.cpp) return entry.torque; + } + return cpp_name; +} + +// Split a possibly namespace-qualified Torque type name into its qualification +// and its identifier. +std::vector<std::string> SplitQualification(std::string* name) { + std::vector<std::string> namespaces; + size_t start = 0; + for (size_t sep = name->find("::"); sep != std::string::npos; + sep = name->find("::", start)) { + namespaces.push_back(name->substr(start, sep - start)); + start = sep + 2; + } + if (!namespaces.empty()) *name = name->substr(start); + return namespaces; +} + +// Metagen preserves V8_TQ_* annotations without interpreting them. Define their +// syntax and valid locations here. +enum class AnnotationOn { kField, kTail, kClass }; + +struct AnnotationSpec { + const char* name; + bool takes_argument; + AnnotationOn on; +}; + +constexpr AnnotationSpec kAnnotations[] = { + {"V8_TQ_CONST", false, AnnotationOn::kField}, + {"V8_TQ_RELAXED", false, AnnotationOn::kField}, + {"V8_TQ_ACQ_REL", false, AnnotationOn::kField}, + {"V8_TQ_CUSTOM_WEAK", false, AnnotationOn::kField}, + {"V8_TQ_NAME", true, AnnotationOn::kField}, + {"V8_TQ_EXTENT_NAME", true, AnnotationOn::kField}, + {"V8_TQ_TYPE", true, AnnotationOn::kField}, + {"V8_TQ_TAIL_LENGTH", true, AnnotationOn::kClass}, + {"V8_TQ_NO_TAIL", false, AnnotationOn::kClass}, +}; + +// Tails accept field annotations except fixed-array extents. +bool AnnotationAllowedOn(const AnnotationSpec& spec, AnnotationOn on) { + if (spec.on == on) return true; + return on == AnnotationOn::kTail && spec.on == AnnotationOn::kField && + std::string_view(spec.name) != "V8_TQ_EXTENT_NAME"; +} + +const JsonObject* FindAnnotation(const JsonObject& record, + std::string_view name, + const std::string& context) { + const JsonValue* list = Lookup(record, "annotations"); + if (list == nullptr) return nullptr; + if (!list->IsArray()) { + ReportError("layout JSON: ", context, + ": \"annotations\" is not " + "an array"); + } + for (const JsonValue& entry : list->ToArray()) { + if (!entry.IsObject()) { + ReportError("layout JSON: ", context, ": annotation is not an object"); + } + const JsonObject& annotation = entry.ToObject(); + if (RequireString(annotation, "name", context) == name) return &annotation; + } + return nullptr; +} + +bool HasAnnotation(const JsonObject& record, std::string_view name, + const std::string& context) { + return FindAnnotation(record, name, context) != nullptr; +} + +const std::string* AnnotationArgument(const JsonObject& record, + std::string_view name, + const std::string& context) { + const JsonObject* annotation = FindAnnotation(record, name, context); + if (annotation == nullptr) return nullptr; + return &RequireString(*annotation, "arg", context); +} + +// Reject unknown and misplaced annotations instead of silently dropping them. +void ValidateAnnotations(const JsonObject& record, AnnotationOn on, + const std::string& context) { + const JsonValue* list = Lookup(record, "annotations"); + if (list == nullptr) return; + if (!list->IsArray()) { + ReportError("layout JSON: ", context, + ": \"annotations\" is not " + "an array"); + } + for (const JsonValue& entry : list->ToArray()) { + if (!entry.IsObject()) { + ReportError("layout JSON: ", context, ": annotation is not an object"); + } + const JsonObject& annotation = entry.ToObject(); + const std::string& name = RequireString(annotation, "name", context); + const AnnotationSpec* spec = nullptr; + for (const AnnotationSpec& candidate : kAnnotations) { + if (name == candidate.name) { + spec = &candidate; + break; + } + } + if (spec == nullptr) { + ReportError("layout JSON: ", context, ": unknown annotation ", name); + } + if (!AnnotationAllowedOn(*spec, on)) { + ReportError("layout JSON: ", context, ": ", name, " is not allowed here"); + } + bool has_argument = Lookup(annotation, "arg") != nullptr; + if (has_argument != spec->takes_argument) { + ReportError( + "layout JSON: ", context, ": ", name, + spec->takes_argument ? " needs an argument" : " takes no argument"); + } + } +} + +std::string TorqueClassName(const JsonObject& record) { + const std::string& cpp_name = RequireString(record, "cpp_name", "class"); + return TorqueClassNameFromCppName(cpp_name, cpp_name); +} + +std::string TorqueFieldName(const JsonObject& record, + const std::string& context) { + if (const std::string* override = + AnnotationArgument(record, "V8_TQ_NAME", context)) { + if (override->empty()) { + ReportError("layout JSON: ", context, ": V8_TQ_NAME is empty"); + } + return *override; + } + std::string name = RequireString(record, "cpp_name", context); + while (!name.empty() && name.back() == '_') name.pop_back(); + if (name.empty()) { + ReportError("layout JSON: ", context, + ": C++ field name maps to an empty Torque name"); + } + return name; +} + +// Compare C++ storage and Torque field types by representation category. +enum class StorageCategory { + kTagged, + kProtectedTagged, + kTrustedPointer, + kExternalPointer, + kCppHeapPointer, + kScalar, +}; + +std::string_view CategoryName(StorageCategory category) { + switch (category) { + case StorageCategory::kTagged: + return "tagged"; + case StorageCategory::kProtectedTagged: + return "protected tagged"; + case StorageCategory::kTrustedPointer: + return "trusted pointer"; + case StorageCategory::kExternalPointer: + return "external pointer"; + case StorageCategory::kCppHeapPointer: + return "cpp-heap pointer"; + case StorageCategory::kScalar: + return "scalar"; + } +} + +bool IsBitFieldKind(const std::string& kind) { + return kind == "bitfield" || kind == "smi_bitfield"; +} + +std::optional<StorageCategory> CategoryOfStorageKind(const std::string& kind) { + if (kind == "tagged" || kind == "smi_bitfield") { + return StorageCategory::kTagged; + } + if (kind == "protected_tagged") return StorageCategory::kProtectedTagged; + if (kind == "trusted_pointer") return StorageCategory::kTrustedPointer; + if (kind == "external_pointer") return StorageCategory::kExternalPointer; + if (kind == "cpp_heap_pointer") return StorageCategory::kCppHeapPointer; + if (kind == "int" || kind == "enum" || kind == "bool" || + kind == "unaligned" || kind == "struct" || kind == "bitfield" || + kind == "js_dispatch_handle") { + return StorageCategory::kScalar; + } + return std::nullopt; +} + +StorageCategory CategoryOfTorqueType(const Type* type) { + // Check specific pointer types before the general tagged category. + if (type->IsSubtypeOf(TypeOracle::GetProtectedPointerType())) { + return StorageCategory::kProtectedTagged; + } + if (type->IsSubtypeOf(TypeOracle::GetTrustedPointerType())) { + return StorageCategory::kTrustedPointer; + } + if (type->IsSubtypeOf(TypeOracle::GetExternalPointerType())) { + return StorageCategory::kExternalPointer; + } + if (type->IsSubtypeOf(TypeOracle::GetCppHeapPointerType())) { + return StorageCategory::kCppHeapPointer; + } + if (type->IsSubtypeOf(TypeOracle::GetTaggedType())) { + return StorageCategory::kTagged; + } + return StorageCategory::kScalar; +} + +std::string_view SynchronizationName(FieldSynchronization synchronization) { + switch (synchronization) { + case FieldSynchronization::kNone: + return "none"; + case FieldSynchronization::kRelaxed: + return "relaxed"; + case FieldSynchronization::kAcquireRelease: + return "acquire_release"; + } +} + +std::optional<size_t> ConstantIndexExtent(const Field& field) { + if (!field.index || !field.index_is_constant) return std::nullopt; + auto* literal = IntegerLiteralExpression::DynamicCast(field.index->expr); + if (literal == nullptr) return std::nullopt; + return literal->value.TryTo<size_t>(); +} + +// Build comparison keys from type syntax without resolving aliases. Sort union +// members because .tq unions and C++ UnionOf may use different orders. +void FlattenUnion(TypeExpression* type, std::vector<std::string>* members); + +std::string TypeExpressionKey(TypeExpression* type) { + if (auto* basic = BasicTypeExpression::DynamicCast(type)) { + std::stringstream s; + for (const std::string& ns : basic->namespace_qualification) { + s << ns << "::"; + } + s << basic->name->value; + if (!basic->generic_arguments.empty()) { + s << "<"; + bool first = true; + for (TypeExpression* argument : basic->generic_arguments) { + if (!first) s << ","; + first = false; + s << TypeExpressionKey(argument); + } + s << ">"; + } + return s.str(); + } + if (UnionTypeExpression::DynamicCast(type) != nullptr) { + std::vector<std::string> members; + FlattenUnion(type, &members); + std::sort(members.begin(), members.end()); + std::stringstream s; + for (size_t i = 0; i < members.size(); ++i) { + if (i > 0) s << "|"; + s << members[i]; + } + return s.str(); + } + ReportError( + "layout JSON: field type uses an expression form TypeExpressionKey " + "does not support, so it cannot be compared"); +} + +void FlattenUnion(TypeExpression* type, std::vector<std::string>* members) { + if (auto* u = UnionTypeExpression::DynamicCast(type)) { + FlattenUnion(u->a, members); + FlattenUnion(u->b, members); + return; + } + members->push_back(TypeExpressionKey(type)); +} + +// Build comparison keys for array extent expressions. Reject unsupported +// forms so two unreadable extents cannot compare equal. +std::string ExpressionKey(Expression* expr) { + if (auto* literal = IntegerLiteralExpression::DynamicCast(expr)) { + std::stringstream s; + // Extents are non-negative; IntegerLiteral::ToString is not linked + // into torque. + if (literal->value.is_negative()) s << "-"; + s << literal->value.absolute_value(); + return s.str(); + } + if (auto* identifier = IdentifierExpression::DynamicCast(expr)) { + std::stringstream s; + for (const std::string& ns : identifier->namespace_qualification) { + s << ns << "::"; + } + s << identifier->name->value; + if (!identifier->generic_arguments.empty()) { + s << "<"; + bool first = true; + for (TypeExpression* argument : identifier->generic_arguments) { + if (!first) s << ","; + first = false; + s << TypeExpressionKey(argument); + } + s << ">"; + } + return s.str(); + } + if (auto* access = FieldAccessExpression::DynamicCast(expr)) { + return ExpressionKey(access->object) + "." + access->field->value; + } + if (auto* call = CallExpression::DynamicCast(expr)) { + std::stringstream s; + // Render binary operators, which parse as calls, in their source form. + const std::string& callee = call->callee->name->value; + if (call->arguments.size() == 2 && + call->callee->namespace_qualification.empty() && + call->callee->generic_arguments.empty() && + std::none_of(callee.begin(), callee.end(), [](char c) { + return c == '_' || std::isalnum(static_cast<unsigned char>(c)); + })) { + s << "(" << ExpressionKey(call->arguments[0]) << " " << callee << " " + << ExpressionKey(call->arguments[1]) << ")"; + return s.str(); + } + s << ExpressionKey(call->callee) << "("; + bool first = true; + for (Expression* argument : call->arguments) { + if (!first) s << ","; + first = false; + s << ExpressionKey(argument); + } + s << ")"; + return s.str(); + } + if (auto* conditional = ConditionalExpression::DynamicCast(expr)) { + return "(" + ExpressionKey(conditional->condition) + " ? " + + ExpressionKey(conditional->if_true) + " : " + + ExpressionKey(conditional->if_false) + ")"; + } + ReportError( + "layout JSON: array extent uses an expression form " + "ExpressionKey does not support, so it cannot be compared"); +} + +std::string IndexKey(const ClassFieldIndexInfo& index) { + std::string result = ExpressionKey(index.expr); + if (index.optional) result += '?'; + return result; +} + +// Non-named super types cannot identify a layout-record boundary. +std::string TorqueSuperName(TypeExpression* super) { + auto* basic = BasicTypeExpression::DynamicCast(super); + return basic == nullptr ? "" : basic->name->value; +} + +std::string FieldKey(const ClassFieldExpression& field) { + std::stringstream s; + s << field.name_and_type.name->value; + if (field.index.has_value()) { + s << "[" << IndexKey(*field.index) << "]"; + } + s << ": " << TypeExpressionKey(field.name_and_type.type); + if (field.const_qualified) s << " const"; + if (field.synchronization != FieldSynchronization::kNone) { + s << " " << SynchronizationName(field.synchronization); + } + if (field.custom_weak_marking) s << " customWeak"; + return s.str(); +} + +JsonValue LoadLayoutDocument(const std::string& layout_json_path) { + std::ifstream stream(layout_json_path); + if (!stream.good()) { + ReportError("cannot open layout JSON: ", layout_json_path); + } + std::string content{std::istreambuf_iterator<char>(stream), + std::istreambuf_iterator<char>()}; + ls::JsonParserResult parse_result = ls::ParseJson(content); + if (parse_result.error.has_value()) { + ReportError("layout JSON ", layout_json_path, + " is not valid JSON: ", parse_result.error->message); + } + if (!parse_result.value.IsObject()) { + ReportError("layout JSON ", layout_json_path, ": expected an object"); + } + const JsonObject& document = parse_result.value.ToObject(); + const JsonValue& version = Require(document, "schema_version", "document"); + if (!version.IsNumber() || version.ToNumber() != kSupportedSchemaVersion) { + ReportError("layout JSON ", layout_json_path, + ": unsupported schema version (expected ", + kSupportedSchemaVersion, ")"); + } + return std::move(parse_result.value); +} + +// Offsets and sizes are valid only for the target configuration that produced +// them. Check it explicitly because a class without a .tq body has no fields +// that could catch a mismatch indirectly. +void VerifyConfig(const JsonValue& document_value, + const std::string& layout_json_path) { + const JsonValue& config_value = + Require(document_value.ToObject(), "config", "document"); + if (!config_value.IsObject()) { + ReportError("layout JSON ", layout_json_path, + ": \"config\" is not an " + "object"); + } + const JsonObject& config = config_value.ToObject(); + struct Expectation { + const char* key; + size_t expected; + }; + const Expectation expectations[] = { + {"tagged_size", TargetArchitecture::TaggedSize()}, + {"pointer_size", TargetArchitecture::RawPtrSize()}, + {"external_pointer_size", TargetArchitecture::ExternalPointerSize()}, + {"cpp_heap_pointer_size", TargetArchitecture::CppHeapPointerSize()}, + {"trusted_pointer_size", TargetArchitecture::TrustedPointerSize()}, + }; + for (const Expectation& expectation : expectations) { + size_t actual = RequireSize(config, expectation.key, "config"); + if (actual != expectation.expected) { + ReportError("layout JSON ", layout_json_path, " was harvested with ", + expectation.key, " ", actual, ", but Torque targets ", + expectation.expected, + ": the layout JSON does not match this build configuration"); + } + } +} + +struct RecordIndexes { + std::map<std::string, const JsonObject*> by_cpp_name; + std::map<std::string, const JsonObject*> by_torque_name; +}; + +RecordIndexes IndexRecords(const JsonValue& document_value) { + const JsonObject& document = document_value.ToObject(); + const JsonValue& classes = Require(document, "classes", "document"); + if (!classes.IsArray()) { + ReportError("layout JSON: \"classes\" is not an array"); + } + RecordIndexes records; + for (const JsonValue& record : classes.ToArray()) { + if (!record.IsObject()) { + ReportError("layout JSON: class record is not an object"); + } + const JsonObject& object = record.ToObject(); + const std::string& cpp_name = RequireString(object, "cpp_name", "class"); + if (!records.by_cpp_name.emplace(cpp_name, &object).second) { + ReportError("layout JSON: duplicate C++ class record \"", cpp_name, "\""); + } + ValidateAnnotations(object, AnnotationOn::kClass, cpp_name); + const JsonValue* fields = Lookup(object, "fields"); + if (fields != nullptr && fields->IsArray()) { + for (const JsonValue& field : fields->ToArray()) { + if (!field.IsObject()) continue; + ValidateAnnotations(field.ToObject(), AnnotationOn::kField, cpp_name); + } + } + if (const JsonValue* tail = Lookup(object, "tail"); + tail != nullptr && tail->IsObject()) { + ValidateAnnotations(tail->ToObject(), AnnotationOn::kTail, cpp_name); + } + std::string torque_name = TorqueClassName(object); + auto [torque_it, torque_inserted] = + records.by_torque_name.emplace(torque_name, &object); + if (!torque_inserted) { + ReportError("layout JSON: C++ classes ", + RequireString(*torque_it->second, "cpp_name", torque_name), + " and ", cpp_name, " both map to Torque class ", torque_name); + } + } + return records; +} + +bool OptionalBool(const JsonObject& record, const std::string& key, + const std::string& context) { + const JsonValue* value = Lookup(record, key); + if (value == nullptr) return false; + if (!value->IsBool()) { + ReportError("layout JSON: ", context, ": key \"", key, + "\" is not a boolean"); + } + return value->ToBool(); +} + +FieldSynchronization ReadSynchronization(const JsonObject& record, + const std::string& context) { + bool relaxed = HasAnnotation(record, "V8_TQ_RELAXED", context); + bool acq_rel = HasAnnotation(record, "V8_TQ_ACQ_REL", context); + if (relaxed && acq_rel) { + ReportError("layout JSON: ", context, + ": V8_TQ_RELAXED and V8_TQ_ACQ_REL on the same member"); + } + if (relaxed) return FieldSynchronization::kRelaxed; + if (acq_rel) return FieldSynchronization::kAcquireRelease; + return FieldSynchronization::kNone; +} + +const JsonObject* LookupTail(const JsonObject& record, + const std::string& name) { + const JsonValue* tail = Lookup(record, "tail"); + if (tail == nullptr) return nullptr; + if (!tail->IsObject()) { + ReportError("layout JSON: ", name, ": \"tail\" is not an object"); + } + return &tail->ToObject(); +} + +// How Torque represents the flexible tail, as specified by class annotations. +enum class TailRepresentation { + // Torque fields end at the fixed header. + kNone, + // The tail is one indexed Torque field. + kIndexedField, + // No length expression: the tail cannot become a Torque field. + kUnspecified, +}; + +TailRepresentation GetTailRepresentation(const JsonObject& class_record, + const JsonObject* tail_record, + const std::string& context) { + bool has_length = HasAnnotation(class_record, "V8_TQ_TAIL_LENGTH", context); + bool no_tail = HasAnnotation(class_record, "V8_TQ_NO_TAIL", context); + if (has_length && no_tail) { + ReportError("layout JSON: ", context, + ": V8_TQ_TAIL_LENGTH and V8_TQ_NO_TAIL are exclusive"); + } + if (tail_record == nullptr) { + if (has_length || no_tail) { + ReportError("layout JSON: ", context, ": ", + has_length ? "V8_TQ_TAIL_LENGTH" : "V8_TQ_NO_TAIL", + " without a flexible array member"); + } + return TailRepresentation::kNone; + } + if (has_length) return TailRepresentation::kIndexedField; + return no_tail ? TailRepresentation::kNone : TailRepresentation::kUnspecified; +} + +// Fold C++-only intermediate bases into the first derived class Torque knows. +// Return contributing records from the outermost base to the derived class. +template <typename BoundaryPredicate> +std::vector<const JsonObject*> CollapseCppOnlyBases( + const JsonObject& record, const std::string& name, + const std::map<std::string, const JsonObject*>& records_by_cpp_name, + BoundaryPredicate is_boundary) { + std::vector<const JsonObject*> groups{&record}; + const JsonObject* outermost = &record; + while (true) { + const JsonValue& base = Require(*outermost, "base", name); + if (base.tag == JsonValue::IS_NULL) break; + if (!base.IsString()) { + ReportError("layout JSON: ", name, ": \"base\" is not a string"); + } + if (is_boundary(TorqueClassNameFromCppName(base.ToString(), name))) break; + auto parent_it = records_by_cpp_name.find(base.ToString()); + if (parent_it == records_by_cpp_name.end()) { + ReportError("layout JSON: ", name, ": C++ base ", base.ToString(), + " has no layout record"); + } + outermost = parent_it->second; + if (Lookup(*outermost, "tail") != nullptr) { + ReportError("layout JSON: ", name, ": C++ base ", base.ToString(), + " has a flexible tail"); + } + groups.insert(groups.begin(), outermost); + } + return groups; +} + +const JsonArray& RequireFields(const JsonObject& group, + const std::string& name) { + const JsonValue& fields_value = Require(group, "fields", name); + if (!fields_value.IsArray()) { + ReportError("layout JSON: ", name, ": \"fields\" is not an array"); + } + return fields_value.ToArray(); +} + +const JsonObject& RequireFieldObject(const JsonValue& field, + const std::string& name) { + if (!field.IsObject()) { + ReportError("layout JSON: ", name, ": field is not an object"); + } + return field.ToObject(); +} + +std::vector<const JsonObject*> CollectFields( + const std::vector<const JsonObject*>& groups, const std::string& name) { + std::vector<const JsonObject*> fields; + for (const JsonObject* group : groups) { + for (const JsonValue& field : RequireFields(*group, name)) { + fields.push_back(&RequireFieldObject(field, name)); + } + } + return fields; +} + +class LayoutVerifier { + public: + void Run(const std::string& layout_json_path) { + for (const ClassType* type : TypeOracle::GetClasses()) { + classes_by_name_[type->name()] = type; + } + JsonValue document = LoadLayoutDocument(layout_json_path); + VerifyConfig(document, layout_json_path); + RecordIndexes records = IndexRecords(document); + records_by_cpp_name_ = std::move(records.by_cpp_name); + for (const auto& entry : records_by_cpp_name_) { + VerifyClass(*entry.second); + } + } + + private: + void VerifyClass(const JsonObject& record) { + std::string name = TorqueClassName(record); + + // The layout JSON also contains classes Torque does not know. + auto it = classes_by_name_.find(name); + if (it == classes_by_name_.end()) return; + const ClassType* type = it->second; + if (!type->IsLayoutDefinedInCpp()) return; + // Classes without a .tq body, such as BigIntBase and Code, have no fields. + if (type->HasUndefinedLayout()) return; + + // Skip C++-only bases to find the base declared in Torque. + std::vector<const JsonObject*> groups = CollapseCppOnlyBases( + record, name, records_by_cpp_name_, [&](const std::string& base) { + return classes_by_name_.count(base) > 0; + }); + + VerifyBase(type, *groups.front(), name); + VerifyFields(type, groups, record, name); + } + + void VerifyBase(const ClassType* type, const JsonObject& record, + const std::string& name) { + const ClassType* super = type->GetSuperClass(); + const JsonValue& base = Require(record, "base", name); + if (base.tag == JsonValue::IS_NULL) { + if (super != nullptr) { + Error("class ", name, ": C++ layout has no base, Torque extends ", + super->name()) + .Position(type->GetPosition()); + } + return; + } + if (!base.IsString()) { + ReportError("layout JSON: ", name, ": \"base\" is not a string"); + } + if (super == nullptr) { + Error("class ", name, ": C++ layout has base ", base.ToString(), + ", Torque has none") + .Position(type->GetPosition()); + return; + } + std::string torque_base = TorqueClassNameFromCppName(base.ToString(), name); + if (super->name() != torque_base) { + Error("class ", name, ": C++ layout base is ", base.ToString(), + ", Torque extends ", super->name()) + .Position(type->GetPosition()); + return; + } + size_t base_size = RequireSize(record, "base_size", name); + auto super_size = super->size().SingleValue(); + if (!super_size.has_value() || *super_size != base_size) { + Error("class ", name, ": sizeof(", base.ToString(), ") is ", base_size, + " in C++, ", + super_size.has_value() ? std::to_string(*super_size) : "dynamic", + " in Torque") + .Position(type->GetPosition()); + } + } + + void VerifyFields(const ClassType* type, + const std::vector<const JsonObject*>& groups, + const JsonObject& record, const std::string& name) { + std::vector<const JsonObject*> json_fields = CollectFields(groups, name); + const JsonObject* tail_record = LookupTail(record, name); + // For an unspecified tail representation, verify the fixed header and + // require indexed fields after it. + TailRepresentation tail_representation = + GetTailRepresentation(record, tail_record, name); + bool tail_is_indexed_field = + tail_representation == TailRepresentation::kIndexedField; + + const std::vector<Field>& torque_fields = type->fields(); + if (tail_representation == TailRepresentation::kNone || + tail_representation == TailRepresentation::kIndexedField) { + size_t expected_count = + json_fields.size() + (tail_is_indexed_field ? 1 : 0); + if (torque_fields.size() != expected_count) { + Error("class ", name, ": C++ layout has ", expected_count, + " field(s), Torque has ", torque_fields.size()) + .Position(type->GetPosition()); + return; + } + } else { + if (torque_fields.size() < json_fields.size()) { + Error("class ", name, ": C++ layout has ", json_fields.size(), + " fixed field(s) before the tail, Torque has only ", + torque_fields.size(), " field(s)") + .Position(type->GetPosition()); + return; + } + for (size_t i = json_fields.size(); i < torque_fields.size(); ++i) { + if (!torque_fields[i].index.has_value()) { + Error("class ", name, ": Torque field ", + torque_fields[i].name_and_type.name, + " is not indexed but lies in the C++ flexible tail") + .Position(torque_fields[i].pos); + return; + } + } + } + + for (size_t i = 0; i < json_fields.size(); ++i) { + VerifyField(name, torque_fields[i], *json_fields[i]); + } + if (tail_is_indexed_field) { + VerifyTail(name, torque_fields.back(), record, *tail_record); + } + + size_t size = RequireSize(record, "size", name); + auto torque_size = type->size().SingleValue(); + if (tail_record != nullptr) { + // VerifyTail checks the flexible portion separately. + if (type->header_size() != size) { + Error("class ", name, ": C++ fixed size is ", size, + ", Torque header size is ", type->header_size()) + .Position(type->GetPosition()); + } + } else if (torque_size.has_value()) { + if (*torque_size != size || type->header_size() != size) { + Error("class ", name, ": sizeof is ", size, " in C++, ", *torque_size, + " in Torque") + .Position(type->GetPosition()); + } + } else { + // A named array extent can leave a fixed C++ layout dynamic in Torque. + // Its element, offset, and total class size still constrain the field. + bool last_is_named_const_array = + !torque_fields.empty() && torque_fields.back().index.has_value() && + torque_fields.back().index_is_constant && + !ConstantIndexExtent(torque_fields.back()).has_value(); + const JsonObject* last_json = + json_fields.empty() ? nullptr : json_fields.back(); + if (!last_is_named_const_array || last_json == nullptr) { + Error("class ", name, + ": C++ layout is fixed-size but the Torque size is dynamic") + .Position(type->GetPosition()); + } else { + size_t last_offset = RequireSize(*last_json, "offset", name); + size_t last_size = RequireSize(*last_json, "size", name); + if (type->header_size() != last_offset || + last_offset + last_size != size) { + Error("class ", name, + ": the named-constant-extent array must " + "span the C++ layout from ", + type->header_size(), " to ", size, ", but spans ", last_offset, + " to ", last_offset + last_size) + .Position(type->GetPosition()); + } + } + } + } + + void VerifyField(const std::string& class_name, const Field& field, + const JsonObject& record) { + std::string name = TorqueFieldName(record, class_name); + std::string context = class_name + "." + name + " (member " + + RequireString(record, "cpp_name", name) + ")"; + + if (field.name_and_type.name != name) { + Error("field ", context, ": Torque declares ", field.name_and_type.name, + " here") + .Position(field.pos); + return; + } + if (field.index.has_value() && !field.index_is_constant) { + Error("field ", context, + ": indexed in Torque but a fixed-offset field in C++") + .Position(field.pos); + return; + } + + size_t offset = RequireSize(record, "offset", context); + if (!field.offset.has_value() || *field.offset != offset) { + Error( + "field ", context, ": offset is ", offset, " in C++, ", + field.offset.has_value() ? std::to_string(*field.offset) : "dynamic", + " in Torque") + .Position(field.pos); + } + + size_t size = RequireSize(record, "size", context); + size_t extent = 1; + if (Lookup(record, "array_extent") != nullptr) { + extent = RequireSize(record, "array_extent", context); + if (!field.index.has_value() || !field.index_is_constant) { + Error("field ", context, ": a [", extent, + "] array in C++ but not in Torque") + .Position(field.pos); + } else if (auto torque_extent = ConstantIndexExtent(field); + torque_extent.has_value() && *torque_extent != extent) { + // Torque does not expose the value of a named constant in this AST. + Error("field ", context, ": a [", extent, "] array in C++, [", + *torque_extent, "] in Torque") + .Position(field.pos); + } + } else if (field.index.has_value()) { + Error("field ", context, ": indexed in Torque but scalar in C++") + .Position(field.pos); + } + size_t element_size = std::get<0>(field.GetFieldSizeInformation()); + if (element_size * extent != size) { + Error("field ", context, ": ", size, " byte(s) in C++, ", + element_size * extent, " in Torque") + .Position(field.pos); + } + + VerifyCategory(context, field, record, "storage"); + VerifyBitFields(context, field, record); + VerifyFlags(context, field, record); + } + + // Check the individual bit fields, not just the member holding them. The + // @cppScope asserts already compare the .tq declaration against the + // C++ BitField aliases, but nothing else checks that the layout JSON agrees + // with both. + void VerifyBitFields(const std::string& context, const Field& field, + const JsonObject& record) { + const JsonValue* storage = Lookup(record, "storage"); + if (storage == nullptr || !storage->IsObject()) return; + const JsonObject& s = storage->ToObject(); + const JsonValue* kind = Lookup(s, "kind"); + if (kind == nullptr || !kind->IsString() || + !IsBitFieldKind(kind->ToString())) { + return; + } + bool smi = kind->ToString() == "smi_bitfield"; + // Groups stored as Smis have type SmiTagged<Struct> in Torque. + const Type* struct_type = field.name_and_type.type; + if (smi) { + std::optional<const Type*> unwrapped = Type::MatchUnaryGeneric( + struct_type, TypeOracle::GetSmiTaggedGeneric()); + struct_type = unwrapped.value_or(nullptr); + } + const auto* type = BitFieldStructType::DynamicCast(struct_type); + if (type == nullptr) { + Error("field ", context, ": a bit field group ", smi ? "in a Smi " : "", + "in C++, ", field.name_and_type.type->ToString(), " in Torque") + .Position(field.pos); + return; + } + const std::string struct_name = TorqueBitFieldStructName(s, context); + if (type->name() != struct_name) { + Error("field ", context, ": the C++ bit field group is ", + RequireString(s, "name", context), ", Torque uses ", type->name()) + .Position(field.pos); + return; + } + const JsonValue& bits = Require(s, "bits", context); + if (!bits.IsArray()) { + ReportError("layout JSON: ", context, ": \"bits\" is not an array"); + } + const std::vector<BitField>& torque_bits = type->fields(); + if (bits.ToArray().size() != torque_bits.size()) { + Error("field ", context, ": C++ declares ", bits.ToArray().size(), + " bit field(s), Torque has ", torque_bits.size()) + .Position(type->GetPosition()); + return; + } + for (size_t i = 0; i < torque_bits.size(); ++i) { + const JsonValue& bit = bits.ToArray()[i]; + if (!bit.IsObject()) { + ReportError("layout JSON: ", context, ": bit field is not an object"); + } + const JsonObject& b = bit.ToObject(); + size_t num_bits = RequireSize(b, "num_bits", context); + std::string name = TorqueBitFieldName( + RequireString(b, "cpp_name", context), num_bits, context); + const BitField& torque_bit = torque_bits[i]; + if (torque_bit.name_and_type.name != name) { + Error("field ", context, ": C++ bit field ", i, " is ", name, + ", Torque declares ", torque_bit.name_and_type.name) + .Position(torque_bit.pos); + continue; + } + size_t offset = RequireSize(b, "offset", context); + if (static_cast<size_t>(torque_bit.offset) != offset || + static_cast<size_t>(torque_bit.num_bits) != num_bits) { + Error("bit field ", context, ".", name, ": ", num_bits, " bit(s) at ", + offset, " in C++, ", torque_bit.num_bits, " at ", + torque_bit.offset, " in Torque") + .Position(torque_bit.pos); + } + } + } + + void VerifyTail(const std::string& class_name, const Field& field, + const JsonObject& class_record, const JsonObject& record) { + std::string name = TorqueFieldName(record, class_name); + std::string context = class_name + "." + name + " (member " + + RequireString(record, "cpp_name", name) + ")"; + + if (field.name_and_type.name != name) { + Error("tail ", context, ": Torque declares ", field.name_and_type.name, + " here") + .Position(field.pos); + return; + } + if (!field.index.has_value() || field.index_is_constant) { + Error("tail ", context, + ": a flexible tail in C++ but not an indexed " + "field in Torque") + .Position(field.pos); + return; + } + size_t offset = RequireSize(record, "offset", context); + if (!field.offset.has_value() || *field.offset != offset) { + Error("tail ", context, ": starts at ", offset, " in C++, ", + field.offset.has_value() ? std::to_string(*field.offset) + : "dynamic offset", + " in Torque") + .Position(field.pos); + } + size_t element_size = RequireSize(record, "element_size", context); + size_t torque_element_size = std::get<0>(field.GetFieldSizeInformation()); + if (torque_element_size != element_size) { + Error("tail ", context, ": element size is ", element_size, " in C++, ", + torque_element_size, " in Torque") + .Position(field.pos); + } + const std::string& length = + *AnnotationArgument(class_record, "V8_TQ_TAIL_LENGTH", context); + // Parsed nodes and parse errors take the Torque field's position. + CurrentSourcePosition::Scope position_scope(field.pos); + std::string expected_key = ExpressionKey(ParseTorqueExpression(length)); + std::string torque_key = ExpressionKey(field.index->expr); + if (torque_key != expected_key) { + Error("tail ", context, ": indexed by ", length, + " in C++, but Torque uses a different index expression") + .Position(field.pos); + } + VerifyCategory(context, field, record, "element_storage"); + } + + void VerifyCategory(const std::string& context, const Field& field, + const JsonObject& record, const std::string& key) { + const JsonValue& storage_value = Require(record, key, context); + if (!storage_value.IsObject()) { + ReportError("layout JSON: ", context, ": \"", key, "\" is not an object"); + } + const JsonObject& storage = storage_value.ToObject(); + const std::string& kind = RequireString(storage, "kind", context); + auto expected = CategoryOfStorageKind(kind); + if (!expected.has_value()) { + ReportError("layout JSON: ", context, ": unknown storage kind \"", kind, + "\""); + } + StorageCategory actual = CategoryOfTorqueType(field.name_and_type.type); + if (actual != *expected) { + Error("field ", context, ": ", CategoryName(*expected), + " storage in C++, but the Torque type ", *field.name_and_type.type, + " is ", CategoryName(actual)) + .Position(field.pos); + } + } + + void VerifyFlags(const std::string& context, const Field& field, + const JsonObject& record) { + bool is_const = HasAnnotation(record, "V8_TQ_CONST", context); + if (field.const_qualified != is_const) { + Error("field ", context, ": ", is_const ? "const" : "not const", + " in C++, ", field.const_qualified ? "const" : "not const", + " in Torque") + .Position(field.pos); + } + + FieldSynchronization synchronization = ReadSynchronization(record, context); + if (field.synchronization != synchronization) { + Error("field ", context, ": synchronization is ", + SynchronizationName(synchronization), " in C++, ", + SynchronizationName(field.synchronization), " in Torque") + .Position(field.pos); + } + + bool custom_weak = HasAnnotation(record, "V8_TQ_CUSTOM_WEAK", context); + if (field.custom_weak_marking != custom_weak) { + Error("field ", context, ": @customWeakMarking differs between C++ (", + custom_weak, ") and Torque (", field.custom_weak_marking, ")") + .Position(field.pos); + } + } + + std::map<std::string, const ClassType*> classes_by_name_; + std::map<std::string, const JsonObject*> records_by_cpp_name_; +}; + +class LayoutImporter { + public: + void Run(const std::string& layout_json_path, + const std::string& positions_path) { + JsonValue document = LoadLayoutDocument(layout_json_path); + VerifyConfig(document, layout_json_path); + RecordIndexes records = IndexRecords(document); + records_by_cpp_name_ = std::move(records.by_cpp_name); + records_by_torque_name_ = std::move(records.by_torque_name); + if (!positions_path.empty()) LoadPositions(positions_path); + CollectBitFieldStructs(CurrentAst::Get().declarations()); + Import(CurrentAst::Get().declarations()); + // Appended after the walk: Import() iterates the same declaration vector. + std::vector<Declaration*>& declarations = CurrentAst::Get().declarations(); + declarations.insert(declarations.end(), new_bit_field_structs_.begin(), + new_bit_field_structs_.end()); + new_bit_field_structs_.clear(); + } + + // Collect existing bitfield structs before importing the JSON declarations. + // Keep the .tq declarations for builds with v8_use_metagen_layouts=false; + // when importing, check that they match the JSON before replacing them. + void CollectBitFieldStructs(const std::vector<Declaration*>& declarations) { + for (Declaration* declaration : declarations) { + if (auto* ns = NamespaceDeclaration::DynamicCast(declaration)) { + CollectBitFieldStructs(ns->declarations); + continue; + } + if (auto* decl = BitFieldStructDeclaration::DynamicCast(declaration)) { + bit_field_structs_.emplace(decl->name->value, decl); + } + } + } + + void ImportBitFieldStructs(const JsonObject& record, + const std::string& cpp_name, + SourcePosition fallback) { + const JsonValue* fields = Lookup(record, "fields"); + if (fields == nullptr || !fields->IsArray()) return; + for (const JsonValue& field : fields->ToArray()) { + if (!field.IsObject()) continue; + const JsonValue* storage = Lookup(field.ToObject(), "storage"); + if (storage == nullptr || !storage->IsObject()) continue; + const JsonObject& s = storage->ToObject(); + const JsonValue* kind = Lookup(s, "kind"); + if (kind == nullptr || !kind->IsString() || + !IsBitFieldKind(kind->ToString())) { + continue; + } + const std::string name = TorqueBitFieldStructName(s, cpp_name); + SourcePosition position = MemberPosition( + cpp_name, RequireString(field.ToObject(), "cpp_name", cpp_name), + fallback); + auto it = bit_field_structs_.find(name); + if (it == bit_field_structs_.end()) { + CurrentSourcePosition::Scope position_scope(position); + auto* decl = MakeNode<BitFieldStructDeclaration>( + MakeNode<Identifier>(name), BitFieldParent(cpp_name, s), + BitFieldEntries(cpp_name, s), std::optional<std::string>{}); + bit_field_structs_.emplace(name, decl); + new_bit_field_structs_.push_back(decl); + continue; + } + // Declared in .tq, or already imported for another member: build at + // the C++ position for diagnostics and compare, then rebuild at the + // Torque position and replace the declaration. + BitFieldStructDeclaration* decl = it->second; + TypeExpression* parent; + std::vector<BitFieldDeclaration> entries; + { + CurrentSourcePosition::Scope position_scope(position); + parent = BitFieldParent(cpp_name, s); + entries = BitFieldEntries(cpp_name, s); + } + if (!BitFieldStructsEquivalent(*decl, parent, entries)) continue; + std::vector<SourcePosition> torque_positions; + for (const BitFieldDeclaration& f : decl->fields) { + torque_positions.push_back(f.name_and_type.name->pos); + } + CurrentSourcePosition::Scope position_scope(decl->pos); + decl->parent = BitFieldParent(cpp_name, s); + decl->fields = BitFieldEntries(cpp_name, s, &torque_positions); + } + } + + bool BitFieldStructsEquivalent( + const BitFieldStructDeclaration& decl, TypeExpression* parent, + const std::vector<BitFieldDeclaration>& built) { + CurrentSourcePosition::Scope position_scope(decl.pos); + const std::string& name = decl.name->value; + if (TypeExpressionKey(decl.parent) != TypeExpressionKey(parent)) { + Error("bitfield struct ", name, ": .tq extends ", + TypeExpressionKey(decl.parent), ", C++ ", TypeExpressionKey(parent)) + .Position(decl.pos); + return false; + } + if (decl.fields.size() != built.size()) { + Error("bitfield struct ", name, ": .tq declares ", decl.fields.size(), + " field(s), C++ ", built.size()) + .Position(decl.pos); + return false; + } + bool equivalent = true; + int64_t offset = 0; + for (size_t i = 0; i < built.size(); ++i) { + offset = decl.fields[i].offset ? *decl.fields[i].offset : offset; + std::string a = BitFieldKey(decl.fields[i], offset); + std::string b = BitFieldKey(built[i], *built[i].offset); + offset += decl.fields[i].num_bits; + if (a != b) { + Error("bitfield struct ", name, ": .tq field \"", a, + "\" differs from C++ field \"", b, "\"") + .Position(decl.fields[i].name_and_type.name->pos); + equivalent = false; + } + } + return equivalent; + } + + static std::string BitFieldKey(const BitFieldDeclaration& field, + int64_t offset) { + return field.name_and_type.name->value + ": " + + TypeExpressionKey(field.name_and_type.type) + ": " + + std::to_string(field.num_bits) + " bit at " + std::to_string(offset); + } + + // Groups stored as Smis use uint31; other groups use their storage width. + TypeExpression* BitFieldParent(const std::string& context, + const JsonObject& storage) { + if (RequireString(storage, "kind", context) == "smi_bitfield") { + return NamedType("uint31"); + } + return NamedType( + "uint" + std::to_string(RequireSize(storage, "width", context) * 8)); + } + + // Build the fields at the current position, or at `positions` (one per + // field) when replacing a .tq declaration. + std::vector<BitFieldDeclaration> BitFieldEntries( + const std::string& context, const JsonObject& storage, + const std::vector<SourcePosition>* positions = nullptr) { + const JsonValue& bits = Require(storage, "bits", context); + if (!bits.IsArray() || bits.ToArray().empty()) { + ReportError("layout JSON: ", context, ": bitfield without fields"); + } + std::vector<BitFieldDeclaration> fields; + for (const JsonValue& bit : bits.ToArray()) { + if (!bit.IsObject()) { + ReportError("layout JSON: ", context, ": bit field is not an object"); + } + const JsonObject& b = bit.ToObject(); + const std::string& cpp_name = RequireString(b, "cpp_name", context); + size_t num_bits = RequireSize(b, "num_bits", context); + size_t offset = RequireSize(b, "offset", context); + if (offset > 64 || num_bits > 64) { + ReportError("layout JSON: ", context, ": bit field exceeds 64 bits"); + } + CurrentSourcePosition::Scope position_scope( + positions != nullptr ? positions->at(fields.size()) + : CurrentSourcePosition::Get()); + fields.push_back(BitFieldDeclaration{ + NameAndTypeExpression{ + MakeNode<Identifier>( + TorqueBitFieldName(cpp_name, num_bits, context)), + NamedType(TorqueTypeName(TorqueNameFromClassScopedName( + RequireString(b, "type", context))))}, + static_cast<int>(num_bits), static_cast<int>(offset)}); + } + return fields; + } + + private: + // Fall back to the .tq declaration when the positions JSON has no entry. + void LoadPositions(const std::string& path) { + JsonValue document_value = LoadLayoutDocument(path); + const JsonValue& classes = + Require(document_value.ToObject(), "classes", "positions"); + if (!classes.IsArray()) { + ReportError("layout JSON: positions \"classes\" is not an array"); + } + for (const JsonValue& entry : classes.ToArray()) { + if (!entry.IsObject()) { + ReportError("layout JSON: positions entry is not an object"); + } + const JsonObject& object = entry.ToObject(); + const std::string& cpp_name = + RequireString(object, "cpp_name", "positions"); + const JsonValue& members = Require(object, "members", cpp_name); + if (!members.IsObject()) { + ReportError("layout JSON: ", cpp_name, + ": \"members\" is not an object"); + } + std::map<std::string, SourcePosition>& class_positions = + positions_[cpp_name]; + for (const auto& [member, value] : members.ToObject()) { + if (!value.IsString()) { + ReportError("layout JSON: ", cpp_name, ".", member, + ": position is not a string"); + } + class_positions.emplace(member, ParsePosition(value.ToString())); + } + } + } + + SourcePosition MemberPosition(const std::string& class_cpp_name, + const std::string& member_cpp_name, + SourcePosition fallback) { + auto class_it = positions_.find(class_cpp_name); + if (class_it == positions_.end()) return fallback; + auto member_it = class_it->second.find(member_cpp_name); + if (member_it == class_it->second.end()) return fallback; + return member_it->second; + } + + void Import(const std::vector<Declaration*>& declarations) { + for (Declaration* declaration : declarations) { + if (auto* ns = NamespaceDeclaration::DynamicCast(declaration)) { + Import(ns->declarations); + continue; + } + auto* decl = ClassDeclaration::DynamicCast(declaration); + if (decl == nullptr) continue; + if (!(decl->flags & ClassFlag::kCppObjectLayoutDefinition)) continue; + ImportClass(decl); + } + } + + void ImportClass(ClassDeclaration* decl) { + const std::string& name = decl->name->value; + bool body_less = (decl->flags & ClassFlag::kUndefinedLayout) != 0; + auto it = records_by_torque_name_.find(name); + if (it == records_by_torque_name_.end()) { + // Classes without a record, such as templates, keep their .tq fields. + if (body_less) { + Error("class ", name, + " has no layout record; a @cppObjectLayoutDefinition " + "class without a .tq body takes its fields from the layout JSON") + .Position(decl->pos); + } + return; + } + const JsonObject& record = *it->second; + + const std::string torque_base = TorqueSuperName(decl->super); + std::vector<const JsonObject*> groups = CollapseCppOnlyBases( + record, name, records_by_cpp_name_, + [&](const std::string& base) { return base == torque_base; }); + + // Members of C++-only bases belong to this class, including any bit field + // groups among them. + for (const JsonObject* group : groups) { + ImportBitFieldStructs(*group, RequireString(*group, "cpp_name", name), + decl->pos); + } + + const JsonObject* tail_record = LookupTail(record, name); + // Keep the .tq fields when the tail has no length. An omitted tail + // contributes no field, but its fixed header still does. + TailRepresentation tail_representation = + GetTailRepresentation(record, tail_record, name); + if (tail_representation == TailRepresentation::kUnspecified) return; + if (tail_representation == TailRepresentation::kNone) tail_record = nullptr; + + // Use C++ positions for diagnostics and strict comparison first. + std::vector<ClassFieldExpression> fields = + BuildFields(name, record, groups, tail_record, tail_representation, + decl->pos, nullptr); + + // Replace a .tq field block only if the built fields are equivalent. + if (!body_less && !FieldsEquivalent(name, decl->fields, fields)) return; + + // Rebuild accepted fields at Torque positions so generated accessors stay + // in the same compilation units as on the legacy path. + std::vector<SourcePosition> torque_positions; + torque_positions.reserve(fields.size()); + if (body_less) { + torque_positions.resize(fields.size(), decl->pos); + } else { + for (const ClassFieldExpression& field : decl->fields) { + torque_positions.push_back(field.name_and_type.name->pos); + } + } + fields = BuildFields(name, record, groups, tail_record, tail_representation, + decl->pos, &torque_positions); + + decl->fields = std::move(fields); + decl->flags &= ~ClassFlags(ClassFlag::kUndefinedLayout); + } + + std::vector<ClassFieldExpression> BuildFields( + const std::string& class_name, const JsonObject& class_record, + const std::vector<const JsonObject*>& groups, + const JsonObject* tail_record, TailRepresentation tail_representation, + SourcePosition default_position, + const std::vector<SourcePosition>* positions) { + std::vector<ClassFieldExpression> fields; + std::map<std::string, std::string> cpp_names_by_torque_name; + auto build = [&](const JsonObject& field_record, + const std::string& owner_cpp_name, bool is_tail) { + std::string torque_name = TorqueFieldName(field_record, class_name); + const std::string& cpp_name = + RequireString(field_record, "cpp_name", class_name); + auto [name_it, inserted] = + cpp_names_by_torque_name.emplace(torque_name, cpp_name); + if (!inserted) { + ReportError("layout JSON: C++ fields ", name_it->second, " and ", + cpp_name, " in class ", class_name, + " both map to Torque field ", torque_name); + } + SourcePosition position = + positions != nullptr + ? positions->at(fields.size()) + : MemberPosition(owner_cpp_name, cpp_name, default_position); + fields.push_back( + is_tail ? BuildTail(class_name, class_record, field_record, position) + : BuildField(class_name, field_record, position)); + }; + for (const JsonObject* group : groups) { + const std::string& owner = RequireString(*group, "cpp_name", class_name); + for (const JsonValue& field : RequireFields(*group, class_name)) { + build(RequireFieldObject(field, class_name), owner, + /*is_tail=*/false); + } + } + if (tail_representation == TailRepresentation::kIndexedField) { + build(*tail_record, RequireString(*groups.back(), "cpp_name", class_name), + /*is_tail=*/true); + } + return fields; + } + + bool FieldsEquivalent(const std::string& class_name, + const std::vector<ClassFieldExpression>& declared, + const std::vector<ClassFieldExpression>& built) { + if (declared.size() != built.size()) { + Error("class ", class_name, ": .tq declares ", declared.size(), + " field(s), C++ ", built.size()) + .Position(declared.empty() + ? CurrentSourcePosition::Get() + : declared.front().name_and_type.name->pos); + return false; + } + bool equivalent = true; + for (size_t i = 0; i < declared.size(); ++i) { + // Errors building comparison keys should point at this field. + CurrentSourcePosition::Scope position_scope( + declared[i].name_and_type.name->pos); + std::string a = FieldKey(declared[i]); + std::string b = FieldKey(built[i]); + if (a != b) { + Error("class ", class_name, ": .tq field \"", a, + "\" differs from C++ field \"", b, "\"") + .Position(declared[i].name_and_type.name->pos); + equivalent = false; + } + } + return equivalent; + } + + ClassFieldExpression BuildField(const std::string& class_name, + const JsonObject& record, + SourcePosition position) { + std::string name = TorqueFieldName(record, class_name); + std::string context = class_name + "." + name; + CurrentSourcePosition::Scope position_scope(position); + + std::optional<ClassFieldIndexInfo> index; + if (Lookup(record, "array_extent") != nullptr) { + size_t extent = RequireSize(record, "array_extent", context); + Expression* extent_expr; + if (const std::string* extent_name = + AnnotationArgument(record, "V8_TQ_EXTENT_NAME", context)) { + // The size checks verify the V8_TQ_EXTENT_NAME expression. + extent_expr = ParseTorqueExpression(*extent_name); + } else { + extent_expr = + MakeNode<IntegerLiteralExpression>(IntegerLiteral(false, extent)); + } + index = ClassFieldIndexInfo{extent_expr, false}; + } + TypeExpression* type = RequireSize(record, "size", context) == 0 + ? NamedType("void") + : BuildFieldType(context, record, "storage"); + return {NameAndTypeExpression{MakeNode<Identifier>(name), type}, + std::move(index), + {}, + HasAnnotation(record, "V8_TQ_CUSTOM_WEAK", context), + HasAnnotation(record, "V8_TQ_CONST", context), + ReadSynchronization(record, context)}; + } + + ClassFieldExpression BuildTail(const std::string& class_name, + const JsonObject& class_record, + const JsonObject& record, + SourcePosition position) { + std::string name = TorqueFieldName(record, class_name); + std::string context = class_name + "." + name; + CurrentSourcePosition::Scope position_scope(position); + const std::string& length = + *AnnotationArgument(class_record, "V8_TQ_TAIL_LENGTH", context); + ClassFieldIndexInfo index{ParseTorqueExpression(length), false}; + return {NameAndTypeExpression{ + MakeNode<Identifier>(name), + BuildFieldType(context, record, "element_storage")}, + std::move(index), + {}, + HasAnnotation(record, "V8_TQ_CUSTOM_WEAK", context), + HasAnnotation(record, "V8_TQ_CONST", context), + ReadSynchronization(record, context)}; + } + + TypeExpression* BuildType(const std::string& context, + const JsonObject& record, const std::string& key) { + const JsonValue& value = Require(record, key, context); + if (!value.IsObject()) { + ReportError("layout JSON: ", context, ": \"", key, "\" is not an object"); + } + return BuildTypeExpression(context, value.ToObject()); + } + + TypeExpression* NamedType(const std::string& name, + TypeExpression* argument = nullptr) { + std::vector<TypeExpression*> arguments; + if (argument != nullptr) arguments.push_back(argument); + std::string identifier = name; + std::vector<std::string> namespaces = SplitQualification(&identifier); + return MakeNode<BasicTypeExpression>(std::move(namespaces), + MakeNode<Identifier>(identifier), + std::move(arguments)); + } + + // Map C++ storage to the Torque field type. + TypeExpression* DeriveType(const std::string& context, + const JsonObject& storage) { + const std::string& kind = RequireString(storage, "kind", context); + if (kind == "tagged" || kind == "unaligned") { + return BuildType(context, storage, "arg"); + } + if (kind == "protected_tagged") { + return NamedType("ProtectedPointer", BuildType(context, storage, "arg")); + } + if (kind == "trusted_pointer") { + // An object's own pointer-table entry has no pointee type. + return Lookup(storage, "arg") == nullptr + ? NamedType("TrustedPointer") + : NamedType("TrustedPointer", + BuildType(context, storage, "arg")); + } + if (kind == "external_pointer") return NamedType("ExternalPointer"); + if (kind == "cpp_heap_pointer") return NamedType("CppHeapPointer"); + // Dispatch handles are typed int32 (see js-function.tq). + if (kind == "js_dispatch_handle") return NamedType("int32"); + if (kind == "bool") return NamedType("bool"); + if (kind == "bitfield") { + return NamedType(TorqueBitFieldStructName(storage, context)); + } + if (kind == "enum" || kind == "struct") { + return NamedType(TorqueTypeName(RequireString(storage, "name", context))); + } + if (kind == "smi_bitfield") { + return NamedType("SmiTagged", + NamedType(TorqueBitFieldStructName(storage, context))); + } + if (kind == "int") { + if (const JsonValue* alias = Lookup(storage, "pointer_width_alias")) { + if (!alias->IsString()) { + ReportError("layout JSON: ", context, + ": \"pointer_width_alias\" is not a string"); + } + return NamedType(TorqueTypeName(alias->ToString())); + } + bool is_signed = OptionalBool(storage, "signed", context); + size_t bits = RequireSize(storage, "width", context) * 8; + return NamedType((is_signed ? "int" : "uint") + std::to_string(bits)); + } + ReportError("layout JSON: ", context, ": unknown storage kind \"", kind, + "\""); + } + + TypeExpression* BuildFieldType(const std::string& context, + const JsonObject& record, + const std::string& storage_key) { + if (const std::string* override = + AnnotationArgument(record, "V8_TQ_TYPE", context)) { + return ParseTorqueTypeExpression(*override); + } + const JsonValue& storage = Require(record, storage_key, context); + if (!storage.IsObject()) { + ReportError("layout JSON: ", context, ": \"", storage_key, + "\" is not an object"); + } + return DeriveType(context, storage.ToObject()); + } + + // Map a supported C++ class template to a Torque type. Torque has no generic + // class types, so known instantiations get specific names. For example, + // CppGCManaged<BackingStore> becomes ManagedBackingStore. Other + // instantiations use the template's Torque base type. Return nullptr if the + // template is not supported. + const char* ClassTemplateTorqueName(const std::string& name, + const JsonObject& type) { + const char* base_name = nullptr; + for (const PrimitiveTypeName& entry : kClassTemplateNames) { + if (name == entry.cpp) base_name = entry.torque; + } + if (base_name == nullptr) return nullptr; + + const JsonValue* args = Lookup(type, "args"); + if (args == nullptr || !args->IsArray() || args->ToArray().size() != 1 || + !args->ToArray()[0].IsObject()) { + return base_name; + } + const JsonObject& payload = args->ToArray()[0].ToObject(); + const JsonValue* payload_name = Lookup(payload, "name"); + if (payload_name == nullptr || !payload_name->IsString()) return base_name; + + std::string key = name + "<"; + if (const JsonValue* namespaces = Lookup(payload, "namespaces")) { + if (namespaces->IsArray()) { + for (const JsonValue& part : namespaces->ToArray()) { + if (part.IsString()) key += part.ToString() + "::"; + } + } + } + key += payload_name->ToString() + ">"; + for (const PrimitiveTypeName& entry : kClassTemplateInstantiations) { + if (key == entry.cpp) return entry.torque; + } + return base_name; + } + + TypeExpression* BuildTypeExpression(const std::string& context, + const JsonObject& type) { + const std::string& kind = RequireString(type, "kind", context); + if (kind == "name") { + if (const char* torque = ClassTemplateTorqueName( + RequireString(type, "name", context), type)) { + return MakeNode<BasicTypeExpression>(std::vector<std::string>{}, + MakeNode<Identifier>(torque), + std::vector<TypeExpression*>{}); + } + std::vector<TypeExpression*> args; + if (const JsonValue* args_value = Lookup(type, "args")) { + if (!args_value->IsArray()) { + ReportError("layout JSON: ", context, + ": type \"args\" is not an array"); + } + for (const JsonValue& arg : args_value->ToArray()) { + if (!arg.IsObject()) { + ReportError("layout JSON: ", context, + ": type argument is not an object"); + } + args.push_back(BuildTypeExpression(context, arg.ToObject())); + } + } + std::vector<std::string> namespaces; + if (const JsonValue* namespaces_value = Lookup(type, "namespaces")) { + if (!namespaces_value->IsArray()) { + ReportError("layout JSON: ", context, + ": type \"namespaces\" is not an array"); + } + for (const JsonValue& part : namespaces_value->ToArray()) { + if (!part.IsString()) { + ReportError("layout JSON: ", context, + ": type namespace is not a string"); + } + namespaces.push_back(part.ToString()); + } + } + std::string identifier = + TorqueTypeName(RequireString(type, "name", context)); + for (std::string& part : SplitQualification(&identifier)) { + namespaces.push_back(std::move(part)); + } + return MakeNode<BasicTypeExpression>(std::move(namespaces), + MakeNode<Identifier>(identifier), + std::move(args)); + } + if (kind == "union") { + const JsonValue& members = Require(type, "members", context); + if (!members.IsArray() || members.ToArray().size() < 2) { + ReportError("layout JSON: ", context, ": malformed union type"); + } + TypeExpression* result = nullptr; + for (const JsonValue& member : members.ToArray()) { + if (!member.IsObject()) { + ReportError("layout JSON: ", context, + ": union member is not an object"); + } + TypeExpression* next = BuildTypeExpression(context, member.ToObject()); + result = result == nullptr + ? next + : MakeNode<UnionTypeExpression>(result, next); + } + return result; + } + ReportError("layout JSON: ", context, ": unknown type kind \"", kind, "\""); + } + + // Parse a 1-based "path:line:column" C++ source position. + SourcePosition ParsePosition(const std::string& position) { + size_t column_sep = position.rfind(':'); + size_t line_sep = column_sep == std::string::npos + ? std::string::npos + : position.rfind(':', column_sep - 1); + if (line_sep == std::string::npos) { + ReportError("layout JSON: malformed position \"", position, "\""); + } + std::string path = position.substr(0, line_sep); + int line = std::atoi(position.substr(line_sep + 1).c_str()); + int column = std::atoi(position.substr(column_sep + 1).c_str()); + if (line <= 0 || column <= 0) { + ReportError("layout JSON: malformed position \"", position, "\""); + } + auto it = source_ids_.find(path); + if (it == source_ids_.end()) { + it = source_ids_.emplace(path, SourceFileMap::AddSource(path)).first; + } + // Torque positions are 0-based; the JSON's are 1-based. + LineAndColumn start = + LineAndColumn::WithUnknownOffset(line - 1, column - 1); + return SourcePosition{it->second, start, start}; + } + + std::map<std::string, const JsonObject*> records_by_cpp_name_; + std::map<std::string, const JsonObject*> records_by_torque_name_; + std::map<std::string, std::map<std::string, SourcePosition>> positions_; + // Bitfield structs declared in .tq or imported from JSON, indexed by name. + std::map<std::string, BitFieldStructDeclaration*> bit_field_structs_; + std::vector<Declaration*> new_bit_field_structs_; + std::map<std::string, SourceId> source_ids_; +}; + +} // namespace + +void VerifyCppLayouts(const std::string& layout_json_path) { + LayoutVerifier().Run(layout_json_path); +} + +void ImportCppLayouts(const std::string& layout_json_path, + const std::string& positions_path) { + LayoutImporter().Run(layout_json_path, positions_path); +} + +} // namespace v8::internal::torque diff --git a/deps/v8/src/torque/layout-loader.h b/deps/v8/src/torque/layout-loader.h new file mode 100644 index 000000000000..7ac5af7ecb2d --- /dev/null +++ b/deps/v8/src/torque/layout-loader.h @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project 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 V8_TORQUE_LAYOUT_LOADER_H_ +#define V8_TORQUE_LAYOUT_LOADER_H_ + +#include <string> + +namespace v8::internal::torque { + +// Loads the metagen layout JSON (schema in tools/metagen/layout_ir.py) +// and verifies every record for a @cppObjectLayoutDefinition class +// against the finalized Torque class type: base, base size, header +// size, and every field's name, offset, element size, storage +// category, constness, synchronization, and array shape must match. +// +// A mismatch is a Torque error at the field's position. A malformed +// file (unreadable, invalid JSON, wrong schema version) aborts +// compilation. The JSON contains every layout defined in C++, so +// records without a Torque class are skipped. +// +// Must run after TypeOracle::FinalizeAggregateTypes(). +void VerifyCppLayouts(const std::string& layout_json_path); + +// Populates @cppObjectLayoutDefinition classes in CurrentAst with fields +// built from the layout JSON. Classes can omit their .tq field declarations +// entirely, making the C++ layout authoritative. During migration, a class +// with a .tq body must declare equivalent fields; a mismatch is a Torque error. +// A class without a record keeps its .tq fields; without a .tq body, +// a missing record is an error. A class with an unannotated tail keeps +// its .tq fields or undefined layout (BigIntBase). +// Must run after parsing, before CompileCurrentAst. +// +// `positions_path` optionally names the positions JSON (per-member C++ +// source positions). With it, diagnostics for the built fields and for +// annotation arguments point at the C++ member; without it they point at +// the .tq class declaration. +void ImportCppLayouts(const std::string& layout_json_path, + const std::string& positions_path); + +} // namespace v8::internal::torque + +#endif // V8_TORQUE_LAYOUT_LOADER_H_ diff --git a/deps/v8/src/torque/source-positions.cc b/deps/v8/src/torque/source-positions.cc index 4c94093e5280..73604a3a01f5 100644 --- a/deps/v8/src/torque/source-positions.cc +++ b/deps/v8/src/torque/source-positions.cc @@ -55,11 +55,17 @@ SourceId SourceFileMap::GetSourceId(const std::string& path) { // static std::vector<SourceId> SourceFileMap::AllSources() { + // The layout loader registers C++ headers to locate Torque snippets in + // V8_TQ_* annotation arguments, such as type overrides, array extents, and + // tail sections. They provide diagnostic positions, not Torque compilation + // units, and must not produce per-source generated files. SourceFileMap& self = Get(); std::vector<SourceId> result; result.reserve(static_cast<int>(self.sources_.size())); for (int i = 0; i < static_cast<int>(self.sources_.size()); ++i) { - result.push_back(SourceId(i)); + if (StringEndsWith(self.sources_[i], ".tq")) { + result.push_back(SourceId(i)); + } } return result; } diff --git a/deps/v8/src/torque/source-positions.h b/deps/v8/src/torque/source-positions.h index 061d59d516cb..010db11d58fc 100644 --- a/deps/v8/src/torque/source-positions.h +++ b/deps/v8/src/torque/source-positions.h @@ -65,6 +65,10 @@ struct SourcePosition { return pos; } + bool IsValid() const { + return source.IsValid() && start.offset >= 0 && end.offset >= 0; + } + bool CompareStartIgnoreColumn(const SourcePosition& pos) const { return start.line == pos.start.line && source == pos.source; } diff --git a/deps/v8/src/torque/torque-compiler.cc b/deps/v8/src/torque/torque-compiler.cc index 23c8c41c8ddd..8e258f522326 100644 --- a/deps/v8/src/torque/torque-compiler.cc +++ b/deps/v8/src/torque/torque-compiler.cc @@ -12,6 +12,7 @@ #include "src/torque/declaration-visitor.h" #include "src/torque/global-context.h" #include "src/torque/implementation-visitor.h" +#include "src/torque/layout-loader.h" #include "src/torque/torque-parser.h" #ifdef V8_ENABLE_EXPERIMENTAL_TQ_TO_TSA #include "src/torque/tsa-generator.h" @@ -69,6 +70,12 @@ void CompileCurrentAst(TorqueCompilerOptions options) { if (options.torque_dwarf) { GlobalContext::SetTorqueDwarf(); } + if (options.kythe_inline_metadata) { + GlobalContext::SetKytheInlineMetadata(); + } + if (!options.kythe_default_corpus.empty()) { + GlobalContext::SetKytheDefaultCorpus(options.kythe_default_corpus); + } TypeOracle::Scope type_oracle; CurrentScope::Scope current_namespace(GlobalContext::GetDefaultNamespace()); @@ -84,6 +91,12 @@ void CompileCurrentAst(TorqueCompilerOptions options) { // mutually refer to each others. TypeOracle::FinalizeAggregateTypes(); + // With all class layouts finalized, cross-check them against the C++ + // layouts in the metagen layout JSON. + if (!options.layout_json_path.empty()) { + VerifyCppLayouts(options.layout_json_path); + } + if (options.output_tsa) { #ifdef V8_ENABLE_EXPERIMENTAL_TQ_TO_TSA #ifdef DEBUG @@ -142,6 +155,9 @@ TorqueCompilerResult CompileTorque(const std::string& source, TorqueCompilerResult result; try { ParseTorque(source); + if (!options.layout_json_path.empty() && options.use_cpp_layouts) { + ImportCppLayouts(options.layout_json_path, options.layout_positions_path); + } CompileCurrentAst(options); } catch (TorqueAbortCompilation&) { // Do nothing. The relevant TorqueMessage is part of the @@ -170,6 +186,9 @@ TorqueCompilerResult CompileTorque(const std::vector<std::string>& files, for (const auto& path : files) { ReadAndParseTorqueFile(path); } + if (!options.layout_json_path.empty() && options.use_cpp_layouts) { + ImportCppLayouts(options.layout_json_path, options.layout_positions_path); + } CompileCurrentAst(options); } catch (TorqueAbortCompilation&) { // Do nothing. The relevant TorqueMessage is part of the diff --git a/deps/v8/src/torque/torque-compiler.h b/deps/v8/src/torque/torque-compiler.h index eddd8364d837..41ccad8823d1 100644 --- a/deps/v8/src/torque/torque-compiler.h +++ b/deps/v8/src/torque/torque-compiler.h @@ -42,6 +42,31 @@ struct TorqueCompilerOptions { // Generates DWARF line info for Torque files. bool torque_dwarf = false; + + // Path to the metagen layout JSON (layouts.json). When set, the C++ + // layouts it describes are verified against the Torque class layouts + // after type finalization; any difference is a compile error. Empty + // disables the check. + std::string layout_json_path = ""; + + // Takes the layouts of @cppObjectLayoutDefinition classes from the + // layout JSON: their .tq field blocks are replaced by fields built from + // the JSON records, after a strict comparison shows both describe the + // same layout. Off is the legacy mode, where the .tq field blocks stay + // authoritative and are only verified. Requires layout_json_path. This + // is the transition switch; the .tq field blocks will be deleted once + // the flag has been on by default for a while. + bool use_cpp_layouts = false; + + // Optional path to the positions JSON (layout-positions.json) with + // per-member C++ source positions for diagnostics. The layout JSON has + // no positions so it only changes when a layout changes; this file + // changes when declaration positions change. + std::string layout_positions_path = ""; + + // Emits #pragma kythe_inline_metadata annotations in generated C++ files. + bool kythe_inline_metadata = false; + std::string kythe_default_corpus = ""; }; DECLARE_CONTEXTUAL_VARIABLE(CurrentCompilerOptions, TorqueCompilerOptions); diff --git a/deps/v8/src/torque/torque-parser.cc b/deps/v8/src/torque/torque-parser.cc index 14736cb2ee91..280d5ab50d10 100644 --- a/deps/v8/src/torque/torque-parser.cc +++ b/deps/v8/src/torque/torque-parser.cc @@ -117,6 +117,12 @@ V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<bool>::id = template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<int32_t>::id = ParseResultTypeId::kInt32; + +template <> +V8_EXPORT_PRIVATE const ParseResultTypeId + ParseResultHolder<std::optional<int32_t>>::id = + ParseResultTypeId::kOptionalInt32; + template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<double>::id = ParseResultTypeId::kDouble; @@ -2269,7 +2275,8 @@ std::optional<ParseResult> MakeBitFieldDeclaration( auto name = child_results->NextAs<Identifier*>(); auto type = child_results->NextAs<TypeExpression*>(); auto num_bits = child_results->NextAs<int32_t>(); - return ParseResult{BitFieldDeclaration{{name, type}, num_bits}}; + auto offset = child_results->NextAs<std::optional<int32_t>>(); + return ParseResult{BitFieldDeclaration{{name, type}, num_bits, offset}}; } std::optional<ParseResult> ExtractAssignmentOperator( @@ -2432,7 +2439,8 @@ struct TorqueGrammar : Grammar { // Result: std::string Symbol identifier = {Rule({Pattern(MatchIdentifier)}, YieldMatchedInput), - Rule({Token("runtime")}, YieldMatchedInput)}; + Rule({Token("runtime")}, YieldMatchedInput), + Rule({Token("type")}, YieldMatchedInput)}; // Result: Identifier* Symbol name = {Rule({&identifier}, MakeIdentifier)}; @@ -2584,9 +2592,10 @@ struct TorqueGrammar : Grammar { MakeStructField)}; // Result: BitFieldDeclaration - Symbol bitFieldDeclaration = {Rule({&name, Token(":"), &type, Token(":"), - &int32Literal, Token("bit"), Token(";")}, - MakeBitFieldDeclaration)}; + Symbol bitFieldDeclaration = {Rule( + {&name, Token(":"), &type, Token(":"), &int32Literal, Token("bit"), + Optional<int32_t>(Sequence({Token("at"), &int32Literal})), Token(";")}, + MakeBitFieldDeclaration)}; // Result: ParameterList Symbol parameterListNoVararg = { @@ -2981,4 +2990,37 @@ void ParseTorque(const std::string& input) { TorqueGrammar().Parse(input); } +namespace { + +// The annotation argument parsers run once per V8_TQ_TYPE / V8_TQ_EXTENT_NAME +// argument; the grammar is immutable after construction, so build it once. +TorqueGrammar& AnnotationGrammar() { + static TorqueGrammar* grammar = new TorqueGrammar(); + return *grammar; +} + +} // namespace + +TypeExpression* ParseTorqueTypeExpression(const std::string& input) { + BuildFlags::Scope build_flags_scope; + TorqueGrammar& grammar = AnnotationGrammar(); + std::optional<ParseResult> result = + grammar.Parse(&grammar.type, input, CurrentSourcePosition::Get()); + if (!result.has_value()) { + ReportError("cannot parse Torque type expression: ", input); + } + return std::move(*result).Cast<TypeExpression*>(); +} + +Expression* ParseTorqueExpression(const std::string& input) { + BuildFlags::Scope build_flags_scope; + TorqueGrammar& grammar = AnnotationGrammar(); + std::optional<ParseResult> result = + grammar.Parse(grammar.expression, input, CurrentSourcePosition::Get()); + if (!result.has_value()) { + ReportError("cannot parse Torque expression: ", input); + } + return std::move(*result).Cast<Expression*>(); +} + } // namespace v8::internal::torque diff --git a/deps/v8/src/torque/torque-parser.h b/deps/v8/src/torque/torque-parser.h index 134a697964c7..d6df5ae3fbdc 100644 --- a/deps/v8/src/torque/torque-parser.h +++ b/deps/v8/src/torque/torque-parser.h @@ -14,6 +14,11 @@ namespace torque { // Adds the parsed input to {CurrentAst} void ParseTorque(const std::string& input); +// Parse a standalone Torque type or expression without adding a declaration +// to CurrentAst. Used for the Torque source in V8_TQ_* annotation arguments. +TypeExpression* ParseTorqueTypeExpression(const std::string& input); +Expression* ParseTorqueExpression(const std::string& input); + Expression* MakeCall(Identifier* callee, const std::vector<TypeExpression*>& generic_arguments, const std::vector<Expression*>& arguments, diff --git a/deps/v8/src/torque/torque.cc b/deps/v8/src/torque/torque.cc index 69e8e6318ad6..7cd78a79e26e 100644 --- a/deps/v8/src/torque/torque.cc +++ b/deps/v8/src/torque/torque.cc @@ -40,12 +40,22 @@ int WrappedMain(int argc, const char** argv) { #else options.force_32bit_output = true; #endif + } else if (argument == "-layout-json") { + options.layout_json_path = argv[++i]; + } else if (argument == "-layout-positions") { + options.layout_positions_path = argv[++i]; + } else if (argument == "-use-cpp-layouts") { + options.use_cpp_layouts = true; } else if (argument == "-annotate-ir") { options.annotate_ir = true; } else if (argument == "-torque-dwarf") { options.torque_dwarf = true; } else if (argument == "-strip-v8-root") { options.strip_v8_root = true; + } else if (argument == "-kythe-inline-metadata") { + options.kythe_inline_metadata = true; + } else if (argument == "-kythe-default-corpus" && i + 1 < argc) { + options.kythe_default_corpus = std::string(argv[++i]); #ifdef V8_ENABLE_EXPERIMENTAL_TQ_TO_TSA } else if (argument == "-output-tsa") { options.output_tsa = true; diff --git a/deps/v8/src/torque/type-visitor.cc b/deps/v8/src/torque/type-visitor.cc index debdc73906fe..53ee736f7a65 100644 --- a/deps/v8/src/torque/type-visitor.cc +++ b/deps/v8/src/torque/type-visitor.cc @@ -116,6 +116,9 @@ void DeclareMethods(AggregateType* container_type, signature, body); m->SetPosition(method->pos); m->SetIdentifierPosition(method->name->pos); + if (GlobalContext::collect_kythe_data()) { + KytheData::AddFunctionDefinition(m); + } } } @@ -170,14 +173,15 @@ const BitFieldStructType* TypeVisitor::ComputeType( ReportError("Invalid number of bits for ", field.name_and_type.name->value); } + offset = field.offset.value_or(offset); + if (offset < 0 || static_cast<size_t>(offset) + field.num_bits > size) { + ReportError("Bitfield outside storage in ", decl->name->value); + } type->RegisterField({field.name_and_type.name->pos, {field.name_and_type.name->value, field_type}, offset, field.num_bits}); offset += field.num_bits; - if (static_cast<size_t>(offset) > size) { - ReportError("Too many total bits in ", decl->name->value); - } } return type; diff --git a/deps/v8/src/torque/types.cc b/deps/v8/src/torque/types.cc index 397d63926a78..cbfd01c2e053 100644 --- a/deps/v8/src/torque/types.cc +++ b/deps/v8/src/torque/types.cc @@ -12,6 +12,7 @@ #include "src/torque/ast.h" #include "src/torque/declarable.h" #include "src/torque/global-context.h" +#include "src/torque/kythe-data.h" #include "src/torque/source-positions.h" #include "src/torque/type-oracle.h" #include "src/torque/type-visitor.h" @@ -317,7 +318,7 @@ std::string UnionType::GetGeneratedTNodeTypeNameImpl() const { std::stringstream result; result << "Union<"; bool first = true; - for (std::string name : names) { + for (const std::string& name : names) { if (!first) { result << ", "; } @@ -373,7 +374,7 @@ std::string UnionType::GetConstexprGeneratedTypeName() const { std::stringstream result; result << "Union<"; bool first = true; - for (std::string name : names) { + for (const std::string& name : names) { if (!first) { result << ", "; } @@ -881,8 +882,13 @@ void ClassType::GenerateAccessors() { MakeNode<ElementAccessExpression>(load_expression, index); } Statement* load_body = MakeNode<ReturnStatement>(load_expression); - Declarations::DeclareMacro(load_macro_name, true, std::nullopt, - load_signature, load_body, std::nullopt); + Macro* load_macro = + Declarations::DeclareMacro(load_macro_name, true, std::nullopt, + load_signature, load_body, std::nullopt); + load_macro->SetIdentifierPosition(field.pos); + if (GlobalContext::collect_kythe_data()) { + KytheData::AddFunctionDefinition(load_macro); + } // Store accessor if (!field.const_qualified) { @@ -909,9 +915,13 @@ void ClassType::GenerateAccessors() { } Statement* store_body = MakeNode<ExpressionStatement>( MakeNode<AssignmentExpression>(store_expression, value)); - Declarations::DeclareMacro(store_macro_name, true, std::nullopt, - store_signature, store_body, std::nullopt, - false); + Macro* store_macro = Declarations::DeclareMacro( + store_macro_name, true, std::nullopt, store_signature, store_body, + std::nullopt, false); + store_macro->SetIdentifierPosition(field.pos); + if (GlobalContext::collect_kythe_data()) { + KytheData::AddFunctionDefinition(store_macro); + } } } } @@ -1039,6 +1049,10 @@ void ClassType::GenerateSliceAccessor(size_t field_index) { Macro* macro = Declarations::DeclareMacro(macro_name, true, std::nullopt, signature, block, std::nullopt); + macro->SetIdentifierPosition(field.pos); + if (GlobalContext::collect_kythe_data()) { + KytheData::AddFunctionDefinition(macro); + } if (this->ShouldGenerateCppObjectLayoutDefinitionAsserts()) { GlobalContext::EnsureInCCDebugOutputList(TorqueMacro::cast(macro), macro->Position().source); diff --git a/deps/v8/src/torque/utils.cc b/deps/v8/src/torque/utils.cc index 767ed953d4bc..a1814a37396f 100644 --- a/deps/v8/src/torque/utils.cc +++ b/deps/v8/src/torque/utils.cc @@ -264,10 +264,10 @@ std::string CapifyStringWithUnderscores(const std::string& camellified_string) { if ((previousWasLowerOrDigit && isupper(current)) || (js_position != std::string::npos && index == js_position + strlen("JS"))) { - result += "_"; + result += '_'; } if (current == '.' || current == '-') { - result += "_"; + result += '_'; previousWasLowerOrDigit = false; continue; } @@ -299,7 +299,7 @@ std::string SnakeifyString(const std::string& camel_string) { bool previousWasLower = false; for (auto current : camel_string) { if (previousWasLower && isupper(current)) { - result += "_"; + result += '_'; } result += tolower(current); previousWasLower = (islower(current)); diff --git a/deps/v8/src/tracing/code-data-source.cc b/deps/v8/src/tracing/code-data-source.cc index eb13ccb3ff13..d7bbc287d584 100644 --- a/deps/v8/src/tracing/code-data-source.cc +++ b/deps/v8/src/tracing/code-data-source.cc @@ -205,8 +205,11 @@ uint64_t CodeDataSourceIncrementalState::InternJsScript(Isolate* isolate, uint64_t CodeDataSourceIncrementalState::InternJsFunction( Isolate* isolate, DirectHandle<SharedFunctionInfo> info, uint64_t v8_js_script_iid, int line_num, int column_num) { + // Some callers already have a `DisallowGarbageCollection` scope open, hence + // we should never allocate in this method. + DisallowGarbageCollection no_gc; DirectHandle<String> function_name = - SharedFunctionInfo::DebugName(isolate, info); + SharedFunctionInfo::DebugName(isolate, info, AllowAllocation{false}); uint64_t v8_js_function_name_iid = InternJsFunctionName(*function_name); auto [it, was_inserted] = functions_.emplace( diff --git a/deps/v8/src/tracing/perfetto-logger.cc b/deps/v8/src/tracing/perfetto-logger.cc index 242de086df54..3a5e33383ba2 100644 --- a/deps/v8/src/tracing/perfetto-logger.cc +++ b/deps/v8/src/tracing/perfetto-logger.cc @@ -175,6 +175,20 @@ void WriteJsCode(Isolate* isolate, const CodeTraceContext& ctx, break; } +#if V8_ENABLE_WEBASSEMBLY + if (code->builtin_id() == Builtin::kJSToWasmWrapper || + code->builtin_id() == Builtin::kWasmPromising || + code->builtin_id() == Builtin::kWasmResume || + code->builtin_id() == Builtin::kWasmReject || +#if V8_ENABLE_DRUMBRAKE + code->builtin_id() == Builtin::kJSToWasmInterpreterWrapper || +#endif + code->builtin_id() == Builtin::kWasmStressSwitch) { + tier = V8JsCode::TIER_UNKNOWN; + break; + } +#endif + // kEmptyFunction is used as a placeholder sometimes. DCHECK_EQ(code->builtin_id(), Builtin::kEmptyFunction); DCHECK(!code->has_instruction_stream()); @@ -194,6 +208,10 @@ void WriteJsCode(Isolate* isolate, const CodeTraceContext& ctx, tier = V8JsCode::TIER_TURBOFAN; break; + case CodeKind::JS_TO_WASM_FUNCTION: + tier = V8JsCode::TIER_UNKNOWN; + break; + case CodeKind::BYTECODE_HANDLER: case CodeKind::FOR_TESTING: case CodeKind::FOR_TESTING_JS: @@ -201,7 +219,6 @@ void WriteJsCode(Isolate* isolate, const CodeTraceContext& ctx, case CodeKind::WASM_FUNCTION: case CodeKind::WASM_TO_CAPI_FUNCTION: case CodeKind::WASM_TO_JS_FUNCTION: - case CodeKind::JS_TO_WASM_FUNCTION: case CodeKind::C_WASM_ENTRY: case CodeKind::WASM_STACK_ENTRY: UNREACHABLE(); diff --git a/deps/v8/src/tracing/traced-value.cc b/deps/v8/src/tracing/traced-value.cc index fb74a78d565e..9141c305e19e 100644 --- a/deps/v8/src/tracing/traced-value.cc +++ b/deps/v8/src/tracing/traced-value.cc @@ -4,6 +4,8 @@ #include "src/tracing/traced-value.h" +#include <array> + #include "src/base/platform/platform.h" #include "src/base/vector.h" #include "src/numbers/conversions.h" @@ -98,7 +100,7 @@ void TracedValue::SetUnsignedInteger(const char* name, uint64_t value) { void TracedValue::SetDouble(const char* name, double value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); WriteName(name); - base::EmbeddedVector<char, 100> buffer; + std::array<char, 100> buffer; data_ += internal::DoubleToStringView(value, buffer); } @@ -147,7 +149,7 @@ void TracedValue::AppendInteger(int value) { void TracedValue::AppendDouble(double value) { DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray); WriteComma(); - base::EmbeddedVector<char, 100> buffer; + std::array<char, 100> buffer; data_ += internal::DoubleToStringView(value, buffer); } diff --git a/deps/v8/src/utils/bit-vector.h b/deps/v8/src/utils/bit-vector.h index a262d1e34a65..d57e63176e91 100644 --- a/deps/v8/src/utils/bit-vector.h +++ b/deps/v8/src/utils/bit-vector.h @@ -6,6 +6,7 @@ #define V8_UTILS_BIT_VECTOR_H_ #include <algorithm> +#include <bit> #include "src/base/bits.h" #include "src/zone/zone.h" @@ -211,6 +212,21 @@ class V8_EXPORT_PRIVATE BitVector : public ZoneObject { std::copy_n(other.data_begin_, data_length(), data_begin_); } + void CopyFrom(const BitVector& other, int index, int count) { + DCHECK_LE(other.length(), length()); + DCHECK_LE(index + count, other.length()); + ForRange( + index, count, + [&](int w, uintptr_t mask) { + data_begin_[w] = + (data_begin_[w] & ~mask) | (other.data_begin_[w] & mask); + }, + [&](int start_w, int num_words) { + std::copy_n(other.data_begin_ + start_w, num_words, + data_begin_ + start_w); + }); + } + void Resize(int new_length, Zone* zone) { DCHECK_GT(new_length, length()); int old_data_length = data_length(); @@ -240,6 +256,14 @@ class V8_EXPORT_PRIVATE BitVector : public ZoneObject { data_begin_[word(i)] |= bit(i); } + void Add(int index, int count) { + ForRange( + index, count, [&](int w, uintptr_t mask) { data_begin_[w] |= mask; }, + [&](int start_w, int num_words) { + std::fill_n(data_begin_ + start_w, num_words, ~uintptr_t{0}); + }); + } + void AddAll() { if (V8_UNLIKELY(length() == 0)) return; int partial_size = length() % kDataBits; @@ -255,6 +279,14 @@ class V8_EXPORT_PRIVATE BitVector : public ZoneObject { data_begin_[word(i)] &= ~bit(i); } + void Remove(int index, int count) { + ForRange( + index, count, [&](int w, uintptr_t mask) { data_begin_[w] &= ~mask; }, + [&](int start_w, int num_words) { + std::fill_n(data_begin_ + start_w, num_words, 0); + }); + } + void Union(const BitVector& other) { DCHECK_LE(other.length(), length()); for (int i = 0; i < other.data_length(); i++) { @@ -355,6 +387,38 @@ class V8_EXPORT_PRIVATE BitVector : public ZoneObject { explicit DataStorage(uintptr_t value) : inline_(value) {} }; + template <typename WordOp, typename FullWordsOp> + void ForRange(int index, int count, WordOp word_op, + FullWordsOp full_words_op) { + DCHECK_GE(index, 0); + DCHECK_GE(count, 0); + DCHECK_LE(index + count, length()); + if (count == 0) return; + + int start_word = word(index); + int start_bit = index & (kDataBits - 1); + if (start_bit + count <= kDataBits) { + uintptr_t mask = (~uintptr_t{0} >> (kDataBits - count)) << start_bit; + word_op(start_word, mask); + return; + } + + uintptr_t first_mask = ~uintptr_t{0} << start_bit; + word_op(start_word, first_mask); + + int remaining = count - (kDataBits - start_bit); + int current_word = start_word + 1; + int full_words = remaining >> kDataBitShift; + full_words_op(current_word, full_words); + + remaining &= (kDataBits - 1); + if (remaining > 0) { + current_word += full_words; + uintptr_t last_mask = ~uintptr_t{0} >> (kDataBits - remaining); + word_op(current_word, last_mask); + } + } + bool is_inline() const { return data_begin_ == &data_.inline_; } int data_length() const { return static_cast<int>(data_end_ - data_begin_); } @@ -427,11 +491,10 @@ class GrowableBitVector { V8_NOINLINE void Grow(int needed_value, Zone* zone) { DCHECK(!InBitsRange(needed_value)); - // Ensure that {RoundUpToPowerOfTwo32} does not overflow {int} range. + // Ensure that {std::bit_ceil} does not overflow {int} range. CHECK_GE(kMaxSupportedValue, needed_value); - int new_length = std::max( - kInitialLength, static_cast<int>(base::bits::RoundUpToPowerOfTwo32( - static_cast<uint32_t>(needed_value + 1)))); + int new_length = std::max<int>(kInitialLength, + std::bit_ceil<uint32_t>(needed_value + 1)); bits_.Resize(new_length, zone); } diff --git a/deps/v8/src/utils/memcopy.h b/deps/v8/src/utils/memcopy.h index 9ca87842c836..54223d320bd2 100644 --- a/deps/v8/src/utils/memcopy.h +++ b/deps/v8/src/utils/memcopy.h @@ -41,16 +41,21 @@ inline void MemCopyAndSwitchEndianness(void* dst, const void* src, // Copies words from |src| to |dst|. The data spans must not overlap. // |src| and |dst| must be TWord-size aligned. -template <typename T> -inline void CopyImpl(T* dst_ptr, const T* src_ptr, size_t count) { - constexpr int kTWordSize = sizeof(T); +template <typename T, typename U> +inline void CopyImpl(T* dst_ptr, const T* src_ptr, U count) { + static_assert(std::is_unsigned_v<U>); + static_assert(sizeof(U) >= sizeof(uint32_t)); + constexpr U kTWordSize = sizeof(T); #ifdef DEBUG Address dst = reinterpret_cast<Address>(dst_ptr); Address src = reinterpret_cast<Address>(src_ptr); DCHECK(IsAligned(dst, kTWordSize)); DCHECK(IsAligned(src, kTWordSize)); #endif - MemCopy(dst_ptr, src_ptr, count * kTWordSize); + // Preserve the domain of `count`. This ensures that e.g. `uint32_t` counts + // stay within `uint32_t` byte range for security reasons. + const U byte_size = count * kTWordSize; + MemCopy(dst_ptr, src_ptr, byte_size); } // Copies `count` system words from `src` to `dst`. The data spans must not @@ -61,8 +66,10 @@ inline void CopyWords(Address dst, const Address src, size_t count) { } // Copies `count` tagged words from `src` to `dst`. The data spans must not -// overlap. `src` and `dst` must be kTaggedSize-aligned. -inline void CopyTagged(Address dst, const Address src, size_t count) { +// overlap. `src` and `dst` must be kTaggedSize-aligned. The size is passed as +// `uint32_t` as tagged copies are only used for on-heap objects which never +// exceed the 32-bit range. +inline void CopyTagged(Address dst, const Address src, uint32_t count) { CopyImpl(reinterpret_cast<Tagged_t*>(dst), reinterpret_cast<const Tagged_t*>(src), count); } diff --git a/deps/v8/src/utils/scoped-list.h b/deps/v8/src/utils/scoped-list.h index 7bc0da372ef7..ec8bb30c968b 100644 --- a/deps/v8/src/utils/scoped-list.h +++ b/deps/v8/src/utils/scoped-list.h @@ -40,10 +40,12 @@ class V8_NODISCARD ScopedList final { ~ScopedList() { Rewind(); } - void Rewind() { + void Rewind(int length = 0) { DCHECK_EQ(buffer_.size(), end_); - buffer_.resize(start_); - end_ = start_; + DCHECK_LE(0, length); + DCHECK_LE(start_ + length, end_); + end_ = start_ + length; + buffer_.resize(end_); } void MergeInto(ScopedList* parent) { @@ -80,6 +82,13 @@ class V8_NODISCARD ScopedList final { ++end_; } + void DropLast() { + DCHECK_EQ(buffer_.size(), end_); + DCHECK_GT(end_, start_); + buffer_.pop_back(); + --end_; + } + void AddAll(base::Vector<const T> list) { DCHECK_EQ(buffer_.size(), end_); buffer_.reserve(buffer_.size() + list.length()); diff --git a/deps/v8/src/utils/sparse-bit-vector.h b/deps/v8/src/utils/sparse-bit-vector.h index a0eef2c65a80..28f8e7c8bafa 100644 --- a/deps/v8/src/utils/sparse-bit-vector.h +++ b/deps/v8/src/utils/sparse-bit-vector.h @@ -209,15 +209,27 @@ class SparseBitVector : public ZoneObject { return {bit_in_segment / kBitsPerWord, bit_in_segment % kBitsPerWord}; } - V8_NOINLINE void InsertBitAfter(Segment* segment, int i) { - Segment* new_segment = zone_->New<Segment>(); + V8_NOINLINE V8_PRESERVE_MOST void InsertBitAfter(Segment* segment, int i) { + // Search for an empty segment to reuse. + Segment* new_segment = nullptr; + for (Segment* prev = &first_segment_; prev->next; prev = prev->next) { + if (Segment* curr = prev->next; curr->empty()) { + prev->next = curr->next; + curr->next = nullptr; + new_segment = curr; + // If {segment} itself was empty and unlinked, insert after {prev}. + if (curr == segment) segment = prev; + break; + } + } + if (!new_segment) new_segment = zone_->New<Segment>(); new_segment->offset = i / kNumBitsPerSegment * kNumBitsPerSegment; set(new_segment, i); InsertSegmentAfter(segment, new_segment); DCHECK(Contains(i)); } - V8_NOINLINE void InsertSegmentAfter(Segment* segment, Segment* new_segment) { + void InsertSegmentAfter(Segment* segment, Segment* new_segment) { DCHECK_NOT_NULL(segment); DCHECK_LT(segment->offset, new_segment->offset); insert_after(segment, new_segment); diff --git a/deps/v8/src/utils/utils.cc b/deps/v8/src/utils/utils.cc index e59717a5c52f..ed3ad33d95b4 100644 --- a/deps/v8/src/utils/utils.cc +++ b/deps/v8/src/utils/utils.cc @@ -229,8 +229,7 @@ uintptr_t GetCurrentStackPosition() { // "name" only the function "name" // "name*" only functions starting with "name" // "~" none; the tilde is not an identifier -bool PassesFilter(base::Vector<const char> name, - base::Vector<const char> filter) { +bool PassesFilter(std::string_view name, std::string_view filter) { if (filter.empty()) return name.empty(); auto filter_it = filter.begin(); bool positive_filter = true; diff --git a/deps/v8/src/utils/utils.h b/deps/v8/src/utils/utils.h index e4e6b703ae3e..48eca5c2a6f2 100644 --- a/deps/v8/src/utils/utils.h +++ b/deps/v8/src/utils/utils.h @@ -11,6 +11,7 @@ #include <cmath> #include <string> +#include <string_view> #include <type_traits> #include "src/base/bits.h" @@ -18,6 +19,7 @@ #include "src/base/hashing.h" #include "src/base/logging.h" #include "src/base/macros.h" +#include "src/base/memory.h" #include "src/base/numerics/safe_conversions.h" #include "src/base/vector.h" #include "src/common/globals.h" @@ -480,6 +482,104 @@ V8_INLINE bool SimdMemEqual(const Char* lhs, const Char* rhs, size_t count) { } } +#if defined(V8_TARGET_LITTLE_ENDIAN) +V8_INLINE uint32_t WidenTwoBytesToU32(const uint8_t* p) { + uint32_t x = base::ReadUnalignedValue<uint16_t>(p); + return (x | (x << 8)) & 0x00FF00FFu; +} + +V8_INLINE uint64_t WidenFourBytesToU64(const uint8_t* p) { + uint64_t x = base::ReadUnalignedValue<uint32_t>(p); + x = (x | (x << 16)) & 0x0000FFFF0000FFFFULL; + return (x | (x << 8)) & 0x00FF00FF00FF00FFULL; +} +#endif // defined(V8_TARGET_LITTLE_ENDIAN) + +V8_INLINE bool CompareOneAndTwoByteCharsFallback(const uint8_t* one_byte, + const uint16_t* two_byte, + size_t length) { + DCHECK_LT(length, 8); +#if defined(V8_TARGET_LITTLE_ENDIAN) + static constexpr size_t kSwarChunkSize = 4; + if (length >= kSwarChunkSize) { + return WidenFourBytesToU64(one_byte) == + base::ReadUnalignedValue<uint64_t>( + reinterpret_cast<const uint8_t*>(two_byte)) && + WidenFourBytesToU64(one_byte + length - kSwarChunkSize) == + base::ReadUnalignedValue<uint64_t>( + reinterpret_cast<const uint8_t*>(two_byte + length - + kSwarChunkSize)); + } + if (length >= 2) { + return WidenTwoBytesToU32(one_byte) == + base::ReadUnalignedValue<uint32_t>( + reinterpret_cast<const uint8_t*>(two_byte)) && + WidenTwoBytesToU32(one_byte + length - 2) == + base::ReadUnalignedValue<uint32_t>( + reinterpret_cast<const uint8_t*>(two_byte + length - 2)); + } + return length == 0 || *one_byte == *two_byte; +#else + for (size_t i = 0; i < length; ++i) { + if (one_byte[i] != two_byte[i]) return false; + } + return true; +#endif // defined(V8_TARGET_LITTLE_ENDIAN) +} + +// We intentionally use misaligned reads for the SIMD intrinsics below, disable +// alignment sanitization explicitly. +#if defined(__SSE3__) +V8_CLANG_NO_SANITIZE("alignment") +V8_INLINE bool CompareOneAndTwoByteChunk(const uint8_t* ob, + const uint16_t* tb) { + __m128i ob8 = _mm_loadu_si64(ob); + __m128i ob16 = _mm_unpacklo_epi8(ob8, _mm_setzero_si128()); + __m128i tb16 = _mm_lddqu_si128(reinterpret_cast<const __m128i*>(tb)); + __m128i eq = _mm_cmpeq_epi16(ob16, tb16); + return _mm_movemask_epi8(eq) == 0xFFFF; +} +#elif defined(V8_OPTIMIZE_WITH_NEON) +V8_CLANG_NO_SANITIZE("alignment") +V8_INLINE bool CompareOneAndTwoByteChunk(const uint8_t* ob, + const uint16_t* tb) { + uint8x8_t ob8 = vld1_u8(ob); + uint16x8_t ob16 = vmovl_u8(ob8); + uint16x8_t tb16 = vld1q_u16(tb); + uint16x8_t diff = veorq_u16(ob16, tb16); + return vmaxvq_u16(diff) == 0; +} +#endif + +#if defined(__SSE3__) || defined(V8_OPTIMIZE_WITH_NEON) +V8_INLINE bool CompareOneAndTwoByteChars(const uint8_t* one_byte, + const uint16_t* two_byte, + size_t length) { + static constexpr size_t kChunkSize = 8; + if (length < kChunkSize) { + return CompareOneAndTwoByteCharsFallback(one_byte, two_byte, length); + } + size_t i = 0; + for (; i + kChunkSize <= length; i += kChunkSize) { + if (!CompareOneAndTwoByteChunk(one_byte + i, two_byte + i)) return false; + } + if (i < length) { + return CompareOneAndTwoByteChunk(one_byte + length - kChunkSize, + two_byte + length - kChunkSize); + } + return true; +} +#else +V8_INLINE bool CompareOneAndTwoByteChars(const uint8_t* one_byte, + const uint16_t* two_byte, + size_t length) { + for (size_t i = 0; i < length; ++i) { + if (one_byte[i] != two_byte[i]) return false; + } + return true; +} +#endif + // Compare 8bit/16bit chars to 8bit/16bit chars. template <typename lchar, typename rchar> inline bool CompareCharsEqualUnsigned(const lchar* lhs, const rchar* rhs, @@ -496,6 +596,12 @@ inline bool CompareCharsEqualUnsigned(const lchar* lhs, const rchar* rhs, // two-byte char comparison is little- or big-endian. return memcmp(lhs, rhs, chars * sizeof(*lhs)) == 0; } + if constexpr (sizeof(*lhs) == 1 && sizeof(*rhs) == 2) { + return CompareOneAndTwoByteChars(lhs, rhs, chars); + } + if constexpr (sizeof(*lhs) == 2 && sizeof(*rhs) == 1) { + return CompareOneAndTwoByteChars(rhs, lhs, chars); + } for (const lchar* limit = lhs + chars; lhs < limit; ++lhs, ++rhs) { if (*lhs != *rhs) return false; } @@ -799,8 +905,8 @@ inline Float16 FpOpWorkaround(Float16 input, Float16 value) { #endif -V8_EXPORT_PRIVATE bool PassesFilter(base::Vector<const char> name, - base::Vector<const char> filter); +V8_EXPORT_PRIVATE bool PassesFilter(std::string_view name, + std::string_view filter); // Zap the specified area with a specific byte pattern. This currently defaults // to int3 on x64 and ia32. On other architectures this will produce unspecified diff --git a/deps/v8/src/wasm/baseline/arm/liftoff-assembler-arm-inl.h b/deps/v8/src/wasm/baseline/arm/liftoff-assembler-arm-inl.h index 24e597152831..eca86cdc48fa 100644 --- a/deps/v8/src/wasm/baseline/arm/liftoff-assembler-arm-inl.h +++ b/deps/v8/src/wasm/baseline/arm/liftoff-assembler-arm-inl.h @@ -533,7 +533,8 @@ void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. @@ -597,14 +598,18 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); mov(WasmHandleStackOverflowDescriptor::GapRegister(), Operand(max_stack_space)); add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(stack_param_slots * kSystemPointerSize + + Operand((stack_param_slots + stack_return_slots) * kSystemPointerSize + CommonFrameConstants::kFixedFrameSizeAboveFp)); + mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Operand(stack_param_slots * kSystemPointerSize)); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -686,59 +691,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, b(ool_label, mi); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return fp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - ldr(old_fp.gp(), MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - cmp(old_fp.gp(), - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - b(&call_runtime, eq); - mov(old_fp.gp(), fp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - MacroAssembler::Move(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - mov(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - { - UseScratchRegisterScope temps{this}; - Register scratch = temps.Acquire(); - ldr(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - cmp(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - b(&done, ne); - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - MacroAssembler::Move(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - mov(fp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -754,12 +706,9 @@ void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { case kF32: vmov(liftoff::GetFloatRegister(reg.fp()), value.to_f32_boxed()); break; - case kF64: { - Register extra_scratch = GetUnusedRegister(kGpReg, {}).gp(); - vmov(reg.fp(), base::Double(value.to_f64_boxed().get_bits()), - extra_scratch); + case kF64: + vmov(reg.fp(), base::Double(value.to_f64_boxed().get_bits())); break; - } default: UNREACHABLE(); } @@ -775,7 +724,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { static_assert(!V8_ENABLE_SANDBOX_BOOL); static_assert(!COMPRESS_POINTERS_BOOL); ldr(dst, MemOperand{src_addr, offset}); @@ -1733,9 +1682,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { - MemOperand dst(frame_pointer, (caller_slot_idx + 1) * kSystemPointerSize); + ValueKind kind) { + MemOperand dst(fp, (caller_slot_idx + 1) * kSystemPointerSize); liftoff::Store(this, src, dst, kind); } @@ -1824,17 +1772,24 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { mov(src, Operand(value.to_i32())); str(src, dst); break; - case kI64: { - int32_t low_word = value.to_i64(); + case kF32: + mov(src, Operand(value.to_f32_boxed().get_bits())); + str(src, dst); + break; + case kI64: + case kF64: { + int64_t val64 = value.type().kind() == kI64 + ? value.to_i64() + : value.to_f64_boxed().get_bits(); + int32_t low_word = static_cast<int32_t>(val64); mov(src, Operand(low_word)); str(src, liftoff::GetHalfStackSlot(offset, kLowWord)); - int32_t high_word = value.to_i64() >> 32; + int32_t high_word = static_cast<int32_t>(val64 >> 32); mov(src, Operand(high_word)); str(src, liftoff::GetHalfStackSlot(offset, kHighWord)); break; } default: - // We do not track f32 and f64 constants, hence they are unreachable. UNREACHABLE(); } } @@ -5227,10 +5182,18 @@ void LiftoffStackSlots::Construct(int param_slots) { break; } case LiftoffAssembler::VarState::kIntConst: { - asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); - DCHECK(src.kind() == kI32 || src.kind() == kI64); + DCHECK(src.kind() == kI32 || src.kind() == kI64 || src.kind() == kF32 || + src.kind() == kF64); UseScratchRegisterScope temps(asm_); Register scratch = temps.Acquire(); + if (src.kind() == kF64) { + asm_->AllocateStackSpace(stack_decrement - kDoubleSize); + DCHECK_EQ(kLowWord, slot.half_); + asm_->mov(scratch, Operand(src.i32_const() >> 31)); + asm_->push(scratch); + stack_decrement = kSystemPointerSize; + } + asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); // The high word is the sign extension of the low word. asm_->mov(scratch, Operand(slot.half_ == kLowWord ? src.i32_const() diff --git a/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64-inl.h b/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64-inl.h index 57476d65f3a4..7ffb05b871f8 100644 --- a/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64-inl.h +++ b/deps/v8/src/wasm/baseline/arm64/liftoff-assembler-arm64-inl.h @@ -213,13 +213,13 @@ inline CPURegister LoadToRegister(LiftoffAssembler* assm, return GetRegFromType(src.reg(), src.kind()); } if (src.is_const()) { - if (src.kind() == kI32) { + if (src.kind() == kI32 || src.kind() == kF32) { if (src.i32_const() == 0) return wzr; Register temp = temps->AcquireW(); assm->Mov(temp, src.i32_const()); return temp; } - DCHECK_EQ(kI64, src.kind()); + DCHECK(src.kind() == kI64 || src.kind() == kF64); if (src.i32_const() == 0) return xzr; Register temp = temps->AcquireX(); assm->Mov(temp, static_cast<int64_t>(src.i32_const())); @@ -322,7 +322,8 @@ void LiftoffAssembler::AlignFrameSize() { void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. @@ -390,13 +391,17 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); Mov(WasmHandleStackOverflowDescriptor::GapRegister(), max_stack_space); Add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(stack_param_slots * kSystemPointerSize + + Operand((stack_param_slots + stack_return_slots) * kSystemPointerSize + CommonFrameConstants::kFixedFrameSizeAboveFp)); + Mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + stack_param_slots * kSystemPointerSize); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -485,63 +490,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, B(ool_label, mi); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return fp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - Ldr(old_fp.gp(), MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - Cmp(old_fp.gp(), - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - B(eq, &call_runtime); - Mov(old_fp.gp(), fp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - Mov(kCArgRegs[0], ExternalReference::isolate_address()); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - Mov(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - { - UseScratchRegisterScope temps{this}; - Register scratch = temps.AcquireX(); - Ldr(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - Cmp(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - B(ne, &done); - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - Mov(kCArgRegs[0], ExternalReference::isolate_address()); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - Mov(fp, kReturnRegister0); - PopRegisters(regs_to_save); - if (options().enable_simulator_code) { - // The next instruction after shrinking stack is leaving the frame. - // So SP will be set to old FP there. Switch simulator stack limit here. - UseScratchRegisterScope temps{this}; - temps.Exclude(x16); - LoadStackLimit(x16, StackLimitKind::kRealStackLimit); - hlt(kImmExceptionIsSwitchStackLimit); - } - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -573,7 +521,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { MemOperand src{src_addr, offset}; LoadTrustedPointerField(dst, src, tag); } @@ -811,7 +759,9 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, UseScratchRegisterScope temps(this); MemOperand dst_op = liftoff::GetMemOp(this, &temps, dst_addr, offset_reg, offset_imm, i64_offset); - DCHECK(!dst_op.IsPostIndex()); // See MacroAssembler::LoadStoreMacroComplex. + // Post-index with a large offset emits `add` after the store, breaking + // `GetTrappingInstruction` (see `MacroAssembler::LoadStoreMacroComplex`). + DCHECK(!dst_op.IsPostIndex()); GetTrappingInstruction<LoadOrStore::kStore> collect_trapping_store( this, trapping_store_pc); switch (type.value()) { @@ -851,6 +801,42 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, } } +void LiftoffAssembler::StoreConst(Register dst_addr, Register offset_reg, + uintptr_t offset_imm, int32_t value, + StoreType type, uint32_t* trapping_store_pc, + bool i64_offset) { + DCHECK_EQ(0, value); + UseScratchRegisterScope temps(this); + MemOperand dst_op = liftoff::GetMemOp(this, &temps, dst_addr, offset_reg, + offset_imm, i64_offset); + // Post-index with a large offset emits `add` after the store, breaking + // `GetTrappingInstruction` (see `MacroAssembler::LoadStoreMacroComplex`). + DCHECK(!dst_op.IsPostIndex()); + GetTrappingInstruction<LoadOrStore::kStore> collect_trapping_store( + this, trapping_store_pc); + switch (type.value()) { + case StoreType::kI32Store8: + case StoreType::kI64Store8: + Strb(wzr, dst_op); + break; + case StoreType::kI32Store16: + case StoreType::kI64Store16: + Strh(wzr, dst_op); + break; + case StoreType::kI32Store: + case StoreType::kI64Store32: + case StoreType::kF32Store: + Str(wzr, dst_op); + break; + case StoreType::kI64Store: + case StoreType::kF64Store: + Str(xzr, dst_op); + break; + default: + UNREACHABLE(); + } +} + namespace liftoff { #define __ lasm-> @@ -1502,10 +1488,9 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = (caller_slot_idx + 1) * LiftoffAssembler::kStackSlotSize; - Str(liftoff::GetRegFromType(src, kind), MemOperand(frame_pointer, offset)); + Str(liftoff::GetRegFromType(src, kind), MemOperand(fp, offset)); } void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, @@ -1557,23 +1542,32 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { CPURegister src = CPURegister::no_reg(); switch (value.type().kind()) { case kI32: - if (value.to_i32() == 0) { + case kF32: { + int32_t val32 = value.type().kind() == kI32 + ? value.to_i32() + : value.to_f32_boxed().get_bits(); + if (val32 == 0) { src = wzr; } else { src = temps.AcquireW(); - Mov(src.W(), value.to_i32()); + Mov(src.W(), val32); } break; + } case kI64: - if (value.to_i64() == 0) { + case kF64: { + int64_t val64 = value.type().kind() == kI64 + ? value.to_i64() + : value.to_f64_boxed().get_bits(); + if (val64 == 0) { src = xzr; } else { src = temps.AcquireX(); - Mov(src.X(), value.to_i64()); + Mov(src.X(), val64); } break; + } default: - // We do not track f32 and f64 constants, hence they are unreachable. UNREACHABLE(); } Str(src, dst); @@ -4677,19 +4671,21 @@ void LiftoffStackSlots::Construct(int param_slots) { asm_->Poke(liftoff::GetRegFromType(slot.src_.reg(), slot.src_.kind()), poke_offset); break; - case LiftoffAssembler::VarState::kIntConst: - DCHECK(slot.src_.kind() == kI32 || slot.src_.kind() == kI64); + case LiftoffAssembler::VarState::kIntConst: { + ValueKind kind = slot.src_.kind(); + DCHECK(kind == kI32 || kind == kI64 || kind == kF32 || kind == kF64); + bool is_32bit = kind == kI32 || kind == kF32; if (slot.src_.i32_const() == 0) { - Register zero_reg = slot.src_.kind() == kI32 ? wzr : xzr; + Register zero_reg = is_32bit ? wzr : xzr; asm_->Poke(zero_reg, poke_offset); } else { UseScratchRegisterScope temps(asm_); - Register scratch = - slot.src_.kind() == kI32 ? temps.AcquireW() : temps.AcquireX(); + Register scratch = is_32bit ? temps.AcquireW() : temps.AcquireX(); asm_->Mov(scratch, int64_t{slot.src_.i32_const()}); asm_->Poke(scratch, poke_offset); } break; + } } } } diff --git a/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32-inl.h b/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32-inl.h index edcbbd074f78..34d6b28b37a4 100644 --- a/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32-inl.h +++ b/deps/v8/src/wasm/baseline/ia32/liftoff-assembler-ia32-inl.h @@ -272,7 +272,8 @@ void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. @@ -344,6 +345,8 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); @@ -352,8 +355,11 @@ void LiftoffAssembler::PatchPrepareStackFrame( mov(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), ebp); add(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), Immediate(static_cast<int32_t>( - stack_param_slots * kSystemPointerSize + + (stack_param_slots + stack_return_slots) * kSystemPointerSize + CommonFrameConstants::kFixedFrameSizeAboveFp))); + mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Immediate( + static_cast<int32_t>(stack_param_slots * kSystemPointerSize))); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -418,55 +424,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, j(negative, ool_label); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return ebp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - cmp(MemOperand(ebp, TypedFrameConstants::kFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - j(equal, &call_runtime); - mov(old_fp.gp(), ebp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - PrepareCallCFunction(1, eax); - MacroAssembler::Move(Operand(esp, 0 * kSystemPointerSize), - Immediate(ExternalReference::isolate_address())); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - mov(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - cmp(MemOperand(ebp, TypedFrameConstants::kFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - Label done; - j(not_equal, &done); - PushRegisters(regs_to_save); - PrepareCallCFunction(1, kReturnRegister0); - MacroAssembler::Move(Operand(esp, 0 * kSystemPointerSize), - Immediate(ExternalReference::isolate_address())); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old ebp. We don't need to restore old esp explicitly, because - // it will be restored from ebp in LeaveFrame before return. - mov(ebp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -499,7 +456,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { static_assert(!V8_ENABLE_SANDBOX_BOOL); static_assert(!COMPRESS_POINTERS_BOOL); mov(dst, Operand{src_addr, offset}); @@ -1475,10 +1432,9 @@ void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister reg, int offset, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { - liftoff::Store(this, frame_pointer, - kSystemPointerSize * (caller_slot_idx + 1), src, kind); + ValueKind kind) { + liftoff::Store(this, ebp, kSystemPointerSize * (caller_slot_idx + 1), src, + kind); } void LiftoffAssembler::MoveStackValue(uint32_t dst_offset, uint32_t src_offset, @@ -1559,15 +1515,21 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { case kI32: mov(dst, Immediate(value.to_i32())); break; - case kI64: { - int32_t low_word = value.to_i64(); - int32_t high_word = value.to_i64() >> 32; + case kF32: + mov(dst, Immediate(value.to_f32_boxed().get_bits())); + break; + case kI64: + case kF64: { + int64_t val64 = value.type().kind() == kI64 + ? value.to_i64() + : value.to_f64_boxed().get_bits(); + int32_t low_word = static_cast<int32_t>(val64); + int32_t high_word = static_cast<int32_t>(val64 >> 32); mov(liftoff::GetHalfStackSlot(offset, kLowWord), Immediate(low_word)); mov(liftoff::GetHalfStackSlot(offset, kHighWord), Immediate(high_word)); break; } default: - // We do not track f32 and f64 constants, hence they are unreachable. UNREACHABLE(); } } @@ -5388,6 +5350,12 @@ void LiftoffStackSlots::Construct(int param_slots) { } break; case LiftoffAssembler::VarState::kIntConst: + if (src.kind() == kF64) { + asm_->AllocateStackSpace(stack_decrement - kDoubleSize); + DCHECK_EQ(kLowWord, slot.half_); + asm_->push(Immediate(src.i32_const() >> 31)); + stack_decrement = kSystemPointerSize; + } asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); // The high word is the sign extension of the low word. asm_->push(Immediate(slot.half_ == kLowWord ? src.i32_const() diff --git a/deps/v8/src/wasm/baseline/liftoff-assembler-inl.h b/deps/v8/src/wasm/baseline/liftoff-assembler-inl.h index 4cbc6d8b14b4..ae239d5ea1af 100644 --- a/deps/v8/src/wasm/baseline/liftoff-assembler-inl.h +++ b/deps/v8/src/wasm/baseline/liftoff-assembler-inl.h @@ -71,7 +71,7 @@ void LiftoffAssembler::PushException() { } void LiftoffAssembler::PushConstant(ValueKind kind, int32_t i32_const) { - V8_ASSUME(kind == kI32 || kind == kI64); + V8_ASSUME(kind == kI32 || kind == kI64 || kind == kF32 || kind == kF64); cache_state_.stack_state.emplace_back(kind, i32_const, NextSpillOffset(kind)); } diff --git a/deps/v8/src/wasm/baseline/liftoff-assembler.cc b/deps/v8/src/wasm/baseline/liftoff-assembler.cc index e126367d9f62..f2a2210fbae0 100644 --- a/deps/v8/src/wasm/baseline/liftoff-assembler.cc +++ b/deps/v8/src/wasm/baseline/liftoff-assembler.cc @@ -985,10 +985,6 @@ void LiftoffAssembler::MoveToReturnLocationsMultiReturn( DCHECK_LE(sig->return_count(), cache_state_.stack_height()); VarState* slots = cache_state_.stack_state.end() - sig->return_count(); LiftoffRegList pinned; - Register old_fp = LoadOldFramePointer(); - if (v8_flags.wasm_growable_stacks) { - pinned.set(LiftoffRegister(old_fp)); - } // Fill return frame slots first to ensure that all potential spills happen // before we prepare the stack transfers. for (size_t i = 0; i < sig->return_count(); ++i) { @@ -1005,8 +1001,7 @@ void LiftoffAssembler::MoveToReturnLocationsMultiReturn( ? LoadI64HalfIntoRegister(slot, half, pinned) : LoadToRegister(slot, pinned); ValueKind lowered_kind = needs_gp_pair ? kI32 : return_kind; - StoreCallerFrameSlot(reg, -loc.AsCallerFrameSlot(), lowered_kind, - old_fp); + StoreCallerFrameSlot(reg, -loc.AsCallerFrameSlot(), lowered_kind); } } } diff --git a/deps/v8/src/wasm/baseline/liftoff-assembler.h b/deps/v8/src/wasm/baseline/liftoff-assembler.h index 3443ca9f6702..2c05bb5eb21f 100644 --- a/deps/v8/src/wasm/baseline/liftoff-assembler.h +++ b/deps/v8/src/wasm/baseline/liftoff-assembler.h @@ -107,13 +107,18 @@ class LiftoffAssembler : public MacroAssembler { // A tagged value known to be a Smi can be treated like a ptr-sized int. static constexpr ValueKind kSmiKind = kTaggedSize == kInt32Size ? kI32 : kI64; - // Whether {StoreConst} is implemented, i.e. whether integer constants can be - // stored to memory as immediates. + // Whether {StoreConst} is supported for the given store type and constant + // value. + static constexpr bool CanStoreConst(StoreType type, int32_t value) { + if (type.value() == StoreType::kF32StoreF16) return false; #if V8_TARGET_ARCH_X64 - static constexpr bool kSupportsStoreConst = true; + return true; +#elif V8_TARGET_ARCH_ARM64 + return value == 0; #else - static constexpr bool kSupportsStoreConst = false; + return false; #endif + } using ValueKindSig = Signature<ValueKind>; @@ -697,7 +702,8 @@ class LiftoffAssembler : public MacroAssembler { inline void AlignFrameSize(); inline void PatchPrepareStackFrame(int offset, SafepointTableBuilder*, bool feedback_vector_slot, - size_t stack_param_slots); + size_t stack_param_slots, + size_t stack_return_slots); inline void FinishCode(); inline void AbortCompilation(); inline static constexpr int StaticStackFrameSize(); @@ -706,8 +712,6 @@ class LiftoffAssembler : public MacroAssembler { inline void CheckTierUp(int declared_func_index, int budget_used, Label* ool_label, const FreezeCacheState& frozen); - inline Register LoadOldFramePointer(); - inline void CheckStackShrink(); inline void LoadConstant(LiftoffRegister, WasmValue); inline void PrepareDebugTrap(MessageTemplate message); @@ -719,7 +723,7 @@ class LiftoffAssembler : public MacroAssembler { Register mem_start, bool reload_mem_start, int mem_index); inline void LoadTrustedPointer(Register dst, Register src_addr, int offset, - IndirectPointerTag tag); + TrustedPointerTag tag); inline void LoadFromInstance(Register dst, Register instance, int offset, int size); inline void LoadTaggedPointerFromInstance(Register dst, Register instance, @@ -778,10 +782,10 @@ class LiftoffAssembler : public MacroAssembler { LiftoffRegList pinned, uint32_t* trapping_store_pc = nullptr, bool is_store_mem = false, bool i64_offset = false); - // Store the integer constant {value} (sign-extended for i64 stores) as an - // immediate. Only implemented on architectures with an immediate store form; - // see {kSupportsStoreConst}. -#if V8_TARGET_ARCH_X64 + // Store the integer or float constant {value} (sign-extended for 64-bit + // stores) as an immediate. Only implemented on architectures where + // {CanStoreConst} can return true. +#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 inline void StoreConst(Register dst_addr, Register offset_reg, uintptr_t offset_imm, int32_t value, StoreType type, uint32_t* trapping_store_pc, bool i64_offset); @@ -863,7 +867,7 @@ class LiftoffAssembler : public MacroAssembler { inline void LoadCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx, ValueKind); inline void StoreCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx, - ValueKind, Register frame_pointer); + ValueKind); inline void LoadReturnStackSlot(LiftoffRegister, int offset, ValueKind); inline void MoveStackValue(uint32_t dst_offset, uint32_t src_offset, ValueKind); @@ -1684,7 +1688,7 @@ class LiftoffAssembler : public MacroAssembler { void set_num_locals(uint32_t num_locals); int GetTotalFrameSlotCountForGC() const; - int OolSpillCount() const; + V8_EXPORT_PRIVATE int OolSpillCount() const; int GetTotalFrameSize() const { return max_used_spill_offset_; } diff --git a/deps/v8/src/wasm/baseline/liftoff-compiler.cc b/deps/v8/src/wasm/baseline/liftoff-compiler.cc index 8c8c46a46707..81f43cd1f466 100644 --- a/deps/v8/src/wasm/baseline/liftoff-compiler.cc +++ b/deps/v8/src/wasm/baseline/liftoff-compiler.cc @@ -4,9 +4,11 @@ #include "src/wasm/baseline/liftoff-compiler.h" +#include <array> #include <optional> #include "src/base/enum-set.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" // TODO(clemensb): Remove dependences on compiler stuff. #include "src/codegen/external-reference.h" @@ -634,17 +636,18 @@ class PrototypeSetupSequenceDetector : public Decoder { if (!module_->has_array(actual_type)) return false; if (module_->canonical_type_id(actual_type) != type) return false; uint32_t segment_index = consume_u32v(kNoTrace); - uint32_t segment_length; ValueType element_type = module_->array_type(actual_type)->element_type(); if (element_type.is_ref()) { if (segment_index >= module_->elem_segments.size()) return false; - segment_length = module_->elem_segments[segment_index].element_count; + uint32_t segment_length = + module_->elem_segments[segment_index].element_count; + if (start > segment_length) return false; + if (length > segment_length - start) return false; } else { - if (segment_index >= module_->data_segments.size()) return false; - segment_length = module_->data_segments[segment_index].source.length(); + if (segment_index >= module_->num_declared_data_segments) return false; + // We can't inspect the segment yet, because it comes after the code + // section and we might be streaming. } - if (start > segment_length) return false; - if (length > segment_length - start) return false; if (length > static_cast<uint32_t>( WasmArray::MaxLength(element_type.value_kind_size()))) { return false; @@ -899,7 +902,8 @@ class LiftoffCompiler { safepoint_table_builder_(zone_), next_breakpoint_ptr_(options.breakpoints.begin()), next_breakpoint_end_(options.breakpoints.end()), - dead_breakpoint_(options.dead_breakpoint), + next_dead_breakpoint_ptr_(options.dead_breakpoints.begin()), + next_dead_breakpoint_end_(options.dead_breakpoints.end()), handlers_(zone), max_steps_(options.max_steps), deopt_info_bytecode_offset_(options.deopt_info_bytecode_offset), @@ -916,6 +920,9 @@ class LiftoffCompiler { DCHECK_IMPLIES( next_breakpoint_ptr_ == next_breakpoint_end_, next_breakpoint_ptr_ == nullptr && next_breakpoint_end_ == nullptr); + DCHECK_IMPLIES(next_dead_breakpoint_ptr_ == next_dead_breakpoint_end_, + next_dead_breakpoint_ptr_ == nullptr && + next_dead_breakpoint_end_ == nullptr); DCHECK_IMPLIES(!for_debugging_, debug_sidetable_builder_ == nullptr); if (v8_flags.wasm_code_coverage) { @@ -942,12 +949,12 @@ class LiftoffCompiler { return std::move(frame_description_); } - base::OwnedVector<uint8_t> GetSourcePositionTable() { + base::UniqueArray<uint8_t> GetSourcePositionTable() { return source_position_table_builder_.ToSourcePositionTableVector(); } - base::OwnedVector<uint8_t> GetTrappingInstructionsData() const { - return base::OwnedCopyOf(base::Vector<const uint8_t>::cast( + base::UniqueArray<uint8_t> GetTrappingInstructionsData() const { + return base::UniqueCopyOf(base::Vector<const uint8_t>::cast( base::VectorOf(trapping_instructions_))); } @@ -998,9 +1005,9 @@ class LiftoffCompiler { default: UNREACHABLE(); } - base::EmbeddedVector<char, 128> buffer; - SNPrintF(buffer, "%s %s", name(kind), context); - unsupported(decoder, bailout_reason, buffer.begin()); + std::array<char, 128> buffer; + base::SNPrintF(buffer, "%s %s", name(kind), context); + unsupported(decoder, bailout_reason, buffer.data()); return false; } @@ -1238,12 +1245,14 @@ class LiftoffCompiler { // having to spill them on merge points. Use of these initial values should // be rare anyway. if (actual_locals > kNumCacheRegisters / 2) return true; - // If there are locals which are not i32 or i64, we also spill all locals, - // because other types cannot be initialized to constants. + // If there are locals which are not i32, i64, f32, or f64, we also spill + // all locals, because other types cannot be initialized to constants. for (uint32_t param_idx = num_params; param_idx < __ num_locals(); ++param_idx) { ValueKind kind = __ local_kind(param_idx); - if (kind != kI32 && kind != kI64) return true; + if (kind != kI32 && kind != kI64 && kind != kF32 && kind != kF64) { + return true; + } } return false; } @@ -1352,8 +1361,8 @@ class LiftoffCompiler { for (uint32_t param_idx = num_params; param_idx < __ num_locals(); ++param_idx) { ValueKind kind = __ local_kind(param_idx); - // Anything which is not i32 or i64 requires spilling. - DCHECK(kind == kI32 || kind == kI64); + // Anything which is not i32, i64, f32, or f64 requires spilling. + DCHECK(kind == kI32 || kind == kI64 || kind == kF32 || kind == kF64); __ PushConstant(kind, int32_t{0}); } } @@ -1444,13 +1453,18 @@ class LiftoffCompiler { if (ool->builtin == Builtin::kWasmGrowableStackGuard) { WasmGrowableStackGuardDescriptor descriptor; DCHECK_EQ(0, descriptor.GetStackParameterCount()); - DCHECK_EQ(2, descriptor.GetRegisterParameterCount()); + DCHECK_EQ(3, descriptor.GetRegisterParameterCount()); Register param_reg0 = descriptor.GetRegisterParameter(0); Register param_reg1 = descriptor.GetRegisterParameter(1); + Register param_reg2 = descriptor.GetRegisterParameter(2); __ LoadConstant(LiftoffRegister(param_reg0), - WasmValue::ForUintPtr(descriptor_->ParameterSlotCount() * + WasmValue::ForUintPtr((descriptor_->ParameterSlotCount() + + descriptor_->ReturnSlotCount()) * kSystemPointerSize)); __ LoadConstant(LiftoffRegister(param_reg1), WasmValue::ForUintPtr(0)); + __ LoadConstant(LiftoffRegister(param_reg2), + WasmValue::ForUintPtr(descriptor_->ParameterSlotCount() * + kSystemPointerSize)); } else if (ool->builtin == Builtin::kWasmStackGuard) { WasmStackGuardDescriptor descriptor; DCHECK_EQ(0, descriptor.GetStackParameterCount()); @@ -1461,13 +1475,14 @@ class LiftoffCompiler { Builtin builtin = ool->builtin; if (V8_UNLIKELY(for_debugging_)) { - // In debug mode, we handle traps by calling the kWasmDebugTrap builtin - // instead of the specific trap-throwing builtin. This allows the debugger - // to inspect all registers at the trap site. + // In debug mode, we handle traps by calling the + // kWasmTrapHandlerThrowTrap builtin instead of the specific + // trap-throwing builtin. This allows the debugger to inspect all + // registers at the trap site. std::optional<MessageTemplate> message = GetMessageTemplateForBuiltin(builtin); if (message) { - builtin = Builtin::kWasmDebugTrap; + builtin = Builtin::kWasmTrapHandlerThrowTrap; __ PrepareDebugTrap(*message); } } @@ -1476,8 +1491,6 @@ class LiftoffCompiler { __ pc_offset(), SourcePosition(ool->position), true); __ CallBuiltin(builtin); auto pc_offset_after_call = __ pc_offset_for_safepoint(); - // It is safe to not check for existing safepoint at this address since we - // just emitted a call. auto safepoint = safepoint_table_builder_.DefineSafepoint(&asm_); if (ool->safepoint_info) { for (auto index : ool->safepoint_info->slots) { @@ -1489,7 +1502,7 @@ class LiftoffCompiler { // so that the GC can scan them (similar to // `DefineSafepointWithCalleeSavedRegisters` in `EmitBreakpoint`, used for // the WasmDebugBreak builtin). - if (builtin == Builtin::kWasmDebugTrap) { + if (builtin == Builtin::kWasmTrapHandlerThrowTrap) { for (auto reg : ool->safepoint_info->spills.GetGpList()) { safepoint.DefineTaggedRegister(reg.code()); } @@ -1576,7 +1589,8 @@ class LiftoffCompiler { DCHECK_EQ(frame_size, __ GetTotalFrameSize()); __ PatchPrepareStackFrame(pc_offset_stack_frame_construction_, &safepoint_table_builder_, v8_flags.wasm_inlining, - descriptor_->ParameterSlotCount()); + descriptor_->ParameterSlotCount(), + descriptor_->ReturnSlotCount()); __ FinishCode(); safepoint_table_builder_.Emit(&asm_, __ GetTotalFrameSlotCountForGC()); // Emit the handler table. @@ -1591,6 +1605,7 @@ class LiftoffCompiler { // The previous calls may have also generated a bailout. DidAssemblerBailout(decoder); DCHECK_EQ(num_exceptions_, 0); + DCHECK_NULL(next_dead_breakpoint_ptr_); if (v8_flags.wasm_inlining && !encountered_call_instructions_.empty()) { // Update the call targets stored in the WasmModule. @@ -1599,13 +1614,12 @@ class LiftoffCompiler { FunctionTypeFeedback& function_feedback = type_feedback.feedback_for_function[func_index_]; function_feedback.liftoff_frame_size = __ GetTotalFrameSize(); - base::OwnedVector<uint32_t>& call_targets = + base::UniqueArray<uint32_t>& call_targets = function_feedback.call_targets; if (call_targets.empty()) { - call_targets = base::OwnedCopyOf(encountered_call_instructions_); + call_targets = base::UniqueCopyOf(encountered_call_instructions_); } else { - DCHECK_EQ(call_targets.as_vector(), - base::VectorOf(encountered_call_instructions_)); + DCHECK_EQ(call_targets, base::VectorOf(encountered_call_instructions_)); } } @@ -1758,16 +1772,26 @@ class LiftoffCompiler { } } + bool has_dead_breakpoint = false; + if (next_dead_breakpoint_ptr_) { + DCHECK_LE(decoder->position(), *next_dead_breakpoint_ptr_); + if (*next_dead_breakpoint_ptr_ == decoder->position()) { + DCHECK(!has_breakpoint); + has_dead_breakpoint = true; + if (++next_dead_breakpoint_ptr_ == next_dead_breakpoint_end_) { + next_dead_breakpoint_ptr_ = next_dead_breakpoint_end_ = nullptr; + } + } + } + if (has_breakpoint) { CODE_COMMENT("breakpoint"); EmitBreakpoint(decoder); - } else if (dead_breakpoint_ == decoder->position()) { - DCHECK(!next_breakpoint_ptr_ || - *next_breakpoint_ptr_ != dead_breakpoint_); - // The top frame is paused at this position, but the breakpoint was - // removed. Adding a dead breakpoint here ensures that the source - // position exists, and that the offset to the return address is the - // same as in the old code. + } else if (has_dead_breakpoint) { + // A frame is paused at this position, but the breakpoint was removed. + // Adding a dead breakpoint here ensures that the source position exists, + // and that the offset to the return address is the same as in the old + // code. CODE_COMMENT("dead breakpoint"); Label cont; __ emit_jump(&cont); @@ -1835,8 +1859,12 @@ class LiftoffCompiler { // Before entering a loop, spill all locals to the stack, in order to free // the cache registers, and to avoid unnecessarily reloading stack values // into registers at branches. - // TODO(clemensb): Come up with a better strategy here, involving - // pre-analysis of the function. + // + // Note: We experimented with implementing better strategies here, involving + // pre-analysis of the function, to eliminate redundant per-iteration + // reloads of loop-invariant locals. But the added complexity did not + // significantly improve performance; the current strategy works well enough + // and a pre-pass is not worth it. __ SpillLocals(); __ SpillLoopArgs(loop->start_merge.arity); @@ -2212,7 +2240,7 @@ class LiftoffCompiler { // There is an extra copy of the exception at this point, below the unpacked // values (if any). It will be dropped in the branch below. BrOrRet(decoder, catch_case.br_imm.depth); - bool is_last = &catch_case == &block->catch_cases.last(); + bool is_last = &catch_case == &block->catch_cases.back(); if (is_last && !decoder->HasCatchAll(block)) { __ bind(&block->try_info->catch_label); __ cache_state()->Steal(block->try_info->catch_state); @@ -2226,10 +2254,12 @@ class LiftoffCompiler { CallBuiltin(Builtin::kWasmThrowRef, MakeSig::Params(kRef), {exn}, decoder->position()); int pc_offset = __ pc_offset_for_safepoint(); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); MaybeOSR(); EmitLandingPad(decoder, pc_offset); } + // LINT.IfChange void ContNew(FullDecoder* decoder, const ContIndexImmediate& imm, const Value& func_ref, Value* result) { // Use UNIMPLEMENTED under --liftoff-only to avoid spurious fuzzer reports. @@ -2241,6 +2271,7 @@ class LiftoffCompiler { "unimplemented Liftoff instruction: cont.new"); } } + // LINT.ThenChange(/test/mjsunit/wasm/compilation-hints/hints-and-deopts.js) void ContBind(FullDecoder* decoder, const ContIndexImmediate& orig_imm, Value input_cont, const Value args[], @@ -2814,23 +2845,17 @@ class LiftoffCompiler { MakeSig::Returns(kRefNull).Params(kRefNull), {input_state}, decoder->position()); __ DropValues(1); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); __ PushRegister(kRef, LiftoffRegister(kReturnRegister0)); return; } case kExprExternConvertAny: { - LiftoffRegList pinned; - LiftoffRegister ref = pinned.set(__ PopToModifiableRegister(pinned)); - LiftoffRegister null = __ GetUnusedRegister(kGpReg, pinned); - LoadNullValueForCompare(null.gp(), pinned, kWasmAnyRef); - Label label; - { - FREEZE_STATE(frozen); - __ emit_cond_jump(kNotEqual, &label, kRefNull, ref.gp(), null.gp(), - frozen); - LoadNullValue(ref.gp(), kWasmExternRef); - __ bind(&label); - } - __ PushRegister(kRefNull, ref); + VarState input_state = __ cache_state() -> stack_state.back(); + CallBuiltin(Builtin::kWasmExternConvertAny, + MakeSig::Returns(kRefNull).Params(kRefNull), {input_state}, + decoder->position()); + __ DropValues(1); + __ PushRegister(kRef, LiftoffRegister(kReturnRegister0)); return; } default: @@ -3454,15 +3479,19 @@ class LiftoffCompiler { } void F32Const(FullDecoder* decoder, Value* result, float value) { - LiftoffRegister reg = __ GetUnusedRegister(kFpReg, {}); - __ LoadConstant(reg, WasmValue(value)); - __ PushRegister(kF32, reg); + __ PushConstant(kF32, base::bit_cast<int32_t>(value)); } void F64Const(FullDecoder* decoder, Value* result, double value) { - LiftoffRegister reg = __ GetUnusedRegister(kFpReg, {}); - __ LoadConstant(reg, WasmValue(value)); - __ PushRegister(kF64, reg); + int64_t value_bits = base::bit_cast<int64_t>(value); + int32_t value_i32 = static_cast<int32_t>(value_bits); + if (value_i32 == value_bits) { + __ PushConstant(kF64, value_i32); + } else { + LiftoffRegister reg = __ GetUnusedRegister(kFpReg, {}); + __ LoadConstant(reg, WasmValue(value)); + __ PushRegister(kF64, reg); + } } void RefNull(FullDecoder* decoder, ValueType type, Value*) { @@ -3502,7 +3531,8 @@ class LiftoffCompiler { } else if (!v8_flags.wasm_skip_null_checks) { // Otherwise, load the word after the map word. static_assert(WasmStruct::kHeaderSize > kTaggedSize); - static_assert(WasmArray::kHeaderSize > kTaggedSize); + static_assert(WasmCustomMap::kHeaderSize > kTaggedSize); + static_assert(WasmArray::HeaderSize(SharedFlag{false}) > kTaggedSize); static_assert(WasmInternalFunction::kHeaderSize > kTaggedSize); LiftoffRegister dst = pinned.set(__ GetUnusedRegister(kGpReg, pinned)); uint32_t trapping_load_pc = 0; @@ -3601,9 +3631,6 @@ class LiftoffCompiler { } size_t num_returns = decoder->sig_->return_count(); if (num_returns > 0) __ MoveToReturnLocations(decoder->sig_, descriptor_); - if (v8_flags.wasm_growable_stacks) { - __ CheckStackShrink(); - } __ LeaveFrame(StackFrame::WASM); __ DropStackSlotsAndRet( static_cast<uint32_t>(descriptor_->ParameterSlotCount())); @@ -4262,8 +4289,8 @@ class LiftoffCompiler { // TODO(13957): Clamp the loaded memory size to a safe value. if (memory->index == 0) { - LOAD_INSTANCE_FIELD(mem_size.gp(), Memory0Size, kSystemPointerSize, - pinned); + LOAD_INSTANCE_FIELD(mem_size.gp(), Memory0SizeOrAddress, + kSystemPointerSize, pinned); } else { LOAD_PROTECTED_PTR_INSTANCE_FIELD(mem_size.gp(), MemoryBasesAndSizes, pinned); @@ -4271,6 +4298,10 @@ class LiftoffCompiler { kSystemPointerSize * (memory->index * 2 + 1); __ LoadFullPointer(mem_size.gp(), mem_size.gp(), buffer_offset); } + if (memory->is_shared) { + // mem_size holds the address of the atomic byte_length_; dereference it. + __ LoadFullPointer(mem_size.gp(), mem_size.gp(), 0); + } // {for_debugging_} needs spill slots in out of line code. OolTrapLabel trap = @@ -4601,13 +4632,7 @@ class LiftoffCompiler { &trapping_load_pc, i64_offset); if (imm.memory->bounds_checks == kTrapHandler) { - trapping_instructions_.emplace_back( - trap_handler::TrappingInstructionData{trapping_load_pc}); - source_position_table_builder_.AddPosition( - trapping_load_pc, SourcePosition(decoder->position()), true); - if (for_debugging_) { - DefineSafepoint(trapping_load_pc); - } + RegisterTrappingInstruction(decoder, trapping_load_pc); } __ PushRegister(kS128, value); @@ -4648,13 +4673,7 @@ class LiftoffCompiler { __ LoadLane(result, value, addr, index, offset, type, laneidx, &trapping_load_pc, i64_offset); if (imm.memory->bounds_checks == kTrapHandler) { - trapping_instructions_.emplace_back( - trap_handler::TrappingInstructionData{trapping_load_pc}); - source_position_table_builder_.AddPosition( - trapping_load_pc, SourcePosition(decoder->position()), true); - if (for_debugging_) { - DefineSafepoint(trapping_load_pc); - } + RegisterTrappingInstruction(decoder, trapping_load_pc); } __ PushRegister(kS128, result); @@ -4674,12 +4693,12 @@ class LiftoffCompiler { if (!CheckSupportedType(decoder, kind, "store")) return; LiftoffRegList pinned; - // Where the architecture has an immediate store form, store an integer - // constant directly instead of materializing it in a register first. Only - // i32 and i64 values are ever constant in the cache state, and Liftoff - // keeps i64 constants as sign-extended 32-bit values. + // Where the architecture has an immediate store form, store an integer or + // float constant directly instead of materializing it in a register first. + // Liftoff keeps 64-bit constants as sign-extended 32-bit values. VarState value = __ PopVarState(); - if (!LiftoffAssembler::kSupportsStoreConst || !value.is_const()) { + if (!value.is_const() || + !LiftoffAssembler::CanStoreConst(type, value.i32_const())) { LiftoffRegister reg = pinned.set(__ LoadToRegister(value, pinned)); value.MakeRegister(reg); } @@ -4687,8 +4706,8 @@ class LiftoffCompiler { if (type.value() == StoreType::kF32StoreF16 && !asm_.supports_f16_mem_access()) { type = StoreType::kI32Store16; - // {value} is always a float, so it is never a constant and cannot - // alias with {i16}. + // {value} was loaded into an FP register above, so it cannot alias with + // {i16}. DCHECK_EQ(kF32, kind); DCHECK(value.is_reg()); LiftoffRegister i16 = pinned.set(__ GetUnusedRegister(kGpReg, {})); @@ -4778,13 +4797,7 @@ class LiftoffCompiler { __ StoreLane(addr, index, offset, value, type, lane, &trapping_store_pc, i64_offset); if (imm.memory->bounds_checks == kTrapHandler) { - trapping_instructions_.emplace_back( - trap_handler::TrappingInstructionData{trapping_store_pc}); - source_position_table_builder_.AddPosition( - trapping_store_pc, SourcePosition(decoder->position()), true); - if (for_debugging_) { - DefineSafepoint(trapping_store_pc); - } + RegisterTrappingInstruction(decoder, trapping_store_pc); } if (V8_UNLIKELY(v8_flags.trace_wasm_memory)) { TraceMemoryOperation(true, imm.mem_index, type.mem_rep(), index, offset, @@ -4798,8 +4811,8 @@ class LiftoffCompiler { LiftoffRegList pinned; LiftoffRegister mem_size = pinned.set(__ GetUnusedRegister(kGpReg, pinned)); if (imm.index == 0) { - LOAD_INSTANCE_FIELD(mem_size.gp(), Memory0Size, kSystemPointerSize, - pinned); + LOAD_INSTANCE_FIELD(mem_size.gp(), Memory0SizeOrAddress, + kSystemPointerSize, pinned); } else { LOAD_PROTECTED_PTR_INSTANCE_FIELD(mem_size.gp(), MemoryBasesAndSizes, pinned); @@ -4807,6 +4820,15 @@ class LiftoffCompiler { kSystemPointerSize * (imm.index * 2 + 1); __ LoadFullPointer(mem_size.gp(), mem_size.gp(), buffer_offset); } + if (imm.memory->is_shared) { + // The Wasm spec requires memory.size to be atomic seq_cst for shared + // memory. mem_size holds the address of BackingStore::byte_length_. + LoadType load_type = + kSystemPointerSize == 8 ? LoadType::kI64Load : LoadType::kI32Load; + __ AtomicLoad(mem_size, mem_size.gp(), no_reg, 0, load_type, nullptr, + AtomicMemoryOrder::kSeqCst, pinned, false, + LiftoffAssembler::kNative); + } // Convert bytes to pages. __ emit_ptrsize_shri(mem_size.gp(), mem_size.gp(), kWasmPageSizeLog2); if (imm.memory->is_memory64() && kNeedI64RegPair) { @@ -4892,11 +4914,11 @@ class LiftoffCompiler { } } - base::OwnedVector<ValueType> GetStackValueTypesForDebugging( + base::UniqueArray<ValueType> GetStackValueTypesForDebugging( FullDecoder* decoder) { DCHECK(for_debugging_); auto stack_value_types = - base::OwnedVector<ValueType>::NewForOverwrite(decoder->stack_size()); + base::UniqueArray<ValueType>::NewForOverwrite(decoder->stack_size()); int depth = 0; for (ValueType& type : base::Reversed(stack_value_types)) { @@ -4905,7 +4927,7 @@ class LiftoffCompiler { return stack_value_types; } - base::OwnedVector<DebugSideTable::Entry::Value> + base::UniqueArray<DebugSideTable::Entry::Value> GetCurrentDebugSideTableEntries( FullDecoder* decoder, DebugSideTableBuilder::AssumeSpilling assume_spilling) { @@ -4924,7 +4946,7 @@ class LiftoffCompiler { #endif auto values = - base::OwnedVector<DebugSideTable::Entry::Value>::NewForOverwrite( + base::UniqueArray<DebugSideTable::Entry::Value>::NewForOverwrite( stack_state.size()); int index = 0; @@ -4992,14 +5014,14 @@ class LiftoffCompiler { if (V8_LIKELY(!debug_sidetable_builder_)) return; debug_sidetable_builder_->NewEntry( __ pc_offset_for_safepoint(), - GetCurrentDebugSideTableEntries(decoder, assume_spilling).as_vector()); + GetCurrentDebugSideTableEntries(decoder, assume_spilling).as_span()); } DebugSideTableBuilder::EntryBuilder* RegisterOOLDebugSideTableEntry( FullDecoder* decoder, DebugSideTableBuilder::AssumeSpilling spilling) { if (V8_LIKELY(!debug_sidetable_builder_)) return nullptr; return debug_sidetable_builder_->NewOOLEntry( - GetCurrentDebugSideTableEntries(decoder, spilling).as_vector()); + GetCurrentDebugSideTableEntries(decoder, spilling).as_span()); } void CallDirect(FullDecoder* decoder, const CallFunctionImmediate& imm, @@ -6054,7 +6076,7 @@ class LiftoffCompiler { CASE_SIMD_REPLACE_LANE_OP(F64x2ReplaceLane, F64, f64x2_replace_lane) #undef CASE_SIMD_REPLACE_LANE_OP case wasm::kExprF16x8ReplaceLane: { - EmitSimdReplaceLaneOp<kI32>( + EmitSimdReplaceLaneOp<kF32>( [this](LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx) { if (asm_.emit_f16x8_replace_lane(dst, src1, src2, imm_lane_idx)) { @@ -7184,8 +7206,8 @@ class LiftoffCompiler { VarState waitqueue = __ PopVarState(); VarState struct_obj = __ PopVarState(); - int offset = WasmStruct::kHeaderSize + - imm.struct_imm.struct_type->field_offset(imm.field_imm.index); + int offset = WasmStruct::FieldOffset(imm.struct_imm.struct_type, + imm.field_imm.index); Builtin target = kind == kI32 ? Builtin::kWasmManagedObjectWait32 : kind == kI64 ? Builtin::kWasmManagedObjectWait64 : Builtin::kWasmManagedObjectWaitRef; @@ -7197,6 +7219,7 @@ class LiftoffCompiler { {struct_obj, VarState{kI32, offset, 0}, expected_value, waitqueue, timeout}, decoder->position()); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); __ PushRegister(kI32, LiftoffRegister{kReturnRegister0}); MaybeOSR(); } @@ -7254,7 +7277,8 @@ class LiftoffCompiler { int elem_size_shift = value_kind_size_log2(kind); DCHECK_NE(elem_size_shift, 0); __ emit_i32_shli(index.gp(), index.gp(), elem_size_shift); - __ emit_i32_addi(index.gp(), index.gp(), WasmArray::kHeaderSize); + __ emit_i32_addi(index.gp(), index.gp(), + WasmArray::HeaderSize(array_obj.type.is_shared())); Builtin target = kind == kI32 ? Builtin::kWasmManagedObjectWait32 : kind == kI64 ? Builtin::kWasmManagedObjectWait64 @@ -7267,6 +7291,7 @@ class LiftoffCompiler { {VarState{kRef, array, 0}, VarState{kI32, index, 0}, expected_value, waitqueue, timeout}, decoder->position()); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); __ PushRegister(kI32, LiftoffRegister{kReturnRegister0}); MaybeOSR(); } @@ -7318,6 +7343,9 @@ class LiftoffCompiler { __ emit_i32_shli(index.gp(), index.gp(), elem_size_shift); } + const int offset = + WasmArray::HeaderSize(imm.array_type->is_shared()) - kHeapObjectTag; + // Skip the non-atomic implementation special case on ia32 as it is not // needed (ia32 doesn't require any alignment for these operation) and there // are only painfully few registers available on ia32. @@ -7328,9 +7356,8 @@ class LiftoffCompiler { // operations. LiftoffRegister result_reg = pinned.set(__ GetUnusedRegister(reg_class_for(elem_kind), pinned)); - LoadObjectField(decoder, result_reg, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, elem_kind, true, - false, pinned); + LoadObjectField(decoder, result_reg, array.gp(), index.gp(), offset, + elem_kind, true, false, pinned); LiftoffRegister new_value = opcode == kExprArrayAtomicExchange ? value : pinned.set(__ GetUnusedRegister( @@ -7357,8 +7384,7 @@ class LiftoffCompiler { UNREACHABLE(); } __ PushRegister(elem_kind, result_reg); - StoreObjectField(decoder, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, new_value, + StoreObjectField(decoder, array.gp(), index.gp(), offset, new_value, false, pinned, elem_kind); return; } @@ -7377,7 +7403,6 @@ class LiftoffCompiler { LiftoffRegister result_reg = pinned.set(__ GetUnusedRegister(reg_class_for(elem_kind), pinned)); #endif - const int offset = WasmArray::kHeaderSize - kHeapObjectTag; switch (opcode) { case kExprArrayAtomicAdd: __ AtomicAdd(array.gp(), index.gp(), offset, value, result_reg, @@ -7427,6 +7452,8 @@ class LiftoffCompiler { const Value& expected_val, const Value& new_val, AtomicMemoryOrder order, Value* result) { + const int offset = + WasmArray::HeaderSize(imm.array_type->is_shared()) - kHeapObjectTag; #if V8_TARGET_ARCH_IA32 // This is an ia32-specific implementation that tries to use as few // registers as possible, so that it works with i64 values lowered to @@ -7468,7 +7495,6 @@ class LiftoffCompiler { __ DropValues(2); // index, array. LiftoffRegister result_reg = expected_value; - const int offset = WasmArray::kHeaderSize - kHeapObjectTag; if (is_reference(elem_kind)) { __ AtomicCompareExchangeTaggedPointer(mem_location.gp(), no_reg, offset, expected_value, new_value, @@ -7505,9 +7531,8 @@ class LiftoffCompiler { if (!array_obj.type.is_shared() && elem_kind == ValueKind::kI64) { LiftoffRegister result_reg = pinned.set(__ GetUnusedRegister(reg_class_for(elem_kind), pinned)); - LoadObjectField(decoder, result_reg, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, elem_kind, true, - false, pinned); + LoadObjectField(decoder, result_reg, array.gp(), index.gp(), offset, + elem_kind, true, false, pinned); { Label end; FREEZE_STATE(frozen); @@ -7522,8 +7547,7 @@ class LiftoffCompiler { __ emit_cond_jump(kNotEqual, &end, kI32, result_reg.low_gp(), expected_value.low_gp(), frozen); } - StoreObjectField(decoder, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, new_value, + StoreObjectField(decoder, array.gp(), index.gp(), offset, new_value, false, pinned, elem_kind); __ bind(&end); } @@ -7533,7 +7557,6 @@ class LiftoffCompiler { LiftoffRegister result_reg = pinned.set(__ GetUnusedRegister(reg_class_for(elem_kind), pinned)); - const int offset = WasmArray::kHeaderSize - kHeapObjectTag; Register offset_reg = index.gp(); if (is_reference(elem_kind)) { __ AtomicCompareExchangeTaggedPointer(array.gp(), offset_reg, offset, @@ -8057,6 +8080,15 @@ class LiftoffCompiler { const Value& descriptor_value) { LiftoffRegList pinned; LiftoffRegister descriptor = pinned.set(__ PopToRegister({})); + if (v8_flags.wasm_merged_descriptors) { + // The descriptor is the RTT, but we have to check if it's null, and + // there's no load that could trigger an implicit check. + if (descriptor_value.type.is_nullable()) { + MaybeEmitNullCheck(decoder, descriptor.gp(), pinned, + descriptor_value.type); + } + return descriptor; + } auto [explicit_check, implicit_check] = null_checks_for_struct_op(descriptor_value.type, 0); if (explicit_check) { @@ -8276,7 +8308,7 @@ class LiftoffCompiler { ValueType elem_type = imm.array_type->element_type(); ValueKind elem_kind = elem_type.kind(); int elem_size = value_kind_size(elem_kind); - const SharedFlag is_shared = decoder->module_->type(imm.index).is_shared; + const SharedFlag is_shared = imm.array_type->is_shared(); // Allocate the array. { @@ -8314,6 +8346,7 @@ class LiftoffCompiler { // {value} is read-only. bool in_old_space = is_shared || v8_flags.single_generation; ArrayFillImpl(decoder, pinned, obj, index, value, length, elem_kind, + is_shared, in_old_space && imm.array_type->element_type().is_ref() && initial_value_on_stack ? compiler::kFullWriteBarrier @@ -8378,11 +8411,11 @@ class LiftoffCompiler { LiftoffRegister index = pinned.set(__ PopToModifiableRegister(pinned)); LiftoffRegister obj = pinned.set(__ PopToRegister(pinned)); - ArrayFillImpl(decoder, pinned, obj, index, value, length, - imm.array_type->element_type().kind(), - imm.array_type->element_type().is_ref() - ? compiler::kFullWriteBarrier - : compiler::kNoWriteBarrier); + ArrayFillImpl( + decoder, pinned, obj, index, value, length, + imm.array_type->element_type().kind(), imm.array_type->is_shared(), + imm.array_type->element_type().is_ref() ? compiler::kFullWriteBarrier + : compiler::kNoWriteBarrier); } void ArrayGet(FullDecoder* decoder, const Value& array_obj, @@ -8406,9 +8439,10 @@ class LiftoffCompiler { } LiftoffRegister value = __ GetUnusedRegister(reg_class_for(elem_kind), pinned); - LoadObjectField(decoder, value, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, elem_kind, - is_signed, false, pinned); + LoadObjectField( + decoder, value, array.gp(), index.gp(), + WasmArray::HeaderSize(imm.array_type->is_shared()) - kHeapObjectTag, + elem_kind, is_signed, false, pinned); __ PushRegister(unpacked(elem_kind), value); } @@ -8434,9 +8468,10 @@ class LiftoffCompiler { } LiftoffRegister value = __ GetUnusedRegister(reg_class_for(elem_kind), pinned); - LoadAtomicObjectField(decoder, value, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, elem_kind, - is_signed, false, memory_order, pinned); + LoadAtomicObjectField( + decoder, value, array.gp(), index.gp(), + WasmArray::HeaderSize(imm.array_type->is_shared()) - kHeapObjectTag, + elem_kind, is_signed, false, memory_order, pinned); __ PushRegister(unpacked(elem_kind), value); } @@ -8461,9 +8496,10 @@ class LiftoffCompiler { if (elem_size_shift != 0) { __ emit_i32_shli(index.gp(), index.gp(), elem_size_shift); } - StoreObjectField(decoder, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, value, false, - pinned, elem_kind); + StoreObjectField( + decoder, array.gp(), index.gp(), + WasmArray::HeaderSize(imm.array_type->is_shared()) - kHeapObjectTag, + value, false, pinned, elem_kind); } void ArrayAtomicSet(FullDecoder* decoder, const Value& array_obj, @@ -8488,9 +8524,10 @@ class LiftoffCompiler { if (elem_size_shift != 0) { __ emit_i32_shli(index.gp(), index.gp(), elem_size_shift); } - StoreAtomicObjectField(decoder, array.gp(), index.gp(), - WasmArray::kHeaderSize - kHeapObjectTag, value, - false, pinned, elem_kind, order); + StoreAtomicObjectField( + decoder, array.gp(), index.gp(), + WasmArray::HeaderSize(imm.array_type->is_shared()) - kHeapObjectTag, + value, false, pinned, elem_kind, order); } void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) { @@ -8527,6 +8564,7 @@ class LiftoffCompiler { __ cache_state()->stack_state.end()[-3]}, decoder->position()); __ DropValues(5); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); } void ArrayNewFixed(FullDecoder* decoder, const ArrayIndexImmediate& array_imm, @@ -8536,8 +8574,7 @@ class LiftoffCompiler { ValueKind elem_kind = array_imm.array_type->element_type().kind(); int32_t elem_count = length_imm.index; // Allocate the array. - const SharedFlag is_shared = - decoder->module_->type(array_imm.index).is_shared; + const SharedFlag is_shared = array_imm.array_type->is_shared(); CallBuiltin(is_shared ? Builtin::kWasmAllocateSharedArray_Uninitialized : Builtin::kWasmAllocateArray_Uninitialized, MakeSig::Returns(kRef).Params(kRef, kI32, kI32), @@ -8557,8 +8594,8 @@ class LiftoffCompiler { for (int i = elem_count - 1; i >= 0; i--) { LiftoffRegList pinned{array}; LiftoffRegister element = pinned.set(__ PopToRegister(pinned)); - int offset = - WasmArray::kHeaderSize + (i << value_kind_size_log2(elem_kind)); + int offset = WasmArray::HeaderSize(is_shared) + + (i << value_kind_size_log2(elem_kind)); // Skipping the write barrier is safe as long as: // (1) {array} is freshly allocated, and // (2) {array} is in new-space (not pretenured). @@ -8583,7 +8620,7 @@ class LiftoffCompiler { // code for debugging (1) doesn't need optimizations, and (2) relies on // PC offsets not changing, so it's safer to skip all conditional // decision-making for it on general principle. - if (prototype_setup_end_ == nullptr && for_debugging_ != kNotForDebugging && + if (prototype_setup_end_ == nullptr && !for_debugging_ && decoder->enabled_.has_custom_descriptors() && v8_flags.wasm_js_interop) { PrototypeSetupSequenceDetector matcher(decoder->pc(), decoder->end(), @@ -8665,9 +8702,11 @@ class LiftoffCompiler { MakeSig::Params(kIntPtrKind, kRef), {VarState{kIntPtrKind, buffer, 0}, VarState{kRef, global, 0}}, position); + int pc_offset = __ pc_offset_for_safepoint(); __ DeallocateStackSlot(kBufferSize); static constexpr int kNumDroppedConstants = 2; __ DropValues(kNumDroppedConstants); + EmitLandingPad(decoder, pc_offset); uint32_t num_locals = __ num_locals(); uint32_t stack_depth = @@ -8710,8 +8749,8 @@ class LiftoffCompiler { // Pop parameters from the value stack. __ DropValues(2); - MaybeOSR(); RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); + MaybeOSR(); LiftoffRegister result(kReturnRegister0); __ PushRegister(kRef, result); @@ -8747,6 +8786,7 @@ class LiftoffCompiler { __ cache_state()->stack_state.end()[-4]}, decoder->position()); __ DropValues(4); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); MaybeOSR(); } @@ -8820,9 +8860,11 @@ class LiftoffCompiler { if (implicit_check) { RegisterTrappingInstruction(decoder, protected_load_pc); } - LoadObjectField(decoder, value, value.gp(), no_reg, - offsetof(Map, instance_descriptors_) - kHeapObjectTag, kRef, - false, false, pinned); + if (!v8_flags.wasm_merged_descriptors) { + LoadObjectField(decoder, value, value.gp(), no_reg, + offsetof(Map, instance_descriptors_) - kHeapObjectTag, + kRef, false, false, pinned); + } __ PushRegister(kRef, value); } @@ -8902,14 +8944,19 @@ class LiftoffCompiler { } if (is_cast_from_any) { - // Check for map being a map for a wasm object (struct, array, func). + // Check for map being a map for a wasm object (struct or array). __ Load(LiftoffRegister(scratch2), tmp1, no_reg, offsetof(Map, instance_type_) - kHeapObjectTag, LoadType::kI32Load16U); + Label is_wasm_obj; __ emit_i32_subi(scratch2, scratch2, FIRST_WASM_OBJECT_TYPE); - __ emit_i32_cond_jumpi(kUnsignedGreaterThan, no_match, scratch2, + __ emit_i32_cond_jumpi(kUnsignedLessThanEqual, &is_wasm_obj, scratch2, LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE, frozen); + __ emit_i32_cond_jumpi(kNotEqual, no_match, scratch2, + WASM_CUSTOM_MAP_TYPE - FIRST_WASM_OBJECT_TYPE, + frozen); + __ bind(&is_wasm_obj); } // Constant-time subtyping check: load exactly one candidate RTT from the @@ -9108,6 +9155,7 @@ class LiftoffCompiler { VarState{kI32, null_succeeds_reg, 0}, }, decoder->position()); + RegisterDebugSideTableEntry(decoder, DebugSideTableBuilder::kDidSpill); MaybeOSR(); } @@ -9495,10 +9543,14 @@ class LiftoffCompiler { // Abstract type checkers. They all fall through on match. void StructCheck(TypeCheck& check, const FreezeCacheState& frozen) { + Label match; LoadInstanceType(check, frozen, check.no_match); LiftoffRegister instance_type(check.instance_type()); - __ emit_i32_cond_jumpi(kNotEqual, check.no_match, check.instance_type(), + __ emit_i32_cond_jumpi(kEqual, &match, check.instance_type(), WASM_STRUCT_TYPE, frozen); + __ emit_i32_cond_jumpi(kNotEqual, check.no_match, check.instance_type(), + WASM_CUSTOM_MAP_TYPE, frozen); + __ bind(&match); } void ArrayCheck(TypeCheck& check, const FreezeCacheState& frozen) { @@ -9520,9 +9572,14 @@ class LiftoffCompiler { // unsigned comparison. Register tmp = check.instance_type(); __ emit_i32_subi(tmp, tmp, FIRST_WASM_OBJECT_TYPE); - __ emit_i32_cond_jumpi(kUnsignedGreaterThan, check.no_match, tmp, + __ emit_i32_cond_jumpi(kUnsignedLessThanEqual, &match, tmp, LAST_WASM_OBJECT_TYPE - FIRST_WASM_OBJECT_TYPE, frozen); + // This will look weird in disassembly, but we want to prioritize the + // fast path (non-descriptor object, successful cast). + __ emit_i32_cond_jumpi(kNotEqual, check.no_match, tmp, + WASM_CUSTOM_MAP_TYPE - FIRST_WASM_OBJECT_TYPE, + frozen); __ bind(&match); } @@ -11007,7 +11064,7 @@ class LiftoffCompiler { __ LoadTrustedPointer( internal_function, func_ref, offsetof(WasmFuncRef, trusted_internal_) - kHeapObjectTag, - kWasmInternalFunctionIndirectPointerTag); + kWasmInternalFunctionTrustedPointerTag); // Load the implicit argument (WasmTrustedInstanceData or WasmImportData) // and target. @@ -11103,8 +11160,7 @@ class LiftoffCompiler { } int StructFieldOffset(const StructType* struct_type, int field_index) { - return WasmStruct::kHeaderSize + struct_type->field_offset(field_index) - - kHeapObjectTag; + return WasmStruct::FieldOffset(struct_type, field_index) - kHeapObjectTag; } std::pair<bool, bool> null_checks_for_struct_op(ValueType struct_type, @@ -11263,16 +11319,16 @@ class LiftoffCompiler { void ArrayFillImpl(FullDecoder* decoder, LiftoffRegList pinned, LiftoffRegister obj, LiftoffRegister index, LiftoffRegister value, LiftoffRegister length, - ValueKind elem_kind, + ValueKind elem_kind, SharedFlag is_shared, compiler::WriteBarrierKind write_barrier) { - // initial_offset = WasmArray::kHeaderSize + index * elem_size. + // initial_offset = WasmArray::HeaderSize(is_shared) + index * elem_size. LiftoffRegister offset = index; if (value_kind_size_log2(elem_kind) != 0) { __ emit_i32_shli(offset.gp(), index.gp(), value_kind_size_log2(elem_kind)); } __ emit_i32_addi(offset.gp(), offset.gp(), - WasmArray::kHeaderSize - kHeapObjectTag); + WasmArray::HeaderSize(is_shared) - kHeapObjectTag); // end_offset = initial_offset + length * elem_size. LiftoffRegister end_offset = length; @@ -11301,17 +11357,21 @@ class LiftoffCompiler { trap_handler::TrappingInstructionData{trapping_instruction_pc}); source_position_table_builder_.AddPosition( trapping_instruction_pc, SourcePosition(decoder->position()), true); + // The trap handler fakes a call from fault_address + 1, so the GC and + // debugger will look up the safepoint, stack frame, and scope at + // trapping_instruction_pc + 1. if (for_debugging_) { - DefineSafepoint(trapping_instruction_pc); + DefineSafepointWithCalleeSavedRegisters( + trapping_instruction_pc + + WasmFrameConstants::kTrappingInstructionReturnAddressOffset); } if (V8_UNLIKELY(debug_sidetable_builder_)) { - // The trap handler fakes a call from fault_address + 1, so the debugger - // will look up the stack frame and scope at trapping_instruction_pc + 1. debug_sidetable_builder_->NewEntry( - trapping_instruction_pc + 1, + trapping_instruction_pc + + WasmFrameConstants::kTrappingInstructionReturnAddressOffset, GetCurrentDebugSideTableEntries( decoder, DebugSideTableBuilder::kAllowRegisters) - .as_vector()); + .as_span()); } } @@ -11363,17 +11423,11 @@ class LiftoffCompiler { } void DefineSafepoint(int pc_offset = 0) { - if (pc_offset == 0) pc_offset = __ pc_offset_for_safepoint(); - if (pc_offset == last_safepoint_offset_) return; - last_safepoint_offset_ = pc_offset; auto safepoint = safepoint_table_builder_.DefineSafepoint(&asm_, pc_offset); __ cache_state()->DefineSafepoint(safepoint); } - void DefineSafepointWithCalleeSavedRegisters() { - int pc_offset = __ pc_offset_for_safepoint(); - if (pc_offset == last_safepoint_offset_) return; - last_safepoint_offset_ = pc_offset; + void DefineSafepointWithCalleeSavedRegisters(int pc_offset = 0) { auto safepoint = safepoint_table_builder_.DefineSafepoint(&asm_, pc_offset); __ cache_state()->DefineSafepointWithCalleeSavedRegisters(safepoint); } @@ -11431,7 +11485,7 @@ class LiftoffCompiler { compiler::CallDescriptor* const descriptor_; CompilationEnv* const env_; DebugSideTableBuilder* const debug_sidetable_builder_; - base::OwnedVector<ValueType> stack_value_types_for_debugging_; + base::UniqueArray<ValueType> stack_value_types_for_debugging_; const ForDebugging for_debugging_; LiftoffBailoutReason bailout_reason_ = kNoReason; const int func_index_; @@ -11461,9 +11515,11 @@ class LiftoffCompiler { std::unique_ptr<WasmCoverageInstrumentation<FullDecoder>> coverage_instrumentation_; - // Introduce a dead breakpoint to ensure that the calculation of the return - // address in OSR is correct. - int dead_breakpoint_ = 0; + // Introduce dead breakpoints to ensure that the calculation of the return + // address in OSR is correct when active frames are paused at removed + // breakpoints. + const int* next_dead_breakpoint_ptr_ = nullptr; + const int* next_dead_breakpoint_end_ = nullptr; // Remember whether the did function-entry break checks (for "hook on function // call" and "break on entry" a.k.a. instrumentation breakpoint). This happens @@ -11481,10 +11537,6 @@ class LiftoffCompiler { // Current number of exception refs on the stack. int num_exceptions_ = 0; - // The pc_offset of the last defined safepoint. -1 if no safepoint has been - // defined yet. - int last_safepoint_offset_ = -1; - // Updated during compilation on every "call", "call_indirect", and "call_ref" // instruction. // Holds the call target, or for "call_indirect" and "call_ref" the sentinels diff --git a/deps/v8/src/wasm/baseline/liftoff-compiler.h b/deps/v8/src/wasm/baseline/liftoff-compiler.h index 207fbe958b06..7c2980cd4dd5 100644 --- a/deps/v8/src/wasm/baseline/liftoff-compiler.h +++ b/deps/v8/src/wasm/baseline/liftoff-compiler.h @@ -40,8 +40,8 @@ struct LiftoffOptions { DelayedCounterUpdates* counter_updates = nullptr; WasmDetectedFeatures* detected_features = nullptr; base::Vector<const int> breakpoints = {}; + base::Vector<const int> dead_breakpoints = {}; std::unique_ptr<DebugSideTable>* debug_sidetable = nullptr; - int dead_breakpoint = 0; int32_t* max_steps = nullptr; uint32_t deopt_info_bytecode_offset = std::numeric_limits<uint32_t>::max(); LocationKindForDeopt deopt_location_kind = LocationKindForDeopt::kNone; diff --git a/deps/v8/src/wasm/baseline/liftoff-varstate.h b/deps/v8/src/wasm/baseline/liftoff-varstate.h index 1cda96d79869..949014dc36ac 100644 --- a/deps/v8/src/wasm/baseline/liftoff-varstate.h +++ b/deps/v8/src/wasm/baseline/liftoff-varstate.h @@ -28,7 +28,7 @@ class LiftoffVarState { kind_(kind), i32_const_(i32_const), spill_offset_(offset) { - DCHECK(kind_ == kI32 || kind_ == kI64); + DCHECK(kind_ == kI32 || kind_ == kI64 || kind_ == kF32 || kind_ == kF64); DCHECK_LE(0, offset); } @@ -45,16 +45,26 @@ class LiftoffVarState { Location loc() const { return loc_; } - // The constant as 32-bit value, to be sign-extended if {kind() == kI64}. + // The constant as 32-bit value, to be sign-extended if {kind()} is 64-bit. int32_t i32_const() const { DCHECK_EQ(loc_, kIntConst); return i32_const_; } WasmValue constant() const { - DCHECK(kind_ == kI32 || kind_ == kI64); DCHECK_EQ(loc_, kIntConst); - return kind_ == kI32 ? WasmValue(i32_const_) - : WasmValue(int64_t{i32_const_}); + switch (kind_) { + case kI32: + return WasmValue(i32_const_); + case kI64: + return WasmValue(int64_t{i32_const_}); + case kF32: + return WasmValue(Float32::FromBits(static_cast<uint32_t>(i32_const_))); + case kF64: + return WasmValue( + Float64::FromBits(static_cast<uint64_t>(int64_t{i32_const_}))); + default: + UNREACHABLE(); + } } int offset() const { @@ -82,7 +92,7 @@ class LiftoffVarState { } void MakeConstant(int32_t i32_const) { - DCHECK(kind_ == kI32 || kind_ == kI64); + DCHECK(kind_ == kI32 || kind_ == kI64 || kind_ == kF32 || kind_ == kF64); loc_ = kIntConst; i32_const_ = i32_const; } diff --git a/deps/v8/src/wasm/baseline/loong64/liftoff-assembler-loong64-inl.h b/deps/v8/src/wasm/baseline/loong64/liftoff-assembler-loong64-inl.h index a83a6fd9182b..212d7d221c43 100644 --- a/deps/v8/src/wasm/baseline/loong64/liftoff-assembler-loong64-inl.h +++ b/deps/v8/src/wasm/baseline/loong64/liftoff-assembler-loong64-inl.h @@ -281,7 +281,8 @@ void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. @@ -347,13 +348,18 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); li(WasmHandleStackOverflowDescriptor::GapRegister(), max_stack_space); - Add_d(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(stack_param_slots * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); + Add_d( + WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((stack_param_slots + stack_return_slots) * kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + li(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + stack_param_slots * kSystemPointerSize); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -428,58 +434,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, Branch(ool_label, less, budget, Operand(zero_reg)); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return fp; - } - - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - Ld_d(old_fp.gp(), MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - BranchShort( - &call_runtime, eq, old_fp.gp(), - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - mov(old_fp.gp(), fp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - li(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1, kScratchReg); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - mov(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - Label done; - { - UseScratchRegisterScope temps{this}; - Register scratch = temps.Acquire(); - Ld_d(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - BranchShort( - &done, ne, scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - li(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1, kScratchReg); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - mov(fp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -511,7 +465,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { MemOperand src{src_addr, offset}; LoadTrustedPointerField(dst, src, tag); } @@ -1353,10 +1307,9 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); - liftoff::Store(this, frame_pointer, offset, src, kind); + liftoff::Store(this, fp, offset, src, kind); } void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, @@ -1449,26 +1402,41 @@ void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueKind kind) { void LiftoffAssembler::Spill(int offset, WasmValue value) { RecordUsedSpillOffset(offset); MemOperand dst = liftoff::GetStackSlot(offset); - switch (value.type().kind()) { - case kI32: { + ValueKind kind = value.type().kind(); + switch (kind) { + case kI32: + case kF32: { + int32_t bits32 = + kind == kF32 ? static_cast<int32_t>(value.to_f32_boxed().get_bits()) + : value.to_i32(); + if (bits32 == 0) { + St_w(zero_reg, dst); + break; + } UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); - MacroAssembler::li(scratch, Operand(value.to_i32())); + MacroAssembler::li(scratch, bits32); St_w(scratch, dst); break; } case kI64: + case kF64: case kRef: case kRefNull: { + int64_t bits64 = + kind == kF64 ? static_cast<int64_t>(value.to_f64_boxed().get_bits()) + : value.to_i64(); + if (bits64 == 0) { + St_d(zero_reg, dst); + break; + } UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); - MacroAssembler::li(scratch, value.to_i64()); + MacroAssembler::li(scratch, bits64); St_d(scratch, dst); break; } default: - // kWasmF32 and kWasmF64 are unreachable, since those - // constants are not tracked. UNREACHABLE(); } } @@ -2701,15 +2669,15 @@ void LiftoffAssembler::emit_i64x2_splat(LiftoffRegister dst, void LiftoffAssembler::emit_f32x4_splat(LiftoffRegister dst, LiftoffRegister src) { VRegister dstReg = dst.fp().toV(); - MacroAssembler::FmoveLow(kScratchReg, src.fp()); - vreplgr2vr_w(dstReg, kScratchReg); + VRegister srcReg = src.fp().toV(); + vreplve_w(dstReg, srcReg, zero_reg); } void LiftoffAssembler::emit_f64x2_splat(LiftoffRegister dst, LiftoffRegister src) { VRegister dstReg = dst.fp().toV(); - MacroAssembler::Move(kScratchReg, src.fp()); - vreplgr2vr_d(dstReg, kScratchReg); + VRegister srcReg = src.fp().toV(); + vreplve_d(dstReg, srcReg, zero_reg); } #define SIMD_BINOP(name1, name2, type) \ @@ -4020,15 +3988,13 @@ void LiftoffAssembler::emit_i64x2_extract_lane(LiftoffRegister dst, void LiftoffAssembler::emit_f32x4_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx) { - vpickve2gr_wu(kScratchReg, lhs.fp().toV(), imm_lane_idx); - MacroAssembler::FmoveLow(dst.fp(), kScratchReg); + vreplvei_w(dst.fp().toV(), lhs.fp().toV(), imm_lane_idx); } void LiftoffAssembler::emit_f64x2_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx) { - vpickve2gr_d(kScratchReg, lhs.fp().toV(), imm_lane_idx); - MacroAssembler::Move(dst.fp(), kScratchReg); + vreplvei_d(dst.fp().toV(), lhs.fp().toV(), imm_lane_idx); } void LiftoffAssembler::emit_i8x16_replace_lane(LiftoffRegister dst, @@ -4075,22 +4041,26 @@ void LiftoffAssembler::emit_f32x4_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx) { - MacroAssembler::FmoveLow(kScratchReg, src2.fp()); + UseScratchRegisterScope temps(this); + Register temp = temps.Acquire(); + movfr2gr_s(temp, src2.fp()); if (dst != src1) { vaddi_wu(dst.fp().toV(), src1.fp().toV(), 0); } - vinsgr2vr_w(dst.fp().toV(), kScratchReg, imm_lane_idx); + vinsgr2vr_w(dst.fp().toV(), temp, imm_lane_idx); } void LiftoffAssembler::emit_f64x2_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx) { - MacroAssembler::Move(kScratchReg, src2.fp()); + UseScratchRegisterScope temps(this); + Register temp = temps.Acquire(); + MacroAssembler::Move(temp, src2.fp()); if (dst != src1) { vaddi_du(dst.fp().toV(), src1.fp().toV(), 0); } - vinsgr2vr_d(dst.fp().toV(), kScratchReg, imm_lane_idx); + vinsgr2vr_d(dst.fp().toV(), temp, imm_lane_idx); } void LiftoffAssembler::emit_f32x4_qfma(LiftoffRegister dst, @@ -4373,7 +4343,8 @@ void LiftoffAssembler::RecordSpillsInSafepoint( SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills, LiftoffRegList ref_spills, int spill_offset) { LiftoffRegList fp_spills = all_spills & kFpCacheRegList; - int spill_space_size = fp_spills.GetNumRegsSet() * kSimd128Size; + int spill_space_size = fp_spills.GetNumRegsSet() * + (IsEnabled(LSX) ? kSimd128Size : kStackSlotSize); LiftoffRegList gp_spills = all_spills & kGpCacheRegList; while (!gp_spills.is_empty()) { LiftoffRegister reg = gp_spills.GetFirstRegSet(); @@ -4541,8 +4512,12 @@ void LiftoffStackSlots::Construct(int param_slots) { } case LiftoffAssembler::VarState::kIntConst: { asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); - asm_->li(kScratchReg, Operand(src.i32_const())); - asm_->Push(kScratchReg); + if (src.i32_const() == 0) { + asm_->Push(zero_reg); + } else { + asm_->li(kScratchReg, Operand(src.i32_const())); + asm_->Push(kScratchReg); + } break; } } diff --git a/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h b/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h index 0e68f6caf045..4b2329ad887b 100644 --- a/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h +++ b/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h @@ -345,7 +345,8 @@ void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. @@ -474,13 +475,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, Branch(ool_label, less, budget, Operand(zero_reg)); } -Register LiftoffAssembler::LoadOldFramePointer() { return fp; } - -void LiftoffAssembler::CheckStackShrink() { - // TODO(mips64): 42202153 - UNIMPLEMENTED(); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -512,7 +506,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { static_assert(!V8_ENABLE_SANDBOX_BOOL); static_assert(!COMPRESS_POINTERS_BOOL); Ld(dst, MemOperand{src_addr, offset}); @@ -1239,10 +1233,9 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); - liftoff::Store(this, frame_pointer, offset, src, kind); + liftoff::Store(this, fp, offset, src, kind); } void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, @@ -1327,22 +1320,41 @@ void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueKind kind) { void LiftoffAssembler::Spill(int offset, WasmValue value) { RecordUsedSpillOffset(offset); MemOperand dst = liftoff::GetStackSlot(offset); - switch (value.type().kind()) { - case kI32: { - MacroAssembler::li(kScratchReg, Operand(value.to_i32())); - Sw(kScratchReg, dst); + ValueKind kind = value.type().kind(); + switch (kind) { + case kI32: + case kF32: { + int32_t bits32 = + kind == kF32 ? static_cast<int32_t>(value.to_f32_boxed().get_bits()) + : value.to_i32(); + if (bits32 == 0) { + Sw(zero_reg, dst); + break; + } + UseScratchRegisterScope temps(this); + Register scratch = temps.Acquire(); + MacroAssembler::li(scratch, bits32); + Sw(scratch, dst); break; } case kI64: + case kF64: case kRef: case kRefNull: { - MacroAssembler::li(kScratchReg, value.to_i64()); - Sd(kScratchReg, dst); + int64_t bits64 = + kind == kF64 ? static_cast<int64_t>(value.to_f64_boxed().get_bits()) + : value.to_i64(); + if (bits64 == 0) { + Sd(zero_reg, dst); + break; + } + UseScratchRegisterScope temps(this); + Register scratch = temps.Acquire(); + MacroAssembler::li(scratch, bits64); + Sd(scratch, dst); break; } default: - // kWasmF32 and kWasmF64 are unreachable, since those - // constants are not tracked. UNREACHABLE(); } } @@ -4246,7 +4258,8 @@ void LiftoffAssembler::RecordSpillsInSafepoint( SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills, LiftoffRegList ref_spills, int spill_offset) { LiftoffRegList fp_spills = all_spills & kFpCacheRegList; - int spill_space_size = fp_spills.GetNumRegsSet() * kSimd128Size; + int spill_space_size = fp_spills.GetNumRegsSet() * + (IsEnabled(MIPS_SIMD) ? kSimd128Size : kStackSlotSize); LiftoffRegList gp_spills = all_spills & kGpCacheRegList; while (!gp_spills.is_empty()) { LiftoffRegister reg = gp_spills.GetFirstRegSet(); @@ -4412,8 +4425,12 @@ void LiftoffStackSlots::Construct(int param_slots) { } case LiftoffAssembler::VarState::kIntConst: { asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); - asm_->li(kScratchReg, Operand(src.i32_const())); - asm_->push(kScratchReg); + if (src.i32_const() == 0) { + asm_->Push(zero_reg); + } else { + asm_->li(kScratchReg, Operand(src.i32_const())); + asm_->Push(kScratchReg); + } break; } } diff --git a/deps/v8/src/wasm/baseline/parallel-move.cc b/deps/v8/src/wasm/baseline/parallel-move.cc index 7159e7411125..58d0f7e2d1ea 100644 --- a/deps/v8/src/wasm/baseline/parallel-move.cc +++ b/deps/v8/src/wasm/baseline/parallel-move.cc @@ -76,9 +76,8 @@ void ParallelMove::ExecuteLoads() { case RegisterLoad::kNop: break; case RegisterLoad::kConstant: - asm_->LoadConstant(dst, load->kind == kI64 - ? WasmValue(int64_t{load->value}) - : WasmValue(int32_t{load->value})); + asm_->LoadConstant(dst, + VarState{load->kind, load->value, 0}.constant()); break; case RegisterLoad::kStack: if (kNeedS128RegPair && load->kind == kS128) { diff --git a/deps/v8/src/wasm/baseline/parallel-move.h b/deps/v8/src/wasm/baseline/parallel-move.h index 2ecd4aee3bc9..4652371fd718 100644 --- a/deps/v8/src/wasm/baseline/parallel-move.h +++ b/deps/v8/src/wasm/baseline/parallel-move.h @@ -48,7 +48,7 @@ class ParallelMove { // Named constructors. static RegisterLoad Const(ValueKind kind, int32_t constant) { - V8_ASSUME(kind == kI32 || kind == kI64); + V8_ASSUME(kind == kI32 || kind == kI64 || kind == kF32 || kind == kF64); return {kConstant, kind, constant}; } static RegisterLoad Stack(int32_t offset, ValueKind kind) { diff --git a/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h b/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h index 5f69e048524d..d82d058d5fc6 100644 --- a/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h +++ b/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h @@ -116,7 +116,7 @@ inline void StoreToMemory(LiftoffAssembler* assm, MemOperand dst, UNREACHABLE(); } } else if (src.is_const()) { - if (src.kind() == kI32) { + if (src.kind() == kI32 || src.kind() == kF32) { assm->mov(scratch, Operand(src.i32_const())); assm->StoreU32(scratch, dst); } else { @@ -189,7 +189,8 @@ void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { int frame_size = GetTotalFrameSize() - (V8_EMBEDDED_CONSTANT_POOL_BOOL ? 3 : 2) * kSystemPointerSize; @@ -255,15 +256,20 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); for (auto reg : kSimd128ParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); mov(WasmHandleStackOverflowDescriptor::GapRegister(), Operand(max_stack_space)); - AddS64(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(stack_param_slots * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); + AddS64( + WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((stack_param_slots + stack_return_slots) * kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Operand(stack_param_slots * kSystemPointerSize)); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -344,60 +350,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, blt(ool_label, cr0); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return fp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - LoadU64(old_fp.gp(), MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - CmpU64(old_fp.gp(), - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - beq(&call_runtime); - mr(old_fp.gp(), fp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - MacroAssembler::Move(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - mr(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - { - UseScratchRegisterScope temps{this}; - Register scratch = temps.Acquire(); - LoadU64(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - CmpU64(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - bne(&done); - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kSimd128ReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - MacroAssembler::Move(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - mr(fp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -437,7 +389,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { LoadTaggedField(dst, MemOperand{src_addr, offset}); } @@ -1212,35 +1164,34 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = (caller_slot_idx + 1) * kSystemPointerSize; switch (kind) { case kI32: { #if defined(V8_TARGET_BIG_ENDIAN) - StoreU32(src.gp(), MemOperand(frame_pointer, offset + 4)); + StoreU32(src.gp(), MemOperand(fp, offset + 4)); break; #else - StoreU32(src.gp(), MemOperand(frame_pointer, offset)); + StoreU32(src.gp(), MemOperand(fp, offset)); break; #endif } case kRef: case kRefNull: case kI64: { - StoreU64(src.gp(), MemOperand(frame_pointer, offset)); + StoreU64(src.gp(), MemOperand(fp, offset)); break; } case kF32: { - StoreF32(src.fp(), MemOperand(frame_pointer, offset)); + StoreF32(src.fp(), MemOperand(fp, offset)); break; } case kF64: { - StoreF64(src.fp(), MemOperand(frame_pointer, offset)); + StoreF64(src.fp(), MemOperand(fp, offset)); break; } case kS128: { - StoreSimd128(src.simd128(), MemOperand(frame_pointer, offset)); + StoreSimd128(src.simd128(), MemOperand(fp, offset)); break; } default: @@ -1379,8 +1330,17 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { StoreU64(src, liftoff::GetStackSlot(offset)); break; } + case kF32: { + mov(src, Operand(value.to_f32_boxed().get_bits())); + StoreU32(src, liftoff::GetStackSlot(offset + stack_bias)); + break; + } + case kF64: { + mov(src, Operand(value.to_f64_boxed().get_bits())); + StoreU64(src, liftoff::GetStackSlot(offset)); + break; + } default: - // We do not track f32 and f64 constants, hence they are unreachable. UNREACHABLE(); } } @@ -3321,15 +3281,23 @@ void LiftoffStackSlots::Construct(int param_slots) { } case LiftoffAssembler::VarState::kIntConst: { asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); - DCHECK(src.kind() == kI32 || src.kind() == kI64); + DCHECK(src.kind() == kI32 || src.kind() == kI64 || src.kind() == kF32 || + src.kind() == kF64); UseScratchRegisterScope temps(asm_); Register scratch = temps.Acquire(); + if (src.kind() == kF32) { + asm_->mov(scratch, Operand(src.i32_const())); + asm_->AddS64(sp, sp, Operand(-kSystemPointerSize)); + asm_->StoreU32(scratch, MemOperand(sp)); + break; + } switch (src.kind()) { case kI32: asm_->mov(scratch, Operand(src.i32_const())); break; case kI64: + case kF64: asm_->mov(scratch, Operand(int64_t{slot.src_.i32_const()})); break; default: diff --git a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv-inl.h b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv-inl.h index fb42204b2774..266bb067a842 100644 --- a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv-inl.h +++ b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv-inl.h @@ -94,59 +94,10 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, Branch(ool_label, lt, budget, Operand{0}); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return fp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - LoadWord(old_fp.gp(), MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - BranchShort( - &call_runtime, eq, old_fp.gp(), - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - mv(old_fp.gp(), fp); - jmp(&done); - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - li(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1, kScratchReg); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - mv(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - Label done; - { - UseScratchRegisterScope temps{this}; - Register scratch = temps.Acquire(); - LoadWord(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - BranchShort( - &done, ne, scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kSimd128ReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - li(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1, kScratchReg); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - mv(fp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. @@ -214,14 +165,19 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); for (auto reg : kSimd128ParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); li(WasmHandleStackOverflowDescriptor::GapRegister(), max_stack_space); - AddWord(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(stack_param_slots * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); + AddWord( + WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((stack_param_slots + stack_return_slots) * kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + li(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + stack_param_slots * kSystemPointerSize); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -287,7 +243,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { MemOperand src{src_addr, offset}; LoadTrustedPointerField(dst, src, tag); } @@ -1444,6 +1400,7 @@ void LiftoffAssembler::emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs, void LiftoffAssembler::emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs) { + VU.SetSimd128(E32); if (is_uint5(rhs % 32)) { vsll_vi(dst.simd128(), lhs.simd128(), rhs % 32); } else { @@ -2709,7 +2666,7 @@ bool LiftoffAssembler::emit_f16x8_min(LiftoffRegister dst, LiftoffRegister lhs, vmfeq_vv(v0, lhs.simd128(), lhs.simd128()); vmfeq_vv(kSimd128ScratchReg, rhs.simd128(), rhs.simd128()); vand_vv(v0, v0, kSimd128ScratchReg); - li(kScratchReg, kFP32DefaultNaN); + li(kScratchReg, kFP16DefaultNaN); vmv_vx(kSimd128ScratchReg, kScratchReg); vfmin_vv(kSimd128ScratchReg, rhs.simd128(), lhs.simd128(), Mask); vmv_vv(dst.simd128(), kSimd128ScratchReg); @@ -2722,7 +2679,7 @@ bool LiftoffAssembler::emit_f16x8_max(LiftoffRegister dst, LiftoffRegister lhs, vmfeq_vv(v0, lhs.simd128(), lhs.simd128()); vmfeq_vv(kSimd128ScratchReg, rhs.simd128(), rhs.simd128()); vand_vv(v0, v0, kSimd128ScratchReg); - li(kScratchReg, 0x7E00); + li(kScratchReg, kFP16DefaultNaN); vmv_vx(kSimd128ScratchReg, kScratchReg); vfmax_vv(kSimd128ScratchReg, rhs.simd128(), lhs.simd128(), Mask); vmv_vv(dst.simd128(), kSimd128ScratchReg); diff --git a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv32-inl.h b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv32-inl.h index c0f36e1f28ce..eb093ac3c0eb 100644 --- a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv32-inl.h +++ b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv32-inl.h @@ -1151,10 +1151,9 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); - liftoff::Store(this, frame_pointer, offset, src, kind); + liftoff::Store(this, fp, offset, src, kind); } void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, diff --git a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h index f0711e49a556..84d49021bb55 100644 --- a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h +++ b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h @@ -181,9 +181,11 @@ inline void StoreToMemory(LiftoffAssembler* assm, MemOperand dst, } switch (src.kind()) { case kI32: + case kF32: assm->Sw(src_reg, dst); break; case kI64: + case kF64: assm->StoreWord(src_reg, dst); break; default: @@ -1129,10 +1131,9 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); - liftoff::Store(this, frame_pointer, offset, src, kind); + liftoff::Store(this, fp, offset, src, kind); } void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, @@ -1269,9 +1270,21 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { Sd(tmp, dst); break; } + case kF32: { + UseScratchRegisterScope temps(this); + Register tmp = temps.Acquire(); + MacroAssembler::li(tmp, Operand(value.to_f32_boxed().get_bits())); + Sw(tmp, dst); + break; + } + case kF64: { + UseScratchRegisterScope temps(this); + Register tmp = temps.Acquire(); + MacroAssembler::li(tmp, Operand(value.to_f64_boxed().get_bits())); + Sd(tmp, dst); + break; + } default: - // kWasmF32 and kWasmF64 are unreachable, since those - // constants are not tracked. UNREACHABLE(); } } @@ -2306,6 +2319,11 @@ void LiftoffStackSlots::Construct(int param_slots) { break; } case LiftoffAssembler::VarState::kIntConst: { + // f32 constants and sign-extendable f64 constants are tracked as + // integer constants. The sign-extending store below materializes them + // correctly (only the low four bytes are relevant for f32). + DCHECK(src.kind() == kI32 || src.kind() == kI64 || src.kind() == kF32 || + src.kind() == kF64); asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); asm_->li(kScratchReg, Operand(src.i32_const())); asm_->push(kScratchReg); diff --git a/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h b/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h index 36c104d65fa3..fd9e320e14ea 100644 --- a/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h +++ b/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h @@ -78,7 +78,7 @@ inline void StoreToMemory(LiftoffAssembler* assm, MemOperand dst, UNREACHABLE(); } } else if (src.is_const()) { - if (src.kind() == kI32) { + if (src.kind() == kI32 || src.kind() == kF32) { assm->mov(scratch, Operand(src.i32_const())); assm->StoreU32(scratch, dst); } else { @@ -150,7 +150,8 @@ void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize; // The frame setup builtin also pushes the feedback vector. if (feedback_vector_slot) { @@ -210,14 +211,19 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); mov(WasmHandleStackOverflowDescriptor::GapRegister(), Operand(max_stack_space)); - AddS64(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, - Operand(stack_param_slots * kSystemPointerSize + - CommonFrameConstants::kFixedFrameSizeAboveFp)); + AddS64( + WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp, + Operand((stack_param_slots + stack_return_slots) * kSystemPointerSize + + CommonFrameConstants::kFixedFrameSizeAboveFp)); + mov(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Operand(stack_param_slots * kSystemPointerSize)); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); @@ -288,59 +294,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, blt(ool_label); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return fp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - LoadU64(old_fp.gp(), MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - CmpU64(old_fp.gp(), - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - beq(&call_runtime); - mov(old_fp.gp(), fp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - MacroAssembler::Move(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1, r0); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - mov(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - { - UseScratchRegisterScope temps{this}; - Register scratch = temps.Acquire(); - LoadU64(scratch, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset)); - CmpU64(scratch, - Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - } - Label done; - bne(&done); - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - MacroAssembler::Move(kCArgRegs[0], ExternalReference::isolate_address()); - PrepareCallCFunction(1, r0); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - mov(fp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -378,7 +331,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { LoadTaggedField(dst, MemOperand{src_addr, offset}); } @@ -1570,37 +1523,36 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { + ValueKind kind) { int32_t offset = (caller_slot_idx + 1) * 8; switch (kind) { case kI32: { #if defined(V8_TARGET_BIG_ENDIAN) - StoreU32(src.gp(), MemOperand(frame_pointer, offset + 4)); + StoreU32(src.gp(), MemOperand(fp, offset + 4)); break; #else - StoreU32(src.gp(), MemOperand(frame_pointer, offset)); + StoreU32(src.gp(), MemOperand(fp, offset)); break; #endif } case kRef: case kRefNull: case kI64: { - StoreU64(src.gp(), MemOperand(frame_pointer, offset)); + StoreU64(src.gp(), MemOperand(fp, offset)); break; } case kF32: { - StoreF32(src.fp(), MemOperand(frame_pointer, offset)); + StoreF32(src.fp(), MemOperand(fp, offset)); break; } case kF64: { - StoreF64(src.fp(), MemOperand(frame_pointer, offset)); + StoreF64(src.fp(), MemOperand(fp, offset)); break; } case kS128: { UseScratchRegisterScope temps(this); Register scratch = temps.Acquire(); - StoreV128(src.fp(), MemOperand(frame_pointer, offset), scratch); + StoreV128(src.fp(), MemOperand(fp, offset), scratch); break; } default: @@ -1758,8 +1710,17 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { StoreU64(src, liftoff::GetStackSlot(offset)); break; } + case kF32: { + mov(src, Operand(value.to_f32_boxed().get_bits())); + StoreU32(src, liftoff::GetStackSlot(offset + stack_bias)); + break; + } + case kF64: { + mov(src, Operand(value.to_f64_boxed().get_bits())); + StoreU64(src, liftoff::GetStackSlot(offset)); + break; + } default: - // We do not track f32 and f64 constants, hence they are unreachable. UNREACHABLE(); } } @@ -3723,15 +3684,23 @@ void LiftoffStackSlots::Construct(int param_slots) { } case LiftoffAssembler::VarState::kIntConst: { asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); - DCHECK(src.kind() == kI32 || src.kind() == kI64); + DCHECK(src.kind() == kI32 || src.kind() == kI64 || src.kind() == kF32 || + src.kind() == kF64); UseScratchRegisterScope temps(asm_); Register scratch = temps.Acquire(); + if (src.kind() == kF32) { + asm_->mov(scratch, Operand(src.i32_const())); + asm_->lay(sp, MemOperand(sp, -kSystemPointerSize)); + asm_->StoreU32(scratch, MemOperand(sp)); + break; + } switch (src.kind()) { case kI32: asm_->mov(scratch, Operand(src.i32_const())); break; case kI64: + case kF64: asm_->mov(scratch, Operand(int64_t{slot.src_.i32_const()})); break; default: diff --git a/deps/v8/src/wasm/baseline/x64/liftoff-assembler-x64-inl.h b/deps/v8/src/wasm/baseline/x64/liftoff-assembler-x64-inl.h index 733107991768..023672a62365 100644 --- a/deps/v8/src/wasm/baseline/x64/liftoff-assembler-x64-inl.h +++ b/deps/v8/src/wasm/baseline/x64/liftoff-assembler-x64-inl.h @@ -137,7 +137,7 @@ inline void StoreToMemory(LiftoffAssembler* assm, Operand dst, if (src.is_reg()) { liftoff::StoreToMemory(assm, dst, src.reg(), src.kind()); } else if (src.is_const()) { - if (src.kind() == kI32) { + if (src.kind() == kI32 || src.kind() == kF32) { assm->movl(dst, Immediate(src.i32_const())); } else { assm->MacroAssembler::Move(dst, static_cast<int64_t>(src.i32_const())); @@ -230,25 +230,31 @@ void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, } void LiftoffAssembler::AlignFrameSize() { - int alignment = v8_flags.enforce_x64_16byte_alignment ? 2 * kSystemPointerSize - : kSystemPointerSize; + int alignment = V8_X64_16BYTE_STACK_ALIGNMENT_BOOL ? 2 * kSystemPointerSize + : kSystemPointerSize; max_used_spill_offset_ = RoundUp(max_used_spill_offset_, alignment); } void LiftoffAssembler::PatchPrepareStackFrame( int offset, SafepointTableBuilder* safepoint_table_builder, - bool feedback_vector_slot, size_t stack_param_slots) { + bool feedback_vector_slot, size_t stack_param_slots, + size_t stack_return_slots) { // The frame_size includes the frame marker and the instance slot. Both are // pushed as part of frame construction, so we don't need to allocate memory // for them anymore. int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize; - // The frame setup builtin also pushes the feedback vector. if (feedback_vector_slot) { - frame_size -= kSystemPointerSize; + // WasmLiftoffFrameSetup also pushes the feedback vector, and (with 16-byte + // alignment) a zero into the OSR target slot so that sp stays aligned. + static_assert(kOSRTargetOffset == 4 * kSystemPointerSize); + frame_size -= V8_X64_16BYTE_STACK_ALIGNMENT_BOOL ? 2 * kSystemPointerSize + : kSystemPointerSize; } + DCHECK_GE(frame_size, 0); DCHECK_EQ(0, frame_size % kSystemPointerSize); - DCHECK_IMPLIES(v8_flags.enforce_x64_16byte_alignment, - GetTotalFrameSize() % (2 * kSystemPointerSize) == 0); +#if V8_X64_16BYTE_STACK_ALIGNMENT + DCHECK_EQ(0, frame_size % (2 * kSystemPointerSize)); +#endif // We can't run out of space when patching, just pass anything big enough to // not cause the assembler to try to grow the buffer. @@ -308,6 +314,8 @@ void LiftoffAssembler::PatchPrepareStackFrame( LiftoffRegList regs_to_save; regs_to_save.set(WasmHandleStackOverflowDescriptor::GapRegister()); regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister()); + regs_to_save.set( + WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister()); for (auto reg : kGpParamRegisters) regs_to_save.set(reg); for (auto reg : kFpParamRegisters) regs_to_save.set(reg); PushRegisters(regs_to_save); @@ -316,12 +324,16 @@ void LiftoffAssembler::PatchPrepareStackFrame( movq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), rbp); addq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), Immediate(static_cast<int32_t>( - stack_param_slots * kSystemPointerSize + + (stack_param_slots + stack_return_slots) * kSystemPointerSize + CommonFrameConstants::kFixedFrameSizeAboveFp))); + movq(WasmHandleStackOverflowDescriptor::ParameterSlotsSizeRegister(), + Immediate( + static_cast<int32_t>(stack_param_slots * kSystemPointerSize))); CallBuiltin(Builtin::kWasmHandleStackOverflow); safepoint_table_builder->DefineSafepoint(this); PopRegisters(regs_to_save); } else { + AssertSpAlignedForCall(); near_call(static_cast<intptr_t>(Builtin::kWasmStackOverflow), RelocInfo::WASM_STUB_CALL); // The call will not return; just define an empty safepoint. @@ -378,53 +390,6 @@ void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used, j(negative, ool_label); } -Register LiftoffAssembler::LoadOldFramePointer() { - if (!v8_flags.wasm_growable_stacks) { - return rbp; - } - LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {}); - FreezeCacheState frozen(*this); - Label done, call_runtime; - cmpq(MemOperand(rbp, TypedFrameConstants::kFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - j(equal, &call_runtime); - movq(old_fp.gp(), rbp); - jmp(&done); - - bind(&call_runtime); - LiftoffRegList regs_to_save = cache_state()->used_registers; - PushRegisters(regs_to_save); - PrepareCallCFunction(1); - LoadAddress(kCArgRegs[0], ExternalReference::isolate_address()); - CallCFunction(ExternalReference::wasm_load_old_fp(), 1); - if (old_fp.gp() != kReturnRegister0) { - movq(old_fp.gp(), kReturnRegister0); - } - PopRegisters(regs_to_save); - - bind(&done); - return old_fp.gp(); -} - -void LiftoffAssembler::CheckStackShrink() { - cmpq(MemOperand(rbp, TypedFrameConstants::kFrameTypeOffset), - Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START))); - Label done; - j(not_equal, &done); - LiftoffRegList regs_to_save; - for (auto reg : kGpReturnRegisters) regs_to_save.set(reg); - for (auto reg : kFpReturnRegisters) regs_to_save.set(reg); - PushRegisters(regs_to_save); - PrepareCallCFunction(1); - LoadAddress(kCArgRegs[0], ExternalReference::isolate_address()); - CallCFunction(ExternalReference::wasm_shrink_stack(), 1); - // Restore old FP. We don't need to restore old SP explicitly, because - // it will be restored from FP in LeaveFrame before return. - movq(rbp, kReturnRegister0); - PopRegisters(regs_to_save); - bind(&done); -} - void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) { switch (value.type().kind()) { case kI32: @@ -457,7 +422,7 @@ void LiftoffAssembler::LoadInstanceDataFromFrame(Register dst) { } void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr, - int offset, IndirectPointerTag tag) { + int offset, TrustedPointerTag tag) { LoadTrustedPointerField(dst, Operand{src_addr, offset}, tag, kScratchRegister); } @@ -735,11 +700,13 @@ void LiftoffAssembler::StoreConst(Register dst_addr, Register offset_reg, break; case StoreType::kI32Store: case StoreType::kI64Store32: + case StoreType::kF32Store: movl(dst_op, Immediate(value)); break; case StoreType::kI64Store: - // The 32-bit immediate is sign-extended, matching how Liftoff keeps i64 - // constants. + case StoreType::kF64Store: + // The 32-bit immediate is sign-extended, matching how Liftoff keeps + // 64-bit constants. movq(dst_op, Immediate(value)); break; default: @@ -1218,9 +1185,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, uint32_t caller_slot_idx, - ValueKind kind, - Register frame_pointer) { - Operand dst(frame_pointer, kSystemPointerSize * (caller_slot_idx + 1)); + ValueKind kind) { + Operand dst(rbp, kSystemPointerSize * (caller_slot_idx + 1)); liftoff::StoreToMemory(this, dst, src, kind); } @@ -1311,22 +1277,28 @@ void LiftoffAssembler::Spill(int offset, WasmValue value) { case kI32: movl(dst, Immediate(value.to_i32())); break; - case kI64: { - if (is_int32(value.to_i64())) { + case kF32: + movl(dst, Immediate(value.to_f32_boxed().get_bits())); + break; + case kI64: + case kF64: { + int64_t val64 = value.type().kind() == kI64 + ? value.to_i64() + : value.to_f64_boxed().get_bits(); + if (is_int32(val64)) { // Sign extend low word. - movq(dst, Immediate(static_cast<int32_t>(value.to_i64()))); - } else if (is_uint32(value.to_i64())) { + movq(dst, Immediate(static_cast<int32_t>(val64))); + } else if (is_uint32(val64)) { // Zero extend low word. - movl(kScratchRegister, Immediate(static_cast<int32_t>(value.to_i64()))); + movl(kScratchRegister, Immediate(static_cast<int32_t>(val64))); movq(dst, kScratchRegister); } else { - movq(kScratchRegister, value.to_i64()); + movq(kScratchRegister, val64); movq(dst, kScratchRegister); } break; } default: - // We do not track f32 and f64 constants, hence they are unreachable. UNREACHABLE(); } } @@ -4701,13 +4673,8 @@ void LiftoffAssembler::emit_f64x2_qfms(LiftoffRegister dst, bool LiftoffAssembler::emit_f16x8_splat(LiftoffRegister dst, LiftoffRegister src) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX2)) { - return false; - } - CpuFeatureScope f16c_scope(this, F16C); - CpuFeatureScope avx2_scope(this, AVX2); - vcvtps2ph(dst.fp(), src.fp(), 0); - vpbroadcastw(dst.fp(), dst.fp()); + if (!CpuFeatures::IsSupported(F16C)) return false; + F16x8Splat(dst.fp(), src.fp()); return true; } @@ -4833,16 +4800,12 @@ bool LiftoffAssembler::emit_f16x8_nearest_int(LiftoffRegister dst, template <void (Assembler::*avx_op)(YMMRegister, YMMRegister, YMMRegister)> bool F16x8CmpOpViaF32(LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX) || - !CpuFeatures::IsSupported(AVX2)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; CpuFeatureScope f16c_scope(assm, F16C); CpuFeatureScope avx_scope(assm, AVX); - CpuFeatureScope avx2_scope(assm, AVX2); YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); - assm->vcvtph2ps(ydst, lhs.fp()); assm->vcvtph2ps(kScratchSimd256Reg, rhs.fp()); + assm->vcvtph2ps(ydst, lhs.fp()); (assm->*avx_op)(ydst, ydst, kScratchSimd256Reg); assm->vextractf128(kScratchDoubleReg, ydst, 1); assm->vpackssdw(dst.fp(), dst.fp(), kScratchDoubleReg); @@ -4892,11 +4855,21 @@ bool F16x8BinOpViaF32(LiftoffAssembler* assm, LiftoffRegister dst, bool LiftoffAssembler::emit_f16x8_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { + if (UseAvx10_1()) { + CpuFeatureScope avx10_1_scope(this, AVX10_1); + vaddph(dst.fp(), lhs.fp(), rhs.fp()); + return true; + } return F16x8BinOpViaF32<&Assembler::vaddps>(this, dst, lhs, rhs); } bool LiftoffAssembler::emit_f16x8_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { + if (UseAvx10_1()) { + CpuFeatureScope avx10_1_scope(this, AVX10_1); + vsubph(dst.fp(), lhs.fp(), rhs.fp()); + return true; + } return F16x8BinOpViaF32<&Assembler::vsubps>(this, dst, lhs, rhs); } @@ -4912,9 +4885,7 @@ bool LiftoffAssembler::emit_f16x8_div(LiftoffRegister dst, LiftoffRegister lhs, bool LiftoffAssembler::emit_f16x8_min(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX2)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; static constexpr RegClass res_rc = reg_class_for(kS128); LiftoffRegister tmp = GetUnusedRegister(res_rc, LiftoffRegList{dst, lhs, rhs}); @@ -4926,9 +4897,7 @@ bool LiftoffAssembler::emit_f16x8_min(LiftoffRegister dst, LiftoffRegister lhs, bool LiftoffAssembler::emit_f16x8_max(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX2)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; static constexpr RegClass res_rc = reg_class_for(kS128); LiftoffRegister tmp = GetUnusedRegister(res_rc, LiftoffRegList{dst, lhs, rhs}); @@ -4952,14 +4921,7 @@ bool LiftoffAssembler::emit_f16x8_pmax(LiftoffRegister dst, LiftoffRegister lhs, bool LiftoffAssembler::emit_i16x8_sconvert_f16x8(LiftoffRegister dst, LiftoffRegister src) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX) || - !CpuFeatures::IsSupported(AVX2)) { - return false; - } - - CpuFeatureScope f16c_scope(this, F16C); - CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); + if (!CpuFeatures::IsSupported(F16C)) return false; YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); I16x8SConvertF16x8(ydst, src.fp(), kScratchSimd256Reg, kScratchRegister); @@ -4968,14 +4930,7 @@ bool LiftoffAssembler::emit_i16x8_sconvert_f16x8(LiftoffRegister dst, bool LiftoffAssembler::emit_i16x8_uconvert_f16x8(LiftoffRegister dst, LiftoffRegister src) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX) || - !CpuFeatures::IsSupported(AVX2)) { - return false; - } - - CpuFeatureScope f16c_scope(this, F16C); - CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); + if (!CpuFeatures::IsSupported(F16C)) return false; YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); I16x8TruncF16x8U(ydst, src.fp(), kScratchSimd256Reg); @@ -4984,35 +4939,17 @@ bool LiftoffAssembler::emit_i16x8_uconvert_f16x8(LiftoffRegister dst, bool LiftoffAssembler::emit_f16x8_sconvert_i16x8(LiftoffRegister dst, LiftoffRegister src) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX) || - !CpuFeatures::IsSupported(AVX2)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; - CpuFeatureScope f16c_scope(this, F16C); - CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); - YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); - vpmovsxwd(ydst, src.fp()); - vcvtdq2ps(ydst, ydst); - vcvtps2ph(dst.fp(), ydst, 0); + F16x8SConvertI16x8(dst.fp(), src.fp(), kScratchSimd256Reg); return true; } bool LiftoffAssembler::emit_f16x8_uconvert_i16x8(LiftoffRegister dst, LiftoffRegister src) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(AVX) || - !CpuFeatures::IsSupported(AVX2)) { - return false; - } + if (!CpuFeatures::IsSupported(F16C)) return false; - CpuFeatureScope f16c_scope(this, F16C); - CpuFeatureScope avx_scope(this, AVX); - CpuFeatureScope avx2_scope(this, AVX2); - YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); - vpmovzxwd(ydst, src.fp()); - vcvtdq2ps(ydst, ydst); - vcvtps2ph(dst.fp(), ydst, 0); + F16x8UConvertI16x8(dst.fp(), src.fp(), kScratchSimd256Reg); return true; } @@ -5022,8 +4959,7 @@ bool LiftoffAssembler::emit_f16x8_demote_f32x4_zero(LiftoffRegister dst, return false; } CpuFeatureScope f16c_scope(this, F16C); - YMMRegister ysrc = YMMRegister::from_code(src.fp().code()); - vcvtps2ph(dst.fp(), ysrc, 0); + vcvtps2ph(dst.fp(), src.fp(), 0); return true; } @@ -5065,18 +5001,36 @@ bool LiftoffAssembler::emit_f32x4_promote_low_f16x8(LiftoffRegister dst, return false; } CpuFeatureScope f16c_scope(this, F16C); - YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); - vcvtph2ps(ydst, src.fp()); + vcvtph2ps(dst.fp(), src.fp()); return true; } +template <void (Assembler::*avx10_op)(XMMRegister, XMMRegister, XMMRegister)> +void F16x8FmaNative(LiftoffAssembler* assm, LiftoffRegister dst, + LiftoffRegister src1, LiftoffRegister src2, + LiftoffRegister src3) { + CpuFeatureScope avx10_scope(assm, AVX10_1); + if (dst == src1) { + (assm->*avx10_op)(dst.fp(), src2.fp(), src3.fp()); + } else if (dst == src2) { + (assm->*avx10_op)(dst.fp(), src1.fp(), src3.fp()); + } else { + XMMRegister result = dst == src3 ? kScratchDoubleReg : dst.fp(); + assm->Movdqa(result, src1.fp()); + (assm->*avx10_op)(result, src2.fp(), src3.fp()); + if (result != dst.fp()) assm->Movdqa(dst.fp(), result); + } +} + bool LiftoffAssembler::emit_f16x8_qfma(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(FMA3)) { - return false; + if (UseAvx10_1()) { + F16x8FmaNative<&Assembler::vfmadd213ph>(this, dst, src1, src2, src3); + return true; } + if (!CpuFeatures::IsSupported(F16C)) return false; YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); YMMRegister tmp = YMMRegister::from_code(kScratchDoubleReg.code()); @@ -5089,9 +5043,11 @@ bool LiftoffAssembler::emit_f16x8_qfms(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3) { - if (!CpuFeatures::IsSupported(F16C) || !CpuFeatures::IsSupported(FMA3)) { - return false; + if (UseAvx10_1()) { + F16x8FmaNative<&Assembler::vfnmadd213ph>(this, dst, src1, src2, src3); + return true; } + if (!CpuFeatures::IsSupported(F16C)) return false; YMMRegister ydst = YMMRegister::from_code(dst.fp().code()); YMMRegister tmp = YMMRegister::from_code(kScratchDoubleReg.code()); @@ -5132,6 +5088,10 @@ void LiftoffAssembler::AssertUnreachable(AbortReason reason) { void LiftoffAssembler::PushRegisters(LiftoffRegList regs) { LiftoffRegList gp_regs = regs & kGpCacheRegList; + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL && + (gp_regs.GetNumRegsSet() & 1) != 0) { + pushq(Immediate(0)); + } while (!gp_regs.is_empty()) { LiftoffRegister reg = gp_regs.GetFirstRegSet(); pushq(reg.gp()); @@ -5163,11 +5123,16 @@ void LiftoffAssembler::PopRegisters(LiftoffRegList regs) { } if (fp_offset) addq(rsp, Immediate(fp_offset)); LiftoffRegList gp_regs = regs & kGpCacheRegList; + bool pad_gp = + V8_X64_16BYTE_STACK_ALIGNMENT_BOOL && (gp_regs.GetNumRegsSet() & 1) != 0; while (!gp_regs.is_empty()) { LiftoffRegister reg = gp_regs.GetLastRegSet(); popq(reg.gp()); gp_regs.clear(reg); } + if (pad_gp) { + addq(rsp, Immediate(kSystemPointerSize)); + } } void LiftoffAssembler::RecordSpillsInSafepoint( @@ -5176,6 +5141,11 @@ void LiftoffAssembler::RecordSpillsInSafepoint( LiftoffRegList fp_spills = all_spills & kFpCacheRegList; int spill_space_size = fp_spills.GetNumRegsSet() * kSimd128Size; LiftoffRegList gp_spills = all_spills & kGpCacheRegList; + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL && + (gp_spills.GetNumRegsSet() & 1) != 0) { + ++spill_offset; + spill_space_size += kSystemPointerSize; + } while (!gp_spills.is_empty()) { LiftoffRegister reg = gp_spills.GetFirstRegSet(); if (ref_spills.has(reg)) { @@ -5291,17 +5261,29 @@ void LiftoffAssembler::TailCallIndirect( } void LiftoffAssembler::CallBuiltin(Builtin builtin) { + if (builtin != Builtin::kWasmLiftoffFrameSetup) { + // {kWasmLiftoffFrameSetup} is called at function entry before {rbp} is + // pushed, while {rsp} still points to the caller's return address + // ({rsp % 16 == 8}). + AssertSpAlignedForCall(); + } // A direct call to a builtin. Just encode the builtin index. This will be // patched at relocation. near_call(static_cast<Address>(builtin), RelocInfo::WASM_STUB_CALL); } void LiftoffAssembler::AllocateStackSlot(Register addr, uint32_t size) { + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + size = RoundUp(size, 2 * kSystemPointerSize); + } AllocateStackSpace(size); movq(addr, rsp); } void LiftoffAssembler::DeallocateStackSlot(uint32_t size) { + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + size = RoundUp(size, 2 * kSystemPointerSize); + } addq(rsp, Immediate(size)); } diff --git a/deps/v8/src/wasm/c-api.cc b/deps/v8/src/wasm/c-api.cc index badd152eaa51..b5888853f9ea 100644 --- a/deps/v8/src/wasm/c-api.cc +++ b/deps/v8/src/wasm/c-api.cc @@ -31,6 +31,7 @@ #include "src/api/api-inl.h" #include "src/base/logging.h" #include "src/base/macros.h" +#include "src/base/unique-array.h" #include "src/builtins/builtins.h" #include "src/common/assert-scope.h" #include "src/compiler/wasm-compiler.h" @@ -523,6 +524,7 @@ void StoreImpl::SetHostInfo(i::DirectHandle<i::Object> object, void* info, void* StoreImpl::GetHostInfo(i::DirectHandle<i::Object> key, const i::DisallowGarbageCollection& no_gc V8_LIFETIME_BOUND) { + v8::Isolate::Scope isolate_scope(isolate()); PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate()); i::Tagged<i::Object> raw = i::Cast<i::EphemeronHashTable>(host_info_map_->table())->Lookup(key); @@ -1253,7 +1255,7 @@ WASM_EXPORT auto Module::make(Store* store_abs, const vec<byte_t>& binary) v8::Isolate::Scope isolate_scope(store->isolate()); i::HandleScope scope(isolate); CheckAndHandleInterrupts(isolate); - v8::base::OwnedVector<const uint8_t> bytes = v8::base::OwnedCopyOf( + v8::base::UniqueArray<const uint8_t> bytes = v8::base::UniqueCopyOf( reinterpret_cast<const uint8_t*>(binary.get()), binary.size()); i::wasm::WasmEnabledFeatures features = i::wasm::WasmEnabledFeatures::FromIsolate(isolate); @@ -1271,6 +1273,9 @@ WASM_EXPORT auto Module::make(Store* store_abs, const vec<byte_t>& binary) } WASM_EXPORT auto Module::imports() const -> ownvec<ImportType> { + i::Isolate* isolate = impl(this)->isolate(); + v8::Isolate::Scope isolate_scope(reinterpret_cast<v8::Isolate*>(isolate)); + PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate); i::CppGCManaged<i::wasm::NativeModule>::Ptr native_module = impl(this)->v8_object()->native_module(); const i::wasm::WasmModule* module = native_module->module(); @@ -1364,16 +1369,13 @@ WASM_EXPORT auto Module::deserialize(Store* store_abs, size_t binary_size = static_cast<size_t>(ReadLebU64(&ptr)); ptrdiff_t size_size = ptr - serialized.get(); size_t serial_size = serialized.size() - size_size - binary_size; - v8::base::OwnedVector<const uint8_t> wire_bytes = - v8::base::OwnedCopyOf(reinterpret_cast<const uint8_t*>(ptr), binary_size); + v8::base::UniqueArray<const uint8_t> wire_bytes = v8::base::UniqueCopyOf( + reinterpret_cast<const uint8_t*>(ptr), binary_size); i::DirectHandle<i::WasmModuleObject> module_obj; if (serial_size > 0) { // The C-API does not allow passing compile imports. // We thus use an empty `CompileTimeImports` object, analogous to module // creation. - // Note that in contrast to the JS API, this does not handle different - // denormals flushing modes (see base::FPU::GetFlushDenormals / - // `CompileTimeImport::kDisableDenormalFloats`). i::wasm::CompileTimeImports compile_imports; i::wasm::WasmEnabledFeatures features = i::wasm::WasmEnabledFeatures::FromIsolate(isolate); @@ -2328,7 +2330,9 @@ WASM_EXPORT auto Memory::make(Store* store_abs, const MemoryType* type) } WASM_EXPORT auto Memory::type() const -> own<MemoryType> { - PtrComprCageAccessScope ptr_compr_cage_access_scope(impl(this)->isolate()); + i::Isolate* isolate = impl(this)->isolate(); + v8::Isolate::Scope isolate_scope(reinterpret_cast<v8::Isolate*>(isolate)); + PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate); i::DirectHandle<i::WasmMemoryObject> memory = impl(this)->v8_object(); uint32_t min = static_cast<uint32_t>(memory->backing_store()->byte_length() / i::wasm::kWasmPageSize); diff --git a/deps/v8/src/wasm/canonical-types.cc b/deps/v8/src/wasm/canonical-types.cc index dd57b62de6db..01fd09718049 100644 --- a/deps/v8/src/wasm/canonical-types.cc +++ b/deps/v8/src/wasm/canonical-types.cc @@ -258,7 +258,7 @@ void TypeCanonicalizer::AddPredefinedTypes() { DCHECK_EQ(index.index, canonical_singleton_groups_.size()); static constexpr bool kMutable = true; CanonicalArrayType* type = - zone_.New<CanonicalArrayType>(element_type, kMutable); + zone_.New<CanonicalArrayType>(element_type, kMutable, sharedness); AddPredefinedSingletonGroup( index, CanonicalType(type, kNoSuper, kFinal, sharedness)); } @@ -479,10 +479,11 @@ TypeCanonicalizer::CanonicalType TypeCanonicalizer::CanonicalizeTypeDef( CanonicalizeTypeIndex(type.describes), type.is_final, type.is_shared); } case TypeDefinition::kArray: { + DCHECK_EQ(type.array_type->is_shared(), type.is_shared); CanonicalValueType element_type = CanonicalizeValueType(type.array_type->element_type()); CanonicalArrayType* array_type = zone_.New<CanonicalArrayType>( - element_type, type.array_type->mutability()); + element_type, type.array_type->mutability(), type.is_shared); return CanonicalType(array_type, supertype, type.is_final, type.is_shared); } @@ -621,6 +622,9 @@ SharedFlag TypeCanonicalizer::IsShared(CanonicalTypeIndex index) const { bool TypeCanonicalizer::has_descriptor(CanonicalTypeIndex index) const { return canonical_types_[index]->descriptor.valid(); } +bool TypeCanonicalizer::is_descriptor(CanonicalTypeIndex index) const { + return canonical_types_[index]->describes.valid(); +} #ifdef DEBUG bool TypeCanonicalizer::Contains(const CanonicalSig* sig) const { diff --git a/deps/v8/src/wasm/canonical-types.h b/deps/v8/src/wasm/canonical-types.h index 503e037befd1..f21e3989ef74 100644 --- a/deps/v8/src/wasm/canonical-types.h +++ b/deps/v8/src/wasm/canonical-types.h @@ -145,6 +145,7 @@ class TypeCanonicalizer { SharedFlag IsShared(CanonicalTypeIndex index) const; bool has_descriptor(CanonicalTypeIndex index) const; + bool is_descriptor(CanonicalTypeIndex index) const; // TODO(manoskouk): Implement a fast version of this if we have evidence that // it is needed. @@ -158,7 +159,8 @@ class TypeCanonicalizer { return depth; } - bool IsHeapSubtype(CanonicalTypeIndex sub, CanonicalTypeIndex super) const; + V8_EXPORT_PRIVATE bool IsHeapSubtype(CanonicalTypeIndex sub, + CanonicalTypeIndex super) const; bool IsCanonicalSubtype_Locked(CanonicalTypeIndex sub_index, CanonicalTypeIndex super_index) const; diff --git a/deps/v8/src/wasm/compilation-hints-generation.cc b/deps/v8/src/wasm/compilation-hints-generation.cc index e0b4a48bc2a9..b5a4b0653413 100644 --- a/deps/v8/src/wasm/compilation-hints-generation.cc +++ b/deps/v8/src/wasm/compilation-hints-generation.cc @@ -4,7 +4,10 @@ #include "src/wasm/compilation-hints-generation.h" +#include <array> + #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-module.h" @@ -28,7 +31,7 @@ void EmitCompilationHintsToBuffer(ZoneBuffer& buffer, buffer.write_u8(kUnknownSectionCode); size_t section_size_offset = buffer.reserve_u32v(); size_t section_body_begin = buffer.offset(); - buffer.write_string(base::StaticCharVector(kCompilationPriorityString)); + buffer.write_string(kCompilationPriorityString); uint32_t num_functions = 0; size_t num_functions_offset = buffer.reserve_u32v(); for (uint32_t func_index = module->num_imported_functions; @@ -73,7 +76,7 @@ void EmitCompilationHintsToBuffer(ZoneBuffer& buffer, buffer.write_u8(kUnknownSectionCode); size_t section_size_offset = buffer.reserve_u32v(); size_t section_body_begin = buffer.offset(); - buffer.write_string(base::StaticCharVector(kInstructionFrequenciesString)); + buffer.write_string(kInstructionFrequenciesString); uint32_t num_functions = 0; size_t num_functions_offset = buffer.reserve_u32v(); @@ -132,7 +135,7 @@ void EmitCompilationHintsToBuffer(ZoneBuffer& buffer, buffer.write_u8(kUnknownSectionCode); size_t section_size_offset = buffer.reserve_u32v(); size_t section_body_begin = buffer.offset(); - buffer.write_string(base::StaticCharVector(kCallTargetsString)); + buffer.write_string(kCallTargetsString); uint32_t num_functions = 0; size_t num_functions_offset = buffer.reserve_u32v(); @@ -205,13 +208,13 @@ void WriteCompilationHintsToFile(ZoneBuffer& buffer, // Write compilation hints to file. uint32_t hash = static_cast<uint32_t>(GetWireBytesHash(native_module->wire_bytes())); - base::EmbeddedVector<char, 48> filename; - SNPrintF(filename, "compilation-hints-wasm-%08x.wasm-no-header", hash); + std::array<char, 48> filename; + base::SNPrintF(filename, "compilation-hints-wasm-%08x.wasm-no-header", hash); - base::OwnedVector<uint8_t> data = base::OwnedCopyOf(buffer); + base::UniqueArray<uint8_t> data = base::UniqueCopyOf(buffer); - if (FILE* file = base::OS::FOpen(filename.begin(), "wb")) { - PrintF("Emitting compilation hints to file '%s'\n", filename.begin()); + if (FILE* file = base::OS::FOpen(filename.data(), "wb")) { + PrintF("Emitting compilation hints to file '%s'\n", filename.data()); size_t written = fwrite(data.begin(), 1, data.size(), file); CHECK_EQ(written, data.size()); base::Fclose(file); diff --git a/deps/v8/src/wasm/constant-expression-interface.cc b/deps/v8/src/wasm/constant-expression-interface.cc index c6f0e51196f4..7c2a8859a951 100644 --- a/deps/v8/src/wasm/constant-expression-interface.cc +++ b/deps/v8/src/wasm/constant-expression-interface.cc @@ -60,20 +60,26 @@ void ConstantExpressionInterface::UnOp(FullDecoder* decoder, WasmOpcode opcode, if (!generate_value()) return; switch (opcode) { case kExprExternConvertAny: { - result->runtime_value = - WasmValue(WasmToJSObject(isolate_, input.runtime_value.to_ref()), - CanonicalValueType::RefMaybeNull(kWasmExternRef, - input.type.nullability())); + result->runtime_value = WasmValue( + // We should not unshare strings; otherwise we might end up with an + // unshared string in a shared externref field. Note: for non-shared + // anyref it is not possible to get a shared string here, because that + // could only come from any.convert_extern, or via the JS->Wasm + // boundary; but JS strings are unshared. + WasmToJSObject(isolate_, input.runtime_value.to_ref(), + kKeepSharedStrings), + CanonicalValueType::RefMaybeNull(CanonicalValueType{result->type}, + input.type.nullability())); break; } case kExprAnyConvertExtern: { const char* error_message = nullptr; - result->runtime_value = - WasmValue(JSToWasmObject(isolate_, input.runtime_value.to_ref(), - kWasmAnyRef, &error_message) - .ToHandleChecked(), - CanonicalValueType::RefMaybeNull(kWasmAnyRef, - input.type.nullability())); + result->runtime_value = WasmValue( + JSToWasmObject(isolate_, input.runtime_value.to_ref(), + CanonicalValueType{result->type}, &error_message) + .ToHandleChecked(), + CanonicalValueType::RefMaybeNull(CanonicalValueType{result->type}, + input.type.nullability())); break; } default: @@ -175,9 +181,13 @@ DirectHandle<Map> ConstantExpressionInterface::GetRtt( error_ = MessageTemplate::kWasmTrapNullDereference; return {}; } - DCHECK(IsWasmStruct(*maybe_obj)); DCHECK_EQ(desc.type().ref_index(), module_->canonical_type_id(type.descriptor)); + if (v8_flags.wasm_merged_descriptors) { + DCHECK(IsWasmCustomMap(*maybe_obj)); + return Cast<WasmCustomMap>(maybe_obj); + } + DCHECK(IsWasmStruct(*maybe_obj)); return direct_handle(Cast<WasmStruct>(*maybe_obj)->described_rtt(), isolate_); } @@ -200,7 +210,8 @@ void ConstantExpressionInterface::StructNew(FullDecoder* decoder, DirectHandle<Map> rtt = GetRtt(imm.index, type, descriptor); if (rtt.is_null()) return; // Trap (descriptor was null). - DirectHandle<WasmStruct> obj; + DirectHandle<HeapObject> obj; + int header_size; if (type.is_descriptor()) { // TODO(14616): Support shared custom descriptors. if (type.is_shared) UNIMPLEMENTED(); @@ -208,26 +219,37 @@ void ConstantExpressionInterface::StructNew(FullDecoder* decoder, struct_type->first_field_can_be_prototype() ? args[0].runtime_value.to_ref() : direct_handle(Smi::zero(), isolate_); - obj = WasmStruct::AllocateDescriptorUninitialized( - isolate_, trusted_instance_data_, imm.index, rtt, first_field); + if (v8_flags.wasm_merged_descriptors) { + obj = WasmCustomMap::AllocateUninitialized( + isolate_, trusted_instance_data_, imm.index, rtt, first_field); + header_size = WasmCustomMap::kHeaderSize; + } else { + obj = WasmStruct::AllocateDescriptorUninitialized( + isolate_, trusted_instance_data_, imm.index, rtt, first_field); + header_size = WasmStruct::kHeaderSize; + } } else { // Pretenure, because we expect values in globals to be long-lived. obj = isolate_->factory()->NewWasmStructUninitialized( struct_type, rtt, type.is_shared ? AllocationType::kSharedOld : AllocationType::kOld); + header_size = WasmStruct::kHeaderSize; } DisallowGarbageCollection no_gc; // Must initialize fields first. SharedObjectConditionalSafePublishGuard publish_guard(*obj, type.is_shared); for (uint32_t i = 0; i < struct_type->field_count(); i++) { - int offset = struct_type->field_offset(i); + int offset = header_size + struct_type->field_offset(i); if (struct_type->field(i).is_numeric()) { uint8_t* address = - reinterpret_cast<uint8_t*>(obj->RawFieldAddress(offset)); + reinterpret_cast<uint8_t*>(obj->GetFieldAddress(offset)); args[i].runtime_value.Packed(struct_type->field(i)).CopyTo(address); } else { - obj->SetTaggedFieldValue(offset, *args[i].runtime_value.to_ref()); + Tagged<Object> value = *args[i].runtime_value.to_ref(); + TaggedField<Object>::store(*obj, offset, value); + WriteBarrier::ForValue(*obj, obj->RawMaybeWeakField(offset), value, + UPDATE_WRITE_BARRIER); } } @@ -308,35 +330,44 @@ void ConstantExpressionInterface::StructNewDefault( DirectHandle<Map> rtt = GetRtt(imm.index, type, descriptor); if (rtt.is_null()) return; // Trap (descriptor was null). - DirectHandle<WasmStruct> obj; + DirectHandle<HeapObject> obj; + int header_size; if (type.is_descriptor()) { // TODO(14616): Implement shared custom descriptors. if (type.is_shared) UNIMPLEMENTED(); DirectHandle<Object> first_field(Smi::zero(), isolate_); - obj = WasmStruct::AllocateDescriptorUninitialized( - isolate_, trusted_instance_data_, imm.index, rtt, first_field); + if (v8_flags.wasm_merged_descriptors) { + obj = WasmCustomMap::AllocateUninitialized( + isolate_, trusted_instance_data_, imm.index, rtt, first_field); + header_size = WasmCustomMap::kHeaderSize; + } else { + obj = WasmStruct::AllocateDescriptorUninitialized( + isolate_, trusted_instance_data_, imm.index, rtt, first_field); + header_size = WasmStruct::kHeaderSize; + } } else { // Pretenure, because we expect values in globals to be long-lived. obj = isolate_->factory()->NewWasmStructUninitialized( struct_type, rtt, type.is_shared ? AllocationType::kSharedOld : AllocationType::kOld); + header_size = WasmStruct::kHeaderSize; } DisallowGarbageCollection no_gc; // Must initialize fields first. SharedObjectConditionalSafePublishGuard publish_guard(*obj, type.is_shared); for (uint32_t i = 0; i < struct_type->field_count(); i++) { - int offset = struct_type->field_offset(i); + int offset = header_size + struct_type->field_offset(i); ValueType ftype = struct_type->field(i); if (ftype.is_numeric()) { uint8_t* address = - reinterpret_cast<uint8_t*>(obj->RawFieldAddress(offset)); + reinterpret_cast<uint8_t*>(obj->GetFieldAddress(offset)); DefaultValueForType(ftype, isolate_, module_) .Packed(ftype) .CopyTo(address); } else { // No write barrier needed, as read-only-space objects never move. - TaggedField<Object, WasmStruct::kHeaderSize>::store( + TaggedField<Object>::store( *obj, offset, *DefaultValueForType(ftype, isolate_, module_).to_ref()); } diff --git a/deps/v8/src/wasm/decoder.h b/deps/v8/src/wasm/decoder.h index 6dc12334345d..bc11f0db4835 100644 --- a/deps/v8/src/wasm/decoder.h +++ b/deps/v8/src/wasm/decoder.h @@ -9,6 +9,7 @@ #error This header should only be included if WebAssembly is enabled. #endif // !V8_ENABLE_WEBASSEMBLY +#include <array> #include <cinttypes> #include <cstdarg> #include <memory> @@ -426,13 +427,13 @@ class Decoder { // Only report the first error. if (!ok()) return; constexpr int kMaxErrorMsg = 256; - base::EmbeddedVector<char, kMaxErrorMsg> buffer; + std::array<char, kMaxErrorMsg> buffer; va_list args; va_start(args, format); int len = base::VSNPrintF(buffer, format, args); va_end(args); CHECK_LT(0, len); - error_ = {offset, {buffer.begin(), static_cast<size_t>(len)}}; + error_ = {offset, {buffer.data(), static_cast<size_t>(len)}}; onFirstError(); } diff --git a/deps/v8/src/wasm/function-body-decoder-impl.h b/deps/v8/src/wasm/function-body-decoder-impl.h index 3818b05ab2c8..73deffe16a39 100644 --- a/deps/v8/src/wasm/function-body-decoder-impl.h +++ b/deps/v8/src/wasm/function-body-decoder-impl.h @@ -14,6 +14,8 @@ #include <inttypes.h> +#include <bit> + #include "src/base/bounds.h" #include "src/base/small-vector.h" #include "src/base/strings.h" @@ -208,6 +210,18 @@ V8_INLINE void DecodeError(Decoder* decoder, const char* str, Args&&... args) { namespace value_type_reader { +#ifdef V8_ENABLE_DRUMBRAKE +template <typename ValidationTag> +bool IsExnRefUnsupportedByDrumBrake(Decoder* decoder, const uint8_t* pc) { + if (!VALIDATE(!v8_flags.wasm_jitless || v8_flags.drumbrake_exnref)) { + DecodeError<ValidationTag>(decoder, pc, + "exnref not supported by the Wasm interpreter"); + return true; + } + return false; +} +#endif // V8_ENABLE_DRUMBRAKE + template <typename ValidationTag> std::pair<HeapType, uint32_t> read_heap_type(Decoder* decoder, const uint8_t* pc, @@ -218,12 +232,15 @@ std::pair<HeapType, uint32_t> read_heap_type(Decoder* decoder, Exactness exactness = Exactness::kAnySubtype; uint32_t type_index; if (heap_index < 0) { - int64_t min_1_byte_leb128 = -64; - if (!VALIDATE(heap_index >= min_1_byte_leb128)) { + // Concrete type indices (heap_index >= 0) are encoded as multi-byte s33 + // LEB128, whereas abstract heap types and type prefixes ('shared', 'exact') + // are encoded as single bytes. + if (!VALIDATE(length == 1)) { DecodeError<ValidationTag>(decoder, pc, "Unknown heap type %" PRId64, heap_index); return {kWasmBottom, length}; } + DCHECK_GE(heap_index, -64); uint8_t uint_7_mask = 0x7F; uint8_t code = static_cast<ValueTypeCode>(heap_index) & uint_7_mask; SharedFlag is_shared = SharedFlag{false}; @@ -234,8 +251,10 @@ std::pair<HeapType, uint32_t> read_heap_type(Decoder* decoder, kSharedFlagCode); return {kWasmBottom, length}; } - code = decoder->read_u8<ValidationTag>(pc + length, "heap type"); - length++; + // 'shared' can only be followed by an abstract heap type, which is + // encoded as a single byte. + code = decoder->read_u8<ValidationTag>(pc + 1, "heap type"); + length = 2; is_shared = SharedFlag{true}; } switch (code) { @@ -261,6 +280,11 @@ std::pair<HeapType, uint32_t> read_heap_type(Decoder* decoder, return {HeapType::from_code(code, is_shared), length}; case kNoExnCode: case kExnRefCode: +#ifdef V8_ENABLE_DRUMBRAKE + if (IsExnRefUnsupportedByDrumBrake<ValidationTag>(decoder, pc)) { + return {kWasmBottom, 0}; + } +#endif // V8_ENABLE_DRUMBRAKE if (!VALIDATE(!detected->has_legacy_eh() || v8_flags.wasm_allow_mixed_eh_for_testing)) { DecodeError<ValidationTag>( @@ -331,6 +355,16 @@ std::pair<HeapType, uint32_t> read_heap_type(Decoder* decoder, "--wasm-custom-descriptors"); return {kWasmBottom, 0}; } + if (!VALIDATE(!is_shared)) { + DecodeError<ValidationTag>( + decoder, pc, + "invalid heap type 'shared exact', 'shared' is only allowed on " + "abstract heap types"); + return {kWasmBottom, 0}; + } + // 'exact' is a single-byte prefix followed by a concrete type index + // encoded as a (potentially multi-byte) u32v. + DCHECK_EQ(1, length); auto [nested_index, index_length] = decoder->read_u32v<ValidationTag>(pc + 1, "type index"); type_index = nested_index; @@ -344,6 +378,7 @@ std::pair<HeapType, uint32_t> read_heap_type(Decoder* decoder, return {kWasmBottom, length}; } } else { + // Concrete type indices are encoded as non-negative s33 LEB128 values. type_index = static_cast<uint32_t>(heap_index); } if (!VALIDATE(type_index < kV8MaxWasmTypes)) { @@ -390,6 +425,11 @@ std::pair<ValueType, uint32_t> read_value_type(Decoder* decoder, 1}; case kNoExnCode: case kExnRefCode: +#ifdef V8_ENABLE_DRUMBRAKE + if (IsExnRefUnsupportedByDrumBrake<ValidationTag>(decoder, pc)) { + return {kWasmBottom, 0}; + } +#endif // V8_ENABLE_DRUMBRAKE if (!VALIDATE(!detected->has_legacy_eh() || v8_flags.wasm_allow_mixed_eh_for_testing)) { DecodeError<ValidationTag>( @@ -427,7 +467,8 @@ std::pair<ValueType, uint32_t> read_value_type(Decoder* decoder, HeapType::from_code(code, SharedFlag{false}).name().c_str()); return {kWasmBottom, 0}; } - return {ValueType::Ref(HeapType::from_code(code, SharedFlag{false})), 1}; + return {ValueType::RefNull(HeapType::from_code(code, SharedFlag{false})), + 1}; } case kContRefCode: case kNoContCode: @@ -465,7 +506,7 @@ std::pair<ValueType, uint32_t> read_value_type(Decoder* decoder, case kS128Code: { if (!VALIDATE(CheckHardwareSupportsSimd())) { if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("Aborting on missing Wasm SIMD support"); + base::FatalNoSecurityImpact("Aborting on missing Wasm SIMD support"); } DecodeError<ValidationTag>(decoder, pc, "Wasm SIMD unsupported"); return {kWasmBottom, 0}; @@ -751,7 +792,7 @@ struct SelectTypeImmediate { SelectTypeImmediate(WasmEnabledFeatures enabled, WasmDetectedFeatures* detected, Decoder* decoder, const uint8_t* pc, ValidationTag = {}) { - uint8_t num_types; + uint32_t num_types; std::tie(num_types, length) = decoder->read_u32v<ValidationTag>(pc, "number of select types"); if (!VALIDATE(num_types == 1)) { @@ -792,14 +833,15 @@ struct BlockTypeImmediate { std::tie(block_type, length) = decoder->read_i33v<ValidationTag>(pc, "block type"); if (block_type < 0) { - // All valid negative types are 1 byte in length, so we check against the - // minimum 1-byte LEB128 value. - constexpr int64_t min_1_byte_leb128 = -64; - if (!VALIDATE(block_type >= min_1_byte_leb128)) { + // Concrete type indices (block_type >= 0) are encoded as multi-byte s33 + // LEB128, whereas kVoidCode (0x40) and value type opcodes are single + // bytes. + if (!VALIDATE(length == 1)) { DecodeError<ValidationTag>(decoder, pc, "invalid block type %" PRId64, block_type); return; } + DCHECK_GE(block_type, -64); if (static_cast<ValueTypeCode>(block_type & 0x7F) != kVoidCode) { sig = FunctionSig{1, 0, single_return_sig_storage}; std::tie(single_return_sig_storage[0], length) = @@ -1803,8 +1845,8 @@ class FastZoneVector { private: V8_NOINLINE V8_PRESERVE_MOST void Grow(int slots_needed, Zone* zone) { - size_t new_capacity = std::max( - size_t{8}, base::bits::RoundUpToPowerOfTwo(size() + slots_needed)); + size_t new_capacity = + std::max(size_t{8}, std::bit_ceil(size_t{size()} + slots_needed)); CHECK_GE(kMaxUInt32, new_capacity); DCHECK_LT(capacity_end_ - begin_, new_capacity); T* new_begin = zone->template AllocateArray<T>(new_capacity); @@ -3794,6 +3836,12 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { } DECODE(TryTable) { +#ifdef V8_ENABLE_DRUMBRAKE + if (value_type_reader::IsExnRefUnsupportedByDrumBrake<ValidationTag>( + this, this->pc_)) { + return 0; + } +#endif // V8_ENABLE_DRUMBRAKE this->detected_->add_exnref(); if (!VALIDATE(!this->detected_->has_legacy_eh() || v8_flags.wasm_allow_mixed_eh_for_testing)) { @@ -3877,6 +3925,12 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { } DECODE(ThrowRef) { +#ifdef V8_ENABLE_DRUMBRAKE + if (value_type_reader::IsExnRefUnsupportedByDrumBrake<ValidationTag>( + this, this->pc_)) { + return 0; + } +#endif // V8_ENABLE_DRUMBRAKE this->detected_->add_exnref(); if (!VALIDATE(!this->detected_->has_legacy_eh() || v8_flags.wasm_allow_mixed_eh_for_testing)) { @@ -5010,14 +5064,14 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { const base::Vector<const ValueType> cont_args = cont_sig->parameters(); if (!VALIDATE(cont_args.size() >= 1 && - IsSubtypeOf(cont_args.last(), kWasmContRef, this->module_))) { + IsSubtypeOf(cont_args.back(), kWasmContRef, this->module_))) { this->DecodeError( "expecting a (ref null? cont) as last parameter of type %d", contimm.index.index); return 0; } - const ValueType return_type = cont_args.last(); + const ValueType return_type = cont_args.back(); if (!VALIDATE(return_type.has_index() && this->module_->has_cont_type(return_type.ref_index()))) { @@ -5035,7 +5089,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { this->DecodeError( "tag %d's return types should be a subtype of return continuation " "%d's return types", - tagimm.index, cont_args.last().ref_index().index); + tagimm.index, return_type.ref_index().index); return 0; } @@ -5066,7 +5120,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { this->detected_->add_simd(); if (!CheckHardwareSupportsSimd()) { if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("Aborting on missing Wasm SIMD support"); + base::FatalNoSecurityImpact("Aborting on missing Wasm SIMD support"); } this->DecodeError("Wasm SIMD unsupported"); return 0; @@ -6299,8 +6353,9 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { // All other generic types would have failed validation above. DCHECK(ref.type.has_index()); // Exactness is only propagated if the actual type on the stack - // exactly matched the type immediate. - if (ref.type.ref_index() != imm.index) { + // is equivalent to the type immediate. + if (!EquivalentIndices(ref.type.ref_index(), imm.index, + this->module_)) { result_exactness = kAnySubtype; } } @@ -7578,9 +7633,15 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { auto [array_obj, index] = Pop(ValueType::RefNull(imm.heap_type()), kWasmI32); Value* value = Push(element_type.Unpacked()); - CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayGet, array_obj, imm, index, - opcode == kExprArrayAtomicGetS, - value); + const bool is_signed = opcode == kExprArrayAtomicGetS; + if (array_obj.type.is_shared()) { + CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayAtomicGet, array_obj, imm, + index, is_signed, + memory_order.order, value); + } else { + CALL_INTERFACE_IF_OK_AND_REACHABLE(ArrayGet, array_obj, imm, index, + is_signed, value); + } return opcode_length + memory_order.length + imm.length; } case kExprArrayAtomicSet: { @@ -7867,7 +7928,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { "invalid numeric opcode: 0x%x, enable with --wasm-fp16", opcode); return 0; } - return DecodeLoadMem(LoadType::kF32LoadF16, 2); + return DecodeLoadMem(LoadType::kF32LoadF16, opcode_length); } case kExprF32StoreMemF16: { if (!this->enabled_.has_fp16()) { @@ -7875,7 +7936,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> { "invalid numeric opcode: 0x%x, enable with --wasm-fp16", opcode); return 0; } - return DecodeStoreMem(StoreType::kF32StoreF16, 2); + return DecodeStoreMem(StoreType::kF32StoreF16, opcode_length); } case kExprI64Add128: { CHECK_PROTOTYPE_OPCODE(wide_arithmetic); diff --git a/deps/v8/src/wasm/function-compiler.cc b/deps/v8/src/wasm/function-compiler.cc index d7f7bc078978..abc5b5ec30d7 100644 --- a/deps/v8/src/wasm/function-compiler.cc +++ b/deps/v8/src/wasm/function-compiler.cc @@ -6,7 +6,6 @@ #include <optional> -#include "src/base/fpu.h" #include "src/codegen/compiler.h" #include "src/codegen/optimized-compilation-info.h" #include "src/compiler/turboshaft/wasm-turboshaft-compiler.h" @@ -177,10 +176,6 @@ void WasmCompilationUnit::CompileWasmFunction(NativeModule* native_module, WasmCompilationUnit unit(function->func_index, tier, kNotForDebugging, kAlreadyValidated); CompilationEnv env = CompilationEnv::ForModule(native_module); - base::FlushDenormalsScope disable_denormals( - tier == ExecutionTier::kTurbofan && - native_module->compile_imports().contains( - CompileTimeImport::kDisableDenormalFloats)); WasmCompilationResult result = unit.ExecuteCompilation( &env, native_module->compilation_state()->GetWireBytesStorage().get(), native_module->counter_updates(), detected); diff --git a/deps/v8/src/wasm/function-compiler.h b/deps/v8/src/wasm/function-compiler.h index 76dfc9ce3082..736e3e09159e 100644 --- a/deps/v8/src/wasm/function-compiler.h +++ b/deps/v8/src/wasm/function-compiler.h @@ -11,6 +11,7 @@ #include <memory> +#include "src/base/unique-array.h" #include "src/codegen/assembler.h" #include "src/codegen/code-desc.h" #include "src/codegen/compiler.h" @@ -79,11 +80,11 @@ struct WasmCompilationResult { uint32_t frame_slot_count = 0; uint32_t ool_spill_count = 0; uint32_t tagged_parameter_slots = 0; - base::OwnedVector<uint8_t> source_positions; - base::OwnedVector<uint8_t> inlining_positions; - base::OwnedVector<uint8_t> trapping_instructions_data; - base::OwnedVector<uint8_t> deopt_data; - base::OwnedVector<uint8_t> effect_handlers; + base::UniqueArray<uint8_t> source_positions; + base::UniqueArray<uint8_t> inlining_positions; + base::UniqueArray<uint8_t> trapping_instructions_data; + base::UniqueArray<uint8_t> deopt_data; + base::UniqueArray<uint8_t> effect_handlers; std::unique_ptr<AssumptionsJournal> assumptions; std::unique_ptr<LiftoffFrameDescriptionForDeopt> liftoff_frame_descriptions; int func_index = kAnonymousFuncIndex; diff --git a/deps/v8/src/wasm/fuzzing/random-module-generation.cc b/deps/v8/src/wasm/fuzzing/random-module-generation.cc index 10af875989fd..55f681a32468 100644 --- a/deps/v8/src/wasm/fuzzing/random-module-generation.cc +++ b/deps/v8/src/wasm/fuzzing/random-module-generation.cc @@ -443,8 +443,7 @@ class GeneratorAlternativesPerOption { wasmgc_(ConcatArrays(mvp, wasmgc)), all_(ConcatArrays(mvp, ConcatArrays(simd, wasmgc))) {} - constexpr base::Vector<const GenerateFn> GetAlternatives( - WasmModuleGenerationOptions options) const { + constexpr auto GetAlternatives(WasmModuleGenerationOptions options) const { switch (options.ToIntegral()) { case 0: // 0 return base::VectorOf(mvp_); @@ -738,7 +737,7 @@ class BodyGen { std::copy_n(type->parameters().begin(), type->parameter_count(), block_returns.begin()); } - if (has_ref) block_returns.last() = kWasmExnRef; + if (has_ref) block_returns.back() = kWasmExnRef; { BlockScope block(this, kExprBlock, param_types, block_returns, block_returns); @@ -2535,7 +2534,7 @@ class BodyGen { if (break_types.empty()) { return false; } - ValueType break_type = break_types.last(); + ValueType break_type = break_types.back(); if (!break_type.is_ref()) { return false; } @@ -4629,7 +4628,8 @@ class ModuleGen { // element type. type = builder_->GetArrayType(supertype)->element_type(); } - ArrayType* array_fuz = zone_->New<ArrayType>(type, true); + ArrayType* array_fuz = + zone_->New<ArrayType>(type, true, SharedFlag{false}); // TODO(14034): Generate some final types too. ModuleTypeIndex index = builder_->AddArrayType(array_fuz, false, supertype); @@ -4693,8 +4693,7 @@ class ModuleGen { for (auto& import : *imports) { import.sig_index = builder_->ForceAddSignature(import.sig, kIsFinal); uint32_t index = - builder_->AddImport(base::VectorOf(import.name), import.sig, - base::VectorOf(import.module_name)); + builder_->AddImport(import.name, import.sig, import.module_name); import.index = index; } imports_ = imports; @@ -4750,20 +4749,16 @@ class ModuleGen { static constexpr FunctionSig kSig_into_a8(1, 3, kReps_into_a8); static constexpr FunctionSig kSig_to_a8(1, 1, kReps_to_a8); - static constexpr base::Vector<const char> kJsString = - base::StaticCharVector("wasm:js-string"); - static constexpr base::Vector<const char> kTextDecoder = - base::StaticCharVector("wasm:text-decoder"); - static constexpr base::Vector<const char> kTextEncoder = - base::StaticCharVector("wasm:text-encoder"); + static constexpr std::string_view kJsString = "wasm:js-string"; + static constexpr std::string_view kTextDecoder = "wasm:text-decoder"; + static constexpr std::string_view kTextEncoder = "wasm:text-encoder"; // The signatures of compile-time imports must be defined in singleton // recgroups, so we can't allow them to get deduplicated against existing // signatures that might be in nontrivial recgroups. static constexpr bool kForceNewSig = true; #define STRINGFUNC(name, sig, group) \ - strings.name = \ - builder_->AddImport(base::CStrVector(#name), &sig, group, kForceNewSig) + strings.name = builder_->AddImport(#name, &sig, group, kForceNewSig) STRINGFUNC(cast, kSig_e_r, kJsString); STRINGFUNC(test, kSig_i_r, kJsString); @@ -5240,10 +5235,10 @@ base::Vector<uint8_t> GenerateRandomWasmModule( static constexpr ModuleTypeIndex kArrayI8{0}; static constexpr ModuleTypeIndex kArrayI16{1}; { - ArrayType* a8 = zone->New<ArrayType>(kWasmI8, 1); + ArrayType* a8 = zone->New<ArrayType>(kWasmI8, 1, SharedFlag{false}); CHECK_EQ(kArrayI8, builder.AddArrayType(a8, true, kNoSuperType)); array_types.push_back(kArrayI8); - ArrayType* a16 = zone->New<ArrayType>(kWasmI16, 1); + ArrayType* a16 = zone->New<ArrayType>(kWasmI16, 1, SharedFlag{false}); CHECK_EQ(kArrayI16, builder.AddArrayType(a16, true, kNoSuperType)); array_types.push_back(kArrayI16); } @@ -5347,9 +5342,9 @@ base::Vector<uint8_t> GenerateRandomWasmModule( gen_body.Generate(return_types, &function_range); f->Emit(kExprEnd); if (module_exports) { - builder.AddExport(base::CStrVector((*module_exports)[i].name.c_str()), f); + builder.AddExport((*module_exports)[i].name, f); } else if (i == 0) { - builder.AddExport(base::CStrVector("main"), f); + builder.AddExport("main", f); } } @@ -5441,7 +5436,7 @@ base::Vector<uint8_t> GenerateWasmModuleForInitExpressions( (module_range.get<uint8_t>() % existing_array_types)}; type = builder.GetArrayType(supertype)->element_type(); } - ArrayType* array_fuz = zone->New<ArrayType>(type, true); + ArrayType* array_fuz = zone->New<ArrayType>(type, true, SharedFlag{false}); ModuleTypeIndex index = builder.AddArrayType(array_fuz, false, supertype); array_types.push_back(index); } @@ -5687,10 +5682,10 @@ base::Vector<uint8_t> GenerateWasmModuleForDeopt( static constexpr ModuleTypeIndex kArrayI8{0}; static constexpr ModuleTypeIndex kArrayI16{1}; { - ArrayType* a8 = zone->New<ArrayType>(kWasmI8, true); + ArrayType* a8 = zone->New<ArrayType>(kWasmI8, true, SharedFlag{false}); CHECK_EQ(kArrayI8, builder.AddArrayType(a8, true, kNoSuperType)); array_types.push_back(kArrayI8); - ArrayType* a16 = zone->New<ArrayType>(kWasmI16, true); + ArrayType* a16 = zone->New<ArrayType>(kWasmI16, true, SharedFlag{false}); CHECK_EQ(kArrayI16, builder.AddArrayType(a16, true, kNoSuperType)); array_types.push_back(kArrayI16); } @@ -5782,9 +5777,8 @@ base::Vector<uint8_t> GenerateWasmModuleForDeopt( // Create global for call target index. // Simplification: This global is used to specify the call target at the deopt // point instead of passing the call target around dynamically. - uint32_t global_index = - builder.AddExportedGlobal(kWasmI32, true, WasmInitExpr(0), - base::StaticCharVector("call_target_index")); + uint32_t global_index = builder.AddExportedGlobal( + kWasmI32, true, WasmInitExpr(0), "call_target_index"); // Create inlinee bodies. for (int i = 0; i < num_inlinees; ++i) { @@ -5839,7 +5833,7 @@ base::Vector<uint8_t> GenerateWasmModuleForDeopt( } f->Emit(kExprEnd); - builder.AddExport(base::StaticCharVector("main"), f); + builder.AddExport("main", f); } // Create call target bodies. @@ -6083,7 +6077,7 @@ base::Vector<uint8_t> GenerateWasmModuleForRevec( } f->Emit(kExprEnd); - if (i == 0) builder.AddExport(base::CStrVector("main"), f); + if (i == 0) builder.AddExport("main", f); } ZoneBuffer buffer{zone}; diff --git a/deps/v8/src/wasm/inlining-tree.h b/deps/v8/src/wasm/inlining-tree.h index 4486db0edb94..1b293b2dfc6d 100644 --- a/deps/v8/src/wasm/inlining-tree.h +++ b/deps/v8/src/wasm/inlining-tree.h @@ -233,7 +233,7 @@ void InliningTree::Inline() { // Feedback found. Populate the `function_calls_` vector with child nodes. const FunctionTypeFeedback& feedback = feedback_it->second; base::Vector<CallSiteFeedback> type_feedback = - feedback.feedback_vector.as_vector(); + feedback.feedback_vector.as_span(); if (!type_feedback.empty()) { DCHECK_EQ(type_feedback.size(), feedback.call_targets.size()); feedback_found_ = true; diff --git a/deps/v8/src/wasm/interpreter/arm64/interpreter-builtins-arm64.cc b/deps/v8/src/wasm/interpreter/arm64/interpreter-builtins-arm64.cc index bb1a7566aee5..04d5afd4bdad 100644 --- a/deps/v8/src/wasm/interpreter/arm64/interpreter-builtins-arm64.cc +++ b/deps/v8/src/wasm/interpreter/arm64/interpreter-builtins-arm64.cc @@ -92,7 +92,7 @@ void LoadFunctionDataAndWasmInstance(MacroAssembler* masm, function_data, FieldMemOperand(shared_function_info, offsetof(SharedFunctionInfo, trusted_function_data_)), - kWasmExportedFunctionDataIndirectPointerTag); + kWasmExportedFunctionDataTrustedPointerTag); shared_function_info = no_reg; LoadWasmInstanceFromFunctionData(masm, function_data, wasm_instance); @@ -851,6 +851,7 @@ void Builtins::Generate_GenericWasmToJSInterpreterWrapper( // Restore after builtin call. __ bind(&finish_param_conversion); + __ Ldr(cp, MemOperand(fp, kContextOffset)); __ Ldr(current_param_slot_offset, MemOperand(fp, kCurrentParamOffset)); __ Add(current_param_slot_offset, current_param_slot_offset, increment); __ Ldr(valuetypes_array_ptr, MemOperand(fp, kValueTypesArrayStartOffset)); diff --git a/deps/v8/src/wasm/interpreter/riscv/interpreter-builtins-riscv.cc b/deps/v8/src/wasm/interpreter/riscv/interpreter-builtins-riscv.cc index f5f3b0248f54..4214fffe3390 100644 --- a/deps/v8/src/wasm/interpreter/riscv/interpreter-builtins-riscv.cc +++ b/deps/v8/src/wasm/interpreter/riscv/interpreter-builtins-riscv.cc @@ -217,7 +217,7 @@ void LoadFunctionDataAndWasmInstance(MacroAssembler* masm, function_data, FieldMemOperand(shared_function_info, offsetof(SharedFunctionInfo, trusted_function_data_)), - kWasmExportedFunctionDataIndirectPointerTag); + kWasmExportedFunctionDataTrustedPointerTag); shared_function_info = no_reg; LoadWasmInstanceFromFunctionData(masm, function_data, wasm_instance); diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter-inl.h b/deps/v8/src/wasm/interpreter/wasm-interpreter-inl.h index d984dc260a7f..a2b563fbb38a 100644 --- a/deps/v8/src/wasm/interpreter/wasm-interpreter-inl.h +++ b/deps/v8/src/wasm/interpreter/wasm-interpreter-inl.h @@ -62,11 +62,10 @@ inline Isolate* WasmInterpreterThread::Activation::GetIsolate() const { inline WasmInterpreterThread::Activation* WasmInterpreterThread::StartActivation(WasmInterpreterRuntime* wasm_runtime, Address frame_pointer, - uint8_t* interpreter_fp, const FrameState& frame_state) { Run(); activations_.emplace_back(std::make_unique<Activation>( - this, wasm_runtime, frame_pointer, interpreter_fp, frame_state)); + this, wasm_runtime, frame_pointer, frame_state)); return activations_.back().get(); } diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime-inl.h b/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime-inl.h index 1bc64acc614c..64805ff9900a 100644 --- a/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime-inl.h +++ b/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime-inl.h @@ -143,7 +143,7 @@ inline size_t WasmInterpreterRuntime::GetMemorySize( } inline size_t WasmInterpreterRuntime::GetMemorySize() const { - return wasm_trusted_instance_data()->memory0_size(); + return wasm_trusted_instance_data()->memory_size(0); } inline void WasmInterpreterRuntime::DataDrop(uint32_t index) { diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.cc b/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.cc index 25766aa55ad1..b0a7d762b0dc 100644 --- a/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.cc +++ b/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.cc @@ -650,10 +650,8 @@ bool WasmInterpreterRuntime::MemoryFill(const uint8_t*& current_code, void WasmInterpreterRuntime::UnpackException( uint32_t* sp, const WasmTag& tag, DirectHandle<Object> exception_object, uint32_t first_param_slot_index, uint32_t first_param_ref_stack_index) { - DirectHandle<Object> values_obj = WasmExceptionPackage::GetExceptionValues( + DirectHandle<FixedArray> encoded_values = GetExceptionValuesField( isolate_, TrustedCast<WasmExceptionPackage>(exception_object)); - SBXCHECK(IsFixedArray(*values_obj)); - DirectHandle<FixedArray> encoded_values = Cast<FixedArray>(values_obj); SBXCHECK_LE(WasmExceptionPackage::GetEncodedSize(module_, &tag), static_cast<uint32_t>(encoded_values->length())); // Decode the exception values from the given exception package and push @@ -717,9 +715,14 @@ void WasmInterpreterRuntime::UnpackException( case kRefNull: { DirectHandle<Object> ref(encoded_values->get(encoded_index++), isolate_); - if (sig->GetParam(i).value_type_code() == wasm::kFuncRefCode && - i::IsNull(*ref)) { - ref = isolate_->factory()->wasm_null(); + // Exception payloads use the same null representation as Wasm values + // (WasmNull for internal types, JS null for extern types). The + // encoded values live in the sandbox, so fail closed on a mismatch: + // a wrong null would bypass the interpreter's typed null checks. + if (sig->GetParam(i).use_wasm_null()) { + SBXCHECK(!i::IsNull(*ref)); + } else { + SBXCHECK(!i::IsWasmNull(*ref)); } StoreWasmRef(first_param_ref_stack_index++, ref); base::WriteUnalignedValue<WasmRef>(reinterpret_cast<Address>(p), ref); @@ -739,6 +742,15 @@ void RedirectCodeToUnwindHandler(const uint8_t*& code) { // Resume execution from s2s_Unwind, which unwinds the Wasm stack frames code = reinterpret_cast<uint8_t*>(&s_unwind_code); } + +// Invalidates the caller's published reentry frame pointer on every return path +// from a callout. A legitimate reentry re-publishes its own frame geometry +// before calling out; one that does not fails BeginExecution's range check +// instead of reusing a stale pointer. +struct InvalidateActivationFrameOnReturn { + WasmInterpreterThread* thread; + ~InvalidateActivationFrameOnReturn() { thread->InvalidateActivationFrame(); } +}; } // namespace // Allocate a new exception. @@ -756,6 +768,31 @@ WasmInterpreterRuntime::CreateWasmExceptionPackage(uint32_t tag_index) const { return exception_object; } +// static +DirectHandle<Object> WasmInterpreterRuntime::GetExceptionTagField( + Isolate* isolate, DirectHandle<WasmExceptionPackage> exception_package) { + // Read the in-object field directly instead of through a property lookup, so + // a rewritten accessor descriptor can't run JS during exception handling. + // WasmExceptionPackage::New stores this field the same way. + Tagged<JSObject> object = Cast<JSObject>(*exception_package); + return direct_handle( + object->InObjectPropertyAtOffset( + object->GetInObjectPropertyOffset(WasmExceptionPackage::kTagIndex)), + isolate); +} + +// static +DirectHandle<FixedArray> WasmInterpreterRuntime::GetExceptionValuesField( + Isolate* isolate, DirectHandle<WasmExceptionPackage> exception_package) { + Tagged<JSObject> object = Cast<JSObject>(*exception_package); + Tagged<Object> values = object->InObjectPropertyAtOffset( + object->GetInObjectPropertyOffset(WasmExceptionPackage::kValuesIndex)); + // The slot offset comes from the map, so check the type before the callers + // encode or decode payload values through it. + SBXCHECK(IsFixedArray(values)); + return direct_handle(Cast<FixedArray>(values), isolate); +} + // Throw a Wasm exception. void WasmInterpreterRuntime::ThrowException(const uint8_t*& code, uint32_t* sp, Tagged<Object> exception_object) { @@ -823,9 +860,8 @@ WasmInterpreterRuntime::HandleException(uint32_t* sp, } else if (IsWasmExceptionPackage(*exception)) { // The exception was thrown by Wasm code and it's wrapped in a // WasmExceptionPackage. - DirectHandle<Object> caught_tag = - WasmExceptionPackage::GetExceptionTag( - isolate_, TrustedCast<WasmExceptionPackage>(exception)); + DirectHandle<Object> caught_tag = GetExceptionTagField( + isolate_, TrustedCast<WasmExceptionPackage>(exception)); DirectHandle<Object> expected_tag( trusted_data->tags_table()->get(catch_handler.tag_index), isolate_); @@ -973,6 +1009,28 @@ int32_t WasmInterpreterRuntime::I64AtomicWait(uint64_t buffer_offset, return result.ToSmi().value(); } +void WasmInterpreterThread::Activation::CheckReentryStackFramePointer( + uint8_t* interpreter_fp) const { + // `interpreter_fp` (== NextFrameAddress()) is where a reentrant JS->Wasm call + // starts its native frame. A legitimate reentry publishes its geometry from + // the live caller frame, so it starts at or above that frame's base and + // within this thread's interpreter stack reservation. Reject anything + // outside that range: BeginExecution computes `stack_limit - interpreter_fp`, + // which is only defined for a pointer inside the allocation. + const Address reentry = reinterpret_cast<Address>(interpreter_fp); + const Address stack_base = reinterpret_cast<Address>(thread_->stack_mem()); + const Address stack_end = + stack_base + static_cast<Address>(kInterpreterStackReservationSize); + // Lower bound: live caller frame base, or the stack base if this activation + // has no bytecode frame (e.g. entered through an imported function). + const Address lower_bound = + current_frame_state_.current_function_ != nullptr + ? reinterpret_cast<Address>(current_frame_state_.current_sp_) + : stack_base; + SBXCHECK_LE(lower_bound, reentry); + SBXCHECK_LE(reentry, stack_end); +} + void WasmInterpreterRuntime::BeginExecution( WasmInterpreterThread* thread, uint32_t func_index, Address frame_pointer, uint8_t* interpreter_fp, uint32_t ref_stack_offset, @@ -980,7 +1038,11 @@ void WasmInterpreterRuntime::BeginExecution( current_thread_ = thread; start_function_index_ = func_index; - thread->StartActivation(this, frame_pointer, interpreter_fp, current_frame_); + // Validate the published reentry frame pointer stays within the top caller + // activation's live frame before we write arguments and slots there. + thread->ValidateReentrantStackFramePointer(interpreter_fp); + + thread->StartActivation(this, frame_pointer, current_frame_); current_frame_.current_function_ = nullptr; current_frame_.previous_frame_ = nullptr; @@ -2455,6 +2517,9 @@ ExternalCallResult WasmInterpreterRuntime::CallExternalJSFunction( DirectHandle<Object> object_ref, const FunctionSig* callsite_sig, uint32_t* sp, uint32_t return_slot_offset, const CanonicalSig* callee_canonical_sig) { + // Invalidate the published reentry frame pointer on every return path. + InvalidateActivationFrameOnReturn invalidate_on_return{current_thread_}; + // TODO(paolosev@microsoft.com) Cache IsJSCompatibleSignature result? if (!IsJSCompatibleSignature( reinterpret_cast<const wasm::CanonicalSig*>(callsite_sig))) { @@ -2656,20 +2721,9 @@ ExternalCallResult WasmInterpreterRuntime::CallExternalJSFunction( continue; } DirectHandle<Object>& ref = ref_returns[ref_idx++]; - // Normalize JS null -> wasm_null for funcref returns (funcref uses - // wasm_null, not JS null). - bool is_funcref = - callee_canonical_sig - ? callee_canonical_sig->GetReturn(i).value_type_code() == - wasm::kFuncRefCode - : callsite_sig->GetReturn(i).value_type_code() == - wasm::kFuncRefCode; - if (is_funcref && i::IsNull(*ref)) { - ref = isolate_->factory()->wasm_null(); - } - // Coerce against the callee's declared type when available, - // otherwise fall back to the callsite type. + // otherwise fall back to the callsite type. {ref} is a JS value here; + // JSToWasmObject() itself maps JS null to wasm_null where needed. if (callee_canonical_sig) { ref = JSToWasmObject(ref, callee_canonical_sig->GetReturn(i)); } else { @@ -2716,8 +2770,8 @@ ExternalCallResult WasmInterpreterRuntime::CallExternalJSFunction( case kRefNull: packer .Pop<Address>(); // Advance offset to stay in sync with PASS 1 - *reinterpret_cast<DirectHandle<Object>*>(sp) = - ref_returns[ref_idx++]; + base::WriteUnalignedValue<WasmRef>(reinterpret_cast<Address>(sp), + ref_returns[ref_idx++]); sp += sizeof(WasmRef) / kSlotSize; break; case kS128: @@ -2748,6 +2802,9 @@ ExternalCallResult WasmInterpreterRuntime::CallExternalWasmFunction( uint32_t target_function_index, DirectHandle<Object> object_ref, const FunctionSig* sig, uint32_t* sp, uint32_t return_slot_offset, uint32_t ref_stack_fp_offset) { + // Invalidate the published reentry frame pointer on every return path. + InvalidateActivationFrameOnReturn invalidate_on_return{current_thread_}; + #ifdef V8_ENABLE_DRUMBRAKE_TRACING if (v8_flags.trace_drumbrake_execution) { Trace(" => Calling external wasm function\n"); @@ -2865,7 +2922,8 @@ WasmInterpreterRuntime::ArrayNewUninitialized(uint32_t length, needs_write_barrier}; } -WasmRef WasmInterpreterRuntime::WasmArrayNewSegment(uint32_t array_index, +WasmRef WasmInterpreterRuntime::WasmArrayNewSegment(bool is_element, + uint32_t array_index, uint32_t segment_index, uint32_t offset, uint32_t length) { @@ -2878,11 +2936,15 @@ WasmRef WasmInterpreterRuntime::WasmArrayNewSegment(uint32_t array_index, // | length | // | offset | // | segment_index | + // | is_element | // first_arg_addr -> | trusted_instance | // - constexpr size_t kArgsLength = 5; - Address args[kArgsLength] = {rtt->ptr(), IntToSmi(length), IntToSmi(offset), + constexpr size_t kArgsLength = 6; + Address args[kArgsLength] = {rtt->ptr(), + IntToSmi(length), + IntToSmi(offset), IntToSmi(segment_index), + IntToSmi(is_element ? 1 : 0), wasm_trusted_instance_data()->ptr()}; Address* first_arg_addr = &args[kArgsLength - 1]; @@ -2897,11 +2959,9 @@ WasmRef WasmInterpreterRuntime::WasmArrayNewSegment(uint32_t array_index, return direct_handle(Tagged<Object>(result), isolate_); } -bool WasmInterpreterRuntime::WasmArrayInitSegment(uint32_t segment_index, - WasmRef wasm_array, - uint32_t array_offset, - uint32_t segment_offset, - uint32_t length) { +bool WasmInterpreterRuntime::WasmArrayInitSegment( + bool is_element, uint32_t segment_index, WasmRef wasm_array, + uint32_t array_offset, uint32_t segment_offset, uint32_t length) { // Call runtime function Runtime_WasmArrayInitSegment. Store the arguments in // reverse order and pass a pointer to the first argument, which is the last // on the stack. @@ -2911,13 +2971,17 @@ bool WasmInterpreterRuntime::WasmArrayInitSegment(uint32_t segment_index, // | array_offset | // | wasm_array | // | segment_index | + // | is_element | // first_arg_addr -> | trusted_instance | // - constexpr size_t kArgsLength = 6; - Address args[kArgsLength] = { - IntToSmi(length), IntToSmi(segment_offset), - IntToSmi(array_offset), (*wasm_array).ptr(), - IntToSmi(segment_index), wasm_trusted_instance_data()->ptr()}; + constexpr size_t kArgsLength = 7; + Address args[kArgsLength] = {IntToSmi(length), + IntToSmi(segment_offset), + IntToSmi(array_offset), + (*wasm_array).ptr(), + IntToSmi(segment_index), + IntToSmi(is_element ? 1 : 0), + wasm_trusted_instance_data()->ptr()}; Address* first_arg_addr = &args[kArgsLength - 1]; // A runtime function can throw, therefore we need to make sure that the @@ -2984,6 +3048,8 @@ WasmRef WasmInterpreterRuntime::WasmJSToWasmObject( WasmRef WasmInterpreterRuntime::JSToWasmObject(WasmRef extern_ref, ValueType type) const { + // {extern_ref} must be a JS value. + DCHECK(!IsWasmNull(*extern_ref)); DirectHandle<Object> result; const char* error_message; if (wasm::JSToWasmObject(isolate_, module_, extern_ref, type, &error_message) @@ -3003,6 +3069,7 @@ WasmRef WasmInterpreterRuntime::JSToWasmObject(WasmRef extern_ref, WasmRef WasmInterpreterRuntime::JSToWasmObject(WasmRef extern_ref, CanonicalValueType type) const { + DCHECK(!IsWasmNull(*extern_ref)); DirectHandle<Object> result; const char* error_message; if (wasm::JSToWasmObject(isolate_, extern_ref, type, &error_message) diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.h b/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.h index 010da0023c27..2ee11eee917f 100644 --- a/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.h +++ b/deps/v8/src/wasm/interpreter/wasm-interpreter-runtime.h @@ -41,7 +41,7 @@ class WasmInterpreterRuntime { // Every public method of WasmInterpreterRuntime that ultimately calls // wasm_trusted_instance_data() must be invoked while an InstanceScope is // active on this runtime (debug DCHECKs enforce this). - class V8_NODISCARD InstanceScope final { + class V8_EXPORT_PRIVATE V8_NODISCARD InstanceScope final { public: InstanceScope(WasmInterpreterRuntime* runtime, DirectHandle<WasmTrustedInstanceData> trusted_data); @@ -133,6 +133,17 @@ class WasmInterpreterRuntime { } DirectHandle<WasmExceptionPackage> CreateWasmExceptionPackage( uint32_t tag_index) const; + + // Read a WasmExceptionPackage's tag/values fields directly from their + // in-object slots, mirroring WasmExceptionPackage::New. Unlike the shared + // WasmExceptionPackage::GetExceptionTag/GetExceptionValues helpers, these + // don't do a generic property lookup, so a rewritten accessor descriptor + // can't run JS while the interpreter builds or handles an exception. + static DirectHandle<Object> GetExceptionTagField( + Isolate* isolate, DirectHandle<WasmExceptionPackage> exception_package); + static DirectHandle<FixedArray> GetExceptionValuesField( + Isolate* isolate, DirectHandle<WasmExceptionPackage> exception_package); + void UnpackException(uint32_t* sp, const WasmTag& tag, DirectHandle<Object> exception_object, uint32_t first_param_slot_index, @@ -217,11 +228,12 @@ class WasmInterpreterRuntime { ArrayNewResult ArrayNewUninitialized(uint32_t length, uint32_t array_index) const; - WasmRef WasmArrayNewSegment(uint32_t array_index, uint32_t segment_index, - uint32_t offset, uint32_t length); - bool WasmArrayInitSegment(uint32_t segment_index, WasmRef wasm_array, - uint32_t array_offset, uint32_t segment_offset, - uint32_t length); + WasmRef WasmArrayNewSegment(bool is_element, uint32_t array_index, + uint32_t segment_index, uint32_t offset, + uint32_t length); + bool WasmArrayInitSegment(bool is_element, uint32_t segment_index, + WasmRef wasm_array, uint32_t array_offset, + uint32_t segment_offset, uint32_t length); bool WasmArrayCopy(WasmRef dest_wasm_array, uint32_t dest_index, WasmRef src_wasm_array, uint32_t src_index, uint32_t length); @@ -372,7 +384,7 @@ class WasmInterpreterRuntime { // (which the GC scans), so the runtime never keeps a global handle to it. // All trusted-data accesses (see wasm_trusted_instance_data()) read this // off-cage, validated value instead of re-loading the in-cage - // WasmInstanceObject::trusted_data_ IndirectPointerHandle on every call, + // WasmInstanceObject::trusted_data_ TrustedPointerHandle on every call, // which would let a sandbox attacker same-tag swap it mid-execution. The // WasmInstanceObject (needed only for stack traces) is reached on demand via // the trusted `instance_object()` back-link. @@ -429,8 +441,8 @@ class WasmInterpreterRuntime { CanonicalTypeIndex sig_index) : mode(mode), func_index(func_index_), sig_index(sig_index) { DCHECK_NE(mode, Mode::kInvalid); - // Exactly the external calls carry no function index; internal calls - // always carry a valid one. + // External calls carry no function index; internal calls always carry a + // valid one. DCHECK_EQ(mode == Mode::kExternalCall, func_index_ == kInvalidFunctionIndex); } diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter.cc b/deps/v8/src/wasm/interpreter/wasm-interpreter.cc index 18319e21875e..616e51f1ea1b 100644 --- a/deps/v8/src/wasm/interpreter/wasm-interpreter.cc +++ b/deps/v8/src/wasm/interpreter/wasm-interpreter.cc @@ -5,6 +5,7 @@ #include "src/wasm/interpreter/wasm-interpreter.h" #include <atomic> +#include <bit> #include <limits> #include <optional> #include <type_traits> @@ -224,6 +225,15 @@ void WasmInterpreter::CodeMap::Preprocess(uint32_t function_index) { // Compute the control targets map and the local declarations. BytecodeIterator it(code->start, code->end, &code->locals, zone_); + // {BytecodeIterator} decodes the local declarations without a module, so + // indexed reference types are left with a default {RefTypeKind::kOther}. + // Populate them now that the module is available, otherwise subtyping checks + // performed while generating the bytecode (e.g. for ref.cast/ref.test) would + // hit an UNREACHABLE in {UpcastToStandardType}. + for (uint32_t i = 0; i < code->locals.num_locals; i++) { + value_type_reader::Populate(&code->locals.local_types[i], module_); + } + WasmBytecodeGenerator bytecode_generator(function_index, code, module_); code->bytecode = bytecode_generator.GenerateBytecode(); @@ -567,7 +577,7 @@ WasmInterpreterThread::~WasmInterpreterThread() { void WasmInterpreterThread::EnsureRefStackSpace(size_t new_size) { if (V8_LIKELY(current_ref_stack_size_ >= new_size)) return; - size_t requested_size = base::bits::RoundUpToPowerOfTwo64(new_size); + size_t requested_size = std::bit_ceil(new_size); new_size = std::max(size_t{8}, std::max(2 * current_ref_stack_size_, requested_size)); int grow_by = static_cast<int>(new_size - current_ref_stack_size_); @@ -5669,8 +5679,9 @@ class Handlers : public HandlersBase { DirectHandle<WasmExceptionPackage> exception_object = wasm_runtime->CreateWasmExceptionPackage(tag_index); - DirectHandle<FixedArray> encoded_values = TrustedCast<FixedArray>( - WasmExceptionPackage::GetExceptionValues(isolate, exception_object)); + DirectHandle<FixedArray> encoded_values = + WasmInterpreterRuntime::GetExceptionValuesField(isolate, + exception_object); // Encode the exception values on the operand stack into the exception // package allocated above. @@ -5710,10 +5721,9 @@ class Handlers : public HandlersBase { } case kRef: case kRefNull: { + // Store refs unchanged (as Liftoff does): internal-type nulls stay + // WasmNull and extern-type nulls stay JS null. DirectHandle<Object> ref = pop<WasmRef>(sp, code, wasm_runtime); - if (IsWasmNull(*ref)) { - ref = direct_handle(ReadOnlyRoots(isolate).null_value(), isolate); - } encoded_values->set(encoded_index++, *ref); break; } @@ -6512,8 +6522,10 @@ class Handlers : public HandlersBase { TRAP(MessageTemplate::kWasmTrapArrayTooLarge) } - WasmRef result = wasm_runtime->WasmArrayNewSegment(array_index, data_index, - offset, length); + constexpr bool is_element = + OutOfBoundsError == MessageTemplate::kWasmTrapElementSegmentOutOfBounds; + WasmRef result = wasm_runtime->WasmArrayNewSegment( + is_element, array_index, data_index, offset, length); if (V8_UNLIKELY(result.is_null())) { MessageTemplate reason = WasmInterpreterThread::GetRuntimeLastWasmError( wasm_runtime->GetIsolate()); @@ -6570,8 +6582,8 @@ class Handlers : public HandlersBase { TRAP(MessageTemplate::kWasmTrapNullDereference) } - bool ok = wasm_runtime->WasmArrayInitSegment(data_index, array, dest_offset, - src_offset, size); + bool ok = wasm_runtime->WasmArrayInitSegment(!init_data, data_index, array, + dest_offset, src_offset, size); if (V8_UNLIKELY(!ok)) { MessageTemplate reason = WasmInterpreterThread::GetRuntimeLastWasmError( wasm_runtime->GetIsolate()); @@ -7896,8 +7908,6 @@ void WasmBytecodeGenerator::StoreBlockParamsIntoSlots( EmitCopySlot(GetParamType(target_block_data, i), from_slot_index, to_slot_index); if (update_stack) { - DCHECK_EQ(GetParamType(target_block_data, i), - slots_[first_param_slot_index + i].value_type); DCHECK_EQ(GetParamType(target_block_data, i), slots_[first_param_slot_index + i].value_type); UpdateStack(stack_top_index() - (params_count - 1) + i, @@ -7963,8 +7973,6 @@ void WasmBytecodeGenerator::StoreBlockParamsAndResultsIntoSlots( stack_.resize(new_stack_height); for (uint32_t i = 0; i < rets_count; i++) { - DCHECK_EQ(GetReturnType(target_block_data, i), - slots_[target_block_data.first_block_index_ + i].value_type); DCHECK_EQ(GetReturnType(target_block_data, i), slots_[target_block_data.first_block_index_ + i].value_type); UpdateStack(target_block_data.stack_size_ - params_count + i, @@ -10214,9 +10222,17 @@ RegMode WasmBytecodeGenerator::DoEncodeInstruction(const WasmInstruction& instr, CurrentCodePos()); } + // Tail-call validation guarantees matching caller and callee result + // counts. + CHECK_IMPLIES( + is_tail_call, + sig->return_count() == wasm_code_->function->sig->return_count()); + const FunctionSig* result_slot_sig = + is_tail_call ? wasm_code_->function->sig : sig; + // Function results are pushed to the stack. for (size_t index = 0; index < sig->return_count(); index++) { - const ValueType value_type = sig->GetReturn(index); + const ValueType value_type = result_slot_sig->GetReturn(index); const ValueKind kind = value_type.kind(); switch (kind) { case kI32: @@ -10306,9 +10322,17 @@ RegMode WasmBytecodeGenerator::DoEncodeInstruction(const WasmInstruction& instr, CurrentCodePos()); } + // Tail-call validation guarantees matching caller and callee result + // counts. + CHECK_IMPLIES( + is_tail_call, + sig->return_count() == wasm_code_->function->sig->return_count()); + const FunctionSig* result_slot_sig = + is_tail_call ? wasm_code_->function->sig : sig; + // Function result is pushed to the stack. for (size_t index = 0; index < sig->return_count(); index++) { - ValueType value_type = sig->GetReturn(index); + const ValueType value_type = result_slot_sig->GetReturn(index); switch (value_type.kind()) { case kI32: case kI64: @@ -10388,9 +10412,17 @@ RegMode WasmBytecodeGenerator::DoEncodeInstruction(const WasmInstruction& instr, CurrentCodePos()); } + // Tail-call validation guarantees matching caller and callee result + // counts. + CHECK_IMPLIES( + is_tail_call, + sig->return_count() == wasm_code_->function->sig->return_count()); + const FunctionSig* result_slot_sig = + is_tail_call ? wasm_code_->function->sig : sig; + // Function result is pushed to the stack. for (size_t index = 0; index < sig->return_count(); index++) { - const ValueType value_type = sig->GetReturn(index); + const ValueType value_type = result_slot_sig->GetReturn(index); const ValueKind kind = value_type.kind(); switch (kind) { case kI32: diff --git a/deps/v8/src/wasm/interpreter/wasm-interpreter.h b/deps/v8/src/wasm/interpreter/wasm-interpreter.h index f2a8cf630361..7f4492981048 100644 --- a/deps/v8/src/wasm/interpreter/wasm-interpreter.h +++ b/deps/v8/src/wasm/interpreter/wasm-interpreter.h @@ -9,6 +9,7 @@ #error This header should only be included if WebAssembly is enabled. #endif // !V8_ENABLE_WEBASSEMBLY +#include <array> #include <atomic> #include <memory> #include <utility> @@ -230,7 +231,7 @@ class WasmBytecode { return ref_slots_count_ - ref_rets_count_ - ref_args_count_; } - inline size_t frame_size() { return total_frame_size_in_bytes_; } + inline size_t frame_size() const { return total_frame_size_in_bytes_; } static inline uint32_t ArgsSizeInSlots(const FunctionSig* sig); static inline uint32_t RetsSizeInSlots(const FunctionSig* sig); @@ -501,14 +502,16 @@ class V8_EXPORT_PRIVATE WasmInterpreterThread { public: Activation(WasmInterpreterThread* thread, WasmInterpreterRuntime* wasm_runtime, Address frame_pointer, - uint8_t* start_fp, const FrameState& callee_frame_state) + const FrameState& callee_frame_state) : thread_(thread), wasm_runtime_(wasm_runtime), frame_pointer_(frame_pointer), current_frame_size_(0), current_ref_stack_fp_(0), current_ref_stack_frame_size_(0), - current_fp_(start_fp), + // No frame geometry is published yet. A reentry must publish its own + // (SetCurrentActivationFrame) before it can be used as a base. + current_fp_(nullptr), current_frame_state_(callee_frame_state) #ifdef V8_ENABLE_DRUMBRAKE_TRACING , @@ -553,10 +556,25 @@ class V8_EXPORT_PRIVATE WasmInterpreterThread { #endif // V8_ENABLE_DRUMBRAKE_TRACING } + // Reset the published frame pointer to a sentinel (null) that lies outside + // every live caller frame, so a later reentry that does not republish + // fails BeginExecution's bounds check. + void InvalidateCurrentActivationFrame() { + current_fp_ = nullptr; + current_frame_size_ = 0; + } + uint8_t* NextFrameAddress() const { + if (current_fp_ == nullptr) return nullptr; return current_fp_ + current_frame_size_; } + // Check that a reentry starting its native frame at `interpreter_fp` (this + // activation's NextFrameAddress()) lies at or above this activation's live + // caller frame (or the interpreter stack base if there is none) and within + // this thread's interpreter stack reservation; SBXCHECK otherwise. + void CheckReentryStackFramePointer(uint8_t* interpreter_fp) const; + uint32_t NextRefStackOffset() const { return current_ref_stack_fp_ + current_ref_stack_frame_size_; } @@ -729,7 +747,7 @@ class V8_EXPORT_PRIVATE WasmInterpreterThread { inline WasmInterpreterThread::Activation* StartActivation( WasmInterpreterRuntime* wasm_runtime, Address frame_pointer, - uint8_t* interpreter_fp, const FrameState& frame_state); + const FrameState& frame_state); inline void FinishActivation(); inline const FrameState* GetCurrentActivationFor( const WasmInterpreterRuntime* wasm_runtime) const; @@ -750,6 +768,14 @@ class V8_EXPORT_PRIVATE WasmInterpreterThread { current_ref_stack_fp, current_ref_stack_frame_size); } + // Invalidate the top activation's published frame geometry once a callout + // returns. Safe to call redundantly; a no-op if there is no live activation. + inline void InvalidateActivationFrame() { + if (!activations_.empty()) { + activations_.back()->InvalidateCurrentActivationFrame(); + } + } + WasmInterpreterThread::Activation* GetActivation( Address frame_pointer) const { for (size_t i = 0; i < activations_.size(); i++) { @@ -760,6 +786,16 @@ class V8_EXPORT_PRIVATE WasmInterpreterThread { return nullptr; } + // Check a reentry starting its native frame at `interpreter_fp` against the + // top (caller) activation's live frame; SBXCHECK otherwise. No-op if the + // thread has no live activation. + // See Activation::CheckReentryStackFramePointer. + void ValidateReentrantStackFramePointer(uint8_t* interpreter_fp) const { + if (!activations_.empty()) { + activations_.back()->CheckReentryStackFramePointer(interpreter_fp); + } + } + uint8_t* NextFrameAddress() const { if (activations_.empty()) { return stack_mem(); @@ -2288,10 +2324,10 @@ class InterpreterTracer final : public Malloced { base::SNPrintF(filename_, "trace-%d-%d.dbt", base::OS::GetCurrentProcessId(), current_chunk_index_); } - WriteChars(filename_.begin(), "", 0, false); + WriteChars(filename_.data(), "", 0, false); if (file_ == nullptr) { - file_ = base::OS::FOpen(filename_.begin(), "w"); + file_ = base::OS::FOpen(filename_.data(), "w"); CHECK_WITH_MSG(file_ != nullptr, "could not open file."); } } @@ -2336,7 +2372,7 @@ class InterpreterTracer final : public Malloced { static bool ShouldRedirect() { return v8_flags.redirect_drumbrake_traces; } int isolate_id_; - base::EmbeddedVector<char, 128> filename_; + std::array<char, 128> filename_; FILE* file_; absl::flat_hash_set<int> traced_functions_; int current_chunk_index_; diff --git a/deps/v8/src/wasm/interpreter/x64/interpreter-builtins-x64.cc b/deps/v8/src/wasm/interpreter/x64/interpreter-builtins-x64.cc index c35f66edc84d..8c0e6be57f1a 100644 --- a/deps/v8/src/wasm/interpreter/x64/interpreter-builtins-x64.cc +++ b/deps/v8/src/wasm/interpreter/x64/interpreter-builtins-x64.cc @@ -86,7 +86,7 @@ void LoadFunctionDataAndWasmInstance(MacroAssembler* masm, function_data, FieldOperand(shared_function_info, offsetof(SharedFunctionInfo, trusted_function_data_)), - kWasmExportedFunctionDataIndirectPointerTag, kScratchRegister); + kWasmExportedFunctionDataTrustedPointerTag, kScratchRegister); shared_function_info = no_reg; diff --git a/deps/v8/src/wasm/jump-table-assembler.cc b/deps/v8/src/wasm/jump-table-assembler.cc index 2c911498f827..3da5307070b0 100644 --- a/deps/v8/src/wasm/jump-table-assembler.cc +++ b/deps/v8/src/wasm/jump-table-assembler.cc @@ -763,11 +763,14 @@ bool JumpTableAssembler::EmitJumpSlot(Address target) { emit<uint32_t>(shared[3]); // Atomically emit the 64-bit value on an aligned address. - DCHECK(IsAligned(pc_, kSystemPointerSize)); - emit<Address>(target); + CHECK(IsAligned(pc_, kSystemPointerSize)); + emit<Address>(target, kRelaxedStore); // Commit the changes to the sequence by (possibly) changing the first - // instruction. The instruction will change between 'jal' and 'auipc'. + // instruction. The instruction will change between 'jal' and 'auipc'. It must + // be written atomically: the jump table can be patched while other threads + // are concurrently executing this slot, so a concurrent instruction fetch + // must observe either the old or the new instruction, never a mix of the two. intptr_t relative_target = target - first; if (is_int21(relative_target)) { int32_t imm21 = static_cast<int32_t>(relative_target); @@ -777,10 +780,12 @@ bool JumpTableAssembler::EmitJumpSlot(Address target) { ((imm21 & 0x800) << 9) | // bit 11 ((imm21 & 0x7fe) << 20) | // bits 10-1 ((imm21 & 0x100000) << 11); // bit 20 - jit_allocation_.WriteUnalignedValue(first, near); + DCHECK(IsAligned(first, kInt32Size)); + jit_allocation_.WriteValue(first, near, kRelaxedStore); } else { uint32_t far = RO_AUIPC | (t6.code() << kRdShift); - jit_allocation_.WriteUnalignedValue(first, far); + DCHECK(IsAligned(first, kInt32Size)); + jit_allocation_.WriteValue(first, far, kRelaxedStore); } return true; } diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc index e5259b9a92e7..9f78bde9a9a1 100644 --- a/deps/v8/src/wasm/module-compiler.cc +++ b/deps/v8/src/wasm/module-compiler.cc @@ -12,15 +12,15 @@ #include "src/api/api-inl.h" #include "src/base/enum-set.h" -#include "src/base/fpu.h" #include "src/base/platform/mutex.h" #include "src/base/platform/semaphore.h" #include "src/base/platform/time.h" +#include "src/base/unique-array.h" #include "src/codegen/compiler.h" #include "src/compiler/wasm-compiler.h" #include "src/debug/debug.h" #include "src/handles/global-handles-inl.h" -#include "src/logging/counters-scopes.h" +#include "src/logging/counters.h" #include "src/logging/metrics.h" #include "src/objects/managed.h" #include "src/tracing/trace-event.h" @@ -798,7 +798,7 @@ class CompilationStateImpl { // protected by the {callbacks_mutes_}, with exceptions during // initialization (see comment in // {CompilationStateImpl::InitializeCompilationUnitForSingleFunction}). - base::OwnedVector<uint8_t> compilation_progress_; + base::UniqueArray<uint8_t> compilation_progress_; // The timestamp of the last top-tier compilation. // This field is updated on every publishing of top-tier code, and is reset @@ -1145,6 +1145,14 @@ void CompileLazy(Isolate* isolate, NativeModule* native_module, WasmCodeRefScope code_ref_scope; WasmCode* code = native_module->PublishCode(native_module->AddCompiledCode(result)); + if (code == nullptr) { + // Publishing only fails when well-known import assumptions in TurboFan code + // were invalidated concurrently. Simply return; jumping to the jump table + // slot will retry lazy compilation (unless another thread compiled the + // function in the meantime). + DCHECK_EQ(ExecutionTier::kTurbofan, result.result_tier); + return; + } DCHECK_EQ(func_index, code->index()); if (V8_UNLIKELY(native_module->log_code())) { @@ -1174,7 +1182,7 @@ class FeedbackMaker { : isolate_(isolate), instance_data_(trusted_instance_data), result_( - base::OwnedVector<CallSiteFeedback>::NewForOverwrite(num_calls)), + base::UniqueArray<CallSiteFeedback>::NewForOverwrite(num_calls)), num_imported_functions_(static_cast<int>( trusted_instance_data->module()->num_imported_functions)), func_index_(func_index) {} @@ -1316,14 +1324,14 @@ class FeedbackMaker { // {GetResult} can only be called on a r-value reference to make it more // obvious at call sites that {this} should not be used after this operation. - base::OwnedVector<CallSiteFeedback> GetResult() && { + base::UniqueArray<CallSiteFeedback> GetResult() && { return std::move(result_); } private: Isolate* const isolate_; const Tagged<WasmTrustedInstanceData> instance_data_; - base::OwnedVector<CallSiteFeedback> result_; + base::UniqueArray<CallSiteFeedback> result_; int seen_calls_ = 0; const int num_imported_functions_; const int func_index_; @@ -1363,7 +1371,7 @@ void TransitiveTypeFeedbackProcessor::ProcessFunction(int func_index) { Tagged<FixedArray> feedback = Cast<FixedArray>(maybe_feedback); base::Vector<uint32_t> call_targets = module_->type_feedback.feedback_for_function[func_index] - .call_targets.as_vector(); + .call_targets.as_span(); // For each entry in {call_targets}, there are two {Object} slots in the // {feedback} vector: @@ -1469,7 +1477,7 @@ void TransitiveTypeFeedbackProcessor::ProcessFunction(int func_index) { // feedback to prevent deopt loops where two different instantiations // (which have their own on-heap feedback vector) to "flip-flop" between // their inlining decisions potentially causing deopt loops. - const base::OwnedVector<CallSiteFeedback>& existing = + const base::UniqueArray<CallSiteFeedback>& existing = feedback_for_function_[func_index].feedback_vector; size_t feedback_index = (i - FeedbackConstants::kHeaderSlots) / FeedbackConstants::kSlotsPerInstruction; @@ -1500,8 +1508,8 @@ void TransitiveTypeFeedbackProcessor::ProcessFunction(int func_index) { fm.FinalizeCall(); } - base::OwnedVector<CallSiteFeedback> result = std::move(fm).GetResult(); - EnqueueCallees(result.as_vector()); + base::UniqueArray<CallSiteFeedback> result = std::move(fm).GetResult(); + EnqueueCallees(result.as_span()); DCHECK_EQ(result.size(), feedback_for_function_[func_index].call_targets.size()); feedback_for_function_[func_index].feedback_vector = std::move(result); @@ -1891,7 +1899,6 @@ CompilationExecutionResult ExecuteCompilationUnits( // These fields are initialized in a {BackgroundCompileScope} before // starting compilation. std::optional<CompilationEnv> env; - std::optional<base::FlushDenormalsScope> disable_denormals; std::shared_ptr<WireBytesStorage> wire_bytes; std::shared_ptr<const WasmModule> module; // Task 0 is any main thread (there might be multiple from multiple isolates), @@ -1914,11 +1921,6 @@ CompilationExecutionResult ExecuteCompilationUnits( BackgroundCompileScope compile_scope(native_module); if (compile_scope.cancelled()) return kYield; env.emplace(CompilationEnv::ForModule(compile_scope.native_module())); - // We only really need this for optimized compilation, but for simplicity - // set it just once for everything. - disable_denormals.emplace( - compile_scope.native_module()->compile_imports().contains( - CompileTimeImport::kDisableDenormalFloats)); wire_bytes = compile_scope.compilation_state()->GetWireBytesStorage(); module = compile_scope.native_module()->shared_module(); queue = compile_scope.compilation_state()->GetQueueForCompileTask(task_id); @@ -2073,13 +2075,13 @@ std::shared_ptr<NativeModule> GetOrCompileNewNativeModule( Isolate* isolate, WasmEnabledFeatures enabled_features, WasmDetectedFeatures detected_features, CompileTimeImports compile_imports, ErrorThrower* thrower, std::shared_ptr<const WasmModule> module, - base::OwnedVector<const uint8_t> wire_bytes, int compilation_id, + base::UniqueArray<const uint8_t> wire_bytes, int compilation_id, v8::metrics::Recorder::ContextId context_id, ProfileInformation* pgo_info) { base::TimeTicks start_time; if (base::TimeTicks::IsHighResolution()) start_time = base::TimeTicks::Now(); std::shared_ptr<NativeModule> native_module = - GetWasmEngine()->MaybeGetNativeModule(wire_bytes.as_vector(), + GetWasmEngine()->MaybeGetNativeModule(wire_bytes.as_span(), enabled_features, compile_imports); if (native_module) { GetWasmEngine()->UseNativeModuleInIsolate(native_module.get(), isolate); @@ -2155,7 +2157,7 @@ std::shared_ptr<NativeModule> CompileToNativeModule( Isolate* isolate, WasmEnabledFeatures enabled_features, WasmDetectedFeatures detected_features, CompileTimeImports compile_imports, ErrorThrower* thrower, std::shared_ptr<const WasmModule> module, - base::OwnedVector<const uint8_t> wire_bytes, int compilation_id, + base::UniqueArray<const uint8_t> wire_bytes, int compilation_id, v8::metrics::Recorder::ContextId context_id, ProfileInformation* pgo_info) { std::shared_ptr<NativeModule> native_module = GetOrCompileNewNativeModule( isolate, enabled_features, detected_features, std::move(compile_imports), @@ -2239,7 +2241,7 @@ class AsyncCompileJob::CompileTask : public CancelableTask { AsyncCompileJob::AsyncCompileJob( WasmEnabledFeatures enabled_features, CompileTimeImports compile_imports, - base::OwnedVector<const uint8_t> bytes, const char* api_method_name, + base::UniqueArray<const uint8_t> bytes, const char* api_method_name, std::shared_ptr<CompilationResultResolver> resolver, int compilation_id) : api_method_name_(api_method_name), enabled_features_(enabled_features), @@ -2247,7 +2249,7 @@ AsyncCompileJob::AsyncCompileJob( start_time_(base::TimeTicks::IsHighResolution() ? base::TimeTicks::Now() : base::TimeTicks{}), bytes_copy_(std::move(bytes)), - wire_bytes_(bytes_copy_.as_vector()), + wire_bytes_(bytes_copy_.as_span()), resolver_(std::move(resolver)), compilation_id_(compilation_id) { TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), @@ -2312,7 +2314,7 @@ struct ValidateFunctionsStreamingJobData { void Initialize(int num_declared_functions) { DCHECK_NULL(units); - units = base::OwnedVector<Unit>::NewForOverwrite(num_declared_functions); + units = base::UniqueArray<Unit>::NewForOverwrite(num_declared_functions); // Initially {next == end}. next_available_unit.store(units.begin(), std::memory_order_relaxed); end_of_available_units.store(units.begin(), std::memory_order_relaxed); @@ -2380,7 +2382,7 @@ struct ValidateFunctionsStreamingJobData { } } - base::OwnedVector<Unit> units; + base::UniqueArray<Unit> units; std::atomic<Unit*> next_available_unit; std::atomic<Unit*> end_of_available_units; std::atomic<bool> found_error{false}; @@ -2456,13 +2458,13 @@ class AsyncStreamingProcessor final : public StreamingProcessor { void OnFinishedChunk() override; - void OnFinishedStream(base::OwnedVector<const uint8_t> bytes, + void OnFinishedStream(base::UniqueArray<const uint8_t> bytes, bool after_error) override; void OnAbort() override; bool Deserialize(base::Vector<const uint8_t> module_bytes, - base::OwnedVector<const uint8_t>& wire_bytes) override; + base::UniqueArray<const uint8_t>& wire_bytes) override; private: void CommitCompilationUnits(); @@ -2570,8 +2572,8 @@ void AsyncCompileJob::FinishCompile( bool is_after_deserialization = !deserialized_module_object.is_null(); if (!is_after_deserialization) { // Prepare runtime objects. - auto source_url = - stream_ ? base::VectorOf(stream_->url()) : base::Vector<const char>(); + std::string_view source_url = + stream_ ? std::string_view(stream_->url()) : std::string_view(); auto script = GetWasmEngine()->GetOrCreateScript(isolate, native_module, source_url); module_object = WasmModuleObject::New(isolate, script); @@ -2634,10 +2636,11 @@ void AsyncCompileJob::FinishCompile( if (sourcemap_symbol.type != WasmDebugSymbols::Type::None && !sourcemap_symbol.external_url.is_empty()) { ModuleWireBytes wire_bytes(native_module->wire_bytes()); + WasmName external_url = + wire_bytes.GetNameOrNull(sourcemap_symbol.external_url); MaybeDirectHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8( - wire_bytes.GetNameOrNull(sourcemap_symbol.external_url), - AllocationType::kOld); + {external_url.data(), external_url.size()}, AllocationType::kOld); script->set_source_mapping_url(*src_map_str.ToHandleChecked()); } { @@ -2665,7 +2668,7 @@ void AsyncCompileJob::FinishCompile( // Finally, log all generated code (it does not matter if this happens // repeatedly in case the script is shared). - native_module->LogWasmCodes(isolate, *script); + native_module->LogWasmCodes(isolate, script); { TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), @@ -3193,7 +3196,7 @@ void AsyncStreamingProcessor::SetCrashKey(std::string_view message) { // Finish the processing of the stream. void AsyncStreamingProcessor::OnFinishedStream( - base::OwnedVector<const uint8_t> bytes, bool after_error) { + base::UniqueArray<const uint8_t> bytes, bool after_error) { TRACE_STREAMING("Finish stream...\n"); ModuleResult module_result = decoder_.FinishDecoding(); if (module_result.failed()) { @@ -3221,7 +3224,7 @@ void AsyncStreamingProcessor::OnFinishedStream( std::memory_order_relaxed); } - job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); + job_->wire_bytes_ = ModuleWireBytes(bytes.as_span()); job_->bytes_copy_ = std::move(bytes); if (!after_error) { @@ -3275,9 +3278,9 @@ void AsyncStreamingProcessor::OnFinishedStream( // validating function bodies. Overall this does not add a lot of overhead. #ifdef DEBUG WasmDetectedFeatures detected_module_features; - DCHECK(DecodeWasmModule( - job_->enabled_features_, job_->bytes_copy_.as_vector(), - /* validate functions */ false, &detected_module_features) + DCHECK(DecodeWasmModule(job_->enabled_features_, job_->bytes_copy_.as_span(), + /* validate functions */ false, + &detected_module_features) .ok()); // Module decoding should not detect any new features. DCHECK(job_->detected_features_.contains_all(detected_module_features)); @@ -3382,14 +3385,9 @@ void AsyncStreamingProcessor::OnAbort() { bool AsyncStreamingProcessor::Deserialize( base::Vector<const uint8_t> module_bytes, - base::OwnedVector<const uint8_t>& wire_bytes) { + base::UniqueArray<const uint8_t>& wire_bytes) { TRACE_EVENT("v8.wasm", "wasm.Deserialize"); Isolate* isolate = job_->isolate_specific_info_.isolate_; - std::optional<TimedHistogramScope> time_scope; - if (base::TimeTicks::IsHighResolution()) { - time_scope.emplace(isolate->counters()->wasm_deserialization_time(), - isolate); - } // DeserializeNativeModule and FinishCompile assume that they are executed in // a HandleScope, and that a context is set on the isolate. HandleScope scope(isolate); @@ -3401,7 +3399,7 @@ bool AsyncStreamingProcessor::Deserialize( DirectHandle<WasmModuleObject> module_object; if (!DeserializeNativeModule(isolate, job_->enabled_features_, module_bytes, wire_bytes, job_->compile_imports_, - base::VectorOf(job_->stream_->url())) + job_->stream_->url()) .ToHandle(&module_object)) { return false; } @@ -3472,7 +3470,8 @@ void CompilationStateImpl::ApplyEagerTierUpToInitialProgress(size_t hint_idx) { ExecutionTier old_baseline_tier = RequiredBaselineTierField::decode(progress); // Compute new information. - ExecutionTier new_baseline_tier = ExecutionTier::kTurbofan; + ExecutionTier new_baseline_tier = + v8_flags.liftoff ? ExecutionTier::kLiftoff : ExecutionTier::kTurbofan; ExecutionTier new_top_tier = ExecutionTier::kTurbofan; progress = RequiredBaselineTierField::update(progress, new_baseline_tier); @@ -3630,7 +3629,7 @@ void CompilationStateImpl::InitializeCompilationProgress( RequiredTopTierField::encode(default_tiers.top_tier) | ReachedTierField::encode(ExecutionTier::kNone); DCHECK_NULL(compilation_progress_); - compilation_progress_ = base::OwnedVector<uint8_t>::New( + compilation_progress_ = base::UniqueArray<uint8_t>::New( module->num_declared_functions, default_progress); if (default_tiers.baseline_tier != ExecutionTier::kNone) { outstanding_baseline_units_ += module->num_declared_functions; @@ -3655,6 +3654,7 @@ void CompilationStateImpl::InitializeCompilationProgress( // Apply --wasm-eager-tier-up-function, if given. if (V8_UNLIKELY( v8_flags.wasm_eager_tier_up_function >= 0 && + !v8_flags.liftoff_only && !native_module_->IsInDebugState() && static_cast<uint32_t>(v8_flags.wasm_eager_tier_up_function) >= module->num_imported_functions && static_cast<uint32_t>(v8_flags.wasm_eager_tier_up_function) < @@ -3738,10 +3738,6 @@ void CompilationStateImpl::InitializeCompilationProgressAfterDeserialization( TRACE_EVENT("v8.wasm", "wasm.CompilationAfterDeserialization", "num_lazy_functions", lazy_functions.size(), "num_eager_functions", eager_functions.size()); - base::ElapsedTimer lazy_compile_time; - if (base::TimeTicks::IsHighResolution()) { - lazy_compile_time.Start(); - } auto* module = native_module_->module(); { @@ -3754,7 +3750,7 @@ void CompilationStateImpl::InitializeCompilationProgressAfterDeserialization( RequiredBaselineTierField::encode(ExecutionTier::kLiftoff) | RequiredTopTierField::encode(ExecutionTier::kTurbofan) | ReachedTierField::encode(ExecutionTier::kTurbofan); - compilation_progress_ = base::OwnedVector<uint8_t>::New( + compilation_progress_ = base::UniqueArray<uint8_t>::New( module->num_declared_functions, kProgressAfterTurbofanDeserialization); // Update compilation state for lazy functions. @@ -3797,11 +3793,6 @@ void CompilationStateImpl::InitializeCompilationProgressAfterDeserialization( if (!v8_flags.wasm_lazy_compilation) { WaitForBaselineCompileJob(); } - - if (lazy_compile_time.IsStarted()) { - native_module_->counter_updates()->AddTimedSample( - &Counters::wasm_compile_after_deserialize, lazy_compile_time.Elapsed()); - } } void CompilationStateImpl::AddCallback( @@ -3927,24 +3918,22 @@ void CompilationStateImpl::OnFinishedUnits( } // Allow another top tier compilation if deopts are enabled and the // currently installed code object is a Liftoff object. - // Ideally, this would be done only if the code->tier() == - // ExecutionTier::Liftoff as the code object for which we run this - // function should be the same as the one installed on the native_module. - // This is unfortunately not the case as installing a code object on the - // native module and updating the compilation_progress_ and the - // CompilationUnitQueues::top_tier_compiled_ are not synchronized. + // Allow another top tier compilation if deopts are enabled and the + // currently installed code object is a Liftoff object. We check the code + // installed on {native_module_} rather than {code->tier()} because + // baseline compilation can finish after top-tier compilation (without + // replacing the top-tier code), and publishing code and updating + // {compilation_progress_} are not synchronized. // Note: GetCode() acquires the NativeModule::allocation_mutex_, so this // could cause deadlocks if any other place acquires // NativeModule::allocation_mutex_ first and then // CompilationStateImpl::callbacks_mutex_! - const bool is_liftoff = code->tier() == ExecutionTier::kLiftoff; auto published_code_is_liftoff = [this](int index) { WasmCode* code = native_module_->GetCode(index); if (code == nullptr) return false; return code->is_liftoff(); }; - if (v8_flags.wasm_deopt && - (is_liftoff || published_code_is_liftoff(code->index()))) { + if (v8_flags.wasm_deopt && published_code_is_liftoff(code->index())) { // Setting the reached tier below the baseline tier would create an // inconsistent state and has actually led to crashes before (see // https://crbug.com/379086474). @@ -4072,12 +4061,19 @@ void CompilationStateImpl::TriggerCallbacks( void CompilationStateImpl::TriggerCachingAfterTimeout() { base::MutexGuard guard{&callbacks_mutex_}; + DCHECK(!last_top_tier_compilation_timestamp_.IsNull()); + // It can happen that we reached the hard threshold while waiting for the - // timeout to expire. In that case, {bytes_since_last_chunk_} might be zero - // and there is nothing new to cache. - if (bytes_since_last_chunk_ == 0) return; + // timeout to expire. In that case, {bytes_since_last_chunk_} was reset to + // zero and might still be below the caching threshold (or zero), so there is + // nothing new to cache yet. + if (bytes_since_last_chunk_ == 0 || + bytes_since_last_chunk_ < + static_cast<size_t>(v8_flags.wasm_caching_threshold)) { + last_top_tier_compilation_timestamp_ = {}; + return; + } - DCHECK(!last_top_tier_compilation_timestamp_.IsNull()); base::TimeTicks caching_time = last_top_tier_compilation_timestamp_ + base::TimeDelta::FromMilliseconds(v8_flags.wasm_caching_timeout_ms); @@ -4085,14 +4081,12 @@ void CompilationStateImpl::TriggerCachingAfterTimeout() { // If we are still half a millisecond or more away from the timeout, // reschedule the task. Otherwise, call the caching callback. if (time_until_caching >= base::TimeDelta::FromMicroseconds(500)) { - int ms_remaining = - static_cast<int>(time_until_caching.InMillisecondsRoundedUp()); - DCHECK_LE(1, ms_remaining); + double seconds_remaining = time_until_caching.InSecondsF(); V8::GetCurrentPlatform()->PostDelayedTaskOnWorkerThread( TaskPriority::kUserVisible, std::make_unique<TriggerCodeCachingAfterTimeoutTask>( native_module_weak_), - ms_remaining); + seconds_remaining); return; } @@ -4133,7 +4127,7 @@ void CompilationStateImpl::PublishCompilationResults( #if DEBUG // We don't compile import wrappers eagerly. - for (const auto& [code, assumptions] : unpublished_code) { + for (const auto& [code, assumptions, for_deopt] : unpublished_code) { int func_index = code->index(); DCHECK_LE(native_module_->num_imported_functions(), func_index); DCHECK_LT(func_index, native_module_->num_functions()); diff --git a/deps/v8/src/wasm/module-compiler.h b/deps/v8/src/wasm/module-compiler.h index c2fcea0016ae..09435d02a77d 100644 --- a/deps/v8/src/wasm/module-compiler.h +++ b/deps/v8/src/wasm/module-compiler.h @@ -14,6 +14,7 @@ #include "include/v8-metrics.h" #include "src/base/platform/time.h" +#include "src/base/unique-array.h" #include "src/common/globals.h" #include "src/handles/maybe-handles.h" #include "src/tasks/cancelable-task.h" @@ -52,7 +53,7 @@ std::shared_ptr<NativeModule> CompileToNativeModule( Isolate* isolate, WasmEnabledFeatures enabled_features, WasmDetectedFeatures detected_features, CompileTimeImports compile_imports, ErrorThrower* thrower, std::shared_ptr<const WasmModule> module, - base::OwnedVector<const uint8_t> wire_bytes, int compilation_id, + base::UniqueArray<const uint8_t> wire_bytes, int compilation_id, v8::metrics::Recorder::ContextId context_id, ProfileInformation* pgo_info); V8_EXPORT_PRIVATE WasmError ValidateAndSetBuiltinImports( @@ -112,7 +113,7 @@ class AsyncCompileJob { public: AsyncCompileJob(WasmEnabledFeatures enabled_features, CompileTimeImports compile_imports, - base::OwnedVector<const uint8_t> bytes, + base::UniqueArray<const uint8_t> bytes, const char* api_method_name, std::shared_ptr<CompilationResultResolver> resolver, int compilation_id); @@ -251,7 +252,7 @@ class AsyncCompileJob { base::TimeTicks compilation_finished_time_; // Copy of the module wire bytes, moved into the {new_native_module_} on its // creation. - base::OwnedVector<const uint8_t> bytes_copy_; + base::UniqueArray<const uint8_t> bytes_copy_; // Reference to the wire bytes (held in {bytes_copy_} or as part of // {new_native_module_}). ModuleWireBytes wire_bytes_; diff --git a/deps/v8/src/wasm/module-decoder-impl.h b/deps/v8/src/wasm/module-decoder-impl.h index 21a99c620099..51b93b44a52b 100644 --- a/deps/v8/src/wasm/module-decoder-impl.h +++ b/deps/v8/src/wasm/module-decoder-impl.h @@ -9,6 +9,8 @@ #error This header should only be included if WebAssembly is enabled. #endif // !V8_ENABLE_WEBASSEMBLY +#include <array> + #include "src/base/platform/wrappers.h" #include "src/strings/unicode.h" #include "src/utils/ostreams.h" @@ -134,25 +136,21 @@ inline SectionCode IdentifyUnknownSectionInternal(Decoder* decoder, static_cast<int>(section_name_start - decoder->start()), string.length() < 20 ? string.length() : 20, section_name_start); - using SpecialSectionPair = std::pair<base::Vector<const char>, SectionCode>; + using SpecialSectionPair = std::pair<std::string_view, SectionCode>; static constexpr SpecialSectionPair kSpecialSections[]{ - {base::StaticCharVector(kNameString), kNameSectionCode}, - {base::StaticCharVector(kSourceMappingURLString), - kSourceMappingURLSectionCode}, - {base::StaticCharVector(kInstTraceString), kInstTraceSectionCode}, - {base::StaticCharVector(kBranchHintsString), kBranchHintsSectionCode}, - {base::StaticCharVector(kCompilationPriorityString), - kCompilationPrioritySectionCode}, - {base::StaticCharVector(kInstructionFrequenciesString), - kInstFrequenciesSectionCode}, - {base::StaticCharVector(kCallTargetsString), kCallTargetsSectionCode}, - {base::StaticCharVector(kDebugInfoString), kDebugInfoSectionCode}, - {base::StaticCharVector(kExternalDebugInfoString), - kExternalDebugInfoSectionCode}, - {base::StaticCharVector(kBuildIdString), kBuildIdSectionCode}}; - - auto name_vec = base::Vector<const char>::cast( - base::VectorOf(section_name_start, string.length())); + {kNameString, kNameSectionCode}, + {kSourceMappingURLString, kSourceMappingURLSectionCode}, + {kInstTraceString, kInstTraceSectionCode}, + {kBranchHintsString, kBranchHintsSectionCode}, + {kCompilationPriorityString, kCompilationPrioritySectionCode}, + {kInstructionFrequenciesString, kInstFrequenciesSectionCode}, + {kCallTargetsString, kCallTargetsSectionCode}, + {kDebugInfoString, kDebugInfoSectionCode}, + {kExternalDebugInfoString, kExternalDebugInfoSectionCode}, + {kBuildIdString, kBuildIdSectionCode}}; + + std::string_view name_vec(reinterpret_cast<const char*>(section_name_start), + string.length()); for (auto& special_section : kSpecialSections) { if (name_vec == special_section.first) return special_section.second; } @@ -292,9 +290,9 @@ inline void DumpModule(const base::Vector<const uint8_t> module_bytes, // File are named `<hash>.{ok,failed}.wasm`. // Limit the hash to 8 characters (32 bits). uint32_t hash = static_cast<uint32_t>(GetWireBytesHash(module_bytes)); - base::EmbeddedVector<char, 32> buf; - SNPrintF(buf, "%08x.%s.wasm", hash, ok ? "ok" : "failed"); - path += buf.begin(); + std::array<char, 32> buf; + base::SNPrintF(buf, "%08x.%s.wasm", hash, ok ? "ok" : "failed"); + path += buf.data(); size_t rv = 0; if (FILE* file = base::OS::FOpen(path.c_str(), "wb")) { rv = fwrite(module_bytes.begin(), module_bytes.size(), 1, file); @@ -409,13 +407,6 @@ class ModuleDecoderImpl : public Decoder { // TODO(12868): If there's a tag section, assert that we're after the // tag section. return check_order(kMemorySectionCode, kGlobalSectionCode); - case kInstTraceSectionCode: - // Custom section following code.metadata tool convention containing - // offsets specifying where trace marks should be emitted. - // Be lenient with placement of instruction trace section. All except - // first occurrence after function section and before code section are - // ignored. - return true; default: return true; } @@ -591,7 +582,7 @@ class ModuleDecoderImpl : public Decoder { } case kWasmArrayTypeCode: { module_->is_wasm_gc = true; - const ArrayType* type = consume_array(); + const ArrayType* type = consume_array(is_shared); if (V8_UNLIKELY(type == nullptr)) { CHECK(!ok()); return {}; @@ -605,10 +596,13 @@ class ModuleDecoderImpl : public Decoder { return {}; } + // TODO(clemensb): Clarify whether cont types take a heaptype (s33) or a + // typeidx (u32v); see + // https://github.com/WebAssembly/stack-switching/issues/157. const uint8_t* pos = pc(); HeapType hp = consume_heap_type(); - if (V8_UNLIKELY(!hp.has_index())) { + if (V8_UNLIKELY(!hp.has_index() || hp.is_exact())) { error(pos, "cont type must refer to a signature index"); return {}; } @@ -2880,12 +2874,13 @@ class ModuleDecoderImpl : public Decoder { return result; } - const ArrayType* consume_array() { + const ArrayType* consume_array(SharedFlag is_shared) { ValueType element_type = consume_storage_type(); bool mutability = consume_mutability(); if (tracer_) tracer_->NextLine(); if (V8_UNLIKELY(failed())) return nullptr; - return module_->signature_storage.New<ArrayType>(element_type, mutability); + return module_->signature_storage.New<ArrayType>(element_type, mutability, + is_shared); } // Consume the attribute field of an exception. diff --git a/deps/v8/src/wasm/module-decoder.cc b/deps/v8/src/wasm/module-decoder.cc index 0420a41e95c8..8d8ec430f071 100644 --- a/deps/v8/src/wasm/module-decoder.cc +++ b/deps/v8/src/wasm/module-decoder.cc @@ -4,6 +4,7 @@ #include "src/wasm/module-decoder.h" +#include "src/base/unique-array.h" #include "src/execution/isolate-inl.h" #include "src/logging/counters.h" #include "src/logging/metrics.h" @@ -359,8 +360,8 @@ void DecodeFunctionNames(base::Vector<const uint8_t> wire_bytes, // - all name payloads are copied out of the wire bytes. void DecodeCanonicalTypeNames( base::Vector<const uint8_t> wire_bytes, const WasmModule* module, - std::vector<base::OwnedVector<char>>& typenames, - std::map<uint32_t, std::vector<base::OwnedVector<char>>>& fieldnames, + std::vector<base::UniqueArray<char>>& typenames, + std::map<uint32_t, std::vector<base::UniqueArray<char>>>& fieldnames, size_t* total_allocated_size) { bool types_done = false; bool fields_done = false; @@ -399,7 +400,7 @@ void DecodeCanonicalTypeNames( if (!validate_utf8(&decoder, name)) continue; uint32_t length = name.length(); typenames[index] = - base::OwnedVector<char>::NewByCopying(base + name.offset(), length); + base::UniqueArray<char>::CopiedFrom(base + name.offset(), length); *total_allocated_size += length; } } else if (name_type == NameSectionKindCode::kFieldCode) { @@ -422,7 +423,7 @@ void DecodeCanonicalTypeNames( GetTypeCanonicalizer()->LookupStruct(canonical_index); auto const& entry = fieldnames.try_emplace( struct_index, size_t{struct_type->field_count()}); - std::vector<base::OwnedVector<char>>& field_names = entry.first->second; + std::vector<base::UniqueArray<char>>& field_names = entry.first->second; uint32_t fields_count = decoder.consume_u32v("fields count"); for (uint32_t j = 0; j < fields_count; j++) { uint32_t field_index = decoder.consume_u32v("field index"); @@ -433,8 +434,8 @@ void DecodeCanonicalTypeNames( if (!field_names[field_index].empty()) continue; if (!validate_utf8(&decoder, name)) continue; uint32_t length = name.length(); - field_names[field_index] = base::OwnedVector<char>::NewByCopying( - base + name.offset(), length); + field_names[field_index] = + base::UniqueArray<char>::CopiedFrom(base + name.offset(), length); *total_allocated_size += length; } if (!decoder.ok()) break; diff --git a/deps/v8/src/wasm/module-decoder.h b/deps/v8/src/wasm/module-decoder.h index 5cf3529581ad..5ba8d262ebe9 100644 --- a/deps/v8/src/wasm/module-decoder.h +++ b/deps/v8/src/wasm/module-decoder.h @@ -11,6 +11,7 @@ #include <memory> +#include "src/base/unique-array.h" #include "src/common/globals.h" #include "src/logging/metrics.h" #include "src/wasm/function-body-decoder.h" @@ -135,8 +136,8 @@ void DecodeFunctionNames(base::Vector<const uint8_t> wire_bytes, // The number of allocated characters will be added to {total_allocated_size}. void DecodeCanonicalTypeNames( base::Vector<const uint8_t> wire_bytes, const WasmModule* module, - std::vector<base::OwnedVector<char>>& typenames, - std::map<uint32_t, std::vector<base::OwnedVector<char>>>& fieldnames, + std::vector<base::UniqueArray<char>>& typenames, + std::map<uint32_t, std::vector<base::UniqueArray<char>>>& fieldnames, size_t* total_allocated_size); // Validate all functions in the module. Return the first validation error diff --git a/deps/v8/src/wasm/module-instantiate.cc b/deps/v8/src/wasm/module-instantiate.cc index 2ce07a3477a6..904d1ed2fe49 100644 --- a/deps/v8/src/wasm/module-instantiate.cc +++ b/deps/v8/src/wasm/module-instantiate.cc @@ -1270,11 +1270,13 @@ Maybe<bool> InstanceBuilder::Build_Phase1( // Process the initialization for the module's globals. //-------------------------------------------------------------------------- InitGlobals(); + if (thrower_->error()) return {}; //-------------------------------------------------------------------------- // Initialize non-defaultable tables. //-------------------------------------------------------------------------- SetTableInitialValues(); + if (thrower_->error()) return {}; //-------------------------------------------------------------------------- // Initialize the tags table. @@ -1377,6 +1379,22 @@ void InstanceBuilder::Build_Phase1_Infallible() { WasmDispatchTable::AddUse(isolate_, dispatch_table_handle, trusted_data_, i); } + + //-------------------------------------------------------------------------- + // Insert the new instance into the script's weak list of instances. This + // list is used for breakpoints affecting all instances belonging to the + // script. + //-------------------------------------------------------------------------- + DCHECK_EQ(untrusted_module_object_->script()->type(), Script::Type::kWasm); + DirectHandle<WeakArrayList> weak_instance_list( + untrusted_module_object_->script()->wasm_weak_instance_list(), isolate_); + DirectHandle<WasmInstanceObject> instance_object( + trusted_data_->instance_object(), isolate_); + weak_instance_list = + WeakArrayList::Append(isolate_, weak_instance_list, + MaybeObjectDirectHandle::Weak(instance_object)); + untrusted_module_object_->script()->set_wasm_weak_instance_list( + *weak_instance_list); } Maybe<bool> InstanceBuilder::Build_Phase2() { @@ -1599,7 +1617,7 @@ DirectHandle<JSFunction> CreateFunctionForCompileTimeImport( auto [name, builtin, length] = NameBuiltinLength(wki); Factory* factory = isolate->factory(); DirectHandle<NativeContext> context(isolate->native_context()); - DirectHandle<Map> map = isolate->strict_function_without_prototype_map(); + DirectHandle<Map> map = isolate->function_without_prototype_map(); DirectHandle<String> name_str = factory->InternalizeUtf8String(name); DirectHandle<SharedFunctionInfo> info = factory->NewSharedFunctionInfoForBuiltin(name_str, builtin, length, @@ -2145,12 +2163,14 @@ bool InstanceBuilder::ProcessImportedMemories( TryCast(memory_object->array_buffer(), &buffer)) { DCHECK_EQ(backing_store, buffer->GetBackingStore()); DCHECK_EQ(backing_store->is_shared(), buffer->is_shared()); + size_t buffer_byte_length = buffer->GetByteLength(); if (backing_store->is_shared()) { // Note: For shared memory, the backing store might have just grown in - // another thread. - DCHECK_GE(backing_store->byte_length(), buffer->GetByteLength()); + // another thread. Read the buffer's byte length first in case it is a + // growable SharedArrayBuffer (which also reads from the backing store). + DCHECK_GE(backing_store->byte_length(), buffer_byte_length); } else { - DCHECK_EQ(backing_store->byte_length(), buffer->GetByteLength()); + DCHECK_EQ(backing_store->byte_length(), buffer_byte_length); } } #endif // DEBUG diff --git a/deps/v8/src/wasm/names-provider.cc b/deps/v8/src/wasm/names-provider.cc index 5888eddbcb28..e268aa8b8a76 100644 --- a/deps/v8/src/wasm/names-provider.cc +++ b/deps/v8/src/wasm/names-provider.cc @@ -426,21 +426,22 @@ size_t StringMapSize(const std::map<uint32_t, std::string>& map) { size_t NamesProvider::EstimateCurrentMemoryConsumption() const { UPDATE_WHEN_CLASS_CHANGES(NamesProvider, 176); size_t result = sizeof(NamesProvider); - if (name_section_names_) { - DecodedNameSection* names = name_section_names_.get(); - result += names->local_names_.EstimateCurrentMemoryConsumption(); - result += names->label_names_.EstimateCurrentMemoryConsumption(); - result += names->type_names_.EstimateCurrentMemoryConsumption(); - result += names->table_names_.EstimateCurrentMemoryConsumption(); - result += names->memory_names_.EstimateCurrentMemoryConsumption(); - result += names->global_names_.EstimateCurrentMemoryConsumption(); - result += names->element_segment_names_.EstimateCurrentMemoryConsumption(); - result += names->data_segment_names_.EstimateCurrentMemoryConsumption(); - result += names->field_names_.EstimateCurrentMemoryConsumption(); - result += names->tag_names_.EstimateCurrentMemoryConsumption(); - } { base::MutexGuard lock(&mutex_); + if (name_section_names_) { + DecodedNameSection* names = name_section_names_.get(); + result += names->local_names_.EstimateCurrentMemoryConsumption(); + result += names->label_names_.EstimateCurrentMemoryConsumption(); + result += names->type_names_.EstimateCurrentMemoryConsumption(); + result += names->table_names_.EstimateCurrentMemoryConsumption(); + result += names->memory_names_.EstimateCurrentMemoryConsumption(); + result += names->global_names_.EstimateCurrentMemoryConsumption(); + result += + names->element_segment_names_.EstimateCurrentMemoryConsumption(); + result += names->data_segment_names_.EstimateCurrentMemoryConsumption(); + result += names->field_names_.EstimateCurrentMemoryConsumption(); + result += names->tag_names_.EstimateCurrentMemoryConsumption(); + } result += StringMapSize(import_export_function_names_); result += StringMapSize(import_export_table_names_); result += StringMapSize(import_export_memory_names_); diff --git a/deps/v8/src/wasm/names-provider.h b/deps/v8/src/wasm/names-provider.h index b7ce3d74ea33..0e14950ec365 100644 --- a/deps/v8/src/wasm/names-provider.h +++ b/deps/v8/src/wasm/names-provider.h @@ -12,6 +12,7 @@ #include <map> #include <string> +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/utils/utils.h" #include "src/wasm/wasm-module.h" @@ -122,7 +123,7 @@ class CanonicalTypeNamesProvider { void DecodeNameSections(); // TODO(jkummerow): Use Zone allocation for the character payloads? - using StringT = base::OwnedVector<char>; + using StringT = base::UniqueArray<char>; std::vector<StringT> type_names_; std::map<uint32_t, std::vector<StringT>> field_names_; diff --git a/deps/v8/src/wasm/pgo.cc b/deps/v8/src/wasm/pgo.cc index 6b5d864878c3..46c26846f322 100644 --- a/deps/v8/src/wasm/pgo.cc +++ b/deps/v8/src/wasm/pgo.cc @@ -4,6 +4,9 @@ #include "src/wasm/pgo.h" +#include <array> + +#include "src/base/unique-array.h" #include "src/wasm/decoder.h" #include "src/wasm/wasm-module-builder.h" // For {ZoneBuffer}. @@ -20,13 +23,13 @@ class ProfileGenerator { type_feedback_mutex_guard_(&module->type_feedback.mutex), tiering_budget_array_(tiering_budget_array) {} - base::OwnedVector<uint8_t> GetProfileData() { + base::UniqueArray<uint8_t> GetProfileData() { ZoneBuffer buffer{&zone_}; SerializeTypeFeedback(buffer); SerializeTieringInfo(buffer); - return base::OwnedCopyOf(buffer); + return base::UniqueCopyOf(buffer); } private: @@ -116,7 +119,7 @@ void DeserializeTypeFeedback(Decoder& decoder, const WasmModule* module) { uint32_t feedback_vector_size = decoder.consume_u32v("feedback vector size"); function_feedback.feedback_vector = - base::OwnedVector<CallSiteFeedback>::NewForOverwrite( + base::UniqueArray<CallSiteFeedback>::NewForOverwrite( feedback_vector_size); for (CallSiteFeedback& feedback : function_feedback.feedback_vector) { int num_cases = decoder.consume_i32v("num cases"); @@ -139,7 +142,7 @@ void DeserializeTypeFeedback(Decoder& decoder, const WasmModule* module) { // Deserialize {call_targets}. uint32_t num_call_targets = decoder.consume_u32v("num call targets"); function_feedback.call_targets = - base::OwnedVector<uint32_t>::NewForOverwrite(num_call_targets); + base::UniqueArray<uint32_t>::NewForOverwrite(num_call_targets); for (uint32_t& call_target : function_feedback.call_targets) { call_target = decoder.consume_u32v("call target"); } @@ -152,8 +155,7 @@ void DeserializeTypeFeedback(Decoder& decoder, const WasmModule* module) { FunctionTypeFeedback& old_feedback = feedback_it->second; CHECK(old_feedback.feedback_vector.empty() || old_feedback.feedback_vector.size() == feedback_vector_size); - CHECK_EQ(old_feedback.call_targets.as_vector(), - function_feedback.call_targets.as_vector()); + CHECK_EQ(old_feedback.call_targets, function_feedback.call_targets); std::swap(old_feedback.feedback_vector, function_feedback.feedback_vector); } @@ -201,18 +203,18 @@ void DumpProfileToFile(const WasmModule* module, // We use the same hash as for reported scripts, to make it easier to // correlate files to wasm modules (see {CreateWasmScript}). uint32_t hash = static_cast<uint32_t>(GetWireBytesHash(wire_bytes)); - base::EmbeddedVector<char, 32> filename; - SNPrintF(filename, "profile-wasm-%08x", hash); + std::array<char, 32> filename; + base::SNPrintF(filename, "profile-wasm-%08x", hash); ProfileGenerator profile_generator{module, tiering_budget_array}; - base::OwnedVector<uint8_t> profile_data = profile_generator.GetProfileData(); + base::UniqueArray<uint8_t> profile_data = profile_generator.GetProfileData(); PrintF( "Dumping Wasm PGO data to file '%s' (module size %zu, %u declared " "functions, %zu bytes PGO data)\n", - filename.begin(), wire_bytes.size(), module->num_declared_functions, + filename.data(), wire_bytes.size(), module->num_declared_functions, profile_data.size()); - if (FILE* file = base::OS::FOpen(filename.begin(), "wb")) { + if (FILE* file = base::OS::FOpen(filename.data(), "wb")) { size_t written = fwrite(profile_data.begin(), 1, profile_data.size(), file); CHECK_EQ(profile_data.size(), written); base::Fclose(file); @@ -226,12 +228,12 @@ std::unique_ptr<ProfileInformation> LoadProfileFromFile( // We use the same hash as for reported scripts, to make it easier to // correlate files to wasm modules (see {CreateWasmScript}). uint32_t hash = static_cast<uint32_t>(GetWireBytesHash(wire_bytes)); - base::EmbeddedVector<char, 32> filename; - SNPrintF(filename, "profile-wasm-%08x", hash); + std::array<char, 32> filename; + base::SNPrintF(filename, "profile-wasm-%08x", hash); - FILE* file = base::OS::FOpen(filename.begin(), "rb"); + FILE* file = base::OS::FOpen(filename.data(), "rb"); if (!file) { - PrintF("No Wasm PGO data found: Cannot open file '%s'\n", filename.begin()); + PrintF("No Wasm PGO data found: Cannot open file '%s'\n", filename.data()); return {}; } @@ -239,10 +241,10 @@ std::unique_ptr<ProfileInformation> LoadProfileFromFile( size_t size = ftell(file); rewind(file); - PrintF("Loading Wasm PGO data from file '%s' (%zu bytes)\n", filename.begin(), + PrintF("Loading Wasm PGO data from file '%s' (%zu bytes)\n", filename.data(), size); - base::OwnedVector<uint8_t> profile_data = - base::OwnedVector<uint8_t>::NewForOverwrite(size); + base::UniqueArray<uint8_t> profile_data = + base::UniqueArray<uint8_t>::NewForOverwrite(size); for (size_t read = 0; read < size;) { read += fread(profile_data.begin() + read, 1, size - read, file); CHECK(!ferror(file)); @@ -250,7 +252,7 @@ std::unique_ptr<ProfileInformation> LoadProfileFromFile( base::Fclose(file); - return RestoreProfileData(module, profile_data.as_vector()); + return RestoreProfileData(module, profile_data.as_span()); } } // namespace v8::internal::wasm diff --git a/deps/v8/src/wasm/stacks.cc b/deps/v8/src/wasm/stacks.cc index 964564fdd6bf..9db7206d3478 100644 --- a/deps/v8/src/wasm/stacks.cc +++ b/deps/v8/src/wasm/stacks.cc @@ -225,7 +225,7 @@ void StackMemory::Iterate(v8::internal::RootVisitor* v, Isolate* isolate, } } -bool StackMemory::Grow(Address current_fp, size_t min_size) { +bool StackMemory::Grow(Address parent_frame_fp, size_t min_size) { DCHECK(owned_); while (V8_UNLIKELY(active_segment_->next_segment_ != nullptr && active_segment_->next_segment_->size_ < min_size)) { @@ -261,7 +261,7 @@ bool StackMemory::Grow(Address current_fp, size_t min_size) { active_segment_->next_segment_ = new_segment; active_segment_ = new_segment; } - active_segment_->old_fp = current_fp; + active_segment_->parent_frame_fp = parent_frame_fp; size_ += active_segment_->size_; if (v8_flags.trace_wasm_stack_switching) { PrintF("Grow stack #%d by %zu bytes (limit: %p, base: %p)\n", id_, @@ -279,9 +279,9 @@ bool StackMemory::Grow(Address current_fp, size_t min_size) { Address StackMemory::Shrink() { DCHECK(owned_); DCHECK_NE(active_segment_->prev_segment_, nullptr); - Address old_fp = active_segment_->old_fp; + Address parent_frame_fp = active_segment_->parent_frame_fp; size_ -= active_segment_->size_; - active_segment_->old_fp = 0; + active_segment_->parent_frame_fp = 0; active_segment_ = active_segment_->prev_segment_; if (v8_flags.trace_wasm_stack_switching) { PrintF("Shrink stack #%d (limit: %p, base: %p)\n", id_, @@ -293,7 +293,7 @@ Address StackMemory::Shrink() { reinterpret_cast<uintptr_t>(active_segment_->limit_), active_segment_->base()); #endif - return old_fp; + return parent_frame_fp; } void StackMemory::ShrinkTo(Address stack_address) { @@ -367,4 +367,15 @@ size_t StackPool::Size() const { return freelist_.size() * sizeof(decltype(freelist_)::value_type) + size_; } +Address StackMemory::GetParentSegmentOldFP(Address child_fp) const { + for (auto segment = active_segment_; segment; + segment = segment->prev_segment_) { + if (reinterpret_cast<Address>(segment->limit_) <= child_fp && + child_fp <= segment->base()) { + return segment->parent_frame_fp; + } + } + return 0; +} + } // namespace v8::internal::wasm diff --git a/deps/v8/src/wasm/stacks.h b/deps/v8/src/wasm/stacks.h index 7cd25c52e8dc..eb4ff2d5756b 100644 --- a/deps/v8/src/wasm/stacks.h +++ b/deps/v8/src/wasm/stacks.h @@ -135,8 +135,11 @@ class StackMemory { void Iterate(v8::internal::RootVisitor* v, Isolate* isolate, ThreadLocalTop* thread); - Address old_fp() { return active_segment_->old_fp; } - bool Grow(Address current_fp, size_t min_size); + // We record the fp of the segment's parent frame (relocated to just below the + // return slots) to facilitate shrinking the current segment on return. + Address parent_frame_fp() const { return active_segment_->parent_frame_fp; } + Address GetParentSegmentOldFP(Address child_fp) const; + bool Grow(Address parent_frame_fp, size_t min_size); Address Shrink(); void ShrinkTo(Address stack_address); bool contains_only_old_pointers() const { @@ -161,7 +164,7 @@ class StackMemory { // References to segments of segmented stack StackSegment* next_segment_ = nullptr; StackSegment* prev_segment_ = nullptr; - Address old_fp = 0; + Address parent_frame_fp = 0; friend class StackMemory; }; diff --git a/deps/v8/src/wasm/std-object-sizes.h b/deps/v8/src/wasm/std-object-sizes.h index c8dc85e1557a..f201bb5d3465 100644 --- a/deps/v8/src/wasm/std-object-sizes.h +++ b/deps/v8/src/wasm/std-object-sizes.h @@ -15,7 +15,7 @@ #include <vector> #include "include/v8config.h" -#include "src/base/vector.h" +#include "src/base/unique-array.h" namespace v8::internal::wasm { @@ -32,7 +32,7 @@ inline size_t ContentSize(const std::vector<T>& vector) { } template <typename T> -inline size_t ContentSize(const base::OwnedVector<T>& vector) { +inline size_t ContentSize(const base::UniqueArray<T>& vector) { return vector.size() * sizeof(T); } diff --git a/deps/v8/src/wasm/streaming-decoder.cc b/deps/v8/src/wasm/streaming-decoder.cc index b2348f06dbed..2e3f7c703a1b 100644 --- a/deps/v8/src/wasm/streaming-decoder.cc +++ b/deps/v8/src/wasm/streaming-decoder.cc @@ -7,6 +7,7 @@ #include <optional> #include <span> +#include "src/base/unique-array.h" #include "src/logging/counters.h" #include "src/wasm/decoder.h" #include "src/wasm/leb-helper.h" @@ -35,11 +36,11 @@ class StreamingDecoder::SectionBuffer : public WireBytesStorage { base::Vector<const uint8_t> length_bytes) : // ID + length + payload module_offset_(module_offset), - bytes_(base::OwnedVector<uint8_t>::NewForOverwrite( + bytes_(base::UniqueArray<uint8_t>::NewForOverwrite( 1 + length_bytes.size() + payload_length)), payload_offset_(1 + length_bytes.size()) { bytes_.begin()[0] = id; - memcpy(bytes_.begin() + 1, &length_bytes.first(), length_bytes.size()); + memcpy(bytes_.begin() + 1, &length_bytes.front(), length_bytes.size()); } SectionCode section_code() const { @@ -56,14 +57,14 @@ class StreamingDecoder::SectionBuffer : public WireBytesStorage { std::optional<ModuleWireBytes> GetModuleBytes() const final { return {}; } uint32_t module_offset() const { return module_offset_; } - base::Vector<uint8_t> bytes() const { return bytes_.as_vector(); } + base::Vector<uint8_t> bytes() const { return bytes_.as_span(); } base::Vector<uint8_t> payload() const { return bytes() + payload_offset_; } size_t length() const { return bytes_.size(); } size_t payload_offset() const { return payload_offset_; } private: const uint32_t module_offset_; - const base::OwnedVector<uint8_t> bytes_; + const base::UniqueArray<uint8_t> bytes_; const size_t payload_offset_; }; @@ -345,7 +346,7 @@ size_t StreamingDecoder::DecodingState::ReadBytes( base::Vector<uint8_t> remaining_buf = buffer() + offset(); size_t num_bytes = std::min(bytes.size(), remaining_buf.size()); TRACE_STREAMING("ReadBytes(%zu bytes)\n", num_bytes); - memcpy(remaining_buf.begin(), &bytes.first(), num_bytes); + memcpy(remaining_buf.begin(), &bytes.front(), num_bytes); set_offset(offset() + num_bytes); return num_bytes; } @@ -379,7 +380,7 @@ void StreamingDecoder::Finish( // Create a final copy of the overall wire bytes; this will finally be // transferred and stored in the NativeModule. - base::OwnedVector<const uint8_t> bytes_copy; + base::UniqueArray<const uint8_t> bytes_copy; DCHECK_IMPLIES(full_wire_bytes_.back().empty(), full_wire_bytes_.size() == 1); size_t total_length = 0; if (!full_wire_bytes_.back().empty()) { @@ -388,7 +389,7 @@ void StreamingDecoder::Finish( // {DecodeSectionLength} enforces this with graceful error reporting. CHECK_LE(total_length, max_module_size()); } - auto all_bytes = base::OwnedVector<uint8_t>::NewForOverwrite(total_length); + auto all_bytes = base::UniqueArray<uint8_t>::NewForOverwrite(total_length); uint8_t* ptr = all_bytes.begin(); for (auto& bytes : full_wire_bytes_) { memcpy(ptr, bytes.data(), bytes.size()); @@ -411,12 +412,12 @@ void StreamingDecoder::Finish( struct CachingInterface : public WasmStreaming::ModuleCachingInterface { StreamingProcessor* const processor; - base::OwnedVector<const uint8_t>& wire_bytes; + base::UniqueArray<const uint8_t>& wire_bytes; bool did_try_deserialization = false; bool did_deserialize = false; CachingInterface(StreamingProcessor* proc, - base::OwnedVector<const uint8_t>& wire_bytes) + base::UniqueArray<const uint8_t>& wire_bytes) : processor(proc), wire_bytes(wire_bytes) {} // Public API: @@ -540,7 +541,7 @@ size_t StreamingDecoder::DecodeVarInt32::ReadBytes( base::Vector<uint8_t> remaining_buf = buf + offset(); size_t new_bytes = std::min(bytes.size(), remaining_buf.size()); TRACE_STREAMING("ReadBytes of a VarInt\n"); - memcpy(remaining_buf.begin(), &bytes.first(), new_bytes); + memcpy(remaining_buf.begin(), &bytes.front(), new_bytes); buf.Truncate(offset() + new_bytes); Decoder decoder(buf, streaming->module_offset() - static_cast<uint32_t>(offset())); diff --git a/deps/v8/src/wasm/streaming-decoder.h b/deps/v8/src/wasm/streaming-decoder.h index d6b5b5a34e89..9e51a933e15c 100644 --- a/deps/v8/src/wasm/streaming-decoder.h +++ b/deps/v8/src/wasm/streaming-decoder.h @@ -10,10 +10,12 @@ #endif // !V8_ENABLE_WEBASSEMBLY #include <memory> +#include <string_view> #include <vector> #include "include/v8-wasm.h" // For WasmStreaming::ModuleCachingInterface. #include "src/base/macros.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/wasm/compilation-environment.h" #include "src/wasm/wasm-constants.h" @@ -67,7 +69,7 @@ class V8_EXPORT_PRIVATE StreamingProcessor { virtual void OnFinishedChunk() = 0; // Report the end of the stream. This will be called even after an error has // been detected. In any case, the parameter is the total received bytes. - virtual void OnFinishedStream(base::OwnedVector<const uint8_t> bytes, + virtual void OnFinishedStream(base::UniqueArray<const uint8_t> bytes, bool after_error) = 0; // Report the abortion of the stream. virtual void OnAbort() = 0; @@ -77,7 +79,7 @@ class V8_EXPORT_PRIVATE StreamingProcessor { // taken over by the deserialized module (the parameter will be reset to an // empty vector); otherwise ownership stays with the caller. virtual bool Deserialize(base::Vector<const uint8_t> module_bytes, - base::OwnedVector<const uint8_t>& wire_bytes) = 0; + base::UniqueArray<const uint8_t>& wire_bytes) = 0; }; // The StreamingDecoder takes a sequence of byte arrays, each received by a call @@ -124,7 +126,7 @@ class V8_EXPORT_PRIVATE StreamingDecoder { const std::string& url() const { return *url_; } std::shared_ptr<const std::string> shared_url() const { return url_; } - void SetUrl(base::Vector<const char> url) { + void SetUrl(std::string_view url) { // We shouldn't modify {url_} while it is being read. The API contract // hence states that {SetUrl()} must be called early. // Enforcing this with a CHECK is possibly racy when an attacker with an @@ -132,7 +134,7 @@ class V8_EXPORT_PRIVATE StreamingDecoder { // becomes a problem, we can add a lock. As an attack mitigation, a CHECK // that fails most of the time is probably good enough. SBXCHECK_EQ(stream_state_, kReceivingBytes); - url_->assign(url.begin(), url.size()); + url_->assign(url); // Safely crash if a race did happen: SBXCHECK_EQ(stream_state_, kReceivingBytes); } diff --git a/deps/v8/src/wasm/struct-types.h b/deps/v8/src/wasm/struct-types.h index 89c58e18fb33..3833ce86dc0d 100644 --- a/deps/v8/src/wasm/struct-types.h +++ b/deps/v8/src/wasm/struct-types.h @@ -63,6 +63,7 @@ class StructTypeBase : public ZoneObject { uint32_t field_offset(uint32_t index) const { DCHECK_LT(index, field_count()); if (index == 0) { + if (v8_flags.wasm_merged_descriptors) return 0; return is_descriptor() ? kTaggedSize : 0; } DCHECK(offsets_initialized_); @@ -70,6 +71,7 @@ class StructTypeBase : public ZoneObject { } uint32_t total_fields_size() const { if (field_count() == 0) { + if (v8_flags.wasm_merged_descriptors) return 0; return is_descriptor() ? kTaggedSize : 0; } return field_offsets_[field_count() - 1]; @@ -90,7 +92,11 @@ class StructTypeBase : public ZoneObject { // update the offset calculation for the first field. UNIMPLEMENTED(); } - uint32_t offset = is_descriptor() ? kTaggedSize : 0; + uint32_t offset = 0; + if (!v8_flags.wasm_merged_descriptors && is_descriptor()) { + // Non-merged descriptors reserve a slot. + offset = kTaggedSize; + } offset += field(0).value_kind_size(); // Optimization: we track the last gap that was introduced by alignment, // and place any sufficiently-small fields in it. @@ -175,7 +181,8 @@ class StructTypeBase : public ZoneObject { // offset == 0 could mean that we'll compute the offsets later, // or that this is the first field's offset being copied over from // another struct type. - DCHECK(offset == 0 || (is_descriptor_ && offset == kTaggedSize)); + DCHECK(offset == 0 || (!v8_flags.wasm_merged_descriptors && + is_descriptor_ && offset == kTaggedSize)); } mutabilities_[cursor_] = mutability; buffer_[cursor_++] = type; @@ -183,7 +190,10 @@ class StructTypeBase : public ZoneObject { void set_total_fields_size(uint32_t size) { if (field_count_ == 0) { - DCHECK_EQ(is_descriptor_ ? kTaggedSize : 0, size); + DCHECK_EQ(!v8_flags.wasm_merged_descriptors && is_descriptor_ + ? kTaggedSize + : 0, + size); return; } field_offsets_[field_count_ - 1] = size; @@ -222,9 +232,6 @@ class StructTypeBase : public ZoneObject { bool* const mutabilities_; }; - static const size_t kMaxFieldOffset = - (kV8MaxWasmStructFields - 1) * kMaxValueTypeSize; - private: friend class StructType; friend class CanonicalStructType; @@ -257,7 +264,8 @@ class StructType : public StructTypeBase { bool operator==(const StructType& other) const { if (this == &other) return true; if (field_count() != other.field_count()) return false; - if (this->is_descriptor() != other.is_descriptor()) return false; + if (is_descriptor() != other.is_descriptor()) return false; + if (is_shared() != other.is_shared()) return false; return std::equal(fields().begin(), fields().end(), other.fields().begin()) && std::equal(mutabilities().begin(), mutabilities().end(), @@ -296,6 +304,7 @@ class CanonicalStructType : public StructTypeBase { if (this == &other) return true; if (field_count() != other.field_count()) return false; if (is_descriptor() != other.is_descriptor()) return false; + if (is_shared() != other.is_shared()) return false; return std::equal(fields().begin(), fields().end(), other.fields().begin()) && std::equal(mutabilities().begin(), mutabilities().end(), @@ -320,21 +329,25 @@ inline std::ostream& operator<<(std::ostream& out, StructTypeBase type) { class ArrayTypeBase : public ZoneObject { public: - constexpr explicit ArrayTypeBase(bool mutability) : mutability_(mutability) {} + constexpr ArrayTypeBase(bool mutability, SharedFlag is_shared) + : mutability_(mutability), is_shared_(is_shared) {} bool mutability() const { return mutability_; } + SharedFlag is_shared() const { return is_shared_; } protected: const bool mutability_; + const SharedFlag is_shared_; }; class ArrayType : public ArrayTypeBase { public: - constexpr ArrayType(ValueType rep, bool mutability) - : ArrayTypeBase(mutability), rep_(rep) {} + constexpr ArrayType(ValueType rep, bool mutability, SharedFlag is_shared) + : ArrayTypeBase(mutability, is_shared), rep_(rep) {} bool operator==(const ArrayType& other) const { - return rep_ == other.rep_ && mutability_ == other.mutability_; + return rep_ == other.rep_ && mutability_ == other.mutability_ && + is_shared_ == other.is_shared_; } ValueType element_type() const { return rep_; } @@ -347,11 +360,13 @@ class ArrayType : public ArrayTypeBase { class CanonicalArrayType : public ArrayTypeBase { public: - CanonicalArrayType(CanonicalValueType rep, bool mutability) - : ArrayTypeBase(mutability), rep_(rep) {} + CanonicalArrayType(CanonicalValueType rep, bool mutability, + SharedFlag is_shared) + : ArrayTypeBase(mutability, is_shared), rep_(rep) {} bool operator==(const CanonicalArrayType& other) const { - return rep_ == other.rep_ && mutability_ == other.mutability_; + return rep_ == other.rep_ && mutability_ == other.mutability_ && + is_shared_ == other.is_shared_; } CanonicalValueType element_type() const { return rep_; } diff --git a/deps/v8/src/wasm/turboshaft-graph-interface-inl.h b/deps/v8/src/wasm/turboshaft-graph-interface-inl.h index c64b53a58ca1..05ed77ba038f 100644 --- a/deps/v8/src/wasm/turboshaft-graph-interface-inl.h +++ b/deps/v8/src/wasm/turboshaft-graph-interface-inl.h @@ -181,9 +181,9 @@ void WasmGraphBuilderBase<Assembler>::BuildSetNewStackLimit( old_limit, new_limit, RegisterRepresentation::WordPtr(), MemoryRepresentation::UintPtr(), compiler::MemoryAccessKind::kNormal, RegisterRepresentation::WordPtr()); - __ Store(__ LoadRootRegister(), new_limit, StoreOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), compiler::kNoWriteBarrier, - IsolateData::real_jslimit_offset()); + __ Store(__ IsolateField(IsolateFieldId::kRealJsLimit), new_limit, + StoreOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), + compiler::kNoWriteBarrier); } template <typename Assembler> @@ -197,37 +197,43 @@ auto WasmGraphBuilderBase<Assembler>::BuildSwitchToTheCentralStack( auto sig = FixedSizeSignature<MachineType>::Params(MachineType::Pointer(), MachineType::Pointer()) .Returns(MachineType::Pointer()); - OpIndex central_stack_sp = - CallC(&sig, ExternalReference::wasm_switch_to_the_central_stack_for_js(), - {__ ExternalConstant(ExternalReference::isolate_address()), - __ FramePointer()}); + OpIndex central_stack_sp = CallC( + &sig, ExternalReference::wasm_switch_to_the_central_stack_for_js(), + {__ IsolateField(IsolateFieldId::kIsolateAddress), __ FramePointer()}); #else // Set the is_on_central_stack flag. - OpIndex isolate_root = __ LoadRootRegister(); - __ Store(isolate_root, __ Word32Constant(1), LoadOp::Kind::RawAligned(), - MemoryRepresentation::Uint8(), compiler::kNoWriteBarrier, - IsolateData::is_on_central_stack_flag_offset()); + V<WordPtr> is_on_central_stack_flag_address = + __ IsolateField(IsolateFieldId::kIsOnCentralStackFlag); + __ Store(is_on_central_stack_flag_address, __ Word32Constant(1), + StoreOp::Kind::RawAligned(), MemoryRepresentation::Uint8(), + compiler::kNoWriteBarrier); // Save the old fp and the target sp in the StackMemory's stack switch info. // We are not on the main stack, so the active stack must be set. - V<WordPtr> active_stack = __ Load(isolate_root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::active_stack_offset()); + V<WordPtr> active_stack_address = + __ IsolateField(IsolateFieldId::kActiveStack); + V<WordPtr> active_stack = + __ Load(active_stack_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); __ Store(active_stack, __ FramePointer(), StoreOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), compiler::kNoWriteBarrier, StackMemory::stack_switch_source_fp_offset()); - V<WordPtr> central_stack_sp = __ Load( - isolate_root, LoadOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), - Isolate::central_stack_sp_offset()); + V<WordPtr> central_stack_sp_address = + __ IsolateField(IsolateFieldId::kCentralStackSP); + V<WordPtr> central_stack_sp = + __ Load(central_stack_sp_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); __ Store(active_stack, central_stack_sp, StoreOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), compiler::kNoWriteBarrier, StackMemory::stack_switch_target_sp_offset()); // Switch the stack limit and the stack pointer. - V<WordPtr> central_stack_limit = __ Load( - isolate_root, LoadOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), - Isolate::central_stack_limit_offset()); + V<WordPtr> central_stack_limit_address = + __ IsolateField(IsolateFieldId::kCentralStackLimit); + V<WordPtr> central_stack_limit = + __ Load(central_stack_limit_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); BuildSetNewStackLimit(old_limit, central_stack_limit); #endif OpIndex old_sp = __ LoadStackPointer(); @@ -239,16 +245,19 @@ template <typename Assembler> inline auto WasmGraphBuilderBase<Assembler>::BuildSwitchToTheCentralStackIfNeeded() -> std::pair<V<WordPtr>, V<WordPtr>> { - V<WordPtr> isolate_root = __ LoadRootRegister(); - V<Word32> is_on_central_stack_flag = __ Load( - isolate_root, LoadOp::Kind::RawAligned(), MemoryRepresentation::Uint8(), - IsolateData::is_on_central_stack_flag_offset()); + V<WordPtr> is_on_central_stack_flag_address = + __ IsolateField(IsolateFieldId::kIsOnCentralStackFlag); + V<Word32> is_on_central_stack_flag = + __ Load(is_on_central_stack_flag_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::Uint8()); ScopedVar<WordPtr> old_sp_var(this, __ IntPtrConstant(0)); ScopedVar<WordPtr> old_limit_var(this, __ IntPtrConstant(0)); IF_NOT (LIKELY(is_on_central_stack_flag)) { - V<WordPtr> old_limit = __ Load(isolate_root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::real_jslimit_offset()); + V<WordPtr> real_jslimit_address = + __ IsolateField(IsolateFieldId::kRealJsLimit); + V<WordPtr> old_limit = + __ Load(real_jslimit_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); V<WordPtr> old_sp = BuildSwitchToTheCentralStack(old_limit); old_sp_var = old_sp; old_limit_var = old_limit; @@ -267,28 +276,33 @@ void WasmGraphBuilderBase<Assembler>::BuildSwitchBackFromCentralStack( auto sig = FixedSizeSignature<MachineType>::Params(MachineType::Pointer()); IF_NOT (LIKELY(__ WordPtrEqual(old_sp, __ IntPtrConstant(0)))) { CallC(&sig, ExternalReference::wasm_switch_from_the_central_stack_for_js(), - {__ ExternalConstant(ExternalReference::isolate_address())}); + {__ IsolateField(IsolateFieldId::kIsolateAddress)}); #else IF_NOT (LIKELY(__ WordPtrEqual(old_sp, __ IntPtrConstant(0)))) { // Reset is_on_central_stack flag. - V<WordPtr> isolate_root = __ LoadRootRegister(); - __ Store(isolate_root, __ Word32Constant(0), StoreOp::Kind::RawAligned(), - MemoryRepresentation::Uint8(), compiler::kNoWriteBarrier, - IsolateData::is_on_central_stack_flag_offset()); + V<WordPtr> is_on_central_stack_flag_address = + __ IsolateField(IsolateFieldId::kIsOnCentralStackFlag); + __ Store(is_on_central_stack_flag_address, __ Word32Constant(0), + StoreOp::Kind::RawAligned(), MemoryRepresentation::Uint8(), + compiler::kNoWriteBarrier); // Clear stack switch info. // We are not on the main stack, so the active stack must be set. - V<WordPtr> active_stack = __ Load(isolate_root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::active_stack_offset()); + V<WordPtr> active_stack_address = + __ IsolateField(IsolateFieldId::kActiveStack); + V<WordPtr> active_stack = + __ Load(active_stack_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); __ Store(active_stack, __ UintPtrConstant(0), StoreOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), compiler::kNoWriteBarrier, StackMemory::stack_switch_source_fp_offset()); // Restore the old stack limit and stack pointer. - V<WordPtr> real_jslimit = __ Load(isolate_root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::real_jslimit_offset()); + V<WordPtr> real_jslimit_address = + __ IsolateField(IsolateFieldId::kRealJsLimit); + V<WordPtr> real_jslimit = + __ Load(real_jslimit_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); BuildSetNewStackLimit(real_jslimit, old_limit); #endif __ SetStackPointer(old_sp); diff --git a/deps/v8/src/wasm/turboshaft-graph-interface.cc b/deps/v8/src/wasm/turboshaft-graph-interface.cc index 1fef1399ee8d..9927f74e5e05 100644 --- a/deps/v8/src/wasm/turboshaft-graph-interface.cc +++ b/deps/v8/src/wasm/turboshaft-graph-interface.cc @@ -27,6 +27,7 @@ #include "src/objects/object-list-macros.h" #include "src/strings/unicode.h" #include "src/trap-handler/trap-handler.h" +#include "src/wasm/baseline/liftoff-compiler.h" #include "src/wasm/canonical-types.h" #include "src/wasm/compilation-environment.h" #include "src/wasm/function-body-decoder-impl.h" @@ -88,6 +89,7 @@ using compiler::turboshaft::Variable; using compiler::turboshaft::WasmArrayNullable; using compiler::turboshaft::WasmStackCheckOp; using compiler::turboshaft::WasmStringRefNullable; +using compiler::turboshaft::WasmStructNonNullable; using compiler::turboshaft::WasmStructNullable; using compiler::turboshaft::WasmTypeAnnotationOp; using compiler::turboshaft::WasmTypeCastOp; @@ -253,7 +255,8 @@ class TurboshaftGraphBuildingInterface std::unique_ptr<AssumptionsJournal>* assumptions, ZoneVector<WasmInliningPosition>* inlining_positions, int func_index, const WireBytesStorage* wire_bytes, Validation validate_inlinees, - WasmFunctionCoverageData* coverage_data) + WasmFunctionCoverageData* coverage_data, + DelayedCounterUpdates* counter_updates) : WasmGraphBuilderBase(zone, assembler), mode_(kRegular), block_phis_(zone), @@ -267,7 +270,8 @@ class TurboshaftGraphBuildingInterface wire_bytes_(wire_bytes), validate_inlinees_(validate_inlinees), return_phis_(nullptr), - is_inlined_tail_call_(false) { + is_inlined_tail_call_(false), + counter_updates_(counter_updates) { DCHECK_NOT_NULL(env_); DCHECK_NOT_NULL(env_->module); @@ -287,7 +291,8 @@ class TurboshaftGraphBuildingInterface const WireBytesStorage* wire_bytes, Validation validate_inlinees, base::Vector<OpIndex> real_parameters, TSBlock* return_block, BlockPhis* return_phis, TSBlock* catch_block, bool is_inlined_tail_call, - OptionalV<EagerFrameState> parent_frame_state) + OptionalV<EagerFrameState> parent_frame_state, + DelayedCounterUpdates* counter_updates) : WasmGraphBuilderBase(zone, assembler), mode_(mode), block_phis_(zone), @@ -304,7 +309,8 @@ class TurboshaftGraphBuildingInterface return_phis_(return_phis), return_catch_block_(catch_block), is_inlined_tail_call_(is_inlined_tail_call), - parent_frame_state_(parent_frame_state) { + parent_frame_state_(parent_frame_state), + counter_updates_(counter_updates) { DCHECK_NE(mode_, kRegular); DCHECK_EQ(return_block == nullptr, mode == kInlinedTailCall); DCHECK_EQ(catch_block != nullptr, mode == kInlinedWithCatch); @@ -410,9 +416,10 @@ class TurboshaftGraphBuildingInterface if (v8_flags.debug_code) { IF_NOT (LIKELY(__ HasInstanceType(trusted_instance_data, - WASM_TRUSTED_INSTANCE_DATA_TYPE))) { - OpIndex message_id = __ TaggedIndexConstant( - static_cast<int32_t>(AbortReason::kUnexpectedInstanceType)); + WASM_TRUSTED_INSTANCE_DATA_TYPE, + SharedFlag{false}))) { + OpIndex message_id = + __ SmiConstant(Smi::FromEnum(AbortReason::kUnexpectedInstanceType)); __ WasmCallRuntime(decoder->zone(), Runtime::kAbort, {message_id}, __ NoContextConstant()); __ Unreachable(); @@ -420,10 +427,8 @@ class TurboshaftGraphBuildingInterface } if (mode_ == kRegular) { - StackCheck(WasmStackCheckOp::Kind::kFunctionEntry, decoder); - // The stack check could make memory growth visible, so only initialize - // the InstanceCache after that. - instance_cache_.Initialize(trusted_instance_data, decoder->module_); + StackCheck(WasmStackCheckOp::Kind::kFunctionEntry); + instance_cache_.Initialize(trusted_instance_data); } if (v8_flags.trace_wasm) { @@ -544,7 +549,7 @@ class TurboshaftGraphBuildingInterface block->start_merge[i].op = phi; } - StackCheck(WasmStackCheckOp::Kind::kLoop, decoder); + StackCheck(WasmStackCheckOp::Kind::kLoop); TSBlock* loop_merge = NewBlockWithPhis(decoder, &block->start_merge); block->merge_block = loop_merge; @@ -911,8 +916,7 @@ class TurboshaftGraphBuildingInterface __ NoContextConstant()); } if (mode_ == kRegular || mode_ == kInlinedTailCall) { - __ Return(__ Word32Constant(0), base::VectorOf(return_values), - v8_flags.wasm_growable_stacks); + __ Return(__ Word32Constant(0), base::VectorOf(return_values)); } else { // Do not add return values if we are in unreachable code. if (__ generating_unreachable_operations()) return; @@ -1089,8 +1093,8 @@ class TurboshaftGraphBuildingInterface void AssertNotNullTypecheck(FullDecoder* decoder, const Value& obj, Value* result) { - __ AssertNotNull(obj.get<Object>(), obj.type, TrapId::kTrapIllegalCast); - Forward(decoder, obj, result); + result->op = + __ AssertNotNull(obj.get<Object>(), obj.type, TrapId::kTrapIllegalCast); } void NopForTestingUnsupportedInLiftoff(FullDecoder* decoder) { @@ -1621,8 +1625,13 @@ class TurboshaftGraphBuildingInterface void CurrentMemoryPages(FullDecoder* decoder, const MemoryIndexImmediate& imm, Value* result) { + V<WordPtr> size_wordptr = imm.memory->is_shared + ? __ Load(MemSizeAddress(imm.index), + LoadOp::Kind::RawAligned().Atomic(), + MemoryRepresentation::UintPtr(), 0) + : MemSize(imm.index); V<WordPtr> result_wordptr = - __ WordPtrShiftRightArithmetic(MemSize(imm.index), kWasmPageSizeLog2); + __ WordPtrShiftRightArithmetic(size_wordptr, kWasmPageSizeLog2); // In the 32-bit case, truncation happens implicitly. if (imm.memory->is_memory64()) { result->op = __ ChangeIntPtrToInt64(result_wordptr); @@ -1656,7 +1665,6 @@ class TurboshaftGraphBuildingInterface result->op = result_64; } - instance_cache_.ReloadCachedMemory(); } V<Word32> IsExternRefString(const Value value) { @@ -1721,10 +1729,11 @@ class TurboshaftGraphBuildingInterface #endif void SetDataViewOpForErrorMessage(DataViewOp op_type) { - OpIndex isolate_root = __ LoadRootRegister(); - __ Store(isolate_root, __ Word32Constant(op_type), + V<WordPtr> error_message_param = + __ IsolateField(IsolateFieldId::kErrorMessageParam); + __ Store(error_message_param, __ Word32Constant(op_type), StoreOp::Kind::RawAligned(), MemoryRepresentation::Uint8(), - compiler::kNoWriteBarrier, Isolate::error_message_param_offset()); + compiler::kNoWriteBarrier); } void ThrowDataViewTypeError(FullDecoder* decoder, V<Object> dataview, @@ -1846,7 +1855,8 @@ class TurboshaftGraphBuildingInterface // - non-resizable ArrayBuffers, length-tracking and non-length-tracking // - non-growable SharedArrayBuffers, length-tracking and non-length-tr. // - growable SharedArrayBuffers, non-length-tracking - IF (LIKELY(__ HasInstanceType(dataview, InstanceType::JS_DATA_VIEW_TYPE))) { + IF (LIKELY(__ HasInstanceType(dataview, InstanceType::JS_DATA_VIEW_TYPE, + SharedFlag{false}))) { if (op_type != DataViewOp::kByteLength) { DataViewRangeCheck(decoder, offset, __ IntPtrConstant(0), op_type, check_for_exception); @@ -1862,7 +1872,8 @@ class TurboshaftGraphBuildingInterface // - resizable ArrayBuffers, length-tracking and non-length-tracking // - growable SharedArrayBuffers, length-tracking GOTO_IF_NOT(LIKELY(__ HasInstanceType( - dataview, InstanceType::JS_RAB_GSAB_DATA_VIEW_TYPE)), + dataview, InstanceType::JS_RAB_GSAB_DATA_VIEW_TYPE, + SharedFlag{false})), type_error_label); if (op_type != DataViewOp::kByteLength) { DataViewRangeCheck(decoder, offset, __ IntPtrConstant(0), op_type, @@ -1874,9 +1885,9 @@ class TurboshaftGraphBuildingInterface V<Word32> bit_field = __ LoadField<Word32>( dataview, AccessBuilder::ForJSArrayBufferViewBitField()); V<Word32> length_tracking = __ Word32BitwiseAnd( - bit_field, JSArrayBufferView::IsLengthTrackingBit::kMask); + bit_field, JSArrayBufferView::Bits::IsLengthTrackingBit::kMask); V<Word32> backed_by_rab_bit = __ Word32BitwiseAnd( - bit_field, JSArrayBufferView::IsBackedByRabBit::kMask); + bit_field, JSArrayBufferView::Bits::IsBackedByRabBit::kMask); V<Object> buffer = __ LoadField<Object>( dataview, compiler::AccessBuilder::ForJSArrayBufferViewBuffer()); @@ -2151,30 +2162,28 @@ class TurboshaftGraphBuildingInterface V<Context> native_context = instance_cache_.native_context(); - __ Store(__ LoadRootRegister(), - __ BitcastHeapObjectToWordPtr(native_context), + V<WordPtr> context_address = __ IsolateField(IsolateFieldId::kContext); + __ Store(context_address, __ BitcastHeapObjectToWordPtr(native_context), StoreOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), - compiler::kNoWriteBarrier, Isolate::context_offset()); + compiler::kNoWriteBarrier); auto [old_sp, old_limit] = BuildSwitchToTheCentralStackIfNeeded(); OpIndex ret_val = __ Call(target_address, OpIndex::Invalid(), base::VectorOf(inputs), ts_call_descriptor); BuildSwitchBackFromCentralStack(old_sp, old_limit); - instance_cache_.ReloadCachedMemory(); #if DEBUG // Reset the context again after the call, to make sure nobody is using the // leftover context in the isolate. - __ Store(__ LoadRootRegister(), __ WordPtrConstant(Context::kNoContext), + __ Store(context_address, __ WordPtrConstant(Context::kNoContext), StoreOp::Kind::RawAligned(), MemoryRepresentation::UintPtr(), - compiler::kNoWriteBarrier, Isolate::context_offset()); + compiler::kNoWriteBarrier); #endif V<Object> exception = __ Load( - __ LoadRootRegister(), LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), IsolateData::exception_offset()); + __ IsolateField(IsolateFieldId::kException), LoadOp::Kind::RawAligned(), + MemoryRepresentation::AnyUncompressedTagged()); - IF_NOT (LIKELY(__ TaggedEqual(exception, - __ LoadRoot<RootIndex::kTheHoleValue>()))) { + IF_NOT (LIKELY(__ IsRootConstant(exception, RootIndex::kTheHoleValue))) { CallBuiltinThroughJumptable< BuiltinCallDescriptor::WasmPropagateException>(decoder, {}, check_for_exception); @@ -2498,7 +2507,7 @@ class TurboshaftGraphBuildingInterface Label<String> search_done_label(&asm_); GOTO_IF_NOT(__ IsNull(search, args[1].type), search_done_label, search); - GOTO(search_done_label, __ LoadRoot<RootIndex::knull_string>()); + GOTO(search_done_label, __ RootConstant<RootIndex::knull_string>()); BIND(search_done_label, search_value); search = search_value; } @@ -2760,8 +2769,7 @@ class TurboshaftGraphBuildingInterface if (HandleWellKnownImport(decoder, imm, args, &wki_return, check_for_exception)) { if (mode_ == kRegular || mode_ == kInlinedTailCall) { - __ Return(__ Word32Constant(0), base::VectorOf({wki_return.op}), - v8_flags.wasm_growable_stacks); + __ Return(__ Word32Constant(0), base::VectorOf({wki_return.op})); } else if (!__ generating_unreachable_operations()) { return_phis_->AddInputForPhi(0, wki_return.op); __ Goto(return_block_); @@ -2908,6 +2916,10 @@ class TurboshaftGraphBuildingInterface : ""); } __ Goto(case_blocks[i + 1]); + // Do not use the deopt slowpath if we decided to not inline (at + // least) one call target. + // Otherwise, this could lead to a deopt loop. + use_deopt_slowpath = false; continue; } @@ -2918,7 +2930,7 @@ class TurboshaftGraphBuildingInterface if (use_deopt_slowpath && is_last_feedback_case) { DeoptIfNot(decoder, __ Word32Equal(target, inlined_target), frame_state); - } else { + } else { TSBlock* inline_block = __ NewBlock(); BranchHint hint = is_last_feedback_case ? BranchHint::kTrue : BranchHint::kNone; @@ -3174,8 +3186,8 @@ class TurboshaftGraphBuildingInterface __ Goto(case_blocks[i + 1]); // Do not use the deopt slowpath if we decided to not inline (at // least) one call target. Otherwise, this could lead to a deopt - // loop. This however is ensured for kMap mode. - DCHECK(!use_deopt_slowpath); + // loop. + use_deopt_slowpath = false; continue; } } @@ -3233,6 +3245,8 @@ class TurboshaftGraphBuildingInterface } InlineWasmCall(decoder, inlined_index, sig, static_cast<uint32_t>(i), false, args, direct_returns.data()); + // InlineWasmCall might have called disable_deopts(). + use_deopt_slowpath = use_deopt_slowpath && deopts_enabled(); if (__ current_block() != nullptr) { // Only add phi inputs and a Goto to {merge} if the current_block is @@ -3855,10 +3869,11 @@ class TurboshaftGraphBuildingInterface BindBlockAndGeneratePhis(decoder, block->false_or_loop_or_catch_block, nullptr, &block->exception); + V<Symbol> tag_symbol = + __ RootConstant<RootIndex::kwasm_exception_tag_symbol>(); V<WasmExceptionTag> caught_tag = V<WasmExceptionTag>::Cast( CallBuiltinThroughJumptable<BuiltinCallDescriptor::WasmGetOwnProperty>( - decoder, {block->exception, - __ LoadRoot<RootIndex::kwasm_exception_tag_symbol>()})); + decoder, {block->exception, tag_symbol})); // TODO(14616): Support shared tags. V<TrustedFixedArray> instance_tags = LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( @@ -3883,7 +3898,7 @@ class TurboshaftGraphBuildingInterface // the JSTag signature, i.e. a single externref or (ref extern), otherwise // we know statically that it cannot be the JSTag. V<Word32> caught_tag_undefined = - __ TaggedEqual(caught_tag, __ LoadRoot<RootIndex::kUndefinedValue>()); + __ IsRootConstant(caught_tag, RootIndex::kUndefinedValue); Label<Object> if_catch(&asm_); Label<> no_catch_merge(&asm_); @@ -3984,16 +3999,17 @@ class TurboshaftGraphBuildingInterface if (catch_case.kind == kCatchAll || catch_case.kind == kCatchAllRef) { if (catch_case.kind == kCatchAllRef) { DCHECK_EQ(values.size(), 1); - values.last().op = - __ AnnotateWasmType(block->exception, values.last().type); + values.back().op = + __ AnnotateWasmType(block->exception, values.back().type); } BrOrRet(decoder, catch_case.br_imm.depth); return; } + V<Symbol> tag_symbol = + __ RootConstant<RootIndex::kwasm_exception_tag_symbol>(); V<WasmExceptionTag> caught_tag = V<WasmExceptionTag>::Cast( CallBuiltinThroughJumptable<BuiltinCallDescriptor::WasmGetOwnProperty>( - decoder, {block->exception, - __ LoadRoot<RootIndex::kwasm_exception_tag_symbol>()})); + decoder, {block->exception, tag_symbol})); // TODO(14616): Support shared tags. V<TrustedFixedArray> instance_tags = LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( @@ -4019,7 +4035,7 @@ class TurboshaftGraphBuildingInterface // the JSTag signature, i.e. a single externref, otherwise // we know statically that it cannot be the JSTag. V<Word32> caught_tag_undefined = - __ TaggedEqual(caught_tag, __ LoadRoot<RootIndex::kUndefinedValue>()); + __ IsRootConstant(caught_tag, RootIndex::kUndefinedValue); Label<Object> if_catch(&asm_); Label<> no_catch_merge(&asm_); @@ -4055,8 +4071,8 @@ class TurboshaftGraphBuildingInterface // exception. values[0].op = __ AnnotateWasmType(caught_exception, values[0].type); if (catch_case.kind == kCatchRef) { - values.last().op = - __ AnnotateWasmType(block->exception, values.last().type); + values.back().op = + __ AnnotateWasmType(block->exception, values.back().type); } } else { TSBlock* if_catch = __ NewBlock(); @@ -4066,8 +4082,8 @@ class TurboshaftGraphBuildingInterface if (catch_case.kind == kCatchRef) { UnpackWasmException(decoder, block->exception, values.SubVector(0, values.size() - 1)); - values.last().op = - __ AnnotateWasmType(block->exception, values.last().type); + values.back().op = + __ AnnotateWasmType(block->exception, values.back().type); } else { UnpackWasmException(decoder, block->exception, values); } @@ -4075,7 +4091,7 @@ class TurboshaftGraphBuildingInterface BrOrRet(decoder, catch_case.br_imm.depth); - bool is_last = &catch_case == &block->catch_cases.last(); + bool is_last = &catch_case == &block->catch_cases.back(); if (is_last && !decoder->HasCatchAll(block)) { BindBlockAndGeneratePhis(decoder, block->false_or_loop_or_catch_block, nullptr, &block->exception); @@ -4166,7 +4182,7 @@ class TurboshaftGraphBuildingInterface __ Load(input_cont.op, LoadOp::Kind::TaggedBase(), MemoryRepresentation::TaggedPointer(), offsetof(WasmContinuationObject, stack_obj_)); - V<Map> map = __ LoadRoot<RootIndex::kWasmContinuationObjectMap>(); + V<Map> map = __ RootConstant<RootIndex::kWasmContinuationObjectMap>(); __ InitializeField(uninitialized_cont, AccessBuilder::ForMap(compiler::kNoWriteBarrier), map); compiler::FieldAccess access = { @@ -4205,10 +4221,11 @@ class TurboshaftGraphBuildingInterface const Value& cont_ref, const ContIndexImmediate& imm) { V<WordPtr> stack = CheckContAndGetStack(cont_ref, imm); - V<WordPtr> root = __ LoadRootRegister(); - V<WordPtr> active_stack = __ Load(root, LoadOp::Kind::RawAligned(), - MemoryRepresentation::UintPtr(), - IsolateData::active_stack_offset()); + V<WordPtr> active_stack_address = + __ IsolateField(IsolateFieldId::kActiveStack); + V<WordPtr> active_stack = + __ Load(active_stack_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::UintPtr()); V<WordPtr> wasm_code = __ RelocatableWasmCodePointer(); #if V8_ENABLE_SANDBOX_HARDWARE_SUPPORT // We don't have write access to the stack metadata from generated code, so @@ -4319,7 +4336,6 @@ class TurboshaftGraphBuildingInterface AnnotateResultIfReference(loaded, tag_params[index].type); }); - instance_cache_.ReloadCachedMemory(); cont_val->op = __ AnnotateWasmType(cont, cont_val->type); DCHECK_EQ(kOnSuspend, handler.kind); BrOrRet(decoder, handler.maybe_depth.br.depth); @@ -4381,10 +4397,11 @@ class TurboshaftGraphBuildingInterface void Switch(FullDecoder* decoder, const TagIndexImmediate& tag_imm, const ContIndexImmediate& con_imm, const Value& cont_ref, const Value args[], Value returns[]) { - V<WordPtr> root = __ LoadRootRegister(); + V<WordPtr> is_on_central_stack_flag_address = + __ IsolateField(IsolateFieldId::kIsOnCentralStackFlag); V<Word32> is_on_central_stack = - __ Load(root, LoadOp::Kind::RawAligned(), MemoryRepresentation::Uint8(), - IsolateData::is_on_central_stack_flag_offset()); + __ Load(is_on_central_stack_flag_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::Uint8()); V<Context> native_context = instance_cache_.native_context(); __ TrapIf(is_on_central_stack, TrapId::kTrapSuspend); @@ -4422,7 +4439,7 @@ class TurboshaftGraphBuildingInterface __ LoadTrustedFixedArrayElement(instance_tags, tag_imm.index)); const ContType* return_cont_type = - decoder->module_->cont_type(sig->parameters().last().ref_index()); + decoder->module_->cont_type(sig->parameters().back().ref_index()); const FunctionSig* return_sig = decoder->module_->signature(return_cont_type->contfun_typeindex()); @@ -4443,7 +4460,6 @@ class TurboshaftGraphBuildingInterface // pointer is not freed prematurely. __ Retain(V<Object>::Cast(cont_ref.op)); - instance_cache_.ReloadCachedMemory(); UnpackResumeReturns(return_sig->parameters(), returns, result_buffer); } @@ -4455,7 +4471,6 @@ class TurboshaftGraphBuildingInterface void EndEffectHandlers(FullDecoder* decoder) { current_resume_handlers_ = {}; __ Bind(resume_return_block_); - instance_cache_.ReloadCachedMemory(); } MemoryRepresentation MemoryRepresentationFor(ValueType type) { @@ -4467,7 +4482,7 @@ class TurboshaftGraphBuildingInterface uninitialized_cont = __ template Allocate<WasmContinuationObject>( __ WordPtrConstant(WasmContinuationObject::kSize), AllocationType::kYoung, AllocationAlignment::kTaggedAligned); - V<Map> map = __ LoadRoot<RootIndex::kWasmContinuationObjectMap>(); + V<Map> map = __ RootConstant<RootIndex::kWasmContinuationObjectMap>(); __ InitializeField(uninitialized_cont, AccessBuilder::ForMap(compiler::kNoWriteBarrier), map); // The {stack_obj_} field is initialized properly in the @@ -4476,16 +4491,17 @@ class TurboshaftGraphBuildingInterface AccessBuilder::ForJSObjectOffset( offsetof(WasmContinuationObject, stack_obj_), compiler::kNoWriteBarrier), - __ LoadRoot<RootIndex::kUndefinedValue>()); + __ RootConstant(RootIndex::kUndefinedValue)); return __ FinishInitialization(std::move(uninitialized_cont)); } void Suspend(FullDecoder* decoder, const TagIndexImmediate& imm, const Value args[], Value returns[]) { - V<WordPtr> root = __ LoadRootRegister(); + V<WordPtr> is_on_central_stack_flag_address = + __ IsolateField(IsolateFieldId::kIsOnCentralStackFlag); V<Word32> is_on_central_stack = - __ Load(root, LoadOp::Kind::RawAligned(), MemoryRepresentation::Uint8(), - IsolateData::is_on_central_stack_flag_offset()); + __ Load(is_on_central_stack_flag_address, LoadOp::Kind::RawAligned(), + MemoryRepresentation::Uint8()); V<Context> native_context = instance_cache_.native_context(); __ TrapIf(is_on_central_stack, TrapId::kTrapSuspend); @@ -4524,7 +4540,6 @@ class TurboshaftGraphBuildingInterface {wanted_tag, cont, arg_buffer, __ RelocatableWasmCanonicalSignatureId(csig_index.index)}, CheckForException::kCatchInThisFrame); - instance_cache_.ReloadCachedMemory(); // Unpack tag returns. IterateWasmFXArgBuffer(sig->returns(), [&](size_t index, int offset) { @@ -5291,8 +5306,8 @@ class TurboshaftGraphBuildingInterface V<FixedArray> elem_segments = LOAD_IMMUTABLE_INSTANCE_FIELD( instance_cache_.trusted_instance_data(), ElementSegments, MemoryRepresentation::TaggedPointer()); - __ StoreFixedArrayElement(elem_segments, imm.index, - __ LoadRoot<RootIndex::kEmptyFixedArray>(), + V<FixedArray> empty_array = __ RootConstant<RootIndex::kEmptyFixedArray>(); + __ StoreFixedArrayElement(elem_segments, imm.index, empty_array, compiler::kFullWriteBarrier); } @@ -5513,9 +5528,8 @@ class TurboshaftGraphBuildingInterface const FieldImmediate& imm, const Value& waitqueue, const Value& expected_value, const Value& timeout_ns, Value* result) { - V<Word32> offset = __ Word32Constant( - WasmStruct::kHeaderSize + - imm.struct_imm.struct_type->field_offset(imm.field_imm.index)); + V<Word32> offset = __ Word32Constant(WasmStruct::FieldOffset( + imm.struct_imm.struct_type, imm.field_imm.index)); ManagedObjectWait(decoder, struct_obj, offset, waitqueue, expected_value, timeout_ns, result); } @@ -5528,7 +5542,7 @@ class TurboshaftGraphBuildingInterface __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); ValueKind kind = expected_value.type.kind(); V<Word32> offset = __ Word32Add( - __ Word32Constant(WasmArray::kHeaderSize), + __ Word32Constant(WasmArray::HeaderSize(array_obj.type.is_shared())), __ Word32ShiftLeft(index.get<Word32>(), value_kind_size_log2(kind))); ManagedObjectWait(decoder, array_obj, offset, waitqueue, expected_value, timeout_ns, result); @@ -5584,7 +5598,7 @@ class TurboshaftGraphBuildingInterface auto array_value = array_obj.get<WasmArrayNullable>(); __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); result->op = __ ArrayGet(array_value, index.get<Word32>(), imm.array_type, - is_signed, {}); + is_signed, {}, array_obj.type.is_shared()); } void ArrayAtomicGet(FullDecoder* decoder, const Value& array_obj, @@ -5593,8 +5607,9 @@ class TurboshaftGraphBuildingInterface Value* result) { auto array_value = array_obj.get<WasmArrayNullable>(); __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); - result->op = __ ArrayGet(array_value, index.get<Word32>(), imm.array_type, - is_signed, memory_order); + result->op = + __ ArrayGet(array_value, index.get<Word32>(), imm.array_type, is_signed, + memory_order, array_obj.type.is_shared()); } void ArraySet(FullDecoder* decoder, const Value& array_obj, @@ -5603,7 +5618,7 @@ class TurboshaftGraphBuildingInterface auto array_value = array_obj.get<WasmArrayNullable>(); __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); __ ArraySet(array_value, index.get<Word32>(), value.op, - imm.array_type->element_type(), {}, + imm.array_type->element_type(), imm.array_type->is_shared(), {}, ArrayIndexImmediateToWriteBarrier(imm), ArraySetOp::Kind::kAssign); } @@ -5614,8 +5629,8 @@ class TurboshaftGraphBuildingInterface auto array_value = array_obj.get<WasmArrayNullable>(); __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); __ ArraySet(array_value, index.get<Word32>(), value.op, - imm.array_type->element_type(), memory_order, - ArrayIndexImmediateToWriteBarrier(imm), + imm.array_type->element_type(), imm.array_type->is_shared(), + memory_order, ArrayIndexImmediateToWriteBarrier(imm), ArraySetOp::Kind::kAssign); } @@ -5629,8 +5644,9 @@ class TurboshaftGraphBuildingInterface // unshared objects don't have the required alignment for 64 bit accesses. auto array_value = array_obj.get<WasmArrayNullable>(); __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); - V<Any> old_value = __ ArrayGet(array_value, index.get<Word32>(), - imm.array_type, true, {}); + V<Any> old_value = + __ ArrayGet(array_value, index.get<Word32>(), imm.array_type, true, + {}, array_obj.type.is_shared()); result->op = old_value; V<Word64> new_value; V<Word64> old = V<Word64>::Cast(old_value); @@ -5658,7 +5674,7 @@ class TurboshaftGraphBuildingInterface } DCHECK(new_value.valid() || __ generating_unreachable_operations()); __ ArraySet(array_value, index.get<Word32>(), new_value, - imm.array_type->element_type(), {}, + imm.array_type->element_type(), SharedFlag{false}, {}, ArrayIndexImmediateToWriteBarrier(imm), ArraySetOp::Kind::kAssign); return; @@ -5685,9 +5701,9 @@ class TurboshaftGraphBuildingInterface })(opcode); auto array_value = array_obj.get<WasmArrayNullable>(); __ WasmBoundsCheckArray(array_value, index.get<Word32>(), array_obj.type); - result->op = __ ArrayAtomicRMW(array_value, index.get<Word32>(), value.op, - OpIndex::Invalid(), op, - imm.array_type->element_type(), order); + result->op = __ ArrayAtomicRMW( + array_value, index.get<Word32>(), value.op, OpIndex::Invalid(), op, + imm.array_type->element_type(), imm.array_type->is_shared(), order); } void ArrayAtomicCompareExchange(FullDecoder* decoder, WasmOpcode opcode, @@ -5704,12 +5720,13 @@ class TurboshaftGraphBuildingInterface imm.array_type->element_type() == kWasmI64) { // On some architectures atomic operations require aligned accesses while // unshared objects don't have the required alignment for 64 bit accesses. - V<Word64> old_value = V<Word64>::Cast(__ ArrayGet( - array_value, index.get<Word32>(), imm.array_type, true, {})); + V<Word64> old_value = V<Word64>::Cast( + __ ArrayGet(array_value, index.get<Word32>(), imm.array_type, true, + {}, SharedFlag{false})); result->op = old_value; IF (__ Word64Equal(old_value, expected_value.get<Word64>())) { __ ArraySet(array_value, index.get<Word32>(), new_value.get<Word64>(), - imm.array_type->element_type(), {}, + imm.array_type->element_type(), SharedFlag{false}, {}, ArrayIndexImmediateToWriteBarrier(imm), ArraySetOp::Kind::kAssign); } @@ -5719,14 +5736,15 @@ class TurboshaftGraphBuildingInterface result->op = __ ArrayAtomicRMW( array_value, index.get<Word32>(), new_value.op, expected_value.op, compiler::turboshaft::ArrayAtomicRMWOp::BinOp::kCompareExchange, - imm.array_type->element_type(), order); + imm.array_type->element_type(), imm.array_type->is_shared(), order); } void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) { result->op = __ ArrayLength(array_obj.get<WasmArrayNullable>(), array_obj.type.is_nullable() ? compiler::kWithNullCheck - : compiler::kWithoutNullCheck); + : compiler::kWithoutNullCheck, + array_obj.type.is_shared()); } void ArrayCopy(FullDecoder* decoder, const Value& dst, const Value& dst_index, @@ -5737,11 +5755,13 @@ class TurboshaftGraphBuildingInterface BoundsCheckArrayWithLength( dst_array, dst_index.get<Word32>(), length.get<Word32>(), dst.type.is_nullable() ? compiler::kWithNullCheck - : compiler::kWithoutNullCheck); + : compiler::kWithoutNullCheck, + dst.type.is_shared()); BoundsCheckArrayWithLength( src_array, src_index.get<Word32>(), length.get<Word32>(), src.type.is_nullable() ? compiler::kWithNullCheck - : compiler::kWithoutNullCheck); + : compiler::kWithoutNullCheck, + src.type.is_shared()); ValueType element_type = src_imm.array_type->element_type(); @@ -5796,9 +5816,11 @@ class TurboshaftGraphBuildingInterface ScopedVar<Word32> dst_index_loop(this, dst_end_index); WHILE(__ Word32Constant(1)) { - V<Any> value = __ ArrayGet(src_array, src_index_loop, - src_imm.array_type, true, {}); - __ ArraySet(dst_array, dst_index_loop, value, element_type, {}, + V<Any> value = + __ ArrayGet(src_array, src_index_loop, src_imm.array_type, true, + {}, src.type.is_shared()); + __ ArraySet(dst_array, dst_index_loop, value, element_type, + dst.type.is_shared(), {}, ArrayIndexImmediateToWriteBarrier(src_imm), ArraySetOp::Kind::kAssign); @@ -5813,9 +5835,11 @@ class TurboshaftGraphBuildingInterface ScopedVar<Word32> dst_index_loop(this, dst_index.get<Word32>()); WHILE(__ Word32Constant(1)) { - V<Any> value = __ ArrayGet(src_array, src_index_loop, - src_imm.array_type, true, {}); - __ ArraySet(dst_array, dst_index_loop, value, element_type, {}, + V<Any> value = + __ ArrayGet(src_array, src_index_loop, src_imm.array_type, true, + {}, src.type.is_shared()); + __ ArraySet(dst_array, dst_index_loop, value, element_type, + dst.type.is_shared(), {}, ArrayIndexImmediateToWriteBarrier(src_imm), ArraySetOp::Kind::kAssign); @@ -5836,7 +5860,8 @@ class TurboshaftGraphBuildingInterface V<WasmArray> array_not_null = BoundsCheckArrayWithLength( array_value, index.get<Word32>(), length.get<Word32>(), array.type.is_nullable() ? compiler::kWithNullCheck - : compiler::kWithoutNullCheck); + : compiler::kWithoutNullCheck, + array.type.is_shared()); ArrayFillImpl(array_not_null, index.get<Word32>(), value.op, length.get<Word32>(), imm.array_type, ArrayIndexImmediateToWriteBarrier(imm), @@ -5850,18 +5875,18 @@ class TurboshaftGraphBuildingInterface wasm::ValueType element_type = type->element_type(); int element_count = length_imm.index; // Initialize the array header. - SharedFlag shared = decoder->module_->type(array_imm.index).is_shared; + SharedFlag shared = type->is_shared(); V<Map> rtt = __ RttCanon(instance_cache_.managed_object_maps(), array_imm.index); - V<WasmArray> array = __ WasmAllocateArray(rtt, element_count, type, shared); + V<WasmArray> array = __ WasmAllocateArray(rtt, element_count, type); WriteBarrierKind write_barrier = (shared || v8_flags.single_generation) && element_type.is_ref() ? kFullWriteBarrier : kNoWriteBarrier; // Initialize all elements. for (int i = 0; i < element_count; i++) { - __ ArraySet(array, __ Word32Constant(i), elements[i].op, element_type, {}, - write_barrier, ArraySetOp::Kind::kInitialize); + __ ArraySet(array, __ Word32Constant(i), elements[i].op, element_type, + shared, {}, write_barrier, ArraySetOp::Kind::kInitialize); } if (shared) __ MemoryBarrier(AtomicMemoryOrder::kAcqRel); result->op = array; @@ -6685,26 +6710,13 @@ class TurboshaftGraphBuildingInterface } private: - // The InstanceCache caches commonly used fields of the + // The InstanceCache caches commonly used immutable fields of the // WasmTrustedInstanceData. - // We can extend the set of cached fields as needed. - // This caching serves two purposes: - // (1) It makes sure that the respective fields are loaded early on, as - // opposed to within conditional branches, so the values are easily - // reusable. - // (2) It makes sure that the loaded values are actually reused. - // It achieves these effects more reliably and more cheaply than general- - // purpose optimizations could (loop peeling isn't always used; load - // elimination struggles with arbitrary side effects of indexed stores; - // we don't currently have a generic mechanism for hoisting loads out of - // conditional branches). class InstanceCache { public: - explicit InstanceCache(Assembler& assembler) - : mem_start_(assembler), mem_size_(assembler), asm_(assembler) {} + explicit InstanceCache(Assembler& assembler) : asm_(assembler) {} - void Initialize(V<WasmTrustedInstanceData> trusted_instance_data, - const WasmModule* mod) { + void Initialize(V<WasmTrustedInstanceData> trusted_instance_data) { DCHECK(!trusted_data_.valid()); // Only call {Initialize()} once. trusted_data_ = trusted_instance_data; managed_object_maps_ = @@ -6715,75 +6727,13 @@ class TurboshaftGraphBuildingInterface __ Load(trusted_instance_data, LoadOp::Kind::TaggedBase().Immutable(), MemoryRepresentation::TaggedPointer(), WasmTrustedInstanceData::kNativeContextOffset); - - if (!mod->memories.empty()) { -#if DEBUG - has_memory_ = true; -#endif - const WasmMemory& mem = mod->memories[0]; - memory_can_grow_ = mem.can_grow(); - memory_can_move_ = mem.can_move(); - memory_is_shared_ = mem.is_shared.value(); - memory_size_cached_ = !mem.is_shared && !memory_can_grow_; - if (memory_size_cached_) { - mem_size_ = LoadMemSize(); - } - mem_start_ = LoadMemStart(); - } - } - - // TODO(14108): Port the dynamic "cached_memory_index" infrastructure - // from Turbofan. - void ReloadCachedMemory() { - if (memory_can_move_) mem_start_ = LoadMemStart(); - if (memory_can_grow_ && memory_size_cached_) mem_size_ = LoadMemSize(); } V<WasmTrustedInstanceData> trusted_instance_data() { return trusted_data_; } V<FixedArray> managed_object_maps() { return managed_object_maps_; } V<NativeContext> native_context() { return native_context_; } - V<WordPtr> memory0_start() { - DCHECK(has_memory_); - return mem_start_; - } - V<WordPtr> memory0_size() { - DCHECK(has_memory_); - if (!memory_size_cached_) return LoadMemSize(); - return mem_size_; - } - void set_memory0_start(V<WordPtr> start) { mem_start_ = start; } - void set_memory0_size(V<WordPtr> size) { mem_size_ = size; } - bool memory_can_grow() const { return memory_can_grow_; } - bool memory_can_move() const { return memory_can_move_; } - bool memory_size_cached() const { return memory_size_cached_; } private: - static constexpr uint8_t kUnused = ~uint8_t{0}; - - V<WordPtr> LoadMemStart() { - DCHECK(has_memory_); - // In contrast to memory size loads, we can mark memory start loads as - // eliminable: shared memories never move, and non-shared memories can't - // have their start modified by other threads. - LoadOp::Kind kind = LoadOp::Kind::TaggedBase(); - if (!memory_can_move_) kind = kind.Immutable(); - return __ Load(trusted_data_, kind, MemoryRepresentation::UintPtr(), - WasmTrustedInstanceData::kMemory0StartOffset); - } - - V<WordPtr> LoadMemSize() { - DCHECK(has_memory_); - LoadOp::Kind kind = LoadOp::Kind::TaggedBase(); - if (memory_is_shared_ && memory_can_grow_) { - // Memory size loads should not be load-eliminated as the memory size - // can be modified by another thread. - kind = kind.NotLoadEliminable(); - } - if (!memory_can_grow_) kind = kind.Immutable(); - return __ Load(trusted_data_, kind, MemoryRepresentation::UintPtr(), - WasmTrustedInstanceData::kMemory0SizeOffset); - } - // For compatibility with `__` macro. Assembler& Asm() { return asm_; } @@ -6792,19 +6742,8 @@ class TurboshaftGraphBuildingInterface V<FixedArray> managed_object_maps_; V<NativeContext> native_context_; - // Cached mutable fields: - ScopedVar<WordPtr> mem_start_; - ScopedVar<WordPtr> mem_size_; - // Other fields for internal usage. Assembler& asm_; - bool memory_is_shared_{false}; - bool memory_can_grow_{false}; - bool memory_can_move_{false}; - bool memory_size_cached_{false}; -#if DEBUG - bool has_memory_{false}; -#endif }; private: @@ -7154,11 +7093,26 @@ class TurboshaftGraphBuildingInterface wasm_local_count - callee_sig->return_count(); local_count += args != nullptr ? callee_sig->parameter_count() : 0; Zone* zone = Asm().data()->compilation_zone(); + uint32_t liftoff_frame_size = GetLiftoffFrameSize(decoder); + if (liftoff_frame_size == + FunctionTypeFeedback::kUninitializedLiftoffFrameSize) { + if (v8_flags.trace_wasm_inlining) { + PrintF( + "[function %d%s: Disabling deoptimizations for speculative " + "inlining as Liftoff failed to compile (cannot compute its frame " + "size)]\n", + func_index_, mode_ == kRegular ? "" : " (inlined)"); + } + // Disable deopts for the rest of the function, as liftoff compilation + // will fail again. + disable_deopts(); + return OpIndex::Invalid(); + } auto* function_info = zone->New<compiler::FrameStateFunctionInfo>( compiler::FrameStateType::kLiftoffFunction, static_cast<uint16_t>(param_count), 0, static_cast<int>(local_count), IndirectHandle<SharedFunctionInfo>(), kNullMaybeHandle, - GetLiftoffFrameSize(decoder), func_index_); + liftoff_frame_size, func_index_); auto* frame_state_info = zone->New<compiler::FrameStateInfo>( BytecodeOffset(decoder->pc_offset()), compiler::OutputFrameStateCombine::Ignore(), function_info); @@ -7224,10 +7178,46 @@ class TurboshaftGraphBuildingInterface return liftoff_frame_size_; } const TypeFeedbackStorage& feedback = decoder->module_->type_feedback; - base::MutexGuard mutex_guard(&feedback.mutex); - auto function_feedback = feedback.feedback_for_function.find(func_index_); - CHECK_NE(function_feedback, feedback.feedback_for_function.end()); - liftoff_frame_size_ = function_feedback->second.liftoff_frame_size; + std::optional<base::MutexGuard> mutex_guard(&feedback.mutex); + auto function_feedback_iter = + feedback.feedback_for_function.find(func_index_); + if (function_feedback_iter == feedback.feedback_for_function.end() || + function_feedback_iter->second.liftoff_frame_size == + FunctionTypeFeedback::kUninitializedLiftoffFrameSize) { + // This can happen if this function has not been compiled with Liftoff + // yet. I.e. we are compiling based on compilation hints. In this case we + // have to generate function_feedback now by compiling with Liftoff, to + // compute the Liftoff frame size. + // We would like to have some tracing output here, but there can be a + // Liftoff compilation in another thread racing this Turboshaft + // compilation. This would affect whether the output would be printed. + // TODO(manoskouk): Improve this. + // if (v8_flags.trace_wasm_inlining) { + // PrintF("[function %d%s: Will invoke liftoff compilation]\n", + // func_index_, mode_ == kRegular ? "" : " (inlined)"); + // } + // Reset the mutex_guard so liftoff can update the module's function + // feedback. + mutex_guard.reset(); + LiftoffOptions options{.func_index = func_index_, + .for_debugging = v8_flags.wasm_code_coverage + ? kForDebugging + : kNotForDebugging, + .counter_updates = counter_updates_, + .detected_features = decoder->detected_}; + WasmCompilationResult liftoff_result = ExecuteLiftoffCompilation( + env_, + FunctionBody(decoder->sig_, decoder->buffer_offset(), + decoder->start(), decoder->end()), + options); + if (liftoff_result.failed()) { + return FunctionTypeFeedback::kUninitializedLiftoffFrameSize; + } + mutex_guard.emplace(&feedback.mutex); + function_feedback_iter = feedback.feedback_for_function.find(func_index_); + } + CHECK_NE(function_feedback_iter, feedback.feedback_for_function.end()); + liftoff_frame_size_ = function_feedback_iter->second.liftoff_frame_size; // The liftoff frame size is strictly required. If it is not properly set, // calling the function embedding the deopt node will always fail on the // stack check. @@ -8277,19 +8267,22 @@ class TurboshaftGraphBuildingInterface } V<WordPtr> MemStart(uint32_t index) { + const WasmMemory& mem = env_->module->memories[index]; + LoadOp::Kind kind = LoadOp::Kind::TaggedBase(); + if (!mem.can_move()) kind = kind.Immutable(); + V<WasmTrustedInstanceData> trusted_data = + instance_cache_.trusted_instance_data(); + if (index == 0) { - // TODO(14108): Port TF's dynamic "cached_memory_index" infrastructure. - return instance_cache_.memory0_start(); - } else { - // TODO(14616): Fix sharedness. - V<TrustedFixedAddressArray> instance_memories = - LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( - instance_cache_.trusted_instance_data(), MemoryBasesAndSizes, - TrustedFixedAddressArray); - return __ Load(instance_memories, LoadOp::Kind::TaggedBase(), - MemoryRepresentation::UintPtr(), - TrustedFixedAddressArray::OffsetOfElementAt(2 * index)); + return __ Load(trusted_data, kind, MemoryRepresentation::UintPtr(), + WasmTrustedInstanceData::kMemory0StartOffset); } + + V<TrustedFixedAddressArray> instance_memories = + LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( + trusted_data, MemoryBasesAndSizes, TrustedFixedAddressArray); + return __ Load(instance_memories, kind, MemoryRepresentation::UintPtr(), + TrustedFixedAddressArray::OffsetOfElementAt(2 * index)); } V<WordPtr> MemBuffer(uint32_t mem_index, uintptr_t offset) { @@ -8298,21 +8291,53 @@ class TurboshaftGraphBuildingInterface return __ WordPtrAdd(mem_start, offset); } + // Returns the address holding the atomic byte length for the shared memory at + // {index} (i.e. BackingStore::byte_length_). + V<WordPtr> MemSizeAddress(uint32_t index) { + DCHECK(env_->module->memories[index].is_shared); + if (index == 0) { + return __ Load(instance_cache_.trusted_instance_data(), + LoadOp::Kind::TaggedBase().Immutable(), + MemoryRepresentation::UintPtr(), + WasmTrustedInstanceData::kMemory0SizeOrAddressOffset); + } + V<TrustedFixedAddressArray> instance_memories = + LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( + instance_cache_.trusted_instance_data(), MemoryBasesAndSizes, + TrustedFixedAddressArray); + return __ Load(instance_memories, LoadOp::Kind::TaggedBase().Immutable(), + MemoryRepresentation::UintPtr(), + TrustedFixedAddressArray::OffsetOfElementAt(2 * index + 1)); + } + V<WordPtr> MemSize(uint32_t index) { + const WasmMemory& mem = env_->module->memories[index]; + if (mem.is_shared) { + V<WordPtr> size_address = MemSizeAddress(index); + // A relaxed (non-atomic) aligned word load is sufficient for bounds + // checks; `memory.size` uses an explicit atomic load. + LoadOp::Kind deref_kind = + mem.can_grow() ? LoadOp::Kind::RawAligned().NotLoadEliminable() + : LoadOp::Kind::RawAligned().Immutable(); + return __ Load(size_address, deref_kind, MemoryRepresentation::UintPtr(), + 0); + } + + LoadOp::Kind kind = LoadOp::Kind::TaggedBase(); + if (!mem.can_grow()) kind = kind.Immutable(); + V<WasmTrustedInstanceData> trusted_data = + instance_cache_.trusted_instance_data(); + if (index == 0) { - // TODO(14108): Port TF's dynamic "cached_memory_index" infrastructure. - return instance_cache_.memory0_size(); - } else { - // TODO(14616): Fix sharedness. - V<TrustedByteArray> instance_memories = - LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( - instance_cache_.trusted_instance_data(), MemoryBasesAndSizes, - TrustedByteArray); - return __ Load( - instance_memories, LoadOp::Kind::TaggedBase().NotLoadEliminable(), - MemoryRepresentation::UintPtr(), - TrustedFixedAddressArray::OffsetOfElementAt(2 * index + 1)); + return __ Load(trusted_data, kind, MemoryRepresentation::UintPtr(), + WasmTrustedInstanceData::kMemory0SizeOrAddressOffset); } + + V<TrustedFixedAddressArray> instance_memories = + LOAD_IMMUTABLE_PROTECTED_INSTANCE_FIELD( + trusted_data, MemoryBasesAndSizes, TrustedFixedAddressArray); + return __ Load(instance_memories, kind, MemoryRepresentation::UintPtr(), + TrustedFixedAddressArray::OffsetOfElementAt(2 * index + 1)); } LoadOp::Kind GetMemoryAccessKind( @@ -8388,24 +8413,9 @@ class TurboshaftGraphBuildingInterface __ NoContextConstant()); } - void StackCheck(WasmStackCheckOp::Kind kind, FullDecoder* decoder) { + void StackCheck(WasmStackCheckOp::Kind kind) { if (V8_UNLIKELY(!v8_flags.wasm_stack_checks)) return; - if (kind == WasmStackCheckOp::Kind::kLoop && - !decoder->module_->memories.empty()) { - // Wasm memories cannot move at loop stack checks because we disallow - // their growth when `Isolate::is_executing_api_interrupt()`. - // Also, memory_size is never cached if the memory is growable, making - // `can_grow_and_cached` always false. Therefore, we don't need to pipe - // memory start/size through WasmStackCheck anymore. - bool can_grow_and_cached = instance_cache_.memory_can_grow() && - instance_cache_.memory_size_cached(); - CHECK(!can_grow_and_cached); - V<WasmTrustedInstanceData> instance = - instance_cache_.trusted_instance_data(); - __ WasmStackCheck(kind, instance); - } else { - __ WasmStackCheck(kind); - } + __ WasmStackCheck(kind); } private: @@ -8587,7 +8597,7 @@ class TurboshaftGraphBuildingInterface V<WasmInternalFunction> internal_function = V<WasmInternalFunction>::Cast(__ LoadTrustedPointer( - func_ref, load_kind, kWasmInternalFunctionIndirectPointerTag, + func_ref, load_kind, kWasmInternalFunctionTrustedPointerTag, offsetof(WasmFuncRef, trusted_internal_))); return BuildFunctionTargetAndImplicitArg(internal_function); } @@ -8628,8 +8638,6 @@ class TurboshaftGraphBuildingInterface __ Projection(call, i, RepresentationFor(type)), type); } } - // Calls might mutate cached instance fields. - instance_cache_.ReloadCachedMemory(); } private: @@ -8791,14 +8799,9 @@ class TurboshaftGraphBuildingInterface __ Bind(exception_block); OpIndex exception = __ CatchBlockBegin(); if (handled_in_this_frame) { - // The exceptional operation could have modified memory size; we need - // to reload the memory context into the exceptional control path. - instance_cache_.ReloadCachedMemory(); SetupControlFlowEdge(decoder, catch_block, 0, exception); } else if (mode_ == kInlinedWithCatch) { if (exception.valid()) return_phis_->AddIncomingException(exception); - // Reloading the InstanceCache will happen when {return_exception_phis_} - // are retrieved. } __ Goto(catch_block); } @@ -8970,11 +8973,11 @@ class TurboshaftGraphBuildingInterface void UnpackWasmException(FullDecoder* decoder, V<Object> exception, base::Vector<Value> values) { + V<Symbol> values_symbol = + __ RootConstant<RootIndex::kwasm_exception_values_symbol>(); V<FixedArray> exception_values_array = V<FixedArray>::Cast( CallBuiltinThroughJumptable<BuiltinCallDescriptor::WasmGetOwnProperty>( - decoder, - {exception, - __ LoadRoot<RootIndex::kwasm_exception_values_symbol>()})); + decoder, {exception, values_symbol})); int index = 0; for (Value& value : values) { @@ -9049,11 +9052,12 @@ class TurboshaftGraphBuildingInterface V<WasmArray> BoundsCheckArrayWithLength(V<WasmArrayNullable> array, V<Word32> index, V<Word32> length, - compiler::CheckForNull null_check) { + compiler::CheckForNull null_check, + SharedFlag shared_base) { if (V8_UNLIKELY(v8_flags.wasm_skip_bounds_checks)) { return V<WasmArray>::Cast(array); } - V<Word32> array_length = __ ArrayLength(array, null_check); + V<Word32> array_length = __ ArrayLength(array, null_check, shared_base); V<Word32> range_end = __ Word32Add(index, length); V<Word32> range_valid = __ Word32BitwiseAnd( // OOB if (index + length > array.len). @@ -9104,9 +9108,9 @@ class TurboshaftGraphBuildingInterface V<Any> initial_value, WriteBarrierKind write_barrier) { // Initialize the array header. - SharedFlag shared = decoder->module_->type(index).is_shared; + SharedFlag shared = array_type->is_shared(); V<Map> rtt = __ RttCanon(instance_cache_.managed_object_maps(), index); - V<WasmArray> array = __ WasmAllocateArray(rtt, length, array_type, shared); + V<WasmArray> array = __ WasmAllocateArray(rtt, length, array_type); // Initialize the elements. ArrayFillImpl(array, __ Word32Constant(0), initial_value, length, array_type, write_barrier, ArraySetOp::Kind::kInitialize); @@ -9115,6 +9119,16 @@ class TurboshaftGraphBuildingInterface } V<Map> GetRttFromDescriptor(const Value& descriptor) { + if (v8_flags.wasm_merged_descriptors) { + V<WasmCustomMap> descriptor_struct = descriptor.get<WasmCustomMap>(); + // The descriptor is the RTT, but we have to check if it's null, and + // there's no load that could trigger an implicit check. + if (descriptor.type.is_nullable()) { + __ TrapIf(__ IsNull(descriptor_struct, wasm::kWasmAnyRef), + TrapId::kTrapNullDereference); + } + return descriptor_struct; + } V<WasmStructNullable> descriptor_struct = descriptor.get<WasmStructNullable>(); // TODO(jkummerow): Refactor this to share the logic with @@ -9138,10 +9152,11 @@ class TurboshaftGraphBuildingInterface WasmStruct::kHeaderSize); } - V<WasmStruct> StructNewImpl(FullDecoder* decoder, - const StructIndexImmediate& imm, - const Value& descriptor, OpIndex args[], - bool has_nondefault_args) { + V<WasmStructNonNullable> StructNewImpl(FullDecoder* decoder, + const StructIndexImmediate& imm, + const Value& descriptor, + OpIndex args[], + bool has_nondefault_args) { if (__ generating_unreachable_operations()) return {}; const TypeDefinition& type = decoder->module_->type(imm.index); DCHECK_EQ(type.has_descriptor(), descriptor.op.valid()); @@ -9152,7 +9167,7 @@ class TurboshaftGraphBuildingInterface rtt = __ RttCanon(instance_cache_.managed_object_maps(), imm.index); } - V<WasmStruct> struct_value; + V<WasmStructNonNullable> struct_value; if (type.is_descriptor()) { bool pass_potential_prototype = has_nondefault_args && @@ -9230,8 +9245,8 @@ class TurboshaftGraphBuildingInterface ScopedVar<Word32> current_index(this, index); WHILE(__ Uint32LessThan(current_index, __ Word32Add(index, length))) { - __ ArraySet(array, current_index, value, type->element_type(), {}, - write_barrier, kind); + __ ArraySet(array, current_index, value, type->element_type(), + type->is_shared(), {}, write_barrier, kind); current_index = __ Word32Add(current_index, 1); } @@ -9349,6 +9364,24 @@ class TurboshaftGraphBuildingInterface return; } + // When the root function inlines a tail call, InlineWasmCall sets + // frame_state = parent_frame_state_ without calling CreateFrameState on the + // root function. Therefore we have to ensure here that the top-level + // function is compilable with Liftoff. Otherwise, the following sequence + // may happen: When the inlinee's deopt triggers at runtime, + // `Deoptimizer::DoComputeOutputFramesWasmImpl` sees + // `translated_state_.frames()[0].wasm_function_index() != + // compiled_optimized_wasm_code_->index()` and calls + // `CompileWithLiftoffAndGetDeoptInfo` on the root function to invalidate + // its optimized code, which fails Liftoff compilation and crashes in + // `native_module->AddCompiledCode(result)`. + if (deopts_enabled() && mode_ == kRegular && is_tail_call) { + if (GetLiftoffFrameSize(decoder) == + FunctionTypeFeedback::kUninitializedLiftoffFrameSize) { + disable_deopts(); + } + } + SmallZoneVector<OpIndex, 16> inlinee_args( inlinee.sig->parameter_count() + 1, decoder->zone_); inlinee_args[0] = instance_cache_.trusted_instance_data(); @@ -9437,7 +9470,8 @@ class TurboshaftGraphBuildingInterface inlining_positions_, func_index, wire_bytes_, validate_inlinees_, base::VectorOf(inlinee_args), callee_return_block, inlinee_return_phis, - callee_catch_block, is_tail_call, frame_state); + callee_catch_block, is_tail_call, frame_state, + counter_updates_); SourcePosition call_position = SourcePosition(decoder->position(), inlining_id_ == kNoInliningId ? SourcePosition::kNotInlined @@ -9488,16 +9522,11 @@ class TurboshaftGraphBuildingInterface Control* current_catch = decoder->control_at(decoder->control_depth_of_current_catch()); catch_block = current_catch->false_or_loop_or_catch_block; - // The exceptional operation could have modified memory size; we need - // to reload the memory context into the exceptional control path. - instance_cache_.ReloadCachedMemory(); SetupControlFlowEdge(decoder, catch_block, 0, exception); } else { DCHECK_EQ(mode_, kInlinedWithCatch); catch_block = return_catch_block_; if (exception.valid()) return_phis_->AddIncomingException(exception); - // Reloading the InstanceCache will happen when {return_exception_phis_} - // are retrieved. } __ Goto(catch_block); } @@ -9637,14 +9666,6 @@ class TurboshaftGraphBuildingInterface void disable_deopts() { deopts_enabled_ = false; } bool deopts_enabled() { if (!deopts_enabled_.has_value()) { - if (inlining_decisions_ && InliningTargetsProvidedByCustomSection()) { - // We have to disable deopts in this case. Deopts need function feedback - // for GetLiftoffFrameSize. - // TODO(manoskouk): Find a way to enable deopts in the presence of - // compilation hints. - deopts_enabled_ = false; - return false; - } deopts_enabled_ = v8_flags.wasm_deopt; if (v8_flags.wasm_deopt) { const wasm::TypeFeedbackStorage& feedback = env_->module->type_feedback; @@ -9742,6 +9763,8 @@ class TurboshaftGraphBuildingInterface // Manages code coverage instrumentation. std::unique_ptr<WasmCoverageInstrumentation<FullDecoder>> coverage_instrumentation_; + + DelayedCounterUpdates* counter_updates_; }; compiler::WriteBarrierKind ArrayIndexImmediateToWriteBarrier( @@ -9763,14 +9786,16 @@ V8_EXPORT_PRIVATE void BuildTSGraph( const WireBytesStorage* wire_bytes, Validation validate_callees, std::unique_ptr<AssumptionsJournal>* assumptions, ZoneVector<WasmInliningPosition>* inlining_positions, int func_index, - WasmFunctionCoverageData* coverage_data) { + WasmFunctionCoverageData* coverage_data, + DelayedCounterUpdates* counter_updates) { Zone zone(data->allocator(), ZONE_NAME); Assembler assembler(data, graph, graph, &zone); WasmFullDecoder<TurboshaftGraphBuildingInterface::ValidationTag, TurboshaftGraphBuildingInterface> decoder(&zone, env->module, env->enabled_features, detected, func_body, &zone, env, assembler, assumptions, inlining_positions, - func_index, wire_bytes, validate_callees, coverage_data); + func_index, wire_bytes, validate_callees, coverage_data, + counter_updates); decoder.Decode(); // The function was already validated, so graph building must always succeed. DCHECK(decoder.ok()); diff --git a/deps/v8/src/wasm/turboshaft-graph-interface.h b/deps/v8/src/wasm/turboshaft-graph-interface.h index b93e34b84d25..1adefb170287 100644 --- a/deps/v8/src/wasm/turboshaft-graph-interface.h +++ b/deps/v8/src/wasm/turboshaft-graph-interface.h @@ -47,7 +47,8 @@ V8_EXPORT_PRIVATE void BuildTSGraph( Validation validate_callees, std::unique_ptr<AssumptionsJournal>* assumptions, ZoneVector<WasmInliningPosition>* inlining_positions, int func_index, - WasmFunctionCoverageData* coverage_data); + WasmFunctionCoverageData* coverage_data, + DelayedCounterUpdates* counter_updates); // Base class for the decoder graph builder interface and for the wrapper // builder. diff --git a/deps/v8/src/wasm/wasm-builtin-list.h b/deps/v8/src/wasm/wasm-builtin-list.h index 57b337bc8ca3..82808d5de05d 100644 --- a/deps/v8/src/wasm/wasm-builtin-list.h +++ b/deps/v8/src/wasm/wasm-builtin-list.h @@ -23,7 +23,7 @@ namespace v8::internal::wasm { V(WasmTriggerTierUp) \ V(WasmLiftoffFrameSetup) \ V(WasmDebugBreak) \ - V(WasmDebugTrap) \ + V(WasmTrapHandlerThrowTrap) \ V(WasmInt32ToHeapNumber) \ V(WasmInt32ToSharedHeapNumber) \ V(WasmFloat64ToString) \ @@ -59,6 +59,7 @@ namespace v8::internal::wasm { V(WasmThrowRef) \ V(WasmRethrowExplicitContext) \ V(WasmHandleStackOverflow) \ + V(WasmReturnFromSegment) \ V(WasmTraceEnter) \ V(WasmTraceExit) \ V(WasmTraceMemory) \ @@ -157,6 +158,7 @@ namespace v8::internal::wasm { V(WasmStringHash) \ V(WasmAnyConvertExtern) \ V(WasmAnyConvertExternShared) \ + V(WasmExternConvertAny) \ V(WasmStringFromDataSegment) \ V(WasmStringAdd_NoMapCheck) \ V(WasmStringAdd_NoMapCheck_Shared) \ @@ -191,8 +193,7 @@ namespace v8::internal::wasm { V(WasmAllocateInSharedHeap) \ V(WasmJSStringEqual) \ V(WasmToJsWrapperInvalidSig) \ - V(WasmTrap) \ - V(WasmTrapHandlerThrowTrap) + V(WasmTrap) #define WASM_BUILTIN_LIST(V, VTRAP) \ WASM_BUILTINS_WITH_JUMP_TABLE_SLOT(V, VTRAP) \ diff --git a/deps/v8/src/wasm/wasm-code-coverage.h b/deps/v8/src/wasm/wasm-code-coverage.h index 84f5fdf377fb..df0395d56c9c 100644 --- a/deps/v8/src/wasm/wasm-code-coverage.h +++ b/deps/v8/src/wasm/wasm-code-coverage.h @@ -13,6 +13,7 @@ #include <stdint.h> #include "src/base/platform/mutex.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/wasm/wasm-opcodes.h" @@ -39,8 +40,8 @@ class WasmFunctionCoverageData { public: explicit WasmFunctionCoverageData( base::Vector<const WasmCodeRange> code_ranges) { - counts_ = base::OwnedVector<uint32_t>::New(code_ranges.size()); - code_ranges_ = base::OwnedCopyOf(code_ranges); + counts_ = base::UniqueArray<uint32_t>::New(code_ranges.size()); + code_ranges_ = base::UniqueCopyOf(code_ranges); } const base::Vector<const WasmCodeRange> code_ranges() const { @@ -52,15 +53,15 @@ class WasmFunctionCoverageData { } private: - base::OwnedVector<const WasmCodeRange> code_ranges_; - base::OwnedVector<uint32_t> counts_; + base::UniqueArray<const WasmCodeRange> code_ranges_; + base::UniqueArray<uint32_t> counts_; }; class WasmModuleCoverageData { public: explicit WasmModuleCoverageData(uint32_t declared_function_count) { function_data_ = - base::OwnedVector<std::unique_ptr<WasmFunctionCoverageData>>::New( + base::UniqueArray<std::unique_ptr<WasmFunctionCoverageData>>::New( declared_function_count); } @@ -93,7 +94,7 @@ class WasmModuleCoverageData { // There is a single WasmModuleCoverageData per NativeModule, that can be // accessed concurrently from multiple Isolates. mutable base::Mutex mutex_; - base::OwnedVector<std::unique_ptr<WasmFunctionCoverageData>> function_data_; + base::UniqueArray<std::unique_ptr<WasmFunctionCoverageData>> function_data_; }; template <typename FullDecoder> diff --git a/deps/v8/src/wasm/wasm-code-manager.cc b/deps/v8/src/wasm/wasm-code-manager.cc index f3578610df7e..36815750ecef 100644 --- a/deps/v8/src/wasm/wasm-code-manager.cc +++ b/deps/v8/src/wasm/wasm-code-manager.cc @@ -20,6 +20,7 @@ #include "src/base/sanitizer/tsan.h" #include "src/base/small-vector.h" #include "src/base/string-format.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/builtins/builtins-inl.h" #include "src/codegen/assembler-inl.h" @@ -302,10 +303,6 @@ void WasmCode::LogCode(Isolate* isolate, const char* source_url, std::string fn_name = DebugName(); WasmName name = base::VectorOf(fn_name); - if (native_module_) { - TryLoadSourceMap(isolate); - } - // Record source positions before adding code, otherwise when code is added, // there are no source positions to associate with the added code. if (!source_positions().empty()) { @@ -414,31 +411,6 @@ void WasmCode::Validate() const { #endif } -void WasmCode::TryLoadSourceMap(Isolate* isolate) const { - auto load_wasm_source_map = isolate->wasm_load_source_map_callback(); - if (!load_wasm_source_map) return; - - if (native_module_->GetWasmSourceMap()) return; - - const WasmModule* module = native_module_->module(); - const WasmDebugSymbols& symbol = - module->debug_symbols[WasmDebugSymbols::Type::SourceMap]; - if (symbol.type != WasmDebugSymbols::Type::SourceMap) return; - if (symbol.external_url.is_empty()) return; - - ModuleWireBytes wire_bytes(native_module_->wire_bytes()); - WasmName external_url = wire_bytes.GetNameOrNull(symbol.external_url); - std::string external_url_string(external_url.data(), external_url.size()); - HandleScope scope(isolate); - v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); - Local<v8::String> source_map_str = - load_wasm_source_map(v8_isolate, external_url_string.c_str()); - if (source_map_str.IsEmpty()) return; - - native_module_->SetWasmSourceMapIfUnset( - std::make_unique<WasmModuleSourceMap>(v8_isolate, source_map_str)); -} - void WasmCode::MaybePrint() const { // Determines whether flags want this code to be printed. bool function_index_matches = @@ -512,8 +484,8 @@ void WasmCode::Disassemble(const char* name, std::ostream& os, if (trapping_instructions_size_ > 0) { os << "Trapping instructions:\n pc offset\n"; for (auto& data : trapping_instructions()) { - os << std::setw(10) << std::hex << data.instr_offset << std::setw(10) - << "\n"; + os << std::setw(10) << std::hex << data.instr_offset << std::dec + << std::setw(10) << "\n"; } os << "\n"; } @@ -1098,13 +1070,39 @@ NativeModule::NativeModule(WasmEnabledFeatures enabled_features, } } -void NativeModule::LogWasmCodes(Isolate* isolate, Tagged<Script> script) { - DisallowGarbageCollection no_gc; +void NativeModule::TryLoadSourceMap(Isolate* isolate) { + auto load_wasm_source_map = isolate->wasm_load_source_map_callback(); + if (!load_wasm_source_map) return; + + if (GetWasmSourceMap()) return; + + const WasmDebugSymbols& symbol = + module_->debug_symbols[WasmDebugSymbols::Type::SourceMap]; + if (symbol.type != WasmDebugSymbols::Type::SourceMap) return; + if (symbol.external_url.is_empty()) return; + + ModuleWireBytes wire_bytes(this->wire_bytes()); + WasmName external_url = wire_bytes.GetNameOrNull(symbol.external_url); + std::string external_url_string(external_url.data(), external_url.size()); + HandleScope scope(isolate); + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); + Local<v8::String> source_map_str = + load_wasm_source_map(v8_isolate, external_url_string.c_str()); + if (source_map_str.IsEmpty()) return; + + SetWasmSourceMapIfUnset( + std::make_unique<WasmModuleSourceMap>(v8_isolate, source_map_str)); +} + +void NativeModule::LogWasmCodes(Isolate* isolate, DirectHandle<Script> script) { if (!WasmCode::ShouldBeLogged(isolate)) return; TRACE_EVENT("v8.wasm", "wasm.LogWasmCodes", "functions", module_->num_declared_functions); + TryLoadSourceMap(isolate); + + DisallowGarbageCollection no_gc; Tagged<Object> url_obj = script->name(); DCHECK(IsString(url_obj) || IsUndefined(url_obj)); std::unique_ptr<char[]> source_url = @@ -1204,30 +1202,30 @@ WasmCode* NativeModule::AddCodeForTesting(const WasmCompilationResult& result, // Flush the i-cache after relocation. FlushInstructionCache(dst_code_bytes.begin(), dst_code_bytes.size()); - std::unique_ptr<WasmCode> unique_code{new (reserved_code) WasmCode{ - this, - kAnonymousFuncIndex, - dst_code_bytes, - static_cast<int>(result.frame_slot_count), - static_cast<int>(result.ool_spill_count), - result.tagged_parameter_slots, - safepoint_table_offset, - handler_table_offset, - constant_pool_offset, - code_comments_offset, - jump_table_info_offset, - instr_size, - result.trapping_instructions_data.as_vector(), - reloc_info, - result.source_positions.as_vector(), - result.inlining_positions.as_vector(), - result.deopt_data.as_vector(), - GetCodeKind(result), - result.result_tier, - result.for_debugging, - signature_hash, - result.effect_handlers.as_vector(), - result.frame_has_feedback_slot}}; + std::unique_ptr<WasmCode> unique_code{ + new (reserved_code) WasmCode{this, + kAnonymousFuncIndex, + dst_code_bytes, + static_cast<int>(result.frame_slot_count), + static_cast<int>(result.ool_spill_count), + result.tagged_parameter_slots, + safepoint_table_offset, + handler_table_offset, + constant_pool_offset, + code_comments_offset, + jump_table_info_offset, + instr_size, + result.trapping_instructions_data.as_span(), + reloc_info, + result.source_positions.as_span(), + result.inlining_positions.as_span(), + result.deopt_data.as_span(), + GetCodeKind(result), + result.result_tier, + result.for_debugging, + signature_hash, + result.effect_handlers.as_span(), + result.frame_has_feedback_slot}}; unique_code->MaybePrint(); unique_code->Validate(); @@ -1423,7 +1421,8 @@ WasmCode* NativeModule::PublishCode(UnpublishedWasmCode unpublished_code) { "wasm.PublishCode"); base::RecursiveMutexGuard lock(&allocation_mutex_); return PublishCodeLocked(std::move(unpublished_code.code), - unpublished_code.assumptions.get()); + unpublished_code.assumptions.get(), + unpublished_code.for_deopt); } std::vector<WasmCode*> NativeModule::PublishCode( @@ -1436,7 +1435,8 @@ std::vector<WasmCode*> NativeModule::PublishCode( // The published code is put into the top-most surrounding {WasmCodeRefScope}. for (auto& unpublished_code : unpublished_codes) { WasmCode* code = PublishCodeLocked(std::move(unpublished_code.code), - unpublished_code.assumptions.get()); + unpublished_code.assumptions.get(), + unpublished_code.for_deopt); if (code == nullptr) { // There were invalid assumptions in the code. DCHECK_NOT_NULL(unpublished_code.assumptions); @@ -1478,7 +1478,8 @@ WasmCode::Kind GetCodeKind(const WasmCompilationResult& result) { } WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> owned_code, - AssumptionsJournal* assumptions) { + AssumptionsJournal* assumptions, + bool for_deopt) { allocation_mutex_.AssertHeld(); DCHECK_LT(owned_code->index(), num_functions()); @@ -1535,7 +1536,7 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> owned_code, kForDebugging > kNotForDebugging && kWithBreakpoints > kForDebugging, "for_debugging is ordered"); - if (should_update_code_table(code, prior_code)) { + if (should_update_code_table(code, prior_code, for_deopt)) { code_table_[slot_idx] = code; if (prior_code) { // Code in the code table is always live, so `AddRef` can be used instead @@ -1559,7 +1560,9 @@ WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> owned_code, } bool NativeModule::should_update_code_table(WasmCode* new_code, - WasmCode* prior_code) const { + WasmCode* prior_code, + bool for_deopt) const { + DCHECK_IMPLIES(for_deopt, v8_flags.wasm_deopt && new_code->is_liftoff()); if (new_code->for_debugging() == kForStepping) { // Never install stepping code. return false; @@ -1576,14 +1579,10 @@ bool NativeModule::should_update_code_table(WasmCode* new_code, } // In kNoDebugging: // Install if the tier is higher than before or we replace debugging code with - // non-debugging code. - // Also allow installing a lower tier if deopt support is enabled and the - // prior code has deopt data. (The check for deopt_data is needed as with - // compilation hints, both baseline and top tier compilation run concurrently - // in the background and can finish in any order.) + // non-debugging code. Also allow installing a lower tier if we are + // deopting. if (prior_code && !prior_code->for_debugging() && - prior_code->tier() > new_code->tier() && - (!v8_flags.wasm_deopt || prior_code->deopt_data().empty())) { + prior_code->tier() > new_code->tier() && !for_deopt) { return false; } return true; @@ -1958,28 +1957,26 @@ namespace { class NativeModuleWireBytesStorage final : public WireBytesStorage { public: explicit NativeModuleWireBytesStorage( - std::shared_ptr<base::OwnedVector<const uint8_t>> wire_bytes) + std::shared_ptr<base::UniqueArray<const uint8_t>> wire_bytes) : wire_bytes_(std::move(wire_bytes)) {} base::Vector<const uint8_t> GetCode(WireBytesRef ref) const final { - return std::atomic_load(&wire_bytes_) - ->as_vector() - .SubVector(ref.offset(), ref.end_offset()); + return std::atomic_load(&wire_bytes_)->subspan(ref.offset(), ref.length()); } std::optional<ModuleWireBytes> GetModuleBytes() const final { return std::optional<ModuleWireBytes>( - std::atomic_load(&wire_bytes_)->as_vector()); + std::atomic_load(&wire_bytes_)->as_span()); } private: - const std::shared_ptr<base::OwnedVector<const uint8_t>> wire_bytes_; + const std::shared_ptr<base::UniqueArray<const uint8_t>> wire_bytes_; }; } // namespace -void NativeModule::SetWireBytes(base::OwnedVector<const uint8_t> wire_bytes) { +void NativeModule::SetWireBytes(base::UniqueArray<const uint8_t> wire_bytes) { auto shared_wire_bytes = - std::make_shared<base::OwnedVector<const uint8_t>>(std::move(wire_bytes)); + std::make_shared<base::UniqueArray<const uint8_t>>(std::move(wire_bytes)); std::atomic_store(&wire_bytes_, shared_wire_bytes); if (!shared_wire_bytes->empty()) { compilation_state_->SetWireBytesStorage( @@ -2596,11 +2593,14 @@ std::shared_ptr<NativeModule> WasmCodeManager::NewNativeModule( // The '--wasm-max-initial-code-space-reservation' testing flag can be used to // reduce the maximum size of the initial code space reservation (in MB). - if (v8_flags.wasm_max_initial_code_space_reservation > 0) { + if (v8_flags.wasm_max_initial_code_space_reservation > 0 && + static_cast<size_t>(v8_flags.wasm_max_initial_code_space_reservation) <= + code_vmem_size / MB) { size_t flag_max_bytes = static_cast<size_t>(v8_flags.wasm_max_initial_code_space_reservation) * MB; - if (flag_max_bytes < code_vmem_size) code_vmem_size = flag_max_bytes; + size_t min_bytes = 2 * OverheadPerCodeSpace(module->num_declared_functions); + code_vmem_size = std::max(flag_max_bytes, min_bytes); } VirtualMemory code_space; @@ -2787,12 +2787,11 @@ std::vector<UnpublishedWasmCode> NativeModule::AddCompiledCode( AddCodeWithCodeSpace( result.func_index, result.code_desc, result.frame_slot_count, result.ool_spill_count, result.tagged_parameter_slots, - result.trapping_instructions_data.as_vector(), - result.source_positions.as_vector(), - result.inlining_positions.as_vector(), - result.deopt_data.as_vector(), GetCodeKind(result), - result.result_tier, result.for_debugging, - result.effect_handlers.as_vector(), result.frame_has_feedback_slot, + result.trapping_instructions_data.as_span(), + result.source_positions.as_span(), + result.inlining_positions.as_span(), result.deopt_data.as_span(), + GetCodeKind(result), result.result_tier, result.for_debugging, + result.effect_handlers.as_span(), result.frame_has_feedback_slot, this_code_space, jump_tables), std::move(result.assumptions)); } @@ -2922,14 +2921,11 @@ size_t NativeModule::EstimateCurrentMemoryConsumption() const { size_t result = sizeof(NativeModule); result += module_->EstimateCurrentMemoryConsumption(); - std::shared_ptr<base::OwnedVector<const uint8_t>> wire_bytes = + std::shared_ptr<base::UniqueArray<const uint8_t>> wire_bytes = std::atomic_load(&wire_bytes_); size_t wire_bytes_size = wire_bytes ? wire_bytes->size() : 0; result += wire_bytes_size; - if (source_map_) { - result += source_map_->EstimateCurrentMemoryConsumption(); - } result += compilation_state_->EstimateCurrentMemoryConsumption(); // For {tiering_budgets_}. result += module_->num_declared_functions * sizeof(uint32_t); @@ -2959,6 +2955,9 @@ size_t NativeModule::EstimateCurrentMemoryConsumption() const { result += module_->num_declared_functions * sizeof(void*); result += ContentSize(code_space_data_); debug_info = debug_info_.get(); + if (source_map_) { + result += source_map_->EstimateCurrentMemoryConsumption(); + } if (names_provider_) { result += names_provider_->EstimateCurrentMemoryConsumption(); } diff --git a/deps/v8/src/wasm/wasm-code-manager.h b/deps/v8/src/wasm/wasm-code-manager.h index 9f54c110103b..5cbdb0537d5c 100644 --- a/deps/v8/src/wasm/wasm-code-manager.h +++ b/deps/v8/src/wasm/wasm-code-manager.h @@ -21,6 +21,7 @@ #include "src/base/bit-field.h" #include "src/base/logging.h" #include "src/base/macros.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/builtins/builtins.h" #include "src/codegen/safepoint-table.h" @@ -470,8 +471,6 @@ class V8_EXPORT_PRIVATE WasmCode final { DCHECK_LE(jump_table_info_offset, unpadded_binary_size); } - void TryLoadSourceMap(Isolate* isolate) const; - std::unique_ptr<const uint8_t[]> ConcatenateBytes( std::initializer_list<base::Vector<const uint8_t>>); @@ -564,6 +563,7 @@ const char* GetWasmCodeKindAsString(WasmCode::Kind); struct UnpublishedWasmCode { std::unique_ptr<WasmCode> code; std::unique_ptr<AssumptionsJournal> assumptions; + bool for_deopt = false; static constexpr AssumptionsJournal* kNoAssumptions = nullptr; }; @@ -767,7 +767,7 @@ class V8_EXPORT_PRIVATE NativeModule final { // Log all owned code in the given isolate, using the given script as the // containing script. Use this after transferring the module to a new isolate // or when enabling a component that needs all code to be logged (profiler). - void LogWasmCodes(Isolate*, Tagged<Script>); + void LogWasmCodes(Isolate*, DirectHandle<Script>); CompilationState* compilation_state() const V8_LIFETIME_BOUND { return compilation_state_.get(); @@ -785,7 +785,7 @@ class V8_EXPORT_PRIVATE NativeModule final { void set_lazy_compile_frozen(bool frozen) { lazy_compile_frozen_ = frozen; } bool lazy_compile_frozen() const { return lazy_compile_frozen_; } base::Vector<const uint8_t> wire_bytes() const V8_LIFETIME_BOUND { - return std::atomic_load(&wire_bytes_)->as_vector(); + return std::atomic_load(&wire_bytes_)->as_span(); } const WasmModule* module() const V8_LIFETIME_BOUND { return module_.get(); } std::shared_ptr<const WasmModule> shared_module() const { return module_; } @@ -810,7 +810,7 @@ class V8_EXPORT_PRIVATE NativeModule final { auto wire_bytes = std::atomic_load(&wire_bytes_); return wire_bytes && !wire_bytes->empty(); } - void SetWireBytes(base::OwnedVector<const uint8_t> wire_bytes); + void SetWireBytes(base::UniqueArray<const uint8_t> wire_bytes); void AddLiftoffBailout() { liftoff_bailout_count_.fetch_add(1, std::memory_order_relaxed); @@ -979,6 +979,8 @@ class V8_EXPORT_PRIVATE NativeModule final { std::shared_ptr<const WasmModule> module, std::shared_ptr<NativeModule>* shared_this); + void TryLoadSourceMap(Isolate* isolate); + std::unique_ptr<WasmCode> AddCodeWithCodeSpace( int index, const CodeDesc& desc, int stack_slots, int ool_spill_count, uint32_t tagged_parameter_slots, @@ -1034,12 +1036,14 @@ class V8_EXPORT_PRIVATE NativeModule final { // {NativeModule}. The {AssumptionsJournal} (if provided) will be checked // before publishing the code, but should only be deallocated by the caller // after releasing the lock, to keep the critical section small. - WasmCode* PublishCodeLocked(std::unique_ptr<WasmCode>, AssumptionsJournal*); + WasmCode* PublishCodeLocked(std::unique_ptr<WasmCode>, AssumptionsJournal*, + bool for_deopt = false); // Transfer owned code from {new_owned_code_} to {owned_code_}. void TransferNewOwnedCodeLocked() const; - bool should_update_code_table(WasmCode* new_code, WasmCode* prior_code) const; + bool should_update_code_table(WasmCode* new_code, WasmCode* prior_code, + bool for_deopt) const; // -- Fields of {NativeModule} start here. @@ -1064,7 +1068,7 @@ class V8_EXPORT_PRIVATE NativeModule final { // Wire bytes, held in a shared_ptr so they can be kept alive by the // {WireBytesStorage}, held by background compile tasks. - std::shared_ptr<base::OwnedVector<const uint8_t>> wire_bytes_; + std::shared_ptr<base::UniqueArray<const uint8_t>> wire_bytes_; // The first allocated jump table. Always used by external calls (from JS). // Wasm calls might use one of the other jump tables stored in diff --git a/deps/v8/src/wasm/wasm-debug.cc b/deps/v8/src/wasm/wasm-debug.cc index 2a45a67074fe..2a48af97e6d4 100644 --- a/deps/v8/src/wasm/wasm-debug.cc +++ b/deps/v8/src/wasm/wasm-debug.cc @@ -8,6 +8,8 @@ #include <unordered_map> #include "src/base/logging.h" +#include "src/base/small-vector.h" +#include "src/base/unique-array.h" #include "src/codegen/safepoint-table.h" #include "src/common/assert-scope.h" #include "src/common/simd128.h" @@ -54,8 +56,8 @@ Address FindNewPC(WasmFrame* frame, WasmCode* wasm_code, int byte_offset, int pc_offset = static_cast<int>(frame->pc() - old_code->instruction_start()); base::Vector<const uint8_t> old_pos_table = old_code->source_positions(); int call_offset = -1; - for (SourcePositionTableIterator old_it(old_pos_table); - !old_it.done() && old_it.code_offset() < pc_offset; old_it.Advance()) { + SourcePositionTableIterator old_it(old_pos_table); + for (; !old_it.done() && old_it.code_offset() < pc_offset; old_it.Advance()) { call_offset = old_it.code_offset(); } DCHECK_LE(0, call_offset); @@ -64,56 +66,47 @@ Address FindNewPC(WasmFrame* frame, WasmCode* wasm_code, int byte_offset, // If {return_location == kAfterBreakpoint}, we want to skip the breakpoint // preamble/handler and resume at the first instruction representing the Wasm // statement. Thus, we find the first code offset marked as a statement. - // If {return_location == kAfterWasmCall}, the frame is waiting for a call - // to return. The call instruction may be inline or inside Out-Of-Line (OOL) - // code (which is appended at the end of the function). In both cases, the - // call is the last instruction emitted for this bytecode offset. Thus, we - // want the last matching code offset. - SourcePositionTableIterator it(new_pos_table); - while (true) { - CHECK(!it.done()); - if (it.source_position().ScriptOffset() == byte_offset) break; - it.Advance(); - } - int code_offset; if (return_location == kAfterBreakpoint) { + SourcePositionTableIterator it(new_pos_table); + while (true) { + CHECK(!it.done()); + if (it.source_position().ScriptOffset() == byte_offset) break; + it.Advance(); + } while (!it.is_statement()) { it.Advance(); CHECK(!it.done()); } DCHECK_EQ(byte_offset, it.source_position().ScriptOffset()); - code_offset = it.code_offset(); - } else { - DCHECK_EQ(kAfterWasmCall, return_location); - // Find the last matching entry in the old code. If the old suspend point - // was the last match, we want the last match in the new code (e.g. for OOL - // trap). Otherwise we want the inline call (which is the last matching - // entry in the first contiguous run). - int last_old_match = -1; - for (SourcePositionTableIterator old_group_it(old_pos_table); - !old_group_it.done(); old_group_it.Advance()) { - if (old_group_it.source_position().ScriptOffset() == byte_offset) { - last_old_match = old_group_it.code_offset(); - } - } - bool was_last_entry = (call_offset == last_old_match); + return wasm_code->instruction_start() + it.code_offset() + + call_instruction_size; + } - // Find the last match in the first contiguous run. - code_offset = it.code_offset(); - for (; !it.done() && it.source_position().ScriptOffset() == byte_offset; - it.Advance()) { - code_offset = it.code_offset(); + // If {return_location == kAfterWasmCall}, the frame is waiting for a call or + // trap to return. Multiple calls or Out-Of-Line (OOL) traps can be emitted + // for the same bytecode offset. Because the only source position difference + // between {old_code} and {new_code} is whether a breakpoint is emitted at the + // start of each instruction (before any calls or OOL traps for that + // instruction), the number of matching entries *after* {call_offset} is + // identical in both tables. + DCHECK_EQ(kAfterWasmCall, return_location); + size_t remaining_matches = 0; + for (; !old_it.done(); old_it.Advance()) { + if (old_it.source_position().ScriptOffset() == byte_offset) { + ++remaining_matches; } - if (was_last_entry) { - // Find the absolute last match in the rest of the table (e.g., OOL trap). - for (; !it.done(); it.Advance()) { - if (it.source_position().ScriptOffset() == byte_offset) { - code_offset = it.code_offset(); - } - } + } + + base::SmallVector<int, 4> matching_offsets; + for (SourcePositionTableIterator it(new_pos_table); !it.done(); + it.Advance()) { + if (it.source_position().ScriptOffset() == byte_offset) { + matching_offsets.push_back(it.code_offset()); } } - CHECK_NE(code_offset, -1); + CHECK_LT(remaining_matches, matching_offsets.size()); + int code_offset = + matching_offsets[matching_offsets.size() - 1 - remaining_matches]; return wasm_code->instruction_start() + code_offset + call_instruction_size; } @@ -221,35 +214,53 @@ class DebugInfoImpl { return offset; } - // Find the dead breakpoint (see above) for the top Wasm frame, if that frame - // is in the function of the given index. - int DeadBreakpoint(int func_index, base::Vector<const int> breakpoints, - Isolate* isolate) { + // Find the dead breakpoints (see above) for all Wasm frames of the given + // function that are currently paused at a breakpoint. + std::vector<int> DeadBreakpoints(int func_index, + base::Vector<const int> breakpoints, + Isolate* isolate) { auto isolate_it = per_isolate_data_.find(isolate); StackFrameId stepping_frame = isolate_it == per_isolate_data_.end() ? NO_ID : isolate_it->second.stepping_frame; - for (DebuggableStackFrameIterator it(isolate); !it.done(); it.Advance()) { - if (it.frame()->id() == stepping_frame) continue; - if (!it.is_wasm()) continue; + std::vector<int> dead_breakpoints; + for (StackFrameIterator it(isolate); !it.done(); it.Advance()) { + if (!it.frame()->is_wasm_debug_break()) continue; + bool at_trap = it.frame()->LookupCode()->builtin_id() == + Builtin::kWasmTrapHandlerThrowTrap; + it.Advance(); + CHECK(!it.done()); + // Frames paused at a trap (rather than a breakpoint) are patched using + // kAfterWasmCall and do not need a dead breakpoint; skip the underlying + // Wasm frame. + if (at_trap) continue; + if (!it.frame()->is_wasm()) continue; #if V8_ENABLE_DRUMBRAKE // TODO(paolosev@microsoft.com) - Implement for Wasm interpreter. - if (it.is_wasm_interpreter_entry()) break; + if (it.frame()->is_wasm_interpreter_entry()) continue; #endif // V8_ENABLE_DRUMBRAKE WasmFrame* wasm_frame = WasmFrame::cast(it.frame()); - if (wasm_frame->native_module() != native_module_) break; - FrameSummary::WasmFrameSummary summary = - FrameSummary::GetInnermost(wasm_frame).AsWasm(); - if (static_cast<int>(summary.function_index()) != func_index) break; - return DeadBreakpoint(wasm_frame, breakpoints); + if (wasm_frame->id() == stepping_frame) continue; + if (wasm_frame->native_module() != native_module_) continue; + WasmCode* code = wasm_frame->wasm_code(); + if (!code->is_liftoff() || code->index() != func_index || + !code->for_debugging()) { + continue; + } + int offset = DeadBreakpoint(wasm_frame, breakpoints); + if (offset != 0) dead_breakpoints.push_back(offset); } - return 0; + std::sort(dead_breakpoints.begin(), dead_breakpoints.end()); + dead_breakpoints.erase( + std::unique(dead_breakpoints.begin(), dead_breakpoints.end()), + dead_breakpoints.end()); + return dead_breakpoints; } - WasmCode* RecompileLiftoffWithBreakpoints(int func_index, - base::Vector<const int> offsets, - int dead_breakpoint) { + WasmCode* RecompileLiftoffWithBreakpoints( + int func_index, base::Vector<const int> offsets, + base::Vector<const int> dead_breakpoints) { mutex_.AssertHeld(); // Mutex is held externally. DCHECK(!v8_flags.wasm_jitless); @@ -261,9 +272,8 @@ class DebugInfoImpl { for (auto begin = cached_debugging_code_.begin(), it = begin, end = cached_debugging_code_.end(); it != end; ++it) { - if (it->func_index == func_index && - it->breakpoint_offsets.as_vector() == offsets && - it->dead_breakpoint == dead_breakpoint) { + if (it->func_index == func_index && it->breakpoint_offsets == offsets && + it->dead_breakpoints == dead_breakpoints) { // Rotate the cache entry to the front (for LRU). for (; it != begin; --it) std::iter_swap(it, it - 1); if (for_debugging == kWithBreakpoints) { @@ -292,10 +302,10 @@ class DebugInfoImpl { .for_debugging = for_debugging, .counter_updates = native_module_->counter_updates(), .breakpoints = offsets, + .dead_breakpoints = dead_breakpoints, .debug_sidetable = generate_debug_sidetable ? &debug_sidetable - : nullptr, - .dead_breakpoint = dead_breakpoint}); + : nullptr}); // Liftoff compilation failure is a FATAL error. We rely on complete Liftoff // support for debugging. if (!result.succeeded()) { @@ -318,8 +328,8 @@ class DebugInfoImpl { // Insert new code into the cache. Insert before existing elements for LRU. cached_debugging_code_.insert( cached_debugging_code_.begin(), - CachedDebuggingCode{func_index, base::OwnedCopyOf(offsets), - dead_breakpoint, new_code}); + CachedDebuggingCode{func_index, base::UniqueCopyOf(offsets), + base::UniqueCopyOf(dead_breakpoints), new_code}); // Increase the ref count (for the cache entry). new_code->IncRef(); // Remove exceeding element. @@ -376,10 +386,11 @@ class DebugInfoImpl { all_breakpoints.insert(insertion_point, offset); } - int dead_breakpoint = - DeadBreakpoint(func_index, base::VectorOf(all_breakpoints), isolate); + std::vector<int> dead_breakpoints = + DeadBreakpoints(func_index, base::VectorOf(all_breakpoints), isolate); WasmCode* new_code = RecompileLiftoffWithBreakpoints( - func_index, base::VectorOf(all_breakpoints), dead_breakpoint); + func_index, base::VectorOf(all_breakpoints), + base::VectorOf(dead_breakpoints)); UpdateReturnAddresses(isolate, new_code, isolate_data.stepping_frame); } @@ -396,13 +407,13 @@ class DebugInfoImpl { void UpdateBreakpoints(int func_index, base::Vector<int> breakpoints, Isolate* isolate, StackFrameId stepping_frame, - int dead_breakpoint) { + base::Vector<const int> dead_breakpoints) { // TODO(paolosev@microsoft.com) - Add support for breakpoints in Wasm // interpreter. if (v8_flags.wasm_jitless) return; mutex_.AssertHeld(); // Mutex is held externally. WasmCode* new_code = RecompileLiftoffWithBreakpoints( - func_index, breakpoints, dead_breakpoint); + func_index, breakpoints, dead_breakpoints); UpdateReturnAddresses(isolate, new_code, stepping_frame); } @@ -417,7 +428,7 @@ class DebugInfoImpl { base::MutexGuard guard(&mutex_); WasmCode* new_code = RecompileLiftoffWithBreakpoints( FrameSummary::GetInnermost(frame).AsWasm().function_index(), - base::ArrayVector(kFloodingBreakpoints), 0); + base::ArrayVector(kFloodingBreakpoints), {}); UpdateReturnAddress(frame, new_code, return_location); per_isolate_data_[frame->isolate()].stepping_frame = frame->id(); @@ -441,8 +452,8 @@ class DebugInfoImpl { wasm::WasmCode* code = frame->wasm_code(); if (!code->is_liftoff()) return false; // Cannot step in TurboFan code. if (IsAtReturn(frame)) return false; // Will return after this step. - ReturnLocation return_location = kAfterBreakpoint; - // Check if the frame above is a WasmDebugTrap builtin call. + // Check if the frame is paused at a WasmDebugBreak builtin call, or waiting + // for a call/trap to return. StackFrameIterator it(frame->isolate()); Builtin last_builtin = Builtin::kNoBuiltinId; while (!it.done()) { @@ -452,9 +463,9 @@ class DebugInfoImpl { : Builtin::kNoBuiltinId; it.Advance(); } - if (last_builtin == Builtin::kWasmDebugTrap) { - return_location = kAfterWasmCall; - } + ReturnLocation return_location = last_builtin == Builtin::kWasmDebugBreak + ? kAfterBreakpoint + : kAfterWasmCall; FloodWithBreakpoints(frame, return_location); return true; } @@ -477,8 +488,11 @@ class DebugInfoImpl { int func_index = code->index(); std::vector<int> breakpoints = FindAllBreakpoints(func_index); int dead_breakpoint = DeadBreakpoint(frame, base::VectorOf(breakpoints)); + base::Vector<const int> dead_breakpoints = + dead_breakpoint == 0 ? base::Vector<const int>{} + : base::VectorOf(&dead_breakpoint, 1); WasmCode* new_code = RecompileLiftoffWithBreakpoints( - func_index, base::VectorOf(breakpoints), dead_breakpoint); + func_index, base::VectorOf(breakpoints), dead_breakpoints); UpdateReturnAddress(frame, new_code, kAfterBreakpoint); } @@ -523,10 +537,11 @@ class DebugInfoImpl { // If the breakpoint is still set in another isolate, don't remove it. DCHECK(std::is_sorted(remaining.begin(), remaining.end())); if (std::binary_search(remaining.begin(), remaining.end(), offset)) return; - int dead_breakpoint = - DeadBreakpoint(func_index, base::VectorOf(remaining), isolate); + std::vector<int> dead_breakpoints = + DeadBreakpoints(func_index, base::VectorOf(remaining), isolate); UpdateBreakpoints(func_index, base::VectorOf(remaining), isolate, - isolate_data.stepping_frame, dead_breakpoint); + isolate_data.stepping_frame, + base::VectorOf(dead_breakpoints)); } void RemoveDebugSideTables(base::Vector<WasmCode* const> codes) { @@ -571,14 +586,14 @@ class DebugInfoImpl { std::vector<int> remaining = FindAllBreakpoints(func_index); if (HasRemovedBreakpoints(removed, remaining)) { RecompileLiftoffWithBreakpoints(func_index, base::VectorOf(remaining), - 0); + {}); } } } size_t EstimateCurrentMemoryConsumption() const { UPDATE_WHEN_CLASS_CHANGES(DebugInfoImpl, 144); - UPDATE_WHEN_CLASS_CHANGES(CachedDebuggingCode, 40); + UPDATE_WHEN_CLASS_CHANGES(CachedDebuggingCode, 48); UPDATE_WHEN_CLASS_CHANGES(PerIsolateDebugData, 48); size_t result = sizeof(DebugInfoImpl); { @@ -592,7 +607,9 @@ class DebugInfoImpl { base::MutexGuard lock(&mutex_); result += ContentSize(cached_debugging_code_); for (const CachedDebuggingCode& code : cached_debugging_code_) { - result += code.breakpoint_offsets.size() * sizeof(int); + result += + (code.breakpoint_offsets.size() + code.dead_breakpoints.size()) * + sizeof(int); } result += ContentSize(per_isolate_data_); for (const auto& [isolate, data] : per_isolate_data_) { @@ -671,13 +688,24 @@ class DebugInfoImpl { const DebugSideTable::Entry::Value* value = debug_side_table->FindValue(debug_side_table_entry, index); if (value->is_constant()) { - DCHECK(value->type == kWasmI32 || value->type == kWasmI64); - return value->type == kWasmI32 ? WasmValue(value->i32_const) - : WasmValue(int64_t{value->i32_const}); + switch (value->type.kind()) { + case kI32: + return WasmValue(value->i32_const); + case kI64: + return WasmValue(int64_t{value->i32_const}); + case kF32: + return WasmValue( + Float32::FromBits(static_cast<uint32_t>(value->i32_const))); + case kF64: + return WasmValue(Float64::FromBits( + static_cast<uint64_t>(int64_t{value->i32_const}))); + default: + UNREACHABLE(); + } } if (value->is_register()) { - if (debug_break_fp == kNullAddress) return {}; + DCHECK_NE(kNullAddress, debug_break_fp); auto reg = LiftoffRegister::from_liftoff_code(value->reg_code); auto gp_addr = [debug_break_fp](Register reg) { return debug_break_fp + @@ -693,7 +721,11 @@ class DebugInfoImpl { } if (reg.is_gp()) { if (value->type == kWasmI32) { - return WasmValue(ReadUnalignedValue<uint32_t>(gp_addr(reg.gp()))); + Address addr = gp_addr(reg.gp()); +#if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT + addr += kInt32Size; +#endif + return WasmValue(ReadUnalignedValue<uint32_t>(addr)); } else if (value->type == kWasmI64) { return WasmValue(ReadUnalignedValue<uint64_t>(gp_addr(reg.gp()))); } else if (value->type.is_ref()) { @@ -732,6 +764,11 @@ class DebugInfoImpl { // Otherwise load the value from the stack. Address stack_address = stack_frame_base - value->stack_offset; +#if V8_TARGET_BIG_ENDIAN && V8_HOST_ARCH_64_BIT + if (value->type.kind() == kI32 || value->type.kind() == kF32) { + stack_address += kInt32Size; + } +#endif switch (value->type.kind()) { case kI32: return WasmValue(ReadUnalignedValue<int32_t>(stack_address)); @@ -772,8 +809,8 @@ class DebugInfoImpl { bool at_debug_break = it.frame()->is_wasm_debug_break(); bool at_trap = false; if (at_debug_break) { - at_trap = - it.frame()->LookupCode()->builtin_id() == Builtin::kWasmDebugTrap; + at_trap = it.frame()->LookupCode()->builtin_id() == + Builtin::kWasmTrapHandlerThrowTrap; it.Advance(); CHECK(!it.done()); } @@ -814,14 +851,6 @@ class DebugInfoImpl { FindNewPC(frame, new_code, summary.code_offset(), return_location); #ifdef DEBUG int old_position = summary.SourcePosition(); -#if !defined(V8_TARGET_ARCH_X64) - // On non-x64 architectures, we patch the return address of the currently - // executing builtin (e.g. kWasmDebugBreak) to jump directly into the new - // code. If the new code has a different safepoint entry than the physical - // frame state, a GC could miss live references or cause type confusion. On - // x64, we return to the old code first, which then performs a cooperative - // transition to the new code, so the safepoint information does not need to - // match exactly at the OSR target PC. { SafepointTable old_table(frame->wasm_code()); SafepointTable new_table(new_code); @@ -836,7 +865,6 @@ class DebugInfoImpl { } } #endif -#endif #if V8_TARGET_ARCH_X64 base::Memory<Address>(frame->fp() - kOSRTargetOffset) = new_pc; #else @@ -893,8 +921,8 @@ class DebugInfoImpl { static constexpr size_t kMaxCachedDebuggingCode = 3; struct CachedDebuggingCode { int func_index; - base::OwnedVector<const int> breakpoint_offsets; - int dead_breakpoint; + base::UniqueArray<const int> breakpoint_offsets; + base::UniqueArray<const int> dead_breakpoints; WasmCode* code; }; std::vector<CachedDebuggingCode> cached_debugging_code_; @@ -1100,14 +1128,12 @@ bool WasmScript::SetBreakPointForFunction( namespace { -int GetBreakpointPos(Isolate* isolate, - Tagged<Object> break_point_info_or_undef) { +int GetBreakpointPos(Tagged<Object> break_point_info_or_undef) { if (IsUndefined(break_point_info_or_undef)) return kMaxInt; return Cast<BreakPointInfo>(break_point_info_or_undef)->source_position(); } -int FindBreakpointInfoInsertPos(Isolate* isolate, - DirectHandle<FixedArray> breakpoint_infos, +int FindBreakpointInfoInsertPos(Tagged<FixedArray> breakpoint_infos, int position) { // Find insert location via binary search, taking care of undefined values on // the right. {position} is either {kOnEntryBreakpointPosition} (which is -1), @@ -1120,17 +1146,47 @@ int FindBreakpointInfoInsertPos(Isolate* isolate, while (right - left > 1) { int mid = left + (right - left) / 2; Tagged<Object> mid_obj = breakpoint_infos->get(mid); - if (GetBreakpointPos(isolate, mid_obj) <= position) { + if (GetBreakpointPos(mid_obj) <= position) { left = mid; } else { right = mid; } } - int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left)); + int left_pos = GetBreakpointPos(breakpoint_infos->get(left)); return left_pos < position ? left + 1 : left; } +bool HasBreakpointAtPosition(Tagged<Script> script, int position) { + if (!script->has_wasm_breakpoint_infos()) return false; + Tagged<FixedArray> breakpoint_infos = script->wasm_breakpoint_infos(); + int pos = FindBreakpointInfoInsertPos(breakpoint_infos, position); + return pos < static_cast<int>(breakpoint_infos->ulength().value()) && + GetBreakpointPos(breakpoint_infos->get(pos)) == position; +} + +bool AnyOtherScriptHasBreakpointAtPosition(Isolate* isolate, + Tagged<Script> script, + wasm::NativeModule* native_module, + int position) { + DirectHandle<WeakArrayList> wasm_scripts = + isolate->debug()->wasm_scripts_with_break_points(); + if (wasm_scripts.is_null()) return false; + DisallowGarbageCollection no_gc; + const uint32_t wasm_scripts_len = wasm_scripts->length().value(); + for (uint32_t i = 0; i < wasm_scripts_len; ++i) { + Tagged<HeapObject> raw_script; + if (!wasm_scripts->Get(i).GetHeapObject(&raw_script)) continue; + Tagged<Script> other_script = Cast<Script>(raw_script); + if (other_script == script) continue; + if (other_script->wasm_native_module().raw() != native_module) continue; + if (HasBreakpointAtPosition(other_script, position)) { + return true; + } + } + return false; +} + } // namespace // static @@ -1142,14 +1198,16 @@ bool WasmScript::ClearBreakPoint(DirectHandle<Script> script, int position, DirectHandle<FixedArray> breakpoint_infos(script->wasm_breakpoint_infos(), isolate); - int int_pos = - FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position); + int int_pos = FindBreakpointInfoInsertPos(*breakpoint_infos, position); DCHECK_GE(int_pos, 0); uint32_t pos = static_cast<uint32_t>(int_pos); uint32_t breakpoint_infos_len = breakpoint_infos->ulength().value(); // Does a BreakPointInfo object already exist for this position? - if (pos == breakpoint_infos_len) return false; + if (pos == breakpoint_infos_len || + GetBreakpointPos(breakpoint_infos->get(pos)) != position) { + return false; + } DirectHandle<BreakPointInfo> info( Cast<BreakPointInfo>(breakpoint_infos->get(pos)), isolate); @@ -1167,19 +1225,22 @@ bool WasmScript::ClearBreakPoint(DirectHandle<Script> script, int position, breakpoint_infos->set(breakpoint_infos_len - 1, ReadOnlyRoots{isolate}.undefined_value(), SKIP_WRITE_BARRIER); - } - if (break_point->id() == v8::internal::Debug::kInstrumentationId) { - // Special handling for instrumentation breakpoints. - SetBreakOnEntryFlag(*script, false); - } else { - // Remove the breakpoint from DebugInfo and recompile. - CppGCManaged<wasm::NativeModule>::Ptr native_module = - script->wasm_native_module(); - const wasm::WasmModule* module = native_module->module(); - int func_index = GetContainingWasmFunction(module, position); - native_module->GetDebugInfo()->RemoveBreakpoint(func_index, position, - isolate); + if (break_point->id() == v8::internal::Debug::kInstrumentationId) { + // Special handling for instrumentation breakpoints. + SetBreakOnEntryFlag(*script, false); + } else { + CppGCManaged<wasm::NativeModule>::Ptr native_module = + script->wasm_native_module(); + if (!AnyOtherScriptHasBreakpointAtPosition( + isolate, *script, native_module.raw(), position)) { + // Remove the breakpoint from DebugInfo and recompile. + const wasm::WasmModule* module = native_module->module(); + int func_index = GetContainingWasmFunction(module, position); + native_module->GetDebugInfo()->RemoveBreakpoint(func_index, position, + isolate); + } + } } return true; @@ -1234,17 +1295,16 @@ void WasmScript::AddBreakpointToInfo(DirectHandle<Script> script, int position, breakpoint_infos = isolate->factory()->NewFixedArray(4, AllocationType::kOld); script->set_wasm_breakpoint_infos(*breakpoint_infos); + isolate->debug()->RecordWasmScriptWithBreakpoints(script); } - int insert_pos = - FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position); + int insert_pos = FindBreakpointInfoInsertPos(*breakpoint_infos, position); uint32_t breakpoint_infos_len = breakpoint_infos->ulength().value(); // If a BreakPointInfo object already exists for this position, add the new // breakpoint object and return. if (insert_pos < static_cast<int>(breakpoint_infos_len) && - GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) == - position) { + GetBreakpointPos(breakpoint_infos->get(insert_pos)) == position) { DirectHandle<BreakPointInfo> old_info( Cast<BreakPointInfo>(breakpoint_infos->get(insert_pos)), isolate); BreakPointInfo::SetBreakPoint(isolate, old_info, break_point); @@ -1356,6 +1416,12 @@ namespace { bool CheckBreakPoint(Isolate* isolate, DirectHandle<BreakPoint> break_point, StackFrameId frame_id) { + // The condition of another break point at the same position might have + // disabled the debugger (e.g. an embedder that dispatches `Debugger.disable` + // synchronously from within the condition). Don't evaluate any further + // conditions in that case, debug-evaluate requires an active debugger. + if (!isolate->debug()->is_active()) return false; + if (break_point->condition()->length() == 0) return true; HandleScope scope(isolate); @@ -1383,8 +1449,7 @@ MaybeDirectHandle<FixedArray> WasmScript::CheckBreakPoints( DirectHandle<FixedArray> breakpoint_infos(script->wasm_breakpoint_infos(), isolate); - int insert_pos = - FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position); + int insert_pos = FindBreakpointInfoInsertPos(*breakpoint_infos, position); if (insert_pos >= static_cast<int>(breakpoint_infos->ulength().value())) { return {}; } diff --git a/deps/v8/src/wasm/wasm-deopt-data.cc b/deps/v8/src/wasm/wasm-deopt-data.cc index 87ab2a082ec4..db162fbd71ef 100644 --- a/deps/v8/src/wasm/wasm-deopt-data.cc +++ b/deps/v8/src/wasm/wasm-deopt-data.cc @@ -5,6 +5,7 @@ #include "src/wasm/wasm-deopt-data.h" #include "src/base/sanitizer/msan.h" +#include "src/base/unique-array.h" #include "src/objects/deoptimization-data.h" namespace v8::internal::wasm { @@ -24,7 +25,7 @@ WasmDeoptView::BuildDeoptimizationLiteralArray() { return deopt_literals; } -base::OwnedVector<uint8_t> WasmDeoptDataProcessor::Serialize( +base::UniqueArray<uint8_t> WasmDeoptDataProcessor::Serialize( int deopt_exit_start_offset, int eager_deopt_count, base::Vector<const uint8_t> translation_array, base::Vector<wasm::WasmDeoptEntry> deopt_entries, @@ -50,8 +51,8 @@ base::OwnedVector<uint8_t> WasmDeoptDataProcessor::Serialize( }); size_t byte_size = sizeof(data) + translation_array_byte_size + deopt_entries_byte_size + deopt_literals_byte_size; - auto result = base::OwnedVector<uint8_t>::New(byte_size); - base::Vector<uint8_t> remaining_buffer = result.as_vector(); + auto result = base::UniqueArray<uint8_t>::New(byte_size); + base::Vector<uint8_t> remaining_buffer = result.as_span(); std::memcpy(remaining_buffer.begin(), &data, sizeof(data)); remaining_buffer += sizeof(data); std::memcpy(remaining_buffer.begin(), translation_array.data(), diff --git a/deps/v8/src/wasm/wasm-deopt-data.h b/deps/v8/src/wasm/wasm-deopt-data.h index d0f29095bd91..df89a8978678 100644 --- a/deps/v8/src/wasm/wasm-deopt-data.h +++ b/deps/v8/src/wasm/wasm-deopt-data.h @@ -9,6 +9,7 @@ #endif // !V8_ENABLE_WEBASSEMBLY #include "src/base/memory.h" +#include "src/base/unique-array.h" #include "src/utils/utils.h" #include "src/wasm/baseline/liftoff-varstate.h" #include "src/zone/zone-containers.h" @@ -85,7 +86,7 @@ class WasmDeoptView { class WasmDeoptDataProcessor { public: - static base::OwnedVector<uint8_t> Serialize( + static base::UniqueArray<uint8_t> Serialize( int deopt_exit_start_offset, int eager_deopt_count, base::Vector<const uint8_t> translation_array, base::Vector<wasm::WasmDeoptEntry> deopt_entries, diff --git a/deps/v8/src/wasm/wasm-engine.cc b/deps/v8/src/wasm/wasm-engine.cc index 47955e35f4cf..92e8a18e0271 100644 --- a/deps/v8/src/wasm/wasm-engine.cc +++ b/deps/v8/src/wasm/wasm-engine.cc @@ -4,11 +4,13 @@ #include "src/wasm/wasm-engine.h" +#include <array> #include <optional> #include "src/base/hashing.h" #include "src/base/platform/time.h" #include "src/base/small-vector.h" +#include "src/base/unique-array.h" #include "src/codegen/cpu-features.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" @@ -234,10 +236,10 @@ class WeakScriptHandle { public: WeakScriptHandle(DirectHandle<Script> script, Isolate* isolate) : script_id_(script->id()), isolate_(isolate) { - DCHECK(IsString(script->name()) || IsUndefined(script->name())); - if (IsString(script->name())) { - source_url_ = Cast<String>(script->name())->ToCString(); - } + DCHECK(IsString(script->name())); + source_url_ = Cast<String>(script->name())->ToCString(); + is_default_url_ = + std::string_view(source_url_.get()).starts_with("wasm://wasm/"); auto global_handle = isolate->global_handles()->Create(*script); location_ = std::make_unique<Address*>(global_handle.location()); GlobalHandles::MakeWeak(location_.get()); @@ -259,6 +261,22 @@ class WeakScriptHandle { WeakScriptHandle(WeakScriptHandle&&) V8_NOEXCEPT = default; + // Move assignment is only used for compacting the `std::vector` in + // `GetOrCreateScript`, where `this` is either cleared or already moved-from, + // and `other` is still alive. + WeakScriptHandle& operator=(WeakScriptHandle&& other) V8_NOEXCEPT { + DCHECK_NE(this, &other); + DCHECK(location_ == nullptr || *location_ == nullptr); + DCHECK_NOT_NULL(other.location_); + DCHECK_NOT_NULL(*other.location_); + DCHECK_EQ(isolate_, other.isolate_); + location_ = std::move(other.location_); + script_id_ = other.script_id_; + source_url_ = std::move(other.source_url_); + is_default_url_ = other.is_default_url_; + return *this; + } + DirectHandle<Script> handle() const { return DirectHandle<Script>::FromSlot(*location_); } @@ -273,6 +291,11 @@ class WeakScriptHandle { return source_url_; } + bool MatchesSourceUrl(std::string_view source_url) const { + if (source_url.empty()) return is_default_url_; + return source_url_.get() == source_url; + } + private: // Store the location in a unique_ptr so that its address stays the same even // when this object is moved/copied. @@ -282,15 +305,21 @@ class WeakScriptHandle { // available. int script_id_; - // Similar for the source URL. We cannot dereference the handle from - // arbitrary threads, but we need the URL available for code logging. - // The shared pointer is kept alive by unlogged code, even if this entry is - // collected in the meantime. + // True if {source_url_} is a synthesized "wasm://wasm/..." default URL. + // {source_url_} stores the name from {Script::name()} (needed for code + // logging), whereas {GetOrCreateScript} receives an empty {source_url} before + // {CreateWasmScript} synthesizes that default URL. + bool is_default_url_ = false; + + // Similar to script ID, do also store the source URL. We cannot dereference + // the handle from arbitrary threads, but we need the URL available for code + // logging. The shared pointer is kept alive by unlogged code, even if this + // entry is collected in the meantime. // TODO(chromium:1132260): Revisit this for huge URLs. std::shared_ptr<const char[]> source_url_; // The Isolate that the handled script belongs to. - Isolate* isolate_; + Isolate* const isolate_; }; // If PGO data is being collected, keep all native modules alive, so repeated @@ -496,29 +525,32 @@ struct WasmEngine::IsolateInfo { // the task that would destroy the {WeakScriptHandle}'s {GlobalHandle}; // whereas if only individual entries of {scripts} get deleted, then // we can and should post such tasks. - for (auto& [native_module, script_handle] : scripts) { - script_handle.Clear(); + for (auto& [native_module, script_handles] : scripts) { + for (WeakScriptHandle& script_handle : script_handles) { + script_handle.Clear(); + } } } // All native modules that are being used by this Isolate. std::unordered_set<NativeModule*> native_modules; - // Scripts created for each native module in this isolate. - std::unordered_map<NativeModule*, WeakScriptHandle> scripts; + // Scripts created for each native module in this isolate. Multiple scripts + // can exist if the same module is compiled with different source URLs. + std::unordered_map<NativeModule*, std::vector<WeakScriptHandle>> scripts; // Caches whether code needs to be logged on this isolate. bool log_codes; - // Maps script ID to vector of code objects that still need to be logged, and - // the respective source URL. - struct CodeToLogPerScript { + // Maps each NativeModule (or nullptr for wrappers) to the vector of code + // objects that still need to be logged. + struct CodeToLogPerModule { std::vector<WasmCode*> code; - // Keep the NativeModule alive while code logging is outstanding. + // Keep the NativeModule alive while code logging is outstanding (nullptr + // for wrapper code). std::shared_ptr<NativeModule> native_module; - std::shared_ptr<const char[]> source_url; }; - std::unordered_map<int, CodeToLogPerScript> code_to_log; + std::unordered_map<NativeModule*, CodeToLogPerModule> code_to_log; // The foreground task runner of the isolate (can be called from background). std::shared_ptr<v8::TaskRunner> foreground_task_runner; @@ -592,6 +624,7 @@ WasmEngine::~WasmEngine() { DCHECK(async_compile_jobs_.empty()); // All Isolates have been deregistered. DCHECK(isolates_.empty()); + DCHECK_EQ(0, num_isolates_with_code_logging_.load(std::memory_order_relaxed)); // All NativeModules did die. DCHECK(native_modules_.empty()); // Native module cache does not leak. @@ -617,8 +650,7 @@ bool WasmEngine::SyncValidate(Isolate* isolate, WasmEnabledFeatures enabled, MaybeDirectHandle<WasmModuleObject> WasmEngine::SyncCompile( Isolate* isolate, WasmEnabledFeatures enabled_features, CompileTimeImports compile_imports, ErrorThrower* thrower, - base::OwnedVector<const uint8_t> bytes, - base::Vector<const char> source_url) { + base::UniqueArray<const uint8_t> bytes, std::string_view source_url) { int compilation_id = next_compilation_id_.fetch_add(1); TRACE_EVENT("v8.wasm", "wasm.SyncCompile", "id", compilation_id); v8::metrics::Recorder::ContextId context_id = @@ -629,7 +661,7 @@ MaybeDirectHandle<WasmModuleObject> WasmEngine::SyncCompile( // This is where sync / sync streaming compilations validate function // bodies. See {DecodeWasmModule} for an overview. ModuleResult result = - DecodeWasmModule(isolate, enabled_features, bytes.as_vector(), true, + DecodeWasmModule(isolate, enabled_features, bytes.as_span(), true, DecodingMethod::kSync, &detected_features); if (result.failed()) { thrower->CompileFailed(result.error()); @@ -637,7 +669,7 @@ MaybeDirectHandle<WasmModuleObject> WasmEngine::SyncCompile( } module = std::move(result).value(); if (WasmError error = - ValidateAndSetBuiltinImports(module.get(), bytes.as_vector(), + ValidateAndSetBuiltinImports(module.get(), bytes.as_span(), compile_imports, &detected_features)) { thrower->CompileError("%s @+%u", error.message().c_str(), error.offset()); return {}; @@ -647,7 +679,7 @@ MaybeDirectHandle<WasmModuleObject> WasmEngine::SyncCompile( // If experimental PGO via files is enabled, load profile information now. std::unique_ptr<ProfileInformation> pgo_info; if (V8_UNLIKELY(v8_flags.wasm_pgo_from_file)) { - pgo_info = LoadProfileFromFile(module.get(), bytes.as_vector()); + pgo_info = LoadProfileFromFile(module.get(), bytes.as_span()); } // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated @@ -672,7 +704,7 @@ MaybeDirectHandle<WasmModuleObject> WasmEngine::SyncCompile( DirectHandle<Script> script = GetOrCreateScript(isolate, native_module, source_url); - native_module->LogWasmCodes(isolate, *script); + native_module->LogWasmCodes(isolate, script); // Create the compiled module object and populate with compiled functions // and information needed at instantiation time. This object needs to be @@ -734,7 +766,7 @@ void WasmEngine::AsyncCompile( Isolate* isolate, WasmEnabledFeatures enabled, CompileTimeImports compile_imports, std::shared_ptr<CompilationResultResolver> resolver, - base::OwnedVector<const uint8_t> bytes, + base::UniqueArray<const uint8_t> bytes, const char* api_method_name_for_errors) { int compilation_id = next_compilation_id_.fetch_add(1); TRACE_EVENT("v8.wasm", "wasm.AsyncCompile", "id", compilation_id); @@ -768,7 +800,7 @@ void WasmEngine::AsyncCompile( auto* rng = isolate->random_number_generator(); base::SmallVector<base::Vector<const uint8_t>, 16> ranges; - if (!bytes.empty()) ranges.push_back(bytes.as_vector()); + if (!bytes.empty()) ranges.push_back(bytes.as_span()); // Split into up to 16 ranges (2^4). for (int round = 0; round < 4; ++round) { for (auto it = ranges.begin(); it != ranges.end(); ++it) { @@ -894,7 +926,7 @@ void WasmEngine::LeaveDebuggingForIsolate(Isolate* isolate) { namespace { DirectHandle<Script> CreateWasmScript( Isolate* isolate, std::shared_ptr<NativeModule> native_module, - base::Vector<const char> source_url) { + std::string_view source_url) { base::Vector<const uint8_t> wire_bytes = native_module->wire_bytes(); // The source URL of the script is @@ -910,18 +942,19 @@ DirectHandle<Script> CreateWasmScript( } else { // Limit the printed hash to 8 characters. uint32_t hash = static_cast<uint32_t>(GetWireBytesHash(wire_bytes)); - base::EmbeddedVector<char, 32> buffer; + std::array<char, 32> buffer; if (module->name.is_empty()) { // Build the URL in the form "wasm://wasm/<hash>". - int url_len = SNPrintF(buffer, "wasm://wasm/%08x", hash); + int url_len = base::SNPrintF(buffer, "wasm://wasm/%08x", hash); DCHECK(url_len >= 0 && static_cast<size_t>(url_len) < buffer.size()); - url_str = isolate->factory() - ->NewStringFromUtf8(buffer.SubVector(0, url_len), - AllocationType::kOld) - .ToHandleChecked(); + url_str = + isolate->factory() + ->NewStringFromUtf8({buffer.data(), static_cast<size_t>(url_len)}, + AllocationType::kOld) + .ToHandleChecked(); } else { // Build the URL in the form "wasm://wasm/<module name>-<hash>". - int hash_len = SNPrintF(buffer, "-%08x", hash); + int hash_len = base::SNPrintF(buffer, "-%08x", hash); DCHECK(hash_len >= 0 && static_cast<size_t>(hash_len) < buffer.size()); DirectHandle<String> prefix = isolate->factory()->NewStringFromStaticChars("wasm://wasm/"); @@ -930,7 +963,8 @@ DirectHandle<Script> CreateWasmScript( isolate, wire_bytes, module->name, kNoInternalize); DirectHandle<String> hash_str = isolate->factory() - ->NewStringFromUtf8(buffer.SubVector(0, hash_len)) + ->NewStringFromUtf8( + {buffer.data(), static_cast<size_t>(hash_len)}) .ToHandleChecked(); // Concatenate the three parts. url_str = isolate->factory() @@ -951,8 +985,8 @@ DirectHandle<Script> CreateWasmScript( ModuleWireBytes(wire_bytes) .GetNameOrNull(source_map_symbols.external_url); MaybeDirectHandle<String> src_map_str = - isolate->factory()->NewStringFromUtf8(external_url, - AllocationType::kOld); + isolate->factory()->NewStringFromUtf8( + {external_url.data(), external_url.size()}, AllocationType::kOld); source_map_url = src_map_str.ToHandleChecked(); } @@ -1002,29 +1036,14 @@ DirectHandle<Script> CreateWasmScript( } } // namespace -MaybeDirectHandle<WasmModuleObject> WasmEngine::ImportNativeModule( +DirectHandle<WasmModuleObject> WasmEngine::ImportNativeModule( Isolate* isolate, std::shared_ptr<NativeModule> shared_native_module, - base::Vector<const char> source_url) { + std::string_view source_url) { NativeModule* native_module = shared_native_module.get(); - CompileTimeImports target_imports = native_module->compile_imports(); - if (isolate->flush_denormals()) { - target_imports.Add(CompileTimeImport::kDisableDenormalFloats); - } else { - target_imports.Remove(CompileTimeImport::kDisableDenormalFloats); - } - - // On denormals mismatch, we recompile the module with the correct - // flags. SyncCompile will check the cache first to avoid redundant work. - if (target_imports != native_module->compile_imports()) { - ErrorThrower thrower(isolate, "WasmEngine::ImportNativeModule"); - return SyncCompile( - isolate, native_module->enabled_features(), target_imports, &thrower, - base::OwnedCopyOf(native_module->wire_bytes()), source_url); - } ModuleWireBytes wire_bytes(native_module->wire_bytes()); DirectHandle<Script> script = GetOrCreateScript(isolate, shared_native_module, source_url); - native_module->LogWasmCodes(isolate, *script); + native_module->LogWasmCodes(isolate, script); DirectHandle<WasmModuleObject> module_object = WasmModuleObject::New(isolate, script); { @@ -1034,9 +1053,7 @@ MaybeDirectHandle<WasmModuleObject> WasmEngine::ImportNativeModule( isolate_info->native_modules.insert(native_module); DCHECK(native_modules_.contains(native_module)); native_modules_[native_module]->isolates.insert(isolate); - if (isolate_info->log_codes && !native_module->log_code()) { - EnableCodeLogging(native_module); - } + if (isolate_info->log_codes) native_module->EnableCodeLogging(); } // Finish the Wasm script now and make it public to the debugger. @@ -1097,7 +1114,7 @@ CodeTracer* WasmEngine::GetCodeTracer() { AsyncCompileJob* WasmEngine::CreateAsyncCompileJob( WasmEnabledFeatures enabled, CompileTimeImports compile_imports, - base::OwnedVector<const uint8_t> bytes, const char* api_method_name, + base::UniqueArray<const uint8_t> bytes, const char* api_method_name, std::shared_ptr<CompilationResultResolver> resolver, int compilation_id) { AsyncCompileJob* job = new AsyncCompileJob(enabled, std::move(compile_imports), std::move(bytes), @@ -1206,6 +1223,9 @@ void WasmEngine::AddIsolate(Isolate* isolate) { base::MutexGuard guard(&mutex_); DCHECK(!isolates_.contains(isolate)); isolates_.emplace(isolate, std::move(isolate_info)); + if (log_code) { + num_isolates_with_code_logging_.fetch_add(1, std::memory_order_relaxed); + } } // Record memory protection key support. @@ -1303,7 +1323,7 @@ void WasmEngine::RemoveIsolate(Isolate* isolate) { DCHECK(native_module_info->isolates.contains(isolate)); native_module_info->isolates.erase(isolate); if (native_module->log_code() && !has_isolate_with_code_logging()) { - DisableCodeLogging(native_module); + native_module->DisableCodeLogging(); } // Remove any debug code and other info for this isolate. @@ -1317,13 +1337,12 @@ void WasmEngine::RemoveIsolate(Isolate* isolate) { if (RemoveIsolateFromCurrentGC(isolate)) PotentiallyFinishCurrentGC(); } - // Clear the {code_to_log} vector. - for (auto& [script_id, code_to_log] : isolate_info->code_to_log) { - if (code_to_log.native_module == nullptr) { - // Wrapper code objects have neither Script nor NativeModule. - DCHECK_EQ(script_id, -1); - } else { - native_modules_with_code_to_log.insert(code_to_log.native_module); + // Clear the {code_to_log} map. + for (auto& [native_module, code_to_log] : isolate_info->code_to_log) { + DCHECK_EQ(native_module, code_to_log.native_module.get()); + if (code_to_log.native_module != nullptr) { + native_modules_with_code_to_log.insert( + std::move(code_to_log.native_module)); } for (WasmCode* code : code_to_log.code) { // Keep a reference in the {code_ref_scope_for_dead_code} such that the @@ -1335,6 +1354,11 @@ void WasmEngine::RemoveIsolate(Isolate* isolate) { isolate_info->code_to_log.clear(); // Finally remove the {IsolateInfo} for this isolate. + if (isolate_info->log_codes) { + DCHECK_LT(0, + num_isolates_with_code_logging_.load(std::memory_order_relaxed)); + num_isolates_with_code_logging_.fetch_sub(1, std::memory_order_relaxed); + } isolates_.erase(isolates_it); } @@ -1360,9 +1384,10 @@ void WasmEngine::LogCode(base::Vector<WasmCode*> code_vec) { if (info->log_codes == false) continue; auto script_it = info->scripts.find(native_module); - // If the script does not yet exist, logging will happen later. If the - // weak handle is cleared already, we also don't need to log any more. + // If the script does not yet exist, logging will happen later. If all + // weak handles are cleared already, we also don't need to log any more. if (script_it == info->scripts.end()) continue; + DCHECK(!script_it->second.empty()); // If there is no code scheduled to be logged already in that isolate, // then schedule a new task and also set an interrupt to log the newly @@ -1373,14 +1398,12 @@ void WasmEngine::LogCode(base::Vector<WasmCode*> code_vec) { std::make_unique<LogCodesTask>(isolate)); } - WeakScriptHandle& weak_script_handle = script_it->second; - auto& log_entry = info->code_to_log[weak_script_handle.script_id()]; + IsolateInfo::CodeToLogPerModule& log_entry = + info->code_to_log[native_module]; if (!log_entry.native_module) { log_entry.native_module = shared_native_module; } - if (!log_entry.source_url) { - log_entry.source_url = weak_script_handle.source_url(); - } + DCHECK_EQ(log_entry.native_module, shared_native_module); log_entry.code.insert(log_entry.code.end(), code_vec.begin(), code_vec.end()); @@ -1400,7 +1423,7 @@ bool WasmEngine::LogWrapperCode(WasmCode* code) { // Wrappers don't belong to any particular NativeModule. DCHECK_NULL(code->native_module()); // Fast path: - if (!num_modules_with_code_logging_.load(std::memory_order_relaxed)) { + if (!num_isolates_with_code_logging_.load(std::memory_order_relaxed)) { return false; } @@ -1424,8 +1447,8 @@ bool WasmEngine::LogWrapperCode(WasmCode* code) { std::make_unique<LogCodesTask>(isolate)); } - constexpr int kNoScriptId = -1; - auto& log_entry = info->code_to_log[kNoScriptId]; + // Pass nullptr as NativeModule* for wrapper code. + IsolateInfo::CodeToLogPerModule& log_entry = info->code_to_log[nullptr]; log_entry.code.push_back(code); // Increment the reference count for the added {log_entry.code} entry. @@ -1433,7 +1456,7 @@ bool WasmEngine::LogWrapperCode(WasmCode* code) { // that manages updating the refcount for the WasmCode it holds. code->IncRef(); } - DCHECK_EQ(did_trigger_code_logging, num_modules_with_code_logging_.load( + DCHECK_EQ(did_trigger_code_logging, num_isolates_with_code_logging_.load( std::memory_order_relaxed) > 0); } for (auto& [runner, task] : to_schedule) { @@ -1450,47 +1473,19 @@ void WasmEngine::EnableCodeLogging(Isolate* isolate) { IsolateInfo* info = it->second.get(); if (info->log_codes) return; info->log_codes = true; + num_isolates_with_code_logging_.fetch_add(1, std::memory_order_relaxed); // Also set {NativeModule::log_code_} for all native modules currently used by // this isolate. for (NativeModule* native_module : info->native_modules) { - if (!native_module->log_code()) EnableCodeLogging(native_module); + native_module->EnableCodeLogging(); } } -void WasmEngine::EnableCodeLogging(NativeModule* native_module) { - // The caller should hold the mutex. - mutex_.AssertHeld(); - DCHECK(!native_module->log_code()); - native_module->EnableCodeLogging(); - num_modules_with_code_logging_.fetch_add(1, std::memory_order_relaxed); - // Check the accuracy of {num_modules_with_code_logging_}. - DCHECK_EQ( - num_modules_with_code_logging_.load(std::memory_order_relaxed), - std::count_if( - native_modules_.begin(), native_modules_.end(), - [](std::pair<NativeModule* const, std::unique_ptr<NativeModuleInfo>>& - pair) { return pair.first->log_code(); })); -} - -void WasmEngine::DisableCodeLogging(NativeModule* native_module) { - // The caller should hold the mutex. - mutex_.AssertHeld(); - DCHECK(native_module->log_code()); - native_module->DisableCodeLogging(); - num_modules_with_code_logging_.fetch_sub(1, std::memory_order_relaxed); - // Check the accuracy of {num_modules_with_code_logging_}. - DCHECK_EQ( - num_modules_with_code_logging_.load(std::memory_order_relaxed), - std::count_if( - native_modules_.begin(), native_modules_.end(), - [](std::pair<NativeModule* const, std::unique_ptr<NativeModuleInfo>>& - pair) { return pair.first->log_code(); })); -} - void WasmEngine::LogOutstandingCodesForIsolate(Isolate* isolate) { // Under the mutex, get the vector of wasm code to log. Then log and decrement // the ref count without holding the mutex. - std::unordered_map<int, IsolateInfo::CodeToLogPerScript> code_to_log_map; + std::unordered_map<NativeModule*, IsolateInfo::CodeToLogPerModule> + code_to_log_map; { base::MutexGuard guard(&mutex_); DCHECK(isolates_.contains(isolate)); @@ -1501,13 +1496,34 @@ void WasmEngine::LogOutstandingCodesForIsolate(Isolate* isolate) { bool should_log = WasmCode::ShouldBeLogged(isolate); TRACE_EVENT("v8.wasm", "wasm.LogCode"); - for (auto& [script_id, code_to_log] : code_to_log_map) { + for (auto& [native_module, code_to_log] : code_to_log_map) { + DCHECK_EQ(native_module, code_to_log.native_module.get()); if (should_log) { - for (WasmCode* code : code_to_log.code) { - const char* source_url = code_to_log.source_url.get(); - // The source URL can be empty for eval()'ed scripts. - if (!source_url) source_url = ""; - code->LogCode(isolate, source_url, script_id); + if (native_module == nullptr) { + for (WasmCode* code : code_to_log.code) { + code->LogCode(isolate, "", -1); + } + } else { + struct ScriptData { + int script_id; + std::shared_ptr<const char[]> source_url; + }; + base::SmallVector<ScriptData, 2> scripts; + { + base::MutexGuard guard(&mutex_); + auto& isolate_scripts = isolates_[isolate]->scripts; + auto scripts_it = isolate_scripts.find(native_module); + if (scripts_it != isolate_scripts.end()) { + for (const WeakScriptHandle& handle : scripts_it->second) { + scripts.push_back({handle.script_id(), handle.source_url()}); + } + } + } + for (WasmCode* code : code_to_log.code) { + for (const ScriptData& script : scripts) { + code->LogCode(isolate, script.source_url.get(), script.script_id); + } + } } } WasmCode::DecrementRefCount(base::VectorOf(code_to_log.code)); @@ -1577,8 +1593,8 @@ void WasmEngine::UseNativeModuleInIsolate(NativeModule* native_module, remove_all_code = true; native_module->SetDebugState(kDebugging); } - if (isolate_info->log_codes && !native_module->log_code()) { - EnableCodeLogging(native_module); + if (isolate_info->log_codes) { + native_module->EnableCodeLogging(); } isolate->counters()->wasm_modules_per_isolate()->AddSample( static_cast<int>(isolate_info->native_modules.size())); @@ -1675,15 +1691,9 @@ void WasmEngine::FreeNativeModule(NativeModule* native_module) { // CppGCManaged<wasm::NativeModule> object is no longer referenced). GetWasmCodeManager()->FlushCodeLookupCache(isolate); - // {CodeToLogPerScript} keeps the NativeModule alive, so if it dies, there + // {CodeToLogPerModule} keeps the NativeModule alive, so if it dies, there // can not be any outstanding code to be logged. -#ifdef DEBUG - for (auto& log_entry : info->code_to_log) { - for (WasmCode* code : log_entry.second.code) { - DCHECK_NE(native_module, code->native_module()); - } - } -#endif + DCHECK(!info->code_to_log.contains(native_module)); } // If there is a GC running which has references to code contained in the // deleted {NativeModule}, remove those references. @@ -1704,8 +1714,6 @@ void WasmEngine::FreeNativeModule(NativeModule* native_module) { // references belonging to the NativeModule that's being deleted. std::erase_if(potentially_dead_code_, part_of_native_module); - if (native_module->log_code()) DisableCodeLogging(native_module); - native_module_cache_.Erase(native_module); native_modules_.erase(module); } @@ -1886,29 +1894,48 @@ void WasmEngine::FreeDeadCodeLocked( DirectHandle<Script> WasmEngine::GetOrCreateScript( Isolate* isolate, const std::shared_ptr<NativeModule>& native_module, - base::Vector<const char> source_url) { + std::string_view source_url) { { base::MutexGuard guard(&mutex_); DCHECK(isolates_.contains(isolate)); auto& scripts = isolates_[isolate]->scripts; auto it = scripts.find(native_module.get()); if (it != scripts.end()) { - DirectHandle<Script> weak_global_handle = it->second.handle(); - if (weak_global_handle.is_null()) { + std::vector<WeakScriptHandle>& handles = it->second; + DCHECK(!handles.empty()); + DirectHandle<Script> matching_script; + // Remove weak handles for scripts that have been garbage-collected in the + // meantime, and in the same pass find a live script with a matching + // source URL. + std::erase_if(handles, [&](const WeakScriptHandle& handle) { + DirectHandle<Script> weak_global_handle = handle.handle(); + if (weak_global_handle.is_null()) return true; + if (matching_script.is_null() && handle.MatchesSourceUrl(source_url)) { + matching_script = + DirectHandle<Script>::New(*weak_global_handle, isolate); + } + return false; + }); + if (!matching_script.is_null()) return matching_script; + if (handles.empty()) { scripts.erase(it); - } else { - return DirectHandle<Script>::New(*weak_global_handle, isolate); } } } // Temporarily release the mutex to let the GC collect native modules. - auto script = CreateWasmScript(isolate, native_module, source_url); + DirectHandle<Script> script = + CreateWasmScript(isolate, native_module, source_url); { base::MutexGuard guard(&mutex_); DCHECK(isolates_.contains(isolate)); - auto& scripts = isolates_[isolate]->scripts; - DCHECK(!scripts.contains(native_module.get())); - scripts.emplace(native_module.get(), WeakScriptHandle(script, isolate)); + std::vector<WeakScriptHandle>& handles = + isolates_[isolate]->scripts[native_module.get()]; + DCHECK(std::none_of(handles.begin(), handles.end(), + [source_url](const WeakScriptHandle& handle) { + return !handle.handle().is_null() && + handle.MatchesSourceUrl(source_url); + })); + handles.emplace_back(script, isolate); return script; } } @@ -2036,6 +2063,10 @@ size_t WasmEngine::EstimateCurrentMemoryConsumption() const { for (const auto& [isolate, isolate_info] : isolates_) { result += ContentSize(isolate_info->native_modules); result += ContentSize(isolate_info->scripts); + for (const auto& [native_module, script_handles] : + isolate_info->scripts) { + result += ContentSize(script_handles); + } result += ContentSize(isolate_info->code_to_log); } diff --git a/deps/v8/src/wasm/wasm-engine.h b/deps/v8/src/wasm/wasm-engine.h index 89e9135a92c1..4c907d443af0 100644 --- a/deps/v8/src/wasm/wasm-engine.h +++ b/deps/v8/src/wasm/wasm-engine.h @@ -13,11 +13,13 @@ #include <map> #include <memory> #include <optional> +#include <string_view> #include <unordered_map> #include <unordered_set> #include "src/base/platform/condition-variable.h" #include "src/base/platform/mutex.h" +#include "src/base/unique-array.h" #include "src/compiler/wasm-call-descriptors.h" #include "src/tasks/operations-barrier.h" #include "src/wasm/canonical-types.h" @@ -193,10 +195,10 @@ class V8_EXPORT_PRIVATE WasmEngine { MaybeDirectHandle<WasmModuleObject> SyncCompile( Isolate* isolate, WasmEnabledFeatures enabled, CompileTimeImports compile_imports, ErrorThrower* thrower, - base::OwnedVector<const uint8_t> bytes, + base::UniqueArray<const uint8_t> bytes, // Optional source URL; needed when recompiling on flags mismatch // to preserve the original URL. - base::Vector<const char> source_url = {}); + std::string_view source_url = {}); // Synchronously instantiate the given Wasm module with the given imports. MaybeDirectHandle<WasmInstanceObject> SyncInstantiate( @@ -209,7 +211,7 @@ class V8_EXPORT_PRIVATE WasmEngine { void AsyncCompile(Isolate* isolate, WasmEnabledFeatures enabled, CompileTimeImports compile_imports, std::shared_ptr<CompilationResultResolver> resolver, - base::OwnedVector<const uint8_t> bytes, + base::UniqueArray<const uint8_t> bytes, const char* api_method_name_for_errors); // Begin an asynchronous instantiation of the given Wasm module. @@ -235,9 +237,9 @@ class V8_EXPORT_PRIVATE WasmEngine { // Imports the shared part of a module from a different Context/Isolate, // recreating a full module object in the given Isolate. - MaybeDirectHandle<WasmModuleObject> ImportNativeModule( + DirectHandle<WasmModuleObject> ImportNativeModule( Isolate* isolate, std::shared_ptr<NativeModule> shared_module, - base::Vector<const char> source_url); + std::string_view source_url); // Flushes all Liftoff code in all NativeModules. void FlushLiftoffCode(); @@ -401,7 +403,7 @@ class V8_EXPORT_PRIVATE WasmEngine { DirectHandle<Script> GetOrCreateScript(Isolate*, const std::shared_ptr<NativeModule>&, - base::Vector<const char> source_url); + std::string_view source_url); // Returns a barrier allowing background compile operations if valid and // preventing this object from being destroyed. @@ -460,7 +462,7 @@ class V8_EXPORT_PRIVATE WasmEngine { AsyncCompileJob* CreateAsyncCompileJob( WasmEnabledFeatures enabled, CompileTimeImports compile_imports, - base::OwnedVector<const uint8_t> bytes, const char* api_method_name, + base::UniqueArray<const uint8_t> bytes, const char* api_method_name, std::shared_ptr<CompilationResultResolver> resolver, int compilation_id); void TriggerCodeGC_Locked(size_t dead_code_limit); @@ -475,11 +477,6 @@ class V8_EXPORT_PRIVATE WasmEngine { // calling this method. void PotentiallyFinishCurrentGC(); - // Enable/disable code logging on the NativeModule, updating - // {num_modules_with_code_logging_} accordingly. - void EnableCodeLogging(NativeModule*); - void DisableCodeLogging(NativeModule*); - // Remember in a global flag whether we saw nondeterminism during execution. // This is used in differential fuzzing. // Some runtime functions will update this flag, e.g. when growing memory @@ -529,10 +526,9 @@ class V8_EXPORT_PRIVATE WasmEngine { std::shared_ptr<OperationsBarrier> operations_barrier_{ std::make_shared<OperationsBarrier>()}; - // Store the number of modules which have code logging enabled. This is then - // used for a fast-path to avoid taking the mutex and iterating Isolates or - // NativeModules. - std::atomic<size_t> num_modules_with_code_logging_{0}; + // Store the number of isolates which have code logging enabled. This is then + // used for a fast-path to avoid taking the mutex and iterating Isolates. + std::atomic<size_t> num_isolates_with_code_logging_{0}; // Size of code that became dead since the last GC. If this exceeds a certain // threshold, a new GC is triggered. diff --git a/deps/v8/src/wasm/wasm-export-wrapper-cache.h b/deps/v8/src/wasm/wasm-export-wrapper-cache.h index 90c5622c940c..886cc667ea2e 100644 --- a/deps/v8/src/wasm/wasm-export-wrapper-cache.h +++ b/deps/v8/src/wasm/wasm-export-wrapper-cache.h @@ -39,7 +39,8 @@ class WasmExportWrapperCache : public AllStatic { static void Verify(Heap* heap); #endif // VERIFY_HEAP - // Defined in cctest/test-run-wasm-wrappers.cc to not bloat shipping binaries. + // Defined in test/unittests/wasm/run-wasm-wrappers-unittest.cc to not bloat + // shipping binaries. static int CountWrappersForTesting(Isolate* isolate); private: diff --git a/deps/v8/src/wasm/wasm-external-refs.cc b/deps/v8/src/wasm/wasm-external-refs.cc index abc56d404638..b304f84a5316 100644 --- a/deps/v8/src/wasm/wasm-external-refs.cc +++ b/deps/v8/src/wasm/wasm-external-refs.cc @@ -16,6 +16,7 @@ #include "src/base/ieee754.h" #include "src/base/numerics/safe_conversions.h" #include "src/base/sanitizer/tsan.h" +#include "src/builtins/builtins-inl.h" #include "src/common/assert-scope.h" #include "src/execution/frames-inl.h" #include "src/execution/frames.h" @@ -493,15 +494,13 @@ void f32x4_nearest_int_wrapper(Address data) { simd_float_round_wrapper<float, &nearbyintf>(data); } -Float16 f16_abs(Float16 a) { - return Float16::FromFloat32(std::abs(a.ToFloat32())); -} +Float16 f16_abs(Float16 a) { return Float16::FromBits(a.get_bits() & 0x7fff); } void f16x8_abs_wrapper(Address data) { simd_float_round_wrapper<Float16, &f16_abs>(data); } -Float16 f16_neg(Float16 a) { return Float16::FromFloat32(-(a.ToFloat32())); } +Float16 f16_neg(Float16 a) { return Float16::FromBits(a.get_bits() ^ 0x8000); } void f16x8_neg_wrapper(Address data) { simd_float_round_wrapper<Float16, &f16_neg>(data); @@ -870,14 +869,10 @@ int32_t memory_fill_wrapper(Address trusted_data_addr, uint32_t mem_index, } namespace { -inline void* ArrayElementAddress(Address array, uint32_t index, - int element_size_bytes) { - return reinterpret_cast<void*>(array + WasmArray::kHeaderSize - - kHeapObjectTag + index * element_size_bytes); -} inline void* ArrayElementAddress(Tagged<WasmArray> array, uint32_t index, int element_size_bytes) { - return ArrayElementAddress(array.ptr(), index, element_size_bytes); + return reinterpret_cast<void*>(array.ptr() + array->header_size() - + kHeapObjectTag + index * element_size_bytes); } } // namespace @@ -925,9 +920,10 @@ DISABLE_TSAN void array_fill_wrapper(Address raw_array, uint32_t index, uint32_t raw_type, Address initial_value_addr) { DisallowGarbageCollection no_gc; + Tagged<WasmArray> array = Cast<WasmArray>(Tagged<Object>(raw_array)); ValueType type = ValueType::FromRawBitField(raw_type); int8_t* initial_element_address = reinterpret_cast<int8_t*>( - ArrayElementAddress(raw_array, index, type.value_kind_size())); + ArrayElementAddress(array, index, type.value_kind_size())); const int bytes_to_set = length * type.value_kind_size(); // We implement the general case by setting the first 8 bytes manually, then @@ -1027,7 +1023,6 @@ DISABLE_TSAN void array_fill_wrapper(Address raw_array, uint32_t index, if (emit_write_barrier) { DCHECK(type.is_ref()); - Tagged<WasmArray> array = Cast<WasmArray>(Tagged<Object>(raw_array)); Isolate* isolate = Isolate::Current(); ObjectSlot start(reinterpret_cast<Address>(initial_element_address)); ObjectSlot end( @@ -1094,6 +1089,7 @@ void start_stack(Isolate* isolate, wasm::StackMemory* to, Address sp, if (v8_flags.trace_wasm_stack_switching) { PrintF("Switch from stack %d to %d (start)\n", from->id(), to->id()); } + isolate->isolate_data()->active_suspender()->set_stack(nullptr); ResumeStack(isolate, from, to, sp, fp, pc); } @@ -1123,7 +1119,9 @@ void suspend_stack(Isolate* isolate, wasm::StackMemory* to, Address sp, Address fp, Address pc) { wasm::StackMemory* from = isolate->isolate_data()->active_stack(); auto suspender = isolate->isolate_data()->active_suspender(); - suspender->set_stack(isolate, from); + DCHECK_NULL(suspender->stack()); + suspender->set_stack(from); + suspender->parent()->set_stack(nullptr); suspender->clear_parent(); if (v8_flags.trace_wasm_stack_switching) { PrintF("Switch from stack %d to %d (suspend)\n", from->id(), to->id()); @@ -1137,8 +1135,11 @@ void resume_jspi_stack(Isolate* isolate, wasm::StackMemory* to, Address sp, auto suspender = TrustedCast<WasmSuspenderObject>(suspender_obj); Tagged<WasmSuspenderObject> active_suspender = isolate->isolate_data()->active_suspender(); - suspender->set_parent(active_suspender); wasm::StackMemory* from = isolate->isolate_data()->active_stack(); + DCHECK_NULL(active_suspender->stack()); + active_suspender->set_stack(from); + suspender->set_parent(active_suspender); + suspender->set_stack(nullptr); if (v8_flags.trace_wasm_stack_switching) { PrintF("Switch from stack %d to %d (resume)\n", from->id(), to->id()); } @@ -1166,7 +1167,7 @@ wasm::StackMemory* find_wasmfx_handler_stack(Isolate* isolate, Address& target_pc, CanonicalTypeIndex* sig) { Tagged<Object> tag_obj(wanted_tag_raw); - auto wanted_tag = TrustedCast<WasmExceptionTag>(tag_obj); + auto wanted_tag = Cast<WasmExceptionTag>(tag_obj); wasm::StackMemory* from = isolate->isolate_data()->active_stack(); wasm::StackMemory* to = from->jmpbuf()->parent; // Search the innermost effect handler with a matching tag. @@ -1186,9 +1187,7 @@ wasm::StackMemory* find_wasmfx_handler_stack(Isolate* isolate, break; } - // The caller frame is the WASM frame that contains the handler table, or - // a WASM_SEGMENT_START frame if this happens to be the first frame of a new - // growable stack segment. + // The caller frame is the WASM frame that contains the handler table. target_pc = StackFrame::ReadPC(reinterpret_cast<Address*>( target_fp + CommonFrameConstants::kCallerPCOffset)); target_sp = target_fp + CommonFrameConstants::kCallerSPOffset; @@ -1196,7 +1195,7 @@ wasm::StackMemory* find_wasmfx_handler_stack(Isolate* isolate, CommonFrameConstants::kCallerFPOffset); type = StackFrame::MarkerToType(base::Memory<intptr_t>( target_fp + CommonFrameConstants::kContextOrFrameTypeOffset)); - CHECK(type == StackFrame::WASM || type == StackFrame::WASM_SEGMENT_START); + CHECK_EQ(type, StackFrame::WASM); // Get the handler table and search for a matching tag. WasmCode* wasm_code = to->wasm_code(); @@ -1340,8 +1339,8 @@ void return_stack(Isolate* isolate, wasm::StackMemory* to) { void return_jspi_stack(Isolate* isolate, wasm::StackMemory* to) { Tagged<WasmSuspenderObject> suspender = isolate->isolate_data()->active_suspender(); - // Clear the external stack pointer to avoid a UAF. - suspender->set_stack(isolate, nullptr); + DCHECK_NULL(suspender->stack()); + suspender->parent()->set_stack(nullptr); return_stack(isolate, to); } @@ -1441,9 +1440,10 @@ void switch_from_the_central_stack_for_js(Isolate* isolate) { #endif } -// frame_size includes param slots area and extra frame slots above FP. +// frame_size includes param slots area, return values and frame size. Address grow_stack(Isolate* isolate, void* current_sp, size_t frame_size, - size_t gap, Address current_fp) { + size_t gap, Address current_fp, + size_t parameter_slots_size) { if (isolate->IsOnCentralStack()) { // Should not grow the central stack. return 0; @@ -1456,28 +1456,49 @@ Address grow_stack(Isolate* isolate, void* current_sp, size_t frame_size, // Grow by at least the new frame size plus the stack limit margin. size_t min = gap + frame_size + StackMemory::JSGrowableStackLimitMarginKB() * KB; - if (!active_stack->Grow(current_fp, min)) { + Address relocated_fp = current_fp + parameter_slots_size; + if (!active_stack->Grow(relocated_fp, min)) { return 0; } Address new_sp = active_stack->base() - frame_size; + size_t sp_to_fp = current_fp - reinterpret_cast<Address>(current_sp); + size_t copy_size = sp_to_fp + CommonFrameConstants::kFixedFrameSizeAboveFp + + parameter_slots_size; // Here we assume stack values don't refer other moved stack slots. // A stack grow event happens right in the beginning of the function // call so moved slots contain only incoming params and frame header. // So, it is reasonable to assume no self references. - std::memcpy(reinterpret_cast<void*>(new_sp), current_sp, frame_size); + std::memcpy(reinterpret_cast<void*>(new_sp), current_sp, copy_size); -#if V8_TARGET_ARCH_ARM64 - Address new_fp = - new_sp + (current_fp - reinterpret_cast<Address>(current_sp)); - Address old_pc_address = current_fp + CommonFrameConstants::kCallerPCOffset; + Address new_fp = new_sp + sp_to_fp; Address new_pc_address = new_fp + CommonFrameConstants::kCallerPCOffset; - Address old_signed_pc = base::Memory<Address>(old_pc_address); - Address new_signed_pc = PointerAuthentication::MoveSignedPC( - isolate, old_signed_pc, new_pc_address + kSystemPointerSize, - old_pc_address + kSystemPointerSize); - WriteUnalignedValue<Address>(new_pc_address, new_signed_pc); -#endif + Address trampoline_entry = + Builtins::EntryOf(Builtin::kWasmReturnFromSegment, isolate); + Address signed_trampoline = PointerAuthentication::SignAndCheckPC( + isolate, trampoline_entry, new_pc_address + kSystemPointerSize); + WriteUnalignedValue<Address>(new_pc_address, signed_trampoline); + + // Relocate the partial frame linkage on the parent stack to just below the + // return slots. This facilitates the return from the stack shrinking + // trampoline: it can assume that the only thing it has to manage is the + // region allocated for return slots. The original parameters were copied to + // the new stack segment during this stack growth. + if (parameter_slots_size > 0) { + Address old_pc_address = + current_fp + CommonFrameConstants::kCallerPCOffset; + Address new_parent_pc_address = + relocated_fp + CommonFrameConstants::kCallerPCOffset; + Address caller_pc = *reinterpret_cast<Address*>(old_pc_address); + Address caller_fp = *reinterpret_cast<Address*>( + current_fp + CommonFrameConstants::kCallerFPOffset); + Address signed_caller_pc = PointerAuthentication::MoveSignedPC( + isolate, caller_pc, new_parent_pc_address + kSystemPointerSize, + old_pc_address + kSystemPointerSize); + WriteUnalignedValue<Address>(new_parent_pc_address, signed_caller_pc); + WriteUnalignedValue<Address>( + relocated_fp + CommonFrameConstants::kCallerFPOffset, caller_fp); + } isolate->stack_guard()->SetStackLimitForStackSwitching( reinterpret_cast<uintptr_t>(active_stack->jslimit())); @@ -1486,29 +1507,31 @@ Address grow_stack(Isolate* isolate, void* current_sp, size_t frame_size, return 0; } - -Address shrink_stack(Isolate* isolate) { - // If there is no parent, then the current stack is the main isolate stack. +// Drop top-most segment in the stack. +Address shrink_stack(Isolate* isolate, void* current_sp) { + CHECK(!isolate->IsOnCentralStack()); wasm::StackMemory* active_stack = isolate->isolate_data()->active_stack(); - if (active_stack->jmpbuf()->parent == nullptr) { - return 0; - } + CHECK_NE(active_stack->parent_frame_fp(), 0); DCHECK(active_stack->IsActive()); - Address old_fp = active_stack->Shrink(); + Address current_sp_addr = reinterpret_cast<Address>(current_sp); + Address active_segment_base = active_stack->base(); + DCHECK_GE(active_segment_base, current_sp_addr); + size_t slots_size = active_segment_base - current_sp_addr; + + // The parent_frame is the partially constructed frame in the parent segment + // that originated the stack growth, relocated to just below the return slots. + Address parent_frame_fp = active_stack->Shrink(); + + // Return slots on the parent stack are at a fixed offset above + // parent_frame_fp. + Address dest = parent_frame_fp + CommonFrameConstants::kFixedFrameSizeAboveFp; + if (slots_size > 0) { + std::memcpy(reinterpret_cast<void*>(dest), current_sp, slots_size); + } isolate->stack_guard()->SetStackLimitForStackSwitching( reinterpret_cast<uintptr_t>(active_stack->jslimit())); - return old_fp; -} - -Address load_old_fp(Isolate* isolate) { - // If there is no parent, then the current stack is the main isolate stack. - wasm::StackMemory* active_stack = isolate->isolate_data()->active_stack(); - if (active_stack->jmpbuf()->parent == nullptr) { - return 0; - } - DCHECK_EQ(active_stack->jmpbuf()->state, wasm::JumpBuffer::Active); - return active_stack->old_fp(); + return parent_frame_fp; } } // namespace v8::internal::wasm diff --git a/deps/v8/src/wasm/wasm-external-refs.h b/deps/v8/src/wasm/wasm-external-refs.h index 05fb79b9029d..67df37aaaea0 100644 --- a/deps/v8/src/wasm/wasm-external-refs.h +++ b/deps/v8/src/wasm/wasm-external-refs.h @@ -232,9 +232,8 @@ void switch_from_the_central_stack(Isolate* isolate); intptr_t switch_to_the_central_stack_for_js(Isolate* isolate, Address fp); void switch_from_the_central_stack_for_js(Isolate* isolate); Address grow_stack(Isolate* isolate, void* current_sp, size_t frame_size, - size_t gap, Address current_fp); -Address shrink_stack(Isolate* isolate); -Address load_old_fp(Isolate* isolate); + size_t gap, Address current_fp, size_t parameter_slots_size); +Address shrink_stack(Isolate* isolate, void* current_sp); } // namespace wasm } // namespace internal diff --git a/deps/v8/src/wasm/wasm-features.h b/deps/v8/src/wasm/wasm-features.h index d140b794a12e..99c890f98437 100644 --- a/deps/v8/src/wasm/wasm-features.h +++ b/deps/v8/src/wasm/wasm-features.h @@ -11,10 +11,10 @@ #include <compare> #include <iosfwd> +#include <span> #include <string> #include "src/base/logging.h" -#include "src/base/small-vector.h" #include "src/common/globals.h" // The feature flags are declared in their own header. #include "src/flags/feature-flags.h" @@ -164,8 +164,6 @@ enum class CompileTimeImport { kTextEncoder, kTextDecoder, kJsPrototypes, - // Not really an import, but needs the same handling as compile-time imports. - kDisableDenormalFloats, }; inline std::ostream& operator<<(std::ostream& os, CompileTimeImport imp) { @@ -195,7 +193,7 @@ class CompileTimeImports { } bool empty() const { return bits_.empty(); } - bool has_string_constants(base::Vector<const uint8_t> name) const { + bool has_string_constants(std::span<const uint8_t> name) const { return bits_.contains(CompileTimeImport::kStringConstants) && constants_module_.size() == name.size() && std::equal(name.begin(), name.end(), constants_module_.begin()); @@ -205,7 +203,6 @@ class CompileTimeImports { auto operator<=>(const CompileTimeImports& other) const = default; void Add(CompileTimeImport imp) { bits_.Add(imp); } - void Remove(CompileTimeImport imp) { bits_.Remove(imp); } std::string& constants_module() { return constants_module_; } const std::string& constants_module() const { return constants_module_; } diff --git a/deps/v8/src/wasm/wasm-js.cc b/deps/v8/src/wasm/wasm-js.cc index efffb941cc5e..d19ad0a51868 100644 --- a/deps/v8/src/wasm/wasm-js.cc +++ b/deps/v8/src/wasm/wasm-js.cc @@ -14,8 +14,8 @@ #include "include/v8-wasm.h" #include "src/api/api-inl.h" #include "src/api/api-natives.h" -#include "src/base/fpu.h" #include "src/base/logging.h" +#include "src/base/unique-array.h" #include "src/execution/execution.h" #include "src/execution/isolate.h" #include "src/execution/messages.h" @@ -110,7 +110,7 @@ class WasmStreaming::WasmStreamingImpl { streaming_decoder_->SetHasCompiledModuleBytes(); } - void SetUrl(base::Vector<const char> url) { streaming_decoder_->SetUrl(url); } + void SetUrl(std::string_view url) { streaming_decoder_->SetUrl(url); } private: i::Isolate* const i_isolate_; @@ -160,7 +160,7 @@ void WasmStreaming::SetMoreFunctionsCanBeSerializedCallback( void WasmStreaming::SetUrl(const char* url, size_t length) { DCHECK_EQ('\0', url[length]); // {url} is null-terminated. TRACE_EVENT("v8.wasm", "wasm.SetUrl", "url", url); - impl_->SetUrl(base::VectorOf(url, length)); + impl_->SetUrl(std::string_view(url, length)); } // static @@ -213,7 +213,7 @@ class WasmModuleCompilation::Impl { streaming_decoder_->SetHasCompiledModuleBytes(); } - void SetUrl(base::Vector<const char> url) { streaming_decoder_->SetUrl(url); } + void SetUrl(std::string_view url) { streaming_decoder_->SetUrl(url); } private: class Resolver final : public i::wasm::CompilationResultResolver { @@ -246,8 +246,7 @@ WasmModuleCompilation::WasmModuleCompilation(const CompileOptions& options) i::wasm::CompileTimeImportsFromOptions(options))) { TRACE_EVENT("v8.wasm", "wasm.ModuleCompilation"); if (!options.source_url.empty()) { - impl_->SetUrl( - base::VectorOf(options.source_url.data(), options.source_url.size())); + impl_->SetUrl(options.source_url); } } @@ -283,7 +282,7 @@ void WasmModuleCompilation::SetMoreFunctionsCanBeSerializedCallback( void WasmModuleCompilation::SetUrl(const char* url, size_t length) { DCHECK_EQ('\0', url[length]); // {url} is null-terminated. TRACE_EVENT("v8.wasm", "wasm.SetUrl", "url", url); - impl_->SetUrl(base::VectorOf(url, length)); + impl_->SetUrl(std::string_view(url, length)); } namespace { @@ -312,7 +311,7 @@ GET_FIRST_ARGUMENT_AS(Tag) #undef GET_FIRST_ARGUMENT_AS -base::OwnedVector<const uint8_t> GetAndCopyFirstArgumentAsBytes( +base::UniqueArray<const uint8_t> GetAndCopyFirstArgumentAsBytes( const v8::FunctionCallbackInfo<v8::Value>& info, size_t max_length, ErrorThrower* thrower) { const uint8_t* start = nullptr; @@ -328,9 +327,9 @@ base::OwnedVector<const uint8_t> GetAndCopyFirstArgumentAsBytes( } else if (source->IsTypedArray()) { // A TypedArray was passed. Local<TypedArray> array = Local<TypedArray>::Cast(source); - Local<ArrayBuffer> buffer = array->Buffer(); + Local<ArrayBufferBase> buffer = array->GetBuffer(); - auto backing_store = buffer->GetBackingStore(); + std::shared_ptr<v8::BackingStore> backing_store = buffer->GetBackingStore(); start = reinterpret_cast<const uint8_t*>(backing_store->Data()) + array->ByteOffset(); @@ -354,7 +353,7 @@ base::OwnedVector<const uint8_t> GetAndCopyFirstArgumentAsBytes( // Use relaxed reads (and writes, which is unnecessary here) to avoid TSan // reports in case the buffer is shared and is being modified concurrently. - auto result = base::OwnedVector<uint8_t>::NewForOverwrite(length); + auto result = base::UniqueArray<uint8_t>::NewForOverwrite(length); base::Relaxed_Memcpy(reinterpret_cast<base::Atomic8*>(result.begin()), reinterpret_cast<const base::Atomic8*>(start), length); return result; @@ -756,7 +755,7 @@ void WebAssemblyCompileImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { return; } - base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( + base::UniqueArray<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( info, i::wasm::max_module_size(), &thrower); if (bytes.empty()) { resolver->OnCompilationFailed(thrower.Reify()); @@ -790,7 +789,7 @@ void WasmStreamingCallbackForTesting( // We don't check the buffer length up front, to allow d8 to test that the // streaming decoder implementation handles overly large inputs correctly. size_t unlimited = std::numeric_limits<size_t>::max(); - base::OwnedVector<const uint8_t> bytes = + base::UniqueArray<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes(info, unlimited, &thrower); if (bytes.empty()) { streaming->Abort(Utils::ToLocal(thrower.Reify())); @@ -918,7 +917,7 @@ void WebAssemblyValidateImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { // Always copy. Even if the buffer isn't shared, // {WasmJs::CompileTimeImportsFromArgument} could detach it. - base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( + base::UniqueArray<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( info, i::wasm::max_module_size(), &thrower); if (bytes.empty()) { js_api_scope.AssertException(); @@ -942,8 +941,7 @@ void WebAssemblyValidateImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { } bool validated = i::wasm::GetWasmEngine()->SyncValidate( - i_isolate, enabled_features, std::move(compile_imports), - bytes.as_vector()); + i_isolate, enabled_features, std::move(compile_imports), bytes.as_span()); return_value.Set(validated); } @@ -972,7 +970,13 @@ bool TransferPrototype(i::Isolate* isolate, void WebAssemblyModuleImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { WasmJSApiScope js_api_scope{info, "WebAssembly.Module()"}; auto [isolate, i_isolate, thrower] = js_api_scope.isolates_and_thrower(); - if (i_isolate->wasm_module_callback()(info)) return; + if (WasmModuleCallback callback = i_isolate->wasm_module_callback()) { + if (callback(isolate, info[0])) return; + } + if (ExtensionCallback callback = + i_isolate->deprecated_wasm_module_callback()) { + if (callback(info)) return; + } RecordCompilationMethod(i_isolate, kSyncCompilation); if (!info.IsConstructCall()) { @@ -988,7 +992,7 @@ void WebAssemblyModuleImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { return; } - base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( + base::UniqueArray<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( info, i::wasm::max_module_size(), &thrower); if (bytes.empty()) return js_api_scope.AssertException(); @@ -1089,7 +1093,13 @@ void WebAssemblyInstanceImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { i_isolate->CountUsage( v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation); - if (i_isolate->wasm_instance_callback()(info)) return; + if (WasmInstanceCallback callback = i_isolate->wasm_instance_callback()) { + if (callback(isolate, info[0])) return; + } + if (ExtensionCallback callback = + i_isolate->deprecated_wasm_instance_callback()) { + if (callback(info)) return; + } i::DirectHandle<i::JSObject> instance_obj; { @@ -1242,7 +1252,7 @@ void WebAssemblyInstantiateImpl( return; } - base::OwnedVector<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( + base::UniqueArray<const uint8_t> bytes = GetAndCopyFirstArgumentAsBytes( info, i::wasm::max_module_size(), &thrower); if (bytes.empty()) { InstantiateModuleResultResolver::FailInstantiation( @@ -1498,8 +1508,8 @@ std::optional<AddressType> GetAddressType(Isolate* isolate, return std::nullopt; } - if (address->IsEqualTo(base::CStrVector("i64"))) return AddressType::kI64; - if (address->IsEqualTo(base::CStrVector("i32"))) return AddressType::kI32; + if (address->IsEqualTo("i64")) return AddressType::kI64; + if (address->IsEqualTo("i32")) return AddressType::kI32; thrower->TypeError("Unknown address type '%s'; pass 'i32' or 'i64'", address->ToCString().get()); @@ -1537,22 +1547,22 @@ void WebAssemblyTableImpl(const v8::FunctionCallbackInfo<v8::Value>& info) { } auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate); // The JS api uses 'anyfunc' instead of 'funcref'. - if (string->IsEqualTo(base::CStrVector("anyfunc"))) { + if (string->IsEqualTo("anyfunc")) { type = i::wasm::kWasmFuncRef; - } else if (string->IsEqualTo(base::CStrVector("externref"))) { + } else if (string->IsEqualTo("externref")) { type = i::wasm::kWasmExternRef; } else if (enabled_features.has_stringref() && - string->IsEqualTo(base::CStrVector("stringref"))) { + string->IsEqualTo("stringref")) { type = i::wasm::kWasmStringRef; - } else if (string->IsEqualTo(base::CStrVector("anyref"))) { + } else if (string->IsEqualTo("anyref")) { type = i::wasm::kWasmAnyRef; - } else if (string->IsEqualTo(base::CStrVector("eqref"))) { + } else if (string->IsEqualTo("eqref")) { type = i::wasm::kWasmEqRef; - } else if (string->IsEqualTo(base::CStrVector("structref"))) { + } else if (string->IsEqualTo("structref")) { type = i::wasm::kWasmStructRef; - } else if (string->IsEqualTo(base::CStrVector("arrayref"))) { + } else if (string->IsEqualTo("arrayref")) { type = i::wasm::kWasmArrayRef; - } else if (string->IsEqualTo(base::CStrVector("i31ref"))) { + } else if (string->IsEqualTo("i31ref")) { type = i::wasm::kWasmI31Ref; } else { thrower.TypeError( @@ -1779,35 +1789,35 @@ std::optional<i::wasm::ValueType> GetValueType( .ToHandle(&string)) { return std::nullopt; } - if (string->IsEqualTo(base::CStrVector("i32"))) { + if (string->IsEqualTo("i32")) { return i::wasm::kWasmI32; - } else if (string->IsEqualTo(base::CStrVector("f32"))) { + } else if (string->IsEqualTo("f32")) { return i::wasm::kWasmF32; - } else if (string->IsEqualTo(base::CStrVector("i64"))) { + } else if (string->IsEqualTo("i64")) { return i::wasm::kWasmI64; - } else if (string->IsEqualTo(base::CStrVector("f64"))) { + } else if (string->IsEqualTo("f64")) { return i::wasm::kWasmF64; - } else if (string->IsEqualTo(base::CStrVector("v128"))) { + } else if (string->IsEqualTo("v128")) { return i::wasm::kWasmS128; - } else if (string->IsEqualTo(base::CStrVector("externref"))) { + } else if (string->IsEqualTo("externref")) { return i::wasm::kWasmExternRef; - } else if (string->IsEqualTo(base::CStrVector("anyfunc"))) { + } else if (string->IsEqualTo("anyfunc")) { // The JS api spec uses 'anyfunc' instead of 'funcref'. return i::wasm::kWasmFuncRef; - } else if (string->IsEqualTo(base::CStrVector("eqref"))) { + } else if (string->IsEqualTo("eqref")) { return i::wasm::kWasmEqRef; } else if (enabled_features.has_stringref() && - string->IsEqualTo(base::CStrVector("stringref"))) { + string->IsEqualTo("stringref")) { return i::wasm::kWasmStringRef; - } else if (string->IsEqualTo(base::CStrVector("anyref"))) { + } else if (string->IsEqualTo("anyref")) { return i::wasm::kWasmAnyRef; - } else if (string->IsEqualTo(base::CStrVector("structref"))) { + } else if (string->IsEqualTo("structref")) { return i::wasm::kWasmStructRef; - } else if (string->IsEqualTo(base::CStrVector("arrayref"))) { + } else if (string->IsEqualTo("arrayref")) { return i::wasm::kWasmArrayRef; - } else if (string->IsEqualTo(base::CStrVector("i31ref"))) { + } else if (string->IsEqualTo("i31ref")) { return i::wasm::kWasmI31Ref; - } else if (string->IsEqualTo(base::CStrVector("exnref"))) { + } else if (string->IsEqualTo("exnref")) { return i::wasm::kWasmExnRef; } // Unrecognized type. @@ -2478,7 +2488,8 @@ V8_WARN_UNUSED_RESULT bool WasmObjectToJSReturnValue( thrower->TypeError("invalid type %s", unsafe_type.name().c_str()); return false; } - return_value.Set(Utils::ToLocal(i::wasm::WasmToJSObject(isolate, value))); + return_value.Set(Utils::ToLocal( + i::wasm::WasmToJSObject(isolate, value, i::wasm::kUnshareStrings))); return true; } } // namespace @@ -2642,7 +2653,8 @@ void WebAssemblyMemoryGrowImpl( } #endif // DEBUG - uint64_t old_pages = backing_store->byte_length() / i::wasm::kWasmPageSize; + uint64_t old_pages = backing_store->byte_length(std::memory_order_seq_cst) / + i::wasm::kWasmPageSize; uint64_t max_pages = receiver->maximum_pages(); if (delta_pages > max_pages - old_pages) { @@ -3322,8 +3334,7 @@ void WasmJs::PrepareForSnapshot(Isolate* isolate) { // By default, make all exported functions an instance of {Function}. { - DirectHandle<Map> function_map = - isolate->sloppy_function_without_prototype_map(); + DirectHandle<Map> function_map = isolate->function_without_prototype_map(); native_context->set_wasm_exported_function_map(*function_map); } @@ -3590,11 +3601,6 @@ CompileTimeImports CompileTimeImportsFromOptions( result.constants_module() = options.imported_string_constants_module; result.Add(CompileTimeImport::kStringConstants); } - // Mirror the JS `WebAssembly.Module` constructor, which disables denormal - // floats at compile time when the host FPU flushes them. - if (base::FPU::GetFlushDenormals()) { - result.Add(CompileTimeImport::kDisableDenormalFloats); - } return result; } } // namespace wasm @@ -3604,9 +3610,6 @@ CompileTimeImports WasmJs::CompileTimeImportsFromArgument( DirectHandle<Object> arg, Isolate* isolate, WasmEnabledFeatures enabled_features) { CompileTimeImports result; - if (base::FPU::GetFlushDenormals()) { - result.Add(CompileTimeImport::kDisableDenormalFloats); - } if (!IsJSReceiver(*arg)) return result; DirectHandle<JSReceiver> receiver = Cast<JSReceiver>(arg); @@ -3638,23 +3641,23 @@ CompileTimeImports WasmJs::CompileTimeImportsFromArgument( {}); if (IsString(*value)) { Tagged<String> builtin = Cast<String>(*value); - if (builtin->IsEqualTo(base::CStrVector("js-string"))) { + if (builtin->IsEqualTo("js-string")) { result.Add(CompileTimeImport::kJsString); continue; } if (enabled_features.has_imported_strings_utf8()) { - if (builtin->IsEqualTo(base::CStrVector("text-encoder"))) { + if (builtin->IsEqualTo("text-encoder")) { result.Add(CompileTimeImport::kTextEncoder); continue; } - if (builtin->IsEqualTo(base::CStrVector("text-decoder"))) { + if (builtin->IsEqualTo("text-decoder")) { result.Add(CompileTimeImport::kTextDecoder); continue; } } if (enabled_features.has_custom_descriptors() && v8_flags.wasm_js_interop) { - if (builtin->IsEqualTo(base::CStrVector("js-prototypes"))) { + if (builtin->IsEqualTo("js-prototypes")) { result.Add(CompileTimeImport::kJsPrototypes); continue; } diff --git a/deps/v8/src/wasm/wasm-js.h b/deps/v8/src/wasm/wasm-js.h index a11b13f71778..32e5754c02db 100644 --- a/deps/v8/src/wasm/wasm-js.h +++ b/deps/v8/src/wasm/wasm-js.h @@ -30,8 +30,7 @@ class StreamingDecoder; V8_EXPORT_PRIVATE std::unique_ptr<WasmStreaming> StartStreamingForTesting( Isolate*, std::shared_ptr<wasm::CompilationResultResolver>); -// Convert compile options from the public API into compile-time imports, -// including the host-FPU denormal handling applied to all compilations. +// Convert compile options from the public API into compile-time imports. V8_EXPORT_PRIVATE CompileTimeImports CompileTimeImportsFromOptions(const v8::WasmModuleObject::CompileOptions&); diff --git a/deps/v8/src/wasm/wasm-module-builder.cc b/deps/v8/src/wasm/wasm-module-builder.cc index be7cd905c954..5c0caf1848e6 100644 --- a/deps/v8/src/wasm/wasm-module-builder.cc +++ b/deps/v8/src/wasm/wasm-module-builder.cc @@ -349,9 +349,7 @@ void WasmFunctionBuilder::EmitFromInitializerExpression( WriteInitializerExpression(&body_, init_expr); } -void WasmFunctionBuilder::SetName(base::Vector<const char> name) { - name_ = name; -} +void WasmFunctionBuilder::SetName(std::string_view name) { name_ = name; } void WasmFunctionBuilder::DeleteCodeAfter(size_t position) { DCHECK_LE(position, body_.size()); @@ -459,14 +457,14 @@ ModuleTypeIndex WasmModuleBuilder::AddStructType(StructType* type, bool is_final, ModuleTypeIndex supertype) { uint32_t index = static_cast<uint32_t>(types_.size()); - types_.emplace_back(type, supertype, is_final, SharedFlag{false}); + types_.emplace_back(type, supertype, is_final, type->is_shared()); return ModuleTypeIndex{index}; } ModuleTypeIndex WasmModuleBuilder::AddArrayType(ArrayType* type, bool is_final, ModuleTypeIndex supertype) { uint32_t index = static_cast<uint32_t>(types_.size()); - types_.emplace_back(type, supertype, is_final, SharedFlag{false}); + types_.emplace_back(type, supertype, is_final, type->is_shared()); return ModuleTypeIndex{index}; } @@ -552,9 +550,9 @@ void WasmModuleBuilder::SetIndirectFunction(uint32_t table_index, AddElementSegment(std::move(segment)); } -uint32_t WasmModuleBuilder::AddImport(base::Vector<const char> name, +uint32_t WasmModuleBuilder::AddImport(std::string_view name, const FunctionSig* sig, - base::Vector<const char> module, + std::string_view module, bool force_new_sig) { DCHECK(adding_imports_allowed_); ModuleTypeIndex sig_index = @@ -564,9 +562,9 @@ uint32_t WasmModuleBuilder::AddImport(base::Vector<const char> name, return static_cast<uint32_t>(function_imports_.size() - 1); } -uint32_t WasmModuleBuilder::AddGlobalImport(base::Vector<const char> name, +uint32_t WasmModuleBuilder::AddGlobalImport(std::string_view name, ValueType type, bool mutability, - base::Vector<const char> module) { + std::string_view module) { global_imports_.push_back({.module = module, .name = name, .type_code = type.value_type_code(), @@ -578,7 +576,7 @@ void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) { start_function_index_ = function->func_index(); } -void WasmModuleBuilder::AddExport(base::Vector<const char> name, +void WasmModuleBuilder::AddExport(std::string_view name, ImportExportKindCode kind, uint32_t index) { DCHECK_LE(index, std::numeric_limits<int>::max()); exports_.push_back( @@ -587,13 +585,13 @@ void WasmModuleBuilder::AddExport(base::Vector<const char> name, uint32_t WasmModuleBuilder::AddExportedGlobal(ValueType type, bool mutability, WasmInitExpr init, - base::Vector<const char> name) { + std::string_view name) { uint32_t index = AddGlobal(type, mutability, init); AddExport(name, kExternalGlobal, index); return index; } -void WasmModuleBuilder::ExportImportedFunction(base::Vector<const char> name, +void WasmModuleBuilder::ExportImportedFunction(std::string_view name, int import_index) { #if DEBUG // The size of function_imports_ must not change any more. @@ -942,7 +940,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const { // Emit a placeholder for the length. size_t start = buffer->reserve_u32v(); // Emit the section string. - buffer->write_string(base::CStrVector("name")); + buffer->write_string("name"); // Emit a subsection for the function names. buffer->write_u8(NameSectionKindCode::kFunctionCode); // Emit a placeholder for the subsection length. diff --git a/deps/v8/src/wasm/wasm-module-builder.h b/deps/v8/src/wasm/wasm-module-builder.h index b7ca2cfe64fb..a5f0303e860b 100644 --- a/deps/v8/src/wasm/wasm-module-builder.h +++ b/deps/v8/src/wasm/wasm-module-builder.h @@ -10,6 +10,7 @@ #endif // !V8_ENABLE_WEBASSEMBLY #include <optional> +#include <string_view> #include "src/base/memory.h" #include "src/base/numerics/safe_conversions.h" @@ -95,9 +96,9 @@ class ZoneBuffer : public ZoneObject { pos_ += size; } - void write_string(base::Vector<const char> name) { + void write_string(std::string_view name) { write_size(name.size()); - write(reinterpret_cast<const uint8_t*>(name.begin()), name.size()); + write(reinterpret_cast<const uint8_t*>(name.data()), name.size()); } size_t reserve_u32v() { @@ -197,7 +198,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject { void EmitValueType(ValueType type); void EmitDirectCallIndex(uint32_t index); void EmitFromInitializerExpression(const WasmInitExpr& init_expr); - void SetName(base::Vector<const char> name); + void SetName(std::string_view name); size_t GetPosition() const { return body_.size(); } void FixupByte(size_t position, uint8_t value) { @@ -228,7 +229,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject { ModuleTypeIndex signature_index_; uint32_t func_index_; ZoneBuffer body_; - base::Vector<const char> name_; + std::string_view name_; ZoneVector<uint32_t> i32_temps_; ZoneVector<uint32_t> i64_temps_; ZoneVector<uint32_t> f32_temps_; @@ -302,15 +303,13 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { }; // Building methods. - uint32_t AddImport(base::Vector<const char> name, const FunctionSig* sig, - base::Vector<const char> module = {}, - bool force_new_sig = false); + uint32_t AddImport(std::string_view name, const FunctionSig* sig, + std::string_view module = {}, bool force_new_sig = false); WasmFunctionBuilder* AddFunction(const FunctionSig* sig = nullptr); WasmFunctionBuilder* AddFunction(ModuleTypeIndex sig_index); uint32_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init); - uint32_t AddGlobalImport(base::Vector<const char> name, ValueType type, - bool mutability, - base::Vector<const char> module = {}); + uint32_t AddGlobalImport(std::string_view name, ValueType type, + bool mutability, std::string_view module = {}); void AddDataSegment(const uint8_t* data, uint32_t size, uint32_t dest); void AddPassiveDataSegment(const uint8_t* data, uint32_t size); // Add an element segment to this {WasmModuleBuilder}. {segment}'s enties @@ -347,14 +346,14 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { uint32_t AddMemory64(uint32_t min_pages); uint32_t AddMemory64(uint32_t min_pages, uint32_t max_pages); void MarkStartFunction(WasmFunctionBuilder* builder); - void AddExport(base::Vector<const char> name, ImportExportKindCode kind, + void AddExport(std::string_view name, ImportExportKindCode kind, uint32_t index); - void AddExport(base::Vector<const char> name, WasmFunctionBuilder* builder) { + void AddExport(std::string_view name, WasmFunctionBuilder* builder) { AddExport(name, kExternalFunction, builder->func_index()); } uint32_t AddExportedGlobal(ValueType type, bool mutability, WasmInitExpr init, - base::Vector<const char> name); - void ExportImportedFunction(base::Vector<const char> name, int import_index); + std::string_view name); + void ExportImportedFunction(std::string_view name, int import_index); // Start a recursive type group; must be followed by `EndRecursiveTypeGroup()` // after adding all types of the recursion group. @@ -477,21 +476,21 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { private: struct WasmFunctionImport { - base::Vector<const char> module; - base::Vector<const char> name; + std::string_view module; + std::string_view name; ModuleTypeIndex sig_index; }; struct WasmGlobalImport { - base::Vector<const char> module; - base::Vector<const char> name; + std::string_view module; + std::string_view name; // TODO(manoskouk): Extend to full value type. ValueTypeCode type_code; bool mutability; }; struct WasmExport { - base::Vector<const char> name; + std::string_view name; ImportExportKindCode kind; int index; // Can be negative for re-exported imports. }; diff --git a/deps/v8/src/wasm/wasm-module-sourcemap.cc b/deps/v8/src/wasm/wasm-module-sourcemap.cc index 9381f94214ed..e47c3e48e5db 100644 --- a/deps/v8/src/wasm/wasm-module-sourcemap.cc +++ b/deps/v8/src/wasm/wasm-module-sourcemap.cc @@ -7,6 +7,7 @@ #include <algorithm> #include "include/v8-context.h" +#include "include/v8-exception.h" #include "include/v8-json.h" #include "include/v8-local-handle.h" #include "include/v8-object.h" @@ -25,10 +26,15 @@ WasmModuleSourceMap::WasmModuleSourceMap(v8::Isolate* v8_isolate, v8::Local<v8::String> src_map_str) { if (src_map_str.IsEmpty()) return; v8::HandleScope scope(v8_isolate); + v8::TryCatch try_catch(v8_isolate); v8::Local<v8::Context> context = v8::Context::New(v8_isolate); + if (context.IsEmpty()) return; v8::Local<v8::Value> src_map_value; - if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value)) return; + if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value) || + !src_map_value->IsObject()) { + return; + } v8::Local<v8::Object> src_map_obj = v8::Local<v8::Object>::Cast(src_map_value); diff --git a/deps/v8/src/wasm/wasm-module.cc b/deps/v8/src/wasm/wasm-module.cc index 4affa84d5378..5036e1ab3220 100644 --- a/deps/v8/src/wasm/wasm-module.cc +++ b/deps/v8/src/wasm/wasm-module.cc @@ -220,7 +220,7 @@ namespace { // Converts the given {type} into a string representation that can be used in // reflective functions. Should be kept in sync with the {GetValueType} helper. DirectHandle<String> ToValueTypeString(Isolate* isolate, ValueType type) { - return isolate->factory()->InternalizeUtf8String(base::VectorOf(type.name())); + return isolate->factory()->InternalizeUtf8String(type.name()); } } // namespace @@ -329,8 +329,7 @@ DirectHandle<JSObject> GetTypeForTable(Isolate* isolate, ValueType type, AddressType address_type) { Factory* factory = isolate->factory(); - DirectHandle<String> element = - factory->InternalizeUtf8String(base::VectorOf(type.name())); + DirectHandle<String> element = factory->InternalizeUtf8String(type.name()); DirectHandle<JSFunction> object_function = isolate->object_function(); DirectHandle<JSObject> object = factory->NewJSObject(object_function); diff --git a/deps/v8/src/wasm/wasm-module.h b/deps/v8/src/wasm/wasm-module.h index cf22f1b10806..e251908904ae 100644 --- a/deps/v8/src/wasm/wasm-module.h +++ b/deps/v8/src/wasm/wasm-module.h @@ -15,6 +15,7 @@ #include "src/base/platform/mutex.h" #include "src/base/strong-alias.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/common/globals.h" #include "src/handles/handles.h" @@ -551,13 +552,13 @@ class CallSiteFeedback { struct FunctionTypeFeedback { // {feedback_vector} is computed from {call_targets} and the instance-specific // feedback vector by {TransitiveTypeFeedbackProcessor}. - base::OwnedVector<CallSiteFeedback> feedback_vector; + base::UniqueArray<CallSiteFeedback> feedback_vector; // {call_targets} has one entry per "call", "call_indirect", and "call_ref" in // the function. // For "call", it holds the index of the called function, for "call_indirect" // and "call_ref" the value will be a sentinel {kCallIndirect} / {kCallRef}. - base::OwnedVector<uint32_t> call_targets; + base::UniqueArray<uint32_t> call_targets; // The number of times this function was invoked. int num_invocations = 0; diff --git a/deps/v8/src/wasm/wasm-objects-inl.h b/deps/v8/src/wasm/wasm-objects-inl.h index 693dec1f44f4..1a727dbaac36 100644 --- a/deps/v8/src/wasm/wasm-objects-inl.h +++ b/deps/v8/src/wasm/wasm-objects-inl.h @@ -31,10 +31,10 @@ #include "src/objects/slots-inl.h" #include "src/objects/tagged-field-inl.h" #include "src/objects/trusted-object-inl.h" -#include "src/objects/trusted-pointer-inl.h" #include "src/roots/roots.h" #include "src/sandbox/check.h" #include "src/sandbox/isolate-inl.h" +#include "src/sandbox/trusted-pointer-inl.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-module.h" #include "third_party/fp16/src/include/fp16.h" @@ -175,7 +175,7 @@ bool WasmGlobalObject::has_trusted_data_unpublished( IsolateForSandbox isolate) const { return TrustedPointerField::IsTrustedPointerFieldUnpublished( Tagged<HeapObject>(this), offsetof(WasmGlobalObject, trusted_data_), - kWasmTrustedInstanceDataIndirectPointerTag, isolate); + kWasmTrustedInstanceDataTrustedPointerTag, isolate); } void WasmGlobalObject::clear_trusted_data() { trusted_data_.clear(this); } @@ -275,8 +275,8 @@ Address WasmGlobalObject::storage() const { PRIMITIVE_ACCESSORS(WasmTrustedInstanceData, memory0_start, uint8_t*, kMemory0StartOffset) -PRIMITIVE_ACCESSORS(WasmTrustedInstanceData, memory0_size, size_t, - kMemory0SizeOffset) +PRIMITIVE_ACCESSORS(WasmTrustedInstanceData, memory0_size_or_address, Address, + kMemory0SizeOrAddressOffset) // ACCESSORS/OPTIONAL_ACCESSORS/PROTECTED_POINTER_ACCESSORS all use // CONDITIONAL_*_WRITE_BARRIER(this, ...) which expands to (object)->... — // arrow access that fails for HeapObject value types. Spell out the @@ -352,6 +352,9 @@ PRIMITIVE_ACCESSORS(WasmTrustedInstanceData, tiering_budget_array, WTI_PROTECTED_POINTER_ACCESSORS(memory_bases_and_sizes, TrustedFixedAddressArray, kProtectedMemoryBasesAndSizesOffset) +WTI_PROTECTED_POINTER_ACCESSORS(shared_memory_backing_stores, + ProtectedFixedArray, + kProtectedSharedMemoryBackingStoresOffset) WTI_PROTECTED_POINTER_ACCESSORS(data_segments, TrustedPodArray<wasm::WireBytesRef>, kProtectedDataSegmentsOffset) @@ -424,12 +427,18 @@ size_t WasmTrustedInstanceData::memory_size(uint32_t memory_index) const { memory_bases_and_sizes()->length().value(); SBXCHECK_EQ(bases_and_sizes_length % 2u, 0u); SBXCHECK_LT(memory_index, bases_and_sizes_length / 2u); - DCHECK_EQ(memory0_size(), memory_bases_and_sizes()->get(1)); - return memory_bases_and_sizes()->get(2 * memory_index + 1); + DCHECK_EQ(memory0_size_or_address(), memory_bases_and_sizes()->get(1)); + Address size_or_address = memory_bases_and_sizes()->get(2 * memory_index + 1); + if (module()->memories[memory_index].is_shared) { + if (size_or_address == kNullAddress) return 0; + return reinterpret_cast<const std::atomic<size_t>*>(size_or_address) + ->load(std::memory_order_seq_cst); + } + return static_cast<size_t>(size_or_address); } wasm::NativeModule* WasmTrustedInstanceData::native_module() const { - return managed_native_module()->raw(); + return managed_native_module()->unsafe_raw(); } Tagged<WasmModuleObject> WasmTrustedInstanceData::module_object() const { @@ -471,7 +480,7 @@ bool WasmInstanceObject::has_trusted_data_unpublished( IsolateForSandbox isolate) const { return TrustedPointerField::IsTrustedPointerFieldUnpublished( Tagged<HeapObject>(this), offsetof(WasmInstanceObject, trusted_data_), - kWasmTrustedInstanceDataIndirectPointerTag, isolate); + kWasmTrustedInstanceDataTrustedPointerTag, isolate); } void WasmInstanceObject::clear_trusted_data() { trusted_data_.clear(this); } @@ -480,8 +489,8 @@ WasmInstanceObject::trusted_data_allow_unpublished( IsolateForSandbox isolate) const { #ifdef V8_ENABLE_SANDBOX Tagged<Object> obj = - RawIndirectPointerField(offsetof(WasmInstanceObject, trusted_data_), - kWasmTrustedInstanceDataIndirectPointerTag) + RawTrustedPointerField(offsetof(WasmInstanceObject, trusted_data_), + kWasmTrustedInstanceDataTrustedPointerTag) .Relaxed_Load_AllowUnpublished(isolate); return TrustedCast<WasmTrustedInstanceData>(obj); #else @@ -565,11 +574,11 @@ void WasmDispatchTableForImports::clear_protected_offheap_data() { WasmDispatchTableData* WasmDispatchTable::offheap_data() const { if (!has_protected_offheap_data()) return nullptr; - return protected_offheap_data()->get().get(); + return protected_offheap_data()->unsafe_raw(); } WasmDispatchTableData* WasmDispatchTableForImports::offheap_data() const { if (!has_protected_offheap_data()) return nullptr; - return protected_offheap_data()->get().get(); + return protected_offheap_data()->unsafe_raw(); } Tagged<ProtectedWeakFixedArray> WasmDispatchTable::protected_uses() const { @@ -743,7 +752,7 @@ void WasmImportData::clear_padding() { // WasmInternalFunction // {implicit_arg} will be a WasmTrustedInstanceData or a WasmImportData. -Tagged<TrustedObject> WasmInternalFunction::implicit_arg() const { +Tagged<WasmImplicitArg> WasmInternalFunction::implicit_arg() const { DCHECK(has_implicit_arg()); return protected_implicit_arg_.load(); } @@ -756,7 +765,7 @@ Tagged<WasmTrustedInstanceData> WasmInternalFunction::instance_data() const { return TrustedCast<WasmImportData>(arg)->importing_instance_data(); } -void WasmInternalFunction::set_implicit_arg(Tagged<TrustedObject> value, +void WasmInternalFunction::set_implicit_arg(Tagged<WasmImplicitArg> value, WriteBarrierMode mode) { protected_implicit_arg_.store(this, value, mode); } @@ -783,10 +792,10 @@ void WasmInternalFunction::set_function_index(int value) { } uint32_t WasmInternalFunction::raw_call_target() const { - return raw_call_target_; + return raw_call_target_.value(); } void WasmInternalFunction::set_raw_call_target(uint32_t value) { - raw_call_target_ = value; + raw_call_target_ = WasmCodePointer{value}; } const wasm::CanonicalSig* WasmInternalFunction::sig() const { @@ -900,11 +909,9 @@ bool WasmExportedFunctionData::is_promising() const { wasm::kPromise; } -WasmCodePointer WasmInternalFunction::call_target() { - return WasmCodePointer{raw_call_target()}; -} +WasmCodePointer WasmInternalFunction::call_target() { return raw_call_target_; } void WasmInternalFunction::set_call_target(WasmCodePointer code_pointer) { - set_raw_call_target(code_pointer.value()); + raw_call_target_ = code_pointer; } // WasmCapiFunctionData @@ -1063,7 +1070,7 @@ bool WasmTableObject::has_trusted_data_unpublished( IsolateForSandbox isolate) const { return TrustedPointerField::IsTrustedPointerFieldUnpublished( Tagged<HeapObject>(this), offsetof(WasmTableObject, trusted_data_), - kWasmTrustedInstanceDataIndirectPointerTag, isolate); + kWasmTrustedInstanceDataTrustedPointerTag, isolate); } void WasmTableObject::clear_trusted_data() { trusted_data_.clear(this); } @@ -1091,7 +1098,7 @@ bool WasmTableObject::has_trusted_dispatch_table_unpublished( return TrustedPointerField::IsTrustedPointerFieldUnpublished( Tagged<HeapObject>(this), offsetof(WasmTableObject, trusted_dispatch_table_), - kWasmDispatchTableIndirectPointerTag, isolate); + kWasmDispatchTableTrustedPointerTag, isolate); } void WasmTableObject::clear_trusted_dispatch_table() { trusted_dispatch_table_.clear(this); @@ -1287,13 +1294,10 @@ void WasmStruct::EncodeInstanceSizeInMap(int instance_size, Tagged<Map> map) { // map so that the GC can read it without relying on any other objects // still being around. To solve this problem, we store the instance size // in two other fields that are otherwise unused for WasmStructs. - static_assert(0xFFFF > ((kHeaderSize + wasm::kMaxValueTypeSize * - wasm::kV8MaxWasmStructFields) >> - kObjectAlignmentBits)); static_assert(0xFFFF > - ((WasmCustomMap::kHeaderSize + - wasm::kMaxValueTypeSize * wasm::kV8MaxWasmStructFields) >> - kObjectAlignmentBits)); + (WasmStruct::kMaxInstanceSize >> kObjectAlignmentBits)); + static_assert(0xFFFF > + (WasmCustomMap::kMaxInstanceSize >> kObjectAlignmentBits)); map->SetWasmByte1((instance_size >> kObjectAlignmentBits) & 0xff); map->SetWasmByte2(instance_size >> (8 + kObjectAlignmentBits)); } @@ -1308,12 +1312,6 @@ int WasmStruct::GcSafeSize(Tagged<Map> map) { return DecodeInstanceSizeFromMap(map); } -int WasmStruct::FieldOffset(const wasm::StructType* type, int field_index) { - int header_size = type->is_descriptor() ? WasmCustomMap::kHeaderSize - : WasmStruct::kHeaderSize; - return header_size + type->field_offset(field_index); -} - Address WasmStruct::RawFieldAddress(int raw_offset) { int offset = WasmStruct::kHeaderSize + raw_offset; return FIELD_ADDR(Tagged<WasmStruct>(this), offset); @@ -1392,27 +1390,49 @@ const wasm::CanonicalValueType WasmArray::GcSafeElementType(Tagged<Map> map) { return type_info->element_type(); } +int WasmArray::HeaderSize(Tagged<Map> map) { + if constexpr (HeaderSize(SharedFlag{true}) == HeaderSize(SharedFlag{false})) { + return sizeof(WasmArray); + } + DCHECK(!HeapLayout::InReadOnlySpace(map)); + return HeaderSize(SharedFlag{HeapLayout::InWritableSharedSpace(map)}); +} + +int WasmArray::header_size() const { + if constexpr (HeaderSize(SharedFlag{true}) == HeaderSize(SharedFlag{false})) { + return sizeof(WasmArray); + } + DCHECK(!HeapLayout::InReadOnlySpace(this)); + return HeaderSize(SharedFlag{HeapLayout::InWritableSharedSpace(this)}); +} + int WasmArray::SizeFor(Tagged<Map> map, int length) { int element_size = DecodeElementSizeFromMap(map); - return SizeFor(element_size, length); + return HeaderSize(map) + RoundUp(element_size * length, kTaggedSize); } -constexpr int WasmArray::SizeFor(int element_size, int length) { - return kHeaderSize + RoundUp(element_size * length, kTaggedSize); +constexpr int WasmArray::SizeFor(int element_size, int length, + SharedFlag is_shared) { + return HeaderSize(is_shared) + RoundUp(element_size * length, kTaggedSize); } // Allocating arrays currently requires passing the requested byte size to the // runtime function as a Smi. -static_assert(Smi::IsValid(WasmArray::SizeFor(1, WasmArray::MaxLength(1)))); -static_assert(Smi::IsValid(WasmArray::SizeFor(2, WasmArray::MaxLength(2)))); -static_assert(Smi::IsValid(WasmArray::SizeFor(4, WasmArray::MaxLength(4)))); -static_assert(Smi::IsValid(WasmArray::SizeFor(8, WasmArray::MaxLength(8)))); -static_assert(Smi::IsValid(WasmArray::SizeFor(16, WasmArray::MaxLength(16)))); +static_assert(Smi::IsValid(WasmArray::SizeFor(1, WasmArray::MaxLength(1), + SharedFlag{true}))); +static_assert(Smi::IsValid(WasmArray::SizeFor(2, WasmArray::MaxLength(2), + SharedFlag{true}))); +static_assert(Smi::IsValid(WasmArray::SizeFor(4, WasmArray::MaxLength(4), + SharedFlag{true}))); +static_assert(Smi::IsValid(WasmArray::SizeFor(8, WasmArray::MaxLength(8), + SharedFlag{true}))); +static_assert(Smi::IsValid(WasmArray::SizeFor(16, WasmArray::MaxLength(16), + SharedFlag{true}))); uint32_t WasmArray::element_offset(uint32_t index) { DCHECK_LE(index, length()); int element_size = DecodeElementSizeFromMap(map()); - return WasmArray::kHeaderSize + index * element_size; + return header_size() + index * element_size; } Address WasmArray::ElementAddress(uint32_t index) { @@ -1422,7 +1442,7 @@ Address WasmArray::ElementAddress(uint32_t index) { ObjectSlot WasmArray::ElementSlot(uint32_t index) { DCHECK_LE(index, length()); DCHECK(map()->wasm_type_info()->element_type().is_ref()); - return RawField(kHeaderSize + kTaggedSize * index); + return RawField(header_size() + kTaggedSize * index); } // static @@ -1448,21 +1468,11 @@ int WasmArray::DecodeElementSizeFromMap(Tagged<Map> map) { return map->WasmByte1(); } -wasm::StackMemory* WasmSuspenderObject::stack(IsolateForSandbox isolate) const { - Address result = stack_.load<kWasmStackMemoryTag>(isolate); - return reinterpret_cast<wasm::StackMemory*>(result); -} wasm::StackMemory* WasmSuspenderObject::stack() const { - return stack(GetCurrentIsolateForSandbox()); + return reinterpret_cast<wasm::StackMemory*>(stack_.value()); } -void WasmSuspenderObject::init_stack(IsolateForSandbox isolate, - const wasm::StackMemory* initial_value) { - stack_.Init<kWasmStackMemoryTag>(address(), isolate, - reinterpret_cast<Address>(initial_value)); -} -void WasmSuspenderObject::set_stack(IsolateForSandbox isolate, - const wasm::StackMemory* value) { - stack_.store<kWasmStackMemoryTag>(isolate, reinterpret_cast<Address>(value)); +void WasmSuspenderObject::set_stack(wasm::StackMemory* value) { + stack_.set_value(reinterpret_cast<Address>(value)); } EXTERNAL_POINTER_ACCESSORS(WasmStackObject, stack, wasm::StackMemory*, @@ -1505,14 +1515,15 @@ bool WasmTagObject::has_trusted_data_unpublished( IsolateForSandbox isolate) const { return TrustedPointerField::IsTrustedPointerFieldUnpublished( Tagged<HeapObject>(this), offsetof(WasmTagObject, trusted_data_), - kWasmTrustedInstanceDataIndirectPointerTag, isolate); + kWasmTrustedInstanceDataTrustedPointerTag, isolate); } void WasmTagObject::clear_trusted_data() { trusted_data_.clear(this); } +WasmExceptionTag::WasmExceptionTag(const AllocationWitness& witness, int index) + : Struct(witness.roots().wasm_exception_tag_map()), + index_(Smi::FromInt(index)) {} + int WasmExceptionTag::index() const { return index_.load().value(); } -void WasmExceptionTag::set_index(int value) { - index_.store(this, Smi::FromInt(value)); -} Tagged<JSReceiver> WasmSuspendingObject::callable() const { return callable_.load(); } @@ -1535,10 +1546,10 @@ void WasmFastApiCallData::set_callback_data(Tagged<Object> value, WriteBarrierMode mode) { callback_data_.store(this, value, mode); } -Tagged<MaybeObject> WasmFastApiCallData::cached_map() const { +Tagged<UnionOf<Null, Weak<Map>>> WasmFastApiCallData::cached_map() const { return cached_map_.load(); } -void WasmFastApiCallData::set_cached_map(Tagged<MaybeObject> value, +void WasmFastApiCallData::set_cached_map(Tagged<UnionOf<Null, Weak<Map>>> value, WriteBarrierMode mode) { cached_map_.store(this, value, mode); } diff --git a/deps/v8/src/wasm/wasm-objects.cc b/deps/v8/src/wasm/wasm-objects.cc index 4c82b3c97229..2548fa1ab541 100644 --- a/deps/v8/src/wasm/wasm-objects.cc +++ b/deps/v8/src/wasm/wasm-objects.cc @@ -13,14 +13,17 @@ #undef MAP_TYPE #endif // V8_TARGET_OS_LINUX +#include <bit> #include <optional> #include "src/base/iterator.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/builtins/builtins-inl.h" #include "src/compiler/wasm-compiler.h" #include "src/debug/debug.h" #include "src/execution/futex-emulation.h" +#include "src/heap/factory-inl.h" #include "src/logging/counters.h" #include "src/objects/heap-object-field-inl.h" #include "src/objects/heap-object-set-map-inl.h" @@ -137,7 +140,8 @@ DirectHandle<String> WasmModuleObject::ExtractUtf8StringFromModuleBytes( DCHECK_IMPLIES(shared, !internalize); return internalize ? factory->InternalizeUtf8String( - base::Vector<const char>::cast(name_vec)) + {reinterpret_cast<const char*>(name_vec.begin()), + name_vec.size()}) : factory ->NewStringFromUtf8( name_vec, UnicodeConfig(unibrow::Utf8Variant::kLossyUtf8, @@ -737,7 +741,6 @@ DirectHandle<WasmSuspendingObject> WasmSuspendingObject::New( namespace { void SetInstanceMemory(Tagged<WasmTrustedInstanceData> trusted_instance_data, - Tagged<HeapObject> maybe_buffer, std::shared_ptr<BackingStore> backing_store, uint32_t memory_index) { DisallowHeapAllocation no_gc; @@ -764,8 +767,17 @@ void SetInstanceMemory(Tagged<WasmTrustedInstanceData> trusted_instance_data, // We checked this before, but a malicious worker thread with an in-sandbox // corruption primitive could have modified it since then. SBXCHECK_GE(byte_length, memory.min_memory_size); + SBXCHECK_EQ(memory.is_shared, backing_store->is_shared()); - trusted_instance_data->SetRawMemory(memory_index, base_address, byte_length); + // For shared memories, store the address of the atomic byte_length_ so that + // JIT bounds checks and memory.size can observe dynamic growth atomically. + Address size_or_address = + memory.is_shared + ? reinterpret_cast<Address>(backing_store->byte_length_address()) + : byte_length; + + trusted_instance_data->SetRawMemory(memory_index, base_address, + size_or_address); #if V8_ENABLE_DRUMBRAKE if (v8_flags.wasm_jitless && @@ -889,14 +901,32 @@ void WasmMemoryObject::UseInInstance( Isolate* isolate, DirectHandle<WasmMemoryObject> memory, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, uint32_t memory_index_in_instance) { - SetInstanceMemory(*trusted_instance_data, memory->array_buffer(), - memory->backing_store().as_shared_ptr(), + std::shared_ptr<BackingStore> backing_store = + memory->backing_store().as_shared_ptr(); + if (trusted_instance_data->module() + ->memories[memory_index_in_instance] + .is_shared) { + // Keep the shared BackingStore alive in trusted space so that + // WasmTrustedInstanceData's raw pointer to BackingStore::byte_length_ + // cannot dangle if in-sandbox references are overwritten. + // Pass 0 as estimated_size because the WasmMemoryObject's + // CppGCManaged<BackingStore> already accounts for external memory. + DirectHandle<TrustedManaged<BackingStore>> managed_backing_store = + TrustedManaged<BackingStore>::From(isolate, 0, backing_store); + trusted_instance_data->shared_memory_backing_stores()->set( + memory_index_in_instance, *managed_backing_store); + } else { + // Shared memories always grow in place, so only non-shared memories need to + // track their using instances for updating on grow. + DirectHandle<WeakArrayList> instances{memory->instances(), isolate}; + MaybeObjectDirectHandle weak_instance_object = + MaybeObjectDirectHandle::Weak(trusted_instance_data->instance_object(), + isolate); + instances = WeakArrayList::Append(isolate, instances, weak_instance_object); + memory->set_instances(*instances); + } + SetInstanceMemory(*trusted_instance_data, std::move(backing_store), memory_index_in_instance); - DirectHandle<WeakArrayList> instances{memory->instances(), isolate}; - auto weak_instance_object = MaybeObjectDirectHandle::Weak( - trusted_instance_data->instance_object(), isolate); - instances = WeakArrayList::Append(isolate, instances, weak_instance_object); - memory->set_instances(*instances); } // static @@ -934,6 +964,8 @@ void WasmMemoryObject::SetNewBuffer(Isolate* isolate, void WasmMemoryObject::UpdateInstances(Isolate* isolate) { DisallowGarbageCollection no_gc; + // SetInstanceMemory has an SBXCHECK for this later. + DCHECK(!backing_store()->is_shared()); Tagged<WeakArrayList> instances = this->instances(); const uint32_t instances_len = instances->length().value(); for (uint32_t i = 0; i < instances_len; ++i) { @@ -949,8 +981,8 @@ void WasmMemoryObject::UpdateInstances(Isolate* isolate) { uint32_t num_memories = memory_objects->ulength().value(); for (uint32_t mem_idx = 0; mem_idx < num_memories; ++mem_idx) { if (memory_objects->get(mem_idx) == Tagged<WasmMemoryObject>(this)) { - SetInstanceMemory(trusted_data, array_buffer(), - backing_store().as_shared_ptr(), mem_idx); + SetInstanceMemory(trusted_data, backing_store().as_shared_ptr(), + mem_idx); } } } @@ -1041,7 +1073,7 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, // {BackingStore::CopyWasmMemory}, and is irrelevant for // {GrowWasmMemoryInPlace} because memory is never allocated with more // capacity than that limit. - size_t old_size = backing_store->byte_length(); + size_t old_size = backing_store->byte_length(std::memory_order_seq_cst); DCHECK_EQ(0, old_size % wasm::kWasmPageSize); size_t old_pages = old_size / wasm::kWasmPageSize; size_t max_pages = memory_object->is_memory64() ? wasm::max_mem64_pages() @@ -1056,12 +1088,14 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, const bool must_grow_in_place = backing_store->is_shared() || backing_store->has_guard_regions() || backing_store->is_resizable_by_js() || pages == 0; - // Disallow growing relocatable (movable) memories during API interrupts - // (such as inspector pauses or debugger stepping). Growing and relocating - // the memory backing store at this point would invalidate cached memory - // base pointers in compiled loop code, leading to a Use-after-Free (or - // requiring costly reloads if we would chose to allow growing). - if (isolate->is_executing_api_interrupt() && !must_grow_in_place) { + // Disallow growing unshared memories during API interrupts (such as + // inspector pauses or debugger stepping). Growing and relocating the memory + // backing store at this point would invalidate cached memory base pointers in + // compiled loop code, leading to a Use-after-Free, and even in-place growth + // of unshared memories would invalidate cached memory sizes in compiled loop + // code. + if (isolate->is_executing_api_interrupt() && !backing_store->is_shared() && + pages != 0) { return -1; } const bool try_grow_in_place = @@ -1075,7 +1109,7 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, // There are different limits per platform, thus crash if the correctness // fuzzer is running. if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("could not grow wasm memory"); + base::FatalNoSecurityImpact("could not grow wasm memory"); } return -1; } @@ -1084,21 +1118,23 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, if (backing_store->is_shared()) { DCHECK(result_inplace.has_value()); backing_store->BroadcastSharedWasmMemoryGrow(isolate); - if (has_old_buffer && !maybe_old_buffer->is_resizable_by_js() && - pages > 0) { - // Independent of potential concurrent grows in other threads: After we - // grew the shared memory, broadcasting should have reset the ArrayBuffer - // so we reallocate it on the next access to the `buffer` property of the - // Wasm memory. - CHECK(IsUndefined(memory_object->array_buffer())); + if (pages > 0) { + if (has_old_buffer && !maybe_old_buffer->is_resizable_by_js()) { + // Independent of potential concurrent grows in other threads: After we + // grew the shared memory, broadcasting should have reset the + // ArrayBuffer so we reallocate it on the next access to the `buffer` + // property of the Wasm memory. + CHECK(IsUndefined(memory_object->array_buffer())); + } + // Report the grown memory size rounded up to the next power of two to + // avoid triggering too many GCs when growing memory in a loop. + memory_object->managed_backing_store()->UpdateEstimatedSize( + std::bit_ceil(backing_store->byte_length()), isolate); } // As {old_pages} was read racefully, we return here the synchronized // value provided by {GrowWasmMemoryInPlace}, to provide the atomic // read-modify-write behavior required by the spec. - uint32_t result = static_cast<int32_t>(result_inplace.value()); - memory_object->managed_backing_store()->UpdateEstimatedSize( - backing_store->byte_length(), isolate); - return result; // success + return static_cast<int32_t>(result_inplace.value()); // success } size_t new_pages = old_pages + pages; @@ -1115,8 +1151,12 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, } memory_object->UpdateInstances(isolate); DCHECK_EQ(result_inplace.value(), old_pages); - memory_object->managed_backing_store()->UpdateEstimatedSize( - backing_store->byte_length(), isolate); + if (pages > 0) { + // Report the grown memory size rounded up to the next power of two to + // avoid triggering too many GCs when growing memory in a loop. + memory_object->managed_backing_store()->UpdateEstimatedSize( + std::bit_ceil(backing_store->byte_length()), isolate); + } return static_cast<int32_t>(result_inplace.value()); // success } DCHECK(!has_old_buffer || !maybe_old_buffer->is_resizable_by_js()); @@ -1143,7 +1183,7 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, if (!new_backing_store) { // Crash on out-of-memory if the correctness fuzzer is running. if (v8_flags.correctness_fuzzer_suppressions) { - FATAL("could not grow wasm memory"); + base::FatalNoSecurityImpact("could not grow wasm memory"); } // Set the non-determinism flag in the WasmEngine. wasm::WasmEngine::set_had_nondeterminism(); @@ -1152,8 +1192,10 @@ int32_t WasmMemoryObject::Grow(Isolate* isolate, DCHECK_EQ(backing_store.raw(), memory_object->backing_store().raw()); size_t new_byte_length = new_backing_store->byte_length(); + // Report the grown memory size rounded up to the next power of two to avoid + // triggering too many GCs when growing memory in a loop. memory_object->managed_backing_store()->SetManagedObject( - std::move(new_backing_store), isolate, new_byte_length); + std::move(new_backing_store), isolate, std::bit_ceil(new_byte_length)); if (has_old_buffer) { JSArrayBuffer::Detach(maybe_old_buffer, true).Check(); @@ -1359,7 +1401,7 @@ Tagged<Object> ImportedFunctionEntry::maybe_callable() { } Tagged<JSReceiver> ImportedFunctionEntry::callable() { - return TrustedCast<JSReceiver>( + return Cast<JSReceiver>( TrustedCast<WasmImportData>(implicit_arg())->callable()); } @@ -1393,20 +1435,35 @@ constexpr decltype(WasmTrustedInstanceData::kProtectedFieldNames) void WasmTrustedInstanceData::SetRawMemory(uint32_t memory_index, uint8_t* mem_start, - size_t mem_size) { + Address size_or_address) { CHECK_LT(memory_index, module()->memories.size()); - CHECK_LE(mem_size, module()->memories[memory_index].is_memory64() - ? wasm::max_mem64_bytes() - : wasm::max_mem32_bytes()); - // All memory bases and sizes are stored in a TrustedFixedAddressArray. + if (!module()->memories[memory_index].is_shared) { + CHECK_LE(size_or_address, module()->memories[memory_index].is_memory64() + ? wasm::max_mem64_bytes() + : wasm::max_mem32_bytes()); + } else { + CHECK_NE(size_or_address, kNullAddress); + CHECK(IsAligned(size_or_address, alignof(size_t))); + // Verify that the shared BackingStore is kept alive in trusted space. + CHECK_LT(memory_index, shared_memory_backing_stores()->ulength().value()); + Tagged<Object> backing_store_obj = + shared_memory_backing_stores()->get(memory_index); + CHECK_EQ(size_or_address, + reinterpret_cast<Address>( + TrustedCast<TrustedManaged<BackingStore>>(backing_store_obj) + ->raw(DisallowGarbageCollection{}) + ->byte_length_address())); + } + // All memory bases and sizes (or addresses of atomic sizes for shared + // memories) are stored in a TrustedFixedAddressArray. Tagged<TrustedFixedAddressArray> bases_and_sizes = memory_bases_and_sizes(); bases_and_sizes->set(memory_index * 2, reinterpret_cast<Address>(mem_start)); - bases_and_sizes->set(memory_index * 2 + 1, mem_size); + bases_and_sizes->set(memory_index * 2 + 1, size_or_address); // Memory 0 has fast-access fields. if (memory_index == 0) { set_memory0_start(mem_start); - set_memory0_size(mem_size); + set_memory0_size_or_address(size_or_address); } } @@ -1467,6 +1524,13 @@ DirectHandle<WasmTrustedInstanceData> WasmTrustedInstanceData::New( isolate->factory()->NewWasmDispatchTable(0, wasm::kWasmFuncRef); DirectHandle<ProtectedFixedArray> empty_protected_fixed_array = isolate->factory()->empty_protected_fixed_array(); + bool has_shared_memory = std::any_of( + module->memories.begin(), module->memories.end(), + [](const wasm::WasmMemory& mem) { return mem.is_shared.value(); }); + DirectHandle<ProtectedFixedArray> shared_memory_backing_stores = + has_shared_memory + ? isolate->factory()->NewProtectedFixedArray(num_memories) + : empty_protected_fixed_array; // Use the same memory estimate as the (untrusted) Managed in // WasmModuleObject. This is not security critical, and we at least always @@ -1524,9 +1588,11 @@ DirectHandle<WasmTrustedInstanceData> WasmTrustedInstanceData::New( trusted_data->set_break_on_entry(module_object->script()->break_on_entry()); trusted_data->InitDataSegmentArrays(native_module.get()); trusted_data->set_memory0_start(empty_backing_store_buffer); - trusted_data->set_memory0_size(0); + trusted_data->set_memory0_size_or_address(0); trusted_data->set_memory_objects(*memory_objects); trusted_data->set_memory_bases_and_sizes(*memory_bases_and_sizes); + trusted_data->set_shared_memory_backing_stores( + *shared_memory_backing_stores); for (uint32_t i = 0; i < num_memories; ++i) { memory_bases_and_sizes->set( @@ -1548,17 +1614,6 @@ DirectHandle<WasmTrustedInstanceData> WasmTrustedInstanceData::New( instance_object->set_module_object(*module_object); trusted_data->set_instance_object(*instance_object); - // Insert the new instance into the script's weak list of instances. This - // list is used for breakpoints affecting all instances belonging to the - // script. - DCHECK_EQ(module_object->script()->type(), Script::Type::kWasm); - DirectHandle<WeakArrayList> weak_instance_list( - module_object->script()->wasm_weak_instance_list(), isolate); - weak_instance_list = - WeakArrayList::Append(isolate, weak_instance_list, - MaybeObjectDirectHandle::Weak(instance_object)); - module_object->script()->set_wasm_weak_instance_list(*weak_instance_list); - return trusted_data; } @@ -1996,8 +2051,7 @@ DirectHandle<WasmCustomMap> WasmCustomMap::AllocateUninitialized( DirectHandle<Map> rtt_parent{ Cast<Map>(trusted_data->managed_object_maps()->get(type.describes.index)), isolate}; - DirectHandle<NativeContext> context( - Cast<NativeContext>(trusted_data->native_context()), isolate); + DCHECK_EQ(trusted_data->native_context(), isolate->raw_native_context()); // There's always at least one supertype for {rtt_parent}. const wasm::TypeDefinition& described_type = module->type(type.describes); int num_supertypes = described_type.subtyping_depth + 1; @@ -2114,8 +2168,7 @@ DirectHandle<WasmCustomMapWrapper> WasmCustomMap::CreateJSWrapper( wasm::WasmValue WasmArray::GetElement(uint32_t index) { wasm::CanonicalValueType element_type = map()->wasm_type_info()->element_type(); - int element_offset = - WasmArray::kHeaderSize + index * element_type.value_kind_size(); + int element_offset = this->element_offset(index); Address element_address = this->field_address(element_offset); switch (element_type.kind()) { #define CASE_TYPE(value_type, ctype) \ @@ -2921,9 +2974,9 @@ std::unique_ptr<char[]> WasmExportedFunction::GetDebugName( constexpr const char kPrefix[] = "js-to-wasm:"; // prefix + parameters + delimiter + returns + zero byte size_t len = strlen(kPrefix) + sig->all().size() + 2; - auto buffer = base::OwnedVector<char>::New(len); + auto buffer = base::UniqueArray<char>::New(len); memcpy(buffer.begin(), kPrefix, strlen(kPrefix)); - PrintSignature(buffer.as_vector() + strlen(kPrefix), sig); + PrintSignature(buffer.subspan(strlen(kPrefix)), sig); return buffer.ReleaseData(); } @@ -3065,10 +3118,7 @@ bool WasmExternalFunction::IsWasmExternalFunction(Tagged<Object> object) { DirectHandle<WasmExceptionTag> WasmExceptionTag::New(Isolate* isolate, int index) { - auto result = Cast<WasmExceptionTag>(isolate->factory()->NewStruct( - WASM_EXCEPTION_TAG_TYPE, AllocationType::kOld)); - result->set_index(index); - return result; + return isolate->factory()->New<WasmExceptionTag, AllocationType::kOld>(index); } namespace { @@ -3412,10 +3462,17 @@ MaybeDirectHandle<Object> JSToWasmObject(Isolate* isolate, } DirectHandle<Object> WasmToJSObject(Isolate* isolate, - DirectHandle<Object> value) { + DirectHandle<Object> value, + UnshareStringsMode unshare_strings) { if (IsWasmNull(*value)) { return direct_handle(ReadOnlyRoots(isolate).null_value(), isolate); } +#ifdef V8_IS_TSAN + if (IsHeapObject(*value) && + HeapLayout::InWritableSharedSpace(Cast<HeapObject>(*value))) { + TSAN_ACQUIRE(Cast<HeapObject>(*value).address()); + } +#endif if (IsWasmFuncRef(*value)) { DirectHandle<WasmInternalFunction> internal( Cast<WasmFuncRef>(value)->internal(isolate), isolate); @@ -3427,9 +3484,11 @@ DirectHandle<Object> WasmToJSObject(Isolate* isolate, return WasmInternalFunction::GetOrCreateExternal(internal); } if (IsString(*value)) { - DirectHandle<String> string = Cast<String>(value); - if (HeapLayout::InWritableSharedSpace(*string)) { - return String::Unshare(isolate, string); + if (unshare_strings) { + DirectHandle<String> string = Cast<String>(value); + if (HeapLayout::InWritableSharedSpace(*string)) { + return String::Unshare(isolate, string); + } } } else if (IsWasmCustomMap(*value)) { DirectHandle<WasmCustomMap> map = Cast<WasmCustomMap>(value); @@ -3440,19 +3499,11 @@ DirectHandle<Object> WasmToJSObject(Isolate* isolate, return value; } -// The WasmArray header is not a multiple of 8 bytes. For shared i64 arrays each -// element needs to be 8 byte aligned for atomic accesses. Therefore shared -// arrays use the kDoubleUnaligned alignment. If the header size changes to a -// multiple of 8 bytes, shared arrays should be allocated using kDoubleAligned -// instead. -// Note that for 64 bit no-pointer-compression builds, kDoubleUnAligned performs -// aligned(!) allocations instead, so we manually align the kHeaderSize there. -// Needed changes in case the header size changes to a multiple of 8: -// - objects-inl.h: HeapObject::RequiredAlignment -// - wasm.tq: WasmAllocateSharedArray_Uninitialized +// For shared i64 arrays each element needs to be 8-byte aligned for atomic +// accesses, and shared arrays are allocated using kDoubleAligned. Therefore the +// shared WasmArray header size must be a multiple of 8 bytes. // LINT.IfChange -static_assert(WasmArray::kHeaderSize % kDoubleSize == - (kTaggedSize != kDoubleSize ? 4 : 0)); +static_assert(WasmArray::HeaderSize(SharedFlag{true}) % kDoubleSize == 0); // LINT.ThenChange(/src/objects/objects-inl.h, /src/builtins/wasm.tq) } // namespace wasm diff --git a/deps/v8/src/wasm/wasm-objects.h b/deps/v8/src/wasm/wasm-objects.h index 46b096c09a8d..55c84d031b0e 100644 --- a/deps/v8/src/wasm/wasm-objects.h +++ b/deps/v8/src/wasm/wasm-objects.h @@ -338,12 +338,12 @@ V8_OBJECT class WasmTableObject : public JSObject { TaggedMember<Smi> current_length_; TaggedMember<UnionOf<Smi, HeapNumber, BigInt, Undefined>> maximum_length_; TaggedMember<Smi> raw_type_; - TrustedPointerMember<WasmDispatchTable, kWasmDispatchTableIndirectPointerTag> + TrustedPointerMember<WasmDispatchTable, kWasmDispatchTableTrustedPointerTag> trusted_dispatch_table_; TrustedPointerMember<WasmTrustedInstanceData, - kWasmTrustedInstanceDataIndirectPointerTag> + kWasmTrustedInstanceDataTrustedPointerTag> trusted_data_; - uint8_t address_type_; + uint8_t address_type_ V8_TQ_TYPE(AddressType); uint8_t padding_for_address_type_0_; uint16_t padding_for_address_type_1_; #if TAGGED_SIZE_8_BYTES @@ -401,10 +401,10 @@ V8_OBJECT class WasmMemoryObject : public JSObject { inline CppGCManaged<BackingStore>::Ptr backing_store() const; // Add a use of this memory object to the given instance. This updates the - // internal weak list of instances that use this memory and also updates the - // fields of the instance to reference this memory's buffer. - // Note that we update both the non-shared and shared (if any) parts of the - // instance for faster access to shared memory. + // fields of the instance to reference this memory's buffer, and either + // keeps the BackingStore alive in trusted space (for shared memories) or + // records the instance in the weak `instances` list (for non-shared + // memories). V8_EXPORT_PRIVATE static void UseInInstance( Isolate* isolate, DirectHandle<WasmMemoryObject> memory, DirectHandle<WasmTrustedInstanceData> trusted_instance_data, @@ -428,8 +428,9 @@ V8_OBJECT class WasmMemoryObject : public JSObject { DirectHandle<WasmMemoryObject> memory, DirectHandle<JSArrayBuffer> new_buffer); - // Updates all WebAssembly instances that use this Memory as a memory, after - // growing or refreshing the memory. + // Updates all WebAssembly instances that use this (non-shared) Memory, after + // growing the memory. Shared memories do not need to update instances because + // their buffer start and byte_length_ address never change. void UpdateInstances(Isolate* isolate); // Fix up a resizable ArrayBuffer that exposes Wasm memory. @@ -483,8 +484,10 @@ V8_OBJECT class WasmMemoryObject : public JSObject { TaggedMember<UnionOf<JSArrayBuffer, Undefined>> array_buffer_; TaggedMember<CppGCManaged<BackingStore>> managed_backing_store_; TaggedMember<Smi> maximum_pages_; + // Weak list of instances using this memory (populated only for non-shared + // memories, since shared memories always grow in place). TaggedMember<WeakArrayList> instances_; - uint8_t address_type_; + uint8_t address_type_ V8_TQ_TYPE(AddressType); uint8_t padding_for_flags_0_; uint16_t padding_for_flags_1_; #if TAGGED_SIZE_8_BYTES @@ -546,7 +549,7 @@ V8_OBJECT class WasmGlobalObject : public JSObject { static const int kHeaderSize; TrustedPointerMember<WasmTrustedInstanceData, - kWasmTrustedInstanceDataIndirectPointerTag> + kWasmTrustedInstanceDataTrustedPointerTag> trusted_data_; TaggedMember<BufferType> buffer_; TaggedMember<Smi> offset_; @@ -617,7 +620,9 @@ V8_OBJECT class V8_EXPORT_PRIVATE WasmTrustedInstanceData DECL_ACCESSORS(feedback_vectors, Tagged<FixedArray>) DECL_ACCESSORS(well_known_imports, Tagged<FixedArray>) DECL_PRIMITIVE_ACCESSORS(memory0_start, uint8_t*) - DECL_PRIMITIVE_ACCESSORS(memory0_size, size_t) + // For unshared memory, stores the byte size directly. For shared memory, + // stores the address of the atomic byte length (std::atomic<size_t>*). + DECL_PRIMITIVE_ACCESSORS(memory0_size_or_address, Address) DECL_PROTECTED_POINTER_ACCESSORS(managed_native_module, TrustedManaged<wasm::NativeModule>) DECL_PRIMITIVE_ACCESSORS(jump_table_start, Address) @@ -625,6 +630,13 @@ V8_OBJECT class V8_EXPORT_PRIVATE WasmTrustedInstanceData DECL_PRIMITIVE_ACCESSORS(tiering_budget_array, std::atomic<uint32_t>*) DECL_PROTECTED_POINTER_ACCESSORS(memory_bases_and_sizes, TrustedFixedAddressArray) + // Indexed by memory index: holds a TrustedManaged<BackingStore> for each + // shared memory (and Smi::zero() for non-shared memories) to keep the + // BackingStore and its atomic byte_length_ (referenced by + // memory0_size_or_address and memory_bases_and_sizes) alive from trusted + // space. Empty if the module has no shared memories. + DECL_PROTECTED_POINTER_ACCESSORS(shared_memory_backing_stores, + ProtectedFixedArray) DECL_PROTECTED_POINTER_ACCESSORS(data_segments, TrustedPodArray<wasm::WireBytesRef>) DECL_ACCESSORS(element_segments, Tagged<FixedArray>) @@ -659,7 +671,7 @@ V8_OBJECT class V8_EXPORT_PRIVATE WasmTrustedInstanceData /* Optional padding to align system pointer size fields */ \ V(kOptionalPaddingOffset, POINTER_SIZE_PADDING(kOptionalPaddingOffset)) \ V(kMemory0StartOffset, kSystemPointerSize) \ - V(kMemory0SizeOffset, kSizetSize) \ + V(kMemory0SizeOrAddressOffset, kSystemPointerSize) \ V(kJumpTableStartOffset, kSystemPointerSize) \ /* End of often-accessed fields. */ \ /* Continue with system pointer size fields to maintain alignment. */ \ @@ -667,6 +679,7 @@ V8_OBJECT class V8_EXPORT_PRIVATE WasmTrustedInstanceData V(kTieringBudgetArrayOffset, kSystemPointerSize) \ /* Less than system pointer size aligned fields are below. */ \ V(kProtectedMemoryBasesAndSizesOffset, kTaggedSize) \ + V(kProtectedSharedMemoryBackingStoresOffset, kTaggedSize) \ V(kProtectedDataSegmentsOffset, kTaggedSize) \ V(kElementSegmentsOffset, kTaggedSize) \ V(kInstanceObjectOffset, kTaggedSize) \ @@ -721,15 +734,16 @@ V8_OBJECT class V8_EXPORT_PRIVATE WasmTrustedInstanceData IF_WASM_DRUMBRAKE(V, kImportedFunctionIndicesOffset, \ "imported_function_indices") \ V(kElementSegmentsOffset, "element_segments") -#define WASM_PROTECTED_INSTANCE_DATA_FIELDS(V) \ - V(kProtectedMemoryBasesAndSizesOffset, "memory_bases_and_sizes") \ - V(kProtectedDataSegmentsOffset, "data_segments") \ - V(kProtectedDispatchTable0Offset, "dispatch_table0") \ - V(kProtectedDispatchTablesOffset, "dispatch_tables") \ - V(kProtectedDispatchTableForImportsOffset, "dispatch_table_for_imports") \ - V(kProtectedTagsTableOffset, "tags_table") \ - IF_WASM_DRUMBRAKE(V, kProtectedInterpreterHandleOffset, \ - "interpreter_handle") \ +#define WASM_PROTECTED_INSTANCE_DATA_FIELDS(V) \ + V(kProtectedMemoryBasesAndSizesOffset, "memory_bases_and_sizes") \ + V(kProtectedSharedMemoryBackingStoresOffset, "shared_memory_backing_stores") \ + V(kProtectedDataSegmentsOffset, "data_segments") \ + V(kProtectedDispatchTable0Offset, "dispatch_table0") \ + V(kProtectedDispatchTablesOffset, "dispatch_tables") \ + V(kProtectedDispatchTableForImportsOffset, "dispatch_table_for_imports") \ + V(kProtectedTagsTableOffset, "tags_table") \ + IF_WASM_DRUMBRAKE(V, kProtectedInterpreterHandleOffset, \ + "interpreter_handle") \ V(kProtectedManagedNativeModuleOffset, "managed_native_module") #define WASM_INSTANCE_FIELD_OFFSET(offset, _) offset, @@ -765,8 +779,15 @@ V8_OBJECT class V8_EXPORT_PRIVATE WasmTrustedInstanceData static_assert(kProtectedFieldOffsets.size() == kProtectedFieldNames.size(), "every protected field offset needs a name"); - void SetRawMemory(uint32_t memory_index, uint8_t* mem_start, size_t mem_size); - + // Sets memory base and size/address for {memory_index}. + // For unshared memories, {size_or_address} is the byte length. + // For shared memories, it is the Address of the backing store's atomic + // byte_length_ (std::atomic<size_t>*), and shared_memory_backing_stores() + // must already hold the corresponding TrustedManaged<BackingStore> at + // {memory_index}. To read the actual byte length, callers must use + // memory_size(index). + void SetRawMemory(uint32_t memory_index, uint8_t* mem_start, + Address size_or_address); static DirectHandle<WasmTrustedInstanceData> New( Isolate*, DirectHandle<WasmModuleObject>, @@ -851,7 +872,7 @@ V8_OBJECT class WasmInstanceObject : public JSObject { static const int kHeaderSize; TrustedPointerMember<WasmTrustedInstanceData, - kWasmTrustedInstanceDataIndirectPointerTag> + kWasmTrustedInstanceDataTrustedPointerTag> trusted_data_; TaggedMember<WasmModuleObject> module_object_; TaggedMember<JSObject> exports_object_; @@ -900,7 +921,7 @@ V8_OBJECT class WasmTagObject : public JSObject { TaggedMember<HeapObject> tag_; TaggedMember<Smi> canonical_type_index_; TrustedPointerMember<WasmTrustedInstanceData, - kWasmTrustedInstanceDataIndirectPointerTag> + kWasmTrustedInstanceDataTrustedPointerTag> trusted_data_; } V8_OBJECT_END; @@ -1413,7 +1434,7 @@ V8_OBJECT class WasmImportData : public TrustedObject { TaggedMember<NativeContext> native_context_; TaggedMember<UnionOf<JSReceiver, Undefined>> callable_; TaggedMember<Cell> wrapper_budget_; - UnalignedValueMember<Address> sig_; + UnalignedValueMember<Address> sig_ V8_TQ_TYPE(RawFunctionSigPtr); uint32_t bit_field_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; @@ -1423,6 +1444,8 @@ V8_OBJECT class WasmImportData : public TrustedObject { inline constexpr int WasmImportData::kHeaderSize = sizeof(WasmImportData); inline constexpr int WasmImportData::kSize = sizeof(WasmImportData); +using WasmImplicitArg = UnionOf<WasmTrustedInstanceData, WasmImportData>; + V8_OBJECT class WasmInternalFunction : public ExposedTrustedObject { public: // Get the external function if it exists. Returns true and writes to the @@ -1437,7 +1460,7 @@ V8_OBJECT class WasmInternalFunction : public ExposedTrustedObject { // target instance data (for wasm functions), or a WasmImportData object (for // non-wasm imports). For imported functions, this value equals the respective // entry in the module's dispatch_table_for_imports. - DECL_PROTECTED_POINTER_ACCESSORS(implicit_arg, TrustedObject) + DECL_PROTECTED_POINTER_ACCESSORS(implicit_arg, WasmImplicitArg) // Returns the instance data associated with the implicit_arg. // If the implicit_arg is a WasmTrustedInstanceData, it is returned directly. @@ -1475,14 +1498,15 @@ V8_OBJECT class WasmInternalFunction : public ExposedTrustedObject { static const int kSize; public: - ProtectedTaggedMember<TrustedObject> protected_implicit_arg_; + ProtectedTaggedMember<UnionOf<WasmTrustedInstanceData, WasmImportData>> + protected_implicit_arg_; TaggedMember<UnionOf<JSFunction, Undefined>> external_; TaggedMember<Smi> function_index_; - uint32_t raw_call_target_; + WasmCodePointer raw_call_target_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif // TAGGED_SIZE_8_BYTES - UnalignedValueMember<Address> sig_; + UnalignedValueMember<Address> sig_ V8_TQ_TYPE(RawFunctionSigPtr); } V8_OBJECT_END; inline constexpr int WasmInternalFunction::kHeaderSize = @@ -1510,7 +1534,7 @@ V8_OBJECT class WasmFuncRef : public HeapObject { static const int kSize; TrustedPointerMember<WasmInternalFunction, - kWasmInternalFunctionIndirectPointerTag> + kWasmInternalFunctionTrustedPointerTag> trusted_internal_; } V8_OBJECT_END; @@ -1565,7 +1589,7 @@ V8_OBJECT class WasmResumeData : public HeapObject { static const int kHeaderSize; static const int kSize; - TrustedPointerMember<WasmSuspenderObject, kWasmSuspenderIndirectPointerTag> + TrustedPointerMember<WasmSuspenderObject, kWasmSuspenderTrustedPointerTag> trusted_suspender_; TaggedMember<Smi> on_resume_; } V8_OBJECT_END; @@ -1645,11 +1669,12 @@ class WasmScript : public AllStatic { // - {WasmInstanceObject::tags_table}: List of tags used by an instance. V8_OBJECT class WasmExceptionTag : public Struct { public: + inline WasmExceptionTag(const AllocationWitness& witness, int index); + V8_EXPORT_PRIVATE static DirectHandle<WasmExceptionTag> New(Isolate* isolate, int index); inline int index() const; - inline void set_index(int value); using BodyDescriptor = StructBodyDescriptor; @@ -1659,7 +1684,7 @@ V8_OBJECT class WasmExceptionTag : public Struct { private: friend class TorqueGeneratedWasmExceptionTagAsserts; - TaggedMember<Smi> index_; + const TaggedMember<Smi> index_; } V8_OBJECT_END; V8_OBJECT class WasmTypeInfo : public HeapObject { @@ -1694,7 +1719,8 @@ V8_OBJECT class WasmTypeInfo : public HeapObject { uint32_t canonical_type_; uint32_t canonical_element_type_; - TaggedMember<Smi> supertypes_length_; + V8_TQ_CONST TaggedMember<Smi> supertypes_length_; + V8_TQ_TAIL_LENGTH(supertypes_length); FLEXIBLE_ARRAY_MEMBER(TaggedMember<Object>, supertypes); } V8_OBJECT_END; @@ -1766,9 +1792,13 @@ V8_OBJECT class WasmStruct : public WasmObject { class BodyDescriptor; static const int kHeaderSize; + static const int kMaxInstanceSize; } V8_OBJECT_END; inline constexpr int WasmStruct::kHeaderSize = sizeof(WasmStruct); +inline constexpr int WasmStruct::kMaxInstanceSize = + WasmStruct::kHeaderSize + + wasm::kMaxValueTypeSize * wasm::kV8MaxWasmStructFields; int WasmStruct::Size(const wasm::StructType* type) { // Object size must fit into a Smi (because of runtime functions), and its @@ -1827,15 +1857,28 @@ V8_OBJECT class WasmCustomMap : public Map { class BodyDescriptor; static const int kHeaderSize; + static const int kMaxInstanceSize; TaggedMember<Union<WasmCustomMapWrapper, Null>> js_wrapper_; // To save memory, we could store the NativeContext in the {js_wrapper} field // before allocating the wrapper, but that would make checking for the // wrapper's presence more expensive. + // We currently also need the NC for prototype chain validity cells. + // TODO(jkummerow): Find a more elegant solution. TaggedMember<NativeContext> native_context_for_wrapper_; } V8_OBJECT_END; inline constexpr int WasmCustomMap::kHeaderSize = sizeof(WasmCustomMap); +inline constexpr int WasmCustomMap::kMaxInstanceSize = + WasmCustomMap::kHeaderSize + + wasm::kMaxValueTypeSize * wasm::kV8MaxWasmStructFields; + +int WasmStruct::FieldOffset(const wasm::StructType* type, int field_index) { + int header_size = type->is_descriptor() && v8_flags.wasm_merged_descriptors + ? WasmCustomMap::kHeaderSize + : WasmStruct::kHeaderSize; + return header_size + type->field_offset(field_index); +} int WasmCustomMap::Size(const wasm::StructType* type) { // Object size must fit into a Smi (because of runtime functions), and its @@ -1889,8 +1932,19 @@ V8_OBJECT class WasmArray : public WasmObject { inline ObjectSlot ElementSlot(uint32_t index); V8_EXPORT_PRIVATE wasm::WasmValue GetElement(uint32_t index); + // Unshared WasmArrays have a 12-byte header (when kTaggedSize == 4). Shared + // WasmArrays are allocated with 8-byte alignment (`kDoubleAligned`, which is + // also the only alignment supported by Large Object Space) and pad their + // header to a multiple of 8 bytes (`kDoubleSize`, i.e. 16 bytes when + // kTaggedSize == 4), so that their elements are 8-byte aligned as required + // for atomic 8-byte-wide accesses on some platforms. + static constexpr int HeaderSize(SharedFlag is_shared); + static inline int HeaderSize(Tagged<Map> map); + inline int header_size() const; + static inline int SizeFor(Tagged<Map> map, int length); - static constexpr int SizeFor(int element_size, int length); + static constexpr int SizeFor(int element_size, int length, + SharedFlag is_shared); // Returns boxed value of the array's element. static inline DirectHandle<Object> GetElement(Isolate* isolate, @@ -1904,14 +1958,7 @@ V8_OBJECT class WasmArray : public WasmObject { inline uint32_t element_offset(uint32_t index); inline Address ElementAddress(uint32_t index); - static constexpr int MaxLength(uint32_t element_size_bytes) { - // The total object size must fit into a Smi, for filler objects. To make - // the behavior of Wasm programs independent from the Smi configuration, - // we hard-code the smaller of the two supported ranges. - return RoundDown( - (int{SmiTagging<4>::kSmiMaxValue} - kHeaderSize) / element_size_bytes, - kTaggedSize); - } + static constexpr int MaxLength(uint32_t element_size_bytes); static int MaxLength(const wasm::ArrayType* type) { return MaxLength(type->element_type().value_kind_size()); @@ -1925,22 +1972,39 @@ V8_OBJECT class WasmArray : public WasmObject { class BodyDescriptor; - static const int kHeaderSize; - uint32_t length_; #if TAGGED_SIZE_8_BYTES uint32_t optional_padding_; #endif + + private: + static const int kHeaderSize; // Use {HeaderSize(...)} instead. } V8_OBJECT_END; -inline constexpr int WasmArray::kHeaderSize = sizeof(WasmArray); +constexpr int WasmArray::HeaderSize(SharedFlag is_shared) { + return is_shared ? RoundUp(int{sizeof(WasmArray)}, kDoubleSize) + : sizeof(WasmArray); +} + +constexpr int WasmArray::MaxLength(uint32_t element_size_bytes) { + // The total object size must fit into a Smi, for filler objects. To make + // the behavior of Wasm programs independent from the Smi configuration, + // we hard-code the smaller of the two supported ranges. We use the larger + // shared header size so that the maximum length is independent of + // sharedness. + return RoundDown( + (int{SmiTagging<4>::kSmiMaxValue} - HeaderSize(SharedFlag{true})) / + element_size_bytes, + kTaggedSize); +} // The suspender object provides an API to suspend and resume wasm code using // promises. See: https://github.com/WebAssembly/js-promise-integration. V8_OBJECT class WasmSuspenderObject : public ExposedTrustedObject { public: enum State : int { kInactive = 0, kActive, kSuspended }; - DECL_EXTERNAL_POINTER_ACCESSORS(stack, wasm::StackMemory*) + inline wasm::StackMemory* stack() const; + inline void set_stack(wasm::StackMemory* value); DECL_PROTECTED_POINTER_ACCESSORS(parent, WasmSuspenderObject) inline Tagged<UnionOf<JSPromise, Undefined>> promise() const; @@ -1964,7 +2028,7 @@ V8_OBJECT class WasmSuspenderObject : public ExposedTrustedObject { static const int kSize; public: - ExternalPointerMember<kWasmStackMemoryTag> stack_; + UnalignedValueMember<Address> stack_; ProtectedTaggedMember<WasmSuspenderObject> parent_; TaggedMember<UnionOf<JSPromise, Undefined>> promise_; TaggedMember<UnionOf<JSObject, Undefined>> resume_; @@ -2048,8 +2112,8 @@ V8_OBJECT class WasmFastApiCallData : public HeapObject { inline void set_callback_data(Tagged<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline Tagged<MaybeObject> cached_map() const; - inline void set_cached_map(Tagged<MaybeObject> value, + inline Tagged<UnionOf<Null, Weak<Map>>> cached_map() const; + inline void set_cached_map(Tagged<UnionOf<Null, Weak<Map>>> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); DECL_PRINTER(WasmFastApiCallData) @@ -2061,7 +2125,7 @@ V8_OBJECT class WasmFastApiCallData : public HeapObject { TaggedMember<HeapObject> signature_; TaggedMember<Object> callback_data_; - TaggedMember<MaybeObject> cached_map_; + TaggedMember<UnionOf<Null, Weak<Map>>> cached_map_; } V8_OBJECT_END; V8_OBJECT class WasmStringViewIter : public HeapObject { @@ -2120,7 +2184,7 @@ V8_OBJECT class WasmNull : public HeapObject { // If {opt_native_context} is not null, creates a contextful map bound to // that context; otherwise creates a context-independent map (which must then // not point to any context-specific objects!). -DirectHandle<Map> CreateStructMap( +V8_EXPORT_PRIVATE DirectHandle<Map> CreateStructMap( Isolate* isolate, wasm::CanonicalTypeIndex type, DirectHandle<Map> opt_rtt_parent, int num_supertypes, DirectHandle<NativeContext> opt_native_context); @@ -2154,11 +2218,16 @@ MaybeDirectHandle<Object> JSToWasmObject(Isolate* isolate, ValueType expected, const char** error_message); +enum UnshareStringsMode : bool { + kKeepSharedStrings = false, + kUnshareStrings = true +}; // Takes a {value} in the Wasm representation and transforms it to the // respective JS representation. The caller is responsible for not providing an // object which cannot be transformed to JS. DirectHandle<Object> WasmToJSObject(Isolate* isolate, - DirectHandle<Object> value); + DirectHandle<Object> value, + UnshareStringsMode unshare_strings); } // namespace wasm } // namespace internal diff --git a/deps/v8/src/wasm/wasm-objects.tq b/deps/v8/src/wasm/wasm-objects.tq index 30d05f7537a2..fd55e6215fd3 100644 --- a/deps/v8/src/wasm/wasm-objects.tq +++ b/deps/v8/src/wasm/wasm-objects.tq @@ -166,7 +166,7 @@ extern class WasmResumeData extends HeapObject { @cppObjectLayoutDefinition extern class WasmSuspenderObject extends ExposedTrustedObject { - stack: ExternalPointer; + stack: RawPtr; parent: ProtectedPointer<WasmSuspenderObject>; promise: JSPromise|Undefined; resume: JSObject|Undefined; diff --git a/deps/v8/src/wasm/wasm-result.cc b/deps/v8/src/wasm/wasm-result.cc index 7219894a8b4a..5cfbd086d49e 100644 --- a/deps/v8/src/wasm/wasm-result.cc +++ b/deps/v8/src/wasm/wasm-result.cc @@ -4,6 +4,8 @@ #include "src/wasm/wasm-result.h" +#include <bit> + #include "src/base/strings.h" #include "src/execution/isolate-inl.h" #include "src/heap/factory.h" @@ -21,7 +23,7 @@ void VPrintFToString(std::string* str, size_t str_offset, const char* format, DCHECK_LE(str_offset, str->size()); size_t len = str_offset + strlen(format); // Allocate increasingly large buffers until the message fits. - for (;; len = base::bits::RoundUpToPowerOfTwo64(len + 1)) { + for (;; len = std::bit_ceil(len + 1)) { DCHECK_GE(kMaxInt, len); str->resize(len); va_list args_copy; @@ -126,9 +128,7 @@ DirectHandle<JSObject> ErrorThrower::Reify() { break; } DirectHandle<String> message = - isolate_->factory() - ->NewStringFromUtf8(base::VectorOf(error_msg_)) - .ToHandleChecked(); + isolate_->factory()->NewStringFromUtf8(error_msg_).ToHandleChecked(); Reset(); return isolate_->factory()->NewError(constructor, message); } diff --git a/deps/v8/src/wasm/wasm-serialization.cc b/deps/v8/src/wasm/wasm-serialization.cc index de8e70d82b0f..f9d9b065496f 100644 --- a/deps/v8/src/wasm/wasm-serialization.cc +++ b/deps/v8/src/wasm/wasm-serialization.cc @@ -4,11 +4,13 @@ #include "src/wasm/wasm-serialization.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler-arch.h" #include "src/codegen/assembler-inl.h" #include "src/debug/debug.h" #include "src/runtime/runtime.h" #include "src/snapshot/snapshot-data.h" +#include "src/trap-handler/trap-handler.h" #include "src/utils/ostreams.h" #include "src/utils/version.h" #include "src/wasm/code-space-access.h" @@ -130,7 +132,7 @@ class Reader { size_t MeasureHeader(const CompileTimeImports& compile_imports) { return 5 * kUInt32Size + // magic number, version hash, cpu features, flags - // hash, enabled features + // hash, enabled features (incl. trap handler) sizeof(typename CompileTimeImportFlags::StorageType) + sizeof(uint32_t) + // length of constants_module. compile_imports.constants_module().size(); @@ -143,7 +145,16 @@ void WriteHeader(Writer* writer, WasmEnabledFeatures enabled_features, writer->Write(Version::Hash()); writer->Write(CpuFeatures::SupportedFeatures().ToIntegral()); writer->Write(FlagList::Hash()); - writer->Write(enabled_features.ToIntegral()); + // Code compiled for the trap handler relies on it for bounds and null checks, + // and embedders enable the trap handler independently of the flags, so its + // state is stored in the most significant bit of the enabled features. + constexpr uint32_t kTrapHandlerBit = uint32_t{1} << 31; + static_assert( + (static_cast<uint32_t>(WasmEnabledFeatures::All().ToIntegral()) & + kTrapHandlerBit) == 0); + uint32_t features = static_cast<uint32_t>(enabled_features.ToIntegral()); + if (trap_handler::IsTrapHandlerEnabled()) features |= kTrapHandlerBit; + writer->Write(features); writer->Write(compile_imports.flags().ToIntegral()); const std::string& constants_module = compile_imports.constants_module(); writer->Write(static_cast<uint32_t>(constants_module.size())); @@ -322,7 +333,7 @@ static_assert(std::is_trivially_destructible_v<ExternalReferenceList>, // Translate the signature IDs in the effect handler table from canonical to // module-relative or vice-versa. template <typename TranslateSigIdCallback> -base::OwnedVector<uint8_t> TranslateEffectHandlersTable( +base::UniqueArray<uint8_t> TranslateEffectHandlersTable( base::Vector<const uint8_t> effect_handlers, TranslateSigIdCallback translate_sig_id) { if (effect_handlers.empty()) return {}; @@ -362,7 +373,7 @@ base::OwnedVector<uint8_t> TranslateEffectHandlersTable( } } - return base::OwnedVector<uint8_t>::NewByCopying(result.data(), result.size()); + return base::UniqueArray<uint8_t>::CopiedFrom(result); } } // namespace @@ -385,7 +396,7 @@ class V8_EXPORT_PRIVATE NativeModuleSerializer { void WriteTieringBudget(Writer* writer); uint32_t CanonicalSigIdToModuleLocalTypeId(uint32_t canonical_sig_id); - base::OwnedVector<uint8_t> TranslateEffectHandlersToModuleRelative( + base::UniqueArray<uint8_t> TranslateEffectHandlersToModuleRelative( base::Vector<const uint8_t> effect_handlers); const NativeModule* const native_module_; @@ -395,7 +406,7 @@ class V8_EXPORT_PRIVATE NativeModuleSerializer { std::unordered_map<uint32_t, uint32_t> canonical_sig_ids_to_module_local_ids_; // Effect handler tables with canonical signature indices translated to // module-relative indices. - std::unordered_map<const WasmCode*, base::OwnedVector<uint8_t>> + std::unordered_map<const WasmCode*, base::UniqueArray<uint8_t>> translated_effect_handlers_; bool write_called_ = false; size_t total_written_code_ = 0; @@ -429,7 +440,7 @@ size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) { return sizeof(uint8_t); } - base::OwnedVector<uint8_t> effect_handlers = + base::UniqueArray<uint8_t> effect_handlers = TranslateEffectHandlersToModuleRelative(code->effect_handlers()); size_t effect_handlers_size = effect_handlers.size(); translated_effect_handlers_.emplace(code, std::move(effect_handlers)); @@ -463,9 +474,6 @@ size_t NativeModuleSerializer::Measure() { void NativeModuleSerializer::WriteHeader(Writer* writer, size_t total_code_size) { - // TODO(eholk): We need to properly preserve the flag whether the trap - // handler was used or not when serializing. - // Serialize the set of detected features; this contains // - all features detected during module decoding, // - all features detected during function body decoding, and @@ -538,7 +546,7 @@ void NativeModuleSerializer::WriteCode( // We always call Measure() before serializing the module, so the map should // already be filled. DCHECK_NE(it, translated_effect_handlers_.end()); - base::Vector<const uint8_t> effect_handlers = it->second.as_vector(); + base::Vector<const uint8_t> effect_handlers = it->second.as_span(); writer->Write(static_cast<uint32_t>(effect_handlers.size())); writer->Write(code->kind()); writer->Write(code->tier()); @@ -680,7 +688,7 @@ uint32_t NativeModuleSerializer::CanonicalSigIdToModuleLocalTypeId( return it->second; } -base::OwnedVector<uint8_t> +base::UniqueArray<uint8_t> NativeModuleSerializer::TranslateEffectHandlersToModuleRelative( base::Vector<const uint8_t> effect_handlers) { return TranslateEffectHandlersTable(effect_handlers, [this](uint32_t sig) { @@ -816,7 +824,7 @@ class V8_EXPORT_PRIVATE NativeModuleDeserializer { void CopyAndRelocate(const DeserializationUnit& unit); void Publish(std::vector<DeserializationUnit> batch); - base::OwnedVector<uint8_t> TranslateEffectHandlersToCanonical( + base::UniqueArray<uint8_t> TranslateEffectHandlersToCanonical( base::Vector<const uint8_t> effect_handlers); NativeModule* const native_module_; @@ -1036,7 +1044,7 @@ DeserializationUnit NativeModuleDeserializer::ReadCode(int fn_index, auto trapping_instructions = reader->ReadVector<uint8_t>(trapping_instructions_size); auto raw_effect_handlers = reader->ReadVector<uint8_t>(effect_handlers_size); - base::OwnedVector<uint8_t> effect_handlers = + base::UniqueArray<uint8_t> effect_handlers = TranslateEffectHandlersToCanonical(raw_effect_handlers); base::Vector<uint8_t> instructions = @@ -1049,12 +1057,12 @@ DeserializationUnit NativeModuleDeserializer::ReadCode(int fn_index, tagged_parameter_slots, safepoint_table_offset, handler_table_offset, constant_pool_offset, code_comment_offset, jump_table_info_offset, unpadded_binary_size, trapping_instructions, reloc_info, source_pos, - inlining_pos, deopt_data, kind, tier, effect_handlers.as_vector()); + inlining_pos, deopt_data, kind, tier, effect_handlers.as_span()); unit.jump_tables = current_jump_tables_; return unit; } -base::OwnedVector<uint8_t> +base::UniqueArray<uint8_t> NativeModuleDeserializer::TranslateEffectHandlersToCanonical( base::Vector<const uint8_t> effect_handlers) { return TranslateEffectHandlersTable(effect_handlers, [this](uint32_t sig) { @@ -1199,15 +1207,14 @@ bool HeaderMatches(base::Vector<const uint8_t> data, MaybeDirectHandle<WasmModuleObject> DeserializeNativeModule( Isolate* isolate, WasmEnabledFeatures enabled_features, base::Vector<const uint8_t> data, - base::OwnedVector<const uint8_t>& wire_bytes_vec, - const CompileTimeImports& compile_imports, - base::Vector<const char> source_url) { + base::UniqueArray<const uint8_t>& wire_bytes_vec, + const CompileTimeImports& compile_imports, std::string_view source_url) { if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) return {}; if (!HeaderMatches(data, enabled_features, compile_imports)) return {}; WasmDetectedFeatures detected_features; ModuleResult decode_result = - DecodeWasmModule(isolate, enabled_features, wire_bytes_vec.as_vector(), + DecodeWasmModule(isolate, enabled_features, wire_bytes_vec.as_span(), false, DecodingMethod::kDeserialize, &detected_features); // The wire bytes were previously considered valid for the same enabled // features (checked above). @@ -1217,7 +1224,7 @@ MaybeDirectHandle<WasmModuleObject> DeserializeNativeModule( WasmEngine* wasm_engine = GetWasmEngine(); std::shared_ptr<NativeModule> shared_native_module = - wasm_engine->MaybeGetNativeModule(wire_bytes_vec.as_vector(), + wasm_engine->MaybeGetNativeModule(wire_bytes_vec.as_span(), enabled_features, compile_imports); if (shared_native_module) { // For consistency, take ownership of the passed `wire_bytes_vec` also when @@ -1261,7 +1268,7 @@ MaybeDirectHandle<WasmModuleObject> DeserializeNativeModule( isolate->debug()->OnAfterCompile(script); // Log the code within the generated module for profiling. - shared_native_module->LogWasmCodes(isolate, *script); + shared_native_module->LogWasmCodes(isolate, script); return module_object; } diff --git a/deps/v8/src/wasm/wasm-serialization.h b/deps/v8/src/wasm/wasm-serialization.h index 31becd542dd6..998fc3fe3086 100644 --- a/deps/v8/src/wasm/wasm-serialization.h +++ b/deps/v8/src/wasm/wasm-serialization.h @@ -9,6 +9,9 @@ #error This header should only be included if WebAssembly is enabled. #endif // !V8_ENABLE_WEBASSEMBLY +#include <string_view> + +#include "src/base/unique-array.h" #include "src/wasm/wasm-code-manager.h" namespace v8::internal::wasm { @@ -32,7 +35,8 @@ class V8_EXPORT_PRIVATE WasmSerializer { // [1] version hash (uint32_t) // [2] supported CPU features (uint32_t) // [3] flag hash (uint32_t) - // [4] enabled features (via flags and OT) (uint32_t) + // [4] enabled features (via flags and OT), with the trap handler state in the + // most significant bit (uint32_t) // [5] compile time imports (variable size) static constexpr size_t kVersionHashOffset = kUInt32Size; @@ -50,9 +54,8 @@ class V8_EXPORT_PRIVATE WasmSerializer { // vector); otherwise ownership stays with the caller. V8_EXPORT_PRIVATE MaybeDirectHandle<WasmModuleObject> DeserializeNativeModule( Isolate*, WasmEnabledFeatures, base::Vector<const uint8_t> data, - base::OwnedVector<const uint8_t>& wire_bytes, - const CompileTimeImports& compile_imports, - base::Vector<const char> source_url); + base::UniqueArray<const uint8_t>& wire_bytes, + const CompileTimeImports& compile_imports, std::string_view source_url); } // namespace v8::internal::wasm diff --git a/deps/v8/src/wasm/wasm-subtyping.cc b/deps/v8/src/wasm/wasm-subtyping.cc index 1956c8d004c9..77ed23e676a0 100644 --- a/deps/v8/src/wasm/wasm-subtyping.cc +++ b/deps/v8/src/wasm/wasm-subtyping.cc @@ -10,14 +10,15 @@ namespace v8::internal::wasm { -namespace { - -V8_INLINE bool EquivalentIndices(ModuleTypeIndex index1, ModuleTypeIndex index2, - const WasmModule* module) { +bool EquivalentIndices(ModuleTypeIndex index1, ModuleTypeIndex index2, + const WasmModule* module) { if (index1 == index2) return true; + if (!index1.valid() || !index2.valid()) return false; return module->canonical_type_id(index1) == module->canonical_type_id(index2); } +namespace { + bool ValidStructSubtypeDefinition(ModuleTypeIndex subtype_index, ModuleTypeIndex supertype_index, const WasmModule* module) { @@ -46,7 +47,8 @@ bool ValidStructSubtypeDefinition(ModuleTypeIndex subtype_index, // and the supertype's descriptor must be a declared supertype of the // subtype's descriptor. if (!super_def.descriptor.valid()) return false; - if (module->supertype(sub_def.descriptor) != super_def.descriptor) { + if (!EquivalentIndices(module->supertype(sub_def.descriptor), + super_def.descriptor, module)) { return false; } } else { @@ -57,7 +59,8 @@ bool ValidStructSubtypeDefinition(ModuleTypeIndex subtype_index, // If a type is a descriptor, its supertype must also be a descriptor, and // must describe a declared supertype of the subtype's described type. if (!super_def.describes.valid()) return false; - if (module->supertype(sub_def.describes) != super_def.describes) { + if (!EquivalentIndices(module->supertype(sub_def.describes), + super_def.describes, module)) { return false; } } else { diff --git a/deps/v8/src/wasm/wasm-subtyping.h b/deps/v8/src/wasm/wasm-subtyping.h index c910da80b4c6..b1d9e47c8106 100644 --- a/deps/v8/src/wasm/wasm-subtyping.h +++ b/deps/v8/src/wasm/wasm-subtyping.h @@ -38,6 +38,10 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool EquivalentTypes(ValueType type1, const WasmModule* module1, const WasmModule* module2); +V8_EXPORT_PRIVATE bool EquivalentIndices(ModuleTypeIndex index1, + ModuleTypeIndex index2, + const WasmModule* module); + // Checks if {subtype}, defined in {module1}, is a subtype of {supertype}, // defined in {module2}. // Subtyping between value types is described by the following rules diff --git a/deps/v8/src/wasm/wasm-value.h b/deps/v8/src/wasm/wasm-value.h index 076e1a40ae35..f7fa749049bc 100644 --- a/deps/v8/src/wasm/wasm-value.h +++ b/deps/v8/src/wasm/wasm-value.h @@ -165,6 +165,7 @@ class WasmValue { if (!(byte & 0xf0)) stream << '0'; stream << static_cast<uint32_t>(byte); } + stream << std::dec; return stream.str(); } case kRefNull: diff --git a/deps/v8/src/wasm/wasm-wrapper-cache-inl.h b/deps/v8/src/wasm/wasm-wrapper-cache-inl.h index 11bbf70a0bb2..34fd160e1cc1 100644 --- a/deps/v8/src/wasm/wasm-wrapper-cache-inl.h +++ b/deps/v8/src/wasm/wasm-wrapper-cache-inl.h @@ -91,11 +91,11 @@ WasmCode* WasmWrapperCache<CacheKey>::ModificationScope::AddWrapper( code_comments_offset, jump_table_info_offset, instr_size, - result.trapping_instructions_data.as_vector(), + result.trapping_instructions_data.as_span(), reloc_info, - result.source_positions.as_vector(), - result.inlining_positions.as_vector(), - result.deopt_data.as_vector(), + result.source_positions.as_span(), + result.inlining_positions.as_span(), + result.deopt_data.as_span(), kind, ExecutionTier::kNone, wasm::kNotForDebugging, diff --git a/deps/v8/src/zone/zone-chunk-list.h b/deps/v8/src/zone/zone-chunk-list.h deleted file mode 100644 index e73ef5e2a884..000000000000 --- a/deps/v8/src/zone/zone-chunk-list.h +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright 2016 the V8 project 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 V8_ZONE_ZONE_CHUNK_LIST_H_ -#define V8_ZONE_ZONE_CHUNK_LIST_H_ - -#include <algorithm> - -#include "src/base/iterator.h" -#include "src/common/globals.h" -#include "src/utils/memcopy.h" -#include "src/zone/zone.h" - -namespace v8 { -namespace internal { - -template <typename T, bool backwards, bool modifiable> -class ZoneChunkListIterator; - -// A zone-backed hybrid of a vector and a linked list. Use it if you need a -// collection that -// * needs to grow indefinitely, -// * will mostly grow at the back, but may sometimes grow in front as well -// (preferably in batches), -// * needs to have very low overhead, -// * offers forward- and backwards-iteration, -// * offers relatively fast seeking, -// * offers bidirectional iterators, -// * can be rewound without freeing the backing store, -// * can be split and joined again efficiently. -// This list will maintain a doubly-linked list of chunks. When a chunk is -// filled up, a new one gets appended. New chunks appended at the end will -// grow in size up to a certain limit to avoid over-allocation and to keep -// the zone clean. Chunks may be partially filled. In particular, chunks may -// be empty after rewinding, such that they can be reused when inserting -// again at a later point in time. -template <typename T> -class ZoneChunkList : public ZoneObject { - public: - using iterator = ZoneChunkListIterator<T, false, true>; - using const_iterator = ZoneChunkListIterator<T, false, false>; - using reverse_iterator = ZoneChunkListIterator<T, true, true>; - using const_reverse_iterator = ZoneChunkListIterator<T, true, false>; - - static constexpr uint32_t kInitialChunkCapacity = 8; - static constexpr uint32_t kMaxChunkCapacity = 256; - - explicit ZoneChunkList(Zone* zone) : zone_(zone) {} - - MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ZoneChunkList); - - size_t size() const { return size_; } - bool empty() const { return size() == 0; } - - T& front(); - const T& front() const; - T& back(); - const T& back() const; - - void push_back(const T& item); - - // If the first chunk has space, inserts into it at the front. Otherwise - // allocate a new chunk with the same growth strategy as `push_back`. - // This limits the amount of copying to O(`kMaxChunkCapacity`). - void push_front(const T& item); - - // Cuts the last list elements so at most 'limit' many remain. Does not - // free the actual memory, since it is zone allocated. - void Rewind(const size_t limit = 0); - - // Quickly scans the list to retrieve the element at the given index. Will - // *not* check bounds. - iterator Find(const size_t index); - const_iterator Find(const size_t index) const; - // TODO(heimbuef): Add 'rFind', seeking from the end and returning a - // reverse iterator. - - // Splits off a new list that contains the elements from `split_begin` to - // `end()`. The current list is truncated to end just before `split_begin`. - // This naturally invalidates all iterators, including `split_begin`. - ZoneChunkList<T> SplitAt(iterator split_begin); - void Append(ZoneChunkList<T>& other); - - void CopyTo(T* ptr); - - iterator begin() { return iterator::Begin(this); } - iterator end() { return iterator::End(this); } - reverse_iterator rbegin() { return reverse_iterator::Begin(this); } - reverse_iterator rend() { return reverse_iterator::End(this); } - const_iterator begin() const { return const_iterator::Begin(this); } - const_iterator end() const { return const_iterator::End(this); } - const_reverse_iterator rbegin() const { - return const_reverse_iterator::Begin(this); - } - const_reverse_iterator rend() const { - return const_reverse_iterator::End(this); - } - - void swap(ZoneChunkList<T>& other) { - DCHECK_EQ(zone_, other.zone_); - std::swap(size_, other.size_); - std::swap(front_, other.front_); - std::swap(last_nonempty_, other.last_nonempty_); - } - - private: - template <typename S, bool backwards, bool modifiable> - friend class ZoneChunkListIterator; - - struct Chunk { - uint32_t capacity_ = 0; - uint32_t position_ = 0; - Chunk* next_ = nullptr; - Chunk* previous_ = nullptr; - T* items() { return reinterpret_cast<T*>(this + 1); } - const T* items() const { return reinterpret_cast<const T*>(this + 1); } - uint32_t size() const { - DCHECK_LE(position_, capacity_); - return position_; - } - bool empty() const { return size() == 0; } - bool full() const { return size() == capacity_; } - }; - - Chunk* NewChunk(const uint32_t capacity) { - void* memory = zone_->Allocate<Chunk>(sizeof(Chunk) + capacity * sizeof(T)); - Chunk* chunk = new (memory) Chunk(); - chunk->capacity_ = capacity; - return chunk; - } - - static uint32_t NextChunkCapacity(uint32_t previous_capacity) { - return std::min(previous_capacity * 2, kMaxChunkCapacity); - } - - struct SeekResult { - Chunk* chunk_; - uint32_t chunk_index_; - }; - - // Returns the chunk and relative index of the element at the given global - // index. Will skip entire chunks and is therefore faster than iterating. - SeekResult SeekIndex(size_t index) const; - -#ifdef DEBUG - // Check the invariants. - void Verify() const { - if (front_ == nullptr) { - // Initial empty state. - DCHECK_NULL(last_nonempty_); - DCHECK_EQ(0, size()); - } else if (empty()) { - // Special case: Fully rewound list, with only empty chunks. - DCHECK_EQ(front_, last_nonempty_); - DCHECK_EQ(0, size()); - for (Chunk* chunk = front_; chunk != nullptr; chunk = chunk->next_) { - DCHECK(chunk->empty()); - } - } else { - // Normal state: Somewhat filled and (partially) rewound. - DCHECK_NOT_NULL(last_nonempty_); - - size_t size_check = 0; - bool in_empty_tail = false; - for (Chunk* chunk = front_; chunk != nullptr; chunk = chunk->next_) { - // Chunks from `front_` to `last_nonempty_` (inclusive) are non-empty. - DCHECK_EQ(in_empty_tail, chunk->empty()); - size_check += chunk->size(); - - if (chunk == last_nonempty_) { - in_empty_tail = true; - } - } - DCHECK_EQ(size_check, size()); - } - } -#endif - - Zone* zone_; - - size_t size_ = 0; - Chunk* front_ = nullptr; - Chunk* last_nonempty_ = nullptr; -}; - -template <typename T, bool backwards, bool modifiable> -class ZoneChunkListIterator - : public base::iterator<std::bidirectional_iterator_tag, T> { - private: - template <typename S> - using maybe_const = std::conditional_t<modifiable, S, std::add_const_t<S>>; - using Chunk = maybe_const<typename ZoneChunkList<T>::Chunk>; - using ChunkList = maybe_const<ZoneChunkList<T>>; - - public: - maybe_const<T>& operator*() const { return current_->items()[position_]; } - maybe_const<T>* operator->() const { return ¤t_->items()[position_]; } - bool operator==(const ZoneChunkListIterator& other) const { - return other.current_ == current_ && other.position_ == position_; - } - bool operator!=(const ZoneChunkListIterator& other) const { - return !operator==(other); - } - - ZoneChunkListIterator& operator++() { - Move<backwards>(); - return *this; - } - - ZoneChunkListIterator operator++(int) { - ZoneChunkListIterator clone(*this); - Move<backwards>(); - return clone; - } - - ZoneChunkListIterator& operator--() { - Move<!backwards>(); - return *this; - } - - ZoneChunkListIterator operator--(int) { - ZoneChunkListIterator clone(*this); - Move<!backwards>(); - return clone; - } - - void Advance(uint32_t amount) { - static_assert(!backwards, "Advance only works on forward iterators"); - -#ifdef DEBUG - ZoneChunkListIterator clone(*this); - for (uint32_t i = 0; i < amount; ++i) { - ++clone; - } -#endif - - CHECK(!base::bits::UnsignedAddOverflow32(position_, amount, &position_)); - while (position_ > 0 && position_ >= current_->position_) { - auto overshoot = position_ - current_->position_; - current_ = current_->next_; - position_ = overshoot; - - DCHECK(position_ == 0 || current_); - } - -#ifdef DEBUG - DCHECK_EQ(clone, *this); -#endif - } - - private: - friend class ZoneChunkList<T>; - - static ZoneChunkListIterator Begin(ChunkList* list) { - // Forward iterator: - if (!backwards) return ZoneChunkListIterator(list->front_, 0); - - // Backward iterator: - if (list->empty()) return End(list); - - DCHECK(!list->last_nonempty_->empty()); - return ZoneChunkListIterator(list->last_nonempty_, - list->last_nonempty_->position_ - 1); - } - - static ZoneChunkListIterator End(ChunkList* list) { - // Backward iterator: - if (backwards) return ZoneChunkListIterator(nullptr, 0); - - // Forward iterator: - if (list->empty()) return Begin(list); - - // NOTE: Decrementing `end()` is not supported if `last_nonempty_->next_` - // is nullptr (in that case `Move` will crash on dereference). - return ZoneChunkListIterator(list->last_nonempty_->next_, 0); - } - - ZoneChunkListIterator(Chunk* current, uint32_t position) - : current_(current), position_(position) { - DCHECK(current == nullptr || position < current->capacity_); - } - - template <bool move_backward> - void Move() { - if (move_backward) { - // Move backwards. - if (position_ == 0) { - current_ = current_->previous_; - position_ = current_ ? current_->position_ - 1 : 0; - } else { - --position_; - } - } else { - // Move forwards. - ++position_; - if (position_ >= current_->position_) { - current_ = current_->next_; - position_ = 0; - } - } - } - - Chunk* current_; - uint32_t position_; -}; - -template <typename T> -T& ZoneChunkList<T>::front() { - DCHECK(!empty()); - return *begin(); -} - -template <typename T> -const T& ZoneChunkList<T>::front() const { - DCHECK(!empty()); - return *begin(); -} - -template <typename T> -T& ZoneChunkList<T>::back() { - DCHECK(!empty()); - // Avoid the branch in `ZoneChunkListIterator::Begin()`. - V8_ASSUME(size_ != 0); - return *rbegin(); -} - -template <typename T> -const T& ZoneChunkList<T>::back() const { - DCHECK(!empty()); - // Avoid the branch in `ZoneChunkListIterator::Begin()`. - V8_ASSUME(size_ != 0); - return *rbegin(); -} - -template <typename T> -void ZoneChunkList<T>::push_back(const T& item) { - if (last_nonempty_ == nullptr) { - // Initially empty chunk list. - front_ = NewChunk(kInitialChunkCapacity); - last_nonempty_ = front_; - } else if (last_nonempty_->full()) { - // If there is an empty chunk following, reuse that, otherwise allocate. - if (last_nonempty_->next_ == nullptr) { - Chunk* chunk = NewChunk(NextChunkCapacity(last_nonempty_->capacity_)); - last_nonempty_->next_ = chunk; - chunk->previous_ = last_nonempty_; - } - last_nonempty_ = last_nonempty_->next_; - DCHECK(!last_nonempty_->full()); - } - - last_nonempty_->items()[last_nonempty_->position_] = item; - ++last_nonempty_->position_; - ++size_; - DCHECK_LE(last_nonempty_->position_, last_nonempty_->capacity_); -} - -template <typename T> -void ZoneChunkList<T>::push_front(const T& item) { - if (front_ == nullptr) { - // Initially empty chunk list. - front_ = NewChunk(kInitialChunkCapacity); - last_nonempty_ = front_; - } else if (front_->full()) { - // First chunk at capacity, so prepend a new chunk. - DCHECK_NULL(front_->previous_); - Chunk* chunk = NewChunk(NextChunkCapacity(front_->capacity_)); - front_->previous_ = chunk; - chunk->next_ = front_; - front_ = chunk; - } - DCHECK(!front_->full()); - - T* end = front_->items() + front_->position_; - std::move_backward(front_->items(), end, end + 1); - front_->items()[0] = item; - ++front_->position_; - ++size_; - DCHECK_LE(front_->position_, front_->capacity_); -} - -template <typename T> -typename ZoneChunkList<T>::SeekResult ZoneChunkList<T>::SeekIndex( - size_t index) const { - DCHECK_LT(index, size()); - Chunk* current = front_; - while (index >= current->capacity_) { - index -= current->capacity_; - current = current->next_; - } - DCHECK_LT(index, current->capacity_); - return {current, static_cast<uint32_t>(index)}; -} - -template <typename T> -void ZoneChunkList<T>::Rewind(const size_t limit) { - if (limit >= size()) return; - - SeekResult seek_result = SeekIndex(limit); - DCHECK_NOT_NULL(seek_result.chunk_); - - // Do a partial rewind of the chunk containing the index. - seek_result.chunk_->position_ = seek_result.chunk_index_; - - // Set last_nonempty_ so iterators will work correctly. - last_nonempty_ = seek_result.chunk_; - - // Do full rewind of all subsequent chunks. - for (Chunk* current = seek_result.chunk_->next_; current != nullptr; - current = current->next_) { - current->position_ = 0; - } - - size_ = limit; - -#ifdef DEBUG - Verify(); -#endif -} - -template <typename T> -typename ZoneChunkList<T>::iterator ZoneChunkList<T>::Find(const size_t index) { - SeekResult seek_result = SeekIndex(index); - return typename ZoneChunkList<T>::iterator(seek_result.chunk_, - seek_result.chunk_index_); -} - -template <typename T> -typename ZoneChunkList<T>::const_iterator ZoneChunkList<T>::Find( - const size_t index) const { - SeekResult seek_result = SeekIndex(index); - return typename ZoneChunkList<T>::const_iterator(seek_result.chunk_, - seek_result.chunk_index_); -} - -template <typename T> -ZoneChunkList<T> ZoneChunkList<T>::SplitAt(iterator split_begin) { - ZoneChunkList<T> result(zone_); - - // `result` is an empty freshly-constructed list. - if (split_begin == end()) return result; - - // `this` is empty after the split and `result` contains everything. - if (split_begin == begin()) { - this->swap(result); - return result; - } - - // There is at least one element in both `this` and `result`. - - // Split the chunk. - Chunk* split_chunk = split_begin.current_; - DCHECK_LE(split_begin.position_, split_chunk->position_); - T* chunk_split_begin = split_chunk->items() + split_begin.position_; - T* chunk_split_end = split_chunk->items() + split_chunk->position_; - uint32_t new_chunk_size = - static_cast<uint32_t>(chunk_split_end - chunk_split_begin); - uint32_t new_chunk_capacity = std::max( - kInitialChunkCapacity, base::bits::RoundUpToPowerOfTwo32(new_chunk_size)); - CHECK_LE(new_chunk_size, new_chunk_capacity); - Chunk* new_chunk = NewChunk(new_chunk_capacity); - std::copy(chunk_split_begin, chunk_split_end, new_chunk->items()); - new_chunk->position_ = new_chunk_size; - split_chunk->position_ = split_begin.position_; - - // Split the linked list. - result.front_ = new_chunk; - result.last_nonempty_ = - (last_nonempty_ == split_chunk) ? new_chunk : last_nonempty_; - new_chunk->next_ = split_chunk->next_; - if (new_chunk->next_) { - new_chunk->next_->previous_ = new_chunk; - } - - last_nonempty_ = split_chunk; - split_chunk->next_ = nullptr; - - // Compute the new size. - size_t new_size = 0; - for (Chunk* chunk = front_; chunk != split_chunk; chunk = chunk->next_) { - DCHECK(!chunk->empty()); - new_size += chunk->size(); - } - new_size += split_chunk->size(); - DCHECK_LT(new_size, size()); - result.size_ = size() - new_size; - size_ = new_size; - -#ifdef DEBUG - Verify(); - result.Verify(); -#endif - - return result; -} - -template <typename T> -void ZoneChunkList<T>::Append(ZoneChunkList<T>& other) { - DCHECK_EQ(zone_, other.zone_); - - if (other.front_ == nullptr) return; - - last_nonempty_->next_ = other.front_; - other.front_->previous_ = last_nonempty_; - - last_nonempty_ = other.last_nonempty_; - - size_ += other.size_; -#ifdef DEBUG - Verify(); -#endif - - // Leave `other` in empty, but valid state. - other.front_ = nullptr; - other.last_nonempty_ = nullptr; - other.size_ = 0; -} - -template <typename T> -void ZoneChunkList<T>::CopyTo(T* ptr) { - for (Chunk* current = front_; current != nullptr; current = current->next_) { - void* start = current->items(); - void* end = current->items() + current->position_; - size_t bytes = static_cast<size_t>(reinterpret_cast<uintptr_t>(end) - - reinterpret_cast<uintptr_t>(start)); - - MemCopy(ptr, current->items(), bytes); - ptr += current->position_; - } -} - -} // namespace internal -} // namespace v8 - -#endif // V8_ZONE_ZONE_CHUNK_LIST_H_ diff --git a/deps/v8/test/benchmarks/cpp/BUILD.gn b/deps/v8/test/benchmarks/cpp/BUILD.gn index 0cba56ee1ab7..1225860bab9e 100644 --- a/deps/v8/test/benchmarks/cpp/BUILD.gn +++ b/deps/v8/test/benchmarks/cpp/BUILD.gn @@ -21,38 +21,47 @@ group("gn_all") { } if (v8_enable_google_benchmark) { + if (build_with_chromium) { + google_benchmark_dep = "//third_party/google_benchmark" + benchmark_main_dep = "//third_party/google_benchmark:benchmark_main" + } else { + google_benchmark_dep = + "//third_party/google_benchmark_chrome:google_benchmark" + benchmark_main_dep = "//third_party/google_benchmark_chrome:benchmark_main" + } + v8_executable("empty_benchmark") { testonly = true - configs = [] + configs = [ "../../..:internal_config_base" ] sources = [ "empty.cc" ] deps = [ - "//:v8_libbase", - "//third_party/google_benchmark_chrome:benchmark_main", - "//third_party/google_benchmark_chrome:google_benchmark", + "../../..:v8_libbase", + benchmark_main_dep, + google_benchmark_dep, ] } v8_executable("dtoa_benchmark") { testonly = true - configs = [] + configs = [ "../../..:internal_config_base" ] sources = [ "dtoa.cc" ] deps = [ - "//:v8_libbase", - "//third_party/google_benchmark_chrome:benchmark_main", - "//third_party/google_benchmark_chrome:google_benchmark", + "../../..:v8_libbase", + benchmark_main_dep, + google_benchmark_dep, ] } v8_executable("bindings_benchmark") { testonly = true - configs = [] + configs = [ "../../..:internal_config_base" ] sources = [ "benchmark-main.cc", @@ -62,18 +71,18 @@ if (v8_enable_google_benchmark) { ] deps = [ - "//:v8", - "//:v8_internal_headers", - "//:v8_libbase", - "//:v8_tracing", - "//third_party/google_benchmark_chrome:google_benchmark", + "../../..:v8", + "../../..:v8_internal_headers", + "../../..:v8_libbase", + "../../..:v8_tracing", + google_benchmark_dep, ] } v8_executable("fast_api_benchmark") { testonly = true - configs = [] + configs = [ "../../..:internal_config_base" ] sources = [ "benchmark-main.cc", @@ -83,9 +92,9 @@ if (v8_enable_google_benchmark) { ] deps = [ - "//:v8", - "//:v8_libbase", - "//third_party/google_benchmark_chrome:google_benchmark", + "../../..:v8", + "../../..:v8_libbase", + google_benchmark_dep, ] } } diff --git a/deps/v8/test/benchmarks/cpp/DEPS b/deps/v8/test/benchmarks/cpp/DEPS index 48d50e6847a1..0f530b613293 100644 --- a/deps/v8/test/benchmarks/cpp/DEPS +++ b/deps/v8/test/benchmarks/cpp/DEPS @@ -1,6 +1,6 @@ include_rules = [ "+src/base", - "+third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h", + "+benchmark/benchmark.h", # TODO(chromium: 328117814) Temporarily allow internals until the API has # landed. "+src/api/api-inl.h", diff --git a/deps/v8/test/benchmarks/cpp/benchmark-main.cc b/deps/v8/test/benchmarks/cpp/benchmark-main.cc index 91d9b5856c62..ec5bde4b6e0c 100644 --- a/deps/v8/test/benchmarks/cpp/benchmark-main.cc +++ b/deps/v8/test/benchmarks/cpp/benchmark-main.cc @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "include/v8-initialization.h" #include "src/base/logging.h" #include "test/benchmarks/cpp/benchmark-utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" // Expanded macro BENCHMARK_MAIN() to allow per-process setup. int main(int argc, char** argv) { diff --git a/deps/v8/test/benchmarks/cpp/benchmark-utils.h b/deps/v8/test/benchmarks/cpp/benchmark-utils.h index 03054efdd1b2..c07862acf372 100644 --- a/deps/v8/test/benchmarks/cpp/benchmark-utils.h +++ b/deps/v8/test/benchmarks/cpp/benchmark-utils.h @@ -5,11 +5,11 @@ #ifndef TEST_BENCHMARK_CPP_BENCHMARK_UTILS_H_ #define TEST_BENCHMARK_CPP_BENCHMARK_UTILS_H_ +#include "benchmark/benchmark.h" #include "include/v8-array-buffer.h" #include "include/v8-cppgc.h" #include "include/v8-isolate.h" #include "include/v8-platform.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" namespace v8::benchmarking { diff --git a/deps/v8/test/benchmarks/cpp/bindings.cc b/deps/v8/test/benchmarks/cpp/bindings.cc index ae2c3685f69f..06bcb8011e87 100644 --- a/deps/v8/test/benchmarks/cpp/bindings.cc +++ b/deps/v8/test/benchmarks/cpp/bindings.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "include/cppgc/allocation.h" #include "include/v8-context.h" #include "include/v8-internal.h" @@ -13,7 +14,6 @@ #include "src/base/macros.h" #include "src/objects/js-objects-inl.h" #include "test/benchmarks/cpp/benchmark-utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" namespace { @@ -216,8 +216,8 @@ class BindingsBenchmarkBase : public v8::benchmarking::BenchmarkWithIsolate { auto* per_context_data = new PerContextData{allocation_handle(), {}}; - context->SetAlignedPointerInEmbedderData(0, per_context_data, - kPerContextDataTag); + context->SetAlignedPointerInEmbedderDataV2(0, per_context_data, + kPerContextDataTag); auto* global_wrappable = ConcreteBindings::CreateGlobalWrappable(per_context_data); diff --git a/deps/v8/test/benchmarks/cpp/cppgc/BUILD.gn b/deps/v8/test/benchmarks/cpp/cppgc/BUILD.gn index 2d3cc513791b..47226cd4f3a5 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/BUILD.gn +++ b/deps/v8/test/benchmarks/cpp/cppgc/BUILD.gn @@ -19,6 +19,7 @@ if (v8_enable_google_benchmark) { testonly = true configs = [ + "//build/config/compiler:no_exit_time_destructors", "../../../..:external_config", "../../../..:internal_config_base", "../../../..:cppgc_base_config", @@ -30,7 +31,11 @@ if (v8_enable_google_benchmark) { "benchmark_utils.cc", "benchmark_utils.h", ] - public_deps = [ "//third_party/google_benchmark_chrome:google_benchmark" ] + if (build_with_chromium) { + public_deps = [ "//third_party/google_benchmark" ] + } else { + public_deps = [ "//third_party/google_benchmark_chrome:google_benchmark" ] + } if (cppgc_is_standalone) { deps = [ "../../../..:cppgc_for_testing" ] } else { @@ -42,6 +47,7 @@ if (v8_enable_google_benchmark) { testonly = true configs = [ + "//build/config/compiler:no_exit_time_destructors", "../../../..:external_config", "../../../..:internal_config_base", "../../../..:cppgc_base_config", @@ -62,6 +68,7 @@ if (v8_enable_google_benchmark) { testonly = true configs = [ + "//build/config/compiler:no_exit_time_destructors", "../../../..:external_config", "../../../..:internal_config_base", "../../../..:cppgc_base_config", diff --git a/deps/v8/test/benchmarks/cpp/cppgc/DEPS b/deps/v8/test/benchmarks/cpp/cppgc/DEPS index 2921355e8e31..75d2e3f45e81 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/DEPS +++ b/deps/v8/test/benchmarks/cpp/cppgc/DEPS @@ -3,5 +3,5 @@ include_rules = [ "+src/base", "+src/heap/cppgc-internal", "+test/unittests/heap/cppgc", - "+third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h", + "+benchmark/benchmark.h", ] diff --git a/deps/v8/test/benchmarks/cpp/cppgc/allocation_perf.cc b/deps/v8/test/benchmarks/cpp/cppgc/allocation_perf.cc index 03fe4bd6f3d4..de037d93e8e4 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/allocation_perf.cc +++ b/deps/v8/test/benchmarks/cpp/cppgc/allocation_perf.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "include/cppgc/allocation.h" #include "include/cppgc/garbage-collected.h" #include "include/cppgc/heap-consistency.h" @@ -9,7 +10,6 @@ #include "src/heap/cppgc-internal/globals.h" #include "src/heap/cppgc-internal/heap.h" #include "test/benchmarks/cpp/cppgc/benchmark_utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" namespace cppgc { namespace internal { diff --git a/deps/v8/test/benchmarks/cpp/cppgc/benchmark_main.cc b/deps/v8/test/benchmarks/cpp/cppgc/benchmark_main.cc index 69a040e4fe1e..ca47a296afc2 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/benchmark_main.cc +++ b/deps/v8/test/benchmarks/cpp/cppgc/benchmark_main.cc @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "include/cppgc/platform.h" #include "test/benchmarks/cpp/cppgc/benchmark_utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" // Expanded macro BENCHMARK_MAIN() to allow per-process setup. int main(int argc, char** argv) { diff --git a/deps/v8/test/benchmarks/cpp/cppgc/benchmark_utils.h b/deps/v8/test/benchmarks/cpp/cppgc/benchmark_utils.h index e388b90faacc..3edf6fe115b2 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/benchmark_utils.h +++ b/deps/v8/test/benchmarks/cpp/cppgc/benchmark_utils.h @@ -5,9 +5,9 @@ #ifndef TEST_BENCHMARK_CPP_CPPGC_BENCHMARK_UTILS_H_ #define TEST_BENCHMARK_CPP_CPPGC_BENCHMARK_UTILS_H_ +#include "benchmark/benchmark.h" #include "include/cppgc/heap.h" #include "test/unittests/heap/cppgc/test-platform.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" namespace cppgc { namespace internal { diff --git a/deps/v8/test/benchmarks/cpp/cppgc/binary-trees_perf.cc b/deps/v8/test/benchmarks/cpp/cppgc/binary-trees_perf.cc index 7d3ac80885b4..4e8c873115ca 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/binary-trees_perf.cc +++ b/deps/v8/test/benchmarks/cpp/cppgc/binary-trees_perf.cc @@ -4,6 +4,7 @@ #include <iostream> +#include "benchmark/benchmark.h" #include "include/cppgc/allocation.h" #include "include/cppgc/garbage-collected.h" #include "include/cppgc/heap.h" @@ -12,7 +13,6 @@ #include "src/base/macros.h" #include "src/heap/cppgc-internal/object-allocator.h" #include "test/benchmarks/cpp/cppgc/benchmark_utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" namespace { diff --git a/deps/v8/test/benchmarks/cpp/cppgc/trace_perf.cc b/deps/v8/test/benchmarks/cpp/cppgc/trace_perf.cc index 607fd2d54d03..983c30e9b216 100644 --- a/deps/v8/test/benchmarks/cpp/cppgc/trace_perf.cc +++ b/deps/v8/test/benchmarks/cpp/cppgc/trace_perf.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "include/cppgc/allocation.h" #include "include/cppgc/garbage-collected.h" #include "include/cppgc/persistent.h" @@ -9,7 +10,6 @@ #include "src/heap/cppgc-internal/globals.h" #include "src/heap/cppgc-internal/heap.h" #include "test/benchmarks/cpp/cppgc/benchmark_utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" #include "v8config.h" namespace cppgc { diff --git a/deps/v8/test/benchmarks/cpp/dtoa.cc b/deps/v8/test/benchmarks/cpp/dtoa.cc index a00e9a87d243..6b2ebd652ee4 100644 --- a/deps/v8/test/benchmarks/cpp/dtoa.cc +++ b/deps/v8/test/benchmarks/cpp/dtoa.cc @@ -2,15 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "src/base/macros.h" #include "src/base/numbers/fast-dtoa.h" -#include "src/base/vector.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" using v8::base::FAST_DTOA_PRECISION; using v8::base::FAST_DTOA_SHORTEST; using v8::base::kFastDtoaMaximalLength; -using v8::base::Vector; // This is a dump from a benchmark (MotionMark suits). // It contains a large number of nontrivial doubles, @@ -1043,24 +1041,22 @@ constexpr const double kTestDoubles[4096] = { static void BM_DtoaShortest(benchmark::State& state) { char output[kFastDtoaMaximalLength + 10]; - Vector<char> buffer(output, sizeof(output)); int length, decimal_point; unsigned idx = 0; for (auto _ : state) { bool ok = FastDtoa(kTestDoubles[idx++ % 4096], FAST_DTOA_SHORTEST, 0, - buffer, &length, &decimal_point); + output, &length, &decimal_point); USE(ok); } } static void BM_DtoaSixDigits(benchmark::State& state) { char output[kFastDtoaMaximalLength + 10]; - Vector<char> buffer(output, sizeof(output)); int length, decimal_point; unsigned idx = 0; for (auto _ : state) { bool ok = FastDtoa(kTestDoubles[idx++ % 4096], FAST_DTOA_PRECISION, 6, - buffer, &length, &decimal_point); + output, &length, &decimal_point); USE(ok); } } diff --git a/deps/v8/test/benchmarks/cpp/empty.cc b/deps/v8/test/benchmarks/cpp/empty.cc index e89d572a174c..8ba51aa55d6d 100644 --- a/deps/v8/test/benchmarks/cpp/empty.cc +++ b/deps/v8/test/benchmarks/cpp/empty.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "src/base/macros.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" static void BM_Empty(benchmark::State& state) { for (auto _ : state) { diff --git a/deps/v8/test/benchmarks/cpp/fast-api.cc b/deps/v8/test/benchmarks/cpp/fast-api.cc index 27a3e0a7b350..a7dd23a16a00 100644 --- a/deps/v8/test/benchmarks/cpp/fast-api.cc +++ b/deps/v8/test/benchmarks/cpp/fast-api.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "benchmark/benchmark.h" #include "include/v8-context.h" #include "include/v8-fast-api-calls.h" #include "include/v8-internal.h" @@ -10,7 +11,6 @@ #include "include/v8-template.h" #include "src/base/macros.h" #include "test/benchmarks/cpp/benchmark-utils.h" -#include "third_party/google_benchmark_chrome/src/include/benchmark/benchmark.h" namespace { @@ -53,7 +53,7 @@ class FastApiBenchmark : public v8::benchmarking::BenchmarkWithIsolate { auto proxy_template_function = v8::FunctionTemplate::New(isolate); auto object_template = proxy_template_function->InstanceTemplate(); { - v8::CFunction fast_callback = + static v8::CFunction fast_callback = v8::CFunction::Make(FastApiBenchmark::FastCallback); object_template->Set( @@ -70,7 +70,7 @@ class FastApiBenchmark : public v8::benchmarking::BenchmarkWithIsolate { isolate, FastApiBenchmark::RegularCallback)); } { - v8::CFunction fast_callback = + static v8::CFunction fast_callback = v8::CFunction::Make(FastApiBenchmark::FastOneByteString); object_template->Set( @@ -81,7 +81,7 @@ class FastApiBenchmark : public v8::benchmarking::BenchmarkWithIsolate { v8::SideEffectType::kHasSideEffect, &fast_callback)); } { - v8::CFunction fast_callback = + static v8::CFunction fast_callback = v8::CFunction::Make(FastApiBenchmark::FastStringValueView); object_template->Set( diff --git a/deps/v8/test/cctest/BUILD.gn b/deps/v8/test/cctest/BUILD.gn index 396472aeb470..4510c9dbdbcc 100644 --- a/deps/v8/test/cctest/BUILD.gn +++ b/deps/v8/test/cctest/BUILD.gn @@ -84,9 +84,6 @@ v8_cluster_source_set("cctest_sources") { "test-api.cc", "test-debug.cc", "test-descriptor-array.cc", - "wasm/test-run-wasm.cc", - "wasm/test-streaming-compilation.cc", - "wasm/wasm-simd-utils.cc", ] sources = [ @@ -107,22 +104,7 @@ v8_cluster_source_set("cctest_sources") { "heap/heap-tester.h", "heap/heap-utils.cc", "heap/heap-utils.h", - "heap/test-alloc.cc", - "heap/test-array-buffer-sweeper.cc", - "heap/test-compaction.cc", - "heap/test-concurrent-allocation.cc", - "heap/test-concurrent-marking.cc", - "heap/test-external-string-tracker.cc", - "heap/test-heap.cc", - "heap/test-incremental-marking.cc", - "heap/test-mark-compact.cc", - "heap/test-memory-measurement.cc", - "heap/test-pool.cc", - "heap/test-spaces.cc", - "heap/test-weak-references.cc", - "heap/test-write-barrier.cc", "jsonstream-helper.h", - "manually-externalized-buffer.h", "print-extension.cc", "print-extension.h", "profiler-extension.cc", @@ -283,44 +265,7 @@ v8_cluster_source_set("cctest_sources") { "compiler/test-run-native-calls.cc", "compiler/turboshaft-test-simd-shift.cc", "test-js-to-wasm.cc", - "wasm/test-backing-store.cc", - "wasm/test-c-wasm-entry.cc", - "wasm/test-compilation-cache.cc", - "wasm/test-fuzzer-steps.cc", - "wasm/test-gc.cc", - "wasm/test-grow-memory.cc", - "wasm/test-jump-table-assembler.cc", - "wasm/test-liftoff-for-fuzzing.cc", - "wasm/test-liftoff-inspection.cc", - "wasm/test-run-wasm-64.cc", - "wasm/test-run-wasm-atomics.cc", - "wasm/test-run-wasm-atomics64.cc", - "wasm/test-run-wasm-bulk-memory.cc", - "wasm/test-run-wasm-exceptions.cc", - "wasm/test-run-wasm-f16.cc", - "wasm/test-run-wasm-js.cc", - "wasm/test-run-wasm-memory64.cc", - "wasm/test-run-wasm-module.cc", - "wasm/test-run-wasm-relaxed-simd.cc", - "wasm/test-run-wasm-sign-extension.cc", - "wasm/test-run-wasm-simd-liftoff.cc", - "wasm/test-run-wasm-simd.cc", - "wasm/test-run-wasm-wrappers.cc", - "wasm/test-run-wasm.cc", - "wasm/test-streaming-compilation.cc", - "wasm/test-wasm-breakpoints.cc", - "wasm/test-wasm-codegen.cc", - "wasm/test-wasm-import-wrapper-cache.cc", - "wasm/test-wasm-metrics.cc", - "wasm/test-wasm-serialization.cc", - "wasm/test-wasm-shared-engine.cc", - "wasm/test-wasm-stack.cc", - "wasm/test-wasm-strings.cc", - "wasm/test-wasm-trap-position.cc", - "wasm/wasm-atomics-utils.h", "wasm/wasm-runner.h", - "wasm/wasm-simd-utils.cc", - "wasm/wasm-simd-utils.h", ] public_deps += [ "../..:wasm_test_common" ] } diff --git a/deps/v8/test/cctest/cctest.cc b/deps/v8/test/cctest/cctest.cc index c74e3d168f65..cf9937d6f754 100644 --- a/deps/v8/test/cctest/cctest.cc +++ b/deps/v8/test/cctest/cctest.cc @@ -27,6 +27,8 @@ #include "test/cctest/cctest.h" +#include <array> + #include "include/cppgc/platform.h" #include "include/libplatform/libplatform.h" #include "include/v8-array-buffer.h" @@ -226,9 +228,9 @@ i::Handle<i::String> CcTest::MakeString(const char* str) { } i::Handle<i::String> CcTest::MakeName(const char* str, int suffix) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; v8::base::SNPrintF(buffer, "%s%d", str, suffix); - return CcTest::MakeString(buffer.begin()); + return CcTest::MakeString(buffer.data()); } v8::base::RandomNumberGenerator* CcTest::random_number_generator() { diff --git a/deps/v8/test/cctest/cctest.h b/deps/v8/test/cctest/cctest.h index 909f3fcff16a..2771445d2f69 100644 --- a/deps/v8/test/cctest/cctest.h +++ b/deps/v8/test/cctest/cctest.h @@ -595,11 +595,11 @@ static inline v8::Local<v8::Value> CompileRunWithOrigin( class StreamerThread : public v8::base::Thread { public: static void StartThreadForTaskAndJoin( - v8::ScriptCompiler::ScriptStreamingTask* task) { + v8::ScriptCompiler::ScriptStreamingTask* task, + i::Isolate* i_isolate = CcTest::i_isolate()) { StreamerThread thread(task); CHECK(thread.Start()); { - i::Isolate* i_isolate = CcTest::i_isolate(); i_isolate->main_thread_local_heap()->ExecuteWhileParked( [&thread]() { thread.Join(); }); } diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index c488e07a8bec..d9b3aa199017 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -55,9 +55,6 @@ # works as intended. 'test-api/DisallowJavascriptExecutionScope': [FAIL], - # Boot up memory use is bloated in debug mode. - 'test-mark-compact/BootUpMemoryUse': [PASS, ['mode == debug', FAIL]], - # This tests API threading, no point in running several variants. 'test-api/Threading*': [PASS, SLOW, NO_VARIANTS], @@ -76,9 +73,6 @@ # BUG(7054) 'test-cpu-profiler/StaticCollectSampleAPI': [SKIP], - # BUG(2340). Preprocessing stack traces is disabled at the moment. - 'test-heap/PreprocessStackTrace': [FAIL], - # BUG(4333). Function name inferrer does not work for ES6 clases. 'test-func-name-inference/UpperCaseClass': [FAIL], 'test-func-name-inference/LowerCaseClass': [FAIL], @@ -95,10 +89,8 @@ # Slow tests. 'test-api/InternalFieldsSubclassing': [PASS, SLOW], - 'test-concurrent-allocation/ConcurrentAllocationInLargeSpace': [PASS, SLOW], 'test-cpu-profiler/NoProfilingProtectorCPUProfiler': [PASS, SLOW], 'test-debug/CallFunctionInDebugger': [PASS, ['mode == debug', SLOW]], - 'test-heap/TestInternalWeakLists': [PASS, SLOW], 'test-heap-profiler/ManyLocalsInSharedContext': [PASS, SLOW], 'test-serialize/CustomSnapshotDataBlobImmortalImmovableRoots': [PASS, ['mode == debug', SKIP]], 'test-serialize/SharedStrings': [PASS, SLOW], @@ -110,7 +102,6 @@ 'test-allocation/AccountingAllocatorOOM': [PASS, HEAVY], 'test-allocation/MallocedOperatorNewOOM': [PASS, HEAVY], 'test-api/NewStringRangeError': [PASS, HEAVY], - 'test-jump-table-assembler/JumpTablePatchingStress': [PASS, HEAVY], 'test-lockers/LockerUnlocker': [PASS, HEAVY], 'test-lockers/LockTwiceAndUnlock': [PASS, HEAVY], 'test-lockers/SeparateIsolatesLocksNonexclusive': [PASS, HEAVY], @@ -121,8 +112,6 @@ 'test-serialize/StartupSerializerOnceRunScript': [PASS, SLOW, HEAVY], 'test-serialize/StartupSerializerTwiceRunScript': [PASS, SLOW, HEAVY], 'test-serialize/StaticRootsPredictableSnapshot': [PASS, SLOW, HEAVY], - 'test-spaces/OldLargeObjectSpace': [PASS, HEAVY], - 'test-spaces/OldSpace': [PASS, HEAVY], 'test-strings/StringOOMNewStringFromOneByte': [PASS, HEAVY], 'test-strings/StringOOMNewStringFromUtf8': [PASS, HEAVY], @@ -138,9 +127,6 @@ 'test-run-machops/*': [SKIP], 'test-select-combine/*': [SKIP], - # TODO(https://crbug.com/467830526): Currently too flaky: - 'test-mark-compact/RegressJoinThreadsOnIsolateDeinit': [SKIP], - ############################################################################## # Behavioural differences between Maglev and Turbofan when the former is used # for OptimizeFunctionOnNextCall or as a frontend for Turboshaft. @@ -199,9 +185,6 @@ ['mode == debug', { # BUG(v8:10996): Flaky on Linux64 - debug 'test-cpu-profiler/StartProfilingAfterOsr': [SKIP], - - 'test-concurrent-allocation/ConcurrentAllocationWhileMainThreadParksAndUnparks': [PASS, SLOW], - 'test-concurrent-allocation/ConcurrentAllocationInLargeSpace': [PASS, SLOW], }], ############################################################################## @@ -210,17 +193,6 @@ # into the handler after the stack has drifted from the context on the # signal. 'test-cpu-profiler/*': [SKIP], - - # Slow tests on TSAN - 'test-heap/Regress8014': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Add_Consts': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Sub_Consts': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Mul_Consts': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Div_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Add_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Sub_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Mul_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Div_Consts': [SKIP], }], ############################################################################## @@ -241,17 +213,8 @@ 'test-serialize/StartupSerializerOnceRunScript': [PASS, FAIL], 'test-serialize/StartupSerializerTwiceRunScript': [PASS, FAIL], - # BUG(v8:3154). - 'test-heap/ReleaseOverReservedPages': [PASS, FAIL], - # BUG(v8:3155). 'test-strings/OneByteArrayJoin': [PASS, ['mode == debug', FAIL]], - - # BUG(v8:3247). - 'test-mark-compact/NoPromotion': [SKIP], - - # BUG(v8:3446). - 'test-mark-compact/Promotion': [PASS, FAIL], }], # 'arch == arm64' ['arch == arm64 and simulator_run', { @@ -260,23 +223,8 @@ 'test-api/ExternalArrays': [PASS, SLOW], 'test-api/Threading*': [SKIP], 'test-cpu-profiler/MultipleIsolates': [PASS, ['not pointer_compression', SLOW]], - - # https://crbug.com/420743936 - 'test-run-wasm-f16/RunWasmLiftoff_F16x8ConvertI16x8': [PASS, ['all_arm64_features', SKIP]], - 'test-run-wasm-f16/RunWasmTurbofan_F16x8ConvertI16x8': [PASS, ['all_arm64_features', SKIP]], }], # 'arch == arm64 and simulator_run' -['arch == arm64 and system == macos and not simulator_run', { - # https://crbug.com/42204313 - 'test-concurrent-allocation/ConcurrentAllocationInOldSpace': [PASS, ['mode == debug', SKIP]], -}], # arch == arm64 and system == macos and not simulator_run - -############################################################################## -['arch == arm and not simulator_run', { - # Fails on ODROID: https://crbug.com/v8/11634 - 'test-wasm-metrics/*': [SKIP], -}], # arch == arm and not simulator_run - ############################################################################## ['variant == nooptimization and (arch == arm or arch == arm64) and simulator_run', { # Slow tests: https://crbug.com/v8/7783 @@ -285,16 +233,6 @@ ############################################################################## ['variant == nooptimization', { - # Wasm serialization relies on TurboFan to be available, hence does not work - # in the 'nooptimization' variant. - 'test-wasm-serialization/*': [SKIP], - 'test-streaming-compilation/SingleThreadedTestDeserializationBypassesCompilation': [SKIP], - 'test-streaming-compilation/SingleThreadedTestDeserializationFails': [SKIP], - 'test-streaming-compilation/SingleThreadedTestIncrementalCaching': [SKIP], - 'test-streaming-compilation/AsyncTestDeserializationFails': [SKIP], - 'test-streaming-compilation/AsyncTestDeserializationBypassesCompilation': [SKIP], - 'test-streaming-compilation/AsyncTestIncrementalCaching': [SKIP], - # %ObserveNode tests rely on TurboFan. 'test-calls-with-arraylike-or-spread/*': [SKIP], 'test-js-to-wasm/*': [SKIP], @@ -304,12 +242,6 @@ 'test-field-type-tracking/*': [SKIP], }], # variant == nooptimization -############################################################################## -['variant == stress_concurrent_allocation', { - # https://crbug.com/42204548 - 'test-mark-compact/MarkCompactCollector': [PASS, SKIP], -}], # variant == stress_concurrent_allocation - ############################################################################## ['asan == True', { # Skip tests not suitable for ASAN. @@ -322,19 +254,6 @@ ['asan or tsan', { # Tests that need to run sequentially (e.g. due to memory consumption). 'regress/regress-crbug-9161': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_Add': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_DivS': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_DivU': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_Eq': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_GeS': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_GeU': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_GtS': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_Ior': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_LeU': [PASS, HEAVY], - 'test-run-wasm/RunWasmLiftoff_I32Binop_LtU': [PASS, HEAVY], - - # Slow tests. - 'test-run-wasm/RunWasmTurbofan_Float32*': [PASS, SLOW], }], # 'asan or tsan' ############################################################################## @@ -351,30 +270,16 @@ ['tsan == True', { # BUG(v8:6924). The test allocates a lot of memory. 'test-api/NewStringRangeError': [PASS, NO_VARIANTS], - # BUG(v8:8296). The tests allocate a lot of objects and timeout in - # the --stress-concurrent-allocation variant. - 'test-heap/OutOfMemorySmallObjects': [PASS, NO_VARIANTS], - 'test-heap/OutOfMemory': [PASS, NO_VARIANTS], - # Too slow for tsan in debug mode: 'test-serialize/StaticRootsPredictableSnapshot': [PASS, ['mode == debug', SKIP]], }], # 'tsan == True' -############################################################################## -['ubsan', { - # https://crbug.com/v8/14309 - 'test-run-wasm-simd/RunWasm*': [SKIP], -}], # 'ubsan' - ############################################################################## ['full_debug', { # Tests too slow in non-optimized debug mode. 'test-api/FastApiCalls': [SKIP], 'test-api/InternalFieldsSubclassing': [SKIP], 'test-api/Threading8': [SKIP], - 'test-concurrent-allocation/ConcurrentAllocationInLargeSpace': [SKIP], - 'test-heap/Regress8014': [SKIP], - 'test-heap/TestInternalWeakLists': [SKIP], 'test-serialize/ContextSerializerContext': [SKIP], 'test-serialize/ContextSerializerCustomContext': [SKIP], 'test-serialize/SharedStrings': [SKIP], @@ -433,19 +338,8 @@ 'test-serialize/StartupSerializerTwiceRunScript': [SKIP], }], # 'arch == arm' -############################################################################## -['arch == mips64', { - # TODO(mips-team): Currently fails on mips64 board. - 'test-run-wasm/RunWasmLiftoff_I32Binop*': [SKIP], -}], # 'arch == mips64' ############################################################################## ['arch == mips64el or arch == mips64', { - # BUG(v8:3154). - 'test-heap/ReleaseOverReservedPages': [PASS, FAIL], - - # TODO(mips-team): Improve code-size on large RegExp's. - 'test-heap/TestSizeOfRegExpCode': [SKIP], - # BUG(1075): Unresolved crashes on MIPS also. 'test-serialize/StartupSerializerOnce': [SKIP], 'test-serialize/StartupSerializerTwice': [SKIP], @@ -455,28 +349,8 @@ # The uint32 values are sign-extended on MIPS64. 'test-run-load-store/RunLoadStoreZeroExtend64': [SKIP], 'test-run-load-store/RunUnalignedLoadStoreZeroExtend64': [SKIP], - - # Flush to zero is not supported yet. - 'test-wasm-shared-engine/RunImportedWithDenormalsMismatchAndSourceUrl': [SKIP], }], # 'arch == mips64el or arch == mips64' -############################################################################## -['(arch == mips64el or arch == mips64) and not simd_mips', { - # Skip tests that fail on MIPS architectures which don't support SIMD, - # because lowering mechanism doesn't work properly - 'test-run-wasm-simd/RunWasm_ReductionTest4_compiled': [SKIP], - 'test-run-wasm-simd/RunWasm_ReductionTest8_compiled': [SKIP], - 'test-run-wasm-simd/RunWasm_ReductionTest16_compiled': [SKIP], - 'test-run-wasm-simd-liftoff/*': [SKIP], -}], # '(arch == mips64el or arch == mips64) and not simd_mips' - -['(arch == mips64el or arch == mips64) and not simd_mips', { - 'test-gc/RunWasmLiftoff_RefTrivialCasts': [SKIP], - 'test-gc/RunWasmTurbofan_RefTrivialCasts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Select_s128_parameters': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Select_s128_parameters': [SKIP], -}], # '(arch == mips64el or arch == mips64) and not simd_mips' - ############################################################################## ['mips_arch_variant == r6', { # For MIPS[64] architecture release 6, fusion multiply-accumulate instructions @@ -495,24 +369,8 @@ # Skipped for unknown reasons. 'test-serialize/StaticRootsPredictableSnapshot': ['pointer_compression', SKIP], - - # According to riscv's NaN generation and propagation scheme, the payload - # is not guaranteed. So the test fails when src bits has payload. - 'test-run-wasm/RunWasmLiftoff_F32ReinterpretI32': [SKIP], - 'test-run-wasm/RunWasmTurbofan_F32ReinterpretI32': [SKIP], - - # Some Wasm functionality is not implemented yet. - 'test-run-wasm-f16/*': [SKIP], - - # Flush to zero is not supported yet. - 'test-wasm-shared-engine/RunImportedWithDenormalsMismatchAndSourceUrl': [SKIP], }], # 'arch == riscv64 or (arch == riscv32)' -['arch == riscv32', { - # Some Wasm functionality is not implemented yet. - 'test-run-wasm-64/*': [SKIP], -}], # 'arch == riscv32' - ############################################################################## ['((arch == riscv64) or (arch == riscv32)) and simulator_run', { @@ -531,8 +389,6 @@ # The uint32 values are sign-extended on loong64. 'test-run-load-store/RunLoadStoreZeroExtend64': [SKIP], 'test-run-load-store/RunUnalignedLoadStoreZeroExtend64': [SKIP], - # Flush to zero is not supported yet. - 'test-wasm-shared-engine/RunImportedWithDenormalsMismatchAndSourceUrl': [SKIP], }], # 'arch == loong64' ############################################################################## @@ -564,9 +420,6 @@ # TODO(ppc): Fix for platforms with function desciptors. 'test-run-machops/RunComputedCodeObject' : [SKIP], - 'test-run-wasm-module/Run_WasmModule_Return114' : [SKIP], - 'test-run-wasm-module/Run_WasmModule_CallAdd' : [SKIP], - 'test-run-wasm-module/Run_WasmModule_CallMain_recursive' : [SKIP], # slow in PASE emulator 'test-cpu-profiler/Inlining2': [PASS, SLOW], 'test-cpu-profiler/CollectCpuProfileCallerLineNumbers': [PASS, SLOW], @@ -590,31 +443,9 @@ }], # 'arch == ppc64 and simulator_run' -############################################################################## -['arch == ppc64 or arch == s390x', { - - # TODO(ppc/s390): support concurrent patching of jump table - 'test-jump-table-assembler/*': [SKIP], - - 'test-wasm-breakpoints/*' : [SKIP], - - # Flush to zero is not supported yet. - 'test-wasm-shared-engine/RunImportedWithDenormalsMismatchAndSourceUrl': [SKIP] - -}], # 'arch == ppc64 or arch == s390x' - ############################################################################## ['variant == stress_incremental_marking', { 'test-heap-profiler/SamplingHeapProfiler': [SKIP], - # Tests time out in stress_incremental_marking. - 'test-run-wasm/RunWasmTurbofan_Float32Add_Consts': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Sub_Consts': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Mul_Consts': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Float32Div_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Add_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Sub_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Mul_Consts': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Float32Div_Consts': [SKIP], # BUG(https://crbug.com/v8/12999): Very slow test. 'test-api/InternalFieldsSubclassing': [PASS, ['mode == debug and arch == ia32', SKIP]], @@ -635,7 +466,6 @@ 'test-cpu-profiler/*': [SKIP], 'test-debug/*': [SKIP], 'test-heap-profiler/*': [SKIP], - 'test-heap/*': [SKIP], 'test-inobject-slack-tracking/*': [SKIP], 'test-lockers/*': [SKIP], 'test-run-machops/*': [SKIP], @@ -659,53 +489,14 @@ 'test-api-array-buffer/ArrayBuffer_NonDetachableWasDetached': [SKIP], 'test-api/TurboAsmDisablesDetach': [SKIP], 'test-api/Wasm*': [SKIP], - 'test-backing-store/Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree': [SKIP], - 'test-compilation-cache/*': [SKIP], - 'test-c-wasm-entry/*': [SKIP], - 'test-fuzzer-steps/*': [SKIP], - 'test-gc/*': [SKIP], - 'test-grow-memory/*': [SKIP], 'test-heap-profiler/HeapSnapshotWithWasmInstance': [SKIP], 'test-js-to-wasm/*': [SKIP], - 'test-jump-table-assembler/*': [SKIP], - 'test-liftoff-for-fuzzing/*': [SKIP], - 'test-liftoff-inspection/*': [SKIP], - 'test-run-wasm*': [SKIP], - 'test-streaming-compilation/*': [SKIP], - 'test-wasm-breakpoints/*': [SKIP], - 'test-wasm-codegen/*': [SKIP], - 'test-wasm-import-wrapper-cache/*': [SKIP], - 'test-wasm-metrics/*': [SKIP], - 'test-wasm-serialization/*': [SKIP], - 'test-wasm-shared-engine/*': [SKIP], - 'test-wasm-stack/*': [SKIP], - 'test-wasm-trap-position/*': [SKIP], 'wasm-run-utils/*': [SKIP], }], # not has_webassembly or variant == jitless -############################################################################## -['has_wasm_interpreter', { - # Skip tests that require Wasm experimental features not supported by the - # Wasm interpreter. - - # --wasm-memory64 - 'test-run-wasm-memory64/*': [SKIP], - - # --wasm-fp16 - 'test-run-wasm-f16/*': [SKIP], - 'test-run-wasm/RunWasmInterpreter_Float32*': [SKIP], - - # --wasm-wide-arithmetic - 'test-run-wasm-64/RunWasmInterpreter_I64MulWideS': [SKIP], - 'test-run-wasm-64/RunWasmInterpreter_I64MulWideU': [SKIP], -}], # has_wasm_interpreter - ############################################################################## ['lite_mode or variant == jitless', { - # Slow tests - 'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [SKIP], - # Tests that generate code at runtime. 'test-accessor-assembler/*': [SKIP], 'test-atomic-load-store-codegen/*': [SKIP], @@ -732,7 +523,6 @@ 'test-torque/*': [SKIP], 'test-verify-type/*': [SKIP], 'test-concurrent-shared-function-info/*': [SKIP], - 'test-concurrent-allocation/*': [SKIP], 'test-sync-primitives-arm64/*': [SKIP], 'turboshaft-test-branch-combine/*': [SKIP], 'turboshaft-test-compare-combine/*': [SKIP], @@ -741,14 +531,6 @@ 'test-unwinder-code-pages/PCIsInV8_LargeCodeObject_CodePagesAPI': [SKIP], 'test-heap-profiler/WeakReference': [SKIP], - 'test-alloc/StressJS': [SKIP], - 'test-alloc/StressHandles': [SKIP], - 'test-heap/CodeLargeObjectSpace': [SKIP], - 'test-heap/CodeLargeObjectSpace64k': [SKIP], - 'test-heap/CodeObjectRegistry': [SKIP], - 'test-heap/HeapObjects': [SKIP], - 'test-heap/Regress10900': [SKIP], - 'test-weak-references/WeakReferencesBasic': [SKIP], # Field representation tracking is disabled in jitless mode. 'test-field-type-tracking/*': [SKIP], @@ -761,8 +543,6 @@ ['has_jitless', { # invocation_count maintenance is disabled. 'test-debug/DebugCoverage*': [SKIP], - # Feedback collection maintenance is (mostly) disabled. - 'test-heap/IncrementalMarkingPreservesMonomorphicCallIC': [SKIP], # WebAssembly not included. 'test-api/Threading8': [SKIP], }], # has_jitless @@ -782,18 +562,7 @@ ['variant == jitless', { # https://crbug.com/v8/7777 'test-cpu-profiler/TickLinesOptimized': [SKIP], - 'test-heap/TestOptimizeAfterBytecodeFlushingCandidate': [SKIP], 'test-js-to-wasm/*': [SKIP], - 'test-run-wasm-exceptions/RunWasmLiftoff_TryCatchCallDirect': [SKIP], - 'test-run-wasm-exceptions/RunWasmLiftoff_TryCatchCallExternal': [SKIP], - 'test-run-wasm-exceptions/RunWasmLiftoff_TryCatchCallIndirect': [SKIP], - 'test-run-wasm-exceptions/RunWasmLiftoff_TryCatchThrow': [SKIP], - 'test-run-wasm-exceptions/RunWasmLiftoff_TryCatchTrapTypeError': [SKIP], - 'test-run-wasm-exceptions/RunWasmTurbofan_TryCatchCallDirect': [SKIP], - 'test-run-wasm-exceptions/RunWasmTurbofan_TryCatchCallExternal': [SKIP], - 'test-run-wasm-exceptions/RunWasmTurbofan_TryCatchCallIndirect': [SKIP], - 'test-run-wasm-exceptions/RunWasmTurbofan_TryCatchThrow': [SKIP], - 'test-run-wasm-exceptions/RunWasmTurbofan_TryCatchTrapTypeError': [SKIP], 'test-verify-type/*': [SKIP], # --interpreted-frames-native-stack tests @@ -810,24 +579,6 @@ '*': [SKIP], # only relevant for mjsunit tests. }], -############################################################################## -['no_simd_hardware == True', { - 'test-run-wasm-relaxed-simd/*': [SKIP], - 'test-run-wasm-simd-liftoff/*': [SKIP], - 'test-run-wasm-simd/*': [SKIP], - 'test-run-wasm-f16/*': [SKIP], - 'test-gc/RunWasmLiftoff_RefTrivialCasts': [SKIP], - 'test-gc/RunWasmTurbofan_RefTrivialCasts': [SKIP], - 'test-gc/RunWasmLiftoff_RefTrivialCastsStatic': [SKIP], - 'test-gc/RunWasmTurbofan_RefTrivialCastsStatic': [SKIP], - 'test-run-wasm/RunWasmLiftoff_Select_s128_parameters': [SKIP], - 'test-run-wasm/RunWasmTurbofan_Select_s128_parameters': [SKIP], - 'test-liftoff-for-fuzzing/NondeterminismUnopF32x4AllNaN': [SKIP], - 'test-liftoff-for-fuzzing/NondeterminismUnopF32x4OneNaN': [SKIP], - 'test-liftoff-for-fuzzing/NondeterminismUnopF64x2AllNaN': [SKIP], - 'test-liftoff-for-fuzzing/NondeterminismUnopF64x2OneNaN': [SKIP], -}], # no_simd_hardware == True - ################################################################################ ['variant == stress_concurrent_inlining', { # crbug.com/v8/11649: Improper access to BreakInfo and friends. @@ -835,13 +586,6 @@ 'test-debug/BreakPointInlining': [PASS, FAIL], # BUG(11524): Crashing flakily. 'test-cpu-profiler/TracingCpuProfiler': [PASS, FAIL], - # crbug.com/v8/11513: Flakily failing due to the additional compile task. - 'test-heap/CellsInOptimizedCodeAreWeak': [PASS, FAIL], - 'test-heap/EnsureAllocationSiteDependentCodesProcessed': [PASS, FAIL], - 'test-heap/LeakNativeContextVia*': [PASS, FAIL], - 'test-heap/NewSpaceObjectsInOptimizedCode': [PASS, FAIL], - 'test-heap/ObjectsInEagerlyDeoptimizedCodeAreWeak': [PASS, FAIL], - 'test-heap/ObjectsInOptimizedCodeAreWeak': [PASS, FAIL], }], # variant == stress_concurrent_inlining ################################################################################ @@ -855,23 +599,8 @@ 'test-calls-with-arraylike-or-spread/*': [SKIP], }], -################################################################################ -['variant == stress or variant == wasm_assert_types or variant == instruction_scheduling or variant == stress_instruction_scheduling or variant == turbofan_random_rescheduling', { - # The 'stress' variant (and the other listed variants) sets the '--no-liftoff' - # flag, which means that Wasm compiles directly to TurboFan. This makes the - # cache no longer incremental, and these tests don't make sense. - 'test-streaming-compilation/AsyncTestIncrementalCaching': [SKIP], - 'test-streaming-compilation/SingleThreadedTestIncrementalCaching': [SKIP], -}], - ############################################################################## ['variant == assert_types', { - # Type assertions add strong pointers, breaking these test. - 'test-heap/ObjectsInOptimizedCodeAreWeak': [SKIP], - 'test-heap/ObjectsInEagerlyDeoptimizedCodeAreWeak': [SKIP], - 'test-heap/NewSpaceObjectsInOptimizedCode': [SKIP], - 'test-heap/LeakNativeContextViaMapKeyed': [SKIP], - 'test-heap/CellsInOptimizedCodeAreWeak': [SKIP], # Type assertions only work without concurrent compilation, but this test # always triggers a concurrent compilation. 'test-concurrent-shared-function-info/TestConcurrentSharedFunctionInfo': [SKIP], @@ -882,18 +611,9 @@ 'test-serialize/StaticRootsPredictableSnapshot': [SKIP], }], # direct_handle -['clang_coverage', { - # Slow tests. - 'test-heap/OutOfMemory': [PASS, SLOW], - 'test-heap/OutOfMemoryIneffectiveGC': [PASS, SLOW], -}], - ['clang_coverage and mode == debug', { # Too slow tests. 'test-api/Threading8': [SKIP], - 'test-concurrent-allocation/ConcurrentAllocationInLargeSpace': [SKIP], - 'test-heap/Regress8014': [SKIP], - 'test-heap/TestInternalWeakLists': [SKIP], 'test-serialize/ContextSerializerContext': [SKIP], 'test-serialize/ContextSerializerCustomContext': [SKIP], 'test-serialize/SharedStrings': [SKIP], @@ -904,33 +624,21 @@ ############################################################################## ['variant == conservative_stack_scanning', { - 'test-run-wasm-64/RunWasmLiftoff_I64WasmRunner': [SLOW], - 'test-run-wasm-64/RunWasmTurbofan_I64WasmRunner': [SLOW], 'test-strings/Traverse': [SLOW], }], # variant == conservative_stack_scanning ############################################################################## ['sandbox_hardware_support', { - # The liftoff-for-fuzzing configuration is currently incompatible with - # sandbox hardware support. See https://crbug.com/431949927. - 'test-liftoff-for-fuzzing/*': [SKIP], - # Tests that require the sampler/profiler, which doesn't work on older kernel # versions if hardware sandboxing is active. See https://crbug.com/429173713. 'test-cpu-profiler/*': [SKIP], 'test-profile-generator/*': [SKIP], - 'test-streaming-compilation/*': [SKIP], 'test-api/SimpleCallbackWithProfiler': [SKIP], 'test-api/FastReturnValuesWithProfiler': [SKIP], 'test-api/FunctionTemplateWithProfiler': [SKIP], 'test-api/CallICFastApi_TrivialSignatureWithProfiler': [SKIP], 'test-api/LoadICFastApi_DirectCall_GCMoveStubWithProfiler': [SKIP], 'test-api/InterceptorCallICFastApi_TrivialSignatureWithProfiler': [SKIP], - - # Tests that rely on Wasm trap handling, which is similarly not supported on - # older kernel versions. See again https://crbug.com/429173713. - 'test-run-wasm-simd/*': [SKIP], - 'test-run-wasm-relaxed-simd/*': [SKIP], }] # sandbox_hardware_support ] diff --git a/deps/v8/test/cctest/collector.h b/deps/v8/test/cctest/collector.h index e535da7588c0..1007496a31a1 100644 --- a/deps/v8/test/cctest/collector.h +++ b/deps/v8/test/cctest/collector.h @@ -8,6 +8,7 @@ #include <vector> #include "src/base/iterator.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/common/checks.h" @@ -27,21 +28,15 @@ template <typename T, int growth_factor = 2, int max_growth = 1 * MB> class Collector { public: explicit Collector(int initial_capacity = kMinCapacity) - : index_(0), size_(0) { - current_chunk_ = base::Vector<T>::New(initial_capacity); - } + : current_chunk_(base::UniqueArray<T>::NewForOverwrite(initial_capacity)), + index_(0), + size_(0) {} - virtual ~Collector() { - // Free backing store (in reverse allocation order). - current_chunk_.Dispose(); - for (auto& chunk : base::Reversed(chunks_)) { - chunk.Dispose(); - } - } + virtual ~Collector() = default; // Add a single element. inline void Add(T value) { - if (index_ >= current_chunk_.length()) { + if (index_ >= static_cast<int>(current_chunk_.size())) { Grow(1); } current_chunk_[index_] = value; @@ -55,7 +50,7 @@ class Collector { // is alive. inline base::Vector<T> AddBlock(int size, T initial_value) { DCHECK_GT(size, 0); - if (size > current_chunk_.length() - index_) { + if (size > static_cast<int>(current_chunk_.size()) - index_) { Grow(size); } T* position = current_chunk_.begin() + index_; @@ -72,7 +67,7 @@ class Collector { // A basic Collector will keep this vector valid as long as the Collector // is alive. inline base::Vector<T> AddBlock(base::Vector<const T> source) { - if (source.length() > current_chunk_.length() - index_) { + if (source.length() > static_cast<int>(current_chunk_.size()) - index_) { Grow(source.length()); } T* position = current_chunk_.begin() + index_; @@ -88,9 +83,9 @@ class Collector { void WriteTo(base::Vector<T> destination) { DCHECK(size_ <= destination.length()); int position = 0; - for (const base::Vector<T>& chunk : chunks_) { - for (int j = 0; j < chunk.length(); j++) { - destination[position] = chunk[j]; + for (const Chunk& chunk : chunks_) { + for (int j = 0; j < chunk.length; j++) { + destination[position] = chunk.data[j]; position++; } } @@ -102,19 +97,15 @@ class Collector { // Allocate a single contiguous vector, copy all the collected // elements to the vector, and return it. - // The caller is responsible for freeing the memory of the returned - // vector (e.g., using Vector::Dispose). - base::Vector<T> ToVector() { - base::Vector<T> new_store = base::Vector<T>::New(size_); - WriteTo(new_store); + base::UniqueArray<T> ToVector() { + base::UniqueArray<T> new_store = + base::UniqueArray<T>::NewForOverwrite(size_); + WriteTo(new_store.as_span()); return new_store; } // Resets the collector to be empty. virtual void Reset() { - for (auto& chunk : base::Reversed(chunks_)) { - chunk.Dispose(); - } chunks_.clear(); index_ = 0; size_ = 0; @@ -124,9 +115,14 @@ class Collector { inline int size() { return size_; } protected: + struct Chunk { + base::UniqueArray<T> data; + int length; + }; + static const int kMinCapacity = 16; - std::vector<base::Vector<T>> chunks_; - base::Vector<T> + std::vector<Chunk> chunks_; + base::UniqueArray<T> current_chunk_; // Block of memory currently being written into. int index_; // Current index in current chunk. int size_; // Total number of elements in collector. @@ -135,7 +131,7 @@ class Collector { void Grow(int min_capacity) { DCHECK_GT(growth_factor, 1); int new_capacity; - int current_length = current_chunk_.length(); + int current_length = static_cast<int>(current_chunk_.size()); if (current_length < kMinCapacity) { // The collector started out as empty. new_capacity = min_capacity * growth_factor; @@ -151,7 +147,7 @@ class Collector { } } NewChunk(new_capacity); - DCHECK(index_ + min_capacity <= current_chunk_.length()); + DCHECK(index_ + min_capacity <= static_cast<int>(current_chunk_.size())); } // Before replacing the current chunk, give a subclass the option to move @@ -159,13 +155,12 @@ class Collector { // the current index_ value to represent data no longer in the current chunk. // Returns the initial index of the new chunk (after copied data). virtual void NewChunk(int new_capacity) { - base::Vector<T> new_chunk = base::Vector<T>::New(new_capacity); + base::UniqueArray<T> new_chunk = + base::UniqueArray<T>::NewForOverwrite(new_capacity); if (index_ > 0) { - chunks_.push_back(current_chunk_.SubVector(0, index_)); - } else { - current_chunk_.Dispose(); + chunks_.push_back({std::move(current_chunk_), index_}); } - current_chunk_ = new_chunk; + current_chunk_ = std::move(new_chunk); index_ = 0; } }; @@ -198,7 +193,8 @@ class SequenceCollector : public Collector<T, growth_factor, max_growth> { int sequence_start = sequence_start_; sequence_start_ = kNoSequence; if (sequence_start == this->index_) return base::Vector<T>(); - return this->current_chunk_.SubVector(sequence_start, this->index_); + return this->current_chunk_.subspan(sequence_start, + this->index_ - sequence_start); } // Drops the currently added sequence, and all collected elements in it. @@ -227,19 +223,17 @@ class SequenceCollector : public Collector<T, growth_factor, max_growth> { return; } int sequence_length = this->index_ - sequence_start_; - base::Vector<T> new_chunk = - base::Vector<T>::New(sequence_length + new_capacity); - DCHECK(sequence_length < new_chunk.length()); + base::UniqueArray<T> new_chunk = + base::UniqueArray<T>::NewForOverwrite(sequence_length + new_capacity); + DCHECK(sequence_length < static_cast<int>(new_chunk.size())); for (int i = 0; i < sequence_length; i++) { new_chunk[i] = this->current_chunk_[sequence_start_ + i]; } if (sequence_start_ > 0) { this->chunks_.push_back( - this->current_chunk_.SubVector(0, sequence_start_)); - } else { - this->current_chunk_.Dispose(); + {std::move(this->current_chunk_), sequence_start_}); } - this->current_chunk_ = new_chunk; + this->current_chunk_ = std::move(new_chunk); this->index_ = sequence_length; sequence_start_ = 0; } diff --git a/deps/v8/test/cctest/compiler/codegen-tester.h b/deps/v8/test/cctest/compiler/codegen-tester.h index 3921323281f6..afbcdb669ffd 100644 --- a/deps/v8/test/cctest/compiler/codegen-tester.h +++ b/deps/v8/test/cctest/compiler/codegen-tester.h @@ -79,8 +79,7 @@ class RawMachineAssemblerTester : public HandleAndZoneScope, Address Generate() override { if (code_.is_null()) { Schedule* schedule = ExportForTest(); - OptimizedCompilationInfo info(base::ArrayVector("testing"), main_zone(), - kind_); + OptimizedCompilationInfo info("testing", main_zone(), kind_); code_ = Pipeline::GenerateCodeForTesting( &info, main_isolate(), call_descriptor(), graph(), AssemblerOptions::Default(main_isolate()), schedule); diff --git a/deps/v8/test/cctest/compiler/test-code-generator.cc b/deps/v8/test/cctest/compiler/test-code-generator.cc index 004525919d82..3a7f2b518f44 100644 --- a/deps/v8/test/cctest/compiler/test-code-generator.cc +++ b/deps/v8/test/cctest/compiler/test-code-generator.cc @@ -1128,8 +1128,7 @@ class CodeGeneratorTester { explicit CodeGeneratorTester(TestEnvironment* environment, int extra_stack_space = 0) : zone_(environment->main_zone()), - info_(base::ArrayVector("test"), environment->main_zone(), - CodeKind::FOR_TESTING), + info_("test", environment->main_zone(), CodeKind::FOR_TESTING), linkage_(environment->test_descriptor()), frame_(environment->test_descriptor()->CalculateFixedFrameSize( CodeKind::FOR_TESTING), @@ -1641,7 +1640,6 @@ TEST(AssembleTailCallGap) { #if V8_TARGET_ARCH_X64 TEST(TurboFanFrameSlotAlignment) { - FLAG_SCOPE(enforce_x64_16byte_alignment); TestEnvironment env; Isolate* isolate = env.main_isolate(); Linkage linkage(env.test_descriptor()); @@ -1659,16 +1657,21 @@ TEST(TurboFanFrameSlotAlignment) { } frame.EnsureReturnSlots(return_slots); - OptimizedCompilationInfo info(base::ArrayVector("test"), &zone, - CodeKind::FOR_TESTING); + OptimizedCompilationInfo info("test", &zone, CodeKind::FOR_TESTING); CodeGenerator codegen( &zone, &frame, &linkage, env.instructions(), &info, isolate, std::optional<OsrHelper>(), kNoSourcePosition, nullptr, AssemblerOptions::Default(isolate), Builtin::kNoBuiltinId, 0, 0); // FinishFrame() has now run via CodeGenerator's constructor. - CHECK_EQ(0, frame.GetTotalFrameSlotCount() % 2); - CHECK_EQ(0, frame.GetReturnSlotCount() % 2); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + CHECK_EQ(0, frame.GetTotalFrameSlotCount() % 2); + CHECK_EQ(0, frame.GetReturnSlotCount() % 2); + } else { + CHECK_EQ(fixed_slots + spill_slots + return_slots, + frame.GetTotalFrameSlotCount()); + CHECK_EQ(return_slots, frame.GetReturnSlotCount()); + } CodeGeneratorTester::AssembleConstructFrameForTest(&codegen); } @@ -1731,8 +1734,8 @@ TEST(Regress_1171759) { m.Return(m.Int32Constant(0)); - OptimizedCompilationInfo info(base::ArrayVector("testing"), - handles.main_zone(), CodeKind::WASM_FUNCTION); + OptimizedCompilationInfo info("testing", handles.main_zone(), + CodeKind::WASM_FUNCTION); wasm::WasmCompilationResult result = Pipeline::GenerateWasmCodeForTesting( &info, handles.main_isolate(), desc, m.graph(), AssemblerOptions::Default(handles.main_isolate()), m.ExportForTest()); diff --git a/deps/v8/test/cctest/compiler/test-concurrent-shared-function-info.cc b/deps/v8/test/cctest/compiler/test-concurrent-shared-function-info.cc index de19c6e368b7..f23a4b6e78fc 100644 --- a/deps/v8/test/cctest/compiler/test-concurrent-shared-function-info.cc +++ b/deps/v8/test/cctest/compiler/test-concurrent-shared-function-info.cc @@ -71,7 +71,6 @@ class BackgroundCompilationThread final : public v8::base::Thread { job_(job) {} void Run() override { - base::FlushDenormalsScope denormals_scope(isolate_->flush_denormals()); RuntimeCallStats stats(RuntimeCallStats::kWorkerThread); LocalIsolate local_isolate(isolate_, ThreadKind::kBackground); sema_execute_start_->Wait(); diff --git a/deps/v8/test/cctest/compiler/test-multiple-return.cc b/deps/v8/test/cctest/compiler/test-multiple-return.cc index 2e2243ca3cda..d4e9a38834c3 100644 --- a/deps/v8/test/cctest/compiler/test-multiple-return.cc +++ b/deps/v8/test/cctest/compiler/test-multiple-return.cc @@ -163,8 +163,7 @@ void TestReturnMultipleValues(MachineType type, int min_count, int max_count) { } m.Return(count, returns.get()); - OptimizedCompilationInfo info(base::ArrayVector("testing"), - handles.main_zone(), + OptimizedCompilationInfo info("testing", handles.main_zone(), CodeKind::WASM_FUNCTION); wasm::WasmCompilationResult wasm_result = Pipeline::GenerateWasmCodeForTesting( @@ -285,8 +284,8 @@ void ReturnLastValue(MachineType type) { m.Return(return_count, returns.get()); - OptimizedCompilationInfo info(base::ArrayVector("testing"), - handles.main_zone(), CodeKind::WASM_FUNCTION); + OptimizedCompilationInfo info("testing", handles.main_zone(), + CodeKind::WASM_FUNCTION); wasm::WasmCompilationResult wasm_result = Pipeline::GenerateWasmCodeForTesting( &info, handles.main_isolate(), desc, m.graph(), @@ -356,8 +355,8 @@ void ReturnSumOfReturns(MachineType type) { m.Return(return_count, returns.get()); - OptimizedCompilationInfo info(base::ArrayVector("testing"), - handles.main_zone(), CodeKind::WASM_FUNCTION); + OptimizedCompilationInfo info("testing", handles.main_zone(), + CodeKind::WASM_FUNCTION); wasm::WasmCompilationResult wasm_result = Pipeline::GenerateWasmCodeForTesting( &info, handles.main_isolate(), desc, m.graph(), diff --git a/deps/v8/test/cctest/compiler/test-run-native-calls.cc b/deps/v8/test/cctest/compiler/test-run-native-calls.cc index c2c043b21bff..b44ddf4976b6 100644 --- a/deps/v8/test/cctest/compiler/test-run-native-calls.cc +++ b/deps/v8/test/cctest/compiler/test-run-native-calls.cc @@ -237,7 +237,7 @@ class Int32Signature : public MachineSignature { Handle<Code> CompileGraph(const char* name, CallDescriptor* call_descriptor, TFGraph* graph, Schedule* schedule = nullptr) { Isolate* isolate = CcTest::InitIsolateOnce(); - OptimizedCompilationInfo info(base::ArrayVector("testing"), graph->zone(), + OptimizedCompilationInfo info("testing", graph->zone(), CodeKind::FOR_TESTING); Handle<Code> code = Pipeline::GenerateCodeForTesting( &info, isolate, call_descriptor, graph, @@ -284,7 +284,8 @@ DirectHandle<Code> WrapWithCFunction(Isolate* isolate, Handle<Code> inner, } MachineSignature* msig = call_descriptor->GetMachineSignature(&zone); - CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, msig); + CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor( + &zone, msig, CallDescriptor::kInitializeRootRegister); return CompileGraph("wrapper", cdesc, caller.graph()); } @@ -437,7 +438,8 @@ class Computer { // Wrap the above code with a callable function that passes constants. Zone zone(isolate->allocator(), ZONE_NAME); TFGraph graph(&zone); - CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); + CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor( + &zone, &csig, CallDescriptor::kInitializeRootRegister); RawMachineAssembler raw(isolate, &graph, cdesc); Node* target = raw.HeapConstant(inner); Node** inputs = zone.AllocateArray<Node*>(num_params + 1); @@ -471,7 +473,8 @@ class Computer { // Wrap the above code with a callable function that loads from {input}. Zone zone(isolate->allocator(), ZONE_NAME); TFGraph graph(&zone); - CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); + CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor( + &zone, &csig, CallDescriptor::kInitializeRootRegister); RawMachineAssembler raw(isolate, &graph, cdesc); Node* base = raw.PointerConstant(io.input); Node* target = raw.HeapConstant(inner); @@ -571,7 +574,8 @@ static void CopyTwentyInt32(CallDescriptor* desc) { // Loads parameters from the input buffer and calls the above code. Zone zone(isolate->allocator(), ZONE_NAME); TFGraph graph(&zone); - CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor(&zone, &csig); + CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor( + &zone, &csig, CallDescriptor::kInitializeRootRegister); RawMachineAssembler raw(isolate, &graph, cdesc); Node* base = raw.PointerConstant(input); Node* target = raw.HeapConstant(inner); @@ -1058,8 +1062,8 @@ void MixedParamTest(int start) { // Wrap the select code with a callable function that passes constants. Zone wrap_zone(&allocator, ZONE_NAME); TFGraph graph(&wrap_zone); - CallDescriptor* cdesc = - Linkage::GetSimplifiedCDescriptor(&wrap_zone, &csig); + CallDescriptor* cdesc = Linkage::GetSimplifiedCDescriptor( + &wrap_zone, &csig, CallDescriptor::kInitializeRootRegister); RawMachineAssembler raw(isolate, &graph, cdesc); Node* target = raw.HeapConstant(select); Node** inputs = wrap_zone.AllocateArray<Node*>(num_params + 1); diff --git a/deps/v8/test/cctest/compiler/turboshaft-codegen-tester.h b/deps/v8/test/cctest/compiler/turboshaft-codegen-tester.h index 5f60a3197efa..4b2e30eaaaf3 100644 --- a/deps/v8/test/cctest/compiler/turboshaft-codegen-tester.h +++ b/deps/v8/test/cctest/compiler/turboshaft-codegen-tester.h @@ -37,8 +37,8 @@ class DataHolder { ParamMachTypes... p) : isolate_(isolate), graph_zone_(zone), - info_(zone->New<OptimizedCompilationInfo>(base::ArrayVector("testing"), - zone, CodeKind::FOR_TESTING)), + info_(zone->New<OptimizedCompilationInfo>("testing", zone, + CodeKind::FOR_TESTING)), zone_stats_(isolate->allocator()), ts_pipeline_data_(&zone_stats_, turboshaft::TurboshaftPipelineKind::kJS, isolate, info_, AssemblerOptions::Default(isolate)), diff --git a/deps/v8/test/cctest/heap/heap-tester.h b/deps/v8/test/cctest/heap/heap-tester.h index 219cc501f274..932468b4a6b8 100644 --- a/deps/v8/test/cctest/heap/heap-tester.h +++ b/deps/v8/test/cctest/heap/heap-tester.h @@ -5,73 +5,18 @@ #ifndef HEAP_HEAP_TESTER_H_ #define HEAP_HEAP_TESTER_H_ -#include "src/heap/spaces.h" -#include "src/objects/fixed-array.h" +#include "src/heap/allocation-result.h" +#include "src/objects/objects.h" // Tests that should have access to private methods of {v8::internal::Heap}. // Those tests need to be defined using HEAP_TEST(Name) { ... }. -#define HEAP_TEST_METHODS(V) \ - V(CodeLargeObjectSpace) \ - V(CodeLargeObjectSpace64k) \ - V(CompactionFullAbortedPage) \ - V(CompactionPartiallyAbortedPage) \ - V(CompactionPartiallyAbortedPageIntraAbortedPointers) \ - V(CompactionPartiallyAbortedPageWithInvalidatedSlots) \ - V(CompactionPartiallyAbortedPageWithRememberedSetEntries) \ - V(CompactionSpaceDivideMultiplePages) \ - V(CompactionSpaceDivideSinglePage) \ - V(InvalidatedSlotsAfterTrimming) \ - V(InvalidatedSlotsAllInvalidatedRanges) \ - V(InvalidatedSlotsCleanupEachObject) \ - V(InvalidatedSlotsCleanupFull) \ - V(InvalidatedSlotsCleanupRightTrim) \ - V(InvalidatedSlotsCleanupOverlapRight) \ - V(InvalidatedSlotsEvacuationCandidate) \ - V(InvalidatedSlotsNoInvalidatedRanges) \ - V(InvalidatedSlotsResetObjectRegression) \ - V(InvalidatedSlotsRightTrimFixedArray) \ - V(InvalidatedSlotsRightTrimLargeFixedArray) \ - V(InvalidatedSlotsFastToSlow) \ - V(InvalidatedSlotsSomeInvalidatedRanges) \ - V(TestNewSpaceRefsInCopiedCode) \ - V(MarkCompactCollector) \ - V(MemoryReducerActivationForSmallHeaps) \ - V(NoPromotion) \ - V(NumberStringCacheSize) \ - V(ObjectGroups) \ - V(Promotion) \ - V(Regression39128) \ - V(ResetWeakHandle) \ - V(StressHandles) \ - V(TestMemoryReducerSampleJsCalls) \ - V(TestSizeOfObjects) \ - V(Regress10560) \ - V(Regress538257) \ - V(Regress658718) \ - V(Regress777177) \ - V(Regress779503) \ - V(Regress791582) \ - V(WriteBarrier_Marking) \ - V(WriteBarrier_MarkingExtension) \ - V(WriteBarriersInCopyJSObject) \ - V(DoNotEvacuatePinnedPages) \ - V(ObjectStartBitmap) +#define HEAP_TEST_METHODS(V) #define HEAP_TEST(Name) \ CcTest register_test_##Name(v8::internal::heap::HeapTester::Test##Name, \ __FILE__, #Name, true, true); \ void v8::internal::heap::HeapTester::Test##Name() -#define UNINITIALIZED_HEAP_TEST(Name) \ - CcTest register_test_##Name(v8::internal::heap::HeapTester::Test##Name, \ - __FILE__, #Name, true, false); \ - void v8::internal::heap::HeapTester::Test##Name() - -#define THREADED_HEAP_TEST(Name) \ - RegisterThreadedTest register_##Name( \ - v8::internal::heap::HeapTester::Test##Name, #Name); \ - /* */ HEAP_TEST(Name) - namespace v8 { namespace internal { namespace heap { @@ -83,28 +28,8 @@ class HeapTester { HEAP_TEST_METHODS(DECLARE_STATIC) #undef HEAP_TEST_METHODS - // test-alloc.cc - static AllocationResult AllocateAfterFailures(); - static DirectHandle<Object> TestAllocateAfterFailures(); - - // test-invalidated-slots.cc - static NormalPage* AllocateByteArraysOnPage( - Heap* heap, std::vector<ByteArray>* byte_arrays); - // test-api.cc static void ResetWeakHandle(bool global_gc); - - // test-heap.cc - static AllocationResult AllocateByteArrayForTest(Heap* heap, uint32_t length, - AllocationType allocation); - static bool CodeEnsureLinearAllocationArea(Heap* heap, int size_in_bytes); - - // test-mark-compact.cc - static AllocationResult AllocateMapForTest(v8::internal::Isolate* isolate); - static AllocationResult AllocateFixedArrayForTest(Heap* heap, uint32_t length, - AllocationType allocation); - - static void UncommitUnusedMemory(Heap* heap); }; } // namespace heap diff --git a/deps/v8/test/cctest/heap/heap-utils.cc b/deps/v8/test/cctest/heap/heap-utils.cc index 9d6ed0e71ef1..927fde375b56 100644 --- a/deps/v8/test/cctest/heap/heap-utils.cc +++ b/deps/v8/test/cctest/heap/heap-utils.cc @@ -23,6 +23,7 @@ #include "src/heap/spaces.h" #include "src/objects/free-space-inl.h" #include "test/cctest/cctest.h" +#include "test/cctest/heap/heap-tester.h" namespace v8 { namespace internal { @@ -48,46 +49,6 @@ int FixedArrayLenFromSize(int size) { FixedArray::kMaxRegularLength}); } -void FillOldSpacePageWithFixedArrays( - Heap* heap, int remainder, DirectHandleVector<FixedArray>* out_handles) { - PauseAllocationObserversScope pause_observers(heap); - Isolate* isolate = heap->isolate(); - const int kArraySize = 128; - const int kArrayLen = heap::FixedArrayLenFromSize(kArraySize); - int allocated = 0; - bool empty = true; - do { - DirectHandle<FixedArray> array; - if (allocated + kArraySize * 2 > - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage())) { - int size = - kArraySize * 2 - - ((allocated + kArraySize * 2) - - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage())) - - remainder; - int last_array_len = heap::FixedArrayLenFromSize(size); - array = isolate->factory()->NewFixedArray(last_array_len, - AllocationType::kOld); - CHECK_EQ(size, array->Size()); - allocated += array->Size() + remainder; - } else { - array = - isolate->factory()->NewFixedArray(kArrayLen, AllocationType::kOld); - allocated += array->Size(); - CHECK_EQ(kArraySize, array->Size()); - } - if (empty) { - // Check that allocations started on a new page. - CHECK_EQ(array->address(), - NormalPage::FromHeapObject(*array)->area_start()); - empty = false; - } - if (out_handles) out_handles->push_back(array); - } while (allocated < - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage())); - heap->FreeMainThreadLinearAllocationAreas(); -} - void CreatePadding(Heap* heap, int padding_size, AllocationType allocation, DirectHandleVector<FixedArray>* out_handles, int object_size) { @@ -226,25 +187,6 @@ void FillPageInPagedSpace(NormalPage* page, CHECK_EQ(epoch, heap->tracer()->CurrentEpoch()); heap->FreeLinearAllocationAreas(); } -} // namespace - -void FillCurrentPage(v8::internal::NewSpace* space, - DirectHandleVector<FixedArray>* out_handles) { - if (v8_flags.minor_ms) { - const Address top = space->heap()->NewSpaceTop(); - space->heap()->FreeMainThreadLinearAllocationAreas(); - PauseAllocationObserversScope pause_observers(space->heap()); - if (top == kNullAddress) return; - NormalPage* page = NormalPage::FromAllocationAreaAddress(top); - space->heap()->EnsureSweepingCompleted( - Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - FillPageInPagedSpace(page, out_handles); - space->heap()->FreeMainThreadLinearAllocationAreas(); - } else { - FillCurrentPageButNBytes(SemiSpaceNewSpace::From(space), 0, out_handles); - } -} void FillCurrentPageButNBytes(v8::internal::SemiSpaceNewSpace* space, int extra_bytes, @@ -265,6 +207,25 @@ void FillCurrentPageButNBytes(v8::internal::SemiSpaceNewSpace* space, out_handles); space->heap()->FreeMainThreadLinearAllocationAreas(); } +} // namespace + +void FillCurrentPage(v8::internal::NewSpace* space, + DirectHandleVector<FixedArray>* out_handles) { + if (v8_flags.minor_ms) { + const Address top = space->heap()->NewSpaceTop(); + space->heap()->FreeMainThreadLinearAllocationAreas(); + PauseAllocationObserversScope pause_observers(space->heap()); + if (top == kNullAddress) return; + NormalPage* page = NormalPage::FromAllocationAreaAddress(top); + space->heap()->EnsureSweepingCompleted( + Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + FillPageInPagedSpace(page, out_handles); + space->heap()->FreeMainThreadLinearAllocationAreas(); + } else { + FillCurrentPageButNBytes(SemiSpaceNewSpace::From(space), 0, out_handles); + } +} void SimulateIncrementalMarking(i::Heap* heap, bool force_completion) { static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); diff --git a/deps/v8/test/cctest/heap/heap-utils.h b/deps/v8/test/cctest/heap/heap-utils.h index 68435384fd03..754bd9f39725 100644 --- a/deps/v8/test/cctest/heap/heap-utils.h +++ b/deps/v8/test/cctest/heap/heap-utils.h @@ -18,14 +18,6 @@ void SealCurrentObjects(Heap* heap); int FixedArrayLenFromSize(int size); -// Fill a page with fixed arrays leaving remainder behind. The function does -// not create additional fillers and assumes that the space has just been -// sealed. If out_handles is not null, it appends the fixed arrays to the -// pointed vector. -void FillOldSpacePageWithFixedArrays( - Heap* heap, int remainder, - DirectHandleVector<FixedArray>* out_handles = nullptr); - void CreatePadding(Heap* heap, int padding_size, AllocationType allocation, DirectHandleVector<FixedArray>* out_handles = nullptr, int object_size = kMaxRegularHeapObjectSize); @@ -33,10 +25,6 @@ void CreatePadding(Heap* heap, int padding_size, AllocationType allocation, void FillCurrentPage(v8::internal::NewSpace* space, DirectHandleVector<FixedArray>* out_handles = nullptr); -void FillCurrentPageButNBytes( - v8::internal::SemiSpaceNewSpace* space, int extra_bytes, - DirectHandleVector<FixedArray>* out_handles = nullptr); - // Helper function that simulates many incremental marking steps until // marking is completed. void SimulateIncrementalMarking(i::Heap* heap, bool force_completion = true); @@ -58,27 +46,10 @@ void EmptyNewSpaceUsingGC(Heap* heap); void ForceEvacuationCandidate(NormalPage* page); -void GrowNewSpace(Heap* heap); - void GrowNewSpaceToMaximumCapacity(Heap* heap); -template <typename GlobalOrPersistent> -bool InYoungGeneration(v8::Isolate* isolate, const GlobalOrPersistent& global) { - v8::HandleScope scope(isolate); - auto tmp = global.Get(isolate); - return i::HeapLayout::InYoungGeneration(*v8::Utils::OpenDirectHandle(*tmp)); -} - bool InCorrectGeneration(Tagged<HeapObject> object); -template <typename GlobalOrPersistent> -bool InCorrectGeneration(v8::Isolate* isolate, - const GlobalOrPersistent& global) { - v8::HandleScope scope(isolate); - auto tmp = global.Get(isolate); - return InCorrectGeneration(*v8::Utils::OpenDirectHandle(*tmp)); -} - class ManualEvacuationCandidatesSelectionScope { public: // Marking a page as an evacuation candidate update the page flags which may diff --git a/deps/v8/test/cctest/heap/test-alloc.cc b/deps/v8/test/cctest/heap/test-alloc.cc deleted file mode 100644 index 369650758e2b..000000000000 --- a/deps/v8/test/cctest/heap/test-alloc.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "include/v8-function.h" -#include "src/api/api-inl.h" -#include "src/builtins/accessors.h" -#include "src/heap/heap-inl.h" -#include "src/init/v8.h" -#include "src/objects/api-callbacks.h" -#include "src/objects/objects-inl.h" -#include "src/objects/property.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8 { -namespace internal { -namespace heap { - -DirectHandle<Object> HeapTester::TestAllocateAfterFailures() { - // Similar to what the factory's retrying logic does in the last-resort case, - // we wrap the allocator function in an AlwaysAllocateScope. Test that - // all allocations succeed immediately without any retry. - Heap* heap = CcTest::heap(); - heap::InvokeMemoryReducingMajorGCs(heap); - AlwaysAllocateScopeForTesting scope(heap); - int size = FixedArray::SizeFor(100); - // Young generation. - Tagged<HeapObject> obj = - heap->AllocateRaw(size, AllocationType::kYoung).ToObjectChecked(); - // In order to pass heap verification on Isolate teardown, mark the - // allocated area as a filler. - heap->CreateFillerObjectAt(obj.address(), size); - - // Old generation. - heap::SimulateFullSpace(heap->old_space()); - obj = heap->AllocateRaw(size, AllocationType::kOld).ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), size); - - // Large object space. - static const size_t kLargeObjectSpaceFillerLength = - 3 * (NormalPage::kPageSize / 10); - static const size_t kLargeObjectSpaceFillerSize = - FixedArray::SizeFor(kLargeObjectSpaceFillerLength); - CHECK_GT(kLargeObjectSpaceFillerSize, - static_cast<size_t>(heap->old_space()->AreaSize())); - while (heap->OldGenerationSpaceAvailable() > kLargeObjectSpaceFillerSize) { - obj = heap->AllocateRaw(kLargeObjectSpaceFillerSize, AllocationType::kOld) - .ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), size); - } - obj = heap->AllocateRaw(kLargeObjectSpaceFillerSize, AllocationType::kOld) - .ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), size); - - // Map space. - heap::SimulateFullSpace(heap->old_space()); - obj = heap->AllocateRaw(Map::kSize, AllocationType::kMap).ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), Map::kSize); - - // Code space. - heap::SimulateFullSpace(heap->code_space()); - size = CcTest::i_isolate()->builtins()->code(Builtin::kIllegal)->Size(); - obj = - heap->AllocateRaw(size, AllocationType::kCode, AllocationOrigin::kRuntime) - .ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), size); - return CcTest::i_isolate()->factory()->true_value(); -} - -HEAP_TEST(StressHandles) { - // For TestAllocateAfterFailures. - v8_flags.stress_concurrent_allocation = false; - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Context> env = v8::Context::New(CcTest::isolate()); - env->Enter(); - DirectHandle<Object> o = TestAllocateAfterFailures(); - CHECK(IsTrue(*o)); - env->Exit(); -} - - -void TestGetter( - v8::Local<v8::Name> name, - const v8::PropertyCallbackInfo<v8::Value>& info) { - i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate()); - HandleScope scope(isolate); - info.GetReturnValue().Set( - v8::Utils::ToLocal(HeapTester::TestAllocateAfterFailures())); -} - -void TestSetter(v8::Local<v8::Name> name, v8::Local<v8::Value> value, - const v8::PropertyCallbackInfo<v8::Boolean>& info) { - UNREACHABLE(); -} - -DirectHandle<AccessorInfo> TestAccessorInfo(Isolate* isolate, - PropertyAttributes attributes) { - DirectHandle<String> name = - isolate->factory()->NewStringFromStaticChars("get"); - return Accessors::MakeAccessor(isolate, name, &TestGetter, &TestSetter); -} - -TEST(StressJS) { - // For TestAllocateAfterFailures in TestGetter. - v8_flags.stress_concurrent_allocation = false; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Context> env = v8::Context::New(CcTest::isolate()); - env->Enter(); - - DirectHandle<NativeContext> context(isolate->native_context()); - DirectHandle<SharedFunctionInfo> info = - factory->NewSharedFunctionInfoForBuiltin( - factory->function_string(), Builtin::kEmptyFunction, 0, kDontAdapt); - info->set_language_mode(LanguageMode::kStrict); - DirectHandle<JSFunction> function = - Factory::JSFunctionBuilder{isolate, info, context}.Build(); - CHECK(!function->shared()->construct_as_builtin()); - - // Force the creation of an initial map. - factory->NewJSObject(function); - - // Patch the map to have an accessor for "get". - DirectHandle<Map> map(function->initial_map(), isolate); - DirectHandle<DescriptorArray> instance_descriptors( - map->instance_descriptors(), isolate); - CHECK_EQ(0, instance_descriptors->number_of_descriptors()); - - PropertyAttributes attrs = NONE; - DirectHandle<AccessorInfo> foreign = TestAccessorInfo(isolate, attrs); - Map::EnsureDescriptorSlack(isolate, map, 1); - - Descriptor d = Descriptor::AccessorConstant( - DirectHandle<Name>(Cast<Name>(foreign->name()), isolate), foreign, attrs); - map->AppendDescriptor(isolate, &d); - - // Add the Foo constructor the global object. - CHECK(env->Global() - ->Set(env, v8::String::NewFromUtf8Literal(CcTest::isolate(), "Foo"), - v8::Utils::CallableToLocal(function)) - .FromJust()); - // Call the accessor through JavaScript. - v8::Local<v8::Value> result = - v8::Script::Compile(env, v8::String::NewFromUtf8Literal(CcTest::isolate(), - "(new Foo).get")) - .ToLocalChecked() - ->Run(env) - .ToLocalChecked(); - CHECK_EQ(true, result->BooleanValue(CcTest::isolate())); - env->Exit(); -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-compaction.cc b/deps/v8/test/cctest/heap/test-compaction.cc deleted file mode 100644 index 2fb616e67808..000000000000 --- a/deps/v8/test/cctest/heap/test-compaction.cc +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright 2015 the V8 project 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 "src/execution/isolate.h" -#include "src/heap/factory.h" -#include "src/heap/heap-inl.h" -#include "src/heap/mark-compact.h" -#include "src/heap/marking-state-inl.h" -#include "src/heap/mutable-page.h" -#include "src/heap/remembered-set-inl.h" -#include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8 { -namespace internal { -namespace heap { - -namespace { - -void CheckInvariantsOfAbortedPage(NormalPage* page) { - // Check invariants: - // 1) Markbits are cleared - // 2) The page is not marked as evacuation candidate anymore - // 3) The page is not marked as aborted compaction anymore. - CHECK(page->marking_bitmap()->IsClean()); - CHECK(!page->is_evacuation_candidate()); - CHECK(!page->evacuation_was_aborted()); -} - -void CheckAllObjectsOnPage(const DirectHandleVector<FixedArray>& handles, - NormalPage* page) { - for (DirectHandle<FixedArray> fixed_array : handles) { - CHECK(NormalPage::FromHeapObject(*fixed_array) == page); - } -} - -} // namespace - -HEAP_TEST(CompactionFullAbortedPage) { - if (!v8_flags.compact) return; - // Test the scenario where we reach OOM during compaction and the whole page - // is aborted. - - // Disable concurrent sweeping to ensure memory is in an expected state, i.e., - // we can reach the state of a half aborted page. - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - auto reset_oom = [](void* heap, size_t limit, size_t) -> size_t { - reinterpret_cast<Heap*>(heap)->set_force_oom(false); - return limit; - }; - heap->AddNearHeapLimitCallback(reset_oom, heap); - { - HandleScope scope1(isolate); - - heap::SealCurrentObjects(heap); - - { - HandleScope scope2(isolate); - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - DirectHandleVector<FixedArray> compaction_page_handles(isolate); - heap::CreatePadding( - heap, - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), - AllocationType::kOld, &compaction_page_handles); - NormalPage* to_be_aborted_page = - NormalPage::FromHeapObject(*compaction_page_handles.front()); - to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); - CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); - - heap->set_force_oom(true); - heap::InvokeMajorGC(heap); - heap->EnsureSweepingCompleted( - Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - - // Check that all handles still point to the same page, i.e., compaction - // has been aborted on the page. - for (DirectHandle<FixedArray> object : compaction_page_handles) { - CHECK_EQ(to_be_aborted_page, NormalPage::FromHeapObject(*object)); - } - CheckInvariantsOfAbortedPage(to_be_aborted_page); - } - } - heap->RemoveNearHeapLimitCallback(reset_oom, 0u); -} - -namespace { - -int GetObjectSize(int objects_per_page) { - int allocatable = - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()); - // Make sure that object_size is a multiple of kTaggedSize. - int object_size = - ((allocatable / kTaggedSize) / objects_per_page) * kTaggedSize; - return std::min(kMaxRegularHeapObjectSize, object_size); -} - -} // namespace - -HEAP_TEST(CompactionPartiallyAbortedPage) { - if (!v8_flags.compact) return; - // Test the scenario where we reach OOM during compaction and parts of the - // page have already been migrated to a new one. - - // Disable concurrent sweeping to ensure memory is in an expected state, i.e., - // we can reach the state of a half aborted page. - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - - const int objects_per_page = 10; - const int object_size = GetObjectSize(objects_per_page); - - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - auto reset_oom = [](void* heap, size_t limit, size_t) -> size_t { - reinterpret_cast<Heap*>(heap)->set_force_oom(false); - return limit; - }; - heap->AddNearHeapLimitCallback(reset_oom, heap); - { - HandleScope scope1(isolate); - - heap::SealCurrentObjects(heap); - - { - HandleScope scope2(isolate); - // Fill another page with objects of size {object_size} (last one is - // properly adjusted). - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - DirectHandleVector<FixedArray> compaction_page_handles(isolate); - heap::CreatePadding( - heap, - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), - AllocationType::kOld, &compaction_page_handles, object_size); - NormalPage* to_be_aborted_page = - NormalPage::FromHeapObject(*compaction_page_handles.front()); - to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); - CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); - - { - // Add another page that is filled with {num_objects} objects of size - // {object_size}. - HandleScope scope3(isolate); - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - const int num_objects = 3; - DirectHandleVector<FixedArray> page_to_fill_handles(isolate); - heap::CreatePadding(heap, object_size * num_objects, - AllocationType::kOld, &page_to_fill_handles, - object_size); - NormalPage* page_to_fill = - NormalPage::FromAddress(page_to_fill_handles.front()->address()); - - heap->set_force_oom(true); - heap::InvokeMajorGC(heap); - heap->EnsureSweepingCompleted( - Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - - bool migration_aborted = false; - for (DirectHandle<FixedArray> object : compaction_page_handles) { - // Once compaction has been aborted, all following objects still have - // to be on the initial page. - CHECK(!migration_aborted || - (NormalPage::FromHeapObject(*object) == to_be_aborted_page)); - if (NormalPage::FromHeapObject(*object) == to_be_aborted_page) { - // This object has not been migrated. - migration_aborted = true; - } else { - CHECK_EQ(NormalPage::FromHeapObject(*object), page_to_fill); - } - } - // Check that we actually created a scenario with a partially aborted - // page. - CHECK(migration_aborted); - CheckInvariantsOfAbortedPage(to_be_aborted_page); - } - } - } - heap->RemoveNearHeapLimitCallback(reset_oom, 0u); -} - -HEAP_TEST(CompactionPartiallyAbortedPageIntraAbortedPointers) { - if (!v8_flags.compact) return; - // Test the scenario where we reach OOM during compaction and parts of the - // page have already been migrated to a new one. Objects on the aborted page - // are linked together. This test makes sure that intra-aborted page pointers - // get properly updated. - - // Disable concurrent sweeping to ensure memory is in an expected state, i.e., - // we can reach the state of a half aborted page. - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - - const int objects_per_page = 10; - const int object_size = GetObjectSize(objects_per_page); - - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - auto reset_oom = [](void* heap, size_t limit, size_t) -> size_t { - reinterpret_cast<Heap*>(heap)->set_force_oom(false); - return limit; - }; - heap->AddNearHeapLimitCallback(reset_oom, heap); - { - HandleScope scope1(isolate); - IndirectHandle<FixedArray> root_array = - isolate->factory()->NewFixedArray(10, AllocationType::kOld); - - heap::SealCurrentObjects(heap); - - NormalPage* to_be_aborted_page = nullptr; - { - HandleScope temporary_scope(isolate); - // Fill a fresh page with objects of size {object_size} (last one is - // properly adjusted). - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - DirectHandleVector<FixedArray> compaction_page_handles(isolate); - heap::CreatePadding( - heap, - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), - AllocationType::kOld, &compaction_page_handles, object_size); - to_be_aborted_page = - NormalPage::FromHeapObject(*compaction_page_handles.front()); - to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); - for (size_t i = compaction_page_handles.size() - 1; i > 0; i--) { - compaction_page_handles[i]->set(0, *compaction_page_handles[i - 1]); - } - root_array->set(0, *compaction_page_handles.back()); - CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); - } - { - // Add another page that is filled with {num_objects} objects of size - // {object_size}. - HandleScope scope3(isolate); - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - const int num_objects = 2; - int used_memory = object_size * num_objects; - DirectHandleVector<FixedArray> page_to_fill_handles(isolate); - heap::CreatePadding(heap, used_memory, AllocationType::kOld, - &page_to_fill_handles, object_size); - NormalPage* page_to_fill = - NormalPage::FromHeapObject(*page_to_fill_handles.front()); - - // We need to invoke GC without stack, otherwise no compaction is - // performed. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - - heap->set_force_oom(true); - heap::InvokeMajorGC(heap); - heap->EnsureSweepingCompleted( - Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - - // The following check makes sure that we compacted "some" objects, while - // leaving others in place. - bool in_place = true; - IndirectHandle<FixedArray> current = root_array; - while (current->get(0) != ReadOnlyRoots(heap).undefined_value()) { - current = IndirectHandle<FixedArray>(Cast<FixedArray>(current->get(0)), - isolate); - CHECK(IsFixedArray(*current)); - if (NormalPage::FromHeapObject(*current) != to_be_aborted_page) { - in_place = false; - } - bool on_aborted_page = - NormalPage::FromHeapObject(*current) == to_be_aborted_page; - bool on_fill_page = - NormalPage::FromHeapObject(*current) == page_to_fill; - CHECK((in_place && on_aborted_page) || (!in_place && on_fill_page)); - } - // Check that we at least migrated one object, as otherwise the test would - // not trigger. - CHECK(!in_place); - CheckInvariantsOfAbortedPage(to_be_aborted_page); - } - } - heap->RemoveNearHeapLimitCallback(reset_oom, 0u); -} - -HEAP_TEST(CompactionPartiallyAbortedPageWithRememberedSetEntries) { - if (!v8_flags.compact || v8_flags.single_generation) return; - // Test the scenario where we reach OOM during compaction and parts of the - // page have already been migrated to a new one. Objects on the aborted page - // are linked together and the very first object on the aborted page points - // into new space. The test verifies that the remembered set entries are - // properly cleared and rebuilt after aborting a page. Failing to do so can - // result in other objects being allocated in the free space where their - // payload looks like a valid new space pointer. - - // Disable concurrent sweeping to ensure memory is in an expected state, i.e., - // we can reach the state of a half aborted page. - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - - const int objects_per_page = 10; - const int object_size = GetObjectSize(objects_per_page); - - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - auto reset_oom = [](void* heap, size_t limit, size_t) -> size_t { - reinterpret_cast<Heap*>(heap)->set_force_oom(false); - return limit; - }; - heap->AddNearHeapLimitCallback(reset_oom, heap); - { - HandleScope scope1(isolate); - IndirectHandle<FixedArray> root_array = - isolate->factory()->NewFixedArray(10, AllocationType::kOld); - heap::SealCurrentObjects(heap); - - NormalPage* to_be_aborted_page = nullptr; - { - HandleScope temporary_scope(isolate); - // Fill another page with objects of size {object_size} (last one is - // properly adjusted). - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - DirectHandleVector<FixedArray> compaction_page_handles(isolate); - heap::CreatePadding( - heap, - static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), - AllocationType::kOld, &compaction_page_handles, object_size); - // Sanity check that we have enough space for linking up arrays. - CHECK_GE(compaction_page_handles.front()->length().value(), 2u); - to_be_aborted_page = - NormalPage::FromHeapObject(*compaction_page_handles.front()); - to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); - - for (size_t i = compaction_page_handles.size() - 1; i > 0; i--) { - compaction_page_handles[i]->set(0, *compaction_page_handles[i - 1]); - } - root_array->set(0, *compaction_page_handles.back()); - DirectHandle<FixedArray> new_space_array = - isolate->factory()->NewFixedArray(1, AllocationType::kYoung); - CHECK(HeapLayout::InYoungGeneration(*new_space_array)); - compaction_page_handles.front()->set(1, *new_space_array); - CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); - } - - { - // Add another page that is filled with {num_objects} objects of size - // {object_size}. - HandleScope scope3(isolate); - CHECK(heap->old_space()->TryExpand(heap->main_thread_local_heap(), - AllocationOrigin::kRuntime)); - const int num_objects = 2; - int used_memory = object_size * num_objects; - DirectHandleVector<FixedArray> page_to_fill_handles(isolate); - heap::CreatePadding(heap, used_memory, AllocationType::kOld, - &page_to_fill_handles, object_size); - NormalPage* page_to_fill = - NormalPage::FromHeapObject(*page_to_fill_handles.front()); - - // We need to invoke GC without stack, otherwise no compaction is - // performed. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - - heap->set_force_oom(true); - heap::InvokeMajorGC(heap); - heap->EnsureSweepingCompleted( - Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - - // The following check makes sure that we compacted "some" objects, while - // leaving others in place. - bool in_place = true; - IndirectHandle<FixedArray> current = root_array; - while (current->get(0) != ReadOnlyRoots(heap).undefined_value()) { - current = IndirectHandle<FixedArray>(Cast<FixedArray>(current->get(0)), - isolate); - CHECK(!HeapLayout::InYoungGeneration(*current)); - CHECK(IsFixedArray(*current)); - if (NormalPage::FromHeapObject(*current) != to_be_aborted_page) { - in_place = false; - } - bool on_aborted_page = - NormalPage::FromHeapObject(*current) == to_be_aborted_page; - bool on_fill_page = - NormalPage::FromHeapObject(*current) == page_to_fill; - CHECK((in_place && on_aborted_page) || (!in_place && on_fill_page)); - } - // Check that we at least migrated one object, as otherwise the test would - // not trigger. - CHECK(!in_place); - CheckInvariantsOfAbortedPage(to_be_aborted_page); - - // Allocate a new object in new space. - IndirectHandle<FixedArray> holder = - isolate->factory()->NewFixedArray(10, AllocationType::kYoung); - // Create a broken address that looks like a tagged pointer to a new space - // object. - Address broken_address = holder->address() + 2 * kTaggedSize + 1; - // Convert it to a vector to create a string from it. - base::Vector<const uint8_t> string_to_broken_address( - reinterpret_cast<const uint8_t*>(&broken_address), kTaggedSize); - - IndirectHandle<String> string; - do { - // We know that the interesting slot will be on the aborted page and - // hence we allocate until we get our string on the aborted page. - // We used slot 1 in the fixed size array which corresponds to the - // the first word in the string. Since the first object definitely - // migrated we can just allocate until we hit the aborted page. - string = isolate->factory() - ->NewStringFromOneByte(string_to_broken_address, - AllocationType::kOld) - .ToHandleChecked(); - } while (NormalPage::FromHeapObject(*string) != to_be_aborted_page); - - // If remembered set entries are not properly filtered/reset for aborted - // pages we have now a broken address at an object slot in old space and - // the following scavenge will crash. - heap::InvokeMinorGC(CcTest::heap()); - } - } - heap->RemoveNearHeapLimitCallback(reset_oom, 0u); -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-concurrent-marking.cc b/deps/v8/test/cctest/heap/test-concurrent-marking.cc deleted file mode 100644 index 9ebd02e5e9d9..000000000000 --- a/deps/v8/test/cctest/heap/test-concurrent-marking.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017 the V8 project 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 <stdlib.h> - -#include "src/heap/concurrent-marking.h" -#include "src/heap/heap.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8::internal::heap { - -TEST(ConcurrentMarkingMarkedBytes) { - if (!v8_flags.incremental_marking) return; - if (!i::v8_flags.concurrent_marking) return; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = CcTest::heap(); - HandleScope sc(isolate); - DirectHandle<FixedArray> root = isolate->factory()->NewFixedArray(1000000); - heap::InvokeMajorGC(heap); - if (!heap->incremental_marking()->IsStopped()) return; - - // Store array in Global such that it is part of the root set when - // starting incremental marking. - v8::Global<Value> global_root(CcTest::isolate(), - Utils::ToLocal(Cast<Object>(root))); - - heap::SimulateIncrementalMarking(heap, false); - // Ensure that objects are published to the global marking worklist such that - // the concurrent markers can pick it up. - heap->mark_compact_collector()->local_marking_worklists()->Publish(); - heap->concurrent_marking()->JoinJobForTesting(); - CHECK_GE(heap->concurrent_marking()->TotalMarkedBytes(), root->Size()); -} - -UNINITIALIZED_TEST(ConcurrentMarkingStoppedOnTeardown) { - if (!v8_flags.incremental_marking) return; - if (!i::v8_flags.concurrent_marking) return; - - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - - { - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - Factory* factory = i_isolate->factory(); - - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Context::New(isolate)->Enter(); - - for (int i = 0; i < 10000; i++) { - factory->NewJSWeakMap(); - } - - Heap* heap = i_isolate->heap(); - heap::SimulateIncrementalMarking(heap, false); - } - - isolate->Dispose(); -} - -} // namespace v8::internal::heap diff --git a/deps/v8/test/cctest/heap/test-heap.cc b/deps/v8/test/cctest/heap/test-heap.cc deleted file mode 100644 index 14c9ede39b93..000000000000 --- a/deps/v8/test/cctest/heap/test-heap.cc +++ /dev/null @@ -1,2784 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <stdlib.h> - -#include <utility> - -#include "include/v8-function.h" -#include "src/api/api-inl.h" -#include "src/base/strings.h" -#include "src/base/strong-alias.h" -#include "src/builtins/builtins-inl.h" -#include "src/codegen/assembler-inl.h" -#include "src/codegen/compilation-cache.h" -#include "src/codegen/compiler.h" -#include "src/codegen/macro-assembler-inl.h" -#include "src/codegen/script-details.h" -#include "src/common/globals.h" -#include "src/deoptimizer/deoptimizer.h" -#include "src/flags/flags.h" -#include "src/handles/global-handles-inl.h" -#include "src/heap/combined-heap.h" -#include "src/heap/factory.h" -#include "src/heap/gc-tracer.h" -#include "src/heap/heap-inl.h" -#include "src/heap/heap-layout-inl.h" -#include "src/heap/heap-verifier.h" -#include "src/heap/heap.h" -#include "src/heap/incremental-marking.h" -#include "src/heap/large-page-inl.h" -#include "src/heap/large-spaces.h" -#include "src/heap/local-heap-inl.h" -#include "src/heap/mark-compact-inl.h" -#include "src/heap/marking-barrier.h" -#include "src/heap/marking-state-inl.h" -#include "src/heap/memory-reducer.h" -#include "src/heap/mutable-page.h" -#include "src/heap/remembered-set-inl.h" -#include "src/heap/safepoint.h" -#include "src/numbers/hash-seed-inl.h" -#include "src/objects/allocation-site.h" -#include "src/objects/call-site-info-inl.h" -#include "src/objects/elements.h" -#include "src/objects/field-type.h" -#include "src/objects/heap-number-inl.h" -#include "src/objects/js-array-inl.h" -#include "src/objects/js-collection-inl.h" -#include "src/objects/managed-inl.h" -#include "src/objects/object-conversions-inl.h" -#include "src/objects/objects-inl.h" -#include "src/objects/objects.h" -#include "src/objects/slots.h" -#include "src/objects/transitions.h" -#include "src/regexp/regexp.h" -#include "src/snapshot/snapshot.h" -#include "src/tracing/tracing-category-observer.h" -#include "src/utils/ostreams.h" -#include "test/cctest/cctest.h" -#include "test/cctest/feedback-vector-helper.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" -#include "test/cctest/test-transitions.h" -#include "test/common/noop-bytecode-verifier.h" - -namespace v8 { -namespace internal { -namespace heap { - -// We only start allocation-site tracking with the second instantiation. -static const int kPretenureCreationCount = - PretenuringHandler::GetMinMementoCountForTesting() + 1; - - - - - - - -static void OptimizeEmptyFunction(const char* name) { - HandleScope scope(CcTest::i_isolate()); - base::EmbeddedVector<char, 256> source; - base::SNPrintF(source, - "function %s() { return 0; }" - "%%PrepareFunctionForOptimization(%s);" - "%s(); %s();" - "%%OptimizeFunctionOnNextCall(%s);" - "%s();", - name, name, name, name, name, name); - CompileRun(source.begin()); -} - -// Count the number of native contexts in the weak list of native contexts. -int CountNativeContexts() { - int count = 0; - Tagged<Object> object = CcTest::heap()->native_contexts_list(); - while (!IsUndefined(object)) { - count++; - object = Cast<Context>(object)->next_context_link(); - } - return count; -} - -TEST(TestInternalWeakLists) { - v8_flags.allow_natives_syntax = true; - - // Some flags turn Scavenge collections into Mark-sweep collections - // and hence are incompatible with this test case. - if (v8_flags.gc_global || v8_flags.stress_compaction || - v8_flags.stress_incremental_marking || v8_flags.single_generation || - v8_flags.stress_concurrent_allocation) { - return; - } - v8_flags.retain_maps_for_n_gc = 0; - - static const int kNumTestContexts = 10; - - ManualGCScope manual_gc_scope; - v8::Isolate* v8_isolate = CcTest::isolate(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = CcTest::heap(); - HandleScope scope(isolate); - v8::Global<v8::Context> ctx[kNumTestContexts]; - if (!isolate->use_optimizer()) return; - - CHECK_EQ(0, CountNativeContexts()); - - // Create a number of global contests which gets linked together. - for (int i = 0; i < kNumTestContexts; i++) { - // Create a handle scope so no contexts or function objects get stuck in the - // outer handle scope. - HandleScope new_scope(isolate); - - ctx[i].Reset(v8_isolate, v8::Context::New(v8_isolate)); - - // Collect garbage that might have been created by one of the - // installed extensions. - isolate->compilation_cache()->Clear(); - { - // In this test, we need to invoke GC without stack, otherwise some - // objects may not be reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - CHECK_EQ(i + 1, CountNativeContexts()); - - ctx[i].Get(v8_isolate)->Enter(); - - OptimizeEmptyFunction("f1"); - OptimizeEmptyFunction("f2"); - OptimizeEmptyFunction("f3"); - OptimizeEmptyFunction("f4"); - OptimizeEmptyFunction("f5"); - - // Remove function f1, and - CompileRun("f1=null"); - - // Scavenge treats these references as strong. - for (int j = 0; j < 10; j++) { - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMinorGC(heap); - } - - // Mark compact handles the weak references. - isolate->compilation_cache()->Clear(); - { - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - // Get rid of f3 and f5 in the same way. - CompileRun("f3=null"); - { - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - for (int j = 0; j < 10; j++) { - heap::InvokeMinorGC(heap); - } - heap::InvokeMajorGC(heap); - } - CompileRun("f5=null"); - { - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - for (int j = 0; j < 10; j++) { - heap::InvokeMinorGC(heap); - } - heap::InvokeMajorGC(heap); - } - ctx[i].Get(v8_isolate)->Exit(); - } - - // Force compilation cache cleanup. - heap->NotifyContextDisposed(true); - { - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - // Dispose the native contexts one by one. - for (int i = 0; i < kNumTestContexts; i++) { - ctx[i].Reset(); - - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - - // Scavenge treats these references as strong. - for (int j = 0; j < 10; j++) { - heap::InvokeMinorGC(heap); - CHECK_EQ(kNumTestContexts - i, CountNativeContexts()); - } - // Mark-compact handles the weak references. - heap::InvokeMajorGC(heap); - - CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts()); - } - - CHECK_EQ(0, CountNativeContexts()); -} - -static int forced_gc_counter = 0; - -void MockUseCounterCallback(v8::Isolate* isolate, - v8::Isolate::UseCounterFeature feature) { - isolate->GetCurrentContext(); - if (feature == v8::Isolate::kForcedGC) { - forced_gc_counter++; - } -} - -TEST(CountForcedGC) { - v8_flags.expose_gc = true; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::HandleScope scope(CcTest::isolate()); - - isolate->SetUseCounterCallback(MockUseCounterCallback); - - forced_gc_counter = 0; - const char* source = "gc();"; - CompileRun(source); - CHECK_GT(forced_gc_counter, 0); -} - -#ifdef OBJECT_PRINT -TEST(PrintSharedFunctionInfo) { - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext(); - const char* source = - "f = function() { return 987654321; }\n" - "g = function() { return 123456789; }\n"; - CompileRun(source); - i::DirectHandle<JSFunction> g = i::Cast<JSFunction>( - v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( - CcTest::global()->Get(ctx, v8_str("g")).ToLocalChecked()))); - - StdoutStream os; - Print(g->shared(), os); - os << std::endl; -} -#endif // OBJECT_PRINT - -TEST(IncrementalMarkingPreservesMonomorphicCallIC) { - if (!v8_flags.use_ic) return; - if (!v8_flags.incremental_marking) return; - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> fun1, fun2; - v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext(); - { - CompileRun("function fun() {};"); - fun1 = CcTest::global()->Get(ctx, v8_str("fun")).ToLocalChecked(); - } - - { - CompileRun("function fun() {};"); - fun2 = CcTest::global()->Get(ctx, v8_str("fun")).ToLocalChecked(); - } - - // Prepare function f that contains type feedback for the two closures. - CHECK(CcTest::global()->Set(ctx, v8_str("fun1"), fun1).FromJust()); - CHECK(CcTest::global()->Set(ctx, v8_str("fun2"), fun2).FromJust()); - CompileRun( - "function f(a, b) { a(); b(); } %EnsureFeedbackVectorForFunction(f); " - "f(fun1, fun2);"); - - DirectHandle<JSFunction> f = Cast<JSFunction>( - v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( - CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked()))); - - Handle<FeedbackVector> feedback_vector(f->feedback_vector(), - CcTest::i_isolate()); - FeedbackVectorHelper feedback_helper(feedback_vector); - - int expected_slots = 2; - CHECK_EQ(expected_slots, feedback_helper.slot_count()); - int slot1 = 0; - int slot2 = 1; - CHECK(feedback_vector->Get(feedback_helper.slot(slot1)).IsWeak()); - CHECK(feedback_vector->Get(feedback_helper.slot(slot2)).IsWeak()); - - heap::SimulateIncrementalMarking(CcTest::heap()); - heap::InvokeMajorGC(CcTest::heap()); - - CHECK(feedback_vector->Get(feedback_helper.slot(slot1)).IsWeak()); - CHECK(feedback_vector->Get(feedback_helper.slot(slot2)).IsWeak()); -} - -static void CheckVectorIC(DirectHandle<JSFunction> f, int slot_index, - InlineCacheState desired_state) { - Handle<FeedbackVector> vector = - Handle<FeedbackVector>(f->feedback_vector(), CcTest::i_isolate()); - FeedbackVectorHelper helper(vector); - FeedbackSlot slot = helper.slot(slot_index); - FeedbackNexus nexus(CcTest::i_isolate(), vector, slot); - CHECK(nexus.ic_state() == desired_state); -} - -TEST(IncrementalMarkingPreservesMonomorphicIC) { - if (!v8_flags.use_ic) return; - if (!v8_flags.incremental_marking) return; - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext(); - // Prepare function f that contains a monomorphic IC for object - // originating from the same native context. - CompileRun( - "function fun() { this.x = 1; }; var obj = new fun();" - "%EnsureFeedbackVectorForFunction(f);" - "function f(o) { return o.x; } f(obj); f(obj);"); - DirectHandle<JSFunction> f = Cast<JSFunction>( - v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( - CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked()))); - - CheckVectorIC(f, 0, InlineCacheState::MONOMORPHIC); - - heap::SimulateIncrementalMarking(CcTest::heap()); - heap::InvokeMajorGC(CcTest::heap()); - - CheckVectorIC(f, 0, InlineCacheState::MONOMORPHIC); -} - -TEST(IncrementalMarkingPreservesPolymorphicIC) { - if (!v8_flags.use_ic) return; - if (!v8_flags.incremental_marking) return; - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> obj1, obj2; - v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext(); - - { - LocalContext env; - CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); - obj1 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); - } - - { - LocalContext env; - CompileRun("function fun() { this.x = 2; }; var obj = new fun();"); - obj2 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); - } - - // Prepare function f that contains a polymorphic IC for objects - // originating from two different native contexts. - CHECK(CcTest::global()->Set(ctx, v8_str("obj1"), obj1).FromJust()); - CHECK(CcTest::global()->Set(ctx, v8_str("obj2"), obj2).FromJust()); - CompileRun( - "function f(o) { return o.x; }; " - "%EnsureFeedbackVectorForFunction(f);" - "f(obj1); f(obj1); f(obj2);"); - DirectHandle<JSFunction> f = Cast<JSFunction>( - v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( - CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked()))); - - CheckVectorIC(f, 0, InlineCacheState::POLYMORPHIC); - - // Fire context dispose notification. - heap::SimulateIncrementalMarking(CcTest::heap()); - heap::InvokeMajorGC(CcTest::heap()); - - CheckVectorIC(f, 0, InlineCacheState::POLYMORPHIC); -} - -TEST(ContextDisposeDoesntClearPolymorphicIC) { - if (!v8_flags.use_ic) return; - if (!v8_flags.incremental_marking) return; - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> obj1, obj2; - v8::Local<v8::Context> ctx = CcTest::isolate()->GetCurrentContext(); - - { - LocalContext env; - CompileRun("function fun() { this.x = 1; }; var obj = new fun();"); - obj1 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); - } - - { - LocalContext env; - CompileRun("function fun() { this.x = 2; }; var obj = new fun();"); - obj2 = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked(); - } - - // Prepare function f that contains a polymorphic IC for objects - // originating from two different native contexts. - CHECK(CcTest::global()->Set(ctx, v8_str("obj1"), obj1).FromJust()); - CHECK(CcTest::global()->Set(ctx, v8_str("obj2"), obj2).FromJust()); - CompileRun( - "function f(o) { return o.x; }; " - "%EnsureFeedbackVectorForFunction(f);" - "f(obj1); f(obj1); f(obj2);"); - DirectHandle<JSFunction> f = Cast<JSFunction>( - v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( - CcTest::global()->Get(ctx, v8_str("f")).ToLocalChecked()))); - - CheckVectorIC(f, 0, InlineCacheState::POLYMORPHIC); - - // Fire context dispose notification. - CcTest::isolate()->ContextDisposedNotification( - v8::ContextDependants::kSomeDependants); - heap::SimulateIncrementalMarking(CcTest::heap()); - heap::InvokeMajorGC(CcTest::heap()); - - CheckVectorIC(f, 0, InlineCacheState::POLYMORPHIC); -} - -class SourceResource : public v8::String::ExternalOneByteStringResource { - public: - explicit SourceResource(const char* data) - : data_(data), length_(strlen(data)) { } - - void Dispose() override { - i::DeleteArray(data_); - data_ = nullptr; - } - - const char* data() const override { return data_; } - - size_t length() const override { return length_; } - - bool IsDisposed() { return data_ == nullptr; } - - private: - const char* data_; - size_t length_; -}; - -void ReleaseStackTraceDataTest(v8::Isolate* isolate, const char* source, - const char* accessor) { - // Test that the data retained by the Error.stack accessor is released - // after the first time the accessor is fired. We use external string - // to check whether the data is being released since the external string - // resource's callback is fired when the external string is GC'ed. - i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - i::Heap* heap = i_isolate->heap(); - v8::HandleScope scope(isolate); - - SourceResource* resource = new SourceResource(i::StrDup(source)); - { - v8::HandleScope new_scope(isolate); - v8::Local<v8::Context> ctx = isolate->GetCurrentContext(); - v8::Local<v8::String> source_string = - v8::String::NewExternalOneByte(isolate, resource).ToLocalChecked(); - heap::InvokeMemoryReducingMajorGCs(heap); - v8::Script::Compile(ctx, source_string) - .ToLocalChecked() - ->Run(ctx) - .ToLocalChecked(); - CHECK(!resource->IsDisposed()); - } - CHECK(!resource->IsDisposed()); - - CompileRun(accessor); - - { - // We need to invoke GC without stack, otherwise some objects may not be - // reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMemoryReducingMajorGCs(heap); - } - - // External source has been released. - CHECK(resource->IsDisposed()); - delete resource; -} - -UNINITIALIZED_TEST(ReleaseStackTraceData) { -#ifndef V8_LITE_MODE - // ICs retain objects. - v8_flags.use_ic = false; -#endif // V8_LITE_MODE - v8_flags.concurrent_recompilation = false; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Context::New(isolate)->Enter(); - static const char* source1 = - "var error = null; " - /* Normal Error */ - "try { " - " throw new Error(); " - "} catch (e) { " - " error = e; " - "} "; - static const char* source2 = - "var error = null; " - /* Stack overflow */ - "try { " - " (function f() { f(); })(); " - "} catch (e) { " - " error = e; " - "} "; - static const char* getter = "error.stack"; - static const char* setter = "error.stack = 0"; - - ReleaseStackTraceDataTest(isolate, source1, setter); - ReleaseStackTraceDataTest(isolate, source2, setter); - ReleaseStackTraceDataTest(isolate, source1, getter); - ReleaseStackTraceDataTest(isolate, source2, getter); - } - isolate->Dispose(); -} - - -static int AllocationSitesCount(Heap* heap) { - int count = 0; - for (Tagged<Object> site = heap->allocation_sites_list(); - IsAllocationSite(site);) { - Tagged<AllocationSiteWithWeakNext> cur = - Cast<AllocationSiteWithWeakNext>(site); - CHECK(cur->HasWeakNext()); - site = cur->weak_next(); - count++; - } - return count; -} - -static int SlimAllocationSiteCount(Heap* heap) { - int count = 0; - for (Tagged<Object> weak_list = heap->allocation_sites_list(); - IsAllocationSite(weak_list);) { - Tagged<AllocationSiteWithWeakNext> weak_cur = - Cast<AllocationSiteWithWeakNext>(weak_list); - for (Tagged<Object> site = weak_cur->nested_site(); - IsAllocationSite(site);) { - Tagged<AllocationSite> cur = Cast<AllocationSite>(site); - CHECK(!cur->HasWeakNext()); - site = cur->nested_site(); - count++; - } - weak_list = weak_cur->weak_next(); - } - return count; -} - -void CheckNumberOfAllocations(Heap* heap, const char* source, - int expected_full_alloc, - int expected_slim_alloc) { - int prev_fat_alloc_count = AllocationSitesCount(heap); - int prev_slim_alloc_count = SlimAllocationSiteCount(heap); - - CompileRun(source); - - int fat_alloc_sites = AllocationSitesCount(heap) - prev_fat_alloc_count; - int slim_alloc_sites = SlimAllocationSiteCount(heap) - prev_slim_alloc_count; - - CHECK_EQ(expected_full_alloc, fat_alloc_sites); - CHECK_EQ(expected_slim_alloc, slim_alloc_sites); -} - -TEST(AllocationSiteCreation) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - HandleScope scope(isolate); - i::v8_flags.allow_natives_syntax = true; - - // Array literals. - CheckNumberOfAllocations(heap, - "function f1() {" - " return []; " - "};" - "%EnsureFeedbackVectorForFunction(f1); f1();", - 1, 0); - CheckNumberOfAllocations(heap, - "function f2() {" - " return [1, 2];" - "};" - "%EnsureFeedbackVectorForFunction(f2); f2();", - 1, 0); - CheckNumberOfAllocations(heap, - "function f3() {" - " return [[1], [2]];" - "};" - "%EnsureFeedbackVectorForFunction(f3); f3();", - 1, 2); - CheckNumberOfAllocations(heap, - "function f4() { " - "return [0, [1, 1.1, 1.2, " - "], 1.5, [2.1, 2.2], 3];" - "};" - "%EnsureFeedbackVectorForFunction(f4); f4();", - 1, 2); - - // Object literals have lazy AllocationSites - CheckNumberOfAllocations(heap, - "function f5() {" - " return {};" - "};" - "%EnsureFeedbackVectorForFunction(f5); f5();", - 0, 0); - - // No AllocationSites are created for the empty object literal. - for (int i = 0; i < 5; i++) { - CheckNumberOfAllocations(heap, "f5(); ", 0, 0); - } - - CheckNumberOfAllocations(heap, - "function f6() {" - " return {a:1};" - "};" - "%EnsureFeedbackVectorForFunction(f6); f6();", - 0, 0); - - CheckNumberOfAllocations(heap, "f6(); ", 1, 0); - - CheckNumberOfAllocations(heap, - "function f7() {" - " return {a:1, b:2};" - "};" - "%EnsureFeedbackVectorForFunction(f7); f7(); ", - 0, 0); - CheckNumberOfAllocations(heap, "f7(); ", 1, 0); - - // No Allocation sites are created for object subliterals - CheckNumberOfAllocations(heap, - "function f8() {" - "return {a:{}, b:{ a:2, c:{ d:{f:{}}} } }; " - "};" - "%EnsureFeedbackVectorForFunction(f8); f8();", - 0, 0); - CheckNumberOfAllocations(heap, "f8(); ", 1, 0); - - // We currently eagerly create allocation sites if there are sub-arrays. - // Allocation sites are created only for array subliterals - CheckNumberOfAllocations(heap, - "function f9() {" - "return {a:[1, 2, 3], b:{ a:2, c:{ d:{f:[]} } }}; " - "};" - "%EnsureFeedbackVectorForFunction(f9); f9(); ", - 1, 2); - - // No new AllocationSites created on the second invocation. - CheckNumberOfAllocations(heap, "f9(); ", 0, 0); -} - -TEST(CellsInOptimizedCodeAreWeak) { - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::internal::Heap* heap = CcTest::heap(); - - if (!isolate->use_optimizer()) return; - HandleScope outer_scope(heap->isolate()); - IndirectHandle<Code> code; - { - LocalContext context; - HandleScope scope(heap->isolate()); - - CompileRun( - "bar = (function() {" - " function bar() {" - " return foo(1);" - " };" - " %PrepareFunctionForOptimization(bar);" - " var foo = function(x) { with (x) { return 1 + x; } };" - " %NeverOptimizeFunction(foo);" - " bar(foo);" - " bar(foo);" - " bar(foo);" - " %OptimizeFunctionOnNextCall(bar);" - " bar(foo);" - " return bar;})();"); - - DirectHandle<JSFunction> bar = Cast<JSFunction>(v8::Utils::OpenDirectHandle( - *v8::Local<v8::Function>::Cast(CcTest::global() - ->Get(context.local(), v8_str("bar")) - .ToLocalChecked()))); - code = handle(bar->code(isolate), isolate); - code = scope.CloseAndEscape(code); - } - - // Now make sure that a gc should get rid of the function - for (int i = 0; i < 4; i++) { - // We need to invoke GC without stack, otherwise some objects may not be - // reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - CHECK(code->marked_for_deoptimization()); - CHECK(code->embedded_objects_cleared()); -} - -TEST(ObjectsInOptimizedCodeAreWeak) { - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::internal::Heap* heap = CcTest::heap(); - - if (!isolate->use_optimizer()) return; - HandleScope outer_scope(heap->isolate()); - IndirectHandle<Code> code; - { - LocalContext context; - HandleScope scope(heap->isolate()); - - CompileRun( - "function bar() {" - " return foo(1);" - "};" - "%PrepareFunctionForOptimization(bar);" - "function foo(x) { with (x) { return 1 + x; } };" - "%NeverOptimizeFunction(foo);" - "bar();" - "bar();" - "bar();" - "%OptimizeFunctionOnNextCall(bar);" - "bar();"); - - DirectHandle<JSFunction> bar = Cast<JSFunction>(v8::Utils::OpenDirectHandle( - *v8::Local<v8::Function>::Cast(CcTest::global() - ->Get(context.local(), v8_str("bar")) - .ToLocalChecked()))); - code = handle(bar->code(isolate), isolate); - code = scope.CloseAndEscape(code); - } - - // Now make sure that a gc should get rid of the function - for (int i = 0; i < 4; i++) { - // We need to invoke GC without stack, otherwise some objects may not be - // reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - CHECK(code->marked_for_deoptimization()); - CHECK(code->embedded_objects_cleared()); -} - -TEST(NewSpaceObjectsInOptimizedCode) { - if (v8_flags.single_generation) return; - v8_flags.allow_natives_syntax = true; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::internal::Heap* heap = CcTest::heap(); - - if (!isolate->use_optimizer()) return; - HandleScope outer_scope(isolate); - IndirectHandle<Code> code; - { - LocalContext context; - HandleScope scope(isolate); - - CompileRun( - "var foo;" - "var bar;" - "(function() {" - " function foo_func(x) { with (x) { return 1 + x; } };" - " %NeverOptimizeFunction(foo_func);" - " function bar_func() {" - " return foo(1);" - " };" - " %PrepareFunctionForOptimization(bar_func);" - " bar = bar_func;" - " foo = foo_func;" - " bar_func();" - " bar_func();" - " bar_func();" - " %OptimizeFunctionOnNextCall(bar_func);" - " bar_func();" - "})();"); - - DirectHandle<JSFunction> bar = Cast<JSFunction>(v8::Utils::OpenDirectHandle( - *v8::Local<v8::Function>::Cast(CcTest::global() - ->Get(context.local(), v8_str("bar")) - .ToLocalChecked()))); - - DirectHandle<JSFunction> foo = Cast<JSFunction>(v8::Utils::OpenDirectHandle( - *v8::Local<v8::Function>::Cast(CcTest::global() - ->Get(context.local(), v8_str("foo")) - .ToLocalChecked()))); - - CHECK(HeapLayout::InYoungGeneration(*foo)); - heap::InvokeMajorGC(heap); - CHECK(!HeapLayout::InYoungGeneration(*foo)); -#ifdef VERIFY_HEAP - HeapVerifier::VerifyHeap(CcTest::heap()); -#endif - CHECK(!bar->code(isolate)->marked_for_deoptimization()); - code = handle(bar->code(isolate), isolate); - code = scope.CloseAndEscape(code); - } - - // Now make sure that a gc should get rid of the function - for (int i = 0; i < 4; i++) { - // We need to invoke GC without stack, otherwise some objects may not be - // reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - CHECK(code->marked_for_deoptimization()); - CHECK(code->embedded_objects_cleared()); -} - -TEST(ObjectsInEagerlyDeoptimizedCodeAreWeak) { - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::internal::Heap* heap = CcTest::heap(); - - if (!isolate->use_optimizer()) return; - HandleScope outer_scope(heap->isolate()); - IndirectHandle<Code> code; - { - LocalContext context; - HandleScope scope(heap->isolate()); - - CompileRun( - "function bar() {" - " return foo(1);" - "};" - "function foo(x) { with (x) { return 1 + x; } };" - "%NeverOptimizeFunction(foo);" - "%PrepareFunctionForOptimization(bar);" - "bar();" - "bar();" - "bar();" - "%OptimizeFunctionOnNextCall(bar);" - "bar();"); - - DirectHandle<JSFunction> bar = Cast<JSFunction>(v8::Utils::OpenDirectHandle( - *v8::Local<v8::Function>::Cast(CcTest::global() - ->Get(context.local(), v8_str("bar")) - .ToLocalChecked()))); - code = handle(bar->code(isolate), isolate); - CompileRun("%DeoptimizeFunction(bar);"); - CHECK(code->marked_for_deoptimization()); - CHECK(!(*code).SafeEquals(bar->code(isolate))); - code = scope.CloseAndEscape(code); - } - - // Now make sure that a gc should get rid of the function - for (int i = 0; i < 4; i++) { - // We need to invoke GC without stack, otherwise some objects may not be - // reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - CHECK(code->marked_for_deoptimization()); - CHECK(code->embedded_objects_cleared()); -} - -static DirectHandle<InstructionStream> DummyOptimizedCode(Isolate* isolate) { - uint8_t buffer[i::Assembler::kDefaultBufferSize]; - MacroAssembler masm(isolate, v8::internal::CodeObjectRequired{true}, - ExternalAssemblerBuffer(buffer, sizeof(buffer))); - CodeDesc desc; -#if V8_TARGET_ARCH_ARM64 - UseScratchRegisterScope temps(&masm); - Register tmp = temps.AcquireX(); - masm.Mov(tmp, Operand(isolate->factory()->undefined_value())); - masm.Push(tmp, tmp); -#else - masm.Push(isolate->factory()->undefined_value()); - masm.Push(isolate->factory()->undefined_value()); -#endif - masm.Drop(2); - masm.GetCode(isolate, &desc); - DirectHandle<InstructionStream> code( - Factory::CodeBuilder(isolate, desc, CodeKind::TURBOFAN_JS) - .set_self_reference(masm.CodeObject()) - .set_empty_source_position_table() - .set_deoptimization_data(DeoptimizationData::Empty(isolate)) - .Build() - ->instruction_stream(), - isolate); - CHECK(IsInstructionStream(*code)); - return code; -} - - -DirectHandle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) { - DirectHandle<String> str = isolate->factory()->InternalizeUtf8String(name); - DirectHandle<Object> obj = - Object::GetProperty(isolate, isolate->global_object(), str) - .ToHandleChecked(); - return Cast<JSFunction>(obj); -} - -void CheckIC(DirectHandle<JSFunction> function, int slot_index, - InlineCacheState state) { - Tagged<FeedbackVector> vector = function->feedback_vector(); - FeedbackSlot slot(slot_index); - FeedbackNexus nexus(CcTest::i_isolate(), vector, slot); - CHECK_EQ(nexus.ic_state(), state); -} - -TEST(MonomorphicStaysMonomorphicAfterGC) { - if (!v8_flags.use_ic) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::HandleScope scope(CcTest::isolate()); - v8_flags.allow_natives_syntax = true; - CompileRun( - "function loadIC(obj) {" - " return obj.name;" - "}" - "%EnsureFeedbackVectorForFunction(loadIC);" - "function testIC() {" - " var proto = {'name' : 'weak'};" - " var obj = Object.create(proto);" - " loadIC(obj);" - " loadIC(obj);" - " loadIC(obj);" - " return proto;" - "};"); - DirectHandle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC"); - { - v8::HandleScope new_scope(CcTest::isolate()); - CompileRun("(testIC())"); - } - heap::InvokeMajorGC(CcTest::heap()); - CheckIC(loadIC, 0, InlineCacheState::MONOMORPHIC); - { - v8::HandleScope new_scope(CcTest::isolate()); - CompileRun("(testIC())"); - } - CheckIC(loadIC, 0, InlineCacheState::MONOMORPHIC); -} - -TEST(PolymorphicStaysPolymorphicAfterGC) { - if (!v8_flags.use_ic) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::HandleScope scope(CcTest::isolate()); - v8_flags.allow_natives_syntax = true; - CompileRun( - "function loadIC(obj) {" - " return obj.name;" - "}" - "%EnsureFeedbackVectorForFunction(loadIC);" - "function testIC() {" - " var proto = {'name' : 'weak'};" - " var obj = Object.create(proto);" - " loadIC(obj);" - " loadIC(obj);" - " loadIC(obj);" - " var poly = Object.create(proto);" - " poly.x = true;" - " loadIC(poly);" - " return proto;" - "};"); - DirectHandle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC"); - { - v8::HandleScope new_scope(CcTest::isolate()); - CompileRun("(testIC())"); - } - heap::InvokeMajorGC(CcTest::heap()); - CheckIC(loadIC, 0, InlineCacheState::POLYMORPHIC); - { - v8::HandleScope new_scope(CcTest::isolate()); - CompileRun("(testIC())"); - } - CheckIC(loadIC, 0, InlineCacheState::POLYMORPHIC); -} - -#ifdef DEBUG -TEST(AddInstructionChangesNewSpacePromotion) { - v8_flags.allow_natives_syntax = true; - v8_flags.expose_gc = true; - v8_flags.stress_compaction = true; - FlagList::EnforceFlagImplications(); - HeapAllocator::SetAllocationGcInterval(1000); - CcTest::InitializeVM(); - if (!v8_flags.allocation_site_pretenuring) return; - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - LocalContext env; - CompileRun( - "function add(a, b) {" - " return a + b;" - "}" - "add(1, 2);" - "add(\"a\", \"b\");" - "var oldSpaceObject;" - "gc();" - "function crash(x) {" - " var object = {a: null, b: null};" - " var result = add(1.5, x | 0);" - " object.a = result;" - " oldSpaceObject = object;" - " return object;" - "}" - "%PrepareFunctionForOptimization(crash);" - "crash(1);" - "crash(1);" - "%OptimizeFunctionOnNextCall(crash);" - "crash(1);"); - - v8::Local<v8::Object> global = CcTest::global(); - v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( - global->Get(env.local(), v8_str("crash")).ToLocalChecked()); - v8::Local<v8::Value> info1[] = {v8_num(1)}; - heap->DisableInlineAllocation(); - heap->set_allocation_timeout(1); - g->Call(env.local(), global, 1, info1).ToLocalChecked(); - heap::InvokeMajorGC(heap); -} - -void OnFatalErrorExpectOOM(const char* location, const char* message) { - // Exit with 0 if the location matches our expectation. - exit(strcmp(location, "CALL_AND_RETRY_LAST")); -} - -TEST(CEntryStubOOM) { - v8_flags.allow_natives_syntax = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - CcTest::isolate()->SetFatalErrorHandler(OnFatalErrorExpectOOM); - - v8::Local<v8::Value> result = CompileRun( - "%SetAllocationTimeout(1, 1);" - "var a = [];" - "a.__proto__ = [];" - "a.unshift(1)"); - - CHECK(result->IsNumber()); -} - -#endif // DEBUG - -static void InterruptCallback357137(v8::Isolate* isolate, void* data) { } - -static void RequestInterrupt(const v8::FunctionCallbackInfo<v8::Value>& info) { - CHECK(i::ValidateCallbackInfo(info)); - CcTest::isolate()->RequestInterrupt(&InterruptCallback357137, nullptr); -} - -HEAP_TEST(Regress538257) { - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - v8::Isolate::CreateParams create_params; - // Set heap limits. - create_params.constraints.set_max_young_generation_size_in_bytes(3 * MB); -#ifdef DEBUG - create_params.constraints.set_max_old_generation_size_in_bytes(20 * MB); -#else - create_params.constraints.set_max_old_generation_size_in_bytes(6 * MB); -#endif - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - isolate->Enter(); - { - i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - HandleScope handle_scope(i_isolate); - PagedSpace* old_space = heap->old_space(); - const int kMaxObjects = 10000; - const int kFixedArrayLen = 512; - Handle<FixedArray> objects[kMaxObjects]; - for (int i = 0; (i < kMaxObjects) && - heap->CanExpandOldGeneration(old_space->AreaSize()); - i++) { - objects[i] = i_isolate->factory()->NewFixedArray(kFixedArrayLen, - AllocationType::kOld); - heap::ForceEvacuationCandidate(NormalPage::FromHeapObject(*objects[i])); - } - heap::SimulateFullSpace(old_space); - heap::InvokeMajorGC(heap); - // If we get this far, we've successfully aborted compaction. Any further - // allocations might trigger OOM. - } - isolate->Exit(); - isolate->Dispose(); -} - -TEST(Regress357137) { - CcTest::InitializeVM(); - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope hscope(isolate); - v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); - global->Set(isolate, "interrupt", - v8::FunctionTemplate::New(isolate, RequestInterrupt)); - v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global); - CHECK(!context.IsEmpty()); - v8::Context::Scope cscope(context); - - v8::Local<v8::Value> result = CompileRun( - "var locals = '';" - "for (var i = 0; i < 512; i++) locals += 'var v' + i + '= 42;';" - "eval('function f() {' + locals + 'return function() { return v0; }; }');" - "interrupt();" // This triggers a fake stack overflow in f. - "f()()"); - CHECK_EQ(42.0, result->ToNumber(context).ToLocalChecked()->Value()); -} - -TEST(Regress507979) { - const int kFixedArrayLen = 10; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - HandleScope handle_scope(isolate); - - DirectHandle<FixedArray> o1 = - isolate->factory()->NewFixedArray(kFixedArrayLen); - DirectHandle<FixedArray> o2 = - isolate->factory()->NewFixedArray(kFixedArrayLen); - CHECK(InCorrectGeneration(*o1)); - CHECK(InCorrectGeneration(*o2)); - - HeapObjectIterator it(isolate->heap(), - i::HeapObjectIterator::kFilterUnreachable); - - // Replace parts of an object placed before a live object with a filler. This - // way the filler object shares the mark bits with the following live object. - o1->RightTrim(isolate, kFixedArrayLen - 1); - - for (Tagged<HeapObject> obj = it.Next(); !obj.is_null(); obj = it.Next()) { - // Let's not optimize the loop away. - CHECK_NE(obj.address(), kNullAddress); - } -} - -TEST(Regress388880) { - if (!v8_flags.incremental_marking) return; - v8_flags.stress_incremental_marking = false; - v8_flags.expose_gc = true; - v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - - DirectHandle<Map> map1 = Map::Create(isolate, 1); - Handle<String> name = factory->NewStringFromStaticChars("foo"); - name = factory->InternalizeString(name); - DirectHandle<Map> map2 = - Map::CopyWithField(isolate, map1, name, FieldType::Any(isolate), NONE, - PropertyConstness::kMutable, Representation::Tagged(), - OMIT_TRANSITION) - .ToHandleChecked(); - - size_t desired_offset = NormalPage::kPageSize - map1->instance_size(); - - // Allocate padding objects in old pointer space so, that object allocated - // afterwards would end at the end of the page. - heap::SimulateFullSpace(heap->old_space()); - size_t padding_size = - desired_offset - MemoryChunkLayout::ObjectStartOffsetInDataPage(); - heap::CreatePadding(heap, static_cast<int>(padding_size), - AllocationType::kOld); - - DirectHandle<JSObject> o = - factory->NewJSObjectFromMap(map1, AllocationType::kOld); - o->set_raw_properties_or_hash(*factory->empty_fixed_array()); - - // Ensure that the object allocated where we need it. - NormalPage* page = NormalPage::FromHeapObject(*o); - CHECK_EQ(desired_offset, page->Offset(o->address())); - - // Now we have an object right at the end of the page. - - // Enable incremental marking to trigger actions in Heap::AdjustLiveBytes() - // that would cause crash. - IncrementalMarking* marking = CcTest::heap()->incremental_marking(); - marking->Stop(); - CcTest::heap()->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - CHECK(marking->IsMarking()); - - // Now everything is set up for crashing in JSObject::MigrateFastToFast() - // when it calls heap->AdjustLiveBytes(...). - JSObject::MigrateToMap(isolate, o, map2); -} - -TEST(Regress3631) { - if (!v8_flags.incremental_marking) return; - v8_flags.expose_gc = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - IncrementalMarking* marking = CcTest::heap()->incremental_marking(); - v8::Local<v8::Value> result = CompileRun( - "var weak_map = new WeakMap();" - "var future_keys = [];" - "for (var i = 0; i < 50; i++) {" - " var key = {'k' : i + 0.1};" - " weak_map.set(key, 1);" - " future_keys.push({'x' : i + 0.2});" - "}" - "weak_map"); - if (marking->IsStopped()) { - CcTest::heap()->StartIncrementalMarking( - i::GCFlag::kNoFlags, i::GarbageCollectionReason::kTesting); - } - // Incrementally mark the backing store. - DirectHandle<JSReceiver> obj = - v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(result)); - DirectHandle<JSWeakCollection> weak_map(Cast<JSWeakCollection>(*obj), - isolate); - SimulateIncrementalMarking(heap); - // Stash the backing store in a handle. - DirectHandle<Object> save(weak_map->table(), isolate); - // The following line will update the backing store. - CompileRun( - "for (var i = 0; i < 50; i++) {" - " weak_map.set(future_keys[i], i);" - "}"); - heap::InvokeMajorGC(heap); -} - -TEST(Regress442710) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - - HandleScope sc(isolate); - DirectHandle<JSGlobalObject> global( - CcTest::i_isolate()->context()->global_object(), isolate); - DirectHandle<JSArray> array = factory->NewJSArray(2); - - DirectHandle<String> name = factory->InternalizeUtf8String("testArray"); - Object::SetProperty(isolate, global, name, array).Check(); - CompileRun("testArray[0] = 1; testArray[1] = 2; testArray.shift();"); - heap::InvokeMajorGC(CcTest::heap()); -} - -HEAP_TEST(NumberStringCacheSize) { - // Test that the number-string cache has not been resized in the snapshot. - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - if (!isolate->snapshot_available()) return; - Heap* heap = isolate->heap(); - CHECK_EQ(SmiStringCache::kInitialSize, heap->smi_string_cache()->capacity()); - CHECK_EQ(DoubleStringCache::kInitialSize, - heap->double_string_cache()->capacity()); -} - -TEST(Regress3877) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope scope(isolate); - CompileRun("function cls() { this.x = 10; }"); - IndirectHandle<WeakFixedArray> weak_prototype_holder = - factory->NewWeakFixedArray(1); - { - HandleScope inner_scope(isolate); - v8::Local<v8::Value> result = CompileRun("cls.prototype"); - DirectHandle<JSReceiver> proto = - v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(result)); - weak_prototype_holder->set(0, MakeWeak(*proto)); - } - CHECK(!weak_prototype_holder->get(0).IsCleared()); - CompileRun( - "var a = { };" - "a.x = new cls();" - "cls.prototype = null;"); - for (int i = 0; i < 4; i++) { - heap::InvokeMajorGC(heap); - } - // The map of a.x keeps prototype alive - CHECK(!weak_prototype_holder->get(0).IsCleared()); - // Detach the map (by promoting it to a prototype). - CompileRun("var b = {}; b.__proto__ = a.x"); - // Change the map of a.x and make the previous map garbage collectable. - CompileRun("a.x.__proto__ = {};"); - - for (int i = 0; i < 4; i++) { - // We need to invoke GC without stack, otherwise some objects may not be - // reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - CHECK(weak_prototype_holder->get(0).IsCleared()); -} - -Handle<WeakFixedArray> AddRetainedMap(Isolate* isolate, - DirectHandle<NativeContext> context) { - HandleScope inner_scope(isolate); - DirectHandle<Map> map = Map::Create(isolate, 1); - v8::Local<v8::Value> result = - CompileRun("(function () { return {x : 10}; })();"); - DirectHandle<JSReceiver> proto = - v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(result)); - Map::SetPrototype(isolate, map, proto); - GlobalHandleVector<Map> maps(isolate->heap()); - maps.Push(*map); - isolate->heap()->AddRetainedMaps(context, std::move(maps)); - Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(1); - array->set(0, MakeWeak(*map)); - return inner_scope.CloseAndEscape(array); -} - -void CheckMapRetainingFor(int n) { - v8_flags.retain_maps_for_n_gc = n; - v8::Isolate* isolate = CcTest::isolate(); - Isolate* i_isolate = CcTest::i_isolate(); - Heap* heap = i_isolate->heap(); - - IndirectHandle<NativeContext> native_context; - // This global is used to visit the object's constructor alive when starting - // incremental marking. The native context keeps the constructor alive. The - // constructor needs to be alive to retain the map. - v8::Global<v8::Context> global_ctxt; - - { - v8::Local<v8::Context> ctx = v8::Context::New(isolate); - IndirectHandle<Context> context = Utils::OpenIndirectHandle(*ctx); - CHECK(IsNativeContext(*context)); - native_context = Cast<NativeContext>(context); - global_ctxt.Reset(isolate, ctx); - ctx->Enter(); - } - - IndirectHandle<WeakFixedArray> array_with_map = - AddRetainedMap(i_isolate, native_context); - CHECK(array_with_map->get(0).IsWeak()); - for (int i = 0; i < n; i++) { - heap::SimulateIncrementalMarking(heap); - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - CHECK(array_with_map->get(0).IsWeak()); - { - heap::SimulateIncrementalMarking(heap); - // In this test, we need to invoke GC without stack, otherwise some objects - // may not be reclaimed because of conservative stack scanning. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - CHECK(array_with_map->get(0).IsCleared()); - - global_ctxt.Get(isolate)->Exit(); -} - -TEST(MapRetaining) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - CheckMapRetainingFor(v8_flags.retain_maps_for_n_gc); - CheckMapRetainingFor(0); - CheckMapRetainingFor(1); - CheckMapRetainingFor(7); -} - -TEST(RetainedMapsCleanup) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - v8::Local<v8::Context> ctx = v8::Context::New(CcTest::isolate()); - DirectHandle<Context> context = Utils::OpenDirectHandle(*ctx); - CHECK(IsNativeContext(*context)); - DirectHandle<NativeContext> native_context = Cast<NativeContext>(context); - - ctx->Enter(); - DirectHandle<WeakFixedArray> array_with_map = - AddRetainedMap(isolate, native_context); - CHECK(array_with_map->get(0).IsWeak()); - heap->NotifyContextDisposed(true); - heap::InvokeMajorGC(heap); - ctx->Exit(); - - CHECK_EQ(ReadOnlyRoots(heap).empty_weak_array_list(), - native_context->retained_maps()); -} - -TEST(PreprocessStackTrace) { - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - v8::TryCatch try_catch(CcTest::isolate()); - CompileRun("throw new Error();"); - CHECK(try_catch.HasCaught()); - Isolate* isolate = CcTest::i_isolate(); - DirectHandle<JSAny> exception = - Cast<JSAny>(v8::Utils::OpenHandle(*try_catch.Exception())); - DirectHandle<Name> key = isolate->factory()->error_stack_symbol(); - DirectHandle<JSAny> stack_trace = Cast<JSAny>( - Object::GetProperty(isolate, exception, key).ToHandleChecked()); - DirectHandle<Object> code = - Object::GetElement(isolate, stack_trace, 3).ToHandleChecked(); - CHECK(IsInstructionStream(*code)); - - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); - - DirectHandle<Object> pos = - Object::GetElement(isolate, stack_trace, 3).ToHandleChecked(); - CHECK(IsSmi(*pos)); - - DirectHandle<FixedArray> frame_array = Cast<FixedArray>(stack_trace); - const uint32_t array_length = frame_array->length().value(); - for (uint32_t i = 0; i < array_length; i++) { - DirectHandle<Object> element = - Object::GetElement(isolate, stack_trace, i).ToHandleChecked(); - CHECK(!IsInstructionStream(*element)); - } -} - -void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) { - CHECK_LE(OFFSET_OF_DATA_START(FixedArray), bytes); - CHECK(IsAligned(bytes, kTaggedSize)); - Factory* factory = isolate->factory(); - HandleScope scope(isolate); - AlwaysAllocateScopeForTesting always_allocate(isolate->heap()); - int elements = static_cast<int>((bytes - OFFSET_OF_DATA_START(FixedArray)) / - kTaggedSize); - DirectHandle<FixedArray> array = factory->NewFixedArray( - elements, - space == NEW_SPACE ? AllocationType::kYoung : AllocationType::kOld); - CHECK((space == NEW_SPACE) == HeapLayout::InYoungGeneration(*array)); - CHECK_EQ(bytes, static_cast<size_t>(array->Size())); -} - -TEST(NewSpaceAllocationCounter) { - if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - heap->FreeMainThreadLinearAllocationAreas(); - size_t counter1 = heap->NewSpaceAllocationCounter(); - heap::EmptyNewSpaceUsingGC(heap); // Ensure new space is empty. - const size_t kSize = 1024; - AllocateInSpace(isolate, kSize, NEW_SPACE); - heap->FreeMainThreadLinearAllocationAreas(); - size_t counter2 = heap->NewSpaceAllocationCounter(); - CHECK_EQ(kSize, counter2 - counter1); - heap::InvokeMinorGC(heap); - size_t counter3 = heap->NewSpaceAllocationCounter(); - CHECK_EQ(0U, counter3 - counter2); - // Test counter overflow. - heap->FreeMainThreadLinearAllocationAreas(); - size_t max_counter = static_cast<size_t>(-1); - heap->SetNewSpaceAllocationCounterForTesting(max_counter - 10 * kSize); - size_t start = heap->NewSpaceAllocationCounter(); - for (int i = 0; i < 20; i++) { - AllocateInSpace(isolate, kSize, NEW_SPACE); - heap->FreeMainThreadLinearAllocationAreas(); - size_t counter = heap->NewSpaceAllocationCounter(); - CHECK_EQ(kSize, counter - start); - start = counter; - } -} - -TEST(OldSpaceAllocationCounter) { - // Using the string forwarding table can free allocations during sweeping, due - // to ThinString trimming, thus failing this test. - // The flag (and handling of the forwarding table/ThinString transitions in - // young gen) is only temporary so we just skip this test for now. - if (v8_flags.always_use_string_forwarding_table) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - // Disable LAB, such that calculations with SizeOfObjects() and object size - // are correct. - heap->DisableInlineAllocation(); - heap::EmptyNewSpaceUsingGC(heap); - size_t counter1 = heap->OldGenerationAllocationCounter(); - const size_t kSize = 1024; - AllocateInSpace(isolate, kSize, OLD_SPACE); - size_t counter2 = heap->OldGenerationAllocationCounter(); - // TODO(ulan): replace all CHECK_LE with CHECK_EQ after v8:4148 is fixed. - CHECK_LE(kSize, counter2 - counter1); - heap::InvokeMinorGC(heap); - size_t counter3 = heap->OldGenerationAllocationCounter(); - CHECK_EQ(0u, counter3 - counter2); - AllocateInSpace(isolate, kSize, OLD_SPACE); - heap::InvokeMajorGC(heap); - size_t counter4 = heap->OldGenerationAllocationCounter(); - CHECK_LE(kSize, counter4 - counter3); - // Test counter overflow. - size_t max_counter = static_cast<size_t>(-1); - heap->set_old_generation_allocation_counter_at_last_gc(max_counter - - 10 * kSize); - size_t start = heap->OldGenerationAllocationCounter(); - for (int i = 0; i < 20; i++) { - AllocateInSpace(isolate, kSize, OLD_SPACE); - size_t counter = heap->OldGenerationAllocationCounter(); - CHECK_LE(kSize, counter - start); - start = counter; - } -} - -static void CheckLeak(const v8::FunctionCallbackInfo<v8::Value>& info) { - CHECK(i::ValidateCallbackInfo(info)); - Isolate* isolate = CcTest::i_isolate(); - Tagged<Object> message( - *reinterpret_cast<Address*>(isolate->pending_message_address())); - CHECK(IsTheHole(message)); -} - -TEST(MessageObjectLeak) { - CcTest::InitializeVM(); - v8_flags.allow_natives_syntax = true; - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); - global->Set(isolate, "check", v8::FunctionTemplate::New(isolate, CheckLeak)); - v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global); - v8::Context::Scope cscope(context); - - const char* test = - "function test() {" - " try {" - " throw 'message 1';" - " } catch (e) {" - " }" - " check();" - " L: try {" - " throw 'message 2';" - " } finally {" - " break L;" - " }" - " check();" - "}" - "%PrepareFunctionForOptimization(test);" - "test()"; - CompileRun(test); - - const char* test2 = - "%OptimizeFunctionOnNextCall(test);" - "test()"; - CompileRun(test2); -} - - -// This is the same as Factory::NewByteArray, except it doesn't retry on -// allocation failure. -AllocationResult HeapTester::AllocateByteArrayForTest( - Heap* heap, uint32_t length, AllocationType allocation_type) { - DCHECK_LE(length, ByteArray::kMaxLength); - int size = ByteArray::SizeFor(length); - Tagged<HeapObject> result; - { - AllocationResult allocation = heap->AllocateRaw(size, allocation_type); - if (!allocation.To(&result)) return allocation; - } - - result->set_map_after_allocation(heap->isolate(), - ReadOnlyRoots(heap).byte_array_map(), - SKIP_WRITE_BARRIER); - Cast<ByteArray>(result)->set_length(length); - return AllocationResult::FromObject(result); -} - -bool HeapTester::CodeEnsureLinearAllocationArea(Heap* heap, int size_in_bytes) { - MainAllocator* allocator = heap->allocator()->code_space_allocator(); - return allocator->EnsureAllocationForTesting( - size_in_bytes, AllocationAlignment::kTaggedAligned, - AllocationOrigin::kRuntime); -} - - - -class StaticOneByteResource : public v8::String::ExternalOneByteStringResource { - public: - explicit StaticOneByteResource(const char* data) : data_(data) {} - - ~StaticOneByteResource() override = default; - - const char* data() const override { return data_; } - - size_t length() const override { return strlen(data_); } - - private: - const char* data_; -}; - -TEST(Regress631969) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - v8_flags.parallel_compaction = false; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - // Get the heap in clean state. - heap::InvokeMajorGC(heap); - heap::InvokeMajorGC(heap); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - // Allocate two strings in a fresh page and mark the page as evacuation - // candidate. - heap::SimulateFullSpace(heap->old_space()); - Handle<String> s1 = - factory->NewStringFromStaticChars("123456789", AllocationType::kOld); - Handle<String> s2 = - factory->NewStringFromStaticChars("01234", AllocationType::kOld); - heap::ForceEvacuationCandidate(NormalPage::FromHeapObject(*s1)); - - heap::SimulateIncrementalMarking(heap, false); - - // Allocate a cons string and promote it to a fresh page in the old space. - DirectHandle<String> s3 = factory->NewConsString(s1, s2).ToHandleChecked(); - heap::EmptyNewSpaceUsingGC(heap); - - heap::SimulateIncrementalMarking(heap, false); - - // Finish incremental marking. - static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); - IncrementalMarking* marking = heap->incremental_marking(); - while (!marking->IsMajorMarkingComplete()) { - marking->AdvanceForTesting(kStepSize); - } - - { - StaticOneByteResource external_string("12345678901234"); - s3->MakeExternal(isolate, &external_string); - heap::InvokeMajorGC(heap); - // This avoids the GC from trying to free stack allocated resources. - i::Cast<i::ExternalOneByteString>(s3)->SetResource(isolate, nullptr); - } -} - -TEST(ContinuousRightTrimFixedArrayInBlackArea) { - if (v8_flags.black_allocated_pages) return; - if (!v8_flags.incremental_marking) return; - v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - Isolate* isolate = CcTest::i_isolate(); - heap::InvokeMajorGC(heap); - - i::IncrementalMarking* marking = heap->incremental_marking(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - } - CHECK(marking->IsMarking()); - CHECK(marking->black_allocation()); - - // Ensure that we allocate a new page, set up a bump pointer area, and - // perform the allocation in a black area. - heap::SimulateFullSpace(heap->old_space()); - isolate->factory()->NewFixedArray(10, AllocationType::kOld); - - // Allocate the fixed array that will be trimmed later. - DirectHandle<FixedArray> array = - isolate->factory()->NewFixedArray(100, AllocationType::kOld); - Address start_address = array->address(); - Address end_address = start_address + array->Size(); - NormalPage* page = NormalPage::FromAddress(start_address); - NonAtomicMarkingState* marking_state = heap->non_atomic_marking_state(); - CHECK(marking_state->IsMarked(*array)); - CHECK(page->marking_bitmap()->AllBitsSetInRange( - MarkingBitmap::AddressToIndex(start_address), - MarkingBitmap::LimitAddressToIndex(end_address))); - CHECK(heap->old_space()->Contains(*array)); - - // Trim it once by one word to check that the trimmed area gets unmarked. - Address previous = end_address - kTaggedSize; - isolate->heap()->RightTrimArray(*array, 99, 100); - - Tagged<HeapObject> filler = HeapObject::FromAddress(previous); - CHECK(IsFreeSpaceOrFiller(filler)); - - // Trim 10 times by one, two, and three word. - for (int i = 1; i <= 3; i++) { - for (int j = 0; j < 10; j++) { - previous -= kTaggedSize * i; - const uint32_t old_capacity = array->capacity().value(); - CHECK_GE(old_capacity, i); - const uint32_t new_capacity = old_capacity - i; - isolate->heap()->RightTrimArray(*array, new_capacity, old_capacity); - filler = HeapObject::FromAddress(previous); - CHECK(IsFreeSpaceOrFiller(filler)); - CHECK(marking_state->IsUnmarked(filler)); - } - } - - heap::InvokeAtomicMajorGC(heap); -} - -TEST(RightTrimFixedArrayWithBlackAllocatedPages) { - if (!v8_flags.black_allocated_pages) return; - if (!v8_flags.incremental_marking) return; - v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - Isolate* isolate = CcTest::i_isolate(); - heap::InvokeMajorGC(heap); - - i::IncrementalMarking* marking = heap->incremental_marking(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - } - CHECK(marking->IsMarking()); - CHECK(marking->black_allocation()); - - // Ensure that we allocate a new page, set up a bump pointer area, and - // perform the allocation in a black area. - heap::SimulateFullSpace(heap->old_space()); - isolate->factory()->NewFixedArray(10, AllocationType::kOld); - - // Allocate the fixed array that will be trimmed later. - DirectHandle<FixedArray> array = - isolate->factory()->NewFixedArray(100, AllocationType::kOld); - Address start_address = array->address(); - Address end_address = start_address + array->Size(); - NormalPage* page = NormalPage::FromHeapObject(*array); - CHECK(page->is_black_allocated()); - CHECK(heap->old_space()->Contains(*array)); - - // Trim it once by one word, which shouldn't affect the BLACK_ALLOCATED flag. - Address previous = end_address - kTaggedSize; - isolate->heap()->RightTrimArray(*array, 99, 100); - - Tagged<HeapObject> filler = HeapObject::FromAddress(previous); - CHECK(IsFreeSpaceOrFiller(filler)); - CHECK(page->is_black_allocated()); - - heap::InvokeAtomicMajorGC(heap); - CHECK(!NormalPage::FromHeapObject(*array)->is_black_allocated()); - - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - - // Allocate the large fixed array that will be trimmed later. - array = isolate->factory()->NewFixedArray(200000, AllocationType::kOld); - CHECK(heap->lo_space()->Contains(*array)); - CHECK(!BasePage::FromHeapObject(*array)->is_black_allocated()); - - heap::InvokeAtomicMajorGC(heap); - CHECK(!BasePage::FromHeapObject(*array)->is_black_allocated()); -} - -TEST(Regress618958) { - if (!v8_flags.incremental_marking) return; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - bool isolate_is_locked = true; - v8::ExternalMemoryAccounter accounter; - accounter.Increase(CcTest::isolate(), 100 * MB); - int mark_sweep_count_before = heap->ms_count(); - heap->MemoryPressureNotification(MemoryPressureLevel::kCritical, - isolate_is_locked); - int mark_sweep_count_after = heap->ms_count(); - int mark_sweeps_performed = mark_sweep_count_after - mark_sweep_count_before; - // The memory pressuer handler either performed two GCs or performed one and - // started incremental marking. - CHECK(mark_sweeps_performed == 2 || - (mark_sweeps_performed == 1 && - !heap->incremental_marking()->IsStopped())); - accounter.Decrease(CcTest::isolate(), 100 * MB); -} - -TEST(YoungGenerationLargeObjectAllocationScavenge) { - if (v8_flags.minor_ms) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - Isolate* isolate = heap->isolate(); - if (!isolate->serializer_enabled()) return; - - DirectHandle<FixedArray> array_small = - isolate->factory()->NewFixedArray(200000); - MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array_small); - BasePage* metadata = chunk->Metadata(isolate); - CHECK_EQ(NEW_LO_SPACE, SbxCast<MutablePage>(metadata)->owner_identity()); - CHECK(metadata->is_large()); - CHECK(chunk->IsToPage()); - - DirectHandle<Object> number = isolate->factory()->NewHeapNumber(123.456); - array_small->set(0, *number); - - heap::InvokeMinorGC(heap); - - // After the first young generation GC array_small will be in the old - // generation large object space. - chunk = MemoryChunk::FromHeapObject(*array_small); - CHECK_EQ(LO_SPACE, SbxCast<MutablePage>(chunk->Metadata())->owner_identity()); - CHECK(!chunk->InYoungGeneration()); - - heap::InvokeMemoryReducingMajorGCs(heap); -} - -TEST(YoungGenerationLargeObjectAllocationMarkCompact) { - if (v8_flags.minor_ms) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - Isolate* isolate = heap->isolate(); - if (!isolate->serializer_enabled()) return; - - DirectHandle<FixedArray> array_small = - isolate->factory()->NewFixedArray(200000); - MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array_small); - BasePage* metadata = chunk->Metadata(isolate); - CHECK_EQ(NEW_LO_SPACE, SbxCast<MutablePage>(metadata)->owner_identity()); - CHECK(metadata->is_large()); - CHECK(chunk->IsToPage()); - - DirectHandle<Object> number = isolate->factory()->NewHeapNumber(123.456); - array_small->set(0, *number); - - heap::InvokeMajorGC(heap); - - // After the first full GC array_small will be in the old generation - // large object space. - chunk = MemoryChunk::FromHeapObject(*array_small); - CHECK_EQ(LO_SPACE, SbxCast<MutablePage>(chunk->Metadata())->owner_identity()); - CHECK(!chunk->InYoungGeneration()); - - heap::InvokeMemoryReducingMajorGCs(heap); -} - -TEST(YoungGenerationLargeObjectAllocationReleaseScavenger) { - if (v8_flags.minor_ms) return; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - Isolate* isolate = heap->isolate(); - if (!isolate->serializer_enabled()) return; - - { - HandleScope new_scope(isolate); - for (int i = 0; i < 10; i++) { - DirectHandle<FixedArray> array_small = - isolate->factory()->NewFixedArray(20000); - MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array_small); - CHECK_EQ(NEW_LO_SPACE, - SbxCast<MutablePage>(chunk->Metadata())->owner_identity()); - CHECK(chunk->IsToPage()); - } - } - - heap::InvokeMinorGC(heap); - CHECK(isolate->heap()->new_lo_space()->IsEmpty()); - CHECK_EQ(0, isolate->heap()->new_lo_space()->Size()); - CHECK_EQ(0, isolate->heap()->new_lo_space()->SizeOfObjects()); - CHECK(isolate->heap()->lo_space()->IsEmpty()); - CHECK_EQ(0, isolate->heap()->lo_space()->Size()); - CHECK_EQ(0, isolate->heap()->lo_space()->SizeOfObjects()); -} - -TEST(UncommitUnusedLargeObjectMemory) { - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Heap* heap = CcTest::heap(); - Isolate* isolate = heap->isolate(); - - DirectHandle<FixedArray> array = - isolate->factory()->NewFixedArray(200000, AllocationType::kOld); - MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array); - MutablePage* page = SbxCast<MutablePage>(chunk->Metadata()); - CHECK_EQ(page->owner_identity(), LO_SPACE); - - intptr_t size_before = array->Size(); - size_t committed_memory_before = page->CommittedPhysicalMemory(); - - array->RightTrim(isolate, 1); - CHECK(array->Size() < size_before); - - heap::InvokeMajorGC(heap); - CHECK(page->CommittedPhysicalMemory() < committed_memory_before); - size_t shrinked_size = RoundUp( - (array->address() - chunk->address()) + array->Size(), CommitPageSize()); - CHECK_EQ(shrinked_size, page->CommittedPhysicalMemory()); -} - -const int kHeapLimit = 100 * MB; -Isolate* oom_isolate = nullptr; - -void OOMCallback(const char* location, const OOMDetails&) { - Heap* heap = oom_isolate->heap(); - size_t kSlack = heap->new_space() ? heap->MaxSemiSpaceSize() : 0; - CHECK_LE(heap->OldGenerationCapacity(), kHeapLimit + kSlack); - base::OS::ExitProcess(0); -} - -UNINITIALIZED_TEST(OutOfMemory) { - if (v8_flags.stress_incremental_marking) return; -#ifdef VERIFY_HEAP - if (v8_flags.verify_heap) return; -#endif - v8_flags.max_old_space_size = kHeapLimit / MB; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - v8::Isolate::Scope isolate_scope(isolate); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - oom_isolate = i_isolate; - isolate->SetOOMErrorHandler(OOMCallback); - { - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - Factory* factory = i_isolate->factory(); - HandleScope handle_scope(i_isolate); - while (true) { - factory->NewFixedArray(100); - } - } -} - -UNINITIALIZED_TEST(OutOfMemoryIneffectiveGC) { - if (!v8_flags.detect_ineffective_gcs_near_heap_limit) return; - if (v8_flags.stress_incremental_marking || - v8_flags.stress_concurrent_allocation) { - return; - } -#ifdef VERIFY_HEAP - if (v8_flags.verify_heap) return; -#endif - - v8_flags.max_old_space_size = kHeapLimit / MB; - // The test timeouts on some platforms with the default 95% heap size - // threshold. - v8_flags.ineffective_gc_size_threshold = 0.8; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - oom_isolate = i_isolate; - isolate->SetOOMErrorHandler(OOMCallback); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - { - v8::Isolate::Scope isolate_scope(isolate); - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - std::vector<Handle<FixedArray>> arrays; - heap::InvokeMajorGC(heap); - - HandleScope scope(i_isolate); - const size_t heap_threshold = heap->MaxOldGenerationSize() * 0.8; - while (heap->OldGenerationSizeOfObjects() < heap_threshold) { - arrays.push_back(factory->NewFixedArray(1000, AllocationType::kOld)); - // This ensures OldGenerationSizeOfObjects() remains above the threshold - // even after a last resort GC. - if (heap->OldGenerationSizeOfObjects() >= heap_threshold) { - heap->CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort); - } - } - { - int initial_ms_count = heap->ms_count(); - int ineffective_ms_start = initial_ms_count; - while (heap->ms_count() < initial_ms_count + 10) { - HandleScope inner_scope(i_isolate); - arrays.push_back(factory->NewFixedArray(30000, AllocationType::kOld)); - if (heap->tracer()->AverageMarkCompactMutatorUtilization() >= 0.3) { - ineffective_ms_start = heap->ms_count() + 1; - } - } - int consecutive_ineffective_ms = heap->ms_count() - ineffective_ms_start; - if (heap->tracer()->AverageMarkCompactMutatorUtilization() < 0.3) { - // The threshold for consecutive MC is 4, but CollectAllAvailableGarbage - // can run 2 cycles which counts as 1 "ineffective MC". - CHECK_LE(consecutive_ineffective_ms, 8); - } - } - } - isolate->Dispose(); -} - -UNINITIALIZED_TEST(OutOfMemoryIneffectiveGCRunningJS) { - if (!v8_flags.detect_ineffective_gcs_near_heap_limit) return; - if (v8_flags.stress_incremental_marking) return; - - v8_flags.max_old_space_size = 10; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - oom_isolate = i_isolate; - - isolate->SetOOMErrorHandler(OOMCallback); - - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Context::New(isolate)->Enter(); - - // Test that source positions are not collected as part of a failing GC, which - // will fail as allocation is disallowed. If the test works, this should call - // OOMCallback and terminate without crashing. - CompileRun(R"javascript( - var array = []; - for(var i = 20000; i < 40000; ++i) { - array.push(new Array(i)); - } - )javascript"); - - FATAL("Should not get here as OOMCallback should be called"); -} - -HEAP_TEST(Regress779503) { - // The following regression test ensures that the Scavenger does not allocate - // over invalid slots. More specific, the Scavenger should not sweep a page - // that it currently processes because it might allocate over the currently - // processed slot. - if (v8_flags.single_generation) return; - v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - const uint32_t kArraySize = 2048; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = CcTest::heap(); - heap::SealCurrentObjects(heap); - { - HandleScope handle_scope(isolate); - // The byte array filled with kHeapObjectTag ensures that we cannot read - // from the slot again and interpret it as heap value. Doing so will crash. - DirectHandle<ByteArray> byte_array = - isolate->factory()->NewByteArray(kArraySize); - CHECK(HeapLayout::InYoungGeneration(*byte_array)); - for (uint32_t i = 0; i < kArraySize; i++) { - byte_array->set(i, kHeapObjectTag); - } - - { - HandleScope new_scope(isolate); - // The FixedArray in old space serves as space for slots. - DirectHandle<FixedArray> fixed_array = - isolate->factory()->NewFixedArray(kArraySize, AllocationType::kOld); - CHECK(!HeapLayout::InYoungGeneration(*fixed_array)); - for (uint32_t i = 0; i < kArraySize; i++) { - fixed_array->set(i, *byte_array); - } - } - // Delay sweeper tasks to allow the scavenger to sweep the page it is - // currently scavenging. - heap->delay_sweeper_tasks_for_testing_ = true; - heap::InvokeMajorGC(heap); - CHECK(!HeapLayout::InYoungGeneration(*byte_array)); - } - // Scavenging and sweeping the same page will crash as slots will be - // overridden. - heap::InvokeMinorGC(heap); - heap->delay_sweeper_tasks_for_testing_ = false; -} - -struct OutOfMemoryState { - Heap* heap; - bool oom_triggered; - size_t old_generation_capacity_at_oom; - size_t memory_allocator_size_at_oom; - size_t new_space_capacity_at_oom; - size_t new_lo_space_size_at_oom; - size_t current_heap_limit; - size_t initial_heap_limit; -}; - -size_t NearHeapLimitCallback(void* raw_state, size_t current_heap_limit, - size_t initial_heap_limit) { - OutOfMemoryState* state = static_cast<OutOfMemoryState*>(raw_state); - Heap* heap = state->heap; - state->oom_triggered = true; - state->old_generation_capacity_at_oom = heap->OldGenerationCapacity(); - state->memory_allocator_size_at_oom = heap->memory_allocator()->Size(); - state->new_space_capacity_at_oom = - heap->new_space() ? heap->new_space()->Capacity() : 0; - state->new_lo_space_size_at_oom = - heap->new_lo_space() ? heap->new_lo_space()->Size() : 0; - state->current_heap_limit = current_heap_limit; - state->initial_heap_limit = initial_heap_limit; - return initial_heap_limit + 100 * MB; -} - -size_t MemoryAllocatorSizeFromHeapCapacity(size_t capacity) { - // Size to capacity factor. - double factor = NormalPage::kPageSize * 1.0 / - MemoryChunkLayout::AllocatableMemoryInDataPage(); - // Some tables (e.g. deoptimization table) are allocated directly with the - // memory allocator. Allow some slack to account for them. - size_t slack = 5 * MB; - return static_cast<size_t>(capacity * factor) + slack; -} - -UNINITIALIZED_TEST(OutOfMemorySmallObjects) { - if (v8_flags.stress_incremental_marking) return; -#ifdef VERIFY_HEAP - if (v8_flags.verify_heap) return; -#endif - const size_t kOldGenerationLimit = 50 * MB; - v8_flags.max_old_space_size = kOldGenerationLimit / MB; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - Factory* factory = i_isolate->factory(); - OutOfMemoryState state; - state.heap = heap; - state.oom_triggered = false; - heap->AddNearHeapLimitCallback(NearHeapLimitCallback, &state); - { - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - - v8::Isolate::Scope isolate_scope(isolate); - HandleScope handle_scope(i_isolate); - while (!state.oom_triggered) { - factory->NewFixedArray(100); - } - } - CHECK_LE(state.old_generation_capacity_at_oom, - kOldGenerationLimit + heap->MaxSemiSpaceSize()); - CHECK_LE(kOldGenerationLimit, - state.old_generation_capacity_at_oom + heap->MaxSemiSpaceSize()); - CHECK_LE( - state.memory_allocator_size_at_oom, - MemoryAllocatorSizeFromHeapCapacity(state.old_generation_capacity_at_oom + - 2 * state.new_space_capacity_at_oom)); - isolate->Dispose(); -} - -UNINITIALIZED_TEST(OutOfMemoryLargeObjects) { - if (v8_flags.stress_incremental_marking) return; -#ifdef VERIFY_HEAP - if (v8_flags.verify_heap) return; -#endif - const size_t kOldGenerationLimit = 50 * MB; - v8_flags.max_old_space_size = kOldGenerationLimit / MB; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - Factory* factory = i_isolate->factory(); - OutOfMemoryState state; - state.heap = heap; - state.oom_triggered = false; - heap->AddNearHeapLimitCallback(NearHeapLimitCallback, &state); - { - v8::Isolate::Scope isolate_scope(isolate); - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - const int kFixedArrayLength = 1000000; - { - HandleScope handle_scope(i_isolate); - while (!state.oom_triggered) { - factory->NewFixedArray(kFixedArrayLength); - } - } - CHECK_LE(state.old_generation_capacity_at_oom, - kOldGenerationLimit + state.new_space_capacity_at_oom + - state.new_lo_space_size_at_oom + - FixedArray::SizeFor(kFixedArrayLength)); - CHECK_LE(kOldGenerationLimit, state.old_generation_capacity_at_oom + - state.new_space_capacity_at_oom + - state.new_lo_space_size_at_oom + - FixedArray::SizeFor(kFixedArrayLength)); - CHECK_LE(state.memory_allocator_size_at_oom, - MemoryAllocatorSizeFromHeapCapacity( - state.old_generation_capacity_at_oom + - 2 * state.new_space_capacity_at_oom + - state.new_lo_space_size_at_oom)); - } - isolate->Dispose(); -} - -UNINITIALIZED_TEST(RestoreHeapLimit) { - if (v8_flags.stress_incremental_marking) return; -#ifdef VERIFY_HEAP - if (v8_flags.verify_heap) return; -#endif - ManualGCScope manual_gc_scope; - const size_t kOldGenerationLimit = 50 * MB; - v8_flags.max_old_space_size = kOldGenerationLimit / MB; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - Factory* factory = i_isolate->factory(); - - { - v8::Isolate::Scope isolate_scope(isolate); - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - - // In this test, we need to invoke GC without stack, otherwise some objects - // may not be reclaimed because of conservative stack scanning and the heap - // limit may be reached. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - - OutOfMemoryState state; - state.heap = heap; - state.oom_triggered = false; - heap->AddNearHeapLimitCallback(NearHeapLimitCallback, &state); - heap->AutomaticallyRestoreInitialHeapLimit(0.5); - const int kFixedArrayLength = 1000000; - { - HandleScope handle_scope(i_isolate); - while (!state.oom_triggered) { - factory->NewFixedArray(kFixedArrayLength); - } - } - heap->MemoryPressureNotification(MemoryPressureLevel::kCritical, true); - state.oom_triggered = false; - { - HandleScope handle_scope(i_isolate); - while (!state.oom_triggered) { - factory->NewFixedArray(kFixedArrayLength); - } - } - CHECK_EQ(state.current_heap_limit, state.initial_heap_limit); - } - - isolate->Dispose(); -} - -void HeapTester::UncommitUnusedMemory(Heap* heap) { - if (!v8_flags.minor_ms) heap->ReduceNewSpaceSizeForTesting(); - heap->memory_allocator()->ReleasePooledChunksImmediately(); -} - -class DeleteNative { - public: - static constexpr ManagedTypeId kTypeID = ManagedTypeId::kTestDeleteNative; -}; - -// The test only runs on 64-bit, because it simulates allocating ~9Gb -// external memory. -#if defined(V8_TARGET_ARCH_64_BIT) -TEST(Regress8014) { - Isolate* isolate = CcTest::InitIsolateOnce(); - Heap* heap = isolate->heap(); - { - HandleScope scope(isolate); - for (int i = 0; i < 10000; i++) { - auto handle = CppGCManaged<DeleteNative>::Create( - isolate, 1000000, std::make_shared<DeleteNative>()); - USE(handle); - } - } - int ms_count = heap->ms_count(); - heap->MemoryPressureNotification(MemoryPressureLevel::kCritical, true); - // Several GCs can be triggred by the above call. - // The bad case triggers 10000 GCs. - CHECK_LE(heap->ms_count(), ms_count + 10); -} -#endif - -TEST(Regress8617) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - HandleScope scope(isolate); - heap::SimulateFullSpace(heap->old_space()); - // Step 1. Create a function and ensure that it is in the old space. - DirectHandle<Object> foo = - v8::Utils::OpenDirectHandle(*CompileRun("function foo() { return 42; };" - "foo;")); - if (HeapLayout::InYoungGeneration(*foo)) { - heap::EmptyNewSpaceUsingGC(heap); - } - // Step 2. Create an object with a reference to foo in the descriptor array. - CompileRun( - "var obj = {};" - "obj.method = foo;" - "obj;"); - // Step 3. Make sure that foo moves during Mark-Compact. - NormalPage* ec_page = NormalPage::FromAddress((*foo).ptr()); - heap::ForceEvacuationCandidate(ec_page); - // Step 4. Start incremental marking. - heap::SimulateIncrementalMarking(heap, false); - CHECK(ec_page->Chunk()->IsEvacuationCandidate()); - // Step 5. Install a new descriptor array on the map of the object. - // This runs the marking barrier for the descriptor array. - // In the bad case it sets the number of marked descriptors but does not - // change the color of the descriptor array. - CompileRun("obj.bar = 10;"); - // Step 6. Promote the descriptor array to old space. During promotion - // the Scavenger will not record the slot of foo in the descriptor array. - heap::EmptyNewSpaceUsingGC(heap); - // Step 7. Complete the Mark-Compact. - heap::InvokeMajorGC(heap); - // Step 8. Use the descriptor for foo, which contains a stale pointer. - CompileRun("obj.method()"); -} - -HEAP_TEST(MemoryReducerActivationForSmallHeaps) { - if (v8_flags.single_generation || !v8_flags.memory_reducer) return; - ManualGCScope manual_gc_scope; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - CHECK_EQ(heap->memory_reducer()->state_.id(), MemoryReducer::kUninit); - LocalContext env; - HandleScope scope(isolate); - const size_t kActivationThreshold = 1 * MB; - size_t initial_capacity = heap->OldGenerationCapacity(); - while (heap->OldGenerationCapacity() < - initial_capacity + kActivationThreshold) { - isolate->factory()->NewFixedArray(1 * KB, AllocationType::kOld); - } - CHECK_EQ(heap->memory_reducer()->state_.id(), MemoryReducer::kWait); -} - -TEST(AllocateExternalBackingStore) { - ManualGCScope manual_gc_scope; - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - int initial_ms_count = heap->ms_count(); - void* result = - heap->AllocateExternalBackingStore([](size_t) { return nullptr; }, 10); - CHECK_NULL(result); - // At least two GCs should happen. - CHECK_LE(2, heap->ms_count() - initial_ms_count); -} - -TEST(CodeObjectRegistry) { - // We turn off compaction to ensure that code is not moving. - v8_flags.compact = false; - - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - DirectHandle<InstructionStream> code1; - HandleScope outer_scope(heap->isolate()); - Address code2_address; - { - // Ensure that both code objects end up on the same page. - CHECK(HeapTester::CodeEnsureLinearAllocationArea( - heap, MemoryChunkLayout::MaxRegularCodeObjectSize())); - code1 = DummyOptimizedCode(isolate); - DirectHandle<InstructionStream> code2 = DummyOptimizedCode(isolate); - code2_address = code2->address(); - - CHECK_EQ(MutablePage::FromHeapObject(isolate, *code1), - MutablePage::FromHeapObject(isolate, *code2)); - CHECK(MutablePage::FromHeapObject(isolate, *code1) - ->Contains(code1->address())); - CHECK(MutablePage::FromHeapObject(isolate, *code2) - ->Contains(code2->address())); - } - heap::InvokeMemoryReducingMajorGCs(heap); - CHECK( - MutablePage::FromHeapObject(isolate, *code1)->Contains(code1->address())); - CHECK(MutablePage::FromAddress(isolate, code2_address) - ->Contains(code2_address)); -} - -TEST(Regress9701) { - ManualGCScope manual_gc_scope; - if (!v8_flags.incremental_marking) return; - CcTest::InitializeVM(); - Heap* heap = CcTest::heap(); - // Start with an empty new space. - InvokeMinorGC(heap); - - int mark_sweep_count_before = heap->ms_count(); - // Allocate many short living array buffers. - for (int i = 0; i < 1000; i++) { - HandleScope scope(heap->isolate()); - CcTest::i_isolate()->factory()->NewJSArrayBufferAndBackingStore( - 64 * KB, InitializedFlag{true}); - } - int mark_sweep_count_after = heap->ms_count(); - // We expect only scavenges, no full GCs. - CHECK_EQ(mark_sweep_count_before, mark_sweep_count_after); -} - -#if defined(V8_TARGET_ARCH_64_BIT) && !defined(V8_OS_ANDROID) -UNINITIALIZED_TEST(HugeHeapLimit) { - uint64_t kMemoryGB = 16; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - create_params.constraints.ConfigureDefaults(kMemoryGB * GB, kMemoryGB * GB); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); -#ifdef V8_COMPRESS_POINTERS - size_t kExpectedHeapLimit = Heap::kAllocatorLimitOnMaxOldGenerationSize; -#else - size_t kExpectedHeapLimit = size_t{4} * GB; -#endif - CHECK_EQ(kExpectedHeapLimit, i_isolate->heap()->MaxOldGenerationSize()); - CHECK_LT(size_t{3} * GB, i_isolate->heap()->MaxOldGenerationSize()); - isolate->Dispose(); -} -#endif - -UNINITIALIZED_TEST(HeapLimit) { - uint64_t kMemoryGB = 16; - v8_flags.high_end_android_physical_memory_threshold = - static_cast<unsigned int>(kMemoryGB); - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - create_params.constraints.ConfigureDefaults(kMemoryGB * GB, kMemoryGB * GB); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); -#if defined(V8_TARGET_ARCH_64_BIT) - // Because we explicitly set --high_end_android_physical_memory_threshold, - // Android has the same expected heap limit. - size_t kExpectedHeapLimit = size_t{4} * GB; -#else - size_t kExpectedHeapLimit = size_t{1} * GB; -#endif - CHECK_EQ(kExpectedHeapLimit, i_isolate->heap()->MaxOldGenerationSize()); - isolate->Dispose(); -} - -TEST(NoCodeRangeInJitlessMode) { - if (!v8_flags.jitless) return; - CcTest::InitializeVM(); - CHECK(CcTest::i_isolate()->heap()->code_region().is_empty()); -} - -TEST(GarbageCollectionWithLocalHeap) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - - LocalHeap* local_heap = CcTest::i_isolate()->main_thread_local_heap(); - - heap::InvokeMajorGC(CcTest::heap()); - local_heap->ExecuteWhileParked([]() { /* nothing */ }); - heap::InvokeMajorGC(CcTest::heap()); -} - -TEST(Regress10698) { - if (!v8_flags.incremental_marking) return; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - HandleScope handle_scope(isolate); - // This is modeled after the manual allocation folding of heap numbers in - // JSON parser (See commit ba7b25e). - // Step 1. Allocate a byte array in the old space. - DirectHandle<ByteArray> array = - factory->NewByteArray(kTaggedSize, AllocationType::kOld); - // Step 2. Start incremental marking. - SimulateIncrementalMarking(heap, false); - // Step 3. Allocate another byte array. It will be black. - factory->NewByteArray(kTaggedSize, AllocationType::kOld); - Address address = reinterpret_cast<Address>(array->begin()); - Tagged<HeapObject> filler = HeapObject::FromAddress(address); - // Step 4. Set the filler at the end of the first array. - // It will have an impossible markbit pattern because the second markbit - // will be taken from the second array. - filler->set_map_after_allocation(isolate, *factory->one_pointer_filler_map()); -} - -class TestAllocationTracker : public HeapObjectAllocationTracker { - public: - explicit TestAllocationTracker(int expected_size) - : expected_size_(expected_size) {} - - void AllocationEvent(Address addr, int size) { - CHECK(expected_size_ == size); - address_ = addr; - } - - Address address() { return address_; } - - private: - int expected_size_; - Address address_; -}; - -HEAP_TEST(CodeLargeObjectSpace) { - Heap* heap = CcTest::heap(); - int size_in_bytes = - heap->MaxRegularHeapObjectSize(AllocationType::kCode) + kTaggedSize; - TestAllocationTracker allocation_tracker{size_in_bytes}; - heap->AddHeapObjectAllocationTracker(&allocation_tracker); - - Tagged<HeapObject> obj; - { - AllocationResult allocation = heap->AllocateRaw( - size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime); - CHECK(allocation.To(&obj)); - CHECK_EQ(allocation.ToAddress(), allocation_tracker.address()); - ThreadIsolation::RegisterInstructionStreamAllocation(obj.address(), - size_in_bytes); - - heap->CreateFillerObjectAt(obj.address(), size_in_bytes); - } - - CHECK(HeapLayout::InAnyLargeSpace(obj)); - heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); -} - -UNINITIALIZED_HEAP_TEST(CodeLargeObjectSpace64k) { - // Simulate having a system with 64k OS pages. - i::v8_flags.v8_os_page_size = 64; - - // Initialize the isolate manually to make sure --v8-os-page-size is taken - // into account. - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - i::Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - - // Allocate a regular code object. - { - v8::Isolate::Scope isolate_scope(isolate); - int size_in_bytes = - heap->MaxRegularHeapObjectSize(AllocationType::kCode) - kTaggedSize; - TestAllocationTracker allocation_tracker{size_in_bytes}; - heap->AddHeapObjectAllocationTracker(&allocation_tracker); - - Tagged<HeapObject> obj; - { - AllocationResult allocation = heap->AllocateRaw( - size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime); - CHECK(allocation.To(&obj)); - CHECK_EQ(allocation.ToAddress(), allocation_tracker.address()); - ThreadIsolation::RegisterInstructionStreamAllocation(obj.address(), - size_in_bytes); - - heap->CreateFillerObjectAt(obj.address(), size_in_bytes); - } - - CHECK(!HeapLayout::InAnyLargeSpace(obj)); - heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); - } - - // Allocate a large code object. - { - v8::Isolate::Scope isolate_scope(isolate); - int size_in_bytes = - heap->MaxRegularHeapObjectSize(AllocationType::kCode) + kTaggedSize; - TestAllocationTracker allocation_tracker{size_in_bytes}; - heap->AddHeapObjectAllocationTracker(&allocation_tracker); - - Tagged<HeapObject> obj; - { - AllocationResult allocation = heap->AllocateRaw( - size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime); - CHECK(allocation.To(&obj)); - CHECK_EQ(allocation.ToAddress(), allocation_tracker.address()); - ThreadIsolation::RegisterInstructionStreamAllocation(obj.address(), - size_in_bytes); - - heap->CreateFillerObjectAt(obj.address(), size_in_bytes); - } - - CHECK(HeapLayout::InAnyLargeSpace(obj)); - heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); - } - - isolate->Dispose(); -} - -TEST(IsPendingAllocationNewSpace) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - HandleScope handle_scope(isolate); - DirectHandle<FixedArray> object = - factory->NewFixedArray(5, AllocationType::kYoung); - CHECK(heap->IsPendingAllocation(*object)); - heap->PublishMainThreadPendingAllocations(); - CHECK(!heap->IsPendingAllocation(*object)); -} - -TEST(IsPendingAllocationNewLOSpace) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - HandleScope handle_scope(isolate); - DirectHandle<FixedArray> object = factory->NewFixedArray( - FixedArray::kMaxRegularLength + 1, AllocationType::kYoung); - CHECK(heap->IsPendingAllocation(*object)); - heap->PublishMainThreadPendingAllocations(); - CHECK(!heap->IsPendingAllocation(*object)); -} - -TEST(IsPendingAllocationOldSpace) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - HandleScope handle_scope(isolate); - DirectHandle<FixedArray> object = - factory->NewFixedArray(5, AllocationType::kOld); - CHECK(heap->IsPendingAllocation(*object)); - heap->PublishMainThreadPendingAllocations(); - CHECK(!heap->IsPendingAllocation(*object)); -} - -TEST(IsPendingAllocationLOSpace) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - Factory* factory = isolate->factory(); - HandleScope handle_scope(isolate); - DirectHandle<FixedArray> object = factory->NewFixedArray( - FixedArray::kMaxRegularLength + 1, AllocationType::kOld); - CHECK(heap->IsPendingAllocation(*object)); - heap->PublishMainThreadPendingAllocations(); - CHECK(!heap->IsPendingAllocation(*object)); -} - -TEST(Regress10900) { - v8_flags.compact_on_every_full_gc = true; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - HandleScope handle_scope(isolate); - uint8_t buffer[i::Assembler::kDefaultBufferSize]; - MacroAssembler masm(isolate, v8::internal::CodeObjectRequired{true}, - ExternalAssemblerBuffer(buffer, sizeof(buffer))); -#if V8_TARGET_ARCH_ARM64 - UseScratchRegisterScope temps(&masm); - Register tmp = temps.AcquireX(); - masm.Mov(tmp, Operand(static_cast<int32_t>( - ReadOnlyRoots(heap).undefined_value().ptr()))); - masm.Push(tmp, tmp); -#else - masm.Push(isolate->factory()->undefined_value()); -#endif - CodeDesc desc; - masm.GetCode(isolate, &desc); - { - DirectHandle<Code> code; - for (int i = 0; i < 100; i++) { - // Generate multiple code pages. - code = Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build(); - } - } - // Force garbage collection that compacts code pages and triggers - // an assertion in Isolate::AddCodeMemoryRange before the bug fix. - heap::InvokeMemoryReducingMajorGCs(heap); -} - -namespace { -v8::Local<v8::Value> GenerateGarbage() { - const char* source = - "let roots = [];" - "for (let i = 0; i < 100; i++) roots.push(new Array(1000).fill(0));" - "roots.push(new Array(1000000).fill(0));" - "roots;"; - return CompileRun(source); -} - -} // anonymous namespace - -TEST(Regress11181) { - v8_flags.compact_on_every_full_gc = true; - CcTest::InitializeVM(); - TracingFlags::runtime_stats.store( - v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE, - std::memory_order_relaxed); - v8::HandleScope scope(CcTest::isolate()); - GenerateGarbage(); - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); -} - -TEST(LongTaskStatsFullAtomic) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(CcTest::isolate()); - GenerateGarbage(); - v8::metrics::LongTaskStats::Reset(isolate); - CHECK_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) - .gc_full_atomic_wall_clock_duration_us); - for (int i = 0; i < 10; ++i) { - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); - } - CHECK_LT(0u, v8::metrics::LongTaskStats::Get(isolate) - .gc_full_atomic_wall_clock_duration_us); - v8::metrics::LongTaskStats::Reset(isolate); - CHECK_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) - .gc_full_atomic_wall_clock_duration_us); -} - -TEST(LongTaskStatsFullIncremental) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(CcTest::isolate()); - v8::Global<v8::Value> objects(isolate, GenerateGarbage()); - v8::metrics::LongTaskStats::Reset(isolate); - CHECK_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) - .gc_full_incremental_wall_clock_duration_us); - for (int i = 0; i < 10; ++i) { - heap::SimulateIncrementalMarking(CcTest::heap()); - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); - } - CHECK_LT(0u, v8::metrics::LongTaskStats::Get(isolate) - .gc_full_incremental_wall_clock_duration_us); - v8::metrics::LongTaskStats::Reset(isolate); - CHECK_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) - .gc_full_incremental_wall_clock_duration_us); -} - -TEST(LongTaskStatsYoung) { - if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(CcTest::isolate()); - GenerateGarbage(); - v8::metrics::LongTaskStats::Reset(isolate); - CHECK_EQ( - 0u, - v8::metrics::LongTaskStats::Get(isolate).gc_young_wall_clock_duration_us); - for (int i = 0; i < 10; ++i) { - heap::InvokeMinorGC(CcTest::heap()); - } - CHECK_LT( - 0u, - v8::metrics::LongTaskStats::Get(isolate).gc_young_wall_clock_duration_us); - v8::metrics::LongTaskStats::Reset(isolate); - CHECK_EQ( - 0u, - v8::metrics::LongTaskStats::Get(isolate).gc_young_wall_clock_duration_us); -} - -} // namespace heap -} // namespace internal -} // namespace v8 - -#undef __ diff --git a/deps/v8/test/cctest/heap/test-incremental-marking.cc b/deps/v8/test/cctest/heap/test-incremental-marking.cc deleted file mode 100644 index 33a094f05a9c..000000000000 --- a/deps/v8/test/cctest/heap/test-incremental-marking.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015 the V8 project 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 <stdlib.h> - -#include "src/heap/safepoint.h" - -#ifdef __linux__ -#include <errno.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#include <utility> - -#include "src/handles/global-handles.h" -#include "src/heap/gc-tracer.h" -#include "src/heap/incremental-marking.h" -#include "src/heap/spaces.h" -#include "src/init/v8.h" -#include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" - -using v8::IdleTask; -using v8::Task; -using v8::Isolate; - -namespace v8 { -namespace internal { -namespace heap { - -TEST_WITH_PLATFORM(IncrementalMarkingUsingTasks, MockPlatform) { - if (!i::v8_flags.incremental_marking) return; - v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. - v8_flags.stress_incremental_marking = false; - v8::Isolate* isolate = CcTest::isolate(); - { - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = CcTest::NewContext(isolate); - v8::Context::Scope context_scope(context); - Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - - i::heap::SimulateFullSpace(heap->old_space()); - i::IncrementalMarking* marking = heap->incremental_marking(); - marking->Stop(); - { - SafepointScope scope(heap->isolate(), - kGlobalSafepointForSharedSpaceIsolate); - heap->tracer()->StartCycle( - GarbageCollector::MARK_COMPACTOR, GarbageCollectionReason::kTesting, - "collector cctest", GCTracer::MarkingType::kIncremental); - marking->Start(GarbageCollector::MARK_COMPACTOR, - i::GarbageCollectionReason::kTesting, "testing"); - } - CHECK(marking->IsMajorMarking()); - while (marking->IsMajorMarking()) { - platform.PerformTask(); - } - CHECK(marking->IsStopped()); - } -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-mark-compact.cc b/deps/v8/test/cctest/heap/test-mark-compact.cc deleted file mode 100644 index 84f7d25ea5a1..000000000000 --- a/deps/v8/test/cctest/heap/test-mark-compact.cc +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <stdlib.h> - -#include "src/common/globals.h" - -#ifdef __linux__ -#include <errno.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#include <utility> - -#include "include/v8-locker.h" -#include "src/handles/global-handles.h" -#include "src/heap/live-object-range-inl.h" -#include "src/heap/mark-compact-inl.h" -#include "src/heap/mark-compact.h" -#include "src/heap/marking-inl.h" -#include "src/init/v8.h" -#include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8 { -namespace internal { -namespace heap { - -TEST(Promotion) { - if (v8_flags.single_generation) return; - v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - { - v8::HandleScope sc(CcTest::isolate()); - Heap* heap = isolate->heap(); - - heap::SealCurrentObjects(heap); - - int array_length = heap::FixedArrayLenFromSize(kMaxRegularHeapObjectSize); - DirectHandle<FixedArray> array = - isolate->factory()->NewFixedArray(array_length); - - // Array should be in the new space. - CHECK(heap->InSpace(*array, NEW_SPACE)); - heap::InvokeMajorGC(heap); - heap::InvokeMajorGC(heap); - CHECK(heap->InSpace(*array, OLD_SPACE)); - } -} - -// This is the same as Factory::NewContextfulMapForCurrentContext, except it -// doesn't retry on allocation failure. -AllocationResult HeapTester::AllocateMapForTest(Isolate* isolate) { - Heap* heap = isolate->heap(); - Tagged<HeapObject> obj; - AllocationResult alloc = heap->AllocateRaw(Map::kSize, AllocationType::kMap); - if (!alloc.To(&obj)) return alloc; - ReadOnlyRoots roots(isolate); - obj->set_map_after_allocation(isolate, *isolate->meta_map()); - return AllocationResult::FromObject(isolate->factory()->InitializeMap( - Cast<Map>(obj), JS_OBJECT_TYPE, JSObject::kHeaderSize, - TERMINAL_FAST_ELEMENTS_KIND, 0, roots)); -} - -// This is the same as Factory::NewFixedArray, except it doesn't retry -// on allocation failure. -AllocationResult HeapTester::AllocateFixedArrayForTest( - Heap* heap, uint32_t length, AllocationType allocation) { - DCHECK_LE(length, FixedArray::kMaxLength); - int size = FixedArray::SizeFor(length); - Tagged<HeapObject> obj; - { - AllocationResult result = heap->AllocateRaw(size, allocation); - if (!result.To(&obj)) return result; - } - obj->set_map_after_allocation(heap->isolate(), - ReadOnlyRoots(heap).fixed_array_map(), - SKIP_WRITE_BARRIER); - Tagged<FixedArray> array = Cast<FixedArray>(obj); - array->set_length(length); - MemsetTagged(array->RawFieldOfFirstElement(), - ReadOnlyRoots(heap).undefined_value(), length); - return AllocationResult::FromObject(array); -} - -HEAP_TEST(MarkCompactCollector) { - v8_flags.incremental_marking = false; - v8_flags.retain_maps_for_n_gc = 0; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = CcTest::heap(); - Factory* factory = isolate->factory(); - - v8::HandleScope sc(CcTest::isolate()); - DirectHandle<JSGlobalObject> global(isolate->context()->global_object(), - isolate); - - // call mark-compact when heap is empty - heap::InvokeMajorGC(heap); - - AllocationResult allocation; - if (!v8_flags.single_generation) { - // keep allocating garbage in new space until it fails - const uint32_t arraysize = 100; - do { - allocation = - AllocateFixedArrayForTest(heap, arraysize, AllocationType::kYoung); - } while (!allocation.IsFailure()); - heap::InvokeMinorGC(heap); - AllocateFixedArrayForTest(heap, arraysize, AllocationType::kYoung) - .ToObjectChecked(); - } - - // keep allocating maps until it fails - do { - allocation = AllocateMapForTest(isolate); - } while (!allocation.IsFailure()); - heap::InvokeMajorGC(heap); - AllocateMapForTest(isolate).ToObjectChecked(); - - { HandleScope scope(isolate); - // allocate a garbage - DirectHandle<String> func_name = - factory->InternalizeUtf8String("theFunction"); - DirectHandle<JSFunction> function = - factory->NewFunctionForTesting(func_name); - Object::SetProperty(isolate, global, func_name, function).Check(); - - factory->NewJSObject(function); - } - - heap::InvokeMajorGC(heap); - - { HandleScope scope(isolate); - DirectHandle<String> func_name = - factory->InternalizeUtf8String("theFunction"); - CHECK(Just(true) == JSReceiver::HasOwnProperty(isolate, global, func_name)); - DirectHandle<Object> func_value = - Object::GetProperty(isolate, global, func_name).ToHandleChecked(); - CHECK(IsJSFunction(*func_value)); - DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); - DirectHandle<JSObject> obj = factory->NewJSObject(function); - - DirectHandle<String> obj_name = factory->InternalizeUtf8String("theObject"); - Object::SetProperty(isolate, global, obj_name, obj).Check(); - DirectHandle<String> prop_name = factory->InternalizeUtf8String("theSlot"); - DirectHandle<Smi> twenty_three(Smi::FromInt(23), isolate); - Object::SetProperty(isolate, obj, prop_name, twenty_three).Check(); - } - - heap::InvokeMajorGC(heap); - - { HandleScope scope(isolate); - DirectHandle<String> obj_name = factory->InternalizeUtf8String("theObject"); - CHECK(Just(true) == JSReceiver::HasOwnProperty(isolate, global, obj_name)); - DirectHandle<Object> object = - Object::GetProperty(isolate, global, obj_name).ToHandleChecked(); - CHECK(IsJSObject(*object)); - DirectHandle<String> prop_name = factory->InternalizeUtf8String("theSlot"); - CHECK_EQ(*Object::GetProperty(isolate, Cast<JSObject>(object), prop_name) - .ToHandleChecked(), - Smi::FromInt(23)); - } -} - -HEAP_TEST(DoNotEvacuatePinnedPages) { - if (!v8_flags.compact || !v8_flags.single_generation) return; - - v8_flags.compact_on_every_full_gc = true; - - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - - v8::HandleScope sc(CcTest::isolate()); - Heap* heap = isolate->heap(); - - heap::SealCurrentObjects(heap); - - DirectHandleVector<FixedArray> handles(isolate); - heap::CreatePadding( - heap, static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), - AllocationType::kOld, &handles); - - MemoryChunk* chunk = MemoryChunk::FromHeapObject(*handles.front()); - auto* page = MutablePage::FromHeapObject(isolate, *handles.front()); - - CHECK(heap->InSpace(*handles.front(), OLD_SPACE)); - page->set_is_pinned_for_testing(true); - - heap::InvokeMajorGC(heap); - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - - // The pinned flag should prevent the page from moving. - for (DirectHandle<FixedArray> object : handles) { - CHECK_EQ(chunk, MemoryChunk::FromHeapObject(*object)); - } - - page->set_is_pinned_for_testing(false); - - heap::InvokeMajorGC(heap); - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - - // `compact_on_every_full_gc` ensures that this page is an evacuation - // candidate, so with the pin flag cleared compaction should now move it. - for (DirectHandle<FixedArray> object : handles) { - CHECK_NE(chunk, MemoryChunk::FromHeapObject(*object)); - } -} - -#if defined(__has_feature) -#if __has_feature(address_sanitizer) -#define V8_WITH_ASAN 1 -#endif -#endif - -// Here is a memory use test that uses /proc, and is therefore Linux-only. We -// do not care how much memory the simulator uses, since it is only there for -// debugging purposes. Testing with ASAN doesn't make sense, either. -#if defined(__linux__) && !defined(USE_SIMULATOR) && !defined(V8_WITH_ASAN) - - -static uintptr_t ReadLong(char* buffer, intptr_t* position, int base) { - char* end_address = buffer + *position; - uintptr_t result = strtoul(buffer + *position, &end_address, base); - CHECK(result != ULONG_MAX || errno != ERANGE); - CHECK(end_address > buffer + *position); - *position = end_address - buffer; - return result; -} - - -// The memory use computed this way is not entirely accurate and depends on -// the way malloc allocates memory. That's why the memory use may seem to -// increase even though the sum of the allocated object sizes decreases. It -// also means that the memory use depends on the kernel and stdlib. -static intptr_t MemoryInUse() { - intptr_t memory_use = 0; - - int fd = open("/proc/self/maps", O_RDONLY); - if (fd < 0) return -1; - - const int kBufSize = 20000; - char buffer[kBufSize]; - ssize_t length = read(fd, buffer, kBufSize); - intptr_t line_start = 0; - CHECK_LT(length, kBufSize); // Make the buffer bigger. - CHECK_GT(length, 0); // We have to find some data in the file. - while (line_start < length) { - if (buffer[line_start] == '\n') { - line_start++; - continue; - } - intptr_t position = line_start; - uintptr_t start = ReadLong(buffer, &position, 16); - CHECK_EQ(buffer[position++], '-'); - uintptr_t end = ReadLong(buffer, &position, 16); - CHECK_EQ(buffer[position++], ' '); - CHECK(buffer[position] == '-' || buffer[position] == 'r'); - bool read_permission = (buffer[position++] == 'r'); - CHECK(buffer[position] == '-' || buffer[position] == 'w'); - bool write_permission = (buffer[position++] == 'w'); - CHECK(buffer[position] == '-' || buffer[position] == 'x'); - bool execute_permission = (buffer[position++] == 'x'); - CHECK(buffer[position] == 's' || buffer[position] == 'p'); - bool private_mapping = (buffer[position++] == 'p'); - CHECK_EQ(buffer[position++], ' '); - uintptr_t offset = ReadLong(buffer, &position, 16); - USE(offset); - CHECK_EQ(buffer[position++], ' '); - uintptr_t major = ReadLong(buffer, &position, 16); - USE(major); - CHECK_EQ(buffer[position++], ':'); - uintptr_t minor = ReadLong(buffer, &position, 16); - USE(minor); - CHECK_EQ(buffer[position++], ' '); - uintptr_t inode = ReadLong(buffer, &position, 10); - while (position < length && buffer[position] != '\n') position++; - if ((read_permission || write_permission || execute_permission) && - private_mapping && inode == 0) { - memory_use += (end - start); - } - - line_start = position; - } - close(fd); - return memory_use; -} - - -intptr_t ShortLivingIsolate() { - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - { v8::Isolate::Scope isolate_scope(isolate); - v8::Locker lock(isolate); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = v8::Context::New(isolate); - CHECK(!context.IsEmpty()); - } - isolate->Dispose(); - return MemoryInUse(); -} - -UNINITIALIZED_TEST(RegressJoinThreadsOnIsolateDeinit) { - // Memory is measured, do not allocate in background thread. - v8_flags.stress_concurrent_allocation = false; - intptr_t size_limit = ShortLivingIsolate() * 2; - for (int i = 0; i < 10; i++) { - CHECK_GT(size_limit, ShortLivingIsolate()); - } -} - -TEST(Regress5829) { - if (!v8_flags.incremental_marking) return; - v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - v8::HandleScope sc(CcTest::isolate()); - Heap* heap = isolate->heap(); - heap::SealCurrentObjects(heap); - i::IncrementalMarking* marking = heap->incremental_marking(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - } - CHECK(marking->IsMarking()); - CHECK(marking->black_allocation()); - DirectHandle<FixedArray> array = - isolate->factory()->NewFixedArray(10, AllocationType::kOld); - Address old_end = array->address() + array->Size(); - // Right trim the array without clearing the mark bits. - array->set_length(9); - heap->CreateFillerObjectAt(old_end - kTaggedSize, kTaggedSize); - heap->FreeMainThreadLinearAllocationAreas(); - NormalPage* page = NormalPage::FromAddress(array->address()); - for (auto object_and_size : LiveObjectRange(page)) { - CHECK(!IsFreeSpaceOrFiller(object_and_size.first)); - } -} - -#endif // __linux__ and !USE_SIMULATOR - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-memory-measurement.cc b/deps/v8/test/cctest/heap/test-memory-measurement.cc deleted file mode 100644 index 6f354768140f..000000000000 --- a/deps/v8/test/cctest/heap/test-memory-measurement.cc +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2019 the V8 project 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 "src/heap/memory-measurement-inl.h" -#include "src/heap/memory-measurement.h" -#include "src/objects/smi.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8 { -namespace internal { -namespace heap { - -namespace { -DirectHandle<NativeContext> GetNativeContext( - Isolate* isolate, v8::Local<v8::Context> v8_context) { - DirectHandle<Context> context = v8::Utils::OpenDirectHandle(*v8_context); - return direct_handle(context->native_context(), isolate); -} -} // anonymous namespace - -TEST(NativeContextInferrerGlobalObject) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - HandleScope handle_scope(isolate); - DirectHandle<NativeContext> native_context = - GetNativeContext(isolate, env.local()); - DirectHandle<JSGlobalObject> global(native_context->global_object(), isolate); - NativeContextInferrer inferrer; - Address inferred_context = 0; - CHECK(inferrer.Infer(isolate, global->map(), *global, &inferred_context)); - CHECK_EQ(native_context->ptr(), inferred_context); -} - -TEST(NativeContextInferrerJSFunction) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - HandleScope scope(isolate); - DirectHandle<NativeContext> native_context = - GetNativeContext(isolate, env.local()); - v8::Local<v8::Value> result = CompileRun("(function () { return 1; })"); - DirectHandle<Object> object = Utils::OpenDirectHandle(*result); - DirectHandle<HeapObject> function = Cast<HeapObject>(object); - NativeContextInferrer inferrer; - Address inferred_context = 0; - CHECK(inferrer.Infer(isolate, function->map(), *function, &inferred_context)); - CHECK_EQ(native_context->ptr(), inferred_context); -} - -TEST(NativeContextInferrerJSObject) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - HandleScope scope(isolate); - DirectHandle<NativeContext> native_context = - GetNativeContext(isolate, env.local()); - v8::Local<v8::Value> result = CompileRun("({a : 10})"); - DirectHandle<Object> object = Utils::OpenDirectHandle(*result); - DirectHandle<HeapObject> function = Cast<HeapObject>(object); - NativeContextInferrer inferrer; - Address inferred_context = 0; - CHECK(inferrer.Infer(isolate, function->map(), *function, &inferred_context)); - CHECK_EQ(native_context->ptr(), inferred_context); -} - -TEST(NativeContextStatsMerge) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - HandleScope scope(isolate); - DirectHandle<NativeContext> native_context = - GetNativeContext(isolate, env.local()); - v8::Local<v8::Value> result = CompileRun("({a : 10})"); - DirectHandle<HeapObject> object = - Cast<HeapObject>(Utils::OpenDirectHandle(*result)); - NativeContextStats stats1, stats2; - stats1.IncrementSize(native_context->ptr(), object->map(), *object, 10); - stats2.IncrementSize(native_context->ptr(), object->map(), *object, 20); - stats1.Merge(stats2); - CHECK_EQ(30, stats1.Get(native_context->ptr())); -} - -TEST(NativeContextStatsArrayBuffers) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - HandleScope scope(isolate); - DirectHandle<NativeContext> native_context = - GetNativeContext(isolate, env.local()); - v8::Local<v8::ArrayBuffer> array_buffer = - v8::ArrayBuffer::New(CcTest::isolate(), 1000); - DirectHandle<JSArrayBuffer> i_array_buffer = - Utils::OpenDirectHandle(*array_buffer); - NativeContextStats stats; - stats.IncrementSize(native_context->ptr(), i_array_buffer->map(), - *i_array_buffer, 10); - CHECK_EQ(1010, stats.Get(native_context->ptr())); -} - -namespace { - -class TestResource : public v8::String::ExternalStringResource { - public: - explicit TestResource(uint16_t* data) : data_(data), length_(0) { - while (data[length_]) ++length_; - } - - ~TestResource() override { i::DeleteArray(data_); } - - const uint16_t* data() const override { return data_; } - - size_t length() const override { return length_; } - - private: - uint16_t* data_; - size_t length_; -}; - -} // anonymous namespace - -TEST(NativeContextStatsExternalString) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - HandleScope scope(isolate); - DirectHandle<NativeContext> native_context = - GetNativeContext(isolate, env.local()); - const char* c_source = "0123456789"; - uint16_t* two_byte_source = AsciiToTwoByteString(c_source); - TestResource* resource = new TestResource(two_byte_source); - Local<v8::String> string = - v8::String::NewExternalTwoByte(CcTest::isolate(), resource) - .ToLocalChecked(); - DirectHandle<String> i_string = Utils::OpenDirectHandle(*string); - NativeContextStats stats; - stats.IncrementSize(native_context->ptr(), i_string->map(), *i_string, 10); - CHECK_EQ(10 + 10 * 2, stats.Get(native_context->ptr())); -} - -namespace { - -class MockMeasureMemoryDelegate : public v8::MeasureMemoryDelegate { - public: - bool ShouldMeasure(v8::Local<v8::Context> context) override { return true; } - - void MeasurementComplete(Result result) override { - // Empty. - } -}; - -} // namespace - -TEST_WITH_PLATFORM(RandomizedTimeout, MockPlatform) { - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = CcTest::isolate(); - std::vector<double> delays; - for (int i = 0; i < 10; i++) { - isolate->MeasureMemory(std::make_unique<MockMeasureMemoryDelegate>()); - delays.push_back(platform.Delay()); - platform.PerformTask(); - } - std::sort(delays.begin(), delays.end()); - CHECK_LT(delays[0], delays.back()); -} - -TEST(LazyMemoryMeasurement) { - CcTest::InitializeVM(); - MockPlatform platform; - CcTest::isolate()->MeasureMemory( - std::make_unique<MockMeasureMemoryDelegate>(), - v8::MeasureMemoryExecution::kLazy); - CHECK(!platform.PendingTask()); -} - -TEST(PartiallyInitializedJSFunction) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - HandleScope scope(isolate); - DirectHandle<JSFunction> js_function = factory->NewFunctionForTesting( - factory->NewStringFromAsciiChecked("test")); - DirectHandle<Context> context(js_function->context(), isolate); - - // 1. Start simulating deserializaiton. - isolate->RegisterDeserializerStarted(); - // 2. Set the context field to the uninitialized sentintel. - TaggedField<Object, offsetof(JSFunction, context_)>::store( - *js_function, Smi::uninitialized_deserialization_value()); - // 3. Request memory measurement and run all tasks. GC that runs as part - // of the measurement should not crash. - CcTest::isolate()->MeasureMemory( - std::make_unique<MockMeasureMemoryDelegate>(), - v8::MeasureMemoryExecution::kEager); - while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(), - CcTest::isolate())) { - } - // 4. Restore the value and complete deserialization. - TaggedField<Object, offsetof(JSFunction, context_)>::store(*js_function, - *context); - isolate->RegisterDeserializerFinished(); -} - -TEST(PartiallyInitializedContext) { - LocalContext env; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - HandleScope scope(isolate); - DirectHandle<ScopeInfo> scope_info = - factory->global_this_binding_scope_info(); - DirectHandle<Context> context = factory->NewScriptContext( - GetNativeContext(isolate, env.local()), scope_info); - DirectHandle<Map> map(context->map(), isolate); - DirectHandle<NativeContext> native_context(map->native_context(), isolate); - // 1. Start simulating deserializaiton. - isolate->RegisterDeserializerStarted(); - // 2. Set the native context field to the uninitialized sentintel. - TaggedField<Object, - offsetof(Map, constructor_or_back_pointer_or_native_context_)>:: - store(*map, Smi::uninitialized_deserialization_value()); - // 3. Request memory measurement and run all tasks. GC that runs as part - // of the measurement should not crash. - CcTest::isolate()->MeasureMemory( - std::make_unique<MockMeasureMemoryDelegate>(), - v8::MeasureMemoryExecution::kEager); - while (v8::platform::PumpMessageLoop(v8::internal::V8::GetCurrentPlatform(), - CcTest::isolate())) { - } - // 4. Restore the value and complete deserialization. - TaggedField<Object, - offsetof(Map, constructor_or_back_pointer_or_native_context_)>:: - store(*map, *native_context); - isolate->RegisterDeserializerFinished(); -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-pool.cc b/deps/v8/test/cctest/heap/test-pool.cc deleted file mode 100644 index 9379b3e3c1cc..000000000000 --- a/deps/v8/test/cctest/heap/test-pool.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018 the V8 project 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 <vector> - -#include "src/heap/heap.h" -#include "src/heap/memory-allocator.h" -#include "src/init/v8.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" - -using v8::IdleTask; -using v8::Task; -using v8::Isolate; - -namespace v8 { -namespace internal { -namespace heap { - -class MockPlatformForPool : public TestPlatform { - public: - ~MockPlatformForPool() override { - for (auto& task : worker_tasks_) { - CcTest::default_platform()->PostTaskOnWorkerThread( - TaskPriority::kUserVisible, std::move(task)); - } - worker_tasks_.clear(); - } - - void PostTaskOnWorkerThreadImpl(TaskPriority priority, - std::unique_ptr<Task> task, - const SourceLocation& location) override { - worker_tasks_.push_back(std::move(task)); - } - - bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; } - - private: - std::vector<std::unique_ptr<Task>> worker_tasks_; -}; - -UNINITIALIZED_TEST(EagerDiscardingInCollectAllAvailableGarbage) { - v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. - MockPlatformForPool platform; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> context = CcTest::NewContext(isolate); - v8::Context::Scope context_scope(context); - Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - i::heap::SimulateFullSpace(heap->old_space()); - i::heap::InvokeMemoryReducingMajorGCs(heap); - CHECK_EQ(0, heap->memory_allocator()->GetPooledChunksCount()); - } - isolate->Dispose(); -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-spaces.cc b/deps/v8/test/cctest/heap/test-spaces.cc deleted file mode 100644 index 6e85614a5190..000000000000 --- a/deps/v8/test/cctest/heap/test-spaces.cc +++ /dev/null @@ -1,826 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <stdlib.h> - -#include <memory> - -#include "include/v8-initialization.h" -#include "include/v8-platform.h" -#include "src/base/bounded-page-allocator.h" -#include "src/base/macros.h" -#include "src/base/platform/platform.h" -#include "src/base/strong-alias.h" -#include "src/common/globals.h" -#include "src/heap/allocation-result.h" -#include "src/heap/factory.h" -#include "src/heap/heap.h" -#include "src/heap/large-spaces.h" -#include "src/heap/main-allocator.h" -#include "src/heap/memory-allocator.h" -#include "src/heap/memory-pool.h" -#include "src/heap/mutable-page.h" -#include "src/heap/spaces-inl.h" -#include "src/heap/spaces.h" -#include "src/objects/free-space.h" -#include "src/objects/objects-inl.h" -#include "src/snapshot/snapshot.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8 { -namespace internal { -namespace heap { - -// Temporarily sets a given allocator in an isolate. -class V8_NODISCARD TestMemoryAllocatorScope { - public: - TestMemoryAllocatorScope(Isolate* isolate, size_t max_capacity, - PageAllocator* page_allocator = nullptr) - : isolate_(isolate), - old_allocator_(std::move(isolate->heap()->memory_allocator_)) { - // Save the code pages for restoring them later on because the constructor - // of MemoryAllocator will change them. - isolate->GetCodePages()->swap(code_pages_); - isolate->heap()->memory_allocator_.reset(new MemoryAllocator( - isolate, - page_allocator != nullptr ? page_allocator : isolate->page_allocator(), - page_allocator != nullptr ? page_allocator : isolate->page_allocator(), - isolate->isolate_group()->memory_pool(), max_capacity)); - if (page_allocator != nullptr) { - isolate->heap()->memory_allocator_->data_page_allocator_ = page_allocator; - } - } - - MemoryAllocator* allocator() { return isolate_->heap()->memory_allocator(); } - - ~TestMemoryAllocatorScope() { - isolate_->heap()->memory_allocator()->ReleasePooledChunksImmediately(); - isolate_->heap()->memory_allocator()->TearDown(); - isolate_->heap()->memory_allocator_.swap(old_allocator_); - isolate_->GetCodePages()->swap(code_pages_); - } - - TestMemoryAllocatorScope(const TestMemoryAllocatorScope&) = delete; - TestMemoryAllocatorScope& operator=(const TestMemoryAllocatorScope&) = delete; - - private: - Isolate* isolate_; - std::unique_ptr<MemoryAllocator> old_allocator_; - std::vector<MemoryRange> code_pages_; -}; - -// Temporarily sets a given code page allocator in an isolate. -class V8_NODISCARD TestCodePageAllocatorScope { - public: - TestCodePageAllocatorScope(Isolate* isolate, - v8::PageAllocator* code_page_allocator) - : isolate_(isolate), - old_code_page_allocator_( - isolate->heap()->memory_allocator()->code_page_allocator()) { - isolate->heap()->memory_allocator()->code_page_allocator_ = - code_page_allocator; - } - - ~TestCodePageAllocatorScope() { - isolate_->heap()->memory_allocator()->code_page_allocator_ = - old_code_page_allocator_; - } - TestCodePageAllocatorScope(const TestCodePageAllocatorScope&) = delete; - TestCodePageAllocatorScope& operator=(const TestCodePageAllocatorScope&) = - delete; - - private: - Isolate* isolate_; - v8::PageAllocator* old_code_page_allocator_; -}; - -static void VerifyMemoryChunk(Isolate* isolate, Heap* heap, - v8::PageAllocator* code_page_allocator, - size_t area_size, Executability executable, - PageSize page_size, LargeObjectSpace* space) { - TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); - MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); - TestCodePageAllocatorScope test_code_page_allocator_scope( - isolate, code_page_allocator); - - v8::PageAllocator* page_allocator = - memory_allocator->page_allocator(space->identity()); - - size_t allocatable_memory_area_offset = - MemoryChunkLayout::ObjectStartOffsetInMemoryChunk(space->identity()); - - MutablePage* memory_chunk = memory_allocator->AllocateLargePage( - space, area_size, executable, AllocationHint()); - size_t reserved_size = - ((executable == EXECUTABLE)) - ? RoundUp(allocatable_memory_area_offset + - RoundUp(area_size, page_allocator->CommitPageSize()), - page_allocator->CommitPageSize()) - : RoundUp(allocatable_memory_area_offset + area_size, - page_allocator->CommitPageSize()); - CHECK(memory_chunk->size() == reserved_size); - CHECK(memory_chunk->area_start() < - memory_chunk->ChunkAddress() + memory_chunk->size()); - CHECK(memory_chunk->area_end() <= - memory_chunk->ChunkAddress() + memory_chunk->size()); - CHECK(static_cast<size_t>(memory_chunk->area_size()) == area_size); - - memory_allocator->Free(MemoryAllocator::FreeMode::kImmediately, memory_chunk); -} - -static unsigned int PseudorandomAreaSize() { - static uint32_t lo = 2345; - lo = 18273 * (lo & 0xFFFFF) + (lo >> 16); - return lo & 0xFFFFF; -} - -TEST(MutablePage) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - IsolateSafepointScope safepoint(heap); - - v8::PageAllocator* page_allocator = GetPlatformPageAllocator(); - size_t area_size; - - for (int i = 0; i < 100; i++) { - area_size = - RoundUp(PseudorandomAreaSize(), page_allocator->CommitPageSize()); - - const size_t code_range_size = 32 * MB; -#ifdef V8_ENABLE_SANDBOX - // When the sandbox is enabled, the code assumes that there's only a single - // code range for easy metadata lookup, so use the process wide code range - // in this case. - CodeRange* code_range = - IsolateGroup::current()->EnsureCodeRange(code_range_size); - base::BoundedPageAllocator* bounded_page_allocator = - code_range->page_allocator(); -#else - // With CodeRange. - bool jitless = isolate->jitless(); - VirtualMemory code_range_reservation( - page_allocator, code_range_size, PageAllocator::AllocationHint(), - MemoryChunk::GetAlignmentForAllocation(), - jitless ? PageAllocator::Permission::kNoAccess - : PageAllocator::Permission::kNoAccessWillJitLater); - - base::PageInitializationMode page_initialization_mode = - base::PageInitializationMode::kAllocatedPagesCanBeUninitialized; - base::PageFreeingMode page_freeing_mode = - base::PageFreeingMode::kMakeInaccessible; - - if (!jitless) { - page_initialization_mode = base::PageInitializationMode::kRecommitOnly; - page_freeing_mode = base::PageFreeingMode::kDiscard; - void* base = reinterpret_cast<void*>(code_range_reservation.address()); - CHECK(page_allocator->SetPermissions(base, code_range_size, - PageAllocator::kReadWriteExecute)); - CHECK(page_allocator->DiscardSystemPages(base, code_range_size)); - } - - CHECK(code_range_reservation.IsReserved()); - - base::BoundedPageAllocator code_page_allocator( - page_allocator, code_range_reservation.address(), - code_range_reservation.size(), MemoryChunk::GetAlignmentForAllocation(), - page_initialization_mode, page_freeing_mode); - base::BoundedPageAllocator* bounded_page_allocator = &code_page_allocator; -#endif - - VerifyMemoryChunk(isolate, heap, bounded_page_allocator, area_size, - EXECUTABLE, PageSize::kLarge, heap->code_lo_space()); - - VerifyMemoryChunk(isolate, heap, bounded_page_allocator, area_size, - NOT_EXECUTABLE, PageSize::kLarge, heap->lo_space()); - } -} - -TEST(MemoryAllocator) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); - MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); - - int total_pages = 0; - OldSpace faked_space(heap); - CHECK(!faked_space.first_page()); - CHECK(!faked_space.last_page()); - NormalPage* first_page = memory_allocator->AllocatePage( - MemoryAllocator::AllocationMode::kRegular, - static_cast<PagedSpace*>(&faked_space), NOT_EXECUTABLE); - - faked_space.memory_chunk_list().PushBack(first_page); - CHECK(first_page->next_page() == nullptr); - total_pages++; - - for (NormalPage* p = first_page; p != nullptr; p = p->next_page()) { - CHECK(p->owner() == &faked_space); - } - - // Again, we should get n or n - 1 pages. - NormalPage* other = memory_allocator->AllocatePage( - MemoryAllocator::AllocationMode::kRegular, - static_cast<PagedSpace*>(&faked_space), NOT_EXECUTABLE); - total_pages++; - faked_space.memory_chunk_list().PushBack(other); - int page_count = 0; - for (NormalPage* p = first_page; p != nullptr; p = p->next_page()) { - CHECK(p->owner() == &faked_space); - page_count++; - } - CHECK(total_pages == page_count); - - NormalPage* second_page = first_page->next_page(); - CHECK_NOT_NULL(second_page); - - // OldSpace's destructor will tear down the space and free up all pages. -} - -TEST(ComputeDiscardMemoryAreas) { - std::optional<base::AddressRegion> discard_area; - size_t page_size = MemoryAllocator::GetCommitPageSize(); - - discard_area = Sweeper::ComputeDiscardMemoryArea(0, 0); - CHECK(!discard_area); - - discard_area = Sweeper::ComputeDiscardMemoryArea(0, page_size); - CHECK_EQ(discard_area->begin(), 0); - CHECK_EQ(discard_area->size(), page_size); - - discard_area = Sweeper::ComputeDiscardMemoryArea(page_size, 2 * page_size); - CHECK_EQ(discard_area->begin(), page_size); - CHECK_EQ(discard_area->size(), page_size); - - discard_area = - Sweeper::ComputeDiscardMemoryArea(page_size - kTaggedSize, 2 * page_size); - CHECK_EQ(discard_area->begin(), page_size); - CHECK_EQ(discard_area->size(), page_size); - - discard_area = - Sweeper::ComputeDiscardMemoryArea(page_size, 2 * page_size + kTaggedSize); - CHECK_EQ(discard_area->begin(), page_size); - CHECK_EQ(discard_area->size(), page_size); - - discard_area = Sweeper::ComputeDiscardMemoryArea(page_size, page_size); - CHECK(!discard_area); - - discard_area = Sweeper::ComputeDiscardMemoryArea(page_size / 2, - page_size + page_size / 2); - CHECK(!discard_area); - - discard_area = Sweeper::ComputeDiscardMemoryArea(page_size / 2, - page_size + page_size / 4); - CHECK(!discard_area); - - discard_area = - Sweeper::ComputeDiscardMemoryArea(page_size / 2, page_size * 3); - CHECK_EQ(discard_area->begin(), page_size); - CHECK_EQ(discard_area->size(), page_size * 2); -} - -TEST(SemiSpaceNewSpace) { - if (v8_flags.single_generation) return; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); - MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); - LinearAllocationArea allocation_info; - - auto new_space = std::make_unique<SemiSpaceNewSpace>( - heap, heap->InitialSemiSpaceSize(), heap->InitialSemiSpaceSize(), - heap->InitialSemiSpaceSize()); - MainAllocator allocator(heap->main_thread_local_heap(), new_space.get(), - MainAllocator::kNewGeneration, &allocation_info); - CHECK(new_space->MaximumCapacity()); - - size_t successful_allocations = 0; - while (new_space->Available() >= kMaxRegularHeapObjectSize) { - AllocationResult allocation = allocator.AllocateRaw( - SafeHeapObjectSize(kMaxRegularHeapObjectSize), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - if (allocation.IsFailure()) break; - successful_allocations++; - Tagged<Object> obj = allocation.ToObjectChecked(); - Tagged<HeapObject> ho = Cast<HeapObject>(obj); - CHECK(new_space->Contains(ho)); - } - CHECK_LT(0, successful_allocations); - - new_space.reset(); - memory_allocator->ReleasePooledChunksImmediately(); -} - -TEST(PagedNewSpace) { - if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); - MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); - LinearAllocationArea allocation_info; - - auto new_space = std::make_unique<PagedNewSpace>( - heap, heap->InitialSemiSpaceSize(), heap->InitialSemiSpaceSize(), - heap->InitialSemiSpaceSize()); - MainAllocator allocator(heap->main_thread_local_heap(), new_space.get(), - MainAllocator::kNewGeneration, &allocation_info); - GrowNewSpaceToMaximumCapacity(heap); - - size_t successful_allocations = 0; - while (true) { - AllocationResult allocation = allocator.AllocateRaw( - SafeHeapObjectSize(kMaxRegularHeapObjectSize), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - if (allocation.IsFailure()) break; - successful_allocations++; - Tagged<Object> obj = allocation.ToObjectChecked(); - Tagged<HeapObject> ho = Cast<HeapObject>(obj); - CHECK(new_space->Contains(ho)); - } - CHECK_LT(0, successful_allocations); - - new_space.reset(); - memory_allocator->ReleasePooledChunksImmediately(); -} - -TEST(OldSpace) { - v8_flags.max_heap_size = 20; - // This test uses its own old space, which confuses the incremental marker. - v8_flags.incremental_marking = false; - // This test doesn't expect GCs caused by concurrent allocations in the - // background thread. - v8_flags.stress_concurrent_allocation = false; - - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); - LinearAllocationArea allocation_info; - - auto old_space = std::make_unique<OldSpace>(heap); - MainAllocator allocator(heap->main_thread_local_heap(), old_space.get(), - MainAllocator::kOldGeneration, &allocation_info); - const int obj_size = kMaxRegularHeapObjectSize; - - size_t successful_allocations = 0; - - while (true) { - AllocationResult allocation = - allocator.AllocateRaw(SafeHeapObjectSize(obj_size), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - if (allocation.IsFailure()) break; - successful_allocations++; - Tagged<Object> obj = allocation.ToObjectChecked(); - Tagged<HeapObject> ho = Cast<HeapObject>(obj); - CHECK(old_space->Contains(ho)); - } - CHECK_LT(0, successful_allocations); -} - -TEST(OldLargeObjectSpace) { - v8_flags.max_heap_size = 20; - // This test uses its own old large object space, which confuses the - // incremental marker. - v8_flags.incremental_marking = false; - // This test doesn't expect GCs caused by concurrent allocations in the - // background thread. - v8_flags.stress_concurrent_allocation = false; - - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - auto lo = std::make_unique<OldLargeObjectSpace>(heap); - const int lo_size = NormalPage::kPageSize; - - HandleScope handle_scope(isolate); - Tagged<Map> map = ReadOnlyRoots(isolate).fixed_double_array_map(); - size_t successful_allocations = 0; - - while (true) { - AllocationResult allocation = lo->AllocateRaw( - heap->main_thread_local_heap(), lo_size, AllocationHint()); - if (allocation.IsFailure()) break; - successful_allocations++; - Tagged<Object> obj = allocation.ToObjectChecked(); - CHECK(IsHeapObject(obj)); - Tagged<HeapObject> ho = Cast<HeapObject>(obj); - CHECK(lo->Contains(ho)); - CHECK_EQ(0, MainAllocator::GetFillToAlign(ho.address(), kTaggedAligned)); - // All large objects have the same alignment because they start at the - // same offset within a page. Fixed double arrays have the most strict - // alignment requirements. - CHECK_EQ(0, MainAllocator::GetFillToAlign( - ho.address(), - HeapObject::RequiredAlignment(lo->identity(), map))); - DirectHandle<HeapObject> keep_alive(ho, isolate); - } - CHECK_LT(0, successful_allocations); - - CHECK(!lo->IsEmpty()); - CHECK( - lo->AllocateRaw(heap->main_thread_local_heap(), lo_size, AllocationHint()) - .IsFailure()); -} - -#ifndef DEBUG -// The test verifies that committed size of a space is less then some threshold. -// Debug builds pull in all sorts of additional instrumentation that increases -// heap sizes. E.g. CSA_DCHECK creates on-heap strings for error messages. These -// messages are also not stable if files are moved and modified during the build -// process (jumbo builds). -TEST(SizeOfInitialHeap) { - ManualGCScope manual_gc_scope; - // Bootstrapping without a snapshot causes more allocations. - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - if (!isolate->snapshot_available()) return; - HandleScope scope(isolate); - v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); - // Skip this test on the custom snapshot builder. - if (!CcTest::global() - ->Get(context, v8_str("assertEquals")) - .ToLocalChecked() - ->IsUndefined()) { - return; - } - // Initial size of LO_SPACE - size_t initial_lo_space = isolate->heap()->lo_space()->Size(); - -// The limit for each space for an empty isolate containing just the -// snapshot. -// In PPC the page size is 64K, causing more internal fragmentation -// hence requiring a larger limit. -#if V8_OS_LINUX && V8_HOST_ARCH_PPC64 - const size_t kMaxInitialSizePerSpace = 3 * MB; -#else - const size_t kMaxInitialSizePerSpace = 2 * MB; -#endif - - // Freshly initialized VM gets by with the snapshot size (which is below - // kMaxInitialSizePerSpace per space). - Heap* heap = isolate->heap(); - for (int i = FIRST_GROWABLE_PAGED_SPACE; i <= LAST_GROWABLE_PAGED_SPACE; - i++) { - if (!heap->paged_space(i)) continue; - - // Debug code can be very large, so skip CODE_SPACE if we are generating it. - if (i == CODE_SPACE && i::v8_flags.debug_code) continue; - - // Check that the initial heap is also below the limit. - CHECK_LE(heap->paged_space(i)->CommittedMemory(), kMaxInitialSizePerSpace); - } - - CompileRun("/*empty*/"); - - // No large objects required to perform the above steps. - CHECK_EQ(initial_lo_space, - static_cast<size_t>(isolate->heap()->lo_space()->Size())); -} -#endif // DEBUG - -class Observer : public AllocationObserver { - public: - explicit Observer(intptr_t step_size) - : AllocationObserver(step_size), count_(0) {} - - void Step(int bytes_allocated, Address addr, size_t) override { count_++; } - - int count() const { return count_; } - - private: - int count_; -}; - -HEAP_TEST(Regress777177) { - v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - HandleScope scope(isolate); - OldSpace* old_space = heap->old_space(); - MainAllocator* old_space_allocator = heap->allocator()->old_space_allocator(); - Observer observer(128); - old_space_allocator->FreeLinearAllocationArea(); - old_space_allocator->AddAllocationObserver(&observer); - - int area_size = old_space->AreaSize(); - int max_object_size = kMaxRegularHeapObjectSize; - int filler_size = area_size - max_object_size; - - { - // Ensure a new linear allocation area on a fresh page. - AlwaysAllocateScopeForTesting always_allocate(heap); - heap::SimulateFullSpace(old_space); - AllocationResult result = old_space_allocator->AllocateRaw( - SafeHeapObjectSize(filler_size), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - Tagged<HeapObject> obj = result.ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), filler_size); - } - - { - // Allocate all bytes of the linear allocation area. This moves top_ and - // top_on_previous_step_ to the next page. - AllocationResult result = old_space_allocator->AllocateRaw( - SafeHeapObjectSize(max_object_size), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - Tagged<HeapObject> obj = result.ToObjectChecked(); - // Simulate allocation folding moving the top pointer back. - old_space_allocator->ResetLab( - obj.address(), heap->allocator()->old_space_allocator()->limit(), - heap->allocator()->old_space_allocator()->limit()); - } - - { - // This triggers assert in crbug.com/777177. - AllocationResult result = old_space_allocator->AllocateRaw( - SafeHeapObjectSize(filler_size), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - Tagged<HeapObject> obj = result.ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), filler_size); - } - old_space_allocator->RemoveAllocationObserver(&observer); -} - -HEAP_TEST(Regress791582) { - if (v8_flags.single_generation) return; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - HandleScope scope(isolate); - MainAllocator* new_space_allocator = heap->allocator()->new_space_allocator(); - GrowNewSpaceToMaximumCapacity(heap); - - int until_page_end = - static_cast<int>(heap->NewSpaceLimit() - heap->NewSpaceTop()); - - if (!IsAligned(until_page_end, kTaggedSize)) { - // The test works if the size of allocation area size is a multiple of - // pointer size. This is usually the case unless some allocation observer - // is already active (e.g. incremental marking observer). - return; - } - - Observer observer(128); - new_space_allocator->FreeLinearAllocationArea(); - new_space_allocator->AddAllocationObserver(&observer); - - { - AllocationResult result = new_space_allocator->AllocateRaw( - SafeHeapObjectSize(until_page_end), kTaggedAligned, - AllocationOrigin::kRuntime, AllocationHint()); - Tagged<HeapObject> obj = result.ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), until_page_end); - // Simulate allocation folding moving the top pointer back. - LinearAllocationArea* new_space = - &isolate->isolate_data()->new_allocation_info(); - *new_space->top_address() = obj.address(); - } - - { - // This triggers assert in crbug.com/791582 - AllocationResult result = new_space_allocator->AllocateRaw( - SafeHeapObjectSize(256), kTaggedAligned, AllocationOrigin::kRuntime, - AllocationHint()); - Tagged<HeapObject> obj = result.ToObjectChecked(); - heap->CreateFillerObjectAt(obj.address(), 256); - } - new_space_allocator->RemoveAllocationObserver(&observer); -} - -namespace { -// PageAllocator that always fails. -class FailingPageAllocator : public v8::PageAllocator { - public: - size_t AllocatePageSize() override { return 1024; } - size_t CommitPageSize() override { return 1024; } - void SetRandomMmapSeed(int64_t seed) override {} - void* GetRandomMmapAddr() override { return nullptr; } - void* AllocatePages(void* address, size_t length, size_t alignment, - Permission permissions) override { - return nullptr; - } - bool FreePages(void* address, size_t length) override { return false; } - bool ReleasePages(void* address, size_t length, size_t new_length) override { - return false; - } - bool SetPermissions(void* address, size_t length, - Permission permissions) override { - return false; - } - bool RecommitPages(void* address, size_t length, - Permission permissions) override { - return false; - } - bool DecommitPages(void* address, size_t length) override { return false; } - bool SealPages(void* address, size_t length) override { return false; } -}; -} // namespace - -TEST(NoMemoryForNewPage) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - // Memory allocator that will fail to allocate any pages. - FailingPageAllocator failing_allocator; - TestMemoryAllocatorScope test_allocator_scope(isolate, 0, &failing_allocator); - MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); - OldSpace faked_space(heap); - NormalPage* page = memory_allocator->AllocatePage( - MemoryAllocator::AllocationMode::kRegular, - static_cast<PagedSpace*>(&faked_space), NOT_EXECUTABLE); - - CHECK_NULL(page); -} - -namespace { -// ReadOnlySpace cannot be torn down by a destructor because the destructor -// cannot take an argument. Since these tests create ReadOnlySpaces not attached -// to the Heap directly, they need to be destroyed to ensure the -// MemoryAllocator's stats are all 0 at exit. -class V8_NODISCARD ReadOnlySpaceScope { - public: - explicit ReadOnlySpaceScope(Heap* heap) : ro_space_(heap) {} - ~ReadOnlySpaceScope() { - ro_space_.TearDown(CcTest::heap()->memory_allocator()); - } - - ReadOnlySpace* space() { return &ro_space_; } - - private: - ReadOnlySpace ro_space_; -}; -} // namespace - -TEST(ReadOnlySpaceMetrics_OnePage) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - // Create a read-only space and allocate some memory, shrink the pages and - // check the allocated object size is as expected. - - ReadOnlySpaceScope scope(heap); - ReadOnlySpace* faked_space = scope.space(); - - // Initially no memory. - CHECK_EQ(faked_space->Size(), 0); - CHECK_EQ(faked_space->Capacity(), 0); - CHECK_EQ(faked_space->CommittedMemory(), 0); - CHECK_EQ(faked_space->CommittedPhysicalMemory(), 0); - - faked_space->AllocateRaw(16, kTaggedAligned); - - faked_space->ShrinkPages(); - faked_space->Seal(ReadOnlySpace::SealMode::kDoNotDetachFromHeap); - - // Allocated objects size. - CHECK_EQ(faked_space->Size(), 16); - - size_t committed_memory = RoundUp( - MemoryChunkLayout::ObjectStartOffsetInDataPage() + faked_space->Size(), - MemoryAllocator::GetCommitPageSize()); - - // Amount of OS allocated memory. - CHECK_EQ(faked_space->CommittedMemory(), committed_memory); - CHECK_EQ(faked_space->CommittedPhysicalMemory(), committed_memory); - - // Capacity will be one OS page minus the page header. - CHECK_EQ(faked_space->Capacity(), - committed_memory - MemoryChunkLayout::ObjectStartOffsetInDataPage()); -} - -TEST(ReadOnlySpaceMetrics_AlignedAllocations) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - // Create a read-only space and allocate some memory, shrink the pages and - // check the allocated object size is as expected. - - ReadOnlySpaceScope scope(heap); - ReadOnlySpace* faked_space = scope.space(); - - // Initially no memory. - CHECK_EQ(faked_space->Size(), 0); - CHECK_EQ(faked_space->Capacity(), 0); - CHECK_EQ(faked_space->CommittedMemory(), 0); - CHECK_EQ(faked_space->CommittedPhysicalMemory(), 0); - - // Allocate an object just under an OS page in size. - int object_size = - static_cast<int>(MemoryAllocator::GetCommitPageSize() - kApiTaggedSize); - - const int kExpectedAlignment = kDoubleSize; - - Tagged<HeapObject> object = - faked_space->AllocateRaw(object_size, kDoubleAligned).ToObjectChecked(); - CHECK_EQ(object.address() % kExpectedAlignment, 0); - object = - faked_space->AllocateRaw(object_size, kDoubleAligned).ToObjectChecked(); - CHECK_EQ(object.address() % kExpectedAlignment, 0); - - // Calculate size of allocations based on area_start. - Address area_start = faked_space->pages().back()->GetAreaStart(); - Address top = RoundUp(area_start, kExpectedAlignment) + object_size; - top = RoundUp(top, kExpectedAlignment) + object_size; - size_t expected_size = top - area_start; - - faked_space->ShrinkPages(); - faked_space->Seal(ReadOnlySpace::SealMode::kDoNotDetachFromHeap); - - // Allocated objects size may will contain 4 bytes of padding on 32-bit or - // with pointer compression. - CHECK_EQ(faked_space->Size(), expected_size); - - size_t committed_memory = RoundUp( - MemoryChunkLayout::ObjectStartOffsetInDataPage() + faked_space->Size(), - MemoryAllocator::GetCommitPageSize()); - - CHECK_EQ(faked_space->CommittedMemory(), committed_memory); - CHECK_EQ(faked_space->CommittedPhysicalMemory(), committed_memory); - - // Capacity will be 3 OS pages minus the page header. - CHECK_EQ(faked_space->Capacity(), - committed_memory - MemoryChunkLayout::ObjectStartOffsetInDataPage()); -} - -TEST(ReadOnlySpaceMetrics_TwoPages) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - // Create a read-only space and allocate some memory, shrink the pages and - // check the allocated object size is as expected. - - ReadOnlySpaceScope scope(heap); - ReadOnlySpace* faked_space = scope.space(); - - // Initially no memory. - CHECK_EQ(faked_space->Size(), 0); - CHECK_EQ(faked_space->Capacity(), 0); - CHECK_EQ(faked_space->CommittedMemory(), 0); - CHECK_EQ(faked_space->CommittedPhysicalMemory(), 0); - - // Allocate an object that's too big to have more than one on a page. - - int object_size = RoundUp( - static_cast<int>( - MemoryChunkLayout::AllocatableMemoryInMemoryChunk(RO_SPACE) / 2 + 16), - kTaggedSize); - CHECK_GT(object_size * 2, - MemoryChunkLayout::AllocatableMemoryInMemoryChunk(RO_SPACE)); - faked_space->AllocateRaw(object_size, kTaggedAligned); - - // Then allocate another so it expands the space to two pages. - faked_space->AllocateRaw(object_size, kTaggedAligned); - - faked_space->ShrinkPages(); - faked_space->Seal(ReadOnlySpace::SealMode::kDoNotDetachFromHeap); - - // Allocated objects size. - CHECK_EQ(faked_space->Size(), object_size * 2); - - // Amount of OS allocated memory. - size_t committed_memory_per_page = - RoundUp(MemoryChunkLayout::ObjectStartOffsetInDataPage() + object_size, - MemoryAllocator::GetCommitPageSize()); - CHECK_EQ(faked_space->CommittedMemory(), 2 * committed_memory_per_page); - CHECK_EQ(faked_space->CommittedPhysicalMemory(), - 2 * committed_memory_per_page); - - // Capacity will be the space up to the amount of committed memory minus the - // page headers. - size_t capacity_per_page = - RoundUp(MemoryChunkLayout::ObjectStartOffsetInDataPage() + object_size, - MemoryAllocator::GetCommitPageSize()) - - MemoryChunkLayout::ObjectStartOffsetInDataPage(); - CHECK_EQ(faked_space->Capacity(), 2 * capacity_per_page); -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-write-barrier.cc b/deps/v8/test/cctest/heap/test-write-barrier.cc deleted file mode 100644 index 258a67083e0c..000000000000 --- a/deps/v8/test/cctest/heap/test-write-barrier.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015 the V8 project 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 "src/heap/incremental-marking.h" -#include "src/heap/mark-compact.h" -#include "src/heap/marking-state-inl.h" -#include "src/heap/spaces.h" -#include "src/objects/js-array-buffer-inl.h" -#include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" - -namespace v8 { -namespace internal { -namespace heap { - -HEAP_TEST(WriteBarrier_Marking) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope outer(isolate); - DirectHandle<FixedArray> objects = factory->NewFixedArray(3); - v8::Global<Value> global_objects(CcTest::isolate(), Utils::ToLocal(objects)); - { - // Make sure that these objects are not immediately reachable from - // the roots to prevent them being marked grey at the start of marking. - HandleScope inner(isolate); - DirectHandle<FixedArray> host = factory->NewFixedArray(1); - DirectHandle<HeapNumber> value1 = factory->NewHeapNumber(1.1); - DirectHandle<HeapNumber> value2 = factory->NewHeapNumber(1.2); - objects->set(0, *host); - objects->set(1, *value1); - objects->set(2, *value2); - } - heap::SimulateIncrementalMarking(CcTest::heap(), false); - Tagged<FixedArray> host = Cast<FixedArray>(objects->get(0)); - Tagged<HeapObject> value1 = Cast<HeapObject>(objects->get(1)); - Tagged<HeapObject> value2 = Cast<HeapObject>(objects->get(2)); - CHECK(heap->marking_state()->IsUnmarked(host)); - CHECK(heap->marking_state()->IsUnmarked(value1)); - // Trigger the barrier for the unmarked host and expect the bail out. - WriteBarrier::MarkingForTesting(host, host->RawFieldOfElementAt(0), value1); - CHECK(heap->marking_state()->IsMarked(value1)); - - CHECK(heap->marking_state()->IsUnmarked(value2)); - WriteBarrier::MarkingForTesting(host, host->RawFieldOfElementAt(0), value2); - CHECK(heap->marking_state()->IsMarked(value2)); - heap::SimulateIncrementalMarking(CcTest::heap(), true); - CHECK(heap->marking_state()->IsMarked(host)); - CHECK(heap->marking_state()->IsMarked(value1)); - CHECK(heap->marking_state()->IsMarked(value2)); -} - -HEAP_TEST(WriteBarrier_MarkingExtension) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope outer(isolate); - DirectHandle<FixedArray> objects = factory->NewFixedArray(1); - ArrayBufferExtension* extension; - { - HandleScope inner(isolate); - Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(CcTest::isolate(), 100); - DirectHandle<JSArrayBuffer> host = v8::Utils::OpenDirectHandle(*ab); - extension = host->extension(); - objects->set(0, *host); - } - heap::SimulateIncrementalMarking(CcTest::heap(), false); - Tagged<JSArrayBuffer> host = Cast<JSArrayBuffer>(objects->get(0)); - CHECK(heap->marking_state()->IsUnmarked(host)); - CHECK(!extension->IsMarked()); - WriteBarrier::ForArrayBufferExtension(host, extension); - CHECK(extension->IsMarked()); - // Concurrent marking barrier should mark the value now. - CHECK(extension->IsMarked()); - // Keep object alive using the global handle. - v8::Global<ArrayBuffer> global_host( - CcTest::isolate(), Utils::ToLocal(direct_handle(host, isolate))); - heap::SimulateIncrementalMarking(CcTest::heap(), true); - CHECK(heap->marking_state()->IsMarked(host)); - CHECK(extension->IsMarked()); -} - -} // namespace heap -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/cctest/test-accessor-assembler.cc b/deps/v8/test/cctest/test-accessor-assembler.cc index 69ddbd3f60d9..8d4d02363b84 100644 --- a/deps/v8/test/cctest/test-accessor-assembler.cc +++ b/deps/v8/test/cctest/test-accessor-assembler.cc @@ -194,7 +194,8 @@ TEST(TryProbeStubCache) { // Generate string. std::stringstream ss; ss << "s" << std::hex - << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize); + << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize) + << std::dec; name = factory->InternalizeUtf8String(ss.str().c_str()); break; } diff --git a/deps/v8/test/cctest/test-api-array-buffer.cc b/deps/v8/test/cctest/test-api-array-buffer.cc index b2b29a1bcb45..8006f72c6474 100644 --- a/deps/v8/test/cctest/test-api-array-buffer.cc +++ b/deps/v8/test/cctest/test-api-array-buffer.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> #include <span> #include "include/cppgc/allocation.h" @@ -45,12 +46,11 @@ void CheckIsDetached(v8::Local<v8::TypedArray> ta) { } void CheckIsTypedArrayVarDetached(const char* name) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1024); + std::array<char, 1024> source; v8::base::SNPrintF( - source.as_vector(), - "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", name, name, - name); - CHECK(CompileRun(source.begin())->IsTrue()); + source, "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", + name, name, name); + CHECK(CompileRun(source.data())->IsTrue()); v8::Local<v8::TypedArray> ta = CompileRun(name).As<v8::TypedArray>(); CheckIsDetached(ta); } @@ -543,10 +543,10 @@ THREADED_TEST(ArrayBuffer_ExternalizeEmpty) { std::shared_ptr<v8::BackingStore> backing_store = Externalize(ab); Local<v8::Uint8Array> u8a = v8::Uint8Array::New(ab, 0, 0); - // Calling Buffer() will materialize the ArrayBuffer (transitioning it from + // Calling GetBuffer() will materialize the ArrayBuffer (transitioning it from // on-heap to off-heap if need be). This should not affect whether it is // marked as is_external or not. - USE(u8a->Buffer()); + USE(u8a->GetBuffer()); CHECK_EQ(2, backing_store->ByteLength()); } @@ -1410,3 +1410,51 @@ TEST(ArrayBuffer_DetachCallback_Wrapped) { isolate->SetArrayBufferDetachCallback(nullptr); } + +TEST(ArrayBufferBase_Methods) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + + v8::Local<v8::ArrayBufferBase> ab = v8::ArrayBuffer::New(isolate, 8); + v8::Local<v8::ArrayBufferBase> sab = v8::SharedArrayBuffer::New(isolate, 8); + + CHECK(ab->IsArrayBufferBase()); + CHECK(ab->IsArrayBuffer()); + CHECK(!ab->IsSharedArrayBuffer()); + CHECK(!ab->IsShared()); + CHECK(ab->IsDetachable()); + CHECK(!ab->WasDetached()); + CHECK(!ab->IsImmutable()); + CHECK(!ab->IsResizableByUserJavaScript()); + CHECK_EQ(8u, ab->ByteLength()); + CHECK_EQ(8u, ab->MaxByteLength()); + + CHECK(sab->IsArrayBufferBase()); + CHECK(!sab->IsArrayBuffer()); + CHECK(sab->IsSharedArrayBuffer()); + CHECK(sab->IsShared()); + CHECK(!sab->IsDetachable()); + CHECK(!sab->WasDetached()); + CHECK(!sab->IsImmutable()); + CHECK(!sab->IsResizableByUserJavaScript()); + CHECK_EQ(8u, sab->ByteLength()); + CHECK_EQ(8u, sab->MaxByteLength()); + + CHECK(!v8::Undefined(isolate)->IsArrayBufferBase()); + CHECK(!ab->GetBackingStore()->IsShared()); + CHECK(sab->GetBackingStore()->IsShared()); + + std::memcpy(ab->Data(), "12345678", 8); + CHECK_EQ(8u, ab->CopyArrayBufferBytes(0, 8, sab, 0)); + CHECK_EQ(0, std::memcmp(sab->Data(), "12345678", 8)); + + std::memcpy(sab->Data(), "abcdefgh", 8); + CHECK_EQ(8u, sab->CopyArrayBufferBytes(0, 8, ab, 0)); + CHECK_EQ(0, std::memcmp(ab->Data(), "abcdefgh", 8)); + + ab.As<v8::ArrayBuffer>()->Detach({}).Check(); + CHECK(ab->WasDetached()); + CHECK_EQ(0u, sab->CopyArrayBufferBytes(0, 8, ab, 0)); + CHECK_EQ(0u, ab->CopyArrayBufferBytes(0, 8, sab, 0)); +} diff --git a/deps/v8/test/cctest/test-api-incumbent.cc b/deps/v8/test/cctest/test-api-incumbent.cc index 9eed1b36d05d..d6f98aef9a98 100644 --- a/deps/v8/test/cctest/test-api-incumbent.cc +++ b/deps/v8/test/cctest/test-api-incumbent.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> #include <optional> #include "include/v8-function-callback.h" @@ -107,9 +108,9 @@ v8::LocalVector<Context> SetupCrossContextTest( { Context::Scope context_scope(context); - auto src = v8::base::OwnedVector<char>::NewForOverwrite(30); - v8::base::SNPrintF(src.as_vector(), "Object.prototype.id = %d", i); - CompileRun(src.begin()); + std::array<char, 30> src; + v8::base::SNPrintF(src, "Object.prototype.id = %d", i); + CompileRun(src.data()); } } @@ -125,17 +126,17 @@ v8::LocalVector<Context> SetupCrossContextTest( // Add "realmX" properties referencing contextX->global. for (int j = 0; j < n; j++) { Local<Context> another_context = contexts[j]; - auto name = v8::base::OwnedVector<char>::NewForOverwrite(30); - v8::base::SNPrintF(name.as_vector(), "realm%d", j); + std::array<char, 30> name; + v8::base::SNPrintF(name, "realm%d", j); CHECK(context->Global() - ->Set(context, v8_str(name.begin()), another_context->Global()) + ->Set(context, v8_str(name.data()), another_context->Global()) .FromJust()); // Check that 'id' property matches the realm index. - auto src = v8::base::OwnedVector<char>::NewForOverwrite(30); - v8::base::SNPrintF(src.as_vector(), "realm%d.id", j); - Local<Value> value = CompileRun(src.begin()); + std::array<char, 30> src; + v8::base::SNPrintF(src, "realm%d.id", j); + Local<Value> value = CompileRun(src.data()); CHECK_EQ(j, value.As<Integer>()->Value()); } @@ -215,9 +216,9 @@ v8::LocalVector<Context> SetupCrossContextTest( expected_incumbent_context_ptr) .ToLocalChecked(); - auto name = v8::base::OwnedVector<char>::NewForOverwrite(30); - v8::base::SNPrintF(name.as_vector(), "realm%d.f", static_cast<int>(i)); - func->SetName(v8_str(name.begin())); + std::array<char, 30> name; + v8::base::SNPrintF(name, "realm%d.f", static_cast<int>(i)); + func->SetName(v8_str(name.data())); CHECK(context->Global()->Set(context, v8_str("f"), func).FromJust()); } diff --git a/deps/v8/test/cctest/test-api-interceptors.cc b/deps/v8/test/cctest/test-api-interceptors.cc index 452bc8dfa2d2..ee2fdaffaefd 100644 --- a/deps/v8/test/cctest/test-api-interceptors.cc +++ b/deps/v8/test/cctest/test-api-interceptors.cc @@ -4,6 +4,7 @@ #include <stdlib.h> +#include <array> #include <optional> #include "include/v8-function.h" @@ -3986,62 +3987,6 @@ THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) { CHECK(v8_num(40013)->Equals(context.local(), result).FromJust()); } -namespace { -void SloppyArgsIndexedPropertyEnumerator( - const v8::PropertyCallbackInfo<v8::Array>& info) { - // Force the list of returned keys to be stored in a Arguments object. - Local<Script> indexed_property_names_script = v8_compile( - "function f(w,x) {" - " return arguments;" - "}" - "keys = f(0, 1, 2, 3);" - "keys;"); - Local<Object> result = - indexed_property_names_script->Run(info.GetIsolate()->GetCurrentContext()) - .ToLocalChecked() - .As<Object>(); - // Have to populate the handle manually, as it's not Cast-able. - i::DirectHandle<i::JSReceiver> o = - v8::Utils::OpenDirectHandle<Object, i::JSReceiver>(result); - i::DirectHandle<i::JSArray> array( - i::UncheckedCast<i::JSArray>(*o), - reinterpret_cast<i::Isolate*>(info.GetIsolate())); - info.GetReturnValue().Set(v8::Utils::ToLocal(array)); -} - -v8::Intercepted SloppyIndexedPropertyGetter( - uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { - ApiTestFuzzer::Fuzz(); - if (index < 4) { - info.GetReturnValue().Set(v8_num(index)); - return v8::Intercepted::kYes; - } - return v8::Intercepted::kNo; -} -} // namespace - -// Make sure that the interceptor code in the runtime properly handles -// merging property name lists for non-string arguments arrays. -THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(isolate); - Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetHandler(v8::IndexedPropertyHandlerConfiguration( - SloppyIndexedPropertyGetter, nullptr, nullptr, nullptr, - SloppyArgsIndexedPropertyEnumerator)); - LocalContext context; - context->Global() - ->Set(context.local(), v8_str("obj"), - templ->NewInstance(context.local()).ToLocalChecked()) - .FromJust(); - Local<Script> create_args_script = v8_compile( - "var key_count = 0;" - "for (x in obj) {key_count++;} key_count;"); - Local<Value> result = - create_args_script->Run(context.local()).ToLocalChecked(); - CHECK(v8_num(4)->Equals(context.local(), result).FromJust()); -} - namespace { v8::Intercepted IdentityIndexedPropertyGetter( uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) { @@ -5925,10 +5870,9 @@ void PreprocessExceptionTestCallback(v8::ExceptionPropagationMessage info) { String::Utf8Value property_name(isolate, info.GetPropertyName()); String::Utf8Value message(isolate, message_value); - auto buf = v8::base::OwnedVector<char>::NewForOverwrite(256); - v8::base::SNPrintF(buf.as_vector(), "%s:%s:%s: %s", *interface_name, - *property_name, ToString(info.GetExceptionContext()), - *message); + std::array<char, 256> buf; + v8::base::SNPrintF(buf, "%s:%s:%s: %s", *interface_name, *property_name, + ToString(info.GetExceptionContext()), *message); std::ignore = exception->CreateDataProperty(context, message_key, v8_str(buf.data())); @@ -6924,38 +6868,6 @@ THREADED_TEST(EnumeratorsAndUnenumerableNamedPropertiesWithoutSet) { ExpectInt32("Object.keys(obj).length", 1); } -THREADED_TEST(EnumeratorsAndUnenumerableIndexedPropertiesArgumentsElements) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); - obj->SetHandler(v8::IndexedPropertyHandlerConfiguration( - ConcatIndexedPropertyGetter, nullptr, RestrictiveIndexedQuery, nullptr, - SloppyArgsIndexedPropertyEnumerator)); - LocalContext context; - context->Global() - ->Set(context.local(), v8_str("obj"), - obj->NewInstance(context.local()).ToLocalChecked()) - .FromJust(); - - ExpectInt32("Object.getOwnPropertyNames(obj).length", 4); - ExpectString("Object.getOwnPropertyNames(obj)[0]", "0"); - ExpectString("Object.getOwnPropertyNames(obj)[1]", "1"); - ExpectString("Object.getOwnPropertyNames(obj)[2]", "2"); - ExpectString("Object.getOwnPropertyNames(obj)[3]", "3"); - - ExpectTrue("Object.getOwnPropertyDescriptor(obj, '2').enumerable"); - - ExpectInt32("Object.entries(obj).length", 1); - ExpectString("Object.entries(obj)[0][0]", "2"); - ExpectInt32("Object.entries(obj)[0][1]", 4); - - ExpectInt32("Object.keys(obj).length", 1); - ExpectString("Object.keys(obj)[0]", "2"); - - ExpectInt32("Object.values(obj).length", 1); - ExpectInt32("Object.values(obj)[0]", 4); -} - THREADED_TEST(EnumeratorsAndUnenumerableIndexedProperties) { // The enumerator interceptor returns a list // of items which are filtered according to the @@ -7434,3 +7346,55 @@ TEST(ScriptContextTableReentrantClash) { // The re-entrant declaration committed before the outer script was rejected. CHECK_EQ(1, v8_run_int32("a")); } + +namespace { + +constexpr uint32_t kDenseInterceptorLength = 2; + +v8::Intercepted DenseSetterMonomorphicBypass( + uint32_t index, v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<v8::Boolean>& info) { + if (index >= kDenseInterceptorLength) return v8::Intercepted::kNo; + int& setter_count = *GetData<int>(info); + setter_count++; + return v8::Intercepted::kYes; +} + +} // namespace + +TEST(RegressKeyedStoreICMonomorphicBypassInterceptor) { + v8::internal::v8_flags.allow_natives_syntax = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + + int setter_count = 0; + v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); + templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration( + nullptr, DenseSetterMonomorphicBypass, nullptr, nullptr, nullptr, + MakeData(isolate, &setter_count))); + + v8::Local<v8::Object> obj = templ->GetFunction(env.local()) + .ToLocalChecked() + ->NewInstance(env.local()) + .ToLocalChecked(); + + env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust(); + + CompileRun( + "function f(o, i, v) { o[i] = v; }\n" + "%PrepareFunctionForOptimization(f);\n" + // Index 2 is outside [0, length), so it is not intercepted and goes to + // the fast elements backing store (allocating capacity > 2) while making + // the IC monomorphic with StoreFastElementIC_InBounds. + "f(obj, 2, 1);\n" + // Indices 0 and 1 are in [0, length) and must call the interceptor. + "f(obj, 0, 2);\n" + "f(obj, 1, 3);\n"); + + CHECK_EQ(2, setter_count); + + CHECK_EQ(1, v8_run_int32("obj[2]")); + CHECK(CompileRun("obj[0]")->IsUndefined()); + CHECK(CompileRun("obj[1]")->IsUndefined()); +} diff --git a/deps/v8/test/cctest/test-api-stack-traces.cc b/deps/v8/test/cctest/test-api-stack-traces.cc index 0bda6c065827..914aacfaaba9 100644 --- a/deps/v8/test/cctest/test-api-stack-traces.cc +++ b/deps/v8/test/cctest/test-api-stack-traces.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> #include <span> #include "include/v8-function.h" @@ -746,11 +747,11 @@ TEST(SourceURLInStackTrace) { "}\n" "eval('(' + outer +')()%s');"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(code.as_vector(), source, "//# sourceURL=eval_url"); - CHECK(CompileRun(code.begin())->IsUndefined()); - v8::base::SNPrintF(code.as_vector(), source, "//@ sourceURL=eval_url"); - CHECK(CompileRun(code.begin())->IsUndefined()); + std::array<char, 1024> code; + v8::base::SNPrintF(code, source, "//# sourceURL=eval_url"); + CHECK(CompileRun(code.data())->IsUndefined()); + v8::base::SNPrintF(code, source, "//@ sourceURL=eval_url"); + CHECK(CompileRun(code.data())->IsUndefined()); } static int scriptIdInStack[2]; @@ -1609,6 +1610,133 @@ TEST(CurrentScriptData_Wasm) { CHECK_EQ(capturedFramesScriptData[1].function, main_func); } +struct DynamicScriptCompiledEvent { + v8::Global<v8::Context> context; + int script_id; +}; + +static std::vector<DynamicScriptCompiledEvent> dynamicScriptCompiledEvents; + +void RecordDynamicScriptCompiled(v8::Local<v8::Context> context, + int script_id) { + dynamicScriptCompiledEvents.push_back( + {v8::Global<v8::Context>(CcTest::isolate(), context), script_id}); +} + +struct DynamicScriptCallbackScope { + explicit DynamicScriptCallbackScope(v8::Isolate* isolate) + : isolate_(isolate) { + dynamicScriptCompiledEvents.clear(); + isolate_->SetDynamicScriptCompiledFromEmbedderCallback( + RecordDynamicScriptCompiled); + } + ~DynamicScriptCallbackScope() { + isolate_->SetDynamicScriptCompiledFromEmbedderCallback(nullptr); + dynamicScriptCompiledEvents.clear(); + } + v8::Isolate* isolate_; +}; + +TEST(CurrentScriptData_DynamicScriptCompiledFromEmbedder_Eval) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + CapturedFramesScope captured_frames_scope; + DynamicScriptCallbackScope callback_scope(isolate); + + Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); + templ->Set(isolate, "CaptureStack", + v8::FunctionTemplate::New(isolate, CaptureScriptData)); + LocalContext context(nullptr, templ); + + v8::Local<v8::Function> eval_fn = context->Global() + ->Get(context.local(), v8_str("eval")) + .ToLocalChecked() + .As<v8::Function>(); + v8::Local<v8::Value> arg = v8_str("CaptureStack()"); + eval_fn->Call(context.local(), context->Global(), 1, &arg).ToLocalChecked(); + + CHECK_EQ(dynamicScriptCompiledEvents.size(), 1); + CHECK_EQ(dynamicScriptCompiledEvents[0].context, context.local()); + int script_id = dynamicScriptCompiledEvents[0].script_id; + CHECK_NE(script_id, v8::UnboundScript::kNoScriptId); + + CHECK_EQ(capturedFramesScriptData.size(), 1); + CHECK_EQ(capturedFramesScriptData[0].id, script_id); + CHECK_EQ(capturedFramesScriptData[0].context, context.local()); + CHECK(!capturedFramesScriptData[0].function.IsEmpty()); + + // When eval is called from a normal JS script with a JS caller on the stack, + // DynamicScriptCompiledFromEmbedderCallback should not be called. + dynamicScriptCompiledEvents.clear(); + CompileRun("(0, eval)('CaptureStack()');"); + CHECK(dynamicScriptCompiledEvents.empty()); + + // A subsequent embedder call with the same source string must not hit the + // compilation cache and must trigger the callback with a fresh script ID. + eval_fn->Call(context.local(), context->Global(), 1, &arg).ToLocalChecked(); + CHECK_EQ(dynamicScriptCompiledEvents.size(), 1); + CHECK_NE(dynamicScriptCompiledEvents[0].script_id, script_id); + CHECK_EQ(capturedFramesScriptData[0].id, + dynamicScriptCompiledEvents[0].script_id); +} + +TEST(CurrentScriptData_DynamicScriptCompiledFromEmbedder_FunctionConstructor) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + CapturedFramesScope captured_frames_scope; + DynamicScriptCallbackScope callback_scope(isolate); + + Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); + templ->Set(isolate, "CaptureStack", + v8::FunctionTemplate::New(isolate, CaptureScriptData)); + LocalContext context(nullptr, templ); + + v8::Local<v8::Function> func_ctor = + context->Global() + ->Get(context.local(), v8_str("Function")) + .ToLocalChecked() + .As<v8::Function>(); + v8::Local<v8::Value> arg = v8_str("CaptureStack()"); + v8::Local<v8::Function> created_fn = + func_ctor->CallAsConstructor(context.local(), 1, &arg) + .ToLocalChecked() + .As<v8::Function>(); + + CHECK_EQ(dynamicScriptCompiledEvents.size(), 1); + CHECK_EQ(dynamicScriptCompiledEvents[0].context, context.local()); + int script_id = dynamicScriptCompiledEvents[0].script_id; + CHECK_NE(script_id, v8::UnboundScript::kNoScriptId); + + created_fn->Call(context.local(), context->Global(), 0, nullptr) + .ToLocalChecked(); + + CHECK_EQ(dynamicScriptCompiledEvents.size(), 1); + CHECK_EQ(capturedFramesScriptData.size(), 1); + CHECK_EQ(capturedFramesScriptData[0].id, script_id); + CHECK_EQ(capturedFramesScriptData[0].function, created_fn); + CHECK_EQ(capturedFramesScriptData[0].context, context.local()); + + // When Function constructor is called from a normal JS script with a JS + // caller on the stack, DynamicScriptCompiledFromEmbedderCallback should not + // be called. + dynamicScriptCompiledEvents.clear(); + CompileRun("new Function('CaptureStack()')();"); + CHECK(dynamicScriptCompiledEvents.empty()); + + // A subsequent embedder call with the same source string must not hit the + // compilation cache and must trigger the callback with a fresh script ID. + v8::Local<v8::Function> created_fn2 = + func_ctor->CallAsConstructor(context.local(), 1, &arg) + .ToLocalChecked() + .As<v8::Function>(); + CHECK_EQ(dynamicScriptCompiledEvents.size(), 1); + CHECK_NE(dynamicScriptCompiledEvents[0].script_id, script_id); + created_fn2->Call(context.local(), context->Global(), 0, nullptr) + .ToLocalChecked(); + CHECK_EQ(capturedFramesScriptData[0].id, + dynamicScriptCompiledEvents[0].script_id); +} + void AnalyzeStackOfInlineScriptWithSourceURL( const v8::FunctionCallbackInfo<v8::Value>& info) { CHECK(i::ValidateCallbackInfo(info)); @@ -1647,11 +1775,11 @@ TEST(InlineScriptWithSourceURLInStackTrace) { "}\n" "outer()\n%s"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(code.as_vector(), source, "//# sourceURL=source_url"); - CHECK(CompileRunWithOrigin(code.begin(), "url", 0, 1)->IsUndefined()); - v8::base::SNPrintF(code.as_vector(), source, "//@ sourceURL=source_url"); - CHECK(CompileRunWithOrigin(code.begin(), "url", 0, 1)->IsUndefined()); + std::array<char, 1024> code; + v8::base::SNPrintF(code, source, "//# sourceURL=source_url"); + CHECK(CompileRunWithOrigin(code.data(), "url", 0, 1)->IsUndefined()); + v8::base::SNPrintF(code, source, "//@ sourceURL=source_url"); + CHECK(CompileRunWithOrigin(code.data(), "url", 0, 1)->IsUndefined()); } void AnalyzeStackOfDynamicScriptWithSourceURL( @@ -1692,11 +1820,11 @@ TEST(DynamicWithSourceURLInStackTrace) { "}\n" "outer()\n%s"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(code.as_vector(), source, "//# sourceURL=source_url"); - CHECK(CompileRunWithOrigin(code.begin(), "url", 0, 0)->IsUndefined()); - v8::base::SNPrintF(code.as_vector(), source, "//@ sourceURL=source_url"); - CHECK(CompileRunWithOrigin(code.begin(), "url", 0, 0)->IsUndefined()); + std::array<char, 1024> code; + v8::base::SNPrintF(code, source, "//# sourceURL=source_url"); + CHECK(CompileRunWithOrigin(code.data(), "url", 0, 0)->IsUndefined()); + v8::base::SNPrintF(code, source, "//@ sourceURL=source_url"); + CHECK(CompileRunWithOrigin(code.data(), "url", 0, 0)->IsUndefined()); } TEST(DynamicWithSourceURLInStackTraceString) { @@ -1712,10 +1840,10 @@ TEST(DynamicWithSourceURLInStackTraceString) { "}\n" "outer()\n%s"; - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(code.as_vector(), source, "//# sourceURL=source_url"); + std::array<char, 1024> code; + v8::base::SNPrintF(code, source, "//# sourceURL=source_url"); v8::TryCatch try_catch(context.isolate()); - CompileRunWithOrigin(code.begin(), "", 0, 0); + CompileRunWithOrigin(code.data(), "", 0, 0); CHECK(try_catch.HasCaught()); v8::String::Utf8Value stack( context.isolate(), diff --git a/deps/v8/test/cctest/test-api-typed-array.cc b/deps/v8/test/cctest/test-api-typed-array.cc index 1878d748dc02..134df0b7aa82 100644 --- a/deps/v8/test/cctest/test-api-typed-array.cc +++ b/deps/v8/test/cctest/test-api-typed-array.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> + #include "src/api/api-inl.h" #include "src/base/strings.h" #include "src/objects/js-array-buffer-inl.h" @@ -107,7 +109,7 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, "sum;"); CHECK_EQ(28, result->Int32Value(context).FromJust()); - auto test_buf = v8::base::OwnedVector<char>::NewForOverwrite(1024); + std::array<char, 1024> test_buf; // Check legal boundary conditions. // The repeated loads and stores ensure the ICs are exercised. @@ -120,12 +122,12 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, " }" "}" "res;"; - v8::base::SNPrintF(test_buf.as_vector(), boundary_program, low); - result = CompileRun(test_buf.begin()); + v8::base::SNPrintF(test_buf, boundary_program, low); + result = CompileRun(test_buf.data()); CHECK_EQ(low, result->IntegerValue(context).FromJust()); - v8::base::SNPrintF(test_buf.as_vector(), boundary_program, high); - result = CompileRun(test_buf.begin()); + v8::base::SNPrintF(test_buf, boundary_program, high); + result = CompileRun(test_buf.data()); CHECK_EQ(high, result->IntegerValue(context).FromJust()); // Check misprediction of type in IC. @@ -145,7 +147,7 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, CHECK_EQ(28, result->Int32Value(context).FromJust()); // Make sure out-of-range loads do not throw. - v8::base::SNPrintF(test_buf.as_vector(), + v8::base::SNPrintF(test_buf, "var caught_exception = false;" "try {" " ext_array[%d];" @@ -154,11 +156,11 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, "}" "caught_exception;", element_count); - result = CompileRun(test_buf.begin()); + result = CompileRun(test_buf.data()); CHECK(!result->BooleanValue(v8_isolate)); // Make sure out-of-range stores do not throw. - v8::base::SNPrintF(test_buf.as_vector(), + v8::base::SNPrintF(test_buf, "var caught_exception = false;" "try {" " ext_array[%d] = 1;" @@ -167,7 +169,7 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, "}" "caught_exception;", element_count); - result = CompileRun(test_buf.begin()); + result = CompileRun(test_buf.data()); CHECK(!result->BooleanValue(v8_isolate)); // Check other boundary conditions, values and operations. @@ -250,7 +252,7 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, bool is_pixel_data = array_type == i::kExternalUint8ClampedArray; v8::base::SNPrintF( - test_buf.as_vector(), + test_buf, "%s" "var all_passed = true;" "for (var i = 0; i < source_data.length; i++) {" @@ -263,7 +265,7 @@ void ObjectWithExternalArrayTestHelper(v8::Isolate* v8_isolate, "all_passed;", (is_unsigned ? unsigned_data : (is_pixel_data ? pixel_data : signed_data))); - result = CompileRun(test_buf.begin()); + result = CompileRun(test_buf.data()); CHECK(result->BooleanValue(v8_isolate)); } @@ -376,7 +378,12 @@ void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset()); CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength()); + CHECK(ab->Equals(env.local(), ta->GetBuffer()).FromJust()); + CHECK_EQ((std::is_same_v<ArrayBufferType, v8::SharedArrayBuffer>), + ta->GetBuffer()->IsShared()); + START_ALLOW_USE_DEPRECATED(); CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust()); + END_ALLOW_USE_DEPRECATED(); ElementType* data = reinterpret_cast<ElementType*>(ab->GetBackingStore()->Data()) + 2; @@ -453,7 +460,10 @@ THREADED_TEST(DataView) { CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); CHECK_EQ(2u, dv->ByteOffset()); CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); + CHECK(ab->Equals(env.local(), dv->GetBuffer()).FromJust()); + START_ALLOW_USE_DEPRECATED(); CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust()); + END_ALLOW_USE_DEPRECATED(); // TODO(v8:11111): Use API functions for testing these, once they're exposed // via the API. @@ -521,7 +531,10 @@ THREADED_TEST(SharedDataView) { CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); CHECK_EQ(2u, dv->ByteOffset()); CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); + CHECK(ab->Equals(env.local(), dv->GetBuffer()).FromJust()); + START_ALLOW_USE_DEPRECATED(); CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust()); + END_ALLOW_USE_DEPRECATED(); // TODO(v8:11111): Use API functions for testing these, once they're exposed // via the API. @@ -696,15 +709,14 @@ void TestOnHeapHasBuffer(const char* array_name, size_t elem_size) { v8::Isolate* isolate = env.isolate(); v8::HandleScope handle_scope(isolate); - auto source = v8::base::OwnedVector<char>::NewForOverwrite(128); + std::array<char, 128> source; // Test on-heap sizes. for (size_t size = 0; size <= i::JSTypedArray::kMaxSizeInHeap; size += elem_size) { size_t length = size / elem_size; - v8::base::SNPrintF(source.as_vector(), "new %sArray(%zu)", array_name, - length); + v8::base::SNPrintF(source, "new %sArray(%zu)", array_name, length); auto typed_array = - v8::Local<v8::TypedArray>::Cast(CompileRun(source.begin())); + v8::Local<v8::TypedArray>::Cast(CompileRun(source.data())); CHECK_EQ(length, typed_array->Length()); @@ -729,15 +741,14 @@ void TestOffHeapHasBuffer(const char* array_name, size_t elem_size) { v8::Isolate* isolate = env.isolate(); v8::HandleScope handle_scope(isolate); - auto source = v8::base::OwnedVector<char>::NewForOverwrite(128); + std::array<char, 128> source; // Test off-heap sizes. size_t size = i::JSTypedArray::kMaxSizeInHeap; for (int i = 0; i < 3; i++) { size_t length = 1 + (size / elem_size); - v8::base::SNPrintF(source.as_vector(), "new %sArray(%zu)", array_name, - length); + v8::base::SNPrintF(source, "new %sArray(%zu)", array_name, length); auto typed_array = - v8::Local<v8::TypedArray>::Cast(CompileRun(source.begin())); + v8::Local<v8::TypedArray>::Cast(CompileRun(source.data())); CHECK_EQ(length, typed_array->Length()); // Should already have a buffer. diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index c98c4e2ecb33..a05627ed8634 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -30,12 +30,14 @@ #include <array> #include <climits> #include <csignal> +#include <format> #include <map> #include <memory> #include <optional> #include <span> #include <sstream> #include <string> +#include <string_view> #include "test/cctest/cctest.h" @@ -63,6 +65,7 @@ #include "src/base/overflowing-math.h" #include "src/base/platform/platform.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/codegen/compilation-cache.h" #include "src/common/globals.h" #include "src/compiler/globals.h" @@ -231,8 +234,8 @@ THREADED_TEST(IsolateOfContext) { static void TestSignatureLooped(const char* operation, Local<Value> receiver, v8::Isolate* isolate) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(200); - v8::base::SNPrintF(source.as_vector(), + std::array<char, 200> source; + v8::base::SNPrintF(source, "for (var i = 0; i < 10; i++) {" " %s" "}", @@ -241,7 +244,7 @@ static void TestSignatureLooped(const char* operation, Local<Value> receiver, signature_expected_receiver_global.Reset(isolate, receiver); bool expected_to_throw = receiver.IsEmpty(); v8::TryCatch try_catch(isolate); - CompileRun(source.begin()); + CompileRun(source.data()); CHECK_EQ(expected_to_throw, try_catch.HasCaught()); if (!expected_to_throw) { CHECK_EQ(10, signature_callback_count); @@ -258,8 +261,8 @@ static void TestSignatureLooped(const char* operation, Local<Value> receiver, static void TestSignatureOptimized(const char* operation, Local<Value> receiver, v8::Isolate* isolate) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(200); - v8::base::SNPrintF(source.as_vector(), + std::array<char, 200> source; + v8::base::SNPrintF(source, "function test() {" " %s" "};" @@ -273,7 +276,7 @@ static void TestSignatureOptimized(const char* operation, Local<Value> receiver, signature_expected_receiver_global.Reset(isolate, receiver); bool expected_to_throw = receiver.IsEmpty(); v8::TryCatch try_catch(isolate); - CompileRun(source.begin()); + CompileRun(source.data()); CHECK_EQ(expected_to_throw, try_catch.HasCaught()); if (!expected_to_throw) { CHECK_EQ(3, signature_callback_count); @@ -382,10 +385,10 @@ THREADED_TEST(ReceiverSignature) { "unrelated", "inherited", "inherited_direct"}; unsigned bad_signature_start_offset = 3; for (unsigned i = 0; i < arraysize(test_objects); i++) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(200); - v8::base::SNPrintF(source.as_vector(), "var test_object = %s; test_object", + std::array<char, 200> source; + v8::base::SNPrintF(source, "var test_object = %s; test_object", test_objects[i]); - Local<Value> test_object = CompileRun(source.begin()); + Local<Value> test_object = CompileRun(source.data()); TestSignature("test_object.prop();", test_object, isolate); TestSignature("test_object.accessor;", test_object, isolate); TestSignature("test_object[accessor_key];", test_object, isolate); @@ -3274,10 +3277,9 @@ THREADED_TEST(InternalFieldsOfRegularObjects) { const char* sources[] = {"new Object()", "{ a: 'a property' }", "arguments"}; for (size_t i = 0; i < arraysize(sources); ++i) { - auto source = v8::base::OwnedVector<char>::NewForOverwrite(128); - v8::base::SNPrintF(source.as_vector(), "(function() { return %s })()", - sources[i]); - v8::Local<v8::Object> obj = CompileRun(source.begin()).As<v8::Object>(); + std::array<char, 128> source; + v8::base::SNPrintF(source, "(function() { return %s })()", sources[i]); + v8::Local<v8::Object> obj = CompileRun(source.data()).As<v8::Object>(); CHECK_EQ(0, obj->InternalFieldCount()); } } @@ -3355,7 +3357,24 @@ static void CheckAlignedPointerInEmbedderData(LocalContext* env, v8::Local<v8::Object> some_obj, int index, void* value) { CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V2. (*env)->SetAlignedPointerInEmbedderData(index, value, kTestTypeTagA); + END_ALLOW_USE_DEPRECATED() + i::heap::InvokeMajorGC(CcTest::heap()); + CHECK_EQ(value, + (*env)->GetAlignedPointerFromEmbedderData(index, kTestTypeTagA)); + CHECK_EQ(value, some_obj->GetAlignedPointerFromEmbedderDataInCreationContext( + index, kTestTypeTagA)); + CHECK_EQ(value, some_obj->GetAlignedPointerFromEmbedderDataInCreationContext( + CcTest::isolate(), index, kTestTypeTagA)); +} + +static void CheckAlignedPointerInEmbedderDataV2(LocalContext* env, + v8::Local<v8::Object> some_obj, + int index, void* value) { + CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); + (*env)->SetAlignedPointerInEmbedderDataV2(index, value, kTestTypeTagA); i::heap::InvokeMajorGC(CcTest::heap()); CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index, kTestTypeTagA)); @@ -3377,27 +3396,30 @@ THREADED_TEST(EmbedderDataAlignedPointers) { v8::Local<v8::Object> obj = v8::Object::New(isolate); CheckAlignedPointerInEmbedderData(&env, obj, 0, nullptr); - CHECK_EQ(1, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(1, (*env)->GetNumberOfEmbedderDataFields()); int* heap_allocated = new int[100]; CheckAlignedPointerInEmbedderData(&env, obj, 1, heap_allocated); - CHECK_EQ(2, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(2, (*env)->GetNumberOfEmbedderDataFields()); delete[] heap_allocated; int stack_allocated[100]; CheckAlignedPointerInEmbedderData(&env, obj, 2, stack_allocated); - CHECK_EQ(3, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(3, (*env)->GetNumberOfEmbedderDataFields()); // The aligned pointer must have the top bits be zero on 64-bit machines (at // least if the sandboxed external pointers are enabled). void* huge = reinterpret_cast<void*>(0x0000fffffffffffe); CheckAlignedPointerInEmbedderData(&env, obj, 3, huge); - CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(4, (*env)->GetNumberOfEmbedderDataFields()); // Test growing of the embedder data's backing store. for (int i = 0; i < 100; i++) { + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V2. env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i), i % V8_EMBEDDER_DATA_TAG_COUNT); + END_ALLOW_USE_DEPRECATED() } i::heap::InvokeMajorGC(CcTest::heap()); for (int i = 0; i < 100; i++) { @@ -3407,6 +3429,28 @@ THREADED_TEST(EmbedderDataAlignedPointers) { } } +THREADED_TEST(EmbedderDataAlignedPointersV2) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + + v8::Local<v8::Object> obj = v8::Object::New(isolate); + + CheckAlignedPointerInEmbedderDataV2(&env, obj, 0, nullptr); + + int* heap_allocated = new int[100]; + CheckAlignedPointerInEmbedderDataV2(&env, obj, 1, heap_allocated); + delete[] heap_allocated; + + int stack_allocated[100]; + CheckAlignedPointerInEmbedderDataV2(&env, obj, 2, stack_allocated); + + // The aligned pointer must have the top bits be zero on 64-bit machines (at + // least if the sandboxed external pointers are enabled). + void* huge = reinterpret_cast<void*>(0x0000fffffffffffe); + CheckAlignedPointerInEmbedderDataV2(&env, obj, 3, huge); +} + THREADED_TEST(EmbedderDataAlignedPointersViaDetachedGlobal) { LocalContext env; v8::Isolate* isolate = env.isolate(); @@ -3415,11 +3459,39 @@ THREADED_TEST(EmbedderDataAlignedPointersViaDetachedGlobal) { v8::Local<v8::Object> obj = env->Global(); CheckAlignedPointerInEmbedderData(&env, obj, 0, nullptr); - CHECK_EQ(1, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(1, (*env)->GetNumberOfEmbedderDataFields()); int stack_allocated[100]; CheckAlignedPointerInEmbedderData(&env, obj, 1, stack_allocated); - CHECK_EQ(2, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(2, (*env)->GetNumberOfEmbedderDataFields()); + + i::heap::InvokeMajorGC(CcTest::heap()); + + CHECK_EQ(stack_allocated, + obj->GetAlignedPointerFromEmbedderDataInCreationContext( + isolate, 1, kTestTypeTagA)); + + env->DetachGlobal(); + + // In case the global object is detached the embedder data can be read + // directly from current native context as long as its global object IS the + // detached global object. + CHECK_EQ(stack_allocated, + obj->GetAlignedPointerFromEmbedderDataInCreationContext( + isolate, 1, kTestTypeTagA)); +} + +THREADED_TEST(EmbedderDataAlignedPointersViaDetachedGlobalV2) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + + v8::Local<v8::Object> obj = env->Global(); + + CheckAlignedPointerInEmbedderDataV2(&env, obj, 0, nullptr); + + int stack_allocated[100]; + CheckAlignedPointerInEmbedderDataV2(&env, obj, 1, stack_allocated); i::heap::InvokeMajorGC(CcTest::heap()); @@ -3439,7 +3511,17 @@ THREADED_TEST(EmbedderDataAlignedPointersViaDetachedGlobal) { static void CheckEmbedderData(LocalContext* env, int index, v8::Local<Value> data) { + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V3. (*env)->SetEmbedderDataV2(index, data); + END_ALLOW_USE_DEPRECATED() + CHECK(v8::Local<v8::Value>::Cast((*env)->GetEmbedderDataV2(index)) + ->StrictEquals(data)); +} + +static void CheckEmbedderDataV3(LocalContext* env, int index, + v8::Local<Value> data) { + (*env)->SetEmbedderDataV3(index, data); CHECK(v8::Local<v8::Value>::Cast((*env)->GetEmbedderDataV2(index)) ->StrictEquals(data)); } @@ -3449,19 +3531,28 @@ THREADED_TEST(EmbedderData) { v8::Isolate* isolate = env.isolate(); v8::HandleScope scope(isolate); - CHECK_EQ(0, (*env)->GetNumberOfEmbedderDataFields()); CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps")); - CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(4, (*env)->GetNumberOfEmbedderDataFields()); CheckEmbedderData(&env, 2, v8_str("over the lazy dog.")); - CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(4, (*env)->GetNumberOfEmbedderDataFields()); CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345)); - CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(4, (*env)->GetNumberOfEmbedderDataFields()); CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true)); - CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields()); + CHECK_LE(4, (*env)->GetNumberOfEmbedderDataFields()); CheckEmbedderData(&env, 211, v8::Boolean::New(isolate, true)); CHECK_EQ(212, (*env)->GetNumberOfEmbedderDataFields()); } +THREADED_TEST(EmbedderDataV3) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + + CheckEmbedderDataV3(&env, 3, v8_str("The quick brown fox jumps")); + CheckEmbedderDataV3(&env, 2, v8_str("over the lazy dog.")); + CheckEmbedderDataV3(&env, 1, v8::Number::New(isolate, 1.2345)); + CheckEmbedderDataV3(&env, 0, v8::Boolean::New(isolate, true)); +} THREADED_TEST(IdentityHash) { LocalContext env; @@ -4427,10 +4518,10 @@ class TwoPassCallbackData { trigger_gc_(false), metadata_(metadata) { HandleScope scope(isolate); - auto buffer = v8::base::OwnedVector<char>::NewForOverwrite(40); - v8::base::SNPrintF(buffer.as_vector(), "%p", static_cast<void*>(this)); + std::array<char, 40> buffer; + v8::base::SNPrintF(buffer, "%p", static_cast<void*>(this)); auto string = - v8::String::NewFromUtf8(isolate, buffer.begin()).ToLocalChecked(); + v8::String::NewFromUtf8(isolate, buffer.data()).ToLocalChecked(); cell_.Reset(isolate, string); metadata_->instance_counter++; } @@ -4552,7 +4643,7 @@ TEST(TwoPassPhantomCallbacksTriggeredByStringAlloc) { data->SetWeak(); CHECK_EQ(metadata.instance_counter, 1); - auto source = v8::base::OwnedVector<uint8_t>::NewForOverwrite(200000); + auto source = v8::base::UniqueArray<uint8_t>::NewForOverwrite(200000); // In the rest of this test, we need to invoke GC without stack, otherwise the // weak references may not be cleared because of conservative stack scanning. @@ -7732,12 +7823,12 @@ TEST(ExtensionWithSourceLength) { for (int source_len = kEmbeddedExtensionSourceValidLen - 1; source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { v8::HandleScope handle_scope(CcTest::isolate()); - auto extension_name = v8::base::OwnedVector<char>::NewForOverwrite(32); - v8::base::SNPrintF(extension_name.as_vector(), "ext #%d", source_len); - v8::RegisterExtension(std::make_unique<Extension>(extension_name.begin(), + std::array<char, 32> extension_name; + v8::base::SNPrintF(extension_name, "ext #%d", source_len); + v8::RegisterExtension(std::make_unique<Extension>(extension_name.data(), kEmbeddedExtensionSource, 0, nullptr, source_len)); - const char* extension_names[1] = {extension_name.begin()}; + const char* extension_names[1] = {extension_name.data()}; v8::ExtensionConfiguration extensions(1, extension_names); v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions); if (source_len == kEmbeddedExtensionSourceValidLen) { @@ -11306,10 +11397,10 @@ THREADED_TEST(Regress91517) { t4->InstanceTemplate()->Set(isolate, "baz", v8_num(4)); // Force dictionary-based properties. - auto name_buf = v8::base::OwnedVector<char>::NewForOverwrite(1024); + std::array<char, 1024> name_buf; for (int i = 1; i <= 1000; i++) { - v8::base::SNPrintF(name_buf.as_vector(), "sdf%d", i); - t2->InstanceTemplate()->Set(v8_str(name_buf.begin()), v8_num(2)); + v8::base::SNPrintF(name_buf, "sdf%d", i); + t2->InstanceTemplate()->Set(v8_str(name_buf.data()), v8_num(2)); } Local<v8::Object> o1 = t1->GetFunction(context.local()) @@ -13508,39 +13599,6 @@ static v8::Isolate::CreateParams CreateTestParams() { return create_params; } -UNINITIALIZED_TEST(SharedObjectGetConstructorName) { - if (!V8_CAN_CREATE_SHARED_HEAP_BOOL) return; - // In multi-cage mode we create one cage per isolate - // and we don't share objects between cages. - if (COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL) return; - - i::v8_flags.shared_string_table = true; - i::v8_flags.harmony_struct = true; - i::FlagList::EnforceFlagImplications(); - - v8::Isolate::CreateParams create_params = CreateTestParams(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - { - v8::Isolate::Scope i_scope(isolate); - v8::HandleScope scope(isolate); - LocalContext context(isolate); - - v8_compile( - "var s = new (new SharedStructType(['foo']));" - "var a = new SharedArray(1);" - "var m = new Atomics.Mutex;" - "var c = new Atomics.Condition;") - ->Run(context.local()) - .ToLocalChecked(); - - CheckGetConstructorNameOfVar(context, "s", "SharedStruct"); - CheckGetConstructorNameOfVar(context, "a", "SharedArray"); - CheckGetConstructorNameOfVar(context, "m", "Atomics.Mutex"); - CheckGetConstructorNameOfVar(context, "c", "Atomics.Condition"); - } - isolate->Dispose(); -} - static void TestAllocateAndNewForTwoIsolateGroups( const v8::Isolate::CreateParams& create_params_1, const v8::Isolate::CreateParams& create_params_2, @@ -13626,6 +13684,59 @@ UNINITIALIZED_TEST(TwoIsolateGroups) { #ifdef V8_ENABLE_SANDBOX +class CustomInSandboxAllocator : public v8::Allocator { + public: + explicit CustomInSandboxAllocator(v8::IsolateGroup& group) + : address_space_(group.GetSandboxAddressSpace()) {} + + void* Allocate(size_t size) override { return AllocateUninitialized(size); } + + void* AllocateUninitialized(size_t size) override { + uintptr_t result = address_space_->AllocatePages( + 0, kSIZE, kALIGN, v8::PagePermissions::kReadWrite); + allocated_address_ = reinterpret_cast<void*>(result); + return allocated_address_; + } + + void* AllocateUninitializedOrCrash(size_t size) override { + void* allocation = AllocateUninitialized(size); + CHECK_NOT_NULL(allocation); + return allocation; + } + + void Free(void* allocation) override { + if (!allocation) return; + address_space_->FreePages(reinterpret_cast<uintptr_t>(allocation), kSIZE); + } + + void* allocated_address() const { return allocated_address_; } + + private: + static constexpr int kSIZE = 1 << 20; + static constexpr int kALIGN = 64 << 10; + v8::VirtualAddressSpace* address_space_; + void* allocated_address_ = nullptr; +}; + +UNINITIALIZED_TEST(SetInSandboxAllocator) { + v8::IsolateGroup group = v8::IsolateGroup::GetDefault(); + auto allocator = std::make_shared<CustomInSandboxAllocator>(group); + group.SetInSandboxAllocator(allocator); + + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> array_buffer_allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = array_buffer_allocator.get(); + + v8::Isolate* isolate = v8::Isolate::New(group, create_params); + std::unique_ptr<v8::BackingStore> backing_store = + v8::ArrayBuffer::NewBackingStore(isolate, 200); + CHECK_EQ(backing_store->Data(), allocator->allocated_address()); + + backing_store.reset(); + isolate->Dispose(); +} + class CustomArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: explicit CustomArrayBufferAllocator(v8::IsolateGroup& group) @@ -15528,159 +15639,6 @@ TEST(ObjectClone) { .FromJust()); } - -class OneByteVectorResource : public v8::String::ExternalOneByteStringResource { - public: - explicit OneByteVectorResource(v8::base::Vector<const char> vector) - : data_(vector) {} - ~OneByteVectorResource() override = default; - size_t length() const override { return data_.length(); } - const char* data() const override { return data_.begin(); } - void Dispose() override {} - - private: - v8::base::Vector<const char> data_; -}; - - -class UC16VectorResource : public v8::String::ExternalStringResource { - public: - explicit UC16VectorResource(v8::base::Vector<const v8::base::uc16> vector) - : data_(vector) {} - ~UC16VectorResource() override = default; - size_t length() const override { return data_.length(); } - const v8::base::uc16* data() const override { return data_.begin(); } - void Dispose() override {} - - private: - v8::base::Vector<const v8::base::uc16> data_; -}; - -static void MorphAString(i::Tagged<i::String> string, - OneByteVectorResource* one_byte_resource, - UC16VectorResource* uc16_resource) { - i::Isolate* isolate = CcTest::i_isolate(); - CHECK(i::StringShape(string).IsExternal()); - i::ReadOnlyRoots roots(CcTest::heap()); - if (string->IsOneByteRepresentation()) { - // Check old map is not internalized or long. - CHECK(string->map() == roots.external_one_byte_string_map()); - // Morph external string to be TwoByte string. - string->set_map(isolate, roots.external_two_byte_string_map()); - i::Tagged<i::ExternalTwoByteString> morphed = - i::Cast<i::ExternalTwoByteString>(string); - CcTest::heap()->UpdateExternalString(morphed, string->length(), 0); - morphed->SetResource(isolate, uc16_resource); - } else { - // Check old map is not internalized or long. - CHECK(string->map() == roots.external_two_byte_string_map()); - // Morph external string to be one-byte string. - string->set_map(isolate, roots.external_one_byte_string_map()); - i::Tagged<i::ExternalOneByteString> morphed = - i::Cast<i::ExternalOneByteString>(string); - CcTest::heap()->UpdateExternalString(morphed, string->length(), 0); - morphed->SetResource(isolate, one_byte_resource); - } -} - -// Test that we can still flatten a string if the components it is built up -// from have been turned into 16 bit strings in the mean time. -THREADED_TEST(MorphCompositeStringTest) { - char utf_buffer[129]; - const char* c_string = "Now is the time for all good men" - " to come to the aid of the party"; - uint16_t* two_byte_string = AsciiToTwoByteString(c_string); - { - LocalContext env; - i::Factory* factory = CcTest::i_isolate()->factory(); - v8::Isolate* isolate = env.isolate(); - i::Isolate* i_isolate = CcTest::i_isolate(); - v8::HandleScope scope(isolate); - OneByteVectorResource one_byte_resource( - v8::base::Vector<const char>(c_string, strlen(c_string))); - UC16VectorResource uc16_resource( - v8::base::Vector<const uint16_t>(two_byte_string, strlen(c_string))); - - Local<String> lhs(v8::Utils::ToLocal( - factory->NewExternalStringFromOneByte(&one_byte_resource) - .ToHandleChecked())); - Local<String> rhs(v8::Utils::ToLocal( - factory->NewExternalStringFromOneByte(&one_byte_resource) - .ToHandleChecked())); - - CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust()); - CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust()); - - CompileRun( - "var cons = lhs + rhs;" - "var slice = lhs.substring(1, lhs.length - 1);" - "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); - - CHECK(lhs->IsOneByte()); - CHECK(rhs->IsOneByte()); - - i::DirectHandle<i::String> ilhs = v8::Utils::OpenDirectHandle(*lhs); - i::DirectHandle<i::String> irhs = v8::Utils::OpenDirectHandle(*rhs); - MorphAString(*ilhs, &one_byte_resource, &uc16_resource); - MorphAString(*irhs, &one_byte_resource, &uc16_resource); - - // This should UTF-8 without flattening, since everything is ASCII. - Local<String> cons = - v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>(); - CHECK_EQ(128, cons->Utf8Length(isolate)); - CHECK_EQ(129, cons->WriteUtf8(isolate, utf_buffer, sizeof(utf_buffer), - String::WriteFlags::kNullTerminate)); - CHECK_EQ(0, strcmp( - utf_buffer, - "Now is the time for all good men to come to the aid of the party" - "Now is the time for all good men to come to the aid of the party")); - - // Now do some stuff to make sure the strings are flattened, etc. - CompileRun( - "/[^a-z]/.test(cons);" - "/[^a-z]/.test(slice);" - "/[^a-z]/.test(slice_on_cons);"); - const char* expected_cons = - "Now is the time for all good men to come to the aid of the party" - "Now is the time for all good men to come to the aid of the party"; - const char* expected_slice = - "ow is the time for all good men to come to the aid of the part"; - const char* expected_slice_on_cons = - "ow is the time for all good men to come to the aid of the party" - "Now is the time for all good men to come to the aid of the part"; - CHECK(v8_str(expected_cons) - ->Equals(env.local(), env->Global() - ->Get(env.local(), v8_str("cons")) - .ToLocalChecked()) - .FromJust()); - CHECK(v8_str(expected_slice) - ->Equals(env.local(), env->Global() - ->Get(env.local(), v8_str("slice")) - .ToLocalChecked()) - .FromJust()); - CHECK(v8_str(expected_slice_on_cons) - ->Equals(env.local(), - env->Global() - ->Get(env.local(), v8_str("slice_on_cons")) - .ToLocalChecked()) - .FromJust()); - - // This avoids the GC from trying to free a stack allocated resource. - if (IsExternalOneByteString(*ilhs)) { - i::Cast<i::ExternalOneByteString>(*ilhs)->SetResource(i_isolate, nullptr); - } else { - i::Cast<i::ExternalTwoByteString>(*ilhs)->SetResource(i_isolate, nullptr); - } - if (IsExternalOneByteString(*irhs)) { - i::Cast<i::ExternalOneByteString>(*irhs)->SetResource(i_isolate, nullptr); - } else { - i::Cast<i::ExternalTwoByteString>(*irhs)->SetResource(i_isolate, nullptr); - } - } - i::DeleteArray(two_byte_string); -} - - TEST(CompileExternalTwoByteSource) { LocalContext context; v8::HandleScope scope(context.isolate()); @@ -16362,8 +16320,8 @@ TEST(ErrorLevelWarning) { v8::Isolate::kMessageAll); for (size_t i = 0; i < arraysize(levels); i++) { i::MessageLocation location(script, 0, 0); - i::DirectHandle<i::String> msg(i_isolate->factory()->InternalizeString( - v8::base::StaticCharVector("test"))); + i::DirectHandle<i::String> msg( + i_isolate->factory()->InternalizeString("test")); i::DirectHandle<i::JSMessageObject> message = i::MessageHandler::MakeMessageObject( i_isolate, i::MessageTemplate::kDataCloneError, &location, msg); @@ -18222,7 +18180,7 @@ TEST(Regress528) { context->Enter(); Local<v8::String> obj = v8_str(""); - context->SetEmbedderDataV2(0, obj); + context->SetEmbedderDataV3(0, obj); CompileRun(source_simple); context->Exit(); } @@ -19406,15 +19364,15 @@ static int CalcFibonacci(v8::Isolate* isolate, int limit) { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope scope(isolate); LocalContext context(isolate); - auto code = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(code.as_vector(), + std::array<char, 1024> code; + v8::base::SNPrintF(code, "function fib(n) {" " if (n <= 2) return 1;" " return fib(n-1) + fib(n-2);" "}" "fib(%d)", limit); - Local<Value> value = CompileRun(code.begin()); + Local<Value> value = CompileRun(code.data()); CHECK(value->IsNumber()); return static_cast<int>(value->NumberValue(context.local()).FromJust()); } @@ -19781,17 +19739,25 @@ TEST(RegExp) { ExpectTrue("ex instanceof SyntaxError"); } - // RegExp::Exec. + // RegExp::Exec / RegExp::ExecV2. { v8::Local<v8::RegExp> regexp = v8::RegExp::New(context.local(), v8_str("a.c"), {}).ToLocalChecked(); - v8::Local<v8::Object> result0 = - regexp->Exec(context.local(), v8_str("abc")).ToLocalChecked(); + v8::Local<v8::Value> result0 = + regexp->ExecV2(context.local(), v8_str("abc")).ToLocalChecked(); CHECK(result0->IsArray()); - v8::Local<v8::Object> result1 = - regexp->Exec(context.local(), v8_str("abd")).ToLocalChecked(); - // TODO(jgruber): Fix the API; `v8::Null` is not a valid `v8::Object`. + v8::Local<v8::Value> result1 = + regexp->ExecV2(context.local(), v8_str("abd")).ToLocalChecked(); CHECK(result1->IsNull()); + + START_ALLOW_USE_DEPRECATED(); + v8::Local<v8::Object> deprecated_result0 = + regexp->Exec(context.local(), v8_str("abc")).ToLocalChecked(); + CHECK(deprecated_result0->IsArray()); + v8::Local<v8::Object> deprecated_result1 = + regexp->Exec(context.local(), v8_str("abd")).ToLocalChecked(); + CHECK(deprecated_result1->IsNull()); + END_ALLOW_USE_DEPRECATED(); } } @@ -21994,10 +21960,9 @@ void CheckCorrectThrow(const char* script) { // The subsequent try-catch should run without any exception. access_check_fail_thrown = false; catch_callback_called = false; - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(source.as_vector(), - "try { %s; } catch (e) { catcher(e); }", script); - CompileRun(source.begin()); + std::array<char, 1024> source; + v8::base::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); + CompileRun(source.data()); CHECK(access_check_fail_thrown); CHECK(catch_callback_called); @@ -22896,24 +22861,24 @@ class ApiCallOptimizationChecker { } } // build wrap_function - auto wrap_function = v8::base::OwnedVector<char>::NewForOverwrite(200); + std::array<char, 200> wrap_function; if (global) { - v8::base::SNPrintF(wrap_function.as_vector(), + v8::base::SNPrintF(wrap_function, "function wrap_f_%d() { var f = g_f; return f(); }\n" "function wrap_get_%d() { return this.g_acc; }\n" "function wrap_set_%d() { return this.g_acc = 1; }\n", key, key, key); } else { v8::base::SNPrintF( - wrap_function.as_vector(), + wrap_function, "function wrap_f_%d() { return receiver_subclass.f(); }\n" "function wrap_get_%d() { return receiver_subclass.acc; }\n" "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n", key, key, key); } // build source string - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1000); - v8::base::SNPrintF(source.as_vector(), + std::array<char, 1000> source; + v8::base::SNPrintF(source, "%s\n" // wrap functions "function wrap_f() { return wrap_f_%d(); }\n" "function wrap_get() { return wrap_get_%d(); }\n" @@ -22942,10 +22907,10 @@ class ApiCallOptimizationChecker { "check(wrap_set());\n" "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n" "check(wrap_set());\n", - wrap_function.begin(), key, key, key, key, key, key, key, + wrap_function.data(), key, key, key, key, key, key, key, key, key); v8::TryCatch try_catch(isolate); - CompileRun(source.begin()); + CompileRun(source.data()); CHECK(!try_catch.HasCaught()); CHECK_EQ(9, count); @@ -24375,6 +24340,60 @@ TEST(ScriptSourceURLAndSourceMappingURL) { "function foo() {}\n" "//# sourceMappingURL= data:application/json,{\"version\":3} \n", nullptr, "data:application/json,{\"version\":3}"); + + // A value can end at the end of the input. + SourceURLHelper(isolate, + "function foo() {}\n" + "//# sourceURL=bar25.js", + "bar25.js", nullptr); + SourceURLHelper(isolate, + "function foo() {}\n" + "//# sourceMappingURL=bar26.js", + nullptr, "bar26.js"); + + // Other line terminators. + SourceURLHelper(isolate, + "function foo() {}\r\n" + "//# sourceURL=bar27.js\r\n" + "//# sourceMappingURL=bar28.js\r\n" + "function baz() {}\r\n", + "bar27.js", "bar28.js"); + SourceURLHelper(isolate, + "function foo() {}\n" + "//# sourceURL=bar29.js\xE2\x80\xA8" + "function baz() {}\n", + "bar29.js", nullptr); + + // The deprecated //@ form. + SourceURLHelper(isolate, + "function foo() {}\n" + "//@ sourceURL=bar30.js\n" + "//@ sourceMappingURL=bar31.js\n", + "bar30.js", "bar31.js"); + + // A malformed or empty last comment removes an earlier value. + SourceURLHelper(isolate, + "function foo() {}\n" + "//# sourceURL=bar32.js\n" + "//# sourceURL=bar33 .js\n" + "//# sourceMappingURL=bar34.js\n" + "//# sourceMappingURL=\n", + nullptr, nullptr); + + // Non-Latin1 characters in the source and in the value. + SourceURLHelper(isolate, + "var s = '\xD7\xA9';\n" + "//# sourceURL=b\xC3\xA4r35\xF0\x9F\x98\x80.js\n", + "b\xC3\xA4r35\xF0\x9F\x98\x80.js", nullptr); + + // Long values. + std::string long_url = std::format("https://example.com/{:x>1000}.js", ""); + std::string long_map_url = long_url + ".map"; + std::string long_source = std::format( + "function foo() {{}}\n//# sourceURL={}\n//# sourceMappingURL={}\n", + long_url, long_map_url); + SourceURLHelper(isolate, long_source.c_str(), long_url.c_str(), + long_map_url.c_str()); } @@ -25783,7 +25802,7 @@ TEST(ModuleEvaluateImportTerminateExecution) { // The exception thrown by terminate execution is not catchable by JavaScript // so the promise can not be settled. CHECK_EQ(promise->State(), v8::Promise::kPending); - CHECK_EQ(module->GetStatus(), Module::kEvaluated); + CHECK_EQ(module->GetStatus(), Module::kErrored); CHECK(try_catch.HasCaught()); CHECK(try_catch.HasTerminated()); } @@ -26028,6 +26047,322 @@ TEST(StreamingScriptWithSourceMappingURLInTheMiddle) { nullptr, "bar2.js"); } +namespace { + +i::DirectHandle<i::Script> GetScript(v8::Isolate* isolate, + Local<v8::UnboundScript> script) { + return i::direct_handle( + i::Cast<i::Script>(v8::Utils::OpenDirectHandle(*script)->script()), + reinterpret_cast<i::Isolate*>(isolate)); +} + +i::DirectHandle<i::Script> GetScript(v8::Isolate* isolate, + Local<v8::UnboundModuleScript> script) { + return i::direct_handle( + i::Cast<i::Script>(v8::Utils::OpenDirectHandle(*script)->script()), + reinterpret_cast<i::Isolate*>(isolate)); +} + +i::DirectHandle<i::Script> GetScript(v8::Isolate* isolate, + Local<v8::Function> function) { + return i::direct_handle( + i::Cast<i::Script>( + i::Cast<i::JSFunction>(*v8::Utils::OpenDirectHandle(*function)) + ->shared() + ->script()), + reinterpret_cast<i::Isolate*>(isolate)); +} + +v8::MaybeLocal<Script> CompileStreamedScript(LocalContext* env, + const char** chunks, + Local<v8::String> full_source, + const v8::ScriptOrigin& origin) { + v8::ScriptCompiler::StreamedSource source( + std::make_unique<i::TestSourceStream>(chunks), + v8::ScriptCompiler::StreamedSource::UTF8); + std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task( + v8::ScriptCompiler::StartStreaming(env->isolate(), &source)); + StreamerThread::StartThreadForTaskAndJoin(task.get(), env->i_isolate()); + return v8::ScriptCompiler::Compile(env->local(), &source, full_source, + origin); +} + +std::string SourceWithMagicComments(std::string_view body, + std::string_view value) { + return std::format( + "{0}\n//# sourceURL={1}\n//# sourceMappingURL={1}\n//# debugId={1}\n", + body, value); +} + +// Checks that the debug magic comment values of {script} are {value}: the +// source map URL as a substring of the script source, the source URL and debug +// ID as sequential strings. +void CheckMagicCommentValuesAreSourceSubstrings( + i::DirectHandle<i::Script> script, const std::string& value) { + i::Tagged<i::Object> source_mapping_url = script->source_mapping_url(); + CHECK(i::IsSlicedString(source_mapping_url)); + CHECK_EQ(i::Cast<i::SlicedString>(source_mapping_url)->parent(), + script->source()); + i::Tagged<i::Object> fields[] = {source_mapping_url, script->source_url(), + script->debug_id()}; + for (i::Tagged<i::Object> field : fields) { + if (field != source_mapping_url) CHECK(i::IsSeqString(field)); + CHECK(i::Cast<i::String>(field)->IsEqualTo( + v8::base::OneByteVector(value.data(), value.size()))); + } +} + +} // namespace + +TEST(MagicCommentValuesAreSourceSubstrings) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + std::string value = std::format("https://example.com/{:x>100}.js", ""); + + { + std::string source = + SourceWithMagicComments("globalThis.Result = 13;", value); + CheckMagicCommentValuesAreSourceSubstrings( + GetScript(isolate, v8_compile(source.c_str())->GetUnboundScript()), + value); + } + { + std::string source = SourceWithMagicComments("export const x = 13;", value); + v8::ScriptOrigin origin(v8_str("module.js"), 0, 0, false, -1, + Local<Value>(), false, false, true); + v8::ScriptCompiler::Source script_source(v8_str(source.c_str()), origin); + Local<v8::Module> module = + v8::ScriptCompiler::CompileModule(isolate, &script_source) + .ToLocalChecked(); + CheckMagicCommentValuesAreSourceSubstrings( + GetScript(isolate, module->GetUnboundModuleScript()), value); + } + { + std::string source = SourceWithMagicComments("return 13;", value); + v8::ScriptCompiler::Source script_source(v8_str(source.c_str())); + Local<v8::Function> function = + v8::ScriptCompiler::CompileFunction(env.local(), &script_source) + .ToLocalChecked(); + CheckMagicCommentValuesAreSourceSubstrings(GetScript(isolate, function), + value); + } + { + // Streaming creates the values from the full source when finalizing. + std::string source = + SourceWithMagicComments("globalThis.Result = 13;", value); + const char* chunks[] = {source.c_str(), nullptr}; + Local<Script> script = + CompileStreamedScript(&env, chunks, v8_str(source.c_str()), + v8::ScriptOrigin(v8_str("streamed.js"))) + .ToLocalChecked(); + CheckMagicCommentValuesAreSourceSubstrings( + GetScript(isolate, script->GetUnboundScript()), value); + } + { + // Short values are not slices, but still have the right contents. + Local<Script> script = v8_compile( + "//# sourceURL=a.js\n//# sourceMappingURL=b.js\n//# debugId=c\n"); + i::DirectHandle<i::Script> i_script = + GetScript(isolate, script->GetUnboundScript()); + CHECK(i::Cast<i::String>(i_script->source_url())->IsOneByteEqualTo("a.js")); + CHECK(i::Cast<i::String>(i_script->source_mapping_url()) + ->IsOneByteEqualTo("b.js")); + CHECK(i::Cast<i::String>(i_script->debug_id())->IsOneByteEqualTo("c")); + } +} + +// Regression test for https://crbug.com/566467883: the source URL is a +// sequential string rather than a slice of the source, even if it is long +// enough to be one, since it is used as the script name (e.g. DevTools reads it +// from heap snapshots). +TEST(MagicCommentSourceUrlIsSequential) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + const std::string value = "inside-direct-eval.js"; + CHECK_GE(value.size(), i::SlicedString::kMinLength); + auto check = [&](i::DirectHandle<i::Script> script) { + CHECK(i::IsSeqString(script->source_url())); + CHECK(!i::IsSlicedString(script->source_url())); + CHECK(i::Cast<i::String>(script->source_url()) + ->IsEqualTo(v8::base::OneByteVector(value.data(), value.size()))); + }; + + { + std::string source = "globalThis.Result = 13;\n//# sourceURL=" + value; + check(GetScript(isolate, v8_compile(source.c_str())->GetUnboundScript())); + } + { + // Streaming creates the value from the full source when finalizing. + std::string source = "globalThis.Result = 13;\n//# sourceURL=" + value; + const char* chunks[] = {source.c_str(), nullptr}; + Local<Script> script = + CompileStreamedScript(&env, chunks, v8_str(source.c_str()), + v8::ScriptOrigin(v8_str("streamed.js"))) + .ToLocalChecked(); + check(GetScript(isolate, script->GetUnboundScript())); + } + { + // Direct eval. + Local<v8::Function> function = Local<v8::Function>::Cast( + CompileRun("eval('(function evalFunction() {})\\n" + "//# sourceURL=inside-direct-eval.js');")); + check(GetScript(isolate, function)); + } +} + +TEST(ApiSourceMapURLTakesPrecedenceOverMagicComment) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + std::string value = std::format("https://example.com/{:x>100}.map", ""); + std::string source = + "globalThis.Result = 13;\n//# sourceMappingURL=" + value + "\n"; + const char* chunks[] = {source.c_str(), nullptr}; + + for (bool streaming : {false, true}) { + // A non-empty API source map URL takes precedence, an empty one does not. + for (const char* api_url : {"api.js.map", ""}) { + v8::ScriptOrigin origin(v8_str("origin.js"), 0, 0, false, -1, + v8_str(api_url)); + Local<Script> script; + if (streaming) { + script = + CompileStreamedScript(&env, chunks, v8_str(source.c_str()), origin) + .ToLocalChecked(); + } else { + v8::ScriptCompiler::Source script_source(v8_str(source.c_str()), + origin); + script = v8::ScriptCompiler::Compile(env.local(), &script_source) + .ToLocalChecked(); + } + v8::String::Utf8Value url( + isolate, script->GetUnboundScript()->GetSourceMappingURL()); + CHECK_EQ(0, strcmp(*api_url != '\0' ? api_url : value.c_str(), *url)); + // Compile each case from scratch. + CcTest::i_isolate()->compilation_cache()->Clear(); + } + } +} + +TEST(StreamingMagicCommentOutsideOfFullSource) { + // The embedder passes a full source that does not match the streamed one. + // Magic comment locations outside of it must be ignored. + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + const char* chunks[] = {"globalThis.Result = 13;\n", + "//# sourceURL=outside.js\n", + "//# sourceMappingURL=outside.js.map\n", nullptr}; + Local<Script> script = + CompileStreamedScript(&env, chunks, v8_str("globalThis.Result = 13;\n"), + v8::ScriptOrigin(v8_str("streamed.js"))) + .ToLocalChecked(); + i::DirectHandle<i::Script> i_script = + GetScript(isolate, script->GetUnboundScript()); + CHECK(i::IsUndefined(i_script->source_url())); + CHECK(i::IsUndefined(i_script->source_mapping_url())); +} + +// Regression test for https://github.com/nodejs/node/issues/64155: a huge +// magic comment value (e.g. an inline source map) must not be copied onto the +// heap. +UNINITIALIZED_TEST(HugeMagicCommentValueDoesNotOOM) { + i::v8_flags.stress_concurrent_allocation = false; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + create_params.constraints.set_max_old_generation_size_in_bytes(16 * i::MB); + v8::Isolate* isolate = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope scope(isolate); + LocalContext env(isolate); + + const std::string url_prefix = "data:application/json;base64,"; + const size_t kPayloadLength = 40 * i::MB; + enum class Mode { kScript, kModule, kFunction, kStreaming }; + for (Mode mode : + {Mode::kScript, Mode::kModule, Mode::kFunction, Mode::kStreaming}) { + // The source URL and debug ID are sequential copies, so huge ones are + // still copied. + for (const char* name : {"sourceMappingURL"}) { + v8::HandleScope inner_scope(isolate); + std::string header = std::format( + "{}\n//# {}=", + mode == Mode::kFunction ? "return 13;" : "globalThis.Result = 13;", + name); + size_t value_offset = header.size(); + size_t value_length = url_prefix.size() + kPayloadLength; + size_t length = value_offset + value_length + 1; + char* data = i::NewArray<char>(length + 1); + memcpy(data, header.data(), header.size()); + memcpy(data + value_offset, url_prefix.data(), url_prefix.size()); + memset(data + value_offset + url_prefix.size(), 'A', kPayloadLength); + data[length - 1] = '\n'; + data[length] = '\0'; + + // The source is external, so it does not count against the heap + // limit, but a copy of the magic comment value would. + Local<v8::String> source = v8::String::NewExternalOneByte( + isolate, new TestOneByteResource(data)) + .ToLocalChecked(); + i::DirectHandle<i::Script> script; + switch (mode) { + case Mode::kScript: { + v8::ScriptCompiler::Source script_source(source); + script = + GetScript(isolate, v8::ScriptCompiler::CompileUnboundScript( + isolate, &script_source) + .ToLocalChecked()); + break; + } + case Mode::kModule: { + v8::ScriptOrigin origin( + v8::String::NewFromUtf8Literal(isolate, "module.js"), 0, 0, + false, -1, Local<Value>(), false, false, true); + v8::ScriptCompiler::Source script_source(source, origin); + script = GetScript(isolate, v8::ScriptCompiler::CompileModule( + isolate, &script_source) + .ToLocalChecked() + ->GetUnboundModuleScript()); + break; + } + case Mode::kFunction: { + v8::ScriptCompiler::Source script_source(source); + script = GetScript(isolate, v8::ScriptCompiler::CompileFunction( + env.local(), &script_source) + .ToLocalChecked()); + break; + } + case Mode::kStreaming: { + const char* chunks[] = {data, nullptr}; + script = GetScript( + isolate, CompileStreamedScript( + &env, chunks, source, + v8::ScriptOrigin(v8::String::NewFromUtf8Literal( + isolate, "streamed.js"))) + .ToLocalChecked() + ->GetUnboundScript()); + break; + } + } + i::Tagged<i::Object> value = script->source_mapping_url(); + i::DirectHandle<i::String> value_string( + i::Cast<i::String>(value), reinterpret_cast<i::Isolate*>(isolate)); + + // Force a full GC while the value is alive: a heap copy of the value + // would exceed the heap limit here even if its allocation succeeded. + isolate->LowMemoryNotification(); + + CHECK(value_string->IsEqualTo( + v8::base::OneByteVector(data + value_offset, value_length))); + } + } + } + isolate->Dispose(); +} + void GetCurrentHostDefinedOptionsTest( const v8::FunctionCallbackInfo<Value>& info) { v8::Local<v8::Data> host_defined_options = @@ -26809,29 +27144,29 @@ TEST(ObjectTemplateArrayProtoIntrinsics) { }; for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) { - auto test_string = v8::base::OwnedVector<char>::NewForOverwrite(64); + std::array<char, 64> test_string; - v8::base::SNPrintF(test_string.as_vector(), "typeof obj1.%s", + v8::base::SNPrintF(test_string, "typeof obj1.%s", intrinsics_comparisons[i].object_property_name); - ExpectString(test_string.begin(), "function"); + ExpectString(test_string.data(), "function"); - v8::base::SNPrintF(test_string.as_vector(), "obj1.%s === %s", + v8::base::SNPrintF(test_string, "obj1.%s === %s", intrinsics_comparisons[i].object_property_name, intrinsics_comparisons[i].array_property_name); - ExpectTrue(test_string.begin()); + ExpectTrue(test_string.data()); - v8::base::SNPrintF(test_string.as_vector(), "obj1.%s = 42", + v8::base::SNPrintF(test_string, "obj1.%s = 42", intrinsics_comparisons[i].object_property_name); - CompileRun(test_string.begin()); + CompileRun(test_string.data()); - v8::base::SNPrintF(test_string.as_vector(), "obj1.%s === %s", + v8::base::SNPrintF(test_string, "obj1.%s === %s", intrinsics_comparisons[i].object_property_name, intrinsics_comparisons[i].array_property_name); - ExpectFalse(test_string.begin()); + ExpectFalse(test_string.data()); - v8::base::SNPrintF(test_string.as_vector(), "typeof obj1.%s", + v8::base::SNPrintF(test_string, "typeof obj1.%s", intrinsics_comparisons[i].object_property_name); - ExpectString(test_string.begin(), "number"); + ExpectString(test_string.data(), "number"); } } @@ -27340,10 +27675,10 @@ TEST(CorrectEnteredContext) { v8::HandleScope scope(CcTest::isolate()); LocalContext currentContext; - currentContext->SetEmbedderDataV2( + currentContext->SetEmbedderDataV3( 1, v8::Integer::New(currentContext.isolate(), CurrentContext)); LocalContext enteredContext; - enteredContext->SetEmbedderDataV2( + enteredContext->SetEmbedderDataV3( 1, v8::Integer::New(enteredContext.isolate(), EnteredContext)); v8::Context::Scope contextScope(enteredContext.local()); @@ -32445,8 +32780,11 @@ TEST(EmbedderDataAlignedPointers_CppHeapPointer) { cpp_heap->GetAllocationHandle())); // Null pointer test. + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V2. (*env)->SetAlignedPointerInEmbedderData( 0, static_cast<TestGarbagedCollectedData*>(nullptr), i::kTagForTesting); + END_ALLOW_USE_DEPRECATED() CHECK_EQ( nullptr, (*env)->GetAlignedPointerFromEmbedderData<TestGarbagedCollectedData>( @@ -32455,8 +32793,11 @@ TEST(EmbedderDataAlignedPointers_CppHeapPointer) { isolate, 0, i::kTagForTesting)); // Valid cppgc object test. + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V2. (*env)->SetAlignedPointerInEmbedderData(1, cpp_object.Get(), i::kTagForTesting); + END_ALLOW_USE_DEPRECATED() CHECK_EQ( cpp_object.Get(), (*env)->GetAlignedPointerFromEmbedderData<TestGarbagedCollectedData>( @@ -32467,8 +32808,69 @@ TEST(EmbedderDataAlignedPointers_CppHeapPointer) { // Detached global proxy test. v8::Local<v8::Object> global_obj = env->Global(); + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V2. (*env)->SetAlignedPointerInEmbedderData(2, cpp_object.Get(), i::kTagForTesting); + END_ALLOW_USE_DEPRECATED() + CHECK_EQ(cpp_object.Get(), + global_obj->GetAlignedPointerFromEmbedderDataInCreationContext( + isolate, 2, i::kTagForTesting)); + + env->DetachGlobal(); + CHECK_EQ(cpp_object.Get(), + global_obj->GetAlignedPointerFromEmbedderDataInCreationContext( + isolate, 2, i::kTagForTesting)); + } + + isolate->Exit(); + isolate->Dispose(); +} + +TEST(EmbedderDataAlignedPointersV2_CppHeapPointer) { + v8::Isolate::CreateParams create_params = CreateTestParams(); + create_params.cpp_heap = + v8::CppHeap::Create(::v8::internal::V8::GetCurrentPlatform(), + v8::CppHeapCreateParams({})) + .release(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + isolate->Enter(); + v8::CppHeap* cpp_heap = isolate->GetCppHeap(); + + { + v8::HandleScope scope(isolate); + LocalContext env(isolate); + v8::Local<v8::Object> obj = v8::Object::New(isolate); + + cppgc::Persistent<TestGarbagedCollectedData> cpp_object( + cppgc::MakeGarbageCollected<TestGarbagedCollectedData>( + cpp_heap->GetAllocationHandle())); + + // Null pointer test. + (*env)->SetAlignedPointerInEmbedderDataV2( + 0, static_cast<TestGarbagedCollectedData*>(nullptr), i::kTagForTesting); + CHECK_EQ( + nullptr, + (*env)->GetAlignedPointerFromEmbedderData<TestGarbagedCollectedData>( + isolate, 0, i::kTagForTesting)); + CHECK_EQ(nullptr, obj->GetAlignedPointerFromEmbedderDataInCreationContext( + isolate, 0, i::kTagForTesting)); + + // Valid cppgc object test. + (*env)->SetAlignedPointerInEmbedderDataV2(1, cpp_object.Get(), + i::kTagForTesting); + CHECK_EQ( + cpp_object.Get(), + (*env)->GetAlignedPointerFromEmbedderData<TestGarbagedCollectedData>( + isolate, 1, i::kTagForTesting)); + CHECK_EQ(cpp_object.Get(), + obj->GetAlignedPointerFromEmbedderDataInCreationContext( + isolate, 1, i::kTagForTesting)); + + // Detached global proxy test. + v8::Local<v8::Object> global_obj = env->Global(); + (*env)->SetAlignedPointerInEmbedderDataV2(2, cpp_object.Get(), + i::kTagForTesting); CHECK_EQ(cpp_object.Get(), global_obj->GetAlignedPointerFromEmbedderDataInCreationContext( isolate, 2, i::kTagForTesting)); @@ -32617,3 +33019,60 @@ TEST(IsolateFree) { v8::Isolate::Free(isolate1); v8::Isolate::Free(isolate2); } + +#ifdef V8_ENABLE_MAGLEV +TEST(MaglevFastProxyCheckTrapResultLazyDeopt) { + if (i::v8_flags.jitless) return; + if (i::v8_flags.disable_optimizing_compilers) return; + if (!i::v8_flags.maglev) return; + + i::v8_flags.allow_natives_syntax = true; + i::v8_flags.fast_proxy_ic = true; + i::v8_flags.optimize_on_next_call_optimizes_to_maglev = true; + + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + + v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); + templ->SetNativeDataProperty( + v8_str("prop"), [](v8::Local<v8::Name> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Local<v8::Context> ctx = info.GetIsolate()->GetCurrentContext(); + v8::Local<v8::Value> trigger = + ctx->Global()->Get(ctx, v8_str("trigger_deopt")).ToLocalChecked(); + if (trigger->BooleanValue(info.GetIsolate())) { + CHECK(ctx->Global() + ->Set(ctx, v8_str("global_dep"), v8_num(2)) + .FromJust()); + } + info.GetReturnValue().Set(v8_num(100)); + }); + + v8::Local<v8::Object> target = templ->NewInstance(context).ToLocalChecked(); + v8::Local<v8::Object> target2 = templ->NewInstance(context).ToLocalChecked(); + CHECK(target2->Set(context, v8_str("extra"), v8_num(1)).FromJust()); + CHECK(context->Global()->Set(context, v8_str("target"), target).FromJust()); + + ExpectInt32( + "var global_dep = 1;" + "var trigger_deopt = false;" + "var mutate_target = false;" + "function get_trap(t, p, r) {" + " if (mutate_target) { t.extra = 1; trigger_deopt = true; }" + " return 42;" + "}" + "%NeverOptimizeFunction(get_trap);" + "const handler = { get: get_trap };" + "const proxy = new Proxy(target, handler);" + "function f(p) { return p.prop + global_dep - global_dep; }" + "%PrepareFunctionForOptimization(f);" + "f(proxy);" + "%OptimizeFunctionOnNextCall(f);" + "f(proxy);" + "mutate_target = true;" + "f(proxy);", + 42); +} +#endif // V8_ENABLE_MAGLEV diff --git a/deps/v8/test/cctest/test-code-stub-assembler.cc b/deps/v8/test/cctest/test-code-stub-assembler.cc index 6f4ad2c4fab6..094671c8c502 100644 --- a/deps/v8/test/cctest/test-code-stub-assembler.cc +++ b/deps/v8/test/cctest/test-code-stub-assembler.cc @@ -3977,83 +3977,6 @@ TEST(SingleInputPhiElimination) { // single-input phi is properly eliminated. } -TEST(SmallOrderedHashMapAllocate) { - Isolate* isolate(CcTest::InitIsolateOnce()); - const int kNumParams = 1; - CodeAssemblerTester asm_tester(isolate, JSParameterCount(kNumParams)); - { - CodeStubAssembler m(asm_tester.state()); - auto capacity = m.Parameter<Smi>(1); - m.Return(m.AllocateSmallOrderedHashMap(m.SmiToIntPtr(capacity))); - } - FunctionTester ft(asm_tester.GenerateCode(), kNumParams); - - Factory* factory = isolate->factory(); - int capacity = SmallOrderedHashMap::kMinCapacity; - while (capacity <= SmallOrderedHashMap::kMaxCapacity) { - DirectHandle<SmallOrderedHashMap> expected = - factory->NewSmallOrderedHashMap(capacity); - DirectHandle<Object> result_raw = - ft.Call(Handle<Smi>(Smi::FromInt(capacity), isolate)).ToHandleChecked(); - DirectHandle<SmallOrderedHashMap> actual = - DirectHandle<SmallOrderedHashMap>( - Cast<SmallOrderedHashMap>(*result_raw), isolate); - CHECK_EQ(capacity, actual->Capacity()); - CHECK_EQ(0, actual->NumberOfElements()); - CHECK_EQ(0, actual->NumberOfDeletedElements()); - CHECK_EQ(capacity / SmallOrderedHashMap::kLoadFactor, - actual->NumberOfBuckets()); - CHECK_EQ(0, memcmp(reinterpret_cast<void*>(expected->address()), - reinterpret_cast<void*>(actual->address()), - SmallOrderedHashMap::SizeFor(capacity))); -#ifdef VERIFY_HEAP - actual->SmallOrderedHashMapVerify(isolate); -#endif - capacity = capacity << 1; - } -#ifdef VERIFY_HEAP - HeapVerifier::VerifyHeap(isolate->heap()); -#endif -} - -TEST(SmallOrderedHashSetAllocate) { - Isolate* isolate(CcTest::InitIsolateOnce()); - const int kNumParams = 1; - CodeAssemblerTester asm_tester(isolate, JSParameterCount(kNumParams)); - { - CodeStubAssembler m(asm_tester.state()); - auto capacity = m.Parameter<Smi>(1); - m.Return(m.AllocateSmallOrderedHashSet(m.SmiToIntPtr(capacity))); - } - FunctionTester ft(asm_tester.GenerateCode(), kNumParams); - - int capacity = SmallOrderedHashSet::kMinCapacity; - Factory* factory = isolate->factory(); - while (capacity <= SmallOrderedHashSet::kMaxCapacity) { - DirectHandle<SmallOrderedHashSet> expected = - factory->NewSmallOrderedHashSet(capacity); - DirectHandle<Object> result_raw = - ft.Call(Handle<Smi>(Smi::FromInt(capacity), isolate)).ToHandleChecked(); - DirectHandle<SmallOrderedHashSet> actual( - Cast<SmallOrderedHashSet>(*result_raw), isolate); - CHECK_EQ(capacity, actual->Capacity()); - CHECK_EQ(0, actual->NumberOfElements()); - CHECK_EQ(0, actual->NumberOfDeletedElements()); - CHECK_EQ(capacity / SmallOrderedHashSet::kLoadFactor, - actual->NumberOfBuckets()); - CHECK_EQ(0, memcmp(reinterpret_cast<void*>(expected->address()), - reinterpret_cast<void*>(actual->address()), - SmallOrderedHashSet::SizeFor(capacity))); -#ifdef VERIFY_HEAP - actual->SmallOrderedHashSetVerify(isolate); -#endif - capacity = capacity << 1; - } -#ifdef VERIFY_HEAP - HeapVerifier::VerifyHeap(isolate->heap()); -#endif -} - TEST(IsDoubleElementsKind) { Isolate* isolate(CcTest::InitIsolateOnce()); const int kNumParams = 2; diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 1600323a222f..92f5d827b1d5 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -27,6 +27,7 @@ // // Tests of the CPU profiler and utilities. +#include <array> #include <limits> #include <memory> @@ -39,6 +40,7 @@ #include "src/api/api-inl.h" #include "src/base/platform/platform.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/codegen/compilation-cache.h" #include "src/codegen/source-position-table.h" #include "src/deoptimizer/deoptimize-reason.h" @@ -123,7 +125,8 @@ TEST(StartStop) { std::unique_ptr<ProfilerEventsProcessor> processor( new SamplingEventsProcessor( isolate, &symbolizer, &code_observer, &profiles, - v8::base::TimeDelta::FromMicroseconds(100), true)); + v8::base::TimeDelta::FromMicroseconds(100), true, + /* sample_context_extractor */ nullptr)); CHECK(processor->Start()); processor->StopSynchronously(); } @@ -166,11 +169,11 @@ class TestSetup { i::Tagged<i::AbstractCode> CreateCode(i::Isolate* isolate, LocalContext* env) { static int counter = 0; - base::EmbeddedVector<char, 256> script; - base::EmbeddedVector<char, 32> name; + std::array<char, 256> script; + std::array<char, 32> name; base::SNPrintF(name, "function_%d", ++counter); - const char* name_start = name.begin(); + const char* name_start = name.data(); base::SNPrintF(script, "function %s() {\n" "var counter = 0;\n" @@ -179,7 +182,7 @@ i::Tagged<i::AbstractCode> CreateCode(i::Isolate* isolate, LocalContext* env) { "}\n" "%s();\n", name_start, counter, name_start, name_start); - CompileRun(script.begin()); + CompileRun(script.data()); i::DirectHandle<i::JSFunction> fun = i::Cast<i::JSFunction>( v8::Utils::OpenDirectHandle(*GetFunction(env->local(), name_start))); @@ -208,9 +211,10 @@ TEST(CodeEvents) { ProfilerCodeObserver code_observer(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer.instruction_stream_map()); - ProfilerEventsProcessor* processor = new SamplingEventsProcessor( - isolate, symbolizer, &code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(100), true); + ProfilerEventsProcessor* processor = + new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles, + v8::base::TimeDelta::FromMicroseconds(100), + true, /* sample_context_extractor */ nullptr); CHECK(processor->Start()); ProfilerListener profiler_listener(isolate, processor, *code_observer.code_entries(), @@ -289,7 +293,8 @@ TEST(TickEvents) { new Symbolizer(code_observer->instruction_stream_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( CcTest::i_isolate(), symbolizer, code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(100), true); + v8::base::TimeDelta::FromMicroseconds(100), true, + /* sample_context_extractor */ nullptr); CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, symbolizer, processor, code_observer); ProfilerId id = profiles->StartProfiling().id; @@ -453,7 +458,8 @@ TEST(Issue1398) { new Symbolizer(code_observer->instruction_stream_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( CcTest::i_isolate(), symbolizer, code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(100), true); + v8::base::TimeDelta::FromMicroseconds(100), true, + /* sample_context_extractor */ nullptr); CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, symbolizer, processor, code_observer); ProfilerId id = profiles->StartProfiling("").id; @@ -603,7 +609,8 @@ class ProfilerHelper { unsigned min_js_samples = 0, unsigned min_external_samples = 0, ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers, unsigned max_samples = v8::CpuProfilingOptions::kNoSampleLimit, - v8::Local<v8::Context> context = v8::Local<v8::Context>()); + v8::Local<v8::Context> context = v8::Local<v8::Context>(), + v8::SampleContextExtractor sample_context_extractor = nullptr); v8::CpuProfiler* profiler() { return profiler_; } @@ -612,16 +619,17 @@ class ProfilerHelper { v8::CpuProfiler* profiler_; }; -v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function, - v8::Local<v8::Value> argv[], int argc, - unsigned min_js_samples, - unsigned min_external_samples, - ProfilingMode mode, unsigned max_samples, - v8::Local<v8::Context> context) { +v8::CpuProfile* ProfilerHelper::Run( + v8::Local<v8::Function> function, v8::Local<v8::Value> argv[], int argc, + unsigned min_js_samples, unsigned min_external_samples, ProfilingMode mode, + unsigned max_samples, v8::Local<v8::Context> context, + v8::SampleContextExtractor sample_context_extractor) { v8::Local<v8::String> profile_name = v8_str("my_profile"); profiler_->SetSamplingInterval(20); - profiler_->StartProfiling(profile_name, {mode, max_samples, 0, context}); + profiler_->StartProfiling(profile_name, {mode, max_samples, 0, context, + v8::CpuProfileSource::kUnspecified, + sample_context_extractor}); v8::internal::CpuProfiler* iprofiler = reinterpret_cast<v8::internal::CpuProfiler*>(profiler_); @@ -1294,9 +1302,9 @@ static void TickLines(bool optimize) { // Ensure that source positions are collected everywhere. isolate->SetIsProfiling(true); - base::EmbeddedVector<char, 512> script; - base::EmbeddedVector<char, 64> prepare_opt; - base::EmbeddedVector<char, 64> optimize_call; + std::array<char, 512> script; + std::array<char, 64> prepare_opt; + std::array<char, 64> optimize_call; const char* func_name = "func"; if (optimize) { @@ -1324,10 +1332,10 @@ static void TickLines(bool optimize) { "%s();\n" "%s" "%s();\n", - func_name, prepare_opt.begin(), func_name, - optimize_call.begin(), func_name); + func_name, prepare_opt.data(), func_name, optimize_call.data(), + func_name); - CompileRun(script.begin()); + CompileRun(script.data()); i::DirectHandle<i::JSFunction> func = i::Cast<i::JSFunction>( v8::Utils::OpenDirectHandle(*GetFunction(env.local(), func_name))); @@ -1348,7 +1356,8 @@ static void TickLines(bool optimize) { new Symbolizer(code_observer->instruction_stream_map()); ProfilerEventsProcessor* processor = new SamplingEventsProcessor( CcTest::i_isolate(), symbolizer, code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(100), true); + v8::base::TimeDelta::FromMicroseconds(100), true, + /* sample_context_extractor */ nullptr); CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, symbolizer, processor, code_observer); ProfilerId id = profiles->StartProfiling().id; @@ -1407,7 +1416,7 @@ static void TickLines(bool optimize) { unsigned int line_count = func_node->GetHitLineCount(); CHECK_EQ(2u, line_count); // Expect two hit source lines - #1 and #5. auto entries = - base::OwnedVector<v8::CpuProfileNode::LineTick>::NewForOverwrite( + base::UniqueArray<v8::CpuProfileNode::LineTick>::NewForOverwrite( line_count); CHECK(func_node->GetLineTicks(&entries[0], line_count)); int value = 0; @@ -2626,9 +2635,9 @@ TEST(CollectDeoptEvents) { "\n"; for (int i = 0; i < 3; ++i) { - base::EmbeddedVector<char, sizeof(opt_source) + 100> buffer; + std::array<char, sizeof(opt_source) + 100> buffer; base::SNPrintF(buffer, opt_source, i, i); - v8::Script::Compile(env, v8_str(buffer.begin())) + v8::Script::Compile(env, v8_str(buffer.data())) .ToLocalChecked() ->Run(env) .ToLocalChecked(); @@ -3691,7 +3700,8 @@ TEST(LowPrecisionSamplingStartStopInternal) { std::unique_ptr<ProfilerEventsProcessor> processor( new SamplingEventsProcessor( isolate, &symbolizer, &code_observer, &profiles, - v8::base::TimeDelta::FromMicroseconds(100), false)); + v8::base::TimeDelta::FromMicroseconds(100), false, + /* sample_context_extractor */ nullptr)); CHECK(processor->Start()); processor->StopSynchronously(); } @@ -3806,10 +3816,10 @@ TEST(ProflilerSubsampling) { new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->instruction_stream_map()); - ProfilerEventsProcessor* processor = - new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(1), - /* use_precise_sampling */ true); + ProfilerEventsProcessor* processor = new SamplingEventsProcessor( + isolate, symbolizer, code_observer, profiles, + v8::base::TimeDelta::FromMicroseconds(1), + /* use_precise_sampling */ true, /* sample_context_extractor */ nullptr); CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, symbolizer, processor, code_observer); @@ -3853,10 +3863,10 @@ TEST(DynamicResampling) { new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->instruction_stream_map()); - ProfilerEventsProcessor* processor = - new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(1), - /* use_precise_sampling */ true); + ProfilerEventsProcessor* processor = new SamplingEventsProcessor( + isolate, symbolizer, code_observer, profiles, + v8::base::TimeDelta::FromMicroseconds(1), + /* use_precise_sampling */ true, /* sample_context_extractor */ nullptr); CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, symbolizer, processor, code_observer); @@ -3926,10 +3936,10 @@ TEST(DynamicResamplingWithBaseInterval) { new ProfilerCodeObserver(isolate, storage); Symbolizer* symbolizer = new Symbolizer(code_observer->instruction_stream_map()); - ProfilerEventsProcessor* processor = - new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles, - v8::base::TimeDelta::FromMicroseconds(1), - /* use_precise_sampling */ true); + ProfilerEventsProcessor* processor = new SamplingEventsProcessor( + isolate, symbolizer, code_observer, profiles, + v8::base::TimeDelta::FromMicroseconds(1), + /* use_precise_sampling */ true, /* sample_context_extractor */ nullptr); CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, symbolizer, processor, code_observer); @@ -4310,6 +4320,167 @@ TEST(EmbedderStatePropagateNativeContextMove) { CHECK_NULL(CcTest::i_isolate()->current_embedder_state()); } +namespace { + +// Sentinel value returned by the test extractor. Must be a non-null, +// non-trivial bit pattern so we can distinguish "extractor ran and stored +// its value" from "context never set" (nullptr) and from accidental write +// of zero/one. The extractor counter records how many times the extractor +// was invoked, for sanity-checking. +void* const kSampleContextSentinel = + reinterpret_cast<void*>(static_cast<uintptr_t>(0xCAFE'F00DULL)); + +std::atomic<int> g_extractor_call_count{0}; + +void* TestSampleContextExtractor(v8::Isolate*) { + g_extractor_call_count.fetch_add(1, std::memory_order_relaxed); + return kSampleContextSentinel; +} + +// Samples are requested explicitly rather than waiting for the sampling +// thread, so that the expectations below hold regardless of how slowly the +// build under test executes. +constexpr int kCollectSampleCount = 10; + +const char* sample_context_extractor_test_source = + "function start() {\n" + " for (var i = 0; i < 10; i++) {\n" + " CollectSample();\n" + " }\n" + "}\n"; + +} // namespace + +// Tests that an embedder SampleContextExtractor installed via +// CpuProfilingOptions is invoked for each sample and its return value is +// retrievable through CpuProfile::GetSampleContext. +TEST(SampleContextExtractor) { + LocalContext env; + v8::HandleScope scope(env.isolate()); + + g_extractor_call_count.store(0, std::memory_order_relaxed); + + InstallCollectSampleFunction(env.local()); + CompileRun(sample_context_extractor_test_source); + v8::Local<v8::Function> function = GetFunction(env.local(), "start"); + + ProfilerHelper helper(env.local()); + v8::CpuProfile* profile = helper.Run( + function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers, + v8::CpuProfilingOptions::kNoSampleLimit, v8::Local<v8::Context>(), + &TestSampleContextExtractor); + + // Every explicitly collected sample is recorded, plus the stack captured + // when profiling started, plus however many the sampling thread managed. + CHECK_GE(profile->GetSamplesCount(), kCollectSampleCount); + + // Every sample carries the value the extractor returned, whichever path + // captured it. Any other value would mean V8 mangled the pointer in + // transit. + for (int i = 0; i < profile->GetSamplesCount(); ++i) { + CHECK_EQ(kSampleContextSentinel, profile->GetSampleContext(i)); + } + + // The extractor runs once per captured sample, including any that were + // dropped before reaching the profile. + CHECK_GE(g_extractor_call_count.load(std::memory_order_relaxed), + profile->GetSamplesCount()); + + profile->Delete(); +} + +// Tests that when no extractor is installed on CpuProfilingOptions, every +// sample's GetSampleContext() returns nullptr (i.e. the default carries +// through, no spurious writes). +TEST(SampleContextExtractorAbsent) { + LocalContext env; + v8::HandleScope scope(env.isolate()); + + InstallCollectSampleFunction(env.local()); + CompileRun(sample_context_extractor_test_source); + v8::Local<v8::Function> function = GetFunction(env.local(), "start"); + + ProfilerHelper helper(env.local()); + // helper.Run() builds CpuProfilingOptions without an extractor. + v8::CpuProfile* profile = helper.Run(function, nullptr, 0); + + CHECK_GE(profile->GetSamplesCount(), kCollectSampleCount); + for (int i = 0; i < profile->GetSamplesCount(); ++i) { + CHECK_NULL(profile->GetSampleContext(i)); + } + profile->Delete(); +} + +// Tests that two CpuProfiler instances on the same isolate keep their +// extractors isolated from one another: each only sees the value its own +// extractor returned. +namespace { + +void* const kExtractorASentinel = + reinterpret_cast<void*>(static_cast<uintptr_t>(0xAAAA'AAAAULL)); +void* const kExtractorBSentinel = + reinterpret_cast<void*>(static_cast<uintptr_t>(0xBBBB'BBBBULL)); + +void* ExtractorA(v8::Isolate*) { return kExtractorASentinel; } +void* ExtractorB(v8::Isolate*) { return kExtractorBSentinel; } + +} // namespace + +TEST(SampleContextExtractorPerProfilerIsolation) { + LocalContext env; + v8::HandleScope scope(env.isolate()); + + InstallCollectSampleFunction(env.local()); + CompileRun(sample_context_extractor_test_source); + v8::Local<v8::Function> function = GetFunction(env.local(), "start"); + + v8::CpuProfiler* profiler_a = v8::CpuProfiler::New(env.isolate()); + v8::CpuProfiler* profiler_b = v8::CpuProfiler::New(env.isolate()); + + v8::Local<v8::String> name_a = v8_str("profile_a"); + v8::Local<v8::String> name_b = v8_str("profile_b"); + v8::CpuProfilingResult result_a = profiler_a->Start( + name_a, + v8::CpuProfilingOptions(v8::CpuProfilingMode::kLeafNodeLineNumbers, + v8::CpuProfilingOptions::kNoSampleLimit, 0, + v8::MaybeLocal<v8::Context>(), + v8::CpuProfileSource::kUnspecified, &ExtractorA)); + v8::CpuProfilingResult result_b = profiler_b->Start( + name_b, + v8::CpuProfilingOptions(v8::CpuProfilingMode::kLeafNodeLineNumbers, + v8::CpuProfilingOptions::kNoSampleLimit, 0, + v8::MaybeLocal<v8::Context>(), + v8::CpuProfileSource::kUnspecified, &ExtractorB)); + CHECK(result_a.status == v8::CpuProfilingStatus::kStarted); + CHECK(result_b.status == v8::CpuProfilingStatus::kStarted); + + // CpuProfiler::CollectSample fans out to every profiler on the isolate, so + // both profiles receive each of these samples. + function->Call(env.local(), env.local()->Global(), 0, nullptr) + .ToLocalChecked(); + + v8::CpuProfile* profile_a = profiler_a->StopProfiling(name_a); + v8::CpuProfile* profile_b = profiler_b->StopProfiling(name_b); + CHECK(profile_a); + CHECK(profile_b); + + // Each profile must contain only its own sentinel — confirming the + // extractor is scoped to its CpuProfiler instance. + CHECK_GE(profile_a->GetSamplesCount(), kCollectSampleCount); + for (int i = 0; i < profile_a->GetSamplesCount(); ++i) { + CHECK_EQ(kExtractorASentinel, profile_a->GetSampleContext(i)); + } + CHECK_GE(profile_b->GetSamplesCount(), kCollectSampleCount); + for (int i = 0; i < profile_b->GetSamplesCount(); ++i) { + CHECK_EQ(kExtractorBSentinel, profile_b->GetSampleContext(i)); + } + + profile_a->Delete(); + profile_b->Delete(); + profiler_a->Dispose(); + profiler_b->Dispose(); +} + // Tests that when a native context that's being filtered is moved, we continue // to track its execution. TEST(ContextFilterMovedNativeContext) { @@ -4947,11 +5118,11 @@ TEST(CpuProfileJSONSerialization) { cpu_profiler->Dispose(); CHECK_GT(stream.size(), 0); CHECK_EQ(1, stream.eos_signaled()); - auto json = base::OwnedVector<char>::NewForOverwrite(stream.size()); - stream.WriteTo(json.as_vector()); + auto json = base::UniqueArray<char>::NewForOverwrite(stream.size()); + stream.WriteTo(json.as_span()); // Verify that snapshot string is valid JSON. - OneByteResource* json_res = new OneByteResource(json.as_vector()); + OneByteResource* json_res = new OneByteResource(json.as_span()); v8::Local<v8::String> json_string = v8::String::NewExternalOneByte(env.isolate(), json_res).ToLocalChecked(); v8::Local<v8::Context> context = v8::Context::New(env.isolate()); @@ -5034,10 +5205,10 @@ TEST(CpuProfileJSONSerializationWithEscapedStrings) { profile->Delete(); CHECK_GT(stream.size(), 0); CHECK_EQ(1, stream.eos_signaled()); - auto json = base::OwnedVector<char>::NewForOverwrite(stream.size()); - stream.WriteTo(json.as_vector()); + auto json = base::UniqueArray<char>::NewForOverwrite(stream.size()); + stream.WriteTo(json.as_span()); - OneByteResource* json_res = new OneByteResource(json.as_vector()); + OneByteResource* json_res = new OneByteResource(json.as_span()); v8::Local<v8::String> json_string = v8::String::NewExternalOneByte(env.isolate(), json_res).ToLocalChecked(); v8::Local<v8::Context> context = v8::Context::New(env.isolate()); diff --git a/deps/v8/test/cctest/test-debug-helper.cc b/deps/v8/test/cctest/test-debug-helper.cc index 7db98b96e910..af527923524c 100644 --- a/deps/v8/test/cctest/test-debug-helper.cc +++ b/deps/v8/test/cctest/test-debug-helper.cc @@ -392,7 +392,7 @@ TEST(GetObjectProperties) { CHECK(props2->brief == std::string("2 (0x2)")); // Verify the result for a heap object field which is itself a struct: the - // "descriptors" field on a DescriptorArray. + // "entries" field on a DescriptorArray. // Start by getting the object's map and the map's descriptor array. uintptr_t map_ptr = ReadProp<i::Tagged_t>(*props, "map"); #if V8_MAP_PACKING @@ -408,12 +408,12 @@ TEST(GetObjectProperties) { uint16_t number_of_all_descriptors = *reinterpret_cast<uint16_t*>(props->properties[1]->address); CHECK_GE(number_of_all_descriptors, 2); - // The "descriptors" property should describe the struct layout for each + // The "entries" property should describe the struct layout for each // element in the array. const d::ObjectProperty& descriptors = *props->properties[5]; // No C++ type is reported directly because there may not be an actual C++ // struct with this layout, hence the empty string in this check. - CheckProp(descriptors, /*type=*/"", "descriptors", + CheckProp(descriptors, /*type=*/"", "entries", d::PropertyKind::kArrayOfKnownSize, number_of_all_descriptors); CHECK_EQ(descriptors.size, 3 * i::kTaggedSize); CHECK_EQ(descriptors.num_struct_fields, 3); @@ -491,7 +491,7 @@ static void FrameIterationCheck( d::StackFrameResultPtr props = d::GetStackFrame(frame->fp(), &ReadMemory); if (frame->is_javascript()) { JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); - CHECK_EQ(props->num_properties, 5); + CHECK_EQ(props->num_properties, 7); auto js_function = js_frame->function(); // This one is Tagged, not TaggedMember, because it's from the stack. CheckProp(*props->properties[0], @@ -523,6 +523,19 @@ static void FrameIterationCheck( CheckStructProp(*function_character_offset.struct_fields[1], "v8::internal::TaggedMember<v8::internal::Object>", "end", 4); + + // These are Tagged too because they are stack slots. + CheckProp(*props->properties[5], + "v8::internal::Tagged<v8::internal::Object>", "receiver", + js_frame->receiver().ptr()); + const d::ObjectProperty& arguments = *props->properties[6]; + uint32_t argc = js_frame->GetActualArgumentCount(); + CheckProp(arguments, "v8::internal::Tagged<v8::internal::Object>", + "arguments", d::PropertyKind::kArrayOfKnownSize, argc); + for (uint32_t arg = 0; arg < argc; arg++) { + CHECK_EQ(reinterpret_cast<Address*>(arguments.address)[arg], + js_frame->GetParameter(arg).ptr()); + } } else { CHECK_EQ(props->num_properties, 0); } @@ -542,10 +555,17 @@ THREADED_TEST(GetFrameStack) { ->Set(env.local(), v8_str("obj"), obj->NewInstance(env.local()).ToLocalChecked()) .FromJust()); - v8::Script::Compile(env.local(), v8_str("function foo() {" + // Cover matched, under-applied, and over-applied argument counts. + v8::Script::Compile(env.local(), v8_str("function exact(a) {" " return obj.xxx;" "}" - "foo();")) + "function underapplied(a, b, c) {" + " return exact(40);" + "}" + "function overapplied(x) {" + " return underapplied(41);" + "}" + "overapplied(42, 43);")) .ToLocalChecked() ->Run(env.local()) .ToLocalChecked(); @@ -570,7 +590,9 @@ TEST(SmallOrderedHashSetGetObjectProperties) { d::GetObjectProperties(set->ptr(), &ReadMemory, heap_addresses); CHECK_EQ(props->type_check_result, d::TypeCheckResult::kUsedMap); CHECK_EQ(props->type, std::string("v8::internal::SmallOrderedHashSet")); - CHECK_EQ(props->num_properties, 8); + // The variable-length tail (data, hash and chain tables) is not visible to + // Torque and thus not reported by the debug helper. + CHECK_EQ(props->num_properties, 5); CheckProp(*props->properties[0], "v8::internal::TaggedMember<v8::internal::Map>", "map"); @@ -584,15 +606,6 @@ TEST(SmallOrderedHashSetGetObjectProperties) { CheckProp(*props->properties[4], "uint8_t", "padding", d::PropertyKind::kArrayOfKnownSize, 1); #endif - CheckProp(*props->properties[5], - "v8::internal::TaggedMember<v8::internal::Object>", "data_table", - d::PropertyKind::kArrayOfKnownSize, - number_of_buckets * OrderedHashMap::kLoadFactor); - CheckProp(*props->properties[6], "uint8_t", "hash_table", - d::PropertyKind::kArrayOfKnownSize, number_of_buckets); - CheckProp(*props->properties[7], "uint8_t", "chain_table", - d::PropertyKind::kArrayOfKnownSize, - number_of_buckets * OrderedHashMap::kLoadFactor); } } // namespace internal diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index aa7bbef607a6..ae513aef213b 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -27,6 +27,8 @@ #include <stdlib.h> +#include <array> + #include "include/v8-extension.h" #include "include/v8-function.h" #include "include/v8-json.h" @@ -3225,6 +3227,66 @@ static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& info) { CHECK(i::ValidateCallbackInfo(info)); } +namespace { + +class ScopeTypesListener : public v8::debug::DebugDelegate { + public: + void BreakProgramRequested( + v8::Local<v8::Context> paused_context, + const std::vector<v8::debug::BreakpointId>& inspector_break_points_hit, + v8::base::EnumSet<v8::debug::BreakReason> break_reasons) override { + auto stack_traces = + v8::debug::StackTraceIterator::Create(CcTest::isolate()); + for (auto scopes = stack_traces->GetScopeIterator(); !scopes->Done(); + scopes->Advance()) { + scope_types_.push_back(scopes->GetType()); + } + } + + const std::vector<v8::debug::ScopeIterator::ScopeType>& scope_types() const { + return scope_types_; + } + + private: + std::vector<v8::debug::ScopeIterator::ScopeType> scope_types_; +}; + +} // namespace + +TEST(DebugScopeIteratorWrappedFunctionWithContextExtension) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + + ScopeTypesListener delegate; + v8::debug::SetDebugDelegate(isolate, &delegate); + + static const char* source = + "let outer = 1;\n" + "{\n" + " let block = 2;\n" + " (function inner() { debugger; })();\n" + "}\n"; + v8::ScriptCompiler::Source script_source(v8_str(source)); + v8::Local<v8::Object> extension = v8::Object::New(isolate); + CHECK(extension->Set(env.local(), v8_str("ext"), v8_num(3)).FromJust()); + v8::Local<v8::Function> fun = + v8::ScriptCompiler::CompileFunction(env.local(), &script_source, 0, + nullptr, 1, &extension) + .ToLocalChecked(); + fun->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked(); + + using ScopeType = v8::debug::ScopeIterator::ScopeType; + const std::vector<ScopeType> expected = { + ScopeType::ScopeTypeLocal, ScopeType::ScopeTypeBlock, + ScopeType::ScopeTypeClosure, ScopeType::ScopeTypeWith, + ScopeType::ScopeTypeGlobal}; + CHECK(delegate.scope_types() == expected); + + v8::debug::SetDebugDelegate(isolate, nullptr); + CheckDebuggerUnloaded(); +} + TEST(DebugScopeIteratorWithFunctionTemplate) { LocalContext env; v8::HandleScope handle_scope(env.isolate()); @@ -3425,10 +3487,10 @@ class EmptyExternalStringResource : public v8::String::ExternalStringResource { EmptyExternalStringResource() { empty_[0] = 0; } ~EmptyExternalStringResource() override = default; size_t length() const override { return empty_.size(); } - const uint16_t* data() const override { return empty_.begin(); } + const uint16_t* data() const override { return empty_.data(); } private: - ::v8::base::EmbeddedVector<uint16_t, 1> empty_; + std::array<uint16_t, 1> empty_; }; TEST(DebugScriptLineEndsAreAscending) { @@ -3537,14 +3599,19 @@ TEST(ContextData) { v8::debug::SetDebugDelegate(isolate, &delegate); // Default data value is undefined. - CHECK_EQ(0, context_1->GetNumberOfEmbedderDataFields()); - CHECK_EQ(0, context_2->GetNumberOfEmbedderDataFields()); + CHECK_EQ(V8_EMBEDDER_DATA_ARRAY_SIZE, + context_1->GetNumberOfEmbedderDataFields()); + CHECK_EQ(V8_EMBEDDER_DATA_ARRAY_SIZE, + context_2->GetNumberOfEmbedderDataFields()); // Set and check different data values. v8::Local<v8::String> data_1 = v8_str(isolate, "1"); v8::Local<v8::String> data_2 = v8_str(isolate, "2"); + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V3. context_1->SetEmbedderDataV2(0, data_1); context_2->SetEmbedderDataV2(0, data_2); + END_ALLOW_USE_DEPRECATED() CHECK(v8::Local<v8::Value>::Cast(context_1->GetEmbedderDataV2(0)) ->StrictEquals(data_1)); CHECK(v8::Local<v8::Value>::Cast(context_2->GetEmbedderDataV2(0)) @@ -3598,11 +3665,12 @@ TEST(EvalContextData) { v8::debug::SetDebugDelegate(isolate, &delegate); // Contexts initially do not have embedder data fields. - CHECK_EQ(0, context_1->GetNumberOfEmbedderDataFields()); + CHECK_EQ(V8_EMBEDDER_DATA_ARRAY_SIZE, + context_1->GetNumberOfEmbedderDataFields()); // Set and check a data value. v8::Local<v8::String> data_1 = v8_str(isolate, "1"); - context_1->SetEmbedderDataV2(0, data_1); + context_1->SetEmbedderDataV3(0, data_1); CHECK(v8::Local<v8::Value>::Cast(context_1->GetEmbedderDataV2(0)) ->StrictEquals(data_1)); @@ -3950,11 +4018,11 @@ static void TestDebugBreakInLoop(const char* loop_head, // Perform a lazy deoptimization after various numbers of breaks // have been hit. - v8::base::EmbeddedVector<char, 1024> buffer; + std::array<char, 1024> buffer; v8::base::SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i], loop_tail); - i::PrintF("%s\n", buffer.begin()); + i::PrintF("%s\n", buffer.data()); for (int j = 0; j < 3; j++) { break_point_hit_count_deoptimize = j; @@ -3967,7 +4035,7 @@ static void TestDebugBreakInLoop(const char* loop_head, terminate_after_max_break_point_hit = true; // Function with infinite loop. - CompileRun(buffer.begin()); + CompileRun(buffer.data()); // Set the debug break to enter the debugger as soon as possible. v8::debug::SetBreakOnNextFunctionCall(CcTest::isolate()); @@ -7426,4 +7494,80 @@ TEST(PerformPromiseAllCaughtDebug) { v8::debug::SetDebugDelegate(isolate, nullptr); } +// Steps over through F (see below) and records every pause as +// "function:line:column". Only functions starting on line {kEnterLine} are +// entered. +class StepOverEnterFunctionsDelegate : public v8::debug::DebugDelegate { + public: + StepOverEnterFunctionsDelegate(v8::Isolate* isolate, bool enter_functions) + : isolate_(isolate), enter_functions_(enter_functions) {} + + void BreakProgramRequested(v8::Local<v8::Context>, + const std::vector<v8::debug::BreakpointId>&, + v8::debug::BreakReasons) override { + auto it = v8::debug::StackTraceIterator::Create(isolate_); + v8::String::Utf8Value name(isolate_, it->GetFunctionDebugName()); + v8::debug::Location location = it->GetSourceLocation(); + pauses_ += std::string(*name) + ":" + + std::to_string(location.GetLineNumber()) + ":" + + std::to_string(location.GetColumnNumber()) + " "; + v8::debug::PrepareStep(isolate_, v8::debug::StepOver, enter_functions_); + } + + bool ShouldEnterFunction(v8::Local<v8::debug::Script> script, + const v8::debug::Location& start, + const v8::debug::Location& end) override { + // Must only be called for steps with {enter_functions}. + CHECK(enter_functions_); + return start.GetLineNumber() == kEnterLine; + } + + static constexpr int kEnterLine = 0; + const std::string& pauses() const { return pauses_; } + + private: + v8::Isolate* isolate_; + bool enter_functions_; + std::string pauses_; +}; + +std::string RunStepOverEnterFunctions(bool enter_functions) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + StepOverEnterFunctionsDelegate delegate(isolate, enter_functions); + v8::debug::SetDebugDelegate(isolate, &delegate); + CompileRun( + "function T() {\n" // 0: Entered. + " return G();\n" // 1 + "}\n" // 2 + "function G() {\n" // 3: Not entered. + " return 2;\n" // 4 + "}\n" // 5 + "function F() {\n" // 6 + " debugger;\n" // 7 + " T();\n" // 8 + " G();\n" // 9 + " [1, 2].forEach(T);\n" // 10 + " return 0;\n" // 11 + "}\n"); // 12 + CompileRun("F()"); + v8::debug::SetDebugDelegate(isolate, nullptr); + CheckDebuggerUnloaded(); + return delegate.pauses(); +} + +TEST(StepOverWithoutEnterFunctions) { + CHECK_EQ("F:7:2 F:8:2 F:9:2 F:10:2 F:11:2 F:11:11 :0:3 ", + RunStepOverEnterFunctions(false)); +} + +TEST(StepOverEnterFunctions) { + // T is entered from F and from the forEach builtin, G is never entered. + CHECK_EQ( + "F:7:2 F:8:2 T:1:2 T:1:13 F:9:2 F:10:2 T:1:2 T:1:13 T:1:2 T:1:13 " + "F:11:2 F:11:11 :0:3 ", + RunStepOverEnterFunctions(true)); +} + } // namespace diff --git a/deps/v8/test/cctest/test-field-type-tracking.cc b/deps/v8/test/cctest/test-field-type-tracking.cc index a88be358eb80..2d773020e150 100644 --- a/deps/v8/test/cctest/test-field-type-tracking.cc +++ b/deps/v8/test/cctest/test-field-type-tracking.cc @@ -1565,7 +1565,7 @@ TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) { Factory* factory = isolate->factory(); DirectHandle<String> name = factory->empty_string(); DirectHandle<Map> sloppy_map = - Map::CopyInitialMap(isolate, isolate->sloppy_function_map()); + Map::CopyInitialMap(isolate, isolate->function_map()); DirectHandle<SharedFunctionInfo> info = factory->NewSharedFunctionInfoForBuiltin(name, Builtin::kIllegal, 0, kDontAdapt); @@ -2852,7 +2852,7 @@ TEST(TransitionDataConstantToAnotherDataConstant) { DirectHandle<String> name = factory->empty_string(); DirectHandle<Map> sloppy_map = - Map::CopyInitialMap(isolate, isolate->sloppy_function_map()); + Map::CopyInitialMap(isolate, isolate->function_map()); DirectHandle<SharedFunctionInfo> info = factory->NewSharedFunctionInfoForBuiltin(name, Builtin::kIllegal, 0, kDontAdapt); @@ -2915,7 +2915,7 @@ TEST(HoleyHeapNumber) { v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - auto mhn = isolate->factory()->NewHeapNumberWithHoleNaN(); + auto mhn = isolate->factory()->NewHeapNumberFromBits(kHoleNanInt64); CHECK_EQ(kHoleNanInt64, mhn->value_as_bits()); mhn = isolate->factory()->NewHeapNumber(0.0); @@ -2930,8 +2930,7 @@ TEST(HoleyHeapNumber) { DirectHandle<Object> obj = Object::NewStorageFor(isolate, isolate->factory()->uninitialized_value(), Representation::Double()); - CHECK(IsHeapNumber(*obj)); - CHECK_EQ(kHoleNanInt64, Cast<HeapNumber>(*obj)->value_as_bits()); + CHECK(IsUninitializedHeapNumber(*obj)); obj = Object::NewStorageFor(isolate, mhn, Representation::Double()); CHECK(IsHeapNumber(*obj)); diff --git a/deps/v8/test/cctest/test-func-name-inference.cc b/deps/v8/test/cctest/test-func-name-inference.cc index 618d4fdcceaa..69db248d2cab 100644 --- a/deps/v8/test/cctest/test-func-name-inference.cc +++ b/deps/v8/test/cctest/test-func-name-inference.cc @@ -33,7 +33,6 @@ #include "src/strings/string-search.h" #include "test/cctest/cctest.h" -using ::v8::base::CStrVector; using ::v8::base::Vector; using ::v8::internal::DirectHandle; using ::v8::internal::Factory; diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 81895814bfb2..7858f2ce8d64 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -29,6 +29,7 @@ #include <ctype.h> +#include <array> #include <memory> #include <optional> #include <string> @@ -41,6 +42,7 @@ #include "src/base/hashmap.h" #include "src/base/logging.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" #include "src/debug/debug.h" #include "src/flags/flags.h" @@ -293,8 +295,8 @@ bool HasString(v8::Isolate* isolate, const v8::HeapGraphNode* node, void EnsureNoUninstrumentedInternals(v8::Isolate* isolate, const v8::HeapGraphNode* node) { for (int i = 0; i < 20; ++i) { - auto buffer = v8::base::OwnedVector<char>::NewForOverwrite(10); - std::string_view str = i::IntToStringView(i, buffer.as_vector()); + std::array<char, 10> buffer; + std::string_view str = i::IntToStringView(i, buffer); // GetProperty requires a null-terminated string. const v8::HeapGraphNode* internal = GetProperty( isolate, node, v8::HeapGraphEdge::kInternal, std::string(str).c_str()); @@ -1095,6 +1097,139 @@ TEST(HeapSnapshotCollection) { CHECK_EQ(s->GetId(), map_s->GetId()); } +namespace { +v8::Global<v8::Module> deferred_module_dependency; + +v8::MaybeLocal<v8::Module> DeferredModuleResolveCallback( + v8::Local<v8::Context> context, v8::Local<v8::String> specifier, + v8::Local<v8::FixedArray> import_attributes, + v8::Local<v8::Module> referrer) { + return deferred_module_dependency.Get(CcTest::isolate()); +} + +v8::Local<v8::Module> CompileModuleForSnapshot(v8::Isolate* isolate, + const char* name, + const char* source) { + v8::ScriptOrigin origin(v8_str(name), 0, 0, false, -1, v8::Local<v8::Value>(), + false, false, true); + v8::ScriptCompiler::Source compiler_source(v8_str(source), origin); + return v8::ScriptCompiler::CompileModule(isolate, &compiler_source) + .ToLocalChecked(); +} + +// Evaluates a module whose imports all resolve to deferred_module_dependency. +void EvaluateModuleForSnapshot(v8::Local<v8::Context> context, const char* name, + const char* source) { + v8::Local<v8::Module> module = + CompileModuleForSnapshot(CcTest::isolate(), name, source); + CHECK(module->InstantiateModule(context, DeferredModuleResolveCallback) + .ToChecked()); + module->Evaluate(context).ToLocalChecked(); +} + +// Returns whether |to| can be reached from |from| by following at most |depth| +// edges. +bool IsReachable(const v8::HeapGraphNode* from, const v8::HeapGraphNode* to, + int depth) { + if (from->GetId() == to->GetId()) return true; + if (depth == 0) return false; + for (int i = 0, count = from->GetChildrenCount(); i < count; ++i) { + if (IsReachable(from->GetChild(i)->GetToNode(), to, depth - 1)) { + return true; + } + } + return false; +} +} // namespace + +// A deferred module namespace must reference its module in heap snapshots, +// and the module must reference both its namespaces and, once evaluated, its +// exports. Taking a snapshot must not evaluate the deferred module. +TEST(HeapSnapshotDeferredModuleNamespace) { + i::v8_flags.js_defer_import_eval = true; + LocalContext env; + v8::Isolate* isolate = env.isolate(); + v8::HandleScope scope(isolate); + v8::Local<v8::Context> context = env.local(); + v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); + + deferred_module_dependency.Reset( + isolate, CompileModuleForSnapshot(isolate, "dependency", + "globalThis.evaluated = true;\n" + "export const foo = {};\n" + "globalThis.foo = foo;")); + EvaluateModuleForSnapshot(context, "deferred-importer", + "import defer * as ns from 'dependency';\n" + "globalThis.ns = ns;"); + + const v8::HeapSnapshot* snapshot; + { + // Evaluating the deferred module while taking the snapshot would be fatal. + v8::Isolate::DisallowJavascriptExecutionScope no_js( + isolate, + v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE); + snapshot = heap_profiler->TakeHeapSnapshot(); + } + CHECK(ValidateSnapshot(snapshot)); + CHECK(env->Global() + ->Get(context, v8_str("evaluated")) + .ToLocalChecked() + ->IsUndefined()); + + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* ns = + GetProperty(isolate, global, v8::HeapGraphEdge::kProperty, "ns"); + CHECK_NOT_NULL(ns); + CHECK_EQ(v8::HeapGraphNode::kObject, ns->GetType()); + CHECK_EQ(std::string_view{"Deferred Module"}, std::string_view{GetName(ns)}); + const v8::HeapGraphNode* module = + GetChildByName(ns, "system / SourceTextModule"); + CHECK_NOT_NULL(module); + // The module holds the namespace through a Cell. + CHECK(IsReachable(module, ns, 2)); + + // Evaluate the module, and import it eagerly as well. + CompileRun("ns.foo"); + EvaluateModuleForSnapshot(context, "eager-importer", + "import * as eager from 'dependency';\n" + "globalThis.eager = eager;"); + CHECK(env->Global() + ->Get(context, v8_str("evaluated")) + .ToLocalChecked() + ->IsTrue()); + + snapshot = heap_profiler->TakeHeapSnapshot(); + CHECK(ValidateSnapshot(snapshot)); + global = GetGlobalObject(snapshot); + ns = GetProperty(isolate, global, v8::HeapGraphEdge::kProperty, "ns"); + CHECK_NOT_NULL(ns); + CHECK_EQ(std::string_view{"Deferred Module"}, std::string_view{GetName(ns)}); + const v8::HeapGraphNode* eager = + GetProperty(isolate, global, v8::HeapGraphEdge::kProperty, "eager"); + CHECK_NOT_NULL(eager); + CHECK_EQ(v8::HeapGraphNode::kObject, eager->GetType()); + CHECK_EQ(std::string_view{"Module"}, std::string_view{GetName(eager)}); + CHECK_NE(ns->GetId(), eager->GetId()); + + // Both namespaces reference the same module, which references both of them. + module = GetChildByName(ns, "system / SourceTextModule"); + CHECK_NOT_NULL(module); + const v8::HeapGraphNode* eager_module = + GetChildByName(eager, "system / SourceTextModule"); + CHECK_NOT_NULL(eager_module); + CHECK_EQ(module->GetId(), eager_module->GetId()); + CHECK(IsReachable(module, ns, 2)); + CHECK(IsReachable(module, eager, 2)); + + // The module references the value of its export through the export's Cell. + const v8::HeapGraphNode* foo = + GetProperty(isolate, global, v8::HeapGraphEdge::kProperty, "foo"); + CHECK_NOT_NULL(foo); + CHECK(IsReachable(module, foo, 3)); + + deferred_module_dependency.Reset(); +} + TEST(HeapSnapshotMap) { LocalContext env; v8::HandleScope scope(env.isolate()); @@ -1365,12 +1500,12 @@ TEST(HeapSnapshotJSONSerialization) { snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); CHECK_GT(stream.size(), 0); CHECK_EQ(1, stream.eos_signaled()); - auto json = v8::base::OwnedVector<char>::NewForOverwrite(stream.size()); - stream.WriteTo(json.as_vector()); + auto json = v8::base::UniqueArray<char>::NewForOverwrite(stream.size()); + stream.WriteTo(json.as_span()); // Verify that snapshot string is valid JSON. v8::internal::OneByteResource* json_res = - new v8::internal::OneByteResource(json.as_vector()); + new v8::internal::OneByteResource(json.as_span()); v8::Local<v8::String> json_string = v8::String::NewExternalOneByte(env.isolate(), json_res).ToLocalChecked(); v8::Local<v8::Context> context = v8::Context::New(env.isolate()); @@ -3090,11 +3225,11 @@ TEST(ManyLocalsInSharedContext) { // Check all the objects have got their names. // ... well check just every 15th because otherwise it's too slow in debug. for (int i = 0; i < num_objects - 1; i += 15) { - v8::base::EmbeddedVector<char, 100> var_name; + std::array<char, 100> var_name; v8::base::SNPrintF(var_name, "f_%d", i); const v8::HeapGraphNode* f_object = GetProperty(env.isolate(), context_object, - v8::HeapGraphEdge::kContextVariable, var_name.begin()); + v8::HeapGraphEdge::kContextVariable, var_name.data()); CHECK(f_object); } } @@ -3193,9 +3328,9 @@ static const v8::HeapGraphNode* GetNodeByPath(v8::Isolate* isolate, const v8::HeapGraphNode* to_node = edge->GetToNode(); v8::String::Utf8Value edge_name(isolate, edge->GetName()); v8::String::Utf8Value node_name(isolate, to_node->GetName()); - v8::base::EmbeddedVector<char, 100> name; + std::array<char, 100> name; v8::base::SNPrintF(name, "%s::%s", *edge_name, *node_name); - if (strstr(name.begin(), path[current_depth])) { + if (strstr(name.data(), path[current_depth])) { node = to_node; break; } @@ -3662,6 +3797,37 @@ TEST(HeapSnapshotScriptContext) { CHECK(found_foo); } +TEST(HeapSnapshotScriptSourceUrl) { + // The source_url node of a script is named by the source URL, even if it is + // long enough to be a sliced string. DevTools relies on this. + LocalContext env; + v8::HandleScope scope(env.isolate()); + v8::HeapProfiler* heap_profiler = env.isolate()->GetHeapProfiler(); + + CompileRun( + "eval('globalThis.f = function f() {};\\n" + "//# sourceURL=inside-direct-eval.js');"); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); + CHECK(ValidateSnapshot(snapshot)); + const v8::HeapGraphNode* global = GetGlobalObject(snapshot); + const v8::HeapGraphNode* f = + GetProperty(env.isolate(), global, v8::HeapGraphEdge::kProperty, "f"); + CHECK(f); + const v8::HeapGraphNode* shared = + GetProperty(env.isolate(), f, v8::HeapGraphEdge::kInternal, "shared"); + CHECK(shared); + const v8::HeapGraphNode* script = GetProperty( + env.isolate(), shared, v8::HeapGraphEdge::kInternal, "script"); + CHECK(script); + const v8::HeapGraphNode* source_url = GetProperty( + env.isolate(), script, v8::HeapGraphEdge::kInternal, "source_url"); + CHECK(source_url); + CHECK_EQ(v8::HeapGraphNode::kString, source_url->GetType()); + v8::String::Utf8Value name(env.isolate(), source_url->GetName()); + CHECK_EQ(0, strcmp("inside-direct-eval.js", *name)); + heap_profiler->DeleteAllHeapSnapshots(); +} + class EmbedderNode : public v8::EmbedderGraph::Node { public: EmbedderNode(const char* name, size_t size, @@ -4481,8 +4647,8 @@ TEST(SamplingHeapProfilerPretenuredInlineAllocations) { GrowNewSpaceToMaximumCapacity(CcTest::heap()); - auto source = v8::base::OwnedVector<char>::NewForOverwrite(1024); - v8::base::SNPrintF(source.as_vector(), + std::array<char, 1024> source; + v8::base::SNPrintF(source, "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" @@ -4500,7 +4666,7 @@ TEST(SamplingHeapProfilerPretenuredInlineAllocations) { i::PretenuringHandler::GetMinMementoCountForTesting() + 1); v8::Local<v8::Function> f = - v8::Local<v8::Function>::Cast(CompileRun(source.begin())); + v8::Local<v8::Function>::Cast(CompileRun(source.data())); // Make sure the function is producing pre-tenured objects. auto res = f->Call(env.local(), env->Global(), 0, nullptr).ToLocalChecked(); @@ -4634,6 +4800,133 @@ TEST(SamplingHeapProfilerSampleIsLive) { heap_profiler->StopSamplingHeapProfiler(); } +namespace { + +uintptr_t sample_context_calls = 0; + +void* CountingSampleContextExtractor(v8::Isolate*) { + return reinterpret_cast<void*>(++sample_context_calls << 1); +} + +void* NullSampleContextExtractor(v8::Isolate*) { + ++sample_context_calls; + return nullptr; +} + +// Checks that each sample's context is the one the counting extractor returned +// for it, and returns the number of samples whose object was collected. +size_t CheckCountingSampleContexts( + const std::vector<v8::AllocationProfile::Sample>& samples) { + CHECK(!samples.empty()); + size_t dead_samples = 0; + for (const auto& sample : samples) { + // Sample ids and extractor calls both count from 1. + CHECK_EQ(reinterpret_cast<void*>(sample.sample_id << 1), sample.context); + if (!sample.is_live) ++dead_samples; + } + return dead_samples; +} + +} // namespace + +TEST(SamplingHeapProfilerSampleContext) { + v8::HandleScope scope(CcTest::isolate()); + LocalContext env; + v8::HeapProfiler* heap_profiler = env.isolate()->GetHeapProfiler(); + + // Suppress randomness to avoid flakiness in tests. + i::v8_flags.sampling_heap_profiler_suppress_randomness = true; + + sample_context_calls = 0; + CHECK(heap_profiler->StartSamplingHeapProfiler( + 64, 16, + static_cast<v8::HeapProfiler::SamplingFlags>( + v8::HeapProfiler::kSamplingForceGC | + v8::HeapProfiler::kSamplingIncludeObjectsCollectedByMajorGC | + v8::HeapProfiler::kSamplingIncludeObjectsCollectedByMinorGC), + CountingSampleContextExtractor)); + + CompileRun( + "var retained = [];\n" + "for (var i = 0; i < 500; i++) retained.push(new Array(10));\n" + "for (var i = 0; i < 500; i++) new Array(10);\n"); + + std::unique_ptr<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(profile); + CHECK_GT(CheckCountingSampleContexts(profile->GetSamples()), 0); + CheckCountingSampleContexts(heap_profiler->GetSamplingHeapProfilerSamples()); + + heap_profiler->StopSamplingHeapProfiler(); +} + +TEST(SamplingHeapProfilerSampleContextMinorGC) { + // The samples must be collected by a minor GC. + if (i::v8_flags.single_generation || i::v8_flags.gc_global || + i::v8_flags.stress_compaction) { + return; + } + i::ManualGCScope manual_gc_scope; + v8::HandleScope scope(CcTest::isolate()); + LocalContext env; + v8::HeapProfiler* heap_profiler = env.isolate()->GetHeapProfiler(); + + // Suppress randomness to avoid flakiness in tests. + i::v8_flags.sampling_heap_profiler_suppress_randomness = true; + + sample_context_calls = 0; + CHECK(heap_profiler->StartSamplingHeapProfiler( + 64, 16, v8::HeapProfiler::kSamplingIncludeObjectsCollectedByMinorGC, + CountingSampleContextExtractor)); + + CompileRun("for (var i = 0; i < 500; i++) new Array(10);\n"); + { + i::DisableConservativeStackScanningScopeForTesting no_stack_scanning( + CcTest::heap()); + i::heap::InvokeMinorGC(CcTest::heap()); + } + CHECK(i::Heap::IsYoungGenerationCollector( + CcTest::heap()->current_or_last_garbage_collector())); + + std::unique_ptr<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(profile); + CHECK_GT(CheckCountingSampleContexts(profile->GetSamples()), 0); + + heap_profiler->StopSamplingHeapProfiler(); +} + +TEST(SamplingHeapProfilerNullSampleContext) { + v8::HandleScope scope(CcTest::isolate()); + LocalContext env; + v8::HeapProfiler* heap_profiler = env.isolate()->GetHeapProfiler(); + + // Suppress randomness to avoid flakiness in tests. + i::v8_flags.sampling_heap_profiler_suppress_randomness = true; + + for (v8::SampleContextExtractor extractor : + {static_cast<v8::SampleContextExtractor>(nullptr), + NullSampleContextExtractor}) { + sample_context_calls = 0; + CHECK(heap_profiler->StartSamplingHeapProfiler( + 64, 16, v8::HeapProfiler::kSamplingNoFlags, extractor)); + CompileRun( + "var retained = [];\n" + "for (var i = 0; i < 100; i++) retained.push(new Array(10));\n"); + + std::unique_ptr<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(profile); + CHECK(!profile->GetSamples().empty()); + for (const auto& sample : profile->GetSamples()) { + CHECK_NULL(sample.context); + } + CHECK_EQ(extractor == nullptr, sample_context_calls == 0); + + heap_profiler->StopSamplingHeapProfiler(); + } +} + TEST(HeapSnapshotPrototypeNotJSReceiver) { LocalContext env; v8::HandleScope scope(env.isolate()); @@ -5004,7 +5297,8 @@ TEST(HeapSnapshotWithWasmInstance) { isolate, trusted_instance_data_node, {"data_segments", "dispatch_table0", "dispatch_table_for_imports", "dispatch_tables", "instance_object", "managed_native_module", "map", - "memory_bases_and_sizes", "native_context"}); + "memory_bases_and_sizes", "native_context", + "shared_memory_backing_stores"}); // "module_object" should be the same as the global "module". const v8::HeapGraphNode* module_node = diff --git a/deps/v8/test/cctest/test-js-to-wasm.cc b/deps/v8/test/cctest/test-js-to-wasm.cc index 8a532767ab7f..97ad03f0154b 100644 --- a/deps/v8/test/cctest/test-js-to-wasm.cc +++ b/deps/v8/test/cctest/test-js-to-wasm.cc @@ -298,8 +298,7 @@ class FastJSWasmCallTester { void DeclareCallback(const char* name, FunctionSig* signature, const char* module) { - builder_->AddImport(base::CStrVector(name), signature, - base::CStrVector(module)); + builder_->AddImport(name, signature, module); } void AddExportedFunction(const ExportedFunction& exported_func) { @@ -308,8 +307,8 @@ class FastJSWasmCallTester { func->EmitCode(exported_func.code.data(), static_cast<uint32_t>(exported_func.code.size())); func->Emit(kExprEnd); - builder_->AddExport(base::CStrVector(exported_func.name.c_str()), - kExternalFunction, func->func_index()); + builder_->AddExport(exported_func.name, kExternalFunction, + func->func_index()); // JS-to-Wasm inlining is disabled when targeting 32 bits if the Wasm // function signature contains an I64. @@ -590,7 +589,8 @@ class FastJSWasmCallTester { ModuleTypeIndex supertype = kNoSuperType, bool is_final = false) { return builder_->AddArrayType( - zone_.New<ArrayType>(element_type, mutability), is_final, supertype); + zone_.New<ArrayType>(element_type, mutability, SharedFlag{false}), + is_final, supertype); } private: @@ -606,11 +606,11 @@ class FastJSWasmCallTester { auto it = buffer.begin(); if (it != buffer.end()) { string_stream << "0x" << std::setfill('0') << std::setw(2) << std::hex - << static_cast<int>(*it++); + << static_cast<int>(*it++) << std::dec; } while (it != buffer.end()) { string_stream << ", 0x" << std::setfill('0') << std::setw(2) << std::hex - << static_cast<int>(*it++); + << static_cast<int>(*it++) << std::dec; } string_stream << "]"; return string_stream.str(); diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc index ae79154c83ac..72e8ff997a7a 100644 --- a/deps/v8/test/cctest/test-log-stack-tracer.cc +++ b/deps/v8/test/cctest/test-log-stack-tracer.cc @@ -29,6 +29,8 @@ #include <stdlib.h> +#include <array> + #include "include/v8-function.h" #include "src/api/api-inl.h" #include "src/base/strings.h" @@ -123,7 +125,7 @@ void CreateFramePointerGrabberConstructor(v8::Local<v8::Context> context, static void CreateTraceCallerFunction(v8::Local<v8::Context> context, const char* func_name, const char* trace_func_name) { - v8::base::EmbeddedVector<char, 256> trace_call_buf; + std::array<char, 256> trace_call_buf; v8::base::SNPrintF(trace_call_buf, "function %s() {" " fp = new FPGrabber();" @@ -136,7 +138,7 @@ static void CreateTraceCallerFunction(v8::Local<v8::Context> context, CreateFramePointerGrabberConstructor(context, "FPGrabber"); // Compile the script. - CompileRun(trace_call_buf.begin()); + CompileRun(trace_call_buf.data()); } diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index 1ac33109fee8..c4c99a4b3897 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -27,6 +27,8 @@ // // Tests of profiles generator and utilities. +#include <array> + #include "include/v8-function.h" #include "include/v8-profiler.h" #include "src/api/api-inl.h" @@ -801,20 +803,16 @@ TEST(Issue51919) { CpuProfilesCollection collection(CcTest::i_isolate()); CpuProfiler profiler(CcTest::i_isolate()); collection.set_cpu_profiler(&profiler); - base::EmbeddedVector<char*, CpuProfilesCollection::kMaxSimultaneousProfiles> + std::array<std::array<char, 16>, + CpuProfilesCollection::kMaxSimultaneousProfiles> titles; for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) { - base::Vector<char> title = v8::base::Vector<char>::New(16); - base::SNPrintF(title, "%d", i); + base::SNPrintF(titles[i], "%d", i); CHECK_EQ(CpuProfilingStatus::kStarted, - collection.StartProfiling(title.begin()).status); - titles[i] = title.begin(); + collection.StartProfiling(titles[i].data()).status); } CHECK_EQ(CpuProfilingStatus::kErrorTooManyProfilers, collection.StartProfiling("maximum").status); - for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) { - i::DeleteArray(titles[i]); - } } static const v8::CpuProfileNode* PickChild(const v8::CpuProfileNode* parent, diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index b71ad2639004..bbcc095243a3 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -230,7 +230,7 @@ class InterruptTest { TryCatch try_catch(env_.isolate()); isolate_->RequestInterrupt(&SignalSemaphore, this); - MaybeLocal<Object> result = regexp_handle_.Get(isolate_)->Exec( + MaybeLocal<Value> result = regexp_handle_.Get(isolate_)->ExecV2( env_.local(), subject_string_handle_.Get(isolate_)); CHECK(result.IsEmpty()); diff --git a/deps/v8/test/cctest/test-sampler-api.cc b/deps/v8/test/cctest/test-sampler-api.cc index da6e79395665..17b02f8c69d8 100644 --- a/deps/v8/test/cctest/test-sampler-api.cc +++ b/deps/v8/test/cctest/test-sampler-api.cc @@ -4,6 +4,7 @@ // // Tests the sampling API in include/v8.h +#include <array> #include <map> #include <string> @@ -20,16 +21,18 @@ namespace { class Sample { public: enum { kFramesLimit = 255 }; - using DataVector = v8::base::EmbeddedVector<void*, kFramesLimit>; + using DataVector = std::array<void*, kFramesLimit>; Sample() = default; const void* operator[](size_t index) const { return data_[index]; } - size_t size() const { return data_.size(); } + size_t size() const { return size_; } + void set_size(size_t size) { size_ = size; } DataVector& data() { return data_; } private: DataVector data_; + size_t size_ = kFramesLimit; }; @@ -95,11 +98,11 @@ class SamplingTestHelper { state.sp = &state; #endif v8::SampleInfo info; - isolate_->GetStackSample(state, sample_.data().begin(), sample_.size(), + isolate_->GetStackSample(state, sample_.data().data(), sample_.size(), &info); size_t frames_count = info.frames_count; CHECK_LE(frames_count, sample_.size()); - sample_.data().Truncate(static_cast<int>(frames_count)); + sample_.set_size(frames_count); sample_is_taken_ = true; } diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index b60564dd3096..5d0f0f17767c 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -40,6 +40,7 @@ #include "include/v8-sandbox.h" #include "include/v8-snapshot.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/codegen/compilation-cache.h" #include "src/codegen/compiler.h" #include "src/codegen/script-details.h" @@ -74,6 +75,7 @@ #include "test/cctest/cctest.h" #include "test/cctest/heap/heap-utils.h" #include "test/cctest/setup-isolate-for-tests.h" +#include "test/common/flag-utils.h" #include "test/common/version-utils.h" namespace v8 { namespace internal { @@ -86,15 +88,9 @@ constexpr EmbedderDataTypeTag kRawDataTag = 2; // A convenience struct to simplify management of the blobs required to // deserialize an isolate. struct StartupBlobs { - base::Vector<const uint8_t> startup; - base::Vector<const uint8_t> read_only; - base::Vector<const uint8_t> shared_space; - - void Dispose() { - startup.Dispose(); - read_only.Dispose(); - shared_space.Dispose(); - } + base::UniqueArray<const uint8_t> startup; + base::UniqueArray<const uint8_t> read_only; + base::UniqueArray<const uint8_t> shared_space; }; } // namespace @@ -123,9 +119,9 @@ class TestSerializer { } static v8::Isolate* NewIsolateFromBlob(const StartupBlobs& blobs) { - SnapshotData startup_snapshot(blobs.startup); - SnapshotData read_only_snapshot(blobs.read_only); - SnapshotData shared_space_snapshot(blobs.shared_space); + SnapshotData startup_snapshot(blobs.startup.as_span()); + SnapshotData read_only_snapshot(blobs.read_only.as_span()); + SnapshotData shared_space_snapshot(blobs.shared_space.as_span()); const bool kEnableSerializer = false; v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer); v8::Isolate::Scope isolate_scope(v8_isolate); @@ -153,12 +149,9 @@ namespace { enum CodeCacheType { kLazy, kEager, kAfterExecute }; -base::Vector<const uint8_t> WritePayload( +base::UniqueArray<const uint8_t> WritePayload( const base::Vector<const uint8_t>& payload) { - int length = payload.length(); - uint8_t* blob = NewArray<uint8_t>(length); - memcpy(blob, payload.begin(), length); - return base::VectorOf(blob, length); + return base::UniqueCopyOf(payload); } // Convenience wrapper around the convenience wrapper. @@ -230,20 +223,16 @@ StartupBlobs Serialize(v8::Isolate* isolate) { WritePayload(shared_space_snapshot.RawData())}; } -base::Vector<const char> ConstructSource(base::Vector<const char> head, - base::Vector<const char> body, - base::Vector<const char> tail, - int repeats) { - size_t source_length = head.size() + body.size() * repeats + tail.size(); - char* source = NewArray<char>(source_length); - CopyChars(source, head.begin(), head.length()); +std::string ConstructSource(std::string_view head, std::string_view body, + std::string_view tail, int repeats) { + std::string source; + source.reserve(head.size() + body.size() * repeats + tail.size()); + source.append(head); for (int i = 0; i < repeats; i++) { - CopyChars(source + head.length() + i * body.length(), body.begin(), - body.length()); + source.append(body); } - CopyChars(source + head.length() + repeats * body.length(), tail.begin(), - tail.length()); - return base::VectorOf(source, source_length); + source.append(tail); + return source; } v8::Isolate* Deserialize(const StartupBlobs& blobs) { @@ -260,7 +249,7 @@ void SanityCheck(v8::Isolate* v8_isolate) { #endif CHECK(IsJSObject(*isolate->global_object())); CHECK(IsContext(*isolate->native_context())); - isolate->factory()->InternalizeString(base::StaticCharVector("Empty")); + isolate->factory()->InternalizeString("Empty"); } void TestStartupSerializerOnceImpl() { @@ -278,7 +267,6 @@ void TestStartupSerializerOnceImpl() { SanityCheck(isolate); } isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -296,7 +284,6 @@ UNINITIALIZED_TEST(StartupSerializerTwice) { isolate = Deserialize(blobs1); StartupBlobs blobs2 = Serialize(isolate); isolate->Dispose(); - blobs1.Dispose(); isolate = Deserialize(blobs2); { @@ -309,7 +296,6 @@ UNINITIALIZED_TEST(StartupSerializerTwice) { SanityCheck(isolate); } isolate->Dispose(); - blobs2.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -333,7 +319,6 @@ UNINITIALIZED_TEST(StartupSerializerOnceRunScript) { CHECK_EQ(4, result.FromJust()); } isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -345,7 +330,6 @@ UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { isolate = Deserialize(blobs1); StartupBlobs blobs2 = Serialize(isolate); isolate->Dispose(); - blobs1.Dispose(); isolate = Deserialize(blobs2); { @@ -363,14 +347,14 @@ UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { CHECK_EQ(4, result.FromJust()); } isolate->Dispose(); - blobs2.Dispose(); FreeCurrentEmbeddedBlob(); } -static void SerializeContext(base::Vector<const uint8_t>* startup_blob_out, - base::Vector<const uint8_t>* read_only_blob_out, - base::Vector<const uint8_t>* shared_space_blob_out, - base::Vector<const uint8_t>* context_blob_out) { +static void SerializeContext( + base::UniqueArray<const uint8_t>* startup_blob_out, + base::UniqueArray<const uint8_t>* read_only_blob_out, + base::UniqueArray<const uint8_t>* shared_space_blob_out, + base::UniqueArray<const uint8_t>* context_blob_out) { v8::Isolate* v8_isolate = TestSerializer::NewIsolateInitialized(); Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); Heap* heap = isolate->heap(); @@ -465,35 +449,31 @@ static void SerializeContext(base::Vector<const uint8_t>* startup_blob_out, #ifdef SNAPSHOT_COMPRESSION UNINITIALIZED_TEST(SnapshotCompression) { - base::Vector<const uint8_t> startup_blob; - base::Vector<const uint8_t> read_only_blob; - base::Vector<const uint8_t> shared_space_blob; - base::Vector<const uint8_t> context_blob; + base::UniqueArray<const uint8_t> startup_blob; + base::UniqueArray<const uint8_t> read_only_blob; + base::UniqueArray<const uint8_t> shared_space_blob; + base::UniqueArray<const uint8_t> context_blob; SerializeContext(&startup_blob, &read_only_blob, &shared_space_blob, &context_blob); - SnapshotData original_snapshot_data(context_blob); + SnapshotData original_snapshot_data(context_blob.as_span()); SnapshotData compressed = i::SnapshotCompression::Compress(&original_snapshot_data); SnapshotData decompressed = i::SnapshotCompression::Decompress(compressed.RawData()); CHECK_EQ(context_blob, decompressed.RawData()); - - startup_blob.Dispose(); - read_only_blob.Dispose(); - shared_space_blob.Dispose(); - context_blob.Dispose(); } #endif // SNAPSHOT_COMPRESSION UNINITIALIZED_TEST(ContextSerializerContext) { - base::Vector<const uint8_t> startup_blob; - base::Vector<const uint8_t> read_only_blob; - base::Vector<const uint8_t> shared_space_blob; - base::Vector<const uint8_t> context_blob; + base::UniqueArray<const uint8_t> startup_blob; + base::UniqueArray<const uint8_t> read_only_blob; + base::UniqueArray<const uint8_t> shared_space_blob; + base::UniqueArray<const uint8_t> context_blob; SerializeContext(&startup_blob, &read_only_blob, &shared_space_blob, &context_blob); - StartupBlobs blobs = {startup_blob, read_only_blob, shared_space_blob}; + StartupBlobs blobs = {std::move(startup_blob), std::move(read_only_blob), + std::move(shared_space_blob)}; v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs); CHECK(v8_isolate); { @@ -506,7 +486,7 @@ UNINITIALIZED_TEST(ContextSerializerContext) { isolate->factory()->NewUninitializedJSGlobalProxy( JSGlobalProxy::SizeWithEmbedderFields(0)); { - SnapshotData snapshot_data(context_blob); + SnapshotData snapshot_data(context_blob.as_span()); root = ContextDeserializer::DeserializeContext( isolate, &snapshot_data, 0, false, global_proxy, DeserializeEmbedderFieldsCallback( @@ -518,7 +498,7 @@ UNINITIALIZED_TEST(ContextSerializerContext) { DirectHandle<Object> root2; { - SnapshotData snapshot_data(context_blob); + SnapshotData snapshot_data(context_blob.as_span()); root2 = ContextDeserializer::DeserializeContext( isolate, &snapshot_data, 0, false, global_proxy, DeserializeEmbedderFieldsCallback( @@ -527,18 +507,16 @@ UNINITIALIZED_TEST(ContextSerializerContext) { CHECK(IsContext(*root2)); CHECK(!root.is_identical_to(root2)); } - context_blob.Dispose(); } v8_isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } static void SerializeCustomContext( - base::Vector<const uint8_t>* startup_blob_out, - base::Vector<const uint8_t>* read_only_blob_out, - base::Vector<const uint8_t>* shared_space_blob_out, - base::Vector<const uint8_t>* context_blob_out) { + base::UniqueArray<const uint8_t>* startup_blob_out, + base::UniqueArray<const uint8_t>* read_only_blob_out, + base::UniqueArray<const uint8_t>* shared_space_blob_out, + base::UniqueArray<const uint8_t>* context_blob_out) { v8::Isolate* isolate = TestSerializer::NewIsolateInitialized(); Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); @@ -568,14 +546,13 @@ static void SerializeCustomContext( "var p = 0;" "(async ()=>{ p = await 42; })();"); - base::Vector<const char> source = ConstructSource( - base::StaticCharVector("function g() { return [,"), - base::StaticCharVector("1,"), - base::StaticCharVector("];} a = g(); b = g(); b.push(1);"), 100000); + std::string source = + ConstructSource("function g() { return [,", "1,", + "];} a = g(); b = g(); b.push(1);", 100000); v8::MaybeLocal<v8::String> source_str = v8::String::NewFromUtf8( - isolate, source.begin(), v8::NewStringType::kNormal, source.length()); + isolate, source.data(), v8::NewStringType::kNormal, + static_cast<int>(source.size())); CompileRun(source_str.ToLocalChecked()); - source.Dispose(); } // If we don't do this then we end up with a stray root pointing at the // context even after we have disposed of env. @@ -666,14 +643,15 @@ static void SerializeCustomContext( } UNINITIALIZED_TEST(ContextSerializerCustomContext) { - base::Vector<const uint8_t> startup_blob; - base::Vector<const uint8_t> read_only_blob; - base::Vector<const uint8_t> shared_space_blob; - base::Vector<const uint8_t> context_blob; + base::UniqueArray<const uint8_t> startup_blob; + base::UniqueArray<const uint8_t> read_only_blob; + base::UniqueArray<const uint8_t> shared_space_blob; + base::UniqueArray<const uint8_t> context_blob; SerializeCustomContext(&startup_blob, &read_only_blob, &shared_space_blob, &context_blob); - StartupBlobs blobs = {startup_blob, read_only_blob, shared_space_blob}; + StartupBlobs blobs = {std::move(startup_blob), std::move(read_only_blob), + std::move(shared_space_blob)}; v8::Isolate* v8_isolate = TestSerializer::NewIsolateFromBlob(blobs); CHECK(v8_isolate); { @@ -686,7 +664,7 @@ UNINITIALIZED_TEST(ContextSerializerCustomContext) { isolate->factory()->NewUninitializedJSGlobalProxy( JSGlobalProxy::SizeWithEmbedderFields(0)); { - SnapshotData snapshot_data(context_blob); + SnapshotData snapshot_data(context_blob.as_span()); root = ContextDeserializer::DeserializeContext( isolate, &snapshot_data, 0, false, global_proxy, DeserializeEmbedderFieldsCallback( @@ -755,10 +733,8 @@ UNINITIALIZED_TEST(ContextSerializerCustomContext) { .FromJust(); CHECK_EQ(100002, b); } - context_blob.Dispose(); } v8_isolate->Dispose(); - blobs.Dispose(); FreeCurrentEmbeddedBlob(); } @@ -826,6 +802,34 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobOverwriteGlobal) { FreeCurrentEmbeddedBlob(); } +UNINITIALIZED_TEST(CustomSnapshotDataBlobDirectEval) { + // The direct eval records f's ScopeInfo weakly in Script::infos(). That + // ScopeInfo is promoted to RO space during snapshot creation; the reference + // must stay weak or calling f() again after deserialization fails a CHECK. + const char* source = "function f() { var x = 1; return eval('x + 1'); } f();"; + + DisableEmbeddedBlobRefcounting(); + v8::StartupData data = CreateSnapshotDataBlobInternal( + v8::SnapshotCreator::FunctionCodeHandling::kKeep, source); + + v8::Isolate::CreateParams params; + params.snapshot_blob = &data; + params.array_buffer_allocator = CcTest::array_buffer_allocator(); + + // Test-appropriate equivalent of v8::Isolate::New. + v8::Isolate* isolate = TestSerializer::NewIsolate(params); + { + v8::Isolate::Scope i_scope(isolate); + v8::HandleScope h_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope c_scope(context); + ExpectInt32("f()", 2); + } + isolate->Dispose(); + delete[] data.data; + FreeCurrentEmbeddedBlob(); +} + UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) { const char* source1 = R"javascript( @@ -1809,13 +1813,11 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobImmortalImmovableRoots) { // Flood the startup snapshot with shared function infos. If they are // serialized before the immortal immovable root, the root will no longer end // up on the first page. - base::Vector<const char> source = - ConstructSource(base::StaticCharVector("var a = [];"), - base::StaticCharVector("a.push(function() {return 7});"), - base::StaticCharVector("\0"), 10000); + std::string source = ConstructSource( + "var a = [];", "a.push(function() {return 7});", "", 10000); DisableEmbeddedBlobRefcounting(); - v8::StartupData data = CreateSnapshotDataBlob(source.begin()); + v8::StartupData data = CreateSnapshotDataBlob(source.c_str()); v8::Isolate::CreateParams params; params.snapshot_blob = &data; @@ -1831,7 +1833,6 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobImmortalImmovableRoots) { CHECK_EQ(7, CompileRun("a[0]()")->Int32Value(context).FromJust()); } isolate->Dispose(); - source.Dispose(); delete[] data.data; // We can dispose of the snapshot blob now. FreeCurrentEmbeddedBlob(); } @@ -1912,12 +1913,10 @@ TEST(CodeSerializerWithProfiler) { const char* source = "1 + 1"; - Handle<String> orig_source = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); - Handle<String> copy_source = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + Handle<String> orig_source = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); + Handle<String> copy_source = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); CHECK(!orig_source.is_identical_to(copy_source)); CHECK(orig_source->Equals(*copy_source)); @@ -1955,12 +1954,10 @@ void TestCodeSerializerOnePlusOneImpl(bool verify_builtins_count = true) { const char* source = "1 + 1"; - Handle<String> orig_source = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); - Handle<String> copy_source = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + Handle<String> orig_source = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); + Handle<String> copy_source = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); CHECK(!orig_source.is_identical_to(copy_source)); CHECK(orig_source->Equals(*copy_source)); @@ -2452,12 +2449,10 @@ TEST(CodeSerializerInternalizedString) { const char* source = "'string1'"; - Handle<String> orig_source = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); - Handle<String> copy_source = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + Handle<String> orig_source = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); + Handle<String> copy_source = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); CHECK(!orig_source.is_identical_to(copy_source)); CHECK(orig_source->Equals(*copy_source)); @@ -2514,11 +2509,10 @@ TEST(CodeSerializerLargeCodeObject) { v8::HandleScope scope(CcTest::isolate()); - base::Vector<const char> source = ConstructSource( - base::StaticCharVector("var j=1; if (j == 0) {"), - base::StaticCharVector( - "for (let i of Object.prototype) for (let k = 0; k < 0; ++k);"), - base::StaticCharVector("} j=7; j"), 2000); + std::string source = ConstructSource( + "var j=1; if (j == 0) {", + "for (let i of Object.prototype) for (let k = 0; k < 0; ++k);", + "} j=7; j", 2000); Handle<String> source_str = isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); @@ -2557,15 +2551,13 @@ TEST(CodeSerializerLargeCodeObject) { CHECK_EQ(7, result_int); delete cache; - source.Dispose(); } TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { if (!v8_flags.incremental_marking) return; if (!v8_flags.compact) return; ManualGCScope manual_gc_scope; - const char* filter_flag = "--turbo-filter=NOTHING"; - FlagList::SetFlagsFromString(filter_flag, strlen(filter_flag)); + v8_flags.turbo_filter.Set("NOTHING"); heap::ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); @@ -2577,10 +2569,9 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { v8::HandleScope scope(CcTest::isolate()); - base::Vector<const char> source = ConstructSource( - base::StaticCharVector("var j=1; if (j == 0) {"), - base::StaticCharVector("for (var i = 0; i < Object.prototype; i++);"), - base::StaticCharVector("} j=7; var s = 'happy_hippo'; j"), 20000); + std::string source = ConstructSource( + "var j=1; if (j == 0) {", "for (var i = 0; i < Object.prototype; i++);", + "} j=7; var s = 'happy_hippo'; j", 20000); Handle<String> source_str = isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); @@ -2642,7 +2633,6 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) { CHECK_EQ(7, result_int); delete cache; - source.Dispose(); } TEST(CodeSerializerLargeStrings) { @@ -2654,12 +2644,10 @@ TEST(CodeSerializerLargeStrings) { v8::HandleScope scope(CcTest::isolate()); - base::Vector<const char> source_s = ConstructSource( - base::StaticCharVector("var s = \""), base::StaticCharVector("abcdef"), - base::StaticCharVector("\";"), 1000000); - base::Vector<const char> source_t = ConstructSource( - base::StaticCharVector("var t = \""), base::StaticCharVector("uvwxyz"), - base::StaticCharVector("\"; s + t"), 999999); + std::string source_s = + ConstructSource("var s = \"", "abcdef", "\";", 1000000); + std::string source_t = + ConstructSource("var t = \"", "uvwxyz", "\"; s + t", 999999); Handle<String> source_str = f->NewConsString(f->NewStringFromUtf8(source_s).ToHandleChecked(), f->NewStringFromUtf8(source_t).ToHandleChecked()) @@ -2705,8 +2693,6 @@ TEST(CodeSerializerLargeStrings) { #endif delete cache; - source_s.Dispose(); - source_t.Dispose(); } TEST(CodeSerializerThreeBigStrings) { @@ -2722,21 +2708,15 @@ TEST(CodeSerializerThreeBigStrings) { const int32_t length_of_b = kMaxRegularHeapObjectSize / 2; const int32_t length_of_c = kMaxRegularHeapObjectSize / 2; - base::Vector<const char> source_a = ConstructSource( - base::StaticCharVector("var a = \""), base::StaticCharVector("a"), - base::StaticCharVector("\";"), length_of_a); + std::string source_a = ConstructSource("var a = \"", "a", "\";", length_of_a); Handle<String> source_a_str = f->NewStringFromUtf8(source_a).ToHandleChecked(); - base::Vector<const char> source_b = ConstructSource( - base::StaticCharVector("var b = \""), base::StaticCharVector("b"), - base::StaticCharVector("\";"), length_of_b); + std::string source_b = ConstructSource("var b = \"", "b", "\";", length_of_b); Handle<String> source_b_str = f->NewStringFromUtf8(source_b).ToHandleChecked(); - base::Vector<const char> source_c = ConstructSource( - base::StaticCharVector("var c = \""), base::StaticCharVector("c"), - base::StaticCharVector("\";"), length_of_c); + std::string source_c = ConstructSource("var c = \"", "c", "\";", length_of_c); Handle<String> source_c_str = f->NewStringFromUtf8(source_c).ToHandleChecked(); @@ -2792,9 +2772,6 @@ TEST(CodeSerializerThreeBigStrings) { CHECK(heap->InSpace(*v8::Utils::OpenDirectHandle(*result_str), OLD_SPACE)); delete cache; - source_a.Dispose(); - source_b.Dispose(); - source_c.Dispose(); } class SerializerOneByteResource @@ -2866,9 +2843,7 @@ TEST(CodeSerializerExternalString) { "o.two_byte = 8; \n" "o.one_byte + o.two_byte; \n"; Handle<String> source_string = - isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); DirectHandle<JSObject> global(isolate->context()->global_object(), isolate); AlignedCachedData* cache = nullptr; @@ -2979,6 +2954,62 @@ UNINITIALIZED_TEST(CodeSerializerExternalStringResourceDataRestored) { isolate->Dispose(); } +// The resource of an external string is restored from the code cache. +UNINITIALIZED_TEST(CodeSerializerExternalStringRoundTrip) { + // Off-thread deserialization doesn't support external strings with API + // resources. + v8_flags.stress_background_compile = false; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + create_params.external_references = external_code_cache_references; + + v8::ScriptCompiler::CachedData* cache; + v8::Isolate* isolate1 = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(isolate1); + v8::HandleScope scope(isolate1); + v8::Local<v8::Context> context = v8::Context::New(isolate1); + v8::Context::Scope context_scope(context); + + v8::Local<v8::String> name_string = + v8::String::NewExternalOneByte(isolate1, + &external_code_cache_name_resource) + .ToLocalChecked(); + v8::ScriptCompiler::Source source(v8_str(kExternalCodeCacheSource), + {name_string}); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript( + isolate1, &source, v8::ScriptCompiler::kEagerCompile) + .ToLocalChecked(); + cache = v8::ScriptCompiler::CreateCodeCache(script); + } + isolate1->Dispose(); + + v8::Isolate* isolate2 = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(isolate2); + v8::HandleScope scope(isolate2); + v8::Local<v8::Context> context = v8::Context::New(isolate2); + v8::Context::Scope context_scope(context); + + // Without an origin, the script name is taken from the code cache. + v8::ScriptCompiler::Source source(v8_str(kExternalCodeCacheSource), cache); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript( + isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!source.GetCachedData()->rejected); + v8::Local<v8::Value> name = script->GetScriptName(); + CHECK(name->IsString()); + CHECK(name.As<v8::String>()->GetExternalOneByteStringResource() == + &external_code_cache_name_resource); + v8::Local<v8::Value> result = + script->BindToCurrentContext()->Run(context).ToLocalChecked(); + CHECK(result->StrictEquals(v8_str("abcdef"))); + } + isolate2->Dispose(); +} + TEST(CodeSerializerLargeExternalString) { LocalContext context; Isolate* isolate = CcTest::i_isolate(); @@ -2990,12 +3021,9 @@ TEST(CodeSerializerLargeExternalString) { v8::HandleScope scope(CcTest::isolate()); // Create a huge external internalized string to use as variable name. - base::Vector<const char> string = ConstructSource( - base::StaticCharVector(""), base::StaticCharVector("abcdef"), - base::StaticCharVector(""), 999999); + std::string string = ConstructSource("", "abcdef", "", 999999); Handle<String> name = f->NewStringFromUtf8(string).ToHandleChecked(); - SerializerOneByteResource one_byte_resource( - reinterpret_cast<const char*>(string.begin()), string.length()); + SerializerOneByteResource one_byte_resource(string.data(), string.size()); name = f->InternalizeString(name); name->MakeExternal(isolate, &one_byte_resource); CHECK(IsExternalOneByteString(*name)); @@ -3040,7 +3068,6 @@ TEST(CodeSerializerLargeExternalString) { // This avoids the GC from trying to free stack allocated resources. i::Cast<i::ExternalOneByteString>(name)->SetResource(isolate, nullptr); delete cache; - string.Dispose(); } TEST(CodeSerializerExternalScriptName) { @@ -3057,8 +3084,7 @@ TEST(CodeSerializerExternalScriptName) { "var a = [1, 2, 3, 4];" "a.reduce(function(x, y) { return x + y }, 0)"; - Handle<String> source_string = - f->NewStringFromUtf8(base::CStrVector(source)).ToHandleChecked(); + Handle<String> source_string = f->NewStringFromUtf8(source).ToHandleChecked(); const SerializerOneByteResource one_byte_resource("one_byte", 8); Handle<String> name = @@ -3498,6 +3524,30 @@ TEST(CodeSerializerEmbedderString) { isolate->Dispose(); } +// The trusted section must be part of the payload. +TEST(CodeSerializerTrustedSectionLengthMismatch) { + std::unique_ptr<v8::ScriptCompiler::CachedData> cache( + CompileRunAndProduceCache("'abcdef'")); + Address header = reinterpret_cast<Address>(cache->data); + base::WriteLittleEndianValue<uint32_t>( + header + SerializedCodeData::kTrustedPayloadLengthOffset, + base::ReadLittleEndianValue<uint32_t>( + header + SerializedCodeData::kPayloadLengthOffset) + + 1); + CHECK_EQ(cache->CompatibilityCheck(CcTest::isolate()), + v8::ScriptCompiler::CachedData::kLengthMismatch); +} + +// The checksum covers the trusted section. +TEST(CodeSerializerTrustedSectionBitFlip) { + i::v8_flags.verify_snapshot_checksum = true; + std::unique_ptr<v8::ScriptCompiler::CachedData> cache( + CompileRunAndProduceCache("'abcdef'")); + const_cast<uint8_t*>(cache->data)[SerializedCodeData::kHeaderSize] ^= 0x40; + CHECK_EQ(cache->CompatibilityCheck(CcTest::isolate()), + v8::ScriptCompiler::CachedData::kChecksumMismatch); +} + TEST(CodeSerializerBitFlip) { i::v8_flags.verify_snapshot_checksum = true; const char* js_source = "function f() { return 'abc'; }; f() + 'def'"; @@ -3528,6 +3578,118 @@ TEST(CodeSerializerBitFlip) { isolate2->Dispose(); } +namespace { +v8::Local<v8::UnboundScript> ConsumeCodeCache( + const char* js_source, v8::ScriptCompiler::CachedData* cache) { + v8::ScriptCompiler::Source source(v8_str(js_source), {v8_str("test")}, cache); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript( + CcTest::isolate(), &source, v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!cache->rejected); + return script; +} +} // namespace + +#ifdef V8_ENABLE_SANDBOX +// Objects from the trusted section refer to the untrusted section, and the +// SharedFunctionInfo and BytecodeWrapper share one export. +TEST(CodeSerializerTrustedSectionRoundTrip) { + const char* js_source = "function f() { function g() {} }; 'abcdef'"; + v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(js_source); + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + v8::HandleScope scope(CcTest::isolate()); + DirectHandle<SharedFunctionInfo> toplevel = + v8::Utils::OpenDirectHandle(*ConsumeCodeCache(js_source, cache)); + Tagged<BytecodeArray> bytecode = toplevel->GetBytecodeArray(isolate); + CHECK(TrustedHeapLayout::InTrustedSpace(bytecode)); + CHECK_EQ(bytecode->wrapper()->bytecode(isolate), bytecode); + SharedFunctionInfo::ScriptIterator it(isolate, + Cast<Script>(toplevel->script())); + CHECK_EQ(it.Next(), *toplevel); + Tagged<SharedFunctionInfo> f = it.Next(); + CHECK(TrustedHeapLayout::InTrustedSpace(f->uncompiled_data(isolate))); + CHECK(IsPreparseData( + f->uncompiled_data_with_preparse_data(isolate)->preparse_data())); +} +#endif // V8_ENABLE_SANDBOX + +// The job is written as null without modifying the live object. +TEST(CodeSerializerUncompiledDataJob) { + constexpr Address kJob = 0x1230; + const char* js_source = "function f() {}; function g() { function h() {} }"; + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + isolate->compilation_cache()->DisableScriptAndEval(); + Factory* factory = isolate->factory(); + v8::HandleScope scope(CcTest::isolate()); + v8::ScriptCompiler::Source source(v8_str(js_source), {v8_str("test")}); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript(CcTest::isolate(), &source) + .ToLocalChecked(); + DirectHandle<SharedFunctionInfo> toplevel = + v8::Utils::OpenDirectHandle(*script); + SharedFunctionInfo::ScriptIterator it(isolate, + Cast<Script>(toplevel->script())); + CHECK_EQ(it.Next(), *toplevel); + DirectHandle<SharedFunctionInfo> f(it.Next(), isolate); + DirectHandle<SharedFunctionInfo> g(it.Next(), isolate); + DirectHandle<UncompiledDataWithoutPreparseDataWithJob> f_data = + factory->NewUncompiledDataWithoutPreparseDataWithJob( + factory->empty_string(), f->StartPosition(), f->EndPosition()); + DirectHandle<UncompiledDataWithPreparseDataAndJob> g_data = + factory->NewUncompiledDataWithPreparseDataAndJob( + factory->empty_string(), g->StartPosition(), g->EndPosition(), + direct_handle( + g->uncompiled_data_with_preparse_data(isolate)->preparse_data(), + isolate)); + f_data->set_job(kJob); + g_data->set_job(kJob); + f->set_uncompiled_data(*f_data); + g->set_uncompiled_data(*g_data); + + std::unique_ptr<v8::ScriptCompiler::CachedData> cache( + v8::ScriptCompiler::CreateCodeCache(script)); + CHECK_EQ(f_data->job(), kJob); + CHECK_EQ(g_data->job(), kJob); + + toplevel = v8::Utils::OpenDirectHandle( + *ConsumeCodeCache(js_source, cache.release())); + SharedFunctionInfo::ScriptIterator copy_it(isolate, + Cast<Script>(toplevel->script())); + CHECK_EQ(copy_it.Next(), *toplevel); + CHECK_EQ(TrustedCast<UncompiledDataWithoutPreparseDataWithJob>( + copy_it.Next()->uncompiled_data(isolate)) + ->job(), + kNullAddress); + CHECK_EQ(TrustedCast<UncompiledDataWithPreparseDataAndJob>( + copy_it.Next()->uncompiled_data(isolate)) + ->job(), + kNullAddress); +} + +// InterpreterData is serialized as its bytecode. +TEST(CodeSerializerInterpreterData) { + v8_flags.interpreted_frames_native_stack = true; + const char* js_source = "function f() { return 'abc'; }; f() + 'def'"; + v8::ScriptCompiler::CachedData* cache = + CompileRunAndProduceCache(js_source, CodeCacheType::kEager); + LocalContext context; + CcTest::i_isolate()->compilation_cache()->DisableScriptAndEval(); + v8::HandleScope scope(CcTest::isolate()); + // Deserializing creates InterpreterData. + v8::Local<v8::UnboundScript> script = ConsumeCodeCache(js_source, cache); + CHECK(v8::Utils::OpenDirectHandle(*script)->HasInterpreterData( + CcTest::i_isolate())); + script = + ConsumeCodeCache(js_source, v8::ScriptCompiler::CreateCodeCache(script)); + CHECK(script->BindToCurrentContext() + ->Run(context.local()) + .ToLocalChecked() + ->StrictEquals(v8_str("abcdef"))); +} + TEST(CodeSerializerWithHarmonyScoping) { const char* source1 = "'use strict'; let x = 'X'"; const char* source2 = "'use strict'; let y = 'Y'"; @@ -3867,8 +4029,11 @@ UNINITIALIZED_TEST(SnapshotCreatorExternalReferences) { v8::Context::Scope context_scope(context); v8::Local<v8::External> writable_external = v8::External::New(isolate, &serialized_static_field, kIntPointerTag); + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V3. context->SetEmbedderDataV2(my_context_embedder_field_index, writable_external); + END_ALLOW_USE_DEPRECATED() v8::Local<v8::External> external = v8::External::New(isolate, &serialized_static_field, kIntPointerTag); v8::Local<v8::FunctionTemplate> callback = @@ -4581,7 +4746,10 @@ void DeserializeContextData(v8::Local<v8::Context> context, int index, InternalFieldData* field = new InternalFieldData{0}; memcpy(field, payload.data, payload.raw_size); CHECK_EQ(context_data.data, field->data); + START_ALLOW_USE_DEPRECATED() + // TODO(b/570436596): Migrate to V2. context->SetAlignedPointerInEmbedderData(index, field, kInternalFieldDataTag); + END_ALLOW_USE_DEPRECATED() } } // namespace context_data_test @@ -4612,8 +4780,8 @@ UNINITIALIZED_TEST(SerializeContextData) { v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - context->SetAlignedPointerInEmbedderData(0, nullptr, kRawDataTag); - context->SetAlignedPointerInEmbedderData( + context->SetAlignedPointerInEmbedderDataV2(0, nullptr, kRawDataTag); + context->SetAlignedPointerInEmbedderDataV2( 1, &context_data_test::context_data, kRawDataTag); v8::Local<v8::ObjectTemplate> object_template = @@ -4651,7 +4819,7 @@ UNINITIALIZED_TEST(SerializeContextData) { context->GetAlignedPointerFromEmbedderData(1, kInternalFieldDataTag)); CHECK_EQ(context_data_test::context_data.data, data->data); - context->SetAlignedPointerInEmbedderData(1, nullptr, kRawDataTag); + context->SetAlignedPointerInEmbedderDataV2(1, nullptr, kRawDataTag); delete data; v8::Local<v8::Value> obj_val = @@ -4682,8 +4850,8 @@ UNINITIALIZED_TEST(SerializeContextData) { v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - context->SetAlignedPointerInEmbedderData(0, nullptr, kRawDataTag); - context->SetAlignedPointerInEmbedderData( + context->SetAlignedPointerInEmbedderDataV2(0, nullptr, kRawDataTag); + context->SetAlignedPointerInEmbedderDataV2( 1, &context_data_test::context_data, kRawDataTag); v8::Local<v8::ObjectTemplate> object_template = @@ -4723,7 +4891,7 @@ UNINITIALIZED_TEST(SerializeContextData) { context->GetAlignedPointerFromEmbedderData(1, kInternalFieldDataTag)); CHECK_EQ(context_data_test::context_data.data, data->data); - context->SetAlignedPointerInEmbedderData(1, nullptr, kRawDataTag); + context->SetAlignedPointerInEmbedderDataV2(1, nullptr, kRawDataTag); delete data; v8::Local<v8::Value> obj_val = @@ -4758,8 +4926,8 @@ UNINITIALIZED_TEST(SerializeContextData) { v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - context->SetAlignedPointerInEmbedderData(0, nullptr, kRawDataTag); - context->SetAlignedPointerInEmbedderData(1, raw_data, kRawDataTag); + context->SetAlignedPointerInEmbedderDataV2(0, nullptr, kRawDataTag); + context->SetAlignedPointerInEmbedderDataV2(1, raw_data, kRawDataTag); v8::Local<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); @@ -6354,9 +6522,8 @@ TEST(WeakArraySerializationInCodeCache) { const char* source = "function foo() { }"; - Handle<String> src = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + Handle<String> src = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); AlignedCachedData* cache = nullptr; ScriptDetails script_details(src); @@ -6682,6 +6849,276 @@ TEST(InvalidCachedCompileFunction) { } } +TEST(CodeCacheSha256SourceHash) { + LocalContext env; + v8::Isolate* isolate = env.isolate(); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i_isolate->compilation_cache()->DisableScriptAndEval(); + + v8::HandleScope scope(isolate); + + // 1. Direct unit checks on SourceHash with SHA256 flag enabled. + { + FlagScope<bool> flag_scope(&v8_flags.code_cache_source_hash_sha256, true); + + // Use a 600-character string (> ConsString::kMinLength == 13) so + // ConsString flattening and SlicedString handling are exercised. + static constexpr int kPartLength = 300; + static constexpr int kTotalLength = kPartLength * 2; + std::string part1_ascii(kPartLength, 'a'); + std::string part2_ascii(kPartLength, 'b'); + for (int i = 0; i < kPartLength; ++i) { + part1_ascii[i] = static_cast<char>('a' + (i % 26)); + part2_ascii[i] = static_cast<char>('A' + (i % 26)); + } + std::string full_ascii = part1_ascii + part2_ascii; + + Handle<String> one_byte = + i_isolate->factory()->NewStringFromAsciiChecked(full_ascii.c_str()); + CHECK(one_byte->IsOneByteRepresentation()); + + std::vector<uint16_t> two_byte_data(kTotalLength); + for (int i = 0; i < kTotalLength; ++i) { + two_byte_data[i] = static_cast<uint16_t>(full_ascii[i]); + } + Handle<String> two_byte = i_isolate->factory() + ->NewRawTwoByteString(kTotalLength) + .ToHandleChecked(); + { + DisallowGarbageCollection no_gc; + CopyChars(Cast<SeqTwoByteString>(*two_byte)->GetChars(no_gc), + two_byte_data.data(), kTotalLength); + } + CHECK(!two_byte->IsOneByteRepresentation()); + + Handle<String> part1 = + i_isolate->factory()->NewStringFromAsciiChecked(part1_ascii.c_str()); + Handle<String> part2 = + i_isolate->factory()->NewStringFromAsciiChecked(part2_ascii.c_str()); + Handle<String> cons = + i_isolate->factory()->NewConsString(part1, part2).ToHandleChecked(); + CHECK(IsConsString(*cons)); + CHECK(!cons->IsFlat()); + + // ConsString with mixed one-byte and two-byte leaves flattens to two-byte. + Handle<String> two_byte_part2 = i_isolate->factory() + ->NewRawTwoByteString(kPartLength) + .ToHandleChecked(); + { + DisallowGarbageCollection no_gc; + CopyChars(Cast<SeqTwoByteString>(*two_byte_part2)->GetChars(no_gc), + two_byte_data.data() + kPartLength, kPartLength); + } + Handle<String> cons_mixed = i_isolate->factory() + ->NewConsString(part1, two_byte_part2) + .ToHandleChecked(); + CHECK(IsConsString(*cons_mixed)); + CHECK(!cons_mixed->IsFlat()); + + // SlicedString representation of the same content. + std::string padded_ascii = "0123456789" + full_ascii + "9876543210"; + Handle<String> padded = + i_isolate->factory()->NewStringFromAsciiChecked(padded_ascii.c_str()); + Handle<String> sliced = + i_isolate->factory()->NewProperSubString(padded, 10, 10 + kTotalLength); + CHECK(IsSlicedString(*sliced)); + + Handle<FixedArray> empty_wrapped_arguments; + ScriptOriginOptions default_origin_options; + + SerializedCodeData::SourceHash hash_one_byte( + one_byte, empty_wrapped_arguments, default_origin_options, i_isolate); + SerializedCodeData::SourceHash hash_two_byte( + two_byte, empty_wrapped_arguments, default_origin_options, i_isolate); + SerializedCodeData::SourceHash hash_cons(cons, empty_wrapped_arguments, + default_origin_options, i_isolate); + SerializedCodeData::SourceHash hash_cons_mixed( + cons_mixed, empty_wrapped_arguments, default_origin_options, i_isolate); + SerializedCodeData::SourceHash hash_sliced( + sliced, empty_wrapped_arguments, default_origin_options, i_isolate); + + CHECK_EQ(hash_one_byte.kSize, kSizeOfSha256Digest); + CHECK_EQ(hash_one_byte, hash_cons); + CHECK_EQ(hash_one_byte, hash_sliced); + CHECK_NE(hash_one_byte, hash_two_byte); + CHECK_EQ(hash_two_byte, hash_cons_mixed); + + // A one-byte string with the exact same raw byte sequence as a two-byte + // string (twice the character length) must produce a different hash + // because the character length is included in the hash. + Handle<SeqOneByteString> one_byte_same_raw_bytes = + i_isolate->factory() + ->NewRawOneByteString(kTotalLength * sizeof(uint16_t)) + .ToHandleChecked(); + { + DisallowGarbageCollection no_gc; + CopyChars(one_byte_same_raw_bytes->GetChars(no_gc), + reinterpret_cast<const uint8_t*>(two_byte_data.data()), + kTotalLength * sizeof(uint16_t)); + } + SerializedCodeData::SourceHash hash_same_raw_bytes( + one_byte_same_raw_bytes, empty_wrapped_arguments, + default_origin_options, i_isolate); + CHECK_NE(hash_two_byte, hash_same_raw_bytes); + + // Different content of the same length produces a different hash. + std::string diff_ascii = full_ascii; + diff_ascii[550] ^= 1; + Handle<String> diff_content = + i_isolate->factory()->NewStringFromAsciiChecked(diff_ascii.c_str()); + SerializedCodeData::SourceHash hash_diff(diff_content, + empty_wrapped_arguments, + default_origin_options, i_isolate); + CHECK_NE(hash_one_byte, hash_diff); + + // Module origin produces different hash. + ScriptOriginOptions module_origin_options(false, false, false, true); + SerializedCodeData::SourceHash hash_module( + one_byte, empty_wrapped_arguments, module_origin_options, i_isolate); + CHECK_NE(hash_one_byte, hash_module); + + // Wrapped arguments presence and contents produce different hashes. + Handle<FixedArray> wrapped_zero = i_isolate->factory()->NewFixedArray(0); + SerializedCodeData::SourceHash hash_wrapped_zero( + one_byte, wrapped_zero, default_origin_options, i_isolate); + CHECK_NE(hash_one_byte, hash_wrapped_zero); + + Handle<FixedArray> wrapped_x = i_isolate->factory()->NewFixedArray(1); + wrapped_x->set(0, *i_isolate->factory()->NewStringFromAsciiChecked("x")); + Handle<FixedArray> wrapped_y = i_isolate->factory()->NewFixedArray(1); + wrapped_y->set(0, *i_isolate->factory()->NewStringFromAsciiChecked("y")); + SerializedCodeData::SourceHash hash_wrapped_x( + one_byte, wrapped_x, default_origin_options, i_isolate); + SerializedCodeData::SourceHash hash_wrapped_y( + one_byte, wrapped_y, default_origin_options, i_isolate); + CHECK_NE(hash_wrapped_zero, hash_wrapped_x); + CHECK_NE(hash_wrapped_x, hash_wrapped_y); + + // Argument boundaries are domain-separated (["ab", "c"] != ["a", "bc"]). + Handle<FixedArray> wrapped_ab_c = i_isolate->factory()->NewFixedArray(2); + wrapped_ab_c->set(0, + *i_isolate->factory()->NewStringFromAsciiChecked("ab")); + wrapped_ab_c->set(1, *i_isolate->factory()->NewStringFromAsciiChecked("c")); + Handle<FixedArray> wrapped_a_bc = i_isolate->factory()->NewFixedArray(2); + wrapped_a_bc->set(0, *i_isolate->factory()->NewStringFromAsciiChecked("a")); + wrapped_a_bc->set(1, + *i_isolate->factory()->NewStringFromAsciiChecked("bc")); + SerializedCodeData::SourceHash hash_wrapped_ab_c( + one_byte, wrapped_ab_c, default_origin_options, i_isolate); + SerializedCodeData::SourceHash hash_wrapped_a_bc( + one_byte, wrapped_a_bc, default_origin_options, i_isolate); + CHECK_NE(hash_wrapped_ab_c, hash_wrapped_a_bc); + } + + // 2. End-to-end code cache serialization and rejection on same-length source + // or parameter name change. + { + FlagScope<bool> flag_scope(&v8_flags.code_cache_source_hash_sha256, true); + + v8::Local<v8::String> source1 = v8_str("function f() { return 1; }"); + v8::Local<v8::String> source2 = v8_str("function f() { return 2; }"); + CHECK_EQ(source1->Length(), source2->Length()); + + // 2a. Consuming with the exact same source succeeds. + { + v8::ScriptCompiler::Source script_source(source1); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript( + isolate, &script_source, v8::ScriptCompiler::kEagerCompile) + .ToLocalChecked(); + ScriptCompiler::CachedData* cache = + v8::ScriptCompiler::CreateCodeCache(script); + CHECK_NOT_NULL(cache); + CHECK(!cache->rejected); + + v8::ScriptCompiler::Source consume_source(source1, cache); + v8::Local<v8::UnboundScript> script2 = + v8::ScriptCompiler::CompileUnboundScript( + isolate, &consume_source, v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!script2.IsEmpty()); + CHECK(!consume_source.GetCachedData()->rejected); + } + + // 2b. Consuming with different source of the same length must be rejected + // with SHA256. + { + v8::ScriptCompiler::Source script_source(source1); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript( + isolate, &script_source, v8::ScriptCompiler::kEagerCompile) + .ToLocalChecked(); + ScriptCompiler::CachedData* cache = + v8::ScriptCompiler::CreateCodeCache(script); + CHECK_NOT_NULL(cache); + CHECK(!cache->rejected); + + v8::ScriptCompiler::Source consume_source(source2, cache); + v8::Local<v8::UnboundScript> script2 = + v8::ScriptCompiler::CompileUnboundScript( + isolate, &consume_source, v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!script2.IsEmpty()); + CHECK(consume_source.GetCachedData()->rejected); + } + + // 2c. CompileFunction cache is rejected if wrapped argument names differ. + { + v8::Local<v8::String> body = v8_str("return arguments[0];"); + v8::Local<v8::String> arg_x = v8_str("x"); + v8::Local<v8::String> arg_y = v8_str("y"); + v8::ScriptCompiler::Source script_source(body); + v8::Local<v8::Function> fun = + v8::ScriptCompiler::CompileFunction(env.local(), &script_source, 1, + &arg_x, 0, nullptr, + v8::ScriptCompiler::kEagerCompile) + .ToLocalChecked(); + ScriptCompiler::CachedData* cache = + v8::ScriptCompiler::CreateCodeCacheForFunction(fun); + CHECK_NOT_NULL(cache); + CHECK(!cache->rejected); + + v8::ScriptCompiler::Source consume_source(body, cache); + v8::Local<v8::Function> fun2 = + v8::ScriptCompiler::CompileFunction( + env.local(), &consume_source, 1, &arg_y, 0, nullptr, + v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!fun2.IsEmpty()); + CHECK(consume_source.GetCachedData()->rejected); + } + } + + // 3. Cached data produced with SHA-256 is rejected if flag is disabled. + { + v8::Local<v8::String> source = v8_str("function f() { return 42; }"); + ScriptCompiler::CachedData* sha256_cache; + { + FlagScope<bool> flag_scope(&v8_flags.code_cache_source_hash_sha256, true); + v8::ScriptCompiler::Source script_source(source); + v8::Local<v8::UnboundScript> script = + v8::ScriptCompiler::CompileUnboundScript( + isolate, &script_source, v8::ScriptCompiler::kEagerCompile) + .ToLocalChecked(); + sha256_cache = v8::ScriptCompiler::CreateCodeCache(script); + CHECK_NOT_NULL(sha256_cache); + CHECK(!sha256_cache->rejected); + } + + { + FlagScope<bool> flag_scope(&v8_flags.code_cache_source_hash_sha256, + false); + v8::ScriptCompiler::Source consume_source(source, sha256_cache); + v8::Local<v8::UnboundScript> script2 = + v8::ScriptCompiler::CompileUnboundScript( + isolate, &consume_source, v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!script2.IsEmpty()); + CHECK(consume_source.GetCachedData()->rejected); + } + } +} + TEST(CachedCompileFunctionRespectsEager) { LocalContext env; Isolate* isolate = CcTest::i_isolate(); @@ -6823,69 +7260,6 @@ UNINITIALIZED_TEST(NoStackFrameCacheSerialization) { delete[] blob.data; } -namespace { -void CheckObjectsAreInSharedHeap(Isolate* isolate) { - Heap* heap = isolate->heap(); - SetCurrentIsolateScope isolate_scope(isolate); - SetCurrentLocalHeapScope local_heap_scope(isolate); - HeapObjectIterator iterator(heap); - DisallowGarbageCollection no_gc; - for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null(); - obj = iterator.Next()) { - const bool expected_in_shared_old = - heap->MustBeInSharedOldSpace(obj) || - (IsString(obj) && String::IsInPlaceInternalizable(Cast<String>(obj))); - if (expected_in_shared_old) { - CHECK(HeapLayout::InAnySharedSpace(obj)); - } - } -} -} // namespace - -UNINITIALIZED_TEST(SharedStrings) { - // Test that deserializing with --shared-string-table deserializes into the - // shared Isolate. - - if (!V8_CAN_CREATE_SHARED_HEAP_BOOL) return; - // In multi-cage mode we create one cage per isolate - // and we don't share objects between cages. - if (COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL) return; - - // Make all the flags that require a shared heap false before creating the - // isolate to serialize. - v8_flags.shared_string_table = false; - v8_flags.harmony_struct = false; - - v8::Isolate* isolate_to_serialize = TestSerializer::NewIsolateInitialized(); - StartupBlobs blobs = Serialize(isolate_to_serialize); - isolate_to_serialize->Dispose(); - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - v8::Isolate* isolate1 = TestSerializer::NewIsolateFromBlob(blobs); - v8::Isolate* isolate2 = TestSerializer::NewIsolateFromBlob(blobs); - Isolate* i_isolate1 = reinterpret_cast<Isolate*>(isolate1); - Isolate* i_isolate2 = reinterpret_cast<Isolate*>(isolate2); - - CHECK_EQ(i_isolate1->string_table(), i_isolate2->string_table()); - i_isolate2->main_thread_local_heap()->ExecuteMainThreadWhileParked( - [i_isolate1]() { CheckObjectsAreInSharedHeap(i_isolate1); }); - - i_isolate1->main_thread_local_heap()->ExecuteMainThreadWhileParked( - [i_isolate2]() { CheckObjectsAreInSharedHeap(i_isolate2); }); - - // Because both isolate1 and isolate2 are considered running on the main - // thread, one must be parked to avoid deadlock in the shared heap - // verification that may happen on client heap disposal. - i_isolate1->main_thread_local_heap()->ExecuteMainThreadWhileParked( - [isolate2]() { isolate2->Dispose(); }); - isolate1->Dispose(); - - blobs.Dispose(); - FreeCurrentEmbeddedBlob(); -} - namespace { class DebugBreakCounter : public v8::debug::DebugDelegate { @@ -7035,12 +7409,140 @@ UNINITIALIZED_TEST(StaticRootsPredictableSnapshot) { // be different. CHECK_EQ(blobs1.read_only, blobs2.read_only); - blobs1.Dispose(); - blobs2.Dispose(); FreeCurrentEmbeddedBlob(); } #endif // defined(V8_COMPRESS_POINTERS_IN_SHARED_CAGE) && // defined(V8_SHARED_RO_HEAP) +UNINITIALIZED_TEST(SnapshotCreatorScriptContextCellsMismatch) { + v8::StartupData blob; + { + SnapshotCreatorParams testing_params; + v8::SnapshotCreator creator(testing_params.create_params); + v8::Isolate* isolate = creator.GetIsolate(); + { + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + + CompileRun( + "let x = 1; x = 2;\n" + "function lazy() { x = 3; return x; }\n"); + + creator.SetDefaultContext(context); + } + blob = + creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); + } + + v8_flags.script_context_cells = false; + v8_flags.function_context_cells = false; + v8_flags.allow_natives_syntax = true; + + { + SnapshotCreatorParams testing_params(nullptr, &blob); + v8::Isolate* isolate = v8::Isolate::New(testing_params.create_params); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + + ExpectInt32( + "%PrepareFunctionForOptimization(lazy);\n" + "lazy();\n" + "%OptimizeFunctionOnNextCall(lazy);\n" + "lazy();\n", + 3); + + ExpectInt32( + "function f() { x = 4; return x; }\n" + "%PrepareFunctionForOptimization(f);\n" + "f(); f();\n" + "%OptimizeMaglevOnNextCall(f);\n" + "f();\n", + 4); + + ExpectInt32( + "function get_x() { return x; }\n" + "%PrepareFunctionForOptimization(get_x);\n" + "get_x(); get_x();\n" + "%OptimizeMaglevOnNextCall(get_x);\n" + "get_x();\n", + 4); + + ExpectInt32( + "function g() { x = 5; return x; }\n" + "%PrepareFunctionForOptimization(g);\n" + "g(); g();\n" + "%OptimizeFunctionOnNextCall(g);\n" + "g();\n", + 5); + } + isolate->Dispose(); + } + delete[] blob.data; +} + +UNINITIALIZED_TEST(SerializeWeakRootArrayConstantsLeak) { + DisableEmbeddedBlobRefcounting(); + v8::StartupData blob; + { + SnapshotCreatorParams testing_params; + v8::SnapshotCreator creator(testing_params.create_params); + v8::Isolate* isolate = creator.GetIsolate(); + { + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::DirectHandle<i::WeakArrayList> list = + i_isolate->factory()->NewWeakArrayList(2); + list->Set(0, i::MakeWeak(i::Cast<i::HeapObject>( + i_isolate->root(i::RootIndex::kHeapNumberMap)))); + i::DirectHandle<i::JSObject> strong_obj = + i_isolate->factory()->NewJSObjectWithNullProto(); + list->Set(1, *strong_obj); + + i::DirectHandle<i::Context> i_context = + v8::Utils::OpenDirectHandle(*context); + i_context->native_context()->set_retained_maps(*list); + + creator.SetDefaultContext(context); + } + blob = + creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); + } + + { + SnapshotCreatorParams testing_params(nullptr, &blob); + v8::Isolate* isolate = v8::Isolate::New(testing_params.create_params); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::DirectHandle<i::Context> i_context = + v8::Utils::OpenDirectHandle(*context); + i::Tagged<i::WeakArrayList> list = i::Cast<i::WeakArrayList>( + i_context->native_context()->retained_maps()); + + i::Tagged<i::MaybeObject> elem0 = list->Get(0); + CHECK(elem0.IsWeak()); + CHECK_EQ(elem0.GetHeapObjectAssumeWeak(), + i_isolate->root(i::RootIndex::kHeapNumberMap)); + + i::Tagged<i::MaybeObject> elem1 = list->Get(1); + CHECK(elem1.IsStrong()); + } + isolate->Dispose(); + } + delete[] blob.data; + FreeCurrentEmbeddedBlob(); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/test-shared-strings.cc b/deps/v8/test/cctest/test-shared-strings.cc index 7d75c35a92ee..5ff31766275c 100644 --- a/deps/v8/test/cctest/test-shared-strings.cc +++ b/deps/v8/test/cctest/test-shared-strings.cc @@ -6,6 +6,7 @@ #include "src/api/api-inl.h" #include "src/api/api.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/flags/flags.h" @@ -34,12 +35,6 @@ namespace v8 { namespace internal { namespace test_shared_strings { -struct V8_NODISCARD IsolateWrapper { - explicit IsolateWrapper(v8::Isolate* isolate) : isolate(isolate) {} - ~IsolateWrapper() { isolate->Dispose(); } - v8::Isolate* const isolate; -}; - // Some tests in this file allocate two Isolates in the same thread to directly // test shared string behavior. Because both are considered running, when // disposing these Isolates, one must be parked to not cause a deadlock in the @@ -98,276 +93,6 @@ class MultiClientIsolateTest { int main_isolate_wakeup_counter_ = 0; }; -UNINITIALIZED_TEST(InPlaceInternalizableStringsAreShared) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "foo"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<const base::uc16> two_byte(raw_two_byte, 3); - - // Old generation 1- and 2-byte seq strings are in-place internalizable. - DirectHandle<String> old_one_byte_seq = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - CHECK(HeapLayout::InAnySharedSpace(*old_one_byte_seq)); - DirectHandle<String> old_two_byte_seq = - factory1->NewStringFromTwoByte(two_byte, AllocationType::kOld) - .ToHandleChecked(); - CHECK(HeapLayout::InAnySharedSpace(*old_two_byte_seq)); - - // Young generation are not internalizable and not shared when sharing the - // string table. - DirectHandle<String> young_one_byte_seq = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kYoung); - CHECK(!HeapLayout::InAnySharedSpace(*young_one_byte_seq)); - DirectHandle<String> young_two_byte_seq = - factory1->NewStringFromTwoByte(two_byte, AllocationType::kYoung) - .ToHandleChecked(); - CHECK(!HeapLayout::InAnySharedSpace(*young_two_byte_seq)); - - // Internalized strings are shared. - HashSeed seed = HashSeed(i_isolate1); - DirectHandle<String> one_byte_intern = factory1->NewOneByteInternalizedString( - base::OneByteVector(raw_one_byte), - StringHasher::HashSequentialString<char>(raw_one_byte, 3, seed)); - CHECK(HeapLayout::InAnySharedSpace(*one_byte_intern)); - DirectHandle<String> two_byte_intern = factory1->NewTwoByteInternalizedString( - two_byte, - StringHasher::HashSequentialString<uint16_t>(raw_two_byte, 3, seed)); - CHECK(HeapLayout::InAnySharedSpace(*two_byte_intern)); -} - -UNINITIALIZED_TEST(InPlaceInternalization) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - MultiClientIsolateTest test; - ManualGCScope manual_gc_scope(test.i_main_isolate()); - - IsolateParkOnDisposeWrapper isolate_wrapper(test.NewClientIsolate(), - test.main_isolate()); - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - HandleScope scope1(i_isolate1); - - const char raw_one_byte[] = "foo"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<const base::uc16> two_byte(raw_two_byte, 3); - - // Allocate two in-place internalizable strings in isolate1 then intern - // them. - DirectHandle<String> old_one_byte_seq1 = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - DirectHandle<String> old_two_byte_seq1 = - factory1->NewStringFromTwoByte(two_byte, AllocationType::kOld) - .ToHandleChecked(); - DirectHandle<String> one_byte_intern1 = - factory1->InternalizeString(old_one_byte_seq1); - DirectHandle<String> two_byte_intern1 = - factory1->InternalizeString(old_two_byte_seq1); - CHECK(HeapLayout::InAnySharedSpace(*old_one_byte_seq1)); - CHECK(HeapLayout::InAnySharedSpace(*old_two_byte_seq1)); - CHECK(HeapLayout::InAnySharedSpace(*one_byte_intern1)); - CHECK(HeapLayout::InAnySharedSpace(*two_byte_intern1)); - CHECK(old_one_byte_seq1.equals(one_byte_intern1)); - CHECK(old_two_byte_seq1.equals(two_byte_intern1)); - CHECK_EQ(*old_one_byte_seq1, *one_byte_intern1); - CHECK_EQ(*old_two_byte_seq1, *two_byte_intern1); - - // Allocate two in-place internalizable strings with the same contents in - // isolate2 then intern them. They should be the same as the interned strings - // from isolate1. - v8::Isolate::Scope isolate2_scope(isolate_wrapper.isolate); - Isolate* i_isolate2 = reinterpret_cast<Isolate*>(isolate_wrapper.isolate); - Factory* factory2 = i_isolate2->factory(); - HandleScope scope2(i_isolate2); - DirectHandle<String> old_one_byte_seq2 = - factory2->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - DirectHandle<String> old_two_byte_seq2 = - factory2->NewStringFromTwoByte(two_byte, AllocationType::kOld) - .ToHandleChecked(); - DirectHandle<String> one_byte_intern2 = - factory2->InternalizeString(old_one_byte_seq2); - DirectHandle<String> two_byte_intern2 = - factory2->InternalizeString(old_two_byte_seq2); - CHECK(HeapLayout::InAnySharedSpace(*old_one_byte_seq2)); - CHECK(HeapLayout::InAnySharedSpace(*old_two_byte_seq2)); - CHECK(HeapLayout::InAnySharedSpace(*one_byte_intern2)); - CHECK(HeapLayout::InAnySharedSpace(*two_byte_intern2)); - CHECK(!old_one_byte_seq2.equals(one_byte_intern2)); - CHECK(!old_two_byte_seq2.equals(two_byte_intern2)); - CHECK_NE(*old_one_byte_seq2, *one_byte_intern2); - CHECK_NE(*old_two_byte_seq2, *two_byte_intern2); - CHECK_EQ(*one_byte_intern1, *one_byte_intern2); - CHECK_EQ(*two_byte_intern1, *two_byte_intern2); -} - -UNINITIALIZED_TEST(YoungInternalization) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - MultiClientIsolateTest test; - IsolateParkOnDisposeWrapper isolate_wrapper(test.NewClientIsolate(), - test.main_isolate()); - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - Isolate* i_isolate2 = reinterpret_cast<Isolate*>(isolate_wrapper.isolate); - Factory* factory2 = i_isolate2->factory(); - - HandleScope scope1(i_isolate1); - HandleScope scope2(i_isolate2); - - const char raw_one_byte[] = "foo"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<const base::uc16> two_byte(raw_two_byte, 3); - - // Allocate two young strings in isolate1 then intern them. Young strings - // aren't in-place internalizable and are copied when internalized. - Handle<String> young_one_byte_seq1; - Handle<String> young_two_byte_seq1; - Handle<String> one_byte_intern1; - Handle<String> two_byte_intern1; - i_isolate2->main_thread_local_isolate()->ExecuteMainThreadWhileParked([&]() { - young_one_byte_seq1 = factory1->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - young_two_byte_seq1 = - factory1->NewStringFromTwoByte(two_byte, AllocationType::kYoung) - .ToHandleChecked(); - one_byte_intern1 = factory1->InternalizeString(young_one_byte_seq1); - two_byte_intern1 = factory1->InternalizeString(young_two_byte_seq1); - CHECK(!HeapLayout::InAnySharedSpace(*young_one_byte_seq1)); - CHECK(!HeapLayout::InAnySharedSpace(*young_two_byte_seq1)); - CHECK(HeapLayout::InAnySharedSpace(*one_byte_intern1)); - CHECK(HeapLayout::InAnySharedSpace(*two_byte_intern1)); - CHECK(!young_one_byte_seq1.equals(one_byte_intern1)); - CHECK(!young_two_byte_seq1.equals(two_byte_intern1)); - CHECK_NE(*young_one_byte_seq1, *one_byte_intern1); - CHECK_NE(*young_two_byte_seq1, *two_byte_intern1); - }); - - // Allocate two young strings with the same contents in isolate2 then intern - // them. They should be the same as the interned strings from isolate1. - Handle<String> young_one_byte_seq2; - Handle<String> young_two_byte_seq2; - Handle<String> one_byte_intern2; - Handle<String> two_byte_intern2; - { - v8::Isolate::Scope isolate_scope(isolate_wrapper.isolate); - young_one_byte_seq2 = factory2->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - young_two_byte_seq2 = - factory2->NewStringFromTwoByte(two_byte, AllocationType::kYoung) - .ToHandleChecked(); - one_byte_intern2 = factory2->InternalizeString(young_one_byte_seq2); - two_byte_intern2 = factory2->InternalizeString(young_two_byte_seq2); - CHECK(!young_one_byte_seq2.equals(one_byte_intern2)); - CHECK(!young_two_byte_seq2.equals(two_byte_intern2)); - CHECK_NE(*young_one_byte_seq2, *one_byte_intern2); - CHECK_NE(*young_two_byte_seq2, *two_byte_intern2); - CHECK_EQ(*one_byte_intern1, *one_byte_intern2); - CHECK_EQ(*two_byte_intern1, *two_byte_intern2); - } -} - -class ConcurrentStringThreadBase : public ParkingThread { - public: - ConcurrentStringThreadBase(const char* name, MultiClientIsolateTest* test, - IndirectHandle<FixedArray> shared_strings, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_start, - ParkingSemaphore* sema_execute_complete) - : ParkingThread(base::Thread::Options(name)), - test_(test), - shared_strings_(shared_strings), - sema_ready_(sema_ready), - sema_execute_start_(sema_execute_start), - sema_execute_complete_(sema_execute_complete) {} - - virtual void Setup() {} - virtual void RunForString(Handle<String> string, int counter) = 0; - virtual void Teardown() {} - void Run() override { - IsolateWrapper isolate_wrapper(test_->NewClientIsolate()); - i_isolate = reinterpret_cast<Isolate*>(isolate_wrapper.isolate); - - Setup(); - - sema_ready_->Signal(); - sema_execute_start_->ParkedWait(i_isolate->main_thread_local_isolate()); - - { - v8::Isolate::Scope isolate_scope(isolate_wrapper.isolate); - HandleScope scope(i_isolate); - const uint32_t shared_strings_len = shared_strings_->length().value(); - for (uint32_t i = 0; i < shared_strings_len; i++) { - Handle<String> input_string(Cast<String>(shared_strings_->get(i)), - i_isolate); - RunForString(input_string, i); - } - } - - sema_execute_complete_->Signal(); - - Teardown(); - - i_isolate = nullptr; - } - - protected: - Isolate* i_isolate; - MultiClientIsolateTest* test_; - IndirectHandle<FixedArray> shared_strings_; - ParkingSemaphore* sema_ready_; - ParkingSemaphore* sema_execute_start_; - ParkingSemaphore* sema_execute_complete_; -}; - -enum TestHitOrMiss { kTestMiss, kTestHit }; - -class ConcurrentInternalizationThread final - : public ConcurrentStringThreadBase { - public: - ConcurrentInternalizationThread(MultiClientIsolateTest* test, - IndirectHandle<FixedArray> shared_strings, - TestHitOrMiss hit_or_miss, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_start, - ParkingSemaphore* sema_execute_complete) - : ConcurrentStringThreadBase("ConcurrentInternalizationThread", test, - shared_strings, sema_ready, - sema_execute_start, sema_execute_complete), - hit_or_miss_(hit_or_miss) {} - - void Setup() override { factory = i_isolate->factory(); } - - void RunForString(Handle<String> input_string, int counter) override { - CHECK(input_string->IsShared()); - DirectHandle<String> interned = factory->InternalizeString(input_string); - CHECK(interned->IsShared()); - CHECK(IsInternalizedString(*interned)); - if (hit_or_miss_ == kTestMiss) { - CHECK_EQ(*input_string, *interned); - } else { - CHECK(input_string->HasForwardingIndex(kAcquireLoad)); - CHECK(String::Equals(i_isolate, input_string, interned)); - } - } - - private: - TestHitOrMiss hit_or_miss_; - Factory* factory; -}; - namespace { std::pair<DirectHandle<String>, MaybeDirectHandle<String>> @@ -395,178 +120,6 @@ CreateSharedOneByteString(Isolate* isolate, Factory* factory, int length, return std::make_pair(string, internalized); } -IndirectHandle<FixedArray> CreateSharedOneByteStrings( - Isolate* isolate, Factory* factory, int count, int lo_count, - int min_length = 2, bool internalize = false) { - IndirectHandle<FixedArray> shared_strings = - factory->NewFixedArray(count + lo_count, AllocationType::kSharedOld); - // Buffer to keep internalized strings alive in the current scope. - DirectHandle<FixedArray> internalized_handles; - if (internalize) { - internalized_handles = - factory->NewFixedArray(count + lo_count, AllocationType::kOld); - } - { - // Create strings in their own scope to be able to delete and GC them. - HandleScope scope(isolate); - for (int i = 0; i < count; i++) { - int length = i + min_length + 1; - auto strings = - CreateSharedOneByteString(isolate, factory, length, internalize); - shared_strings->set(i, *strings.first); - if (internalize) { - internalized_handles->set(i, *strings.second.ToHandleChecked()); - } - } - int min_lo_length = - isolate->heap()->MaxRegularHeapObjectSize(AllocationType::kOld) + 1; - for (int i = 0; i < lo_count; i++) { - int length = i + min_lo_length + 1; - auto strings = - CreateSharedOneByteString(isolate, factory, length, internalize); - shared_strings->set(count + i, *strings.first); - if (internalize) { - internalized_handles->set(count + i, *strings.second.ToHandleChecked()); - } - } - } - return shared_strings; -} - -void TestConcurrentInternalization(TestHitOrMiss hit_or_miss) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - constexpr int kThreads = 4; - constexpr int kStrings = 4096; - constexpr int kLOStrings = 16; - - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> shared_strings = - CreateSharedOneByteStrings(i_isolate, factory, kStrings - kLOStrings, - kLOStrings, 2, hit_or_miss == kTestHit); - - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<ConcurrentInternalizationThread>> threads; - for (int i = 0; i < kThreads; i++) { - auto thread = std::make_unique<ConcurrentInternalizationThread>( - &test, shared_strings, hit_or_miss, &sema_ready, &sema_execute_start, - &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - - LocalIsolate* local_isolate = i_isolate->main_thread_local_isolate(); - for (int i = 0; i < kThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - for (int i = 0; i < kThreads; i++) { - sema_execute_start.Signal(); - } - for (int i = 0; i < kThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); - } - - ParkingThread::ParkedJoinAll(local_isolate, threads); -} -} // namespace - -UNINITIALIZED_TEST(ConcurrentInternalizationMiss) { - TestConcurrentInternalization(kTestMiss); -} - -UNINITIALIZED_TEST(ConcurrentInternalizationHit) { - TestConcurrentInternalization(kTestHit); -} - -class ConcurrentStringTableLookupThread final - : public ConcurrentStringThreadBase { - public: - ConcurrentStringTableLookupThread(MultiClientIsolateTest* test, - IndirectHandle<FixedArray> shared_strings, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_start, - ParkingSemaphore* sema_execute_complete) - : ConcurrentStringThreadBase("ConcurrentStringTableLookup", test, - shared_strings, sema_ready, - sema_execute_start, sema_execute_complete) {} - - void RunForString(Handle<String> input_string, int counter) override { - CHECK(input_string->IsShared()); - Tagged<Object> result = - Tagged<Object>(StringTable::TryStringToIndexOrLookupExisting( - i_isolate, input_string->ptr())); - if (IsString(result)) { - Tagged<String> internalized = Cast<String>(result); - CHECK(IsInternalizedString(internalized)); - CHECK_IMPLIES(IsInternalizedString(*input_string), - *input_string == internalized); - } else { - CHECK_EQ(Cast<Smi>(result).value(), ResultSentinel::kNotFound); - } - } -}; - -UNINITIALIZED_TEST(ConcurrentStringTableLookup) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - constexpr int kTotalThreads = 4; - constexpr int kInternalizationThreads = 1; - constexpr int kStrings = 4096; - constexpr int kLOStrings = 16; - - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> shared_strings = CreateSharedOneByteStrings( - i_isolate, factory, kStrings - kLOStrings, kLOStrings, 2, false); - - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<ConcurrentStringThreadBase>> threads; - for (int i = 0; i < kInternalizationThreads; i++) { - auto thread = std::make_unique<ConcurrentInternalizationThread>( - &test, shared_strings, kTestMiss, &sema_ready, &sema_execute_start, - &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - for (int i = 0; i < kTotalThreads - kInternalizationThreads; i++) { - auto thread = std::make_unique<ConcurrentStringTableLookupThread>( - &test, shared_strings, &sema_ready, &sema_execute_start, - &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - - LocalIsolate* local_isolate = i_isolate->main_thread_local_isolate(); - for (int i = 0; i < kTotalThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - for (int i = 0; i < kTotalThreads; i++) { - sema_execute_start.Signal(); - } - for (int i = 0; i < kTotalThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); - } - - ParkingThread::ParkedJoinAll(local_isolate, threads); -} - -namespace { - void CheckSharedStringIsEqualCopy(DirectHandle<String> shared, DirectHandle<String> original) { CHECK(shared->IsShared()); @@ -606,1477 +159,219 @@ class TwoByteResource : public v8::String::ExternalStringResource { public: TwoByteResource(const uint16_t* data, size_t length) : data_(data), length_(length) {} - const uint16_t* data() const override { return data_; } - size_t length() const override { return length_; } - void Dispose() override { - i::DeleteArray(data_); - data_ = nullptr; - } - bool IsDisposed() const { return data_ == nullptr; } - - private: - const uint16_t* data_; - size_t length_; -}; - -class ExternalResourceFactory { - public: - ~ExternalResourceFactory() { - for (auto* res : one_byte_resources_) { - CHECK(res->IsDisposed()); - delete res; - } - for (auto* res : two_byte_resources_) { - CHECK(res->IsDisposed()); - delete res; - } - } - OneByteResource* CreateOneByte(const char* data, size_t length, - bool copy = true) { - OneByteResource* res = - new OneByteResource(copy ? i::StrDup(data) : data, length); - Register(res); - return res; - } - OneByteResource* CreateOneByte(const char* data, bool copy = true) { - return CreateOneByte(data, strlen(data), copy); - } - TwoByteResource* CreateTwoByte(const uint16_t* data, size_t length) { - TwoByteResource* res = new TwoByteResource(data, length); - Register(res); - return res; - } - TwoByteResource* CreateTwoByte(base::Vector<base::uc16> vector, - bool copy = true) { - if (copy) { - vector = base::VectorOf(base::OwnedCopyOf(vector).ReleaseData().release(), - vector.size()); - } - return CreateTwoByte(vector.data(), vector.size()); - } - void Register(OneByteResource* res) { one_byte_resources_.push_back(res); } - void Register(TwoByteResource* res) { two_byte_resources_.push_back(res); } - - private: - std::vector<OneByteResource*> one_byte_resources_; - std::vector<TwoByteResource*> two_byte_resources_; -}; - -} // namespace - -UNINITIALIZED_TEST(StringShare) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ManualGCScope manual_gc_scope; - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - // A longer string so that concatenated to itself, the result is > - // ConsString::kMinLength. - const char raw_one_byte[] = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<base::uc16> two_byte(raw_two_byte, 3); - - { - // Old-generation sequential strings are shared in-place. - Handle<String> one_byte_seq = - factory->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte_seq = - factory->NewStringFromTwoByte(two_byte, AllocationType::kOld) - .ToHandleChecked(); - CHECK(!one_byte_seq->IsShared()); - CHECK(!two_byte_seq->IsShared()); - DirectHandle<String> shared_one_byte = - ShareAndVerify(i_isolate, one_byte_seq); - DirectHandle<String> shared_two_byte = - ShareAndVerify(i_isolate, two_byte_seq); - CHECK_EQ(*one_byte_seq, *shared_one_byte); - CHECK_EQ(*two_byte_seq, *shared_two_byte); - } - - { - // Internalized strings are always shared. - Handle<String> one_byte_seq = - factory->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte_seq = - factory->NewStringFromTwoByte(two_byte, AllocationType::kOld) - .ToHandleChecked(); - CHECK(!one_byte_seq->IsShared()); - CHECK(!two_byte_seq->IsShared()); - Handle<String> one_byte_intern = factory->InternalizeString(one_byte_seq); - Handle<String> two_byte_intern = factory->InternalizeString(two_byte_seq); - CHECK(one_byte_intern->IsShared()); - CHECK(two_byte_intern->IsShared()); - DirectHandle<String> shared_one_byte_intern = - ShareAndVerify(i_isolate, one_byte_intern); - DirectHandle<String> shared_two_byte_intern = - ShareAndVerify(i_isolate, two_byte_intern); - CHECK_EQ(*one_byte_intern, *shared_one_byte_intern); - CHECK_EQ(*two_byte_intern, *shared_two_byte_intern); - } - - { - // Old-generation external strings are shared in-place. - Handle<String> one_byte_ext = - factory->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte_ext = - factory->NewStringFromTwoByte(two_byte, AllocationType::kOld) - .ToHandleChecked(); - OneByteResource* one_byte_res = - resource_factory.CreateOneByte(raw_one_byte); - TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte); - CHECK(one_byte_ext->MakeExternal(i_isolate, one_byte_res)); - CHECK(two_byte_ext->MakeExternal(i_isolate, two_byte_res)); - if (v8_flags.always_use_string_forwarding_table) { - i_isolate->heap()->CollectGarbageShared( - i_isolate->main_thread_local_heap(), - GarbageCollectionReason::kTesting); - } - CHECK(IsExternalString(*one_byte_ext)); - CHECK(IsExternalString(*two_byte_ext)); - CHECK(!one_byte_ext->IsShared()); - CHECK(!two_byte_ext->IsShared()); - DirectHandle<String> shared_one_byte = - ShareAndVerify(i_isolate, one_byte_ext); - DirectHandle<String> shared_two_byte = - ShareAndVerify(i_isolate, two_byte_ext); - CHECK_EQ(*one_byte_ext, *shared_one_byte); - CHECK_EQ(*two_byte_ext, *shared_two_byte); - } - - // All other strings are flattened then copied if the flatten didn't already - // create a new copy. - - if (!v8_flags.single_generation) { - // Young strings - Handle<String> young_one_byte_seq = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - Handle<String> young_two_byte_seq = - factory->NewStringFromTwoByte(two_byte, AllocationType::kYoung) - .ToHandleChecked(); - CHECK(HeapLayout::InYoungGeneration(*young_one_byte_seq)); - CHECK(HeapLayout::InYoungGeneration(*young_two_byte_seq)); - CHECK(!young_one_byte_seq->IsShared()); - CHECK(!young_two_byte_seq->IsShared()); - DirectHandle<String> shared_one_byte = - ShareAndVerify(i_isolate, young_one_byte_seq); - DirectHandle<String> shared_two_byte = - ShareAndVerify(i_isolate, young_two_byte_seq); - CheckSharedStringIsEqualCopy(shared_one_byte, young_one_byte_seq); - CheckSharedStringIsEqualCopy(shared_two_byte, young_two_byte_seq); - } - - if (!v8_flags.always_use_string_forwarding_table) { - // Thin strings - Handle<String> one_byte_seq1 = - factory->NewStringFromAsciiChecked(raw_one_byte); - Handle<String> one_byte_seq2 = - factory->NewStringFromAsciiChecked(raw_one_byte); - CHECK(!one_byte_seq1->IsShared()); - CHECK(!one_byte_seq2->IsShared()); - factory->InternalizeString(one_byte_seq1); - factory->InternalizeString(one_byte_seq2); - CHECK(StringShape(*one_byte_seq2).IsThin()); - DirectHandle<String> shared = ShareAndVerify(i_isolate, one_byte_seq2); - CheckSharedStringIsEqualCopy(shared, one_byte_seq2); - } - - { - // Cons strings - Handle<String> one_byte_seq1 = - factory->NewStringFromAsciiChecked(raw_one_byte); - Handle<String> one_byte_seq2 = - factory->NewStringFromAsciiChecked(raw_one_byte); - CHECK(!one_byte_seq1->IsShared()); - CHECK(!one_byte_seq2->IsShared()); - Handle<String> cons = - factory->NewConsString(one_byte_seq1, one_byte_seq2).ToHandleChecked(); - CHECK(!cons->IsShared()); - CHECK(IsConsString(*cons)); - DirectHandle<String> shared = ShareAndVerify(i_isolate, cons); - CheckSharedStringIsEqualCopy(shared, cons); - } - - { - // Sliced strings - Handle<String> one_byte_seq = - factory->NewStringFromAsciiChecked(raw_one_byte); - CHECK(!one_byte_seq->IsShared()); - Handle<String> sliced = - factory->NewSubString(one_byte_seq, 1, one_byte_seq->length()); - CHECK(!sliced->IsShared()); - CHECK(IsSlicedString(*sliced)); - DirectHandle<String> shared = ShareAndVerify(i_isolate, sliced); - CheckSharedStringIsEqualCopy(shared, sliced); - } -} - -UNINITIALIZED_TEST(PromotionMarkCompact) { - if (v8_flags.single_generation) return; - - v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - - MultiClientIsolateTest test; - v8::Isolate* isolate = test.main_isolate(); - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - // Heap* shared_heap = test.i_shared_isolate()->heap(); - - const char raw_one_byte[] = "foo"; - - { - Global<v8::String> one_byte_seq_global; - ObjectSlot slot; - { - HandleScope scope(i_isolate); - - IndirectHandle<String> one_byte_seq = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - - CHECK(String::IsInPlaceInternalizable(*one_byte_seq)); - CHECK(heap->InSpace(*one_byte_seq, NEW_SPACE)); - - // 1st GC moves `one_byte_seq` to old space and 2nd GC evacuates it within - // old space. - heap::InvokeMajorGC(heap); - heap::ForceEvacuationCandidate( - i::NormalPage::FromHeapObject(*one_byte_seq)); - - one_byte_seq_global.Reset(isolate, v8::Utils::ToLocal(one_byte_seq)); - } - { - // We need to invoke GC without stack, otherwise no compaction is - // performed. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - { - v8::HandleScope nested_scope(isolate); - IndirectHandle<String> one_byte_seq = - v8::Utils::OpenHandle(*one_byte_seq_global.Get(isolate)); - // In-place-internalizable strings are promoted into the shared heap when - // sharing. - CHECK(heap->SharedHeapContains(*one_byte_seq)); - } - } -} - -UNINITIALIZED_TEST(PromotionScavenge) { - if (v8_flags.minor_ms) return; - if (v8_flags.single_generation) return; - if (v8_flags.scavenger_chaos_mode) return; - - v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - v8_flags.shared_string_table = true; - v8_flags.scavenger_precise_object_pinning = false; - v8_flags.precise_object_pinning = false; - i::FlagList::EnforceFlagImplications(); - - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - // Heap* shared_heap = test.i_shared_isolate()->heap(); - - const char raw_one_byte[] = "foo"; - - { - HandleScope scope(i_isolate); - - // heap::SealCurrentObjects(heap); - // heap::SealCurrentObjects(shared_heap); - - IndirectHandle<String> one_byte_seq = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - - CHECK(String::IsInPlaceInternalizable(*one_byte_seq)); - CHECK(heap->InSpace(*one_byte_seq, NEW_SPACE)); - - { - // CSS prevents moving the string to shared space. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - for (int i = 0; i < 2; i++) { - heap::InvokeMinorGC(heap); - } - } - - // In-place-internalizable strings are promoted into the shared heap when - // sharing. - CHECK(heap->SharedHeapContains(*one_byte_seq)); - } -} - -UNINITIALIZED_TEST(PromotionScavengeOldToShared) { - if (v8_flags.minor_ms) { - // Promoting from new space directly to shared heap is not implemented in - // MinorMS. - return; - } - if (v8_flags.single_generation) return; - if (v8_flags.stress_concurrent_allocation) return; - if (v8_flags.scavenger_chaos_mode) return; - - v8_flags.shared_string_table = true; - v8_flags.scavenger_precise_object_pinning = false; - v8_flags.precise_object_pinning = false; - i::FlagList::EnforceFlagImplications(); - - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - ManualGCScope manual_gc(i_isolate); - - const char raw_one_byte[] = "foo"; - - { - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> old_object = - factory->NewFixedArray(1, AllocationType::kOld); - MemoryChunk* old_object_chunk = MemoryChunk::FromHeapObject(*old_object); - CHECK(!old_object_chunk->InYoungGeneration()); - - IndirectHandle<String> one_byte_seq = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - CHECK(String::IsInPlaceInternalizable(*one_byte_seq)); - CHECK(MemoryChunk::FromHeapObject(*one_byte_seq)->InYoungGeneration()); - - old_object->set(0, *one_byte_seq); - ObjectSlot slot = old_object->RawFieldOfFirstElement(); - CHECK(RememberedSet<OLD_TO_NEW>::Contains( - SbxCast<MutablePage>(old_object_chunk->Metadata()), slot.address())); - - { - // CSS prevents moving the string to shared space. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - for (int i = 0; i < 2; i++) { - heap::InvokeMinorGC(heap); - } - } - - // In-place-internalizable strings are promoted into the shared heap when - // sharing. - CHECK(heap->SharedHeapContains(*one_byte_seq)); - - // Since the GC promoted that string into shared heap, it also needs to - // create an OLD_TO_SHARED slot. - CHECK(RememberedSet<OLD_TO_SHARED>::Contains( - SbxCast<MutablePage>(old_object_chunk->Metadata()), slot.address())); - } -} - -UNINITIALIZED_TEST(PromotionMarkCompactNewToShared) { - if (v8_flags.single_generation) return; - if (v8_flags.stress_concurrent_allocation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - v8_flags.page_promotion = false; - - MultiClientIsolateTest test; - v8::Isolate* isolate = test.main_isolate(); - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - - const char raw_one_byte[] = "foo"; - - { - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> old_object = - factory->NewFixedArray(1, AllocationType::kOld); - MemoryChunk* old_object_chunk = MemoryChunk::FromHeapObject(*old_object); - CHECK(!old_object_chunk->InYoungGeneration()); - - Global<v8::String> one_byte_seq_global; - { - HandleScope nested_scope(i_isolate); - IndirectHandle<String> one_byte_seq = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - CHECK(String::IsInPlaceInternalizable(*one_byte_seq)); - CHECK(MemoryChunk::FromHeapObject(*one_byte_seq)->InYoungGeneration()); - - old_object->set(0, *one_byte_seq); - one_byte_seq_global.Reset(isolate, v8::Utils::ToLocal(one_byte_seq)); - } - ObjectSlot slot = old_object->RawFieldOfFirstElement(); - CHECK(RememberedSet<OLD_TO_NEW>::Contains( - SbxCast<MutablePage>(old_object_chunk->Metadata()), slot.address())); - - { - // We need to invoke GC without stack, otherwise no compaction is - // performed. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - { - v8::HandleScope nested_scope(isolate); - IndirectHandle<String> one_byte_seq = - v8::Utils::OpenHandle(*one_byte_seq_global.Get(isolate)); - // In-place-internalizable strings are promoted into the shared heap when - // sharing. - CHECK(heap->SharedHeapContains(*one_byte_seq)); - } - // Since the GC promoted that string into shared heap, it also needs to - // create an OLD_TO_SHARED slot. - CHECK(RememberedSet<OLD_TO_SHARED>::Contains( - SbxCast<MutablePage>(old_object_chunk->Metadata()), slot.address())); - } -} - -UNINITIALIZED_TEST(PromotionMarkCompactOldToShared) { - if (v8_flags.stress_concurrent_allocation) return; - if (!v8_flags.page_promotion) return; - if (v8_flags.single_generation) { - // String allocated in old space may be "pretenured" to the shared heap. - return; - } - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - - MultiClientIsolateTest test; - v8::Isolate* isolate = test.main_isolate(); - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - - const char raw_one_byte[] = "foo"; - - { - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> old_object = - factory->NewFixedArray(1, AllocationType::kOld); - MemoryChunk* old_object_chunk = MemoryChunk::FromHeapObject(*old_object); - CHECK(!old_object_chunk->InYoungGeneration()); - - Global<v8::String> one_byte_seq_global; - ObjectSlot slot; - { - HandleScope nested_scope(i_isolate); - IndirectHandle<String> one_byte_seq = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kYoung); - CHECK(String::IsInPlaceInternalizable(*one_byte_seq)); - CHECK(MemoryChunk::FromHeapObject(*one_byte_seq)->InYoungGeneration()); - - DirectHandleVector<FixedArray> handles(i_isolate); - // Fill the page and do a full GC. Page promotion should kick in and - // promote the page as is to old space. - heap::FillCurrentPage(heap->new_space(), &handles); - heap::InvokeMajorGC(heap); - // Make sure 'one_byte_seq' is in old space. - CHECK(!MemoryChunk::FromHeapObject(*one_byte_seq)->InYoungGeneration()); - CHECK(heap->Contains(*one_byte_seq)); - - old_object->set(0, *one_byte_seq); - slot = old_object->RawFieldOfFirstElement(); - CHECK(!RememberedSet<OLD_TO_NEW>::Contains( - SbxCast<MutablePage>(old_object_chunk->Metadata()), slot.address())); - - heap::ForceEvacuationCandidate(NormalPage::FromHeapObject(*one_byte_seq)); - one_byte_seq_global.Reset(isolate, v8::Utils::ToLocal(one_byte_seq)); - } - { - // We need to invoke GC without stack, otherwise no compaction is - // performed. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); - } - - { - v8::HandleScope nested_scope(isolate); - IndirectHandle<String> one_byte_seq = - v8::Utils::OpenHandle(*one_byte_seq_global.Get(isolate)); - - // In-place-internalizable strings are promoted into the shared heap when - // sharing. - CHECK(heap->SharedHeapContains(*one_byte_seq)); - } - // Since the GC promoted that string into shared heap, it also needs to - // create an OLD_TO_SHARED slot. - CHECK(RememberedSet<OLD_TO_SHARED>::Contains( - SbxCast<MutablePage>(old_object_chunk->Metadata()), slot.address())); - } -} - -UNINITIALIZED_TEST(PagePromotionRecordingOldToShared) { - if (v8_flags.single_generation) return; - if (v8_flags.stress_concurrent_allocation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope - manual_evacuation_candidate_selection_scope(manual_gc_scope); - - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); - - const char raw_one_byte[] = "foo"; - - { - HandleScope scope(i_isolate); - - DirectHandle<FixedArray> young_object = - factory->NewFixedArray(1, AllocationType::kYoung); - CHECK(HeapLayout::InYoungGeneration(*young_object)); - Address young_object_address = young_object->address(); - - DirectHandleVector<FixedArray> handles(i_isolate); - // Make the whole page transition from new->old, getting the buffers - // processed in the sweeper (relying on marking information) instead of - // processing during newspace evacuation. - heap::FillCurrentPage(heap->new_space(), &handles); - - DirectHandle<String> shared_string = factory->NewStringFromAsciiChecked( - raw_one_byte, AllocationType::kSharedOld); - CHECK(HeapLayout::InWritableSharedSpace(*shared_string)); - - young_object->set(0, *shared_string); - - heap::EmptyNewSpaceUsingGC(heap); - - // Object should get promoted using page promotion, so address should remain - // the same. - CHECK(!HeapLayout::InYoungGeneration(*shared_string)); - CHECK_EQ(young_object_address, young_object->address()); - - // Since the GC promoted that string into shared heap, it also needs to - // create an OLD_TO_SHARED slot. - ObjectSlot slot = young_object->RawFieldOfFirstElement(); - CHECK(RememberedSet<OLD_TO_SHARED>::Contains( - MutablePage::FromHeapObject(i_isolate, *young_object), slot.address())); - } -} - -namespace { - -void TriggerGCWithTransitions(Heap* heap) { - v8_flags.transition_strings_during_gc_with_stack = true; - heap::CollectSharedGarbage(heap); - v8_flags.transition_strings_during_gc_with_stack = false; -} - -} // namespace - -UNINITIALIZED_TEST(InternalizedSharedStringsTransitionDuringGC) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - constexpr int kStrings = 4096; - constexpr int kLOStrings = 16; - - MultiClientIsolateTest test; - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - // Run two times to test that everything is reset correctly during GC. - for (int run = 0; run < 2; run++) { - DirectHandle<FixedArray> shared_strings = CreateSharedOneByteStrings( - i_isolate, factory, kStrings - kLOStrings, kLOStrings, 2, run == 0); - - // Check strings are in the forwarding table after internalization. - const uint32_t shared_strings_len = shared_strings->length().value(); - for (uint32_t i = 0; i < shared_strings_len; i++) { - Handle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - DirectHandle<String> interned = factory->InternalizeString(input_string); - CHECK(input_string->IsShared()); - CHECK(!IsThinString(*input_string)); - CHECK(input_string->HasForwardingIndex(kAcquireLoad)); - CHECK(String::Equals(i_isolate, input_string, interned)); - } - - // Trigger garbage collection on the shared isolate. - TriggerGCWithTransitions(i_isolate->heap()); - - // Check that GC cleared the forwarding table. - CHECK_EQ(i_isolate->string_forwarding_table()->size(), 0); - - // Check all strings are transitioned to ThinStrings - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - CHECK(IsThinString(*input_string)); - } - } -} - -UNINITIALIZED_TEST(ShareExternalString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - - // External strings in old space can be shared in-place. - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - CHECK(!one_byte->IsShared()); - - OneByteResource* resource = resource_factory.CreateOneByte(raw_one_byte); - one_byte->MakeExternal(i_isolate1, resource); - if (v8_flags.always_use_string_forwarding_table) { - i_isolate1->heap()->CollectGarbageShared( - i_isolate1->main_thread_local_heap(), - GarbageCollectionReason::kTesting); - } - CHECK(IsExternalString(*one_byte)); - Handle<ExternalOneByteString> one_byte_external = - Cast<ExternalOneByteString>(one_byte); - DirectHandle<String> shared_one_byte = - ShareAndVerify(i_isolate1, one_byte_external); - CHECK_EQ(*shared_one_byte, *one_byte); -} - -namespace { - -void CheckExternalStringResource( - DirectHandle<String> string, - v8::String::ExternalStringResourceBase* resource) { - const bool is_one_byte = string->IsOneByteRepresentation(); - Local<v8::String> api_string = Utils::ToLocal(string); - v8::String::Encoding encoding; - CHECK_EQ(resource, api_string->GetExternalStringResourceBase(&encoding)); - if (is_one_byte) { - CHECK_EQ(encoding, v8::String::Encoding::ONE_BYTE_ENCODING); - CHECK_EQ(resource, api_string->GetExternalOneByteStringResource()); - } else { - CHECK(string->IsTwoByteRepresentation()); - CHECK_EQ(encoding, v8::String::Encoding::TWO_BYTE_ENCODING); - CHECK_EQ(resource, api_string->GetExternalStringResource()); - } -} - -} // namespace - -UNINITIALIZED_TEST(ExternalizeSharedString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<base::uc16> two_byte_vec(raw_two_byte, 3); - - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte = - factory1->NewStringFromTwoByte(two_byte_vec, AllocationType::kOld) - .ToHandleChecked(); - CHECK(one_byte->IsOneByteRepresentation()); - CHECK(two_byte->IsTwoByteRepresentation()); - CHECK(!one_byte->IsShared()); - CHECK(!two_byte->IsShared()); - - DirectHandle<String> shared_one_byte = ShareAndVerify(i_isolate1, one_byte); - DirectHandle<String> shared_two_byte = ShareAndVerify(i_isolate1, two_byte); - - OneByteResource* one_byte_res = resource_factory.CreateOneByte(raw_one_byte); - TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte_vec); - shared_one_byte->MakeExternal(i_isolate1, one_byte_res); - shared_two_byte->MakeExternal(i_isolate1, two_byte_res); - CHECK(!IsExternalString(*shared_one_byte)); - CHECK(!IsExternalString(*shared_two_byte)); - CHECK(shared_one_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(shared_two_byte->HasExternalForwardingIndex(kAcquireLoad)); - - // Check that API calls return the resource from the forwarding table. - CheckExternalStringResource(shared_one_byte, one_byte_res); - CheckExternalStringResource(shared_two_byte, two_byte_res); -} - -UNINITIALIZED_TEST(ExternalizedSharedStringsTransitionDuringGC) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - - constexpr int kStrings = 4096; - constexpr int kLOStrings = 16; - - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - // Run two times to test that everything is reset correctly during GC. - for (int run = 0; run < 2; run++) { - DirectHandle<FixedArray> shared_strings = CreateSharedOneByteStrings( - i_isolate, factory, kStrings - kLOStrings, kLOStrings, - sizeof(UncachedExternalString), run == 0); - - // Check strings are in the forwarding table after internalization. - const uint32_t shared_strings_len = shared_strings->length().value(); - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - const uint32_t length = input_string->length(); - char* buffer = new char[length + 1]; - String::WriteToFlat(*input_string, reinterpret_cast<uint8_t*>(buffer), 0, - length); - OneByteResource* resource = - resource_factory.CreateOneByte(buffer, length, false); - CHECK(input_string->MakeExternal(i_isolate, resource)); - CHECK(input_string->IsShared()); - CHECK(!IsExternalString(*input_string)); - CHECK(input_string->HasExternalForwardingIndex(kAcquireLoad)); - } - - // Trigger garbage collection on the shared isolate. - TriggerGCWithTransitions(i_isolate->heap()); - - // Check that GC cleared the forwarding table. - CHECK_EQ(i_isolate->string_forwarding_table()->size(), 0); - - // Check all strings are transitioned to ExternalStrings - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - CHECK(IsExternalString(*input_string)); - } - } -} - -UNINITIALIZED_TEST(ExternalizeInternalizedString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<base::uc16> two_byte_vec(raw_two_byte, 3); - - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte = - factory1->NewStringFromTwoByte(two_byte_vec, AllocationType::kOld) - .ToHandleChecked(); - // Internalize copies, s.t. internalizing the original strings creates a - // forwarding entry. - factory1->InternalizeString( - factory1->NewStringFromAsciiChecked(raw_one_byte)); - factory1->InternalizeString( - factory1->NewStringFromTwoByte(two_byte_vec).ToHandleChecked()); - DirectHandle<String> one_byte_intern = factory1->InternalizeString(one_byte); - DirectHandle<String> two_byte_intern = factory1->InternalizeString(two_byte); - if (v8_flags.always_use_string_forwarding_table) { - i_isolate1->heap()->CollectGarbageShared( - i_isolate1->main_thread_local_heap(), - GarbageCollectionReason::kTesting); - } - CHECK(IsThinString(*one_byte)); - CHECK(IsThinString(*two_byte)); - CHECK(one_byte_intern->IsOneByteRepresentation()); - CHECK(two_byte_intern->IsTwoByteRepresentation()); - CHECK(one_byte_intern->IsShared()); - CHECK(two_byte_intern->IsShared()); - - uint32_t one_byte_hash = one_byte_intern->hash(); - uint32_t two_byte_hash = two_byte_intern->hash(); - - OneByteResource* one_byte_res = resource_factory.CreateOneByte(raw_one_byte); - TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte_vec); - CHECK(one_byte_intern->MakeExternal(i_isolate1, one_byte_res)); - CHECK(two_byte_intern->MakeExternal(i_isolate1, two_byte_res)); - CHECK(!IsExternalString(*one_byte_intern)); - CHECK(!IsExternalString(*two_byte_intern)); - CHECK(one_byte_intern->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(two_byte_intern->HasExternalForwardingIndex(kAcquireLoad)); - // The hash of internalized strings is stored in the forwarding table. - CHECK_EQ(one_byte_intern->hash(), one_byte_hash); - CHECK_EQ(two_byte_intern->hash(), two_byte_hash); - - // Check that API calls return the resource from the forwarding table. - CheckExternalStringResource(one_byte_intern, one_byte_res); - CheckExternalStringResource(two_byte_intern, two_byte_res); -} - -UNINITIALIZED_TEST(InternalizeSharedExternalString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<base::uc16> two_byte_vec(raw_two_byte, 3); - - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte = - factory1->NewStringFromTwoByte(two_byte_vec, AllocationType::kOld) - .ToHandleChecked(); - - Handle<String> shared_one_byte = ShareAndVerify(i_isolate1, one_byte); - DirectHandle<String> shared_two_byte = ShareAndVerify(i_isolate1, two_byte); - - OneByteResource* one_byte_res = resource_factory.CreateOneByte(raw_one_byte); - TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte_vec); - CHECK(shared_one_byte->MakeExternal(i_isolate1, one_byte_res)); - CHECK(shared_two_byte->MakeExternal(i_isolate1, two_byte_res)); - CHECK(shared_one_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(shared_two_byte->HasExternalForwardingIndex(kAcquireLoad)); - - // Trigger GC to externalize the shared string. - TriggerGCWithTransitions(i_isolate1->heap()); - - CHECK(shared_one_byte->IsShared()); - CHECK(IsExternalString(*shared_one_byte)); - CHECK(shared_two_byte->IsShared()); - CHECK(IsExternalString(*shared_two_byte)); - - // Shared cached external strings are in-place internalizable. - DirectHandle<String> one_byte_intern = - factory1->InternalizeString(shared_one_byte); - CHECK_EQ(*one_byte_intern, *shared_one_byte); - CHECK(IsExternalString(*shared_one_byte)); - CHECK(IsInternalizedString(*shared_one_byte)); - - // Depending on the architecture/build options the two byte string might be - // cached or uncached. - const bool is_uncached = - two_byte->Size() < static_cast<int>(sizeof(ExternalString)); - - if (is_uncached) { - // Shared uncached external strings are not internalizable. A new internal - // copy will be created. - DirectHandle<String> two_byte_intern = - factory1->InternalizeString(two_byte); - CHECK_NE(*two_byte_intern, *shared_two_byte); - CHECK(shared_two_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - CHECK(IsInternalizedString(*two_byte_intern)); - CHECK(!IsExternalString(*two_byte_intern)); - } else { - DirectHandle<String> two_byte_intern = - factory1->InternalizeString(two_byte); - CHECK_EQ(*two_byte_intern, *shared_two_byte); - CHECK(IsExternalString(*shared_two_byte)); - CHECK(IsInternalizedString(*shared_two_byte)); - } - - // Another GC should create an externalized internalized string of the cached - // (one byte) string and turn the uncached (two byte) string into a - // ThinString, disposing the external resource. - TriggerGCWithTransitions(i_isolate1->heap()); - - CHECK_EQ(shared_one_byte->map()->instance_type(), - InstanceType::EXTERNAL_INTERNALIZED_ONE_BYTE_STRING_TYPE); - if (is_uncached) { - CHECK(IsThinString(*shared_two_byte)); - CHECK(two_byte_res->IsDisposed()); - } else { - CHECK_EQ(shared_two_byte->map()->instance_type(), - InstanceType::EXTERNAL_INTERNALIZED_TWO_BYTE_STRING_TYPE); - } -} - -UNINITIALIZED_TEST(ExternalizeAndInternalizeMissSharedString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - uint32_t one_byte_hash = one_byte->EnsureHash(); - - Handle<String> shared_one_byte = ShareAndVerify(i_isolate1, one_byte); - - OneByteResource* one_byte_res = resource_factory.CreateOneByte(raw_one_byte); - - CHECK(shared_one_byte->MakeExternal(i_isolate1, one_byte_res)); - CHECK(shared_one_byte->HasExternalForwardingIndex(kAcquireLoad)); - - DirectHandle<String> one_byte_intern = - factory1->InternalizeString(shared_one_byte); - CHECK_EQ(*one_byte_intern, *shared_one_byte); - CHECK(IsInternalizedString(*shared_one_byte)); - // Check that we have both, a forwarding index and an accessible hash. - CHECK(shared_one_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(shared_one_byte->HasHashCode()); - CHECK_EQ(shared_one_byte->hash(), one_byte_hash); -} - -UNINITIALIZED_TEST(InternalizeHitAndExternalizeSharedString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<base::uc16> two_byte_vec(raw_two_byte, 3); - - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte = - factory1->NewStringFromTwoByte(two_byte_vec, AllocationType::kOld) - .ToHandleChecked(); - Handle<String> shared_one_byte = ShareAndVerify(i_isolate1, one_byte); - Handle<String> shared_two_byte = ShareAndVerify(i_isolate1, two_byte); - // Internalize copies, s.t. internalizing the original strings creates a - // forwarding entry. - factory1->InternalizeString( - factory1->NewStringFromAsciiChecked(raw_one_byte)); - factory1->InternalizeString( - factory1->NewStringFromTwoByte(two_byte_vec).ToHandleChecked()); - DirectHandle<String> one_byte_intern = - factory1->InternalizeString(shared_one_byte); - DirectHandle<String> two_byte_intern = - factory1->InternalizeString(shared_two_byte); - CHECK_NE(*one_byte_intern, *shared_one_byte); - CHECK_NE(*two_byte_intern, *shared_two_byte); - CHECK(String::IsHashFieldComputed(one_byte_intern->raw_hash_field())); - CHECK(String::IsHashFieldComputed(two_byte_intern->raw_hash_field())); - CHECK(shared_one_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - CHECK(shared_two_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - - OneByteResource* one_byte_res = resource_factory.CreateOneByte(raw_one_byte); - TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte_vec); - CHECK(shared_one_byte->MakeExternal(i_isolate1, one_byte_res)); - CHECK(shared_two_byte->MakeExternal(i_isolate1, two_byte_res)); - CHECK(shared_one_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(shared_two_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(shared_one_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - CHECK(shared_two_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - - // Check that API calls return the resource from the forwarding table. - CheckExternalStringResource(shared_one_byte, one_byte_res); - CheckExternalStringResource(shared_two_byte, two_byte_res); -} - -UNINITIALIZED_TEST(InternalizeMissAndExternalizeSharedString) { - if (v8_flags.single_generation) return; - - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - Isolate* i_isolate1 = test.i_main_isolate(); - Factory* factory1 = i_isolate1->factory(); - - HandleScope handle_scope(i_isolate1); - - const char raw_one_byte[] = "external string"; - base::uc16 raw_two_byte[] = {2001, 2002, 2003}; - base::Vector<base::uc16> two_byte_vec(raw_two_byte, 3); - - Handle<String> one_byte = - factory1->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); - Handle<String> two_byte = - factory1->NewStringFromTwoByte(two_byte_vec, AllocationType::kOld) - .ToHandleChecked(); - Handle<String> shared_one_byte = ShareAndVerify(i_isolate1, one_byte); - Handle<String> shared_two_byte = ShareAndVerify(i_isolate1, two_byte); - DirectHandle<String> one_byte_intern = - factory1->InternalizeString(shared_one_byte); - DirectHandle<String> two_byte_intern = - factory1->InternalizeString(shared_two_byte); - CHECK_EQ(*one_byte_intern, *shared_one_byte); - CHECK_EQ(*two_byte_intern, *shared_two_byte); - CHECK(!shared_one_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - CHECK(!shared_two_byte->HasInternalizedForwardingIndex(kAcquireLoad)); - - OneByteResource* one_byte_res = resource_factory.CreateOneByte(raw_one_byte); - TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte_vec); - CHECK(shared_one_byte->MakeExternal(i_isolate1, one_byte_res)); - CHECK(shared_two_byte->MakeExternal(i_isolate1, two_byte_res)); - CHECK(shared_one_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(shared_two_byte->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(one_byte_intern->HasExternalForwardingIndex(kAcquireLoad)); - CHECK(two_byte_intern->HasExternalForwardingIndex(kAcquireLoad)); - - // Check that API calls return the resource from the forwarding table. - CheckExternalStringResource(shared_one_byte, one_byte_res); - CheckExternalStringResource(shared_two_byte, two_byte_res); -} - -class ConcurrentExternalizationThread final - : public ConcurrentStringThreadBase { - public: - ConcurrentExternalizationThread(MultiClientIsolateTest* test, - IndirectHandle<FixedArray> shared_strings, - std::vector<OneByteResource*> resources, - bool share_resources, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_start, - ParkingSemaphore* sema_execute_complete) - : ConcurrentStringThreadBase("ConcurrentExternalizationThread", test, - shared_strings, sema_ready, - sema_execute_start, sema_execute_complete), - resources_(resources), - share_resources_(share_resources) {} - - void RunForString(Handle<String> input_string, int counter) override { - CHECK(input_string->IsShared()); - OneByteResource* resource = Resource(counter); - if (!input_string->MakeExternal(i_isolate, resource)) { - if (!share_resources_) { - resource->Unaccount(reinterpret_cast<v8::Isolate*>(i_isolate)); - resource->Dispose(); - } - } - CHECK(input_string->HasForwardingIndex(kAcquireLoad)); - } - - OneByteResource* Resource(int index) const { return resources_[index]; } - - private: - std::vector<OneByteResource*> resources_; - const bool share_resources_; -}; - -namespace { - -void CreateExternalResources(Isolate* i_isolate, - DirectHandle<FixedArray> strings, - std::vector<OneByteResource*>& resources, - ExternalResourceFactory& resource_factory) { - HandleScope scope(i_isolate); - const uint32_t strings_len = strings->length().value(); - resources.reserve(strings_len); - for (uint32_t i = 0; i < strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(strings->get(i)), i_isolate); - CHECK(Utils::ToLocal(input_string) - ->CanMakeExternal(v8::String::Encoding::ONE_BYTE_ENCODING)); - const uint32_t length = input_string->length(); - char* buffer = new char[length + 1]; - String::WriteToFlat(*input_string, reinterpret_cast<uint8_t*>(buffer), 0, - length); - resources.push_back(resource_factory.CreateOneByte(buffer, length, false)); - } -} - -void CheckStringAndResource( - Tagged<String> string, int index, bool should_be_alive, - Tagged<String> deleted_string, bool check_transition, bool shared_resources, - const std::vector<std::unique_ptr<ConcurrentExternalizationThread>>& - threads) { - if (check_transition) { - if (should_be_alive) { - CHECK(IsExternalString(string)); - } else { - CHECK_EQ(string, deleted_string); - } - } - int alive_resources = 0; - for (size_t t = 0; t < threads.size(); t++) { - ConcurrentExternalizationThread* thread = threads[t].get(); - if (!thread->Resource(index)->IsDisposed()) { - alive_resources++; - } - } - - // Check exact alive resources only if the string has transitioned, otherwise - // there can still be multiple resource instances in the forwarding table. - // Only check no resource is alive if the string is dead. - const bool check_alive = check_transition || !should_be_alive; - if (check_alive) { - size_t expected_alive; - if (should_be_alive) { - if (shared_resources) { - // Since we share the same resource for all threads, we accounted for it - // in every thread. - expected_alive = threads.size(); - } else { - // Check that exactly one resource is alive. - expected_alive = 1; - } - } else { - expected_alive = 0; - } - CHECK_EQ(alive_resources, expected_alive); - } -} - -} // namespace - -void TestConcurrentExternalization(bool share_resources) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - - constexpr int kThreads = 4; - constexpr int kStrings = 4096; - constexpr int kLOStrings = 16; - - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> shared_strings = CreateSharedOneByteStrings( - i_isolate, factory, kStrings - kLOStrings, kLOStrings, - sizeof(UncachedExternalString), false); - - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<ConcurrentExternalizationThread>> threads; - std::vector<OneByteResource*> shared_resources; - - if (share_resources) { - CreateExternalResources(i_isolate, shared_strings, shared_resources, - resource_factory); + const uint16_t* data() const override { return data_; } + size_t length() const override { return length_; } + void Dispose() override { + i::DeleteArray(data_); + data_ = nullptr; } + bool IsDisposed() const { return data_ == nullptr; } + + private: + const uint16_t* data_; + size_t length_; +}; - for (int i = 0; i < kThreads; i++) { - std::vector<OneByteResource*> local_resources; - if (share_resources) { - local_resources = shared_resources; - } else { - CreateExternalResources(i_isolate, shared_strings, local_resources, - resource_factory); +class ExternalResourceFactory { + public: + ~ExternalResourceFactory() { + for (auto* res : one_byte_resources_) { + CHECK(res->IsDisposed()); + delete res; + } + for (auto* res : two_byte_resources_) { + CHECK(res->IsDisposed()); + delete res; } - auto thread = std::make_unique<ConcurrentExternalizationThread>( - &test, shared_strings, local_resources, share_resources, &sema_ready, - &sema_execute_start, &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); } - - LocalIsolate* local_isolate = i_isolate->main_thread_local_isolate(); - for (int i = 0; i < kThreads; i++) { - sema_ready.ParkedWait(local_isolate); + OneByteResource* CreateOneByte(const char* data, size_t length, + bool copy = true) { + OneByteResource* res = + new OneByteResource(copy ? i::StrDup(data) : data, length); + Register(res); + return res; } - for (int i = 0; i < kThreads; i++) { - sema_execute_start.Signal(); + OneByteResource* CreateOneByte(const char* data, bool copy = true) { + return CreateOneByte(data, strlen(data), copy); } - for (int i = 0; i < kThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); + TwoByteResource* CreateTwoByte(const uint16_t* data, size_t length) { + TwoByteResource* res = new TwoByteResource(data, length); + Register(res); + return res; } - - TriggerGCWithTransitions(i_isolate->heap()); - - const uint32_t shared_strings_len = shared_strings->length().value(); - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - Tagged<String> string = *input_string; - CheckStringAndResource(string, i, true, {}, true, share_resources, threads); + TwoByteResource* CreateTwoByte(base::Vector<base::uc16> vector, + bool copy = true) { + if (copy) { + vector = base::VectorOf( + base::UniqueCopyOf(vector).ReleaseData().release(), vector.size()); + } + return CreateTwoByte(vector.data(), vector.size()); } + void Register(OneByteResource* res) { one_byte_resources_.push_back(res); } + void Register(TwoByteResource* res) { two_byte_resources_.push_back(res); } - ParkingThread::ParkedJoinAll(local_isolate, threads); -} - -UNINITIALIZED_TEST(ConcurrentExternalizationWithUniqueResources) { - TestConcurrentExternalization(false); -} + private: + std::vector<OneByteResource*> one_byte_resources_; + std::vector<TwoByteResource*> two_byte_resources_; +}; -UNINITIALIZED_TEST(ConcurrentExternalizationWithSharedResources) { - TestConcurrentExternalization(true); -} +} // namespace -void TestConcurrentExternalizationWithDeadStrings(bool share_resources, - bool transition_with_stack) { - if (v8_flags.conservative_stack_scanning) return; - v8_flags.shared_string_table = true; +UNINITIALIZED_TEST(StringShare) { + v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); + ManualGCScope manual_gc_scope; ExternalResourceFactory resource_factory; MultiClientIsolateTest test; - - constexpr int kThreads = 4; - constexpr int kStrings = 12; - constexpr int kLOStrings = 2; - Isolate* i_isolate = test.i_main_isolate(); Factory* factory = i_isolate->factory(); - ManualGCScope manual_gc_scope(i_isolate); HandleScope scope(i_isolate); - IndirectHandle<FixedArray> shared_strings = CreateSharedOneByteStrings( - i_isolate, factory, kStrings - kLOStrings, kLOStrings, - sizeof(UncachedExternalString), false); - - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<ConcurrentExternalizationThread>> threads; - std::vector<OneByteResource*> shared_resources; + // A longer string so that concatenated to itself, the result is > + // ConsString::kMinLength. + const char raw_one_byte[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; + base::uc16 raw_two_byte[] = {2001, 2002, 2003}; + base::Vector<base::uc16> two_byte(raw_two_byte, 3); - if (share_resources) { - CreateExternalResources(i_isolate, shared_strings, shared_resources, - resource_factory); - } + // Strings are flattened then copied if the flatten didn't already create a + // new copy. - for (int i = 0; i < kThreads; i++) { - std::vector<OneByteResource*> local_resources; - if (share_resources) { - local_resources = shared_resources; - } else { - CreateExternalResources(i_isolate, shared_strings, local_resources, - resource_factory); - } - auto thread = std::make_unique<ConcurrentExternalizationThread>( - &test, shared_strings, local_resources, share_resources, &sema_ready, - &sema_execute_start, &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); + { + // Old strings. + Handle<String> one_byte_seq = + factory->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); + Handle<String> two_byte_seq = + factory->NewStringFromTwoByte(two_byte, AllocationType::kOld) + .ToHandleChecked(); + CHECK(!one_byte_seq->IsShared()); + CHECK(!two_byte_seq->IsShared()); + DirectHandle<String> shared_one_byte = + ShareAndVerify(i_isolate, one_byte_seq); + DirectHandle<String> shared_two_byte = + ShareAndVerify(i_isolate, two_byte_seq); + CheckSharedStringIsEqualCopy(shared_one_byte, one_byte_seq); + CheckSharedStringIsEqualCopy(shared_two_byte, two_byte_seq); } - LocalIsolate* local_isolate = i_isolate->main_thread_local_isolate(); - for (int i = 0; i < kThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - for (int i = 0; i < kThreads; i++) { - sema_execute_start.Signal(); - } - for (int i = 0; i < kThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); + { + // Internalized strings. + Handle<String> one_byte_seq = + factory->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); + Handle<String> two_byte_seq = + factory->NewStringFromTwoByte(two_byte, AllocationType::kOld) + .ToHandleChecked(); + CHECK(!one_byte_seq->IsShared()); + CHECK(!two_byte_seq->IsShared()); + Handle<String> one_byte_intern = factory->InternalizeString(one_byte_seq); + Handle<String> two_byte_intern = factory->InternalizeString(two_byte_seq); + CHECK(!one_byte_intern->IsShared()); + CHECK(!two_byte_intern->IsShared()); + DirectHandle<String> shared_one_byte_intern = + ShareAndVerify(i_isolate, one_byte_intern); + DirectHandle<String> shared_two_byte_intern = + ShareAndVerify(i_isolate, two_byte_intern); + CheckSharedStringIsEqualCopy(shared_one_byte_intern, one_byte_intern); + CheckSharedStringIsEqualCopy(shared_two_byte_intern, two_byte_intern); } - DirectHandle<String> empty_string( - ReadOnlyRoots(i_isolate->heap()).empty_string(), i_isolate); - const uint32_t shared_strings_len = shared_strings->length().value(); - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - // Patch every third string to empty. The next GC will dispose the external - // resources. - if (i % 3 == 0) { - input_string.SetValue(*empty_string); - shared_strings->set(i, *input_string); + { + // External strings. + Handle<String> one_byte_ext = + factory->NewStringFromAsciiChecked(raw_one_byte, AllocationType::kOld); + Handle<String> two_byte_ext = + factory->NewStringFromTwoByte(two_byte, AllocationType::kOld) + .ToHandleChecked(); + OneByteResource* one_byte_res = + resource_factory.CreateOneByte(raw_one_byte); + TwoByteResource* two_byte_res = resource_factory.CreateTwoByte(two_byte); + CHECK(one_byte_ext->MakeExternal(i_isolate, one_byte_res)); + CHECK(two_byte_ext->MakeExternal(i_isolate, two_byte_res)); + if (v8_flags.always_use_string_forwarding_table) { + i_isolate->heap()->CollectGarbageShared( + i_isolate->main_thread_local_heap(), + GarbageCollectionReason::kTesting); } + CHECK(IsExternalString(*one_byte_ext)); + CHECK(IsExternalString(*two_byte_ext)); + CHECK(!one_byte_ext->IsShared()); + CHECK(!two_byte_ext->IsShared()); + DirectHandle<String> shared_one_byte = + ShareAndVerify(i_isolate, one_byte_ext); + DirectHandle<String> shared_two_byte = + ShareAndVerify(i_isolate, two_byte_ext); + CheckSharedStringIsEqualCopy(shared_one_byte, one_byte_ext); + CheckSharedStringIsEqualCopy(shared_two_byte, two_byte_ext); } - v8_flags.transition_strings_during_gc_with_stack = transition_with_stack; - i_isolate->heap()->CollectGarbageShared(i_isolate->main_thread_local_heap(), - GarbageCollectionReason::kTesting); - - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - const bool should_be_alive = i % 3 != 0; - Tagged<String> string = *input_string; - CheckStringAndResource(string, i, should_be_alive, *empty_string, - transition_with_stack, share_resources, threads); - } - - // If we didn't test transitions during GC with stack, trigger another GC - // (allowing transitions with stack) to ensure everything is handled - // correctly. - if (!transition_with_stack) { - v8_flags.transition_strings_during_gc_with_stack = true; - - i_isolate->heap()->CollectGarbageShared(i_isolate->main_thread_local_heap(), - GarbageCollectionReason::kTesting); - - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - const bool should_be_alive = i % 3 != 0; - Tagged<String> string = *input_string; - CheckStringAndResource(string, i, should_be_alive, *empty_string, true, - share_resources, threads); - } + if (!v8_flags.single_generation) { + // Young strings + Handle<String> young_one_byte_seq = factory->NewStringFromAsciiChecked( + raw_one_byte, AllocationType::kYoung); + Handle<String> young_two_byte_seq = + factory->NewStringFromTwoByte(two_byte, AllocationType::kYoung) + .ToHandleChecked(); + CHECK(HeapLayout::InYoungGeneration(*young_one_byte_seq)); + CHECK(HeapLayout::InYoungGeneration(*young_two_byte_seq)); + CHECK(!young_one_byte_seq->IsShared()); + CHECK(!young_two_byte_seq->IsShared()); + DirectHandle<String> shared_one_byte = + ShareAndVerify(i_isolate, young_one_byte_seq); + DirectHandle<String> shared_two_byte = + ShareAndVerify(i_isolate, young_two_byte_seq); + CheckSharedStringIsEqualCopy(shared_one_byte, young_one_byte_seq); + CheckSharedStringIsEqualCopy(shared_two_byte, young_two_byte_seq); } - ParkingThread::ParkedJoinAll(local_isolate, threads); -} - -UNINITIALIZED_TEST( - ExternalizationWithDeadStringsAndUniqueResourcesTransitionWithStack) { - TestConcurrentExternalizationWithDeadStrings(false, true); -} - -UNINITIALIZED_TEST( - ExternalizationWithDeadStringsAndSharedResourcesTransitionWithStack) { - TestConcurrentExternalizationWithDeadStrings(true, true); -} - -UNINITIALIZED_TEST(ExternalizationWithDeadStringsAndUniqueResources) { - TestConcurrentExternalizationWithDeadStrings(false, false); -} - -UNINITIALIZED_TEST(ExternalizationWithDeadStringsAndSharedResources) { - TestConcurrentExternalizationWithDeadStrings(true, false); -} - -void TestConcurrentExternalizationAndInternalization( - TestHitOrMiss hit_or_miss) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ExternalResourceFactory resource_factory; - MultiClientIsolateTest test; - - constexpr int kInternalizationThreads = 4; - constexpr int kExternalizationThreads = 4; - constexpr int kTotalThreads = - kInternalizationThreads + kExternalizationThreads; - constexpr int kStrings = 4096; - constexpr int kLOStrings = 16; - - Isolate* i_isolate = test.i_main_isolate(); - Factory* factory = i_isolate->factory(); - - HandleScope scope(i_isolate); - - IndirectHandle<FixedArray> shared_strings = CreateSharedOneByteStrings( - i_isolate, factory, kStrings - kLOStrings, kLOStrings, - sizeof(UncachedExternalString), hit_or_miss == kTestHit); - - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<ConcurrentStringThreadBase>> threads; - for (int i = 0; i < kInternalizationThreads; i++) { - auto thread = std::make_unique<ConcurrentInternalizationThread>( - &test, shared_strings, hit_or_miss, &sema_ready, &sema_execute_start, - &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - for (int i = 0; i < kExternalizationThreads; i++) { - std::vector<OneByteResource*> resources; - CreateExternalResources(i_isolate, shared_strings, resources, - resource_factory); - auto thread = std::make_unique<ConcurrentExternalizationThread>( - &test, shared_strings, resources, false, &sema_ready, - &sema_execute_start, &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); + if (!v8_flags.always_use_string_forwarding_table) { + // Thin strings + Handle<String> one_byte_seq1 = + factory->NewStringFromAsciiChecked(raw_one_byte); + Handle<String> one_byte_seq2 = + factory->NewStringFromAsciiChecked(raw_one_byte); + CHECK(!one_byte_seq1->IsShared()); + CHECK(!one_byte_seq2->IsShared()); + factory->InternalizeString(one_byte_seq1); + factory->InternalizeString(one_byte_seq2); + CHECK(StringShape(*one_byte_seq2).IsThin()); + DirectHandle<String> shared = ShareAndVerify(i_isolate, one_byte_seq2); + CheckSharedStringIsEqualCopy(shared, one_byte_seq2); } - LocalIsolate* local_isolate = i_isolate->main_thread_local_isolate(); - for (int i = 0; i < kTotalThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - for (int i = 0; i < kTotalThreads; i++) { - sema_execute_start.Signal(); - } - for (int i = 0; i < kTotalThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); + { + // Cons strings + Handle<String> one_byte_seq1 = + factory->NewStringFromAsciiChecked(raw_one_byte); + Handle<String> one_byte_seq2 = + factory->NewStringFromAsciiChecked(raw_one_byte); + CHECK(!one_byte_seq1->IsShared()); + CHECK(!one_byte_seq2->IsShared()); + Handle<String> cons = + factory->NewConsString(one_byte_seq1, one_byte_seq2).ToHandleChecked(); + CHECK(!cons->IsShared()); + CHECK(IsConsString(*cons)); + DirectHandle<String> shared = ShareAndVerify(i_isolate, cons); + CheckSharedStringIsEqualCopy(shared, cons); } - TriggerGCWithTransitions(i_isolate->heap()); - - const uint32_t shared_strings_len = shared_strings->length().value(); - for (uint32_t i = 0; i < shared_strings_len; i++) { - DirectHandle<String> input_string(Cast<String>(shared_strings->get(i)), - i_isolate); - Tagged<String> string = *input_string; - if (hit_or_miss == kTestHit) { - CHECK(IsThinString(string)); - string = Cast<ThinString>(string)->actual(); - } - int alive_resources = 0; - for (int t = kInternalizationThreads; t < kTotalThreads; t++) { - ConcurrentExternalizationThread* thread = - reinterpret_cast<ConcurrentExternalizationThread*>(threads[t].get()); - if (!thread->Resource(i)->IsDisposed()) { - alive_resources++; - } - } - - StringShape shape(string); - CHECK(shape.IsInternalized()); - // Check at most one external resource is alive. - // If internalization happens on an external string and we already have an - // internalized string with the same content, we turn it into a ThinString - // and dispose the resource. - CHECK_LE(alive_resources, 1); - CHECK_EQ(shape.IsExternal(), alive_resources); - CHECK(string->HasHashCode()); + { + // Sliced strings + Handle<String> one_byte_seq = + factory->NewStringFromAsciiChecked(raw_one_byte); + CHECK(!one_byte_seq->IsShared()); + Handle<String> sliced = + factory->NewSubString(one_byte_seq, 1, one_byte_seq->length()); + CHECK(!sliced->IsShared()); + CHECK(IsSlicedString(*sliced)); + DirectHandle<String> shared = ShareAndVerify(i_isolate, sliced); + CheckSharedStringIsEqualCopy(shared, sliced); } - - ParkingThread::ParkedJoinAll(local_isolate, threads); -} - -UNINITIALIZED_TEST(ConcurrentExternalizationAndInternalizationMiss) { - TestConcurrentExternalizationAndInternalization(kTestMiss); -} - -UNINITIALIZED_TEST(ConcurrentExternalizationAndInternalizationHit) { - TestConcurrentExternalizationAndInternalization(kTestHit); } UNINITIALIZED_TEST(SharedStringInGlobalHandle) { - v8_flags.shared_string_table = true; + v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); MultiClientIsolateTest test; @@ -2159,7 +454,7 @@ class WorkerIsolateThread : public v8::base::Thread { }; UNINITIALIZED_TEST(SharedStringInClientGlobalHandle) { - v8_flags.shared_string_table = true; + v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); MultiClientIsolateTest test; @@ -2248,7 +543,7 @@ UNINITIALIZED_TEST(RegisterOldToSharedForPromotedPageFromClient) { if (!v8_flags.minor_ms) return; v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - v8_flags.shared_string_table = true; + v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); ManualGCScope manual_gc_scope; @@ -2288,7 +583,7 @@ UNINITIALIZED_TEST( if (!v8_flags.minor_ms) return; v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - v8_flags.shared_string_table = true; + v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); ManualGCScope manual_gc_scope; @@ -2445,7 +740,7 @@ UNINITIALIZED_TEST(SharedObjectRetainedByClientRememberedSet) { if (!v8_flags.minor_ms) return; v8_flags.stress_concurrent_allocation = false; // For SealCurrentObjects. - v8_flags.shared_string_table = true; + v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); ManualGCScope manual_gc_scope; @@ -2594,13 +889,15 @@ class Regress1424955ClientIsolateThread : public v8::base::Thread { int wakeup_counter_ = 0; }; +// TOOD(pthier): This test doesn't belong here. It should be moved to +// shared-heap testing. UNINITIALIZED_TEST(Regress1424955) { if (v8_flags.single_generation) return; // When heap verification is enabled, sweeping is finalized in the atomic // pause. This issue requires that sweeping is still in progress after the // atomic pause is finished. if (v8_flags.verify_heap) return; - v8_flags.shared_string_table = true; + v8_flags.shared_heap = true; i::FlagList::EnforceFlagImplications(); ManualGCScope manual_gc_scope; @@ -2635,80 +932,6 @@ UNINITIALIZED_TEST(Regress1424955) { thread.Join(); } -class ProtectExternalStringTableAddStringClientIsolateThread - : public v8::base::Thread { - public: - ProtectExternalStringTableAddStringClientIsolateThread( - const char* name, MultiClientIsolateTest* test, v8::Isolate* isolate) - : v8::base::Thread(base::Thread::Options(name)), - test_(test), - isolate_(isolate), - i_isolate_(reinterpret_cast<Isolate*>(isolate)) {} - - void Run() override { - const char* text = "worker_external_string"; - - { - v8::Isolate::Scope isolate_scope(isolate_); - - for (int i = 0; i < 1'000; i++) { - HandleScope scope(i_isolate_); - DirectHandle<String> string = - i_isolate_->factory()->NewStringFromAsciiChecked( - text, AllocationType::kOld); - CHECK(HeapLayout::InWritableSharedSpace(*string)); - CHECK(!string->IsShared()); - CHECK( - string->MakeExternal(i_isolate_, new StaticOneByteResource(text))); - CHECK(IsExternalOneByteString(*string)); - } - } - - isolate_->Dispose(); - - V8::GetCurrentPlatform() - ->GetForegroundTaskRunner(test_->main_isolate()) - ->PostTask(std::make_unique<WakeupTask>( - test_->i_main_isolate(), test_->main_isolate_wakeup_counter())); - } - - private: - MultiClientIsolateTest* test_; - v8::Isolate* isolate_; - Isolate* i_isolate_; -}; - -UNINITIALIZED_TEST(ProtectExternalStringTableAddString) { - v8_flags.shared_string_table = true; - i::FlagList::EnforceFlagImplications(); - - ManualGCScope manual_gc_scope; - - MultiClientIsolateTest test; - v8::Isolate* client = test.NewClientIsolate(); - ProtectExternalStringTableAddStringClientIsolateThread thread("worker", &test, - client); - CHECK(thread.Start()); - Isolate* isolate = test.i_main_isolate(); - HandleScope scope(isolate); - - for (int i = 0; i < 1'000; i++) { - isolate->factory() - ->NewExternalStringFromOneByte( - new StaticOneByteResource("main_external_string")) - .Check(); - } - - // Wait for client isolate to finish the minor GC and dispose of its isolate. - while (test.main_isolate_wakeup_counter() < 1) { - v8::platform::PumpMessageLoop( - i::V8::GetCurrentPlatform(), test.main_isolate(), - v8::platform::MessageLoopBehavior::kWaitForWork); - } - - thread.Join(); -} - // This client isolate thread and the following test are equivalent to // `HeapTest.ConservativePinningScopeMarkCompactRetainsObjectReachableFromStack` // in heap-unittest.cc but for client isolates and shared heap GCs. @@ -2783,7 +1006,7 @@ UNINITIALIZED_TEST(ConservativePinningScopeInClientIsolate) { if (v8_flags.conservative_stack_scanning) { return; } - v8_flags.shared_string_table = true; + v8_flags.shared_strings = true; v8_flags.scavenger_conservative_object_pinning = false; v8_flags.precise_object_pinning = false; v8_flags.scavenger_precise_object_pinning = false; @@ -2808,7 +1031,6 @@ UNINITIALIZED_TEST(ConservativePinningScopeInClientIsolate) { UNINITIALIZED_TEST(InternalizeWithoutSharedStringTable) { if (v8_flags.single_generation) return; - v8_flags.shared_string_table = false; v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); @@ -2854,7 +1076,6 @@ UNINITIALIZED_TEST(InternalizeWithoutSharedStringTable) { UNINITIALIZED_TEST(InternalizeSharedWithoutSharedStringTable) { if (v8_flags.single_generation) return; - v8_flags.shared_string_table = false; v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); @@ -2926,7 +1147,6 @@ UNINITIALIZED_TEST(InternalizeSharedWithoutSharedStringTable) { UNINITIALIZED_TEST(LookupSharedWithoutSharedStringTable) { if (v8_flags.single_generation) return; - v8_flags.shared_string_table = false; v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); @@ -2974,7 +1194,6 @@ UNINITIALIZED_TEST(LookupSharedWithoutSharedStringTable) { UNINITIALIZED_TEST(ExternalizeSharedWithoutSharedStringTable) { if (v8_flags.single_generation) return; - v8_flags.shared_string_table = false; v8_flags.shared_strings = true; i::FlagList::EnforceFlagImplications(); diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 7524353a07c5..cef6c97a1019 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -37,6 +37,7 @@ #include "src/api/api-inl.h" #include "src/base/platform/elapsed-timer.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/execution/messages.h" #include "src/heap/factory.h" #include "src/heap/heap-inl.h" @@ -1715,21 +1716,20 @@ TEST(InvalidExternalString) { } } -#define INVALID_STRING_TEST(FUN, TYPE) \ - TEST(StringOOM##FUN) { \ - CcTest::InitializeVM(); \ - LocalContext context; \ - Isolate* isolate = CcTest::i_isolate(); \ - static_assert(String::kMaxLength < kMaxInt); \ - static const int invalid = String::kMaxLength + 1; \ - HandleScope scope(isolate); \ - v8::base::Vector<TYPE> dummy = v8::base::Vector<TYPE>::New(invalid); \ - memset(dummy.begin(), 0x0, dummy.length() * sizeof(TYPE)); \ - CHECK(isolate->factory()->FUN(dummy).is_null()); \ - memset(dummy.begin(), 0x20, dummy.length() * sizeof(TYPE)); \ - CHECK(isolate->has_exception()); \ - isolate->clear_exception(); \ - dummy.Dispose(); \ +#define INVALID_STRING_TEST(FUN, TYPE) \ + TEST(StringOOM##FUN) { \ + CcTest::InitializeVM(); \ + LocalContext context; \ + Isolate* isolate = CcTest::i_isolate(); \ + static_assert(String::kMaxLength < kMaxInt); \ + static const int invalid = String::kMaxLength + 1; \ + HandleScope scope(isolate); \ + auto dummy = v8::base::UniqueArray<TYPE>::NewForOverwrite(invalid); \ + memset(dummy.begin(), 0x0, dummy.size() * sizeof(TYPE)); \ + CHECK(isolate->factory()->FUN({dummy.begin(), dummy.size()}).is_null()); \ + memset(dummy.begin(), 0x20, dummy.size() * sizeof(TYPE)); \ + CHECK(isolate->has_exception()); \ + isolate->clear_exception(); \ } INVALID_STRING_TEST(NewStringFromUtf8, char) diff --git a/deps/v8/test/cctest/test-swiss-name-dictionary-csa.cc b/deps/v8/test/cctest/test-swiss-name-dictionary-csa.cc index d134110a3d93..d1e745173ecd 100644 --- a/deps/v8/test/cctest/test-swiss-name-dictionary-csa.cc +++ b/deps/v8/test/cctest/test-swiss-name-dictionary-csa.cc @@ -35,7 +35,7 @@ namespace test_swiss_hash_table { // See RuntimeTestRunner for description of public functions. class CSATestRunner { public: - CSATestRunner(Isolate* isolate, int initial_capacity, KeyCache& keys); + CSATestRunner(Isolate* isolate, uint32_t initial_capacity, KeyCache& keys); // TODO(v8:11330): Remove once CSA implementation has a fallback for // non-SSSE3/AVX configurations. @@ -60,8 +60,9 @@ class CSATestRunner { void Shrink(); DirectHandle<FixedArray> GetData(InternalIndex entry); - void CheckCounts(std::optional<int> capacity, std::optional<int> elements, - std::optional<int> deleted); + void CheckCounts(std::optional<uint32_t> capacity, + std::optional<uint32_t> elements, + std::optional<uint32_t> deleted); void CheckEnumerationOrder(const std::vector<std::string>& expected_keys); void CheckCopy(); void VerifyHeap(); @@ -116,7 +117,7 @@ class CSATestRunner { static constexpr int kCopyParams = 1; // (table) }; -CSATestRunner::CSATestRunner(Isolate* isolate, int initial_capacity, +CSATestRunner::CSATestRunner(Isolate* isolate, uint32_t initial_capacity, KeyCache& keys) : isolate_{isolate}, reference_{isolate_->factory()->NewSwissNameDictionaryWithCapacity( @@ -145,8 +146,8 @@ void CSATestRunner::Add(DirectHandle<Name> key, DirectHandle<Object> value, if (*success == roots.false_value()) { // |add_ft_| does not resize and indicates the need to do so by returning // false. - int capacity = table->Capacity(); - int used_capacity = table->UsedCapacity(); + uint32_t capacity = table->Capacity(); + uint32_t used_capacity = table->UsedCapacity(); CHECK_GT(used_capacity + 1, SwissNameDictionary::MaxUsableCapacity(capacity)); @@ -185,9 +186,9 @@ DirectHandle<FixedArray> CSATestRunner::GetData(InternalIndex entry) { table, handle(Smi::FromInt(entry.as_int()), isolate_)); } -void CSATestRunner::CheckCounts(std::optional<int> capacity, - std::optional<int> elements, - std::optional<int> deleted) { +void CSATestRunner::CheckCounts(std::optional<uint32_t> capacity, + std::optional<uint32_t> elements, + std::optional<uint32_t> deleted) { DirectHandle<FixedArray> counts = get_counts_ft_.CallChecked<FixedArray>(table); diff --git a/deps/v8/test/cctest/test-swiss-name-dictionary-infra.h b/deps/v8/test/cctest/test-swiss-name-dictionary-infra.h index 551e37d34fd8..7293dc0952a4 100644 --- a/deps/v8/test/cctest/test-swiss-name-dictionary-infra.h +++ b/deps/v8/test/cctest/test-swiss-name-dictionary-infra.h @@ -24,10 +24,10 @@ using IndexOpt = std::optional<InternalIndex>; static const ValueOpt kNoValue; static const PropertyDetailsOpt kNoDetails; -static const std::optional<int> kNoInt; +static const std::optional<uint32_t> kNoUint32; static const IndexOpt kIndexUnknown; -static const std::vector<int> interesting_initial_capacities = { +static const std::vector<uint32_t> interesting_initial_capacities = { 4, 8, 16, @@ -40,10 +40,10 @@ static const std::vector<int> interesting_initial_capacities = { // TODO(v8:11330) Revisit this once the actual CSA/Torque versions are run by // the test suite, which will speed things up. #if defined(THREAD_SANITIZER) || defined(V8_ENABLE_CONTROL_FLOW_INTEGRITY) -static const std::vector<int> capacities_for_slow_sanitizer_tests = {4, 8, 16, - 128, 1024}; +static const std::vector<uint32_t> capacities_for_slow_sanitizer_tests = { + 4, 8, 16, 128, 1024}; #else -static const std::vector<int> capacities_for_slow_sanitizer_tests = +static const std::vector<uint32_t> capacities_for_slow_sanitizer_tests = interesting_initial_capacities; #endif @@ -52,10 +52,10 @@ static const std::vector<int> capacities_for_slow_sanitizer_tests = // TODO(v8:11330) Revisit this once the actual CSA/Torque versions are run by // the test suite, which will speed things up. #if DEBUG -static const std::vector<int> capacities_for_slow_debug_tests = {4, 8, 16, 128, - 1024}; +static const std::vector<uint32_t> capacities_for_slow_debug_tests = { + 4, 8, 16, 128, 1024}; #else -static const std::vector<int> capacities_for_slow_debug_tests = +static const std::vector<uint32_t> capacities_for_slow_debug_tests = interesting_initial_capacities; #endif @@ -65,7 +65,7 @@ extern const std::vector<PropertyDetails> distinct_property_details; struct FakeH1 { uint32_t value; - explicit FakeH1(int value) : value{static_cast<uint32_t>(value)} {} + explicit FakeH1(uint32_t value) : value{value} {} bool operator==(const FakeH1& other) const { return value == other.value; } }; @@ -115,7 +115,7 @@ class CSATestRunner; template <typename TestRunner> class TestSequence { public: - explicit TestSequence(Isolate* isolate, int initial_capacity) + explicit TestSequence(Isolate* isolate, uint32_t initial_capacity) : isolate{isolate}, initial_capacity{initial_capacity}, keys_{}, @@ -246,9 +246,10 @@ class TestSequence { CHECK(runner_.FindEntry(key_handle).is_found()); } - void CheckCounts(std::optional<int> capacity, - std::optional<int> elements = std::optional<int>(), - std::optional<int> deleted = std::optional<int>()) { + void CheckCounts( + std::optional<uint32_t> capacity, + std::optional<uint32_t> elements = std::optional<uint32_t>(), + std::optional<uint32_t> deleted = std::optional<uint32_t>()) { runner_.CheckCounts(capacity, elements, deleted); } @@ -271,7 +272,7 @@ class TestSequence { // Just for debugging void Print() { runner_.PrintTable(); } - static std::vector<int> boundary_indices(int capacity) { + static std::vector<uint32_t> boundary_indices(uint32_t capacity) { if (capacity == 4 && SwissNameDictionary::MaxUsableCapacity(4) < 4) { // If we cannot put 4 entries in a capacity 4 table without resizing, just // work with 3 boundary indices. @@ -292,16 +293,17 @@ class TestSequence { } static void WithInitialCapacity( - int capacity, std::function<void(TestSequence&)> manipulate_sequence) { + uint32_t capacity, + std::function<void(TestSequence&)> manipulate_sequence) { WithInitialCapacities({capacity}, manipulate_sequence); } // For each capacity in |capacities|, create a TestSequence and run the given // function on it. static void WithInitialCapacities( - const std::vector<int>& capacities, + const std::vector<uint32_t>& capacities, std::function<void(TestSequence&)> manipulate_sequence) { - for (int capacity : capacities) { + for (uint32_t capacity : capacities) { Isolate* isolate = CcTest::InitIsolateOnce(); HandleScope scope{isolate}; TestSequence<TestRunner> s(isolate, capacity); @@ -310,7 +312,7 @@ class TestSequence { } Isolate* const isolate; - const int initial_capacity; + const uint32_t initial_capacity; private: // Caches keys used in this TestSequence. See |create_key_with_hash| for diff --git a/deps/v8/test/cctest/test-swiss-name-dictionary-shared-tests.h b/deps/v8/test/cctest/test-swiss-name-dictionary-shared-tests.h index c3a520a68f07..03864040fc86 100644 --- a/deps/v8/test/cctest/test-swiss-name-dictionary-shared-tests.h +++ b/deps/v8/test/cctest/test-swiss-name-dictionary-shared-tests.h @@ -57,7 +57,8 @@ struct SharedSwissTableTests { // H1 values are used modulo the capacity of the table, this has no further // effects. Note that using just this value itself as an H1 value means that a // key will (try to) occupy bucket 0. - static const int kBigModulus = (1 << 22); + static const uint32_t kBigModulus = + V8_LOWER_LIMITS_MODE_BOOL ? (1 << 18) : (1 << 22); static_assert(SwissNameDictionary::IsValidCapacity(kBigModulus)); // Returns elements from TS::distinct_property_details in a deterministic @@ -73,13 +74,13 @@ struct SharedSwissTableTests { // Capacity() - 2, and Capacity() - 1. (But only three of those if the table // can't hold 4 elements without resizing). static void AddAtBoundaries(TS& s) { - int capacity = s.initial_capacity; - std::vector<int> interesting_indices = s.boundary_indices(capacity); + uint32_t capacity = s.initial_capacity; + std::vector<uint32_t> interesting_indices = s.boundary_indices(capacity); s.CheckCounts(capacity, 0, 0); int count = 0; - for (int index : interesting_indices) { + for (uint32_t index : interesting_indices) { std::string key = "k" + std::to_string(index); std::string value = "v" + std::to_string(index); PropertyDetails details = distinct_details(count++); @@ -95,10 +96,10 @@ struct SharedSwissTableTests { // appending the actual index (e.g., 0, ...., counts - 1) to |key_prefix| and // |value_prefix|, respectively. The property details are taken from // |distinct_property_details|. - static void AddMultiple(TS& s, int count, std::string key_prefix = "key", + static void AddMultiple(TS& s, uint32_t count, std::string key_prefix = "key", std::string value_prefix = "value", int details_offset = 0) { - for (int i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { std::string key = key_prefix + std::to_string(i); std::string value = value_prefix + std::to_string(i); PropertyDetails d = distinct_details(i); @@ -108,14 +109,15 @@ struct SharedSwissTableTests { // Checks that |count| entries exist, as they would have been added by a call // to AddMultiple with the same arguments. - static void CheckMultiple(TS& s, int count, std::string key_prefix = "key", + static void CheckMultiple(TS& s, uint32_t count, + std::string key_prefix = "key", std::string value_prefix = "value", int details_offset = 0) { DCHECK_LE(count, SwissNameDictionary::MaxUsableCapacity(s.initial_capacity)); std::vector<std::string> expected_keys; - for (int i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { std::string key = key_prefix + std::to_string(i); expected_keys.push_back(key); std::string value = value_prefix + std::to_string(i); @@ -268,13 +270,13 @@ struct SharedSwissTableTests { TS::WithAllInterestingInitialCapacities([](TS& s) { AddAtBoundaries(s); - int capacity = s.initial_capacity; + uint32_t capacity = s.initial_capacity; - std::vector<int> boundary_indices = s.boundary_indices(capacity); - int size = static_cast<int>(boundary_indices.size()); + std::vector<uint32_t> boundary_indices = s.boundary_indices(capacity); + uint32_t size = static_cast<uint32_t>(boundary_indices.size()); int count = 0; - for (int index : boundary_indices) { + for (uint32_t index : boundary_indices) { std::string key = "k" + std::to_string(index); std::string value = "v" + std::to_string(index); PropertyDetails details = distinct_details(count++); @@ -295,13 +297,13 @@ struct SharedSwissTableTests { TS::WithAllInterestingInitialCapacities([](TS& s) { AddAtBoundaries(s); - int capacity = s.initial_capacity; + uint32_t capacity = s.initial_capacity; - std::vector<int> boundary_indices = s.boundary_indices(capacity); + std::vector<uint32_t> boundary_indices = s.boundary_indices(capacity); int size = static_cast<int>(boundary_indices.size()); int count = 0; - for (int index : boundary_indices) { + for (uint32_t index : boundary_indices) { std::string key = "k" + std::to_string(index); std::string value = "newv" + std::to_string(index); // setting offset means getting other PropertyDetails than before @@ -311,7 +313,7 @@ struct SharedSwissTableTests { } count = 0; - for (int index : boundary_indices) { + for (uint32_t index : boundary_indices) { std::string key = "k" + std::to_string(index); std::string value = "newv" + std::to_string(index); PropertyDetails details = distinct_details(count++, size); @@ -330,29 +332,30 @@ struct SharedSwissTableTests { if (!TestRunner::IsEnabled()) return; // The maximum value of {TS::boundary_indices(capacity).size()} for any // |capacity|. - int count = 4; + uint32_t count = 4; // Due to shrink-on-delete, we create a new dictionary prior to each // deletion, so that we don't re-hash (which would defeat the purpose of // this test). - for (int i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { // In this iteration, we delete the i-th element of |boundary_indices|. TS::WithAllInterestingInitialCapacities([&](TS& s) { - std::vector<int> boundary_indices = + std::vector<uint32_t> boundary_indices = TS::boundary_indices(s.initial_capacity); - int number_of_entries = static_cast<int>(boundary_indices.size()); + uint32_t number_of_entries = + static_cast<uint32_t>(boundary_indices.size()); DCHECK_GE(count, number_of_entries); - if (i >= static_cast<int>(boundary_indices.size())) { + if (i >= number_of_entries) { // Nothing to do. return; } AddAtBoundaries(s); - int entry_to_delete = boundary_indices[i]; - int h1 = entry_to_delete + kBigModulus; + uint32_t entry_to_delete = boundary_indices[i]; + uint32_t h1 = entry_to_delete + kBigModulus; // We know that the key in question was added at bucket // |entry_to_delete| by AddAtBoundaries. @@ -361,9 +364,10 @@ struct SharedSwissTableTests { s.CheckKeyAbsent(key); // Account for the fact that a shrink-on-delete may have happened. - int expected_capacity = number_of_entries - 1 < s.initial_capacity / 4 - ? s.initial_capacity / 2 - : s.initial_capacity; + uint32_t expected_capacity = + number_of_entries - 1 < s.initial_capacity / 4 + ? s.initial_capacity / 2 + : s.initial_capacity; s.CheckCounts(expected_capacity, number_of_entries - 1); }); } @@ -378,15 +382,15 @@ struct SharedSwissTableTests { TS::WithAllInterestingInitialCapacities([](TS& s) { AddAtBoundaries(s); - int capacity = s.initial_capacity; + uint32_t capacity = s.initial_capacity; - std::vector<int> boundary_indices = s.boundary_indices(capacity); + std::vector<uint32_t> boundary_indices = s.boundary_indices(capacity); std::vector<std::string> keys, values; std::vector<PropertyDetails> details; int count = 0; - for (int index : boundary_indices) { + for (uint32_t index : boundary_indices) { std::string key = "additional_k" + std::to_string(index); std::string value = "additional_v" + std::to_string(index); @@ -398,7 +402,7 @@ struct SharedSwissTableTests { } count = 0; - for (int entry : boundary_indices) { + for (uint32_t entry : boundary_indices) { std::string key = keys[count]; std::string value = values[count]; PropertyDetails d = details[count]; @@ -412,7 +416,7 @@ struct SharedSwissTableTests { // The entries added by AddAtBoundaries must also still be there, at their // original indices. count = 0; - for (int index : boundary_indices) { + for (uint32_t index : boundary_indices) { std::string key = "k" + std::to_string(index); std::string value = "v" + std::to_string(index); PropertyDetails detail = distinct_property_details.at(count++); @@ -474,8 +478,8 @@ struct SharedSwissTableTests { // entries, and then delete every second one of those. Note that we do // this all on a single table, meaning that the entries from the previous // value of |exponent| are still present. - int added = 0; - int deleted = 0; + uint32_t added = 0; + uint32_t deleted = 0; int offset = 0; for (int exponent = 0; exponent <= max_exponent; ++exponent) { int count = 1 << exponent; @@ -495,14 +499,14 @@ struct SharedSwissTableTests { ++deleted; } - s.CheckCounts(kNoInt, added - deleted, kNoInt); + s.CheckCounts(kNoUint32, added - deleted, kNoUint32); offset += count; } // Some internal consistency checks on the test itself: DCHECK_EQ((1 << (max_exponent + 1)) - 1, offset); - DCHECK_EQ(offset, added); - DCHECK_EQ(offset / 2, deleted); + DCHECK_EQ(static_cast<uint32_t>(offset), added); + DCHECK_EQ(static_cast<uint32_t>(offset / 2), deleted); // Check that those entries that we expect are indeed present. for (int i = 0; i < offset; i += 2) { @@ -521,7 +525,8 @@ struct SharedSwissTableTests { // non-SSSE3/AVX configurations. if (!TestRunner::IsEnabled()) return; TS::WithInitialCapacities({4, 8, 16, 128}, [](TS& s) { - int count = SwissNameDictionary::MaxUsableCapacity(s.initial_capacity); + uint32_t count = + SwissNameDictionary::MaxUsableCapacity(s.initial_capacity); AddMultiple(s, count, "resize2"); @@ -543,9 +548,9 @@ struct SharedSwissTableTests { // Determine those capacities, allowing 100% max load factor. We trust // MaxUsableCapacity to tell us which capacities that are (e.g., 4 and 8), // because we tested that function separately elsewhere. - std::vector<int> capacities_allowing_full_utilization; - for (int c = SwissNameDictionary::kInitialCapacity; - c <= static_cast<int>(SwissNameDictionary::kGroupWidth); c *= 2) { + std::vector<uint32_t> capacities_allowing_full_utilization; + for (uint32_t c = SwissNameDictionary::kInitialCapacity; + c <= SwissNameDictionary::kGroupWidth; c *= 2) { if (SwissNameDictionary::MaxUsableCapacity(c) == c) { capacities_allowing_full_utilization.push_back(c); } @@ -580,16 +585,16 @@ struct SharedSwissTableTests { // larger capacities. // TODO(v8:11330) Revisit this once the actual CSA/Torque versions are run // by the test suite, which will speed things up. - std::vector<int> capacities_to_test = + std::vector<uint32_t> capacities_to_test = TS::IsRuntimeTest() ? interesting_initial_capacities : capacities_for_slow_sanitizer_tests; TS::WithInitialCapacities(capacities_to_test, [](TS& s) { std::vector<std::string> expected_keys; - int count = std::min( - SwissNameDictionary::MaxUsableCapacity(s.initial_capacity), 1000); + uint32_t count = std::min( + SwissNameDictionary::MaxUsableCapacity(s.initial_capacity), 1000u); - for (int i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { std::string key = "enumkey" + std::to_string(i); expected_keys.push_back(key); s.Add(Key{key}); @@ -620,10 +625,10 @@ struct SharedSwissTableTests { // is 4 and the group size is 8, the three deletes above caused a // shrink, which in this case was just a rehash. So we need to add 4 // elements to cause a resize. - int resize_at = + uint32_t resize_at = SwissNameDictionary::MaxUsableCapacity(s.initial_capacity) + 4; - for (int i = count; i < resize_at; ++i) { + for (uint32_t i = count; i < resize_at; ++i) { std::string key = "enumkey" + std::to_string(i); expected_keys.push_back(key); s.Add(Key{key}); @@ -639,14 +644,14 @@ struct SharedSwissTableTests { // TODO(v8:11330): Remove once CSA implementation has a fallback for // non-SSSE3/AVX configurations. if (!TestRunner::IsEnabled()) return; - int i = 0; + uint32_t i = 0; TS::WithAllInterestingInitialCapacities([&](TS& s) { // Let's try a few different values for h1, starting at big_modulus;. - int first_h1 = i * 13 + kBigModulus; - int second_h1 = first_h1 + s.initial_capacity; + uint32_t first_h1 = i * 13 + kBigModulus; + uint32_t second_h1 = first_h1 + s.initial_capacity; - int first_entry = first_h1 % s.initial_capacity; - int second_entry = (first_h1 + 1) % s.initial_capacity; + uint32_t first_entry = first_h1 % s.initial_capacity; + uint32_t second_entry = (first_h1 + 1) % s.initial_capacity; // Add two keys with same H1 modulo capacity and same H2. Key k1{"first_key", FakeH1{first_h1}, FakeH2{42}}; @@ -690,10 +695,10 @@ struct SharedSwissTableTests { // non-SSSE3/AVX configurations. if (!TestRunner::IsEnabled()) return; TS::WithInitialCapacity(128, [](TS& s) { - int h1 = 33; // Arbitrarily chosen. - int count = 37; // Will lead to more than 2 groups being filled. + uint32_t h1 = 33; // Arbitrarily chosen. + uint32_t count = 37; // Will lead to more than 2 groups being filled. - for (int i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { std::string key = "key" + std::to_string(i); std::string value = "value" + std::to_string(i); @@ -728,31 +733,34 @@ struct SharedSwissTableTests { // This test times out in CSA mode when testing the larger capacities. // TODO(v8:11330) Revisit this once the actual CSA/Torque versions are run // by the test suite, which will speed things up. - std::vector<int> capacities_to_test = TS::IsRuntimeTest() - ? interesting_initial_capacities - : capacities_for_slow_debug_tests; + std::vector<uint32_t> capacities_to_test = + TS::IsRuntimeTest() ? interesting_initial_capacities + : capacities_for_slow_debug_tests; - int width = SwissNameDictionary::kGroupWidth; - for (int offset_from_end = 0; offset_from_end < width; ++offset_from_end) { + uint32_t width = SwissNameDictionary::kGroupWidth; + for (uint32_t offset_from_end = 0; offset_from_end < width; + ++offset_from_end) { TS::WithInitialCapacities(capacities_to_test, [&](TS& s) { - int capacity = s.initial_capacity; - int first_bucket = capacity - offset_from_end; + uint32_t capacity = s.initial_capacity; + if (capacity < offset_from_end) { + return; + } + uint32_t first_bucket = capacity - offset_from_end; // How many entries to add (carefully chosen not to cause a resize). - int filler_entries = + uint32_t filler_entries = std::min(width, SwissNameDictionary::MaxUsableCapacity(capacity)) - 1; - if (first_bucket < 0 || - // No wraparound in this case: - first_bucket + filler_entries < capacity) { + // No wraparound in this case: + if (first_bucket + filler_entries < capacity) { return; } // Starting at bucket |first_bucket|, add a sequence of |kGroupWidth| // - 1 (if table can take that many, see calculation of |filler_entries| // above) entries in a single collision chain. - for (int f = 0; f < filler_entries; ++f) { + for (uint32_t f = 0; f < filler_entries; ++f) { std::string key = "filler" + std::to_string(f); s.Add(Key{key, FakeH1{first_bucket}}); } @@ -769,7 +777,7 @@ struct SharedSwissTableTests { // Now delete the entries in between and make sure that this // doesn't break anything. - for (int f = 0; f < filler_entries; ++f) { + for (uint32_t f = 0; f < filler_entries; ++f) { std::string key = "filler" + std::to_string(f); s.DeleteByKey(Key{key, FakeH1{first_bucket}}); } @@ -783,7 +791,7 @@ struct SharedSwissTableTests { // This test may fully fill the table and hardly depends on the underlying // shape (e.g., meta table structure). Thus not testing overly large // capacities. - std::vector<int> capacities_to_test = {4, 8, 16, 128, 1024}; + std::vector<uint32_t> capacities_to_test = {4, 8, 16, 128, 1024}; if (TS::IsRuntimeTest()) { TS::WithInitialCapacities(capacities_to_test, [](TS& s) { if (s.initial_capacity <= 8) { @@ -802,7 +810,7 @@ struct SharedSwissTableTests { s.CheckDataAtKey(Key{"key2"}, kIndexUnknown, "value2"); s.CheckEnumerationOrder({"key1", "key2"}); } else { - int count = + uint32_t count = SwissNameDictionary::MaxUsableCapacity(s.initial_capacity) - 5; AddMultiple(s, count); @@ -816,7 +824,7 @@ struct SharedSwissTableTests { s.RehashInplace(); std::vector<std::string> expected_enum_order; - for (int i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { if (i == 1 || i == 2 || i == count - 1) { // These are the keys we deleted. continue; @@ -841,7 +849,7 @@ struct SharedSwissTableTests { if (TS::IsRuntimeTest()) { TS::WithInitialCapacity(32, [&](TS& s) { // Filling less than a forth of the table: - int count = 4; + uint32_t count = 4; AddMultiple(s, count); @@ -850,7 +858,7 @@ struct SharedSwissTableTests { CheckMultiple(s, count, "key", "value", 0); // Shrink doesn't shrink to fit, but only halves the capacity. - int expected_capacity = s.initial_capacity / 2; + uint32_t expected_capacity = s.initial_capacity / 2; s.CheckCounts(expected_capacity, 4, 0); s.CheckEnumerationOrder({"key0", "key1", "key2", "key3"}); @@ -902,12 +910,12 @@ struct SharedSwissTableTests { // larger capacities. // TODO(v8:11330) Revisit this once the actual CSA/Torque versions are run // by the test suite, which will speed things up. - std::vector<int> capacities_to_test = + std::vector<uint32_t> capacities_to_test = TS::IsRuntimeTest() ? interesting_initial_capacities : capacities_for_slow_sanitizer_tests; TS::WithInitialCapacities(capacities_to_test, [](TS& s) { - int fill = std::min( - 1000, + uint32_t fill = std::min( + 1000u, // -2 due to the two manually added keys below. SwissNameDictionary::MaxUsableCapacity(s.initial_capacity) - 2); AddMultiple(s, fill); diff --git a/deps/v8/test/cctest/test-swiss-name-dictionary.cc b/deps/v8/test/cctest/test-swiss-name-dictionary.cc index 549a4d8aa698..61d9cb0921b2 100644 --- a/deps/v8/test/cctest/test-swiss-name-dictionary.cc +++ b/deps/v8/test/cctest/test-swiss-name-dictionary.cc @@ -16,7 +16,7 @@ namespace test_swiss_hash_table { // Executes tests by executing C++ versions of dictionary operations. class RuntimeTestRunner { public: - RuntimeTestRunner(Isolate* isolate, int initial_capacity, KeyCache& keys) + RuntimeTestRunner(Isolate* isolate, uint32_t initial_capacity, KeyCache& keys) : isolate_{isolate}, keys_{keys} { table = isolate->factory()->NewSwissNameDictionaryWithCapacity( initial_capacity, AllocationType::kYoung); @@ -43,8 +43,9 @@ class RuntimeTestRunner { // Tests that the current table has the given capacity, and number of // (deleted) elements, based on which optional values are present. - void CheckCounts(std::optional<int> capacity, std::optional<int> elements, - std::optional<int> deleted); + void CheckCounts(std::optional<uint32_t> capacity, + std::optional<uint32_t> elements, + std::optional<uint32_t> deleted); // Checks that |expected_keys| contains exactly the keys in the current table, // in the given order. void CheckEnumerationOrder(const std::vector<std::string>& expected_keys); @@ -97,9 +98,9 @@ void RuntimeTestRunner::Delete(InternalIndex entry) { table = table->DeleteEntry(isolate_, table, entry); } -void RuntimeTestRunner::CheckCounts(std::optional<int> capacity, - std::optional<int> elements, - std::optional<int> deleted) { +void RuntimeTestRunner::CheckCounts(std::optional<uint32_t> capacity, + std::optional<uint32_t> elements, + std::optional<uint32_t> deleted) { if (capacity.has_value()) { CHECK_EQ(capacity.value(), table->Capacity()); } @@ -114,7 +115,7 @@ void RuntimeTestRunner::CheckCounts(std::optional<int> capacity, void RuntimeTestRunner::CheckEnumerationOrder( const std::vector<std::string>& expected_keys) { ReadOnlyRoots roots(isolate_); - int i = 0; + size_t i = 0; for (InternalIndex index : table->IterateEntriesOrdered()) { Tagged<Object> key; if (table->ToKey(roots, index, &key)) { @@ -155,66 +156,66 @@ void RuntimeTestRunner::PrintTable() { } TEST(CapacityFor) { - for (int elements = 0; elements <= 32; elements++) { - int capacity = SwissNameDictionary::CapacityFor(elements); + for (uint32_t elements = 0; elements <= 32; elements++) { + uint32_t capacity = SwissNameDictionary::CapacityFor(elements); if (elements == 0) { - CHECK_EQ(0, capacity); + CHECK_EQ(0u, capacity); } else if (elements <= 3) { - CHECK_EQ(4, capacity); + CHECK_EQ(4u, capacity); } else if (elements == 4) { CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 8, capacity == 8); CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 16, capacity == 4); } else if (elements <= 7) { - CHECK_EQ(8, capacity); + CHECK_EQ(8u, capacity); } else if (elements <= 14) { - CHECK_EQ(16, capacity); + CHECK_EQ(16u, capacity); } else if (elements <= 28) { - CHECK_EQ(32, capacity); + CHECK_EQ(32u, capacity); } else if (elements <= 32) { - CHECK_EQ(64, capacity); + CHECK_EQ(64u, capacity); } } } TEST(MaxUsableCapacity) { - CHECK_EQ(0, SwissNameDictionary::MaxUsableCapacity(0)); + CHECK_EQ(0u, SwissNameDictionary::MaxUsableCapacity(0)); CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 8, SwissNameDictionary::MaxUsableCapacity(4) == 3); CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 16, SwissNameDictionary::MaxUsableCapacity(4) == 4); - CHECK_EQ(7, SwissNameDictionary::MaxUsableCapacity(8)); - CHECK_EQ(14, SwissNameDictionary::MaxUsableCapacity(16)); - CHECK_EQ(28, SwissNameDictionary::MaxUsableCapacity(32)); + CHECK_EQ(7u, SwissNameDictionary::MaxUsableCapacity(8)); + CHECK_EQ(14u, SwissNameDictionary::MaxUsableCapacity(16)); + CHECK_EQ(28u, SwissNameDictionary::MaxUsableCapacity(32)); } TEST(SizeFor) { - int baseline = sizeof(HeapObject) + - // prefix: - 4 + - // capacity: - 4 + - // meta table: - kTaggedSize; - - int size_0 = baseline + - // ctrl table: - SwissNameDictionary::kGroupWidth; - - int size_4 = baseline + - // data table: - 4 * 2 * kTaggedSize + - // ctrl table: - 4 + SwissNameDictionary::kGroupWidth + - // property details table: - 4; - - int size_8 = baseline + - // data table: - 8 * 2 * kTaggedSize + - // ctrl table: - 8 + SwissNameDictionary::kGroupWidth + - // property details table: - 8; + uint32_t baseline = sizeof(HeapObject) + + // prefix: + 4 + + // capacity: + 4 + + // meta table: + kTaggedSize; + + uint32_t size_0 = baseline + + // ctrl table: + SwissNameDictionary::kGroupWidth; + + uint32_t size_4 = baseline + + // data table: + 4 * 2 * kTaggedSize + + // ctrl table: + 4 + SwissNameDictionary::kGroupWidth + + // property details table: + 4; + + uint32_t size_8 = baseline + + // data table: + 8 * 2 * kTaggedSize + + // ctrl table: + 8 + SwissNameDictionary::kGroupWidth + + // property details table: + 8; CHECK_EQ(SwissNameDictionary::SizeFor(0), size_0); CHECK_EQ(SwissNameDictionary::SizeFor(4), size_4); diff --git a/deps/v8/test/cctest/test-transitions.cc b/deps/v8/test/cctest/test-transitions.cc index e2d253872f09..0fce6e1381eb 100644 --- a/deps/v8/test/cctest/test-transitions.cc +++ b/deps/v8/test/cctest/test-transitions.cc @@ -6,6 +6,7 @@ #include <stdlib.h> +#include <array> #include <utility> #include "src/api/api-inl.h" @@ -162,9 +163,9 @@ TEST(TransitionArray_DifferentFieldNames) { CHECK(IsSmi(map0->raw_transitions())); for (int i = 0; i < PROPS_COUNT; i++) { - base::EmbeddedVector<char, 64> buffer; - SNPrintF(buffer, "prop%d", i); - Handle<String> name = factory->InternalizeUtf8String(buffer.begin()); + std::array<char, 64> buffer; + base::SNPrintF(buffer, "prop%d", i); + Handle<String> name = factory->InternalizeUtf8String(buffer.data()); Handle<Map> map = Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate), attributes, PropertyConstness::kMutable, @@ -254,9 +255,9 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) { // Some number of fields. for (int i = 0; i < PROPS_COUNT; i++) { - base::EmbeddedVector<char, 64> buffer; - SNPrintF(buffer, "prop%d", i); - Handle<String> name = factory->InternalizeUtf8String(buffer.begin()); + std::array<char, 64> buffer; + base::SNPrintF(buffer, "prop%d", i); + Handle<String> name = factory->InternalizeUtf8String(buffer.data()); Handle<Map> map = Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate), NONE, PropertyConstness::kMutable, @@ -589,9 +590,9 @@ TEST(TransitionArray_LinearSearchHandlesUnsortedArray) { Handle<String> names[kCount]; for (int i = 0; i < kCount; i++) { - base::EmbeddedVector<char, 64> buffer; - SNPrintF(buffer, "prop%d", i); - Handle<String> name = factory->InternalizeUtf8String(buffer.begin()); + std::array<char, 64> buffer; + base::SNPrintF(buffer, "prop%d", i); + Handle<String> name = factory->InternalizeUtf8String(buffer.data()); Handle<Map> next = Map::CopyWithField(isolate, map0, name, FieldType::Any(isolate), NONE, PropertyConstness::kMutable, diff --git a/deps/v8/test/cctest/test-usecounters.cc b/deps/v8/test/cctest/test-usecounters.cc index cbc43a082847..6756246f90f1 100644 --- a/deps/v8/test/cctest/test-usecounters.cc +++ b/deps/v8/test/cctest/test-usecounters.cc @@ -37,25 +37,17 @@ TEST(AssigmentExpressionLHSIsCall) { CHECK_EQ(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy]); CHECK_EQ(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict]); - // AssignmentExpressions whose LHS is a call increment appropriate counters + // AssignmentExpressions whose LHS is a call increment the sloppy counter. CompileRun("function f(){ a() = 0; }"); CHECK_NE(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy]); CHECK_EQ(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict]); use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy] = 0; - CompileRun("function f(){ 'use strict'; a() = 0; }"); - CHECK_EQ(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy]); - CHECK_NE(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict]); - use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict] = 0; - // UpdateExpressions whose LHS is a call increment appropriate counters + // UpdateExpressions whose LHS is a call increment the sloppy counter. CompileRun("function f(){ ++a(); }"); CHECK_NE(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy]); CHECK_EQ(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict]); use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy] = 0; - CompileRun("function f(){ 'use strict'; ++a(); }"); - CHECK_EQ(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy]); - CHECK_NE(0, use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict]); - use_counts[v8::Isolate::kAssigmentExpressionLHSIsCallInStrict] = 0; global_use_counts = nullptr; } @@ -281,6 +273,44 @@ TEST(RegExpSplitUseCounters) { global_use_counts = nullptr; } +TEST(BigInt) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + int use_counts[v8::Isolate::kUseCounterFeatureCount] = {}; + global_use_counts = use_counts; + CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback); + + CompileRun("1 + 2; '123'; new Int32Array(1); new Float64Array(1);"); + CHECK_EQ(0, use_counts[v8::Isolate::kBigInt]); + + CompileRun("123n;"); + CHECK_LT(0, use_counts[v8::Isolate::kBigInt]); + use_counts[v8::Isolate::kBigInt] = 0; + + CompileRun("function f() { return 456n; } f();"); + CHECK_LT(0, use_counts[v8::Isolate::kBigInt]); + use_counts[v8::Isolate::kBigInt] = 0; + + CompileRun("BigInt(123);"); + CHECK_EQ(1, use_counts[v8::Isolate::kBigInt]); + use_counts[v8::Isolate::kBigInt] = 0; + + CompileRun("BigInt('456');"); + CHECK_EQ(1, use_counts[v8::Isolate::kBigInt]); + use_counts[v8::Isolate::kBigInt] = 0; + + CompileRun("new BigInt64Array(1);"); + CHECK_EQ(1, use_counts[v8::Isolate::kBigInt]); + use_counts[v8::Isolate::kBigInt] = 0; + + CompileRun("new BigUint64Array(1);"); + CHECK_EQ(1, use_counts[v8::Isolate::kBigInt]); + use_counts[v8::Isolate::kBigInt] = 0; + + global_use_counts = nullptr; +} + } // namespace test_usecounters } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/test-utils.cc b/deps/v8/test/cctest/test-utils.cc index 43860ff66de0..9bd827862149 100644 --- a/deps/v8/test/cctest/test-utils.cc +++ b/deps/v8/test/cctest/test-utils.cc @@ -31,6 +31,7 @@ #include "src/api/api-inl.h" #include "src/base/bit-field.h" +#include "src/base/unique-array.h" #include "src/numbers/conversions.h" #include "test/cctest/cctest.h" #include "test/cctest/collector.h" @@ -102,9 +103,8 @@ TEST(BitSetComputer) { const int words = 750; CHECK_EQ(words, TwoBits::word_count(3000)); const int offset = 10; - base::Vector<unsigned char> buffer = - base::Vector<unsigned char>::New(offset + words); - memset(buffer.begin(), 0, sizeof(unsigned char) * buffer.length()); + base::UniqueArray<unsigned char> buffer = + base::UniqueArray<unsigned char>::New(offset + words); for (int i = 0; i < words; i++) { const int index = TwoBits::index(offset, i); unsigned char data = buffer[index]; @@ -117,7 +117,6 @@ TEST(BitSetComputer) { unsigned char data = buffer[index]; CHECK_EQ(i % 4, TwoBits::decode(data, i)); } - buffer.Dispose(); } @@ -128,7 +127,8 @@ TEST(SNPrintF) { int length = static_cast<int>(strlen(s)); for (int i = 1; i < length * 2; i++) { static const char kMarker = static_cast<char>(42); - base::Vector<char> buffer = base::Vector<char>::New(i + 1); + base::UniqueArray<char> buffer = + base::UniqueArray<char>::NewForOverwrite(i + 1); buffer[i] = kMarker; int n = SNPrintF(base::Vector<char>(buffer.begin(), i), "%s", s); CHECK(n <= i); @@ -140,7 +140,6 @@ TEST(SNPrintF) { } else { CHECK_EQ(length, strlen(buffer.begin())); } - buffer.Dispose(); } } @@ -201,8 +200,8 @@ TEST(Collector) { block[i] = i * 7; } } - base::Vector<int> result = collector.ToVector(); - CHECK_EQ(kLoops * (kBlockSize + kSequentialSize), result.length()); + base::UniqueArray<int> result = collector.ToVector(); + CHECK_EQ(kLoops * (kBlockSize + kSequentialSize), result.size()); for (int i = 0; i < kLoops; i++) { int offset = i * (kSequentialSize + kBlockSize); for (int j = 0; j < kBlockSize - 1; j++) { @@ -213,7 +212,6 @@ TEST(Collector) { CHECK_EQ(j, result[offset + kBlockSize + j]); } } - result.Dispose(); } @@ -221,7 +219,7 @@ TEST(SequenceCollector) { SequenceCollector<int> collector(8); const int kLoops = 5000; const int kMaxSequenceSize = 13; - int total_length = 0; + size_t total_length = 0; for (int loop = 0; loop < kLoops; loop++) { int seq_length = loop % kMaxSequenceSize; collector.StartSequence(); @@ -234,8 +232,8 @@ TEST(SequenceCollector) { } total_length += seq_length; } - base::Vector<int> result = collector.ToVector(); - CHECK_EQ(total_length, result.length()); + base::UniqueArray<int> result = collector.ToVector(); + CHECK_EQ(total_length, result.size()); int offset = 0; for (int loop = 0; loop < kLoops; loop++) { int seq_length = loop % kMaxSequenceSize; @@ -244,7 +242,6 @@ TEST(SequenceCollector) { offset++; } } - result.Dispose(); } diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-f16.cc b/deps/v8/test/cctest/wasm/test-run-wasm-f16.cc deleted file mode 100644 index 1c30d81c3b12..000000000000 --- a/deps/v8/test/cctest/wasm/test-run-wasm-f16.cc +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright 2024 the V8 project 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 "src/base/overflowing-math.h" -#include "src/codegen/assembler-inl.h" -#include "src/numbers/conversions.h" -#include "src/wasm/wasm-opcodes.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" -#include "test/cctest/wasm/wasm-simd-utils.h" -#include "test/common/wasm/test-signatures.h" -#include "test/common/wasm/wasm-macro-gen.h" -#include "third_party/fp16/src/include/fp16.h" - -namespace v8 { -namespace internal { -namespace wasm { -namespace test_run_wasm_f16 { - -WASM_EXEC_TEST(F16Load) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<float> r(execution_tier); - uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(4); - r.Build({WASM_F16_LOAD_MEM(WASM_I32V_1(4))}); - r.builder().WriteMemory(&memory[2], fp16_ieee_from_fp32_value(2.75)); - CHECK_EQ(2.75f, r.Call()); -} - -WASM_EXEC_TEST(F16Store) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t> r(execution_tier); - uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(4); - r.Build({WASM_F16_STORE_MEM(WASM_I32V_1(4), WASM_F32(2.75)), WASM_ZERO}); - r.Call(); - CHECK_EQ(r.builder().ReadMemory(&memory[2]), fp16_ieee_from_fp32_value(2.75)); -} - -WASM_EXEC_TEST(F16x8Splat) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, float> r(execution_tier); - // Set up a global to hold output vector. - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - uint8_t param1 = 0; - r.Build({WASM_GLOBAL_SET(0, WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(param1))), - WASM_ONE}); - - FOR_FLOAT32_INPUTS(x) { - r.Call(x); - uint16_t expected = fp16_ieee_from_fp32_value(x); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 8; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - if (std::isnan(x)) { - CHECK(isnan(actual_lane)); - } else { - CHECK_EQ(actual_lane, expected); - } - } - } -} - -WASM_EXEC_TEST(F16x8ReplaceLane) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t> r(execution_tier); - // Set up a global to hold output vector. - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - // Build function to replace each lane with its (FP) index. - r.Build({WASM_SIMD_F16x8_SPLAT(WASM_F32(3.14159f)), - WASM_F32(0.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 0, - WASM_F32(1.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 1, - WASM_F32(2.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 2, - WASM_F32(3.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 3, - WASM_F32(4.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 4, - WASM_F32(5.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 5, - WASM_F32(6.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 6, - WASM_F32(7.0f), - WASM_SIMD_OP(kExprF16x8ReplaceLane), - 7, - kExprGlobalSet, - 0, - WASM_ONE}); - - r.Call(); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 8; i++) { - CHECK_EQ(fp16_ieee_from_fp32_value(static_cast<float>(i)), - LANE(actual.to_i16x8(), i)); - } -} - -WASM_EXEC_TEST(F16x8ExtractLane) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t> r(execution_tier); - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - const WasmGlobal* globals[8]; - std::array<int16_t, 8> g_val; - for (int i = 0; i < 8; i++) { - LANE(g_val, i) = - static_cast<int16_t>(fp16_ieee_from_fp32_value(static_cast<float>(i))); - globals[i] = r.builder().AddGlobal(kWasmF32); - } - r.builder().WriteGlobal(*g, WasmValue(Simd128(g_val))); - - r.Build( - {WASM_GLOBAL_SET(1, WASM_SIMD_F16x8_EXTRACT_LANE(0, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(2, WASM_SIMD_F16x8_EXTRACT_LANE(1, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(3, WASM_SIMD_F16x8_EXTRACT_LANE(2, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(4, WASM_SIMD_F16x8_EXTRACT_LANE(3, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(5, WASM_SIMD_F16x8_EXTRACT_LANE(4, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(6, WASM_SIMD_F16x8_EXTRACT_LANE(5, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(7, WASM_SIMD_F16x8_EXTRACT_LANE(6, WASM_GLOBAL_GET(0))), - WASM_GLOBAL_SET(8, WASM_SIMD_F16x8_EXTRACT_LANE(7, WASM_GLOBAL_GET(0))), - WASM_ONE}); - - r.Call(); - for (int i = 0; i < 8; i++) { - CHECK_EQ(r.builder().ReadGlobal(*globals[i]).to_f32(), i); - } -} - -#define UN_OP_LIST(V) \ - V(Abs, std::abs) \ - V(Neg, -) \ - V(Sqrt, std::sqrt) \ - V(Ceil, ceilf) \ - V(Floor, floorf) \ - V(Trunc, truncf) \ - V(NearestInt, nearbyintf) - -#define TEST_UN_OP(WasmName, COp) \ - uint16_t WasmName##F16(uint16_t a) { \ - return fp16_ieee_from_fp32_value(COp(fp16_ieee_to_fp32_value(a))); \ - } \ - WASM_EXEC_TEST(F16x8##WasmName) { \ - i::v8_flags.wasm_fp16 = true; \ - RunF16x8UnOpTest(execution_tier, kExprF16x8##WasmName, WasmName##F16); \ - } - -UN_OP_LIST(TEST_UN_OP) - -#undef TEST_UN_OP -#undef UN_OP_LIST - -#define CMP_OP_LIST(V) \ - V(Eq, ==) \ - V(Ne, !=) \ - V(Gt, >) \ - V(Ge, >=) \ - V(Lt, <) \ - V(Le, <=) - -#define TEST_CMP_OP(WasmName, COp) \ - int16_t WasmName(uint16_t a, uint16_t b) { \ - return fp16_ieee_to_fp32_value(a) COp fp16_ieee_to_fp32_value(b) ? -1 : 0; \ - } \ - WASM_EXEC_TEST(F16x8##WasmName) { \ - i::v8_flags.wasm_fp16 = true; \ - RunF16x8CompareOpTest(execution_tier, kExprF16x8##WasmName, WasmName); \ - } - -CMP_OP_LIST(TEST_CMP_OP) - -#undef TEST_CMP_OP -#undef UN_CMP_LIST - -float Add(float a, float b) { return a + b; } -float Sub(float a, float b) { return a - b; } -float Mul(float a, float b) { return a * b; } - -#define BIN_OP_LIST(V) \ - V(Add, Add) \ - V(Sub, Sub) \ - V(Mul, Mul) \ - V(Div, base::Divide) \ - V(Min, JSMin) \ - V(Max, JSMax) \ - V(Pmin, Minimum) \ - V(Pmax, Maximum) - -#define TEST_BIN_OP(WasmName, COp) \ - uint16_t WasmName##F16(uint16_t a, uint16_t b) { \ - return fp16_ieee_from_fp32_value( \ - COp(fp16_ieee_to_fp32_value(a), fp16_ieee_to_fp32_value(b))); \ - } \ - WASM_EXEC_TEST(F16x8##WasmName) { \ - i::v8_flags.wasm_fp16 = true; \ - RunF16x8BinOpTest(execution_tier, kExprF16x8##WasmName, WasmName##F16); \ - } - -BIN_OP_LIST(TEST_BIN_OP) - -#undef TEST_BIN_OP -#undef BIN_OP_LIST - -WASM_EXEC_TEST(F16x8ConvertI16x8) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, int32_t> r(execution_tier); - // Create two output vectors to hold signed and unsigned results. - const WasmGlobal* g0 = r.builder().AddGlobal(kWasmS128); - const WasmGlobal* g1 = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform conversions, and write the results. - uint8_t value = 0; - uint8_t temp1 = r.AllocateLocal(kWasmS128); - r.Build({WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(kExprF16x8SConvertI16x8, - WASM_LOCAL_GET(temp1))), - WASM_GLOBAL_SET(1, WASM_SIMD_UNOP(kExprF16x8UConvertI16x8, - WASM_LOCAL_GET(temp1))), - WASM_ONE}); - - FOR_INT16_INPUTS(x) { - r.Call(x); - uint16_t expected_signed = fp16_ieee_from_fp32_value(static_cast<float>(x)); - uint16_t expected_unsigned = - fp16_ieee_from_fp32_value(static_cast<float>(static_cast<uint16_t>(x))); - Simd128 actual0 = r.builder().ReadGlobal(*g0).to_s128(); - Simd128 actual1 = r.builder().ReadGlobal(*g1).to_s128(); - for (int i = 0; i < 8; i++) { - CHECK_EQ(expected_signed, ULANE(actual0.to_i16x8(), i)); - CHECK_EQ(expected_unsigned, LANE(actual1.to_i16x8(), i)); - } - } -} - -int16_t ConvertToInt(uint16_t f16, bool unsigned_result) { - float f32 = fp16_ieee_to_fp32_value(f16); - if (std::isnan(f32)) return 0; - if (unsigned_result) { - if (f32 > float{kMaxUInt16}) return static_cast<uint16_t>(kMaxUInt16); - if (f32 < 0) return 0; - return static_cast<uint16_t>(f32); - } else { - if (f32 > float{kMaxInt16}) return static_cast<int16_t>(kMaxInt16); - if (f32 < float{kMinInt16}) return static_cast<int16_t>(kMinInt16); - return static_cast<int16_t>(f32); - } -} - -// Tests both signed and unsigned conversion. -WASM_EXEC_TEST(I16x8ConvertF16x8) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, float> r(execution_tier); - // Create two output vectors to hold signed and unsigned results. - const WasmGlobal* g0 = r.builder().AddGlobal(kWasmS128); - const WasmGlobal* g1 = r.builder().AddGlobal(kWasmS128); - // Build fn to splat test value, perform conversions, and write the results. - uint8_t value = 0; - uint8_t temp1 = r.AllocateLocal(kWasmS128); - r.Build({WASM_LOCAL_SET(temp1, WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value))), - WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(kExprI16x8SConvertF16x8, - WASM_LOCAL_GET(temp1))), - WASM_GLOBAL_SET(1, WASM_SIMD_UNOP(kExprI16x8UConvertF16x8, - WASM_LOCAL_GET(temp1))), - WASM_ONE}); - - FOR_FLOAT32_INPUTS(x) { - if (!PlatformCanRepresent(x)) continue; - r.Call(x); - int16_t expected_signed = ConvertToInt(fp16_ieee_from_fp32_value(x), false); - uint16_t expected_unsigned = - ConvertToInt(fp16_ieee_from_fp32_value(x), true); - Simd128 actual0 = r.builder().ReadGlobal(*g0).to_s128(); - Simd128 actual1 = r.builder().ReadGlobal(*g1).to_s128(); - for (int i = 0; i < 8; i++) { - CHECK_EQ(expected_signed, LANE(actual0.to_i16x8(), i)); - CHECK_EQ(expected_unsigned, ULANE(actual1.to_i16x8(), i)); - } - } -} - -WASM_EXEC_TEST(F16x8DemoteF32x4Zero) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, float> r(execution_tier); - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - r.Build({WASM_GLOBAL_SET( - 0, WASM_SIMD_UNOP(kExprF16x8DemoteF32x4Zero, - WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(0)))), - WASM_ONE}); - - FOR_FLOAT32_INPUTS(x) { - r.Call(x); - uint16_t expected = fp16_ieee_from_fp32_value(x); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 4; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - CheckFloat16LaneResult(x, x, expected, actual_lane, true); - } - for (int i = 4; i < 8; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - CheckFloat16LaneResult(x, x, 0, actual_lane, true); - } - } -} - -WASM_EXEC_TEST(F16x8DemoteF64x2Zero) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, double> r(execution_tier); - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - r.Build({WASM_GLOBAL_SET( - 0, WASM_SIMD_UNOP(kExprF16x8DemoteF64x2Zero, - WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(0)))), - WASM_ONE}); - - FOR_FLOAT64_INPUTS(x) { - r.Call(x); - uint16_t expected = DoubleToFloat16(x); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 2; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - CheckFloat16LaneResult(x, x, expected, actual_lane, true); - } - for (int i = 2; i < 8; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - CheckFloat16LaneResult(x, x, 0, actual_lane, true); - } - } -} - -WASM_EXEC_TEST(F32x4PromoteLowF16x8) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, float> r(execution_tier); - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - r.Build({WASM_GLOBAL_SET( - 0, WASM_SIMD_UNOP(kExprF32x4PromoteLowF16x8, - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(0)))), - WASM_ONE}); - - FOR_FLOAT32_INPUTS(x) { - r.Call(x); - float expected = fp16_ieee_to_fp32_value(fp16_ieee_from_fp32_value(x)); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 4; i++) { - float actual_lane = LANE(actual.to_f32x4(), i); - CheckFloatResult(x, x, expected, actual_lane, true); - } - } -} - -struct FMOperation { - const float a; - const float b; - const float c; - const float fused_result; -}; - -constexpr float large_n = 1e4; -constexpr float finf = std::numeric_limits<float>::infinity(); -constexpr float qNan = std::numeric_limits<float>::quiet_NaN(); - -// Fused Multiply-Add performs a * b + c. -static FMOperation qfma_array[] = { - {2.0f, 3.0f, 1.0f, 7.0f}, - // fused: a * b + c = (positive overflow) + -inf = -inf - // unfused: a * b + c = inf + -inf = NaN - {large_n, large_n, -finf, -finf}, - // fused: a * b + c = (negative overflow) + inf = inf - // unfused: a * b + c = -inf + inf = NaN - {-large_n, large_n, finf, finf}, - // NaN - {2.0f, 3.0f, qNan, qNan}, - // -NaN - {2.0f, 3.0f, -qNan, qNan}}; - -base::Vector<const FMOperation> qfma_vector() { - return base::ArrayVector(qfma_array); -} - -// Fused Multiply-Subtract performs -(a * b) + c. -static FMOperation qfms_array[]{ - {2.0f, 3.0f, 1.0f, -5.0f}, - // fused: -(a * b) + c = - (positive overflow) + inf = inf - // unfused: -(a * b) + c = - inf + inf = NaN - {large_n, large_n, finf, finf}, - // fused: -(a * b) + c = (negative overflow) + -inf = -inf - // unfused: -(a * b) + c = -inf - -inf = NaN - {-large_n, large_n, -finf, -finf}, - // NaN - {2.0f, 3.0f, qNan, qNan}, - // -NaN - {2.0f, 3.0f, -qNan, qNan}}; - -base::Vector<const FMOperation> qfms_vector() { - return base::ArrayVector(qfms_array); -} - -WASM_EXEC_TEST(F16x8Qfma) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, float, float, float> r(execution_tier); - // Set up global to hold output. - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - uint8_t value1 = 0, value2 = 1, value3 = 2; - r.Build( - {WASM_GLOBAL_SET(0, WASM_SIMD_F16x8_QFMA( - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value1)), - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value2)), - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value3)))), - WASM_ONE}); - for (FMOperation x : qfma_vector()) { - r.Call(x.a, x.b, x.c); - uint16_t expected = fp16_ieee_from_fp32_value(x.fused_result); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 8; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - CheckFloat16LaneResult(x.a, x.b, x.c, expected, actual_lane, - true /* exact */); - } - } -} - -WASM_EXEC_TEST(F16x8Qfms) { - i::v8_flags.wasm_fp16 = true; - WasmRunner<int32_t, float, float, float> r(execution_tier); - // Set up global to hold output. - const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); - uint8_t value1 = 0, value2 = 1, value3 = 2; - r.Build( - {WASM_GLOBAL_SET(0, WASM_SIMD_F16x8_QFMS( - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value1)), - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value2)), - WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value3)))), - WASM_ONE}); - - for (FMOperation x : qfms_vector()) { - r.Call(x.a, x.b, x.c); - uint16_t expected = fp16_ieee_from_fp32_value(x.fused_result); - Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); - for (int i = 0; i < 8; i++) { - uint16_t actual_lane = LANE(actual.to_i16x8(), i); - CheckFloat16LaneResult(x.a, x.b, x.c, expected, actual_lane, - true /* exact */); - } - } -} - -} // namespace test_run_wasm_f16 -} // namespace wasm -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/common/code-assembler-tester.h b/deps/v8/test/common/code-assembler-tester.h index 81725c804f37..bba916df7ee0 100644 --- a/deps/v8/test/common/code-assembler-tester.h +++ b/deps/v8/test/common/code-assembler-tester.h @@ -50,7 +50,7 @@ class CodeAssemblerTester { [this](Builtin, Handle<Code> code) { this->code_ = code; }, [parameter_count](Zone* zone) { return Linkage::GetJSCallDescriptor(zone, false, parameter_count, - CallDescriptor::kCanUseRoots); + CallDescriptor::kNoFlags); }, CodeKind::FOR_TESTING_JS, name)), scope_(isolate) { diff --git a/deps/v8/test/common/wasm/fuzzer-common.cc b/deps/v8/test/common/wasm/fuzzer-common.cc index 4f3ba70d0ca3..0a1aa6a65365 100644 --- a/deps/v8/test/common/wasm/fuzzer-common.cc +++ b/deps/v8/test/common/wasm/fuzzer-common.cc @@ -7,6 +7,7 @@ #include <cstdint> #include <iomanip> #include <iostream> +#include <limits> #include <memory> #include <sstream> #include <unordered_map> @@ -23,6 +24,7 @@ #include "include/v8-isolate.h" #include "include/v8-local-handle.h" #include "include/v8-metrics.h" +#include "src/base/unique-array.h" #include "src/common/assert-scope.h" #include "src/execution/isolate.h" #include "src/objects/managed.h" @@ -53,6 +55,13 @@ #include "src/wasm/interpreter/wasm-interpreter.h" #endif // V8_ENABLE_DRUMBRAKE +#if V8_OS_WIN +#include <windows.h> + +// This has to come after windows.h. +#include <psapi.h> // For `QueryWorkingSetEx`. +#endif // V8_OS_WIN + namespace v8::internal::wasm::fuzzing { namespace { @@ -128,8 +137,11 @@ bool ValuesEquivalent(const WasmValue& init_lhs, const WasmValue& init_rhs, return true; }; - auto CheckStruct = [&cmp, &lhs_map](Tagged<WasmStruct> lhs, - Tagged<WasmStruct> rhs) -> bool { + auto CheckStruct = [&cmp, &lhs_map]<typename Struct>( + Tagged<Struct> lhs, Tagged<Struct> rhs) -> bool + requires(std::is_same_v<Struct, WasmStruct> || + std::is_same_v<Struct, WasmCustomMap>) + { auto [iter, inserted] = lhs_map.insert({lhs.ptr(), rhs.ptr()}); if (!inserted) { return iter->second == rhs.ptr(); @@ -177,6 +189,12 @@ bool ValuesEquivalent(const WasmValue& init_lhs, const WasmValue& init_rhs, if (!CheckStruct(Cast<WasmStruct>(lhs_ref), Cast<WasmStruct>(rhs_ref))) { return false; } + } else if (IsWasmCustomMap(lhs_ref)) { + if (!IsWasmCustomMap(rhs_ref)) return false; + if (!CheckStruct(Cast<WasmCustomMap>(lhs_ref), + Cast<WasmCustomMap>(rhs_ref))) { + return false; + } } else if (IsWasmArray(lhs_ref)) { if (!IsWasmArray(rhs_ref)) return false; if (!CheckArray(Cast<WasmArray>(lhs_ref), Cast<WasmArray>(rhs_ref))) { @@ -249,20 +267,25 @@ void PrintValue(std::ostream& os, const WasmValue& value) { } seen_objects.insert(ref.ptr()); - if (IsWasmStruct(ref)) { - Tagged<WasmStruct> struct_ref = Cast<WasmStruct>(ref); + auto PrintStruct = [&]<typename Struct>(Tagged<Struct> ref) -> void { const auto* type = GetTypeCanonicalizer()->LookupStruct( - struct_ref->map()->wasm_type_info()->type_index()); + ref->map()->wasm_type_info()->type_index()); uint32_t count = type->field_count(); print_stack.push_back(PrintSymbol::kStructClose); for (uint32_t i = count; i-- > 0;) { - print_stack.push_back(struct_ref->GetFieldValue(i)); + print_stack.push_back(ref->GetFieldValue(i)); if (i > 0) { print_stack.push_back(PrintSymbol::kComma); } } os << '{'; + }; + + if (IsWasmStruct(ref)) { + PrintStruct(Cast<WasmStruct>(ref)); + } else if (IsWasmCustomMap(ref)) { + PrintStruct(Cast<WasmCustomMap>(ref)); } else if (IsWasmArray(ref)) { Tagged<WasmArray> array_ref = Cast<WasmArray>(ref); uint32_t len = array_ref->length(); @@ -453,7 +476,7 @@ MaybeDirectHandle<WasmModuleObject> CompileReferenceModule( native_module = GetWasmEngine()->NewNativeModule( isolate, enabled_features, detected_features, CompileTimeImportsForFuzzing(), module, code_size_estimate); - native_module->SetWireBytes(base::OwnedCopyOf(wire_bytes)); + native_module->SetWireBytes(base::UniqueCopyOf(wire_bytes)); // The value is -3 so that it is different than the compilation ID of actual // compilations, different than the sentinel value of the CompilationState @@ -471,7 +494,7 @@ MaybeDirectHandle<WasmModuleObject> CompileReferenceModule( } // Create the module object. - constexpr base::Vector<const char> kNoSourceUrl; + constexpr std::string_view kNoSourceUrl; DirectHandle<Script> script = GetWasmEngine()->GetOrCreateScript(isolate, native_module, kNoSourceUrl); TypeCanonicalizer::PrepareForCanonicalTypeId( @@ -661,12 +684,12 @@ static std::optional<ExecutionResult> ExecuteNonReferenceRun( int FindExportedMainFunction(const WasmModule* module, base::Vector<const uint8_t> wire_bytes) { - constexpr base::Vector<const char> kMainName = base::StaticCharVector("main"); for (const WasmExport& exp : module->export_table) { if (exp.kind != ImportExportKindCode::kExternalFunction) continue; - base::Vector<const uint8_t> name = - wire_bytes.SubVector(exp.name.offset(), exp.name.end_offset()); - if (base::Vector<const char>::cast(name) != kMainName) continue; + std::string_view name( + reinterpret_cast<const char*>(wire_bytes.begin() + exp.name.offset()), + exp.name.length()); + if (name != "main") continue; return exp.index; } return -1; @@ -702,38 +725,59 @@ bool GlobalsMatch(Isolate* isolate, const WasmModule* module, return global_mismatches == 0; } -#if V8_OS_LINUX || V8_OS_DARWIN +#if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_WIN // Compares two memory regions efficiently by skipping non-resident pages. // Processes memory in batches to minimize metadata overhead. bool sparse_memory_equal(uint8_t* addr1, uint8_t* addr2, size_t total_length) { + if (total_length == 0) return true; + const size_t page_size = i::CommitPageSize(); // TODO(clemensb): Add batching if necessary. 16GB is 4M pages of 4kB, hence - // the two vectors below are <= 4MB, which is OK. + // the two vectors below are <= 4MB (or <= 64MB each on Windows), which is OK. static_assert(kMaxMemory64Size <= uint64_t{16} * GB); DCHECK_GE(kMaxMemory64Size, total_length); const size_t num_pages = total_length / page_size; DCHECK_EQ(total_length, num_pages * page_size); -#ifdef V8_OS_DARWIN - using mincore_dst_type = char; +#if V8_OS_WIN + using residency_type = PSAPI_WORKING_SET_EX_INFORMATION; +#elif V8_OS_DARWIN + using residency_type = char; #else - using mincore_dst_type = unsigned char; -#endif // V8_OS_DARWIN + using residency_type = unsigned char; +#endif // Allocate storage for the two residency vectors. auto storage = - base::OwnedVector<mincore_dst_type>::NewForOverwrite(2 * num_pages); - mincore_dst_type* vec1 = storage.data(); - mincore_dst_type* vec2 = vec1 + num_pages; + base::UniqueArray<residency_type>::NewForOverwrite(2 * num_pages); + residency_type* vec1 = storage.data(); + residency_type* vec2 = vec1 + num_pages; // Fetch residency status for both address ranges. +#if V8_OS_WIN + for (size_t i = 0; i < num_pages; ++i) { + vec1[i].VirtualAddress = addr1 + (i * page_size); + vec2[i].VirtualAddress = addr2 + (i * page_size); + } + const size_t byte_size = storage.size() * sizeof(residency_type); + DCHECK_GE(std::numeric_limits<DWORD>::max(), byte_size); + if (!QueryWorkingSetEx(GetCurrentProcess(), storage.data(), + static_cast<DWORD>(byte_size))) { + FATAL("QueryWorkingSetEx failed: %lu", GetLastError()); + } + auto is_resident = [](const residency_type& info) -> bool { + return info.VirtualAttributes.Valid; + }; +#else if (mincore(addr1, total_length, vec1) != 0 || mincore(addr2, total_length, vec2) != 0) { FATAL("mincore failed: %s", strerror(errno)); } + auto is_resident = [](residency_type val) -> bool { return val & 1; }; +#endif for (size_t i = 0; i < num_pages; ++i) { - bool p1_res = vec1[i] & 1; - bool p2_res = vec2[i] & 1; + bool p1_res = is_resident(vec1[i]); + bool p2_res = is_resident(vec2[i]); // Compare pages if at least one is resident. if (!p1_res && !p2_res) continue; @@ -745,7 +789,7 @@ bool sparse_memory_equal(uint8_t* addr1, uint8_t* addr2, size_t total_length) { return true; } -#endif // V8_OS_LINUX || V8_OS_DARWIN +#endif // V8_OS_LINUX || V8_OS_DARWIN || V8_OS_WIN bool MemoriesMatch(Isolate* isolate, const WasmModule* module, Tagged<WasmTrustedInstanceData> instance_data, @@ -782,11 +826,11 @@ bool MemoriesMatch(Isolate* isolate, const WasmModule* module, uint8_t* data = static_cast<uint8_t*>(store->buffer_start()); uint8_t* ref_data = static_cast<uint8_t*>(ref_store->buffer_start()); -#if V8_OS_LINUX || V8_OS_DARWIN +#if V8_OS_LINUX || V8_OS_DARWIN || V8_OS_WIN const bool memory_equal = sparse_memory_equal(ref_data, data, memory_size); #else const bool memory_equal = std::memcmp(ref_data, data, memory_size) == 0; -#endif // V8_OS_LINUX || V8_OS_DARWIN +#endif // V8_OS_LINUX || V8_OS_DARWIN || V8_OS_WIN if (memory_equal) continue; @@ -825,6 +869,7 @@ bool MemoriesMatch(Isolate* isolate, const WasmModule* module, ss << "\n - Actual: "; print_mem_block(ss, data + j); + ss << std::dec; ss << "\n "; for (size_t k = 0; k < block_size; ++k) { @@ -1072,7 +1117,7 @@ int ExecuteAgainstReference(Isolate* isolate, MaybeDirectHandle<WasmModuleObject> maybe_module = GetWasmEngine()->SyncCompile(isolate, enabled_features, CompileTimeImportsForFuzzing(), &thrower, - base::OwnedCopyOf(wire_bytes)); + base::UniqueCopyOf(wire_bytes)); module_object_traced = maybe_module.ToHandleChecked(); CHECK(!thrower.error()); } @@ -1400,7 +1445,7 @@ int SyncCompileAndExecuteAgainstReference( MaybeDirectHandle<WasmModuleObject> compiled_module = GetWasmEngine()->SyncCompile(i_isolate, enabled_features, CompileTimeImportsForFuzzing(), &thrower, - base::OwnedCopyOf(wire_bytes)); + base::UniqueCopyOf(wire_bytes)); CHECK_EQ(valid, !compiled_module.is_null()); CHECK_EQ(!valid, thrower.error()); if (require_valid && !valid) { diff --git a/deps/v8/test/common/wasm/wasm-module-runner.cc b/deps/v8/test/common/wasm/wasm-module-runner.cc index 297dcfbcc032..391c2475e6fd 100644 --- a/deps/v8/test/common/wasm/wasm-module-runner.cc +++ b/deps/v8/test/common/wasm/wasm-module-runner.cc @@ -4,6 +4,7 @@ #include "test/common/wasm/wasm-module-runner.h" +#include "src/base/unique-array.h" #include "src/execution/isolate.h" #include "src/handles/handles.h" #include "src/objects/heap-number-inl.h" @@ -25,7 +26,7 @@ MaybeDirectHandle<WasmModuleObject> CompileForTesting( auto enabled_features = WasmEnabledFeatures::FromIsolate(isolate); MaybeDirectHandle<WasmModuleObject> module = GetWasmEngine()->SyncCompile( isolate, enabled_features, CompileTimeImports{}, thrower, - base::OwnedCopyOf(bytes)); + base::UniqueCopyOf(bytes)); DCHECK_EQ(thrower->error(), module.is_null()); return module; } diff --git a/deps/v8/test/common/wasm/wasm-run-utils.cc b/deps/v8/test/common/wasm/wasm-run-utils.cc index b3f98b70bcaf..7fcef6d94ceb 100644 --- a/deps/v8/test/common/wasm/wasm-run-utils.cc +++ b/deps/v8/test/common/wasm/wasm-run-utils.cc @@ -6,6 +6,7 @@ #include <optional> +#include "src/base/unique-array.h" #include "src/codegen/assembler-inl.h" #include "src/compiler/pipeline.h" #include "src/diagnostics/code-tracer.h" @@ -17,6 +18,7 @@ #include "src/wasm/module-compiler.h" #include "src/wasm/module-instantiate.h" #include "src/wasm/wasm-code-pointer-table-inl.h" +#include "src/wasm/wasm-debug.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-import-wrapper-cache.h" #include "src/wasm/wasm-objects-inl.h" @@ -151,10 +153,15 @@ TestingModuleBuilder::TestingModuleBuilder( WellKnownImport::kUninstantiated); ImportCallKind kind = resolved.kind(); DirectHandle<JSReceiver> callable = resolved.callable(); + int expected_arity = static_cast<int>(sig->parameter_count()); + if (kind == ImportCallKind::kJSFunction) { + expected_arity = Cast<JSFunction>(callable) + ->shared() + ->internal_formal_parameter_count_without_receiver(); + } std::shared_ptr<wasm::WasmWrapperHandle> wrapper_handle = GetWasmImportWrapperCache()->GetCompiled( - isolate, - {kind, sig, static_cast<int>(sig->parameter_count()), kNoSuspend}); + isolate, {kind, sig, expected_arity, kNoSuspend}); ImportedFunctionEntry(trusted_instance_data_, maybe_import_index) .SetWasmToWrapper(isolate_, callable, std::move(wrapper_handle), @@ -163,6 +170,9 @@ TestingModuleBuilder::TestingModuleBuilder( } TestingModuleBuilder::~TestingModuleBuilder() { + if (native_module_->HasDebugInfo()) { + native_module_->GetDebugInfo()->RemoveIsolate(isolate_); + } // When the native module dies and is erased from the cache, it is expected to // have either valid bytes or no bytes at all. native_module_->SetWireBytes({}); @@ -183,14 +193,10 @@ uint8_t* TestingModuleBuilder::AddMemory(uint32_t size, SharedFlag shared, ? static_cast<uint32_t>(RoundUp(max_size.value(), kWasmPageSize) / kWasmPageSize) : initial_pages; - module_->memories.resize(1); - WasmMemory* memory = &module_->memories[0]; - memory->initial_pages = initial_pages; - memory->maximum_pages = maximum_pages; - memory->address_type = address_type; - UpdateComputedInformation(memory); - // Create the WasmMemoryObject. + // Allocate heap objects before resizing module_->memories so heap + // verification sees consistent array lengths if GC triggers during + // allocation. DirectHandle<WasmMemoryObject> memory_object = WasmMemoryObject::New(isolate_, initial_pages, maximum_pages, shared, address_type) @@ -198,27 +204,41 @@ uint8_t* TestingModuleBuilder::AddMemory(uint32_t size, SharedFlag shared, DirectHandle<FixedArray> memory_objects = isolate_->factory()->NewFixedArray(1); memory_objects->set(0, *memory_object); - trusted_instance_data_->set_memory_objects(*memory_objects); - - // Create the memory_bases_and_sizes array. DirectHandle<TrustedFixedAddressArray> memory_bases_and_sizes = TrustedFixedAddressArray::New(isolate_, 2); - uint8_t* mem_start = reinterpret_cast<uint8_t*>( - memory_object->backing_store()->buffer_start()); - memory_bases_and_sizes->set(0, reinterpret_cast<Address>(mem_start)); - memory_bases_and_sizes->set(1, size); + DirectHandle<ProtectedFixedArray> shared_memory_backing_stores = + shared.value() ? isolate_->factory()->NewProtectedFixedArray(1) + : isolate_->factory()->empty_protected_fixed_array(); + + module_->memories.resize(1); + WasmMemory* memory = &module_->memories[0]; + memory->initial_pages = initial_pages; + memory->maximum_pages = maximum_pages; + memory->address_type = address_type; + memory->is_shared = shared; + UpdateComputedInformation(memory); + + trusted_instance_data_->set_memory_objects(*memory_objects); trusted_instance_data_->set_memory_bases_and_sizes(*memory_bases_and_sizes); + trusted_instance_data_->set_shared_memory_backing_stores( + *shared_memory_backing_stores); - mem0_start_ = mem_start; + mem0_start_ = reinterpret_cast<uint8_t*>( + memory_object->backing_store()->buffer_start()); mem0_size_ = size; CHECK(size == 0 || mem0_start_); + // Keep memory_bases_and_sizes zero-initialized until UseInInstance populates + // shared_memory_backing_stores and calls SetRawMemory, so heap verification + // succeeds if GC triggers inside UseInInstance. WasmMemoryObject::UseInInstance(isolate_, memory_object, trusted_instance_data_, 0); - // TODO(wasm): Delete the following line when test-run-wasm will use a - // multiple of kPageSize as memory size. At the moment, the effect of these - // two lines is used to shrink the memory for testing purposes. - trusted_instance_data_->SetRawMemory(0, mem0_start_, mem0_size_); + if (!shared.value()) { + // TODO(wasm): Delete the following line when test-run-wasm will use a + // multiple of kPageSize as memory size. At the moment, this is used to + // shrink non-shared memory to a sub-page size for testing purposes. + trusted_instance_data_->SetRawMemory(0, mem0_start_, mem0_size_); + } return mem0_start_; } @@ -249,8 +269,7 @@ uint32_t TestingModuleBuilder::AddFunction(const FunctionSig* sig, DCHECK_EQ(module_->functions.size(), module_->num_imported_functions + module_->num_declared_functions); if (name) { - base::Vector<const uint8_t> name_vec = - base::Vector<const uint8_t>::cast(base::CStrVector(name)); + base::Vector<const uint8_t> name_vec = base::OneByteVector(name); module_->lazily_generated_names.AddForTesting( index, {AddBytes(name_vec), static_cast<uint32_t>(name_vec.size())}); } @@ -385,8 +404,8 @@ uint32_t TestingModuleBuilder::AddBytes(base::Vector<const uint8_t> bytes) { // set", e.g. for function names. uint32_t bytes_offset = old_size ? old_size : 1; size_t new_size = bytes_offset + bytes.size(); - base::OwnedVector<uint8_t> new_bytes = - base::OwnedVector<uint8_t>::New(new_size); + base::UniqueArray<uint8_t> new_bytes = + base::UniqueArray<uint8_t>::New(new_size); if (old_size > 0) { memcpy(new_bytes.begin(), old_bytes.begin(), old_size); } else { @@ -472,9 +491,9 @@ DirectHandle<WasmInstanceObject> TestingModuleBuilder::InitInstanceObject() { module_, code_size_estimate); // Reset the declared functions; functions will be added later in the test. module_->num_declared_functions = 0; - native_module->SetWireBytes(base::OwnedVector<const uint8_t>()); + native_module->SetWireBytes(base::UniqueArray<const uint8_t>()); native_module->compilation_state()->set_compilation_id(0); - constexpr base::Vector<const char> kNoSourceUrl{"", 0}; + constexpr std::string_view kNoSourceUrl{"", 0}; DirectHandle<Script> script = GetWasmEngine()->GetOrCreateScript(isolate_, native_module, kNoSourceUrl); @@ -527,7 +546,7 @@ void WasmFunctionCompiler::Build(base::Vector<const uint8_t> bytes) { CompilationEnv env = CompilationEnv::ForModule(native_module); auto func_wire_bytes = - base::OwnedVector<uint8_t>::NewForOverwrite(function_->code.length()); + base::UniqueArray<uint8_t>::NewForOverwrite(function_->code.length()); memcpy(func_wire_bytes.begin(), wire_bytes.begin() + function_->code.offset(), func_wire_bytes.size()); diff --git a/deps/v8/test/common/wasm/wasm-run-utils.h b/deps/v8/test/common/wasm/wasm-run-utils.h index 0c175edf2cb1..bec26732a179 100644 --- a/deps/v8/test/common/wasm/wasm-run-utils.h +++ b/deps/v8/test/common/wasm/wasm-run-utils.h @@ -221,7 +221,23 @@ class TestingModuleBuilder { void SetMemoryShared() { CHECK_EQ(1, module_->memories.size()); + // Populate shared_memory_backing_stores before setting is_shared and + // calling SetRawMemory, since the memory was initially added as non-shared + // in AddMemory. + DirectHandle<WasmMemoryObject> mem_obj( + trusted_instance_data_->memory_object(0), isolate_); + DirectHandle<ProtectedFixedArray> shared_backing_stores = + isolate_->factory()->NewProtectedFixedArray(1); + DirectHandle<TrustedManaged<BackingStore>> managed_backing_store = + TrustedManaged<BackingStore>::From( + isolate_, 0, mem_obj->backing_store().as_shared_ptr()); + shared_backing_stores->set(0, *managed_backing_store); + trusted_instance_data_->set_shared_memory_backing_stores( + *shared_backing_stores); module_->memories[0].is_shared = SharedFlag{true}; + Address size_or_address = reinterpret_cast<Address>( + mem_obj->backing_store()->byte_length_address()); + trusted_instance_data_->SetRawMemory(0, mem0_start_, size_or_address); } enum FunctionType { kImport, kWasm }; @@ -605,45 +621,6 @@ class CommonWasmRunner : public WasmRunnerBase { void SetMaxSteps(int n) { builder_.set_max_steps(n); } }; -// A macro to define tests that run in different engine configurations. -#if V8_ENABLE_DRUMBRAKE -#define TEST_IF_DRUMBRAKE(name) \ - TEST(RunWasmInterpreter_##name) { \ - FLAG_SCOPE(wasm_jitless); \ - WasmInterpreterThread::Initialize(); \ - RunWasm_##name(TestExecutionTier::kInterpreter); \ - WasmInterpreterThread::Terminate(); \ - } -#else -#define TEST_IF_DRUMBRAKE(name) -#endif // V8_ENABLE_DRUMBRAKE -#define WASM_EXEC_TEST(name) \ - void RunWasm_##name(TestExecutionTier execution_tier); \ - TEST(RunWasmTurbofan_##name) { \ - RunWasm_##name(TestExecutionTier::kTurbofan); \ - } \ - TEST(RunWasmLiftoff_##name) { RunWasm_##name(TestExecutionTier::kLiftoff); } \ - TEST_IF_DRUMBRAKE(name) \ - void RunWasm_##name(TestExecutionTier execution_tier) - -#define UNINITIALIZED_WASM_EXEC_TEST(name) \ - void RunWasm_##name(TestExecutionTier execution_tier); \ - UNINITIALIZED_TEST(RunWasmTurbofan_##name) { \ - RunWasm_##name(TestExecutionTier::kTurbofan); \ - } \ - UNINITIALIZED_TEST(RunWasmLiftoff_##name) { \ - RunWasm_##name(TestExecutionTier::kLiftoff); \ - } \ - void RunWasm_##name(TestExecutionTier execution_tier) - -#define WASM_COMPILED_EXEC_TEST(name) \ - void RunWasm_##name(TestExecutionTier execution_tier); \ - TEST(RunWasmTurbofan_##name) { \ - RunWasm_##name(TestExecutionTier::kTurbofan); \ - } \ - TEST(RunWasmLiftoff_##name) { RunWasm_##name(TestExecutionTier::kLiftoff); } \ - void RunWasm_##name(TestExecutionTier execution_tier) - } // namespace v8::internal::wasm #endif // TEST_COMMON_WASM_WASM_RUN_UTILS_H diff --git a/deps/v8/test/debugger/debug/debug-eval-scope.js b/deps/v8/test/debugger/debug/debug-eval-scope.js index e7fc026568f4..fc702d50c8f5 100644 --- a/deps/v8/test/debugger/debug/debug-eval-scope.js +++ b/deps/v8/test/debugger/debug/debug-eval-scope.js @@ -49,6 +49,7 @@ eval("'use strict'; \n" + // We cannot access stack-allocated values in the eval-scope. delegate = function(exec_state) { assertEquals([ debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Script, debug.ScopeType.Global ], exec_state.frame(0).allScopes().map(s => s.scopeType())); @@ -68,6 +69,7 @@ eval("'use strict'; \n" + // Current function is an escaped inner function. delegate = function(exec_state) { assertEquals([ debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Script, debug.ScopeType.Global ], exec_state.frame(0).allScopes().map(s => s.scopeType())); diff --git a/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context-reuse.js b/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context-reuse.js index b7abd6ec81e9..a244d577faba 100644 --- a/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context-reuse.js +++ b/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context-reuse.js @@ -329,10 +329,15 @@ listener_delegate = function(exec_state) { assertThrows(() => exec_state.frame(0).scope(0).evaluate("c_block_test").value(), ReferenceError); assertEquals(21, exec_state.frame(0).scope(0).evaluate("b_block_test").value()); - // In `f` (`scope(1)`), `a_block_test` is shadowed, but `c_block_test` (from the inner block) is not. + // The inner block (`scope(1)`) has no context, but still shadows both. assertThrows(() => exec_state.frame(0).scope(1).evaluate("a_block_test").value(), ReferenceError); - assertEquals('global_c', exec_state.frame(0).scope(1).evaluate("c_block_test").value()); + assertThrows(() => exec_state.frame(0).scope(1).evaluate("c_block_test").value(), ReferenceError); assertEquals(21, exec_state.frame(0).scope(1).evaluate("b_block_test").value()); + + // In `f` (`scope(2)`), `a_block_test` is shadowed, but `c_block_test` (from the inner block) is not. + assertThrows(() => exec_state.frame(0).scope(2).evaluate("a_block_test").value(), ReferenceError); + assertEquals('global_c', exec_state.frame(0).scope(2).evaluate("c_block_test").value()); + assertEquals(21, exec_state.frame(0).scope(2).evaluate("b_block_test").value()); }; break_position = 1; (test_inner_block_isolation())(); diff --git a/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context.js b/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context.js index 36578548f6fa..7452af7bae20 100644 --- a/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context.js +++ b/deps/v8/test/debugger/debug/debug-evaluate-shadowed-context.js @@ -296,10 +296,15 @@ listener_delegate = function(exec_state) { assertThrows(() => exec_state.frame(0).scope(0).evaluate("c_block_test").value(), ReferenceError); assertEquals(21, exec_state.frame(0).scope(0).evaluate("b_block_test").value()); - // In `f` (`scope(1)`), `a_block_test` is shadowed, but `c_block_test` (from the inner block) is not. + // The inner block (`scope(1)`) has no context, but still shadows both. assertThrows(() => exec_state.frame(0).scope(1).evaluate("a_block_test").value(), ReferenceError); - assertEquals('global_c', exec_state.frame(0).scope(1).evaluate("c_block_test").value()); + assertThrows(() => exec_state.frame(0).scope(1).evaluate("c_block_test").value(), ReferenceError); assertEquals(21, exec_state.frame(0).scope(1).evaluate("b_block_test").value()); + + // In `f` (`scope(2)`), `a_block_test` is shadowed, but `c_block_test` (from the inner block) is not. + assertThrows(() => exec_state.frame(0).scope(2).evaluate("a_block_test").value(), ReferenceError); + assertEquals('global_c', exec_state.frame(0).scope(2).evaluate("c_block_test").value()); + assertEquals(21, exec_state.frame(0).scope(2).evaluate("b_block_test").value()); }; break_position = 1; (test_inner_block_isolation())(); diff --git a/deps/v8/test/debugger/debug/debug-function-scopes.js b/deps/v8/test/debugger/debug/debug-function-scopes.js index caca2114fdb0..e28e20a169e4 100644 --- a/deps/v8/test/debugger/debug/debug-function-scopes.js +++ b/deps/v8/test/debugger/debug/debug-function-scopes.js @@ -111,13 +111,14 @@ listenerDelegate = function(exec_state) { listenerDelegate = function(exec_state) { const frame = exec_state.frame(0); - assertEquals(5, frame.scopeCount()); + assertEquals(6, frame.scopeCount()); CheckScope(frame.scope(0), {}, ScopeType.Local); CheckScope(frame.scope(1), { visible2: 20 }, ScopeType.Closure); - CheckScope(frame.scope(2), { visible1: 10 }, ScopeType.Closure); - CheckScope(frame.scope(3), {}, ScopeType.Script); - CheckScope(frame.scope(4), {}, ScopeType.Global); + CheckScope(frame.scope(2), { invisible2: undefined }, ScopeType.Closure); + CheckScope(frame.scope(3), { visible1: 10, invisible1: undefined }, ScopeType.Closure); + CheckScope(frame.scope(4), {}, ScopeType.Script); + CheckScope(frame.scope(5), {}, ScopeType.Global); }; (function F1(invisible_parameter) { @@ -137,13 +138,14 @@ listenerDelegate = function(exec_state) { listenerDelegate = function(exec_state) { const frame = exec_state.frame(0); - assertEquals(5, frame.scopeCount()); + assertEquals(6, frame.scopeCount()); CheckScope(frame.scope(0), {}, ScopeType.Local); CheckScope(frame.scope(1), { e2: "I'm error 2" }, ScopeType.Catch); CheckScope(frame.scope(2), { e1: "I'm error 1" }, ScopeType.Catch); - CheckScope(frame.scope(3), {}, ScopeType.Script); - CheckScope(frame.scope(4), {}, ScopeType.Global); + CheckScope(frame.scope(3), {}, ScopeType.Closure); + CheckScope(frame.scope(4), {}, ScopeType.Script); + CheckScope(frame.scope(5), {}, ScopeType.Global); }; (function One() { diff --git a/deps/v8/test/debugger/debug/debug-modules-set-variable-value.mjs b/deps/v8/test/debugger/debug/debug-modules-set-variable-value.mjs index 04751bd7240c..89c650e67122 100644 --- a/deps/v8/test/debugger/debug/debug-modules-set-variable-value.mjs +++ b/deps/v8/test/debugger/debug/debug-modules-set-variable-value.mjs @@ -269,7 +269,7 @@ let salad = 12; function listener(event, exec_state) { if (event == Debug.DebugEvent.Break) { let scope_count = exec_state.frame().scopeCount(); - let module_scope = exec_state.frame().scope(1); + let module_scope = exec_state.frame().scope(2); assertEquals(debug.ScopeType.Module, module_scope.scopeType()); module_scope.setVariableValue('salad', 42); } @@ -309,7 +309,7 @@ export let ham = 1; function listener(event, exec_state) { if (event == Debug.DebugEvent.Break) { let scope_count = exec_state.frame().scopeCount(); - let module_scope = exec_state.frame().scope(1); + let module_scope = exec_state.frame().scope(2); assertEquals(debug.ScopeType.Module, module_scope.scopeType()); module_scope.setVariableValue('ham', 2); } diff --git a/deps/v8/test/debugger/debug/debug-scopes-suspended-generators.js b/deps/v8/test/debugger/debug/debug-scopes-suspended-generators.js index 8d09e9c2a34d..e0663262e537 100644 --- a/deps/v8/test/debugger/debug/debug-scopes-suspended-generators.js +++ b/deps/v8/test/debugger/debug/debug-scopes-suspended-generators.js @@ -308,7 +308,7 @@ CheckScopeChain([debug.ScopeType.Local, debug.ScopeType.Script, debug.ScopeType.Global], g); CheckScopeContent({a: 1}, 0, g); -CheckScopeContent({b: 2}, 1, g); +CheckScopeContent({a: undefined, b: 2}, 1, g); // Set a variable in an empty scope. diff --git a/deps/v8/test/debugger/debug/debug-scopes.js b/deps/v8/test/debugger/debug/debug-scopes.js index 08e8d366230d..146bc9bbd718 100644 --- a/deps/v8/test/debugger/debug/debug-scopes.js +++ b/deps/v8/test/debugger/debug/debug-scopes.js @@ -691,10 +691,12 @@ function closure_8() { listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); CheckScopeContent({x: 2}, 0, exec_state); - CheckScopeChainNames(["inner", undefined, undefined], exec_state); + CheckScopeContent({}, 1, exec_state); + CheckScopeChainNames(["inner", undefined, undefined, undefined], exec_state); }; closure_8(); EndTest(); @@ -896,10 +898,12 @@ function closure_in_with_1() { listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Local, debug.ScopeType.With, + debug.ScopeType.Closure, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); CheckScopeContent({x: 2}, 0, exec_state); CheckScopeContent({x: 1}, 1, exec_state); + CheckScopeContent({}, 2, exec_state); }; closure_in_with_1(); EndTest(); @@ -920,13 +924,15 @@ listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.With, debug.ScopeType.Local, debug.ScopeType.With, + debug.ScopeType.Closure, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); CheckScopeContent({x: 3}, 0, exec_state); CheckScopeContent({x: 2}, 1, exec_state); CheckScopeContent({x: 1}, 2, exec_state); + CheckScopeContent({}, 3, exec_state); CheckScopeChainNames(["inner", "inner", "closure_in_with_2", - undefined, undefined], exec_state); + undefined, undefined, undefined], exec_state); }; closure_in_with_2(); EndTest(); @@ -1175,10 +1181,13 @@ BeginTest("Classes and methods 1"); listener_delegate = function(exec_state) { "use strict" CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Block, + debug.ScopeType.Closure, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); - CheckScopeContent({}, 1, exec_state); - CheckScopeChainNames(["m", undefined, undefined], exec_state); + CheckScopeContent({}, 3, exec_state); + CheckScopeChainNames(["m", undefined, undefined, undefined, undefined], + exec_state); }; (function() { @@ -1367,6 +1376,29 @@ listener_delegate = function(exec_state) { eval(code8); EndTest(); +BeginTest("Switch discriminant is outside switch block scope"); +function switch_discriminant_test() { + function tag() { + debugger; + return 0; + } + switch (tag()) { + case 0: + let x = 1; + break; + } +} + +listener_delegate = function(exec_state) { + var outer_frame = exec_state.frame(1); + assertEquals(3, outer_frame.scopeCount()); + assertEquals(debug.ScopeType.Local, outer_frame.scope(0).scopeType()); + assertEquals(debug.ScopeType.Script, outer_frame.scope(1).scopeType()); + assertEquals(debug.ScopeType.Global, outer_frame.scope(2).scopeType()); +}; +switch_discriminant_test(); +EndTest(); + assertEquals(begin_test_count, break_count, 'one or more tests did not enter the debugger'); assertEquals(begin_test_count, end_test_count, diff --git a/deps/v8/test/debugger/debug/es6/regress-nested-arrow-default-param-this.js b/deps/v8/test/debugger/debug/es6/regress-nested-arrow-default-param-this.js new file mode 100644 index 000000000000..dc07286d4de2 --- /dev/null +++ b/deps/v8/test/debugger/debug/es6/regress-nested-arrow-default-param-this.js @@ -0,0 +1,35 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const Debug = debug.Debug; + +let break_count = 0; +let exception = null; + +const obj = { x: 42 }; +function m() { + return () => (a = this) => { + debugger; + return a; + }; +} + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + assertEquals(obj, exec_state.frame(0).evaluate("this").value()); + assertTrue(exec_state.frame(0).evaluate("this === obj").value()); + break_count++; + } catch (e) { + exception = e; + print(e + e.stack); + } +} + +Debug.setListener(listener); +assertEquals(obj, m.call(obj)()()); +Debug.setListener(null); + +assertEquals(1, break_count); +assertNull(exception); diff --git a/deps/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs b/deps/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs index 17897981bcfc..fc80b11c4661 100644 --- a/deps/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs +++ b/deps/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs @@ -524,11 +524,14 @@ function closure_8() { listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); CheckScopeContent({x: 2}, 0, exec_state); - CheckScopeChainNames(["inner", undefined, undefined, undefined], exec_state); + CheckScopeContent({}, 1, exec_state); + CheckScopeChainNames(["inner", undefined, undefined, undefined, undefined], + exec_state); }; closure_8(); EndTest(); @@ -698,11 +701,14 @@ BeginTest("Classes and methods 1"); listener_delegate = function(exec_state) { "use strict" CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Block, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); - CheckScopeContent({}, 1, exec_state); - CheckScopeChainNames(["m", undefined, undefined, undefined], exec_state); + CheckScopeContent({}, 3, exec_state); + CheckScopeChainNames( + ["m", undefined, undefined, undefined, undefined, undefined], exec_state); }; (function() { @@ -747,6 +753,7 @@ var code3 = "function for_statement() { \n" + listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Block, debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); @@ -769,6 +776,7 @@ listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Block, debug.ScopeType.Block, debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); @@ -790,6 +798,7 @@ var code5 = "function for_each_statement() { \n" + listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Block, debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); @@ -812,6 +821,7 @@ listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Block, debug.ScopeType.Block, debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); @@ -833,6 +843,7 @@ var code7 = "function for_each_statement() { \n" + listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); @@ -855,6 +866,7 @@ var code8 = "function for_each_statement() { \n" + listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.Block, debug.ScopeType.Local, + debug.ScopeType.Closure, debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], exec_state); diff --git a/deps/v8/test/debugger/debug/regress-debug-scopes-context-blocklist.js b/deps/v8/test/debugger/debug/regress-debug-scopes-context-blocklist.js index 54425333a3de..44eab6ae6c8d 100644 --- a/deps/v8/test/debugger/debug/regress-debug-scopes-context-blocklist.js +++ b/deps/v8/test/debugger/debug/regress-debug-scopes-context-blocklist.js @@ -43,14 +43,15 @@ function outer() { let f = outer(); listener_delegate = function(exec_state) { - // exec_state.frame(0).scope(1) is 'outer's closure scope. + // exec_state.frame(0).scope(2) is 'outer's closure scope (scope(1) is + // 'intermediate's contextless closure scope). // We evaluate 'x' inside 'outer's scope. // It should return 'global_x' because 'outer' does not have an 'x'. // But due to the defect, 'intermediate's stack variable 'x' leaks // into 'outer's context blocklist, causing a ReferenceError. let val; try { - val = exec_state.frame(0).scope(1).evaluate('x').value(); + val = exec_state.frame(0).scope(2).evaluate('x').value(); } catch (e) { throw new Error('Spurious error: ' + e.message); } diff --git a/deps/v8/test/debugger/debugger.status b/deps/v8/test/debugger/debugger.status index 68d35bf48562..127a9b70e0ce 100644 --- a/deps/v8/test/debugger/debugger.status +++ b/deps/v8/test/debugger/debugger.status @@ -129,6 +129,12 @@ 'regress/wasm/*': [SKIP], }], # not has_webassembly or variant == jitless +############################################################################## +['arch in [ppc64, s390x] or sandbox_hardware_support', { + # Wasm code coverage is not supported yet. + 'regress/wasm/regress-576981470': [SKIP], +}], # arch in [ppc64, s390x] or sandbox_hardware_support + ############################################################################## # Tests requiring Sparkplug. ['arch not in (x64, arm64, ia32, arm, mips64el, loong64)', { diff --git a/deps/v8/test/debugger/regress/regress-510925423.js b/deps/v8/test/debugger/regress/regress-510925423.js deleted file mode 100644 index 37cfe616ff8c..000000000000 --- a/deps/v8/test/debugger/regress/regress-510925423.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --fuzzing - -// Trigger a ReferenceError in the inspector 'receive' callback. -// This should not crash d8 in Debug builds when --fuzzing is enabled. -globalThis.receive = function(message) { - __v_27; -}; - -// Trigger a notification from the inspector. -send(JSON.stringify({ - id: 0, - method: 'Debugger.enable', -})); diff --git a/deps/v8/test/debugger/regress/regress-571155503.js b/deps/v8/test/debugger/regress/regress-571155503.js new file mode 100644 index 000000000000..c8052d0cfbd7 --- /dev/null +++ b/deps/v8/test/debugger/regress/regress-571155503.js @@ -0,0 +1,132 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const Debug = debug.Debug; + +// Case 1: Clearing the last breakpoint during an interrupt at a Return bytecode +// after a one-shot step/debug break. +(function TestClearBreakPointDuringInterruptAtReturn() { + let bp; + function bar() { + %ScheduleBreak(); + } + function foo() { + bar(); + } + + let step = 0; + Debug.setListener(function(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + step++; + if (step === 1) { + exec_state.prepareStep(Debug.StepAction.StepOut); + } else if (step === 2) { + Debug.clearBreakPoint(bp); + } + }); + + bp = Debug.setBreakPoint(foo, 0); + foo(); + Debug.setListener(null); +})(); + +// Case 2: Clearing a breakpoint in a callee and setting a new breakpoint in +// the caller during an interrupt at a Return bytecode. +(function TestSetBreakPointDuringInterruptAtReturn() { + let bp; + function bar() { + Debug.clearBreakPoint(bp); + %ScheduleBreak(); + } + function foo() { + bar(); + } + + let step = 0; + Debug.setListener(function(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + step++; + if (step === 1) { + exec_state.prepareStep(Debug.StepAction.StepOut); + } else if (step === 2) { + bp = Debug.setBreakPoint(foo, 0); + } + }); + + bp = Debug.setBreakPoint(foo, 0); + foo(); + Debug.clearBreakPoint(bp); + Debug.setListener(null); +})(); + +// Case 3: Lazy deoptimization of an active optimized frame after +// Debug::PerformSideEffectCheck creates a DebugInfo with debug bytecode +// (without BreakInfo), followed by setting and clearing a breakpoint. +(function TestLazyDeoptAfterSideEffectCheck() { + let trigger = false; + function side_effect(o) { + o.x = 1; + } + %NeverOptimizeFunction(side_effect); + + function bar(o, do_se) { + if (do_se) side_effect(o); + if (trigger) { + debugger; + } + } + %NeverOptimizeFunction(bar); + + function foo(o, do_se) { + bar(o, do_se); + return o.x; + } + + %PrepareFunctionForOptimization(foo); + let obj = {x: 0}; + for (let i = 0; i < 10; i++) foo(obj, false); + %OptimizeFunctionOnNextCall(foo); + foo(obj, false); + + Debug.setListener(function(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + exec_state.frame(0).evaluate("foo({x: 0}, true)", true); + } catch (e) { + } + %DeoptimizeFunction(foo); + let bp = Debug.setBreakPoint(foo, 0); + Debug.clearBreakPoint(bp); + }); + + trigger = true; + foo(obj, false); + Debug.setListener(null); +})(); + +// Case 4: Async generator SuspendGenerator bytecode during side-effect check +// evaluation followed by clearing breakpoints. +(function TestAsyncGeneratorSuspendDuringSideEffectCheck() { + let bp; + async function* gen() { + yield 1; + } + + let in_eval = false; + Debug.setListener(function(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + if (!in_eval) { + in_eval = true; + try { + exec_state.frame(0).evaluate("gen().next()", true); + } catch (e) { + } + Debug.clearBreakPoint(bp); + } + }); + + bp = Debug.setBreakPoint(gen, 0); + gen().next(); + Debug.setListener(null); +})(); diff --git a/deps/v8/test/debugger/regress/wasm/regress-532625490.js b/deps/v8/test/debugger/regress/wasm/regress-532625490.js deleted file mode 100644 index d615122f75fe..000000000000 --- a/deps/v8/test/debugger/regress/wasm/regress-532625490.js +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --fuzzing - -// Trigger an error in the inspector 'receive' callback during BindToCurrentContext. -// BindToCurrentContext is triggered by script compilation (e.g. eval). -// This should not hit the DCHECK(AllowExceptions::IsAllowed(this)) in Isolate::ReportPendingMessages. -globalThis.receive = function(message) { - throw new Error("fuzzer error"); -}; - -send(JSON.stringify({ - id: 0, - method: 'Debugger.enable', -})); - -eval("1 + 1"); - -// Also test Wasm instantiation which triggered the original report. -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); -const builder = new WasmModuleBuilder(); -builder.addFunction('main', kSig_v_v).addBody([]).exportFunc(); -builder.instantiate(); diff --git a/deps/v8/test/debugger/regress/wasm/regress-570547314.js b/deps/v8/test/debugger/regress/wasm/regress-570547314.js new file mode 100644 index 000000000000..ebe776119722 --- /dev/null +++ b/deps/v8/test/debugger/regress/wasm/regress-570547314.js @@ -0,0 +1,68 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const Debug = debug.Debug; +Debug.enable(); + +const builder = new WasmModuleBuilder(); +const func_a = builder.addFunction('a', kSig_i_i) + .addBody([ + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Add, // Breakpoint 1 (offset 5) + kExprI32Const, 2, + kExprI32Add, // Breakpoint 2 (offset 8) + ]) + .exportFunc(); +const func_b = builder.addFunction('b', kSig_v_v) + .addBody([ + kExprNop, // Breakpoint 3 (offset 1) + ]) + .exportFunc(); + +const instance = builder.instantiate(); + +// Test 1: Removing a breakpoint in `a` while a younger Wasm frame `b` is on top +// of the stack. +const bp_a1 = Debug.setBreakPoint(instance.exports.a, 0, 5, 'onBreakA1()'); +const bp_b = Debug.setBreakPoint(instance.exports.b, 0, 1, 'onBreakB()'); + +globalThis.onBreakA1 = function() { + instance.exports.b(); + return false; +}; + +globalThis.onBreakB = function() { + Debug.clearBreakPoint(bp_a1); + Debug.clearBreakPoint(bp_b); + return false; +}; + +assertEquals(13, instance.exports.a(10)); + +// Test 2: Two recursive activations of `a` paused at different breakpoints when +// both breakpoints are removed. +const bp_a_first = Debug.setBreakPoint( + instance.exports.a, 0, 5, 'onBreakFirst()'); +const bp_a_second = Debug.setBreakPoint( + instance.exports.a, 0, 8, 'onBreakSecond()'); + +let depth = 0; +globalThis.onBreakFirst = function() { + if (depth === 0) { + depth++; + Debug.clearBreakPoint(bp_a_first); + assertEquals(23, instance.exports.a(20)); + } + return false; +}; + +globalThis.onBreakSecond = function() { + Debug.clearBreakPoint(bp_a_second); + return false; +}; + +assertEquals(13, instance.exports.a(10)); diff --git a/deps/v8/test/debugger/regress/wasm/regress-576981470.js b/deps/v8/test/debugger/regress/wasm/regress-576981470.js new file mode 100644 index 000000000000..7330af85d65e --- /dev/null +++ b/deps/v8/test/debugger/regress/wasm/regress-576981470.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-code-coverage + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const Debug = debug.Debug; + +let exception = null; +let names = []; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + for (let i = 0; i < exec_state.frameCount(); ++i) { + names.push(exec_state.frame(i).func().name()); + } + } catch (e) { + exception = e; + } +} + +const builder = new WasmModuleBuilder(); +builder.addImport('mod', 'func', kSig_v_v); +builder.addFunction('w\u00e9sm', kSig_v_v) + .addBody([kExprCallFunction, 0]) + .exportAs('main'); + +function call_debugger() { + debugger; +} + +const instance = builder.instantiate({mod: {func: call_debugger}}); + +Debug.setListener(listener); +instance.exports.main(); +Debug.setListener(null); + +assertNull(exception); +assertTrue(names.includes('$w\u00e9sm'), names.join(',')); + +const coverage = %DebugCollectWasmCoverage(); +assertTrue(coverage.length > 0); diff --git a/deps/v8/test/debugger/test-api.js b/deps/v8/test/debugger/test-api.js index 4917c0ba200d..4844d4717db0 100644 --- a/deps/v8/test/debugger/test-api.js +++ b/deps/v8/test/debugger/test-api.js @@ -210,7 +210,15 @@ class DebugWrapper { const scopeObject = { value : () => details[kScopeDetailsObjectIndex], - property : (prop) => details[kScopeDetailsObjectIndex][prop], + property : (prop) => { + // Unavailable variables (e.g. stack-allocated variables of outer + // functions) are exposed as accessors that throw on access. + try { + return details[kScopeDetailsObjectIndex][prop]; + } catch (e) { + return undefined; + } + }, properties : scopeObjectProperties, propertyNames : () => Object.keys(details[kScopeDetailsObjectIndex]) .map((key, _) => key), diff --git a/deps/v8/test/filecheck/deopt-now-fuzzing.js b/deps/v8/test/filecheck/deopt-now-fuzzing.js new file mode 100644 index 000000000000..e8df25085a31 --- /dev/null +++ b/deps/v8/test/filecheck/deopt-now-fuzzing.js @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --fuzzing --allow-natives-syntax --no-concurrent-recompilation +// Flags: --trace-deopt --no-stress-maglev --no-always-sparkplug + +function testFunction(deopt) { + if (deopt) { + %DeoptimizeNow(); + } + return 42; +} + +%PrepareFunctionForOptimization(testFunction); +testFunction(false); +%OptimizeFunctionOnNextCall(testFunction); +testFunction(false); +// CHECK: [marking dependent code {{.*}} ({{.*}} <SharedFunctionInfo testFunction>) {{.*}} for deoptimization, reason: for testing] +// CHECK: [bailout (kind: deopt-lazy, reason: (unknown)): begin. deoptimizing {{.*}} <JSFunction testFunction +testFunction(true); + +function testOsr() { + let sum = 0; + for (let i = 0; i < 10; i++) { + if (i == 2) %OptimizeOsr(); + if (i == 5) %DeoptimizeNow(); + sum += i; + } + return sum; +} + +%PrepareFunctionForOptimization(testOsr); +// CHECK: [marking dependent code {{.*}} ({{.*}} <SharedFunctionInfo testOsr>) {{.*}} for deoptimization, reason: for testing] +// CHECK: [bailout (kind: deopt-lazy, reason: (unknown)): begin. deoptimizing {{.*}} <JSFunction testOsr +testOsr(); + +for (let i = 0; i < 10; i++) { + if (i == 2) %OptimizeOsr(); + if (i == 5) %DeoptimizeNow(); +} +// CHECK: [marking dependent code {{.*}} ({{.*}} <SharedFunctionInfo>) {{.*}} for deoptimization, reason: for testing] +// CHECK: [bailout (kind: deopt-lazy, reason: (unknown)): begin. deoptimizing {{.*}} <JSFunction diff --git a/deps/v8/test/filecheck/filecheck.status b/deps/v8/test/filecheck/filecheck.status index 84b6b07dffe7..27ace5ebb088 100644 --- a/deps/v8/test/filecheck/filecheck.status +++ b/deps/v8/test/filecheck/filecheck.status @@ -20,6 +20,7 @@ }], # not has_webassembly or variant == jitless ['variant in (jitless, nooptimization)', { + 'deopt-now-fuzzing': [SKIP], 'js-wasm-wrapper-inlining-lazy-deopt': [SKIP], 'js-wasm-wrapper-inlining-eager-deopt': [SKIP], 'js-wasm-wrapper-inlining-type-combos': [SKIP], diff --git a/deps/v8/test/filecheck/turbolev-spread-rest-parameter-late-inlined-mutation.js b/deps/v8/test/filecheck/turbolev-spread-rest-parameter-late-inlined-mutation.js new file mode 100644 index 000000000000..62eef71065f7 --- /dev/null +++ b/deps/v8/test/filecheck/turbolev-spread-rest-parameter-late-inlined-mutation.js @@ -0,0 +1,42 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev --maglev-object-tracking +// Flags: --max-turbolev-eager-inlined-bytecode-size=0 +// Flags: --trace-turbo-inlining --no-stress-concurrent-inlining +// Flags: --no-stress-maglev --no-optimize-on-next-call-optimizes-to-maglev + +d8.file.execute('test/mjsunit/mjsunit.js'); + +// Disabling eager inlining makes Maglev build the caller before the mutation +// below is introduced by the later Maglev inlining phase. Passing the rest +// array to a callee keeps it escaping during graph building, so argument +// forwarding must not be selected before that phase runs. + +function mutate(a) { + a[0] = 42; +} + +function join() { + return Array.prototype.join.call(arguments, '|'); +} + +function spreadAfterLateInlinedMutation(...r) { + mutate(r); + return join(...r); +} + +%PrepareFunctionForOptimization(mutate); +%PrepareFunctionForOptimization(spreadAfterLateInlinedMutation); + +assertEquals('42|2|3', spreadAfterLateInlinedMutation(1, 2, 3)); +assertEquals('42|2|3', spreadAfterLateInlinedMutation(1, 2, 3)); + +// CHECK-LABEL: TestLateInlinedMutation +print('TestLateInlinedMutation'); +%OptimizeFunctionOnNextCall(spreadAfterLateInlinedMutation); +assertEquals('42|2|3', spreadAfterLateInlinedMutation(1, 2, 3)); +// ANSI color escapes separate the decision from the function name. +// CHECK: INLINE{{.*}}mutate +assertOptimized(spreadAfterLateInlinedMutation); diff --git a/deps/v8/test/filecheck/wasm-turbolev-inlined-wrapper.js b/deps/v8/test/filecheck/wasm-turbolev-inlined-wrapper.js index 9e6be68a714d..8c6326ec4fe7 100644 --- a/deps/v8/test/filecheck/wasm-turbolev-inlined-wrapper.js +++ b/deps/v8/test/filecheck/wasm-turbolev-inlined-wrapper.js @@ -6,6 +6,9 @@ // Flags: --allow-natives-syntax // Flags: --trace-turbo-filter=jsFunc --trace-turbo-graph --no-stress-maglev // Flags: --no-turbolev-non-eager-loop-peeling +// Disable LoadElimination verification since it re-emits eliminated loads in +// the loop body to assert equality with their replacement. +// Flags: --no-verify-turboshaft d8.file.execute("test/mjsunit/mjsunit.js"); d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); @@ -41,13 +44,15 @@ m.val.value = 1000; jsFunc(); assertEquals(0, m.val.value); -// Expectation: In the TurboshaftMemoryOptimization phase there is a call to a -// wasm function whose output directly goes into the branch instruction needed -// for the loop. There is no other usage of the DidntThrow output of the wasm -// call. +// Expectation: In the TurboshaftMemoryOptimization phase all wrapper loads are +// hoisted/eliminated by GVN across loop peeling, so inside the loop there is +// directly a call to the wasm function whose output goes into the branch +// instruction needed for the loop. There is no other usage of the DidntThrow +// output of the wasm call. // CHECK-LABEL: ----- V8.TFTurboshaftMemoryOptimization ----- // CHECK: LOOP B{{[0-9]+}} +// CHECK-NOT: Load // CHECK: [[Call:[0-9]+]]: Call{{.*}}WasmFunctionIndirect // CHECK: [[DidntThrow:[0-9]+]]: DidntThrow(#[[Call]]) // CHECK-NEXT: Branch(#[[DidntThrow]]) diff --git a/deps/v8/test/filecheck/wasm/turbofan-extern-convert-any-static.js b/deps/v8/test/filecheck/wasm/turbofan-extern-convert-any-static.js index b37dc6b729ec..6e8e1e9c97a7 100644 --- a/deps/v8/test/filecheck/wasm/turbofan-extern-convert-any-static.js +++ b/deps/v8/test/filecheck/wasm/turbofan-extern-convert-any-static.js @@ -21,6 +21,9 @@ let instance = builder.instantiate(); // CHECK-LABEL: V8.TFTurboshaftWasmDeadCodeElimination // CHECK: MERGE B0 // CHECK-NEXT: 0: Parameter()[1] -// CHECK-NEXT: 1: Constant()[word32: 0] -// CHECK-NEXT: 2: Return(#1, #0)[0] +// TODO(jkummerow): Implement type-based optimizations for ExternConvertAny +// and rephrase this test (using an input type that's statically guaranteed +// not to be a Custom Descriptor) so that it will again emit the following IR: +// CHECK-NEXT-disabled: 1: Constant()[word32: 0] +// CHECK-NEXT-disabled: 2: Return(#1, #0) instance.exports.externConvertAny(); diff --git a/deps/v8/test/fuzzer/multi-return.cc b/deps/v8/test/fuzzer/multi-return.cc index d232ff2db2da..9d34041dd607 100644 --- a/deps/v8/test/fuzzer/multi-return.cc +++ b/deps/v8/test/fuzzer/multi-return.cc @@ -246,8 +246,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { } callee.Return(static_cast<int>(desc->ReturnCount()), returns.get()); - OptimizedCompilationInfo info(base::ArrayVector("testing"), &zone, - CodeKind::WASM_FUNCTION); + OptimizedCompilationInfo info("testing", &zone, CodeKind::WASM_FUNCTION); wasm::WasmCompilationResult wasm_result = Pipeline::GenerateWasmCodeForTesting( &info, i_isolate, desc, callee.graph(), @@ -299,7 +298,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { caller.Return(ret); // Call the wrapper. - OptimizedCompilationInfo wrapper_info(base::ArrayVector("wrapper"), &zone, + OptimizedCompilationInfo wrapper_info("wrapper", &zone, CodeKind::FOR_TESTING); DirectHandle<Code> wrapper_code = Pipeline::GenerateCodeForTesting( diff --git a/deps/v8/test/fuzzer/wasm/async.cc b/deps/v8/test/fuzzer/wasm/async.cc index c145a098009b..352da61127c0 100644 --- a/deps/v8/test/fuzzer/wasm/async.cc +++ b/deps/v8/test/fuzzer/wasm/async.cc @@ -10,6 +10,7 @@ #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" +#include "src/base/unique-array.h" #include "src/execution/isolate-inl.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-module.h" @@ -84,7 +85,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { bool done = false; auto enabled_features = WasmEnabledFeatures::FromIsolate(i_isolate); constexpr const char* kAPIMethodName = "WasmAsyncFuzzer.compile"; - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(data, size); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(data, size); std::shared_ptr<AsyncFuzzerResolver> resolver = std::make_shared<AsyncFuzzerResolver>(i_isolate, &done); GetWasmEngine()->AsyncCompile(i_isolate, enabled_features, diff --git a/deps/v8/test/fuzzer/wasm/code.cc b/deps/v8/test/fuzzer/wasm/code.cc index 32b77cf24835..1f42cce278a8 100644 --- a/deps/v8/test/fuzzer/wasm/code.cc +++ b/deps/v8/test/fuzzer/wasm/code.cc @@ -22,7 +22,7 @@ class WasmCodeFuzzer : public WasmExecutionFuzzer { WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii()); f->EmitCode(data.begin(), static_cast<uint32_t>(data.size())); f->Emit(kExprEnd); - builder.AddExport(base::CStrVector("main"), f); + builder.AddExport("main", f); builder.AddMemory(0, 32); builder.WriteTo(buffer); diff --git a/deps/v8/test/fuzzer/wasm/deopt.cc b/deps/v8/test/fuzzer/wasm/deopt.cc index 104b5153157a..36bd8705fe44 100644 --- a/deps/v8/test/fuzzer/wasm/deopt.cc +++ b/deps/v8/test/fuzzer/wasm/deopt.cc @@ -6,6 +6,7 @@ #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/execution/isolate.h" #include "src/objects/property-descriptor.h" @@ -273,7 +274,7 @@ int FuzzIt(base::Vector<const uint8_t> data) { // optimizing an inner wasm function, there can be a large amount of // parameters and returns with all kinds of types. const bool optimize_main_function = - inlinees.empty() || data.empty() || !(data.last() & 1); + inlinees.empty() || data.empty() || !(data.back() & 1); #if defined(DEBUG) && defined(V8_USE_ADDRESS_SANITIZER) // Disable register allocator verification on slow builds (Debug + ASan) to // avoid timeouts in TurboFan/Turboshaft compilation on pathological inputs @@ -283,7 +284,7 @@ int FuzzIt(base::Vector<const uint8_t> data) { // TurboFan compilation (see crbug.com/520317061). const bool assert_types = false; #else - const bool assert_types = !data.empty() && (data.last() & 2); + const bool assert_types = !data.empty() && (data.back() & 2); #endif FlagScope<bool> assert_types_scope(&v8_flags.wasm_assert_types, assert_types); @@ -324,7 +325,7 @@ int FuzzIt(base::Vector<const uint8_t> data) { ErrorThrower thrower(i_isolate, "WasmFuzzerSyncCompile"); MaybeDirectHandle<WasmModuleObject> compiled = GetWasmEngine()->SyncCompile( i_isolate, enabled_features, CompileTimeImportsForFuzzing(), &thrower, - base::OwnedCopyOf(buffer)); + base::UniqueCopyOf(buffer)); if (!valid) { FATAL("Generated module should validate, but got: %s\n", thrower.error_msg()); @@ -333,9 +334,11 @@ int FuzzIt(base::Vector<const uint8_t> data) { std::vector<ExecutionResult> reference_results = PerformReferenceRun( callees, wire_bytes, enabled_features, valid, i_isolate); - if (reference_results.empty()) { - // If the first run already included non-determinism, there isn't any value - // in even compiling it (as this fuzzer focuses on executing deopts). + if (reference_results.size() < 2) { + // If the first run already included non-determinism or aborted before + // executing at least 2 callees (e.g. due to reaching max steps or stack + // overflow), there isn't any value in compiling it as we need at least 2 + // callees to trigger a deopt. // Return -1 to not add this case to the corpus. return -1; } diff --git a/deps/v8/test/fuzzer/wasm/init-expr.cc b/deps/v8/test/fuzzer/wasm/init-expr.cc index cbeeb62c1050..5867f28f9e92 100644 --- a/deps/v8/test/fuzzer/wasm/init-expr.cc +++ b/deps/v8/test/fuzzer/wasm/init-expr.cc @@ -6,6 +6,7 @@ #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/execution/isolate.h" #include "src/objects/property-descriptor.h" @@ -111,7 +112,7 @@ void FuzzIt(base::Vector<const uint8_t> data) { MaybeDirectHandle<WasmModuleObject> compiled_module = GetWasmEngine()->SyncCompile(i_isolate, enabled_features, CompileTimeImportsForFuzzing(), &thrower, - base::OwnedCopyOf(bytes)); + base::UniqueCopyOf(bytes)); CHECK(!compiled_module.is_null()); CHECK(!thrower.error()); thrower.Reset(); diff --git a/deps/v8/test/fuzzer/wasm/interpreter/fast-interpreter.cc b/deps/v8/test/fuzzer/wasm/interpreter/fast-interpreter.cc index ec7091bca6c9..aacc189894c0 100644 --- a/deps/v8/test/fuzzer/wasm/interpreter/fast-interpreter.cc +++ b/deps/v8/test/fuzzer/wasm/interpreter/fast-interpreter.cc @@ -4,6 +4,7 @@ #include "include/v8-context.h" #include "include/v8-isolate.h" +#include "src/base/unique-array.h" #include "src/execution/isolate-inl.h" #include "src/wasm/fuzzing/random-module-generation.h" #include "src/wasm/wasm-engine.h" @@ -54,7 +55,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { GetWasmEngine() ->SyncCompile(i_isolate, enabled_features, CompileTimeImports{}, &thrower, - v8::base::OwnedCopyOf(wire_bytes.module_bytes())) + v8::base::UniqueCopyOf(wire_bytes.module_bytes())) .ToHandle(&module_object); // TODO(338326645): Add similar GenerateTestCase code for wasm fast // interpreter. diff --git a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-code.cc b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-code.cc index 3d29c2ea6895..d23602ca8eb4 100644 --- a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-code.cc +++ b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-code.cc @@ -18,7 +18,7 @@ bool GenerateModule(Isolate* isolate, Zone* zone, WasmFunctionBuilder* f = builder.AddFunction(&sig_i_iii); f->EmitCode(data.begin(), static_cast<uint32_t>(data.size())); f->Emit(kExprEnd); - builder.AddExport(base::CStrVector("main"), f); + builder.AddExport("main", f); builder.AddMemory(0, 32); builder.WriteTo(buffer); diff --git a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-diff.cc b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-diff.cc index da4d43aee657..6636bd05f72a 100644 --- a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-diff.cc +++ b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-diff.cc @@ -11,6 +11,7 @@ #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" +#include "src/base/unique-array.h" #include "src/execution/isolate-inl.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-module.h" @@ -68,7 +69,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { GetWasmEngine() ->SyncCompile(i_isolate, enabled_features, fuzzing::CompileTimeImportsForFuzzing(), &thrower, - v8::base::OwnedCopyOf(wire_bytes.module_bytes())) + v8::base::UniqueCopyOf(wire_bytes.module_bytes())) .ToHandle(&module_object); if (v8_flags.wasm_fuzzer_gen_test) { diff --git a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-fuzzer-common.cc b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-fuzzer-common.cc index 5a02b24f6d03..f8c8cf0ab04c 100644 --- a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-fuzzer-common.cc +++ b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-fuzzer-common.cc @@ -13,6 +13,7 @@ #include "include/v8-local-handle.h" #include "include/v8-metrics.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/execution/isolate.h" #include "src/objects/managed-inl.h" #include "src/objects/objects-inl.h" @@ -215,7 +216,7 @@ Handle<String> ExtractUtf8StringFromModuleBytes( base::Vector<const uint8_t> name_vec = wire_bytes.SubVector(ref.offset(), ref.end_offset()); return isolate->factory()->InternalizeUtf8String( - base::Vector<const char>::cast(name_vec)); + {reinterpret_cast<const char*>(name_vec.begin()), name_vec.size()}); } Handle<JSObject> CreateImportObjectInternal( @@ -604,7 +605,7 @@ int LLVMFuzzerTestOneInputCommon(const uint8_t* data, size_t size, bool compiles = wasm::GetWasmEngine() ->SyncCompile(i_isolate, enabled_features, fuzzing::CompileTimeImportsForFuzzing(), - &thrower, v8::base::OwnedCopyOf(buffer)) + &thrower, v8::base::UniqueCopyOf(buffer)) .ToHandle(&module_object); // TODO(338326645): add similar GenerateTestCase code for wasm fast // interpreter. @@ -679,13 +680,13 @@ int LLVMFuzzerTestTwoModulesCommon( bool compiles = wasm::GetWasmEngine() ->SyncCompile(i_isolate, enabled_features, fuzzing::CompileTimeImportsForFuzzing(), - &thrower, v8::base::OwnedCopyOf(buffer_2)) + &thrower, v8::base::UniqueCopyOf(buffer_2)) .ToHandle(&module_object); DirectHandle<WasmModuleObject> other_module_object; bool compiles_2 = wasm::GetWasmEngine() ->SyncCompile(i_isolate, enabled_features, fuzzing::CompileTimeImportsForFuzzing(), - &thrower, v8::base::OwnedCopyOf(buffer)) + &thrower, v8::base::UniqueCopyOf(buffer)) .ToHandle(&other_module_object); int execute_module_result = -1; if (compiles && compiles_2) { diff --git a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-init-expr.cc b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-init-expr.cc index 126180d57fac..649414dc4294 100644 --- a/deps/v8/test/fuzzer/wasm/interpreter/interpreter-init-expr.cc +++ b/deps/v8/test/fuzzer/wasm/interpreter/interpreter-init-expr.cc @@ -6,6 +6,7 @@ #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/execution/isolate.h" #include "src/objects/property-descriptor.h" @@ -261,7 +262,7 @@ void FuzzIt(base::Vector<const uint8_t> data) { MaybeDirectHandle<WasmModuleObject> compiled_module = GetWasmEngine()->SyncCompile(i_isolate, enabled_features, CompileTimeImportsForFuzzing(), &thrower, - base::OwnedCopyOf(bytes)); + base::UniqueCopyOf(bytes)); CHECK(!compiled_module.is_null()); CHECK(!thrower.error()); thrower.Reset(); diff --git a/deps/v8/test/fuzzer/wasm/module.cc b/deps/v8/test/fuzzer/wasm/module.cc index 01306b7f9e44..bc66230459f5 100644 --- a/deps/v8/test/fuzzer/wasm/module.cc +++ b/deps/v8/test/fuzzer/wasm/module.cc @@ -11,6 +11,7 @@ #include "include/v8-exception.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" +#include "src/base/unique-array.h" #include "src/execution/isolate-inl.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-module.h" @@ -75,7 +76,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { GetWasmEngine() ->SyncCompile(i_isolate, enabled_features, CompileTimeImportsForFuzzing(), &thrower, - base::OwnedCopyOf(wire_bytes.module_bytes())) + base::UniqueCopyOf(wire_bytes.module_bytes())) .ToHandle(&module_object); if (v8_flags.wasm_fuzzer_gen_test) { diff --git a/deps/v8/test/fuzzer/wasm/streaming.cc b/deps/v8/test/fuzzer/wasm/streaming.cc index a5291afd28b4..2b49c0be60f6 100644 --- a/deps/v8/test/fuzzer/wasm/streaming.cc +++ b/deps/v8/test/fuzzer/wasm/streaming.cc @@ -7,6 +7,7 @@ #include "include/v8-isolate.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/flags/flags.h" #include "src/objects/managed.h" #include "src/wasm/streaming-decoder.h" @@ -123,6 +124,10 @@ CompilationResult CompileStreaming(v8_fuzzer::FuzzerSupport* support, // cache, but we have to be careful not to break other internal assumptions // then (because we have several identical modules / scripts). while (weak_native_module.lock()) { + // We need to invoke GC without stack, otherwise the native module may + // survive. + DisableConservativeStackScanningScopeForTesting no_stack_scanning( + i_isolate->heap()); isolate->RequestGarbageCollectionForTesting( v8::Isolate::kFullGarbageCollection); } @@ -137,7 +142,7 @@ CompilationResult CompileSync(Isolate* isolate, CompilationResult result; if (!GetWasmEngine() ->SyncCompile(isolate, enabled_features, CompileTimeImports{}, - &thrower, base::OwnedCopyOf(data)) + &thrower, base::UniqueCopyOf(data)) .ToHandle(&module_object)) { DirectHandle<Object> error = thrower.Reify(); DirectHandle<String> error_msg = diff --git a/deps/v8/test/inspector/console/enable-with-stored-exception-expected.txt b/deps/v8/test/inspector/console/enable-with-stored-exception-expected.txt new file mode 100644 index 000000000000..a74924903495 --- /dev/null +++ b/deps/v8/test/inspector/console/enable-with-stored-exception-expected.txt @@ -0,0 +1,9 @@ +Checks that Console.enable skips stored exceptions. +Storing messages while both domains are disabled. +Enabling Console. +Console: before exception +Console: after exception +Logging a live console message. +Console: live message +Enabling Runtime. +Runtime exception: Uncaught Error: stored exception diff --git a/deps/v8/test/inspector/console/enable-with-stored-exception.js b/deps/v8/test/inspector/console/enable-with-stored-exception.js new file mode 100644 index 000000000000..7eab2827f526 --- /dev/null +++ b/deps/v8/test/inspector/console/enable-with-stored-exception.js @@ -0,0 +1,35 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = + InspectorTest.start('Checks that Console.enable skips stored exceptions.'); + +Protocol.Console.onMessageAdded(({params}) => { + InspectorTest.log(`Console: ${params.message.text}`); +}); +Protocol.Runtime.onExceptionThrown(({params}) => { + InspectorTest.log(`Runtime exception: ${params.exceptionDetails.text}`); +}); + +(async function test() { + InspectorTest.log('Storing messages while both domains are disabled.'); + // Use a script so the exception is reported as uncaught. + contextGroup.addScript(` + console.log('before exception'); + throw new Error('stored exception'); + `); + await Protocol.Runtime.evaluate( + {expression: `console.log('after exception')`}); + + InspectorTest.log('Enabling Console.'); + await Protocol.Console.enable(); + + InspectorTest.log('Logging a live console message.'); + await Protocol.Runtime.evaluate({expression: `console.log('live message')`}); + + // Console must leave the stored exception available to Runtime. + InspectorTest.log('Enabling Runtime.'); + await Protocol.Runtime.enable(); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/class-fields-scopes-expected.txt b/deps/v8/test/inspector/debugger/class-fields-scopes-expected.txt index a5b131ed3c0b..09d043a71719 100644 --- a/deps/v8/test/inspector/debugger/class-fields-scopes-expected.txt +++ b/deps/v8/test/inspector/debugger/class-fields-scopes-expected.txt @@ -18,7 +18,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 3 lineNumber : 5 @@ -92,10 +92,10 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { - columnNumber : 13 - lineNumber : 14 + columnNumber : 3 + lineNumber : 15 scriptId : <scriptId> } name : run @@ -106,11 +106,11 @@ Running test: testScopesPaused type : object } startLocation : { - columnNumber : 4 - lineNumber : 12 + columnNumber : 2 + lineNumber : 11 scriptId : <scriptId> } - type : local + type : block } [1] : { endLocation : { @@ -201,7 +201,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 13 lineNumber : 14 @@ -222,6 +222,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -241,7 +262,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -275,7 +296,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 2 lineNumber : 11 @@ -296,6 +317,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -315,7 +357,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -437,7 +479,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 13 lineNumber : 14 @@ -458,6 +500,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -477,7 +540,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -511,7 +574,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 2 lineNumber : 11 @@ -532,6 +595,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -551,7 +635,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -673,7 +757,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 13 lineNumber : 14 @@ -694,6 +778,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -713,7 +818,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -747,7 +852,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 2 lineNumber : 11 @@ -768,6 +873,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -787,7 +913,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -909,7 +1035,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 3 lineNumber : 9 @@ -983,7 +1109,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 13 lineNumber : 14 @@ -1004,6 +1130,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -1023,7 +1170,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global @@ -1057,7 +1204,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 2 lineNumber : 11 @@ -1078,6 +1225,27 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 15 + scriptId : <scriptId> + } + name : run + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 11 + scriptId : <scriptId> + } + type : block + } + [2] : { endLocation : { columnNumber : 1 lineNumber : 19 @@ -1097,7 +1265,7 @@ Running test: testScopesPaused } type : closure } - [2] : { + [3] : { object : { className : global description : global diff --git a/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt b/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt index 6dbacb6705b4..6e541edbb069 100644 --- a/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt +++ b/deps/v8/test/inspector/debugger/class-private-fields-scopes-expected.txt @@ -18,7 +18,7 @@ Running test: testScopesPaused } scopeChain : [ [0] : { - empty : true + emptyReason : no-variables endLocation : { columnNumber : 5 lineNumber : 6 @@ -39,6 +39,46 @@ Running test: testScopesPaused type : local } [1] : { + emptyReason : no-variables + endLocation : { + columnNumber : 3 + lineNumber : 7 + scriptId : <scriptId> + } + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 2 + lineNumber : 2 + scriptId : <scriptId> + } + type : block + } + [2] : { + emptyReason : all-unavailable + endLocation : { + columnNumber : 1 + lineNumber : 9 + scriptId : <scriptId> + } + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 12 + lineNumber : 1 + scriptId : <scriptId> + } + type : closure + } + [3] : { object : { className : global description : global diff --git a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-module-expected.txt b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-module-expected.txt index 78f2adb412b0..51dfc28a0198 100644 --- a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-module-expected.txt +++ b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-module-expected.txt @@ -12,8 +12,9 @@ local:foo1 module [ [0] : a1 = 10 - [1] : b1 = 11 - [2] : foo1 = function foo1() { let c1 = 12; let g1 = 2; debugger; return a1 + b1 + c1 + g1; } + [1] : g1 + [2] : b1 = 11 + [3] : foo1 = function foo1() { let c1 = 12; let g1 = 2; debugger; return a1 + b1 + c1 + g1; } ] global [ @@ -100,8 +101,8 @@ local:foo2 ] module [ - [0] : a2 = 20 - [1] : foo1 = function foo1() { let c1 = 12; let g1 = 2; debugger; return a1 + b1 + c1 + g1; } + [0] : foo1 = function foo1() { let c1 = 12; let g1 = 2; debugger; return a1 + b1 + c1 + g1; } + [1] : a2 = 20 [2] : b2 = 21 [3] : foo2 = function foo2() { let c2 = 22; return foo1() + a2 + b2 + c2; } ] @@ -135,6 +136,13 @@ updated c2 = value : 23 } Evaluating: --c2 +foo1 = +{ + className : Function + description : function foo1() { let c1 = 12; let g1 = 2; debugger; return a1 + b1 + c1 + g1; } + objectId : <objectId> + type : function +} a2 = { description : 20 @@ -149,13 +157,6 @@ updated a2 = value : 21 } Evaluating: --a2 -foo1 = -{ - className : Function - description : function foo1() { let c1 = 12; let g1 = 2; debugger; return a1 + b1 + c1 + g1; } - objectId : <objectId> - type : function -} b2 = { description : 21 @@ -246,6 +247,12 @@ closure:bar [ [0] : a = 0 ] +module +[ + [0] : a + [1] : b + [2] : bar +] global [ ... @@ -280,6 +287,12 @@ local:bar [ [0] : a = 0 ] +module +[ + [0] : a + [1] : b + [2] : bar +] global [ ... diff --git a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope-expected.txt b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope-expected.txt new file mode 100644 index 000000000000..d77156aca4b8 --- /dev/null +++ b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope-expected.txt @@ -0,0 +1,16 @@ +Checks that evaluating on a call frame paused inside a with statement, whose subject is a proxy with a throwing trap, surfaces the trap error instead of leaving an exception pending while Context::Lookup keeps walking the context chain. + +Running test: testEvaluateOnCallFrameInWithScopeThrowingProxy +Side-effect-free Debugger.evaluateOnCallFrame of foo: +Threw: Error: error from the trap + at Object.getOwnPropertyDescriptor (<anonymous>:2:48) + at eval (eval at runWith (:1:34), <anonymous>:1:1) + at runWith (<anonymous>:1:34) + at <anonymous>:2:1 + +Regular Debugger.evaluateOnCallFrame of foo: +Threw: Error: error from the trap + at Object.getOwnPropertyDescriptor (<anonymous>:2:48) + at eval (eval at runWith (:1:34), <anonymous>:1:1) + at runWith (<anonymous>:1:34) + at <anonymous>:2:1 diff --git a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope.js b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope.js new file mode 100644 index 000000000000..ee95aae7067e --- /dev/null +++ b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-in-throwing-with-scope.js @@ -0,0 +1,53 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that evaluating on a call frame paused inside a with statement, ' + + 'whose subject is a proxy with a throwing trap, surfaces the trap error ' + + 'instead of leaving an exception pending while Context::Lookup keeps ' + + 'walking the context chain.'); + +function logEvaluateResult(response) { + const {result, exceptionDetails} = response.result; + if (exceptionDetails) { + InspectorTest.log('Threw: ' + exceptionDetails.exception.description); + } else { + InspectorTest.log('Result: ' + result.value); + } +} + +InspectorTest.runAsyncTestSuite([ + async function testEvaluateOnCallFrameInWithScopeThrowingProxy() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + + // The debug-evaluate context looks up the wrapped with-context with + // DONT_FOLLOW_CHAINS, which queries own-property attributes rather than + // going through the `has` trap. So getOwnPropertyDescriptor is the trap + // reached here. + await Protocol.Runtime.evaluate({ + expression: `globalThis.p = new Proxy({}, { + getOwnPropertyDescriptor(t, k) { throw new Error('error from the trap'); } + });` + }); + + Protocol.Runtime.evaluate({ + expression: 'function runWith(o) { with (o) { debugger; } }\n' + + 'runWith(globalThis.p);' + }); + const {params: {callFrames: [{callFrameId}]}} = + await Protocol.Debugger.oncePaused(); + + InspectorTest.log('Side-effect-free Debugger.evaluateOnCallFrame of foo:'); + logEvaluateResult(await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId, expression: 'foo', throwOnSideEffect: true})); + + InspectorTest.log('\nRegular Debugger.evaluateOnCallFrame of foo:'); + logEvaluateResult(await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId, expression: 'foo'})); + + await Protocol.Debugger.resume(); + await Protocol.Debugger.disable(); + }, +]); diff --git a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-conflict-expected.txt b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-conflict-expected.txt index 5b406d0a4d49..1897244f8b50 100644 --- a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-conflict-expected.txt +++ b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-conflict-expected.txt @@ -19,6 +19,14 @@ class StaticClass extends Klass { debugger; Running test: evaluatePrivateMembers +Debugger.evaluateOnCallFrame: `#name in (new ClassWithField)` +{ + className : Error + description : Error: Operation is ambiguous because there are more than one private name'#name' on the object at eval (eval at <anonymous> (:18:1), <anonymous>:1:11) at <anonymous>:18:1 + objectId : <objectId> + subtype : error + type : object +} Debugger.evaluateOnCallFrame: `(new ClassWithField).#name` { className : Error @@ -27,6 +35,14 @@ Debugger.evaluateOnCallFrame: `(new ClassWithField).#name` subtype : error type : object } +Debugger.evaluateOnCallFrame: `#name in (new ClassWithMethod)` +{ + className : Error + description : Error: Operation is ambiguous because there are more than one private name'#name' on the object at eval (eval at <anonymous> (:18:1), <anonymous>:1:11) at <anonymous>:18:1 + objectId : <objectId> + subtype : error + type : object +} Debugger.evaluateOnCallFrame: `(new ClassWithMethod).#name` { className : Error @@ -35,6 +51,14 @@ Debugger.evaluateOnCallFrame: `(new ClassWithMethod).#name` subtype : error type : object } +Debugger.evaluateOnCallFrame: `#name in (new ClassWithAccessor)` +{ + className : Error + description : Error: Operation is ambiguous because there are more than one private name'#name' on the object at eval (eval at <anonymous> (:18:1), <anonymous>:1:11) at <anonymous>:18:1 + objectId : <objectId> + subtype : error + type : object +} Debugger.evaluateOnCallFrame: `(new ClassWithAccessor).#name` { className : Error @@ -43,11 +67,21 @@ Debugger.evaluateOnCallFrame: `(new ClassWithAccessor).#name` subtype : error type : object } +Debugger.evaluateOnCallFrame: `#name in StaticClass` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `StaticClass.#name` { type : string value : child } +Debugger.evaluateOnCallFrame: `#name in (new StaticClass)` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `(new StaticClass).#name` { type : string diff --git a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-expected.txt b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-expected.txt index 651306c9cdb2..a70829b445a4 100644 --- a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-expected.txt +++ b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-expected.txt @@ -13,6 +13,24 @@ debugger; Running test: evaluatePrivateMembers Checking private fields +Debugger.evaluateOnCallFrame: `#field in obj` +{ + type : boolean + value : true +} +Debugger.evaluateOnCallFrame: `#nonExistent in obj` +{ + type : boolean + value : false +} +Debugger.evaluateOnCallFrame: `#field in 1` +{ + className : TypeError + description : TypeError: Cannot use 'in' operator to search for '#field' in 1 at eval (eval at <anonymous> (:11:1), <anonymous>:1:11) at <anonymous>:11:1 + objectId : <objectId> + subtype : error + type : object +} Debugger.evaluateOnCallFrame: `obj.#field` { type : string @@ -67,6 +85,11 @@ Debugger.evaluateOnCallFrame: `obj.#field` value : 0 } Checking private getter-only accessors +Debugger.evaluateOnCallFrame: `#getterOnly in obj` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `obj.#getterOnly` { type : string @@ -102,6 +125,11 @@ Debugger.evaluateOnCallFrame: `obj.#getterOnly` value : getterOnly } Checking private setter-only accessors +Debugger.evaluateOnCallFrame: `#setterOnly in obj` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `obj.#setterOnly` { className : Error @@ -138,6 +166,11 @@ Debugger.evaluateOnCallFrame: `obj.#field` value : setterOnlyCalled } Checking private accessors +Debugger.evaluateOnCallFrame: `#accessor in obj` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `obj.#accessor` { type : string @@ -190,6 +223,11 @@ Debugger.evaluateOnCallFrame: `obj.#field` value : 0 } Checking private methods +Debugger.evaluateOnCallFrame: `#method in obj` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `obj.#method` { className : Function diff --git a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-static-expected.txt b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-static-expected.txt index 28122d3999f6..76648c124b02 100644 --- a/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-static-expected.txt +++ b/deps/v8/test/inspector/debugger/evaluate-on-call-frame-private-class-member-static-expected.txt @@ -13,6 +13,24 @@ debugger; Running test: evaluatePrivateMembers Checking private fields +Debugger.evaluateOnCallFrame: `#field in Klass` +{ + type : boolean + value : true +} +Debugger.evaluateOnCallFrame: `#nonExistent in Klass` +{ + type : boolean + value : false +} +Debugger.evaluateOnCallFrame: `#field in 1` +{ + className : TypeError + description : TypeError: Cannot use 'in' operator to search for '#field' in 1 at eval (eval at <anonymous> (:11:1), <anonymous>:1:11) at <anonymous>:11:1 + objectId : <objectId> + subtype : error + type : object +} Debugger.evaluateOnCallFrame: `Klass.#field` { type : string @@ -67,6 +85,11 @@ Debugger.evaluateOnCallFrame: `Klass.#field` value : 0 } Checking private getter-only accessors +Debugger.evaluateOnCallFrame: `#getterOnly in Klass` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `Klass.#getterOnly` { type : string @@ -102,6 +125,11 @@ Debugger.evaluateOnCallFrame: `Klass.#getterOnly` value : getterOnly } Checking private setter-only accessors +Debugger.evaluateOnCallFrame: `#setterOnly in Klass` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `Klass.#setterOnly` { className : Error @@ -138,6 +166,11 @@ Debugger.evaluateOnCallFrame: `Klass.#field` value : setterOnlyCalled } Checking private accessors +Debugger.evaluateOnCallFrame: `#accessor in Klass` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `Klass.#accessor` { type : string @@ -190,6 +223,11 @@ Debugger.evaluateOnCallFrame: `Klass.#field` value : 0 } Checking private methods +Debugger.evaluateOnCallFrame: `#method in Klass` +{ + type : boolean + value : true +} Debugger.evaluateOnCallFrame: `Klass.#method` { className : Function diff --git a/deps/v8/test/inspector/debugger/function-constructor-anonymous-scopes-expected.txt b/deps/v8/test/inspector/debugger/function-constructor-anonymous-scopes-expected.txt index 06cf6e1aefc1..543f27bf3832 100644 --- a/deps/v8/test/inspector/debugger/function-constructor-anonymous-scopes-expected.txt +++ b/deps/v8/test/inspector/debugger/function-constructor-anonymous-scopes-expected.txt @@ -10,4 +10,5 @@ Paused in '': Running test: testNested Paused in 'inner': [0] local: + [1] closure: a anonymous = string: global anonymous diff --git a/deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate-expected.txt b/deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate-expected.txt new file mode 100644 index 000000000000..f86c21b6cbb1 --- /dev/null +++ b/deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate-expected.txt @@ -0,0 +1,19 @@ +Tests import.meta in lazy functions during module debug-evaluate. +{ + id : <messageId> + result : { + result : { + type : boolean + value : true + } + } +} +{ + id : <messageId> + result : { + result : { + type : string + value : SyntaxError + } + } +} diff --git a/deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate.js b/deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate.js new file mode 100644 index 000000000000..a6c27642d146 --- /dev/null +++ b/deps/v8/test/inspector/debugger/modules-import-meta-debug-evaluate.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests import.meta in lazy functions during module debug-evaluate.'); + +const moduleSource = ` +let evaluateResult; +function runEval() { + (() => eval('let h = () => import.meta; h()'))(); +} +debugger; +try { + runEval(); + globalThis.evalResult = 'did not throw'; +} catch (e) { + globalThis.evalResult = e.name; +} +`; + +(async function test() { + await Protocol.Debugger.enable(); + contextGroup.addModule(moduleSource, 'module1'); + const {params: {callFrames}} = await Protocol.Debugger.oncePaused(); + const callFrameId = callFrames[0].callFrameId; + InspectorTest.logMessage(await Protocol.Debugger.evaluateOnCallFrame({ + callFrameId, + expression: 'let f = () => import.meta; let g = () => () => import.meta; ' + + 'f() === import.meta && g()() === import.meta', + returnByValue: true, + })); + await Protocol.Debugger.resume(); + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: 'globalThis.evalResult', + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/osr-debug-break-expected.txt b/deps/v8/test/inspector/debugger/osr-debug-break-expected.txt new file mode 100644 index 000000000000..9c414de1df1f --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-debug-break-expected.txt @@ -0,0 +1,3 @@ +Tests that OSR topmost frame is deoptimized after debugger break +Paused on debugger statement +isTopFrameTurboFanned: false diff --git a/deps/v8/test/inspector/debugger/osr-debug-break.js b/deps/v8/test/inspector/debugger/osr-debug-break.js new file mode 100644 index 000000000000..e781518aef19 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-debug-break.js @@ -0,0 +1,53 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that OSR topmost frame is deoptimized after debugger break'); + +contextGroup.addScript( + ` +let top_frame_status_after_break = -1; +function check_deopt() { + eval(""); + top_frame_status_after_break = %GetOptimizationStatus(osr_top); +} +%NeverOptimizeFunction(check_deopt); + +function osr_top() { + for (let i = 0; i < 20; i++) { + if (i === 10) { + %OptimizeOsr(); + } + } + debugger; + check_deopt(); +} + +function run() { + %PrepareFunctionForOptimization(osr_top); + osr_top(); + // kTopmostFrameIsTurboFanned is bit 11 (1 << 11 = 2048) of + // GetOptimizationStatus. + const kTopmostFrameIsTurboFanned = 1 << 11; + const isTopFrameTurboFanned = + (top_frame_status_after_break & kTopmostFrameIsTurboFanned) !== 0; + return isTopFrameTurboFanned; +} +`, + 0, 0, 'test.js'); + +Protocol.Debugger.onPaused(async message => { + InspectorTest.log('Paused on debugger statement'); + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Debugger.enable(); + const result = await Protocol.Runtime.evaluate( + {expression: 'run()', returnByValue: true}); + InspectorTest.log('isTopFrameTurboFanned: ' + result.result.result.value); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/osr-step-in-blackboxed-expected.txt b/deps/v8/test/inspector/debugger/osr-step-in-blackboxed-expected.txt new file mode 100644 index 000000000000..a05e68e0625d --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-in-blackboxed-expected.txt @@ -0,0 +1,5 @@ +Tests stepping with blackboxing and inlining across OSR +Paused in: callee +Paused in: callee +Paused in: target +Target was paused: true diff --git a/deps/v8/test/inspector/debugger/osr-step-in-blackboxed.js b/deps/v8/test/inspector/debugger/osr-step-in-blackboxed.js new file mode 100644 index 000000000000..e55d4e6c4e79 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-in-blackboxed.js @@ -0,0 +1,61 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests stepping with blackboxing and inlining across OSR'); + +contextGroup.addScript( + `function target() { + return 1; +} + +function callee() { + eval(""); + debugger; +} +%NeverOptimizeFunction(callee); + +// Gather feedback for inlining +%PrepareFunctionForOptimization(target); +callee(); +target(); +callee(); +target(); +`, + 0, 0, 'target.js'); + +contextGroup.addScript( + `function osr_caller(osr) { + for (let i = 0; i < 20; i++) { + if (osr && i === 10) %OptimizeOsr(); + } + callee(); + target(); +} +%PrepareFunctionForOptimization(osr_caller); +osr_caller(false); +osr_caller(false); +`, + 0, 0, 'osr_caller.js'); + +Protocol.Debugger.enable(); +Protocol.Debugger.setBlackboxPatterns({patterns: ['osr_caller\\.js']}); + +Protocol.Debugger.onPaused(handlePaused); +Protocol.Runtime.evaluate({expression: 'osr_caller(true);'}); + +function handlePaused(message) { + const callFrames = message.params.callFrames; + const fnName = callFrames[0].functionName; + InspectorTest.log('Paused in: ' + fnName); + if (fnName === 'callee') { + Protocol.Debugger.stepInto(); + } else { + Protocol.Debugger.resume(); + InspectorTest.log('Target was paused: ' + (fnName === 'target')); + InspectorTest.completeTest(); + } +} diff --git a/deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed-expected.txt b/deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed-expected.txt new file mode 100644 index 000000000000..d047cb3e9363 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed-expected.txt @@ -0,0 +1,5 @@ +Tests step on throw across blackboxed OSR caller +Paused in: thrower +Paused in: thrower +Paused in: target +Target was paused: true diff --git a/deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed.js b/deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed.js new file mode 100644 index 000000000000..03cbd1e10507 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-on-throw-blackboxed.js @@ -0,0 +1,59 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +const {session, contextGroup, Protocol} = + InspectorTest.start('Tests step on throw across blackboxed OSR caller'); + +contextGroup.addScript( + `function target() { + return 1; +} + +function thrower() { + eval(""); + debugger; + throw new Error("test"); +} +%NeverOptimizeFunction(thrower); + +// Gather feedback for inlining +%PrepareFunctionForOptimization(target); +try { thrower(); } catch(e) { target(); } +try { thrower(); } catch(e) { target(); } +`, + 0, 0, 'target.js'); + +contextGroup.addScript( + `function osr_caller(osr) { + for (let i = 0; i < 20; i++) { + if (osr && i === 10) %OptimizeOsr(); + } + try { thrower(); } catch (e) { target(); } +} +%PrepareFunctionForOptimization(osr_caller); +osr_caller(false); +osr_caller(false); +`, + 0, 0, 'osr_caller.js'); + +Protocol.Debugger.enable(); +Protocol.Debugger.setBlackboxPatterns({patterns: ['osr_caller\\.js']}); + +Protocol.Debugger.onPaused(handlePaused); +Protocol.Runtime.evaluate({expression: 'osr_caller(true);'}); + +function handlePaused(message) { + const callFrames = message.params.callFrames; + const fnName = callFrames[0].functionName; + InspectorTest.log('Paused in: ' + fnName); + if (fnName === 'thrower') { + Protocol.Debugger.stepInto(); + } else { + Protocol.Debugger.resume(); + InspectorTest.log('Target was paused: ' + (fnName === 'target')); + InspectorTest.completeTest(); + } +} diff --git a/deps/v8/test/inspector/debugger/osr-step-on-throw-expected.txt b/deps/v8/test/inspector/debugger/osr-step-on-throw-expected.txt new file mode 100644 index 000000000000..74520045d741 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-on-throw-expected.txt @@ -0,0 +1,5 @@ +Tests step into on throw in OSR function +Paused in: thrower +Paused in: thrower +Paused in: osr_caller +Paused in: caught_target diff --git a/deps/v8/test/inspector/debugger/osr-step-on-throw.js b/deps/v8/test/inspector/debugger/osr-step-on-throw.js new file mode 100644 index 000000000000..14960788bdb5 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-on-throw.js @@ -0,0 +1,55 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +const {session, contextGroup, Protocol} = + InspectorTest.start('Tests step into on throw in OSR function'); + +contextGroup.addScript( + `function caught_target() { + eval(""); +} + +function thrower() { + eval(""); + debugger; + throw new Error("test"); +} + +%NeverOptimizeFunction(thrower); +%NeverOptimizeFunction(caught_target); + +function osr_caller() { + for (let i = 0; i < 20; i++) { + if (i === 10) { + %OptimizeOsr(); + } + } + try { + thrower(); + } catch (e) { + caught_target(); + } +} +%PrepareFunctionForOptimization(osr_caller); +`, + 0, 0, 'test.js'); + +Protocol.Debugger.enable(); + +Protocol.Debugger.onPaused(handlePaused); +Protocol.Runtime.evaluate({expression: 'osr_caller();'}); + +function handlePaused(message) { + const callFrames = message.params.callFrames; + const fnName = callFrames[0].functionName; + InspectorTest.log('Paused in: ' + fnName); + if (fnName !== 'caught_target') { + Protocol.Debugger.stepInto(); + } else { + Protocol.Debugger.resume(); + InspectorTest.completeTest(); + } +} diff --git a/deps/v8/test/inspector/debugger/osr-step-out-expected.txt b/deps/v8/test/inspector/debugger/osr-step-out-expected.txt new file mode 100644 index 000000000000..23f1b7ee8883 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-out-expected.txt @@ -0,0 +1,4 @@ +Tests stepping out of function called from OSR function +Paused in: foo +Paused in: osr_caller +Paused in: bar diff --git a/deps/v8/test/inspector/debugger/osr-step-out.js b/deps/v8/test/inspector/debugger/osr-step-out.js new file mode 100644 index 000000000000..92c804f8e336 --- /dev/null +++ b/deps/v8/test/inspector/debugger/osr-step-out.js @@ -0,0 +1,51 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests stepping out of function called from OSR function'); + +contextGroup.addScript( + `function bar() { + // Should pause here when stepping out of foo() from osr_caller() +} +%NeverOptimizeFunction(bar); + +function foo() { + debugger; +} +%NeverOptimizeFunction(foo); + +function osr_caller() { + for (let i = 0; i < 20; i++) { + if (i === 10) { + %OptimizeOsr(); + } + } + foo(); + bar(); +} +%PrepareFunctionForOptimization(osr_caller); +`, + 0, 0, 'test.js'); + +Protocol.Debugger.enable(); + +Protocol.Debugger.onPaused(handlePaused); +Protocol.Runtime.evaluate({expression: 'osr_caller();'}); + +function handlePaused(message) { + const callFrames = message.params.callFrames; + const fnName = callFrames[0].functionName; + InspectorTest.log('Paused in: ' + fnName); + if (fnName === 'foo') { + Protocol.Debugger.stepOut(); + } else if (fnName === 'osr_caller') { + Protocol.Debugger.stepInto(); + } else { + Protocol.Debugger.resume(); + InspectorTest.completeTest(); + } +} diff --git a/deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed-expected.txt b/deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed-expected.txt new file mode 100644 index 000000000000..508d2741c36c --- /dev/null +++ b/deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed-expected.txt @@ -0,0 +1,3 @@ +Tests that an OOM break pauses even if all frames are blackboxed +reason: OOM +Test finished normally. diff --git a/deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed.js b/deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed.js new file mode 100644 index 000000000000..322a1432a040 --- /dev/null +++ b/deps/v8/test/inspector/debugger/pause-on-oom-all-frames-blackboxed.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --max-old-space-size=16 --no-concurrent-recompilation + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that an OOM break pauses even if all frames are blackboxed'); + +Protocol.Debugger.onPaused(async message => { + InspectorTest.log(`reason: ${message.params.reason}`); + await Protocol.Debugger.evaluateOnCallFrame({ + callFrameId: message.params.callFrames[0].callFrameId, + expression: 'arr = []; stop = true;' + }); + Protocol.Debugger.resume(); +}); + +(async function test() { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setBlackboxPatterns({patterns: ['blackboxed']}); + + await Protocol.Runtime.evaluate({ + expression: ` + function f() { return 1; } + //# sourceURL=blackboxed-f.js` + }); + + // Both the loop and `f` are blackboxed, so the OOM interrupt fires with + // only blackboxed frames on the stack, either at the function-entry stack + // check of `f` or at the loop back-edge. + await Protocol.Runtime.evaluate({ + expression: ` + let arr = []; + let stop = false; + while (!stop) { + arr.push(1n << (4n * 1024n * 1024n)); + f(); + } + //# sourceURL=blackboxed-loop.js` + }); + + InspectorTest.log('Test finished normally.'); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed-expected.txt b/deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed-expected.txt new file mode 100644 index 000000000000..70f23d4aa05d --- /dev/null +++ b/deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed-expected.txt @@ -0,0 +1,3 @@ +Tests that an OOM break triggered at the entry of a blackboxed function with a non-blackboxed caller pauses +reason: OOM +Test finished normally. diff --git a/deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed.js b/deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed.js new file mode 100644 index 000000000000..54690339ffc4 --- /dev/null +++ b/deps/v8/test/inspector/debugger/pause-on-oom-in-blackboxed.js @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --max-old-space-size=16 --no-concurrent-recompilation + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that an OOM break triggered at the entry of a blackboxed function ' + + 'with a non-blackboxed caller pauses'); + +Protocol.Debugger.onPaused(async message => { + InspectorTest.log(`reason: ${message.params.reason}`); + await Protocol.Debugger.evaluateOnCallFrame({ + callFrameId: message.params.callFrames[0].callFrameId, + expression: 'arr = []; stop = true;' + }); + Protocol.Debugger.resume(); +}); + +(async function test() { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setBlackboxPatterns({patterns: ['blackboxed.js']}); + + await Protocol.Runtime.evaluate({ + expression: ` + function f() { return 1; } + //# sourceURL=blackboxed.js` + }); + + // The loop body only allocates before calling the blackboxed function, so + // the OOM interrupt requested by the near-heap-limit callback is likely to + // fire at the function-entry stack check of `f`. + await Protocol.Runtime.evaluate({ + expression: ` + let arr = []; + let stop = false; + while (!stop) { + arr.push(1n << (4n * 1024n * 1024n)); + f(); + } + //# sourceURL=test.js` + }); + + InspectorTest.log('Test finished normally.'); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/regress-blackbox-exact-start-expected.txt b/deps/v8/test/inspector/debugger/regress-blackbox-exact-start-expected.txt new file mode 100644 index 000000000000..ac71595ac6e5 --- /dev/null +++ b/deps/v8/test/inspector/debugger/regress-blackbox-exact-start-expected.txt @@ -0,0 +1,3 @@ +Tests that a blackboxed range includes its exact start boundary +Compiled script +Test completed diff --git a/deps/v8/test/inspector/debugger/regress-blackbox-exact-start.js b/deps/v8/test/inspector/debugger/regress-blackbox-exact-start.js new file mode 100644 index 000000000000..42e5986e8543 --- /dev/null +++ b/deps/v8/test/inspector/debugger/regress-blackbox-exact-start.js @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start('Tests that a blackboxed range includes its exact start boundary'); + +const scriptSource = `debugger;\n//# sourceURL=test-script.js`; + +Promise.all([ + Protocol.Debugger.enable(), + Protocol.Runtime.enable() +]).then(() => { + Protocol.Debugger.onPaused(message => { + let callFrame = message.params.callFrames[0]; + InspectorTest.log(`Paused in ${callFrame.functionName || '<top level>'}`); + Protocol.Debugger.resume(); + }); + + return Protocol.Runtime.compileScript({ + expression: scriptSource, + sourceURL: 'test-script.js', + persistScript: true + }); + }) + .then(response => { + let scriptId = response.result.scriptId; + InspectorTest.log(`Compiled script`); + return Protocol.Debugger.setBlackboxedRanges({ + scriptId: scriptId, + positions: [ { lineNumber: 0, columnNumber: 0 } ] + }).then(() => scriptId); + }) + .then(scriptId => { + return Protocol.Runtime.runScript({ scriptId: scriptId }); + }) + .then(() => { + InspectorTest.log('Test completed'); + InspectorTest.completeTest(); + }) + .catch(e => { + InspectorTest.log(`Error: ${e}`); + InspectorTest.completeTest(); + }); diff --git a/deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start-expected.txt b/deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start-expected.txt new file mode 100644 index 000000000000..aa2c0b942e59 --- /dev/null +++ b/deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start-expected.txt @@ -0,0 +1,2 @@ +Tests Debugger.stepOver with enterRanges starting exactly at the function start position. +Paused in outlinedPart diff --git a/deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start.js b/deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start.js new file mode 100644 index 000000000000..4643a8cd65e4 --- /dev/null +++ b/deps/v8/test/inspector/debugger/regress-step-over-enter-ranges-exact-start.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = + InspectorTest.start('Tests Debugger.stepOver with enterRanges starting exactly at the function start position.'); + +contextGroup.addScript(`function outlinedPart() { return 1; } +function main() { debugger; outlinedPart(); return 2; }`); + +(async function() { + Protocol.Debugger.enable(); + const scriptResult = await Protocol.Debugger.onceScriptParsed(); + const scriptId = scriptResult.params.scriptId; + + let evalPromise = Protocol.Runtime.evaluate({expression: 'main()'}); + + // Pause on "debugger;" + let pause = await Protocol.Debugger.oncePaused(); + + // Step over "debugger;" to reach "outlinedPart();" + Protocol.Debugger.stepOver(); + pause = await Protocol.Debugger.oncePaused(); + + // The functionLocation of outlinedPart is line 0, column 21. + // When enterRanges starts exactly at this position, it should enter. + const enterRanges = [{ + scriptId: scriptId, + start: {lineNumber: 0, columnNumber: 21}, + end: {lineNumber: 0, columnNumber: 37} + }]; + + Protocol.Debugger.stepOver({enterRanges}); + pause = await Protocol.Debugger.oncePaused(); + + let frame = pause.params.callFrames[0]; + InspectorTest.log(`Paused in ${frame.functionName}`); + + await Protocol.Debugger.setSkipAllPauses({skip: true}); + await Protocol.Debugger.resume(); + await evalPromise; + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause-expected.txt b/deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause-expected.txt new file mode 100644 index 000000000000..6a09c027904c --- /dev/null +++ b/deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause-expected.txt @@ -0,0 +1,3 @@ +Checks restartFrame during an embedder breakProgram pause +caller() returned 42 after 2 pauses. +Done (no crash). diff --git a/deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause.js b/deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause.js new file mode 100644 index 000000000000..0b0ee6418613 --- /dev/null +++ b/deps/v8/test/inspector/debugger/restart-frame/restart-frame-during-embedder-pause.js @@ -0,0 +1,63 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks restartFrame during an embedder breakProgram pause'); + +session.setupScriptMap(); + +contextGroup.addScript( + ` +function target() { + inspector.breakProgram('reason', ''); + return 42; +} +function caller() { + return target(); +} +function victim(x) { + return x + 1; +} +`, + 0, 0, 'test.js'); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Runtime.enable(); + // Blackboxing keeps PrepareRestartFrame's StepInto from flooding the frames + // with one-shot breaks, so execution resumes from the embedder pause without + // re-entering Runtime_DebugBreakOnBytecode (which would terminate). + await Protocol.Debugger.setBlackboxPatterns({patterns: ['test\\.js']}); + + let pauses = 0; + Protocol.Debugger.onPaused(async ({params}) => { + ++pauses; + if (pauses === 1) { + // Request a restart of `caller` while paused inside the embedder's + // breakProgram call. + await Protocol.Debugger.restartFrame( + {callFrameId: params.callFrames[1].callFrameId, mode: 'StepInto'}); + } else { + await Protocol.Debugger.resume(); + } + }); + + const {result: {result}} = + await Protocol.Runtime.evaluate({expression: 'caller()'}); + InspectorTest.log( + `caller() returned ${result.value} after ${pauses} pauses.`); + + // Ensure a subsequent lazy deopt does not crash with a stale scheduled + // frame restart. + await Protocol.Runtime.evaluate({ + expression: `%PrepareFunctionForOptimization(victim); victim(1); victim(2); + %OptimizeFunctionOnNextCall(victim); victim(3); + %DeoptimizeFunction(victim); victim(4);` + }); + + InspectorTest.log('Done (no crash).'); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash-expected.txt b/deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash-expected.txt new file mode 100644 index 000000000000..b7274aa8defd --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash-expected.txt @@ -0,0 +1,18 @@ +Tests scopes of a direct eval whose not-yet-pushed block scope starts at the same offset as a block scope in the caller script. + +Running test: testGeneratorScopes +state: suspended +Block + x1: <unavailable> + x2: <unavailable> + x3: <unavailable> + x4: <unavailable> + x5: <unavailable> + x6: <unavailable> +Local +Block (outer) + a: 111 + eval_str: (async function*(){ for await (const [x1,x2,x3,x4,x5,x6] of never) { () => [x1,x2,x3,x4,x5,x6]; }})() +Closure (outer) + arguments: Arguments(0) +Global diff --git a/deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash.js b/deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash.js new file mode 100644 index 000000000000..14590035a08c --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-eval-unique-id-clash.js @@ -0,0 +1,61 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests scopes of a direct eval whose not-yet-pushed block scope starts ' + + 'at the same offset as a block scope in the caller script.'); + +// The block in `outer` and the `for await` block inside the eval string start +// at the same character offset (in their respective scripts). The generator is +// suspended in the `for await` header, before its block context is pushed, so +// the generator's context is still the caller's block context. +const kEvalPrefix = '(async function*(){'; +const kForHeader = 'for await ('; +let source = ` +var never = {[Symbol.asyncIterator]() { + return {next() { return new Promise(() => {}); }}; +}}; +function outer() { + { /* BLOCK_START */ + let a = 111; + () => a; + let eval_str = "${kEvalPrefix}" + " ".repeat(PAD) + + "${kForHeader}const [x1,x2,x3,x4,x5,x6] of never) { () => [x1,x2,x3,x4,x5,x6]; }})()"; + return eval(eval_str); + } +} +var g = outer(); +g.next(); +`; +const blockOffset = source.indexOf('{ /* BLOCK_START */'); +source = source.replace( + 'PAD', blockOffset - kEvalPrefix.length - kForHeader.length); +contextGroup.addScript(source); + +InspectorTest.runAsyncTestSuite([ + async function testGeneratorScopes() { + const {result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'g'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId}); + const state = internalProperties.find(p => p.name === '[[GeneratorState]]'); + InspectorTest.log('state: ' + state.value.value); + const scopes = internalProperties.find(p => p.name === '[[Scopes]]'); + const {result: {result: scopeList}} = await Protocol.Runtime.getProperties( + {objectId: scopes.value.objectId, ownProperties: true}); + for (const scope of scopeList) { + if (!scope.value || !scope.value.objectId) continue; + InspectorTest.log(scope.value.description); + if (scope.value.description === 'Global') continue; + const {result: {result: vars}} = await Protocol.Runtime.getProperties( + {objectId: scope.value.objectId, ownProperties: true}); + for (const v of vars) { + const value = v.value ? + (v.value.description ?? v.value.value ?? v.value.type) : + '<unavailable>'; + InspectorTest.log(` ${v.name}: ${value}`); + } + } + }, +]); diff --git a/deps/v8/test/inspector/debugger/scope-chain-outer-scopes-expected.txt b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes-expected.txt new file mode 100644 index 000000000000..1e1d2661a141 --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes-expected.txt @@ -0,0 +1,269 @@ +Tests that the scope chain includes outer scopes without a context. + +Running test: setUp + +Running test: testContextlessOuterScopes +Paused in inner: +[0] local name=inner emptyReason=no-variables 6:19-6:35 +[1] block emptyReason=all-unavailable 4:2-7:3 + blockVar : <value_unavailable> +[2] closure emptyReason=all-unavailable 2:20-8:1 + param : <value_unavailable> + shadowed : <value_unavailable> +[3] global + scopeNumber 0: shadowed = ReferenceError: shadowed is not defined + scopeNumber 0: blockVar = ReferenceError: blockVar is not defined + scopeNumber 0: param = ReferenceError: param is not defined + scopeNumber 1: shadowed = ReferenceError: shadowed is not defined + scopeNumber 1: blockVar = ReferenceError: blockVar is not defined + scopeNumber 1: param = ReferenceError: param is not defined + scopeNumber 2: shadowed = ReferenceError: shadowed is not defined + scopeNumber 2: blockVar = ReferenceError: blockVar is not defined + scopeNumber 2: param = ReferenceError: param is not defined + scopeNumber 3: shadowed = "global" + scopeNumber 3: blockVar = ReferenceError: blockVar is not defined + scopeNumber 3: param = ReferenceError: param is not defined + +Running test: testContextfulOuterScopes +Paused in inner: +[0] local name=inner emptyReason=no-variables 14:19-14:45 +[1] block name=withContext emptyReason=all-unavailable 12:2-15:3 + blockVar : <value_unavailable> +[2] closure name=withContext 10:20-16:1 + captured : "captured" +[3] global + scopeNumber 0: captured = "captured" + scopeNumber 0: blockVar = ReferenceError: blockVar is not defined + scopeNumber 1: captured = "captured" + scopeNumber 1: blockVar = ReferenceError: blockVar is not defined + scopeNumber 2: captured = "captured" + scopeNumber 2: blockVar = ReferenceError: blockVar is not defined + scopeNumber 3: captured = ReferenceError: captured is not defined + scopeNumber 3: blockVar = ReferenceError: blockVar is not defined + +Running test: testEmptyOuterFunction +Paused in inner: +[0] local name=inner emptyReason=no-variables 19:23-19:39 +[1] closure emptyReason=no-variables 18:19-20:1 +[2] global + scopeNumber 0: shadowed = "global" + scopeNumber 1: shadowed = "global" + scopeNumber 2: shadowed = "global" + +Running test: testFunctionConstructor +Paused in innerCtor: +[0] local name=innerCtor emptyReason=no-variables 2:25-2:41 [anonymous #1] +[1] closure emptyReason=all-unavailable 0:19-3:1 [anonymous #1] + a : <value_unavailable> +[2] global + scopeNumber 0: a = ReferenceError: a is not defined + scopeNumber 1: a = ReferenceError: a is not defined + scopeNumber 2: a = ReferenceError: a is not defined + +Running test: testWrappedFunction +[0] local name=inner emptyReason=no-variables 0:55-0:71 [wrapped.js] +[1] block emptyReason=all-unavailable 0:20-0:77 [wrapped.js] + blockVar : <value_unavailable> +[2] closure emptyReason=all-unavailable 0:0-0:77 [wrapped.js] + wrappedVar : <value_unavailable> +[3] global + +Running test: testGeneratorScopesKeepEmptyLocalScope +0: Local (emptyGenerator) +1: Global + +Running test: testDirectEvalOuterScopes +Paused in innerEval: +[0] local name=innerEval emptyReason=no-variables 0:36-0:52 [anonymous #1] +[1] closure 0:0-0:56 [anonymous #1] + evalVar : 1 +[2] block 30:4-33:5 + blockVar : "block" +[3] closure emptyReason=no-variables 29:3-34:3 +[4] closure name=directEvalOuter 26:24-35:1 + param : 42 + outerVar : "outer" + arguments : Arguments(1) +[5] global + scopeNumber 0: outerVar = "outer" + scopeNumber 0: evalVar = 1 + scopeNumber 0: param = 42 + scopeNumber 1: outerVar = "outer" + scopeNumber 1: evalVar = 1 + scopeNumber 1: param = 42 + scopeNumber 2: outerVar = "outer" + scopeNumber 2: evalVar = ReferenceError: evalVar is not defined + scopeNumber 2: param = 42 + scopeNumber 3: outerVar = "outer" + scopeNumber 3: evalVar = ReferenceError: evalVar is not defined + scopeNumber 3: param = 42 + scopeNumber 4: outerVar = "outer" + scopeNumber 4: evalVar = ReferenceError: evalVar is not defined + scopeNumber 4: param = 42 + scopeNumber 5: outerVar = ReferenceError: outerVar is not defined + scopeNumber 5: evalVar = ReferenceError: evalVar is not defined + scopeNumber 5: param = ReferenceError: param is not defined + +Running test: testChainedDirectEvalOuterScopes +Paused in innerMost: +[0] local name=innerMost emptyReason=no-variables 0:30-0:46 [anonymous #1] +[1] closure 0:0-0:50 [anonymous #1] + e : 5 +[2] block 0:11-0:85 [anonymous #2] + d : 4 +[3] closure 0:0-0:85 [anonymous #2] + c : 3 +[4] block name=chainedDirectEval 39:2-42:3 + b : 2 +[5] closure name=chainedDirectEval 37:26-43:1 + a : 1 + arguments : Arguments(0) +[6] global + scopeNumber 0: a = 1 + scopeNumber 0: b = 2 + scopeNumber 0: c = 3 + scopeNumber 0: d = 4 + scopeNumber 0: e = 5 + scopeNumber 1: a = 1 + scopeNumber 1: b = 2 + scopeNumber 1: c = 3 + scopeNumber 1: d = 4 + scopeNumber 1: e = 5 + scopeNumber 2: a = 1 + scopeNumber 2: b = 2 + scopeNumber 2: c = 3 + scopeNumber 2: d = 4 + scopeNumber 2: e = ReferenceError: e is not defined + scopeNumber 3: a = 1 + scopeNumber 3: b = 2 + scopeNumber 3: c = 3 + scopeNumber 3: d = ReferenceError: d is not defined + scopeNumber 3: e = ReferenceError: e is not defined + scopeNumber 4: a = 1 + scopeNumber 4: b = 2 + scopeNumber 4: c = ReferenceError: c is not defined + scopeNumber 4: d = ReferenceError: d is not defined + scopeNumber 4: e = ReferenceError: e is not defined + scopeNumber 5: a = 1 + scopeNumber 5: b = ReferenceError: b is not defined + scopeNumber 5: c = ReferenceError: c is not defined + scopeNumber 5: d = ReferenceError: d is not defined + scopeNumber 5: e = ReferenceError: e is not defined + scopeNumber 6: a = ReferenceError: a is not defined + scopeNumber 6: b = ReferenceError: b is not defined + scopeNumber 6: c = ReferenceError: c is not defined + scopeNumber 6: d = ReferenceError: d is not defined + scopeNumber 6: e = ReferenceError: e is not defined + +Running test: testPauseInDirectEvalCode +Paused in : +[0] eval 0:0-0:34 [anonymous #1] + evalLet : "evalLet" +[1] block name=pauseInEvalCode 47:2-50:3 + blockLet : "blockLet" +[2] closure name=pauseInEvalCode 45:24-51:1 + outerLet : "outerLet" + arguments : Arguments(0) +[3] global + scopeNumber 0: outerLet = "outerLet" + scopeNumber 0: blockLet = "blockLet" + scopeNumber 0: evalLet = "evalLet" + scopeNumber 1: outerLet = "outerLet" + scopeNumber 1: blockLet = "blockLet" + scopeNumber 1: evalLet = ReferenceError: evalLet is not defined + scopeNumber 2: outerLet = "outerLet" + scopeNumber 2: blockLet = ReferenceError: blockLet is not defined + scopeNumber 2: evalLet = ReferenceError: evalLet is not defined + scopeNumber 3: outerLet = ReferenceError: outerLet is not defined + scopeNumber 3: blockLet = ReferenceError: blockLet is not defined + scopeNumber 3: evalLet = ReferenceError: evalLet is not defined + +Running test: testPauseInNestedDirectEvalCode +Paused in : +[0] closure 0:0-0:28 [anonymous #1] + y : 1 +[1] closure name=pauseInNestedEvalCode 53:30-55:1 + arguments : Arguments(0) +[2] global + scopeNumber 0: y = 1 + scopeNumber 1: y = ReferenceError: y is not defined + scopeNumber 2: y = ReferenceError: y is not defined + +Running test: testSloppyDirectEvalInCatchAndWith +Paused in sloppyInner: +[0] local name=sloppyInner emptyReason=no-variables 0:44-0:60 [anonymous #1] +[1] with name=sloppyDirectEval 60:32-62:5 + withProp : "withProp" +[2] catch name=sloppyDirectEval 59:29-63:3 + caught : "err" +[3] closure name=sloppyDirectEval 57:25-64:1 + param : 42 + fnVar : "fnVar" + arguments : Arguments(1) + leaked : "leaked" +[4] global + scopeNumber 0: fnVar = "fnVar" + scopeNumber 0: caught = "err" + scopeNumber 0: withProp = "withProp" + scopeNumber 0: leaked = "leaked" + scopeNumber 0: param = 42 + scopeNumber 1: fnVar = "fnVar" + scopeNumber 1: caught = "err" + scopeNumber 1: withProp = "withProp" + scopeNumber 1: leaked = "leaked" + scopeNumber 1: param = 42 + scopeNumber 2: fnVar = "fnVar" + scopeNumber 2: caught = "err" + scopeNumber 2: withProp = ReferenceError: withProp is not defined + scopeNumber 2: leaked = "leaked" + scopeNumber 2: param = 42 + scopeNumber 3: fnVar = "fnVar" + scopeNumber 3: caught = ReferenceError: caught is not defined + scopeNumber 3: withProp = ReferenceError: withProp is not defined + scopeNumber 3: leaked = "leaked" + scopeNumber 3: param = 42 + scopeNumber 4: fnVar = ReferenceError: fnVar is not defined + scopeNumber 4: caught = ReferenceError: caught is not defined + scopeNumber 4: withProp = ReferenceError: withProp is not defined + scopeNumber 4: leaked = ReferenceError: leaked is not defined + scopeNumber 4: param = ReferenceError: param is not defined + +Running test: testSetVariableValueInDirectEvalCaller +Paused in setInner: +[0] local name=setInner emptyReason=no-variables 0:18-0:34 [anonymous #1] +[1] block name=setVariableInCaller 68:2-72:3 + blockVar : "block" +[2] closure name=setVariableInCaller 66:28-73:1 + outerVar : "outer" + arguments : Arguments(0) +[3] global + setVariableValue(1, blockVar): ok + setVariableValue(2, outerVar): ok +Result: "new outerVar new blockVar" + +Running test: testDirectEvalInForLetInitializer +Paused in : +[0] block name=directEvalInForLetInitializer 76:7-78:3 + x : 42 + y : <value_unavailable> +[1] closure name=directEvalInForLetInitializer 75:38-79:1 + arguments : Arguments(0) +[2] global + scopeNumber 0: x = 42 + scopeNumber 0: y = ReferenceError: y is not defined + scopeNumber 1: x = ReferenceError: x is not defined + scopeNumber 1: y = ReferenceError: y is not defined + scopeNumber 2: x = ReferenceError: x is not defined + scopeNumber 2: y = ReferenceError: y is not defined +Result: 43 + +Running test: testDirectEvalInForLetBody +Paused in : +[0] block name=directEvalInForLetBody 82:16-84:3 + x : 7 +[1] closure name=directEvalInForLetBody 81:31-85:1 + arguments : Arguments(0) +[2] global + scopeNumber 0: x = 7 + scopeNumber 1: x = ReferenceError: x is not defined + scopeNumber 2: x = ReferenceError: x is not defined diff --git a/deps/v8/test/inspector/debugger/scope-chain-outer-scopes.js b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes.js new file mode 100644 index 000000000000..4438ecbf9985 --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-outer-scopes.js @@ -0,0 +1,278 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that the scope chain includes outer scopes without a context.'); + +contextGroup.addScript(` +var shadowed = 'global'; +function contextless(param) { + let shadowed = 'outer'; + { + let blockVar = 1; + (function inner() { debugger; })(); + } +} + +function withContext() { + let captured = 'captured'; + { + let blockVar = 1; + (function inner() { captured; debugger; })(); + } +} + +function emptyOuter() { + return function inner() { debugger; }; +} + +function* emptyGenerator() { yield 1; } + +var ctor = new Function('a', 'return function innerCtor() { debugger; }'); + +function directEvalOuter(param) { + 'use strict'; + let outerVar = 'outer'; + (() => { + { + let blockVar = 'block'; + eval('let evalVar = 1; (function innerEval() { debugger; })();'); + } + })(); +} + +function chainedDirectEval() { + let a = 1; + { + let b = 2; + eval("let c = 3; { let d = 4; eval('let e = 5; (function innerMost() { debugger; })();'); }"); + } +} + +function pauseInEvalCode() { + let outerLet = 'outerLet'; + { + let blockLet = 'blockLet'; + eval("let evalLet = 'evalLet'; debugger;"); + } +} + +function pauseInNestedEvalCode() { + eval("let y = 1; eval('debugger;')"); +} + +function sloppyDirectEval(param) { + var fnVar = 'fnVar'; + try { throw 'err'; } catch (caught) { + with ({withProp: 'withProp'}) { + eval("var leaked = 'leaked'; (function sloppyInner() { debugger; })();"); + } + } +} + +function setVariableInCaller() { + let outerVar = 'outer'; + { + let blockVar = 'block'; + eval('(function setInner() { debugger; })();'); + return outerVar + ' ' + blockVar; + } +} + +function directEvalInForLetInitializer() { + for (let x = 42, y = eval('debugger; x + 1'); ; ) { + return y; + } +} + +function directEvalInForLetBody() { + for (let x = 7; x < 8; x++) { + eval('debugger;'); + } +} +//# sourceURL=test.js`); + +// Scripts other than test.js are labelled in the order in which they appear +// in a scope chain, starting with the innermost. +const scriptUrls = new Map(); +Protocol.Debugger.onScriptParsed( + ({params: {scriptId, url}}) => scriptUrls.set(scriptId, url)); +let scriptLabels; + +function scriptLabel(scriptId) { + const url = scriptUrls.get(scriptId); + if (url === 'test.js') return ''; + if (!scriptLabels.has(scriptId)) { + scriptLabels.set( + scriptId, url ? `[${url}]` : `[anonymous #${scriptLabels.size + 1}]`); + } + return ` ${scriptLabels.get(scriptId)}`; +} + +function locationToString(location) { + return `${location.lineNumber}:${location.columnNumber}`; +} + +function describe(remoteObject) { + return remoteObject.type === 'string' ? JSON.stringify(remoteObject.value) : + remoteObject.description; +} + +async function logScope(scope, index) { + let line = `[${index}] ${scope.type}`; + if (scope.name) line += ` name=${scope.name}`; + if (scope.emptyReason) line += ` emptyReason=${scope.emptyReason}`; + if (scope.startLocation) { + line += ` ${locationToString(scope.startLocation)}-` + + `${locationToString(scope.endLocation)}` + + scriptLabel(scope.startLocation.scriptId); + } + InspectorTest.log(line); + if (scope.type === 'global') return; + const {result: {result: variables}} = await Protocol.Runtime.getProperties( + {objectId: scope.object.objectId, ownProperties: true}); + for (const variable of variables) { + const value = + 'value' in variable ? describe(variable.value) : '<value_unavailable>'; + InspectorTest.log(` ${variable.name} : ${value}`); + } +} + +async function logScopeChain(callFrame) { + scriptLabels = new Map(); + for (let i = 0; i < callFrame.scopeChain.length; ++i) { + await logScope(callFrame.scopeChain[i], i); + } +} + +async function evaluateInEachScope(callFrame, expressions) { + for (let i = 0; i < callFrame.scopeChain.length; ++i) { + for (const expression of expressions) { + const {result: {result, exceptionDetails}} = + await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId: callFrame.callFrameId, expression, scopeNumber: i}); + const value = exceptionDetails ? + exceptionDetails.exception.description.split('\n')[0] : + describe(result); + InspectorTest.log(` scopeNumber ${i}: ${expression} = ${value}`); + } + } +} + +async function pauseAndLogScopes( + expression, evaluateExpressions = [], whilePaused = async () => {}) { + const paused = Protocol.Debugger.oncePaused(); + const evaluated = Protocol.Runtime.evaluate({expression}); + const {params: {callFrames: [callFrame]}} = await paused; + InspectorTest.log(`Paused in ${callFrame.functionName}:`); + await logScopeChain(callFrame); + await evaluateInEachScope(callFrame, evaluateExpressions); + await whilePaused(callFrame); + await Protocol.Debugger.resume(); + return (await evaluated).result.result; +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Debugger.enable(); + await Protocol.Runtime.enable(); + }, + + async function testContextlessOuterScopes() { + await pauseAndLogScopes( + 'contextless(42)', ['shadowed', 'blockVar', 'param']); + }, + + async function testContextfulOuterScopes() { + await pauseAndLogScopes('withContext()', ['captured', 'blockVar']); + }, + + async function testEmptyOuterFunction() { + await pauseAndLogScopes('emptyOuter()()', ['shadowed']); + }, + + async function testFunctionConstructor() { + await pauseAndLogScopes('ctor(42)()', ['a']); + }, + + async function testWrappedFunction() { + const paused = Protocol.Debugger.oncePaused(); + utils.compileAndRunWrapped( + contextGroup.id, + 'let wrappedVar = 1; ' + + '{ let blockVar = 2; (function inner() { debugger; })(); }', + 'wrapped.js'); + const {params: {callFrames: [callFrame]}} = await paused; + await logScopeChain(callFrame); + await Protocol.Debugger.resume(); + }, + + async function testGeneratorScopesKeepEmptyLocalScope() { + const {result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'emptyGenerator()'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId}); + const scopes = internalProperties.find(p => p.name === '[[Scopes]]'); + const {result: {result: entries}} = await Protocol.Runtime.getProperties( + {objectId: scopes.value.objectId, ownProperties: true}); + for (const entry of entries) { + if (entry.value) { + InspectorTest.log(`${entry.name}: ${entry.value.description}`); + } + } + }, + + async function testDirectEvalOuterScopes() { + await pauseAndLogScopes( + 'directEvalOuter(42)', ['outerVar', 'evalVar', 'param']); + }, + + async function testChainedDirectEvalOuterScopes() { + await pauseAndLogScopes( + 'chainedDirectEval()', ['a', 'b', 'c', 'd', 'e']); + }, + + async function testPauseInDirectEvalCode() { + await pauseAndLogScopes( + 'pauseInEvalCode()', ['outerLet', 'blockLet', 'evalLet']); + }, + + async function testPauseInNestedDirectEvalCode() { + await pauseAndLogScopes('pauseInNestedEvalCode()', ['y']); + }, + + async function testSloppyDirectEvalInCatchAndWith() { + await pauseAndLogScopes( + 'sloppyDirectEval(42)', + ['fnVar', 'caught', 'withProp', 'leaked', 'param']); + }, + + async function testSetVariableValueInDirectEvalCaller() { + const result = await pauseAndLogScopes( + 'setVariableInCaller()', [], async (callFrame) => { + for (const [scopeNumber, variableName] of [[1, 'blockVar'], + [2, 'outerVar']]) { + const {error} = await Protocol.Debugger.setVariableValue({ + callFrameId: callFrame.callFrameId, + scopeNumber, + variableName, + newValue: {value: `new ${variableName}`}, + }); + InspectorTest.log(` setVariableValue(${scopeNumber}, ${ + variableName}): ${error ? error.message : 'ok'}`); + } + }); + InspectorTest.log(`Result: ${describe(result)}`); + }, + + async function testDirectEvalInForLetInitializer() { + const result = + await pauseAndLogScopes('directEvalInForLetInitializer()', ['x', 'y']); + InspectorTest.log(`Result: ${describe(result)}`); + }, + + async function testDirectEvalInForLetBody() { + await pauseAndLogScopes('directEvalInForLetBody()', ['x']); + }, +]); diff --git a/deps/v8/test/inspector/debugger/scope-chain-return-position-expected.txt b/deps/v8/test/inspector/debugger/scope-chain-return-position-expected.txt new file mode 100644 index 000000000000..b2162e1e1853 --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-return-position-expected.txt @@ -0,0 +1,77 @@ +Tests the scope chain at the return position of a function that returns from inside a block context while its own scope has no context. + +Running test: setUp + +Running test: testReturnInsideBlockInWith +Paused in 'returnInsideBlockInWith' at 6:6 + [0] block + x : 1 + [1] local + [2] block + returnInsideBlockInWith : <value_unavailable> + [3] with + withProp : 1 + [4] global + x = 1 +Paused in 'returnInsideBlockInWith' at 7:6 + [0] block + x : 1 + [1] local + [2] block + returnInsideBlockInWith : <value_unavailable> + [3] with + withProp : 1 + [4] global + x = 1 +Paused in 'returnInsideBlockInWith' at 7:16 + [0] local + [1] block + returnInsideBlockInWith : <value_unavailable> + [2] with + withProp : 1 + [3] global + x = ReferenceError: x is not defined + at eval (eval at returnInsideBlockInWith (:8:17), <anonymous>:1:1) + at returnInsideBlockInWith (test.js:8:17) + at <anonymous>:1:1 +Result: 42 + +Running test: testReturnInsideBlockInDirectEval +Paused in '' at 0:40 + [0] block + x : 1 + [1] local + [2] block + x : 5 + a : 2 + b : 3 + c : 4 + [3] closure + arguments : Arguments(0) + [4] global + x = 1 +Paused in '' at 0:50 + [0] block + x : 1 + [1] local + [2] block + x : 5 + a : 2 + b : 3 + c : 4 + [3] closure + arguments : Arguments(0) + [4] global + x = 1 +Paused in '' at 0:60 + [0] local + [1] block + x : 5 + a : 2 + b : 3 + c : 4 + [2] closure + arguments : Arguments(0) + [3] global + x = 5 +Result: 42 diff --git a/deps/v8/test/inspector/debugger/scope-chain-return-position.js b/deps/v8/test/inspector/debugger/scope-chain-return-position.js new file mode 100644 index 000000000000..8a1801b15292 --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-chain-return-position.js @@ -0,0 +1,88 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests the scope chain at the return position of a function that ' + + 'returns from inside a block context while its own scope has no context.'); + +contextGroup.addScript(` +with ({withProp: 1}) { + function returnInsideBlockInWith() { + { + let x = 1; + (() => x)(); + debugger; + return 42; + } + } +} + +function returnInsideBlockInEval() { + // The block in the outer eval starts at the same offset (14) as the block + // inside the function in the inner eval. + return eval( + ' { let x = 5, a = 2, b = 3, c = 4; (() => x + a + b + c)(); ' + + 'eval("(function() { { let x = 1; (() => x)(); debugger; return 42; } })()"); }'); +} +//# sourceURL=test.js`); + +function describe(remoteObject) { + return remoteObject.type === 'string' ? JSON.stringify(remoteObject.value) : + remoteObject.description; +} + +async function logScopeChain(callFrame) { + for (let i = 0; i < callFrame.scopeChain.length; ++i) { + const scope = callFrame.scopeChain[i]; + InspectorTest.log(` [${i}] ${scope.type}`); + if (scope.type === 'global') continue; + const {result: {result: variables}} = await Protocol.Runtime.getProperties( + {objectId: scope.object.objectId, ownProperties: true}); + for (const variable of variables) { + const value = + 'value' in variable ? describe(variable.value) : '<value_unavailable>'; + InspectorTest.log(` ${variable.name} : ${value}`); + } + } +} + +async function logPause() { + const {params: {callFrames: [callFrame]}} = + await Protocol.Debugger.oncePaused(); + const {lineNumber, columnNumber} = callFrame.location; + InspectorTest.log(`Paused in '${callFrame.functionName}' at ${lineNumber}:${ + columnNumber}`); + await logScopeChain(callFrame); + const {result: {result}} = await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId: callFrame.callFrameId, expression: 'x'}); + InspectorTest.log(` x = ${describe(result)}`); +} + +// Pauses at the `debugger` statement, then steps to the `return` statement +// and on to the return position of the function. +async function stepToReturnAndLogScopes(expression) { + const evaluated = Protocol.Runtime.evaluate({expression}); + await logPause(); + for (let i = 0; i < 2; ++i) { + Protocol.Debugger.stepOver(); + await logPause(); + } + await Protocol.Debugger.resume(); + InspectorTest.log(`Result: ${describe((await evaluated).result.result)}`); +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Debugger.enable(); + await Protocol.Runtime.enable(); + }, + + async function testReturnInsideBlockInWith() { + await stepToReturnAndLogScopes('returnInsideBlockInWith()'); + }, + + async function testReturnInsideBlockInDirectEval() { + await stepToReturnAndLogScopes('returnInsideBlockInEval()'); + }, +]); diff --git a/deps/v8/test/inspector/debugger/scope-empty-reason-expected.txt b/deps/v8/test/inspector/debugger/scope-empty-reason-expected.txt new file mode 100644 index 000000000000..8d09b6d4a3a3 --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-empty-reason-expected.txt @@ -0,0 +1,15 @@ +Tests Debugger.Scope.emptyReason. + +Running test: testEmptyReason +Paused in empty: + local: no-variables +Paused in allUnavailable: + local: all-unavailable +Paused in blockAllUnavailable: + block: all-unavailable + local: <absent> +Paused in someAvailable: + local: <absent> +Paused in inner: + local: no-variables + closure: <absent> diff --git a/deps/v8/test/inspector/debugger/scope-empty-reason.js b/deps/v8/test/inspector/debugger/scope-empty-reason.js new file mode 100644 index 000000000000..686564e57eff --- /dev/null +++ b/deps/v8/test/inspector/debugger/scope-empty-reason.js @@ -0,0 +1,70 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Tests Debugger.Scope.emptyReason.'); + +contextGroup.addScript(` +function empty() { + debugger; +} + +function allUnavailable() { + debugger; + let a = 1; + const b = 2; + return a + b; +} + +function blockAllUnavailable(x) { + { + debugger; + let a = 1; + let b = 2; + return a + b + x; + } +} + +function someAvailable() { + let a = 1; + debugger; + let b = 2; + return a + b; +} + +function closure() { + let outer = 42; + return function inner() { + debugger; + return outer; + }; +} +`); + +async function dumpScopeChain(expression) { + const pausedPromise = Protocol.Debugger.oncePaused(); + const evaluatePromise = Protocol.Runtime.evaluate({expression}); + const {params: {callFrames: [{functionName, scopeChain}]}} = + await pausedPromise; + InspectorTest.log(`Paused in ${functionName}:`); + for (const {type, emptyReason} of scopeChain) { + // Script and global scopes depend on the test harness. + if (type === 'script' || type === 'global') continue; + InspectorTest.log(` ${type}: ${emptyReason ?? '<absent>'}`); + } + await Protocol.Debugger.resume(); + await evaluatePromise; +} + +InspectorTest.runAsyncTestSuite([ + async function testEmptyReason() { + await Protocol.Debugger.enable(); + await dumpScopeChain('empty()'); + await dumpScopeChain('allUnavailable()'); + await dumpScopeChain('blockAllUnavailable(1)'); + await dumpScopeChain('someAvailable()'); + await dumpScopeChain('closure()()'); + await Protocol.Debugger.disable(); + }, +]); diff --git a/deps/v8/test/inspector/debugger/script-parsed-long-magic-comments-expected.txt b/deps/v8/test/inspector/debugger/script-parsed-long-magic-comments-expected.txt new file mode 100644 index 000000000000..2d70725beb30 --- /dev/null +++ b/deps/v8/test/inspector/debugger/script-parsed-long-magic-comments-expected.txt @@ -0,0 +1,13 @@ +Tests long magic comment values in Debugger.scriptParsed +Debugger.scriptParsed with: +url: full value +hasSourceURL: true +sourceMapURL: full value +buildId: full value + +Debugger.scriptParsed with: +url: full value +hasSourceURL: true +sourceMapURL: full value +buildId: full value + diff --git a/deps/v8/test/inspector/debugger/script-parsed-long-magic-comments.js b/deps/v8/test/inspector/debugger/script-parsed-long-magic-comments.js new file mode 100644 index 000000000000..58f7a9f8e13e --- /dev/null +++ b/deps/v8/test/inspector/debugger/script-parsed-long-magic-comments.js @@ -0,0 +1,36 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const { session, contextGroup, Protocol } = InspectorTest.start( + 'Tests long magic comment values in Debugger.scriptParsed'); + +const value = 'data:application/json;base64,' + 'A'.repeat(100000); +const source = `const foo = 42; +//# sourceURL=${value} +//# sourceMappingURL=${value} +//# debugId=${value} +`; + +function describe(actual) { + return actual === value ? 'full value' : + `unexpected value of length ${actual.length}`; +} + +contextGroup.addScript(source, 0, 0, 'script.js'); +contextGroup.addModule(source, 'module.js'); + +(async () => { + Protocol.Debugger.onScriptParsed( + ({params: {url, hasSourceURL, sourceMapURL, buildId}}) => { + InspectorTest.log('Debugger.scriptParsed with:'); + InspectorTest.log('url: ' + describe(url)); + InspectorTest.log('hasSourceURL: ' + hasSourceURL); + InspectorTest.log('sourceMapURL: ' + describe(sourceMapURL)); + InspectorTest.log('buildId: ' + describe(buildId)); + InspectorTest.log(); + }); + + await Protocol.Debugger.enable(); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position-expected.txt b/deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position-expected.txt new file mode 100644 index 000000000000..476a12787ab9 --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position-expected.txt @@ -0,0 +1,31 @@ +Checks that breakpoints after the last breakable position of a function resolve forward into nested functions. +Setting breakpoint at line 3: + function inner() { + #return 1; + } + +Setting breakpoint at line 10: + function inner() { + #return 2; + } + +Setting breakpoint at line 17: + function inner() { + #return 3; + } + +Evaluating returnBeforeInner()(): + function inner() { + #return 1; + } + +Evaluating try { throwBeforeInner(); } catch (inner) { inner(); }: + function inner() { + #return 2; + } + +Evaluating liveCodeBeforeInner()(): + function inner() { + #return 3; + } + diff --git a/deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position.js b/deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position.js new file mode 100644 index 000000000000..cf7c544dbd8b --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-breakpoint-after-last-breakable-position.js @@ -0,0 +1,66 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that breakpoints after the last breakable position of a ' + + 'function resolve forward into nested functions.'); + +const source = ` +function returnBeforeInner() { + return inner; + function inner() { + return 1; + } +} + +function throwBeforeInner() { + throw inner; + function inner() { + return 2; + } +} + +function liveCodeBeforeInner() { + var x = inner; + function inner() { + return 3; + } + return x; +} +`; +contextGroup.addScript(source, 0, 0, 'test.js'); + +session.setupScriptMap(); + +(async () => { + await Protocol.Debugger.enable(); + + // Set breakpoints on the lines declaring the nested `inner` functions. + for (const lineNumber of [3, 10, 17]) { + InspectorTest.log(`Setting breakpoint at line ${lineNumber}:`); + const {result: {locations}} = await Protocol.Debugger.setBreakpointByUrl( + {lineNumber, url: 'test.js'}); + for (const location of locations) { + await session.logSourceLocation(location); + } + } + + // Check that the breakpoints are hit in the nested `inner` functions. + const expressions = [ + 'returnBeforeInner()()', + 'try { throwBeforeInner(); } catch (inner) { inner(); }', + 'liveCodeBeforeInner()()', + ]; + for (const expression of expressions) { + InspectorTest.log(`Evaluating ${expression}:`); + const evaluatePromise = Protocol.Runtime.evaluate({expression}); + const {params: {callFrames: [{location}]}} = + await Protocol.Debugger.oncePaused(); + await session.logSourceLocation(location); + await Protocol.Debugger.resume(); + await evaluatePromise; + } + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position-expected.txt b/deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position-expected.txt new file mode 100644 index 000000000000..63041b6895f7 --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position-expected.txt @@ -0,0 +1,3 @@ +Checks that setting a breakpoint on a function with no breakable positions does not crash. +Setting breakpoint on loop function... +Breakpoint result: {"breakpointId":"1:2:0:loop.js","locations":[{"scriptId":"3","lineNumber":2,"columnNumber":6}]} diff --git a/deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position.js b/deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position.js new file mode 100644 index 000000000000..f2b15066101c --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-breakpoint-no-breakable-position.js @@ -0,0 +1,29 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const { session, contextGroup, Protocol } = InspectorTest.start( + 'Checks that setting a breakpoint on a function with no breakable positions does not crash.'); + +(async () => { + await Protocol.Debugger.enable(); + + contextGroup.addScript(` + function loop() { + while (true) {} + } + `, 0, 0, 'loop.js'); + + InspectorTest.log('Setting breakpoint on loop function...'); + const {result, error} = await Protocol.Debugger.setBreakpointByUrl({ + lineNumber: 2, + url: 'loop.js' + }); + if (error) { + InspectorTest.log(`Error: ${error.message}`); + } else { + InspectorTest.log(`Breakpoint result: ${JSON.stringify(result)}`); + } + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/set-variable-value-unallocated-expected.txt b/deps/v8/test/inspector/debugger/set-variable-value-unallocated-expected.txt new file mode 100644 index 000000000000..279ec5e2ef5a --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-variable-value-unallocated-expected.txt @@ -0,0 +1,19 @@ +Checks that Debugger.setVariableValue handles unallocated variables gracefully +Local scope found: true +Setting unallocated local variable "unusedLocal": +{ + error : { + code : -32603 + message : Internal error + } + id : <messageId> +} +Closure scope found: true +Setting unallocated outer variable "unusedOuter": +{ + error : { + code : -32603 + message : Internal error + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/debugger/set-variable-value-unallocated.js b/deps/v8/test/inspector/debugger/set-variable-value-unallocated.js new file mode 100644 index 000000000000..0e108ae21066 --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-variable-value-unallocated.js @@ -0,0 +1,57 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that Debugger.setVariableValue handles unallocated variables gracefully'); + +const source = ` +function outer() { + var unusedOuter; + function inner() { + var unusedLocal; + debugger; + } + inner(); +} +outer(); +`; + +(async () => { + await Protocol.Debugger.enable(); + + Protocol.Runtime.evaluate({expression: source}); + const {params: {callFrames}} = await Protocol.Debugger.oncePaused(); + const {callFrameId, scopeChain} = callFrames[0]; + + let localScopeNumber = -1; + let closureScopeNumber = -1; + for (let i = 0; i < scopeChain.length; ++i) { + if (scopeChain[i].type === 'local' && localScopeNumber === -1) { + localScopeNumber = i; + } else if (scopeChain[i].type === 'closure' && closureScopeNumber === -1) { + closureScopeNumber = i; + } + } + + InspectorTest.log('Local scope found: ' + (localScopeNumber >= 0)); + InspectorTest.log('Setting unallocated local variable "unusedLocal":'); + InspectorTest.logMessage(await Protocol.Debugger.setVariableValue({ + scopeNumber: localScopeNumber, + variableName: 'unusedLocal', + newValue: {value: 42}, + callFrameId, + })); + + InspectorTest.log('Closure scope found: ' + (closureScopeNumber >= 0)); + InspectorTest.log('Setting unallocated outer variable "unusedOuter":'); + InspectorTest.logMessage(await Protocol.Debugger.setVariableValue({ + scopeNumber: closureScopeNumber, + variableName: 'unusedOuter', + newValue: {value: 42}, + callFrameId, + })); + + await Protocol.Debugger.resume(); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/set-variable-value-varblock-eval-expected.txt b/deps/v8/test/inspector/debugger/set-variable-value-varblock-eval-expected.txt new file mode 100644 index 000000000000..dd268856c86c --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-variable-value-varblock-eval-expected.txt @@ -0,0 +1,10 @@ +Checks that Debugger.setVariableValue can set eval-introduced vars in the varblock scope of a function with non-simple parameters +Scope chain: block, local, global +Block scope variables: leaked=1 +Setting "leaked" on the block scope to 42: +{ + id : <messageId> + result : { + } +} +f() returned: 42 diff --git a/deps/v8/test/inspector/debugger/set-variable-value-varblock-eval.js b/deps/v8/test/inspector/debugger/set-variable-value-varblock-eval.js new file mode 100644 index 000000000000..8631431b7890 --- /dev/null +++ b/deps/v8/test/inspector/debugger/set-variable-value-varblock-eval.js @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that Debugger.setVariableValue can set eval-introduced vars in ' + + 'the varblock scope of a function with non-simple parameters'); + +contextGroup.addScript(` +function f(a = 1) { + eval("var leaked = 1;"); + debugger; + return leaked; +} +`); + +(async () => { + await Protocol.Debugger.enable(); + + const evalPromise = + Protocol.Runtime.evaluate({expression: 'f()', returnByValue: true}); + const {params: {callFrames}} = await Protocol.Debugger.oncePaused(); + const {callFrameId, scopeChain} = callFrames[0]; + + InspectorTest.log('Scope chain: ' + scopeChain.map(s => s.type).join(', ')); + const blockScopeNumber = scopeChain.findIndex(s => s.type === 'block'); + + const {result: {result: props}} = await Protocol.Runtime.getProperties( + {objectId: scopeChain[blockScopeNumber].object.objectId}); + InspectorTest.log( + 'Block scope variables: ' + + props.map(p => `${p.name}=${p.value.value}`).join(', ')); + + InspectorTest.log('Setting "leaked" on the block scope to 42:'); + InspectorTest.logMessage(await Protocol.Debugger.setVariableValue({ + scopeNumber: blockScopeNumber, + variableName: 'leaked', + newValue: {value: 42}, + callFrameId, + })); + + await Protocol.Debugger.resume(); + const {result: {result}} = await evalPromise; + InspectorTest.log('f() returned: ' + result.value); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call-expected.txt b/deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call-expected.txt new file mode 100644 index 000000000000..4823d842bf94 --- /dev/null +++ b/deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call-expected.txt @@ -0,0 +1,11 @@ +Checks side-effect free evaluation while a pause on the next function call is requested. +Evaluate side-effect free call: +{ + description : 42 + type : number + value : 42 +} +Evaluate side-effecting call: +EvalError: Possible side-effect in debug-evaluate +Pause request is still honored afterwards: +Paused in (anonymous) diff --git a/deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call.js b/deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call.js new file mode 100644 index 000000000000..eb365e35dc0f --- /dev/null +++ b/deps/v8/test/inspector/debugger/side-effect-free-evaluate-with-pause-on-next-call.js @@ -0,0 +1,40 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks side-effect free evaluation while a pause on the next function ' + + 'call is requested.'); + +contextGroup.addScript(` +var x = 0; +function f() { + return 42; +} +function g() { + x = 1; +} +//# sourceURL=test.js`); + +(async function() { + await Protocol.Debugger.enable(); + // Not running JavaScript, so this requests a pause on the next call. + await Protocol.Debugger.pause(); + + InspectorTest.log('Evaluate side-effect free call:'); + InspectorTest.logMessage((await Protocol.Runtime.evaluate( + {expression: 'f()', throwOnSideEffect: true})).result.result); + + InspectorTest.log('Evaluate side-effecting call:'); + InspectorTest.logMessage((await Protocol.Runtime.evaluate( + {expression: 'g()', throwOnSideEffect: true})).result.exceptionDetails + .exception.description); + + InspectorTest.log('Pause request is still honored afterwards:'); + Protocol.Runtime.evaluate({expression: 'f()'}); + const {params: {callFrames: [{functionName}]}} = + await Protocol.Debugger.oncePaused(); + InspectorTest.log(`Paused in ${functionName || '(anonymous)'}`); + await Protocol.Debugger.resume(); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/step-over-enter-ranges-expected.txt b/deps/v8/test/inspector/debugger/step-over-enter-ranges-expected.txt new file mode 100644 index 000000000000..8398cc33907b --- /dev/null +++ b/deps/v8/test/inspector/debugger/step-over-enter-ranges-expected.txt @@ -0,0 +1,106 @@ +Tests Debugger.stepOver with enterRanges. + +Test: without enterRanges, no function is entered +Step over through main() with no arguments: + main: #debugger; + main: #outlinedPart(); + main: #notEntered(); + main: #callCallback(outlinedPart); + main: #[1, 2].forEach(outlinedPart); + main: #outlinedPartInOtherScript(); + main: #return 0; + main: return 0;# + (top-level) + +Test: functions in enterRanges are entered, also from another script and when called by a non-entered function or a builtin +Note: when an entered function returns into a non-entered function (callCallback), the step pauses there, like a regular step out. +Step over through main() with enterRanges: [outlinedPart, outlinedPartInOtherScript]: + main: #debugger; + main: #outlinedPart(); + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #notEntered(); + main: #callCallback(outlinedPart); + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + callCallback: return cb();# + main: #[1, 2].forEach(outlinedPart); + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #outlinedPartInOtherScript(); + outlinedPartInOtherScript: #return 3; + outlinedPartInOtherScript: return 3;# + main: #return 0; + main: return 0;# + (top-level) + +Test: functions in enterRanges are entered through a blackboxed function, which itself is not paused in +Step over through main() with enterRanges: [outlinedPart]: + main: #debugger; + main: #outlinedPart(); + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #notEntered(); + main: #callCallback(outlinedPart); + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #[1, 2].forEach(outlinedPart); + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + outlinedPart: let x = #1; + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #outlinedPartInOtherScript(); + main: #return 0; + main: return 0;# + (top-level) + +Test: skipList also applies inside entered functions +Step over through main() with enterRanges: [outlinedPart], skipList: ['let x = 1;']: + main: #debugger; + main: #outlinedPart(); + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #notEntered(); + main: #callCallback(outlinedPart); + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + callCallback: return cb();# + main: #[1, 2].forEach(outlinedPart); + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + outlinedPart: #return notEntered(); + outlinedPart: return notEntered();# + main: #outlinedPartInOtherScript(); + main: #return 0; + main: return 0;# + (top-level) + +Test: recursive calls of the stepped over function are not entered +Step over through recursive(1) with enterRanges: [outlinedPart]: + recursive: #debugger; + recursive: #callRecursive(n); + recursive: #return n; + recursive: return n;# + (top-level) + +Test: enterRanges only apply to the step they are passed to + main: #debugger; +Step over with enterRanges: [outlinedPart]: + main: #outlinedPart(); +Step over with no arguments steps over outlinedPart: + main: #notEntered(); + +Test: enterRanges with an unknown script are rejected +Step over through main() with enterRanges: [unknown script]: + main: #debugger; + Error: No script with passed id. diff --git a/deps/v8/test/inspector/debugger/step-over-enter-ranges.js b/deps/v8/test/inspector/debugger/step-over-enter-ranges.js new file mode 100644 index 000000000000..c9a9fc38f25c --- /dev/null +++ b/deps/v8/test/inspector/debugger/step-over-enter-ranges.js @@ -0,0 +1,185 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = + InspectorTest.start('Tests Debugger.stepOver with enterRanges.'); + +const source = [ + 'function outlinedPart() {', // Entered when in enterRanges. + ' let x = 1;', + ' return notEntered();', + '}', + 'function notEntered() {', // Never in enterRanges. + ' return 2;', + '}', + 'function callCallback(cb) {', + ' return cb();', + '}', + 'function main() {', + ' debugger;', + ' outlinedPart();', + ' notEntered();', + ' callCallback(outlinedPart);', + ' [1, 2].forEach(outlinedPart);', + ' outlinedPartInOtherScript();', + ' return 0;', + '}', + 'function recursive(n) {', + ' if (n == 0) return 0;', + ' debugger;', + ' callRecursive(n);', + ' return n;', + '}', + 'function callRecursive(n) {', + ' return recursive(n - 1);', + '}', +]; + +const otherSource = [ + 'function outlinedPartInOtherScript() {', + ' return 3;', + '}', +]; + +contextGroup.addScript(source.join('\n')); +contextGroup.addScript(otherSource.join('\n')); + +const linesByScriptId = new Map(); +const rangeNames = new Map(); + +// Returns the range [start of `function name(`, start of the line after its +// closing brace). +function functionRange(scriptId, name) { + const lines = linesByScriptId.get(scriptId); + const start = lines.findIndex(l => l.startsWith(`function ${name}(`)); + const end = lines.findIndex((l, i) => i > start && l.startsWith('}')) + 1; + return namedRange(name, scriptId, start, end); +} + +// Returns the range covering the line containing {text}. +function lineRange(scriptId, text) { + const line = linesByScriptId.get(scriptId).findIndex(l => l.includes(text)); + return namedRange(`'${text}'`, scriptId, line, line + 1); +} + +function namedRange(name, scriptId, startLine, endLine) { + const range = { + scriptId, + start: {lineNumber: startLine, columnNumber: 0}, + end: {lineNumber: endLine, columnNumber: 0}, + }; + rangeNames.set(range, name); + return range; +} + +function describeStepArgs(args) { + const parts = Object.entries(args).map( + ([key, ranges]) => + `${key}: [${ranges.map(r => rangeNames.get(r)).join(', ')}]`); + return parts.length ? parts.join(', ') : 'no arguments'; +} + +// Logs the pause as "function: source line", with # marking the position. +function logPause({params: {callFrames}}) { + const {functionName, location: {scriptId, lineNumber, columnNumber}} = + callFrames[0]; + const lines = linesByScriptId.get(scriptId); + if (!lines) { + InspectorTest.log(' (top-level)'); + return functionName; + } + const line = lines[lineNumber]; + const marked = line.slice(0, columnNumber) + '#' + line.slice(columnNumber); + InspectorTest.log(` ${functionName}: ${marked.trim()}`); + return functionName; +} + +async function finishEvaluation(evaluation) { + await Protocol.Debugger.setSkipAllPauses({skip: true}); + await Protocol.Debugger.resume(); + await evaluation; + await Protocol.Debugger.setSkipAllPauses({skip: false}); +} + +// Evaluates {expression} until the first debugger statement, then steps over +// with {args} until the top-level frame is reached. +async function stepThrough(expression, args) { + InspectorTest.log(`Step over through ${expression} with ${ + describeStepArgs(args)}:`); + const evaluation = Protocol.Runtime.evaluate({expression}); + let functionName = logPause(await Protocol.Debugger.oncePaused()); + while (functionName) { + const response = await Protocol.Debugger.stepOver(args); + if (response.error) { + InspectorTest.log(` Error: ${response.error.message}`); + break; + } + functionName = logPause(await Protocol.Debugger.oncePaused()); + } + await finishEvaluation(evaluation); +} + +(async function() { + Protocol.Debugger.enable(); + const [{params: {scriptId}}, {params: {scriptId: otherScriptId}}] = + await Protocol.Debugger.onceScriptParsed(2); + linesByScriptId.set(scriptId, source); + linesByScriptId.set(otherScriptId, otherSource); + const outlinedPart = functionRange(scriptId, 'outlinedPart'); + const outlinedPartInOtherScript = + functionRange(otherScriptId, 'outlinedPartInOtherScript'); + + InspectorTest.log('\nTest: without enterRanges, no function is entered'); + await stepThrough('main()', {}); + + InspectorTest.log( + '\nTest: functions in enterRanges are entered, also from another ' + + 'script and when called by a non-entered function or a builtin'); + InspectorTest.log( + 'Note: when an entered function returns into a non-entered function ' + + '(callCallback), the step pauses there, like a regular step out.'); + await stepThrough( + 'main()', {enterRanges: [outlinedPart, outlinedPartInOtherScript]}); + + InspectorTest.log( + '\nTest: functions in enterRanges are entered through a blackboxed ' + + 'function, which itself is not paused in'); + const callCallback = functionRange(scriptId, 'callCallback'); + await Protocol.Debugger.setBlackboxedRanges({ + scriptId, + positions: [callCallback.start, callCallback.end], + }); + await stepThrough('main()', {enterRanges: [outlinedPart]}); + await Protocol.Debugger.setBlackboxedRanges({scriptId, positions: []}); + + InspectorTest.log( + '\nTest: skipList also applies inside entered functions'); + await stepThrough('main()', { + enterRanges: [outlinedPart], + skipList: [lineRange(scriptId, 'let x = 1;')], + }); + + InspectorTest.log( + '\nTest: recursive calls of the stepped over function are not entered'); + await stepThrough('recursive(1)', {enterRanges: [outlinedPart]}); + + InspectorTest.log( + '\nTest: enterRanges only apply to the step they are passed to'); + const evaluation = Protocol.Runtime.evaluate({expression: 'main()'}); + logPause(await Protocol.Debugger.oncePaused()); + InspectorTest.log(`Step over with ${ + describeStepArgs({enterRanges: [outlinedPart]})}:`); + Protocol.Debugger.stepOver({enterRanges: [outlinedPart]}); + logPause(await Protocol.Debugger.oncePaused()); + InspectorTest.log('Step over with no arguments steps over outlinedPart:'); + Protocol.Debugger.stepOver({}); + logPause(await Protocol.Debugger.oncePaused()); + await finishEvaluation(evaluation); + + InspectorTest.log('\nTest: enterRanges with an unknown script are rejected'); + await stepThrough( + 'main()', {enterRanges: [namedRange('unknown script', '-1', 0, 1)]}); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert-expected.txt b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert-expected.txt new file mode 100644 index 000000000000..62fe7a2c0c1d --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert-expected.txt @@ -0,0 +1,25 @@ +Tests that the skipList of stepInto and stepOver does not suppress assert pauses. + +Test: stepInto into a skipped range hits an assert in the skipped range +Paused with reason: step + debugger; + #skippedBody(); + return 0; + +Paused with reason: ambiguous (assert, step) + let a = 1; + console.#assert(false, "assert failed"); + let b = 2; + + +Test: stepOver into a skipped range hits an assert in the skipped range +Paused with reason: step + debugger; + #skippedBody(); + return 0; + +Paused with reason: ambiguous (assert, step) + let a = 1; + console.#assert(false, "assert failed"); + let b = 2; + diff --git a/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert.js b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert.js new file mode 100644 index 000000000000..62acf3160111 --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-assert.js @@ -0,0 +1,82 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that the skipList of stepInto and stepOver does not suppress ' + + 'assert pauses.'); + +const source = [ + 'function skippedBody() {', // 0 + ' let a = 1;', // 1 + ' console.assert(false, "assert failed");', // 2 + ' let b = 2;', // 3 + ' return a + b;', // 4 + '}', // 5 + 'function test() {', // 6 + ' debugger;', // 7 + ' skippedBody();', // 8 + ' return 0;', // 9 + '}', // 10 +].join('\n'); + +contextGroup.addScript(source); +session.setupScriptMap(); + +function range(scriptId, startLine, startColumn, endLine, endColumn) { + return { + scriptId, + start: {lineNumber: startLine, columnNumber: startColumn}, + end: {lineNumber: endLine, columnNumber: endColumn}, + }; +} + +async function logPause(paused) { + const {reason, data, callFrames} = paused.params; + const reasons = reason === 'ambiguous' ? + ` (${data.reasons.map(r => r.reason).join(', ')})` : + ''; + InspectorTest.log(`Paused with reason: ${reason}${reasons}`); + await session.logSourceLocation(callFrames[0].location); +} + +let evaluation; + +// Runs test() until the `debugger` statement in test(). +async function startTest() { + evaluation = Protocol.Runtime.evaluate({expression: 'test()'}); + await Protocol.Debugger.oncePaused(); +} + +// Resumes and ignores any further pauses until test() returned. +async function finishTest() { + await Protocol.Debugger.setSkipAllPauses({skip: true}); + await Protocol.Debugger.resume(); + await evaluation; + await Protocol.Debugger.setSkipAllPauses({skip: false}); +} + +async function step(action, skipList) { + Protocol.Debugger[action]({skipList}); + await logPause(await Protocol.Debugger.oncePaused()); +} + +(async function() { + Protocol.Debugger.enable(); + const {params: {scriptId}} = await Protocol.Debugger.onceScriptParsed(); + // console.assert only pauses if pause on exceptions is enabled. + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + const skippedBodyRange = range(scriptId, 1, 0, 5, 0); + + for (const action of ['stepInto', 'stepOver']) { + InspectorTest.log( + `\nTest: ${action} into a skipped range hits an assert in the ` + + `skipped range`); + await startTest(); + await step('stepOver', []); + await step(action, [skippedBodyRange]); + await finishTest(); + } + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints-expected.txt b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints-expected.txt new file mode 100644 index 000000000000..4200883cfcf8 --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints-expected.txt @@ -0,0 +1,114 @@ +Tests that the skipList of stepInto and stepOver does not suppress breakpoints or debugger statements. + +Test: stepInto into a skipped range hits a breakpoint in the skipped range +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: ambiguous, hitBreakpoints: 1 + let a = 1; + let b = #2; + return a + b; + + +Test: stepInto into a skipped range stops at a debugger statement in the skipped range +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: step, hitBreakpoints: 0 + inlinedBody(); + #withDebuggerStmt(); + return 0; + +Paused with reason: ambiguous, hitBreakpoints: 0 + let c = 1; + #debugger; + return c; + + +Test: stepInto into a skipped range without breakpoints skips the range +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: step, hitBreakpoints: 0 + inlinedBody(); + #withDebuggerStmt(); + return 0; + + +Test: stepInto into a skipped range skips a breakpoint with a false condition +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: step, hitBreakpoints: 0 + inlinedBody(); + #withDebuggerStmt(); + return 0; + + +Test: stepOver into a skipped range hits a breakpoint in the skipped range +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: ambiguous, hitBreakpoints: 1 + let a = 1; + let b = #2; + return a + b; + + +Test: stepOver into a skipped range stops at a debugger statement in the skipped range +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: step, hitBreakpoints: 0 + inlinedBody(); + #withDebuggerStmt(); + return 0; + +Paused with reason: ambiguous, hitBreakpoints: 0 + let c = 1; + #debugger; + return c; + + +Test: stepOver into a skipped range without breakpoints skips the range +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: step, hitBreakpoints: 0 + inlinedBody(); + #withDebuggerStmt(); + return 0; + + +Test: stepOver into a skipped range skips a breakpoint with a false condition +Paused with reason: step, hitBreakpoints: 0 + debugger; + #inlinedBody(); + withDebuggerStmt(); + +Paused with reason: step, hitBreakpoints: 0 + inlinedBody(); + #withDebuggerStmt(); + return 0; + + +Test: stepOver stops at a breakpoint in the skipped range +Paused with reason: ambiguous, hitBreakpoints: 1 + inlinedBody(); + #withDebuggerStmt(); + return 0; + diff --git a/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints.js b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints.js new file mode 100644 index 000000000000..ed92f08dd612 --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-with-skip-list-and-breakpoints.js @@ -0,0 +1,122 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that the skipList of stepInto and stepOver does not suppress ' + + 'breakpoints or debugger statements.'); + +const source = [ + 'function inlinedBody() {', // 0 + ' let a = 1;', // 1 + ' let b = 2;', // 2 + ' return a + b;', // 3 + '}', // 4 + 'function withDebuggerStmt() {', // 5 + ' let c = 1;', // 6 + ' debugger;', // 7 + ' return c;', // 8 + '}', // 9 + 'function test() {', // 10 + ' debugger;', // 11 + ' inlinedBody();', // 12 + ' withDebuggerStmt();', // 13 + ' return 0;', // 14 + '}', // 15 +].join('\n'); + +contextGroup.addScript(source); +session.setupScriptMap(); + +function range(scriptId, startLine, startColumn, endLine, endColumn) { + return { + scriptId, + start: {lineNumber: startLine, columnNumber: startColumn}, + end: {lineNumber: endLine, columnNumber: endColumn}, + }; +} + +async function logPause(paused) { + const {reason, hitBreakpoints, callFrames} = paused.params; + InspectorTest.log(`Paused with reason: ${reason}, hitBreakpoints: ${ + (hitBreakpoints || []).length}`); + await session.logSourceLocation(callFrames[0].location); +} + +let evaluation; + +// Runs test() until the `debugger` statement in test(). +async function startTest() { + evaluation = Protocol.Runtime.evaluate({expression: 'test()'}); + await Protocol.Debugger.oncePaused(); +} + +// Resumes and ignores any further pauses until test() returned. +async function finishTest() { + await Protocol.Debugger.setSkipAllPauses({skip: true}); + await Protocol.Debugger.resume(); + await evaluation; + await Protocol.Debugger.setSkipAllPauses({skip: false}); +} + +async function step(action, skipList) { + Protocol.Debugger[action]({skipList}); + await logPause(await Protocol.Debugger.oncePaused()); +} + +(async function() { + Protocol.Debugger.enable(); + const {params: {scriptId}} = await Protocol.Debugger.onceScriptParsed(); + const inlinedBodyRange = range(scriptId, 1, 0, 4, 0); + const withDebuggerStmtRange = range(scriptId, 6, 0, 9, 0); + + for (const action of ['stepInto', 'stepOver']) { + InspectorTest.log(`\nTest: ${action} into a skipped range hits a ` + + `breakpoint in the skipped range`); + await startTest(); + let {result: {breakpointId}} = await Protocol.Debugger.setBreakpoint( + {location: {scriptId, lineNumber: 2, columnNumber: 2}}); + await step('stepOver', []); + await step(action, [inlinedBodyRange]); + await Protocol.Debugger.removeBreakpoint({breakpointId}); + await finishTest(); + + InspectorTest.log(`\nTest: ${action} into a skipped range stops at a ` + + `debugger statement in the skipped range`); + await startTest(); + await step('stepOver', []); + await step('stepOver', []); + await step(action, [withDebuggerStmtRange]); + await finishTest(); + + InspectorTest.log(`\nTest: ${action} into a skipped range without ` + + `breakpoints skips the range`); + await startTest(); + await step('stepOver', []); + await step(action, [inlinedBodyRange]); + await finishTest(); + + InspectorTest.log(`\nTest: ${action} into a skipped range skips a ` + + `breakpoint with a false condition`); + await startTest(); + ({result: {breakpointId}} = await Protocol.Debugger.setBreakpoint({ + location: {scriptId, lineNumber: 2, columnNumber: 2}, + condition: 'false' + })); + await step('stepOver', []); + await step(action, [inlinedBodyRange]); + await Protocol.Debugger.removeBreakpoint({breakpointId}); + await finishTest(); + } + + InspectorTest.log( + '\nTest: stepOver stops at a breakpoint in the skipped range'); + await startTest(); + const {result: {breakpointId}} = await Protocol.Debugger.setBreakpoint( + {location: {scriptId, lineNumber: 13, columnNumber: 2}}); + await step('stepOver', [range(scriptId, 12, 0, 14, 0)]); + await Protocol.Debugger.removeBreakpoint({breakpointId}); + await finishTest(); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/stepping-with-stale-skip-list-expected.txt b/deps/v8/test/inspector/debugger/stepping-with-stale-skip-list-expected.txt new file mode 100644 index 000000000000..341563786121 --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-with-stale-skip-list-expected.txt @@ -0,0 +1,63 @@ +Tests that the skipList of a step does not outlive that step. + +Test: stepOut after stepInto with skipList +Paused with reason: other +function callee() { + #debugger; + let x = 1; + +stepInto({"skipList":[{"scriptId":"3","start":{"lineNumber":7,"columnNumber":0},"end":{"lineNumber":8,"columnNumber":0}}]}) +Paused with reason: step + debugger; + let x = #1; + return x; + +stepOut({}) +Paused with reason: step + callee(); + let y = #2; + return y; + + +Test: stepOut after resume after stepInto with skipList +Paused with reason: other +function callee() { + #debugger; + let x = 1; + +stepInto({"skipList":[{"scriptId":"3","start":{"lineNumber":7,"columnNumber":0},"end":{"lineNumber":8,"columnNumber":0}}]}) +Paused with reason: step + debugger; + let x = #1; + return x; + +Paused with reason: other +function callee() { + #debugger; + let x = 1; + +stepOut({}) +Paused with reason: step + callee(); + let y = #2; + return y; + + +Test: stepInto with skipList after stepInto with skipList uses the new skipList +Paused with reason: other +function callee() { + #debugger; + let x = 1; + +stepInto({"skipList":[{"scriptId":"3","start":{"lineNumber":2,"columnNumber":0},"end":{"lineNumber":3,"columnNumber":0}}]}) +Paused with reason: step + let x = 1; + return x;# +} + +stepInto({"skipList":[{"scriptId":"3","start":{"lineNumber":7,"columnNumber":0},"end":{"lineNumber":8,"columnNumber":0}}]}) +Paused with reason: step + let y = 2; + return y;# +} + diff --git a/deps/v8/test/inspector/debugger/stepping-with-stale-skip-list.js b/deps/v8/test/inspector/debugger/stepping-with-stale-skip-list.js new file mode 100644 index 000000000000..c04016dd7bc3 --- /dev/null +++ b/deps/v8/test/inspector/debugger/stepping-with-stale-skip-list.js @@ -0,0 +1,84 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that the skipList of a step does not outlive that step.'); + +const source = [ + 'function callee() {', // 0 + ' debugger;', // 1 + ' let x = 1;', // 2 + ' return x;', // 3 + '}', // 4 + 'function test() {', // 5 + ' callee();', // 6 + ' let y = 2;', // 7 + ' return y;', // 8 + '}', // 9 +].join('\n'); + +contextGroup.addScript(source); +session.setupScriptMap(); + +function range(scriptId, startLine, startColumn, endLine, endColumn) { + return { + scriptId, + start: {lineNumber: startLine, columnNumber: startColumn}, + end: {lineNumber: endLine, columnNumber: endColumn}, + }; +} + +async function logPause(paused) { + const {reason, callFrames} = paused.params; + InspectorTest.log(`Paused with reason: ${reason}`); + await session.logSourceLocation(callFrames[0].location); +} + +let evaluation; + +// Runs test() until the `debugger` statement in callee(). +async function startTest() { + evaluation = Protocol.Runtime.evaluate({expression: 'test()'}); + await logPause(await Protocol.Debugger.oncePaused()); +} + +async function finishTest() { + await Protocol.Debugger.resume(); + await evaluation; +} + +async function step(action, args) { + InspectorTest.log(`${action}(${JSON.stringify(args)})`); + Protocol.Debugger[action](args); + await logPause(await Protocol.Debugger.oncePaused()); +} + +(async function() { + Protocol.Debugger.enable(); + const {params: {scriptId}} = await Protocol.Debugger.onceScriptParsed(); + const letYRange = range(scriptId, 7, 0, 8, 0); + + InspectorTest.log('\nTest: stepOut after stepInto with skipList'); + await startTest(); + await step('stepInto', {skipList: [letYRange]}); + await step('stepOut', {}); + await finishTest(); + + InspectorTest.log('\nTest: stepOut after resume after stepInto with skipList'); + await startTest(); + await step('stepInto', {skipList: [letYRange]}); + await finishTest(); + await startTest(); + await step('stepOut', {}); + await finishTest(); + + InspectorTest.log('\nTest: stepInto with skipList after stepInto with ' + + 'skipList uses the new skipList'); + await startTest(); + await step('stepInto', {skipList: [range(scriptId, 2, 0, 3, 0)]}); + await step('stepInto', {skipList: [letYRange]}); + await finishTest(); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/tdz-modules-scopes-expected.txt b/deps/v8/test/inspector/debugger/tdz-modules-scopes-expected.txt index 5400273ca355..0188e12f2359 100644 --- a/deps/v8/test/inspector/debugger/tdz-modules-scopes-expected.txt +++ b/deps/v8/test/inspector/debugger/tdz-modules-scopes-expected.txt @@ -8,6 +8,8 @@ Debug break Debug break Scope type: local Scope type: module + moduleLet : <value_unavailable> + moduleConst : <value_unavailable> exportedModuleLet : <value_unavailable> exportedModuleConst : <value_unavailable> Debug break @@ -19,6 +21,8 @@ Debug break Debug break Scope type: local Scope type: module + moduleLet : <value_unavailable> + moduleConst : <value_unavailable> exportedModuleLet : 1 exportedModuleConst : 2 Debug break @@ -32,6 +36,8 @@ Debug break Scope type: module exportedModuleLet : 1 exportedModuleConst : 2 + moduleLet : <value_unavailable> + moduleConst : <value_unavailable> Debug break Scope type: module exportedModuleLet : 1 @@ -43,3 +49,5 @@ Debug break Scope type: module exportedModuleLet : 1 exportedModuleConst : 2 + moduleLet : <value_unavailable> + moduleConst : <value_unavailable> diff --git a/deps/v8/test/inspector/debugger/tdz-scopes-expected.txt b/deps/v8/test/inspector/debugger/tdz-scopes-expected.txt index 1e7046549f01..a9af73838b6f 100644 --- a/deps/v8/test/inspector/debugger/tdz-scopes-expected.txt +++ b/deps/v8/test/inspector/debugger/tdz-scopes-expected.txt @@ -11,6 +11,8 @@ Debug break Debug break Scope type: local Scope type: block + blockLet : <value_unavailable> + blockConst : <value_unavailable> contextBlockLet : <value_unavailable> contextBlockConst : <value_unavailable> Scope type: script @@ -28,6 +30,8 @@ Debug break Debug break Scope type: local Scope type: block + blockLet : <value_unavailable> + blockConst : <value_unavailable> contextBlockLet : 3 contextBlockConst : 4 Scope type: script diff --git a/deps/v8/test/inspector/debugger/untrusted-terminate-on-resume-expected.txt b/deps/v8/test/inspector/debugger/untrusted-terminate-on-resume-expected.txt new file mode 100644 index 000000000000..4af942d6da96 --- /dev/null +++ b/deps/v8/test/inspector/debugger/untrusted-terminate-on-resume-expected.txt @@ -0,0 +1,26 @@ +Untrusted sessions must not terminate execution via Debugger.resume({terminateOnResume:true}) +Runtime.terminateExecution on untrusted session: +{ + error : { + code : -32000 + message : Runtime.terminateExecution is not allowed for untrusted clients + } + id : <messageId> +} +Debugger.resume({terminateOnResume:true}): +{ + error : { + code : -32000 + message : `terminateOnResume` is not allowed for untrusted clients + } + id : <messageId> +} +{ + id : <messageId> + result : { + result : { + type : boolean + value : true + } + } +} diff --git a/deps/v8/test/inspector/debugger/untrusted-terminate-on-resume.js b/deps/v8/test/inspector/debugger/untrusted-terminate-on-resume.js new file mode 100644 index 000000000000..3b520b6bb568 --- /dev/null +++ b/deps/v8/test/inspector/debugger/untrusted-terminate-on-resume.js @@ -0,0 +1,29 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +InspectorTest.start( + 'Untrusted sessions must not terminate execution via ' + + 'Debugger.resume({terminateOnResume:true})'); + +(async () => { + const contextGroup = new InspectorTest.ContextGroup(); + const session = contextGroup.connect(/* isFullyTrusted */ false); + const {Protocol} = session; + + await Protocol.Debugger.enable(); + + InspectorTest.log('Runtime.terminateExecution on untrusted session:'); + InspectorTest.logMessage(await Protocol.Runtime.terminateExecution()); + + const evaluated = Protocol.Runtime.evaluate( + {expression: `globalThis.ran = false; debugger; globalThis.ran = true;`}); + await Protocol.Debugger.oncePaused(); + InspectorTest.log('Debugger.resume({terminateOnResume:true}):'); + InspectorTest.logMessage( + await Protocol.Debugger.resume({terminateOnResume: true})); + await Protocol.Debugger.resume(); + InspectorTest.logMessage(await evaluated); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap-expected.txt b/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap-expected.txt index cf184168410c..95e3d4e00291 100644 --- a/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap-expected.txt +++ b/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap-expected.txt @@ -5,10 +5,12 @@ Instantiating. Calling trapping function. Paused at: --- 0 --- -Script wasm://wasm/c24ede22 byte offset 58: Wasm opcode 0x28 (kExprI32LoadMem) +Script wasm://wasm/f7d6287a byte offset 89: Wasm opcode 0x28 (kExprI32LoadMem) - scope (wasm-expression-stack): - stack: [42 (i32)] + stack: [42 (i32), 11 (i32), 3.5 (f64), Struct ((ref $canon32))] - scope (local): + $var0: 10 (i32) + $var1: 2.5 (f64) - scope (module): instance: <module-scope> module: <module-scope> @@ -16,7 +18,7 @@ Script wasm://wasm/c24ede22 byte offset 58: Wasm opcode 0x28 (kExprI32LoadMem) memories: <module-scope> --- 1 --- try { - instance.exports.#trigger_oob_trap(); + instance.exports.#trigger_oob_trap(10, 2.5); } catch (e) { --- 2 --- diff --git a/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap.js b/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap.js index 4c486acc4a31..20edbf3c6c28 100644 --- a/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap.js +++ b/deps/v8/test/inspector/debugger/wasm-inspect-inline-trap.js @@ -9,13 +9,26 @@ const {session, contextGroup, Protocol} = session.setupScriptMap(); const builder = new WasmModuleBuilder(); +const struct_type = builder.addStruct([makeField(kWasmI32, false)]); builder.addMemory(1, 1); -builder.addFunction('trigger_oob_trap', makeSig([], [kWasmI32])) +builder + .addFunction('trigger_oob_trap', makeSig([kWasmI32, kWasmF64], [kWasmI32])) .addBody([ - ...wasmI32Const(42), // constant to keep on the expression stack - ...wasmI32Const(100000), // highly out of bounds index + ...wasmI32Const(42), // constant on the stack + kExprLocalGet, 0, // GP register local + ...wasmI32Const(1), + kExprI32Add, // GP register on the stack + kExprLocalGet, 1, // FP register local + ...wasmF64Const(1.0), + kExprF64Add, // FP register on the stack + ...wasmI32Const(99), + kGCPrefix, kExprStructNew, struct_type, // tagged reference in register + ...wasmI32Const(100000), // highly out of bounds index kExprI32LoadMem, 0, 0, - kExprDrop // drop the loaded value, leaving only 42 + kExprDrop, + kExprDrop, + kExprDrop, + kExprDrop ]) .exportFunc(); @@ -50,7 +63,7 @@ Protocol.Debugger.onPaused(async msg => { var properties = await Protocol.Runtime.getProperties( {'objectId': scope.object.objectId}); for (let {name, value} of properties.result.result) { - let valStr = value.value !== undefined ? value.value : JSON.stringify(value); + let valStr = await WasmInspectorTest.getWasmValue(value); InspectorTest.log(` ${name}: ${valStr}`); } } @@ -63,7 +76,7 @@ Protocol.Debugger.onPaused(async msg => { function call_trap() { try { - instance.exports.trigger_oob_trap(); + instance.exports.trigger_oob_trap(10, 2.5); } catch (e) { e.stack; } diff --git a/deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry-expected.txt b/deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry-expected.txt new file mode 100644 index 000000000000..f62d8396e25b --- /dev/null +++ b/deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry-expected.txt @@ -0,0 +1,8 @@ +Tests setting a Wasm breakpoint at columnNumber -1. +{ + error : { + code : -32000 + message : Could not resolve breakpoint + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry.js b/deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry.js new file mode 100644 index 000000000000..5a915b6778c0 --- /dev/null +++ b/deps/v8/test/inspector/debugger/wasm-set-breakpoint-on-entry.js @@ -0,0 +1,24 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Tests setting a Wasm breakpoint at columnNumber -1.'); + +(async () => { + await Protocol.Debugger.enable(); + const scriptParsedPromise = Protocol.Debugger.onceScriptParsed(2); + await Protocol.Runtime.evaluate({ + expression: + 'new WebAssembly.Module(new Uint8Array([0, 0x61, 0x73, 0x6d, 1, 0, 0, 0]));', + }); + const [, {params: {scriptId}}] = await scriptParsedPromise; + InspectorTest.logMessage(await Protocol.Debugger.setBreakpoint({ + location: { + scriptId, + lineNumber: 0, + columnNumber: -1, // -1 is not a valid regular breakpoint position. + }, + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/inspector-test.cc b/deps/v8/test/inspector/inspector-test.cc index d655375be31e..d15cf6eb935a 100644 --- a/deps/v8/test/inspector/inspector-test.cc +++ b/deps/v8/test/inspector/inspector-test.cc @@ -282,14 +282,13 @@ class UtilsExtension : public InspectorIsolateData::SetupGlobalTask { std::vector<uint16_t> details = ToVector(info.GetIsolate(), info[2].As<v8::String>()); int context_group_id = info[0].As<v8::Int32>()->Value(); - RunSyncTask(backend_runner_, - [&context_group_id, &reason, - &details](InspectorIsolateData* data) { - data->SchedulePauseOnNextStatement( - context_group_id, - v8_inspector::StringView(reason.data(), reason.size()), - v8_inspector::StringView(details.data(), details.size())); - }); + RunSyncTask(backend_runner_, [&context_group_id, &reason, + &details](InspectorIsolateData* data) { + data->SchedulePauseOnNextStatement( + context_group_id, + v8_inspector::StringView(reason.data(), reason.size()), + v8_inspector::StringView(details.data(), details.size())); + }); } static void CancelPauseOnNextStatement( @@ -367,12 +366,12 @@ class UtilsExtension : public InspectorIsolateData::SetupGlobalTask { std::vector<uint16_t> name = ToVector(info.GetIsolate(), info[1].As<v8::String>()); - RunSyncTask(backend_runner_, [&context_group_id, - name](InspectorIsolateData* data) { - CHECK(data->CreateContext( - context_group_id, - v8_inspector::StringView(name.data(), name.size()))); - }); + RunSyncTask(backend_runner_, + [&context_group_id, name](InspectorIsolateData* data) { + CHECK(data->CreateContext( + context_group_id, + v8_inspector::StringView(name.data(), name.size()))); + }); } static void ResetContextGroup( @@ -985,14 +984,28 @@ int InspectorTestMain(int argc, char* argv[]) { v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::V8::InitializeExternalStartupData(argv[0]); v8::V8::Initialize(); - // Enable the WebAssembly trap handler in inspector-test to match d8/Chrome. - v8::V8::EnableWebAssemblyTrapHandler(true); + bool enable_wasm_trap_handler = true; + for (int i = 1; i < argc; ++i) { + if (argv[i] == nullptr) continue; + if (strcmp(argv[i], "--wasm-trap-handler") == 0) { + enable_wasm_trap_handler = true; + argv[i] = nullptr; + } else if (strcmp(argv[i], "--no-wasm-trap-handler") == 0) { + enable_wasm_trap_handler = false; + argv[i] = nullptr; + } + } + if (enable_wasm_trap_handler) { + // Enable the WebAssembly trap handler in inspector-test to match d8/Chrome. + v8::V8::EnableWebAssemblyTrapHandler(true); + } i::DisableEmbeddedBlobRefcounting(); base::Semaphore ready_semaphore(0); StartupData startup_data = {nullptr, 0}; for (int i = 1; i < argc; ++i) { + if (argv[i] == nullptr) continue; if (strcmp(argv[i], "--embed") == 0) { argv[i++] = nullptr; printf("Embedding script '%s'\n", argv[i]); diff --git a/deps/v8/test/inspector/inspector.status b/deps/v8/test/inspector/inspector.status index 4041d4a50527..cb1f5f712e93 100644 --- a/deps/v8/test/inspector/inspector.status +++ b/deps/v8/test/inspector/inspector.status @@ -31,6 +31,14 @@ 'runtime/regress-520052954': [PASS, ['not asan', SKIP]], 'runtime/regress-520052954-2': [PASS, ['not asan', SKIP]], 'runtime/regress-520052954-3': [PASS, ['not asan', SKIP]], + + # Sandbox regression tests requiring the memory corruption API. + 'regress/regress-502337304': [PASS, ['not memory_corruption_api', SKIP]], + 'regress/regress-507490539': [PASS, ['not memory_corruption_api', SKIP]], + 'regress/regress-513048538': [PASS, ['not memory_corruption_api', SKIP]], + 'regress/regress-568338771': [PASS, ['not memory_corruption_api', SKIP]], + 'regress/regress-570558888': [PASS, ['not memory_corruption_api', SKIP]], + 'regress/regress-crbug-568986689': [PASS, ['not memory_corruption_api', SKIP]], }], # ALWAYS ############################################################################## @@ -74,7 +82,25 @@ 'debugger/wasm-*': [SKIP], 'cpu-profiler/console-profile-wasm': [SKIP], 'runtime/get-properties': [SKIP], + 'regress/regress-502287689': [SKIP], + 'regress/regress-513413942': [SKIP], + 'regress/regress-519715438': [SKIP], + 'regress/regress-521715545': [SKIP], + 'regress/regress-526163463': [SKIP], + 'regress/regress-527985808': [SKIP], + 'regress/regress-529880019': [SKIP], + 'regress/regress-530658019': [SKIP], + 'regress/regress-534275413': [SKIP], + 'regress/regress-534579660': [SKIP], + 'regress/regress-537219980': [SKIP], + 'regress/regress-569886678': [SKIP], + 'regress/regress-570538338': [SKIP], + 'regress/regress-571965281': [SKIP], + 'regress/regress-572276045': [SKIP], + 'regress/regress-572403047': [SKIP], + 'regress/regress-572834323': [SKIP], 'regress/regress-crbug-349248170': [SKIP], + 'regress/regress-nested-stack-switch-catch': [SKIP], }], # not has_webassembly or variant == jitless ############################################################################## @@ -117,6 +143,9 @@ 'debugger/wasm-stepping-with-source-map': [SKIP], # Generic wasm-to-js wrapper must be enabled. 'cpu-profiler/console-profile-wasm': [SKIP], + # Wasm code coverage is not supported yet. + 'regress/regress-521715545': [SKIP], + 'regress/regress-526163463': [SKIP], }], # 'arch == s390x or arch == ppc64' ############################################################################## @@ -254,4 +283,11 @@ 'debugger/wasm-jspi-async-stack': [SKIP], }], # (arch != x64 and arch != arm64 and arch != ia32 and arch != arm and arch != ppc64 and arch != s390x) +############################################################################## +['sandbox_hardware_support', { + # Wasm code coverage is not currently supported. + 'regress/regress-521715545': [SKIP], + 'regress/regress-526163463': [SKIP], +}], # sandbox_hardware_support + ] diff --git a/deps/v8/test/inspector/isolate-data.cc b/deps/v8/test/inspector/isolate-data.cc index 49a134bd35c7..e2603df09d55 100644 --- a/deps/v8/test/inspector/isolate-data.cc +++ b/deps/v8/test/inspector/isolate-data.cc @@ -128,10 +128,10 @@ bool InspectorIsolateData::CreateContext(int context_group_id, v8::Local<v8::Context> context = v8::Context::New(isolate_.get(), nullptr, global_template); if (context.IsEmpty()) return false; - context->SetAlignedPointerInEmbedderData(kIsolateDataIndex, this, - kInspectorIsolateDataTag); + context->SetAlignedPointerInEmbedderDataV2(kIsolateDataIndex, this, + kInspectorIsolateDataTag); // Should be 2-byte aligned. - context->SetAlignedPointerInEmbedderData( + context->SetAlignedPointerInEmbedderDataV2( kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2), kContextGroupIdTag); contexts_[context_group_id].emplace_back(isolate_.get(), context); diff --git a/deps/v8/test/inspector/private-class-member-inspector-test.js b/deps/v8/test/inspector/private-class-member-inspector-test.js index 6cdc988cd32f..0b87a0aa5a4d 100644 --- a/deps/v8/test/inspector/private-class-member-inspector-test.js +++ b/deps/v8/test/inspector/private-class-member-inspector-test.js @@ -53,6 +53,9 @@ ${pause}`; async function testAllPrivateMembers(type, runAndLog) { const receiver = getTestReceiver(type); InspectorTest.log('Checking private fields'); + await runAndLog(`#field in ${receiver}`); + await runAndLog(`#nonExistent in ${receiver}`); + await runAndLog(`#field in 1`); await runAndLog(`${receiver}.#field`); await runAndLog(`${receiver}.#field = 1`); await runAndLog(`${receiver}.#field`); @@ -64,6 +67,7 @@ async function testAllPrivateMembers(type, runAndLog) { await runAndLog(`${receiver}.#field`); InspectorTest.log('Checking private getter-only accessors'); + await runAndLog(`#getterOnly in ${receiver}`); await runAndLog(`${receiver}.#getterOnly`); await runAndLog(`${receiver}.#getterOnly = 1`); await runAndLog(`${receiver}.#getterOnly++`); @@ -71,6 +75,7 @@ async function testAllPrivateMembers(type, runAndLog) { await runAndLog(`${receiver}.#getterOnly`); InspectorTest.log('Checking private setter-only accessors'); + await runAndLog(`#setterOnly in ${receiver}`); await runAndLog(`${receiver}.#setterOnly`); await runAndLog(`${receiver}.#setterOnly = 1`); await runAndLog(`${receiver}.#setterOnly++`); @@ -78,6 +83,7 @@ async function testAllPrivateMembers(type, runAndLog) { await runAndLog(`${receiver}.#field`); InspectorTest.log('Checking private accessors'); + await runAndLog(`#accessor in ${receiver}`); await runAndLog(`${receiver}.#accessor`); await runAndLog(`${receiver}.#accessor = 1`); await runAndLog(`${receiver}.#field`); @@ -89,6 +95,7 @@ async function testAllPrivateMembers(type, runAndLog) { await runAndLog(`${receiver}.#field`); InspectorTest.log('Checking private methods'); + await runAndLog(`#method in ${receiver}`); await runAndLog(`${receiver}.#method`); await runAndLog(`${receiver}.#method = 1`); await runAndLog(`${receiver}.#method++`); @@ -97,10 +104,15 @@ async function testAllPrivateMembers(type, runAndLog) { } async function testConflictingPrivateMembers(runAndLog) { + await runAndLog(`#name in (new ClassWithField)`); await runAndLog(`(new ClassWithField).#name`); + await runAndLog(`#name in (new ClassWithMethod)`); await runAndLog(`(new ClassWithMethod).#name`); + await runAndLog(`#name in (new ClassWithAccessor)`); await runAndLog(`(new ClassWithAccessor).#name`); + await runAndLog(`#name in StaticClass`); await runAndLog(`StaticClass.#name`); + await runAndLog(`#name in (new StaticClass)`); await runAndLog(`(new StaticClass).#name`); } diff --git a/deps/v8/test/inspector/regress/regress-502287689-expected.txt b/deps/v8/test/inspector/regress/regress-502287689-expected.txt new file mode 100644 index 000000000000..828bc80e00d3 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-502287689-expected.txt @@ -0,0 +1,12 @@ +Regression test for crbug.com/502287689. +Setting breakpoint at Y (offset 34)... +Calling f(7)... +Paused! +Removing breakpoint at Y: 4:0:34:5 +Setting breakpoint at X... +Resuming... +Paused! +Removing breakpoint at Y: 4:0:34:5 +Setting breakpoint at X... +Resuming... +Finished. diff --git a/deps/v8/test/inspector/regress/regress-502287689.js b/deps/v8/test/inspector/regress/regress-502287689.js new file mode 100644 index 000000000000..c8e7da6731b1 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-502287689.js @@ -0,0 +1,104 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/502287689.'); + +contextGroup.addScript(` +const bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x06, // section length 6 + 0x01, 0x60, // types count 1: kind: func + 0x01, 0x7f, // param count 1: i32 + 0x01, 0x7f, // return count 1: i32 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $f (param i32) (result i32) + + 0x07, // section kind: Export + 0x05, // section length 5 + 0x01, // exports count 1: export # 0 + 0x01, // field name length: 1 + 0x66, // field name: f + 0x00, 0x00, // kind: function index: 0 + + 0x0a, // section kind: Code + 0x12, // section length 18 + 0x01, // functions count 1 + // function #0 $f + 0x10, // body size 16 + 0x00, // 0 entries in locals list + 0x41, 0x0a, // i32.const 10 + 0x41, 0x02, // i32.const 2 <-- Y = 34 (relative to module start) + 0x6a, // i32.add + 0x41, 0x03, // i32.const 3 <-- X = 37 + 0x6a, // i32.add + 0x20, 0x00, // local.get $var0 + 0x6d, // i32.div_s + 0x20, 0x00, // local.get $var0 + 0x6d, // i32.div_s + 0x0b, // end +]); +let instance; +`); + +let wasmScriptId = null; +let lastBreakpointId = null; + +Protocol.Debugger.onPaused(async () => { + InspectorTest.log('Paused!'); + + // 5) Remove BP at Y (offset 34) + // This will call UpdateReturnAddresses with a new code that (buggy) + // might not have a source position for Y. + if (lastBreakpointId) { + InspectorTest.log('Removing breakpoint at Y: ' + lastBreakpointId); + await Protocol.Debugger.removeBreakpoint({breakpointId: lastBreakpointId}); + } + + // 6) Set BP at X (offset 37) + // This would be the next step in the two-isolate PoC, but we might have + // already crashed. + InspectorTest.log('Setting breakpoint at X...'); + await Protocol.Debugger.setBreakpoint({ + location: {scriptId: wasmScriptId, lineNumber: 0, columnNumber: 37}, + }); + + // 8) Resume + InspectorTest.log('Resuming...'); + await Protocol.Debugger.resume(); +}); + +(async () => { + // Enable debugger + await Protocol.Debugger.enable(); + + const scriptParsedPromise = Protocol.Debugger.onceScriptParsed(2); + await Protocol.Runtime.evaluate({ + expression: ` + const module = new WebAssembly.Module(bytes); + instance = new WebAssembly.Instance(module); + `, + }); + const [, {params: {scriptId}}] = await scriptParsedPromise; + wasmScriptId = scriptId; + + InspectorTest.log('Setting breakpoint at Y (offset 34)...'); + const bpResult = await Protocol.Debugger.setBreakpoint({ + location: {scriptId: wasmScriptId, lineNumber: 0, columnNumber: 34}, + }); + lastBreakpointId = bpResult.result.breakpointId; + + InspectorTest.log('Calling f(7)...'); + await Protocol.Runtime.evaluate({ + expression: 'instance.exports.f(7)', + }); + InspectorTest.log('Finished.'); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-502337304-expected.txt b/deps/v8/test/inspector/regress/regress-502337304-expected.txt new file mode 100644 index 000000000000..a0a3fb4f90b1 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-502337304-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/502337304 diff --git a/deps/v8/test/inspector/regress/regress-502337304.js b/deps/v8/test/inspector/regress/regress-502337304.js new file mode 100644 index 000000000000..18aae2f7ddc4 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-502337304.js @@ -0,0 +1,58 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-memory-corruption-api --sandbox-testing + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/502337304'); + +contextGroup.addScript(` +const NUM_PARAMS = 60000; +let paramTail = ''; +for (let i = 0; i < NUM_PARAMS; i++) paramTail += ',p' + i; +const padLen = paramTail.length; +const head = 'function victim(a'; +const tail = '){debugger;}'; +const origSource = head + '/*' + 'X'.repeat(padLen - 4) + '*/' + tail; +const corruptSource = head + paramTail + tail; + +// Indirect eval to get a Script object +(0, eval)(origSource); + +function corrupt() { + if (typeof Sandbox === 'undefined') return; + + let victim_addr = Sandbox.getAddressOf(victim); + let view = new DataView(new Sandbox.MemoryView(victim_addr, 32)); + let sfi_ptr = view.getUint32(16, true); + let sfi_addr = sfi_ptr - 1; + + let sfi_view = new DataView(new Sandbox.MemoryView(sfi_addr, 32)); + let script_ptr = sfi_view.getUint32(20, true); + let script_addr = script_ptr - 1; + + let script_view = new DataView(new Sandbox.MemoryView(script_addr, 32)); + let corrupt_source_addr = Sandbox.getAddressOf(corruptSource); + script_view.setUint32(4, corrupt_source_addr | 1, true); +} +`, 0, 0, 'setup.js'); + +Protocol.Debugger.onPaused(async message => { + const callFrameId = message.params.callFrames[0].callFrameId; + await Protocol.Runtime.evaluate({expression: 'corrupt()'}); + await Protocol.Debugger.setVariableValue({ + scopeNumber: 0, + variableName: 'p59999', + newValue: {value: 42}, + callFrameId: callFrameId, + }); + await Protocol.Debugger.resume(); + InspectorTest.completeTest(); +}); + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + Protocol.Runtime.evaluate({expression: 'victim(1);'}); +})(); diff --git a/deps/v8/test/inspector/regress/regress-507490539-expected.txt b/deps/v8/test/inspector/regress/regress-507490539-expected.txt new file mode 100644 index 000000000000..196aa3ac0bc2 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-507490539-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/507490539 diff --git a/deps/v8/test/mjsunit/sandbox/regress-507490539.js b/deps/v8/test/inspector/regress/regress-507490539.js similarity index 77% rename from deps/v8/test/mjsunit/sandbox/regress-507490539.js rename to deps/v8/test/inspector/regress/regress-507490539.js index 5ff4d7b47f14..3aea93e0c736 100644 --- a/deps/v8/test/mjsunit/sandbox/regress-507490539.js +++ b/deps/v8/test/inspector/regress/regress-507490539.js @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --enable-inspector --sandbox-testing +// Flags: --sandbox-testing -globalThis.receive = function(message) { - print(message); -}; +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/507490539'); const expression = String.raw` -const print = (...args) => console.log(...args); +const print = (...args) => {}; const mem = new DataView(new Sandbox.MemoryView(0, 0x100000000)); function r32(addr) { @@ -151,16 +150,16 @@ function chooseUnmappedTarget() { throw new Error("could not choose an out-of-sandbox target"); } +for (let i = 0; i < 200; i++) { + findCommandLineAccessorInfo("$0"); +} const {accessorInfo, nameTagged, key} = findCommandLineAccessorInfo("$0"); -// Real FixedArray ["$0"] used by accessorSetterCallback's installed-methods -// loop. The first element must StrictEquals the accessor name. const methodsCarrier = [key]; const methodsElements = findArrayElements( methodsCarrier, ({length, first}) => length > 0 && first === nameTagged); +isTaggedHeapObject((methodsElements.offset + 8) | 1); -// A large in-sandbox FixedArray gives us stable writable bytes for fake C++ -// objects and fake native handle slots. const holder = {}; const arenaCarrier = new Array(512).fill(holder); const arenaElements = findArrayElements( @@ -173,27 +172,11 @@ const methodsGlobalSlot = (arena + 0x380) >>> 0; const fakeData = new ArrayBuffer(8); const target = chooseUnmappedTarget(); -// A v8::Global<T> stores a native pointer to a slot containing the full tagged -// object address. Put a fake persistent slot inside sandbox memory. w64(methodsGlobalSlot, full(methodsElements.tagged)); -// CommandLineAPIScope layout on this x64 build: -// +0x00 v8::Isolate* m_isolate -// +0x08 Global<Context> m_context -// +0x10 Global<Object> m_commandLineAPI -// +0x18 Global<Object> m_global -// +0x20 Global<PrimitiveArray> m_installedMethods -// +0x28 Global<ArrayBuffer> m_thisReference w64(fakeScope + 0x00, full(fakeIsolate)); w64(fakeScope + 0x20, full(methodsGlobalSlot)); -// Isolate::isolate_data_.handle_scope_data_ offsets in this x64 release build: -// +0x230 Address* next -// +0x238 Address* limit -// -// Local handle creation will read next/limit from the fake isolate, update -// next in sandbox memory, then perform *next = value at the out-of-sandbox -// target below. This makes the crash a real write violation. w64(fakeIsolate + 0x230, target); w64(fakeIsolate + 0x238, target + 0x100n); @@ -208,26 +191,15 @@ print("fakeScope=" + hex64(full(fakeScope))); print("fakeIsolate=" + hex64(full(fakeIsolate))); print("target=" + hex64(target)); -// AccessorInfo layout in this pointer-compressed build: -// +0 map -// +4 data -// +8 name -// +12 getter external-pointer handle -// +16 setter external-pointer handle -// +20 flags w32(accessorInfo + 4, (raw(fakeData) + 1) >>> 0); -// Trigger V8Console::CommandLineAPIScope::accessorSetterCallback. The forged -// scope survives through installedMethods(), then Local::New creates an API -// handle through the forged isolate's HandleScopeData and writes to target. globalThis.$0 = 13; `; -send(JSON.stringify({ - id: 1, - method: 'Runtime.evaluate', - params: { +(async () => { + await Protocol.Runtime.evaluate({ includeCommandLineAPI: true, expression, - }, -})); + }); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-513048538-expected.txt b/deps/v8/test/inspector/regress/regress-513048538-expected.txt new file mode 100644 index 000000000000..9f08e6c12945 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-513048538-expected.txt @@ -0,0 +1,9 @@ +Regression test for crbug.com/513048538 +{ + id : <messageId> + result : { + result : { + type : undefined + } + } +} diff --git a/deps/v8/test/mjsunit/sandbox/regress-513048538.js b/deps/v8/test/inspector/regress/regress-513048538.js similarity index 94% rename from deps/v8/test/mjsunit/sandbox/regress-513048538.js rename to deps/v8/test/inspector/regress/regress-513048538.js index e107e352ffc1..ca2105b137cc 100644 --- a/deps/v8/test/mjsunit/sandbox/regress-513048538.js +++ b/deps/v8/test/inspector/regress/regress-513048538.js @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --enable-inspector --sandbox-testing +// Flags: --sandbox-testing -globalThis.receive = function(message) { - print(message); -}; +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/513048538'); const expression = String.raw` const print = (...args) => console.log(...args); @@ -147,11 +146,10 @@ if (!foundData) { } `; -send(JSON.stringify({ - id: 1, - method: 'Runtime.evaluate', - params: { +(async () => { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ includeCommandLineAPI: true, expression, - }, -})); + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-513413942-expected.txt b/deps/v8/test/inspector/regress/regress-513413942-expected.txt new file mode 100644 index 000000000000..f6e90ea60a0e --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-513413942-expected.txt @@ -0,0 +1,12 @@ +Regression test for crbug.com/513413942. +{ + id : <messageId> + result : { + actualLocation : { + columnNumber : 57 + lineNumber : 0 + scriptId : <scriptId> + } + breakpointId : <breakpointId> + } +} diff --git a/deps/v8/test/inspector/regress/regress-513413942.js b/deps/v8/test/inspector/regress/regress-513413942.js new file mode 100644 index 000000000000..48228ea7e25c --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-513413942.js @@ -0,0 +1,77 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --no-wasm-tier-up +// Flags: --no-wasm-trap-handler --stress-wasm-memory-moving + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/513413942.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +builder.addMemory(1, 1000); +builder.exportMemoryAs('memory', 0); + +const body = [ + ...wasmI32Const(0), + kExprI32LoadMem, 0, 0, + kExprDrop, + kExprNop, + ...wasmI32Const(0), + ...wasmI32Const(123), + kExprI32StoreMem, 0, 0, +]; + +const target = builder.addFunction('target', kSig_v_v) + .addBody(body) + .exportFunc(); + +const module_bytes = builder.toBuffer(); +const nop_offset = target.body_offset + 6; +`); + +Protocol.Debugger.onPaused(() => Protocol.Debugger.resume()); + +(async () => { + await Protocol.Debugger.enable(); + + const scriptParsedPromise = Protocol.Debugger.onceScriptParsed(2); + await Protocol.Runtime.evaluate({ + expression: ` + const module = new WebAssembly.Module(module_bytes); + const instance = new WebAssembly.Instance(module); + globalThis.instance = instance; + globalThis.grown = false; + `, + }); + const [, {params: {scriptId: wasmScriptId}}] = await scriptParsedPromise; + + const {result: {result: {value: nop_offset}}} = + await Protocol.Runtime.evaluate({ + expression: 'nop_offset', + returnByValue: true, + }); + + const condition = `(function() { + if (!globalThis.grown) { + globalThis.instance.exports.memory.grow(1); + globalThis.grown = true; + return true; + } + return false; +})()`; + + InspectorTest.logMessage(await Protocol.Debugger.setBreakpoint({ + location: {scriptId: wasmScriptId, lineNumber: 0, columnNumber: nop_offset}, + condition: condition, + })); + + await Protocol.Runtime.evaluate({ + expression: 'instance.exports.target()', + }); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-514561070-expected.txt b/deps/v8/test/inspector/regress/regress-514561070-expected.txt new file mode 100644 index 000000000000..339dad433f8a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-514561070-expected.txt @@ -0,0 +1,9 @@ +Tests that CommandLineAPIScope ignores a getter on Array.prototype[0]. +{ + id : <messageId> + result : { + result : { + type : undefined + } + } +} diff --git a/deps/v8/test/inspector/regress/regress-514561070.js b/deps/v8/test/inspector/regress/regress-514561070.js new file mode 100644 index 000000000000..aab4eeee9fa1 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-514561070.js @@ -0,0 +1,20 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests that CommandLineAPIScope ignores a getter on Array.prototype[0].'); + +contextGroup.addScript(` +Array.prototype.__defineGetter__(0, function() { + return new Number(); +}); +`); + +(async function test() { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + includeCommandLineAPI: true, + expression: '', + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-516022777-expected.txt b/deps/v8/test/inspector/regress/regress-516022777-expected.txt new file mode 100644 index 000000000000..4b2b13caeb93 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-516022777-expected.txt @@ -0,0 +1,9 @@ +Tests that CommandLineAPI evaluation ignores a setter on Array.prototype[0]. +{ + id : <messageId> + result : { + result : { + type : undefined + } + } +} diff --git a/deps/v8/test/inspector/regress/regress-516022777.js b/deps/v8/test/inspector/regress/regress-516022777.js new file mode 100644 index 000000000000..f5416b7cdf9d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-516022777.js @@ -0,0 +1,22 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests that CommandLineAPI evaluation ignores a setter on Array.prototype[0].'); + +contextGroup.addScript(` +Object.defineProperty(Array.prototype, 0, { + set() { + throw 42; + } +}); +`); + +(async function test() { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + includeCommandLineAPI: true, + expression: '', + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-519715438-expected.txt b/deps/v8/test/inspector/regress/regress-519715438-expected.txt new file mode 100644 index 000000000000..198297dd271b --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-519715438-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/519715438. diff --git a/deps/v8/test/inspector/regress/regress-519715438.js b/deps/v8/test/inspector/regress/regress-519715438.js new file mode 100644 index 000000000000..8aecbe6ef67a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-519715438.js @@ -0,0 +1,75 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-wasm-trap-handler --stress-wasm-memory-moving + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/519715438.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +builder.addMemory(1, 100); +builder.exportMemoryAs('mem'); +const setupIdx = builder.addImport('env', 'setup', kSig_v_v); + +builder.addFunction('vuln', kSig_v_i) + .addLocals(kWasmI32, 1) + .addBody([ + kExprCallFunction, setupIdx, + kExprLoop, kWasmVoid, + kExprI32Const, 4, + ...wasmI32Const(0x41414141), + kExprI32StoreMem, 2, 0, + kExprLocalGet, 1, + kExprI32Const, 1, + kExprI32Add, + kExprLocalTee, 1, + kExprLocalGet, 0, + kExprI32LtS, + kExprBrIf, 0, + kExprEnd, + ]) + .exportFunc(); + +function setup() { + console.log('setup'); + inspector.runNestedMessageLoop(); +} + +const instance = builder.instantiate({env: {setup}}); +const mem = instance.exports.mem; +`); + +let pauseHandled = false; +Protocol.Debugger.onPaused(async () => { + // Called while the optimized Wasm frame is on the stack. + if (!pauseHandled) { + pauseHandled = true; + await Protocol.Runtime.evaluate({expression: 'let r = mem.grow(10);'}); + } + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Runtime.enable(); + + const consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + // Iteration count must be large enough that Turboshaft's loop unrolling + // still leaves a stack-check that fires before all stores complete. + const evalPromise = + Protocol.Runtime.evaluate({expression: 'instance.exports.vuln(100)'}); + + await consolePromise; + // Without Wasm lazy-deopt, this does not replace the optimized frame on + // the stack. + await Protocol.Debugger.enable(); + // Request an API_INTERRUPT. + Protocol.Debugger.pause(); + await Protocol.Runtime.runIfWaitingForDebugger(); + + await evalPromise; + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-521715545-expected.txt b/deps/v8/test/inspector/regress/regress-521715545-expected.txt new file mode 100644 index 000000000000..d7e64c289ab8 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-521715545-expected.txt @@ -0,0 +1,12 @@ +Regression test for crbug.com/521715545. +{ + id : <messageId> + result : { + actualLocation : { + columnNumber : 35 + lineNumber : 0 + scriptId : <scriptId> + } + breakpointId : <breakpointId> + } +} diff --git a/deps/v8/test/inspector/regress/regress-521715545.js b/deps/v8/test/inspector/regress/regress-521715545.js new file mode 100644 index 000000000000..fa3b677b5476 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-521715545.js @@ -0,0 +1,57 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-code-coverage + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/521715545.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +const func = builder.addFunction('main', kSig_v_v) + .addBody([ + kExprI32Const, 0, + kExprI32Const, 1, + kExprI32Add, + kExprDrop + ]) + .exportFunc(); +const buffer = builder.toBuffer(); + +// Offset into the code section for the 'i32.add' instruction. +// The header is 8 bytes, sections are typically 1 byte ID + length. +// WasmModuleBuilder offsets are relative to the start of the buffer. +const offset = func.body_offset + 2; +`); + +(async () => { + await Protocol.Debugger.enable(); + + const scriptParsedPromise = Protocol.Debugger.onceScriptParsed(2); + await Protocol.Runtime.evaluate({ + expression: ` + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module); + `, + }); + const [, {params: {scriptId}}] = await scriptParsedPromise; + + const {result: {result: {value: offset}}} = await Protocol.Runtime.evaluate({ + expression: 'offset', + returnByValue: true, + }); + + InspectorTest.logMessage(await Protocol.Debugger.setBreakpoint({ + location: { + scriptId, + lineNumber: 0, + columnNumber: offset, + }, + })); + + // If we reached here without crashing, the fix works. + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-526163463-expected.txt b/deps/v8/test/inspector/regress/regress-526163463-expected.txt new file mode 100644 index 000000000000..d1948dd152a2 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-526163463-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/526163463. diff --git a/deps/v8/test/inspector/regress/regress-526163463.js b/deps/v8/test/inspector/regress/regress-526163463.js new file mode 100644 index 000000000000..1a9ff9d0076a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-526163463.js @@ -0,0 +1,52 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-code-coverage + +// Pausing the debugger while executing Wasm triggers regeneration of the +// Liftoff debug side table. With --wasm-code-coverage, the regenerated code +// must include coverage instrumentation so its PC offsets match the original +// code. Ensure frame inspection does not crash. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/526163463.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +const setupIdx = builder.addImport('env', 'setup', kSig_v_v); +builder.addFunction('vuln', kSig_v_v) + .addBody([ + kExprCallFunction, setupIdx, + kExprLoop, kWasmVoid, + kExprEnd, + ]) + .exportFunc(); + +function setup() { + console.log('setup'); + inspector.runNestedMessageLoop(); +} + +const instance = builder.instantiate({env: {setup}}); +`); + +Protocol.Debugger.onPaused(() => Protocol.Debugger.resume()); + +(async () => { + await Protocol.Runtime.enable(); + + const consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + const evalPromise = + Protocol.Runtime.evaluate({expression: 'instance.exports.vuln()'}); + + await consolePromise; + await Protocol.Debugger.enable(); + Protocol.Debugger.pause(); + await Protocol.Runtime.runIfWaitingForDebugger(); + + await evalPromise; + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-527985808-expected.txt b/deps/v8/test/inspector/regress/regress-527985808-expected.txt new file mode 100644 index 000000000000..98f6f95fda91 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-527985808-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/527985808. diff --git a/deps/v8/test/inspector/regress/regress-527985808.js b/deps/v8/test/inspector/regress/regress-527985808.js new file mode 100644 index 000000000000..39b6daaa684c --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-527985808.js @@ -0,0 +1,53 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-wasm-trap-handler --stress-wasm-memory-moving + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/527985808.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +function setup() { + console.log('setup'); + inspector.runNestedMessageLoop(); +} + +const builder = new WasmModuleBuilder(); +builder.addMemory(1); +builder.exportMemoryAs('mem'); +const $setup = builder.addImport('env', 'setup', kSig_v_v); +builder.addFunction('vuln', kSig_v_i).addLocals(kWasmI32, 1).addBody([ + kExprCallFunction, $setup, + kExprLoop, kWasmVoid, + kExprI32Const, 4, + kExprI32Const, 0, + kExprI32StoreMem, 0, 0, + kExprEnd]).exportFunc(); + +const instance = builder.instantiate({ env: {setup} }); +const memory = instance.exports.mem; +`); + +Protocol.Debugger.onPaused(async () => { + await Protocol.Runtime.evaluate({expression: 'memory.grow(10);'}); + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Runtime.enable(); + + const consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + const evalPromise = + Protocol.Runtime.evaluate({expression: 'instance.exports.vuln()'}); + + await consolePromise; + await Protocol.Debugger.enable(); + Protocol.Debugger.pause(); + await Protocol.Runtime.runIfWaitingForDebugger(); + + await evalPromise; + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-529880019-expected.txt b/deps/v8/test/inspector/regress/regress-529880019-expected.txt new file mode 100644 index 000000000000..386efe8dc348 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-529880019-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/529880019. diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-529880019.js b/deps/v8/test/inspector/regress/regress-529880019.js similarity index 52% rename from deps/v8/test/mjsunit/regress/wasm/regress-529880019.js rename to deps/v8/test/inspector/regress/regress-529880019.js index 630408103deb..2c96d215a734 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-529880019.js +++ b/deps/v8/test/inspector/regress/regress-529880019.js @@ -2,27 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --enable-inspector --no-wasm-trap-handler --stress-wasm-memory-moving --no-liftoff +// Flags: --no-wasm-trap-handler --stress-wasm-memory-moving --no-liftoff -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/529880019.'); -let debugCommandId = 0; -function sendDebugCommand(cmd) { - send(JSON.stringify({ - id: ++debugCommandId, - method: cmd, - })); -} - -globalThis.handleInspectorMessage = function() { - // Grow memory and relocate it (via --stress-wasm-memory-moving). - instance.exports.mem.grow(1); - sendDebugCommand('Debugger.resume'); -}; +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); +contextGroup.addScript(` function setup() { - sendDebugCommand('Debugger.enable'); - sendDebugCommand('Debugger.pause'); + console.log('setup'); + inspector.runNestedMessageLoop(); } const builder = new WasmModuleBuilder(); @@ -48,4 +38,26 @@ builder.addFunction('main', kSig_v_v) ]).exportFunc(); const instance = builder.instantiate({ env: {setup} }); -instance.exports.main(); +`); + +Protocol.Debugger.onPaused(async () => { + // Grow memory and relocate it (via --stress-wasm-memory-moving). + await Protocol.Runtime.evaluate({expression: 'instance.exports.mem.grow(1);'}); + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Runtime.enable(); + + const consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + const evalPromise = + Protocol.Runtime.evaluate({expression: 'instance.exports.main()'}); + + await consolePromise; + await Protocol.Debugger.enable(); + Protocol.Debugger.pause(); + await Protocol.Runtime.runIfWaitingForDebugger(); + + await evalPromise; + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-530658019-expected.txt b/deps/v8/test/inspector/regress/regress-530658019-expected.txt new file mode 100644 index 000000000000..47f3ee81319c --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-530658019-expected.txt @@ -0,0 +1,2 @@ +Regression test for crbug.com/530658019. +view[1]: 0x41414141 diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-530658019.js b/deps/v8/test/inspector/regress/regress-530658019.js similarity index 52% rename from deps/v8/test/mjsunit/regress/wasm/regress-530658019.js rename to deps/v8/test/inspector/regress/regress-530658019.js index 9cf5b67fea85..6de2b8f6249e 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-530658019.js +++ b/deps/v8/test/inspector/regress/regress-530658019.js @@ -2,28 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --enable-inspector --no-wasm-trap-handler +// Flags: --allow-natives-syntax --no-wasm-trap-handler // Flags: --stress-wasm-memory-moving --no-wasm-inlining -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/530658019.'); -let cdpId = 0; -function cdp(method, params) { - send(JSON.stringify({id: ++cdpId, method, params: params || {}})); -} - -let pauseHandled = false; -globalThis.handleInspectorMessage = function() { - // d8 calls this from runMessageLoopOnPause while `inner`'s Turboshaft frame - // is on the stack, paused inside Runtime_WasmStackGuard at the - // kFunctionEntry stack check. - if (!pauseHandled) { - pauseHandled = true; - mem.grow(10); - } - cdp('Debugger.resume'); -}; +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); +contextGroup.addScript(` const builder = new WasmModuleBuilder(); builder.addMemory(1, 100); builder.exportMemoryAs('mem'); @@ -47,14 +34,16 @@ const outer = builder.addFunction('outer', kSig_v_v).exportFunc() let instance; function setup() { - cdp('Debugger.enable'); - // In {d8 --enable-inspector}, inspector protocol messages are processed + console.log('enable'); + inspector.runNestedMessageLoop(); + // In {inspector-test}, inspector protocol messages are processed // synchronously. That's different in Chrome, and the following two // natives calls fake the effect that async processing would have, which is // that {inner} can still be tiered up when it is called. %WasmLeaveDebugging(); %WasmTierUpFunction(instance.exports.inner); - cdp('Debugger.pause'); + console.log('pause'); + inspector.runNestedMessageLoop(); } instance = builder.instantiate({env: {setup, nop: () => {}}}); @@ -62,7 +51,43 @@ const mem = instance.exports.mem; %WasmTierUpFunction(instance.exports.inner); %WasmTierUpFunction(instance.exports.outer); +`); + +let pauseHandled = false; +Protocol.Debugger.onPaused(async () => { + // Called from runMessageLoopOnPause while `inner`'s Turboshaft frame + // is on the stack, paused inside Runtime_WasmStackGuard at the + // kFunctionEntry stack check. + if (!pauseHandled) { + pauseHandled = true; + await Protocol.Runtime.evaluate({expression: 'mem.grow(10);'}); + } + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Runtime.enable(); + + let consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + const evalPromise = Protocol.Runtime.evaluate({ + expression: ` + instance.exports.outer(); + const view = new Int32Array(mem.buffer); + view[1]; + `, + returnByValue: true, + }); + + await consolePromise; + consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + await Protocol.Debugger.enable(); + await Protocol.Runtime.runIfWaitingForDebugger(); + + await consolePromise; + Protocol.Debugger.pause(); + await Protocol.Runtime.runIfWaitingForDebugger(); -instance.exports.outer(); -const view = new Int32Array(mem.buffer); -assertEquals(0x41414141, view[1]); + const {result: {result}} = await evalPromise; + InspectorTest.log(`view[1]: 0x${result.value.toString(16)}`); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-531297707-expected.txt b/deps/v8/test/inspector/regress/regress-531297707-expected.txt new file mode 100644 index 000000000000..d5bd9de3f982 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-531297707-expected.txt @@ -0,0 +1,4 @@ +Tests that deoptimizing the topmost optimized frame on debugger break prevents stale TypedArray length/backing-store accesses. +Paused in hot +Paused in hot +Paused in hot diff --git a/deps/v8/test/inspector/regress/regress-531297707.js b/deps/v8/test/inspector/regress/regress-531297707.js new file mode 100644 index 000000000000..14a9de9b0eb3 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-531297707.js @@ -0,0 +1,51 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests that deoptimizing the topmost optimized frame on debugger break ' + + 'prevents stale TypedArray length/backing-store accesses.'); + +contextGroup.addScript(` +let ab = new ArrayBuffer(0x40000); // 256 KiB +let ta = new Uint32Array(ab); + +let armDetach = false; + +function hot(ta) { + %ScheduleBreak(); + let sum = 0; + const n = ta.length; + for (let i = 0; i < n; i++) { + sum += ta[i]; + if (i > 10) break; // Early exit keeps it fast when deoptimized + } + return sum; +} + +function run() { + %PrepareFunctionForOptimization(hot); + hot(ta); + %OptimizeFunctionOnNextCall(hot); + hot(ta); // Trigger optimization + + %OptimizeFunctionOnNextCall(hot); + armDetach = true; + hot(ta); // Should deopt and not crash +} +`, 0, 0, 'test.js'); + +(async function test() { + await Protocol.Debugger.enable(); + Protocol.Debugger.onPaused(async ({params: {callFrames}}) => { + InspectorTest.log('Paused in ' + callFrames[0].functionName); + await Protocol.Runtime.evaluate({ + expression: 'if (armDetach) ab.transfer(0);', + }); + await Protocol.Debugger.resume(); + }); + await Protocol.Runtime.evaluate({expression: 'run()'}); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-532720981-expected.txt b/deps/v8/test/inspector/regress/regress-532720981-expected.txt new file mode 100644 index 000000000000..b0d47b72d063 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-532720981-expected.txt @@ -0,0 +1 @@ +Tests that sending a malformed protocol message with a throwing global prototype Proxy does not crash. diff --git a/deps/v8/test/inspector/regress/regress-532720981.js b/deps/v8/test/inspector/regress/regress-532720981.js new file mode 100644 index 000000000000..8b29d8306de4 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-532720981.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that sending a malformed protocol message with a throwing global ' + + 'prototype Proxy does not crash.'); + +const source = ` +Object.setPrototypeOf(globalThis, new Proxy({}, { + get(target, prop) { + if (prop === 'receive') { + throw new Error('Triggering error crash during send()!'); + } + return Reflect.get(target, prop); + } +})); +`; + +(async function test() { + contextGroup.addScript(source); + session.sendRawCommand(1, 'test message', () => {}); + await Protocol.Runtime.evaluate({expression: '1'}); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-534275413-expected.txt b/deps/v8/test/inspector/regress/regress-534275413-expected.txt new file mode 100644 index 000000000000..789471561281 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-534275413-expected.txt @@ -0,0 +1,7 @@ +Regression test for crbug.com/534275413. +RangeError: WebAssembly.Memory.grow(): Unable to grow instance memory +RangeError: WebAssembly.Memory.grow(): Unable to grow instance memory +[ + [0] : 42 + [1] : 42 +] diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-534275413.js b/deps/v8/test/inspector/regress/regress-534275413.js similarity index 53% rename from deps/v8/test/mjsunit/regress/wasm/regress-534275413.js rename to deps/v8/test/inspector/regress/regress-534275413.js index b3b325a50192..ae8d569caf2f 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-534275413.js +++ b/deps/v8/test/inspector/regress/regress-534275413.js @@ -2,31 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --enable-inspector --no-wasm-trap-handler --stress-wasm-memory-moving +// Flags: --no-wasm-trap-handler --stress-wasm-memory-moving // Liftoff does not emit loop stack checks (relies on dynamic tiering instead), // hence this test would fail under Liftoff. // Flags: --no-liftoff -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/534275413.'); -let debugCommandId = 0; -function sendDebugCommand(cmd) { - send(JSON.stringify({ - id: ++debugCommandId, - method: cmd, - })); -} - -globalThis.handleInspectorMessage = function() { - // Growing memory 2 should fail because it cannot grow in place (because of - // --stress-wasm-memory-moving). - assertThrows(() => instance.exports.mem2.grow(1), Error, /Unable to grow/); - sendDebugCommand('Debugger.resume'); -}; +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); +contextGroup.addScript(` function setup() { - sendDebugCommand('Debugger.enable'); - sendDebugCommand('Debugger.pause'); + console.log('setup'); + inspector.runNestedMessageLoop(); } const builder = new WasmModuleBuilder(); @@ -57,7 +46,7 @@ builder.addFunction('main', kSig_i_v) kExprI32Sub, kExprLocalTee, 0, // Loop stack check happens here. It will process the pending interrupt - // from setup() on the 1st iteration, triggering handleInspectorMessage. + // from setup() on the 1st iteration, triggering Debugger.paused. // Load from Memory 2 inside the loop. kExprI32Const, 0, kExprI32LoadMem, 0x40, 2, 0, @@ -76,7 +65,45 @@ const instance = builder.instantiate({ env: {setup} }); // Write 42 to Memory 2 before growth. new DataView(instance.exports.mem2.buffer).setInt32(0, 42, true); +`); + +Protocol.Debugger.onPaused(async () => { + // Growing memory 2 should fail because it cannot grow in place (because of + // --stress-wasm-memory-moving). + let {result: {result: res2}} = await Protocol.Runtime.evaluate({ + expression: 'instance.exports.mem2.grow(1)', + }); + InspectorTest.log(res2.description.split('\n')[0]); + // Growing memory 1 should also fail even when it must grow in place (via + // toResizableBuffer()). + let {result: {result: res1}} = await Protocol.Runtime.evaluate({ + expression: ` + instance.exports.mem1.toResizableBuffer(); + instance.exports.mem1.grow(1); + `, + }); + InspectorTest.log(res1.description.split('\n')[0]); + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Runtime.enable(); + + const consolePromise = Protocol.Runtime.onceConsoleAPICalled(); + const evalPromise = Protocol.Runtime.evaluate({ + expression: ` + const result = instance.exports.main(); + [result, new DataView(instance.exports.mem2.buffer).getInt32(0, true)]; + `, + returnByValue: true, + }); + + await consolePromise; + await Protocol.Debugger.enable(); + Protocol.Debugger.pause(); + await Protocol.Runtime.runIfWaitingForDebugger(); -let result = instance.exports.main(); -assertEquals(42, result); -assertEquals(42, new DataView(instance.exports.mem2.buffer).getInt32(0, true)); + const {result: {result}} = await evalPromise; + InspectorTest.logObject(result.value); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-534579660-expected.txt b/deps/v8/test/inspector/regress/regress-534579660-expected.txt new file mode 100644 index 000000000000..29c2f482707a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-534579660-expected.txt @@ -0,0 +1,5 @@ +Regression test for crbug.com/534579660 +Paused in $trigger at column 199 +Breakpoint set: true +Threw WebAssembly.RuntimeError: true +breakpoint_set: true diff --git a/deps/v8/test/inspector/regress/regress-534579660.js b/deps/v8/test/inspector/regress/regress-534579660.js new file mode 100644 index 000000000000..ad5d25e473e6 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-534579660.js @@ -0,0 +1,85 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --expose-gc --liftoff --no-wasm-tier-up + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/534579660'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +function instantiateAndRun() { + let builder = new WasmModuleBuilder(); + let array_type = builder.addArray(kWasmI32); + + // create_array() returns (ref $array_type) + builder.addFunction('create_array', makeSig([], [wasmRefType(array_type)])) + .addBody([kExprI32Const, 5, kGCPrefix, kExprArrayNewDefault, array_type]) + .exportFunc(); + + // trigger(arr_0, arr_1, ..., arr_29) + let num_params = 30; + let params = Array(num_params).fill(wasmRefType(array_type)); + builder.addFunction('trigger', makeSig(params, [kWasmI32])) + .addLocals(kWasmI32, 1) + .addBody([ + ...Array(num_params).fill(0).map((_, i) => [kExprLocalGet, i]).flat(), + ...wasmI32Const(0x7fffffff), // OOB index + kGCPrefix, kExprArrayGet, array_type, kExprLocalSet, num_params, + ...Array(num_params - 1).fill(kExprDrop), kExprLocalGet, num_params + ]) + .exportFunc(); + + let module_bytes = builder.toArray(); + globalThis.body_offset = builder.functions[1].body_offset; + + let instance = builder.instantiate({}); + let arr = instance.exports.create_array(); + + let threw = false; + try { + instance.exports.trigger(...Array(30).fill(arr)); + } catch (e) { + threw = e instanceof WebAssembly.RuntimeError; + } + return threw; +} +`); + +let breakpoint_set = false; +Protocol.Debugger.onPaused(async msg => { + if (!breakpoint_set) { + breakpoint_set = true; + // The top frame is $trigger itself when paused on exception/trap. + const triggerFrame = msg.params.callFrames[0]; + const scriptId = triggerFrame.location.scriptId; + const columnNumber = triggerFrame.location.columnNumber; + InspectorTest.log( + `Paused in ${triggerFrame.functionName} at column ${columnNumber}`); + + // Set breakpoint inside trigger at the exact trapping columnNumber. + const bpResult = await Protocol.Debugger.setBreakpoint({ + location: {scriptId, lineNumber: 0, columnNumber}, + }); + InspectorTest.log('Breakpoint set: ' + ('breakpointId' in bpResult.result)); + + // Once the breakpoint is set, trigger GC while paused to verify the + // safepoint layout. + await Protocol.Runtime.evaluate({expression: 'gc()'}); + } + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + const {result: {result}} = await Protocol.Runtime.evaluate({ + expression: 'instantiateAndRun()', + returnByValue: true, + }); + InspectorTest.log('Threw WebAssembly.RuntimeError: ' + result.value); + InspectorTest.log('breakpoint_set: ' + breakpoint_set); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-537219980-expected.txt b/deps/v8/test/inspector/regress/regress-537219980-expected.txt new file mode 100644 index 000000000000..0d42210d5f04 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-537219980-expected.txt @@ -0,0 +1,5 @@ +Regression test for crbug.com/537219980 +Paused in $trigger at column 206 +Breakpoint set: true +Threw WebAssembly.RuntimeError: true +breakpoint_set: true diff --git a/deps/v8/test/inspector/regress/regress-537219980.js b/deps/v8/test/inspector/regress/regress-537219980.js new file mode 100644 index 000000000000..dc44f480cb63 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-537219980.js @@ -0,0 +1,87 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/537219980'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +function instantiateAndRun() { + let builder = new WasmModuleBuilder(); + let array_type = builder.addArray(kWasmI32); + let sig_index = builder.addType(kSig_i_v); + builder.addTable(kWasmFuncRef, 1, 1); + + builder.addFunction('create_array', makeSig([], [wasmRefType(array_type)])) + .addBody([kExprI32Const, 5, kGCPrefix, kExprArrayNewDefault, array_type]) + .exportFunc(); + + // call_indirect emits multiple OOL traps (table OOB, null func, sig mismatch) + // for the same bytecode offset. Trapping on table OOB pauses in the first OOL + // trap rather than the last one. + let num_params = 30; + let params = Array(num_params).fill(wasmRefType(array_type)); + builder.addFunction('trigger', makeSig(params, [kWasmI32])) + .addLocals(kWasmI32, 1) + .addBody([ + ...Array(num_params).fill(0).map((_, i) => [kExprLocalGet, i]).flat(), + ...wasmI32Const(10), // OOB table index + kExprCallIndirect, sig_index, kTableZero, + kExprLocalSet, num_params, + ...Array(num_params).fill(kExprDrop), + kExprLocalGet, num_params + ]) + .exportFunc(); + + let instance = builder.instantiate({}); + let arr = instance.exports.create_array(); + + let threw = false; + try { + instance.exports.trigger(...Array(num_params).fill(arr)); + } catch (e) { + threw = e instanceof WebAssembly.RuntimeError; + } + return threw; +} +`); + +let breakpoint_set = false; +Protocol.Debugger.onPaused(async msg => { + if (!breakpoint_set) { + breakpoint_set = true; + // The top frame is $trigger itself when paused on exception/trap. + const triggerFrame = msg.params.callFrames[0]; + const scriptId = triggerFrame.location.scriptId; + const columnNumber = triggerFrame.location.columnNumber; + InspectorTest.log( + `Paused in ${triggerFrame.functionName} at column ${columnNumber}`); + + // Set breakpoint inside trigger at the exact trapping columnNumber. + const bpResult = await Protocol.Debugger.setBreakpoint({ + location: {scriptId, lineNumber: 0, columnNumber}, + }); + InspectorTest.log('Breakpoint set: ' + ('breakpointId' in bpResult.result)); + + // Once the breakpoint is set, trigger GC while paused to verify the + // safepoint layout. + await Protocol.Runtime.evaluate({expression: 'gc()'}); + } + await Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + const {result: {result}} = await Protocol.Runtime.evaluate({ + expression: 'instantiateAndRun()', + returnByValue: true, + }); + InspectorTest.log('Threw WebAssembly.RuntimeError: ' + result.value); + InspectorTest.log('breakpoint_set: ' + breakpoint_set); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-568338771-expected.txt b/deps/v8/test/inspector/regress/regress-568338771-expected.txt new file mode 100644 index 000000000000..8f50d0aa83ce --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-568338771-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/568338771 diff --git a/deps/v8/test/inspector/regress/regress-568338771.js b/deps/v8/test/inspector/regress/regress-568338771.js new file mode 100644 index 000000000000..6d7180b9bd56 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-568338771.js @@ -0,0 +1,56 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --allow-natives-syntax + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/568338771'); + +contextGroup.addScript( + `function pad(x) { + return x; +} +%NeverOptimizeFunction(pad); + +const donor = (0, eval)( + '(function donor(a, b) { let x = a; return b; })\\n' + + '//# sourceURL=donor.js'); +donor(1, 2); + +function victim(a, b) { + pad(a); + pad(a); + pad(a); + pad(a); + return b + 1; +} + +function test() { + %PrepareFunctionForOptimization(victim); + victim(1, 2); + %OptimizeFunctionOnNextCall(victim); + victim(1, 2); + + const donor_sfi = + Sandbox.dereferenceTaggedPointerField(donor, 'shared_function_info'); + const victim_sfi = + Sandbox.dereferenceTaggedPointerField(victim, 'shared_function_info'); + const donor_id = Sandbox.readObjectField(donor_sfi, 'unique_id', 32); + Sandbox.corruptObjectField(victim_sfi, 'unique_id', donor_id, 32); + + victim(1, {}); +} +`, + 0, 0, 'test.js'); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setBreakpointByUrl({ + url: 'donor.js', + lineNumber: 0, + columnNumber: 24, + }); + await Protocol.Runtime.evaluate({expression: 'test()'}); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-569886678-expected.txt b/deps/v8/test/inspector/regress/regress-569886678-expected.txt new file mode 100644 index 000000000000..1942a86e3f88 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-569886678-expected.txt @@ -0,0 +1,2 @@ +Regression test for crbug.com/569886678. +Paused on exception: TypeError: Cannot convert a Symbol value to a number diff --git a/deps/v8/test/inspector/regress/regress-569886678.js b/deps/v8/test/inspector/regress/regress-569886678.js new file mode 100644 index 000000000000..94bb5524f86e --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-569886678.js @@ -0,0 +1,50 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-custom-descriptors --wasm-js-interop + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/569886678.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); +contextGroup.addScript( + utils.read('test/mjsunit/wasm/prototype-setup-builder.js')); + +contextGroup.addScript(` +let builder = new WasmModuleBuilder(); +let proto_config = new WasmPrototypeSetupBuilder(builder); + +// We need a JS-to-wasm method wrapper to trigger the defect. +// The defect requires the parameter conversion to fail, so we create a +// method taking an i32 and pass it a Symbol receiver. +let $g_proto = builder.addImportedGlobal('p', 'proto', kWasmExternRef); +let $myMethod = builder.addFunction("myMethod", kSig_v_i).addBody([]); +proto_config.addConfig($g_proto) + .addMethod('myMethod', kWasmMethod, $myMethod); +proto_config.build(); + +const constructors = {}; +const proto = {}; +builder.instantiate({ c: { constructors }, p: { proto } }, { builtins: ['js-prototypes'] }); + +function runTrigger() { + try { + proto.myMethod.call(Symbol("sym")); + } catch(e) { + } +} +`); + +Protocol.Debugger.onPaused(message => { + InspectorTest.log( + `Paused on ${message.params.reason}: ${message.params.data.description.split('\n')[0]}`); + Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'caught'}); + await Protocol.Runtime.evaluate({expression: 'runTrigger()'}); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-570538338-expected.txt b/deps/v8/test/inspector/regress/regress-570538338-expected.txt new file mode 100644 index 000000000000..a45a35389f65 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-570538338-expected.txt @@ -0,0 +1,6 @@ +Regression test for crbug.com/570538338. +{ + cond1Evaluated : true + cond2Evaluated : false + mainResult : 42 +} diff --git a/deps/v8/test/inspector/regress/regress-570538338.js b/deps/v8/test/inspector/regress/regress-570538338.js new file mode 100644 index 000000000000..279b984a946d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-570538338.js @@ -0,0 +1,94 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A Wasm breakpoint condition can synchronously disable the debugger while it +// is being evaluated. A second break point (from setBreakpointOnFunctionCall) +// at the same position must not be evaluated anymore afterwards. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/570538338.'); + +const source = ` +let mod_bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x05, // section length 5 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $main (result i32) + + 0x07, // section kind: Export + 0x08, // section length 8 + 0x01, // exports count 1: export # 0 + 0x04, // field name length: 4 + 0x6d, 0x61, 0x69, 0x6e, // field name: main + 0x00, 0x00, // kind: function index: 0 + + 0x0a, // section kind: Code + 0x07, // section length 7 + 0x01, // functions count 1 + // function #0 $main + 0x05, // body size 5 + 0x00, // 0 entries in locals list + 0x01, // nop + 0x41, 0x2a, // i32.const 42 + 0x0b, // end +]); + +let i1; +let cond1Evaluated = false; +let cond2Evaluated = false; +let mainResult; + +globalThis.cond1 = function() { + cond1Evaluated = true; + inspector.disconnectSession(${session.id}); + return false; +}; +globalThis.cond2 = function() { + cond2Evaluated = true; + return false; +}; + +globalThis.i1 = i1 = + new WebAssembly.Instance(new WebAssembly.Module(mod_bytes)); +`; + +(async function test() { + await Protocol.Debugger.enable(); + contextGroup.addScript(source); + const [, {params: {scriptId}}] = await Protocol.Debugger.onceScriptParsed(2); + + const {result: {locations}} = await Protocol.Debugger.getPossibleBreakpoints({ + start: {scriptId, lineNumber: 0, columnNumber: 0}, + }); + await Protocol.Debugger.setBreakpoint({ + location: locations[0], + condition: 'globalThis.cond1()', + }); + const {result: {result: {objectId}}} = await Protocol.Runtime.evaluate({ + expression: 'globalThis.i1.exports.main', + }); + await Protocol.Debugger.setBreakpointOnFunctionCall({ + objectId, + condition: 'globalThis.cond2()', + }); + + contextGroup.addScript('mainResult = i1.exports.main();'); + InspectorTest._sessions.delete(session); + + const session2 = contextGroup.connect(); + const {result: {result}} = await session2.Protocol.Runtime.evaluate({ + expression: '({mainResult, cond1Evaluated, cond2Evaluated})', + returnByValue: true, + }); + InspectorTest.logObject(result.value); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-570547313-expected.txt b/deps/v8/test/inspector/regress/regress-570547313-expected.txt new file mode 100644 index 000000000000..791a654b3d05 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-570547313-expected.txt @@ -0,0 +1,6 @@ +Tests that a second breakpoint condition at the same location is not evaluated if the first condition synchronously disables the debugger. +{ + cond1Evaluated : true + cond2Evaluated : false + outerResult : 3 +} diff --git a/deps/v8/test/inspector/regress/regress-570547313.js b/deps/v8/test/inspector/regress/regress-570547313.js new file mode 100644 index 000000000000..0fc89c638462 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-570547313.js @@ -0,0 +1,54 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that a second breakpoint condition at the same location is not ' + + 'evaluated if the first condition synchronously disables the debugger.'); + +const source = ` +function outer() { + function inner1() { return 1; } + function inner2() { return 2; } + return inner1() + inner2(); +} +let cond1Evaluated = false; +let cond2Evaluated = false; +globalThis.cond1 = function() { + cond1Evaluated = true; + inspector.disconnectSession(${session.id}); + return false; +}; +globalThis.cond2 = function() { + cond2Evaluated = true; + return false; +}; +`; + +(async function test() { + await Protocol.Debugger.enable(); + contextGroup.addScript(source, 0, 0, 'test.js'); + const {params: {scriptId}} = await Protocol.Debugger.onceScriptParsed(); + + await Protocol.Debugger.setBreakpoint({ + location: {scriptId, lineNumber: 2, columnNumber: 22}, + condition: 'globalThis.cond1()', + }); + await Protocol.Debugger.setBreakpointByUrl({ + urlRegex: 'test\\.js', + lineNumber: 2, + columnNumber: 22, + condition: 'globalThis.cond2()', + }); + + contextGroup.addScript('globalThis.outerResult = outer();'); + InspectorTest._sessions.delete(session); + + const session2 = contextGroup.connect(); + const {result: {result}} = await session2.Protocol.Runtime.evaluate({ + expression: '({outerResult, cond1Evaluated, cond2Evaluated})', + returnByValue: true, + }); + InspectorTest.logObject(result.value); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-570558888-expected.txt b/deps/v8/test/inspector/regress/regress-570558888-expected.txt new file mode 100644 index 000000000000..b773e4a0568f --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-570558888-expected.txt @@ -0,0 +1 @@ +Regression test for crbug.com/570558888. diff --git a/deps/v8/test/inspector/regress/regress-570558888.js b/deps/v8/test/inspector/regress/regress-570558888.js new file mode 100644 index 000000000000..ab2765aec6ac --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-570558888.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/570558888.'); + +contextGroup.addScript( + `function donor(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,bb,cc) { + return corrupt(); +} +function victim() { + corrupt(); + return 0; +}`, + 0, 0, 'test.js'); + +contextGroup.addScript(` +function corrupt() { + const donor_sfi = Sandbox.readObjectField(donor, 'shared_function_info'); + Sandbox.corruptObjectField(victim, 'shared_function_info', donor_sfi); +} + +function trigger() { + victim(); +} +`); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setBreakpointByUrl({ + url: 'test.js', + lineNumber: 1, + columnNumber: 0, + }); + await Protocol.Debugger.setBreakpointByUrl({ + url: 'test.js', + lineNumber: 5, + columnNumber: 0, + }); + await Protocol.Runtime.evaluate({expression: 'trigger()'}); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-571965281-expected.txt b/deps/v8/test/inspector/regress/regress-571965281-expected.txt new file mode 100644 index 000000000000..00a9bda334bc --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-571965281-expected.txt @@ -0,0 +1,5 @@ +Regression test for crbug.com/571965281. +Paused on exception: RuntimeError: data segment out of bounds +Paused on exception: RuntimeError: dereferencing a null pointer +Paused on exception: RuntimeError: dereferencing a null pointer +Paused on exception: RuntimeError: rethrowing null value diff --git a/deps/v8/test/inspector/regress/regress-571965281.js b/deps/v8/test/inspector/regress/regress-571965281.js new file mode 100644 index 000000000000..05e9d9775ea8 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-571965281.js @@ -0,0 +1,78 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/571965281.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +Protocol.Debugger.onPaused(message => { + InspectorTest.log( + `Paused on ${message.params.reason}: ${message.params.data.description.split('\n')[0]}`); + Protocol.Debugger.resume(); +}); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + + contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +const array = builder.addArray(kWasmI32); +const segment = builder.addPassiveDataSegment([]); + +builder.addFunction('array_new_data', kSig_v_v) + .addBody([ + kExprI32Const, 0, + kExprI32Const, 1, + kGCPrefix, kExprArrayNewData, array, segment, + kExprDrop, + ]) + .exportFunc(); + +builder.addFunction('array_init_data', kSig_v_v) + .addBody([ + kExprRefNull, array, + kExprI32Const, 0, + kExprI32Const, 0, + kExprI32Const, 0, + kGCPrefix, kExprArrayInitData, array, segment, + ]) + .exportFunc(); + +builder.addFunction('array_copy', kSig_v_v) + .addBody([ + kExprRefNull, array, + kExprI32Const, 0, + kExprRefNull, array, + kExprI32Const, 0, + kExprI32Const, 0, + kGCPrefix, kExprArrayCopy, array, array, + ]) + .exportFunc(); + +builder.addFunction('throw_ref', kSig_v_v) + .addBody([ + kExprRefNull, kExnRefCode, + kExprThrowRef, + ]) + .exportFunc(); + +const instance = builder.instantiate(); +`); + + await Protocol.Runtime.evaluate({ + expression: 'instance.exports.array_new_data()', + }); + await Protocol.Runtime.evaluate({ + expression: 'instance.exports.array_init_data()', + }); + await Protocol.Runtime.evaluate({ + expression: 'instance.exports.array_copy()', + }); + await Protocol.Runtime.evaluate({ + expression: 'instance.exports.throw_ref()', + }); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-572276045-expected.txt b/deps/v8/test/inspector/regress/regress-572276045-expected.txt new file mode 100644 index 000000000000..1569961e06f0 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572276045-expected.txt @@ -0,0 +1,8 @@ +Regression test for crbug.com/572276045. +{ + error : { + code : -32000 + message : Object is not available + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/regress/regress-572276045.js b/deps/v8/test/inspector/regress/regress-572276045.js new file mode 100644 index 000000000000..fee555c8a0e3 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572276045.js @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-stress-incremental-marking + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/572276045.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); +contextGroup.addScript(` +const table = new WebAssembly.Table({ element: 'structref', initial: 1 }); +`); + +const snapshotChunks = []; + +Protocol.HeapProfiler.onAddHeapSnapshotChunk(msg => { + snapshotChunks.push(msg.params.chunk); +}); + +Protocol.HeapProfiler.takeHeapSnapshot().then(() => { + const fullSnapshot = JSON.parse(snapshotChunks.join('')); + const nodes = fullSnapshot.nodes; + const strings = fullSnapshot.strings; + const nodeFields = fullSnapshot.snapshot.meta.node_fields; + const fieldCount = nodeFields.length; + + const promises = []; + for (let i = 0; i < nodes.length; i += fieldCount) { + const nameIdx = nodes[i + 1]; + const id = nodes[i + 2]; + const name = strings[nameIdx]; + if (name === 'null (wasm)') { + promises.push( + Protocol.HeapProfiler + .getObjectByHeapObjectId({ + objectId: String(id), + }) + .then(InspectorTest.logMessage)); + } + } + Promise.all(promises).then(InspectorTest.completeTest); +}); diff --git a/deps/v8/test/inspector/regress/regress-572276137-expected.txt b/deps/v8/test/inspector/regress/regress-572276137-expected.txt new file mode 100644 index 000000000000..fb66cab9e14d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572276137-expected.txt @@ -0,0 +1,3 @@ +Regression test for crbug.com/572276137. +results: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42 +paused_count: 20 diff --git a/deps/v8/test/inspector/regress/regress-572276137.js b/deps/v8/test/inspector/regress/regress-572276137.js new file mode 100644 index 000000000000..af54fb3ffa1a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572276137.js @@ -0,0 +1,77 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/572276137.'); + +contextGroup.addScript(` +let should_trigger = false; +let current_trigger = null; + +function target() { + if (should_trigger) { + should_trigger = false; + current_trigger(); + } + return 42; +} + +const triggers = [ + () => { throw new Error('boom'); }, + () => { Promise.reject(new Error('reject')).catch(() => {}); }, + () => { new Promise((_, reject) => reject(new Error('reject2'))).catch(() => {}); }, + () => { console.assert(false); }, + () => { %ScheduleBreak(); %ScheduleBreak(); (() => {})(); }, +]; + +function runTest() { + const results = []; + for (const trigger of triggers) { + current_trigger = trigger; + + // Test restartFrame from an interpreted frame. + should_trigger = true; + results.push(target()); + + // Test restartFrame from an optimized frame (exercising lazy deopt + unwind). + %PrepareFunctionForOptimization(target); + should_trigger = false; + results.push(target()); + %OptimizeFunctionOnNextCall(target); + should_trigger = true; + results.push(target()); + } + return results.join(','); +} +`); + +let paused_count = 0; +let should_restart = true; + +Protocol.Debugger.onPaused(msg => { + paused_count++; + if (should_restart) { + should_restart = false; + const target_frame = + msg.params.callFrames.find(f => f.functionName === 'target'); + Protocol.Debugger.restartFrame({ + callFrameId: target_frame.callFrameId, + mode: 'StepInto', + }); + } else { + should_restart = true; + Protocol.Debugger.resume(); + } +}); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + const {result} = await Protocol.Runtime.evaluate({expression: 'runTest()'}); + InspectorTest.log('results: ' + result.result.value); + InspectorTest.log('paused_count: ' + paused_count); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-572401025-expected.txt b/deps/v8/test/inspector/regress/regress-572401025-expected.txt new file mode 100644 index 000000000000..25ae0454ec0c --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572401025-expected.txt @@ -0,0 +1,39 @@ +Regression test for crbug.com/572401025. +{ + id : <messageId> + result : { + locations : [ + [0] : { + columnNumber : 0 + lineNumber : 0 + scriptId : <scriptId> + } + ] + } +} +{ + id : <messageId> + result : { + exceptionDetails : { + columnNumber : 6 + exception : { + className : ReferenceError + description : ReferenceError: Cannot access 'x' before initialization at f (target.js:10:7) at <anonymous>:1:13 + objectId : <objectId> + subtype : error + type : object + } + exceptionId : <exceptionId> + lineNumber : 9 + scriptId : <scriptId> + text : Uncaught + } + result : { + className : ReferenceError + description : ReferenceError: Cannot access 'x' before initialization at f (target.js:10:7) at <anonymous>:1:13 + objectId : <objectId> + subtype : error + type : object + } + } +} diff --git a/deps/v8/test/inspector/regress/regress-572401025.js b/deps/v8/test/inspector/regress/regress-572401025.js new file mode 100644 index 000000000000..2ab270a5dc3f --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572401025.js @@ -0,0 +1,47 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --stress-flush-code + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/572401025.'); + +contextGroup.addScript( + `1 + 1; +var call_outer = (function outer() { + "use strict"; + let f_ref; + label: { + f_ref = f; + break label; + let x = 1; + function f() { + return x; + } + } + return f_ref; +});`, + 0, 0, 'target.js'); + +contextGroup.addScript(` +for (let i = 0; i < 4; i++) gc(); +`); + +(async () => { + let scriptId; + Protocol.Debugger.onScriptParsed(msg => { + if (msg.params.url === 'target.js') { + scriptId = msg.params.scriptId; + } + }); + await Protocol.Debugger.enable(); + InspectorTest.logMessage(await Protocol.Debugger.getPossibleBreakpoints({ + start: {scriptId, lineNumber: 0, columnNumber: 0}, + end: {scriptId, lineNumber: 0, columnNumber: 5}, + })); + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: 'call_outer()() + 1', + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-572403047-expected.txt b/deps/v8/test/inspector/regress/regress-572403047-expected.txt new file mode 100644 index 000000000000..3be55d04ab04 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572403047-expected.txt @@ -0,0 +1,2 @@ +Regression test for crbug.com/572403047. +paused_count: 3 diff --git a/deps/v8/test/inspector/regress/regress-572403047.js b/deps/v8/test/inspector/regress/regress-572403047.js new file mode 100644 index 000000000000..29e7382294da --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572403047.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/572403047.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); +contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +const fn = builder.addImport('m', 'fn', kSig_v_v); +builder.addFunction('main', kSig_v_v) + .addBody([kExprCallFunction, fn]) + .exportFunc(); +const instance = builder.instantiate({m: {fn: Math.sin}}); +`); + +let objectId; +let paused_count = 0; +Protocol.Debugger.onPaused(() => { + ++paused_count; + Protocol.Debugger.stepInto(); +}); + +async function test() { + await Protocol.Debugger.enable(); + ({result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'Math.sin'})); + await Protocol.Debugger.setBreakpointOnFunctionCall({objectId}); + await Protocol.Runtime.evaluate({expression: 'instance.exports.main()'}); + InspectorTest.log(`paused_count: ${paused_count}`); + InspectorTest.completeTest(); +} +test(); diff --git a/deps/v8/test/inspector/regress/regress-572834323-expected.txt b/deps/v8/test/inspector/regress/regress-572834323-expected.txt new file mode 100644 index 000000000000..4ce1b7d09acd --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572834323-expected.txt @@ -0,0 +1,27 @@ +Regression test for crbug.com/572834323. +{ + id : <messageId> + result : { + exceptionDetails : { + columnNumber : 0 + exception : { + className : LinkError + description : LinkError: WebAssembly.Instance(): Import #0 "m" "f": function import requires a callable at <anonymous>:5:1 + objectId : <objectId> + subtype : error + type : object + } + exceptionId : <exceptionId> + lineNumber : 4 + scriptId : <scriptId> + text : Uncaught + } + result : { + className : LinkError + description : LinkError: WebAssembly.Instance(): Import #0 "m" "f": function import requires a callable at <anonymous>:5:1 + objectId : <objectId> + subtype : error + type : object + } + } +} diff --git a/deps/v8/test/inspector/regress/regress-572834323.js b/deps/v8/test/inspector/regress/regress-572834323.js new file mode 100644 index 000000000000..7ea378249b45 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-572834323.js @@ -0,0 +1,26 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/572834323.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +(async () => { + await Protocol.Debugger.enable(); + await Protocol.Debugger.setInstrumentationBreakpoint({ + instrumentation: 'beforeScriptExecution', + }); + + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: ` +const builder = new WasmModuleBuilder(); +builder.addImport('m', 'f', kSig_v_v); +const module = builder.toModule(); +new WebAssembly.Instance(module, {m: {f: 123}}); +`, + disableBreaks: true, + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-574453614-expected.txt b/deps/v8/test/inspector/regress/regress-574453614-expected.txt new file mode 100644 index 000000000000..cb188f5867cb --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574453614-expected.txt @@ -0,0 +1,31 @@ +Tests that returnByValue serialization limits the total number of values for shared (non-cyclic) references. + +Running test: testSharedReferences +{ + type : object + value : [ + [0] : { + a : 1 + } + [1] : { + a : 1 + } + [2] : { + b : { + a : 1 + } + } + ] +} + +Running test: testExponentialSharedArrays +{ + code : -32000 + message : Object is too large to be returned by value +} + +Running test: testNestedLargeArrays +{ + code : -32000 + message : Object is too large to be returned by value +} diff --git a/deps/v8/test/inspector/regress/regress-574453614.js b/deps/v8/test/inspector/regress/regress-574453614.js new file mode 100644 index 000000000000..bf4899893ec0 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574453614.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that returnByValue serialization limits the total number of ' + + 'values for shared (non-cyclic) references.'); + +async function evaluate(expression) { + const response = + await Protocol.Runtime.evaluate({expression, returnByValue: true}); + InspectorTest.logMessage(response.error ?? response.result.result); +} + +InspectorTest.runAsyncTestSuite([ + async function testSharedReferences() { + await evaluate('const o = {a: 1}; [o, o, {b: o}]'); + }, + + async function testExponentialSharedArrays() { + // Each level references the previous level twice, so the serialized + // value would have 2^3 * 4e6 elements, although the object graph is small. + await evaluate(` + let x = 0; + for (let i = 0; i < 3; ++i) { + const a = []; + a[4e6 - 1] = 0; + a[0] = a[1] = x; + x = a; + } + x`); + }, + + async function testNestedLargeArrays() { + await evaluate( + 'const a = [], b = []; a[6e6 - 1] = b[6e6 - 1] = 0; a[0] = b; a'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-574454550-expected.txt b/deps/v8/test/inspector/regress/regress-574454550-expected.txt new file mode 100644 index 000000000000..971a0b749ed8 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574454550-expected.txt @@ -0,0 +1,5 @@ +Tests that returnByValue serialization of a large self-referential sparse array fails quickly. +{ + code : -32000 + message : Object is too large to be returned by value +} diff --git a/deps/v8/test/inspector/regress/regress-574454550.js b/deps/v8/test/inspector/regress/regress-574454550.js new file mode 100644 index 000000000000..7deec5a4c565 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574454550.js @@ -0,0 +1,17 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that returnByValue serialization of a large self-referential ' + + 'sparse array fails quickly.'); + +(async function test() { + await Protocol.Runtime.enable(); + const response = await Protocol.Runtime.evaluate({ + expression: 'var a = []; a[1e7 - 1] = 0; a[0] = a; a', + returnByValue: true, + }); + InspectorTest.logMessage(response.error); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-574597225-expected.txt b/deps/v8/test/inspector/regress/regress-574597225-expected.txt new file mode 100644 index 000000000000..29f5b0cbffa5 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574597225-expected.txt @@ -0,0 +1,15 @@ +Tests that execution really stops when Runtime.terminateExecution arrives while the console builds the preview of an Error value + +Running test: setUp + +Running test: testErrorAsMapEntry +evaluate error: Execution was terminated +ran after console.log: false + +Running test: testErrorAsProperty +evaluate error: Execution was terminated +ran after console.log: false + +Running test: testErrorAsArgument +evaluate error: Execution was terminated +ran after console.log: false diff --git a/deps/v8/test/inspector/regress/regress-574597225.js b/deps/v8/test/inspector/regress/regress-574597225.js new file mode 100644 index 000000000000..1fd832d670aa --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574597225.js @@ -0,0 +1,65 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that execution really stops when Runtime.terminateExecution ' + + 'arrives while the console builds the preview of an Error value'); + +function makeExpression(value) { + return ` + globalThis.ranAfterConsoleLog = false; + { + let pausing = false; + const err = new Error(); + Object.setPrototypeOf(err, { + get name() { + if (pausing) return 'Error'; + pausing = true; + debugger; + for (;;) {} + } + }); + console.log(${value}); + } + globalThis.ranAfterConsoleLog = true; + `; +} + +async function runTest(value) { + // The `name` getter of the Error's prototype is invoked by + // descriptionForError() while the console builds the preview for the + // `value`. It pauses there, the test terminates execution, and the + // statement after console.log must not run. + const paused = Protocol.Debugger.oncePaused(); + const evaluated = + Protocol.Runtime.evaluate({expression: makeExpression(value)}); + await paused; + Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + const response = await evaluated; + InspectorTest.log('evaluate error: ' + (response.error || {}).message); + const {result: {result: {value: ranAfterConsoleLog}}} = + await Protocol.Runtime.evaluate( + {expression: 'globalThis.ranAfterConsoleLog', returnByValue: true}); + InspectorTest.log('ran after console.log: ' + ranAfterConsoleLog); +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + }, + + async function testErrorAsMapEntry() { + await runTest('new Map([[1, err]])'); + }, + + async function testErrorAsProperty() { + await runTest('{a: err}'); + }, + + async function testErrorAsArgument() { + await runTest('err'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-574597313-expected.txt b/deps/v8/test/inspector/regress/regress-574597313-expected.txt new file mode 100644 index 000000000000..cdae91a30a35 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574597313-expected.txt @@ -0,0 +1,3 @@ +Tests that a failed side-effect check while describing an internal#entry key is reported instead of being cleared. +callFunctionOn on internal#entry with side-effect Error key: exception (Uncaught EvalError: Possible side-effect in debug-evaluate) +sideEffects length: 0 diff --git a/deps/v8/test/inspector/regress/regress-574597313.js b/deps/v8/test/inspector/regress/regress-574597313.js new file mode 100644 index 000000000000..b805142b5070 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-574597313.js @@ -0,0 +1,62 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that a failed side-effect check while describing an ' + + 'internal#entry key is reported instead of being cleared.'); + +contextGroup.addScript(` + var sideEffects = []; + function makeErrorWithSideEffectPrototype(tag) { + const err = new Error(); + Object.setPrototypeOf(err, new Proxy({}, { + get(target, prop) { + sideEffects.push(tag); + return 'custom'; + } + })); + return err; + } + var mapWithErrorKey = + new Map([[makeErrorWithSideEffectPrototype('entry-key'), 123]]); +`); + +(async () => { + await Protocol.Runtime.enable(); + const {result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'mapWithErrorKey'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId}); + const {value: {objectId: entriesId}} = + internalProperties.find(({name}) => name === '[[Entries]]'); + const {result: {result}} = await Protocol.Runtime.getProperties( + {objectId: entriesId, ownProperties: true}); + const entry = result.find(({value}) => value?.subtype === 'internal#entry'); + + // The previous (not side-effect free) requests already described the Error + // key, so reset the side-effect log before the side-effect free request. + await Protocol.Runtime.evaluate({expression: 'sideEffects.length = 0'}); + + // Serializing the entry wrapper describes its Error key, whose prototype + // proxy getter fails the side-effect check. The termination exception must + // survive until the side-effect check scope converts it into an EvalError. + const response = await Protocol.Runtime.callFunctionOn({ + objectId: entry.value.objectId, + functionDeclaration: 'function() { return this; }', + throwOnSideEffect: true, + returnByValue: true, + }); + InspectorTest.log( + 'callFunctionOn on internal#entry with side-effect Error key: ' + + (response.result.exceptionDetails ? + 'exception (' + response.result.exceptionDetails.text + ' ' + + response.result.exceptionDetails.exception.description + ')' : + 'ok (' + JSON.stringify(response.result.result.value) + ')')); + + const {result: {result: {value: sideEffects}}} = + await Protocol.Runtime.evaluate( + {expression: 'sideEffects', returnByValue: true}); + InspectorTest.log('sideEffects length: ' + sideEffects.length); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575321664-expected.txt b/deps/v8/test/inspector/regress/regress-575321664-expected.txt new file mode 100644 index 000000000000..8a4f260df16a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575321664-expected.txt @@ -0,0 +1,6 @@ +Checks that custom preview generation stops after execution termination. +log: [object Object] +{ + code : -32000 + message : Execution was terminated +} diff --git a/deps/v8/test/inspector/regress/regress-575321664.js b/deps/v8/test/inspector/regress/regress-575321664.js new file mode 100644 index 000000000000..eb2b65e57b04 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575321664.js @@ -0,0 +1,56 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom preview generation stops after execution termination.'); + +const expression = ` + const inner = {}; + const outer = {}; + const header = ['span', ['object', {object: inner}]]; + Object.defineProperty(header, 2, { + get() { + console.log('FAIL: ran after termination'); + return 'x'; + }, + enumerable: true, + configurable: true, + }); + globalThis.devtoolsFormatters = [{ + header(object) { + if (object === inner) { + debugger; + for (;;) {} + } + if (object === outer) return header; + return null; + }, + hasBody(object) { return object === outer; }, + body(object) { return ['span', 'body']; }, + }]; + console.log(outer); +`; + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`${type}: ${args.map(({value}) => value).join(' ')}`); + }); + + // The header formatter for `inner` is called while the custom preview for + // `outer` is generated (via the nested object tag). It pauses there, the + // test terminates execution, and nothing else must run afterwards. + const paused = Protocol.Debugger.oncePaused(); + const evaluated = Protocol.Runtime.evaluate({expression}); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + await terminated; + InspectorTest.logMessage((await evaluated).error ?? 'evaluate finished'); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575325461-expected.txt b/deps/v8/test/inspector/regress/regress-575325461-expected.txt new file mode 100644 index 000000000000..4dacf687e92d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575325461-expected.txt @@ -0,0 +1,21 @@ +Checks that custom formatters cannot return huge JSONML arrays. + +Running test: setUp + +Running test: testHugeHeader +error: Custom Formatter Failed: Uncaught JSONML is too large +no custom preview + +Running test: testNestedHeader +error: Custom Formatter Failed: Uncaught JSONML is too large +no custom preview + +Running test: testHugeBody +{ + bodyGetterId : <bodyGetterId> + header : ["span","huge-body"] +} +error: Custom Formatter Failed: Uncaught JSONML is too large +{ + type : undefined +} diff --git a/deps/v8/test/inspector/regress/regress-575325461.js b/deps/v8/test/inspector/regress/regress-575325461.js new file mode 100644 index 000000000000..ee861d33e69f --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575325461.js @@ -0,0 +1,74 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom formatters cannot return huge JSONML arrays.'); + +contextGroup.addScript(` + function hugeSparseArray(tag, length) { + const a = [tag]; + a[length - 1] = 0; + return a; + } + + globalThis.devtoolsFormatters = [{ + header(object) { + switch (object.kind) { + case 'huge-header': + return hugeSparseArray('div', 0xFFFFFFFF); + case 'nested-header': { + const a = hugeSparseArray('div', 6e4); + a[1] = hugeSparseArray('span', 6e4); + return a; + } + default: + return ['span', object.kind]; + } + }, + hasBody(object) { + return object.kind === 'huge-body'; + }, + body(object) { + return hugeSparseArray('div', 0xFFFFFFFF); + } + }]; +`); + +Protocol.Runtime.onConsoleAPICalled( + ({params: {type, args}}) => InspectorTest.log(`${type}: ${args[0].value}`)); + +async function evaluateWithCustomPreview(kind) { + const {result: {result}} = await Protocol.Runtime.evaluate( + {expression: `({kind: '${kind}'})`, generatePreview: true}); + InspectorTest.logMessage(result.customPreview ?? 'no custom preview'); + return result; +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + }, + + async function testHugeHeader() { + await evaluateWithCustomPreview('huge-header'); + }, + + async function testNestedHeader() { + await evaluateWithCustomPreview('nested-header'); + }, + + async function testHugeBody() { + const {objectId, customPreview: {bodyGetterId}} = + await evaluateWithCustomPreview('huge-body'); + const {result: {result}} = await Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: + 'function(bodyGetter) { return bodyGetter.call(this); }', + arguments: [{objectId: bodyGetterId}], + returnByValue: true + }); + InspectorTest.logMessage(result); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575735741-expected.txt b/deps/v8/test/inspector/regress/regress-575735741-expected.txt new file mode 100644 index 000000000000..7e2f10b0d303 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575735741-expected.txt @@ -0,0 +1,3 @@ +Tests that a failed side-effect check while describing a nested internal#entry key is reported instead of being cleared. +callFunctionOn on internal#entry with nested side-effect Error key: exception (Uncaught EvalError: Possible side-effect in debug-evaluate) +sideEffects length: 0 diff --git a/deps/v8/test/inspector/regress/regress-575735741.js b/deps/v8/test/inspector/regress/regress-575735741.js new file mode 100644 index 000000000000..a2a786f3d806 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575735741.js @@ -0,0 +1,66 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that a failed side-effect check while describing a nested ' + + 'internal#entry key is reported instead of being cleared.'); + +contextGroup.addScript(` + var sideEffects = []; + function makeErrorWithSideEffectPrototype(tag) { + const err = new Error(); + Object.setPrototypeOf(err, new Proxy({}, { + get(target, prop) { + sideEffects.push(tag); + return 'custom'; + } + })); + return err; + } + // The key of the outer entry is itself a Map, so previewing it runs + // EntryMirror::getEntries for the inner map, whose key is the Error with + // the side-effecting prototype. + var innerMap = new Map([[makeErrorWithSideEffectPrototype('inner-key'), 1]]); + var outerMap = new Map([[innerMap, 123]]); +`); + +(async () => { + await Protocol.Runtime.enable(); + const {result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'outerMap'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId}); + const {value: {objectId: entriesId}} = + internalProperties.find(({name}) => name === '[[Entries]]'); + const {result: {result}} = await Protocol.Runtime.getProperties( + {objectId: entriesId, ownProperties: true}); + const entry = result.find(({value}) => value?.subtype === 'internal#entry'); + + // The previous (not side-effect free) requests already described the Error + // key, so reset the side-effect log before the side-effect free request. + await Protocol.Runtime.evaluate({expression: 'sideEffects.length = 0'}); + + // Serializing the entry wrapper previews the inner Map key, which describes + // the Error whose prototype proxy getter fails the side-effect check. The + // termination exception must survive until the side-effect check scope + // converts it into an EvalError. + const response = await Protocol.Runtime.callFunctionOn({ + objectId: entry.value.objectId, + functionDeclaration: 'function() { return this; }', + throwOnSideEffect: true, + returnByValue: true, + }); + InspectorTest.log( + 'callFunctionOn on internal#entry with nested side-effect Error key: ' + + (response.result.exceptionDetails ? + 'exception (' + response.result.exceptionDetails.text + ' ' + + response.result.exceptionDetails.exception.description + ')' : + 'ok (' + JSON.stringify(response.result.result.value) + ')')); + + const {result: {result: {value: sideEffects}}} = + await Protocol.Runtime.evaluate( + {expression: 'sideEffects', returnByValue: true}); + InspectorTest.log('sideEffects length: ' + sideEffects.length); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575737154-expected.txt b/deps/v8/test/inspector/regress/regress-575737154-expected.txt new file mode 100644 index 000000000000..495f4065fd95 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575737154-expected.txt @@ -0,0 +1,3 @@ +Tests that object previews handle a pending termination correctly. +callFunctionOn on internal#entry with Promise key: exception (Uncaught EvalError: Possible side-effect in debug-evaluate) +sideEffects length: 0 diff --git a/deps/v8/test/inspector/regress/regress-575737154.js b/deps/v8/test/inspector/regress/regress-575737154.js new file mode 100644 index 000000000000..98f9faadae45 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575737154.js @@ -0,0 +1,60 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that object previews handle a pending termination correctly.'); + +contextGroup.addScript(` + var sideEffects = []; + var errWithProxyProto = new Error(); + Object.setPrototypeOf(errWithProxyProto, new Proxy({}, { + get(target, prop) { + if (prop === 'name') { + sideEffects.push('side_effect'); + return 'custom'; + } + } + })); + var m = new Map([[Promise.resolve(errWithProxyProto), 123]]); +`); + +(async function test() { + await Protocol.Runtime.enable(); + const {result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'm'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId, ownProperties: true}); + const {value: {objectId: entriesId}} = + internalProperties.find(({name}) => name === '[[Entries]]'); + const {result: {result}} = await Protocol.Runtime.getProperties( + {objectId: entriesId, ownProperties: true}); + const entry = result.find(({value}) => value?.subtype === 'internal#entry'); + + // The previous (not side-effect free) requests already described the Error, + // so reset the side-effect log before the side-effect free request. + await Protocol.Runtime.evaluate({expression: 'sideEffects.length = 0'}); + + // Describing the entry previews the Promise key, whose [[PromiseResult]] + // is the Error whose prototype proxy getter fails the side-effect check. + // The preview must not continue with the own properties of the Promise + // while the termination exception is pending. + const response = await Protocol.Runtime.callFunctionOn({ + objectId: entry.value.objectId, + functionDeclaration: 'function() { return this; }', + throwOnSideEffect: true, + returnByValue: true, + }); + InspectorTest.log( + 'callFunctionOn on internal#entry with Promise key: ' + + (response.result.exceptionDetails ? + 'exception (' + response.result.exceptionDetails.text + ' ' + + response.result.exceptionDetails.exception.description + ')' : + 'ok (' + JSON.stringify(response.result.result.value) + ')')); + + const {result: {result: {value: sideEffects}}} = + await Protocol.Runtime.evaluate( + {expression: 'sideEffects', returnByValue: true}); + InspectorTest.log('sideEffects length: ' + sideEffects.length); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575762332-expected.txt b/deps/v8/test/inspector/regress/regress-575762332-expected.txt new file mode 100644 index 000000000000..d2c0ac6bcb28 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575762332-expected.txt @@ -0,0 +1,25 @@ +Tests that returnByValue serialization limits the total length of strings for shared references. + +Running test: testSmallStrings +{ + type : object + value : [ + [0] : abc + [1] : abc + [2] : { + t : abc + } + ] +} + +Running test: testLargeStringInArray +{ + code : -32000 + message : Object is too large to be returned by value +} + +Running test: testLargeStringInObject +{ + code : -32000 + message : Object is too large to be returned by value +} diff --git a/deps/v8/test/inspector/regress/regress-575762332.js b/deps/v8/test/inspector/regress/regress-575762332.js new file mode 100644 index 000000000000..93416fcdd27d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575762332.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that returnByValue serialization limits the total length of ' + + 'strings for shared references.'); + +contextGroup.addScript(` + // Two references to this string exceed the maximum string length together. + var s = 'x'.repeat(Math.floor(%StringMaxLength() / 2) + 1); +`); + +async function evaluate(expression) { + const response = + await Protocol.Runtime.evaluate({expression, returnByValue: true}); + InspectorTest.logMessage(response.error ?? response.result.result); +} + +InspectorTest.runAsyncTestSuite([ + async function testSmallStrings() { + await evaluate('const t = "abc"; [t, t, {t}]'); + }, + + async function testLargeStringInArray() { + await evaluate('[s, s]'); + }, + + async function testLargeStringInObject() { + await evaluate('({a: s, b: s})'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575806232-expected.txt b/deps/v8/test/inspector/regress/regress-575806232-expected.txt new file mode 100644 index 000000000000..713531f752c5 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575806232-expected.txt @@ -0,0 +1,6 @@ +Checks that console argument wrapping stops after a custom formatter terminated execution. +log: 1 argument(s) +{ + code : -32000 + message : Execution was terminated +} diff --git a/deps/v8/test/inspector/regress/regress-575806232.js b/deps/v8/test/inspector/regress/regress-575806232.js new file mode 100644 index 000000000000..e1e0b76d251e --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575806232.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that console argument wrapping stops after a custom formatter ' + + 'terminated execution.'); + +const expression = ` + const first = {}; + globalThis.devtoolsFormatters = [{ + header(object) { + if (object === first) { + debugger; + for (;;) {} + } + return null; + }, + hasBody() { return false; }, + }]; + console.log(first, Object.create(null)); +`; + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`${type}: ${args.length} argument(s)`); + }); + + // The header formatter for the first console argument pauses; the test + // terminates execution there. Afterwards nothing must call into V8 again, + // in particular the second console argument must not be wrapped. + const paused = Protocol.Debugger.oncePaused(); + const evaluated = Protocol.Runtime.evaluate({expression}); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + await terminated; + InspectorTest.logMessage((await evaluated).error ?? 'evaluate finished'); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575834150-expected.txt b/deps/v8/test/inspector/regress/regress-575834150-expected.txt new file mode 100644 index 000000000000..1bc60cb37c9d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575834150-expected.txt @@ -0,0 +1,12 @@ +Tests that termination inside custom preview stops remaining custom preview execution at call depth zero. +{ + id : <messageId> + result : { + } +} +{ + id : <messageId> + result : { + } +} +["outerHeader","innerHeader","innerGetter","outerHeader","innerHeader","innerGetter"] diff --git a/deps/v8/test/inspector/regress/regress-575834150.js b/deps/v8/test/inspector/regress/regress-575834150.js new file mode 100644 index 000000000000..534157ee619a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575834150.js @@ -0,0 +1,72 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that termination inside custom preview stops remaining custom ' + + 'preview execution at call depth zero.'); + +const setup = ` + var log = []; + const inner = {}; + const outer = {}; + const innerHeader = ['span', 'inner']; + Object.defineProperty(innerHeader, 1, { + get() { + log.push('innerGetter'); + debugger; + for (;;) {} + }, + enumerable: true, + configurable: true, + }); + const outerHeader = ['span', ['object', {object: inner}]]; + Object.defineProperty(outerHeader, 2, { + get() { + log.push('FAIL: outer getter ran after termination'); + return 'x'; + }, + enumerable: true, + configurable: true, + }); + globalThis.devtoolsFormatters = [{ + header(object) { + if (object === inner) { + log.push('innerHeader'); + return innerHeader; + } + if (object === outer) { + log.push('outerHeader'); + return outerHeader; + } + return null; + }, + hasBody(object) { return false; }, + body(object) { return null; }, + }]; + globalThis.outer = outer; +`; + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + await Protocol.Runtime.evaluate({expression: setup}); + + for (let i = 0; i < 2; ++i) { + const paused = Protocol.Debugger.oncePaused(); + const evaluated = + Protocol.Runtime.evaluate({expression: 'outer', generatePreview: true}); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + InspectorTest.logMessage(await terminated); + await evaluated; + } + + const {result: {result}} = + await Protocol.Runtime.evaluate({expression: 'JSON.stringify(log)'}); + InspectorTest.log(result.value); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575834938-expected.txt b/deps/v8/test/inspector/regress/regress-575834938-expected.txt new file mode 100644 index 000000000000..dd2ba1acbdd4 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575834938-expected.txt @@ -0,0 +1,6 @@ +Checks that nested custom formatters do not bypass JSONML budget and cause OOM. + +Running test: setUp + +Running test: testOOM +no custom preview diff --git a/deps/v8/test/inspector/regress/regress-575834938.js b/deps/v8/test/inspector/regress/regress-575834938.js new file mode 100644 index 000000000000..3c46a6193c13 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575834938.js @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that nested custom formatters do not bypass JSONML budget and ' + + 'cause OOM.'); + +contextGroup.addScript(` + const largeString = 'a'.repeat(1024 * 1024 * 10); // 10MB string + + globalThis.devtoolsFormatters = [{ + header(object) { + if (object.kind === 'outer') { + const result = ['div']; + // Generate enough children so that the total string size exceeds memory + // if budgets are not shared. Each child will serialize the large string. + for (let i = 0; i < 200; i++) { + result.push(['object', { object: { kind: 'child' } }]); + } + return result; + } + if (object.kind === 'child') { + return ['span', largeString]; + } + return null; + }, + hasBody() { return false; }, + }]; +`); + +async function evaluateWithCustomPreview(kind) { + const {result: {result}} = await Protocol.Runtime.evaluate( + {expression: `({kind: '${kind}'})`, generatePreview: true}); + InspectorTest.logMessage(result.customPreview ?? 'no custom preview'); + return result; +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + }, + + async function testOOM() { + await evaluateWithCustomPreview('outer'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575835333-expected.txt b/deps/v8/test/inspector/regress/regress-575835333-expected.txt new file mode 100644 index 000000000000..dab0ac59fddf --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575835333-expected.txt @@ -0,0 +1,6 @@ +Checks that custom formatters cannot return strings that cause OOM. + +Running test: setUp + +Running test: testOOM +no custom preview diff --git a/deps/v8/test/inspector/regress/regress-575835333.js b/deps/v8/test/inspector/regress/regress-575835333.js new file mode 100644 index 000000000000..adf2af93afa6 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575835333.js @@ -0,0 +1,37 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom formatters cannot return strings that cause OOM.'); + +contextGroup.addScript(` + globalThis.devtoolsFormatters = [{ + header(object) { + if (object.kind === 'oom') { + const s = 'x'.repeat(2**28 - 24); + return ['div', s, s, s, s, s, s, s, s]; + } + return null; + }, + hasBody() { return false; }, + }]; +`); + +async function evaluateWithCustomPreview(kind) { + const {result: {result}} = await Protocol.Runtime.evaluate( + {expression: `({kind: '${kind}'})`, generatePreview: true}); + InspectorTest.logMessage(result.customPreview ?? 'no custom preview'); + return result; +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + }, + + async function testOOM() { + await evaluateWithCustomPreview('oom'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575838270-expected.txt b/deps/v8/test/inspector/regress/regress-575838270-expected.txt new file mode 100644 index 000000000000..b0b9434393c4 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575838270-expected.txt @@ -0,0 +1,11 @@ +Checks that custom formatters budget correctly charges for undefined/function properties. + +Running test: setUp + +Running test: testShared60k +Evaluating shared-60k +no custom preview + +Running test: testDAG +Evaluating DAG +no custom preview diff --git a/deps/v8/test/inspector/regress/regress-575838270.js b/deps/v8/test/inspector/regress/regress-575838270.js new file mode 100644 index 000000000000..ee7f08015185 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575838270.js @@ -0,0 +1,60 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --max-old-space-size=64 + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom formatters budget correctly charges for ' + + 'undefined/function properties.'); + +contextGroup.addScript(` + function makeObjectWithUndefinedProperties(count) { + const leaf = {}; + for (let i = 0; i < count; i++) { + leaf[i] = undefined; + } + const a = ['div']; + for (let i = 0; i < 500; i++) { + a.push(leaf); + } + return a; + } + + globalThis.devtoolsFormatters = [{ + header(object) { + if (object.kind === 'shared-60k') { + return makeObjectWithUndefinedProperties(60000); + } + if (object.kind === 'DAG') { + return makeObjectWithUndefinedProperties(1000000); + } + return null; + }, + hasBody(object) { return false; }, + body(object) { return null; } + }]; +`); + +async function evaluateWithCustomPreview(kind) { + InspectorTest.log('Evaluating ' + kind); + const {result: {result}} = await Protocol.Runtime.evaluate( + {expression: `({kind: '${kind}'})`, generatePreview: true}); + InspectorTest.logMessage(result.customPreview ?? 'no custom preview'); + return result; +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + }, + + async function testShared60k() { + await evaluateWithCustomPreview('shared-60k'); + }, + + async function testDAG() { + await evaluateWithCustomPreview('DAG'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575863785-expected.txt b/deps/v8/test/inspector/regress/regress-575863785-expected.txt new file mode 100644 index 000000000000..84e0d3198154 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575863785-expected.txt @@ -0,0 +1,47 @@ +Tests that deep serialization limits the total length of strings for shared references. + +Running test: testSmallStrings +{ + className : Array + deepSerializedValue : { + type : array + value : [ + [0] : { + type : string + value : abc + } + [1] : { + type : string + value : abc + } + [2] : { + type : object + value : [ + [0] : [ + [0] : t + [1] : { + type : string + value : abc + } + ] + ] + } + ] + } + description : Array(3) + objectId : <objectId> + subtype : array + type : object +} + +Running test: testLargeStringInArray +Error: Object is too large to be returned by value + +Running test: testLargeStringInObject +Error: Object is too large to be returned by value + +Running test: testLargeStringInMap +Error: Object is too large to be returned by value + +Running test: testLargeStringAfterBigInt +Error: Object is too large to be returned by value diff --git a/deps/v8/test/inspector/regress/regress-575863785.js b/deps/v8/test/inspector/regress/regress-575863785.js new file mode 100644 index 000000000000..35851a028dee --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575863785.js @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that deep serialization limits the total length of strings for ' + + 'shared references.'); + +const source = ` + var s = 'x'.repeat(%StringMaxLength()); +`; +contextGroup.addScript(source); + +async function evaluate(expression) { + const response = await Protocol.Runtime.evaluate( + {expression, serializationOptions: {serialization: 'deep'}}); + if (response.error) { + InspectorTest.logMessage('Error: ' + response.error.message); + } else { + InspectorTest.logMessage(response.result.result); + } +} + +InspectorTest.runAsyncTestSuite([ + async function testSmallStrings() { + await evaluate('const t = "abc"; [t, t, {t}]'); + }, + + async function testLargeStringInArray() { + await evaluate("['a', s]"); + }, + + async function testLargeStringInObject() { + await evaluate('({a: s})'); + }, + + async function testLargeStringInMap() { + await evaluate("new Map([['a', s]])"); + }, + + async function testLargeStringAfterBigInt() { + await evaluate('[1n, s]'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575876559-expected.txt b/deps/v8/test/inspector/regress/regress-575876559-expected.txt new file mode 100644 index 000000000000..f4e0a24e5c28 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575876559-expected.txt @@ -0,0 +1,3 @@ +Tests that a failed side-effect check in doesAttributeHaveObservableSideEffectOnGet is not swallowed. +Request side-effect: exception (Uncaught EvalError: Possible side-effect in debug-evaluate) +Response side-effect: exception (Uncaught EvalError: Possible side-effect in debug-evaluate) diff --git a/deps/v8/test/inspector/regress/regress-575876559.js b/deps/v8/test/inspector/regress/regress-575876559.js new file mode 100644 index 000000000000..b9480086d271 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575876559.js @@ -0,0 +1,86 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that a failed side-effect check in ' + + 'doesAttributeHaveObservableSideEffectOnGet is not swallowed.'); + +contextGroup.addScript(` + var sideEffects = []; + var key = {}; + Object.defineProperty(key, 'body', {get: Date.now, configurable: true}); + var m = new Map([[key, 123]]); +`); + +(async function test() { + await Protocol.Runtime.enable(); + const {result: {result: {objectId}}} = + await Protocol.Runtime.evaluate({expression: 'm'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId, ownProperties: true}); + const {value: {objectId: entriesId}} = + internalProperties.find(({name}) => name === '[[Entries]]'); + const {result: {result}} = await Protocol.Runtime.getProperties( + {objectId: entriesId, ownProperties: true}); + const entry = result.find(({value}) => value?.subtype === 'internal#entry'); + + // Case 1: Request[Symbol.hasInstance] fails the side-effect check and + // terminates execution; the following Response check must not run. + await Protocol.Runtime.evaluate({ + expression: ` + globalThis.Request = { + [Symbol.hasInstance](o) { + sideEffects.push('Request'); + return false; + } + }; + globalThis.Response = { + [Symbol.hasInstance](o) { + throw new Error('boom'); + } + }; + `, + }); + let response = await Protocol.Runtime.callFunctionOn({ + objectId: entry.value.objectId, + functionDeclaration: 'function() { return this; }', + throwOnSideEffect: true, + returnByValue: true, + }); + InspectorTest.log( + 'Request side-effect: ' + + (response.result.exceptionDetails ? + 'exception (' + response.result.exceptionDetails.text + ' ' + + response.result.exceptionDetails.exception.description + ')' : + 'ok (' + JSON.stringify(response.result.result.value) + ')')); + + // Case 2: Response[Symbol.hasInstance] fails the side-effect check and + // terminates execution; ValueMirror::getProperties must not invoke the + // 'body' getter afterwards and clear the pending termination exception. + await Protocol.Runtime.evaluate({ + expression: ` + delete globalThis.Request; + globalThis.Response = { + [Symbol.hasInstance](o) { + sideEffects.push('Response'); + return false; + } + }; + `, + }); + response = await Protocol.Runtime.callFunctionOn({ + objectId: entry.value.objectId, + functionDeclaration: 'function() { return this; }', + throwOnSideEffect: true, + returnByValue: true, + }); + InspectorTest.log( + 'Response side-effect: ' + + (response.result.exceptionDetails ? + 'exception (' + response.result.exceptionDetails.text + ' ' + + response.result.exceptionDetails.exception.description + ')' : + 'ok (' + JSON.stringify(response.result.result.value) + ')')); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575876890-expected.txt b/deps/v8/test/inspector/regress/regress-575876890-expected.txt new file mode 100644 index 000000000000..94000777fe78 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575876890-expected.txt @@ -0,0 +1,7 @@ +Tests that execution really stops when Runtime.terminateExecution arrives while the console builds the message string for the first of several console.log() arguments + +Running test: setUp + +Running test: testTwoArguments +evaluate error: Execution was terminated +ran after console.log: false diff --git a/deps/v8/test/inspector/regress/regress-575876890.js b/deps/v8/test/inspector/regress/regress-575876890.js new file mode 100644 index 000000000000..3d35b9388091 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575876890.js @@ -0,0 +1,53 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that execution really stops when Runtime.terminateExecution ' + + 'arrives while the console builds the message string for the first of ' + + 'several console.log() arguments'); + +function makeExpression(args) { + // The element getter of `arr` runs inside V8ValueStringBuilder::append() + // while console.log() builds the message string for the first argument. + // It pauses there, the test terminates execution, and the statement after + // console.log() must not run - no matter how many arguments are logged. + return ` + globalThis.ranAfterConsoleLog = false; + const arr = []; + Object.defineProperty(arr, '0', { + get() { debugger; return 1; }, + enumerable: true, + configurable: true, + }); + arr.length = 1; + console.log(${args}); + globalThis.ranAfterConsoleLog = true; + `; +} + +async function runTest(args) { + const paused = Protocol.Debugger.oncePaused(); + const evaluated = + Protocol.Runtime.evaluate({expression: makeExpression(args)}); + await paused; + Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + const response = await evaluated; + InspectorTest.log('evaluate error: ' + (response.error || {}).message); + const {result: {result: {value: ranAfterConsoleLog}}} = + await Protocol.Runtime.evaluate( + {expression: 'globalThis.ranAfterConsoleLog', returnByValue: true}); + InspectorTest.log('ran after console.log: ' + ranAfterConsoleLog); +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + }, + + async function testTwoArguments() { + await runTest('arr, {}'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-575892969-expected.txt b/deps/v8/test/inspector/regress/regress-575892969-expected.txt new file mode 100644 index 000000000000..4adc87ec1968 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575892969-expected.txt @@ -0,0 +1,11 @@ +Checks that the console.table column loop stops after a column getter terminated execution. +table: 1 argument(s) +{ + code : -32000 + message : Execution was terminated +} +table: 1 argument(s) +{ + code : -32000 + message : Execution was terminated +} diff --git a/deps/v8/test/inspector/regress/regress-575892969.js b/deps/v8/test/inspector/regress/regress-575892969.js new file mode 100644 index 000000000000..dfb9f19cc9a3 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575892969.js @@ -0,0 +1,61 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that the console.table column loop stops after a column getter ' + + 'terminated execution.'); + +function makeExpression(pauseOnAccess) { + return ` + { + let count = 0; + let paused = false; + const columns = []; + Object.defineProperty(columns, 0, { + enumerable: true, + get() { + if (++count === ${pauseOnAccess}) { + paused = true; + debugger; + for (;;) {} + } + return 'a'; + }, + }); + Object.defineProperty(columns, 1, { + enumerable: true, + get() { + if (paused) console.log('second column getter ran'); + return 'b'; + }, + }); + console.table([{a: 1, b: 2}], columns); + } + `; +} + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`${type}: ${args.length} argument(s)`); + }); + + // Pause on access 1 (V8ValueStringBuilder::append) and access 2 + // (InjectedScript::wrapTable). In both cases the getter for the second + // column must not run after termination. + for (const pauseOnAccess of [1, 2]) { + const paused = Protocol.Debugger.oncePaused(); + const evaluated = + Protocol.Runtime.evaluate({expression: makeExpression(pauseOnAccess)}); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + await terminated; + InspectorTest.logMessage((await evaluated).error ?? 'evaluate finished'); + } + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575895942-expected.txt b/deps/v8/test/inspector/regress/regress-575895942-expected.txt new file mode 100644 index 000000000000..9683198c8a11 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575895942-expected.txt @@ -0,0 +1,6 @@ +Checks that console.table argument wrapping stops after the column setup terminated execution. +table: Error: e col +{ + code : -32000 + message : Execution was terminated +} diff --git a/deps/v8/test/inspector/regress/regress-575895942.js b/deps/v8/test/inspector/regress/regress-575895942.js new file mode 100644 index 000000000000..3833c661bfe9 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575895942.js @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that console.table argument wrapping stops after the column ' + + 'setup terminated execution.'); + +const expression = ` + Object.defineProperty(Array.prototype, '0', { + set(v) { + Object.defineProperty(Error.prototype, 'name', { + get() { + console.log('FAIL: ran after termination'); + return 'X'; + }, + configurable: true, + }); + debugger; + for (;;) {} + }, + configurable: true, + }); + console.table(new Error('e'), 'col'); +`; + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`${type}: ${args.map(({value, description}) => value ?? description).join(' ')}`); + }); + + // The Array.prototype[0] setter runs while console.table builds the column + // array; it pauses and the test terminates execution there. Afterwards + // nothing must call into V8 again, in particular the Error.prototype.name + // getter must not run. + const paused = Protocol.Debugger.oncePaused(); + const evaluated = Protocol.Runtime.evaluate({expression}); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + await terminated; + InspectorTest.logMessage((await evaluated).error ?? 'evaluate finished'); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-575910950-expected.txt b/deps/v8/test/inspector/regress/regress-575910950-expected.txt new file mode 100644 index 000000000000..f020bd9ce82e --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575910950-expected.txt @@ -0,0 +1,5 @@ +Tests that returnByValue serialization charges undefined-valued properties against the protocol value budget. +{ + code : -32000 + message : Object is too large to be returned by value +} diff --git a/deps/v8/test/inspector/regress/regress-575910950.js b/deps/v8/test/inspector/regress/regress-575910950.js new file mode 100644 index 000000000000..041c90d247a3 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-575910950.js @@ -0,0 +1,23 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that returnByValue serialization charges undefined-valued ' + + 'properties against the protocol value budget.'); + +const source = ` + const o = {a: undefined}; + const a = []; + a[10000000 - 3] = 0; +`; +contextGroup.addScript(source); + +(async function test() { + const response = await Protocol.Runtime.evaluate({ + expression: '[o, a]', + returnByValue: true, + }); + InspectorTest.logMessage(response.error ?? response.result.result); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-576260517-expected.txt b/deps/v8/test/inspector/regress/regress-576260517-expected.txt new file mode 100644 index 000000000000..357492efabdb --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576260517-expected.txt @@ -0,0 +1,7 @@ +Tests that termination inside a custom preview during Runtime.getProperties is not swallowed at call depth zero. +{ + id : <messageId> + result : { + } +} +["outerHeader","innerHeader","innerGetter"] diff --git a/deps/v8/test/inspector/regress/regress-576260517.js b/deps/v8/test/inspector/regress/regress-576260517.js new file mode 100644 index 000000000000..b0aa004265f0 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576260517.js @@ -0,0 +1,66 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that termination inside a custom preview during ' + + 'Runtime.getProperties is not swallowed at call depth zero.'); + +const setup = ` + var log = []; + const inner = {}; + const outer = {}; + const innerHeader = ['span', 'inner']; + Object.defineProperty(innerHeader, 1, { + get() { + log.push('innerGetter'); + Promise.resolve().then(() => log.push('FAIL: microtask after termination')); + debugger; + for (;;) {} + }, + enumerable: true, + configurable: true, + }); + const outerHeader = ['span', ['object', {object: inner}]]; + globalThis.devtoolsFormatters = [{ + header(object) { + if (object === inner) { + log.push('innerHeader'); + return innerHeader; + } + if (object === outer) { + log.push('outerHeader'); + return outerHeader; + } + return null; + }, + hasBody(object) { return false; }, + body(object) { return null; }, + }]; + globalThis.holder = {p: outer}; +`; + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + await Protocol.Runtime.evaluate({expression: setup}); + + const {result: {result: holder}} = + await Protocol.Runtime.evaluate({expression: 'holder'}); + + const paused = Protocol.Debugger.oncePaused(); + const properties = Protocol.Runtime.getProperties( + {objectId: holder.objectId, generatePreview: true}); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + InspectorTest.logMessage(await terminated); + await properties; + + const {result: {result}} = + await Protocol.Runtime.evaluate({expression: 'JSON.stringify(log)'}); + InspectorTest.log(result.value); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-576261017-expected.txt b/deps/v8/test/inspector/regress/regress-576261017-expected.txt new file mode 100644 index 000000000000..27c796ad956d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576261017-expected.txt @@ -0,0 +1,3 @@ +Tests that termination inside an error description getter stops the remaining preview work at call depth zero. +evaluate after terminateExecution: Execution was terminated +getters that ran: ["name"] diff --git a/deps/v8/test/inspector/regress/regress-576261017.js b/deps/v8/test/inspector/regress/regress-576261017.js new file mode 100644 index 000000000000..1854e2a8d074 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576261017.js @@ -0,0 +1,53 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that termination inside an error description getter stops the ' + + 'remaining preview work at call depth zero.'); + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Runtime.evaluate({ + expression: ` + var log = []; + var pausing = false; + var messageCalls = 0; + globalThis.err = new Error(); + Object.setPrototypeOf(globalThis.err, { + get name() { + if (pausing) return 'Error'; + log.push('name'); + pausing = true; + debugger; + for (;;) {} + }, + get message() { + // Building Debugger.paused for callFrames[0].this formats err once + // before terminateExecution() is sent; only log calls after that. + if (++messageCalls > 1) log.push('message'); + return 'm'; + }, + }); + 42; + ` + }); + + const paused = Protocol.Debugger.oncePaused(); + const evaluated = + Protocol.Runtime.evaluate({expression: 'err', generatePreview: true}); + await paused; + Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + const response = await evaluated; + InspectorTest.log( + 'evaluate after terminateExecution: ' + + (response.error ? response.error.message : 'NO ERROR')); + + const {result: {result}} = + await Protocol.Runtime.evaluate({expression: 'JSON.stringify(log)'}); + InspectorTest.log('getters that ran: ' + result.value); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-576534261-expected.txt b/deps/v8/test/inspector/regress/regress-576534261-expected.txt new file mode 100644 index 000000000000..055c375f4ca9 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576534261-expected.txt @@ -0,0 +1,8 @@ +Regression test for crbug.com/576534261. +{ + error : { + code : -32000 + message : Object is too large to be returned by value + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/regress/regress-576534261.js b/deps/v8/test/inspector/regress/regress-576534261.js new file mode 100644 index 000000000000..560d70ad84c9 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576534261.js @@ -0,0 +1,24 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/576534261.'); + +const source = ` + const s = 'x'.repeat(%StringMaxLength()); +`; +contextGroup.addScript(source); + +(async () => { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: '[/a/, s]', + generatePreview: false, + serializationOptions: { + serialization: 'deep', + }, + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-576631304-expected.txt b/deps/v8/test/inspector/regress/regress-576631304-expected.txt new file mode 100644 index 000000000000..fcc0bb0bd640 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576631304-expected.txt @@ -0,0 +1,6 @@ +Tests that DebugEvaluate::Local write-back does not overwrite TDZ stack locals with undefined. + +Running test: testTdzPreservedAcrossEvaluateOnCallFrame +a = 25 -> 25 +x -> ReferenceError: Cannot access 'x' from debugger +Resumed result: 25: ReferenceError: Cannot access 'x' before initialization diff --git a/deps/v8/test/inspector/regress/regress-576631304.js b/deps/v8/test/inspector/regress/regress-576631304.js new file mode 100644 index 000000000000..6a7f5144e2c6 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-576631304.js @@ -0,0 +1,54 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that DebugEvaluate::Local write-back does not overwrite TDZ stack ' + + 'locals with undefined.'); + +contextGroup.addScript(` +function readTdzAfterEvaluate() { + let a = 10; + debugger; + try { + return x; + } catch (e) { + return a + ': ' + e.toString(); + } + let x = 42; +} +`); + +InspectorTest.runAsyncTestSuite([ + async function testTdzPreservedAcrossEvaluateOnCallFrame() { + await Protocol.Debugger.enable(); + await Protocol.Runtime.enable(); + + const paused = Protocol.Debugger.oncePaused(); + const evaluated = + Protocol.Runtime.evaluate({expression: 'readTdzAfterEvaluate()'}); + const {params: {callFrames: [callFrame]}} = await paused; + + // 1. Evaluate an expression that modifies initialized local `a` while `x` + // is still in its TDZ. + const eval1 = await Protocol.Debugger.evaluateOnCallFrame({ + callFrameId: callFrame.callFrameId, + expression: 'a = 25', + }); + InspectorTest.log(`a = 25 -> ${eval1.result.result.description}`); + + // 2. Reading `x` via evaluateOnCallFrame should still throw ReferenceError. + const eval2 = await Protocol.Debugger.evaluateOnCallFrame({ + callFrameId: callFrame.callFrameId, + expression: 'x', + }); + InspectorTest.log( + `x -> ${eval2.result.exceptionDetails.exception.description.split('\n')[0]}`); + + // 3. Resuming the paused function should still observe `x` in TDZ and `a` + // updated to 25. + await Protocol.Debugger.resume(); + const {result: {result}} = await evaluated; + InspectorTest.log(`Resumed result: ${result.value}`); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-console-assert-termination-expected.txt b/deps/v8/test/inspector/regress/regress-console-assert-termination-expected.txt new file mode 100644 index 000000000000..cbdb1e03cf16 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-console-assert-termination-expected.txt @@ -0,0 +1,3 @@ +Checks that console.assert() does not break into the debugger after formatting its arguments terminated execution. +paused: other +evaluate returned diff --git a/deps/v8/test/inspector/regress/regress-console-assert-termination.js b/deps/v8/test/inspector/regress/regress-console-assert-termination.js new file mode 100644 index 000000000000..47d9bd26265a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-console-assert-termination.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that console.assert() does not break into the debugger after ' + + 'formatting its arguments terminated execution.'); + +const expression = ` + const arr = []; + Object.defineProperty(arr, '0', { + enumerable: true, + configurable: true, + get() { debugger; return 1; }, + }); + arr.length = 1; + console.assert(false, arr); +`; + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + + let pauses = 0; + Protocol.Debugger.onPaused(({params: {reason}}) => { + InspectorTest.log(`paused: ${reason}`); + if (++pauses === 1) { + Protocol.Runtime.terminateExecution(); + } + Protocol.Debugger.resume(); + if (pauses > 1) InspectorTest.quitImmediately(); + }); + + await Protocol.Runtime.evaluate({expression}); + InspectorTest.log('evaluate returned'); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-console-table-column-getter-throws-expected.txt b/deps/v8/test/inspector/regress/regress-console-table-column-getter-throws-expected.txt new file mode 100644 index 000000000000..6ac5414423e6 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-console-table-column-getter-throws-expected.txt @@ -0,0 +1,3 @@ +Checks that a throwing console.table() column getter does not leak the exception into the running script. +Runtime disabled: no throw +Runtime enabled: no throw diff --git a/deps/v8/test/inspector/regress/regress-console-table-column-getter-throws.js b/deps/v8/test/inspector/regress/regress-console-table-column-getter-throws.js new file mode 100644 index 000000000000..bb4877ae075f --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-console-table-column-getter-throws.js @@ -0,0 +1,42 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that a throwing console.table() column getter does not leak the ' + + 'exception into the running script.'); + +const expression = ` + (function() { + let count = 0; + const columns = []; + Object.defineProperty(columns, 0, { + get() { + // The first invocation happens in the user's own call; the second one + // comes from the inspector re-reading the columns in wrapTable(). + if (++count === 2) throw new Error('boom'); + return 'a'; + }, + enumerable: true, + configurable: true, + }); + try { + console.table([{a: 1}], columns); + return 'no throw'; + } catch (e) { + return 'threw ' + e.message; + } + })() +`; + +(async () => { + const before = await Protocol.Runtime.evaluate({expression}); + InspectorTest.log(`Runtime disabled: ${before.result.result.value}`); + + await Protocol.Runtime.enable(); + + const after = await Protocol.Runtime.evaluate({expression}); + InspectorTest.log(`Runtime enabled: ${after.result.result.value}`); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-crbug-383029265-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-383029265-expected.txt index 45997f7539b6..7fd5bd554012 100644 --- a/deps/v8/test/inspector/regress/regress-crbug-383029265-expected.txt +++ b/deps/v8/test/inspector/regress/regress-crbug-383029265-expected.txt @@ -7,6 +7,27 @@ Running test: testSubjectPause [ [0] : { + emptyReason : no-variables + endLocation : { + columnNumber : 32 + lineNumber : 2 + scriptId : <scriptId> + } + name : f + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 17 + lineNumber : 2 + scriptId : <scriptId> + } + type : block + } + [1] : { endLocation : { columnNumber : 3 lineNumber : 5 @@ -26,7 +47,7 @@ Running test: testSubjectPause } type : local } - [1] : { + [2] : { object : { className : global description : global @@ -101,6 +122,27 @@ Running test: testAsyncSubjectPause [ [0] : { + emptyReason : no-variables + endLocation : { + columnNumber : 72 + lineNumber : 2 + scriptId : <scriptId> + } + name : h + object : { + className : Object + description : Object + objectId : <objectId> + type : object + } + startLocation : { + columnNumber : 23 + lineNumber : 2 + scriptId : <scriptId> + } + type : block + } + [1] : { endLocation : { columnNumber : 3 lineNumber : 5 @@ -120,7 +162,7 @@ Running test: testAsyncSubjectPause } type : local } - [1] : { + [2] : { object : { className : global description : global diff --git a/deps/v8/test/inspector/regress/regress-crbug-568986689-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-568986689-expected.txt new file mode 100644 index 000000000000..7d475b2f18be --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-568986689-expected.txt @@ -0,0 +1,2 @@ +Regression test for crbug.com/568986689. +done diff --git a/deps/v8/test/inspector/regress/regress-crbug-568986689.js b/deps/v8/test/inspector/regress/regress-crbug-568986689.js new file mode 100644 index 000000000000..95a1f5a379a0 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-568986689.js @@ -0,0 +1,164 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-memory-corruption-api + +const {session, contextGroup, Protocol} = + InspectorTest.start('Regression test for crbug.com/568986689.'); +const PAGE_SRC = ` +var __status = 'init'; // phase-1 status, read by the client +var __status2 = 'init'; // phase-2 status, read by the client +var __hits1 = 0, __hits2 = 0; +var __stash = null; // strong JS ref to the stale JSExternalObject +var __stashMapWord = -1; // JSExternalObject map word, for verification +var K1, K2, g1, objB, graph2; +var __aG1 = 0, __aK1 = 0, __aK2 = 0, __aG2 = 0, __aObjB = 0, __stashTagged = 0; + +var SB = (typeof Sandbox !== 'undefined') ? Sandbox : null; +var PAGE = 0x40000; // V8 heap page size (256 KiB) + +function __tagged(o) { return (SB.getAddressOf(o) | 1) >>> 0; } + +function preparePhase1() { + if (!SB) { __status = 'NO_SANDBOX_API'; return __status; } + K1 = {}; K2 = {}; + g1 = {m1: K1, m2: K2}; + Object.defineProperty(g1, 'g', + {enumerable: true, configurable: true, get: __g1getter}); + __stash = null; + __status = 'prepared1'; + return __status; +} + +function snapshotAddrs1() { + __aG1 = __tagged(g1); __aK1 = __tagged(K1); __aK2 = __tagged(K2); + __status = 'snap1 g1=0x' + __aG1.toString(16) + ' K1=0x' + + __aK1.toString(16) + ' K2=0x' + __aK2.toString(16); + return __status; +} + +function __g1getter() { + try { + var probe = {}; + var probeAddr = SB.getAddressOf(probe); + var base = probeAddr - (probeAddr % PAGE); + var len = (probeAddr - base) & ~3; + if (len < 64) { __status = 'G1 window-too-small'; return 1; } + var ab = new SB.MemoryView(base, len); + var u16 = new Uint16Array(ab); + var u32 = new Uint32Array(ab); + var g1lo = __aG1 & 0xFFFF, g1hi = __aG1 >>> 16; + var k1lo = __aK1 & 0xFFFF, k1hi = __aK1 >>> 16; + var k2lo = __aK2 & 0xFFFF, k2hi = __aK2 >>> 16; + var hit = -1, hits = 0, n = u16.length - 14; + for (var i = 0; i <= n; i += 2) { + if (u16[i] === g1lo && u16[i + 1] === g1hi && + u16[i + 6] === k1lo && u16[i + 7] === k1hi && + u16[i + 12] === k2lo && u16[i + 13] === k2hi) { hit = i; hits++; } + } + __hits1 = hits; + if (hit < 0) { __status = 'G1 scan-miss len=0x' + len.toString(16); return 1; } + var extTagged = u32[(hit * 2 + 16) >> 2]; + if ((extTagged & 3) !== 1) { __status = 'G1 value-not-tagged'; return 1; } + __stash = SB.getObjectAt(extTagged); + var t = SB.getInstanceTypeOf(__stash); + if (t !== 'JS_EXTERNAL_OBJECT_TYPE') { + __status = 'G1 wrong-type: ' + t; __stash = null; return 1; + } + var sAddr = SB.getAddressOf(__stash); + __stashMapWord = new Uint32Array(new SB.MemoryView(sAddr, 8))[0]; + __status = 'stash-ok hits=' + hits + ' ext=0x' + extTagged.toString(16); + } catch (e) { + __status = 'G1-error: ' + String(e && e.message || e); + } + return 1; +} + +function preparePhase2() { + objB = {}; + graph2 = {a: objB}; // objB registered at 'a' + Object.defineProperty(graph2, 'b', // getter fires between 'a' and 'c' + {enumerable: true, configurable: true, get: __g2getter}); + graph2.c = objB; // objB re-encountered at 'c' + __status2 = 'prepared2'; + return __status2; +} + +function snapshotAddrs2() { + if (!__stash) { __status2 = 'no-stash'; return __status2; } + __aG2 = __tagged(graph2); __aObjB = __tagged(objB); + __stashTagged = __tagged(__stash); + __status2 = 'snap2 stash=0x' + __stashTagged.toString(16); + return __status2; +} + +function __g2getter() { + try { + if (!__stashTagged) { __status2 = 'G2 not-armed'; return 2; } + var probe = {}; + var probeAddr = SB.getAddressOf(probe); + var base = probeAddr - (probeAddr % PAGE); + var len = (probeAddr - base) & ~3; + if (len < 64) { __status2 = 'G2 window-too-small'; return 2; } + var ab = new SB.MemoryView(base, len); + var u16 = new Uint16Array(ab); + var u32 = new Uint32Array(ab); + var g2lo = __aG2 & 0xFFFF, g2hi = __aG2 >>> 16; + var bLo = __aObjB & 0xFFFF, bHi = __aObjB >>> 16; + var hit = -1, hits = 0, n = u16.length - 8; + for (var i = 0; i <= n; i += 2) { + if (u16[i] === g2lo && u16[i + 1] === g2hi && + u16[i + 6] === bLo && u16[i + 7] === bHi) { hit = i; hits++; } + } + __hits2 = hits; + if (hit < 0) { __status2 = 'G2 scan-miss len=0x' + len.toString(16); return 2; } + var vIdx = (hit * 2 + 16) >> 2; // objB entry's value slot + var cur = u32[vIdx]; + if ((cur & 3) !== 1) { __status2 = 'G2 cur-not-tagged'; return 2; } + var curOff = ((cur & ~3) >>> 0) - base; + if (curOff >= 0 && curOff + 4 <= len && u32[curOff >> 2] !== __stashMapWord) { + __status2 = 'G2 mapword-mismatch'; return 2; + } + u32[vIdx] = __stashTagged; + __status2 = 'swap-ok hits=' + hits; + } catch (e) { + __status2 = 'G2-error: ' + String(e && e.message || e); + } + return 2; +} +'page-script-loaded'; +`; +const MAX_ATTEMPTS = 8; + +async function ev(expr) { + const r = + await Protocol.Runtime.evaluate({expression: expr, returnByValue: true}); + return r.result.result.value; +} + +async function fullGC() { + await Protocol.HeapProfiler.collectGarbage(); + await Protocol.HeapProfiler.collectGarbage(); +} + +(async function main() { + await ev(PAGE_SRC); + for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { + await ev('preparePhase1()'); + await fullGC(); + await ev('snapshotAddrs1()'); + await Protocol.Runtime.evaluate( + {expression: 'g1', serializationOptions: {serialization: 'deep'}}); + const st1 = await ev('__status'); + if (!/^stash-ok/.test(st1)) continue; + await ev('preparePhase2()'); + await fullGC(); + await ev('snapshotAddrs2()'); + await Protocol.Runtime.evaluate( + {expression: 'graph2', serializationOptions: {serialization: 'deep'}}); + break; + } + InspectorTest.log('done'); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-crbug-570558711-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-570558711-expected.txt new file mode 100644 index 000000000000..ad79ba0e4357 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-570558711-expected.txt @@ -0,0 +1,17 @@ +Regression test for crbug.com/570558711 + +Running test: testInvalidSamplingInterval +{ + error : { + code : -32000 + message : Invalid sampling interval + } + id : <messageId> +} +{ + error : { + code : -32000 + message : Invalid sampling interval + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/regress/regress-crbug-570558711.js b/deps/v8/test/inspector/regress/regress-crbug-570558711.js new file mode 100644 index 000000000000..95cfaec9207d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-570558711.js @@ -0,0 +1,18 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {contextGroup, Protocol} = InspectorTest.start('Regression test for crbug.com/570558711'); + +InspectorTest.runAsyncTestSuite([ + async function testInvalidSamplingInterval() { + await Protocol.Profiler.enable(); + let message = await Protocol.Profiler.setSamplingInterval({interval: 0}); + InspectorTest.logMessage(message); + message = await Protocol.Profiler.setSamplingInterval({interval: -1}); + InspectorTest.logMessage(message); + await Protocol.Profiler.start(); + await Protocol.Profiler.stop(); + await Protocol.Profiler.disable(); + } +]); diff --git a/deps/v8/test/inspector/regress/regress-crbug-571211187-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-571211187-expected.txt new file mode 100644 index 000000000000..36db45ff237f --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571211187-expected.txt @@ -0,0 +1,7 @@ +Tests that console.assert does not crash when the context has no contextGroupId + +Running test: testAssertInDestroyedContext + +Running test: testDestroyContextDuringAssertFormatting + +Running test: testDestroyContextDuringAssertWrapping diff --git a/deps/v8/test/inspector/regress/regress-crbug-571211187.js b/deps/v8/test/inspector/regress/regress-crbug-571211187.js new file mode 100644 index 000000000000..5bba0a32dadc --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571211187.js @@ -0,0 +1,80 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests that console.assert does not crash when the context has no contextGroupId'); + +InspectorTest.runAsyncTestSuite([ + async function testAssertInDestroyedContext() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + + contextGroup.createContext('destroyed-before-assert'); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + await Protocol.Runtime.evaluate({ + expression: ` + inspector.fireContextDestroyed(); + console.assert(false); + `, + uniqueContextId: uniqueId, + }); + + await Protocol.Debugger.disable(); + await Protocol.Runtime.disable(); + }, + + async function testDestroyContextDuringAssertFormatting() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + + contextGroup.createContext('destroyed-during-formatting'); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + await Protocol.Runtime.evaluate({ + expression: ` + const err = new Error('trigger'); + Object.defineProperty(err, 'name', { + get() { + inspector.fireContextDestroyed(); + return 'Error'; + }, + }); + console.assert(false, err); + `, + uniqueContextId: uniqueId, + }); + + await Protocol.Debugger.disable(); + await Protocol.Runtime.disable(); + }, + + async function testDestroyContextDuringAssertWrapping() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await Protocol.Debugger.setPauseOnExceptions({state: 'all'}); + + contextGroup.createContext('destroyed-during-wrapping'); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + await Protocol.Runtime.evaluate({ + expression: ` + Error.prepareStackTrace = function(error, trace) { + inspector.fireContextDestroyed(); + return '<mock formatted stack trace>'; + }; + console.assert(false, new Error('trigger')); + `, + uniqueContextId: uniqueId, + }); + + await Protocol.Debugger.disable(); + await Protocol.Runtime.disable(); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-crbug-571845147-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-571845147-expected.txt new file mode 100644 index 000000000000..0fdb37af1ec6 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571845147-expected.txt @@ -0,0 +1,4 @@ +Tests that objects logged during context destruction are not retained forever. + +Running test: testMemoryLeak +No leak detected. diff --git a/deps/v8/test/inspector/regress/regress-crbug-571845147.js b/deps/v8/test/inspector/regress/regress-crbug-571845147.js new file mode 100644 index 000000000000..c8d0ce1cab22 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571845147.js @@ -0,0 +1,117 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-stress-incremental-marking + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that objects logged during context destruction are not retained forever.'); + +const kNodeName = 1; +const kNodeEdgeCount = 4; +const kNodeSize = 6; +const kEdgeName = 1; +const kEdgeTarget = 2; +const kEdgeSize = 3; + +function EdgeName(snapshot, edgeIndex) { + return snapshot['strings'][snapshot['edges'][edgeIndex + kEdgeName]]; +} + +function EdgeTarget(snapshot, edgeIndex) { + return snapshot['edges'][edgeIndex + kEdgeTarget]; +} + +function EdgeCount(snapshot, nodeIndex) { + return snapshot['nodes'][nodeIndex + kNodeEdgeCount]; +} + +function NodeName(snapshot, nodeIndex) { + return snapshot['strings'][snapshot['nodes'][nodeIndex + kNodeName]]; +} + +function NodeEdges(snapshot, nodeIndex) { + let startEdgeIndex = 0; + for (let i = 0; i < nodeIndex; i += kNodeSize) { + startEdgeIndex += EdgeCount(snapshot, i); + } + let endEdgeIndex = startEdgeIndex + EdgeCount(snapshot, nodeIndex); + let result = []; + for (let i = startEdgeIndex; i < endEdgeIndex; ++i) { + result.push(i * kEdgeSize); + } + return result; +} + +function NodeByName(snapshot, name) { + let count = snapshot['nodes'].length / kNodeSize; + for (let i = 0; i < count; i++) { + if (NodeName(snapshot, i * kNodeSize) == name) return i * kNodeSize; + } + return -1; +} + +function GlobalHandleEdgeNames(snapshot, targetName) { + let targetIndex = NodeByName(snapshot, targetName); + if (targetIndex === -1) return []; + let sourceIndex = NodeByName(snapshot, '(Global handles)'); + if (sourceIndex === -1) return []; + + let edges = NodeEdges(snapshot, sourceIndex); + let results = []; + for (let edge of edges) { + if (EdgeTarget(snapshot, edge) == targetIndex) { + let edgeName = EdgeName(snapshot, edge); + results.push(edgeName.substring(edgeName.indexOf('/') + 2)); + } + } + return results; +} + +InspectorTest.runAsyncTestSuite([async function testMemoryLeak() { + await Protocol.Runtime.enable(); + await Protocol.HeapProfiler.enable(); + + contextGroup.createContext('destroyed-context'); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + await Protocol.Runtime.evaluate({ + expression: ` + (() => { + class MyLeakedObject extends Error {}; + const err = new MyLeakedObject(); + Object.defineProperty(err, 'name', { + get() { + inspector.fireContextDestroyed(); + return 'Error'; + }, + }); + console.log(err); + })(); + `, + uniqueContextId: uniqueId, + }); + + // Now the context is destroyed. + // The console.log should not retain MyLeakedObject in group 0 storage. + let snapshot_string = ''; + function onChunk(message) { + snapshot_string += message['params']['chunk']; + } + Protocol.HeapProfiler.onAddHeapSnapshotChunk(onChunk); + await Protocol.HeapProfiler.collectGarbage(); + await Protocol.HeapProfiler.takeHeapSnapshot({reportProgress: false}); + let snapshot = JSON.parse(snapshot_string); + let edges = GlobalHandleEdgeNames(snapshot, 'MyLeakedObject'); + if (edges.length > 0) { + InspectorTest.log( + `Leak detected: edge from (Global handles) to MyLeakedObject: ${ + edges.join(', ')}`); + } else { + InspectorTest.log('No leak detected.'); + } + + await Protocol.Runtime.disable(); + await Protocol.HeapProfiler.disable(); +}]); diff --git a/deps/v8/test/inspector/regress/regress-crbug-571979576-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-571979576-expected.txt new file mode 100644 index 000000000000..aff4767e3e7a --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571979576-expected.txt @@ -0,0 +1,4 @@ +Tests that objects logged are not retained when custom formatters destroy the context. + +Running test: testMemoryLeak +No leak detected. diff --git a/deps/v8/test/inspector/regress/regress-crbug-571979576.js b/deps/v8/test/inspector/regress/regress-crbug-571979576.js new file mode 100644 index 000000000000..433724102146 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571979576.js @@ -0,0 +1,118 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-stress-incremental-marking + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that objects logged are not retained when custom formatters destroy the context.'); + +const kNodeName = 1; +const kNodeEdgeCount = 4; +const kNodeSize = 6; +const kEdgeName = 1; +const kEdgeTarget = 2; +const kEdgeSize = 3; + +function EdgeName(snapshot, edgeIndex) { + return snapshot['strings'][snapshot['edges'][edgeIndex + kEdgeName]]; +} + +function EdgeTarget(snapshot, edgeIndex) { + return snapshot['edges'][edgeIndex + kEdgeTarget]; +} + +function EdgeCount(snapshot, nodeIndex) { + return snapshot['nodes'][nodeIndex + kNodeEdgeCount]; +} + +function NodeName(snapshot, nodeIndex) { + return snapshot['strings'][snapshot['nodes'][nodeIndex + kNodeName]]; +} + +function NodeEdges(snapshot, nodeIndex) { + let startEdgeIndex = 0; + for (let i = 0; i < nodeIndex; i += kNodeSize) { + startEdgeIndex += EdgeCount(snapshot, i); + } + let endEdgeIndex = startEdgeIndex + EdgeCount(snapshot, nodeIndex); + let result = []; + for (let i = startEdgeIndex; i < endEdgeIndex; ++i) { + result.push(i * kEdgeSize); + } + return result; +} + +function NodeByName(snapshot, name) { + let count = snapshot['nodes'].length / kNodeSize; + for (let i = 0; i < count; i++) { + if (NodeName(snapshot, i * kNodeSize) == name) return i * kNodeSize; + } + return -1; +} + +function GlobalHandleEdgeNames(snapshot, targetName) { + let targetIndex = NodeByName(snapshot, targetName); + if (targetIndex === -1) return []; + let sourceIndex = NodeByName(snapshot, '(Global handles)'); + if (sourceIndex === -1) return []; + + let edges = NodeEdges(snapshot, sourceIndex); + let results = []; + for (let edge of edges) { + if (EdgeTarget(snapshot, edge) == targetIndex) { + let edgeName = EdgeName(snapshot, edge); + results.push(edgeName.substring(edgeName.indexOf('/') + 2)); + } + } + return results; +} + +InspectorTest.runAsyncTestSuite([async function testMemoryLeak() { + await Protocol.Runtime.enable(); + await Protocol.HeapProfiler.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + + contextGroup.createContext('destroyed-context'); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + await Protocol.Runtime.evaluate({ + expression: ` + (() => { + class MyLeakedObject {}; + globalThis.devtoolsFormatters = [{ + header(o) { + if (o instanceof MyLeakedObject) inspector.fireContextDestroyed(); + return null; + }, + hasBody() { return false; } + }]; + console.log(new MyLeakedObject()); + })(); + `, + uniqueContextId: uniqueId, + }); + + // Now the context is destroyed. + // The console.log should not retain MyLeakedObject in group 0 storage. + let snapshot_string = ''; + function onChunk(message) { + snapshot_string += message['params']['chunk']; + } + Protocol.HeapProfiler.onAddHeapSnapshotChunk(onChunk); + await Protocol.HeapProfiler.collectGarbage(); + await Protocol.HeapProfiler.takeHeapSnapshot({reportProgress: false}); + let snapshot = JSON.parse(snapshot_string); + let edges = GlobalHandleEdgeNames(snapshot, 'MyLeakedObject'); + if (edges.length > 0) { + InspectorTest.log( + `Leak detected: edge from (Global handles) to MyLeakedObject: ${ + edges.join(', ')}`); + } else { + InspectorTest.log('No leak detected.'); + } + + await Protocol.Runtime.disable(); + await Protocol.HeapProfiler.disable(); +}]); diff --git a/deps/v8/test/inspector/regress/regress-crbug-571984048-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-571984048-expected.txt new file mode 100644 index 000000000000..2e0845ac5edd --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571984048-expected.txt @@ -0,0 +1,8 @@ +Tests that console label APIs bail out when the context is destroyed during label conversion. + +Running test: testLabelConversion +console.count(): error: Cannot find context with specified id +console.countReset(): error: Cannot find context with specified id +console.time(): error: Cannot find context with specified id +console.timeLog(): error: Cannot find context with specified id +console.timeEnd(): error: Cannot find context with specified id diff --git a/deps/v8/test/inspector/regress/regress-crbug-571984048.js b/deps/v8/test/inspector/regress/regress-crbug-571984048.js new file mode 100644 index 000000000000..5629539e7013 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-571984048.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that console label APIs bail out when the context is destroyed ' + + 'during label conversion.'); + +InspectorTest.runAsyncTestSuite([async function testLabelConversion() { + await Protocol.Runtime.enable(); + Protocol.Runtime.onConsoleAPICalled( + ({params: {type}}) => + InspectorTest.log(`Unexpected console API call: ${type}`)); + + for (const method of ['count', 'countReset', 'time', 'timeLog', + 'timeEnd']) { + contextGroup.createContext(`destroyed-context-${method}`); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + const {result, error} = await Protocol.Runtime.evaluate({ + expression: ` + console.${method}({ + toString() { + inspector.fireContextDestroyed(); + return 'label'; + } + }); + 'done'; + `, + uniqueContextId: uniqueId, + }); + InspectorTest.log(`console.${method}(): ${ + error ? `error: ${error.message}` : result.result.value}`); + } + + await Protocol.Runtime.disable(); +}]); diff --git a/deps/v8/test/inspector/regress/regress-crbug-572821841-expected.txt b/deps/v8/test/inspector/regress/regress-crbug-572821841-expected.txt new file mode 100644 index 000000000000..8d9947a4b17c --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-572821841-expected.txt @@ -0,0 +1,4 @@ +Tests that custom formatter error strings are not retained in group 0 when context is destroyed. + +Running test: testMemoryLeak +No leak detected. diff --git a/deps/v8/test/inspector/regress/regress-crbug-572821841.js b/deps/v8/test/inspector/regress/regress-crbug-572821841.js new file mode 100644 index 000000000000..91e3e333e586 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-crbug-572821841.js @@ -0,0 +1,142 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-stress-incremental-marking + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that custom formatter error strings are not retained in group 0 ' + + 'when context is destroyed.'); + +const kNodeName = 1; +const kNodeEdgeCount = 4; +const kNodeSize = 6; +const kEdgeName = 1; +const kEdgeTarget = 2; +const kEdgeSize = 3; + +function EdgeName(snapshot, edgeIndex) { + return snapshot['strings'][snapshot['edges'][edgeIndex + kEdgeName]]; +} + +function EdgeTarget(snapshot, edgeIndex) { + return snapshot['edges'][edgeIndex + kEdgeTarget]; +} + +function EdgeCount(snapshot, nodeIndex) { + return snapshot['nodes'][nodeIndex + kNodeEdgeCount]; +} + +function NodeName(snapshot, nodeIndex) { + return snapshot['strings'][snapshot['nodes'][nodeIndex + kNodeName]]; +} + +function NodeByName(snapshot, name) { + let count = snapshot['nodes'].length / kNodeSize; + for (let i = 0; i < count; i++) { + if (NodeName(snapshot, i * kNodeSize) == name) return i * kNodeSize; + } + return -1; +} + +InspectorTest.runAsyncTestSuite([async function testMemoryLeak() { + await Protocol.Runtime.enable(); + await Protocol.HeapProfiler.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + + Protocol.Runtime.onConsoleAPICalled( + message => { + // Suppress console API log output to keep expected.txt clean. + }); + + contextGroup.createContext('destroyed-context'); + const {params: {context: {uniqueId}}} = + await Protocol.Runtime.onceExecutionContextCreated(); + + await Protocol.Runtime.evaluate({ + expression: ` + (() => { + class MyLeakedObject {}; + globalThis.devtoolsFormatters = [{ + header(o) { + if (o instanceof MyLeakedObject) { + inspector.fireContextDestroyed(); + throw new Error('MyUniqueLeakedString'); + } + return null; + }, + hasBody() { return false; } + }]; + console.log(new MyLeakedObject()); + })(); + `, + uniqueContextId: uniqueId, + }); + + // Now the context is destroyed. + // The error string should not be retained in group 0 storage. + let snapshot_string = ''; + function onChunk(message) { + snapshot_string += message['params']['chunk']; + } + Protocol.HeapProfiler.onAddHeapSnapshotChunk(onChunk); + await Protocol.HeapProfiler.collectGarbage(); + await Protocol.HeapProfiler.takeHeapSnapshot({reportProgress: false}); + let snapshot = JSON.parse(snapshot_string); + + let found_strings = []; + for (let i = 0; i < snapshot['strings'].length; i++) { + let s = snapshot['strings'][i]; + if (s.includes('Uncaught Error: MyUniqueLeakedString')) { + found_strings.push(s); + } + } + + let leak_detected = false; + if (found_strings.length > 0) { + let targetIndex = NodeByName(snapshot, found_strings[0]); + let consStringIndex = -1; + if (targetIndex !== -1) { + let count = snapshot['nodes'].length / kNodeSize; + let edgeIndex = 0; + for (let i = 0; i < count; i++) { + let edgeCount = EdgeCount(snapshot, i * kNodeSize); + for (let j = 0; j < edgeCount; j++) { + if (EdgeTarget(snapshot, edgeIndex) === targetIndex) { + if (NodeName(snapshot, i * kNodeSize) === '(concatenated string)') { + consStringIndex = i * kNodeSize; + } + } + edgeIndex += kEdgeSize; + } + } + } + if (consStringIndex !== -1) { + let count = snapshot['nodes'].length / kNodeSize; + let edgeIndex = 0; + for (let i = 0; i < count; i++) { + let edgeCount = EdgeCount(snapshot, i * kNodeSize); + for (let j = 0; j < edgeCount; j++) { + if (EdgeTarget(snapshot, edgeIndex) === consStringIndex) { + if (NodeName(snapshot, i * kNodeSize) === '(Global handles)') { + let edgeName = EdgeName(snapshot, edgeIndex); + if (edgeName.includes('DevTools console')) { + leak_detected = true; + } + } + } + edgeIndex += kEdgeSize; + } + } + } + } + + if (leak_detected) { + InspectorTest.log('Leak detected.'); + } else { + InspectorTest.log('No leak detected.'); + } + + await Protocol.Runtime.disable(); + await Protocol.HeapProfiler.disable(); +}]); diff --git a/deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses-expected.txt b/deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses-expected.txt new file mode 100644 index 000000000000..d8e5e537860d --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses-expected.txt @@ -0,0 +1,12 @@ +Checks that custom formatters cannot bypass length limits via object tags or nested escaping. + +Running test: setUp + +Running test: testDirectString +[DirectString] no custom preview + +Running test: testObjectTags +[ObjectTags] no custom preview + +Running test: testNestedHeader +[NestedHeader] no custom preview diff --git a/deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses.js b/deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses.js new file mode 100644 index 000000000000..a60d2f59afc8 --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-inspector-custom-preview-bypasses.js @@ -0,0 +1,74 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom formatters cannot bypass length limits via object tags or nested escaping.'); + +contextGroup.addScript(` + globalThis.devtoolsFormatters = [ + { + header(object) { + if (object.kind === 'direct_string') { + const s = 'x'.repeat(4e6); + return ['div', s, s, s]; + } + if (object.kind === 'object_tags') { + const s = 'x'.repeat(4e6); + return ['div', + ['object', {object: s}], + ['object', {object: s}], + ['object', {object: s}] + ]; + } + if (object.kind === 'nested_header') { + if (object.depth > 0) { + return ['div', ['object', {object: {kind: 'nested_header', depth: object.depth - 1, s: object.s}}]]; + } + return ['div', object.s]; + } + return null; + }, + hasBody() { return false; }, + } + ]; +`); + +async function evaluateWithCustomPreview(expression, bypassName) { + const {result: {result}} = + await Protocol.Runtime.evaluate({expression, generatePreview: true}); + if (result.customPreview) { + const len = result.customPreview.header.length; + InspectorTest.logMessage(`[${bypassName}] customPreview length: ${len}`); + if (len > 10_000_000) { + InspectorTest.logMessage( + `FAILURE: ${bypassName} bypassed the 10M budget!`); + } + } else { + InspectorTest.logMessage(`[${bypassName}] no custom preview`); + } +} + +InspectorTest.runAsyncTestSuite([ + async function setUp() { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + }, + + async function testDirectString() { + await evaluateWithCustomPreview( + `({kind: 'direct_string'})`, 'DirectString'); + }, + + async function testObjectTags() { + await evaluateWithCustomPreview(`({kind: 'object_tags'})`, 'ObjectTags'); + }, + + async function testNestedHeader() { + contextGroup.addScript(` + var bad_string = '\\\\\\\\'.repeat(2e6); // 2 million backslashes + `); + await evaluateWithCustomPreview( + `({kind: 'nested_header', depth: 4, s: bad_string})`, 'NestedHeader'); + }, +]); diff --git a/deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow-expected.txt b/deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow-expected.txt new file mode 100644 index 000000000000..7a6e4846ab8e --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow-expected.txt @@ -0,0 +1,8 @@ +Tests that deep serialization gracefully reports stack overflow. +{ + error : { + code : -32000 + message : exception during deep serialization + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow.js b/deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow.js new file mode 100644 index 000000000000..7c86db4cc9bd --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-inspector-deep-serialization-stack-overflow.js @@ -0,0 +1,27 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Lower the C++ stack limit so 1000-level C++ recursion in +// `buildDeepSerializedValue` hits the stack overflow check on both native and +// simulator builds. +// Flags: --stack-size=100 + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests that deep serialization gracefully reports stack overflow.'); + +contextGroup.addScript(` +// Build a 1000-level nested array matching kMaxProtocolDepth. +let deepArray = []; +for (let i = 0; i < 1000; i++) { + deepArray = [deepArray]; +} +`); + +(async function test() { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: 'deepArray', + serializationOptions: {serialization: 'deep'}, + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-nested-stack-switch-catch-expected.txt b/deps/v8/test/inspector/regress/regress-nested-stack-switch-catch-expected.txt new file mode 100644 index 000000000000..a5399b53659b --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-nested-stack-switch-catch-expected.txt @@ -0,0 +1,38 @@ +Tests nested Wasm stack-switching catch inside breakpoint condition. +{ + id : <messageId> + result : { + actualLocation : { + columnNumber : 79 + lineNumber : 0 + scriptId : <scriptId> + } + breakpointId : <breakpointId> + } +} +{ + id : <messageId> + result : { + exceptionDetails : { + columnNumber : 81 + exception : { + className : RuntimeError + description : RuntimeError: unreachable at target (wasm://wasm/7f608ad6:wasm-function[1]:0x51) at <anonymous>:1:18 + objectId : <objectId> + subtype : error + type : object + } + exceptionId : <exceptionId> + lineNumber : 0 + scriptId : <scriptId> + text : Uncaught + } + result : { + className : RuntimeError + description : RuntimeError: unreachable at target (wasm://wasm/7f608ad6:wasm-function[1]:0x51) at <anonymous>:1:18 + objectId : <objectId> + subtype : error + type : object + } + } +} diff --git a/deps/v8/test/inspector/regress/regress-nested-stack-switch-catch.js b/deps/v8/test/inspector/regress/regress-nested-stack-switch-catch.js new file mode 100644 index 000000000000..43197a0610cb --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-nested-stack-switch-catch.js @@ -0,0 +1,77 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --stress-wasm-stack-switching + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests nested Wasm stack-switching catch inside breakpoint condition.'); + +contextGroup.addScript(utils.read('test/mjsunit/wasm/wasm-module-builder.js')); + +contextGroup.addScript(` +const builder = new WasmModuleBuilder(); +builder.addMemory(1); +const tag = builder.addTag(kSig_v_v); + +// target2: throws and catches internally. +// With --stress-wasm-stack-switching, this will run on Stack 2. +builder.addFunction('target2', kSig_v_v) + .addBody([ + kExprTry, kWasmVoid, + kExprThrow, tag, + kExprCatch, tag, + kExprEnd + ]).exportFunc(); + +// target: hits breakpoint. +// With --stress-wasm-stack-switching, this will run on Stack 1. +const body = [...wasmI32Const(5), kExprI32LoadMem, 0, kExprDrop, + ...wasmI32Const(5), ...wasmI32Const(5), 0]; +const target = builder.addFunction('target', kSig_v_v) + .addBody(body).exportFunc(); + +const buffer = builder.toBuffer(); +// Offset of the I32LoadMem instruction. +const bodyOffset = target.body_offset + 6; +let instance; +`); + +(async () => { + await Protocol.Debugger.enable(); + + // Instantiate triggers compilation and sends scriptParsed event (which sets + // scriptId). + const scriptParsedPromise = Protocol.Debugger.onceScriptParsed(2); + const { + result: {result: {value: bodyOffset}} + } = await Protocol.Runtime.evaluate({ + expression: + 'instance = new WebAssembly.Instance(new WebAssembly.Module(buffer)); bodyOffset', + returnByValue: true, + }); + const [, {params: {scriptId}}] = await scriptParsedPromise; + + // Condition for breakpoint: call target2. + const condition = `(function() { + instance.exports.target2(); +})()`; + + InspectorTest.logMessage(await Protocol.Debugger.setBreakpoint({ + location: { + scriptId, + lineNumber: 0, + columnNumber: bodyOffset, + }, + condition, + })); + + // Run target. It will hit breakpoint, evaluate condition (runs target2 on + // Stack 2), target2 catches exception and clears secondary SP. When target + // resumes, it should not crash. + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: 'instance.exports.target()', + })); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-proxy-has-command-line-api-expected.txt b/deps/v8/test/inspector/regress/regress-proxy-has-command-line-api-expected.txt new file mode 100644 index 000000000000..4a3896862a3e --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-proxy-has-command-line-api-expected.txt @@ -0,0 +1,24 @@ +Tests that CommandLineAPIScope uses HasRealNamedProperty and does not trigger a Proxy has trap on globalThis. +{ + id : <messageId> + result : { + result : { + description : 2 + type : number + value : 2 + } + } +} +{ + id : <messageId> + result : { + result : { + type : object + value : { + globalDebugType : undefined + leakedDebugType : undefined + sideEffectTriggered : false + } + } + } +} diff --git a/deps/v8/test/inspector/regress/regress-proxy-has-command-line-api.js b/deps/v8/test/inspector/regress/regress-proxy-has-command-line-api.js new file mode 100644 index 000000000000..9d42178ea50c --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-proxy-has-command-line-api.js @@ -0,0 +1,35 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = InspectorTest.start( + 'Tests that CommandLineAPIScope uses HasRealNamedProperty and does not trigger a Proxy has trap on globalThis.'); + +contextGroup.addScript(` +let leakedDebug; +let sideEffectTriggered = false; + +Object.setPrototypeOf(globalThis, new Proxy({}, { + has(target, prop) { + if (prop === 'queryObjects') { + leakedDebug = globalThis.debug; + sideEffectTriggered = true; + } + return false; + } +})); +`); + +(async function test() { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + includeCommandLineAPI: true, + throwOnSideEffect: true, + expression: '1 + 1', + })); + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: + '({sideEffectTriggered, leakedDebugType: typeof leakedDebug, globalDebugType: typeof globalThis.debug})', + returnByValue: true, + })); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install-expected.txt b/deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install-expected.txt new file mode 100644 index 000000000000..689daebb370f --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install-expected.txt @@ -0,0 +1,2 @@ +Runtime.terminateExecution followed by resume(terminateOnResume) +Resumed without crashing diff --git a/deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install.js b/deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install.js new file mode 100644 index 000000000000..5489468d18bc --- /dev/null +++ b/deps/v8/test/inspector/regress/regress-terminate-on-resume-double-install.js @@ -0,0 +1,23 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Debugger.resume({terminateOnResume: true}) must not install the termination +// callbacks a second time when a Runtime.terminateExecution request is already +// pending. + +let {session, contextGroup, Protocol} = InspectorTest.start( + 'Runtime.terminateExecution followed by resume(terminateOnResume)'); + +(async function test() { + await Protocol.Debugger.enable(); + const paused = Protocol.Debugger.oncePaused(); + Protocol.Runtime.evaluate({expression: `debugger; for (;;) {}`}); + await paused; + // Do not await: the pause loop keeps running, so the termination is not + // reported while we are paused. + Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume({terminateOnResume: true}); + InspectorTest.log('Resumed without crashing'); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/console-context-expected.txt b/deps/v8/test/inspector/runtime/console-context-expected.txt index a77b4fa72ba0..d5bcf73edd02 100644 --- a/deps/v8/test/inspector/runtime/console-context-expected.txt +++ b/deps/v8/test/inspector/runtime/console-context-expected.txt @@ -94,3 +94,16 @@ Running test: testConsoleTimeInDifferentConsoleContexts value : foo: 2 ms } ] + +Running test: testConsoleAssertInConsoleContext +assert-context#13 +[ + [0] : { + type : string + value : failed %s + } + [1] : { + type : string + value : assertion + } +] diff --git a/deps/v8/test/inspector/runtime/console-context.js b/deps/v8/test/inspector/runtime/console-context.js index d7db3091916a..eda095373f8f 100644 --- a/deps/v8/test/inspector/runtime/console-context.js +++ b/deps/v8/test/inspector/runtime/console-context.js @@ -135,5 +135,27 @@ InspectorTest.runAsyncTestSuite([ ({params: {args}}) => InspectorTest.logMessage(args)), ]); await Protocol.Runtime.disable(); + }, + + async function testConsoleAssertInConsoleContext() { + await Protocol.Runtime.enable(); + Protocol.Runtime.evaluate({ + expression: ` + var assertContext = console.context('assert-context'); + assertContext.assert(true); + assertContext.assert(true, '%s', { + toString() { + throw new Error('Should not format when condition is true'); + } + }); + assertContext.assert(false, 'failed %s', 'assertion'); + `, + }); + var {params: {context, args}} = + await Protocol.Runtime.onceConsoleAPICalled(); + InspectorTest.log(context); + InspectorTest.logMessage(args); + await Protocol.Runtime.evaluate({expression: 'console.clear()'}); + await Protocol.Runtime.disable(); } ]); diff --git a/deps/v8/test/inspector/runtime/console-label-conversion-failure-expected.txt b/deps/v8/test/inspector/runtime/console-label-conversion-failure-expected.txt new file mode 100644 index 000000000000..7b8058951a6f --- /dev/null +++ b/deps/v8/test/inspector/runtime/console-label-conversion-failure-expected.txt @@ -0,0 +1,21 @@ +Checks that console methods propagate failures of label conversions. +Without Runtime domain: +console.count: TypeError, CustomError +console.countReset: TypeError, CustomError +console.profile: TypeError, CustomError +console.profileEnd: TypeError, CustomError +console.time: TypeError, CustomError +console.timeLog: TypeError, CustomError +console.timeEnd: TypeError, CustomError +console.timeStamp: TypeError, CustomError +With Runtime domain: +console.count: TypeError, CustomError +console.countReset: TypeError, CustomError +console.profile: TypeError, CustomError +console.profileEnd: TypeError, CustomError +console.time: TypeError, CustomError +console.timeLog: TypeError, CustomError +console.timeEnd: TypeError, CustomError +console.timeStamp: TypeError, CustomError +Terminating execution during label conversion: +Execution was terminated diff --git a/deps/v8/test/inspector/runtime/console-label-conversion-failure.js b/deps/v8/test/inspector/runtime/console-label-conversion-failure.js new file mode 100644 index 000000000000..5f2c00a399a2 --- /dev/null +++ b/deps/v8/test/inspector/runtime/console-label-conversion-failure.js @@ -0,0 +1,80 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that console methods propagate failures of label conversions.'); + +contextGroup.addScript(` +class CustomError extends Error {} + +function test(method) { + const labels = [ + Symbol('label'), + {toString() { throw new CustomError(); }}, + ]; + const results = []; + for (const label of labels) { + try { + // Pass an additional argument, which console.timeLog() and + // console.timeStamp() report along with the label. + console[method](label, {}); + results.push('no exception'); + } catch (e) { + results.push(e.constructor.name); + } + } + return \`console.\${method}: \${results.join(', ')}\`; +} +`); + +const methods = [ + 'count', + 'countReset', + 'profile', + 'profileEnd', + 'time', + 'timeLog', + 'timeEnd', + 'timeStamp', +]; + +async function testMethods() { + for (const method of methods) { + const {result: {result: {value}}} = + await Protocol.Runtime.evaluate({expression: `test('${method}')`}); + InspectorTest.log(value); + } +} + +(async () => { + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`console.${type}: ${args.map(({value}) => value)}`); + }); + + InspectorTest.log('Without Runtime domain:'); + await testMethods(); + + InspectorTest.log('With Runtime domain:'); + await Protocol.Runtime.enable(); + await testMethods(); + + InspectorTest.log('Terminating execution during label conversion:'); + await Protocol.Debugger.enable(); + const paused = Protocol.Debugger.oncePaused(); + const evaluation = Protocol.Runtime.evaluate({ + expression: ` + console.time(); + console.timeLog({toString() { debugger; for (;;) {} }}, {}); + console.log('FAIL: execution continued after termination'); + ` + }); + await paused; + const terminated = Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + await terminated; + const {error} = await evaluation; + InspectorTest.log(error?.message); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/custom-preview-body-too-long-expected.txt b/deps/v8/test/inspector/runtime/custom-preview-body-too-long-expected.txt new file mode 100644 index 000000000000..574b5ffc978f --- /dev/null +++ b/deps/v8/test/inspector/runtime/custom-preview-body-too-long-expected.txt @@ -0,0 +1,5 @@ +Checks that custom formatter body does not crash on huge strings. +error: Custom Formatter Failed: Uncaught JSONML is too large +{ + type : undefined +} diff --git a/deps/v8/test/inspector/runtime/custom-preview-body-too-long.js b/deps/v8/test/inspector/runtime/custom-preview-body-too-long.js new file mode 100644 index 000000000000..381c0426c7d2 --- /dev/null +++ b/deps/v8/test/inspector/runtime/custom-preview-body-too-long.js @@ -0,0 +1,51 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom formatter body does not crash on huge strings.'); + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`${type}: ${args.map(({value}) => value).join(' ')}`); + }); + + await Protocol.Runtime.evaluate({ + expression: ` + const s = 'a'.repeat(%StringMaxLength()); + globalThis.devtoolsFormatters = [{ + header(object) { + return ['span', 'x']; + }, + hasBody(object) { + return true; + }, + body(object) { + return ['div', s]; + } + }]; + ` + }); + + const result = await Protocol.Runtime.evaluate( + {expression: '({})', generatePreview: true}); + + const customPreview = result.result.result.customPreview; + if (customPreview && customPreview.bodyGetterId) { + const objectId = result.result.result.objectId; + const body = await Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: + 'function(bodyGetter) { return bodyGetter.call(this); }', + arguments: [{objectId: customPreview.bodyGetterId}], + returnByValue: true + }); + InspectorTest.logMessage(body.result.result); + } + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/custom-preview-long-error-message-expected.txt b/deps/v8/test/inspector/runtime/custom-preview-long-error-message-expected.txt new file mode 100644 index 000000000000..727ad95a7621 --- /dev/null +++ b/deps/v8/test/inspector/runtime/custom-preview-long-error-message-expected.txt @@ -0,0 +1,2 @@ +Checks that custom formatter errors with too long messages are reported. +error: Custom Formatter Failed: <message too long> diff --git a/deps/v8/test/inspector/runtime/custom-preview-long-error-message.js b/deps/v8/test/inspector/runtime/custom-preview-long-error-message.js new file mode 100644 index 000000000000..564f3f038203 --- /dev/null +++ b/deps/v8/test/inspector/runtime/custom-preview-long-error-message.js @@ -0,0 +1,32 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that custom formatter errors with too long messages are reported.'); + +(async () => { + await Protocol.Runtime.enable(); + await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true}); + Protocol.Runtime.onConsoleAPICalled(({params: {type, args}}) => { + InspectorTest.log(`${type}: ${args.map(({value}) => value).join(' ')}`); + }); + + // Throw a string such that the message for the uncaught exception (i.e. + // "Uncaught " followed by the thrown string) has the maximum string length. + await Protocol.Runtime.evaluate({ + expression: ` + const error = 'a'.repeat(%StringMaxLength() - 'Uncaught '.length); + globalThis.devtoolsFormatters = [{ + header(object) { + throw error; + } + }]; + ` + }); + await Protocol.Runtime.evaluate({expression: '({})', generatePreview: true}); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/deep-serialization-errors-expected.txt b/deps/v8/test/inspector/runtime/deep-serialization-errors-expected.txt index 3d96a162a941..eb490ae98af1 100644 --- a/deps/v8/test/inspector/runtime/deep-serialization-errors-expected.txt +++ b/deps/v8/test/inspector/runtime/deep-serialization-errors-expected.txt @@ -42,6 +42,27 @@ Runtime.callFunctionOn id : <messageId> } +Running test: LargeSparseArray +testing expression: (()=>{ const a = []; a.length = 0xFFFFFFFF; return a; })() +Runtime.evaluate +...no deepSerializedValue... +{ + error : { + code : -32000 + message : Array length exceeds maximum limit for deep serialization + } + id : <messageId> +} +Runtime.callFunctionOn +...no deepSerializedValue... +{ + error : { + code : -32000 + message : Array length exceeds maximum limit for deep serialization + } + id : <messageId> +} + Running test: NestedThrowingGetter testing expression: ({ a: { b: [ { get c() { throw new Error('nested error'); } } ] } }) Runtime.evaluate diff --git a/deps/v8/test/inspector/runtime/deep-serialization-errors.js b/deps/v8/test/inspector/runtime/deep-serialization-errors.js index f0f50a55ed92..3bd354b99277 100644 --- a/deps/v8/test/inspector/runtime/deep-serialization-errors.js +++ b/deps/v8/test/inspector/runtime/deep-serialization-errors.js @@ -15,6 +15,9 @@ InspectorTest.runAsyncTestSuite([ async function ArrayThrowingGetter() { await testExpression("(()=>{ const a = [1]; Object.defineProperty(a, '1', { get() { throw new Error('array element error'); }, enumerable: true }); return a; })()"); }, + async function LargeSparseArray() { + await testExpression("(()=>{ const a = []; a.length = 0xFFFFFFFF; return a; })()"); + }, async function NestedThrowingGetter() { await testExpression("({ a: { b: [ { get c() { throw new Error('nested error'); } } ] } })"); }, diff --git a/deps/v8/test/inspector/runtime/evaluate-private-class-member-conflict-expected.txt b/deps/v8/test/inspector/runtime/evaluate-private-class-member-conflict-expected.txt index 5b92d1c6b465..f2ce0e3ed95c 100644 --- a/deps/v8/test/inspector/runtime/evaluate-private-class-member-conflict-expected.txt +++ b/deps/v8/test/inspector/runtime/evaluate-private-class-member-conflict-expected.txt @@ -19,6 +19,14 @@ class StaticClass extends Klass { Running test: evaluatePrivateMembers +Runtime.evaluate: `#name in (new ClassWithField)` +{ + className : Error + description : Error: Operation is ambiguous because there are more than one private name'#name' on the object at <anonymous>:1:11 + objectId : <objectId> + subtype : error + type : object +} Runtime.evaluate: `(new ClassWithField).#name` { className : Error @@ -27,6 +35,14 @@ Runtime.evaluate: `(new ClassWithField).#name` subtype : error type : object } +Runtime.evaluate: `#name in (new ClassWithMethod)` +{ + className : Error + description : Error: Operation is ambiguous because there are more than one private name'#name' on the object at <anonymous>:1:11 + objectId : <objectId> + subtype : error + type : object +} Runtime.evaluate: `(new ClassWithMethod).#name` { className : Error @@ -35,6 +51,14 @@ Runtime.evaluate: `(new ClassWithMethod).#name` subtype : error type : object } +Runtime.evaluate: `#name in (new ClassWithAccessor)` +{ + className : Error + description : Error: Operation is ambiguous because there are more than one private name'#name' on the object at <anonymous>:1:11 + objectId : <objectId> + subtype : error + type : object +} Runtime.evaluate: `(new ClassWithAccessor).#name` { className : Error @@ -43,11 +67,21 @@ Runtime.evaluate: `(new ClassWithAccessor).#name` subtype : error type : object } +Runtime.evaluate: `#name in StaticClass` +{ + type : boolean + value : true +} Runtime.evaluate: `StaticClass.#name` { type : string value : child } +Runtime.evaluate: `#name in (new StaticClass)` +{ + type : boolean + value : true +} Runtime.evaluate: `(new StaticClass).#name` { type : string diff --git a/deps/v8/test/inspector/runtime/evaluate-private-class-member-expected.txt b/deps/v8/test/inspector/runtime/evaluate-private-class-member-expected.txt index 9a81f57cf7e5..291b7df33d30 100644 --- a/deps/v8/test/inspector/runtime/evaluate-private-class-member-expected.txt +++ b/deps/v8/test/inspector/runtime/evaluate-private-class-member-expected.txt @@ -13,6 +13,24 @@ const obj = new Klass(); Running test: evaluatePrivateMembers Checking private fields +Runtime.evaluate: `#field in obj` +{ + type : boolean + value : true +} +Runtime.evaluate: `#nonExistent in obj` +{ + type : boolean + value : false +} +Runtime.evaluate: `#field in 1` +{ + className : TypeError + description : TypeError: Cannot use 'in' operator to search for '#field' in 1 at <anonymous>:1:11 + objectId : <objectId> + subtype : error + type : object +} Runtime.evaluate: `obj.#field` { type : string @@ -67,6 +85,11 @@ Runtime.evaluate: `obj.#field` value : 0 } Checking private getter-only accessors +Runtime.evaluate: `#getterOnly in obj` +{ + type : boolean + value : true +} Runtime.evaluate: `obj.#getterOnly` { type : string @@ -102,6 +125,11 @@ Runtime.evaluate: `obj.#getterOnly` value : getterOnly } Checking private setter-only accessors +Runtime.evaluate: `#setterOnly in obj` +{ + type : boolean + value : true +} Runtime.evaluate: `obj.#setterOnly` { className : Error @@ -138,6 +166,11 @@ Runtime.evaluate: `obj.#field` value : setterOnlyCalled } Checking private accessors +Runtime.evaluate: `#accessor in obj` +{ + type : boolean + value : true +} Runtime.evaluate: `obj.#accessor` { type : string @@ -190,6 +223,11 @@ Runtime.evaluate: `obj.#field` value : 0 } Checking private methods +Runtime.evaluate: `#method in obj` +{ + type : boolean + value : true +} Runtime.evaluate: `obj.#method` { className : Function diff --git a/deps/v8/test/inspector/runtime/evaluate-private-class-member-static-expected.txt b/deps/v8/test/inspector/runtime/evaluate-private-class-member-static-expected.txt index d52f4960fd1e..b426baed7c34 100644 --- a/deps/v8/test/inspector/runtime/evaluate-private-class-member-static-expected.txt +++ b/deps/v8/test/inspector/runtime/evaluate-private-class-member-static-expected.txt @@ -13,6 +13,24 @@ const obj = new Klass(); Running test: evaluatePrivateMembers Checking private fields +Runtime.evaluate: `#field in Klass` +{ + type : boolean + value : true +} +Runtime.evaluate: `#nonExistent in Klass` +{ + type : boolean + value : false +} +Runtime.evaluate: `#field in 1` +{ + className : TypeError + description : TypeError: Cannot use 'in' operator to search for '#field' in 1 at <anonymous>:1:11 + objectId : <objectId> + subtype : error + type : object +} Runtime.evaluate: `Klass.#field` { type : string @@ -67,6 +85,11 @@ Runtime.evaluate: `Klass.#field` value : 0 } Checking private getter-only accessors +Runtime.evaluate: `#getterOnly in Klass` +{ + type : boolean + value : true +} Runtime.evaluate: `Klass.#getterOnly` { type : string @@ -102,6 +125,11 @@ Runtime.evaluate: `Klass.#getterOnly` value : getterOnly } Checking private setter-only accessors +Runtime.evaluate: `#setterOnly in Klass` +{ + type : boolean + value : true +} Runtime.evaluate: `Klass.#setterOnly` { className : Error @@ -138,6 +166,11 @@ Runtime.evaluate: `Klass.#field` value : setterOnlyCalled } Checking private accessors +Runtime.evaluate: `#accessor in Klass` +{ + type : boolean + value : true +} Runtime.evaluate: `Klass.#accessor` { type : string @@ -190,6 +223,11 @@ Runtime.evaluate: `Klass.#field` value : 0 } Checking private methods +Runtime.evaluate: `#method in Klass` +{ + type : boolean + value : true +} Runtime.evaluate: `Klass.#method` { className : Function diff --git a/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview-expected.txt b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview-expected.txt new file mode 100644 index 000000000000..554b01f9de1d --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview-expected.txt @@ -0,0 +1,9 @@ +Tests that side-effect-free evaluation enforces side-effect checks while generating a preview + +Running test: testPreviewRunsUserHasInstance +preview with Request[Symbol.hasInstance]: exception +sideEffects after preview: [] + +Running test: testPreviewRunsMutatingBuiltinGetter +preview with Array.prototype.pop getter: exception +length after preview: 2 diff --git a/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview.js b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview.js new file mode 100644 index 000000000000..612cf9f8a470 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-preview.js @@ -0,0 +1,63 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that side-effect-free evaluation enforces side-effect checks while generating a preview'); + +contextGroup.addScript(` + var sideEffects = []; + globalThis.Request = { + [Symbol.hasInstance](value) { + sideEffects.push('Request.hasInstance'); + return false; + } + }; + var objectWithBody = {}; + Object.defineProperty(objectWithBody, 'body', { + get: Date.now, + enumerable: true, + }); + var arrayLike = {0: 'a', 1: 'b', length: 2}; + Object.defineProperty(arrayLike, 'popped', { + get: Array.prototype.pop, + enumerable: true, + }); +`); + +async function evaluateWithPreview(name, expression) { + const {result} = await Protocol.Runtime.evaluate({ + expression, + throwOnSideEffect: true, + generatePreview: true, + }); + if (result.exceptionDetails) { + InspectorTest.log(`${name}: exception`); + } else { + InspectorTest.log(`${name}: ok (${result.result.type})`); + } +} + +async function logExpression(name, expression) { + const {result} = await Protocol.Runtime.evaluate( + {expression, returnByValue: true}); + InspectorTest.log(`${name}: ${JSON.stringify(result.result.value)}`); +} + +InspectorTest.runAsyncTestSuite([ + async function testPreviewRunsUserHasInstance() { + await Protocol.Runtime.enable(); + await evaluateWithPreview( + 'preview with Request[Symbol.hasInstance]', 'objectWithBody'); + await logExpression('sideEffects after preview', 'sideEffects'); + await Protocol.Runtime.disable(); + }, + + async function testPreviewRunsMutatingBuiltinGetter() { + await Protocol.Runtime.enable(); + await evaluateWithPreview( + 'preview with Array.prototype.pop getter', 'arrayLike'); + await logExpression('length after preview', 'arrayLike.length'); + await Protocol.Runtime.disable(); + }, +]); diff --git a/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result-expected.txt b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result-expected.txt new file mode 100644 index 000000000000..8d215f6d30d4 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result-expected.txt @@ -0,0 +1,40 @@ +Tests that side-effect-free evaluation enforces side-effect checks during result serialization + +Running test: testRuntimeEvaluateReturnByValue +returnByValue with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +returnByValue with pure object: ok ({"a":42,"nested":[1,2]}) +returnByValue with Error object: ok ({}) +returnByValue with Error side-effect prototype: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testRuntimeEvaluateDeepSerialization +deep serialization with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +deep serialization with Error object: ok ({"type":"error"}) +deep serialization with Error side-effect prototype: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testRuntimeEvaluateProxyTrap +returnByValue with proxy ownKeys side-effect: exception (EvalError: Possible side-effect in debug-evaluate) +returnByValue with proxy getOwnPropertyDescriptor side-effect: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testRuntimeCallFunctionOn +callFunctionOn returnByValue with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +callFunctionOn deep serialization with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testDebuggerEvaluateOnCallFrame +evaluateOnCallFrame returnByValue with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testRuntimeEvaluateAwaitPromise +awaitPromise returnByValue with non-promise side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +awaitPromise returnByValue with resolved promise side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +awaitPromise returnByValue with resolved promise pure object: ok ({"a":42,"nested":[1,2]}) +awaitPromise deep serialization with resolved promise side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +awaitPromise returnByValue with rejected promise side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testRuntimeCallFunctionOnAwaitPromise +callFunctionOn awaitPromise returnByValue with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) +callFunctionOn awaitPromise deep serialization with side-effect getter: exception (EvalError: Possible side-effect in debug-evaluate) + +Running test: testVerifyNoSideEffectsOccurred +sideEffects length: 0 + +Running test: testTerminateExecutionDuringMapEntryErrorPreview +terminateExecution during Map entry Error preview: Execution was terminated diff --git a/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result.js b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result.js new file mode 100644 index 000000000000..cf39b4bdee99 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-throw-on-side-effect-wrap-result.js @@ -0,0 +1,288 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Tests that side-effect-free evaluation enforces side-effect checks during result serialization'); + +contextGroup.addScript(` + var sideEffects = []; + function makeObjectWithSideEffectGetter(tag) { + return { + get a() { + sideEffects.push(tag); + return 42; + } + }; + } + function makeProxyWithSideEffectTrap(tag) { + return new Proxy({a: 1}, { + ownKeys() { + sideEffects.push(tag); + return ['a']; + } + }); + } + function makeProxyWithDescriptorSideEffectTrap(tag) { + return new Proxy({a: 1, b: 2}, { + getOwnPropertyDescriptor(target, prop) { + sideEffects.push(tag); + return Object.getOwnPropertyDescriptor(target, prop); + } + }); + } + function makePureObject() { + return {a: 42, nested: [1, 2]}; + } + function makeErrorWithSideEffectPrototype(tag) { + const err = new Error(); + Object.setPrototypeOf(err, new Proxy({}, { + get(target, prop) { + sideEffects.push(tag); + return 'custom'; + } + })); + return err; + } + var globalObjEvalJson = makeObjectWithSideEffectGetter('eval-json'); + var globalObjEvalDeep = makeObjectWithSideEffectGetter('eval-deep'); + var globalErrorEvalJson = makeErrorWithSideEffectPrototype('error-proto-json'); + var globalErrorEvalDeep = makeErrorWithSideEffectPrototype('error-proto-deep'); + var globalProxyEvalJson = makeProxyWithSideEffectTrap('proxy-ownKeys'); + var globalProxyDescriptorEvalJson = makeProxyWithDescriptorSideEffectTrap('proxy-getOwnPropertyDescriptor'); + var globalObjCallJson = makeObjectWithSideEffectGetter('callFunctionOn-json'); + var globalObjCallDeep = makeObjectWithSideEffectGetter('callFunctionOn-deep'); + var resolvedPromiseJson = Promise.resolve(makeObjectWithSideEffectGetter('promise-json')); + var resolvedPromiseDeep = Promise.resolve(makeObjectWithSideEffectGetter('promise-deep')); + var resolvedPromisePure = Promise.resolve(makePureObject()); + var rejectedPromiseJson = Promise.reject(makeObjectWithSideEffectGetter('reject-json')); + rejectedPromiseJson.catch(function() {}); + function pauseWithLocal() { + const localObj = makeObjectWithSideEffectGetter('evaluateOnCallFrame-json'); + debugger; + } +`); + +async function logResult(label, response) { + const {result} = response; + if (result.exceptionDetails) { + InspectorTest.log(`${label}: exception (${result.result.description.split('\n')[0]})`); + } else { + InspectorTest.log(`${label}: ok (${JSON.stringify(result.result.value ?? result.result.deepSerializedValue)})`); + } +} + +InspectorTest.runAsyncTestSuite([ + async function testRuntimeEvaluateReturnByValue() { + await logResult( + 'returnByValue with side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'globalObjEvalJson', + throwOnSideEffect: true, + returnByValue: true, + })); + await logResult( + 'returnByValue with pure object', + await Protocol.Runtime.evaluate({ + expression: 'makePureObject()', + throwOnSideEffect: true, + returnByValue: true, + })); + await logResult( + 'returnByValue with Error object', + await Protocol.Runtime.evaluate({ + expression: 'new Error()', + throwOnSideEffect: true, + returnByValue: true, + })); + await logResult( + 'returnByValue with Error side-effect prototype', + await Protocol.Runtime.evaluate({ + expression: 'globalErrorEvalJson', + throwOnSideEffect: true, + returnByValue: true, + })); + }, + + async function testRuntimeEvaluateDeepSerialization() { + await logResult( + 'deep serialization with side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'globalObjEvalDeep', + throwOnSideEffect: true, + serializationOptions: {serialization: 'deep'}, + })); + await logResult( + 'deep serialization with Error object', + await Protocol.Runtime.evaluate({ + expression: 'new Error()', + throwOnSideEffect: true, + serializationOptions: {serialization: 'deep'}, + })); + await logResult( + 'deep serialization with Error side-effect prototype', + await Protocol.Runtime.evaluate({ + expression: 'globalErrorEvalDeep', + throwOnSideEffect: true, + serializationOptions: {serialization: 'deep'}, + })); + }, + + async function testRuntimeEvaluateProxyTrap() { + await logResult( + 'returnByValue with proxy ownKeys side-effect', + await Protocol.Runtime.evaluate({ + expression: 'globalProxyEvalJson', + throwOnSideEffect: true, + returnByValue: true, + })); + await logResult( + 'returnByValue with proxy getOwnPropertyDescriptor side-effect', + await Protocol.Runtime.evaluate({ + expression: 'globalProxyDescriptorEvalJson', + throwOnSideEffect: true, + returnByValue: true, + })); + }, + + async function testRuntimeCallFunctionOn() { + const {result: {result: {objectId}}} = await Protocol.Runtime.evaluate({ + expression: '({})', + }); + await logResult( + 'callFunctionOn returnByValue with side-effect getter', + await Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: 'function() { return globalObjCallJson; }', + throwOnSideEffect: true, + returnByValue: true, + })); + await logResult( + 'callFunctionOn deep serialization with side-effect getter', + await Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: 'function() { return globalObjCallDeep; }', + throwOnSideEffect: true, + serializationOptions: {serialization: 'deep'}, + })); + }, + + async function testDebuggerEvaluateOnCallFrame() { + await Protocol.Debugger.enable(); + Protocol.Runtime.evaluate({expression: 'setTimeout(pauseWithLocal, 0)'}); + const {params: {callFrames: [{callFrameId}]}} = await Protocol.Debugger.oncePaused(); + await logResult( + 'evaluateOnCallFrame returnByValue with side-effect getter', + await Protocol.Debugger.evaluateOnCallFrame({ + callFrameId, + expression: 'localObj', + throwOnSideEffect: true, + returnByValue: true, + })); + await Protocol.Debugger.resume(); + await Protocol.Debugger.disable(); + }, + + async function testRuntimeEvaluateAwaitPromise() { + await logResult( + 'awaitPromise returnByValue with non-promise side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'globalObjEvalJson', + throwOnSideEffect: true, + returnByValue: true, + awaitPromise: true, + })); + await logResult( + 'awaitPromise returnByValue with resolved promise side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'resolvedPromiseJson', + throwOnSideEffect: true, + returnByValue: true, + awaitPromise: true, + })); + await logResult( + 'awaitPromise returnByValue with resolved promise pure object', + await Protocol.Runtime.evaluate({ + expression: 'resolvedPromisePure', + throwOnSideEffect: true, + returnByValue: true, + awaitPromise: true, + })); + await logResult( + 'awaitPromise deep serialization with resolved promise side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'resolvedPromiseDeep', + throwOnSideEffect: true, + serializationOptions: {serialization: 'deep'}, + awaitPromise: true, + })); + await logResult( + 'awaitPromise returnByValue with rejected promise side-effect getter', + await Protocol.Runtime.evaluate({ + expression: 'rejectedPromiseJson', + throwOnSideEffect: true, + returnByValue: true, + awaitPromise: true, + })); + }, + + async function testRuntimeCallFunctionOnAwaitPromise() { + const {result: {result: {objectId}}} = await Protocol.Runtime.evaluate({ + expression: '({})', + }); + await logResult( + 'callFunctionOn awaitPromise returnByValue with side-effect getter', + await Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: 'function() { return globalObjCallJson; }', + throwOnSideEffect: true, + returnByValue: true, + awaitPromise: true, + })); + await logResult( + 'callFunctionOn awaitPromise deep serialization with side-effect getter', + await Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: 'function() { return globalObjCallDeep; }', + throwOnSideEffect: true, + serializationOptions: {serialization: 'deep'}, + awaitPromise: true, + })); + }, + + async function testVerifyNoSideEffectsOccurred() { + const {result: {result: {value}}} = await Protocol.Runtime.evaluate({ + expression: 'sideEffects', + returnByValue: true, + }); + InspectorTest.log('sideEffects length: ' + value.length); + }, + + async function testTerminateExecutionDuringMapEntryErrorPreview() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + const paused = Protocol.Debugger.oncePaused(); + const evaluated = Protocol.Runtime.evaluate({ + expression: ` + let pausing = false; + const err = new Error(); + Object.setPrototypeOf(err, { + get name() { + if (pausing) return 'Error'; + pausing = true; + debugger; + for (;;) {} + } + }); + console.log(new Map([[1, err]])); + ` + }); + await paused; + Protocol.Runtime.terminateExecution(); + await Protocol.Debugger.resume(); + const response = await evaluated; + InspectorTest.log('terminateExecution during Map entry Error preview: ' + response.error.message); + await Protocol.Debugger.disable(); + await Protocol.Runtime.disable(); + }, +]); diff --git a/deps/v8/test/inspector/runtime/evaluate-without-side-effects-expected.txt b/deps/v8/test/inspector/runtime/evaluate-without-side-effects-expected.txt index 768ed3c9d647..deb8c0588c3a 100644 --- a/deps/v8/test/inspector/runtime/evaluate-without-side-effects-expected.txt +++ b/deps/v8/test/inspector/runtime/evaluate-without-side-effects-expected.txt @@ -109,3 +109,12 @@ Test that private member access does not trigger with replMode and throwOnSideEf } } } +{ + id : <messageId> + result : { + result : { + type : boolean + value : true + } + } +} diff --git a/deps/v8/test/inspector/runtime/evaluate-without-side-effects.js b/deps/v8/test/inspector/runtime/evaluate-without-side-effects.js index e514bf143e12..4afe0e457b9d 100644 --- a/deps/v8/test/inspector/runtime/evaluate-without-side-effects.js +++ b/deps/v8/test/inspector/runtime/evaluate-without-side-effects.js @@ -65,6 +65,11 @@ Protocol.Debugger.onPaused(message => { throwOnSideEffect: true, replMode: true, })); + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: "#bar in foo", + throwOnSideEffect: true, + replMode: true, + })); InspectorTest.completeTest(); })(); diff --git a/deps/v8/test/inspector/runtime/get-heap-usage-expected.txt b/deps/v8/test/inspector/runtime/get-heap-usage-expected.txt index 4bd9699e574a..bb6d3e0e77f5 100644 --- a/deps/v8/test/inspector/runtime/get-heap-usage-expected.txt +++ b/deps/v8/test/inspector/runtime/get-heap-usage-expected.txt @@ -1 +1,9 @@ Checks that Runtime.getHeapUsage works +getHeapUsage is not allowed for untrusted clients +{ + error : { + code : -32000 + message : Runtime.getHeapUsage is not allowed for untrusted clients + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/runtime/get-heap-usage.js b/deps/v8/test/inspector/runtime/get-heap-usage.js index 8330001315b6..dd06bdbdfe20 100644 --- a/deps/v8/test/inspector/runtime/get-heap-usage.js +++ b/deps/v8/test/inspector/runtime/get-heap-usage.js @@ -11,5 +11,12 @@ const {session, contextGroup, Protocol} = InspectorTest.start('Checks that Runti console.assert(usedSize > 0); console.assert(totalSize > 0); console.assert(totalSize >= usedSize); + + InspectorTest.log('getHeapUsage is not allowed for untrusted clients'); + const untrustedSession = contextGroup.connect(/* isFullyTrusted */ false); + InspectorTest.logMessage( + await untrustedSession.Protocol.Runtime.getHeapUsage()); + untrustedSession.disconnect(); + InspectorTest.completeTest(); })(); diff --git a/deps/v8/test/inspector/runtime/get-isolate-id-expected.txt b/deps/v8/test/inspector/runtime/get-isolate-id-expected.txt index 7b3dcfc500d0..e235ac803d21 100644 --- a/deps/v8/test/inspector/runtime/get-isolate-id-expected.txt +++ b/deps/v8/test/inspector/runtime/get-isolate-id-expected.txt @@ -1 +1,9 @@ Checks that Runtime.getIsolateId works +getIsolateId is not allowed for untrusted clients +{ + error : { + code : -32000 + message : Runtime.getIsolateId is not allowed for untrusted clients + } + id : <messageId> +} diff --git a/deps/v8/test/inspector/runtime/get-isolate-id.js b/deps/v8/test/inspector/runtime/get-isolate-id.js index 59bfc6263911..4a4bc2ba0475 100644 --- a/deps/v8/test/inspector/runtime/get-isolate-id.js +++ b/deps/v8/test/inspector/runtime/get-isolate-id.js @@ -8,5 +8,12 @@ const {session, contextGroup, Protocol} = InspectorTest.start('Checks that Runti const id = await Protocol.Runtime.getIsolateId(); console.assert(typeof id === 'string'); console.assert(id.length > 0); + + InspectorTest.log('getIsolateId is not allowed for untrusted clients'); + const untrustedSession = contextGroup.connect(/* isFullyTrusted */ false); + InspectorTest.logMessage( + await untrustedSession.Protocol.Runtime.getIsolateId()); + untrustedSession.disconnect(); + InspectorTest.completeTest(); })(); diff --git a/deps/v8/test/inspector/runtime/import-defer-exception-stack-trace-expected.txt b/deps/v8/test/inspector/runtime/import-defer-exception-stack-trace-expected.txt new file mode 100644 index 000000000000..bfdf339e930c --- /dev/null +++ b/deps/v8/test/inspector/runtime/import-defer-exception-stack-trace-expected.txt @@ -0,0 +1,325 @@ +Checks the stack trace reported for an uncaught exception thrown while a deferred module is evaluated, with and without async stack traces. + +Running with async stack traces enabled. + +Access from an async function, after an await: +Runtime.exceptionThrown: +{ + columnNumber : 8 + lineNumber : 2 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-async-enabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-async-enabled.js + } + [2] : { + columnNumber : 12 + functionName : read + lineNumber : 4 + scriptId : <scriptId> + url : main-async-enabled.js + } + ] + parent : { + callFrames : [ + [0] : { + columnNumber : 0 + functionName : + lineNumber : 6 + scriptId : <scriptId> + url : main-async-enabled.js + } + ] + description : await + } + } + text : Uncaught Error: deferred module threw + url : deferred-async-enabled.js +} +Runtime.exceptionRevoked: Handler added to rejected promise +Runtime.exceptionThrown: +{ + columnNumber : 16 + lineNumber : 4 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-async-enabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-async-enabled.js + } + [2] : { + columnNumber : 12 + functionName : read + lineNumber : 4 + scriptId : <scriptId> + url : main-async-enabled.js + } + ] + parent : { + callFrames : [ + [0] : { + columnNumber : 0 + functionName : + lineNumber : 6 + scriptId : <scriptId> + url : main-async-enabled.js + } + ] + description : await + } + } + text : Uncaught Error: deferred module threw + url : main-async-enabled.js +} + +Access from a classic script: +Runtime.exceptionThrown: +{ + columnNumber : 8 + lineNumber : 2 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-script-enabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-script-enabled.js + } + [2] : { + columnNumber : 23 + functionName : read + lineNumber : 2 + scriptId : <scriptId> + url : script-enabled.js + } + [3] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : script-enabled.js + } + ] + } + text : Uncaught Error: deferred module threw + url : deferred-script-enabled.js +} +Runtime.exceptionRevoked: Handler added to rejected promise +Runtime.exceptionThrown: +{ + columnNumber : 23 + lineNumber : 2 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-script-enabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-script-enabled.js + } + [2] : { + columnNumber : 23 + functionName : read + lineNumber : 2 + scriptId : <scriptId> + url : script-enabled.js + } + [3] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : script-enabled.js + } + ] + } + text : Uncaught Error: deferred module threw + url : script-enabled.js +} + +Running with async stack traces disabled. + +Access from an async function, after an await: +Runtime.exceptionThrown: +{ + columnNumber : 8 + lineNumber : 2 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-async-disabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-async-disabled.js + } + [2] : { + columnNumber : 12 + functionName : read + lineNumber : 4 + scriptId : <scriptId> + url : main-async-disabled.js + } + ] + } + text : Uncaught Error: deferred module threw + url : deferred-async-disabled.js +} +Runtime.exceptionRevoked: Handler added to rejected promise +Runtime.exceptionThrown: +{ + columnNumber : 16 + lineNumber : 4 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-async-disabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-async-disabled.js + } + [2] : { + columnNumber : 12 + functionName : read + lineNumber : 4 + scriptId : <scriptId> + url : main-async-disabled.js + } + ] + } + text : Uncaught Error: deferred module threw + url : main-async-disabled.js +} + +Access from a classic script: +Runtime.exceptionThrown: +{ + columnNumber : 8 + lineNumber : 2 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-script-disabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-script-disabled.js + } + [2] : { + columnNumber : 23 + functionName : read + lineNumber : 2 + scriptId : <scriptId> + url : script-disabled.js + } + [3] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : script-disabled.js + } + ] + } + text : Uncaught Error: deferred module threw + url : deferred-script-disabled.js +} +Runtime.exceptionRevoked: Handler added to rejected promise +Runtime.exceptionThrown: +{ + columnNumber : 23 + lineNumber : 2 + stackTrace : { + callFrames : [ + [0] : { + columnNumber : 8 + functionName : thrower + lineNumber : 2 + scriptId : <scriptId> + url : deferred-script-disabled.js + } + [1] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : deferred-script-disabled.js + } + [2] : { + columnNumber : 23 + functionName : read + lineNumber : 2 + scriptId : <scriptId> + url : script-disabled.js + } + [3] : { + columnNumber : 0 + functionName : + lineNumber : 4 + scriptId : <scriptId> + url : script-disabled.js + } + ] + } + text : Uncaught Error: deferred module threw + url : script-disabled.js +} diff --git a/deps/v8/test/inspector/runtime/import-defer-exception-stack-trace.js b/deps/v8/test/inspector/runtime/import-defer-exception-stack-trace.js new file mode 100644 index 000000000000..91d279f6f52e --- /dev/null +++ b/deps/v8/test/inspector/runtime/import-defer-exception-stack-trace.js @@ -0,0 +1,87 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks the stack trace reported for an uncaught exception thrown while ' + + 'a deferred module is evaluated, with and without async stack traces.'); + +Protocol.Runtime.onExceptionThrown(({params: {exceptionDetails}}) => { + const {text, url, lineNumber, columnNumber, stackTrace} = exceptionDetails; + InspectorTest.log('Runtime.exceptionThrown:'); + InspectorTest.logMessage({text, url, lineNumber, columnNumber, stackTrace}); +}); +// Evaluating a deferred module rejects the module's internal top-level promise, +// which is reported as an unhandled rejection. EvaluateModuleSync then marks +// that promise as handled (HostPromiseRejectionTracker(promise, "handle")), +// which revokes the report, and throws the error at the access site. Hosts +// that defer reporting until the next microtask checkpoint, as HTML does, never +// show the first report; this test runner reports it immediately. +Protocol.Runtime.onExceptionRevoked(({params: {reason}}) => { + InspectorTest.log(`Runtime.exceptionRevoked: ${reason}`); +}); + +const kDeferredModule = ` +function thrower() { + throw new Error('deferred module threw'); +} +thrower(); +export const foo = 42; +`; + +async function testAsyncFunction(suffix) { + InspectorTest.log('\nAccess from an async function, after an await:'); + contextGroup.addModuleWithoutEvaluating( + kDeferredModule, `deferred-async-${suffix}.js`); + contextGroup.addModule( + ` +import defer * as ns from 'deferred-async-${suffix}.js'; +async function read() { + await 0; + return ns.foo; +} +read(); +`, + `main-async-${suffix}.js`); + await InspectorTest.waitForPendingTasks(); +} + +async function testClassicScript(suffix) { + InspectorTest.log('\nAccess from a classic script:'); + contextGroup.addModuleWithoutEvaluating( + kDeferredModule, `deferred-script-${suffix}.js`); + contextGroup.addModule( + ` +import defer * as ns from 'deferred-script-${suffix}.js'; +globalThis.ns = ns; +`, + `main-script-${suffix}.js`); + await InspectorTest.waitForPendingTasks(); + contextGroup.addScript( + ` +function read() { + return globalThis.ns.foo; +} +read(); +`, + 0, 0, `script-${suffix}.js`); + await InspectorTest.waitForPendingTasks(); +} + +(async function test() { + await Protocol.Runtime.enable(); + + InspectorTest.log('\nRunning with async stack traces enabled.'); + await Protocol.Runtime.setAsyncCallStackDepth({maxDepth: 32}); + await testAsyncFunction('enabled'); + await testClassicScript('enabled'); + + InspectorTest.log('\nRunning with async stack traces disabled.'); + await Protocol.Runtime.setAsyncCallStackDepth({maxDepth: 0}); + await testAsyncFunction('disabled'); + await testClassicScript('disabled'); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-expected.txt b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-expected.txt new file mode 100644 index 000000000000..63376d0c6b4f --- /dev/null +++ b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-expected.txt @@ -0,0 +1,25 @@ +Checks that reading an export of a deferred module namespace in a side-effect-free evaluation (as DevTools does for eager evaluation and autocomplete) fails without starting the module evaluation, and that a later regular evaluation still evaluates the module. + +Running test: testRuntimeEvaluate +[[ModuleStatus]] of console: linked +globalThis.consoleEvaluated: undefined + +Side-effect-free Runtime.evaluate of consoleNs.foo: +Threw: EvalError: Possible side-effect in debug-evaluate +[[ModuleStatus]] of console: linked +globalThis.consoleEvaluated: undefined + +Regular Runtime.evaluate of consoleNs.foo: +Result: 1 +[[ModuleStatus]] of console: evaluated +globalThis.consoleEvaluated: true + +Running test: testEvaluateOnCallFrame +Side-effect-free Debugger.evaluateOnCallFrame of pausedNs.foo: +Threw: EvalError: Possible side-effect in debug-evaluate + at <anonymous>:1:1 + +Regular Debugger.evaluateOnCallFrame of pausedNs.foo: +Result: 2 +[[ModuleStatus]] of paused: evaluated +globalThis.pausedEvaluated: true diff --git a/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope-expected.txt b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope-expected.txt new file mode 100644 index 000000000000..9ba5ff02115a --- /dev/null +++ b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope-expected.txt @@ -0,0 +1,12 @@ +Checks that a side-effect-free evaluation on a call frame paused inside a with statement over a deferred module namespace fails without starting the module evaluation. + +Running test: testEvaluateOnCallFrameInWithScope +Side-effect-free Debugger.evaluateOnCallFrame of foo: +Threw: EvalError: Possible side-effect in debug-evaluate + at runWith (<anonymous>:1:34) + at <anonymous>:2:1 +globalThis.deferredEvaluated: undefined + +Regular Debugger.evaluateOnCallFrame of foo: +Result: 1 +globalThis.deferredEvaluated: true diff --git a/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope.js b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope.js new file mode 100644 index 000000000000..687c49239122 --- /dev/null +++ b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate-with-scope.js @@ -0,0 +1,67 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that a side-effect-free evaluation on a call frame paused inside ' + + 'a with statement over a deferred module namespace fails without ' + + 'starting the module evaluation.'); + +contextGroup.addModuleWithoutEvaluating( + ` +globalThis.deferredEvaluated = true; +export const foo = 1; +`, + 'deferred'); + +contextGroup.addModule( + ` +import defer * as ns from 'deferred'; +globalThis.ns = ns; +`, + 'main'); + +function logEvaluateResult(response) { + const {result, exceptionDetails} = response.result; + if (exceptionDetails) { + InspectorTest.log('Threw: ' + exceptionDetails.exception.description); + } else { + InspectorTest.log('Result: ' + result.value); + } +} + +async function logDeferredEvaluated() { + const {result: {result}} = await Protocol.Runtime.evaluate( + {expression: 'String(globalThis.deferredEvaluated)'}); + InspectorTest.log('globalThis.deferredEvaluated: ' + result.value); +} + +InspectorTest.runAsyncTestSuite([ + async function testEvaluateOnCallFrameInWithScope() { + await Protocol.Runtime.enable(); + await Protocol.Debugger.enable(); + await InspectorTest.waitForPendingTasks(); + + Protocol.Runtime.evaluate({ + expression: 'function runWith(o) { with (o) { debugger; } }\n' + + 'runWith(globalThis.ns);' + }); + const {params: {callFrames: [{callFrameId}]}} = + await Protocol.Debugger.oncePaused(); + + InspectorTest.log('Side-effect-free Debugger.evaluateOnCallFrame of foo:'); + logEvaluateResult(await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId, expression: 'foo', throwOnSideEffect: true})); + await logDeferredEvaluated(); + + InspectorTest.log('\nRegular Debugger.evaluateOnCallFrame of foo:'); + logEvaluateResult(await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId, expression: 'foo'})); + await logDeferredEvaluated(); + + await Protocol.Debugger.resume(); + await Protocol.Debugger.disable(); + }, +]); diff --git a/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate.js b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate.js new file mode 100644 index 000000000000..892c66c6f5d4 --- /dev/null +++ b/deps/v8/test/inspector/runtime/import-defer-side-effect-free-evaluate.js @@ -0,0 +1,99 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that reading an export of a deferred module namespace in a ' + + 'side-effect-free evaluation (as DevTools does for eager evaluation and ' + + 'autocomplete) fails without starting the module evaluation, and that a ' + + 'later regular evaluation still evaluates the module.'); + +contextGroup.addModuleWithoutEvaluating( + ` +globalThis.consoleEvaluated = true; +export const foo = 1; +`, + 'console'); + +contextGroup.addModuleWithoutEvaluating( + ` +globalThis.pausedEvaluated = true; +export const foo = 2; +`, + 'paused'); + +contextGroup.addModule( + ` +import defer * as consoleNs from 'console'; +import defer * as pausedNs from 'paused'; +globalThis.consoleNs = consoleNs; +globalThis.pausedNs = pausedNs; +`, + 'main'); + +async function evaluateToString(expression) { + const {result: {result}} = + await Protocol.Runtime.evaluate({expression: `String(${expression})`}); + return result.value; +} + +async function logModuleStatus(name) { + const {result: {result}} = await Protocol.Runtime.evaluate( + {expression: `globalThis.${name}Ns`, generatePreview: true}); + const status = + result.preview.properties.find(p => p.name === '[[ModuleStatus]]'); + InspectorTest.log( + `[[ModuleStatus]] of ${name}: ` + (status ? status.value : '<none>')); + InspectorTest.log( + `globalThis.${name}Evaluated: ` + + await evaluateToString(`globalThis.${name}Evaluated`)); +} + +function logEvaluateResult(response) { + const {result, exceptionDetails} = response.result; + if (exceptionDetails) { + InspectorTest.log('Threw: ' + exceptionDetails.exception.description); + } else { + InspectorTest.log('Result: ' + result.value); + } +} + +InspectorTest.runAsyncTestSuite([ + async function testRuntimeEvaluate() { + await Protocol.Runtime.enable(); + await InspectorTest.waitForPendingTasks(); + await logModuleStatus('console'); + + InspectorTest.log('\nSide-effect-free Runtime.evaluate of consoleNs.foo:'); + logEvaluateResult(await Protocol.Runtime.evaluate( + {expression: 'consoleNs.foo', throwOnSideEffect: true})); + await logModuleStatus('console'); + + InspectorTest.log('\nRegular Runtime.evaluate of consoleNs.foo:'); + logEvaluateResult( + await Protocol.Runtime.evaluate({expression: 'consoleNs.foo'})); + await logModuleStatus('console'); + }, + + async function testEvaluateOnCallFrame() { + await Protocol.Debugger.enable(); + Protocol.Runtime.evaluate({expression: 'debugger;'}); + const {params: {callFrames: [{callFrameId}]}} = + await Protocol.Debugger.oncePaused(); + + InspectorTest.log( + 'Side-effect-free Debugger.evaluateOnCallFrame of pausedNs.foo:'); + logEvaluateResult(await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId, expression: 'pausedNs.foo', throwOnSideEffect: true})); + + InspectorTest.log('\nRegular Debugger.evaluateOnCallFrame of pausedNs.foo:'); + logEvaluateResult(await Protocol.Debugger.evaluateOnCallFrame( + {callFrameId, expression: 'pausedNs.foo'})); + + await Protocol.Debugger.resume(); + await logModuleStatus('paused'); + await Protocol.Debugger.disable(); + }, +]); diff --git a/deps/v8/test/inspector/runtime/internal-entry-cycle-expected.txt b/deps/v8/test/inspector/runtime/internal-entry-cycle-expected.txt new file mode 100644 index 000000000000..4f3a07745228 --- /dev/null +++ b/deps/v8/test/inspector/runtime/internal-entry-cycle-expected.txt @@ -0,0 +1,13 @@ +Checks that describing cyclic internal#entry wrappers terminates. +Original entries: +0: {1 => 2} +1: {3 => 4} +2: {5 => 6} +Nested non-cyclic entries: +0: {1 => {3 => 4}} +1: {3 => 4} +2: {5 => 6} +Cyclic entries: +0: {1 => {Object => Object}} +1: {Object => {1 => Object}} +2: {5 => Object} diff --git a/deps/v8/test/inspector/runtime/internal-entry-cycle.js b/deps/v8/test/inspector/runtime/internal-entry-cycle.js new file mode 100644 index 000000000000..a9ff3b81afae --- /dev/null +++ b/deps/v8/test/inspector/runtime/internal-entry-cycle.js @@ -0,0 +1,59 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that describing cyclic internal#entry wrappers terminates.'); + +(async () => { + const {result: {result: {objectId}}} = await Protocol.Runtime.evaluate( + {expression: 'new Map([[1, 2], [3, 4], [5, 6]])'}); + const {result: {internalProperties}} = + await Protocol.Runtime.getProperties({objectId}); + const {value: {objectId: entriesId}} = + internalProperties.find(({name}) => name === '[[Entries]]'); + + async function logEntries() { + const {result: {result}} = await Protocol.Runtime.getProperties( + {objectId: entriesId, ownProperties: true, generatePreview: true}); + const entries = + result.filter(({value}) => value?.subtype === 'internal#entry'); + for (const {name, value: {description}} of entries) { + InspectorTest.log(`${name}: ${description}`); + } + return entries.map(({value: {objectId}}) => objectId); + } + + InspectorTest.log('Original entries:'); + const entryIds = await logEntries(); + + // Make entry 0 refer to entry 1 (non-cyclic nesting: A -> B). + await Protocol.Runtime.callFunctionOn({ + objectId: entryIds[0], + functionDeclaration: 'function(other) { this.value = other; }', + arguments: [{objectId: entryIds[1]}], + }); + + InspectorTest.log('Nested non-cyclic entries:'); + await logEntries(); + + // Make the entry wrappers cyclic: + // - entry 0 <-> entry 1 (2-hop cycle: A -> B -> A) + // - entry 1 key refers to itself (direct key cycle) + // - entry 2 value refers to itself via a property of another object + await Protocol.Runtime.callFunctionOn({ + objectId: entryIds[1], + functionDeclaration: + 'function(other) { this.key = this; this.value = other; }', + arguments: [{objectId: entryIds[0]}], + }); + await Protocol.Runtime.callFunctionOn({ + objectId: entryIds[2], + functionDeclaration: 'function() { this.value = {entry: this}; }', + }); + + InspectorTest.log('Cyclic entries:'); + await logEntries(); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id-expected.txt b/deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id-expected.txt new file mode 100644 index 000000000000..ca11b8df58c7 --- /dev/null +++ b/deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id-expected.txt @@ -0,0 +1,4 @@ +Untrusted sessions must not learn the isolate id from objectId +getIsolateId denied for untrusted session: true +isolate id recovered from untrusted objectId matches getIsolateId: false +callFunctionOn with untrusted objectId result: 2 diff --git a/deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id.js b/deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id.js new file mode 100644 index 000000000000..aca0fd2e58ce --- /dev/null +++ b/deps/v8/test/inspector/runtime/isolate-id-leaked-via-object-id.js @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {contextGroup, Protocol} = InspectorTest.start( + 'Untrusted sessions must not learn the isolate id from objectId'); + +(async function test() { + // A fully trusted session is allowed to read the isolate id. + const {result: {id: trustedIsolateId}} = + await Protocol.Runtime.getIsolateId(); + + // An untrusted session is denied by Runtime.getIsolateId. + const untrustedSession = contextGroup.connect(/* isFullyTrusted */ false); + const denied = await untrustedSession.Protocol.Runtime.getIsolateId(); + InspectorTest.log( + 'getIsolateId denied for untrusted session: ' + Boolean(denied.error)); + + // Verify that objectId on untrusted sessions does not leak the isolate id. + const {result: {result: {objectId}}} = + await untrustedSession.Protocol.Runtime.evaluate( + {expression: '({a: 1})'}); + const leaked = objectId.split('.')[0]; + const leakedAsHex = BigInt(leaked).toString(16); + + InspectorTest.log( + 'isolate id recovered from untrusted objectId matches getIsolateId: ' + + (leakedAsHex === trustedIsolateId)); + + // Verify that objectId operations still work within the untrusted session. + const {result: {result: {value: propValue}}} = + await untrustedSession.Protocol.Runtime.callFunctionOn({ + objectId, + functionDeclaration: 'function(arg) { return this.a + arg.a; }', + arguments: [{objectId}], + returnByValue: true, + }); + InspectorTest.log( + 'callFunctionOn with untrusted objectId result: ' + propValue); + + untrustedSession.disconnect(); + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/private-methods-description-expected.txt b/deps/v8/test/inspector/runtime/private-methods-description-expected.txt new file mode 100644 index 000000000000..ceb4b2c0085d --- /dev/null +++ b/deps/v8/test/inspector/runtime/private-methods-description-expected.txt @@ -0,0 +1,26 @@ +Checks that mutating private method wrapper does not crash descriptionForPrivateMethod +Found [[PrivateMethods]]: true +Method wrapper found: true +Mutating wrapper.value to non-function... +Re-inspecting private methods list: +{ + id : <messageId> + result : { + result : [ + [0] : { + configurable : true + enumerable : true + isOwn : true + name : 0 + value : { + className : Object + description : + objectId : <objectId> + subtype : internal#privateMethod + type : object + } + writable : true + } + ] + } +} diff --git a/deps/v8/test/inspector/runtime/private-methods-description.js b/deps/v8/test/inspector/runtime/private-methods-description.js new file mode 100644 index 000000000000..2b10c86ad5ae --- /dev/null +++ b/deps/v8/test/inspector/runtime/private-methods-description.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {session, contextGroup, Protocol} = InspectorTest.start( + 'Checks that mutating private method wrapper does not crash descriptionForPrivateMethod'); + +(async () => { + await Protocol.Runtime.enable(); + + const {result: {result: instance}} = await Protocol.Runtime.evaluate({ + expression: 'new class { #m() {} }', + }); + + const {result: {internalProperties}} = await Protocol.Runtime.getProperties({ + objectId: instance.objectId, + }); + + const privateMethodsProp = + internalProperties.find(p => p.name === '[[PrivateMethods]]'); + InspectorTest.log('Found [[PrivateMethods]]: ' + !!privateMethodsProp); + + const {result: {result: privateMethodsList}} = + await Protocol.Runtime.getProperties({ + objectId: privateMethodsProp.value.objectId, + }); + + const methodWrapper = privateMethodsList[0].value; + InspectorTest.log('Method wrapper found: ' + !!methodWrapper); + + InspectorTest.log('Mutating wrapper.value to non-function...'); + await Protocol.Runtime.callFunctionOn({ + objectId: methodWrapper.objectId, + functionDeclaration: 'function() { this.value = 42; }', + }); + + InspectorTest.log('Re-inspecting private methods list:'); + const reinspect = await Protocol.Runtime.getProperties({ + objectId: privateMethodsProp.value.objectId, + }); + InspectorTest.logMessage(reinspect); + + InspectorTest.completeTest(); +})(); diff --git a/deps/v8/test/inspector/runtime/regression-736302-expected.txt b/deps/v8/test/inspector/runtime/regression-736302-expected.txt index 2174bc54a260..d6d5b3135f32 100644 --- a/deps/v8/test/inspector/runtime/regression-736302-expected.txt +++ b/deps/v8/test/inspector/runtime/regression-736302-expected.txt @@ -2,28 +2,12 @@ crbug.com/736302 Running test: testThrowException { - method : Runtime.consoleAPICalled - params : { - args : [ - [0] : { - type : string - value : default: 1 - } - ] - executionContextId : <executionContextId> - stackTrace : { - callFrames : [ - [0] : { - columnNumber : 12 - functionName : - lineNumber : 1 - scriptId : <scriptId> - url : - } - ] + id : <messageId> + result : { + result : { + type : string + value : Thrown from Symbol.toStringTag getter } - timestamp : <timestamp> - type : count } } diff --git a/deps/v8/test/inspector/runtime/regression-736302.js b/deps/v8/test/inspector/runtime/regression-736302.js index 083e34af2df0..6bca9b9b2f31 100644 --- a/deps/v8/test/inspector/runtime/regression-736302.js +++ b/deps/v8/test/inspector/runtime/regression-736302.js @@ -7,13 +7,18 @@ let {session, contextGroup, Protocol} = InspectorTest.start('crbug.com/736302'); InspectorTest.runAsyncTestSuite([ async function testThrowException() { await Protocol.Runtime.enable(); - Protocol.Runtime.evaluate({expression: ` - console.count({ - get [Symbol.toStringTag]() { - throw new Error(); - } - });`}); - InspectorTest.logMessage(await Protocol.Runtime.onceConsoleAPICalled()); + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: ` + try { + console.count({ + get [Symbol.toStringTag]() { + throw new Error('Thrown from Symbol.toStringTag getter'); + } + }); + } catch (e) { + e.message; + }` + })); await Protocol.Runtime.disable(); }, diff --git a/deps/v8/test/inspector/runtime/remote-object-expected.txt b/deps/v8/test/inspector/runtime/remote-object-expected.txt index c31da16a7ec6..5de68183f76e 100644 --- a/deps/v8/test/inspector/runtime/remote-object-expected.txt +++ b/deps/v8/test/inspector/runtime/remote-object-expected.txt @@ -271,6 +271,12 @@ Error object } } } +Large sparse array +'new Array(0xFFFFFFFF)', returnByValue: true, generatePreview: false +{ + code : -32000 + message : Array length exceeds maximum limit +} Running test: testFunction '(() => 42)', returnByValue: false, generatePreview: false diff --git a/deps/v8/test/inspector/runtime/remote-object.js b/deps/v8/test/inspector/runtime/remote-object.js index b3bc98e0a919..94bbbc53d39e 100644 --- a/deps/v8/test/inspector/runtime/remote-object.js +++ b/deps/v8/test/inspector/runtime/remote-object.js @@ -147,6 +147,10 @@ InspectorTest.runAsyncTestSuite([ InspectorTest.logMessage((await evaluate({ expression: 'new Error()', returnByValue: true })).result); + InspectorTest.log('Large sparse array'); + InspectorTest.logMessage((await evaluate({ + expression: 'new Array(0xFFFFFFFF)', returnByValue: true + })).error); }, async function testFunction() { InspectorTest.logMessage((await evaluate({ diff --git a/deps/v8/test/inspector/runtime/shutdown-pending-evaluate-expected.txt b/deps/v8/test/inspector/runtime/shutdown-pending-evaluate-expected.txt new file mode 100644 index 000000000000..d366909c5209 --- /dev/null +++ b/deps/v8/test/inspector/runtime/shutdown-pending-evaluate-expected.txt @@ -0,0 +1 @@ +Tests that an unresolved asynchronous Runtime.evaluate does not cause a use-after-free during inspector and session teardown. diff --git a/deps/v8/test/inspector/runtime/shutdown-pending-evaluate.js b/deps/v8/test/inspector/runtime/shutdown-pending-evaluate.js new file mode 100644 index 000000000000..af515a9421c2 --- /dev/null +++ b/deps/v8/test/inspector/runtime/shutdown-pending-evaluate.js @@ -0,0 +1,13 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const {Protocol} = InspectorTest.start( + 'Tests that an unresolved asynchronous Runtime.evaluate does not cause a ' + + 'use-after-free during inspector and session teardown.'); + +Protocol.Runtime.evaluate({ + expression: 'new Promise(() => {})', + awaitPromise: true, +}); +InspectorTest.completeTest(); diff --git a/deps/v8/test/intl/regexp-case-equivalence.js b/deps/v8/test/intl/regexp-case-equivalence.js index 33da7140c526..b21926d27526 100644 --- a/deps/v8/test/intl/regexp-case-equivalence.js +++ b/deps/v8/test/intl/regexp-case-equivalence.js @@ -2,7 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Exercise literals, ranges, and backreferences with the same case pairs. +// Unicode 18 assigns U+1DF95 LATIN SMALL LIGATURE LONG S WITH DESCENDER S, +// the first supplementary character that case-folds to a BMP character +// (U+00DF). It is thus case-equivalent to U+00DF and U+1E9E under /iu and +// /iv, but never under /i, which compares UTF-16 code units. +const hasUnicode18 = '\u{1DF95}'.toUpperCase() === 'SS'; + +// Exercise literals, ranges, backreferences, lookbehinds, and class strings +// with the same case pairs. const pairs = [ ['a', 'A', true, true], ['k', '\u212a', false, true], @@ -12,6 +19,8 @@ const pairs = [ ['i', '\u0130', false, false], ['I', '\u0131', false, false], ['\u{10400}', '\u{10428}', false, true], + ['\u00df', '\u{1DF95}', false, hasUnicode18], + ['\u1e9e', '\u{1DF95}', false, hasUnicode18], ['\ud800', '\ud800', true, true], ['\ud800', '\ud801', false, false], ]; @@ -29,16 +38,64 @@ for (const [a, b, legacy, unicode] of pairs) { ? new RegExp('^' + prefix + '[' + c1 + '-' + c1 + ']$', flags) : null; assertEquals(expected, literal.test(prefix + c2), literal.toString()); - assertEquals(expected, backref.test(prefix + c1 + c2), - backref.toString()); + // TODO(crbug.com/571793821): Case-insensitive backreferences do not + // yet match captures of a different UTF-16 length (U+00DF vs U+1DF95). + if (c1.length === c2.length) { + assertEquals(expected, backref.test(prefix + c1 + c2), + backref.toString()); + } if (range !== null) { assertEquals(expected, range.test(prefix + c2), range.toString()); } + const lookbehind = new RegExp('(?<=^' + prefix + c1 + ')x$', flags); + assertEquals(expected, lookbehind.test(prefix + c2 + 'x'), + lookbehind.toString()); + if (flags === 'iv') { + const classString = new RegExp( + '^' + prefix + '[\\q{' + c1 + 'x}]$', flags); + assertEquals(expected, classString.test(prefix + c2 + 'x'), + classString.toString()); + } } } } } +// Supplementary case equivalents of BMP characters must be matched in +// unicode mode both as plain pattern characters and inside character +// classes, but never in legacy mode. +if (hasUnicode18) { + const S = '\u{1DF95}'; + const cases = [ + // [pattern, subject, expected] + ['^\u00df$', S, true], + ['^\u1e9e$', S, true], + ['^' + S + '$', '\u00df', true], + ['^' + S + '$', '\u1e9e', true], + ['^\\u00df$', S, true], + ['^\\u{df}$', S, true], + ['^a\u00dfb$', 'A' + S + 'B', true], + ['^(?:\u00df)+$', S + '\u00df\u1e9e' + S, true], + ['^\u00df{2}$', S + '\u1e9e', true], + ['^\u00df{2}$', S, false], + ['^(?:x|\u00df)$', S, true], + ['^[\u00df]$', S, true], + ['^[^\u00df]$', S, false], + ['^(\u00df)$', S, true], + ]; + for (const [pattern, subject, expected] of cases) { + for (const flags of ['iu', 'iv']) { + const re = new RegExp(pattern, flags); + assertEquals(expected, re.test(subject), re.toString() + ' ' + subject); + } + // In legacy mode, the astral character consists of two code units, + // neither of which has case equivalents. + const re = new RegExp(pattern, 'i'); + assertFalse(re.test(subject), re.toString() + ' ' + subject); + } + assertEquals([S, S], /(\u00df)/iu.exec(S)); +} + for (const flags of ['i', 'iu', 'iv']) { const re = new RegExp('^[a-c\u017f\u00df]$', flags); for (const c of ['a', 'B', 'c', '\u017f', '\u00df']) { diff --git a/deps/v8/test/intl/regress-110086.js b/deps/v8/test/intl/regress-110086.js new file mode 100644 index 000000000000..9e358717da7a --- /dev/null +++ b/deps/v8/test/intl/regress-110086.js @@ -0,0 +1,13 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --icu-locale=tr + +assertEquals('\u0130', 'i'.toLocaleUpperCase()); +assertEquals('\u0130', 'i'.toLocaleUpperCase(undefined)); +assertEquals('\u0130', 'i'.toLocaleUpperCase([])); + +assertEquals('\u0131', 'I'.toLocaleLowerCase()); +assertEquals('\u0131', 'I'.toLocaleLowerCase(undefined)); +assertEquals('\u0131', 'I'.toLocaleLowerCase([])); diff --git a/deps/v8/test/memory/Memory.json b/deps/v8/test/memory/Memory.json index f78e358f9a21..ae644e6d406e 100644 --- a/deps/v8/test/memory/Memory.json +++ b/deps/v8/test/memory/Memory.json @@ -1,7 +1,7 @@ { "owners": ["yangguo@chromium.org", "jgruber@chromium.org"], "name": "Memory", - "run_count": 5, + "run_count": 30, "units": "bytes", "resources": ["run.js"], "main": "run.js", @@ -39,16 +39,44 @@ }, { "name": "DeserializationTimeReadOnly", + "units": "ms", "results_regexp": "\\[Deserializing read-only space \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" }, { "name": "DeserializationTimeIsolate", + "units": "ms", "results_regexp": "\\[Deserializing isolate \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" }, + { + "name": "DeserializationTimeSharedHeap", + "units": "ms", + "results_regexp": "\\[Deserializing shared heap \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" + }, { "name": "DeserializationTimeContext", + "units": "ms", "results_regexp": "\\[Deserializing context #0 \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" }, + { + "name": "SerializationTimeReadOnly", + "units": "ms", + "results_regexp": "\\[Serializing read-only space \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" + }, + { + "name": "SerializationTimeStartup", + "units": "ms", + "results_regexp": "\\[Serializing isolate \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" + }, + { + "name": "SerializationTimeSharedHeap", + "units": "ms", + "results_regexp": "\\[Serializing shared heap \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" + }, + { + "name": "SerializationTimeContext", + "units": "ms", + "results_regexp": "\\[Serializing context #0 \\(\\d+ bytes\\) took ([\\d.]+) ms\\]" + }, { "name": "EmbeddedBuiltinsSize", "results_regexp": "^Embedded blob is (\\d+) bytes$" diff --git a/deps/v8/test/message/fail/bundle-duplicate-module.js b/deps/v8/test/message/fail/bundle-duplicate-module.js new file mode 100644 index 000000000000..72aef7049d70 --- /dev/null +++ b/deps/v8/test/message/fail/bundle-duplicate-module.js @@ -0,0 +1,14 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle + +// JS_BUNDLE_MODULE:a.mjs +export const a = 1; + +// JS_BUNDLE_MODULE:a.mjs +export const a = 2; + +// JS_BUNDLE_MODULE_ENTRYPOINT +import {a} from 'a.mjs'; diff --git a/deps/v8/test/message/fail/bundle-duplicate-module.out b/deps/v8/test/message/fail/bundle-duplicate-module.out new file mode 100644 index 000000000000..451cf433a1d0 --- /dev/null +++ b/deps/v8/test/message/fail/bundle-duplicate-module.out @@ -0,0 +1 @@ +Error: Duplicate bundle module: *a.mjs diff --git a/deps/v8/test/message/wasm-compilation-hints-inlining.js b/deps/v8/test/message/wasm-compilation-hints-inlining.js index 62a6f5119d0c..1fcdf79fda9c 100644 --- a/deps/v8/test/message/wasm-compilation-hints-inlining.js +++ b/deps/v8/test/message/wasm-compilation-hints-inlining.js @@ -59,7 +59,7 @@ d8.file.execute('test/mjsunit/mjsunit.js'); builder.setCompilationPriority(caller.index, 0, 0) builder.setInstructionFrequencies( - intermediate.index, [{offset:10, frequency: 32}]) + intermediate.index, [{offset:10, frequency: 32}]); builder.setCallTargets( intermediate.index, [{offset: 10, targets: [ {function_index: add.index, frequency_percent: 99}]}]); diff --git a/deps/v8/test/mjsunit/array-index-undefined-optimized.js b/deps/v8/test/mjsunit/array-index-undefined-optimized.js new file mode 100644 index 000000000000..790315772924 --- /dev/null +++ b/deps/v8/test/mjsunit/array-index-undefined-optimized.js @@ -0,0 +1,56 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev + +function checkOptimizedPair(omitted, explicit, expected, nextExpected) { + %PrepareFunctionForOptimization(omitted); + %PrepareFunctionForOptimization(explicit); + assertEquals(expected, omitted([42])); + assertEquals(expected, explicit([42])); + %OptimizeFunctionOnNextCall(omitted); + %OptimizeFunctionOnNextCall(explicit); + assertEquals(expected, omitted([42])); + assertEquals(expected, explicit([42])); + assertOptimized(omitted); + assertOptimized(explicit); + assertEquals(nextExpected, omitted([99])); + assertEquals(nextExpected, explicit([99])); + assertOptimized(omitted); + assertOptimized(explicit); +} + +function atOmitted(array) { + return array.at(); +} + +function atUndefined(array) { + return array.at(undefined); +} + +checkOptimizedPair(atOmitted, atUndefined, 42, 99); +assertEquals(undefined, atOmitted([])); +assertEquals(undefined, atUndefined([])); +assertOptimized(atOmitted); +assertOptimized(atUndefined); + +function indexOfOmitted(array) { + return array.indexOf(42); +} + +function indexOfUndefined(array) { + return array.indexOf(42, undefined); +} + +checkOptimizedPair(indexOfOmitted, indexOfUndefined, 0, -1); + +function includesOmitted(array) { + return array.includes(42); +} + +function includesUndefined(array) { + return array.includes(42, undefined); +} + +checkOptimizedPair(includesOmitted, includesUndefined, true, false); diff --git a/deps/v8/test/mjsunit/array-literal-transitions-no-pretenuring.js b/deps/v8/test/mjsunit/array-literal-transitions-no-pretenuring.js new file mode 100644 index 000000000000..57fef31d4a37 --- /dev/null +++ b/deps/v8/test/mjsunit/array-literal-transitions-no-pretenuring.js @@ -0,0 +1,246 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --no-allocation-site-pretenuring + +(function TestPackedDoubleToPackedObject() { + function make() { + return [1.1, 2.2]; + } + %PrepareFunctionForOptimization(make); + + // First call goes through Runtime_CreateArrayLiteral -> DeepCopy. + let a = make(); + assertTrue(%HasDoubleElements(a)); + assertTrue(%HasFastPackedElements(a)); + + a[0] = 'obj'; + assertTrue(%HasObjectElements(a)); + assertTrue(%HasFastPackedElements(a)); + + let b = make(); + assertTrue(%HasObjectElements(b)); + assertTrue(%HasFastPackedElements(b)); + + %OptimizeFunctionOnNextCall(make); + let c = make(); + assertTrue(%HasObjectElements(c)); + assertTrue(%HasFastPackedElements(c)); +})(); + +(function TestPackedDoubleToHoleyDouble() { + function make() { + return [1.1, 2.2]; + } + %PrepareFunctionForOptimization(make); + + let a = make(); + assertTrue(%HasDoubleElements(a)); + assertTrue(%HasFastPackedElements(a)); + + a[5] = 3.3; + assertTrue(%HasDoubleElements(a)); + assertTrue(%HasHoleyElements(a)); + + let b = make(); + assertTrue(%HasDoubleElements(b)); + assertTrue(%HasHoleyElements(b)); + + %OptimizeFunctionOnNextCall(make); + let c = make(); + assertTrue(%HasDoubleElements(c)); + assertTrue(%HasHoleyElements(c)); +})(); + +(function TestHoleyDoubleToHoleyObject() { + function make() { + return [1.1, , 2.2]; + } + %PrepareFunctionForOptimization(make); + + let a = make(); + assertTrue(%HasDoubleElements(a)); + assertTrue(%HasHoleyElements(a)); + + a[0] = 'obj'; + assertTrue(%HasObjectElements(a)); + assertTrue(%HasHoleyElements(a)); + + let b = make(); + assertTrue(%HasObjectElements(b)); + assertTrue(%HasHoleyElements(b)); + + %OptimizeFunctionOnNextCall(make); + let c = make(); + assertTrue(%HasObjectElements(c)); + assertTrue(%HasHoleyElements(c)); +})(); + +(function TestPackedObjectToHoleyObject() { + function make() { + return ['a', 'b']; + } + %PrepareFunctionForOptimization(make); + + let a = make(); + assertTrue(%HasObjectElements(a)); + assertTrue(%HasFastPackedElements(a)); + + a[5] = 'c'; + assertTrue(%HasObjectElements(a)); + assertTrue(%HasHoleyElements(a)); + + let b = make(); + assertTrue(%HasObjectElements(b)); + assertTrue(%HasHoleyElements(b)); + + %OptimizeFunctionOnNextCall(make); + let c = make(); + assertTrue(%HasObjectElements(c)); + assertTrue(%HasHoleyElements(c)); +})(); + +(function TestPackedSmiToDoubleToObject() { + function make() { + return [1, 2]; + } + %PrepareFunctionForOptimization(make); + + let a = make(); + assertTrue(%HasSmiElements(a)); + assertTrue(%HasFastPackedElements(a)); + + a[0] = 1.5; + let b = make(); + assertTrue(%HasDoubleElements(b)); + assertTrue(%HasFastPackedElements(b)); + + b[0] = 'obj'; + let c = make(); + assertTrue(%HasObjectElements(c)); + assertTrue(%HasFastPackedElements(c)); + + %OptimizeFunctionOnNextCall(make); + let d = make(); + assertTrue(%HasObjectElements(d)); + assertTrue(%HasFastPackedElements(d)); +})(); + +(function TestNestedArrayAndObjectLiterals() { + function makeNested() { + return { + double_arr: [1.1, 2.2], + obj_arr: ['a', 'b'], + deep_arr: [[[[1.1, 2.2]]]], + }; + } + %PrepareFunctionForOptimization(makeNested); + + let a = makeNested(); + assertTrue(%HasDoubleElements(a.double_arr)); + assertTrue(%HasFastPackedElements(a.double_arr)); + assertTrue(%HasObjectElements(a.obj_arr)); + assertTrue(%HasFastPackedElements(a.obj_arr)); + assertTrue(%HasDoubleElements(a.deep_arr[0][0][0])); + assertTrue(%HasFastPackedElements(a.deep_arr[0][0][0])); + + a.double_arr[0] = 'obj'; + a.obj_arr[5] = 'c'; + a.deep_arr[0][0][0][0] = 'obj'; + + let b = makeNested(); + assertTrue(%HasObjectElements(b.double_arr)); + assertTrue(%HasFastPackedElements(b.double_arr)); + assertTrue(%HasObjectElements(b.obj_arr)); + assertTrue(%HasHoleyElements(b.obj_arr)); + assertTrue(%HasObjectElements(b.deep_arr[0][0][0])); + assertTrue(%HasFastPackedElements(b.deep_arr[0][0][0])); + + // Also test transitioning a nested array on a subsequent call that goes + // through runtime deep copy. + b.deep_arr[0][0][0][5] = 'holey'; + let c = makeNested(); + assertTrue(%HasObjectElements(c.deep_arr[0][0][0])); + assertTrue(%HasHoleyElements(c.deep_arr[0][0][0])); +})(); + +(function TestDeoptOnPackedDoubleBoilerplateTransition() { + function make() { + return [1.1, 2.2]; + } + %PrepareFunctionForOptimization(make); + + // Allocate before optimization so `a` has an AllocationMemento. + let a = make(); + make(); + %OptimizeFunctionOnNextCall(make); + let b = make(); + assertTrue(%HasDoubleElements(b)); + assertTrue(%HasFastPackedElements(b)); + + // Transitioning `a` from PACKED_DOUBLE_ELEMENTS to PACKED_ELEMENTS updates + // the AllocationSite boilerplate and must deoptimize `make`. + a[0] = 'obj'; + assertUnoptimized(make); + + let c = make(); + assertTrue(%HasObjectElements(c)); + assertTrue(%HasFastPackedElements(c)); +})(); + +(function TestDeoptOnPackedObjectBoilerplateTransition() { + function make() { + return ['a', 'b']; + } + %PrepareFunctionForOptimization(make); + + // Allocate before optimization so `a` has an AllocationMemento. + let a = make(); + make(); + %OptimizeFunctionOnNextCall(make); + let b = make(); + assertTrue(%HasObjectElements(b)); + assertTrue(%HasFastPackedElements(b)); + + // Transitioning `a` from PACKED_ELEMENTS to HOLEY_ELEMENTS updates the + // AllocationSite boilerplate and must deoptimize `make`. + a[5] = 'c'; + assertUnoptimized(make); + + let c = make(); + assertTrue(%HasObjectElements(c)); + assertTrue(%HasHoleyElements(c)); +})(); + +(function TestArrayConstructorNonSmiTransitionsAndDeopt() { + function make() { + return new Array(); + } + %PrepareFunctionForOptimization(make); + + let a = make(); + assertTrue(%HasSmiElements(a)); + assertTrue(%HasFastPackedElements(a)); + + // Transition PACKED_SMI_ELEMENTS -> PACKED_DOUBLE_ELEMENTS. + a[0] = 1.5; + let b = make(); + assertTrue(%HasDoubleElements(b)); + assertTrue(%HasFastPackedElements(b)); + + %OptimizeFunctionOnNextCall(make); + let c = make(); + assertTrue(%HasDoubleElements(c)); + assertTrue(%HasFastPackedElements(c)); + + // `b` was allocated before optimization when the site had + // PACKED_DOUBLE_ELEMENTS; transitioning `b` to PACKED_ELEMENTS must update + // the site and deoptimize `make`. + b[0] = 'obj'; + assertUnoptimized(make); + + let d = make(); + assertTrue(%HasObjectElements(d)); + assertTrue(%HasFastPackedElements(d)); +})(); diff --git a/deps/v8/test/mjsunit/baseline/embedded-feedback-monotonic.js b/deps/v8/test/mjsunit/baseline/embedded-feedback-monotonic.js new file mode 100644 index 000000000000..52036201501c --- /dev/null +++ b/deps/v8/test/mjsunit/baseline/embedded-feedback-monotonic.js @@ -0,0 +1,39 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --sparkplug --sparkplug-plus --turbofan +// Flags: --no-always-sparkplug + +// Embedded feedback in the BytecodeArray must only ever widen, even when a +// Sparkplug+ typed stub misses after the interpreter has already widened the +// feedback byte behind its back. + +function f(a, b, cb) { + cb(); + return a + b; +} +function noop() {} +function compileBaseline() { %CompileBaseline(f); } + +%PrepareFunctionForOptimization(f); + +// Interpreter: byte = SignedSmall. +for (let i = 0; i < 10; i++) f(1, 2, noop); + +// Compile baseline from inside a live interpreted frame of f, so baseline +// picks the SignedSmall stub. The interpreted frame then widens the byte to +// Any with a string add. +f("a", "b", compileBaseline); + +// Baseline: the SignedSmall stub misses on HeapNumbers. This must merge into +// the existing Any feedback rather than overwrite it with Number. +f(1.5, 2.5, noop); + +%OptimizeFunctionOnNextCall(f); +f(1.5, 2.5, noop); +assertOptimized(f); + +// With Any feedback the optimized code uses a generic add and must not deopt. +assertEquals("ab", f("a", "b", noop)); +assertOptimized(f); diff --git a/deps/v8/test/mjsunit/call-lhs-web-compat-early-errors.js b/deps/v8/test/mjsunit/call-lhs-web-compat-early-errors.js index 3ac1cbe4d6f6..9a3b90086239 100644 --- a/deps/v8/test/mjsunit/call-lhs-web-compat-early-errors.js +++ b/deps/v8/test/mjsunit/call-lhs-web-compat-early-errors.js @@ -42,6 +42,16 @@ assertLateError("for (foo() of []) {}"); assertLateError("for (foo() in {}) {}"); assertLateError("for await (foo() of []) {}"); +// The web compatibility behavior does not apply in strict mode. +assertEarlyError("\"use strict\"; foo() = 0;"); +assertEarlyError("\"use strict\"; foo()++;"); +assertEarlyError("\"use strict\"; ++foo();"); +assertEarlyError("\"use strict\"; foo() += 1;"); +assertEarlyError("\"use strict\"; for (foo() of []) {}"); +assertEarlyError("\"use strict\"; for (foo() in {}) {}"); +assertEarlyError("\"use strict\"; (foo()) = 0;"); +assertEarlyError("\"use strict\"; (foo()) += 1;"); + // These are early errors though: assertEarlyError("for (let foo() = 0; ;) {}"); assertEarlyError("for (const foo() = 0; ;) {}"); diff --git a/deps/v8/test/mjsunit/code-cache-sha256.js b/deps/v8/test/mjsunit/code-cache-sha256.js new file mode 100644 index 000000000000..e05c200ffdc2 --- /dev/null +++ b/deps/v8/test/mjsunit/code-cache-sha256.js @@ -0,0 +1,11 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --cache=code --code-cache-source-hash-sha256 + +function foo(a, b) { + return a + b; +} + +assertEquals(foo(10, 20), 30); diff --git a/deps/v8/test/mjsunit/compiler/regress-531297707.js b/deps/v8/test/mjsunit/compiler/regress-531297707.js deleted file mode 100644 index b64b56575348..000000000000 --- a/deps/v8/test/mjsunit/compiler/regress-531297707.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --enable-inspector - -let msgId = 1; -function cmd(method, params) { - return JSON.stringify({id: msgId++, method: method, params: params || {}}); -} - -let ab = new ArrayBuffer(0x40000); // 256 KiB -let ta = new Uint32Array(ab); - -let armDetach = false; - -globalThis.handleInspectorMessage = function() { - if (armDetach) { - ab.transfer(0); - } - send(cmd("Debugger.resume")); -}; - -send(cmd("Debugger.enable")); -const PAUSE = cmd("Debugger.pause"); - -function hot(ta) { - send(PAUSE); - let sum = 0; - const n = ta.length; - for (let i = 0; i < n; i++) { - sum += ta[i]; - if (i > 10) break; // Early exit keeps it fast when deoptimized - } - return sum; -} - -%PrepareFunctionForOptimization(hot); -hot(ta); -%OptimizeFunctionOnNextCall(hot); -hot(ta); // Trigger optimization - -armDetach = true; -hot(ta); // Should deopt and not crash diff --git a/deps/v8/test/mjsunit/d8/d8-flag-normalization.js b/deps/v8/test/mjsunit/d8/d8-flag-normalization.js new file mode 100644 index 000000000000..47af1eb74e3a --- /dev/null +++ b/deps/v8/test/mjsunit/d8/d8-flag-normalization.js @@ -0,0 +1,9 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: -disallow_unsafe_flags -flag_processing_mode=ignore-contradictions +// Flags: --enable-os-system --noarguments + +assertEquals(undefined, os.system); +assertEquals('undefined', typeof arguments); diff --git a/deps/v8/test/mjsunit/d8/d8-inspector-shutdown-pending-evaluate.js b/deps/v8/test/mjsunit/d8/d8-inspector-shutdown-pending-evaluate.js deleted file mode 100644 index 0788bd7c46e3..000000000000 --- a/deps/v8/test/mjsunit/d8/d8-inspector-shutdown-pending-evaluate.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector - -// Verify that an unresolved asynchronous evaluation does not cause a -// use-after-free during d8 isolate and inspector session teardown. -send(JSON.stringify({ - id: 1, - method: 'Runtime.evaluate', - params: { - expression: 'new Promise(() => {})', - awaitPromise: true - } -})); diff --git a/deps/v8/test/mjsunit/d8/d8-module-tree-rollback.js b/deps/v8/test/mjsunit/d8/d8-module-tree-rollback.js new file mode 100644 index 000000000000..d7f0f5176d91 --- /dev/null +++ b/deps/v8/test/mjsunit/d8/d8-module-tree-rollback.js @@ -0,0 +1,31 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle --allow-natives-syntax + +// JS_BUNDLE_MODULE:mBad.mjs +syntax error! + +// JS_BUNDLE_MODULE:mB.mjs +import './mA.mjs'; + +// JS_BUNDLE_MODULE:mA.mjs +import './mB.mjs'; +import './mBad.mjs'; + +// JS_BUNDLE_SCRIPT +let caughtA = false; +let caughtB = false; + +import('mA.mjs').catch(e => { + caughtA = true; +}); +%PerformMicrotaskCheckpoint(); +assertTrue(caughtA); + +import('mB.mjs').catch(e => { + caughtB = true; +}); +%PerformMicrotaskCheckpoint(); +assertTrue(caughtB); diff --git a/deps/v8/test/mjsunit/d8/d8-realm-shared-templates.js b/deps/v8/test/mjsunit/d8/d8-realm-shared-templates.js new file mode 100644 index 000000000000..7f58ec8dfedd --- /dev/null +++ b/deps/v8/test/mjsunit/d8/d8-realm-shared-templates.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// All realms of an isolate share the templates of the d8 API. The objects and +// functions are still created per realm, but API objects created in one realm +// pass the receiver checks of the API functions of another realm. + +function getNodeTypeGetter(obj) { + for (let p = Object.getPrototypeOf(obj); p !== null; + p = Object.getPrototypeOf(p)) { + const desc = Object.getOwnPropertyDescriptor(p, 'nodeType'); + if (desc !== undefined) return desc.get; + } + return undefined; +} + +const realm = Realm.create(); +const div = new d8.dom.Div(); +const realm_div = Realm.eval(realm, 'new d8.dom.Div()'); + +// Constructors, prototypes and API functions are per realm. +assertNotSame(d8.dom.Div, Realm.eval(realm, 'd8.dom.Div')); +assertNotSame(Object.getPrototypeOf(div), Object.getPrototypeOf(realm_div)); +const getter = getNodeTypeGetter(div); +const realm_getter = getNodeTypeGetter(realm_div); +assertEquals('function', typeof getter); +assertEquals('function', typeof realm_getter); +assertNotSame(getter, realm_getter); + +// The receiver checks accept the objects of both realms. +assertEquals(div.nodeType, getter.call(realm_div)); +assertEquals(realm_div.nodeType, realm_getter.call(div)); + +// Non-API objects are still rejected (with the TypeError of the getter's +// realm). +assertThrows(() => getter.call({}), TypeError); +assertThrows(() => realm_getter.call({}), Realm.eval(realm, 'TypeError')); + +// Every realm still gets fresh objects: changes in one realm are not visible +// in another one. +d8.test.foo = 42; +assertEquals(undefined, Realm.eval(realm, 'd8.test.foo')); +assertEquals(undefined, Realm.eval(Realm.create(), 'd8.test.foo')); diff --git a/deps/v8/test/mjsunit/d8/d8-test-fast-api-realms.js b/deps/v8/test/mjsunit/d8/d8-test-fast-api-realms.js new file mode 100644 index 000000000000..61c4b1fdc355 --- /dev/null +++ b/deps/v8/test/mjsunit/d8/d8-test-fast-api-realms.js @@ -0,0 +1,59 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --turbo-fast-api-calls --expose-fast-api + +// d8.test.FastCAPI and d8.test.LeafInterfaceType are instantiated lazily in +// every realm, but their templates are shared by all realms of an isolate. +// Thus is_fast_c_api_object() recognizes the FastCAPI objects of all realms, +// independently of the order in which the realms accessed the constructor. + +// The constructors are not exposed in all configurations. +if (d8.test.FastCAPI !== undefined) { + const main_obj = new d8.test.FastCAPI(); + const realm = Realm.create(); + const realm_obj = Realm.eval(realm, 'new d8.test.FastCAPI()'); + + // Every realm has its own constructor function, created in that realm. + const realm_ctor = Realm.eval(realm, 'd8.test.FastCAPI'); + assertNotSame(d8.test.FastCAPI, realm_ctor); + assertSame( + Realm.eval(realm, 'Function.prototype'), + Object.getPrototypeOf(realm_ctor)); + // Later accesses return the same function. + assertSame(realm_ctor, Realm.eval(realm, 'd8.test.FastCAPI')); + + // The constructor is created in the realm of the d8.test object, even if + // the first access comes from another realm. + const other_realm = Realm.create(); + const other_test = Realm.eval(other_realm, 'd8.test'); + const other_ctor = other_test.FastCAPI; + assertSame( + Realm.eval(other_realm, 'Function.prototype'), + Object.getPrototypeOf(other_ctor)); + assertSame(other_ctor, Realm.eval(other_realm, 'd8.test.FastCAPI')); + assertSame( + Realm.eval(other_realm, 'Function.prototype'), + Object.getPrototypeOf(other_test.LeafInterfaceType)); + + assertTrue(main_obj.is_fast_c_api_object(main_obj)); + assertTrue(main_obj.is_fast_c_api_object(realm_obj)); + Realm.shared = {main_obj, realm_obj}; + assertTrue(Realm.eval( + realm, + 'Realm.shared.realm_obj.is_fast_c_api_object(Realm.shared.main_obj)')); + + // Accessing the constructor in another realm does not change the result. + const realm2 = Realm.create(); + const realm2_obj = Realm.eval(realm2, 'new d8.test.FastCAPI()'); + assertTrue(main_obj.is_fast_c_api_object(main_obj)); + assertTrue(main_obj.is_fast_c_api_object(realm_obj)); + assertTrue(main_obj.is_fast_c_api_object(realm2_obj)); + + // Objects of an unrelated API type are not FastCAPI objects in any realm. + assertFalse(main_obj.is_fast_c_api_object(new d8.test.LeafInterfaceType())); + assertFalse(main_obj.is_fast_c_api_object( + Realm.eval(realm, 'new d8.test.LeafInterfaceType()'))); + assertFalse(main_obj.is_fast_c_api_object({})); +} diff --git a/deps/v8/test/mjsunit/d8/flush-denormals-flag.js b/deps/v8/test/mjsunit/d8/flush-denormals-flag.js deleted file mode 100644 index e4c6f7b1165a..000000000000 --- a/deps/v8/test/mjsunit/d8/flush-denormals-flag.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --flush-denormals - -assertFalse(Number.MIN_VALUE * 2 > 0); -assertEquals(Number.MIN_VALUE * 2, 0); diff --git a/deps/v8/test/mjsunit/d8/flush-denormals-helper.js b/deps/v8/test/mjsunit/d8/flush-denormals-helper.js deleted file mode 100644 index 2e701a7de9df..000000000000 --- a/deps/v8/test/mjsunit/d8/flush-denormals-helper.js +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -assertTrue(Number.MIN_VALUE * 2 > 0); -d8.test.setFlushDenormals(true); -assertFalse(Number.MIN_VALUE * 2 > 0); -assertEquals(Number.MIN_VALUE * 2, 0); -d8.test.setFlushDenormals(false); -assertTrue(Number.MIN_VALUE * 2 > 0); diff --git a/deps/v8/test/mjsunit/d8/flush-denormals-worker.js b/deps/v8/test/mjsunit/d8/flush-denormals-worker.js deleted file mode 100644 index c4edff5e3941..000000000000 --- a/deps/v8/test/mjsunit/d8/flush-denormals-worker.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -assertTrue(Number.MIN_VALUE * 2 > 0); - -let flushed = new Worker(function() { - postMessage(Number.MIN_VALUE * 2 > 0); - postMessage(Number.MIN_VALUE * 2 == 0); -}, { - type: "function", - flushDenormals: true -}); -assertFalse(flushed.getMessage()); -assertTrue(flushed.getMessage()); - -let nonFlushed = new Worker(function() { - postMessage(Number.MIN_VALUE * 2 > 0); -}, { - type: "function", - flushDenormals: false -}); -assertTrue(nonFlushed.getMessage()); - -let defaultFlush = new Worker(function() { - postMessage(Number.MIN_VALUE * 2 > 0); -}, { - type: "function" -}); -assertTrue(defaultFlush.getMessage()); - -d8.test.setFlushDenormals(true); - -let defaultFlushWithFlush = new Worker(function() { - postMessage(Number.MIN_VALUE * 2 > 0); - postMessage(Number.MIN_VALUE * 2 == 0); -}, { - type: "function" -}); -assertFalse(defaultFlushWithFlush.getMessage()); -assertTrue(defaultFlushWithFlush.getMessage()); - -d8.test.setFlushDenormals(false); diff --git a/deps/v8/test/mjsunit/d8/regress-564550564.js b/deps/v8/test/mjsunit/d8/regress-564550564.js new file mode 100644 index 000000000000..c886a7d4a671 --- /dev/null +++ b/deps/v8/test/mjsunit/d8/regress-564550564.js @@ -0,0 +1,28 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle + +// JS_BUNDLE_MODULE:bundled.mjs +export const value = 42; + +// JS_BUNDLE_SCRIPT +const worker = new Worker(function() { + onmessage = function() { + import('bundled.mjs').then( + m => postMessage(m.value), e => postMessage(String(e))); + }; +}, {type: 'function'}); + +const worker_result = new Promise(resolve => { + worker.onmessage = function(event) { + worker.terminate(); + resolve(event.data); + }; +}); +assertPromiseResult(worker_result, value => assertEquals(42, value)); + +// Post from a task, so that the worker imports the bundled module only after +// the bundle's top-level code has finished. +setTimeout(() => worker.postMessage('import'), 0); diff --git a/deps/v8/test/mjsunit/debug-osr-debug-break.js b/deps/v8/test/mjsunit/debug-osr-debug-break.js deleted file mode 100644 index bd65449ae0d4..000000000000 --- a/deps/v8/test/mjsunit/debug-osr-debug-break.js +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --enable-inspector --turbofan --no-maglev - -let msgId = 1; -function cmd(method, params) { - return JSON.stringify({id: msgId++, method: method, params: params || {}}); -} - -function receive(msg) { - let obj = JSON.parse(msg); - if (obj.method === "Debugger.paused") { - send(cmd("Debugger.resume")); - } -} - -let top_frame_status_after_break = -1; -function check_deopt() { - eval(""); - top_frame_status_after_break = %GetOptimizationStatus(osr_top); -} -%NeverOptimizeFunction(check_deopt); - -function osr_top() { - for (let i = 0; i < 20; i++) { - if (i === 10) { - %OptimizeOsr(); - } - } - debugger; - check_deopt(); -} - -send(cmd("Debugger.enable")); -%PrepareFunctionForOptimization(osr_top); -osr_top(); - -// kTopmostFrameIsTurboFanned is bit 11 (1 << 11 = 2048) of GetOptimizationStatus -const kTopmostFrameIsTurboFanned = 1 << 11; -const isTopFrameTurboFanned = (top_frame_status_after_break & kTopmostFrameIsTurboFanned) !== 0; - -assertFalse(isTopFrameTurboFanned, "OSR topmost frame should be deoptimized after debugger break"); diff --git a/deps/v8/test/mjsunit/debug-osr-step-in-blackboxed.js b/deps/v8/test/mjsunit/debug-osr-step-in-blackboxed.js deleted file mode 100644 index 628647308a02..000000000000 --- a/deps/v8/test/mjsunit/debug-osr-step-in-blackboxed.js +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --enable-inspector --turbofan --no-maglev - -let msgId = 1; -function cmd(method, params) { return JSON.stringify({id: msgId++, method: method, params: params || {}}); } - -let paused_locations = []; - -function receive(msg) { - let obj = JSON.parse(msg); - if (obj.method === "Debugger.paused") { - let fnName = obj.params.callFrames[0].functionName; - paused_locations.push(fnName); - if (fnName === "callee") { - send(cmd("Debugger.stepInto")); - } else { - send(cmd("Debugger.resume")); - } - } -} - -function target() { - return 1; -} - -function callee() { - eval(""); - debugger; -} -%NeverOptimizeFunction(callee); - -eval(` -function osr_caller(osr) { - for (let i = 0; i < 20; i++) { - if (osr && i === 10) %OptimizeOsr(); - } - callee(); - target(); -} -//# sourceURL=osr_caller.js -`); - -// Gather feedback for inlining -%PrepareFunctionForOptimization(target); -callee(); -target(); -callee(); -target(); - -%PrepareFunctionForOptimization(osr_caller); -osr_caller(false); -osr_caller(false); - -send(cmd("Debugger.enable")); -// Blackbox osr_caller so FloodWithOneShot is skipped, exposing the bug in PrepareStep -send(cmd("Debugger.setBlackboxPatterns", { patterns: ["osr_caller\\.js"] })); - -paused_locations = []; -osr_caller(true); - -assertTrue(paused_locations.includes("target"), "BUG: target was not stepped into across blackboxed OSR caller"); diff --git a/deps/v8/test/mjsunit/debug-osr-step-on-throw-blackboxed.js b/deps/v8/test/mjsunit/debug-osr-step-on-throw-blackboxed.js deleted file mode 100644 index a8c83800d629..000000000000 --- a/deps/v8/test/mjsunit/debug-osr-step-on-throw-blackboxed.js +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --enable-inspector --turbofan --no-maglev - -let msgId = 1; -function cmd(method, params) { return JSON.stringify({id: msgId++, method: method, params: params || {}}); } - -let paused_locations = []; - -function receive(msg) { - let obj = JSON.parse(msg); - if (obj.method === "Debugger.paused") { - let fnName = obj.params.callFrames[0].functionName; - paused_locations.push(fnName); - if (fnName === "thrower") { - send(cmd("Debugger.stepInto")); - } else { - send(cmd("Debugger.resume")); - } - } -} - -function target() { - return 1; -} - -function thrower() { - eval(""); - debugger; - throw new Error("test"); -} -%NeverOptimizeFunction(thrower); - -eval(` -function osr_caller(osr) { - for (let i = 0; i < 20; i++) { - if (osr && i === 10) %OptimizeOsr(); - } - try { thrower(); } catch (e) { target(); } -} -//# sourceURL=osr_caller.js -`); - -// Gather feedback for inlining -%PrepareFunctionForOptimization(target); -try { thrower(); } catch(e) { target(); } -try { thrower(); } catch(e) { target(); } - -%PrepareFunctionForOptimization(osr_caller); -osr_caller(false); -osr_caller(false); - -send(cmd("Debugger.enable")); -// Blackbox osr_caller so FloodWithOneShot is skipped, exposing the bug in PrepareStepOnThrow -send(cmd("Debugger.setBlackboxPatterns", { patterns: ["osr_caller\\.js"] })); - -paused_locations = []; -osr_caller(true); - -assertTrue(paused_locations.includes("target"), "BUG: target was not stepped into across blackboxed OSR caller"); diff --git a/deps/v8/test/mjsunit/debug-osr-step-on-throw.js b/deps/v8/test/mjsunit/debug-osr-step-on-throw.js deleted file mode 100644 index de09c11931b6..000000000000 --- a/deps/v8/test/mjsunit/debug-osr-step-on-throw.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --enable-inspector --turbofan --no-maglev - -let msgId = 1; -function cmd(method, params) { - return JSON.stringify({id: msgId++, method: method, params: params || {}}); -} - -let paused_locations = []; - -function receive(msg) { - let obj = JSON.parse(msg); - if (obj.method === "Debugger.paused") { - let fnName = obj.params.callFrames[0].functionName; - paused_locations.push(fnName); - if (fnName !== "caught_target") { - send(cmd("Debugger.stepInto")); - } else { - send(cmd("Debugger.resume")); - } - } -} - -function caught_target() { - eval(""); - // Should step into here after exception unwinds to catch handler in osr_caller() -} - -function thrower() { - eval(""); - debugger; - throw new Error("test"); -} - -%NeverOptimizeFunction(thrower); -%NeverOptimizeFunction(caught_target); - -function osr_caller() { - for (let i = 0; i < 20; i++) { - if (i === 10) { - %OptimizeOsr(); - } - } - try { - thrower(); - } catch (e) { - caught_target(); - } -} - -send(cmd("Debugger.enable")); -%PrepareFunctionForOptimization(osr_caller); -osr_caller(); - -assertEquals(["thrower", "thrower", "osr_caller", "caught_target"], paused_locations); diff --git a/deps/v8/test/mjsunit/debug-osr-step-out.js b/deps/v8/test/mjsunit/debug-osr-step-out.js deleted file mode 100644 index 9044d75fc43a..000000000000 --- a/deps/v8/test/mjsunit/debug-osr-step-out.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --enable-inspector --turbofan --no-maglev - -let msgId = 1; -function cmd(method, params) { - return JSON.stringify({id: msgId++, method: method, params: params || {}}); -} - -let paused_locations = []; -function receive(msg) { - let obj = JSON.parse(msg); - if (obj.method === "Debugger.paused") { - let fnName = obj.params.callFrames[0].functionName; - paused_locations.push(fnName); - if (fnName === "foo") { - send(cmd("Debugger.stepOut")); - } else if (fnName === "osr_caller") { - send(cmd("Debugger.stepInto")); - } else { - send(cmd("Debugger.resume")); - } - } -} - -function bar() { - // Should pause here when stepping out of foo() from osr_caller() -} -%NeverOptimizeFunction(bar); - -function foo() { - debugger; -} -%NeverOptimizeFunction(foo); - -function osr_caller() { - for (let i = 0; i < 20; i++) { - if (i === 10) { - %OptimizeOsr(); - } - } - foo(); - bar(); -} - -send(cmd("Debugger.enable")); -%PrepareFunctionForOptimization(osr_caller); -osr_caller(); - -assertEquals(["foo", "osr_caller", "bar"], paused_locations); diff --git a/deps/v8/test/mjsunit/destructuring-default-maybe-assigned.js b/deps/v8/test/mjsunit/destructuring-default-maybe-assigned.js new file mode 100644 index 000000000000..8ba7c7739d87 --- /dev/null +++ b/deps/v8/test/mjsunit/destructuring-default-maybe-assigned.js @@ -0,0 +1,108 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function testLetArrayDefault(input) { + let [x = 10, [y = 20] = []] = input; + function read() { + return x + y; + } + return read; +} + +function testLetObjectDefault(input) { + let {x = 10, a: y = 20, b: {z = 30} = {}} = input; + function read() { + return x + y + z; + } + return read; +} + +function testVarDefault(input) { + var [x = 10] = input; + var {y = 20, a: z = 30} = input[1] || {}; + function read() { + return x + y + z; + } + return read; +} + +function testCatchDefault(input) { + try { + throw input; + } catch ([x = 10, {y = 20, a: z = 30} = {}]) { + return function read() { + return x + y + z; + }; + } +} + +function testLetDefaultMutatingEarlierBinding(input) { + let [x = 10, y = (x = 40)] = input; + function read() { + return x + y; + } + return read; +} + +function testVarDefaultSelfAssignment(input) { + var [x = (x = 42)] = input; + function read() { + return x; + } + return read; +} + +%PrepareFunctionForOptimization(testLetArrayDefault); +%PrepareFunctionForOptimization(testLetObjectDefault); +%PrepareFunctionForOptimization(testVarDefault); +%PrepareFunctionForOptimization(testCatchDefault); +%PrepareFunctionForOptimization(testLetDefaultMutatingEarlierBinding); +%PrepareFunctionForOptimization(testVarDefaultSelfAssignment); + +for (let i = 0; i < 3; ++i) { + assertEquals(30, testLetArrayDefault([])()); + assertEquals(3, testLetArrayDefault([1, [2]])()); + + assertEquals(60, testLetObjectDefault({})()); + assertEquals(6, testLetObjectDefault({x: 1, a: 2, b: {z: 3}})()); + + assertEquals(60, testVarDefault([])()); + assertEquals(6, testVarDefault([1, {y: 2, a: 3}])()); + + assertEquals(60, testCatchDefault([])()); + assertEquals(6, testCatchDefault([1, {y: 2, a: 3}])()); + + assertEquals(80, testLetDefaultMutatingEarlierBinding([])()); + assertEquals(5, testLetDefaultMutatingEarlierBinding([2, 3])()); + + assertEquals(42, testVarDefaultSelfAssignment([])()); + assertEquals(7, testVarDefaultSelfAssignment([7])()); +} + +%OptimizeFunctionOnNextCall(testLetArrayDefault); +%OptimizeFunctionOnNextCall(testLetObjectDefault); +%OptimizeFunctionOnNextCall(testVarDefault); +%OptimizeFunctionOnNextCall(testCatchDefault); +%OptimizeFunctionOnNextCall(testLetDefaultMutatingEarlierBinding); +%OptimizeFunctionOnNextCall(testVarDefaultSelfAssignment); + +assertEquals(30, testLetArrayDefault([])()); +assertEquals(3, testLetArrayDefault([1, [2]])()); + +assertEquals(60, testLetObjectDefault({})()); +assertEquals(6, testLetObjectDefault({x: 1, a: 2, b: {z: 3}})()); + +assertEquals(60, testVarDefault([])()); +assertEquals(6, testVarDefault([1, {y: 2, a: 3}])()); + +assertEquals(60, testCatchDefault([])()); +assertEquals(6, testCatchDefault([1, {y: 2, a: 3}])()); + +assertEquals(80, testLetDefaultMutatingEarlierBinding([])()); +assertEquals(5, testLetDefaultMutatingEarlierBinding([2, 3])()); + +assertEquals(42, testVarDefaultSelfAssignment([])()); +assertEquals(7, testVarDefaultSelfAssignment([7])()); diff --git a/deps/v8/test/mjsunit/disable-eager-inlining-no-non-eager.js b/deps/v8/test/mjsunit/disable-eager-inlining-no-non-eager.js new file mode 100644 index 000000000000..fce82f5a6e08 --- /dev/null +++ b/deps/v8/test/mjsunit/disable-eager-inlining-no-non-eager.js @@ -0,0 +1,67 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev --no-turbofan +// Flags: --no-maglev-non-eager-inlining +// Flags: --no-optimize-maglev-optimizes-to-turbofan + +(function TestEagerInliningBaseline() { + const proto = { x: 1 }; + const obj = Object.create(proto); + + function callee() { + return obj.x; + } + + function caller() { + return callee() + 10; + } + + %PrepareFunctionForOptimization(callee); + %PrepareFunctionForOptimization(caller); + assertEquals(11, caller()); + assertEquals(11, caller()); + + %OptimizeMaglevOnNextCall(caller); + assertEquals(11, caller()); + assertMaglevved(caller); + + // Invalidate prototype stability dependency. + proto.y = 2; + + // callee was eagerly inlined into caller, so caller must deoptimize. + assertUnoptimized(caller); + assertEquals(11, caller()); +})(); + +(function TestEagerInliningDisabled() { + const proto = { x: 1 }; + const obj = Object.create(proto); + + function callee() { + return obj.x; + } + %DisableEagerInlining(callee); + + function caller() { + return callee() + 10; + } + + %PrepareFunctionForOptimization(callee); + %PrepareFunctionForOptimization(caller); + assertEquals(11, caller()); + assertEquals(11, caller()); + + %OptimizeMaglevOnNextCall(caller); + assertEquals(11, caller()); + assertMaglevved(caller); + + // Invalidate prototype stability dependency. + proto.y = 2; + + // Eager inlining was disabled and non-eager inlining is disabled, so callee + // was not inlined. caller must remain Maglevved. + assertMaglevved(caller); + assertEquals(11, caller()); +})(); diff --git a/deps/v8/test/mjsunit/disable-eager-inlining.js b/deps/v8/test/mjsunit/disable-eager-inlining.js new file mode 100644 index 000000000000..3d01f28e6403 --- /dev/null +++ b/deps/v8/test/mjsunit/disable-eager-inlining.js @@ -0,0 +1,63 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev --maglev-non-eager-inlining --no-turbofan +// Flags: --no-optimize-maglev-optimizes-to-turbofan + +(function TestDirectOptimizationStillWorks() { + function fun(x) { + return x + 1; + } + %DisableEagerInlining(fun); + %PrepareFunctionForOptimization(fun); + assertEquals(43, fun(42)); + assertEquals(43, fun(42)); + %OptimizeMaglevOnNextCall(fun); + assertEquals(43, fun(42)); + assertMaglevved(fun); +})(); + +(function TestDisablingOptimizationStillWorks() { + function fun(x) { + return x + 1; + } + %DisableEagerInlining(fun); + %NeverOptimizeFunction(fun); + %PrepareFunctionForOptimization(fun); + assertEquals(43, fun(42)); + assertEquals(43, fun(42)); + %OptimizeMaglevOnNextCall(fun); + assertEquals(43, fun(42)); + assertUnoptimized(fun); +})(); + +(function TestNonEagerInliningWithDependency() { + const proto = { x: 1 }; + const obj = Object.create(proto); + + function callee() { + return obj.x; + } + %DisableEagerInlining(callee); + + function caller() { + return callee() + 10; + } + + %PrepareFunctionForOptimization(callee); + %PrepareFunctionForOptimization(caller); + assertEquals(11, caller()); + assertEquals(11, caller()); + + %OptimizeMaglevOnNextCall(caller); + assertEquals(11, caller()); + assertMaglevved(caller); + + // Invalidate prototype stability dependency. + proto.y = 2; + + // callee was non-eagerly inlined into caller, so caller must deoptimize. + assertUnoptimized(caller); + assertEquals(11, caller()); +})(); diff --git a/deps/v8/test/mjsunit/es6/classes-subclass-builtins.js b/deps/v8/test/mjsunit/es6/classes-subclass-builtins.js index aa5caae1366e..660cc77a529b 100644 --- a/deps/v8/test/mjsunit/es6/classes-subclass-builtins.js +++ b/deps/v8/test/mjsunit/es6/classes-subclass-builtins.js @@ -119,12 +119,10 @@ function checkPrototypeChain(object, constructors) { assertTrue(%HaveSameMap(sloppy_func, sloppy_func1)); // Strict function. - // When V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS is disabled, strict and - // sloppy functions have the same descriptors and share the derived initial - // map. + // Strict and sloppy functions have the same descriptors and share the + // derived initial map. var strict_func = new A("'use strict'; " + source); - assertEquals(!sloppy_func.hasOwnProperty("arguments"), - %HaveSameMap(strict_func, sloppy_func)); + assertTrue(%HaveSameMap(strict_func, sloppy_func)); CheckFunction(strict_func, false); var strict_func1 = new A("'use strict'; return 312;"); @@ -632,11 +630,9 @@ function TestMapSetSubclassing(container, is_map) { assertTrue(%HaveSameMap(sloppy_func, sloppy_func1)); // Strict generator function. - // When V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS is disabled, strict and - // sloppy functions share the derived initial map. + // Strict and sloppy functions share the derived initial map. var strict_func = new A("'use strict'; " + source); - assertEquals(!sloppy_func.hasOwnProperty("arguments"), - %HaveSameMap(strict_func, sloppy_func)); + assertTrue(%HaveSameMap(strict_func, sloppy_func)); CheckFunction(strict_func, false); var strict_func1 = new A("'use strict'; yield 312;"); diff --git a/deps/v8/test/mjsunit/es6/regress-analyze-partially-arrow-head-lazy.js b/deps/v8/test/mjsunit/es6/regress-analyze-partially-arrow-head-lazy.js new file mode 100644 index 000000000000..5afa507b17a5 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-analyze-partially-arrow-head-lazy.js @@ -0,0 +1,53 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that unresolved variables from lazily parsed functions inside the +// parameter list of a lazily parsed arrow function are properly propagated to +// outer scopes during Scope::AnalyzePartially. + +(function TestSloppyEvalLetAssignedInArrowHeadDefaultFunc() { + eval(` + let x = 1; + let g = () => x; + let f = (a = function foo() { x = 42; }) => { + a(); + }; + for (let i = 0; i < 10000; i++) { + assertEquals(1, g()); + } + f(); + assertEquals(42, g()); + `); +})(); + +(function TestSloppyEvalArrowHeadAndOuterCapture() { + eval(` + let x = 1; + let g = () => x; + let f = (a = function foo() { b = 10; x = 99; }, b = 2) => { + assertEquals(2, b); + a(); + assertEquals(10, b); + }; + for (let i = 0; i < 10000; i++) { + assertEquals(1, g()); + } + f(); + assertEquals(99, g()); + `); +})(); + +try { + throw 1; +} catch (x) { + var g_catch = () => x; + var f_catch = (a = function foo() { x = 42; }) => { + a(); + }; + for (let i = 0; i < 10000; i++) { + assertEquals(1, g_catch()); + } + f_catch(); + assertEquals(42, g_catch()); +} diff --git a/deps/v8/test/mjsunit/es6/regress-arrow-cover-grammar-scope.js b/deps/v8/test/mjsunit/es6/regress-arrow-cover-grammar-scope.js new file mode 100644 index 000000000000..9f98be07e44b --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-arrow-cover-grammar-scope.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Arrow parameter list cover-grammar extensions (rest parameters and +// trailing commas before `) =>`) are only allowed in arrow head scopes, and +// strict `eval`/`arguments` rest parameters must be classified via +// RecordStrictModeParameterError rather than failing eagerly in +// ParseBindingPattern. + +assertThrows( + () => eval("a, ...x = 1"), + SyntaxError, + "Unexpected token '...'"); +assertThrows( + () => eval("a, ...x, y"), + SyntaxError, + "Unexpected token '...'"); +assertThrows( + () => eval("if (a,) => {}"), + SyntaxError, + "Unexpected token ')'"); +assertThrows( + () => eval("while (a,) => {}"), + SyntaxError, + "Unexpected token ')'"); +assertThrows( + () => eval('"use strict"; ({a = 42}, ...eval) => {}'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('"use strict"; (1, ...eval) => {}'), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval('"use strict"; (a, ...eval)'), + SyntaxError, + "Unexpected token '...'"); diff --git a/deps/v8/test/mjsunit/es6/regress-arrow-head-pattern-error-order.js b/deps/v8/test/mjsunit/es6/regress-arrow-head-pattern-error-order.js new file mode 100644 index 000000000000..10e80fedbada --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-arrow-head-pattern-error-order.js @@ -0,0 +1,61 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ArrowHeadParsingScope must validate both declaration and pattern errors so +// the earliest error in source order is reported, and must not overwrite +// earlier errors or validate expression errors when rest parameter parsing +// fails. + +assertThrows( + () => eval("([...a, b], 1) => {}"), + SyntaxError, + "Rest element must be last element"); +assertThrows( + () => eval("({...a, b}, 1) => {}"), + SyntaxError, + "Rest element must be last element"); +assertThrows( + () => eval("([...a, b], [c.d]) => {}"), + SyntaxError, + "Rest element must be last element"); +assertThrows( + () => eval("([a, a], [...b, c]) => {}"), + SyntaxError, + "Rest element must be last element"); +assertThrows( + () => eval("([a, a], [1]) => {}"), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval("({a = 42}, ...z = 1) => {}"), + SyntaxError, + "Rest parameter may not have a default initializer"); +assertThrows( + () => eval("({a = 42}, ...z, w) => {}"), + SyntaxError, + "Rest parameter must be last formal parameter"); +assertThrows( + () => eval("(1, ...z = 1) => {}"), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval("([a.b], ...z = 1) => {}"), + SyntaxError, + "Illegal property in declaration context"); +assertThrows( + () => eval("([...a, b], ...z = 1) => {}"), + SyntaxError, + "Rest element must be last element"); +assertThrows( + () => eval("(1, ...z, w) => {}"), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval("({a = 42}, ...1) => {}"), + SyntaxError, + "Unexpected number"); +assertThrows( + () => eval("(1, ...2) => {}"), + SyntaxError, + "Invalid destructuring assignment target"); diff --git a/deps/v8/test/mjsunit/es6/regress-arrow-reparse-strict-param.js b/deps/v8/test/mjsunit/es6/regress-arrow-reparse-strict-param.js new file mode 100644 index 000000000000..5fae19a1a3c2 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-arrow-reparse-strict-param.js @@ -0,0 +1,24 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// When a lazy top-level arrow function aborts preparsing due to an +// unidentifiable error in its body and reparses the arrow head, strict +// parameter errors in the head must still be preserved and reported first. + +assertThrows( + () => eval('let f = (eval) => { "use strict"; let x; let x; };'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('let f = eval => { "use strict"; let x; let x; };'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('let f = (arguments) => { "use strict"; let x; let x; };'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('let f = (implements) => { "use strict"; function g(a, a) {} };'), + SyntaxError, + "Unexpected strict mode reserved word"); diff --git a/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-eos.js b/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-eos.js new file mode 100644 index 000000000000..52538f6dbce9 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-eos.js @@ -0,0 +1,102 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let x = 1; + +// Instance field initializer throwing when the final uninitialized field is +// named static, get, set, or async (with or without semicolon / static). +assertThrows(() => { + class C { a = x(); static; } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); static } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); get; } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); get } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); set; } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); set } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); async; } + new C(); +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { a = x(); async } + new C(); +}, TypeError, "x is not a function"); + +// Static field initializer throwing when the final uninitialized field is +// named static, get, set, or async (instance or static). +assertThrows(() => { + class C { static a = x(); static; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); get; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); set; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); async; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static static; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static get; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static get } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static set; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static set } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static async; } +}, TypeError, "x is not a function"); + +assertThrows(() => { + class C { static a = x(); static async } +}, TypeError, "x is not a function"); + +// Incomplete classes at EOF must still throw SyntaxError. +assertThrows(() => eval("class C { static"), SyntaxError); +assertThrows(() => eval("class C { get"), SyntaxError); +assertThrows(() => eval("class C { set"), SyntaxError); +assertThrows(() => eval("class C { async"), SyntaxError); +assertThrows(() => eval("class C { static get"), SyntaxError); +assertThrows(() => eval("class C { static set"), SyntaxError); +assertThrows(() => eval("class C { static async"), SyntaxError); diff --git a/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-super.js b/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-super.js new file mode 100644 index 000000000000..bb8a1ae31ca3 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-class-member-init-reparse-super.js @@ -0,0 +1,128 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Case A1: Inner class without ClassScope in ScopeInfo, computed property key +// with super.prop inside a method with a context. +{ + class Outer { + m() { + let x; + () => x; + return class { + a = 1; + [super.prop]() {} + b = ({x: this.a} = null); + }; + } + } + const C = new Outer().m(); + assertThrows( + () => new C(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); +} + +// Case A2: Outer object literal without ObjectLiteralScope in ScopeInfo, +// enclosing method m1 with a context, inner class m2 without context, +// and innermost class with [super.prop] computed property key. +{ + const obj = { + m1() { + let x; + () => x; + const Outer2 = class { + m2() { + return class { + a = 1; + [super.prop]() {} + b = ({x: this.a} = null); + }; + } + }; + return new Outer2().m2(); + } + }; + const C = obj.m1(); + assertThrows( + () => new C(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); +} + +// Case B1: Enclosing static method without context (elided from ScopeInfo), +// inner class with [super.prop] computed method key. +{ + class Outer { + static m() { + return class Inner { + a = 1; + [super.prop]() {} + b = ({x: this.a} = null); + }; + } + } + const C = Outer.m(); + assertThrows( + () => new C(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); +} + +// Case B2: Computed property key with super[expr] and computed field with +// super.prop in both instance and static initializers. +{ + class Outer { + m() { + return class Inner { + a = 1; + [super['prop']] = 2; + b = ({x: this.a} = null); + }; + } + static sm() { + return class StaticInner { + static a = 1; + static [super.prop]() {} + static { + ({x: this.a} = null); + } + }; + } + } + const C = new Outer().m(); + assertThrows( + () => new C(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); + assertThrows( + () => Outer.sm(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); +} + +// Case C: super() and new.target in computed property keys when enclosing +// constructor/function scope was elided from ScopeInfo. +{ + class Base {} + class Derived extends Base { + constructor() { + return class Inner { + a = 1; + [super()]() {} + b = ({x: this.a} = null); + }; + } + } + const C1 = new Derived(); + assertThrows( + () => new C1(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); + + function makeClass() { + return class Inner { + a = 1; + [new.target]() {} + b = ({x: this.a} = null); + }; + } + const C2 = makeClass(); + assertThrows( + () => new C2(), TypeError, + "Cannot destructure property 'x' of 'null' as it is null."); +} diff --git a/deps/v8/test/mjsunit/es6/regress-comma-expression-arrow-initializers.js b/deps/v8/test/mjsunit/es6/regress-comma-expression-arrow-initializers.js new file mode 100644 index 000000000000..ff17fa4b2878 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-comma-expression-arrow-initializers.js @@ -0,0 +1,15 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let b = 0; +([1], [b] = [42]); +assertEquals(42, b); + +for (let i = ([1], [b] = [99]); false; ) {} +assertEquals(99, b); + +assertThrows( + () => eval("for (let i = ([{a = 42}.f()], [b] = [1]); false; ) {}"), + SyntaxError, + "Invalid shorthand property initializer"); diff --git a/deps/v8/test/mjsunit/es6/regress-conditional-chain-non-short-circuit.js b/deps/v8/test/mjsunit/es6/regress-conditional-chain-non-short-circuit.js new file mode 100644 index 000000000000..5dd75f23747b --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-conditional-chain-non-short-circuit.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// In ConditionalExpression (`ShortCircuitExpression ? AssignmentExpression : +// AssignmentExpression`), if the else branch is an AssignmentExpression that +// is not a ShortCircuitExpression (such as an ArrowFunction with a block body +// or a bare YieldExpression), it cannot be followed by `?` as the condition +// of another conditional expression. + +assertThrows( + () => eval("false ? 1 : () => {} ? 2 : 3"), + SyntaxError, + "Unexpected token '?'"); +assertThrows( + () => eval("false ? 1 : x => {} ? 2 : 3"), + SyntaxError, + "Unexpected token '?'"); +assertThrows( + () => eval("false ? 1 : async () => {} ? 2 : 3"), + SyntaxError, + "Unexpected token '?'"); +assertThrows( + () => eval("false ? 1 : async x => {} ? 2 : 3"), + SyntaxError, + "Unexpected token '?'"); +assertThrows( + () => eval("function* g() { return false ? 1 : yield\n ? 2 : 3; }"), + SyntaxError, + "Unexpected token '?'"); +assertThrows( + () => eval("true ? () => {} : () => {} ? 2 : 3"), + SyntaxError, + "Unexpected token '?'"); diff --git a/deps/v8/test/mjsunit/es6/regress-dynamic-local-param-hole-check.js b/deps/v8/test/mjsunit/es6/regress-dynamic-local-param-hole-check.js new file mode 100644 index 000000000000..af7e61b28a41 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-dynamic-local-param-hole-check.js @@ -0,0 +1,70 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const s = "x".repeat(70000); + +// Regular function with > 64KB default parameter, sloppy eval, block scope +// reference, and inner closure reference (inner closure resolved before block +// scope due to LIFO inner_scope_ list). +assertEquals(1, eval(` + (function f(b = "${s}", a = 1) { + eval(""); + { + let c = 1; + a; + } + return (() => a)(); + })(); +`)); + +// Arrow function with > 64KB default parameter, sloppy eval, block scope +// reference, and inner closure reference. +assertEquals(1, eval(` + ((b = "${s}", a = 1) => { + eval(""); + { + let c = 1; + a; + } + return (() => a)(); + })(); +`)); + +// Direct reference in the VarBlock body resolved before the inner closure. +assertEquals(1, eval(` + (function f(b = "${s}", a = 1) { + eval(""); + a; + return (() => a)(); + })(); +`)); + +assertEquals(1, eval(` + ((b = "${s}", a = 1) => { + eval(""); + a; + return (() => a)(); + })(); +`)); + +// Non-simple parameters with context-allocated variable in the body. +(function f(b = 0, a = 1) { + let captured = 2; + eval(""); + { + let c = 1; + assertEquals(1, a); + } + assertEquals(3, (() => a + captured)()); +})(); + +((b = 0, a = 1) => { + let captured = 2; + eval(""); + { + let c = 1; + assertEquals(1, a); + } + assertEquals(3, (() => a + captured)()); +})(); diff --git a/deps/v8/test/mjsunit/es6/regress-escaped-contextual-keywords.js b/deps/v8/test/mjsunit/es6/regress-escaped-contextual-keywords.js new file mode 100644 index 000000000000..e40a1d2125e2 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-escaped-contextual-keywords.js @@ -0,0 +1,72 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-decorators + +// Issue A: `for \u0061wait` must not be parsed as `for await`. +assertThrows("async function f() { for \\u0061wait (let x of []) {} }", SyntaxError); +assertThrows("async () => { for \\u0061wait (let x of []) {} }", SyntaxError); + +// Issue B: Escaped `using` or `await` must not be parsed as `using` / `await using`. +assertThrows("{ \\u0075sing x = null; }", SyntaxError); +assertThrows("function f() { \\u0075sing x = null; }", SyntaxError); +assertThrows("for (\\u0075sing x of []) {}", SyntaxError); +assertThrows("for (\\u0075sing x = null;;) {}", SyntaxError); +assertThrows("async function f() { for await (\\u0075sing x of []) {} }", SyntaxError); + +assertThrows("async function f() { \\u0061wait using x = null; }", SyntaxError); +assertThrows("async function f() { await \\u0075sing x = null; }", SyntaxError); +assertThrows("async function f() { for (\\u0061wait using x of []) {} }", SyntaxError); +assertThrows("async function f() { for (await \\u0075sing x of []) {} }", SyntaxError); +assertThrows("async function f() { for (\\u0061wait using x = null;;) {} }", SyntaxError); +assertThrows("async function f() { for (await \\u0075sing x = null;;) {} }", SyntaxError); +assertThrows("async function f() { for await (\\u0061wait using x of []) {} }", SyntaxError); +assertThrows("async function f() { for await (await \\u0075sing x of []) {} }", SyntaxError); + +// Escaped `\u006ff` in `for (using \u006ff of ...)` is a valid binding identifier. +{ + let disposed = false; + for (using \u006ff of [{ [Symbol.dispose]() { disposed = true; } }]) { + assertEquals("object", typeof of); + } + assertTrue(disposed); +} + +// Escaped `\u0075sing` in `for (\u0075sing of ...)` is an identifier reference. +{ + let using = 0; + for (\u0075sing of [42]) {} + assertEquals(42, using); +} + +// Issue C: Escaped `\u0061ccessor` in class body cannot start an auto-accessor. +assertThrows("class C { \\u0061ccessor x = 1; }", SyntaxError); +assertThrows("class C { static \\u0061ccessor x = 1; }", SyntaxError); +assertThrows("class C { \\u0061ccessor [x] = 1; }", SyntaxError); + +{ + class C { + \u0061ccessor = 42; + \u0061ccessor2() { return 10; } + } + assertEquals(42, new C().accessor); +} + +{ + class C { + \u0061ccessor() { return 42; } + } + assertEquals(42, new C().accessor()); +} + +{ + class C { + \u0061ccessor + x = 42; + } + let c = new C(); + assertTrue(Object.hasOwn(c, "accessor")); + assertEquals(undefined, c.accessor); + assertEquals(42, c.x); +} diff --git a/deps/v8/test/mjsunit/es6/regress-eval-var-arguments-default-param.js b/deps/v8/test/mjsunit/es6/regress-eval-var-arguments-default-param.js new file mode 100644 index 000000000000..77fb7431ac13 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-eval-var-arguments-default-param.js @@ -0,0 +1,107 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Direct eval declaring `var arguments` or `function arguments` in a +// non-simple parameter default initializer must throw a SyntaxError. + +assertThrows(() => { + function f(a = eval("var arguments = 42")) { + return arguments; + } + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = eval("var arguments")) { + return arguments; + } + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = eval("function arguments() {}")) { + return arguments; + } + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = { Let: eval("var arguments = 42") }) { + return arguments; + } + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = eval("var arguments")) {} + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = eval("var arguments")) { + var arguments; + } + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = eval("var arguments")) { + let arguments; + } + f(); +}, SyntaxError); + +assertThrows(() => { + function f(a = eval("var arguments")) { + function arguments() {} + } + f(); +}, SyntaxError); + +// Direct eval in the function body with non-simple parameters is still allowed +// to declare `var arguments`. +(function() { + function f(a = 1) { + eval("var arguments = 42"); + return arguments; + } + assertEquals(42, f()); +})(); + +// Direct eval in the function body with simple parameters is still allowed +// to declare `var arguments`. +(function() { + function f() { + eval("var arguments = 42"); + return arguments; + } + assertEquals(42, f()); +})(); + +// Direct eval inside an inner function in a default parameter initializer +// declares `var arguments` in the inner function's scope and does not conflict +// with the outer function's `arguments`. +(function() { + function f(a = (() => eval("var arguments = 42; arguments"))()) { + return [a, arguments[1]]; + } + assertEquals([42, 10], f(undefined, 10)); +})(); + +(function() { + function f(a = (function() { return eval("var arguments = 42; arguments"); })()) { + return [a, arguments[1]]; + } + assertEquals([42, 10], f(undefined, 10)); +})(); + +// Direct eval in an arrow function's default parameter initializer hoists to +// the enclosing non-arrow function's body scope if allowed. +(function() { + function outer() { + let arrow = (a = eval("var arguments = 42")) => arguments; + return arrow(); + } + assertEquals(42, outer()); +})(); diff --git a/deps/v8/test/mjsunit/es6/regress-for-of-async-property.js b/deps/v8/test/mjsunit/es6/regress-for-of-async-property.js new file mode 100644 index 000000000000..cbbc9d14b60e --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-for-of-async-property.js @@ -0,0 +1,36 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Only the bare identifier `async` is disallowed as the left-hand side of a +// for-of loop (`for (async of ...)`). Property accesses like `x.async` must +// be allowed, and non-identifier expressions ending in `async` must report +// standard LHS errors rather than "The left-hand side of a for-of loop may +// not be 'async'". + +let obj = {}; +for (obj.async of [42]) {} +assertEquals(42, obj.async); + +{ + let async = 0; + for ((async) of [42]) {} + assertEquals(42, async); +} + +assertThrows( + () => eval("for (async of [1]) {}"), + SyntaxError, + "The left-hand side of a for-of loop may not be 'async'."); +assertThrows( + () => eval("for (obj?.async of [1]) {}"), + SyntaxError, + "Invalid left-hand side in for-loop"); +assertThrows( + () => eval("for (+async of [1]) {}"), + SyntaxError, + "Invalid left-hand side in for-loop"); +assertThrows( + () => eval("for (a, async of [1]) {}"), + SyntaxError, + "Invalid left-hand side in for-loop"); diff --git a/deps/v8/test/mjsunit/es6/regress-invalid-lhs-validate-expression.js b/deps/v8/test/mjsunit/es6/regress-invalid-lhs-validate-expression.js new file mode 100644 index 000000000000..36e3029bfd25 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-invalid-lhs-validate-expression.js @@ -0,0 +1,35 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Expression errors inside an invalid assignment or count-operation LHS +// must be validated before reporting or rewriting the invalid reference. + +assertThrows( + () => eval("+({a = 42}) = 1"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("+{a = 42} = 1"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("++{a = 42}"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({a = 42}++)"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({a = 42}.f() &&= 1)"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({a = 42}.f`` = 1)"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[{a = 42}.f() = 1] = []"), + SyntaxError, + "Invalid shorthand property initializer"); diff --git a/deps/v8/test/mjsunit/es6/regress-member-template-expression-scope.js b/deps/v8/test/mjsunit/es6/regress-member-template-expression-scope.js new file mode 100644 index 000000000000..f7d1777f327c --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-member-template-expression-scope.js @@ -0,0 +1,39 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Bracketed property keys and template literal interpolations are always +// expressions, never binding patterns or arrow parameter lists. + +assertThrows( + () => eval("let [a, b[a]] = [];"), + SyntaxError, + "Illegal property in declaration context"); +assertThrows( + () => eval("let [b[let]] = [];"), + SyntaxError, + "Illegal property in declaration context"); +assertThrows( + () => eval("let [a, b?.[a]] = [];"), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval("let [a, tag`${a}`] = [];"), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval("let [tag`${let}`] = [];"), + SyntaxError, + "Invalid destructuring assignment target"); +assertThrows( + () => eval("[obj[{a = 42}].f()] = [];"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[obj?.[{a = 42}].f()] = [];"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[`${{a = 42}}`] = [];"), + SyntaxError, + "Invalid shorthand property initializer"); diff --git a/deps/v8/test/mjsunit/es6/regress-object-rest-property-validation.js b/deps/v8/test/mjsunit/es6/regress-object-rest-property-validation.js new file mode 100644 index 000000000000..cf8ff94eb975 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-object-rest-property-validation.js @@ -0,0 +1,40 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Object spread/rest properties must validate inner expression errors when +// the operand is not a valid reference expression, and must only record +// kElementAfterRest when followed by a comma. + +assertThrows( + () => eval("({...{a = 42}} = {})"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({...[{a = 42}]} = {})"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({...{a = 42}}) => {}"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({...1} = {})"), + SyntaxError, + "`...` must be followed by an assignable reference in assignment contexts"); +assertThrows( + () => eval("({...[1]} = {})"), + SyntaxError, + "`...` must be followed by an assignable reference in assignment contexts"); +assertThrows( + () => eval("let { ...a b } = {}"), + SyntaxError, + "Unexpected identifier 'b'"); +assertThrows( + () => eval("let { ...a : 1 } = {}"), + SyntaxError, + "Unexpected token ':'"); +assertThrows( + () => eval("function f({ ...a : 1 }) {}"), + SyntaxError, + "Unexpected token ':'"); diff --git a/deps/v8/test/mjsunit/es6/regress-preparser-optional-chain-private.js b/deps/v8/test/mjsunit/es6/regress-preparser-optional-chain-private.js new file mode 100644 index 000000000000..7465ef46377d --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-preparser-optional-chain-private.js @@ -0,0 +1,26 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Optional chains ending in a private field (`a?.#b`) are not valid +// LeftHandSideExpressions for assignment, update expressions, destructuring, +// or for-in/of targets, including when lazy-parsed by PreParser. + +const cases = [ + "class C { #b; m(a) { a?.#b = 1; } }", + "class C { #b; m(a) { a?.#b += 1; } }", + "class C { #b; m(a) { ++a?.#b; } }", + "class C { #b; m(a) { a?.#b++; } }", + "class C { #b; m(a) { [a?.#b] = []; } }", + "class C { #b; m(a) { ({x: a?.#b} = {}); } }", + "class C { #b; m(a) { [...a?.#b] = []; } }", + "class C { #b; m(a) { ({...a?.#b} = {}); } }", + "class C { #b; m(a) { let [a?.#b] = []; } }", + "class C { #b; m(a) { for (a?.#b of []) {} } }", + "class C { #b; m(a) { for (a?.#b in {}) {} } }", +]; + +for (const code of cases) { + assertThrows(() => eval(code), SyntaxError); + assertThrows(() => eval("(" + code + ")"), SyntaxError); +} diff --git a/deps/v8/test/mjsunit/es6/regress-preparser-validate-formals-on-body-error.js b/deps/v8/test/mjsunit/es6/regress-preparser-validate-formals-on-body-error.js new file mode 100644 index 000000000000..a119b1a9b47d --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-preparser-validate-formals-on-body-error.js @@ -0,0 +1,28 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Lazy functions must validate formal parameters and propagate body strict +// mode even when the function body has a syntax error, matching eager +// parsing and reporting the earlier parameter error first. + +assertThrows( + () => eval('function f(eval) { "use strict"; break; }'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('function f(a, a) { "use strict"; break; }'), + SyntaxError, + "Duplicate parameter name not allowed in this context"); +assertThrows( + () => eval('function f(eval, a = 1) { "use strict"; }'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('let f = (eval, a = 1) => { "use strict"; };'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('let f = (eval) => { "use strict"; break; };'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); diff --git a/deps/v8/test/mjsunit/es6/regress-private-name-heritage-recalc.js b/deps/v8/test/mjsunit/es6/regress-private-name-heritage-recalc.js new file mode 100644 index 000000000000..682b3aae66fb --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-private-name-heritage-recalc.js @@ -0,0 +1,90 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test 1: Nested class in heritage expression with lazy method compilation +// and PreparseData. +{ + class B { + #x = "from B"; + static { + class C extends (class D { + static m() { + return (() => function(o) { return o.#x; })(); + } + }) { + #x = "from C"; + } + assertEquals("from B", C.m()(new B())); + assertThrows(() => C.m()(new C()), TypeError); + } + } +} + +// Test 2: Direct eval in heritage expression of a class that does not allocate +// a context. +{ + let f; + class B { + #x = "from B"; + [(class extends (f = (o) => eval("o.#x"), Object) {})]; + } + assertEquals("from B", f(new B())); +} + +// Test 3: Direct eval in nested function inside heritage expression where +// the outer heritage function does not allocate a context. +{ + class B { + #x = "from B"; + static test(b) { + let f; + class C extends (() => { + f = (o) => eval("o.#x"); + return Object; + })() { + #x = "from C"; + } + assertThrows(() => f(new C()), TypeError); + return f(b); + } + } + assertEquals("from B", B.test(new B())); +} + +// Test 4: Nested class with its own private field inside a lazy heritage +// function that does not allocate a context, using direct eval. +{ + class B { + #x = "from B"; + static { + let f; + class C extends (f = () => class D { + #y = "from D"; + static m(o) { + return eval("o.#x"); + } + }, Object) { + #x = "from C"; + } + assertEquals("from B", f().m(new B())); + assertThrows(() => f().m(new C()), TypeError); + } + } +} + +// Test 5: Nested class with its own private field inside heritage expression +// of an anonymous class that does not allocate a context, using direct eval. +{ + let D_cls; + class B { + #x = "from B"; + [(class extends (D_cls = class D { + #y = "from D"; + static m(o) { + return eval("o.#x"); + } + }) {})]; + } + assertEquals("from B", D_cls.m(new B())); +} diff --git a/deps/v8/test/mjsunit/es6/regress-rewriter-completion-values.js b/deps/v8/test/mjsunit/es6/regress-rewriter-completion-values.js new file mode 100644 index 000000000000..42f2637f7ce6 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-rewriter-completion-values.js @@ -0,0 +1,31 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Sloppy block function hoisting in scripts must not contribute to the +// completion value. +const r = Realm.create(); +assertEquals(undefined, Realm.eval(r, "{ function f() {} }")); +assertEquals(1, Realm.eval(r, "1; { function f() {} }")); + +// An empty catch block (or one without a value-producing statement) must +// produce undefined even if the try block wrote to .result before throwing. +assertEquals(undefined, eval("try { do { 42; } while (null.x); } catch (e) {}")); +assertEquals( + undefined, eval("try { try { 42; } finally { null.x; } } catch (e) {}")); +assertEquals( + undefined, + eval("try { using x = { [Symbol.dispose]() { throw 1; } }; 42; } catch (e) {}")); +assertEquals( + undefined, + eval("L: { try { 42; L2: { break L2; } null.x; } catch (e) {} }")); + +// A labeled break whose target is inside a finally block completes the finally +// block normally and must preserve the try block's completion value. +assertEquals(1, eval("L: { try { 1; } finally { L2: { break L2; } } }")); +assertEquals( + 1, eval("while (true) { try { 1; break; } finally { L2: { break L2; } } }")); +assertEquals( + 1, + eval("while (true) { try { 1; break; } finally { L2: { break L2; } 2; } }")); +assertEquals(undefined, eval("while (true) { try { 1; } finally { break; } }")); diff --git a/deps/v8/test/mjsunit/es6/regress-static-field-await-identifier.js b/deps/v8/test/mjsunit/es6/regress-static-field-await-identifier.js new file mode 100644 index 000000000000..655bd1b48c2f --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-static-field-await-identifier.js @@ -0,0 +1,56 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Per ECMA-262, FieldDefinition (`[Yield, ~Await]`) does not have the +// `[+Await]` grammar parameter, unlike ClassStaticBlockBody (`[~Yield, +Await]`). +// In Script mode outside async functions and static blocks, `await` is a +// valid identifier in static class field initializers. + +var await = 42; + +class C1 { + static x = await; + static f = (await) => await; + static g = ({await = 10} = {}) => await; +} +assertEquals(42, C1.x); +assertEquals(7, C1.f(7)); +assertEquals(10, C1.g()); + +class C2 { + instanceField = 1; + static x = await; + static f = (await) => await; + static g = ({await = 10} = {}) => await; +} +assertEquals(42, C2.x); +assertEquals(7, C2.f(7)); +assertEquals(10, C2.g()); + +// Inside a `static {}` block, `await` is disallowed as an identifier. +assertThrows( + () => eval("class C { static { await; } }"), + SyntaxError, + "Unexpected reserved word"); +assertThrows( + () => eval("class C { static { (await) => {}; } }"), + SyntaxError, + "Unexpected reserved word"); +assertThrows( + () => eval("class C { static { ({await} = {}); } }"), + SyntaxError, + "Unexpected reserved word"); +assertThrows( + () => eval("class C { static { ({await = 1} = {}); } }"), + SyntaxError, + "Unexpected reserved word"); +assertThrows( + () => eval("class C { static { class D { [await] = 1; } } }"), + SyntaxError, + "Unexpected reserved word"); + +assertThrows( + () => eval("async ({await = 1}) => {}"), + SyntaxError, + "'await' is not a valid identifier name in an async function"); diff --git a/deps/v8/test/mjsunit/es6/regress-strict-eval-destructuring-subpattern.js b/deps/v8/test/mjsunit/es6/regress-strict-eval-destructuring-subpattern.js new file mode 100644 index 000000000000..578b32e1aca1 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-strict-eval-destructuring-subpattern.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// In strict mode, `eval` and `arguments` in destructuring sub-patterns and +// object rest properties must report `kStrictEvalArguments` rather than +// generic destructuring target errors. + +const cases = [ + '"use strict"; [eval] = [];', + '"use strict"; [arguments] = [];', + '"use strict"; [...eval] = [];', + '"use strict"; let [eval] = [];', + '"use strict"; let [...eval] = [];', + '"use strict"; ({a: eval} = {});', + '"use strict"; ({a: arguments} = {});', + '"use strict"; let {a: eval} = {};', + '"use strict"; ({...eval} = {});', + '"use strict"; ({...arguments} = {});', + '"use strict"; let {...eval} = {};', + '"use strict"; ([eval]) => {};', + '"use strict"; ({a: eval}) => {};', + '"use strict"; ({...eval}) => {};', + '"use strict"; function f([eval]) {}', + '"use strict"; function f({a: eval}) {}', + '"use strict"; function f({...eval}) {}', +]; + +for (const code of cases) { + assertThrows( + () => eval(code), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +} diff --git a/deps/v8/test/mjsunit/es6/regress-strict-octal-after-rbrace.js b/deps/v8/test/mjsunit/es6/regress-strict-octal-after-rbrace.js new file mode 100644 index 000000000000..96ca1e8650d8 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-strict-octal-after-rbrace.js @@ -0,0 +1,57 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Strict-mode octal literals and octal escape sequences inside a class or +// function body must be rejected even when the token immediately after the +// closing `}` in an outer sloppy scope is an octal literal or escape, or +// when a lazy function or arrow function has a later declaration conflict. + +assertThrows( + () => eval("class C { static x = 010; }\n020;"), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval("class C { static { 010; } }\n020;"), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval("class C { x = 010; }\n020;"), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval('class C { static x = "\\01"; }\n020;'), + SyntaxError, + "Octal escape sequences are not allowed in strict mode."); +assertThrows( + () => eval('!function() { "use strict"; return 010; }\n020;'), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval('!function() { "use strict"; return "\\01"; }\n020;'), + SyntaxError, + "Octal escape sequences are not allowed in strict mode."); +assertThrows( + () => eval('function f() { "use strict"; return 010; }\n020;'), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval('function outer() { function f() { "use strict"; return 010; }\n020; }'), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval('function outer() { () => { "use strict"; return 010; }\n020; }'), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval('(() => { "use strict"; return 010; })\n020;'), + SyntaxError, + "Octal literals are not allowed in strict mode."); +assertThrows( + () => eval('() => { "\\01"; "use strict"; var x; let x; }'), + SyntaxError, + "Octal escape sequences are not allowed in strict mode."); +assertThrows( + () => eval('function f() { "\\01"; "use strict"; { let x; { var x; } } }'), + SyntaxError, + "Octal escape sequences are not allowed in strict mode."); diff --git a/deps/v8/test/mjsunit/es6/regress-strict-param-error-order.js b/deps/v8/test/mjsunit/es6/regress-strict-param-error-order.js new file mode 100644 index 000000000000..ca6c794d29b7 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-strict-param-error-order.js @@ -0,0 +1,32 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Strict mode parameter errors and arrow declaration errors should report +// the first error encountered in the parameter list rather than overwriting +// it with later errors. + +assertThrows( + () => eval('(function f(implements, eval) { "use strict"; })'), + SyntaxError, + "Unexpected strict mode reserved word"); +assertThrows( + () => eval('(implements, eval) => { "use strict"; }'), + SyntaxError, + "Unexpected strict mode reserved word"); +assertThrows( + () => eval('(function f(eval, implements) { "use strict"; })'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval('(eval, implements) => { "use strict"; }'), + SyntaxError, + "Unexpected eval or arguments in strict mode"); +assertThrows( + () => eval("([a.b], 1) => {}"), + SyntaxError, + "Illegal property in declaration context"); +assertThrows( + () => eval("function* g() { (b = yield a, 1) => {}; }"), + SyntaxError, + "Yield expression not allowed in formal parameter"); diff --git a/deps/v8/test/mjsunit/es6/regress-subpattern-validate-expression.js b/deps/v8/test/mjsunit/es6/regress-subpattern-validate-expression.js new file mode 100644 index 000000000000..1168e9e569a4 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-subpattern-validate-expression.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Non-pattern expressions inside destructuring patterns or arrow parameter +// lists must validate inner expression errors before recording pattern or +// parameter declaration errors. + +assertThrows( + () => eval("[{a = 42}.f()] = []"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[!{a = 42}] = []"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[{a = 42} + 1] = []"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[{a = 42} ? 1 : 2] = []"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("[{a = 42}?.b] = []"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({x: {a = 42} + 1} = {})"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({a = 42}.b) => {}"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("({a = 42} + 1) => {}"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("(!{a = 42}) => {}"), + SyntaxError, + "Invalid shorthand property initializer"); diff --git a/deps/v8/test/mjsunit/es6/regress-super-optional-chain.js b/deps/v8/test/mjsunit/es6/regress-super-optional-chain.js new file mode 100644 index 000000000000..0e84951b368a --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-super-optional-chain.js @@ -0,0 +1,18 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Optional chaining on `super` should report `kOptionalChainingNoSuper`. + +assertThrows( + () => eval("class A { m() { return super?.x; } }"), + SyntaxError, + "Invalid optional chain from super property"); +assertThrows( + () => eval("class A { m() { return super?.['x']; } }"), + SyntaxError, + "Invalid optional chain from super property"); +assertThrows( + () => eval("class A extends Object { constructor() { super?.(); } }"), + SyntaxError, + "Invalid optional chain from super property"); diff --git a/deps/v8/test/mjsunit/es6/regress-yield-expression-scope.js b/deps/v8/test/mjsunit/es6/regress-yield-expression-scope.js new file mode 100644 index 000000000000..22efcaa4211e --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress-yield-expression-scope.js @@ -0,0 +1,19 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// YieldExpression operands are unconditionally AssignmentExpressions and +// should validate expression errors before outer pattern validation. + +assertThrows( + () => eval("function* g() { [yield {a = 42}] = []; }"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("function* g() { [yield* {a = 42}] = []; }"), + SyntaxError, + "Invalid shorthand property initializer"); +assertThrows( + () => eval("function* g() { ({x: yield {a = 42}} = {}); }"), + SyntaxError, + "Invalid shorthand property initializer"); diff --git a/deps/v8/test/mjsunit/es8/regress-async-arrow-scope-and-new.js b/deps/v8/test/mjsunit/es8/regress-async-arrow-scope-and-new.js new file mode 100644 index 000000000000..7a590195df32 --- /dev/null +++ b/deps/v8/test/mjsunit/es8/regress-async-arrow-scope-and-new.js @@ -0,0 +1,70 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that parenthesized async arrow functions parse cleanly in both lazy and +// eager closures when an outer `let async` binding is present. +function makeLazyClosure() { + let async = {}; + let fn = () => { + let a = async () => 42; + let b = (async (x) => x); + return [a, b]; + }; + return { fn }; +} + +let lazy = makeLazyClosure(); +assertEquals(2, lazy.fn().length); + +let eager = (() => { + let async = {}; + let fn = (() => { + let a = async () => 42; + let b = (async (x) => x); + return () => [a, b]; + })(); + return { fn }; +})(); +assertEquals(2, eager.fn().length); + +// Test Scope::Snapshot and Reparent when an arrow parameter list calls sloppy +// eval inside a block scope or alongside an outer sloppy eval. +(function TestArrowParamEvalInBlockScope() { + let outer_var = 10; + function f() { + { + let a = (x = eval("var y = 20")) => [x, y]; + assertEquals([undefined, 20], a()); + } + let b = (z = (1)) => outer_var + z; + assertEquals(11, b()); + } + f(); + + function g() { + let async = 10; + return (function() { + { + let a = async (x = eval("var async = 20")) => async; + } + return async; + })(); + } + assertEquals(10, g()); + + function h() { + eval("var v = 42"); + { + let a = (y = 1) => y; + assertEquals(1, a()); + } + return v; + } + assertEquals(42, h()); +})(); + +// Test that invalid async arrow heads with `new` or parentheses throw +// SyntaxError. +assertThrows("new async()() => {}", SyntaxError); +assertThrows("(async)() => {}", SyntaxError); diff --git a/deps/v8/test/mjsunit/es8/regress-lazy-arrow-formal-params-function-state.js b/deps/v8/test/mjsunit/es8/regress-lazy-arrow-formal-params-function-state.js new file mode 100644 index 000000000000..e0bbf9bbeacc --- /dev/null +++ b/deps/v8/test/mjsunit/es8/regress-lazy-arrow-formal-params-function-state.js @@ -0,0 +1,67 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var await = 10; +var yield = 20; + +// Case 1: 'await' as binding identifier in lazy arrow formal parameters inside +// a contextless sync function nested in an async function. +(function TestAwaitBindingIdentifierInAsyncOuter() { + async function outer() { + let ctx; + () => ctx; + function sync_inner() { + let f = await => await; + return f(42); + } + return sync_inner(); + } + assertPromiseResult(outer(), v => assertEquals(42, v)); +})(); + +// Case 2: 'await' in default parameter initializer of lazy arrow function +// inside a contextless sync function nested in an async function. +(function TestAwaitDefaultParamInAsyncOuter() { + async function outer() { + let ctx; + () => ctx; + function sync_inner() { + let f = (a = await / 2) => a; + return f(); + } + return sync_inner(); + } + assertPromiseResult(outer(), v => assertEquals(5, v)); +})(); + +// Case 3: 'yield' in default parameter initializer of lazy arrow function +// inside a contextless sync function nested in a generator function. +(function TestYieldDefaultParamInGeneratorOuter() { + function* outer() { + let ctx = 1; + () => ctx; + function sync_inner() { + let f = (a = yield) => { return a; }; + return f(); + } + return sync_inner(); + } + assertEquals({value: 20, done: true}, outer().next()); +})(); + +// Case 4: Both 'await' and 'yield' in lazy arrow formal parameters inside +// a contextless sync function nested in an async generator function. +(function TestAwaitAndYieldInAsyncGeneratorOuter() { + async function* outer() { + let ctx = 1; + () => ctx; + function sync_inner() { + let f1 = await => await; + let f2 = (a = await / 2, b = yield) => a + b; + return f1(10) + f2(); + } + return sync_inner(); + } + assertPromiseResult(outer().next(), v => assertEquals({value: 35, done: true}, v)); +})(); diff --git a/deps/v8/test/mjsunit/harmony/modules-import-defer-stack-trace.js b/deps/v8/test/mjsunit/harmony/modules-import-defer-stack-trace.js new file mode 100644 index 000000000000..2debb508a6b2 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/modules-import-defer-stack-trace.js @@ -0,0 +1,171 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Flags: --js-defer-import-eval --bundle --allow-natives-syntax --turbofan + +// An exception thrown while a deferred module is evaluated synchronously must +// produce a stack trace that contains the frames of the deferred module body +// followed by the frames of the code whose namespace access triggered the +// evaluation, all with correct source positions. + +// JS_BUNDLE_MODULE:get.mjs +function thrower() { + throw new Error('get'); +} +thrower(); +export const foo = 42; + +// JS_BUNDLE_MODULE:has.mjs +throw new Error('has'); +export const foo = 42; + +// JS_BUNDLE_MODULE:keys.mjs +throw new Error('keys'); +export const foo = 42; + +// JS_BUNDLE_MODULE:for-in.mjs +throw new Error('for-in'); +export const foo = 42; + +// JS_BUNDLE_MODULE:warm.mjs +export const foo = 42; + +// JS_BUNDLE_MODULE:optimized.mjs +throw new Error('optimized'); +export const foo = 42; + +// JS_BUNDLE_MODULE:async.mjs +throw new Error('async'); +export const foo = 42; + +// JS_BUNDLE_MODULE:structured.mjs +throw new Error('structured'); +export const foo = 42; + +// JS_BUNDLE_MODULE_ENTRYPOINT:entry.mjs +import defer * as get from 'get.mjs'; +import defer * as has from 'has.mjs'; +import defer * as keys from 'keys.mjs'; +import defer * as forIn from 'for-in.mjs'; +import defer * as warm from 'warm.mjs'; +import defer * as optimized from 'optimized.mjs'; +import defer * as asyncNs from 'async.mjs'; +import defer * as structured from 'structured.mjs'; + +// Returns the frames of `e.stack`, without the directory part of file names. +function stackOf(e) { + return e.stack.split('\n').slice(1).map( + line => line.trim().replace(/[^ (]*\//, '')); +} + +// [[Get]] from a function, with a function call inside the module body. +function readGet() { + return get.foo; +} +let getError; +try { readGet(); } catch (e) { getError = e; } +assertEquals([ + 'at thrower (get.mjs:2:9)', + 'at get.mjs:4:1', + 'at readGet (entry.mjs:18:14)', + 'at entry.mjs:21:7', +], stackOf(getError)); + +// A second access rethrows the same error, keeping the original stack. +try { readGet(); } catch (e) { assertSame(getError, e); } +assertEquals([ + 'at thrower (get.mjs:2:9)', + 'at get.mjs:4:1', + 'at readGet (entry.mjs:18:14)', + 'at entry.mjs:21:7', +], stackOf(getError)); + +// [[HasProperty]]. +let hasError; +try { 'foo' in has; } catch (e) { hasError = e; } +assertEquals([ + 'at has.mjs:1:7', + 'at entry.mjs:40:13', +], stackOf(hasError)); + +// [[OwnPropertyKeys]], through a builtin. +let keysError; +try { Object.keys(keys); } catch (e) { keysError = e; } +assertEquals([ + 'at keys.mjs:1:7', + 'at Object.keys (<anonymous>)', + 'at entry.mjs:48:14', +], stackOf(keysError)); + +// for-in enumeration. +let forInError; +try { for (const k in forIn) {} } catch (e) { forInError = e; } +assertEquals([ + 'at for-in.mjs:1:7', + 'at entry.mjs:57:23', +], stackOf(forInError)); + +// [[Get]] from optimized code. The load is megamorphic, so the optimized code +// reaches the evaluation through the IC instead of deoptimizing first. +function readOptimized(ns) { + return ns.foo; +} +%PrepareFunctionForOptimization(readOptimized); +for (let i = 0; i < 3; i++) { + readOptimized(warm); + readOptimized({foo: 1}); + readOptimized({a: 1, foo: 1}); + readOptimized({b: 1, foo: 1}); + readOptimized({c: 1, foo: 1}); + readOptimized({d: 1, foo: 1}); +} +%OptimizeFunctionOnNextCall(readOptimized); +readOptimized(warm); +assertOptimized(readOptimized); +let optimizedError; +try { readOptimized(optimized); } catch (e) { optimizedError = e; } +assertEquals([ + 'at optimized.mjs:1:7', + 'at readOptimized (entry.mjs:66:13)', + 'at entry.mjs:81:7', +], stackOf(optimizedError)); +assertOptimized(readOptimized); + +// [[Get]] after an await, with async callers. +async function inner() { + await 0; + return asyncNs.foo; +} +async function outer() { + await inner(); +} +let asyncError; +try { await outer(); } catch (e) { asyncError = e; } +assertEquals([ + 'at async.mjs:1:7', + 'at inner (entry.mjs:92:18)', + 'at async outer (entry.mjs:95:3)', + 'at async entry.mjs:98:7', +], stackOf(asyncError)); + +// Structured call sites. +Error.prepareStackTrace = (e, frames) => frames; +let structuredError; +try { structured.foo; } catch (e) { structuredError = e; } +// Formatting is lazy, so read the stack before restoring the default. +const frames = structuredError.stack; +Error.prepareStackTrace = undefined; +assertEquals(2, frames.length); +const [moduleFrame, accessFrame] = frames; + +assertNull(moduleFrame.getFunctionName()); +assertTrue(moduleFrame.getFileName().endsWith('structured.mjs')); +assertEquals(1, moduleFrame.getLineNumber()); +assertEquals(7, moduleFrame.getColumnNumber()); +assertTrue(moduleFrame.isToplevel()); + +assertNull(accessFrame.getFunctionName()); +assertTrue(accessFrame.getFileName().endsWith('entry.mjs')); +assertEquals(109, accessFrame.getLineNumber()); +assertEquals(18, accessFrame.getColumnNumber()); +assertTrue(accessFrame.isToplevel()); diff --git a/deps/v8/test/mjsunit/harmony/modules-import-defer-terminate.mjs b/deps/v8/test/mjsunit/harmony/modules-import-defer-terminate.mjs new file mode 100644 index 000000000000..9fdce33a5a50 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/modules-import-defer-terminate.mjs @@ -0,0 +1,15 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval + +// Dynamic import() starts evaluating the top-level-await module so it enters +// kEvaluatingAsync. In the same microtask checkpoint, the d8.terminate +// reaction requests termination right before the import.defer() task calls +// Module::EvaluateForImportDefer -> JSPromise::PerformPromiseAll, where the +// perform_promise_then entry stack check throws the termination exception. +const url = 'data:text/javascript,await 0'; +import(url); +Promise.resolve().then(d8.terminate); +import.defer(url); diff --git a/deps/v8/test/mjsunit/harmony/modules-using-export.mjs b/deps/v8/test/mjsunit/harmony/modules-using-export.mjs new file mode 100644 index 000000000000..efdd4ab89bda --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/modules-using-export.mjs @@ -0,0 +1,97 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// MODULE +// Flags: --allow-natives-syntax + +// 1. Exported `using` bindings are disposed in reverse declaration order at the +// end of synchronous module evaluation. +globalThis.syncLog = []; +const syncNs = await import(`data:text/javascript, + using x = { + val: 10, + [Symbol.dispose]() { globalThis.syncLog.push('dispose x'); } + }; + using y = { + val: 20, + [Symbol.dispose]() { globalThis.syncLog.push('dispose y'); } + }; + globalThis.syncLog.push('sync body'); + export { x, y }; +`); +assertEquals(['sync body', 'dispose y', 'dispose x'], globalThis.syncLog); +assertEquals(10, syncNs.x.val); +assertEquals(20, syncNs.y.val); + +// 2. Exported `using` and `await using` bindings are disposed in reverse +// declaration order at the end of asynchronous module evaluation. +globalThis.asyncLog = []; +const asyncNs = await import(`data:text/javascript, + using a = { + val: 1, + [Symbol.dispose]() { globalThis.asyncLog.push('dispose a'); } + }; + await using b = { + val: 2, + async [Symbol.asyncDispose]() { globalThis.asyncLog.push('asyncDispose b'); } + }; + using c = { + val: 3, + [Symbol.dispose]() { globalThis.asyncLog.push('dispose c'); } + }; + globalThis.asyncLog.push('async body'); + export { a, b, c }; +`); +assertEquals( + ['async body', 'dispose c', 'asyncDispose b', 'dispose a'], + globalThis.asyncLog); +assertEquals(1, asyncNs.a.val); +assertEquals(2, asyncNs.b.val); +assertEquals(3, asyncNs.c.val); + +// 3. Exported `using` bindings are disposed when module evaluation throws. +globalThis.throwLog = []; +await assertThrowsAsync( + import(`data:text/javascript, + using x = { + [Symbol.dispose]() { globalThis.throwLog.push('dispose x on throw'); } + }; + throw new Error('boom'); + export { x }; + `), + Error, 'boom'); +assertEquals(['dispose x on throw'], globalThis.throwLog); + +// 4. Non-disposable values in exported `using` and `await using` declarations +// reject with TypeError. +await assertThrowsAsync( + import('data:text/javascript,using x = 42; export { x };'), TypeError); +await assertThrowsAsync( + import('data:text/javascript,await using x = 42; export { x };'), + TypeError); + +// 5. Reassigning exported `using` or `await using` bindings rejects with +// TypeError. +await assertThrowsAsync( + import('data:text/javascript,using x = null; x = 1; export { x };'), + TypeError); +await assertThrowsAsync( + import('data:text/javascript,await using x = null; x = 1; export { x };'), + TypeError); + +// 6. REPL_GLOBAL `using` and `await using` bindings forbid reassignment. +await assertThrowsAsync( + %RuntimeEvaluateREPL('using repl_assign = null; repl_assign = 1;'), + TypeError); +await assertThrowsAsync( + %RuntimeEvaluateREPL( + 'await using repl_await_assign = null; repl_await_assign = 1;'), + TypeError); + +using topLevelExported = { + value: 123, + [Symbol.dispose]() {} +}; +export { topLevelExported }; +assertEquals(123, topLevelExported.value); diff --git a/deps/v8/test/mjsunit/harmony/optional-chaining-this-private.js b/deps/v8/test/mjsunit/harmony/optional-chaining-this-private.js index 2a708a6a94b9..84cd6c697d68 100644 --- a/deps/v8/test/mjsunit/harmony/optional-chaining-this-private.js +++ b/deps/v8/test/mjsunit/harmony/optional-chaining-this-private.js @@ -5,6 +5,7 @@ class C { static #c = C; static #m() { return this; } + static get #g() { return this.#m; } static test(C) { assertEquals(C?.#m(), C); assertEquals((C?.#m)(), C); @@ -15,6 +16,17 @@ class C { assertEquals((C?.#m)(42), C); assertEquals(C?.#c?.#m(42), C); assertEquals((C?.#c?.#m)(42), C); + + assertEquals(C?.#g(), C); + assertEquals((C?.#g)(), C); + assertEquals(C?.#c?.#g(), C); + assertEquals((C?.#c?.#g)(), C); + + assertEquals(C?.#g(42), C); + assertEquals((C?.#g)(42), C); + assertEquals(C?.#c?.#g(42), C); + assertEquals((C?.#c?.#g)(42), C); + assertEquals((C?.#g)(1, ...[2], 3), C); } } diff --git a/deps/v8/test/mjsunit/harmony/regexp-unicode-sets-class-string-disjunction.js b/deps/v8/test/mjsunit/harmony/regexp-unicode-sets-class-string-disjunction.js new file mode 100644 index 000000000000..5ead3f16d0e8 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regexp-unicode-sets-class-string-disjunction.js @@ -0,0 +1,94 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Case-equivalence closure for single-character strings in \q{...} with /vi. +assertTrue(/^[\q{a}]$/vi.test('a')); +assertTrue(/^[\q{a}]$/vi.test('A')); +assertTrue(/^[\q{A}]$/vi.test('a')); +assertTrue(/^[\q{A}]$/vi.test('A')); + +// Mixed single-character and multi-character strings in \q{...} with /vi. +assertTrue(/^[\q{a|bc}]$/vi.test('a')); +assertTrue(/^[\q{a|bc}]$/vi.test('A')); +assertTrue(/^[\q{a|bc}]$/vi.test('bc')); +assertTrue(/^[\q{a|bc}]$/vi.test('BC')); +assertTrue(/^[\q{a|bc}]$/vi.test('Bc')); +assertTrue(/^[\q{A|BC}]$/vi.test('a')); +assertTrue(/^[\q{A|BC}]$/vi.test('A')); +assertTrue(/^[\q{A|BC}]$/vi.test('bc')); +assertTrue(/^[\q{a|}]$/vi.test('A')); +assertTrue(/^[\q{a|}]$/vi.test('')); + +// Set operations (intersection, subtraction, complement) with single-character +// \q{...} and /vi. +assertTrue(/^[\q{a}&&[A]]$/vi.test('A')); +assertTrue(/^[\q{a}&&[A]]$/vi.test('a')); +assertTrue(/^[\q{A}&&[a]]$/vi.test('A')); +assertTrue(/^[\q{A}&&[a]]$/vi.test('a')); +assertTrue(/^[\q{a}&&\q{A}]$/vi.test('A')); +assertTrue(/^[\q{a}&&\q{A}]$/vi.test('a')); +assertTrue(/^[\q{a|bc}&&[A]]$/vi.test('A')); +assertFalse(/^[\q{a|bc}&&[A]]$/vi.test('bc')); + +assertFalse(/^[[A]--\q{a}]$/vi.test('A')); +assertFalse(/^[[A]--\q{a}]$/vi.test('a')); +assertFalse(/^[[a]--\q{A}]$/vi.test('A')); +assertFalse(/^[[a]--\q{A}]$/vi.test('a')); +assertFalse(/^[[a-c]--\q{B}]$/vi.test('b')); +assertFalse(/^[[a-c]--\q{B}]$/vi.test('B')); +assertTrue(/^[[a-c]--\q{B}]$/vi.test('A')); +assertTrue(/^[[a-c]--\q{B}]$/vi.test('C')); +assertFalse(/^[\q{a|b}--[A]]$/vi.test('A')); +assertFalse(/^[\q{a|b}--[A]]$/vi.test('a')); +assertTrue(/^[\q{a|b}--[A]]$/vi.test('B')); + +assertFalse(/^[^\q{a}]$/vi.test('A')); +assertFalse(/^[^\q{a}]$/vi.test('a')); +assertFalse(/^[^\q{A}]$/vi.test('a')); +assertFalse(/^[^\q{A}]$/vi.test('A')); +assertTrue(/^[^\q{a}]$/vi.test('B')); + +// Non-ASCII Unicode simple case folding in single-character \q{...} with /vi. +// U+212A KELVIN SIGN <-> 'k', 'K' +assertTrue(/^[\q{k}]$/vi.test('\u212A')); +assertTrue(/^[\q{K}]$/vi.test('\u212A')); +assertTrue(/^[\q{\u212A}]$/vi.test('k')); +assertTrue(/^[\q{\u212A}]$/vi.test('K')); +assertFalse(/^[[K]--\q{\u212A}]$/vi.test('k')); +assertFalse(/^[[K]--\q{\u212A}]$/vi.test('K')); +assertFalse(/^[[K]--\q{\u212A}]$/vi.test('\u212A')); + +// U+017F LATIN SMALL LETTER LONG S <-> 's', 'S' +assertTrue(/^[\q{\u017F}]$/vi.test('s')); +assertTrue(/^[\q{\u017F}]$/vi.test('S')); +assertTrue(/^[\q{s}]$/vi.test('\u017F')); +assertTrue(/^[\q{S}]$/vi.test('\u017F')); + +// U+00B5 MICRO SIGN <-> U+03BC GREEK SMALL LETTER MU, U+039C GREEK CAPITAL LETTER MU +assertTrue(/^[\q{\u00B5}]$/vi.test('\u03BC')); +assertTrue(/^[\q{\u00B5}]$/vi.test('\u039C')); + +// Non-BMP (supplementary) case folding: Deseret U+10400 <-> U+10428 +assertTrue(/^[\q{\u{10400}}]$/vi.test('\u{10428}')); +assertTrue(/^[\q{\u{10428}}]$/vi.test('\u{10400}')); +assertFalse(/^[\q{\u{10400}}--\q{\u{10428}}]$/vi.test('\u{10400}')); +assertFalse(/^[\q{\u{10400}}--\q{\u{10428}}]$/vi.test('\u{10428}')); + +// Isolated escaped surrogates in \q{...} must not combine into a single astral +// code point. +assertFalse(/^[\q{\u{D800}\u{DC00}}]$/v.test('\u{10000}')); +assertFalse(/^[\q{\uD800\u{DC00}}]$/v.test('\u{10000}')); +assertFalse(/^[\q{\u{D800}\uDC00}]$/v.test('\u{10000}')); +assertFalse(/^[\q{\u{D800}\u{DC00}}]$/vi.test('\u{10000}')); + +assertThrows('/^[^\\q{\\u{D800}\\u{DC00}}]$/v', SyntaxError); +assertThrows('/^[^\\q{\\uD800\\u{DC00}}]$/v', SyntaxError); +assertThrows('/^[^\\q{\\u{D800}\\uDC00}]$/v', SyntaxError); + +// 4-hex-digit surrogate pairs and single astral code point escapes in \q{...} +// are single code points. +assertTrue(/^[\q{\uD800\uDC00}]$/v.test('\u{10000}')); +assertTrue(/^[\q{\u{10000}}]$/v.test('\u{10000}')); +assertFalse(/^[^\q{\uD800\uDC00}]$/v.test('\u{10000}')); +assertFalse(/^[^\q{\u{10000}}]$/v.test('\u{10000}')); diff --git a/deps/v8/test/mjsunit/harmony/regress-auto-accessor-tostring.js b/deps/v8/test/mjsunit/harmony/regress-auto-accessor-tostring.js new file mode 100644 index 000000000000..e08674818ec8 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress-auto-accessor-tostring.js @@ -0,0 +1,69 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-decorators + +// Top-level (eager) class with instance, static, and computed auto-accessors. +class TopLevelClass { + accessor x = 1; + static accessor y = 2; + accessor ['z'] = 3; +} + +const topX = Object.getOwnPropertyDescriptor(TopLevelClass.prototype, 'x'); +assertEquals('function get x() { [native code] }', topX.get.toString()); +assertEquals('function set x() { [native code] }', topX.set.toString()); + +const topY = Object.getOwnPropertyDescriptor(TopLevelClass, 'y'); +assertEquals('function get y() { [native code] }', topY.get.toString()); +assertEquals('function set y() { [native code] }', topY.set.toString()); + +const topZ = Object.getOwnPropertyDescriptor(TopLevelClass.prototype, 'z'); +assertEquals('function () { [native code] }', topZ.get.toString()); +assertEquals('function () { [native code] }', topZ.set.toString()); + +// Lazy function containing classes (base and derived) with auto-accessors. +function testLazy() { + class Base { + accessor a = 10; + static accessor b = 20; + } + + class Derived extends Base { + accessor c = 30; + static accessor d = 40; + } + + const descA = Object.getOwnPropertyDescriptor(Base.prototype, 'a'); + assertEquals('function get a() { [native code] }', descA.get.toString()); + assertEquals('function set a() { [native code] }', descA.set.toString()); + + const descB = Object.getOwnPropertyDescriptor(Base, 'b'); + assertEquals('function get b() { [native code] }', descB.get.toString()); + assertEquals('function set b() { [native code] }', descB.set.toString()); + + const descC = Object.getOwnPropertyDescriptor(Derived.prototype, 'c'); + assertEquals('function get c() { [native code] }', descC.get.toString()); + assertEquals('function set c() { [native code] }', descC.set.toString()); + + const descD = Object.getOwnPropertyDescriptor(Derived, 'd'); + assertEquals('function get d() { [native code] }', descD.get.toString()); + assertEquals('function set d() { [native code] }', descD.set.toString()); + + const inst = new Derived(); + assertEquals(10, inst.a); + assertEquals(30, inst.c); + inst.a = 11; + inst.c = 31; + assertEquals(11, inst.a); + assertEquals(31, inst.c); + assertEquals(20, Base.b); + assertEquals(40, Derived.d); + Base.b = 21; + Derived.d = 41; + assertEquals(21, Base.b); + assertEquals(41, Derived.d); +} + +testLazy(); diff --git a/deps/v8/test/mjsunit/harmony/regress-class-reparse-no-lazy-and-brand-check-pos.js b/deps/v8/test/mjsunit/harmony/regress-class-reparse-no-lazy-and-brand-check-pos.js new file mode 100644 index 000000000000..89535ff10c11 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress-class-reparse-no-lazy-and-brand-check-pos.js @@ -0,0 +1,70 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-lazy + +// Reparsing class member initializers when collecting source positions or +// rendering call sites with --no-lazy. +class C1 { + m() {} + x = new Error().stack; +} +assertEquals('string', typeof new C1().x); + +class C2 { + static m() {} + static x = new Error().stack; +} +assertEquals('string', typeof C2.x); + +assertThrows(() => { + class C3 { + m() {} + x = null.prop; + } + new C3(); +}, TypeError); + +// Private brand check (#x in o) should not push #x onto FuncNameInferrer. +class C4 { + #x; + static testLogical(o) { + #x in o || (o.prop = function() { return new Error().stack; }); + return o.prop(); + } + static testComma(o) { + #x in (o.prop = function() { return new Error().stack; }, o); + return o.prop(); + } +} + +const stack1 = C4.testLogical({}); +assertFalse(stack1.includes('#x')); + +const stack2 = C4.testComma({}); +assertFalse(stack2.includes('#x')); + +// Private brand check (#y in o) with an undeclared private name should report +// the SyntaxError at the position of #y, not the preceding token. +if (typeof Worker !== 'undefined') { + const w1 = new Worker(function() { + globalThis.onerror = function(msg, source, lineno, colno) { + postMessage([lineno, colno]); + return true; + }; + eval('class C { m(o) {\n return\n #y in o;\n} }'); + }, {type: 'function'}); + assertEquals([3, 3], w1.getMessage()); + w1.terminate(); + + const w2 = new Worker(function() { + globalThis.onerror = function(msg, source, lineno, colno) { + postMessage([lineno, colno]); + return true; + }; + eval('1;\n #y in o;'); + }, {type: 'function'}); + assertEquals([2, 3], w2.getMessage()); + w2.terminate(); +} diff --git a/deps/v8/test/mjsunit/harmony/regress-for-using-closure-assignment.js b/deps/v8/test/mjsunit/harmony/regress-for-using-closure-assignment.js new file mode 100644 index 000000000000..2bee11d68e5a --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress-for-using-closure-assignment.js @@ -0,0 +1,72 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function testLazyUsingUnusedClosure() { + for (using x = null; ;) { + () => {}; + x = 1; + } +} +assertThrows( + testLazyUsingUnusedClosure, TypeError, 'Assignment to using variable.'); + +function testLazyUsingCapturingClosure() { + for (using x = null; ;) { + () => x; + x = 1; + } +} +assertThrows( + testLazyUsingCapturingClosure, TypeError, 'Assignment to using variable.'); + +assertThrows(() => { + for (using x = null; ;) { + () => {}; + x = 1; + } +}, TypeError, 'Assignment to using variable.'); + +assertThrows(() => { + for (using x = { [Symbol.dispose]() {} }; ;) { + x = 1; + } +}, TypeError, 'Assignment to using variable.'); + +async function testLazyAwaitUsingUnusedClosure() { + for (await using x = null; ;) { + () => {}; + x = 1; + } +} + +async function testLazyAwaitUsingCapturingClosure() { + for (await using x = null; ;) { + () => x; + x = 1; + } +} + +function testLazyConstCapturingClosure() { + for (const x = 1; ;) { + () => x; + x = 2; + } +} +assertThrows( + testLazyConstCapturingClosure, TypeError, 'Assignment to constant variable.'); + +assertThrowsAsync( + testLazyAwaitUsingUnusedClosure(), TypeError, + 'Assignment to await using variable.'); +assertThrowsAsync( + testLazyAwaitUsingCapturingClosure(), TypeError, + 'Assignment to await using variable.'); +assertThrowsAsync( + (async () => { + for (await using x = null; ;) { + () => {}; + x = 1; + } + })(), + TypeError, 'Assignment to await using variable.'); diff --git a/deps/v8/test/mjsunit/harmony/regress-private-name-heritage-catch-eval.js b/deps/v8/test/mjsunit/harmony/regress-private-name-heritage-catch-eval.js new file mode 100644 index 000000000000..5d27d38bb37d --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress-private-name-heritage-catch-eval.js @@ -0,0 +1,131 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test private name resolution in class heritage clauses across catch scopes +// and direct eval calls. + +class Outer { + #x = 'outer'; + + testCatchInHeritage() { + let f1, f2, evalRes; + class Inner extends (() => { + try { + throw null; + } catch (e) { + f1 = () => this.#x; + f2 = () => () => this.#x; + evalRes = eval('this.#x'); + } + return Object; + })() { + #x = 'inner'; + } + assertEquals('outer', f1()); + assertEquals('outer', f2()()); + assertEquals('outer', evalRes); + } + + testDirectEvalInHeritage() { + let res1, res2, bodyFn; + class D1 extends (res1 = eval('this.#x'), Object) { + [( + assertThrows(() => eval('this.#x'), TypeError), + bodyFn = (o) => eval('o.#x'), + 'prop' + )] = 1; + #x = 'D1'; + } + assertEquals('outer', res1); + assertEquals('D1', bodyFn(new D1())); + assertThrows(() => bodyFn(this), TypeError); + + class D2 extends (() => { + res2 = eval('this.#x'); + return Object; + })() { + #x = 'D2'; + } + assertEquals('outer', res2); + } + + testNestedEvalAndLazyFunctionsInHeritage() { + let nested1, nested2, lazyFn1, lazyFn2, lazyArrow1, lazyArrow2; + class D1 extends ( + nested1 = eval("eval('this.#x')"), + lazyFn1 = eval('(function() { return this.#x; })'), + lazyArrow1 = eval('(() => () => this.#x)()'), + Object + ) { + #x = 'D1'; + } + assertEquals('outer', nested1); + assertEquals('outer', lazyFn1.call(this)); + assertEquals('outer', lazyArrow1()); + + class D2 extends (() => { + nested2 = eval("eval('this.#x')"); + lazyFn2 = eval('(function() { return this.#x; })'); + lazyArrow2 = eval('(() => () => this.#x)()'); + return Object; + })() { + #x = 'D2'; + } + assertEquals('outer', nested2); + assertEquals('outer', lazyFn2.call(this)); + assertEquals('outer', lazyArrow2()); + } + + testContextlessClassInHeritage() { + let res1, res2; + class D extends ( + class { + static [res1 = eval('this.#x')] = 1; + }, + class extends (res2 = eval('this.#x'), Object) {}, + Object + ) { + #x = 'D'; + } + assertEquals('outer', res1); + assertEquals('outer', res2); + + let bodyFn; + class E { + #x = 'E'; + static [class extends (bodyFn = (o) => eval('o.#x'), Object) {}] = 1; + } + assertEquals('E', bodyFn(new E())); + assertThrows(() => bodyFn(this), TypeError); + } + + testArrowParamReparentInHeritage() { + class Middle { + #x = 'middle'; + run() { + let res; + class Inner extends (( + a = class { + #y = 1; + static [res = this.#x] = 2; + } + ) => { + () => a; + return Object; + })() { + #x = 'inner'; + } + return res; + } + } + assertEquals('middle', new Middle().run()); + } +} + +const outer = new Outer(); +outer.testCatchInHeritage(); +outer.testDirectEvalInHeritage(); +outer.testNestedEvalAndLazyFunctionsInHeritage(); +outer.testContextlessClassInHeritage(); +outer.testArrowParamReparentInHeritage(); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-511329274.js b/deps/v8/test/mjsunit/harmony/regress/regress-511329274.js index 984e6631ea38..8ec3564847ba 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-511329274.js +++ b/deps/v8/test/mjsunit/harmony/regress/regress-511329274.js @@ -42,12 +42,43 @@ const callIntoWasm = sr.evaluate(` globalThis[Symbol.toStringTag] = "RealmGlobal"; const bytes = new Uint8Array([ - 0x00,0x61,0x73,0x6d, 0x01,0x00,0x00,0x00, - 0x01,0x04,0x01,0x60,0x00,0x00, - 0x02,0x09,0x01,0x02,0x6a,0x73,0x02,0x63,0x62,0x00,0x00, - 0x03,0x02,0x01,0x00, - 0x07,0x07,0x01,0x03,0x72,0x75,0x6e,0x00,0x01, - 0x0a,0x06,0x01,0x04,0x00,0x10,0x00,0x0b + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x04, // section length 4 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x00, // return count 0 + + 0x02, // section kind: Import + 0x09, // section length 9 + 0x01, 0x02, // imports count 1: module name length: 2 + 0x6a, 0x73, // module name: js + 0x02, // field name length: 2 + 0x63, 0x62, // field name: cb + 0x00, 0x00, // kind or compact flag: function + // import #0 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 1 $run + + 0x07, // section kind: Export + 0x07, // section length 7 + 0x01, // exports count 1: export # 0 + 0x03, // field name length: 3 + 0x72, 0x75, 0x6e, // field name: run + 0x00, 0x01, // kind: function index: 1 + + 0x0a, // section kind: Code + 0x06, // section length 6 + 0x01, // functions count 1 + // function #1 $run + 0x04, // body size 4 + 0x00, // 0 entries in locals list + 0x10, 0x00, // call $js.cb + 0x0b, // end ]); const mod = new WebAssembly.Module(bytes); (function (cb) { diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-520728938.js b/deps/v8/test/mjsunit/harmony/regress/regress-520728938.js deleted file mode 100644 index d189e906db5d..000000000000 --- a/deps/v8/test/mjsunit/harmony/regress/regress-520728938.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --harmony-struct --allow-natives-syntax --no-lazy-feedback-allocation - -function f() { - return Atomics.Mutex.prototype; -} - -%PrepareFunctionForOptimization(f); -f(); -f(); -%OptimizeFunctionOnNextCall(f); -f(); -assertEquals(null, f()); diff --git a/deps/v8/test/mjsunit/harmony/shadowrealm-evaluate.js b/deps/v8/test/mjsunit/harmony/shadowrealm-evaluate.js index 828896342813..63b0796b33a8 100644 --- a/deps/v8/test/mjsunit/harmony/shadowrealm-evaluate.js +++ b/deps/v8/test/mjsunit/harmony/shadowrealm-evaluate.js @@ -7,7 +7,7 @@ var shadowRealm = new ShadowRealm(); // re-throwing with SyntaxError -assertThrows(() => shadowRealm.evaluate('...'), SyntaxError, 'Unexpected end of input') +assertThrows(() => shadowRealm.evaluate('...'), SyntaxError, "Unexpected token '...'") // builtin var wrapped = shadowRealm.evaluate('String.prototype.substring'); diff --git a/deps/v8/test/mjsunit/iterable-foreach.js b/deps/v8/test/mjsunit/iterable-foreach.js index 4ed6b155dba4..17c1cfc9e6d7 100644 --- a/deps/v8/test/mjsunit/iterable-foreach.js +++ b/deps/v8/test/mjsunit/iterable-foreach.js @@ -406,6 +406,107 @@ if (typeof Float16Array !== 'undefined') { assertEquals(i, 1); })(); +// JSArrayIterator with replaced prototype (crbug.com/566974983) +(function TestArrayIteratorPrototypeReplaced() { + let arr = [1, 2, 3]; + let it = arr.values(); + let done = false; + Object.setPrototypeOf(it, { + [Symbol.iterator]() { return this; }, + next() { + if (!done) { + done = true; + return { value: 99, done: false }; + } + return { value: undefined, done: true }; + } + }); + let result = []; + %IterableForEach(it, (val) => result.push(val)); + assertEquals([99], result); +})(); + +// Empty array iterator exhausted by IterableForEach (crbug.com/572143990) +(function TestEmptyArrayIteratorExhausted() { + let arr = []; + let it = arr.values(); + %IterableForEach(it, () => {}); + arr.push(1); + assertEquals({ value: undefined, done: true }, it.next()); +})(); + +// TypedArray fast path with patched ArrayIteratorPrototype.return (crbug.com/571926077) +(function TestTypedArrayFastPathPrototypeReturn() { + const ArrayIteratorPrototype = Object.getPrototypeOf([].values()); + const typedArrays = [ + [new Uint8Array([1, 2, 3]), {value: 2, done: false}], + [new Float64Array([1.5, 2.5]), {value: 2.5, done: false}], + ]; + if (typeof Float16Array !== 'undefined') { + typedArrays.push([new Float16Array([1.5, 2.5]), {value: 2.5, done: false}]); + } + for (const [ta, expectedNext] of typedArrays) { + let closed = false; + let nextResult; + ArrayIteratorPrototype.return = function() { + closed = true; + nextResult = this.next(); + return {}; + }; + try { + assertThrows(() => { + %IterableForEach(ta, () => { + throw new Error("stop"); + }); + }, Error); + } finally { + delete ArrayIteratorPrototype.return; + } + assertTrue(closed); + assertEquals(expectedNext, nextResult); + } +})(); + +// Cross-realm TypedArray with patched other-realm ArrayIteratorPrototype.return +(function TestCrossRealmTypedArrayPrototypeReturn() { + const realm = Realm.createAllowCrossRealmAccess(); + const ta = Realm.eval(realm, "new Uint8Array([10, 20, 30])"); + const OtherArrayIteratorPrototype = + Realm.eval(realm, "Object.getPrototypeOf([].values())"); + let closed = false; + let nextResult; + OtherArrayIteratorPrototype.return = function() { + closed = true; + nextResult = this.next(); + return {}; + }; + try { + assertThrows(() => { + %IterableForEach(ta, () => { + throw new Error("stop"); + }); + }, Error); + } finally { + delete OtherArrayIteratorPrototype.return; + } + assertTrue(closed); + assertEquals({value: 20, done: false}, nextResult); +})(); + +// Callback advances JSArrayIterator via it.next() and then throws +(function TestIteratorNextCalledBeforeThrow() { + let arr = [1, 2, 3, 4]; + let it = arr.values(); + assertThrows(() => { + %IterableForEach(it, (val) => { + assertEquals(1, val); + assertEquals({value: 2, done: false}, it.next()); + throw new Error("stop"); + }); + }, Error); + assertEquals({value: 3, done: false}, it.next()); +})(); + // Modified Array Iterator -> Slow path (function TestModifiedArrayIterator() { let result = []; diff --git a/deps/v8/test/mjsunit/loadic-transition-elements.js b/deps/v8/test/mjsunit/loadic-transition-elements.js index ebe8dc6c4f7b..4ed97832e70d 100644 --- a/deps/v8/test/mjsunit/loadic-transition-elements.js +++ b/deps/v8/test/mjsunit/loadic-transition-elements.js @@ -39,3 +39,107 @@ if (hasMementos) { // Loading the element updated the elements kind. assertTrue(%HasDoubleElements(smiArray2)); } + +// Simple map-change transitions (sharing the same backing store representation) +// must not transition elements kinds or pollute AllocationSites on loads. +(function TestNoSimpleMapChangeTransitionOnLoad() { + // 1. PACKED_ELEMENTS -> HOLEY_ELEMENTS + function makePackedObjectArray() { + return ['a', 'b']; + } + %PrepareFunctionForOptimization(makePackedObjectArray); + function loadPackedOrHoleyObject(a) { + return a[0]; + } + %PrepareFunctionForOptimization(loadPackedOrHoleyObject); + + let holeyObjectArray = ['x', , 'z']; + assertTrue(%HasObjectElements(holeyObjectArray)); + assertTrue(%HasHoleyElements(holeyObjectArray)); + + let packedObj1 = makePackedObjectArray(); + assertTrue(%HasObjectElements(packedObj1)); + assertTrue(%HasPackedElements(packedObj1)); + + loadPackedOrHoleyObject(holeyObjectArray); + loadPackedOrHoleyObject(packedObj1); + + let packedObj2 = makePackedObjectArray(); + assertTrue(%HasPackedElements(packedObj2)); + loadPackedOrHoleyObject(packedObj2); + assertTrue(%HasPackedElements(packedObj2)); + assertTrue(%HasPackedElements(makePackedObjectArray())); + + // 2. PACKED_SMI_ELEMENTS -> HOLEY_SMI_ELEMENTS + function makePackedSmiArray() { + return [1, 2]; + } + %PrepareFunctionForOptimization(makePackedSmiArray); + function loadPackedOrHoleySmi(a) { + return a[0]; + } + %PrepareFunctionForOptimization(loadPackedOrHoleySmi); + + let holeySmiArray = [1, , 3]; + assertTrue(%HasSmiElements(holeySmiArray)); + assertTrue(%HasHoleyElements(holeySmiArray)); + + loadPackedOrHoleySmi(holeySmiArray); + loadPackedOrHoleySmi(makePackedSmiArray()); + + let packedSmi2 = makePackedSmiArray(); + assertTrue(%HasSmiElements(packedSmi2)); + assertFalse(%HasHoleyElements(packedSmi2)); + loadPackedOrHoleySmi(packedSmi2); + assertTrue(%HasSmiElements(packedSmi2)); + assertFalse(%HasHoleyElements(packedSmi2)); + assertFalse(%HasHoleyElements(makePackedSmiArray())); + + // 3. PACKED_DOUBLE_ELEMENTS -> HOLEY_DOUBLE_ELEMENTS + function makePackedDoubleArray() { + return [1.5, 2.5]; + } + %PrepareFunctionForOptimization(makePackedDoubleArray); + function loadPackedOrHoleyDouble(a) { + return a[0]; + } + %PrepareFunctionForOptimization(loadPackedOrHoleyDouble); + + let holeyDoubleArray = [1.5, , 3.5]; + assertTrue(%HasDoubleElements(holeyDoubleArray)); + assertTrue(%HasHoleyElements(holeyDoubleArray)); + + loadPackedOrHoleyDouble(holeyDoubleArray); + loadPackedOrHoleyDouble(makePackedDoubleArray()); + + let packedDouble2 = makePackedDoubleArray(); + assertTrue(%HasDoubleElements(packedDouble2)); + assertFalse(%HasHoleyElements(packedDouble2)); + loadPackedOrHoleyDouble(packedDouble2); + assertTrue(%HasDoubleElements(packedDouble2)); + assertFalse(%HasHoleyElements(packedDouble2)); + assertFalse(%HasHoleyElements(makePackedDoubleArray())); + + // 4. PACKED_SMI_ELEMENTS -> PACKED_ELEMENTS + function makeSmiForObjLoad() { + return [10, 20]; + } + %PrepareFunctionForOptimization(makeSmiForObjLoad); + function loadSmiOrObject(a) { + return a[0]; + } + %PrepareFunctionForOptimization(loadSmiOrObject); + + let objArray = ['hello', 'world']; + assertTrue(%HasObjectElements(objArray)); + assertTrue(%HasPackedElements(objArray)); + + loadSmiOrObject(objArray); + loadSmiOrObject(makeSmiForObjLoad()); + + let smiArr = makeSmiForObjLoad(); + assertTrue(%HasSmiElements(smiArr)); + loadSmiOrObject(smiArr); + assertTrue(%HasSmiElements(smiArr)); + assertTrue(%HasSmiElements(makeSmiForObjLoad())); +})(); diff --git a/deps/v8/test/mjsunit/lower_limits_mode/regress/regress-571759664.js b/deps/v8/test/mjsunit/lower_limits_mode/regress/regress-571759664.js new file mode 100644 index 000000000000..05a4c1ef0357 --- /dev/null +++ b/deps/v8/test/mjsunit/lower_limits_mode/regress/regress-571759664.js @@ -0,0 +1,33 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +const builder = new WasmModuleBuilder(); +builder.startRecGroup(); +const kArrayI16 = builder.addArray(kWasmI16, {final: true}); +builder.endRecGroup(); + +const kRefExtern = wasmRefType(kWasmExternRef); +const kFromCharCodeArray = builder.addImport( + 'wasm:js-string', 'fromCharCodeArray', + makeSig([wasmRefNullType(kArrayI16), kWasmI32, kWasmI32], [kRefExtern])); + +const kLength = %StringMaxLength() + 1; + +builder.addFunction('main', kSig_r_v) + .addBody([ + ...wasmI32Const(kLength), + kGCPrefix, kExprArrayNewDefault, kArrayI16, + ...wasmI32Const(0), + ...wasmI32Const(kLength), + kExprCallFunction, kFromCharCodeArray, + ]) + .exportFunc(); + +const instance = builder.instantiate({}, {builtins: ['js-string']}); +assertThrows( + () => instance.exports.main(), RangeError, /Invalid string length/); diff --git a/deps/v8/test/mjsunit/maglev/branch-if-int32-bitwise-and-nonzero.js b/deps/v8/test/mjsunit/maglev/branch-if-int32-bitwise-and-nonzero.js new file mode 100644 index 000000000000..f0c50a65f211 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/branch-if-int32-bitwise-and-nonzero.js @@ -0,0 +1,66 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --allow-natives-syntax --maglev --turbolev --turbofan + +// Branches on `x & mask` fuse into a single test-and-branch. + +function oneBit(x) { return (x & 1) ? "odd" : "even"; } +function oneBitNegated(x) { return !(x & 1) ? "even" : "odd"; } +function multiBit(x) { return (x & 0x30) ? 1 : 0; } +// The bytecode generator commutes the Smi literal to the right. +function constantOnTheLeft(x) { return (0x40 & x) ? 1 : 0; } +// 0x80000000 is not an int32, so the mask reaches Maglev as -2147483648. +function signBit(x) { return (x & 0x80000000) ? 1 : 0; } +// The and result is also used elsewhere, so it must stay alive. +function usedTwice(x) { let m = x & 6; return m ? m : -1; } +// The and result is live in a deopt frame in the taken branch. +function deoptInBranch(x, o) { let m = x & 6; return m ? o.y + m : -1; } + +function check() { + assertEquals("odd", oneBit(1)); + assertEquals("even", oneBit(2)); + assertEquals("odd", oneBit(-1)); + assertEquals("even", oneBitNegated(2)); + assertEquals("odd", oneBitNegated(3)); + assertEquals(1, multiBit(0x10)); + assertEquals(1, multiBit(0x20)); + assertEquals(0, multiBit(0x40)); + assertEquals(0, multiBit(0)); + assertEquals(1, constantOnTheLeft(0x40)); + assertEquals(0, constantOnTheLeft(0x20)); + assertEquals(1, signBit(-1)); + assertEquals(1, signBit(-2147483648)); + assertEquals(0, signBit(0x7fffffff)); + assertEquals(0, signBit(0)); + assertEquals(2, usedTwice(2)); + assertEquals(6, usedTwice(7)); + assertEquals(-1, usedTwice(1)); + assertEquals(3, deoptInBranch(2, {y: 1})); + assertEquals(-1, deoptInBranch(1, {y: 1})); +} + +const functions = [oneBit, oneBitNegated, multiBit, constantOnTheLeft, signBit, + usedTwice, deoptInBranch]; +for (const f of functions) %PrepareFunctionForOptimization(f); +check(); +for (const f of functions) %OptimizeMaglevOnNextCall(f); +check(); +for (const f of functions) assertMaglevved(f); + +// A different map in the taken branch deoptimizes with the and result live. +assertEquals(8, deoptInBranch(6, {z: 0, y: 2})); +assertUnoptimized(deoptInBranch); + +// Turbolev builds the same fused branch and lowers it back to an and and a +// branch for Turboshaft. +for (const f of functions) %PrepareFunctionForOptimization(f); +check(); +for (const f of functions) %OptimizeFunctionOnNextCall(f); +check(); +for (const f of functions) assertOptimized(f); + +// A third map in the taken branch deoptimizes the Turbolev code too. +assertEquals(8, deoptInBranch(6, {w: 0, z: 0, y: 2})); +assertUnoptimized(deoptInBranch); diff --git a/deps/v8/test/mjsunit/maglev/create-closure-top-level.js b/deps/v8/test/mjsunit/maglev/create-closure-top-level.js new file mode 100644 index 000000000000..c6137b2069e2 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/create-closure-top-level.js @@ -0,0 +1,31 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --allow-natives-syntax --maglev + +// Closures created outside of a function scope (e.g. in top-level code) don't +// use the FastNewClosure builtin. OSR the top-level code into Maglev to +// exercise the CreateClosure node, which calls the runtime instead. + +const topLevel = %GetFunctionForCurrentFrame(); +%PrepareFunctionForOptimization(topLevel); + +let v = 7; +let x = 4; +let o; +let created_in_maglev = false; +// Declare the loop variable outside of the loop: a `for (let ...)` loop that +// creates closures is desugared into nested loops. +let i = 0; +for (; i < 3; i++) { + o = {}; + o.x = (c) => v + x++ + 2 + c; + if (topFrameIsMaglevved(%GetOptimizationStatus(topLevel))) { + created_in_maglev = true; + } + if (i == 1) %OptimizeOsr(); +} +assertTrue(created_in_maglev); +assertEquals(7 + 4 + 2 + 2, o.x(2)); +assertEquals(7 + 5 + 2 + 5, o.x(5)); diff --git a/deps/v8/test/mjsunit/maglev/define-const-data-field-spread-literal.js b/deps/v8/test/mjsunit/maglev/define-const-data-field-spread-literal.js deleted file mode 100644 index 1b10b3548cee..000000000000 --- a/deps/v8/test/mjsunit/maglev/define-const-data-field-spread-literal.js +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --maglev - -// A DefineNamedOwnProperty into a const field may only keep the field const -// when the field still holds the uninitialized value, i.e. when the define is -// the initializing store of an object literal. An object literal with a spread -// clones the source object and then defines the remaining properties into the -// clone, so the define may hit an already initialized const field copied from -// the source. It must then generalize the field to mutable. -// -// Note that Maglev does not know the map of the cloned object, so the define -// is compiled from its own feedback, which the runtime only produces after it -// has already generalized the field. These tests therefore document the -// expected behavior; they do not exercise the uninitialized check in the -// optimized code. - -(function TestSpreadDefineIntoInitializedConstField() { - const first = {}; - const second = {}; - function make(src) { - return {...src, a: second}; - } - - const src = {a: first}; - assertTrue(%HasOwnConstDataProperty(src, "a")); - - %PrepareFunctionForOptimization(make); - make(src); - make(src); - %OptimizeMaglevOnNextCall(make); - const o = make(src); - assertSame(second, o.a); - assertMaglevved(make); - assertFalse(%HasOwnConstDataProperty(o, "a")); - assertSame(first, src.a); -})(); - -// Same, but the const field has Smi representation. The representation is -// determined by the first store; there is no runtime function to assert it, -// so the test relies on 1 giving a Smi field. -(function TestSpreadDefineIntoInitializedConstSmiField() { - function make(src) { - return {...src, b: 2}; - } - - const src = {b: 1}; - assertTrue(%HasOwnConstDataProperty(src, "b")); - - %PrepareFunctionForOptimization(make); - make(src); - make(src); - %OptimizeMaglevOnNextCall(make); - const o = make(src); - assertEquals(2, o.b); - assertMaglevved(make); - assertFalse(%HasOwnConstDataProperty(o, "b")); - assertEquals(1, src.b); -})(); - -// Same, but the const field has Double representation. -(function TestSpreadDefineIntoInitializedConstDoubleField() { - function make(src) { - return {...src, c: 2.5}; - } - - const src = {c: 1.5}; - assertTrue(%HasOwnConstDataProperty(src, "c")); - - %PrepareFunctionForOptimization(make); - make(src); - make(src); - %OptimizeMaglevOnNextCall(make); - const o = make(src); - assertEquals(2.5, o.c); - assertMaglevved(make); - assertFalse(%HasOwnConstDataProperty(o, "c")); - assertEquals(1.5, src.c); -})(); diff --git a/deps/v8/test/mjsunit/maglev/int32-div-const-fold.js b/deps/v8/test/mjsunit/maglev/int32-div-const-fold.js new file mode 100644 index 000000000000..e1480c1f52bc --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/int32-div-const-fold.js @@ -0,0 +1,162 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --allow-natives-syntax --maglev + +// Exact constant Int32 divisions (both Div and DivSmi). +(function testExactConstantDivide() { + function div(a, b) { + return a / b; + } + function f() { + let n = 15908864; + let min_int = 1 << 31; + let d1 = n / 4; + let d2 = div(100, -5); + let d3 = div(-100, -5); + let d4 = div(0, 7); + let d5 = div(min_int, 2); + return d1 + d2 + d3 + d4 + d5; + } + + %PrepareFunctionForOptimization(div); + %PrepareFunctionForOptimization(f); + const expected = 3977216 + (-20) + 20 + 0 + (-1073741824); + assertEquals(expected, f()); + assertEquals(expected, f()); + %OptimizeFunctionOnNextCall(f); + assertEquals(expected, f()); +})(); + +// Non-exact constant division must not fold to truncated Int32. +(function testNonExactConstantDivide() { + function div(a, b, run) { + if (!run) return 0; + return a / b; + } + function f(run) { + return div(7, 2, run); + } + + %PrepareFunctionForOptimization(div); + %PrepareFunctionForOptimization(f); + assertEquals(4, div(8, 2, true)); + assertEquals(-3, div(-12, 4, true)); + assertEquals(0, f(false)); + assertEquals(0, f(false)); + %OptimizeFunctionOnNextCall(f); + assertEquals(0, f(false)); + assertEquals(3.5, f(true)); +})(); + +// Division by zero must not fold or trigger divide-by-zero UB. +(function testDivideByZero() { + function div(a, b, run) { + if (!run) return 0; + return a / b; + } + function f(run) { + return div(42, 0, run); + } + + %PrepareFunctionForOptimization(div); + %PrepareFunctionForOptimization(f); + assertEquals(4, div(8, 2, true)); + assertEquals(-3, div(-12, 4, true)); + assertEquals(0, f(false)); + assertEquals(0, f(false)); + %OptimizeFunctionOnNextCall(f); + assertEquals(0, f(false)); + assertEquals(Infinity, f(true)); +})(); + +// kMinInt / -1 overflows Int32 and must not fold or trigger signed overflow UB. +(function testMinIntDivideMinusOne() { + function div(a, b, run) { + if (!run) return 0; + return a / b; + } + function f(run) { + let min_int = 1 << 31; + return div(min_int, -1, run); + } + + %PrepareFunctionForOptimization(div); + %PrepareFunctionForOptimization(f); + assertEquals(4, div(8, 2, true)); + assertEquals(-3, div(-12, 4, true)); + assertEquals(0, f(false)); + assertEquals(0, f(false)); + %OptimizeFunctionOnNextCall(f); + assertEquals(0, f(false)); + assertEquals(2147483648, f(true)); +})(); + +// 0 / negative must produce -0, not fold to +0. +(function testMinusZeroDivide() { + function div1(a, b, run) { + if (!run) return 0; + return a / b; + } + function div4(a, b, run) { + if (!run) return 0; + return a / b; + } + function f1(run) { + return div1(0, -1, run); + } + function f4(run) { + return div4(0, -4, run); + } + + %PrepareFunctionForOptimization(div1); + %PrepareFunctionForOptimization(div4); + %PrepareFunctionForOptimization(f1); + %PrepareFunctionForOptimization(f4); + assertEquals(4, div1(8, 2, true)); + assertEquals(-3, div1(-12, 4, true)); + assertEquals(4, div4(8, 2, true)); + assertEquals(-3, div4(-12, 4, true)); + assertEquals(0, f1(false)); + assertEquals(0, f1(false)); + assertEquals(0, f4(false)); + assertEquals(0, f4(false)); + %OptimizeFunctionOnNextCall(f1); + %OptimizeFunctionOnNextCall(f4); + assertEquals(0, f1(false)); + assertEquals(0, f4(false)); + assertEquals(-Infinity, 1 / f1(true)); + assertEquals(-Infinity, 1 / f4(true)); + // Ensure feedback was updated by the -0 result and re-optimization does not + // enter a deopt loop. + %OptimizeFunctionOnNextCall(f1); + %OptimizeFunctionOnNextCall(f4); + assertEquals(-Infinity, 1 / f1(true)); + assertEquals(-Infinity, 1 / f4(true)); + assertOptimized(f1); + assertOptimized(f4); +})(); + +// Loop bound derived from constant Int32 division enables range analysis. +(function testLoopBoundFromConstantDivide() { + function sumQuarter(arr) { + let bytes = 256; + let limit = bytes / 4; + let sum = 0; + for (let i = 0; i < limit; i++) { + sum = (sum + arr[i]) | 0; + } + return sum; + } + + const arr = new Int32Array(64); + for (let i = 0; i < 64; i++) arr[i] = i + 1; + const expected = (64 * 65) / 2; + + %PrepareFunctionForOptimization(sumQuarter); + assertEquals(expected, sumQuarter(arr)); + assertEquals(expected, sumQuarter(arr)); + %OptimizeFunctionOnNextCall(sumQuarter); + assertEquals(expected, sumQuarter(arr)); +})(); diff --git a/deps/v8/test/mjsunit/maglev/new-closure-tenured.js b/deps/v8/test/mjsunit/maglev/new-closure-tenured.js deleted file mode 100644 index a13d0819fb0f..000000000000 --- a/deps/v8/test/mjsunit/maglev/new-closure-tenured.js +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --allow-natives-syntax --maglev - -function create_closure(v) { - let o = {}; - let x = 4; - o.x = (c) => v + x++ + 2 + c; - return o; -} - -%PrepareFunctionForOptimization(create_closure); -let o = create_closure(7); -%PretenureAllocationSite(o.x); -o = create_closure(7); - -%OptimizeMaglevOnNextCall(create_closure); -o = create_closure(7); -assertEquals(7+4+2+2, o.x(2)); -assertEquals(7+5+2+5, o.x(5)); -assertMaglevved(create_closure); diff --git a/deps/v8/test/mjsunit/maglev/read-only-constant-compare.js b/deps/v8/test/mjsunit/maglev/read-only-constant-compare.js new file mode 100644 index 000000000000..75ec9dd70076 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/read-only-constant-compare.js @@ -0,0 +1,55 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev --no-turbofan + +// Compares against read-only roots, which arm64 reads as immediates: +// the FixedArray map that a keyed store checks its elements against, and the +// read-only "length" string that a dictionary-mode load checks its entry's +// key against. + +// A keyed store that has only seen writable elements checks them against the +// FixedArray map and deoptimizes on a copy-on-write array. +function store(a, i, v) { + a[i] = v; + return a; +} +function writable() { + const a = []; + a.push(1, 2, 3); + return a; +} +%PrepareFunctionForOptimization(store); +assertEquals([1, 7, 3], store(writable(), 1, 7)); +assertEquals([1, 2, 8], store(writable(), 2, 8)); +%OptimizeMaglevOnNextCall(store); +assertEquals([9, 2, 3], store(writable(), 0, 9)); +assertMaglevved(store); +// The literal's elements are copy-on-write. +assertEquals([1, 2, 10], store([1, 2, 3], 2, 10)); +assertUnoptimized(store); + +// A dictionary-mode load of "length" compares the entry's key against the +// read-only string. +function length(o) { + return o.length; +} +function makeDictionary() { + const o = {}; + for (let i = 0; i < 150; i++) o["p" + i] = i; + o.length = 42; + return o; +} +const dict = makeDictionary(); +%PrepareFunctionForOptimization(length); +assertEquals(42, length(dict)); +assertEquals(42, length(dict)); +%OptimizeMaglevOnNextCall(length); +assertEquals(42, length(dict)); +assertMaglevved(length); +dict.length = 43; +assertEquals(43, length(dict)); +delete dict.length; +assertEquals(undefined, length(dict)); +assertMaglevved(length); diff --git a/deps/v8/test/mjsunit/maglev/regress-563882510.js b/deps/v8/test/mjsunit/maglev/regress-563882510.js new file mode 100644 index 000000000000..c3c330d5dc6f --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-563882510.js @@ -0,0 +1,49 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev --no-lazy-feedback-allocation +// Flags: --max-maglev-hard-inline-depth=200 + +// Deeply nested inlined `forEach` calls create one JS builtin continuation +// frame per level. The Maglev prologue stack check must account for their +// full size (including the JS trampoline register parameters), otherwise an +// eager deopt near the stack limit overshoots it. + +const kDepth = 100; +let body = 'return obj.y;'; +for (let i = 0; i < kDepth; i++) body = `arr.forEach(() => { ${body} });`; +const target = new Function( + 'arr', 'obj', 'deopt', `const x = obj.x; if (!deopt) return x; ${body}`); + +const arr = [1]; +const good = {x: 1, y: 1}; +const bad = {x: 1}; // Different map: `obj.y` deopts eagerly. + +%PrepareFunctionForOptimization(target); +target(arr, good, true); +target(arr, bad, false); +target(arr, good, true); +%OptimizeMaglevOnNextCall(target); +target(arr, good, true); + +// Recurse until overflow, then on the way back up try to enter `target` at +// every depth. The deepest successful entry sits right at the prologue stack +// check, where an under-estimated deopt frame size makes the deoptimizer +// exceed the stack limit. +let entered = false; +function probe() { + try { + probe(); + } catch (e) { + } + if (entered) return; + try { + target(arr, bad, true); + entered = true; + } catch (e) { + } +} +%NeverOptimizeFunction(probe); +probe(); +assertTrue(entered); diff --git a/deps/v8/test/mjsunit/maglev/regress-569212098.js b/deps/v8/test/mjsunit/maglev/regress-569212098.js new file mode 100644 index 000000000000..38a9c8b07e0f --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-569212098.js @@ -0,0 +1,13 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-script-context-cells --no-function-context-cells +// Flags: --allow-natives-syntax + +let x = 1; +let f = new Function("x = 2; return x;"); +%PrepareFunctionForOptimization(f); +assertEquals(2, f()); +%OptimizeMaglevOnNextCall(f); +assertEquals(2, f()); diff --git a/deps/v8/test/mjsunit/maglev/regress-569376794-1.js b/deps/v8/test/mjsunit/maglev/regress-569376794-1.js new file mode 100644 index 000000000000..ea8a43a002a8 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-569376794-1.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --no-lazy-feedback-allocation +// Flags: --max-maglev-hard-inline-depth=2200 +// Flags: --max-maglev-inlined-bytecode-size-small-total=30000 + +(function TestDeepNestedForEach() { + let body = ''; + for (let i = 0; i < 250; i++) { + body = `arr.forEach(() => { ${body} });`; + } + const f = new Function('arr', body); + %PrepareFunctionForOptimization(f); + f([1]); + %OptimizeMaglevOnNextCall(f, 'concurrent'); + f([1]); + %FinalizeOptimization(); +})(); + +(function TestMutuallyRecursiveForEachClosures() { + let f; + for (let i = 0; i < 3; i++) { + const prev = f, a = i ? [1] : []; + f = () => a.forEach(() => prev()); + } + %PrepareFunctionForOptimization(f); + f(); + f(); + %OptimizeMaglevOnNextCall(f, 'concurrent'); + f(); + %FinalizeOptimization(); +})(); diff --git a/deps/v8/test/mjsunit/maglev/regress-569376794-2.js b/deps/v8/test/mjsunit/maglev/regress-569376794-2.js new file mode 100644 index 000000000000..4d9d4bfbe7a9 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-569376794-2.js @@ -0,0 +1,16 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +(function TestDeepFunctionPrototypeCallReduction() { + const c = Function.prototype.call; + const g = () => {}; + const f = eval(`(() => (i) => i ? 0 : c.call(${'c,'.repeat(25000)}g))()`); + %PrepareFunctionForOptimization(f); + f(0); + %OptimizeMaglevOnNextCall(f, 'concurrent'); + f(1); + %FinalizeOptimization(); +})(); diff --git a/deps/v8/test/mjsunit/maglev/regress-569947577.js b/deps/v8/test/mjsunit/maglev/regress-569947577.js new file mode 100644 index 000000000000..708068a7d9b2 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-569947577.js @@ -0,0 +1,24 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --maglev --maglev-osr --no-turbofan --no-concurrent-osr + +function foo(n) { + let outer_var = 0; + { + let block_var = 1; + for (let i = 0; i < n; i++) { + let inner = function() { + outer_var += 3; + return block_var; + }; + outer_var = outer_var + 1; + inner(); + outer_var = outer_var + 1; + } + return outer_var; + } +} + +assertEquals(5000, foo(1000)); diff --git a/deps/v8/test/mjsunit/maglev/regress-570091260.js b/deps/v8/test/mjsunit/maglev/regress-570091260.js new file mode 100644 index 000000000000..8230fa7849d1 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-570091260.js @@ -0,0 +1,50 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc + +function f1() { + return f1; +} +class C2 extends f1 { + constructor() { + try { + const v6 = Symbol.dispose; + const v10 = { + [v6]() { + gc(); + }, + }; + using v11 = v10; + super(); + throw 889951875n; + } catch (e12) { + } + } +} +for (let v13 = 0; v13 < 25; v13++) { + new C2(); +} + +const holder = {obj: {}}; +function f2() { + return holder.obj; +} +class C3 extends f2 { + constructor() { + try { + using v = { + [Symbol.dispose]() { + gc(); + }, + }; + super(); + throw 1; + } catch (e) { + } + } +} +for (let i = 0; i < 25; i++) { + new C3(); +} diff --git a/deps/v8/test/mjsunit/maglev/regress-573856023.js b/deps/v8/test/mjsunit/maglev/regress-573856023.js new file mode 100644 index 000000000000..2ef6d1a6c16c --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-573856023.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev + +// Transitioning store to a const double field from a holey double array. +(function TestConstTransitioningDoubleStore() { + function F(a, i) { + this.x = a[i]; + } + + const arr = [1.5, , 2.5]; + %PrepareFunctionForOptimization(F); + assertEquals(1.5, new F(arr, 0).x); + assertEquals(2.5, new F(arr, 2).x); + + %OptimizeMaglevOnNextCall(F); + assertEquals(1.5, new F(arr, 0).x); + assertEquals(undefined, new F(arr, 1).x); +})(); + +// Transitioning store to a mutable double field from a holey double array. +(function TestMutableTransitioningDoubleStore() { + function F(a, i) { + this.x = a[i]; + } + + const arr = [1.5, , 2.5]; + %PrepareFunctionForOptimization(F); + const o = new F(arr, 0); + o.x = 3.5; + assertEquals(2.5, new F(arr, 2).x); + + %OptimizeMaglevOnNextCall(F); + assertEquals(1.5, new F(arr, 0).x); + assertEquals(undefined, new F(arr, 1).x); +})(); diff --git a/deps/v8/test/mjsunit/maglev/regress-574021176.js b/deps/v8/test/mjsunit/maglev/regress-574021176.js new file mode 100644 index 000000000000..780b5b1c8cfa --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-574021176.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +let g = () => class {}; + +function* gen(o) { + // Context-allocated, maybe-assigned variable so the function context uses a + // ContextCell for `x`. + let x = 42; + () => x = 0; + + // Polymorphic property load with a call continuation. The class literal + // pushes a `CLASS_SCOPE` context (needed for `super.x`) before evaluating + // `extends g()` and pops it after defining the class. When `g()` aborts in + // every polymorphic arm, skipping the rest of the continuation must still pop + // that `CLASS_SCOPE`. + o.f(class extends g() { + constructor() { + super.x; + } + }); + + // In dead code after all polymorphic arms abort, `SuspendGenerator` records + // `current_scope_info_` on the `ResumeGenerator` merge state. + yield; + + // Loads `x` using the `ScopeInfo` from the resume merge state (which must be + // the generator's `FUNCTION_SCOPE` with cells, not the leaked `CLASS_SCOPE`). + return x; +} + +const suspended = gen({f() {}}); +suspended.next(); + +g = class {}; +%PrepareFunctionForOptimization(gen); +assertThrows(() => gen({f() {}}).next(), TypeError); +assertThrows(() => gen({a: 1, f() {}}).next(), TypeError); + +%OptimizeFunctionOnNextCall(gen); +assertEquals(42, suspended.next().value); diff --git a/deps/v8/test/mjsunit/maglev/regress-574412712.js b/deps/v8/test/mjsunit/maglev/regress-574412712.js new file mode 100644 index 000000000000..9d1166900968 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-574412712.js @@ -0,0 +1,47 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev + +const o = {abc: 1}; + +function f1(s) { + let c = s + s; + if (s) { + o[s]; + c + "x"; + } + return c + "abcdefg"; +} + +%PrepareFunctionForOptimization(f1); +f1("abc"); +%OptimizeMaglevOnNextCall(f1); +// If `f1("")` returns an invalid `ConsString("", "abcdefg")` with length 7 +// (< ConsString::kMinLength), concatenating `"12345"` (total length 12 < 13) +// enters the short-string fast path in `NewConsString` that assumes direct +// string inputs. +assertEquals("abcdefg12345", f1("") + "12345"); +assertMaglevved(f1); + +const re = /(?=(a))$/; +re.test("a"); + +function f2(s, b) { + let c = s + s; + if (s) { + o[s]; + c + "x"; + } + return "0123456789abc" + (b + "x") + (b + "x") + c; +} + +%PrepareFunctionForOptimization(f2); +f2("abc", "x"); +%OptimizeMaglevOnNextCall(f2); +// Verify that `f2("", "x")` does not produce a `ConsString` with an empty +// `second` and an unflattened `ConsString` `first`, which `String::Flatten` +// would treat as already flat when passing the subject to RegExp execution. +assertEquals("0123456789abcxxxx", f2("", "x").replace(re, () => "")); +assertMaglevved(f2); diff --git a/deps/v8/test/mjsunit/maglev/regress-577954376.js b/deps/v8/test/mjsunit/maglev/regress-577954376.js new file mode 100644 index 000000000000..86a0773af515 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/regress-577954376.js @@ -0,0 +1,19 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +function foo(n) { + let s = "a"; + for (let i = 0; i < n; i++) { + s = "b"; + } + let c = s + "x"; + return c + "0123456789abc"; +} + +%PrepareFunctionForOptimization(foo); +foo(2); +%OptimizeFunctionOnNextCall(foo); +assertEquals("bx0123456789abc", foo(2)); diff --git a/deps/v8/test/mjsunit/maglev/script-context-specialization.js b/deps/v8/test/mjsunit/maglev/script-context-specialization.js index 70c784621b36..0e9a63e99fa5 100644 --- a/deps/v8/test/mjsunit/maglev/script-context-specialization.js +++ b/deps/v8/test/mjsunit/maglev/script-context-specialization.js @@ -54,3 +54,469 @@ assertEquals(42, g2()); assertMaglevved(g2); assertEquals(42, g1()); assertMaglevved(g1); + +// Test inlining a known constant JSFunction from another script (with its own +// ScriptContext and FunctionContext). +const otherScriptFn = Realm.eval(Realm.current(), ` + const otherScriptConst = 100; + let otherScriptLet = 200; + (function makeOther() { + let otherFuncVar = 300; + return function otherInlined(x) { + return otherScriptConst + otherScriptLet + otherFuncVar + x; + }; + })(); +`); + +function callOtherScriptFn(x) { + return otherScriptFn(x) + scriptConst; +} +%PrepareFunctionForOptimization(otherScriptFn); +%PrepareFunctionForOptimization(callOtherScriptFn); +assertEquals(643, callOtherScriptFn(1)); +assertEquals(644, callOtherScriptFn(2)); +%OptimizeMaglevOnNextCall(callOtherScriptFn); +assertEquals(645, callOtherScriptFn(3)); +assertMaglevved(callOtherScriptFn); + +// Test inlining a closure created via FastCreateClosure inside a non-FCI caller +// and inside a many-closures caller. +function makeCallerWithFastCreateClosure(base) { + return function caller(x) { + const inner = (y) => base + scriptConst + y; + return inner(x); + }; +} +const c1 = makeCallerWithFastCreateClosure(10); +%PrepareFunctionForOptimization(c1); +assertEquals(53, c1(1)); +assertEquals(54, c1(2)); +%OptimizeMaglevOnNextCall(c1); +assertEquals(55, c1(3)); +assertMaglevved(c1); + +const c2 = makeCallerWithFastCreateClosure(20); +%PrepareFunctionForOptimization(c2); +assertEquals(63, c2(1)); +assertEquals(64, c2(2)); +%OptimizeMaglevOnNextCall(c2); +assertEquals(65, c2(3)); +assertMaglevved(c2); +assertEquals(55, c1(3)); + +// Test inlining via FeedbackCell (dynamic closure with different +// FunctionContext instances, sharing the same ScriptContext). +function makeDynamicInner(secret) { + return function dynamicInner(x) { + return secret + scriptConst + x; + }; +} +const dyn1 = makeDynamicInner(100); +const dyn2 = makeDynamicInner(200); +function callDynamicInner(fn, x) { + return fn(x); +} +%PrepareFunctionForOptimization(dyn1); +%PrepareFunctionForOptimization(dyn2); +%PrepareFunctionForOptimization(callDynamicInner); +assertEquals(143, callDynamicInner(dyn1, 1)); +assertEquals(244, callDynamicInner(dyn2, 2)); +%OptimizeMaglevOnNextCall(callDynamicInner); +assertEquals(145, callDynamicInner(dyn1, 3)); +assertEquals(246, callDynamicInner(dyn2, 4)); +assertMaglevved(callDynamicInner); + +// Test OSR compilation with script context specialization. +function createClosureOsr() { + return function osrSimple(n) { + let sum = 0; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst; + } + return sum; + }; +} + +const osr1 = createClosureOsr(); +const osr2 = createClosureOsr(); +%PrepareFunctionForOptimization(osr1); +assertEquals(420, osr1(10)); +%PrepareFunctionForOptimization(osr2); +assertEquals(420, osr2(10)); + +// Test OSR when an inner FunctionContext is pushed before the OSR loop. +function createClosureOsrInnerContext() { + return function osrInner(n) { + let captured = 10; + let getCaptured = () => captured; + let sum = 0; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst + getCaptured(); + } + return sum; + }; +} + +const osrInner1 = createClosureOsrInnerContext(); +const osrInner2 = createClosureOsrInnerContext(); +%PrepareFunctionForOptimization(osrInner1); +assertEquals(520, osrInner1(10)); +%PrepareFunctionForOptimization(osrInner2); +assertEquals(520, osrInner2(10)); + +// Test OSR when a BlockContext is pushed before the OSR loop. +function createClosureOsrBlockContext() { + return function osrBlock(n) { + let sum = 0; + { + let blockVar = 20; + let getBlockVar = () => blockVar; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst + getBlockVar(); + } + } + return sum; + }; +} + +const osrBlock1 = createClosureOsrBlockContext(); +const osrBlock2 = createClosureOsrBlockContext(); +%PrepareFunctionForOptimization(osrBlock1); +assertEquals(620, osrBlock1(10)); +%PrepareFunctionForOptimization(osrBlock2); +assertEquals(620, osrBlock2(10)); + +// Test OSR inside a catch block (CatchContext pushed before OSR loop). +function createClosureOsrCatchContext() { + return function osrCatch(n) { + let sum = 0; + try { + throw 1; + } catch (e) { + let getE = () => e; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst + getE(); + } + } + return sum; + }; +} + +const osrCatch1 = createClosureOsrCatchContext(); +const osrCatch2 = createClosureOsrCatchContext(); +%PrepareFunctionForOptimization(osrCatch1); +assertEquals(430, osrCatch1(10)); +%PrepareFunctionForOptimization(osrCatch2); +assertEquals(430, osrCatch2(10)); + +// Test popping out of nested OSR contexts (PopContext after loop exit) and +// accessing outer contexts (both intermediate contexts and ScriptContext). +function createClosureOsrPopOutNested() { + return function osrPopOut(n) { + let funcVar = 100; + let getFuncVar = () => funcVar; + let sum = 0; + { + let block1Var = 10; + let getBlock1Var = () => block1Var; + { + let block2Var = 1; + let getBlock2Var = () => block2Var; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst + getBlock2Var(); + } + } + // Popped out of block2 (the OSR entry context) into block1! + sum += scriptConst + getBlock1Var() + getFuncVar(); + } + // Popped out of block1 into FunctionContext! + sum += scriptConst + getFuncVar(); + return sum; + }; +} + +const osrPop1 = createClosureOsrPopOutNested(); +const osrPop2 = createClosureOsrPopOutNested(); +%PrepareFunctionForOptimization(osrPop1); +assertEquals(430 + 42 + 10 + 100 + 42 + 100, osrPop1(10)); +%PrepareFunctionForOptimization(osrPop2); +assertEquals(430 + 42 + 10 + 100 + 42 + 100, osrPop2(10)); + +// Test popping out of the OSR context via exception handling (try/catch +// outside the OSR block context). +function createClosureOsrPopOutException() { + return function osrPopException(n) { + let funcVar = 200; + let getFuncVar = () => funcVar; + let sum = 0; + try { + { + let blockVar = 30; + let getBlockVar = () => blockVar; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst + getBlockVar(); + if (i == 8) throw new Error("boom"); + } + } + } catch (e) { + // Caught outside the inner BlockContext; current context is CatchContext + // whose outer is FunctionContext -> ScriptContext. + sum += scriptConst + getFuncVar(); + } + // Popped out of CatchContext back to FunctionContext. + sum += scriptConst + getFuncVar(); + return sum; + }; +} + +const osrExc1 = createClosureOsrPopOutException(); +const osrExc2 = createClosureOsrPopOutException(); +%PrepareFunctionForOptimization(osrExc1); +assertEquals(9 * (42 + 30) + (42 + 200) + (42 + 200), osrExc1(10)); +%PrepareFunctionForOptimization(osrExc2); +assertEquals(9 * (42 + 30) + (42 + 200) + (42 + 200), osrExc2(10)); + +// Test OSR in a top-level function where specialization_context_distance is 0 +// (the function's context is the ScriptContext itself, with no pushed context +// at loop entry). +function toplevelOsrDistanceZero(n) { + let sum = 0; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst; + } + return sum; +} + +%PrepareFunctionForOptimization(toplevelOsrDistanceZero); +assertEquals(420, toplevelOsrDistanceZero(10)); + +// Regression test: register reuse after PopContext at distance 0 before an OSR +// for..in loop (where ToObject reuses the popped context register without a +// preceding Star). +function toplevelOsrRegisterReuse(obj) { + { + let x = 1; + (() => x)(); + } + let res = []; + let i = 0; + for (let k in obj) { + if (i++ == 2) %OptimizeOsr(); + res.push(k + scriptConst); + } + return res; +} + +%PrepareFunctionForOptimization(toplevelOsrRegisterReuse); +assertEquals( + ['a42', 'b42', 'c42', 'd42', 'e42'], + toplevelOsrRegisterReuse({a: 1, b: 2, c: 3, d: 4, e: 5})); + +// Regression test: branching control flow before an OSR loop where only one +// branch pushes/pops a block context. +function toplevelOsrBranchBeforeLoop(cond, n) { + if (cond) { + let x = 10; + (() => x)(); + } + let sum = 0; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += scriptConst; + } + return sum; +} + +%PrepareFunctionForOptimization(toplevelOsrBranchBeforeLoop); +assertEquals(420, toplevelOsrBranchBeforeLoop(true, 10)); +assertEquals(420, toplevelOsrBranchBeforeLoop(false, 10)); + +// Regression test: inlined function inside an OSR script-context-specialized +// function accessing script context slots. +function inlineHelper(x) { + return x + scriptConst; +} +%PrepareFunctionForOptimization(inlineHelper); + +function toplevelOsrWithInlining(n) { + let sum = 0; + for (let i = 0; i < n; i++) { + if (i == 5) %OptimizeOsr(); + sum += inlineHelper(i); + } + return sum; +} + +%PrepareFunctionForOptimization(toplevelOsrWithInlining); +assertEquals(420 + 45, toplevelOsrWithInlining(10)); + +// Regression test: inlined inner closure inside a factory-created outer +// function (where specialization_context_distance > 0) accessing scriptConst. +function createOuterWithInlinedClosure(capturedParam) { + return function outerWithInlinedClosure(n) { + let innerClosure = (x) => x + capturedParam + scriptConst; + %PrepareFunctionForOptimization(innerClosure); + let sum = 0; + for (let i = 0; i < n; i++) { + sum += innerClosure(i); + } + return sum; + }; +} + +const inlinedClosure1 = createOuterWithInlinedClosure(10); +const inlinedClosure2 = createOuterWithInlinedClosure(20); +%PrepareFunctionForOptimization(inlinedClosure1); +%PrepareFunctionForOptimization(inlinedClosure2); +assertEquals(45 + 100 + 420, inlinedClosure1(10)); +%OptimizeMaglevOnNextCall(inlinedClosure1); +assertEquals(45 + 100 + 420, inlinedClosure1(10)); +assertEquals(45 + 200 + 420, inlinedClosure2(10)); + +// Regression test: inlined closure that pushes a BlockContext across a branch +// (producing a Phi context inside the inlined function) and accesses outer +// function and script context slots. +function createOuterWithBranchingInlinedClosure(capturedParam) { + return function outerWithBranchingInlinedClosure(n) { + let innerClosure = (x) => { + let res = 0; + { + let blockVar = x; + let getBlockVar = () => blockVar; + if (x & 1) { + let innerBlockVar = x + 1; + let getInner = () => innerBlockVar; + res += getInner(); + } + // After the `if`, if we had a context phi or inside the block context: + res += getBlockVar() + capturedParam + scriptConst; + } + return res; + }; + %PrepareFunctionForOptimization(innerClosure); + let sum = 0; + for (let i = 0; i < n; i++) { + sum += innerClosure(i); + } + return sum; + }; +} + +const branchingInlined1 = createOuterWithBranchingInlinedClosure(10); +%PrepareFunctionForOptimization(branchingInlined1); +assertEquals(30 + 45 + 100 + 420, branchingInlined1(10)); +%OptimizeMaglevOnNextCall(branchingInlined1); +assertEquals(30 + 45 + 100 + 420, branchingInlined1(10)); + +// Regression test: top-level eval (with and without EvalContext) undergoing OSR +// and accessing scriptConst. +const evalResultWithContext = eval(` + let evalVar = 5; + let getEvalVar = () => evalVar; + let evalSum = 0; + for (let i = 0; i < 10; i++) { + if (i == 5) %OptimizeOsr(); + evalSum += scriptConst + getEvalVar(); + } + evalSum; +`); +assertEquals(470, evalResultWithContext); + +const evalResultWithoutContext = eval(` + var evalNoCtxSum = 0; + for (var j = 0; j < 10; j++) { + if (j == 5) %OptimizeOsr(); + evalNoCtxSum += scriptConst; + } + evalNoCtxSum; +`); +assertEquals(420, evalResultWithoutContext); + +// Regression test (crbug.com/569212097): inlining a closure created inside an +// inlined factory call whose FunctionContext has the same ScopeInfo as the +// outer caller's specialization_context. +function outerFactoryWithOuterAccess(createTop, val) { + let captured = val; + function inner() { + return captured + scriptConst; + } + if (createTop) { + return function top() { + const freshInner = outerFactoryWithOuterAccess(false, 100); + return freshInner() + captured; + }; + } + return inner; +} + +const topWithOuterAccess = outerFactoryWithOuterAccess(true, 1); +%PrepareFunctionForOptimization(outerFactoryWithOuterAccess); +%PrepareFunctionForOptimization(topWithOuterAccess); +assertEquals(143, topWithOuterAccess()); +assertEquals(143, topWithOuterAccess()); +%OptimizeMaglevOnNextCall(topWithOuterAccess); +assertEquals(143, topWithOuterAccess()); +assertMaglevved(topWithOuterAccess); + +// Same scenario at depth 0 only (immutable const slot in FunctionContext), +// ensuring the fresh closure's FunctionContext is not confused with the +// caller's specialization_context. +function outerFactoryDepthZeroOnly(createTop, val) { + const immutableCaptured = val; + function inner() { + return immutableCaptured; + } + if (createTop) { + return function top() { + const freshInner = outerFactoryDepthZeroOnly(false, 100); + return freshInner() + immutableCaptured; + }; + } + return inner; +} + +const topDepthZeroOnly = outerFactoryDepthZeroOnly(true, 1); +%PrepareFunctionForOptimization(outerFactoryDepthZeroOnly); +%PrepareFunctionForOptimization(topDepthZeroOnly); +assertEquals(101, topDepthZeroOnly()); +assertEquals(101, topDepthZeroOnly()); +%OptimizeMaglevOnNextCall(topDepthZeroOnly); +assertEquals(101, topDepthZeroOnly()); +assertMaglevved(topDepthZeroOnly); + +// Three-level nesting: grandOuter -> outerFactory -> inner, where top is +// specialized to the first outerFactory context (C_1) while freshInner is +// created in a second outerFactory context (C_2) that still shares grandOuter's +// context (C_0) and the script context. +function makeGrandOuter(grandVal) { + const grandCaptured = grandVal; + function outerFactory(createTop, val) { + const outerCaptured = val; + function inner() { + return outerCaptured + grandCaptured + scriptConst; + } + if (createTop) { + return function top() { + const freshInner = outerFactory(false, 200); + return freshInner() + outerCaptured; + }; + } + return inner; + } + return outerFactory(true, 1); +} + +const topThreeLevel = makeGrandOuter(1000); +%PrepareFunctionForOptimization(topThreeLevel); +assertEquals(1243, topThreeLevel()); +assertEquals(1243, topThreeLevel()); +%OptimizeMaglevOnNextCall(topThreeLevel); +assertEquals(1243, topThreeLevel()); +assertMaglevved(topThreeLevel); diff --git a/deps/v8/test/mjsunit/maglev/spread-rest-parameter-element-mutation.js b/deps/v8/test/mjsunit/maglev/spread-rest-parameter-element-mutation.js new file mode 100644 index 000000000000..a3c30287f771 --- /dev/null +++ b/deps/v8/test/mjsunit/maglev/spread-rest-parameter-element-mutation.js @@ -0,0 +1,103 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev --maglev-object-tracking + +// A rest parameter is a JSArray whose backing store is an ArgumentsElements +// node. TryGetNonEscapingArgumentsOrArray accepts such an array unconditionally +// once it sees ArgumentsElements, so a preceding element store (which lands on +// the ArgumentsElements node and leaves the array itself non-escaping) does not +// prevent the spread from being lowered to CallForwardVarargs. That builtin +// copies the caller's physical stack frame and drops the store. +// +// Turbolev shares these paths, hence %OptimizeFunctionOnNextCall rather than +// %OptimizeMaglevOnNextCall: it reaches Maglev under the variants that pass +// --optimize-on-next-call-optimizes-to-maglev and Turbolev under --turbolev. + +function join() { + return Array.prototype.join.call(arguments, '|'); +} + +function spread(...r) { + r[0] = 42; + return join(...r); +} + +function apply(...r) { + r[0] = 42; + return join.apply(null, r); +} + +function Collect() { + this.result = Array.prototype.join.call(arguments, '|'); +} + +function construct(...r) { + r[0] = 42; + return new Collect(...r).result; +} + +function testOptimized(test) { + %PrepareFunctionForOptimization(test); + assertEquals('42|2|3', test(1, 2, 3)); + assertEquals('42|2|3', test(1, 2, 3)); + %OptimizeFunctionOnNextCall(test); + assertEquals('42|2|3', test(1, 2, 3)); + assertOptimized(test); +} + +// These stores are emitted directly while building the caller graph and must +// disable argument forwarding. +for (const test of [spread, apply, construct]) { + testOptimized(test); +} + +// Also cover a store emitted while eagerly inlining a callee. +function mutate(a) { + a[0] = 42; +} + +function spreadAfterInlinedMutation(...r) { + mutate(r); + return join(...r); +} + +%PrepareFunctionForOptimization(mutate); +mutate([1, 2, 3]); +mutate([1, 2, 3]); +testOptimized(spreadAfterInlinedMutation); + +// The following cases exercise the safety conditions that let the mutation +// mark remain local to stores already emitted by the graph builder. + +// Passing the rest array to a non-inlined callee must make it escape, which +// prevents the following spread from using argument forwarding. +function mutateNeverInlined(a) { + a[0] = 42; +} + +%PrepareFunctionForOptimization(mutateNeverInlined); +mutateNeverInlined([0]); +%NeverOptimizeFunction(mutateNeverInlined); + +function spreadAfterNonInlinedMutation(...r) { + mutateNeverInlined(r); + return join(...r); +} + +testOptimized(spreadAfterNonInlinedMutation); + +// The spread comes first in bytecode order, but on the second iteration it has +// to observe the store from the first. The rest allocation is outside the loop, +// so argument forwarding must be rejected inside the loop. +function spreadBeforeMutationInLoop(...r) { + let result; + for (let i = 0; i < 2; i++) { + result = join(...r); + r[0] = 42; + } + return result; +} + +testOptimized(spreadBeforeMutationInLoop); diff --git a/deps/v8/test/mjsunit/math-sum-precise/closing.js b/deps/v8/test/mjsunit/math-sum-precise/closing.js index 5cb1a36a0f9b..8cc251f893b3 100644 --- a/deps/v8/test/mjsunit/math-sum-precise/closing.js +++ b/deps/v8/test/mjsunit/math-sum-precise/closing.js @@ -6,19 +6,49 @@ function test(obj) { let it = obj.values(); var closed = false; + var next; it.return = function () { closed = true; - assertEquals("pos", it.next()); + next = it.next(); + return {}; }; assertThrows(() => Math.sumPrecise(it), TypeError); assertTrue(closed); + assertEquals({value: "pos", done: false}, next); } - test([1,"pos",2]); - test([1,,"pos",2]); - test([,1,"pos",2]); - test([,"pos",]); - test(new Set([1, "pos", 2])); - let set = new Set([1,"pos"]); + test([1, "bad", "pos", 2]); + test([1, , "pos", 2]); + test([, "pos", 2]); + test([, "pos", ]); + test(new Set([1, "bad", "pos", 2])); + let set = new Set([1, "bad", "pos"]); set.delete(1); test(set); })(); + +(function TestArrayFastPathPrototypeReturn() { + const ArrayIteratorPrototype = Object.getPrototypeOf([].values()); + const cases = [ + [["bad"], {value: undefined, done: true}], + [[1, "bad", 2], {value: 2, done: false}], + [[1, , 2], {value: 2, done: false}], + [[1.1, , 2.2], {value: 2.2, done: false}], + [[, "bad"], {value: "bad", done: false}], + ]; + for (const [arr, expectedNext] of cases) { + let closed = false; + let nextResult; + ArrayIteratorPrototype.return = function() { + closed = true; + nextResult = this.next(); + return {}; + }; + try { + assertThrows(() => Math.sumPrecise(arr), TypeError); + } finally { + delete ArrayIteratorPrototype.return; + } + assertTrue(closed); + assertEquals(expectedNext, nextResult); + } +})(); diff --git a/deps/v8/test/mjsunit/math-sum-precise/iterator-clear-on-error.js b/deps/v8/test/mjsunit/math-sum-precise/iterator-clear-on-error.js deleted file mode 100644 index 3eae0a951b54..000000000000 --- a/deps/v8/test/mjsunit/math-sum-precise/iterator-clear-on-error.js +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -(function TestArrayIteratorClearedOnError() { - const it = [10, 20, "bad", 30, 40][Symbol.iterator](); - assertThrows(() => Math.sumPrecise(it), TypeError); - assertEquals({value: undefined, done: true}, it.next()); - - const it2 = [10, 20, "bad", 30, 40][Symbol.iterator](); - assertThrows(() => Math.sumPrecise(it2), TypeError); - assertEquals(-0, Math.sumPrecise(it2)); -})(); - -(function TestMapIteratorClearedOnError() { - let m = new Map([[1, 10], [2, "bad"], [3, 30]]); - let it = m.values(); - assertThrows(() => Math.sumPrecise(it), TypeError); - assertEquals({value: undefined, done: true}, it.next()); - - let it2 = m.values(); - assertThrows(() => Math.sumPrecise(it2), TypeError); - assertEquals(-0, Math.sumPrecise(it2)); -})(); diff --git a/deps/v8/test/mjsunit/math-sum-precise/iterator-not-exhausted-on-error.js b/deps/v8/test/mjsunit/math-sum-precise/iterator-not-exhausted-on-error.js new file mode 100644 index 000000000000..c764ba814dca --- /dev/null +++ b/deps/v8/test/mjsunit/math-sum-precise/iterator-not-exhausted-on-error.js @@ -0,0 +1,50 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Per ECMA-262 IteratorClose, built-in iterators lack a .return() method and +// must remain at the element immediately following the failing element on +// abrupt completion (crbug.com/573855950). + +(function TestArrayIteratorNotExhaustedOnError() { + const it = [10, 20, "bad", 30, 40][Symbol.iterator](); + assertThrows(() => Math.sumPrecise(it), TypeError); + assertEquals({value: 30, done: false}, it.next()); + + const it2 = [10, 20, "bad", 30, 40][Symbol.iterator](); + assertThrows(() => Math.sumPrecise(it2), TypeError); + assertEquals(70, Math.sumPrecise(it2)); +})(); + +(function TestMapIteratorNotExhaustedOnError() { + let m = new Map([[1, 10], [2, "bad"], [3, 30]]); + let it = m.values(); + assertThrows(() => Math.sumPrecise(it), TypeError); + assertEquals({value: 30, done: false}, it.next()); + + let it2 = m.values(); + assertThrows(() => Math.sumPrecise(it2), TypeError); + assertEquals(30, Math.sumPrecise(it2)); +})(); + +(function TestStringIteratorNotExhaustedOnError() { + let it = "abc"[Symbol.iterator](); + assertThrows(() => Math.sumPrecise(it), TypeError); + assertEquals({value: "b", done: false}, it.next()); +})(); + +(function TestRegExpStringIteratorNotExhaustedOnError() { + let it = "ab".matchAll(/./g); + assertThrows(() => Math.sumPrecise(it), TypeError); + let next = it.next(); + assertFalse(next.done); + assertEquals("b", next.value[0]); +})(); + +(function TestEmptyArrayIteratorExhausted() { + let a = []; + let it = a.values(); + assertEquals(-0, Math.sumPrecise(it)); + a.push(1); + assertEquals({value: undefined, done: true}, it.next()); +})(); diff --git a/deps/v8/test/mjsunit/math-sum-precise/regress-sumPrecise-iterator.js b/deps/v8/test/mjsunit/math-sum-precise/regress-sumPrecise-iterator.js index da9215c2722b..a6a69eaadf70 100644 --- a/deps/v8/test/mjsunit/math-sum-precise/regress-sumPrecise-iterator.js +++ b/deps/v8/test/mjsunit/math-sum-precise/regress-sumPrecise-iterator.js @@ -58,3 +58,37 @@ let obj = { [Symbol.iterator]() { return iter; } }; assertEquals(240, Math.sumPrecise(obj)); } + +{ + // Case 6: JSArrayIterator with replaced prototype (crbug.com/566974983). + let it = [1, 2, 3].values(); + let calls = 0; + Object.setPrototypeOf(it, { + next() { + if (calls++ === 0) return { value: 42, done: false }; + return { value: undefined, done: true }; + } + }); + assertEquals(42, Math.sumPrecise({ [Symbol.iterator]() { return it; } })); +} + +{ + // Case 7: JSSetIterator with replaced prototype (crbug.com/566974983). + let it = new Set([1, 2, 3]).values(); + let calls = 0; + Object.setPrototypeOf(it, { + next() { + if (calls++ === 0) return { value: 42, done: false }; + return { value: undefined, done: true }; + } + }); + assertEquals(42, Math.sumPrecise({ [Symbol.iterator]() { return it; } })); +} + +{ + // Case 8: Set.prototype.entries() yields [key, value] arrays and must throw + // TypeError (crbug.com/566973695). + let it = new Set([1, 2, 3]).entries(); + assertThrows(() => Math.sumPrecise(it), TypeError); + assertEquals({ value: [2, 2], done: false }, it.next()); +} diff --git a/deps/v8/test/mjsunit/math-sum-precise/set-iterator-clear-on-error.js b/deps/v8/test/mjsunit/math-sum-precise/set-iterator-clear-on-error.js deleted file mode 100644 index 0aa59d9cf750..000000000000 --- a/deps/v8/test/mjsunit/math-sum-precise/set-iterator-clear-on-error.js +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -(function TestSetIteratorNotClearedOnError() { - let s = new Set([1, "a", 3]); - let it = s[Symbol.iterator](); - - assertThrows(() => Math.sumPrecise(it), TypeError); - - let next = it.next(); - assertTrue(next.done); - assertEquals(undefined, next.value); -})(); - -(function TestSetIteratorNotClearedOnErrorAndSetChanges() { - let s = new Set([1, "a", 3]); - let it = s[Symbol.iterator](); - - assertThrows(() => Math.sumPrecise(it), TypeError); - - s.add(4); - let next = it.next(); - assertTrue(next.done); - assertEquals(undefined, next.value); -})(); diff --git a/deps/v8/test/mjsunit/math-sum-precise/set-iterator-not-exhausted-on-error.js b/deps/v8/test/mjsunit/math-sum-precise/set-iterator-not-exhausted-on-error.js new file mode 100644 index 000000000000..b2366f703245 --- /dev/null +++ b/deps/v8/test/mjsunit/math-sum-precise/set-iterator-not-exhausted-on-error.js @@ -0,0 +1,27 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Per ECMA-262 IteratorClose, built-in Set iterators lack a .return() method +// and are not exhausted on abrupt completion (crbug.com/573855950). + +(function TestSetIteratorNotExhaustedOnError() { + let s = new Set([1, "a", 3]); + let it = s[Symbol.iterator](); + + assertThrows(() => Math.sumPrecise(it), TypeError); + + assertEquals({value: 3, done: false}, it.next()); + assertEquals({value: undefined, done: true}, it.next()); +})(); + +(function TestSetIteratorNotExhaustedOnErrorAndSetChanges() { + let s = new Set([1, "a", 3]); + let it = s[Symbol.iterator](); + + assertThrows(() => Math.sumPrecise(it), TypeError); + + s.add(4); + assertEquals(7, Math.sumPrecise(it)); + assertEquals({value: undefined, done: true}, it.next()); +})(); diff --git a/deps/v8/test/mjsunit/math-sum-precise/uncaught-error-message.js b/deps/v8/test/mjsunit/math-sum-precise/uncaught-error-message.js new file mode 100644 index 000000000000..fac9b05a34f3 --- /dev/null +++ b/deps/v8/test/mjsunit/math-sum-precise/uncaught-error-message.js @@ -0,0 +1,78 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Verify that uncaught exceptions thrown during Math.sumPrecise (after +// IteratorClose) preserve their pending exception message (crbug.com/572143833). + +let messages = []; +globalThis.onerror = function(msg) { + messages.push(msg); + return true; +}; + +setTimeout(() => { + Math.sumPrecise("not a number"); +}, 0); + +setTimeout(() => { + Math.sumPrecise(["not a number"]); +}, 0); + +setTimeout(() => { + Math.sumPrecise(new Set(["not a number"])); +}, 0); + +setTimeout(() => { + Math.sumPrecise({ + [Symbol.iterator]() { + return { + next() { + return { value: "not a number", done: false }; + }, + return() { + throw new Error("inner return error"); + } + }; + } + }); +}, 0); + +setTimeout(() => { + Math.sumPrecise({ + [Symbol.iterator]() { + return { + next() { + return { value: "not a number", done: false }; + }, + get return() { + throw new Error("inner return getter error"); + } + }; + } + }); +}, 0); + +setTimeout(() => { + Math.sumPrecise({ + [Symbol.iterator]() { + return { + next() { + return { value: "not a number", done: false }; + }, + return() { + return 42; + } + }; + } + }); +}, 0); + +setTimeout(() => { + globalThis.onerror = null; + assertEquals(6, messages.length); + for (const msg of messages) { + assertTrue(msg.includes("Uncaught TypeError"), msg); + } + quit(0); +}, 0); diff --git a/deps/v8/test/mjsunit/mjsunit.js b/deps/v8/test/mjsunit/mjsunit.js index 6f4de2b61fa2..fb4b808b2db4 100644 --- a/deps/v8/test/mjsunit/mjsunit.js +++ b/deps/v8/test/mjsunit/mjsunit.js @@ -133,9 +133,10 @@ var assertException; // The exception is checked against the second argument using assertEquals. var assertThrowsEquals; -// Assert that the passed promise does not resolve, but eventually throws an -// exception. The optional second argument is an exception constructor that the -// thrown exception is checked against with "instanceof". +// Assert that the passed promise (or function returning a promise) does not +// resolve, but eventually throws an exception. The optional second argument is +// an exception constructor that the thrown exception is checked against with +// "instanceof". // The optional third argument is a message type string or RegExp object that is // compared to the message of the thrown exception. var assertThrowsAsync; @@ -182,8 +183,6 @@ var assertMatches; // chain. var assertPromiseResult; -var promiseTestChain; - // These bits must be in sync with bits defined in Runtime_GetOptimizationStatus var V8OptimizationStatus = { kIsFunction: 1 << 0, @@ -638,15 +637,17 @@ var prettyPrinted; assertThrowsAsync = function assertThrowsAsync(promise, type_opt, cause_opt) { if (arguments.length > 1 && type_opt === undefined) { - failWithMessage('invalid use of assertThrows, unknown type_opt given'); + failWithMessage( + 'invalid use of assertThrowsAsync, unknown type_opt given'); } if (type_opt !== undefined && typeof type_opt !== 'function') { failWithMessage( - 'invalid use of assertThrows, maybe you want assertThrowsEquals'); + 'invalid use of assertThrowsAsync, maybe you want assertThrowsEquals'); } let msg = 'Promise did not throw exception'; if (type_opt !== undefined && type_opt.name !== undefined) msg += ', expected ' + type_opt.name; + if (typeof promise === 'function') promise = promise(); return assertPromiseResult( promise, // Use setTimeout to throw the error again to get out of the promise @@ -740,7 +741,7 @@ var prettyPrinted; assertInstanceof(promise, Promise); const stack = (new Error()).stack; - var test_promise = promise.then( + return promise.then( result => { try { if (success !== undefined) success(result); @@ -764,9 +765,6 @@ var prettyPrinted; }, 0); } }); - - if (!promiseTestChain) promiseTestChain = Promise.resolve(); - return promiseTestChain.then(test_promise); }; var OptimizationStatusImpl = undefined; diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index 5974a6eb18b9..d8970f6a209e 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -101,6 +101,56 @@ 'regress/regress-538529872-2': [SKIP], 'turboshaft/regress-523436017': [SKIP], + # TODO(572988458): Skip --harmony-struct/--shared-string-table tests. + # To be removed soon. + 'regress/regress-476509600': [SKIP], + 'regress/regress-499155348': [SKIP], + 'regress/regress-505101417': [SKIP], + 'regress/wasm/regress-474491347': [SKIP], + 'regress/wasm/regress-490877756': [SKIP], + 'turbolev/instanceof': [SKIP], + 'shared-memory/brand-checks': [SKIP], + 'shared-memory/builtins': [SKIP], + 'shared-memory/cannot-redefine-properties': [SKIP], + 'shared-memory/optimize-non-instance': [SKIP], + 'shared-memory/private-brand': [SKIP], + 'shared-memory/private-field': [SKIP], + 'shared-memory/private-name': [SKIP], + 'shared-memory/regress-488754149': [SKIP], + 'shared-memory/regress-crbug-1394741': [SKIP], + 'shared-memory/regress-crbug-1395117': [SKIP], + 'shared-memory/regress-crbug-1425710': [SKIP], + 'shared-memory/regress-crbug-1429570': [SKIP], + 'shared-memory/regress-crbug-1441241': [SKIP], + 'shared-memory/regress-crbug-1487973': [SKIP], + 'shared-memory/regress-crbug-1492013': [SKIP], + 'shared-memory/regress/regress-468231509': [SKIP], + 'shared-memory/regress/regress-469804007': [SKIP], + 'shared-memory/regress/regress-541880797': [SKIP], + 'shared-memory/shared-array-atomics': [SKIP], + 'shared-memory/shared-array-atomics-workers': [SKIP], + 'shared-memory/shared-array-concat': [SKIP], + 'shared-memory/shared-array-surface': [SKIP], + 'shared-memory/shared-array-workers': [SKIP], + 'shared-memory/shared-external-string-dictionary-lookup': [SKIP], + 'shared-memory/shared-external-string-megamorphic-ic': [SKIP], + 'shared-memory/shared-object-has-instance': [SKIP], + 'shared-memory/shared-string-copy-on-share': [SKIP], + 'shared-memory/shared-string-copy-on-share-large': [SKIP], + 'shared-memory/shared-string-in-global-object-optimized': [SKIP], + 'shared-memory/shared-string': [SKIP], + 'shared-memory/shared-string-promotion-major': [SKIP], + 'shared-memory/shared-string-promotion-minor': [SKIP], + 'shared-memory/shared-struct-atomics': [SKIP], + 'shared-memory/shared-struct-atomics-workers': [SKIP], + 'shared-memory/shared-struct-property-storage': [SKIP], + 'shared-memory/shared-struct-surface': [SKIP], + 'shared-memory/shared-struct-type-registry': [SKIP], + 'shared-memory/shared-struct-workers': [SKIP], + 'shared-memory/shared-struct-workers-optimized-code': [SKIP], + 'shared-memory/shared-value-barrier-optimization': [SKIP], + 'shared-memory/shrink-large-object': [SKIP], + ############################################################################## # Tests where variants make no sense. 'd8/enable-tracing': [PASS, NO_VARIANTS], @@ -214,6 +264,7 @@ 'regress/regress-558568713': [PASS, SLOW, NO_VARIANTS], 'regress/regress-rab-proto-oob': [PASS, SLOW, ['tsan', SKIP]], 'regress/regress-crbug-503557995-b': [PASS, ['mode != release or simulator_run', SKIP]], + 'regress/regress-crbug-540324230': [PASS, SLOW], 'regress/wasm/regress-810973': [PASS, SLOW], 'sealed-array-reduce': [PASS, SLOW], 'string-replace-gc': [PASS, SLOW], @@ -228,6 +279,7 @@ 'wasm/compare-exchange64-stress': [PASS, SLOW, NO_VARIANTS], 'wasm/code-space-overflow': [PASS, SLOW, NO_VARIANTS, ['gc_stress == True or (simulator_run and mode == debug)', SKIP]], 'wasm/max-wasm-functions': [PASS, SLOW, ['mode != release or dcheck_always_on or simulator_run or verify_predictable', SKIP], ['tsan', SKIP]], + 'wasm/test-growable-tail-call-matrix': [PASS, SLOW], 'wasm/wasm-interpreter': [PASS, SLOW], # Very slow on ARM, MIPS, RISCV and LOONG, contains no architecture dependent code. @@ -245,9 +297,6 @@ # Also disabled on Mac ASAN for https://crbug.com/v8/11437. 'regress/regress-crbug-9161': [PASS, SLOW, ['not asan or system == macos', SKIP]], - # Test is only enabled on ASAN because it relies on ASAN stack poisoning. - 'regress/regress-532288251': [PASS, ['not asan', SKIP]], - # OOM with too many isolates/memory objects (https://crbug.com/1010272) # Predictable tests fail due to race between postMessage and GrowMemory 'regress/wasm/regress-1010272': [PASS, HEAVY, NO_VARIANTS, ['system == android', SKIP], ['verify_predictable', SKIP]], @@ -269,6 +318,7 @@ 'regress/regress-1034322': [PASS, HEAVY, NO_VARIANTS, ['mode != release', SKIP]], 'regress/regress-1320641': [PASS, HEAVY], 'regress/regress-1447343': [PASS, HEAVY], + 'regress/regress-571944332': [PASS, HEAVY], 'regress/wasm/regress-523591366': [PASS, HEAVY], 'wasm/grow-huge-memory': [PASS, HEAVY], 'wasm/grow-huge-memory-resizable-buffer': [PASS, HEAVY], @@ -320,6 +370,8 @@ 'arbitrary-length-varargs-prototype-setter': [PASS, ['mode == debug or simulator_run or lower_limits_mode', SKIP]], 'regress/regress-509622555*': [['not sparkplug_plus', SKIP]], + 'sandbox/regress-567222739*': [['not sparkplug_plus', SKIP]], + 'baseline/embedded-feedback-monotonic': [['not sparkplug_plus', SKIP]], # Because of frontend lowerings being different in Maglev and Turbofan, some # unit tests don't pass when using Maglev as a frontend for Turboshaft. @@ -630,6 +682,7 @@ 'wasm/atomics-memory64': [SKIP], 'compiler/inlining-exponential': [SKIP], # Profiler test is flaky on simulators. + 'regress/wasm/regress-574704749': [SKIP], 'wasm/log-wasm-to-js-wrapper-callref': [SKIP], 'wasm/log-wasm-to-js-wrapper-indirect': [SKIP], 'es6/big-weakmap': [SKIP], @@ -661,6 +714,7 @@ # Skip tests not suitable for GC stress. 'allocation-site-info': [SKIP], 'array-constructor-feedback': [SKIP], + 'array-literal-transitions-no-pretenuring': [SKIP], 'd8/d8-performance-now': [SKIP], 'opt-elements-kind': [SKIP], 'regress/regress-trap-allocation-memento': [SKIP], @@ -678,6 +732,7 @@ 'whitespaces': [SKIP], 'baseline/*': [SKIP], 'regress/regress-chromium-1194026': [SKIP], + 'regress/regress-crbug-540324230': [SKIP], # Unsuitable for GC stress because coverage information is lost on GC. 'code-coverage-ad-hoc': [SKIP], @@ -822,7 +877,10 @@ 'sandbox/regress/regress-334120897': [SKIP], 'sandbox/regress/regress-349502157': [SKIP], + 'sandbox/regress/regress-572826713': [SKIP], + 'sandbox/regress/regress-574792351': [SKIP], 'sandbox/regress-537948358': [SKIP], + 'sandbox/regress-558640961': [SKIP], 'sandbox/wasm-inlining-sigcheck': [SKIP], 'sandbox/wasm-signature-verification': [SKIP], 'sandbox/wasm-table-import': [SKIP], @@ -845,6 +903,14 @@ ############################################################################## ['not has_wasm_interpreter or variant != jitless', { # Tests to run only with the Wasm interpreter. + 'regress/wasm/regress-drumbrake-array-segment-args': [SKIP], + 'regress/wasm/regress-drumbrake-cast-nofunc': [SKIP], + 'regress/wasm/regress-drumbrake-exception-null': [SKIP], + 'regress/wasm/regress-drumbrake-exnref': [SKIP], + 'regress/wasm/regress-drumbrake-import-context': [SKIP], + 'regress/wasm/regress-drumbrake-import-null': [SKIP], + 'regress/wasm/regress-drumbrake-return-call-subtype': [SKIP], + 'regress/wasm/regress-drumbrake-v128-js-boundary': [SKIP], 'regress/wasm/regress-interpreter-failed-reentry': [SKIP], 'wasm/wasm-interpreter-fuzzer' : [SKIP], 'wasm/wasm-interpreter-memory*' : [SKIP], @@ -860,24 +926,20 @@ ############################################################################## ['not has_wasm_interpreter', { # This sandbox regression test forces --wasm-jitless to exercise the DrumBrake - # interpreter's JS-to-Wasm wrapper. + # interpreter. 'sandbox/regress-522294322': [SKIP], # These sandbox regression tests force --wasm-jitless to exercise the # DrumBrake interpreter's InterpreterHandle handling. 'sandbox/regress-527689557-1': [SKIP], 'sandbox/regress-527689557-2': [SKIP], 'sandbox/regress-535518222': [SKIP], + 'sandbox/wasm-interpreter-reentrant-throw-overlap': [SKIP], }], # not has_wasm_interpreter -['has_wasm_interpreter and variant == jitless', { +['variant == jitless', { # Skip tests that require Wasm experimental features not supported by the # Wasm interpreter, or that explicitly require compilation. - # Wasm debugging that runs GC while paused at a trap safepoint is not - # supported by the Wasm interpreter; it crashes (BUS_ADRALN) in the DrumBrake - # safepoint path in jitless mode. Passes in JIT variants. - 'wasm/regress-534579660': [SKIP], - # --wasm-inlining 'regress/wasm/regress-crbug-1510626': [SKIP], @@ -930,6 +992,7 @@ 'regress/wasm/regress-377620832': [SKIP], 'regress/wasm/regress-410295354': [SKIP], 'regress/wasm/regress-434008619': [SKIP], + 'regress/wasm/regress-563427048': [SKIP], 'wasm/exnref*': [SKIP], 'wasm/gc-casts-exnref': [SKIP], 'wasm/gc-casts-invalid': [SKIP], @@ -949,6 +1012,8 @@ 'regress/wasm/regress-v8-14471': [SKIP], 'wasm/jspi*': [SKIP], 'wasm/growable-stacks': [SKIP], + 'wasm/growable-stacks-simd': [SKIP], + 'wasm/test-growable-tail-call-*': [SKIP], # --wasm-growable-stacks 'regress/wasm/regress-421055121': [SKIP], @@ -964,6 +1029,8 @@ 'regress/wasm/regress-493430818': [SKIP], 'regress/wasm/regress-493529579': [SKIP], 'regress/wasm/regress-493521637': [SKIP], + 'regress/wasm/regress-557846268': [SKIP], + 'regress/wasm/regress-wasmfx-unreachable-resume': [SKIP], 'wasm/cont-bind': [SKIP], 'wasm/regress-496645739': [SKIP], 'wasm/regress-497667917': [SKIP], @@ -986,6 +1053,7 @@ 'regress/wasm/regress-497330272': [SKIP], 'regress/wasm/regress-511160771': [SKIP], 'regress/wasm/regress-516109051': [SKIP], + 'regress/wasm/regress-565341967': [SKIP], 'regress/wasm/regress-crbug-1463232': [SKIP], 'regress/wasm/regress-crbug-1466312': [SKIP], 'regress/wasm/regress-v8-14710': [SKIP], @@ -1012,7 +1080,7 @@ 'regress/wasm/regress-350779988': [SKIP], 'regress/wasm/regress-366350772': [SKIP], 'regress/wasm/regress-397043084': [SKIP], - 'wasm/denormals': [SKIP], + 'regress/wasm/regress-523591366': [SKIP], 'wasm/deopt/*': [SKIP], 'wasm/enter-debug-state': [SKIP], 'wasm/liftoff-trap-handler': [SKIP], @@ -1045,7 +1113,6 @@ # --wasm-lazy-validation 'regress/wasm/regress-334687959': [SKIP], 'regress/wasm/regress-441221187': [SKIP], - 'regress/wasm/regress-505124865': [SKIP], # Wasm imported strings (just text-decoder or text-encoder) 'wasm/imported-strings-utf8': [SKIP], @@ -1074,7 +1141,11 @@ 'regress/wasm/regress-521064735': [SKIP], 'regress/wasm/regress-524830496': [SKIP], 'regress/wasm/regress-536581698': [SKIP], + 'regress/wasm/regress-552026580': [SKIP], + 'regress/wasm/regress-563068683': [SKIP], 'regress/wasm/regress-565565747': [SKIP], + 'regress/wasm/regress-567624365': [SKIP], + 'regress/wasm/regress-568629618': [SKIP], 'wasm/shared-everything/*': [SKIP], 'wasm/subtyping-invalid': [SKIP], @@ -1094,11 +1165,18 @@ 'regress/wasm/regress-407298298': [SKIP], 'regress/wasm/regress-407797300': [SKIP], 'regress/wasm/regress-408254017': [SKIP], + 'regress/wasm/regress-567481597': [SKIP], 'regress/wasm/regress-crbug-408253898': [SKIP], # --wasm-fp16 'regress/wasm/regress-499027764': [SKIP], 'regress/wasm/regress-504612573': [SKIP], + 'regress/wasm/regress-565847635': [SKIP], + 'regress/wasm/regress-567911985': [SKIP], + 'regress/wasm/regress-570433240': [SKIP], + 'regress/wasm/regress-570433264': [SKIP], + 'regress/wasm/regress-573260377': [SKIP], + 'regress/wasm/regress-simd-526303932': [SKIP], 'wasm/fp16-load-mul': [SKIP], 'wasm/fp16-oob-trap': [SKIP], 'wasm/fp16-store': [SKIP], @@ -1139,8 +1217,12 @@ 'regress/wasm/regress-457106696': [SKIP], 'regress/wasm/regress-513063392': [SKIP], 'regress/wasm/regress-525437482': [SKIP], + 'regress/wasm/regress-561662099': [SKIP], + 'regress/wasm/regress-563427048*': [SKIP], + 'regress/wasm/regress-567171844': [SKIP], 'wasm/custom-descriptors*': [SKIP], 'wasm/exact-types': [SKIP], + 'wasm/wasm-gc-js-roundtrip': [SKIP], # --wasm-compact-imports 'wasm/compact-imports': [SKIP], @@ -1149,6 +1231,7 @@ 'regress/wasm/regress-515525741': [SKIP], 'regress/wasm/regress-516102112-1': [SKIP], 'regress/wasm/regress-simd-520944504': [SKIP], + 'wasm/wide-add': [SKIP], 'wasm/wide-arithmetic': [SKIP], # --wasm-imported-strings-utf8 @@ -1170,13 +1253,14 @@ 'regress/wasm/regress-8896': [SKIP], 'wasm/compiled-module-serialization': [SKIP], 'wasm/print-code': [SKIP], + 'wasm/regress-535877252-2': [SKIP], # Compiled-wrapper stack headroom. # Other tests that require compilation. 'compiler/fast-api-calls-wasm': [SKIP], + 'maglev/regress-498199197': [SKIP], 'regress/wasm/regress-403308742': [SKIP], 'regress/wasm/regress-488943662': [SKIP], - 'regress/wasm/regress-526163463': [SKIP], # --wasm-code-coverage - 'wasm/regression-521715545': [SKIP], # --wasm-code-coverage + 'regress/wasm/regress-505124865': [SKIP], # --wasm-compilation-hints 'wasm/async-compile': [SKIP], 'wasm/log-code-after-post-message': [SKIP], 'wasm/multiple-code-spaces': [SKIP], @@ -1184,6 +1268,7 @@ 'wasm/wrapper-compilation': [SKIP], # Tests that expect different profiling samples. + 'regress/wasm/regress-574704749': [SKIP], 'wasm/log-wasm-to-js-wrapper-indirect': [SKIP], # Interpreter stack trace not fully implemented yet. @@ -1192,7 +1277,6 @@ # d8.exe --no-wasm-trap-handler. 'regress/wasm/regress-842501': [SKIP], - 'regress/wasm/regress-513413942': [SKIP], # TODO(paolosev): Support Wasm to JS calls to JSApiObjects. 'wasm/ffi': [SKIP], @@ -1228,16 +1312,21 @@ 'regress/wasm/regress-511772679': [SKIP], 'regress/wasm/regress-518697709': [SKIP], 'regress/wasm/regress-524792614': [SKIP], - 'regress/wasm/regress-530658019': [SKIP], 'regress/wasm/regress-535659723': [SKIP], 'regress/wasm/regress-538378084': [SKIP], 'regress/wasm/regress-540446645': [SKIP], 'regress/wasm/regress-543901836': [SKIP], + 'regress/wasm/regress-561660149': [SKIP], 'regress/wasm/regress-crbug-1507751': [SKIP], 'regress/wasm/regress-simd-518058891': [SKIP], 'regress/wasm/regress-simd-525600038': [SKIP], 'regress/wasm/regress-simd-526303929': [SKIP], 'regress/wasm/regress-simd-528884838': [SKIP], + 'regress/wasm/regress-simd-549328680*': [SKIP], + 'regress/wasm/regress-simd-555760230': [SKIP], + 'regress/wasm/regress-simd-555806042*': [SKIP], + 'regress/wasm/regress-simd-557107349': [SKIP], + 'regress/wasm/regress-simd-570497964': [SKIP], 'wasm/bit-shift-right': [SKIP], 'wasm/bounds-check-turbofan': [SKIP], 'wasm/enter-and-leave-debug-state': [SKIP], @@ -1283,6 +1372,7 @@ 'regress/wasm/regress-498814570': [SKIP], 'regress/wasm/regress-498818401': [SKIP], 'regress/wasm/regress-500113958': [SKIP], + 'regress/wasm/regress-555812363': [SKIP], # The interpreter call stack contains an additional top frame if we throw a # type-mismatch exception before executing the Wasm function. @@ -1376,9 +1466,11 @@ # RegExp unicode tests relies on ICU for property classes and # case-insensitive unicode patterns. + 'harmony/regexp-unicode-sets-class-string-disjunction': [SKIP], 'regexp-unicode-sets': [PASS,FAIL], 'regexp-not-jetstream': [SKIP], 'regexp-jetstream': [SKIP], + 'regress/regress-571871980': [SKIP], # The noi18n build cannot parse characters in supplementary plane. 'harmony/regexp-named-captures': [FAIL], @@ -1402,6 +1494,7 @@ 'regress/regress-crbug-335592010': [SKIP], 'regress/regress-352402863': [SKIP], 'regress/regress-549231120': [SKIP], + 'regress/regress-557076207': [SKIP], 'string-localecompare-inline': [SKIP], # Non-BMP characters currently aren't considered identifiers without i18n @@ -1805,12 +1898,6 @@ # MIPS64 port doesn't support maglev yet. 'turbolev/*': [SKIP], - - # Flush to zero is not supported yet. - 'd8/flush-denormals-flag': [SKIP], - 'd8/flush-denormals-helper': [SKIP], - 'd8/flush-denormals-worker': [SKIP], - 'wasm/denormals': [SKIP] }], # 'arch == mips64el or arch == mips64' ############################################################################## @@ -1819,12 +1906,6 @@ # This test fail because when convert sNaN to qNaN, loong64 use a different # qNaN encoding with x86 architectures 'wasm/float-constant-folding': [SKIP], - - # Flush to zero is not supported yet. - 'd8/flush-denormals-flag': [SKIP], - 'd8/flush-denormals-helper': [SKIP], - 'd8/flush-denormals-worker': [SKIP], - 'wasm/denormals': [SKIP] }], # 'arch == loong64' ############################################################################## @@ -1871,12 +1952,6 @@ # This often fails in debug mode because it is too slow. 'd8/d8-performance-now': [PASS, ['mode == debug', SKIP]], - - # Flush to zero is not supported yet. - 'd8/flush-denormals-flag': [SKIP], - 'd8/flush-denormals-helper': [SKIP], - 'd8/flush-denormals-worker': [SKIP], - 'wasm/denormals': [SKIP], }], # 'arch == riscv64 or arch == riscv32' @@ -2005,6 +2080,7 @@ # The test enables the global profiler, and there can only exist one profiler # at a time. + 'regress/wasm/regress-574704749': [SKIP], 'wasm/log-code-after-post-message': [SKIP], # These test cases assert on the exact amount of deopts happening between two @@ -2012,6 +2088,9 @@ 'wasm/deopt/deopt-dynamic-tierup': [SKIP], 'wasm/deopt/deopt-metrics': [SKIP], + # These test cases assume a specific pattern of deopting and tiering-up. + 'wasm/compilation-hints/hints-and-deopts': [SKIP], + # The test explicitly deserializes a wasm module and expects the resulting # wasm module to match the serialized one. With multiple isolate the resulting # wasm module can however, come from the native module cache, and therefore @@ -2043,6 +2122,10 @@ 'compiler/regress-519664497': [SKIP], 'turboshaft/regress-539984773': [SKIP], + # Exhausts 32-bit virtual address space across concurrent isolates, causing + # Worker thread creation to fail (https://crbug.com/577898450). + 'regress/regress-571944332': [SKIP], + }], # 'isolates' ############################################################################## @@ -2107,6 +2190,7 @@ # Tests that fail some assertions due to checking internal state sensitive # to GC. + 'array-literal-transitions-no-pretenuring': [SKIP], 'compiler/native-context-specialization-hole-check': [SKIP], 'compiler/serializer-apply': [SKIP], 'compiler/serializer-call': [SKIP], @@ -2243,6 +2327,7 @@ 'd8/d8-worker-shutdown-gc': [SKIP], 'd8/d8-worker-onmessage-ping-pong': [SKIP], 'harmony/futex': [SKIP], + 'regress/regress-571944332': [SKIP], 'typedarray-growablesharedarraybuffer-atomics': [SKIP], # Tests using a shared heap are inherently non-deterministic. @@ -2271,6 +2356,7 @@ 'regress/regress-crbug-1237153': [SKIP], 'regress/wasm/regress-1067621': [SKIP], 'regress/wasm/regress-377942344': [SKIP], + 'regress/wasm/regress-575514140': [SKIP], # BUG(v8:9975). 'es6/typedarray-copywithin': [SKIP], @@ -2283,6 +2369,7 @@ # allocations. 'regress/regress-1394663': [SKIP], 'regress/wasm/regress-crbug-1502180': [SKIP], + 'regress/wasm/regress-574704749': [SKIP], 'wasm/log-wasm-to-js-wrapper-callref': [SKIP], 'wasm/log-wasm-to-js-wrapper-indirect': [SKIP], @@ -2312,17 +2399,9 @@ 'regress/wasm/regress-368086282': [SKIP], 'regress/wasm/regress-438770394': [SKIP], - # Flush to zero is not supported yet. - 'd8/flush-denormals-flag': [SKIP], - 'd8/flush-denormals-helper': [SKIP], - 'd8/flush-denormals-worker': [SKIP], - 'wasm/denormals': [SKIP], - # Wasm code coverage is not supported yet. 'regress/wasm/regress-488943662': [SKIP], 'wasm/wasm-code-coverage': [SKIP], - 'wasm/regression-521715545': [SKIP], - 'regress/wasm/regress-526163463': [SKIP] }], # arch in [ppc64, s390x]' ############################################################################## @@ -2740,13 +2819,20 @@ ############################################################################## ['variant == stress_incremental_marking', { + # Incremental marking GCs can clear young-generation AllocationMementos + # before elements kind transitions occur. + 'array-literal-transitions-no-pretenuring': [SKIP], 'harmony/sharedarraybuffer-worker-gc-stress': [PASS, ['gc_stress', SKIP]], + 'regress/regress-crbug-540324230': [SKIP], 'regress/regress-crbug-820312': [PASS, SLOW], 'wasm/shared-memory-worker-stress': [PASS, SLOW, ['tsan', SKIP]], }], # variant == stress_incremental_marking ############################################################################## ['variant == stress_concurrent_allocation', { + # Concurrent allocations trigger GCs that clear AllocationMementos before + # elements kind transitions occur. + 'array-literal-transitions-no-pretenuring': [SKIP], # This test manually forces pretenuring of allocation sites. # stress-concurrent-allocation reverts the pretenuring decision due to low # survival rate in old generation. @@ -2785,6 +2871,7 @@ 'wasm/deopt/deopt-value-types': [SKIP], 'wasm/exceptions-simd': [SKIP], 'wasm/growable-stacks': [SKIP], + 'wasm/growable-stacks-simd': [SKIP], 'wasm/interleaved-loads': [SKIP], 'wasm/js-to-js': [SKIP], 'wasm/large-struct': [SKIP], @@ -2864,6 +2951,10 @@ 'regress/wasm/regress-504612573': [SKIP], 'regress/wasm/regress-504711585': [SKIP], 'regress/wasm/regress-513250424': [SKIP], + 'regress/wasm/regress-565847635': [SKIP], + 'regress/wasm/regress-567911985': [SKIP], + 'regress/wasm/regress-570433240': [SKIP], + 'regress/wasm/regress-570433264': [SKIP], 'regress/wasm/regress-crbug-1338980': [SKIP], 'regress/wasm/regress-crbug-1355070': [SKIP], 'regress/wasm/regress-crbug-1356718': [SKIP], @@ -2910,43 +3001,20 @@ ['single_generation', { # These tests rely on allocation site tracking which only works in the young generation. 'array-constructor-feedback': [SKIP], - 'wasm/generic-wrapper': [SKIP], + 'array-literal-transitions-no-pretenuring': [SKIP], 'wasm/gc-casts-invalid': [SKIP], 'regress/regress-trap-allocation-memento': [SKIP], - 'regress/regress-crbug-1151890': [SKIP], - 'regress/regress-crbug-1163184': [SKIP], - 'regress/regress-11519': [SKIP], 'regress/regress-4121': [SKIP], - 'packed-elements': [SKIP], 'compiler/native-context-specialization-hole-check': [SKIP], 'compiler/test-literal-map-migration': [SKIP], 'compiler/deopt-pretenure': [SKIP], 'compiler/fast-api-sequences-x64': [SKIP], - 'compiler/regress-store-store-elim': [SKIP], # TODO(v8:12031): Reimplement elements kinds transitions when concurrent # inlining. 'default-nospec': [SKIP], 'es6/collections-constructor-*': [SKIP], 'es6/map-constructor-entry-side-effect*': [SKIP], - # These tests use %SimulateNewspaceFull, which only works in the young generation - 'regress/regress-1424415': [SKIP], - 'regress/wasm/regress-375314963': [SKIP], - 'wasm/jspi-export': [SKIP], - 'wasm/jspi-generic-wrapper': [SKIP], - 'wasm/jspi-no-stress': [SKIP], - 'regress/wasm/regress-v8-14471': [SKIP], - 'regress/wasm/regress-346597059': [SKIP], - 'regress/wasm/regress-349640002': [SKIP], - 'regress/wasm/regress-455832038': [SKIP], - 'regress/wasm/regress-483269968': [SKIP], - 'regress/wasm/regress-543901836': [SKIP], - 'regress/wasm/regress-560536735': [SKIP], - 'regress/wasm/regress-561660149': [SKIP], - 'regress/wasm/regress-574223268': [SKIP], - 'compiler/regress-347724915': [SKIP], - 'regress/regress-crbug-418520151': [SKIP], - 'regress/regress-535000102': [SKIP], # TODO(v8:14581): Re-enable this test once TransitionElementsKindOrCheckMap is # supported by the Maglev->Turboshaft graph builder. @@ -2999,10 +3067,15 @@ }], # (arch == mips64el) ############################################################################## -['arch != arm64 and arch != x64 and arch != arm and arch != ia32 and arch != loong64 and arch != riscv64 and arch != ppc64 and arch != s390x', { +['arch != arm64 and arch != x64 and arch != arm and arch != ia32 and arch != riscv64 and arch != ppc64 and arch != s390x', { # Growable stacks are not supported on all platforms.. - 'wasm/growable-stacks': [SKIP] -}], # (arch != arm64 and arch != x64 and arch != arm and arch != ia32 and arch != loong64 and arch != riscv64 and arch != ppc64 and arch != s390x) + 'wasm/growable-stacks': [SKIP], + 'wasm/growable-stacks-simd': [SKIP], + 'wasm/test-growable-tail-call-*': [SKIP], + 'regress/wasm/regress-421055121': [SKIP], + 'regress/wasm/regress-513250424': [SKIP], + 'regress/wasm/regress-520777574': [SKIP], +}], # (arch != arm64 and arch != x64 and arch != arm and arch != ia32 and arch != riscv64) ############################################################################## ['arch != x64 and arch != arm64 and arch != loong64 and arch != mips64 and arch != riscv64', { @@ -3045,6 +3118,7 @@ ['arch in [mips64, ppc64, s390x]', { # --wasm-deopt implementation not ported to all architectures, yet. 'wasm/deopt/*': [SKIP], + 'wasm/compilation-hints/hints-and-deopts': [SKIP], 'regress/wasm/regress-350779988': [SKIP], 'regress/wasm/regress-353582136': [SKIP], 'regress/wasm/regress-353913485': [SKIP], @@ -3068,6 +3142,11 @@ 'regress/regress-425583995': [SKIP], 'regress/regress-490446682': [SKIP], 'regress/regress-506499280-extended': [SKIP], + 'regress/regress-571944332': [SKIP], + # These tests fail because of a different ArrayBufferAllocator is used in + # google3. + 'huge-typedarrays-*': [SKIP], + 'regress/regress-354626177': [SKIP], # Needs temporal: 'regress/regress-463593768': [SKIP], @@ -3075,6 +3154,7 @@ 'regress/regress-temporal-zoneinfo': [SKIP], 'regress/regress-493269623': [SKIP], 'regress/regress-495503781': [SKIP], + 'regress/regress-572400584': [SKIP], # TODO(victorgomes): 'es6/unicode-regexp-ignore-case-noi18n': [SKIP], @@ -3086,10 +3166,6 @@ # TODO(b/201757247): 'array-constructor-feedback': [FAIL], 'compiler/deopt-pretenure': [FAIL], - 'compiler/native-context-specialization-hole-check': [FAIL], - 'compiler/test-literal-map-migration': [FAIL], - 'regress/regress-4121': [FAIL], - 'regress/regress-trap-allocation-memento': [FAIL], # TODO(v8:14581): Re-enable this once turboshaft frontend is done. 'turbolev/*': [SKIP], @@ -3172,6 +3248,7 @@ ############################################################################## ['variant == stress_wasm_stack_switching', { # TODO(thibaudm): Fix profiler. + 'regress/wasm/regress-574704749': [SKIP], 'wasm/log-wasm-to-js-wrapper-callref': [SKIP], 'wasm/log-wasm-to-js-wrapper-indirect': [SKIP], }], @@ -3187,6 +3264,8 @@ # It does not support multiple stacks yet. 'wasm/jspi*': [SKIP], 'wasm/growable-stacks': [SKIP], + 'wasm/growable-stacks-simd': [SKIP], + 'wasm/test-growable-tail-call-*': [SKIP], 'regress/wasm/regress-v8-14471': [SKIP], 'regress/wasm/regress-336852356': [SKIP], 'regress/wasm/regress-336358915': [SKIP], @@ -3266,12 +3345,6 @@ 'regress/regress-392928803': [FAIL], }], # not disassembler -############################################################################## -# https://issues.chromium.org/issues/404881599 -['(arch == arm64) and simulator_run', { -'wasm/growable-stacks': [SKIP], -}], # (arch == arm64) and simulator_run - ############################################################################## ['sandbox_hardware_support', { # Skip tests for unsupported features. See https://crbug.com/428674890. @@ -3298,7 +3371,6 @@ # Wasm code coverage is not currently supported. 'regress/wasm/regress-488943662': [SKIP], 'wasm/wasm-code-coverage': [SKIP], - 'regress/wasm/regress-526163463': [SKIP], # Tests that require the sampler/profiler, which doesn't work on older kernel # versions if hardware sandboxing is active. See https://crbug.com/429173713. @@ -3311,11 +3383,14 @@ 'regress/wasm/regress-406043349': [SKIP], 'regress/wasm/regress-413963387': [SKIP], 'regress/wasm/regress-562455563': [SKIP], + 'regress/wasm/regress-573446890': [SKIP], + 'regress/wasm/regress-574704749': [SKIP], 'wasm/interrupt-worker-with-perf': [SKIP], 'wasm/liftoff-trap-handler': [SKIP], 'wasm/log-code-after-post-message': [SKIP], 'wasm/log-wasm-to-js-wrapper-callref': [SKIP], 'wasm/log-wasm-to-js-wrapper-indirect': [SKIP], + 'wasm/stack-switching-profiler': [SKIP], }], # sandbox_hardware_support ['variant == experimental_regexp', { @@ -3498,6 +3573,7 @@ 'regress/regress-464961493': [SKIP], 'regress/regress-493269623': [SKIP], 'regress/regress-495503781': [SKIP], + 'regress/regress-572400584': [SKIP], 'regress/regress-temporal-zoneinfo': [SKIP], }], diff --git a/deps/v8/test/mjsunit/parser/array-literal-fast-path.js b/deps/v8/test/mjsunit/parser/array-literal-fast-path.js new file mode 100644 index 000000000000..8bf9e4c14ce7 --- /dev/null +++ b/deps/v8/test/mjsunit/parser/array-literal-fast-path.js @@ -0,0 +1,89 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function testParsing(run_expr, run_stmt) { + // Correct values and holes + assertEquals([1, 2, , 3], run_expr("[1, 2, , 3]")); + assertEquals([, 1], run_expr("[, 1]")); + assertEquals([1, ], run_expr("[1, ]")); + assertEquals([null, true, false, "s", 1.5, 0x10], + run_expr('[null, true, false, "s", 1.5, 0x10]')); + assertEquals([1n, 16n, 18446744073709551616n], + run_expr('[1n, 0x10n, 18446744073709551616n]')); + assertEquals([1, 2], run_expr('[1/*]*/,2]')); + assertEquals([1, 2], run_expr('[1//comment\n,2]')); + assertEquals([1], run_expr('[1\u00a0]')); + assertEquals([3], run_expr('[1/*]*/+2]')); + + // Syntax errors + assertThrows(() => run_expr("[1] = x"), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr("[...1] = x"), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr("[1, 2] = x"), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr("[1n] = x"), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr("([1n]) => 0"), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr('[1, "s".x] = []'), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr('[1, ...[], 2] = []'), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_expr("([1]) => 0"), SyntaxError, + "Invalid destructuring assignment target"); + assertThrows(() => run_stmt("for ([1] of []) {}"), SyntaxError, + "Invalid destructuring assignment target"); + + // Keep existing behavior + assertEquals([3], run_expr("[1 + 2]")); + assertThrows(() => run_expr("[1 2]"), SyntaxError); + assertEquals([false], run_stmt('var o = {}; return ["a" in o];')); + assertEquals([2], run_expr("[1 ? 2 : 3]")); + assertThrows(() => run_expr("[1.toString]"), SyntaxError, + "Invalid or unexpected token"); + assertEquals(["1"], run_expr("[1..toString()]")); + assertEquals(["1"], run_expr("[1n.toString()]")); + assertEquals([1], run_expr('["s".length]')); + assertEquals([1], run_expr('["s"?.length]')); + assertEquals(["s"], run_expr('["s"[0]]')); + assertEquals([undefined], run_expr('[null?.x]')); + assertEquals([8, 2n], run_expr('[2 ** 3, 1n + 1n]')); + assertEquals([2, true, 3], run_expr('[1 && 2, true || false, null ?? 3]')); + assertEquals([true], run_expr('["x" in {x: 1}]')); + assertThrows(() => run_expr('[null ?? true || false]'), SyntaxError); + assertThrows(() => run_expr("[1 = 2]"), SyntaxError, + "Invalid left-hand side in assignment"); + + // Legacy octal literals + assertEquals([1, 8], run_expr("[01, 08]")); + assertThrows(() => run_stmt("'use strict'; [01, 08]"), SyntaxError, + "Decimals with leading zeros are not allowed in strict mode."); + assertThrows(() => run_stmt("'use strict'; [08]"), SyntaxError, + "Decimals with leading zeros are not allowed in strict mode."); +} + +// Eagerly parsed +testParsing( + src => eval("(" + src + ")"), + src => { + let f; + eval("f = function() { " + src + " }"); + return f(); + } +); + +// Lazily compiled (preparser path) +testParsing( + src => { + let f; + eval("f = function() { return (" + src + "); }"); + return f(); + }, + src => { + let f; + eval("f = function() { " + src + " }"); + return f(); + } +); diff --git a/deps/v8/test/mjsunit/regexp-boyer-moore-backtrack.js b/deps/v8/test/mjsunit/regexp-boyer-moore-backtrack.js new file mode 100644 index 000000000000..160fc8a92c6c --- /dev/null +++ b/deps/v8/test/mjsunit/regexp-boyer-moore-backtrack.js @@ -0,0 +1,9 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +assertEquals(1, /[B]|.+?!^/s.exec('1B').index); +assertEquals(0, /(?s:.*?D)?^/.exec('').index); +assertEquals(0, /[^]+?w^|/.exec('a').index); +assertEquals(0, /.*?1^|/s.exec('A,A ').index); +assertEquals(0, /.+?](^)|/s.exec('0').index); diff --git a/deps/v8/test/mjsunit/regexp-unicode-sets.js b/deps/v8/test/mjsunit/regexp-unicode-sets.js index 98c4309f980a..602f6a910801 100644 --- a/deps/v8/test/mjsunit/regexp-unicode-sets.js +++ b/deps/v8/test/mjsunit/regexp-unicode-sets.js @@ -232,6 +232,20 @@ assertEquals(['xyz'], /[\q{W|xyz|xy}a-c]/v.exec('xyzabc')); // Empty string is last. assertEquals(['a'], /[\q{W|}a-c]/v.exec('abc')); +// Lone lead and trail surrogates in \q{} should not combine into a surrogate +// pair unless written as a literal surrogate pair or \uXXXX\uYYYY. +assertFalse(/^[\q{\uD83D\u{DE00}}]$/v.test('\u{1F600}')); +assertFalse(/^[\q{\u{D83D}\u{DE00}}]$/v.test('\u{1F600}')); +assertFalse(/^[\q{\u{D83D}\uDE00}]$/v.test('\u{1F600}')); +assertFalse(/^[\q{\uD83D\u{DE00}x}]$/v.test('\u{1F600}x')); +assertFalse(/^[\q{\uD83D\u{DE00}}]$/iv.test('\u{1F600}')); +assertFalse(new RegExp('^[\\q{\uD83D\\uDE00}]$', 'v').test('\u{1F600}')); +assertFalse(new RegExp('^[\\q{\\uD83D\uDE00}]$', 'v').test('\u{1F600}')); +assertTrue(/^[\q{\uD83D\uDE00}]$/v.test('\u{1F600}')); +assertTrue(/^[\q{😀}]$/v.test('\u{1F600}')); +assertTrue(/^[\q{\u{1F600}}]$/v.test('\u{1F600}')); +assertTrue(new RegExp('^[\\q{\uD83D\uDE00}]$', 'v').test('\u{1F600}')); + // Some more sophisticated tests taken from // https://v8.dev/features/regexp-v-flag assertTrue(/^\p{RGI_Emoji}$/v.test('⚽')); @@ -278,3 +292,16 @@ assertEquals('XXXXXX4#', 'aAbBcC4#'.replaceAll(/\p{Lowercase_Letter}/giv, 'X')); assertEquals('XXXXXX4#', 'aAbBcC4#'.replaceAll(/[^\P{Lowercase_Letter}]/giv, 'X')); assertFalse(/\P{ASCII}/iv.test('K')); assertFalse(/^\P{Lowercase}/iv.test('A')); + +// \p{ASCII} must be closed over simple case folding in /vi mode, adding +// U+017F (LATIN SMALL LETTER LONG S, folds to 's') and U+212A (KELVIN SIGN, +// folds to 'k'). +assertTrue(/\p{ASCII}/vi.test('\u017f')); +assertTrue(/\p{ASCII}/vi.test('\u212a')); +assertFalse(/\P{ASCII}/vi.test('\u017f')); +assertFalse(/\P{ASCII}/vi.test('\u212a')); +assertTrue(/[\p{ASCII}&&\p{Lowercase}]/vi.test('\u212a')); +assertFalse(/[\p{Any}--\p{ASCII}]/vi.test('\u017f')); +// Without /i there is no case-fold closure. +assertFalse(/\p{ASCII}/v.test('\u017f')); +assertTrue(/\P{ASCII}/v.test('\u212a')); diff --git a/deps/v8/test/mjsunit/regexp/drain.js b/deps/v8/test/mjsunit/regexp/drain.js index 5bcf188d125f..ca5eee36dccf 100644 --- a/deps/v8/test/mjsunit/regexp/drain.js +++ b/deps/v8/test/mjsunit/regexp/drain.js @@ -329,6 +329,9 @@ assertEquals((1 << 20) + 1, // A sibling alternative must match at the original position, not at a // leaked extent: the grant is revoked on any backtrack retarget. check(/[ab]*c|/, "abx", [""], 0); +// Unrolling %{1} enables masked dispatch; the parked loop must not skip B. +check(/%{1}~|9()|B|%*^>/, "a%B9", ["B", undefined], 2); +check(/%{1}~|9()|B|%*^>/, "a%B", ["B", undefined], 2); check(/\w*\b=|/, "ab!", [""], 0); check(/[ab]+c|/, "abx", [""], 0); @@ -385,6 +388,19 @@ assertEquals(["ab=", "cd="], "ab= cd=".match(/\w*\b=/g)); // Captures across parked give-ups. check(/(\w+)\b=(\d)/, "ab cd=7", ["cd=7", "cd", "7"], 3); +// Later starts reach the same loop extent with a different capture. A failed +// backreference at the first start must not skip a successful later start. +check(/(?<g0>A+9)\k<g0>/, "AA9A9", ["A9A9", "A9"], 1); +check(/(A*9)\1/, "AA9A9", ["A9A9", "A9"], 1); +check(/(A+)9\1/, "AA9A", ["A9A", "A"], 1); +check(/(?<g0>A+9)\k<g0>/iu, "AA9a9", ["A9a9", "A9"], 1); +check(/(?<g0>A+9)\k<g0>/, "\u0100AA9A9", ["A9A9", "A9"], 2); + +// Unreferenced captures and captures written after the loop retain their +// existing drain reductions. +check(/(A+)9/, "AAA!AA9", ["AA9", "AA"], 4); +check(/A+(9)\1/, "AAA!AA99", ["AA99", "9"], 4); + // A parked give-up can land exactly at the subject end (impossible for // AT_END shapes); the search-retry re-entry must bounds-check its reload. check(/\w+\b=/, "dddd", null); @@ -401,6 +417,7 @@ check(/\w*\b$/, "", null); // would time out at O(n^2). const run = "a".repeat(1 << 20); check(/[a-z]+0/, run + "!", null); +check(/a+(9)\1/, run + "!", null); check(/\w+\b=/, run + "!", null); check(/\w*\b=/, run + "!", null); assertEquals((1 << 20) + 1, /[a-z]*0/.exec(run + "0")[0].length); diff --git a/deps/v8/test/mjsunit/regress/fast-proxy-load-ic-bailouts.js b/deps/v8/test/mjsunit/regress/fast-proxy-load-ic-bailouts.js index 13d36147a4bd..e9f0c6dd7427 100644 --- a/deps/v8/test/mjsunit/regress/fast-proxy-load-ic-bailouts.js +++ b/deps/v8/test/mjsunit/regress/fast-proxy-load-ic-bailouts.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --fast-proxy-ic --allow-natives-syntax --turbofan +// Flags: --fast-proxy-ic --allow-natives-syntax // 1. Operation Type Bailouts @@ -318,9 +318,10 @@ // 5. Positive Inlining Test (function TestTrapInlining() { const target = { a: 42 }; + let should_deopt = false; const handler = { get(t, p, r) { - %DeoptimizeNow(); + if (should_deopt) %DeoptimizeNow(); return t[p] + 1; } }; @@ -339,8 +340,15 @@ %OptimizeFunctionOnNextCall(load); assertEquals(43, load(proxy)); + const was_maglev = + (%GetOptimizationStatus(load) & V8OptimizationStatus.kMaglevved) !== 0; - // If the trap was successfully inlined into `load`, the `%DeoptimizeNow()` - // call inside the trap will deoptimize the `load` function itself. - assertUnoptimized(load); + should_deopt = true; + assertEquals(43, load(proxy)); + + // If the trap was successfully inlined into `load` by Maglev, the + // `%DeoptimizeNow()` call inside the trap will deoptimize `load` itself. + if (was_maglev) { + assertUnoptimized(load); + } })(); diff --git a/deps/v8/test/mjsunit/regress/regress-108296.js b/deps/v8/test/mjsunit/regress/regress-108296.js index a38d0e4396f7..7c905a55baf7 100644 --- a/deps/v8/test/mjsunit/regress/regress-108296.js +++ b/deps/v8/test/mjsunit/regress/regress-108296.js @@ -40,7 +40,7 @@ function f(k, a, b) { %PrepareFunctionForOptimization(f); var a = {}; -// Make sure that foo is a CONSTANT_FUNCTION but not be pretenured. +// Make sure that foo is a CONSTANT_FUNCTION in new space. a.foo = function() { return function() {}; }(); diff --git a/deps/v8/test/mjsunit/regress/regress-1494681.js b/deps/v8/test/mjsunit/regress/regress-1494681.js index b95994a8e9cd..03c95f4dcb65 100644 --- a/deps/v8/test/mjsunit/regress/regress-1494681.js +++ b/deps/v8/test/mjsunit/regress/regress-1494681.js @@ -4,4 +4,4 @@ assertThrows( () => eval('A interface'), SyntaxError, - 'Unexpected identifier \'undefined\''); + 'Unexpected identifier \'interface\''); diff --git a/deps/v8/test/mjsunit/regress/regress-440528038.js b/deps/v8/test/mjsunit/regress/regress-440528038.js deleted file mode 100644 index 9260e1ae7acf..000000000000 --- a/deps/v8/test/mjsunit/regress/regress-440528038.js +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax --fuzzing - -const v1 = %AtomicsSynchronizationPrimitiveNumWaitersForTesting(Atomics); diff --git a/deps/v8/test/mjsunit/regress/regress-461969023.js b/deps/v8/test/mjsunit/regress/regress-461969023.js index 79e5369b2b4c..12d900e1a0e9 100644 --- a/deps/v8/test/mjsunit/regress/regress-461969023.js +++ b/deps/v8/test/mjsunit/regress/regress-461969023.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --shared-string-table +// Flags: --allow-natives-syntax --shared-strings for (let v1 = 0; v1 < 5; v1++) { const v3 = %ShareObject(("6").repeat(v1)); diff --git a/deps/v8/test/mjsunit/regress/regress-498904299.js b/deps/v8/test/mjsunit/regress/regress-498904299.js index 18d4f63b2e64..3b9658cf1684 100644 --- a/deps/v8/test/mjsunit/regress/regress-498904299.js +++ b/deps/v8/test/mjsunit/regress/regress-498904299.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --flush-denormals +// Flags: --allow-natives-syntax function divByPow2(x) { return x / 8.98846567431158e+307; // 2^1023 diff --git a/deps/v8/test/mjsunit/regress/regress-505481956.js b/deps/v8/test/mjsunit/regress/regress-505481956.js index 2c6bb35ea63e..6feb8ac805b5 100644 --- a/deps/v8/test/mjsunit/regress/regress-505481956.js +++ b/deps/v8/test/mjsunit/regress/regress-505481956.js @@ -20,7 +20,7 @@ const o = create(holeNaN); f64[0] = o.key; -assertNotEquals(Array.from(u32), [0xFFF7FFFF, 0xFFF7FFFF]); +assertTrue(isNaN(o.key)); function test() { let v = o.key; @@ -33,4 +33,8 @@ for (let i = 0; i < 100; i++) test(); let result = test(); f64[0] = result; -assertNotEquals(Array.from(u32), [0xFFF7FFFF, 0xFFF7FFFF]); +assertTrue(isNaN(result)); + +o.key = 42; +assertEquals(42, o.key); +assertEquals(42, test()); diff --git a/deps/v8/test/mjsunit/regress/regress-514561070.js b/deps/v8/test/mjsunit/regress/regress-514561070.js deleted file mode 100644 index 1b357ea43c45..000000000000 --- a/deps/v8/test/mjsunit/regress/regress-514561070.js +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector - -Array.prototype.__defineGetter__(0, function() { - return new Number(); -}); -send(JSON.stringify({ - id: 1, - method: 'Runtime.evaluate', - params: {includeCommandLineAPI: true, expression: ''} -})); diff --git a/deps/v8/test/mjsunit/regress/regress-516022777.js b/deps/v8/test/mjsunit/regress/regress-516022777.js deleted file mode 100644 index 6a254db1ae1b..000000000000 --- a/deps/v8/test/mjsunit/regress/regress-516022777.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector - -Object.defineProperty(Array.prototype, 0, { - set() { - throw 42; - } -}); -send(JSON.stringify({ - id: 1, - method: 'Runtime.evaluate', - params: {includeCommandLineAPI: true, expression: ''} -})); diff --git a/deps/v8/test/mjsunit/regress/regress-521520188.js b/deps/v8/test/mjsunit/regress/regress-521520188.js new file mode 100644 index 000000000000..553296e0f926 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-521520188.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +class Klass { + #field = 1; + #method() {} + get #getter() { return 2; } + set #setter(v) {} + static #staticField = 3; + static #staticMethod() {} +} + +class SubWithConflict extends Klass { + #field = 4; +} + +globalThis.Klass = Klass; +globalThis.obj = new Klass(); +globalThis.conflictObj = new SubWithConflict(); +globalThis.res = undefined; + +async function evalREPL(expr) { + await %RuntimeEvaluateREPL(`res = (${expr})`); + return globalThis.res; +} + +async function test() { + assertEquals(false, await evalREPL('#brand in globalThis')); + assertEquals(true, await evalREPL('#field in obj')); + assertEquals(true, await evalREPL('#method in obj')); + assertEquals(true, await evalREPL('#getter in obj')); + assertEquals(true, await evalREPL('#setter in obj')); + assertEquals(false, await evalREPL('#staticField in obj')); + assertEquals(true, await evalREPL('#staticField in Klass')); + assertEquals(true, await evalREPL('#staticMethod in Klass')); + + await assertThrowsAsync(%RuntimeEvaluateREPL('#field in 1'), TypeError); + await assertThrowsAsync(%RuntimeEvaluateREPL('#field in conflictObj'), Error); +} + +assertPromiseResult(test()); diff --git a/deps/v8/test/mjsunit/regress/regress-523431532.js b/deps/v8/test/mjsunit/regress/regress-523431532.js new file mode 100644 index 000000000000..d71ea04ffeab --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-523431532.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const other_realm = Realm.create(); +Realm.shared = {}; + +Realm.eval(other_realm, ` + function victim(secret) { + Realm.shared.spy(); + } + function victim_caller() { + victim("secret"); + } + Realm.shared.victim = victim; + Realm.shared.victim_caller = victim_caller; +`); + +const args_getter = + Object.getOwnPropertyDescriptor(Function.prototype, 'arguments').get; +const caller_getter = + Object.getOwnPropertyDescriptor(Function.prototype, 'caller').get; + +let spy_called = false; +Realm.shared.spy = function() { + spy_called = true; + assertEquals(null, caller_getter.call(Realm.shared.victim)); + assertEquals(null, Realm.shared.victim.caller); + assertEquals(null, args_getter.call(Realm.shared.victim)); + assertEquals(null, Realm.shared.victim.arguments); +}; + +Realm.eval(other_realm, `Realm.shared.victim_caller();`); +assertTrue(spy_called); diff --git a/deps/v8/test/mjsunit/regress/regress-532288251.js b/deps/v8/test/mjsunit/regress/regress-532288251.js deleted file mode 100644 index a94eda623463..000000000000 --- a/deps/v8/test/mjsunit/regress/regress-532288251.js +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --stress-runs=2 --no-wait-for-background-tasks --omit-quit --disable-in-process-stack-traces - -// Stack-use-after-return in d8's InspectorClient. -// -// d8's InspectorClient is stack-allocated inside Shell::RunMainIsolate() and -// stashes a raw `this` pointer in the v8::Context's embedder data. It also -// installs a global `send()` whose native callback -// (InspectorClient::SendInspectorMessage) reads that embedder-data pointer -// and dereferences `inspector_client->session_`. -// -// With --stress-runs=2 the script is executed twice in two separate -// RunMainIsolate() stack frames, each with its own stack InspectorClient. -// With --no-wait-for-background-tasks, run #1 does *not* wait for the pending -// async WebAssembly compilation before RunMainIsolate() returns and destroys -// its InspectorClient. The compilation-finished foreground task -// (D8WasmAsyncResolvePromiseTask) is later pumped by run #2's -// FinishExecuting(); it resolves run #1's promise, whose reaction job runs in -// run #1's context and calls run #1's `send`, which dereferences the dead -// stack InspectorClient => stack-use-after-return. - -// Minimal valid WebAssembly module: magic + version only. -const kMinimalWasm = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, // \0asm - 0x01, 0x00, 0x00, 0x00, // version 1 -]); - -// Capture this run's `send` so the delayed reaction still uses run #1's -// binding after run #2 replaces the global. -const capturedSend = send; - -// Nudge ASAN's fake-stack round-robin allocator so that, at crash time, the -// dead RunMainIsolate slot is in the poisoned "after-return" state instead of -// being coincidentally recycled by a live frame in the same size class. -// (Without this the same root cause manifests as a null-pointer SEGV in -// SendInspectorMessage rather than a clean stack-use-after-return report.) -for (let i = 0; i < 3; i++) JSON.parse('{"a":[1,2,3]}'); - -// Kick off async wasm compilation. Its completion is delivered via a -// foreground D8WasmAsyncResolvePromiseTask which, thanks to -// --no-wait-for-background-tasks, can land after this run's RunMainIsolate() -// stack frame has already returned. -if (typeof WebAssembly !== 'undefined') { - WebAssembly.compile(kMinimalWasm).then( - (mod) => { - print("Wasm loaded in run: " + (mod instanceof WebAssembly.Module)); - // Triggers InspectorClient::SendInspectorMessage -> GetSession(context), - // which reads the stale InspectorClient* from run #1's context embedder - // data and does `inspector_client->session_.get()` on dead stack memory. - capturedSend('{"id":1,"method":"Runtime.enable"}'); - }, - (e) => { - print("compile rejected: " + e); - capturedSend('{"id":1,"method":"Runtime.enable"}'); - } - ); -} diff --git a/deps/v8/test/mjsunit/regress/regress-532720981.js b/deps/v8/test/mjsunit/regress/regress-532720981.js deleted file mode 100644 index 0c1d7a482d1b..000000000000 --- a/deps/v8/test/mjsunit/regress/regress-532720981.js +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector - -Object.setPrototypeOf(globalThis, new Proxy({}, { - get(target, prop) { - if (prop === 'receive') { - throw new Error("Triggering error crash during send()!"); - } - return Reflect.get(target, prop); - } -})); - -try { - send("test message"); -} catch (error) { - -} diff --git a/deps/v8/test/mjsunit/regress/regress-533311268.js b/deps/v8/test/mjsunit/regress/regress-533311268.js index a817259b39b3..1a349b49ea09 100644 --- a/deps/v8/test/mjsunit/regress/regress-533311268.js +++ b/deps/v8/test/mjsunit/regress/regress-533311268.js @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --fuzzing --allow-natives-syntax --array-destructure-bytecode --no-maglev --no-turbolev +// Flags: --flag-processing-mode=ignore-contradictions --allow-natives-syntax +// Flags: --array-destructure-bytecode --no-maglev --no-turbolev function test() { let a, b; diff --git a/deps/v8/test/mjsunit/regress/regress-535071448.js b/deps/v8/test/mjsunit/regress/regress-535071448.js new file mode 100644 index 000000000000..abc57b0b7631 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-535071448.js @@ -0,0 +1,259 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev --turbolev --array-destructure-bytecode + +// Destructuring patterns with more than three targets use +// ArrayDestructureLazyDeoptContinuation as the top deopt frame, which handles +// register writes itself rather than via LazyDeoptInfo result_size. + +(function TestFourElements() { + function f(obj) { + let [a, b, c, d] = obj; + return [a, b, c, d]; + } + + %PrepareFunctionForOptimization(f); + assertArrayEquals([1, 2, 3, 4], f([1, 2, 3, 4])); + assertArrayEquals([1, 2, 3, 4], f([1, 2, 3, 4])); + %OptimizeMaglevOnNextCall(f); + assertArrayEquals([1, 2, 3, 4], f([1, 2, 3, 4])); +})(); + +(function TestManyElements() { + function f(obj) { + let [a, b, c, d, e, g, h, i, j, k] = obj; + return a + b + c + d + e + g + h + i + j + k; + } + + %PrepareFunctionForOptimization(f); + assertEquals(55, f([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); + assertEquals(55, f([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); + %OptimizeFunctionOnNextCall(f); + assertEquals(55, f([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); + assertOptimized(f); +})(); + +(function TestShortIterable() { + function f(obj) { + let [a, b, c, d, e] = obj; + return [a, b, c, d, e]; + } + + %PrepareFunctionForOptimization(f); + assertArrayEquals([1, 2, undefined, undefined, undefined], f([1, 2])); + assertArrayEquals([1, 2, undefined, undefined, undefined], f([1, 2])); + %OptimizeFunctionOnNextCall(f); + assertArrayEquals([1, 2, undefined, undefined, undefined], f([1, 2])); + assertOptimized(f); +})(); + +(function TestLazyDeoptOnFirstNext() { + function f(obj) { + let [a, b, c, d] = obj; + return [a, b, c, d]; + } + + let do_deopt = false; + let iterable = { + [Symbol.iterator]() { + let count = 0; + return { + next() { + count++; + if (count === 1 && do_deopt) %DeoptimizeFunction(f); + if (count <= 4) return { value: count * 10, done: false }; + return { value: undefined, done: true }; + } + }; + } + }; + + %PrepareFunctionForOptimization(f); + assertArrayEquals([10, 20, 30, 40], f(iterable)); + assertArrayEquals([10, 20, 30, 40], f(iterable)); + %OptimizeMaglevOnNextCall(f); + assertArrayEquals([10, 20, 30, 40], f(iterable)); + + do_deopt = true; + assertArrayEquals([10, 20, 30, 40], f(iterable)); +})(); + +(function TestLazyDeoptMidIteration() { + function f(obj) { + let [a, b, c, d, e] = obj; + return [a, b, c, d, e]; + } + + let do_deopt = false; + let iterable = { + [Symbol.iterator]() { + let count = 0; + return { + next() { + count++; + if (count === 3 && do_deopt) %DeoptimizeFunction(f); + if (count <= 5) return { value: count * 10, done: false }; + return { value: undefined, done: true }; + } + }; + } + }; + + %PrepareFunctionForOptimization(f); + assertArrayEquals([10, 20, 30, 40, 50], f(iterable)); + assertArrayEquals([10, 20, 30, 40, 50], f(iterable)); + %OptimizeFunctionOnNextCall(f); + assertArrayEquals([10, 20, 30, 40, 50], f(iterable)); + assertOptimized(f); + + do_deopt = true; + assertArrayEquals([10, 20, 30, 40, 50], f(iterable)); + assertUnoptimized(f); +})(); + +(function TestLazyDeoptOnDone() { + function f(obj) { + let [a, b, c, d, e] = obj; + return [a, b, c, d, e]; + } + + let do_deopt = false; + let iterable = { + [Symbol.iterator]() { + let count = 0; + return { + next() { + count++; + if (count === 1) return { value: 10, done: false }; + if (count === 2 && do_deopt) %DeoptimizeFunction(f); + return { value: undefined, done: true }; + } + }; + } + }; + + %PrepareFunctionForOptimization(f); + assertArrayEquals([10, undefined, undefined, undefined, undefined], f(iterable)); + assertArrayEquals([10, undefined, undefined, undefined, undefined], f(iterable)); + %OptimizeFunctionOnNextCall(f); + assertArrayEquals([10, undefined, undefined, undefined, undefined], f(iterable)); + assertOptimized(f); + + do_deopt = true; + assertArrayEquals([10, undefined, undefined, undefined, undefined], f(iterable)); + assertUnoptimized(f); +})(); + +(function TestIteratorGetterDeopt() { + function f(obj) { + let [a, b, c, d] = obj; + return [a, b, c, d]; + } + + let do_deopt = false; + let iterable = { + get [Symbol.iterator]() { + if (do_deopt) %DeoptimizeFunction(f); + return function() { + let count = 0; + return { + next() { + count++; + if (count <= 4) return { value: count, done: false }; + return { value: undefined, done: true }; + } + }; + }; + } + }; + + %PrepareFunctionForOptimization(f); + assertArrayEquals([1, 2, 3, 4], f(iterable)); + assertArrayEquals([1, 2, 3, 4], f(iterable)); + %OptimizeFunctionOnNextCall(f); + assertArrayEquals([1, 2, 3, 4], f(iterable)); + assertOptimized(f); + + do_deopt = true; + assertArrayEquals([1, 2, 3, 4], f(iterable)); + assertUnoptimized(f); +})(); + +(function TestNextGetterDeopt() { + function f(obj) { + let [a, b, c, d] = obj; + return [a, b, c, d]; + } + + let do_deopt = false; + let iterable = { + [Symbol.iterator]() { + let count = 0; + return { + get next() { + if (do_deopt) %DeoptimizeFunction(f); + return function() { + count++; + if (count <= 4) return { value: count * 100, done: false }; + return { value: undefined, done: true }; + }; + } + }; + } + }; + + %PrepareFunctionForOptimization(f); + assertArrayEquals([100, 200, 300, 400], f(iterable)); + assertArrayEquals([100, 200, 300, 400], f(iterable)); + %OptimizeFunctionOnNextCall(f); + assertArrayEquals([100, 200, 300, 400], f(iterable)); + assertOptimized(f); + + do_deopt = true; + assertArrayEquals([100, 200, 300, 400], f(iterable)); + assertUnoptimized(f); +})(); + +(function TestIteratorCloseDeopt() { + function f(obj) { + let [a, b, c, d] = obj; + return [a, b, c, d]; + } + + let do_deopt = false; + let return_called = 0; + let iterable = { + [Symbol.iterator]() { + let count = 0; + return { + next() { + count++; + return { value: count * 10, done: false }; + }, + return() { + return_called++; + if (do_deopt) %DeoptimizeFunction(f); + return {}; + } + }; + } + }; + + %PrepareFunctionForOptimization(f); + assertArrayEquals([10, 20, 30, 40], f(iterable)); + assertArrayEquals([10, 20, 30, 40], f(iterable)); + assertEquals(2, return_called); + return_called = 0; + %OptimizeFunctionOnNextCall(f); + assertArrayEquals([10, 20, 30, 40], f(iterable)); + assertEquals(1, return_called); + assertOptimized(f); + + return_called = 0; + do_deopt = true; + assertArrayEquals([10, 20, 30, 40], f(iterable)); + assertEquals(1, return_called); + assertUnoptimized(f); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-539212794.js b/deps/v8/test/mjsunit/regress/regress-539212794.js index 453d16dbe5d8..91462227d727 100644 --- a/deps/v8/test/mjsunit/regress/regress-539212794.js +++ b/deps/v8/test/mjsunit/regress/regress-539212794.js @@ -3,6 +3,7 @@ // found in the LICENSE file. // Flags: --allow-natives-syntax --turbofan --expose-externalize-string +// Flags: --no-enable-slow-asserts // A string constant baked into optimized code can change shape afterwards. // Externalizing one in place swaps in an external string map and shrinks the diff --git a/deps/v8/test/mjsunit/regress/regress-544787343.js b/deps/v8/test/mjsunit/regress/regress-544787343.js new file mode 100644 index 000000000000..449f744cbd7a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-544787343.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +%RuntimeEvaluateREPL('let v1 = 0;'); +%RuntimeEvaluateREPL('let v1 = 0; (() => { eval(""); v1--; })(); assertEquals(-1, v1);'); + +%RuntimeEvaluateREPL('let v2 = 10;'); +%RuntimeEvaluateREPL(` + let v2 = 10; + function outer(code) { + eval(code); + function inner() { + v2--; + return v2; + } + return inner; + } + assertEquals(9, outer("")()); + assertEquals(9, v2); + assertEquals(99, outer("var v2 = 100")()); + assertEquals(9, v2); +`); diff --git a/deps/v8/test/mjsunit/regress/regress-546370272.js b/deps/v8/test/mjsunit/regress/regress-546370272.js new file mode 100644 index 000000000000..fafb13e5d4ee --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-546370272.js @@ -0,0 +1,20 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The low bytes are ASCII 0, 9, A, F, a, f, and 5 respectively. +const code_units = [0x130, 0x139, 0x141, 0x146, 0x161, 0x166, 0x435]; +const positions = [0, 7, 8, 15, 16, 23, 24, 31]; + +for (const code_unit of code_units) { + for (const position of positions) { + const input = Array(32).fill('d'); + input[position] = String.fromCharCode(code_unit); + const string = input.join(''); + + assertThrows(() => Uint8Array.fromHex(string), SyntaxError); + assertThrows( + () => new Uint8Array(string.length / 2).setFromHex(string), + SyntaxError); + } +} diff --git a/deps/v8/test/mjsunit/regress/regress-557076207.js b/deps/v8/test/mjsunit/regress/regress-557076207.js new file mode 100644 index 000000000000..5ce1c06f8314 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-557076207.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let subtags = [ + "heploc", "alalc97", "baku1926", "luna1918", "colb1945", "petr17", "aaland", + "saaho", "posix", "oxendict", "pinyin", "fonipa", "1990", "1901", "1606pcm", + "1959", "1994", "1996", "16102", "16103", "aluku", "ao1990", "aragon", + "arkadj", "asyrc", "balanka", "barla" +]; + +if (typeof Intl !== 'undefined') { + assertThrows(() => { + new Intl.Locale("en", { + variants: subtags.join("-"), + calendar: "gregory" + }); + }, RangeError); + + assertThrows(() => { + new Intl.Locale("en-u-ca-gregory", { + variants: subtags.join("-") + }); + }, RangeError); +} diff --git a/deps/v8/test/mjsunit/regress/regress-561116894.js b/deps/v8/test/mjsunit/regress/regress-561116894.js new file mode 100644 index 000000000000..5723cd8fa6f8 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-561116894.js @@ -0,0 +1,16 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --array-destructure-bytecode + +function test() { + let a, b; + [a, b] = [1, 2]; + return a + b; +} + +%PrepareFunctionForOptimization(test); +assertEquals(3, test()); +%OptimizeFunctionOnNextCall(test); +assertEquals(3, test()); diff --git a/deps/v8/test/mjsunit/regress/regress-561672123.js b/deps/v8/test/mjsunit/regress/regress-561672123.js new file mode 100644 index 000000000000..c6ad0cae365b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-561672123.js @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const realm = Realm.create(); +const victimProxy = Realm.global(realm); + +Realm.eval(realm, ` + Error.captureStackTrace(globalThis); + globalThis.stack = "secret-realm-stack"; +`); + +const accessChecked = d8.test.createAccessCheckedObject(true); +Error.captureStackTrace(accessChecked); +accessChecked.stack = "secret-object-stack"; +d8.test.setAccessPolicy(accessChecked, false); + +const localTarget = {}; +Error.captureStackTrace(localTarget); +const customDesc = Object.getOwnPropertyDescriptor(localTarget, "stack"); + +const errorInstance = new Error(); +const errorDesc = Object.getOwnPropertyDescriptor(errorInstance, "stack"); + +// Same-origin globalThis.stack still works on JSGlobalProxy. +Error.captureStackTrace(globalThis); +globalThis.stack = "same-origin-stack"; +assertEquals("same-origin-stack", globalThis.stack); +assertEquals("same-origin-stack", customDesc.get.call(globalThis)); + +for (const [holder, desc] of [[localTarget, customDesc], [errorInstance, errorDesc]]) { + for (const target of [victimProxy, accessChecked]) { + // Direct getter/setter invocation. + assertThrows(() => desc.get.call(target), TypeError); + assertThrows(() => Reflect.apply(desc.get, target, []), TypeError); + assertThrows(() => desc.set.call(target, "clobbered"), TypeError); + assertThrows(() => Reflect.apply(desc.set, target, ["clobbered"]), TypeError); + + // Receiver-substituted property access. + assertThrows(() => Reflect.get(holder, "stack", target), TypeError); + assertThrows(() => Reflect.set(holder, "stack", "clobbered", target), TypeError); + } +} + +// Verify values were not modified. +assertEquals("secret-realm-stack", Realm.eval(realm, "globalThis.stack")); +d8.test.setAccessPolicy(accessChecked, true); +assertEquals("secret-object-stack", accessChecked.stack); diff --git a/deps/v8/test/mjsunit/regress/regress-561799397.mjs b/deps/v8/test/mjsunit/regress/regress-561799397.mjs new file mode 100644 index 000000000000..d0fc9b91b842 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-561799397.mjs @@ -0,0 +1,55 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax +// Resources: test/mjsunit/harmony/modules-skip-1.mjs + +const other_realm = Realm.createAllowCrossRealmAccess(); + +// Populate the eval compilation cache from a script with a different origin +// ("(d8)" via Realm.eval) in both another Realm and the current Realm. +const eval_code = "import('../harmony/modules-skip-1.mjs')"; +const func_code = "return import('../harmony/modules-skip-1.mjs')"; + +Realm.eval(other_realm, `(0, eval)(${JSON.stringify(eval_code)}).catch(() => {})`); +Realm.eval(other_realm, `new Function(${JSON.stringify(func_code)})().catch(() => {})`); +Realm.eval(Realm.current(), `(0, eval)(${JSON.stringify(eval_code)}).catch(() => {})`); +Realm.eval(Realm.current(), `new Function(${JSON.stringify(func_code)})().catch(() => {})`); + +// Calling indirect eval and new Function from this script must not reuse the +// cached Script from Realm.eval, and must resolve the relative dynamic import +// against this script's path (test/mjsunit/regress/regress-561799397.mjs). +const ns1 = await (0, eval)(eval_code); +assertEquals(42, ns1.life()); + +const ns2 = await (new Function(func_code))(); +assertEquals(42, ns2.life()); + +// Verify that Error stack frame eval origins also reflect the calling script, +// including when callers are inlined. +Realm.eval(other_realm, `(0, eval)("new Error()")`); +Error.prepareStackTrace = (err, frames) => frames[0].getEvalOrigin(); +const origin = (0, eval)("new Error()").stack; +Error.prepareStackTrace = undefined; +assertTrue(origin.includes("regress-561799397.mjs"), origin); + +function inlinedEvalA() { + return (0, eval)('new Error().stack'); +} +function inlinedEvalB() { + return (0, eval)('new Error().stack'); +} +function outerWrapper(which) { + return which ? inlinedEvalA() : inlinedEvalB(); +} + +%PrepareFunctionForOptimization(inlinedEvalA); +%PrepareFunctionForOptimization(inlinedEvalB); +%PrepareFunctionForOptimization(outerWrapper); +assertMatches(/eval at inlinedEvalA/, outerWrapper(true)); +assertMatches(/eval at inlinedEvalB/, outerWrapper(false)); +%OptimizeFunctionOnNextCall(outerWrapper); +assertMatches(/eval at inlinedEvalA/, outerWrapper(true)); +assertMatches(/eval at inlinedEvalB/, outerWrapper(false)); + diff --git a/deps/v8/test/mjsunit/regress/regress-564012076.js b/deps/v8/test/mjsunit/regress/regress-564012076.js new file mode 100644 index 000000000000..dd53d7f60b34 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564012076.js @@ -0,0 +1,40 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --correctness-fuzzer-cross-arch-suppressions --allow-natives-syntax --use-std-math-pow + +function f(x) { + return x ** 0; +} + +assertEquals(1, f(5)); +assertEquals(1, f(NaN)); +assertEquals(1, f(-0)); + +%PrepareFunctionForOptimization(f); +f(5); +f(NaN); +f(-0); +%OptimizeFunctionOnNextCall(f); +assertEquals(1, f(5)); +assertEquals(1, f(NaN)); +assertEquals(1, f(-0)); + +assertEquals(1, Math.pow(5, 0)); +assertEquals(1, Math.pow(NaN, 0)); +assertEquals(1, Math.pow(-0, -0)); +assertTrue(Number.isNaN(Math.pow(NaN, 3))); + +assertEquals(42, Math.pow(3, 1.7)); + +function g() { + return NaN ** 3; +} + +assertTrue(Number.isNaN(g())); +%PrepareFunctionForOptimization(g); +g(); +g(); +%OptimizeFunctionOnNextCall(g); +assertTrue(Number.isNaN(g())); diff --git a/deps/v8/test/mjsunit/regress/regress-564879562.js b/deps/v8/test/mjsunit/regress/regress-564879562.js new file mode 100644 index 000000000000..5c58658cc4d3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564879562.js @@ -0,0 +1,75 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval --bundle + +// Regression test for crbug.com/564879562: on a deferred module namespace, +// "then" must be treated as an ordinary (absent) property per +// IsSymbolLikeNamespaceKey. Accessing it must not evaluate the module, read +// the export Cell, or observe a TDZ ReferenceError, and dynamic import.defer() +// must resolve to the namespace without invoking an exported `then`. + +// JS_BUNDLE_MODULE:mod_then_fn.mjs +globalThis.fn_module_evaluated = true; +export let tdz_binding = 'initialized'; +export function then(resolve) { + globalThis.then_ran_while_unevaluated = !globalThis.fn_module_evaluated; + resolve('hijacked-thenable'); +} + +// JS_BUNDLE_MODULE:mod_then_tdz.mjs +globalThis.tdz_module_evaluated = true; +export const then = 42; + +// JS_BUNDLE_MODULE_ENTRYPOINT +import defer * as ns_fn from './mod_then_fn.mjs'; +import defer * as ns_tdz from './mod_then_tdz.mjs'; + +function readThenIC(o) { + return o.then; +} + +// 1. Per IsSymbolLikeNamespaceKey("then", ns), [[Get]], [[GetOwnProperty]], +// [[HasProperty]], and [[DefineOwnProperty]] on a deferred namespace must +// treat "then" as an ordinary property (not an export lookup) and must NOT +// evaluate the module or read the export Cell. +for (let i = 0; i < 10; i++) { + assertEquals(undefined, readThenIC(ns_fn)); + assertEquals(undefined, readThenIC(ns_tdz)); +} +assertEquals(undefined, Object.getOwnPropertyDescriptor(ns_fn, 'then')); +assertEquals(undefined, Object.getOwnPropertyDescriptor(ns_tdz, 'then')); +assertFalse('then' in ns_fn); +assertFalse('then' in ns_tdz); +assertThrows(() => { + Object.defineProperty(ns_tdz, 'then', { value: 1 }); +}, TypeError); + +assertEquals(undefined, globalThis.fn_module_evaluated); +assertEquals(undefined, globalThis.tdz_module_evaluated); + +// 2. Dynamic import.defer() must resolve to the deferred namespace without +// invoking the exported `then` function or rejecting with a TDZ ReferenceError. +const imported_fn = await import.defer('./mod_then_fn.mjs'); +assertSame(ns_fn, imported_fn); +assertEquals(undefined, globalThis.then_ran_while_unevaluated); +assertEquals(undefined, globalThis.fn_module_evaluated); + +const imported_tdz = await import.defer('./mod_then_tdz.mjs'); +assertSame(ns_tdz, imported_tdz); +assertEquals(undefined, globalThis.tdz_module_evaluated); + +// 3. "then" is excluded from the deferred namespace's exports, so it stays +// absent once the module has been evaluated. +assertEquals('initialized', ns_fn.tdz_binding); +assertTrue(globalThis.fn_module_evaluated); +assertEquals(['tdz_binding'], Reflect.ownKeys(ns_fn).filter( + k => typeof k === 'string')); +assertEquals(['tdz_binding'], Object.keys(ns_fn)); +for (const k in ns_fn) assertEquals('tdz_binding', k); +assertEquals(undefined, readThenIC(ns_fn)); +assertEquals(undefined, Object.getOwnPropertyDescriptor(ns_fn, 'then')); +assertEquals(undefined, Object.prototype.__lookupGetter__.call(ns_fn, 'then')); +assertFalse('then' in ns_fn); +assertTrue(delete ns_fn.then); diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-2.js b/deps/v8/test/mjsunit/regress/regress-564880275-2.js new file mode 100644 index 000000000000..eaae6d1e45d5 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-2.js @@ -0,0 +1,42 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval --bundle + +// JS_BUNDLE_MODULE:m_term.mjs +export var x = 1; +d8.terminate(); +(() => {})(); + +// JS_BUNDLE_MODULE:outer.mjs +import defer * as mt from './m_term.mjs'; +export var y = mt.x; + +// JS_BUNDLE_MODULE_ENTRYPOINT +import defer * as mt from './m_term.mjs'; +import defer * as outer from './outer.mjs'; + +// Terminates inside nested synchronous evaluation: outer.mjs -> m_term.mjs. +// Both modules transition to kErrored with a null exception and no capability. +setTimeout(() => { + outer.y; + assertUnreachable(); +}, 0); + +let outer_import_rejected = false; +setTimeout(() => { + assertThrowsEquals(() => mt.x, null); + import('./outer.mjs').then( + () => assertUnreachable(), + (e) => { + assertEquals(null, e); + assertThrowsEquals(() => outer.y, null); + outer_import_rejected = true; + }); + Promise.resolve().then(() => { + setTimeout(() => { + assertTrue(outer_import_rejected); + }, 0); + }); +}, 0); diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-3.js b/deps/v8/test/mjsunit/regress/regress-564880275-3.js new file mode 100644 index 000000000000..ad3857acde4a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-3.js @@ -0,0 +1,72 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval --bundle + +// JS_BUNDLE_MODULE:c.mjs +await 0; +throw new Error('boom'); + +// JS_BUNDLE_MODULE:b.mjs +import './a.mjs'; +export let x = 1; +await new Promise(() => {}); + +// JS_BUNDLE_MODULE:a.mjs +import './b.mjs'; +import './c.mjs'; + +// JS_BUNDLE_MODULE:parent.mjs +import './a.mjs'; + +// JS_BUNDLE_MODULE:defer_b.mjs +import defer * as ns from './b.mjs'; +export {ns}; + +// JS_BUNDLE_MODULE_ENTRYPOINT +let first_error; +try { + await import('./parent.mjs'); + assertUnreachable(); +} catch (e) { + first_error = e; +} +assertInstanceof(first_error, Error); +assertEquals('boom', first_error.message); + +const {ns} = await import('./defer_b.mjs'); + +setTimeout(() => { + d8.terminate(); + try { + ns.x; + } catch (e) { + } + (() => {})(); +}, 0); + +setTimeout(() => { + let sync_error; + try { + ns.x; + assertUnreachable(); + } catch (e) { + sync_error = e; + } + assertInstanceof(sync_error, Error); + assertEquals('boom', sync_error.message); + + let async_error; + import('./a.mjs').then( + () => assertUnreachable(), + (e) => { + async_error = e; + }); + Promise.resolve().then(() => { + setTimeout(() => { + assertInstanceof(async_error, Error); + assertEquals('boom', async_error.message); + }, 0); + }); +}, 0); diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-4.js b/deps/v8/test/mjsunit/regress/regress-564880275-4.js new file mode 100644 index 000000000000..df3fa5a88a21 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-4.js @@ -0,0 +1,65 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle --expose-gc --verify-heap + +// JS_BUNDLE_MODULE:cycle_c.mjs +throw new Error('sync error'); + +// JS_BUNDLE_MODULE:cycle_b.mjs +import './cycle_a.mjs'; +await new Promise(() => {}); + +// JS_BUNDLE_MODULE:cycle_a.mjs +import './cycle_b.mjs'; +import './cycle_c.mjs'; + +// JS_BUNDLE_MODULE:sync_term_tla.mjs +d8.terminate(); +(() => {})(); +await 0; + +// JS_BUNDLE_MODULE_ENTRYPOINT:entry1.mjs +import './entry2.mjs'; + +// Scenario 1: cycle_b starts async evaluation (setting its ordinal) as part of +// an SCC whose cycle root cycle_a then fails synchronously in cycle_c. +let cycle_error; +try { + await import('./cycle_a.mjs'); + assertUnreachable(); +} catch (e) { + cycle_error = e; +} +assertInstanceof(cycle_error, Error); +assertEquals('sync error', cycle_error.message); +gc(); + +// Scenario 2: sync_term_tla has top-level await (so it sets its ordinal) but +// terminates synchronously before reaching the await. +setTimeout(() => { + import('./sync_term_tla.mjs'); +}, 0); + +// Absorbs the re-requested TerminateExecution interrupt from d8's dynamic +// import handler during entry2.mjs's EmptyMessageQueues below. +setTimeout(() => {}, 0); + +let reimport_rejected = false; +setTimeout(() => { + gc(); + import('./sync_term_tla.mjs').then( + () => assertUnreachable(), + (e) => { + assertEquals(null, e); + reimport_rejected = true; + }); + Promise.resolve().then(() => { + setTimeout(() => { + assertTrue(reimport_rejected); + }, 0); + }); +}, 0); + +// JS_BUNDLE_MODULE_ENTRYPOINT:entry2.mjs diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-5.js b/deps/v8/test/mjsunit/regress/regress-564880275-5.js new file mode 100644 index 000000000000..cd831dd4b57f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-5.js @@ -0,0 +1,10 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle + +// JS_BUNDLE_MODULE_ENTRYPOINT +await new Promise(r => setTimeout(r, 0)); +d8.terminate(); +(() => {})(); diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-6.js b/deps/v8/test/mjsunit/regress/regress-564880275-6.js new file mode 100644 index 000000000000..35af1a6e9284 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-6.js @@ -0,0 +1,51 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle --expose-gc --verify-heap + +// JS_BUNDLE_MODULE:tla.mjs +export let x = 42; +await new Promise(r => { + globalThis.resume_tla = r; +}); + +// JS_BUNDLE_MODULE:parent.mjs +import './tla.mjs'; +export let ok = true; + +// JS_BUNDLE_MODULE_ENTRYPOINT +let parent_resolved = false; +import('./parent.mjs').then((ns) => { + assertTrue(ns.ok); + parent_resolved = true; +}); +await 0; + +setTimeout(() => { + // tla.mjs is kEvaluatingAsync (via parent.mjs) with no top_level_capability + // yet. Evaluating it directly while a termination interrupt is pending must + // not transition it to kErrored. + Promise.resolve().then(() => d8.terminate()); + import('./tla.mjs'); +}, 0); + +// Absorbs the d8.terminate() interrupt inside dynamic import's nested +// EmptyMessageQueues. +setTimeout(() => {}, 0); + +let tla_resolved = false; +setTimeout(() => { + gc(); + globalThis.resume_tla(); + import('./tla.mjs').then((ns) => { + assertEquals(42, ns.x); + tla_resolved = true; + }); + Promise.resolve().then(() => { + setTimeout(() => { + assertTrue(parent_resolved); + assertTrue(tla_resolved); + }, 0); + }); +}, 0); diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-7.js b/deps/v8/test/mjsunit/regress/regress-564880275-7.js new file mode 100644 index 000000000000..75f42bd412f0 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-7.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval --bundle --expose-gc --verify-heap + +// JS_BUNDLE_MODULE:child.mjs +await new Promise(r => setTimeout(r, 0)); + +// JS_BUNDLE_MODULE:m1.mjs +import './child.mjs'; +export var x = 1; +d8.terminate(); +(() => {})(); + +// JS_BUNDLE_MODULE:other.mjs +import './m1.mjs'; +export var y = 2; + +// JS_BUNDLE_MODULE:setup.mjs +import defer * as ns_m1 from './m1.mjs'; + +// Runs after child.mjs's timer resolves and m1.mjs terminates inside +// AsyncModuleExecutionFulfilled. Both m1.mjs and the entrypoint must be +// transitioned to kErrored (with a null exception and finished async ordinal). +let other_rejected = false; +setTimeout(() => { + gc(); + assertThrowsEquals(() => ns_m1.x, null); + import('./other.mjs').then( + () => assertUnreachable(), + (e) => { + assertEquals(null, e); + other_rejected = true; + }); + Promise.resolve().then(() => { + setTimeout(() => { + assertTrue(other_rejected); + }, 0); + }); +}, 0); + +// JS_BUNDLE_MODULE_ENTRYPOINT +import './m1.mjs'; +import './setup.mjs'; diff --git a/deps/v8/test/mjsunit/regress/regress-564880275-8.js b/deps/v8/test/mjsunit/regress/regress-564880275-8.js new file mode 100644 index 000000000000..052df4be7375 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275-8.js @@ -0,0 +1,49 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval --bundle --expose-gc --verify-heap + +// JS_BUNDLE_MODULE:child.mjs +await new Promise(r => setTimeout(r, 0)); + +// JS_BUNDLE_MODULE:m1.mjs +import './child.mjs'; +export var x = 1; +d8.terminate(); +(() => {})(); +await 0; + +// JS_BUNDLE_MODULE:other.mjs +import './m1.mjs'; +export var y = 2; + +// JS_BUNDLE_MODULE:setup.mjs +import defer * as ns_m1 from './m1.mjs'; + +// Like regress-564880275-7.js, but m1.mjs has a top-level await, so it is +// started via ExecuteAsyncModule (not ExecuteModule) from the exec list of +// AsyncModuleExecutionFulfilled once child.mjs's timer resolves, and +// terminates synchronously before reaching its first await. Both m1.mjs and +// the entrypoint must be transitioned to kErrored (with a null exception and +// finished async ordinal). +let other_rejected = false; +setTimeout(() => { + gc(); + assertThrowsEquals(() => ns_m1.x, null); + import('./other.mjs').then( + () => assertUnreachable(), + (e) => { + assertEquals(null, e); + other_rejected = true; + }); + Promise.resolve().then(() => { + setTimeout(() => { + assertTrue(other_rejected); + }, 0); + }); +}, 0); + +// JS_BUNDLE_MODULE_ENTRYPOINT +import './m1.mjs'; +import './setup.mjs'; diff --git a/deps/v8/test/mjsunit/regress/regress-564880275.js b/deps/v8/test/mjsunit/regress/regress-564880275.js new file mode 100644 index 000000000000..9e15b0c72148 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-564880275.js @@ -0,0 +1,28 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --js-defer-import-eval --bundle + +// JS_BUNDLE_MODULE:mod_term.mjs +export var foo = 42; +d8.terminate(); +(() => {})(); + +// JS_BUNDLE_MODULE_ENTRYPOINT +import defer * as ns from './mod_term.mjs'; + +// First task triggers synchronous evaluation of `mod_term.mjs`, which +// terminates during InnerModuleEvaluation and transitions `mod_term.mjs` to +// `kErrored`. +setTimeout(() => { + ns.foo; +}, 0); + +// Second task runs after d8 clears the termination exception and accesses +// `ns.foo` on the `kErrored` module. `foo` is a `var` so that the access can't +// throw because of TDZ. +setTimeout(() => { + assertThrowsEquals(() => ns.foo, null); + assertThrowsEquals(() => ns.foo, null); +}, 0); diff --git a/deps/v8/test/mjsunit/regress/regress-566415771.js b/deps/v8/test/mjsunit/regress/regress-566415771.js new file mode 100644 index 000000000000..325360000a6a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-566415771.js @@ -0,0 +1,23 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --multi-mapped-mock-allocator + +let buf; +try { + buf = new ArrayBuffer(0x80000000 + 8); +} catch (e) { + // 32-bit platforms cannot allocate > 2GB ArrayBuffers. + quit(0); +} + +const view = new Uint8Array(buf); + +// SerializationTag::kOneByteString (0x22) with byte_length = 0x80000000. +view.set([0xff, 0x10, 0x22, 0x80, 0x80, 0x80, 0x80, 0x08]); +assertThrows(() => d8.serializer.deserialize(buf), RangeError); + +// SerializationTag::kTwoByteString (0x63) with byte_length = 0x80000000. +view.set([0xff, 0x10, 0x63, 0x80, 0x80, 0x80, 0x80, 0x08]); +assertThrows(() => d8.serializer.deserialize(buf), RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-567222737-2.js b/deps/v8/test/mjsunit/regress/regress-567222737-2.js new file mode 100644 index 000000000000..6a5381b196be --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567222737-2.js @@ -0,0 +1,42 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --stress-flush-code + +// CoverInitializedName in a call argument must be rejected even when followed +// by a destructuring assignment in a subsequent argument. +assertThrows("f({x = 1}, [a] = [])", SyntaxError); +assertThrows("new C({x = 1}, [a] = [])", SyntaxError); +assertThrows("obj.m({x = 1}, {a} = {})", SyntaxError); +assertThrows("f(...{x = 1}, [a] = [])", SyntaxError); + +// Object literals inside call arguments of a valid property destructuring +// target must still be allowed. +let target = {}; +[(() => target)({x: 1}).prop] = [42]; +assertEquals(42, target.prop); + +// Ensure lazy vs. eager parsing of an inner function containing a call with +// CoverInitializedName followed by destructuring cannot cause a ContextCell +// mutability mismatch. +assertThrows(() => { + Function(` + function maker() { + return (() => { + let x = 1, z = 2; + function getter() { return x; } + function inner() { + f({x = z}, [a] = []); + } + return getter; + }); + } + const outer = maker(); + const get1 = outer(); + get1(); + gc(); + const get2 = outer(); + get2(); + `)(); +}, SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-567222737-3.js b/deps/v8/test/mjsunit/regress/regress-567222737-3.js new file mode 100644 index 000000000000..4d38d5e5f1a9 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567222737-3.js @@ -0,0 +1,37 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --stress-flush-code + +// CoverInitializedName in or before an import() expression must be rejected +// even when followed by a destructuring assignment argument. +assertThrows("import({x = 1})", SyntaxError); +assertThrows("import('foo', {x = 1})", SyntaxError); +assertThrows("import({x = 1}, [a] = [])", SyntaxError); +assertThrows("1 + {x = 1} + import([a] = [])", SyntaxError); +assertThrows("import('foo', {x = 1} + ([a] = []))", SyntaxError); + +// Ensure lazy vs. eager parsing of an inner function containing an import() +// expression with CoverInitializedName followed by destructuring cannot cause +// a ContextCell mutability mismatch. +assertThrows(() => { + Function(` + function maker() { + return (() => { + let x = 1, z = 2; + function getter() { return x; } + function inner() { + import({x = z}, [a] = []); + } + return getter; + }); + } + const outer = maker(); + const get1 = outer(); + get1(); + gc(); + const get2 = outer(); + get2(); + `)(); +}, SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-567222737-4.js b/deps/v8/test/mjsunit/regress/regress-567222737-4.js new file mode 100644 index 000000000000..df82d1520a5c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567222737-4.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +"use strict"; + +assertThrows(() => eval("((eval, a = (1)) => eval)(42)"), SyntaxError); +assertThrows(() => eval("((arguments, a = (1)) => arguments)(42)"), SyntaxError); +assertThrows(() => eval("((eval, a = () => {}) => eval)(42)"), SyntaxError); +assertThrows(() => eval("((eval, a = async(1)) => eval)(42)"), SyntaxError); +assertThrows(() => eval("(async (eval, a = (1)) => eval)(42)"), SyntaxError); +assertThrows(() => eval("(async (arguments, a = (1)) => arguments)(42)"), SyntaxError); + +// Also test lazy compilation (PreParser). +assertThrows(() => eval("function f() { const g = (eval, a = (1)) => eval; }"), SyntaxError); +assertThrows(() => eval("function f() { const g = async (eval, a = (1)) => eval; }"), SyntaxError); + +// Valid strict-mode arrow functions with parenthesized eval/arguments in default +// initializers or comma expressions must still succeed. +assertEquals(typeof ((a = (eval)) => a)(), "function"); +assertEquals((eval, (a = (1)) => a)(), 1); diff --git a/deps/v8/test/mjsunit/regress/regress-567222737-5.js b/deps/v8/test/mjsunit/regress/regress-567222737-5.js new file mode 100644 index 000000000000..d96c8f169d3b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567222737-5.js @@ -0,0 +1,30 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A call to `async(...)` with spread arguments inside an async arrow function's +// parameter initializer should not record rest-parameter errors on the outer +// async arrow head. +{ + let async = (...args) => args; + + let f1 = async (a = async(...[1, 2], 3)) => a; + f1().then(v => assertEquals([1, 2, 3], v)); + + let b; + let f2 = async (a = async(...b = [4, 5])) => a; + f2().then(v => { + assertEquals([4, 5], v); + assertEquals([4, 5], b); + }); + + // Top-level/eagerly parsed versions: + let f3 = (async (a = async(...[6, 7], 8)) => a); + f3().then(v => assertEquals([6, 7, 8], v)); +} + +// Actual invalid rest parameters in async arrow heads must still be rejected. +assertThrows("async (...a, b) => {}", SyntaxError); +assertThrows("async (...a = [1]) => {}", SyntaxError); +assertThrows("async (x = async (...a, b) => {}) => {}", SyntaxError); +assertThrows("async (x = async (...a = [1]) => {}) => {}", SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-567222737-6.js b/deps/v8/test/mjsunit/regress/regress-567222737-6.js new file mode 100644 index 000000000000..be5f67711845 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567222737-6.js @@ -0,0 +1,59 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +function testPatternAssignment() { + let obj = { prop: 0 }; + let arr = [0]; + let idx = 0; + let commaVar = 10; + let callArg = 20; + let arrayElem = 30; + let assignedObj; + let a = 0, b = 0, c = 0, d = 0; + + let readCaptured = () => { + return obj.prop + arr[idx] + commaVar + callArg + arrayElem + + a + b + c + d + (assignedObj === obj ? 100 : 0); + }; + + function id(x, y) { return y; } + + // 1. Comma expression before destructuring assignment. + (commaVar, [a] = [1]); + // 2. Call arguments before destructuring assignment. + id(callArg, [b] = [2]); + // 3. Array element before destructuring assignment. + [arrayElem, [c] = [3]]; + // 4. Property and element targets inside destructuring assignment, + // plus a real assignment inside a property target's receiver. + [obj.prop, arr[idx], (assignedObj = obj).prop2, d] = [4, 5, 6, 7]; + + return readCaptured(); +} + +%PrepareFunctionForOptimization(testPatternAssignment); +assertEquals(10 + 20 + 30 + 4 + 5 + 1 + 2 + 3 + 7 + 100, testPatternAssignment()); +assertEquals(10 + 20 + 30 + 4 + 5 + 1 + 2 + 3 + 7 + 100, testPatternAssignment()); +%OptimizeFunctionOnNextCall(testPatternAssignment); +assertEquals(10 + 20 + 30 + 4 + 5 + 1 + 2 + 3 + 7 + 100, testPatternAssignment()); + +// Also test for-of destructuring with property targets and inner assignments. +function testForOfPattern() { + let obj = { x: 0 }; + let target; + let val = 0; + let read = () => obj.x + val + (target === obj ? 50 : 0); + for ([obj.x, (target = obj).y, val] of [[10, 20, 30]]) {} + return read(); +} + +%PrepareFunctionForOptimization(testForOfPattern); +assertEquals(90, testForOfPattern()); +%OptimizeFunctionOnNextCall(testForOfPattern); +assertEquals(90, testForOfPattern()); + +assertThrows(() => eval("let [a()] = [];"), SyntaxError); +assertThrows(() => eval("function f([a()]) {}"), SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-567222737.js b/deps/v8/test/mjsunit/regress/regress-567222737.js new file mode 100644 index 000000000000..025e64d1dd43 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567222737.js @@ -0,0 +1,52 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --stress-flush-code + +// CoverInitializedName inside a call expression on the LHS of for-in/of must +// be rejected as a SyntaxError even though legacy web compatibility defers the +// invalid LHS ReferenceError for call expressions to runtime. +assertThrows("for (g({x = 1}) in {}) {}", SyntaxError); +assertThrows("for (g({x = 1}) of []) {}", SyntaxError); +assertThrows("async function f() { for await (g({x = 1}) of []) {} }", SyntaxError); + +// Valid call expressions on the LHS of for-in/of should still parse and throw +// ReferenceError at runtime. +let count = 0; +function g() { + count++; +} +assertThrows(() => { + for (g({x: 1}) in {a: 1}) {} +}, ReferenceError); +assertEquals(1, count); + +assertThrows(() => { + for (g({x: 1}) of [1]) {} +}, ReferenceError); +assertEquals(2, count); + +// Ensure lazy vs. eager parsing of an inner function containing a call target +// with CoverInitializedName in a for-in header cannot cause a ContextCell +// mutability mismatch. +assertThrows(() => { + Function(` + function maker() { + return (() => { + let x = 1, z = 2; + function getter() { return x; } + function inner() { + for (g({x = z}) in {}) {} + } + return getter; + }); + } + const outer = maker(); + const get1 = outer(); + get1(); + gc(); + const get2 = outer(); + get2(); + `)(); +}, SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-567574900.js b/deps/v8/test/mjsunit/regress/regress-567574900.js new file mode 100644 index 000000000000..034c9e03f68d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567574900.js @@ -0,0 +1,19 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-lazy-feedback-allocation + +(function TestMigrateUninitializedDoubleFieldToTagged() { + let o1 = {c: 1, a: 1.5}; + function f(x) { + return {c: 1, a: x}; + } + f(2.5); + f(2.5); + + let o2 = {c: 1.5, a: "str"}; + let res = f(3.5); + assertEquals(1, res.c); + assertEquals(3.5, res.a); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-567576220.js b/deps/v8/test/mjsunit/regress/regress-567576220.js new file mode 100644 index 000000000000..8e13d958aabd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567576220.js @@ -0,0 +1,49 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-lazy-feedback-allocation + +(function TestFirstFieldUninitializedDouble() { + function f(v) { + return {a: v()}; + } + + f(() => 1.5); + f(() => 2.5); + + let inner; + const outer = f(() => { + inner = f(() => 2.25); + return 7.75; + }); + + assertEquals(2.25, inner.a); + assertEquals(7.75, outer.a); + + outer.a = 99.5; + assertEquals(2.25, inner.a); + assertEquals(99.5, outer.a); +})(); + +(function TestSubsequentFieldUninitializedDouble() { + function f(v) { + return {x: 1.5, a: v()}; + } + + f(() => 1.5); + f(() => 2.5); + + let inner; + const outer = f(() => { + inner = f(() => 2.25); + return 7.75; + }); + + assertEquals(2.25, inner.a); + assertEquals(7.75, outer.a); + + outer.a = 99.5; + assertEquals(2.25, inner.a); + assertEquals(99.5, outer.a); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-567827593.js b/deps/v8/test/mjsunit/regress/regress-567827593.js new file mode 100644 index 000000000000..5340da56dbe5 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-567827593.js @@ -0,0 +1,26 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +if (this.Intl) { + const nf = new Intl.NumberFormat('bn-u-nu-mathsanb', { + style: 'currency', + currency: 'USD', + minimumSignificantDigits: 1, + }); + + const huge_bigint = -(1n << 4000000n); + assertThrows(() => nf.format(huge_bigint), TypeError); + assertThrows(() => nf.formatToParts(huge_bigint), TypeError); + assertThrows(() => nf.formatRange(huge_bigint, huge_bigint), TypeError); + assertThrows( + () => nf.formatRangeToParts(huge_bigint, huge_bigint), TypeError); + assertThrows(() => huge_bigint.toLocaleString('bn-u-nu-mathsanb'), TypeError); + + const huge_str = '1.' + '0'.repeat(1000000); + assertThrows(() => nf.format(huge_str), TypeError); + assertThrows(() => nf.formatRange(huge_str, huge_str), TypeError); + + const sci_nf = new Intl.NumberFormat('en', {notation: 'scientific'}); + assertEquals('1E-400', sci_nf.format('1e-400')); +} diff --git a/deps/v8/test/mjsunit/regress/regress-568341998.js b/deps/v8/test/mjsunit/regress/regress-568341998.js new file mode 100644 index 000000000000..b63daa02c640 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568341998.js @@ -0,0 +1,10 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +for (let i = 0; i < 1600; i++) eval("({k" + i + ": 1})"); +function g() { + return 42; +} +let o = {zz: g()}; +assertEquals(42, o.zz); diff --git a/deps/v8/test/mjsunit/regress/regress-568633429.js b/deps/v8/test/mjsunit/regress/regress-568633429.js new file mode 100644 index 000000000000..b36f57532452 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568633429.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --turbolev --allow-natives-syntax + +function outer() { + try { + throw 1; + } catch (e) {} + + function inner(arg1, arg2) { + for (let i = 0; i < 5; i++) { + Number.isNaN(Math.log10(arg2), inner); + arg2 = arg1; + } + } + inner(inner, inner); +} + +%PrepareFunctionForOptimization(outer); +outer(); +outer(); +%OptimizeFunctionOnNextCall(outer); +outer(); diff --git a/deps/v8/test/mjsunit/regress/regress-568654095.js b/deps/v8/test/mjsunit/regress/regress-568654095.js new file mode 100644 index 000000000000..390cadb5d6c6 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568654095.js @@ -0,0 +1,11 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --verify-heap + +for (let i = 0; i < 5; i++) { + const src = { maxByteLength: 1073741825 }; + const dst = { maxByteLength: 2754, ...src, maxByteLength: i }; + assertEquals(i, dst.maxByteLength); +} diff --git a/deps/v8/test/mjsunit/regress/regress-568794851.js b/deps/v8/test/mjsunit/regress/regress-568794851.js new file mode 100644 index 000000000000..76118ff07c64 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568794851.js @@ -0,0 +1,132 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function* gen_yield(o) { + eval(""); + do { + with (o) { + return; + } + } while (yield); + yield; + return x; +} + +function* gen_yield_star(o) { + eval(""); + do { + with (o) { + return; + } + } while (yield* o); + return x; +} + +function* gen_try_finally(o) { + eval(""); + l: { + try { + if (o) return 1; + if (o) break l; + } finally { + with (o) { + return 2; + } + } + } + yield; + return x; +} + +function* gen_switch(o) { + eval(""); + if (true || o) { + with (o) { + return; + } + } else switch (o) { + case 0: + yield; + } + return x; +} + +function* gen_switch_table(o) { + eval(""); + if (true || o) { + with (o) { + return; + } + } else switch (o) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + yield; + } + return x; +} + +function* gen_switch_throwing_tag(o) { + eval(""); + try { + with (o) { + switch (o() = 1) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + yield; + } + } + } catch {} + yield; + return 42; +} + +function outer_without_eval() { + let outer_var = 1; + return function* (o) { + do { + with (o) { + return outer_var; + } + } while ((yield, yield, x)); + eval(""); + }; +} +const gen_outer_without_eval = outer_without_eval(); + +function* gen_unreachable_resumable_loop(o) { + eval(""); + with (o) { + return; + } + do { + yield x; + } while (x); +} + +function inlined_returns_in_different_scopes(cond, o) { + if (cond) return 1; + with (o) { + return 2; + } +} + +for (let i = 0; i < 1000; i++) { + gen_yield({}).next(); + gen_yield_star({}).next(); + gen_try_finally({}).next(); + gen_switch({}).next(); + gen_switch_table({}).next(); + gen_switch_throwing_tag(() => {}).next(); + gen_outer_without_eval({}).next(); + gen_unreachable_resumable_loop({}).next(); + inlined_returns_in_different_scopes(i % 2 === 0, {}); +} diff --git a/deps/v8/test/mjsunit/regress/regress-568893995-1.js b/deps/v8/test/mjsunit/regress/regress-568893995-1.js new file mode 100644 index 000000000000..1860c02aaf05 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568893995-1.js @@ -0,0 +1,29 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const iterator = { + [Symbol.iterator]() { + return this; + }, + next() { + return { value: 42, done: false }; + }, + return() { + d8.terminateNow(); + return {}; + } +}; + +try { + %IterableForEach(iterator, () => { + throw new Error("abrupt completion"); + }); +} catch (e) { + // If the termination exception is swallowed, we catch Error("abrupt + // completion") here. +} + +assertUnreachable("Termination exception was swallowed in IteratorClose"); diff --git a/deps/v8/test/mjsunit/regress/regress-568893995-2.js b/deps/v8/test/mjsunit/regress/regress-568893995-2.js new file mode 100644 index 000000000000..7742377711e0 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568893995-2.js @@ -0,0 +1,27 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +let worker = new Worker(` + const iterator = { + [Symbol.iterator]() { + return this; + }, + next() { + return { value: 42, done: false }; + }, + return() { + postMessage("return_called"); + return {}; + } + }; + %IterableForEach(iterator, () => { + d8.terminateNow(); + }); +`, {type: "string"}); + +let msg = worker.getMessage(); +assertEquals(undefined, msg, + "iterator.return() must not be called when execution is terminating"); diff --git a/deps/v8/test/mjsunit/regress/regress-568893995-3.js b/deps/v8/test/mjsunit/regress/regress-568893995-3.js new file mode 100644 index 000000000000..c21d678a9e1b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-568893995-3.js @@ -0,0 +1,28 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const iterator = { + [Symbol.iterator]() { + return this; + }, + next() { + return { value: 42, done: false }; + }, + get return() { + d8.terminateNow(); + } +}; + +try { + %IterableForEach(iterator, () => { + throw new Error("abrupt completion"); + }); +} catch (e) { + // If the termination exception is swallowed, we catch Error("abrupt + // completion") here. +} + +assertUnreachable("Termination exception was swallowed in IteratorClose when getting return"); diff --git a/deps/v8/test/mjsunit/regress/regress-569056575.js b/deps/v8/test/mjsunit/regress/regress-569056575.js new file mode 100644 index 000000000000..c105b81a6248 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-569056575.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Regression test for crbug.com/569056575 and crbug.com/569134276: +// FastJsonStringifier::AppendStringSWAR must use unaligned loads when reading +// 64-bit chunks of two-byte strings (e.g. when AppendStringSIMD advances past +// an escaped character at an even index leaving an odd start_index, or when +// stringifying a SlicedString with an odd offset). + +(function TestTwoByteSimdToSwarUnalignedTail() { + const escapes = + ['"', '\\', '\n', '\u001f', '\ud800', '\udfff', '\ud83d\ude00']; + const expectedEscapes = + ['\\"', '\\\\', '\\n', '\\u001f', '\\ud800', '\\udfff', '\ud83d\ude00']; + + for (let e = 0; e < escapes.length; e++) { + const esc = escapes[e]; + const exp = expectedEscapes[e]; + for (let prefixLen = 0; prefixLen <= 18; prefixLen++) { + for (let suffixLen = 0; suffixLen <= 18; suffixLen++) { + const s = '\u0100'.repeat(prefixLen) + esc + '\u0101'.repeat(suffixLen); + const expected = '"' + + '\u0100'.repeat(prefixLen) + exp + '\u0101'.repeat(suffixLen) + '"'; + assertEquals(expected, JSON.stringify(s)); + assertEquals('{"a":' + expected + '}', JSON.stringify({a: s})); + assertEquals('[' + expected + ']', JSON.stringify([s])); + } + } + } +})(); + +(function TestTwoByteSlicedStringUnalignedOffset() { + const parent = 'x' + + '\u0100'.repeat(60) + '"' + + '\u0101'.repeat(20); + for (let offset = 1; offset <= 8; offset++) { + for (let len = 4; len <= 36; len++) { + const slice = parent.substring(offset, offset + len); + const parsed = JSON.parse(JSON.stringify(slice)); + assertEquals(slice, parsed); + } + } +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-571397035.js b/deps/v8/test/mjsunit/regress/regress-571397035.js new file mode 100644 index 000000000000..dd3ff443fdbd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571397035.js @@ -0,0 +1,93 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const kBatchLength = 32; +const kInputLength = kBatchLength * 2; +const kTargetLength = kInputLength / 2; +const kDecodedByte = 0xaa; +const kInitialByte = 0x55; + +function testSetFromHex(invalid_idx, is_two_byte, use_sab, invalid_pair) { + const hex = kDecodedByte.toString(16).repeat(kTargetLength); + assertTrue(invalid_idx < kInputLength); + assertEquals(0, invalid_idx % 2); + let str = hex.substring(0, invalid_idx) + invalid_pair + + hex.substring(invalid_idx + invalid_pair.length); + + if (is_two_byte) { + // Keep two-byte characters beyond the target's capacity. + str += '\u0100\u0100'; + } + str = %FlattenString(str); + assertEquals(!is_two_byte, %StringIsOneByteRepresentation(str)); + assertEquals(0, str.length % 2); + + let target; + if (use_sab) { + target = new Uint8Array(new SharedArrayBuffer(kTargetLength)); + } else { + target = new Uint8Array(kTargetLength); + } + + target.fill(kInitialByte); + + assertThrows(() => target.setFromHex(str), SyntaxError); + + const valid_bytes = invalid_idx / 2; + for (let i = 0; i < target.length; i++) { + if (i < valid_bytes) { + assertEquals(kDecodedByte, target[i], `Decoded byte at index ${i}`); + } else { + assertEquals(kInitialByte, target[i], `Untouched byte at index ${i}`); + } + } +} + +// Invalid pair at char offsets 0, 2, 14, 16 and 30 of the first 32-char batch, +// and at the start of the second batch (offset 32). +const invalid_offsets = [0, 2, 14, 16, 30, kBatchLength]; +const invalid_pairs = ['zz', 'za']; + +for (let offset of invalid_offsets) { + for (let is_two_byte of [false, true]) { + for (let use_sab of [false, true]) { + for (let pair of invalid_pairs) { + testSetFromHex(offset, is_two_byte, use_sab, pair); + } + } + } +} + +// Odd-length input must still throw and write nothing. +function testOddLength(is_two_byte, use_sab) { + let str = kDecodedByte.toString(16).repeat(kTargetLength / 2) + 'a'; + if (is_two_byte) { + str += '\u0100\u0100'; + } + str = %FlattenString(str); + assertEquals(!is_two_byte, %StringIsOneByteRepresentation(str)); + assertEquals(1, str.length % 2); + + let target; + if (use_sab) { + target = new Uint8Array(new SharedArrayBuffer(kTargetLength)); + } else { + target = new Uint8Array(kTargetLength); + } + + target.fill(kInitialByte); + + assertThrows(() => target.setFromHex(str), SyntaxError); + + for (let i = 0; i < target.length; i++) { + assertEquals(kInitialByte, target[i]); + } +} + +testOddLength(false, false); +testOddLength(true, false); +testOddLength(false, true); +testOddLength(true, true); diff --git a/deps/v8/test/mjsunit/regress/regress-571565364-empty.txt b/deps/v8/test/mjsunit/regress/regress-571565364-empty.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/deps/v8/test/mjsunit/regress/regress-571565364.js b/deps/v8/test/mjsunit/regress/regress-571565364.js new file mode 100644 index 000000000000..57e72a479c7a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571565364.js @@ -0,0 +1,8 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Resources: test/mjsunit/regress/regress-571565364-empty.txt + +const buffer = readbuffer('test/mjsunit/regress/regress-571565364-empty.txt'); +assertEquals(0, buffer.byteLength); diff --git a/deps/v8/test/mjsunit/regress/regress-571811885.js b/deps/v8/test/mjsunit/regress/regress-571811885.js new file mode 100644 index 000000000000..e89655c61a1a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571811885.js @@ -0,0 +1,19 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let arr = []; +Object.setPrototypeOf(arr, Object.prototype); +assertEquals('{"\u1234":[]}', JSON.stringify({"\u1234": arr})); +assertEquals('{"a":[]}', JSON.stringify({"a": arr})); + +let fn = function () {}; +Object.setPrototypeOf(fn, Object.prototype); +assertEquals('{}', JSON.stringify({"\u1234": fn})); + +let bf = (function () {}).bind(null); +Object.setPrototypeOf(bf, Object.prototype); +assertEquals('{}', JSON.stringify({"\u1234": bf})); + +assertEquals('{}', JSON.stringify({"\u1234": Function.prototype})); +assertEquals('{}', JSON.stringify({"a": Function.prototype})); diff --git a/deps/v8/test/mjsunit/regress/regress-571853016.js b/deps/v8/test/mjsunit/regress/regress-571853016.js new file mode 100644 index 000000000000..61fe9323e831 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571853016.js @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-lazy-feedback-allocation + +(function TestCrossRealmArrayPrototype() { + const r = Realm.create(); + Realm.eval( + r, + 'Object.defineProperty(Object.prototype, "prop", {set(_){}, configurable:true})'); + const ap = Realm.eval(r, 'Array.prototype'); + function write(o, k, v) { + o[k] = v; + } + write(Realm.eval(r, '({prop:1})'), 'prop', 1); + write(ap, 'prop', 1); + write(Realm.eval(r, '[]'), 0, 1); + write(ap, 0, 'boom'); + const res1 = Realm.eval(r, '[...[,1]]'); + const res2 = Realm.eval(r, '[,1][0]'); + assertEquals('boom', res2); + assertEquals(res2, res1[0]); +})(); + +(function TestCrossRealmObjectPrototype() { + const r = Realm.create(); + Realm.eval( + r, + 'Object.defineProperty(Object.prototype, "prop", {set(_){}, configurable:true})'); + const op = Realm.eval(r, 'Object.prototype'); + function write(o, k, v) { + o[k] = v; + } + write(Realm.eval(r, '({prop:1})'), 'prop', 1); + write(op, 'prop', 1); + write(Realm.eval(r, '[]'), 0, 1); + write(op, 0, 'boom'); + const res1 = Realm.eval(r, '[...[,1]]'); + const res2 = Realm.eval(r, '[,1][0]'); + assertEquals('boom', res2); + assertEquals(res2, res1[0]); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-571871980.js b/deps/v8/test/mjsunit/regress/regress-571871980.js new file mode 100644 index 000000000000..226b9aa0a340 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571871980.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Character classes in one-byte pattern sources were marked as certainly +// matching one code point, even in unicode mode where \u{...}, \uXXXX\uXXXX +// and \p{...} can describe supplementary code points that match a surrogate +// pair. The resulting too-small max_match broke the end-anchor optimization. + +const tests = [ + // One-byte pattern, end-anchored, class containing a surrogate pair. + { re: /x[\u{1F600}]$/u, str: 'x\u{1F600}', expected: true }, + { re: /x[\uD83D\uDE00]$/u, str: 'x\u{1F600}', expected: true }, + { re: /x[\p{Emoji_Presentation}]$/u, str: 'x\u{1F600}', expected: true }, + { re: /[\u{1F600}][\u{1F600}]$/u, str: '\u{1F600}\u{1F600}', expected: true }, + { re: /x[\u{1F600}]$/iu, str: 'x\u{1F600}', expected: true }, + // Negated classes match surrogate pairs in unicode mode as well. + { re: /x[^a]$/u, str: 'x\u{1F600}', expected: true }, + { re: /x[^a]$/iu, str: 'x\u{1F600}', expected: true }, + // Two-byte pattern sources. + { re: /\u{10000}[\u{1F600}]$/u, str: '\u{10000}\u{1F600}', expected: true }, + { re: /\u{10000}[^a]$/u, str: '\u{10000}\u{1F600}', expected: true }, + + // Controls: no end anchor, start anchor, /v. + { re: /x[\u{1F600}]/u, str: 'x\u{1F600}', expected: true }, + { re: /^x[\u{1F600}]$/u, str: 'x\u{1F600}', expected: true }, + { re: /x[\u{1F600}]$/v, str: 'x\u{1F600}', expected: true }, + + // Non-unicode mode: classes match a single code unit. + { re: /x[\uD83D\uDE00]$/, str: 'x\u{1F600}', expected: false }, + { re: /x[\uD83D\uDE00][\uD83D\uDE00]$/, str: 'x\u{1F600}', expected: true }, + { re: /x[\uD83D]$/, str: 'x\u{1F600}', expected: false }, + { re: /x[^a]$/, str: 'x\u{1F600}', expected: false }, + { re: /x[^a][^a]$/, str: 'x\u{1F600}', expected: true }, +]; + +for (const { re, str, expected } of tests) { + assertEquals(expected, re.test(str), re.toString()); + const match = re.exec(str); + if (expected) { + assertNotNull(match, re.toString()); + } else { + assertNull(match, re.toString()); + } +} diff --git a/deps/v8/test/mjsunit/regress/regress-571944332.js b/deps/v8/test/mjsunit/regress/regress-571944332.js new file mode 100644 index 000000000000..9deb891ef607 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571944332.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +let workerCode = ` + onmessage = function() { + const maxByteLength = Math.min((%ArrayBufferMaxByteLength() + 1) / 2, 2**42) / 128; + let bufs = []; + while (true) { + try { + bufs.push(new ArrayBuffer(0, {maxByteLength})); + } catch(e) { + bufs.length = 0; + } + } + }; +`; + +let worker = new Worker(workerCode, {type: 'string'}); +worker.postMessage('start'); + +const maxByteLength = Math.min((%ArrayBufferMaxByteLength() + 1) / 2, 2 ** 42); + +let rabs = []; +for (let i = 0; i < 100; i++) { + try { + rabs.push(new ArrayBuffer(0, {maxByteLength})); + } catch (e) { + break; + } +} + +try { + for (let iter = 0; iter < 1000; iter++) { + for (let i = 0; i < rabs.length; i++) { + rabs[i] = rabs[i].transfer(0); + } + } +} catch (e) { + assertInstanceof(e, RangeError); +} + +worker.terminate(); diff --git a/deps/v8/test/mjsunit/regress/regress-571975489.js b/deps/v8/test/mjsunit/regress/regress-571975489.js new file mode 100644 index 000000000000..dda0a2ac9234 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-571975489.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --multi-mapped-mock-allocator + +let buf; +try { + buf = new ArrayBuffer(0x80000000 + 16); +} catch (e) { + // 32-bit platforms cannot allocate > 2GB ArrayBuffers. + quit(0); +} + +const view = new Uint8Array(buf); + +// SerializationTag::kBeginJSObject (0x6f), followed by +// SerializationTag::kUtf8String (0x53) property key with +// byte_length = 0x80000000. +view.set([0xff, 0x10, 0x6f, 0x53, 0x80, 0x80, 0x80, 0x80, 0x08]); +assertThrows(() => d8.serializer.deserialize(buf), RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-572400584.js b/deps/v8/test/mjsunit/regress/regress-572400584.js new file mode 100644 index 000000000000..039d5bb7cbb2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-572400584.js @@ -0,0 +1,80 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The lazy globalThis.Temporal and Date.prototype.toTemporalInstant accessors +// must initialize Temporal in the realm that owns the property, not in the +// realm of the caller. + +// First access to another realm's globalThis.Temporal. +{ + const r = Realm.createAllowCrossRealmAccess(); + const t = Realm.global(r).Temporal; + assertSame(Realm.eval(r, "Temporal"), t); + assertSame(Realm.eval(r, "Object.prototype"), Object.getPrototypeOf(t)); + assertSame(Realm.eval(r, "new Temporal.Instant(0n)").constructor, + t.Instant); + assertTrue(Realm.eval(r, + "new Date(0).toTemporalInstant() instanceof Temporal.Instant")); + assertNotSame(Temporal, t); + assertNotSame(Temporal.Instant, t.Instant); +} + +// First access to another realm's Date.prototype.toTemporalInstant. +{ + const r = Realm.createAllowCrossRealmAccess(); + const d = Realm.eval(r, "new Date(0)"); + const fn = d.toTemporalInstant; + assertSame(Realm.eval(r, "Date.prototype.toTemporalInstant"), fn); + assertSame(Realm.eval(r, "Function.prototype"), Object.getPrototypeOf(fn)); + assertNotSame(Date.prototype.toTemporalInstant, fn); + const instant_proto = Realm.eval(r, "Temporal.Instant.prototype"); + assertSame(instant_proto, Object.getPrototypeOf(fn.call(new Date(0)))); + assertSame(instant_proto, Object.getPrototypeOf( + Realm.eval(r, "new Date(0).toTemporalInstant()"))); + assertTrue(Realm.eval(r, + "new Date(0).toTemporalInstant() instanceof Temporal.Instant")); +} + +// The other realm initializes Temporal itself first, then the main realm +// reads it. +{ + const r = Realm.createAllowCrossRealmAccess(); + const own_temporal = Realm.eval(r, "Temporal"); + const own_fn = Realm.eval(r, "Date.prototype.toTemporalInstant"); + assertSame(own_temporal, Realm.global(r).Temporal); + assertSame(own_fn, Realm.eval(r, "Date.prototype").toTemporalInstant); + assertNotSame(Temporal, own_temporal); + assertNotSame(Date.prototype.toTemporalInstant, own_fn); +} + +// Both lazy accessors are first touched from the main realm, in reverse +// order. +{ + const r = Realm.createAllowCrossRealmAccess(); + const fn = Realm.eval(r, "Date.prototype").toTemporalInstant; + const t = Realm.global(r).Temporal; + assertSame(Realm.eval(r, "Temporal"), t); + assertSame(t.Instant.prototype, Object.getPrototypeOf(fn.call(new Date(0)))); + assertTrue(Realm.eval(r, + "new Date(0).toTemporalInstant() instanceof Temporal.Instant")); +} + +// First access through Reflect.get with an unrelated receiver. +{ + const r = Realm.createAllowCrossRealmAccess(); + const t = Reflect.get(Realm.global(r), "Temporal", {}); + assertSame(Realm.eval(r, "Temporal"), t); + assertNotSame(Temporal, t); +} + +// First access through an object inheriting from another realm's +// Date.prototype. +{ + const r = Realm.createAllowCrossRealmAccess(); + const o = Object.create(Realm.eval(r, "Date.prototype")); + const fn = o.toTemporalInstant; + assertSame(Realm.eval(r, "Date.prototype.toTemporalInstant"), fn); + assertNotSame(Date.prototype.toTemporalInstant, fn); + assertFalse(Object.hasOwn(o, "toTemporalInstant")); +} diff --git a/deps/v8/test/mjsunit/regress/regress-572988453.js b/deps/v8/test/mjsunit/regress/regress-572988453.js new file mode 100644 index 000000000000..f0dd7bcd2a43 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-572988453.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --stress-flush-code + +class Outer { + #a = 'outer_a'; + #b = 'outer_b'; + + static make() { + let fn; + class Inner extends (() => { + try { + throw null; + } catch (e) { + fn = (function(o) { + return o.#a + ':' + o.#b; + }); + } + return Object; + })() { + #a() {} + #b() {} + } + return {fn, Inner}; + } +} + +const {fn, Inner} = Outer.make(); +assertEquals('outer_a:outer_b', fn(new Outer())); +for (let i = 0; i < 4; i++) gc(); +assertEquals('outer_a:outer_b', fn(new Outer())); +assertThrows(() => fn(new Inner()), TypeError); diff --git a/deps/v8/test/mjsunit/regress/regress-573037572.js b/deps/v8/test/mjsunit/regress/regress-573037572.js new file mode 100644 index 000000000000..3fba57917077 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573037572.js @@ -0,0 +1,118 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function execAt(re, str, lastIndex) { + re.lastIndex = lastIndex; + return re.exec(str); +} + +function assertMatch(expected, index, lastIndex, result, re) { + assertNotNull(result); + assertEquals(expected, result[0]); + assertEquals(index, result.index); + assertEquals(lastIndex, re.lastIndex); +} + +const kEmoji = '\u{1F600}'; +const kTrailSurrogate = '\uDE00'; + +// Non-Unicode matching keeps the code unit position. +for (const re of [/./g, /./y]) { + assertMatch(kTrailSurrogate, 1, 2, execAt(re, kEmoji, 1), re); +} + +// lastIndex points at the trail surrogate of a pair. Matching starts at the +// lead surrogate; if that fails, the trail surrogate must not be retried. +for (const re of [/(?!.)/yu, /(?!.)|a^/yu, /(?!.)/yv, /(?![\s\S])(?!$)/gu, + /(?![\s\S])(?!$)/gv]) { + assertNull(execAt(re, kEmoji, 1), re.source); + assertEquals(0, re.lastIndex); +} + +// With g, a failure from the lead surrogate must not rescan the rest of the +// subject from the trail surrogate. +{ + const re = /(?![\s\S])(?!$)|^x/gu; + assertNull(execAt(re, kEmoji + 'x', 1)); +} + +// Positive controls: stepping back to the lead surrogate still works. +{ + const re = /./yu; + assertMatch(kEmoji, 0, 2, execAt(re, kEmoji, 1), re); +} +{ + const re = /\u{1F600}/gu; + assertMatch(kEmoji, 1, 3, execAt(re, 'a' + kEmoji, 2), re); + assertMatch(kEmoji, 0, 2, execAt(re, kEmoji, 1), re); +} +{ + const re = /\u{1F600}/yv; + assertMatch(kEmoji, 0, 2, execAt(re, kEmoji + 'a', 1), re); +} +{ + // Backreferences and lookbehinds see the stepped-back position. + const re = /(?<=^)(.)\1/yu; + assertMatch(kEmoji + kEmoji, 0, 4, execAt(re, kEmoji + kEmoji, 1), re); + const re2 = /(?<!^)./gu; + assertMatch('b', 2, 3, execAt(re2, kEmoji + 'b', 1), re2); +} +{ + // Global search continues forward from the lead surrogate. + const re = /b/gu; + assertMatch('b', 2, 3, execAt(re, kEmoji + 'b', 1), re); +} + +// Global matching restarts at the next pair without repeating a match. +for (const re of [/./gu, /./gv]) { + assertEquals([kEmoji, kEmoji], (kEmoji + kEmoji).match(re)); +} + +// lastIndex on a non-surrogate character: no step back. +{ + const re = /(?!.)/yu; + assertNull(execAt(re, 'ab\u1234', 1)); + const re2 = /./yu; + assertMatch('b', 1, 2, execAt(re2, 'ab\u1234', 1), re2); +} + +// Lone trail surrogate not preceded by a lead surrogate: no step back. +{ + const re = /./yu; + assertMatch(kTrailSurrogate, 1, 2, execAt(re, 'a' + kTrailSurrogate, 1), re); + const re2 = /[\uDC00-\uDFFF]/yu; + assertMatch(kTrailSurrogate, 0, 1, execAt(re2, kTrailSurrogate, 0), re2); + const re3 = /(?!.)/yu; + assertNull(execAt(re3, 'a' + kTrailSurrogate, 1)); + const re4 = /(?=\uDE00)/yu; + assertMatch('', 1, 1, execAt(re4, 'a' + kTrailSurrogate, 1), re4); +} + +// A lone trail surrogate at index 0 (nothing to step back over). +{ + const re = /\uDE00/yu; + assertMatch(kTrailSurrogate, 0, 1, execAt(re, kTrailSurrogate + kEmoji, 0), re); +} + +// The surrogate check must also allow matching at the end of the input. +for (const re of [/$/gu, /$/yu, /$/gv, /$/yv]) { + assertMatch('', 0, 0, execAt(re, '', 0), re); + assertMatch('', 2, 2, execAt(re, kEmoji, 2), re); +} + +// /(?!.)/gu scans forward from the lead surrogate to the end of the string. +{ + const re = /(?!.)/gu; + assertMatch('', 2, 2, execAt(re, kEmoji, 1), re); + assertMatch('', 4, 4, execAt(re, kEmoji + kEmoji, 3), re); + assertMatch('', 3, 3, execAt(re, kEmoji + 'a', 1), re); +} + +// A lead surrogate at the end of the string and a trail surrogate preceded by +// a trail surrogate are not pairs: no step back. +{ + const re = /./yu; + assertMatch('\uD83D', 1, 2, execAt(re, 'a\uD83D', 1), re); + assertMatch(kTrailSurrogate, 1, 2, execAt(re, kTrailSurrogate + kTrailSurrogate, 1), re); +} diff --git a/deps/v8/test/mjsunit/regress/regress-573038326.js b/deps/v8/test/mjsunit/regress/regress-573038326.js new file mode 100644 index 000000000000..0771b973723b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573038326.js @@ -0,0 +1,50 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev + +// DataView.prototype.setFloat64/setFloat32 must write the same bytes for a +// signaling NaN before and after optimization. + +const source = new ArrayBuffer(8); +new BigUint64Array(source)[0] = 0xfff2800000000000n; +const signalingNaN = new Float64Array(source)[0]; + +const target = new ArrayBuffer(8); +const dv = new DataView(target); + +function storeFloat64(value) { + dv.setFloat64(0, value, true); +} +function storeFloat64BigEndian(value) { + dv.setFloat64(0, value, false); +} +function storeFloat32(value) { + dv.setFloat32(0, value, true); +} +function storeFloat64DynamicEndian(value, littleEndian) { + dv.setFloat64(0, value, littleEndian); +} + +function run(f, ...args) { + dv.setBigUint64(0, 0n); + f(signalingNaN, ...args); + return dv.getBigUint64(0, true); +} + +function test(f, ...args) { + %PrepareFunctionForOptimization(f); + const expected = run(f, ...args); + %OptimizeMaglevOnNextCall(f); + assertEquals(expected, run(f, ...args)); + assertOptimized(f); + %OptimizeFunctionOnNextCall(f); + assertEquals(expected, run(f, ...args)); + assertOptimized(f); +} + +test(storeFloat64); +test(storeFloat64BigEndian); +test(storeFloat32); +test(storeFloat64DynamicEndian, true); diff --git a/deps/v8/test/mjsunit/regress/regress-573048357.js b/deps/v8/test/mjsunit/regress/regress-573048357.js new file mode 100644 index 000000000000..239b4bba23e2 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573048357.js @@ -0,0 +1,72 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +// A Baseline constructor called from a Maglev frame with an inlined construct +// stub must keep its constructor flag in the captured stack trace. + +function captureFrames() { + Error.prepareStackTrace = (e, frames) => + frames.map(f => [f.getFunctionName(), f.isConstructor()]); + const frames = new Error().stack; + Error.prepareStackTrace = undefined; + return frames; +} +%NeverOptimizeFunction(captureFrames); + +(function TestConstructorCapturesStack() { + function C(capture) { + if (capture) { + this.stack = new Error().stack; + this.frames = captureFrames(); + } + } + + function constructC(capture) { + return new C(capture); + } + + %NeverOptimizeFunction(C); + if (%IsSparkplugEnabled()) %CompileBaseline(C); + %PrepareFunctionForOptimization(constructC); + constructC(false); + %OptimizeMaglevOnNextCall(constructC); + + const res = constructC(true); + assertMatches(/at new C/, res.stack); + assertEquals(['captureFrames', false], res.frames[0]); + assertEquals(['C', true], res.frames[1]); + assertEquals(['constructC', false], res.frames[2]); +})(); + +(function TestConstructorCallsCapturingFunction() { + function D() { + return captureFrames(); + } + + function C(capture) { + if (capture) this.frames = D(); + } + + function constructC(capture) { + return new C(capture); + } + + %NeverOptimizeFunction(D); + %NeverOptimizeFunction(C); + if (%IsSparkplugEnabled()) { + %CompileBaseline(D); + %CompileBaseline(C); + } + %PrepareFunctionForOptimization(constructC); + constructC(false); + %OptimizeMaglevOnNextCall(constructC); + + const res = constructC(true); + assertEquals(['captureFrames', false], res.frames[0]); + assertEquals(['D', false], res.frames[1]); + assertEquals(['C', true], res.frames[2]); + assertEquals(['constructC', false], res.frames[3]); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-573048572.js b/deps/v8/test/mjsunit/regress/regress-573048572.js new file mode 100644 index 000000000000..015786bf12b8 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573048572.js @@ -0,0 +1,9 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --stress-delay-tasks + +const i32a = new Int32Array(new SharedArrayBuffer(16)); +const res = Atomics.waitAsync(i32a, 0, 0, 1); +assertEquals(true, res.async); diff --git a/deps/v8/test/mjsunit/regress/regress-573263262.js b/deps/v8/test/mjsunit/regress/regress-573263262.js new file mode 100644 index 000000000000..1c2d9a1d5f10 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573263262.js @@ -0,0 +1,17 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Unrolls to six copies of the literal, which exceeds the maximum character +// offset while keeping the pattern short enough to be optimized. +const kTooBig = '(?:(?:' + 'a'.repeat(5462) + '){3}){2}'; +const subject = 'b'.repeat(1000); + +function assertTooLarge(source) { + assertThrows(() => new RegExp(source).exec(subject), SyntaxError, + /Regular expression too large/); +} + +// BEGIN_POSITIVE_SUBMATCH / BEGIN_NEGATIVE_SUBMATCH with a non-trivial trace. +assertTooLarge('x(?=' + kTooBig + ')|y'); +assertTooLarge('x(?!' + kTooBig + ')|y'); diff --git a/deps/v8/test/mjsunit/regress/regress-573471186.js b/deps/v8/test/mjsunit/regress/regress-573471186.js new file mode 100644 index 000000000000..74c82eff175e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573471186.js @@ -0,0 +1,80 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --fast-proxy-ic + +const handler = { + get(target, property, receiver) { + return Reflect.get(target, property, receiver); + } +}; + +const proxy1 = new Proxy({a: 1}, handler); +const proxy2 = new Proxy({a: 1, b: 2}, handler); +const proxySlow = new Proxy({a: 1}, {}); + +function getICState(fn) { + const feedback = %GetFeedback(fn); + if (feedback === undefined) return undefined; + return feedback[0][1].split('\n')[0]; +} + +// FastProxy -> FastProxy with different target map downgrades to slow LoadProxy +// and stays MONOMORPHIC. +(function TestFastProxyToFastProxyDowngrade() { + function load(o) { + return o.a; + } + %PrepareFunctionForOptimization(load); + + assertEquals(1, load(proxy1)); + if (getICState(load) !== undefined) { + assertEquals('MONOMORPHIC', getICState(load)); + } + + assertEquals(1, load(proxy2)); + if (getICState(load) !== undefined) { + assertEquals('MONOMORPHIC', getICState(load)); + } +})(); + +// FastProxy -> slow LoadProxy (proxy not eligible for fast path) downgrades to +// slow LoadProxy and stays MONOMORPHIC. +(function TestFastProxyToSlowProxyDowngrade() { + function load(o) { + return o.a; + } + %PrepareFunctionForOptimization(load); + + assertEquals(1, load(proxy1)); + if (getICState(load) !== undefined) { + assertEquals('MONOMORPHIC', getICState(load)); + } + + assertEquals(1, load(proxySlow)); + if (getICState(load) !== undefined) { + assertEquals('MONOMORPHIC', getICState(load)); + } +})(); + +// Polymorphic IC containing a FastProxy handler downgrades the proxy entry in +// place and stays POLYMORPHIC. +(function TestPolymorphicFastProxyDowngrade() { + function load(o) { + return o.a; + } + %PrepareFunctionForOptimization(load); + + const normalObj = {a: 42}; + assertEquals(42, load(normalObj)); + assertEquals(1, load(proxy1)); + if (getICState(load) !== undefined) { + assertEquals('POLYMORPHIC', getICState(load)); + } + + assertEquals(1, load(proxy2)); + if (getICState(load) !== undefined) { + assertEquals('POLYMORPHIC', getICState(load)); + } +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-573777594.js b/deps/v8/test/mjsunit/regress/regress-573777594.js new file mode 100644 index 000000000000..23d9ead6c5ff --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573777594.js @@ -0,0 +1,8 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const match = /^[z]?z|[38]/v.exec('aa3aaaaaaaaaaaaaaa'); +assertNotNull(match); +assertEquals(2, match.index); +assertEquals('3', match[0]); diff --git a/deps/v8/test/mjsunit/regress/regress-573962535.js b/deps/v8/test/mjsunit/regress/regress-573962535.js new file mode 100644 index 000000000000..29db88a4be57 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-573962535.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --no-compilation-cache --stress-flush-code +// Flags: --stress-lazy-source-positions + +class B { + #x = 'B'; + static makeHeritageEvalFunction() { + let g; + let h; + let nested; + let nestedEval; + class C extends ( + g = eval('0, function(o) { return o.#x; }'), + h = eval('(() => (o) => o.#x)()'), + nested = eval('(() => { let ctx = 1; return (o) => { () => ctx; return o.#x; }; })()'), + nestedEval = eval("eval('0, function(o) { return o.#x; }')"), + Object + ) { + #x = 'C'; + } + return {g, h, nested, nestedEval, C}; + } +} + +const {g, h, nested, nestedEval, C} = B.makeHeritageEvalFunction(); + +// Drop the eval's top-level SharedFunctionInfo and flush bytecode before +// lazy compilation. +for (let i = 0; i < 4; i++) gc(); + +assertEquals('B', g(new B())); +assertThrows(() => g(new C()), TypeError); + +assertEquals('B', h(new B())); +assertThrows(() => h(new C()), TypeError); + +assertEquals('B', nested(new B())); +assertThrows(() => nested(new C()), TypeError); + +assertEquals('B', nestedEval(new B())); +assertThrows(() => nestedEval(new C()), TypeError); diff --git a/deps/v8/test/mjsunit/regress/regress-574038247.js b/deps/v8/test/mjsunit/regress/regress-574038247.js new file mode 100644 index 000000000000..d35372f23eff --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-574038247.js @@ -0,0 +1,68 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --bundle + +// JS_BUNDLE_MODULE:c1.mjs +export const x = 1; + +// JS_BUNDLE_MODULE:c2.mjs +export const x = 2; + +// JS_BUNDLE_MODULE:p.mjs +export * from "n.mjs"; +export * from "c1.mjs"; + +// JS_BUNDLE_MODULE:n.mjs +export * from "p.mjs"; + +// JS_BUNDLE_MODULE:outer.mjs +export * from "m.mjs"; +export * from "p.mjs"; +export * from "c2.mjs"; + +// JS_BUNDLE_MODULE:m.mjs +const a = 1; +export { a, a as b, a as c, a as d, a as e }; +export * from "outer.mjs"; +export * from "n.mjs"; + +// JS_BUNDLE_MODULE:trigger.mjs +import { x } from "outer.mjs"; + +// JS_BUNDLE_MODULE:outer_no_ns.mjs +export * from "m_no_ns.mjs"; +export * from "p.mjs"; +export * from "c2.mjs"; + +// JS_BUNDLE_MODULE:m_no_ns.mjs +export const a = 1; +export * from "outer_no_ns.mjs"; +export * from "n.mjs"; + +// JS_BUNDLE_MODULE:trigger_no_ns.mjs +import { x } from "outer_no_ns.mjs"; + +// JS_BUNDLE_MODULE:import_x_from_m_no_ns.mjs +import { x } from "m_no_ns.mjs"; + +// JS_BUNDLE_MODULE_ENTRYPOINT +import * as ns from "m.mjs"; +import { a } from "m_no_ns.mjs"; + +assertEquals(1, a); + +function read(o) { + return o.a + o.b + o.c + o.d + o.e; +} + +for (let i = 0; i < 12; i++) { + assertEquals(5, read(ns)); +} + +await assertThrowsAsync(import("trigger.mjs"), SyntaxError); +assertEquals(5, read(ns)); + +await assertThrowsAsync(import("trigger_no_ns.mjs"), SyntaxError); +await assertThrowsAsync(import("import_x_from_m_no_ns.mjs"), SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-575750485.js b/deps/v8/test/mjsunit/regress/regress-575750485.js new file mode 100644 index 000000000000..24366df564c7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-575750485.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +const byteLength = Object.getOwnPropertyDescriptor( + Object.getPrototypeOf(Uint8Array.prototype), 'byteLength').get; + +function getByteLength(ta) { + ta.byteOffset; + return byteLength.call(ta); +} + +const abToDetach = new ArrayBuffer(10); +const ta1 = new Uint8Array(abToDetach); +const ta2 = new Uint8Array(abToDetach); +%ArrayBufferDetach(abToDetach); + +const rab = new ArrayBuffer(10, {maxByteLength: 20}); +const rabTa = new Uint8Array(rab); + +const normalAb = new ArrayBuffer(10); +const normalTa1 = new Uint8Array(normalAb); +const normalTa2 = new Uint8Array(normalAb); + +%PrepareFunctionForOptimization(getByteLength); +getByteLength(rabTa); +getByteLength(normalTa1); +%OptimizeFunctionOnNextCall(getByteLength); +assertEquals(10, getByteLength(normalTa1)); + +%ArrayBufferDetach(normalAb); +assertEquals(0, getByteLength(normalTa1)); diff --git a/deps/v8/test/mjsunit/regress/regress-575820656.js b/deps/v8/test/mjsunit/regress/regress-575820656.js new file mode 100644 index 000000000000..53cd3bc8fd2f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-575820656.js @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --cache=after-execute + +function f(a = 1) { + var x = 1; + { let b1 = 1; + { let b2 = 1; + { let b3 = 1; + { let b4 = 1; + { let b5 = 1; + { let b6 = 1; + { let b7 = 1; + { let b8 = 1; + { let b9 = 1; + { let b10 = 1; + { let b11 = 1; + { let b12 = 1; + { let b13 = 1; + { let b14 = 1; + { let b15 = 1; + { let b16 = 1; + { let b17 = 1; + { let b18 = 1; + { let b19 = 1; + { let b20 = 1; + { let b21 = 1; + { let b22 = 1; + { let b23 = 1; + { let b24 = 1; + { let b25 = 1; + { let b26 = 1; + { let b27 = 1; + function inner() { + return a + x + b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9 + b10 + + b11 + b12 + b13 + b14 + b15 + b16 + b17 + b18 + b19 + b20 + + b21 + b22 + b23 + b24 + b25 + b26 + b27; + } + eval(''); + %PrepareFunctionForOptimization(inner); + inner(); inner(); + %OptimizeFunctionOnNextCall(inner); + inner(); + } } } } } } } } } } } } } } } } } } } } } } } } } } } +} +f(); diff --git a/deps/v8/test/mjsunit/regress/regress-576225189.js b/deps/v8/test/mjsunit/regress/regress-576225189.js new file mode 100644 index 000000000000..dd73bf63ae90 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-576225189.js @@ -0,0 +1,37 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A groups object returned from the regexp results cache must be created in +// the calling realm, not in the realm that filled the entry. + +// The subject is longer than kMinLengthToCache and, as a string literal, +// internalized, so all realms evaluating this source use the same subject. +// The regexp data is shared through the compilation cache. +const kReplace = `(function() { + let groups; + "${'xy'.repeat(0x900)}".replace(/(?<n>x)y/g, function(...args) { + if (groups === undefined) groups = args[args.length - 1]; + return ''; + }); + return groups; +})()`; + +// Whether the groups object was created in the evaluating realm. +// Error.captureStackTrace installs an accessor whose getter is instantiated in +// the holder's creation realm. +const kCheck = `(function(groups) { + if (groups.n !== 'x') return false; + if (Object.getPrototypeOf(groups) !== null) return false; + Error.captureStackTrace(groups); + const getter = Object.getOwnPropertyDescriptor(groups, 'stack').get; + return Object.getPrototypeOf(getter) === Function.prototype; +})(${kReplace})`; + +const other = Realm.create(); + +// Repeated calls per realm also exercise same-realm cache hits. +assertTrue(Realm.eval(other, kCheck)); +for (let i = 0; i < 3; i++) assertTrue(eval(kCheck)); +for (let i = 0; i < 3; i++) assertTrue(Realm.eval(other, kCheck)); +assertTrue(eval(kCheck)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-540324230.js b/deps/v8/test/mjsunit/regress/regress-crbug-540324230.js new file mode 100644 index 000000000000..621876fff1af --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-540324230.js @@ -0,0 +1,28 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --allow-natives-syntax --verify-heap --conservative-stack-scanning --regexp-interpret-all + +function workerCode() { + function overflow() { + try { + overflow(); + throw 1; + } catch (e) { + try { + %NewRegExpWithBacktrackLimit(".+".repeat(99), "", 1).exec(); + } catch (e) {} + } + } + try { + performance.measureMemory(); + } catch (e) {} + try { + Object.defineProperty(d8.__proto__, "then", { + get: overflow + }); + } catch (e) {} +} + +assertEquals(undefined, new Worker(workerCode, { type: "function" }).getMessage()); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-572331419.js b/deps/v8/test/mjsunit/regress/regress-crbug-572331419.js new file mode 100644 index 000000000000..1079f914f983 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-572331419.js @@ -0,0 +1,37 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Unanchored regexps containing an anchor get the implicit `.*?` search +// prefix unrolled once. In unicode mode the unrolled step must advance by +// code point (AdvanceStringIndex), never landing between the halves of a +// surrogate pair. + +// Only matches the empty string; must not match between surrogates. +assertFalse(/(?<![\s\S])(?:(?:^)*)(?![\s\S])/mu.test("\u{1F600}")); +assertTrue(/(?<![\s\S])(?:(?:^)*)(?![\s\S])/mu.test("")); + +// Position 1 (inside the pair) is not a valid start in unicode mode. +assertEquals(2, /(?!.)|a^/u.exec("\u{1F600}").index); +assertEquals(2, /\n|(?!^)/u.exec("\u{1F600}").index); +assertEquals(2, /(?!.)|a^/v.exec("\u{1F600}").index); +assertEquals(2, /(?!.)|a^/ui.exec("\u{1F600}").index); +assertEquals(2, /(?!.)|a^/mu.exec("\u{1F600}").index); +// Control: no anchor, no unrolling. +assertEquals(2, /(?!.)/u.exec("\u{1F600}").index); +// Pair not at the unrolled position. +assertEquals(4, /(?!.)|a^/u.exec("a\u{1F600}b").index); + +// Lone surrogates are code points of their own. +assertEquals(1, /(?!.)|a^/u.exec("\uD83D").index); +assertEquals(1, /(?!.)|a^/u.exec("\uDE00").index); +assertEquals(2, /(?!.)|a^/u.exec("\uDE00\uD83D").index); + +// Without /u, code units are the unit of advance. +assertEquals(1, /\n|(?!^)/.exec("\u{1F600}").index); + +// Global / sticky variants take the OptionallyStepBackToLeadSurrogate path. +assertEquals(2, /(?!.)|a^/gu.exec("\u{1F600}").index); +assertEquals(null, /(?!.)|a^/yu.exec("\u{1F600}")); +assertEquals([""], "\u{1F600}".match(/(?!.)|a^/gu)); +assertEquals(["\u{1F600}"], "\u{1F600}".split(/\n|(?!^)/u)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-917076.js b/deps/v8/test/mjsunit/regress/regress-crbug-917076.js index 7c19c022045c..2f653edc20f4 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-917076.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-917076.js @@ -16,5 +16,5 @@ Object.defineProperty(Promise, Symbol.species, { async function foo() { } assertPromiseResult(Promise.all([foo()]), () => { - assertEquals(3, speciesCounter); + assertEquals(2, speciesCounter); }); diff --git a/deps/v8/test/mjsunit/regress/regress-declare-arguments-maybe-assigned.js b/deps/v8/test/mjsunit/regress/regress-declare-arguments-maybe-assigned.js new file mode 100644 index 000000000000..9232bf4ea711 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-declare-arguments-maybe-assigned.js @@ -0,0 +1,51 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test eager function with `var arguments = 42`. +(function testEagerVarArguments() { + let g = () => arguments; + for (let i = 0; i < 10000; i++) { + assertEquals('object', typeof g()); + } + var arguments = 42; + assertEquals(42, g()); +})(); + +// Test lazy function with `var arguments = 42`. +function testLazyVarArguments() { + let g = () => arguments; + for (let i = 0; i < 10000; i++) { + assertEquals('object', typeof g()); + } + var arguments = 42; + assertEquals(42, g()); +} +testLazyVarArguments(); + +// Test Annex B block-scoped function declaration `{ function arguments() {} }`. +function testAnnexBBlockFunctionArguments() { + let g = () => arguments; + for (let i = 0; i < 10000; i++) { + assertEquals('object', typeof g()); + } + { + function arguments() { + return 'annex-b'; + } + } + assertEquals('function', typeof g()); + assertEquals('annex-b', g()()); +} +testAnnexBBlockFunctionArguments(); + +// Test destructuring `var {arguments = 42} = {}`. +function testDestructuringVarArguments() { + let g = () => arguments; + for (let i = 0; i < 10000; i++) { + assertEquals('object', typeof g()); + } + var {arguments = 42} = {}; + assertEquals(42, g()); +} +testDestructuringVarArguments(); diff --git a/deps/v8/test/mjsunit/regress/regress-fast-proxy-deprecated-map.js b/deps/v8/test/mjsunit/regress/regress-fast-proxy-deprecated-map.js new file mode 100644 index 000000000000..d38438743d03 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-fast-proxy-deprecated-map.js @@ -0,0 +1,79 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --fast-proxy-ic --allow-natives-syntax --maglev +// Flags: --optimize-on-next-call-optimizes-to-maglev + +function makeHandler(x) { + return { + x, + get(target, prop, receiver) { + return target[prop]; + }, + }; +} + +// Test 1: Deprecated handler map in FastProxy DataHandler must not abort +// Maglev compilation when committing field dependencies. +(function TestDeprecatedHandlerMap() { + let h1 = makeHandler(1); + let h2 = makeHandler(1); + let p = new Proxy({a: 42}, h1); + + function loadFromProxy(proxy, run) { + if (run) return proxy.a; + return 0; + } + + %PrepareFunctionForOptimization(loadFromProxy); + for (let i = 0; i < 10; i++) { + assertEquals(42, loadFromProxy(p, true)); + } + + // Transition x from Smi to Double on h2, deprecating h1's map while h1 + // remains unmigrated and the proxy LoadIC DataHandler still holds h1's + // deprecated map. + h2.x = 1.5; + + loadFromProxy(p, false); + %OptimizeFunctionOnNextCall(loadFromProxy); + assertEquals(0, loadFromProxy(p, false)); + assertOptimized(loadFromProxy); + assertEquals(42, loadFromProxy(p, true)); +})(); + +// Test 2: Deprecated target map in FastProxy DataHandler must not emit a +// stale CheckMaps on the deprecated target map that immediately deopts. +(function TestDeprecatedTargetMap() { + function makeTarget(x) { + return {a: 42, x}; + } + let t1 = makeTarget(1); + let t2 = makeTarget(1); + let h = { + get(target, prop, receiver) { + return target[prop]; + }, + }; + let p = new Proxy(t1, h); + + function loadFromProxyTarget(proxy) { + return proxy.a; + } + + %PrepareFunctionForOptimization(loadFromProxyTarget); + for (let i = 0; i < 10; i++) { + assertEquals(42, loadFromProxyTarget(p)); + } + + // Deprecate t1's map via t2 and migrate t1 by reading a property on t1. + t2.x = 1.5; + assertEquals(1, t1.x); + + // Compile before executing loadFromProxyTarget again (so the DataHandler + // still holds t1's old deprecated map). + %OptimizeFunctionOnNextCall(loadFromProxyTarget); + assertEquals(42, loadFromProxyTarget(p)); + assertOptimized(loadFromProxyTarget); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-fast-proxy-keyed-miss.js b/deps/v8/test/mjsunit/regress/regress-fast-proxy-keyed-miss.js new file mode 100644 index 000000000000..43e9369b6ada --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-fast-proxy-keyed-miss.js @@ -0,0 +1,189 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --fast-proxy-ic + +const proxy = new Proxy({ a: 1 }, { + get(target, prop, receiver) { + return prop; + } +}); + +const proxy2 = new Proxy({ a: 1, b: 2 }, { + get(target, prop, receiver) { + return prop; + } +}); + +function getICState(fn) { + const feedback = %GetFeedback(fn); + if (feedback === undefined) return undefined; + return feedback[0][1].split("\n")[0]; +} + +// Test keyed loads with primitive keys (undefined, null, true, false, 1.5). +function testPrimitiveKey(key, expected) { + function load(p, k) { + return p[k]; + } + %PrepareFunctionForOptimization(load); + + for (let i = 0; i < 1000; i++) { + assertEquals(expected, load(proxy, key)); + } +} + +testPrimitiveKey(undefined, "undefined"); +testPrimitiveKey(null, "null"); +testPrimitiveKey(true, "true"); +testPrimitiveKey(false, "false"); +testPrimitiveKey(1.5, "1.5"); + +// On 64-bit platforms, non-internalized integer index strings > kMaxArrayIndex +// (2^32 - 2) bail out of CSA TryInternalizeString to Runtime_KeyedLoadIC_Miss, +// where TryConvertKey internalizes them as kName. Verify that the proxy IC +// progresses to the same state (MEGAMORPHIC on 64-bit) as a normal object IC +// instead of looping in MONOMORPHIC and allocating a new DataHandler on every +// call. +(function TestUncacheableIntegerIndexStringKeyedMiss() { + const prefix = "500000"; + const normalObj = { a: 1, 5000000000: "5000000000" }; + + function loadNormal(o, k) { + return o[k]; + } + %PrepareFunctionForOptimization(loadNormal); + assertEquals("5000000000", loadNormal(normalObj, prefix + "0000")); + assertEquals("5000000000", loadNormal(normalObj, prefix + "0000")); + const expectedState = getICState(loadNormal); + + function load(p, k) { + return p[k]; + } + %PrepareFunctionForOptimization(load); + + assertEquals("5000000000", load(proxy, prefix + "0000")); + if (expectedState !== undefined) { + assertEquals("MONOMORPHIC", getICState(load)); + } + + assertEquals("5000000000", load(proxy, prefix + "0000")); + if (expectedState !== undefined) { + assertEquals(expectedState, getICState(load)); + } + + for (let i = 0; i < 1000; i++) { + assertEquals("5000000000", load(proxy, prefix + "0000")); + } +})(); + +// Test when the slot was already downgraded from LoadProxyFast to LoadProxy +// Smi handler before missing again with a key that converts to the same Name. +(function TestDowngradedProxyIntegerIndexKeyedMiss() { + const prefix = "500000"; + const normalObj = { a: 1, 5000000000: "5000000000" }; + + function loadNormal(o, k) { + return o[k]; + } + %PrepareFunctionForOptimization(loadNormal); + loadNormal(normalObj, prefix + "0000"); + loadNormal(normalObj, prefix + "0000"); + const expectedState = getICState(loadNormal); + + function load(p, k) { + return p[k]; + } + %PrepareFunctionForOptimization(load); + + // Install LoadProxyFast for "5000000000" (on 32-bit) or LoadProxy Smi + // (on 64-bit, where "5000000000" is an integer index). + assertEquals("5000000000", load(proxy, "5000000000")); + // Downgrade to slow LoadProxy Smi handler (proxy2 has a different target map). + assertEquals("5000000000", load(proxy2, "5000000000")); + + if (expectedState !== undefined) { + assertEquals("MONOMORPHIC", getICState(load)); + } + + // Miss with non-internalized integer index string "500000" + "0000", which + // converts to "5000000000" with state() != RECOMPUTE_HANDLER. Since the + // handler is already slow LoadProxy, it must transition to MEGAMORPHIC on + // 64-bit platforms. + assertEquals("5000000000", load(proxy2, prefix + "0000")); + + if (expectedState !== undefined) { + assertEquals(expectedState, getICState(load)); + } + + for (let i = 0; i < 1000; i++) { + assertEquals("5000000000", load(proxy2, prefix + "0000")); + } +})(); + +(function TestDowngradedProxyKeyedMiss() { + const normalObj = { a: 1, "1.5": "1.5" }; + + function loadNormal(o, k) { + return o[k]; + } + %PrepareFunctionForOptimization(loadNormal); + loadNormal(normalObj, "1.5"); + loadNormal(normalObj, 1.5); + const expectedState = getICState(loadNormal); + + function load(p, k) { + return p[k]; + } + %PrepareFunctionForOptimization(load); + + // Install LoadProxyFast for "1.5". + assertEquals("1.5", load(proxy, "1.5")); + // Downgrade to slow LoadProxy Smi handler (proxy2 has a different target map). + assertEquals("1.5", load(proxy2, "1.5")); + + if (expectedState !== undefined) { + assertEquals("MONOMORPHIC", getICState(load)); + } + + // Miss with HeapNumber key 1.5, which converts to "1.5" in TryConvertKey + // with state() != RECOMPUTE_HANDLER. Since the handler is already slow + // LoadProxy, it must transition to MEGAMORPHIC. + assertEquals("1.5", load(proxy2, 1.5)); + + if (expectedState !== undefined) { + assertEquals(expectedState, getICState(load)); + } + + for (let i = 0; i < 1000; i++) { + assertEquals("1.5", load(proxy2, 1.5)); + } +})(); + +// Test monomorphic -> polymorphic IC transition with fast proxy handler. +(function TestFastProxyPolymorphicTransition() { + function load(obj) { + return obj.a; + } + %PrepareFunctionForOptimization(load); + + for (let i = 0; i < 100; i++) { + assertEquals("a", load(proxy)); + } + + if (getICState(load) !== undefined) { + assertEquals("MONOMORPHIC", getICState(load)); + } + + const normalObj = { a: 42 }; + // Load twice: with --sparkplug-plus, the first execution of the load in + // (concurrently installed) baseline code may only patch the IC call target + // without updating the feedback. + assertEquals(42, load(normalObj)); + assertEquals(42, load(normalObj)); + + if (getICState(load) !== undefined) { + assertEquals("POLYMORPHIC", getICState(load)); + } +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-fast-proxy-target-toctou.js b/deps/v8/test/mjsunit/regress/regress-fast-proxy-target-toctou.js new file mode 100644 index 000000000000..931769ca7443 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-fast-proxy-target-toctou.js @@ -0,0 +1,331 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --fast-proxy-ic --allow-natives-syntax --no-turbofan + +let uniqueCounter = 0; +function makeTarget(stableMap) { + if (!stableMap) return {}; + const obj = {}; + obj['uniqueProp_' + (uniqueCounter++)] = 1; + return obj; +} + +// 1. Test IC / CSA fast path when get trap mutates target and returns +// conflicting value. +for (const stableMap of [false, true]) { + const target = makeTarget(stableMap); + let shouldLock = false; + let trapCalls = 0; + const handler = { + get(t, prop, receiver) { + trapCalls++; + if (shouldLock) { + Object.defineProperty(t, prop, { + value: 42, + configurable: false, + writable: false, + }); + return 999; + } + return 42; + } + }; + const proxy = new Proxy(target, handler); + function read(p) { + return p.x; + } + %NeverOptimizeFunction(read); + + for (let i = 0; i < 20; i++) { + assertEquals(42, read(proxy)); + } + assertEquals(20, trapCalls); + + shouldLock = true; + assertThrows(() => read(proxy), TypeError); + assertEquals(21, trapCalls); +} + +// 2. Test IC / CSA fast path when get trap mutates target and returns +// matching value. +for (const stableMap of [false, true]) { + const target = makeTarget(stableMap); + let shouldLock = false; + let trapCalls = 0; + const handler = { + get(t, prop, receiver) { + trapCalls++; + if (shouldLock) { + Object.defineProperty(t, prop, { + value: 42, + configurable: false, + writable: false, + }); + return 42; + } + return 42; + } + }; + const proxy = new Proxy(target, handler); + function read(p) { + return p.x; + } + %NeverOptimizeFunction(read); + + for (let i = 0; i < 20; i++) { + assertEquals(42, read(proxy)); + } + assertEquals(20, trapCalls); + + shouldLock = true; + assertEquals(42, read(proxy)); + assertEquals(21, trapCalls); +} + +// 3. Test Maglev optimized code with inlined and non-inlined +// traps, both conflicting and matching values, stable and unstable target maps, +// and try/catch exception wiring. +function runOptimizedTest(inlineTrap, returnMatching, useTryCatch, stableMap) { + const target = makeTarget(stableMap); + let shouldLock = false; + let trapCalls = 0; + function lockTarget(t, prop) { + Object.defineProperty(t, prop, { + value: 42, + configurable: false, + writable: false, + }); + return returnMatching ? 42 : 999; + } + %NeverOptimizeFunction(lockTarget); + function getTrap(t, prop, receiver) { + trapCalls++; + if (shouldLock) { + return lockTarget(t, prop); + } + return 42; + } + if (!inlineTrap) { + %NeverOptimizeFunction(getTrap); + } + const handler = { get: getTrap }; + const proxy = new Proxy(target, handler); + + let read; + if (useTryCatch) { + read = function(p) { + try { + return p.x; + } catch (e) { + return e; + } + }; + } else { + read = function(p) { + return p.x; + }; + } + + %PrepareFunctionForOptimization(read); + if (inlineTrap) { + %PrepareFunctionForOptimization(getTrap); + } + for (let i = 0; i < 20; i++) { + assertEquals(42, read(proxy)); + } + %OptimizeFunctionOnNextCall(read); + assertEquals(42, read(proxy)); + const callsBefore = trapCalls; + + shouldLock = true; + if (returnMatching) { + assertEquals(42, read(proxy)); + } else if (useTryCatch) { + assertInstanceof(read(proxy), TypeError); + } else { + assertThrows(() => read(proxy), TypeError); + } + assertEquals(callsBefore + 1, trapCalls); +} + +for (const inlineTrap of [true, false]) { + for (const returnMatching of [true, false]) { + for (const useTryCatch of [true, false]) { + for (const stableMap of [false, true]) { + runOptimizedTest(inlineTrap, returnMatching, useTryCatch, stableMap); + } + } + } +} + +// 4. Test Maglev optimized code when an eagerly inlined get trap mutates the +// target and then accesses a property on the target, giving the target a fresh +// NodeInfo whose possible_maps includes the mutated map rather than only +// expected_target_map. +{ + let shouldLock = false; + function mutate(t) { + if (shouldLock) { + Object.defineProperty(t, 'x', { + value: 42, + configurable: false, + writable: false, + }); + return 999; + } + return 42; + } + %NeverOptimizeFunction(mutate); + + function getTrapWithLoad(t) { + const r = mutate(t); + t.y; + return r; + } + + %PrepareFunctionForOptimization(getTrapWithLoad); + shouldLock = true; + for (let i = 0; i < 10; i++) { + const dummy = { y: 1 }; + assertEquals(999, getTrapWithLoad(dummy)); + } + shouldLock = false; + + const target = { y: 1 }; + const proxy = new Proxy(target, { get: getTrapWithLoad }); + function readInlinedWithLoad(p) { + return p.x; + } + %PrepareFunctionForOptimization(readInlinedWithLoad); + for (let i = 0; i < 20; i++) { + assertEquals(42, readInlinedWithLoad(proxy)); + } + %OptimizeFunctionOnNextCall(readInlinedWithLoad); + assertEquals(42, readInlinedWithLoad(proxy)); + + shouldLock = true; + assertThrows(() => readInlinedWithLoad(proxy), TypeError); +} + +// 5. Test lazy deoptimization during the trap call (via explicit +// %DeoptimizeFunction, pre-existing stable map dependency in the caller, or +// eager deopt inside an inlined trap after mutating the target), verifying +// that ProxyGetPropertyTrapResultLazyDeoptContinuation validates the trap +// result without re-executing the trap. +for (const inlineTrap of [true, false]) { + for (const stableMap of [false, true]) { + const target = makeTarget(stableMap); + let shouldLock = false; + let trapCalls = 0; + let read; + + function lockAndDeopt(t, prop) { + Object.defineProperty(t, prop, { + value: 42, + configurable: false, + writable: false, + }); + %DeoptimizeFunction(read); + return 999; + } + %NeverOptimizeFunction(lockAndDeopt); + + function getTrap(t, prop) { + trapCalls++; + if (shouldLock) { + return lockAndDeopt(t, prop); + } + return 42; + } + if (!inlineTrap) { + %NeverOptimizeFunction(getTrap); + } + + const proxy = new Proxy(target, { get: getTrap }); + read = function(p, t) { + // Touch `t` before the proxy access so a stable map dependency may + // already be installed in the caller before TryBuildProxyPropertyAccess. + const before = t.nonExistent; + return p.x ?? before; + }; + + %PrepareFunctionForOptimization(read); + if (inlineTrap) { + %PrepareFunctionForOptimization(getTrap); + } + for (let i = 0; i < 20; i++) { + assertEquals(42, read(proxy, target)); + } + %OptimizeFunctionOnNextCall(read); + assertEquals(42, read(proxy, target)); + const callsBefore = trapCalls; + + shouldLock = true; + assertThrows(() => read(proxy, target), TypeError); + assertEquals(callsBefore + 1, trapCalls); + } +} + +{ + let shouldLock = false; + let trapCalls = 0; + let addend = 0; + + function mutateForEagerDeopt(t) { + trapCalls++; + if (shouldLock) { + Object.defineProperty(t, 'x', { + value: 42, + configurable: false, + writable: false, + }); + return 999; + } + return 42; + } + %NeverOptimizeFunction(mutateForEagerDeopt); + + function getTrapEagerDeopt(t) { + const r = mutateForEagerDeopt(t); + return r + addend; + } + + const target = makeTarget(false); + const proxy = new Proxy(target, { get: getTrapEagerDeopt }); + function readWithInlinedEagerDeopt(p) { + return p.x; + } + + %PrepareFunctionForOptimization(getTrapEagerDeopt); + %PrepareFunctionForOptimization(readWithInlinedEagerDeopt); + for (let i = 0; i < 20; i++) { + assertEquals(42, readWithInlinedEagerDeopt(proxy)); + } + %OptimizeFunctionOnNextCall(readWithInlinedEagerDeopt); + assertEquals(42, readWithInlinedEagerDeopt(proxy)); + const callsBefore = trapCalls; + + shouldLock = true; + // Trigger an eager Smi deopt on `r + addend` inside the inlined trap after + // `mutateForEagerDeopt(t)` has already mutated `target`. + addend = { valueOf() { return 0; } }; + assertThrows(() => readWithInlinedEagerDeopt(proxy), TypeError); + assertEquals(callsBefore + 1, trapCalls); +} + +// 6. Test that Runtime::kCheckProxyGetSetTrapResult returns the trap result +// instead of undefined. +{ + const target = {}; + assertEquals(42, %CheckProxyGetSetTrapResult('x', target, 42, 0)); + assertEquals('result', %CheckProxyGetSetTrapResult('x', target, 'result', 0)); + const obj = { a: 1 }; + assertEquals(obj, %CheckProxyGetSetTrapResult('x', target, obj, 0)); + assertEquals(undefined, %CheckProxyGetSetTrapResult('x', target, undefined, 0)); + assertEquals(null, %CheckProxyGetSetTrapResult('x', target, null, 0)); + + // AccessKind::kSet also returns the value. + assertEquals(42, %CheckProxyGetSetTrapResult('x', target, 42, 1)); +} diff --git a/deps/v8/test/mjsunit/regress/regress-homomorphic-maglev.js b/deps/v8/test/mjsunit/regress/regress-homomorphic-maglev.js index fa86e210f176..e3e9386355c0 100644 --- a/deps/v8/test/mjsunit/regress/regress-homomorphic-maglev.js +++ b/deps/v8/test/mjsunit/regress/regress-homomorphic-maglev.js @@ -16,9 +16,11 @@ function createNormalObject() { return o.a; } %PrepareFunctionForOptimization(load); + let objects = []; for (let i = 0; i < 11; i++) { let o = createNormalObject(); o.a = i; + objects.push(o); load(o); } %OptimizeMaglevOnNextCall(load); @@ -39,9 +41,11 @@ function createNormalObject() { return o.a; } %PrepareFunctionForOptimization(load); + let objects = []; for (let i = 0; i < 11; i++) { let o = createNormalObject(); o.a = i; + objects.push(o); load(o); } %OptimizeMaglevOnNextCall(load); diff --git a/deps/v8/test/mjsunit/regress/regress-homomorphic-turbofan.js b/deps/v8/test/mjsunit/regress/regress-homomorphic-turbofan.js index b0f9d8b81132..3a9a928003e5 100644 --- a/deps/v8/test/mjsunit/regress/regress-homomorphic-turbofan.js +++ b/deps/v8/test/mjsunit/regress/regress-homomorphic-turbofan.js @@ -16,9 +16,11 @@ function createNormalObject() { return o.a; } %PrepareFunctionForOptimization(load); + let objects = []; for (let i = 0; i < 11; i++) { let o = createNormalObject(); o.a = i; + objects.push(o); load(o); } %OptimizeFunctionOnNextCall(load); @@ -39,9 +41,11 @@ function createNormalObject() { return o.a; } %PrepareFunctionForOptimization(load); + let objects = []; for (let i = 0; i < 11; i++) { let o = createNormalObject(); o.a = i; + objects.push(o); load(o); } %OptimizeFunctionOnNextCall(load); diff --git a/deps/v8/test/mjsunit/regress/regress-homomorphic-unoptimized.js b/deps/v8/test/mjsunit/regress/regress-homomorphic-unoptimized.js index bc4d07af67ed..1e893fc89adb 100644 --- a/deps/v8/test/mjsunit/regress/regress-homomorphic-unoptimized.js +++ b/deps/v8/test/mjsunit/regress/regress-homomorphic-unoptimized.js @@ -16,10 +16,13 @@ function load(o) { %PrepareFunctionForOptimization(load); // Warm up with normal JS objects which have the same shape but distinct maps -// so that the LoadIC enters HOMOMORPHIC state. +// so that the LoadIC enters HOMOMORPHIC state. Keep them alive so GC stress +// does not collect their maps before the IC transitions to HOMOMORPHIC. +let objects = []; for (let i = 0; i < 11; i++) { let o = createNormalObject(); o.a = i; + objects.push(o); assertEquals(i, load(o)); } diff --git a/deps/v8/test/mjsunit/regress/regress-memory-pool-release-task.js b/deps/v8/test/mjsunit/regress/regress-memory-pool-release-task.js new file mode 100644 index 000000000000..e74146739219 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-memory-pool-release-task.js @@ -0,0 +1,24 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --trace-gc-nvp --memory-pool-timeout=1 --expose-gc + +// The memory pool release task runs on a worker thread, where +// IsolateGroup::current() may not be set. Make sure tracing from it works. + +function allocate() { + let arr = []; + for (let i = 0; i < 10000; i++) { + arr.push(new Array(100)); + } +} + +for (let i = 0; i < 10; i++) { + allocate(); + gc(); +} + +// Wait for the release task to run. +let start = Date.now(); +while (Date.now() - start < 1500) {} diff --git a/deps/v8/test/mjsunit/regress/regress-preparser-eval-default-params.js b/deps/v8/test/mjsunit/regress/regress-preparser-eval-default-params.js new file mode 100644 index 000000000000..f540569f13a0 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-preparser-eval-default-params.js @@ -0,0 +1,30 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function outer() { + var x = 1; + var y = 1; + function middle(a = eval("var x = 2"), b = () => x + y) { + var y = 3; + function inner() { + return x + y; + } + return [b(), inner()]; + } + return middle(); +} +assertEquals([3, 5], outer()); + +function outerArrow() { + var x = 10; + function middle() { + var f = (a = eval("var x = 20"), b = () => x) => b() + a; + function inner() { + return x; + } + return [f(5), inner()]; + } + return middle(); +} +assertEquals([15, 10], outerArrow()); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-1189454.js b/deps/v8/test/mjsunit/regress/wasm/regress-1189454.js index ccb6178eb952..81fb4fe36c84 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-1189454.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-1189454.js @@ -29,188 +29,1410 @@ builder.instantiate(); // We include a clusterfuzz-generated testcase for this error verbatim. const module = new WebAssembly.Module(new Uint8Array([ - 0, 97, 115, 109, 1, 0, 0, 0, 1, 51, 9, 96, 0, 0, 96, - 0, 1, 125, 96, 0, 1, 124, 96, 2, 124, 127, 1, 125, 96, 4, - 126, 126, 125, 127, 1, 127, 96, 1, 126, 1, 127, 96, 7, 127, 126, - 126, 125, 124, 127, 125, 1, 124, 96, 0, 1, 127, 96, 1, 124, 1, - 125, 3, 23, 22, 0, 4, 0, 5, 6, 0, 7, 0, 2, 0, 3, - 1, 0, 8, 0, 0, 0, 0, 0, 2, 2, 0, 4, 5, 1, 112, - 1, 9, 9, 5, 4, 1, 3, 1, 1, 6, 6, 1, 127, 1, 65, - 10, 11, 7, 213, 1, 14, 6, 102, 117, 110, 99, 95, 48, 0, 0, - 14, 102, 117, 110, 99, 95, 49, 95, 105, 110, 118, 111, 107, 101, 114, - 0, 2, 14, 102, 117, 110, 99, 95, 52, 95, 105, 110, 118, 111, 107, - 101, 114, 0, 5, 14, 102, 117, 110, 99, 95, 54, 95, 105, 110, 118, - 111, 107, 101, 114, 0, 7, 14, 102, 117, 110, 99, 95, 56, 95, 105, - 110, 118, 11, 107, 101, 114, 0, 9, 7, 102, 117, 110, 99, 95, 49, - 49, 0, 11, 15, 102, 117, 110, 99, 95, 49, 49, 95, 105, 110, 118, - 111, 107, 101, 114, 0, 12, 15, 102, 117, 110, 99, 95, 49, 51, 95, - 105, 110, 118, 111, 107, 101, 114, 0, 14, 7, 102, 117, 110, 99, 95, - 49, 53, 0, 15, 15, 102, 117, 110, 99, 95, 49, 53, 95, 105, 110, - 118, 111, 107, 101, 114, 0, 16, 15, 102, 117, 110, 99, 95, 49, 55, - 95, 105, 110, 118, 111, 107, 101, 114, 0, 18, 7, 102, 117, 110, 99, - 95, 49, 57, 0, 19, 7, 102, 117, 110, 99, 95, 50, 48, 0, 20, - 20, 104, 97, 110, 103, 76, 105, 109, 105, 116, 73, 110, 105, 116, 105, - 97, 108, 105, 122, 101, 114, 0, 21, 9, 15, 1, 0, 65, 0, 11, - 9, 4, 6, 6, 8, 10, 11, 11, 15, 15, 10, 220, 18, 22, 113, - 0, 35, 0, 69, 4, 64, 15, 11, 35, 0, 65, 1, 107, 36, 0, - 3, 64, 35, 0, 69, 4, 64, 15, 11, 35, 0, 65, 1, 107, 36, - 0, 2, 127, 35, 0, 69, 4, 64, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 65, 128, 128, 128, 4, 11, 4, 127, 65, 193, 255, 3, 5, - 2, 127, 3, 64, 35, 0, 69, 4, 64, 15, 11, 35, 0, 65, 1, - 107, 36, 0, 3, 64, 35, 0, 69, 4, 64, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 12, 1, 11, 0, 65, 0, 13, 1, 0, 11, 0, - 11, 11, 26, 12, 0, 11, 0, 11, 131, 3, 1, 1, 125, 35, 0, - 69, 4, 64, 65, 128, 128, 128, 2, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 2, 127, 2, 64, 66, 157, 228, 193, 147, 127, 3, 126, 35, - 0, 69, 4, 64, 65, 224, 196, 126, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 35, 0, 69, 4, 64, 65, 129, 128, 124, 15, 11, 35, 0, - 65, 1, 107, 36, 0, 32, 3, 65, 105, 13, 2, 13, 0, 66, 128, - 128, 128, 128, 192, 0, 11, 2, 125, 35, 0, 69, 4, 64, 32, 3, - 15, 11, 35, 0, 65, 1, 107, 36, 0, 67, 0, 0, 80, 193, 32, - 2, 2, 127, 35, 0, 69, 4, 64, 65, 117, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 32, 3, 11, 27, 34, 4, 67, 0, 0, 0, 0, - 32, 4, 32, 4, 91, 27, 11, 32, 3, 16, 1, 3, 127, 35, 0, - 69, 4, 64, 65, 168, 186, 126, 15, 11, 35, 0, 65, 1, 107, 36, - 0, 35, 0, 69, 4, 64, 65, 128, 1, 15, 11, 35, 0, 65, 1, - 107, 36, 0, 65, 255, 0, 32, 3, 69, 13, 2, 34, 3, 13, 0, - 32, 3, 11, 69, 13, 1, 32, 3, 69, 13, 1, 65, 220, 188, 126, - 13, 1, 34, 3, 4, 64, 2, 64, 2, 127, 35, 0, 69, 4, 64, - 65, 128, 128, 128, 128, 120, 15, 11, 35, 0, 65, 1, 107, 36, 0, - 32, 3, 32, 3, 13, 0, 13, 3, 35, 0, 69, 4, 64, 32, 3, - 15, 11, 35, 0, 65, 1, 107, 36, 0, 12, 1, 11, 26, 3, 127, - 35, 0, 69, 4, 64, 32, 3, 15, 11, 35, 0, 65, 1, 107, 36, - 0, 32, 3, 13, 0, 65, 1, 11, 26, 12, 2, 11, 35, 0, 69, - 4, 64, 65, 167, 127, 15, 11, 35, 0, 65, 1, 107, 36, 0, 35, - 0, 69, 4, 64, 65, 128, 192, 0, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 35, 0, 69, 4, 64, 32, 3, 15, 11, 35, 0, 65, 1, - 107, 36, 0, 65, 147, 127, 12, 2, 5, 35, 0, 69, 4, 64, 65, - 129, 128, 128, 128, 120, 15, 11, 35, 0, 65, 1, 107, 36, 0, 11, - 11, 65, 255, 255, 125, 11, 11, 33, 0, 66, 252, 130, 221, 255, 15, - 66, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 67, 0, 0, 234, - 66, 65, 252, 224, 168, 179, 122, 16, 1, 26, 11, 178, 2, 1, 2, - 127, 35, 0, 69, 4, 64, 65, 120, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 2, 127, 35, 0, 69, 4, 64, 65, 0, 15, 11, 35, 0, - 65, 1, 107, 36, 0, 2, 127, 35, 0, 69, 4, 64, 65, 0, 15, - 11, 35, 0, 65, 1, 107, 36, 0, 65, 128, 8, 11, 4, 127, 65, - 0, 5, 2, 127, 65, 0, 65, 129, 126, 69, 13, 2, 4, 64, 3, - 64, 35, 0, 69, 4, 64, 65, 159, 216, 137, 124, 15, 11, 35, 0, - 65, 1, 107, 36, 0, 65, 0, 40, 2, 3, 26, 35, 0, 69, 4, - 64, 65, 222, 136, 126, 15, 11, 35, 0, 65, 1, 107, 36, 0, 3, - 64, 35, 0, 4, 64, 35, 0, 65, 1, 107, 36, 0, 12, 1, 5, - 65, 128, 8, 15, 11, 0, 11, 0, 11, 0, 5, 3, 64, 35, 0, - 69, 4, 64, 65, 0, 15, 11, 35, 0, 65, 1, 107, 36, 0, 2, - 127, 35, 0, 69, 4, 64, 65, 0, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 65, 0, 2, 127, 35, 0, 69, 4, 64, 65, 0, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 3, 64, 35, 0, 69, 4, 64, 65, - 0, 15, 11, 35, 0, 65, 1, 107, 36, 0, 11, 65, 1, 254, 18, - 0, 22, 11, 69, 13, 0, 11, 13, 0, 35, 0, 69, 4, 64, 65, - 128, 124, 15, 11, 35, 0, 65, 1, 107, 36, 0, 3, 64, 35, 0, - 69, 4, 64, 65, 224, 216, 2, 15, 11, 35, 0, 65, 1, 107, 36, - 0, 35, 0, 69, 4, 64, 65, 128, 128, 2, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 65, 190, 127, 12, 3, 11, 0, 11, 0, 11, 0, - 11, 11, 11, 11, 23, 0, 35, 0, 69, 4, 64, 32, 4, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 65, 0, 43, 3, 2, 11, 116, 0, - 65, 141, 176, 126, 66, 217, 236, 126, 66, 128, 1, 67, 0, 0, 0, - 79, 68, 0, 0, 0, 0, 0, 0, 80, 64, 65, 76, 67, 0, 0, - 128, 95, 16, 4, 26, 65, 32, 66, 129, 128, 128, 128, 120, 66, 230, - 212, 156, 252, 15, 67, 0, 0, 160, 64, 68, 0, 0, 0, 0, 0, - 0, 224, 67, 65, 127, 67, 0, 0, 128, 128, 16, 4, 26, 65, 255, - 166, 200, 177, 123, 66, 185, 127, 66, 128, 128, 128, 128, 8, 67, 0, - 0, 0, 93, 68, 0, 0, 0, 0, 0, 0, 96, 67, 65, 150, 224, - 126, 67, 0, 0, 0, 88, 16, 4, 26, 11, 111, 0, 35, 0, 69, - 4, 64, 65, 144, 194, 0, 15, 11, 35, 0, 65, 1, 107, 36, 0, - 3, 64, 35, 0, 69, 4, 64, 65, 0, 15, 11, 35, 0, 65, 1, - 107, 36, 0, 3, 64, 35, 0, 69, 4, 64, 65, 124, 15, 11, 35, - 0, 65, 1, 107, 36, 0, 35, 0, 69, 4, 64, 65, 111, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 3, 127, 35, 0, 69, 4, 64, 65, - 128, 128, 2, 15, 11, 35, 0, 65, 1, 107, 36, 0, 65, 128, 128, - 126, 11, 69, 13, 0, 12, 1, 11, 0, 69, 0, 13, 0, 0, 11, - 0, 11, 14, 0, 16, 6, 26, 16, 6, 26, 16, 6, 26, 16, 6, - 26, 11, 34, 0, 35, 0, 69, 4, 64, 68, 0, 0, 0, 0, 0, - 0, 224, 67, 15, 11, 35, 0, 65, 1, 107, 36, 0, 68, 26, 192, - 255, 255, 255, 255, 255, 255, 11, 5, 0, 16, 8, 26, 11, 26, 0, - 35, 0, 69, 4, 64, 67, 0, 0, 0, 0, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 67, 0, 0, 128, 214, 11, 26, 0, 35, 0, 69, - 4, 64, 67, 0, 0, 0, 90, 15, 11, 35, 0, 65, 1, 107, 36, - 0, 67, 0, 0, 44, 194, 11, 8, 0, 16, 11, 26, 16, 11, 26, - 11, 26, 0, 35, 0, 69, 4, 64, 67, 0, 0, 0, 197, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 67, 117, 227, 255, 255, 11, 38, 0, - 68, 129, 255, 255, 255, 255, 255, 255, 255, 16, 13, 26, 68, 0, 0, - 0, 0, 0, 0, 16, 65, 16, 13, 26, 68, 193, 255, 255, 255, 255, - 255, 255, 255, 16, 13, 26, 11, 30, 0, 35, 0, 69, 4, 64, 15, - 11, 35, 0, 65, 1, 107, 36, 0, 35, 0, 69, 4, 64, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 11, 6, 0, 16, 15, 16, 15, 11, - 16, 0, 35, 0, 69, 4, 64, 15, 11, 35, 0, 65, 1, 107, 36, - 0, 11, 8, 0, 16, 17, 16, 17, 16, 17, 11, 52, 0, 35, 0, - 69, 4, 64, 68, 0, 0, 0, 0, 0, 0, 0, 0, 15, 11, 35, - 0, 65, 1, 107, 36, 0, 3, 124, 35, 0, 4, 124, 35, 0, 65, - 1, 107, 36, 0, 12, 1, 5, 68, 0, 0, 0, 0, 0, 128, 109, - 64, 11, 11, 11, 218, 7, 3, 4, 127, 1, 126, 2, 125, 35, 0, - 69, 4, 64, 68, 255, 255, 255, 255, 255, 255, 239, 255, 15, 11, 35, - 0, 65, 1, 107, 36, 0, 2, 124, 3, 64, 35, 0, 69, 4, 64, - 68, 0, 0, 0, 0, 0, 0, 42, 192, 15, 11, 35, 0, 65, 1, - 107, 36, 0, 2, 64, 3, 64, 35, 0, 69, 4, 64, 68, 0, 0, - 0, 0, 0, 0, 176, 64, 15, 11, 35, 0, 65, 1, 107, 36, 0, - 65, 128, 127, 34, 2, 4, 127, 32, 0, 5, 35, 0, 69, 4, 64, - 68, 0, 0, 192, 137, 207, 250, 239, 65, 15, 11, 35, 0, 65, 1, - 107, 36, 0, 3, 64, 35, 0, 69, 4, 64, 68, 0, 0, 0, 245, - 255, 255, 239, 65, 15, 11, 35, 0, 65, 1, 107, 36, 0, 65, 134, - 82, 34, 0, 33, 3, 32, 1, 69, 13, 0, 11, 35, 0, 69, 4, - 64, 68, 0, 0, 0, 0, 0, 0, 144, 192, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 32, 1, 69, 13, 2, 32, 4, 16, 3, 13, 1, - 65, 116, 33, 0, 12, 3, 11, 33, 2, 3, 127, 35, 0, 69, 4, - 64, 68, 77, 69, 29, 145, 255, 255, 255, 255, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 32, 1, 13, 0, 32, 2, 34, 0, 34, 1, 11, - 13, 0, 11, 3, 64, 35, 0, 69, 4, 64, 68, 0, 0, 0, 0, - 0, 0, 48, 64, 15, 11, 35, 0, 65, 1, 107, 36, 0, 35, 0, - 69, 4, 64, 68, 0, 0, 0, 0, 0, 160, 102, 64, 15, 11, 35, - 0, 65, 1, 107, 36, 0, 32, 1, 33, 2, 65, 7, 17, 0, 0, - 3, 127, 35, 0, 69, 4, 64, 68, 0, 0, 0, 0, 0, 0, 240, - 63, 15, 11, 35, 0, 65, 1, 107, 36, 0, 2, 127, 35, 0, 69, - 4, 64, 68, 0, 0, 0, 0, 0, 128, 78, 192, 15, 11, 35, 0, - 65, 1, 107, 36, 0, 66, 129, 128, 128, 128, 120, 66, 128, 128, 2, - 32, 0, 27, 33, 4, 65, 177, 152, 126, 11, 4, 64, 3, 64, 35, - 0, 69, 4, 64, 68, 0, 0, 0, 0, 0, 0, 16, 195, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 16, 6, 65, 15, 113, 65, 130, 128, - 126, 254, 0, 2, 0, 4, 64, 32, 0, 32, 1, 32, 2, 27, 4, - 127, 65, 207, 230, 157, 153, 4, 34, 0, 5, 65, 140, 226, 132, 187, - 6, 11, 26, 5, 67, 151, 255, 255, 255, 33, 6, 11, 32, 2, 13, - 0, 66, 128, 128, 128, 128, 128, 1, 33, 4, 11, 11, 3, 64, 35, - 0, 69, 4, 64, 68, 0, 0, 0, 0, 32, 250, 239, 64, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 32, 6, 26, 3, 127, 35, 0, 69, - 4, 64, 68, 0, 0, 0, 0, 0, 0, 128, 67, 15, 11, 35, 0, - 65, 1, 107, 36, 0, 3, 127, 35, 0, 69, 4, 64, 68, 0, 0, - 0, 0, 0, 0, 77, 64, 15, 11, 35, 0, 65, 1, 107, 36, 0, - 67, 80, 255, 55, 202, 33, 6, 32, 2, 69, 13, 0, 65, 110, 11, - 34, 3, 13, 4, 32, 2, 33, 0, 32, 3, 69, 13, 0, 65, 128, - 96, 11, 69, 13, 0, 32, 1, 4, 127, 2, 127, 35, 0, 69, 4, - 64, 68, 138, 255, 255, 255, 255, 255, 255, 255, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 35, 0, 69, 4, 64, 68, 215, 255, 255, 255, 255, - 255, 255, 255, 15, 11, 35, 0, 65, 1, 107, 36, 0, 65, 185, 127, - 2, 127, 35, 0, 69, 4, 64, 68, 0, 0, 0, 0, 0, 0, 224, - 195, 15, 11, 35, 0, 65, 1, 107, 36, 0, 65, 0, 11, 13, 0, - 4, 64, 68, 0, 0, 0, 0, 0, 0, 240, 66, 32, 3, 65, 4, - 17, 3, 0, 26, 5, 32, 1, 69, 13, 3, 11, 32, 2, 34, 1, - 11, 5, 65, 129, 1, 34, 1, 34, 0, 11, 69, 13, 2, 11, 32, - 1, 65, 15, 113, 65, 128, 128, 32, 34, 1, 254, 0, 2, 0, 69, - 13, 0, 65, 128, 128, 32, 65, 129, 128, 124, 32, 0, 27, 11, 34, - 0, 13, 0, 65, 4, 66, 217, 208, 176, 127, 254, 24, 3, 0, 12, - 0, 11, 0, 11, 3, 127, 35, 0, 69, 4, 64, 68, 0, 0, 0, - 0, 0, 128, 84, 64, 15, 11, 35, 0, 65, 1, 107, 36, 0, 35, - 0, 69, 4, 64, 68, 177, 255, 255, 255, 255, 255, 255, 255, 15, 11, - 35, 0, 65, 1, 107, 36, 0, 32, 2, 13, 0, 35, 0, 69, 4, - 64, 68, 0, 0, 0, 0, 0, 0, 64, 195, 15, 11, 35, 0, 65, - 1, 107, 36, 0, 32, 0, 69, 13, 0, 35, 0, 69, 4, 64, 68, - 0, 0, 0, 0, 0, 0, 96, 64, 15, 11, 35, 0, 65, 1, 107, - 36, 0, 3, 124, 35, 0, 69, 4, 64, 68, 0, 0, 0, 0, 0, - 0, 16, 184, 15, 11, 35, 0, 65, 1, 107, 36, 0, 32, 3, 13, - 0, 68, 0, 0, 0, 0, 0, 0, 224, 195, 11, 32, 0, 13, 2, - 26, 35, 0, 69, 4, 64, 68, 0, 0, 0, 0, 0, 0, 192, 66, - 15, 11, 35, 0, 65, 1, 107, 36, 0, 32, 1, 13, 0, 35, 0, - 69, 4, 64, 68, 0, 0, 0, 0, 0, 0, 240, 191, 15, 11, 35, - 0, 65, 1, 107, 36, 0, 65, 128, 126, 11, 13, 0, 11, 35, 0, - 69, 4, 64, 68, 136, 255, 255, 255, 255, 255, 255, 255, 15, 11, 35, - 0, 65, 1, 107, 36, 0, 68, 0, 0, 0, 0, 0, 0, 0, 192, - 11, 11, 6, 0, 65, 10, 36, 0, 11, 11, 15, 1, 0, 65, 0, - 11, 9, 109, 0, 0, 0, 0, 0, 0, 0, 38 + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x33, // section length 51 + 0x09, // types count 9 + 0x60, // type #0 $type0 kind: func + 0x00, // param count 0 + 0x00, // return count 0 + 0x60, // type #1 $type1 kind: func + 0x00, // param count 0 + 0x01, 0x7d, // return count 1: f32 + 0x60, // type #2 $type2 kind: func + 0x00, // param count 0 + 0x01, 0x7c, // return count 1: f64 + 0x60, // type #3 $type3 kind: func + 0x02, // param count 2 + 0x7c, 0x7f, // f64 i32 + 0x01, 0x7d, // return count 1: f32 + 0x60, // type #4 $type4 kind: func + 0x04, // param count 4 + 0x7e, 0x7e, 0x7d, 0x7f, // i64 i64 f32 i32 + 0x01, 0x7f, // return count 1: i32 + 0x60, // type #5 $type5 kind: func + 0x01, 0x7e, // param count 1: i64 + 0x01, 0x7f, // return count 1: i32 + 0x60, // type #6 $type6 kind: func + 0x07, // param count 7 + 0x7f, 0x7e, 0x7e, 0x7d, // i32 i64 i64 f32 + 0x7c, 0x7f, 0x7d, // f64 i32 f32 + 0x01, 0x7c, // return count 1: f64 + 0x60, // type #7 $type7 kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + 0x60, // type #8 $type8 kind: func + 0x01, 0x7c, // param count 1: f64 + 0x01, 0x7d, // return count 1: f32 + + 0x03, // section kind: Function + 0x17, // section length 23 + 0x16, // functions count 22 + 0x00, // 0 $func_0 + 0x04, // 1 $func1 (param i64 i64 f32 i32) (result i32) + 0x00, // 2 $func_1_invoker + 0x05, // 3 $func3 (param i64) (result i32) + 0x06, // 4 $func4 (param i32 i64 i64 f32 f64 i32 f32) (result f64) + 0x00, // 5 $func_4_invoker + 0x07, // 6 $func6 (result i32) + 0x00, // 7 $func_6_invoker + 0x02, // 8 $func8 (result f64) + 0x00, // 9 $func_8_invoker + 0x03, // 10 $func10 (param f64 i32) (result f32) + 0x01, // 11 $func_11 (result f32) + 0x00, // 12 $func_11_invoker + 0x08, // 13 $func13 (param f64) (result f32) + 0x00, // 14 $func_13_invoker + 0x00, // 15 $func_15 + 0x00, // 16 $func_15_invoker + 0x00, // 17 $func17 + 0x00, // 18 $func_17_invoker + 0x02, // 19 $func_19 (result f64) + 0x02, // 20 $func_20 (result f64) + 0x00, // 21 $hangLimitInitializer + + 0x04, // section kind: Table + 0x05, // section length 5 + 0x01, 0x70, 0x01, // table count 1: funcref with maximum + 0x09, // initial size 9 + 0x09, // maximum size 9 + + 0x05, // section kind: Memory + 0x04, // section length 4 + 0x01, 0x03, // memory count 1: shared with maximum + 0x01, // initial size 1 + 0x01, // maximum size 1 + + 0x06, // section kind: Global + 0x06, // section length 6 + 0x01, 0x7f, 0x01, // globals count 1: global #0: i32 mutable + 0x41, 0x0a, 0x0b, // i32.const 10 + + 0x07, // section kind: Export + 0xd5, 0x01, // section length 213 + 0x0e, // exports count 14 + // export # 0 + 0x06, // field name length: 6 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x30, // field name: func_0 + 0x00, 0x00, // kind: function index: 0 + // export # 1 + 0x0e, // field name length: 14 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x5f, 0x69, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_1_invoker + 0x00, 0x02, // kind: function index: 2 + // export # 2 + 0x0e, // field name length: 14 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x34, 0x5f, 0x69, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_4_invoker + 0x00, 0x05, // kind: function index: 5 + // export # 3 + 0x0e, // field name length: 14 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x36, 0x5f, 0x69, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_6_invoker + 0x00, 0x07, // kind: function index: 7 + // export # 4 + 0x0e, // field name length: 14 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x38, 0x5f, 0x69, + 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_8_invoker + 0x00, 0x09, // kind: function index: 9 + // export # 5 + 0x07, // field name length: 7 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x31, // field name: func_11 + 0x00, 0x0b, // kind: function index: 11 + // export # 6 + 0x0f, // field name length: 15 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x31, 0x5f, + 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_11_invoker + 0x00, 0x0c, // kind: function index: 12 + // export # 7 + 0x0f, // field name length: 15 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x33, 0x5f, + 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_13_invoker + 0x00, 0x0e, // kind: function index: 14 + // export # 8 + 0x07, // field name length: 7 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x35, // field name: func_15 + 0x00, 0x0f, // kind: function index: 15 + // export # 9 + 0x0f, // field name length: 15 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x35, 0x5f, + 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_15_invoker + 0x00, 0x10, // kind: function index: 16 + // export # 10 + 0x0f, // field name length: 15 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x37, 0x5f, + 0x69, 0x6e, 0x76, 0x6f, 0x6b, 0x65, 0x72, + // field name: func_17_invoker + 0x00, 0x12, // kind: function index: 18 + // export # 11 + 0x07, // field name length: 7 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x31, 0x39, // field name: func_19 + 0x00, 0x13, // kind: function index: 19 + // export # 12 + 0x07, // field name length: 7 + 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x32, 0x30, // field name: func_20 + 0x00, 0x14, // kind: function index: 20 + // export # 13 + 0x14, // field name length: 20 + 0x68, 0x61, 0x6e, 0x67, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x72, // field name: hangLimitInitializer + 0x00, 0x15, // kind: function index: 21 + + 0x09, // section kind: Element + 0x0f, // section length 15 + 0x01, 0x00, // segment count 1: flag: active, offset: + 0x41, 0x00, 0x0b, // i32.const 0 + 0x09, // number of elements 9 + 0x04, // index: 4 + 0x06, // index: 6 + 0x06, // index: 6 + 0x08, // index: 8 + 0x0a, // index: 10 + 0x0b, // index: 11 + 0x0b, // index: 11 + 0x0f, // index: 15 + 0x0f, // index: 15 + + 0x0a, // section kind: Code + 0xdc, 0x12, // section length 2396 + 0x16, // functions count 22 + // function #0 $func_0 + 0x71, // body size 113 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop $label2 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7f, // block (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x80, 0x80, 0x80, 0x04, // i32.const 8388608 + 0x0b, // end + 0x04, 0x7f, // if (result i32) + 0x41, 0xc1, 0xff, 0x03, // i32.const 65473 + 0x05, // else + 0x02, 0x7f, // block (result i32) $label1 + 0x03, 0x40, // loop $label0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0c, 0x01, // br $label0 + 0x0b, // end + 0x00, // unreachable + 0x41, 0x00, // i32.const 0 + 0x0d, 0x01, // br_if $label1 + 0x00, // unreachable + 0x0b, // end $label0 + 0x00, // unreachable + 0x0b, // end $label1 + 0x0b, // end + 0x1a, // drop + 0x0c, 0x00, // br $label2 + 0x0b, // end $label2 + 0x00, // unreachable + 0x0b, // end + // function #1 $func1 + 0x83, 0x03, // body size 387 + 0x01, // 1 entries in locals list + 0x01, 0x7d, // 1 local of type f32 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0x80, 0x80, 0x02, // i32.const 4194304 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7f, // block (result i32) $label0 + 0x02, 0x40, // block $label4 + 0x42, 0x9d, 0xe4, 0xc1, 0x93, 0x7f, // i64.const -227511779 + 0x03, 0x7e, // loop (result i64) $label1 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0xe0, 0xc4, 0x7e, // i32.const -23968 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x81, 0x80, 0x7c, // i32.const -65535 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x03, // local.get $var3 + 0x41, 0x69, // i32.const -23 + 0x0d, 0x02, // br_if $label0 + 0x0d, 0x00, // br_if $label1 + 0x42, 0x80, 0x80, 0x80, 0x80, 0xc0, 0x00, // i64.const 17179869184 + 0x0b, // end $label1 + 0x02, 0x7d, // block (result f32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x20, 0x03, // local.get $var3 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x43, 0x00, 0x00, 0x50, 0xc1, // f32.const -13 + 0x20, 0x02, // local.get $var2 + 0x02, 0x7f, // block (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x75, // i32.const -11 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x03, // local.get $var3 + 0x0b, // end + 0x1b, // select + 0x22, 0x04, // local.tee $var4 + 0x43, 0x00, 0x00, 0x00, 0x00, // f32.const 0.0 + 0x20, 0x04, // local.get $var4 + 0x20, 0x04, // local.get $var4 + 0x5b, // f32.eq + 0x1b, // select + 0x0b, // end + 0x20, 0x03, // local.get $var3 + 0x10, 0x01, // call $func1 + 0x03, 0x7f, // loop (result i32) $label2 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0xa8, 0xba, 0x7e, // i32.const -25304 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0x01, // i32.const 128 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0xff, 0x00, // i32.const 127 + 0x20, 0x03, // local.get $var3 + 0x45, // i32.eqz + 0x0d, 0x02, // br_if $label0 + 0x22, 0x03, // local.tee $var3 + 0x0d, 0x00, // br_if $label2 + 0x20, 0x03, // local.get $var3 + 0x0b, // end $label2 + 0x45, // i32.eqz + 0x0d, 0x01, // br_if $label0 + 0x20, 0x03, // local.get $var3 + 0x45, // i32.eqz + 0x0d, 0x01, // br_if $label0 + 0x41, 0xdc, 0xbc, 0x7e, // i32.const -24996 + 0x0d, 0x01, // br_if $label0 + 0x22, 0x03, // local.tee $var3 + 0x04, 0x40, // if + 0x02, 0x40, // block $label5 + 0x02, 0x7f, // block (result i32) $label3 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0x80, 0x80, 0x80, 0x78, // i32.const -2147483648 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x03, // local.get $var3 + 0x20, 0x03, // local.get $var3 + 0x0d, 0x00, // br_if $label3 + 0x0d, 0x03, // br_if $label4 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x20, 0x03, // local.get $var3 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0c, 0x01, // br $label5 + 0x0b, // end $label3 + 0x1a, // drop + 0x03, 0x7f, // loop (result i32) $label6 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x20, 0x03, // local.get $var3 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x03, // local.get $var3 + 0x0d, 0x00, // br_if $label6 + 0x41, 0x01, // i32.const 1 + 0x0b, // end $label6 + 0x1a, // drop + 0x0c, 0x02, // br $label4 + 0x0b, // end $label5 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0xa7, 0x7f, // i32.const -89 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0xc0, 0x00, // i32.const 8192 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x20, 0x03, // local.get $var3 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x93, 0x7f, // i32.const -109 + 0x0c, 0x02, // br $label0 + 0x05, // else + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x81, 0x80, 0x80, 0x80, 0x78, // i32.const -2147483647 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0b, // end + 0x0b, // end $label4 + 0x41, 0xff, 0xff, 0x7d, // i32.const -32769 + 0x0b, // end $label0 + 0x0b, // end + // function #2 $func_1_invoker + 0x21, // body size 33 + 0x00, // 0 entries in locals list + 0x42, 0xfc, 0x82, 0xdd, 0xff, 0x0f, // i64.const 4294394236 + 0x42, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, // i64.const 9223372036854775807 + 0x43, 0x00, 0x00, 0xea, 0x42, // f32.const 117 + 0x41, 0xfc, 0xe0, 0xa8, 0xb3, 0x7a, // i32.const -1502990212 + 0x10, 0x01, // call $func1 + 0x1a, // drop + 0x0b, // end + // function #3 $func3 + 0xb2, 0x02, // body size 306 + 0x01, // 1 entries in locals list + 0x02, 0x7f, // 2 locals of type i32 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x78, // i32.const -8 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7f, // block (result i32) $label0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7f, // block (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x80, 0x08, // i32.const 1024 + 0x0b, // end + 0x04, 0x7f, // if (result i32) + 0x41, 0x00, // i32.const 0 + 0x05, // else + 0x02, 0x7f, // block (result i32) $label4 + 0x41, 0x00, // i32.const 0 + 0x41, 0x81, 0x7e, // i32.const -255 + 0x45, // i32.eqz + 0x0d, 0x02, // br_if $label0 + 0x04, 0x40, // if + 0x03, 0x40, // loop + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x9f, 0xd8, 0x89, 0x7c, // i32.const -8229857 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x00, // i32.const 0 + 0x28, 0x02, 0x03, // i32.load offset=3 + 0x1a, // drop + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0xde, 0x88, 0x7e, // i32.const -31650 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop $label1 + 0x23, 0x00, // global.get $global0 + 0x04, 0x40, // if + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0c, 0x01, // br $label1 + 0x05, // else + 0x41, 0x80, 0x08, // i32.const 1024 + 0x0f, // return + 0x0b, // end + 0x00, // unreachable + 0x0b, // end $label1 + 0x00, // unreachable + 0x0b, // end + 0x00, // unreachable + 0x05, // else + 0x03, 0x40, // loop $label3 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7f, // block (result i32) $label2 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x00, // i32.const 0 + 0x02, 0x7f, // block (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0b, // end + 0x41, 0x01, // i32.const 1 + 0xfe, 0x12, 0x00, 0x16, // i32.atomic.load8_u offset=22 + 0x0b, // end + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label2 + 0x0b, // end $label2 + 0x0d, 0x00, // br_if $label3 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0x7c, // i32.const -512 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0xe0, 0xd8, 0x02, // i32.const 44128 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0x80, 0x02, // i32.const 32768 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0xbe, 0x7f, // i32.const -66 + 0x0c, 0x03, // br $label4 + 0x0b, // end + 0x00, // unreachable + 0x0b, // end $label3 + 0x00, // unreachable + 0x0b, // end + 0x00, // unreachable + 0x0b, // end $label4 + 0x0b, // end + 0x0b, // end $label0 + 0x0b, // end + // function #4 $func4 + 0x17, // body size 23 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x20, 0x04, // local.get $var4 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x00, // i32.const 0 + 0x2b, 0x03, 0x02, // f64.load offset=2 + 0x0b, // end + // function #5 $func_4_invoker + 0x74, // body size 116 + 0x00, // 0 entries in locals list + 0x41, 0x8d, 0xb0, 0x7e, // i32.const -26611 + 0x42, 0xd9, 0xec, 0x7e, // i64.const -18855 + 0x42, 0x80, 0x01, // i64.const 128 + 0x43, 0x00, 0x00, 0x00, 0x4f, // f32.const 2.14748365e+09 + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, // f64.const 64 + 0x41, 0x4c, // i32.const -52 + 0x43, 0x00, 0x00, 0x80, 0x5f, // f32.const 1.84467441e+19 + 0x10, 0x04, // call $func4 + 0x1a, // drop + 0x41, 0x20, // i32.const 32 + 0x42, 0x81, 0x80, 0x80, 0x80, 0x78, // i64.const -2147483647 + 0x42, 0xe6, 0xd4, 0x9c, 0xfc, 0x0f, // i64.const 4287048294 + 0x43, 0x00, 0x00, 0xa0, 0x40, // f32.const 5 + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x43, // f64.const 9223372036854776000 + 0x41, 0x7f, // i32.const -1 + 0x43, 0x00, 0x00, 0x80, 0x80, // f32.const -1.17549435e-38 + 0x10, 0x04, // call $func4 + 0x1a, // drop + 0x41, 0xff, 0xa6, 0xc8, 0xb1, 0x7b, // i32.const -1238232193 + 0x42, 0xb9, 0x7f, // i64.const -71 + 0x42, 0x80, 0x80, 0x80, 0x80, 0x08, // i64.const 2147483648 + 0x43, 0x00, 0x00, 0x00, 0x5d, // f32.const 5.76460752e+17 + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x43, // f64.const 36028797018963970 + 0x41, 0x96, 0xe0, 0x7e, // i32.const -20458 + 0x43, 0x00, 0x00, 0x00, 0x58, // f32.const 5.62949953e+14 + 0x10, 0x04, // call $func4 + 0x1a, // drop + 0x0b, // end + // function #6 $func6 + 0x6f, // body size 111 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x90, 0xc2, 0x00, // i32.const 8464 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop $label1 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop $label0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x7c, // i32.const -4 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x6f, // i32.const -17 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x7f, // loop (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x41, 0x80, 0x80, 0x02, // i32.const 32768 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x80, 0x80, 0x7e, // i32.const -32768 + 0x0b, // end + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label0 + 0x0c, 0x01, // br $label1 + 0x0b, // end $label0 + 0x00, // unreachable + 0x45, // i32.eqz + 0x00, // unreachable + 0x0d, 0x00, // br_if $label1 + 0x00, // unreachable + 0x0b, // end $label1 + 0x00, // unreachable + 0x0b, // end + // function #7 $func_6_invoker + 0x0e, // body size 14 + 0x00, // 0 entries in locals list + 0x10, 0x06, // call $func6 + 0x1a, // drop + 0x10, 0x06, // call $func6 + 0x1a, // drop + 0x10, 0x06, // call $func6 + 0x1a, // drop + 0x10, 0x06, // call $func6 + 0x1a, // drop + 0x0b, // end + // function #8 $func8 + 0x22, // body size 34 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x43, // f64.const 9223372036854776000 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x44, 0x1a, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffc01a + 0x0b, // end + // function #9 $func_8_invoker + 0x05, // body size 5 + 0x00, // 0 entries in locals list + 0x10, 0x08, // call $func8 + 0x1a, // drop + 0x0b, // end + // function #10 $func10 + 0x1a, // body size 26 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x43, 0x00, 0x00, 0x00, 0x00, // f32.const 0.0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x43, 0x00, 0x00, 0x80, 0xd6, // f32.const -7.03687442e+13 + 0x0b, // end + // function #11 $func_11 + 0x1a, // body size 26 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x43, 0x00, 0x00, 0x00, 0x5a, // f32.const 9.00719925e+15 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x43, 0x00, 0x00, 0x2c, 0xc2, // f32.const -43 + 0x0b, // end + // function #12 $func_11_invoker + 0x08, // body size 8 + 0x00, // 0 entries in locals list + 0x10, 0x0b, // call $func_11 + 0x1a, // drop + 0x10, 0x0b, // call $func_11 + 0x1a, // drop + 0x0b, // end + // function #13 $func13 + 0x1a, // body size 26 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x43, 0x00, 0x00, 0x00, 0xc5, // f32.const -2048 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x43, 0x75, 0xe3, 0xff, 0xff, // f32.const -nan:0x7fe375 + 0x0b, // end + // function #14 $func_13_invoker + 0x26, // body size 38 + 0x00, // 0 entries in locals list + 0x44, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffff81 + 0x10, 0x0d, // call $func13 + 0x1a, // drop + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x41, // f64.const 262144 + 0x10, 0x0d, // call $func13 + 0x1a, // drop + 0x44, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffffc1 + 0x10, 0x0d, // call $func13 + 0x1a, // drop + 0x0b, // end + // function #15 $func_15 + 0x1e, // body size 30 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0b, // end + // function #16 $func_15_invoker + 0x06, // body size 6 + 0x00, // 0 entries in locals list + 0x10, 0x0f, // call $func_15 + 0x10, 0x0f, // call $func_15 + 0x0b, // end + // function #17 $func17 + 0x10, // body size 16 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0b, // end + // function #18 $func_17_invoker + 0x08, // body size 8 + 0x00, // 0 entries in locals list + 0x10, 0x11, // call $func17 + 0x10, 0x11, // call $func17 + 0x10, 0x11, // call $func17 + 0x0b, // end + // function #19 $func_19 + 0x34, // body size 52 + 0x00, // 0 entries in locals list + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // f64.const 0.0 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x7c, // loop (result f64) $label0 + 0x23, 0x00, // global.get $global0 + 0x04, 0x7c, // if (result f64) + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x0c, 0x01, // br $label0 + 0x05, // else + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x6d, 0x40, // f64.const 236 + 0x0b, // end + 0x0b, // end $label0 + 0x0b, // end + // function #20 $func_20 + 0xda, 0x07, // body size 986 + 0x03, // 3 entries in locals list + 0x04, 0x7f, // 4 locals of type i32 + 0x01, 0x7e, // 1 local of type i64 + 0x02, 0x7d, // 2 locals of type f32 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, // f64.const -1.7976931348623157e+308 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7c, // block (result f64) $label14 + 0x03, 0x40, // loop $label3 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0xc0, // f64.const -13 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x40, // block $label1 + 0x03, 0x40, // loop $label2 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x40, // f64.const 4096 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x80, 0x7f, // i32.const -128 + 0x22, 0x02, // local.tee $var2 + 0x04, 0x7f, // if (result i32) + 0x20, 0x00, // local.get $var0 + 0x05, // else + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0xc0, 0x89, 0xcf, 0xfa, 0xef, 0x41, // f64.const 4292246606 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x40, // loop $label0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0xf5, 0xff, 0xff, 0xef, 0x41, // f64.const 4294967208 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x86, 0x52, // i32.const -5882 + 0x22, 0x00, // local.tee $var0 + 0x21, 0x03, // local.set $var3 + 0x20, 0x01, // local.get $var1 + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label0 + 0x0b, // end $label0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xc0, // f64.const -1024 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x01, // local.get $var1 + 0x45, // i32.eqz + 0x0d, 0x02, // br_if $label1 + 0x20, 0x04, // local.get $var4 + 0x10, 0x03, // call $func3 + 0x0d, 0x01, // br_if $label2 + 0x41, 0x74, // i32.const -12 + 0x21, 0x00, // local.set $var0 + 0x0c, 0x03, // br $label3 + 0x0b, // end + 0x21, 0x02, // local.set $var2 + 0x03, 0x7f, // loop (result i32) $label4 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x4d, 0x45, 0x1d, 0x91, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffff911d454d + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x01, // local.get $var1 + 0x0d, 0x00, // br_if $label4 + 0x20, 0x02, // local.get $var2 + 0x22, 0x00, // local.tee $var0 + 0x22, 0x01, // local.tee $var1 + 0x0b, // end $label4 + 0x0d, 0x00, // br_if $label2 + 0x0b, // end $label2 + 0x03, 0x40, // loop $label10 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, // f64.const 16 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x66, 0x40, // f64.const 181 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x01, // local.get $var1 + 0x21, 0x02, // local.set $var2 + 0x41, 0x07, // i32.const 7 + 0x11, 0x00, 0x00, // call_indirect + 0x03, 0x7f, // loop (result i32) $label11 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // f64.const 1 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x02, 0x7f, // block (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4e, 0xc0, // f64.const -61 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x42, 0x81, 0x80, 0x80, 0x80, 0x78, // i64.const -2147483647 + 0x42, 0x80, 0x80, 0x02, // i64.const 32768 + 0x20, 0x00, // local.get $var0 + 0x1b, // select + 0x21, 0x04, // local.set $var4 + 0x41, 0xb1, 0x98, 0x7e, // i32.const -29647 + 0x0b, // end + 0x04, 0x40, // if + 0x03, 0x40, // loop $label5 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xc3, // f64.const -1125899906842624 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x10, 0x06, // call $func6 + 0x41, 0x0f, // i32.const 15 + 0x71, // i32.and + 0x41, 0x82, 0x80, 0x7e, // i32.const -32766 + 0xfe, 0x00, 0x02, 0x00, // memory.atomic.notify + 0x04, 0x40, // if + 0x20, 0x00, // local.get $var0 + 0x20, 0x01, // local.get $var1 + 0x20, 0x02, // local.get $var2 + 0x1b, // select + 0x04, 0x7f, // if (result i32) + 0x41, 0xcf, 0xe6, 0x9d, 0x99, 0x04, // i32.const 1126658895 + 0x22, 0x00, // local.tee $var0 + 0x05, // else + 0x41, 0x8c, 0xe2, 0x84, 0xbb, 0x06, // i32.const 1734422796 + 0x0b, // end + 0x1a, // drop + 0x05, // else + 0x43, 0x97, 0xff, 0xff, 0xff, // f32.const -nan:0x7fff97 + 0x21, 0x06, // local.set $var6 + 0x0b, // end + 0x20, 0x02, // local.get $var2 + 0x0d, 0x00, // br_if $label5 + 0x42, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, // i64.const 34359738368 + 0x21, 0x04, // local.set $var4 + 0x0b, // end $label5 + 0x0b, // end + 0x03, 0x40, // loop $label8 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x20, 0xfa, 0xef, 0x40, // f64.const 65489 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x06, // local.get $var6 + 0x1a, // drop + 0x03, 0x7f, // loop (result i32) $label7 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, // f64.const 144115188075855870 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x7f, // loop (result i32) $label6 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x40, // f64.const 58 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x43, 0x50, 0xff, 0x37, 0xca, // f32.const -3014612 + 0x21, 0x06, // local.set $var6 + 0x20, 0x02, // local.get $var2 + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label6 + 0x41, 0x6e, // i32.const -18 + 0x0b, // end $label6 + 0x22, 0x03, // local.tee $var3 + 0x0d, 0x04, // br_if $label1 + 0x20, 0x02, // local.get $var2 + 0x21, 0x00, // local.set $var0 + 0x20, 0x03, // local.get $var3 + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label7 + 0x41, 0x80, 0x60, // i32.const -4096 + 0x0b, // end $label7 + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label8 + 0x20, 0x01, // local.get $var1 + 0x04, 0x7f, // if (result i32) + 0x02, 0x7f, // block (result i32) $label9 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffff8a + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffffd7 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0xb9, 0x7f, // i32.const -71 + 0x02, 0x7f, // block (result i32) + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xc3, // f64.const -9223372036854776000 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x00, // i32.const 0 + 0x0b, // end + 0x0d, 0x00, // br_if $label9 + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x42, // f64.const 281474976710656 + 0x20, 0x03, // local.get $var3 + 0x41, 0x04, // i32.const 4 + 0x11, 0x03, 0x00, // call_indirect (param f64 i32) (result f32) + 0x1a, // drop + 0x05, // else + 0x20, 0x01, // local.get $var1 + 0x45, // i32.eqz + 0x0d, 0x03, // br_if $label8 + 0x0b, // end + 0x20, 0x02, // local.get $var2 + 0x22, 0x01, // local.tee $var1 + 0x0b, // end $label9 + 0x05, // else + 0x41, 0x81, 0x01, // i32.const 129 + 0x22, 0x01, // local.tee $var1 + 0x22, 0x00, // local.tee $var0 + 0x0b, // end + 0x45, // i32.eqz + 0x0d, 0x02, // br_if $label10 + 0x0b, // end $label8 + 0x20, 0x01, // local.get $var1 + 0x41, 0x0f, // i32.const 15 + 0x71, // i32.and + 0x41, 0x80, 0x80, 0x20, // i32.const 524288 + 0x22, 0x01, // local.tee $var1 + 0xfe, 0x00, 0x02, 0x00, // memory.atomic.notify + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label11 + 0x41, 0x80, 0x80, 0x20, // i32.const 524288 + 0x41, 0x81, 0x80, 0x7c, // i32.const -65535 + 0x20, 0x00, // local.get $var0 + 0x1b, // select + 0x0b, // end $label11 + 0x22, 0x00, // local.tee $var0 + 0x0d, 0x00, // br_if $label10 + 0x41, 0x04, // i32.const 4 + 0x42, 0xd9, 0xd0, 0xb0, 0x7f, // i64.const -1300391 + 0xfe, 0x18, 0x03, 0x00, // i64.atomic.store + 0x0c, 0x00, // br $label10 + 0x0b, // end $label10 + 0x00, // unreachable + 0x0b, // end $label1 + 0x03, 0x7f, // loop (result i32) $label12 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x54, 0x40, // f64.const 82 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffffb1 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x02, // local.get $var2 + 0x0d, 0x00, // br_if $label12 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc3, // f64.const -9007199254740992 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x00, // local.get $var0 + 0x45, // i32.eqz + 0x0d, 0x00, // br_if $label12 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x40, // f64.const 128 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x03, 0x7c, // loop (result f64) $label13 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb8, // f64.const -1.1754943508222875e-38 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x03, // local.get $var3 + 0x0d, 0x00, // br_if $label13 + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xc3, // f64.const -9223372036854776000 + 0x0b, // end $label13 + 0x20, 0x00, // local.get $var0 + 0x0d, 0x02, // br_if $label14 + 0x1a, // drop + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x42, // f64.const 35184372088832 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x20, 0x01, // local.get $var1 + 0x0d, 0x00, // br_if $label12 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf, // f64.const -1 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x41, 0x80, 0x7e, // i32.const -256 + 0x0b, // end $label12 + 0x0d, 0x00, // br_if $label3 + 0x0b, // end $label3 + 0x23, 0x00, // global.get $global0 + 0x45, // i32.eqz + 0x04, 0x40, // if + 0x44, 0x88, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // f64.const -nan:0xfffffffffff88 + 0x0f, // return + 0x0b, // end + 0x23, 0x00, // global.get $global0 + 0x41, 0x01, // i32.const 1 + 0x6b, // i32.sub + 0x24, 0x00, // global.set $global0 + 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, // f64.const -2 + 0x0b, // end $label14 + 0x0b, // end + // function #21 $hangLimitInitializer + 0x06, // body size 6 + 0x00, // 0 entries in locals list + 0x41, 0x0a, // i32.const 10 + 0x24, 0x00, // global.set $global0 + 0x0b, // end + + 0x0b, // section kind: Data + 0x0f, // section length 15 + 0x01, 0x00, // data segments count 1: flag: active no index + 0x41, 0x00, 0x0b, // i32.const 0 + 0x09, // source size 9 + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x26, // segment data ])); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-12866.js b/deps/v8/test/mjsunit/regress/wasm/regress-12866.js index d96aaf95d073..e90a9fb00d2a 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-12866.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-12866.js @@ -2,5 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -let empty_module = Uint8Array.from([0, 97, 115, 109, 1, 0, 0, 0]); +let empty_module = Uint8Array.from([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version +]); new WebAssembly.Instance(new WebAssembly.Module(empty_module)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-355493919.js b/deps/v8/test/mjsunit/regress/wasm/regress-355493919.js index c6beb68ed235..c5da448bc25c 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-355493919.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-355493919.js @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax +// Flags: --allow-natives-syntax --stack-size=100 class C0 { constructor() { - try { new C0; } catch (e) {} + try { new C0; } catch (e) { const v5 = %WasmStruct(); + } } } new C0; diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-358393368.js b/deps/v8/test/mjsunit/regress/wasm/regress-358393368.js index 02b175aff33f..aee1f6f1f5ff 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-358393368.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-358393368.js @@ -4,14 +4,89 @@ function f() { const arr = new Uint8Array([ - 0, 97, 115, 109, 1, 0, 0, 0, 1, 11, 2, 96, 2, 126, 124, 1, 126, 96, 0, 1, - 124, 3, 2, 1, 0, 4, 5, 1, 112, 1, 6, 6, 10, 114, 1, 112, 4, 244, 2, 127, - 118, 126, 31, 125, 1, 124, 2, 126, 2, 64, 2, 127, 3, 64, 2, 124, 3, 127, - 65, 0, 65, 0, 13, 3, 33, 142, 1, 65, 0, 13, 0, 65, 0, 11, 65, 0, 13, 2, 34, - 143, 1, 34, 241, 2, 34, 191, 2, 34, 242, 2, 34, 208, 2, 33, 144, 1, 2, 127, - 65, 0, 4, 64, 65, 0, 13, 5, 11, 65, 0, 11, 33, 145, 1, 65, 0, 17, 1, 0, 11, - 33, 139, 4, 65, 0, 13, 0, 11, 12, 1, 11, 13, 0, 11, 66, 128, 127, 34, 189, - 3, 65, 0, 13, 0, 34, 199, 3, 11, 11 + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x0b, // section length 11 + 0x02, // types count 2 + 0x60, // kind: func + 0x02, // param count 2 + 0x7e, 0x7c, // i64 f64 + 0x01, 0x7e, // return count 1: i64 + 0x60, // kind: func + 0x00, // param count 0 + 0x01, 0x7c, // return count 1: f64 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $func0 (param i64 f64) (result i64) + + 0x04, // section kind: Table + 0x05, // section length 5 + 0x01, 0x70, 0x01, // table count 1: funcref with maximum + 0x06, // initial size 6 + 0x06, // maximum size 6 + + 0x0a, // section kind: Code + 0x72, // section length 114 + 0x01, // functions count 1 + // function #0 $func0 + 0x70, // body size 112 + 0x04, // 4 entries in locals list + 0xf4, 0x02, 0x7f, // 372 locals of type i32 + 0x76, 0x7e, // 118 locals of type i64 + 0x1f, 0x7d, // 31 locals of type f32 + 0x01, 0x7c, // 1 local of type f64 + 0x02, 0x7e, // block (result i64) $label4 + 0x02, 0x40, // block $label2 + 0x02, 0x7f, // block (result i32) $label0 + 0x03, 0x40, // loop $label3 + 0x02, 0x7c, // block (result f64) + 0x03, 0x7f, // loop (result i32) $label1 + 0x41, 0x00, // i32.const 0 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x03, // br_if $label0 + 0x21, 0x8e, 0x01, // local.set $var142 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x00, // br_if $label1 + 0x41, 0x00, // i32.const 0 + 0x0b, // end $label1 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x02, // br_if $label0 + 0x22, 0x8f, 0x01, // local.tee $var143 + 0x22, 0xf1, 0x02, // local.tee $var369 + 0x22, 0xbf, 0x02, // local.tee $var319 + 0x22, 0xf2, 0x02, // local.tee $var370 + 0x22, 0xd0, 0x02, // local.tee $var336 + 0x21, 0x90, 0x01, // local.set $var144 + 0x02, 0x7f, // block (result i32) + 0x41, 0x00, // i32.const 0 + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0d, 0x05, // br_if $label2 + 0x0b, // end + 0x41, 0x00, // i32.const 0 + 0x0b, // end + 0x21, 0x91, 0x01, // local.set $var145 + 0x41, 0x00, // i32.const 0 + 0x11, 0x01, 0x00, // call_indirect (result f64) + 0x0b, // end + 0x21, 0x8b, 0x04, // local.set $var523 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x00, // br_if $label3 + 0x0b, // end $label3 + 0x0c, 0x01, // br $label2 + 0x0b, // end $label0 + 0x0d, 0x00, // br_if $label2 + 0x0b, // end $label2 + 0x42, 0x80, 0x7f, // i64.const -128 + 0x22, 0xbd, 0x03, // local.tee $var445 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x00, // br_if $label4 + 0x22, 0xc7, 0x03, // local.tee $var455 + 0x0b, // end $label4 + 0x0b, // end ]); WebAssembly.instantiate(arr); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-399402814.js b/deps/v8/test/mjsunit/regress/wasm/regress-399402814.js index daaf25b68ae7..fd8d87444d6d 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-399402814.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-399402814.js @@ -4,7 +4,10 @@ // Flags: --allow-natives-syntax -let empty_module = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0]); +let empty_module = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version +]); let module = new WebAssembly.Module(empty_module); let instance = new WebAssembly.Instance(module, {}); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-449010912.js b/deps/v8/test/mjsunit/regress/wasm/regress-449010912.js index 59fdd87618b4..7e5c435900c9 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-449010912.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-449010912.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --no-liftoff --flush-denormals +// Flags: --no-liftoff d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-502287689.js b/deps/v8/test/mjsunit/regress/wasm/regress-502287689.js deleted file mode 100644 index 5d8a8b01561b..000000000000 --- a/deps/v8/test/mjsunit/regress/wasm/regress-502287689.js +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector - -'use strict'; - -let wasmScriptId = null; -let lastBreakpointId = null; -let scriptIds = []; - -function receive(m) { - let msg = JSON.parse(m); - if (msg.method === 'Debugger.scriptParsed') { - if (msg.params.url.startsWith('wasm://')) { - wasmScriptId = msg.params.scriptId; - print('Wasm script parsed: ' + wasmScriptId); - } - scriptIds.push(msg.params.scriptId); - } - if (msg.id === 2) { - lastBreakpointId = msg.result.breakpointId; - } -} - -function handleInspectorMessage() { - print('Paused!'); - - // 5) Remove BP at Y (offset 34) - // This will call UpdateReturnAddresses with a new code that (buggy) - // might not have a source position for Y. - if (lastBreakpointId) { - print('Removing breakpoint at Y: ' + lastBreakpointId); - send(JSON.stringify({ - id: 10, - method: 'Debugger.removeBreakpoint', - params: {breakpointId: lastBreakpointId} - })); - } - - // 6) Set BP at X (offset 37) - // This would be the next step in the two-isolate PoC, but we might have - // already crashed. - print('Setting breakpoint at X...'); - send(JSON.stringify({ - id: 11, - method: 'Debugger.setBreakpoint', - params: - {location: {scriptId: wasmScriptId, lineNumber: 0, columnNumber: 37}} - })); - - // 8) Resume - print('Resuming...'); - send(JSON.stringify({id: 12, method: 'Debugger.resume'})); -} - -// Enable debugger -send(JSON.stringify({id: 1, method: 'Debugger.enable'})); - -const bytes = new Uint8Array([ - 0x00,0x61,0x73,0x6d, 0x01,0x00,0x00,0x00, - 0x01,0x06, 0x01, 0x60,0x01,0x7f,0x01,0x7f, - 0x03,0x02, 0x01, 0x00, - 0x07,0x05, 0x01, 0x01,0x66, 0x00,0x00, - 0x0a,0x12, 0x01, - 0x10, 0x00, - 0x41,0x0a, - 0x41,0x02, // Y = 34 (relative to module start) - 0x6a, - 0x41,0x03, // X = 37 - 0x6a, - 0x20,0x00, - 0x6d, - 0x20,0x00, - 0x6d, - 0x0b -]); - -// Wait for Debugger.enable to be processed and scriptParsed to be sent. -// In d8 this happens when we give it a chance to pump messages. -// Calling WebAssembly.Module should trigger it. -const module = new WebAssembly.Module(bytes); -const instance = new WebAssembly.Instance(module); - -if (!wasmScriptId) { - // Try to find it in scriptIds - wasmScriptId = - scriptIds.find(id => id > 3); // Wasm scripts usually have higher IDs -} - -print('Using wasmScriptId: ' + wasmScriptId); - -print('Setting breakpoint at Y (offset 34)...'); -send(JSON.stringify({ - id: 2, - method: 'Debugger.setBreakpoint', - params: {location: {scriptId: wasmScriptId, lineNumber: 0, columnNumber: 34}} -})); - -print('Calling f(7)...'); -try { - instance.exports.f(7); -} catch (e) { - print('Caught: ' + e); -} -print('Finished.'); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-502300817.js b/deps/v8/test/mjsunit/regress/wasm/regress-502300817.js index 860b86c347ae..f22bd5e38bb0 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-502300817.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-502300817.js @@ -3,19 +3,115 @@ // found in the LICENSE file. const bytes = new Uint8Array([ -0x00,0x61,0x73,0x6d,0x01,0x00,0x00,0x00,0x01,0x12,0x03,0x60,0x01,0x7e,0x01,0x7e, -0x60,0x02,0x7e,0x7e,0x01,0x7e,0x60,0x03,0x7e,0x7e,0x7f,0x00,0x03,0x04,0x03,0x00, -0x01,0x02,0x05,0x05,0x02,0x04,0x02,0x04,0x01,0x07,0x32,0x05,0x02,0x6d,0x30,0x02, -0x00,0x02,0x6d,0x31,0x02,0x01,0x0c,0x63,0x6f,0x72,0x72,0x75,0x70,0x74,0x5f,0x6c, -0x6f,0x61,0x64,0x00,0x00,0x08,0x6f,0x6f,0x62,0x5f,0x72,0x65,0x61,0x64,0x00,0x01, -0x0a,0x6f,0x6f,0x62,0x5f,0x77,0x72,0x69,0x74,0x65,0x38,0x00,0x02,0x0a,0x37,0x03, -0x11,0x00,0x42,0x00,0x41,0xc1,0x00,0x20,0x00,0xfc,0x0b,0x00,0x42,0x00,0x29,0x03, -0x00,0x0b,0x10,0x00,0x42,0x00,0x41,0x00,0x20,0x00,0xfc,0x0b,0x00,0x20,0x01,0x29, -0x03,0x00,0x0b,0x12,0x00,0x42,0x00,0x41,0x00,0x20,0x00,0xfc,0x0b,0x00,0x20,0x01, -0x20,0x02,0x3a,0x00,0x00,0x0b,0x00,0x2c,0x04,0x6e,0x61,0x6d,0x65,0x01,0x25,0x03, -0x00,0x0c,0x63,0x6f,0x72,0x72,0x75,0x70,0x74,0x5f,0x6c,0x6f,0x61,0x64,0x01,0x08, -0x6f,0x6f,0x62,0x5f,0x72,0x65,0x61,0x64,0x02,0x0a,0x6f,0x6f,0x62,0x5f,0x77,0x72, -0x69,0x74,0x65,0x38, + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x12, // section length 18 + 0x03, // types count 3 + 0x60, // kind: func + 0x01, 0x7e, // param count 1: i64 + 0x01, 0x7e, // return count 1: i64 + 0x60, // kind: func + 0x02, // param count 2 + 0x7e, 0x7e, // i64 i64 + 0x01, 0x7e, // return count 1: i64 + 0x60, // kind: func + 0x03, // param count 3 + 0x7e, 0x7e, 0x7f, // i64 i64 i32 + 0x00, // return count 0 + + 0x03, // section kind: Function + 0x04, // section length 4 + 0x03, // functions count 3 + 0x00, // 0 $corrupt_load (param i64) (result i64) + 0x01, // 1 $oob_read (param i64 i64) (result i64) + 0x02, // 2 $oob_write8 (param i64 i64 i32) + + 0x05, // section kind: Memory + 0x05, // section length 5 + 0x02, // memory count 2 + 0x04, // mem64 no maximum + 0x02, // initial size 2 + 0x04, // mem64 no maximum + 0x01, // initial size 1 + + 0x07, // section kind: Export + 0x32, // section length 50 + 0x05, // exports count 5 + // export # 0 + 0x02, // field name length: 2 + 0x6d, 0x30, // field name: m0 + 0x02, 0x00, // kind: memory memory index + // export # 1 + 0x02, // field name length: 2 + 0x6d, 0x31, // field name: m1 + 0x02, 0x01, // kind: memory memory index + // export # 2 + 0x0c, // field name length: 12 + 0x63, 0x6f, 0x72, 0x72, 0x75, 0x70, 0x74, 0x5f, + 0x6c, 0x6f, 0x61, 0x64, // field name: corrupt_load + 0x00, 0x00, // kind: function index: 0 + // export # 3 + 0x08, // field name length: 8 + 0x6f, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x61, 0x64, // field name: oob_read + 0x00, 0x01, // kind: function index: 1 + // export # 4 + 0x0a, // field name length: 10 + 0x6f, 0x6f, 0x62, 0x5f, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x38, // field name: oob_write8 + 0x00, 0x02, // kind: function index: 2 + + 0x0a, // section kind: Code + 0x37, // section length 55 + 0x03, // functions count 3 + // function #0 $corrupt_load + 0x11, // body size 17 + 0x00, // 0 entries in locals list + 0x42, 0x00, // i64.const 0 + 0x41, 0xc1, 0x00, // i32.const 65 + 0x20, 0x00, // local.get $var0 + 0xfc, 0x0b, 0x00, // memory.fill + 0x42, 0x00, // i64.const 0 + 0x29, 0x03, 0x00, // i64.load + 0x0b, // end + // function #1 $oob_read + 0x10, // body size 16 + 0x00, // 0 entries in locals list + 0x42, 0x00, // i64.const 0 + 0x41, 0x00, // i32.const 0 + 0x20, 0x00, // local.get $var0 + 0xfc, 0x0b, 0x00, // memory.fill + 0x20, 0x01, // local.get $var1 + 0x29, 0x03, 0x00, // i64.load + 0x0b, // end + // function #2 $oob_write8 + 0x12, // body size 18 + 0x00, // 0 entries in locals list + 0x42, 0x00, // i64.const 0 + 0x41, 0x00, // i32.const 0 + 0x20, 0x00, // local.get $var0 + 0xfc, 0x0b, 0x00, // memory.fill + 0x20, 0x01, // local.get $var1 + 0x20, 0x02, // local.get $var2 + 0x3a, 0x00, 0x00, // i32.store8 + 0x0b, // end + + 0x00, // section kind: Unknown + 0x2c, // section length 44 + 0x04, // section name length: 4 + 0x6e, 0x61, 0x6d, 0x65, // section name: name + 0x01, // name type: function + 0x25, // payload length: 37 + 0x03, // names count 3 + 0x00, 0x0c, // index 0 name length: 12 + 0x63, 0x6f, 0x72, 0x72, 0x75, 0x70, 0x74, 0x5f, + 0x6c, 0x6f, 0x61, 0x64, // name: corrupt_load + 0x01, 0x08, // index 1 name length: 8 + 0x6f, 0x6f, 0x62, 0x5f, 0x72, 0x65, 0x61, 0x64, // name: oob_read + 0x02, 0x0a, // index 2 name length: 10 + 0x6f, 0x6f, 0x62, 0x5f, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x38, // name: oob_write8 ]); async function run() { diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-513413942.js b/deps/v8/test/mjsunit/regress/wasm/regress-513413942.js deleted file mode 100644 index fbff72e2e43e..000000000000 --- a/deps/v8/test/mjsunit/regress/wasm/regress-513413942.js +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --allow-natives-syntax --no-wasm-tier-up -// Flags: --no-wasm-trap-handler --stress-wasm-memory-moving - -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); - -let wasmScriptId = null; -let instance = null; - -globalThis.receive = function(m) { - let msg = JSON.parse(m); - if (msg.method === 'Debugger.scriptParsed') { - if (msg.params.url && msg.params.url.startsWith('wasm://')) { - wasmScriptId = msg.params.scriptId; - } - } -}; - -globalThis.handleInspectorMessage = function() { - send(JSON.stringify({id: 100, method: 'Debugger.resume'})); -}; - -const builder = new WasmModuleBuilder(); -builder.addMemory(1, 1000); -builder.exportMemoryAs('memory', 0); - -const body = [ - ...wasmI32Const(0), - kExprI32LoadMem, 0, 0, - kExprDrop, - kExprNop, - ...wasmI32Const(0), - ...wasmI32Const(123), - kExprI32StoreMem, 0, 0, -]; - -const target = builder.addFunction('target', kSig_v_v) - .addBody(body) - .exportFunc(); - -const module_bytes = builder.toBuffer(); -const nop_offset = target.body_offset + 6; - -send(JSON.stringify({id: 1, method: 'Debugger.enable'})); -const module = new WebAssembly.Module(module_bytes); -instance = new WebAssembly.Instance(module); -globalThis.instance = instance; -globalThis.grown = false; - -const condition = `(function() { - if (!globalThis.grown) { - globalThis.instance.exports.memory.grow(1); - globalThis.grown = true; - return true; - } - return false; -})()`; - -send(JSON.stringify({ - id: 2, - method: 'Debugger.setBreakpoint', - params: { - location: {scriptId: wasmScriptId, lineNumber: 0, columnNumber: nop_offset}, - condition: condition - } -})); - -instance.exports.target(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-519715438.js b/deps/v8/test/mjsunit/regress/wasm/regress-519715438.js deleted file mode 100644 index dcb6cf440050..000000000000 --- a/deps/v8/test/mjsunit/regress/wasm/regress-519715438.js +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --no-wasm-trap-handler --stress-wasm-memory-moving - -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); - -let cdpId = 0; -function cdp(method, params) { - send(JSON.stringify({id: ++cdpId, method, params: params || {}})); -} - -let pauseHandled = false; -globalThis.handleInspectorMessage = function() { - // Called in a loop by d8's runMessageLoopOnPause while the optimized Wasm - // frame is on the stack. - if (!pauseHandled) { - pauseHandled = true; - let r = mem.grow(10); - } - cdp('Debugger.resume'); -}; - -const builder = new WasmModuleBuilder(); -builder.addMemory(1, 100); -builder.exportMemoryAs('mem'); -const setupIdx = builder.addImport('env', 'setup', kSig_v_v); - -builder.addFunction('vuln', kSig_v_i) - .addLocals(kWasmI32, 1) - .addBody([ - kExprCallFunction, setupIdx, - kExprLoop, kWasmVoid, - kExprI32Const, 4, - ...wasmI32Const(0x41414141), - kExprI32StoreMem, 2, 0, - kExprLocalGet, 1, - kExprI32Const, 1, - kExprI32Add, - kExprLocalTee, 1, - kExprLocalGet, 0, - kExprI32LtS, - kExprBrIf, 0, - kExprEnd, - ]) - .exportFunc(); - -function setup() { - // Without Wasm lazy-deopt, this does not replace the optimized frame on - // the stack. - cdp('Debugger.enable'); - // Request an API_INTERRUPT. - cdp('Debugger.pause'); -} - -const instance = builder.instantiate({env: {setup}}); -const mem = instance.exports.mem; - -// Iteration count must be large enough that Turboshaft's loop unrolling -// still leaves a stack-check that fires before all stores complete. -instance.exports.vuln(100); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-526163463.js b/deps/v8/test/mjsunit/regress/wasm/regress-526163463.js deleted file mode 100644 index 24772efcbe6a..000000000000 --- a/deps/v8/test/mjsunit/regress/wasm/regress-526163463.js +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --wasm-code-coverage - -// Pausing the debugger while executing Wasm triggers regeneration of the -// Liftoff debug side table. With --wasm-code-coverage, the regenerated code -// must include coverage instrumentation so its PC offsets match the original -// code. Ensure frame inspection does not crash. - -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); - -let builder = new WasmModuleBuilder(); -let setup_idx = builder.addImport('env', 'setup', kSig_v_v); -builder.addFunction('vuln', kSig_v_v) - .addBody([ - kExprCallFunction, setup_idx, - kExprLoop, kWasmVoid, - kExprEnd, - ]) - .exportFunc(); - -let instance = builder.instantiate({ - env: { - setup: function() { - send(JSON.stringify({ - id: 1, - method: 'Debugger.enable', - })); - send(JSON.stringify({ - id: 2, - method: 'Debugger.pause', - })); - } - } -}); - -instance.exports.vuln(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-527985808.js b/deps/v8/test/mjsunit/regress/wasm/regress-527985808.js deleted file mode 100644 index 790b6d6fc82d..000000000000 --- a/deps/v8/test/mjsunit/regress/wasm/regress-527985808.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --no-wasm-trap-handler --stress-wasm-memory-moving - -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); - -let debugCommandId = 0; -function sendDebugCommand(cmd) { - send(JSON.stringify({ - id: ++debugCommandId, - method: cmd, - })); -} - -globalThis.handleInspectorMessage = function () { - memory.grow(10); - sendDebugCommand('Debugger.resume'); -}; - -function setup() { - sendDebugCommand('Debugger.enable'); - sendDebugCommand('Debugger.pause'); -} - -const builder = new WasmModuleBuilder(); -builder.addMemory(1); -builder.exportMemoryAs('mem'); -const $setup = builder.addImport('env', 'setup', kSig_v_v); -builder.addFunction('vuln', kSig_v_i).addLocals(kWasmI32, 1).addBody([ - kExprCallFunction, $setup, - kExprLoop, kWasmVoid, - kExprI32Const, 4, - kExprI32Const, 0, - kExprI32StoreMem, 0, 0, - kExprEnd]).exportFunc(); - -const instance = builder.instantiate({ env: {setup} }); -const memory = instance.exports.mem; -instance.exports.vuln(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-531302064.js b/deps/v8/test/mjsunit/regress/wasm/regress-531302064.js index 0a378647f5f1..d1cd4cb73a21 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-531302064.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-531302064.js @@ -11,7 +11,14 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); // it if possible and quietly skip it otherwise. // Meaning of these validation bytes: "(module (type (array (field v128))))". const kSimdEnabled = WebAssembly.validate( - new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 94, 123, 0])); + new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x04, // section length 4 + 0x01, 0x5e, 0x7b, 0x00, // types count 1: kind: array v128 immutable + ])); console.log(`Including SIMD test scenario: ${kSimdEnabled}`); let builder = new WasmModuleBuilder(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-533578412.js b/deps/v8/test/mjsunit/regress/wasm/regress-533578412.js new file mode 100644 index 000000000000..a0be56912184 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-533578412.js @@ -0,0 +1,32 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --max-old-space-size=64 + +// Growing a Wasm memory in small steps beyond 2 * max-old-space-size should not +// trigger a Mark-Compact GC storm. +const ws = new WeakSet(); +function putWeak() { + ws.add({}); +} +putWeak(); + +let gcs = 0; +const memory = new WebAssembly.Memory({initial: 0}); +for (let i = 0; i < 1024; i++) { + try { + memory.grow(4); + } catch (e) { + // Growing may fail with RangeError on 32-bit platforms or under memory + // pressure. + assertInstanceof(e, RangeError); + break; + } + if (%GetWeakCollectionSize(ws) === 0) { + gcs++; + putWeak(); + } +} + +assertTrue(gcs <= 5, `Expected at most 5 GCs, got ${gcs}`); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-563068683.js b/deps/v8/test/mjsunit/regress/wasm/regress-563068683.js new file mode 100644 index 000000000000..8311bc856db3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-563068683.js @@ -0,0 +1,22 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-shared --verify-heap + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +// Large enough to allocate the array in Large Object Space. +const ARRAY_SIZE = 200_000; + +let builder = new WasmModuleBuilder(); +let $array = builder.addArray(kWasmI8, {shared: true}); +builder.addFunction('create_array', makeSig([], [wasmRefType($array)])) + .exportFunc() + .addBody([ + ...wasmI32Const(ARRAY_SIZE), + kGCPrefix, kExprArrayNewDefault, $array + ]); + +let instance = builder.instantiate(); +let array = instance.exports.create_array(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-565341967.js b/deps/v8/test/mjsunit/regress/wasm/regress-565341967.js new file mode 100644 index 000000000000..957a9df05d92 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-565341967.js @@ -0,0 +1,36 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-stringref --turboshaft-verify-load-elimination + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +let builder = new WasmModuleBuilder(); +let internalize = builder.addImport("env", "internalize", kSig_v_r); +builder.addFunction("test", makeSig([kWasmExternRef, kWasmI32], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprAnyConvertExtern, + kGCPrefix, kExprRefCastNull, kStringRefCode, + ...GCInstr(kExprStringAsWtf16), + kExprDrop, + kExprLocalGet, 0, + kExprCallFunction, internalize, + kExprLocalGet, 0, + kGCPrefix, kExprAnyConvertExtern, + kGCPrefix, kExprRefCastNull, kStringRefCode, + ...GCInstr(kExprStringAsWtf16), + kExprLocalGet, 1, + ...GCInstr(kExprStringViewWtf16GetCodeunit), + ]).exportFunc(); + +let map = new Map(); +function do_internalize(s) { + map.set(s); // internalizes s in-place -> ThinString! +} +let instance = builder.instantiate({ env: { internalize: do_internalize } }); +let arr = [, , ]; +let s1 = String.fromCharCode(...arr); // SeqOneByteString +let r = instance.exports.test(s1); +console.log(r); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-565847635.js b/deps/v8/test/mjsunit/regress/wasm/regress-565847635.js index 7e5955eb465d..99c20cd1a8d2 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-565847635.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-565847635.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --wasm-fp16 --no-enable-avx2 +// Flags: --wasm-fp16 --no-enable-avx2 --no-enable-fma3 d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); @@ -21,7 +21,77 @@ builder.addFunction('test_load', kSig_f_v) kNumericPrefix, kExprF32LoadF16, 0, 0, ].flat()) .exportFunc(); +builder.addFunction('test_simd', kSig_f_f) + .addLocals(kWasmS128, 2) + .addBody([ + // v0 = min(splat(x), splat(2.0)) = 1.5 (or NaN if x is NaN) + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + wasmF32Const(2.0), + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF16x8Min, + // v1 = max(v0, splat(1.0)) = 1.5 (or NaN if x is NaN) + wasmF32Const(1.0), + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF16x8Max, + kExprLocalTee, 2, + // v2 = qfma(v1, 2.0, 1.0) = 1.5 * 2.0 + 1.0 = 4.0 + wasmF32Const(2.0), + kSimdPrefix, kExprF16x8Splat, + wasmF32Const(1.0), + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF16x8Qfma, + // v3 = qfms(v2, 0.5, 5.0) = 5.0 - 4.0 * 0.5 = 3.0 + wasmF32Const(0.5), + kSimdPrefix, kExprF16x8Splat, + wasmF32Const(5.0), + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF16x8Qfms, + // Round-trip through signed and unsigned i16x8 conversions (still 3.0). + kSimdPrefix, kExprI16x8SConvertF16x8, + kSimdPrefix, kExprF16x8SConvertI16x8, + kSimdPrefix, kExprI16x8UConvertF16x8, + kSimdPrefix, kExprF16x8UConvertI16x8, + kExprLocalTee, 1, + // Compare: (1.5 < 3.0) & (3.0 == 3.0) & (1.5 != 3.0) & (1.5 <= 3.0) = -1 + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kExprLocalGet, 1, + kSimdPrefix, kExprF16x8Lt, + kExprLocalGet, 1, + kExprLocalGet, 1, + kSimdPrefix, kExprF16x8Eq, + kSimdPrefix, kExprS128And, + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kExprLocalGet, 1, + kSimdPrefix, kExprF16x8Ne, + kSimdPrefix, kExprS128And, + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kExprLocalGet, 1, + kSimdPrefix, kExprF16x8Le, + kSimdPrefix, kExprS128And, + // Convert -1 (i16x8) to -1.0 (f16x8) and subtract from 3.0 -> 4.0, + // then add 0.5 -> 4.5, and max with v1 (1.5 or NaN). + kSimdPrefix, kExprF16x8SConvertI16x8, + kSimdPrefix, kExprF16x8Sub, + wasmF32Const(0.5), + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF16x8Add, + kExprLocalGet, 2, + kSimdPrefix, kExprF16x8Max, + kExprLocalTee, 1, + // Check both low (lane 0) and high (lane 7) lanes. + kSimdPrefix, kExprF16x8ExtractLane, 0, + kExprLocalGet, 1, + kSimdPrefix, kExprF16x8ExtractLane, 7, + kExprF32Add, + ].flat()) + .exportFunc(); let instance = builder.instantiate(); instance.exports.test_store(1.5); assertEquals(1.5, instance.exports.test_load()); +assertEquals(9.0, instance.exports.test_simd(1.5)); +assertTrue(isNaN(instance.exports.test_simd(NaN))); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-566359200.js b/deps/v8/test/mjsunit/regress/wasm/regress-566359200.js new file mode 100644 index 000000000000..46a5fd030807 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-566359200.js @@ -0,0 +1,65 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-stringref --turboshaft-verify-load-elimination + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +const builder = new WasmModuleBuilder(); + +let $sig_v_v = builder.addType(kSig_v_v); +let $sig4 = builder.addType(makeSig([kWasmI32], [kWasmExternRef])); +let $sig5 = builder.addType(makeSig([kWasmExternRef, kWasmI32], [kWasmI32])); +let import_0_v2 = builder.addImport('imports', 'import_0_v2', $sig4); +let charCodeAt = builder.addImport('wasm:js-string', 'charCodeAt', $sig5); +let $global0 = builder.addImportedGlobal('"', 'foo', wasmRefType(kWasmExternRef)); + +let $var0 = 0; +let $var1 = 1; +let $var2 = 2; +let $var3 = 3; +let w0 = builder.addFunction("w0", $sig_v_v).exportFunc() + .addLocals(wasmRefType(kWasmArrayRef), 1) // $var0 + .addLocals(wasmRefType(kWasmExternRef), 1) // $var1 + .addLocals(kWasmI32, 1) // $var2 + .addLocals(wasmRefType(kWasmAnyRef), 1) // $var3 + .addBody([ + kExprRefNull, kArrayRefCode, + kExprBrOnNull, 0, + kExprLocalSet, $var0, + kExprGlobalGet, $global0, + kExprLocalSet, $var1, + kExprLocalGet, $var1, + kGCPrefix, kExprAnyConvertExtern, + kGCPrefix, kExprRefTest, kEqRefCode, + kExprLocalSet, $var2, + kExprBlock, $sig_v_v, + kExprBlock, $sig_v_v, + kExprBlock, $sig_v_v, + kExprLocalGet, $var2, + kExprBrTable, 2, 2, 0, 1, + kExprEnd, + kExprLocalGet, $var1, + kExprI32Const, 0, + kExprCallFunction, charCodeAt, + kExprLocalSet, $var2, + kExprEnd, + kExprTry, kWasmVoid, + kExprI32Const, 0, + kExprCallFunction, import_0_v2, + kExprDrop, + kExprCatchAll, + kExprLocalGet, $var1, + kGCPrefix, kExprAnyConvertExtern, + kExprLocalSet, $var3, + kExprEnd, + kExprEnd, + ]); + +const instance = builder.instantiate( + { imports: { import_0_v2: Symbol } }, + { builtins: ['js-string'], importedStringConstants: '"' } +); + +instance.exports.w0(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-566727937.js b/deps/v8/test/mjsunit/regress/wasm/regress-566727937.js new file mode 100644 index 000000000000..c9ad62bf4b75 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-566727937.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Verify that Wasm memory deserialization fails before adding an incomplete +// WasmMemoryObject to the ID map when no delegate is present. +const stream = [ + 0xFF, 13, + 0x41, 0x02, + 0x42, 0, + 0x56, 0x62, 0, 0, + 0x44, + 0x5E, 0x04, + 0x24, 0x00, 0x02, + 0x00, 0x00, 0x00, + 0x6D, 0x00, 0x00 +]; +const bytes = new Uint8Array(stream); +assertThrows( + () => d8.serializer.deserialize(bytes.buffer), Error, + 'Unable to deserialize cloned data.'); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-567126756.js b/deps/v8/test/mjsunit/regress/wasm/regress-567126756.js new file mode 100644 index 000000000000..b4979d0e187b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-567126756.js @@ -0,0 +1,13 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --fuzzing + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction('f', kSig_v_v).addBody([]).exportFunc(); +const instance = builder.instantiate(); + +%NeverOptimizeFunction(instance.exports.f); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-567171844.js b/deps/v8/test/mjsunit/regress/wasm/regress-567171844.js new file mode 100644 index 000000000000..10a316d510ff --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-567171844.js @@ -0,0 +1,153 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-custom-descriptors --wasm-js-interop + +const wasm_bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x1a, // section length 26 + 0x06, // types count 6 + 0x5e, 0x6f, 0x01, // type #0 $type0 kind: array externref mutable + 0x5e, 0x70, 0x01, // type #1 $type1 kind: array funcref mutable + 0x5e, 0x78, 0x01, // type #2 $type2 kind: array i8 mutable + 0x60, // type #3 $type3 kind: func + 0x04, // param count 4 + 0x63, 0x00, 0x63, 0x01, // (ref null $type0) (ref null $type1) + 0x63, 0x02, 0x6f, // (ref null $type2) externref + 0x00, // return count 0 + 0x60, // type #4 $type4 kind: func + 0x00, // param count 0 + 0x00, // return count 0 + 0x60, // type #5 $type5 kind: func + 0x00, // param count 0 + 0x00, // return count 0 + + 0x02, // section kind: Import + 0x51, // section length 81 + 0x04, // imports count 4 + 0x12, // module name length: 18 + 0x77, 0x61, 0x73, 0x6d, 0x3a, 0x6a, 0x73, 0x2d, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, + 0x65, 0x73, // module name: wasm:js-prototypes + 0x0c, // field name length: 12 + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x65, 0x41, 0x6c, 0x6c, // field name: configureAll + 0x00, 0x03, // kind or compact flag: function (param (ref null $type0) (ref null $type1) (ref null $type2) externref) + // import #0 + 0x01, // module name length: 1 + 0x63, // module name: c + 0x0c, // field name length: 12 + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x6f, 0x72, 0x73, // field name: constructors + 0x03, 0x6f, 0x00, // kind or compact flag: global externref immutable + // import #1 + 0x03, // module name length: 3 + 0x6d, 0x6f, 0x64, // module name: mod + 0x0a, // field name length: 10 + 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x75, + 0x6e, 0x63, // field name: outer_func + 0x00, 0x04, // kind or compact flag: function + // import #2 + 0x01, // module name length: 1 + 0x63, // module name: c + 0x05, // field name length: 5 + 0x70, 0x72, 0x6f, 0x74, 0x6f, // field name: proto + 0x03, 0x6f, 0x00, // kind or compact flag: global externref immutable + // import #3 + + 0x03, // section kind: Function + 0x03, // section length 3 + 0x02, // functions count 2 + 0x04, // 2 $myMethod + 0x05, // 3 $start + + 0x08, // section kind: Start + 0x01, // section length 1 + 0x03, // index: 3 + + 0x09, // section kind: Element + 0x0b, // section length 11 + 0x02, // segment count 2 + 0x05, 0x6f, 0x01, // flag: passive, element type: externref number of elements 1: + 0x23, 0x00, 0x0b, // global.get $c.constructors + 0x01, 0x00, 0x01, // flag: passive, element type: function number of elements 1: + 0x02, // index: 2 + + 0x0c, // section kind: DataCount + 0x01, // section length 1 + 0x01, // data segments count 1: + + 0x0a, // section kind: Code + 0x25, // section length 37 + 0x02, // functions count 2 + // function #2 $myMethod + 0x04, // body size 4 + 0x00, // 0 entries in locals list + 0x10, 0x01, // call $mod.outer_func + 0x0b, // end + // function #3 $start + 0x1e, // body size 30 + 0x00, // 0 entries in locals list + 0x41, 0x00, // i32.const 0 + 0x41, 0x01, // i32.const 1 + 0xfb, 0x0a, 0x00, 0x00, // array.new_elem $type0 $elem0 + 0x41, 0x00, // i32.const 0 + 0x41, 0x01, // i32.const 1 + 0xfb, 0x0a, 0x01, 0x01, // array.new_elem $type1 $elem1 + 0x41, 0x00, // i32.const 0 + 0x41, 0x0e, // i32.const 14 + 0xfb, 0x09, 0x02, 0x00, // array.new_data $type2 0 + 0x23, 0x00, // global.get $c.constructors + 0x10, 0x00, // call $wasm:js-prototypes.configureAll + 0x0b, // end + + 0x0b, // section kind: Data + 0x11, // section length 17 + 0x01, 0x01, // data segments count 1: flag: passive + 0x0e, // source size 14 + 0x01, 0x00, 0x01, 0x00, 0x08, 0x6d, 0x79, 0x4d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x7f, + // segment data + + 0x00, // section kind: Unknown + 0x19, // section length 25 + 0x04, // section name length: 4 + 0x6e, 0x61, 0x6d, 0x65, // section name: name + 0x01, // name type: function + 0x12, // payload length: 18 + 0x02, // names count 2 + 0x02, 0x08, // index 2 name length: 8 + 0x6d, 0x79, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, // name: myMethod + 0x03, 0x05, // index 3 name length: 5 + 0x73, 0x74, 0x61, 0x72, 0x74, // name: start +]); + +const myProto = {}; +const constructors = {}; +const handler = { apply: function() { return 42; } }; +const proxy = new Proxy(function() {}, handler); + +const wasm_module = new WebAssembly.Module(wasm_bytes, + { builtins: ["js-prototypes"] }); +const wasm_instance = new WebAssembly.Instance( + wasm_module, + { + mod: { + outer_func: proxy + }, + c: { proto: myProto, constructors: constructors } + } +); + +for (let i = 0; i < 1000; i++) { + constructors.myMethod(); +} + +handler.apply = 123; + +assertThrows(() => constructors.myMethod(), TypeError, + "number 123 is not a function"); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-567481597.js b/deps/v8/test/mjsunit/regress/wasm/regress-567481597.js new file mode 100644 index 000000000000..123b4bd2e842 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-567481597.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-stack-switching-stack-size=1 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const kNumParams = 1000; +const builder = new WasmModuleBuilder(); +const sig = builder.addType(makeSig(new Array(kNumParams).fill(kWasmF64), [])); +builder.addFunction('f', sig).exportFunc().addBody([]); +const instance = builder.instantiate(); +const promising = WebAssembly.promising(instance.exports.f); + +// On platforms with 4 KB page allocation granularity (e.g. Linux), the +// secondary stack is rounded up to 8 KB (4 KB usable), so 1000 f64 parameters +// (~8 KB) trigger the preemptive stack overflow check and reject with a +// RangeError. On platforms with 16 KB or 64 KB allocation granularity (e.g. +// macOS arm64 or Windows), the secondary stack is rounded up to a full page +// and the call succeeds. +assertPromiseResult( + promising(...new Array(kNumParams)), + () => {}, + e => assertInstanceof(e, RangeError)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-567624365.js b/deps/v8/test/mjsunit/regress/wasm/regress-567624365.js new file mode 100644 index 000000000000..13fb714a0584 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-567624365.js @@ -0,0 +1,22 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-shared --no-wasm-lazy-compilation + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +let $array0 = builder.addArray(kWasmI8); +let $struct = builder.addStruct( + {fields: [makeField(wasmRefNullType($array0), true)]}); +let main = builder.addFunction(undefined, kSig_v_v).exportAs('main'); +main.addLocals(wasmRefNullType($struct), 1) + .addBody([ + kExprRefNull, ...wasmSignedLeb($struct), + kExprRefNull, ...wasmSignedLeb($array0), + kAtomicPrefix, kExprStructAtomicExchange, kAtomicAcqRel, $struct, 0, + kGCPrefix, kExprRefCastNull, $struct, + kExprLocalSet, 0, + ]); +builder.instantiate({}); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-567911985.js b/deps/v8/test/mjsunit/regress/wasm/regress-567911985.js new file mode 100644 index 000000000000..22b4bdc3e259 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-567911985.js @@ -0,0 +1,77 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-fp16 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction('qfma', makeSig([kWasmF32], [kWasmF32])) + .addLocals(kWasmS128, 1) + .addBody([ + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kExprLocalTee, 1, + kExprLocalGet, 1, + wasmF32Const(1.0), + kSimdPrefix, kExprF16x8Splat, + kExprLocalTee, 1, + kSimdPrefix, kExprF16x8Qfma, + kSimdPrefix, kExprF16x8ExtractLane, 0, + ].flat()) + .exportFunc(); + +builder.addFunction('qfms', makeSig([kWasmF32], [kWasmF32])) + .addLocals(kWasmS128, 1) + .addBody([ + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kExprLocalTee, 1, + kExprLocalGet, 1, + wasmF32Const(10.0), + kSimdPrefix, kExprF16x8Splat, + kExprLocalTee, 1, + kSimdPrefix, kExprF16x8Qfms, + kSimdPrefix, kExprF16x8ExtractLane, 0, + ].flat()) + .exportFunc(); + +builder.addFunction('demote_zero', makeSig([kWasmF32], [kWasmF32])) + .addBody([ + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF32x4PromoteLowF16x8, + kSimdPrefix, kExprF16x8DemoteF32x4Zero, + kSimdPrefix, kExprF16x8ExtractLane, 7, + ].flat()) + .exportFunc(); + +builder.addFunction('gt', makeSig([kWasmF32, kWasmF32], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8Splat, + kExprLocalGet, 1, + kSimdPrefix, kExprF16x8Splat, + kSimdPrefix, kExprF16x8Gt, + kSimdPrefix, kExprI16x8ExtractLaneS, 0, + ].flat()) + .exportFunc(); + +builder.addFunction('replace_lane', makeSig([kWasmF32], [kWasmF32])) + .addLocals(kWasmS128, 1) + .addBody([ + kExprLocalGet, 1, + kExprLocalGet, 0, + kSimdPrefix, kExprF16x8ReplaceLane, 0, + kSimdPrefix, kExprF16x8ExtractLane, 0, + ].flat()) + .exportFunc(); + +const instance = builder.instantiate(); +assertEquals(5.0, instance.exports.qfma(2.0)); +assertEquals(6.0, instance.exports.qfms(2.0)); +assertEquals(0.0, instance.exports.demote_zero(1.5)); +assertEquals(-1, instance.exports.gt(2.0, 1.0)); +assertEquals(0, instance.exports.gt(1.0, 2.0)); +assertEquals(3.5, instance.exports.replace_lane(3.5)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-568629618.js b/deps/v8/test/mjsunit/regress/wasm/regress-568629618.js new file mode 100644 index 000000000000..7163319f8873 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-568629618.js @@ -0,0 +1,84 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --turboshaft-verify-load-elimination --wasm-shared + +// Run with --no-liftoff to reproduce (not included in flags as it is included +// with --variants=stress). + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +let workerScript = ` + onmessage = function(msg) { + let struct = msg.data.struct; + let module = msg.data.module; + let instance = new WebAssembly.Instance(module); + let setFn = instance.exports.set; + let i = 0; + while (true) { + setFn(struct, i++); + } + }; +`; + +let builder = new WasmModuleBuilder(); +let struct_type = builder.addStruct({fields: [makeField(kWasmI32, true)], + shared: true}); +let kSig_i_my_struct = makeSig([wasmRefNullType(struct_type)], [kWasmI32]); + +builder.addFunction("test", kSig_i_my_struct) + .addLocals(kWasmI32, 1) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprStructGet, struct_type, 0, + + // Delay loop + kExprI32Const, 0, + kExprLocalSet, 1, + kExprLoop, kWasmVoid, + kExprLocalGet, 1, + kExprI32Const, 1, + kExprI32Add, + kExprLocalSet, 1, + kExprLocalGet, 1, + ...wasmI32Const(5000), + kExprI32LtS, + kExprBrIf, 0, + kExprEnd, + + kExprLocalGet, 0, + kGCPrefix, kExprStructGet, struct_type, 0, + + kExprI32Add + ]) + .exportFunc(); + +builder.addFunction("alloc", makeSig([], [wasmRefNullType(struct_type)])) + .addBody([ + kExprI32Const, 10, + kGCPrefix, kExprStructNew, struct_type + ]) + .exportFunc(); + +builder.addFunction("set", + makeSig([wasmRefNullType(struct_type), kWasmI32], [])) + .addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kGCPrefix, kExprStructSet, struct_type, 0 + ]) + .exportFunc(); + +let module = builder.toModule(); +let instance = new WebAssembly.Instance(module); +let struct = instance.exports.alloc(); + +let worker = new Worker(workerScript, {type: 'string'}); +worker.postMessage({struct: struct, module: module}); + +let testFn = instance.exports.test; +for (let i = 0; i < 10000; i++) { + testFn(struct); +} +print("Done"); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-568806936.js b/deps/v8/test/mjsunit/regress/wasm/regress-568806936.js new file mode 100644 index 000000000000..886a4a98d4df --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-568806936.js @@ -0,0 +1,36 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const kMaxPages = 500; +const kStateIndex = 0; +const kWorkerRunning = 0; +const kWorkerDone = 1; + +const builder = new WasmModuleBuilder(); +builder.addImportedMemory('mod', 'mem', 1, kMaxPages, 'shared'); +const module = builder.toModule(); + +const mem = + new WebAssembly.Memory({initial: 1, maximum: kMaxPages, shared: true}); +const comm = new Int32Array(mem.toResizableBuffer()); + +function workerCode() { + onmessage = function({data}) { + postMessage('started'); + for (let i = 1; i < data.kMaxPages; i++) { + data.mem.grow(1); + } + Atomics.store(data.comm, data.kStateIndex, data.kWorkerDone); + }; +} + +const worker = new Worker(workerCode, {type: 'function'}); +worker.postMessage({mem, comm, kMaxPages, kStateIndex, kWorkerDone}); +assertEquals('started', worker.getMessage()); + +while (Atomics.load(comm, kStateIndex) == kWorkerRunning) { + new WebAssembly.Instance(module, {mod: {mem}}); +} diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-569071532.js b/deps/v8/test/mjsunit/regress/wasm/regress-569071532.js new file mode 100644 index 000000000000..4ed75d94a797 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-569071532.js @@ -0,0 +1,36 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +let sig0 = builder.addType( + makeSig([kWasmI31Ref, kWasmExternRef], [kWasmExternRef])); +let sigCast = + builder.addType(makeSig([kWasmExternRef], [wasmRefType(kWasmExternRef)])); +let jsStringCast = builder.addImport('wasm:js-string', 'cast', sigCast); + +builder.addFunction('w0', sig0) + .addBody([ + kExprLocalGet, 0, + kExprRefIsNull, + kExprI32Eqz, + kExprIf, kWasmVoid, + kExprLocalGet, 1, + kGCPrefix, kExprBrOnCast, 0b11, 1, kExternRefCode, kExternRefCode, + kExprDrop, + kExprEnd, + kExprLocalGet, 1, + kExprLocalGet, 0, + kExprBrOnNull, 0, + kExprDrop, + kExprLocalGet, 1, + kExprBrOnNull, 0, + kExprCallFunction, jsStringCast, + kExprReturn, + ]) + .exportFunc(); + +const instance = builder.instantiate({}, {builtins: ['js-string']}); +assertEquals(42, instance.exports.w0(0, 42)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-570433240.js b/deps/v8/test/mjsunit/regress/wasm/regress-570433240.js new file mode 100644 index 000000000000..9fdc18c90395 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-570433240.js @@ -0,0 +1,72 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-fp16 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addMemory(1, 1, false); +builder.exportMemoryAs("memory"); + +builder.addFunction("testNeg", makeSig([kWasmI32, kWasmI32], [])) + .addBody([ + kExprLocalGet, 1, // dst + kExprLocalGet, 0, // src + kSimdPrefix, kExprS128LoadMem, 0, 0, + kSimdPrefix, ...kExprF16x8Neg, + kSimdPrefix, kExprS128StoreMem, 0, 0, + ]) + .exportFunc(); + +builder.addFunction("testAbs", makeSig([kWasmI32, kWasmI32], [])) + .addBody([ + kExprLocalGet, 1, // dst + kExprLocalGet, 0, // src + kSimdPrefix, kExprS128LoadMem, 0, 0, + kSimdPrefix, ...kExprF16x8Abs, + kSimdPrefix, kExprS128StoreMem, 0, 0, + ]) + .exportFunc(); + +const instance = builder.instantiate(); +const dv = new DataView(instance.exports.memory.buffer); + +const testValues = [ + 0x7e01, // positive quiet NaN with payload 1 + 0xfe01, // negative quiet NaN with payload 1 + 0x7e55, // positive quiet NaN with payload 0x55 + 0xfeaa, // negative quiet NaN with payload 0x2aa + 0x7c01, // positive signaling NaN with payload 1 + 0xfc01, // negative signaling NaN with payload 1 + 0x0000, // +0.0 + 0x8000, // -0.0 + 0x7c00, // +infinity + 0xfc00, // -infinity + 0x3c00, // +1.0 + 0xbc00, // -1.0 + 0x0001, // subnormal + 0x8001, // -subnormal + 0x7fff, // quiet NaN all payload bits 1 + 0xffff, // -quiet NaN all payload bits 1 +]; + +// Test batches of 8 values +for (let offset = 0; offset + 8 <= testValues.length; offset += 8) { + for (let i = 0; i < 8; i++) { + dv.setUint16(i * 2, testValues[offset + i], true); + } + + instance.exports.testNeg(0, 16); + for (let i = 0; i < 8; i++) { + const expected = testValues[offset + i] ^ 0x8000; + assertEquals(expected, dv.getUint16((8 + i) * 2, true), `f16x8.neg mismatch at index ${offset + i}`); + } + + instance.exports.testAbs(0, 16); + for (let i = 0; i < 8; i++) { + const expected = testValues[offset + i] & 0x7fff; + assertEquals(expected, dv.getUint16((8 + i) * 2, true), `f16x8.abs mismatch at index ${offset + i}`); + } +} diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-570433264.js b/deps/v8/test/mjsunit/regress/wasm/regress-570433264.js new file mode 100644 index 000000000000..81890acda323 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-570433264.js @@ -0,0 +1,80 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-fp16 --no-liftoff --sim-arm64-optional-features=all + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const vectorA = [ + 0x00, 0x3c, // 1.0 + 0x00, 0x40, // 2.0 + 0x00, 0x42, // 3.0 + 0x00, 0x44, // 4.0 + 0x00, 0x45, // 5.0 + 0x00, 0x46, // 6.0 + 0x00, 0x47, // 7.0 + 0x00, 0x48, // 8.0 +]; + +const expected = [ + 0x4000, // 1.0 * 2.0 = 2.0 + 0x4400, // 2.0 * 2.0 = 4.0 + 0x4600, // 3.0 * 2.0 = 6.0 + 0x4800, // 4.0 * 2.0 = 8.0 + 0x4900, // 5.0 * 2.0 = 10.0 + 0x4a00, // 6.0 * 2.0 = 12.0 + 0x4b00, // 7.0 * 2.0 = 14.0 + 0x4c00, // 8.0 * 2.0 = 16.0 +]; + +for (let lane = 0; lane < 8; lane++) { + for (const splat_on_right of [true, false]) { + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + builder.exportMemoryAs('memory'); + + const vectorB = new Array(16).fill(0); + vectorB[lane * 2] = 0x00; + vectorB[lane * 2 + 1] = 0x40; // 2.0 in FP16 + + const b0 = lane * 2; + const b1 = lane * 2 + 1; + const shuffle = []; + for (let i = 0; i < 8; i++) { + shuffle.push(b0, b1); + } + + const opA = [ + ...wasmS128Const(vectorA), + ]; + const opB = [ + ...wasmS128Const(vectorB), + ...wasmS128Const(vectorB), + kSimdPrefix, kExprI8x16Shuffle, + ...shuffle, + ]; + + const lhs = splat_on_right ? opA : opB; + const rhs = splat_on_right ? opB : opA; + + builder.addFunction('test', kSig_v_v) + .addBody([ + kExprI32Const, 0, + ...lhs, + ...rhs, + kSimdPrefix, ...wasmSignedLeb(0x13f), // f16x8.mul + kSimdPrefix, kExprS128StoreMem, 0, 0, + ]) + .exportFunc(); + + const instance = builder.instantiate(); + instance.exports.test(); + + const memoryView = new DataView(instance.exports.memory.buffer); + for (let i = 0; i < 8; i++) { + assertEquals(expected[i], memoryView.getUint16(i * 2, true), + `Mismatch at lane ${i} (splat lane ${lane}, splat_on_right: ${splat_on_right})`); + } + } +} diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-571155505.js b/deps/v8/test/mjsunit/regress/wasm/regress-571155505.js new file mode 100644 index 000000000000..d7a8adc89174 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-571155505.js @@ -0,0 +1,7 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --stress-snapshot + +let table = new WebAssembly.Table({element: 'structref', initial: 1}); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-571348848.js b/deps/v8/test/mjsunit/regress/wasm/regress-571348848.js new file mode 100644 index 000000000000..0d91111994dd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-571348848.js @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-random-rescheduling --no-liftoff + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +let $sig0 = builder.addType(kSig_v_v); + +builder.addFunction('test_abstract', makeSig([kWasmNullRef], [kWasmI32])) + .addLocals(wasmRefType(kWasmAnyRef), 1) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprRefCast, kAnyRefCode, + kExprLocalTee, 1, + kGCPrefix, kExprRefTest, kEqRefCode, + kExprLocalGet, 1, + kGCPrefix, kExprRefTest, kStructRefCode, + kExprLocalGet, 1, + kGCPrefix, kExprRefTest, kArrayRefCode, + kExprLocalGet, 1, + kGCPrefix, kExprRefTest, kI31RefCode, + kExprI32Add, + kExprI32Add, + kExprI32Add, + ]) + .exportFunc(); + +builder.addFunction('test_indexed', makeSig([kWasmNullFuncRef], [kWasmI32])) + .addLocals(wasmRefType(kWasmFuncRef), 1) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprRefCast, kFuncRefCode, + kExprLocalTee, 1, + kGCPrefix, kExprRefTest, $sig0, + kExprLocalGet, 1, + kGCPrefix, kExprRefTest, $sig0, + kExprI32Add, + ]) + .exportFunc(); + +const instance = builder.instantiate(); +assertTraps(kTrapIllegalCast, () => instance.exports.test_abstract(null)); +assertTraps(kTrapIllegalCast, () => instance.exports.test_indexed(null)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-571700025.js b/deps/v8/test/mjsunit/regress/wasm/regress-571700025.js new file mode 100644 index 000000000000..d3c5c44546cc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-571700025.js @@ -0,0 +1,40 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-liftoff --no-wasm-inlining --expose-gc + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const struct_type = builder.addStruct([makeField(kWasmI32, true)]); +const ref_type = wasmRefType(struct_type); +const sig = makeSig([kWasmI32], [kWasmI32, kWasmI32, ref_type]); +const gc_idx = builder.addImport('m', 'gc', kSig_v_v); + +const callee = builder.addFunction('callee', sig).addBody([ + kExprLocalGet, 0, + kExprLocalGet, 0, + kExprLocalGet, 0, + kGCPrefix, kExprStructNew, struct_type, +]); + +builder.addFunction('caller', kSig_i_i).addBody([ + kExprLocalGet, 0, + kExprCallFunction, callee.index, + kExprCallFunction, gc_idx, + kGCPrefix, kExprStructGet, struct_type, 0, + kExprI32Add, + kExprI32Add, +]).exportFunc(); + +const instance = builder.instantiate({ + m: { + gc: () => { + for (let i = 0; i < 10000; i++) new Array(100); + gc(); + } + } +}); + +assertEquals(126, instance.exports.caller(42)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-571812798.js b/deps/v8/test/mjsunit/regress/wasm/regress-571812798.js new file mode 100644 index 000000000000..942ce78db54e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-571812798.js @@ -0,0 +1,43 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-js-interop + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); +d8.file.execute("test/mjsunit/wasm/prototype-setup-builder.js"); + +let builder = new WasmModuleBuilder(); +let proto_config = new WasmPrototypeSetupBuilder(builder); + +let $proto = builder.addImportedGlobal("p", "proto", kWasmExternRef); + +let ctor = builder.addFunction("ctor", kSig_v_v).addBody([]); +let method = builder.addFunction("method", kSig_v_v).addBody([]); + +proto_config.addConfig($proto) + .addConstructor("C", ctor) + .addMethod("m", kWasmMethod, method); + +proto_config.build(); + +let proto = {}; +let constructors = new Proxy({}, { + defineProperty(target, prop, desc) { + Object.defineProperty(proto, "m", { + value: "old", + writable: false, + configurable: false, + }); + return Reflect.defineProperty(target, prop, desc); + } +}); + +let imports = { + p: {proto}, + c: {constructors}, +}; + +assertThrows(() => builder.instantiate(imports, {builtins: ["js-prototypes"]}), + TypeError, "Cannot redefine property: m"); +assertEquals(proto.m, "old"); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-572399938.js b/deps/v8/test/mjsunit/regress/wasm/regress-572399938.js new file mode 100644 index 000000000000..cc6e5df453a3 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-572399938.js @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-shared --expose-gc --verify-heap --allow-natives-syntax + +// Tests that we don't unshare strings when invoking `extern.convert_any` for a +// shared input, both in constant expressions and in functions. +// Also that said strings *are* unshared when crossing the Wasm->JS boundary +// as shared externrefs. + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +const builder = new WasmModuleBuilder(); + +const struct_type = builder.addStruct({ + fields: [makeField(wasmRefNullType(kWasmExternRef).shared(), true)], + is_shared: true +}); + +builder.addImportedGlobal("m", "g", wasmRefNullType(kWasmAnyRef).shared(), + false, false); + +builder.addGlobal(wasmRefNullType(struct_type), false, false, [ + kExprGlobalGet, 0, + kGCPrefix, kExprExternConvertAny, + kGCPrefix, kExprStructNew, struct_type +]).exportAs("global"); + +builder.addFunction("make_struct", makeSig([], [wasmRefType(struct_type)])) + .addBody([ + kExprGlobalGet, 0, + kGCPrefix, kExprExternConvertAny, + kGCPrefix, kExprStructNew, struct_type]) + .exportFunc(); + +builder.addFunction("get", makeSig( + [wasmRefNullType(struct_type)], [wasmRefNullType(kWasmExternRef).shared()])) + .addBody([kExprLocalGet, 0, kGCPrefix, kExprStructGet, struct_type, 0]) + .exportFunc(); + +const js_string = "hello" + " world"; +let wasm = builder.instantiate({m: {g: js_string}}).exports; +let struct = wasm.make_struct(); +gc(); + +assertFalse(%IsSharedString(wasm.get(struct))); +assertFalse(%IsSharedString(wasm.get(wasm.global.value))); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-572627851.js b/deps/v8/test/mjsunit/regress/wasm/regress-572627851.js new file mode 100644 index 000000000000..440d691a17d9 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-572627851.js @@ -0,0 +1,46 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-shared --no-liftoff + +// Tests that we mark a value as aliasing when we set it as a struct field. + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +let builder = new WasmModuleBuilder(); +let inner = builder.addStruct({ + fields: [makeField(kWasmI32, true)], + is_shared: true, +}); +let outer = builder.addStruct({ + fields: [makeField(wasmRefNullType(inner), true)], + is_shared: true, +}); + +builder.addFunction("test_struct_atomic_set", makeSig([], [kWasmI32])) + .addLocals(wasmRefType(inner), 1) + .addLocals(wasmRefType(outer), 1) + .addBody([ + kGCPrefix, kExprStructNewDefault, inner, + kExprLocalSet, 0, + kGCPrefix, kExprStructNewDefault, outer, + kExprLocalSet, 1, + kExprLocalGet, 1, + kExprLocalGet, 0, + // outer.f = s + kAtomicPrefix, kExprStructAtomicSet, kAtomicSeqCst, outer, 0, + kExprLocalGet, 0, + kExprI32Const, 11, + kGCPrefix, kExprStructSet, inner, 0, // s.f = 11 + kExprLocalGet, 1, + kGCPrefix, kExprStructGet, outer, 0, + kExprI32Const, 22, + kGCPrefix, kExprStructSet, inner, 0, // outer.f.f = 22 + kExprLocalGet, 0, + kGCPrefix, kExprStructGet, inner, 0, // s.f -> must be 22 + ]) + .exportFunc(); + +let instance = builder.instantiate(); +assertEquals(22, instance.exports.test_struct_atomic_set()); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573042748.js b/deps/v8/test/mjsunit/regress/wasm/regress-573042748.js new file mode 100644 index 000000000000..3a8b385f2ffd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573042748.js @@ -0,0 +1,75 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-js-interop + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +let builder = new WasmModuleBuilder(); +let $array_externref = builder.addArray(kWasmExternRef, {final: true}); +let $array_funcref = builder.addArray(kWasmFuncRef, {final: true}); +let $array_i8 = builder.addArray(kWasmI8, {final: true}); +let $configureAll = builder.addImport( + 'wasm:js-prototypes', 'configureAll', + makeSig( + [ + wasmRefNullType($array_externref), + wasmRefNullType($array_funcref), + wasmRefNullType($array_i8), + kWasmExternRef, + ], + [])); +let $constructors = + builder.addImportedGlobal('c', 'constructors', kWasmExternRef, false); +let $g_proto = builder.addImportedGlobal('p', 'proto', kWasmExternRef, false); +let $m = builder.addFunction('m', kSig_v_v).addBody([]); + +// 1 config, no constructor, 0 statics, 1 method ('m' -> $m), no parent (-1). +let data = [ + 1, // 1 config + 0, // no constructor / 0 statics + 1, // 1 method + 0, 1, 109, // kWasmMethod, name="m" + 0x7f, // parent = -1 +]; + +let proto_segment = builder.addPassiveElementSegment( + [[kExprGlobalGet, $g_proto]], kWasmExternRef); +let func_segment = builder.addPassiveElementSegment([$m.index]); +let data_segment = builder.addPassiveDataSegment(data); + +// Call configureAll inside a Wasm try_table (catch_all) and return 1 if caught, +// 0 if configureAll did not throw. +builder.addFunction('test', kSig_i_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprTryTable, kWasmVoid, 1, + kCatchAllNoRef, 0, + kExprI32Const, 0, + kExprI32Const, 1, + kGCPrefix, kExprArrayNewElem, $array_externref, proto_segment, + + kExprI32Const, 0, + kExprI32Const, 1, + kGCPrefix, kExprArrayNewElem, $array_funcref, func_segment, + + kExprI32Const, 0, + kExprI32Const, data.length, + kGCPrefix, kExprArrayNewData, $array_i8, data_segment, + kExprGlobalGet, $constructors, + kExprCallFunction, $configureAll, + kExprI32Const, 0, + kExprReturn, + kExprEnd, + kExprEnd, + kExprI32Const, 1, + ]) + .exportFunc(); + +// Invalid prototype (42 is not an Object or null) causes configureAll to throw +// a catchable TypeError. +let instance = builder.instantiate( + {c: {constructors: {}}, p: {proto: 42}}, {builtins: ['js-prototypes']}); + +assertEquals(1, instance.exports.test()); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573260377.js b/deps/v8/test/mjsunit/regress/wasm/regress-573260377.js new file mode 100644 index 000000000000..23c459d265cb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573260377.js @@ -0,0 +1,55 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-fp16 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +// Test 1: Valid overlong LEB128 encodings for f32.load_f16 (0xfc 0x30) and +// f32.store_f16 (0xfc 0x31). +(function TestOverlongFp16LoadStore() { + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + + builder.addFunction('store_and_load', kSig_f_f) + .addBody([ + kExprI32Const, 0, + kExprLocalGet, 0, + // 5-byte LEB128 encoding of kExprF32StoreMemF16 (0xfc 0x31): + kNumericPrefix, 0xb1, 0x80, 0x80, 0x00, 0, 0, + kExprI32Const, 0, + // 5-byte LEB128 encoding of kExprF32LoadMemF16 (0xfc 0x30): + kNumericPrefix, 0xb0, 0x80, 0x80, 0x00, 0, 0, + ]) + .exportFunc(); + + const instance = builder.instantiate(); + assertEquals(1.5, instance.exports.store_and_load(1.5)); +})(); + +// Test 2: Ensure WasmFullDecoder and OpcodeLength stay synchronized on +// overlong LEB128 encodings of f32.load_f16 and reject invalid immediates. +(function TestInvalidImmediateAfterOverlongFp16Load() { + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + + builder.addFunction('invalid_offset', kSig_v_v) + .addBody([ + kExprLoop, kWasmVoid, + kExprI32Const, 0, + // 4-byte LEB128 encoding of kExprF32LoadMemF16 (0xfc 0x30): + kNumericPrefix, 0xb0, 0x80, 0x00, + // 5-byte LEB128 encoding of align = 0: + 0x80, 0x80, 0x80, 0x80, 0x00, + // 10 bytes of 0x8c (kExprF32Abs), which form an invalid LEB128 offset: + ...new Array(10).fill(kExprF32Abs), + kExprDrop, + kExprEnd, + ]) + .exportFunc(); + + assertThrows( + () => builder.instantiate().exports.invalid_offset(), + WebAssembly.CompileError); +})(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573446890.js b/deps/v8/test/mjsunit/regress/wasm/regress-573446890.js new file mode 100644 index 000000000000..68d817ff57c1 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573446890.js @@ -0,0 +1,20 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --log-code --vtune-prof-annotate-wasm + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +let builder = new WasmModuleBuilder(); +builder.addFunction('f', kSig_i_v).addBody([kExprI32Const, 42]).exportAs('f'); +let url = 'test/mjsunit/wasm/wasm-module-builder.js'; +let url_bytes = []; +for (let i = 0; i < url.length; i++) url_bytes.push(url.charCodeAt(i)); +builder.addCustomSection('sourceMappingURL', [url_bytes.length, ...url_bytes]); + +let module = new WebAssembly.Module(builder.toBuffer()); +let instance = new WebAssembly.Instance(module); + +assertEquals(42, instance.exports.f()); +console.profile(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573498301.js b/deps/v8/test/mjsunit/regress/wasm/regress-573498301.js new file mode 100644 index 000000000000..aa2b6238305a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573498301.js @@ -0,0 +1,45 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-custom-descriptors --wasm-merged-descriptors + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +let builder = new WasmModuleBuilder(); +builder.startRecGroup(); +let $desc = builder.nextTypeIndex() + 1; +let $s = builder.addStruct( + {fields: [makeField(kWasmI32, true)], descriptor: $desc}); +/* $desc */ builder.addStruct({fields: [], describes: $s}); +let $regular = builder.addStruct({}); +let $sig_a_v = builder.addType(makeSig([], [kWasmAnyRef])); +builder.endRecGroup(); + +let $g_desc = builder.addGlobal(wasmRefType($desc).exact(), false, false, + [kGCPrefix, kExprStructNewDefault, $desc]); + +builder.addFunction("make", $sig_a_v).exportFunc().addBody([ + kExprI32Const, 42, + kExprGlobalGet, $g_desc.index, + kGCPrefix, kExprStructNewDesc, $s, +]); +builder.addFunction("make_regular", $sig_a_v).exportFunc().addBody([ + kGCPrefix, kExprStructNew, $regular, +]); +builder.addFunction("get_desc", $sig_a_v).exportFunc().addBody([ + kExprGlobalGet, $g_desc.index, +]); + +let instance = builder.instantiate(); +// For regular Wasm structs, we use context-independent maps ("canonical RTTs"), +// so we cannot easily track their creation context. +let regular_struct = instance.exports.make_regular(); +assertThrows(() => Realm.owner(regular_struct), Error, + "object doesn't have creation context"); +// Custom Descriptors are NC-specific so that they can hold a prototype, +// so objects created from them can also know their own creation context. +let described_struct = instance.exports.make(); +assertEquals(0, Realm.owner(described_struct)); +let descriptor = instance.exports.get_desc(); +assertEquals(0, Realm.owner(descriptor)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573612775.js b/deps/v8/test/mjsunit/regress/wasm/regress-573612775.js new file mode 100644 index 000000000000..6953da73ee94 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573612775.js @@ -0,0 +1,34 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --wasm-in-js-inlining-body +// Flags: --wasm-in-js-inlining-opt --turbolev + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction('test_func', makeSig([kWasmExternRef], [kWasmI32])) + .addLocals(wasmRefType(kWasmAnyRef), 1) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprAnyConvertExtern, + kGCPrefix, kExprRefCast, kAnyRefCode, + kExprLocalTee, 1, + kGCPrefix, kExprRefCast, kStructRefCode, + kExprDrop, + kExprI32Const, 0, + ]) + .exportFunc(); + +const instance = builder.instantiate(); +const test_func = instance.exports.test_func; + +function js_fn(x) { + return test_func(x); +} + +%PrepareFunctionForOptimization(js_fn); +assertTraps(kTrapIllegalCast, () => js_fn(null)); +%OptimizeFunctionOnNextCall(js_fn); +assertTraps(kTrapIllegalCast, () => js_fn(null)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573816513.js b/deps/v8/test/mjsunit/regress/wasm/regress-573816513.js new file mode 100644 index 000000000000..bcddadc6b8da --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573816513.js @@ -0,0 +1,59 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-custom-descriptors + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +let builder = new WasmModuleBuilder(); + +builder.startRecGroup(); +let $desc0 = builder.nextTypeIndex() + 1; +let $s0 = builder.addStruct({descriptor: $desc0}); +builder.addStruct({describes: $s0}); +builder.endRecGroup(); + +builder.startRecGroup(); +let $desc1 = builder.nextTypeIndex() + 1; +let $s1 = builder.addStruct({descriptor: $desc1}); +builder.addStruct({describes: $s1}); +builder.endRecGroup(); + +let ref_exact_s0 = wasmRefType($s0).exact(); +let ref_exact_s1 = wasmRefType($s1).exact(); +let ref_exact_desc1 = wasmRefType($desc1).exact(); + +// Direct stack flow: ref.get_desc $s1 on a value of type (ref (exact $s0)) +// must preserve exactness and produce (ref (exact $desc1)). +builder.addFunction("direct", makeSig([ref_exact_s0], [ref_exact_desc1])) + .exportFunc() + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprRefGetDesc, $s1, + ]); + +// Flow through a local of type (ref (exact $s1)) into ref.get_desc $s1 and +// ref.cast_desc_eq (exact $s1), exercising WasmGCTypeAnalyzer::ProcessStructGet. +builder.addFunction("via_local", makeSig([ref_exact_s0], [kWasmAnyRef])) + .addLocals(ref_exact_s1, 1) + .exportFunc() + .addBody([ + kExprLocalGet, 0, + kExprLocalTee, 1, + kExprLocalGet, 1, + kGCPrefix, kExprRefGetDesc, $s1, + kGCPrefix, kExprRefCastDescEq, kWasmExact, $s1, + ]); + +builder.addFunction("make_s0", makeSig([], [ref_exact_s0])) + .exportFunc() + .addBody([ + kGCPrefix, kExprStructNewDefault, $desc0, + kGCPrefix, kExprStructNewDefaultDesc, $s0, + ]); + +let wasm = builder.instantiate().exports; +let s0 = wasm.make_s0(); +assertSame(s0, wasm.via_local(s0)); +assertSame(wasm.direct(s0), wasm.direct(s0)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573866983.js b/deps/v8/test/mjsunit/regress/wasm/regress-573866983.js new file mode 100644 index 000000000000..aced94343b2a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573866983.js @@ -0,0 +1,156 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-shared + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +(function TestStructAtomicGetSignedZeroExtension() { + for (let is_shared of [true, false]) { + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + const struct = builder.addStruct({ + fields: [makeField(kWasmI8, true), makeField(kWasmI16, true)], + is_shared, + }); + const structRef = wasmRefNullType(struct); + + builder + .addFunction('makeStruct', makeSig([kWasmI32, kWasmI32], [structRef])) + .addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kGCPrefix, kExprStructNew, struct, + ]) + .exportFunc(); + + builder.addFunction('extendU8', makeSig([structRef], [kWasmI64])) + .addBody([ + kExprLocalGet, 0, + kAtomicPrefix, kExprStructAtomicGetS, kAtomicSeqCst, struct, 0, + kExprI64UConvertI32, + ]) + .exportFunc(); + + builder.addFunction('extendU16', makeSig([structRef], [kWasmI64])) + .addBody([ + kExprLocalGet, 0, + kAtomicPrefix, kExprStructAtomicGetS, kAtomicSeqCst, struct, 1, + kExprI64UConvertI32, + ]) + .exportFunc(); + + // Using the i32 result as a 32-bit memory index emits a ChangeUint32ToUint64 + // in Turboshaft. On arm64, instruction selection elides this zero-extension + // because ZeroExtendsWord32ToWord64 returns true for the atomic load. If the + // atomic load sign-extends a negative value (-1) to 64 bits instead of + // 32 bits, the load accesses mem_base - 1 instead of trapping out-of-bounds. + builder.addFunction('memLoadIdx8', makeSig([structRef], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + kAtomicPrefix, kExprStructAtomicGetS, kAtomicSeqCst, struct, 0, + kExprI32LoadMem, 0, 0, + ]) + .exportFunc(); + + builder.addFunction('memLoadIdx16', makeSig([structRef], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + kAtomicPrefix, kExprStructAtomicGetS, kAtomicSeqCst, struct, 1, + kExprI32LoadMem, 0, 0, + ]) + .exportFunc(); + + const wasm = builder.instantiate().exports; + + const sNeg1 = wasm.makeStruct(-1, -1); + assertEquals(0xffffffffn, wasm.extendU8(sNeg1)); + assertEquals(0xffffffffn, wasm.extendU16(sNeg1)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx8(sNeg1)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx16(sNeg1)); + + const sMin = wasm.makeStruct(-128, -32768); + assertEquals(0xffffff80n, wasm.extendU8(sMin)); + assertEquals(0xffff8000n, wasm.extendU16(sMin)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx8(sMin)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx16(sMin)); + } +})(); + +(function TestArrayAtomicGetSignedZeroExtension() { + for (let is_shared of [true, false]) { + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + const array8 = builder.addArray(kWasmI8, {is_shared}); + const array16 = builder.addArray(kWasmI16, {is_shared}); + const array8Ref = wasmRefNullType(array8); + const array16Ref = wasmRefNullType(array16); + + builder.addFunction('makeArray8', makeSig([kWasmI32], [array8Ref])) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprArrayNewFixed, array8, 1, + ]) + .exportFunc(); + + builder.addFunction('makeArray16', makeSig([kWasmI32], [array16Ref])) + .addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprArrayNewFixed, array16, 1, + ]) + .exportFunc(); + + builder.addFunction('extendU8', makeSig([array8Ref], [kWasmI64])) + .addBody([ + kExprLocalGet, 0, + kExprI32Const, 0, + kAtomicPrefix, kExprArrayAtomicGetS, kAtomicSeqCst, array8, + kExprI64UConvertI32, + ]) + .exportFunc(); + + builder.addFunction('extendU16', makeSig([array16Ref], [kWasmI64])) + .addBody([ + kExprLocalGet, 0, + kExprI32Const, 0, + kAtomicPrefix, kExprArrayAtomicGetS, kAtomicSeqCst, array16, + kExprI64UConvertI32, + ]) + .exportFunc(); + + builder.addFunction('memLoadIdx8', makeSig([array8Ref], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + kExprI32Const, 0, + kAtomicPrefix, kExprArrayAtomicGetS, kAtomicSeqCst, array8, + kExprI32LoadMem, 0, 0, + ]) + .exportFunc(); + + builder.addFunction('memLoadIdx16', makeSig([array16Ref], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + kExprI32Const, 0, + kAtomicPrefix, kExprArrayAtomicGetS, kAtomicSeqCst, array16, + kExprI32LoadMem, 0, 0, + ]) + .exportFunc(); + + const wasm = builder.instantiate().exports; + + const a8Neg1 = wasm.makeArray8(-1); + const a16Neg1 = wasm.makeArray16(-1); + assertEquals(0xffffffffn, wasm.extendU8(a8Neg1)); + assertEquals(0xffffffffn, wasm.extendU16(a16Neg1)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx8(a8Neg1)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx16(a16Neg1)); + + const a8Min = wasm.makeArray8(-128); + const a16Min = wasm.makeArray16(-32768); + assertEquals(0xffffff80n, wasm.extendU8(a8Min)); + assertEquals(0xffff8000n, wasm.extendU16(a16Min)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx8(a8Min)); + assertTraps(kTrapMemOutOfBounds, () => wasm.memLoadIdx16(a16Min)); + } +})(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-573974793.js b/deps/v8/test/mjsunit/regress/wasm/regress-573974793.js new file mode 100644 index 000000000000..cd61c8c76535 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-573974793.js @@ -0,0 +1,138 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-shared + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const struct = builder.addStruct({ + fields: [makeField(kWasmI32, true)], + shared: true, +}); +const array8 = builder.addArray(kWasmI8, {shared: true}); +const array16 = builder.addArray(kWasmI16, {shared: true}); + +builder.addFunction('makeStruct', makeSig([kWasmI32], [wasmRefType(struct)])) + .addBody([kExprLocalGet, 0, kGCPrefix, kExprStructNew, struct]) + .exportFunc(); + +builder.addFunction('makeArray8', makeSig([], [wasmRefType(array8)])) + .addBody([ + kExprI32Const, 0, + kExprI32Const, 0, + kGCPrefix, kExprArrayNewFixed, array8, 2, + ]) + .exportFunc(); + +builder.addFunction('makeArray16', makeSig([], [wasmRefType(array16)])) + .addBody([ + kExprI32Const, 0, + kExprI32Const, 0, + kGCPrefix, kExprArrayNewFixed, array16, 2, + ]) + .exportFunc(); + +function addWaitAndRead(name, array_type, atomic_get_op) { + builder.addFunction( + name, + makeSig([wasmRefType(struct), wasmRefType(array_type)], + [kWasmI32, kWasmI32, kWasmI32])) + .addLocals(kWasmI32, 1) + .addBody([ + // 1. Non-atomic read of struct field 0 (initially 0). + kExprLocalGet, 0, + kGCPrefix, kExprStructGet, struct, 0, + kExprLocalTee, 2, + // 2. Signal the worker via a non-atomic array.set on index 1 (dependent + // on the struct load so it cannot be reordered before the load, and + // non-atomic so WasmLoadEliminationReducer does not invalidate shared + // struct state here). + kExprLocalGet, 1, + kExprI32Const, 1, + kExprLocalGet, 2, + kExprI32Const, 1, + kExprI32Add, + kGCPrefix, kExprArraySet, array_type, + // 3. Spin until index 0 becomes non-zero using array.atomic.get_[s|u]. + kExprLoop, kWasmI32, + kExprLocalGet, 1, + kExprI32Const, 0, + kAtomicPrefix, atomic_get_op, kAtomicSeqCst, array_type, + kExprLocalTee, 2, + kExprI32Eqz, + kExprBrIf, 0, + kExprLocalGet, 2, + kExprEnd, + // 4. Non-atomic read of struct field 0; must not be load-eliminated + // across the synchronizing array.atomic.get_[s|u] in the loop. + kExprLocalGet, 0, + kGCPrefix, kExprStructGet, struct, 0, + ]) + .exportFunc(); +} + +addWaitAndRead('waitAndReadS8', array8, kExprArrayAtomicGetS); +addWaitAndRead('waitAndReadU8', array8, kExprArrayAtomicGetU); +addWaitAndRead('waitAndReadS16', array16, kExprArrayAtomicGetS); +addWaitAndRead('waitAndReadU16', array16, kExprArrayAtomicGetU); + +function addSignal(name, array_type, atomic_get_op) { + builder.addFunction( + name, + makeSig([wasmRefType(struct), wasmRefType(array_type)], [])) + .addBody([ + kExprLoop, kWasmVoid, + kExprLocalGet, 1, + kExprI32Const, 1, + kAtomicPrefix, atomic_get_op, kAtomicSeqCst, array_type, + kExprI32Eqz, + kExprBrIf, 0, + kExprEnd, + kExprLocalGet, 0, + kExprI32Const, 42, + kAtomicPrefix, kExprStructAtomicSet, kAtomicSeqCst, struct, 0, + kExprLocalGet, 1, + kExprI32Const, 0, + ...wasmI32Const(-1), + kAtomicPrefix, kExprArrayAtomicSet, kAtomicSeqCst, array_type, + ]) + .exportFunc(); +} + +addSignal('signal8', array8, kExprArrayAtomicGetU); +addSignal('signal16', array16, kExprArrayAtomicGetU); + +const module = builder.toModule(); +const instance = new WebAssembly.Instance(module); +const wasm = instance.exports; + +const worker = new Worker(function() { + let inst; + onmessage = function({data: msg}) { + if (msg.module) { + inst = new WebAssembly.Instance(msg.module); + postMessage('ready'); + return; + } + inst.exports[msg.signal](msg.s, msg.a); + }; +}, {type: 'function'}); + +worker.postMessage({module}); +assertEquals('ready', worker.getMessage()); + +for (const [waitFn, makeArrayFn, signalFn, expectedArrayVal] of [ + ['waitAndReadS8', 'makeArray8', 'signal8', -1], + ['waitAndReadU8', 'makeArray8', 'signal8', 0xff], + ['waitAndReadS16', 'makeArray16', 'signal16', -1], + ['waitAndReadU16', 'makeArray16', 'signal16', 0xffff], +]) { + const s = wasm.makeStruct(0); + const a = wasm[makeArrayFn](); + worker.postMessage({signal: signalFn, s, a}); + assertEquals([0, expectedArrayVal, 42], wasm[waitFn](s, a)); +} + +worker.terminate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js b/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js index edbbaa76ede5..234fc34719a2 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-574223268.js @@ -6,19 +6,19 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); -function buildModule(numTargets, tableSize = numTargets) { +function buildModule(numTargets, tableSize = numTargets, hasMemory = true) { const builder = new WasmModuleBuilder(); - builder.addMemory(1, 1); + if (hasMemory) builder.addMemory(1, 1); const sig_v_v = builder.addType(kSig_v_v); const sig_v_i = builder.addType(kSig_v_i); const funcs = []; for (let i = 0; i < numTargets; i++) { const f = builder.addFunction('f' + i, sig_v_v) - .addBody([ + .addBody(hasMemory ? [ kExprI32Const, 0, kExprI32Const, 42 + i, kExprI32StoreMem, 0, 0, - ]) + ] : []) .exportFunc(); funcs.push(f.index); } @@ -36,7 +36,7 @@ function buildModule(numTargets, tableSize = numTargets) { // Fill the bootstrap trusted page(s) (which are marked never_evacuate) so that // subsequent trusted objects land on movable pages. const filler = []; -const fillerModule = buildModule(1, 2000); +const fillerModule = buildModule(1, 2000, false); for (let i = 0; i < 64; i++) { filler.push(new WebAssembly.Instance(fillerModule)); } diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-574681855.js b/deps/v8/test/mjsunit/regress/wasm/regress-574681855.js new file mode 100644 index 000000000000..f2eb7c11af1b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-574681855.js @@ -0,0 +1,94 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --wasm-deopt --wasm-inlining-ignore-call-counts +// Flags: --wasm-sync-tier-up --wasm-inlining-budget=25000 +// Flags: --wasm-inlining-max-size=2500 --wasm-inlining-factor=15 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const sig_index = builder.addType(makeSig( + [ + kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, + kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, kWasmI32, + kWasmI32, kWasmI32 + ], + [kWasmI32])); + +const g = builder.addGlobal(kWasmI32, true, false); +for (let d = 0; d < 10; d++) { + builder.addFunction('dummy_' + d, kSig_i_i).addBody([kExprLocalGet, 0]); +} + +// Keep leaf larger than --wasm-inlining-max-size so it remains a real call that +// clobbers caller-saved registers and splits live ranges across branches. +let leaf_body = [kExprLocalGet, 0]; +for (let i = 0; i < 900; i++) { + leaf_body.push(kExprI32Const, 1, kExprI32Add); +} +const leaf = builder.addFunction('leaf', kSig_i_i).addBody(leaf_body); + +const num_callees = 3; +const callees = []; + +for (let c = 0; c < num_callees; c++) { + let body = []; + for (let iter = 0; iter < 25; iter++) { + body.push( + kExprLocalGet, iter % 16, + kExprIf, kWasmVoid, + kExprLocalGet, (iter + 1) % 16, + kExprCallFunction, leaf.index, + kExprLocalGet, (iter + 2) % 16, + kExprI32Add, + kExprLocalSet, (iter + 3) % 16, + kExprElse, + kExprLocalGet, (iter + 4) % 16, + kExprLocalGet, (iter + 5) % 16, + kExprI32Mul, + kExprLocalSet, (iter + 6) % 16, + kExprEnd); + } + body.push(kExprLocalGet, 0); + for (let i = 1; i < 16; i++) { + body.push(kExprLocalGet, i, kExprI32Add); + } + callees.push(builder.addFunction('callee_' + c, sig_index).addBody(body)); +} + +const table = builder.addTable(kWasmFuncRef, num_callees, num_callees); +builder.addActiveElementSegment( + table.index, wasmI32Const(0), + callees.map(f => [kExprRefFunc, f.index]), kWasmFuncRef); + +let inlinee_body = []; +for (let k = 0; k < 6; k++) { + for (let i = 0; i < 16; i++) { + inlinee_body.push(kExprLocalGet, (i + k) % 16); + } + inlinee_body.push( + kExprGlobalGet, g.index, + kExprCallIndirect, sig_index, table.index, + kExprLocalSet, k % 16); +} +inlinee_body.push(kExprLocalGet, 0); +const inlinee = + builder.addFunction('inlinee', sig_index).addBody(inlinee_body).exportFunc(); + +let main_body = [ + kExprLocalGet, 0, + kExprGlobalSet, g.index, +]; +for (let i = 0; i < 16; i++) { + main_body.push(kExprLocalGet, 0, kExprI32Const, i + 1, kExprI32Add); +} +main_body.push(kExprCallFunction, inlinee.index); +builder.addFunction('main', kSig_i_i).addBody(main_body).exportFunc(); + +const instance = builder.instantiate(); +for (let i = 0; i < num_callees; i++) { + instance.exports.main(i); + %WasmTierUpFunction(instance.exports.inlinee); +} diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-574704749.js b/deps/v8/test/mjsunit/regress/wasm/regress-574704749.js new file mode 100644 index 000000000000..ff5acbe7ebdd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-574704749.js @@ -0,0 +1,63 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-wasm-generic-wrapper --cpu-profiler-sampling-interval=1000000 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +let sampleCollected = false; +function OnProfilerSampleCallback(profile) { + profile = profile.replaceAll('\\', '/'); + profile = JSON.parse(profile); + let functionNames = profile.nodes.map(n => n.callFrame.functionName); + for (let i = 0; i < functionNames.length; ++i) { + if (functionNames[i].startsWith('js-to-wasm') && + functionNames[i + 1]?.startsWith('main') && + functionNames[i + 2]?.startsWith('wasm-to-js') && + functionNames[i + 3]?.startsWith('imp')) { + sampleCollected = true; + return; + } + } +} + +d8.profiler.setOnProfileEndListener(OnProfilerSampleCallback); +// Enable profiling on the main isolate before it has any NativeModule. +console.profile(); + +const builder = new WasmModuleBuilder(); +const imp_index = builder.addImport('q', 'f', kSig_i_i); +builder.addFunction('main', kSig_i_i) + .addBody([ + kExprLocalGet, 0, + kExprCallFunction, imp_index, + ]) + .exportFunc(); +const wire_bytes = builder.toBuffer(); + +function workerCode() { + onmessage = ({data: bytes}) => { + const module = new WebAssembly.Module(bytes); + // Keep the instance alive until the main thread finishes profiling so the + // compiled wasm-to-js wrapper stays in the engine-wide + // WasmImportWrapperCache. + globalThis.instance = new WebAssembly.Instance(module, {q: {f: (i) => i}}); + postMessage(module); + }; +} + +const worker = new Worker(workerCode, {type: 'function'}); +worker.postMessage(wire_bytes); +const wasm_module = worker.getMessage(); + +function imp(i) { + d8.profiler.triggerSample(); + console.profileEnd(); + return i; +} +const instance = new WebAssembly.Instance(wasm_module, {q: {f: imp}}); +instance.exports.main(3); +worker.terminate(); + +assertTrue(sampleCollected); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-574824670.js b/deps/v8/test/mjsunit/regress/wasm/regress-574824670.js new file mode 100644 index 000000000000..886fee8a6dcc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-574824670.js @@ -0,0 +1,30 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-custom-descriptors --wasm-merged-descriptors + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +let builder = new WasmModuleBuilder(); +builder.startRecGroup(); +let $desc = builder.nextTypeIndex() + 1; +let $s = builder.addStruct( + {fields: [makeField(kWasmI32, true)], descriptor: $desc}); +/* $desc */ builder.addStruct({fields: [], describes: $s}); +let $sig_a_v = builder.addType(makeSig([], [kWasmAnyRef])); +builder.endRecGroup(); + +let $g_desc = builder.addGlobal(wasmRefType($desc).exact(), false, false, + [kGCPrefix, kExprStructNewDefault, $desc]); + +builder.addFunction('make', $sig_a_v).exportFunc().addBody([ + kExprI32Const, 42, + kExprGlobalGet, $g_desc.index, + kGCPrefix, kExprStructNewDesc, $s, +]); + +let instance = builder.instantiate(); +let described_struct = instance.exports.make(); + +performance.measureMemory({execution: 'eager'}); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-575514140.js b/deps/v8/test/mjsunit/regress/wasm/regress-575514140.js new file mode 100644 index 000000000000..3d57258dc171 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-575514140.js @@ -0,0 +1,71 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that lazy TurboFan compilation (--no-liftoff) handles well-known import +// assumptions being invalidated concurrently on another thread before the +// compiled code is published. + +// Flags: --no-liftoff + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const imp = builder.addImport('m', 'f', kSig_d_d); +const notify = builder.addImport('m', 'notify', kSig_v_v); +const body = [kExprLocalGet, 0]; +for (let i = 0; i < 30; i++) { + body.push(kExprCallFunction, imp); +} +const callee = builder.addFunction(undefined, kSig_d_d).addBody(body); +// Signal the worker from Wasm right before calling the lazily compiled callee +// so the worker races directly against callee's lazy compilation. +builder.addFunction(undefined, kSig_d_d) + .addBody([ + kExprCallFunction, notify, + kExprLocalGet, 0, + kExprCallFunction, callee.index, + ]) + .exportAs('main'); +// Mutate a custom section byte per round to bypass the NativeModule cache. +builder.addCustomSection('s', [0]); +const wire_bytes = new Uint8Array(builder.toBuffer()); + +const kRounds = 4; +const modules = Array.from({length: kRounds}, (_, i) => { + wire_bytes[wire_bytes.length - 1] = i; + return new WebAssembly.Module(wire_bytes); +}); +// sync[0]: main-thread round; sync[1]: worker round; sync[2]: worker ready. +const sab = new SharedArrayBuffer(12); +const sync = new Int32Array(sab); + +function workerCode() { + onmessage = ({data: {modules, sab}}) => { + const sync = new Int32Array(sab); + Atomics.store(sync, 2, 1); + for (let r = 0; r < modules.length; r++) { + while (Atomics.load(sync, 0) <= r) { + } + // Instantiating with Math.cos invalidates the Math.sin assumption. + new WebAssembly.Instance(modules[r], {m: {f: Math.cos, notify: () => {}}}); + Atomics.store(sync, 1, r + 1); + } + }; +} + +const worker = new Worker(workerCode, {type: 'function'}); +worker.postMessage({modules, sab}); +while (Atomics.load(sync, 2) === 0) { +} + +for (let r = 0; r < kRounds; r++) { + // First instantiation sets the well-known import status to Math.sin. + const instance = new WebAssembly.Instance(modules[r], { + m: {f: Math.sin, notify: () => Atomics.store(sync, 0, r + 1)}, + }); + assertEquals(0, instance.exports.main(0)); + while (Atomics.load(sync, 1) <= r) { + } +} +worker.terminate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-575829159.js b/deps/v8/test/mjsunit/regress/wasm/regress-575829159.js new file mode 100644 index 000000000000..6a4230bc8480 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-575829159.js @@ -0,0 +1,19 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --correctness-fuzzer-suppressions + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +// Valid as a normal import, but invalid when 'js-string' builtins are enabled. +builder.addImport('wasm:js-string', 'cast', kSig_i_i); +const wire_bytes = builder.toBuffer(); + +const module = new WebAssembly.Module(wire_bytes); +const serialized = d8.wasm.serializeModule(module); +assertThrows( + () => d8.wasm.deserializeModule( + serialized, wire_bytes, {builtins: ['js-string']}), + WebAssembly.CompileError); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-575926503.js b/deps/v8/test/mjsunit/regress/wasm/regress-575926503.js new file mode 100644 index 000000000000..d88b2946908f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-575926503.js @@ -0,0 +1,30 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --log-code --vtune-prof-annotate-wasm + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const worker = new Worker(function() { + postMessage(0); + while (true) { + %EstimateCurrentMemoryConsumption(); + } +}, {type: 'function'}); +worker.getMessage(); + +const builder = new WasmModuleBuilder(); +builder.addFunction('f', kSig_v_v).addBody([]); +const url = 'test/mjsunit/regress/wasm/regress-575926503.js'; +const url_bytes = Array.from(url, c => c.charCodeAt(0)); +builder.addCustomSection('sourceMappingURL', [url_bytes.length, ...url_bytes]); +builder.addCustomSection('id', [0, 0]); +const wire_bytes = new Uint8Array(builder.toBuffer()); + +for (let i = 0; i < 10; i++) { + wire_bytes[wire_bytes.length - 1] = i & 0xff; + wire_bytes[wire_bytes.length - 2] = (i >> 8) & 0xff; + new WebAssembly.Module(wire_bytes); +} +worker.terminate(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-576112595.js b/deps/v8/test/mjsunit/regress/wasm/regress-576112595.js new file mode 100644 index 000000000000..d69616a96532 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-576112595.js @@ -0,0 +1,64 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); + +const s0 = builder.addStruct([makeField(kWasmI32, true)]); +const s1 = builder.addStruct({ + fields: [makeField(kWasmI32, true), makeField(kWasmI32, true)], + supertype: s0, +}); +const s2 = builder.addStruct({ + fields: [ + makeField(kWasmI32, true), + makeField(kWasmI32, true), + makeField(kWasmI32, true), + ], + supertype: s1, + final: true, +}); + +const f = builder.addImport('m', 'f', kSig_v_i); + +const sig = makeSig( + [kWasmI32, wasmRefNullType(s0), wasmRefNullType(s0)], + [kWasmI32]); + +builder.addFunction('test', sig) + .addLocals(wasmRefType(s1), 1) // local 3: (ref $s1) + .addBody([ + // local 3 = struct.new $s1 (10, 20) + kExprI32Const, 10, + kExprI32Const, 20, + kGCPrefix, kExprStructNew, s1, + kExprLocalSet, 3, + kExprLoop, kWasmVoid, + // call $f(ref.test (ref $s2) (local.get 3)) + kExprLocalGet, 3, + kGCPrefix, kExprRefTest, s2, + kExprCallFunction, f, + // local 3 = ref.cast (ref $s1) (local.get 1) + kExprLocalGet, 1, + kGCPrefix, kExprRefCast, s1, + kExprLocalSet, 3, + // local 1 = local.get 2 + kExprLocalGet, 2, + kExprLocalSet, 1, + // br_if 0 (local.tee 0 (i32.sub (local.get 0) 1)) + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalTee, 0, + kExprBrIf, 0, + kExprEnd, + kExprI32Const, 42, + ]) + .exportFunc(); + +const instance = builder.instantiate({m: {f: () => {}}}); +%WasmTierUpFunction(instance.exports.test); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-577305505.js b/deps/v8/test/mjsunit/regress/wasm/regress-577305505.js new file mode 100644 index 000000000000..251f1a440a90 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-577305505.js @@ -0,0 +1,120 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --wasm-js-interop + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.startRecGroup(); +const $obj0 = builder.addStruct({fields: [], descriptor: 1}); +const $desc0 = builder.addStruct( + {fields: [makeField(kWasmExternRef, false)], describes: $obj0}); +builder.endRecGroup(); + +const $p0 = builder.addImportedGlobal('p', 'p0', kWasmExternRef); +const $p1 = builder.addImportedGlobal('p', 'p1', kWasmExternRef); +const $g_desc0 = builder.addGlobal( + wasmRefType($desc0).exact(), false, false, + [kExprGlobalGet, $p0, kGCPrefix, kExprStructNew, $desc0]); +const $g_desc1 = builder.addGlobal( + wasmRefType($desc0).exact(), false, false, + [kExprGlobalGet, $p1, kGCPrefix, kExprStructNew, $desc0]); + +builder.addFunction('make0', makeSig([], [kWasmAnyRef])).exportFunc().addBody([ + kExprGlobalGet, $g_desc0.index, + kGCPrefix, kExprStructNewDesc, $obj0, +]); +builder.addFunction('make1', makeSig([], [kWasmAnyRef])).exportFunc().addBody([ + kExprGlobalGet, $g_desc1.index, + kGCPrefix, kExprStructNewDesc, $obj0, +]); + +const kTrapSig = makeSig([kWasmExternRef, kWasmI32, kWasmExternRef], [kWasmI32]); +builder.addFunction('geti', kTrapSig).exportFunc().addBody([ + kExprI32Const, 11, +]); +builder.addFunction('geti2', kTrapSig).exportFunc().addBody([ + kExprI32Const, 22, +]); + +const proto0 = {}; +const proto1 = {}; +const instance = builder.instantiate({p: {p0: proto0, p1: proto1}}); +const wasm = instance.exports; + +// Case 1: Proxy handler inherits the "get" trap from its prototype at an +// in-object offset beyond the handler's own instance size. +function HandlerProto() { + this.a = 1; + this.get = wasm.geti; +} +const handler_proto = new HandlerProto(); +function EmptyHandler() {} +EmptyHandler.prototype = handler_proto; + +// Finish slack tracking on EmptyHandler and make handler_proto fast. +function warmupProto(h) { + return h.get; +} +for (let i = 0; i < 20; i++) { + warmupProto(new EmptyHandler()); +} + +function allocHandlerAndAdjacentHeapNumber(v, zero) { + const h = new EmptyHandler(); + const hn = v + zero; + return [h, hn]; +} +const [handler] = allocHandlerAndAdjacentHeapNumber(1.2, 0.0); + +Object.setPrototypeOf( + proto0, new Proxy(Object.freeze(Object.create(null)), handler)); +Object.freeze(proto0); +const w0 = wasm.make0(); + +function readElem0(o) { + return o[0]; +} +%PrepareFunctionForOptimization(readElem0); +for (let i = 0; i < 5; i++) { + assertEquals(11, readElem0(w0)); +} +%OptimizeFunctionOnNextCall(readElem0); +assertEquals(11, readElem0(w0)); + +// Mutating the prototype trap or shadowing it on the handler must deoptimize. +handler_proto.get = wasm.geti2; +assertEquals(22, readElem0(w0)); + +%PrepareFunctionForOptimization(readElem0); +for (let i = 0; i < 5; i++) { + assertEquals(22, readElem0(w0)); +} +%OptimizeFunctionOnNextCall(readElem0); +assertEquals(22, readElem0(w0)); + +handler.get = () => 33; +assertEquals(33, readElem0(w0)); + +// Case 2: Proxy handler has an own constant "get" trap that is later mutated +// in-place. +const own_handler = {get: wasm.geti}; +Object.setPrototypeOf( + proto1, new Proxy(Object.freeze(Object.create(null)), own_handler)); +Object.freeze(proto1); +const w1 = wasm.make1(); + +function readElem1(o) { + return o[0]; +} +%PrepareFunctionForOptimization(readElem1); +for (let i = 0; i < 5; i++) { + assertEquals(11, readElem1(w1)); +} +%OptimizeFunctionOnNextCall(readElem1); +assertEquals(11, readElem1(w1)); + +own_handler.get = wasm.geti2; +assertEquals(22, readElem1(w1)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-670683.js b/deps/v8/test/mjsunit/regress/wasm/regress-670683.js index 095de05c83d7..e28292adf206 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-670683.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-670683.js @@ -5,11 +5,45 @@ // Flags: --allow-natives-syntax const bytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, - 0x60, 0x00, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, - 0x00, 0x01, 0x07, 0x11, 0x02, 0x04, 0x67, 0x72, 0x6f, 0x77, 0x00, - 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x0a, - 0x08, 0x01, 0x06, 0x00, 0x41, 0x01, 0x40, 0x00, 0x0b + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x05, // section length 5 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $grow (result i32) + + 0x05, // section kind: Memory + 0x03, // section length 3 + 0x01, 0x00, // memory count 1: no maximum + 0x01, // initial size 1 + + 0x07, // section kind: Export + 0x11, // section length 17 + 0x02, // exports count 2 + // export # 0 + 0x04, // field name length: 4 + 0x67, 0x72, 0x6f, 0x77, // field name: grow + 0x00, 0x00, // kind: function index: 0 + // export # 1 + 0x06, // field name length: 6 + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, // field name: memory + 0x02, 0x00, // kind: memory memory index + + 0x0a, // section kind: Code + 0x08, // section length 8 + 0x01, // functions count 1 + // function #0 $grow + 0x06, // body size 6 + 0x00, // 0 entries in locals list + 0x41, 0x01, // i32.const 1 + 0x40, 0x00, // memory.grow + 0x0b, // end ]); assertPromiseResult( diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-734108.js b/deps/v8/test/mjsunit/regress/wasm/regress-734108.js index 74a1717b8d26..2e201d524a16 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-734108.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-734108.js @@ -3,11 +3,45 @@ // found in the LICENSE file. __v_0 = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, - 0x60, 0x00, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, - 0x00, 0x01, 0x07, 0x11, 0x02, 0x04, 0x67, 0x72, 0x6f, 0x77, 0x00, - 0x00, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x0a, - 0x08, 0x01, 0x06, 0x00, 0x41, 0x01, 0x40, 0x00, 0x0b + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x05, // section length 5 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $grow (result i32) + + 0x05, // section kind: Memory + 0x03, // section length 3 + 0x01, 0x00, // memory count 1: no maximum + 0x01, // initial size 1 + + 0x07, // section kind: Export + 0x11, // section length 17 + 0x02, // exports count 2 + // export # 0 + 0x04, // field name length: 4 + 0x67, 0x72, 0x6f, 0x77, // field name: grow + 0x00, 0x00, // kind: function index: 0 + // export # 1 + 0x06, // field name length: 6 + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, // field name: memory + 0x02, 0x00, // kind: memory memory index + + 0x0a, // section kind: Code + 0x08, // section length 8 + 0x01, // functions count 1 + // function #0 $grow + 0x06, // body size 6 + 0x00, // 0 entries in locals list + 0x41, 0x01, // i32.const 1 + 0x40, 0x00, // memory.grow + 0x0b, // end ]); assertPromiseResult( WebAssembly.compile(__v_0) diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1340488.js b/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1340488.js index ff836575e942..9f47dcd07cf3 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1340488.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-crbug-1340488.js @@ -3,16 +3,89 @@ // found in the LICENSE file. var bytes = [ - 0, 97, 115, 109, 1, 0, 0, 0, 1, 11, 2, 96, 2, 126, 124, - 1, 126, 96, 0, 1, 124, 3, 2, 1, 0, 4, 5, 1, 112, 1, - 6, 6, 10, 114, 1, 112, 4, 244, 2, 127, 118, 126, 31, 125, 1, - 124, 2, 126, 2, 64, 2, 127, 3, 64, 2, 124, 3, 127, 65, 0, - 65, 0, 13, 3, 33, 142, 1, 65, 0, 13, 0, 65, 0, 11, 65, - 0, 13, 2, 34, 143, 1, 34, 241, 2, 34, 191, 2, 34, 242, 2, - 34, 208, 2, 33, 144, 1, 2, 127, 65, 0, 4, 64, 65, 0, 13, - 5, 11, 65, 0, 11, 33, 145, 1, 65, 0, 17, 1, 0, 11, 33, - 139, 4, 65, 0, 13, 0, 11, 12, 1, 11, 13, 0, 11, 66, 128, - 127, 34, 189, 3, 65, 0, 13, 0, 34, 199, 3, 11, 11 + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x0b, // section length 11 + 0x02, // types count 2 + 0x60, // kind: func + 0x02, // param count 2 + 0x7e, 0x7c, // i64 f64 + 0x01, 0x7e, // return count 1: i64 + 0x60, // kind: func + 0x00, // param count 0 + 0x01, 0x7c, // return count 1: f64 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $func0 (param i64 f64) (result i64) + + 0x04, // section kind: Table + 0x05, // section length 5 + 0x01, 0x70, 0x01, // table count 1: funcref with maximum + 0x06, // initial size 6 + 0x06, // maximum size 6 + + 0x0a, // section kind: Code + 0x72, // section length 114 + 0x01, // functions count 1 + // function #0 $func0 + 0x70, // body size 112 + 0x04, // 4 entries in locals list + 0xf4, 0x02, 0x7f, // 372 locals of type i32 + 0x76, 0x7e, // 118 locals of type i64 + 0x1f, 0x7d, // 31 locals of type f32 + 0x01, 0x7c, // 1 local of type f64 + 0x02, 0x7e, // block (result i64) $label4 + 0x02, 0x40, // block $label2 + 0x02, 0x7f, // block (result i32) $label0 + 0x03, 0x40, // loop $label3 + 0x02, 0x7c, // block (result f64) + 0x03, 0x7f, // loop (result i32) $label1 + 0x41, 0x00, // i32.const 0 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x03, // br_if $label0 + 0x21, 0x8e, 0x01, // local.set $var142 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x00, // br_if $label1 + 0x41, 0x00, // i32.const 0 + 0x0b, // end $label1 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x02, // br_if $label0 + 0x22, 0x8f, 0x01, // local.tee $var143 + 0x22, 0xf1, 0x02, // local.tee $var369 + 0x22, 0xbf, 0x02, // local.tee $var319 + 0x22, 0xf2, 0x02, // local.tee $var370 + 0x22, 0xd0, 0x02, // local.tee $var336 + 0x21, 0x90, 0x01, // local.set $var144 + 0x02, 0x7f, // block (result i32) + 0x41, 0x00, // i32.const 0 + 0x04, 0x40, // if + 0x41, 0x00, // i32.const 0 + 0x0d, 0x05, // br_if $label2 + 0x0b, // end + 0x41, 0x00, // i32.const 0 + 0x0b, // end + 0x21, 0x91, 0x01, // local.set $var145 + 0x41, 0x00, // i32.const 0 + 0x11, 0x01, 0x00, // call_indirect (result f64) + 0x0b, // end + 0x21, 0x8b, 0x04, // local.set $var523 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x00, // br_if $label3 + 0x0b, // end $label3 + 0x0c, 0x01, // br $label2 + 0x0b, // end $label0 + 0x0d, 0x00, // br_if $label2 + 0x0b, // end $label2 + 0x42, 0x80, 0x7f, // i64.const -128 + 0x22, 0xbd, 0x03, // local.tee $var445 + 0x41, 0x00, // i32.const 0 + 0x0d, 0x00, // br_if $label4 + 0x22, 0xc7, 0x03, // local.tee $var455 + 0x0b, // end $label4 + 0x0b, // end ]; var module = new WebAssembly.Module(new Uint8Array(bytes)); new WebAssembly.Instance(module); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-array-segment-args.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-array-segment-args.js new file mode 100644 index 000000000000..abe42d1e4d8d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-array-segment-args.js @@ -0,0 +1,94 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const sig = builder.addType(kSig_i_v); +const $i8Array = builder.addArray(kWasmI8); +const $funcArray = builder.addArray(kWasmFuncRef); + +const f42 = builder.addFunction('f42', sig).addBody([...wasmI32Const(42)]); +const f43 = builder.addFunction('f43', sig).addBody([...wasmI32Const(43)]); +const $data = builder.addPassiveDataSegment([42, 43, 44, 45]); +const $elem = builder.addPassiveElementSegment([f42.index, f43.index]); + +function callFuncAt(index) { + return [ + ...wasmI32Const(index), + kGCPrefix, kExprArrayGet, $funcArray, + kGCPrefix, kExprRefCast, sig, + kExprCallRef, sig, + ]; +} + +builder.addFunction('newData', kSig_i_ii) + .addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kGCPrefix, kExprArrayNewData, $i8Array, $data, + ...wasmI32Const(1), + kGCPrefix, kExprArrayGetU, $i8Array, + ]) + .exportFunc(); + +builder.addFunction('initData', kSig_i_i) + .addLocals(wasmRefNullType($i8Array), 1) + .addBody([ + ...wasmI32Const(4), + kGCPrefix, kExprArrayNewDefault, $i8Array, + kExprLocalSet, 1, + kExprLocalGet, 1, + ...wasmI32Const(1), + kExprLocalGet, 0, + ...wasmI32Const(3), + kGCPrefix, kExprArrayInitData, $i8Array, $data, + kExprLocalGet, 1, + ...wasmI32Const(3), + kGCPrefix, kExprArrayGetU, $i8Array, + ]) + .exportFunc(); + +builder.addFunction('newElem', kSig_i_ii) + .addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kGCPrefix, kExprArrayNewElem, $funcArray, $elem, + ...callFuncAt(0), + ]) + .exportFunc(); + +builder.addFunction('initElem', kSig_i_i) + .addLocals(wasmRefNullType($funcArray), 1) + .addBody([ + ...wasmI32Const(2), + kGCPrefix, kExprArrayNewDefault, $funcArray, + kExprLocalSet, 1, + kExprLocalGet, 1, + ...wasmI32Const(1), + kExprLocalGet, 0, + ...wasmI32Const(1), + kGCPrefix, kExprArrayInitElem, $funcArray, $elem, + kExprLocalGet, 1, + ...callFuncAt(1), + ]) + .exportFunc(); + +const exports = builder.instantiate().exports; + +assertEquals(43, exports.newData(0, 4)); +assertEquals(45, exports.newData(2, 2)); +assertTraps(kTrapDataSegmentOutOfBounds, () => exports.newData(3, 2)); + +assertEquals(45, exports.initData(1)); +assertTraps(kTrapDataSegmentOutOfBounds, () => exports.initData(2)); + +assertEquals(42, exports.newElem(0, 2)); +assertEquals(43, exports.newElem(1, 1)); +assertTraps(kTrapElementSegmentOutOfBounds, () => exports.newElem(1, 2)); + +assertEquals(43, exports.initElem(1)); +assertTraps(kTrapElementSegmentOutOfBounds, () => exports.initElem(2)); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-cast-nofunc.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-cast-nofunc.js new file mode 100644 index 000000000000..e49617fe20e1 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-cast-nofunc.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-jitless --jitless + +// Regression test for a bug in the Wasm interpreter, which decoded a function's +// local declarations without passing a module to DecodeLocalDecls, which left +// indexed reference-type locals with a default RefTypeKind::kOther. +// When the bytecode generator later ran a subtyping check for a ref.cast whose +// operand was such a local, UpcastToStandardType() hit UNREACHABLE. + +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const sig = builder.addType(kSig_v_v); + +builder.addFunction('w0', kSig_v_v) + // local 0: (ref null func) + .addLocals(wasmRefNullType(kWasmFuncRef), 1) + // local 1: (ref null $sig) + .addLocals(wasmRefNullType(sig), 1) + // local 2: (ref null nofunc) + .addLocals(wasmRefNullType(kWasmNullFuncRef), 1) + .addBody([ + kExprRefNull, kFuncRefCode, + kExprLocalSet, 0, + kExprLocalGet, 0, + kGCPrefix, kExprRefCastNull, sig, + kExprLocalSet, 1, + kExprLocalGet, 1, + kGCPrefix, kExprRefCastNull, kNullFuncRefCode, + kExprLocalSet, 2, + ]) + .exportFunc(); + +const instance = builder.instantiate(); +instance.exports.w0(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exception-null.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exception-null.js new file mode 100644 index 000000000000..d0862e3c8559 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exception-null.js @@ -0,0 +1,133 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +// A null reference thrown as an exception payload must be caught as the same +// kind of null (WasmNull for internal types, JS null for extern types), so +// that null checks keep working after the catch. + +(function TestNullPayloadRoundTrip() { + const builder = new WasmModuleBuilder(); + const struct = builder.addStruct([makeField(kWasmI32, true)]); + const cases = [ + ['anyref', kWasmAnyRef, [kAnyRefCode], false], + ['eqref', kWasmEqRef, [kEqRefCode], true], + ['structref', wasmRefNullType(struct), wasmSignedLeb(struct), true], + ['nullref', kWasmNullRef, [kNullRefCode], true], + ['funcref', kWasmFuncRef, [kFuncRefCode], false], + ['externref', kWasmExternRef, [kExternRefCode], false], + ]; + for (const [name, type, heap_type, eq] of cases) { + const tag = builder.addTag(makeSig([type], [])); + const block_type = builder.addType(makeSig([], [type])); + const throw_and_catch_null = [ + kExprTry, ...wasmSignedLeb(block_type), + kExprRefNull, ...heap_type, + kExprThrow, ...wasmUnsignedLeb(tag), + kExprCatch, ...wasmUnsignedLeb(tag), + kExprEnd, + ]; + builder.addFunction(name + '_is_null', kSig_i_v) + .addBody([...throw_and_catch_null, kExprRefIsNull]) + .exportFunc(); + builder.addFunction(name + '_br_on_null', kSig_i_v) + .addBody([ + kExprBlock, kWasmVoid, + ...throw_and_catch_null, + kExprBrOnNull, 0, + kExprDrop, + kExprI32Const, 0, + kExprReturn, + kExprEnd, + kExprI32Const, 1, + ]) + .exportFunc(); + builder.addFunction(name + '_test_null', kSig_i_v) + .addBody([ + ...throw_and_catch_null, + kGCPrefix, kExprRefTestNull, ...heap_type, + ]) + .exportFunc(); + if (eq) { + builder.addFunction(name + '_eq_null', kSig_i_v) + .addBody([ + ...throw_and_catch_null, + kExprRefNull, ...heap_type, + kExprRefEq, + ]) + .exportFunc(); + } + builder.addFunction(name + '_get', makeSig([], [type])) + .addBody(throw_and_catch_null) + .exportFunc(); + } + + const instance = builder.instantiate(); + for (const [name, , , eq] of cases) { + assertEquals(1, instance.exports[name + '_is_null'](), name); + assertEquals(1, instance.exports[name + '_br_on_null'](), name); + assertEquals(1, instance.exports[name + '_test_null'](), name); + if (eq) assertEquals(1, instance.exports[name + '_eq_null'](), name); + assertNull(instance.exports[name + '_get'](), name); + } +})(); + +(function TestNullPayloadCastToSubtype() { + // After a caught null payload incorrectly passes br_on_null, a cast to a + // non-final subtype would inspect the map of the JS null object as if it was + // a Wasm struct. + const builder = new WasmModuleBuilder(); + const super_type = builder.addStruct( + [makeField(kWasmI32, true)], kNoSuperType, false); + const sub_type = builder.addStruct( + [makeField(kWasmI32, true), makeField(kWasmI64, true)], super_type, + false); + const tag = builder.addTag(makeSig([wasmRefNullType(super_type)], [])); + const block_type = + builder.addType(makeSig([], [wasmRefNullType(super_type)])); + builder.addFunction('main', kSig_i_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprTry, ...wasmSignedLeb(block_type), + kExprRefNull, ...wasmSignedLeb(super_type), + kExprThrow, tag, + kExprCatch, tag, + kExprEnd, + kExprBrOnNull, 0, + kGCPrefix, kExprRefCast, ...wasmSignedLeb(sub_type), + kGCPrefix, kExprStructGet, ...wasmUnsignedLeb(sub_type), 0, + kExprReturn, + kExprEnd, + kExprI32Const, 42, + ]) + .exportFunc(); + const instance = builder.instantiate(); + assertEquals(42, instance.exports.main()); +})(); + +(function TestNullPayloadFromJS() { + // Null payloads of exceptions created from JS must be handled the same way. + const builder = new WasmModuleBuilder(); + const tag_index = builder.addImportedTag('m', 'tag', makeSig([kWasmAnyRef], [])); + const throw_index = builder.addImport('m', 'throw', kSig_v_v); + const block_type = builder.addType(makeSig([], [kWasmAnyRef])); + builder.addFunction('main', kSig_i_v) + .addBody([ + kExprTry, ...wasmSignedLeb(block_type), + kExprCallFunction, throw_index, + kExprUnreachable, + kExprCatch, tag_index, + kExprEnd, + kExprRefIsNull, + ]) + .exportFunc(); + const tag = new WebAssembly.Tag({parameters: ['anyref']}); + const instance = builder.instantiate({ + m: {tag, throw() { throw new WebAssembly.Exception(tag, [null]); }} + }); + assertEquals(1, instance.exports.main()); +})(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exnref.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exnref.js new file mode 100644 index 000000000000..f2aa644a0357 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-exnref.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addFunction('test', kSig_v_v) + .addBody([ + kExprTryTable, kWasmVoid, 0, + kExprEnd, + ]) + .exportFunc(); + +const wire_bytes = builder.toBuffer(); +assertFalse(WebAssembly.validate(wire_bytes)); +assertThrows( + () => new WebAssembly.Module(wire_bytes), WebAssembly.CompileError, + /exnref not supported by the Wasm interpreter/); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-context.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-context.js new file mode 100644 index 000000000000..e7301b7b32e7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-context.js @@ -0,0 +1,41 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless --allow-natives-syntax + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +// Numeric parameter conversion calls allocation builtins before dispatching to +// the imported callable. Those calls must not leave the context register +// clobbered when a Proxy is dispatched through CallProxy. +const kParamCount = 40; +const builder = new WasmModuleBuilder(); +const importSig = + builder.addType(makeSig(new Array(kParamCount).fill(kWasmI64), [])); +const importIndex = builder.addImport('m', 'f', importSig); + +const body = []; +for (let i = 0; i < kParamCount; ++i) { + body.push(...wasmI64Const(BigInt(i) * 0x100000001n + 0x11223344n)); +} +body.push(kExprCallFunction, importIndex); +builder.addFunction('run', kSig_v_v).addBody(body).exportFunc(); + +let calls = 0; +const callable = new Proxy(function(...args) { + assertEquals(kParamCount, args.length); + for (let i = 0; i < args.length; ++i) { + assertEquals(BigInt(i) * 0x100000001n + 0x11223344n, args[i]); + } + ++calls; +}, { + apply(target, receiver, args) { + return Reflect.apply(target, receiver, args); + }, +}); + +const instance = builder.instantiate({m: {f: callable}}); +%SimulateNewspaceFull(); +instance.exports.run(); +assertEquals(1, calls); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-null.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-null.js new file mode 100644 index 000000000000..ef798ee3eafb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-import-null.js @@ -0,0 +1,122 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless --expose-gc + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +// A JS import returning null for a nullable reference type must be converted +// to the right Wasm null representation, without passing WasmNull to the +// JS-to-Wasm conversion. + +(function TestFuzzerRepro() { + // Minimized from the fuzzer case (scenario "import_ref_null"). + const builder = new WasmModuleBuilder(); + const imp = builder.addImport('m', 'callback', makeSig([], [kWasmFuncRef])); + builder.addFunction('run', kSig_i_v) + .addBody([kExprCallFunction, imp, kExprDrop, ...wasmI32Const(7)]) + .exportFunc(); + const instance = + builder.instantiate({m: {callback() { gc(); return null; }}}); + assertEquals(7, instance.exports.run()); + assertEquals(7, instance.exports.run()); +})(); + +(function TestImportReturnsNull() { + const builder = new WasmModuleBuilder(); + const struct = builder.addStruct([makeField(kWasmI32, true)]); + const cases = [ + ['funcref', kWasmFuncRef], + ['anyref', kWasmAnyRef], + ['eqref', kWasmEqRef], + ['structref', wasmRefNullType(struct)], + ['nullref', kWasmNullRef], + ['externref', kWasmExternRef], + ]; + const imports = {}; + const import_indices = cases.map(([name, type]) => { + imports[name] = () => { gc(); return null; }; + return builder.addImport('m', name, makeSig([], [type])); + }); + cases.forEach(([name, type], i) => { + const sig = makeSig([], [type]); + const imp = import_indices[i]; + builder.addFunction(name + '_is_null', kSig_i_v) + .addBody([kExprCallFunction, imp, kExprRefIsNull]) + .exportFunc(); + builder.addFunction(name + '_br_on_null', kSig_i_v) + .addBody([ + kExprBlock, kWasmVoid, + kExprCallFunction, imp, + kExprBrOnNull, 0, + kExprDrop, + kExprI32Const, 0, + kExprReturn, + kExprEnd, + kExprI32Const, 1, + ]) + .exportFunc(); + builder.addFunction(name + '_get', sig) + .addBody([kExprCallFunction, imp]) + .exportFunc(); + }); + const instance = builder.instantiate({m: imports}); + for (const [name] of cases) { + assertEquals(1, instance.exports[name + '_is_null'](), name); + assertEquals(1, instance.exports[name + '_br_on_null'](), name); + assertNull(instance.exports[name + '_get'](), name); + } +})(); + +(function TestImportReturnsMultipleNulls() { + const builder = new WasmModuleBuilder(); + const sig = makeSig([], [kWasmFuncRef, kWasmI32, kWasmExternRef, + kWasmFuncRef]); + const imp = builder.addImport('m', 'f', sig); + builder.addFunction('main', sig) + .addBody([kExprCallFunction, imp]) + .exportFunc(); + const instance = builder.instantiate( + {m: {f() { gc(); return [null, 7, null, null]; }}}); + assertEquals([null, 7, null, null], instance.exports.main()); +})(); + +(function TestIndirectCallToImportReturnsNull() { + // Indirect calls coerce the result against the callee's canonical + // signature. + const builder = new WasmModuleBuilder(); + const sig = builder.addType(makeSig([], [kWasmFuncRef])); + const imp = builder.addImport('m', 'f', sig); + const table = builder.addTable(kWasmFuncRef, 1, 1); + builder.addActiveElementSegment(table.index, wasmI32Const(0), [imp]); + builder.addFunction('call_indirect', kSig_i_v) + .addBody([ + kExprI32Const, 0, + kExprCallIndirect, sig, table.index, + kExprRefIsNull, + ]) + .exportFunc(); + builder.addDeclarativeElementSegment([imp]); + builder.addFunction('call_ref', kSig_i_v) + .addBody([ + kExprRefFunc, imp, + kExprCallRef, sig, + kExprRefIsNull, + ]) + .exportFunc(); + const instance = builder.instantiate({m: {f() { gc(); return null; }}}); + assertEquals(1, instance.exports.call_indirect()); + assertEquals(1, instance.exports.call_ref()); +})(); + +(function TestImportReturnsNullForNonNullableType() { + const builder = new WasmModuleBuilder(); + const imp = builder.addImport( + 'm', 'f', makeSig([], [wasmRefType(kWasmFuncRef)])); + builder.addFunction('main', kSig_v_v) + .addBody([kExprCallFunction, imp, kExprDrop]) + .exportFunc(); + const instance = builder.instantiate({m: {f() { return null; }}}); + assertThrows(() => instance.exports.main(), TypeError); +})(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-return-call-subtype.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-return-call-subtype.js new file mode 100644 index 000000000000..7529954709d9 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-return-call-subtype.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const functionType = builder.addType(kSig_v_v); +const calleeType = + builder.addType(makeSig([], [wasmRefNullType(functionType)])); +const callerType = builder.addType(makeSig([], [kWasmFuncRef])); + +// A tail callee may return a subtype of its caller's declared result type. +const callee = builder.addFunction('callee', calleeType) + .addBody([kExprRefNull, functionType]); +builder.addFunction('direct', callerType) + .addBody([kExprReturnCall, callee.index]) + .exportFunc(); +builder.addFunction('indirect', callerType) + .addBody([ + kExprI32Const, 0, + kExprReturnCallIndirect, calleeType, kTableZero, + ]) + .exportFunc(); +builder.addFunction('ref', callerType) + .addBody([ + kExprRefFunc, callee.index, + kExprReturnCallRef, calleeType, + ]) + .exportFunc(); +builder.appendToTable([callee.index]); + +const instance = builder.instantiate(); +assertEquals(null, instance.exports.direct()); +assertEquals(null, instance.exports.indirect()); +assertEquals(null, instance.exports.ref()); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-v128-js-boundary.js b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-v128-js-boundary.js new file mode 100644 index 000000000000..ed6e5e743d33 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-drumbrake-v128-js-boundary.js @@ -0,0 +1,52 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-jitless --jitless + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +(function TestV128HostBoundaryThrows() { + const builder = new WasmModuleBuilder(); + builder.addFunction('v128Param', makeSig([kWasmS128], [kWasmI32])) + .addBody([kExprI32Const, 0]) + .exportFunc(); + builder.addFunction('v128Return', makeSig([], [kWasmS128])) + .addBody(wasmS128Const(0, 0)) + .exportFunc(); + builder.addFunction( + 'MultiValueV128Return', makeSig([], [kWasmI32, kWasmS128])) + .addBody([...wasmI32Const(42), ...wasmS128Const(0, 0)]) + .exportFunc(); + + const instance = builder.instantiate(); + assertThrows(() => instance.exports.v128Param(), TypeError); + assertThrows(() => instance.exports.v128Return(), TypeError); + assertThrows(() => instance.exports.MultiValueV128Return(), TypeError); +})(); + +(function TestNestedJSToWasmContextLoad() { + const builder = new WasmModuleBuilder(); + const reduceRight = builder.addImport( + 'env', 'reduceRight', makeSig([kWasmFuncRef], [])); + const callback = builder.addFunction( + 'callback', makeSig([kWasmS128], [])) + .addBody([kExprUnreachable]) + .index; + + builder.addFunction('callReduceRight', kSig_v_v) + .addBody([ + kExprRefFunc, callback, + kExprCallFunction, reduceRight, + ]) + .exportFunc(); + builder.addDeclarativeElementSegment([callback]); + + const array = [0, , 1]; + Object.setPrototypeOf(array, new Proxy(Array.prototype, {})); + const instance = builder.instantiate({ + env: {reduceRight: Array.prototype.reduceRight.bind(array)}, + }); + + assertThrows(() => instance.exports.callReduceRight(), TypeError); +})(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-simd-570497964.js b/deps/v8/test/mjsunit/regress/wasm/regress-simd-570497964.js new file mode 100644 index 000000000000..db6db296a702 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-simd-570497964.js @@ -0,0 +1,155 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-revectorize --wasm-assert-types --allow-natives-syntax +// Flags: --no-wasm-inlining +// +// --no-wasm-inlining prevents `inner` from being inlined into `test` after +// the Liftoff warm-up call below (wasm inlining uses call-count feedback +// collected by Liftoff), which would otherwise eliminate the cross-function +// Return ABI boundary this test depends on. + +// Regression test for returning a revectorized Simd256Extract128Lane(lane=0) +// result as one of several wasm multi-return values. On x64, the lane-0 +// extraction is elided during instruction selection: the result is aliased +// (via EmitIdentity) directly to its Simd256 producer, so the register +// allocator ends up treating the value as a full 256-bit (32-byte) quantity. +// When this value has to be placed in a fixed caller-frame stack slot sized +// for a 128-bit (16-byte) wasm v128 value, the generated move wrote the full +// 32 bytes into that 16-byte slot, clobbering whatever memory follows it. +// +// Moves for multi-return values are emitted in return-index order, and their +// stack slot addresses increase monotonically with index. So a buggy 32-byte +// write at slot i always overflows into slot i+1 -- but slot i+1's own move +// always executes right after and overwrites/heals that overflow, UNLESS i +// is the very last return value, in which case the overflow spills past the +// whole return area into whatever (unclaimed) stack memory follows it. +// +// `inner` returns [f64, f64, v128, i64, v128]: the two f64 returns occupy +// both available FP/SIMD return registers (xmm1/xmm2) on x64, forcing the +// v128 returns onto the stack; the i64 return goes into a GP register. The +// same elided extraction is returned twice so that the second occurrence is +// the *last* return value -- the only position where its overflow isn't +// healed by a subsequent return value's own move, making the corruption +// observable. +// +// To observe that overflow, `test` (the caller) keeps an unrelated v128 +// value (`extra`) live across the call to `inner`, so it gets spilled to +// `test`'s own frame, adjacent to `inner`'s outgoing return-value area. +// Without the fix, the overflow clobbers `extra`'s spill slot with unrelated +// data (the packed op's other lane); with the fix, it reads back correctly. +// `inner`'s own return values aren't otherwise needed, so they're dropped. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addMemory(1, 1); +builder.exportMemoryAs('memory'); + +const inner_sig = makeSig( + [kWasmI32], + [kWasmF64, kWasmF64, kWasmS128, kWasmI64, kWasmS128]); + +const inner = builder.addFunction('inner', inner_sig) + .addLocals(kWasmS128, 2) // 1: lo, 2: hi + .addBody([ + // lo = i32x4.add(v128.load(offset + 0), i32x4.splat(1)) + kExprLocalGet, 0, + kSimdPrefix, ...wasmUnsignedLeb(kExprS128LoadMem), 0, 0, + kExprI32Const, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Splat), + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Add), + kExprLocalSet, 1, + + // hi = i32x4.add(v128.load(offset + 16), i32x4.splat(1)) + kExprLocalGet, 0, + kSimdPrefix, ...wasmUnsignedLeb(kExprS128LoadMem), 0, 16, + kExprI32Const, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Splat), + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Add), + kExprLocalSet, 2, + + // Combine lo and hi with an i32x4.add "reduce seed" in revectorizer. + // `lo` is also used below as a return value (an "external use" + // outside the packed region), which is exactly what + // produces the elided Simd256Extract128Lane(lane=0) this test targets. + kExprLocalGet, 1, + kExprLocalGet, 2, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Add), + kExprDrop, + + // Return values, in signature order: f64, f64, v128 (lo), i64, + // v128 (lo again -- the *last* return value, so its overflow spills + // past the whole return area instead of into another return slot). + ...wasmF64Const(1.0), + ...wasmF64Const(2.0), + kExprLocalGet, 1, + ...wasmI64Const(42), + kExprLocalGet, 1, + ]).exportFunc(); + +// Wrapper that calls `inner`, keeping `extra` live across the call, and +// extracts it as i32 lanes (since v128 values cannot cross the JS/wasm +// boundary). `inner`'s own return values are dropped -- only `extra`'s +// spill slot is relevant to this test. +builder.addFunction('test', makeSig( + [kWasmI32], + [kWasmI32, kWasmI32, kWasmI32, kWasmI32])) + .addLocals(kWasmS128, 1) // 1: extra + .addBody([ + // extra = i32x4.add(v128.load(offset + 32), splat(1)). Computed before + // the call and used after it, so it must stay live across the call to + // `inner` and gets spilled somewhere in `test`'s own frame -- possibly + // adjacent to `inner`'s outgoing return-value area. + kExprLocalGet, 0, + kSimdPrefix, ...wasmUnsignedLeb(kExprS128LoadMem), 0, 32, + kExprI32Const, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Splat), + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4Add), + kExprLocalSet, 1, + + kExprLocalGet, 0, + kExprCallFunction, inner.index, + kExprDrop, // v128 (lo again) + kExprDrop, // i64 + kExprDrop, // v128 (lo) + kExprDrop, // f64 + kExprDrop, // f64 + + // extra, checked *after* the call, to detect whether the overflow + // (spilling past the return area) clobbered its spill slot. + kExprLocalGet, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4ExtractLane), 0, + kExprLocalGet, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4ExtractLane), 1, + kExprLocalGet, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4ExtractLane), 2, + kExprLocalGet, 1, + kSimdPrefix, ...wasmUnsignedLeb(kExprI32x4ExtractLane), 3, + ]).exportFunc(); + +const instance = builder.instantiate(); +const mem = new DataView(instance.exports.memory.buffer); +for (let i = 0; i < 12; i++) { + mem.setInt32(i * 4, i + 100, true); +} + +// Run once on Liftoff first. +instance.exports.test(0); + +// `inner` is only reachable via a direct call from `test`, so it must be +// tiered up explicitly for revectorization to run on it (and must be +// exported so %WasmTierUpFunction can reference it, even though it's never +// called directly from JS since it returns v128 values). +%WasmTierUpFunction(instance.exports.inner); +%WasmTierUpFunction(instance.exports.test); + +// This should not crash (the bug manifested as a wasm type assertion +// violation when the overflow clobbered unrelated stack content), and +// `extra` -- live across the call to `inner` -- must not be clobbered by the +// overflowing 32-byte write of `inner`'s last return value. +const result = instance.exports.test(0); + +// extra = memory[8..11] + 1. +assertEquals([109, 110, 111, 112], result); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-simd-573671130.js b/deps/v8/test/mjsunit/regress/wasm/regress-simd-573671130.js new file mode 100644 index 000000000000..2a3a73338fac --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-simd-573671130.js @@ -0,0 +1,49 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-revectorize --allow-natives-syntax + +// Regression test: IntersectPackNode is only supported when intersecting +// with a ForcePackNode. SLPTree::BuildTreeRec checked node1 for an +// incompatible PackNode only in the `!is_intersected` branch, so when +// node0 alone already set `is_intersected`, node1 could keep a +// DefaultPackNode that doesn't support intersecting, causing a crash +// during revectorization. +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addMemory(1, 1); +builder.addFunction('test', kSig_v_v) + .addLocals(kWasmS128, 6) + .addBody([ + // load1 = v128.load(0, offset=0), load2 = v128.load(0, offset=16) + kExprI32Const, 0, kSimdPrefix, kExprS128LoadMem, 4, 0, kExprLocalSet, 0, + kExprI32Const, 0, kSimdPrefix, kExprS128LoadMem, 4, 16, kExprLocalSet, 1, + // u1 = i8x16.abs(load1) (emitted before load0) + kExprLocalGet, 0, kSimdPrefix, kExprI8x16Abs, kExprLocalSet, 2, + // load0 = v128.load(0, offset=64), load3 = v128.load(0, offset=96) + kExprI32Const, 0, kSimdPrefix, kExprS128LoadMem, 4, 64, kExprLocalSet, 3, + kExprI32Const, 0, kSimdPrefix, kExprS128LoadMem, 4, 96, kExprLocalSet, 4, + // u0 = i8x16.abs(load0) + kExprLocalGet, 3, kSimdPrefix, kExprI8x16Abs, kExprLocalSet, 5, + // Tree 1: packs [load1, load2] as DefaultPackNode + kExprI32Const, 0, kExprLocalGet, 0, kSimdPrefix, kExprI8x16Neg, + kSimdPrefix, kExprS128Not, kSimdPrefix, kExprS128StoreMem, 4, ...wasmUnsignedLeb(128), + kExprI32Const, 0, kExprLocalGet, 1, kSimdPrefix, kExprI8x16Neg, + kSimdPrefix, kExprS128Not, kSimdPrefix, kExprS128StoreMem, 4, ...wasmUnsignedLeb(144), + // Tree 2: packs [load0, load3] as ForcePackNode + kExprI32Const, 0, kExprLocalGet, 3, kSimdPrefix, kExprI8x16Neg, + kSimdPrefix, kExprS128Not, kSimdPrefix, kExprS128StoreMem, 4, ...wasmUnsignedLeb(160), + kExprI32Const, 0, kExprLocalGet, 4, kSimdPrefix, kExprI8x16Neg, + kSimdPrefix, kExprS128Not, kSimdPrefix, kExprS128StoreMem, 4, ...wasmUnsignedLeb(176), + // Tree 3: packs [u0, u1] and creates IntersectPackNode([load0, load1]) + kExprI32Const, 0, kExprLocalGet, 5, kSimdPrefix, kExprI8x16Neg, + kSimdPrefix, kExprS128StoreMem, 4, ...wasmUnsignedLeb(192), + kExprI32Const, 0, kExprLocalGet, 2, kSimdPrefix, kExprI8x16Neg, + kSimdPrefix, kExprS128StoreMem, 4, ...wasmUnsignedLeb(208), + ]).exportFunc(); +const instance = builder.instantiate(); +instance.exports.test(); +%WasmTierUpFunction(instance.exports.test); +instance.exports.test(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-simd-573671231.js b/deps/v8/test/mjsunit/regress/wasm/regress-simd-573671231.js new file mode 100644 index 000000000000..540ad1b1fdfb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-simd-573671231.js @@ -0,0 +1,101 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-revectorize --allow-natives-syntax + +// Regression test for MoveOptimizer::FinalizeMoves zeroing the upper 128 +// bits of a Simd256 register. A 128-bit kSimd128 value shares the same +// virtual register as its 256-bit kSimd256 producer (e.g. a lane-0 +// "extract" that got elided and aliased to its Simd256 producer on x64). +// When that virtual register is spilled to a 256-bit stack slot and later +// reloaded in the same ParallelMove by both a 128-bit destination and a +// 256-bit destination, LoadCompare's sort didn't distinguish Simd256 from +// Simd128 operand widths. This let MoveOptimizer::FinalizeMoves pick the +// 128-bit reload as the group's representative ("group_begin") and rewrite +// the 256-bit reload to source from the 128-bit register instead of the +// stack slot, silently zeroing the upper 128 bits (lanes 4..7) of the wider +// register. +// +// `w0`/`w1` are revectorized into one 256-bit value, which gets spilled +// across the call to the imported `nop` function. After the call, `phi_128` +// reloads only the low 128 bits (w0), while `phi_low`/`phi_high` need the +// full spilled value (w0 and w1) to feed a revectorized store -- both +// reloading from the very same spill slot in the same gap. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +(function TestMoveOptimizerSimd256ZeroHigh128() { + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + builder.exportMemoryAs('memory'); + const call_import = builder.addImport('env', 'nop', makeSig([], [])); + builder.addFunction('test', makeSig([kWasmI32, kWasmI32], [])) + .addLocals(kWasmS128, 5) // locals 2..6: w0, w1, phi_128, phi_low, phi_high + .addBody([ + kExprLocalGet, 0, + kExprIf, kWasmVoid, + // Load v0, v1 from addr+0, addr+16 and add to themselves -> w0, w1 + kExprLocalGet, 1, + kSimdPrefix, kExprS128LoadMem, 0, ...wasmUnsignedLeb(0), + kExprLocalTee, 2, + kExprLocalGet, 2, + kSimdPrefix, ...wasmSignedLeb(kExprI32x4Add), + kExprLocalSet, 2, + kExprLocalGet, 1, + kSimdPrefix, kExprS128LoadMem, 0, ...wasmUnsignedLeb(16), + kExprLocalTee, 3, + kExprLocalGet, 3, + kSimdPrefix, ...wasmSignedLeb(kExprI32x4Add), + kExprLocalSet, 3, + // Call imported nop() so v256 = [w0, w1] is spilled to a 256-bit + // stack slot. + kExprCallFunction, call_import, + // phi_128 (local 4) = w0 (the elided, lane-0 "extract" of v256). + kExprLocalGet, 2, + kExprLocalSet, 4, + // phi_low (local 5) = w0, phi_high (local 6) = w1. + kExprLocalGet, 2, + kExprLocalSet, 5, + kExprLocalGet, 3, + kExprLocalSet, 6, + kExprElse, + kExprLocalGet, 1, + kSimdPrefix, kExprS128LoadMem, 0, ...wasmUnsignedLeb(32), + kExprLocalSet, 4, + kExprLocalGet, 1, + kSimdPrefix, kExprS128LoadMem, 0, ...wasmUnsignedLeb(64), + kExprLocalSet, 5, + kExprLocalGet, 1, + kSimdPrefix, kExprS128LoadMem, 0, ...wasmUnsignedLeb(80), + kExprLocalSet, 6, + kExprEnd, + // Store phi_low and phi_high to addr+128 and addr+144 (revectorized). + kExprLocalGet, 1, + kExprLocalGet, 5, + kSimdPrefix, kExprS128StoreMem, 0, ...wasmUnsignedLeb(128), + kExprLocalGet, 1, + kExprLocalGet, 6, + kSimdPrefix, kExprS128StoreMem, 0, ...wasmUnsignedLeb(144), + // Store phi_128 (the 128-bit use) to addr+200. + kExprLocalGet, 1, + kExprLocalGet, 4, + kSimdPrefix, kExprS128StoreMem, 0, ...wasmUnsignedLeb(200), + ]) + .exportFunc(); + const instance = builder.instantiate({env: {nop: () => {}}}); + const i32 = new Int32Array(instance.exports.memory.buffer); + for (let i = 0; i < 8; i++) { + i32[i] = (i + 1) * 10; // lanes 0..3 = 10..40, lanes 4..7 = 50..80 + } + // Run once on Liftoff first. + instance.exports.test(1, 0); + + // Force tier-up to the optimizing compiler where revectorization runs. + %WasmTierUpFunction(instance.exports.test); + instance.exports.test(1, 0); + + const out = Array.from(i32.slice(128 / 4, 160 / 4)); + const expected = [20, 40, 60, 80, 100, 120, 140, 160]; + assertEquals(expected, out); +})(); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-v8-9106.js b/deps/v8/test/mjsunit/regress/wasm/regress-v8-9106.js index 75f72d8048b9..2a0f77863ada 100644 --- a/deps/v8/test/mjsunit/regress/wasm/regress-v8-9106.js +++ b/deps/v8/test/mjsunit/regress/wasm/regress-v8-9106.js @@ -5,18 +5,95 @@ // Make sure DCHECK doesn't fire when passive data segment is at the end of the // module. let bytes = new Uint8Array([ - 0, 97, 115, 109, 1, 0, 0, 0, 1, 132, 128, 128, 128, 0, 1, - 96, 0, 0, 3, 133, 128, 128, 128, 0, 4, 0, 0, 0, 0, 5, - 131, 128, 128, 128, 0, 1, 0, 1, 7, 187, 128, 128, 128, 0, 4, - 12, 100, 114, 111, 112, 95, 112, 97, 115, 115, 105, 118, 101, 0, 0, - 12, 105, 110, 105, 116, 95, 112, 97, 115, 115, 105, 118, 101, 0, 1, - 11, 100, 114, 111, 112, 95, 97, 99, 116, 105, 118, 101, 0, 2, 11, - 105, 110, 105, 116, 95, 97, 99, 116, 105, 118, 101, 0, 3, 12, 129, - 128, 128, 128, 0, 2, 10, 183, 128, 128, 128, 0, 4, 133, 128, 128, - 128, 0, 0, 252, 9, 0, 11, 140, 128, 128, 128, 0, 0, 65, 0, - 65, 0, 65, 0, 252, 8, 0, 0, 11, 133, 128, 128, 128, 0, 0, - 252, 9, 1, 11, 140, 128, 128, 128, 0, 0, 65, 0, 65, 0, 65, - 0, 252, 8, 1, 0, 11, 11, 136, 128, 128, 128, 0, 2, 1, 0, - 0, 65, 0, 11, 0 + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x84, 0x80, 0x80, 0x80, 0x00, // section length 4 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x00, // return count 0 + + 0x03, // section kind: Function + 0x85, 0x80, 0x80, 0x80, 0x00, // section length 5 + 0x04, // functions count 4 + 0x00, // 0 $drop_passive + 0x00, // 1 $init_passive + 0x00, // 2 $drop_active + 0x00, // 3 $init_active + + 0x05, // section kind: Memory + 0x83, 0x80, 0x80, 0x80, 0x00, // section length 3 + 0x01, 0x00, // memory count 1: no maximum + 0x01, // initial size 1 + + 0x07, // section kind: Export + 0xbb, 0x80, 0x80, 0x80, 0x00, // section length 59 + 0x04, // exports count 4 + // export # 0 + 0x0c, // field name length: 12 + 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x70, 0x61, 0x73, + 0x73, 0x69, 0x76, 0x65, // field name: drop_passive + 0x00, 0x00, // kind: function index: 0 + // export # 1 + 0x0c, // field name length: 12 + 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x70, 0x61, 0x73, + 0x73, 0x69, 0x76, 0x65, // field name: init_passive + 0x00, 0x01, // kind: function index: 1 + // export # 2 + 0x0b, // field name length: 11 + 0x64, 0x72, 0x6f, 0x70, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x65, // field name: drop_active + 0x00, 0x02, // kind: function index: 2 + // export # 3 + 0x0b, // field name length: 11 + 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x76, 0x65, // field name: init_active + 0x00, 0x03, // kind: function index: 3 + + 0x0c, // section kind: DataCount + 0x81, 0x80, 0x80, 0x80, 0x00, // section length 1 + 0x02, // data segments count 2 + + 0x0a, // section kind: Code + 0xb7, 0x80, 0x80, 0x80, 0x00, // section length 55 + 0x04, // functions count 4 + // function #0 $drop_passive + 0x85, 0x80, 0x80, 0x80, 0x00, // body size 5 + 0x00, // 0 entries in locals list + 0xfc, 0x09, 0x00, // data.drop 0 + 0x0b, // end + // function #1 $init_passive + 0x8c, 0x80, 0x80, 0x80, 0x00, // body size 12 + 0x00, // 0 entries in locals list + 0x41, 0x00, // i32.const 0 + 0x41, 0x00, // i32.const 0 + 0x41, 0x00, // i32.const 0 + 0xfc, 0x08, 0x00, 0x00, // memory.init 0 + 0x0b, // end + // function #2 $drop_active + 0x85, 0x80, 0x80, 0x80, 0x00, // body size 5 + 0x00, // 0 entries in locals list + 0xfc, 0x09, 0x01, // data.drop 1 + 0x0b, // end + // function #3 $init_active + 0x8c, 0x80, 0x80, 0x80, 0x00, // body size 12 + 0x00, // 0 entries in locals list + 0x41, 0x00, // i32.const 0 + 0x41, 0x00, // i32.const 0 + 0x41, 0x00, // i32.const 0 + 0xfc, 0x08, 0x01, 0x00, // memory.init 1 + 0x0b, // end + + 0x0b, // section kind: Data + 0x88, 0x80, 0x80, 0x80, 0x00, // section length 8 + 0x02, // data segments count 2 + 0x01, // flag: passive + 0x00, // source size 0 + // segment data + 0x00, // flag: active no index + 0x41, 0x00, 0x0b, // i32.const 0 + 0x00, // source size 0 + // segment data ]); new WebAssembly.Instance(new WebAssembly.Module(bytes)); diff --git a/deps/v8/test/mjsunit/sandbox/fixed-double-array-field-count.js b/deps/v8/test/mjsunit/sandbox/fixed-double-array-field-count.js new file mode 100644 index 000000000000..8a0af2d4d336 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/fixed-double-array-field-count.js @@ -0,0 +1,38 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --allow-natives-syntax + +const memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const read32 = address => memory.getUint32(address, true); +const write32 = (address, value) => memory.setUint32(address, value, true); + +function materialize(x) { + const object = {first: 34, second: 43}; + object.first = 2; + object.second = 12; + x++; + return object === null; +} +const sample = {first: 13, second: 46}; +%PrepareFunctionForOptimization(materialize); +for (let i = 0; i < 10; ++i) materialize(1); + +const map = read32(Sandbox.getAddressOf(sample)) - 1; +const descriptors = read32(map + 24) - 1; +const first = read32(descriptors + 20); +const second = read32(descriptors + 32); +// Capture three fields, with the two stores occupying the object header. +write32(descriptors + 20, first - (2 << 20)); +write32(descriptors + 32, second - (2 << 20)); +%OptimizeFunctionOnNextCall(materialize); +materialize(2); +write32(descriptors + 20, first); +write32(descriptors + 32, second); + +// The captured object has one element field, but claims two elements. +memory.setUint16(map + 8, + Sandbox.getInstanceTypeIdFor('FIXED_DOUBLE_ARRAY_TYPE'), true); +materialize(1.5); +assertUnreachable(); diff --git a/deps/v8/test/mjsunit/sandbox/regress-443772809.js b/deps/v8/test/mjsunit/sandbox/regress-443772809.js index d352e89303a3..0e6e7a074d41 100644 --- a/deps/v8/test/mjsunit/sandbox/regress-443772809.js +++ b/deps/v8/test/mjsunit/sandbox/regress-443772809.js @@ -18,7 +18,69 @@ const nuke_handle_from_heap_and_hope_nothing_important_is_gone = (dispatch_handl } // From test/mjsunit/sandbox/regress-430960844.js. -let spray_mod = new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 24, 2, 96, 16, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 0, 96, 1, 126, 0, 2, 15, 1, 2, 106, 115, 8, 115, 112, 114, 97, 121, 95, 99, 98, 0, 0, 3, 2, 1, 1, 7, 9, 1, 5, 115, 112, 114, 97, 121, 0, 1, 10, 38, 1, 36, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 16, 0, 11])); +let spray_mod = new WebAssembly.Module(new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x18, // section length 24 + 0x02, // types count 2 + 0x60, // kind: func + 0x10, // param count 16 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x00, // return count 0 + 0x60, // kind: func + 0x01, 0x7e, // param count 1: i64 + 0x00, // return count 0 + + 0x02, // section kind: Import + 0x0f, // section length 15 + 0x01, 0x02, // imports count 1: module name length: 2 + 0x6a, 0x73, // module name: js + 0x08, // field name length: 8 + 0x73, 0x70, 0x72, 0x61, 0x79, 0x5f, 0x63, 0x62, // field name: spray_cb + 0x00, 0x00, // kind or compact flag: function (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) + // import #0 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x01, // functions count 1: 1 $spray (param i64) + + 0x07, // section kind: Export + 0x09, // section length 9 + 0x01, // exports count 1: export # 0 + 0x05, // field name length: 5 + 0x73, 0x70, 0x72, 0x61, 0x79, // field name: spray + 0x00, 0x01, // kind: function index: 1 + + 0x0a, // section kind: Code + 0x26, // section length 38 + 0x01, // functions count 1 + // function #1 $spray + 0x24, // body size 36 + 0x00, // 0 entries in locals list + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x10, 0x00, // call $js.spray_cb + 0x0b, // end +])); let { spray } = new WebAssembly.Instance(spray_mod, { js: { spray_cb: () => { } } }).exports; // Get a clean slate. diff --git a/deps/v8/test/mjsunit/sandbox/regress-524290062.js b/deps/v8/test/mjsunit/sandbox/regress-524290062.js index 7649aaf8f545..a4ecf8ca8ba3 100644 --- a/deps/v8/test/mjsunit/sandbox/regress-524290062.js +++ b/deps/v8/test/mjsunit/sandbox/regress-524290062.js @@ -5,14 +5,43 @@ // Flags: --stress-incremental-marking --concurrent-marking-high-priority-threads const WASM_BYTES = new Uint8Array([ - 0x00,0x61,0x73,0x6d, 0x01,0x00,0x00,0x00, // magic + version - 0x01,0x04,0x01, 0x60,0x00,0x00, // type: () -> () - 0x03,0x02,0x01, 0x00, // func: 1 func of type 0 - 0x04,0x04,0x01, 0x70,0x00,0x01, // table: funcref, min=1 - 0x07,0x09,0x02, // export: 2 exports - 0x01,0x74, 0x01,0x00, // "t" -> table 0 - 0x01,0x66, 0x00,0x00, // "f" -> func 0 - 0x0a,0x04,0x01, 0x02,0x00,0x0b // code: empty body + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x04, // section length 4 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x00, // return count 0 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $f + + 0x04, // section kind: Table + 0x04, // section length 4 + 0x01, 0x70, 0x00, // table count 1: funcref no maximum + 0x01, // initial size 1 + + 0x07, // section kind: Export + 0x09, // section length 9 + 0x02, // exports count 2 + // export # 0 + 0x01, // field name length: 1 + 0x74, // field name: t + 0x01, 0x00, // kind: table index: 0 + // export # 1 + 0x01, // field name length: 1 + 0x66, // field name: f + 0x00, 0x00, // kind: function index: 0 + + 0x0a, // section kind: Code + 0x04, // section length 4 + 0x01, // functions count 1 + // function #0 $f + 0x02, // body size 2 + 0x00, // 0 entries in locals list + 0x0b, // end ]); const module = new WebAssembly.Module(WASM_BYTES); diff --git a/deps/v8/test/mjsunit/sandbox/regress-558640961.js b/deps/v8/test/mjsunit/sandbox/regress-558640961.js new file mode 100644 index 000000000000..e1f6098e7ce8 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-558640961.js @@ -0,0 +1,101 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +const kNumFields = 9999; +let $struct = + builder.addStruct(new Array(kNumFields).fill(makeField(kWasmI64, true))); +let $sig_struct = builder.addType(makeSig([], [wasmRefType($struct)])); +let $sig_any = builder.addType(makeSig([], [kWasmAnyRef])); +let $box = builder.addStruct([makeField(kWasmFuncRef, true)]); + +let $f_struct = builder.addFunction('f_struct', $sig_struct) + .exportFunc() + .addBody([ + kGCPrefix, + kExprStructNewDefault, + $struct, + ]); +let $f_any = builder.addFunction('f_any', $sig_any) + .exportFunc() + .addBody([ + ...wasmI32Const(0x7fffffff), + kGCPrefix, + kExprRefI31, + ]); +builder.addFunction('get_struct_fref', kSig_r_v) + .exportFunc() + .addBody([ + kExprRefFunc, + $f_struct.index, + kGCPrefix, + kExprStructNew, + $box, + kGCPrefix, + kExprExternConvertAny, + ]); +builder.addFunction('get_any_fref', kSig_r_v) + .exportFunc() + .addBody([ + kExprRefFunc, + $f_any.index, + kGCPrefix, + kExprStructNew, + $box, + kGCPrefix, + kExprExternConvertAny, + ]); +builder.addFunction('boom', makeSig([kWasmFuncRef, kWasmI64], [])) + .exportFunc() + .addBody([ + kExprLocalGet, + 0, + kGCPrefix, + kExprRefCast, + $sig_struct, + kExprCallRef, + $sig_struct, + kExprLocalGet, + 1, + kGCPrefix, + kExprStructSet, + $struct, + ...wasmUnsignedLeb(kNumFields - 1), + ]); + +let instance = builder.instantiate(); +let {boom, get_struct_fref, get_any_fref, f_struct} = instance.exports; + +const kHeapObjectTag = 1; +const kStructField0Offset = 8; +const kWasmFuncRefType = Sandbox.getInstanceTypeIdFor('WASM_FUNC_REF_TYPE'); +const kWasmFuncRefInternalOffset = + Sandbox.getFieldOffset(kWasmFuncRefType, 'trusted_internal'); + +let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +function getPtr(obj) { + return Sandbox.getAddressOf(obj) + kHeapObjectTag; +} +function getField(obj, offset) { + return memory.getUint32(obj + offset - kHeapObjectTag, true); +} +function setField(obj, offset, value) { + memory.setUint32(obj + offset - kHeapObjectTag, value, true); +} + +let struct_box = getPtr(get_struct_fref()); +let struct_fref = getField(struct_box, kStructField0Offset); + +let any_box = getPtr(get_any_fref()); +let any_fref = getField(any_box, kStructField0Offset); +let any_int = getField(any_fref, kWasmFuncRefInternalOffset); + +// Swap struct_fref's trusted_internal to point to any_int (f_any) +setField(struct_fref, kWasmFuncRefInternalOffset, any_int); + +boom(f_struct, 0x41414141n); diff --git a/deps/v8/test/mjsunit/sandbox/regress-560980980.js b/deps/v8/test/mjsunit/sandbox/regress-560980980.js new file mode 100644 index 000000000000..c40ac0598f09 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-560980980.js @@ -0,0 +1,52 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --allow-natives-syntax + +function makeClass() { + class C { + m() {} + } + return C; +} + +%PrepareFunctionForOptimization(makeClass); +makeClass(); + +// Retrieve the ClassBoilerplate from the bytecode constant pool. +const bytecode = %GetBytecode(makeClass); +const kClassBoilerplateType = + Sandbox.getInstanceTypeIdFor("CLASS_BOILERPLATE_TYPE"); +let boilerplate = null; +for (let i = 0; i < bytecode.constant_pool.length; i++) { + const elem = bytecode.constant_pool[i]; + if (Sandbox.getInstanceTypeOf(elem) === "CLASS_BOILERPLATE_TYPE") { + boilerplate = elem; + break; + } +} +assertTrue(boilerplate !== null); + +const kInstancePropsOffset = Sandbox.getFieldOffset( + kClassBoilerplateType, "instance_properties_template"); +const template = + Sandbox.dereferenceTaggedPointerField(boilerplate, kInstancePropsOffset); +assertTrue(template !== null); + +// The dynamic method argument index for `m` is Smi(3) (raw value 6). +// Corrupt it to Smi(4) (raw value 8) which equals args.length(). +let found = false; +for (let offset = 0; offset < Sandbox.getSizeOf(template); offset += 4) { + if (Sandbox.readObjectField(template, offset) === (3 << 1)) { + Sandbox.corruptObjectField(template, offset, 4 << 1); + found = true; + break; + } +} +assertTrue(found); + +// Re-executing makeClass() must safely abort via SBXCHECK_LT. +makeClass(); + +assertUnreachable("Argument index out of bounds should be trapped by SBXCHECK"); diff --git a/deps/v8/test/mjsunit/sandbox/regress-561387542.js b/deps/v8/test/mjsunit/sandbox/regress-561387542.js index ad17ca49b283..add49e4a02db 100644 --- a/deps/v8/test/mjsunit/sandbox/regress-561387542.js +++ b/deps/v8/test/mjsunit/sandbox/regress-561387542.js @@ -16,11 +16,33 @@ const innerFunc = outer(); const wasmTable = new WebAssembly.Table({ initial: 2, element: "anyfunc" }); const wasmBytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // wasm magic & version - 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, // type section: () -> () - 0x03, 0x02, 0x01, 0x00, // func section - 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, // export section: export "f" - 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b // code section: empty function + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x04, // section length 4 + 0x01, 0x60, // types count 1: kind: func + 0x00, // param count 0 + 0x00, // return count 0 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $f + + 0x07, // section kind: Export + 0x05, // section length 5 + 0x01, // exports count 1: export # 0 + 0x01, // field name length: 1 + 0x66, // field name: f + 0x00, 0x00, // kind: function index: 0 + + 0x0a, // section kind: Code + 0x04, // section length 4 + 0x01, // functions count 1 + // function #0 $f + 0x02, // body size 2 + 0x00, // 0 entries in locals list + 0x0b, // end ]); const wasmModule = new WebAssembly.Module(wasmBytes); const wasmInstance = new WebAssembly.Instance(wasmModule); diff --git a/deps/v8/test/mjsunit/sandbox/regress-564835629.js b/deps/v8/test/mjsunit/sandbox/regress-564835629.js new file mode 100644 index 000000000000..90b748df0729 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-564835629.js @@ -0,0 +1,16 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --cache=after-execute + +function target() { + const arr = [1, 2, 3]; + const sandboxMemory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); + const arrAddress = Sandbox.getAddressOf(arr); + const elementsAddress = sandboxMemory.getUint32(arrAddress + 8, true) - 1; + const kSmiMinusOne = (-1 << 1) >>> 0; + sandboxMemory.setUint32(elementsAddress + 4, kSmiMinusOne, true); +} + +target(); diff --git a/deps/v8/test/mjsunit/sandbox/regress-564835816.js b/deps/v8/test/mjsunit/sandbox/regress-564835816.js new file mode 100644 index 000000000000..a94c19aea705 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-564835816.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --expose-externalize-string --cache=after-execute + +let s = createExternalizableString("A".repeat(32)); +externalizeString(s, true); +let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +let s_addr = Sandbox.getAddressOf(s); + +function target() { return 1; } +target(); + +let sfi = memory.getUint32(Sandbox.getAddressOf(target) + 16, true) - 1; +let script = memory.getUint32(sfi + 20, true) - 1; +// Attach external string s to script.source_mapping_url_ (offset 64) +memory.setUint32(script + 64, s_addr + 1, true); + +// Corrupt length of ExternalString s from 32 to 100000: +memory.setInt32(s_addr + 8, 100000, true); diff --git a/deps/v8/test/mjsunit/sandbox/regress-566142291.js b/deps/v8/test/mjsunit/sandbox/regress-566142291.js new file mode 100644 index 000000000000..1cf7a1257d0f --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-566142291.js @@ -0,0 +1,75 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --cache=after-execute + +function target() {} +target(); + +let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +let target_addr = Sandbox.getAddressOf(target); +let sfi_addr = (memory.getUint32(target_addr + 16, true) - 1) & 0xffffffff; + +let fixed_array_map = 0x5dd; +let byte_array_map = 0x9ad; +let swiss_map = 0xc5d; + +// Allocate carrier arrays +let carrier_dict1 = new Array(64); +let dict1_addr = (memory.getUint32(Sandbox.getAddressOf(carrier_dict1) + 8, true) - 1) & 0xffffffff; + +let carrier_ba1 = new Array(64); +let ba1_addr = (memory.getUint32(Sandbox.getAddressOf(carrier_ba1) + 8, true) - 1) & 0xffffffff; + +let carrier_ba2 = new Array(256); +let ba2_addr = (memory.getUint32(Sandbox.getAddressOf(carrier_ba2) + 8, true) - 1) & 0xffffffff; + +let carrier_fa = new Array(256); +let fa_addr = (memory.getUint32(Sandbox.getAddressOf(carrier_fa) + 8, true) - 1) & 0xffffffff; + +// Zero carrier buffers +for (let i = 0; i < 256; i += 4) memory.setUint32(dict1_addr + i, 0, true); +for (let i = 0; i < 256; i += 4) memory.setUint32(ba1_addr + i, 0, true); +for (let i = 0; i < 512; i += 4) memory.setUint32(ba2_addr + i, 0, true); +for (let i = 0; i < 512; i += 4) memory.setUint32(fa_addr + i, 0, true); + +// Setup meta table ByteArray for dict1 +memory.setUint32(ba1_addr + 0, byte_array_map, true); +memory.setUint32(ba1_addr + 4, 16, true); + +// Setup payload carrier ByteArray (ba2) +memory.setUint32(ba2_addr + 0, byte_array_map, true); +memory.setUint32(ba2_addr + 4, 256, true); + +// Format SwissNameDictionary (capacity = 1 -> unaligned SizeFor = 42 bytes -> 2 leftover bytes) +memory.setUint32(dict1_addr + 0, swiss_map, true); +memory.setUint32(dict1_addr + 4, 0, true); // hash +memory.setUint32(dict1_addr + 8, 1, true); // capacity = 1 +memory.setUint32(dict1_addr + 12, ba1_addr + 1, true); // meta_table -> ba1 + +// Stream desynchronization via leftover bytes at dict1 offset 40, 41: +// Opcode 0x11 (kVariableRawData) consuming 3 tagged words (12 bytes) +// to skip the ByteArray serialization header of ba2. +memory.setUint8(dict1_addr + 40, 0x11); +memory.setUint8(dict1_addr + 41, 0x0c); // (3 << 2) | 0 = 12 + +// Construct synthetic deserializer byte stream inside ba2 payload: +let p = ba2_addr + 8; +memory.setUint8(p + 0, 0x00); // 12th skipped byte + +// Bytecode: kOffHeapBackingStore (0x0d) +memory.setUint8(p + 1, 0x0d); +// byte_length: 65536 bytes (0x00010000) +// Deserializer allocates 64KB backing store and triggers unchecked memcpy +// beyond the end of the host heap snapshot buffer (CopyRaw). +memory.setUint32(p + 2, 65536, true); + +// Format FixedArray linking dict1 and ba2 +memory.setUint32(fa_addr + 0, fixed_array_map, true); +memory.setUint32(fa_addr + 4, 91 << 1, true); // length = Smi(91) +memory.setUint32(fa_addr + 8, dict1_addr + 1, true); // elements[0] = dict1 +memory.setUint32(fa_addr + 12, ba2_addr + 1, true); // elements[1] = ba2 + +// Attach corrupted FixedArray to target function SFI untrusted_function_data +memory.setUint32(sfi_addr + 8, fa_addr + 1, true); diff --git a/deps/v8/test/mjsunit/sandbox/regress-567222739.js b/deps/v8/test/mjsunit/sandbox/regress-567222739.js new file mode 100644 index 000000000000..7a6056d569d3 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-567222739.js @@ -0,0 +1,37 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --sandbox-testing --sparkplug --sparkplug-plus + +const memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const field = (type, name) => + Sandbox.getFieldOffset(Sandbox.getInstanceTypeIdFor(type), name); +const read32 = p => memory.getUint32(p, true); +const write32 = (p, value) => memory.setUint32(p, value, true); + +const cell_offset = field('JS_FUNCTION_TYPE', 'feedback_cell'); +const value_offset = field('FEEDBACK_CELL_TYPE', 'value'); +const data_offset = field('FEEDBACK_VECTOR_TYPE', 'data'); +const get_vector = fn => + read32(read32(Sandbox.getAddressOf(fn) + cell_offset) - 1 + value_offset) - + 1; + +function test_corrupted_offset(handler_smi) { + const fn = eval(`(function(o) { return o.value; })`); + const object = {value: 42}; + %CompileBaseline(fn); + %PrepareFunctionForOptimization(fn); + + const slot = get_vector(fn) + data_offset; + write32(slot, read32(Sandbox.getAddressOf(object)) | 2); + write32(slot + 4, handler_smi); + + assertEquals(42, fn(object)); +} + +// Forged Smi LoadHandler: non-double in-object field at word offset 0. +test_corrupted_offset(2 * ((1 << 17) | 5)); + +// Forged Smi LoadHandler: non-double property-array field at word offset 0. +test_corrupted_offset(2 * 5); diff --git a/deps/v8/test/mjsunit/sandbox/regress-569548220.js b/deps/v8/test/mjsunit/sandbox/regress-569548220.js new file mode 100644 index 000000000000..b8f340131a2e --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-569548220.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --trace-gc-object-stats --sandbox-testing + +const memory = new DataView(new Sandbox.MemoryView(0, 2**32)); +function setupFakeBytecodeArray() { + const fakeObj = new Array().fill(); + const fakeAddr = Sandbox.getAddressOf(fakeObj); + for (let addr = 0x800; addr < 0x10000; addr += 4) { + if (Sandbox.getInstanceTypeOfObjectAt(addr) === "MAP_TYPE") { + memory.setUint32(fakeAddr, addr | 1, true); + if (Sandbox.getInstanceTypeOfObjectAt(fakeAddr) === "BYTECODE_ARRAY_TYPE") { + break; + } + } + } +} +setupFakeBytecodeArray(); +gc(); diff --git a/deps/v8/test/mjsunit/sandbox/regress-571126471.js b/deps/v8/test/mjsunit/sandbox/regress-571126471.js new file mode 100644 index 000000000000..e0dd215ec595 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-571126471.js @@ -0,0 +1,69 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing + +const memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); + +const offsetOf = (object, field) => + Sandbox.getFieldOffset(Sandbox.getInstanceTypeIdOf(object), field); +const jsFuncSfiOffset = offsetOf(function() {}, 'shared_function_info'); + +// Create a lazy async function with an inner skippable function so V8 attaches +// an on-heap PreparseData object in the sandbox. +const bodyPadding = ' '.repeat(2 ** 11); +const origSource = + `async function victim() { let x = 1; function skip_me() { return x; } ${bodyPadding} }`; +(0, eval)(origSource); + +const target = globalThis.victim; +const targetAddr = Sandbox.getAddressOf(target); +const sfiAddr = memory.getUint32(targetAddr + jsFuncSfiOffset, true) - 1; +const sfi = Sandbox.getObjectAt(sfiAddr); +const script = Sandbox.dereferenceTaggedPointerField(sfi, 'script'); + +// PreparseData is allocated immediately after victim's SharedFunctionInfo. +const preparseDataAddr = sfiAddr + 0x30; + +const prefix = 'async function victim() { /* '; +const commentCode = '}) ) => { await 0; })(); } */ '; +const awaits = Array.from({length: 64}, () => 'await 1').join(' + '); +const middle = `(async (a = ${awaits}, (b = function skip_me`; +const suffix = '() {})) => {})() }'; + +const targetBracePos = prefix.length; +const skipMeStartPos = (prefix + commentCode + middle).length; +const newSource = + (prefix + commentCode + middle + suffix).padEnd(origSource.length, ' '); + +function encodeVarint32(val) { + const out = []; + do { + let b = val & 0x7f; + val >>>= 7; + if (val) b |= 0x80; + out.push(b); + } while (val); + return out; +} + +const newPreparseBytes = [ + ...encodeVarint32(skipMeStartPos), + ...encodeVarint32(targetBracePos + 1), + ...encodeVarint32(2), + ...encodeVarint32(0), + 0, 0, 0, 0, 0, +]; + +memory.setInt32(preparseDataAddr + 4, newPreparseBytes.length, true); +for (let i = 0; i < newPreparseBytes.length; i++) { + memory.setUint8(preparseDataAddr + 12 + i, newPreparseBytes[i]); +} + +const scriptPosition = offsetOf(script, 'wasm_managed_native_module'); +const scriptSourceOffset = scriptPosition - 36; +const tagged = obj => (Sandbox.getAddressOf(obj) + 1) >>> 0; +Sandbox.corruptObjectField(script, scriptSourceOffset, tagged(newSource), 32); + +target(); diff --git a/deps/v8/test/mjsunit/sandbox/regress-571127829.js b/deps/v8/test/mjsunit/sandbox/regress-571127829.js new file mode 100644 index 000000000000..2cccacc98027 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress-571127829.js @@ -0,0 +1,125 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --allow-natives-syntax --expose-gc + +const kNumVictims = 40; +const kNumAwaits = 8; +const kDelayStatements = '1;'.repeat(500); +const kAwaitStatements = 'await 1;'.repeat(kNumAwaits); +const kSeqTwoByteHeaderSize = 12; + +function buildSources(count) { + const origParts = ['/*\u0100 */']; + const replParts = ['/*\u0100 */']; + for (let i = 0; i < count; i++) { + const body = + `let f = async function inner() { ` + + `await using x = null; ${kAwaitStatements} ${kDelayStatements} ` + + `let y = 1; let z_${i} = 2; }();`; + const placeholder = '()=>0;' + ' '.repeat(body.length - 6); + origParts.push(`function victim_${i}() { ${placeholder} }\n`); + replParts.push(`function victim_${i}() { ${body} }\n`); + } + const origSrc = origParts.join(''); + const replSrc = replParts.join(''); + origSrc.indexOf('___'); + replSrc.indexOf('___'); + return {origSrc, replSrc}; +} + +const {origSrc, replSrc} = buildSources(kNumVictims); +(0, eval)(origSrc); + +const memory = new DataView(new Sandbox.MemoryView(0, 2 ** 32)); +const offsetOf = (object, field) => + Sandbox.getFieldOffset(Sandbox.getInstanceTypeIdOf(object), field); +const fieldOffset = (typeName, field) => + Sandbox.getFieldOffset(Sandbox.getInstanceTypeIdFor(typeName), field); + +gc(); +gc(); + +let replSeqAddr = Sandbox.getAddressOf(replSrc); +if (Sandbox.getInstanceTypeOf(replSrc).startsWith('CONS_')) { + replSeqAddr = + memory.getUint32(replSeqAddr + offsetOf(replSrc, 'first'), true) - 1; +} + +const victimAddr = Sandbox.getAddressOf(globalThis.victim_0); +const sfiAddr = + memory.getUint32( + victimAddr + offsetOf(globalThis.victim_0, 'shared_function_info'), + true) - + 1; +const scriptAddr = + memory.getUint32( + sfiAddr + fieldOffset('SHARED_FUNCTION_INFO_TYPE', 'script'), true) - + 1; +const scriptSourceOffset = + fieldOffset('SCRIPT_TYPE', 'wasm_managed_native_module') - 36; + +memory.setUint32( + scriptAddr + scriptSourceOffset, (replSeqAddr + 1) >>> 0, true); + +const sourceAddr = replSeqAddr; +const syncByteOffset = sourceAddr + kSeqTwoByteHeaderSize + 4; +const readyByteOffset = sourceAddr + kSeqTwoByteHeaderSize + 6; + +const targetOffsets = []; +for (let i = 0; i < kNumVictims; i++) { + const charIndex = replSrc.indexOf(`let z_${i} = 2`) + 4; + const byteOffset = sourceAddr + kSeqTwoByteHeaderSize + charIndex * 2; + memory.setUint16(byteOffset, 0x79, true); + const tokenLength = (`z_${i}`).length; + for (let j = 1; j < tokenLength; j++) { + memory.setUint16(byteOffset + j * 2, 0x20, true); + } + targetOffsets.push(byteOffset); +} + +function workerMain() { + const dv = new DataView(new Sandbox.MemoryView(0, 2 ** 32)); + function spin(offsets, syncOffset, readyOffset) { + dv.setUint16(readyOffset, 1, true); + while (true) { + const idx = dv.getUint16(syncOffset, true); + if (idx >= offsets.length) break; + const off = offsets[idx]; + dv.setUint16(off, 0x79, true); + dv.setUint16(off, 0x79, true); + dv.setUint16(off, 0x79, true); + dv.setUint16(off, 0x79, true); + dv.setUint16(off, 0x7a, true); + } + } + %NeverOptimizeFunction(spin); + onmessage = function(e) { + const {offsets, syncOffset, readyOffset} = e.data; + spin(offsets, syncOffset, readyOffset); + }; +} + +memory.setUint16(syncByteOffset, 0, true); +memory.setUint16(readyByteOffset, 0, true); + +const worker = new Worker(workerMain, {type: 'function'}); +worker.postMessage({ + offsets: targetOffsets, + syncOffset: syncByteOffset, + readyOffset: readyByteOffset, +}); +while (memory.getUint16(readyByteOffset, true) === 0) {} + +for (let i = 0; i < kNumVictims; i++) { + memory.setUint16(syncByteOffset, i, true); + for (let attempt = 0; attempt < 200; attempt++) { + try { + globalThis[`victim_${i}`](); + break; + } catch (e) { + } + } +} +memory.setUint16(syncByteOffset, kNumVictims, true); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-435630464-disabled.js b/deps/v8/test/mjsunit/sandbox/regress/regress-435630464-disabled.js index dec317643310..d5a6ba98040c 100644 --- a/deps/v8/test/mjsunit/sandbox/regress/regress-435630464-disabled.js +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-435630464-disabled.js @@ -8,8 +8,8 @@ const builtin_names = Sandbox.getBuiltinNames(); var f0 = BigInt; // constructor with kDontAdaptArgumentsSentinel. -Sandbox.setFunctionCodeToBuiltin(f0, builtin_names.indexOf("SharedStructTypeConstructor")); -// If this test starts to fail because we shipped --harmony-struct, the test -// must be updated to use a builtin belonging to some other not-yet shipped -// feature. +// ConstructFunction is used as a dummy (intentionally classified as +// DisabledFlagDependent). See Builtins::GetJSBuiltinState(). +Sandbox.setFunctionCodeToBuiltin( + f0, builtin_names.indexOf('ConstructFunction')); assertUnreachable(); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-462217236.js b/deps/v8/test/mjsunit/sandbox/regress/regress-462217236.js index 18fe24349795..78261e7d6174 100644 --- a/deps/v8/test/mjsunit/sandbox/regress/regress-462217236.js +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-462217236.js @@ -18,7 +18,69 @@ const getField = (obj, offset) => memory.getUint32(getPtr(obj) + offset - kHeapO const setField = (obj, offset, value) => memory.setUint32(getPtr(obj) + offset - kHeapObjectTag, value, true); // from test/mjsunit/sandbox/regress-430960844.js -let spray_mod = new WebAssembly.Module(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 24, 2, 96, 16, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 0, 96, 1, 126, 0, 2, 15, 1, 2, 106, 115, 8, 115, 112, 114, 97, 121, 95, 99, 98, 0, 0, 3, 2, 1, 1, 7, 9, 1, 5, 115, 112, 114, 97, 121, 0, 1, 10, 38, 1, 36, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 16, 0, 11])); +let spray_mod = new WebAssembly.Module(new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x18, // section length 24 + 0x02, // types count 2 + 0x60, // kind: func + 0x10, // param count 16 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x7e, 0x7e, 0x7e, 0x7e, // i64 i64 i64 i64 + 0x00, // return count 0 + 0x60, // kind: func + 0x01, 0x7e, // param count 1: i64 + 0x00, // return count 0 + + 0x02, // section kind: Import + 0x0f, // section length 15 + 0x01, 0x02, // imports count 1: module name length: 2 + 0x6a, 0x73, // module name: js + 0x08, // field name length: 8 + 0x73, 0x70, 0x72, 0x61, 0x79, 0x5f, 0x63, 0x62, // field name: spray_cb + 0x00, 0x00, // kind or compact flag: function (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) + // import #0 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x01, // functions count 1: 1 $spray (param i64) + + 0x07, // section kind: Export + 0x09, // section length 9 + 0x01, // exports count 1: export # 0 + 0x05, // field name length: 5 + 0x73, 0x70, 0x72, 0x61, 0x79, // field name: spray + 0x00, 0x01, // kind: function index: 1 + + 0x0a, // section kind: Code + 0x26, // section length 38 + 0x01, // functions count 1 + // function #1 $spray + 0x24, // body size 36 + 0x00, // 0 entries in locals list + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x20, 0x00, // local.get $var0 + 0x10, 0x00, // call $js.spray_cb + 0x0b, // end +])); let { spray } = new WebAssembly.Instance(spray_mod, { js: { spray_cb: () => { } } }).exports; // get a clean slate diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-502337304.js b/deps/v8/test/mjsunit/sandbox/regress/regress-502337304.js deleted file mode 100644 index eaaea1f38bd5..000000000000 --- a/deps/v8/test/mjsunit/sandbox/regress/regress-502337304.js +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --expose-memory-corruption-api -// Flags: --sandbox-testing --fuzzing - -const NUM_PARAMS = 60000; -let paramTail = ''; -for (let i = 0; i < NUM_PARAMS; i++) paramTail += ',p' + i; -const padLen = paramTail.length; -const head = 'function victim(a'; -const tail = '){debugger;}'; -const origSource = head + '/*' + 'X'.repeat(padLen - 4) + '*/' + tail; -const corruptSource = head + paramTail + tail; - -// Indirect eval to get a Script object -(0, eval)(origSource); - -let callFrameId = null; -let step = 0; - -function receive(msg) { - let obj = JSON.parse(msg); - if (obj.method === "Debugger.paused") { - callFrameId = obj.params.callFrames[0].callFrameId; - } -} - -function handleInspectorMessage() { - if (step === 0) { - if (!callFrameId) return; - corrupt(); - step = 1; - send(JSON.stringify({ - id: 3, - method: "Debugger.setVariableValue", - params: { - scopeNumber: 0, - variableName: "p59999", - newValue: { value: 42 }, - callFrameId: callFrameId - } - })); - } else if (step === 1) { - send(JSON.stringify({ - id: 4, - method: "Debugger.resume" - })); - step = 2; - } else { - quit(); - } -} - -function corrupt() { - if (typeof Sandbox === 'undefined') return; - - let victim_addr = Sandbox.getAddressOf(victim); - let view = new DataView(new Sandbox.MemoryView(victim_addr, 32)); - let sfi_ptr = view.getUint32(16, true); - let sfi_addr = sfi_ptr - 1; - - let sfi_view = new DataView(new Sandbox.MemoryView(sfi_addr, 32)); - let script_ptr = sfi_view.getUint32(20, true); - let script_addr = script_ptr - 1; - - let script_view = new DataView(new Sandbox.MemoryView(script_addr, 32)); - let corrupt_source_addr = Sandbox.getAddressOf(corruptSource); - script_view.setUint32(4, corrupt_source_addr | 1, true); -} - -send(JSON.stringify({ id: 1, method: "Runtime.enable" })); -send(JSON.stringify({ id: 2, method: "Debugger.enable" })); - -victim(1); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-502997649.js b/deps/v8/test/mjsunit/sandbox/regress/regress-502997649.js index 9b4529f142fb..911bbe110104 100644 --- a/deps/v8/test/mjsunit/sandbox/regress/regress-502997649.js +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-502997649.js @@ -14,9 +14,36 @@ const WASM_MODULE_OBJECT_TYPE = Sandbox.getInstanceTypeIdFor('WASM_MODULE_OBJECT const SCRIPT_TYPE = Sandbox.getInstanceTypeIdFor('SCRIPT_TYPE'); const kWasmBytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, - 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, - 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x0b + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x06, // section length 6 + 0x01, 0x60, // types count 1: kind: func + 0x01, 0x7f, // param count 1: i32 + 0x01, 0x7f, // return count 1: i32 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x00, // functions count 1: 0 $f (param i32) (result i32) + + 0x07, // section kind: Export + 0x05, // section length 5 + 0x01, // exports count 1: export # 0 + 0x01, // field name length: 1 + 0x66, // field name: f + 0x00, 0x00, // kind: function index: 0 + + 0x0a, // section kind: Code + 0x09, // section length 9 + 0x01, // functions count 1 + // function #0 $f + 0x07, // body size 7 + 0x00, // 0 entries in locals list + 0x20, 0x00, // local.get $var0 + 0x41, 0x01, // i32.const 1 + 0x6a, // i32.add + 0x0b, // end ]); let mod = new WebAssembly.Module(kWasmBytes); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-514163419.js b/deps/v8/test/mjsunit/sandbox/regress/regress-514163419.js index daca123cb982..06e4c08957bd 100644 --- a/deps/v8/test/mjsunit/sandbox/regress/regress-514163419.js +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-514163419.js @@ -9,8 +9,13 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); // Pad trusted-space so the next trusted allocation (our table) lands on // an evacuatable page. const bigTableBytes = new Uint8Array([ - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x05, 0x01, 0x70, 0x00, 0xc0, 0x3e + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x04, // section kind: Table + 0x05, // section length 5 + 0x01, 0x70, 0x00, // table count 1: funcref no maximum + 0xc0, 0x3e, // initial size 8000 ]); const bigModule = new WebAssembly.Module(bigTableBytes); var prePad = []; diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-543557673.js b/deps/v8/test/mjsunit/sandbox/regress/regress-543557673.js index ddf0591c099c..e4ad8d6bb5bd 100644 --- a/deps/v8/test/mjsunit/sandbox/regress/regress-543557673.js +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-543557673.js @@ -5,29 +5,200 @@ // Flags: --sandbox-testing --allow-natives-syntax const moduleABytes = new Uint8Array([ - 0, 97, 115, 109, 1, 0, 0, 0, 1, 22, 5, 96, 0, 1, 127, - 96, 1, 111, 0, 96, 0, 1, 111, 96, 1, 127, 1, 127, 96, 0, - 1, 127, 2, 27, 2, 1, 109, 9, 102, 117, 110, 99, 116, 105, 111, - 110, 115, 1, 112, 1, 1, 1, 1, 109, 3, 116, 97, 103, 4, 0, - 1, 3, 3, 2, 3, 4, 4, 5, 1, 105, 1, 1, 1, 6, 32, - 6, 127, 1, 65, 239, 0, 11, 127, 1, 65, 0, 11, 127, 1, 65, - 0, 11, 127, 1, 65, 0, 11, 127, 1, 65, 0, 11, 127, 1, 65, - 0, 11, 7, 30, 3, 10, 101, 120, 99, 101, 112, 116, 105, 111, 110, - 115, 1, 1, 6, 100, 114, 105, 118, 101, 114, 0, 0, 4, 115, 101, - 101, 100, 0, 1, 10, 48, 2, 41, 0, 65, 0, 17, 0, 0, 26, - 32, 0, 4, 64, 2, 2, 31, 2, 1, 0, 0, 0, 65, 0, 37, - 1, 10, 11, 11, 26, 65, 0, 36, 5, 65, 0, 17, 0, 0, 15, - 11, 65, 0, 11, 4, 0, 65, 7, 11, 0, 22, 4, 110, 97, 109, - 101, 1, 15, 2, 0, 6, 100, 114, 105, 118, 101, 114, 1, 4, 115, - 101, 101, 100, + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x16, // section length 22 + 0x05, // types count 5 + 0x60, // type #0 $type0 kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + 0x60, // type #1 $type1 kind: func + 0x01, 0x6f, // param count 1: externref + 0x00, // return count 0 + 0x60, // type #2 $type2 kind: func + 0x00, // param count 0 + 0x01, 0x6f, // return count 1: externref + 0x60, // type #3 $type3 kind: func + 0x01, 0x7f, // param count 1: i32 + 0x01, 0x7f, // return count 1: i32 + 0x60, // type #4 $type4 kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + + 0x02, // section kind: Import + 0x1b, // section length 27 + 0x02, // imports count 2 + 0x01, // module name length: 1 + 0x6d, // module name: m + 0x09, // field name length: 9 + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, // field name: functions + 0x01, 0x70, 0x01, // kind or compact flag: table funcref with maximum + 0x01, // initial size 1 + 0x01, // maximum size 1 + // import #0 + 0x01, // module name length: 1 + 0x6d, // module name: m + 0x03, // field name length: 3 + 0x74, 0x61, 0x67, // field name: tag + 0x04, 0x00, 0x01, // kind or compact flag: tag (param externref) + // import #1 + + 0x03, // section kind: Function + 0x03, // section length 3 + 0x02, // functions count 2 + 0x03, // 0 $driver (param i32) (result i32) + 0x04, // 1 $seed (result i32) + + 0x04, // section kind: Table + 0x05, // section length 5 + 0x01, 0x69, 0x01, // table count 1: exnref with maximum + 0x01, // initial size 1 + 0x01, // maximum size 1 + + 0x06, // section kind: Global + 0x20, // section length 32 + 0x06, // globals count 6 + 0x7f, 0x01, // global #0: i32 mutable + 0x41, 0xef, 0x00, 0x0b, // i32.const 111 + 0x7f, 0x01, // global #1: i32 mutable + 0x41, 0x00, 0x0b, // i32.const 0 + 0x7f, 0x01, // global #2: i32 mutable + 0x41, 0x00, 0x0b, // i32.const 0 + 0x7f, 0x01, // global #3: i32 mutable + 0x41, 0x00, 0x0b, // i32.const 0 + 0x7f, 0x01, // global #4: i32 mutable + 0x41, 0x00, 0x0b, // i32.const 0 + 0x7f, 0x01, // global #5: i32 mutable + 0x41, 0x00, 0x0b, // i32.const 0 + + 0x07, // section kind: Export + 0x1e, // section length 30 + 0x03, // exports count 3 + // export # 0 + 0x0a, // field name length: 10 + 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, // field name: exceptions + 0x01, 0x01, // kind: table index: 1 + // export # 1 + 0x06, // field name length: 6 + 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, // field name: driver + 0x00, 0x00, // kind: function index: 0 + // export # 2 + 0x04, // field name length: 4 + 0x73, 0x65, 0x65, 0x64, // field name: seed + 0x00, 0x01, // kind: function index: 1 + + 0x0a, // section kind: Code + 0x30, // section length 48 + 0x02, // functions count 2 + // function #0 $driver + 0x29, // body size 41 + 0x00, // 0 entries in locals list + 0x41, 0x00, // i32.const 0 + 0x11, 0x00, 0x00, // call_indirect (result i32) + 0x1a, // drop + 0x20, 0x00, // local.get $var0 + 0x04, 0x40, // if + 0x02, 0x02, // block (result externref) $label0 + 0x1f, 0x02, 0x01, 0x00, 0x00, 0x00, // try_table (result externref) catch $m.tag $label0 + 0x41, 0x00, // i32.const 0 + 0x25, 0x01, // table.get $exceptions + 0x0a, // throw_ref + 0x0b, // end $label0 + 0x0b, // end + 0x1a, // drop + 0x41, 0x00, // i32.const 0 + 0x24, 0x05, // global.set $global5 + 0x41, 0x00, // i32.const 0 + 0x11, 0x00, 0x00, // call_indirect (result i32) + 0x0f, // return + 0x0b, // end + 0x41, 0x00, // i32.const 0 + 0x0b, // end + // function #1 $seed + 0x04, // body size 4 + 0x00, // 0 entries in locals list + 0x41, 0x07, // i32.const 7 + 0x0b, // end + + 0x00, // section kind: Unknown + 0x16, // section length 22 + 0x04, // section name length: 4 + 0x6e, 0x61, 0x6d, 0x65, // section name: name + 0x01, // name type: function + 0x0f, // payload length: 15 + 0x02, // names count 2 + 0x00, 0x06, // index 0 name length: 6 + 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, // name: driver + 0x01, 0x04, // index 1 name length: 4 + 0x73, 0x65, 0x65, 0x64, // name: seed ]); const moduleDBytes = new Uint8Array([ - 0, 97, 115, 109, 1, 0, 0, 0, 1, 13, 3, 96, 0, 1, 127, - 96, 0, 1, 127, 96, 0, 1, 127, 3, 4, 3, 0, 1, 2, 7, - 10, 1, 6, 116, 97, 114, 103, 101, 116, 0, 2, 10, 17, 3, 4, - 0, 65, 0, 11, 4, 0, 65, 1, 11, 5, 0, 65, 222, 1, 11, - 0, 28, 4, 110, 97, 109, 101, 1, 21, 3, 0, 4, 112, 97, 100, - 48, 1, 4, 112, 97, 100, 49, 2, 6, 116, 97, 114, 103, 101, 116 + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x0d, // section length 13 + 0x03, // types count 3 + 0x60, // kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + 0x60, // kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + 0x60, // kind: func + 0x00, // param count 0 + 0x01, 0x7f, // return count 1: i32 + + 0x03, // section kind: Function + 0x04, // section length 4 + 0x03, // functions count 3 + 0x00, // 0 $pad0 (result i32) + 0x01, // 1 $pad1 (result i32) + 0x02, // 2 $target (result i32) + + 0x07, // section kind: Export + 0x0a, // section length 10 + 0x01, // exports count 1: export # 0 + 0x06, // field name length: 6 + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, // field name: target + 0x00, 0x02, // kind: function index: 2 + + 0x0a, // section kind: Code + 0x11, // section length 17 + 0x03, // functions count 3 + // function #0 $pad0 + 0x04, // body size 4 + 0x00, // 0 entries in locals list + 0x41, 0x00, // i32.const 0 + 0x0b, // end + // function #1 $pad1 + 0x04, // body size 4 + 0x00, // 0 entries in locals list + 0x41, 0x01, // i32.const 1 + 0x0b, // end + // function #2 $target + 0x05, // body size 5 + 0x00, // 0 entries in locals list + 0x41, 0xde, 0x01, // i32.const 222 + 0x0b, // end + + 0x00, // section kind: Unknown + 0x1c, // section length 28 + 0x04, // section name length: 4 + 0x6e, 0x61, 0x6d, 0x65, // section name: name + 0x01, // name type: function + 0x15, // payload length: 21 + 0x03, // names count 3 + 0x00, 0x04, // index 0 name length: 4 + 0x70, 0x61, 0x64, 0x30, // name: pad0 + 0x01, 0x04, // index 1 name length: 4 + 0x70, 0x61, 0x64, 0x31, // name: pad1 + 0x02, 0x06, // index 2 name length: 6 + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, // name: target ]); const kHeapObjectTag = 1; diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-555304822.js b/deps/v8/test/mjsunit/sandbox/regress/regress-555304822.js new file mode 100644 index 000000000000..69a55ab4055f --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-555304822.js @@ -0,0 +1,110 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --sandbox-testing --allow-natives-syntax + +const cage = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const functionType = Sandbox.getInstanceTypeIdFor('JS_FUNCTION_TYPE'); +const sfiType = Sandbox.getInstanceTypeIdFor('SHARED_FUNCTION_INFO_TYPE'); +const sfiOffset = Sandbox.getFieldOffset(functionType, 'shared_function_info'); +const dispatchHandleOffset = + Sandbox.getFieldOffset(functionType, 'dispatch_handle'); +const formalCountOffset = + Sandbox.getFieldOffset(sfiType, 'formal_parameter_count'); + +function objectOffset(object) { + return Sandbox.getAddressOf(object) >>> 0; +} +function getSfiOffset(fn) { + return (cage.getUint32(objectOffset(fn) + sfiOffset, true) - 1) >>> 0; +} +function readFormalCount(fn) { + return cage.getUint16(getSfiOffset(fn) + formalCountOffset, true); +} +function writeFormalCount(fn, value) { + cage.setUint16(getSfiOffset(fn) + formalCountOffset, value, true); +} +function readDispatchHandle(fn) { + return cage.getUint32(objectOffset(fn) + dispatchHandleOffset, true); +} +function writeDispatchHandle(fn, value) { + cage.setUint32(objectOffset(fn) + dispatchHandleOffset, value, true); +} + +// Part 1: Corrupting SFI::formal_parameter_count in the sandbox must not cause +// TurboFan to emit mismatched underapplication padding or corrupt SP/locals. +function target1(a) { + return a === undefined ? 1 : 2; +} +%NeverOptimizeFunction(target1); + +const doubles = new Float64Array(48); +for (let i = 0; i < doubles.length; ++i) doubles[i] = i + 0.25; + +const declarations = []; +const additions = []; +for (let i = 0; i < doubles.length; ++i) { + declarations.push(`const v${i} = doubles[${i}];`); + additions.push(`v${i}`); +} +const factory = + new Function('target', `return function caller1(run, alternate, doubles) { + if (!run) return 0; + alternate |= 0; + ${declarations.join('\n')} + target(); + const total = ${additions.join(' + ')}; + return alternate + (total > 0 ? 1 : 0); + };`); +const caller1 = factory(target1); + +%PrepareFunctionForOptimization(caller1); +assertEquals(0x101, caller1(true, 0x100, doubles)); +assertEquals(0x101, caller1(true, 0x100, doubles)); + +const authenticCount = readFormalCount(target1); +writeFormalCount(target1, 8); +%OptimizeFunctionOnNextCall(caller1); +assertEquals(0x101, caller1(true, 0x100, doubles)); +writeFormalCount(target1, authenticCount); + +// Part 2: Defense-in-depth runtime check. If a JSFunction's dispatch_handle is +// swapped in-sandbox to a target with fewer parameters than the caller's padded +// argument_count (so argument_count > parameter_count while +// argc_reg < argument_count), CallJSFunction must abort with +// kJSSignatureMismatch. +function makeTarget() { + return function targetMany(a, b, c, d) { + return 10; + }; +} +const t1 = makeTarget(); +const t2 = makeTarget(); +function targetFew() { + return 20; +} +%NeverOptimizeFunction(t1); +%NeverOptimizeFunction(t2); +%NeverOptimizeFunction(targetFew); +%PrepareFunctionForOptimization(t1); +%PrepareFunctionForOptimization(t2); +%PrepareFunctionForOptimization(targetFew); +t1(); +t2(); +targetFew(); + +function caller2(fn) { + return fn(); +} +%PrepareFunctionForOptimization(caller2); +assertEquals(10, caller2(t1)); +assertEquals(10, caller2(t2)); +%OptimizeFunctionOnNextCall(caller2); +assertEquals(10, caller2(t1)); + +// Swap t1's dispatch handle to targetFew's dispatch handle (0 params). +// caller2 pushes 5 slots (receiver + 4 padded undefineds) with argc_reg = 1, +// while targetFew expects 1 slot (receiver). This triggers SbxCheck abort. +writeDispatchHandle(t1, readDispatchHandle(targetFew)); +caller2(t1); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-560536734.js b/deps/v8/test/mjsunit/sandbox/regress/regress-560536734.js new file mode 100644 index 000000000000..403c31eec359 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-560536734.js @@ -0,0 +1,78 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --allow-natives-syntax + +const kHeapNumberType = Sandbox.getInstanceTypeIdFor("HEAP_NUMBER_TYPE"); +const kHeapNumberValueOffset = Sandbox.getFieldOffset(kHeapNumberType, "value"); + +// The byteLength must exceed Smi::kMaxValue (1 GB on 64-bit architectures) +// so that Runtime_GrowableSharedArrayBufferByteLength allocates a HeapNumber. +const kByteLength = 0x40001000; +const kTimeoutMs = 1000; + +function testCorruptedGsabLength(corruptedFloat) { + const sharedBuffer = new SharedArrayBuffer(16); + const sharedState = new Int32Array(sharedBuffer); + + const workerScript = ` + const byteLength = ${kByteLength}; + const buffer = new SharedArrayBuffer(byteLength, {maxByteLength: byteLength}); + const view = new Uint8Array(buffer); + + function getLength(v) { return v.length; } + %PrepareFunctionForOptimization(getLength); + getLength(view); + getLength(view); + %OptimizeFunctionOnNextCall(getLength); + getLength(view); + + postMessage("ready"); + + onmessage = function(msg) { + const sharedState = new Int32Array(msg.data); + const marker = {}; + // In the bump-pointer new space allocation arena, the HeapNumber allocated + // by Runtime_GrowableSharedArrayBufferByteLength will be placed immediately + // after the newly allocated marker object. + const heapNumAddr = Sandbox.getAddressOf(marker) + Sandbox.getSizeOf(marker); + Atomics.store(sharedState, 0, heapNumAddr); + + // getLength invokes Runtime_GrowableSharedArrayBufferByteLength, which + // allocates the HeapNumber and pauses at the synchronization point. + const len = getLength(view); + postMessage({resultLen: len}); + }; + `; + + const worker = new Worker(workerScript, {type: "string"}); + assertEquals("ready", worker.getMessage()); + + %BlockAt("GrowableSharedArrayBufferByteLength", kTimeoutMs); + worker.postMessage(sharedBuffer); + + assertTrue(%WaitUntilBlocked("GrowableSharedArrayBufferByteLength", kTimeoutMs)); + + let heapNumAddr = 0; + while ((heapNumAddr = Atomics.load(sharedState, 0)) === 0) {} + + const mem = new DataView(new Sandbox.MemoryView(0, 0x100000000)); + assertEquals(kByteLength, mem.getFloat64(heapNumAddr + kHeapNumberValueOffset, true)); + + // Corrupt the HeapNumber's float64 payload to an invalid/negative value. + mem.setFloat64(heapNumAddr + kHeapNumberValueOffset, corruptedFloat, true); + + assertTrue(%Resume("GrowableSharedArrayBufferByteLength")); + + const res = worker.getMessage(); + // With the fix, any corrupted/negative byte_length exceeding kMaxByteLength + // causes the bounds check to fail and length safely evaluates to 0. + assertEquals(0, res.resultLen); + worker.terminate(); +} + +testCorruptedGsabLength(-65536.0); +testCorruptedGsabLength(-1.0); +testCorruptedGsabLength(-1e15); +testCorruptedGsabLength(NaN); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-567526351.js b/deps/v8/test/mjsunit/sandbox/regress/regress-567526351.js new file mode 100644 index 000000000000..3406ffdb1c67 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-567526351.js @@ -0,0 +1,50 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --expose-gc + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const mem1 = new WebAssembly.Memory( + {initial: 1n, maximum: 10n, shared: true, address: 'i64'}); +const mem2 = new WebAssembly.Memory( + {initial: 1n, maximum: 10n, shared: true, address: 'i64'}); + +const builder = new WasmModuleBuilder(); +builder.addImportedMemory('m', 'mem', 1, 10, true, true); +builder.addFunction('size', makeSig([], [kWasmI64])) + .addBody([kExprMemorySize, 0]) + .exportFunc(); +builder.addFunction('fill', makeSig([kWasmI64, kWasmI32, kWasmI64], [])) + .addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kExprLocalGet, 2, + kNumericPrefix, kExprMemoryFill, 0, + ]) + .exportFunc(); + +const instance = builder.instantiate({m: {mem: mem1}}); + +// Overwrite mem1's managed_backing_store with mem2's so that GC collects +// mem1's CppGCManaged<BackingStore> while the instance remains alive. +const kManagedBackingStoreOffset = Sandbox.getFieldOffset( + Sandbox.getInstanceTypeIdFor('WASM_MEMORY_OBJECT_TYPE'), + 'managed_backing_store'); +Sandbox.corruptObjectField( + mem1, kManagedBackingStoreOffset, + Sandbox.readObjectField(mem2, kManagedBackingStoreOffset, 32), 32); + +gc(); +gc(); + +assertThrows( + () => instance.exports.fill(0x20000000000n, 0x42, 8n), + WebAssembly.RuntimeError); +assertEquals(1n, instance.exports.size()); + +// Growing mem2 triggers UpdateSharedWasmMemoryObjects, which must not +// re-read mem1's corrupted managed_backing_store into the instance. +mem2.grow(1n); +assertEquals(1n, instance.exports.size()); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-572826713.js b/deps/v8/test/mjsunit/sandbox/regress/regress-572826713.js new file mode 100644 index 000000000000..ba5360ca0461 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-572826713.js @@ -0,0 +1,89 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing + +// Tests that array.{new|init}_{elem|data} are hardened against corrupted +// WasmTypeInfo. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +let $array0 = builder.addArray(kWasmAnyRef); +let $array1 = builder.addArray(kWasmI8); +let $sig2 = builder.addType(makeSig([], [wasmRefNullType($array1)])); +let $sig3 = builder.addType(makeSig([], [wasmRefNullType($array0)])); +let $sig4 = builder.addType(makeSig([kWasmI32, kWasmI32], [kWasmAnyRef])); +let make_i8 = builder.addFunction(undefined, $sig2).exportAs('make_i8'); +let make_any = builder.addFunction(undefined, $sig3).exportAs('make_any'); +let test = builder.addFunction(undefined, $sig4).exportAs('test'); +let $data0 = builder.addPassiveDataSegment([]); +let $segment0 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment1 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment2 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment3 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment4 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment5 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment6 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment7 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment8 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment9 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment10 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment11 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment12 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment13 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment14 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment15 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment16 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment17 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment18 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment19 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment20 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment21 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment22 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment23 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment24 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment25 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment26 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment27 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment28 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment29 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment30 = builder.addPassiveElementSegment([], kWasmAnyRef); +let $segment31 = builder.addPassiveElementSegment([], kWasmAnyRef); + +// func $make_i8: [] -> [wasmRefNullType($array1)] +make_i8.addBody([ + kExprI32Const, 4, + kGCPrefix, kExprArrayNewDefault, $array1, +]); + +// func $make_any: [] -> [wasmRefNullType($array0)] +make_any.addBody([ + kExprI32Const, 4, + kGCPrefix, kExprArrayNewDefault, $array0, +]); + +// func $test: [kWasmI32, kWasmI32] -> [kWasmAnyRef] +test.addBody([ + kExprLocalGet, 0, // $var0 + kExprLocalGet, 1, // $var1 + kGCPrefix, kExprArrayNewElem, $array0, $segment31, +]); + +const instance = builder.instantiate({}); + +const memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const i8_array_addr = Sandbox.getAddressOf(instance.exports.make_i8()); +const any_array_addr = Sandbox.getAddressOf(instance.exports.make_any()); +const i8_map = memory.getUint32(i8_array_addr, true) - 1; +const any_map = memory.getUint32(any_array_addr, true) - 1; + +const kWasmTypeInfoOffset = 20; +memory.setUint32( + any_map + kWasmTypeInfoOffset, + memory.getUint32(i8_map + kWasmTypeInfoOffset, true), + true); + +assertTraps(kTrapElementSegmentOutOfBounds, + () => instance.exports.test(0, 0x01000000)); diff --git a/deps/v8/test/mjsunit/sandbox/regress/regress-574792351.js b/deps/v8/test/mjsunit/sandbox/regress/regress-574792351.js new file mode 100644 index 000000000000..ab0aafcb9858 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/regress/regress-574792351.js @@ -0,0 +1,55 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --wasm-imported-strings-utf8 --allow-natives-syntax + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +function workerCode() { + onmessage = function(addr) { + let memview = new Sandbox.MemoryView(addr.data, 0x100); + let view = new Uint8Array(memview); + view[12] = 0xC2; + view[13] = 0xA2; + %BlockAt('NewStringFromBytes', 10000); + postMessage("ready"); + %WaitUntilBlocked('NewStringFromBytes', 10000); + view[12] = 0x41; + view[13] = 0x41; + %Resume('NewStringFromBytes'); + }; +} + +let worker = new Worker(workerCode, {type: 'function'}); + +const builder = new WasmModuleBuilder(); +let $array0 = builder.addArray(kWasmI8, {final: true}); +let $sig1 = builder.addType(makeSig( + [wasmRefNullType($array0), kWasmI32, kWasmI32], + [wasmRefType(kWasmExternRef)])); +let $sig2 = builder.addType(makeSig([], [wasmRefNullType($array0)])); +let $sig3 = builder.addType( + makeSig([wasmRefNullType($array0)], [wasmRefType(kWasmExternRef)])); +let decodeStringFromUTF8Array = + builder.addImport('wasm:text-decoder', 'decodeStringFromUTF8Array', $sig1); +let create_array = builder.addFunction("create_array", $sig2).exportFunc() + .addBody([ + kExprI32Const, 10, + kGCPrefix, kExprArrayNewDefault, $array0, + ]); +let decode = builder.addFunction("decode", $sig3).exportFunc().addBody([ + kExprLocalGet, 0, // $var0 + kExprI32Const, 0, + kExprI32Const, 2, + kExprCallFunction, decodeStringFromUTF8Array, + ]); + +let instance = builder.instantiate({}, {builtins: ["text-decoder"]}); +let wasm_array = instance.exports.create_array(); +let addr = Sandbox.getAddressOf(wasm_array); + +worker.postMessage(addr); +worker.getMessage(); + +instance.exports.decode(wasm_array); diff --git a/deps/v8/test/mjsunit/sandbox/wasm-interpreter-reentrant-throw-overlap.js b/deps/v8/test/mjsunit/sandbox/wasm-interpreter-reentrant-throw-overlap.js new file mode 100644 index 000000000000..830aa32fba78 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/wasm-interpreter-reentrant-throw-overlap.js @@ -0,0 +1,180 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --jitless --wasm-jitless --sandbox-testing + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const read32 = address => memory.getUint32(address >>> 0, true); +const write32 = (address, value) => + memory.setUint32(address >>> 0, value >>> 0, true); + +function mapAddress(object) { + return (read32(Sandbox.getAddressOf(object) >>> 0) - 1) >>> 0; +} + +function descriptorArrayAddress(object) { + return (read32(mapAddress(object) + 0x18) - 1) >>> 0; +} + +// V8 DescriptorArray layout (compressed pointers, 4-byte slots). These fragile +// constants live here only, so every access below goes through these helpers. +const kDescriptorCountOffset = 6; // uint16 number_of_descriptors +const kDescriptorHeaderSize = 0x10; // offset of the first entry +const kDescriptorEntrySize = 0xc; // {key, details, value} per entry +const kDescriptorDetailsOffset = 4; +const kDescriptorValueOffset = 8; + +function descriptorCount(descriptors) { + return memory.getUint16(descriptors + kDescriptorCountOffset, true); +} + +function descriptorEntryAt(descriptors, index) { + return descriptors + kDescriptorHeaderSize + index * kDescriptorEntrySize; +} + +const descriptorKey = entry => read32(entry); +const descriptorDetails = entry => read32(entry + kDescriptorDetailsOffset); +const descriptorValue = entry => read32(entry + kDescriptorValueOffset); + +function findDescriptorEntry(descriptors, keyTagged) { + const count = descriptorCount(descriptors); + for (let i = 0; i < count; ++i) { + const entry = descriptorEntryAt(descriptors, i); + if (descriptorKey(entry) === keyTagged) return entry; + } + throw new Error(`descriptor key 0x${keyTagged.toString(16)} not found`); +} + +const originalPayload = 0x3132333435363738n; +const replacementSeed = 0x5152535455565758n; +const overwriteValue = 0x4141414242424243n; + +// Give the deep frame a large slot area so the shallow publisher's stale +// pointer aliases live deep-frame slots on an unhardened build. +const kDeepSimdLocals = 256; + +const builder = new WasmModuleBuilder(); +const noopSig = builder.addType(makeSig([], [])); +const nestedSig = builder.addType(makeSig([kWasmI64], [])); +const tagSig = builder.addType(makeSig([kWasmI64], [])); +const noopIndex = builder.addImport('m', 'noop', noopSig); +const tagIndex = builder.addTag(tagSig); +builder.addExportOfKind('tag', kExternalTag, tagIndex); + +// Reentry target invoked from the corrupted values-getter. +builder.addFunction('nested', nestedSig).addBody([]).exportFunc(); + +// Deep frame: large slot area, throws an i64 payload. Its s2s_Throw handler +// runs the accessor-honoring values lookup while this frame is still live. +const deep = builder.addFunction('deep', makeSig([], [])) + .addLocals(kWasmS128, kDeepSimdLocals) + .addBody([ + ...wasmI64Const(originalPayload), + kExprThrow, ...wasmUnsignedLeb(tagIndex), + kExprUnreachable, + ]); + +// Shallow frame: publishes the stack frame pointer via a JS import that +// returns, then calls deep() with an s2s call so it is not republished. +builder.addFunction('shallow', makeSig([], [])) + .addBody([ + kExprCallFunction, ...wasmUnsignedLeb(noopIndex), + kExprTry, kWasmVoid, + kExprCallFunction, ...wasmUnsignedLeb(deep.index), + kExprCatch, ...wasmUnsignedLeb(tagIndex), + kExprDrop, + kExprEnd, + ]) + .exportFunc(); + +const instance = builder.instantiate({m: {noop() {}}}); +const tagObject = instance.exports.tag; +const sacrificial = new WebAssembly.Exception(tagObject, [replacementSeed]); +const originalDescriptors = descriptorArrayAddress(sacrificial); +const key0Tagged = descriptorKey(descriptorEntryAt(originalDescriptors, 0)); +const key1Tagged = descriptorKey(descriptorEntryAt(originalDescriptors, 1)); +const key0 = Sandbox.getObjectAt((key0Tagged - 1) >>> 0); +const key1 = Sandbox.getObjectAt((key1Tagged - 1) >>> 0); + +let tagSymbol; +let valuesSymbol; +for (const [key, tagged] of [[key0, key0Tagged], [key1, key1Tagged]]) { + const value = sacrificial[key]; + if (Sandbox.getInstanceTypeOf(value) === 'WASM_EXCEPTION_TAG_TYPE') { + tagSymbol = key; + } else if (Sandbox.getInstanceTypeOf(value) === 'FIXED_ARRAY_TYPE') { + valuesSymbol = key; + } else { + throw new Error( + `unexpected private field for key 0x${tagged.toString(16)}`); + } +} + +const expectedTag = sacrificial[tagSymbol]; +const replacementValues = sacrificial[valuesSymbol]; +let tagGets = 0; +let valueGets = 0; + +function tagGetter() { + ++tagGets; + return expectedTag; +} + +// Reentry trigger: while deep()'s s2s_Throw builds the exception, this getter +// reenters the instance. The stale shallow pointer still points inside the live +// deep frame on an unhardened build. +function valuesGetter() { + ++valueGets; + if (valueGets === 1) { + instance.exports.nested(overwriteValue); + } + return replacementValues; +} + +function makeFastAccessorDescriptor(getter) { + function Carrier() { + this.a = 1; + this.b = 2; + this.c = 3; + this.d = 4; + } + for (let i = 0; i < 20; ++i) new Carrier(); + const carrier = new Carrier(); + Object.defineProperty( + carrier, 'accessor', {get: getter, configurable: true}); + const descriptors = descriptorArrayAddress(carrier); + const count = descriptorCount(descriptors); + for (let i = 0; i < count; ++i) { + const entry = descriptorEntryAt(descriptors, i); + const value = descriptorValue(entry); + if ((value & 1) !== 0 && + Sandbox.isValidObjectAt((value - 1) >>> 0) && + Sandbox.getInstanceTypeOfObjectAt((value - 1) >>> 0) === + 'ACCESSOR_PAIR_TYPE') { + return {details: descriptorDetails(entry), value}; + } + } + throw new Error('failed to create a fast AccessorPair descriptor'); +} + +const tagAccessor = makeFastAccessorDescriptor(tagGetter); +const valuesAccessor = makeFastAccessorDescriptor(valuesGetter); +for (const [keyTagged, descriptor] of [ + [key0Tagged, tagSymbol === key0 ? tagAccessor : valuesAccessor], + [key1Tagged, tagSymbol === key1 ? tagAccessor : valuesAccessor], + ]) { + const dst = findDescriptorEntry(originalDescriptors, keyTagged); + write32(dst + kDescriptorDetailsOffset, descriptor.details); + write32(dst + kDescriptorValueOffset, descriptor.value); +} + +instance.exports.shallow(); + +// Both fields must be read straight from their in-object slots. If either +// lookup starts honoring the rewritten descriptors again, the corresponding +// counter becomes non-zero. +assertEquals(0, tagGets, 'tag getter must not run'); +assertEquals(0, valueGets, 'values getter must not run'); diff --git a/deps/v8/test/mjsunit/sandbox/wasm-suspender-stack-reference.js b/deps/v8/test/mjsunit/sandbox/wasm-suspender-stack-reference.js new file mode 100644 index 000000000000..edff342b82fe --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/wasm-suspender-stack-reference.js @@ -0,0 +1,95 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --expose-gc + +const kHeapObjectTag = 1; +const memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +const read32 = p => memory.getUint32(p, true); +const write32 = (p, value) => memory.setUint32(p, value, true); +const address = object => Sandbox.getAddressOf(object); +const bytes = new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version + + 0x01, // section kind: Type + 0x07, // section length 7 + 0x02, // types count 2 + 0x60, // kind: func + 0x00, // param count 0 + 0x00, // return count 0 + 0x60, // kind: func + 0x00, // param count 0 + 0x00, // return count 0 + + 0x02, // section kind: Import + 0x07, // section length 7 + 0x01, 0x01, // imports count 1: module name length: 1 + 0x6d, // module name: m + 0x01, // field name length: 1 + 0x70, // field name: p + 0x00, 0x00, // kind or compact flag: function + // import #0 + + 0x03, // section kind: Function + 0x02, // section length 2 + 0x01, 0x01, // functions count 1: 1 $f + + 0x07, // section kind: Export + 0x05, // section length 5 + 0x01, // exports count 1: export # 0 + 0x01, // field name length: 1 + 0x66, // field name: f + 0x00, 0x01, // kind: function index: 1 + + 0x0a, // section kind: Code + 0x06, // section length 6 + 0x01, // functions count 1 + // function #1 $f + 0x04, // body size 4 + 0x00, // 0 entries in locals list + 0x10, 0x00, // call $m.p + 0x0b, // end +]); +const instance = new WebAssembly.Instance(new WebAssembly.Module(bytes), { + m: {p: new WebAssembly.Suspending(() => new Promise(() => {}))} +}); +const suspend = WebAssembly.promising(instance.exports.f); +const buffer1 = new Uint8Array(1); +const buffer2 = new Uint8Array(1); +const tagObj = new WebAssembly.Tag({parameters: []}); +gc(); + +const extensionOffset = Sandbox.getFieldOffset( + Sandbox.getInstanceTypeIdFor('JS_ARRAY_BUFFER_TYPE'), 'extension'); +const firstHandle = read32(address(buffer1.buffer) + extensionOffset); +const secondHandle = read32(address(buffer2.buffer) + extensionOffset); +const handleStride = secondHandle - firstHandle; +assertTrue(handleStride > 0); +suspend(); + +const mapType = Sandbox.getInstanceTypeIdFor('MAP_TYPE'); +const instanceTypeOffset = Sandbox.getFieldOffset(mapType, 'instance_type'); +const stackType = Sandbox.getInstanceTypeIdFor('WASM_STACK_OBJECT_TYPE'); +const stackOffset = Sandbox.getFieldOffset(stackType, 'stack'); +const tagOffset = Sandbox.getFieldOffset( + Sandbox.getInstanceTypeIdFor('WASM_TAG_OBJECT_TYPE'), 'tag'); + +const p = read32(address(tagObj) + tagOffset) - kHeapObjectTag; +const metaMap = read32(read32(p) - kHeapObjectTag); +let stackMap = 0; +for (let addr = 0; addr < 0x10000; addr += 4) { + if (read32(addr) === metaMap && + memory.getUint16(addr + instanceTypeOffset, true) === stackType) { + stackMap = addr + kHeapObjectTag; + break; + } +} +assertNotEquals(0, stackMap); +write32(p, stackMap); +write32(p + stackOffset, secondHandle + handleStride); + +// An in-cage stack object cannot acquire a trusted suspender's stack reference. +gc(); +assertUnreachable(); diff --git a/deps/v8/test/mjsunit/sandbox/wasmfx-jspi-uaf.js b/deps/v8/test/mjsunit/sandbox/wasmfx-jspi-uaf.js new file mode 100644 index 000000000000..9ff500d1d9b8 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/wasmfx-jspi-uaf.js @@ -0,0 +1,69 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sandbox-testing --wasm-wasmfx --expose-gc + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +d8.file.execute('test/mjsunit/sandbox/wasm-jspi.js'); + +let builder = new WasmModuleBuilder(); +let sig_v_v = builder.addType(kSig_v_v); +let cont_index = builder.addCont(sig_v_v); + +let resolveB; +let promiseB = new Promise(r => { resolveB = r; }); +let wasm_promiseB; +let suspenderB; + +let suspendB_index = builder.addImport('m', 'suspendB', kSig_v_v); +let suspendA_index = builder.addImport('m', 'suspendA', kSig_v_v); +let call_promising_nop_index = + builder.addImport('m', 'call_promising_nop', kSig_v_v); +let trigger_index = builder.addImport('m', 'trigger', kSig_v_v); + +builder.addFunction('nop', kSig_v_v).addBody([]).exportFunc(); + +let cont_main = builder.addFunction('cont_main', kSig_v_v) + .addBody([ + kExprCallFunction, call_promising_nop_index, + ]).exportFunc(); + +builder.addFunction('runB', kSig_v_v) + .addBody([ + // 1. Suspend once so JS can read suspenderB's handle. + kExprCallFunction, suspendB_index, + // 2. Start a WasmFX continuation X that calls a promising export (nop), + // setting suspenderB->stack_ = X, and then returns, retiring X to + // the StackPool. + kExprRefFunc, cont_main.index, + kExprContNew, cont_index, + kExprResume, cont_index, 0, + // 3. While suspenderB is still Active, free X from the StackPool, + // corrupt wasm_promiseB's reaction to point to suspenderB, and capture + // an async stack trace. + kExprCallFunction, trigger_index, + ]).exportFunc(); + +builder.addExport('suspendA', suspendA_index); + +let instance = builder.instantiate({ + m: { + suspendB: new WebAssembly.Suspending(() => promiseB), + suspendA: new WebAssembly.Suspending(() => wasm_promiseB), + call_promising_nop: () => { + WebAssembly.promising(instance.exports.nop)(); + }, + trigger: () => { + gc({type: 'major', execution: 'sync', flavor: 'last-resort'}); + set_suspender(get_resume_data(wasm_promiseB), suspenderB); + new Error().stack; + assertUnreachable('Process should have been killed.'); + }, + } +}); + +wasm_promiseB = WebAssembly.promising(instance.exports.runB)(); +WebAssembly.promising(instance.exports.suspendA)(); +suspenderB = get_suspender(get_resume_data(promiseB)); +resolveB(); diff --git a/deps/v8/test/mjsunit/shared-memory/brand-checks.js b/deps/v8/test/mjsunit/shared-memory/brand-checks.js index ab43747d3cf3..9596a9005b4e 100644 --- a/deps/v8/test/mjsunit/shared-memory/brand-checks.js +++ b/deps/v8/test/mjsunit/shared-memory/brand-checks.js @@ -4,37 +4,21 @@ // // Flags: --harmony-struct -function TestBrandChecks(struct1, struct2, sa, mutex, cv) { +function TestBrandChecks(struct1, struct2, sa) { assertTrue(SharedStructType.isSharedStruct(struct1)); assertTrue(SharedStructType.isSharedStruct(struct2)); - for (const x of [sa, mutex, cv]) { - assertFalse(SharedStructType.isSharedStruct(x)); - } + assertFalse(SharedStructType.isSharedStruct(sa)); assertTrue(SharedArray.isSharedArray(sa)); assertTrue(sa instanceof SharedArray); - for (const x of [struct1, struct2, mutex, cv]) { + for (const x of [struct1, struct2]) { assertFalse(SharedArray.isSharedArray(x)); } - assertTrue(Atomics.Mutex.isMutex(mutex)); - assertTrue(mutex instanceof Atomics.Mutex); - for (const x of [struct1, struct2, sa, cv]) { - assertFalse(Atomics.Mutex.isMutex(x)); - } - - assertTrue(Atomics.Condition.isCondition(cv)); - assertTrue(cv instanceof Atomics.Condition); - for (const x of [struct1, struct2, sa, mutex]) { - assertFalse(Atomics.Condition.isCondition(x)); - } - const falsehoods = [42, -0, undefined, null, true, false, 'foo', {}, []]; for (const x of falsehoods) { assertFalse(SharedStructType.isSharedStruct(x)); assertFalse(SharedArray.isSharedArray(x)); - assertFalse(Atomics.Mutex.isMutex(x)); - assertFalse(Atomics.Condition.isCondition(x)); } } @@ -44,18 +28,14 @@ const S2 = new SharedStructType(['field2']); const struct1 = new S1(); const struct2 = new S2(); const sa = new SharedArray(1); -const mutex = new Atomics.Mutex(); -const cv = new Atomics.Condition(); -TestBrandChecks(struct1, struct2, sa, mutex, cv); +TestBrandChecks(struct1, struct2, sa); // Test cross-Realm. -const [otherStruct1, otherStruct2, otherSa, otherMutex, otherCv] = +const [otherStruct1, otherStruct2, otherSa] = Realm.eval(Realm.create(), `const S1 = new SharedStructType(['field']); const S2 = new SharedStructType(['field2']); const struct1 = new S1(); const struct2 = new S2(); const sa = new SharedArray(1); -const mutex = new Atomics.Mutex(); -const cv = new Atomics.Condition(); -[struct1, struct2, sa, mutex, cv]`); -TestBrandChecks(otherStruct1, otherStruct2, otherSa, otherMutex, otherCv); +[struct1, struct2, sa]`); +TestBrandChecks(otherStruct1, otherStruct2, otherSa); diff --git a/deps/v8/test/mjsunit/shared-memory/cannot-redefine-properties.js b/deps/v8/test/mjsunit/shared-memory/cannot-redefine-properties.js index 5e9ab359c79c..f4476075879c 100644 --- a/deps/v8/test/mjsunit/shared-memory/cannot-redefine-properties.js +++ b/deps/v8/test/mjsunit/shared-memory/cannot-redefine-properties.js @@ -34,7 +34,5 @@ function TestSharedObjectCannotRedefineProperty(sharedObj) { assertTrue(Object.isSealed(sharedObj)); } -TestSharedObjectCannotRedefineProperty(new Atomics.Condition()); -TestSharedObjectCannotRedefineProperty(new Atomics.Mutex()); TestSharedObjectCannotRedefineProperty(new (new SharedStructType(['p']))); TestSharedObjectCannotRedefineProperty(new SharedArray(1)); diff --git a/deps/v8/test/mjsunit/shared-memory/client-gc.js b/deps/v8/test/mjsunit/shared-memory/client-gc.js index e545de9cbca3..488eef54f73b 100644 --- a/deps/v8/test/mjsunit/shared-memory/client-gc.js +++ b/deps/v8/test/mjsunit/shared-memory/client-gc.js @@ -2,6 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Flags: --shared-string-table --allow-natives-syntax --expose-gc +// Flags: --shared-heap --allow-natives-syntax --expose-gc gc(); diff --git a/deps/v8/test/mjsunit/shared-memory/condition-workers.js b/deps/v8/test/mjsunit/shared-memory/condition-workers.js deleted file mode 100644 index 97ce2a9da4b9..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/condition-workers.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2022 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --harmony-struct --allow-natives-syntax - -"use strict"; - -if (this.Worker) { - -(function TestWait() { - let workerScript = - `onmessage = function({data:msg}) { - let mutex = msg.mutex; - let cv = msg.cv; - let res = Atomics.Mutex.lock(mutex, function() { - return Atomics.Condition.wait(cv, mutex); - }); - postMessage(res); - };`; - - let mutex = new Atomics.Mutex; - let cv = new Atomics.Condition; - let msg = {mutex, cv}; - - let worker1 = new Worker(workerScript, { type: 'string' }); - let worker2 = new Worker(workerScript, { type: 'string' }); - worker1.postMessage(msg); - worker2.postMessage(msg); - - // Spin until both workers are waiting. - while (%AtomicsSynchronizationPrimitiveNumWaitersForTesting(cv) != 2) {} - - assertEquals(2, Atomics.Condition.notify(cv, 2)); - - assertEquals(true, worker1.getMessage()); - assertEquals(true, worker2.getMessage()); - - worker1.terminate(); - worker2.terminate(); -})(); - -} diff --git a/deps/v8/test/mjsunit/shared-memory/condition.js b/deps/v8/test/mjsunit/shared-memory/condition.js deleted file mode 100644 index b548cadef06f..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/condition.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2022 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --harmony-struct --allow-natives-syntax - -let mutex = new Atomics.Mutex; -let cv = new Atomics.Condition; - -(function TestConditionWaitNotAllowed() { - assertThrows(() => { - Atomics.Mutex.lock(mutex, () => { - %SetAllowAtomicsWait(false); - Atomics.Condition.wait(cv, mutex); - }); - }); - %SetAllowAtomicsWait(true); -})(); - -(function TestConditionMutexNotHeld() { - // Cannot wait on a mutex not owned by the current thread. - assertThrows(() => { - Atomics.Condition.wait(cv, mutex); - }); -})(); - -(function TestConditionNoWaiters() { - // Notify returns number of threads woken up. - assertEquals(0, Atomics.Condition.notify(cv)); -})(); - -(function TestConditionWaitTimeout() { - Atomics.Mutex.lock(mutex, () => { - assertEquals(false, Atomics.Condition.wait(cv, mutex, 100)); - }); -})(); - -// Mutexes can be assigned to shared objects. -(function TestConditionCanBeAssignedToSharedObjects() { - const Box = new SharedStructType(["payload"]); - const box = new Box; - box.payload = cv; -})(); diff --git a/deps/v8/test/mjsunit/shared-memory/mutex-lock-twice.js b/deps/v8/test/mjsunit/shared-memory/mutex-lock-twice.js deleted file mode 100644 index ad43129192d3..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/mutex-lock-twice.js +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --expose-gc --harmony-struct - -let mtx = new Atomics.Mutex(); -let cnd = new Atomics.Condition(); - -Atomics.Mutex.lock(mtx, () => { - Atomics.Condition.wait(cnd, mtx, 100); -}); - -gc(); -gc(); - -Atomics.Mutex.lock(mtx, () => { - Atomics.Condition.wait(cnd, mtx, 100); -}); diff --git a/deps/v8/test/mjsunit/shared-memory/mutex-workers.js b/deps/v8/test/mjsunit/shared-memory/mutex-workers.js deleted file mode 100644 index 47e972bd85da..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/mutex-workers.js +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2022 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --harmony-struct --allow-natives-syntax - -"use strict"; - -if (this.Worker) { - -(function TestMutexWorkers() { - let workerScript = - `onmessage = function({data:msg}) { - let mutex = msg.mutex; - let box = msg.box; - for (let i = 0; i < 10; i++) { - Atomics.Mutex.lock(mutex, function() { - box.counter++; - }); - } - postMessage("done"); - }; - postMessage("started");`; - - let worker1 = new Worker(workerScript, { type: 'string' }); - let worker2 = new Worker(workerScript, { type: 'string' }); - assertEquals("started", worker1.getMessage()); - assertEquals("started", worker2.getMessage()); - - let Box = new SharedStructType(['counter']); - let box = new Box(); - box.counter = 0; - let mutex = new Atomics.Mutex(); - let msg = { mutex, box }; - worker1.postMessage(msg); - worker2.postMessage(msg); - assertEquals("done", worker1.getMessage()); - assertEquals("done", worker2.getMessage()); - assertEquals(20, box.counter); - - worker1.terminate(); - worker2.terminate(); -})(); - -(function TestMutexWaiters() { - let workerScript = `onmessage = function({data:msg}) { - let mutex = msg.mutex; - let box = msg.box; - Atomics.Mutex.lock(mutex, function() { - while(!Atomics.load(box, 'isDone')) {} - }); - postMessage("done"); - }; - postMessage("started");`; - - let worker1 = new Worker(workerScript, {type: 'string'}); - let worker2 = new Worker(workerScript, {type: 'string'}); - let worker3 = new Worker(workerScript, {type: 'string'}); - assertEquals('started', worker1.getMessage()); - assertEquals('started', worker2.getMessage()); - assertEquals('started', worker3.getMessage()); - - let Box = new SharedStructType(['isDone']); - let box = new Box(); - box.isDone = false; - let mutex = new Atomics.Mutex(); - let msg = {mutex, box}; - worker1.postMessage(msg); - worker2.postMessage(msg); - worker3.postMessage(msg); - while (%AtomicsSynchronizationPrimitiveNumWaitersForTesting(mutex) !== 2) {} - box.isDone = true; - assertEquals('done', worker1.getMessage()); - assertEquals('done', worker2.getMessage()); - assertEquals('done', worker3.getMessage()); - assertEquals(0, %AtomicsSynchronizationPrimitiveNumWaitersForTesting(mutex)); - - worker1.terminate(); - worker2.terminate(); - worker3.terminate(); -})(); - -(function TestTimeout() { - let worker1Script = `onmessage = function({data:msg}) { - let {mutex, box, cv, cv_mutex} = msg; - Atomics.Mutex.lock(mutex, function() { - Atomics.Mutex.lock(cv_mutex, function() { - // Post inside cv_mutex critical section to ensure worker2 - // requests it after worker1. - postMessage("lock acquired"); - while(!box.timedOut) { - Atomics.Condition.wait(cv, cv_mutex); - } - }); - }); - postMessage("done"); - }; - postMessage("started");`; - let worker2Script = `onmessage = function({data:msg}) { - let {mutex, box, cv, cv_mutex} = msg; - let result = - Atomics.Mutex.lockWithTimeout(mutex, ()=>{} , 1); - box.timedOut = !result.success; - // Use cv_mutex to ensure the notify happens after the wait. - Atomics.Mutex.lock(cv_mutex, function() { - Atomics.Condition.notify(cv); - }); - postMessage("done"); - }; - postMessage("started");`; - let worker1 = new Worker(worker1Script, {type: 'string'}); - let worker2 = new Worker(worker2Script, {type: 'string'}); - - assertEquals('started', worker2.getMessage()); - assertEquals('started', worker1.getMessage()); - - let Box = new SharedStructType(['timedOut']); - let box = new Box(); - box.timedOut = false; - let mutex = new Atomics.Mutex; - let cv = new Atomics.Condition; - let cv_mutex = new Atomics.Mutex; - let msg = {mutex, box, cv, cv_mutex}; - worker1.postMessage(msg); - assertEquals('lock acquired', worker1.getMessage()); - worker2.postMessage(msg); - assertEquals('done', worker2.getMessage()); - assertEquals('done', worker1.getMessage()); - worker1.terminate(); - worker2.terminate(); -})(); - -(function TestUnlockWhileTimingOut() { - // Racy version of the timeout test, where the worker holding the lock might - // unlock it while the other worker is timing out and cleaning its waiter from - // the queue. - let workerLockScript = `onmessage = function({data:msg}) { - let {mutex, box} = msg; - Atomics.Mutex.lock(mutex, function() { - while (!Atomics.load(box, 'isDone')) {} - }); - postMessage("done"); - } - postMessage("started");`; - - let timedOutWorkerScript = `onmessage = function({data:msg}) { - let {mutex} = msg; - let result = Atomics.Mutex.lockWithTimeout(mutex, function() {}, 0); - postMessage("done"); - } - postMessage("started");`; - - let workerLock = new Worker(workerLockScript, {type: 'string'}); - let timedOutWorker = new Worker(timedOutWorkerScript, {type: 'string'}); - assertEquals('started', workerLock.getMessage()); - assertEquals('started', timedOutWorker.getMessage()); - - let Box = new SharedStructType(['isDone']); - let box = new Box(); - box.isDone = false; - let mutex = new Atomics.Mutex; - - workerLock.postMessage({mutex, box}); - timedOutWorker.postMessage({mutex}); - box.isDone = true; - assertEquals('done', workerLock.getMessage()); - assertEquals('done', timedOutWorker.getMessage()); - assertEquals(0, %AtomicsSynchronizationPrimitiveNumWaitersForTesting(mutex)); - assertTrue(Atomics.Mutex.tryLock(mutex, function() {}).success); - - workerLock.terminate(); - timedOutWorker.terminate(); -})(); - -} diff --git a/deps/v8/test/mjsunit/shared-memory/mutex.js b/deps/v8/test/mjsunit/shared-memory/mutex.js deleted file mode 100644 index 13b3d170e04b..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/mutex.js +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2022 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --harmony-struct - -let mutex = new Atomics.Mutex; -let locked_count = 0; - -assertEquals(42, Atomics.Mutex.lock(mutex, () => { - locked_count++; return 42; -})); -assertEquals(locked_count, 1); - -let lockResult = Atomics.Mutex.tryLock(mutex, () => { - locked_count++; -}); -assertEquals(true, lockResult.success); -assertEquals(locked_count, 2); - -// Recursively locking throws. -Atomics.Mutex.lock(mutex, () => { - locked_count++; - assertThrows(() => { - Atomics.Mutex.lock(mutex, () => { throw "unreachable"; }); - }, Error); -}); -assertEquals(locked_count, 3); - -// Recursive tryLocking returns returns false success value. -Atomics.Mutex.lock(mutex, () => { - locked_count++; - lockResult = Atomics.Mutex.tryLock(mutex, () => { - throw 'unreachable'; - }); - assertEquals(false, lockResult.success); - assertEquals(undefined, lockResult.value); -}); -assertEquals(locked_count, 4); - -// Throwing in the callback should unlock the mutex. -assertThrowsEquals(() => { - Atomics.Mutex.lock(mutex, () => { throw 42; }); -}, 42); -Atomics.Mutex.lock(mutex, () => { locked_count++; }); -assertEquals(locked_count, 5); - -assertThrowsEquals(() => { - Atomics.Mutex.tryLock(mutex, () => { throw 42; }); -}, 42); -Atomics.Mutex.tryLock(mutex, () => { locked_count++; }); -assertEquals(locked_count, 6); - -// Mutexes can be assigned to shared objects. -(function TestMutexCanBeAssignedToSharedObjects() { - const Box = new SharedStructType(["payload"]); - const box = new Box; - box.payload = mutex; -})(); - -// lockWithTimeout's return value is an object with a value field -// and a success field. -lockResult = Atomics.Mutex.lockWithTimeout(mutex, () => 42, 1); -assertEquals(42, lockResult.value); -assertEquals(true, lockResult.success); - -// Timeout must be a number. -assertThrows(() => { - Atomics.Mutex.lockWithTimeout(mutex, () => {}, '42'); -}) -assertThrows(() => { - Atomics.Mutex.lockWithTimeout(mutex, () => {}, {}); -}) -assertThrows(() => { - Atomics.Mutex.lockWithTimeout(mutex, () => {}); -}) diff --git a/deps/v8/test/mjsunit/shared-memory/optimize-non-instance.js b/deps/v8/test/mjsunit/shared-memory/optimize-non-instance.js index 46df6dcfb0a8..d558400d6a83 100644 --- a/deps/v8/test/mjsunit/shared-memory/optimize-non-instance.js +++ b/deps/v8/test/mjsunit/shared-memory/optimize-non-instance.js @@ -6,12 +6,6 @@ function Foo() {} -function TestInstanceOfMutex() { - return Foo instanceof Atomics.Mutex; -} -function TestInstanceOfCondition() { - return Foo instanceof Atomics.Condition; -} function TestInstanceOfSharedArray() { return Foo instanceof SharedArray; } @@ -19,24 +13,16 @@ function TestInstanceOfSharedStruct() { return Foo instanceof (new SharedStructType(["foo"])); } -%PrepareFunctionForOptimization(TestInstanceOfMutex); -%PrepareFunctionForOptimization(TestInstanceOfCondition); %PrepareFunctionForOptimization(TestInstanceOfSharedArray); %PrepareFunctionForOptimization(TestInstanceOfSharedStruct); for (let i = 0; i < 10; i++) { - assertFalse(TestInstanceOfMutex()); - assertFalse(TestInstanceOfCondition()); assertFalse(TestInstanceOfSharedArray()); assertFalse(TestInstanceOfSharedStruct()); } -%OptimizeFunctionOnNextCall(TestInstanceOfMutex); -%OptimizeFunctionOnNextCall(TestInstanceOfCondition); %OptimizeFunctionOnNextCall(TestInstanceOfSharedArray); %OptimizeFunctionOnNextCall(TestInstanceOfSharedStruct); -assertFalse(TestInstanceOfMutex()); -assertFalse(TestInstanceOfCondition()); assertFalse(TestInstanceOfSharedArray()); assertFalse(TestInstanceOfSharedStruct()); diff --git a/deps/v8/test/mjsunit/shared-memory/private-brand.js b/deps/v8/test/mjsunit/shared-memory/private-brand.js index 0dabcbebfca3..a51851ed2d24 100644 --- a/deps/v8/test/mjsunit/shared-memory/private-brand.js +++ b/deps/v8/test/mjsunit/shared-memory/private-brand.js @@ -20,7 +20,5 @@ function TestSharedObjectCannotAddPrivateBrand(sharedObj) { }); } -TestSharedObjectCannotAddPrivateBrand(new Atomics.Condition()); -TestSharedObjectCannotAddPrivateBrand(new Atomics.Mutex()); TestSharedObjectCannotAddPrivateBrand(new (new SharedStructType(['p']))); TestSharedObjectCannotAddPrivateBrand(new SharedArray(1)); diff --git a/deps/v8/test/mjsunit/shared-memory/private-field.js b/deps/v8/test/mjsunit/shared-memory/private-field.js index dd3a3c1abd3d..4b02cb6dcba7 100644 --- a/deps/v8/test/mjsunit/shared-memory/private-field.js +++ b/deps/v8/test/mjsunit/shared-memory/private-field.js @@ -19,7 +19,5 @@ function TestSharedObjectCannotAddPrivateField(sharedObj) { }); } -TestSharedObjectCannotAddPrivateField(new Atomics.Condition()); -TestSharedObjectCannotAddPrivateField(new Atomics.Mutex()); TestSharedObjectCannotAddPrivateField(new (new SharedStructType(['p']))); TestSharedObjectCannotAddPrivateField(new SharedArray(1)); diff --git a/deps/v8/test/mjsunit/shared-memory/private-name.js b/deps/v8/test/mjsunit/shared-memory/private-name.js index a2e2f0caae1b..09121fba1f77 100644 --- a/deps/v8/test/mjsunit/shared-memory/private-name.js +++ b/deps/v8/test/mjsunit/shared-memory/private-name.js @@ -7,7 +7,5 @@ // Private names as used by V8-specific APIs like Error.captureStackTrace should // not bypass shared objects' extensibility check. -assertThrows(() => Error.captureStackTrace(new Atomics.Condition())); -assertThrows(() => Error.captureStackTrace(new Atomics.Mutex())); assertThrows(() => Error.captureStackTrace(new (new SharedStructType(['p'])))); assertThrows(() => Error.captureStackTrace(new SharedArray(1))); diff --git a/deps/v8/test/mjsunit/shared-memory/regress-524783017.js b/deps/v8/test/mjsunit/shared-memory/regress-524783017.js deleted file mode 100644 index 1a7de07a87d0..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/regress-524783017.js +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --harmony-struct - -"use strict"; - -(function TestRegress524783017() { - function workerCode() { - onmessage = function({data: {mutex, box}}) { - while (Atomics.load(box, 0) === 0) { - Atomics.Mutex.lockWithTimeout(mutex, () => {}, 1); - } - }; - } - - let box = new Int32Array(new SharedArrayBuffer(4)); - let mutex = new Atomics.Mutex(); - let workers = []; - for (let i = 0; i < 16; i++) { - let w = new Worker(workerCode, { type: 'function' }); - w.postMessage({ mutex, box }); - workers.push(w); - } - let start = Date.now(); - while (Date.now() - start < 200) {} - Atomics.store(box, 0, 1); - for (let w of workers) w.terminate(); -})(); diff --git a/deps/v8/test/mjsunit/shared-memory/regress-crbug-1441241.js b/deps/v8/test/mjsunit/shared-memory/regress-crbug-1441241.js index c0e0cddd24fa..d4a98aaaaf27 100644 --- a/deps/v8/test/mjsunit/shared-memory/regress-crbug-1441241.js +++ b/deps/v8/test/mjsunit/shared-memory/regress-crbug-1441241.js @@ -5,7 +5,7 @@ // Flags: --allow-natives-syntax --harmony-struct const sharedCtors = [ - new SharedStructType(['x']), SharedArray, Atomics.Mutex, Atomics.Condition + new SharedStructType(['x']), SharedArray ]; for (let ctor of sharedCtors) { diff --git a/deps/v8/test/mjsunit/shared-memory/regress-crbug-1449611.js b/deps/v8/test/mjsunit/shared-memory/regress-crbug-1449611.js deleted file mode 100644 index 4a48effdcda9..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/regress-crbug-1449611.js +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2023 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --jit-fuzzing --harmony-struct - -function f(a) { a[4] = 42; } - -for (let i = 0; i < 2; i++) { - f([]); - f(Atomics.Mutex()); - f(Atomics.Condition()); -} diff --git a/deps/v8/test/mjsunit/shared-memory/regress-crbug-333007256.js b/deps/v8/test/mjsunit/shared-memory/regress-crbug-333007256.js deleted file mode 100644 index 87d90bfbf869..000000000000 --- a/deps/v8/test/mjsunit/shared-memory/regress-crbug-333007256.js +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2024 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --harmony-struct --expose-gc - -const Probe = function() { - const ProxyConstructor = Proxy; - const getPrototypeOf = Object.getPrototypeOf; - const setPrototypeOf = Object.setPrototypeOf; - function probe(value) { - originalPrototype = getPrototypeOf(value); - newPrototype = new ProxyConstructor(originalPrototype, function(){}); - setPrototypeOf(value, newPrototype); - } - return { - probe: probe, - }; -}(); - -gc(); - -for (let v2 = 0; v2 < 5; v2++) { - // Creates a derived map with non-JSObject prototype. - Probe.probe(Atomics); - Atomics.h = Atomics.Mutex(); -} diff --git a/deps/v8/test/mjsunit/shared-memory/regress/regress-528397177.js b/deps/v8/test/mjsunit/shared-memory/regress/regress-528397177.js index e0f2c0d3c69f..d07896600165 100644 --- a/deps/v8/test/mjsunit/shared-memory/regress/regress-528397177.js +++ b/deps/v8/test/mjsunit/shared-memory/regress/regress-528397177.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --expose-gc --shared-string-table --cache +// Flags: --expose-gc --shared-heap --cache const value = "some value"; const map = new WeakMap(); diff --git a/deps/v8/test/mjsunit/shared-memory/shared-object-has-instance.js b/deps/v8/test/mjsunit/shared-memory/shared-object-has-instance.js index 917ec70e2e68..05c57cb492d8 100644 --- a/deps/v8/test/mjsunit/shared-memory/shared-object-has-instance.js +++ b/deps/v8/test/mjsunit/shared-memory/shared-object-has-instance.js @@ -65,30 +65,6 @@ function BuildPrototypeChain(base_obj) { assertTrue(BuildPrototypeChain(sa) instanceof SharedArray); })(); -(function TestAtomicsMutexHasInstance() { - let lock = new Atomics.Mutex(); - // Returns true for the original constructor. - assertTrue(lock instanceof Atomics.Mutex); - // Returns false for a different object. - assertFalse(other_obj instanceof Atomics.Mutex); - // Returns false for a different constructor. - assertFalse(lock instanceof OtherConstructor); - // Returns true if the mutex is in the prototype chain. - assertTrue(BuildPrototypeChain(lock) instanceof Atomics.Mutex); -})(); - -(function TestAtomicsConditionHasInstance() { - let conditon = new Atomics.Condition(); - // Returns true for the original constructor. - assertTrue(conditon instanceof Atomics.Condition); - // Returns false for a different object. - assertFalse(other_obj instanceof Atomics.Condition); - // Returns false for a different constructor. - assertFalse(conditon instanceof OtherConstructor); - // Returns true if the condition is in the prototype chain. - assertTrue(BuildPrototypeChain(conditon) instanceof Atomics.Condition); -})(); - (function TestCallStaticHasInstance() { let s1 = new S1(); // Returns true when calling with the correct constructor as the receiver. diff --git a/deps/v8/test/mjsunit/shared-memory/shared-string-in-code-object.js b/deps/v8/test/mjsunit/shared-memory/shared-string-in-code-object.js index 18b3051f55c9..4cbab3020ebc 100644 --- a/deps/v8/test/mjsunit/shared-memory/shared-string-in-code-object.js +++ b/deps/v8/test/mjsunit/shared-memory/shared-string-in-code-object.js @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Flags: --shared-string-table --allow-natives-syntax --stress-compaction +// Flags: --shared-strings --allow-natives-syntax --stress-compaction -function foo() { return "foo"; } +function foo() { return %ShareObject("foo"); } %PrepareFunctionForOptimization(foo); let value = foo(); diff --git a/deps/v8/test/mjsunit/shared-memory/shared-string-in-weak-map.js b/deps/v8/test/mjsunit/shared-memory/shared-string-in-weak-map.js index cf4c95e8a403..116aa9425c3c 100644 --- a/deps/v8/test/mjsunit/shared-memory/shared-string-in-weak-map.js +++ b/deps/v8/test/mjsunit/shared-memory/shared-string-in-weak-map.js @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Flags: --shared-string-table --allow-natives-syntax --stress-compaction --expose-gc +// Flags: --shared-strings --allow-natives-syntax --stress-compaction --expose-gc -const val1 = "some value"; +const val1 = %ShareObject("some value"); assertTrue(%IsSharedString(val1)); const wm = new WeakMap(); diff --git a/deps/v8/test/mjsunit/string-index-undefined-optimized.js b/deps/v8/test/mjsunit/string-index-undefined-optimized.js new file mode 100644 index 000000000000..fa379a2b8b62 --- /dev/null +++ b/deps/v8/test/mjsunit/string-index-undefined-optimized.js @@ -0,0 +1,79 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --maglev + +function checkOptimizedPair(omitted, explicit, expected, nextExpected) { + %PrepareFunctionForOptimization(omitted); + %PrepareFunctionForOptimization(explicit); + assertEquals(expected, omitted('abc')); + assertEquals(expected, explicit('abc')); + %OptimizeFunctionOnNextCall(omitted); + %OptimizeFunctionOnNextCall(explicit); + assertEquals(expected, omitted('abc')); + assertEquals(omitted('abc'), explicit('abc')); + assertOptimized(omitted); + assertOptimized(explicit); + assertEquals(nextExpected, omitted('xyz')); + assertEquals(omitted('xyz'), explicit('xyz')); + assertOptimized(omitted); + assertOptimized(explicit); +} + +function charAtOmitted(string) { + return string.charAt(); +} + +function charAtUndefined(string) { + return string.charAt(undefined); +} +checkOptimizedPair(charAtOmitted, charAtUndefined, 'a', 'x'); + +function charCodeAtOmitted(string) { + return string.charCodeAt(); +} + +function charCodeAtUndefined(string) { + return string.charCodeAt(undefined); +} +checkOptimizedPair(charCodeAtOmitted, charCodeAtUndefined, 97, 120); + +function codePointAtOmitted(string) { + return string.codePointAt(); +} + +function codePointAtUndefined(string) { + return string.codePointAt(undefined); +} +checkOptimizedPair(codePointAtOmitted, codePointAtUndefined, 97, 120); + +function startsWithOmitted(string) { + return string.startsWith('a'); +} + +function startsWithUndefined(string) { + return string.startsWith('a', undefined); +} + +checkOptimizedPair(startsWithOmitted, startsWithUndefined, true, false); + +function indexOfOmitted(string) { + return string.indexOf('b'); +} + +function indexOfUndefined(string) { + return string.indexOf('b', undefined); +} + +checkOptimizedPair(indexOfOmitted, indexOfUndefined, 1, -1); + +function includesOmitted(string) { + return string.includes('b'); +} + +function includesUndefined(string) { + return string.includes('b', undefined); +} + +checkOptimizedPair(includesOmitted, includesUndefined, true, false); diff --git a/deps/v8/test/mjsunit/transition-elements-kind.js b/deps/v8/test/mjsunit/transition-elements-kind.js index 9021639103d5..8eb9717292af 100644 --- a/deps/v8/test/mjsunit/transition-elements-kind.js +++ b/deps/v8/test/mjsunit/transition-elements-kind.js @@ -59,7 +59,7 @@ function poly_store(a, x) { %PrepareFunctionForOptimization(poly_store); poly_store([1.1], 'a'); poly_store([1.1], 2.1); -var x = foo(); +var x = new Array(); x[0] = 1.1; x.x = 12; poly_store(x, 'a'); diff --git a/deps/v8/test/mjsunit/turbolev/convert-receiver.js b/deps/v8/test/mjsunit/turbolev/convert-receiver.js index 527aa31a5cdf..02945d997d98 100644 --- a/deps/v8/test/mjsunit/turbolev/convert-receiver.js +++ b/deps/v8/test/mjsunit/turbolev/convert-receiver.js @@ -34,6 +34,10 @@ assertOptimized(call_f_receiver_number); function f() { return this.x; } +// Prevent `f` from being inlined, as inlining `this.x` would add a dependency +// on `x`'s PropertyCell and cause `call_f_receiver_undefined` to deopt on +// `var x = 23`. +%NeverOptimizeFunction(f); function call_f_receiver_undefined(o) { return f.call(o); diff --git a/deps/v8/test/mjsunit/turbolev/create-closure-top-level.js b/deps/v8/test/mjsunit/turbolev/create-closure-top-level.js new file mode 100644 index 000000000000..7bd7ce61b128 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/create-closure-top-level.js @@ -0,0 +1,31 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --allow-natives-syntax --turbolev --turbofan --no-maglev + +// Closures created outside of a function scope (e.g. in top-level code) don't +// use the FastNewClosure builtin. OSR the top-level code into Turbolev to +// exercise the CreateClosure node, which calls the runtime instead. + +const topLevel = %GetFunctionForCurrentFrame(); +%PrepareFunctionForOptimization(topLevel); + +let v = 7; +let x = 4; +let o; +let created_in_turbofan = false; +// Declare the loop variable outside of the loop: a `for (let ...)` loop that +// creates closures is desugared into nested loops. +let i = 0; +for (; i < 3; i++) { + o = {}; + o.x = (c) => v + x++ + 2 + c; + if (%CurrentFrameIsTurbofan()) { + created_in_turbofan = true; + } + if (i == 1) %OptimizeOsr(); +} +assertTrue(created_in_turbofan); +assertEquals(7 + 4 + 2 + 2, o.x(2)); +assertEquals(7 + 5 + 2 + 5, o.x(5)); diff --git a/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-561781465.js b/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-561781465.js new file mode 100644 index 000000000000..c03896a89344 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-561781465.js @@ -0,0 +1,27 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev --turbolev-escape-analysis + +function* foo() { + for (let i = 0; i < 4; i++) { + const o = { y: "abc" }; + for (let j = 0; j < 5; j++) { + o.y = {}; + } + if (i < 1) { + o.y = "def"; + } + for (let k = 0; k < 2; k++) { + for (let c = 0; c;) { + yield; + } + } + } +} + +%PrepareFunctionForOptimization(foo); +foo().next(); +%OptimizeFunctionOnNextCall(foo); +foo().next(); diff --git a/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692-array-at.js b/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692-array-at.js new file mode 100644 index 000000000000..21183dfea7fe --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692-array-at.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev --turbolev-escape-analysis +// Flags: --no-maglev-range-analysis --no-turbolev-untagged-phis + +function bar() {} +%NeverOptimizeFunction(bar); + +const offset = 0x1fffffff; + +function foo() { + let arr = [3.3, , 4.5]; + + bar(); + + return arr.at(offset); +} + +%PrepareFunctionForOptimization(foo); +assertEquals(undefined, foo()); + +%OptimizeFunctionOnNextCall(foo); +assertEquals(undefined, foo()); diff --git a/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692.js b/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692.js new file mode 100644 index 000000000000..ed128cdb9f00 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/escape-analysis-regress-564543692.js @@ -0,0 +1,25 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev --turbolev-escape-analysis +// Flags: --no-maglev-range-analysis --no-turbolev-untagged-phis + +function bar() {} +%NeverOptimizeFunction(bar); + +const offset = 0x1fffffff; + +function foo() { + let arr = [3.3, 4.5]; + + arr[offset] = 3.35; + + bar(); +} + +%PrepareFunctionForOptimization(foo); +foo(); + +%OptimizeFunctionOnNextCall(foo); +foo(); diff --git a/deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder-holey.js b/deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder-holey.js new file mode 100644 index 000000000000..62c682774c5e --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder-holey.js @@ -0,0 +1,180 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +// Tests that when --forin-enumerator-holder is enabled, holey elements kinds safely +// fall back to standard enum cache iteration (FixedArray) and maintain correct ES spec +// enumeration order even when mutated during iteration. + +// Test 1: Holey Smi elements. +(function() { + function allKeys(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + // o has hole at index 1. + const o = [1, , 3]; + assertEquals(["0", "2"], allKeys(o)); + assertEquals(["0", "2"], allKeys(o)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(["0", "2"], allKeys(o)); + assertOptimized(allKeys); +})(); + +// Test 2: Holey Double elements. +(function() { + function allKeys(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + const o = [1.1, , 3.3]; + assertEquals(["0", "2"], allKeys(o)); + assertEquals(["0", "2"], allKeys(o)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(["0", "2"], allKeys(o)); + assertOptimized(allKeys); +})(); + +// Test 3: Holey Object elements. +(function() { + function allKeys(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + const o = [{a: 1}, , {c: 3}]; + assertEquals(["0", "2"], allKeys(o)); + assertEquals(["0", "2"], allKeys(o)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(["0", "2"], allKeys(o)); + assertOptimized(allKeys); +})(); + +// Test 4: Mutation during iteration - deleting elements. +(function() { + function iterateAndDelete(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') { + delete o[1]; // delete next element (which becomes hole) + } + } + return keys; + } + %PrepareFunctionForOptimization(iterateAndDelete); + + for (let i = 0; i < 20; i++) { + iterateAndDelete([1, 2, 3]); + } + + %OptimizeFunctionOnNextCall(iterateAndDelete); + const arr1 = [1, 2, 3]; + assertEquals(["0", "2"], iterateAndDelete(arr1)); // 1 is deleted, should be skipped. + + // Case 4b: Start with holey, delete element. Map doesn't change. + function iterateAndDeleteHole(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') { + delete o[2]; // delete index 2 + } + } + return keys; + } + %PrepareFunctionForOptimization(iterateAndDeleteHole); + for (let i = 0; i < 20; i++) { + iterateAndDeleteHole([1, , 3, 4]); + } + %OptimizeFunctionOnNextCall(iterateAndDeleteHole); + const arr2 = [1, , 3, 4]; + assertEquals(["0", "3"], iterateAndDeleteHole(arr2)); + assertOptimized(iterateAndDeleteHole); +})(); + +// Test 5: Mutation of length during iteration. +(function() { + function iterateAndShrink(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') { + o.length = 1; // shrink array + } + } + return keys; + } + %PrepareFunctionForOptimization(iterateAndShrink); + for (let i = 0; i < 20; i++) { + iterateAndShrink([1, 2, 3]); + } + %OptimizeFunctionOnNextCall(iterateAndShrink); + + const arr = [1, 2, 3]; + assertEquals(["0"], iterateAndShrink(arr)); +})(); + +// Test 6: In-place hole filling during for..in on a holey array must not +// enumerate the newly added property if the implementation uses snapshot +// EnumCache semantics. +(function() { + function fillHoleDuringForIn(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') { + o[1] = 2; + } + } + return keys; + } + %PrepareFunctionForOptimization(fillHoleDuringForIn); + + for (let i = 0; i < 20; i++) { + fillHoleDuringForIn([1, , 3]); + } + %OptimizeFunctionOnNextCall(fillHoleDuringForIn); + assertEquals(["0", "2"], fillHoleDuringForIn([1, , 3])); + assertOptimized(fillHoleDuringForIn); +})(); + +// Test 7: Array.prototype.unshift during for..in on a holey array. +(function() { + function unshiftDuringForIn(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') { + o.unshift(0); + } + } + return keys; + } + %PrepareFunctionForOptimization(unshiftDuringForIn); + + for (let i = 0; i < 20; i++) { + unshiftDuringForIn([1, , 3]); + } + %OptimizeFunctionOnNextCall(unshiftDuringForIn); + assertEquals(["0"], unshiftDuringForIn([1, , 3])); + assertOptimized(unshiftDuringForIn); +})(); diff --git a/deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder.js b/deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder.js new file mode 100644 index 000000000000..1f9b857ebb18 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/for-in-enumerator-holder.js @@ -0,0 +1,294 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +(function() { + function firstKey(o) { + for (const k in o) { return k; } + return 'empty'; + } + %PrepareFunctionForOptimization(firstKey); + + const arr = [1, 2, 3]; + assertEquals("0", firstKey(arr)); + assertEquals("0", firstKey(arr)); + %OptimizeFunctionOnNextCall(firstKey); + assertEquals("0", firstKey(arr)); + assertOptimized(firstKey); +})(); + +(function() { + function allKeys(o) { + // Initialize as PACKED_ELEMENTS to avoid deopts when allocation site + // tracking is disabled (e.g. single_generation). + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + const arr = [1, 2]; + arr.foo = 'bar'; + arr.bar = 'baz'; + + assertEquals(["0", "1", "foo", "bar"], allKeys(arr)); + assertEquals(["0", "1", "foo", "bar"], allKeys(arr)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(["0", "1", "foo", "bar"], allKeys(arr)); + assertOptimized(allKeys); +})(); + +(function() { + function iterateAndMutate(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') { + o.new_prop = 'new'; + } + } + return keys; + } + %PrepareFunctionForOptimization(iterateAndMutate); + + const arr = [1, 2]; + arr.foo = 'bar'; + + // Warmup with fresh objects to avoid polluting the map history too much, + // but they must have the same shape. + for (let i = 0; i < 20; i++) { + const temp = [1, 2]; + temp.foo = 'bar'; + iterateAndMutate(temp); + } + + %OptimizeFunctionOnNextCall(iterateAndMutate); + const my_arr = [1, 2]; + my_arr.foo = 'bar'; + assertEquals(["0", "1", "foo"], iterateAndMutate(my_arr)); +})(); + +// Shared DescriptorArray / EnumCache where a child map has more properties +// than the parent map: must use the receiver map's EnumLength, not the full +// EnumCache keys array length. +(function() { + function allKeys(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + const a = [1]; + a.x = 10; + a.y = 20; + for (let k in a) {} + + const b = [1]; + b.x = 10; + assertEquals(["0", "x"], allKeys(b)); + assertEquals(["0", "x"], allKeys(b)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(["0", "x"], allKeys(b)); + assertOptimized(allKeys); +})(); + +// JSArray with slack capacity (elements.length > array.length): must only +// enumerate up to array.length, not elements.length. +(function() { + function allKeys(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + const a = []; + a.push(10, 20); + assertEquals(["0", "1"], allKeys(a)); + assertEquals(["0", "1"], allKeys(a)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(["0", "1"], allKeys(a)); + assertOptimized(allKeys); +})(); + +// OSR inside a for..in loop over a large array on its very first execution +// (feedback starts uninitialized, then transitions to kEnumeratorHolder). +(function() { + const big = []; + for (let i = 0; i < 5000; i++) big.push(i); + big.extra = 'end'; + + function osrLoop(o) { + let count = 0; + let last = ''; + for (const k in o) { + count++; + last = k; + } + return [count, last]; + } + assertEquals([5001, 'extra'], osrLoop(big)); +})(); + +// Nested loops with for..in over packed array with named properties. +(function() { + function peeledForIn(o) { + const keys = ['']; + keys.length = 0; + for (let i = 0; i < 3; i++) { + for (const k in o) { + keys.push(k); + for (let j = 0; j < 2; j++) { + if (j === 1 && k === 'a') keys.push('inner'); + } + } + } + return keys; + } + %PrepareFunctionForOptimization(peeledForIn); + + const arr = [1, 2]; + arr.a = 10; + const expected = [ + '0', '1', 'a', 'inner', + '0', '1', 'a', 'inner', + '0', '1', 'a', 'inner', + ]; + assertEquals(expected, peeledForIn(arr)); + assertEquals(expected, peeledForIn(arr)); + %OptimizeFunctionOnNextCall(peeledForIn); + assertEquals(expected, peeledForIn(arr)); + assertOptimized(peeledForIn); +})(); + +// Non-JSArray with packed elements (object literal and strict arguments), +// including adding an indexed element mid-loop. +(function() { + function allKeys(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { keys.push(k); } + return keys; + } + %PrepareFunctionForOptimization(allKeys); + + const obj = {0: 'a', 1: 'b', foo: 'bar'}; + const args = (function() { 'use strict'; return arguments; })('x', 'y'); + assertEquals(['0', '1', 'foo'], allKeys(obj)); + assertEquals(['0', '1'], allKeys(args)); + %OptimizeFunctionOnNextCall(allKeys); + assertEquals(['0', '1', 'foo'], allKeys(obj)); + assertEquals(['0', '1'], allKeys(args)); + assertOptimized(allKeys); + + function addIndexedOnObject(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') o[2] = 'c'; + } + return keys; + } + %PrepareFunctionForOptimization(addIndexedOnObject); + for (let i = 0; i < 10; i++) { + addIndexedOnObject({0: 'a', 1: 'b', foo: 'bar'}); + } + %OptimizeFunctionOnNextCall(addIndexedOnObject); + assertEquals(['0', '1', 'foo'], + addIndexedOnObject({0: 'a', 1: 'b', foo: 'bar'})); +})(); + +// JSArray push and pop mid-loop. +(function() { + function iterateAndPush(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') o.push(99); + } + return keys; + } + %PrepareFunctionForOptimization(iterateAndPush); + for (let i = 0; i < 10; i++) { + const a = [1, 2]; + a.foo = 'bar'; + iterateAndPush(a); + } + %OptimizeFunctionOnNextCall(iterateAndPush); + const a1 = [1, 2]; + a1.foo = 'bar'; + assertEquals(['0', '1', 'foo'], iterateAndPush(a1)); + + function iterateAndPop(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') o.pop(); + } + return keys; + } + %PrepareFunctionForOptimization(iterateAndPop); + for (let i = 0; i < 10; i++) { + const a = [1, 2]; + a.foo = 'bar'; + iterateAndPop(a); + } + %OptimizeFunctionOnNextCall(iterateAndPop); + const a2 = [1, 2]; + a2.foo = 'bar'; + assertEquals(['0', 'foo'], iterateAndPop(a2)); +})(); + +// JSArray elements kind transition mid-loop (PACKED_SMI -> PACKED_DOUBLE and +// PACKED_SMI -> PACKED_ELEMENTS). +(function() { + function transitionToDouble(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') o[1] = 1.5; + } + return keys; + } + %PrepareFunctionForOptimization(transitionToDouble); + for (let i = 0; i < 10; i++) { + const a = [1, 2]; + a.foo = 'bar'; + transitionToDouble(a); + } + %OptimizeFunctionOnNextCall(transitionToDouble); + const a1 = [1, 2]; + a1.foo = 'bar'; + assertEquals(['0', '1', 'foo'], transitionToDouble(a1)); + + function transitionToTagged(o) { + const keys = ['']; + keys.length = 0; + for (const k in o) { + keys.push(k); + if (k === '0') o[1] = 'str'; + } + return keys; + } + %PrepareFunctionForOptimization(transitionToTagged); + for (let i = 0; i < 10; i++) { + const a = [1, 2]; + a.foo = 'bar'; + transitionToTagged(a); + } + %OptimizeFunctionOnNextCall(transitionToTagged); + const a2 = [1, 2]; + a2.foo = 'bar'; + assertEquals(['0', '1', 'foo'], transitionToTagged(a2)); +})(); diff --git a/deps/v8/test/mjsunit/turbolev/loop-in-maglev-but-not-turboshaft.js b/deps/v8/test/mjsunit/turbolev/loop-in-maglev-but-not-turboshaft.js new file mode 100644 index 000000000000..2154a9e52f2c --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/loop-in-maglev-but-not-turboshaft.js @@ -0,0 +1,27 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +function foo(x) { + for (let i = 0; i < 10; ) { + i++; + let v1 = i << 2 | i >>> 28; + let v2 = i >>> 28 | i << 2; + // Turboshaft's MachineOptimizationReducer will optimize both {v1} and {v2} + // to a simple rotation by 2, and GVN will merge them into a single + // operation (all of this during TurbolevGraphBuilding). This means that + // this loop in Maglev (that doesn't realize that {v1} and {v2} are the + // same), but not in Turboshaft (that realizes that the `break` is always + // taken). + if (v1 == v2) break; + } +} + +%PrepareFunctionForOptimization(foo); +foo(); +foo(); + +%OptimizeFunctionOnNextCall(foo); +foo(); diff --git a/deps/v8/test/mjsunit/turbolev/new-closure-tenured.js b/deps/v8/test/mjsunit/turbolev/new-closure-tenured.js deleted file mode 100644 index 1b075fb19c4c..000000000000 --- a/deps/v8/test/mjsunit/turbolev/new-closure-tenured.js +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Flags: --allow-natives-syntax --turbolev --turbofan - -function create_closure(v) { - let o = {}; - let x = 4; - o.x = (c) => v + x++ + 2 + c; - return o; -} - -%PrepareFunctionForOptimization(create_closure); -let o = create_closure(7); -%PretenureAllocationSite(o.x); -o = create_closure(7); - -%OptimizeFunctionOnNextCall(create_closure); -o = create_closure(7); -assertEquals(7+4+2+2, o.x(2)); -assertEquals(7+5+2+5, o.x(5)); -assertOptimized(create_closure); diff --git a/deps/v8/test/mjsunit/turbolev/regress-505610970.js b/deps/v8/test/mjsunit/turbolev/regress-505610970.js index 717b052f0281..fbeac59de688 100644 --- a/deps/v8/test/mjsunit/turbolev/regress-505610970.js +++ b/deps/v8/test/mjsunit/turbolev/regress-505610970.js @@ -7,7 +7,8 @@ function foo() { const v1 = ("string").normalize(); const v4 = new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([ - 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x61, 0x73, 0x6d, // wasm magic + 0x01, 0x00, 0x00, 0x00, // wasm version ]))); const v5 = v4.exports; for (let v6 = 0; v6 < 5; v6++) { diff --git a/deps/v8/test/mjsunit/turbolev/regress-564329221.js b/deps/v8/test/mjsunit/turbolev/regress-564329221.js new file mode 100644 index 000000000000..2fa16e7e0eb4 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-564329221.js @@ -0,0 +1,22 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --turbolev --turbolev-future --allow-natives-syntax +// Flags: --no-maglev-range-analysis --no-turbolev-untagged-phis + +function foo(m) { + let it = m.entries(); + let res = it.next().value; + return res[0]; +} + +let m = new Map(); +m.set(1, 2); + +%PrepareFunctionForOptimization(foo); +foo(m); +foo(m); + +%OptimizeFunctionOnNextCall(foo); +foo(m); diff --git a/deps/v8/test/mjsunit/turbolev/regress-567993838.js b/deps/v8/test/mjsunit/turbolev/regress-567993838.js new file mode 100644 index 000000000000..2d6b5705bbb5 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-567993838.js @@ -0,0 +1,32 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev +// +// Inlining `inner(x, 0.5)` into `outer` feeds a non-safe-int constant `0.5` +// into `c + b` while both additions carry `AdditiveSafeInteger` feedback. +// Backward truncation propagation must reject `c + 0.5` and its input `x + 1`. + +let should_throw = false; +function inner(x, b) { + if (should_throw) throw 1; + let c = x + 1; + return (c + b) | 0; +} + +%PrepareFunctionForOptimization(inner); +inner(0x100000000, 0x100000000); + +function outer(x) { + return inner(x, 0.5); +} + +%PrepareFunctionForOptimization(outer); +should_throw = true; +try { outer(10); } catch {} +should_throw = false; + +%OptimizeFunctionOnNextCall(outer); +assertEquals(11, outer(10)); +assertEquals(-2147483648, outer(-2147483650)); diff --git a/deps/v8/test/mjsunit/turbolev/regress-568010379.js b/deps/v8/test/mjsunit/turbolev/regress-568010379.js new file mode 100644 index 000000000000..eaa39a1c7e53 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-568010379.js @@ -0,0 +1,48 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +function noop(a) { + let r = a + 1; + r = r + 2; + r = r + 3; + r = r + 4; + r = r + 5; + r = r + 6; + r = r + 7; + return r; +} + +function dummy() {} + +function outer(trigger) { + let x = 1; + function mid() { + let a0 = 0, a1 = 1, a2 = 2, a3 = 3, a4 = 4, + a5 = 5, a6 = 6, a7 = 7, a8 = 8, a9 = 9, + a10 = 10, a11 = 11, a12 = 12, a13 = 13, a14 = 14; + return function f() { + x = 2; + return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + + a8 + a9 + a10 + a11 + a12 + a13 + a14; + }; + } + + let box = { fn: dummy }; + box.fn = mid(); + x = 1; + noop(trigger); + let g = box.fn; + g(); + return x; +} + +%PrepareFunctionForOptimization(noop); +%PrepareFunctionForOptimization(outer); +for (let i = 0; i < 10; i++) { + assertEquals(2, outer(i)); +} +%OptimizeFunctionOnNextCall(outer); +assertEquals(2, outer(10)); diff --git a/deps/v8/test/mjsunit/turbolev/regress-571002038.js b/deps/v8/test/mjsunit/turbolev/regress-571002038.js new file mode 100644 index 000000000000..676141d2b988 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-571002038.js @@ -0,0 +1,65 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +function makeScopeAClosure(capturedA) { + let a0 = capturedA; + let a1 = a0 + 1; + return function scopeAClosure() { + let sum = a0 + a1; + for (let i = 0; i < 4; i++) { + sum += i; + sum ^= i; + sum += a0; + sum ^= a1; + } + return sum; + }; +} + +const closureA1 = makeScopeAClosure(1); +const closureA2 = makeScopeAClosure(2); + +function makeScopeBFactory() { + let capturedB = 10; + return function closureFactory(whichScopeA) { + let sum = capturedB + 1; + if (whichScopeA === 1) return closureA1; + if (whichScopeA === 2) return closureA2; + return function scopeBClosure() { + return sum; + }; + }; +} + +const closureFactory = makeScopeBFactory(); + +function callClosureFromFactory(whichScopeA, callIt) { + const fn = closureFactory(whichScopeA); + if (callIt) { + return fn(); + } + return 0; +} + +function triggerMismatch(callIt) { + return callClosureFromFactory(0, callIt); +} + +%PrepareFunctionForOptimization(closureA1); +%PrepareFunctionForOptimization(closureFactory); +%PrepareFunctionForOptimization(callClosureFromFactory); +%PrepareFunctionForOptimization(triggerMismatch); + +closureFactory(1); +closureFactory(2); +closureFactory(0); + +callClosureFromFactory(1, true); +callClosureFromFactory(2, true); + +triggerMismatch(false); +%OptimizeFunctionOnNextCall(triggerMismatch); +triggerMismatch(true); diff --git a/deps/v8/test/mjsunit/turbolev/regress-forin-type-confusion.js b/deps/v8/test/mjsunit/turbolev/regress-forin-type-confusion.js new file mode 100644 index 000000000000..252a5c2bf70c --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/regress-forin-type-confusion.js @@ -0,0 +1,44 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +function firstKeyViaForIn(o) { + for (const k in o) { return k; } + return 'empty'; +} + +%PrepareFunctionForOptimization(firstKeyViaForIn); + +const arr = [1]; +firstKeyViaForIn(arr); +firstKeyViaForIn(arr); + +%OptimizeFunctionOnNextCall(firstKeyViaForIn); +firstKeyViaForIn(arr); + +// It should stay optimized because generic ForIn calls the ForIn builtins. +assertEquals("0", firstKeyViaForIn(arr)); +assertOptimized(firstKeyViaForIn); + +(function() { + function firstKeyEnumCache(o) { + for (const k in o) { return k; } + return 'empty'; + } + %PrepareFunctionForOptimization(firstKeyEnumCache); + + const obj = {a: 1}; + assertEquals("a", firstKeyEnumCache(obj)); + assertEquals("a", firstKeyEnumCache(obj)); + + %OptimizeFunctionOnNextCall(firstKeyEnumCache); + assertEquals("a", firstKeyEnumCache(obj)); + assertOptimized(firstKeyEnumCache); + + // Passing an array returns a ForInEnumeratorHolder, which must safely deopt + // when compiled for ForInHint::kEnumCacheKeysAndIndices instead of + // type-confusing ForInEnumeratorHolder with Map. + assertEquals("0", firstKeyEnumCache([1])); +})(); diff --git a/deps/v8/test/mjsunit/turbolev/store-const-heap-number.js b/deps/v8/test/mjsunit/turbolev/store-const-heap-number.js new file mode 100644 index 000000000000..cbb2efae2614 --- /dev/null +++ b/deps/v8/test/mjsunit/turbolev/store-const-heap-number.js @@ -0,0 +1,21 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev --turbofan + +globalThis.y = 1.5; // PropertyCellType::kConstant (HeapNumber) +globalThis.z = 1.5; +globalThis.z = 2.5; // PropertyCellType::kConstantType (HeapNumber) +globalThis.z = 1.5; + +function store() { + y = z; +} + +%PrepareFunctionForOptimization(store); +store(); +store(); +%OptimizeFunctionOnNextCall(store); +store(); +assertOptimized(store); diff --git a/deps/v8/test/mjsunit/turboshaft/couldhavesamemap-poly-poly.js b/deps/v8/test/mjsunit/turboshaft/couldhavesamemap-poly-poly.js new file mode 100644 index 000000000000..313659cf3d88 --- /dev/null +++ b/deps/v8/test/mjsunit/turboshaft/couldhavesamemap-poly-poly.js @@ -0,0 +1,49 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --turbolev + +const funcs = []; +for (let i = 0; i < 20; i++) { + const fn = new Function('a', 'b', ` + /* test_id_${i} */ + let v1 = a.x; // polymorphic + b.x = 42; // polymorphic + let v2 = a.x; // can we eliminate this load? + return v1 + v2; + `); + + const a_objs = [ + {x: 1, a1: 1, ['dummy_a_' + i]: 1}, + {x: 2, a2: 2, ['dummy_a_' + i]: 2}, + {x: 3, a3: 3, ['dummy_a_' + i]: 3}, + {x: 4, a4: 4, ['dummy_a_' + i]: 4}, + ]; + // Make this field mutable + for (let a of a_objs) a.x = 10; + + const b_objs = [ + {x: 1, b1: 1, ['dummy_b_' + i]: 1}, + {x: 2, b2: 2, ['dummy_b_' + i]: 2}, + {x: 3, b3: 3, ['dummy_b_' + i]: 3}, + {x: 4, b4: 4, ['dummy_b_' + i]: 4}, + ]; + // Make this field mutable + for (let b of b_objs) b.x = 10; + + funcs.push({fn, a_objs, b_objs}); +} + +for (let {fn, a_objs, b_objs} of funcs) { + %PrepareFunctionForOptimization(fn); + for (let j = 0; j < 4; j++) { + fn(a_objs[j], b_objs[j]); + } + %OptimizeFunctionOnNextCall(fn); + const result = fn(a_objs[0], b_objs[0]); + // Unfortunately we cannot observe whether the load was eliminated, we can + // only assert the result. Run with --turboshaft-trace-load-elimination to + // observe the load being eliminated. + assertEquals(20, result); +} diff --git a/deps/v8/test/mjsunit/turboshaft/reduce-strictly-less-than.js b/deps/v8/test/mjsunit/turboshaft/reduce-strictly-less-than.js new file mode 100644 index 000000000000..18e10c319739 --- /dev/null +++ b/deps/v8/test/mjsunit/turboshaft/reduce-strictly-less-than.js @@ -0,0 +1,35 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbolev + +// Signed 32-bit integer comparison: (x | 0) +function test_signed_lt(x) { + x = x | 0; + let y = (x + 1) | 0; + y = (y - 1) | 0; // Simplified to x + return x < y; // Lowers to Turboshaft kSignedLessThan (Word32) +} + +function test_signed_le(x) { + x = x | 0; + let y = (x + 1) | 0; + y = (y - 1) | 0; // Simplified to x + return x <= y; // Lowers to Turboshaft kSignedLessThanOrEqual (Word32) +} + +%PrepareFunctionForOptimization(test_signed_lt); +%PrepareFunctionForOptimization(test_signed_le); + +assertFalse(test_signed_lt(42)); +assertTrue(test_signed_le(42)); + +%OptimizeFunctionOnNextCall(test_signed_lt); +%OptimizeFunctionOnNextCall(test_signed_le); + +assertFalse(test_signed_lt(42)); +assertTrue(test_signed_le(42)); + +assertOptimized(test_signed_lt); +assertOptimized(test_signed_le); diff --git a/deps/v8/test/mjsunit/turboshaft/regress-574660146.js b/deps/v8/test/mjsunit/turboshaft/regress-574660146.js new file mode 100644 index 000000000000..bc82a2684baa --- /dev/null +++ b/deps/v8/test/mjsunit/turboshaft/regress-574660146.js @@ -0,0 +1,41 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --turbofan --no-maglev + +function cb() { + return arguments.length; +} +%NeverOptimizeFunction(cb); + +// Passing `kArgCount` distinct expressions to a non-inlined call keeps all of +// them live simultaneously at the call site, requiring > 1024 stack slots +// (> 4KB on both 32-bit and 64-bit targets) while keeping the bytecode small +// enough to be compiled. +const kArgCount = 1100; +const args = Array.from({length: kArgCount}, (_, k) => `p ^ ${k + 1}`); + +function buildWideFrame(osr) { + return Function('x', 'cb', 'p', ` + let result = 0; + for (let i = 0; i < 10; ++i) { + ${osr ? 'if (i === 5) %OptimizeOsr();' : ''} + if (x < 0) return cb(${args}); + result = (x + i) | 0; + } + return result; + `); +} + +const wide = buildWideFrame(false); +%PrepareFunctionForOptimization(wide); +assertEquals(kArgCount, wide(-1, cb, 1)); +assertEquals(10, wide(1, cb, 1)); +%OptimizeFunctionOnNextCall(wide); +assertEquals(10, wide(1, cb, 1)); + +const wideOsr = buildWideFrame(true); +%PrepareFunctionForOptimization(wideOsr); +assertEquals(kArgCount, wideOsr(-1, cb, 1)); +assertEquals(10, wideOsr(1, cb, 1)); diff --git a/deps/v8/test/mjsunit/wasm/compilation-hints/hints-and-deopts.js b/deps/v8/test/mjsunit/wasm/compilation-hints/hints-and-deopts.js new file mode 100644 index 000000000000..6399b9676a8a --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/compilation-hints/hints-and-deopts.js @@ -0,0 +1,181 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-compilation-hints --wasm-wasmfx --liftoff +// Flags: --wasm-dynamic-tiering --wasm-tiering-budget=5 --no-predictable +// Flags: --allow-natives-syntax --wasm-deopt + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +(function HintsAndDeopts() { + print(arguments.callee.name); + + let builder = new WasmModuleBuilder(); + + let sig = builder.addType(kSig_i_ii); + + let add = builder.addFunction("add", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add]); + + let sub = builder.addFunction("sub", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Sub]); + + let intermediate = builder.addFunction("intermediate", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprRefFunc, add.index, + kExprCallRef, sig]); + + let caller = builder.addFunction("caller", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, + kExprRefFunc, intermediate.index, kExprCallRef, sig]) + .exportFunc(); + + builder.addDeclarativeElementSegment([ + add.index, sub.index, intermediate.index]); + + builder.setCompilationPriority(caller.index, 0, 0); + + builder.setInstructionFrequencies( + intermediate.index, [{offset: 7, frequency: 32}]); + builder.setCallTargets(intermediate.index, + [{offset: 7, + targets: [ + {function_index: sub.index, frequency_percent: 100}]}]); + + builder.setInstructionFrequencies( + caller.index, [{offset: 7, frequency: 32}]); + builder.setCallTargets(caller.index, + [{offset: 7, + targets: [ + {function_index: intermediate.index, frequency_percent: 100}]}]); + + let wasm = builder.instantiate().exports; + + while (!%IsTurboFanFunction(wasm.caller)) {} + + assertEquals(15, wasm.caller(10, 5)); + + // Deopt happened. + assertTrue(%IsLiftoffFunction(wasm.caller)); + + while (%IsLiftoffFunction(wasm.caller)) { + assertEquals(15, wasm.caller(10, 5)); + } + + // Recompiled with turbofan with dynamic tiering. + assertTrue(%IsTurboFanFunction(wasm.caller)); + + assertEquals(15, wasm.caller(10, 5)); + + // Recompiled with feedback this time; no deopt loops. + assertTrue(%IsTurboFanFunction(wasm.caller)); +})(); + +// This test counts on cont.new not being implemented in Liftoff. +(function HintsAndDeoptsLiftoffBailout() { + print(arguments.callee.name); + + let builder = new WasmModuleBuilder(); + + let sig = builder.addType(kSig_i_ii); + + let cont = builder.addCont(sig); + + let add = builder.addFunction("add", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add]); + + let sub = builder.addFunction("sub", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Sub]); + + let intermediate = builder.addFunction("intermediate", sig) + .addBody([kExprRefFunc, add.index, kExprContNew, cont, kExprDrop, + kExprLocalGet, 0, kExprLocalGet, 1, kExprRefFunc, add.index, + kExprCallRef, sig]); + + let caller = builder.addFunction("caller", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, + kExprRefFunc, intermediate.index, kExprCallRef, sig]) + .exportFunc(); + + builder.addDeclarativeElementSegment([ + add.index, sub.index, intermediate.index]); + + builder.setCompilationPriority(caller.index, 0, 0); + + builder.setInstructionFrequencies( + intermediate.index, [{offset: 12, frequency: 32}]); + builder.setCallTargets(intermediate.index, + [{offset: 12, + targets: [ + {function_index: sub.index, frequency_percent: 100}]}]); + + builder.setInstructionFrequencies( + caller.index, [{offset: 7, frequency: 32}]); + builder.setCallTargets(caller.index, + [{offset: 7, + targets: [ + {function_index: intermediate.index, frequency_percent: 100}]}]); + + let wasm = builder.instantiate().exports; + + while (!%IsTurboFanFunction(wasm.caller)) {} + + assertEquals(15, wasm.caller(10, 5)); + + // Deopt did not happen: Since Liftoff compilation failed for intermediate, + // we bailed out from deopts. + assertTrue(%IsTurboFanFunction(wasm.caller)); +})(); + +(function HintsAndDeoptsLiftoffBailoutInTailCaller() { + print(arguments.callee.name); + + let builder = new WasmModuleBuilder(); + + let sig = builder.addType(kSig_i_ii); + + let cont = builder.addCont(sig); + + let add = builder.addFunction("add", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add]); + + let sub = builder.addFunction("sub", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Sub]); + + let intermediate = builder.addFunction("intermediate", sig) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprRefFunc, add.index, + kExprCallRef, sig]); + + let caller = builder.addFunction("caller", sig) + .addBody([kExprRefFunc, add.index, kExprContNew, cont, kExprDrop, + kExprLocalGet, 0, kExprLocalGet, 1, + kExprRefFunc, intermediate.index, kExprReturnCallRef, sig]) + .exportFunc(); + + builder.addDeclarativeElementSegment([ + add.index, sub.index, intermediate.index]); + + builder.setCompilationPriority(caller.index, 0, 0); + + builder.setInstructionFrequencies( + intermediate.index, [{offset: 7, frequency: 32}]); + builder.setCallTargets(intermediate.index, + [{offset: 7, + targets: [ + {function_index: sub.index, frequency_percent: 100}]}]); + + builder.setInstructionFrequencies( + caller.index, [{offset: 12, frequency: 32}]); + builder.setCallTargets(caller.index, + [{offset: 12, + targets: [ + {function_index: intermediate.index, frequency_percent: 100}]}]); + + let wasm = builder.instantiate().exports; + + while (!%IsTurboFanFunction(wasm.caller)) {} + + assertEquals(15, wasm.caller(10, 5)); + + assertTrue(%IsTurboFanFunction(wasm.caller)); +})(); diff --git a/deps/v8/test/mjsunit/wasm/compiled-module-serialization.js b/deps/v8/test/mjsunit/wasm/compiled-module-serialization.js index 20b1bfed34cb..2e63f91aa02b 100644 --- a/deps/v8/test/mjsunit/wasm/compiled-module-serialization.js +++ b/deps/v8/test/mjsunit/wasm/compiled-module-serialization.js @@ -440,6 +440,16 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); serialized_bytes_no_builtins, wire_bytes, kStringBuiltins), Error, /Deserialization failed/); + // Exceptions thrown while reading compile-time imports propagate directly. + assertThrows( + () => d8.wasm.deserializeModule( + serialized_bytes_string_builtins, wire_bytes, { + get builtins() { + throw new TypeError('custom error'); + } + }), + TypeError, /custom error/); + // Deserialization succeeds on matching builtins. assertInstanceof( d8.wasm.deserializeModule(serialized_bytes_no_builtins, wire_bytes), diff --git a/deps/v8/test/mjsunit/wasm/custom-descriptors-validity.js b/deps/v8/test/mjsunit/wasm/custom-descriptors-validity.js index 980265f269f8..37e888d1a9bb 100644 --- a/deps/v8/test/mjsunit/wasm/custom-descriptors-validity.js +++ b/deps/v8/test/mjsunit/wasm/custom-descriptors-validity.js @@ -141,6 +141,18 @@ CheckValid((builder) => { builder.addStruct({describes: 2, supertype: 1}); // 3 }); +// Canonically equivalent supertypes across separate recgroups. +CheckValid((builder) => { + builder.addStruct({descriptor: 1, final: false}); // 0 + builder.addStruct({describes: 0, final: false}); // 1 +}, (builder) => { + builder.addStruct({descriptor: 3, final: false}); // 2 + builder.addStruct({describes: 2, final: false}); // 3 +}, (builder) => { + builder.addStruct({descriptor: 5, supertype: 0}); // 4 + builder.addStruct({describes: 4, supertype: 3}); // 5 +}); + CheckInvalid(/type 3 has invalid explicit supertype 0/, (builder) => { builder.addStruct({final: false}); // 0 }, (builder) => { diff --git a/deps/v8/test/mjsunit/wasm/debug-set-breakpoint-on-entry.js b/deps/v8/test/mjsunit/wasm/debug-set-breakpoint-on-entry.js deleted file mode 100644 index dca14e01ca70..000000000000 --- a/deps/v8/test/mjsunit/wasm/debug-set-breakpoint-on-entry.js +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector - -let breakpoint_resolved = false; - -globalThis.receive = (msg) => { - let m = JSON.parse(msg); - if (m.method === 'Debugger.scriptParsed' && m.params.url.startsWith('wasm://')) { - send(JSON.stringify({ - id: 2, - method: 'Debugger.setBreakpoint', - params: { - location: { - scriptId: m.params.scriptId, - lineNumber: 0, - columnNumber: -1 // -1 is not a valid regular breakpoint position. - } - } - })); - } - if (m.id === 2) { - breakpoint_resolved = true; - assertTrue(!!m.error, 'Breakpoint at -1 should fail'); - assertEquals('Could not resolve breakpoint', m.error.message); - } -}; - -send(JSON.stringify({id: 1, method: 'Debugger.enable'})); -new WebAssembly.Module(new Uint8Array([0, 0x61, 0x73, 0x6d, 1, 0, 0, 0])); - -assertTrue(breakpoint_resolved); diff --git a/deps/v8/test/mjsunit/wasm/denormals.js b/deps/v8/test/mjsunit/wasm/denormals.js deleted file mode 100644 index b4a86a875116..000000000000 --- a/deps/v8/test/mjsunit/wasm/denormals.js +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2025 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --allow-natives-syntax - -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); - -let builder = new WasmModuleBuilder(); - -builder.addFunction("flushed", kSig_i_v).exportFunc().addBody([ - ...wasmF64Const(Number.MIN_VALUE), - ...wasmF64Const(2), - kExprF64Mul, - ...wasmF64Const(0), - kExprF64Eq, - kExprIf, kWasmI32, - kExprI32Const, 1, - kExprElse, - kExprI32Const, 0, - kExprEnd, -]); - -let inst1 = builder.instantiate(); -assertEquals(0, inst1.exports.flushed()); -d8.test.setFlushDenormals(true); -let inst2 = builder.instantiate(); -let result1 = %IsLiftoffFunction(inst1.exports.flushed) ? 1 : 0; -assertEquals(result1, inst1.exports.flushed()); -assertEquals(1, inst2.exports.flushed()); -d8.test.setFlushDenormals(false); -assertEquals(0, inst1.exports.flushed()); -let result2 = %IsLiftoffFunction(inst2.exports.flushed) ? 0 : 1; -assertEquals(result2, inst2.exports.flushed()); diff --git a/deps/v8/test/mjsunit/wasm/esm/module-import-source.mjs b/deps/v8/test/mjsunit/wasm/esm/module-import-source.mjs index 43d8e1fe64a0..6f35db391b59 100644 --- a/deps/v8/test/mjsunit/wasm/esm/module-import-source.mjs +++ b/deps/v8/test/mjsunit/wasm/esm/module-import-source.mjs @@ -5,9 +5,21 @@ // Flags: --js-source-phase-imports --allow-natives-syntax import source mod from '../incrementer.wasm'; +import source async from '../incrementer.wasm'; +import source get from '../incrementer.wasm'; +import source set from '../incrementer.wasm'; +import source using from '../incrementer.wasm'; +import source of from '../incrementer.wasm'; +import source accessor from '../incrementer.wasm'; assertEquals(Object.getPrototypeOf(mod), WebAssembly.Module.prototype); assertEquals(mod[Symbol.toStringTag], 'WebAssembly.Module'); +assertEquals(async, mod); +assertEquals(get, mod); +assertEquals(set, mod); +assertEquals(using, mod); +assertEquals(of, mod); +assertEquals(accessor, mod); var AbstractModuleSource = %GetAbstractModuleSource(); var ToStringTag = Object diff --git a/deps/v8/test/mjsunit/wasm/gc-casts-branch.js b/deps/v8/test/mjsunit/wasm/gc-casts-branch.js new file mode 100644 index 000000000000..ee5fefadba27 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/gc-casts-branch.js @@ -0,0 +1,223 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-custom-descriptors + +// Type checks against an rtt (br_on_cast, br_on_cast_fail, ref.test) whose +// result is only used by a branch are lowered directly into that branch by +// the optimizing compiler. Check all these forms against the value form, for +// various source and target types. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +let builder = new WasmModuleBuilder(); +builder.startRecGroup(); +let $base = builder.addStruct([makeField(kWasmI32, true)]); +let $sub1 = builder.addStruct( + {fields: [makeField(kWasmI32, true)], supertype: $base}); +let $sub2 = builder.addStruct( + {fields: [makeField(kWasmI32, true)], supertype: $sub1}); +// At depth 3, the supertype array of the object's type is bounds-checked. +let $sub3 = builder.addStruct( + {fields: [makeField(kWasmI32, true)], supertype: $sub2}); +let $sub4 = builder.addStruct( + {fields: [makeField(kWasmI32, true)], supertype: $sub3}); +let $final = builder.addStruct( + {fields: [makeField(kWasmI32, true)], supertype: $base, final: true}); +let $other = builder.addStruct([makeField(kWasmI64, true)]); +let $array = builder.addArray(kWasmI32, {mutable: true}); +// Types with custom descriptors: exact casts check the immediate supertype of +// the object's map. +let $desc = builder.nextTypeIndex() + 1; +let $described = builder.addStruct({fields: [], descriptor: $desc}); +builder.addStruct({fields: [], describes: $described}); +let $desc_sub = builder.nextTypeIndex() + 1; +let $described_sub = builder.addStruct( + {fields: [], supertype: $described, descriptor: $desc_sub}); +builder.addStruct({fields: [], supertype: $desc, describes: $described_sub}); +builder.endRecGroup(); + +let $nop = builder.addImport('m', 'nop', kSig_v_v); + +// The supertypes of each struct type (including itself). +let supertypes = { + [$base]: [$base], + [$sub1]: [$sub1, $base], + [$sub2]: [$sub2, $sub1, $base], + [$sub3]: [$sub3, $sub2, $sub1, $base], + [$sub4]: [$sub4, $sub3, $sub2, $sub1, $base], + [$final]: [$final, $base], + [$other]: [$other], + [$array]: [$array], + [$described]: [$described], + [$described_sub]: [$described_sub, $described], +}; + +// Functions creating the Wasm values. +for (let type of [$base, $sub1, $sub2, $sub3, $sub4, $final]) { + builder.addFunction('make' + type, makeSig([], [kWasmAnyRef])) + .exportFunc() + .addBody([kExprI32Const, 7, kGCPrefix, kExprStructNew, type]); +} +builder.addFunction('make' + $other, makeSig([], [kWasmAnyRef])) + .exportFunc() + .addBody([kExprI64Const, 7, kGCPrefix, kExprStructNew, $other]); +builder.addFunction('make' + $array, makeSig([], [kWasmAnyRef])) + .exportFunc() + .addBody([kExprI32Const, 7, kGCPrefix, kExprArrayNewFixed, $array, 1]); +builder.addFunction('make' + $described, makeSig([], [kWasmAnyRef])) + .exportFunc() + .addBody([ + kGCPrefix, kExprStructNew, $desc, + kGCPrefix, kExprStructNewDesc, $described, + ]); +builder.addFunction('make' + $described_sub, makeSig([], [kWasmAnyRef])) + .exportFunc() + .addBody([ + kGCPrefix, kExprStructNew, $desc_sub, + kGCPrefix, kExprStructNewDesc, $described_sub, + ]); +builder.addFunction('makeI31', makeSig([], [kWasmAnyRef])) + .exportFunc() + .addBody([kExprI32Const, 42, kGCPrefix, kExprRefI31]); + +// Source types: anyref (casts from any also check that the object is a Wasm +// object) and (ref null $base) (the object cannot be an i31). +let sources = [ + {name: 'any', type: wasmRefNullType(kWasmAnyRef), accepts: (v) => true}, + { + name: 'base', + type: wasmRefNullType($base), + accepts: (v) => v.kind == 'null' || + (v.kind == 'struct' && supertypes[v.type].includes($base)) + }, +]; + +// Target types, nullable or not, possibly exact. +let targets = []; +for (let type of [$base, $sub1, $sub3, $final]) { + for (let nullable of [false, true]) targets.push({type, nullable}); +} +targets.push({type: $sub3, nullable: false, exact: true}); +targets.push({type: $described, nullable: false, exact: true}); +targets.push({type: $described, nullable: true, exact: true}); +targets.push({type: $described, nullable: false}); + +function heapType(target) { + let type = target.nullable ? wasmRefNullType(target.type) : + wasmRefType(target.type); + return target.exact ? type.exact() : type; +} + +function refTest(target) { + return [ + kGCPrefix, target.nullable ? kExprRefTestNull : kExprRefTest, + ...(target.exact ? [kWasmExact] : []), ...wasmSignedLeb(target.type) + ]; +} + +let tests = []; +for (let source of sources) { + for (let target of targets) { + // Only the targets that are subtypes of the source. + if (source.name == 'base' && + !supertypes[target.type].includes($base)) { + continue; + } + let name = `${source.name}_${target.type}_${target.nullable ? 'null' : ''}` + + `${target.exact ? 'exact' : ''}`; + let sig = makeSig([source.type, kWasmI32], [kWasmI32]); + let forms = {}; + // ref.test as a value (stored into a local and returned). + forms.value = builder.addFunction('value_' + name, sig).exportFunc() + .addLocals(kWasmI32, 1) + .addBody([ + kExprLocalGet, 0, ...refTest(target), kExprLocalSet, 2, + kExprLocalGet, 2, + ]); + // if on a ref.test. + forms.if = builder.addFunction('if_' + name, sig).exportFunc() + .addBody([ + kExprLocalGet, 0, ...refTest(target), + kExprIf, kWasmI32, kExprI32Const, 1, kExprElse, kExprI32Const, 0, + kExprEnd, + ]); + // A ref.test in a different block from the branch using it. + forms.separate = builder.addFunction('separate_' + name, sig).exportFunc() + .addLocals(kWasmI32, 1) + .addBody([ + kExprLocalGet, 0, ...refTest(target), kExprLocalSet, 2, + kExprLocalGet, 1, kExprIf, kWasmVoid, kExprCallFunction, $nop, + kExprEnd, + kExprLocalGet, 2, + kExprIf, kWasmI32, kExprI32Const, 1, kExprElse, kExprI32Const, 0, + kExprEnd, + ]); + // br_on_cast. + forms.br_on_cast = builder.addFunction('br_on_cast_' + name, sig) + .exportFunc() + .addBody([ + kExprBlock, kAnyRefCode, + kExprLocalGet, 0, + ...wasmBrOnCast(0, source.type, heapType(target)), + kExprDrop, kExprI32Const, 0, kExprReturn, + kExprEnd, + kExprDrop, kExprI32Const, 1, + ]); + // br_on_cast_fail. + forms.br_on_cast_fail = builder.addFunction('br_on_cast_fail_' + name, sig) + .exportFunc() + .addBody([ + kExprBlock, kAnyRefCode, + kExprLocalGet, 0, + ...wasmBrOnCastFail(0, source.type, heapType(target)), + kExprDrop, kExprI32Const, 1, kExprReturn, + kExprEnd, + kExprDrop, kExprI32Const, 0, + ]); + tests.push({name, source, target, forms}); + } +} + +let instance = builder.instantiate({m: {nop: () => {}}}); +let exports = instance.exports; + +let values = [{name: 'null', kind: 'null', value: null}]; +values.push({name: 'i31', kind: 'i31', value: exports.makeI31()}); +for (let type in supertypes) { + values.push({ + name: 'struct' + type, + kind: 'struct', + type: Number(type), + value: exports['make' + type]() + }); +} +values.push({name: 'object', kind: 'js', value: {}}); +values.push({name: 'string', kind: 'js', value: 'foo'}); +values.push({name: 'number', kind: 'js', value: 1.5}); + +function expected(target, v) { + if (v.kind == 'null') return target.nullable ? 1 : 0; + if (v.kind != 'struct') return 0; + if (target.exact) return v.type == target.type ? 1 : 0; + return supertypes[v.type].includes(target.type) ? 1 : 0; +} + +function runAll() { + for (let test of tests) { + for (let v of values) { + if (!test.source.accepts(v)) continue; + let want = expected(test.target, v); + for (let form in test.forms) { + for (let flag of [0, 1]) { + assertEquals( + want, exports[`${form}_${test.name}`](v.value, flag), + `${form}_${test.name}(${v.name}, ${flag})`); + } + } + } + } +} + +runAll(); diff --git a/deps/v8/test/mjsunit/wasm/growable-stacks-simd.js b/deps/v8/test/mjsunit/wasm/growable-stacks-simd.js new file mode 100644 index 000000000000..24dfd06a941a --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/growable-stacks-simd.js @@ -0,0 +1,155 @@ +// Copyright 2024 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --wasm-growable-stacks +// Flags: --expose-gc --stack-size=400 + +d8.file.execute('test/mjsunit/mjsunit.js'); +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +(function TestStackGrowSIMDS128() { + print(arguments.callee.name); + const builder = new WasmModuleBuilder(); + builder.addGlobal(kWasmI32, true).exportAs('depth'); + + // 10 s128 params and 4 s128 returns exceed GP/FP register limits on all + // architectures (max 8 FP param regs, max 2 FP return regs), ensuring both + // register and stack parameter/return slots are used across stack growth and + // return trampoline shrinking. + const kNumParams = 10; + const kNumReturns = 4; + const paramTypes = Array(kNumParams).fill(kWasmS128); + const returnTypes = Array(kNumReturns).fill(kWasmS128); + const sig = makeSig(paramTypes, returnTypes); + const import_index = builder.addImport('m', 'import', kSig_v_v); + const sig_if = builder.addType(makeSig([], returnTypes)); + const deep_calc = builder.addFunction('deep_calc', sig); + const simd_const = [kExprI32Const, 1, ...SimdInstr(kExprI32x4Splat)]; + + const recursive_args = []; + for (let i = 0; i < kNumParams; ++i) { + recursive_args.push( + kExprLocalGet, i, ...simd_const, ...SimdInstr(kExprI32x4Add)); + } + + // Return 2 register params (0, 1) and 2 stack params (8, 9) in the 4 return + // slots (2 register returns + 2 stack returns). + const return_indices = [0, 1, 8, 9]; + const base_returns = []; + for (const idx of return_indices) { + base_returns.push(kExprLocalGet, idx); + } + + deep_calc.addBody([ + kExprGlobalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprGlobalSet, 0, + + kExprGlobalGet, 0, + kExprIf, sig_if, + ...recursive_args, + kExprCallFunction, deep_calc.index, + kExprElse, + kExprCallFunction, import_index, + ...base_returns, + kExprEnd, + ]); + + const check_simd = + builder + .addFunction( + 'check_simd', + makeSig( + [kWasmS128, kWasmI32, kWasmI32, kWasmI32, kWasmI32], + [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + ...SimdInstr(kExprI32x4ExtractLane), 0, + kExprLocalGet, 1, + kExprI32Eq, + + kExprLocalGet, 0, + ...SimdInstr(kExprI32x4ExtractLane), 1, + kExprLocalGet, 2, + kExprI32Eq, + kExprI32And, + + kExprLocalGet, 0, + ...SimdInstr(kExprI32x4ExtractLane), 2, + kExprLocalGet, 3, + kExprI32Eq, + kExprI32And, + + kExprLocalGet, 0, + ...SimdInstr(kExprI32x4ExtractLane), 3, + kExprLocalGet, 4, + kExprI32Eq, + kExprI32And, + ]); + + const makeSimdConst = (base) => wasmS128Const([ + base + 1, 0, 0, 0, + base + 2, 0, 0, 0, + base + 3, 0, 0, 0, + base + 4, 0, 0, 0, + ]); + + const test_body = []; + for (let i = 0; i < kNumParams; ++i) { + test_body.push(...makeSimdConst(i * 10)); + } + test_body.push(kExprCallFunction, deep_calc.index); + // Store the 4 s128 returns into locals 1..4 (in reverse pop order: 4..1). + for (let r = kNumReturns; r >= 1; --r) { + test_body.push(kExprLocalSet, r); + } + + // Verify each of the 4 returned s128 values. + // Each recursive step with depth > 0 increments every lane by 1, so for + // initial depth D, each lane is incremented (D - 1) times. + // combined with base = idx * 10 + lane (1..4), expected value for lane L (0..3) + // is: (idx * 10 + L) + D. + for (let r = 0; r < kNumReturns; ++r) { + const paramIdx = return_indices[r]; + const baseOffset = paramIdx * 10; + test_body.push( + kExprLocalGet, r + 1, + kExprLocalGet, 0, + kExprI32Const, ...wasmSignedLeb(baseOffset), + kExprI32Add, + kExprLocalGet, 0, + kExprI32Const, ...wasmSignedLeb(baseOffset + 1), + kExprI32Add, + kExprLocalGet, 0, + kExprI32Const, ...wasmSignedLeb(baseOffset + 2), + kExprI32Add, + kExprLocalGet, 0, + kExprI32Const, ...wasmSignedLeb(baseOffset + 3), + kExprI32Add, + kExprCallFunction, check_simd.index, + ); + if (r > 0) { + test_body.push(kExprI32And); + } + } + + builder.addFunction('test', kSig_i_i) + .addLocals(kWasmS128, kNumReturns) + .addBody(test_body) + .exportFunc(); + + const js_import = new WebAssembly.Suspending(() => { + gc(); + return Promise.resolve(); + }); + + const instance = builder.instantiate({m: {import: js_import}}); + const wrapper = WebAssembly.promising(instance.exports.test); + + const depth = 430; + instance.exports.depth.value = depth; + + assertPromiseResult(wrapper(depth), res => assertEquals(res, 1)); +})(); diff --git a/deps/v8/test/mjsunit/wasm/growable-stacks.js b/deps/v8/test/mjsunit/wasm/growable-stacks.js index e9ba1d197cce..d24d803f00c6 100644 --- a/deps/v8/test/mjsunit/wasm/growable-stacks.js +++ b/deps/v8/test/mjsunit/wasm/growable-stacks.js @@ -15,7 +15,48 @@ function flatRange(upperBound, gen) { return res.flat(); } -function growAndShrinkTwice(depth, paramType, constFn, addOp, result, heavy = false) { +function addActiveLocals( + func, numParams, numLocals = 600, + seedExpr = [kExprLocalGet, 0, kExprI64UConvertI32]) { + func.addLocals(kWasmI64, numLocals + 1); + const firstLocal = numParams; + const lastLocal = numParams + numLocals - 1; + const sumIdx = numParams + numLocals; + const body = [ + ...seedExpr, + kExprI64Const, 1, + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(firstLocal), + ]; + for (let i = firstLocal + 1; i <= lastLocal; ++i) { + body.push( + kExprLocalGet, ...wasmUnsignedLeb(i - 1), + kExprI64Const, 1, + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(i), + ); + } + body.push(kExprI64Const, 0, kExprLocalSet, ...wasmUnsignedLeb(sumIdx)); + for (let i = firstLocal; i <= lastLocal; ++i) { + body.push( + kExprLocalGet, ...wasmUnsignedLeb(sumIdx), + kExprLocalGet, ...wasmUnsignedLeb(i), + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(sumIdx), + ); + } + body.push( + kExprLocalGet, ...wasmUnsignedLeb(sumIdx), + kExprI64Eqz, + kExprIf, kWasmVoid, + kExprUnreachable, + kExprEnd, + ); + return body; +} + +function growAndShrinkTwice( + depth, paramType, constFn, addOp, result, heavy = false) { const builder = new WasmModuleBuilder(); builder.addGlobal(kWasmI32, true).exportAs('depth'); // To cover the large frame stack check, make the import return 512 extra @@ -65,9 +106,7 @@ function growAndShrinkTwice(depth, paramType, constFn, addOp, result, heavy = fa ...flatRange(numIntArgs, constFn), kExprCallFunction, deep_calc.index, ]).exportFunc(); - const js_import = new WebAssembly.Suspending((...args) => { - return Promise.resolve(args.concat(Array(extra_returns).fill(0n))) - }) + const js_import = (...args) => args.concat(Array(extra_returns).fill(0n)); const instance = builder.instantiate({ m: { import: js_import } }); const wrapper = WebAssembly.promising(instance.exports.test); instance.exports.depth.value = depth; @@ -257,13 +296,11 @@ function growAndShrinkTwice(depth, paramType, constFn, addOp, result, heavy = fa print(arguments.callee.name); let builder = new WasmModuleBuilder(); - let main = builder.addFunction("main", kSig_v_v); - main.addLocals(kWasmI64, 8000); - main.addBody([ - ]).exportFunc(); + let main = builder.addFunction("main", kSig_v_i); + main.addBody(addActiveLocals(main, 1, 8000)).exportFunc(); let wasm = builder.instantiate().exports; - WebAssembly.promising(wasm.main)(); + WebAssembly.promising(wasm.main)(1); })(); (function TestMaxParameters() { @@ -273,16 +310,219 @@ function growAndShrinkTwice(depth, paramType, constFn, addOp, result, heavy = fa [kExprI32Const, 0, kSimdPrefix, kExprI32x4Splat]]; for (let i = 0; i < types.length; ++i) { let builder = new WasmModuleBuilder(); - let sig = builder.addType(makeSig(Array(kSpecMaxFunctionParams).fill(types[i]), [])); - let g = builder.addFunction('g', sig).addBody([]); + let globalIdx = + builder.addGlobal(kWasmI32, true, false, wasmI32Const(1)).index; + let sig = builder.addType( + makeSig(Array(kSpecMaxFunctionParams).fill(types[i]), [])); + let g = builder.addFunction('g', sig); + g.addBody(addActiveLocals( + g, kSpecMaxFunctionParams, 600, + [kExprGlobalGet, globalIdx, kExprI64UConvertI32])); + builder.appendToTable([g.index]); let f = builder.addFunction('f', kSig_v_v); let f_body = []; for (let j = 0; j < kSpecMaxFunctionParams; j++) { f_body.push(...default_value[i]); } - f_body.push(kExprCallFunction, g.index); + f_body.push(kExprI32Const, 0, kExprCallIndirect, sig, 0); f.addBody(f_body).exportFunc(); let instance = builder.instantiate(); WebAssembly.promising(instance.exports.f)(); } })(); + +(function TestTieringCallIndirect() { + print(arguments.callee.name); + const builder = new WasmModuleBuilder(); + const sig_index = builder.addType(makeSig([kWasmI32], [kWasmI32])); + + const target_A = + builder.addFunction('target_A', sig_index).addBody([kExprLocalGet, 0]); + + const target_B = builder.addFunction('target_B', sig_index).addBody([ + kExprLocalGet, 0, kExprI32Const, 2, kExprI32Add + ]); + + builder.appendToTable([target_A.index, target_B.index]); + + const test = + builder.addFunction('test', makeSig([kWasmI32, kWasmI32], [kWasmI32])); + test.addBody([ + ...addActiveLocals(test, 2, 100), + kExprLocalGet, 0, + kExprIf, kWasmVoid, + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprCallFunction, test.index, + kExprDrop, + kExprEnd, + kExprLocalGet, 1, + kExprLocalGet, 0, + kExprIf, kWasmI32, + kExprI32Const, 1, + kExprElse, + kExprI32Const, 0, + kExprEnd, + kExprCallIndirect, sig_index, 0, + ]) + .exportFunc(); + + const instance = builder.instantiate(); + const wrapper = WebAssembly.promising(instance.exports.test); + + wrapper(0, 42); + %WasmTierUpFunction(instance.exports.test); + + assertPromiseResult(wrapper(100, 42), res => assertEquals(44, res)); +})(); + +(function TestMutualTailRecursionVaryingSignatures() { + print(arguments.callee.name); + const builder = new WasmModuleBuilder(); + const gcImport = builder.addImport('m', 'gc', kSig_v_v); + const sigA = builder.addType(makeSig(Array(10).fill(kWasmI32), [kWasmI32])); + const sigB = builder.addType(makeSig(Array(20).fill(kWasmI32), [kWasmI32])); + const sigC = builder.addType(makeSig(Array(30).fill(kWasmI32), [kWasmI32])); + + const caller = builder.addFunction('caller', sigA).exportFunc(); + const funcA = builder.addFunction('funcA', sigA); + const funcB = builder.addFunction('funcB', sigB); + const funcC = builder.addFunction('funcC', sigC); + + const caller_body = []; + for (let i = 0; i < 10; ++i) caller_body.push(kExprLocalGet, i); + caller_body.push(kExprCallFunction, funcA.index); + caller.addBody(caller_body); + + const funcA_body = [ + ...addActiveLocals(funcA, 10, 1000), + kExprLocalGet, 0, + kExprI32Eqz, + kExprIf, kWasmVoid, + kExprCallFunction, gcImport, + kExprLocalGet, 1, + kExprReturn, + kExprEnd, + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprI32Const, 1, + kExprI32Add, + ]; + for (let i = 2; i < 10; ++i) funcA_body.push(kExprLocalGet, i); + for (let i = 10; i < 20; ++i) funcA_body.push(kExprI32Const, i); + funcA_body.push(kExprReturnCall, funcB.index); + funcA.addBody(funcA_body); + + const funcB_body = [ + ...addActiveLocals(funcB, 20, 2000), + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprI32Const, 2, + kExprI32Add, + ]; + for (let i = 2; i < 20; ++i) funcB_body.push(kExprLocalGet, i); + for (let i = 20; i < 30; ++i) funcB_body.push(kExprI32Const, i); + funcB_body.push(kExprReturnCall, funcC.index); + funcB.addBody(funcB_body); + + const funcC_body = [ + ...addActiveLocals(funcC, 30, 4000), + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprI32Const, 3, + kExprI32Add, + ]; + for (let i = 2; i < 10; ++i) funcC_body.push(kExprLocalGet, i); + funcC_body.push(kExprReturnCall, funcA.index); + funcC.addBody(funcC_body); + + const instance = builder.instantiate({m: {gc: () => gc()}}); + const promising_caller = WebAssembly.promising(instance.exports.caller); + + const rounds = 5; + const depth = rounds * 3; + const args = [depth, 0]; + for (let i = 2; i < 10; ++i) args.push(i); + assertPromiseResult( + promising_caller(...args), res => assertEquals(rounds * 6, res)); +})(); + +(function TestExceptionUnwindingAcrossSegments() { + print(arguments.callee.name); + const builder = new WasmModuleBuilder(); + const sig = builder.addType(makeSig([kWasmI32, kWasmI32], [kWasmI32])); + + const jsThrower = () => { + throw new Error('thrown from JS callback'); + }; + const imp = builder.addImport('env', 'jsThrower', makeSig([], [])); + + const step = builder.addFunction('step', sig); + step.addBody([ + ...addActiveLocals(step, 2, 600), + kExprLocalGet, 0, + kExprI32Eqz, + kExprIf, kWasmVoid, + kExprCallFunction, imp, + kExprI32Const, 0, + kExprReturn, + kExprEnd, + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprI32Const, 10, + kExprI32Add, + kExprCallFunction, step.index, + ]); + + const entry = builder.addFunction('entry', sig); + entry.addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kExprCallFunction, step.index, + ]); + + builder.addExport('main', entry.index); + const instance = builder.instantiate({env: {jsThrower}}); + const promising_main = WebAssembly.promising(instance.exports.main); + + assertPromiseResult( + promising_main(5, 0), v => assertUnreachable(), + e => assertEquals('thrown from JS callback', e.message)); +})(); + +(function TestJSPIPromisingTailCalls() { + print(arguments.callee.name); + const builder = new WasmModuleBuilder(); + const sig = builder.addType(makeSig([kWasmI32], [kWasmI32])); + + const recurse = builder.addFunction('recurse', sig); + recurse.addBody([ + kExprLocalGet, 0, + kExprI32Eqz, + kExprIf, kWasmVoid, + kExprI32Const, 42, + kExprReturn, + kExprEnd, + ...addActiveLocals(recurse, 1, 600), + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprReturnCall, recurse.index, + ]); + + builder.addExport('main', recurse.index); + const instance = builder.instantiate(); + const wrapper = WebAssembly.promising(instance.exports.main); + + assertPromiseResult(wrapper(5), res => assertEquals(42, res)); +})(); diff --git a/deps/v8/test/mjsunit/wasm/imported-dataview.js b/deps/v8/test/mjsunit/wasm/imported-dataview.js index 8ae6cd55afd6..64ce73421c09 100644 --- a/deps/v8/test/mjsunit/wasm/imported-dataview.js +++ b/deps/v8/test/mjsunit/wasm/imported-dataview.js @@ -300,7 +300,7 @@ let instance = MakeInstance(); let dataview = new DataView(buffer); instance.exports.setInt32(dataview, 0, 100, 1); - assertEquals(100, array[0]); + assertEquals(100, dataview.getInt32(0, true)); assertEquals(100, instance.exports.getInt32(dataview, 0, 1)); CheckDataViewErrorMessages('setInt32', array, false, 42); @@ -309,9 +309,9 @@ let instance = MakeInstance(); (function TestGetBigInt64() { print(arguments.callee.name); let array = new BigInt64Array(2); - array[0] = 0x7FFFFFFFFFFFFFFFn; - array[1] = 0x12345678n; let dataview = new DataView(array.buffer); + dataview.setBigInt64(0, 0x7FFFFFFFFFFFFFFFn, true); + dataview.setBigInt64(8, 0x12345678n, true); assertEquals( 0x7FFFFFFFFFFFFFFFn, instance.exports.getBigInt64(dataview, 0, 1)); @@ -325,9 +325,9 @@ let instance = MakeInstance(); (function TestGetBigUint64() { print(arguments.callee.name); let array = new BigUint64Array(2); - array[0] = 0x7FFFFFFFFFFFFFFFn; - array[1] = 0x12345678n; let dataview = new DataView(array.buffer); + dataview.setBigUint64(0, 0x7FFFFFFFFFFFFFFFn, true); + dataview.setBigUint64(8, 0x12345678n, true); assertEquals( 0x7FFFFFFFFFFFFFFFn, instance.exports.getBigUint64(dataview, 0, 1)); @@ -340,9 +340,9 @@ let instance = MakeInstance(); (function TestGetFloat32() { print(arguments.callee.name); let array = new Float32Array(2); - array[0] = 140.125; - array[1] = -2048.015625; let dataview = new DataView(array.buffer); + dataview.setFloat32(0, 140.125, true); + dataview.setFloat32(4, -2048.015625, true); assertEquals(140.125, instance.exports.getFloat32(dataview, 0, 1)); assertEquals( @@ -354,9 +354,9 @@ let instance = MakeInstance(); (function TestGetFloat64() { print(arguments.callee.name); let array = new Float64Array(2); - array[0] = 140.125; - array[1] = -20480000.001953125; let dataview = new DataView(array.buffer); + dataview.setFloat64(0, 140.125, true); + dataview.setFloat64(8, -20480000.001953125, true); assertEquals(140.125, instance.exports.getFloat64(dataview, 0, 1)); assertEquals( @@ -381,9 +381,9 @@ let instance = MakeInstance(); (function TestGetInt16() { print(arguments.callee.name); let array = new Int16Array(2); - array[0] = 32767; - array[1] = 0x1234; let dataview = new DataView(array.buffer); + dataview.setInt16(0, 32767, true); + dataview.setInt16(2, 0x1234, true); assertEquals(32767, instance.exports.getInt16(dataview, 0, 1)); assertEquals(0x3412, instance.exports.getInt16(dataview, 2, 0)); @@ -394,9 +394,9 @@ let instance = MakeInstance(); (function TestGetInt32() { print(arguments.callee.name); let array = new Int32Array(2); - array[0] = 42; - array[1] = 0x12345678; let dataview = new DataView(array.buffer); + dataview.setInt32(0, 42, true); + dataview.setInt32(4, 0x12345678, true); assertEquals(42, instance.exports.getInt32(dataview, 0, 1)); assertEquals(0x12345678, instance.exports.getInt32(dataview, 4, 1)); @@ -419,9 +419,9 @@ let instance = MakeInstance(); (function TestGetUint16() { print(arguments.callee.name); let array = new Uint16Array(2); - array[0] = 0xFFFF; - array[1] = 0x1234; let dataview = new DataView(array.buffer); + dataview.setUint16(0, 0xFFFF, true); + dataview.setUint16(2, 0x1234, true); assertEquals(0xFFFF, instance.exports.getUint16(dataview, 0, 1)); assertEquals(0x3412, instance.exports.getUint16(dataview, 2, 0)); @@ -432,9 +432,9 @@ let instance = MakeInstance(); (function TestGetUint32() { print(arguments.callee.name); let array = new Uint32Array(2); - array[0] = 0x7FFFFFFF; - array[1] = 0x12345678; let dataview = new DataView(array.buffer); + dataview.setUint32(0, 0x7FFFFFFF, true); + dataview.setUint32(4, 0x12345678, true); assertEquals(0x7FFFFFFF, instance.exports.getUint32(dataview, 0, 1)); assertEquals(0x78563412, instance.exports.getUint32(dataview, 4, 0)); @@ -448,11 +448,11 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setBigInt64(dataview, 0, 0x7FFFFFFFFFFFFFFFn, 1); - assertEquals(0x7FFFFFFFFFFFFFFFn, array[0]); + assertEquals(0x7FFFFFFFFFFFFFFFn, dataview.getBigInt64(0, true)); instance.exports.setBigInt64(dataview, 0, -0x7FFFFFFFFFFFFFFFn, 1); - assertEquals(-0x7FFFFFFFFFFFFFFFn, array[0]); + assertEquals(-0x7FFFFFFFFFFFFFFFn, dataview.getBigInt64(0, true)); instance.exports.setBigInt64(dataview, 8, 0x12345678n, 0); - assertEquals(0x7856341200000000n, array[1]); + assertEquals(0x7856341200000000n, dataview.getBigInt64(8, true)); CheckDataViewErrorMessages('setBigInt64', array, true, 50n); })(); @@ -463,9 +463,9 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setBigUint64(dataview, 0, 0xFFFFFFFFFFFFFFFFn, 1); - assertEquals(0xFFFFFFFFFFFFFFFFn, array[0]); + assertEquals(0xFFFFFFFFFFFFFFFFn, dataview.getBigUint64(0, true)); instance.exports.setBigUint64(dataview, 0, 0x12345678n, 0); - assertEquals(0x7856341200000000n, array[0]); + assertEquals(0x7856341200000000n, dataview.getBigUint64(0, true)); CheckDataViewErrorMessages('setBigUint64', array, true, 50n); })(); @@ -476,10 +476,10 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setFloat32(dataview, 0, 50.5, 1); - assertEquals(50.5, array[0]); + assertEquals(50.5, dataview.getFloat32(0, true)); instance.exports.setFloat32(dataview, 0, 0x1234, 0); dataview.setFloat32(4, 0x1234, 0); - assertEquals(array[1], array[0]); + assertEquals(dataview.getFloat32(4, true), dataview.getFloat32(0, true)); CheckDataViewErrorMessages('setFloat32', array, true, 50.5); })(); @@ -490,10 +490,10 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setFloat64(dataview, 0, 42.5, 1); - assertEquals(42.5, array[0]); + assertEquals(42.5, dataview.getFloat64(0, true)); instance.exports.setFloat64(dataview, 0, 0x1234, 0); dataview.setFloat64(8, 0x1234, 0); - assertEquals(array[1], array[0]); + assertEquals(dataview.getFloat64(8, true), dataview.getFloat64(0, true)); CheckDataViewErrorMessages('setFloat64', array, true, 50.5); })(); @@ -515,9 +515,9 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setInt16(dataview, 0, 0x1234, 1); - assertEquals(0x1234, array[0]); + assertEquals(0x1234, dataview.getInt16(0, true)); instance.exports.setInt16(dataview, 2, 0x1234, 0); - assertEquals(0x3412, array[1]); + assertEquals(0x3412, dataview.getInt16(2, true)); CheckDataViewErrorMessages('setInt16', array, true, 120); })(); @@ -528,11 +528,11 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setInt32(dataview, 0, 50, 1); - assertEquals(50, array[0]); + assertEquals(50, dataview.getInt32(0, true)); instance.exports.setInt32(dataview, 4, 100, 1); - assertEquals(100, array[1]); + assertEquals(100, dataview.getInt32(4, true)); instance.exports.setInt32(dataview, 0, 0x12345678, 0); - assertEquals(0x78563412, array[0]); + assertEquals(0x78563412, dataview.getInt32(0, true)); CheckDataViewErrorMessages('setInt32', array, true, 100); })(); @@ -554,9 +554,9 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setUint16(dataview, 0, 0x1234, 1); - assertEquals(0x1234, array[0]); + assertEquals(0x1234, dataview.getUint16(0, true)); instance.exports.setUint16(dataview, 2, 0x1234, 0); - assertEquals(0x3412, array[1]); + assertEquals(0x3412, dataview.getUint16(2, true)); CheckDataViewErrorMessages('setUint16', array, true, 100); })(); @@ -567,9 +567,9 @@ let instance = MakeInstance(); let dataview = new DataView(array.buffer); instance.exports.setUint32(dataview, 0, 50, 1); - assertEquals(50, array[0]); + assertEquals(50, dataview.getUint32(0, true)); instance.exports.setUint32(dataview, 4, 0x12345678, 0); - assertEquals(0x78563412, array[1]); + assertEquals(0x78563412, dataview.getUint32(4, true)); CheckDataViewErrorMessages('setUint32', array, true, 100); })(); @@ -613,10 +613,10 @@ let instance = MakeInstance(); let array = new Int32Array(buffer); let dataview = new DataView(buffer); - array[0] = 123; + dataview.setInt32(0, 123, true); assertEquals(123, instance.exports.getInt32(dataview, 0, 1)); instance.exports.setInt32(dataview, 4, 100, 1); - assertEquals(100, array[1]); + assertEquals(100, dataview.getInt32(4, true)); assertEquals(8, instance.exports.byteLength(dataview)); buffer.resize(24); @@ -634,10 +634,10 @@ let instance = MakeInstance(); let array = new Uint32Array(buffer); let dataview = new DataView(buffer, 8); - array[2] = 123; + dataview.setUint32(0, 123, true); assertEquals(123, instance.exports.getUint32(dataview, 0, 1)); instance.exports.setUint32(dataview, 0, 100, 1); - assertEquals(100, array[2]); + assertEquals(100, dataview.getUint32(0, true)); assertEquals(4, instance.exports.byteLength(dataview)); buffer.resize(24); @@ -671,10 +671,10 @@ let instance = MakeInstance(); let array = new BigInt64Array(buffer); let dataview = new DataView(buffer, 24, 16); - array[3] = 123n; + dataview.setBigInt64(0, 123n, true); assertEquals(123n, instance.exports.getBigInt64(dataview, 0, 1)); instance.exports.setBigInt64(dataview, 8, 100n, 1); - assertEquals(100n, array[4]); + assertEquals(100n, dataview.getBigInt64(8, true)); assertEquals(16, instance.exports.byteLength(dataview)); buffer.resize(40); @@ -727,10 +727,10 @@ let instance = MakeInstance(); let array = new Float32Array(buffer); let dataview = new DataView(buffer); - array[0] = 23.5; + dataview.setFloat32(0, 23.5, true); assertEquals(23.5, instance.exports.getFloat32(dataview, 0, 1)); instance.exports.setFloat32(dataview, 4, 12.25, 1); - assertEquals(12.25, array[1]); + assertEquals(12.25, dataview.getFloat32(4, true)); assertEquals(24, instance.exports.byteLength(dataview)); buffer.grow(25); @@ -748,10 +748,10 @@ let instance = MakeInstance(); assertEquals(0, instance.exports.byteLength(dataview)); buffer.grow(36); - array[12] = 123; + dataview.setInt16(0, 123, true); assertEquals(123, instance.exports.getInt16(dataview, 0, 1)); instance.exports.setInt16(dataview, 2, 100, 1); - assertEquals(100, array[13]); + assertEquals(100, dataview.getInt16(2, true)); assertEquals(12, instance.exports.byteLength(dataview)); CheckDataViewErrorMessages('setInt16', array, false, 57); diff --git a/deps/v8/test/mjsunit/wasm/instance-gc.js b/deps/v8/test/mjsunit/wasm/instance-gc.js index 98e87702e818..5b469771831c 100644 --- a/deps/v8/test/mjsunit/wasm/instance-gc.js +++ b/deps/v8/test/mjsunit/wasm/instance-gc.js @@ -21,8 +21,8 @@ function newModule() { function newInstance(module, val) { var instance = new WebAssembly.Instance(module); - var view = new Int32Array(instance.exports.memory.buffer); - view[0] = val; + var view = new DataView(instance.exports.memory.buffer); + view.setInt32(0, val, true); return instance; } diff --git a/deps/v8/test/mjsunit/wasm/instantiate-module-basic.js b/deps/v8/test/mjsunit/wasm/instantiate-module-basic.js index e4cef2e7cc26..929590f49407 100644 --- a/deps/v8/test/mjsunit/wasm/instantiate-module-basic.js +++ b/deps/v8/test/mjsunit/wasm/instantiate-module-basic.js @@ -147,11 +147,11 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); var module = new WebAssembly.Module(builder.toBuffer()); var mem_1 = new WebAssembly.Memory({initial: 1}); var mem_2 = new WebAssembly.Memory({initial: 1}); - var view_1 = new Int32Array(mem_1.buffer); - var view_2 = new Int32Array(mem_2.buffer); + var view_1 = new DataView(mem_1.buffer); + var view_2 = new DataView(mem_2.buffer); - view_1[0] = 42; - view_2[0] = 1000; + view_1.setInt32(0, 42, true); + view_2.setInt32(0, 1000, true); var outval_1; var outval_2; @@ -204,10 +204,10 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); var mem_1 = new WebAssembly.Memory({initial: 1}); var mem_2 = new WebAssembly.Memory({initial: 1}); - var view_1 = new Int32Array(mem_1.buffer); - var view_2 = new Int32Array(mem_2.buffer); - view_1[0] = 1; - view_2[0] = 1000; + var view_1 = new DataView(mem_1.buffer); + var view_2 = new DataView(mem_2.buffer); + view_1.setInt32(0, 1, true); + view_2.setInt32(0, 1000, true); var module = new WebAssembly.Module(builder.toBuffer()); var i1 = new WebAssembly.Instance(module, {'': {memory: mem_1}}); diff --git a/deps/v8/test/mjsunit/wasm/lazy-compilation.js b/deps/v8/test/mjsunit/wasm/lazy-compilation.js index 2eac01b790e0..f3addf4269eb 100644 --- a/deps/v8/test/mjsunit/wasm/lazy-compilation.js +++ b/deps/v8/test/mjsunit/wasm/lazy-compilation.js @@ -30,7 +30,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); ]) .exportFunc(); const instance1 = builder1.instantiate(); - const mem1 = new Int32Array(instance1.exports.memory.buffer); + const mem1 = new DataView(instance1.exports.memory.buffer); const builder2 = new WasmModuleBuilder(); builder2.addMemory(1, 1); @@ -40,17 +40,17 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); .addBody([kExprLocalGet, 0, kExprCallFunction, 0]) .exportFunc(); const instance2 = builder2.instantiate({mod: {store: instance1.exports.store}}); - const mem2 = new Int32Array(instance2.exports.memory.buffer); + const mem2 = new DataView(instance2.exports.memory.buffer); - assertEquals(0, mem1[0]); - assertEquals(0, mem2[0]); + assertEquals(0, mem1.getInt32(0, true)); + assertEquals(0, mem2.getInt32(0, true)); instance2.exports.call_store(3); - assertEquals(3, mem1[0]); - assertEquals(0, mem2[0]); + assertEquals(3, mem1.getInt32(0, true)); + assertEquals(0, mem2.getInt32(0, true)); %FreezeWasmLazyCompilation(instance1); %FreezeWasmLazyCompilation(instance2); instance2.exports.call_store(7); - assertEquals(7, mem1[0]); + assertEquals(7, mem1.getInt32(0, true)); })(); (function exportImportedFunction() { @@ -83,7 +83,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); ]) .exportFunc(); const instance1 = builder1.instantiate(); - const mem1 = new Int32Array(instance1.exports.memory.buffer); + const mem1 = new DataView(instance1.exports.memory.buffer); const builder2 = new WasmModuleBuilder(); builder2.addMemory(1, 1); @@ -91,13 +91,13 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); const imp_idx = builder2.addImport('A', 'store', kSig_v_i); builder2.addExport('exp_store', imp_idx); const instance2 = builder2.instantiate({A: instance1.exports}); - const mem2 = new Int32Array(instance2.exports.memory.buffer); + const mem2 = new DataView(instance2.exports.memory.buffer); instance2.exports.exp_store(3); - assertEquals(3, mem1[0]); - assertEquals(0, mem2[0]); + assertEquals(3, mem1.getInt32(0, true)); + assertEquals(0, mem2.getInt32(0, true)); %FreezeWasmLazyCompilation(instance1); %FreezeWasmLazyCompilation(instance2); instance2.exports.exp_store(7); - assertEquals(7, mem1[0]); + assertEquals(7, mem1.getInt32(0, true)); })(); diff --git a/deps/v8/test/mjsunit/wasm/load-shift32.js b/deps/v8/test/mjsunit/wasm/load-shift32.js index a530bc6a188b..9396a310a3f6 100644 --- a/deps/v8/test/mjsunit/wasm/load-shift32.js +++ b/deps/v8/test/mjsunit/wasm/load-shift32.js @@ -35,11 +35,11 @@ builder.addFunction("load_shift3", makeSig([kWasmI64], [kWasmI32])).exportFunc() const instance = builder.instantiate({}); const {memory, load, load_shift3} = instance.exports; -const view = new Int32Array(memory.buffer); +const view = new DataView(memory.buffer); // Initialize memory with ascending values. -for (let i = 0; i < view.length; i++) { - view[i] = i; +for (let i = 0; i < memory.buffer.byteLength / 4; i++) { + view.setInt32(i * 4, i, true); } function test(fct, index, shift) { @@ -53,8 +53,7 @@ function test(fct, index, shift) { return; } - const viewIndex = byteOffset >> 2; - const expected = view[viewIndex]; + const expected = view.getInt32(byteOffset, true); assertEquals(expected, fct(index), `At index ${index} with shift ${shift}`); } diff --git a/deps/v8/test/mjsunit/wasm/reference-globals.js b/deps/v8/test/mjsunit/wasm/reference-globals.js index ce9f0a070bb9..c2e2f640efea 100644 --- a/deps/v8/test/mjsunit/wasm/reference-globals.js +++ b/deps/v8/test/mjsunit/wasm/reference-globals.js @@ -453,3 +453,25 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); assertEquals(42, instance.exports.getter()); assertTraps(kTrapIllegalCast, () => instance.exports.getter_fail()); })(); + +(function TestAnyConvertExtern() { + print(arguments.callee.name); + + let builder = new WasmModuleBuilder(); + + let imported_global = builder.addImportedGlobal( + "m", "imported", kWasmExternRef, false, false); + + let defined_global = builder.addGlobal( + kWasmAnyRef, false, false, + [kExprGlobalGet, imported_global, kGCPrefix, kExprAnyConvertExtern] + ); + + let tester = builder.addFunction("tester", kSig_i_v) + .addBody([kExprGlobalGet, defined_global.index, kExprRefIsNull]) + .exportFunc(); + + let wasm = builder.instantiate({m: {imported: null }}).exports; + + assertEquals(1, wasm.tester()); +})(); diff --git a/deps/v8/test/mjsunit/wasm/regress-534579660.js b/deps/v8/test/mjsunit/wasm/regress-534579660.js deleted file mode 100644 index bd04b3e04ed9..000000000000 --- a/deps/v8/test/mjsunit/wasm/regress-534579660.js +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --allow-natives-syntax --expose-gc --liftoff -// Flags: --no-wasm-tier-up - -d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); - -let next_id = 2; -let breakpoint_set = false; -let instance; -let arr; - -function receive(message) { - let msg = JSON.parse(message); - if (msg.error) { - failWithMessage('Inspector error: ' + JSON.stringify(msg.error)); - } - if (msg.id === 1) { - // Step 2: Debugger enabled, now set pause on exceptions - send(JSON.stringify({ - id: 10, - method: 'Debugger.setPauseOnExceptions', - params: {state: 'all'} - })); - } else if (msg.id === 10) { - // Step 3: Pause on exceptions is set, now instantiate and run Wasm - instantiateAndRun(); - } else if (msg.method === 'Debugger.paused') { - if (!breakpoint_set) { - breakpoint_set = true; - // The top frame is $trigger itself when paused on exception/trap - let triggerFrame = msg.params.callFrames[0]; - let scriptId = triggerFrame.location.scriptId; - let columnNumber = triggerFrame.location.columnNumber; - - // Set breakpoint inside trigger at the exact trapping columnNumber! - send(JSON.stringify({ - id: 2, - method: 'Debugger.setBreakpoint', - params: { - location: - {scriptId: scriptId, lineNumber: 0, columnNumber: columnNumber} - } - })); - } else { - send(JSON.stringify({id: next_id++, method: 'Debugger.resume'})); - } - } else if (msg.id === 2) { - // Once the breakpoint is set, trigger GC while paused to verify the - // safepoint layout - gc(); - send(JSON.stringify({id: 3, method: 'Debugger.resume'})); - } -} - -function instantiateAndRun() { - let builder = new WasmModuleBuilder(); - let array_type = builder.addArray(kWasmI32); - - // create_array() returns (ref $array_type) - builder.addFunction('create_array', makeSig([], [wasmRefType(array_type)])) - .addBody([kExprI32Const, 5, kGCPrefix, kExprArrayNewDefault, array_type]) - .exportFunc(); - - // trigger(arr_0, arr_1, ..., arr_29) - let num_params = 30; - let params = Array(num_params).fill(wasmRefType(array_type)); - builder.addFunction('trigger', makeSig(params, [kWasmI32])) - .addLocals(kWasmI32, 1) - .addBody([ - ...Array(num_params).fill(0).map((_, i) => [kExprLocalGet, i]).flat(), - ...wasmI32Const(0x7fffffff), // OOB index - kGCPrefix, kExprArrayGet, array_type, kExprLocalSet, num_params, - ...Array(num_params - 1).fill(kExprDrop), kExprLocalGet, num_params - ]) - .exportFunc(); - - let module_bytes = builder.toArray(); - globalThis.body_offset = builder.functions[1].body_offset; - - instance = builder.instantiate({}); - arr = instance.exports.create_array(); - - assertThrows( - () => instance.exports.trigger(...Array(30).fill(arr)), - WebAssembly.RuntimeError); - assertTrue(breakpoint_set); -} - -// Start sequence -send(JSON.stringify({id: 1, method: 'Debugger.enable'})); diff --git a/deps/v8/test/mjsunit/wasm/regress-535877252-2.js b/deps/v8/test/mjsunit/wasm/regress-535877252-2.js new file mode 100644 index 000000000000..4fb928d363c5 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/regress-535877252-2.js @@ -0,0 +1,92 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-wasm-generic-wrapper --stack-size=100 + +d8.file.execute('test/mjsunit/mjsunit.js'); +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +function exhaustAndCall(callFn, expectOverflow = true) { + let maxDepth = 0; + let depth = 0; + let didCall = false; + let caughtError = null; + function recurse() { + depth++; + if (depth > maxDepth) maxDepth = depth; + try { + recurse(); + } catch (e) { + depth--; + // Unwind 10 frames to provide controlled headroom (~800 bytes): enough + // for a 0-slot wrapper to run successfully, but small enough to trigger + // overflow when allocating large parameter or return frames. + if (depth === maxDepth - 10 && !didCall) { + didCall = true; + try { + callFn(); + } catch (callErr) { + caughtError = callErr; + } + } + throw e; + } + } + assertThrows(recurse, RangeError, /Maximum call stack size exceeded/); + assertTrue(didCall); + if (expectOverflow) { + assertInstanceof(caughtError, RangeError); + assertEquals('Maximum call stack size exceeded', caughtError.message); + } else { + assertEquals(null, caughtError); + } +} + +(function testCompiledWrapperPreemptiveStackCheckParams() { + let builder = new WasmModuleBuilder(); + let sig = builder.addType(makeSig(Array(1000).fill(kWasmI32), [])); + builder.addFunction('main', sig).exportFunc().addBody([]); + let instance = builder.instantiate(); + + // Warm up before stack exhaustion. + instance.exports.main(); + + // Call without arguments: missing parameters are default-initialized, so no + // JS argument slots are pushed. The wrapper is entered with minimal stack + // usage, and its prologue checks that the stack can hold the 1,000 Wasm + // parameter slots. + exhaustAndCall(instance.exports.main); +})(); + +(function testCompiledWrapperPreemptiveStackCheckReturns() { + let builder = new WasmModuleBuilder(); + let sig = builder.addType(makeSig([], Array(1000).fill(kWasmI32))); + let body = []; + for (let i = 0; i < 1000; ++i) { + body.push(kExprI32Const, 0); + } + builder.addFunction('main', sig).exportFunc().addBody(body); + let instance = builder.instantiate(); + + // Warm up before stack exhaustion. + instance.exports.main(); + + // Multi-value returns exceeding register capacity allocate return slots + // on the wrapper stack frame, exercising the stack check for return counts. + exhaustAndCall(instance.exports.main); +})(); + +(function testCompiledWrapperPreemptiveStackCheckZeroSlots() { + let builder = new WasmModuleBuilder(); + let sig = builder.addType(makeSig([], [])); + builder.addFunction('main', sig).exportFunc().addBody([]); + let instance = builder.instantiate(); + + // Warm up before stack exhaustion. + instance.exports.main(); + + // A 0-slot wrapper requires no extra stack space beyond its fixed frame, + // so it should execute and succeed within the headroom of the unwound frame. + exhaustAndCall(instance.exports.main, false); +})(); diff --git a/deps/v8/test/mjsunit/wasm/regress-535877252.js b/deps/v8/test/mjsunit/wasm/regress-535877252.js new file mode 100644 index 000000000000..9fd384613963 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/regress-535877252.js @@ -0,0 +1,92 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-generic-wrapper --stack-size=100 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +function exhaustAndCall(callFn) { + let didCall = false; + let caughtError = null; + function recurse() { + try { + recurse(); + } catch (e) { + if (!didCall) { + didCall = true; + try { + callFn(); + } catch (callErr) { + caughtError = callErr; + } + } + throw e; + } + } + assertThrows(recurse, RangeError, /Maximum call stack size exceeded/); + assertTrue(didCall); + assertInstanceof(caughtError, RangeError); + assertEquals('Maximum call stack size exceeded', caughtError.message); +} + +const kBoundaryParamCounts = [0, 4, 5, 6, 8, 9]; +const kI32Const0x500 = new Array(500).fill([kExprI32Const, 0]).flat(); +const kI32Const0x1000 = kI32Const0x500.concat(kI32Const0x500); + +const builder = new WasmModuleBuilder(); +const sigParams1000 = builder.addType(makeSig(Array(1000).fill(kWasmI32), [])); +const sigReturns1000 = builder.addType(makeSig([], Array(1000).fill(kWasmI32))); +const sigParamsReturns500 = builder.addType( + makeSig(Array(500).fill(kWasmI32), Array(500).fill(kWasmI32))); + +builder.addFunction('params1000', sigParams1000).exportFunc().addBody([]); +builder.addFunction('returns1000', sigReturns1000) + .exportFunc() + .addBody(kI32Const0x1000); +builder.addFunction('paramsReturns500', sigParamsReturns500) + .exportFunc() + .addBody(kI32Const0x500); + +for (let paramCount of kBoundaryParamCounts) { + let sig = builder.addType(makeSig(Array(paramCount).fill(kWasmI32), [])); + builder.addFunction(`params${paramCount}`, sig).exportFunc().addBody([]); +} + +const instance = builder.instantiate(); +const args1000 = new Array(1000).fill(42); +const args500 = args1000.slice(0, 500); + +(function testGenericWrapperPreemptiveStackCheckParams() { + exhaustAndCall(() => instance.exports.params1000(...args1000)); +})(); + +(function testGenericWrapperPreemptiveStackCheckReturns() { + exhaustAndCall(() => instance.exports.returns1000()); +})(); + +(function testGenericWrapperPreemptiveStackCheckParamsAndReturns() { + exhaustAndCall(() => instance.exports.paramsReturns500(...args500)); +})(); + +(function testGenericWrapperPreemptiveStackCheckRegisterBoundary() { + for (let paramCount of kBoundaryParamCounts) { + let fn = instance.exports[`params${paramCount}`]; + let args = args1000.slice(0, paramCount); + fn(...args); + exhaustAndCall(() => fn(...args)); + } +})(); + +(function testGenericWrapperPreemptiveStackCheckJSPIParams() { + if (typeof WebAssembly.promising !== 'function') return; + let promisingParams1000 = WebAssembly.promising(instance.exports.params1000); + exhaustAndCall(() => promisingParams1000(...args1000)); +})(); + +(function testGenericWrapperPreemptiveStackCheckJSPIReturns() { + if (typeof WebAssembly.promising !== 'function') return; + let promisingReturns1000 = + WebAssembly.promising(instance.exports.returns1000); + exhaustAndCall(() => promisingReturns1000()); +})(); diff --git a/deps/v8/test/mjsunit/wasm/regress-569014241.js b/deps/v8/test/mjsunit/wasm/regress-569014241.js new file mode 100644 index 000000000000..4198e50222bc --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/regress-569014241.js @@ -0,0 +1,107 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --no-wasm-generic-wrapper --stack-size=200 + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +function exhaustAndCall(callFn, checkError = true, unwindFrames = 10) { + let maxDepth = 0; + let depth = 0; + let didCall = false; + let caughtError = null; + let result; + function recurse() { + depth++; + if (depth > maxDepth) maxDepth = depth; + try { + recurse(); + } catch (e) { + depth--; + // Unwind unwindFrames frames: enough to enter the JS-to-Wasm wrapper and + // Wasm function, reaching the compiled Wasm-to-JS wrapper where outgoing + // parameters are checked. + if (depth === maxDepth - unwindFrames && !didCall) { + didCall = true; + try { + result = callFn(0); + } catch (callErr) { + caughtError = callErr; + } + } + throw e; + } + } + assertThrows(recurse, RangeError, /Maximum call stack size exceeded/); + assertTrue(didCall); + if (checkError) { + assertInstanceof(caughtError, RangeError); + assertEquals('Maximum call stack size exceeded', caughtError.message); + assertMatches(/wasm-function/, caughtError.stack); + } else { + assertNull(caughtError); + } + return result; +} + +const kHighArity = 14000; +const paramNames = Array.from({length: kHighArity}, (_, i) => `p${i}`); +const highArityImportFn = new Function(paramNames.join(','), 'return 1;'); + +(function testHighExpectedArityJSImport() { + const builder = new WasmModuleBuilder(); + const sig = builder.addType(kSig_i_i); + const impIndex = builder.addImport('env', 'f', sig); + builder.addFunction('main', sig) + .addBody([kExprLocalGet, 0, kExprCallFunction, impIndex]) + .exportFunc(); + const instance = builder.instantiate({env: {f: highArityImportFn}}); + + // Pushing 14,001 slots (~112 KB on 64-bit) exceeds the stack limit and margin + // when called near stack exhaustion. + exhaustAndCall(instance.exports.main); +})(); + +(function testManyWasmParamsImport() { + const kNumParams = 1000; + const builder = new WasmModuleBuilder(); + const sig = builder.addType( + makeSig(Array(kNumParams).fill(kWasmExternRef), [kWasmI32])); + const impIndex = builder.addImport('env', 'f', sig); + const body = []; + for (let i = 0; i < kNumParams; ++i) { + body.push(kExprRefNull, kExternRefCode); + } + body.push(kExprCallFunction, impIndex); + builder.addFunction('main', kSig_i_v).addBody(body).exportFunc(); + const instance = builder.instantiate({env: {f: () => 42}}); + + assertEquals(42, instance.exports.main()); + exhaustAndCall(instance.exports.main); +})(); + +(function testJSPIHighExpectedArityImport() { + if (typeof WebAssembly.promising !== 'function') return; + + const suspendingImport = new WebAssembly.Suspending(highArityImportFn); + + const builder = new WasmModuleBuilder(); + const sig = builder.addType(kSig_i_i); + const impIndex = builder.addImport('env', 'f', sig); + builder.addFunction('main', sig) + .addBody([kExprLocalGet, 0, kExprCallFunction, impIndex]) + .exportFunc(); + const instance = builder.instantiate({env: {f: suspendingImport}}); + const promisingMain = WebAssembly.promising(instance.exports.main); + + // For JSPI, allocating a suspender on the central stack requires enough stack + // headroom for GC during stress modes, so unwind more frames (50). The + // parameter payload (14,000 slots / ~112 KB) still comfortably exceeds the + // remaining stack headroom on a 200 KB stack. + const promise = exhaustAndCall(promisingMain, false, 50); + assertPromiseResult(promise, assertUnreachable, err => { + assertInstanceof(err, RangeError); + assertMatches(/wasm-function/, err.stack); + }); +})(); diff --git a/deps/v8/test/mjsunit/wasm/regress-576453351.js b/deps/v8/test/mjsunit/wasm/regress-576453351.js new file mode 100644 index 000000000000..04ead6bef756 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/regress-576453351.js @@ -0,0 +1,99 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const kBigGrow = 1024; +const kMaxPages = kBigGrow + 1; +const kNumRounds = 8; + +const builder = new WasmModuleBuilder(); +builder.addImportedMemory('m', 'memory', 1, kMaxPages, true); +builder.addFunction('load', kSig_i_i) + .addBody([kExprLocalGet, 0, kExprI32LoadMem8U, 0, 0]) + .exportFunc(); +builder.addFunction('store', kSig_v_ii) + .addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32StoreMem8, 0, 0]) + .exportFunc(); +builder.addFunction('size', kSig_i_v) + .addBody([kExprMemorySize, 0]) + .exportFunc(); +const module = builder.toModule(); + +function workerCode() { + onmessage = function({data: [memory, sync, bigGrow]}) { + const flags = new Int32Array(sync); + const arg = { + valueOf() { + Atomics.store(flags, 0, 1); + while (Atomics.load(flags, 1) === 0) {} + return bigGrow; + } + }; + try { + memory.grow(arg); + postMessage(true); + } catch (e) { + postMessage(e instanceof RangeError ? false : 'unexpected: ' + e); + } + }; +} + +const worker = new Worker(workerCode, {type: 'function'}); +const sync = new SharedArrayBuffer(8); +const flags = new Int32Array(sync); +const mainArg = { + valueOf() { + while (Atomics.load(flags, 0) === 0) {} + Atomics.store(flags, 1, 1); + return 1; + } +}; + +for (let round = 0; round < kNumRounds; ++round) { + let memory; + try { + memory = new WebAssembly.Memory( + {initial: 1, maximum: kMaxPages, shared: true}); + } catch (e) { + // Out of memory on 32-bit platforms or memory-constrained bots. + assertInstanceof(e, RangeError); + break; + } + + Atomics.store(flags, 0, 0); + Atomics.store(flags, 1, 0); + worker.postMessage([memory, sync, kBigGrow]); + + let smallGrowSucceeded = false; + try { + assertEquals(1, memory.grow(mainArg)); + smallGrowSucceeded = true; + } catch (e) { + assertInstanceof(e, RangeError); + } + const bigGrowSucceeded = worker.getMessage(); + assertEquals('boolean', typeof bigGrowSucceeded); + + if (smallGrowSucceeded) { + assertFalse(bigGrowSucceeded); + const {load, store, size} = + new WebAssembly.Instance(module, {m: {memory}}).exports; + assertEquals(2, size()); + assertEquals(2 * kPageSize, memory.buffer.byteLength); + const outOfBoundsOffset = 2 * kPageSize + 4; + assertTraps(kTrapMemOutOfBounds, () => store(outOfBoundsOffset, 0x5a)); + assertTraps(kTrapMemOutOfBounds, () => load(outOfBoundsOffset)); + assertEquals(2, memory.grow(1)); + assertEquals(0, load(outOfBoundsOffset)); + } else if (bigGrowSucceeded) { + assertEquals(kMaxPages * kPageSize, memory.buffer.byteLength); + } else { + // Out of memory or reduced capacity on 32-bit platforms. + assertEquals(kPageSize, memory.buffer.byteLength); + break; + } +} + +worker.terminate(); diff --git a/deps/v8/test/mjsunit/wasm/regress-nested-stack-switch-catch.js b/deps/v8/test/mjsunit/wasm/regress-nested-stack-switch-catch.js deleted file mode 100644 index 369966cd5848..000000000000 --- a/deps/v8/test/mjsunit/wasm/regress-nested-stack-switch-catch.js +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --enable-inspector --stress-wasm-stack-switching - -load('test/mjsunit/wasm/wasm-module-builder.js'); - -let scriptId; -let bodyOffset; - -globalThis.receive = function (message) { - let json = JSON.parse(message); - if (json.params && json.params.scriptId) { - scriptId = json.params.scriptId; - } -}; - -const builder = new WasmModuleBuilder(); -builder.addMemory(1); -const tag = builder.addTag(kSig_v_v); - -// target2: throws and catches internally. -// With --stress-wasm-stack-switching, this will run on Stack 2. -builder.addFunction('target2', kSig_v_v) - .addBody([ - kExprTry, kWasmVoid, - kExprThrow, tag, - kExprCatch, tag, - kExprEnd - ]).exportFunc(); - -// target: hits breakpoint. -// With --stress-wasm-stack-switching, this will run on Stack 1. -const body = [...wasmI32Const(5), kExprI32LoadMem, 0, kExprDrop, - ...wasmI32Const(5), ...wasmI32Const(5), 0]; -const target = builder.addFunction('target', kSig_v_v) - .addBody(body).exportFunc(); - -const buffer = builder.toBuffer(); -// Offset of the I32LoadMem instruction. -bodyOffset = target.body_offset + 6; - -send(JSON.stringify({ - id: 1, - method: 'Debugger.enable' -})); - -// Instantiate triggers compilation and sends scriptParsed event (which sets -// scriptId). -const instance = new WebAssembly.Instance(new WebAssembly.Module(buffer)); - -// Condition for breakpoint: call target2. -const condition = `(function() { - instance.exports.target2(); -})()`; - -send(JSON.stringify({ - id: 2, - method: 'Debugger.setBreakpoint', - params: { - location: { - scriptId: scriptId, - lineNumber: 0, - columnNumber: bodyOffset - }, - condition: condition - } -})); - -// Run target. It will hit breakpoint, evaluate condition (runs target2 on Stack -// 2), target2 catches exception and clears secondary SP. When target resumes, -// it should not crash. -assertThrows(() => instance.exports.target(), - WebAssembly.RuntimeError, /unreachable/); diff --git a/deps/v8/test/mjsunit/wasm/regression-521715545.js b/deps/v8/test/mjsunit/wasm/regression-521715545.js deleted file mode 100644 index 2ce928a547a2..000000000000 --- a/deps/v8/test/mjsunit/wasm/regression-521715545.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2026 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Flags: --wasm-code-coverage --enable-inspector - -load('test/mjsunit/wasm/wasm-module-builder.js'); - -const builder = new WasmModuleBuilder(); -const func = builder.addFunction('main', kSig_v_v) - .addBody([ - kExprI32Const, 0, - kExprI32Const, 1, - kExprI32Add, - kExprDrop - ]) - .exportFunc(); -const buffer = builder.toBuffer(); - -let scriptId; -globalThis.receive = function(msg) { - let response = JSON.parse(msg); - if (response.method === 'Debugger.scriptParsed') { - scriptId = response.params.scriptId; - } -}; - -send(JSON.stringify({ - id: 1, - method: 'Debugger.enable' -})); - -const module = new WebAssembly.Module(buffer); -const instance = new WebAssembly.Instance(module); - -// Offset into the code section for the 'i32.add' instruction. -// The header is 8 bytes, sections are typically 1 byte ID + length. -// WasmModuleBuilder offsets are relative to the start of the buffer. -const offset = func.body_offset + 2; - -send(JSON.stringify({ - id: 2, - method: 'Debugger.setBreakpoint', - params: { - location: { - scriptId: scriptId, - lineNumber: 0, - columnNumber: offset - }, - } -})); - -// If we reached here without crashing, the fix works. diff --git a/deps/v8/test/mjsunit/wasm/shared-everything/gc-casts-subtypes-shared.js b/deps/v8/test/mjsunit/wasm/shared-everything/gc-casts-subtypes-shared.js index 709ad3972eb4..bc90f78367ad 100644 --- a/deps/v8/test/mjsunit/wasm/shared-everything/gc-casts-subtypes-shared.js +++ b/deps/v8/test/mjsunit/wasm/shared-everything/gc-casts-subtypes-shared.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --wasm-shared --harmony-struct +// Flags: --wasm-shared d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); @@ -415,7 +415,6 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); let builder = new WasmModuleBuilder(); let sharedExternRef = wasmRefNullType(kWasmExternRef).shared(); let sharedNullExternRef = wasmRefNullType(kWasmNullExternRef).shared(); - let sharedObj = new (new SharedStructType(["prop"])); builder.addFunction('testExternRef', makeSig([sharedExternRef], [kWasmI32, kWasmI32])) @@ -441,13 +440,11 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); assertEquals([1, 0], wasm.testExternRef(undefined)); assertEquals([1, 0], wasm.testExternRef(1)); assertEquals([1, 0], wasm.testExternRef("test")); - assertEquals([1, 0], wasm.testExternRef(sharedObj)); assertEquals([1, 1], wasm.testNullExternRef(null)); assertEquals([1, 0], wasm.testNullExternRef(undefined)); assertEquals([1, 0], wasm.testNullExternRef(1)); assertEquals([1, 0], wasm.testNullExternRef("test")); - assertEquals([1, 0], wasm.testNullExternRef(sharedObj)); })(); (function RefCastExternRef() { @@ -491,23 +488,18 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); assertTraps(kTrapIllegalCast, () => wasm.castToExternRef(null)); assertEquals(undefined, wasm.castToExternRef(undefined)); assertEquals(1, wasm.castToExternRef(1)); - let obj = new (new SharedStructType(["prop"])); - assertSame(obj, wasm.castToExternRef(obj)); assertTraps(kTrapIllegalCast, () => wasm.castToNullExternRef(null)); assertTraps(kTrapIllegalCast, () => wasm.castToNullExternRef(undefined)); assertTraps(kTrapIllegalCast, () => wasm.castToNullExternRef(1)); - assertTraps(kTrapIllegalCast, () => wasm.castToNullExternRef(obj)); assertSame(null, wasm.castNullToExternRef(null)); assertEquals(undefined, wasm.castNullToExternRef(undefined)); assertEquals(1, wasm.castNullToExternRef(1)); - assertSame(obj, wasm.castNullToExternRef(obj)); assertSame(null, wasm.castNullToNullExternRef(null)); assertTraps(kTrapIllegalCast, () => wasm.castNullToNullExternRef(undefined)); assertTraps(kTrapIllegalCast, () => wasm.castNullToNullExternRef(1)); - assertTraps(kTrapIllegalCast, () => wasm.castNullToNullExternRef(obj)); })(); (function BrOnCastExternRef() { @@ -650,47 +642,38 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); let instance = builder.instantiate(); let wasm = instance.exports; - let obj = new (new SharedStructType(["prop"])); assertEquals(0, wasm.castToExternRef(null)); assertEquals(1, wasm.castToExternRef(undefined)); assertEquals(1, wasm.castToExternRef(1)); - assertEquals(1, wasm.castToExternRef(obj)); assertEquals(0, wasm.castToNullExternRef(null)); assertEquals(0, wasm.castToNullExternRef(undefined)); assertEquals(0, wasm.castToNullExternRef(1)); - assertEquals(0, wasm.castToNullExternRef(obj)); assertEquals(1, wasm.castNullToExternRef(null)); assertEquals(1, wasm.castNullToExternRef(undefined)); assertEquals(1, wasm.castNullToExternRef(1)); - assertEquals(1, wasm.castNullToExternRef(obj)); assertEquals(1, wasm.castNullToNullExternRef(null)); assertEquals(0, wasm.castNullToNullExternRef(undefined)); assertEquals(0, wasm.castNullToNullExternRef(1)); - assertEquals(0, wasm.castNullToNullExternRef(obj)); assertEquals(1, wasm.castFailToExternRef(null)); assertEquals(0, wasm.castFailToExternRef(undefined)); assertEquals(0, wasm.castFailToExternRef(1)); - assertEquals(0, wasm.castFailToExternRef(obj)); assertEquals(1, wasm.castFailToNullExternRef(null)); assertEquals(1, wasm.castFailToNullExternRef(undefined)); assertEquals(1, wasm.castFailToNullExternRef(1)); - assertEquals(1, wasm.castFailToNullExternRef(obj)); assertEquals(0, wasm.castFailNullToExternRef(null)); assertEquals(0, wasm.castFailNullToExternRef(undefined)); assertEquals(0, wasm.castFailNullToExternRef(1)); - assertEquals(0, wasm.castFailNullToExternRef(obj)); assertEquals(0, wasm.castFailNullToNullExternRef(null)); assertEquals(1, wasm.castFailNullToNullExternRef(undefined)); assertEquals(1, wasm.castFailNullToNullExternRef(1)); - assertEquals(1, wasm.castFailNullToNullExternRef(obj)); })(); (function RefTestAnyRefHierarchy() { diff --git a/deps/v8/test/mjsunit/wasm/shared-everything/wait-queue.js b/deps/v8/test/mjsunit/wasm/shared-everything/wait-queue.js index 3656f4969b10..2b6bc66435c4 100644 --- a/deps/v8/test/mjsunit/wasm/shared-everything/wait-queue.js +++ b/deps/v8/test/mjsunit/wasm/shared-everything/wait-queue.js @@ -19,6 +19,31 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); /opcode pause is not allowed in constant expressions/); })(); +(function TestShorthandIsNullable() { + print(arguments.callee.name); + + let builder = new WasmModuleBuilder(); + + builder.addFunction("shorthand_typed", makeSig([], [kWasmWaitqueueRef])) + .addBody([kExprRefNull, kWaitqueueRefCode]) + .exportFunc(); + + builder.instantiate(); +})(); + +(function TestShorthandIsNotShared() { + print(arguments.callee.name); + + let builder = new WasmModuleBuilder(); + + builder.addFunction("shorthand_typed", makeSig([], [kWasmWaitqueueRef])) + .addBody([kAtomicPrefix, kExprWaitqueueNew]) + .exportFunc(); + + assertThrows(() => builder.instantiate(), WebAssembly.CompileError, + /\(expected waitqueueref, got \(ref shared waitqueue\)\)/); +})(); + (function TestTypeTestAndCast() { print(arguments.callee.name); diff --git a/deps/v8/test/mjsunit/wasm/shared-everything/wrapper-type-checks.js b/deps/v8/test/mjsunit/wasm/shared-everything/wrapper-type-checks.js index 7756eabb490b..ccd5f58bab0c 100644 --- a/deps/v8/test/mjsunit/wasm/shared-everything/wrapper-type-checks.js +++ b/deps/v8/test/mjsunit/wasm/shared-everything/wrapper-type-checks.js @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --wasm-shared -// Flags: --allow-natives-syntax --shared-string-table --harmony-struct +// Flags: --wasm-shared --allow-natives-syntax d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); -let sharedJSStruct = new (new SharedStructType(["str"])); -sharedJSStruct.str = "shared string"; -assertTrue(%IsSharedString(sharedJSStruct.str)); +let sharedStr = %ShareObject("shared string"); +assertTrue(%IsSharedString(sharedStr)); let createHeapNumber = (x) => x + x; @@ -22,8 +20,7 @@ let vHeapNumber = () => 1.5; let vHeapNumberSmi = () => createHeapNumber(5.5); let vStringLiteral = () => "test"; let vStringDynamic = () => [1, 2, 3].join("-"); -let vSharedString = () => sharedJSStruct.str; -let vSharedJSStruct = () => sharedJSStruct; +let vSharedString = () => sharedStr; let vObject = () => ({object: "literal"}); let vSharedWasmStruct = (instance) => instance.exports.createSharedStruct(); let vSharedWasmArray = (instance) => instance.exports.createSharedArray(); @@ -43,8 +40,8 @@ let tests = [ name: "shared externref", type: wasmRefNullType(kWasmExternRef).shared(), valid: [vNull, vUndefined, vTrue, vFalse, vSmi, vStringLiteral, - vSharedString, vSharedJSStruct, vSharedWasmStruct, - vSharedWasmArray, vHeapNumber, vHeapNumberSmi, vStringDynamic], + vSharedString, vSharedWasmStruct, vSharedWasmArray, vHeapNumber, + vHeapNumberSmi, vStringDynamic], invalid: [vUnsharedWasmStruct, vUnsharedWasmArray, vObject, vSymbol, vBigInt] }, @@ -52,8 +49,8 @@ let tests = [ name: "shared anyref", type: wasmRefNullType(kWasmAnyRef).shared(), valid: [vNull, vUndefined, vTrue, vFalse, vSmi, vStringLiteral, - vSharedString, vSharedJSStruct, vSharedWasmStruct, - vSharedWasmArray, vHeapNumber, vHeapNumberSmi, vStringDynamic], + vSharedString, vSharedWasmStruct, vSharedWasmArray, vHeapNumber, + vHeapNumberSmi, vStringDynamic], invalid: [vUnsharedWasmStruct, vUnsharedWasmArray, vObject, vSymbol, vBigInt] }, @@ -62,8 +59,8 @@ let tests = [ type: wasmRefNullType(kWasmExternRef), valid: [vNull, vUndefined, vTrue, vFalse, vSmi, vHeapNumber, vStringLiteral, vStringDynamic, vObject, vUnsharedWasmStruct, vUnsharedWasmArray, - vSharedString, vSharedJSStruct, vSharedWasmStruct, vSharedWasmArray, - vHeapNumberSmi, vSymbol, vBigInt], + vSharedString, vSharedWasmStruct, vSharedWasmArray, vHeapNumberSmi, + vSymbol, vBigInt], invalid: [] }, { @@ -71,8 +68,8 @@ let tests = [ type: wasmRefNullType(kWasmAnyRef), valid: [vNull, vUndefined, vTrue, vFalse, vSmi, vHeapNumber, vStringLiteral, vStringDynamic, vObject, vUnsharedWasmStruct, vUnsharedWasmArray, - vSharedString, vSharedJSStruct, vSharedWasmStruct, vSharedWasmArray, - vHeapNumberSmi, vSymbol, vBigInt], + vSharedString, vSharedWasmStruct, vSharedWasmArray, vHeapNumberSmi, + vSymbol, vBigInt], invalid: [] }, { @@ -80,8 +77,8 @@ let tests = [ type: wasmRefNullType(kWasmEqRef).shared(), valid: [vNull, vSmi, vHeapNumberSmi, vSharedWasmStruct, vSharedWasmArray], invalid: [vUndefined, vTrue, vFalse, vHeapNumber, vStringLiteral, - vStringDynamic, vSharedString, vSharedJSStruct, vObject, - vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, vBigInt] + vStringDynamic, vSharedString, vObject, vUnsharedWasmStruct, + vUnsharedWasmArray, vSymbol, vBigInt] }, { name: "eqref", @@ -89,80 +86,77 @@ let tests = [ valid: [vNull, vSmi, vHeapNumberSmi, vUnsharedWasmStruct, vUnsharedWasmArray], invalid: [vUndefined, vTrue, vFalse, vHeapNumber, vStringLiteral, - vStringDynamic, vSharedString, vSharedJSStruct, vObject, - vSharedWasmStruct, vSharedWasmArray, vSymbol, vBigInt] + vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vSharedWasmArray, vSymbol, vBigInt] }, { name: "shared i31ref", type: wasmRefNullType(kWasmI31Ref).shared(), valid: [vNull, vSmi, vHeapNumberSmi], invalid: [vUndefined, vTrue, vFalse, vHeapNumber, vStringLiteral, - vStringDynamic, vSharedString, vSharedJSStruct, vObject, - vSharedWasmStruct, vSharedWasmArray, vUnsharedWasmStruct, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vSharedWasmArray, vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, + vBigInt] }, { name: "i31ref", type: wasmRefNullType(kWasmI31Ref), valid: [vNull, vSmi, vHeapNumberSmi], invalid: [vUndefined, vTrue, vFalse, vHeapNumber, vStringLiteral, - vStringDynamic, vSharedString, vSharedJSStruct, vObject, - vSharedWasmStruct, vSharedWasmArray, vUnsharedWasmStruct, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vSharedWasmArray, vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, + vBigInt] }, { name: "shared arrayref", type: wasmRefNullType(kWasmArrayRef).shared(), valid: [vNull, vSharedWasmArray], invalid: [vUndefined, vTrue, vFalse, vSmi, vHeapNumberSmi, vHeapNumber, - vStringLiteral, vStringDynamic, vSharedString, vSharedJSStruct, - vObject, vSharedWasmStruct, vUnsharedWasmStruct, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringLiteral, vStringDynamic, vSharedString, vObject, + vSharedWasmStruct, vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, + vBigInt] }, { name: "arrayref", type: wasmRefNullType(kWasmArrayRef), valid: [vNull, vUnsharedWasmArray], invalid: [vUndefined, vTrue, vFalse, vSmi, vHeapNumberSmi, vHeapNumber, - vStringLiteral, vStringDynamic, vSharedString, vSharedJSStruct, - vObject, vSharedWasmStruct, vUnsharedWasmStruct, - vSharedWasmArray, vSymbol, vBigInt] + vStringLiteral, vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vUnsharedWasmStruct, vSharedWasmArray, vSymbol, vBigInt] }, { name: "shared structref", type: wasmRefNullType(kWasmStructRef).shared(), valid: [vNull, vSharedWasmStruct], invalid: [vUndefined, vTrue, vFalse, vSmi, vHeapNumberSmi, vHeapNumber, - vStringLiteral, vStringDynamic, vSharedString, vSharedJSStruct, - vObject, vSharedWasmArray, vUnsharedWasmStruct, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringLiteral, vStringDynamic, vSharedString, vObject, vSharedWasmArray, + vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, vBigInt] }, { name: "structref", type: wasmRefNullType(kWasmStructRef), valid: [vNull, vUnsharedWasmStruct], invalid: [vUndefined, vTrue, vFalse, vSmi, vHeapNumberSmi, vHeapNumber, - vStringLiteral, vStringDynamic, vSharedString, vSharedJSStruct, - vObject, vSharedWasmStruct, vSharedWasmArray, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringLiteral, vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vSharedWasmArray, vUnsharedWasmArray, vSymbol, vBigInt] }, { name: "shared none", type: wasmRefNullType(kWasmNullRef).shared(), valid: [vNull], invalid: [vUndefined, vTrue, vFalse, vSmi, vHeapNumberSmi, vHeapNumber, - vStringLiteral, vStringDynamic, vSharedString, vSharedJSStruct, - vObject, vSharedWasmStruct, vSharedWasmArray, vUnsharedWasmStruct, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringLiteral, vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vSharedWasmArray, vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, + vBigInt] }, { name: "none", type: wasmRefNullType(kWasmNullRef), valid: [vNull], invalid: [vUndefined, vTrue, vFalse, vSmi, vHeapNumberSmi, vHeapNumber, - vStringLiteral, vStringDynamic, vSharedString, vSharedJSStruct, - vObject, vSharedWasmStruct, vSharedWasmArray, vUnsharedWasmStruct, - vUnsharedWasmArray, vSymbol, vBigInt] + vStringLiteral, vStringDynamic, vSharedString, vObject, vSharedWasmStruct, + vSharedWasmArray, vUnsharedWasmStruct, vUnsharedWasmArray, vSymbol, + vBigInt] }, ]; diff --git a/deps/v8/test/mjsunit/wasm/shared-memory-grow-bounds-check.js b/deps/v8/test/mjsunit/wasm/shared-memory-grow-bounds-check.js new file mode 100644 index 000000000000..049a9e5c6f65 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/shared-memory-grow-bounds-check.js @@ -0,0 +1,67 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-enforce-bounds-checks + +d8.file.execute('test/mjsunit/mjsunit.js'); +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const memory = new WebAssembly.Memory({initial: 1, maximum: 5, shared: true}); + +const builder = new WasmModuleBuilder(); +builder.addImportedMemory('mod', 'mem', 1, 5, true); + +// Function: +// Performs memory load at byte offset 65536 (page 2) without calling +// memory.size. +const body = [ + ...wasmI32Const(65536), + kAtomicPrefix, kExprI32AtomicLoad, 2, 0, +]; + +builder.addFunction('load_page2_without_size', makeSig([], [kWasmI32])) + .addBody(body) + .exportFunc(); + +const module = new WebAssembly.Module(builder.toBuffer()); + +function workerCode() { + onmessage = function({data: {module, memory}}) { + try { + const instance = new WebAssembly.Instance(module, {mod: {mem: memory}}); + postMessage({status: 'ready'}); + // Wait for main thread to grow memory and signal completion. + const i32 = new Int32Array(memory.buffer); + while (Atomics.load(i32, 0) !== 2) {} + const val = instance.exports.load_page2_without_size(); + postMessage({status: 'done', val: val}); + } catch (e) { + postMessage({status: 'error', error: String(e)}); + } + }; +} + +const worker = new Worker(workerCode, {type: 'function'}); +worker.postMessage({module: module, memory: memory}); + +const msg1 = worker.getMessage(); +assertEquals('ready', msg1.status, msg1.error); + +// Main thread grows memory +memory.grow(1); + +const i32_grown = new Int32Array(memory.buffer); +// Write payload to byte offset 65536 (index 16384 in Int32Array) +const payload_conv = new DataView(new ArrayBuffer(4)); +payload_conv.setInt32(0, 0x123456, true); +Atomics.store(i32_grown, 16384, new Int32Array(payload_conv.buffer)[0]); + +// Release worker by setting memory[0] = 2 +Atomics.store(i32_grown, 0, 2); + +const msg2 = worker.getMessage(); +assertEquals('done', msg2.status, msg2.error); +assertEquals(0x123456, msg2.val); + +worker.terminate(); diff --git a/deps/v8/test/mjsunit/wasm/shared-memory-size-atomic.js b/deps/v8/test/mjsunit/wasm/shared-memory-size-atomic.js new file mode 100644 index 000000000000..401ecd1aca90 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/shared-memory-size-atomic.js @@ -0,0 +1,88 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/mjsunit.js'); +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +const memory = new WebAssembly.Memory({initial: 1, maximum: 5, shared: true}); + +const builder = new WasmModuleBuilder(); +builder.addImportedMemory('mod', 'mem', 1, 5, true); + +// Function: +// 1. Sets memory[0] = 1 atomically to signal main thread. +// 2. Waits in Loop 1 for memory[0] == 2 (main thread signal). +// 3. Straight-line atomic load checks (NO loop, so no stack check interrupts). +// 4. Reads memory.size onto the stack (atomic seq_cst load). +// 5. Performs a memory load at byte offset 65536 (page 2). +// 6. Returns [size, page2_val]. +const body = [ + ...wasmI32Const(0), + ...wasmI32Const(1), + kAtomicPrefix, kExprI32AtomicStore, 2, 0, + + // Loop 1: Wait for memory[0] == 2 + kExprLoop, kWasmVoid, + ...wasmI32Const(0), + kAtomicPrefix, kExprI32AtomicLoad, 2, 0, + kExprI32Const, 2, + kExprI32Ne, + kExprBrIf, 0, + kExprEnd, + + // Straight-line: read memory.size and perform memory load at byte + // offset 65536. + kExprMemorySize, 0, + ...wasmI32Const(65536), + kAtomicPrefix, kExprI32AtomicLoad, 2, 0, +]; + +builder.addFunction( + 'check_size_and_load_page2', makeSig([], [kWasmI32, kWasmI32])) + .addBody(body) + .exportFunc(); + +const module = new WebAssembly.Module(builder.toBuffer()); + +function workerCode() { + onmessage = function({data: {module, memory}}) { + try { + const instance = new WebAssembly.Instance(module, {mod: {mem: memory}}); + postMessage({status: 'ready'}); + const results = instance.exports.check_size_and_load_page2(); + postMessage({status: 'done', size: results[0], page2_val: results[1]}); + } catch (e) { + postMessage({status: 'error', error: String(e)}); + } + }; +} + +const worker = new Worker(workerCode, {type: 'function'}); +worker.postMessage({module: module, memory: memory}); + +const msg1 = worker.getMessage(); +assertEquals('ready', msg1.status, msg1.error); + +// Wait for worker to enter the Wasm function Loop 1 +const i32 = new Int32Array(memory.buffer); +while (Atomics.load(i32, 0) !== 1) {} + +// Main thread grows memory first while worker is waiting in Loop 1 +memory.grow(1); + +const i32_grown = new Int32Array(memory.buffer); +// Write magic payload to byte offset 65536 (index 16384 in Int32Array) +Atomics.store(i32_grown, 16384, 0x778899); + +// Release worker from Loop 1 by setting memory[0] = 2 +Atomics.store(i32_grown, 0, 2); + +const msg2 = worker.getMessage(); +assertEquals('done', msg2.status, msg2.error); +// Worker observed memory.size == 2 and successfully loaded 0x778899 from +// page 2 (byte offset 65536) +assertEquals(2, msg2.size); +assertEquals(0x778899, msg2.page2_val); + +worker.terminate(); diff --git a/deps/v8/test/mjsunit/wasm/simd-add-sub-high-narrow.js b/deps/v8/test/mjsunit/wasm/simd-add-sub-high-narrow.js new file mode 100644 index 000000000000..32e070d11211 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/simd-add-sub-high-narrow.js @@ -0,0 +1,93 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +d8.file.execute('test/mjsunit/value-helper.js'); + +// Test narrowing right-shifted SIMD sums and differences with saturating +// conversions. + +const configs = [ + { + laneBits: 16, + values: int16_array, + type: kWasmI32, + splat: kExprI16x8Splat, + extract: kExprI8x16ExtractLaneS, + add: kExprI16x8Add, + sub: kExprI16x8Sub, + shrS: kExprI16x8ShrS, + shrU: kExprI16x8ShrU, + narrowS: kExprI8x16SConvertI16x8, + narrowU: kExprI8x16UConvertI16x8 + }, + { + laneBits: 32, + values: int32_array, + type: kWasmI32, + splat: kExprI32x4Splat, + extract: kExprI16x8ExtractLaneS, + add: kExprI32x4Add, + sub: kExprI32x4Sub, + shrS: kExprI32x4ShrS, + shrU: kExprI32x4ShrU, + narrowS: kExprI16x8SConvertI32x4, + narrowU: kExprI16x8UConvertI32x4 + }, +]; + +function addConvertCase(config, testAdd, arithmeticShift, lane) { + const builder = new WasmModuleBuilder(); + const {type, splat, extract, laneBits} = config; + const binop = testAdd ? config.add : config.sub; + const shift = arithmeticShift ? config.shrS : config.shrU; + + builder.addFunction( + 'convert', makeSig([type, type, type, type], [kWasmI32])) + .addBody([ + kExprLocalGet, 0, + ...SimdInstr(splat), + kExprLocalGet, 1, + ...SimdInstr(splat), + ...SimdInstr(binop), + ...wasmI32Const(laneBits / 2), + ...SimdInstr(shift), + kExprLocalGet, 2, + ...SimdInstr(splat), + kExprLocalGet, 3, + ...SimdInstr(splat), + ...SimdInstr(binop), + ...wasmI32Const(laneBits / 2), + ...SimdInstr(shift), + ...SimdInstr(arithmeticShift ? config.narrowS : config.narrowU), + ...SimdInstr(extract), lane, + ]) + .exportFunc(); + + const wasm = builder.instantiate().exports; + testResults(config, testAdd, wasm.convert); +} + +function testResults(config, testAdd, func) { + const narrowBits = config.laneBits / 2; + for (const left of config.values) { + for (const right of config.values) { + const a = BigInt(left); + const b = BigInt(right); + const value = BigInt.asUintN(config.laneBits, testAdd ? a + b : a - b); + const shifted = value >> BigInt(narrowBits); + const expected = Number(BigInt.asIntN(narrowBits, shifted)); + assertEquals(expected, func(left, right, left, right)); + } + } +} + +for (const config of configs) { + for (const testAdd of [false, true]) { + for (const arithmeticShift of [false, true]) { + addConvertCase(config, testAdd, arithmeticShift, 0); + addConvertCase(config, testAdd, arithmeticShift, 128 / config.laneBits); + } + } +} diff --git a/deps/v8/test/mjsunit/wasm/simd-i64x2-mul-mixed-sign.js b/deps/v8/test/mjsunit/wasm/simd-i64x2-mul-mixed-sign.js new file mode 100644 index 000000000000..5d1e579996c1 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/simd-i64x2-mul-mixed-sign.js @@ -0,0 +1,74 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +d8.file.execute('test/mjsunit/value-helper.js'); + +// Test widening multiplication of signed and unsigned 32-bit integers. +const mixed_sign_mul_configs = [ + { + name: 'i32x4 * u32x4 -> i64x2 low', + left_values: int32_array, + right_values: new Uint32Array(int32_array), + left_ext: kExprI64x2SConvertI32x4Low, + right_ext: kExprI64x2UConvertI32x4Low, + }, + { + name: 'u32x4 * i32x4 -> i64x2 low', + left_values: new Uint32Array(int32_array), + right_values: int32_array, + left_ext: kExprI64x2UConvertI32x4Low, + right_ext: kExprI64x2SConvertI32x4Low, + }, + { + name: 'i32x4 * u32x4 -> i64x2 high', + left_values: int32_array, + right_values: new Uint32Array(int32_array), + left_ext: kExprI64x2SConvertI32x4High, + right_ext: kExprI64x2UConvertI32x4High, + }, + { + name: 'u32x4 * i32x4 -> i64x2 high', + left_values: new Uint32Array(int32_array), + right_values: int32_array, + left_ext: kExprI64x2UConvertI32x4High, + right_ext: kExprI64x2SConvertI32x4High, + }, +]; + +function TestMixedSignMul(config) { + const builder = new WasmModuleBuilder(); + const {left_ext, right_ext} = config; + builder.addFunction( + 'mixed_sign_mul', makeSig([kWasmI32, kWasmI32], [kWasmI64, kWasmI64])) + .addLocals(kWasmS128, 1) + .addBody([ + kExprLocalGet, 0, + ...SimdInstr(kExprI32x4Splat), + ...SimdInstr(left_ext), + kExprLocalGet, 1, + ...SimdInstr(kExprI32x4Splat), + ...SimdInstr(right_ext), + ...SimdInstr(kExprI64x2Mul), + kExprLocalTee, 2, + ...SimdInstr(kExprI64x2ExtractLane), 0, + kExprLocalGet, 2, + ...SimdInstr(kExprI64x2ExtractLane), 1, + ]) + .exportFunc(); + + const wasm = builder.instantiate().exports; + for (const left of config.left_values) { + for (const right of config.right_values) { + const expected = BigInt(left) * BigInt(right); + assertEquals( + [expected, expected], wasm.mixed_sign_mul(left, right), + `${config.name}, left ${left}, right ${right}`); + } + } +} + +for (const config of mixed_sign_mul_configs) { + TestMixedSignMul(config); +} diff --git a/deps/v8/test/mjsunit/wasm/simd-narrow-interleave.js b/deps/v8/test/mjsunit/wasm/simd-narrow-interleave.js new file mode 100644 index 000000000000..30be743863ff --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/simd-narrow-interleave.js @@ -0,0 +1,259 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +d8.file.execute('test/mjsunit/value-helper.js'); + +// Test that low-half widening followed by two whole-lane shuffles and matching +// narrowing can be replaced with a single shuffle of the original inputs, +// if the shuffle width is equal to vector lanes' widths after widening. + +// Shuffles for the low and high halves of the narrowed result that concatenate +// to give the expected mask, for the cases of 16 and 32-bit shuffles. +const halfwordShuffles = [{ + name: 'Zip', + low: [0, 8, 1, 9, 2, 10, 3, 11], + high: [4, 12, 5, 13, 6, 14, 7, 15], +}, { + name: 'Unzip', + low: [0, 2, 4, 6, 8, 10, 12, 14], + high: [1, 3, 5, 7, 9, 11, 13, 15], +}, { + name: 'Transpose', + low: [0, 8, 2, 10, 4, 12, 6, 14], + high: [1, 9, 3, 11, 5, 13, 7, 15], +}, { + name: 'Extract', + low: [1, 2, 3, 4, 5, 6, 7, 8], + high: [7, 8, 9, 10, 11, 12, 13, 14], +}, { + name: 'PermutationWithDuplicates', + low: [15, 0, 9, 9, 6, 2, 12, 4], + high: [8, 7, 1, 14, 3, 11, 5, 10], +}]; + +const wordShuffles = [{ + name: 'Zip', + low: [0, 4, 1, 5], + high: [2, 6, 3, 7], +}, { + name: 'Unzip', + low: [0, 2, 4, 6], + high: [1, 3, 5, 7], +}, { + name: 'Transpose', + low: [0, 4, 2, 6], + high: [1, 5, 3, 7], +}, { + name: 'Extract', + low: [1, 2, 3, 4], + high: [3, 4, 5, 6], +}, { + name: 'PermutationWithDuplicates', + low: [7, 0, 5, 5], + high: [2, 4, 1, 6], +}]; + +function ShuffleBytes(lanes, laneBytes) { + // Expand each whole source lane into consecutive byte indices. For example, + // halfword lanes [0, 8] become bytes [0, 1, 16, 17]. + return lanes.flatMap(lane => + Array.from({length: laneBytes}, (_, byte) => lane * laneBytes + byte)); +} + +// Creates the values and intermediates +function ExpectedNarrowShuffle(lhs, rhs, config) { + const laneBytes = config.arrayType.BYTES_PER_ELEMENT; + const wideBytes = 2 * laneBytes; + const widened = new DataView(new ArrayBuffer(32)); + for (const [input, values] of [lhs, rhs].entries()) { + const start = input === 1 && config.highRight ? 8 / laneBytes : 0; + for (let lane = 0; lane < 8 / laneBytes; ++lane) { + const offset = 16 * input + wideBytes * lane; + if (wideBytes === 2) { + widened.setInt16(offset, values[start + lane], true); + } else { + widened.setInt32(offset, values[start + lane], true); + } + } + } + const bits = 8 * laneBytes; + const min = config.signed ? -(2 ** (bits - 1)) : 0; + const max = config.signed ? 2 ** (bits - 1) - 1 : 2 ** bits - 1; + const expected = []; + const intermediates = Array.from(new Uint8Array(widened.buffer)); + for (const mask of [config.lowShuffle, config.highShuffle]) { + const shuffled = new DataView(new ArrayBuffer(16)); + for (let byte = 0; byte < 16; ++byte) { + shuffled.setUint8(byte, widened.getUint8(mask[byte])); + } + intermediates.push(...new Uint8Array(shuffled.buffer)); + for (let byte = 0; byte < 16; byte += wideBytes) { + // Both signed and unsigned Wasm narrowing interpret the input as signed. + const value = wideBytes === 2 ? shuffled.getInt16(byte, true) : + shuffled.getInt32(byte, true); + expected.push(Math.min(max, Math.max(min, value))); + } + } + return {result: expected, intermediates}; +} + +// Take two input vector lanes, widen their lower halves, narrow with the same +// signedness, then check if this equal the expected shuffling. +function NarrowShuffleTest(config) { + print(config.name); + const builder = new WasmModuleBuilder(); + builder.addMemory(1, 1); + builder.exportMemoryAs('memory'); + + const simd = [ + kExprLocalGet, 0, // Push lhs/rhs inputs and widen + ...SimdInstr(kExprS128LoadMem), 0, 0, + ...SimdInstr(config.extend), + kExprLocalSet, 3, + kExprLocalGet, 1, + ...SimdInstr(kExprS128LoadMem), 0, 0, + ...SimdInstr(config.highRight ? config.extendHigh : config.extend), + kExprLocalSet, 4, + kExprLocalGet, 2, // Get output address + kExprLocalGet, 3, kExprLocalGet, 4, // Do low/high shuffles + ...SimdInstr(kExprI8x16Shuffle), ...config.lowShuffle, + kExprLocalTee, 5, + kExprLocalGet, 3, kExprLocalGet, 4, + ...SimdInstr(kExprI8x16Shuffle), ...config.highShuffle, + kExprLocalTee, 6, + ...SimdInstr(config.narrow), // Narrow the result and store + ...SimdInstr(kExprS128StoreMem), 0, 0, + ]; + + // For the sharedInputs case, store widens and shuffles after narrowing. + if (config.sharedInputs) { + for (let i = 0; i < 4; ++i) { + simd.push( + kExprLocalGet, 2, + kExprLocalGet, 3 + i, + ...SimdInstr(kExprS128StoreMem), 0, 16 * (i + 1)); + } + } + + builder.addFunction('simd', kSig_v_iii) + .addLocals(kWasmS128, 4) + .addBody(simd) + .exportFunc(); + + const wasm = builder.instantiate().exports; + const laneBytes = config.arrayType.BYTES_PER_ELEMENT; + const numLanes = 16 / laneBytes; + const lhs = new config.arrayType(numLanes); + const rhs = new config.arrayType(numLanes); + const result = new config.arrayType(numLanes); + const memory = new DataView(wasm.memory.buffer); + const values = config.values; + + for (let i = 0; i < values.length; ++i) { + for (let lane = 0; lane < numLanes; ++lane) { + // Right lane reads numLanes ahead of the left to catch bad shuffles. + lhs[lane] = values[(i + lane) % values.length]; + rhs[lane] = values[(i + numLanes + lane) % values.length]; + if (laneBytes === 1) { + memory.setInt8(lane, lhs[lane]); + memory.setInt8(16 + lane, rhs[lane]); + } else { + memory.setInt16(2 * lane, lhs[lane], true); + memory.setInt16(16 + 2 * lane, rhs[lane], true); + } + } + const expected = ExpectedNarrowShuffle(lhs, rhs, config); + // Call with offsets for the lhs, rhs and result. + wasm.simd(0, 16, 32); + for (let lane = 0; lane < numLanes; ++lane) { + result[lane] = laneBytes === 1 ? memory.getInt8(32 + lane) : + memory.getInt16(32 + 2 * lane, true); + } + assertEquals(expected.result, Array.from(result), `${config.name}: ${i}`); + if (config.sharedInputs) { + assertEquals( + expected.intermediates, + // Reads widened left/right inputs and both shuffle results. + Array.from(new Uint8Array(wasm.memory.buffer, 48, 64)), + `${config.name}: intermediates ${i}`); + } + } +} + +const configs = [{ + name: 'Signed8To16To8', + extend: kExprI16x8SConvertI8x16Low, + extendHigh: kExprI16x8SConvertI8x16High, + narrow: kExprI8x16SConvertI16x8, + signed: true, + arrayType: Int8Array, + values: int8_array, +}, { + name: 'Unsigned8To16To8', + extend: kExprI16x8UConvertI8x16Low, + extendHigh: kExprI16x8UConvertI8x16High, + narrow: kExprI8x16UConvertI16x8, + signed: false, + arrayType: Uint8Array, + values: int8_array, +}, { + name: 'Signed16To32To16', + extend: kExprI32x4SConvertI16x8Low, + extendHigh: kExprI32x4SConvertI16x8High, + narrow: kExprI16x8SConvertI32x4, + signed: true, + arrayType: Int16Array, + values: int16_array, +}, { + name: 'Unsigned16To32To16', + extend: kExprI32x4UConvertI16x8Low, + extendHigh: kExprI32x4UConvertI16x8High, + narrow: kExprI16x8UConvertI32x4, + signed: false, + arrayType: Uint16Array, + values: int16_array, +}]; + +(function NarrowShuffleTestAll() { + for (const config of configs) { + const laneBytes = config.arrayType.BYTES_PER_ELEMENT; + const wideBytes = 2 * laneBytes; + const shuffles = laneBytes === 1 ? halfwordShuffles : wordShuffles; + for (const shuffle of shuffles) { + const base = { + ...config, + name: `${config.name}/${shuffle.name}`, + lowShuffle: ShuffleBytes(shuffle.low, wideBytes), + highShuffle: ShuffleBytes(shuffle.high, wideBytes), + }; + function TestCase(name, overrides) { + NarrowShuffleTest({ ...base, ...overrides, name: `${base.name}/${name}` }); + } + + NarrowShuffleTest(base); + TestCase('SharedInputs', {sharedInputs: true}); + TestCase('HighHalfRightInput', {highRight: true}); + + // Break each shuffle independently: both masks must preserve whole lanes. + for (const field of ['lowShuffle', 'highShuffle']) { + const mask = base[field]; + const dataInUpperHalf = mask.slice(); + dataInUpperHalf[wideBytes - 1] = mask[0]; + TestCase(`${field}/DataInUpperHalf`, {[field]: dataInUpperHalf}); + + const extensionInLowerHalf = mask.slice(); + extensionInLowerHalf[0] = mask[laneBytes]; + TestCase(`${field}/ExtensionInLowerHalf`, + {[field]: extensionInLowerHalf}); + + const otherExtension = mask.slice(); + // Replace the first vector lane's upper half with another upper half. + // Reject since shuffling is done at a finer level than vector masks. + otherExtension[laneBytes] = (mask[0] + wideBytes + laneBytes) % 32; + TestCase(`${field}/OtherExtension`, {[field]: otherExtension}); + } + } + } +})(); diff --git a/deps/v8/test/mjsunit/wasm/simd-replace-lane-zero.js b/deps/v8/test/mjsunit/wasm/simd-replace-lane-zero.js index 414721719ba8..7af947bb463d 100644 --- a/deps/v8/test/mjsunit/wasm/simd-replace-lane-zero.js +++ b/deps/v8/test/mjsunit/wasm/simd-replace-lane-zero.js @@ -4,34 +4,46 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +function LEView(memory, type, count) { + const dv = new DataView(memory.buffer); + const accessors = { + i32: {size: 4, get: (i) => dv.getInt32(i * 4, true)}, + i64: {size: 8, get: (i) => dv.getBigInt64(i * 8, true)}, + f32: {size: 4, get: (i) => dv.getFloat32(i * 4, true)}, + f64: {size: 8, get: (i) => dv.getFloat64(i * 8, true)}, + }; + const {size, get} = accessors[type]; + return {get, byteLength: count * size}; +} + (function ReplaceLaneZeroWithConstant() { const replace_lane_configs = [ { name: 'i32x4 lane0', replace_opcode: kExprI32x4ReplaceLane, value_bytes: wasmI32Const(0x1234), - view: (memory) => new Int32Array(memory.buffer, 0, 4), + view: (memory) => LEView(memory, 'i32', 4), expected: [0x1234, 0, 0, 0], }, { name: 'i64x2 lane0', replace_opcode: kExprI64x2ReplaceLane, value_bytes: wasmI64Const(0x1234), - view: (memory) => new BigInt64Array(memory.buffer, 0, 2), + view: (memory) => LEView(memory, 'i64', 2), expected: [0x1234n, 0n], }, { name: 'f32x4 lane0', replace_opcode: kExprF32x4ReplaceLane, value_bytes: wasmF32Const(1.5), - view: (memory) => new Float32Array(memory.buffer, 0, 4), + view: (memory) => LEView(memory, 'f32', 4), expected: [1.5, 0, 0, 0], }, { name: 'f64x2 lane0', replace_opcode: kExprF64x2ReplaceLane, value_bytes: wasmF64Const(2.25), - view: (memory) => new Float64Array(memory.buffer, 0, 2), + view: (memory) => LEView(memory, 'f64', 2), expected: [2.25, 0], }, ]; @@ -61,7 +73,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); const view = config.view(memory); for (let i = 0; i < config.expected.length; ++i) { - assertEquals(config.expected[i], view[i]); + assertEquals(config.expected[i], view.get(i)); } // The rest should be zero. for (let i = view.byteLength; i < 16; ++i) { @@ -77,7 +89,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); replace_opcode: kExprI32x4ReplaceLane, sig: kSig_v_i, param_value: 0x5678, - view: (memory) => new Int32Array(memory.buffer, 0, 4), + view: (memory) => LEView(memory, 'i32', 4), expected: [0x5678, 0, 0, 0], }, { @@ -85,7 +97,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); replace_opcode: kExprI64x2ReplaceLane, sig: kSig_v_l, param_value: 0x5678n, - view: (memory) => new BigInt64Array(memory.buffer, 0, 2), + view: (memory) => LEView(memory, 'i64', 2), expected: [0x5678n, 0n], }, { @@ -93,7 +105,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); replace_opcode: kExprF32x4ReplaceLane, sig: kSig_v_f, param_value: 3.5, - view: (memory) => new Float32Array(memory.buffer, 0, 4), + view: (memory) => LEView(memory, 'f32', 4), expected: [3.5, 0, 0, 0], }, { @@ -101,7 +113,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); replace_opcode: kExprF64x2ReplaceLane, sig: kSig_v_d, param_value: 4.75, - view: (memory) => new Float64Array(memory.buffer, 0, 2), + view: (memory) => LEView(memory, 'f64', 2), expected: [4.75, 0], }, ]; @@ -131,7 +143,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); const view = config.view(memory); for (let i = 0; i < config.expected.length; ++i) { - assertEquals(config.expected[i], view[i]); + assertEquals(config.expected[i], view.get(i)); } // The rest should be zero. for (let i = view.byteLength; i < 16; ++i) { diff --git a/deps/v8/test/mjsunit/wasm/simd-shift-left-long.js b/deps/v8/test/mjsunit/wasm/simd-shift-left-long.js new file mode 100644 index 000000000000..0bf0f05f6edf --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/simd-shift-left-long.js @@ -0,0 +1,100 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); +d8.file.execute('test/mjsunit/value-helper.js'); + +const shift_left_long_configs = [ + { + name: 'i8x16 -> i16x8', + source_bits: 8, + values: int8_array, + sig: kSig_i_i, + splat_opcode: kExprI8x16Splat, + convert_opcodes: [kExprI16x8SConvertI8x16Low, kExprI16x8SConvertI8x16High], + shift_opcode: kExprI16x8Shl, + extract_opcode: kExprI16x8ExtractLaneS, + }, + { + name: 'u8x16 -> u16x8', + source_bits: 8, + values: new Uint8Array(int8_array), + sig: kSig_i_i, + splat_opcode: kExprI8x16Splat, + convert_opcodes: [kExprI16x8UConvertI8x16Low, kExprI16x8UConvertI8x16High], + shift_opcode: kExprI16x8Shl, + extract_opcode: kExprI16x8ExtractLaneS, + }, + { + name: 'i16x8 -> i32x4', + source_bits: 16, + values: int16_array, + sig: kSig_i_i, + splat_opcode: kExprI16x8Splat, + convert_opcodes: [kExprI32x4SConvertI16x8Low, kExprI32x4SConvertI16x8High], + shift_opcode: kExprI32x4Shl, + extract_opcode: kExprI32x4ExtractLane, + }, + { + name: 'u16x8 -> u32x4', + source_bits: 16, + values: new Uint16Array(int16_array), + sig: kSig_i_i, + splat_opcode: kExprI16x8Splat, + convert_opcodes: [kExprI32x4UConvertI16x8Low, kExprI32x4UConvertI16x8High], + shift_opcode: kExprI32x4Shl, + extract_opcode: kExprI32x4ExtractLane, + }, + { + name: 'i32x4 -> i64x2', + source_bits: 32, + values: int32_array, + sig: kSig_l_i, + splat_opcode: kExprI32x4Splat, + convert_opcodes: [kExprI64x2SConvertI32x4Low, kExprI64x2SConvertI32x4High], + shift_opcode: kExprI64x2Shl, + extract_opcode: kExprI64x2ExtractLane, + }, + { + name: 'u32x4 -> u64x2', + source_bits: 32, + values: new Uint32Array(int32_array), + sig: kSig_l_i, + splat_opcode: kExprI32x4Splat, + convert_opcodes: [kExprI64x2UConvertI32x4Low, kExprI64x2UConvertI32x4High], + shift_opcode: kExprI64x2Shl, + extract_opcode: kExprI64x2ExtractLane, + }, +]; + +function TestShiftLeftLong(config, high) { + const source_bits = config.source_bits; + const lane_bits = 2 * source_bits; + for (let shift = -lane_bits; shift <= lane_bits + source_bits; ++shift) { + const builder = new WasmModuleBuilder(); + builder.addFunction('shift_left_long', config.sig) + .addBody([ + kExprLocalGet, 0, + ...SimdInstr(config.splat_opcode), + ...SimdInstr(config.convert_opcodes[high]), + ...wasmI32Const(shift), + ...SimdInstr(config.shift_opcode), + ...SimdInstr(config.extract_opcode), 0, + ]) + .exportFunc(); + + const wasm = builder.instantiate().exports; + const shift_amount = BigInt(shift & (lane_bits - 1)); + for (const value of config.values) { + const result = wasm.shift_left_long(value); + const expected = BigInt.asIntN(lane_bits, BigInt(value) << shift_amount); + assertEquals(lane_bits === 64 ? expected : Number(expected), result); + } + } +} + +for (const config of shift_left_long_configs) { + TestShiftLeftLong(config, 0); + TestShiftLeftLong(config, 1); +} diff --git a/deps/v8/test/mjsunit/wasm/stack-switching-profiler.js b/deps/v8/test/mjsunit/wasm/stack-switching-profiler.js new file mode 100644 index 000000000000..957b8f1c0fe8 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/stack-switching-profiler.js @@ -0,0 +1,55 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-wasmfx --cpu-profiler-sampling-interval=10 + +d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); + +(function TestStackSwitchingProfiler() { + let builder = new WasmModuleBuilder(); + let sig_v_v = builder.addType(kSig_v_v); + let cont_index = builder.addCont(sig_v_v); + let nop = builder.addFunction("nop", sig_v_v).addBody([]).exportFunc(); + let kCount = 10; + let table = builder.addTable(wasmRefNullType(cont_index), kCount, kCount); + builder.addFunction("fill", kSig_v_v) + .addLocals(kWasmI32, 1) + .addBody([ + kExprLoop, kWasmVoid, + kExprLocalGet, 0, + kExprRefFunc, nop.index, + kExprContNew, cont_index, + kExprTableSet, table.index, + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Add, + kExprLocalTee, 0, + kExprI32Const, ...wasmSignedLeb(kCount), + kExprI32LtU, + kExprBrIf, 0, + kExprEnd, + ]).exportFunc(); + builder.addFunction("run", kSig_v_v) + .addLocals(kWasmI32, 1) + .addBody([ + kExprLoop, kWasmVoid, + kExprLocalGet, 0, + kExprTableGet, table.index, + kExprResume, cont_index, 0, + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Add, + kExprLocalTee, 0, + kExprI32Const, ...wasmSignedLeb(kCount), + kExprI32LtU, + kExprBrIf, 0, + kExprEnd, + ]).exportFunc(); + const instance = builder.instantiate(); + console.profile(); + for (let i = 0; i < 100; ++i) { + instance.exports.fill(); + instance.exports.run(); + } +})(); diff --git a/deps/v8/test/mjsunit/wasm/stack-switching.js b/deps/v8/test/mjsunit/wasm/stack-switching.js index fdfa99fa149c..0eff23864af7 100644 --- a/deps/v8/test/mjsunit/wasm/stack-switching.js +++ b/deps/v8/test/mjsunit/wasm/stack-switching.js @@ -52,6 +52,11 @@ builder.addFunction("call_next", kSig_v_v) kExprCallFunction, get_next_index, kExprCallRef, sig_v_v, ]).exportFunc(); +builder.addFunction("suspend_jspi_twice", kSig_v_v) + .addBody([ + kExprCallFunction, jspi_suspending_index, + kExprCallFunction, jspi_suspending_index, + ]).exportFunc(); builder.addFunction("call_next_in_catch_all", kSig_v_v) .addBody([ kExprTryTable, kWasmVoid, 1, @@ -437,3 +442,17 @@ instance = builder.instantiate( {m: { WebAssembly.promising(instance.exports.call_next_as_cont)(), WebAssembly.RuntimeError); })(); + +(function TestJSPIInWasmFXSuspendTwice() { + print(arguments.callee.name); + let promise; + let call_promising = () => { + promise = WebAssembly.promising(instance.exports.suspend_jspi_twice)(); + }; + instance.exports.call_stack.value = [ + instance.exports.call_next_from_js, + call_promising, + ]; + instance.exports.call_next_as_cont(); + assertPromiseResult(promise); +})(); diff --git a/deps/v8/test/mjsunit/wasm/test-growable-tail-call-matrix.js b/deps/v8/test/mjsunit/wasm/test-growable-tail-call-matrix.js new file mode 100644 index 000000000000..3cbf1392f3e2 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/test-growable-tail-call-matrix.js @@ -0,0 +1,248 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-growable-stacks --no-wasm-inlining +// Flags: --wasm-wasmfx --allow-natives-syntax + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +function addActiveLocals(func, numParams, numLocals = 600) { + func.addLocals(kWasmI64, numLocals + 1); + const firstLocal = numParams; + const lastLocal = numParams + numLocals - 1; + const sumIdx = numParams + numLocals; + const body = [ + kExprLocalGet, 0, + kExprI64UConvertI32, + kExprI64Const, 1, + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(firstLocal), + ]; + for (let i = firstLocal + 1; i <= lastLocal; ++i) { + body.push( + kExprLocalGet, ...wasmUnsignedLeb(i - 1), + kExprI64Const, 1, + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(i), + ); + } + body.push(kExprI64Const, 0, kExprLocalSet, ...wasmUnsignedLeb(sumIdx)); + for (let i = firstLocal; i <= lastLocal; ++i) { + body.push( + kExprLocalGet, ...wasmUnsignedLeb(sumIdx), + kExprLocalGet, ...wasmUnsignedLeb(i), + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(sumIdx), + ); + } + body.push( + kExprLocalGet, ...wasmUnsignedLeb(sumIdx), + kExprI64Eqz, + kExprIf, kWasmVoid, + kExprUnreachable, + kExprEnd, + ); + return body; +} + +// Test 1: Asymmetric tail calls: growing stack params (delta > 0) and +// shrinking stack params (delta < 0) across segment boundaries. +(function testAsymmetricStackParamsDelta() { + const builder = new WasmModuleBuilder(); + + // Sig small: (depth: i32, a: i32, b: i64, c: f64) -> (i64, f64) + const sigSmall = builder.addType( + makeSig([kWasmI32, kWasmI32, kWasmI64, kWasmF64], [kWasmI64, kWasmF64])); + + // Sig large: (depth: i32, a: i32, b: i64, c: f64, p4..p35: i32) -> (i64, f64) + const largeParams = [kWasmI32, kWasmI32, kWasmI64, kWasmF64]; + for (let i = 4; i < 36; ++i) largeParams.push(kWasmI32); + const sigLarge = builder.addType(makeSig(largeParams, [kWasmI64, kWasmF64])); + + // f_small (index 0): small frame, calls f_large_caller + const f_small = builder.addFunction('f_small', sigSmall); + f_small.addLocals(kWasmI32, 2); + f_small.addBody([ + kExprLocalGet, 0, // depth + kExprI32Eqz, + kExprIf, kWasmVoid, + kExprLocalGet, 2, // return b + kExprLocalGet, 3, // return c + kExprReturn, + kExprEnd, + // Call f_large_grower with 36 params + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprLocalGet, 2, + kExprLocalGet, 3, + ...(() => { + let extra = []; + for (let i = 4; i < 36; ++i) extra.push(kExprI32Const, i); + return extra; + })(), + kExprCallFunction, 1, // call f_large_grower (index 1) + ]); + + // f_large_grower (index 1): large frame (600 locals) forces stack segment + // allocation, then tail-calls f_small (delta < 0, shrinking stack params + // from 36 to 4). + const f_large_grower = builder.addFunction('f_large_grower', sigLarge); + const growerLocals = addActiveLocals(f_large_grower, 36, 600); + f_large_grower.addBody([ + ...growerLocals, + // Verify extra params + kExprLocalGet, 4, + kExprI32Const, 4, + kExprI32Ne, + kExprIf, kWasmVoid, + kExprUnreachable, + kExprEnd, + kExprLocalGet, 35, + kExprI32Const, 35, + kExprI32Ne, + kExprIf, + kWasmVoid, + kExprUnreachable, + kExprEnd, + + // Tail-call f_small (shrinking stack params) + kExprLocalGet, 0, // depth + kExprLocalGet, 1, // a + kExprLocalGet, 2, // b + kExprLocalGet, 3, // c + kExprReturnCall, 0, // return_call f_small + ]); + + builder.addExport('main', 0); + const instance = builder.instantiate(); + const promising_main = WebAssembly.promising(instance.exports.main); + + assertPromiseResult(promising_main(5, 42, 1000n, 3.14159), res => { + assertEquals(1000n, res[0]); + assertEquals(3.14159, res[1]); + }); +})(); + +// Test 2: Growing stack params (delta > 0) in tail call across segment +// boundaries. +(function testGrowingStackParamsDelta() { + const builder = new WasmModuleBuilder(); + + const sigSmall = builder.addType(makeSig([kWasmI32, kWasmI32], [kWasmI32])); + const largeParams = [kWasmI32, kWasmI32]; + for (let i = 2; i < 30; ++i) largeParams.push(kWasmI32); + const sigLarge = builder.addType(makeSig(largeParams, [kWasmI32])); + + // f_consumer (index 0): sums all 30 params + const f_consumer = builder.addFunction('f_consumer', sigLarge); + f_consumer.addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kExprI32Add, + ...(() => { + let ops = []; + for (let i = 2; i < 30; ++i) ops.push(kExprLocalGet, i, kExprI32Add); + return ops; + })(), + ]); + + // f_step (index 1): takes 2 params (sigSmall), large frame forces segment + // allocation, then tail-calls f_consumer with 30 params (delta > 0). + const f_step = builder.addFunction('f_step', sigSmall); + const stepLocals = addActiveLocals(f_step, 2, 1000); + f_step.addBody([ + ...stepLocals, + kExprLocalGet, 0, + kExprLocalGet, 1, + ...(() => { + let ops = []; + for (let i = 2; i < 30; ++i) ops.push(kExprI32Const, i); + return ops; + })(), + kExprReturnCall, f_consumer.index, + ]); + + // f_entry (index 2): takes 2 params (sigSmall), calls f_step + const f_entry = builder.addFunction('f_entry', sigSmall); + f_entry.addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, + kExprCallFunction, + f_step.index, + ]); + + builder.addExport('main', f_entry.index); + const instance = builder.instantiate(); + const promising_main = WebAssembly.promising(instance.exports.main); + + // Sum of 0..29 = 435. 10 + 20 + 2..29 = 464. + assertPromiseResult(promising_main(10, 20), res => assertEquals(464, res)); +})(); + +// Test 3: Indirect tail calls (return_call_indirect) across segment boundaries. +(function testIndirectTailCallsAcrossSegments() { + const builder = new WasmModuleBuilder(); + + const paramTypes = [kWasmI32, kWasmI64, kWasmF64]; + for (let i = 3; i < 20; ++i) paramTypes.push(kWasmI32); + const sig = builder.addType(makeSig(paramTypes, [kWasmI64])); + + const table = builder.addTable(kWasmFuncRef, 2, 2); + + // f_target (index 0) + const f_target = builder.addFunction('f_target', sig); + f_target.addBody([ + kExprLocalGet, 0, // depth + kExprI32Eqz, + kExprIf, kWasmVoid, + kExprLocalGet, 1, // return i64 + kExprReturn, + kExprEnd, + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, + kExprLocalGet, 1, + kExprLocalGet, 2, + ...(() => { + let ops = []; + for (let i = 3; i < 20; ++i) ops.push(kExprLocalGet, i); + return ops; + })(), + kExprCallFunction, + 1, // call f_grow + ]); + + // f_grow (index 1): large frame, indirect tail call back to f_target + // (table index 0). + const f_grow = builder.addFunction('f_grow', sig); + const growLocals = addActiveLocals(f_grow, 20, 600); + f_grow.addBody([ + ...growLocals, + kExprLocalGet, 0, + kExprLocalGet, 1, + kExprLocalGet, 2, + ...(() => { + let ops = []; + for (let i = 3; i < 20; ++i) ops.push(kExprLocalGet, i); + return ops; + })(), + kExprI32Const, 0, // table index 0 + kExprReturnCallIndirect, sig, table.index, + ]); + + builder.addActiveElementSegment( + table.index, [kExprI32Const, 0], [f_target.index, f_grow.index]); + builder.addExport('main', 0); + + const instance = builder.instantiate(); + const promising_main = WebAssembly.promising(instance.exports.main); + const args = [5, 777777n, 2.718]; + for (let i = 3; i < 20; ++i) args.push(i * 10); + assertPromiseResult( + promising_main(...args), res => assertEquals(777777n, res)); +})(); + +print('test-growable-tail-call-matrix passed!'); diff --git a/deps/v8/test/mjsunit/wasm/test-growable-tail-call-stack-params.js b/deps/v8/test/mjsunit/wasm/test-growable-tail-call-stack-params.js new file mode 100644 index 000000000000..f702a8203446 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/test-growable-tail-call-stack-params.js @@ -0,0 +1,99 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --wasm-growable-stacks --no-wasm-inlining +// Flags: --wasm-wasmfx --allow-natives-syntax + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +function addActiveLocals(func, numParams, numLocals = 600) { + func.addLocals(kWasmI64, numLocals + 1); + const firstLocal = numParams; + const lastLocal = numParams + numLocals - 1; + const sumIdx = numParams + numLocals; + const body = [ + kExprLocalGet, 0, + kExprI64UConvertI32, + kExprI64Const, 1, + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(firstLocal), + ]; + for (let i = firstLocal + 1; i <= lastLocal; ++i) { + body.push( + kExprLocalGet, ...wasmUnsignedLeb(i - 1), + kExprI64Const, 1, + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(i), + ); + } + body.push(kExprI64Const, 0, kExprLocalSet, ...wasmUnsignedLeb(sumIdx)); + for (let i = firstLocal; i <= lastLocal; ++i) { + body.push( + kExprLocalGet, ...wasmUnsignedLeb(sumIdx), + kExprLocalGet, ...wasmUnsignedLeb(i), + kExprI64Add, + kExprLocalSet, ...wasmUnsignedLeb(sumIdx), + ); + } + body.push( + kExprLocalGet, ...wasmUnsignedLeb(sumIdx), + kExprI64Eqz, + kExprIf, kWasmVoid, + kExprUnreachable, + kExprEnd, + ); + return body; +} + +const builder = new WasmModuleBuilder(); + +// 12 parameters (forces stack parameters across IA32, X64, ARM, and ARM64) +const paramTypes = Array(12).fill(kWasmI32); +const sig = builder.addType(makeSig(paramTypes, [kWasmI32])); + +// f_dest: adds up all 12 parameters when depth == 0 +const f_dest_body = [ + kExprLocalGet, 0, // depth + kExprI32Eqz, + kExprIf, kWasmI32, +]; +f_dest_body.push(kExprLocalGet, 0); +for (let i = 1; i < 12; ++i) { + f_dest_body.push(kExprLocalGet, i, kExprI32Add); +} +f_dest_body.push(kExprReturn, kExprElse); +// Otherwise decrement depth and call f_grow +f_dest_body.push( + kExprLocalGet, 0, + kExprI32Const, 1, + kExprI32Sub, +); +for (let i = 1; i < 12; ++i) { + f_dest_body.push(kExprLocalGet, i); +} + +const f_dest = builder.addFunction('f_dest', sig); +const f_grow = builder.addFunction('f_grow', sig); + +f_dest_body.push(kExprCallFunction, f_grow.index, kExprEnd); +f_dest.addBody(f_dest_body); + +// f_grow: large frame (600 locals) to force stack growth, then tail calls +// f_dest. +const f_grow_body = [...addActiveLocals(f_grow, 12, 600)]; +for (let i = 0; i < 12; ++i) { + f_grow_body.push(kExprLocalGet, i); +} +f_grow_body.push(kExprReturnCall, f_dest.index); +f_grow.addBody(f_grow_body); + +builder.addExport('main', f_dest.index); + +const instance = builder.instantiate(); +const promising_main = WebAssembly.promising(instance.exports.main); + +// Sum of 1..11 = 66 +// First arg is the depth +assertPromiseResult(promising_main(5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), + res => assertEquals(66, res)); diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status index 5795e84776fe..2f738e6e838c 100644 --- a/deps/v8/test/test262/test262.status +++ b/deps/v8/test/test262/test262.status @@ -70,94 +70,6 @@ 'language/statements/variable/binding-resolution': [FAIL], # https://bugs.chromium.org/p/v8/issues/detail?id=4628 - 'language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-decl-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-func-expr-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-meth-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-meth-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/async-gen-named-func-expr-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-decl-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/func-decl-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-decl-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/func-decl-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-decl-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/func-decl-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-decl-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/func-decl-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-expr-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/func-expr-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-expr-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/func-expr-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-expr-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/func-expr-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/func-expr-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/func-expr-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-decl-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-decl-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-decl-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-decl-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-decl-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-decl-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-decl-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-decl-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-named-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-func-expr-nameless-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-meth-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-meth-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-meth-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-meth-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/gen-meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/meth-fn-body-cntns-arguments-func-decl-declare-arguments': [FAIL], - 'language/eval-code/direct/meth-fn-body-cntns-arguments-func-decl-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/meth-fn-body-cntns-arguments-lex-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/meth-fn-body-cntns-arguments-lex-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/meth-fn-body-cntns-arguments-var-bind-declare-arguments': [FAIL], - 'language/eval-code/direct/meth-fn-body-cntns-arguments-var-bind-declare-arguments-and-assign': [FAIL], - 'language/eval-code/direct/meth-no-pre-existing-arguments-bindings-are-present-declare-arguments': [FAIL], - 'language/eval-code/direct/meth-no-pre-existing-arguments-bindings-are-present-declare-arguments-and-assign': [FAIL], 'language/eval-code/direct/non-definable-function-with-function': [FAIL], 'language/eval-code/direct/non-definable-function-with-variable': [FAIL], 'language/eval-code/indirect/non-definable-function-with-function': [FAIL], @@ -255,44 +167,13 @@ # there are only 16 tests. Skip for now. 'staging/sm/Temporal/*': [SKIP], - # toLocaleString with just an era setting should format as default - # b/463427743 - 'intl402/Temporal/Instant/prototype/toLocaleString/era': [FAIL], - 'intl402/Temporal/PlainDate/prototype/toLocaleString/era': [FAIL], - 'intl402/Temporal/PlainDateTime/prototype/toLocaleString/era': [FAIL], - 'intl402/Temporal/ZonedDateTime/prototype/toLocaleString/era': [FAIL], - 'intl402/Temporal/PlainYearMonth/prototype/toLocaleString/era': [FAIL], - 'intl402/DateTimeFormat/prototype/format/temporal-objects-format-with-era': [FAIL], - 'intl402/DateTimeFormat/prototype/formatRange/temporal-objects-format-with-era': [FAIL], - # DateTimeFormat doesn't respect hourCycle for Temporal # b/468559222 'intl402/Temporal/Instant/prototype/toLocaleString/hourcycle': [SKIP], 'intl402/Temporal/PlainDateTime/prototype/toLocaleString/hourcycle': [SKIP], - 'intl402/Temporal/PlainTime/prototype/toLocaleString/datestyle-and-timestyle': [SKIP], 'intl402/Temporal/PlainTime/prototype/toLocaleString/hourcycle': [SKIP], 'intl402/Temporal/ZonedDateTime/prototype/toLocaleString/hourcycle': [SKIP], - # DateTimeFormat should ignore timezone setting when formatting plain dates - # b/494308555 - 'intl402/DateTimeFormat/prototype/format/temporal-objects-ignore-timezone': [SKIP], - 'intl402/DateTimeFormat/prototype/formatRange/temporal-objects-ignore-timezone': [SKIP], - 'intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-ignore-timezone': [SKIP], - 'intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-ignore-timezone': [SKIP], - 'intl402/Temporal/PlainDate/prototype/toLocaleString/ignore-timezone': [SKIP], - 'intl402/Temporal/PlainDateTime/prototype/toLocaleString/ignore-timezone': [SKIP], - - # Formatting a Plain* object should not break the formatter for Instant - # b/494309393 - 'intl402/Temporal/Instant/prototype/toLocaleString/respect-timezone-after-formatting-plaindatetime': [SKIP], - - # Adjusting of dateStyle - # b/494309457 - 'intl402/Temporal/Instant/prototype/toLocaleString/datestyle-not-adjusted-when-no-conflicting-options': [SKIP], - 'intl402/Temporal/PlainDate/prototype/toLocaleString/datestyle-not-adjusted-when-no-conflicting-options': [SKIP], - 'intl402/Temporal/PlainDateTime/prototype/toLocaleString/datestyle-not-adjusted-when-no-conflicting-options': [SKIP], - 'intl402/Temporal/ZonedDateTime/prototype/toLocaleString/datestyle-not-adjusted-when-no-conflicting-options': [SKIP], - # ICU4X and ICU4C do not implement the same algorithm for Chinese # b/434224293 'intl402/DateTimeFormat/prototype/formatToParts/compare-to-temporal-lunisolar': [SKIP], @@ -362,17 +243,12 @@ 'intl402/DateTimeFormat/prototype/format/timedatestyle-en': [FAIL], # In alignment with Firefox and Safari, Function.prototype.arguments and - # .caller are ordinary accessors instead of the "poison pill thrower" when V8 is - # compiled without V8_FUNCTION_ARGUMENTS_CALLER_ARE_OWN_PROPS. - # - # These expectations should be negated if the build time flag is true. + # .caller are ordinary accessors instead of the "poison pill thrower". # # See also https://bugs.chromium.org/p/v8/issues/detail?id=6049 'built-ins/Function/prototype/arguments/prop-desc': [FAIL], 'built-ins/Function/prototype/caller-arguments/accessor-properties': [FAIL], 'built-ins/Function/prototype/caller/prop-desc': [FAIL], - 'built-ins/Object/internals/DefineOwnProperty/consistent-value-function-caller': [PASS], - 'built-ins/Object/internals/DefineOwnProperty/consistent-value-function-arguments': [PASS], 'built-ins/ThrowTypeError/unique-per-realm-function-proto': [FAIL], ############################ INVALID TESTS ############################# @@ -786,7 +662,6 @@ [ALWAYS, { 'staging/sm/class/superCallOrder': [FAIL], 'staging/sm/class/superPropOrdering': [FAIL], - 'staging/sm/eval/redeclared-arguments-in-param-expression-eval': [FAIL], 'staging/sm/expressions/short-circuit-compound-assignment-property-key-evaluation': [FAIL], 'staging/sm/extensions/recursion': [FAIL], 'staging/sm/extensions/regress-650753': [FAIL], @@ -873,21 +748,6 @@ # End roll-watcher patch #### -#### -# Roll-watcher patch -[ALWAYS, { - 'language/expressions/assignmenttargettype/direct-callexpression': [SKIP], - 'language/expressions/assignmenttargettype/direct-callexpression-as-for-in-lhs': [SKIP], - 'language/expressions/assignmenttargettype/direct-callexpression-as-for-of-lhs': [SKIP], - 'language/expressions/assignmenttargettype/direct-callexpression-in-compound-assignment': [SKIP], - 'language/expressions/assignmenttargettype/direct-callexpression-in-postfix-update': [SKIP], - 'language/expressions/assignmenttargettype/direct-callexpression-in-prefix-update': [SKIP], - 'language/expressions/assignmenttargettype/parenthesized-callexpression': [SKIP], - 'language/expressions/assignmenttargettype/parenthesized-callexpression-in-compound-assignment': [SKIP], -}], -# End roll-watcher patch -#### - #### # Roll-watcher patch [ALWAYS, { @@ -1256,4 +1116,18 @@ }], # End roll-watcher patch #### + +#### +# Roll-watcher patch +[ALWAYS, { + 'intl402/Locale/prototype/getCollations/preferred-from-unicode-extension-true-empty': [SKIP], + 'intl402/Locale/prototype/getNumberingSystems/preferred-from-unicode-extension-true-empty': [SKIP], + 'intl402/Locale/prototype/getTextInfo/language-subtag-with-more-than-three-letters': [SKIP], + 'intl402/Locale/prototype/getTextInfo/script-metadata-rtl-is-unknown': [SKIP], + 'intl402/Locale/prototype/getTextInfo/script-metadata-unlisted-language-script-is-rtl': [SKIP], + 'intl402/Locale/prototype/getTextInfo/script-subtag-missing': [SKIP], + 'intl402/Locale/prototype/getTextInfo/script-unregistered-or-privateuse': [SKIP], +}], +# End roll-watcher patch +#### ] diff --git a/deps/v8/test/torque/test-torque.tq b/deps/v8/test/torque/test-torque.tq index 8d9572b91d58..2aba78f52924 100644 --- a/deps/v8/test/torque/test-torque.tq +++ b/deps/v8/test/torque/test-torque.tq @@ -1015,10 +1015,34 @@ macro TestBitFieldStore(val: TestBitFieldStruct): void { TestBitFieldLoad(val, !a, b, c, b == c); } +bitfield struct TestOverlappingBitFieldStruct extends uint32 { + low: uint32: 4 bit; + high: uint32: 4 bit; + all: uint32: 8 bit at 0; +} + @export macro TestBitFieldInit(a: bool, b: uint16, c: uint32, d: bool): void { const val: TestBitFieldStruct = TestBitFieldStruct{a: a, b: b, c: c, d: d}; TestBitFieldLoad(val, a, b, c, d); + TestBitFieldLoad( + TestBitFieldStruct{}, false, FromConstexpr<uint8>(0), 0, false); + TestBitFieldLoad(TestBitFieldStruct{d: d, b: b}, false, b, 0, d); + TestBitFieldLoad( + TestBitFieldStruct{c: c}, false, FromConstexpr<uint8>(0), c, false); + + const low = TestOverlappingBitFieldStruct{low: c}; + check(low.low == c); + check(low.high == 0); + check(low.all == c); + const high = TestOverlappingBitFieldStruct{high: c}; + check(high.low == 0); + check(high.high == c); + check(high.all == (c << 4)); + const all = TestOverlappingBitFieldStruct{all: c}; + check(all.low == c); + check(all.high == 0); + check(all.all == c); } // Some other bitfield structs, to verify getting uintptr values out of word32 diff --git a/deps/v8/test/unittests/BUILD.gn b/deps/v8/test/unittests/BUILD.gn index bf8dfc2ee23d..27ae1d5c174b 100644 --- a/deps/v8/test/unittests/BUILD.gn +++ b/deps/v8/test/unittests/BUILD.gn @@ -275,6 +275,7 @@ v8_cluster_source_set("v8_unittests_sources") { "../common/node-observer-tester.h", "../common/value-helper.cc", "../common/value-helper.h", + "../common/version-utils.h", "api/access-check-unittest.cc", "api/accessor-unittest.cc", "api/api-icu-unittest.cc", @@ -311,6 +312,7 @@ v8_cluster_source_set("v8_unittests_sources") { "base/fast-dtoa-unittest.cc", "base/fixed-dtoa-unittest.cc", "base/flags-unittest.cc", + "base/growing-circular-queue-unittest.cc", "base/hashing-unittest.cc", "base/hashmap-unittest.cc", "base/ieee754-unittest.cc", @@ -330,6 +332,7 @@ v8_cluster_source_set("v8_unittests_sources") { "base/sys-info-unittest.cc", "base/template-utils-unittest.cc", "base/threaded-list-unittest.cc", + "base/unique-array-unittest.cc", "base/utils/random-number-generator-unittest.cc", "base/vector-unittest.cc", "base/virtual-address-space-unittest.cc", @@ -370,8 +373,10 @@ v8_cluster_source_set("v8_unittests_sources") { "gay-shortest.cc", "gay-shortest.h", "heap/allocation-observer-unittest.cc", + "heap/array-buffer-sweeper-unittest.cc", "heap/code-range-unittest.cc", "heap/collection-barrier-unittest.cc", + "heap/concurrent-allocation-unittest.cc", "heap/conservative-stack-visitor-unittest.cc", "heap/cppgc-js/cpp-heap-stack-start-marker-unittest.cc", "heap/cppgc-js/embedder-roots-handler-unittest.cc", @@ -382,6 +387,7 @@ v8_cluster_source_set("v8_unittests_sources") { "heap/cppgc-js/unified-heap-utils.h", "heap/cppgc-js/young-unified-heap-unittest.cc", "heap/direct-handles-unittest.cc", + "heap/external-string-tracker-unittest.cc", "heap/gc-tracer-unittest.cc", "heap/global-handles-unittest.cc", "heap/global-safepoint-unittest.cc", @@ -397,9 +403,11 @@ v8_cluster_source_set("v8_unittests_sources") { "heap/local-factory-unittest.cc", "heap/local-handles-unittest.cc", "heap/local-heap-unittest.cc", + "heap/mark-compact-unittest.cc", "heap/marking-bitmap-unittest.cc", "heap/marking-progress-tracker-unittest.cc", "heap/marking-worklist-unittest.cc", + "heap/memory-measurement-unittest.cc", "heap/memory-reducer-unittest.cc", "heap/minimal-stack-unittest.cc", "heap/object-stats-unittest.cc", @@ -407,12 +415,12 @@ v8_cluster_source_set("v8_unittests_sources") { "heap/page-promotion-unittest.cc", "heap/pending-allocations-unittest.cc", "heap/persistent-handles-unittest.cc", - "heap/pool-unittest.cc", "heap/safepoint-unittest.cc", "heap/shared-heap-unittest.cc", "heap/slot-set-unittest.cc", "heap/spaces-unittest.cc", "heap/strong-root-allocator-unittest.cc", + "heap/weak-references-unittest.cc", "heap/write-barrier-unittest.cc", "interpreter/bytecode-array-builder-unittest.cc", "interpreter/bytecode-array-iterator-unittest.cc", @@ -439,7 +447,6 @@ v8_cluster_source_set("v8_unittests_sources") { "interpreter/source-position-matcher.cc", "interpreter/source-position-matcher.h", "interpreter/source-positions-unittest.cc", - "js-atomics/js-atomics-synchronization-primitive-unittest.cc", "libplatform/default-job-unittest.cc", "libplatform/default-platform-unittest.cc", "libplatform/default-worker-threads-task-runner-unittest.cc", @@ -463,6 +470,7 @@ v8_cluster_source_set("v8_unittests_sources") { "numbers/diy-fp-unittest.cc", "numbers/strtod-unittest.cc", "objects/array-list-unittest.cc", + "objects/casting-unittest.cc", "objects/concurrent-descriptor-array-unittest.cc", "objects/concurrent-feedback-vector-unittest.cc", "objects/concurrent-js-array-unittest.cc", @@ -515,6 +523,7 @@ v8_cluster_source_set("v8_unittests_sources") { "run-all-unittests.cc", "runtime/runtime-debug-unittest.cc", "sandbox/bytecode-verifier-unittest.cc", + "sandbox/code-cache-unittest.cc", "sandbox/generated-code-validator-unittest.cc", "sandbox/libcxx-hardening-unittest.cc", "sandbox/pointer-table-unittest.cc", @@ -548,7 +557,6 @@ v8_cluster_source_set("v8_unittests_sources") { "utils/utils-unittest.cc", "utils/version-unittest.cc", "zone/zone-allocator-unittest.cc", - "zone/zone-chunk-list-unittest.cc", "zone/zone-compact-set-unittest.cc", "zone/zone-unittest.cc", "zone/zone-vector-unittest.cc", @@ -569,7 +577,10 @@ v8_cluster_source_set("v8_unittests_sources") { "objects/concurrent-transition-array-unittest.cc", "wasm/float32-cross-compiler-determinism-fuzztest.cc", "wasm/module-decoder-unittest.cc", + "wasm/run-wasm-unittest.cc", + "wasm/streaming-compilation-unittest.cc", "wasm/streaming-decoder-unittest.cc", + "wasm/wasm-simd-utils.cc", "wasm/wasm-usecounters.cc", ] @@ -652,6 +663,7 @@ v8_cluster_source_set("v8_unittests_sources") { "compiler/state-values-utils-unittest.cc", "compiler/turboshaft/call-runtime-unittest.cc", "compiler/turboshaft/control-flow-unittest.cc", + "compiler/turboshaft/duplication-optimization-reducer-unittest.cc", "compiler/turboshaft/instruction-selection-normalization-reducer-unittest.cc", "compiler/turboshaft/late-load-elimination-reducer-unittest.cc", "compiler/turboshaft/load-store-address-hoisting-unittest.cc", @@ -685,26 +697,54 @@ v8_cluster_source_set("v8_unittests_sources") { "api/api-wasm-unittest.cc", "compiler/int64-lowering-unittest.cc", "compiler/turboshaft/wasm-simd-unittest.cc", - "compiler/wasm-address-reassociation-unittest.cc", "objects/wasm-backing-store-unittest.cc", + "wasm/backing-store-unittest.cc", "wasm/basic-block-calculator-unittest.cc", + "wasm/c-wasm-entry-unittest.cc", + "wasm/compilation-cache-unittest.cc", "wasm/compilation-hints-unittest.cc", "wasm/decoder-unittest.cc", "wasm/function-body-decoder-unittest.cc", + "wasm/fuzzer-steps-unittest.cc", + "wasm/gc-unittest.cc", + "wasm/grow-memory-unittest.cc", + "wasm/jump-table-assembler-unittest.cc", "wasm/leb-helper-unittest.cc", + "wasm/liftoff-for-fuzzing-unittest.cc", + "wasm/liftoff-inspection-unittest.cc", "wasm/liftoff-register-unittests.cc", "wasm/loop-assignment-analysis-unittest.cc", + "wasm/manually-externalized-buffer.h", "wasm/memory-protection-unittest.cc", "wasm/module-decoder-memory64-unittest.cc", "wasm/module-decoder-table64-unittest.cc", "wasm/module-decoder-unittest.cc", + "wasm/run-wasm-64-unittest.cc", + "wasm/run-wasm-atomics-unittest.cc", + "wasm/run-wasm-atomics64-unittest.cc", + "wasm/run-wasm-bulk-memory-unittest.cc", + "wasm/run-wasm-exceptions-unittest.cc", + "wasm/run-wasm-f16-unittest.cc", + "wasm/run-wasm-js-unittest.cc", + "wasm/run-wasm-memory64-unittest.cc", + "wasm/run-wasm-module-unittest.cc", + "wasm/run-wasm-relaxed-simd-unittest.cc", + "wasm/run-wasm-sign-extension-unittest.cc", + "wasm/run-wasm-simd-liftoff-unittest.cc", + "wasm/run-wasm-simd-unittest.cc", + "wasm/run-wasm-unittest.cc", + "wasm/run-wasm-wrappers-unittest.cc", "wasm/signature-hashing-unittest.cc", + "wasm/streaming-compilation-unittest.cc", "wasm/streaming-decoder-unittest.cc", "wasm/string-builder-unittest.cc", "wasm/struct-types-unittest.cc", "wasm/subtyping-unittest.cc", + "wasm/wasm-atomics-utils.h", + "wasm/wasm-breakpoints-unittest.cc", "wasm/wasm-code-manager-unittest.cc", "wasm/wasm-code-pointer-table-unittest.cc", + "wasm/wasm-codegen-unittest.cc", "wasm/wasm-compile-module.h", "wasm/wasm-compiler-unittest.cc", "wasm/wasm-disassembler-unittest-bad-name-section.wasm.inc", @@ -721,11 +761,21 @@ v8_cluster_source_set("v8_unittests_sources") { "wasm/wasm-disassembler-unittest-too-many-ends.wasm.inc", "wasm/wasm-disassembler-unittest-too-many-ends.wat.inc", "wasm/wasm-disassembler-unittest.cc", + "wasm/wasm-import-wrapper-cache-unittest.cc", "wasm/wasm-interpreter-thread-unittest.cc", "wasm/wasm-macro-gen-unittest.cc", + "wasm/wasm-metrics-unittest.cc", "wasm/wasm-module-builder-unittest.cc", "wasm/wasm-module-sourcemap-unittest.cc", + "wasm/wasm-runner.h", + "wasm/wasm-serialization-unittest.cc", + "wasm/wasm-shared-engine-unittest.cc", + "wasm/wasm-simd-utils.cc", + "wasm/wasm-simd-utils.h", + "wasm/wasm-stack-unittest.cc", + "wasm/wasm-strings-unittest.cc", "wasm/wasm-tracing-unittest.cc", + "wasm/wasm-trap-position-unittest.cc", "wasm/wasm-usecounters.cc", ] diff --git a/deps/v8/test/unittests/api/api-icu-unittest.cc b/deps/v8/test/unittests/api/api-icu-unittest.cc index 1b3dc39336de..368618ca1e61 100644 --- a/deps/v8/test/unittests/api/api-icu-unittest.cc +++ b/deps/v8/test/unittests/api/api-icu-unittest.cc @@ -31,6 +31,12 @@ class ApiIcuTest : public v8::TestWithContext { icu::Locale::setDefault(locale, error_code); CHECK(U_SUCCESS(error_code)); } + + void CheckLocaleCaseMapping(const char* locale_name, const char* expression) { + SetIcuLocale(locale_name); + isolate()->LocaleConfigurationChangeNotification(); + CHECK(RunJS(expression)->IsTrue()); + } }; TEST_F(ApiIcuTest, LocaleConfigurationChangeNotification) { @@ -53,4 +59,26 @@ TEST_F(ApiIcuTest, LocaleConfigurationChangeNotification) { CHECK(U_SUCCESS(error_code)); } +TEST_F(ApiIcuTest, LocaleConfigurationChangeNotificationCaseMapping) { + icu::Locale default_locale = icu::Locale::getDefault(); + + CheckLocaleCaseMapping("en_US", + "'i'.toLocaleUpperCase() === 'I' && " + "'I'.toLocaleLowerCase() === 'i'"); + CheckLocaleCaseMapping("tr_TR", + "'I'.toLocaleLowerCase() === '\\u0131' && " + "'i'.toLocaleUpperCase() === '\\u0130'"); + CheckLocaleCaseMapping("az_AZ", "'i'.toLocaleUpperCase() === '\\u0130'"); + CheckLocaleCaseMapping( + "el_GR", + "'\\u03ac\\u03cc\\u03cd\\u03ce'.toLocaleUpperCase() === " + "'\\u0391\\u039f\\u03ab\\u03a9'"); + CheckLocaleCaseMapping("lt_LT", "'i\\u0307'.toLocaleUpperCase() === 'I'"); + CheckLocaleCaseMapping("en_US", "'i'.toLocaleUpperCase() === 'I'"); + + UErrorCode error_code = U_ZERO_ERROR; + icu::Locale::setDefault(default_locale, error_code); + CHECK(U_SUCCESS(error_code)); +} + #endif // V8_INTL_SUPPORT diff --git a/deps/v8/test/unittests/api/api-wasm-unittest.cc b/deps/v8/test/unittests/api/api-wasm-unittest.cc index 03d251448256..664017d992b3 100644 --- a/deps/v8/test/unittests/api/api-wasm-unittest.cc +++ b/deps/v8/test/unittests/api/api-wasm-unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> #include <memory> #include <thread> // NOLINT(build/c++11) @@ -293,22 +294,83 @@ TEST_F(ApiWasmTest, WasmCompileWithSourceUrl) { Local<Context> context = Context::New(isolate()); Context::Scope context_scope(context); - constexpr std::string_view kUrl = "file:///test/module.wasm"; - Local<WasmModuleObject> with_url = + constexpr std::string_view kUrl1 = "file:///test/module1.wasm"; + Local<WasmModuleObject> with_url1 = WasmModuleObject::Compile(isolate(), kMinimalWasmModuleBytes, - {.source_url = kUrl}) + {.source_url = kUrl1}) .ToLocalChecked(); - CHECK_EQ(kUrl, with_url->GetCompiledModule().source_url()); + CHECK_EQ(kUrl1, with_url1->GetCompiledModule().source_url()); - // A distinct module, since scripts (and their URLs) are cached per module - // per isolate. Without a source URL a wasm:// URL is synthesized. - const uint8_t distinct_module[] = {0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x01, 'x'}; + // Compiling the same module bytes with a different source URL creates a + // separate script with its own URL rather than reusing the previous URL. + constexpr std::string_view kUrl2 = "file:///test/module2.wasm"; + Local<WasmModuleObject> with_url2 = + WasmModuleObject::Compile(isolate(), kMinimalWasmModuleBytes, + {.source_url = kUrl2}) + .ToLocalChecked(); + CHECK_EQ(kUrl2, with_url2->GetCompiledModule().source_url()); + + // Without a source URL, a wasm:// URL is synthesized even when a script with + // an explicit URL already exists for the same module bytes. Local<WasmModuleObject> plain = - WasmModuleObject::Compile(isolate(), distinct_module).ToLocalChecked(); + WasmModuleObject::Compile(isolate(), kMinimalWasmModuleBytes) + .ToLocalChecked(); CHECK_EQ(0u, plain->GetCompiledModule().source_url().find("wasm://wasm/")); } +// Regression test for https://crbug.com/564190098. +TEST_F(ApiWasmTest, WasmCompileSourceUrlNotLeakedAcrossTrapStacks) { + Isolate::Scope iscope(isolate()); + HandleScope scope(isolate()); + + // Minimal Wasm module exporting `boom()` which traps with `unreachable`. + const uint8_t kTrappingModuleBytes[] = { + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, + 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x07, 0x08, 0x01, 0x04, 0x62, 0x6f, + 0x6f, 0x6d, 0x00, 0x00, 0x0a, 0x05, 0x01, 0x03, 0x00, 0x00, 0x0b}; + + constexpr std::string_view kVictimUrl = + "https://victim.example/module.wasm?secret=VICTIM_SECRET"; + constexpr std::string_view kAttackerUrl = + "https://attacker.example/module.wasm"; + + Local<Context> victim_context = Context::New(isolate()); + Local<WasmModuleObject> victim_module; + { + Context::Scope victim_scope(victim_context); + victim_module = WasmModuleObject::Compile(isolate(), kTrappingModuleBytes, + {.source_url = kVictimUrl}) + .ToLocalChecked(); + CHECK_EQ(kVictimUrl, victim_module->GetCompiledModule().source_url()); + } + + Local<Context> attacker_context = Context::New(isolate()); + { + Context::Scope attacker_scope(attacker_context); + Local<WasmModuleObject> attacker_module = + WasmModuleObject::Compile(isolate(), kTrappingModuleBytes, + {.source_url = kAttackerUrl}) + .ToLocalChecked(); + CHECK_EQ(kAttackerUrl, attacker_module->GetCompiledModule().source_url()); + + CHECK(attacker_context->Global() + ->Set(attacker_context, + String::NewFromUtf8Literal(isolate(), "mod"), + attacker_module) + .FromJust()); + Local<Value> stack_val = RunJS( + "try {\n" + " new WebAssembly.Instance(mod).exports.boom();\n" + "} catch (e) {\n" + " e.stack;\n" + "}"); + String::Utf8Value stack_utf8(isolate(), stack_val); + std::string_view stack(*stack_utf8, stack_utf8.length()); + CHECK_NE(std::string_view::npos, stack.find(kAttackerUrl)); + CHECK_EQ(std::string_view::npos, stack.find("VICTIM_SECRET")); + } +} + TEST_F(ApiWasmTest, WasmStreamingSetCallback) { TestWasmStreaming(WasmStreamingMoreFunctionsCanBeSerializedCallback, Promise::kPending); @@ -495,14 +557,11 @@ TEST_F(ApiWasmTest, WasmModuleCompilation_SourceUrl) { CHECK_EQ(kSetUrl, module->GetCompiledModule().source_url()); } - // Without a URL, a wasm:// URL is synthesized. A distinct module, since - // scripts (and their URLs) are cached per module per isolate. + // Without a URL, a wasm:// URL is synthesized even for the same module bytes. { - const uint8_t distinct_module[] = {0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x01, 'y'}; WasmModuleCompilation compilation; Local<WasmModuleObject> module = - FinishModuleCompilation(compilation, distinct_module); + FinishModuleCompilation(compilation, kMinimalWasmModuleBytes); CHECK_EQ(0u, module->GetCompiledModule().source_url().find("wasm://wasm/")); } CHECK(!try_catch.HasCaught()); @@ -616,4 +675,71 @@ TEST_F(ApiWasmTest, WasmModuleCompilation_MultiThreaded) { for (auto& t : threads) t.join(); } +TEST_F(ApiWasmTest, WasmMemoryObjectGetBuffer) { + HandleScope scope(isolate()); + Local<Context> context = Context::New(isolate()); + Context::Scope context_scope(context); + + Local<WasmMemoryObject> unshared_memory = + RunJS("new WebAssembly.Memory({initial: 1})").As<WasmMemoryObject>(); + Local<ArrayBufferBase> unshared_buffer = unshared_memory->GetBuffer(); + EXPECT_TRUE(unshared_buffer->IsArrayBufferBase()); + EXPECT_TRUE(unshared_buffer->IsArrayBuffer()); + EXPECT_FALSE(unshared_buffer->IsSharedArrayBuffer()); + EXPECT_FALSE(unshared_buffer->IsShared()); + + Local<WasmMemoryObject> shared_memory = + RunJS("new WebAssembly.Memory({initial: 1, maximum: 1, shared: true})") + .As<WasmMemoryObject>(); + Local<ArrayBufferBase> shared_buffer = shared_memory->GetBuffer(); + EXPECT_TRUE(shared_buffer->IsArrayBufferBase()); + EXPECT_FALSE(shared_buffer->IsArrayBuffer()); + EXPECT_TRUE(shared_buffer->IsSharedArrayBuffer()); + EXPECT_TRUE(shared_buffer->IsShared()); + + START_ALLOW_USE_DEPRECATED(); + EXPECT_TRUE(unshared_memory->Buffer()->IsArrayBuffer()); + EXPECT_TRUE(shared_memory->Buffer()->IsSharedArrayBuffer()); + END_ALLOW_USE_DEPRECATED(); +} + +TEST_F(ApiWasmTest, OwnedBufferSpanAndMoveSemantics) { + OwnedBuffer empty_buffer; + EXPECT_TRUE(empty_buffer.empty()); + EXPECT_TRUE(empty_buffer.as_span().empty()); + EXPECT_EQ(nullptr, empty_buffer.as_span().data()); + + constexpr uint8_t kPayload[] = {10, 20, 30, 40}; + std::unique_ptr<uint8_t[]> backing = + std::make_unique<uint8_t[]>(sizeof(kPayload)); + std::copy(std::begin(kPayload), std::end(kPayload), backing.get()); + const uint8_t* raw_ptr = backing.get(); + + START_ALLOW_USE_DEPRECATED() + OwnedBuffer owned(std::move(backing), sizeof(kPayload)); + END_ALLOW_USE_DEPRECATED() + + EXPECT_FALSE(owned.empty()); + EXPECT_EQ(raw_ptr, owned.as_span().data()); + EXPECT_EQ(sizeof(kPayload), owned.as_span().size()); + EXPECT_TRUE(std::ranges::equal(kPayload, owned.as_span())); + + // Move construction transfers ownership and leaves the source empty. + OwnedBuffer move_constructed(std::move(owned)); + EXPECT_TRUE(owned.empty()); + EXPECT_TRUE(owned.as_span().empty()); + EXPECT_EQ(nullptr, owned.as_span().data()); + EXPECT_EQ(raw_ptr, move_constructed.as_span().data()); + EXPECT_EQ(sizeof(kPayload), move_constructed.as_span().size()); + + // Move assignment also leaves the source empty. + OwnedBuffer move_assigned; + move_assigned = std::move(move_constructed); + EXPECT_TRUE(move_constructed.empty()); + EXPECT_TRUE(move_constructed.as_span().empty()); + EXPECT_EQ(nullptr, move_constructed.as_span().data()); + EXPECT_EQ(raw_ptr, move_assigned.as_span().data()); + EXPECT_EQ(sizeof(kPayload), move_assigned.as_span().size()); +} + } // namespace v8 diff --git a/deps/v8/test/unittests/api/deserialize-unittest.cc b/deps/v8/test/unittests/api/deserialize-unittest.cc index fb9fb9983b7d..4eee48ebb3b3 100644 --- a/deps/v8/test/unittests/api/deserialize-unittest.cc +++ b/deps/v8/test/unittests/api/deserialize-unittest.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <format> +#include <string_view> + #include "include/v8-context.h" #include "include/v8-function.h" #include "include/v8-isolate.h" @@ -9,8 +12,11 @@ #include "include/v8-platform.h" #include "include/v8-primitive.h" #include "include/v8-script.h" +#include "src/api/api-inl.h" #include "src/codegen/compilation-cache.h" #include "src/common/synchronization-point-support.h" +#include "src/objects/script-inl.h" +#include "src/objects/string-inl.h" #include "test/unittests/heap/heap-utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -198,6 +204,210 @@ TEST_F(DeserializeTest, OffThreadDeserialize) { } } +namespace { + +std::string LongMagicCommentValue() { + return std::format("data:application/json;base64,{:A>2000}", ""); +} + +std::string SourceWithLongMagicComments( + std::string_view body = "function foo() { return 42; }") { + return std::format( + "{0}\n//# sourceURL={1}\n//# sourceMappingURL={1}\n//# debugId={1}\n", + body, LongMagicCommentValue()); +} + +// Compiled scripts have the source map URL magic comment value as a slice of +// the source (the source URL and debug ID are sequential copies). The code +// cache contains it as a sequential string, since the slice could not be +// deserialized off-thread, where the source is not available. +void CheckLongMagicCommentValues(Isolate* isolate, Local<Script> script, + bool expect_slices) { + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::DirectHandle<i::Script> i_script( + i::Cast<i::Script>( + Utils::OpenDirectHandle(*script->GetUnboundScript())->script()), + i_isolate); + std::string value = LongMagicCommentValue(); + // The source URL and debug ID are always sequential strings. + i::Tagged<i::Object> copied_fields[] = {i_script->source_url(), + i_script->debug_id()}; + for (i::Tagged<i::Object> field : copied_fields) { + CHECK(i::IsSeqString(field)); + CHECK(i::Cast<i::String>(field)->IsEqualTo( + base::OneByteVector(value.data(), value.size()))); + } + i::Tagged<i::Object> source_mapping_url = i_script->source_mapping_url(); + CHECK_EQ(expect_slices, i::IsSlicedString(source_mapping_url)); + if (expect_slices) { + CHECK_EQ(i::Cast<i::SlicedString>(source_mapping_url)->parent(), + i_script->source()); + } + CHECK(i::Cast<i::String>(source_mapping_url) + ->IsEqualTo(base::OneByteVector(value.data(), value.size()))); +} + +} // namespace + +TEST_F(DeserializeTest, DeserializeLongMagicComments) { + std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data; + std::string source_text = SourceWithLongMagicComments(); + + { + IsolateAndContextScope scope(this); + Local<Script> script = + Script::Compile(context(), NewString(source_text.c_str())) + .ToLocalChecked(); + CheckLongMagicCommentValues(isolate(), script, true); + cached_data.reset( + ScriptCompiler::CreateCodeCache(script->GetUnboundScript())); + } + + { + IsolateAndContextScope scope(this); + ScriptCompiler::Source source(NewString(source_text.c_str()), + cached_data.release()); + Local<Script> script = + ScriptCompiler::Compile(context(), &source, + ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!source.GetCachedData()->rejected); + CheckLongMagicCommentValues(isolate(), script, false); + CHECK(!script->Run(context()).IsEmpty()); + CHECK_EQ(RunGlobalFunc("foo"), Integer::New(isolate(), 42)); + } +} + +TEST_F(DeserializeTest, OffThreadDeserializeLongMagicComments) { + std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data; + std::string source_text = SourceWithLongMagicComments(); + + { + IsolateAndContextScope scope(this); + Local<Script> script = + Script::Compile(context(), NewString(source_text.c_str())) + .ToLocalChecked(); + CheckLongMagicCommentValues(isolate(), script, true); + cached_data.reset( + ScriptCompiler::CreateCodeCache(script->GetUnboundScript())); + } + + { + IsolateAndContextScope scope(this); + DeserializeThread deserialize_thread( + ScriptCompiler::StartConsumingCodeCache( + isolate(), std::make_unique<ScriptCompiler::CachedData>( + cached_data->data, cached_data->length, + ScriptCompiler::CachedData::BufferNotOwned))); + CHECK(deserialize_thread.Start()); + deserialize_thread.Join(); + + ScriptCompiler::Source source(NewString(source_text.c_str()), + cached_data.release(), + deserialize_thread.TakeTask().release()); + Local<Script> script = + ScriptCompiler::Compile(context(), &source, + ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!source.GetCachedData()->rejected); + CheckLongMagicCommentValues(isolate(), script, false); + CHECK(!script->Run(context()).IsEmpty()); + CHECK_EQ(RunGlobalFunc("foo"), Integer::New(isolate(), 42)); + } +} + +TEST_F(DeserializeTest, DeserializeLongMagicCommentsFromTwoByteSource) { + // The source is two-byte, but the magic comment values are one-byte. The + // values are two-byte slices of the source, but should be cached (and + // deserialized) as one-byte strings. + std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data; + std::string source_text = SourceWithLongMagicComments( + "var s = '\xD7\x90';\nfunction foo() { return 42; }"); + + { + IsolateAndContextScope scope(this); + Local<Script> script = + Script::Compile(context(), NewString(source_text.c_str())) + .ToLocalChecked(); + CheckLongMagicCommentValues(isolate(), script, true); + i::DirectHandle<i::Script> i_script( + i::Cast<i::Script>( + Utils::OpenDirectHandle(*script->GetUnboundScript())->script()), + reinterpret_cast<i::Isolate*>(isolate())); + CHECK(i::Cast<i::String>(i_script->source())->IsTwoByteRepresentation()); + cached_data.reset( + ScriptCompiler::CreateCodeCache(script->GetUnboundScript())); + } + + for (bool off_thread : {false, true}) { + IsolateAndContextScope scope(this); + auto data = std::make_unique<ScriptCompiler::CachedData>( + cached_data->data, cached_data->length, + ScriptCompiler::CachedData::BufferNotOwned); + std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> task; + if (off_thread) { + DeserializeThread deserialize_thread( + ScriptCompiler::StartConsumingCodeCache( + isolate(), std::make_unique<ScriptCompiler::CachedData>( + cached_data->data, cached_data->length, + ScriptCompiler::CachedData::BufferNotOwned))); + CHECK(deserialize_thread.Start()); + deserialize_thread.Join(); + task = deserialize_thread.TakeTask(); + } + ScriptCompiler::Source source(NewString(source_text.c_str()), + data.release(), task.release()); + Local<Script> script = + ScriptCompiler::Compile(context(), &source, + ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + CHECK(!source.GetCachedData()->rejected); + CheckLongMagicCommentValues(isolate(), script, false); + i::DirectHandle<i::Script> i_script( + i::Cast<i::Script>( + Utils::OpenDirectHandle(*script->GetUnboundScript())->script()), + reinterpret_cast<i::Isolate*>(isolate())); + i::Tagged<i::Object> fields[] = {i_script->source_url(), + i_script->source_mapping_url(), + i_script->debug_id()}; + for (i::Tagged<i::Object> field : fields) { + CHECK(i::IsSeqOneByteString(field)); + } + } +} + +TEST_F(DeserializeTest, DeserializeKeepsApiSourceMapURL) { + std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data; + std::string source_text = SourceWithLongMagicComments(); + auto compile = [&](ScriptCompiler::CachedData* data) { + ScriptOrigin origin(NewString("origin.js"), 0, 0, false, -1, + NewString("api.js.map")); + ScriptCompiler::Source source(NewString(source_text.c_str()), origin, data); + Local<Script> script = + ScriptCompiler::Compile(context(), &source, + data ? ScriptCompiler::kConsumeCodeCache + : ScriptCompiler::kNoCompileOptions) + .ToLocalChecked(); + CHECK(!data || !source.GetCachedData()->rejected); + String::Utf8Value url(isolate(), + script->GetUnboundScript()->GetSourceMappingURL()); + CHECK_EQ(0, strcmp("api.js.map", *url)); + return script; + }; + + { + IsolateAndContextScope scope(this); + Local<Script> script = compile(nullptr); + cached_data.reset( + ScriptCompiler::CreateCodeCache(script->GetUnboundScript())); + } + + { + IsolateAndContextScope scope(this); + compile(cached_data.release()); + } +} + // Check that off-thread deserialization works. TEST_F(DeserializeTest, OffThreadDeserializeRejectsDifferentSource) { std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data; diff --git a/deps/v8/test/unittests/api/dictionary-template-unittest.cc b/deps/v8/test/unittests/api/dictionary-template-unittest.cc index b264a591911b..d663bfe2667a 100644 --- a/deps/v8/test/unittests/api/dictionary-template-unittest.cc +++ b/deps/v8/test/unittests/api/dictionary-template-unittest.cc @@ -154,13 +154,11 @@ TEST_F(DictionaryTemplateTest, HoleNanCanonicalization) { Local<Object> instance2 = tpl->NewInstance(context(), values2); EXPECT_FALSE(instance2.IsEmpty()); - // The stored HeapNumber value must not have the hole-NaN bit pattern. auto value2 = instance2->Get(context(), v8_str(isolate(), "a")).ToLocalChecked(); EXPECT_TRUE(value2->IsNumber()); double val2 = value2.As<v8::Number>()->Value(); EXPECT_TRUE(std::isnan(val2)); - EXPECT_NE(base::bit_cast<uint64_t>(val2), i::kHoleNanInt64); // The property must be mutable and not in Read-Only space. EXPECT_TRUE(instance2 diff --git a/deps/v8/test/unittests/api/interceptor-unittest.cc b/deps/v8/test/unittests/api/interceptor-unittest.cc index d0ae70df06c7..ca2fcfecc289 100644 --- a/deps/v8/test/unittests/api/interceptor-unittest.cc +++ b/deps/v8/test/unittests/api/interceptor-unittest.cc @@ -348,6 +348,7 @@ TEST_F(InterceptorTest, IndexedInterceptorIterableToList_ValidityCellBypass) { i::DirectHandle<i::JSObject> i_prototype = i::Cast<i::JSObject>(v8::Utils::OpenDirectHandle(*prototype)); ASSERT_TRUE(i_prototype->map()->is_dictionary_map()); + ASSERT_FALSE(i_prototype->map()->should_be_fast_prototype_map()); // 2. Make Symbol.iterator mutable but keep the value unchanged. RunJS(R"( @@ -361,6 +362,9 @@ TEST_F(InterceptorTest, IndexedInterceptorIterableToList_ValidityCellBypass) { // perform the necessary checks. RunJS("Array.from(obj);"); ASSERT_EQ(data.call_count, 1); + ASSERT_TRUE(i_prototype->map()->should_be_fast_prototype_map()); + ASSERT_EQ(!V8_DICT_PROPERTY_CONST_TRACKING_BOOL, + i_prototype->HasFastProperties()); // 4. Modify Symbol.iterator again, the fast path shouldn't be taken. RunJS("proto[Symbol.iterator] = function*() { yield 42; };"); @@ -379,6 +383,34 @@ TEST_F(InterceptorTest, IndexedInterceptorIterableToList_ValidityCellBypass) { ASSERT_EQ(42, arr->Get(context(), 0).ToLocalChecked().As<Integer>()->Value()); } +TEST_F(InterceptorTest, + IndexedInterceptorIterableToList_PrototypeBecomesFastOnPropertyAccess) { + i::FlagScope<bool> enable_flag(&i::v8_flags.fast_api_iterable_to_list, true); + v8::HandleScope scope(isolate()); + InterceptorData data; + + Local<FunctionTemplate> tmpl = + CreateIterableToListInterceptorTemplate(isolate(), &data); + Local<Function> ctor = tmpl->GetFunction(context()).ToLocalChecked(); + Local<Object> obj = ctor->NewInstance(context()).ToLocalChecked(); + SetGlobalProperty("obj", obj); + + Local<Object> prototype = obj->GetPrototype().As<Object>(); + i::DirectHandle<i::JSObject> i_prototype = + i::Cast<i::JSObject>(v8::Utils::OpenDirectHandle(*prototype)); + ASSERT_TRUE(i_prototype->map()->is_dictionary_map()); + ASSERT_FALSE(i_prototype->map()->should_be_fast_prototype_map()); + + // Accessing a property on the prototype via LoadIC (without calling + // Array.from or spread) must transition the prototype out of setup mode. + Local<Value> res = RunJS("obj.length"); + ASSERT_EQ(3, res.As<Integer>()->Value()); + ASSERT_EQ(0, data.call_count); + ASSERT_TRUE(i_prototype->map()->should_be_fast_prototype_map()); + ASSERT_EQ(!V8_DICT_PROPERTY_CONST_TRACKING_BOOL, + i_prototype->HasFastProperties()); +} + TEST_F(InterceptorTest, IndexedInterceptorIterableToList_SetPrototypeBypass) { i::FlagScope<bool> enable_flag(&i::v8_flags.fast_api_iterable_to_list, true); v8::HandleScope scope(isolate()); @@ -431,6 +463,38 @@ TEST_F(InterceptorTest, IndexedInterceptorIterableToList_SetPrototypeBypass) { ASSERT_TRUE(is_error->IsTrue()); } +TEST_F(InterceptorTest, + IndexedInterceptorIterableToList_ArrayIteratorProtector) { + i::FlagScope<bool> enable_flag(&i::v8_flags.fast_api_iterable_to_list, true); + v8::HandleScope scope(isolate()); + InterceptorData data; + + Local<FunctionTemplate> tmpl = + CreateIterableToListInterceptorTemplate(isolate(), &data); + Local<Function> ctor = tmpl->GetFunction(context()).ToLocalChecked(); + Local<Object> obj = ctor->NewInstance(context()).ToLocalChecked(); + SetGlobalProperty("obj", obj); + + // Invalidate the ArrayIterator protector. + RunJS( + "Object.getPrototypeOf([][Symbol.iterator]()).next = function(){return " + "{done:true}};"); + + int initial_count = data.call_count; + + Local<Value> res_from = RunJS("Array.from(obj)"); + ASSERT_TRUE(res_from->IsArray()); + Local<Array> arr_from = res_from.As<Array>(); + ASSERT_EQ(0u, arr_from->Length()); + + Local<Value> res_spread = RunJS("((...a)=>a)(...obj)"); + ASSERT_TRUE(res_spread->IsArray()); + Local<Array> arr_spread = res_spread.As<Array>(); + ASSERT_EQ(0u, arr_spread->Length()); + + ASSERT_EQ(initial_count, data.call_count); +} + // namespace internal { namespace { diff --git a/deps/v8/test/unittests/api/v8-array-buffer-unittest.cc b/deps/v8/test/unittests/api/v8-array-buffer-unittest.cc index 0eb69a291293..3cc0da15eda1 100644 --- a/deps/v8/test/unittests/api/v8-array-buffer-unittest.cc +++ b/deps/v8/test/unittests/api/v8-array-buffer-unittest.cc @@ -6,9 +6,12 @@ #include <algorithm> #include <cstdint> +#include <limits> #include <memory> #include <span> +#include "src/objects/backing-store.h" +#include "src/utils/allocation.h" #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -60,5 +63,16 @@ TEST_F(ArrayBufferTest, BackingStoreByteSpan) { } } +TEST_F(ArrayBufferTest, TryAllocateAndPartiallyCommitMemoryNullIsolate) { + size_t page_size = i::AllocatePageSize(); + size_t max_pages = std::numeric_limits<size_t>::max() / page_size; + size_t max_byte_length = max_pages * page_size; + std::unique_ptr<i::BackingStore> backing_store = + i::BackingStore::TryAllocateAndPartiallyCommitMemory( + nullptr, 0, max_byte_length, page_size, 0, max_pages, + i::WasmMemoryFlag::kNotWasm, i::SharedFlag{false}); + EXPECT_EQ(backing_store, nullptr); +} + } // namespace } // namespace v8 diff --git a/deps/v8/test/unittests/api/v8-object-unittest.cc b/deps/v8/test/unittests/api/v8-object-unittest.cc index 5b84a238b0d3..b31600706ca5 100644 --- a/deps/v8/test/unittests/api/v8-object-unittest.cc +++ b/deps/v8/test/unittests/api/v8-object-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "include/v8-context.h" +#include "include/v8-exception.h" #include "include/v8-function.h" #include "include/v8-isolate.h" #include "include/v8-local-handle.h" @@ -217,5 +218,401 @@ TEST_F(LapContextTest, CurrentContextInLazyAccessorOnInterface) { EXPECT_EQ(8, call_count); } +class TryGetWithNoSideEffectsTest : public TestWithContext { + protected: + // Calls TryGetWithNoSideEffects(), which must neither run script nor throw. + MaybeLocal<Value> TryGet(Local<Object> object, Local<Name> key, + Local<Context> context) { + TryCatch try_catch(isolate()); + Isolate::DisallowJavascriptExecutionScope no_script( + isolate(), Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE); + MaybeLocal<Value> result = object->TryGetWithNoSideEffects(context, key); + EXPECT_FALSE(try_catch.HasCaught()); + return result; + } + + MaybeLocal<Value> TryGet(Local<Object> object, const char* key) { + return TryGet(object, NewString(key), context()); + } + + // Expects TryGetWithNoSideEffects() to return the value of the JavaScript + // expression `expected`. + void ExpectValue(Local<Object> object, const char* key, + const char* expected) { + Local<Value> value; + ASSERT_TRUE(TryGet(object, key).ToLocal(&value)) << key; + EXPECT_TRUE(value->StrictEquals(RunJS(expected))) << key; + } + + void ExpectEmpty(Local<Object> object, const char* key) { + EXPECT_TRUE(TryGet(object, key).IsEmpty()) << key; + } + + Local<Object> RunJSObject(const char* source) { + return RunJS(source).As<Object>(); + } + + int32_t RunJSInt32(const char* source) { + return RunJS(source)->Int32Value(context()).FromJust(); + } +}; + +TEST_F(TryGetWithNoSideEffectsTest, DataProperties) { + Local<Object> object = RunJSObject(R"( + var proto = {inherited: 'inherited', shadowed: 'proto'}; + var object = Object.create(proto); + object.own = 'own'; + object.shadowed = 'own'; + object.undefined_value = undefined; + object[0] = 'element'; + object[Symbol.for('symbol')] = 'symbol'; + Object.defineProperty(object, 'non_configurable', {value: 'nc'}); + object; + )"); + ExpectValue(object, "own", "'own'"); + ExpectValue(object, "inherited", "'inherited'"); + ExpectValue(object, "shadowed", "'own'"); + ExpectValue(object, "undefined_value", "undefined"); + ExpectValue(object, "0", "'element'"); + ExpectValue(object, "non_configurable", "'nc'"); + ExpectValue(object, "toString", "Object.prototype.toString"); + Local<Value> value; + ASSERT_TRUE( + TryGet(object, Symbol::For(isolate(), NewString("symbol")), context()) + .ToLocal(&value)); + EXPECT_TRUE(value->StrictEquals(NewString("symbol"))); + + ExpectValue(RunJSObject("Object.freeze({frozen: 'frozen'})"), "frozen", + "'frozen'"); + ExpectValue(RunJSObject("[1, 2]"), "1", "2"); + ExpectValue(RunJSObject("new Uint8Array([1, 2])"), "1", "2"); +} + +TEST_F(TryGetWithNoSideEffectsTest, GlobalObject) { + RunJS("var global_var = 'var'; globalThis.global_property = 'property';"); + Local<Object> global = context()->Global(); + ExpectValue(global, "global_var", "'var'"); + ExpectValue(global, "global_property", "'property'"); + ExpectValue(global, "Object", "Object"); + ExpectEmpty(global, "missing"); +} + +TEST_F(TryGetWithNoSideEffectsTest, MissingProperties) { + ExpectEmpty(RunJSObject("({})"), "missing"); + ExpectEmpty(RunJSObject("[]"), "0"); + ExpectEmpty(RunJSObject("Object.create(null)"), "toString"); + // Out-of-bounds typed array elements are not looked up on the prototype + // chain. + ExpectEmpty(RunJSObject("Uint8Array.prototype[2] = 'proto';" + "new Uint8Array(2)"), + "2"); +} + +TEST_F(TryGetWithNoSideEffectsTest, AccessorsAreNotCalled) { + Local<Object> object = RunJSObject(R"( + var calls = 0; + function getter() { calls++; return 'getter'; } + function setter(value) { calls++; } + var proto = Object.defineProperty({}, 'inherited', {get: getter}); + var object = Object.create(proto); + Object.defineProperty(object, 'own', {get: getter, configurable: true}); + Object.defineProperty(object, 'non_configurable', {get: getter}); + Object.defineProperty(object, 'setter_only', {set: setter}); + object; + )"); + ExpectEmpty(object, "own"); + ExpectEmpty(object, "inherited"); + ExpectEmpty(object, "non_configurable"); + ExpectEmpty(object, "setter_only"); + + // Data properties shadowing accessors can be read. + Local<Object> shadowing = RunJSObject( + "Object.defineProperty(Object.create(object), 'own', {value: 'data'})"); + ExpectValue(shadowing, "own", "'data'"); + ExpectEmpty(shadowing, "inherited"); + EXPECT_EQ(0, RunJSInt32("calls")); +} + +// Getters are never called, not even native functions declared side-effect +// free, as script can install any function as a getter on any object. +TEST_F(TryGetWithNoSideEffectsTest, NativeGettersAreNotCalled) { + static int calls; + calls = 0; + Local<FunctionTemplate> getter = FunctionTemplate::New( + isolate(), + [](const FunctionCallbackInfo<Value>& info) { + ++calls; + info.GetReturnValue().Set(42); + }, + Local<Value>(), Local<Signature>(), 0, ConstructorBehavior::kThrow, + SideEffectType::kHasNoSideEffect); + Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate()); + object_template->SetAccessorProperty(NewString("getter"), getter); + Local<Object> object = + object_template->NewInstance(context()).ToLocalChecked(); + SetGlobalProperty("object", object); + ExpectEmpty(object, "getter"); + + Local<Object> array = RunJSObject(R"( + var array = [1, 2, 3]; + Object.defineProperty(array, 'getter', + Object.getOwnPropertyDescriptor(object, 'getter')); + Object.defineProperty(array, 'pop', {get: Array.prototype.pop}); + array; + )"); + ExpectEmpty(array, "getter"); + ExpectEmpty(array, "pop"); + EXPECT_EQ(0, calls); + ExpectValue(array, "length", "3"); + + // Unlike TryGetWithNoSideEffects(), Get() calls the getter. + EXPECT_FALSE(object->Get(context(), NewString("getter")).IsEmpty()); + EXPECT_EQ(1, calls); +} + +// Properties like these are implemented as side-effect free native data +// properties, which behave like data properties. +TEST_F(TryGetWithNoSideEffectsTest, BuiltinNativeDataProperties) { + Local<Object> function = RunJSObject("function f(a, b) {}; f"); + ExpectValue(function, "prototype", "f.prototype"); + ExpectValue(function, "name", "'f'"); + ExpectValue(function, "length", "2"); + ExpectValue(RunJSObject("[1, 2, 3]"), "length", "3"); + ExpectValue(RunJSObject("new String('abc')"), "length", "3"); +} + +TEST_F(TryGetWithNoSideEffectsTest, EmbedderNativeDataProperties) { + static int calls; + calls = 0; + AccessorNameGetterCallback getter = + [](Local<Name>, const PropertyCallbackInfo<Value>& info) { + ++calls; + info.GetReturnValue().Set(42); + }; + Local<Object> object = Object::New(isolate()); + ASSERT_TRUE( + object->SetNativeDataProperty(context(), NewString("native"), getter) + .FromJust()); + ASSERT_TRUE(object->SetLazyDataProperty(context(), NewString("lazy"), getter) + .FromJust()); + ASSERT_TRUE(object + ->SetNativeDataProperty(context(), + NewString("side_effect_free_native"), + getter, nullptr, Local<Value>(), None, + SideEffectType::kHasNoSideEffect) + .FromJust()); + ASSERT_TRUE(object + ->SetLazyDataProperty( + context(), NewString("side_effect_free_lazy"), getter, + Local<Value>(), None, SideEffectType::kHasNoSideEffect) + .FromJust()); + SetGlobalProperty("object", object); + + // Getters that may have side effects are not called. + ExpectEmpty(object, "native"); + ExpectEmpty(object, "lazy"); + EXPECT_EQ(0, calls); + + ExpectValue(object, "side_effect_free_native", "42"); + EXPECT_EQ(1, calls); + ExpectValue(RunJSObject("Object.create(object)"), "side_effect_free_native", + "42"); + EXPECT_EQ(2, calls); + ExpectValue(object, "side_effect_free_lazy", "42"); + EXPECT_EQ(3, calls); + // The lazy data property has been replaced by a data property. + ExpectValue(object, "side_effect_free_lazy", "42"); + EXPECT_EQ(3, calls); +} + +TEST_F(TryGetWithNoSideEffectsTest, ThrowingNativeDataProperty) { + AccessorNameGetterCallback getter = + [](Local<Name>, const PropertyCallbackInfo<Value>& info) { + info.GetIsolate()->ThrowError("error"); + }; + Local<Object> object = Object::New(isolate()); + ASSERT_TRUE(object + ->SetNativeDataProperty(context(), NewString("throws"), + getter, nullptr, Local<Value>(), None, + SideEffectType::kHasNoSideEffect) + .FromJust()); + // The exception doesn't escape, which TryGet() checks. + ExpectEmpty(object, "throws"); +} + +// Embedders may install interface objects (e.g. `Node` in Blink) as lazy data +// properties on the global object. Their `prototype` holds the methods. +TEST_F(TryGetWithNoSideEffectsTest, InterfaceObjectOnGlobalObject) { + static int calls; + calls = 0; + AccessorNameGetterCallback getter = + [](Local<Name>, const PropertyCallbackInfo<Value>& info) { + ++calls; + Isolate* isolate = info.GetIsolate(); + Local<FunctionTemplate> interface_template = + FunctionTemplate::New(isolate); + interface_template->ReadOnlyPrototype(); + interface_template->PrototypeTemplate()->Set( + isolate, "method", FunctionTemplate::New(isolate)); + info.GetReturnValue().Set( + interface_template->GetFunction(isolate->GetCurrentContext()) + .ToLocalChecked()); + }; + Local<Object> global = context()->Global(); + ASSERT_TRUE(global + ->SetLazyDataProperty(context(), NewString("Interface"), + getter, Local<Value>(), DontEnum, + SideEffectType::kHasNoSideEffect) + .FromJust()); + + Local<Value> interface; + ASSERT_TRUE(TryGet(global, "Interface").ToLocal(&interface)); + ASSERT_TRUE(interface->IsFunction()); + Local<Value> prototype; + ASSERT_TRUE(TryGet(interface.As<Object>(), "prototype").ToLocal(&prototype)); + ASSERT_TRUE(prototype->IsObject()); + Local<Value> method; + ASSERT_TRUE(TryGet(prototype.As<Object>(), "method").ToLocal(&method)); + EXPECT_TRUE(method->StrictEquals(RunJS("Interface.prototype.method"))); + EXPECT_EQ(1, calls); +} + +TEST_F(TryGetWithNoSideEffectsTest, InterceptorsAreNotCalled) { + static int calls; + Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate()); + object_template->SetHandler(NamedPropertyHandlerConfiguration( + [](Local<Name>, const PropertyCallbackInfo<Value>& info) { + ++calls; + info.GetReturnValue().Set(42); + return Intercepted::kYes; + })); + object_template->SetHandler(IndexedPropertyHandlerConfiguration( + [](uint32_t, const PropertyCallbackInfo<Value>& info) { + ++calls; + info.GetReturnValue().Set(42); + return Intercepted::kYes; + })); + object_template->Set(isolate(), "own", NewString("own")); + Local<Object> object = + object_template->NewInstance(context()).ToLocalChecked(); + SetGlobalProperty("object", object); + Local<Object> derived = RunJSObject(R"( + var derived = Object.create(object); + Object.defineProperty(derived, 'own', {value: 'derived'}); + derived; + )"); + + calls = 0; + // Interceptors are consulted before the object's own properties. + ExpectEmpty(object, "own"); + ExpectEmpty(object, "missing"); + ExpectEmpty(object, "0"); + // Properties found before reaching the interceptor can be read. + ExpectValue(derived, "own", "'derived'"); + ExpectEmpty(derived, "missing"); + EXPECT_EQ(0, calls); +} + +TEST_F(TryGetWithNoSideEffectsTest, NonMaskingInterceptorsAreNotCalled) { + static int calls; + Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate()); + object_template->SetHandler(NamedPropertyHandlerConfiguration( + [](Local<Name>, const PropertyCallbackInfo<Value>& info) { + ++calls; + info.GetReturnValue().Set(42); + return Intercepted::kYes; + }, + nullptr, nullptr, nullptr, nullptr, Local<Value>(), + PropertyHandlerFlags::kNonMasking)); + object_template->Set(isolate(), "own", NewString("own")); + Local<Object> object = + object_template->NewInstance(context()).ToLocalChecked(); + + calls = 0; + // Non-masking interceptors are only consulted for properties that are not + // found on the prototype chain. + ExpectValue(object, "own", "'own'"); + ExpectValue(object, "toString", "Object.prototype.toString"); + ExpectEmpty(object, "missing"); + EXPECT_EQ(0, calls); +} + +TEST_F(TryGetWithNoSideEffectsTest, ProxiesAreNotCalled) { + Local<Object> proxy = RunJSObject(R"( + var trap_lookups = 0; + var handler = new Proxy({}, { + get() { + trap_lookups++; + return undefined; + } + }); + var proxy = new Proxy({data: 'data'}, handler); + var derived = Object.defineProperty(Object.create(proxy), 'own', + {value: 'own'}); + proxy; + )"); + ExpectEmpty(proxy, "data"); + ExpectEmpty(proxy, "missing"); + // Properties found before reaching the proxy can be read. + Local<Object> derived = RunJSObject("derived"); + ExpectValue(derived, "own", "'own'"); + ExpectEmpty(derived, "data"); + EXPECT_EQ(0, RunJSInt32("trap_lookups")); + + // Proxies are not looked through, even if they have no traps. + ExpectEmpty(RunJSObject("new Proxy({data: 'data'}, {})"), "data"); + // Unlike Get(), this doesn't throw for revoked proxies. + ExpectEmpty(RunJSObject(R"( + var {proxy: revoked, revoke} = Proxy.revocable({data: 'data'}, {}); + revoke(); + revoked; + )"), + "data"); +} + +TEST_F(TryGetWithNoSideEffectsTest, AccessChecks) { + static bool allow_access; + static int access_checks; + static int failed_access_checks; + isolate()->SetFailedAccessCheckCallbackFunction( + [](Local<Object>, AccessType, Local<Value>) { ++failed_access_checks; }); + Local<ObjectTemplate> object_template = ObjectTemplate::New(isolate()); + object_template->SetAccessCheckCallback( + [](Local<Context>, Local<Object>, Local<Value>) { + ++access_checks; + return allow_access; + }); + object_template->Set(isolate(), "data", NewString("data")); + allow_access = true; + Local<Object> object = + object_template->NewInstance(context()).ToLocalChecked(); + failed_access_checks = 0; + + access_checks = 0; + ExpectValue(object, "data", "'data'"); + EXPECT_LT(0, access_checks); + + access_checks = 0; + allow_access = false; + ExpectEmpty(object, "data"); + EXPECT_LT(0, access_checks); + EXPECT_EQ(0, failed_access_checks); +} + +TEST_F(TryGetWithNoSideEffectsTest, CrossContextAccess) { + RunJS("var data = 'data';"); + Local<Object> global = context()->Global(); + Local<Name> key = NewString("data"); + Local<Context> other_context = Context::New(isolate()); + EXPECT_TRUE(TryGet(global, key, other_context).IsEmpty()); + + Local<Value> token = NewString("token"); + context()->SetSecurityToken(token); + other_context->SetSecurityToken(token); + Local<Value> value; + ASSERT_TRUE(TryGet(global, key, other_context).ToLocal(&value)); + EXPECT_TRUE(value->StrictEquals(NewString("data"))); +} + } // namespace } // namespace v8 diff --git a/deps/v8/test/unittests/api/v8-script-unittest.cc b/deps/v8/test/unittests/api/v8-script-unittest.cc index 8d702aaa79ce..03abd157fdfc 100644 --- a/deps/v8/test/unittests/api/v8-script-unittest.cc +++ b/deps/v8/test/unittests/api/v8-script-unittest.cc @@ -11,6 +11,7 @@ #include "include/v8-local-handle.h" #include "include/v8-primitive.h" #include "include/v8-template.h" +#include "src/codegen/compilation-cache.h" #include "src/objects/objects-inl.h" #include "test/common/flag-utils.h" #include "test/common/streaming-helper.h" @@ -894,5 +895,338 @@ TEST_F(CompileHintsTest, EXPECT_FALSE(FunctionIsCompiled("test_function_2")); } +namespace { +class HistogramRecorder { + public: + static void Reset() { + base::MutexGuard guard(&mutex_); + histograms_.clear(); + } + + static void* CreateHistogram(const char* name, int min, int max, + size_t buckets) { + base::MutexGuard guard(&mutex_); + auto& entry = histograms_[name]; + if (!entry) { + entry = std::make_unique<std::vector<int>>(); + } + return entry.get(); + } + + static void AddHistogramSample(void* histogram, int sample) { + base::MutexGuard guard(&mutex_); + static_cast<std::vector<int>*>(histogram)->push_back(sample); + } + + static size_t Count(const char* name) { + base::MutexGuard guard(&mutex_); + auto it = histograms_.find(name); + if (it == histograms_.end() || !it->second) return 0; + return it->second->size(); + } + + private: + static base::Mutex mutex_; + static std::map<std::string, std::unique_ptr<std::vector<int>>> histograms_; +}; + +base::Mutex HistogramRecorder::mutex_; +std::map<std::string, std::unique_ptr<std::vector<int>>> + HistogramRecorder::histograms_; + +class OffThreadDeserializeThread : public base::Thread { + public: + explicit OffThreadDeserializeThread( + ScriptCompiler::ConsumeCodeCacheTask* task) + : Thread(base::Thread::Options("OffThreadDeserializeThread")), + task_(task) {} + + void Run() override { task_->Run(); } + + std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> TakeTask() { + return std::move(task_); + } + + private: + std::unique_ptr<ScriptCompiler::ConsumeCodeCacheTask> task_; +}; +} // namespace + +TEST_F(ScriptTest, CompileAndDeserializeHistograms) { + HistogramRecorder::Reset(); + isolate()->SetCreateHistogramFunction(&HistogramRecorder::CreateHistogram); + isolate()->SetAddHistogramSampleFunction( + &HistogramRecorder::AddHistogramSample); + + v8::ScriptOrigin classic_origin(NewString("classic.js")); + v8::ScriptOrigin module_origin(NewString("module.mjs"), 0, 0, false, -1, + Local<Value>(), false, false, true); + + // 1. Main-thread classic script compile. + const char* classic_code = "function classic_fn() { return 1; }"; + v8::ScriptCompiler::Source classic_source(NewString(classic_code), + classic_origin); + Local<Script> classic_script = + v8::ScriptCompiler::Compile(v8_context(), &classic_source) + .ToLocalChecked(); + std::unique_ptr<v8::ScriptCompiler::CachedData> classic_cache( + v8::ScriptCompiler::CreateCodeCache(classic_script->GetUnboundScript())); + + EXPECT_EQ(1u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds")); + EXPECT_EQ(1u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Classic")); + EXPECT_EQ(0u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Module")); + EXPECT_EQ( + 1u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds.MainThread")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.MainThread.Classic")); + EXPECT_EQ(0u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.MainThread.Module")); + + // 2. Main-thread module script compile. + const char* module_code = "export function module_fn() { return 2; }"; + v8::ScriptCompiler::Source module_source(NewString(module_code), + module_origin); + Local<Module> module = + v8::ScriptCompiler::CompileModule(isolate(), &module_source) + .ToLocalChecked(); + std::unique_ptr<v8::ScriptCompiler::CachedData> module_cache( + v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript())); + + EXPECT_EQ(2u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds")); + EXPECT_EQ(1u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Classic")); + EXPECT_EQ(1u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Module")); + EXPECT_EQ( + 2u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds.MainThread")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.MainThread.Classic")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.MainThread.Module")); + + // 3. Main-thread classic script deserialize. + i_isolate()->compilation_cache()->Clear(); + { + auto* cached_data = new v8::ScriptCompiler::CachedData( + classic_cache->data, classic_cache->length, + v8::ScriptCompiler::CachedData::BufferNotOwned); + v8::ScriptCompiler::Source cached_classic_source( + NewString(classic_code), classic_origin, cached_data); + v8::ScriptCompiler::Compile(v8_context(), &cached_classic_source, + v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + EXPECT_FALSE(cached_classic_source.GetCachedData()->rejected); + } + + EXPECT_EQ(1u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.Classic")); + EXPECT_EQ( + 0u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds.Module")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread.Classic")); + EXPECT_EQ(0u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread.Module")); + EXPECT_EQ(3u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds")); + EXPECT_EQ(2u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Classic")); + EXPECT_EQ(1u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Module")); + EXPECT_EQ( + 2u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds.MainThread")); + + // 4. Main-thread module script deserialize. + i_isolate()->compilation_cache()->Clear(); + { + auto* cached_data = new v8::ScriptCompiler::CachedData( + module_cache->data, module_cache->length, + v8::ScriptCompiler::CachedData::BufferNotOwned); + v8::ScriptCompiler::Source cached_module_source(NewString(module_code), + module_origin, cached_data); + v8::ScriptCompiler::CompileModule(isolate(), &cached_module_source, + v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + EXPECT_FALSE(cached_module_source.GetCachedData()->rejected); + } + + EXPECT_EQ(2u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.Classic")); + EXPECT_EQ( + 1u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds.Module")); + EXPECT_EQ(2u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread.Classic")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread.Module")); + EXPECT_EQ(4u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds")); + EXPECT_EQ(2u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Classic")); + EXPECT_EQ(2u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Module")); + EXPECT_EQ( + 2u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds.MainThread")); + + // 5. Background streaming classic script compile. + { + const char* chunks[] = {"function streamed_classic() { return 3; }", + nullptr}; + v8::ScriptCompiler::StreamedSource streamed_source( + std::make_unique<i::TestSourceStream>(chunks), + v8::ScriptCompiler::StreamedSource::ONE_BYTE); + std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task( + v8::ScriptCompiler::StartStreaming(isolate(), &streamed_source, + v8::ScriptType::kClassic)); + StreamerThread::StartThreadForTaskAndJoin(task.get()); + task.reset(); + + std::unique_ptr<char[]> full_source( + i::TestSourceStream::FullSourceString(chunks)); + v8::ScriptCompiler::Compile(v8_context(), &streamed_source, + NewString(full_source.get()), classic_origin) + .ToLocalChecked(); + } + + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.BackgroundThread")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.BackgroundThread.Classic")); + EXPECT_EQ(0u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.BackgroundThread.Module")); + EXPECT_EQ(5u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds")); + EXPECT_EQ(3u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Classic")); + EXPECT_EQ(2u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Module")); + EXPECT_EQ( + 2u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds.MainThread")); + + // 6. Background streaming module script compile. + { + const char* chunks[] = {"export function streamed_module() { return 4; }", + nullptr}; + v8::ScriptCompiler::StreamedSource streamed_source( + std::make_unique<i::TestSourceStream>(chunks), + v8::ScriptCompiler::StreamedSource::ONE_BYTE); + std::unique_ptr<v8::ScriptCompiler::ScriptStreamingTask> task( + v8::ScriptCompiler::StartStreaming(isolate(), &streamed_source, + v8::ScriptType::kModule)); + StreamerThread::StartThreadForTaskAndJoin(task.get()); + task.reset(); + + std::unique_ptr<char[]> full_source( + i::TestSourceStream::FullSourceString(chunks)); + v8::ScriptCompiler::CompileModule(v8_context(), &streamed_source, + NewString(full_source.get()), + module_origin) + .ToLocalChecked(); + } + + EXPECT_EQ(2u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.BackgroundThread")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.BackgroundThread.Classic")); + EXPECT_EQ(1u, HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.BackgroundThread.Module")); + EXPECT_EQ(6u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds")); + EXPECT_EQ(3u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Classic")); + EXPECT_EQ(3u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds.Module")); + EXPECT_EQ( + 2u, HistogramRecorder::Count("V8.CompileScriptMicroSeconds.MainThread")); + + // 7. Background classic script deserialize. + i_isolate()->compilation_cache()->Clear(); + { + OffThreadDeserializeThread deserialize_thread( + v8::ScriptCompiler::StartConsumingCodeCache( + isolate(), std::make_unique<v8::ScriptCompiler::CachedData>( + classic_cache->data, classic_cache->length, + v8::ScriptCompiler::CachedData::BufferNotOwned))); + CHECK(deserialize_thread.Start()); + deserialize_thread.Join(); + + auto* cached_data = new v8::ScriptCompiler::CachedData( + classic_cache->data, classic_cache->length, + v8::ScriptCompiler::CachedData::BufferNotOwned); + v8::ScriptCompiler::Source source(NewString(classic_code), classic_origin, + cached_data, + deserialize_thread.TakeTask().release()); + v8::ScriptCompiler::Compile(v8_context(), &source, + v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + EXPECT_FALSE(source.GetCachedData()->rejected); + } + + EXPECT_EQ(1u, + HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread")); + EXPECT_EQ(1u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds." + "ConsumeCache.BackgroundThread.Classic")); + EXPECT_EQ( + 0u, + HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread.Module")); + EXPECT_EQ(3u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds")); + EXPECT_EQ(2u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.Classic")); + EXPECT_EQ( + 1u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds.Module")); + EXPECT_EQ(2u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread")); + + // 8. Background module script deserialize. + i_isolate()->compilation_cache()->Clear(); + { + OffThreadDeserializeThread deserialize_thread( + v8::ScriptCompiler::StartConsumingCodeCache( + isolate(), std::make_unique<v8::ScriptCompiler::CachedData>( + module_cache->data, module_cache->length, + v8::ScriptCompiler::CachedData::BufferNotOwned))); + CHECK(deserialize_thread.Start()); + deserialize_thread.Join(); + + auto* cached_data = new v8::ScriptCompiler::CachedData( + module_cache->data, module_cache->length, + v8::ScriptCompiler::CachedData::BufferNotOwned); + v8::ScriptCompiler::Source source(NewString(module_code), module_origin, + cached_data, + deserialize_thread.TakeTask().release()); + v8::ScriptCompiler::CompileModule(isolate(), &source, + v8::ScriptCompiler::kConsumeCodeCache) + .ToLocalChecked(); + EXPECT_FALSE(source.GetCachedData()->rejected); + } + + EXPECT_EQ(2u, + HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread")); + EXPECT_EQ(1u, + HistogramRecorder::Count("V8.CompileScriptMicroSeconds." + "ConsumeCache.BackgroundThread.Classic")); + EXPECT_EQ( + 1u, + HistogramRecorder::Count( + "V8.CompileScriptMicroSeconds.ConsumeCache.BackgroundThread.Module")); + EXPECT_EQ(4u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds")); + EXPECT_EQ(2u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.Classic")); + EXPECT_EQ( + 2u, HistogramRecorder::Count("V8.CompileDeserializeMicroSeconds.Module")); + EXPECT_EQ(2u, HistogramRecorder::Count( + "V8.CompileDeserializeMicroSeconds.MainThread")); + + isolate()->SetCreateHistogramFunction(nullptr); + isolate()->SetAddHistogramSampleFunction(nullptr); + HistogramRecorder::Reset(); +} + } // namespace } // namespace v8 diff --git a/deps/v8/test/unittests/api/v8-value-unittest.cc b/deps/v8/test/unittests/api/v8-value-unittest.cc index 11dd1807e2e0..8a8fe004acf7 100644 --- a/deps/v8/test/unittests/api/v8-value-unittest.cc +++ b/deps/v8/test/unittests/api/v8-value-unittest.cc @@ -4,6 +4,7 @@ #include "include/v8-value.h" +#include "include/v8-primitive.h" #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -28,5 +29,30 @@ TEST_F(ValueTest, TypecheckWitness) { EXPECT_TRUE(witness.Matches(bar)); } +TEST_F(ValueTest, ToUint32) { + HandleScope scope(isolate()); + + Local<Value> pos_smi = Integer::New(isolate(), 42); + Local<Uint32> pos_uint32 = pos_smi->ToUint32(context()).ToLocalChecked(); + EXPECT_TRUE(pos_uint32->IsUint32()); + EXPECT_EQ(42u, pos_uint32->Value()); + EXPECT_EQ(42.0, pos_uint32.As<Number>()->Value()); + EXPECT_EQ(42u, pos_smi->Uint32Value(context()).FromJust()); + + Local<Value> neg_smi = Integer::New(isolate(), -37); + Local<Uint32> neg_uint32 = neg_smi->ToUint32(context()).ToLocalChecked(); + EXPECT_TRUE(neg_uint32->IsUint32()); + EXPECT_EQ(4294967259u, neg_uint32->Value()); + EXPECT_EQ(4294967259.0, neg_uint32.As<Number>()->Value()); + EXPECT_EQ(4294967259u, neg_smi->Uint32Value(context()).FromJust()); + + Local<Value> neg_str = String::NewFromUtf8Literal(isolate(), "-37"); + Local<Uint32> str_uint32 = neg_str->ToUint32(context()).ToLocalChecked(); + EXPECT_TRUE(str_uint32->IsUint32()); + EXPECT_EQ(4294967259u, str_uint32->Value()); + EXPECT_EQ(4294967259.0, str_uint32.As<Number>()->Value()); + EXPECT_EQ(4294967259u, neg_str->Uint32Value(context()).FromJust()); +} + } // namespace } // namespace v8 diff --git a/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc b/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc index e5fd46a7f87d..df61de1ac16e 100644 --- a/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc +++ b/deps/v8/test/unittests/assembler/assembler-arm64-unittest.cc @@ -6769,6 +6769,56 @@ TEST_F(AssemblerArm64Test, ldur_stur) { CHECK_EQUAL_64(dst_base + 32, x20); } +TEST_F(AssemblerArm64Test, ldapur_stlur) { + SETUP(); + SETUP_FEATURE(LRCPC2); + + uint64_t src[2] = {0x0123456789ABCDEFUL, 0xFEDCBA9876543210UL}; + uint64_t dst[3] = {0, 0, 0}; + uintptr_t src_base = reinterpret_cast<uintptr_t>(src); + uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst); + + START(); + __ Mov(x17, src_base + 1); + __ Mov(x28, dst_base + 1); + __ Mov(x19, src_base + 15); + __ Mov(x20, dst_base + 19); + __ Ldapur(w0, MemOperand(x17, -1)); + __ Stlur(w0, MemOperand(x28, -1)); + __ Ldapur(w2, MemOperand(x17, 3)); + __ Stlur(w2, MemOperand(x28, 3)); + __ Ldapur(x1, MemOperand(x17, 7)); + __ Stlur(x1, MemOperand(x28, 7)); + __ Ldapurb(w3, MemOperand(x19, -2)); + __ Stlurb(w3, MemOperand(x20, -1)); + __ Ldapursb(x4, MemOperand(x19, -15)); + __ Ldapursh(x5, MemOperand(x19, -13)); + __ Ldapursw(x6, MemOperand(x19, -3)); + __ Ldapurh(w7, MemOperand(x19, -13)); + __ Stlurh(w7, MemOperand(x20, -3)); + END(); + + if (CAN_RUN()) { + RUN(); + + CHECK_EQUAL_64(0x89ABCDEFUL, x0); + CHECK_EQUAL_64(0x01234567UL, x2); + CHECK_EQUAL_64(0x0123456789ABCDEFUL, dst[0]); + CHECK_EQUAL_64(0xFEDCBA9876543210UL, x1); + CHECK_EQUAL_64(0xFEDCBA9876543210UL, dst[1]); + CHECK_EQUAL_64(0x000000BAUL, x3); + CHECK_EQUAL_64(0xFFFFFFFFFFFFFFEFUL, x4); + CHECK_EQUAL_64(0xFFFFFFFFFFFF89ABUL, x5); + CHECK_EQUAL_64(0xFFFFFFFFFEDCBA98UL, x6); + CHECK_EQUAL_64(0x000089ABUL, x7); + CHECK_EQUAL_64(0x00BA89ABUL, dst[2]); + CHECK_EQUAL_64(src_base + 1, x17); + CHECK_EQUAL_64(dst_base + 1, x28); + CHECK_EQUAL_64(src_base + 15, x19); + CHECK_EQUAL_64(dst_base + 19, x20); + } +} + TEST_F(AssemblerArm64Test, ldr_pcrel_large_offset) { SETUP_SIZE(1 * MB); @@ -11760,6 +11810,48 @@ TEST_F(AssemblerArm64Test, scvtf_ucvtf_float) { TestUScvtf32Helper(0xFFFFFFFFFFFFFFFF, 0xBF800000, 0x5F800000); } +TEST_F(AssemblerArm64Test, scvtf_ucvtf_upper_bits) { + SETUP(); + START(); + + __ Movi(v0.V16B(), 0xFF); + __ Movi(v1.V16B(), 0xFF); + __ Movi(v4.V16B(), 0xFF); + __ Movi(v5.V16B(), 0xFF); + __ Movi(v6.V16B(), 0xFF); + __ Movi(v7.V16B(), 0xFF); + + __ Mov(w0, 42); + __ Dup(v2.V2S(), w0); + __ Dup(v3.V2S(), w0); + + // Vector 2S integer-to-float (upper 64 bits must be zeroed). + __ Ucvtf(v0.V2S(), v2.V2S()); + __ Scvtf(v1.V2S(), v3.V2S()); + + // Vector 2S fixed-point-to-float (upper 64 bits must be zeroed). + __ Ucvtf(v4.V2S(), v2.V2S(), 1); + __ Scvtf(v5.V2S(), v3.V2S(), 1); + + // Scalar 1D fixed-point-to-float (upper 64 bits must be zeroed). + __ Mov(x0, 42); + __ Fmov(v8_.V1D(), x0); + __ Ucvtf(v6.V1D(), v8_.V1D(), 1); + __ Scvtf(v7.V1D(), v8_.V1D(), 1); + + END(); + RUN(); + + CHECK_EQUAL_128(0, 0x4228000042280000, q0); + CHECK_EQUAL_128(0, 0x4228000042280000, q1); + // 42 >> 1 = 21.0f = 0x41a80000 + CHECK_EQUAL_128(0, 0x41a8000041a80000, q4); + CHECK_EQUAL_128(0, 0x41a8000041a80000, q5); + // 42.0 / 2.0 = 21.0 = 0x4035000000000000 + CHECK_EQUAL_128(0, 0x4035000000000000, q6); + CHECK_EQUAL_128(0, 0x4035000000000000, q7); +} + TEST_F(AssemblerArm64Test, system_mrs) { SETUP(); @@ -16442,6 +16534,45 @@ TEST_F(AssemblerArm64Test, sve_bit_permute) { } } +TEST_F(AssemblerArm64Test, sve2_mul) { + SETUP(); + SETUP_FEATURE(SVE2); + START(); + + __ Movi(v1.V2D(), 0x00'00'00'00'00'00'00'02, 0x00'00'00'00'00'00'00'04); + __ Movi(v2.V2D(), 0x00'00'00'00'00'00'00'03, 0x00'00'00'00'00'00'00'03); + __ Movi(v4.V2D(), 0x0000'0000'0000'0002, 0x0000'0000'0000'0004); + __ Movi(v5.V2D(), 0x0000'0000'0000'0003, 0x0000'0000'0000'0003); + __ Movi(v7.V2D(), 0x00000000'00000002, 0x00000000'00000004); + __ Movi(v8.V2D(), 0x00000000'00000003, 0x00000000'00000003); + __ Movi(v10.V2D(), 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF); + __ Movi(v11.V2D(), 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF); + __ Movi(v12.V2D(), 0x00000000'00000003, 0x00000000'00000003); + __ Movi(v13.V2D(), 0x00000000'00000003, 0x00000000'00000003); + __ Movi(v14.V2D(), 0x00000000'00000003, 0x00000000'00000004); + __ Movi(v15.V2D(), 0x00000000'00000003, 0x00000000'00000004); + + __ Mul(z0.VnB(), z1.VnB(), z2.VnB()); + __ Mul(z3.VnH(), z4.VnH(), z5.VnH()); + __ Mul(z6.VnS(), z7.VnS(), z8.VnS()); + __ Mul(z9.VnD(), z10.VnD(), z11.VnD()); + __ Mul(z12.VnD(), z12.VnD(), z13.VnD()); + __ Mul(z15.VnD(), z14.VnD(), z15.VnD()); + + END(); + + if (CAN_RUN()) { + RUN(); + + CHECK_EQUAL_128(0x00'00'00'00'00'00'00'06, 0x00'00'00'00'00'00'00'0c, q0); + CHECK_EQUAL_128(0x0000'0000'0000'0006, 0x0000'0000'0000'000c, q3); + CHECK_EQUAL_128(0x00000000'00000006, 0x00000000'0000000c, q6); + CHECK_EQUAL_128(0x0000000000000001, 0x0000000000000001, q9); + CHECK_EQUAL_128(0x0000000000000009, 0x0000000000000009, q12); + CHECK_EQUAL_128(0x0000000000000009, 0x0000000000000010, q15); + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/assembler/assembler-riscv64-unittest.cc b/deps/v8/test/unittests/assembler/assembler-riscv64-unittest.cc index bf86fdee3ca9..e9a1521da4c5 100644 --- a/deps/v8/test/unittests/assembler/assembler-riscv64-unittest.cc +++ b/deps/v8/test/unittests/assembler/assembler-riscv64-unittest.cc @@ -4563,6 +4563,141 @@ UTEST_RVV_VFW_REDSUM_VV_FORM_WITH_RES(vfwredusum_vs) UTEST_RVV_VFW_REDSUM_VV_FORM_WITH_RES(vfwredosum_vs) #undef UTEST_RVV_VFW_REDSUM_VV_FORM_WITH_RES + +// Regression tests for the FP16 fused multiply-add (SEW=16). The product-sum +// must be rounded only once to Float16; computing it in float and converting +// the result to Float16 double-rounds. +// +// Operands are passed as float values (all exactly representable in FP16) and +// converted with Float16::FromFloat32: +// vd = -1025/1024 = -1.0009765625 (accumulator) +// vs1 = 3/2 = 1.5 +// vs2 = -2^-24 = -0x1p-24f = -5.9604645e-08 +// The exact product-sum lies just below the FP16 rounding midpoint between the +// 1.5009765625 and 1.501953125 results, so vfnmsub_vv must round it down to +// 1.5009765625; a float intermediate double-rounds it up to 1.501953125. +#define UTEST_RVV_F16_FMA_VV(instr_name, vd, vs1, vs2, expected) \ + TEST_F(AssemblerRISCV64Test, RISCV_UTEST_F16_##instr_name) { \ + if (!CpuFeatures::IsSupported(RVV)) { \ + return; \ + } \ + \ + uint16_t result[kMaxElements] = {0}; \ + auto fn = [&result](MacroAssembler& assm) { \ + __ VU.set(t0, zero_reg, VSew::E16, m1); \ + __ vmv_vx(v0, a0); \ + __ vmv_vx(v1, a1); \ + __ vmv_vx(v2, a2); \ + __ instr_name(v0, v1, v2); \ + __ li(a3, Operand(int64_t(result))); \ + __ vs(v0, a3, 0, E16); \ + }; \ + GenAndRunTest<uint32_t, uint32_t>(Float16::FromFloat32(vd).get_bits(), \ + Float16::FromFloat32(vs1).get_bits(), \ + Float16::FromFloat32(vs2).get_bits(), \ + fn); \ + uint16_t expected_bits = Float16::FromFloat32(expected).get_bits(); \ + for (unsigned i = 0; i < CpuFeatures::vlen() / 16; i++) { \ + CHECK_EQ(expected_bits, result[i]); \ + } \ + } + +// vd vs1 vs2 expected +UTEST_RVV_F16_FMA_VV(vfmadd_vv, -1.0009765625f, 1.5f, -0x1p-24f, -1.501953125f) +UTEST_RVV_F16_FMA_VV(vfnmadd_vv, -1.0009765625f, 1.5f, -0x1p-24f, 1.501953125f) +UTEST_RVV_F16_FMA_VV(vfmsub_vv, -1.0009765625f, 1.5f, -0x1p-24f, -1.5009765625f) +UTEST_RVV_F16_FMA_VV(vfnmsub_vv, -1.0009765625f, 1.5f, -0x1p-24f, 1.5009765625f) +UTEST_RVV_F16_FMA_VV(vfmacc_vv, -1.0009765625f, 1.5f, -0x1p-24f, -1.0009765625f) +UTEST_RVV_F16_FMA_VV(vfnmacc_vv, -1.0009765625f, 1.5f, -0x1p-24f, 1.0009765625f) +UTEST_RVV_F16_FMA_VV(vfmsac_vv, -1.0009765625f, 1.5f, -0x1p-24f, 1.0009765625f) +UTEST_RVV_F16_FMA_VV(vfnmsac_vv, -1.0009765625f, 1.5f, -0x1p-24f, + -1.0009765625f) + +#undef UTEST_RVV_F16_FMA_VV + +// Direct test for the widening floating-point sum reduction with SEW=16 +// (F16 -> F32): the masked-off elements must be skipped. +TEST_F(AssemblerRISCV64Test, RISCV_UTEST_F16_VFWREDUSUM_VS) { + if (!CpuFeatures::IsSupported(RVV)) return; + + const unsigned n = CpuFeatures::vlen() / 16; + struct T { + uint16_t src[kMaxElements] = {0}; + } t; + float expected = 0.0f; + for (unsigned i = 0; i < n; i++) { + float v = static_cast<float>(i + 1); + t.src[i] = Float16::FromFloat32(v).get_bits(); + expected += v; + } + + auto fn = [](MacroAssembler& assm) { + __ fmv_w_x(fa0, zero_reg); + __ VU.set(t0, zero_reg, VSew::E32, m1); + __ vfmv_vf(v4, fa0); // vs1 = 0.0 (F32) + __ VU.set(t0, zero_reg, VSew::E16, m1); + __ vl(v2, a0, 0, E16); // vs2 = F16 input + __ vfwredusum_vs(v0, v2, v4); + __ VU.set(t0, zero_reg, VSew::E32, m1); + __ vfmv_fs(fa0, v0); + }; + float res = GenAndRunTest<float, int64_t>((int64_t)&t.src[0], fn); + CHECK_FLOAT_EQ(expected, res); +} + +// Same reduction with a mask: only the element at index 1 is active, so the +// masked-off elements must not contribute to the result. +TEST_F(AssemblerRISCV64Test, RISCV_UTEST_F16_VFWREDUSUM_VS_MASK) { + if (!CpuFeatures::IsSupported(RVV)) return; + + const unsigned n = CpuFeatures::vlen() / 16; + struct T { + uint16_t src[kMaxElements] = {0}; + } t; + for (unsigned i = 0; i < n; i++) { + t.src[i] = Float16::FromFloat32(static_cast<float>(i + 1)).get_bits(); + } + + auto fn = [](MacroAssembler& assm) { + __ fmv_w_x(fa0, zero_reg); + __ VU.set(t0, zero_reg, VSew::E16, m1); + __ vid_v(v1, NoMask); + __ li(a1, Operand(1)); + __ vmseq_vx(v0, v1, a1); // mask = (element index == 1) + __ vl(v2, a0, 0, E16); + __ VU.set(t0, zero_reg, VSew::E32, m1); + __ vfmv_vf(v4, fa0); // vs1 = 0.0 (F32) + __ VU.set(t0, zero_reg, VSew::E16, m1); + __ vfwredusum_vs(v8, v2, v4, Mask); + __ VU.set(t0, zero_reg, VSew::E32, m1); + __ vfmv_fs(fa0, v8); + }; + float res = GenAndRunTest<float, int64_t>((int64_t)&t.src[0], fn); + CHECK_FLOAT_EQ(2.0f, res); +} + +// When vl == 0 the destination must not be modified by the reduction. +TEST_F(AssemblerRISCV64Test, RISCV_UTEST_F16_VFWREDUSUM_VS_VL0) { + if (!CpuFeatures::IsSupported(RVV)) return; + + float result[kMaxElements] = {0}; + + auto fn = [&result](MacroAssembler& assm) { + __ li(t1, Operand(0x42280000)); // 42.0f + __ fmv_w_x(fa0, t1); + __ VU.set(t0, zero_reg, VSew::E32, m1); // vl = VLMAX + __ vfmv_vf(v8, fa0); // vd[0] = 42.0 sentinel + __ li(t1, Operand(0)); + __ VU.set(t0, t1, VSew::E16, m1); // vl = 0 + __ vfwredusum_vs(v8, v2, v4); + __ VU.set(t0, zero_reg, VSew::E32, m1); // vl = VLMAX + __ li(a3, Operand(int64_t(result))); + __ vs(v8, a3, 0, E32); + }; + GenAndRunTest(fn); + CHECK_FLOAT_EQ(42.0f, result[0]); +} + // calculate the value of r used in rounding static inline uint8_t get_round(int vxrm, uint64_t v, uint8_t shift) { // uint8_t d = extract64(v, shift, 1); diff --git a/deps/v8/test/unittests/assembler/assembler-x64-unittest.cc b/deps/v8/test/unittests/assembler/assembler-x64-unittest.cc index 96bbaa268e4c..0a9bbd94bb66 100644 --- a/deps/v8/test/unittests/assembler/assembler-x64-unittest.cc +++ b/deps/v8/test/unittests/assembler/assembler-x64-unittest.cc @@ -3281,6 +3281,217 @@ TEST_F(AssemblerX64Test, AVX10RegisterCodes) { #endif // V8_ENABLE_AVX10_1 #ifdef V8_ENABLE_AVX10_1 +TEST_F(AssemblerX64Test, AVX10Vaddph) { + auto buffer = AllocateAssemblerBuffer(); + Assembler masm(AssemblerOptions{}, buffer->CreateView()); + // Encoding only: do not execute AVX10.1 instructions on the test host. + CpuFeatureScope fscope(&masm, AVX10_1, CpuFeatureScope::kDontCheckSupported); + + __ vaddph(xmm3, xmm2, xmm1); + __ vaddph(ymm3, ymm2, ymm1); + __ vaddph(xmm19, xmm18, xmm17); + __ vaddph(ymm31, ymm30, ymm29); + __ vaddph(xmm3, xmm3, xmm1); + __ vaddph(xmm3, xmm2, xmm3); + __ vaddph(xmm3, xmm3, xmm3); + __ vaddph(ymm3, ymm3, ymm1); + __ vaddph(ymm3, ymm2, ymm3); + __ vaddph(ymm3, ymm3, ymm3); + __ vaddph(xmm3, xmm2, Operand(rbx, 64)); + __ vaddph(ymm3, ymm2, Operand(rbx, 128)); + __ vaddph(xmm3, xmm2, Operand(rbx, -16)); + __ vaddph(ymm3, ymm2, Operand(rbx, -32)); + // Not divisible by vector width: disp32 instead of compressed disp8. + __ vaddph(xmm3, xmm2, Operand(rbx, 20)); + __ vaddph(ymm3, ymm2, Operand(rbx, 36)); + // Compressed displacement is out of range. + __ vaddph(xmm3, xmm2, Operand(rbx, 2048)); + __ vaddph(ymm3, ymm2, Operand(rbx, 4096)); + __ vaddph(xmm19, xmm18, Operand(r12, r13, times_2, 64)); + __ vaddph(ymm19, ymm18, Operand(r12, r13, times_2, 128)); + Label xmm_label, ymm_label; + __ bind(&xmm_label); + __ vaddph(xmm3, xmm2, Operand(&xmm_label)); + __ bind(&ymm_label); + __ vaddph(ymm3, ymm2, Operand(&ymm_label)); + + int instruction_length = masm.pc_offset(); + CodeDesc desc; + masm.GetCode(i_isolate(), &desc); + // Independently checked with LLVM's assembler: EVEX.NP.MAP5.W0 58 /r. + // Keep one instruction per line. + // clang-format off + const uint8_t expected[] = { + // Register operands, including high registers and aliasing. + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0xd9, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0xd9, + 0x62, 0xa5, 0x6c, 0x00, 0x58, 0xd9, + 0x62, 0x05, 0x0c, 0x20, 0x58, 0xfd, + 0x62, 0xf5, 0x64, 0x08, 0x58, 0xd9, + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0xdb, + 0x62, 0xf5, 0x64, 0x08, 0x58, 0xdb, + 0x62, 0xf5, 0x64, 0x28, 0x58, 0xd9, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0xdb, + 0x62, 0xf5, 0x64, 0x28, 0x58, 0xdb, + // Compressed disp8: scale is 16 bytes for XMM, 32 for YMM. + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0x5b, 0x04, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0x5b, 0x04, + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0x5b, 0xff, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0x5b, 0xff, + // disp32 fallback: unaligned or out of compressed disp8 range. + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0x9b, 0x24, 0x00, 0x00, 0x00, + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0x9b, 0x00, 0x08, 0x00, 0x00, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0x9b, 0x00, 0x10, 0x00, 0x00, + // SIB addressing with extended base/index and vector registers. + 0x62, 0x85, 0x6c, 0x00, 0x58, 0x5c, 0x6c, 0x04, + 0x62, 0x85, 0x6c, 0x20, 0x58, 0x5c, 0x6c, 0x04, + // RIP-relative displacements are not compressed. + 0x62, 0xf5, 0x6c, 0x08, 0x58, 0x1d, 0xf6, 0xff, 0xff, 0xff, + 0x62, 0xf5, 0x6c, 0x28, 0x58, 0x1d, 0xf6, 0xff, 0xff, 0xff}; + // clang-format on + CHECK_EQ(static_cast<int>(sizeof(expected)), instruction_length); + CHECK_EQ(0, memcmp(expected, desc.buffer, sizeof(expected))); +} + +TEST_F(AssemblerX64Test, AVX10Vsubph) { + auto buffer = AllocateAssemblerBuffer(); + Assembler masm(AssemblerOptions{}, buffer->CreateView()); + CpuFeatureScope fscope(&masm, AVX10_1, CpuFeatureScope::kDontCheckSupported); + + __ vsubph(xmm3, xmm2, xmm1); + __ vsubph(ymm3, ymm2, ymm1); + __ vsubph(xmm19, xmm18, xmm17); + __ vsubph(ymm31, ymm30, ymm29); + __ vsubph(xmm3, xmm3, xmm1); + __ vsubph(xmm3, xmm2, xmm3); + __ vsubph(xmm3, xmm3, xmm3); + __ vsubph(ymm3, ymm3, ymm1); + __ vsubph(ymm3, ymm2, ymm3); + __ vsubph(ymm3, ymm3, ymm3); + __ vsubph(xmm3, xmm2, Operand(rbx, 2032)); + __ vsubph(ymm3, ymm2, Operand(rbx, 4064)); + __ vsubph(xmm3, xmm2, Operand(rbx, -2048)); + __ vsubph(ymm3, ymm2, Operand(rbx, -4096)); + __ vsubph(xmm3, xmm2, Operand(rbx, 20)); + __ vsubph(ymm3, ymm2, Operand(rbx, 36)); + __ vsubph(xmm3, xmm2, Operand(rbx, 2048)); + __ vsubph(ymm3, ymm2, Operand(rbx, 4096)); + __ vsubph(xmm19, xmm18, Operand(r12, r13, times_2, 64)); + __ vsubph(ymm19, ymm18, Operand(r12, r13, times_2, 128)); + Label xmm_label, ymm_label; + __ bind(&xmm_label); + __ vsubph(xmm3, xmm2, Operand(&xmm_label)); + __ bind(&ymm_label); + __ vsubph(ymm3, ymm2, Operand(&ymm_label)); + + int instruction_length = masm.pc_offset(); + CodeDesc desc; + masm.GetCode(i_isolate(), &desc); + // clang-format off + const uint8_t expected[] = { + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0xd9, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0xd9, + 0x62, 0xa5, 0x6c, 0x00, 0x5c, 0xd9, + 0x62, 0x05, 0x0c, 0x20, 0x5c, 0xfd, + 0x62, 0xf5, 0x64, 0x08, 0x5c, 0xd9, + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0xdb, + 0x62, 0xf5, 0x64, 0x08, 0x5c, 0xdb, + 0x62, 0xf5, 0x64, 0x28, 0x5c, 0xd9, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0xdb, + 0x62, 0xf5, 0x64, 0x28, 0x5c, 0xdb, + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0x5b, 0x7f, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0x5b, 0x7f, + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0x5b, 0x80, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0x5b, 0x80, + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0x9b, 0x24, 0x00, 0x00, 0x00, + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0x9b, 0x00, 0x08, 0x00, 0x00, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0x9b, 0x00, 0x10, 0x00, 0x00, + 0x62, 0x85, 0x6c, 0x00, 0x5c, 0x5c, 0x6c, 0x04, + 0x62, 0x85, 0x6c, 0x20, 0x5c, 0x5c, 0x6c, 0x04, + 0x62, 0xf5, 0x6c, 0x08, 0x5c, 0x1d, 0xf6, 0xff, 0xff, 0xff, + 0x62, 0xf5, 0x6c, 0x28, 0x5c, 0x1d, 0xf6, 0xff, 0xff, 0xff}; + // clang-format on + CHECK_EQ(static_cast<int>(sizeof(expected)), instruction_length); + CHECK_EQ(0, memcmp(expected, desc.buffer, sizeof(expected))); +} + +TEST_F(AssemblerX64Test, AVX10FmaPh) { + for (bool negate : {false, true}) { + auto buffer = AllocateAssemblerBuffer(); + Assembler masm(AssemblerOptions{}, buffer->CreateView()); + CpuFeatureScope fscope(&masm, AVX10_1, + CpuFeatureScope::kDontCheckSupported); + auto emit = [&](auto dst, auto src1, auto src2) { + if (negate) { + __ vfnmadd213ph(dst, src1, src2); + } else { + __ vfmadd213ph(dst, src1, src2); + } + }; + emit(xmm3, xmm2, xmm1); + emit(ymm3, ymm2, ymm1); + emit(xmm19, xmm18, xmm17); + emit(ymm31, ymm30, ymm29); + emit(xmm3, xmm3, xmm1); + emit(xmm3, xmm2, xmm3); + emit(xmm3, xmm3, xmm3); + emit(ymm3, ymm3, ymm1); + emit(ymm3, ymm2, ymm3); + emit(ymm3, ymm3, ymm3); + // Inclusive limits of compressed disp8, then unaligned/out-of-range disp32. + emit(xmm3, xmm2, Operand(rbx, 2032)); + emit(ymm3, ymm2, Operand(rbx, 4064)); + emit(xmm3, xmm2, Operand(rbx, -2048)); + emit(ymm3, ymm2, Operand(rbx, -4096)); + emit(xmm3, xmm2, Operand(rbx, 20)); + emit(ymm3, ymm2, Operand(rbx, 36)); + emit(xmm3, xmm2, Operand(rbx, 2048)); + emit(ymm3, ymm2, Operand(rbx, 4096)); + emit(xmm19, xmm18, Operand(r12, r13, times_2, 64)); + emit(ymm19, ymm18, Operand(r12, r13, times_2, 128)); + Label xmm_label, ymm_label; + __ bind(&xmm_label); + emit(xmm3, xmm2, Operand(&xmm_label)); + __ bind(&ymm_label); + emit(ymm3, ymm2, Operand(&ymm_label)); + + int instruction_length = masm.pc_offset(); + CodeDesc desc; + masm.GetCode(i_isolate(), &desc); + // Independently checked with LLVM: EVEX.66.MAP6.W0 A8/AC /r. + const uint8_t op = negate ? 0xac : 0xa8; + // clang-format off + const uint8_t expected[] = { + 0x62, 0xf6, 0x6d, 0x08, op, 0xd9, + 0x62, 0xf6, 0x6d, 0x28, op, 0xd9, + 0x62, 0xa6, 0x6d, 0x00, op, 0xd9, + 0x62, 0x06, 0x0d, 0x20, op, 0xfd, + 0x62, 0xf6, 0x65, 0x08, op, 0xd9, + 0x62, 0xf6, 0x6d, 0x08, op, 0xdb, + 0x62, 0xf6, 0x65, 0x08, op, 0xdb, + 0x62, 0xf6, 0x65, 0x28, op, 0xd9, + 0x62, 0xf6, 0x6d, 0x28, op, 0xdb, + 0x62, 0xf6, 0x65, 0x28, op, 0xdb, + 0x62, 0xf6, 0x6d, 0x08, op, 0x5b, 0x7f, + 0x62, 0xf6, 0x6d, 0x28, op, 0x5b, 0x7f, + 0x62, 0xf6, 0x6d, 0x08, op, 0x5b, 0x80, + 0x62, 0xf6, 0x6d, 0x28, op, 0x5b, 0x80, + 0x62, 0xf6, 0x6d, 0x08, op, 0x9b, 0x14, 0x00, 0x00, 0x00, + 0x62, 0xf6, 0x6d, 0x28, op, 0x9b, 0x24, 0x00, 0x00, 0x00, + 0x62, 0xf6, 0x6d, 0x08, op, 0x9b, 0x00, 0x08, 0x00, 0x00, + 0x62, 0xf6, 0x6d, 0x28, op, 0x9b, 0x00, 0x10, 0x00, 0x00, + 0x62, 0x86, 0x6d, 0x00, op, 0x5c, 0x6c, 0x04, + 0x62, 0x86, 0x6d, 0x20, op, 0x5c, 0x6c, 0x04, + 0x62, 0xf6, 0x6d, 0x08, op, 0x1d, 0xf6, 0xff, 0xff, 0xff, + 0x62, 0xf6, 0x6d, 0x28, op, 0x1d, 0xf6, 0xff, 0xff, 0xff}; + // clang-format on + CHECK_EQ(static_cast<int>(sizeof(expected)), instruction_length); + CHECK_EQ(0, memcmp(expected, desc.buffer, sizeof(expected))); + } +} + TEST_F(AssemblerX64Test, AVX10Vpmullq) { auto buffer = AllocateAssemblerBuffer(); Isolate* isolate = i_isolate(); diff --git a/deps/v8/test/unittests/assembler/disasm-arm-unittest.cc b/deps/v8/test/unittests/assembler/disasm-arm-unittest.cc index 5b446d3cc94f..7b1e4a7a8d41 100644 --- a/deps/v8/test/unittests/assembler/disasm-arm-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-arm-unittest.cc @@ -26,6 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // +#include <array> #include <cinttypes> #include <cstdlib> @@ -58,7 +59,7 @@ bool DisassembleAndCompare(uint8_t* begin, UseRegex use_regex, S... expected_strings) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; std::vector<std::string> expected_disassembly = {expected_strings...}; size_t n_expected = expected_disassembly.size(); @@ -67,7 +68,7 @@ bool DisassembleAndCompare(uint8_t* begin, UseRegex use_regex, std::vector<std::string> disassembly; for (uint8_t* pc = begin; pc < end;) { pc += disasm.InstructionDecode(buffer, pc); - disassembly.emplace_back(buffer.begin()); + disassembly.emplace_back(buffer.data()); } bool test_passed = true; diff --git a/deps/v8/test/unittests/assembler/disasm-arm64-unittest.cc b/deps/v8/test/unittests/assembler/disasm-arm64-unittest.cc index 1c54e9f6efe8..0fb65ba4cc37 100644 --- a/deps/v8/test/unittests/assembler/disasm-arm64-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-arm64-unittest.cc @@ -1519,6 +1519,30 @@ TEST_F(DisasmArm64Test, load_store_acquire_release) { COMPARE(caspal(x4, x5, x6, x7, MemOperand(sp)), "caspal x4, x5, x6, x7, [sp]"); + { + CpuFeatureScope lrcpc2_scope(assm, LRCPC2, + CpuFeatureScope::kDontCheckSupported); + COMPARE(stlurb(w0, MemOperand(x1, 0)), "stlurb w0, [x1]"); + COMPARE(stlurb(w2, MemOperand(x3, -1)), "stlurb w2, [x3, #-1]"); + COMPARE(stlurb(wzr, MemOperand(sp, 255)), "stlurb wzr, [sp, #255]"); + COMPARE(stlurh(w4, MemOperand(x5, -256)), "stlurh w4, [x5, #-256]"); + COMPARE(stlurh(wzr, MemOperand(sp, 0)), "stlurh wzr, [sp]"); + COMPARE(stlur(w6, MemOperand(x7, -1)), "stlur w6, [x7, #-1]"); + COMPARE(stlur(x8, MemOperand(x9, 7)), "stlur x8, [x9, #7]"); + COMPARE(stlur(xzr, MemOperand(sp, -8)), "stlur xzr, [sp, #-8]"); + + COMPARE(ldapurb(w10, MemOperand(x11, 0)), "ldapurb w10, [x11]"); + COMPARE(ldapurb(w12, MemOperand(x13, -1)), "ldapurb w12, [x13, #-1]"); + COMPARE(ldapursb(w14, MemOperand(x15, 127)), "ldapursb w14, [x15, #127]"); + COMPARE(ldapursb(x16, MemOperand(x17, -128)), "ldapursb x16, [x17, #-128]"); + COMPARE(ldapurh(w18, MemOperand(x19, 2)), "ldapurh w18, [x19, #2]"); + COMPARE(ldapursh(w20, MemOperand(x21, -2)), "ldapursh w20, [x21, #-2]"); + COMPARE(ldapursh(x22, MemOperand(x23, 6)), "ldapursh x22, [x23, #6]"); + COMPARE(ldapur(w24, MemOperand(x25, -1)), "ldapur w24, [x25, #-1]"); + COMPARE(ldapur(x26, MemOperand(x27, 15)), "ldapur x26, [cp, #15]"); + COMPARE(ldapursw(x28, MemOperand(sp, -4)), "ldapursw x28, [sp, #-4]"); + } + CLEANUP(); } @@ -5218,6 +5242,20 @@ TEST_F(DisasmArm64Test, sve_bit_permute) { CLEANUP(); } +TEST_F(DisasmArm64Test, mul) { + SET_UP_MASM(); + + CpuFeatureScope feature_scope(assm, SVE2, + CpuFeatureScope::kDontCheckSupported); + + COMPARE(Mul(z0.VnB(), z1.VnB(), z2.VnB()), "mul z0.b, z1.b, z2.b"); + COMPARE(Mul(z0.VnH(), z1.VnH(), z2.VnH()), "mul z0.h, z1.h, z2.h"); + COMPARE(Mul(z0.VnS(), z1.VnS(), z2.VnS()), "mul z0.s, z1.s, z2.s"); + COMPARE(Mul(z0.VnD(), z1.VnD(), z2.VnD()), "mul z0.d, z1.d, z2.d"); + + CLEANUP(); +} + #undef TEST_ #undef EXP_SIZE #undef INSTR_SIZE diff --git a/deps/v8/test/unittests/assembler/disasm-loong64-unittest.cc b/deps/v8/test/unittests/assembler/disasm-loong64-unittest.cc index e2cd234a67ca..4ef89d88556e 100644 --- a/deps/v8/test/unittests/assembler/disasm-loong64-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-loong64-unittest.cc @@ -29,6 +29,8 @@ #include <stdio.h> #include <stdlib.h> +#include <array> + #include "src/codegen/macro-assembler.h" #include "src/debug/debug.h" #include "src/diagnostics/disasm.h" @@ -46,7 +48,7 @@ using DisasmLoong64Test = TestWithIsolate; bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; /* if (prev_instr_compact_branch) { disasm.InstructionDecode(disasm_buffer, pc); @@ -55,13 +57,13 @@ bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm.InstructionDecode(disasm_buffer, pc); - if (strcmp(compare_string, disasm_buffer.begin()) != 0) { + if (strcmp(compare_string, disasm_buffer.data()) != 0) { fprintf(stderr, "expected: \n" "%s\n" "disassembled: \n" "%s\n\n", - compare_string, disasm_buffer.begin()); + compare_string, disasm_buffer.data()); return false; } return true; diff --git a/deps/v8/test/unittests/assembler/disasm-mips64-unittest.cc b/deps/v8/test/unittests/assembler/disasm-mips64-unittest.cc index 02def4b133b0..ee8a31179e0d 100644 --- a/deps/v8/test/unittests/assembler/disasm-mips64-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-mips64-unittest.cc @@ -28,6 +28,8 @@ #include <stdlib.h> +#include <array> + #include "src/codegen/macro-assembler.h" #include "src/debug/debug.h" #include "src/diagnostics/disasm.h" @@ -47,7 +49,7 @@ bool prev_instr_compact_branch = false; bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; if (prev_instr_compact_branch) { disasm.InstructionDecode(disasm_buffer, pc); @@ -56,13 +58,13 @@ bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm.InstructionDecode(disasm_buffer, pc); - if (strcmp(compare_string, disasm_buffer.begin()) != 0) { + if (strcmp(compare_string, disasm_buffer.data()) != 0) { fprintf(stderr, "expected: \n" "%s\n" "disassembled: \n" "%s\n\n", - compare_string, disasm_buffer.begin()); + compare_string, disasm_buffer.data()); return false; } return true; diff --git a/deps/v8/test/unittests/assembler/disasm-ppc-unittest.cc b/deps/v8/test/unittests/assembler/disasm-ppc-unittest.cc index 95960651ed2d..32a9f70cec77 100644 --- a/deps/v8/test/unittests/assembler/disasm-ppc-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-ppc-unittest.cc @@ -28,6 +28,8 @@ #include <stdlib.h> +#include <array> + #include "src/codegen/macro-assembler.h" #include "src/debug/debug.h" #include "src/diagnostics/disasm.h" @@ -45,17 +47,17 @@ using DisasmPpcTest = TestWithIsolate; bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; disasm.InstructionDecode(disasm_buffer, pc); - if (strcmp(compare_string, disasm_buffer.begin()) != 0) { + if (strcmp(compare_string, disasm_buffer.data()) != 0) { fprintf(stderr, "expected: \n" "%s\n" "disassembled: \n" "%s\n\n", - compare_string, disasm_buffer.begin()); + compare_string, disasm_buffer.data()); return false; } return true; diff --git a/deps/v8/test/unittests/assembler/disasm-riscv-unittest.cc b/deps/v8/test/unittests/assembler/disasm-riscv-unittest.cc index d9eeeb693292..59bd71ad8f03 100644 --- a/deps/v8/test/unittests/assembler/disasm-riscv-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-riscv-unittest.cc @@ -28,6 +28,8 @@ #include <stdlib.h> +#include <array> + #include "src/codegen/macro-assembler.h" #include "src/debug/debug.h" #include "src/diagnostics/disasm.h" @@ -47,7 +49,7 @@ bool prev_instr_compact_branch = false; bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; if (prev_instr_compact_branch) { disasm.InstructionDecode(disasm_buffer, pc); @@ -56,13 +58,13 @@ bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm.InstructionDecode(disasm_buffer, pc); - if (strcmp(compare_string, disasm_buffer.begin()) != 0) { + if (strcmp(compare_string, disasm_buffer.data()) != 0) { fprintf(stderr, "expected: \n" "%s\n" "disassembled: \n" "%s\n\n", - compare_string, disasm_buffer.begin()); + compare_string, disasm_buffer.data()); return false; } return true; diff --git a/deps/v8/test/unittests/assembler/disasm-s390-unittest.cc b/deps/v8/test/unittests/assembler/disasm-s390-unittest.cc index 4cedd7bdcf70..2042dfbefd1e 100644 --- a/deps/v8/test/unittests/assembler/disasm-s390-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-s390-unittest.cc @@ -28,6 +28,8 @@ #include <stdlib.h> +#include <array> + #include "src/codegen/macro-assembler.h" #include "src/debug/debug.h" #include "src/diagnostics/disasm.h" @@ -45,17 +47,17 @@ using DisasmS390Test = TestWithIsolate; bool DisassembleAndCompare(uint8_t* pc, const char* compare_string) { disasm::NameConverter converter; disasm::Disassembler disasm(converter); - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; disasm.InstructionDecode(disasm_buffer, pc); - if (strcmp(compare_string, disasm_buffer.begin()) != 0) { + if (strcmp(compare_string, disasm_buffer.data()) != 0) { fprintf(stderr, "expected: \n" "%s\n" "disassembled: \n" "%s\n\n", - compare_string, disasm_buffer.begin()); + compare_string, disasm_buffer.data()); return false; } return true; diff --git a/deps/v8/test/unittests/assembler/disasm-x64-unittest.cc b/deps/v8/test/unittests/assembler/disasm-x64-unittest.cc index 5c7ecba9f553..c62b2092c5de 100644 --- a/deps/v8/test/unittests/assembler/disasm-x64-unittest.cc +++ b/deps/v8/test/unittests/assembler/disasm-x64-unittest.cc @@ -27,6 +27,8 @@ #include <stdlib.h> +#include <array> + #include "src/base/vector.h" #include "src/codegen/code-factory.h" #include "src/codegen/macro-assembler.h" @@ -79,31 +81,31 @@ TEST_F(DisasmX64Test, AVX512) { disasm::NameConverter converter; disasm::Disassembler d(converter); - v8::base::EmbeddedVector<char, 128> out_buffer; + std::array<char, 128> out_buffer; uint8_t* pc = buffer; int len = d.InstructionDecode(out_buffer, pc); EXPECT_EQ(len, 7); - EXPECT_STREQ(out_buffer.begin(), + EXPECT_STREQ(out_buffer.data(), "62f37d203f0700 vpcmpb k0,ymm16,[rdi],0x0"); pc += len; len = d.InstructionDecode(out_buffer, pc); EXPECT_EQ(len, 4); - EXPECT_STREQ(out_buffer.begin(), "c5fb93c0 kmovd rax,k0"); + EXPECT_STREQ(out_buffer.data(), "c5fb93c0 kmovd rax,k0"); // Verify resilient decoding of malformed vex prefix (prevent out of bounds // read). pc += len; len = d.InstructionDecode(out_buffer, pc); EXPECT_EQ(len, 4); - EXPECT_STREQ(out_buffer.begin(), "c57b93c0 kmovd rax,k0"); + EXPECT_STREQ(out_buffer.data(), "c57b93c0 kmovd rax,k0"); // Verify decoding of upper EVEX AVX-512 register (ymm17) and vector width. pc += len; len = d.InstructionDecode(out_buffer, pc); EXPECT_EQ(len, 7); - EXPECT_STREQ(out_buffer.begin(), + EXPECT_STREQ(out_buffer.data(), "62b37d203fc100 vpcmpb k0,ymm16,ymm17,0x0"); } @@ -115,18 +117,18 @@ TEST_F(DisasmX64Test, EVEXVectorW) { disasm::NameConverter converter; disasm::Disassembler disassembler(converter); - v8::base::EmbeddedVector<char, 128> out_buffer; + std::array<char, 128> out_buffer; uint8_t* pc = buffer; int len = disassembler.InstructionDecode(out_buffer, pc); EXPECT_EQ(len, 6); - EXPECT_STREQ(out_buffer.begin(), + EXPECT_STREQ(out_buffer.data(), "62f17e082ac0 vcvtlsi2ss xmm0,xmm0,rax"); pc += len; len = disassembler.InstructionDecode(out_buffer, pc); EXPECT_EQ(len, 6); - EXPECT_STREQ(out_buffer.begin(), + EXPECT_STREQ(out_buffer.data(), "62f1fe082ac0 vcvtqsi2ss xmm0,xmm0,rax"); } @@ -371,6 +373,7 @@ TEST_F(DisasmX64Test, DisasmX64) { __ mfence(); __ lfence(); __ pause(); + __ stmxcsr(Operand(rsp, 0)); __ ret(0); CodeDesc desc; @@ -400,7 +403,7 @@ struct DisassemblerTester { std::string InstructionDecode() { disasm.InstructionDecode(disasm_buffer, buffer_ + prev_offset); - return std::string{disasm_buffer.begin()}; + return std::string{disasm_buffer.data()}; } int pc_offset() { return assm_.pc_offset(); } @@ -411,7 +414,7 @@ struct DisassemblerTester { Assembler assm_; disasm::NameConverter converter_; disasm::Disassembler disasm; - base::EmbeddedVector<char, 128> disasm_buffer; + std::array<char, 128> disasm_buffer; int prev_offset = 0; }; @@ -791,6 +794,7 @@ TEST_F(DisasmX64Test, DisasmX64CheckOutput) { COMPARE("dfbc8b10270000 fistp_d [rbx+rcx*4+0x2710]", fistp_d(Operand(rbx, rcx, times_4, 10000))); COMPARE("dfe0 fnstsw_ax", fnstsw_ax()); + COMPARE("0fae1c24 stmxcsr [rsp]", stmxcsr(Operand(rsp, 0))); COMPARE("dcc3 fadd st3", fadd(3)); COMPARE("dceb fsub st3", fsub(3)); COMPARE("dccb fmul st3", fmul(3)); @@ -1894,6 +1898,182 @@ TEST_F(DisasmX64Test, DisasmX64CheckOutputAPX) { #endif // V8_ENABLE_APX_F #ifdef V8_ENABLE_AVX10_1 +TEST_F(DisasmX64Test, DisasmX64CheckOutputAVX10FP16) { + DisassemblerTester t; + std::string actual; + CpuFeatureScope fscope(&t.assm_, AVX10_1, + CpuFeatureScope::kDontCheckSupported); + + COMPARE_INSTR("vaddph xmm3,xmm2,xmm1", vaddph(xmm3, xmm2, xmm1)); + COMPARE_INSTR("vaddph ymm3,ymm2,ymm1", vaddph(ymm3, ymm2, ymm1)); + COMPARE_INSTR("vaddph xmm19,xmm18,xmm17", vaddph(xmm19, xmm18, xmm17)); + COMPARE_INSTR("vaddph ymm31,ymm30,ymm29", vaddph(ymm31, ymm30, ymm29)); + COMPARE_INSTR("vaddph xmm3,xmm3,xmm1", vaddph(xmm3, xmm3, xmm1)); + COMPARE_INSTR("vaddph xmm3,xmm2,xmm3", vaddph(xmm3, xmm2, xmm3)); + COMPARE_INSTR("vaddph xmm3,xmm3,xmm3", vaddph(xmm3, xmm3, xmm3)); + COMPARE_INSTR("vaddph ymm3,ymm3,ymm1", vaddph(ymm3, ymm3, ymm1)); + COMPARE_INSTR("vaddph ymm3,ymm2,ymm3", vaddph(ymm3, ymm2, ymm3)); + COMPARE_INSTR("vaddph ymm3,ymm3,ymm3", vaddph(ymm3, ymm3, ymm3)); + COMPARE_INSTR("vaddph xmm3,xmm2,[rbx+0x40]", + vaddph(xmm3, xmm2, Operand(rbx, 64))); + COMPARE_INSTR("vaddph ymm3,ymm2,[rbx+0x80]", + vaddph(ymm3, ymm2, Operand(rbx, 128))); + COMPARE_INSTR("vaddph xmm3,xmm2,[rbx-0x10]", + vaddph(xmm3, xmm2, Operand(rbx, -16))); + COMPARE_INSTR("vaddph ymm3,ymm2,[rbx-0x20]", + vaddph(ymm3, ymm2, Operand(rbx, -32))); + COMPARE_INSTR("vaddph xmm3,xmm2,[rbx+0x14]", + vaddph(xmm3, xmm2, Operand(rbx, 20))); + COMPARE_INSTR("vaddph ymm3,ymm2,[rbx+0x24]", + vaddph(ymm3, ymm2, Operand(rbx, 36))); + COMPARE_INSTR("vaddph xmm3,xmm2,[rbx+0x800]", + vaddph(xmm3, xmm2, Operand(rbx, 2048))); + COMPARE_INSTR("vaddph ymm3,ymm2,[rbx+0x1000]", + vaddph(ymm3, ymm2, Operand(rbx, 4096))); + COMPARE_INSTR("vaddph xmm19,xmm18,[r12+r13*2+0x40]", + vaddph(xmm19, xmm18, Operand(r12, r13, times_2, 64))); + COMPARE_INSTR("vaddph ymm19,ymm18,[r12+r13*2+0x80]", + vaddph(ymm19, ymm18, Operand(r12, r13, times_2, 128))); + Label xmm_label, ymm_label; + t.assm_.bind(&xmm_label); + COMPARE_INSTR("vaddph xmm3,xmm2,[rip+0xfffffff6]", + vaddph(xmm3, xmm2, Operand(&xmm_label))); + t.assm_.bind(&ymm_label); + COMPARE_INSTR("vaddph ymm3,ymm2,[rip+0xfffffff6]", + vaddph(ymm3, ymm2, Operand(&ymm_label))); +} + +TEST_F(DisasmX64Test, DisasmX64CheckOutputAVX10Vsubph) { + DisassemblerTester t; + std::string actual; + CpuFeatureScope fscope(&t.assm_, AVX10_1, + CpuFeatureScope::kDontCheckSupported); + + COMPARE_INSTR("vsubph xmm3,xmm2,xmm1", vsubph(xmm3, xmm2, xmm1)); + COMPARE_INSTR("vsubph ymm3,ymm2,ymm1", vsubph(ymm3, ymm2, ymm1)); + COMPARE_INSTR("vsubph xmm19,xmm18,xmm17", vsubph(xmm19, xmm18, xmm17)); + COMPARE_INSTR("vsubph ymm31,ymm30,ymm29", vsubph(ymm31, ymm30, ymm29)); + COMPARE_INSTR("vsubph xmm3,xmm3,xmm1", vsubph(xmm3, xmm3, xmm1)); + COMPARE_INSTR("vsubph xmm3,xmm2,xmm3", vsubph(xmm3, xmm2, xmm3)); + COMPARE_INSTR("vsubph xmm3,xmm3,xmm3", vsubph(xmm3, xmm3, xmm3)); + COMPARE_INSTR("vsubph ymm3,ymm3,ymm1", vsubph(ymm3, ymm3, ymm1)); + COMPARE_INSTR("vsubph ymm3,ymm2,ymm3", vsubph(ymm3, ymm2, ymm3)); + COMPARE_INSTR("vsubph ymm3,ymm3,ymm3", vsubph(ymm3, ymm3, ymm3)); + COMPARE_INSTR("vsubph xmm3,xmm2,[rbx+0x7f0]", + vsubph(xmm3, xmm2, Operand(rbx, 2032))); + COMPARE_INSTR("vsubph ymm3,ymm2,[rbx+0xfe0]", + vsubph(ymm3, ymm2, Operand(rbx, 4064))); + COMPARE_INSTR("vsubph xmm3,xmm2,[rbx-0x800]", + vsubph(xmm3, xmm2, Operand(rbx, -2048))); + COMPARE_INSTR("vsubph ymm3,ymm2,[rbx-0x1000]", + vsubph(ymm3, ymm2, Operand(rbx, -4096))); + COMPARE_INSTR("vsubph xmm3,xmm2,[rbx+0x14]", + vsubph(xmm3, xmm2, Operand(rbx, 20))); + COMPARE_INSTR("vsubph ymm3,ymm2,[rbx+0x24]", + vsubph(ymm3, ymm2, Operand(rbx, 36))); + COMPARE_INSTR("vsubph xmm3,xmm2,[rbx+0x800]", + vsubph(xmm3, xmm2, Operand(rbx, 2048))); + COMPARE_INSTR("vsubph ymm3,ymm2,[rbx+0x1000]", + vsubph(ymm3, ymm2, Operand(rbx, 4096))); + COMPARE_INSTR("vsubph xmm19,xmm18,[r12+r13*2+0x40]", + vsubph(xmm19, xmm18, Operand(r12, r13, times_2, 64))); + COMPARE_INSTR("vsubph ymm19,ymm18,[r12+r13*2+0x80]", + vsubph(ymm19, ymm18, Operand(r12, r13, times_2, 128))); + Label xmm_label, ymm_label; + t.assm_.bind(&xmm_label); + COMPARE_INSTR("vsubph xmm3,xmm2,[rip+0xfffffff6]", + vsubph(xmm3, xmm2, Operand(&xmm_label))); + t.assm_.bind(&ymm_label); + COMPARE_INSTR("vsubph ymm3,ymm2,[rip+0xfffffff6]", + vsubph(ymm3, ymm2, Operand(&ymm_label))); +} + +TEST_F(DisasmX64Test, DisasmX64CheckOutputAVX10FmaPh) { + DisassemblerTester t; + std::string actual; + CpuFeatureScope fscope(&t.assm_, AVX10_1, + CpuFeatureScope::kDontCheckSupported); + + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,xmm1", vfmadd213ph(xmm3, xmm2, xmm1)); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,ymm1", vfmadd213ph(ymm3, ymm2, ymm1)); + COMPARE_INSTR("vfmadd213ph xmm19,xmm18,xmm17", + vfmadd213ph(xmm19, xmm18, xmm17)); + COMPARE_INSTR("vfmadd213ph ymm31,ymm30,ymm29", + vfmadd213ph(ymm31, ymm30, ymm29)); + COMPARE_INSTR("vfmadd213ph xmm3,xmm3,xmm1", vfmadd213ph(xmm3, xmm3, xmm1)); + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,xmm3", vfmadd213ph(xmm3, xmm2, xmm3)); + COMPARE_INSTR("vfmadd213ph xmm3,xmm3,xmm3", vfmadd213ph(xmm3, xmm3, xmm3)); + COMPARE_INSTR("vfmadd213ph ymm3,ymm3,ymm1", vfmadd213ph(ymm3, ymm3, ymm1)); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,ymm3", vfmadd213ph(ymm3, ymm2, ymm3)); + COMPARE_INSTR("vfmadd213ph ymm3,ymm3,ymm3", vfmadd213ph(ymm3, ymm3, ymm3)); + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,[rbx+0x7f0]", + vfmadd213ph(xmm3, xmm2, Operand(rbx, 2032))); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,[rbx+0xfe0]", + vfmadd213ph(ymm3, ymm2, Operand(rbx, 4064))); + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,[rbx-0x800]", + vfmadd213ph(xmm3, xmm2, Operand(rbx, -2048))); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,[rbx-0x1000]", + vfmadd213ph(ymm3, ymm2, Operand(rbx, -4096))); + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,[rbx+0x14]", + vfmadd213ph(xmm3, xmm2, Operand(rbx, 20))); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,[rbx+0x24]", + vfmadd213ph(ymm3, ymm2, Operand(rbx, 36))); + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,[rbx+0x800]", + vfmadd213ph(xmm3, xmm2, Operand(rbx, 2048))); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,[rbx+0x1000]", + vfmadd213ph(ymm3, ymm2, Operand(rbx, 4096))); + COMPARE_INSTR("vfmadd213ph xmm19,xmm18,[r12+r13*2+0x40]", + vfmadd213ph(xmm19, xmm18, Operand(r12, r13, times_2, 64))); + COMPARE_INSTR("vfmadd213ph ymm19,ymm18,[r12+r13*2+0x80]", + vfmadd213ph(ymm19, ymm18, Operand(r12, r13, times_2, 128))); + Label add_xmm, add_ymm, nadd_xmm, nadd_ymm; + t.assm_.bind(&add_xmm); + COMPARE_INSTR("vfmadd213ph xmm3,xmm2,[rip+0xfffffff6]", + vfmadd213ph(xmm3, xmm2, Operand(&add_xmm))); + t.assm_.bind(&add_ymm); + COMPARE_INSTR("vfmadd213ph ymm3,ymm2,[rip+0xfffffff6]", + vfmadd213ph(ymm3, ymm2, Operand(&add_ymm))); + + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,xmm1", vfnmadd213ph(xmm3, xmm2, xmm1)); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,ymm1", vfnmadd213ph(ymm3, ymm2, ymm1)); + COMPARE_INSTR("vfnmadd213ph xmm19,xmm18,xmm17", + vfnmadd213ph(xmm19, xmm18, xmm17)); + COMPARE_INSTR("vfnmadd213ph ymm31,ymm30,ymm29", + vfnmadd213ph(ymm31, ymm30, ymm29)); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm3,xmm1", vfnmadd213ph(xmm3, xmm3, xmm1)); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,xmm3", vfnmadd213ph(xmm3, xmm2, xmm3)); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm3,xmm3", vfnmadd213ph(xmm3, xmm3, xmm3)); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm3,ymm1", vfnmadd213ph(ymm3, ymm3, ymm1)); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,ymm3", vfnmadd213ph(ymm3, ymm2, ymm3)); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm3,ymm3", vfnmadd213ph(ymm3, ymm3, ymm3)); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,[rbx+0x7f0]", + vfnmadd213ph(xmm3, xmm2, Operand(rbx, 2032))); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,[rbx+0xfe0]", + vfnmadd213ph(ymm3, ymm2, Operand(rbx, 4064))); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,[rbx-0x800]", + vfnmadd213ph(xmm3, xmm2, Operand(rbx, -2048))); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,[rbx-0x1000]", + vfnmadd213ph(ymm3, ymm2, Operand(rbx, -4096))); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,[rbx+0x14]", + vfnmadd213ph(xmm3, xmm2, Operand(rbx, 20))); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,[rbx+0x24]", + vfnmadd213ph(ymm3, ymm2, Operand(rbx, 36))); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,[rbx+0x800]", + vfnmadd213ph(xmm3, xmm2, Operand(rbx, 2048))); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,[rbx+0x1000]", + vfnmadd213ph(ymm3, ymm2, Operand(rbx, 4096))); + COMPARE_INSTR("vfnmadd213ph xmm19,xmm18,[r12+r13*2+0x40]", + vfnmadd213ph(xmm19, xmm18, Operand(r12, r13, times_2, 64))); + COMPARE_INSTR("vfnmadd213ph ymm19,ymm18,[r12+r13*2+0x80]", + vfnmadd213ph(ymm19, ymm18, Operand(r12, r13, times_2, 128))); + t.assm_.bind(&nadd_xmm); + COMPARE_INSTR("vfnmadd213ph xmm3,xmm2,[rip+0xfffffff6]", + vfnmadd213ph(xmm3, xmm2, Operand(&nadd_xmm))); + t.assm_.bind(&nadd_ymm); + COMPARE_INSTR("vfnmadd213ph ymm3,ymm2,[rip+0xfffffff6]", + vfnmadd213ph(ymm3, ymm2, Operand(&nadd_ymm))); +} + TEST_F(DisasmX64Test, DisasmX64CheckOutputAVX10) { DisassemblerTester t; std::string actual; diff --git a/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc b/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc index 2ef1b31f6d55..769398ffa1d4 100644 --- a/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc +++ b/deps/v8/test/unittests/assembler/macro-assembler-arm64-unittest.cc @@ -135,6 +135,42 @@ TEST_F(MacroAssemblerTest, CompareAndBranch) { } } +TEST_F(MacroAssemblerTest, DispatchHandlePoolEntries) { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(isolate(), AssemblerOptions{}, CodeObjectRequired{false}, + buffer->CreateView()); + const uint32_t kHandleA = 0x1200; + const uint32_t kHandleB = 0x3400; + + { + AssemblerBufferWriteScope rw_scope(*buffer); + + __ Mov(w0, Immediate(kHandleA, RelocInfo::JS_DISPATCH_HANDLE)); + __ Mov(w1, Immediate(kHandleA, RelocInfo::JS_DISPATCH_HANDLE)); + __ Mov(w2, Immediate(kHandleB, RelocInfo::JS_DISPATCH_HANDLE)); + + CodeDesc desc; + masm.GetCode(isolate(), &desc); + } + + Instruction* load_a = reinterpret_cast<Instruction*>(buffer->start()); + Instruction* load_a_again = load_a->following(); + Instruction* load_b = load_a_again->following(); + ASSERT_TRUE(load_a->IsLdrLiteralW()); + ASSERT_TRUE(load_a_again->IsLdrLiteralW()); + ASSERT_TRUE(load_b->IsLdrLiteralW()); + EXPECT_EQ(load_a->ImmPCOffsetTarget(), load_a_again->ImmPCOffsetTarget()); + EXPECT_EQ(kHandleA, + *reinterpret_cast<uint32_t*>(load_a->ImmPCOffsetTarget())); + EXPECT_EQ(kHandleB, + *reinterpret_cast<uint32_t*>(load_b->ImmPCOffsetTarget())); + + // The pool holds the guard and one 4-byte entry per handle. + Instruction* marker = load_b->following(); + ASSERT_TRUE(marker->IsLdrLiteralX()); + EXPECT_EQ(3, marker->ImmLLiteral()); +} + struct MoveObjectAndSlotTestCase { const char* comment; Register dst_object; @@ -265,6 +301,40 @@ INSTANTIATE_TEST_SUITE_P(MacroAssemblerTest, MacroAssemblerTestMoveObjectAndSlot, ::testing::ValuesIn(kMoveObjectAndSlotTestCases)); +#ifdef V8_COMPRESS_POINTERS +TEST_F(MacroAssemblerTest, ConstantPoolAlignmentGap) { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(isolate(), AssemblerOptions{}, CodeObjectRequired{false}, + buffer->CreateView()); + Handle<HeapObject> object = isolate()->factory()->undefined_value(); + + { + AssemblerBufferWriteScope rw_scope(*buffer); + + __ Mov(x0, Operand(object)); + __ Mov(w1, Operand(object, RelocInfo::COMPRESSED_EMBEDDED_OBJECT)); + // Start the pool's entries at an offset that is not 8-byte aligned. + __ Nop(); + + CodeDesc desc; + masm.GetCode(isolate(), &desc); + } + + Instruction* load64 = reinterpret_cast<Instruction*>(buffer->start()); + Instruction* load32 = load64->following(); + Instruction* marker = load32->following()->following(); + ASSERT_TRUE(load64->IsLdrLiteralX()); + ASSERT_TRUE(load32->IsLdrLiteralW()); + ASSERT_TRUE(marker->IsLdrLiteralX()); + + // The 32-bit entry fills the alignment gap after the guard. + Instruction* gap = marker->following()->following(); + EXPECT_EQ(gap, load32->ImmPCOffsetTarget()); + EXPECT_EQ(gap->following(), load64->ImmPCOffsetTarget()); + EXPECT_EQ(4, marker->ImmLLiteral()); +} +#endif // V8_COMPRESS_POINTERS + #undef __ } // namespace internal diff --git a/deps/v8/test/unittests/assembler/test-helper-riscv32.h b/deps/v8/test/unittests/assembler/test-helper-riscv32.h index bdfa61ef5758..8229414fce11 100644 --- a/deps/v8/test/unittests/assembler/test-helper-riscv32.h +++ b/deps/v8/test/unittests/assembler/test-helper-riscv32.h @@ -17,7 +17,7 @@ #define PRINT_RES(res, expected_res, in_hex) \ if (in_hex) std::cout << "[hex-form]" << std::hex; \ std::cout << "res = " << (res) << " expected = " << (expected_res) \ - << std::endl; + << std::dec << std::endl; namespace v8 { namespace internal { diff --git a/deps/v8/test/unittests/assembler/test-helper-riscv64.h b/deps/v8/test/unittests/assembler/test-helper-riscv64.h index 56b2972855eb..4b3a8d0e40a4 100644 --- a/deps/v8/test/unittests/assembler/test-helper-riscv64.h +++ b/deps/v8/test/unittests/assembler/test-helper-riscv64.h @@ -14,7 +14,7 @@ #define PRINT_RES(res, expected_res, in_hex) \ if (in_hex) std::cout << "[hex-form]" << std::hex; \ std::cout << "res = " << (res) << " expected = " << (expected_res) \ - << std::endl; + << std::dec << std::endl; namespace v8 { namespace internal { diff --git a/deps/v8/test/unittests/base/bignum-unittest.cc b/deps/v8/test/unittests/base/bignum-unittest.cc index 72acf29e6203..5b011bd1c224 100644 --- a/deps/v8/test/unittests/base/bignum-unittest.cc +++ b/deps/v8/test/unittests/base/bignum-unittest.cc @@ -18,11 +18,11 @@ namespace test_bignum { static const int kBufferSize = 1024; static void AssignHexString(Bignum* bignum, const char* str) { - bignum->AssignHexString(CStrVector(str)); + bignum->AssignHexString(str); } static void AssignDecimalString(Bignum* bignum, const char* str) { - bignum->AssignDecimalString(CStrVector(str)); + bignum->AssignDecimalString(str); } TEST_F(BignumTest, Assign) { diff --git a/deps/v8/test/unittests/base/bits-unittest.cc b/deps/v8/test/unittests/base/bits-unittest.cc index 7f04339af859..413d50e1d60e 100644 --- a/deps/v8/test/unittests/base/bits-unittest.cc +++ b/deps/v8/test/unittests/base/bits-unittest.cc @@ -170,49 +170,6 @@ TEST(Bits, WhichPowerOfTwo64) { } } -TEST(Bits, RoundUpToPowerOfTwo32) { - TRACED_FORRANGE(uint32_t, shift, 0, 31) { - EXPECT_EQ(1u << shift, RoundUpToPowerOfTwo32(1u << shift)); - } - EXPECT_EQ(1u, RoundUpToPowerOfTwo32(0)); - EXPECT_EQ(1u, RoundUpToPowerOfTwo32(1)); - EXPECT_EQ(4u, RoundUpToPowerOfTwo32(3)); - EXPECT_EQ(0x80000000u, RoundUpToPowerOfTwo32(0x7FFFFFFFu)); -} - - -TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo32)) { - ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo32(0x80000001u); }, - ".*heck failed:.* << 31"); -} - -TEST(Bits, RoundUpToPowerOfTwo64) { - TRACED_FORRANGE(uint64_t, shift, 0, 63) { - uint64_t value = uint64_t{1} << shift; - EXPECT_EQ(value, RoundUpToPowerOfTwo64(value)); - } - EXPECT_EQ(uint64_t{1}, RoundUpToPowerOfTwo64(0)); - EXPECT_EQ(uint64_t{1}, RoundUpToPowerOfTwo64(1)); - EXPECT_EQ(uint64_t{4}, RoundUpToPowerOfTwo64(3)); - EXPECT_EQ(uint64_t{1} << 63, RoundUpToPowerOfTwo64((uint64_t{1} << 63) - 1)); - EXPECT_EQ(uint64_t{1} << 63, RoundUpToPowerOfTwo64(uint64_t{1} << 63)); -} - -TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo64)) { - ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo64((uint64_t{1} << 63) + 1); }, - ".*heck failed:.* << 63"); -} - - -TEST(Bits, RoundDownToPowerOfTwo32) { - TRACED_FORRANGE(uint32_t, shift, 0, 31) { - EXPECT_EQ(1u << shift, RoundDownToPowerOfTwo32(1u << shift)); - } - EXPECT_EQ(0u, RoundDownToPowerOfTwo32(0)); - EXPECT_EQ(4u, RoundDownToPowerOfTwo32(5)); - EXPECT_EQ(0x80000000u, RoundDownToPowerOfTwo32(0x80000001u)); -} - TEST(Bits, RotateRight32) { TRACED_FORRANGE(uint32_t, shift, 0, 31) { diff --git a/deps/v8/test/unittests/base/growing-circular-queue-unittest.cc b/deps/v8/test/unittests/base/growing-circular-queue-unittest.cc new file mode 100644 index 000000000000..9899312c126b --- /dev/null +++ b/deps/v8/test/unittests/base/growing-circular-queue-unittest.cc @@ -0,0 +1,187 @@ +// Copyright 2026 the V8 project 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 "src/base/growing-circular-queue.h" + +#include <memory> + +#include "testing/gtest-support.h" + +namespace v8::base { + +TEST(GrowingCircularQueueTest, EmptyAndEnqueueDequeue) { + GrowingCircularQueue<int> queue; + EXPECT_TRUE(queue.empty()); + EXPECT_EQ(0u, queue.size()); + EXPECT_EQ(0u, queue.capacity()); + + queue.Enqueue(10); + EXPECT_FALSE(queue.empty()); + EXPECT_EQ(1u, queue.size()); + EXPECT_EQ(GrowingCircularQueue<int>::kInitialCapacity, queue.capacity()); + EXPECT_EQ(10, queue.Dequeue()); + EXPECT_TRUE(queue.empty()); + EXPECT_EQ(0u, queue.size()); + // Capacity is retained after draining. + EXPECT_EQ(GrowingCircularQueue<int>::kInitialCapacity, queue.capacity()); + + // Enqueuing again reuses the existing buffer without growing. + queue.Enqueue(20); + queue.Enqueue(30); + EXPECT_EQ(2u, queue.size()); + EXPECT_EQ(GrowingCircularQueue<int>::kInitialCapacity, queue.capacity()); + EXPECT_EQ(20, queue.Dequeue()); + EXPECT_EQ(30, queue.Dequeue()); + EXPECT_TRUE(queue.empty()); +} + +TEST(GrowingCircularQueueTest, WrapAroundWithoutGrowing) { + GrowingCircularQueue<int> queue; + constexpr size_t kCap = GrowingCircularQueue<int>::kInitialCapacity; + + // Fill to full capacity and drain repeatedly to exercise wrap-around. + for (int round = 0; round < 5; ++round) { + for (size_t i = 0; i < kCap; ++i) { + queue.Enqueue(static_cast<int>(round * 100 + i)); + } + EXPECT_EQ(kCap, queue.size()); + EXPECT_EQ(kCap, queue.capacity()); + + // Dequeue two, enqueue two (wrapping tail around the end of the buffer). + EXPECT_EQ(round * 100 + 0, queue.Dequeue()); + EXPECT_EQ(round * 100 + 1, queue.Dequeue()); + EXPECT_EQ(kCap - 2, queue.size()); + + queue.Enqueue(round * 100 + 50); + queue.Enqueue(round * 100 + 51); + EXPECT_EQ(kCap, queue.size()); + EXPECT_EQ(kCap, queue.capacity()); + + for (size_t i = 2; i < kCap; ++i) { + EXPECT_EQ(static_cast<int>(round * 100 + i), queue.Dequeue()); + } + EXPECT_EQ(round * 100 + 50, queue.Dequeue()); + EXPECT_EQ(round * 100 + 51, queue.Dequeue()); + EXPECT_TRUE(queue.empty()); + EXPECT_EQ(kCap, queue.capacity()); + } +} + +TEST(GrowingCircularQueueTest, GrowContiguousAndWrapped) { + // 1. Grow when head_ is at buffer_.begin() (contiguous). + { + GrowingCircularQueue<int> queue; + for (int i = 0; i < 20; ++i) { + queue.Enqueue(i); + EXPECT_EQ(static_cast<size_t>(i + 1), queue.size()); + } + EXPECT_GE(queue.capacity(), 20u); + for (int i = 0; i < 20; ++i) { + EXPECT_EQ(i, queue.Dequeue()); + } + EXPECT_TRUE(queue.empty()); + } + + // 2. Grow when head_ > tail_ (wrapped around). + { + GrowingCircularQueue<int> queue; + constexpr int kCap = + static_cast<int>(GrowingCircularQueue<int>::kInitialCapacity); + // Enqueue kCap - 1 elements and dequeue them so head_ advances to index + // kCap - 1. + for (int i = 0; i < kCap - 1; ++i) { + queue.Enqueue(-1); + EXPECT_EQ(-1, queue.Dequeue()); + } + EXPECT_TRUE(queue.empty()); + + // Now enqueue 20 elements; the first growth happens while wrapped around. + for (int i = 0; i < 20; ++i) { + queue.Enqueue(100 + i); + EXPECT_EQ(static_cast<size_t>(i + 1), queue.size()); + } + for (int i = 0; i < 20; ++i) { + EXPECT_EQ(100 + i, queue.Dequeue()); + } + EXPECT_TRUE(queue.empty()); + } +} + +TEST(GrowingCircularQueueTest, MoveOnlyElementsAndClear) { + GrowingCircularQueue<std::unique_ptr<int>> queue; + for (int i = 0; i < 10; ++i) { + queue.Enqueue(std::make_unique<int>(i)); + } + EXPECT_EQ(10u, queue.size()); + + GrowingCircularQueue<std::unique_ptr<int>> moved_queue = std::move(queue); + EXPECT_TRUE(queue.empty()); + EXPECT_EQ(0u, queue.size()); + EXPECT_EQ(0u, queue.capacity()); + EXPECT_EQ(10u, moved_queue.size()); + + for (int i = 0; i < 5; ++i) { + std::unique_ptr<int> val = moved_queue.Dequeue(); + ASSERT_NE(nullptr, val); + EXPECT_EQ(i, *val); + } + EXPECT_EQ(5u, moved_queue.size()); + + moved_queue.Clear(); + EXPECT_TRUE(moved_queue.empty()); + EXPECT_EQ(0u, moved_queue.size()); + + // Reusable after Clear(). + moved_queue.Enqueue(std::make_unique<int>(42)); + EXPECT_EQ(1u, moved_queue.size()); + EXPECT_EQ(42, *moved_queue.Dequeue()); + EXPECT_TRUE(moved_queue.empty()); +} + +namespace { + +template <typename T> +class CountingAllocator { + public: + using value_type = T; + + explicit CountingAllocator(size_t* active_bytes) + : active_bytes_(active_bytes) {} + + T* allocate(size_t n) { + *active_bytes_ += n * sizeof(T); + return std::allocator<T>{}.allocate(n); + } + + void deallocate(T* p, size_t n) noexcept { + *active_bytes_ -= n * sizeof(T); + std::allocator<T>{}.deallocate(p, n); + } + + private: + size_t* active_bytes_; +}; + +} // namespace + +TEST(GrowingCircularQueueTest, CustomAllocator) { + size_t active_bytes = 0; + { + GrowingCircularQueue<int, CountingAllocator<int>> queue{ + CountingAllocator<int>(&active_bytes)}; + EXPECT_EQ(0u, active_bytes); + + for (int i = 0; i < 10; ++i) { + queue.Enqueue(i); + } + EXPECT_EQ(queue.capacity() * sizeof(int), active_bytes); + + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(i, queue.Dequeue()); + } + } + EXPECT_EQ(0u, active_bytes); +} + +} // namespace v8::base diff --git a/deps/v8/test/unittests/base/hashing-unittest.cc b/deps/v8/test/unittests/base/hashing-unittest.cc index 919df5a3dda9..e7bb43731a6b 100644 --- a/deps/v8/test/unittests/base/hashing-unittest.cc +++ b/deps/v8/test/unittests/base/hashing-unittest.cc @@ -6,6 +6,7 @@ #include <limits> #include <set> +#include <span> #include "test/unittests/test-utils.h" @@ -118,6 +119,55 @@ TYPED_TEST(HashingTest, HashValueArrayUsesHashRange) { EXPECT_EQ(hash_range(values, values + arraysize(values)), hash_value(values)); } +TYPED_TEST(HashingTest, HashSpanUsesHashRange) { + TypeParam values[128]; + this->rng()->NextBytes(&values, sizeof(values)); + const size_t expected = hash_range(values, values + arraysize(values)); + + std::span<TypeParam> dynamic_span(values); + std::span<const TypeParam> const_dynamic_span(values); + std::span<TypeParam, 128> static_span(values); + std::span<const TypeParam, 128> const_static_span(values); + + EXPECT_EQ(expected, hash<std::span<TypeParam>>{}(dynamic_span)); + EXPECT_EQ(expected, hash<std::span<const TypeParam>>{}(const_dynamic_span)); + EXPECT_EQ(expected, (hash<std::span<TypeParam, 128>>{}(static_span))); + EXPECT_EQ(expected, + (hash<std::span<const TypeParam, 128>>{}(const_static_span))); + + EXPECT_EQ(expected, hash_value(dynamic_span)); + EXPECT_EQ(expected, hash_value(const_dynamic_span)); + EXPECT_EQ(expected, hash_value(static_span)); + EXPECT_EQ(expected, hash_value(const_static_span)); + + const size_t expected_combined = Hasher{}.AddHash(expected).hash(); + EXPECT_EQ(expected_combined, Hasher::Combine(dynamic_span)); + EXPECT_EQ(expected_combined, Hasher::Combine(const_dynamic_span)); + EXPECT_EQ(expected_combined, Hasher::Combine(static_span)); + EXPECT_EQ(expected_combined, Hasher::Combine(const_static_span)); + + const size_t expected_empty = hash_range(values, values); + std::span<TypeParam> empty_dynamic_span{}; + std::span<const TypeParam> empty_const_dynamic_span{}; + std::span<TypeParam, 0> empty_static_span(values, 0); + + EXPECT_EQ(expected_empty, hash<std::span<TypeParam>>{}(empty_dynamic_span)); + EXPECT_EQ(expected_empty, + hash<std::span<const TypeParam>>{}(empty_const_dynamic_span)); + EXPECT_EQ(expected_empty, + (hash<std::span<TypeParam, 0>>{}(empty_static_span))); + + EXPECT_EQ(expected_empty, hash_value(empty_dynamic_span)); + EXPECT_EQ(expected_empty, hash_value(empty_const_dynamic_span)); + EXPECT_EQ(expected_empty, hash_value(empty_static_span)); + + const size_t expected_empty_combined = + Hasher{}.AddHash(expected_empty).hash(); + EXPECT_EQ(expected_empty_combined, Hasher::Combine(empty_dynamic_span)); + EXPECT_EQ(expected_empty_combined, Hasher::Combine(empty_const_dynamic_span)); + EXPECT_EQ(expected_empty_combined, Hasher::Combine(empty_static_span)); +} + TYPED_TEST(HashingTest, BitEqualTo) { bit_equal_to<TypeParam> pred; for (size_t i = 0; i < 128; ++i) { @@ -166,6 +216,10 @@ TEST(HashingTest, HashUsesArgumentDependentLookup) { hash<Foo> h; Foo foo = {x, y}; EXPECT_EQ(hash_combine(x, y), h(foo)); + std::span<const Foo> foo_span(&foo, 1); + EXPECT_EQ(hash_range(&foo, &foo + 1), + hash<std::span<const Foo>>{}(foo_span)); + EXPECT_EQ(hash_range(&foo, &foo + 1), hash_value(foo_span)); } } } diff --git a/deps/v8/test/unittests/base/platform/mutex-unittest.cc b/deps/v8/test/unittests/base/platform/mutex-unittest.cc index c728ffa81335..0a7b2455bfc1 100644 --- a/deps/v8/test/unittests/base/platform/mutex-unittest.cc +++ b/deps/v8/test/unittests/base/platform/mutex-unittest.cc @@ -21,6 +21,16 @@ TEST(Mutex, LockGuardMutex) { Mutex mutex; { MutexGuard lock_guard(&mutex); } { MutexGuard lock_guard(&mutex); } + { + std::optional<MutexGuard> lock_guard1 = MutexGuard::TryLock(&mutex); + EXPECT_TRUE(lock_guard1.has_value()); + std::optional<MutexGuard> lock_guard2 = MutexGuard::TryLock(&mutex); + EXPECT_FALSE(lock_guard2.has_value()); + } + { + std::optional<MutexGuard> lock_guard = MutexGuard::TryLock(mutex); + EXPECT_TRUE(lock_guard.has_value()); + } } diff --git a/deps/v8/test/unittests/base/small-vector-unittest.cc b/deps/v8/test/unittests/base/small-vector-unittest.cc index bb36b64eeafa..b339e05d0beb 100644 --- a/deps/v8/test/unittests/base/small-vector-unittest.cc +++ b/deps/v8/test/unittests/base/small-vector-unittest.cc @@ -11,6 +11,7 @@ #include <type_traits> #include <vector> +#include "src/base/vector.h" #include "testing/gmock-support.h" namespace v8::base { diff --git a/deps/v8/test/unittests/base/unique-array-unittest.cc b/deps/v8/test/unittests/base/unique-array-unittest.cc new file mode 100644 index 000000000000..713d91d9e867 --- /dev/null +++ b/deps/v8/test/unittests/base/unique-array-unittest.cc @@ -0,0 +1,92 @@ +// Copyright 2026 the V8 project 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 "src/base/unique-array.h" + +#include <algorithm> +#include <span> + +#include "testing/gmock-support.h" + +namespace v8 { +namespace base { + +TEST(UniqueArrayTest, Equals) { + auto int_arr = base::UniqueArray<int>::New(4); + EXPECT_EQ(4u, int_arr.size()); + auto find_non_zero = [](int i) { return i != 0; }; + EXPECT_EQ(int_arr.end(), + std::find_if(int_arr.begin(), int_arr.end(), find_non_zero)); + + constexpr int kInit[] = {4, 11, 3}; + auto init_arr1 = base::UniqueCopyOf(kInit); + // Note: `const int` should also work: We initialize the unique array, but + // afterwards it's non-modifiable. + auto init_arr2 = base::UniqueCopyOf(std::span<const int>(kInit)); + EXPECT_EQ(init_arr1, std::span(kInit)); + EXPECT_EQ(std::span(kInit), init_arr1); + EXPECT_EQ(init_arr1, init_arr2); + EXPECT_EQ(init_arr2, init_arr1); + EXPECT_NE(init_arr1, int_arr); +} + +TEST(UniqueArrayTest, FactoriesAndViews) { + auto fill_arr = base::UniqueArray<int>::New(3, 42); + EXPECT_EQ(3u, fill_arr.size()); + EXPECT_THAT(fill_arr.as_span(), testing::ElementsAre(42, 42, 42)); + + auto const_fill_arr = base::UniqueArray<const int>::New(2, 7); + EXPECT_EQ(2u, const_fill_arr.size()); + EXPECT_THAT(const_fill_arr.as_span(), testing::ElementsAre(7, 7)); + + constexpr int kInit[] = {4, 11, 3}; + auto copied_ptr = base::UniqueArray<int>::CopiedFrom(kInit, 3); + EXPECT_THAT(copied_ptr.as_span(), testing::ElementsAreArray(kInit)); + EXPECT_EQ(copied_ptr, std::span(kInit)); + + auto copied_span = base::UniqueArray<int>::CopiedFrom(std::span(kInit)); + EXPECT_THAT(copied_span.as_span(), testing::ElementsAreArray(kInit)); + EXPECT_EQ(copied_span, std::span(kInit)); + + auto const_copied_span = + base::UniqueArray<const int>::CopiedFrom(std::span(kInit)); + EXPECT_THAT(const_copied_span.as_span(), testing::ElementsAreArray(kInit)); + EXPECT_EQ(const_copied_span, std::span(kInit)); + + auto copy_of_ptr = base::UniqueCopyOf(kInit, 2); + EXPECT_THAT(copy_of_ptr.as_span(), testing::ElementsAre(4, 11)); + + EXPECT_THAT(copied_span.first(2), testing::ElementsAre(4, 11)); + EXPECT_THAT(copied_span.last(2), testing::ElementsAre(11, 3)); + EXPECT_THAT(copied_span.subspan(1), testing::ElementsAre(11, 3)); + EXPECT_THAT(copied_span.subspan(1, 1), testing::ElementsAre(11)); +} + +TEST(UniqueArrayTest, MoveConstructionAndAssignment) { + constexpr int kValues[] = {4, 11, 3}; + auto int_arr = base::UniqueCopyOf(kValues); + EXPECT_EQ(3u, int_arr.size()); + + auto move_constructed_arr = std::move(int_arr); + EXPECT_EQ(move_constructed_arr, std::span(kValues)); + + auto move_assigned_to_empty = base::UniqueArray<int>{}; + move_assigned_to_empty = std::move(move_constructed_arr); + EXPECT_EQ(move_assigned_to_empty, std::span(kValues)); + + auto move_assigned_to_non_empty = base::UniqueArray<int>::New(2); + move_assigned_to_non_empty = std::move(move_assigned_to_empty); + EXPECT_EQ(move_assigned_to_non_empty, std::span(kValues)); + + // All but the last array must be empty (length 0, nullptr data). + EXPECT_TRUE(int_arr.empty()); + EXPECT_TRUE(int_arr.begin() == nullptr); + EXPECT_TRUE(move_constructed_arr.empty()); + EXPECT_TRUE(move_constructed_arr.begin() == nullptr); + EXPECT_TRUE(move_assigned_to_empty.empty()); + EXPECT_TRUE(move_assigned_to_empty.begin() == nullptr); +} + +} // namespace base +} // namespace v8 diff --git a/deps/v8/test/unittests/base/vector-unittest.cc b/deps/v8/test/unittests/base/vector-unittest.cc index 85d70d5623a9..b793c180765a 100644 --- a/deps/v8/test/unittests/base/vector-unittest.cc +++ b/deps/v8/test/unittests/base/vector-unittest.cc @@ -12,28 +12,32 @@ namespace v8 { namespace base { TEST(VectorTest, Factories) { - auto vec = base::CStrVector("foo"); + auto vec = base::OneByteVector("foo"); EXPECT_EQ(3u, vec.size()); EXPECT_EQ(0, memcmp(vec.begin(), "foo", 3)); - vec = base::ArrayVector("foo"); - EXPECT_EQ(4u, vec.size()); - EXPECT_EQ(0, memcmp(vec.begin(), "foo\0", 4)); + auto char_vec = base::ArrayVector("foo"); + EXPECT_EQ(4u, char_vec.size()); + EXPECT_EQ(0, memcmp(char_vec.begin(), "foo\0", 4)); - vec = base::CStrVector("foo\0\0"); + vec = base::OneByteVector("foo\0\0"); EXPECT_EQ(3u, vec.size()); EXPECT_EQ(0, memcmp(vec.begin(), "foo", 3)); - vec = base::CStrVector(""); + vec = base::OneByteVector(""); EXPECT_EQ(0u, vec.size()); - vec = base::CStrVector("\0"); + vec = base::OneByteVector("\0"); EXPECT_EQ(0u, vec.size()); + + vec = base::StaticOneByteVector("foo\0\0"); + EXPECT_EQ(5u, vec.size()); + EXPECT_EQ(0, memcmp(vec.begin(), "foo\0\0", 5)); } // Test operator== and operator!= on different Vector types. TEST(VectorTest, Equals) { - auto foo1 = base::CStrVector("foo"); + auto foo1 = base::VectorOf("foo", 3); auto foo2 = base::ArrayVector("ffoo") + 1; EXPECT_EQ(4u, foo2.size()); // Includes trailing '\0'. foo2.Truncate(foo2.size() - 1); @@ -60,47 +64,6 @@ TEST(VectorTest, Equals) { EXPECT_TRUE(vec3_char != vec1_const_char); } -TEST(OwnedVectorTest, Equals) { - auto int_vec = base::OwnedVector<int>::New(4); - EXPECT_EQ(4u, int_vec.size()); - auto find_non_zero = [](int i) { return i != 0; }; - EXPECT_EQ(int_vec.end(), - std::find_if(int_vec.begin(), int_vec.end(), find_non_zero)); - - constexpr int kInit[] = {4, 11, 3}; - auto init_vec1 = base::OwnedCopyOf(kInit); - // Note: {const int} should also work: We initialize the owned vector, but - // afterwards it's non-modifyable. - auto init_vec2 = base::OwnedCopyOf(base::ArrayVector(kInit)); - EXPECT_EQ(init_vec1.as_vector(), base::ArrayVector(kInit)); - EXPECT_EQ(init_vec1.as_vector(), init_vec2.as_vector()); -} - -TEST(OwnedVectorTest, MoveConstructionAndAssignment) { - constexpr int kValues[] = {4, 11, 3}; - auto int_vec = base::OwnedCopyOf(kValues); - EXPECT_EQ(3u, int_vec.size()); - - auto move_constructed_vec = std::move(int_vec); - EXPECT_EQ(move_constructed_vec.as_vector(), base::ArrayVector(kValues)); - - auto move_assigned_to_empty = base::OwnedVector<int>{}; - move_assigned_to_empty = std::move(move_constructed_vec); - EXPECT_EQ(move_assigned_to_empty.as_vector(), base::ArrayVector(kValues)); - - auto move_assigned_to_non_empty = base::OwnedVector<int>::New(2); - move_assigned_to_non_empty = std::move(move_assigned_to_empty); - EXPECT_EQ(move_assigned_to_non_empty.as_vector(), base::ArrayVector(kValues)); - - // All but the last vector must be empty (length 0, nullptr data). - EXPECT_TRUE(int_vec.empty()); - EXPECT_TRUE(int_vec.begin() == nullptr); - EXPECT_TRUE(move_constructed_vec.empty()); - EXPECT_TRUE(move_constructed_vec.begin() == nullptr); - EXPECT_TRUE(move_assigned_to_empty.empty()); - EXPECT_TRUE(move_assigned_to_empty.begin() == nullptr); -} - // Test that the constexpr factory methods work. TEST(VectorTest, ConstexprFactories) { static constexpr int kInit1[] = {4, 11, 3}; @@ -111,11 +74,112 @@ TEST(VectorTest, ConstexprFactories) { static constexpr auto kVec2 = base::VectorOf(kInit1, 2); static_assert(kVec2.size() == 2); EXPECT_THAT(kVec2, testing::ElementsAre(4, 11)); +} + +TEST(VectorTest, SpanConversion) { + int arr[] = {1, 2, 3}; + std::span<int, 3> static_span(arr); + std::span<int> dynamic_span(arr); + + base::Vector<int> vec_from_static = static_span; + base::Vector<int> vec_from_dynamic = dynamic_span; + base::Vector<const int> const_vec_from_mutable_span = dynamic_span; + EXPECT_EQ(vec_from_static, vec_from_dynamic); + EXPECT_EQ(vec_from_dynamic, const_vec_from_mutable_span); + + std::span<int> span_from_vec = vec_from_dynamic; + std::span<const int> const_span_from_vec = vec_from_dynamic; + std::span<int> explicit_span_from_vec = + static_cast<std::span<int>>(vec_from_dynamic); + std::span<const int> explicit_const_span_from_vec = + static_cast<std::span<const int>>(vec_from_dynamic); + std::span s(vec_from_dynamic); + static_assert(std::is_same_v<decltype(s), std::span<int>>); + const base::Vector<int> const_vec_of_mutable = dynamic_span; + std::span<int> span_from_const_vec = const_vec_of_mutable; + EXPECT_EQ(span_from_vec.data(), arr); + EXPECT_EQ(span_from_vec.size(), 3u); + EXPECT_EQ(const_span_from_vec.data(), arr); + EXPECT_EQ(const_span_from_vec.size(), 3u); + EXPECT_EQ(explicit_span_from_vec.data(), arr); + EXPECT_EQ(explicit_span_from_vec.size(), 3u); + EXPECT_EQ(explicit_const_span_from_vec.data(), arr); + EXPECT_EQ(explicit_const_span_from_vec.size(), 3u); + EXPECT_EQ(s.data(), arr); + EXPECT_EQ(s.size(), 3u); + EXPECT_EQ(span_from_const_vec.data(), arr); + EXPECT_EQ(span_from_const_vec.size(), 3u); +} + +TEST(VectorTest, SpanCompatibleMethods) { + static constexpr int kArr[] = {10, 20, 30, 40, 50}; + static constexpr auto kVec = base::ArrayVector(kArr); + + static_assert(kVec.front() == 10); + static_assert(kVec.back() == 50); + + static constexpr auto kFirst2 = kVec.first(2); + static_assert(kFirst2.size() == 2); + static_assert(kFirst2.front() == 10); + static_assert(kFirst2.back() == 20); + EXPECT_THAT(kFirst2, testing::ElementsAre(10, 20)); + EXPECT_EQ(kVec.first(5), kVec); + EXPECT_TRUE(kVec.first(0).empty()); + + static constexpr auto kLast2 = kVec.last(2); + static_assert(kLast2.size() == 2); + static_assert(kLast2.front() == 40); + static_assert(kLast2.back() == 50); + EXPECT_THAT(kLast2, testing::ElementsAre(40, 50)); + EXPECT_EQ(kVec.last(5), kVec); + EXPECT_TRUE(kVec.last(0).empty()); + + static constexpr auto kSubFrom2 = kVec.subspan(2); + static_assert(kSubFrom2.size() == 3); + static_assert(kSubFrom2.front() == 30); + static_assert(kSubFrom2.back() == 50); + EXPECT_THAT(kSubFrom2, testing::ElementsAre(30, 40, 50)); + EXPECT_EQ(kVec.subspan(0), kVec); + EXPECT_TRUE(kVec.subspan(5).empty()); + + static constexpr auto kSubMiddle = kVec.subspan(1, 3); + static_assert(kSubMiddle.size() == 3); + static_assert(kSubMiddle.front() == 20); + static_assert(kSubMiddle.back() == 40); + EXPECT_THAT(kSubMiddle, testing::ElementsAre(20, 30, 40)); + EXPECT_EQ(kVec.subspan(0, 5), kVec); + EXPECT_TRUE(kVec.subspan(2, 0).empty()); + EXPECT_TRUE(kVec.subspan(5, 0).empty()); + EXPECT_TRUE(base::Vector<int>{}.subspan(0, 0).empty()); + + int mutable_arr[] = {1, 2, 3}; + base::Vector<int> mutable_vec = base::ArrayVector(mutable_arr); + mutable_vec.front() = 100; + mutable_vec.back() = 300; + EXPECT_THAT(mutable_vec, testing::ElementsAre(100, 2, 300)); + + const base::Vector<int> const_mutable_vec = mutable_vec; + const_mutable_vec.front() = 10; + const_mutable_vec.back() = 30; + EXPECT_THAT(mutable_vec, testing::ElementsAre(10, 2, 30)); +} - static constexpr const char kInit3[] = "foobar"; - static constexpr auto kVec3 = base::StaticCharVector(kInit3); - static_assert(kVec3.size() == 6); - EXPECT_THAT(kVec3, testing::ElementsAreArray(kInit3, kInit3 + 6)); +TEST(VectorTest, ArrayConversion) { + std::array<int, 3> arr = {1, 2, 3}; + const std::array<int, 3> const_arr = {1, 2, 3}; + + base::Vector<int> vec_from_arr = arr; + base::Vector<const int> const_vec_from_arr = arr; + base::Vector<const int> const_vec_from_const_arr = const_arr; + + EXPECT_EQ(vec_from_arr.data(), arr.data()); + EXPECT_EQ(vec_from_arr.size(), 3u); + EXPECT_EQ(const_vec_from_arr.data(), arr.data()); + EXPECT_EQ(const_vec_from_arr.size(), 3u); + EXPECT_EQ(const_vec_from_const_arr.data(), const_arr.data()); + EXPECT_EQ(const_vec_from_const_arr.size(), 3u); + EXPECT_EQ(vec_from_arr, const_vec_from_arr); + EXPECT_EQ(const_vec_from_arr, const_vec_from_const_arr); } } // namespace base diff --git a/deps/v8/test/unittests/codegen/aligned-slot-allocator-unittest.cc b/deps/v8/test/unittests/codegen/aligned-slot-allocator-unittest.cc index 3b04f7888ac6..f03f5042be57 100644 --- a/deps/v8/test/unittests/codegen/aligned-slot-allocator-unittest.cc +++ b/deps/v8/test/unittests/codegen/aligned-slot-allocator-unittest.cc @@ -4,7 +4,8 @@ #include "src/codegen/aligned-slot-allocator.h" -#include "src/base/bits.h" +#include <bit> + #include "testing/gtest-support.h" namespace v8 { @@ -22,8 +23,7 @@ class AlignedSlotAllocatorUnitTest : public ::testing::Test { EXPECT_EQ(next, result); // NextSlot/Allocate are consistent. EXPECT_EQ(expected, result); EXPECT_EQ(0, result & (size - 1)); // result is aligned to size. - int slot_end = result + static_cast<int>(base::bits::RoundUpToPowerOfTwo32( - static_cast<uint32_t>(size))); + int slot_end = result + std::bit_ceil<uint32_t>(size); EXPECT_LE(slot_end, allocator_.Size()); // allocator Size is beyond slot. } diff --git a/deps/v8/test/unittests/codegen/safepoint-table-unittest.cc b/deps/v8/test/unittests/codegen/safepoint-table-unittest.cc index 972b446f6a34..631158e73981 100644 --- a/deps/v8/test/unittests/codegen/safepoint-table-unittest.cc +++ b/deps/v8/test/unittests/codegen/safepoint-table-unittest.cc @@ -4,6 +4,7 @@ #include "src/codegen/safepoint-table.h" +#include "src/base/unique-array.h" #include "src/codegen/macro-assembler.h" #include "test/unittests/fuzztest.h" #include "test/unittests/test-utils.h" @@ -320,12 +321,9 @@ TEST_F(SafepointTableTest, Bigger) { TEST_F(SafepointTableTest, DecodeSafepointEntry) { static constexpr size_t kSize = 16; // Bytes. Enough for this test. - base::OwnedVector<uint8_t> safepoint(std::make_unique<uint8_t[]>(kSize), - kSize); - base::OwnedVector<uint8_t> tagged_slots(std::make_unique<uint8_t[]>(kSize), - kSize); - base::OwnedVector<uint8_t> expected_vector(std::make_unique<uint8_t[]>(kSize), - kSize); + auto safepoint = base::UniqueArray<uint8_t>::New(kSize); + auto tagged_slots = base::UniqueArray<uint8_t>::New(kSize); + auto expected_vector = base::UniqueArray<uint8_t>::New(kSize); auto Test = [&](std::initializer_list<uint8_t> input, std::initializer_list<uint8_t> expected) { std::copy(input.begin(), input.end(), safepoint.data()); diff --git a/deps/v8/test/unittests/common/thread-isolation-unittest.cc b/deps/v8/test/unittests/common/thread-isolation-unittest.cc index 78b5deec12be..64dd6a8eef44 100644 --- a/deps/v8/test/unittests/common/thread-isolation-unittest.cc +++ b/deps/v8/test/unittests/common/thread-isolation-unittest.cc @@ -170,5 +170,62 @@ TEST(ThreadIsolation, InvalidFreeRange) { ThreadIsolation::UnregisterJitPage(address1, size); } +TEST(ThreadIsolation, TryLookupStartOfJitAllocationAt) { + InitializeThreadIsolation(); + + Address address1 = 0x4100000; + size_t size = 0x1000; + Address address2 = address1 + 2 * size; + ThreadIsolation::RegisterJitPage(address1, size); + ThreadIsolation::RegisterJitPage(address2, size); + + Address alloc1 = address1 + 0x100; + size_t alloc1_size = 0x80; + ThreadIsolation::RegisterJitAllocationForTesting(alloc1, alloc1_size); + + Address alloc2 = address2 + 0x200; + size_t alloc2_size = 0x40; + ThreadIsolation::RegisterJitAllocationForTesting(alloc2, alloc2_size); + + // Outside any JIT page. + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(address1 - 1), + std::nullopt); + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(address1 + size), + std::nullopt); + + // Inside JIT page 1, outside alloc1. + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(address1), + std::nullopt); + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc1 - 1), + std::nullopt); + EXPECT_EQ( + ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc1 + alloc1_size), + std::nullopt); + + // Inside alloc1. + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc1), alloc1); + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc1 + 1), + alloc1); + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc1 + + alloc1_size - 1), + alloc1); + + // While page 1 is locked (e.g., on the interrupted thread), looking up on + // page 1 returns std::nullopt instead of deadlocking, while looking up on + // page 2 still succeeds. + { + WritableJitPage locked_page1(address1, size); + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc1), + std::nullopt); + EXPECT_EQ(ThreadIsolation::TryLookupStartOfJitAllocationAt(alloc2 + 10), + alloc2); + } + + ThreadIsolation::UnregisterJitAllocationForTesting(alloc1, alloc1_size); + ThreadIsolation::UnregisterJitAllocationForTesting(alloc2, alloc2_size); + ThreadIsolation::UnregisterJitPage(address1, size); + ThreadIsolation::UnregisterJitPage(address2, size); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/arm/turboshaft-instruction-selector-arm-unittest.cc b/deps/v8/test/unittests/compiler/arm/turboshaft-instruction-selector-arm-unittest.cc index 720bd09c06ba..bde4f0bae0c8 100644 --- a/deps/v8/test/unittests/compiler/arm/turboshaft-instruction-selector-arm-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm/turboshaft-instruction-selector-arm-unittest.cc @@ -146,6 +146,11 @@ TEST_P(TurboshaftInstructionSelectorDPITest, Immediate) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Emit(dpi.op, m.Parameter(0), m.Int32Constant(imm))); Stream s = m.Build(); + if (imm == 0 && + (dpi.op == TSBinop::kWord32Add || dpi.op == TSBinop::kWord32Sub)) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); @@ -157,6 +162,10 @@ TEST_P(TurboshaftInstructionSelectorDPITest, Immediate) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Emit(dpi.op, m.Int32Constant(imm), m.Parameter(0))); Stream s = m.Build(); + if (imm == 0 && dpi.op == TSBinop::kWord32Add) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode()); EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); @@ -260,8 +269,14 @@ TEST_P(TurboshaftInstructionSelectorDPITest, BranchWithImmediate) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); - EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + if (imm == 0 && + (dpi.op == TSBinop::kWord32Add || dpi.op == TSBinop::kWord32Sub)) { + EXPECT_EQ(kArmTst, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + } else { + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + } EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); } @@ -276,8 +291,13 @@ TEST_P(TurboshaftInstructionSelectorDPITest, BranchWithImmediate) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); - EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + if (imm == 0 && dpi.op == TSBinop::kWord32Add) { + EXPECT_EQ(kArmTst, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode()); + } else { + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); + } EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); } @@ -429,7 +449,11 @@ TEST_P(TurboshaftInstructionSelectorDPITest, BranchIfZeroWithImmediate) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + if (imm == 0 && dpi.op == TSBinop::kWord32Add) { + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + } else { + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + } EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kEqual, s[0]->flags_condition()); @@ -446,7 +470,11 @@ TEST_P(TurboshaftInstructionSelectorDPITest, BranchIfZeroWithImmediate) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + if (imm == 0 && dpi.op == TSBinop::kWord32Add) { + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + } else { + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + } EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kEqual, s[0]->flags_condition()); @@ -468,7 +496,11 @@ TEST_P(TurboshaftInstructionSelectorDPITest, BranchIfNotZeroWithImmediate) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + if (imm == 0 && dpi.op == TSBinop::kWord32Add) { + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + } else { + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + } EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); @@ -486,7 +518,11 @@ TEST_P(TurboshaftInstructionSelectorDPITest, BranchIfNotZeroWithImmediate) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + if (imm == 0 && dpi.op == TSBinop::kWord32Add) { + EXPECT_EQ(kArmCmp, s[0]->arch_opcode()); + } else { + EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode()); + } EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); diff --git a/deps/v8/test/unittests/compiler/arm64/turboshaft-instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/turboshaft-instruction-selector-arm64-unittest.cc index 03b0eced4c84..d838f0eb3407 100644 --- a/deps/v8/test/unittests/compiler/arm64/turboshaft-instruction-selector-arm64-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm64/turboshaft-instruction-selector-arm64-unittest.cc @@ -477,6 +477,10 @@ TEST_P(TurboshaftInstructionSelectorAddSubTest, ImmediateOnRight) { StreamBuilder m(this, type, type); m.Return(m.Emit(dpi.mi.op, m.Parameter(0), BuildConstant(&m, type, imm))); Stream s = m.Build(); + if (imm == 0) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); ASSERT_EQ(2U, s[0]->InputCount()); @@ -645,6 +649,10 @@ TEST_F(TurboshaftInstructionSelectorTest, AddImmediateOnLeft) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32Add(m.Int32Constant(imm), m.Parameter(0))); Stream s = m.Build(); + if (imm == 0) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); ASSERT_EQ(2U, s[0]->InputCount()); @@ -658,6 +666,10 @@ TEST_F(TurboshaftInstructionSelectorTest, AddImmediateOnLeft) { StreamBuilder m(this, MachineType::Int64(), MachineType::Int64()); m.Return(m.Word64Add(m.Int64Constant(imm), m.Parameter(0))); Stream s = m.Build(); + if (imm == 0) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); ASSERT_EQ(2U, s[0]->InputCount()); @@ -1123,7 +1135,8 @@ TEST_F(TurboshaftInstructionSelectorTest, AddBranchWithImmediateOnRight) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); + EXPECT_EQ((imm == 0) ? kArm64CompareAndBranch32 : kArm64Cmn32, + s[0]->arch_opcode()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); } @@ -1207,7 +1220,8 @@ TEST_F(TurboshaftInstructionSelectorTest, AddBranchWithImmediateOnLeft) { m.Return(m.Int32Constant(0)); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode()); + EXPECT_EQ((imm == 0) ? kArm64CompareAndBranch32 : kArm64Cmn32, + s[0]->arch_opcode()); ASSERT_LE(1U, s[0]->InputCount()); EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); EXPECT_EQ(kNotEqual, s[0]->flags_condition()); @@ -3463,6 +3477,33 @@ TEST_F(TurboshaftInstructionSelectorTest, AddReduce) { } } +TEST_F(TurboshaftInstructionSelectorTest, I64x2MulSVE2) { + if (!CpuFeatures::IsSupported(SVE2) || + CpuFeatures::svevlen() != kSimd128Size) { + GTEST_SKIP() << "Requires a 128-bit SVE vector-length"; + } + + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + V<Simd128> lhs = m.Parameter<Simd128>(0); + V<Simd128> rhs = m.Parameter<Simd128>(1); + V<Simd128> prod = m.Simd128Binop(lhs, rhs, Simd128BinopOp::Kind::kI64x2Mul); + m.Return(prod); + Stream s = m.Build(SVE2); + + ASSERT_EQ(1U, s.size()); + + EXPECT_EQ(kArm64IMul, s[0]->arch_opcode()); + EXPECT_EQ(64, LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(lhs), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(rhs), s.ToVreg(s[0]->InputAt(1))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(prod), s.ToVreg(s[0]->Output())); + + return; +} + TEST_F(TurboshaftInstructionSelectorTest, I64x2Mul) { StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), MachineType::Simd128()); @@ -3518,6 +3559,59 @@ TEST_F(TurboshaftInstructionSelectorTest, I64x2Mul) { EXPECT_EQ(s.ToVreg(prod), s.ToVreg(s[6]->Output())); } +TEST_F(TurboshaftInstructionSelectorTest, I64x2MulMixedSignExtensions) { + using Kind = Simd128UnaryOp::Kind; + for (bool high : {false, true}) { + for (bool swap_operands : {false, true}) { + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + V<Simd128> signed_input = m.Parameter(0); + V<Simd128> unsigned_input = m.Parameter(1); + V<Simd128> signed_ext = + m.Simd128Unary(signed_input, high ? Kind::kI64x2SConvertI32x4High + : Kind::kI64x2SConvertI32x4Low); + V<Simd128> unsigned_ext = + m.Simd128Unary(unsigned_input, high ? Kind::kI64x2UConvertI32x4High + : Kind::kI64x2UConvertI32x4Low); + V<Simd128> product = swap_operands ? m.I64x2Mul(unsigned_ext, signed_ext) + : m.I64x2Mul(signed_ext, unsigned_ext); + m.Return(product); + Stream s = m.Build(); + + ASSERT_EQ(4U, s.size()); + + EXPECT_EQ(kArm64IShrS, s[0]->arch_opcode()); + EXPECT_EQ(32, LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(unsigned_input), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(31, s.ToInt32(s[0]->InputAt(1))); + + EXPECT_EQ(kArm64S128And, s[1]->arch_opcode()); + ASSERT_EQ(2U, s[1]->InputCount()); + ASSERT_EQ(1U, s[1]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(signed_input), s.ToVreg(s[1]->InputAt(1))); + + EXPECT_EQ(high ? kArm64IShll2 : kArm64IShll, s[2]->arch_opcode()); + EXPECT_EQ(64, LaneSizeBits(LaneSizeField::decode(s[2]->opcode()))); + ASSERT_EQ(1U, s[2]->InputCount()); + ASSERT_EQ(1U, s[2]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(0))); + + EXPECT_EQ(high ? kArm64Smlal2 : kArm64Smlal, s[3]->arch_opcode()); + EXPECT_EQ(64, LaneSizeBits(LaneSizeField::decode(s[3]->opcode()))); + ASSERT_EQ(3U, s[3]->InputCount()); + ASSERT_EQ(1U, s[3]->OutputCount()); + EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0))); + EXPECT_EQ(s.ToVreg(signed_input), s.ToVreg(s[3]->InputAt(1))); + EXPECT_EQ(s.ToVreg(unsigned_input), s.ToVreg(s[3]->InputAt(2))); + EXPECT_EQ(s.ToVreg(product), s.ToVreg(s[3]->Output())); + EXPECT_TRUE(s.IsSameAsInput(s[3]->Output(), 0)); + } + } +} + TEST_F(TurboshaftInstructionSelectorTest, ExtractLaneZero) { { StreamBuilder m(this, MachineType::Float32(), MachineType::Simd128()); @@ -3645,6 +3739,125 @@ TEST_F(TurboshaftInstructionSelectorTest, I32x4AddPairwise) { namespace { +struct HalvingAddTestCase { + const char* halving_add_name; + Simd128BinopOp::Kind add_kind; + Simd128ShiftOp::Kind shift_kind; + LaneSize lane_size; + int lane_bits; + ArchOpcode expected_opcode; +}; + +constexpr HalvingAddTestCase kHalvingAddCases[] = { + {"i8x16_signed", Simd128BinopOp::Kind::kI8x16Add, + Simd128ShiftOp::Kind::kI8x16ShrS, LaneSize::kL8, 8, kArm64Shadd}, + {"i8x16_unsigned", Simd128BinopOp::Kind::kI8x16Add, + Simd128ShiftOp::Kind::kI8x16ShrU, LaneSize::kL8, 8, kArm64Uhadd}, + {"i16x8_signed", Simd128BinopOp::Kind::kI16x8Add, + Simd128ShiftOp::Kind::kI16x8ShrS, LaneSize::kL16, 16, kArm64Shadd}, + {"i16x8_unsigned", Simd128BinopOp::Kind::kI16x8Add, + Simd128ShiftOp::Kind::kI16x8ShrU, LaneSize::kL16, 16, kArm64Uhadd}, + {"i32x4_signed", Simd128BinopOp::Kind::kI32x4Add, + Simd128ShiftOp::Kind::kI32x4ShrS, LaneSize::kL32, 32, kArm64Shadd}, + {"i32x4_unsigned", Simd128BinopOp::Kind::kI32x4Add, + Simd128ShiftOp::Kind::kI32x4ShrU, LaneSize::kL32, 32, kArm64Uhadd}, +}; + +} // namespace + +TEST_F(TurboshaftInstructionSelectorTest, Simd128HalvingAddWithXor) { + // Test signed and unsigned-shift half-add for 16x8, 8x16 and 4x32-bit lanes + for (const HalvingAddTestCase& c : kHalvingAddCases) { + SCOPED_TRACE(c.halving_add_name); + // Use ADD|XOR|AND bits to show which order the operands are in + // (a & b) + ((a ^ b) >> 1) has 8 possible commutations for the 3 operations + for (int comms = 0; comms < 8; ++comms) { + SCOPED_TRACE(comms); + // Test for the 3 shifts that are 1 when modulo the lane width + for (int shift : {1, c.lane_bits + 1, 1 - c.lane_bits}) { + SCOPED_TRACE(shift); + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + + OpIndex lhs = m.Parameter(0); + OpIndex rhs = m.Parameter(1); + + OpIndex and_lhs = (comms & 1) ? rhs : lhs; + OpIndex and_rhs = (comms & 1) ? lhs : rhs; + OpIndex xor_lhs = (comms & 2) ? rhs : lhs; + OpIndex xor_rhs = (comms & 2) ? lhs : rhs; + + // Check the AND, XOR and ADD operand orderings + V<Simd128> and_node = + m.Simd128Binop(and_lhs, and_rhs, Simd128BinopOp::Kind::kS128And); + V<Simd128> xor_node = + m.Simd128Binop(xor_lhs, xor_rhs, Simd128BinopOp::Kind::kS128Xor); + V<Simd128> shift_node = m.Simd128Shift( + xor_node, m.Word32Constant(static_cast<uint32_t>(shift)), + c.shift_kind); + V<Simd128> result = + (comms & 4) ? m.Simd128Binop(shift_node, and_node, c.add_kind) + : m.Simd128Binop(and_node, shift_node, c.add_kind); + m.Return(result); + + Stream s = m.Build(); + + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(c.expected_opcode, s[0]->arch_opcode()); + EXPECT_EQ(c.lane_size, LaneSizeField::decode(s[0]->opcode())); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + + EXPECT_EQ(s.ToVreg(and_lhs), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(and_rhs), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(result), s.ToVreg(s[0]->OutputAt(0))); + } + } + } +} + +TEST_F(TurboshaftInstructionSelectorTest, + Simd128HalvingAddWithMismatchedOperands) { + // Test that sharing even one operand should avoid a half-add optimization. + for (const HalvingAddTestCase& c : kHalvingAddCases) { + SCOPED_TRACE(c.halving_add_name); + // Make the shared input either lhs (0) or rhs (1). + for (int shared_input : {0, 1}) { + SCOPED_TRACE(shared_input); + for (int comms = 0; comms < 8; ++comms) { + SCOPED_TRACE(comms); + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128(), MachineType::Simd128()); + OpIndex lhs = m.Parameter(0); + OpIndex rhs = m.Parameter(1); + OpIndex other = m.Parameter(2); + OpIndex shared = m.Parameter(shared_input); + + V<Simd128> and_node = + m.Simd128Binop((comms & 1) ? rhs : lhs, (comms & 1) ? lhs : rhs, + Simd128BinopOp::Kind::kS128And); + V<Simd128> xor_node = m.Simd128Binop((comms & 2) ? other : shared, + (comms & 2) ? shared : other, + Simd128BinopOp::Kind::kS128Xor); + V<Simd128> shift_node = + m.Simd128Shift(xor_node, m.Word32Constant(1), c.shift_kind); + m.Return((comms & 4) + ? m.Simd128Binop(shift_node, and_node, c.add_kind) + : m.Simd128Binop(and_node, shift_node, c.add_kind)); + + Stream s = m.Build(); + ASSERT_GT(s.size(), 0U); + for (size_t i = 0; i < s.size(); ++i) { + EXPECT_NE(kArm64Shadd, s[i]->arch_opcode()); + EXPECT_NE(kArm64Uhadd, s[i]->arch_opcode()); + } + } + } + } +} + +namespace { + struct SIMDMulDPInst { const char* mul_constructor_name; TSBinop mul_operator; @@ -4108,6 +4321,35 @@ struct S128ShuffleInst { const std::array<uint8_t, kSimd128Size> shuffle; }; +void ExpectS128Tbl1Sequence(const TurboshaftInstructionSelectorTest::Stream& s, + size_t start, OpIndex input, int32_t expected_imm0, + int32_t expected_imm1, int32_t expected_imm2, + int32_t expected_imm3) { + ASSERT_LE(start + 2, s.size()); + + EXPECT_EQ(kArm64S128Const, s[start]->arch_opcode()); + EXPECT_EQ(4U, s[start]->InputCount()); + EXPECT_EQ(1U, s[start]->OutputCount()); + EXPECT_EQ(expected_imm0, s.ToInt32(s[start]->InputAt(0))); + EXPECT_EQ(expected_imm1, s.ToInt32(s[start]->InputAt(1))); + EXPECT_EQ(expected_imm2, s.ToInt32(s[start]->InputAt(2))); + EXPECT_EQ(expected_imm3, s.ToInt32(s[start]->InputAt(3))); + + EXPECT_EQ(kArm64S128Tbl1, s[start + 1]->arch_opcode()); + EXPECT_EQ(2U, s[start + 1]->InputCount()); + EXPECT_EQ(1U, s[start + 1]->OutputCount()); + EXPECT_EQ(s.ToVreg(input), s.ToVreg(s[start + 1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[start]->Output()), s.ToVreg(s[start + 1]->InputAt(1))); +} + +void ExpectS128Tbl1SequenceWith64BitMask( + const TurboshaftInstructionSelectorTest::Stream& s, size_t start, + OpIndex input, int64_t expected_mask) { + int32_t mask_lo = static_cast<int32_t>(expected_mask); + int32_t mask_hi = static_cast<int32_t>(expected_mask >> 32); + ExpectS128Tbl1Sequence(s, start, input, mask_lo, mask_hi, mask_lo, mask_hi); +} + std::ostream& operator<<(std::ostream& os, const S128ShuffleInst& inst) { return os << inst.constructor_name << (inst.lane_size > 0 ? "." + std::to_string(inst.lane_size) : ""); @@ -4128,10 +4370,6 @@ const S128ShuffleInst kShuffles[] = { kArm64S128UnzipRight, 64, {{8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31}}}, - {"kArm64S32x4Shuffle", - kArm64S32x4Shuffle, - 0, - {{0, 1, 2, 3, 16, 17, 18, 19, 16, 17, 18, 19, 20, 21, 22, 23}}}, {"kArm64S128Rev32", kArm64S128Rev32, 8, // 8x4Reverse @@ -5250,11 +5488,9 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle8x4Test) { m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(1), Simd128ShuffleOp::Kind::kI8x4, shuffle)); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64I8x16Shuffle, s[0]->arch_opcode()); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s.size()); + ExpectS128Tbl1Sequence(s, 0, m.Parameter(0), 0x04080705, 0x04080705, + 0x04080705, 0x04080705); } { const uint8_t shuffle[] = { @@ -5267,11 +5503,9 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle8x4Test) { m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(1), Simd128ShuffleOp::Kind::kI8x4, shuffle)); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64I8x16Shuffle, s[0]->arch_opcode()); - EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s.size()); + ExpectS128Tbl1Sequence(s, 0, m.Parameter(1), 0x09060300, 0x09060300, + 0x09060300, 0x09060300); } { const uint8_t shuffle[] = { @@ -5284,14 +5518,105 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle8x4Test) { m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(0), Simd128ShuffleOp::Kind::kI8x4, shuffle)); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64I8x16Shuffle, s[0]->arch_opcode()); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(3U, s.size()); + EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode()); + EXPECT_EQ(8, LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(m.Parameter(0))); + EXPECT_EQ(s.ToInt32(s[0]->InputAt(1)), 0); + EXPECT_EQ(kArm64S128MoveLane, s[1]->arch_opcode()); + EXPECT_EQ(8, LaneSizeBits(LaneSizeField::decode(s[1]->opcode()))); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[0]->Output())); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(1)), s.ToVreg(m.Parameter(0))); + EXPECT_EQ(s.ToInt32(s[1]->InputAt(2)), 8); + EXPECT_EQ(kArm64S128MoveLane, s[2]->arch_opcode()); + EXPECT_EQ(8, LaneSizeBits(LaneSizeField::decode(s[2]->opcode()))); + EXPECT_EQ(s.ToVreg(s[2]->InputAt(0)), s.ToVreg(s[1]->Output())); + EXPECT_EQ(s.ToVreg(s[2]->InputAt(1)), s.ToVreg(m.Parameter(0))); + EXPECT_EQ(s.ToInt32(s[2]->InputAt(2)), 8); + EXPECT_EQ(1U, s[2]->OutputCount()); } } +namespace { + +struct AddSubHighNarrowConvertConfig { + const char* name; + TSBinop operation; + int lane_size; + TSBinop binop; + TSBinop shift; + ArchOpcode hn_opcode; + ArchOpcode hn2_opcode; +}; + +std::ostream& operator<<(std::ostream& os, + const AddSubHighNarrowConvertConfig& config) { + return os << config.name; +} + +const AddSubHighNarrowConvertConfig kAddSubHighNarrowConvertConfigs[] = { + {"I16x8SConvertI32x4Add", TSBinop::kI16x8SConvertI32x4, 32, + TSBinop::kI32x4Add, TSBinop::kI32x4ShrS, kArm64Addhn, kArm64Addhn2}, + {"I16x8SConvertI32x4Sub", TSBinop::kI16x8SConvertI32x4, 32, + TSBinop::kI32x4Sub, TSBinop::kI32x4ShrS, kArm64Subhn, kArm64Subhn2}, + {"I16x8UConvertI32x4Add", TSBinop::kI16x8UConvertI32x4, 32, + TSBinop::kI32x4Add, TSBinop::kI32x4ShrU, kArm64Addhn, kArm64Addhn2}, + {"I16x8UConvertI32x4Sub", TSBinop::kI16x8UConvertI32x4, 32, + TSBinop::kI32x4Sub, TSBinop::kI32x4ShrU, kArm64Subhn, kArm64Subhn2}, + {"I8x16SConvertI16x8Add", TSBinop::kI8x16SConvertI16x8, 16, + TSBinop::kI16x8Add, TSBinop::kI16x8ShrS, kArm64Addhn, kArm64Addhn2}, + {"I8x16SConvertI16x8Sub", TSBinop::kI8x16SConvertI16x8, 16, + TSBinop::kI16x8Sub, TSBinop::kI16x8ShrS, kArm64Subhn, kArm64Subhn2}, + {"I8x16UConvertI16x8Add", TSBinop::kI8x16UConvertI16x8, 16, + TSBinop::kI16x8Add, TSBinop::kI16x8ShrU, kArm64Addhn, kArm64Addhn2}, + {"I8x16UConvertI16x8Sub", TSBinop::kI8x16UConvertI16x8, 16, + TSBinop::kI16x8Sub, TSBinop::kI16x8ShrU, kArm64Subhn, kArm64Subhn2}, +}; + +} // namespace + +using TurboshaftInstructionSelectorAddSubHighNarrowConvertTest = + TurboshaftInstructionSelectorTestWithParam<AddSubHighNarrowConvertConfig>; + +TEST_P(TurboshaftInstructionSelectorAddSubHighNarrowConvertTest, + ShiftedAddSub) { + const auto& param = GetParam(); + const MachineType type = MachineType::Simd128(); + StreamBuilder m(this, type, type, type, type, type); + OpIndex amount = m.Int32Constant(param.lane_size / 2); + OpIndex low = m.Emit(param.binop, m.Parameter(0), m.Parameter(1)); + OpIndex high = m.Emit(param.binop, m.Parameter(2), m.Parameter(3)); + low = m.Emit(param.shift, low, amount); + high = m.Emit(param.shift, high, amount); + OpIndex result = m.Emit(param.operation, low, high); + m.Return(result); + Stream s = m.Build(); + + ASSERT_EQ(2U, s.size()); + EXPECT_EQ(param.hn_opcode, s[0]->arch_opcode()); + EXPECT_EQ(param.hn2_opcode, s[1]->arch_opcode()); + EXPECT_EQ(param.lane_size, + LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(param.lane_size, + LaneSizeBits(LaneSizeField::decode(s[1]->opcode()))); + ASSERT_EQ(1U, s[1]->OutputCount()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(3U, s[1]->InputCount()); + EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(m.Parameter(2)), s.ToVreg(s[1]->InputAt(1))); + EXPECT_EQ(s.ToVreg(m.Parameter(3)), s.ToVreg(s[1]->InputAt(2))); + EXPECT_TRUE(s.IsSameAsFirst(s[1]->Output())); + EXPECT_EQ(s.ToVreg(result), s.ToVreg(s[1]->Output())); +} + +INSTANTIATE_TEST_SUITE_P( + TurboshaftInstructionSelectorTest, + TurboshaftInstructionSelectorAddSubHighNarrowConvertTest, + ::testing::ValuesIn(kAddSubHighNarrowConvertConfigs)); + TEST_F(TurboshaftInstructionSelectorTest, Shuffle8x8Test) { const MachineType type = MachineType::Simd128(); { @@ -5581,11 +5906,9 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle16x4Test) { m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(1), Simd128ShuffleOp::Kind::kI8x8, shuffle)); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64I8x16Shuffle, s[0]->arch_opcode()); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s.size()); + ExpectS128Tbl1SequenceWith64BitMask(s, 0, m.Parameter(0), + 0x01000b0a07060302); } { const uint8_t shuffle[] = { @@ -5595,11 +5918,9 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle16x4Test) { m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(1), Simd128ShuffleOp::Kind::kI8x8, shuffle)); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64I8x16Shuffle, s[0]->arch_opcode()); - EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(2U, s.size()); + ExpectS128Tbl1SequenceWith64BitMask(s, 0, m.Parameter(1), + 0x0d0c0f0e05040100); } { const uint8_t shuffle[] = {0, 1, 14, 15, 22, 23, 26, 27}; @@ -5607,11 +5928,27 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle16x4Test) { m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(1), Simd128ShuffleOp::Kind::kI8x8, shuffle)); Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64I8x16Shuffle, s[0]->arch_opcode()); - EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); - EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); - EXPECT_EQ(1U, s[0]->OutputCount()); + ASSERT_EQ(4U, s.size()); + EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode()); + EXPECT_EQ(16, LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(m.Parameter(0))); + EXPECT_EQ(s.ToInt32(s[0]->InputAt(1)), 0); + EXPECT_EQ(kArm64S128MoveLane, s[1]->arch_opcode()); + EXPECT_EQ(16, LaneSizeBits(LaneSizeField::decode(s[1]->opcode()))); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[0]->Output())); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(1)), s.ToVreg(m.Parameter(0))); + EXPECT_EQ(s.ToInt32(s[1]->InputAt(2)), 7); + EXPECT_EQ(kArm64S128MoveLane, s[2]->arch_opcode()); + EXPECT_EQ(16, LaneSizeBits(LaneSizeField::decode(s[2]->opcode()))); + EXPECT_EQ(s.ToVreg(s[2]->InputAt(0)), s.ToVreg(s[1]->Output())); + EXPECT_EQ(s.ToVreg(s[2]->InputAt(1)), s.ToVreg(m.Parameter(1))); + EXPECT_EQ(s.ToInt32(s[2]->InputAt(2)), 3); + EXPECT_EQ(kArm64S128MoveLane, s[3]->arch_opcode()); + EXPECT_EQ(16, LaneSizeBits(LaneSizeField::decode(s[3]->opcode()))); + EXPECT_EQ(s.ToVreg(s[3]->InputAt(0)), s.ToVreg(s[2]->Output())); + EXPECT_EQ(s.ToVreg(s[3]->InputAt(1)), s.ToVreg(m.Parameter(1))); + EXPECT_EQ(s.ToInt32(s[3]->InputAt(2)), 5); + EXPECT_EQ(1U, s[3]->OutputCount()); } } @@ -5685,6 +6022,35 @@ TEST_F(TurboshaftInstructionSelectorTest, Shuffle32x2Test) { } } +TEST_F(TurboshaftInstructionSelectorTest, Shuffle32x4) { + const MachineType type = MachineType::Simd128(); + { + // shuffle32x4 + std::array<uint8_t, kSimd128Size> shuffle = { + 0, 1, 2, 3, 16, 17, 18, 19, 16, 17, 18, 19, 20, 21, 22, 23}; + StreamBuilder m(this, type, type, type, type); + m.Return(m.Simd128Shuffle(m.Parameter(0), m.Parameter(1), + Simd128ShuffleOp::Kind::kI8x16, shuffle.data())); + Stream s = m.Build(); + ASSERT_EQ(3U, s.size()); + EXPECT_EQ(kArm64S128Dup, s[0]->arch_opcode()); + EXPECT_EQ(32, LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(m.Parameter(1))); + EXPECT_EQ(s.ToInt32(s[0]->InputAt(1)), 0); + EXPECT_EQ(kArm64S128MoveLane, s[1]->arch_opcode()); + EXPECT_EQ(32, LaneSizeBits(LaneSizeField::decode(s[1]->opcode()))); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[0]->Output())); + EXPECT_EQ(s.ToVreg(s[1]->InputAt(1)), s.ToVreg(m.Parameter(0))); + EXPECT_EQ(s.ToInt32(s[1]->InputAt(2)), 0); + EXPECT_EQ(kArm64S128MoveLane, s[2]->arch_opcode()); + EXPECT_EQ(32, LaneSizeBits(LaneSizeField::decode(s[2]->opcode()))); + EXPECT_EQ(s.ToVreg(s[2]->InputAt(0)), s.ToVreg(s[1]->Output())); + EXPECT_EQ(s.ToVreg(s[2]->InputAt(1)), s.ToVreg(m.Parameter(1))); + EXPECT_EQ(s.ToInt32(s[2]->InputAt(2)), 1); + EXPECT_EQ(1U, s[2]->OutputCount()); + } +} + TEST_F(TurboshaftInstructionSelectorTest, Shuffle64x1Test) { const MachineType type = MachineType::Simd128(); { @@ -7401,7 +7767,7 @@ TEST_F(TurboshaftInstructionSelectorTest, LoadTransform) { } #endif // V8_ENABLE_WEBASSEMBLY -// This list doesn't contain kIndirectPointerWriteBarrier because only indirect +// This list doesn't contain kTrustedPointerWriteBarrier because only trusted // pointer fields can be stored to with that barrier kind. static const WriteBarrierKind kWriteBarrierKinds[] = { kMapWriteBarrier, kPointerWriteBarrier, kEphemeronKeyWriteBarrier, @@ -10513,6 +10879,74 @@ TEST_F(TurboshaftInstructionSelectorTest, SimdShiftToAdd) { } } +namespace { + +struct SIMDShiftLeftLongTest { + const TSUnop extension; + const TSBinop shift; + const ArchOpcode regular_opcode; + const ArchOpcode full_width_opcode; + const int lane_bits; +}; + +#define SIMD_SHIFT_LEFT_LONG_TESTS(Dst, Src, LaneBits) \ + {TSUnop::k##Dst##SConvert##Src##Low, TSBinop::k##Dst##Shl, kArm64Sshll, \ + kArm64IShll, LaneBits}, \ + {TSUnop::k##Dst##SConvert##Src##High, TSBinop::k##Dst##Shl, \ + kArm64Sshll2, kArm64IShll2, LaneBits}, \ + {TSUnop::k##Dst##UConvert##Src##Low, TSBinop::k##Dst##Shl, kArm64Ushll, \ + kArm64IShll, LaneBits}, \ + { \ + TSUnop::k##Dst##UConvert##Src##High, TSBinop::k##Dst##Shl, kArm64Ushll2, \ + kArm64IShll2, LaneBits \ + } + +const SIMDShiftLeftLongTest kSIMDShiftLeftLongTests[] = { + SIMD_SHIFT_LEFT_LONG_TESTS(I16x8, I8x16, 16), + SIMD_SHIFT_LEFT_LONG_TESTS(I32x4, I16x8, 32), + SIMD_SHIFT_LEFT_LONG_TESTS(I64x2, I32x4, 64), +}; + +#undef SIMD_SHIFT_LEFT_LONG_TESTS + +} // namespace + +TEST_F(TurboshaftInstructionSelectorTest, SimdShiftLeftLong) { + for (const SIMDShiftLeftLongTest& test : kSIMDShiftLeftLongTests) { + const int source_lane_bits = test.lane_bits / 2; + TRACED_FORRANGE(int, shift_amount, 1, source_lane_bits) { + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128()); + const V<Simd128> input = m.Parameter(0); + const OpIndex extension = m.Emit(test.extension, input); + const OpIndex result = + m.Emit(test.shift, extension, m.Int32Constant(shift_amount)); + m.Return(result); + const Stream s = m.Build(); + + if (shift_amount == source_lane_bits) { + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(test.full_width_opcode, s[0]->arch_opcode()); + EXPECT_EQ(test.lane_bits, + LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + EXPECT_EQ(1U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(input), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(result), s.ToVreg(s[0]->Output())); + } else { + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(test.regular_opcode, s[0]->arch_opcode()); + EXPECT_EQ(test.lane_bits, + LaneSizeBits(LaneSizeField::decode(s[0]->opcode()))); + EXPECT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(input), s.ToVreg(s[0]->InputAt(0))); + EXPECT_EQ(s.ToVreg(result), s.ToVreg(s[0]->Output())); + EXPECT_EQ(shift_amount, s.ToInt32(s[0]->InputAt(1))); + } + } + } +} + INSTANTIATE_TEST_SUITE_P(TurboshaftInstructionSelectorTest, TurboshaftInstructionSelectorSIMDSubFamilyTest, ::testing::ValuesIn(kSIMDSubFamilyTests)); diff --git a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc index 6e21b88e90ff..013e9f1e3c27 100644 --- a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.cc @@ -353,8 +353,7 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { ZoneVector<MachineType> empty_type(zone()); auto call_descriptor = Linkage::GetJSCallDescriptor( - zone(), false, 1, - CallDescriptor::kNeedsFrameState | CallDescriptor::kCanUseRoots); + zone(), false, 1, CallDescriptor::kNeedsFrameState); // Build frame state for the state before the call. Node* parameters = m.AddNode( diff --git a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.h index 146688e62305..b88e684b9308 100644 --- a/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.h +++ b/deps/v8/test/unittests/compiler/backend/instruction-selector-unittest.h @@ -129,7 +129,7 @@ class InstructionSelectorTest : public TestWithNativeContextAndZone { Operator::kNoProperties, // properties kCalleeSaveRegisters, // callee-saved registers kCalleeSaveFPRegisters, // callee-saved fp regs - CallDescriptor::kCanUseRoots, // flags + CallDescriptor::kNoFlags, // flags "iselect-test-call"); } diff --git a/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.cc index c042c0954551..dd8b7c1936df 100644 --- a/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.cc @@ -51,8 +51,12 @@ TurboshaftInstructionSelectorTest::StreamBuilder::Build( // Initialize an instruction sequence. InstructionBlocks* instruction_blocks = InstructionSequence::InstructionBlocksFor(test_->zone(), graph); - InstructionSequence sequence(test_->isolate(), test_->zone(), - instruction_blocks); + bool is_wasm = false; +#if V8_ENABLE_WEBASSEMBLY + is_wasm = call_descriptor()->IsAnyWasmFunctionCall(); +#endif // V8_ENABLE_WEBASSEMBLY + InstructionSequence sequence(is_wasm ? nullptr : test_->isolate(), + test_->zone(), instruction_blocks); TickCounter tick_counter; size_t max_unoptimized_frame_height = 0; @@ -62,7 +66,8 @@ TurboshaftInstructionSelectorTest::StreamBuilder::Build( InstructionSelector::kEnableSwitchJumpTable, &tick_counter, nullptr, &max_unoptimized_frame_height, &max_pushed_argument_count, source_position_mode, features, scheduling_mode, - InstructionSelector::kEnableRootsRelativeAddressing, + is_wasm ? InstructionSelector::kDisableRootsRelativeAddressing + : InstructionSelector::kEnableRootsRelativeAddressing, InstructionSelector::kDisableTraceTurboJson, InstructionSelector::kNoDeterministicNan); @@ -327,8 +332,7 @@ TARGET_TEST_F(TurboshaftInstructionSelectorTest, CallJSFunctionWithDeopt) { ZoneVector<MachineType> empty_type(zone()); auto call_descriptor = Linkage::GetJSCallDescriptor( - zone(), false, 1, - CallDescriptor::kNeedsFrameState | CallDescriptor::kCanUseRoots); + zone(), false, 1, CallDescriptor::kNeedsFrameState); // Build frame state for the state before the call. Node* parameters = m.AddNode( diff --git a/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.h index 7bc2bb398ce8..4c63059a301a 100644 --- a/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.h +++ b/deps/v8/test/unittests/compiler/backend/turboshaft-instruction-selector-unittest.h @@ -176,6 +176,15 @@ class TurboshaftInstructionSelectorTest : public TestWithNativeContextAndZone { class StreamBuilder final : public BaseAssembler { public: + StreamBuilder(TurboshaftInstructionSelectorTest* test, + CallDescriptor* call_descriptor) + : BaseAssembler(test->data(), test->graph(), test->graph(), + test->zone()), + test_(test), + call_descriptor_(call_descriptor) { + Init(); + } + StreamBuilder(TurboshaftInstructionSelectorTest* test, MachineType return_type) : BaseAssembler(test->data(), test->graph(), test->graph(), @@ -290,7 +299,7 @@ class TurboshaftInstructionSelectorTest : public TestWithNativeContextAndZone { Operator::kNoProperties, // properties kCalleeSaveRegisters, // callee-saved registers kCalleeSaveFPRegisters, // callee-saved fp regs - CallDescriptor::kCanUseRoots, // flags + CallDescriptor::kNoFlags, // flags "iselect-test-call"); } diff --git a/deps/v8/test/unittests/compiler/bytecode-analysis-unittest.cc b/deps/v8/test/unittests/compiler/bytecode-analysis-unittest.cc index e2f2980c98e2..21da8c7cc51a 100644 --- a/deps/v8/test/unittests/compiler/bytecode-analysis-unittest.cc +++ b/deps/v8/test/unittests/compiler/bytecode-analysis-unittest.cc @@ -496,6 +496,41 @@ TEST_F(BytecodeAnalysisTest, SuspendPoint) { EnsureLivenessMatches(bytecode, expected_liveness); } +TEST_F(BytecodeAnalysisTest, JumpIfToBooleanTryCatch) { + interpreter::BytecodeArrayBuilder builder(zone(), 3, 3); + std::vector<std::pair<std::string, std::string>> expected_liveness; + + interpreter::Register reg_1(1); + interpreter::Register reg_context(2); + + interpreter::TryCatchBuilder try_builder(&builder, nullptr, nullptr, + HandlerTable::CAUGHT); + try_builder.BeginTry(reg_context); + { + interpreter::BytecodeLabel label; + builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &label); + expected_liveness.emplace_back("...L", "...L"); + + builder.Bind(&label); + } + try_builder.EndTry(); + expected_liveness.emplace_back("...L", "...L"); + + // Catch + { + builder.LoadAccumulatorWithRegister(reg_1); + expected_liveness.emplace_back(".L..", "...L"); + } + try_builder.EndCatch(); + + builder.Return(); + expected_liveness.emplace_back("...L", "...."); + + Handle<BytecodeArray> bytecode = builder.ToBytecodeArray(isolate()); + + EnsureLivenessMatches(bytecode, expected_liveness); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/codegen-tester.h b/deps/v8/test/unittests/compiler/codegen-tester.h index 958af7c4fe0a..44f79e5f91bc 100644 --- a/deps/v8/test/unittests/compiler/codegen-tester.h +++ b/deps/v8/test/unittests/compiler/codegen-tester.h @@ -81,7 +81,7 @@ class RawMachineAssemblerTester : public CallHelper<ReturnType>, Address Generate() override { if (code_.is_null()) { Schedule* schedule = ExportForTest(); - OptimizedCompilationInfo info(base::ArrayVector("testing"), zone_, kind_); + OptimizedCompilationInfo info("testing", zone_, kind_); code_ = Pipeline::GenerateCodeForTesting( &info, isolate_, call_descriptor(), graph(), AssemblerOptions::Default(isolate_), schedule); diff --git a/deps/v8/test/unittests/compiler/compiler-unittest.cc b/deps/v8/test/unittests/compiler/compiler-unittest.cc index 63ab3a6d48c6..c3efdf238d1a 100644 --- a/deps/v8/test/unittests/compiler/compiler-unittest.cc +++ b/deps/v8/test/unittests/compiler/compiler-unittest.cc @@ -7,6 +7,7 @@ #include <stdlib.h> #include <wchar.h> +#include <array> #include <memory> #include "include/v8-extension.h" @@ -50,9 +51,8 @@ static void SetGlobalProperty(const char* name, Tagged<Object> value) { static DirectHandle<JSFunction> Compile(const char* source) { Isolate* isolate = reinterpret_cast<i::Isolate*>(v8::Isolate::GetCurrent()); - Handle<String> source_code = isolate->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + Handle<String> source_code = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); ScriptCompiler::CompilationDetails compilation_details; DirectHandle<SharedFunctionInfo> shared = Compiler::GetSharedFunctionInfoForScript( @@ -67,10 +67,10 @@ static DirectHandle<JSFunction> Compile(const char* source) { static double Inc(Isolate* isolate, int x) { const char* source = "result = %d + 1;"; - base::EmbeddedVector<char, 512> buffer; - SNPrintF(buffer, source, x); + std::array<char, 512> buffer; + base::SNPrintF(buffer, source, x); - DirectHandle<JSFunction> fun = Compile(buffer.begin()); + DirectHandle<JSFunction> fun = Compile(buffer.data()); if (fun.is_null()) return -1; DirectHandle<JSObject> global(isolate->context()->global_object(), isolate); @@ -241,7 +241,7 @@ TEST_F(CompilerTestWithPrintExtension, C2JSFrames) { EXPECT_TRUE(IsJSFunction(*fun1)); DirectHandle<Object> args[] = { - isolate->factory()->InternalizeString(base::StaticCharVector("hello"))}; + isolate->factory()->InternalizeString("hello")}; Execution::Call(isolate, Cast<JSFunction>(fun1), global, base::VectorOf(args)) .Check(); } @@ -264,14 +264,14 @@ TEST_F(CompilerTest, GetScriptLineNumber) { const char function_f[] = "function f() {}"; const int max_rows = 1000; const int buffer_size = max_rows + sizeof(function_f); - auto buffer = base::OwnedVector<char>::NewForOverwrite(buffer_size); - memset(buffer.begin(), '\n', buffer_size - 1); + std::array<char, buffer_size> buffer; + memset(buffer.data(), '\n', buffer_size - 1); buffer[buffer_size - 1] = '\0'; for (int i = 0; i < max_rows; ++i) { if (i > 0) buffer[i - 1] = '\n'; MemCopy(&buffer[i], function_f, sizeof(function_f) - 1); - v8::Local<v8::String> script_body = NewString(buffer.begin()); + v8::Local<v8::String> script_body = NewString(buffer.data()); v8::Script::Compile(context(), script_body, &origin) .ToLocalChecked() ->Run(context()) @@ -955,10 +955,7 @@ TEST_F(BackgroundMergeTest, GCDuringMerge) { " }" "})"; IndirectHandle<String> source_string = - isolate() - ->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + isolate()->factory()->NewStringFromUtf8(source).ToHandleChecked(); const int kTopLevelId = 0; const int kFId = 1; @@ -1161,10 +1158,7 @@ TEST_F(BackgroundMergeTest, MergeWithEval) { " return eval('1');" "};"; IndirectHandle<String> source_string = - isolate() - ->factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + isolate()->factory()->NewStringFromUtf8(source).ToHandleChecked(); ScriptCompiler::CompilationDetails compilation_details; DirectHandle<SharedFunctionInfo> top_level_sfi = diff --git a/deps/v8/test/unittests/compiler/ia32/turboshaft-instruction-selector-ia32-unittest.cc b/deps/v8/test/unittests/compiler/ia32/turboshaft-instruction-selector-ia32-unittest.cc index 970545ae930d..8987abdd3a26 100644 --- a/deps/v8/test/unittests/compiler/ia32/turboshaft-instruction-selector-ia32-unittest.cc +++ b/deps/v8/test/unittests/compiler/ia32/turboshaft-instruction-selector-ia32-unittest.cc @@ -31,31 +31,31 @@ TEST_F(TurboshaftInstructionSelectorTest, Word32AddWithImmediate) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32Add(m.Parameter(0), m.Int32Constant(imm))); Stream s = m.Build(); + if (imm == 0) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); if (imm != kMinInt) { EXPECT_EQ(kIA32Lea, s[0]->arch_opcode()); } - if (imm == 0) { - ASSERT_EQ(1U, s[0]->InputCount()); - } else { - ASSERT_EQ(2U, s[0]->InputCount()); - EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); - } + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); } { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32Add(m.Int32Constant(imm), m.Parameter(0))); Stream s = m.Build(); + if (imm == 0) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); if (imm != kMinInt) { EXPECT_EQ(kIA32Lea, s[0]->arch_opcode()); } - if (imm == 0) { - ASSERT_EQ(1U, s[0]->InputCount()); - } else { - ASSERT_EQ(2U, s[0]->InputCount()); - EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); - } + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); } } } @@ -75,6 +75,10 @@ TEST_F(TurboshaftInstructionSelectorTest, Word32SubWithImmediate) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32Sub(m.Parameter(0), m.Int32Constant(imm))); Stream s = m.Build(); + if (imm == 0) { + ASSERT_EQ(0U, s.size()); + continue; + } ASSERT_EQ(1U, s.size()); EXPECT_EQ(kIA32Sub, s[0]->arch_opcode()); ASSERT_EQ(2U, s[0]->InputCount()); diff --git a/deps/v8/test/unittests/compiler/linkage-unittest.cc b/deps/v8/test/unittests/compiler/linkage-unittest.cc index 578b84e0b1ce..a418a3cc4cb2 100644 --- a/deps/v8/test/unittests/compiler/linkage-unittest.cc +++ b/deps/v8/test/unittests/compiler/linkage-unittest.cc @@ -50,10 +50,8 @@ static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, // So we can get a real JS function. static Handle<JSFunction> Compile(Isolate* isolate, std::string_view source) { - Handle<String> source_code = isolate->factory() - ->NewStringFromUtf8(base::Vector<const char>( - source.data(), source.length())) - .ToHandleChecked(); + Handle<String> source_code = + isolate->factory()->NewStringFromUtf8(source).ToHandleChecked(); ScriptCompiler::CompilationDetails compilation_details; DirectHandle<SharedFunctionInfo> shared = Compiler::GetSharedFunctionInfoForScript( @@ -126,8 +124,7 @@ TEST_F(LinkageTest, TestLinkageStubCall) { Isolate* isolate_ptr = isolate(); Zone zone(isolate_ptr->allocator(), ZONE_NAME); Callable callable = Builtins::CallableFor(isolate_ptr, Builtin::kToNumber); - OptimizedCompilationInfo info(base::ArrayVector("test"), &zone, - CodeKind::FOR_TESTING); + OptimizedCompilationInfo info("test", &zone, CodeKind::FOR_TESTING); auto call_descriptor = Linkage::GetStubCallDescriptor( &zone, callable.descriptor(), 0, CallDescriptor::kNoFlags, Operator::kNoProperties); @@ -148,8 +145,7 @@ TEST_F(LinkageTest, TestFPLinkageStubCall) { Zone zone(isolate_ptr->allocator(), ZONE_NAME); Callable callable = Builtins::CallableFor(isolate_ptr, Builtin::kWasmFloat64ToNumber); - OptimizedCompilationInfo info(base::ArrayVector("test"), &zone, - CodeKind::FOR_TESTING); + OptimizedCompilationInfo info("test", &zone, CodeKind::FOR_TESTING); auto call_descriptor = Linkage::GetStubCallDescriptor( &zone, callable.descriptor(), 0, CallDescriptor::kNoFlags, Operator::kNoProperties); diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 6c5678da0671..89a0f2c1af11 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -855,7 +855,6 @@ class IsSpeculativeBinopMatcher final : public TestNodeMatcher { bool MatchAndExplain(Node* node, MatchResultListener* listener) const final { return (TestNodeMatcher::MatchAndExplain(node, listener) && - // TODO(bmeurer): The type parameter is currently ignored. PrintMatchAndExplain(NumberOperationHintOf(node->op()), "hints", hint_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs", @@ -870,7 +869,6 @@ class IsSpeculativeBinopMatcher final : public TestNodeMatcher { private: const Matcher<NumberOperationHint> hint_matcher_; - const Matcher<Type> type_matcher_; const Matcher<Node*> lhs_matcher_; const Matcher<Node*> rhs_matcher_; const Matcher<Node*> effect_matcher_; diff --git a/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc b/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc index 875088a20cdf..cc838fc4e07f 100644 --- a/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc +++ b/deps/v8/test/unittests/compiler/regalloc/register-allocator-unittest.cc @@ -82,8 +82,8 @@ class RegisterAllocatorTest : public InstructionSequenceTest { InstructionSequence* sequence = this->sequence(); - OptimizedCompilationInfo info(base::ArrayVector("testing"), - sequence->zone(), CodeKind::FOR_TESTING); + OptimizedCompilationInfo info("testing", sequence->zone(), + CodeKind::FOR_TESTING); ZoneStats zone_stats(sequence->isolate()->allocator()); turboshaft::PipelineData data( &zone_stats, turboshaft::TurboshaftPipelineKind::kCSA, nullptr, &info, diff --git a/deps/v8/test/unittests/compiler/run-bytecode-graph-builder-unittest.cc b/deps/v8/test/unittests/compiler/run-bytecode-graph-builder-unittest.cc index d7cf86cc7faa..4ee1e25df8c0 100644 --- a/deps/v8/test/unittests/compiler/run-bytecode-graph-builder-unittest.cc +++ b/deps/v8/test/unittests/compiler/run-bytecode-graph-builder-unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> #include <utility> #include "include/v8-function.h" @@ -223,11 +224,11 @@ class RunBytecodeGraphBuilderTest : public TestWithNativeContext { for (size_t i = 0; i < arraysize(snippets); i++) { if ((i % 2) != shard) continue; - auto script = base::OwnedVector<char>::NewForOverwrite(3072); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 3072> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(i_isolate(), script.begin()); + BytecodeGraphTester tester(i_isolate(), script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -270,11 +271,11 @@ class RunBytecodeGraphBuilderTest : public TestWithNativeContext { for (size_t i = 0; i < arraysize(snippets); i++) { if ((i % 2) != shard) continue; - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1, p2) { %s };\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1, p2) { %s };\n%s({});", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -392,11 +393,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderReturnStatements) { {"return NaN;", {factory->nan_value()}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -416,11 +417,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderPrimitiveExpressions) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -469,11 +470,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTwoParameterTests) { {MakeString("abcdef"), MakeString("abc"), MakeString("def")}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1, p2) { %s }\n%s(0, 0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0), snippets[i].parameter(1)) @@ -502,11 +503,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderNamedLoad) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -547,11 +548,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderKeyedLoad) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1, p2) { %s };\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0), snippets[i].parameter(1)) @@ -580,11 +581,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderPropertyCall) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s({func() {}});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s({func() {}});", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -720,11 +721,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderToName) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s({});", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -745,11 +746,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLogicalNot) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -772,11 +773,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTypeOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -814,11 +815,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCompareTypeOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -860,11 +861,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCountOperation) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -891,11 +892,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDelete) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -942,11 +943,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDeleteGlobal) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s %s({});", snippets[i].code_snippet, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "%s %s({});", snippets[i].code_snippet, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -978,11 +979,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDeleteLookupSlot) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s %s %s", function_prologue, - snippets[i].code_snippet, function_epilogue); + std::array<char, 1024> script; + base::SNPrintF(script, "%s %s %s", function_prologue, + snippets[i].code_snippet, function_epilogue); - BytecodeGraphTester tester(isolate, script.begin(), "t"); + BytecodeGraphTester tester(isolate, script.data(), "t"); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1017,11 +1018,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupSlot) { {factory->NewNumber(23.456)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s %s %s", function_prologue, - snippets[i].code_snippet, function_epilogue); + std::array<char, 1024> script; + base::SNPrintF(script, "%s %s %s", function_prologue, + snippets[i].code_snippet, function_epilogue); - BytecodeGraphTester tester(isolate, script.begin(), "t"); + BytecodeGraphTester tester(isolate, script.data(), "t"); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1042,13 +1043,13 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupContextSlot) { {"'use strict'; eval('var x = 1'); return x;", {factory->NewNumber(0)}}}; for (size_t i = 0; i < arraysize(inner_eval_snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s %s %s } ; %s() ;", - kFunctionName, inner_eval_prologue, - inner_eval_snippets[i].code_snippet, inner_eval_epilogue, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s %s %s } ; %s() ;", + kFunctionName, inner_eval_prologue, + inner_eval_snippets[i].code_snippet, inner_eval_epilogue, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, @@ -1066,13 +1067,12 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupContextSlot) { {"'use strict'; var x = 0; eval('var x = 1');", {factory->NewNumber(0)}}}; for (size_t i = 0; i < arraysize(outer_eval_snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s %s %s } ; %s() ;", - kFunctionName, outer_eval_prologue, - outer_eval_snippets[i].code_snippet, outer_eval_epilogue, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s %s %s } ; %s() ;", kFunctionName, + outer_eval_prologue, outer_eval_snippets[i].code_snippet, + outer_eval_epilogue, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, @@ -1094,13 +1094,13 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupGlobalSlot) { {"'use strict'; eval('var x = 1'); return x;", {factory->NewNumber(0)}}}; for (size_t i = 0; i < arraysize(inner_eval_snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s %s %s } ; %s() ;", - kFunctionName, inner_eval_prologue, - inner_eval_snippets[i].code_snippet, inner_eval_epilogue, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s %s %s } ; %s() ;", + kFunctionName, inner_eval_prologue, + inner_eval_snippets[i].code_snippet, inner_eval_epilogue, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, @@ -1118,13 +1118,12 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupGlobalSlot) { {"'use strict'; x = 0; eval('var x = 1');", {factory->NewNumber(0)}}}; for (size_t i = 0; i < arraysize(outer_eval_snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s %s %s } ; %s() ;", - kFunctionName, outer_eval_prologue, - outer_eval_snippets[i].code_snippet, outer_eval_epilogue, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s %s %s } ; %s() ;", kFunctionName, + outer_eval_prologue, outer_eval_snippets[i].code_snippet, + outer_eval_epilogue, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, @@ -1161,11 +1160,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLookupSlotWide) { {factory->NewNumber(23.456)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(3072); - SNPrintF(script.as_vector(), "%s %s %s", function_prologue, - snippets[i].code_snippet, function_epilogue); + std::array<char, 3072> script; + base::SNPrintF(script, "%s %s %s", function_prologue, + snippets[i].code_snippet, function_epilogue); - BytecodeGraphTester tester(isolate, script.begin(), "t"); + BytecodeGraphTester tester(isolate, script.data(), "t"); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1188,10 +1187,10 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCallLookupSlot) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1234,10 +1233,10 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderEval) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1259,10 +1258,10 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderEvalParams) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -1356,12 +1355,12 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCompare) { factory->NewNumberFromInt(SMI_MIN)}; for (size_t i = 0; i < arraysize(kCompareOperators); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1, p2) { %s }\n%s({}, {});", - kFunctionName, get_code_snippet(kCompareOperators[i]), - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", + kFunctionName, get_code_snippet(kCompareOperators[i]), + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); for (size_t j = 0; j < arraysize(lhs_values); j++) { for (size_t k = 0; k < arraysize(rhs_values); k++) { @@ -1402,11 +1401,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTestIn) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1, p2) { %s }\n%s({}, {});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0), snippets[i].parameter(1)) @@ -1431,11 +1430,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTestInstanceOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s(p1) { %s }\n%s({});", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -1459,11 +1458,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTryCatch) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1495,11 +1494,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTryFinally1) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1517,11 +1516,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderTryFinally2) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); v8::Local<v8::String> expected_string = NewString(snippets[i].return_value()); @@ -1544,11 +1543,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderThrow) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); v8::Local<v8::String> expected_string = NewString(snippets[i].return_value()); @@ -1602,10 +1601,10 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderContext) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s", snippets[i].code_snippet); + std::array<char, 1024> script; + base::SNPrintF(script, "%s", snippets[i].code_snippet); - BytecodeGraphTester tester(isolate, script.begin(), "f"); + BytecodeGraphTester tester(isolate, script.data(), "f"); auto callable = tester.GetCallable<>("f"); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1664,10 +1663,10 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderLoadContextNoCell) { {factory->NewNumberFromInt(24), factory->NewNumberFromInt(4)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s", snippets[i].code_snippet); + std::array<char, 1024> script; + base::SNPrintF(script, "%s", snippets[i].code_snippet); - BytecodeGraphTester tester(isolate, script.begin(), "*"); + BytecodeGraphTester tester(isolate, script.data(), "*"); auto callable = tester.GetCallable<Handle<Object>>("f"); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -1694,11 +1693,11 @@ TEST_F(RunBytecodeGraphBuilderTest, }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s\n%s();", snippets[i].code_snippet, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1735,11 +1734,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCreateArguments) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s\n%s();", snippets[i].code_snippet, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); DirectHandle<Object> return_value = @@ -1777,11 +1776,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderCreateRestArguments) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s\n%s();", snippets[i].code_snippet, - kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); DirectHandle<Object> return_value = @@ -1809,11 +1808,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderRegExpLiterals) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(4096); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 4096> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1844,11 +1843,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderArrayLiterals) { {MakeString("1t")}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(4096); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 4096> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -1902,10 +1901,10 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderObjectLiterals) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(4096); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + std::array<char, 4096> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2007,11 +2006,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderIf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -2035,11 +2034,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderConditionalOperator) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -2080,11 +2079,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderSwitch) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -2127,11 +2126,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderSwitchMerge) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1) { %s };\n%s(0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0)).ToHandleChecked(); @@ -2184,11 +2183,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderNestedSwitch) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(2048); - SNPrintF(script.as_vector(), "function %s(p1, p2) { %s };\n%s(0, 0);", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 2048> script; + base::SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0, 0);", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>(); DirectHandle<Object> return_value = callable(snippets[i].parameter(0), snippets[i].parameter(1)) @@ -2224,11 +2223,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderBreakableBlocks) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2270,11 +2269,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderWhile) { {factory->NewNumberFromInt(16)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2316,11 +2315,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderDo) { {factory->NewNumber(3)}}}; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2407,11 +2406,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderFor) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2476,11 +2475,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderForIn) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2565,11 +2564,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderForOf) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2602,11 +2601,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderWithStatement) { }; for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2647,11 +2646,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderConstDeclaration) { // Tests for sloppy mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2659,11 +2658,11 @@ TEST_F(RunBytecodeGraphBuilderTest, BytecodeGraphBuilderConstDeclaration) { // Tests for strict mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() {'use strict'; %s }\n%s();", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2688,11 +2687,11 @@ TEST_F(RunBytecodeGraphBuilderTest, // Tests for sloppy mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2700,11 +2699,11 @@ TEST_F(RunBytecodeGraphBuilderTest, // Tests for strict mode. for (size_t i = 0; i < arraysize(snippets); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() {'use strict'; %s }\n%s();", - kFunctionName, snippets[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", + kFunctionName, snippets[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *snippets[i].return_value())); @@ -2747,11 +2746,11 @@ TEST_F(RunBytecodeGraphBuilderTest, {handle(Smi::FromInt(-1), isolate)}}}; for (size_t i = 0; i < arraysize(const_decl); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "%s %s %s", prologue, - const_decl[i].code_snippet, epilogue); + std::array<char, 1024> script; + base::SNPrintF(script, "%s %s %s", prologue, const_decl[i].code_snippet, + epilogue); - BytecodeGraphTester tester(isolate, script.begin(), "*"); + BytecodeGraphTester tester(isolate, script.data(), "*"); auto callable = tester.GetCallable<>(); DirectHandle<Object> return_value = callable().ToHandleChecked(); CHECK(Object::SameValue(*return_value, *const_decl[i].return_value())); @@ -2779,11 +2778,11 @@ TEST_F(RunBytecodeGraphBuilderTest, // Tests for sloppy mode. for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() { %s }\n%s();", kFunctionName, - illegal_const_decl[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + illegal_const_decl[i].code_snippet, kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); v8::Local<v8::String> expected_string = NewString(illegal_const_decl[i].return_value()); @@ -2793,11 +2792,12 @@ TEST_F(RunBytecodeGraphBuilderTest, // Tests for strict mode. for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { - auto script = base::OwnedVector<char>::NewForOverwrite(1024); - SNPrintF(script.as_vector(), "function %s() {'use strict'; %s }\n%s();", - kFunctionName, illegal_const_decl[i].code_snippet, kFunctionName); + std::array<char, 1024> script; + base::SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", + kFunctionName, illegal_const_decl[i].code_snippet, + kFunctionName); - BytecodeGraphTester tester(isolate, script.begin()); + BytecodeGraphTester tester(isolate, script.data()); v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); v8::Local<v8::String> expected_string = NewString(illegal_const_decl[i].return_value()); diff --git a/deps/v8/test/unittests/compiler/run-variables-unittest.cc b/deps/v8/test/unittests/compiler/run-variables-unittest.cc index 99dc362127e3..0924b3c47efb 100644 --- a/deps/v8/test/unittests/compiler/run-variables-unittest.cc +++ b/deps/v8/test/unittests/compiler/run-variables-unittest.cc @@ -64,11 +64,11 @@ static void RunVariableTests(Isolate* isolate, std::string_view source_format, std::span<const TestCase> test_cases) { for (size_t i = 0; i < test_cases.size(); ++i) { const auto& test_case = test_cases[i]; - base::EmbeddedVector<char, 512> buffer; - SNPrintF(buffer, source_format.data(), test_case.code.data()); - PrintF("#%zu: %s\n", i, buffer.begin()); + std::array<char, 512> buffer; + base::SNPrintF(buffer, source_format.data(), test_case.code.data()); + PrintF("#%zu: %s\n", i, buffer.data()); - FunctionTester tester(isolate, buffer.begin()); + FunctionTester tester(isolate, buffer.data()); // Check function with non-falsey parameter. if (test_case.expected_truthy != kThrows) { diff --git a/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc b/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc index 6187763bd31c..25c43d1439f6 100644 --- a/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-lowering-unittest.cc @@ -48,7 +48,7 @@ class SimplifiedLoweringTest : public GraphTest { } Linkage* linkage = zone()->New<Linkage>(Linkage::GetJSCallDescriptor( - zone(), false, num_parameters_ + 1, CallDescriptor::kCanUseRoots)); + zone(), false, num_parameters_ + 1, CallDescriptor::kNoFlags)); SimplifiedLowering lowering(jsgraph(), broker(), zone(), source_positions(), node_origins(), tick_counter(), linkage, nullptr); diff --git a/deps/v8/test/unittests/compiler/turboshaft/duplication-optimization-reducer-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/duplication-optimization-reducer-unittest.cc new file mode 100644 index 000000000000..f6a006349116 --- /dev/null +++ b/deps/v8/test/unittests/compiler/turboshaft/duplication-optimization-reducer-unittest.cc @@ -0,0 +1,254 @@ +// Copyright 2026 the V8 project 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 "src/compiler/turboshaft/duplication-optimization-reducer.h" + +#include <array> + +#include "test/unittests/compiler/turboshaft/reducer-test.h" + +namespace v8::internal::compiler::turboshaft { + +#include "src/compiler/turboshaft/define-assembler-macros.inc" + +class DuplicationOptimizationReducerTest : public ReducerTest {}; + +namespace { + +// Returns the branch on the comparison (the other branch is on a parameter). +const BranchOp& GetBranchOnComparison(TestInstance& test) { + const BranchOp* result = nullptr; + for (const Operation& op : test.graph().AllOperations()) { + const BranchOp* branch = op.TryCast<BranchOp>(); + if (branch == nullptr || + test.graph().Get(branch->condition()).Is<ParameterOp>()) { + continue; + } + CHECK_NULL(result); + result = branch; + } + CHECK_NOT_NULL(result); + return *result; +} + +// The number of comparisons that are not used (and thus not emitted by the +// InstructionSelector). +size_t CountUnusedComparisons(TestInstance& test) { + size_t count = 0; + for (const Operation& op : test.graph().AllOperations()) { + if (op.Is<ComparisonOp>() && op.saturated_use_count.Is(0)) count++; + } + return count; +} + +constexpr std::array kParameterReps = { + RegisterRepresentation::Word32(), RegisterRepresentation::Word32(), + RegisterRepresentation::Word32(), RegisterRepresentation::Word32()}; + +} // namespace + +// A comparison whose only use is a branch in a later block is re-emitted right +// before that branch, so that the InstructionSelector can combine them. +TEST_F(DuplicationOptimizationReducerTest, SinkComparisonIntoBranchBlock) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> c = Asm.template GetParameter<Word32>(2); + V<Word32> comparison = __ Word32Equal(a, b); + // An unrelated branch, so that the branch on {comparison} is in + // another block. + IF (c) { + __ Return(__ Word32Constant(2)); + } + IF (comparison) { + __ Return(__ Word32Constant(1)); + } ELSE { + __ Return(__ Word32Constant(0)); + } + }); + + test.Run<DuplicationOptimizationReducer>(); + + const BranchOp& branch = GetBranchOnComparison(test); + const Graph& graph = test.graph(); + const ComparisonOp* condition = + graph.Get(branch.condition()).TryCast<ComparisonOp>(); + ASSERT_NE(condition, nullptr); + EXPECT_EQ(ComparisonOp::Kind::kEqual, condition->kind); + EXPECT_EQ(graph.BlockOf(branch.condition()), + graph.BlockOf(graph.Index(branch))); + // The original comparison is still in the graph, but unused. + EXPECT_EQ(2u, test.CountOp(Opcode::kComparison)); + EXPECT_EQ(1u, CountUnusedComparisons(test)); +} + +// Same for a select. +TEST_F(DuplicationOptimizationReducerTest, SinkComparisonIntoSelectBlock) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> c = Asm.template GetParameter<Word32>(2); + V<Word32> comparison = __ Word32Equal(a, b); + IF (c) { + __ Return(__ Word32Constant(2)); + } + __ Return(__ Word32Select(comparison, a, b)); + }); + + test.Run<DuplicationOptimizationReducer>(); + + const Graph& graph = test.graph(); + const SelectOp* select = nullptr; + for (const Operation& op : graph.AllOperations()) { + if (const SelectOp* s = op.TryCast<SelectOp>()) { + ASSERT_EQ(select, nullptr); + select = s; + } + } + ASSERT_NE(select, nullptr); + ASSERT_TRUE(graph.Get(select->cond()).Is<ComparisonOp>()); + EXPECT_EQ(graph.BlockOf(select->cond()), graph.BlockOf(graph.Index(*select))); + EXPECT_EQ(1u, CountUnusedComparisons(test)); +} + +// A comparison that is already in the block of the branch using it is left +// alone. +TEST_F(DuplicationOptimizationReducerTest, KeepComparisonInBranchBlock) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> c = Asm.template GetParameter<Word32>(2); + IF (c) { + __ Return(__ Word32Constant(2)); + } + IF (__ Word32Equal(a, b)) { + __ Return(__ Word32Constant(1)); + } ELSE { + __ Return(__ Word32Constant(0)); + } + }); + + test.Run<DuplicationOptimizationReducer>(); + + EXPECT_EQ(1u, test.CountOp(Opcode::kComparison)); + const BranchOp& branch = GetBranchOnComparison(test); + const Graph& graph = test.graph(); + EXPECT_EQ(graph.BlockOf(branch.condition()), + graph.BlockOf(graph.Index(branch))); +} + +// A comparison that is not in the single predecessor of the block of the +// branch, and whose inputs are only used by it, is left alone, so as not to +// extend the live ranges of its inputs. +TEST_F(DuplicationOptimizationReducerTest, KeepComparisonNotInPredecessor) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> c = Asm.template GetParameter<Word32>(2); + V<Word32> d = Asm.template GetParameter<Word32>(3); + V<Word32> comparison = __ Word32Equal(a, b); + IF (c) { + __ Return(__ Word32Constant(2)); + } + IF (d) { + __ Return(__ Word32Constant(3)); + } + IF (comparison) { + __ Return(__ Word32Constant(1)); + } ELSE { + __ Return(__ Word32Constant(0)); + } + }); + + test.Run<DuplicationOptimizationReducer>(); + + EXPECT_EQ(1u, test.CountOp(Opcode::kComparison)); + const BranchOp& branch = GetBranchOnComparison(test); + const Graph& graph = test.graph(); + EXPECT_NE(graph.BlockOf(branch.condition()), + graph.BlockOf(graph.Index(branch))); +} + +// When one of its inputs has other uses, a comparison is re-emitted right +// before the branch even if it is further away. +TEST_F(DuplicationOptimizationReducerTest, SinkComparisonWithSharedInput) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> c = Asm.template GetParameter<Word32>(2); + V<Word32> d = Asm.template GetParameter<Word32>(3); + V<Word32> comparison = __ Word32Equal(a, b); + IF (c) { + __ Return(__ Word32Constant(2)); + } + IF (d) { + __ Return(__ Word32Constant(3)); + } + IF (comparison) { + __ Return(a); + } ELSE { + __ Return(__ Word32Constant(0)); + } + }); + + test.Run<DuplicationOptimizationReducer>(); + + const BranchOp& branch = GetBranchOnComparison(test); + const Graph& graph = test.graph(); + EXPECT_EQ(graph.BlockOf(branch.condition()), + graph.BlockOf(graph.Index(branch))); + EXPECT_EQ(1u, CountUnusedComparisons(test)); +} + +// A comparison is not re-emitted into a loop header, even though it is in the +// only predecessor of the loop header seen so far: it would be recomputed at +// each iteration. +TEST_F(DuplicationOptimizationReducerTest, KeepComparisonOutOfLoopHeader) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> c = Asm.template GetParameter<Word32>(2); + V<Word32> comparison = __ Word32Equal(a, b); + LoopLabel<Word32> loop(&Asm); + GOTO(loop, c); + BIND_LOOP(loop, iteration) { + IF (comparison) { + __ Return(a); + } + GOTO(loop, __ Word32Add(iteration, 1)); + } + }); + + test.Run<DuplicationOptimizationReducer>(); + + EXPECT_EQ(1u, test.CountOp(Opcode::kComparison)); +} + +// Only the first use of a comparison in the output graph is considered: here, +// it is a branch in the same block, so the comparison is not re-emitted for +// the second branch. +TEST_F(DuplicationOptimizationReducerTest, KeepComparisonWithEarlierUse) { + auto test = CreateFromGraph(base::VectorOf(kParameterReps), [](auto& Asm) { + V<Word32> a = Asm.template GetParameter<Word32>(0); + V<Word32> b = Asm.template GetParameter<Word32>(1); + V<Word32> comparison = __ Word32Equal(a, b); + IF (comparison) { + __ Return(__ Word32Constant(2)); + } + IF (comparison) { + __ Return(__ Word32Constant(1)); + } ELSE { + __ Return(__ Word32Constant(0)); + } + }); + + test.Run<DuplicationOptimizationReducer>(); + + EXPECT_EQ(1u, test.CountOp(Opcode::kComparison)); + EXPECT_EQ(0u, CountUnusedComparisons(test)); +} + +#include "src/compiler/turboshaft/undef-assembler-macros.inc" + +} // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/test/unittests/compiler/turboshaft/instruction-selection-normalization-reducer-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/instruction-selection-normalization-reducer-unittest.cc index bfc06da08b3b..5b10634da351 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/instruction-selection-normalization-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/turboshaft/instruction-selection-normalization-reducer-unittest.cc @@ -4,15 +4,18 @@ #include "src/compiler/turboshaft/instruction-selection-normalization-reducer.h" +#include <algorithm> #include <array> +#include "src/codegen/cpu-features.h" +#include "src/compiler/turboshaft/dead-code-elimination-reducer.h" #include "test/unittests/compiler/turboshaft/reducer-test.h" namespace v8::internal::compiler::turboshaft { using InstructionSelectionNormalizationReducerTest = ReducerTest; -#if V8_ENABLE_WEBASSEMBLY && defined(V8_TARGET_ARCH_ARM64) +#if V8_ENABLE_SIMD128 && defined(V8_TARGET_ARCH_ARM64) TEST_F(InstructionSelectionNormalizationReducerTest, ReduceWideningLoadTransforms) { using TransformKind = Simd128LoadTransformOp::TransformKind; @@ -62,6 +65,199 @@ TEST_F(InstructionSelectionNormalizationReducerTest, EXPECT_EQ(test.graph().Index(*load), extension->input()); } } -#endif // V8_ENABLE_WEBASSEMBLY && V8_TARGET_ARCH_ARM64 + +TEST_F(InstructionSelectionNormalizationReducerTest, ReduceWasmDotsToArmDot) { + // Input: + // I32x4Add( + // I32x4DotI16x8S(I16x8SConvertI8x16Low(left), + // I16x8SConvertI8x16Low(right)), + // I32x4DotI16x8S(I16x8SConvertI8x16High(left), + // I16x8SConvertI8x16High(right))) + // Expected: + // I32x4DotI8x16S(Shuffle(left), Shuffle(right)) + if (!CpuFeatures::IsSupported(DOTPROD)) GTEST_SKIP(); + + using BinopKind = Simd128BinopOp::Kind; + using UnaryKind = Simd128UnaryOp::Kind; + constexpr std::array parameter_reps = {RegisterRepresentation::Simd128(), + RegisterRepresentation::Simd128()}; + auto test = CreateFromGraph( + base::VectorOf(parameter_reps), + [](TestInstance& test_instance) { + V<Simd128> left = test_instance.Capture( + test_instance.GetParameter<Simd128>(0), "left"); + V<Simd128> right = test_instance.Capture( + test_instance.GetParameter<Simd128>(1), "right"); + auto WasmDot = [&](UnaryKind extension_kind) { + V<Simd128> left_extension = + test_instance.Asm().Simd128Unary(left, extension_kind); + V<Simd128> right_extension = + test_instance.Asm().Simd128Unary(right, extension_kind); + return test_instance.Asm().Simd128Binop( + left_extension, right_extension, BinopKind::kI32x4DotI16x8S); + }; + V<Simd128> low_dot = WasmDot(UnaryKind::kI16x8SConvertI8x16Low); + V<Simd128> high_dot = WasmDot(UnaryKind::kI16x8SConvertI8x16High); + V<Simd128> add = test_instance.Asm().Simd128Binop(low_dot, high_dot, + BinopKind::kI32x4Add); + test_instance.Asm().Return(test_instance.Capture(add, "add")); + }, + true); + + test.Run<InstructionSelectionNormalizationReducer>(); + test.Run<DeadCodeEliminationReducer>(); + + ASSERT_EQ(test.CountOp(Opcode::kSimd128Unary), 0u); + ASSERT_EQ(test.CountOp(Opcode::kSimd128Binop), 1u); + ASSERT_EQ(test.CountOp(Opcode::kSimd128Shuffle), 2u); + const auto* dot = test.GetCapture("add").GetFirst<Simd128BinopOp>(); + ASSERT_NE(dot, nullptr); + EXPECT_EQ(BinopKind::kI32x4DotI8x16S, dot->kind); + + constexpr std::array expected_shuffle = {0, 1, 8, 9, 2, 3, 10, 11, + 4, 5, 12, 13, 6, 7, 14, 15}; + auto CheckShuffle = [&](OpIndex input, const char* capture) { + const auto* shuffle = test.graph().Get(input).TryCast<Simd128ShuffleOp>(); + ASSERT_NE(shuffle, nullptr); + EXPECT_EQ(Simd128ShuffleOp::Kind::kI8x16, shuffle->kind); + EXPECT_TRUE(test.GetCapture(capture).Is(shuffle->left())); + EXPECT_EQ(shuffle->left(), shuffle->right()); + EXPECT_TRUE(std::equal(expected_shuffle.begin(), expected_shuffle.end(), + std::begin(shuffle->shuffle))); + }; + CheckShuffle(dot->left(), "left"); + CheckShuffle(dot->right(), "right"); +} + +TEST_F(InstructionSelectionNormalizationReducerTest, + ReduceWasmDotOfWideningLoads) { + // Input: + // I32x4DotI16x8S(Load8x8S/U(left), Load8x8S/U(right)) + // Expected: + // I32x4ExtAddPairwiseI16x8S/U( + // I16x8ExtMulLowI8x16S/U(Load64Zero(left), Load64Zero(right))) + using BinopKind = Simd128BinopOp::Kind; + using TransformKind = Simd128LoadTransformOp::TransformKind; + using UnaryKind = Simd128UnaryOp::Kind; + constexpr std::array parameter_reps = {RegisterRepresentation::WordPtr(), + RegisterRepresentation::WordPtr()}; + + for (TransformKind transform_kind : + {TransformKind::k8x8S, TransformKind::k8x8U}) { + auto test = CreateFromGraph( + base::VectorOf(parameter_reps), + [transform_kind](TestInstance& test_instance) { + V<Simd128> left = test_instance.Capture( + test_instance.Asm().Simd128LoadTransform( + test_instance.GetParameter<WordPtr>(0), + test_instance.Asm().WordPtrConstant(0), + LoadOp::Kind::Trapping(), transform_kind, 0), + "left"); + V<Simd128> right = test_instance.Capture( + test_instance.Asm().Simd128LoadTransform( + test_instance.GetParameter<WordPtr>(1), + test_instance.Asm().WordPtrConstant(0), + LoadOp::Kind::Trapping(), transform_kind, 0), + "right"); + V<Simd128> dot = test_instance.Capture( + test_instance.Asm().Simd128Binop(left, right, + BinopKind::kI32x4DotI16x8S), + "dot"); + test_instance.Asm().Return(dot); + }, + true); + + test.Run<InstructionSelectionNormalizationReducer>(); + test.Run<DeadCodeEliminationReducer>(); + + ASSERT_EQ(test.CountOp(Opcode::kSimd128LoadTransform), 2u); + ASSERT_EQ(test.CountOp(Opcode::kSimd128Unary), 1u); + ASSERT_EQ(test.CountOp(Opcode::kSimd128Shuffle), 0u); + ASSERT_EQ(test.CountOp(Opcode::kSimd128Binop), 1u); + const bool is_signed = transform_kind == TransformKind::k8x8S; + const auto* pairwise = test.GetCapture("dot").GetFirst<Simd128UnaryOp>(); + ASSERT_NE(pairwise, nullptr); + EXPECT_EQ(is_signed ? UnaryKind::kI32x4ExtAddPairwiseI16x8S + : UnaryKind::kI32x4ExtAddPairwiseI16x8U, + pairwise->kind); + const auto& product = + test.graph().Get(pairwise->input()).Cast<Simd128BinopOp>(); + EXPECT_EQ(is_signed ? BinopKind::kI16x8ExtMulLowI8x16S + : BinopKind::kI16x8ExtMulLowI8x16U, + product.kind); + EXPECT_TRUE(test.GetCapture("left").Is(product.left())); + EXPECT_TRUE(test.GetCapture("right").Is(product.right())); + for (OpIndex input : product.inputs()) { + const auto& load = test.graph().Get(input).Cast<Simd128LoadTransformOp>(); + EXPECT_EQ(TransformKind::k64Zero, load.transform_kind); + } + } +} + +TEST_F(InstructionSelectionNormalizationReducerTest, + ReduceWideningMultiplication) { + using BinopKind = Simd128BinopOp::Kind; + using UnaryKind = Simd128UnaryOp::Kind; + struct TestCase { + BinopKind mul_kind; + UnaryKind extension_kind; + BinopKind extmul_kind; + }; + constexpr std::array test_cases = { + TestCase{BinopKind::kI16x8Mul, UnaryKind::kI16x8SConvertI8x16Low, + BinopKind::kI16x8ExtMulLowI8x16S}, + TestCase{BinopKind::kI16x8Mul, UnaryKind::kI16x8SConvertI8x16High, + BinopKind::kI16x8ExtMulHighI8x16S}, + TestCase{BinopKind::kI16x8Mul, UnaryKind::kI16x8UConvertI8x16Low, + BinopKind::kI16x8ExtMulLowI8x16U}, + TestCase{BinopKind::kI16x8Mul, UnaryKind::kI16x8UConvertI8x16High, + BinopKind::kI16x8ExtMulHighI8x16U}, + TestCase{BinopKind::kI32x4Mul, UnaryKind::kI32x4SConvertI16x8Low, + BinopKind::kI32x4ExtMulLowI16x8S}, + TestCase{BinopKind::kI32x4Mul, UnaryKind::kI32x4SConvertI16x8High, + BinopKind::kI32x4ExtMulHighI16x8S}, + TestCase{BinopKind::kI32x4Mul, UnaryKind::kI32x4UConvertI16x8Low, + BinopKind::kI32x4ExtMulLowI16x8U}, + TestCase{BinopKind::kI32x4Mul, UnaryKind::kI32x4UConvertI16x8High, + BinopKind::kI32x4ExtMulHighI16x8U}, + TestCase{BinopKind::kI64x2Mul, UnaryKind::kI64x2SConvertI32x4Low, + BinopKind::kI64x2ExtMulLowI32x4S}, + TestCase{BinopKind::kI64x2Mul, UnaryKind::kI64x2SConvertI32x4High, + BinopKind::kI64x2ExtMulHighI32x4S}, + TestCase{BinopKind::kI64x2Mul, UnaryKind::kI64x2UConvertI32x4Low, + BinopKind::kI64x2ExtMulLowI32x4U}, + TestCase{BinopKind::kI64x2Mul, UnaryKind::kI64x2UConvertI32x4High, + BinopKind::kI64x2ExtMulHighI32x4U}, + }; + constexpr std::array parameter_reps = {RegisterRepresentation::Simd128(), + RegisterRepresentation::Simd128()}; + + for (const TestCase& test_case : test_cases) { + auto test = CreateFromGraph( + base::VectorOf(parameter_reps), + [test_case](TestInstance& t) { + V<Simd128> left = t.Capture(t.GetParameter<Simd128>(0), "left"); + V<Simd128> right = t.Capture(t.GetParameter<Simd128>(1), "right"); + V<Simd128> left_extension = + t.Asm().Simd128Unary(left, test_case.extension_kind); + V<Simd128> right_extension = + t.Asm().Simd128Unary(right, test_case.extension_kind); + V<Simd128> mul = t.Asm().Simd128Binop(left_extension, right_extension, + test_case.mul_kind); + t.Asm().Return(t.Capture(mul, "mul")); + }, + true); + + test.Run<InstructionSelectionNormalizationReducer>(); + + const Simd128BinopOp* extmul = + test.GetCapture("mul").GetFirst<Simd128BinopOp>(); + ASSERT_NE(extmul, nullptr); + EXPECT_EQ(test_case.extmul_kind, extmul->kind); + EXPECT_TRUE(test.GetCapture("left").Is(extmul->left())); + EXPECT_TRUE(test.GetCapture("right").Is(extmul->right())); + } +} +#endif // V8_ENABLE_SIMD128 && V8_TARGET_ARCH_ARM64 } // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/test/unittests/compiler/turboshaft/machine-optimization-reducer-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/machine-optimization-reducer-unittest.cc index 48bb812c0e82..1f5db37a696c 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/machine-optimization-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/turboshaft/machine-optimization-reducer-unittest.cc @@ -6,6 +6,7 @@ #include "src/compiler/turboshaft/operations.h" #include "src/compiler/turboshaft/opmasks.h" +#include "src/compiler/turboshaft/use-map.h" #include "test/unittests/compiler/turboshaft/reducer-test.h" namespace v8::internal::compiler::turboshaft { @@ -323,4 +324,239 @@ TEST_F(MachineOptimizationReducerTest, KeepNarrowingShiftAmountMask) { .template Is<Opmask::kWord32BitwiseAnd>()); } +TEST_F(MachineOptimizationReducerTest, + MakeTupleOpExcludedFromUseCountAndUseMap) { + OpIndex tuple; + OpIndex proj0; + OpIndex proj1; + OpIndex consumer; + + const RegisterRepresentation rep32 = RegisterRepresentation::Word32(); + base::SmallVector<RegisterRepresentation, 2> reps = {rep32, rep32}; + auto test = CreateFromGraph(base::VectorOf(reps), [&](auto& t) { + auto a = t.template GetParameter<Word32>(0); + auto b = t.template GetParameter<Word32>(1); + + auto binop = t.Asm().OverflowCheckedBinop( + a, b, OverflowCheckedBinopOp::Kind::kSignedAdd, + WordRepresentation::Word32()); + tuple = binop; + auto p0 = t.Asm().template Projection<0>(binop, rep32); + auto p1 = t.Asm().template Projection<1>(binop, rep32); + proj0 = p0; + proj1 = p1; + + // MakeTupleOp itself must have 0 uses. + EXPECT_TRUE(t.graph().Get(tuple).saturated_use_count.Is(0)); + // Both projections should initially have 0 uses despite being bundled in + // MakeTupleOp. + EXPECT_TRUE(t.graph().Get(proj0).saturated_use_count.Is(0)); + EXPECT_TRUE(t.graph().Get(proj1).saturated_use_count.Is(0)); + + // Adding a temporary consumer increments proj0's saturated_use_count to 1. + t.Asm().Word32Add(V<Word32>::Cast(proj0), a); + EXPECT_TRUE(t.graph().Get(proj0).saturated_use_count.Is(1)); + + // Removing the consumer decrements proj0's saturated_use_count back to 0. + t.graph().RemoveLast(); + EXPECT_TRUE(t.graph().Get(proj0).saturated_use_count.Is(0)); + + // Adding the actual consumer leaves saturated_use_count at 1. + consumer = t.Asm().Word32Add(V<Word32>::Cast(proj0), a); + EXPECT_TRUE(t.graph().Get(proj0).saturated_use_count.Is(1)); + EXPECT_TRUE( + t.graph().Get(consumer).IsOnlyUserOf(t.graph().Get(proj0), t.graph())); + + // Adding and removing a MakeTupleOp leaves proj0's saturated_use_count + // unchanged at 1. + t.Asm().MakeTuple(proj0, proj1); + t.graph().RemoveLast(); + EXPECT_TRUE(t.graph().Get(proj0).saturated_use_count.Is(1)); + + t.Asm().Return(consumer); + }); + + const Graph& graph = test.graph(); + const Operation& tuple_op = graph.Get(tuple); + EXPECT_TRUE(tuple_op.Is<MakeTupleOp>()); + EXPECT_TRUE(tuple_op.saturated_use_count.Is(0)); + + const Operation& proj0_op = graph.Get(proj0); + const Operation& proj1_op = graph.Get(proj1); + EXPECT_TRUE(proj0_op.Is<ProjectionOp>()); + EXPECT_TRUE(proj1_op.Is<ProjectionOp>()); + EXPECT_TRUE(proj0_op.saturated_use_count.Is(1)); + EXPECT_TRUE(proj1_op.saturated_use_count.Is(0)); + EXPECT_TRUE(graph.Get(consumer).IsOnlyUserOf(proj0_op, graph)); + + // Verify UseMap ignores MakeTupleOp: unused projection has no uses, and used + // projection has only consumer (not MakeTupleOp). + UseMap use_map(graph, test.zone()); + EXPECT_TRUE(use_map.uses(proj1).empty()); + auto proj0_uses = use_map.uses(proj0); + ASSERT_EQ(proj0_uses.size(), 1u); + EXPECT_EQ(proj0_uses[0], consumer); +} + +#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64) || \ + defined(V8_TARGET_ARCH_LOONG64) || defined(V8_TARGET_ARCH_MIPS64) +TEST_F(MachineOptimizationReducerTest, ReduceNestedWord64Add128ToWord64Add3) { + const RegisterRepresentation rep64 = RegisterRepresentation::Word64(); + base::SmallVector<RegisterRepresentation, 3> reps = {rep64, rep64, rep64}; + auto test = CreateFromGraph(base::VectorOf(reps), [](auto& t) { + auto a = t.template GetParameter<Word64>(0); + auto b = t.template GetParameter<Word64>(1); + auto c = t.template GetParameter<Word64>(2); + auto zero = t.Asm().Word64Constant(uint64_t{0}); + + auto add1 = t.Asm().Add128(a, zero, b, zero); + auto add1_low = t.Asm().template Projection<0>(add1); + auto add1_high = t.Asm().template Projection<1>(add1); + + auto add2 = t.Asm().Add128(add1_low, add1_high, c, zero); + auto sum = t.Asm().template Projection<0>(add2); + t.Asm().Return(sum); + }); + + test.Run<MachineOptimizationReducer>(); + + bool found_add3 = false; + for (OpIndex index : test.graph().AllOperationIndices()) { + if (test.graph().Get(index).Is<Word64Add3Op>()) { + found_add3 = true; + break; + } + } + EXPECT_TRUE(found_add3); +} +#endif + +TEST_F(MachineOptimizationReducerTest, SelfComparisonLessThanOrEqual) { + { + // Word32 + const RegisterRepresentation rep32 = RegisterRepresentation::Word32(); + base::SmallVector<RegisterRepresentation, 1> reps = {rep32}; + for (ComparisonOp::Kind kind : + {ComparisonOp::Kind::kSignedLessThanOrEqual, + ComparisonOp::Kind::kUnsignedLessThanOrEqual}) { + auto test = CreateFromGraph(base::VectorOf(reps), [kind](auto& t) { + auto x = t.template GetParameter<Word32>(0); + auto cmp = + t.Asm().Comparison(x, x, kind, RegisterRepresentation::Word32()); + t.Asm().Return(cmp); + }); + + test.Run<MachineOptimizationReducer>(); + + const ReturnOp* ret = test.graph() + .Get(test.graph().LastOperation()) + .template TryCast<ReturnOp>(); + ASSERT_NE(ret, nullptr); + ASSERT_EQ(ret->return_values().size(), 1u); + + const ConstantOp* constant = test.graph() + .Get(ret->return_values()[0]) + .template TryCast<ConstantOp>(); + ASSERT_NE(constant, nullptr); + EXPECT_EQ(constant->kind, ConstantOp::Kind::kWord32); + EXPECT_EQ(constant->word32(), 1u); + EXPECT_EQ(test.CountOp(Opcode::kComparison), 0u); + } + } + { + // Word64 + const RegisterRepresentation rep64 = RegisterRepresentation::Word64(); + base::SmallVector<RegisterRepresentation, 1> reps = {rep64}; + for (ComparisonOp::Kind kind : + {ComparisonOp::Kind::kSignedLessThanOrEqual, + ComparisonOp::Kind::kUnsignedLessThanOrEqual}) { + auto test = CreateFromGraph(base::VectorOf(reps), [kind](auto& t) { + auto x = t.template GetParameter<Word64>(0); + auto cmp = + t.Asm().Comparison(x, x, kind, RegisterRepresentation::Word64()); + t.Asm().Return(cmp); + }); + + test.Run<MachineOptimizationReducer>(); + + const ReturnOp* ret = test.graph() + .Get(test.graph().LastOperation()) + .template TryCast<ReturnOp>(); + ASSERT_NE(ret, nullptr); + ASSERT_EQ(ret->return_values().size(), 1u); + + const ConstantOp* constant = test.graph() + .Get(ret->return_values()[0]) + .template TryCast<ConstantOp>(); + ASSERT_NE(constant, nullptr); + EXPECT_EQ(constant->kind, ConstantOp::Kind::kWord32); + EXPECT_EQ(constant->word32(), 1u); + EXPECT_EQ(test.CountOp(Opcode::kComparison), 0u); + } + } +} + +TEST_F(MachineOptimizationReducerTest, SelfComparisonLessThan) { + { + // Word32 + const RegisterRepresentation rep32 = RegisterRepresentation::Word32(); + base::SmallVector<RegisterRepresentation, 1> reps = {rep32}; + for (ComparisonOp::Kind kind : {ComparisonOp::Kind::kSignedLessThan, + ComparisonOp::Kind::kUnsignedLessThan}) { + auto test = CreateFromGraph(base::VectorOf(reps), [kind](auto& t) { + auto x = t.template GetParameter<Word32>(0); + auto cmp = + t.Asm().Comparison(x, x, kind, RegisterRepresentation::Word32()); + t.Asm().Return(cmp); + }); + + test.Run<MachineOptimizationReducer>(); + + const ReturnOp* ret = test.graph() + .Get(test.graph().LastOperation()) + .template TryCast<ReturnOp>(); + ASSERT_NE(ret, nullptr); + ASSERT_EQ(ret->return_values().size(), 1u); + + const ConstantOp* constant = test.graph() + .Get(ret->return_values()[0]) + .template TryCast<ConstantOp>(); + ASSERT_NE(constant, nullptr); + EXPECT_EQ(constant->kind, ConstantOp::Kind::kWord32); + EXPECT_EQ(constant->word32(), 0u); + EXPECT_EQ(test.CountOp(Opcode::kComparison), 0u); + } + } + { + // Word64 + const RegisterRepresentation rep64 = RegisterRepresentation::Word64(); + base::SmallVector<RegisterRepresentation, 1> reps = {rep64}; + for (ComparisonOp::Kind kind : {ComparisonOp::Kind::kSignedLessThan, + ComparisonOp::Kind::kUnsignedLessThan}) { + auto test = CreateFromGraph(base::VectorOf(reps), [kind](auto& t) { + auto x = t.template GetParameter<Word64>(0); + auto cmp = + t.Asm().Comparison(x, x, kind, RegisterRepresentation::Word64()); + t.Asm().Return(cmp); + }); + + test.Run<MachineOptimizationReducer>(); + + const ReturnOp* ret = test.graph() + .Get(test.graph().LastOperation()) + .template TryCast<ReturnOp>(); + ASSERT_NE(ret, nullptr); + ASSERT_EQ(ret->return_values().size(), 1u); + + const ConstantOp* constant = test.graph() + .Get(ret->return_values()[0]) + .template TryCast<ConstantOp>(); + ASSERT_NE(constant, nullptr); + EXPECT_EQ(constant->kind, ConstantOp::Kind::kWord32); + EXPECT_EQ(constant->word32(), 0u); + EXPECT_EQ(test.CountOp(Opcode::kComparison), 0u); + } + } +} + } // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/test/unittests/compiler/turboshaft/reducer-test.h b/deps/v8/test/unittests/compiler/turboshaft/reducer-test.h index 778254cd8153..cd634bc74034 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/reducer-test.h +++ b/deps/v8/test/unittests/compiler/turboshaft/reducer-test.h @@ -332,16 +332,12 @@ class ReducerTest : public TestWithNativeContextAndZone { const testing::TestInfo* test_info = testing::UnitTest::GetInstance()->current_test_info(); std::stringstream file_name; - const char* debug_name = test_info->name(); - size_t debug_name_len = std::strlen(debug_name); - CodeKind code_kind = is_wasm ? CodeKind::WASM_FUNCTION : CodeKind::FOR_TESTING_JS; TurboshaftPipelineKind pipeline_kind = is_wasm ? TurboshaftPipelineKind::kWasm : TurboshaftPipelineKind::kJS; - info_.reset(new OptimizedCompilationInfo( - base::Vector<const char>(debug_name, debug_name_len), this->zone(), - code_kind)); + info_.reset(new OptimizedCompilationInfo(test_info->name(), this->zone(), + code_kind)); AssemblerOptions options = AssemblerOptions::Default(this->isolate()); options.is_wasm = is_wasm; pipeline_data_.reset(new turboshaft::PipelineData( diff --git a/deps/v8/test/unittests/compiler/turboshaft/turboshaft-typer-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/turboshaft-typer-unittest.cc index d5f3ed517d9a..9ebc2dfbe295 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/turboshaft-typer-unittest.cc +++ b/deps/v8/test/unittests/compiler/turboshaft/turboshaft-typer-unittest.cc @@ -339,6 +339,55 @@ TYPED_TEST(FloatTyperTest, Divide) { EXPECT_DIV(Set({-inf, inf}), Set({-inf, inf}), T::NaN()); } +TYPED_TEST(FloatTyperTest, SetWithSpecialsAndOverflow) { + DEFINE_TEST_HELPERS() + + // 1. Set with NaN, -0.0, duplicate values, and out-of-order floats. + { + std::vector<float_t> raw_elements = {nan, + static_cast<float_t>(42.0), + static_cast<float_t>(-0.0), + static_cast<float_t>(-5.0), + nan, + static_cast<float_t>(-0.0), + static_cast<float_t>(42.0)}; + auto result = FloatOperationTyper<TestFixture::Bits>::Set(raw_elements, 0, + this->zone()); + EXPECT_TRUE(result.has_nan()); + EXPECT_TRUE(result.has_minus_zero()); + EXPECT_TRUE(result.Contains(static_cast<float_t>(42.0))); + EXPECT_TRUE(result.Contains(static_cast<float_t>(-5.0))); + EXPECT_FALSE(result.Contains(static_cast<float_t>(0.0))); + EXPECT_FALSE(result.Contains(static_cast<float_t>(1.0))); + } + + // 2. Set with only NaN and -0.0. + { + std::vector<float_t> raw_elements = {nan, static_cast<float_t>(-0.0), nan}; + auto result = FloatOperationTyper<TestFixture::Bits>::Set(raw_elements, 0, + this->zone()); + EXPECT_TRUE(result.is_only_special_values()); + EXPECT_TRUE(result.has_nan()); + EXPECT_TRUE(result.has_minus_zero()); + } + + // 3. Set with elements exceeding kMaxSetSize -> converts to Range. + { + std::vector<float_t> raw_elements; + for (int i = 0; i < T::kMaxSetSize + 5; ++i) { + raw_elements.push_back(static_cast<float_t>(i * 10)); + } + auto result = FloatOperationTyper<TestFixture::Bits>::Set(raw_elements, 0, + this->zone()); + EXPECT_TRUE(result.is_range()); + EXPECT_EQ(result.range_min(), static_cast<float_t>(0.0)); + EXPECT_EQ(result.range_max(), + static_cast<float_t>((T::kMaxSetSize + 4) * 10)); + EXPECT_TRUE(result.Contains(static_cast<float_t>(20.0))); + EXPECT_TRUE(result.Contains(static_cast<float_t>(15.0))); // inside range + } +} + #undef DEFINE_TEST_HELPERS } // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/test/unittests/compiler/turboshaft/turboshaft-types-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/turboshaft-types-unittest.cc index 2ad6a9d476e1..ba11aebc515b 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/turboshaft-types-unittest.cc +++ b/deps/v8/test/unittests/compiler/turboshaft/turboshaft-types-unittest.cc @@ -782,4 +782,127 @@ TEST_F(TurboshaftTypesTest, Float64LeastUpperBound) { } } +TEST_F(TurboshaftTypesTest, WordIntersectWrappingRanges) { + const auto max32 = std::numeric_limits<uint32_t>::max(); + + // Case 1: Disjoint wrapping ranges (no overlap in the middle): + // lhs: |-------| |---| + // lhs_to (50) lhs_from (max - 100) + // + // rhs: |---| |------------| + // rhs_to (20) rhs_from (max - 200) + // + // res: |---| |---| + // res_to (20) res_from (max - 100) + { + Word32Type lhs = Word32Type::Range(max32 - 100, 50, zone()); + Word32Type rhs = Word32Type::Range(max32 - 200, 20, zone()); + EXPECT_TRUE(lhs.is_wrapping()); + EXPECT_TRUE(rhs.is_wrapping()); + + Type res = Word32Type::Intersect( + lhs, rhs, Type::ResolutionMode::kPreciseOrInvalid, zone()); + ASSERT_TRUE(res.IsWord32()); + EXPECT_TRUE(res.AsWord32().is_wrapping()); + EXPECT_TRUE( + res.AsWord32().Equals(Word32Type::Range(max32 - 100, 20, zone()))); + EXPECT_TRUE(res.AsWord32().Contains(0)); + EXPECT_TRUE(res.AsWord32().Contains(20)); + EXPECT_FALSE(res.AsWord32().Contains(21)); + EXPECT_FALSE(res.AsWord32().Contains(max32 - 101)); + EXPECT_TRUE(res.AsWord32().Contains(max32 - 100)); + EXPECT_TRUE(res.AsWord32().Contains(max32)); + } + + // Case 2: Overlapping wrapping ranges (producing 3 disconnected intervals): + // lhs: |-------------------| | + // lhs_to lhs_from (max) + // + // rhs: |-------| |----------------------| + // rhs_to rhs_from + // + // res: |-------| |------| | + // (not representable as a single range) + // + // Middle interval [2126514467, 2438280307] is in both lhs and rhs. + { + Word32Type lhs = Word32Type::Range(4294967295u, 2438280307u, zone()); + Word32Type rhs = Word32Type::Range(2126514467u, 829474146u, zone()); + EXPECT_TRUE(lhs.is_wrapping()); + EXPECT_TRUE(rhs.is_wrapping()); + + // In PreciseOrInvalid mode, must return Invalid since 3 intervals cannot be + // represented. + Type res_precise = Word32Type::Intersect( + lhs, rhs, Type::ResolutionMode::kPreciseOrInvalid, zone()); + EXPECT_TRUE(res_precise.IsInvalid()); + + // In OverApproximate mode, the returned type must contain all points in + // both lhs and rhs, including the middle intersection point 2438280307u. + Type res_over = Word32Type::Intersect( + lhs, rhs, Type::ResolutionMode::kOverApproximate, zone()); + ASSERT_TRUE(res_over.IsWord32()); + EXPECT_TRUE(res_over.AsWord32().is_wrapping()); + EXPECT_TRUE(lhs.Contains(2438280307u)); + EXPECT_TRUE(rhs.Contains(2438280307u)); + EXPECT_TRUE(res_over.AsWord32().Contains(2438280307u)); + EXPECT_TRUE(res_over.AsWord32().Contains(0u)); + EXPECT_TRUE(res_over.AsWord32().Contains(4294967295u)); + + // In GreatestLowerBound mode, returns the wrapping candidate + // [max, min(lhs_to, rhs_to)] = [4294967295, 829474146]. + Type res_glb = Word32Type::Intersect( + lhs, rhs, Type::ResolutionMode::kGreatestLowerBound, zone()); + ASSERT_TRUE(res_glb.IsWord32()); + EXPECT_TRUE(res_glb.AsWord32().is_wrapping()); + EXPECT_TRUE(res_glb.AsWord32().Contains(0u)); + EXPECT_TRUE(res_glb.AsWord32().Contains(4294967295u)); + EXPECT_FALSE(res_glb.AsWord32().Contains(2438280307u)); + } + + // Case 3: Small wrapping range intersection that normalizes to a Set: + // lhs: | |---| + // lhs_to (0) lhs_from (max - 10) + // + // rhs: |-------| | + // rhs_to (100) rhs_from (max) + // + // res: | | + // res_to (0) res_from (max) + // -> {0, max} (normalized to Set) + { + Word32Type lhs = Word32Type::Range(max32 - 10, 0, zone()); + Word32Type rhs = Word32Type::Range(max32, 100, zone()); + EXPECT_TRUE(lhs.is_wrapping()); + EXPECT_TRUE(rhs.is_wrapping()); + + Type res = Word32Type::Intersect( + lhs, rhs, Type::ResolutionMode::kPreciseOrInvalid, zone()); + ASSERT_TRUE(res.IsWord32()); + EXPECT_TRUE(res.AsWord32().is_set()); + EXPECT_EQ(res.AsWord32().set_size(), 2); + EXPECT_TRUE(res.AsWord32().Contains(0)); + EXPECT_TRUE(res.AsWord32().Contains(max32)); + EXPECT_FALSE(res.AsWord32().Contains(1)); + EXPECT_FALSE(res.AsWord32().Contains(max32 - 1)); + } + + // 4. Same test with Word64Type + const auto max64 = std::numeric_limits<uint64_t>::max(); + { + Word64Type lhs = Word64Type::Range(max64 - 10, 0, zone()); + Word64Type rhs = Word64Type::Range(max64, 100, zone()); + EXPECT_TRUE(lhs.is_wrapping()); + EXPECT_TRUE(rhs.is_wrapping()); + + Type res = Word64Type::Intersect( + lhs, rhs, Type::ResolutionMode::kPreciseOrInvalid, zone()); + ASSERT_TRUE(res.IsWord64()); + EXPECT_TRUE(res.AsWord64().is_set()); + EXPECT_EQ(res.AsWord64().set_size(), 2); + EXPECT_TRUE(res.AsWord64().Contains(0)); + EXPECT_TRUE(res.AsWord64().Contains(max64)); + } +} + } // namespace v8::internal::compiler::turboshaft diff --git a/deps/v8/test/unittests/compiler/turboshaft/wasm-shuffle-reducer-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/wasm-shuffle-reducer-unittest.cc index 09e46cf73ab6..2fd964bcd427 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/wasm-shuffle-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/turboshaft/wasm-shuffle-reducer-unittest.cc @@ -5,6 +5,7 @@ #include "src/compiler/turboshaft/wasm-shuffle-reducer.h" #include "src/base/vector.h" +#include "src/compiler/backend/simd-shuffle.h" #include "src/compiler/turboshaft/assembler.h" #include "src/compiler/turboshaft/copying-phase.h" #include "src/compiler/turboshaft/dead-code-elimination-reducer.h" @@ -1238,6 +1239,115 @@ TEST_F(ReducerTest, ShuffleTwoShuffles) { } } +namespace { +SimdShuffle::ShuffleArray<kSimd128Size> Mask( + const SimdShuffle::CanonicalShuffle shuffle) { + const std::optional<SimdShuffle::ShuffleArray<kSimd128Size>> byte_mask = + SimdShuffle::TryGetCanonicalMask(shuffle); + CHECK(byte_mask.has_value()); + return *byte_mask; +} +} // namespace + +TEST_F(ReducerTest, NarrowShuffle) { + using Unary = Simd128UnaryOp::Kind; + using Binary = Simd128BinopOp::Kind; + using Shuffle = SimdShuffle::ShuffleArray<>; + using CanonicalShuffle = SimdShuffle::CanonicalShuffle; + + struct Config { + Unary left_extend; + Unary right_extend; + Shuffle lower_shuffle; + Shuffle upper_shuffle; + Binary narrow; + bool expect_reduced; + Shuffle expected_shuffle{}; + }; + + const Shuffle zip8_low = Mask(CanonicalShuffle::kS8x16InterleaveLowHalves); + const Shuffle zip16_low = Mask(CanonicalShuffle::kS16x8InterleaveLowHalves); + const Shuffle zip16_high = Mask(CanonicalShuffle::kS16x8InterleaveHighHalves); + const Shuffle zip32_low = Mask(CanonicalShuffle::kS32x4InterleaveLowHalves); + const Shuffle zip32_high = Mask(CanonicalShuffle::kS32x4InterleaveHighHalves); + + const Config configs[] = { + {Unary::kI16x8SConvertI8x16Low, Unary::kI16x8SConvertI8x16Low, zip16_low, + zip16_high, Binary::kI8x16SConvertI16x8, true, zip8_low}, + {Unary::kI16x8UConvertI8x16Low, Unary::kI16x8UConvertI8x16Low, zip16_low, + zip16_high, Binary::kI8x16UConvertI16x8, true, zip8_low}, + {Unary::kI32x4SConvertI16x8Low, Unary::kI32x4SConvertI16x8Low, zip32_low, + zip32_high, Binary::kI16x8SConvertI32x4, true, zip16_low}, + {Unary::kI32x4UConvertI16x8Low, Unary::kI32x4UConvertI16x8Low, zip32_low, + zip32_high, Binary::kI16x8UConvertI32x4, true, zip16_low}, + // Right extend's signedness mismatches from narrowing. + {Unary::kI16x8SConvertI8x16Low, Unary::kI16x8UConvertI8x16Low, zip16_low, + zip16_high, Binary::kI8x16SConvertI16x8, false}, + // Right extend's lane size mismatches from narrowing. + {Unary::kI16x8SConvertI8x16Low, Unary::kI32x4SConvertI16x8Low, zip16_low, + zip16_high, Binary::kI8x16SConvertI16x8, false}, + // Both extends' lane size mismatches from narrowing. + {Unary::kI16x8SConvertI8x16Low, Unary::kI16x8SConvertI8x16Low, zip16_low, + zip16_high, Binary::kI16x8SConvertI32x4, false}, + // Lower/upper shuffle's lane size mismatches from widening operations. + {Unary::kI32x4SConvertI16x8Low, Unary::kI32x4SConvertI16x8Low, zip16_low, + zip32_high, Binary::kI16x8SConvertI32x4, false}, + {Unary::kI32x4SConvertI16x8Low, Unary::kI32x4SConvertI16x8Low, zip32_low, + zip16_high, Binary::kI16x8SConvertI32x4, false}}; + + const RegisterRepresentation reps[] = {RegisterRepresentation::Simd128(), + RegisterRepresentation::Simd128()}; + + for (const Config& config : configs) { + SCOPED_TRACE(config.left_extend); + SCOPED_TRACE(config.right_extend); + SCOPED_TRACE(::testing::PrintToString(config.lower_shuffle)); + SCOPED_TRACE(::testing::PrintToString(config.upper_shuffle)); + SCOPED_TRACE(config.narrow); + + auto test = CreateFromGraph(base::VectorOf(reps), [&](auto& Asm) { + constexpr auto kind = Simd128ShuffleOp::Kind::kI8x16; + OpIndex lhs = Asm.Capture(Asm.template GetParameter<Simd128>(0), "lhs"); + OpIndex rhs = Asm.Capture(Asm.template GetParameter<Simd128>(1), "rhs"); + OpIndex wide_left = __ Simd128Unary(lhs, config.left_extend); + OpIndex wide_right = __ Simd128Unary(rhs, config.right_extend); + OpIndex first_shuffle = __ Simd128Shuffle(wide_left, wide_right, kind, + config.lower_shuffle.data()); + OpIndex second_shuffle = __ Simd128Shuffle(wide_left, wide_right, kind, + config.upper_shuffle.data()); + OpIndex narrow = Asm.Capture( + __ Simd128Binop(first_shuffle, second_shuffle, config.narrow), + "narrow"); + __ Return(narrow); + }); + + WasmShuffleAnalyzer analyzer(test.zone(), test.graph()); + analyzer.Run(); + const auto* narrow = test.GetCapture("narrow").GetAs<Simd128BinopOp>(); + ASSERT_NE(narrow, nullptr); + EXPECT_EQ(analyzer.GetNarrowShuffleCandidate(test.graph().Index(*narrow)) + .has_value(), + config.expect_reduced); + test.Run<WasmShuffleReducer>(); + test.Run<DeadCodeEliminationReducer>(); + + if (!config.expect_reduced) { + EXPECT_TRUE(test.GetCapture("narrow").GetAs<Simd128BinopOp>()); + continue; + } + const auto* shuffle = test.GetCapture("narrow").GetAs<Simd128ShuffleOp>(); + ASSERT_TRUE(shuffle); + EXPECT_EQ(shuffle->kind, Simd128ShuffleOp::Kind::kI8x16); + EXPECT_EQ(shuffle->shuffle, config.expected_shuffle); + EXPECT_TRUE(test.GetCapture("lhs").Is(shuffle->left())); + EXPECT_TRUE(test.GetCapture("rhs").Is(shuffle->right())); + EXPECT_EQ(test.CountOp(Opcode::kSimd128Binop), 0u); + EXPECT_EQ(test.CountOp(Opcode::kSimd128Unary), 0u); + EXPECT_EQ(test.CountOp(Opcode::kSimd128Shuffle), 1u); + EXPECT_TRUE(analyzer.ShouldReduce()); + } +} + TEST_F(ReducerTest, I32x4AddReduceOfDotI8x16S) { auto test = CreateFromGraph(1, [](auto& Asm) { constexpr auto SplatKind = Simd128SplatOp::Kind::kI8x16; diff --git a/deps/v8/test/unittests/compiler/turboshaft/wasm-simd-unittest.cc b/deps/v8/test/unittests/compiler/turboshaft/wasm-simd-unittest.cc index 6fc0fff31054..ca7a9480a7c2 100644 --- a/deps/v8/test/unittests/compiler/turboshaft/wasm-simd-unittest.cc +++ b/deps/v8/test/unittests/compiler/turboshaft/wasm-simd-unittest.cc @@ -7,6 +7,7 @@ #include "src/compiler/turboshaft/assembler.h" #include "src/compiler/turboshaft/copying-phase.h" #include "src/compiler/turboshaft/dead-code-elimination-reducer.h" +#include "src/compiler/turboshaft/instruction-selection-normalization-reducer.h" #include "src/compiler/turboshaft/machine-optimization-reducer.h" #include "src/compiler/turboshaft/operations.h" #include "src/compiler/turboshaft/representations.h" @@ -202,7 +203,7 @@ TEST_F(WasmSimdTest, SingleExtMulI8Dot) { __ Simd128Binop(left, right, Simd128BinopOp::Kind::kI32x4DotI16x8S)); }); - test.Run<MachineOptimizationReducer>(); + test.Run<InstructionSelectionNormalizationReducer>(); test.Run<DeadCodeEliminationReducer>(); ASSERT_EQ(test.CountOp(Opcode::kSimd128Unary), 1u); @@ -222,7 +223,7 @@ TEST_F(WasmSimdTest, AddPairwiseMulI8Dot) { __ Simd128Binop(left, right, Simd128BinopOp::Kind::kI32x4DotI16x8S)); }); - test.Run<MachineOptimizationReducer>(); + test.Run<InstructionSelectionNormalizationReducer>(); test.Run<DeadCodeEliminationReducer>(); #ifdef V8_TARGET_ARCH_ARM64 @@ -258,7 +259,7 @@ TEST_F(WasmSimdTest, AddExtMulPairwiseToI8x16DotProduct) { __ Return(add); }); - test.Run<MachineOptimizationReducer>(); + test.Run<InstructionSelectionNormalizationReducer>(); test.Run<DeadCodeEliminationReducer>(); constexpr uint8_t expected_shuffle[kSimd128Size] = { diff --git a/deps/v8/test/unittests/compiler/wasm-address-reassociation-unittest.cc b/deps/v8/test/unittests/compiler/wasm-address-reassociation-unittest.cc deleted file mode 100644 index bc00196b5736..000000000000 --- a/deps/v8/test/unittests/compiler/wasm-address-reassociation-unittest.cc +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2023 the V8 project 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 "src/compiler/wasm-address-reassociation.h" - -#include "src/compiler/js-graph.h" -#include "src/compiler/machine-operator-reducer.h" -#include "src/compiler/node.h" -#include "test/unittests/compiler/graph-unittest.h" -#include "test/unittests/compiler/node-test-utils.h" -#include "testing/gmock-support.h" - -namespace v8 { -namespace internal { -namespace compiler { - -class WasmAddressReassociationTest : public GraphTest { - public: - WasmAddressReassociationTest() - : GraphTest(3), - machine_(zone()), - javascript_(zone()), - jsgraph_(isolate(), graph(), common(), &javascript_, nullptr, - &machine_), - ar_(&jsgraph_, zone()), - trapping_load_op_(machine()->TrappingLoad(MachineType::Int32())), - trapping_store_op_( - machine()->TrappingStore(MachineRepresentation::kWord32)), - base_(graph()->NewNode(common()->Parameter(0), graph()->start())), - offset_(graph()->NewNode(common()->Parameter(1), graph()->start())) {} - - ~WasmAddressReassociationTest() override = default; - - protected: - MachineOperatorBuilder* machine() { return &machine_; } - WasmAddressReassociation* ar() { return &ar_; } - Node* Int32Constant(int32_t value) { - return graph()->NewNode(common()->Int32Constant(value)); - } - Node* Int64Constant(int64_t value) { - return graph()->NewNode(common()->Int64Constant(value)); - } - Node* Int32Add(Node* lhs, Node* rhs) { - return graph()->NewNode(machine()->Int32Add(), lhs, rhs); - } - Node* Int64Add(Node* lhs, Node* rhs) { - return graph()->NewNode(machine()->Int64Add(), lhs, rhs); - } - Node* ExtendAdd(Node* lhs, Node* rhs) { - Node* add = Int32Add(lhs, rhs); - return graph()->NewNode(machine()->ChangeUint32ToUint64(), add); - } - Node* TrappingLoad(Node* base, Node* offset, Node* effect, Node* control) { - return graph()->NewNode(trapping_load_op_, base, offset, effect, control); - } - Node* TrappingStore(Node* base, Node* offset, Node* val, Node* effect, - Node* control) { - return graph()->NewNode(trapping_store_op_, base, offset, val, effect, - control); - } - void CheckEffectChain(Node* effect_op, Node* end, - std::vector<int64_t>& expected_offsets) { - std::vector<NodeId> base_addrs; - std::vector<int64_t> offsets; - std::set<NodeId> all_visited; - std::vector<Node*> effect_nodes = {effect_op}; - while (!effect_nodes.empty()) { - effect_op = effect_nodes.back(); - effect_nodes.pop_back(); - if (all_visited.count(effect_op->id())) continue; - if (effect_op == end) continue; - - all_visited.insert(effect_op->id()); - for (int i = 0; i < effect_op->op()->EffectInputCount(); ++i) { - effect_nodes.push_back(NodeProperties::GetEffectInput(effect_op, i)); - } - - if (effect_op->opcode() == IrOpcode::kTrappingLoad || - effect_op->opcode() == IrOpcode::kTrappingStore) { - Node* add = effect_op->InputAt(0); - EXPECT_EQ(add->opcode(), IrOpcode::kInt64Add); - EXPECT_TRUE(add->InputAt(0) == base_); - EXPECT_TRUE(add->InputAt(1) == offset_); - Node* offset = effect_op->InputAt(1); - EXPECT_TRUE(NodeProperties::IsConstant(offset)); - base_addrs.push_back(add->id()); - offsets.push_back(OpParameter<int64_t>(offset->op())); - } - } - EXPECT_EQ(base_addrs.size(), expected_offsets.size()); - EXPECT_TRUE(std::adjacent_find(base_addrs.begin(), base_addrs.end(), - std::not_equal_to<>()) == base_addrs.end()); - EXPECT_EQ(offsets, expected_offsets); - } - Node* base() const { return base_; } - Node* offset() const { return offset_; } - - private: - MachineOperatorBuilder machine_; - JSOperatorBuilder javascript_; - JSGraph jsgraph_; - WasmAddressReassociation ar_; - const Operator* trapping_load_op_; - const Operator* trapping_store_op_; - Node* base_; - Node* offset_; -}; - -TEST_F(WasmAddressReassociationTest, TrappingBase) { - if (machine()->Is32()) return; - - Node* control = graph()->start(); - Node* effect = graph()->start(); - NodeId effect_id = effect->id(); - for (unsigned i = 0; i < 3; ++i) { - Node* index = Int64Constant((i + 1) * 8); - Node* object = Int64Add(base(), index); - Node* load = TrappingLoad(object, offset(), effect, control); - Node* store = TrappingStore(object, offset(), load, load, control); - ar()->VisitTrappingMemOp(load, effect_id); - ar()->VisitTrappingMemOp(store, effect_id); - effect = store; - } - graph()->end()->InsertInput(zone(), 0, effect); - ar()->Optimize(); - std::vector<int64_t> offsets = {24, 24, 16, 16, 8, 8}; - CheckEffectChain(effect, graph()->start(), offsets); -} - -TEST_F(WasmAddressReassociationTest, TrappingIndex) { - if (machine()->Is32()) return; - - Node* control = graph()->start(); - Node* effect = graph()->start(); - NodeId effect_id = effect->id(); - for (int64_t i = 0; i < 3; ++i) { - Node* index = Int64Constant((i + 1) * -8); - Node* add = Int64Add(offset(), index); - Node* load = TrappingLoad(base(), add, effect, control); - Node* store = TrappingStore(base(), add, load, load, control); - ar()->VisitTrappingMemOp(load, effect_id); - ar()->VisitTrappingMemOp(store, effect_id); - effect = store; - } - graph()->end()->InsertInput(zone(), 0, effect); - ar()->Optimize(); - std::vector<int64_t> offsets = {-24, -24, -16, -16, -8, -8}; - CheckEffectChain(effect, graph()->start(), offsets); -} - -TEST_F(WasmAddressReassociationTest, TrappingBaseIndex) { - if (machine()->Is32()) return; - - Node* control = graph()->start(); - Node* effect = graph()->start(); - NodeId effect_id = effect->id(); - for (unsigned i = 0; i < 3; ++i) { - Node* base_add = Int64Add(base(), Int64Constant(i * 4)); - Node* index_add = Int64Add(offset(), Int64Constant((i + 1) * 8)); - Node* load = TrappingLoad(base_add, index_add, effect, control); - Node* store = TrappingStore(base_add, index_add, load, load, control); - ar()->VisitTrappingMemOp(load, effect_id); - ar()->VisitTrappingMemOp(store, effect_id); - effect = store; - } - graph()->end()->InsertInput(zone(), 0, effect); - ar()->Optimize(); - std::vector<int64_t> offsets = {32, 32, 20, 20, 8, 8}; - CheckEffectChain(effect, graph()->start(), offsets); -} - -TEST_F(WasmAddressReassociationTest, TrappingExtendIndex) { - if (machine()->Is32()) return; - - Node* control = graph()->start(); - Node* effect = graph()->start(); - NodeId effect_id = effect->id(); - for (unsigned i = 0; i < 3; ++i) { - Node* index = Int32Constant(8); - Node* add = ExtendAdd(offset(), index); - Node* load = TrappingLoad(base(), add, effect, control); - Node* store = TrappingStore(base(), add, load, load, control); - ar()->VisitTrappingMemOp(load, effect_id); - ar()->VisitTrappingMemOp(store, effect_id); - effect = store; - } - graph()->end()->InsertInput(zone(), 0, effect); - ar()->Optimize(); - - while (effect && effect != graph()->start()) { - EXPECT_FALSE(NodeProperties::IsConstant(effect->InputAt(1))); - effect = NodeProperties::GetEffectInput(effect, 0); - } -} - -TEST_F(WasmAddressReassociationTest, Diamond) { - if (machine()->Is32()) return; - - // start - // 3 loads - // branch - // if_true - // 3 loads - // if_false - // 3 stores - // merge - // 3 loads - auto SequentialLoads = [this](size_t N, Node* effect_chain, Node* control_in, - Node* effect_region) { - NodeId effect_region_id = effect_region->id(); - for (unsigned i = 0; i < N; ++i) { - size_t current_offset = 8 * (i + 1); - Node* add = Int64Add(base(), Int64Constant(current_offset)); - Node* load = TrappingLoad(add, offset(), effect_chain, control_in); - ar()->VisitTrappingMemOp(load, effect_region_id); - effect_chain = load; - } - return effect_chain; - }; - auto SequentialStores = [this](size_t N, Node* effect_chain, Node* control_in, - Node* effect_region) { - NodeId effect_region_id = effect_region->id(); - for (unsigned i = 0; i < N; ++i) { - size_t current_offset = 8 * (i + 1); - Node* add = Int64Add(offset(), Int64Constant(current_offset)); - Node* store = TrappingStore(base(), add, add, effect_chain, control_in); - ar()->VisitTrappingMemOp(store, effect_region_id); - effect_chain = store; - } - return effect_chain; - }; - Node* start = graph()->start(); - Node* effect = SequentialLoads(3, start, start, start); - Node* check = Parameter(Type::Boolean(), 1); - Node* branch = graph()->NewNode(common()->Branch(), check, start); - Node* etrue = effect; - Node* efalse = effect; - - Node* if_true = graph()->NewNode(common()->IfTrue(), branch); - etrue = SequentialLoads(3, etrue, if_true, start); - - Node* if_false = graph()->NewNode(common()->IfFalse(), branch); - efalse = SequentialStores(3, efalse, if_false, start); - - Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); - Node* effect_phi = - graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge); - Node* end = SequentialLoads(3, effect_phi, merge, effect_phi); - - ar()->Optimize(); - - // end to effect phi: 3 loads sharing base address. - std::vector<int64_t> offsets = {24, 16, 8}; - CheckEffectChain(end, effect_phi, offsets); - - // effect phi to start: 9 operations sharing base address. - offsets = {24, 16, 8, 24, 16, 8, 24, 16, 8}; - CheckEffectChain(effect_phi, start, offsets); -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/x64/turboshaft-instruction-selector-x64-unittest.cc b/deps/v8/test/unittests/compiler/x64/turboshaft-instruction-selector-x64-unittest.cc index 40f43ba878be..0086574e3283 100644 --- a/deps/v8/test/unittests/compiler/x64/turboshaft-instruction-selector-x64-unittest.cc +++ b/deps/v8/test/unittests/compiler/x64/turboshaft-instruction-selector-x64-unittest.cc @@ -14,6 +14,8 @@ #if V8_ENABLE_WEBASSEMBLY #include "src/compiler/backend/simd-shuffle.h" +#include "src/compiler/wasm-compiler-definitions.h" +#include "src/wasm/value-type.h" #endif // V8_ENABLE_WEBASSEMBLY namespace v8::internal::compiler::turboshaft { @@ -2984,7 +2986,250 @@ TEST_F(TurboshaftInstructionSelectorTest, SIMDF32x4SConvert) { EXPECT_EQ(1U, s[2]->OutputCount()); } +TEST_F(TurboshaftInstructionSelectorTest, F16x8FmaFallback) { #ifdef V8_ENABLE_AVX10_1 + FlagScope<bool> disable_avx10(&v8_flags.enable_avx10_1, false); +#endif + for (bool negate : {false, true}) { + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128(), MachineType::Simd128()); + auto kind = negate ? Simd128TernaryOp::Kind::kF16x8Qfms + : Simd128TernaryOp::Kind::kF16x8Qfma; + m.Return(m.Simd128Ternary(m.Parameter<Simd128>(0), m.Parameter<Simd128>(1), + m.Parameter<Simd128>(2), kind)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(negate ? kX64F16x8Qfms : kX64F16x8Qfma, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(2U, s[0]->TempCount()); + for (size_t i = 0; i < 3; ++i) { + const auto* input = UnallocatedOperand::cast(s[0]->InputAt(i)); + EXPECT_TRUE(input->HasRegisterPolicy()); + EXPECT_FALSE(input->IsUsedAtStart()); + } + } +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8AddFallback) { +#ifdef V8_ENABLE_AVX10_1 + FlagScope<bool> disable_avx10(&v8_flags.enable_avx10_1, false); +#endif + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + m.Return(m.F16x8Add(m.Parameter<Simd128>(0), m.Parameter<Simd128>(1))); + Stream s = m.Build(); + + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64FAdd, s[0]->arch_opcode()); + EXPECT_EQ(LaneSize::kL16, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(VectorLength::kV128, VectorLengthField::decode(s[0]->opcode())); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(2U, s[0]->TempCount()); + for (size_t i = 0; i < 2; ++i) { + const auto* input = UnallocatedOperand::cast(s[0]->InputAt(i)); + EXPECT_TRUE(input->HasRegisterPolicy()); + EXPECT_FALSE(input->IsUsedAtStart()); + } +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8SubFallback) { +#ifdef V8_ENABLE_AVX10_1 + FlagScope<bool> disable_avx10(&v8_flags.enable_avx10_1, false); +#endif + StreamBuilder builder(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + V<Simd128> lhs = builder.Parameter<Simd128>(0); + V<Simd128> rhs = builder.Parameter<Simd128>(1); + builder.Return(builder.F16x8Sub(lhs, rhs)); + Stream stream = builder.Build(); + + ASSERT_EQ(1U, stream.size()); + EXPECT_EQ(kX64FSub, stream[0]->arch_opcode()); + EXPECT_EQ(LaneSize::kL16, LaneSizeField::decode(stream[0]->opcode())); + EXPECT_EQ(VectorLength::kV128, + VectorLengthField::decode(stream[0]->opcode())); + ASSERT_EQ(2U, stream[0]->InputCount()); + EXPECT_EQ(1U, stream[0]->OutputCount()); + EXPECT_EQ(2U, stream[0]->TempCount()); + EXPECT_EQ(stream.ToVreg(lhs), stream.ToVreg(stream[0]->InputAt(0))); + EXPECT_EQ(stream.ToVreg(rhs), stream.ToVreg(stream[0]->InputAt(1))); + for (size_t index = 0; index < 2; ++index) { + const auto* input = UnallocatedOperand::cast(stream[0]->InputAt(index)); + EXPECT_TRUE(input->HasRegisterPolicy()); + EXPECT_FALSE(input->IsUsedAtStart()); + } +} + +#ifdef V8_ENABLE_AVX10_1 +TEST_F(TurboshaftInstructionSelectorTest, F16x8SubAVX10_1) { + if (!UseAvx10_1()) GTEST_SKIP() << "AVX10.1 must be supported and enabled"; + + StreamBuilder builder(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + V<Simd128> lhs = builder.Parameter<Simd128>(0); + V<Simd128> rhs = builder.Parameter<Simd128>(1); + builder.Return(builder.F16x8Sub(lhs, rhs)); + Stream stream = builder.Build(); + + ASSERT_EQ(1U, stream.size()); + EXPECT_EQ(kX64FSub, stream[0]->arch_opcode()); + EXPECT_EQ(LaneSize::kL16, LaneSizeField::decode(stream[0]->opcode())); + EXPECT_EQ(VectorLength::kV128, + VectorLengthField::decode(stream[0]->opcode())); + ASSERT_EQ(2U, stream[0]->InputCount()); + EXPECT_EQ(1U, stream[0]->OutputCount()); + EXPECT_EQ(0U, stream[0]->TempCount()); + EXPECT_TRUE( + UnallocatedOperand::cast(stream[0]->Output())->HasRegisterPolicy()); + EXPECT_EQ(stream.ToVreg(lhs), stream.ToVreg(stream[0]->InputAt(0))); + EXPECT_EQ(stream.ToVreg(rhs), stream.ToVreg(stream[0]->InputAt(1))); + for (size_t index = 0; index < 2; ++index) { + const auto* input = UnallocatedOperand::cast(stream[0]->InputAt(index)); + EXPECT_TRUE(input->HasRegisterPolicy()); + EXPECT_TRUE(input->IsUsedAtStart()); + } +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8SubRepeatedInputAVX10_1) { + if (!UseAvx10_1()) GTEST_SKIP() << "AVX10.1 must be supported and enabled"; + + StreamBuilder builder(this, MachineType::Simd128(), MachineType::Simd128()); + V<Simd128> input = builder.Parameter<Simd128>(0); + V<Simd128> difference = builder.F16x8Sub(input, input); + builder.Return(builder.F16x8Sub(input, difference)); + Stream stream = builder.Build(); + + ASSERT_EQ(2U, stream.size()); + for (size_t index = 0; index < stream.size(); ++index) { + EXPECT_EQ(kX64FSub, stream[index]->arch_opcode()); + EXPECT_EQ(LaneSize::kL16, LaneSizeField::decode(stream[index]->opcode())); + EXPECT_EQ(VectorLength::kV128, + VectorLengthField::decode(stream[index]->opcode())); + ASSERT_EQ(2U, stream[index]->InputCount()); + EXPECT_EQ(1U, stream[index]->OutputCount()); + EXPECT_EQ(0U, stream[index]->TempCount()); + EXPECT_TRUE( + UnallocatedOperand::cast(stream[index]->Output())->HasRegisterPolicy()); + EXPECT_TRUE( + UnallocatedOperand::cast(stream[index]->InputAt(0))->IsUsedAtStart()); + EXPECT_TRUE( + UnallocatedOperand::cast(stream[index]->InputAt(1))->IsUsedAtStart()); + } + EXPECT_EQ(stream.ToVreg(input), stream.ToVreg(stream[0]->InputAt(0))); + EXPECT_EQ(stream.ToVreg(input), stream.ToVreg(stream[0]->InputAt(1))); + EXPECT_EQ(stream.ToVreg(input), stream.ToVreg(stream[1]->InputAt(0))); + EXPECT_EQ(stream.ToVreg(stream[0]->Output()), + stream.ToVreg(stream[1]->InputAt(1))); +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8FmaAVX10_1) { + if (!UseAvx10_1()) GTEST_SKIP() << "AVX10.1 must be supported and enabled"; + + for (bool negate : {false, true}) { + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128(), MachineType::Simd128()); + auto kind = negate ? Simd128TernaryOp::Kind::kF16x8Qfms + : Simd128TernaryOp::Kind::kF16x8Qfma; + m.Return(m.Simd128Ternary(m.Parameter<Simd128>(0), m.Parameter<Simd128>(1), + m.Parameter<Simd128>(2), kind)); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(negate ? kX64F16x8Qfms : kX64F16x8Qfma, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(0U, s[0]->TempCount()); + const auto* output = UnallocatedOperand::cast(s[0]->Output()); + ASSERT_TRUE(output->HasSameAsInputPolicy()); + EXPECT_EQ(0, output->input_index()); + for (size_t i = 0; i < 3; ++i) { + const auto* input = UnallocatedOperand::cast(s[0]->InputAt(i)); + EXPECT_EQ(i < 2, input->HasRegisterPolicy()); + EXPECT_EQ(i == 2, input->HasRegisterOrSlotPolicy()); + EXPECT_TRUE(input->IsUsedAtStart()); + } + } +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8FmaRepeatedInputAVX10_1) { + if (!UseAvx10_1()) GTEST_SKIP() << "AVX10.1 must be supported and enabled"; + + for (bool negate : {false, true}) { + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128()); + auto kind = negate ? Simd128TernaryOp::Kind::kF16x8Qfms + : Simd128TernaryOp::Kind::kF16x8Qfma; + V<Simd128> a = m.Parameter<Simd128>(0); + V<Simd128> acc = m.Simd128Ternary(a, a, a, kind); + m.Return(m.Simd128Ternary(a, a, acc, kind)); + Stream s = m.Build(); + ASSERT_EQ(2U, s.size()); + for (size_t i = 0; i < s.size(); ++i) { + EXPECT_EQ(negate ? kX64F16x8Qfms : kX64F16x8Qfma, s[i]->arch_opcode()); + ASSERT_EQ(3U, s[i]->InputCount()); + ASSERT_EQ(1U, s[i]->OutputCount()); + EXPECT_EQ(0U, s[i]->TempCount()); + const auto* output = UnallocatedOperand::cast(s[i]->Output()); + ASSERT_TRUE(output->HasSameAsInputPolicy()); + EXPECT_EQ(0, output->input_index()); + for (size_t j = 0; j < 3; ++j) { + EXPECT_TRUE( + UnallocatedOperand::cast(s[i]->InputAt(j))->IsUsedAtStart()); + } + } + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(2))); + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(0))); + EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(2))); + } +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8AddAVX10_1) { + if (!UseAvx10_1()) GTEST_SKIP() << "AVX10.1 must be supported and enabled"; + + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128(), + MachineType::Simd128()); + m.Return(m.F16x8Add(m.Parameter<Simd128>(0), m.Parameter<Simd128>(1))); + Stream s = m.Build(); + + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64FAdd, s[0]->arch_opcode()); + EXPECT_EQ(LaneSize::kL16, LaneSizeField::decode(s[0]->opcode())); + EXPECT_EQ(VectorLength::kV128, VectorLengthField::decode(s[0]->opcode())); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(0U, s[0]->TempCount()); + EXPECT_TRUE(UnallocatedOperand::cast(s[0]->Output())->HasRegisterPolicy()); + for (size_t i = 0; i < 2; ++i) { + const auto* input = UnallocatedOperand::cast(s[0]->InputAt(i)); + EXPECT_TRUE(input->HasRegisterPolicy()); + EXPECT_TRUE(input->IsUsedAtStart()); + } +} + +TEST_F(TurboshaftInstructionSelectorTest, F16x8AddRepeatedInputAVX10_1) { + if (!UseAvx10_1()) GTEST_SKIP() << "AVX10.1 must be supported and enabled"; + + StreamBuilder m(this, MachineType::Simd128(), MachineType::Simd128()); + V<Simd128> input = m.Parameter<Simd128>(0); + V<Simd128> sum = m.F16x8Add(input, input); + m.Return(m.F16x8Add(sum, input)); + Stream s = m.Build(); + + ASSERT_EQ(2U, s.size()); + for (size_t i = 0; i < s.size(); ++i) { + EXPECT_EQ(kX64FAdd, s[i]->arch_opcode()); + EXPECT_EQ(LaneSize::kL16, LaneSizeField::decode(s[i]->opcode())); + EXPECT_EQ(VectorLength::kV128, VectorLengthField::decode(s[i]->opcode())); + ASSERT_EQ(2U, s[i]->InputCount()); + EXPECT_EQ(1U, s[i]->OutputCount()); + EXPECT_EQ(0U, s[i]->TempCount()); + EXPECT_TRUE(UnallocatedOperand::cast(s[i]->InputAt(0))->IsUsedAtStart()); + EXPECT_TRUE(UnallocatedOperand::cast(s[i]->InputAt(1))->IsUsedAtStart()); + } + EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1))); +} + TEST_F(TurboshaftInstructionSelectorTest, I64x2MulAVX10_1) { if (!UseAvx10_1()) return; @@ -3131,6 +3376,20 @@ TEST_F(TurboshaftInstructionSelectorTest, S256SelectAVX10_1) { #endif // V8_ENABLE_SIMD256 #endif // V8_ENABLE_AVX10_1 +TEST_F(TurboshaftInstructionSelectorTest, + WasmIsolateFieldUsesRootRelativeAddressing) { + wasm::ValueType kTypes[] = {wasm::kWasmI64}; + wasm::FunctionSig sig(1, 0, kTypes); + StreamBuilder m(this, GetWasmCallDescriptor(zone(), &sig)); + V<WordPtr> top_addr = m.IsolateField(IsolateFieldId::kNewAllocationInfoTop); + m.Return(m.LoadOffHeap(top_addr, MemoryRepresentation::UintPtr())); + Stream s = m.Build(); + + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Movq, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Root, s[0]->addressing_mode()); +} + #endif // V8_ENABLE_WEBASSEMBLY TEST_F(TurboshaftInstructionSelectorTest, AtomicStoreWithWriteBarrier) { diff --git a/deps/v8/test/unittests/debug/debug-property-iterator-unittest.cc b/deps/v8/test/unittests/debug/debug-property-iterator-unittest.cc index 2ef430b6521e..ee236c112780 100644 --- a/deps/v8/test/unittests/debug/debug-property-iterator-unittest.cc +++ b/deps/v8/test/unittests/debug/debug-property-iterator-unittest.cc @@ -157,44 +157,6 @@ TEST_F(DebugPropertyIteratorTest, SkipsIndicesOnTypedArrays) { } } -#if V8_CAN_CREATE_SHARED_HEAP_BOOL - -using SharedObjectDebugPropertyIteratorTest = TestJSSharedMemoryWithContext; - -TEST_F(SharedObjectDebugPropertyIteratorTest, SharedStruct) { - TryCatch try_catch(isolate()); - - const char source_text[] = - "let S = new SharedStructType(['field', 'another_field']);" - "new S();"; - - auto shared_struct = - RunJS(context(), source_text)->ToObject(context()).ToLocalChecked(); - auto iterator = PropertyIterator::Create(context(), shared_struct); - - ASSERT_NE(iterator, nullptr); - ASSERT_FALSE(iterator->Done()); - EXPECT_TRUE(iterator->is_own()); - char name_buffer[64]; - iterator->name().As<v8::String>()->WriteUtf8( - isolate(), name_buffer, sizeof(name_buffer), - String::WriteFlags::kNullTerminate); - EXPECT_EQ("field", std::string(name_buffer)); - ASSERT_TRUE(iterator->Advance().FromMaybe(false)); - - ASSERT_FALSE(iterator->Done()); - EXPECT_TRUE(iterator->is_own()); - iterator->name().As<v8::String>()->WriteUtf8( - isolate(), name_buffer, sizeof(name_buffer), - String::WriteFlags::kNullTerminate); - EXPECT_EQ("another_field", std::string(name_buffer)); - ASSERT_TRUE(iterator->Advance().FromMaybe(false)); - - ASSERT_FALSE(iterator->Done()); -} - -#endif // V8_CAN_CREATE_SHARED_HEAP_BOOL - } // namespace } // namespace debug } // namespace v8 diff --git a/deps/v8/test/unittests/debug/debug-scope-info-unittest.cc b/deps/v8/test/unittests/debug/debug-scope-info-unittest.cc index eaced1b679f8..0b2a78cc43ca 100644 --- a/deps/v8/test/unittests/debug/debug-scope-info-unittest.cc +++ b/deps/v8/test/unittests/debug/debug-scope-info-unittest.cc @@ -1838,10 +1838,9 @@ TEST_F(DebugScopeInfoTest, FindInnermostScopeStartsAtClosureScope) { ParsedScript parsed = ParseAndSerialize(source); DirectHandle<DebugScriptScopeInfo> info = parsed.scope_info; - DebugScriptScope script_scope = DebugScriptScope::FromIndex(info, 0); - DebugScriptScope foo = - FindInnermostScope(script_scope, PositionOf(source, "let a") + 1); + DebugScriptScope foo = DebugScriptScope::FromIndex(info, 3); ASSERT_TRUE(foo.is_function_scope()); + ASSERT_EQ(foo.start_position(), PositionOf(source, "() {")); DebugScriptScope found = FindInnermostScope(foo, PositionOf(source, "let b") + 1); @@ -1904,18 +1903,49 @@ TEST_F(DebugScopeInfoTest, FindInnermostScopeClassScope) { EXPECT_EQ(found.scope_index(), class_scope->scope_index()); } -TEST_F(DebugScopeInfoTest, FindInnermostScopeNestedArrowFunctions) { +TEST_F(DebugScopeInfoTest, FindInnermostScopeSkipsFunctionScopes) { HandleScope scope(isolate()); - // Both arrow functions end at the same position, so the tightest fit is - // decided by the start position. - const char* source = "const f = a => b => a + b;"; + const char* source = "const f = a => b => { let c = a + b; return c; };"; ParsedScript parsed = ParseAndSerialize(source); DirectHandle<DebugScriptScopeInfo> info = parsed.scope_info; DebugScriptScope script_scope = DebugScriptScope::FromIndex(info, 0); + DebugScriptScope outer_arrow = DebugScriptScope::FromIndex(info, 1); + DebugScriptScope inner_arrow = DebugScriptScope::FromIndex(info, 2); + ASSERT_TRUE(outer_arrow.is_function_scope()); + ASSERT_TRUE(inner_arrow.is_function_scope()); + + const int body_pos = PositionOf(source, "let c") + 1; + // Searching from `script_scope` or `outer_arrow` must not descend into child + // FUNCTION_SCOPEs. + EXPECT_EQ(FindInnermostScope(script_scope, body_pos).scope_index(), + script_scope.scope_index()); + EXPECT_EQ(FindInnermostScope(outer_arrow, body_pos).scope_index(), + outer_arrow.scope_index()); + EXPECT_EQ(FindInnermostScope(inner_arrow, body_pos).scope_index(), + inner_arrow.scope_index()); +} + +TEST_F(DebugScopeInfoTest, FindInnermostScopeClassComputedFieldKey) { + HandleScope scope(isolate()); + // The synthetic instance_members_initializer_function FUNCTION_SCOPE spans + // from `a = 1` to `b = 3`, straddling `[computed()]`. Searching from `foo` + // for a position inside `computed()` must stop at `CLASS_SCOPE` and not + // descend into the synthetic initializer FUNCTION_SCOPE. + const char* source = + "function foo() { class C { a = 1; [computed()] = 2; b = 3; } }"; + ParsedScript parsed = ParseAndSerialize(source); + DirectHandle<DebugScriptScopeInfo> info = parsed.scope_info; + + DebugScriptScope foo = DebugScriptScope::FromIndex(info, 1); + ASSERT_TRUE(foo.is_function_scope()); + std::optional<DebugScriptScope> class_scope = + FindFirstScopeOfType(info, ScopeType::CLASS_SCOPE); + ASSERT_TRUE(class_scope.has_value()); + DebugScriptScope found = - FindInnermostScope(script_scope, PositionOf(source, "a + b") + 1); - EXPECT_EQ(found.scope_index(), 2); + FindInnermostScope(foo, PositionOf(source, "computed()")); + EXPECT_EQ(found.scope_index(), class_scope->scope_index()); } TEST_F(DebugScopeInfoTest, FindInnermostScopeOutsideOfClosureScope) { @@ -1932,5 +1962,163 @@ TEST_F(DebugScopeInfoTest, FindInnermostScopeOutsideOfClosureScope) { EXPECT_EQ(found.scope_index(), foo.scope_index()); } +TEST_F(DebugScopeInfoTest, FindInnermostScopeSwitchStatement) { + HandleScope scope(isolate()); + // The switch discriminant `tag()` is evaluated outside the switch block + // scope, so positions inside `tag()` must resolve to `foo` rather than the + // switch's BLOCK_SCOPE. + const char* source = + "function foo() { switch (tag()) { case 0: let a = 1; break; } }"; + ParsedScript parsed = ParseAndSerialize(source); + DirectHandle<DebugScriptScopeInfo> info = parsed.scope_info; + + DebugScriptScope foo = DebugScriptScope::FromIndex(info, 1); + ASSERT_TRUE(foo.is_function_scope()); + DebugScriptScope switch_scope = DebugScriptScope::FromIndex(info, 2); + ASSERT_TRUE(switch_scope.is_block_scope()); + EXPECT_EQ(switch_scope.start_position(), PositionOf(source, "{ case")); + + EXPECT_EQ(FindInnermostScope(foo, PositionOf(source, "tag()")).scope_index(), + foo.scope_index()); + EXPECT_EQ(FindInnermostScope(foo, PositionOf(source, "let a")).scope_index(), + switch_scope.scope_index()); +} + +TEST_F(DebugScopeInfoTest, FindEvalOuterScopeNestedBlocks) { + HandleScope scope(isolate()); + Handle<JSFunction> inner = RunJS<JSFunction>( + "function outer(param) {\n" + " let a = 1;\n" + " {\n" + " let b = 2;\n" + " {\n" + " let c = 3;\n" + " return eval('() => param');\n" + " }\n" + " }\n" + "}\n" + "outer(10);"); + DirectHandle<Script> eval_script(Cast<Script>(inner->shared()->script()), + isolate()); + isolate()->debug()->ClearScriptScopeInfos(); + + std::optional<DebugScriptScope> block_c = + FindEvalOuterScope(isolate(), eval_script); + ASSERT_TRUE(block_c.has_value()); + EXPECT_TRUE(block_c->is_block_scope()); + ASSERT_EQ(block_c->variable_count(), 1); + EXPECT_TRUE(block_c->variable(0).name->IsEqualTo("c")); + + DirectHandle<Script> outer_script( + Cast<Script>(eval_script->eval_from_shared()->script()), isolate()); + EXPECT_EQ(*block_c->info(), + *EnsureDebugScriptScopeInfo(isolate(), outer_script)); + + std::optional<DebugScriptScope> block_b = block_c->parent(); + ASSERT_TRUE(block_b.has_value()); + EXPECT_TRUE(block_b->is_block_scope()); + ASSERT_EQ(block_b->variable_count(), 1); + EXPECT_TRUE(block_b->variable(0).name->IsEqualTo("b")); + + std::optional<DebugScriptScope> fn_outer = block_b->parent(); + ASSERT_TRUE(fn_outer.has_value()); + EXPECT_TRUE(fn_outer->is_function_scope()); + EXPECT_EQ(fn_outer->start_position(), 14); + + std::optional<DebugScriptScope> script_scope = fn_outer->parent(); + ASSERT_TRUE(script_scope.has_value()); + EXPECT_TRUE(script_scope->is_script_scope()); + EXPECT_FALSE(script_scope->parent().has_value()); +} + +TEST_F(DebugScopeInfoTest, FindEvalOuterScopeChainedDirectEval) { + HandleScope scope(isolate()); + Handle<JSFunction> inner = RunJS<JSFunction>( + "function outer() {\n" + " let a = 1;\n" + " {\n" + " let b = 2;\n" + " return eval(\"let c = 3; { let d = 4; eval('() => a'); }\");\n" + " }\n" + "}\n" + "outer();"); + DirectHandle<Script> inner_eval_script( + Cast<Script>(inner->shared()->script()), isolate()); + isolate()->debug()->ClearScriptScopeInfos(); + + std::optional<DebugScriptScope> block_d = + FindEvalOuterScope(isolate(), inner_eval_script); + ASSERT_TRUE(block_d.has_value()); + EXPECT_TRUE(block_d->is_block_scope()); + ASSERT_EQ(block_d->variable_count(), 1); + EXPECT_TRUE(block_d->variable(0).name->IsEqualTo("d")); + + std::optional<DebugScriptScope> mid_eval_scope = block_d->parent(); + ASSERT_TRUE(mid_eval_scope.has_value()); + EXPECT_TRUE(mid_eval_scope->is_eval_scope()); + EXPECT_FALSE(mid_eval_scope->parent().has_value()); + + DirectHandle<Script> mid_eval_script( + Cast<Script>(inner_eval_script->eval_from_shared()->script()), isolate()); + std::optional<DebugScriptScope> block_b = + FindEvalOuterScope(isolate(), mid_eval_script); + ASSERT_TRUE(block_b.has_value()); + EXPECT_TRUE(block_b->is_block_scope()); + ASSERT_EQ(block_b->variable_count(), 1); + EXPECT_TRUE(block_b->variable(0).name->IsEqualTo("b")); + + std::optional<DebugScriptScope> fn_outer = block_b->parent(); + ASSERT_TRUE(fn_outer.has_value()); + EXPECT_TRUE(fn_outer->is_function_scope()); + EXPECT_EQ(fn_outer->start_position(), 14); +} + +TEST_F(DebugScopeInfoTest, FindEvalOuterScopeTopLevelScript) { + HandleScope scope(isolate()); + Handle<JSFunction> inner = RunJS<JSFunction>( + "let top_a = 1;\n" + "let result;\n" + "{\n" + " let top_b = 2;\n" + " result = eval('() => top_a');\n" + "}\n" + "result;"); + DirectHandle<Script> eval_script(Cast<Script>(inner->shared()->script()), + isolate()); + isolate()->debug()->ClearScriptScopeInfos(); + + std::optional<DebugScriptScope> block_b = + FindEvalOuterScope(isolate(), eval_script); + ASSERT_TRUE(block_b.has_value()); + EXPECT_TRUE(block_b->is_block_scope()); + ASSERT_EQ(block_b->variable_count(), 1); + EXPECT_TRUE(block_b->variable(0).name->IsEqualTo("top_b")); + + std::optional<DebugScriptScope> script_scope = block_b->parent(); + ASSERT_TRUE(script_scope.has_value()); + EXPECT_TRUE(script_scope->is_script_scope()); + EXPECT_FALSE(script_scope->parent().has_value()); +} + +TEST_F(DebugScopeInfoTest, FindEvalOuterScopeNonDirectEval) { + HandleScope scope(isolate()); + Handle<JSFunction> regular = RunJS<JSFunction>("(() => 1);"); + DirectHandle<Script> regular_script(Cast<Script>(regular->shared()->script()), + isolate()); + EXPECT_FALSE(FindEvalOuterScope(isolate(), regular_script).has_value()); + + Handle<JSFunction> indirect_eval = + RunJS<JSFunction>("(0, eval)('(() => 1)');"); + DirectHandle<Script> indirect_eval_script( + Cast<Script>(indirect_eval->shared()->script()), isolate()); + EXPECT_FALSE(FindEvalOuterScope(isolate(), indirect_eval_script).has_value()); + + Handle<JSFunction> fn_ctor = + RunJS<JSFunction>("new Function('return () => 1;')();"); + DirectHandle<Script> fn_ctor_script(Cast<Script>(fn_ctor->shared()->script()), + isolate()); + EXPECT_FALSE(FindEvalOuterScope(isolate(), fn_ctor_script).has_value()); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/deoptimizer/deoptimization-unittest.cc b/deps/v8/test/unittests/deoptimizer/deoptimization-unittest.cc index 08b3ca8b92ee..faccda45164d 100644 --- a/deps/v8/test/unittests/deoptimizer/deoptimization-unittest.cc +++ b/deps/v8/test/unittests/deoptimizer/deoptimization-unittest.cc @@ -27,6 +27,8 @@ #include <stdlib.h> +#include <array> + #include "include/v8-function.h" #include "src/api/api-inl.h" #include "src/base/platform/platform.h" @@ -44,7 +46,6 @@ namespace v8 { namespace internal { -using ::v8::base::EmbeddedVector; using ::v8::base::OS; class DeoptimizationTest : public TestWithContext { @@ -389,10 +390,10 @@ class DeoptimizationDisableConcurrentRecompilationTest } static void SetUpTestSuite() { i::v8_flags.concurrent_recompilation = false; } void TestDeoptimizeBinaryOp(const char* binary_op) { - v8::base::EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer; + std::array<char, SMALL_STRING_BUFFER_SIZE> f_source_buffer; v8::base::SNPrintF(f_source_buffer, "function f(x, y) { return x %s y; };", binary_op); - char* f_source = f_source_buffer.begin(); + char* f_source = f_source_buffer.data(); AllowNativesSyntaxNoInlining options; // Compile function f and collect to type feedback to insert binary op stub diff --git a/deps/v8/test/unittests/flags/flag-definitions-unittest.cc b/deps/v8/test/unittests/flags/flag-definitions-unittest.cc index bfafc52b831a..c68562fcde9e 100644 --- a/deps/v8/test/unittests/flags/flag-definitions-unittest.cc +++ b/deps/v8/test/unittests/flags/flag-definitions-unittest.cc @@ -48,7 +48,6 @@ void TestDefault() { CHECK_EQ(0, strcmp(v8_flags.testing_string_flag, "Hello, world!")); } -// This test must be executed first! TEST_F(FlagDefinitionsTest, Default) { TestDefault(); } TEST_F(FlagDefinitionsTest, Flags1) { FlagList::PrintHelp(); } @@ -260,6 +259,7 @@ class ExperimentalFlagImplicationTest // Check that no experimental feature is enabled; this is executed for different // {FlagAndName} combinations. TEST_P(ExperimentalFlagImplicationTest, TestExperimentalNotEnabled) { + SaveFlags save_flags; FlagList::EnforceFlagImplications(); // --experimental should normally be disabled by default. Note that unittests @@ -300,6 +300,44 @@ TEST_P(ExperimentalFlagImplicationTest, TestExperimentalNotEnabled) { } } +// Check that --test-only-unsafe is not enabled by default or implied by any of +// the tested {FlagAndName} combinations. +TEST_P(ExperimentalFlagImplicationTest, TestUnsafeNotEnabled) { + SaveFlags save_flags; + FlagList::EnforceFlagImplications(); + + // In case unittests are executed with an unsafe flag (e.g. on PKU bots with + // --force-memory-protection-keys), this test must take it into account. + bool already_in_unsafe = v8_flags.test_only_unsafe; + + auto [flag_value, flag_name, test_name] = GetParam(); + CHECK_EQ(flag_value == nullptr, flag_name == nullptr); + + if (flag_name) { + int argc = 2; + const char* argv[] = {"", flag_name}; + CHECK_EQ(0, FlagList::SetFlagsFromCommandLine( + &argc, const_cast<char**>(argv), false)); + CHECK(*flag_value); + FlagList::EnforceFlagImplications(); + } + + if (already_in_unsafe) { + if (!v8_flags.test_only_unsafe) { + FATAL("--test-only-unsafe was enabled and then disabled"); + } + return; + } + + if (v8_flags.test_only_unsafe) { + if (flag_value == nullptr) { + FATAL("--test-only-unsafe is enabled by default"); + } else { + FATAL("--test-only-unsafe is implied by %s", flag_name); + } + } +} + std::string FlagNameToTestName(::testing::TestParamInfo<FlagAndName> info) { return info.param.test_name; } @@ -419,6 +457,13 @@ TEST(FlagInternalsTest, LookupAllFlagsByName) { } } +TEST(FlagInternalsTest, LookupAllFlagsByPointer) { + for (const Flag& flag : Flags()) { + if (flag.IsReadOnly()) continue; + CHECK_EQ(&flag, FindFlagByPointer(flag.valptr_)); + } +} + TEST(FlagInternalsTest, LookupAllImplicationFlagsByName) { for (const Flag& flag : Flags()) { CHECK_EQ(&flag, FindImplicationFlagByName(flag.name())); @@ -428,13 +473,121 @@ TEST(FlagInternalsTest, LookupAllImplicationFlagsByName) { } TEST(FlagInternalsTest, ImplicationOrderShouldNotMatter) { - static constexpr char kTestingBoolFlagC[] = "--testing-bool-flag-C"; - CHECK_EQ(0, FlagList::SetFlagsFromString(kTestingBoolFlagC, - strlen(kTestingBoolFlagC))); + v8_flags.testing_bool_flag_C.Set(true); FlagList::EnforceFlagImplications(); CHECK(v8_flags.testing_bool_flag_C); CHECK(!v8_flags.testing_bool_flag_B); CHECK(!v8_flags.testing_bool_flag_A); } +TEST_F(FlagDefinitionsTest, FlagValueSetChecksContradictions) { + SaveFlags save_flags; + v8_flags.flag_processing_mode.Set("abort-on-error"); + v8_flags.testing_bool_flag.Set(true); + // Setting the same boolean value again is allowed. + v8_flags.testing_bool_flag.Set(true); + // Setting a contradictory boolean value fails. + ASSERT_DEATH_IF_SUPPORTED( + v8_flags.testing_bool_flag.Set(false), + "Command-line provided flag --testing-bool-flag specified as both true " + "and false"); + FindFlagByName("flag_processing_mode")->Reset(); +} + +TEST_F(FlagDefinitionsTest, UnsafeFlagImpliesTestOnlyUnsafe) { + if (v8_flags.test_only_unsafe) { + // Unittests were invoked with an explicit unsafe flag (e.g. PKU bots with + // --force-memory-protection-keys). + return; + } + { + SaveFlags save_flags; + v8_flags.expose_trigger_failure.Set(true); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.expose_trigger_failure); + CHECK(v8_flags.test_only_unsafe); + } +#if V8_ENABLE_WEBASSEMBLY + { + SaveFlags save_flags; + v8_flags.wasm_bounds_checks.Set(false); + FlagList::EnforceFlagImplications(); + CHECK(!v8_flags.wasm_bounds_checks); + CHECK(v8_flags.test_only_unsafe); + } +#endif // V8_ENABLE_WEBASSEMBLY + { + SaveFlags save_flags; + v8_flags.gc_fake_mmap.Set("/tmp/foo"); + FlagList::EnforceFlagImplications(); + CHECK_EQ(0, strcmp(v8_flags.gc_fake_mmap, "/tmp/foo")); + CHECK(v8_flags.test_only_unsafe); + FindFlagByName("gc_fake_mmap")->Reset(); + } + { + // Test conditional DISALLOW_UNSAFE_FLAG_IF: a non-default valid stack size + // should not imply --test-only-unsafe, but an invalid one should. + SaveFlags save_flags; + v8_flags.stack_size.Set(100); + FlagList::EnforceFlagImplications(); + CHECK_EQ(100, v8_flags.stack_size); + CHECK(!v8_flags.test_only_unsafe); + } + { + SaveFlags save_flags; + v8_flags.stack_size.Set(40); + FlagList::EnforceFlagImplications(); + CHECK_EQ(40, v8_flags.stack_size); + CHECK(v8_flags.test_only_unsafe); + } +} + +TEST_F(FlagDefinitionsTest, FuzzingImpliesDisallowUnsafeFlags) { + { + // Setting --disallow-unsafe-flags alone should not imply --fuzzing. + SaveFlags save_flags; + v8_flags.disallow_unsafe_flags.Set(true); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.disallow_unsafe_flags); + CHECK(!v8_flags.fuzzing); + } + { + // Setting --fuzzing should imply --disallow-unsafe-flags and reset unsafe + // flags to their defaults without aborting. + SaveFlags save_flags; + const char* str = + "--fuzzing --mock-arraybuffer-allocator --gc-fake-mmap=/tmp/x " + "--csa-trap-on-node=stub,1" +#ifdef DEBUG + " --turboshaft-opt-bisect-break=50 --turboshaft-opt-bisect-limit=100" +#endif + " --expose-trigger-failure --stack-size=40"; + CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str))); + FlagList::ResolveContradictionsWhenFuzzing(); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.fuzzing); + CHECK(v8_flags.disallow_unsafe_flags); + CHECK(!v8_flags.mock_arraybuffer_allocator); + CHECK_EQ(0, strcmp("/tmp/__v8_gc__", v8_flags.gc_fake_mmap)); + CHECK_EQ(nullptr, v8_flags.csa_trap_on_node); +#ifdef DEBUG + CHECK_EQ(std::numeric_limits<uint64_t>::max(), + v8_flags.turboshaft_opt_bisect_break); + CHECK_EQ(std::numeric_limits<uint64_t>::max(), + v8_flags.turboshaft_opt_bisect_limit); +#endif + CHECK(!v8_flags.expose_trigger_failure); + CHECK_EQ(V8_DEFAULT_STACK_SIZE_KB, v8_flags.stack_size); + CHECK(!v8_flags.test_only_unsafe); + } +} + +TEST_F(FlagDefinitionsTest, CorrectnessFuzzerSuppressionsIsDeveloperOnly) { + SaveFlags save_flags; + v8_flags.correctness_fuzzer_suppressions.Set(true); + FlagList::EnforceFlagImplications(); + CHECK(v8_flags.correctness_fuzzer_suppressions); + CHECK(v8_flags.developer_only_features); +} + } // namespace v8::internal diff --git a/deps/v8/test/cctest/heap/test-array-buffer-sweeper.cc b/deps/v8/test/unittests/heap/array-buffer-sweeper-unittest.cc similarity index 55% rename from deps/v8/test/cctest/heap/test-array-buffer-sweeper.cc rename to deps/v8/test/unittests/heap/array-buffer-sweeper-unittest.cc index fe4782876dce..92572ed835e2 100644 --- a/deps/v8/test/cctest/heap/test-array-buffer-sweeper.cc +++ b/deps/v8/test/unittests/heap/array-buffer-sweeper-unittest.cc @@ -2,64 +2,75 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/heap/array-buffer-sweeper.h" + +#include <algorithm> +#include <memory> +#include <vector> + #include "src/api/api-inl.h" #include "src/common/globals.h" #include "src/execution/isolate.h" #include "src/flags/flags.h" -#include "src/heap/array-buffer-sweeper.h" #include "src/heap/heap-inl.h" -#include "src/heap/spaces.h" +#include "src/heap/mutable-page-inl.h" +#include "src/heap/normal-page-inl.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { +namespace heap { namespace { -bool IsTrackedYoung(i::Heap* heap, i::ArrayBufferExtension* extension) { +bool IsTrackedYoung(Heap* heap, ArrayBufferExtension* extension) { bool in_young = heap->array_buffer_sweeper()->young().ContainsSlow(extension); bool in_old = heap->array_buffer_sweeper()->old().ContainsSlow(extension); CHECK(!(in_young && in_old)); return in_young; } -bool IsTrackedOld(i::Heap* heap, i::ArrayBufferExtension* extension) { +bool IsTrackedOld(Heap* heap, ArrayBufferExtension* extension) { bool in_young = heap->array_buffer_sweeper()->young().ContainsSlow(extension); bool in_old = heap->array_buffer_sweeper()->old().ContainsSlow(extension); CHECK(!(in_young && in_old)); return in_old; } -bool IsTracked(i::Heap* heap, i::ArrayBufferExtension* extension) { +bool IsTracked(Heap* heap, ArrayBufferExtension* extension) { bool in_young = heap->array_buffer_sweeper()->young().ContainsSlow(extension); bool in_old = heap->array_buffer_sweeper()->old().ContainsSlow(extension); CHECK(!(in_young && in_old)); return in_young || in_old; } -bool IsTracked(i::Heap* heap, i::Tagged<i::JSArrayBuffer> buffer) { +bool IsTracked(Heap* heap, Tagged<JSArrayBuffer> buffer) { return IsTracked(heap, buffer->extension()); } -} // namespace +using ArrayBufferSweeperTest = TestWithHeapInternalsAndContext; -namespace v8 { -namespace internal { -namespace heap { +class ArrayBufferSweeperUninitializedTest + : public TestWithPlatformAndHeapInternals { + private: + SaveFlags save_flags_; +}; + +} // namespace // The following tests make sure that JSArrayBuffer tracking works expected when // moving the objects through various spaces during GC phases. -TEST(ArrayBuffer_OnlyMC) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_OnlyMC) { v8_flags.concurrent_array_buffer_sweeping = false; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning( - CcTest::heap()); + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); ArrayBufferExtension* extension; { @@ -67,29 +78,25 @@ TEST(ArrayBuffer_OnlyMC) { Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf = v8::Utils::OpenDirectHandle(*ab); extension = buf->extension(); - CHECK(v8_flags.single_generation ? IsTrackedOld(heap, extension) - : IsTrackedYoung(heap, extension)); - heap::InvokeAtomicMajorGC(heap); - CHECK(IsTrackedOld(heap, extension)); - heap::InvokeAtomicMajorGC(heap); - CHECK(IsTrackedOld(heap, extension)); + CHECK(v8_flags.single_generation ? IsTrackedOld(heap(), extension) + : IsTrackedYoung(heap(), extension)); + InvokeAtomicMajorGC(); + CHECK(IsTrackedOld(heap(), extension)); + InvokeAtomicMajorGC(); + CHECK(IsTrackedOld(heap(), extension)); } - heap::InvokeAtomicMajorGC(heap); - CHECK(!IsTracked(heap, extension)); + InvokeAtomicMajorGC(); + CHECK(!IsTracked(heap(), extension)); } -TEST(ArrayBuffer_OnlyScavenge) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_OnlyScavenge) { if (v8_flags.single_generation) return; if (v8_flags.scavenger_chaos_mode) return; v8_flags.concurrent_array_buffer_sweeping = false; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning( - CcTest::heap()); + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); ArrayBufferExtension* extension; { @@ -97,28 +104,24 @@ TEST(ArrayBuffer_OnlyScavenge) { Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf = v8::Utils::OpenDirectHandle(*ab); extension = buf->extension(); - CHECK(IsTrackedYoung(heap, extension)); - heap::InvokeAtomicMinorGC(heap); - CHECK(IsTrackedYoung(heap, extension)); - heap::InvokeAtomicMajorGC(heap); - CHECK(IsTrackedOld(heap, extension)); + CHECK(IsTrackedYoung(heap(), extension)); + InvokeAtomicMinorGC(); + CHECK(IsTrackedYoung(heap(), extension)); + InvokeAtomicMajorGC(); + CHECK(IsTrackedOld(heap(), extension)); } - heap::InvokeAtomicMajorGC(heap); - CHECK(!IsTracked(heap, extension)); + InvokeAtomicMajorGC(); + CHECK(!IsTracked(heap(), extension)); } -TEST(ArrayBuffer_ScavengeAndMC) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_ScavengeAndMC) { if (v8_flags.single_generation) return; if (v8_flags.scavenger_chaos_mode) return; v8_flags.concurrent_array_buffer_sweeping = false; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning( - CcTest::heap()); + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); ArrayBufferExtension* extension; { @@ -126,31 +129,28 @@ TEST(ArrayBuffer_ScavengeAndMC) { Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf = v8::Utils::OpenDirectHandle(*ab); extension = buf->extension(); - CHECK(IsTrackedYoung(heap, extension)); - heap::InvokeAtomicMinorGC(heap); - CHECK(IsTrackedYoung(heap, extension)); - heap::InvokeAtomicMajorGC(heap); - CHECK(IsTrackedOld(heap, extension)); - heap::InvokeAtomicMinorGC(heap); - CHECK(IsTrackedOld(heap, extension)); + CHECK(IsTrackedYoung(heap(), extension)); + InvokeAtomicMinorGC(); + CHECK(IsTrackedYoung(heap(), extension)); + InvokeAtomicMajorGC(); + CHECK(IsTrackedOld(heap(), extension)); + InvokeAtomicMinorGC(); + CHECK(IsTrackedOld(heap(), extension)); } - heap::InvokeAtomicMinorGC(heap); - CHECK(IsTrackedOld(heap, extension)); - heap::InvokeAtomicMajorGC(heap); - CHECK(!IsTracked(heap, extension)); + InvokeAtomicMinorGC(); + CHECK(IsTrackedOld(heap(), extension)); + InvokeAtomicMajorGC(); + CHECK(!IsTracked(heap(), extension)); } -TEST(ArrayBuffer_Compaction) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_Compaction) { if (!v8_flags.compact) return; - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); v8_flags.concurrent_array_buffer_sweeping = false; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); - heap::AbandonCurrentlyFreeMemory(heap->old_space()); + v8::Isolate* isolate = v8_isolate(); + AbandonCurrentlyFreeMemory(heap()->old_space()); Global<v8::ArrayBuffer> ab1_global; NormalPage* page_before_gc; @@ -158,33 +158,33 @@ TEST(ArrayBuffer_Compaction) { v8::HandleScope handle_scope(isolate); Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, 100); IndirectHandle<JSArrayBuffer> buf1 = v8::Utils::OpenIndirectHandle(*ab1); - CHECK(IsTracked(heap, *buf1)); - heap::InvokeAtomicMajorGC(heap); + CHECK(IsTracked(heap(), *buf1)); + InvokeAtomicMajorGC(); page_before_gc = NormalPage::FromHeapObject(*buf1); - heap::ForceEvacuationCandidate(page_before_gc); - CHECK(IsTracked(heap, *buf1)); + ForceEvacuationCandidate(page_before_gc); + CHECK(IsTracked(heap(), *buf1)); ab1_global.Reset(isolate, ab1); } { // We need to invoke GC without stack, otherwise no compaction is // performed. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); } { v8::HandleScope scope(isolate); - IndirectHandle<JSArrayBuffer> buf1 = - v8::Utils::OpenHandle(*ab1_global.Get(isolate)); + DirectHandle<JSArrayBuffer> buf1 = + v8::Utils::OpenDirectHandle(*ab1_global.Get(isolate)); NormalPage* page_after_gc = NormalPage::FromHeapObject(*buf1); - CHECK(IsTracked(heap, *buf1)); + CHECK(IsTracked(heap(), *buf1)); CHECK_NE(page_before_gc, page_after_gc); } } -TEST(ArrayBuffer_UnregisterDuringSweep) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_UnregisterDuringSweep) { // Regular pages in old space (without compaction) are processed concurrently // in the sweeper. If we happen to unregister a buffer (either explicitly, or // implicitly through e.g. |Detach|) we need to sync with the sweeper @@ -195,15 +195,12 @@ TEST(ArrayBuffer_UnregisterDuringSweep) { // Disable verify-heap since it forces sweeping to be completed in the // epilogue of the GC. #ifdef VERIFY_HEAP - i::v8_flags.verify_heap = false; + v8_flags.verify_heap = false; #endif // VERIFY_HEAP - ManualGCScope manual_gc_scope; - i::v8_flags.concurrent_array_buffer_sweeping = false; + ManualGCScope manual_gc_scope(i_isolate()); + v8_flags.concurrent_array_buffer_sweeping = false; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); + v8::Isolate* isolate = v8_isolate(); { v8::HandleScope handle_scope(isolate); Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); @@ -215,15 +212,15 @@ TEST(ArrayBuffer_UnregisterDuringSweep) { // non-empty set of buffers in the last GC. Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf2 = v8::Utils::OpenDirectHandle(*ab2); - CHECK(IsTracked(heap, *buf)); - heap::InvokeAtomicMinorGC(heap); - CHECK(IsTracked(heap, *buf)); - heap::InvokeAtomicMinorGC(heap); - CHECK(IsTracked(heap, *buf)); - CHECK(IsTracked(heap, *buf2)); + CHECK(IsTracked(heap(), *buf)); + InvokeAtomicMinorGC(); + CHECK(IsTracked(heap(), *buf)); + InvokeAtomicMinorGC(); + CHECK(IsTracked(heap(), *buf)); + CHECK(IsTracked(heap(), *buf2)); } - heap::InvokeMajorGC(heap); + InvokeMajorGC(); // |Detach| will cause the buffer to be |Unregister|ed. Without // barriers and proper synchronization this will trigger a data race on // TSAN. @@ -231,65 +228,59 @@ TEST(ArrayBuffer_UnregisterDuringSweep) { } } -TEST(ArrayBuffer_SemiSpaceCopyThenPagePromotion) { - if (!i::v8_flags.incremental_marking) return; +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_SemiSpaceCopyThenPagePromotion) { + if (!v8_flags.incremental_marking) return; if (v8_flags.minor_ms) return; v8_flags.concurrent_array_buffer_sweeping = false; v8_flags.scavenger_precise_object_pinning = false; - ManualGCScope manual_gc_scope; + ManualGCScope manual_gc_scope(i_isolate()); // The test verifies that the marking state is preserved across semispace // copy. - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); + v8::Isolate* isolate = v8_isolate(); - heap::SealCurrentObjects(heap); + SealCurrentObjects(); { v8::HandleScope handle_scope(isolate); DirectHandle<FixedArray> root = - heap->isolate()->factory()->NewFixedArray(1, AllocationType::kOld); + factory()->NewFixedArray(1, AllocationType::kOld); { v8::HandleScope new_handle_scope(isolate); Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf = v8::Utils::OpenDirectHandle(*ab); root->set(0, *buf); // Buffer that should be promoted as live. - MutablePage::FromHeapObject(heap->isolate(), *buf)->MarkNeverEvacuate(); + MutablePage::FromHeapObject(i_isolate(), *buf)->MarkNeverEvacuate(); } - DirectHandleVector<FixedArray> handles(isolate); + std::vector<Handle<FixedArray>> handles; // Make the whole page transition from new->old, getting the buffers // processed in the sweeper (relying on marking information) instead of // processing during newspace evacuation. - heap::FillCurrentPage(heap->new_space(), &handles); - CHECK(IsTracked(heap, Cast<JSArrayBuffer>(root->get(0)))); + FillCurrentPage(heap()->new_space(), &handles); + CHECK(IsTracked(heap(), Cast<JSArrayBuffer>(root->get(0)))); { // CSS prevent semi space copying in Scavenger. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeAtomicMinorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeAtomicMinorGC(); } - heap::SimulateIncrementalMarking(heap, true); - heap::InvokeAtomicMajorGC(heap); - CHECK(IsTracked(heap, Cast<JSArrayBuffer>(root->get(0)))); + SimulateIncrementalMarking(true); + InvokeAtomicMajorGC(); + CHECK(IsTracked(heap(), Cast<JSArrayBuffer>(root->get(0)))); } } -TEST(ArrayBuffer_PagePromotion) { - if (!i::v8_flags.incremental_marking || i::v8_flags.single_generation) return; - i::v8_flags.concurrent_array_buffer_sweeping = false; +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_PagePromotion) { + if (!v8_flags.incremental_marking || v8_flags.single_generation) return; + v8_flags.concurrent_array_buffer_sweeping = false; - ManualGCScope manual_gc_scope; + ManualGCScope manual_gc_scope(i_isolate()); // The test verifies that the marking state is preserved across semispace // copy. - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); + v8::Isolate* isolate = v8_isolate(); - heap::SealCurrentObjects(heap); + SealCurrentObjects(); { v8::HandleScope handle_scope(isolate); DirectHandle<FixedArray> root = - heap->isolate()->factory()->NewFixedArray(1, AllocationType::kOld); + factory()->NewFixedArray(1, AllocationType::kOld); ArrayBufferExtension* extension; { v8::HandleScope new_handle_scope(isolate); @@ -298,109 +289,105 @@ TEST(ArrayBuffer_PagePromotion) { extension = buf->extension(); root->set(0, *buf); // Buffer that should be promoted as live. } - DirectHandleVector<FixedArray> handles(isolate); + std::vector<Handle<FixedArray>> handles; // Create live objects on page such that the whole page gets promoted - heap::FillCurrentPage(heap->new_space(), &handles); - CHECK(IsTrackedYoung(heap, extension)); - heap::SimulateIncrementalMarking(heap, true); - heap::InvokeAtomicMajorGC(heap); - CHECK(IsTrackedOld(heap, extension)); + FillCurrentPage(heap()->new_space(), &handles); + CHECK(IsTrackedYoung(heap(), extension)); + SimulateIncrementalMarking(true); + InvokeAtomicMajorGC(); + CHECK(IsTrackedOld(heap(), extension)); } } -UNINITIALIZED_TEST(ArrayBuffer_SemiSpaceCopyMultipleTasks) { +TEST_F(ArrayBufferSweeperUninitializedTest, + ArrayBuffer_SemiSpaceCopyMultipleTasks) { if (v8_flags.optimize_for_size || v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; + ManualGCScope manual_gc_scope(nullptr); // Test allocates JSArrayBuffer on different pages before triggering a // full GC that performs the semispace copy. If parallelized, this test // ensures proper synchronization in TSAN configurations. v8_flags.min_semi_space_size = std::max(2 * NormalPage::kPageSize / MB, 1); v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); v8::Isolate* isolate = v8::Isolate::New(create_params); - i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); - v8::Context::New(isolate)->Enter(); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); Heap* heap = i_isolate->heap(); // Ensure heap is in a clean state. - heap::InvokeMajorGC(heap); - heap::InvokeMajorGC(heap); + InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf1 = v8::Utils::OpenDirectHandle(*ab1); - heap::FillCurrentPage(heap->new_space()); + FillCurrentPage(heap->new_space()); Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, 100); DirectHandle<JSArrayBuffer> buf2 = v8::Utils::OpenDirectHandle(*ab2); CHECK_NE(NormalPage::FromHeapObject(*buf1), NormalPage::FromHeapObject(*buf2)); - heap::InvokeAtomicMajorGC(heap); + InvokeAtomicMajorGC(i_isolate); } isolate->Dispose(); } -TEST(ArrayBuffer_ExternalBackingStoreSizeIncreases) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_ExternalBackingStoreSizeIncreases) { if (v8_flags.single_generation) return; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); + v8::Isolate* isolate = v8_isolate(); const size_t backing_store_before = - heap->array_buffer_sweeper()->BytesForTesting(); + heap()->array_buffer_sweeper()->BytesForTesting(); { const size_t kArraybufferSize = 117; v8::HandleScope handle_scope(isolate); Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, kArraybufferSize); USE(ab); const size_t backing_store_after = - heap->array_buffer_sweeper()->BytesForTesting(); + heap()->array_buffer_sweeper()->BytesForTesting(); CHECK_EQ(kArraybufferSize, backing_store_after - backing_store_before); } } -TEST(ArrayBuffer_ExternalBackingStoreSizeDecreases) { +TEST_F(ArrayBufferSweeperTest, ArrayBuffer_ExternalBackingStoreSizeDecreases) { if (v8_flags.single_generation) return; v8_flags.concurrent_array_buffer_sweeping = false; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); + v8::Isolate* isolate = v8_isolate(); const size_t backing_store_before = - heap->array_buffer_sweeper()->BytesForTesting(); + heap()->array_buffer_sweeper()->BytesForTesting(); { const size_t kArraybufferSize = 117; v8::HandleScope handle_scope(isolate); Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, kArraybufferSize); USE(ab); } - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeAtomicMajorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeAtomicMajorGC(); const size_t backing_store_after = - heap->array_buffer_sweeper()->BytesForTesting(); - CHECK_EQ(0, backing_store_after - backing_store_before); + heap()->array_buffer_sweeper()->BytesForTesting(); + CHECK_EQ(0u, backing_store_after - backing_store_before); } -TEST(ArrayBuffer_ExternalBackingStoreSizeIncreasesMarkCompact) { +TEST_F(ArrayBufferSweeperTest, + ArrayBuffer_ExternalBackingStoreSizeIncreasesMarkCompact) { if (!v8_flags.compact) return; - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); v8_flags.concurrent_array_buffer_sweeping = false; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); - heap::AbandonCurrentlyFreeMemory(heap->old_space()); + v8::Isolate* isolate = v8_isolate(); + AbandonCurrentlyFreeMemory(heap()->old_space()); // We need to invoke GC without stack, otherwise some objects may survive. - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); const size_t backing_store_before = - heap->array_buffer_sweeper()->BytesForTesting(); + heap()->array_buffer_sweeper()->BytesForTesting(); const size_t kArraybufferSize = 117; { @@ -408,24 +395,24 @@ TEST(ArrayBuffer_ExternalBackingStoreSizeIncreasesMarkCompact) { Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, kArraybufferSize); IndirectHandle<JSArrayBuffer> buf1 = v8::Utils::OpenIndirectHandle(*ab1); - CHECK(IsTracked(heap, *buf1)); - heap::InvokeAtomicMajorGC(heap); + CHECK(IsTracked(heap(), *buf1)); + InvokeAtomicMajorGC(); NormalPage* page_before_gc = NormalPage::FromHeapObject(*buf1); - heap::ForceEvacuationCandidate(page_before_gc); - CHECK(IsTracked(heap, *buf1)); + ForceEvacuationCandidate(page_before_gc); + CHECK(IsTracked(heap(), *buf1)); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); const size_t backing_store_after = - heap->array_buffer_sweeper()->BytesForTesting(); + heap()->array_buffer_sweeper()->BytesForTesting(); CHECK_EQ(kArraybufferSize, backing_store_after - backing_store_before); } - heap::InvokeAtomicMajorGC(heap); + InvokeAtomicMajorGC(); const size_t backing_store_after = - heap->array_buffer_sweeper()->BytesForTesting(); - CHECK_EQ(0, backing_store_after - backing_store_before); + heap()->array_buffer_sweeper()->BytesForTesting(); + CHECK_EQ(0u, backing_store_after - backing_store_before); } } // namespace heap diff --git a/deps/v8/test/cctest/heap/test-concurrent-allocation.cc b/deps/v8/test/unittests/heap/concurrent-allocation-unittest.cc similarity index 53% rename from deps/v8/test/cctest/heap/test-concurrent-allocation.cc rename to deps/v8/test/unittests/heap/concurrent-allocation-unittest.cc index 790ce3e2d09c..17ccf1e17987 100644 --- a/deps/v8/test/cctest/heap/test-concurrent-allocation.cc +++ b/deps/v8/test/unittests/heap/concurrent-allocation-unittest.cc @@ -2,39 +2,46 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <atomic> #include <memory> +#include <utility> +#include <vector> -#include "src/api/api.h" -#include "src/base/platform/condition-variable.h" -#include "src/base/platform/mutex.h" +#include "include/libplatform/libplatform.h" #include "src/base/platform/semaphore.h" -#include "src/base/strong-alias.h" #include "src/codegen/assembler-inl.h" -#include "src/codegen/assembler.h" #include "src/codegen/macro-assembler-inl.h" -#include "src/codegen/macro-assembler.h" #include "src/codegen/reloc-info-inl.h" #include "src/common/globals.h" #include "src/common/ptr-compr.h" +#include "src/execution/local-isolate-inl.h" +#include "src/flags/flags.h" #include "src/handles/global-handles-inl.h" #include "src/handles/handles-inl.h" -#include "src/handles/handles.h" -#include "src/handles/local-handles-inl.h" -#include "src/handles/persistent-handles.h" -#include "src/heap/heap.h" +#include "src/heap/factory.h" +#include "src/heap/heap-inl.h" +#include "src/heap/heap-layout-inl.h" +#include "src/heap/incremental-marking.h" #include "src/heap/local-heap-inl.h" #include "src/heap/marking-state-inl.h" +#include "src/heap/normal-page-inl.h" #include "src/heap/parked-scope.h" -#include "src/heap/safepoint.h" #include "src/objects/heap-number.h" #include "src/objects/heap-object.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" namespace v8 { namespace internal { +class ConcurrentAllocationUninitializedTest : public TestWithPlatform { + private: + SaveFlags save_flags_; +}; + namespace { + void CreateFixedArray(Heap* heap, Address start, uint32_t size) { Tagged<HeapObject> object = HeapObject::FromAddress(start); object->set_map_after_allocation(heap->isolate(), @@ -48,9 +55,10 @@ void CreateFixedArray(Heap* heap, Address start, uint32_t size) { ReadOnlyRoots(heap).undefined_value(), length); } -const uint32_t kNumIterations = 2000; -const uint32_t kSmallObjectSize = 10 * kTaggedSize; -const uint32_t kMediumObjectSize = 8 * KB; +constexpr uint32_t kNumIterations = 2000; +constexpr uint32_t kWhiteIterations = 1000; +constexpr uint32_t kSmallObjectSize = 10 * kTaggedSize; +constexpr uint32_t kMediumObjectSize = 8 * KB; void AllocateSomeObjects(LocalHeap* local_heap) { for (uint32_t i = 0; i < kNumIterations; i++) { @@ -73,7 +81,6 @@ void AllocateSomeObjects(LocalHeap* local_heap) { } } } -} // namespace class ConcurrentAllocationThread final : public v8::base::Thread { public: @@ -90,24 +97,154 @@ class ConcurrentAllocationThread final : public v8::base::Thread { if (pending_) pending_->fetch_sub(1); } + private: + Heap* heap_; + std::atomic<int>* pending_; +}; + +class LargeObjectConcurrentAllocationThread final : public v8::base::Thread { + public: + explicit LargeObjectConcurrentAllocationThread(Heap* heap, + std::atomic<int>* pending) + : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), + heap_(heap), + pending_(pending) {} + + void Run() override { + LocalHeap local_heap(heap_, ThreadKind::kBackground); + UnparkedScope unparked_scope(&local_heap); + constexpr size_t kLargeObjectSize = kMaxRegularHeapObjectSize * 2; + + for (uint32_t i = 0; i < kNumIterations; i++) { + AllocationResult result = local_heap.AllocateRaw( + kLargeObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, + AllocationAlignment::kTaggedAligned); + if (result.IsFailure()) { + heap_->TriggerAndWaitForGCFromBackgroundThread(&local_heap, + RequestedGCKind::kMajor); + } else { + Address address = result.ToAddress(); + CreateFixedArray(heap_, address, kLargeObjectSize); + } + local_heap.Safepoint(); + } + + pending_->fetch_sub(1); + } + + private: Heap* heap_; std::atomic<int>* pending_; }; -UNINITIALIZED_TEST(ConcurrentAllocationInOldSpace) { +class ConcurrentBlackAllocationThread final : public v8::base::Thread { + public: + explicit ConcurrentBlackAllocationThread( + Heap* heap, std::vector<Address>* objects, base::Semaphore* sema_white, + base::Semaphore* sema_marking_started) + : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), + heap_(heap), + objects_(objects), + sema_white_(sema_white), + sema_marking_started_(sema_marking_started) {} + + void Run() override { + LocalHeap local_heap(heap_, ThreadKind::kBackground); + UnparkedScope unparked_scope(&local_heap); + + for (uint32_t i = 0; i < kNumIterations; i++) { + if (i == kWhiteIterations) { + local_heap.ExecuteWhileParked([this]() { + sema_white_->Signal(); + sema_marking_started_->Wait(); + }); + } + Address address = local_heap.AllocateRawOrFail( + kSmallObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, + AllocationAlignment::kTaggedAligned); + objects_->push_back(address); + CreateFixedArray(heap_, address, kSmallObjectSize); + address = local_heap.AllocateRawOrFail( + kMediumObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, + AllocationAlignment::kTaggedAligned); + objects_->push_back(address); + CreateFixedArray(heap_, address, kMediumObjectSize); + } + } + + private: + Heap* heap_; + std::vector<Address>* objects_; + base::Semaphore* sema_white_; + base::Semaphore* sema_marking_started_; +}; + +class ConcurrentWriteBarrierThread final : public v8::base::Thread { + public: + ConcurrentWriteBarrierThread(Heap* heap, Tagged<FixedArray> fixed_array, + Tagged<HeapObject> value) + : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), + heap_(heap), + fixed_array_(fixed_array), + value_(value) {} + + void Run() override { + LocalHeap local_heap(heap_, ThreadKind::kBackground); + UnparkedScope unparked_scope(&local_heap); + fixed_array_->set(0, value_); + } + + private: + Heap* heap_; + Tagged<FixedArray> fixed_array_; + Tagged<HeapObject> value_; +}; + +class ConcurrentRecordRelocSlotThread final : public v8::base::Thread { + public: + ConcurrentRecordRelocSlotThread(Heap* heap, Tagged<Code> code, + Tagged<HeapObject> value) + : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), + heap_(heap), + code_(code), + value_(value) {} + + void Run() override { + LocalHeap local_heap(heap_, ThreadKind::kBackground); + UnparkedScope unparked_scope(&local_heap); + DisallowGarbageCollection no_gc; + Tagged<InstructionStream> istream = code_->instruction_stream(); + int mode_mask = RelocInfo::EmbeddedObjectModeMask(); + WritableJitAllocation jit_allocation = ThreadIsolation::LookupJitAllocation( + istream->address(), istream->Size(), + ThreadIsolation::JitAllocationType::kInstructionStream, true); + for (WritableRelocIterator it(jit_allocation, istream, + code_->constant_pool(), mode_mask); + !it.done(); it.next()) { + DCHECK(RelocInfo::IsEmbeddedObjectMode(it.rinfo()->rmode())); + it.rinfo()->set_target_object(istream, value_); + } + } + + private: + Heap* heap_; + Tagged<Code> code_; + Tagged<HeapObject> value_; +}; + +} // namespace + +TEST_F(ConcurrentAllocationUninitializedTest, ConcurrentAllocationInOldSpace) { v8_flags.detect_ineffective_gcs_near_heap_limit = false; v8_flags.max_old_space_size = 64; v8_flags.stress_concurrent_allocation = false; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + v8::Isolate* isolate = isolate_wrapper.isolate(); + Isolate* i_isolate = isolate_wrapper.i_isolate(); std::vector<std::unique_ptr<ConcurrentAllocationThread>> threads; - - const int kThreads = 4; - + constexpr int kThreads = 4; std::atomic<int> pending(kThreads); for (int i = 0; i < kThreads; i++) { @@ -118,46 +255,40 @@ UNINITIALIZED_TEST(ConcurrentAllocationInOldSpace) { } while (pending > 0) { - v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), isolate); + v8::platform::PumpMessageLoop(V8::GetCurrentPlatform(), isolate); } for (auto& thread : threads) { thread->Join(); } - - isolate->Dispose(); } -UNINITIALIZED_TEST(ConcurrentAllocationInOldSpaceFromMainThread) { +TEST_F(ConcurrentAllocationUninitializedTest, + ConcurrentAllocationInOldSpaceFromMainThread) { v8_flags.max_old_space_size = 4; v8_flags.stress_concurrent_allocation = false; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + v8::Isolate* isolate = isolate_wrapper.isolate(); + Isolate* i_isolate = isolate_wrapper.i_isolate(); - { - v8::Isolate::Scope isolate_scope(isolate); - AllocateSomeObjects(i_isolate->main_thread_local_heap()); - } - isolate->Dispose(); + v8::Isolate::Scope isolate_scope(isolate); + AllocateSomeObjects(i_isolate->main_thread_local_heap()); } -UNINITIALIZED_TEST(ConcurrentAllocationWhileMainThreadIsParked) { +TEST_F(ConcurrentAllocationUninitializedTest, + ConcurrentAllocationWhileMainThreadIsParked) { // With CSS, it is expected that the GCs triggered by concurrent allocation // will reclaim less memory. If this test fails, this limit should probably // be further increased. v8_flags.max_old_space_size = v8_flags.conservative_stack_scanning ? 10 : 4; v8_flags.stress_concurrent_allocation = false; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + Isolate* i_isolate = isolate_wrapper.i_isolate(); std::vector<std::unique_ptr<ConcurrentAllocationThread>> threads; - const int kThreads = 4; + constexpr int kThreads = 4; i_isolate->main_thread_local_isolate()->ExecuteMainThreadWhileParked( [i_isolate, &threads]() { @@ -172,142 +303,95 @@ UNINITIALIZED_TEST(ConcurrentAllocationWhileMainThreadIsParked) { thread->Join(); } }); - - isolate->Dispose(); } -UNINITIALIZED_TEST(ConcurrentAllocationWhileMainThreadParksAndUnparks) { +TEST_F(ConcurrentAllocationUninitializedTest, + ConcurrentAllocationWhileMainThreadParksAndUnparks) { // With CSS, it is expected that the GCs triggered by concurrent allocation // will reclaim less memory. If this test fails, this limit should probably // be further increased. v8_flags.max_old_space_size = v8_flags.conservative_stack_scanning ? 10 : 4; v8_flags.stress_concurrent_allocation = false; v8_flags.incremental_marking = false; - i::FlagList::EnforceFlagImplications(); + FlagList::EnforceFlagImplications(); - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + Isolate* i_isolate = isolate_wrapper.i_isolate(); std::vector<std::unique_ptr<ConcurrentAllocationThread>> threads; - const int kThreads = 4; + constexpr int kThreads = 4; - { - for (int i = 0; i < kThreads; i++) { - auto thread = - std::make_unique<ConcurrentAllocationThread>(i_isolate->heap()); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - - for (int i = 0; i < 300'000; i++) { - i_isolate->main_thread_local_isolate()->ExecuteMainThreadWhileParked( - []() { /* nothing */ }); - } + for (int i = 0; i < kThreads; i++) { + auto thread = + std::make_unique<ConcurrentAllocationThread>(i_isolate->heap()); + CHECK(thread->Start()); + threads.push_back(std::move(thread)); + } + for (int i = 0; i < 300'000; i++) { i_isolate->main_thread_local_isolate()->ExecuteMainThreadWhileParked( - [&threads]() { - for (auto& thread : threads) { - thread->Join(); - } - }); + []() { /* nothing */ }); } - isolate->Dispose(); + i_isolate->main_thread_local_isolate()->ExecuteMainThreadWhileParked( + [&threads]() { + for (auto& thread : threads) { + thread->Join(); + } + }); } -UNINITIALIZED_TEST(ConcurrentAllocationWhileMainThreadRunsWithSafepoints) { +TEST_F(ConcurrentAllocationUninitializedTest, + ConcurrentAllocationWhileMainThreadRunsWithSafepoints) { // With CSS, it is expected that the GCs triggered by concurrent allocation // will reclaim less memory. If this test fails, this limit should probably // be further increased. v8_flags.max_old_space_size = v8_flags.conservative_stack_scanning ? 10 : 4; v8_flags.stress_concurrent_allocation = false; v8_flags.incremental_marking = false; - i::FlagList::EnforceFlagImplications(); + FlagList::EnforceFlagImplications(); - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + Isolate* i_isolate = isolate_wrapper.i_isolate(); std::vector<std::unique_ptr<ConcurrentAllocationThread>> threads; - const int kThreads = 4; - - { - for (int i = 0; i < kThreads; i++) { - auto thread = - std::make_unique<ConcurrentAllocationThread>(i_isolate->heap()); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } + constexpr int kThreads = 4; - // Some of the following Safepoint() invocations are supposed to perform a - // GC. - for (int i = 0; i < 1'000'000; i++) { - i_isolate->main_thread_local_heap()->Safepoint(); - } + for (int i = 0; i < kThreads; i++) { + auto thread = + std::make_unique<ConcurrentAllocationThread>(i_isolate->heap()); + CHECK(thread->Start()); + threads.push_back(std::move(thread)); + } - i_isolate->main_thread_local_isolate()->ExecuteMainThreadWhileParked( - [&threads]() { - for (auto& thread : threads) { - thread->Join(); - } - }); + // Some of the following Safepoint() invocations are supposed to perform a + // GC. + for (int i = 0; i < 1'000'000; i++) { + i_isolate->main_thread_local_heap()->Safepoint(); } + i_isolate->main_thread_local_isolate()->ExecuteMainThreadWhileParked( + [&threads]() { + for (auto& thread : threads) { + thread->Join(); + } + }); + i_isolate->main_thread_local_heap()->Safepoint(); - isolate->Dispose(); } -class LargeObjectConcurrentAllocationThread final : public v8::base::Thread { - public: - explicit LargeObjectConcurrentAllocationThread(Heap* heap, - std::atomic<int>* pending) - : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), - heap_(heap), - pending_(pending) {} - - void Run() override { - LocalHeap local_heap(heap_, ThreadKind::kBackground); - UnparkedScope unparked_scope(&local_heap); - const size_t kLargeObjectSize = kMaxRegularHeapObjectSize * 2; - - for (uint32_t i = 0; i < kNumIterations; i++) { - AllocationResult result = local_heap.AllocateRaw( - kLargeObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, - AllocationAlignment::kTaggedAligned); - if (result.IsFailure()) { - heap_->TriggerAndWaitForGCFromBackgroundThread(&local_heap, - RequestedGCKind::kMajor); - } else { - Address address = result.ToAddress(); - CreateFixedArray(heap_, address, kLargeObjectSize); - } - local_heap.Safepoint(); - } - - pending_->fetch_sub(1); - } - - Heap* heap_; - std::atomic<int>* pending_; -}; - -UNINITIALIZED_TEST(ConcurrentAllocationInLargeSpace) { +TEST_F(ConcurrentAllocationUninitializedTest, + ConcurrentAllocationInLargeSpace) { v8_flags.detect_ineffective_gcs_near_heap_limit = false; v8_flags.max_old_space_size = 32; v8_flags.stress_concurrent_allocation = false; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + v8::Isolate* isolate = isolate_wrapper.isolate(); + Isolate* i_isolate = isolate_wrapper.i_isolate(); std::vector<std::unique_ptr<LargeObjectConcurrentAllocationThread>> threads; - - const int kThreads = 4; - + constexpr int kThreads = 4; std::atomic<int> pending(kThreads); for (int i = 0; i < kThreads; i++) { @@ -318,276 +402,170 @@ UNINITIALIZED_TEST(ConcurrentAllocationInLargeSpace) { } while (pending > 0) { - v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), isolate); + v8::platform::PumpMessageLoop(V8::GetCurrentPlatform(), isolate); } for (auto& thread : threads) { thread->Join(); } - - isolate->Dispose(); } -const uint32_t kWhiteIterations = 1000; - -class ConcurrentBlackAllocationThread final : public v8::base::Thread { - public: - explicit ConcurrentBlackAllocationThread( - Heap* heap, std::vector<Address>* objects, base::Semaphore* sema_white, - base::Semaphore* sema_marking_started) - : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), - heap_(heap), - objects_(objects), - sema_white_(sema_white), - sema_marking_started_(sema_marking_started) {} - - void Run() override { - LocalHeap local_heap(heap_, ThreadKind::kBackground); - UnparkedScope unparked_scope(&local_heap); +TEST_F(ConcurrentAllocationUninitializedTest, ConcurrentBlackAllocation) { + if (!v8_flags.incremental_marking) return; - for (uint32_t i = 0; i < kNumIterations; i++) { - if (i == kWhiteIterations) { - local_heap.ExecuteWhileParked([this]() { - sema_white_->Signal(); - sema_marking_started_->Wait(); - }); - } - Address address = local_heap.AllocateRawOrFail( - kSmallObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, - AllocationAlignment::kTaggedAligned); - objects_->push_back(address); - CreateFixedArray(heap_, address, kSmallObjectSize); - address = local_heap.AllocateRawOrFail( - kMediumObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, - AllocationAlignment::kTaggedAligned); - objects_->push_back(address); - CreateFixedArray(heap_, address, kMediumObjectSize); - } - } + IsolateWrapper isolate_wrapper(kNoCounters); + v8::Isolate* isolate = isolate_wrapper.isolate(); + Isolate* i_isolate = isolate_wrapper.i_isolate(); + Heap* heap = i_isolate->heap(); - Heap* heap_; - std::vector<Address>* objects_; - base::Semaphore* sema_white_; - base::Semaphore* sema_marking_started_; -}; + v8::Isolate::Scope isolate_scope(isolate); -UNINITIALIZED_TEST(ConcurrentBlackAllocation) { - if (!v8_flags.incremental_marking) return; - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - Heap* heap = i_isolate->heap(); - { - v8::Isolate::Scope isolate_scope(isolate); + std::vector<Address> objects; - std::vector<Address> objects; + base::Semaphore sema_white(0); + base::Semaphore sema_marking_started(0); - base::Semaphore sema_white(0); - base::Semaphore sema_marking_started(0); + auto thread = std::make_unique<ConcurrentBlackAllocationThread>( + heap, &objects, &sema_white, &sema_marking_started); + CHECK(thread->Start()); - auto thread = std::make_unique<ConcurrentBlackAllocationThread>( - heap, &objects, &sema_white, &sema_marking_started); - CHECK(thread->Start()); + sema_white.Wait(); + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + sema_marking_started.Signal(); - sema_white.Wait(); - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - sema_marking_started.Signal(); + thread->Join(); - thread->Join(); + constexpr uint32_t kObjectsAllocatedPerIteration = 2; - const uint32_t kObjectsAllocatedPerIteration = 2; - - for (uint32_t i = 0; i < kNumIterations * kObjectsAllocatedPerIteration; - i++) { - Address address = objects[i]; - Tagged<HeapObject> object = HeapObject::FromAddress(address); - if (v8_flags.black_allocated_pages) { - CHECK(heap->marking_state()->IsUnmarked(object)); - if (i < kWhiteIterations * kObjectsAllocatedPerIteration) { - CHECK(!TrustedHeapLayout::InBlackAllocatedPage(object)); - } else { - CHECK(TrustedHeapLayout::InBlackAllocatedPage(object)); - } + for (uint32_t i = 0; i < kNumIterations * kObjectsAllocatedPerIteration; + i++) { + Address address = objects[i]; + Tagged<HeapObject> object = HeapObject::FromAddress(address); + if (v8_flags.black_allocated_pages) { + EXPECT_TRUE(heap->marking_state()->IsUnmarked(object)); + if (i < kWhiteIterations * kObjectsAllocatedPerIteration) { + EXPECT_FALSE(TrustedHeapLayout::InBlackAllocatedPage(object)); } else { - if (i < kWhiteIterations * kObjectsAllocatedPerIteration) { - CHECK(heap->marking_state()->IsUnmarked(object)); - } else { - CHECK(heap->marking_state()->IsMarked(object)); - } + EXPECT_TRUE(TrustedHeapLayout::InBlackAllocatedPage(object)); + } + } else { + if (i < kWhiteIterations * kObjectsAllocatedPerIteration) { + EXPECT_TRUE(heap->marking_state()->IsUnmarked(object)); + } else { + EXPECT_TRUE(heap->marking_state()->IsMarked(object)); } } } - isolate->Dispose(); } -class ConcurrentWriteBarrierThread final : public v8::base::Thread { - public: - ConcurrentWriteBarrierThread(Heap* heap, Tagged<FixedArray> fixed_array, - Tagged<HeapObject> value) - : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), - heap_(heap), - fixed_array_(fixed_array), - value_(value) {} - - void Run() override { - LocalHeap local_heap(heap_, ThreadKind::kBackground); - UnparkedScope unparked_scope(&local_heap); - fixed_array_->set(0, value_); - } - - Heap* heap_; - Tagged<FixedArray> fixed_array_; - Tagged<HeapObject> value_; -}; - -UNINITIALIZED_TEST(ConcurrentWriteBarrier) { +TEST_F(ConcurrentAllocationUninitializedTest, ConcurrentWriteBarrier) { if (!v8_flags.incremental_marking) return; if (!v8_flags.concurrent_marking) { // The test requires concurrent marking barrier. return; } - ManualGCScope manual_gc_scope; + ManualGCScope manual_gc_scope(nullptr); - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + v8::Isolate* isolate = isolate_wrapper.isolate(); + Isolate* i_isolate = isolate_wrapper.i_isolate(); Heap* heap = i_isolate->heap(); + + v8::Isolate::Scope isolate_scope(isolate); + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + Tagged<FixedArray> fixed_array; + Tagged<HeapObject> value; { - v8::Isolate::Scope isolate_scope(isolate); - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - Tagged<FixedArray> fixed_array; - Tagged<HeapObject> value; - { - HandleScope handle_scope(i_isolate); - DirectHandle<FixedArray> fixed_array_handle( - i_isolate->factory()->NewFixedArray(1)); - DirectHandle<HeapNumber> value_handle( - i_isolate->factory()->NewHeapNumber<AllocationType::kOld>(1.1)); - fixed_array = *fixed_array_handle; - value = *value_handle; - } - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - CHECK(heap->marking_state()->IsUnmarked(value)); + HandleScope handle_scope(i_isolate); + DirectHandle<FixedArray> fixed_array_handle( + i_isolate->factory()->NewFixedArray(1)); + DirectHandle<HeapNumber> value_handle( + i_isolate->factory()->NewHeapNumber<AllocationType::kOld>(1.1)); + fixed_array = *fixed_array_handle; + value = *value_handle; + } + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + EXPECT_TRUE(heap->marking_state()->IsUnmarked(value)); - // Mark host |fixed_array| to trigger the barrier. - heap->marking_state()->TryMarkAndAccountLiveBytes(fixed_array); + // Mark host |fixed_array| to trigger the barrier. + heap->marking_state()->TryMarkAndAccountLiveBytes(fixed_array); - auto thread = std::make_unique<ConcurrentWriteBarrierThread>( - heap, fixed_array, value); - CHECK(thread->Start()); + auto thread = + std::make_unique<ConcurrentWriteBarrierThread>(heap, fixed_array, value); + CHECK(thread->Start()); - thread->Join(); + thread->Join(); - CHECK(heap->marking_state()->IsMarked(value)); - heap::InvokeMajorGC(heap); - } - isolate->Dispose(); + EXPECT_TRUE(heap->marking_state()->IsMarked(value)); + InvokeMajorGC(i_isolate); } -class ConcurrentRecordRelocSlotThread final : public v8::base::Thread { - public: - ConcurrentRecordRelocSlotThread(Heap* heap, Tagged<Code> code, - Tagged<HeapObject> value) - : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), - heap_(heap), - code_(code), - value_(value) {} - - void Run() override { - LocalHeap local_heap(heap_, ThreadKind::kBackground); - UnparkedScope unparked_scope(&local_heap); - DisallowGarbageCollection no_gc; - Tagged<InstructionStream> istream = code_->instruction_stream(); - int mode_mask = RelocInfo::EmbeddedObjectModeMask(); - WritableJitAllocation jit_allocation = ThreadIsolation::LookupJitAllocation( - istream->address(), istream->Size(), - ThreadIsolation::JitAllocationType::kInstructionStream, true); - for (WritableRelocIterator it(jit_allocation, istream, - code_->constant_pool(), mode_mask); - !it.done(); it.next()) { - DCHECK(RelocInfo::IsEmbeddedObjectMode(it.rinfo()->rmode())); - it.rinfo()->set_target_object(istream, value_); - } - } - - Heap* heap_; - Tagged<Code> code_; - Tagged<HeapObject> value_; -}; - -UNINITIALIZED_TEST(ConcurrentRecordRelocSlot) { +TEST_F(ConcurrentAllocationUninitializedTest, ConcurrentRecordRelocSlot) { if (!v8_flags.incremental_marking) return; if (!v8_flags.concurrent_marking) { // The test requires concurrent marking barrier. return; } - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope + ManualGCScope manual_gc_scope(nullptr); + ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + IsolateWrapper isolate_wrapper(kNoCounters); + v8::Isolate* isolate = isolate_wrapper.isolate(); + Isolate* i_isolate = isolate_wrapper.i_isolate(); Heap* heap = i_isolate->heap(); + + v8::Isolate::Scope isolate_scope(isolate); + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + Tagged<Code> code; + Tagged<HeapObject> value; { - v8::Isolate::Scope isolate_scope(isolate); - PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); - Tagged<Code> code; - Tagged<HeapObject> value; - { - HandleScope handle_scope(i_isolate); - uint8_t buffer[i::Assembler::kDefaultBufferSize]; - MacroAssembler masm(i_isolate, v8::internal::CodeObjectRequired{true}, - ExternalAssemblerBuffer(buffer, sizeof(buffer))); + HandleScope handle_scope(i_isolate); + uint8_t buffer[Assembler::kDefaultBufferSize]; + MacroAssembler masm(i_isolate, CodeObjectRequired{true}, + ExternalAssemblerBuffer(buffer, sizeof(buffer))); #if V8_TARGET_ARCH_ARM64 - // Arm64 requires stack alignment. - UseScratchRegisterScope temps(&masm); - Register tmp = temps.AcquireX(); - masm.Mov(tmp, Operand(i_isolate->factory()->undefined_value())); - masm.Push(tmp, padreg); + // Arm64 requires stack alignment. + UseScratchRegisterScope temps(&masm); + Register tmp = temps.AcquireX(); + masm.Mov(tmp, Operand(i_isolate->factory()->undefined_value())); + masm.Push(tmp, padreg); #else - masm.Push(i_isolate->factory()->undefined_value()); + masm.Push(i_isolate->factory()->undefined_value()); #endif - CodeDesc desc; - masm.GetCode(i_isolate, &desc); - DirectHandle<Code> code_handle = - Factory::CodeBuilder(i_isolate, desc, CodeKind::FOR_TESTING).Build(); - // Globalize the handle for |code| for the incremental marker to mark it. - i_isolate->global_handles()->Create(*code_handle); - heap::AbandonCurrentlyFreeMemory(heap->old_space()); - DirectHandle<HeapNumber> value_handle( - i_isolate->factory()->NewHeapNumber<AllocationType::kOld>(1.1)); - heap::ForceEvacuationCandidate(NormalPage::FromHeapObject(*value_handle)); - code = *code_handle; - value = *value_handle; - } - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - CHECK(heap->marking_state()->IsUnmarked(value)); + CodeDesc desc; + masm.GetCode(i_isolate, &desc); + DirectHandle<Code> code_handle = + Factory::CodeBuilder(i_isolate, desc, CodeKind::FOR_TESTING).Build(); + // Globalize the handle for |code| for the incremental marker to mark it. + i_isolate->global_handles()->Create(*code_handle); + AbandonCurrentlyFreeMemory(heap->old_space()); + DirectHandle<HeapNumber> value_handle( + i_isolate->factory()->NewHeapNumber<AllocationType::kOld>(1.1)); + ForceEvacuationCandidate(NormalPage::FromHeapObject(*value_handle)); + code = *code_handle; + value = *value_handle; + } + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + EXPECT_TRUE(heap->marking_state()->IsUnmarked(value)); - // Advance marking to make sure |code| is marked. - heap->incremental_marking()->AdvanceForTesting(v8::base::TimeDelta::Max()); + // Advance marking to make sure |code| is marked. + heap->incremental_marking()->AdvanceForTesting(v8::base::TimeDelta::Max()); - CHECK(heap->marking_state()->IsMarked(code)); - CHECK(heap->marking_state()->IsUnmarked(value)); + EXPECT_TRUE(heap->marking_state()->IsMarked(code)); + EXPECT_TRUE(heap->marking_state()->IsUnmarked(value)); - { - auto thread = - std::make_unique<ConcurrentRecordRelocSlotThread>(heap, code, value); - CHECK(thread->Start()); + auto thread = + std::make_unique<ConcurrentRecordRelocSlotThread>(heap, code, value); + CHECK(thread->Start()); - thread->Join(); - } + thread->Join(); - CHECK(heap->marking_state()->IsMarked(value)); - heap::InvokeMajorGC(heap); - } - isolate->Dispose(); + EXPECT_TRUE(heap->marking_state()->IsMarked(value)); + InvokeMajorGC(i_isolate); } } // namespace internal diff --git a/deps/v8/test/unittests/heap/cppgc-js/cpp-heap-stack-start-marker-unittest.cc b/deps/v8/test/unittests/heap/cppgc-js/cpp-heap-stack-start-marker-unittest.cc index 1e0c63bca302..f2916beacd61 100644 --- a/deps/v8/test/unittests/heap/cppgc-js/cpp-heap-stack-start-marker-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc-js/cpp-heap-stack-start-marker-unittest.cc @@ -21,6 +21,8 @@ class CppHeapStackStartMarkerTest : public TestWithPlatform {}; } // namespace +START_ALLOW_USE_DEPRECATED() + TEST_F(CppHeapStackStartMarkerTest, StackStartMarkerIsUsed) { cppgc::StackStartMarker marker; CppHeapCreateParams params({}); @@ -64,5 +66,28 @@ TEST_F(CppHeapStackStartMarkerTest, IsolateUsesStackStartMarker) { EXPECT_EQ(expected_stack_start, i_isolate->heap()->stack().stack_start()); } +END_ALLOW_USE_DEPRECATED() + +TEST_F(CppHeapStackStartMarkerTest, StackStartScopeIsUsedByCppHeapAndIsolate) { + const void* original_stack_start = v8::base::Stack::GetEffectiveStackStart(); + { + v8::StackStartScope scope; + const void* scoped_stack_start = v8::base::Stack::GetEffectiveStackStart(); + EXPECT_LT(scoped_stack_start, original_stack_start); + + CppHeapCreateParams params({}); + auto cpp_heap = CppHeap::Create(platform(), params); + CppHeap* internal_heap = CppHeap::From(cpp_heap.get()); + EXPECT_EQ(scoped_stack_start, internal_heap->stack()->stack_start()); + + IsolateWrapper::set_cpp_heap_for_next_isolate(std::move(cpp_heap)); + IsolateWrapper isolate_wrapper(kNoCounters); + + i::Isolate* i_isolate = isolate_wrapper.i_isolate(); + EXPECT_EQ(scoped_stack_start, i_isolate->heap()->stack().stack_start()); + } + EXPECT_EQ(original_stack_start, v8::base::Stack::GetEffectiveStackStart()); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/cppgc-js/unified-heap-snapshot-unittest.cc b/deps/v8/test/unittests/heap/cppgc-js/unified-heap-snapshot-unittest.cc index 76fd2ee5b6c4..1ffbe7f62b6d 100644 --- a/deps/v8/test/unittests/heap/cppgc-js/unified-heap-snapshot-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc-js/unified-heap-snapshot-unittest.cc @@ -1079,7 +1079,7 @@ class WrappedContext : public cppgc::GarbageCollected<WrappedContext>, v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Local<v8::Object> obj = WrapperHelper::CreateWrapper(context, nullptr, "js WrappedContext"); - context->SetEmbedderDataV2(kContextDataIndex, obj); + context->SetEmbedderDataV3(kContextDataIndex, obj); cppgc::Persistent<WrappedContext> ref = cppgc::MakeGarbageCollected<WrappedContext>( isolate->GetCppHeap()->GetAllocationHandle(), isolate, obj, diff --git a/deps/v8/test/unittests/heap/cppgc/allocation-unittest.cc b/deps/v8/test/unittests/heap/cppgc/allocation-unittest.cc index 0853a916d915..28a31a011de5 100644 --- a/deps/v8/test/unittests/heap/cppgc/allocation-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/allocation-unittest.cc @@ -4,10 +4,19 @@ #include "include/cppgc/allocation.h" +#include "include/cppgc/custom-space.h" +#include "include/cppgc/explicit-management.h" +#include "include/cppgc/member.h" +#include "include/cppgc/persistent.h" #include "include/cppgc/visitor.h" +#include "src/heap/cppgc-internal/compactor.h" #include "src/heap/cppgc-internal/globals.h" +#include "src/heap/cppgc-internal/heap-base.h" #include "src/heap/cppgc-internal/heap-config.h" #include "src/heap/cppgc-internal/heap-object-header.h" +#include "src/heap/cppgc-internal/heap.h" +#include "src/heap/cppgc-internal/marker.h" +#include "src/heap/cppgc-internal/sweeper.h" #include "test/unittests/heap/cppgc/tests.h" #include "testing/gtest/include/gtest/gtest.h" @@ -251,5 +260,239 @@ TEST_F(CppgcAllocationTest, AlignToDoubleWordFromAligned) { } } +namespace { + +class TestAllocationSampler : public cppgc::AllocationSampler { + public: + size_t sample_interval = 0; + size_t GetSampleInterval() const override { return sample_interval; } + bool OnAllocated(void* address, size_t size) override { + allocations.push_back({address, size}); + return true; + } + void OnFreed(void* address) override { freed.push_back(address); } + bool OnMove(void* from, void* to, size_t size) override { + OnFreed(from); + return OnAllocated(to, size); + } + + struct Allocation { + void* address; + size_t size; + }; + std::vector<Allocation> allocations; + std::vector<void*> freed; +}; + +struct SampledObject : GarbageCollected<SampledObject> { + char data[64]; + void Trace(Visitor*) const {} +}; + +struct LargeSampledObject : GarbageCollected<LargeSampledObject> { + char data[kLargeObjectSizeThreshold + 1024]; + void Trace(Visitor*) const {} +}; + +} // namespace + +TEST_F(CppgcAllocationTest, AllocationSampler) { + TestAllocationSampler sampler; + sampler.sample_interval = 1024; // Clamp LAB to 1KB. + auto platform = std::make_shared<testing::TestPlatform>(); + cppgc::Heap::HeapOptions options; + options.allocation_sampler = &sampler; + auto heap = cppgc::Heap::Create(platform, std::move(options)); + + EXPECT_EQ(0u, sampler.allocations.size()); + + // Allocate an object in regular space, which triggers a clamped LAB refill + // and samples the object crossing the LAB boundary. + auto* obj1 = MakeGarbageCollected<SampledObject>(heap->GetAllocationHandle()); + EXPECT_NE(nullptr, obj1); + ASSERT_GE(sampler.allocations.size(), 1u); + EXPECT_EQ(obj1, sampler.allocations[0].address); + EXPECT_EQ(sizeof(SampledObject) + sizeof(HeapObjectHeader), + sampler.allocations[0].size); + + // Allocate a large object (> kLargeObjectSizeThreshold). + const size_t prev_allocations = sampler.allocations.size(); + auto* large_obj = + MakeGarbageCollected<LargeSampledObject>(heap->GetAllocationHandle()); + EXPECT_NE(nullptr, large_obj); + EXPECT_EQ(sampler.allocations.size(), prev_allocations + 1); + EXPECT_EQ(large_obj, sampler.allocations.back().address); + EXPECT_EQ(sizeof(LargeSampledObject) + sizeof(HeapObjectHeader), + sampler.allocations.back().size); + + // Allocate a large object that is kept alive through GC. + Persistent<LargeSampledObject> surviving_obj = + MakeGarbageCollected<LargeSampledObject>(heap->GetAllocationHandle()); + EXPECT_NE(nullptr, surviving_obj); + EXPECT_EQ(surviving_obj.Get(), sampler.allocations.back().address); + + // Trigger GC to verify unreachable objects notify OnFreed, while reachable + // objects remain alive. + heap->ForceGarbageCollectionSlow("Testing", "Testing", + cppgc::Heap::StackState::kNoHeapPointers); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), obj1) != + sampler.freed.end()); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + large_obj) != sampler.freed.end()); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + surviving_obj.Get()) == sampler.freed.end()); + + // Clear root and trigger second GC. The object should now be freed. + void* surviving_address = surviving_obj.Get(); + surviving_obj.Clear(); + heap->ForceGarbageCollectionSlow("Testing", "Testing", + cppgc::Heap::StackState::kNoHeapPointers); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + surviving_address) != sampler.freed.end()); + + // Explicitly freeing a sampled object should immediately notify OnFreed and + // remove it from tracked objects. + auto* explicitly_freed_obj = + MakeGarbageCollected<LargeSampledObject>(heap->GetAllocationHandle()); + void* explicitly_freed_address = explicitly_freed_obj; + EXPECT_EQ(explicitly_freed_address, sampler.allocations.back().address); + sampler.freed.clear(); + subtle::FreeUnreferencedObject(heap->GetHeapHandle(), *explicitly_freed_obj); + EXPECT_EQ(1, std::count(sampler.freed.begin(), sampler.freed.end(), + explicitly_freed_address)); + sampler.freed.clear(); + heap->ForceGarbageCollectionSlow("Testing", "Testing", + cppgc::Heap::StackState::kNoHeapPointers); + EXPECT_TRUE(sampler.freed.empty()); + + // Allocate an object that stays alive until heap destruction. + Persistent<LargeSampledObject> teardown_obj = + MakeGarbageCollected<LargeSampledObject>(heap->GetAllocationHandle()); + void* teardown_address = teardown_obj.Get(); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + teardown_address) == sampler.freed.end()); + + // Destroy the heap. Remaining sampled objects should notify OnFreed. + heap.reset(); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + teardown_address) != sampler.freed.end()); +} + +TEST_F(CppgcAllocationTest, AllocationSamplerObjectLargerThanSampleInterval) { + TestAllocationSampler sampler; + sampler.sample_interval = 1024; + auto platform = std::make_shared<testing::TestPlatform>(); + cppgc::Heap::HeapOptions options; + options.allocation_sampler = &sampler; + auto heap = cppgc::Heap::Create(platform, std::move(options)); + + struct LargeNormalObject : GarbageCollected<LargeNormalObject> { + char data[2048]; + void Trace(Visitor*) const {} + }; + + // Allocating an object in normal space larger than sample_interval should + // succeed without infinite recursion or crashing, and clamp LAB + // appropriately. + auto* obj = + MakeGarbageCollected<LargeNormalObject>(heap->GetAllocationHandle()); + EXPECT_NE(nullptr, obj); + ASSERT_GE(sampler.allocations.size(), 1u); + EXPECT_EQ(obj, sampler.allocations.back().address); +} + +} // namespace internal + +class CompactableCustomSpaceForSampler + : public CustomSpace<CompactableCustomSpaceForSampler> { + public: + static constexpr CustomSpaceIndex kSpaceIndex = 0; + static constexpr bool kSupportsCompaction = true; +}; + +struct MovableSampledGCed : public GarbageCollected<MovableSampledGCed> { + public: + void Trace(Visitor* visitor) const {} + size_t id = 0; +}; + +struct MovableSampledHolder : public GarbageCollected<MovableSampledHolder> { + public: + explicit MovableSampledHolder(cppgc::AllocationHandle& allocation_handle) { + objects[0] = MakeGarbageCollected<MovableSampledGCed>(allocation_handle); + objects[1] = MakeGarbageCollected<MovableSampledGCed>(allocation_handle); + } + void Trace(Visitor* visitor) const { + for (int i = 0; i < 2; ++i) { + visitor->Trace(objects[i]); + visitor->RegisterMovableReference(objects[i].GetSlotForTesting()); + } + } + subtle::UncompressedMember<MovableSampledGCed> objects[2]{}; +}; + +template <> +struct SpaceTrait<MovableSampledGCed> { + using Space = CompactableCustomSpaceForSampler; +}; + +namespace internal { + +TEST_F(CppgcAllocationTest, AllocationSamplerCompaction) { + TestAllocationSampler sampler; + sampler.sample_interval = sizeof(MovableSampledGCed); + auto platform = std::make_shared<testing::TestPlatform>(); + cppgc::Heap::HeapOptions options; + options.allocation_sampler = &sampler; + options.custom_spaces.emplace_back( + std::make_unique<CompactableCustomSpaceForSampler>()); + auto heap = cppgc::Heap::Create(platform, std::move(options)); + + Persistent<MovableSampledHolder> holder = + MakeGarbageCollected<MovableSampledHolder>(heap->GetAllocationHandle(), + heap->GetAllocationHandle()); + void* first_address = holder->objects[0].Get(); + void* original_address = holder->objects[1].Get(); + EXPECT_NE(nullptr, original_address); + EXPECT_NE(first_address, original_address); + EXPECT_EQ(original_address, sampler.allocations.back().address); + const size_t expected_size = sampler.allocations.back().size; + + // Start incremental GC with compaction enabled, free objects[0], and compact + // so that objects[1] is relocated to objects[0]'s former address. + auto* internal_heap = Heap::From(heap.get()); + auto& compactor = internal_heap->compactor(); + compactor.EnableForNextGCForTesting(); + compactor.InitializeIfShouldCompact(GCConfig::MarkingType::kIncremental, + StackState::kNoHeapPointers); + internal_heap->StartIncrementalGarbageCollection( + GCConfig::PreciseIncrementalConfig()); + holder->objects[0] = nullptr; + internal_heap->marker()->FinishMarking(StackState::kNoHeapPointers); + internal_heap->GetMarkerRefForTesting().reset(); + internal_heap->FilterSampledObjects(); + const auto compactable_space_handling = compactor.CompactSpacesIfEnabled(); + internal_heap->sweeper().Start( + {SweepingConfig::SweepingType::kAtomic, compactable_space_handling}); + internal_heap->sweeper().FinishIfRunning(); + + void* current_address = holder->objects[1].Get(); + EXPECT_NE(current_address, original_address); + EXPECT_EQ(current_address, first_address); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + original_address) != sampler.freed.end()); + EXPECT_EQ(current_address, sampler.allocations.back().address); + EXPECT_EQ(expected_size, sampler.allocations.back().size); + + // Clear root and trigger GC. The object at its relocated address should now + // be freed. + sampler.freed.clear(); + holder.Clear(); + heap->ForceGarbageCollectionSlow("Testing", "Testing", + cppgc::Heap::StackState::kNoHeapPointers); + EXPECT_TRUE(std::find(sampler.freed.begin(), sampler.freed.end(), + current_address) != sampler.freed.end()); +} + } // namespace internal } // namespace cppgc diff --git a/deps/v8/test/unittests/heap/cppgc/concurrent-marking-unittest.cc b/deps/v8/test/unittests/heap/cppgc/concurrent-marking-unittest.cc index a09ea3734e6b..4d1ac77d479f 100644 --- a/deps/v8/test/unittests/heap/cppgc/concurrent-marking-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/concurrent-marking-unittest.cc @@ -4,8 +4,12 @@ #include "include/cppgc/allocation.h" #include "include/cppgc/default-platform.h" +#include "include/cppgc/heap-consistency.h" +#include "include/cppgc/liveness-broker.h" #include "include/cppgc/member.h" #include "include/cppgc/persistent.h" +#include "include/cppgc/testing.h" +#include "include/cppgc/trace-trait.h" #include "src/heap/cppgc-internal/globals.h" #include "src/heap/cppgc-internal/marker.h" #include "src/heap/cppgc-internal/marking-visitor.h" @@ -13,6 +17,10 @@ #include "test/unittests/heap/cppgc/tests.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(CPPGC_IS_STANDALONE) +#include "src/common/synchronization-point-support.h" +#endif // !defined(CPPGC_IS_STANDALONE) + namespace cppgc { namespace internal { @@ -195,5 +203,121 @@ TEST_F(ConcurrentMarkingTest, FinishGC(); } +#if !defined(CPPGC_IS_STANDALONE) + +namespace { + +class WeakTableBacking : public GarbageCollected<WeakTableBacking> { + public: + explicit WeakTableBacking(GCed* value) : value_(value) {} + void Trace(cppgc::Visitor* visitor) const { visitor->TraceStrongly(value_); } + + CPPGC_PLUGIN_IGNORE("Traced strongly through TraceStrongly") + WeakMember<GCed> value_; +}; + +class WeakTable { + CPPGC_DISALLOW_NEW(); + + public: + static constexpr std::string_view kSyncPoint = + "cppgc.ConcurrentMarkingTest.TraceWeakTable"; + + WeakTable() = default; + explicit WeakTable(AllocationHandle& handle) + : backing_(MakeGarbageCollected<WeakTableBacking>( + handle, MakeGarbageCollected<GCed>(handle))) {} + + void Trace(cppgc::Visitor* visitor) const { + const WeakTableBacking* backing = backing_.Get(); + SYNCHRONIZATION_POINT(kSyncPoint); + visitor->TraceWeakContainer(backing, WeakCallback, this); + } + + void Swap(WeakTable& other) { + backing_.Swap(other.backing_); + WriteBarrier(backing_); + WriteBarrier(other.backing_); + } + + private: + static void WeakCallback(const LivenessBroker& broker, const void* data) { + const WeakTable* self = static_cast<const WeakTable*>(data); + if (self->backing_ && !broker.IsHeapObjectAlive(self->backing_->value_)) { + self->backing_->value_.Clear(); + } + } + + static void WriteBarrier(Member<WeakTableBacking>& slot) { + WeakTableBacking* value = slot.Get(); + if (!value) return; + subtle::HeapConsistency::WriteBarrierParams params; + const auto barrier_type = + subtle::HeapConsistency::GetWriteBarrierType(slot, params); + DCHECK(barrier_type == + subtle::HeapConsistency::WriteBarrierType::kMarking || + barrier_type == subtle::HeapConsistency::WriteBarrierType::kNone); + if (barrier_type == subtle::HeapConsistency::WriteBarrierType::kMarking) { + subtle::HeapConsistency::DijkstraWriteBarrier(params, value); + } + if (subtle::HeapConsistency::GetWriteBarrierType(value, params) == + subtle::HeapConsistency::WriteBarrierType::kMarking) { + subtle::HeapConsistency::SteeleWriteBarrier(params, value); + } + } + + CPPGC_PLUGIN_IGNORE("Traced through TraceWeakContainer") + Member<WeakTableBacking> backing_; +}; + +struct WeakTableHolder : public GarbageCollected<WeakTableHolder> { + explicit WeakTableHolder(AllocationHandle& handle) : table(handle) {} + void Trace(cppgc::Visitor* visitor) const { visitor->Trace(table); } + + WeakTable table; +}; + +} // namespace + +} // namespace internal + +template <> +struct TraceTrait<internal::WeakTableBacking> + : public internal::TraceTraitBase<internal::WeakTableBacking> { + static TraceDescriptor GetWeakTraceDescriptor(const void* self) { + return {self, nullptr}; + } +}; + +namespace internal { + +TEST_F(ConcurrentMarkingTest, SwapWeakTableWithStackDuringConcurrentMarking) { + // Regression test: https://crbug.com/575143870. + static constexpr v8::base::TimeDelta kTimeout = + v8::base::TimeDelta::FromSeconds(5); + + auto* sync_points = v8::internal::SynchronizationPointSupport::Get(); + sync_points->RequestBlockAt(std::string(WeakTable::kSyncPoint), kTimeout); + + Persistent<WeakTableHolder> holder = MakeGarbageCollected<WeakTableHolder>( + GetAllocationHandle(), GetAllocationHandle()); + WeakTable stack_table; + + cppgc::testing::StandaloneTestingHeap testing_heap(GetHeapHandle()); + testing_heap.StartGarbageCollection(); + + ASSERT_TRUE(sync_points->WaitUntilBlocked(WeakTable::kSyncPoint, kTimeout)); + + holder->table.Swap(stack_table); + + ASSERT_TRUE(sync_points->Resume(WeakTable::kSyncPoint)); + + testing_heap.FinalizeGarbageCollection(EmbedderStackState::kNoHeapPointers); + + ConservativeGC(); +} + +#endif // !defined(CPPGC_IS_STANDALONE) + } // namespace internal } // namespace cppgc diff --git a/deps/v8/test/unittests/heap/cppgc/stack-start-marker-unittest.cc b/deps/v8/test/unittests/heap/cppgc/stack-start-marker-unittest.cc index 3366f6850f1d..4dd0880641c4 100644 --- a/deps/v8/test/unittests/heap/cppgc/stack-start-marker-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/stack-start-marker-unittest.cc @@ -44,5 +44,40 @@ TEST_F(StackStartMarkerTest, DefaultWithoutStackStartMarker) { internal_heap->stack()->stack_start()); } +TEST_F(StackStartMarkerTest, StackStartScopeIsUsed) { + const void* original_stack_start = v8::base::Stack::GetStackStart(); + EXPECT_EQ(original_stack_start, v8::base::Stack::GetEffectiveStackStart()); + { + StackStartScope scope; + EXPECT_GT(original_stack_start, v8::base::Stack::GetEffectiveStackStart()); + EXPECT_EQ(original_stack_start, v8::base::Stack::GetStackStart()); + + auto heap = Heap::Create(GetPlatformHandle()); + Heap* internal_heap = Heap::From(heap.get()); + + EXPECT_EQ(v8::base::Stack::GetEffectiveStackStart(), + internal_heap->stack()->stack_start()); + EXPECT_TRUE(internal_heap->ShouldCheckForTLSOnStack()); + } + EXPECT_EQ(original_stack_start, v8::base::Stack::GetEffectiveStackStart()); +} + +V8_NOINLINE void TestNestedStackStartScope(const void* outer_stack_start) { + StackStartScope inner_scope; + EXPECT_GT(outer_stack_start, v8::base::Stack::GetEffectiveStackStart()); +} + +TEST_F(StackStartMarkerTest, NestedStackStartScopes) { + const void* original_stack_start = v8::base::Stack::GetEffectiveStackStart(); + { + StackStartScope outer_scope; + const void* outer_stack_start = v8::base::Stack::GetEffectiveStackStart(); + EXPECT_LT(outer_stack_start, original_stack_start); + TestNestedStackStartScope(outer_stack_start); + EXPECT_EQ(outer_stack_start, v8::base::Stack::GetEffectiveStackStart()); + } + EXPECT_EQ(original_stack_start, v8::base::Stack::GetEffectiveStackStart()); +} + } // namespace internal } // namespace cppgc diff --git a/deps/v8/test/unittests/heap/cppgc/stack-unittest.cc b/deps/v8/test/unittests/heap/cppgc/stack-unittest.cc index 28950b415156..b3146b0de457 100644 --- a/deps/v8/test/unittests/heap/cppgc/stack-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/stack-unittest.cc @@ -25,7 +25,8 @@ namespace { class GCStackTest : public ::testing::Test { public: GCStackTest() : stack_(std::make_unique<Stack>()) { - stack_->SetStackStart(v8::base::Stack::GetStackStart()); + stack_->SetStackStart(v8::base::Stack::GetStackStart(), + /*check_for_tls=*/true); } Stack* GetStack() const { return stack_.get(); } diff --git a/deps/v8/test/unittests/heap/cppgc/workloads-unittest.cc b/deps/v8/test/unittests/heap/cppgc/workloads-unittest.cc index 3329dc785bc3..edbd1a2c1cc9 100644 --- a/deps/v8/test/unittests/heap/cppgc/workloads-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/workloads-unittest.cc @@ -184,11 +184,12 @@ class DynamicallySizedObject final : public GarbageCollected<DynamicallySizedObject> { public: static DynamicallySizedObject* Create(AllocationHandle& allocation_handle, - size_t size) { + uint32_t size) { CHECK_GT(size, sizeof(DynamicallySizedObject)); return MakeGarbageCollected<DynamicallySizedObject>( allocation_handle, - AdditionalBytes(size - sizeof(DynamicallySizedObject))); + AdditionalBytes(size - + static_cast<uint32_t>(sizeof(DynamicallySizedObject)))); } uint8_t Get(int i) { return *(reinterpret_cast<uint8_t*>(this) + i); } @@ -275,7 +276,7 @@ TEST_F(WorkloadsTest, BasicFunctionality) { EXPECT_EQ(0ul, heap->stats_collector()->allocated_memory_size()); } - size_t big = 1008; + uint32_t big = 1008; Persistent<DynamicallySizedObject> big_area = DynamicallySizedObject::Create(GetAllocationHandle(), big); total += big; @@ -285,7 +286,7 @@ TEST_F(WorkloadsTest, BasicFunctionality) { Persistent<DynamicallySizedObject>* persistents[kNumPersistents]; for (int i = 0; i < 1000; i++) { - size_t size = 128 + i * 8; + uint32_t size = 128 + i * 8; total += size; persistents[persistent_count++] = new Persistent<DynamicallySizedObject>( DynamicallySizedObject::Create(GetAllocationHandle(), size)); diff --git a/deps/v8/test/unittests/heap/cppgc/write-barrier-unittest.cc b/deps/v8/test/unittests/heap/cppgc/write-barrier-unittest.cc index 9df26a108ca6..bfe99ffa50e1 100644 --- a/deps/v8/test/unittests/heap/cppgc/write-barrier-unittest.cc +++ b/deps/v8/test/unittests/heap/cppgc/write-barrier-unittest.cc @@ -476,11 +476,11 @@ TEST_F(WriteBarrierTest, SteeleWriteBarrierTriggersWhenMarkingIsOn) { } } -TEST_F(WriteBarrierTest, SteeleWriteBarrierBailoutIfNotMarked) { +TEST_F(WriteBarrierTest, SteeleWriteBarrierTriggersEvenIfNotMarked) { auto* object1 = MakeGarbageCollected<GCed>(GetAllocationHandle()); auto* object2 = MakeGarbageCollected<GCed>(GetAllocationHandle(), object1); { - ExpectNoWriteBarrierFires scope(marker(), {object1}); + ExpectWriteBarrierFires scope(marker(), {object1}); WriteBarrierParams params; EXPECT_EQ(WriteBarrierType::kMarking, HeapConsistency::GetWriteBarrierType( diff --git a/deps/v8/test/cctest/heap/test-external-string-tracker.cc b/deps/v8/test/unittests/heap/external-string-tracker-unittest.cc similarity index 53% rename from deps/v8/test/cctest/heap/test-external-string-tracker.cc rename to deps/v8/test/unittests/heap/external-string-tracker-unittest.cc index 5848e8f35129..be9e509ae40d 100644 --- a/deps/v8/test/cctest/heap/test-external-string-tracker.cc +++ b/deps/v8/test/unittests/heap/external-string-tracker-unittest.cc @@ -7,17 +7,21 @@ #include "src/execution/isolate.h" #include "src/heap/heap-inl.h" #include "src/heap/heap-layout-inl.h" +#include "src/heap/normal-page-inl.h" #include "src/heap/spaces.h" #include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" #define TEST_STR "tests are great!" namespace v8 { namespace internal { -namespace heap { + +namespace { + +using ExternalStringTrackerTest = TestWithHeapInternalsAndContext; // Adapted from cctest/test-api.cc class TestOneByteResource : public v8::String::ExternalOneByteStringResource { @@ -45,168 +49,168 @@ class TestOneByteResource : public v8::String::ExternalOneByteStringResource { int* counter_; }; -TEST(ExternalString_ExternalBackingStoreSizeIncreases) { - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); +} // namespace + +TEST_F(ExternalStringTrackerTest, + ExternalString_ExternalBackingStoreSizeIncreases) { + v8::Isolate* isolate = v8_isolate(); + Heap* heap = this->heap(); const size_t backing_store_before = heap->GetExternalStrinBytesForTesting(); { v8::HandleScope handle_scope(isolate); v8::Local<v8::String> es = v8::String::NewExternalOneByte( - isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked(); + isolate, new TestOneByteResource( + i::StrDup(TEST_STR))) + .ToLocalChecked(); USE(es); const size_t backing_store_after = heap->GetExternalStrinBytesForTesting(); - CHECK_EQ(es->Length(), backing_store_after - backing_store_before); + EXPECT_EQ(static_cast<size_t>(es->Length()), + backing_store_after - backing_store_before); } } -TEST(ExternalString_ExternalBackingStoreSizeDecreases) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); +TEST_F(ExternalStringTrackerTest, + ExternalString_ExternalBackingStoreSizeDecreases) { + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + Heap* heap = this->heap(); const size_t backing_store_before = heap->GetExternalStrinBytesForTesting(); { v8::HandleScope handle_scope(isolate); v8::Local<v8::String> es = v8::String::NewExternalOneByte( - isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked(); + isolate, new TestOneByteResource( + i::StrDup(TEST_STR))) + .ToLocalChecked(); USE(es); } { // We need to invoke GC without stack, otherwise some objects may not be // reclaimed because of conservative stack scanning. - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeAtomicMajorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + InvokeAtomicMajorGC(); } const size_t backing_store_after = heap->GetExternalStrinBytesForTesting(); - CHECK_EQ(backing_store_after, backing_store_before); + EXPECT_EQ(backing_store_after, backing_store_before); } -TEST(ExternalString_ExternalBackingStoreSizeIncreasesMarkCompact) { +TEST_F(ExternalStringTrackerTest, + ExternalString_ExternalBackingStoreSizeIncreasesMarkCompact) { if (!v8_flags.compact) return; - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); - heap::AbandonCurrentlyFreeMemory(heap->old_space()); + v8::Isolate* isolate = v8_isolate(); + Heap* heap = this->heap(); + AbandonCurrentlyFreeMemory(heap->old_space()); const size_t backing_store_before = heap->GetExternalStrinBytesForTesting(); { v8::HandleScope handle_scope(isolate); v8::Local<v8::String> es = v8::String::NewExternalOneByte( - isolate, new TestOneByteResource(i::StrDup(TEST_STR))).ToLocalChecked(); - v8::internal::DirectHandle<v8::internal::String> esh = - v8::Utils::OpenDirectHandle(*es); + isolate, new TestOneByteResource( + i::StrDup(TEST_STR))) + .ToLocalChecked(); + DirectHandle<String> esh = v8::Utils::OpenDirectHandle(*es); NormalPage* page_before_gc = NormalPage::FromHeapObject(*esh); - heap::ForceEvacuationCandidate(page_before_gc); + ForceEvacuationCandidate(page_before_gc); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); const size_t backing_store_after = heap->GetExternalStrinBytesForTesting(); - CHECK_EQ(es->Length(), backing_store_after - backing_store_before); + EXPECT_EQ(static_cast<size_t>(es->Length()), + backing_store_after - backing_store_before); } { // We need to invoke GC without stack, otherwise some objects may not be // reclaimed because of conservative stack scanning. - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeAtomicMajorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + InvokeAtomicMajorGC(); } const size_t backing_store_after = heap->GetExternalStrinBytesForTesting(); - CHECK_EQ(0, backing_store_after - backing_store_before); + EXPECT_EQ(0u, backing_store_after - backing_store_before); } -TEST(ExternalString_ExternalBackingStoreSizeIncreasesAfterExternalization) { +TEST_F(ExternalStringTrackerTest, + ExternalString_ExternalBackingStoreSizeIncreasesAfterExternalization) { if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap(); + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + Heap* heap = this->heap(); const size_t backing_store_before = heap->GetExternalStrinBytesForTesting(); { v8::HandleScope handle_scope(isolate); - // Allocate normal string in the new gen. v8::Local<v8::String> str = v8::String::NewFromUtf8Literal(isolate, TEST_STR); - CHECK_EQ(heap->GetExternalStrinBytesForTesting(), backing_store_before); + EXPECT_EQ(heap->GetExternalStrinBytesForTesting(), backing_store_before); // Trigger full GC so that the newly allocated string moves to old gen. - heap::InvokeAtomicMajorGC(heap); + InvokeAtomicMajorGC(); bool success = str->MakeExternal( isolate, new TestOneByteResource(i::StrDup(TEST_STR))); - CHECK(success); + EXPECT_TRUE(success); - CHECK_EQ(str->Length(), - heap->GetExternalStrinBytesForTesting() - backing_store_before); + EXPECT_EQ(static_cast<size_t>(str->Length()), + heap->GetExternalStrinBytesForTesting() - backing_store_before); } { // We need to invoke GC without stack, otherwise some objects may not be // reclaimed because of conservative stack scanning. - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeAtomicMajorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + InvokeAtomicMajorGC(); } const size_t backing_store_after = heap->GetExternalStrinBytesForTesting(); - CHECK_EQ(backing_store_after, backing_store_before); + EXPECT_EQ(backing_store_after, backing_store_before); } -TEST(ExternalString_PromotedThinString) { +TEST_F(ExternalStringTrackerTest, ExternalString_PromotedThinString) { if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext env; - v8::Isolate* isolate = env.isolate(); - i::Isolate* i_isolate = CcTest::i_isolate(); - i::Factory* factory = i_isolate->factory(); - Heap* heap = i_isolate->heap(); + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + Factory* factory = i_isolate()->factory(); { v8::HandleScope handle_scope(isolate); // New external string in the old space. - v8::internal::Handle<v8::internal::String> string1 = + Handle<String> string1 = factory ->NewExternalStringFromOneByte( new TestOneByteResource(i::StrDup(TEST_STR))) .ToHandleChecked(); // Internalize external string. - i::Handle<i::String> isymbol1 = factory->InternalizeString(string1); - CHECK(IsInternalizedString(*isymbol1)); - CHECK(IsExternalString(*string1)); - CHECK(!HeapLayout::InYoungGeneration(*isymbol1)); + Handle<String> isymbol1 = factory->InternalizeString(string1); + EXPECT_TRUE(IsInternalizedString(*isymbol1)); + EXPECT_TRUE(IsExternalString(*string1)); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*isymbol1)); // Collect thin string. References to the thin string will be updated to // point to the actual external string in the old space. - heap::InvokeAtomicMinorGC(heap); + InvokeAtomicMinorGC(); USE(isymbol1); } } -} // namespace heap + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/gc-tracer-unittest.cc b/deps/v8/test/unittests/heap/gc-tracer-unittest.cc index 0a3c311f01f4..86877bd1cf17 100644 --- a/deps/v8/test/unittests/heap/gc-tracer-unittest.cc +++ b/deps/v8/test/unittests/heap/gc-tracer-unittest.cc @@ -180,6 +180,45 @@ TEST_F(GCTracerTest, PerGenerationAllocationThroughput) { tracer->ExternalAllocationThroughputInBytesPerMillisecond())); } +TEST_F(GCTracerTest, LowAllocationRateWithZeroEmbedderAllocation) { + if (v8_flags.stress_incremental_marking) return; + Heap* heap = i_isolate()->heap(); + GCTracer* tracer = heap->tracer(); + tracer->ResetForTesting(); + tracer->allocation_time_ = base::TimeTicks(); + + // Two samples 100 ms apart. Young and old generation allocate a little; + // the embedder (CppHeap) and external memory allocate nothing at all, as + // in an embedder that never uses cppgc (e.g. Node.js without node:vm). + tracer->SampleAllocation(base::TimeTicks::FromMsTicksForTesting(0), 0, 0, 0, + 0); + tracer->SampleAllocation(base::TimeTicks::FromMsTicksForTesting(100), 100, + 100, 0, 0); + + EXPECT_DOUBLE_EQ(0.0, + tracer->EmbedderAllocationThroughputInBytesPerMillisecond()); + EXPECT_TRUE(heap->HasLowAllocationRate()); +} + +TEST_F(GCTracerTest, HighAllocationRateWithEmbedderAllocation) { + if (v8_flags.stress_incremental_marking) return; + Heap* heap = i_isolate()->heap(); + GCTracer* tracer = heap->tracer(); + tracer->ResetForTesting(); + tracer->allocation_time_ = base::TimeTicks(); + + // Same as above, but the embedder allocates heavily: 1 GB over 100 ms is + // ~10^7 B/ms, so the embedder term must still report a high allocation + // rate (mu = 200000 / (10^7 + 200000) < 0.993). + tracer->SampleAllocation(base::TimeTicks::FromMsTicksForTesting(0), 0, 0, 0, + 0); + tracer->SampleAllocation(base::TimeTicks::FromMsTicksForTesting(100), 100, + 100, size_t{1} << 30, 0); + + EXPECT_GT(tracer->EmbedderAllocationThroughputInBytesPerMillisecond(), 0.0); + EXPECT_FALSE(heap->HasLowAllocationRate()); +} + TEST_F(GCTracerTest, RegularScope) { if (v8_flags.stress_incremental_marking) return; GCTracer* tracer = i_isolate()->heap()->tracer(); diff --git a/deps/v8/test/unittests/heap/heap-unittest.cc b/deps/v8/test/unittests/heap/heap-unittest.cc index 850bfa9f06b7..be815116a1c1 100644 --- a/deps/v8/test/unittests/heap/heap-unittest.cc +++ b/deps/v8/test/unittests/heap/heap-unittest.cc @@ -4,6 +4,7 @@ #include "src/heap/heap.h" +#include <array> #include <cmath> #include <cstdint> #include <cstdio> @@ -11,6 +12,7 @@ #include <iostream> #include <limits> #include <memory> +#include <set> #include <string> #include <string_view> #include <unordered_map> @@ -22,44 +24,79 @@ #include "include/v8-function.h" #include "include/v8-initialization.h" #include "include/v8-isolate.h" +#include "include/v8-metrics.h" #include "include/v8-object.h" +#include "src/api/api-inl.h" #include "src/base/bounded-page-allocator.h" +#include "src/base/strings.h" +#include "src/builtins/accessors.h" +#include "src/builtins/builtins-inl.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/compilation-cache.h" #include "src/codegen/compiler.h" +#include "src/codegen/macro-assembler-inl.h" #include "src/codegen/script-details.h" #include "src/common/globals.h" +#include "src/deoptimizer/deoptimizer.h" #include "src/flags/flags.h" +#include "src/handles/global-handles-inl.h" #include "src/handles/handles-inl.h" +#include "src/heap/combined-heap.h" #include "src/heap/factory.h" #include "src/heap/gc-tracer-inl.h" #include "src/heap/gc-tracer.h" #include "src/heap/heap-controller.h" +#include "src/heap/heap-inl.h" #include "src/heap/heap-layout-inl.h" #include "src/heap/heap-layout.h" +#include "src/heap/heap-verifier.h" +#include "src/heap/incremental-marking.h" #include "src/heap/large-page-inl.h" +#include "src/heap/large-spaces.h" +#include "src/heap/local-heap-inl.h" #include "src/heap/main-allocator-inl.h" +#include "src/heap/mark-compact-inl.h" #include "src/heap/marking-barrier.h" #include "src/heap/marking-state-inl.h" +#include "src/heap/memory-reducer.h" #include "src/heap/minor-mark-sweep.h" #include "src/heap/mutable-page.h" +#include "src/heap/remembered-set-inl.h" #include "src/heap/remembered-set.h" #include "src/heap/safepoint.h" #include "src/heap/spaces-inl.h" #include "src/heap/trusted-range.h" +#include "src/numbers/hash-seed-inl.h" +#include "src/objects/allocation-site.h" +#include "src/objects/api-callbacks.h" #include "src/objects/bytecode-array-inl.h" +#include "src/objects/call-site-info-inl.h" +#include "src/objects/elements.h" #include "src/objects/feedback-vector-inl.h" +#include "src/objects/field-type.h" #include "src/objects/fixed-array.h" #include "src/objects/free-space-inl.h" +#include "src/objects/heap-number-inl.h" #include "src/objects/instruction-stream-inl.h" #include "src/objects/internal-index.h" #include "src/objects/js-array-buffer-inl.h" +#include "src/objects/js-array-inl.h" #include "src/objects/js-collection-inl.h" +#include "src/objects/managed-inl.h" +#include "src/objects/number-string-cache-inl.h" +#include "src/objects/object-conversions-inl.h" +#include "src/objects/objects-inl.h" +#include "src/objects/property.h" #include "src/objects/script-inl.h" #include "src/objects/shared-function-info-inl.h" +#include "src/objects/slots.h" #include "src/objects/transitions-inl.h" #include "src/regexp/regexp.h" #include "src/sandbox/external-pointer-table.h" +#include "src/snapshot/snapshot.h" +#include "src/tracing/tracing-category-observer.h" +#include "src/utils/ostreams.h" +#include "test/common/flag-utils.h" #include "test/common/noop-bytecode-verifier.h" #include "test/unittests/heap/heap-utils.h" #include "test/unittests/test-utils.h" @@ -491,7 +528,7 @@ TEST_F(HeapTest, GrowAndShrinkNewSpace) { old_capacity = new_space->TotalCapacity(); { - v8::HandleScope temporary_scope(reinterpret_cast<v8::Isolate*>(isolate())); + v8::HandleScope temporary_scope(v8_isolate()); SimulateFullSpace(new_space); } new_capacity = new_space->TotalCapacity(); @@ -535,7 +572,7 @@ TEST_F(HeapTest, CollectingAllAvailableGarbageShrinksNewSpace) { return; } - v8::Isolate* iso = reinterpret_cast<v8::Isolate*>(isolate()); + v8::Isolate* iso = v8_isolate(); v8::HandleScope scope(iso); NewSpace* new_space = heap()->new_space(); GrowNewSpaceToMaximumCapacity(); @@ -557,7 +594,7 @@ TEST_F(HeapTest, OptimizedAllocationAlwaysInNewSpace) { v8_flags.stress_incremental_marking) { return; } - v8::Isolate* iso = reinterpret_cast<v8::Isolate*>(isolate()); + v8::Isolate* iso = v8_isolate(); ManualGCScope manual_gc_scope(isolate()); v8::HandleScope scope(iso); v8::Local<v8::Context> ctx = iso->GetCurrentContext(); @@ -649,15 +686,25 @@ TEST_F(HeapTest, RememberedSet_InsertOnPromotingObjectToOld) { heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, CompleteSweepingReason::kTesting); - CHECK(heap->InOldSpace(*arr)); - CHECK(HeapLayout::InYoungGeneration(arr->get(0))); + EXPECT_TRUE(heap->InOldSpace(*arr)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(arr->get(0))); if (v8_flags.minor_ms) { - CHECK_EQ(1, GetRememberedSetSize<OLD_TO_NEW_BACKGROUND>(isolate(), *arr)); + EXPECT_EQ(1u, GetRememberedSetSize<OLD_TO_NEW_BACKGROUND>(isolate(), *arr)); } else { - CHECK_EQ(1, GetRememberedSetSize<OLD_TO_NEW>(isolate(), *arr)); + EXPECT_EQ(1u, GetRememberedSetSize<OLD_TO_NEW>(isolate(), *arr)); } } +namespace { +Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) { + DirectHandle<String> str = isolate->factory()->InternalizeUtf8String(name); + Handle<Object> obj = + Object::GetProperty(isolate, isolate->global_object(), str) + .ToHandleChecked(); + return Cast<JSFunction>(obj); +} +} // namespace + TEST_F(HeapTest, Regress978156) { if (!v8_flags.incremental_marking) return; if (v8_flags.single_generation) return; @@ -674,22 +721,22 @@ TEST_F(HeapTest, Regress978156) { // 3. Trim the last array by one word thus creating a one-word filler. DirectHandle<FixedArray> last = arrays.back(); const uint32_t last_len = last->length().value(); - CHECK_GT(last_len, 0); + ASSERT_GT(last_len, 0u); heap->RightTrimArray(*last, last_len - 1, last_len); // 4. Get the last filler on the page. Tagged<HeapObject> filler = HeapObject::FromAddress( MutablePage::FromHeapObject(isolate(), *last)->area_end() - kTaggedSize); HeapObject::FromAddress(last->address() + last->Size()); - CHECK(IsFiller(filler)); + EXPECT_TRUE(IsFiller(filler)); // 5. Start incremental marking. - i::IncrementalMarking* marking = heap->incremental_marking(); + IncrementalMarking* marking = heap->incremental_marking(); if (marking->IsStopped()) { SafepointScope scope(isolate(), kGlobalSafepointForSharedSpaceIsolate); heap->tracer()->StartCycle( GarbageCollector::MARK_COMPACTOR, GarbageCollectionReason::kTesting, "collector cctest", GCTracer::MarkingType::kIncremental); marking->Start(GarbageCollector::MARK_COMPACTOR, - i::GarbageCollectionReason::kTesting, "testing"); + GarbageCollectionReason::kTesting, "testing"); } // 6. Mark the filler black to access its two markbits. This triggers // an out-of-bounds access of the marking bitmap in a bad case. @@ -711,20 +758,20 @@ TEST_F(HeapTest, SemiSpaceNewSpaceGrowsDuringFullGCIncrementalMarking) { // 2. Fill the new space with FixedArrays. std::vector<Handle<FixedArray>> arrays; SimulateFullSpace(heap->new_space(), &arrays); - CHECK_EQ(0, heap->new_space()->Available()); + EXPECT_EQ(0u, heap->new_space()->Available()); AllocationResult failed_allocation = heap->allocator()->AllocateRaw( 2 * kTaggedSize, AllocationType::kYoung, AllocationOrigin::kRuntime); EXPECT_TRUE(failed_allocation.IsFailure()); // 3. Start incremental marking. - i::IncrementalMarking* marking = heap->incremental_marking(); - CHECK(marking->IsStopped()); + IncrementalMarking* marking = heap->incremental_marking(); + EXPECT_TRUE(marking->IsStopped()); { SafepointScope scope(isolate(), kGlobalSafepointForSharedSpaceIsolate); heap->tracer()->StartCycle(GarbageCollector::MARK_COMPACTOR, GarbageCollectionReason::kTesting, "tesing", GCTracer::MarkingType::kIncremental); marking->Start(GarbageCollector::MARK_COMPACTOR, - i::GarbageCollectionReason::kTesting, "testing"); + GarbageCollectionReason::kTesting, "testing"); } // 4. Allocate in new space. AllocationResult allocation = heap->allocator()->AllocateRaw( @@ -872,17 +919,17 @@ TEST_F(HeapTest, ContainsSlow) { HandleScope scope(iso); DirectHandle<FixedArray> arr = iso->factory()->NewFixedArray(1, AllocationType::kOld); - CHECK(heap->old_space()->ContainsSlow(arr->address())); + EXPECT_TRUE(heap->old_space()->ContainsSlow(arr->address())); CHECK(heap->old_space()->ContainsSlow( MemoryChunk::FromAddress(arr->address())->address())); - CHECK(!heap->old_space()->ContainsSlow(0)); + EXPECT_FALSE(heap->old_space()->ContainsSlow(0)); DirectHandle<FixedArray> large_arr = iso->factory()->NewFixedArray( kMaxRegularHeapObjectSize + 1, AllocationType::kOld); - CHECK(heap->lo_space()->ContainsSlow(large_arr->address())); + EXPECT_TRUE(heap->lo_space()->ContainsSlow(large_arr->address())); CHECK(heap->lo_space()->ContainsSlow( MemoryChunk::FromAddress(large_arr->address())->address())); - CHECK(!heap->lo_space()->ContainsSlow(0)); + EXPECT_FALSE(heap->lo_space()->ContainsSlow(0)); } TEST_F(HeapTest, ReadOnlySpaceContainsSlowRejectsAddressPastAreaEnd) { @@ -892,7 +939,7 @@ TEST_F(HeapTest, ReadOnlySpaceContainsSlowRejectsAddressPastAreaEnd) { Heap* heap = isolate()->heap(); ReadOnlySpace* ro_space = heap->read_only_space(); const auto& pages = ro_space->pages(); - CHECK(!pages.empty()); + EXPECT_FALSE(pages.empty()); for (ReadOnlyPage* page : pages) { Address area_start = page->area_start(); @@ -900,14 +947,14 @@ TEST_F(HeapTest, ReadOnlySpaceContainsSlowRejectsAddressPastAreaEnd) { Address chunk_end = page->ChunkAddress() + kRegularPageSize; // Addresses within the committed area must be reported as contained. - CHECK(ro_space->ContainsSlow(area_start)); - CHECK(ro_space->ContainsSlow(area_end - 1)); + EXPECT_TRUE(ro_space->ContainsSlow(area_start)); + EXPECT_TRUE(ro_space->ContainsSlow(area_end - 1)); // Addresses past area_end but still within the original chunk range must // NOT be reported as contained — that memory may be decommitted. if (area_end < chunk_end) { - CHECK(!ro_space->ContainsSlow(area_end)); - CHECK(!ro_space->ContainsSlow(chunk_end - 1)); + EXPECT_FALSE(ro_space->ContainsSlow(area_end)); + EXPECT_FALSE(ro_space->ContainsSlow(chunk_end - 1)); } } } @@ -930,12 +977,12 @@ TEST_F( // will not move during GCs with stack. Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); for (int i = 0; i < 10; i++) { InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); } // `number` is already in the intermediate generation. A stackless GC should @@ -945,8 +992,8 @@ TEST_F( isolate()->heap()); InvokeMinorGC(); } - CHECK(!HeapLayout::InYoungGeneration(*number)); - CHECK_NE(number_address, number->address()); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*number)); + EXPECT_NE(number_address, number->address()); } TEST_F(HeapTest, @@ -965,17 +1012,17 @@ TEST_F(HeapTest, // will not move during a GC with stack. Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); // `number` is already in the intermediate generation. Another GC should // now promote the page to the old generation, again not moving the object. InvokeMinorGC(); - CHECK(!HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); } TEST_F(HeapTest, ConservativePinningScavengerObjectWithSelfReference) { @@ -987,7 +1034,7 @@ TEST_F(HeapTest, ConservativePinningScavengerObjectWithSelfReference) { static constexpr int kArraySize = 10; DirectHandle<FixedArray> array = isolate()->factory()->NewFixedArray(kArraySize, AllocationType::kYoung); - CHECK(HeapLayout::InYoungGeneration(*array)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*array)); for (int i = 0; i < kArraySize; i++) { array->set(i, *array); @@ -1005,18 +1052,18 @@ TEST_F(HeapTest, v8_flags.scavenger_promote_quarantined_pages = false; ManualGCScope manual_gc_scope(isolate()); - v8::HandleScope handle_scope(reinterpret_cast<v8::Isolate*>(isolate())); + v8::HandleScope handle_scope(v8_isolate()); IndirectHandle<HeapObject> number = isolate()->factory()->NewHeapNumber<AllocationType::kYoung>(42); Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); for (int i = 0; i < 10; i++) { InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); } } @@ -1028,65 +1075,68 @@ TEST_F(HeapTest, PrecisePinningScavengerDoesntMoveObjectReachableFromHandles) { v8_flags.scavenger_promote_quarantined_pages = true; ManualGCScope manual_gc_scope(isolate()); - v8::HandleScope handle_scope(reinterpret_cast<v8::Isolate*>(isolate())); + v8::HandleScope handle_scope(v8_isolate()); IndirectHandle<HeapObject> number = isolate()->factory()->NewHeapNumber<AllocationType::kYoung>(42); Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); // `number` is already in the intermediate generation. Another GC should // now move it to old gen. InvokeMinorGC(); - CHECK(!HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); } TEST_F(HeapTest, PrecisePinningFullGCDoesntMoveYoungObjectReachableFromHandles) { if (v8_flags.single_generation) return; v8_flags.precise_object_pinning = true; + FlagList::EnforceFlagImplications(); ManualGCScope manual_gc_scope(isolate()); - v8::HandleScope handle_scope(reinterpret_cast<v8::Isolate*>(isolate())); + v8::HandleScope handle_scope(v8_isolate()); IndirectHandle<HeapObject> number = isolate()->factory()->NewHeapNumber<AllocationType::kYoung>(42); Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); InvokeMajorGC(); - CHECK(!HeapLayout::InYoungGeneration(*number)); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_EQ(number_address, number->address()); } TEST_F(HeapTest, PrecisePinningFullGCDoesntMoveOldObjectReachableFromHandles) { v8_flags.precise_object_pinning = true; - v8_flags.manual_evacuation_candidates_selection = true; + FlagList::EnforceFlagImplications(); ManualGCScope manual_gc_scope(isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); SimulateFullSpace(isolate()->heap()->old_space()); - v8::HandleScope handle_scope(reinterpret_cast<v8::Isolate*>(isolate())); + v8::HandleScope handle_scope(v8_isolate()); IndirectHandle<HeapObject> number = isolate()->factory()->NewHeapNumber<AllocationType::kOld>(42); - CHECK(!HeapLayout::InYoungGeneration(*number)); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*number)); Address number_address = number->address(); - i::MutablePage::FromHeapObject(isolate(), *number) + MutablePage::FromHeapObject(isolate(), *number) ->set_forced_evacuation_candidate_for_testing(true); InvokeMajorGC(); - CHECK_EQ(number_address, number->address()); + EXPECT_EQ(number_address, number->address()); } TEST_F( @@ -1108,12 +1158,12 @@ TEST_F( // will not move during GCs with stack. Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); for (int i = 0; i < 10; i++) { InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); } } @@ -1135,24 +1185,25 @@ TEST_F(HeapTest, // will not move during a GC with stack. Address number_address = number->address(); - CHECK(HeapLayout::InYoungGeneration(*number)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); // `number` is already in the intermediate generation. Another GC should // now promote the page to the old generation, again not moving the object. InvokeMinorGC(); - CHECK(!HeapLayout::InYoungGeneration(*number)); - CHECK_EQ(number_address, number->address()); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*number)); + EXPECT_EQ(number_address, number->address()); } TEST_F(HeapTest, ConservativePinningScopeMarkCompactDoesntMoveObjectReachableFromStack) { - v8_flags.manual_evacuation_candidates_selection = true; v8_flags.compact_with_stack = true; ManualGCScope manual_gc_scope(isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); SimulateFullSpace(isolate()->heap()->old_space()); @@ -1166,10 +1217,10 @@ TEST_F(HeapTest, Address number_address = number->address(); for (int i = 0; i < 10; i++) { - i::MutablePage::FromHeapObject(isolate(), *number) + MutablePage::FromHeapObject(isolate(), *number) ->set_forced_evacuation_candidate_for_testing(true); InvokeMajorGC(); - CHECK_EQ(number_address, number->address()); + EXPECT_EQ(number_address, number->address()); } } @@ -1180,7 +1231,7 @@ TEST_F(HeapTest, ScavengerDoesntStrongifyWeakGlobals) { v8_flags.scavenger_precise_object_pinning = false; ManualGCScope manual_gc_scope(isolate()); Factory* factory = isolate()->factory(); - v8::Isolate* iso = reinterpret_cast<v8::Isolate*>(isolate()); + v8::Isolate* iso = v8_isolate(); // Make sure weak Globals are not strongified by Scavenger. If this ever // changes the CHECK in this block should fail. @@ -1192,9 +1243,9 @@ TEST_F(HeapTest, ScavengerDoesntStrongifyWeakGlobals) { global.Reset(iso, Utils::ToLocal(str)); global.SetWeak(); } - CHECK(!global.IsEmpty()); + EXPECT_FALSE(global.IsEmpty()); InvokeMinorGC(); - CHECK(global.IsEmpty()); + EXPECT_TRUE(global.IsEmpty()); } namespace { @@ -1206,7 +1257,7 @@ void ConservativePinningScopeScavengeRetainsObjectReachableFromStack( v8_flags.scavenger_promote_quarantined_pages = false; ManualGCScope manual_gc_scope(test->isolate()); Factory* factory = test->isolate()->factory(); - v8::Isolate* iso = reinterpret_cast<v8::Isolate*>(test->isolate()); + v8::Isolate* iso = test->v8_isolate(); ConservativePinningScope conservative_pinning_scope(test->isolate()->heap()); @@ -1227,13 +1278,13 @@ void ConservativePinningScopeScavengeRetainsObjectReachableFromStack( object = *str; } - CHECK(!global.IsEmpty()); - CHECK(global.IsWeak()); + EXPECT_FALSE(global.IsEmpty()); + EXPECT_TRUE(global.IsWeak()); gc_callback(object); - CHECK(global.IsWeak()); - CHECK(!global.IsEmpty()); + EXPECT_TRUE(global.IsWeak()); + EXPECT_FALSE(global.IsEmpty()); // Make sure `object` isn't optimized away. - CHECK_EQ(*Utils::OpenDirectHandle(*global.Get(iso)), object); + EXPECT_EQ(*Utils::OpenDirectHandle(*global.Get(iso)), object); } } // namespace @@ -1243,9 +1294,9 @@ TEST_F(HeapTest, if (v8_flags.minor_ms) return; ConservativePinningScopeScavengeRetainsObjectReachableFromStack( this, AllocationType::kYoung, [this](Tagged<String> object) { - CHECK(HeapLayout::InYoungGeneration(object)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(object)); InvokeMinorGC(); - CHECK(HeapLayout::InYoungGeneration(object)); + EXPECT_TRUE(HeapLayout::InYoungGeneration(object)); }); } @@ -1491,8 +1542,9 @@ TEST_F(HeapTest, BytecodeArray) { static const uint16_t kParameterCount = 2; static const uint16_t kMaxArguments = 0; - v8_flags.manual_evacuation_candidates_selection = true; ManualGCScope manual_gc_scope(isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); Factory* factory = i_isolate()->factory(); HandleScope scope(i_isolate()); @@ -1542,7 +1594,7 @@ TEST_F(HeapTest, BytecodeArray) { // Perform a full garbage collection and force the constant pool to be on an // evacuation candidate. - i::MutablePage::FromHeapObject(isolate(), *constant_pool) + MutablePage::FromHeapObject(isolate(), *constant_pool) ->set_forced_evacuation_candidate_for_testing(true); { // We need to invoke GC without stack, otherwise no compaction is performed. @@ -1567,13 +1619,13 @@ TEST_F(HeapTest, BytecodeArray) { TEST_F(HeapTest, BytecodeFlushing) { #if !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) v8_flags.turbofan = false; - i::v8_flags.optimize_for_size = false; + v8_flags.optimize_for_size = false; #endif // !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) #ifdef V8_ENABLE_SPARKPLUG v8_flags.always_sparkplug = false; #endif // V8_ENABLE_SPARKPLUG - i::v8_flags.flush_bytecode = true; - i::v8_flags.allow_natives_syntax = true; + v8_flags.flush_bytecode = true; + v8_flags.allow_natives_syntax = true; ManualGCScope manual_gc_scope(i_isolate()); v8::HandleScope scope(v8_isolate()); @@ -1584,7 +1636,6 @@ TEST_F(HeapTest, BytecodeFlushing) { " var z = x + y;" "};" "foo()"; - DirectHandle<String> foo_name = factory()->InternalizeUtf8String("foo"); // This compile will add the code to the compilation cache. { @@ -1593,11 +1644,7 @@ TEST_F(HeapTest, BytecodeFlushing) { } // Check function is compiled. - DirectHandle<Object> func_value = - Object::GetProperty(i_isolate(), i_isolate()->global_object(), foo_name) - .ToHandleChecked(); - EXPECT_TRUE(IsJSFunction(*func_value)); - DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); + DirectHandle<JSFunction> function = GetFunctionByName(i_isolate(), "foo"); EXPECT_TRUE(function->shared()->is_compiled()); // The code will survive at least two GCs. @@ -1608,7 +1655,7 @@ TEST_F(HeapTest, BytecodeFlushing) { } EXPECT_TRUE(function->shared()->is_compiled()); - i::SharedFunctionInfo::EnsureOldForTesting(function->shared()); + SharedFunctionInfo::EnsureOldForTesting(function->shared()); { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); @@ -1628,7 +1675,7 @@ void RunMultiReferencedBytecodeFlushingTest(HeapTest* test, bool sparkplug_compile) { #if !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) v8_flags.turbofan = false; - i::v8_flags.optimize_for_size = false; + v8_flags.optimize_for_size = false; #endif // !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) #ifdef V8_ENABLE_SPARKPLUG v8_flags.always_sparkplug = false; @@ -1636,8 +1683,8 @@ void RunMultiReferencedBytecodeFlushingTest(HeapTest* test, #else if (sparkplug_compile) return; #endif // V8_ENABLE_SPARKPLUG - i::v8_flags.flush_bytecode = true; - i::v8_flags.allow_natives_syntax = true; + v8_flags.flush_bytecode = true; + v8_flags.allow_natives_syntax = true; ManualGCScope manual_gc_scope(test->i_isolate()); v8::HandleScope scope(test->v8_isolate()); @@ -1648,8 +1695,6 @@ void RunMultiReferencedBytecodeFlushingTest(HeapTest* test, " var z = x + y;" "};" "foo()"; - DirectHandle<String> foo_name = test->factory()->InternalizeUtf8String("foo"); - // This compile will add the code to the compilation cache. { v8::HandleScope new_scope(test->v8_isolate()); @@ -1657,12 +1702,8 @@ void RunMultiReferencedBytecodeFlushingTest(HeapTest* test, } // Check function is compiled. - DirectHandle<Object> func_value = - Object::GetProperty(test->i_isolate(), test->i_isolate()->global_object(), - foo_name) - .ToHandleChecked(); - EXPECT_TRUE(IsJSFunction(*func_value)); - DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); + DirectHandle<JSFunction> function = + GetFunctionByName(test->i_isolate(), "foo"); DirectHandle<SharedFunctionInfo> shared(function->shared(), test->i_isolate()); EXPECT_TRUE(shared->is_compiled()); @@ -1679,7 +1720,7 @@ void RunMultiReferencedBytecodeFlushingTest(HeapTest* test, test->i_isolate(), copy, Compiler::CLEAR_EXCEPTION, &is_compiled_scope); } - i::SharedFunctionInfo::EnsureOldForTesting(*shared); + SharedFunctionInfo::EnsureOldForTesting(*shared); { // We need to invoke GC without stack, otherwise some objects may not be // reclaimed because of conservative stack scanning. @@ -1874,15 +1915,16 @@ TEST_F(HeapTest, CompilationCacheCachingBehaviorRetainScript) { #if !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) TEST_F(HeapTest, OptimizeAfterBytecodeFlushingCandidate) { + if (v8_flags.jitless) return; if (v8_flags.single_generation) return; + if (!v8_flags.incremental_marking) return; v8_flags.turbofan = true; #ifdef V8_ENABLE_SPARKPLUG v8_flags.always_sparkplug = false; #endif // V8_ENABLE_SPARKPLUG - i::v8_flags.optimize_for_size = false; - i::v8_flags.incremental_marking = true; - i::v8_flags.flush_bytecode = true; - i::v8_flags.allow_natives_syntax = true; + v8_flags.optimize_for_size = false; + v8_flags.flush_bytecode = true; + v8_flags.allow_natives_syntax = true; ManualGCScope manual_gc_scope(i_isolate()); v8::HandleScope outer_scope(v8_isolate()); @@ -1893,7 +1935,6 @@ TEST_F(HeapTest, OptimizeAfterBytecodeFlushingCandidate) { " var z = x + y;" "};" "foo()"; - DirectHandle<String> foo_name = factory()->InternalizeUtf8String("foo"); // This compile will add the code to the compilation cache. { @@ -1902,11 +1943,7 @@ TEST_F(HeapTest, OptimizeAfterBytecodeFlushingCandidate) { } // Check function is compiled. - DirectHandle<Object> func_value = - Object::GetProperty(i_isolate(), i_isolate()->global_object(), foo_name) - .ToHandleChecked(); - EXPECT_TRUE(IsJSFunction(*func_value)); - DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); + DirectHandle<JSFunction> function = GetFunctionByName(i_isolate(), "foo"); EXPECT_TRUE(function->shared()->is_compiled()); // The code will survive at least two GCs. @@ -1919,7 +1956,7 @@ TEST_F(HeapTest, OptimizeAfterBytecodeFlushingCandidate) { } EXPECT_TRUE(function->shared()->is_compiled()); - i::SharedFunctionInfo::EnsureOldForTesting(function->shared()); + SharedFunctionInfo::EnsureOldForTesting(function->shared()); { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); @@ -1959,14 +1996,14 @@ TEST_F(HeapTest, OptimizeAfterBytecodeFlushingCandidate) { TEST_F(HeapTest, MultiReferencedBytecodeFlushingBothOld) { #if !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) v8_flags.turbofan = false; - i::v8_flags.optimize_for_size = false; + v8_flags.optimize_for_size = false; #endif // !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) #ifdef V8_ENABLE_SPARKPLUG v8_flags.always_sparkplug = false; v8_flags.flush_baseline_code = true; #endif // V8_ENABLE_SPARKPLUG - i::v8_flags.flush_bytecode = true; - i::v8_flags.allow_natives_syntax = true; + v8_flags.flush_bytecode = true; + v8_flags.allow_natives_syntax = true; ManualGCScope manual_gc_scope(i_isolate()); v8::HandleScope scope(v8_isolate()); @@ -1977,7 +2014,6 @@ TEST_F(HeapTest, MultiReferencedBytecodeFlushingBothOld) { " var z = x + y;" "};" "foo()"; - DirectHandle<String> foo_name = factory()->InternalizeUtf8String("foo"); // This compile will add the code to the compilation cache. { @@ -1986,11 +2022,7 @@ TEST_F(HeapTest, MultiReferencedBytecodeFlushingBothOld) { } // Check function is compiled. - DirectHandle<Object> func_value = - Object::GetProperty(i_isolate(), i_isolate()->global_object(), foo_name) - .ToHandleChecked(); - EXPECT_TRUE(IsJSFunction(*func_value)); - DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); + DirectHandle<JSFunction> function = GetFunctionByName(i_isolate(), "foo"); DirectHandle<SharedFunctionInfo> shared(function->shared(), i_isolate()); EXPECT_TRUE(shared->is_compiled()); @@ -2001,8 +2033,8 @@ TEST_F(HeapTest, MultiReferencedBytecodeFlushingBothOld) { EXPECT_EQ(shared->GetBytecodeArray(i_isolate()), copy->GetBytecodeArray(i_isolate())); - i::SharedFunctionInfo::EnsureOldForTesting(*shared); - i::SharedFunctionInfo::EnsureOldForTesting(*copy); + SharedFunctionInfo::EnsureOldForTesting(*shared); + SharedFunctionInfo::EnsureOldForTesting(*copy); { // We need to invoke GC without stack, otherwise some objects may not be @@ -2016,7 +2048,7 @@ TEST_F(HeapTest, MultiReferencedBytecodeFlushingBothOld) { EXPECT_FALSE(copy->is_compiled()); } -TEST_F(HeapTest, Regress10843) { +TEST_F(TestWithPlatform, Regress10843) { v8_flags.max_semi_space_size = 2; v8_flags.min_semi_space_size = 2; v8_flags.max_old_space_size = 8; @@ -2047,32 +2079,32 @@ TEST_F(HeapTest, Regress10843) { for (int i = 0; i < 140; i++) { arrays.push_back(factory->NewFixedArray(10000)); } - i::InvokeMajorGC(i_isolate); - i::InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); for (int i = 0; i < 40; i++) { arrays.push_back(factory->NewFixedArray(10000)); } - i::InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); for (int i = 0; i < 100; i++) { arrays.push_back(factory->NewFixedArray(10000)); } - i::InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); EXPECT_TRUE(callback_was_invoked); } isolate->Dispose(); } TEST_F(HeapTest, Regress10560) { - i::v8_flags.flush_bytecode = true; - i::v8_flags.allow_natives_syntax = true; + v8_flags.flush_bytecode = true; + v8_flags.allow_natives_syntax = true; // Disable flags that allocate a feedback vector eagerly. #if !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) - i::v8_flags.turbofan = false; + v8_flags.turbofan = false; #endif // !defined(V8_LITE_MODE) && defined(V8_ENABLE_TURBOFAN) #ifdef V8_ENABLE_SPARKPLUG v8_flags.always_sparkplug = false; #endif // V8_ENABLE_SPARKPLUG - i::v8_flags.lazy_feedback_allocation = true; + v8_flags.lazy_feedback_allocation = true; ManualGCScope manual_gc_scope(i_isolate()); v8::HandleScope scope(v8_isolate()); @@ -2083,15 +2115,10 @@ TEST_F(HeapTest, Regress10560) { " var z = x + y;" "};" "foo()"; - DirectHandle<String> foo_name = factory()->InternalizeUtf8String("foo"); RunJS(source); // Check function is compiled. - DirectHandle<Object> func_value = - Object::GetProperty(i_isolate(), i_isolate()->global_object(), foo_name) - .ToHandleChecked(); - EXPECT_TRUE(IsJSFunction(*func_value)); - DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); + DirectHandle<JSFunction> function = GetFunctionByName(i_isolate(), "foo"); EXPECT_TRUE(function->shared()->is_compiled()); EXPECT_FALSE(function->has_feedback_vector()); @@ -2116,9 +2143,7 @@ TEST_F(HeapTest, Regress10560) { EXPECT_TRUE(function->is_compiled(i_isolate())); } -using LeakNativeContextViaMapKeyedTest = TestWithHeapInternals; - -TEST_F(LeakNativeContextViaMapKeyedTest, LeakNativeContextViaMapKeyed) { +TEST_F(TestWithHeapInternals, LeakNativeContextViaMapKeyed) { v8_flags.allow_natives_syntax = true; v8::Isolate* isolate = v8_isolate(); Heap* heap_instance = heap(); @@ -2206,9 +2231,9 @@ size_t InvokeGCNearHeapLimitCallback(void* data, size_t current_heap_limit, } } // namespace -TEST_F(HeapTest, Regress12777) { +TEST_F(TestWithPlatform, Regress12777) { v8::Isolate::CreateParams create_params; - create_params.constraints.set_max_old_generation_size_in_bytes(10 * i::MB); + create_params.constraints.set_max_old_generation_size_in_bytes(10 * MB); std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( v8::ArrayBuffer::Allocator::NewDefaultAllocator()); create_params.array_buffer_allocator = allocator.get(); @@ -2223,26 +2248,26 @@ TEST_F(HeapTest, Regress12777) { Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); // Allocate data to trigger the NearHeapLimitCallback. HandleScope scope(i_isolate); - int length = 2 * i::MB / i::kTaggedSize; + int length = 2 * MB / kTaggedSize; std::vector<Handle<FixedArray>> arrays; for (int i = 0; i < 5; i++) { arrays.push_back(i_isolate->factory()->NewFixedArray(length)); } - i::InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); for (int i = 0; i < 5; i++) { arrays.push_back(i_isolate->factory()->NewFixedArray(length)); } - i::InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); for (int i = 0; i < 5; i++) { arrays.push_back(i_isolate->factory()->NewFixedArray(length)); } - i::InvokeMajorGC(i_isolate); + InvokeMajorGC(i_isolate); EXPECT_GT(near_heap_limit_invocation_count, 0u); } isolate->Dispose(); } -TEST_F(HeapTest, LeakNativeContextViaMap) { +TEST_F(TestWithHeapInternals, LeakNativeContextViaMap) { v8_flags.allow_natives_syntax = true; v8::Isolate* isolate = v8_isolate(); Heap* heap_instance = heap(); @@ -2263,10 +2288,7 @@ TEST_F(HeapTest, LeakNativeContextViaMap) { heap_instance); InvokeMemoryReducingMajorGCs(); } - // HeapTest creates and enters a default context (context 0) which is - // unaffected by the test, so there are 3 global objects initially (default - // context + ctx1 + ctx2). - EXPECT_EQ(3, NumberOfGlobalObjects()); + EXPECT_EQ(2, NumberOfGlobalObjects()); { v8::HandleScope inner_scope(isolate); @@ -2303,17 +2325,17 @@ TEST_F(HeapTest, LeakNativeContextViaMap) { heap_instance); InvokeMemoryReducingMajorGCs(); } - EXPECT_EQ(2, NumberOfGlobalObjects()); + EXPECT_EQ(1, NumberOfGlobalObjects()); ctx2p.Reset(); { DisableConservativeStackScanningScopeForTesting no_stack_scanning( heap_instance); InvokeMemoryReducingMajorGCs(); } - EXPECT_EQ(1, NumberOfGlobalObjects()); + EXPECT_EQ(0, NumberOfGlobalObjects()); } -TEST_F(HeapTest, LeakNativeContextViaMapProto) { +TEST_F(TestWithHeapInternals, LeakNativeContextViaMapProto) { v8_flags.allow_natives_syntax = true; v8::Isolate* isolate = v8_isolate(); Heap* heap_instance = heap(); @@ -2334,7 +2356,7 @@ TEST_F(HeapTest, LeakNativeContextViaMapProto) { heap_instance); InvokeMemoryReducingMajorGCs(); } - EXPECT_EQ(3, NumberOfGlobalObjects()); + EXPECT_EQ(2, NumberOfGlobalObjects()); { v8::HandleScope inner_scope(isolate); @@ -2375,14 +2397,14 @@ TEST_F(HeapTest, LeakNativeContextViaMapProto) { heap_instance); InvokeMemoryReducingMajorGCs(); } - EXPECT_EQ(2, NumberOfGlobalObjects()); + EXPECT_EQ(1, NumberOfGlobalObjects()); ctx2p.Reset(); { DisableConservativeStackScanningScopeForTesting no_stack_scanning( heap_instance); InvokeMemoryReducingMajorGCs(); } - EXPECT_EQ(1, NumberOfGlobalObjects()); + EXPECT_EQ(0, NumberOfGlobalObjects()); } TEST_F(HeapTest, OptimizedPretenuringNestedDoubleLiterals) { @@ -2405,8 +2427,8 @@ TEST_F(HeapTest, OptimizedPretenuringNestedDoubleLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); - base::SNPrintF(source.as_vector(), + std::array<char, 1024> source; + base::SNPrintF(source, "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" @@ -2422,7 +2444,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedDoubleLiterals) { "f();", kPretenureCreationCount); - Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.begin())); + Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.data())); DirectHandle<JSObject> double_array_handle_1 = Cast<JSObject>( JSReceiver::GetElement(i_isolate(), o, 0).ToHandleChecked()); @@ -2455,9 +2477,9 @@ TEST_F(HeapTest, OptimizedPretenuringNestedInObjectProperties) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); + std::array<char, 1024> source; base::SNPrintF( - source.as_vector(), + source, "let number_elements = %d;" "let elements = new Array(number_elements);" "function f() {" @@ -2474,7 +2496,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedInObjectProperties) { "f();", kPretenureCreationCount); - Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.begin())); + Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.data())); EXPECT_TRUE(HeapLayout::InYoungGeneration(*o)); } @@ -2498,8 +2520,8 @@ TEST_F(HeapTest, OptimizedPretenuringNestedObjectLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); - base::SNPrintF(source.as_vector(), + std::array<char, 1024> source; + base::SNPrintF(source, "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" @@ -2515,7 +2537,7 @@ TEST_F(HeapTest, OptimizedPretenuringNestedObjectLiterals) { "f();", kPretenureCreationCount); - Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.begin())); + Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.data())); DirectHandle<JSObject> int_array_handle_1 = Cast<JSObject>( JSReceiver::GetElement(i_isolate(), o, 0).ToHandleChecked()); @@ -2548,8 +2570,8 @@ TEST_F(HeapTest, OptimizedPretenuringMixedInObjectProperties) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); - base::SNPrintF(source.as_vector(), + std::array<char, 1024> source; + base::SNPrintF(source, "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" @@ -2565,7 +2587,7 @@ TEST_F(HeapTest, OptimizedPretenuringMixedInObjectProperties) { "f();", kPretenureCreationCount); - Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.begin())); + Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.data())); EXPECT_TRUE(heap()->InOldSpace(*o)); FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0); @@ -2599,8 +2621,8 @@ TEST_F(HeapTest, OptimizedPretenuringDoubleArrayLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); - base::SNPrintF(source.as_vector(), + std::array<char, 1024> source; + base::SNPrintF(source, "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" @@ -2616,7 +2638,7 @@ TEST_F(HeapTest, OptimizedPretenuringDoubleArrayLiterals) { "f();", kPretenureCreationCount); - Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.begin())); + Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.data())); EXPECT_TRUE(heap()->InOldSpace(o->elements())); EXPECT_TRUE(heap()->InOldSpace(*o)); @@ -2642,8 +2664,8 @@ TEST_F(HeapTest, OptimizedPretenuringNestedMixedArrayLiterals) { static const int kPretenureCreationCount = PretenuringHandler::GetMinMementoCountForTesting() + 1; - auto source = base::OwnedVector<char>::NewForOverwrite(1024); - base::SNPrintF(source.as_vector(), + std::array<char, 1024> source; + base::SNPrintF(source, "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" @@ -2659,21 +2681,21 @@ TEST_F(HeapTest, OptimizedPretenuringNestedMixedArrayLiterals) { "f();", kPretenureCreationCount); - Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.begin())); + Handle<JSObject> o = Cast<JSObject>(RunJS(ctx, source.data())); v8::Local<v8::Value> int_array = v8::Utils::ToLocal(o) ->ToObject(ctx) .ToLocalChecked() ->Get(ctx, NewString("0")) .ToLocalChecked(); - i::DirectHandle<JSObject> int_array_handle = i::Cast<JSObject>( + DirectHandle<JSObject> int_array_handle = Cast<JSObject>( v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(int_array))); v8::Local<v8::Value> double_array = v8::Utils::ToLocal(o) ->ToObject(ctx) .ToLocalChecked() ->Get(ctx, NewString("1")) .ToLocalChecked(); - i::DirectHandle<JSObject> double_array_handle = i::Cast<JSObject>( + DirectHandle<JSObject> double_array_handle = Cast<JSObject>( v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(double_array))); EXPECT_TRUE(heap()->InOldSpace(*o)); @@ -2969,6 +2991,7 @@ TEST_F(HeapTest, CompilationCacheRegeneration7) { RunCompilationCacheRegenerationTest(this, true, true, true); } +namespace { void CheckWeakness(HeapTest* test, const char* source) { // ManualGCScope is necessary to finalize any active incremental marking and // disable concurrent/stress marking. Otherwise, under flags like @@ -2996,6 +3019,7 @@ void CheckWeakness(HeapTest* test, const char* source) { } EXPECT_TRUE(garbage.IsEmpty()); } +} // namespace TEST_F(HeapTest, WeakFunctionInConstructor) { // ManualGCScope is necessary to finalize any active incremental marking and @@ -3481,6 +3505,7 @@ TEST_F(HeapTest, TestAlignedOverAllocation) { #ifdef DEBUG TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToZero) { + v8_flags.retain_maps_for_n_gc = 0; v8_flags.stress_compaction = false; v8_flags.stress_incremental_marking = false; v8_flags.allow_natives_syntax = true; @@ -3490,9 +3515,9 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToZero) { { AlwaysAllocateScopeForTesting always_allocate(heap()); for (int i = 0; i < transitions_count; i++) { - base::EmbeddedVector<char, 64> buffer; + std::array<char, 64> buffer; base::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); - RunJS(buffer.begin()); + RunJS(buffer.data()); } } RunJS("var root = new F;"); @@ -3513,7 +3538,6 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToZero) { DirectHandle<Smi> twenty_three(Smi::FromInt(23), i_isolate()); HeapAllocator::SetAllocationGcInterval(2); v8_flags.gc_global = true; - v8_flags.retain_maps_for_n_gc = 0; heap()->set_allocation_timeout(2); Object::SetProperty(i_isolate(), root, prop_name, twenty_three).Check(); { @@ -3532,6 +3556,7 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToZero) { } TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOne) { + v8_flags.retain_maps_for_n_gc = 0; v8_flags.stress_compaction = false; v8_flags.stress_incremental_marking = false; v8_flags.allow_natives_syntax = true; @@ -3541,9 +3566,9 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOne) { { AlwaysAllocateScopeForTesting always_allocate(heap()); for (int i = 0; i < transitions_count; i++) { - base::EmbeddedVector<char, 64> buffer; + std::array<char, 64> buffer; base::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); - RunJS(buffer.begin()); + RunJS(buffer.data()); } } RunJS("var root = new F;"); @@ -3559,7 +3584,6 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOne) { DirectHandle<Smi> twenty_three(Smi::FromInt(23), i_isolate()); HeapAllocator::SetAllocationGcInterval(2); v8_flags.gc_global = true; - v8_flags.retain_maps_for_n_gc = 0; heap()->set_allocation_timeout(2); Object::SetProperty(i_isolate(), root, prop_name, twenty_three).Check(); { @@ -3578,6 +3602,7 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOne) { } TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOnePropertyFound) { + v8_flags.retain_maps_for_n_gc = 0; v8_flags.stress_compaction = false; v8_flags.stress_incremental_marking = false; v8_flags.allow_natives_syntax = true; @@ -3587,9 +3612,9 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOnePropertyFound) { { AlwaysAllocateScopeForTesting always_allocate(heap()); for (int i = 0; i < transitions_count; i++) { - base::EmbeddedVector<char, 64> buffer; + std::array<char, 64> buffer; base::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); - RunJS(buffer.begin()); + RunJS(buffer.data()); } } RunJS("var root = new F;"); @@ -3605,7 +3630,6 @@ TEST_F(HeapTest, TransitionArrayShrinksDuringAllocToOnePropertyFound) { DirectHandle<Smi> twenty_three(Smi::FromInt(23), i_isolate()); HeapAllocator::SetAllocationGcInterval(0); v8_flags.gc_global = true; - v8_flags.retain_maps_for_n_gc = 0; heap()->set_allocation_timeout(0); Object::SetProperty(i_isolate(), root, prop_name, twenty_three).Check(); InvokeMajorGC(); @@ -3937,7 +3961,7 @@ TEST_F(HeapTest, Regress670675) { Heap::SweepingForcedFinalizationMode::kUnifiedHeap, CompleteSweepingReason::kTesting); heap->tracer()->StopFullCycleIfFinished(); - i::IncrementalMarking* marking = heap->incremental_marking(); + IncrementalMarking* marking = heap->incremental_marking(); if (marking->IsStopped()) { SafepointScope safepoint_scope(isolate, kGlobalSafepointForSharedSpaceIsolate); @@ -3945,7 +3969,7 @@ TEST_F(HeapTest, Regress670675) { GarbageCollector::MARK_COMPACTOR, GarbageCollectionReason::kTesting, "collector unittest", GCTracer::MarkingType::kIncremental); marking->Start(GarbageCollector::MARK_COMPACTOR, - i::GarbageCollectionReason::kTesting, "testing"); + GarbageCollectionReason::kTesting, "testing"); } size_t array_length = 128 * KB; size_t n = OldGenerationSpaceAvailable() / array_length; @@ -4125,8 +4149,9 @@ TEST_F(HeapTest, Regress169928) { TEST_F(HeapTest, LargeObjectSlotRecording) { if (!v8_flags.incremental_marking) return; if (!v8_flags.compact) return; - v8_flags.manual_evacuation_candidates_selection = true; ManualGCScope manual_gc_scope(isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); const int size = std::max(1000000, kMaxRegularHeapObjectSize + KB); const int kStep = size / 10; @@ -4210,18 +4235,20 @@ TEST_F(HeapTest, PersistentHandles) { persistent.Detach(); } -void TestFillersFromPersistentHandles(Isolate* isolate, bool promote) { +namespace { +void TestFillersFromPersistentHandles(HeapTest* test, bool promote) { // We assume that the fillers can only arise when left-trimming arrays. + Isolate* isolate = test->i_isolate(); ManualGCScope manual_gc_scope(isolate); - Heap* heap = isolate->heap(); - v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate)); + Heap* heap = test->heap(); + v8::HandleScope scope(test->v8_isolate()); const size_t n = 10; - DirectHandle<FixedArray> array = isolate->factory()->NewFixedArray(n); + DirectHandle<FixedArray> array = test->factory()->NewFixedArray(n); if (promote) { // Age the array so it's ready for promotion on next GC. - InvokeMinorGC(isolate); + test->InvokeMinorGC(); } EXPECT_TRUE(HeapLayout::InYoungGeneration(*array)); @@ -4241,7 +4268,7 @@ void TestFillersFromPersistentHandles(Isolate* isolate, bool promote) { persistent_scope.Detach()); // GC should retain the trimmed array but drop all of the three fillers. - InvokeMinorGC(isolate); + test->InvokeMinorGC(); if (!v8_flags.single_generation) { if (promote) { EXPECT_TRUE(heap->InOldSpace(*tail)); @@ -4254,15 +4281,16 @@ void TestFillersFromPersistentHandles(Isolate* isolate, bool promote) { EXPECT_FALSE(IsHeapObject(*filler_2)); EXPECT_FALSE(IsHeapObject(*filler_3)); } +} // namespace TEST_F(HeapTest, DoNotEvacuateFillersFromPersistentHandles) { if (v8_flags.single_generation || v8_flags.move_object_start) return; - TestFillersFromPersistentHandles(i_isolate(), false /*promote*/); + TestFillersFromPersistentHandles(this, false /*promote*/); } TEST_F(HeapTest, DoNotPromoteFillersFromPersistentHandles) { if (v8_flags.single_generation || v8_flags.move_object_start) return; - TestFillersFromPersistentHandles(i_isolate(), true /*promote*/); + TestFillersFromPersistentHandles(this, true /*promote*/); } TEST_F(HeapTest, IncrementalMarkingStepMakesBigProgressWithLargeObjects) { @@ -4311,6 +4339,56 @@ TEST_F(HeapTest, DisableInlineAllocation) { RunJS("run()"); } +namespace { +int AllocationSitesCount(Heap* heap) { + int count = 0; + for (Tagged<Object> site = heap->allocation_sites_list(); + IsAllocationSite(site);) { + Tagged<AllocationSiteWithWeakNext> cur = + Cast<AllocationSiteWithWeakNext>(site); + EXPECT_TRUE(cur->HasWeakNext()); + site = cur->weak_next(); + count++; + } + return count; +} + +int SlimAllocationSiteCount(Heap* heap) { + int count = 0; + for (Tagged<Object> weak_list = heap->allocation_sites_list(); + IsAllocationSite(weak_list);) { + Tagged<AllocationSiteWithWeakNext> weak_cur = + Cast<AllocationSiteWithWeakNext>(weak_list); + for (Tagged<Object> site = weak_cur->nested_site(); + IsAllocationSite(site);) { + Tagged<AllocationSite> cur = Cast<AllocationSite>(site); + EXPECT_FALSE(cur->HasWeakNext()); + site = cur->nested_site(); + count++; + } + weak_list = weak_cur->weak_next(); + } + return count; +} + +void CheckNumberOfAllocations(HeapTest* test, const char* source, + int expected_full_alloc, + int expected_slim_alloc) { + int prev_fat_alloc_count = AllocationSitesCount(test->heap()); + int prev_slim_alloc_count = SlimAllocationSiteCount(test->heap()); + + test->RunJS(source); + + int fat_alloc_sites = + AllocationSitesCount(test->heap()) - prev_fat_alloc_count; + int slim_alloc_sites = + SlimAllocationSiteCount(test->heap()) - prev_slim_alloc_count; + + EXPECT_EQ(expected_full_alloc, fat_alloc_sites); + EXPECT_EQ(expected_slim_alloc, slim_alloc_sites); +} +} // namespace + TEST_F(HeapTest, EnsureAllocationSiteDependentCodesProcessed) { if (!V8_ALLOCATION_SITE_TRACKING_BOOL) { return; @@ -4322,19 +4400,6 @@ TEST_F(HeapTest, EnsureAllocationSiteDependentCodesProcessed) { if (!isolate->use_optimizer()) return; - auto allocation_sites_count = [](Heap* heap) { - int count = 0; - for (Tagged<Object> site = heap->allocation_sites_list(); - IsAllocationSite(site);) { - Tagged<AllocationSiteWithWeakNext> cur = - Cast<AllocationSiteWithWeakNext>(site); - EXPECT_TRUE(cur->HasWeakNext()); - site = cur->weak_next(); - count++; - } - return count; - }; - // The allocation site at the head of the list is ours. IndirectHandle<AllocationSite> site; { @@ -4342,7 +4407,7 @@ TEST_F(HeapTest, EnsureAllocationSiteDependentCodesProcessed) { v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Context::Scope context_scope(context); - int count = allocation_sites_count(heap); + int count = AllocationSitesCount(heap); RunJS(context, "var bar = function() { return (new Array()); };" "%PrepareFunctionForOptimization(bar);" @@ -4351,7 +4416,7 @@ TEST_F(HeapTest, EnsureAllocationSiteDependentCodesProcessed) { "bar();"); // One allocation site should have been created. - int new_count = allocation_sites_count(heap); + int new_count = AllocationSitesCount(heap); EXPECT_EQ(new_count, count + 1); site = Cast<AllocationSite>(global_handles->Create( Cast<AllocationSite>(heap->allocation_sites_list()))); @@ -4396,430 +4461,3203 @@ TEST_F(HeapTest, EnsureAllocationSiteDependentCodesProcessed) { EXPECT_TRUE(site->dependent_code()->Get(0).IsCleared()); } -void CheckEqualSharedFunctionInfos( - const v8::FunctionCallbackInfo<v8::Value>& info) { - CHECK(i::ValidateCallbackInfo(info)); - DirectHandle<Object> obj1 = v8::Utils::OpenDirectHandle(*info[0]); - DirectHandle<Object> obj2 = v8::Utils::OpenDirectHandle(*info[1]); - DirectHandle<JSFunction> fun1 = Cast<JSFunction>(obj1); - DirectHandle<JSFunction> fun2 = Cast<JSFunction>(obj2); - CHECK_EQ(fun1->shared(), fun2->shared()); -} - -void RemoveCodeAndGC(const v8::FunctionCallbackInfo<v8::Value>& info) { - CHECK(i::ValidateCallbackInfo(info)); - Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); - DirectHandle<Object> obj = v8::Utils::OpenDirectHandle(*info[0]); - DirectHandle<JSFunction> fun = Cast<JSFunction>(obj); - // Bytecode is code too. - SharedFunctionInfo::DiscardCompiled(isolate, - direct_handle(fun->shared(), isolate)); - fun->UpdateCode(isolate, *BUILTIN_CODE(isolate, CompileLazy)); - InvokeMemoryReducingMajorGCs(isolate); +namespace { +void OptimizeEmptyFunction(TestWithHeapInternals* test, const char* name) { + HandleScope inner_scope(test->i_isolate()); + std::array<char, 256> source; + base::SNPrintF(source, + "function %s() { return 0; }" + "%%PrepareFunctionForOptimization(%s);" + "%s(); %s();" + "%%OptimizeFunctionOnNextCall(%s);" + "%s();", + name, name, name, name, name, name); + test->RunJS(source.data()); } -TEST_F(HeapTest, CanonicalSharedFunctionInfo) { - SetGlobalProperty( - "check", v8::Function::New(v8_context(), CheckEqualSharedFunctionInfos) - .ToLocalChecked()); - SetGlobalProperty( - "remove", - v8::Function::New(v8_context(), RemoveCodeAndGC).ToLocalChecked()); - RunJS( - "function f() { return function g() {}; }\n" - "var g1 = f();\n" - "remove(f);\n" - "var g2 = f();\n" - "check(g1, g2);\n"); - - RunJS( - "function f() { return (function() { return function g() {}; })(); }\n" - "var g1 = f();\n" - "remove(f);\n" - "var g2 = f();\n" - "check(g1, g2);\n"); +// Count the number of native contexts in the weak list of native contexts. +int CountNativeContexts(Heap* heap) { + int count = 0; + Tagged<Object> object = heap->native_contexts_list(); + while (!IsUndefined(object)) { + count++; + object = Cast<Context>(object)->next_context_link(); + } + return count; } +} // namespace -TEST_F(HeapTest, ScriptIterator) { - v8::HandleScope scope(v8_isolate()); - - InvokeMajorGC(); - - int script_count = 0; - { - HeapObjectIterator it(heap()); - for (Tagged<HeapObject> obj = it.Next(); !obj.is_null(); obj = it.Next()) { - if (IsScript(obj)) script_count++; - } - } +TEST_F(TestWithHeapInternals, TestInternalWeakLists) { + v8_flags.allow_natives_syntax = true; - { - Script::Iterator iterator(i_isolate()); - for (Tagged<Script> script = iterator.Next(); !script.is_null(); - script = iterator.Next()) { - script_count--; - } + // Some flags turn Scavenge collections into Mark-sweep collections + // and hence are incompatible with this test case. + if (v8_flags.gc_global || v8_flags.stress_compaction || + v8_flags.stress_incremental_marking || v8_flags.single_generation || + v8_flags.stress_concurrent_allocation) { + return; } + v8_flags.retain_maps_for_n_gc = 0; - EXPECT_EQ(0, script_count); -} + static const int kNumTestContexts = 10; -TEST_F(HeapTest, Regress587004) { - if (v8_flags.single_generation) return; ManualGCScope manual_gc_scope(i_isolate()); -#ifdef VERIFY_HEAP - v8_flags.verify_heap = false; -#endif HandleScope scope(i_isolate()); - Heap* heap = this->heap(); - Isolate* isolate = this->i_isolate(); - Factory* factory = isolate->factory(); - const int N = (kMaxRegularHeapObjectSize - OFFSET_OF_DATA_START(FixedArray)) / - kTaggedSize; - DirectHandle<FixedArray> array = - factory->NewFixedArray(N, AllocationType::kOld); - CHECK(heap->old_space()->Contains(*array)); - DirectHandle<Object> number = factory->NewHeapNumber(1.0); - CHECK(HeapLayout::InYoungGeneration(*number)); - for (int i = 0; i < N; i++) { - array->set(i, *number); - } - InvokeMajorGC(); - SimulateFullSpace(heap->old_space()); - heap->RightTrimArray(*array, 1, N); - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - Tagged<ByteArray> byte_array; - const uint32_t M = 256; - // Don't allow old space expansion. The test works without this flag too, - // but becomes very slow. - SetForceOOM(heap, true); - while ( - AllocateByteArrayForTest(heap, M, AllocationType::kOld).To(&byte_array)) { - for (uint32_t j = 0; j < M; j++) { - byte_array->set(j, 0x31); - } - } - // Re-enable old space expansion to avoid OOM crash. - SetForceOOM(heap, false); - InvokeMinorGC(); -} + v8::Global<v8::Context> ctx[kNumTestContexts]; + if (!i_isolate()->use_optimizer()) return; -TEST_F(HeapTest, Regress589413) { - if (!v8_flags.incremental_marking || v8_flags.stress_concurrent_allocation) { - return; - } - v8_flags.stress_compaction = true; - ManualGCScope manual_gc_scope(i_isolate()); - v8_flags.manual_evacuation_candidates_selection = true; - v8_flags.parallel_compaction = false; - HandleScope scope(i_isolate()); - Heap* heap = this->heap(); - // Get the heap in clean state. - InvokeMajorGC(); - InvokeMajorGC(); - Isolate* isolate = i_isolate(); - Factory* factory = isolate->factory(); + EXPECT_EQ(0, CountNativeContexts(heap())); - auto force_evacuation_candidate = [](NormalPage* page) { - Isolate* isolate = page->owner()->heap()->isolate(); - SafepointScope safepoint(isolate, kGlobalSafepointForSharedSpaceIsolate); - CHECK(v8_flags.manual_evacuation_candidates_selection); - page->set_forced_evacuation_candidate_for_testing(true); - page->owner()->heap()->FreeLinearAllocationAreas(); - }; + // Create a number of global contexts which get linked together. + for (int i = 0; i < kNumTestContexts; i++) { + // Create a handle scope so no contexts or function objects get stuck in the + // outer handle scope. + HandleScope new_scope(i_isolate()); - // Fill the new space with byte arrays with elements looking like pointers. - const uint32_t M = 256; - Tagged<ByteArray> byte_array; - NormalPage* young_page = nullptr; - while (AllocateByteArrayForTest(heap, M, AllocationType::kYoung) - .To(&byte_array)) { - // Only allocate objects on one young page as a rough estimate on - // how much memory can be promoted into the old generation. - // Otherwise we would crash when forcing promotion of all young - // live objects. - if (!young_page) young_page = NormalPage::FromHeapObject(byte_array); - if (NormalPage::FromHeapObject(byte_array) != young_page) break; + ctx[i].Reset(v8_isolate(), v8::Context::New(v8_isolate())); - for (uint32_t j = 0; j < M; j++) { - byte_array->set(j, 0x31); + // Collect garbage that might have been created by one of the + // installed extensions. + i_isolate()->compilation_cache()->Clear(); + { + // In this test, we need to invoke GC without stack, otherwise some + // objects may not be reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); } - // Add the array in root set. - handle(byte_array, isolate); - } - auto reset_oom = [](void* data, size_t limit, size_t) -> size_t { - HeapTest* test = static_cast<HeapTest*>(data); - test->SetForceOOM(test->heap(), false); - return limit; - }; - heap->AddNearHeapLimitCallback(reset_oom, this); - { - // Ensure that incremental marking is not started unexpectedly. - AlwaysAllocateScopeForTesting always_allocate(isolate->heap()); + EXPECT_EQ(i + 1, CountNativeContexts(heap())); - // Make sure the byte arrays will be promoted on the next GC. - InvokeMinorGC(); - // This number is close to large free list category threshold. - const uint32_t N = 0x3EEE; + ctx[i].Get(v8_isolate())->Enter(); - std::vector<Tagged<FixedArray>> arrays; - std::set<NormalPage*> pages; - Tagged<FixedArray> array; - // Fill all pages with fixed arrays. - SetForceOOM(heap, true); - while ( - AllocateFixedArrayForTest(heap, N, AllocationType::kOld).To(&array)) { - arrays.push_back(array); - pages.insert(NormalPage::FromHeapObject(array)); - // Add the array in root set. - handle(array, isolate); + OptimizeEmptyFunction(this, "f1"); + OptimizeEmptyFunction(this, "f2"); + OptimizeEmptyFunction(this, "f3"); + OptimizeEmptyFunction(this, "f4"); + OptimizeEmptyFunction(this, "f5"); + + // Remove function f1, and + RunJS("f1=null"); + + // Scavenge treats these references as strong. + for (int j = 0; j < 10; j++) { + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMinorGC(); } - SetForceOOM(heap, false); - size_t initial_pages = pages.size(); - // Expand and fill two pages with fixed array to ensure enough space both - // the young objects and the evacuation candidate pages. - while ( - AllocateFixedArrayForTest(heap, N, AllocationType::kOld).To(&array)) { - arrays.push_back(array); - pages.insert(NormalPage::FromHeapObject(array)); - // Add the array in root set. - handle(array, isolate); - // Do not expand anymore. - if (pages.size() - initial_pages == 2) { - SetForceOOM(heap, true); + + // Mark compact handles the weak references. + i_isolate()->compilation_cache()->Clear(); + { + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + + // Get rid of f3 and f5 in the same way. + RunJS("f3=null"); + { + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + for (int j = 0; j < 10; j++) { + InvokeMinorGC(); } + InvokeMajorGC(); } - // Expand and mark the new page as evacuation candidate. - SetForceOOM(heap, false); + RunJS("f5=null"); { - DirectHandle<HeapObject> ec_obj = - factory->NewFixedArray(5000, AllocationType::kOld); - NormalPage* ec_page = NormalPage::FromHeapObject(*ec_obj); - force_evacuation_candidate(ec_page); - // Make all arrays point to evacuation candidate so that - // slots are recorded for them. - for (size_t j = 0; j < arrays.size(); j++) { - array = arrays[j]; - for (uint32_t i = 0; i < N; i++) { - array->set(i, *ec_obj); - } + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + for (int j = 0; j < 10; j++) { + InvokeMinorGC(); } + InvokeMajorGC(); } - CHECK(heap->incremental_marking()->IsStopped()); - SimulateIncrementalMarking(); - for (size_t j = 0; j < arrays.size(); j++) { - heap->RightTrimArray(arrays[j], 1, N); + ctx[i].Get(v8_isolate())->Exit(); + } + + // Force compilation cache cleanup. + heap()->NotifyContextDisposed(true); + { + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + + // Dispose the native contexts one by one. + for (int i = 0; i < kNumTestContexts; i++) { + ctx[i].Reset(); + + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + + // Scavenge treats these references as strong. + for (int j = 0; j < 10; j++) { + InvokeMinorGC(); + EXPECT_EQ(kNumTestContexts - i, CountNativeContexts(heap())); } + // Mark-compact handles the weak references. + InvokeMajorGC(); + + EXPECT_EQ(kNumTestContexts - i - 1, CountNativeContexts(heap())); } - // Force allocation from the free list. - SetForceOOM(heap, true); - InvokeMajorGC(); - heap->RemoveNearHeapLimitCallback(reset_oom, 0); + EXPECT_EQ(0, CountNativeContexts(heap())); } -TEST_F(HeapTest, Regress598319) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope(i_isolate()); - // This test ensures that no white objects can cross the progress bar of large - // objects during incremental marking. It checks this by using Shift() during - // incremental marking. +TEST_F(TestWithHeapInternals, CountForcedGC) { + v8_flags.expose_gc = true; v8::HandleScope scope(v8_isolate()); - Heap* heap = this->heap(); - Isolate* isolate = i_isolate(); - - // The size of the array should be larger than kProgressBarScanningChunk. - const uint32_t kNumberOfObjects = - std::max(FixedArray::kMaxRegularLength + 1, 128 * KB); + v8::Local<v8::Context> new_context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(new_context); - struct Arr { - Arr(Isolate* isolate, v8::Isolate* v8_isolate, uint32_t number_of_objects) { - root = isolate->factory()->NewFixedArray(1, AllocationType::kOld); - { - // Temporary scope to avoid getting any other objects into the root set. - v8::HandleScope new_scope(v8_isolate); - DirectHandle<FixedArray> tmp = isolate->factory()->NewFixedArray( - number_of_objects, AllocationType::kOld); - root->set(0, *tmp); - const uint32_t length = get()->length().value(); - for (uint32_t i = 0; i < length; i++) { - tmp = isolate->factory()->NewFixedArray(100, AllocationType::kOld); - get()->set(i, *tmp); - } - } - global_root.Reset(v8_isolate, Utils::ToLocal(Cast<Object>(root))); + struct Counter { + static int& value() { + static int c = 0; + return c; } + static void Callback(v8::Isolate* isolate, + v8::Isolate::UseCounterFeature feature) { + isolate->GetCurrentContext(); + if (feature == v8::Isolate::kForcedGC) value()++; + } + }; + Counter::value() = 0; - Tagged<FixedArray> get() { return Cast<FixedArray>(root->get(0)); } + i_isolate()->SetUseCounterCallback(Counter::Callback); - Handle<FixedArray> root; + const char* source = "gc();"; + RunJS(source); + EXPECT_GT(Counter::value(), 0); +} - // Store array in global as well to make it part of the root set when - // starting incremental marking. - v8::Global<Value> global_root; - } arr(isolate, v8_isolate(), kNumberOfObjects); +#ifdef OBJECT_PRINT +TEST_F(HeapTest, PrintSharedFunctionInfo) { + v8::HandleScope scope(v8_isolate()); + const char* source = + "f = function() { return 987654321; }\n" + "g = function() { return 123456789; }\n"; + RunJS(source); + DirectHandle<JSFunction> g = Cast< + JSFunction>(v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + context()->Global()->Get(context(), NewString("g")).ToLocalChecked()))); - CHECK_EQ(arr.get()->length().value(), kNumberOfObjects); - CHECK(heap->lo_space()->Contains(arr.get())); - LargePage* page = LargePage::FromHeapObject(isolate, arr.get()); - CHECK_NOT_NULL(page); + StdoutStream os; + Print(g->shared(), os); + os << std::endl; +} +#endif // OBJECT_PRINT - // GC to cleanup state - InvokeMajorGC(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); +TEST_F(HeapTest, IncrementalMarkingPreservesMonomorphicCallIC) { + if (!v8_flags.use_ic) return; + if (!v8_flags.incremental_marking) return; + v8_flags.allow_natives_syntax = true; + v8::HandleScope scope(v8_isolate()); + v8::Local<v8::Value> fun1, fun2; + { + RunJS("function fun() {};"); + fun1 = + context()->Global()->Get(context(), NewString("fun")).ToLocalChecked(); } - CHECK(heap->lo_space()->Contains(arr.get())); - IncrementalMarking* marking = heap->incremental_marking(); - MarkingState* marking_state = heap->marking_state(); - CHECK(marking_state->IsUnmarked(arr.get())); - - for (uint32_t i = 0; i < arr.get()->length().value(); i++) { - Tagged<HeapObject> arr_value = Cast<HeapObject>(arr.get()->get(i)); - CHECK(marking_state->IsUnmarked(arr_value)); + { + RunJS("function fun() {};"); + fun2 = + context()->Global()->Get(context(), NewString("fun")).ToLocalChecked(); } - // Start incremental marking. - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); - } - CHECK(marking->IsMarking()); + // Prepare function f that contains type feedback for the two closures. + EXPECT_TRUE( + context()->Global()->Set(context(), NewString("fun1"), fun1).FromJust()); + EXPECT_TRUE( + context()->Global()->Set(context(), NewString("fun2"), fun2).FromJust()); + RunJS( + "function f(a, b) { a(); b(); } %EnsureFeedbackVectorForFunction(f); " + "f(fun1, fun2);"); - // Check that we have not marked the interesting array during root scanning. - for (uint32_t i = 0; i < arr.get()->length().value(); i++) { - Tagged<HeapObject> arr_value = Cast<HeapObject>(arr.get()->get(i)); - CHECK(marking_state->IsUnmarked(arr_value)); + DirectHandle<JSFunction> f = Cast< + JSFunction>(v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + context()->Global()->Get(context(), NewString("f")).ToLocalChecked()))); + + Handle<FeedbackVector> feedback_vector(f->feedback_vector(), i_isolate()); + FeedbackVectorHelper helper(feedback_vector); + + ASSERT_EQ(2, helper.slot_count()); + FeedbackSlot slot1 = helper.slot(0); + FeedbackSlot slot2 = helper.slot(1); + EXPECT_TRUE(feedback_vector->Get(slot1).IsWeak()); + EXPECT_TRUE(feedback_vector->Get(slot2).IsWeak()); + + SimulateIncrementalMarking(); + InvokeMajorGC(); + + EXPECT_TRUE(feedback_vector->Get(slot1).IsWeak()); + EXPECT_TRUE(feedback_vector->Get(slot2).IsWeak()); +} + +namespace { +void CheckIC(Isolate* isolate, DirectHandle<JSFunction> f, int slot_index, + InlineCacheState desired_state) { + Handle<FeedbackVector> vector(f->feedback_vector(), isolate); + FeedbackVectorHelper helper(vector); + ASSERT_LT(slot_index, helper.slot_count()); + FeedbackNexus nexus(isolate, vector, helper.slot(slot_index)); + EXPECT_EQ(nexus.ic_state(), desired_state); +} +} // namespace + +TEST_F(HeapTest, IncrementalMarkingPreservesMonomorphicIC) { + if (!v8_flags.use_ic) return; + if (!v8_flags.incremental_marking) return; + v8_flags.allow_natives_syntax = true; + v8::HandleScope scope(v8_isolate()); + // Prepare function f that contains a monomorphic IC for object + // originating from the same native context. + RunJS( + "function fun() { this.x = 1; }; var obj = new fun();" + "%EnsureFeedbackVectorForFunction(f);" + "function f(o) { return o.x; } f(obj); f(obj);"); + DirectHandle<JSFunction> f = Cast< + JSFunction>(v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + context()->Global()->Get(context(), NewString("f")).ToLocalChecked()))); + + CheckIC(i_isolate(), f, 0, InlineCacheState::MONOMORPHIC); + + SimulateIncrementalMarking(); + InvokeMajorGC(); + + CheckIC(i_isolate(), f, 0, InlineCacheState::MONOMORPHIC); +} + +TEST_F(HeapTest, IncrementalMarkingPreservesPolymorphicIC) { + if (!v8_flags.use_ic) return; + if (!v8_flags.incremental_marking) return; + v8_flags.allow_natives_syntax = true; + v8::HandleScope scope(v8_isolate()); + v8::Local<v8::Value> obj1, obj2; + + { + v8::EscapableHandleScope inner_scope(v8_isolate()); + v8::Local<v8::Context> env = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(env); + RunJS("function fun() { this.x = 1; }; var obj = new fun();"); + obj1 = inner_scope.Escape( + env->Global()->Get(env, NewString("obj")).ToLocalChecked()); } - // Now we search for a state where we are in incremental marking and have - // only partially marked the large object. - static constexpr auto kSmallStepSize = - v8::base::TimeDelta::FromMillisecondsD(0.1); - static constexpr size_t kSmallMaxBytesToMark = 100; - while (!marking->IsMajorMarkingComplete()) { - marking->AdvanceForTesting(kSmallStepSize, kSmallMaxBytesToMark); - MarkingProgressTracker& progress_tracker = page->marking_progress_tracker(); - if (progress_tracker.IsEnabled() && - progress_tracker.GetCurrentChunkForTesting() > 0) { - CHECK_NE(progress_tracker.GetCurrentChunkForTesting(), arr.get()->Size()); - { - // Shift by 1, effectively moving one white object across the progress - // bar, meaning that we will miss marking it. - v8::HandleScope new_scope(v8_isolate()); - DirectHandle<JSArray> js_array = - isolate->factory()->NewJSArrayWithElements( - DirectHandle<FixedArray>(arr.get(), isolate)); - js_array->GetElementsAccessor()->Shift(isolate, js_array); - } - break; - } + { + v8::EscapableHandleScope inner_scope(v8_isolate()); + v8::Local<v8::Context> env = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(env); + RunJS("function fun() { this.x = 2; }; var obj = new fun();"); + obj2 = inner_scope.Escape( + env->Global()->Get(env, NewString("obj")).ToLocalChecked()); } - SafepointScope safepoint_scope(heap->isolate(), - kGlobalSafepointForSharedSpaceIsolate); - MarkingBarrier::PublishAll(heap); + // Prepare function f that contains a polymorphic IC for objects + // originating from two different native contexts. + EXPECT_TRUE( + context()->Global()->Set(context(), NewString("obj1"), obj1).FromJust()); + EXPECT_TRUE( + context()->Global()->Set(context(), NewString("obj2"), obj2).FromJust()); + RunJS( + "function f(o) { return o.x; }; " + "%EnsureFeedbackVectorForFunction(f);" + "f(obj1); f(obj1); f(obj2);"); + DirectHandle<JSFunction> f = Cast< + JSFunction>(v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + context()->Global()->Get(context(), NewString("f")).ToLocalChecked()))); - // Finish marking with bigger steps to speed up test. - static constexpr auto kLargeStepSize = - v8::base::TimeDelta::FromMilliseconds(1000); - while (!marking->IsMajorMarkingComplete()) { - marking->AdvanceForTesting(kLargeStepSize); + CheckIC(i_isolate(), f, 0, InlineCacheState::POLYMORPHIC); + + // Fire context dispose notification. + SimulateIncrementalMarking(); + InvokeMajorGC(); + + CheckIC(i_isolate(), f, 0, InlineCacheState::POLYMORPHIC); +} + +TEST_F(HeapTest, ContextDisposeDoesntClearPolymorphicIC) { + if (!v8_flags.use_ic) return; + if (!v8_flags.incremental_marking) return; + v8_flags.allow_natives_syntax = true; + v8::HandleScope scope(v8_isolate()); + v8::Local<v8::Value> obj1, obj2; + + { + v8::EscapableHandleScope inner_scope(v8_isolate()); + v8::Local<v8::Context> env = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(env); + RunJS("function fun() { this.x = 1; }; var obj = new fun();"); + obj1 = inner_scope.Escape( + env->Global()->Get(env, NewString("obj")).ToLocalChecked()); } - CHECK(marking->IsMajorMarkingComplete()); - // All objects need to be black after marking. If a white object crossed the - // progress bar, we would fail here. - for (uint32_t i = 0; i < arr.get()->length().value(); i++) { - Tagged<HeapObject> arr_value = Cast<HeapObject>(arr.get()->get(i)); - CHECK(HeapLayout::InReadOnlySpace(arr_value) || - marking_state->IsMarked(arr_value)); + { + v8::EscapableHandleScope inner_scope(v8_isolate()); + v8::Local<v8::Context> env = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(env); + RunJS("function fun() { this.x = 2; }; var obj = new fun();"); + obj2 = inner_scope.Escape( + env->Global()->Get(env, NewString("obj")).ToLocalChecked()); } + + // Prepare function f that contains a polymorphic IC for objects + // originating from two different native contexts. + EXPECT_TRUE( + context()->Global()->Set(context(), NewString("obj1"), obj1).FromJust()); + EXPECT_TRUE( + context()->Global()->Set(context(), NewString("obj2"), obj2).FromJust()); + RunJS( + "function f(o) { return o.x; }; " + "%EnsureFeedbackVectorForFunction(f);" + "f(obj1); f(obj1); f(obj2);"); + DirectHandle<JSFunction> f = Cast< + JSFunction>(v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + context()->Global()->Get(context(), NewString("f")).ToLocalChecked()))); + + CheckIC(i_isolate(), f, 0, InlineCacheState::POLYMORPHIC); + + // Fire context dispose notification. + v8_isolate()->ContextDisposedNotification( + v8::ContextDependants::kSomeDependants); + SimulateIncrementalMarking(); + InvokeMajorGC(); + + CheckIC(i_isolate(), f, 0, InlineCacheState::POLYMORPHIC); } -DirectHandle<FixedArray> ShrinkArrayAndCheckSize(Heap* heap, int length) { - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - // Make sure there is no garbage and the compilation cache is empty. - for (int i = 0; i < 5; i++) { - InvokeMajorGC(heap->isolate()); +namespace { +class SourceResource : public v8::String::ExternalOneByteStringResource { + public: + explicit SourceResource(const char* data) + : data_(data), length_(strlen(data)) {} + + void Dispose() override { + DeleteArray(data_); + data_ = nullptr; } - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - // Disable LAB, such that calculations with SizeOfObjects() and object size - // are correct. - heap->DisableInlineAllocation(); - size_t size_before_allocation = heap->SizeOfObjects(); - IndirectHandle<FixedArray> array( - *heap->isolate()->factory()->NewFixedArray(length, AllocationType::kOld), - heap->isolate()); - size_t size_after_allocation = heap->SizeOfObjects(); - CHECK_EQ(size_after_allocation, size_before_allocation + array->Size()); - array->RightTrim(heap->isolate(), 1); - size_t size_after_shrinking = heap->SizeOfObjects(); - // Shrinking does not change the space size immediately. - CHECK_EQ(size_after_allocation, size_after_shrinking); - // GC and sweeping updates the size to account for shrinking. - InvokeMajorGC(heap->isolate()); - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); - intptr_t size_after_gc = heap->SizeOfObjects(); - CHECK_EQ(size_after_gc, size_before_allocation + array->Size()); - return array; -} -TEST_F(HeapTest, Regress609761) { - ManualGCScope manual_gc_scope(i_isolate()); - int length = kMaxRegularHeapObjectSize / kTaggedSize + 1; - DirectHandle<FixedArray> array = ShrinkArrayAndCheckSize(heap(), length); - CHECK(heap()->lo_space()->Contains(*array)); + const char* data() const override { return data_; } + + size_t length() const override { return length_; } + + bool IsDisposed() { return data_ == nullptr; } + + private: + const char* data_; + size_t length_; +}; + +void ReleaseStackTraceDataTest(v8::Isolate* isolate, const char* source, + const char* accessor) { + // Test that the data retained by the Error.stack accessor is released + // after the first time the accessor is fired. We use external string + // to check whether the data is being released since the external string + // resource's callback is fired when the external string is GC'ed. + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + v8::HandleScope scope(isolate); + + SourceResource* resource = new SourceResource(StrDup(source)); + { + v8::HandleScope new_scope(isolate); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + v8::Local<v8::String> source_string = + v8::String::NewExternalOneByte(isolate, resource).ToLocalChecked(); + InvokeMemoryReducingMajorGCs(i_isolate); + v8::Script::Compile(context, source_string) + .ToLocalChecked() + ->Run(context) + .ToLocalChecked(); + EXPECT_FALSE(resource->IsDisposed()); + } + EXPECT_FALSE(resource->IsDisposed()); + + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + v8::Script::Compile( + context, v8::String::NewFromUtf8(isolate, accessor).ToLocalChecked()) + .ToLocalChecked() + ->Run(context) + .ToLocalChecked(); + + { + // We need to invoke GC without stack, otherwise some objects may not be + // reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + InvokeMemoryReducingMajorGCs(i_isolate); + } + + // External source has been released. + EXPECT_TRUE(resource->IsDisposed()); + delete resource; } +} // namespace -TEST_F(HeapTest, LiveBytes) { - ManualGCScope manual_gc_scope(i_isolate()); - DirectHandle<FixedArray> array = ShrinkArrayAndCheckSize(heap(), 2000); - CHECK(heap()->old_space()->Contains(*array)); +TEST_F(TestWithPlatform, ReleaseStackTraceData) { +#ifndef V8_LITE_MODE + // ICs retain objects. + v8_flags.use_ic = false; +#endif // V8_LITE_MODE + v8_flags.concurrent_recompilation = false; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + v8::Context::Scope context_scope(context); + static const char* source1 = + "var error = null; " + /* Normal Error */ + "try { " + " throw new Error(); " + "} catch (e) { " + " error = e; " + "} "; + static const char* source2 = + "var error = null; " + /* Stack overflow */ + "try { " + " (function f() { f(); })(); " + "} catch (e) { " + " error = e; " + "} "; + static const char* getter = "error.stack"; + static const char* setter = "error.stack = 0"; + + ReleaseStackTraceDataTest(isolate, source1, setter); + ReleaseStackTraceDataTest(isolate, source2, setter); + ReleaseStackTraceDataTest(isolate, source1, getter); + ReleaseStackTraceDataTest(isolate, source2, getter); + } + isolate->Dispose(); } -TEST_F(HeapTest, Regress615489) { - if (!v8_flags.incremental_marking) return; - ManualGCScope manual_gc_scope(i_isolate()); - HandleScope scope(i_isolate()); - Heap* heap = this->heap(); +TEST_F(HeapTest, AllocationSiteCreation) { Isolate* isolate = i_isolate(); - InvokeMajorGC(); + HandleScope scope(isolate); + v8_flags.allow_natives_syntax = true; - IncrementalMarking* marking = heap->incremental_marking(); - if (heap->sweeping_in_progress()) { - heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, - CompleteSweepingReason::kTesting); + // Array literals. + CheckNumberOfAllocations(this, + "function f1() {" + " return []; " + "};" + "%EnsureFeedbackVectorForFunction(f1); f1();", + 1, 0); + CheckNumberOfAllocations(this, + "function f2() {" + " return [1, 2];" + "};" + "%EnsureFeedbackVectorForFunction(f2); f2();", + 1, 0); + CheckNumberOfAllocations(this, + "function f3() {" + " return [[1], [2]];" + "};" + "%EnsureFeedbackVectorForFunction(f3); f3();", + 1, 2); + CheckNumberOfAllocations(this, + "function f4() { " + "return [0, [1, 1.1, 1.2, " + "], 1.5, [2.1, 2.2], 3];" + "};" + "%EnsureFeedbackVectorForFunction(f4); f4();", + 1, 2); + + // Object literals have lazy AllocationSites + CheckNumberOfAllocations(this, + "function f5() {" + " return {};" + "};" + "%EnsureFeedbackVectorForFunction(f5); f5();", + 0, 0); + + // No AllocationSites are created for the empty object literal. + for (int i = 0; i < 5; i++) { + CheckNumberOfAllocations(this, "f5(); ", 0, 0); + } + + CheckNumberOfAllocations(this, + "function f6() {" + " return {a:1};" + "};" + "%EnsureFeedbackVectorForFunction(f6); f6();", + 0, 0); + + CheckNumberOfAllocations(this, "f6(); ", 1, 0); + + CheckNumberOfAllocations(this, + "function f7() {" + " return {a:1, b:2};" + "};" + "%EnsureFeedbackVectorForFunction(f7); f7(); ", + 0, 0); + CheckNumberOfAllocations(this, "f7(); ", 1, 0); + + // No Allocation sites are created for object subliterals + CheckNumberOfAllocations(this, + "function f8() {" + "return {a:{}, b:{ a:2, c:{ d:{f:{}}} } }; " + "};" + "%EnsureFeedbackVectorForFunction(f8); f8();", + 0, 0); + CheckNumberOfAllocations(this, "f8(); ", 1, 0); + + // We currently eagerly create allocation sites if there are sub-arrays. + // Allocation sites are created only for array subliterals + CheckNumberOfAllocations(this, + "function f9() {" + "return {a:[1, 2, 3], b:{ a:2, c:{ d:{f:[]} } }}; " + "};" + "%EnsureFeedbackVectorForFunction(f9); f9(); ", + 1, 2); + + // No new AllocationSites created on the second invocation. + CheckNumberOfAllocations(this, "f9(); ", 0, 0); +} + +TEST_F(HeapTest, CellsInOptimizedCodeAreWeak) { + v8_flags.allow_natives_syntax = true; + if (!i_isolate()->use_optimizer()) return; + HandleScope outer_scope(i_isolate()); + IndirectHandle<Code> code; + { + HandleScope scope(i_isolate()); + { + v8::Local<v8::Context> local_context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(local_context); + + RunJS( + "bar = (function() {" + " function bar() {" + " return foo(1);" + " };" + " %PrepareFunctionForOptimization(bar);" + " var foo = function(x) { with (x) { return 1 + x; } };" + " %NeverOptimizeFunction(foo);" + " bar(foo);" + " bar(foo);" + " bar(foo);" + " %OptimizeFunctionOnNextCall(bar);" + " bar(foo);" + " return bar;})();"); + + DirectHandle<JSFunction> bar = Cast<JSFunction>( + v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + local_context->Global() + ->Get(local_context, NewString("bar")) + .ToLocalChecked()))); + code = handle(bar->code(i_isolate()), i_isolate()); + } + code = scope.CloseAndEscape(code); } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - heap->StartIncrementalMarking(GCFlag::kNoFlags, - GarbageCollectionReason::kTesting); + + // Now make sure that a gc should get rid of the function + for (int i = 0; i < 4; i++) { + // We need to invoke GC without stack, otherwise some objects may not be + // reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); } - CHECK(marking->IsMarking()); - CHECK(marking->black_allocation()); + + EXPECT_TRUE(code->marked_for_deoptimization()); + EXPECT_TRUE(code->embedded_objects_cleared()); +} + +TEST_F(HeapTest, ObjectsInOptimizedCodeAreWeak) { + v8_flags.allow_natives_syntax = true; + if (!i_isolate()->use_optimizer()) return; + HandleScope outer_scope(i_isolate()); + IndirectHandle<Code> code; { - AlwaysAllocateScopeForTesting always_allocate(heap); - HandleScope inner(isolate); - isolate->factory()->NewFixedArray(500, AllocationType::kOld)->Size(); + HandleScope scope(i_isolate()); + { + v8::Local<v8::Context> local_context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(local_context); + + RunJS( + "function bar() {" + " return foo(1);" + "};" + "%PrepareFunctionForOptimization(bar);" + "function foo(x) { with (x) { return 1 + x; } };" + "%NeverOptimizeFunction(foo);" + "bar();" + "bar();" + "bar();" + "%OptimizeFunctionOnNextCall(bar);" + "bar();"); + + DirectHandle<JSFunction> bar = Cast<JSFunction>( + v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + local_context->Global() + ->Get(local_context, NewString("bar")) + .ToLocalChecked()))); + code = handle(bar->code(i_isolate()), i_isolate()); + } + code = scope.CloseAndEscape(code); } - static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); - while (!marking->IsMajorMarkingComplete()) { - marking->AdvanceForTesting(kStepSize); + + // Now make sure that a gc should get rid of the function + for (int i = 0; i < 4; i++) { + // We need to invoke GC without stack, otherwise some objects may not be + // reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); } - CHECK(marking->IsMajorMarkingComplete()); - size_t size_before = heap->SizeOfObjects(); - InvokeMajorGC(); - size_t size_after = heap->SizeOfObjects(); - // Live size does not increase after garbage collection. - CHECK_LE(size_after, size_before); + + EXPECT_TRUE(code->marked_for_deoptimization()); + EXPECT_TRUE(code->embedded_objects_cleared()); +} + +TEST_F(HeapTest, NewSpaceObjectsInOptimizedCode) { + if (v8_flags.single_generation) return; + v8_flags.allow_natives_syntax = true; + ManualGCScope manual_gc_scope(i_isolate()); + if (!i_isolate()->use_optimizer()) return; + HandleScope outer_scope(i_isolate()); + IndirectHandle<Code> code; + { + HandleScope scope(i_isolate()); + { + v8::Local<v8::Context> local_context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(local_context); + + RunJS( + "var foo;" + "var bar;" + "(function() {" + " function foo_func(x) { with (x) { return 1 + x; } };" + " %NeverOptimizeFunction(foo_func);" + " function bar_func() {" + " return foo(1);" + " };" + " %PrepareFunctionForOptimization(bar_func);" + " bar = bar_func;" + " foo = foo_func;" + " bar_func();" + " bar_func();" + " bar_func();" + " %OptimizeFunctionOnNextCall(bar_func);" + " bar_func();" + "})();"); + + DirectHandle<JSFunction> bar = Cast<JSFunction>( + v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + local_context->Global() + ->Get(local_context, NewString("bar")) + .ToLocalChecked()))); + + DirectHandle<JSFunction> foo = Cast<JSFunction>( + v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + local_context->Global() + ->Get(local_context, NewString("foo")) + .ToLocalChecked()))); + + EXPECT_TRUE(HeapLayout::InYoungGeneration(*foo)); + InvokeMajorGC(); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*foo)); +#ifdef VERIFY_HEAP + HeapVerifier::VerifyHeap(heap()); +#endif + EXPECT_FALSE(bar->code(i_isolate())->marked_for_deoptimization()); + code = handle(bar->code(i_isolate()), i_isolate()); + } + code = scope.CloseAndEscape(code); + } + + // Now make sure that a gc should get rid of the function + for (int i = 0; i < 4; i++) { + // We need to invoke GC without stack, otherwise some objects may not be + // reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + + EXPECT_TRUE(code->marked_for_deoptimization()); + EXPECT_TRUE(code->embedded_objects_cleared()); +} + +TEST_F(HeapTest, ObjectsInEagerlyDeoptimizedCodeAreWeak) { + v8_flags.allow_natives_syntax = true; + if (!i_isolate()->use_optimizer()) return; + HandleScope outer_scope(i_isolate()); + IndirectHandle<Code> code; + { + HandleScope scope(i_isolate()); + { + v8::Local<v8::Context> local_context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(local_context); + + RunJS( + "function bar() {" + " return foo(1);" + "};" + "function foo(x) { with (x) { return 1 + x; } };" + "%NeverOptimizeFunction(foo);" + "%PrepareFunctionForOptimization(bar);" + "bar();" + "bar();" + "bar();" + "%OptimizeFunctionOnNextCall(bar);" + "bar();"); + + DirectHandle<JSFunction> bar = Cast<JSFunction>( + v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( + local_context->Global() + ->Get(local_context, NewString("bar")) + .ToLocalChecked()))); + code = handle(bar->code(i_isolate()), i_isolate()); + RunJS("%DeoptimizeFunction(bar);"); + EXPECT_TRUE(code->marked_for_deoptimization()); + EXPECT_FALSE((*code).SafeEquals(bar->code(i_isolate()))); + } + code = scope.CloseAndEscape(code); + } + + // Now make sure that a gc should get rid of the function + for (int i = 0; i < 4; i++) { + // We need to invoke GC without stack, otherwise some objects may not be + // reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + + EXPECT_TRUE(code->marked_for_deoptimization()); + EXPECT_TRUE(code->embedded_objects_cleared()); +} + +TEST_F(HeapTest, MonomorphicStaysMonomorphicAfterGC) { + if (!v8_flags.use_ic) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + v8_flags.allow_natives_syntax = true; + RunJS( + "function loadIC(obj) {" + " return obj.name;" + "}" + "%EnsureFeedbackVectorForFunction(loadIC);" + "function testIC() {" + " var proto = {'name' : 'weak'};" + " var obj = Object.create(proto);" + " loadIC(obj);" + " loadIC(obj);" + " loadIC(obj);" + " return proto;" + "};"); + DirectHandle<JSFunction> loadIC = GetFunctionByName(i_isolate(), "loadIC"); + { + v8::HandleScope new_scope(v8_isolate()); + RunJS("(testIC())"); + } + InvokeMajorGC(); + CheckIC(i_isolate(), loadIC, 0, InlineCacheState::MONOMORPHIC); + { + v8::HandleScope new_scope(v8_isolate()); + RunJS("(testIC())"); + } + CheckIC(i_isolate(), loadIC, 0, InlineCacheState::MONOMORPHIC); +} + +TEST_F(HeapTest, PolymorphicStaysPolymorphicAfterGC) { + if (!v8_flags.use_ic) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + v8_flags.allow_natives_syntax = true; + RunJS( + "function loadIC(obj) {" + " return obj.name;" + "}" + "%EnsureFeedbackVectorForFunction(loadIC);" + "function testIC() {" + " var proto = {'name' : 'weak'};" + " var obj = Object.create(proto);" + " loadIC(obj);" + " loadIC(obj);" + " loadIC(obj);" + " var poly = Object.create(proto);" + " poly.x = true;" + " loadIC(poly);" + " return proto;" + "};"); + DirectHandle<JSFunction> loadIC = GetFunctionByName(i_isolate(), "loadIC"); + { + v8::HandleScope new_scope(v8_isolate()); + RunJS("(testIC())"); + } + InvokeMajorGC(); + CheckIC(i_isolate(), loadIC, 0, InlineCacheState::POLYMORPHIC); + { + v8::HandleScope new_scope(v8_isolate()); + RunJS("(testIC())"); + } + CheckIC(i_isolate(), loadIC, 0, InlineCacheState::POLYMORPHIC); +} + +#ifdef DEBUG +TEST_F(TestWithPlatform, AddInstructionChangesNewSpacePromotion) { + v8_flags.allow_natives_syntax = true; + v8_flags.expose_gc = true; + v8_flags.stress_compaction = true; + FlagList::EnforceFlagImplications(); + HeapAllocator::SetAllocationGcInterval(1000); + if (!v8_flags.allocation_site_pretenuring) { + HeapAllocator::SetAllocationGcInterval(-1); + return; + } + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* v8_isolate = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(v8_isolate); + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + Heap* heap = isolate->heap(); + v8::HandleScope scope(v8_isolate); + v8::Local<v8::Context> local_context = v8::Context::New(v8_isolate); + v8::Context::Scope context_scope(local_context); + v8::Script::Compile( + local_context, + v8::String::NewFromUtf8Literal(v8_isolate, + "function add(a, b) {" + " return a + b;" + "}" + "add(1, 2);" + "add(\"a\", \"b\");" + "var oldSpaceObject;" + "gc();" + "function crash(x) {" + " var object = {a: null, b: null};" + " var result = add(1.5, x | 0);" + " object.a = result;" + " oldSpaceObject = object;" + " return object;" + "}" + "%PrepareFunctionForOptimization(crash);" + "crash(1);" + "crash(1);" + "%OptimizeFunctionOnNextCall(crash);" + "crash(1);")) + .ToLocalChecked() + ->Run(local_context) + .ToLocalChecked(); + + v8::Local<v8::Object> global = local_context->Global(); + v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( + global + ->Get(local_context, + v8::String::NewFromUtf8Literal(v8_isolate, "crash")) + .ToLocalChecked()); + v8::Local<v8::Value> info1[] = {v8::Number::New(v8_isolate, 1)}; + heap->DisableInlineAllocation(); + heap->set_allocation_timeout(1); + g->Call(local_context, global, 1, info1).ToLocalChecked(); + InvokeMajorGC(isolate); + } + v8_isolate->Dispose(); + HeapAllocator::SetAllocationGcInterval(-1); +} +#endif // DEBUG + +TEST_F(TestWithPlatformAndHeapInternals, Regress538257) { + ManualGCScope manual_gc_scope(nullptr); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + v8::Isolate::CreateParams create_params; + // Set heap limits. + create_params.constraints.set_max_young_generation_size_in_bytes(3 * MB); +#ifdef DEBUG + create_params.constraints.set_max_old_generation_size_in_bytes(20 * MB); +#else + create_params.constraints.set_max_old_generation_size_in_bytes(6 * MB); +#endif + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + isolate->Enter(); + { + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + HandleScope handle_scope(i_isolate); + PagedSpace* old_space = heap->old_space(); + const int kMaxObjects = 10000; + const int kFixedArrayLen = 512; + Handle<FixedArray> objects[kMaxObjects]; + for (int i = 0; (i < kMaxObjects) && + heap->CanExpandOldGeneration(old_space->AreaSize()); + i++) { + objects[i] = i_isolate->factory()->NewFixedArray(kFixedArrayLen, + AllocationType::kOld); + ForceEvacuationCandidate(NormalPage::FromHeapObject(*objects[i])); + } + SimulateFullSpace(old_space); + InvokeMajorGC(i_isolate); + // If we get this far, we've successfully aborted compaction. Any further + // allocations might trigger OOM. + } + isolate->Exit(); + isolate->Dispose(); +} + +TEST_F(HeapTest, Regress357137) { + struct InterruptHelper { + static void Callback(v8::Isolate*, void*) {} + static void Request(const v8::FunctionCallbackInfo<v8::Value>& info) { + EXPECT_TRUE(ValidateCallbackInfo(info)); + info.GetIsolate()->RequestInterrupt(&Callback, nullptr); + } + }; + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope hscope(isolate); + v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); + global->Set(isolate, "interrupt", + v8::FunctionTemplate::New(isolate, InterruptHelper::Request)); + v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global); + EXPECT_FALSE(context.IsEmpty()); + v8::Context::Scope cscope(context); + + v8::Local<v8::Value> result = v8::Utils::ToLocal(RunJS( + "var locals = '';" + "for (var i = 0; i < 512; i++) locals += 'var v' + i + '= 42;';" + "eval('function f() {' + locals + 'return function() { return v0; }; }');" + "interrupt();" // This triggers a fake stack overflow in f. + "f()()")); + EXPECT_EQ(42.0, result->ToNumber(context).ToLocalChecked()->Value()); +} + +TEST_F(HeapTest, Regress507979) { + const int kFixedArrayLen = 10; + ManualGCScope manual_gc_scope(i_isolate()); + Isolate* isolate = i_isolate(); + HandleScope handle_scope(isolate); + + DirectHandle<FixedArray> o1 = + isolate->factory()->NewFixedArray(kFixedArrayLen); + DirectHandle<FixedArray> o2 = + isolate->factory()->NewFixedArray(kFixedArrayLen); + EXPECT_TRUE(IsNewObjectInCorrectGeneration(*o1)); + EXPECT_TRUE(IsNewObjectInCorrectGeneration(*o2)); + + HeapObjectIterator it(isolate->heap(), + HeapObjectIterator::kFilterUnreachable); + + // Replace parts of an object placed before a live object with a filler. This + // way the filler object shares the mark bits with the following live object. + o1->RightTrim(isolate, kFixedArrayLen - 1); + + for (Tagged<HeapObject> obj = it.Next(); !obj.is_null(); obj = it.Next()) { + // Let's not optimize the loop away. + EXPECT_NE(obj.address(), kNullAddress); + } +} + +TEST_F(HeapTest, Regress388880) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + + DirectHandle<Map> map1 = Map::Create(i_isolate(), 1); + Handle<String> name = factory()->NewStringFromStaticChars("foo"); + name = factory()->InternalizeString(name); + DirectHandle<Map> map2 = + Map::CopyWithField(i_isolate(), map1, name, FieldType::Any(i_isolate()), + NONE, PropertyConstness::kMutable, + Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); + + size_t desired_offset = NormalPage::kPageSize - map1->instance_size(); + + // Allocate padding objects in old pointer space so, that object allocated + // afterwards would end at the end of the page. + SimulateFullSpace(heap()->old_space()); + size_t padding_size = + desired_offset - MemoryChunkLayout::ObjectStartOffsetInDataPage(); + CreatePadding(static_cast<int>(padding_size), AllocationType::kOld); + heap()->FreeMainThreadLinearAllocationAreas(); + + DirectHandle<JSObject> o = + factory()->NewJSObjectFromMap(map1, AllocationType::kOld); + o->set_raw_properties_or_hash(*factory()->empty_fixed_array()); + + // Ensure that the object allocated where we need it. + NormalPage* page = NormalPage::FromHeapObject(*o); + EXPECT_EQ(desired_offset, page->Offset(o->address())); + + // Now we have an object right at the end of the page. + + // Enable incremental marking to trigger actions in Heap::AdjustLiveBytes() + // that would cause crash. + IncrementalMarking* marking = heap()->incremental_marking(); + marking->Stop(); + heap()->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + EXPECT_TRUE(marking->IsMarking()); + + // Now everything is set up for crashing in JSObject::MigrateFastToFast() + // when it calls heap->AdjustLiveBytes(...). + JSObject::MigrateToMap(i_isolate(), o, map2); +} + +TEST_F(HeapTest, Regress3631) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + IncrementalMarking* marking = heap()->incremental_marking(); + v8::Local<v8::Value> result = + v8::Utils::ToLocal(RunJS("var weak_map = new WeakMap();" + "var future_keys = [];" + "for (var i = 0; i < 50; i++) {" + " var key = {'k' : i + 0.1};" + " weak_map.set(key, 1);" + " future_keys.push({'x' : i + 0.2});" + "}" + "weak_map")); + if (marking->IsStopped()) { + heap()->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + } + // Incrementally mark the backing store. + DirectHandle<JSReceiver> obj = + v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(result)); + DirectHandle<JSWeakCollection> weak_map(Cast<JSWeakCollection>(*obj), + i_isolate()); + SimulateIncrementalMarking(); + // Stash the backing store in a handle. + DirectHandle<Object> save(weak_map->table(), i_isolate()); + USE(save); + // The following line will update the backing store. + RunJS( + "for (var i = 0; i < 50; i++) {" + " weak_map.set(future_keys[i], i);" + "}"); + InvokeMajorGC(); +} + +TEST_F(HeapTest, Regress442710) { + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + + HandleScope sc(isolate); + DirectHandle<JSGlobalObject> global(isolate->context()->global_object(), + isolate); + DirectHandle<JSArray> array = factory->NewJSArray(2); + + DirectHandle<String> name = factory->InternalizeUtf8String("testArray"); + Object::SetProperty(isolate, global, name, array).Check(); + RunJS("testArray[0] = 1; testArray[1] = 2; testArray.shift();"); + InvokeMajorGC(); +} + +TEST_F(HeapTest, NumberStringCacheSize) { + // Test that the number-string cache has not been resized in the snapshot. + if (!i_isolate()->snapshot_available()) return; + EXPECT_EQ(static_cast<uint32_t>(SmiStringCache::kInitialSize), + factory()->smi_string_cache()->capacity()); + EXPECT_EQ(static_cast<uint32_t>(DoubleStringCache::kInitialSize), + factory()->double_string_cache()->capacity()); +} + +TEST_F(HeapTest, Regress3877) { + HandleScope scope(i_isolate()); + RunJS("function cls() { this.x = 10; }"); + IndirectHandle<WeakFixedArray> weak_prototype_holder = + factory()->NewWeakFixedArray(1); + { + HandleScope inner_scope(i_isolate()); + DirectHandle<JSReceiver> proto = RunJS<JSReceiver>("cls.prototype"); + weak_prototype_holder->set(0, MakeWeak(*proto)); + } + EXPECT_FALSE(weak_prototype_holder->get(0).IsCleared()); + RunJS( + "var a = { };" + "a.x = new cls();" + "cls.prototype = null;"); + for (int i = 0; i < 4; i++) { + InvokeMajorGC(); + } + // The map of a.x keeps prototype alive + EXPECT_FALSE(weak_prototype_holder->get(0).IsCleared()); + // Detach the map (by promoting it to a prototype). + RunJS("var b = {}; b.__proto__ = a.x"); + // Change the map of a.x and make the previous map garbage collectable. + RunJS("a.x.__proto__ = {};"); + + for (int i = 0; i < 4; i++) { + // We need to invoke GC without stack, otherwise some objects may not be + // reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + EXPECT_TRUE(weak_prototype_holder->get(0).IsCleared()); +} + +namespace { +Handle<WeakFixedArray> AddRetainedMap(Isolate* isolate, + DirectHandle<NativeContext> context) { + HandleScope inner_scope(isolate); + IndirectHandle<Map> map = Map::Create(isolate, 1); + v8::Isolate* v8_iso = reinterpret_cast<v8::Isolate*>(isolate); + v8::Local<v8::Context> v8_ctx = v8::Utils::ToLocal(context); + v8::Local<v8::Value> result = + v8::Script::Compile(v8_ctx, + v8::String::NewFromUtf8Literal( + v8_iso, "(function () { return {x : 10}; })();")) + .ToLocalChecked() + ->Run(v8_ctx) + .ToLocalChecked(); + DirectHandle<JSReceiver> proto = + v8::Utils::OpenDirectHandle(*v8::Local<v8::Object>::Cast(result)); + Map::SetPrototype(isolate, map, proto); + isolate->heap()->AddRetainedMaps(context, base::VectorOf(&map, 1)); + Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(1); + array->set(0, MakeWeak(*map)); + return inner_scope.CloseAndEscape(array); +} + +void CheckMapRetainingFor(HeapTest* test, int n) { + v8_flags.retain_maps_for_n_gc = n; + IndirectHandle<NativeContext> native_context; + // This global is used to visit the object's constructor alive when starting + // incremental marking. The native context keeps the constructor alive. The + // constructor needs to be alive to retain the map. + v8::Global<v8::Context> global_ctxt; + + { + v8::Local<v8::Context> ctx = v8::Context::New(test->v8_isolate()); + IndirectHandle<Context> context = v8::Utils::OpenIndirectHandle(*ctx); + EXPECT_TRUE(IsNativeContext(*context)); + native_context = Cast<NativeContext>(context); + global_ctxt.Reset(test->v8_isolate(), ctx); + ctx->Enter(); + } + + IndirectHandle<WeakFixedArray> array_with_map = + AddRetainedMap(test->i_isolate(), native_context); + EXPECT_TRUE(array_with_map->get(0).IsWeak()); + for (int i = 0; i < n; i++) { + test->SimulateIncrementalMarking(); + DisableConservativeStackScanningScopeForTesting no_stack_scanning( + test->heap()); + test->InvokeMajorGC(); + } + EXPECT_TRUE(array_with_map->get(0).IsWeak()); + { + test->SimulateIncrementalMarking(); + // In this test, we need to invoke GC without stack, otherwise some + // objects may not be reclaimed because of conservative stack scanning. + DisableConservativeStackScanningScopeForTesting no_stack_scanning( + test->heap()); + test->InvokeMajorGC(); + } + EXPECT_TRUE(array_with_map->get(0).IsCleared()); + + global_ctxt.Get(test->v8_isolate())->Exit(); +} +} // namespace + +TEST_F(HeapTest, MapRetaining) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + + CheckMapRetainingFor(this, v8_flags.retain_maps_for_n_gc); + CheckMapRetainingFor(this, 0); + CheckMapRetainingFor(this, 1); + CheckMapRetainingFor(this, 7); +} + +TEST_F(HeapTest, RetainedMapsCleanup) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + v8::Local<v8::Context> ctx = v8::Context::New(v8_isolate()); + DirectHandle<Context> context = v8::Utils::OpenDirectHandle(*ctx); + EXPECT_TRUE(IsNativeContext(*context)); + DirectHandle<NativeContext> native_context = Cast<NativeContext>(context); + + { + v8::Context::Scope context_scope(ctx); + DirectHandle<WeakFixedArray> array_with_map = + AddRetainedMap(i_isolate(), native_context); + EXPECT_TRUE(array_with_map->get(0).IsWeak()); + heap()->NotifyContextDisposed(true); + InvokeMajorGC(); + } + + EXPECT_EQ(ReadOnlyRoots(heap()).empty_weak_array_list(), + native_context->retained_maps()); +} + +TEST_F(HeapTest, TrimDescriptorArrayClearsSlackDescriptors) { + FlagScope<bool> no_stress_trimming(&v8_flags.stress_descriptor_array_trimming, + false); + ManualGCScope manual_gc_scope(i_isolate()); + HandleScope scope(i_isolate()); + + IndirectHandle<JSObject> parent = + RunJS<JSObject>("var parent = { a: 1 }; parent"); + IndirectHandle<WeakFixedArray> weak_getter = factory()->NewWeakFixedArray(1); + { + HandleScope inner_scope(i_isolate()); + DirectHandle<JSFunction> getter = RunJS<JSFunction>( + "(function() {" + " var child = { a: 1 };" + " var getter = function() { return 42; };" + " Object.defineProperty(child, 'b', { get: getter });" + " return getter;" + "})()"); + weak_getter->set(0, MakeWeak(*getter)); + } + EXPECT_EQ(1, parent->map()->NumberOfOwnDescriptors()); + EXPECT_FALSE(parent->map()->owns_descriptors()); + EXPECT_EQ(2, parent->map()->instance_descriptors()->number_of_descriptors()); + EXPECT_EQ(2, + parent->map()->instance_descriptors()->number_of_all_descriptors()); + EXPECT_FALSE(weak_getter->get(0).IsCleared()); + + // The first GC clears the dead child map transition and trims + // `number_of_descriptors` back to 1 without right-trimming the + // DescriptorArray. It should clear the slack descriptor slots. + { + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + EXPECT_TRUE(parent->map()->owns_descriptors()); + EXPECT_EQ(1, parent->map()->instance_descriptors()->number_of_descriptors()); + EXPECT_EQ(2, + parent->map()->instance_descriptors()->number_of_all_descriptors()); + // `getter` was still marked during the first GC before `TrimDescriptorArray` + // cleared the slack descriptor slot during weak clearing. + EXPECT_FALSE(weak_getter->get(0).IsCleared()); + + // The second GC should now reclaim `getter` since the slack descriptor slot + // was cleared. + { + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); + } + EXPECT_TRUE(weak_getter->get(0).IsCleared()); +} + +namespace { +void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) { + ASSERT_LE(static_cast<size_t>(OFFSET_OF_DATA_START(FixedArray)), bytes); + ASSERT_TRUE(IsAligned(bytes, kTaggedSize)); + Factory* factory = isolate->factory(); + HandleScope scope(isolate); + AlwaysAllocateScopeForTesting always_allocate(isolate->heap()); + int elements = static_cast<int>((bytes - OFFSET_OF_DATA_START(FixedArray)) / + kTaggedSize); + DirectHandle<FixedArray> array = factory->NewFixedArray( + elements, + space == NEW_SPACE ? AllocationType::kYoung : AllocationType::kOld); + EXPECT_EQ(space == NEW_SPACE, HeapLayout::InYoungGeneration(*array)); + EXPECT_EQ(bytes, static_cast<size_t>(array->Size())); +} +} // namespace + +TEST_F(HeapTest, NewSpaceAllocationCounter) { + if (v8_flags.single_generation) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = this->heap(); + heap->FreeMainThreadLinearAllocationAreas(); + size_t counter1 = heap->NewSpaceAllocationCounter(); + EmptyNewSpaceUsingGC(); // Ensure new space is empty. + const size_t kSize = 1024; + AllocateInSpace(isolate, kSize, NEW_SPACE); + heap->FreeMainThreadLinearAllocationAreas(); + size_t counter2 = heap->NewSpaceAllocationCounter(); + EXPECT_EQ(kSize, counter2 - counter1); + InvokeMinorGC(); + size_t counter3 = heap->NewSpaceAllocationCounter(); + EXPECT_EQ(0U, counter3 - counter2); + // Test counter overflow. + heap->FreeMainThreadLinearAllocationAreas(); + size_t max_counter = static_cast<size_t>(-1); + heap->SetNewSpaceAllocationCounterForTesting(max_counter - 10 * kSize); + size_t start = heap->NewSpaceAllocationCounter(); + for (int i = 0; i < 20; i++) { + AllocateInSpace(isolate, kSize, NEW_SPACE); + heap->FreeMainThreadLinearAllocationAreas(); + size_t counter = heap->NewSpaceAllocationCounter(); + EXPECT_EQ(kSize, counter - start); + start = counter; + } +} + +TEST_F(HeapTest, OldSpaceAllocationCounter) { + // Using the string forwarding table can free allocations during sweeping, due + // to ThinString trimming, thus failing this test. + // The flag (and handling of the forwarding table/ThinString transitions in + // young gen) is only temporary so we just skip this test for now. + if (v8_flags.always_use_string_forwarding_table) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = this->heap(); + // Disable LAB, such that calculations with SizeOfObjects() and object size + // are correct. + heap->DisableInlineAllocation(); + EmptyNewSpaceUsingGC(); + size_t counter1 = heap->OldGenerationAllocationCounter(); + const size_t kSize = 1024; + AllocateInSpace(isolate, kSize, OLD_SPACE); + size_t counter2 = heap->OldGenerationAllocationCounter(); + // TODO(ulan): replace all CHECK_LE with CHECK_EQ after v8:4148 is fixed. + EXPECT_LE(kSize, counter2 - counter1); + InvokeMinorGC(); + size_t counter3 = heap->OldGenerationAllocationCounter(); + EXPECT_EQ(0u, counter3 - counter2); + AllocateInSpace(isolate, kSize, OLD_SPACE); + InvokeMajorGC(); + size_t counter4 = heap->OldGenerationAllocationCounter(); + EXPECT_LE(kSize, counter4 - counter3); + // Test counter overflow. + size_t max_counter = static_cast<size_t>(-1); + heap->set_old_generation_allocation_counter_at_last_gc(max_counter - + 10 * kSize); + size_t start = heap->OldGenerationAllocationCounter(); + for (int i = 0; i < 20; i++) { + AllocateInSpace(isolate, kSize, OLD_SPACE); + size_t counter = heap->OldGenerationAllocationCounter(); + EXPECT_LE(kSize, counter - start); + start = counter; + } +} + +TEST_F(HeapTest, MessageObjectLeak) { + struct LeakHelper { + static void CheckLeak(const v8::FunctionCallbackInfo<v8::Value>& info) { + EXPECT_TRUE(ValidateCallbackInfo(info)); + Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + Tagged<Object> message( + *reinterpret_cast<Address*>(isolate->pending_message_address())); + EXPECT_TRUE(IsTheHole(message)); + } + }; + + v8_flags.allow_natives_syntax = true; + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope scope(isolate); + v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); + global->Set(isolate, "check", + v8::FunctionTemplate::New(isolate, LeakHelper::CheckLeak)); + v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global); + v8::Context::Scope cscope(context); + + const char* test = + "function test() {" + " try {" + " throw 'message 1';" + " } catch (e) {" + " }" + " check();" + " L: try {" + " throw 'message 2';" + " } finally {" + " break L;" + " }" + " check();" + "}" + "%PrepareFunctionForOptimization(test);" + "test()"; + RunJS(test); + + const char* test2 = + "%OptimizeFunctionOnNextCall(test);" + "test()"; + RunJS(test2); +} + +TEST_F(HeapTest, CanonicalSharedFunctionInfo) { + struct CanonicalSFIHelper { + static void CheckEqualSharedFunctionInfos( + const v8::FunctionCallbackInfo<v8::Value>& info) { + EXPECT_TRUE(ValidateCallbackInfo(info)); + DirectHandle<Object> obj1 = v8::Utils::OpenDirectHandle(*info[0]); + DirectHandle<Object> obj2 = v8::Utils::OpenDirectHandle(*info[1]); + DirectHandle<JSFunction> fun1 = Cast<JSFunction>(obj1); + DirectHandle<JSFunction> fun2 = Cast<JSFunction>(obj2); + EXPECT_EQ(fun1->shared(), fun2->shared()); + } + + static void RemoveCodeAndGC( + const v8::FunctionCallbackInfo<v8::Value>& info) { + EXPECT_TRUE(ValidateCallbackInfo(info)); + Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + DirectHandle<Object> obj = v8::Utils::OpenDirectHandle(*info[0]); + DirectHandle<JSFunction> fun = Cast<JSFunction>(obj); + // Bytecode is code too. + SharedFunctionInfo::DiscardCompiled( + isolate, direct_handle(fun->shared(), isolate)); + fun->UpdateCode(isolate, *BUILTIN_CODE(isolate, CompileLazy)); + internal::InvokeMemoryReducingMajorGCs(isolate); + } + }; + + SetGlobalProperty( + "check", + v8::Function::New(v8_context(), + CanonicalSFIHelper::CheckEqualSharedFunctionInfos) + .ToLocalChecked()); + SetGlobalProperty( + "remove", + v8::Function::New(v8_context(), CanonicalSFIHelper::RemoveCodeAndGC) + .ToLocalChecked()); + RunJS( + "function f() { return function g() {}; }" + "var g1 = f();" + "remove(f);" + "var g2 = f();" + "check(g1, g2);"); + + RunJS( + "function f() { return (function() { return function g() {}; })(); }" + "var g1 = f();" + "remove(f);" + "var g2 = f();" + "check(g1, g2);"); +} + +TEST_F(HeapTest, ScriptIterator) { + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = this->heap(); + + InvokeMajorGC(); + + int script_count = 0; + { + HeapObjectIterator it(heap); + for (Tagged<HeapObject> obj = it.Next(); !obj.is_null(); obj = it.Next()) { + if (IsScript(obj)) script_count++; + } + } + + { + Script::Iterator iterator(isolate); + for (Tagged<Script> script = iterator.Next(); !script.is_null(); + script = iterator.Next()) { + script_count--; + } + } + + EXPECT_EQ(0, script_count); +} + +TEST_F(HeapTest, Regress587004) { + if (v8_flags.single_generation) return; + ManualGCScope manual_gc_scope(i_isolate()); +#ifdef VERIFY_HEAP + v8_flags.verify_heap = false; +#endif + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + const int N = (kMaxRegularHeapObjectSize - OFFSET_OF_DATA_START(FixedArray)) / + kTaggedSize; + DirectHandle<FixedArray> array = + factory->NewFixedArray(N, AllocationType::kOld); + EXPECT_TRUE(heap()->old_space()->Contains(*array)); + DirectHandle<Object> number = factory->NewHeapNumber(1.0); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*number)); + for (int i = 0; i < N; i++) { + array->set(i, *number); + } + InvokeMajorGC(); + SimulateFullSpace(heap()->old_space()); + heap()->RightTrimArray(*array, 1, N); + heap()->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + Tagged<ByteArray> byte_array; + const uint32_t M = 256; + // Don't allow old space expansion. The test works without this flag too, + // but becomes very slow. + SetForceOOM(true); + while (AllocateByteArrayForTest(heap(), M, AllocationType::kOld) + .To(&byte_array)) { + for (uint32_t j = 0; j < M; j++) { + byte_array->set(j, 0x31); + } + } + // Re-enable old space expansion to avoid OOM crash. + SetForceOOM(false); + InvokeMinorGC(); +} + +namespace { +template <typename TMixin> +class WithStressCompaction : public TMixin { + private: + FlagScope<bool> stress_compaction_{&v8_flags.stress_compaction, true}; +}; + +using HeapTestWithStressCompaction = // + WithContextMixin< // + WithHeapInternals< // + WithInternalIsolateMixin< // + WithIsolateScopeMixin< // + WithIsolateMixin< // + WithCppHeap< // + WithStressCompaction< // + WithDefaultPlatformMixin< // + ::testing::Test>>>>>>>>; +} // namespace + +TEST_F(HeapTestWithStressCompaction, Regress589413) { + if (!v8_flags.incremental_marking || v8_flags.stress_concurrent_allocation) { + return; + } + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + FLAG_VALUE_SCOPE(parallel_compaction, false); + v8::HandleScope scope(v8_isolate()); + // Get the heap in clean state. + InvokeMajorGC(); + InvokeMajorGC(); + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + // Fill the new space with byte arrays with elements looking like pointers. + const uint32_t M = 256; + Tagged<ByteArray> byte_array; + NormalPage* young_page = nullptr; + while (AllocateByteArrayForTest(heap(), M, AllocationType::kYoung) + .To(&byte_array)) { + // Only allocate objects on one young page as a rough estimate on + // how much memory can be promoted into the old generation. + // Otherwise we would crash when forcing promotion of all young + // live objects. + if (!young_page) young_page = NormalPage::FromHeapObject(byte_array); + if (NormalPage::FromHeapObject(byte_array) != young_page) break; + + for (uint32_t j = 0; j < M; j++) { + byte_array->set(j, 0x31); + } + // Add the array in root set. + handle(byte_array, isolate); + } + auto reset_oom = [](void* data, size_t limit, size_t) -> size_t { + reinterpret_cast<HeapTestWithStressCompaction*>(data)->SetForceOOM(false); + return limit; + }; + heap()->AddNearHeapLimitCallback( + reset_oom, static_cast<HeapTestWithStressCompaction*>(this)); + + { + // Ensure that incremental marking is not started unexpectedly. + AlwaysAllocateScopeForTesting always_allocate(heap()); + + // Make sure the byte arrays will be promoted on the next GC. + InvokeMinorGC(); + // This number is close to large free list category threshold. + const uint32_t N = 0x3EEE; + + std::vector<Tagged<FixedArray>> arrays; + std::set<NormalPage*> pages; + Tagged<FixedArray> array; + // Fill all pages with fixed arrays. + SetForceOOM(true); + while ( + AllocateFixedArrayForTest(heap(), N, AllocationType::kOld).To(&array)) { + arrays.push_back(array); + pages.insert(NormalPage::FromHeapObject(array)); + // Add the array in root set. + handle(array, isolate); + } + SetForceOOM(false); + size_t initial_pages = pages.size(); + // Expand and fill two pages with fixed array to ensure enough space both + // the young objects and the evacuation candidate pages. + while ( + AllocateFixedArrayForTest(heap(), N, AllocationType::kOld).To(&array)) { + arrays.push_back(array); + pages.insert(NormalPage::FromHeapObject(array)); + // Add the array in root set. + handle(array, isolate); + // Do not expand anymore. + if (pages.size() - initial_pages == 2) { + SetForceOOM(true); + } + } + // Expand and mark the new page as evacuation candidate. + SetForceOOM(false); + { + DirectHandle<HeapObject> ec_obj = + factory->NewFixedArray(5000, AllocationType::kOld); + NormalPage* ec_page = NormalPage::FromHeapObject(*ec_obj); + ForceEvacuationCandidate(ec_page); + // Make all arrays point to evacuation candidate so that + // slots are recorded for them. + for (size_t j = 0; j < arrays.size(); j++) { + array = arrays[j]; + for (uint32_t i = 0; i < N; i++) { + array->set(i, *ec_obj); + } + } + } + EXPECT_TRUE(heap()->incremental_marking()->IsStopped()); + SimulateIncrementalMarking(); + for (size_t j = 0; j < arrays.size(); j++) { + heap()->RightTrimArray(arrays[j], 1, N); + } + } + + // Force allocation from the free list. + SetForceOOM(true); + InvokeMajorGC(); + heap()->RemoveNearHeapLimitCallback(reset_oom, 0); +} + +TEST_F(HeapTest, Regress598319) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + // This test ensures that no white objects can cross the progress bar of large + // objects during incremental marking. It checks this by using Shift() during + // incremental marking. + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + + // The size of the array should be larger than kProgressBarScanningChunk. + const uint32_t kNumberOfObjects = + std::max(FixedArray::kMaxRegularLength + 1, 128 * KB); + + struct Arr { + Arr(v8::Isolate* v8_isolate, Isolate* isolate, uint32_t number_of_objects) { + root = isolate->factory()->NewFixedArray(1, AllocationType::kOld); + { + // Temporary scope to avoid getting any other objects into the root set. + v8::HandleScope new_scope(v8_isolate); + DirectHandle<FixedArray> tmp = isolate->factory()->NewFixedArray( + number_of_objects, AllocationType::kOld); + root->set(0, *tmp); + const uint32_t length = get()->length().value(); + for (uint32_t i = 0; i < length; i++) { + tmp = isolate->factory()->NewFixedArray(100, AllocationType::kOld); + get()->set(i, *tmp); + } + } + global_root.Reset(v8_isolate, v8::Utils::ToLocal(Cast<Object>(root))); + } + + Tagged<FixedArray> get() { return Cast<FixedArray>(root->get(0)); } + + Handle<FixedArray> root; + + // Store array in global as well to make it part of the root set when + // starting incremental marking. + v8::Global<v8::Value> global_root; + } arr(v8_isolate(), isolate, kNumberOfObjects); + + EXPECT_EQ(arr.get()->length().value(), kNumberOfObjects); + EXPECT_TRUE(heap()->lo_space()->Contains(arr.get())); + LargePage* page = LargePage::FromHeapObject(isolate, arr.get()); + ASSERT_NE(nullptr, page); + + // GC to cleanup state + InvokeMajorGC(); + if (heap()->sweeping_in_progress()) { + heap()->EnsureSweepingCompleted( + Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + } + + EXPECT_TRUE(heap()->lo_space()->Contains(arr.get())); + IncrementalMarking* marking = heap()->incremental_marking(); + MarkingState* marking_state = heap()->marking_state(); + EXPECT_TRUE(marking_state->IsUnmarked(arr.get())); + + for (uint32_t i = 0; i < arr.get()->length().value(); i++) { + Tagged<HeapObject> arr_value = Cast<HeapObject>(arr.get()->get(i)); + EXPECT_TRUE(marking_state->IsUnmarked(arr_value)); + } + + // Start incremental marking. + EXPECT_TRUE(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + heap()->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking()); + + // Check that we have not marked the interesting array during root scanning. + for (uint32_t i = 0; i < arr.get()->length().value(); i++) { + Tagged<HeapObject> arr_value = Cast<HeapObject>(arr.get()->get(i)); + EXPECT_TRUE(marking_state->IsUnmarked(arr_value)); + } + + // Now we search for a state where we are in incremental marking and have + // only partially marked the large object. + static constexpr auto kSmallStepSize = + v8::base::TimeDelta::FromMillisecondsD(0.1); + static constexpr size_t kSmallMaxBytesToMark = 100; + while (!marking->IsMajorMarkingComplete()) { + marking->AdvanceForTesting(kSmallStepSize, kSmallMaxBytesToMark); + MarkingProgressTracker& progress_tracker = page->marking_progress_tracker(); + if (progress_tracker.IsEnabled() && + progress_tracker.GetCurrentChunkForTesting() > 0) { + EXPECT_NE(progress_tracker.GetCurrentChunkForTesting(), + static_cast<size_t>(arr.get()->Size())); + { + // Shift by 1, effectively moving one white object across the progress + // bar, meaning that we will miss marking it. + v8::HandleScope new_scope(v8_isolate()); + DirectHandle<JSArray> js_array = + isolate->factory()->NewJSArrayWithElements( + DirectHandle<FixedArray>(arr.get(), isolate)); + js_array->GetElementsAccessor()->Shift(isolate, js_array); + } + break; + } + } + + SafepointScope safepoint_scope(isolate, + kGlobalSafepointForSharedSpaceIsolate); + MarkingBarrier::PublishAll(heap()); + + // Finish marking with bigger steps to speed up test. + static constexpr auto kLargeStepSize = + v8::base::TimeDelta::FromMilliseconds(1000); + while (!marking->IsMajorMarkingComplete()) { + marking->AdvanceForTesting(kLargeStepSize); + } + EXPECT_TRUE(marking->IsMajorMarkingComplete()); + + // All objects need to be black after marking. If a white object crossed the + // progress bar, we would fail here. + for (uint32_t i = 0; i < arr.get()->length().value(); i++) { + Tagged<HeapObject> arr_value = Cast<HeapObject>(arr.get()->get(i)); + EXPECT_TRUE(HeapLayout::InReadOnlySpace(arr_value) || + marking_state->IsMarked(arr_value)); + } +} + +namespace { +DirectHandle<FixedArray> ShrinkArrayAndCheckSize(HeapTest* test, int length) { + Heap* heap = test->heap(); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + // Make sure there is no garbage and the compilation cache is empty. + for (int i = 0; i < 5; i++) { + test->InvokeMajorGC(); + } + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + // Disable LAB, such that calculations with SizeOfObjects() and object size + // are correct. + heap->DisableInlineAllocation(); + size_t size_before_allocation = heap->SizeOfObjects(); + IndirectHandle<FixedArray> array( + *heap->isolate()->factory()->NewFixedArray(length, AllocationType::kOld), + heap->isolate()); + size_t size_after_allocation = heap->SizeOfObjects(); + EXPECT_EQ(size_after_allocation, size_before_allocation + array->Size()); + array->RightTrim(heap->isolate(), 1); + size_t size_after_shrinking = heap->SizeOfObjects(); + // Shrinking does not change the space size immediately. + EXPECT_EQ(size_after_allocation, size_after_shrinking); + // GC and sweeping updates the size to account for shrinking. + test->InvokeMajorGC(); + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + size_t size_after_gc = heap->SizeOfObjects(); + EXPECT_EQ(size_after_gc, size_before_allocation + array->Size()); + return array; +} +} // namespace + +TEST_F(HeapTest, Regress609761) { + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + int length = kMaxRegularHeapObjectSize / kTaggedSize + 1; + DirectHandle<FixedArray> array = ShrinkArrayAndCheckSize(this, length); + EXPECT_TRUE(heap()->lo_space()->Contains(*array)); +} + +TEST_F(HeapTest, LiveBytes) { + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + DirectHandle<FixedArray> array = ShrinkArrayAndCheckSize(this, 2000); + EXPECT_TRUE(heap()->old_space()->Contains(*array)); +} + +TEST_F(HeapTest, Regress615489) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Heap* heap = this->heap(); + Isolate* isolate = heap->isolate(); + InvokeMajorGC(); + + IncrementalMarking* marking = heap->incremental_marking(); + if (heap->sweeping_in_progress()) { + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking()); + EXPECT_TRUE(marking->black_allocation()); + { + AlwaysAllocateScopeForTesting always_allocate(heap); + v8::HandleScope inner(v8_isolate()); + isolate->factory()->NewFixedArray(500, AllocationType::kOld)->Size(); + } + static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); + while (!marking->IsMajorMarkingComplete()) { + marking->AdvanceForTesting(kStepSize); + } + EXPECT_TRUE(marking->IsMajorMarkingComplete()); + size_t size_before = heap->SizeOfObjects(); + InvokeMajorGC(); + size_t size_after = heap->SizeOfObjects(); + // Live size does not increase after garbage collection. + EXPECT_LE(size_after, size_before); +} + +namespace { +class StaticOneByteResource : public v8::String::ExternalOneByteStringResource { + public: + explicit StaticOneByteResource(const char* data) : data_(data) {} + ~StaticOneByteResource() override = default; + const char* data() const override { return data_; } + size_t length() const override { return strlen(data_); } + + private: + const char* data_; +}; +} // namespace + +TEST_F(HeapTest, Regress631969) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + v8_flags.parallel_compaction = false; + v8::HandleScope scope(v8_isolate()); + Heap* heap = this->heap(); + // Get the heap in clean state. + InvokeMajorGC(); + InvokeMajorGC(); + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + // Allocate two strings in a fresh page and mark the page as evacuation + // candidate. + SimulateFullSpace(heap->old_space()); + Handle<String> s1 = + factory->NewStringFromStaticChars("123456789", AllocationType::kOld); + Handle<String> s2 = + factory->NewStringFromStaticChars("01234", AllocationType::kOld); + ForceEvacuationCandidate(NormalPage::FromHeapObject(*s1)); + + SimulateIncrementalMarking(false); + + // Allocate a cons string and promote it to a fresh page in the old space. + DirectHandle<String> s3 = factory->NewConsString(s1, s2).ToHandleChecked(); + EmptyNewSpaceUsingGC(); + + SimulateIncrementalMarking(false); + + // Finish incremental marking. + static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); + IncrementalMarking* marking = heap->incremental_marking(); + while (!marking->IsMajorMarkingComplete()) { + marking->AdvanceForTesting(kStepSize); + } + + { + StaticOneByteResource external_string("12345678901234"); + s3->MakeExternal(isolate, &external_string); + InvokeMajorGC(); + // This avoids the GC from trying to free stack allocated resources. + Cast<ExternalOneByteString>(s3)->SetResource(isolate, nullptr); + } +} + +TEST_F(HeapTest, ContinuousRightTrimFixedArrayInBlackArea) { + if (v8_flags.black_allocated_pages) return; + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Heap* heap = this->heap(); + Isolate* isolate = i_isolate(); + InvokeMajorGC(); + + IncrementalMarking* marking = heap->incremental_marking(); + if (heap->sweeping_in_progress()) { + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking()); + EXPECT_TRUE(marking->black_allocation()); + + // Ensure that we allocate a new page, set up a bump pointer area, and + // perform the allocation in a black area. + SimulateFullSpace(heap->old_space()); + isolate->factory()->NewFixedArray(10, AllocationType::kOld); + + // Allocate the fixed array that will be trimmed later. + DirectHandle<FixedArray> array = + isolate->factory()->NewFixedArray(100, AllocationType::kOld); + Address start_address = array->address(); + Address end_address = start_address + array->Size(); + NormalPage* page = NormalPage::FromAddress(start_address); + NonAtomicMarkingState* marking_state = heap->non_atomic_marking_state(); + EXPECT_TRUE(marking_state->IsMarked(*array)); + EXPECT_TRUE(page->marking_bitmap()->AllBitsSetInRange( + MarkingBitmap::AddressToIndex(start_address), + MarkingBitmap::LimitAddressToIndex(end_address))); + EXPECT_TRUE(heap->old_space()->Contains(*array)); + + // Trim it once by one word to check that the trimmed area gets unmarked. + Address previous = end_address - kTaggedSize; + isolate->heap()->RightTrimArray(*array, 99, 100); + + Tagged<HeapObject> filler = HeapObject::FromAddress(previous); + EXPECT_TRUE(IsFreeSpaceOrFiller(filler)); + + // Trim 10 times by one, two, and three word. + for (uint32_t i = 1; i <= 3; i++) { + for (int j = 0; j < 10; j++) { + previous -= kTaggedSize * i; + const uint32_t old_capacity = array->capacity().value(); + EXPECT_GE(old_capacity, i); + const uint32_t new_capacity = old_capacity - i; + isolate->heap()->RightTrimArray(*array, new_capacity, old_capacity); + filler = HeapObject::FromAddress(previous); + EXPECT_TRUE(IsFreeSpaceOrFiller(filler)); + EXPECT_TRUE(marking_state->IsUnmarked(filler)); + } + } + + InvokeAtomicMajorGC(); +} + +TEST_F(HeapTest, RightTrimFixedArrayWithBlackAllocatedPages) { + if (!v8_flags.black_allocated_pages) return; + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Heap* heap = this->heap(); + Isolate* isolate = i_isolate(); + InvokeMajorGC(); + + IncrementalMarking* marking = heap->incremental_marking(); + if (heap->sweeping_in_progress()) { + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking()); + EXPECT_TRUE(marking->black_allocation()); + + // Ensure that we allocate a new page, set up a bump pointer area, and + // perform the allocation in a black area. + SimulateFullSpace(heap->old_space()); + isolate->factory()->NewFixedArray(10, AllocationType::kOld); + + // Allocate the fixed array that will be trimmed later. + DirectHandle<FixedArray> array = + isolate->factory()->NewFixedArray(100, AllocationType::kOld); + Address start_address = array->address(); + Address end_address = start_address + array->Size(); + NormalPage* page = NormalPage::FromHeapObject(*array); + EXPECT_TRUE(page->is_black_allocated()); + EXPECT_TRUE(heap->old_space()->Contains(*array)); + + // Trim it once by one word, which shouldn't affect the BLACK_ALLOCATED flag. + Address previous = end_address - kTaggedSize; + isolate->heap()->RightTrimArray(*array, 99, 100); + + Tagged<HeapObject> filler = HeapObject::FromAddress(previous); + EXPECT_TRUE(IsFreeSpaceOrFiller(filler)); + EXPECT_TRUE(page->is_black_allocated()); + + InvokeAtomicMajorGC(); + EXPECT_FALSE(NormalPage::FromHeapObject(*array)->is_black_allocated()); + + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + + // Allocate the large fixed array that will be trimmed later. + array = isolate->factory()->NewFixedArray(200000, AllocationType::kOld); + EXPECT_TRUE(heap->lo_space()->Contains(*array)); + EXPECT_FALSE(BasePage::FromHeapObject(*array)->is_black_allocated()); + + InvokeAtomicMajorGC(); + EXPECT_FALSE(BasePage::FromHeapObject(*array)->is_black_allocated()); +} + +TEST_F(HeapTest, Regress618958) { + if (!v8_flags.incremental_marking) return; + v8::HandleScope scope(v8_isolate()); + Heap* heap = this->heap(); + bool isolate_is_locked = true; + v8::ExternalMemoryAccounter accounter; + accounter.Increase(v8_isolate(), 100 * MB); + int mark_sweep_count_before = heap->ms_count(); + heap->MemoryPressureNotification(MemoryPressureLevel::kCritical, + isolate_is_locked); + int mark_sweep_count_after = heap->ms_count(); + int mark_sweeps_performed = mark_sweep_count_after - mark_sweep_count_before; + // The memory pressuer handler either performed two GCs or performed one and + // started incremental marking. + EXPECT_TRUE(mark_sweeps_performed == 2 || + (mark_sweeps_performed == 1 && + !heap->incremental_marking()->IsStopped())); + accounter.Decrease(v8_isolate(), 100 * MB); +} + +TEST_F(HeapTest, YoungGenerationLargeObjectAllocationScavenge) { + if (v8_flags.minor_ms) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + if (!isolate->serializer_enabled()) return; + + DirectHandle<FixedArray> array_small = + isolate->factory()->NewFixedArray(200000); + MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array_small); + BasePage* metadata = chunk->Metadata(isolate); + EXPECT_EQ(NEW_LO_SPACE, SbxCast<MutablePage>(metadata)->owner_identity()); + EXPECT_TRUE(metadata->is_large()); + EXPECT_TRUE(chunk->IsToPage()); + + DirectHandle<Object> number = isolate->factory()->NewHeapNumber(123.456); + array_small->set(0, *number); + + InvokeMinorGC(); + + // After the first young generation GC array_small will be in the old + // generation large object space. + chunk = MemoryChunk::FromHeapObject(*array_small); + EXPECT_EQ(LO_SPACE, + SbxCast<MutablePage>(chunk->Metadata())->owner_identity()); + EXPECT_FALSE(chunk->InYoungGeneration()); + + InvokeMemoryReducingMajorGCs(); +} + +TEST_F(HeapTest, YoungGenerationLargeObjectAllocationMarkCompact) { + if (v8_flags.minor_ms) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + if (!isolate->serializer_enabled()) return; + + DirectHandle<FixedArray> array_small = + isolate->factory()->NewFixedArray(200000); + MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array_small); + BasePage* metadata = chunk->Metadata(isolate); + EXPECT_EQ(NEW_LO_SPACE, SbxCast<MutablePage>(metadata)->owner_identity()); + EXPECT_TRUE(metadata->is_large()); + EXPECT_TRUE(chunk->IsToPage()); + + DirectHandle<Object> number = isolate->factory()->NewHeapNumber(123.456); + array_small->set(0, *number); + + InvokeMajorGC(); + + // After the first full GC array_small will be in the old generation + // large object space. + chunk = MemoryChunk::FromHeapObject(*array_small); + EXPECT_EQ(LO_SPACE, + SbxCast<MutablePage>(chunk->Metadata())->owner_identity()); + EXPECT_FALSE(chunk->InYoungGeneration()); + + InvokeMemoryReducingMajorGCs(); +} + +TEST_F(HeapTest, YoungGenerationLargeObjectAllocationReleaseScavenger) { + if (v8_flags.minor_ms) return; + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + if (!isolate->serializer_enabled()) return; + + { + HandleScope new_scope(isolate); + for (int i = 0; i < 10; i++) { + DirectHandle<FixedArray> array_small = + isolate->factory()->NewFixedArray(20000); + MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array_small); + EXPECT_EQ(NEW_LO_SPACE, + SbxCast<MutablePage>(chunk->Metadata())->owner_identity()); + EXPECT_TRUE(chunk->IsToPage()); + } + } + + InvokeMinorGC(); + EXPECT_TRUE(isolate->heap()->new_lo_space()->IsEmpty()); + EXPECT_EQ(0u, isolate->heap()->new_lo_space()->Size()); + EXPECT_EQ(0u, isolate->heap()->new_lo_space()->SizeOfObjects()); + EXPECT_TRUE(isolate->heap()->lo_space()->IsEmpty()); + EXPECT_EQ(0u, isolate->heap()->lo_space()->Size()); + EXPECT_EQ(0u, isolate->heap()->lo_space()->SizeOfObjects()); +} + +TEST_F(HeapTest, UncommitUnusedLargeObjectMemory) { + v8::HandleScope scope(v8_isolate()); + Isolate* isolate = i_isolate(); + + DirectHandle<FixedArray> array = + isolate->factory()->NewFixedArray(200000, AllocationType::kOld); + MemoryChunk* chunk = MemoryChunk::FromHeapObject(*array); + MutablePage* page = SbxCast<MutablePage>(chunk->Metadata()); + EXPECT_EQ(page->owner_identity(), LO_SPACE); + + intptr_t size_before = array->Size(); + size_t committed_memory_before = page->CommittedPhysicalMemory(); + + array->RightTrim(isolate, 1); + EXPECT_LT(array->Size(), size_before); + + InvokeMajorGC(); + EXPECT_LT(page->CommittedPhysicalMemory(), committed_memory_before); + size_t shrinked_size = RoundUp( + (array->address() - chunk->address()) + array->Size(), CommitPageSize()); + EXPECT_EQ(shrinked_size, page->CommittedPhysicalMemory()); +} + +namespace { +struct OOMCallbackTracker { + static constexpr int kHeapLimit = 100 * MB; + static Isolate* oom_isolate; + static void Callback(const char* location, const OOMDetails&) { + Heap* heap = oom_isolate->heap(); + size_t kSlack = heap->new_space() ? heap->MaxSemiSpaceSize() : 0; + CHECK_LE(heap->OldGenerationCapacity(), kHeapLimit + kSlack); + base::OS::PrintError("Reached OOM callback.\n"); + base::OS::Abort(); + } +}; + +Isolate* OOMCallbackTracker::oom_isolate = nullptr; + +// The bodies of the OutOfMemory* death tests below are kept in separate +// functions instead of being passed to ASSERT_DEATH_IF_SUPPORTED directly: +// macros expanded inside the death test statement (e.g. CHECK_*) can introduce +// top-level commas, which the nested ASSERT_DEATH expansion would treat as +// argument separators. + +void RunOutOfMemory() { + v8_flags.max_old_space_size = OOMCallbackTracker::kHeapLimit / MB; + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + v8::Isolate::Scope isolate_scope(isolate); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + OOMCallbackTracker::oom_isolate = i_isolate; + isolate->SetOOMErrorHandler(OOMCallbackTracker::Callback); + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + Factory* factory = i_isolate->factory(); + HandleScope handle_scope(i_isolate); + while (true) { + factory->NewFixedArray(100); + } +} + +void RunOutOfMemoryIneffectiveGC() { + v8_flags.max_old_space_size = OOMCallbackTracker::kHeapLimit / MB; + // The test timeouts on some platforms with the default 95% heap size + // threshold. + v8_flags.ineffective_gc_size_threshold = 0.8; + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + OOMCallbackTracker::oom_isolate = i_isolate; + isolate->SetOOMErrorHandler(OOMCallbackTracker::Callback); + Factory* factory = i_isolate->factory(); + Heap* heap = i_isolate->heap(); + { + v8::Isolate::Scope isolate_scope(isolate); + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + std::vector<Handle<FixedArray>> arrays; + InvokeMajorGC(i_isolate); + + HandleScope scope(i_isolate); + const size_t heap_threshold = heap->MaxOldGenerationSize() * 0.8; + while (heap->OldGenerationSizeOfObjects() < heap_threshold) { + arrays.push_back(factory->NewFixedArray(1000, AllocationType::kOld)); + // This ensures OldGenerationSizeOfObjects() remains above the + // threshold even after a last resort GC. + if (heap->OldGenerationSizeOfObjects() >= heap_threshold) { + heap->CollectAllAvailableGarbage(GarbageCollectionReason::kLastResort); + } + } + { + int initial_ms_count = heap->ms_count(); + int ineffective_ms_start = initial_ms_count; + while (heap->ms_count() < initial_ms_count + 10) { + HandleScope inner_scope(i_isolate); + arrays.push_back(factory->NewFixedArray(30000, AllocationType::kOld)); + if (heap->tracer()->AverageMarkCompactMutatorUtilization() >= 0.3) { + ineffective_ms_start = heap->ms_count() + 1; + } + } + int consecutive_ineffective_ms = heap->ms_count() - ineffective_ms_start; + if (heap->tracer()->AverageMarkCompactMutatorUtilization() < 0.3) { + // The threshold for consecutive MC is 4, but + // CollectAllAvailableGarbage can run 2 cycles which counts as 1 + // "ineffective MC". + CHECK_LE(consecutive_ineffective_ms, 8); + } + } + } + isolate->Dispose(); + base::OS::PrintError("Reached end of test.\n"); + base::OS::Abort(); +} + +void RunOutOfMemoryIneffectiveGCRunningJS() { + v8_flags.max_old_space_size = 10; + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + OOMCallbackTracker::oom_isolate = i_isolate; + + isolate->SetOOMErrorHandler(OOMCallbackTracker::Callback); + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + context->Enter(); + + // Test that source positions are not collected as part of a failing + // GC, which will fail as allocation is disallowed. If the test works, + // this should call OOMCallback and terminate without crashing. + USE(v8::Script::Compile(context, + v8::String::NewFromUtf8Literal(isolate, R"javascript( + var array = []; + for(var i = 20000; i < 40000; ++i) { + array.push(new Array(i)); + } + )javascript")) + .ToLocalChecked() + ->Run(context)); + + FATAL("Should not get here as OOMCallback should be called"); +} +} // namespace + +TEST_F(TestWithPlatform, OutOfMemory) { + if (v8_flags.stress_incremental_marking) return; +#ifdef VERIFY_HEAP + if (v8_flags.verify_heap) return; +#endif + ASSERT_DEATH_IF_SUPPORTED(RunOutOfMemory(), "Reached OOM callback."); +} + +TEST_F(TestWithPlatform, OutOfMemoryIneffectiveGC) { + if (!v8_flags.detect_ineffective_gcs_near_heap_limit) return; + if (v8_flags.stress_incremental_marking || + v8_flags.stress_concurrent_allocation) { + return; + } +#ifdef VERIFY_HEAP + if (v8_flags.verify_heap) return; +#endif + + // The test either terminates in the OOM callback once ineffective GCs are + // detected near the heap limit, or runs to completion if GCs remain + // effective enough. Both outcomes are valid. + ASSERT_DEATH_IF_SUPPORTED( + RunOutOfMemoryIneffectiveGC(), + ::testing::AnyOf(::testing::HasSubstr("Reached OOM callback."), + ::testing::HasSubstr("Reached end of test."))); +} + +TEST_F(TestWithPlatform, OutOfMemoryIneffectiveGCRunningJS) { + if (!v8_flags.detect_ineffective_gcs_near_heap_limit) return; + if (v8_flags.stress_incremental_marking) return; + + ASSERT_DEATH_IF_SUPPORTED(RunOutOfMemoryIneffectiveGCRunningJS(), + "Reached OOM callback."); +} + +TEST_F(TestWithHeapInternals, Regress779503) { + // The following regression test ensures that the Scavenger does not allocate + // over invalid slots. More specific, the Scavenger should not sweep a page + // that it currently processes because it might allocate over the currently + // processed slot. + if (v8_flags.single_generation) return; + const uint32_t kArraySize = 2048; + ManualGCScope manual_gc_scope(i_isolate()); + Isolate* isolate = i_isolate(); + SealCurrentObjects(); + { + HandleScope handle_scope(isolate); + // The byte array filled with kHeapObjectTag ensures that we cannot read + // from the slot again and interpret it as heap value. Doing so will crash. + DirectHandle<ByteArray> byte_array = + isolate->factory()->NewByteArray(kArraySize); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*byte_array)); + for (uint32_t i = 0; i < kArraySize; i++) { + byte_array->set(i, kHeapObjectTag); + } + + { + HandleScope new_scope(isolate); + // The FixedArray in old space serves as space for slots. + DirectHandle<FixedArray> fixed_array = + isolate->factory()->NewFixedArray(kArraySize, AllocationType::kOld); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*fixed_array)); + for (uint32_t i = 0; i < kArraySize; i++) { + fixed_array->set(i, *byte_array); + } + } + // Delay sweeper tasks to allow the scavenger to sweep the page it is + // currently scavenging. + SetDelaySweeperTasksForTesting(true); + InvokeMajorGC(); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*byte_array)); + } + // Scavenging and sweeping the same page will crash as slots will be + // overridden. + InvokeMinorGC(); + SetDelaySweeperTasksForTesting(false); +} + +namespace { +struct OutOfMemoryState { + Heap* heap; + bool oom_triggered; + size_t old_generation_capacity_at_oom; + size_t memory_allocator_size_at_oom; + size_t new_space_capacity_at_oom; + size_t new_lo_space_size_at_oom; + size_t current_heap_limit; + size_t initial_heap_limit; + + static size_t NearHeapLimitCallback(void* raw_state, + size_t current_heap_limit, + size_t initial_heap_limit) { + OutOfMemoryState* state = static_cast<OutOfMemoryState*>(raw_state); + Heap* heap = state->heap; + state->oom_triggered = true; + state->old_generation_capacity_at_oom = heap->OldGenerationCapacity(); + state->memory_allocator_size_at_oom = heap->memory_allocator()->Size(); + state->new_space_capacity_at_oom = + heap->new_space() ? heap->new_space()->Capacity() : 0; + state->new_lo_space_size_at_oom = + heap->new_lo_space() ? heap->new_lo_space()->Size() : 0; + state->current_heap_limit = current_heap_limit; + state->initial_heap_limit = initial_heap_limit; + return initial_heap_limit + 100 * MB; + } + + static size_t MemoryAllocatorSizeFromHeapCapacity(size_t capacity) { + // Size to capacity factor. + double factor = NormalPage::kPageSize * 1.0 / + MemoryChunkLayout::AllocatableMemoryInDataPage(); + // Some tables (e.g. deoptimization table) are allocated directly with the + // memory allocator. Allow some slack to account for them. + size_t slack = 5 * MB; + return static_cast<size_t>(capacity * factor) + slack; + } +}; +} // namespace + +TEST_F(TestWithPlatform, OutOfMemorySmallObjects) { + if (v8_flags.stress_incremental_marking) return; +#ifdef VERIFY_HEAP + if (v8_flags.verify_heap) return; +#endif + const size_t kOldGenerationLimit = 50 * MB; + FLAG_VALUE_SCOPE(max_old_space_size, kOldGenerationLimit / MB); + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + Factory* factory = i_isolate->factory(); + OutOfMemoryState state; + state.heap = heap; + state.oom_triggered = false; + heap->AddNearHeapLimitCallback(OutOfMemoryState::NearHeapLimitCallback, + &state); + { + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + + v8::Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(i_isolate); + while (!state.oom_triggered) { + factory->NewFixedArray(100); + } + } + EXPECT_LE(state.old_generation_capacity_at_oom, + kOldGenerationLimit + heap->MaxSemiSpaceSize()); + EXPECT_LE(kOldGenerationLimit, + state.old_generation_capacity_at_oom + heap->MaxSemiSpaceSize()); + EXPECT_LE(state.memory_allocator_size_at_oom, + OutOfMemoryState::MemoryAllocatorSizeFromHeapCapacity( + state.old_generation_capacity_at_oom + + 2 * state.new_space_capacity_at_oom)); + isolate->Dispose(); +} + +TEST_F(TestWithPlatform, OutOfMemoryLargeObjects) { + if (v8_flags.stress_incremental_marking) return; +#ifdef VERIFY_HEAP + if (v8_flags.verify_heap) return; +#endif + const size_t kOldGenerationLimit = 50 * MB; + FLAG_VALUE_SCOPE(max_old_space_size, kOldGenerationLimit / MB); + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + Factory* factory = i_isolate->factory(); + OutOfMemoryState state; + state.heap = heap; + state.oom_triggered = false; + heap->AddNearHeapLimitCallback(OutOfMemoryState::NearHeapLimitCallback, + &state); + { + v8::Isolate::Scope isolate_scope(isolate); + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + const int kFixedArrayLength = 1000000; + { + HandleScope handle_scope(i_isolate); + while (!state.oom_triggered) { + factory->NewFixedArray(kFixedArrayLength); + } + } + EXPECT_LE(state.old_generation_capacity_at_oom, + kOldGenerationLimit + state.new_space_capacity_at_oom + + state.new_lo_space_size_at_oom + + FixedArray::SizeFor(kFixedArrayLength)); + EXPECT_LE(kOldGenerationLimit, state.old_generation_capacity_at_oom + + state.new_space_capacity_at_oom + + state.new_lo_space_size_at_oom + + FixedArray::SizeFor(kFixedArrayLength)); + EXPECT_LE(state.memory_allocator_size_at_oom, + OutOfMemoryState::MemoryAllocatorSizeFromHeapCapacity( + state.old_generation_capacity_at_oom + + 2 * state.new_space_capacity_at_oom + + state.new_lo_space_size_at_oom)); + } + isolate->Dispose(); +} + +TEST_F(TestWithPlatform, RestoreHeapLimit) { + if (v8_flags.stress_incremental_marking) return; +#ifdef VERIFY_HEAP + if (v8_flags.verify_heap) return; +#endif + ManualGCScope manual_gc_scope(nullptr); + const size_t kOldGenerationLimit = 50 * MB; + FLAG_VALUE_SCOPE(max_old_space_size, kOldGenerationLimit / MB); + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + Factory* factory = i_isolate->factory(); + + { + v8::Isolate::Scope isolate_scope(isolate); + PtrComprCageAccessScope ptr_compr_cage_access_scope(i_isolate); + + // In this test, we need to invoke GC without stack, otherwise some objects + // may not be reclaimed because of conservative stack scanning and the heap + // limit may be reached. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + + OutOfMemoryState state; + state.heap = heap; + state.oom_triggered = false; + heap->AddNearHeapLimitCallback(OutOfMemoryState::NearHeapLimitCallback, + &state); + heap->AutomaticallyRestoreInitialHeapLimit(0.5); + const int kFixedArrayLength = 1000000; + { + HandleScope handle_scope(i_isolate); + while (!state.oom_triggered) { + factory->NewFixedArray(kFixedArrayLength); + } + } + heap->MemoryPressureNotification(MemoryPressureLevel::kCritical, true); + state.oom_triggered = false; + { + HandleScope handle_scope(i_isolate); + while (!state.oom_triggered) { + factory->NewFixedArray(kFixedArrayLength); + } + } + EXPECT_EQ(state.current_heap_limit, state.initial_heap_limit); + } + + isolate->Dispose(); +} + +// The test only runs on 64-bit, because it simulates allocating ~9Gb +// external memory. +#if defined(V8_TARGET_ARCH_64_BIT) +namespace { +class DeleteNative { + public: + static constexpr ManagedTypeId kTypeID = ManagedTypeId::kTestDeleteNative; +}; +} // namespace + +TEST_F(HeapTest, Regress8014) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + { + HandleScope scope(isolate); + for (int i = 0; i < 10000; i++) { + auto handle = CppGCManaged<DeleteNative>::Create( + isolate, 1000000, std::make_shared<DeleteNative>()); + USE(handle); + } + } + int ms_count = heap->ms_count(); + heap->MemoryPressureNotification(MemoryPressureLevel::kCritical, true); + // Several GCs can be triggred by the above call. + // The bad case triggers 10000 GCs. + EXPECT_LE(heap->ms_count(), ms_count + 10); +} +#endif + +TEST_F(HeapTest, Regress8617) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + HandleScope scope(isolate); + SimulateFullSpace(heap->old_space()); + // Step 1. Create a function and ensure that it is in the old space. + DirectHandle<Object> foo = RunJS( + "function foo() { return 42; };" + "foo;"); + if (HeapLayout::InYoungGeneration(*foo)) { + EmptyNewSpaceUsingGC(); + } + // Step 2. Create an object with a reference to foo in the descriptor array. + RunJS( + "var obj = {};" + "obj.method = foo;" + "obj;"); + // Step 3. Make sure that foo moves during Mark-Compact. + NormalPage* ec_page = NormalPage::FromAddress((*foo).ptr()); + ForceEvacuationCandidate(ec_page); + // Step 4. Start incremental marking. + SimulateIncrementalMarking(false); + EXPECT_TRUE(ec_page->Chunk()->IsEvacuationCandidate()); + // Step 5. Install a new descriptor array on the map of the object. + // This runs the marking barrier for the descriptor array. + // In the bad case it sets the number of marked descriptors but does not + // change the color of the descriptor array. + RunJS("obj.bar = 10;"); + // Step 6. Promote the descriptor array to old space. During promotion + // the Scavenger will not record the slot of foo in the descriptor array. + EmptyNewSpaceUsingGC(); + // Step 7. Complete the Mark-Compact. + InvokeMajorGC(); + // Step 8. Use the descriptor for foo, which contains a stale pointer. + RunJS("obj.method()"); +} + +TEST_F(TestWithHeapInternals, MemoryReducerActivationForSmallHeaps) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + if (v8_flags.memory_reducer_limit_based) return; + ManualGCScope manual_gc_scope(i_isolate()); + EXPECT_EQ(MemoryReducerStateId(), MemoryReducer::kUninit); + v8::HandleScope handle_scope(v8_isolate()); + v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(context); + const size_t kActivationThreshold = 1 * MB; + size_t initial_capacity = heap()->OldGenerationCapacity(); + while (heap()->OldGenerationCapacity() < + initial_capacity + kActivationThreshold) { + factory()->NewFixedArray(1 * KB, AllocationType::kOld); + } + EXPECT_EQ(MemoryReducerStateId(), MemoryReducer::kWait); +} + +TEST_F(TestWithHeapInternals, AllocateExternalBackingStore) { + ManualGCScope manual_gc_scope(i_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + int initial_ms_count = heap->ms_count(); + void* result = + heap->AllocateExternalBackingStore([](size_t) { return nullptr; }, 10); + EXPECT_EQ(nullptr, result); + // At least two GCs should happen. + EXPECT_LE(2, heap->ms_count() - initial_ms_count); +} + +namespace { +DirectHandle<InstructionStream> DummyOptimizedCode( + Isolate* isolate, CodeKind kind = CodeKind::TURBOFAN_JS) { + uint8_t buffer[Assembler::kDefaultBufferSize]; + MacroAssembler masm(isolate, CodeObjectRequired{true}, + ExternalAssemblerBuffer(buffer, sizeof(buffer))); + CodeDesc desc; +#if V8_TARGET_ARCH_ARM64 + UseScratchRegisterScope temps(&masm); + Register tmp = temps.AcquireX(); + masm.Mov(tmp, Operand(isolate->factory()->undefined_value())); + masm.Push(tmp, tmp); +#else + masm.Push(isolate->factory()->undefined_value()); + masm.Push(isolate->factory()->undefined_value()); +#endif + masm.Drop(2); + masm.GetCode(isolate, &desc); + Factory::CodeBuilder builder(isolate, desc, kind); + builder.set_self_reference(masm.CodeObject()) + .set_empty_source_position_table(); + if (CodeKindUsesDeoptimizationData(kind)) { + builder.set_deoptimization_data(DeoptimizationData::Empty(isolate)); + } + DirectHandle<InstructionStream> code(builder.Build()->instruction_stream(), + isolate); + EXPECT_TRUE(IsInstructionStream(*code)); + return code; +} +} // namespace + +TEST_F(HeapTest, CodeObjectRegistry) { + // We turn off compaction to ensure that code is not moving. + v8_flags.compact = false; + + Isolate* isolate = i_isolate(); + + DirectHandle<InstructionStream> code1; + HandleScope outer_scope(isolate); + Address code2_address; + { + // Ensure that both code objects end up on the same page. + EXPECT_TRUE( + heap()->allocator()->code_space_allocator()->EnsureAllocationForTesting( + MemoryChunkLayout::MaxRegularCodeObjectSize(), + AllocationAlignment::kTaggedAligned, AllocationOrigin::kRuntime)); + code1 = DummyOptimizedCode(isolate); + DirectHandle<InstructionStream> code2 = DummyOptimizedCode(isolate); + code2_address = code2->address(); + + EXPECT_EQ(MutablePage::FromHeapObject(isolate, *code1), + MutablePage::FromHeapObject(isolate, *code2)); + EXPECT_TRUE(MutablePage::FromHeapObject(isolate, *code1) + ->Contains(code1->address())); + EXPECT_TRUE(MutablePage::FromHeapObject(isolate, *code2) + ->Contains(code2->address())); + } + InvokeMemoryReducingMajorGCs(); + EXPECT_TRUE( + MutablePage::FromHeapObject(isolate, *code1)->Contains(code1->address())); + EXPECT_TRUE(MutablePage::FromAddress(isolate, code2_address) + ->Contains(code2_address)); +} + +TEST_F(TestWithHeapInternals, Regress9701) { + ManualGCScope manual_gc_scope(i_isolate()); + if (!v8_flags.incremental_marking) return; + v8::HandleScope handle_scope(v8_isolate()); + v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(context); + // Start with an empty new space. + InvokeMinorGC(); + + int mark_sweep_count_before = heap()->ms_count(); + // Allocate many short living array buffers. + for (int i = 0; i < 1000; i++) { + HandleScope scope(i_isolate()); + i_isolate()->factory()->NewJSArrayBufferAndBackingStore( + 64 * KB, InitializedFlag{true}); + } + int mark_sweep_count_after = heap()->ms_count(); + // We expect only scavenges, no full GCs. + EXPECT_EQ(mark_sweep_count_before, mark_sweep_count_after); +} + +#if defined(V8_TARGET_ARCH_64_BIT) && !defined(V8_OS_ANDROID) +TEST_F(TestWithPlatform, HugeHeapLimit) { + uint64_t kMemoryGB = 16; + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + create_params.constraints.ConfigureDefaults(kMemoryGB * GB, kMemoryGB * GB); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); +#ifdef V8_COMPRESS_POINTERS + size_t kExpectedHeapLimit = Heap::kAllocatorLimitOnMaxOldGenerationSize; +#else + size_t kExpectedHeapLimit = size_t{4} * GB; +#endif + EXPECT_EQ(kExpectedHeapLimit, i_isolate->heap()->MaxOldGenerationSize()); + EXPECT_LT(size_t{3} * GB, i_isolate->heap()->MaxOldGenerationSize()); + isolate->Dispose(); +} +#endif + +TEST_F(TestWithPlatform, HeapLimit) { + uint64_t kMemoryGB = 16; + FLAG_VALUE_SCOPE(high_end_android_physical_memory_threshold, + static_cast<unsigned int>(kMemoryGB)); + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + create_params.constraints.ConfigureDefaults(kMemoryGB * GB, kMemoryGB * GB); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); +#if defined(V8_TARGET_ARCH_64_BIT) + // Because we explicitly set --high_end_android_physical_memory_threshold, + // Android has the same expected heap limit. + size_t kExpectedHeapLimit = size_t{4} * GB; +#else + size_t kExpectedHeapLimit = size_t{1} * GB; +#endif + EXPECT_EQ(kExpectedHeapLimit, i_isolate->heap()->MaxOldGenerationSize()); + isolate->Dispose(); +} + +TEST_F(HeapTest, NoCodeRangeInJitlessMode) { + if (!v8_flags.jitless) return; + EXPECT_TRUE(i_isolate()->heap()->code_region().is_empty()); +} + +TEST_F(TestWithHeapInternals, GarbageCollectionWithLocalHeap) { + ManualGCScope manual_gc_scope(i_isolate()); + + LocalHeap* local_heap = i_isolate()->main_thread_local_heap(); + + InvokeMajorGC(); + local_heap->ExecuteWhileParked([]() { /* nothing */ }); + InvokeMajorGC(); +} + +TEST_F(HeapTest, Regress10698) { + if (!v8_flags.incremental_marking) return; + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + HandleScope handle_scope(isolate); + // This is modeled after the manual allocation folding of heap numbers in + // JSON parser (See commit ba7b25e). + // Step 1. Allocate a byte array in the old space. + DirectHandle<ByteArray> array = + factory->NewByteArray(kTaggedSize, AllocationType::kOld); + // Step 2. Start incremental marking. + SimulateIncrementalMarking(false); + // Step 3. Allocate another byte array. It will be black. + factory->NewByteArray(kTaggedSize, AllocationType::kOld); + Address address = reinterpret_cast<Address>(array->begin()); + Tagged<HeapObject> filler = HeapObject::FromAddress(address); + // Step 4. Set the filler at the end of the first array. + // It will have an impossible markbit pattern because the second markbit + // will be taken from the second array. + filler->set_map_after_allocation(isolate, *factory->one_pointer_filler_map()); +} + +namespace { +class TestAllocationTracker : public HeapObjectAllocationTracker { + public: + explicit TestAllocationTracker(int expected_size) + : expected_size_(expected_size) {} + void AllocationEvent(Address addr, int size) override { + EXPECT_EQ(size, expected_size_); + address_ = addr; + } + Address address() const { return address_; } + + private: + int expected_size_; + Address address_ = kNullAddress; +}; +} // namespace + +TEST_F(HeapTest, CodeLargeObjectSpace) { + Heap* heap = this->heap(); + int size_in_bytes = + heap->MaxRegularHeapObjectSize(AllocationType::kCode) + kTaggedSize; + TestAllocationTracker allocation_tracker{size_in_bytes}; + heap->AddHeapObjectAllocationTracker(&allocation_tracker); + + Tagged<HeapObject> obj; + { + AllocationResult allocation = heap->allocator()->AllocateRaw( + size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime); + EXPECT_TRUE(allocation.To(&obj)); + EXPECT_EQ(allocation.ToAddress(), allocation_tracker.address()); + ThreadIsolation::RegisterInstructionStreamAllocation(obj.address(), + size_in_bytes); + + heap->CreateFillerObjectAt(obj.address(), size_in_bytes); + } + + EXPECT_TRUE(HeapLayout::InAnyLargeSpace(obj)); + heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); +} + +TEST_F(TestWithPlatform, CodeLargeObjectSpace64k) { + // Simulate having a system with 64k OS pages. + FLAG_VALUE_SCOPE(v8_os_page_size, 64); + + // Initialize the isolate manually to make sure --v8-os-page-size is taken + // into account. + v8::Isolate::CreateParams create_params; + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Heap* heap = i_isolate->heap(); + + // Allocate a regular code object. + { + v8::Isolate::Scope isolate_scope(isolate); + int size_in_bytes = + heap->MaxRegularHeapObjectSize(AllocationType::kCode) - kTaggedSize; + TestAllocationTracker allocation_tracker{size_in_bytes}; + heap->AddHeapObjectAllocationTracker(&allocation_tracker); + + Tagged<HeapObject> obj; + { + AllocationResult allocation = heap->allocator()->AllocateRaw( + size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime); + EXPECT_TRUE(allocation.To(&obj)); + EXPECT_EQ(allocation.ToAddress(), allocation_tracker.address()); + ThreadIsolation::RegisterInstructionStreamAllocation(obj.address(), + size_in_bytes); + + heap->CreateFillerObjectAt(obj.address(), size_in_bytes); + } + + EXPECT_FALSE(HeapLayout::InAnyLargeSpace(obj)); + heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); + } + + // Allocate a large code object. + { + v8::Isolate::Scope isolate_scope(isolate); + int size_in_bytes = + heap->MaxRegularHeapObjectSize(AllocationType::kCode) + kTaggedSize; + TestAllocationTracker allocation_tracker{size_in_bytes}; + heap->AddHeapObjectAllocationTracker(&allocation_tracker); + + Tagged<HeapObject> obj; + { + AllocationResult allocation = heap->allocator()->AllocateRaw( + size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime); + EXPECT_TRUE(allocation.To(&obj)); + EXPECT_EQ(allocation.ToAddress(), allocation_tracker.address()); + ThreadIsolation::RegisterInstructionStreamAllocation(obj.address(), + size_in_bytes); + + heap->CreateFillerObjectAt(obj.address(), size_in_bytes); + } + + EXPECT_TRUE(HeapLayout::InAnyLargeSpace(obj)); + heap->RemoveHeapObjectAllocationTracker(&allocation_tracker); + } + + isolate->Dispose(); +} + +TEST_F(HeapTest, IsPendingAllocationNewSpace) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + HandleScope handle_scope(isolate); + DirectHandle<FixedArray> object = + factory->NewFixedArray(5, AllocationType::kYoung); + EXPECT_TRUE(heap->IsPendingAllocation(*object)); + heap->PublishMainThreadPendingAllocations(); + EXPECT_FALSE(heap->IsPendingAllocation(*object)); +} + +TEST_F(HeapTest, IsPendingAllocationNewLOSpace) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + HandleScope handle_scope(isolate); + DirectHandle<FixedArray> object = factory->NewFixedArray( + FixedArray::kMaxRegularLength + 1, AllocationType::kYoung); + EXPECT_TRUE(heap->IsPendingAllocation(*object)); + heap->PublishMainThreadPendingAllocations(); + EXPECT_FALSE(heap->IsPendingAllocation(*object)); +} + +TEST_F(HeapTest, IsPendingAllocationOldSpace) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + HandleScope handle_scope(isolate); + DirectHandle<FixedArray> object = + factory->NewFixedArray(5, AllocationType::kOld); + EXPECT_TRUE(heap->IsPendingAllocation(*object)); + heap->PublishMainThreadPendingAllocations(); + EXPECT_FALSE(heap->IsPendingAllocation(*object)); +} + +TEST_F(HeapTest, IsPendingAllocationLOSpace) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + HandleScope handle_scope(isolate); + DirectHandle<FixedArray> object = factory->NewFixedArray( + FixedArray::kMaxRegularLength + 1, AllocationType::kOld); + EXPECT_TRUE(heap->IsPendingAllocation(*object)); + heap->PublishMainThreadPendingAllocations(); + EXPECT_FALSE(heap->IsPendingAllocation(*object)); +} + +TEST_F(HeapTest, Regress10900) { + v8_flags.compact_on_every_full_gc = true; + Isolate* isolate = i_isolate(); + HandleScope handle_scope(isolate); + for (int i = 0; i < 100; i++) { + // Generate multiple code pages. + DummyOptimizedCode(isolate, CodeKind::FOR_TESTING); + } + // Force garbage collection that compacts code pages and triggers + // an assertion in Isolate::AddCodeMemoryRange before the bug fix. + InvokeMemoryReducingMajorGCs(); +} + +namespace { +v8::Local<v8::Value> GenerateGarbage(HeapTest* test) { + return Utils::ToLocal(test->RunJS( + "let roots = []; for (let i = 0; i < 100; i++) roots.push(new " + "Array(1000).fill(0)); roots.push(new Array(1000000).fill(0)); " + "roots;")); +} +} // namespace + +TEST_F(HeapTest, Regress11181) { + v8_flags.compact_on_every_full_gc = true; + unsigned int prev_runtime_stats = TracingFlags::runtime_stats.exchange( + v8::tracing::TracingCategoryObserver::ENABLED_BY_NATIVE, + std::memory_order_relaxed); + v8::HandleScope scope(v8_isolate()); + GenerateGarbage(this); + InvokeMemoryReducingMajorGCs(); + TracingFlags::runtime_stats.store(prev_runtime_stats, + std::memory_order_relaxed); +} + +TEST_F(HeapTest, LongTaskStatsFullAtomic) { + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope scope(v8_isolate()); + GenerateGarbage(this); + v8::metrics::LongTaskStats::Reset(isolate); + EXPECT_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) + .gc_full_atomic_wall_clock_duration_us); + for (int i = 0; i < 10; ++i) { + InvokeMemoryReducingMajorGCs(); + } + EXPECT_LT(0u, v8::metrics::LongTaskStats::Get(isolate) + .gc_full_atomic_wall_clock_duration_us); + v8::metrics::LongTaskStats::Reset(isolate); + EXPECT_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) + .gc_full_atomic_wall_clock_duration_us); +} + +TEST_F(HeapTest, LongTaskStatsFullIncremental) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope scope(v8_isolate()); + v8::Global<v8::Value> objects(isolate, GenerateGarbage(this)); + v8::metrics::LongTaskStats::Reset(isolate); + EXPECT_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) + .gc_full_incremental_wall_clock_duration_us); + for (int i = 0; i < 10; ++i) { + SimulateIncrementalMarking(); + InvokeMemoryReducingMajorGCs(); + } + EXPECT_LT(0u, v8::metrics::LongTaskStats::Get(isolate) + .gc_full_incremental_wall_clock_duration_us); + v8::metrics::LongTaskStats::Reset(isolate); + EXPECT_EQ(0u, v8::metrics::LongTaskStats::Get(isolate) + .gc_full_incremental_wall_clock_duration_us); +} + +TEST_F(HeapTest, LongTaskStatsYoung) { + if (v8_flags.single_generation) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope scope(v8_isolate()); + GenerateGarbage(this); + v8::metrics::LongTaskStats::Reset(isolate); + EXPECT_EQ( + 0u, + v8::metrics::LongTaskStats::Get(isolate).gc_young_wall_clock_duration_us); + for (int i = 0; i < 10; ++i) { + InvokeMinorGC(); + } + EXPECT_LT( + 0u, + v8::metrics::LongTaskStats::Get(isolate).gc_young_wall_clock_duration_us); + v8::metrics::LongTaskStats::Reset(isolate); + EXPECT_EQ( + 0u, + v8::metrics::LongTaskStats::Get(isolate).gc_young_wall_clock_duration_us); +} + +namespace { + +DirectHandle<Object> TestAllocateAfterFailures(Isolate* isolate) { + // Similar to what the factory's retrying logic does in the last-resort case, + // we wrap the allocator function in an AlwaysAllocateScope. Test that + // all allocations succeed immediately without any retry. + Heap* heap = isolate->heap(); + InvokeMemoryReducingMajorGCs(isolate); + AlwaysAllocateScopeForTesting scope(heap); + int size = FixedArray::SizeFor(100); + // Young generation. + Tagged<HeapObject> obj = + HeapTest::AllocateRawForTest(heap, size, AllocationType::kYoung) + .ToObjectChecked(); + // In order to pass heap verification on Isolate teardown, mark the + // allocated area as a filler. + heap->CreateFillerObjectAt(obj.address(), size); + + // Old generation. + HeapTest::SimulateFullSpace(heap->old_space()); + obj = HeapTest::AllocateRawForTest(heap, size, AllocationType::kOld) + .ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), size); + + // Large object space. + static const size_t kLargeObjectSpaceFillerLength = + 3 * (NormalPage::kPageSize / 10); + static const size_t kLargeObjectSpaceFillerSize = + FixedArray::SizeFor(kLargeObjectSpaceFillerLength); + CHECK_GT(kLargeObjectSpaceFillerSize, + static_cast<size_t>(heap->old_space()->AreaSize())); + while (HeapTest::OldGenerationSpaceAvailable(heap) > + kLargeObjectSpaceFillerSize) { + obj = HeapTest::AllocateRawForTest( + heap, static_cast<int>(kLargeObjectSpaceFillerSize), + AllocationType::kOld) + .ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), size); + } + obj = HeapTest::AllocateRawForTest( + heap, static_cast<int>(kLargeObjectSpaceFillerSize), + AllocationType::kOld) + .ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), size); + + // Map space. + HeapTest::SimulateFullSpace(heap->old_space()); + obj = HeapTest::AllocateRawForTest(heap, Map::kSize, AllocationType::kMap) + .ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), Map::kSize); + + // Code space. + HeapTest::SimulateFullSpace(heap->code_space()); + size = isolate->builtins()->code(Builtin::kIllegal)->Size(); + obj = HeapTest::AllocateRawForTest(heap, size, AllocationType::kCode, + AllocationOrigin::kRuntime) + .ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), size); + return isolate->factory()->true_value(); +} + +void TestGetter(v8::Local<v8::Name> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + HandleScope scope(isolate); + info.GetReturnValue().Set( + v8::Utils::ToLocal(TestAllocateAfterFailures(isolate))); +} + +void TestSetter(v8::Local<v8::Name> name, v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<v8::Boolean>& info) { + UNREACHABLE(); +} + +DirectHandle<AccessorInfo> TestAccessorInfo(Isolate* isolate) { + DirectHandle<String> name = + isolate->factory()->NewStringFromStaticChars("get"); + return Accessors::MakeAccessor(isolate, name, &TestGetter, &TestSetter); +} + +} // namespace + +TEST_F(HeapTest, StressHandles) { + // For TestAllocateAfterFailures. + v8_flags.stress_concurrent_allocation = false; + v8::HandleScope scope(v8_isolate()); + DirectHandle<Object> o = TestAllocateAfterFailures(i_isolate()); + CHECK(IsTrue(*o)); +} + +TEST_F(HeapTest, StressJS) { + // For TestAllocateAfterFailures in TestGetter. + v8_flags.stress_concurrent_allocation = false; + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + v8::HandleScope scope(v8_isolate()); + + DirectHandle<NativeContext> context(isolate->native_context()); + DirectHandle<SharedFunctionInfo> info = + factory->NewSharedFunctionInfoForBuiltin( + factory->function_string(), Builtin::kEmptyFunction, 0, kDontAdapt); + info->set_language_mode(LanguageMode::kStrict); + DirectHandle<JSFunction> function = + Factory::JSFunctionBuilder{isolate, info, context}.Build(); + CHECK(!function->shared()->construct_as_builtin()); + + // Force the creation of an initial map. + factory->NewJSObject(function); + + // Patch the map to have an accessor for "get". + DirectHandle<Map> map(function->initial_map(), isolate); + DirectHandle<DescriptorArray> instance_descriptors( + map->instance_descriptors(), isolate); + CHECK_EQ(0, instance_descriptors->number_of_descriptors()); + + PropertyAttributes attrs = NONE; + DirectHandle<AccessorInfo> foreign = TestAccessorInfo(isolate); + Map::EnsureDescriptorSlack(isolate, map, 1); + + Descriptor d = Descriptor::AccessorConstant( + DirectHandle<Name>(Cast<Name>(foreign->name()), isolate), foreign, attrs); + map->AppendDescriptor(isolate, &d); + + // Add the Foo constructor to the global object. + SetGlobalProperty("Foo", v8::Utils::CallableToLocal(function)); + // Call the accessor through JavaScript. + v8::Local<v8::Value> result = TryRunJS("(new Foo).get").ToLocalChecked(); + CHECK_EQ(true, result->BooleanValue(v8_isolate())); } } // namespace internal diff --git a/deps/v8/test/unittests/heap/heap-utils.cc b/deps/v8/test/unittests/heap/heap-utils.cc index 13f8ea9afce8..684502330bab 100644 --- a/deps/v8/test/unittests/heap/heap-utils.cc +++ b/deps/v8/test/unittests/heap/heap-utils.cc @@ -9,21 +9,35 @@ #include "src/base/iterator.h" #include "src/common/globals.h" #include "src/flags/flags.h" +#include "src/heap/factory.h" #include "src/heap/gc-tracer-inl.h" #include "src/heap/heap-layout-inl.h" #include "src/heap/incremental-marking.h" #include "src/heap/main-allocator-inl.h" #include "src/heap/mark-compact.h" +#include "src/heap/marking-barrier.h" +#include "src/heap/memory-reducer.h" #include "src/heap/new-spaces.h" #include "src/heap/normal-page-inl.h" #include "src/heap/safepoint.h" #include "src/heap/spaces-inl.h" -#include "src/objects/fixed-primitive-array-inl.h" #include "src/objects/free-space-inl.h" namespace v8 { namespace internal { +void HeapInternalsBase::SetForceOOM(Heap* heap, bool value) { + heap->set_force_oom(value); +} + +void HeapInternalsBase::SetDelaySweeperTasksForTesting(Heap* heap, bool value) { + heap->delay_sweeper_tasks_for_testing_ = value; +} + +int HeapInternalsBase::MemoryReducerStateId(Heap* heap) { + return reinterpret_cast<MemoryReducer*>(heap->memory_reducer())->state_.id(); +} + size_t HeapInternalsBase::OldGenerationSpaceAvailable(Heap* heap) { return heap->OldGenerationSpaceAvailable(); } @@ -32,7 +46,7 @@ void HeapInternalsBase::SimulateIncrementalMarking(Heap* heap, bool force_completion) { static constexpr auto kStepSize = v8::base::TimeDelta::FromMilliseconds(100); CHECK(v8_flags.incremental_marking); - i::IncrementalMarking* marking = heap->incremental_marking(); + IncrementalMarking* marking = heap->incremental_marking(); if (heap->sweeping_in_progress()) { SafepointScope scope(heap->isolate(), @@ -41,25 +55,37 @@ void HeapInternalsBase::SimulateIncrementalMarking(Heap* heap, CompleteSweepingReason::kTesting); } + if (marking->IsMinorMarking()) { + // If minor incremental marking is running, we need to finalize it first + // because of the AdvanceForTesting call in this function which is currently + // only possible for MajorMC. + heap->CollectGarbage(NEW_SPACE, + GarbageCollectionReason::kFinalizeMinorMSForMajorGC); + } + if (marking->IsStopped()) { - heap->StartIncrementalMarking(i::GCFlag::kNoFlags, - i::GarbageCollectionReason::kTesting); + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); } CHECK(marking->IsMajorMarking()); if (!force_completion) return; + SafepointScope scope(heap->isolate(), kGlobalSafepointForSharedSpaceIsolate); + MarkingBarrier::PublishAll(heap); + marking->MarkRootsForTesting(); + while (!marking->IsMajorMarkingComplete()) { marking->AdvanceForTesting(kStepSize); } } -namespace { - int FixedArrayLenFromSize(int size) { return std::min({(size - OFFSET_OF_DATA_START(FixedArray)) / kTaggedSize, FixedArray::kMaxRegularLength}); } +namespace { + void FillPageInPagedSpace(NormalPage* page, std::vector<Handle<FixedArray>>* out_handles) { Heap* heap = page->heap(); @@ -154,8 +180,7 @@ void FillPageInPagedSpace(NormalPage* page, } // namespace void HeapInternalsBase::SimulateFullSpace( - v8::internal::NewSpace* new_space, - std::vector<Handle<FixedArray>>* out_handles) { + NewSpace* new_space, std::vector<Handle<FixedArray>>* out_handles) { Heap* heap = new_space->heap(); SafepointScope safepoint_scope(heap->isolate(), kGlobalSafepointForSharedSpaceIsolate); @@ -182,7 +207,7 @@ void HeapInternalsBase::SimulateFullSpace( } } -void HeapInternalsBase::SimulateFullSpace(v8::internal::PagedSpace* space) { +void HeapInternalsBase::SimulateFullSpace(PagedSpace* space) { Heap* heap = space->heap(); SafepointScope safepoint_scope(heap->isolate(), kGlobalSafepointForSharedSpaceIsolate); @@ -198,15 +223,17 @@ void HeapInternalsBase::SimulateFullSpace(v8::internal::PagedSpace* space) { } namespace { -std::vector<Handle<FixedArray>> CreatePadding(Heap* heap, int padding_size, - AllocationType allocation) { + +std::vector<Handle<FixedArray>> CreatePadding( + Heap* heap, int padding_size, AllocationType allocation, + int object_size = kMaxRegularHeapObjectSize) { std::vector<Handle<FixedArray>> handles; Isolate* isolate = heap->isolate(); int allocate_memory; int length; int free_memory = padding_size; heap->FreeMainThreadLinearAllocationAreas(); - if (allocation == i::AllocationType::kOld) { + if (allocation == AllocationType::kOld) { int overall_free_memory = static_cast<int>(heap->old_space()->Available()); CHECK(padding_size <= overall_free_memory || overall_free_memory == 0); } else { @@ -214,15 +241,15 @@ std::vector<Handle<FixedArray>> CreatePadding(Heap* heap, int padding_size, CHECK(padding_size <= overall_free_memory || overall_free_memory == 0); } while (free_memory > 0) { - if (free_memory > kMaxRegularHeapObjectSize) { - allocate_memory = kMaxRegularHeapObjectSize; + if (free_memory > object_size) { + allocate_memory = object_size; length = FixedArrayLenFromSize(allocate_memory); } else { allocate_memory = free_memory; length = FixedArrayLenFromSize(allocate_memory); if (length <= 0) { // Not enough room to create another FixedArray, so create a filler. - if (allocation == i::AllocationType::kOld) { + if (allocation == AllocationType::kOld) { LinearAllocationArea* old_space = &heap->isolate()->isolate_data()->old_allocation_info(); heap->CreateFillerObjectAt(old_space->top(), free_memory); @@ -242,11 +269,12 @@ std::vector<Handle<FixedArray>> CreatePadding(Heap* heap, int padding_size, v8_flags.single_generation); free_memory -= handles.back()->Size(); } + heap->FreeMainThreadLinearAllocationAreas(); return handles; } void FillCurrentSemiSpacePageButNBytes( - v8::internal::SemiSpaceNewSpace* space, int extra_bytes, + SemiSpaceNewSpace* space, int extra_bytes, std::vector<Handle<FixedArray>>* out_handles = nullptr) { // We cannot rely on `space->limit()` to point to the end of the current page // in the case where inline allocations are disabled, it actually points to @@ -260,37 +288,44 @@ void FillCurrentSemiSpacePageButNBytes( int new_linear_size = space_remaining - extra_bytes; if (new_linear_size == 0) return; std::vector<Handle<FixedArray>> handles = - CreatePadding(space->heap(), new_linear_size, i::AllocationType::kYoung); + CreatePadding(space->heap(), new_linear_size, AllocationType::kYoung); if (out_handles != nullptr) { out_handles->insert(out_handles->end(), handles.begin(), handles.end()); } } -void FillCurrentSemiSpacePage(v8::internal::SemiSpaceNewSpace* space, +void FillCurrentSemiSpacePage(SemiSpaceNewSpace* space, std::vector<Handle<FixedArray>>* out_handles) { FillCurrentSemiSpacePageButNBytes(space, 0, out_handles); } -void FillCurrentPagedSpacePage(v8::internal::NewSpace* space, +void FillCurrentPagedSpacePage(NewSpace* space, Address top, std::vector<Handle<FixedArray>>* out_handles) { - const Address top = space->heap()->NewSpaceTop(); if (top == kNullAddress) return; NormalPage* page = NormalPage::FromAllocationAreaAddress(top); space->heap()->EnsureSweepingCompleted( Heap::SweepingForcedFinalizationMode::kV8Only, CompleteSweepingReason::kTesting); + ManualGCScope manual_gc_scope(space->heap()->isolate()); + SafepointScope safepoint_scope(space->heap()->isolate(), + kGlobalSafepointForSharedSpaceIsolate); FillPageInPagedSpace(page, out_handles); } } // namespace +std::vector<Handle<FixedArray>> HeapInternalsBase::CreatePadding( + Heap* heap, int padding_size, AllocationType allocation, int object_size) { + return internal::CreatePadding(heap, padding_size, allocation, object_size); +} + void HeapInternalsBase::FillCurrentPage( - v8::internal::NewSpace* space, - std::vector<Handle<FixedArray>>* out_handles) { + NewSpace* space, std::vector<Handle<FixedArray>>* out_handles) { + const Address top = space->heap()->NewSpaceTop(); space->heap()->FreeMainThreadLinearAllocationAreas(); PauseAllocationObserversScope pause_observers(space->heap()); if (v8_flags.minor_ms) { - FillCurrentPagedSpacePage(space, out_handles); + FillCurrentPagedSpacePage(space, top, out_handles); } else { FillCurrentSemiSpacePage(SemiSpaceNewSpace::From(space), out_handles); } @@ -298,7 +333,7 @@ void HeapInternalsBase::FillCurrentPage( } void HeapInternalsBase::FillCurrentPageButNBytes( - v8::internal::SemiSpaceNewSpace* space, int extra_bytes, + SemiSpaceNewSpace* space, int extra_bytes, std::vector<Handle<FixedArray>>* out_handles) { space->heap()->FreeMainThreadLinearAllocationAreas(); PauseAllocationObserversScope pause_observers(space->heap()); @@ -307,8 +342,8 @@ void HeapInternalsBase::FillCurrentPageButNBytes( } bool IsNewObjectInCorrectGeneration(Tagged<HeapObject> object) { - return v8_flags.single_generation ? !i::HeapLayout::InYoungGeneration(object) - : i::HeapLayout::InYoungGeneration(object); + return v8_flags.single_generation ? !HeapLayout::InYoungGeneration(object) + : HeapLayout::InYoungGeneration(object); } ManualGCScope::ManualGCScope(Isolate* isolate) @@ -410,6 +445,14 @@ void ForceEvacuationCandidate(NormalPage* page) { page->owner()->heap()->FreeLinearAllocationAreas(); } +AllocationResult HeapInternalsBase::AllocateRawForTest( + Heap* heap, int size_in_bytes, AllocationType type, + AllocationOrigin origin) { + return heap->AllocateRaw(size_in_bytes, type, origin); +} + +// This is the same as Factory::NewByteArray, except it doesn't retry on +// allocation failure. AllocationResult HeapInternalsBase::AllocateByteArrayForTest( Heap* heap, uint32_t length, AllocationType allocation_type) { DCHECK_LE(length, ByteArray::kMaxLength); @@ -446,8 +489,18 @@ AllocationResult HeapInternalsBase::AllocateFixedArrayForTest( return AllocationResult::FromObject(array); } -void HeapInternalsBase::SetForceOOM(Heap* heap, bool value) { - heap->set_force_oom(value); +// This is the same as Factory::NewContextfulMapForCurrentContext, except it +// doesn't retry on allocation failure. +AllocationResult HeapInternalsBase::AllocateMapForTest(Isolate* isolate) { + Heap* heap = isolate->heap(); + Tagged<HeapObject> obj; + AllocationResult alloc = heap->AllocateRaw(Map::kSize, AllocationType::kMap); + if (!alloc.To(&obj)) return alloc; + ReadOnlyRoots roots(isolate); + obj->set_map_after_allocation(isolate, *isolate->meta_map()); + return AllocationResult::FromObject(isolate->factory()->InitializeMap( + Cast<Map>(obj), JS_OBJECT_TYPE, JSObject::kHeaderSize, + TERMINAL_FAST_ELEMENTS_KIND, 0, roots)); } } // namespace internal diff --git a/deps/v8/test/unittests/heap/heap-utils.h b/deps/v8/test/unittests/heap/heap-utils.h index 7e867ec19b4c..c5b4ac35ca03 100644 --- a/deps/v8/test/unittests/heap/heap-utils.h +++ b/deps/v8/test/unittests/heap/heap-utils.h @@ -20,38 +20,46 @@ class SemiSpaceNewSpace; class HeapInternalsBase { protected: - size_t OldGenerationSpaceAvailable(Heap* heap); - void SimulateIncrementalMarking(Heap* heap, bool force_completion); + static size_t OldGenerationSpaceAvailable(Heap* heap); + void SimulateIncrementalMarking(Heap* heap, bool force_completion = true); void SimulateFullSpace( - v8::internal::NewSpace* space, - std::vector<Handle<FixedArray>>* out_handles = nullptr); - void SimulateFullSpace(v8::internal::PagedSpace* space); - void FillCurrentPage(v8::internal::NewSpace* space, + NewSpace* space, std::vector<Handle<FixedArray>>* out_handles = nullptr); + static void SimulateFullSpace(PagedSpace* space); + void FillCurrentPage(NewSpace* space, std::vector<Handle<FixedArray>>* out_handles = nullptr); void FillCurrentPageButNBytes( - v8::internal::SemiSpaceNewSpace* space, int extra_bytes, + SemiSpaceNewSpace* space, int extra_bytes, std::vector<Handle<FixedArray>>* out_handles = nullptr); + static AllocationResult AllocateRawForTest( + Heap* heap, int size_in_bytes, AllocationType type, + AllocationOrigin origin = AllocationOrigin::kRuntime); AllocationResult AllocateByteArrayForTest(Heap* heap, uint32_t length, AllocationType allocation_type); AllocationResult AllocateFixedArrayForTest(Heap* heap, uint32_t length, AllocationType allocation); + AllocationResult AllocateMapForTest(Isolate* isolate); void SetForceOOM(Heap* heap, bool value); + void SetDelaySweeperTasksForTesting(Heap* heap, bool value); + int MemoryReducerStateId(Heap* heap); + std::vector<Handle<FixedArray>> CreatePadding( + Heap* heap, int padding_size, AllocationType allocation, + int object_size = kMaxRegularHeapObjectSize); }; -inline void InvokeMajorGC(i::Isolate* isolate) { +inline void InvokeMajorGC(Isolate* isolate) { isolate->heap()->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting); } -inline void InvokeMajorGC(i::Isolate* isolate, GCFlag gc_flag) { +inline void InvokeMajorGC(Isolate* isolate, GCFlag gc_flag) { isolate->heap()->CollectAllGarbage(gc_flag, GarbageCollectionReason::kTesting); } -inline void InvokeMinorGC(i::Isolate* isolate) { +inline void InvokeMinorGC(Isolate* isolate) { isolate->heap()->CollectGarbage(NEW_SPACE, GarbageCollectionReason::kTesting); } -inline void InvokeAtomicMajorGC(i::Isolate* isolate) { +inline void InvokeAtomicMajorGC(Isolate* isolate) { Heap* heap = isolate->heap(); heap->PreciseCollectAllGarbage(GCFlag::kNoFlags, GarbageCollectionReason::kTesting); @@ -62,7 +70,7 @@ inline void InvokeAtomicMajorGC(i::Isolate* isolate) { } } -inline void InvokeAtomicMinorGC(i::Isolate* isolate) { +inline void InvokeAtomicMinorGC(Isolate* isolate) { InvokeMinorGC(isolate); Heap* heap = isolate->heap(); if (heap->sweeping_in_progress()) { @@ -72,7 +80,7 @@ inline void InvokeAtomicMinorGC(i::Isolate* isolate) { } } -inline void InvokeMemoryReducingMajorGCs(i::Isolate* isolate) { +inline void InvokeMemoryReducingMajorGCs(Isolate* isolate) { isolate->heap()->CollectAllAvailableGarbage( GarbageCollectionReason::kTesting); } @@ -84,20 +92,24 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { WithHeapInternals(const WithHeapInternals&) = delete; WithHeapInternals& operator=(const WithHeapInternals&) = delete; - void InvokeMajorGC() { i::InvokeMajorGC(this->i_isolate()); } + void InvokeMajorGC() { internal::InvokeMajorGC(this->i_isolate()); } void InvokeMajorGC(GCFlag gc_flag) { - i::InvokeMajorGC(this->i_isolate(), gc_flag); + internal::InvokeMajorGC(this->i_isolate(), gc_flag); } - void InvokeMinorGC() { i::InvokeMinorGC(this->i_isolate()); } + void InvokeMinorGC() { internal::InvokeMinorGC(this->i_isolate()); } - void InvokeAtomicMajorGC() { i::InvokeAtomicMajorGC(this->i_isolate()); } + void InvokeAtomicMajorGC() { + internal::InvokeAtomicMajorGC(this->i_isolate()); + } - void InvokeAtomicMinorGC() { i::InvokeAtomicMinorGC(this->i_isolate()); } + void InvokeAtomicMinorGC() { + internal::InvokeAtomicMinorGC(this->i_isolate()); + } void InvokeMemoryReducingMajorGCs() { - i::InvokeMemoryReducingMajorGCs(this->i_isolate()); + internal::InvokeMemoryReducingMajorGCs(this->i_isolate()); } void PreciseCollectAllGarbage() { @@ -107,31 +119,44 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { Heap* heap() const { return this->i_isolate()->heap(); } + using HeapInternalsBase::OldGenerationSpaceAvailable; size_t OldGenerationSpaceAvailable() { return HeapInternalsBase::OldGenerationSpaceAvailable(heap()); } + using HeapInternalsBase::SimulateIncrementalMarking; void SimulateIncrementalMarking(bool force_completion = true) { return HeapInternalsBase::SimulateIncrementalMarking(heap(), force_completion); } void SimulateFullSpace( - v8::internal::NewSpace* space, - std::vector<Handle<FixedArray>>* out_handles = nullptr) { + NewSpace* space, std::vector<Handle<FixedArray>>* out_handles = nullptr) { return HeapInternalsBase::SimulateFullSpace(space, out_handles); } - void SimulateFullSpace(v8::internal::PagedSpace* space) { + static void SimulateFullSpace(PagedSpace* space) { return HeapInternalsBase::SimulateFullSpace(space); } + void FillCurrentPage(NewSpace* space, + std::vector<Handle<FixedArray>>* out_handles = nullptr) { + return HeapInternalsBase::FillCurrentPage(space, out_handles); + } + void FillCurrentPageButNBytes( - v8::internal::SemiSpaceNewSpace* space, int extra_bytes, + SemiSpaceNewSpace* space, int extra_bytes, std::vector<Handle<FixedArray>>* out_handles = nullptr) { return HeapInternalsBase::FillCurrentPageButNBytes(space, extra_bytes, out_handles); } + using HeapInternalsBase::AllocateRawForTest; + AllocationResult AllocateRawForTest( + int size_in_bytes, AllocationType type, + AllocationOrigin origin = AllocationOrigin::kRuntime) { + return HeapInternalsBase::AllocateRawForTest(heap(), size_in_bytes, type, + origin); + } AllocationResult AllocateByteArrayForTest(Heap* heap, uint32_t length, AllocationType allocation_type) { return HeapInternalsBase::AllocateByteArrayForTest(heap, length, @@ -142,8 +167,17 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { return HeapInternalsBase::AllocateFixedArrayForTest(heap, length, allocation); } - void SetForceOOM(Heap* heap, bool value) { - HeapInternalsBase::SetForceOOM(heap, value); + AllocationResult AllocateMapForTest(Isolate* isolate) { + return HeapInternalsBase::AllocateMapForTest(isolate); + } + void SetForceOOM(bool value) { + HeapInternalsBase::SetForceOOM(heap(), value); + } + void SetDelaySweeperTasksForTesting(bool value) { + HeapInternalsBase::SetDelaySweeperTasksForTesting(heap(), value); + } + int MemoryReducerStateId() { + return HeapInternalsBase::MemoryReducerStateId(heap()); } void GrowNewSpaceToMaximumCapacity() { @@ -169,7 +203,7 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { } void ForceEvacuationCandidate(NormalPage* page) { - i::ForceEvacuationCandidate(page); + internal::ForceEvacuationCandidate(page); } void EmptyNewSpaceUsingGC() { InvokeMajorGC(); } @@ -183,8 +217,18 @@ class WithHeapInternals : public TMixin, HeapInternalsBase { } return count; } + + std::vector<Handle<FixedArray>> CreatePadding( + int padding_size, AllocationType allocation, + int object_size = kMaxRegularHeapObjectSize) { + return HeapInternalsBase::CreatePadding(heap(), padding_size, allocation, + object_size); + } }; +class TestWithPlatformAndHeapInternals : public TestWithPlatform, + protected HeapInternalsBase {}; + template <typename TMixin> class WithCppHeap : public TMixin { public: @@ -279,6 +323,8 @@ class V8_NODISCARD DisableHandleChecksForMockingScope final { }; #endif +int FixedArrayLenFromSize(int size); + void AbandonCurrentlyFreeMemory(PagedSpace* space); Tagged<HeapObject> AllocateAligned(Heap* heap, MainAllocator* allocator, diff --git a/deps/v8/test/unittests/heap/local-factory-unittest.cc b/deps/v8/test/unittests/heap/local-factory-unittest.cc index 1946ba728594..6750e145b584 100644 --- a/deps/v8/test/unittests/heap/local-factory-unittest.cc +++ b/deps/v8/test/unittests/heap/local-factory-unittest.cc @@ -69,9 +69,7 @@ class LocalFactoryTest : public TestWithIsolateAndZone { // Normally this would be an external string or whatever, we don't have to // worry about it for now. - source_string_ = factory() - ->NewStringFromUtf8(base::CStrVector(source)) - .ToHandleChecked(); + source_string_ = factory()->NewStringFromUtf8(source).ToHandleChecked(); script_ = parse_info_.CreateScript(local_isolate(), local_factory()->empty_string(), @@ -127,7 +125,7 @@ TEST_F(LocalFactoryTest, OneByteInternalizedString_IsAddedToStringTable) { string = local_isolate()->heap()->NewPersistentHandle(local_string); } - EXPECT_TRUE(string->IsOneByteEqualTo(base::CStrVector("foo"))); + EXPECT_TRUE(string->IsOneByteEqualTo("foo")); EXPECT_TRUE(IsInternalizedString(*string)); Handle<String> same_string = isolate() @@ -159,7 +157,7 @@ TEST_F(LocalFactoryTest, OneByteInternalizedString_DuplicateIsDeduplicated) { string_2 = local_isolate()->heap()->NewPersistentHandle(local_string_2); } - EXPECT_TRUE(string_1->IsOneByteEqualTo(base::CStrVector("foo"))); + EXPECT_TRUE(string_1->IsOneByteEqualTo("foo")); EXPECT_TRUE(IsInternalizedString(*string_1)); EXPECT_EQ(*string_1, *string_2); } @@ -179,7 +177,7 @@ TEST_F(LocalFactoryTest, AstRawString_IsInternalized) { string = local_isolate()->heap()->NewPersistentHandle(raw_string->string()); } - EXPECT_TRUE(string->IsOneByteEqualTo(base::CStrVector("foo"))); + EXPECT_TRUE(string->IsOneByteEqualTo("foo")); EXPECT_TRUE(IsInternalizedString(*string)); } @@ -242,7 +240,7 @@ TEST_F(LocalFactoryTest, LazyFunction) { DirectHandle<SharedFunctionInfo> lazy_sfi = shared; EXPECT_EQ(lazy_sfi->function_literal_id(kRelaxedLoad), 1); - EXPECT_TRUE(lazy_sfi->Name()->IsOneByteEqualTo(base::CStrVector("lazy"))); + EXPECT_TRUE(lazy_sfi->Name()->IsOneByteEqualTo("lazy")); EXPECT_FALSE(lazy_sfi->is_compiled()); EXPECT_TRUE(lazy_sfi->HasUncompiledDataWithoutPreparseData(local_isolate())); } @@ -269,7 +267,7 @@ TEST_F(LocalFactoryTest, EagerFunction) { DirectHandle<SharedFunctionInfo> eager_sfi = shared; EXPECT_EQ(eager_sfi->function_literal_id(kRelaxedLoad), 1); - EXPECT_TRUE(eager_sfi->Name()->IsOneByteEqualTo(base::CStrVector("eager"))); + EXPECT_TRUE(eager_sfi->Name()->IsOneByteEqualTo("eager")); EXPECT_FALSE(eager_sfi->HasUncompiledData(local_isolate())); // TODO(leszeks): Add compilation support and enable these checks. // EXPECT_TRUE(eager_sfi->is_compiled()); @@ -300,8 +298,7 @@ TEST_F(LocalFactoryTest, ImplicitNameFunction) { DirectHandle<SharedFunctionInfo> implicit_name_sfi = shared; EXPECT_EQ(implicit_name_sfi->function_literal_id(kRelaxedLoad), 1); - EXPECT_TRUE(implicit_name_sfi->Name()->IsOneByteEqualTo( - base::CStrVector("implicit_name"))); + EXPECT_TRUE(implicit_name_sfi->Name()->IsOneByteEqualTo("implicit_name")); } TEST_F(LocalFactoryTest, GCDuringPublish) { @@ -328,8 +325,7 @@ TEST_F(LocalFactoryTest, GCDuringPublish) { DirectHandle<SharedFunctionInfo> implicit_name_sfi = shared; EXPECT_EQ(implicit_name_sfi->function_literal_id(kRelaxedLoad), 1); - EXPECT_TRUE(implicit_name_sfi->Name()->IsOneByteEqualTo( - base::CStrVector("implicit_name"))); + EXPECT_TRUE(implicit_name_sfi->Name()->IsOneByteEqualTo("implicit_name")); } } // namespace internal diff --git a/deps/v8/test/unittests/heap/mark-compact-unittest.cc b/deps/v8/test/unittests/heap/mark-compact-unittest.cc new file mode 100644 index 000000000000..1f97e8109226 --- /dev/null +++ b/deps/v8/test/unittests/heap/mark-compact-unittest.cc @@ -0,0 +1,707 @@ +// Copyright 2026 the V8 project 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 "src/heap/mark-compact.h" + +#include <algorithm> +#include <memory> +#include <vector> + +#include "src/api/api-inl.h" +#include "src/common/globals.h" +#include "src/handles/handles-inl.h" +#include "src/heap/concurrent-marking.h" +#include "src/heap/factory.h" +#include "src/heap/incremental-marking.h" +#include "src/heap/live-object-range-inl.h" +#include "src/heap/memory-chunk-inl.h" +#include "src/heap/memory-chunk-layout.h" +#include "src/heap/mutable-page-inl.h" +#include "src/heap/normal-page-inl.h" +#include "src/heap/spaces-inl.h" +#include "src/objects/objects-inl.h" +#include "test/common/flag-utils.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +using MarkCompactTest = TestWithHeapInternalsAndContext; +using MarkCompactPlatformTest = TestWithPlatformAndHeapInternals; + +TEST_F(MarkCompactTest, Promotion) { + if (v8_flags.single_generation) return; + Isolate* isolate = i_isolate(); + ManualGCScope manual_gc_scope(isolate); + v8::HandleScope sc(v8_isolate()); + Heap* heap = isolate->heap(); + + SealCurrentObjects(); + + int array_length = FixedArrayLenFromSize(kMaxRegularHeapObjectSize); + DirectHandle<FixedArray> array = + isolate->factory()->NewFixedArray(array_length); + + // Array should be in the new space. + EXPECT_TRUE(heap->InSpace(*array, NEW_SPACE)); + InvokeMajorGC(); + InvokeMajorGC(); + EXPECT_TRUE(heap->InSpace(*array, OLD_SPACE)); +} + +TEST_F(MarkCompactTest, MarkCompactCollector) { + ManualGCScope manual_gc_scope(i_isolate()); + FlagScope<bool> no_incremental_marking(&v8_flags.incremental_marking, false); + FlagScope<int> no_retain_maps(&v8_flags.retain_maps_for_n_gc, 0); + + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + + v8::HandleScope sc(v8_isolate()); + DirectHandle<JSGlobalObject> global(isolate->context()->global_object(), + isolate); + + // call mark-compact when heap is empty + InvokeMajorGC(); + + AllocationResult allocation; + if (!v8_flags.single_generation) { + // keep allocating garbage in new space until it fails + const uint32_t arraysize = 100; + do { + allocation = + AllocateFixedArrayForTest(heap, arraysize, AllocationType::kYoung); + } while (!allocation.IsFailure()); + InvokeMinorGC(); + AllocateFixedArrayForTest(heap, arraysize, AllocationType::kYoung) + .ToObjectChecked(); + } + + // keep allocating maps until it fails + do { + allocation = AllocateMapForTest(isolate); + } while (!allocation.IsFailure()); + InvokeMajorGC(); + AllocateMapForTest(isolate).ToObjectChecked(); + + { + HandleScope scope(isolate); + // allocate a garbage + DirectHandle<String> func_name = + factory->InternalizeUtf8String("theFunction"); + DirectHandle<JSFunction> function = + factory->NewFunctionForTesting(func_name); + Object::SetProperty(isolate, global, func_name, function).Check(); + + factory->NewJSObject(function); + } + + InvokeMajorGC(); + + { + HandleScope scope(isolate); + DirectHandle<String> func_name = + factory->InternalizeUtf8String("theFunction"); + EXPECT_EQ(Just(true), + JSReceiver::HasOwnProperty(isolate, global, func_name)); + DirectHandle<Object> func_value = + Object::GetProperty(isolate, global, func_name).ToHandleChecked(); + ASSERT_TRUE(IsJSFunction(*func_value)); + DirectHandle<JSFunction> function = Cast<JSFunction>(func_value); + DirectHandle<JSObject> obj = factory->NewJSObject(function); + + DirectHandle<String> obj_name = factory->InternalizeUtf8String("theObject"); + Object::SetProperty(isolate, global, obj_name, obj).Check(); + DirectHandle<String> prop_name = factory->InternalizeUtf8String("theSlot"); + DirectHandle<Smi> twenty_three(Smi::FromInt(23), isolate); + Object::SetProperty(isolate, obj, prop_name, twenty_three).Check(); + } + + InvokeMajorGC(); + + { + HandleScope scope(isolate); + DirectHandle<String> obj_name = factory->InternalizeUtf8String("theObject"); + EXPECT_EQ(Just(true), + JSReceiver::HasOwnProperty(isolate, global, obj_name)); + DirectHandle<Object> object = + Object::GetProperty(isolate, global, obj_name).ToHandleChecked(); + ASSERT_TRUE(IsJSObject(*object)); + DirectHandle<String> prop_name = factory->InternalizeUtf8String("theSlot"); + EXPECT_EQ(*Object::GetProperty(isolate, Cast<JSObject>(object), prop_name) + .ToHandleChecked(), + Smi::FromInt(23)); + } +} + +TEST_F(MarkCompactTest, DoNotEvacuatePinnedPages) { + if (!v8_flags.compact || !v8_flags.single_generation || + v8_flags.precise_object_pinning) { + return; + } + + ManualGCScope manual_gc_scope(i_isolate()); + FlagScope<bool> compact_on_every_full_gc(&v8_flags.compact_on_every_full_gc, + true); + + v8::HandleScope sc(v8_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + + SealCurrentObjects(); + + std::vector<Handle<FixedArray>> handles = CreatePadding( + static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), + AllocationType::kOld); + ASSERT_FALSE(handles.empty()); + + MemoryChunk* chunk = MemoryChunk::FromHeapObject(*handles.front()); + auto* page = MutablePage::FromHeapObject(isolate, *handles.front()); + + EXPECT_TRUE(heap->InSpace(*handles.front(), OLD_SPACE)); + page->set_is_pinned_for_testing(true); + + InvokeMajorGC(); + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + + // The pinned flag should prevent the page from moving. + for (DirectHandle<FixedArray> object : handles) { + EXPECT_EQ(chunk, MemoryChunk::FromHeapObject(*object)); + } + + page->set_is_pinned_for_testing(false); + + InvokeMajorGC(); + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + + // `compact_on_every_full_gc` ensures that this page is an evacuation + // candidate, so with the pin flag cleared compaction should now move it. + for (DirectHandle<FixedArray> object : handles) { + EXPECT_NE(chunk, MemoryChunk::FromHeapObject(*object)); + } +} + +TEST_F(MarkCompactTest, Regress5829) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + v8::HandleScope sc(v8_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + SealCurrentObjects(); + IncrementalMarking* marking = heap->incremental_marking(); + if (heap->sweeping_in_progress()) { + heap->EnsureSweepingCompleted(Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + } + EXPECT_TRUE(marking->IsMarking() || marking->IsStopped()); + if (marking->IsStopped()) { + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + } + ASSERT_TRUE(marking->IsMarking()); + EXPECT_TRUE(marking->black_allocation()); + DirectHandle<FixedArray> array = + isolate->factory()->NewFixedArray(10, AllocationType::kOld); + Address old_end = array->address() + array->Size(); + // Right trim the array without clearing the mark bits. + array->set_length(9); + heap->CreateFillerObjectAt(old_end - kTaggedSize, kTaggedSize); + heap->FreeMainThreadLinearAllocationAreas(); + NormalPage* page = NormalPage::FromAddress(array->address()); + for (auto object_and_size : LiveObjectRange(page)) { + EXPECT_FALSE(IsFreeSpaceOrFiller(object_and_size.first)); + } +} + +TEST_F(MarkCompactTest, IncrementalMarkingUsingTasks) { + if (!v8_flags.incremental_marking) return; + FLAG_VALUE_SCOPE(stress_concurrent_allocation, false); + FLAG_VALUE_SCOPE(stress_incremental_marking, false); + + IncrementalMarking* marking = heap()->incremental_marking(); + if (marking->IsMarking()) { + InvokeAtomicMajorGC(); + } + SimulateFullSpace(heap()->old_space()); + EXPECT_TRUE(marking->IsStopped()); + + heap()->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + EXPECT_TRUE(marking->IsMajorMarking()); + while (marking->IsMajorMarking()) { + ASSERT_TRUE( + v8::platform::PumpMessageLoop(V8::GetCurrentPlatform(), v8_isolate())); + } + EXPECT_TRUE(marking->IsStopped()); +} + +TEST_F(MarkCompactTest, ConcurrentMarkingMarkedBytes) { + if (!v8_flags.incremental_marking || !v8_flags.concurrent_marking) return; + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + HandleScope sc(isolate); + DirectHandle<FixedArray> root = isolate->factory()->NewFixedArray(1000000); + InvokeMajorGC(); + if (!heap->incremental_marking()->IsStopped()) return; + + // Store array in Global such that it is part of the root set when + // starting incremental marking. + v8::Global<Value> global_root(v8_isolate(), + Utils::ToLocal(Cast<Object>(root))); + + SimulateIncrementalMarking(false); + // Ensure that objects are published to the global marking worklist such that + // the concurrent markers can pick it up. + heap->mark_compact_collector()->local_marking_worklists()->Publish(); + heap->concurrent_marking()->JoinJobForTesting(); + EXPECT_GE(heap->concurrent_marking()->TotalMarkedBytes(), + static_cast<size_t>(root->Size())); +} + +TEST_F(MarkCompactPlatformTest, ConcurrentMarkingStoppedOnTeardown) { + if (!v8_flags.incremental_marking || !v8_flags.concurrent_marking) return; + + // Create and dispose a standalone Isolate directly because IsolateWrapper + // pumps the message loop before Dispose(), which would finish marking early. + std::unique_ptr<v8::ArrayBuffer::Allocator> allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = allocator.get(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + + { + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + Factory* factory = i_isolate->factory(); + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::New(isolate)->Enter(); + + for (int i = 0; i < 10000; i++) { + factory->NewJSWeakMap(); + } + + Heap* heap = i_isolate->heap(); + SimulateIncrementalMarking(heap, false); + } + + isolate->Dispose(); +} + +namespace { + +void CheckInvariantsOfAbortedPage(NormalPage* page) { + // Check invariants: + // 1) Markbits are cleared + // 2) The page is not marked as evacuation candidate anymore + // 3) The page is not marked as aborted compaction anymore. + EXPECT_TRUE(page->marking_bitmap()->IsClean()); + EXPECT_FALSE(page->is_evacuation_candidate()); + EXPECT_FALSE(page->evacuation_was_aborted()); +} + +void CheckAllObjectsOnPage(const std::vector<Handle<FixedArray>>& handles, + NormalPage* page) { + for (DirectHandle<FixedArray> fixed_array : handles) { + EXPECT_EQ(NormalPage::FromHeapObject(*fixed_array), page); + } +} + +int GetObjectSize(int objects_per_page) { + int allocatable = + static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()); + // Make sure that object_size is a multiple of kTaggedSize. + int object_size = + ((allocatable / kTaggedSize) / objects_per_page) * kTaggedSize; + return std::min(kMaxRegularHeapObjectSize, object_size); +} + +} // namespace + +TEST_F(MarkCompactTest, CompactionFullAbortedPage) { + if (!v8_flags.compact) return; + // Test the scenario where we reach OOM during compaction and the whole page + // is aborted. + + // Disable concurrent sweeping to ensure memory is in an expected state, i.e., + // we can reach the state of a half aborted page. + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(isolate); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + auto reset_oom = [](void* data, size_t limit, size_t) -> size_t { + reinterpret_cast<MarkCompactTest*>(data)->SetForceOOM(false); + return limit; + }; + heap->AddNearHeapLimitCallback(reset_oom, this); + { + HandleScope scope1(isolate); + + SealCurrentObjects(); + + { + HandleScope scope2(isolate); + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + std::vector<Handle<FixedArray>> compaction_page_handles = CreatePadding( + static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), + AllocationType::kOld); + ASSERT_FALSE(compaction_page_handles.empty()); + NormalPage* to_be_aborted_page = + NormalPage::FromHeapObject(*compaction_page_handles.front()); + to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); + CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); + + SetForceOOM(true); + InvokeMajorGC(); + heap->EnsureSweepingCompleted( + Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + + // Check that all handles still point to the same page, i.e., compaction + // has been aborted on the page. + for (DirectHandle<FixedArray> object : compaction_page_handles) { + EXPECT_EQ(to_be_aborted_page, NormalPage::FromHeapObject(*object)); + } + CheckInvariantsOfAbortedPage(to_be_aborted_page); + } + } + heap->RemoveNearHeapLimitCallback(reset_oom, 0u); +} + +TEST_F(MarkCompactTest, CompactionPartiallyAbortedPage) { + if (!v8_flags.compact) return; + // Test the scenario where we reach OOM during compaction and parts of the + // page have already been migrated to a new one. + + // Disable concurrent sweeping to ensure memory is in an expected state, i.e., + // we can reach the state of a half aborted page. + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(isolate); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + + const int objects_per_page = 10; + const int object_size = GetObjectSize(objects_per_page); + + auto reset_oom = [](void* data, size_t limit, size_t) -> size_t { + reinterpret_cast<MarkCompactTest*>(data)->SetForceOOM(false); + return limit; + }; + heap->AddNearHeapLimitCallback(reset_oom, this); + { + HandleScope scope1(isolate); + + SealCurrentObjects(); + + { + HandleScope scope2(isolate); + // Fill another page with objects of size {object_size} (last one is + // properly adjusted). + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + std::vector<Handle<FixedArray>> compaction_page_handles = CreatePadding( + static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), + AllocationType::kOld, object_size); + ASSERT_FALSE(compaction_page_handles.empty()); + NormalPage* to_be_aborted_page = + NormalPage::FromHeapObject(*compaction_page_handles.front()); + to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); + CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); + + { + // Add another page that is filled with {num_objects} objects of size + // {object_size}. + HandleScope scope3(isolate); + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + const int num_objects = 3; + std::vector<Handle<FixedArray>> page_to_fill_handles = CreatePadding( + object_size * num_objects, AllocationType::kOld, object_size); + ASSERT_FALSE(page_to_fill_handles.empty()); + NormalPage* page_to_fill = + NormalPage::FromAddress(page_to_fill_handles.front()->address()); + + SetForceOOM(true); + InvokeMajorGC(); + heap->EnsureSweepingCompleted( + Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + + bool migration_aborted = false; + for (DirectHandle<FixedArray> object : compaction_page_handles) { + // Once compaction has been aborted, all following objects still have + // to be on the initial page. + EXPECT_TRUE( + !migration_aborted || + (NormalPage::FromHeapObject(*object) == to_be_aborted_page)); + if (NormalPage::FromHeapObject(*object) == to_be_aborted_page) { + // This object has not been migrated. + migration_aborted = true; + } else { + EXPECT_EQ(NormalPage::FromHeapObject(*object), page_to_fill); + } + } + // Check that we actually created a scenario with a partially aborted + // page. + EXPECT_TRUE(migration_aborted); + CheckInvariantsOfAbortedPage(to_be_aborted_page); + } + } + } + heap->RemoveNearHeapLimitCallback(reset_oom, 0u); +} + +TEST_F(MarkCompactTest, CompactionPartiallyAbortedPageIntraAbortedPointers) { + if (!v8_flags.compact) return; + // Test the scenario where we reach OOM during compaction and parts of the + // page have already been migrated to a new one. Objects on the aborted page + // are linked together. This test makes sure that intra-aborted page pointers + // get properly updated. + + // Disable concurrent sweeping to ensure memory is in an expected state, i.e., + // we can reach the state of a half aborted page. + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(isolate); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + + const int objects_per_page = 10; + const int object_size = GetObjectSize(objects_per_page); + + auto reset_oom = [](void* data, size_t limit, size_t) -> size_t { + reinterpret_cast<MarkCompactTest*>(data)->SetForceOOM(false); + return limit; + }; + heap->AddNearHeapLimitCallback(reset_oom, this); + { + HandleScope scope1(isolate); + IndirectHandle<FixedArray> root_array = + isolate->factory()->NewFixedArray(10, AllocationType::kOld); + + SealCurrentObjects(); + + NormalPage* to_be_aborted_page = nullptr; + { + HandleScope temporary_scope(isolate); + // Fill a fresh page with objects of size {object_size} (last one is + // properly adjusted). + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + std::vector<Handle<FixedArray>> compaction_page_handles = CreatePadding( + static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), + AllocationType::kOld, object_size); + ASSERT_FALSE(compaction_page_handles.empty()); + to_be_aborted_page = + NormalPage::FromHeapObject(*compaction_page_handles.front()); + to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); + for (size_t i = compaction_page_handles.size() - 1; i > 0; i--) { + compaction_page_handles[i]->set(0, *compaction_page_handles[i - 1]); + } + root_array->set(0, *compaction_page_handles.back()); + CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); + } + { + // Add another page that is filled with {num_objects} objects of size + // {object_size}. + HandleScope scope3(isolate); + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + const int num_objects = 2; + int used_memory = object_size * num_objects; + std::vector<Handle<FixedArray>> page_to_fill_handles = + CreatePadding(used_memory, AllocationType::kOld, object_size); + ASSERT_FALSE(page_to_fill_handles.empty()); + NormalPage* page_to_fill = + NormalPage::FromHeapObject(*page_to_fill_handles.front()); + + // We need to invoke GC without stack, otherwise no compaction is + // performed. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + + SetForceOOM(true); + InvokeMajorGC(); + heap->EnsureSweepingCompleted( + Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + + // The following check makes sure that we compacted "some" objects, while + // leaving others in place. + bool in_place = true; + IndirectHandle<FixedArray> current = root_array; + while (current->get(0) != ReadOnlyRoots(heap).undefined_value()) { + current = IndirectHandle<FixedArray>(Cast<FixedArray>(current->get(0)), + isolate); + ASSERT_TRUE(IsFixedArray(*current)); + if (NormalPage::FromHeapObject(*current) != to_be_aborted_page) { + in_place = false; + } + bool on_aborted_page = + NormalPage::FromHeapObject(*current) == to_be_aborted_page; + bool on_fill_page = + NormalPage::FromHeapObject(*current) == page_to_fill; + EXPECT_TRUE((in_place && on_aborted_page) || + (!in_place && on_fill_page)); + } + // Check that we at least migrated one object, as otherwise the test would + // not trigger. + EXPECT_FALSE(in_place); + CheckInvariantsOfAbortedPage(to_be_aborted_page); + } + } + heap->RemoveNearHeapLimitCallback(reset_oom, 0u); +} + +TEST_F(MarkCompactTest, + CompactionPartiallyAbortedPageWithRememberedSetEntries) { + if (!v8_flags.compact || v8_flags.single_generation) return; + // Test the scenario where we reach OOM during compaction and parts of the + // page have already been migrated to a new one. Objects on the aborted page + // are linked together and the very first object on the aborted page points + // into new space. The test verifies that the remembered set entries are + // properly cleared and rebuilt after aborting a page. Failing to do so can + // result in other objects being allocated in the free space where their + // payload looks like a valid new space pointer. + + // Disable concurrent sweeping to ensure memory is in an expected state, i.e., + // we can reach the state of a half aborted page. + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(isolate); + ManualEvacuationCandidatesSelectionScope + manual_evacuation_candidate_selection_scope(manual_gc_scope); + + const int objects_per_page = 10; + const int object_size = GetObjectSize(objects_per_page); + + auto reset_oom = [](void* data, size_t limit, size_t) -> size_t { + reinterpret_cast<MarkCompactTest*>(data)->SetForceOOM(false); + return limit; + }; + heap->AddNearHeapLimitCallback(reset_oom, this); + { + HandleScope scope1(isolate); + IndirectHandle<FixedArray> root_array = + isolate->factory()->NewFixedArray(10, AllocationType::kOld); + SealCurrentObjects(); + + NormalPage* to_be_aborted_page = nullptr; + { + HandleScope temporary_scope(isolate); + // Fill another page with objects of size {object_size} (last one is + // properly adjusted). + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + std::vector<Handle<FixedArray>> compaction_page_handles = CreatePadding( + static_cast<int>(MemoryChunkLayout::AllocatableMemoryInDataPage()), + AllocationType::kOld, object_size); + ASSERT_FALSE(compaction_page_handles.empty()); + // Sanity check that we have enough space for linking up arrays. + ASSERT_GE(compaction_page_handles.front()->length().value(), 2u); + to_be_aborted_page = + NormalPage::FromHeapObject(*compaction_page_handles.front()); + to_be_aborted_page->set_forced_evacuation_candidate_for_testing(true); + + for (size_t i = compaction_page_handles.size() - 1; i > 0; i--) { + compaction_page_handles[i]->set(0, *compaction_page_handles[i - 1]); + } + root_array->set(0, *compaction_page_handles.back()); + DirectHandle<FixedArray> new_space_array = + isolate->factory()->NewFixedArray(1, AllocationType::kYoung); + EXPECT_TRUE(HeapLayout::InYoungGeneration(*new_space_array)); + compaction_page_handles.front()->set(1, *new_space_array); + CheckAllObjectsOnPage(compaction_page_handles, to_be_aborted_page); + } + + { + // Add another page that is filled with {num_objects} objects of size + // {object_size}. + HandleScope scope3(isolate); + ASSERT_TRUE(heap->old_space()->TryExpand(heap->main_thread_local_heap(), + AllocationOrigin::kRuntime)); + const int num_objects = 2; + int used_memory = object_size * num_objects; + std::vector<Handle<FixedArray>> page_to_fill_handles = + CreatePadding(used_memory, AllocationType::kOld, object_size); + ASSERT_FALSE(page_to_fill_handles.empty()); + NormalPage* page_to_fill = + NormalPage::FromHeapObject(*page_to_fill_handles.front()); + + // We need to invoke GC without stack, otherwise no compaction is + // performed. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); + + SetForceOOM(true); + InvokeMajorGC(); + heap->EnsureSweepingCompleted( + Heap::SweepingForcedFinalizationMode::kV8Only, + CompleteSweepingReason::kTesting); + + // The following check makes sure that we compacted "some" objects, while + // leaving others in place. + bool in_place = true; + IndirectHandle<FixedArray> current = root_array; + while (current->get(0) != ReadOnlyRoots(heap).undefined_value()) { + current = IndirectHandle<FixedArray>(Cast<FixedArray>(current->get(0)), + isolate); + EXPECT_FALSE(HeapLayout::InYoungGeneration(*current)); + ASSERT_TRUE(IsFixedArray(*current)); + if (NormalPage::FromHeapObject(*current) != to_be_aborted_page) { + in_place = false; + } + bool on_aborted_page = + NormalPage::FromHeapObject(*current) == to_be_aborted_page; + bool on_fill_page = + NormalPage::FromHeapObject(*current) == page_to_fill; + EXPECT_TRUE((in_place && on_aborted_page) || + (!in_place && on_fill_page)); + } + // Check that we at least migrated one object, as otherwise the test would + // not trigger. + EXPECT_FALSE(in_place); + CheckInvariantsOfAbortedPage(to_be_aborted_page); + + // Allocate a new object in new space. + IndirectHandle<FixedArray> holder = + isolate->factory()->NewFixedArray(10, AllocationType::kYoung); + // Create a broken address that looks like a tagged pointer to a new space + // object. + Address broken_address = holder->address() + 2 * kTaggedSize + 1; + // Convert it to a vector to create a string from it. + base::Vector<const uint8_t> string_to_broken_address( + reinterpret_cast<const uint8_t*>(&broken_address), kTaggedSize); + + IndirectHandle<String> string; + do { + // We know that the interesting slot will be on the aborted page and + // hence we allocate until we get our string on the aborted page. + // We used slot 1 in the fixed size array which corresponds to the + // the first word in the string. Since the first object definitely + // migrated we can just allocate until we hit the aborted page. + string = isolate->factory() + ->NewStringFromOneByte(string_to_broken_address, + AllocationType::kOld) + .ToHandleChecked(); + } while (NormalPage::FromHeapObject(*string) != to_be_aborted_page); + + // If remembered set entries are not properly filtered/reset for aborted + // pages we have now a broken address at an object slot in old space and + // the following scavenge will crash. + InvokeMinorGC(); + } + } + heap->RemoveNearHeapLimitCallback(reset_oom, 0u); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/heap/memory-measurement-unittest.cc b/deps/v8/test/unittests/heap/memory-measurement-unittest.cc new file mode 100644 index 000000000000..c4a919a1ba6b --- /dev/null +++ b/deps/v8/test/unittests/heap/memory-measurement-unittest.cc @@ -0,0 +1,282 @@ +// Copyright 2019 the V8 project 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 "src/heap/memory-measurement.h" + +#include <algorithm> +#include <cstddef> +#include <memory> +#include <vector> + +#include "include/v8-array-buffer.h" +#include "include/v8-local-handle.h" +#include "include/v8-platform.h" +#include "include/v8-primitive.h" +#include "include/v8-statistics.h" +#include "src/api/api-inl.h" +#include "src/execution/isolate-inl.h" +#include "src/heap/factory.h" +#include "src/heap/memory-measurement-inl.h" +#include "src/libplatform/default-platform.h" +#include "src/objects/js-array-buffer-inl.h" +#include "src/objects/js-function-inl.h" +#include "src/objects/smi.h" +#include "src/objects/tagged-field-inl.h" +#include "src/utils/allocation.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8::internal { +namespace { + +class TestResource : public v8::String::ExternalStringResource { + public: + explicit TestResource(uint16_t* data) : data_(data) { + while (data[length_]) ++length_; + } + + ~TestResource() override { DeleteArray(data_); } + + const uint16_t* data() const override { return data_; } + + size_t length() const override { return length_; } + + private: + uint16_t* data_; + size_t length_ = 0; +}; + +class MockMeasureMemoryDelegate : public v8::MeasureMemoryDelegate { + public: + bool ShouldMeasure(v8::Local<v8::Context> context) override { return true; } + + void MeasurementComplete(Result result) override {} +}; + +class MockTaskRunner : public v8::TaskRunner { + public: + void PostTaskImpl(std::unique_ptr<Task> task, + const SourceLocation& location) override { + task_ = std::move(task); + } + + void PostNonNestableTaskImpl(std::unique_ptr<Task> task, + const SourceLocation& location) override { + PostTask(std::move(task)); + } + + void PostDelayedTaskImpl(std::unique_ptr<Task> task, double delay_in_seconds, + const SourceLocation& location) override { + delay_ = delay_in_seconds; + PostTask(std::move(task)); + } + + void PostNonNestableDelayedTaskImpl(std::unique_ptr<Task> task, + double delay_in_seconds, + const SourceLocation& location) override { + PostDelayedTaskImpl(std::move(task), delay_in_seconds, location); + } + + void PostIdleTaskImpl(std::unique_ptr<IdleTask> task, + const SourceLocation& location) override { + UNREACHABLE(); + } + + bool IdleTasksEnabled() override { return false; } + bool NonNestableTasksEnabled() const override { return true; } + bool NonNestableDelayedTasksEnabled() const override { return true; } + + bool PendingTask() const { return task_ != nullptr; } + + double Delay() const { return delay_; } + + void PerformTask() { + std::unique_ptr<Task> task = std::move(task_); + task->Run(); + } + + private: + double delay_ = -1; + std::unique_ptr<Task> task_; +}; + +class MockPlatform : public v8::platform::DefaultPlatform { + public: + explicit MockPlatform(v8::Platform* default_platform) + : default_platform_(default_platform), + task_runner_(std::make_shared<MockTaskRunner>()) { + CHECK_NOT_NULL(default_platform_); + EnsureBackgroundTaskRunnerInitialized(); + V8::SetPlatformForTesting(this); + } + + ~MockPlatform() override { + if (V8::GetCurrentPlatform() == this) { + V8::SetPlatformForTesting(default_platform_); + } + } + + std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner( + v8::Isolate*, v8::TaskPriority) override { + return task_runner_; + } + + bool PendingTask() const { return task_runner_->PendingTask(); } + void PerformTask() { task_runner_->PerformTask(); } + double Delay() const { return task_runner_->Delay(); } + + private: + v8::Platform* default_platform_; + std::shared_ptr<MockTaskRunner> task_runner_; +}; + +template <typename TMixin> +class WithMockPlatformMixin : public TMixin { + public: + WithMockPlatformMixin() : mock_platform_(this->platform()) {} + WithMockPlatformMixin(const WithMockPlatformMixin&) = delete; + WithMockPlatformMixin& operator=(const WithMockPlatformMixin&) = delete; + + MockPlatform& mock_platform() { return mock_platform_; } + + private: + MockPlatform mock_platform_; +}; + +using MemoryMeasurementTest = TestWithHeapInternalsAndContext; +using MemoryMeasurementWithMockPlatformTest = WithIsolateScopeMixin< + WithIsolateMixin<WithMockPlatformMixin<TestWithPlatform>>>; + +} // namespace + +TEST_F(MemoryMeasurementTest, NativeContextInferrerGlobalObject) { + DirectHandle<JSGlobalObject> global(native_context()->global_object(), + i_isolate()); + NativeContextInferrer inferrer; + Address inferred_context = 0; + EXPECT_TRUE( + inferrer.Infer(i_isolate(), global->map(), *global, &inferred_context)); + EXPECT_EQ(native_context()->ptr(), inferred_context); +} + +TEST_F(MemoryMeasurementTest, NativeContextInferrerJSFunction) { + DirectHandle<HeapObject> function = + RunJS<HeapObject>("(function () { return 1; })"); + NativeContextInferrer inferrer; + Address inferred_context = 0; + EXPECT_TRUE(inferrer.Infer(i_isolate(), function->map(), *function, + &inferred_context)); + EXPECT_EQ(native_context()->ptr(), inferred_context); +} + +TEST_F(MemoryMeasurementTest, NativeContextInferrerJSObject) { + DirectHandle<HeapObject> object = RunJS<HeapObject>("({a : 10})"); + NativeContextInferrer inferrer; + Address inferred_context = 0; + EXPECT_TRUE( + inferrer.Infer(i_isolate(), object->map(), *object, &inferred_context)); + EXPECT_EQ(native_context()->ptr(), inferred_context); +} + +TEST_F(MemoryMeasurementTest, NativeContextStatsMerge) { + DirectHandle<HeapObject> object = RunJS<HeapObject>("({a : 10})"); + NativeContextStats stats1, stats2; + stats1.IncrementSize(native_context()->ptr(), object->map(), *object, 10); + stats2.IncrementSize(native_context()->ptr(), object->map(), *object, 20); + stats1.Merge(stats2); + EXPECT_EQ(30u, stats1.Get(native_context()->ptr())); +} + +TEST_F(MemoryMeasurementTest, NativeContextStatsArrayBuffers) { + v8::Local<v8::ArrayBuffer> array_buffer = + v8::ArrayBuffer::New(v8_isolate(), 1000); + DirectHandle<JSArrayBuffer> i_array_buffer = + Utils::OpenDirectHandle(*array_buffer); + NativeContextStats stats; + stats.IncrementSize(native_context()->ptr(), i_array_buffer->map(), + *i_array_buffer, 10); + EXPECT_EQ(1010u, stats.Get(native_context()->ptr())); +} + +TEST_F(MemoryMeasurementTest, NativeContextStatsExternalString) { + const char* c_source = "0123456789"; + uint16_t* two_byte_source = AsciiToTwoByteString(c_source); + TestResource* resource = new TestResource(two_byte_source); + v8::Local<v8::String> string = + v8::String::NewExternalTwoByte(v8_isolate(), resource).ToLocalChecked(); + DirectHandle<String> i_string = Utils::OpenDirectHandle(*string); + NativeContextStats stats; + stats.IncrementSize(native_context()->ptr(), i_string->map(), *i_string, 10); + EXPECT_EQ(10u + 10u * 2, stats.Get(native_context()->ptr())); +} + +TEST_F(MemoryMeasurementWithMockPlatformTest, RandomizedTimeout) { + std::vector<double> delays; + for (int i = 0; i < 10; i++) { + v8_isolate()->MeasureMemory(std::make_unique<MockMeasureMemoryDelegate>()); + delays.push_back(mock_platform().Delay()); + ASSERT_TRUE(mock_platform().PendingTask()); + mock_platform().PerformTask(); + } + std::sort(delays.begin(), delays.end()); + EXPECT_LT(delays[0], delays.back()); +} + +TEST_F(MemoryMeasurementWithMockPlatformTest, LazyMemoryMeasurement) { + v8_isolate()->MeasureMemory(std::make_unique<MockMeasureMemoryDelegate>(), + v8::MeasureMemoryExecution::kLazy); + EXPECT_FALSE(mock_platform().PendingTask()); +} + +TEST_F(MemoryMeasurementTest, PartiallyInitializedJSFunction) { + Isolate* isolate = i_isolate(); + // Use indirect handles across EmptyMessageQueues()'s stackless GC task. + Handle<JSFunction> js_function = factory()->NewFunctionForTesting( + factory()->NewStringFromAsciiChecked("test")); + Handle<Context> context(js_function->context(), isolate); + + // 1. Start simulating deserialization. + isolate->RegisterDeserializerStarted(); + // 2. Set the context field to the uninitialized sentinel. + TaggedField<Object, offsetof(JSFunction, context_)>::store( + *js_function, Smi::uninitialized_deserialization_value()); + // 3. Request memory measurement and run all tasks. GC that runs as part + // of the measurement should not crash. + v8_isolate()->MeasureMemory(std::make_unique<MockMeasureMemoryDelegate>(), + v8::MeasureMemoryExecution::kEager); + EmptyMessageQueues(); + // 4. Restore the value and complete deserialization. + TaggedField<Object, offsetof(JSFunction, context_)>::store(*js_function, + *context); + isolate->RegisterDeserializerFinished(); +} + +TEST_F(MemoryMeasurementTest, PartiallyInitializedContext) { + Isolate* isolate = i_isolate(); + DirectHandle<ScopeInfo> scope_info = + factory()->global_this_binding_scope_info(); + Handle<Context> context = indirect_handle( + factory()->NewScriptContext(native_context(), scope_info), isolate); + Handle<Map> map(context->map(), isolate); + Handle<NativeContext> saved_native_context(map->native_context(), isolate); + // 1. Start simulating deserialization. + isolate->RegisterDeserializerStarted(); + // 2. Set the native context field to the uninitialized sentinel. + TaggedField<Object, + offsetof(Map, constructor_or_back_pointer_or_native_context_)>:: + store(*map, Smi::uninitialized_deserialization_value()); + // 3. Request memory measurement and run all tasks. GC that runs as part + // of the measurement should not crash. + v8_isolate()->MeasureMemory(std::make_unique<MockMeasureMemoryDelegate>(), + v8::MeasureMemoryExecution::kEager); + EmptyMessageQueues(); + // 4. Restore the value and complete deserialization. + TaggedField<Object, + offsetof(Map, constructor_or_back_pointer_or_native_context_)>:: + store(*map, *saved_native_context); + isolate->RegisterDeserializerFinished(); +} + +} // namespace v8::internal diff --git a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc index d2bb9a357f34..3a1c4856fa88 100644 --- a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc +++ b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc @@ -2,10 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/heap/memory-reducer.h" + #include <limits> +#include <memory> +#include <utility> +#include "include/v8-platform.h" #include "src/flags/flags.h" -#include "src/heap/memory-reducer.h" +#include "src/heap/heap-controller.h" +#include "src/heap/heap-inl.h" +#include "src/heap/incremental-marking.h" +#include "src/libplatform/default-platform.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace v8 { @@ -304,5 +314,285 @@ TEST(MemoryReducer, FromRunToWait) { EXPECT_EQ(2000, state1.last_gc_time_ms()); } +namespace { + +class MockTaskRunner final : public v8::TaskRunner { + public: + void PostTaskImpl(std::unique_ptr<v8::Task> task, + const v8::SourceLocation& location) override { + task_ = std::move(task); + } + + void PostNonNestableTaskImpl(std::unique_ptr<v8::Task> task, + const v8::SourceLocation& location) override { + PostTask(std::move(task)); + } + + void PostDelayedTaskImpl(std::unique_ptr<v8::Task> task, + double delay_in_seconds, + const v8::SourceLocation& location) override { + delay_ = delay_in_seconds; + PostTask(std::move(task)); + } + + void PostNonNestableDelayedTaskImpl( + std::unique_ptr<v8::Task> task, double delay_in_seconds, + const v8::SourceLocation& location) override { + PostDelayedTaskImpl(std::move(task), delay_in_seconds, location); + } + + void PostIdleTaskImpl(std::unique_ptr<v8::IdleTask> task, + const v8::SourceLocation& location) override { + UNREACHABLE(); + } + + bool IdleTasksEnabled() override { return false; } + bool NonNestableTasksEnabled() const override { return true; } + bool NonNestableDelayedTasksEnabled() const override { return true; } + + bool PendingTask() const { return task_ != nullptr; } + + void PerformTask() { + std::unique_ptr<v8::Task> task = std::move(task_); + task->Run(); + } + + private: + double delay_ = -1; + std::unique_ptr<v8::Task> task_; +}; + +class MemoryReducerMockPlatform final : public v8::platform::DefaultPlatform { + public: + explicit MemoryReducerMockPlatform(v8::Platform* default_platform) + : default_platform_(default_platform), + task_runner_(std::make_shared<MockTaskRunner>()) { + CHECK_NOT_NULL(default_platform_); + // The MemoryReducer is constructed alongside the Heap, which happens + // before the test bodies are run. So, we choose which MemoryReducer we use + // here. + v8_flags.memory_reducer_limit_based = true; + v8_flags.stress_incremental_marking = false; + EnsureBackgroundTaskRunnerInitialized(); + V8::SetPlatformForTesting(this); + } + + ~MemoryReducerMockPlatform() override { + if (V8::GetCurrentPlatform() == this) { + V8::SetPlatformForTesting(default_platform_); + } + } + + std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner( + v8::Isolate*, v8::TaskPriority) override { + return task_runner_; + } + + bool PendingTask() const { return task_runner_->PendingTask(); } + void PerformTask() { task_runner_->PerformTask(); } + + private: + SaveFlags save_flags_; + v8::Platform* default_platform_; + std::shared_ptr<MockTaskRunner> task_runner_; +}; + +template <typename TMixin> +class WithMemoryReducerMockPlatformMixin : public TMixin { + public: + WithMemoryReducerMockPlatformMixin() : mock_platform_(this->platform()) {} + WithMemoryReducerMockPlatformMixin( + const WithMemoryReducerMockPlatformMixin&) = delete; + WithMemoryReducerMockPlatformMixin& operator=( + const WithMemoryReducerMockPlatformMixin&) = delete; + + MemoryReducerMockPlatform& mock_platform() { return mock_platform_; } + + private: + MemoryReducerMockPlatform mock_platform_; +}; + +using LimitBasedMemoryReducerTest = // + WithContextMixin< // + WithHeapInternals< // + WithInternalIsolateMixin< // + WithIsolateScopeMixin< // + WithIsolateMixin< // + WithCppHeap< // + WithMemoryReducerMockPlatformMixin< // + TestWithPlatform>>>>>>>; + +} // namespace + +TEST_F(LimitBasedMemoryReducerTest, LimitBasedMemoryReducerTriggersGC) { + if (!v8_flags.incremental_marking) return; + v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. + v8_flags.stress_incremental_marking = false; + v8_flags.memory_reducer_delay_ms = 0; + + Isolate* i_isolate = this->i_isolate(); + Heap* heap = this->heap(); + MemoryReducerMockPlatform& platform = mock_platform(); + + IncrementalMarking* marking = heap->incremental_marking(); + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + heap->CollectGarbage(OLD_SPACE, GarbageCollectionReason::kTesting); + + CHECK(platform.PendingTask()); + CHECK(memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + + SimulateFullSpace(heap->old_space()); + i_isolate->factory()->NewFixedArray( + V8HeapTrait::kMinimumAllocationLimitGrowingStep, AllocationType::kOld); + + // Run the MemoryReducer task. + platform.PerformTask(); + + // Check that we do a GC here, and reschedule memory reducer. + CHECK(!marking->IsStopped()); + CHECK(platform.PendingTask()); + CHECK(!memory_reducer->is_scheduled()); + + CHECK(marking->IsMajorMarking()); + while (marking->IsMajorMarking()) { + platform.PerformTask(); + } + CHECK(marking->IsStopped()); + + // We did a GC, so memory reducer should be rescheduled. + CHECK(platform.PendingTask()); + CHECK(memory_reducer->is_scheduled()); + + // Run the memory reducer task. Since we haven't allocated since the last + // GC, this should not reschedule. + platform.PerformTask(); + + CHECK(!platform.PendingTask()); + CHECK(!memory_reducer->is_scheduled()); + CHECK(marking->IsStopped()); +} + +TEST_F(LimitBasedMemoryReducerTest, LimitBasedMemoryReducerNotifyMarkCompact) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + v8_flags.memory_reducer_delay_ms = 0; + + ManualGCScope manual_gc_scope(i_isolate()); + Heap* heap = this->heap(); + MemoryReducerMockPlatform& platform = mock_platform(); + + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + heap->limits()->UpdateConsumedAfterGC(); + + CHECK(!platform.PendingTask()); + CHECK(!memory_reducer->is_scheduled()); + + // Trigger MemoryReducer and run a GC. + memory_reducer->NotifyMarkCompact(0); + + CHECK(memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + platform.PerformTask(); + + // We did not do a GC, so don't reschedule. + CHECK(!platform.PendingTask()); + CHECK(!memory_reducer->is_scheduled()); +} + +TEST_F(LimitBasedMemoryReducerTest, LimitBasedMemoryReducerBackgrounded) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + v8_flags.memory_reducer_delay_ms = 0; + + ManualGCScope manual_gc_scope(i_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = this->heap(); + MemoryReducerMockPlatform& platform = mock_platform(); + + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + heap->limits()->UpdateConsumedAfterGC(); + + CHECK(!memory_reducer->is_scheduled()); + CHECK(!platform.PendingTask()); + + // Send to background. + isolate->SetPriority(v8::Isolate::Priority::kBestEffort); + + // MemoryReducer should not be running yet, but the task to start it should + // be scheduled by us going to background. + CHECK(!memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + + // Run the task to schedule MemoryReducer. + platform.PerformTask(); + + // Verify that MemoryReducer was scheduled. + CHECK(memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + + // Run the memory reducer task. + platform.PerformTask(); + + // Check that we don't reschedule the memory reducer here, because we didn't + // do a GC. + CHECK(!memory_reducer->is_scheduled()); + CHECK(!platform.PendingTask()); +} + +TEST_F(LimitBasedMemoryReducerTest, LimitBasedMemoryReducerOvershoot) { + if (v8_flags.single_generation || !v8_flags.memory_reducer) return; + v8_flags.memory_reducer_delay_ms = 0; + + ManualGCScope manual_gc_scope(i_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = this->heap(); + MemoryReducerMockPlatform& platform = mock_platform(); + + IncrementalMarking* marking = heap->incremental_marking(); + auto* memory_reducer = + static_cast<LimitBasedMemoryReducer*>(heap->memory_reducer()); + + heap->limits()->UpdateConsumedAfterGC(); + + // Allocate 20MB in old space after the simulated GC and start major + // incremental marking. + v8_flags.memory_reducer_for_small_heaps = false; + for (int i = 0; i < 20; i++) { + isolate->factory()->NewFixedArray(1024 * 1024 / kTaggedSize, + AllocationType::kOld); + } + heap->StartIncrementalMarking(GCFlag::kNoFlags, + GarbageCollectionReason::kTesting); + CHECK(marking->IsMajorMarking()); + + size_t limit_before = heap->limits()->old_generation_allocation_limit(); + size_t consumed = heap->OldGenerationConsumedBytes(); + CHECK_GE(limit_before, consumed); + + // Send to background while major marking is running, which schedules + // MemoryReducer. + isolate->SetPriority(v8::Isolate::Priority::kBestEffort); + CHECK(!memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + + // Run ActivateMemoryReducerTask to schedule LimitBasedMemoryReducer. + platform.PerformTask(); + CHECK(memory_reducer->is_scheduled()); + CHECK(platform.PendingTask()); + + // Run LimitBasedMemoryReducer::TimerTask while major marking is running. + platform.PerformTask(); + CHECK(!memory_reducer->is_scheduled()); + + // Limits must not be shrunk while major incremental marking is running. + CHECK_EQ(limit_before, heap->limits()->old_generation_allocation_limit()); + CHECK_GE(heap->limits()->old_generation_allocation_limit(), consumed); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/pool-unittest.cc b/deps/v8/test/unittests/heap/pool-unittest.cc deleted file mode 100644 index 6f62e906044d..000000000000 --- a/deps/v8/test/unittests/heap/pool-unittest.cc +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright 2014 the V8 project 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 <map> -#include <optional> - -#include "src/base/region-allocator.h" -#include "src/execution/isolate.h" -#include "src/heap/heap-inl.h" -#include "src/heap/memory-allocator.h" -#include "src/heap/memory-pool.h" -#include "src/heap/spaces-inl.h" -#include "src/utils/ostreams.h" -#include "test/common/flag-utils.h" -#include "test/unittests/test-utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace v8 { -namespace internal { - -// This is a v8::PageAllocator implementation that decorates provided page -// allocator object with page tracking functionality. -class TrackingPageAllocator : public ::v8::PageAllocator { - public: - explicit TrackingPageAllocator(v8::PageAllocator* page_allocator) - : page_allocator_(page_allocator), - allocate_page_size_(page_allocator_->AllocatePageSize()), - commit_page_size_(page_allocator_->CommitPageSize()), - region_allocator_(kNullAddress, size_t{0} - commit_page_size_, - commit_page_size_) { - CHECK_NOT_NULL(page_allocator); - CHECK(IsAligned(allocate_page_size_, commit_page_size_)); - } - ~TrackingPageAllocator() override = default; - - size_t AllocatePageSize() override { return allocate_page_size_; } - - size_t CommitPageSize() override { return commit_page_size_; } - - void SetRandomMmapSeed(int64_t seed) override { - return page_allocator_->SetRandomMmapSeed(seed); - } - - void* GetRandomMmapAddr() override { - return page_allocator_->GetRandomMmapAddr(); - } - - void* AllocatePages(void* address, size_t size, size_t alignment, - PageAllocator::Permission access) override { - void* result = - page_allocator_->AllocatePages(address, size, alignment, access); - if (result) { - // Mark pages as used. - Address current_page = reinterpret_cast<Address>(result); - CHECK(IsAligned(current_page, allocate_page_size_)); - CHECK(IsAligned(size, allocate_page_size_)); - CHECK(region_allocator_.AllocateRegionAt(current_page, size)); - Address end = current_page + size; - while (current_page < end) { - PageState state{access, access != kNoAccess}; - page_permissions_.insert({current_page, state}); - current_page += commit_page_size_; - } - } - return result; - } - - bool FreePages(void* address, size_t size) override { - bool result = page_allocator_->FreePages(address, size); - if (result) { - // Mark pages as free. - Address start = reinterpret_cast<Address>(address); - CHECK(IsAligned(start, allocate_page_size_)); - CHECK(IsAligned(size, allocate_page_size_)); - size_t freed_size = region_allocator_.FreeRegion(start); - CHECK(IsAligned(freed_size, commit_page_size_)); - CHECK_EQ(RoundUp(freed_size, allocate_page_size_), size); - auto start_iter = page_permissions_.find(start); - CHECK_NE(start_iter, page_permissions_.end()); - auto end_iter = page_permissions_.lower_bound(start + size); - page_permissions_.erase(start_iter, end_iter); - } - return result; - } - - bool ReleasePages(void* address, size_t size, size_t new_size) override { - bool result = page_allocator_->ReleasePages(address, size, new_size); - if (result) { - Address start = reinterpret_cast<Address>(address); - CHECK(IsAligned(start, allocate_page_size_)); - CHECK(IsAligned(size, commit_page_size_)); - CHECK(IsAligned(new_size, commit_page_size_)); - CHECK_LT(new_size, size); - CHECK_EQ(region_allocator_.TrimRegion(start, new_size), size - new_size); - auto start_iter = page_permissions_.find(start + new_size); - CHECK_NE(start_iter, page_permissions_.end()); - auto end_iter = page_permissions_.lower_bound(start + size); - page_permissions_.erase(start_iter, end_iter); - } - return result; - } - - bool RecommitPages(void* address, size_t size, - PageAllocator::Permission access) override { - bool result = page_allocator_->RecommitPages(address, size, access); - if (result) { - // Check that given range had given access permissions. - CheckPagePermissions(reinterpret_cast<Address>(address), size, access, - {}); - UpdatePagePermissions(reinterpret_cast<Address>(address), size, access, - true); - } - return result; - } - - bool DiscardSystemPages(void* address, size_t size) override { - bool result = page_allocator_->DiscardSystemPages(address, size); - if (result) { - UpdatePagePermissions(reinterpret_cast<Address>(address), size, {}, - false); - } - return result; - } - - bool DecommitPages(void* address, size_t size) override { - bool result = page_allocator_->DecommitPages(address, size); - if (result) { - // Mark pages as non-accessible. - UpdatePagePermissions(reinterpret_cast<Address>(address), size, kNoAccess, - false); - } - return result; - } - - bool SetPermissions(void* address, size_t size, - PageAllocator::Permission access) override { - bool result = page_allocator_->SetPermissions(address, size, access); - if (result) { - bool committed = access != kNoAccess && access != kNoAccessWillJitLater; - UpdatePagePermissions(reinterpret_cast<Address>(address), size, access, - committed); - } - return result; - } - - // Returns true if all the allocated pages were freed. - bool IsEmpty() { return page_permissions_.empty(); } - - void CheckIsFree(Address address, size_t size) { - CHECK(IsAligned(address, allocate_page_size_)); - CHECK(IsAligned(size, allocate_page_size_)); - EXPECT_TRUE(region_allocator_.IsFree(address, size)); - } - - void CheckPagePermissions(Address address, size_t size, - PageAllocator::Permission access, - std::optional<bool> committed = {true}) { - CHECK_IMPLIES(committed.has_value() && committed.value(), - access != PageAllocator::kNoAccess); - ForEachPage(address, size, [=](PagePermissionsMap::value_type* value) { - if (committed.has_value()) { - EXPECT_EQ(committed.value(), value->second.committed); - } - EXPECT_EQ(access, value->second.access); - }); - } - - void Print(const char* comment) const { - i::StdoutStream os; - os << "\n=========================================" - << "\nTracingPageAllocator state: "; - if (comment) os << comment; - os << "\n-----------------------------------------\n"; - region_allocator_.Print(os); - os << "-----------------------------------------" - << "\nPage permissions:"; - if (page_permissions_.empty()) { - os << " empty\n"; - return; - } - os << "\n" << std::hex << std::showbase; - - Address contiguous_region_start = static_cast<Address>(-1); - Address contiguous_region_end = contiguous_region_start; - PageAllocator::Permission contiguous_region_access = - PageAllocator::kNoAccess; - bool contiguous_region_access_committed = false; - for (auto& pair : page_permissions_) { - if (contiguous_region_end == pair.first && - pair.second.access == contiguous_region_access && - pair.second.committed == contiguous_region_access_committed) { - contiguous_region_end += commit_page_size_; - continue; - } - if (contiguous_region_start != contiguous_region_end) { - PrintRegion(os, contiguous_region_start, contiguous_region_end, - contiguous_region_access, - contiguous_region_access_committed); - } - contiguous_region_start = pair.first; - contiguous_region_end = pair.first + commit_page_size_; - contiguous_region_access = pair.second.access; - contiguous_region_access_committed = pair.second.committed; - } - if (contiguous_region_start != contiguous_region_end) { - PrintRegion(os, contiguous_region_start, contiguous_region_end, - contiguous_region_access, contiguous_region_access_committed); - } - } - - private: - struct PageState { - PageAllocator::Permission access; - bool committed; - }; - using PagePermissionsMap = std::map<Address, PageState>; - using ForEachFn = std::function<void(PagePermissionsMap::value_type*)>; - - static void PrintRegion(std::ostream& os, Address start, Address end, - PageAllocator::Permission access, bool committed) { - os << " page: [" << start << ", " << end << "), access: "; - switch (access) { - case PageAllocator::kNoAccess: - case PageAllocator::kNoAccessWillJitLater: - os << "--"; - break; - case PageAllocator::kRead: - os << "R"; - break; - case PageAllocator::kReadWrite: - os << "RW"; - break; - case PageAllocator::kReadWriteExecute: - os << "RWX"; - break; - case PageAllocator::kReadExecute: - os << "RX"; - break; - } - os << ", committed: " << static_cast<int>(committed) << "\n"; - } - - void ForEachPage(Address address, size_t size, const ForEachFn& fn) { - CHECK(IsAligned(address, commit_page_size_)); - CHECK(IsAligned(size, commit_page_size_)); - auto start_iter = page_permissions_.find(address); - // Start page must exist in page_permissions_. - CHECK_NE(start_iter, page_permissions_.end()); - auto end_iter = page_permissions_.find(address + size - commit_page_size_); - // Ensure the last but one page exists in page_permissions_. - CHECK_NE(end_iter, page_permissions_.end()); - // Now make it point to the next element in order to also process is by the - // following for loop. - ++end_iter; - for (auto iter = start_iter; iter != end_iter; ++iter) { - PagePermissionsMap::value_type& pair = *iter; - fn(&pair); - } - } - - void UpdatePagePermissions(Address address, size_t size, - std::optional<PageAllocator::Permission> access, - bool committed) { - ForEachPage(address, size, [=](PagePermissionsMap::value_type* value) { - if (access.has_value()) { - value->second.access = access.value(); - } - value->second.committed = committed; - }); - } - - v8::PageAllocator* const page_allocator_; - const size_t allocate_page_size_; - const size_t commit_page_size_; - // Region allocator tracks page allocation/deallocation requests. - base::RegionAllocator region_allocator_; - // This map keeps track of allocated pages' permissions. - PagePermissionsMap page_permissions_; -}; - -// This test is currently incompatible with the sandbox. Enable it -// once the VirtualAddressSpace interface is stable. -#if !V8_OS_FUCHSIA && !V8_ENABLE_SANDBOX - -template <typename TMixin> -class PoolTestMixin : public TMixin { - public: - PoolTestMixin(); - ~PoolTestMixin() override; -}; - -class PoolTest : public // - WithInternalIsolateMixin< // - WithIsolateScopeMixin< // - WithIsolateMixin< // - PoolTestMixin< // - WithDefaultPlatformMixin< // - ::testing::Test>>>>> { - public: - PoolTest() = default; - ~PoolTest() override = default; - PoolTest(const PoolTest&) = delete; - PoolTest& operator=(const PoolTest&) = delete; - - static void DoMixinSetUp() { - CHECK_NULL(tracking_page_allocator_); - old_page_allocator_ = GetPlatformPageAllocator(); - tracking_page_allocator_ = new TrackingPageAllocator(old_page_allocator_); - CHECK(tracking_page_allocator_->IsEmpty()); - CHECK_EQ(old_page_allocator_, - SetPlatformPageAllocatorForTesting(tracking_page_allocator_)); - old_sweeping_flag_ = i::v8_flags.concurrent_sweeping; - i::v8_flags.concurrent_sweeping = false; - IsolateGroup::ReleaseDefault(); -#ifdef V8_ENABLE_SANDBOX - // Reinitialze the sandbox so it uses the TrackingPageAllocator. - Sandbox::current()->TearDown(); - constexpr bool use_guard_regions = false; - CHECK(Sandbox::current()->Initialize( - tracking_page_allocator_, kSandboxMinimumSize, use_guard_regions)); -#endif - IsolateGroup::InitializeOncePerProcess(); - } - - static void DoMixinTearDown() { - IsolateGroup::ReleaseDefault(); -#ifdef V8_ENABLE_SANDBOX - Sandbox::current()->TearDown(); -#endif - i::v8_flags.concurrent_sweeping = old_sweeping_flag_; - CHECK(tracking_page_allocator_->IsEmpty()); - - // Restore the original v8::PageAllocator and delete the tracking one. - CHECK_EQ(tracking_page_allocator_, - SetPlatformPageAllocatorForTesting(old_page_allocator_)); - delete tracking_page_allocator_; - tracking_page_allocator_ = nullptr; - - IsolateGroup::InitializeOncePerProcess(); - } - - Heap* heap() { return isolate()->heap(); } - MemoryAllocator* allocator() { return heap()->memory_allocator(); } - MemoryPool* pool() { return isolate()->isolate_group()->memory_pool(); } - - TrackingPageAllocator* tracking_page_allocator() { - return tracking_page_allocator_; - } - - private: - static TrackingPageAllocator* tracking_page_allocator_; - static v8::PageAllocator* old_page_allocator_; - static bool old_sweeping_flag_; -}; - -TrackingPageAllocator* PoolTest::tracking_page_allocator_ = nullptr; -v8::PageAllocator* PoolTest::old_page_allocator_ = nullptr; -bool PoolTest::old_sweeping_flag_; - -template <typename TMixin> -PoolTestMixin<TMixin>::PoolTestMixin() { - PoolTest::DoMixinSetUp(); -} -template <typename TMixin> -PoolTestMixin<TMixin>::~PoolTestMixin() { - PoolTest::DoMixinTearDown(); -} - -// See v8:5945. -TEST_F(PoolTest, UnmapOnTeardown) { - // Wait for the task to finish and disable rescheduling. - pool()->CancelAndWaitForTaskToFinishForTesting(); - - NormalPage* page = - allocator()->AllocatePage(MemoryAllocator::AllocationMode::kRegular, - static_cast<PagedSpace*>(heap()->old_space()), - Executability::NOT_EXECUTABLE); - Address chunk_address = page->ChunkAddress(); - EXPECT_NE(nullptr, page); - const size_t page_size = tracking_page_allocator()->AllocatePageSize(); - tracking_page_allocator()->CheckPagePermissions(chunk_address, page_size, - PageAllocator::kReadWrite); - - allocator()->Free(MemoryAllocator::FreeMode::kPool, page); - tracking_page_allocator()->CheckPagePermissions(chunk_address, page_size, - PageAllocator::kReadWrite); - pool()->ReleaseImmediately(i_isolate()); -#ifdef V8_COMPRESS_POINTERS - // In this mode Isolate uses bounded page allocator which allocates pages - // inside prereserved region. Thus these pages are kept reserved until - // the Isolate dies. - tracking_page_allocator()->CheckPagePermissions( - chunk_address, page_size, PageAllocator::kNoAccess, false); -#else - tracking_page_allocator()->CheckIsFree(chunk_address, page_size); -#endif // V8_COMPRESS_POINTERS - - // Wait for the task to finish and disable rescheduling. - pool()->ReenableTaskForTesting(); -} -#endif // !V8_OS_FUCHSIA && !V8_ENABLE_SANDBOX - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/heap/spaces-unittest.cc b/deps/v8/test/unittests/heap/spaces-unittest.cc index 61ce0caa3fa0..d678e1e01d9c 100644 --- a/deps/v8/test/unittests/heap/spaces-unittest.cc +++ b/deps/v8/test/unittests/heap/spaces-unittest.cc @@ -4,26 +4,127 @@ #include "src/heap/spaces.h" +#include <functional> +#include <map> #include <memory> - +#include <optional> +#include <vector> + +#include "include/v8-platform.h" +#include "src/base/bounded-page-allocator.h" +#include "src/base/macros.h" +#include "src/base/platform/platform.h" +#include "src/base/region-allocator.h" #include "src/common/globals.h" #include "src/execution/isolate.h" +#include "src/flags/flags.h" +#include "src/handles/handles.h" +#include "src/heap/allocation-result.h" +#include "src/heap/code-range.h" +#include "src/heap/free-list.h" #include "src/heap/heap-inl.h" #include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap.h" #include "src/heap/large-spaces.h" +#include "src/heap/main-allocator-inl.h" #include "src/heap/main-allocator.h" +#include "src/heap/memory-allocator.h" +#include "src/heap/memory-pool.h" #include "src/heap/mutable-page.h" +#include "src/heap/new-spaces.h" +#include "src/heap/paged-spaces.h" +#include "src/heap/read-only-spaces.h" +#include "src/heap/safepoint.h" #include "src/heap/spaces-inl.h" -#include "src/heap/trusted-range.h" +#include "src/heap/sweeper.h" +#include "src/init/isolate-group.h" +#include "src/objects/objects-inl.h" +#include "src/utils/allocation.h" +#include "src/utils/ostreams.h" +#include "test/common/flag-utils.h" +#include "test/unittests/heap/heap-utils.h" #include "test/unittests/test-utils.h" namespace v8 { namespace internal { -static Tagged<HeapObject> AllocateUnaligned(MainAllocator* allocator, - SpaceWithLinearArea* space, - int size) { +// The two scopes below must live in v8::internal::heap because Heap and +// MemoryAllocator befriend them under that name (see heap.h and +// memory-allocator.h). +namespace heap { + +// Temporarily sets a given allocator in an isolate. +class V8_NODISCARD TestMemoryAllocatorScope { + public: + TestMemoryAllocatorScope(Isolate* isolate, size_t max_capacity, + PageAllocator* page_allocator = nullptr) + : isolate_(isolate), + old_allocator_(std::move(isolate->heap()->memory_allocator_)) { + // Save the code pages for restoring them later on because the constructor + // of MemoryAllocator will change them. + isolate->GetCodePages()->swap(code_pages_); + PageAllocator* effective_allocator = + page_allocator != nullptr ? page_allocator : isolate->page_allocator(); + isolate->heap()->memory_allocator_ = std::make_unique<MemoryAllocator>( + isolate, effective_allocator, effective_allocator, + isolate->isolate_group()->memory_pool(), max_capacity); + if (page_allocator != nullptr) { + isolate->heap()->memory_allocator_->data_page_allocator_ = page_allocator; + } + } + + MemoryAllocator* allocator() { return isolate_->heap()->memory_allocator(); } + + ~TestMemoryAllocatorScope() { + isolate_->heap()->memory_allocator()->ReleasePooledChunksImmediately(); + isolate_->heap()->memory_allocator()->TearDown(); + isolate_->heap()->memory_allocator_.swap(old_allocator_); + isolate_->GetCodePages()->swap(code_pages_); + } + + TestMemoryAllocatorScope(const TestMemoryAllocatorScope&) = delete; + TestMemoryAllocatorScope& operator=(const TestMemoryAllocatorScope&) = delete; + + private: + Isolate* isolate_; + std::unique_ptr<MemoryAllocator> old_allocator_; + std::vector<MemoryRange> code_pages_; +}; + +// Temporarily sets a given code page allocator in an isolate. +class V8_NODISCARD TestCodePageAllocatorScope { + public: + TestCodePageAllocatorScope(Isolate* isolate, + v8::PageAllocator* code_page_allocator) + : isolate_(isolate), + old_code_page_allocator_( + isolate->heap()->memory_allocator()->code_page_allocator()) { + isolate->heap()->memory_allocator()->code_page_allocator_ = + code_page_allocator; + } + + ~TestCodePageAllocatorScope() { + isolate_->heap()->memory_allocator()->code_page_allocator_ = + old_code_page_allocator_; + } + TestCodePageAllocatorScope(const TestCodePageAllocatorScope&) = delete; + TestCodePageAllocatorScope& operator=(const TestCodePageAllocatorScope&) = + delete; + + private: + Isolate* isolate_; + v8::PageAllocator* old_code_page_allocator_; +}; + +} // namespace heap + +using heap::TestCodePageAllocatorScope; +using heap::TestMemoryAllocatorScope; + +namespace { + +Tagged<HeapObject> AllocateUnaligned(MainAllocator* allocator, + SpaceWithLinearArea* space, int size) { AllocationResult allocation = allocator->AllocateRaw(SafeHeapObjectSize(size), kTaggedAligned, AllocationOrigin::kRuntime, AllocationHint()); @@ -34,9 +135,8 @@ static Tagged<HeapObject> AllocateUnaligned(MainAllocator* allocator, return filler; } -static Tagged<HeapObject> AllocateUnaligned(OldLargeObjectSpace* allocator, - OldLargeObjectSpace* space, - int size) { +Tagged<HeapObject> AllocateUnaligned(OldLargeObjectSpace* allocator, + OldLargeObjectSpace* space, int size) { AllocationResult allocation = allocator->AllocateRaw( space->heap()->main_thread_local_heap(), size, AllocationHint()); CHECK(!allocation.IsFailure()); @@ -46,21 +146,219 @@ static Tagged<HeapObject> AllocateUnaligned(OldLargeObjectSpace* allocator, return filler; } -using SpacesTest = TestWithIsolate; +class Observer : public AllocationObserver { + public: + explicit Observer(intptr_t step_size) + : AllocationObserver(step_size), count_(0) {} + + void Step(int bytes_allocated, Address addr, size_t) override { count_++; } + + int count() const { return count_; } + + private: + int count_; +}; + +template <typename T, typename A> +void TestAllocationObserver(Isolate* i_isolate, T* space, A* allocator) { + Observer observer1(128); + i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); + allocator->AddAllocationObserver(&observer1); + + // The observer should not get notified if we have only allocated less than + // 128 bytes. + AllocateUnaligned(allocator, space, 64); + CHECK_EQ(observer1.count(), 0); + + // The observer should get called when we have allocated exactly 128 bytes. + AllocateUnaligned(allocator, space, 64); + CHECK_EQ(observer1.count(), 1); + + // Another >128 bytes should get another notification. + AllocateUnaligned(allocator, space, 136); + CHECK_EQ(observer1.count(), 2); + + // Allocating a large object should get only one notification. + AllocateUnaligned(allocator, space, 1024); + CHECK_EQ(observer1.count(), 3); + + // Allocating another 2048 bytes in small objects should get 16 + // notifications. + for (int i = 0; i < 64; ++i) { + AllocateUnaligned(allocator, space, 32); + } + CHECK_EQ(observer1.count(), 19); + + // Multiple observers should work. + Observer observer2(96); + i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); + allocator->AddAllocationObserver(&observer2); + + AllocateUnaligned(allocator, space, 2048); + CHECK_EQ(observer1.count(), 20); + CHECK_EQ(observer2.count(), 1); + + AllocateUnaligned(allocator, space, 104); + CHECK_EQ(observer1.count(), 20); + CHECK_EQ(observer2.count(), 2); + + // Callback should stop getting called after an observer is removed. + allocator->RemoveAllocationObserver(&observer1); + + AllocateUnaligned(allocator, space, 384); + CHECK_EQ(observer1.count(), 20); // no more notifications. + CHECK_EQ(observer2.count(), 3); // this one is still active. + + // Ensure that PauseInlineAllocationObserversScope work correctly. + AllocateUnaligned(allocator, space, 48); + CHECK_EQ(observer2.count(), 3); + { + i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); + PauseAllocationObserversScope pause_observers(i_isolate->heap()); + CHECK_EQ(observer2.count(), 3); + AllocateUnaligned(allocator, space, 384); + CHECK_EQ(observer2.count(), 3); + i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); + } + CHECK_EQ(observer2.count(), 3); + // Coupled with the 48 bytes allocated before the pause, another 48 bytes + // allocated here should trigger a notification. + AllocateUnaligned(allocator, space, 48); + CHECK_EQ(observer2.count(), 4); + + allocator->RemoveAllocationObserver(&observer2); + AllocateUnaligned(allocator, space, 384); + CHECK_EQ(observer1.count(), 20); + CHECK_EQ(observer2.count(), 4); +} + +void VerifyMemoryChunk(Isolate* isolate, v8::PageAllocator* code_page_allocator, + size_t area_size, Executability executable, + LargeObjectSpace* space) { + Heap* heap = isolate->heap(); + TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); + MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); + TestCodePageAllocatorScope test_code_page_allocator_scope( + isolate, code_page_allocator); + + v8::PageAllocator* page_allocator = + memory_allocator->page_allocator(space->identity()); + + size_t allocatable_memory_area_offset = + MemoryChunkLayout::ObjectStartOffsetInMemoryChunk(space->identity()); + + MutablePage* memory_chunk = memory_allocator->AllocateLargePage( + space, area_size, executable, AllocationHint()); + ASSERT_NE(nullptr, memory_chunk); + size_t reserved_size = + (executable == EXECUTABLE) + ? RoundUp(allocatable_memory_area_offset + + RoundUp(area_size, page_allocator->CommitPageSize()), + page_allocator->CommitPageSize()) + : RoundUp(allocatable_memory_area_offset + area_size, + page_allocator->CommitPageSize()); + CHECK_EQ(memory_chunk->size(), reserved_size); + CHECK_LT(memory_chunk->area_start(), + memory_chunk->ChunkAddress() + memory_chunk->size()); + CHECK_LE(memory_chunk->area_end(), + memory_chunk->ChunkAddress() + memory_chunk->size()); + CHECK_EQ(static_cast<size_t>(memory_chunk->area_size()), area_size); + + memory_allocator->Free(MemoryAllocator::FreeMode::kImmediately, memory_chunk); +} + +unsigned int PseudorandomAreaSize() { + static uint32_t lo = 2345; + lo = 18273 * (lo & 0xFFFFF) + (lo >> 16); + return lo & 0xFFFFF; +} + +template <typename TMixin> +class WithSmallHeapFlagsMixin : public TMixin { + public: + WithSmallHeapFlagsMixin() { + v8_flags.max_heap_size = 20; + // These tests use their own old/large object space, which confuses the + // incremental marker. + v8_flags.incremental_marking = false; + // These tests don't expect GCs caused by concurrent allocations in the + // background thread. + v8_flags.stress_concurrent_allocation = false; + } + + private: + SaveFlags save_flags_; +}; + +// PageAllocator that always fails. +class FailingPageAllocator : public v8::PageAllocator { + public: + size_t AllocatePageSize() override { return 1024; } + size_t CommitPageSize() override { return 1024; } + void SetRandomMmapSeed(int64_t seed) override {} + void* GetRandomMmapAddr() override { return nullptr; } + void* AllocatePages(void* address, size_t length, size_t alignment, + Permission permissions) override { + return nullptr; + } + bool FreePages(void* address, size_t length) override { return false; } + bool ReleasePages(void* address, size_t length, size_t new_length) override { + return false; + } + bool SetPermissions(void* address, size_t length, + Permission permissions) override { + return false; + } + bool RecommitPages(void* address, size_t length, + Permission permissions) override { + return false; + } + bool DecommitPages(void* address, size_t length) override { return false; } + bool SealPages(void* address, size_t length) override { return false; } +}; + +// ReadOnlySpace cannot be torn down by a destructor because the destructor +// cannot take an argument. Since these tests create ReadOnlySpaces not attached +// to the Heap directly, they need to be destroyed to ensure the +// MemoryAllocator's stats are all 0 at exit. +class V8_NODISCARD ReadOnlySpaceScope { + public: + explicit ReadOnlySpaceScope(Heap* heap) : heap_(heap), ro_space_(heap) {} + ~ReadOnlySpaceScope() { ro_space_.TearDown(heap_->memory_allocator()); } + + ReadOnlySpace* space() { return &ro_space_; } + + private: + Heap* heap_; + ReadOnlySpace ro_space_; +}; + +} // namespace + +using SpacesTest = TestWithHeapInternals; + +using SpacesTestWithSmallHeap = // + WithHeapInternals< // + WithInternalIsolateMixin< // + WithIsolateScopeMixin< // + WithIsolateMixin< // + WithCppHeap< // + WithDefaultPlatformMixin< // + WithSmallHeapFlagsMixin< // + ::testing::Test>>>>>>>; TEST_F(SpacesTest, CompactionSpaceMerge) { Heap* heap = i_isolate()->heap(); OldSpace* old_space = heap->old_space(); - EXPECT_TRUE(old_space != nullptr); + ASSERT_NE(nullptr, old_space); heap->SetGCState(Heap::MARK_COMPACT); - CompactionSpace* compaction_space = - new CompactionSpace(heap, OLD_SPACE, NOT_EXECUTABLE, - CompactionSpaceKind::kCompactionSpaceForMarkCompact, - CompactionSpace::DestinationHeap::kSameHeap); - MainAllocator allocator(heap, compaction_space, MainAllocator::kInGC); - EXPECT_TRUE(compaction_space != nullptr); + auto compaction_space = std::make_unique<CompactionSpace>( + heap, OLD_SPACE, NOT_EXECUTABLE, + CompactionSpaceKind::kCompactionSpaceForMarkCompact, + CompactionSpace::DestinationHeap::kSameHeap); + MainAllocator allocator(heap, compaction_space.get(), MainAllocator::kInGC); for (NormalPage* p : *old_space) { // Unlink free lists from the main space to avoid reusing the memory for @@ -88,11 +386,11 @@ TEST_F(SpacesTest, CompactionSpaceMerge) { int pages_in_compaction_space = compaction_space->CountTotalPages(); EXPECT_EQ(kExpectedPages, pages_in_compaction_space); allocator.FreeLinearAllocationArea(); - old_space->MergeCompactionSpace(compaction_space); + old_space->MergeCompactionSpace(compaction_space.get()); EXPECT_EQ(pages_in_old_space + pages_in_compaction_space, old_space->CountTotalPages()); - delete compaction_space; + compaction_space.reset(); heap->SetGCState(Heap::NOT_IN_GC); } @@ -101,7 +399,7 @@ TEST_F(SpacesTest, WriteBarriers) { // Test allocates a real page in OLD_SPACE to check various flag combinaton. Heap* heap = i_isolate()->heap(); OldSpace* old_space = heap->old_space(); - EXPECT_TRUE(old_space != nullptr); + ASSERT_NE(nullptr, old_space); for (NormalPage* p : *old_space) { // Unlink free lists from the main space to avoid reusing the memory for @@ -111,10 +409,10 @@ TEST_F(SpacesTest, WriteBarriers) { heap->SetGCState(Heap::MARK_COMPACT); { - std::unique_ptr<CompactionSpace> compaction_space( - new CompactionSpace(heap, OLD_SPACE, NOT_EXECUTABLE, - CompactionSpaceKind::kCompactionSpaceForMarkCompact, - CompactionSpace::DestinationHeap::kSameHeap)); + auto compaction_space = std::make_unique<CompactionSpace>( + heap, OLD_SPACE, NOT_EXECUTABLE, + CompactionSpaceKind::kCompactionSpaceForMarkCompact, + CompactionSpace::DestinationHeap::kSameHeap); EXPECT_TRUE(compaction_space); MainAllocator allocator(heap, compaction_space.get(), MainAllocator::kInGC); @@ -284,120 +582,30 @@ TEST_F(SpacesTest, } } -class Observer : public AllocationObserver { - public: - explicit Observer(intptr_t step_size) - : AllocationObserver(step_size), count_(0) {} - - void Step(int bytes_allocated, Address addr, size_t) override { count_++; } - - int count() const { return count_; } - - private: - int count_; -}; - -template <typename T, typename A> -void testAllocationObserver(Isolate* i_isolate, T* space, A* allocator) { - Observer observer1(128); - i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); - allocator->AddAllocationObserver(&observer1); - - // The observer should not get notified if we have only allocated less than - // 128 bytes. - AllocateUnaligned(allocator, space, 64); - CHECK_EQ(observer1.count(), 0); - - // The observer should get called when we have allocated exactly 128 bytes. - AllocateUnaligned(allocator, space, 64); - CHECK_EQ(observer1.count(), 1); - - // Another >128 bytes should get another notification. - AllocateUnaligned(allocator, space, 136); - CHECK_EQ(observer1.count(), 2); - - // Allocating a large object should get only one notification. - AllocateUnaligned(allocator, space, 1024); - CHECK_EQ(observer1.count(), 3); - - // Allocating another 2048 bytes in small objects should get 16 - // notifications. - for (int i = 0; i < 64; ++i) { - AllocateUnaligned(allocator, space, 32); - } - CHECK_EQ(observer1.count(), 19); - - // Multiple observers should work. - Observer observer2(96); - i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); - allocator->AddAllocationObserver(&observer2); - - AllocateUnaligned(allocator, space, 2048); - CHECK_EQ(observer1.count(), 20); - CHECK_EQ(observer2.count(), 1); - - AllocateUnaligned(allocator, space, 104); - CHECK_EQ(observer1.count(), 20); - CHECK_EQ(observer2.count(), 2); - - // Callback should stop getting called after an observer is removed. - allocator->RemoveAllocationObserver(&observer1); - - AllocateUnaligned(allocator, space, 384); - CHECK_EQ(observer1.count(), 20); // no more notifications. - CHECK_EQ(observer2.count(), 3); // this one is still active. - - // Ensure that PauseInlineAllocationObserversScope work correctly. - AllocateUnaligned(allocator, space, 48); - CHECK_EQ(observer2.count(), 3); - { - i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); - PauseAllocationObserversScope pause_observers(i_isolate->heap()); - CHECK_EQ(observer2.count(), 3); - AllocateUnaligned(allocator, space, 384); - CHECK_EQ(observer2.count(), 3); - i_isolate->heap()->FreeMainThreadLinearAllocationAreas(); - } - CHECK_EQ(observer2.count(), 3); - // Coupled with the 48 bytes allocated before the pause, another 48 bytes - // allocated here should trigger a notification. - AllocateUnaligned(allocator, space, 48); - CHECK_EQ(observer2.count(), 4); - - allocator->RemoveAllocationObserver(&observer2); - AllocateUnaligned(allocator, space, 384); - CHECK_EQ(observer1.count(), 20); - CHECK_EQ(observer2.count(), 4); -} - TEST_F(SpacesTest, AllocationObserver) { if (v8_flags.single_generation) return; - v8::Isolate::Scope isolate_scope(v8_isolate()); - v8::HandleScope handle_scope(v8_isolate()); - v8::Context::New(v8_isolate())->Enter(); + v8::Context::Scope context_scope(v8::Context::New(v8_isolate())); - testAllocationObserver<NewSpace>( + TestAllocationObserver<NewSpace>( i_isolate(), i_isolate()->heap()->new_space(), i_isolate()->heap()->allocator()->new_space_allocator()); // Old space is used but the code path is shared for all // classes inheriting from PagedSpace. - testAllocationObserver<PagedSpace>( + TestAllocationObserver<PagedSpace>( i_isolate(), i_isolate()->heap()->old_space(), i_isolate()->heap()->allocator()->old_space_allocator()); - testAllocationObserver<OldLargeObjectSpace>(i_isolate(), + TestAllocationObserver<OldLargeObjectSpace>(i_isolate(), i_isolate()->heap()->lo_space(), i_isolate()->heap()->lo_space()); } TEST_F(SpacesTest, InlineAllocationObserverCadence) { if (v8_flags.single_generation) return; - v8::Isolate::Scope isolate_scope(v8_isolate()); - v8::HandleScope handle_scope(v8_isolate()); - v8::Context::New(v8_isolate())->Enter(); + v8::Context::Scope context_scope(v8::Context::New(v8_isolate())); // Clear out any pre-existing garbage to make the test consistent // across snapshot/no-snapshot builds. - InvokeMajorGC(i_isolate()); + InvokeMajorGC(); MainAllocator* new_space_allocator = i_isolate()->heap()->allocator()->new_space_allocator(); @@ -424,9 +632,7 @@ TEST_F(SpacesTest, TrustedSpaceNullPage) { // Trusted space should have a reserved, inaccessible area at the start to // mitigate (compressed) nullptr dereference bugs. - v8::Isolate::Scope isolate_scope(v8_isolate()); - v8::HandleScope handle_scope(v8_isolate()); - v8::Context::New(v8_isolate())->Enter(); + v8::Context::Scope context_scope(v8::Context::New(v8_isolate())); Address trusted_space_base = i_isolate()->isolate_group()->GetTrustedPtrComprCageBase(); @@ -456,5 +662,968 @@ TEST_F(SpacesTest, TrustedSpaceNullPage) { } #endif // V8_ENABLE_SANDBOX +TEST_F(SpacesTest, MutablePage) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + IsolateSafepointScope safepoint(heap); + + v8::PageAllocator* page_allocator = GetPlatformPageAllocator(); + size_t area_size; + + for (int i = 0; i < 100; i++) { + area_size = + RoundUp(PseudorandomAreaSize(), page_allocator->CommitPageSize()); + + const size_t code_range_size = 32 * MB; +#ifdef V8_ENABLE_SANDBOX + // When the sandbox is enabled, the code assumes that there's only a single + // code range for easy metadata lookup, so use the process wide code range + // in this case. + CodeRange* code_range = + IsolateGroup::current()->EnsureCodeRange(code_range_size); + base::BoundedPageAllocator* bounded_page_allocator = + code_range->page_allocator(); +#else + // With CodeRange. + bool jitless = isolate->jitless(); + VirtualMemory code_range_reservation( + page_allocator, code_range_size, PageAllocator::AllocationHint(), + MemoryChunk::GetAlignmentForAllocation(), + jitless ? PageAllocator::Permission::kNoAccess + : PageAllocator::Permission::kNoAccessWillJitLater); + + base::PageInitializationMode page_initialization_mode = + base::PageInitializationMode::kAllocatedPagesCanBeUninitialized; + base::PageFreeingMode page_freeing_mode = + base::PageFreeingMode::kMakeInaccessible; + + if (!jitless) { + page_initialization_mode = base::PageInitializationMode::kRecommitOnly; + page_freeing_mode = base::PageFreeingMode::kDiscard; + void* base = reinterpret_cast<void*>(code_range_reservation.address()); + CHECK(page_allocator->SetPermissions(base, code_range_size, + PageAllocator::kReadWriteExecute)); + CHECK(page_allocator->DiscardSystemPages(base, code_range_size)); + } + + CHECK(code_range_reservation.IsReserved()); + + base::BoundedPageAllocator code_page_allocator( + page_allocator, code_range_reservation.address(), + code_range_reservation.size(), MemoryChunk::GetAlignmentForAllocation(), + page_initialization_mode, page_freeing_mode); + base::BoundedPageAllocator* bounded_page_allocator = &code_page_allocator; +#endif + + VerifyMemoryChunk(isolate, bounded_page_allocator, area_size, EXECUTABLE, + heap->code_lo_space()); + + VerifyMemoryChunk(isolate, bounded_page_allocator, area_size, + NOT_EXECUTABLE, heap->lo_space()); + } +} + +TEST_F(SpacesTest, MemoryAllocator) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + + TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); + MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); + + int total_pages = 0; + OldSpace faked_space(heap); + CHECK(!faked_space.first_page()); + CHECK(!faked_space.last_page()); + NormalPage* first_page = memory_allocator->AllocatePage( + MemoryAllocator::AllocationMode::kRegular, &faked_space, NOT_EXECUTABLE); + ASSERT_NE(nullptr, first_page); + + faked_space.memory_chunk_list().PushBack(first_page); + CHECK_NULL(first_page->next_page()); + total_pages++; + + for (NormalPage* p = first_page; p != nullptr; p = p->next_page()) { + CHECK_EQ(p->owner(), &faked_space); + } + + // Again, we should get n or n - 1 pages. + NormalPage* other = memory_allocator->AllocatePage( + MemoryAllocator::AllocationMode::kRegular, &faked_space, NOT_EXECUTABLE); + total_pages++; + faked_space.memory_chunk_list().PushBack(other); + int page_count = 0; + for (NormalPage* p = first_page; p != nullptr; p = p->next_page()) { + CHECK_EQ(p->owner(), &faked_space); + page_count++; + } + CHECK_EQ(total_pages, page_count); + + NormalPage* second_page = first_page->next_page(); + CHECK_NOT_NULL(second_page); + + // OldSpace's destructor will tear down the space and free up all pages. +} + +TEST_F(SpacesTest, ComputeDiscardMemoryAreas) { + std::optional<base::AddressRegion> discard_area; + size_t page_size = MemoryAllocator::GetCommitPageSize(); + + discard_area = Sweeper::ComputeDiscardMemoryArea(0, 0); + CHECK(!discard_area); + + discard_area = Sweeper::ComputeDiscardMemoryArea(0, page_size); + CHECK_EQ(discard_area->begin(), 0); + CHECK_EQ(discard_area->size(), page_size); + + discard_area = Sweeper::ComputeDiscardMemoryArea(page_size, 2 * page_size); + CHECK_EQ(discard_area->begin(), page_size); + CHECK_EQ(discard_area->size(), page_size); + + discard_area = + Sweeper::ComputeDiscardMemoryArea(page_size - kTaggedSize, 2 * page_size); + CHECK_EQ(discard_area->begin(), page_size); + CHECK_EQ(discard_area->size(), page_size); + + discard_area = + Sweeper::ComputeDiscardMemoryArea(page_size, 2 * page_size + kTaggedSize); + CHECK_EQ(discard_area->begin(), page_size); + CHECK_EQ(discard_area->size(), page_size); + + discard_area = Sweeper::ComputeDiscardMemoryArea(page_size, page_size); + CHECK(!discard_area); + + discard_area = Sweeper::ComputeDiscardMemoryArea(page_size / 2, + page_size + page_size / 2); + CHECK(!discard_area); + + discard_area = Sweeper::ComputeDiscardMemoryArea(page_size / 2, + page_size + page_size / 4); + CHECK(!discard_area); + + discard_area = + Sweeper::ComputeDiscardMemoryArea(page_size / 2, page_size * 3); + CHECK_EQ(discard_area->begin(), page_size); + CHECK_EQ(discard_area->size(), page_size * 2); +} + +TEST_F(SpacesTest, SemiSpaceNewSpace) { + if (v8_flags.single_generation) return; + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); + MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); + LinearAllocationArea allocation_info; + + auto new_space = std::make_unique<SemiSpaceNewSpace>( + heap, heap->InitialSemiSpaceSize(), heap->InitialSemiSpaceSize(), + heap->InitialSemiSpaceSize()); + MainAllocator allocator(heap->main_thread_local_heap(), new_space.get(), + MainAllocator::kNewGeneration, &allocation_info); + CHECK(new_space->MaximumCapacity()); + + size_t successful_allocations = 0; + while (new_space->Available() >= kMaxRegularHeapObjectSize) { + AllocationResult allocation = allocator.AllocateRaw( + SafeHeapObjectSize(kMaxRegularHeapObjectSize), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + if (allocation.IsFailure()) break; + successful_allocations++; + Tagged<Object> obj = allocation.ToObjectChecked(); + Tagged<HeapObject> ho = Cast<HeapObject>(obj); + CHECK(new_space->Contains(ho)); + } + CHECK_LT(0, successful_allocations); + + new_space.reset(); + memory_allocator->ReleasePooledChunksImmediately(); +} + +TEST_F(SpacesTest, PagedNewSpace) { + if (v8_flags.single_generation) return; + ManualGCScope manual_gc_scope(i_isolate()); + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); + MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); + LinearAllocationArea allocation_info; + + auto new_space = std::make_unique<PagedNewSpace>( + heap, heap->InitialSemiSpaceSize(), heap->InitialSemiSpaceSize(), + heap->InitialSemiSpaceSize()); + MainAllocator allocator(heap->main_thread_local_heap(), new_space.get(), + MainAllocator::kNewGeneration, &allocation_info); + GrowNewSpaceToMaximumCapacity(); + + size_t successful_allocations = 0; + while (true) { + AllocationResult allocation = allocator.AllocateRaw( + SafeHeapObjectSize(kMaxRegularHeapObjectSize), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + if (allocation.IsFailure()) break; + successful_allocations++; + Tagged<Object> obj = allocation.ToObjectChecked(); + Tagged<HeapObject> ho = Cast<HeapObject>(obj); + CHECK(new_space->Contains(ho)); + } + CHECK_LT(0, successful_allocations); + + new_space.reset(); + memory_allocator->ReleasePooledChunksImmediately(); +} + +TEST_F(SpacesTestWithSmallHeap, OldSpace) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + TestMemoryAllocatorScope test_allocator_scope(isolate, heap->MaxReserved()); + LinearAllocationArea allocation_info; + + auto old_space = std::make_unique<OldSpace>(heap); + MainAllocator allocator(heap->main_thread_local_heap(), old_space.get(), + MainAllocator::kOldGeneration, &allocation_info); + const int obj_size = kMaxRegularHeapObjectSize; + + size_t successful_allocations = 0; + + while (true) { + AllocationResult allocation = + allocator.AllocateRaw(SafeHeapObjectSize(obj_size), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + if (allocation.IsFailure()) break; + successful_allocations++; + Tagged<Object> obj = allocation.ToObjectChecked(); + Tagged<HeapObject> ho = Cast<HeapObject>(obj); + CHECK(old_space->Contains(ho)); + } + CHECK_LT(0, successful_allocations); +} + +TEST_F(SpacesTestWithSmallHeap, OldLargeObjectSpace) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + + auto lo = std::make_unique<OldLargeObjectSpace>(heap); + // Handles must not outlive the detached space they point into. + HandleScope handle_scope(isolate); + const int lo_size = NormalPage::kPageSize; + + Tagged<Map> map = ReadOnlyRoots(isolate).fixed_double_array_map(); + size_t successful_allocations = 0; + + while (true) { + AllocationResult allocation = lo->AllocateRaw( + heap->main_thread_local_heap(), lo_size, AllocationHint()); + if (allocation.IsFailure()) break; + successful_allocations++; + Tagged<Object> obj = allocation.ToObjectChecked(); + CHECK(IsHeapObject(obj)); + Tagged<HeapObject> ho = Cast<HeapObject>(obj); + CHECK(lo->Contains(ho)); + CHECK_EQ(0, MainAllocator::GetFillToAlign(ho.address(), kTaggedAligned)); + // All large objects have the same alignment because they start at the + // same offset within a page. Fixed double arrays have the most strict + // alignment requirements. + CHECK_EQ(0, MainAllocator::GetFillToAlign( + ho.address(), + HeapObject::RequiredAlignment(lo->identity(), map))); + DirectHandle<HeapObject> keep_alive(ho, isolate); + } + CHECK_LT(0, successful_allocations); + + CHECK(!lo->IsEmpty()); + CHECK( + lo->AllocateRaw(heap->main_thread_local_heap(), lo_size, AllocationHint()) + .IsFailure()); +} + +#ifndef DEBUG +// The test verifies that committed size of a space is less then some threshold. +// Debug builds pull in all sorts of additional instrumentation that increases +// heap sizes. E.g. CSA_DCHECK creates on-heap strings for error messages. These +// messages are also not stable if files are moved and modified during the build +// process (jumbo builds). +TEST_F(SpacesTest, SizeOfInitialHeap) { + Isolate* isolate = i_isolate(); + // Bootstrapping without a snapshot causes more allocations. + if (!isolate->snapshot_available()) return; + ManualGCScope manual_gc_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); + v8::Context::Scope context_scope(context); + // Skip this test on the custom snapshot builder. + if (!context->Global() + ->Get(context, NewString("assertEquals")) + .ToLocalChecked() + ->IsUndefined()) { + return; + } + // Initial size of LO_SPACE + size_t initial_lo_space = isolate->heap()->lo_space()->Size(); + +// The limit for each space for an empty isolate containing just the +// snapshot. +// In PPC the page size is 64K, causing more internal fragmentation +// hence requiring a larger limit. +#if V8_OS_LINUX && V8_HOST_ARCH_PPC64 + const size_t kMaxInitialSizePerSpace = 3 * MB; +#else + const size_t kMaxInitialSizePerSpace = 2 * MB; +#endif + + // Freshly initialized VM gets by with the snapshot size (which is below + // kMaxInitialSizePerSpace per space). + Heap* heap = isolate->heap(); + for (int i = FIRST_GROWABLE_PAGED_SPACE; i <= LAST_GROWABLE_PAGED_SPACE; + i++) { + if (!heap->paged_space(i)) continue; + + // Debug code can be very large, so skip CODE_SPACE if we are generating it. + if (i == CODE_SPACE && i::v8_flags.debug_code) continue; + + // Check that the initial heap is also below the limit. + CHECK_LE(heap->paged_space(i)->CommittedMemory(), kMaxInitialSizePerSpace); + } + + RunJS("/*empty*/"); + + // No large objects required to perform the above steps. + CHECK_EQ(initial_lo_space, + static_cast<size_t>(isolate->heap()->lo_space()->Size())); +} +#endif // DEBUG + +TEST_F(SpacesTest, Regress777177) { + SaveFlags save_flags; + v8_flags.stress_concurrent_allocation = false; // For SimulateFullSpace. + v8::Context::Scope context_scope(v8::Context::New(v8_isolate())); + Heap* heap = i_isolate()->heap(); + OldSpace* old_space = heap->old_space(); + MainAllocator* old_space_allocator = heap->allocator()->old_space_allocator(); + Observer observer(128); + old_space_allocator->FreeLinearAllocationArea(); + old_space_allocator->AddAllocationObserver(&observer); + + int area_size = old_space->AreaSize(); + int max_object_size = kMaxRegularHeapObjectSize; + int filler_size = area_size - max_object_size; + + { + // Ensure a new linear allocation area on a fresh page. + AlwaysAllocateScopeForTesting always_allocate(heap); + SimulateFullSpace(old_space); + AllocationResult result = old_space_allocator->AllocateRaw( + SafeHeapObjectSize(filler_size), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + Tagged<HeapObject> obj = result.ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), filler_size); + } + + { + // Allocate all bytes of the linear allocation area. This moves top_ and + // top_on_previous_step_ to the next page. + AllocationResult result = old_space_allocator->AllocateRaw( + SafeHeapObjectSize(max_object_size), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + Tagged<HeapObject> obj = result.ToObjectChecked(); + // Simulate allocation folding moving the top pointer back. + old_space_allocator->ResetLab( + obj.address(), heap->allocator()->old_space_allocator()->limit(), + heap->allocator()->old_space_allocator()->limit()); + } + + { + // This triggers assert in crbug.com/777177. + AllocationResult result = old_space_allocator->AllocateRaw( + SafeHeapObjectSize(filler_size), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + Tagged<HeapObject> obj = result.ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), filler_size); + } + old_space_allocator->RemoveAllocationObserver(&observer); +} + +TEST_F(SpacesTest, Regress791582) { + if (v8_flags.single_generation) return; + v8::Context::Scope context_scope(v8::Context::New(v8_isolate())); + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + MainAllocator* new_space_allocator = heap->allocator()->new_space_allocator(); + GrowNewSpaceToMaximumCapacity(); + + int until_page_end = + static_cast<int>(heap->NewSpaceLimit() - heap->NewSpaceTop()); + + if (!IsAligned(until_page_end, kTaggedSize)) { + // The test works if the size of allocation area size is a multiple of + // pointer size. This is usually the case unless some allocation observer + // is already active (e.g. incremental marking observer). + return; + } + + Observer observer(128); + new_space_allocator->FreeLinearAllocationArea(); + new_space_allocator->AddAllocationObserver(&observer); + + { + AllocationResult result = new_space_allocator->AllocateRaw( + SafeHeapObjectSize(until_page_end), kTaggedAligned, + AllocationOrigin::kRuntime, AllocationHint()); + Tagged<HeapObject> obj = result.ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), until_page_end); + // Simulate allocation folding moving the top pointer back. + LinearAllocationArea* new_space = + &isolate->isolate_data()->new_allocation_info(); + *new_space->top_address() = obj.address(); + } + + { + // This triggers assert in crbug.com/791582 + AllocationResult result = new_space_allocator->AllocateRaw( + SafeHeapObjectSize(256), kTaggedAligned, AllocationOrigin::kRuntime, + AllocationHint()); + Tagged<HeapObject> obj = result.ToObjectChecked(); + heap->CreateFillerObjectAt(obj.address(), 256); + } + new_space_allocator->RemoveAllocationObserver(&observer); +} + +TEST_F(SpacesTest, NoMemoryForNewPage) { + Isolate* isolate = i_isolate(); + Heap* heap = isolate->heap(); + + // Memory allocator that will fail to allocate any pages. + FailingPageAllocator failing_allocator; + TestMemoryAllocatorScope test_allocator_scope(isolate, 0, &failing_allocator); + MemoryAllocator* memory_allocator = test_allocator_scope.allocator(); + OldSpace faked_space(heap); + NormalPage* page = memory_allocator->AllocatePage( + MemoryAllocator::AllocationMode::kRegular, &faked_space, NOT_EXECUTABLE); + + CHECK_NULL(page); +} + +TEST_F(SpacesTest, ReadOnlySpaceMetrics_OnePage) { + // Create a read-only space and allocate some memory, shrink the pages and + // check the allocated object size is as expected. + + ReadOnlySpaceScope scope(heap()); + ReadOnlySpace* faked_space = scope.space(); + + // Initially no memory. + CHECK_EQ(faked_space->Size(), 0); + CHECK_EQ(faked_space->Capacity(), 0); + CHECK_EQ(faked_space->CommittedMemory(), 0); + CHECK_EQ(faked_space->CommittedPhysicalMemory(), 0); + + faked_space->AllocateRaw(16, kTaggedAligned); + + faked_space->ShrinkPages(); + faked_space->Seal(ReadOnlySpace::SealMode::kDoNotDetachFromHeap); + + // Allocated objects size. + CHECK_EQ(faked_space->Size(), 16); + + size_t committed_memory = RoundUp( + MemoryChunkLayout::ObjectStartOffsetInDataPage() + faked_space->Size(), + MemoryAllocator::GetCommitPageSize()); + + // Amount of OS allocated memory. + CHECK_EQ(faked_space->CommittedMemory(), committed_memory); + CHECK_EQ(faked_space->CommittedPhysicalMemory(), committed_memory); + + // Capacity will be one OS page minus the page header. + CHECK_EQ(faked_space->Capacity(), + committed_memory - MemoryChunkLayout::ObjectStartOffsetInDataPage()); +} + +TEST_F(SpacesTest, ReadOnlySpaceMetrics_AlignedAllocations) { + // Create a read-only space and allocate some memory, shrink the pages and + // check the allocated object size is as expected. + + ReadOnlySpaceScope scope(heap()); + ReadOnlySpace* faked_space = scope.space(); + + // Initially no memory. + CHECK_EQ(faked_space->Size(), 0); + CHECK_EQ(faked_space->Capacity(), 0); + CHECK_EQ(faked_space->CommittedMemory(), 0); + CHECK_EQ(faked_space->CommittedPhysicalMemory(), 0); + + // Allocate an object just under an OS page in size. + int object_size = + static_cast<int>(MemoryAllocator::GetCommitPageSize() - kApiTaggedSize); + + const int kExpectedAlignment = kDoubleSize; + + Tagged<HeapObject> object = + faked_space->AllocateRaw(object_size, kDoubleAligned).ToObjectChecked(); + CHECK_EQ(object.address() % kExpectedAlignment, 0); + object = + faked_space->AllocateRaw(object_size, kDoubleAligned).ToObjectChecked(); + CHECK_EQ(object.address() % kExpectedAlignment, 0); + + // Calculate size of allocations based on area_start. + Address area_start = faked_space->pages().back()->GetAreaStart(); + Address top = RoundUp(area_start, kExpectedAlignment) + object_size; + top = RoundUp(top, kExpectedAlignment) + object_size; + size_t expected_size = top - area_start; + + faked_space->ShrinkPages(); + faked_space->Seal(ReadOnlySpace::SealMode::kDoNotDetachFromHeap); + + // Allocated objects size may will contain 4 bytes of padding on 32-bit or + // with pointer compression. + CHECK_EQ(faked_space->Size(), expected_size); + + size_t committed_memory = RoundUp( + MemoryChunkLayout::ObjectStartOffsetInDataPage() + faked_space->Size(), + MemoryAllocator::GetCommitPageSize()); + + CHECK_EQ(faked_space->CommittedMemory(), committed_memory); + CHECK_EQ(faked_space->CommittedPhysicalMemory(), committed_memory); + + // Capacity will be 3 OS pages minus the page header. + CHECK_EQ(faked_space->Capacity(), + committed_memory - MemoryChunkLayout::ObjectStartOffsetInDataPage()); +} + +TEST_F(SpacesTest, ReadOnlySpaceMetrics_TwoPages) { + // Create a read-only space and allocate some memory, shrink the pages and + // check the allocated object size is as expected. + + ReadOnlySpaceScope scope(heap()); + ReadOnlySpace* faked_space = scope.space(); + + // Initially no memory. + CHECK_EQ(faked_space->Size(), 0); + CHECK_EQ(faked_space->Capacity(), 0); + CHECK_EQ(faked_space->CommittedMemory(), 0); + CHECK_EQ(faked_space->CommittedPhysicalMemory(), 0); + + // Allocate an object that's too big to have more than one on a page. + + int object_size = RoundUp( + static_cast<int>( + MemoryChunkLayout::AllocatableMemoryInMemoryChunk(RO_SPACE) / 2 + 16), + kTaggedSize); + CHECK_GT(object_size * 2, + MemoryChunkLayout::AllocatableMemoryInMemoryChunk(RO_SPACE)); + faked_space->AllocateRaw(object_size, kTaggedAligned); + + // Then allocate another so it expands the space to two pages. + faked_space->AllocateRaw(object_size, kTaggedAligned); + + faked_space->ShrinkPages(); + faked_space->Seal(ReadOnlySpace::SealMode::kDoNotDetachFromHeap); + + // Allocated objects size. + CHECK_EQ(faked_space->Size(), object_size * 2); + + // Amount of OS allocated memory. + size_t committed_memory_per_page = + RoundUp(MemoryChunkLayout::ObjectStartOffsetInDataPage() + object_size, + MemoryAllocator::GetCommitPageSize()); + CHECK_EQ(faked_space->CommittedMemory(), 2 * committed_memory_per_page); + CHECK_EQ(faked_space->CommittedPhysicalMemory(), + 2 * committed_memory_per_page); + + // Capacity will be the space up to the amount of committed memory minus the + // page headers. + size_t capacity_per_page = + RoundUp(MemoryChunkLayout::ObjectStartOffsetInDataPage() + object_size, + MemoryAllocator::GetCommitPageSize()) - + MemoryChunkLayout::ObjectStartOffsetInDataPage(); + CHECK_EQ(faked_space->Capacity(), 2 * capacity_per_page); +} + +// This test is currently incompatible with the sandbox. Enable it +// once the VirtualAddressSpace interface is stable. +#if !V8_OS_FUCHSIA && !V8_ENABLE_SANDBOX + +namespace { + +// This is a v8::PageAllocator implementation that decorates provided page +// allocator object with page tracking functionality. +class TrackingPageAllocator : public ::v8::PageAllocator { + public: + explicit TrackingPageAllocator(v8::PageAllocator* page_allocator) + : page_allocator_(page_allocator), + allocate_page_size_(page_allocator_->AllocatePageSize()), + commit_page_size_(page_allocator_->CommitPageSize()), + region_allocator_(kNullAddress, size_t{0} - commit_page_size_, + commit_page_size_) { + CHECK_NOT_NULL(page_allocator); + CHECK(IsAligned(allocate_page_size_, commit_page_size_)); + } + ~TrackingPageAllocator() override = default; + + size_t AllocatePageSize() override { return allocate_page_size_; } + + size_t CommitPageSize() override { return commit_page_size_; } + + void SetRandomMmapSeed(int64_t seed) override { + return page_allocator_->SetRandomMmapSeed(seed); + } + + void* GetRandomMmapAddr() override { + return page_allocator_->GetRandomMmapAddr(); + } + + void* AllocatePages(void* address, size_t size, size_t alignment, + PageAllocator::Permission access) override { + void* result = + page_allocator_->AllocatePages(address, size, alignment, access); + if (result) { + // Mark pages as used. + Address current_page = reinterpret_cast<Address>(result); + CHECK(IsAligned(current_page, allocate_page_size_)); + CHECK(IsAligned(size, allocate_page_size_)); + CHECK(region_allocator_.AllocateRegionAt(current_page, size)); + Address end = current_page + size; + while (current_page < end) { + PageState state{access, access != kNoAccess}; + page_permissions_.insert({current_page, state}); + current_page += commit_page_size_; + } + } + return result; + } + + bool FreePages(void* address, size_t size) override { + bool result = page_allocator_->FreePages(address, size); + if (result) { + // Mark pages as free. + Address start = reinterpret_cast<Address>(address); + CHECK(IsAligned(start, allocate_page_size_)); + CHECK(IsAligned(size, allocate_page_size_)); + size_t freed_size = region_allocator_.FreeRegion(start); + CHECK(IsAligned(freed_size, commit_page_size_)); + CHECK_EQ(RoundUp(freed_size, allocate_page_size_), size); + auto start_iter = page_permissions_.find(start); + CHECK_NE(start_iter, page_permissions_.end()); + auto end_iter = page_permissions_.lower_bound(start + size); + page_permissions_.erase(start_iter, end_iter); + } + return result; + } + + bool ReleasePages(void* address, size_t size, size_t new_size) override { + bool result = page_allocator_->ReleasePages(address, size, new_size); + if (result) { + Address start = reinterpret_cast<Address>(address); + CHECK(IsAligned(start, allocate_page_size_)); + CHECK(IsAligned(size, commit_page_size_)); + CHECK(IsAligned(new_size, commit_page_size_)); + CHECK_LT(new_size, size); + CHECK_EQ(region_allocator_.TrimRegion(start, new_size), size - new_size); + auto start_iter = page_permissions_.find(start + new_size); + CHECK_NE(start_iter, page_permissions_.end()); + auto end_iter = page_permissions_.lower_bound(start + size); + page_permissions_.erase(start_iter, end_iter); + } + return result; + } + + bool RecommitPages(void* address, size_t size, + PageAllocator::Permission access) override { + bool result = page_allocator_->RecommitPages(address, size, access); + if (result) { + // Check that given range had given access permissions. + CheckPagePermissions(reinterpret_cast<Address>(address), size, access, + {}); + UpdatePagePermissions(reinterpret_cast<Address>(address), size, access, + true); + } + return result; + } + + bool DiscardSystemPages(void* address, size_t size) override { + bool result = page_allocator_->DiscardSystemPages(address, size); + if (result) { + UpdatePagePermissions(reinterpret_cast<Address>(address), size, {}, + false); + } + return result; + } + + bool DecommitPages(void* address, size_t size) override { + bool result = page_allocator_->DecommitPages(address, size); + if (result) { + // Mark pages as non-accessible. + UpdatePagePermissions(reinterpret_cast<Address>(address), size, kNoAccess, + false); + } + return result; + } + + bool SetPermissions(void* address, size_t size, + PageAllocator::Permission access) override { + bool result = page_allocator_->SetPermissions(address, size, access); + if (result) { + bool committed = access != kNoAccess && access != kNoAccessWillJitLater; + UpdatePagePermissions(reinterpret_cast<Address>(address), size, access, + committed); + } + return result; + } + + // Returns true if all the allocated pages were freed. + bool IsEmpty() { return page_permissions_.empty(); } + + void CheckIsFree(Address address, size_t size) { + CHECK(IsAligned(address, allocate_page_size_)); + CHECK(IsAligned(size, allocate_page_size_)); + EXPECT_TRUE(region_allocator_.IsFree(address, size)); + } + + void CheckPagePermissions(Address address, size_t size, + PageAllocator::Permission access, + std::optional<bool> committed = {true}) { + CHECK_IMPLIES(committed.has_value() && committed.value(), + access != PageAllocator::kNoAccess); + ForEachPage(address, size, [=](PagePermissionsMap::value_type* value) { + if (committed.has_value()) { + EXPECT_EQ(committed.value(), value->second.committed); + } + EXPECT_EQ(access, value->second.access); + }); + } + + void Print(const char* comment) const { + i::StdoutStream os; + os << "\n=========================================" + << "\nTracingPageAllocator state: "; + if (comment) os << comment; + os << "\n-----------------------------------------\n"; + region_allocator_.Print(os); + os << "-----------------------------------------" + << "\nPage permissions:"; + if (page_permissions_.empty()) { + os << " empty\n"; + return; + } + os << "\n" << std::hex << std::showbase; + + Address contiguous_region_start = static_cast<Address>(-1); + Address contiguous_region_end = contiguous_region_start; + PageAllocator::Permission contiguous_region_access = + PageAllocator::kNoAccess; + bool contiguous_region_access_committed = false; + for (auto& pair : page_permissions_) { + if (contiguous_region_end == pair.first && + pair.second.access == contiguous_region_access && + pair.second.committed == contiguous_region_access_committed) { + contiguous_region_end += commit_page_size_; + continue; + } + if (contiguous_region_start != contiguous_region_end) { + PrintRegion(os, contiguous_region_start, contiguous_region_end, + contiguous_region_access, + contiguous_region_access_committed); + } + contiguous_region_start = pair.first; + contiguous_region_end = pair.first + commit_page_size_; + contiguous_region_access = pair.second.access; + contiguous_region_access_committed = pair.second.committed; + } + if (contiguous_region_start != contiguous_region_end) { + PrintRegion(os, contiguous_region_start, contiguous_region_end, + contiguous_region_access, contiguous_region_access_committed); + } + os << std::dec << std::noshowbase; + } + + private: + struct PageState { + PageAllocator::Permission access; + bool committed; + }; + using PagePermissionsMap = std::map<Address, PageState>; + using ForEachFn = std::function<void(PagePermissionsMap::value_type*)>; + + static void PrintRegion(std::ostream& os, Address start, Address end, + PageAllocator::Permission access, bool committed) { + os << " page: [" << start << ", " << end << "), access: "; + switch (access) { + case PageAllocator::kNoAccess: + case PageAllocator::kNoAccessWillJitLater: + os << "--"; + break; + case PageAllocator::kRead: + os << "R"; + break; + case PageAllocator::kReadWrite: + os << "RW"; + break; + case PageAllocator::kReadWriteExecute: + os << "RWX"; + break; + case PageAllocator::kReadExecute: + os << "RX"; + break; + } + os << ", committed: " << static_cast<int>(committed) << "\n"; + } + + void ForEachPage(Address address, size_t size, const ForEachFn& fn) { + CHECK(IsAligned(address, commit_page_size_)); + CHECK(IsAligned(size, commit_page_size_)); + auto start_iter = page_permissions_.find(address); + // Start page must exist in page_permissions_. + CHECK_NE(start_iter, page_permissions_.end()); + auto end_iter = page_permissions_.find(address + size - commit_page_size_); + // Ensure the last but one page exists in page_permissions_. + CHECK_NE(end_iter, page_permissions_.end()); + // Now make it point to the next element in order to also process is by the + // following for loop. + ++end_iter; + for (auto iter = start_iter; iter != end_iter; ++iter) { + PagePermissionsMap::value_type& pair = *iter; + fn(&pair); + } + } + + void UpdatePagePermissions(Address address, size_t size, + std::optional<PageAllocator::Permission> access, + bool committed) { + ForEachPage(address, size, [=](PagePermissionsMap::value_type* value) { + if (access.has_value()) { + value->second.access = access.value(); + } + value->second.committed = committed; + }); + } + + v8::PageAllocator* const page_allocator_; + const size_t allocate_page_size_; + const size_t commit_page_size_; + // Region allocator tracks page allocation/deallocation requests. + base::RegionAllocator region_allocator_; + // This map keeps track of allocated pages' permissions. + PagePermissionsMap page_permissions_; +}; + +template <typename TMixin> +class PoolTestMixin : public TMixin { + public: + PoolTestMixin(); + ~PoolTestMixin() override; +}; + +} // namespace + +// PoolTest must live in v8::internal because IsolateGroup befriends it under +// that name (see isolate-group.h). +class PoolTest : public // + WithInternalIsolateMixin< // + WithIsolateScopeMixin< // + WithIsolateMixin< // + PoolTestMixin< // + WithDefaultPlatformMixin< // + ::testing::Test>>>>> { + public: + PoolTest() = default; + ~PoolTest() override = default; + PoolTest(const PoolTest&) = delete; + PoolTest& operator=(const PoolTest&) = delete; + + static void DoMixinSetUp() { + CHECK_NULL(tracking_page_allocator_); + old_page_allocator_ = GetPlatformPageAllocator(); + tracking_page_allocator_ = new TrackingPageAllocator(old_page_allocator_); + CHECK(tracking_page_allocator_->IsEmpty()); + CHECK_EQ(old_page_allocator_, + SetPlatformPageAllocatorForTesting(tracking_page_allocator_)); + old_sweeping_flag_ = i::v8_flags.concurrent_sweeping; + i::v8_flags.concurrent_sweeping = false; + IsolateGroup::ReleaseDefault(); + IsolateGroup::InitializeOncePerProcess(); + } + + static void DoMixinTearDown() { + IsolateGroup::ReleaseDefault(); + i::v8_flags.concurrent_sweeping = old_sweeping_flag_; + CHECK(tracking_page_allocator_->IsEmpty()); + + // Restore the original v8::PageAllocator and delete the tracking one. + CHECK_EQ(tracking_page_allocator_, + SetPlatformPageAllocatorForTesting(old_page_allocator_)); + delete tracking_page_allocator_; + tracking_page_allocator_ = nullptr; + + IsolateGroup::InitializeOncePerProcess(); + } + + Heap* heap() { return isolate()->heap(); } + MemoryAllocator* allocator() { return heap()->memory_allocator(); } + MemoryPool* pool() { return isolate()->isolate_group()->memory_pool(); } + + TrackingPageAllocator* tracking_page_allocator() { + return tracking_page_allocator_; + } + + private: + static TrackingPageAllocator* tracking_page_allocator_; + static v8::PageAllocator* old_page_allocator_; + static bool old_sweeping_flag_; +}; + +TrackingPageAllocator* PoolTest::tracking_page_allocator_ = nullptr; +v8::PageAllocator* PoolTest::old_page_allocator_ = nullptr; +bool PoolTest::old_sweeping_flag_; + +template <typename TMixin> +PoolTestMixin<TMixin>::PoolTestMixin() { + PoolTest::DoMixinSetUp(); +} +template <typename TMixin> +PoolTestMixin<TMixin>::~PoolTestMixin() { + PoolTest::DoMixinTearDown(); +} + +// See v8:5945. +TEST_F(PoolTest, UnmapOnTeardown) { + // Wait for the task to finish and disable rescheduling. + pool()->CancelAndWaitForTaskToFinishForTesting(); + + NormalPage* page = + allocator()->AllocatePage(MemoryAllocator::AllocationMode::kRegular, + static_cast<PagedSpace*>(heap()->old_space()), + Executability::NOT_EXECUTABLE); + Address chunk_address = page->ChunkAddress(); + EXPECT_NE(nullptr, page); + const size_t page_size = tracking_page_allocator()->AllocatePageSize(); + tracking_page_allocator()->CheckPagePermissions(chunk_address, page_size, + PageAllocator::kReadWrite); + + allocator()->Free(MemoryAllocator::FreeMode::kPool, page); + tracking_page_allocator()->CheckPagePermissions(chunk_address, page_size, + PageAllocator::kReadWrite); + pool()->ReleaseImmediately(i_isolate()); +#ifdef V8_COMPRESS_POINTERS + // In this mode Isolate uses bounded page allocator which allocates pages + // inside prereserved region. Thus these pages are kept reserved until + // the Isolate dies. + tracking_page_allocator()->CheckPagePermissions( + chunk_address, page_size, PageAllocator::kNoAccess, false); +#else + tracking_page_allocator()->CheckIsFree(chunk_address, page_size); +#endif // V8_COMPRESS_POINTERS + + // Wait for the task to finish and disable rescheduling. + pool()->ReenableTaskForTesting(); +} +#endif // !V8_OS_FUCHSIA && !V8_ENABLE_SANDBOX + +TEST_F(SpacesTest, EagerDiscardingInCollectAllAvailableGarbage) { + // --stress-concurrent-allocation is re-checked by the heap's allocation + // observer on every step, so disabling it on the already created isolate is + // sufficient for SimulateFullSpace. + FLAG_VALUE_SCOPE(stress_concurrent_allocation, false); + SimulateFullSpace(heap()->old_space()); + InvokeMemoryReducingMajorGCs(); + // The pooled chunk count is IsolateGroup-wide, so this relies on the fixture + // isolate being the only isolate in the group. + EXPECT_EQ(0u, heap()->memory_allocator()->GetPooledChunksCount()); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-weak-references.cc b/deps/v8/test/unittests/heap/weak-references-unittest.cc similarity index 58% rename from deps/v8/test/cctest/heap/test-weak-references.cc rename to deps/v8/test/unittests/heap/weak-references-unittest.cc index 3debbf32f759..3fa957ac01f1 100644 --- a/deps/v8/test/cctest/heap/test-weak-references.cc +++ b/deps/v8/test/unittests/heap/weak-references-unittest.cc @@ -7,17 +7,23 @@ #include "src/execution/isolate.h" #include "src/heap/factory.h" #include "src/heap/heap-inl.h" +#include "src/heap/heap-layout-inl.h" +#include "src/heap/memory-allocator.h" #include "src/ic/handler-configuration.h" #include "src/objects/data-handler-inl.h" #include "src/objects/smi.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-tester.h" -#include "test/cctest/heap/heap-utils.h" +#include "test/common/flag-utils.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/test-utils.h" namespace v8 { namespace internal { namespace heap { +using WeakReferencesTest = TestWithHeapInternalsAndContext; + +namespace { + Handle<LoadHandler> CreateLoadHandlerForTest( Factory* factory, AllocationType allocation = AllocationType::kYoung) { Handle<LoadHandler> result = factory->NewLoadHandler(1, allocation); @@ -27,35 +33,32 @@ Handle<LoadHandler> CreateLoadHandlerForTest( return result; } -TEST(WeakReferencesBasic) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning( - CcTest::heap()); - HandleScope outer_scope(isolate); +} // namespace + +TEST_F(WeakReferencesTest, WeakReferencesBasic) { + ManualGCScope manual_gc_scope(i_isolate()); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); - IndirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory); + IndirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory()); if (!v8_flags.single_generation) CHECK(HeapLayout::InYoungGeneration(*lh)); Tagged<MaybeObject> code_object = lh->data1(); CHECK(IsSmi(code_object)); - heap::InvokeMajorGC(CcTest::heap()); + InvokeMajorGC(); CHECK(!HeapLayout::InYoungGeneration(*lh)); CHECK_EQ(code_object, lh->data1()); { - HandleScope inner_scope(isolate); + HandleScope inner_scope(i_isolate()); // Create a new Code. - Assembler assm(isolate->allocator(), AssemblerOptions{}); + Assembler assm(i_isolate()->allocator(), AssemblerOptions{}); assm.nop(); // supported on all architectures CodeDesc desc; - assm.GetCode(isolate, &desc); + assm.GetCode(i_isolate(), &desc); IndirectHandle<Code> code = - Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build(); + Factory::CodeBuilder(i_isolate(), desc, CodeKind::FOR_TESTING).Build(); CHECK(IsCode(*code)); // We cannot store the Code object itself into the tagged field as it will @@ -66,142 +69,118 @@ TEST(WeakReferencesBasic) { CHECK(lh->data1().GetHeapObjectIfWeak(&code_wrapper_heap_object)); CHECK_EQ(code->wrapper(), code_wrapper_heap_object); - heap::InvokeMajorGC(CcTest::heap()); + InvokeMajorGC(); CHECK(lh->data1().GetHeapObjectIfWeak(&code_wrapper_heap_object)); CHECK_EQ(code->wrapper(), code_wrapper_heap_object); } // code will go out of scope. - heap::InvokeMajorGC(CcTest::heap()); + InvokeMajorGC(); CHECK(lh->data1().IsCleared()); } -TEST(WeakReferencesOldToOld) { +TEST_F(WeakReferencesTest, WeakReferencesOldToOld) { // Like WeakReferencesBasic, but the updated weak slot is in the old space, // and referring to an old space object. - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope outer_scope(isolate); DirectHandle<LoadHandler> lh = - CreateLoadHandlerForTest(factory, AllocationType::kOld); - CHECK(heap->InOldSpace(*lh)); + CreateLoadHandlerForTest(factory(), AllocationType::kOld); + CHECK(heap()->InOldSpace(*lh)); // Create a new FixedArray which the LoadHandler will point to. DirectHandle<FixedArray> fixed_array = - factory->NewFixedArray(1, AllocationType::kOld); - CHECK(heap->InOldSpace(*fixed_array)); + factory()->NewFixedArray(1, AllocationType::kOld); + CHECK(heap()->InOldSpace(*fixed_array)); lh->set_data1(MakeWeak(*fixed_array)); NormalPage* page_before_gc = NormalPage::FromHeapObject(*fixed_array); - heap::ForceEvacuationCandidate(page_before_gc); - heap::InvokeMajorGC(heap); - CHECK(heap->InOldSpace(*fixed_array)); + ForceEvacuationCandidate(page_before_gc); + InvokeMajorGC(); + CHECK(heap()->InOldSpace(*fixed_array)); Tagged<HeapObject> heap_object; CHECK(lh->data1().GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(heap_object, *fixed_array); } -TEST(WeakReferencesOldToNew) { +TEST_F(WeakReferencesTest, WeakReferencesOldToNew) { // Like WeakReferencesBasic, but the updated weak slot is in the old space, // and referring to an new space object. if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(i_isolate()); - HandleScope outer_scope(isolate); DirectHandle<LoadHandler> lh = - CreateLoadHandlerForTest(factory, AllocationType::kOld); - CHECK(heap->InOldSpace(*lh)); + CreateLoadHandlerForTest(factory(), AllocationType::kOld); + CHECK(heap()->InOldSpace(*lh)); // Create a new FixedArray which the LoadHandler will point to. - DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1); + DirectHandle<FixedArray> fixed_array = factory()->NewFixedArray(1); CHECK(HeapLayout::InYoungGeneration(*fixed_array)); lh->set_data1(MakeWeak(*fixed_array)); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); Tagged<HeapObject> heap_object; CHECK(lh->data1().GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(heap_object, *fixed_array); } -TEST(WeakReferencesOldToNewScavenged) { +TEST_F(WeakReferencesTest, WeakReferencesOldToNewScavenged) { if (v8_flags.single_generation) return; // Like WeakReferencesBasic, but the updated weak slot is in the old space, // and referring to an new space object, which is then scavenged. - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(i_isolate()); - HandleScope outer_scope(isolate); DirectHandle<LoadHandler> lh = - CreateLoadHandlerForTest(factory, AllocationType::kOld); - CHECK(heap->InOldSpace(*lh)); + CreateLoadHandlerForTest(factory(), AllocationType::kOld); + CHECK(heap()->InOldSpace(*lh)); // Create a new FixedArray which the LoadHandler will point to. - DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1); + DirectHandle<FixedArray> fixed_array = factory()->NewFixedArray(1); CHECK(HeapLayout::InYoungGeneration(*fixed_array)); lh->set_data1(MakeWeak(*fixed_array)); - heap::InvokeMinorGC(heap); + InvokeMinorGC(); Tagged<HeapObject> heap_object; CHECK(lh->data1().GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(heap_object, *fixed_array); } -TEST(WeakReferencesOldToCleared) { +TEST_F(WeakReferencesTest, WeakReferencesOldToCleared) { // Like WeakReferencesBasic, but the updated weak slot is in the old space, // and is cleared. - ManualGCScope manual_gc_scope; - heap::ManualEvacuationCandidatesSelectionScope + ManualGCScope manual_gc_scope(i_isolate()); + ManualEvacuationCandidatesSelectionScope manual_evacuation_candidate_selection_scope(manual_gc_scope); - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope outer_scope(isolate); DirectHandle<LoadHandler> lh = - CreateLoadHandlerForTest(factory, AllocationType::kOld); - CHECK(heap->InOldSpace(*lh)); + CreateLoadHandlerForTest(factory(), AllocationType::kOld); + CHECK(heap()->InOldSpace(*lh)); lh->set_data1(kClearedWeakValue); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); CHECK(lh->data1().IsCleared()); } -TEST(ObjectWithWeakFieldDies) { +TEST_F(WeakReferencesTest, ObjectWithWeakFieldDies) { if (!v8_flags.incremental_marking) { return; } - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(i_isolate()); { - HandleScope outer_scope(isolate); - DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory); - CHECK(InCorrectGeneration(*lh)); + HandleScope outer_scope(i_isolate()); + DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory()); + CHECK(IsNewObjectInCorrectGeneration(*lh)); { - HandleScope inner_scope(isolate); + HandleScope inner_scope(i_isolate()); // Create a new FixedArray which the LoadHandler will point to. - DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1); - CHECK(InCorrectGeneration(*fixed_array)); + DirectHandle<FixedArray> fixed_array = factory()->NewFixedArray(1); + CHECK(IsNewObjectInCorrectGeneration(*fixed_array)); lh->set_data1(MakeWeak(*fixed_array)); // inner_scope will go out of scope, so when marking the next time, // *fixed_array will stay white. @@ -209,128 +188,103 @@ TEST(ObjectWithWeakFieldDies) { // Do marking steps; this will store *lh into the list for later processing // (since it points to a white object). - SimulateIncrementalMarking(heap, true); + SimulateIncrementalMarking(true); } // outer_scope goes out of scope // lh will die - heap::InvokeMinorGC(heap); + InvokeMinorGC(); // This used to crash when processing the dead weak reference. - heap::InvokeMajorGC(heap); + InvokeMajorGC(); } -TEST(ObjectWithWeakReferencePromoted) { +TEST_F(WeakReferencesTest, ObjectWithWeakReferencePromoted) { if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - - HandleScope outer_scope(isolate); - DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory); + ManualGCScope manual_gc_scope(i_isolate()); + + DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory()); CHECK(HeapLayout::InYoungGeneration(*lh)); // Create a new FixedArray which the LoadHandler will point to. - DirectHandle<FixedArray> fixed_array = factory->NewFixedArray(1); + DirectHandle<FixedArray> fixed_array = factory()->NewFixedArray(1); CHECK(HeapLayout::InYoungGeneration(*fixed_array)); lh->set_data1(MakeWeak(*fixed_array)); - heap::EmptyNewSpaceUsingGC(heap); - CHECK(heap->InOldSpace(*lh)); - CHECK(heap->InOldSpace(*fixed_array)); + EmptyNewSpaceUsingGC(); + CHECK(heap()->InOldSpace(*lh)); + CHECK(heap()->InOldSpace(*fixed_array)); Tagged<HeapObject> heap_object; CHECK(lh->data1().GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(heap_object, *fixed_array); } -TEST(ObjectWithClearedWeakReferencePromoted) { +TEST_F(WeakReferencesTest, ObjectWithClearedWeakReferencePromoted) { if (v8_flags.single_generation || v8_flags.stress_incremental_marking) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - - HandleScope outer_scope(isolate); - DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory); + ManualGCScope manual_gc_scope(i_isolate()); + + DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory()); CHECK(HeapLayout::InYoungGeneration(*lh)); lh->set_data1(kClearedWeakValue); - heap::EmptyNewSpaceUsingGC(heap); - CHECK(heap->InOldSpace(*lh)); + EmptyNewSpaceUsingGC(); + CHECK(heap()->InOldSpace(*lh)); CHECK(lh->data1().IsCleared()); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); CHECK(lh->data1().IsCleared()); } -TEST(WeakReferenceWriteBarrier) { +TEST_F(WeakReferencesTest, WeakReferenceWriteBarrier) { if (!v8_flags.incremental_marking) { return; } - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); + ManualGCScope manual_gc_scope(i_isolate()); - HandleScope outer_scope(isolate); - DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory); - CHECK(InCorrectGeneration(*lh)); + DirectHandle<LoadHandler> lh = CreateLoadHandlerForTest(factory()); + CHECK(IsNewObjectInCorrectGeneration(*lh)); - v8::Global<Value> global_lh(CcTest::isolate(), Utils::ToLocal(lh)); + v8::Global<Value> global_lh(v8_isolate(), Utils::ToLocal(lh)); { - HandleScope inner_scope(isolate); + HandleScope inner_scope(i_isolate()); // Create a new FixedArray which the LoadHandler will point to. - DirectHandle<FixedArray> fixed_array1 = factory->NewFixedArray(1); - CHECK(InCorrectGeneration(*fixed_array1)); + DirectHandle<FixedArray> fixed_array1 = factory()->NewFixedArray(1); + CHECK(IsNewObjectInCorrectGeneration(*fixed_array1)); lh->set_data1(MakeWeak(*fixed_array1)); - SimulateIncrementalMarking(heap, true); + SimulateIncrementalMarking(true); - DirectHandle<FixedArray> fixed_array2 = factory->NewFixedArray(1); - CHECK(InCorrectGeneration(*fixed_array2)); + DirectHandle<FixedArray> fixed_array2 = factory()->NewFixedArray(1); + CHECK(IsNewObjectInCorrectGeneration(*fixed_array2)); // This write will trigger the write barrier. lh->set_data1(MakeWeak(*fixed_array2)); } - heap::InvokeMajorGC(heap); + InvokeMajorGC(); // Check that the write barrier treated the weak reference as strong. CHECK(lh->data1().IsWeak()); } -TEST(EmptyWeakArray) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - HandleScope outer_scope(isolate); - - DirectHandle<WeakFixedArray> array = factory->empty_weak_fixed_array(); +TEST_F(WeakReferencesTest, EmptyWeakArray) { + DirectHandle<WeakFixedArray> array = factory()->empty_weak_fixed_array(); CHECK(IsWeakFixedArray(*array)); CHECK(!IsFixedArray(*array)); CHECK_EQ(array->length().value(), 0u); } -TEST(WeakArraysBasic) { +TEST_F(WeakReferencesTest, WeakArraysBasic) { if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - HandleScope outer_scope(isolate); + ManualGCScope manual_gc_scope(i_isolate()); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); const uint32_t length = 4; - IndirectHandle<WeakFixedArray> array = factory->NewWeakFixedArray(length); + IndirectHandle<WeakFixedArray> array = factory()->NewWeakFixedArray(length); CHECK(IsWeakFixedArray(*array)); CHECK(!IsFixedArray(*array)); CHECK_EQ(array->length().value(), length); @@ -340,20 +294,20 @@ TEST(WeakArraysBasic) { for (uint32_t i = 0; i < length; ++i) { Tagged<HeapObject> heap_object; CHECK(array->get(i).GetHeapObjectIfStrong(&heap_object)); - CHECK_EQ(heap_object, ReadOnlyRoots(heap).undefined_value()); + CHECK_EQ(heap_object, ReadOnlyRoots(heap()).undefined_value()); } IndirectHandle<HeapObject> saved; { - HandleScope inner_scope(isolate); - IndirectHandle<FixedArray> index0 = factory->NewFixedArray(1); + HandleScope inner_scope(i_isolate()); + IndirectHandle<FixedArray> index0 = factory()->NewFixedArray(1); index0->set(0, Smi::FromInt(2016)); - IndirectHandle<FixedArray> index1 = factory->NewFixedArray(1); + IndirectHandle<FixedArray> index1 = factory()->NewFixedArray(1); index1->set(0, Smi::FromInt(2017)); - IndirectHandle<FixedArray> index2 = factory->NewFixedArray(1); + IndirectHandle<FixedArray> index2 = factory()->NewFixedArray(1); index2->set(0, Smi::FromInt(2018)); - IndirectHandle<FixedArray> index3 = factory->NewFixedArray(1); + IndirectHandle<FixedArray> index3 = factory()->NewFixedArray(1); index3->set(0, Smi::FromInt(2019)); array->set(0, MakeWeak(*index0)); @@ -369,7 +323,7 @@ TEST(WeakArraysBasic) { // TODO(marja): update this when/if we do handle weak references in the new // space. - heap::InvokeMinorGC(heap); + InvokeMinorGC(); Tagged<HeapObject> heap_object; CHECK(array->get(0).GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(Cast<Smi>(Cast<FixedArray>(heap_object)->get(0)).value(), 2016); @@ -380,8 +334,8 @@ TEST(WeakArraysBasic) { CHECK(array->get(3).GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(Cast<Smi>(Cast<FixedArray>(heap_object)->get(0)).value(), 2019); - heap::InvokeMajorGC(heap); - CHECK(heap->InOldSpace(*array)); + InvokeMajorGC(); + CHECK(heap()->InOldSpace(*array)); CHECK(array->get(0).IsCleared()); CHECK(array->get(1).GetHeapObjectIfWeak(&heap_object)); CHECK_EQ(Cast<Smi>(Cast<FixedArray>(heap_object)->get(0)).value(), 2017); @@ -390,61 +344,60 @@ TEST(WeakArraysBasic) { CHECK(array->get(3).IsCleared()); } -TEST(WeakArrayListBasic) { +TEST_F(WeakReferencesTest, WeakArrayListBasic) { if (v8_flags.single_generation) return; - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - HandleScope outer_scope(isolate); + ManualGCScope manual_gc_scope(i_isolate()); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); - Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(), - isolate); + Handle<WeakArrayList> array(ReadOnlyRoots(heap()).empty_weak_array_list(), + i_isolate()); CHECK(IsWeakArrayList(*array)); CHECK(!IsFixedArray(*array)); CHECK(!IsWeakFixedArray(*array)); CHECK_EQ(array->length().value(), 0u); - DirectHandle<FixedArray> index2 = factory->NewFixedArray(1); + DirectHandle<FixedArray> index2 = factory()->NewFixedArray(1); index2->set(0, Smi::FromInt(2017)); { - HandleScope inner_scope(isolate); - DirectHandle<FixedArray> index0 = factory->NewFixedArray(1); + HandleScope inner_scope(i_isolate()); + DirectHandle<FixedArray> index0 = factory()->NewFixedArray(1); index0->set(0, Smi::FromInt(2016)); - DirectHandle<FixedArray> index4 = factory->NewFixedArray(1); + DirectHandle<FixedArray> index4 = factory()->NewFixedArray(1); index4->set(0, Smi::FromInt(2018)); - DirectHandle<FixedArray> index6 = factory->NewFixedArray(1); + DirectHandle<FixedArray> index6 = factory()->NewFixedArray(1); index6->set(0, Smi::FromInt(2019)); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(index0)); array = WeakArrayList::AddToEnd( - isolate, array, MaybeObjectDirectHandle(Smi::FromInt(1), isolate)); + i_isolate(), array, + MaybeObjectDirectHandle(Smi::FromInt(1), i_isolate())); CHECK_EQ(array->length().value(), 2u); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(index2)); array = WeakArrayList::AddToEnd( - isolate, array, MaybeObjectDirectHandle(Smi::FromInt(3), isolate)); + i_isolate(), array, + MaybeObjectDirectHandle(Smi::FromInt(3), i_isolate())); CHECK_EQ(array->length().value(), 4u); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(index4)); array = WeakArrayList::AddToEnd( - isolate, array, MaybeObjectDirectHandle(Smi::FromInt(5), isolate)); + i_isolate(), array, + MaybeObjectDirectHandle(Smi::FromInt(5), i_isolate())); CHECK_EQ(array->length().value(), 6u); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(index6)); array = WeakArrayList::AddToEnd( - isolate, array, MaybeObjectDirectHandle(Smi::FromInt(7), isolate)); + i_isolate(), array, + MaybeObjectDirectHandle(Smi::FromInt(7), i_isolate())); CHECK_EQ(array->length().value(), 8u); - CHECK(InCorrectGeneration(*array)); + CHECK(IsNewObjectInCorrectGeneration(*array)); CHECK_EQ(array->get(0), MakeWeak(*index0)); CHECK_EQ(array->get(1).ToSmi().value(), 1); @@ -465,7 +418,7 @@ TEST(WeakArrayListBasic) { // TODO(marja): update this when/if we do handle weak references in the new // space. - heap::InvokeMinorGC(heap); + InvokeMinorGC(); Tagged<HeapObject> heap_object; CHECK_EQ(array->length().value(), 8u); CHECK(array->get(0).GetHeapObjectIfWeak(&heap_object)); @@ -484,8 +437,8 @@ TEST(WeakArrayListBasic) { CHECK_EQ(Cast<Smi>(Cast<FixedArray>(heap_object)->get(0)).value(), 2019); CHECK_EQ(array->get(7).ToSmi().value(), 7); - heap::InvokeMajorGC(heap); - CHECK(heap->InOldSpace(*array)); + InvokeMajorGC(); + CHECK(heap()->InOldSpace(*array)); CHECK_EQ(array->length().value(), 8u); CHECK(array->get(0).IsCleared()); CHECK_EQ(array->get(1).ToSmi().value(), 1); @@ -501,26 +454,21 @@ TEST(WeakArrayListBasic) { CHECK_EQ(array->get(7).ToSmi().value(), 7); } -TEST(WeakArrayListRemove) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope outer_scope(isolate); +TEST_F(WeakReferencesTest, WeakArrayListRemove) { + ManualGCScope manual_gc_scope(i_isolate()); - Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(), - isolate); + Handle<WeakArrayList> array(ReadOnlyRoots(heap()).empty_weak_array_list(), + i_isolate()); - DirectHandle<FixedArray> elem0 = factory->NewFixedArray(1); - DirectHandle<FixedArray> elem1 = factory->NewFixedArray(1); - DirectHandle<FixedArray> elem2 = factory->NewFixedArray(1); + DirectHandle<FixedArray> elem0 = factory()->NewFixedArray(1); + DirectHandle<FixedArray> elem1 = factory()->NewFixedArray(1); + DirectHandle<FixedArray> elem2 = factory()->NewFixedArray(1); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(elem0)); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(elem1)); - array = WeakArrayList::AddToEnd(isolate, array, + array = WeakArrayList::AddToEnd(i_isolate(), array, MaybeObjectDirectHandle::Weak(elem2)); CHECK_EQ(array->length().value(), 3u); @@ -550,31 +498,26 @@ TEST(WeakArrayListRemove) { CHECK_EQ(array->length().value(), 0u); } -TEST(ProtectedWeakFixedArray) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope handle_scope(isolate); +TEST_F(WeakReferencesTest, ProtectedWeakFixedArray) { + ManualGCScope manual_gc_scope(i_isolate()); IndirectHandle<ProtectedWeakFixedArray> array = - factory->NewProtectedWeakFixedArray(5); + factory()->NewProtectedWeakFixedArray(5); - IndirectHandle<TrustedFixedArray> elem1 = factory->NewTrustedFixedArray(1); - IndirectHandle<TrustedFixedArray> elem3 = factory->NewTrustedFixedArray(1); + IndirectHandle<TrustedFixedArray> elem1 = factory()->NewTrustedFixedArray(1); + IndirectHandle<TrustedFixedArray> elem3 = factory()->NewTrustedFixedArray(1); array->set(1, MakeWeak(*elem1)); array->set(3, MakeWeak(*elem3)); { - HandleScope inner_scope(isolate); - DirectHandle<TrustedFixedArray> elem0 = factory->NewTrustedFixedArray(1); - DirectHandle<TrustedFixedArray> elem2 = factory->NewTrustedFixedArray(1); - DirectHandle<TrustedFixedArray> elem4 = factory->NewTrustedFixedArray(1); + HandleScope inner_scope(i_isolate()); + DirectHandle<TrustedFixedArray> elem0 = factory()->NewTrustedFixedArray(1); + DirectHandle<TrustedFixedArray> elem2 = factory()->NewTrustedFixedArray(1); + DirectHandle<TrustedFixedArray> elem4 = factory()->NewTrustedFixedArray(1); array->set(0, MakeWeak(*elem0)); array->set(2, MakeWeak(*elem2)); array->set(4, MakeWeak(*elem4)); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); CHECK_EQ(array->get(0).GetHeapObjectAssumeWeak(), *elem0); CHECK_EQ(array->get(1).GetHeapObjectAssumeWeak(), *elem1); CHECK_EQ(array->get(2).GetHeapObjectAssumeWeak(), *elem2); @@ -582,8 +525,8 @@ TEST(ProtectedWeakFixedArray) { CHECK_EQ(array->get(4).GetHeapObjectAssumeWeak(), *elem4); } - DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - heap::InvokeMajorGC(heap); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); + InvokeMajorGC(); CHECK(array->get(0).IsCleared()); CHECK_EQ(array->get(1).GetHeapObjectAssumeWeak(), *elem1); CHECK(array->get(2).IsCleared()); @@ -591,21 +534,17 @@ TEST(ProtectedWeakFixedArray) { CHECK(array->get(4).IsCleared()); } -TEST(Regress7768) { - i::v8_flags.allow_natives_syntax = true; - i::v8_flags.turbo_inlining = false; +TEST_F(WeakReferencesTest, Regress7768) { if (!v8_flags.incremental_marking) { return; } - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - HandleScope outer_scope(isolate); + FlagScope<bool> allow_natives_syntax(&v8_flags.allow_natives_syntax, true); + FlagScope<bool> no_turbo_inlining(&v8_flags.turbo_inlining, false); + ManualGCScope manual_gc_scope(i_isolate()); + // Create an optimized code which will contain a weak reference to another // function ("f"). The weak reference is the only reference to the function. - CompileRun( + RunJS( "function myfunc(f) { f(); } " "%PrepareFunctionForOptimization(myfunc); " "(function wrapper() { " @@ -617,41 +556,35 @@ TEST(Regress7768) { // Do marking steps; this will store the objects pointed by myfunc for later // processing. - SimulateIncrementalMarking(heap, true); + SimulateIncrementalMarking(true); // Deoptimize the code; now the pointers inside it will be replaced with // undefined, and the weak_objects_in_code is the only place pointing to the // function f. - CompileRun("%DeoptimizeFunction(myfunc);"); + RunJS("%DeoptimizeFunction(myfunc);"); // The object pointed to by the weak reference won't be scavenged. - heap::InvokeMinorGC(heap); + InvokeMinorGC(); // Make sure the memory where it's stored is invalidated, so that we'll crash // if we try to access it. - HeapTester::UncommitUnusedMemory(heap); + if (!v8_flags.minor_ms) heap()->ReduceNewSpaceSizeForTesting(); + heap()->memory_allocator()->ReleasePooledChunksImmediately(); // This used to crash when processing the dead weak reference. - heap::InvokeMajorGC(heap); + InvokeMajorGC(); } -TEST(PrototypeUsersBasic) { - CcTest::InitializeVM(); - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - HandleScope outer_scope(isolate); - - Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(), - isolate); +TEST_F(WeakReferencesTest, PrototypeUsersBasic) { + Handle<WeakArrayList> array(ReadOnlyRoots(heap()).empty_weak_array_list(), + i_isolate()); // Add some objects into the array. int index = -1; { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); CHECK_EQ(array->length().value(), index + 1); } CHECK_EQ(index, 1); @@ -663,9 +596,9 @@ TEST(PrototypeUsersBasic) { int last_index = index; uint32_t old_capacity = array->capacity().value(); while (!array->IsFull()) { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); CHECK_EQ(index, last_index + 1); CHECK_EQ(array->length().value(), index + 1); last_index = index; @@ -673,17 +606,17 @@ TEST(PrototypeUsersBasic) { // The next addition will fill the empty slot. { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); } CHECK_EQ(index, empty_index); - // The next addition will make the arrow grow again. + // The next addition will make the array grow again. { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); CHECK_EQ(array->length().value(), index + 1); last_index = index; } @@ -698,9 +631,9 @@ TEST(PrototypeUsersBasic) { // Fill the array (still adding to the end) old_capacity = array->capacity().value(); while (!array->IsFull()) { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); CHECK_EQ(index, last_index + 1); CHECK_EQ(array->length().value(), index + 1); last_index = index; @@ -708,16 +641,16 @@ TEST(PrototypeUsersBasic) { // Make sure we use the empty slots in (reverse) order. { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); } CHECK_EQ(index, empty_index2); { - DirectHandle<Map> map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map, &index); + array = PrototypeUsers::Add(i_isolate(), array, map, &index); } CHECK_EQ(index, empty_index1); } @@ -726,8 +659,8 @@ namespace { Tagged<HeapObject> saved_heap_object; -static void TestCompactCallback(Tagged<HeapObject> value, int old_index, - int new_index) { +void TestCompactCallback(Tagged<HeapObject> value, int old_index, + int new_index) { saved_heap_object = value; CHECK_EQ(old_index, 2); CHECK_EQ(new_index, 1); @@ -735,48 +668,42 @@ static void TestCompactCallback(Tagged<HeapObject> value, int old_index, } // namespace -TEST(PrototypeUsersCompacted) { - ManualGCScope manual_gc_scope; - CcTest::InitializeVM(); - LocalContext context; - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - Heap* heap = isolate->heap(); - i::DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); - HandleScope outer_scope(isolate); +TEST_F(WeakReferencesTest, PrototypeUsersCompacted) { + ManualGCScope manual_gc_scope(i_isolate()); + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); - Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(), - isolate); + Handle<WeakArrayList> array(ReadOnlyRoots(heap()).empty_weak_array_list(), + i_isolate()); // Add some objects into the array. int index = -1; DirectHandle<Map> map_cleared_by_user = - factory->NewContextfulMapForCurrentContext(JS_OBJECT_TYPE, - JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, map_cleared_by_user, &index); + factory()->NewContextfulMapForCurrentContext(JS_OBJECT_TYPE, + JSObject::kHeaderSize); + array = PrototypeUsers::Add(i_isolate(), array, map_cleared_by_user, &index); CHECK_EQ(index, 1); - DirectHandle<Map> live_map = factory->NewContextfulMapForCurrentContext( + DirectHandle<Map> live_map = factory()->NewContextfulMapForCurrentContext( JS_OBJECT_TYPE, JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, live_map, &index); + array = PrototypeUsers::Add(i_isolate(), array, live_map, &index); CHECK_EQ(index, 2); { - HandleScope inner_scope(isolate); + HandleScope inner_scope(i_isolate()); DirectHandle<Map> soon_dead_map = - factory->NewContextfulMapForCurrentContext(JS_OBJECT_TYPE, - JSObject::kHeaderSize); - array = PrototypeUsers::Add(isolate, array, soon_dead_map, &index); + factory()->NewContextfulMapForCurrentContext(JS_OBJECT_TYPE, + JSObject::kHeaderSize); + array = PrototypeUsers::Add(i_isolate(), array, soon_dead_map, &index); CHECK_EQ(index, 3); array = inner_scope.CloseAndEscape(array); } PrototypeUsers::MarkSlotEmpty(*array, 1); - heap::InvokeMajorGC(heap); + InvokeMajorGC(); CHECK(array->get(3).IsCleared()); CHECK_EQ(array->length().value(), 3 + PrototypeUsers::kFirstIndex); Tagged<WeakArrayList> new_array = - PrototypeUsers::Compact(array, heap, TestCompactCallback); + PrototypeUsers::Compact(array, heap(), TestCompactCallback); CHECK_EQ(new_array->length().value(), 1 + PrototypeUsers::kFirstIndex); CHECK_EQ(saved_heap_object, *live_map); } diff --git a/deps/v8/test/unittests/heap/write-barrier-unittest.cc b/deps/v8/test/unittests/heap/write-barrier-unittest.cc index 421437b53de9..521e150c8d7a 100644 --- a/deps/v8/test/unittests/heap/write-barrier-unittest.cc +++ b/deps/v8/test/unittests/heap/write-barrier-unittest.cc @@ -4,14 +4,17 @@ #include "src/common/globals.h" #include "src/handles/handles.h" -#include "src/heap/heap-write-barrier.h" +#include "src/heap/heap-write-barrier-inl.h" #include "src/heap/local-heap.h" -#include "src/objects/objects.h" +#include "src/heap/marking-state-inl.h" +#include "src/objects/js-array-buffer-inl.h" +#include "src/objects/objects-inl.h" +#include "test/unittests/heap/heap-utils.h" #include "test/unittests/test-utils.h" namespace v8::internal { -using HeapWriteBarrierTest = TestWithIsolate; +using HeapWriteBarrierTest = TestWithHeapInternalsAndContext; #if V8_VERIFY_WRITE_BARRIERS @@ -73,4 +76,66 @@ TEST_F(HeapWriteBarrierTest, #endif // V8_VERIFY_WRITE_BARRIERS +TEST_F(HeapWriteBarrierTest, WriteBarrier_Marking) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + DirectHandle<FixedArray> objects = factory()->NewFixedArray(3); + v8::Global<Value> global_objects(v8_isolate(), Utils::ToLocal(objects)); + { + // Make sure that these objects are not immediately reachable from + // the roots to prevent them being marked grey at the start of marking. + HandleScope inner(i_isolate()); + DirectHandle<FixedArray> host = factory()->NewFixedArray(1); + DirectHandle<HeapNumber> value1 = factory()->NewHeapNumber(1.1); + DirectHandle<HeapNumber> value2 = factory()->NewHeapNumber(1.2); + objects->set(0, *host); + objects->set(1, *value1); + objects->set(2, *value2); + } + SimulateIncrementalMarking(false); + Tagged<FixedArray> host = Cast<FixedArray>(objects->get(0)); + Tagged<HeapObject> value1 = Cast<HeapObject>(objects->get(1)); + Tagged<HeapObject> value2 = Cast<HeapObject>(objects->get(2)); + EXPECT_TRUE(heap()->marking_state()->IsUnmarked(host)); + EXPECT_TRUE(heap()->marking_state()->IsUnmarked(value1)); + // Trigger the barrier for the unmarked host and expect the bail out. + WriteBarrier::MarkingForTesting(host, host->RawFieldOfElementAt(0), value1); + EXPECT_TRUE(heap()->marking_state()->IsMarked(value1)); + + EXPECT_TRUE(heap()->marking_state()->IsUnmarked(value2)); + WriteBarrier::MarkingForTesting(host, host->RawFieldOfElementAt(0), value2); + EXPECT_TRUE(heap()->marking_state()->IsMarked(value2)); + SimulateIncrementalMarking(true); + EXPECT_TRUE(heap()->marking_state()->IsMarked(host)); + EXPECT_TRUE(heap()->marking_state()->IsMarked(value1)); + EXPECT_TRUE(heap()->marking_state()->IsMarked(value2)); +} + +TEST_F(HeapWriteBarrierTest, WriteBarrier_MarkingExtension) { + if (!v8_flags.incremental_marking) return; + ManualGCScope manual_gc_scope(i_isolate()); + DirectHandle<FixedArray> objects = factory()->NewFixedArray(1); + ArrayBufferExtension* extension; + { + HandleScope inner(i_isolate()); + Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(v8_isolate(), 100); + DirectHandle<JSArrayBuffer> host = v8::Utils::OpenDirectHandle(*ab); + extension = host->extension(); + objects->set(0, *host); + } + SimulateIncrementalMarking(false); + Tagged<JSArrayBuffer> host = Cast<JSArrayBuffer>(objects->get(0)); + EXPECT_TRUE(heap()->marking_state()->IsUnmarked(host)); + EXPECT_FALSE(extension->IsMarked()); + WriteBarrier::ForArrayBufferExtension(host, extension); + // Concurrent marking barrier should mark the value now. + EXPECT_TRUE(extension->IsMarked()); + // Keep object alive using the global handle. + v8::Global<ArrayBufferBase> global_host( + v8_isolate(), Utils::ToLocal(direct_handle(host, i_isolate()))); + SimulateIncrementalMarking(true); + EXPECT_TRUE(heap()->marking_state()->IsMarked(host)); + EXPECT_TRUE(extension->IsMarked()); +} + } // namespace v8::internal diff --git a/deps/v8/test/unittests/inspector/inspector-unittest.cc b/deps/v8/test/unittests/inspector/inspector-unittest.cc index ddbcf7694167..7aefaf42a6e7 100644 --- a/deps/v8/test/unittests/inspector/inspector-unittest.cc +++ b/deps/v8/test/unittests/inspector/inspector-unittest.cc @@ -4,7 +4,10 @@ #include <memory> #include <span> +#include <string> +#include "include/v8-external.h" +#include "include/v8-function.h" #include "include/v8-inspector.h" #include "include/v8-local-handle.h" #include "include/v8-primitive.h" @@ -233,6 +236,77 @@ class TestChannel : public V8Inspector::Channel { v8_inspector::String16 expected_response_matcher_; }; +class DeepSerializeEmbedderClient : public v8_inspector::V8InspectorClient { + public: + std::unique_ptr<v8_inspector::DeepSerializationResult> deepSerialize( + v8::Local<v8::Value> v8Value, int maxDepth, + v8::Local<v8::Object> additionalParameters) override { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + if (v8Value->IsObject()) { + v8::Local<v8::Object> obj = v8Value.As<v8::Object>(); + v8::Local<v8::Value> marker; + if (obj->Get(context, + v8::String::NewFromUtf8Literal(isolate, "embedder_marker")) + .ToLocal(&marker) && + marker->IsTrue()) { + auto deep_val = std::make_unique<v8_inspector::DeepSerializedValue>( + v8_inspector::StringBuffer::create(toStringView("embedder_node")), + v8::String::NewFromUtf8Literal(isolate, "a")); + return std::make_unique<v8_inspector::DeepSerializationResult>( + std::move(deep_val)); + } + } + return nullptr; + } +}; + +class OOMTestChannel : public v8_inspector::V8Inspector::Channel { + public: + ~OOMTestChannel() override = default; + void sendResponse( + int callId, + std::unique_ptr<v8_inspector::StringBuffer> message) override { + response_ = v8_inspector::toString16(message->string()); + } + void sendNotification( + std::unique_ptr<v8_inspector::StringBuffer> message) override {} + void flushProtocolNotifications() override {} + + v8_inspector::String16 response_; +}; + +TEST_F(InspectorTest, RegressDeepSerializeBudget) { + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope handle_scope(isolate); + + DeepSerializeEmbedderClient client; + std::unique_ptr<V8Inspector> inspector = + V8Inspector::create(isolate, &client); + V8ContextInfo context_info(v8_context(), 1, toStringView("")); + inspector->contextCreated(context_info); + + OOMTestChannel channel; + std::unique_ptr<V8InspectorSession> session = + inspector->connect(1, &channel, toStringView("{}"), + v8_inspector::V8Inspector::kFullyTrusted); + + std::string command = + "{\"id\": 1, \"method\": \"Runtime.evaluate\", \"params\": " + "{\"expression\": " + "\"[{embedder_marker: true}, 'x'.repeat(" + + std::to_string(v8::String::kMaxLength) + + ")]\", \"contextId\": 1, \"generatePreview\": false, " + "\"serializationOptions\": " + "{\"serialization\": \"deep\"}}}"; + + session->dispatchProtocolMessage(toStringView(String16(command.c_str()))); + + CHECK_NE( + channel.response_.find(toString16(toStringView("Object is too large"))), + String16::kNotFound); +} + TEST_F(InspectorTest, NoConsoleAPIForUntrustedClient) { v8::Isolate* isolate = v8_isolate(); v8::HandleScope handle_scope(isolate); @@ -616,5 +690,166 @@ TEST_F(InspectorTest, WrapObjectWithCustomPreviewNoPreview) { EXPECT_FALSE(remote_object->hasCustomPreview()); EXPECT_EQ(channel.triggerCount(), 0); } + +namespace { + +void TerminateExecutionCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + info.GetIsolate()->TerminateExecution(); +} + +} // namespace + +// Regression test for the dangling termination exception left behind by +// generateCustomPreview() when it runs at call depth zero without an outer +// v8::TryCatch (e.g. an embedder calling V8InspectorSession::wrapObject with +// generatePreview=true from C++). +TEST_F(InspectorTest, TerminationInCustomPreviewAtCallDepthZero) { + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope handle_scope(isolate); + + v8_inspector::V8InspectorClient default_client; + std::unique_ptr<V8Inspector> inspector = + V8Inspector::create(isolate, &default_client); + V8ContextInfo context_info(v8_context(), 1, toStringView("")); + inspector->contextCreated(context_info); + + NoopChannel channel; + std::unique_ptr<V8InspectorSession> session = + inspector->connect(1, &channel, toStringView("{}"), + v8_inspector::V8Inspector::kFullyTrusted); + session->dispatchProtocolMessage(toStringView(R"({ + "id": 1, + "method": "Runtime.enable" + })")); + session->dispatchProtocolMessage(toStringView(R"({ + "id": 2, + "method": "Runtime.setCustomObjectFormatterEnabled", + "params": {"enabled": true} + })")); + + v8::Local<v8::Function> terminate = + v8::Function::New(v8_context(), &TerminateExecutionCallback) + .ToLocalChecked(); + CHECK(v8_context() + ->Global() + ->Set(v8_context(), NewString("terminate"), terminate) + .FromJust()); + + // The custom formatter terminates execution while generateCustomPreview() + // calls into it. + TryRunJS(R"( + this.devtoolsFormatters = [{ + header: (x) => { terminate(); return ['span', 'header']; }, + hasBody: (x) => false, + }]; + this.obj = {a: 1}; + )"); + CHECK(!isolate->IsExecutionTerminating()); + + v8::Local<v8::Value> obj = v8_context() + ->Global() + ->Get(v8_context(), NewString("obj")) + .ToLocalChecked(); + + // No enclosing v8::TryCatch and no JavaScript on the stack: call depth is + // zero here. + session->wrapObject(v8_context(), obj, toStringView("testGroup"), + /*generatePreview=*/true); + + // The termination must not be left pending on the isolate after the API + // call returned at call depth zero: the next V8 API call would hit + // DCHECK(!is_execution_terminating()) in EnterV8InternalScope. + CHECK(!isolate->IsExecutionTerminating()); +} + +namespace { + +// Calls into JavaScript for every Debugger.paused and Debugger.resumed +// notification, like an embedder that exposes an in-process session to JS. +class JSCallbackChannel : public V8Inspector::Channel { + public: + JSCallbackChannel(v8::Isolate* isolate, v8::Local<v8::Context> context, + v8::Local<v8::Function> callback) + : m_isolate(isolate), + m_context(isolate, context), + m_callback(isolate, callback) {} + ~JSCallbackChannel() override = default; + + void sendResponse(int callId, + std::unique_ptr<StringBuffer> message) override {} + + void sendNotification(std::unique_ptr<StringBuffer> message) override { + String16 message_str = toString16(message->string()); + if (message_str.find("Debugger.paused") == String16::kNotFound && + message_str.find("Debugger.resumed") == String16::kNotFound) { + return; + } + v8::HandleScope handle_scope(m_isolate); + v8::Local<v8::Context> context = m_context.Get(m_isolate); + v8::Context::Scope context_scope(context); + m_callback.Get(m_isolate) + ->Call(context, v8::Undefined(m_isolate), 0, nullptr) + .ToLocalChecked(); + } + + void flushProtocolNotifications() override {} + + private: + v8::Isolate* m_isolate; + v8::Global<v8::Context> m_context; + v8::Global<v8::Function> m_callback; +}; + +void DispatchPause(const v8::FunctionCallbackInfo<v8::Value>& info) { + static_cast<V8InspectorSession*>(info.DataV2().As<v8::External>()->Value( + v8::kExternalPointerTypeTagDefault)) + ->dispatchProtocolMessage( + toStringView(R"({"id": 2, "method": "Debugger.pause"})")); +} + +} // namespace + +TEST_F(InspectorTest, ChannelCanRunJSWhenPausedOnInterrupt) { + v8::Isolate* isolate = v8_isolate(); + v8::HandleScope handle_scope(isolate); + + v8_inspector::V8InspectorClient default_client; + std::unique_ptr<V8Inspector> inspector = + V8Inspector::create(isolate, &default_client); + V8ContextInfo context_info(v8_context(), 1, toStringView("")); + inspector->contextCreated(context_info); + + v8::Local<v8::Function> callback = + RunJS("globalThis.notifications = 0; () => notifications++") + .As<v8::Function>(); + JSCallbackChannel channel(isolate, v8_context(), callback); + std::unique_ptr<V8InspectorSession> session = inspector->connect( + 1, &channel, toStringView("{}"), v8_inspector::V8Inspector::kFullyTrusted, + v8_inspector::V8Inspector::kNotWaitingForDebugger); + session->dispatchProtocolMessage( + toStringView(R"({"id": 1, "method": "Debugger.enable"})")); + + v8::Local<v8::Function> pause = + v8::Function::New(v8_context(), &DispatchPause, + v8::External::New(isolate, session.get(), + v8::kExternalPointerTypeTagDefault)) + .ToLocalChecked(); + CHECK(v8_context() + ->Global() + ->Set(v8_context(), NewString("pause"), pause) + .FromJust()); + + // Debugger.pause while JavaScript runs schedules the break through an API + // interrupt, where JavaScript execution is disallowed. The loop spins until + // it takes that interrupt on a back edge. Taken on function entry instead, + // V8 would step in and pause at the next statement, outside the interrupt, + // so the count is read in the same script. + v8::Local<v8::Value> result = RunJS( + "pause();" + "for (let i = 0; i < 1e7 && notifications === 0; i++) {}" + "notifications"); + CHECK_EQ(result->Int32Value(v8_context()).FromJust(), 2); +} } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 1a98ec1c0eea..8ae6d11a09c5 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -45,7 +45,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { DeclarationScope scope(zone(), &ast_factory); Handle<ScopeInfo> scope_info = factory->NewScopeInfo(0); - int flags = ScopeInfo::HasContextCellsBit::encode(true); + auto flags = ScopeInfo::Flags{}.with_has_context_cells(true); scope_info->set_flags(flags, kRelaxedStore); scope_info->set_context_local_count(0); scope_info->set_parameter_count(0); @@ -195,7 +195,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .PopContext(reg); Handle<ScopeInfo> scope_info2 = factory->NewScopeInfo(0); - int flags2 = ScopeInfo::HasContextCellsBit::encode(false); + auto flags2 = ScopeInfo::Flags{}.with_has_context_cells(false); scope_info2->set_flags(flags2, kRelaxedStore); scope_info2->set_context_local_count(0); scope_info2->set_parameter_count(0); @@ -217,7 +217,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .PopContext(reg); Handle<ScopeInfo> scope_info3 = factory->NewScopeInfo(0); - int flags3 = ScopeInfo::IsHoistedInContextBit::encode(true); + auto flags3 = ScopeInfo::Flags{}.with_is_hoisted_in_context(true); scope_info3->set_flags(flags3, kRelaxedStore); scope_info3->set_context_local_count(0); scope_info3->set_parameter_count(0); @@ -227,7 +227,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { scope_info3); EXPECT_TRUE(fun_scope3.is_hoisted_in_context()); - int flags4 = ScopeInfo::IsHoistedInContextBit::encode(false); + auto flags4 = ScopeInfo::Flags{}.with_is_hoisted_in_context(false); scope_info3->set_flags(flags4, kRelaxedStore); DeclarationScope fun_scope4(zone(), ScopeType::FUNCTION_SCOPE, &ast_factory, scope_info3); @@ -284,7 +284,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .LoadLookupGlobalSlot(name, TypeofMode::kInside, 1, 0); // Emit closure operations. - builder.CreateClosure(0, 1, static_cast<int>(AllocationType::kYoung)); + builder.CreateClosure(0, 1, CreateClosureFlags::Encode(false)); // Emit create context operation. builder.CreateBlockContext(&scope); @@ -520,7 +520,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { LookupHoistingMode::kNormal); // CreateClosureWide - builder.CreateClosure(1000, 321, static_cast<int>(AllocationType::kYoung)); + builder.CreateClosure(1000, 321, CreateClosureFlags::Encode(false)); // Emit wide variant of literal creation operations. builder diff --git a/deps/v8/test/unittests/interpreter/bytecode-expectations-printer.cc b/deps/v8/test/unittests/interpreter/bytecode-expectations-printer.cc index 940e8520b737..965baece264b 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-expectations-printer.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-expectations-printer.cc @@ -99,10 +99,10 @@ i::Handle<i::BytecodeArray> BytecodeExpectationsPrinter::GetBytecodeArrayForModule( v8::Local<v8::Module> module) const { i::DirectHandle<i::Module> i_module = v8::Utils::OpenDirectHandle(*module); - return i::handle( - Cast<SharedFunctionInfo>(Cast<i::SourceTextModule>(i_module)->code()) - ->GetBytecodeArray(i_isolate()), - i_isolate()); + return i::handle(Cast<i::SourceTextModule>(i_module) + ->GetSharedFunctionInfo() + ->GetBytecodeArray(i_isolate()), + i_isolate()); } i::Handle<i::BytecodeArray> diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/BasicLoops.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/BasicLoops.golden index 268db9545db1..835a70b91b98 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/BasicLoops.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/BasicLoops.golden @@ -669,7 +669,7 @@ bytecodes: [ B(PushContext), R(3), B(LdaTdzHole), B(StaCurrentContextSlotNoCell), C8(2), - B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), /* 73 S> */ B(LdaSmi), I8(1), /* 73 E> */ B(StaCurrentContextSlotNoCell), C8(2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/BreakableBlocks.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/BreakableBlocks.golden index 03d1fab80417..3b08e6e33e3d 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/BreakableBlocks.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/BreakableBlocks.golden @@ -103,7 +103,7 @@ bytecodes: [ B(PushContext), R(2), B(LdaTdzHole), B(StaCurrentContextSlotNoCell), C8(2), - B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star1), /* 53 S> */ B(LdaSmi), I8(10), /* 53 E> */ B(StaCurrentContextSlotNoCell), C8(2), @@ -148,7 +148,7 @@ bytecodes: [ B(PushContext), R(3), B(LdaTdzHole), B(StaCurrentContextSlotNoCell), C8(2), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star1), /* 76 S> */ B(LdaSmi), I8(2), /* 76 E> */ B(StaCurrentContextSlotNoCell), C8(2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/CallLookupSlot.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/CallLookupSlot.golden index 3904fdf27418..eb09adb040f5 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/CallLookupSlot.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/CallLookupSlot.golden @@ -21,7 +21,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(5), B(Ldar), R(0), B(StaCurrentContextSlotNoCell), C8(4), - /* 34 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 34 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 36 E> */ B(StaLookupSlot), U8(2:"g"), Flag8(0x0), /* 52 S> */ B(LdaLookupGlobalSlot), U8(3:"eval"), FBV(0), U8(1), B(Star2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/CallNew.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/CallNew.golden index 8045161eb8b1..91f2ec4e076e 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/CallNew.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/CallNew.golden @@ -97,7 +97,7 @@ bytecodes: [ B(PushContext), R(0), B(LdaTheHole), B(Star4), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star1), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/ClassDeclarations.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/ClassDeclarations.golden index cbd3c9d65956..c307832141f1 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/ClassDeclarations.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/ClassDeclarations.golden @@ -20,11 +20,11 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star6), B(Mov), R(2), R(4), B(CallRuntime), U16(Runtime::kDefineClass), R(3), RegCount8(4), @@ -57,11 +57,11 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star6), B(Mov), R(2), R(4), B(CallRuntime), U16(Runtime::kDefineClass), R(3), RegCount8(4), @@ -102,14 +102,14 @@ bytecodes: [ B(PushContext), R(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(4:CLASS_BOILERPLATE_TYPE), B(Star4), /* 75 S> */ B(LdaImmutableContextSlot), R(2), C8(2), U8(0), B(ToName), B(Star7), - B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star8), /* 106 S> */ B(LdaImmutableContextSlot), R(2), C8(3), U8(0), B(ToName), @@ -119,7 +119,7 @@ bytecodes: [ B(Mov), R(3), R(5), B(JumpIfFalse), U8(7), B(CallRuntime), U16(Runtime::kThrowStaticPrototypeError), R(0), RegCount8(0), - B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star10), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(7), B(PopContext), R(2), @@ -159,7 +159,7 @@ bytecodes: [ B(PushContext), R(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(2:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -193,7 +193,7 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -204,11 +204,11 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(4:CLASS_BOILERPLATE_TYPE), B(Star3), - B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star6), B(Mov), R(2), R(4), B(CallRuntime), U16(Runtime::kDefineClass), R(3), RegCount8(4), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/CompoundExpressions.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/CompoundExpressions.golden index 4b8d4114eebe..f6926c2fb958 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/CompoundExpressions.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/CompoundExpressions.golden @@ -104,7 +104,7 @@ bytecodes: [ B(PushContext), R(0), /* 42 S> */ B(LdaSmi), I8(1), /* 42 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 45 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 45 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 75 S> */ B(LdaCurrentContextSlotNoCell), C8(2), B(BitwiseOrSmi), I8(24), EmbeddedFeedback(), /* 77 E> */ B(StaCurrentContextSlotNoCell), C8(2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextParameters.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextParameters.golden index 65bd0632f460..424a59f47b8c 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextParameters.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextParameters.golden @@ -19,7 +19,7 @@ bytecodes: [ B(PushContext), R(0), B(Ldar), R(arg0), B(StaCurrentContextSlotNoCell), C8(2), - /* 19 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 19 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 51 S> */ B(Return), ] constant pool: [ @@ -42,7 +42,7 @@ bytecodes: [ B(PushContext), R(1), B(Ldar), R(arg0), B(StaCurrentContextSlotNoCell), C8(2), - /* 27 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 27 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star0), /* 53 S> */ B(LdaCurrentContextSlotNoCell), C8(2), /* 65 S> */ B(Return), @@ -69,7 +69,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(Ldar), R(arg2), B(StaCurrentContextSlotNoCell), C8(2), - /* 29 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 29 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 60 S> */ B(Return), ] constant pool: [ @@ -92,7 +92,7 @@ bytecodes: [ B(PushContext), R(0), /* 26 S> */ B(Ldar), R(this), /* 26 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 32 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 32 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 64 S> */ B(Return), ] constant pool: [ diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextVariables.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextVariables.golden index 0864076bd77a..74e68c124bf4 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextVariables.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/ContextVariables.golden @@ -15,7 +15,7 @@ bytecode array length: 10 bytecodes: [ /* 30 E> */ B(CreateFunctionContext), U8(0:SCOPE_INFO_TYPE), U8(1), B(PushContext), R(0), - /* 41 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 41 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 70 S> */ B(Return), ] constant pool: [ @@ -37,7 +37,7 @@ bytecodes: [ B(PushContext), R(0), /* 42 S> */ B(LdaSmi), I8(1), /* 42 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 45 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 45 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 74 S> */ B(Return), ] constant pool: [ @@ -61,7 +61,7 @@ bytecodes: [ /* 42 E> */ B(StaCurrentContextSlotNoCell), C8(2), /* 53 S> */ B(LdaSmi), I8(2), /* 53 E> */ B(StaCurrentContextSlotNoCell), C8(3), - /* 56 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 56 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 91 S> */ B(Return), ] constant pool: [ @@ -81,7 +81,7 @@ bytecode array length: 16 bytecodes: [ /* 30 E> */ B(CreateFunctionContext), U8(0:SCOPE_INFO_TYPE), U8(1), B(PushContext), R(0), - /* 41 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 41 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star1), /* 64 E> */ B(CallUndefinedReceiver0), R(1), FBV(0), /* 68 S> */ B(LdaCurrentContextSlotNoCell), C8(2), @@ -116,7 +116,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), /* 69 S> */ B(LdaSmi), I8(2), /* 69 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 72 S> */ B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 72 S> */ B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 101 S> */ B(Return), ] constant pool: [ diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/CountOperators.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/CountOperators.golden index 1425763e59a9..16e087d8bcda 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/CountOperators.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/CountOperators.golden @@ -205,7 +205,7 @@ bytecodes: [ B(PushContext), R(1), /* 42 S> */ B(LdaSmi), I8(1), /* 42 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 53 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 53 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star0), /* 78 S> */ B(LdaCurrentContextSlotNoCell), C8(2), B(Inc), EmbeddedFeedback(), @@ -231,7 +231,7 @@ bytecodes: [ B(PushContext), R(1), /* 42 S> */ B(LdaSmi), I8(1), /* 42 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 53 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 53 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star0), /* 78 S> */ B(LdaCurrentContextSlotNoCell), C8(2), B(ToNumeric), FBV(0), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/Delete.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/Delete.golden index 0ea810751903..90913db9dd49 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/Delete.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/Delete.golden @@ -100,7 +100,7 @@ bytecodes: [ B(PushContext), R(0), /* 56 S> */ B(CreateObjectLiteral), U8(1:OBJECT_BOILERPLATE_DESCRIPTION_TYPE), FBV(0), Flag8(0x29), /* 56 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 64 S> */ B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 64 S> */ B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 93 S> */ B(LdaImmutableCurrentContextSlot), C8(2), B(Star1), B(LdaSmi), I8(1), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/ForOfLoop.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/ForOfLoop.golden index ee6263cdeb12..32c6cae202c9 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/ForOfLoop.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/ForOfLoop.golden @@ -258,7 +258,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), /* 29 S> */ B(Ldar), R(0), /* 29 E> */ B(StaCurrentContextSlotNoCell), C8(2), - /* 41 S> */ B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 41 S> */ B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star11), /* 67 E> */ B(CallUndefinedReceiver0), R(11), FBV(12), B(PopContext), R(10), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/FunctionLiterals.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/FunctionLiterals.golden index c7c18944cd5b..371ff941beb0 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/FunctionLiterals.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/FunctionLiterals.golden @@ -13,7 +13,7 @@ frame size: 0 parameter count: 1 bytecode array length: 5 bytecodes: [ - /* 34 S> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 34 S> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), /* 54 S> */ B(Return), ] constant pool: [ @@ -30,7 +30,7 @@ frame size: 1 parameter count: 1 bytecode array length: 9 bytecodes: [ - /* 34 S> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 34 S> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star0), /* 56 E> */ B(CallUndefinedReceiver0), R(0), FBV(0), /* 58 S> */ B(Return), @@ -49,7 +49,7 @@ frame size: 2 parameter count: 1 bytecode array length: 13 bytecodes: [ - /* 34 S> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 34 S> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star0), B(LdaSmi), I8(1), B(Star1), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/NewAndSpread.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/NewAndSpread.golden index 4d4429504e56..389a11629efb 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/NewAndSpread.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/NewAndSpread.golden @@ -18,7 +18,7 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -55,7 +55,7 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -94,7 +94,7 @@ bytecodes: [ B(PushContext), R(1), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden index c972f099ddeb..3da7918c5954 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/ObjectLiterals.golden @@ -97,7 +97,7 @@ bytecode array length: 16 bytecodes: [ /* 34 S> */ B(CreateObjectLiteral), U8(0:OBJECT_BOILERPLATE_DESCRIPTION_TYPE), FBV(0), Flag8(0x29), B(Star0), - /* 49 E> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 49 E> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(DefineNamedOwnPropertyInLiteral), R(0), U8(2:"func"), FBV(1), B(Ldar), R(0), /* 66 S> */ B(Return), @@ -120,7 +120,7 @@ bytecode array length: 16 bytecodes: [ /* 34 S> */ B(CreateObjectLiteral), U8(0:OBJECT_BOILERPLATE_DESCRIPTION_TYPE), FBV(0), Flag8(0x29), B(Star0), - /* 43 E> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 43 E> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(DefineNamedOwnPropertyInLiteral), R(0), U8(2:"func"), FBV(1), B(Ldar), R(0), /* 67 S> */ B(Return), @@ -145,7 +145,7 @@ bytecodes: [ B(Star0), B(LdaConstant), U8(1:"a"), B(Star2), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaNull), B(Star4), @@ -176,9 +176,9 @@ bytecodes: [ B(Star0), B(LdaConstant), U8(1:"a"), B(Star2), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(LdaZero), B(Star5), @@ -210,7 +210,7 @@ bytecodes: [ B(Star2), B(LdaNull), B(Star3), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star4), B(LdaZero), B(Star5), @@ -376,7 +376,7 @@ bytecodes: [ /* 64 E> */ B(DefineKeyedOwnPropertyInLiteral), R(1), R(2), Flag8(0x0), FBV(1), B(LdaConstant), U8(3:"a"), B(Star3), - /* 71 E> */ B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 71 E> */ B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star4), B(LdaZero), B(Star5), @@ -384,7 +384,7 @@ bytecodes: [ B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), R(2), RegCount8(4), B(LdaConstant), U8(3:"a"), B(Star3), - /* 84 E> */ B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + /* 84 E> */ B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(LdaZero), B(Star5), @@ -403,3 +403,27 @@ constant pool: [ handlers: [ ] +--- +snippet: " + var a = { x: 1 }; return { ...a, x: 2 }; +" +frame size: 2 +parameter count: 1 +bytecode array length: 19 +bytecodes: [ + /* 42 S> */ B(CreateObjectLiteral), U8(0:OBJECT_BOILERPLATE_DESCRIPTION_TYPE), FBV(0), Flag8(0x29), + B(Star0), + /* 52 S> */ B(CloneObject), R(0), Flag8(0x29), FBV(1), + B(Star1), + B(LdaSmi), I8(2), + /* 70 E> */ B(DefineNamedOwnPropertyInLiteral), R(1), U8(1:"x"), FBV(3), + B(Ldar), R(1), + /* 74 S> */ B(Return), +] +constant pool: [ + OBJECT_BOILERPLATE_DESCRIPTION_TYPE, + INTERNALIZED_ONE_BYTE_STRING_TYPE ["x"], +] +handlers: [ +] + diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorAccess.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorAccess.golden index c513769242c3..e8668d47fcdb 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorAccess.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorAccess.golden @@ -83,7 +83,7 @@ bytecodes: [ /* 48 E> */ B(DefineKeyedOwnProperty), R(this), R(0), Flag8(0x0), FBV(0), /* 53 S> */ B(LdaImmutableCurrentContextSlot), C8(3), /* 58 E> */ B(GetKeyedProperty), R(this), FBV(2), - B(Wide), B(LdaSmi), I16(342), + B(Wide), B(LdaSmi), I16(341), B(Star2), B(LdaConstant), U8(0:"#b"), B(Star3), @@ -115,7 +115,7 @@ bytecodes: [ /* 41 E> */ B(DefineKeyedOwnProperty), R(this), R(0), Flag8(0x0), FBV(0), /* 46 S> */ B(LdaImmutableCurrentContextSlot), C8(3), /* 51 E> */ B(GetKeyedProperty), R(this), FBV(2), - B(Wide), B(LdaSmi), I16(341), + B(Wide), B(LdaSmi), I16(340), B(Star2), B(LdaConstant), U8(0:"#c"), B(Star3), @@ -149,7 +149,7 @@ bytecodes: [ B(Star2), B(LdaImmutableCurrentContextSlot), C8(3), /* 58 E> */ B(GetKeyedProperty), R(this), FBV(2), - B(Wide), B(LdaSmi), I16(342), + B(Wide), B(LdaSmi), I16(341), B(Star3), B(LdaConstant), U8(0:"#d"), B(Star4), @@ -181,7 +181,7 @@ bytecodes: [ /* 41 E> */ B(DefineKeyedOwnProperty), R(this), R(0), Flag8(0x0), FBV(0), /* 46 S> */ B(LdaImmutableCurrentContextSlot), C8(3), /* 51 E> */ B(GetKeyedProperty), R(this), FBV(2), - B(Wide), B(LdaSmi), I16(341), + B(Wide), B(LdaSmi), I16(340), B(Star2), B(LdaConstant), U8(0:"#e"), B(Star3), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden index e52f9bb33d62..05d172d0de65 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateAccessorDeclaration.golden @@ -24,15 +24,15 @@ bytecodes: [ B(Star3), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(3), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(3), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -72,7 +72,7 @@ bytecodes: [ B(Star3), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(3), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaNull), B(Star4), @@ -80,7 +80,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -121,13 +121,13 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaNull), B(Star3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(3), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -172,15 +172,15 @@ bytecodes: [ B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(4), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star4), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star5), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(4), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -194,13 +194,13 @@ bytecodes: [ B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(4), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star4), - B(CreateClosure), U8(10:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x2), + B(CreateClosure), U8(10:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x1), B(Star5), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(4), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), - /* 118 E> */ B(CreateClosure), U8(11:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x2), + /* 118 E> */ B(CreateClosure), U8(11:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x1), B(Star3), B(LdaConstant), U8(7:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -247,11 +247,11 @@ bytecodes: [ B(PushContext), R(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star7), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(4), @@ -263,13 +263,13 @@ bytecodes: [ B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(4), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(7:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(7:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star4), B(LdaNull), B(Star5), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(4), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), - /* 77 E> */ B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + /* 77 E> */ B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star3), B(LdaConstant), U8(5:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -317,11 +317,11 @@ bytecodes: [ B(PushContext), R(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star7), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(4), @@ -335,11 +335,11 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaNull), B(Star4), - B(CreateClosure), U8(7:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(7:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star5), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(4), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), - /* 80 E> */ B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + /* 80 E> */ B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star3), B(LdaConstant), U8(5:CLASS_BOILERPLATE_TYPE), B(Star4), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateClassFields.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateClassFields.golden index 7ebadf731143..3f77c8b57701 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateClassFields.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateClassFields.golden @@ -36,13 +36,13 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(3), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(SetNamedProperty), R(3), U8(5:SYMBOL_TYPE), FBV(0), B(PopContext), R(2), B(Mov), R(5), R(0), @@ -56,13 +56,13 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star3), B(LdaConstant), U8(7:CLASS_BOILERPLATE_TYPE), B(Star4), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(3), - B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(SetNamedProperty), R(3), U8(5:SYMBOL_TYPE), FBV(2), B(PopContext), R(2), B(Mov), R(5), R(1), @@ -137,20 +137,20 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star11), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star8), B(LdaConstant), U8(3:CLASS_BOILERPLATE_TYPE), B(Star9), B(Mov), R(8), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(9), RegCount8(3), - B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star5), B(Mov), R(4), R(6), B(Mov), R(10), R(7), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(3), - B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(SetNamedProperty), R(4), U8(7:SYMBOL_TYPE), FBV(0), B(PopContext), R(3), B(Mov), R(6), R(0), @@ -170,24 +170,24 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaTheHole), B(Star11), - B(CreateClosure), U8(12:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(12:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star8), B(LdaConstant), U8(11:CLASS_BOILERPLATE_TYPE), B(Star9), B(Mov), R(8), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(9), RegCount8(3), - B(CreateClosure), U8(13:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x2), + B(CreateClosure), U8(13:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x1), B(Star4), B(LdaConstant), U8(9:CLASS_BOILERPLATE_TYPE), B(Star5), - B(CreateClosure), U8(14:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x2), + B(CreateClosure), U8(14:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x1), B(Star8), - B(CreateClosure), U8(15:SHARED_FUNCTION_INFO_TYPE), FBV(6), Flag8(0x2), + B(CreateClosure), U8(15:SHARED_FUNCTION_INFO_TYPE), FBV(6), Flag8(0x1), B(Star9), B(Mov), R(4), R(6), B(Mov), R(10), R(7), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(5), - B(CreateClosure), U8(16:SHARED_FUNCTION_INFO_TYPE), FBV(7), Flag8(0x2), + B(CreateClosure), U8(16:SHARED_FUNCTION_INFO_TYPE), FBV(7), Flag8(0x1), B(SetNamedProperty), R(4), U8(7:SYMBOL_TYPE), FBV(2), B(PopContext), R(3), B(Mov), R(6), R(1), @@ -199,14 +199,14 @@ bytecodes: [ B(Star5), B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(2), - /* 356 E> */ B(CreateClosure), U8(19:SHARED_FUNCTION_INFO_TYPE), FBV(8), Flag8(0x2), + /* 356 E> */ B(CreateClosure), U8(19:SHARED_FUNCTION_INFO_TYPE), FBV(8), Flag8(0x1), B(Star4), B(LdaConstant), U8(18:CLASS_BOILERPLATE_TYPE), B(Star5), B(Mov), R(4), R(6), B(Mov), R(1), R(7), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(3), - B(CreateClosure), U8(20:SHARED_FUNCTION_INFO_TYPE), FBV(9), Flag8(0x2), + B(CreateClosure), U8(20:SHARED_FUNCTION_INFO_TYPE), FBV(9), Flag8(0x1), B(SetNamedProperty), R(4), U8(7:SYMBOL_TYPE), FBV(4), B(PopContext), R(3), B(Mov), R(6), R(2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodAccess.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodAccess.golden index 7d9b1b73cda6..09d29df41e09 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodAccess.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodAccess.golden @@ -58,7 +58,7 @@ bytecodes: [ B(Star2), B(LdaImmutableCurrentContextSlot), C8(3), /* 54 E> */ B(GetKeyedProperty), R(this), FBV(2), - B(Wide), B(LdaSmi), I16(340), + B(Wide), B(LdaSmi), I16(339), B(Star3), B(LdaConstant), U8(0:"#b"), B(Star4), @@ -91,7 +91,7 @@ bytecodes: [ /* 44 E> */ B(DefineKeyedOwnProperty), R(this), R(0), Flag8(0x0), FBV(0), /* 49 S> */ B(LdaImmutableCurrentContextSlot), C8(3), /* 54 E> */ B(GetKeyedProperty), R(this), FBV(2), - B(Wide), B(LdaSmi), I16(340), + B(Wide), B(LdaSmi), I16(339), B(Star2), B(LdaConstant), U8(0:"#c"), B(Star3), @@ -126,7 +126,7 @@ bytecodes: [ B(Star1), B(Ldar), R(0), B(DefineKeyedOwnProperty), R(this), R(1), Flag8(0x0), FBV(0), - /* 49 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 49 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), /* 61 E> */ B(CallUndefinedReceiver0), R(3), FBV(2), B(Star3), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden index 6341d1fc7203..b567977f7eb1 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/PrivateMethodDeclaration.golden @@ -23,11 +23,11 @@ bytecodes: [ B(Star3), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(3), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -69,11 +69,11 @@ bytecodes: [ B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(4), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -87,9 +87,9 @@ bytecodes: [ B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(4), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(2), - /* 93 E> */ B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + /* 93 E> */ B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star3), B(LdaConstant), U8(6:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -133,11 +133,11 @@ bytecodes: [ B(PushContext), R(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star7), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(4), @@ -149,9 +149,9 @@ bytecodes: [ B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(4), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(7:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(7:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(2), - /* 77 E> */ B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + /* 77 E> */ B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star3), B(LdaConstant), U8(5:CLASS_BOILERPLATE_TYPE), B(Star4), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/PublicClassFields.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/PublicClassFields.golden index 5db865ffb6c6..c2fbcc3f3a21 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/PublicClassFields.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/PublicClassFields.golden @@ -31,7 +31,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -40,7 +40,7 @@ bytecodes: [ B(Star7), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(4), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(SetNamedProperty), R(3), U8(5:SYMBOL_TYPE), FBV(0), B(PopContext), R(2), B(Mov), R(5), R(0), @@ -50,7 +50,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star3), B(LdaConstant), U8(7:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -59,7 +59,7 @@ bytecodes: [ B(Star7), B(Mov), R(3), R(5), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(4), - B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(9:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(SetNamedProperty), R(3), U8(5:SYMBOL_TYPE), FBV(2), B(PopContext), R(2), B(Mov), R(5), R(1), @@ -125,13 +125,13 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star11), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star8), B(LdaConstant), U8(2:CLASS_BOILERPLATE_TYPE), B(Star9), B(Mov), R(8), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(9), RegCount8(3), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star5), @@ -141,7 +141,7 @@ bytecodes: [ B(Mov), R(4), R(6), B(Mov), R(10), R(7), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(4), - B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(SetNamedProperty), R(4), U8(7:SYMBOL_TYPE), FBV(0), B(PopContext), R(3), B(Mov), R(6), R(0), @@ -151,25 +151,25 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star11), - B(CreateClosure), U8(11:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(11:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star8), B(LdaConstant), U8(10:CLASS_BOILERPLATE_TYPE), B(Star9), B(Mov), R(8), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(9), RegCount8(3), - B(CreateClosure), U8(12:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x2), + B(CreateClosure), U8(12:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x1), B(Star4), B(LdaConstant), U8(9:CLASS_BOILERPLATE_TYPE), B(Star5), /* 133 S> */ B(LdaConstant), U8(5:"b"), B(StaCurrentContextSlotNoCell), C8(2), B(Star8), - B(CreateClosure), U8(13:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x2), + B(CreateClosure), U8(13:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x1), B(Star9), B(Mov), R(4), R(6), B(Mov), R(10), R(7), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(5), - B(CreateClosure), U8(14:SHARED_FUNCTION_INFO_TYPE), FBV(6), Flag8(0x2), + B(CreateClosure), U8(14:SHARED_FUNCTION_INFO_TYPE), FBV(6), Flag8(0x1), B(SetNamedProperty), R(4), U8(7:SYMBOL_TYPE), FBV(2), B(PopContext), R(3), B(Mov), R(6), R(1), @@ -177,7 +177,7 @@ bytecodes: [ B(PushContext), R(3), B(LdaTdzHole), B(StaCurrentContextSlotNoCell), C8(2), - /* 236 E> */ B(CreateClosure), U8(17:SHARED_FUNCTION_INFO_TYPE), FBV(7), Flag8(0x2), + /* 236 E> */ B(CreateClosure), U8(17:SHARED_FUNCTION_INFO_TYPE), FBV(7), Flag8(0x1), B(Star4), B(LdaConstant), U8(16:CLASS_BOILERPLATE_TYPE), B(Star5), @@ -187,7 +187,7 @@ bytecodes: [ B(Mov), R(4), R(6), B(Mov), R(1), R(7), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(4), - B(CreateClosure), U8(18:SHARED_FUNCTION_INFO_TYPE), FBV(8), Flag8(0x2), + B(CreateClosure), U8(18:SHARED_FUNCTION_INFO_TYPE), FBV(8), Flag8(0x1), B(SetNamedProperty), R(4), U8(7:SYMBOL_TYPE), FBV(4), B(PopContext), R(3), B(Mov), R(6), R(2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden index 4cf494b89e4b..d80b4a436b56 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden @@ -21,7 +21,7 @@ frame size: 1 parameter count: 1 bytecode array length: 10 bytecodes: [ - /* 10 E> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 10 E> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star0), B(SetPrototypeProperties), U8(1:OBJECT_BOILERPLATE_DESCRIPTION_TYPE), FBV(1), B(LdaUndefined), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/StandardForLoop.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/StandardForLoop.golden index e0e42d1bd62b..11768b5c03a6 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/StandardForLoop.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/StandardForLoop.golden @@ -178,7 +178,7 @@ bytecodes: [ B(LdaSmi), I8(1), B(TestEqual), R(2), EmbeddedFeedback(), B(JumpIfFalse), U8(19), - /* 48 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 48 S> */ B(CreateClosure), U8(1:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star5), /* 74 E> */ B(CallUndefinedReceiver0), R(5), FBV(0), B(LdaZero), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticClassFields.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticClassFields.golden index 171412bd790e..411612375543 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticClassFields.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticClassFields.golden @@ -37,7 +37,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -54,9 +54,9 @@ bytecodes: [ B(Ldar), R(8), B(StaCurrentContextSlotNoCell), C8(3), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(5), - B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(6:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(SetNamedProperty), R(3), U8(7:SYMBOL_TYPE), FBV(0), - B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star5), B(CallProperty0), R(5), R(3), FBV(2), B(PopContext), R(2), @@ -69,7 +69,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaTheHole), B(Star6), - B(CreateClosure), U8(11:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(11:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star3), B(LdaConstant), U8(10:CLASS_BOILERPLATE_TYPE), B(Star4), @@ -86,9 +86,9 @@ bytecodes: [ B(Ldar), R(8), B(StaCurrentContextSlotNoCell), C8(3), B(CallRuntime), U16(Runtime::kDefineClass), R(4), RegCount8(5), - B(CreateClosure), U8(12:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x2), + B(CreateClosure), U8(12:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x1), B(SetNamedProperty), R(3), U8(7:SYMBOL_TYPE), FBV(4), - B(CreateClosure), U8(13:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x2), + B(CreateClosure), U8(13:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x1), B(Star5), B(CallProperty0), R(5), R(3), FBV(6), B(PopContext), R(2), @@ -167,13 +167,13 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaTheHole), B(Star11), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star8), B(LdaConstant), U8(2:CLASS_BOILERPLATE_TYPE), B(Star9), B(Mov), R(8), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(9), RegCount8(3), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star5), @@ -191,9 +191,9 @@ bytecodes: [ B(Ldar), R(9), B(StaCurrentContextSlotNoCell), C8(3), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(5), - B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(8:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(SetNamedProperty), R(4), U8(9:SYMBOL_TYPE), FBV(0), - B(CreateClosure), U8(10:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x2), + B(CreateClosure), U8(10:SHARED_FUNCTION_INFO_TYPE), FBV(3), Flag8(0x1), B(Star6), B(CallProperty0), R(6), R(4), FBV(2), B(PopContext), R(3), @@ -206,13 +206,13 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(3), B(LdaTheHole), B(Star11), - B(CreateClosure), U8(14:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x2), + B(CreateClosure), U8(14:SHARED_FUNCTION_INFO_TYPE), FBV(4), Flag8(0x1), B(Star8), B(LdaConstant), U8(13:CLASS_BOILERPLATE_TYPE), B(Star9), B(Mov), R(8), R(10), B(CallRuntime), U16(Runtime::kDefineClass), R(9), RegCount8(3), - B(CreateClosure), U8(15:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x2), + B(CreateClosure), U8(15:SHARED_FUNCTION_INFO_TYPE), FBV(5), Flag8(0x1), B(Star4), B(LdaConstant), U8(12:CLASS_BOILERPLATE_TYPE), B(Star5), @@ -229,12 +229,12 @@ bytecodes: [ B(CallRuntime), U16(Runtime::kThrowStaticPrototypeError), R(0), RegCount8(0), B(Ldar), R(9), B(StaCurrentContextSlotNoCell), C8(3), - B(CreateClosure), U8(16:SHARED_FUNCTION_INFO_TYPE), FBV(6), Flag8(0x2), + B(CreateClosure), U8(16:SHARED_FUNCTION_INFO_TYPE), FBV(6), Flag8(0x1), B(Star10), B(CallRuntime), U16(Runtime::kDefineClass), R(5), RegCount8(6), - B(CreateClosure), U8(17:SHARED_FUNCTION_INFO_TYPE), FBV(7), Flag8(0x2), + B(CreateClosure), U8(17:SHARED_FUNCTION_INFO_TYPE), FBV(7), Flag8(0x1), B(SetNamedProperty), R(4), U8(9:SYMBOL_TYPE), FBV(4), - B(CreateClosure), U8(18:SHARED_FUNCTION_INFO_TYPE), FBV(8), Flag8(0x2), + B(CreateClosure), U8(18:SHARED_FUNCTION_INFO_TYPE), FBV(8), Flag8(0x1), B(Star6), B(CallProperty0), R(6), R(4), FBV(6), B(PopContext), R(3), @@ -245,7 +245,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTdzHole), B(StaCurrentContextSlotNoCell), C8(3), - /* 313 E> */ B(CreateClosure), U8(21:SHARED_FUNCTION_INFO_TYPE), FBV(9), Flag8(0x2), + /* 313 E> */ B(CreateClosure), U8(21:SHARED_FUNCTION_INFO_TYPE), FBV(9), Flag8(0x1), B(Star4), B(LdaConstant), U8(20:CLASS_BOILERPLATE_TYPE), B(Star5), @@ -266,9 +266,9 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(4), B(Ldar), R(4), B(StaCurrentContextSlotNoCell), C8(5), - B(CreateClosure), U8(22:SHARED_FUNCTION_INFO_TYPE), FBV(10), Flag8(0x2), + B(CreateClosure), U8(22:SHARED_FUNCTION_INFO_TYPE), FBV(10), Flag8(0x1), B(SetNamedProperty), R(4), U8(9:SYMBOL_TYPE), FBV(8), - B(CreateClosure), U8(23:SHARED_FUNCTION_INFO_TYPE), FBV(11), Flag8(0x2), + B(CreateClosure), U8(23:SHARED_FUNCTION_INFO_TYPE), FBV(11), Flag8(0x1), B(Star6), B(CallProperty0), R(6), R(4), FBV(10), B(PopContext), R(3), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodAccess.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodAccess.golden index 7bc4e1bfda0f..0a27738beb27 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodAccess.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodAccess.golden @@ -24,7 +24,7 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(1), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star2), B(LdaConstant), U8(0:"A"), B(Star3), @@ -61,13 +61,13 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star2), B(LdaConstant), U8(0:"B"), B(Star3), /* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), RegCount8(2), B(Throw), - B(Wide), B(LdaSmi), I16(340), + B(Wide), B(LdaSmi), I16(339), B(Star2), B(LdaConstant), U8(1:"#b"), B(Star3), @@ -99,13 +99,13 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star1), B(LdaConstant), U8(0:"C"), B(Star2), /* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), RegCount8(2), B(Throw), - B(Wide), B(LdaSmi), I16(340), + B(Wide), B(LdaSmi), I16(339), B(Star1), B(LdaConstant), U8(1:"#c"), B(Star2), @@ -145,7 +145,7 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star2), B(LdaConstant), U8(0:"D"), B(Star3), @@ -167,7 +167,7 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star3), B(LdaConstant), U8(0:"D"), B(Star4), @@ -182,7 +182,7 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star2), B(LdaConstant), U8(0:"D"), B(Star3), @@ -216,13 +216,13 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star1), B(LdaConstant), U8(0:"E"), B(Star2), /* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), RegCount8(2), B(Throw), - B(Wide), B(LdaSmi), I16(342), + B(Wide), B(LdaSmi), I16(341), B(Star1), B(LdaConstant), U8(1:"#e"), B(Star2), @@ -253,13 +253,13 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star1), B(LdaConstant), U8(0:"F"), B(Star2), /* 58 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), RegCount8(2), B(Throw), - B(Wide), B(LdaSmi), I16(341), + B(Wide), B(LdaSmi), I16(340), B(Star1), B(LdaConstant), U8(1:"#f"), B(Star2), @@ -292,13 +292,13 @@ bytecodes: [ B(TestReferenceEqual), R(this), B(Mov), R(this), R(0), B(JumpIfTrue), U8(16), - B(Wide), B(LdaSmi), I16(334), + B(Wide), B(LdaSmi), I16(333), B(Star2), B(LdaConstant), U8(0:"G"), B(Star3), /* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(2), RegCount8(2), B(Throw), - B(Wide), B(LdaSmi), I16(342), + B(Wide), B(LdaSmi), I16(341), B(Star2), B(LdaConstant), U8(1:"#d"), B(Star3), @@ -327,7 +327,7 @@ bytecode array length: 19 bytecodes: [ /* 46 S> */ B(LdaImmutableCurrentContextSlot), C8(3), /* 51 E> */ B(GetKeyedProperty), R(this), FBV(0), - B(Wide), B(LdaSmi), I16(341), + B(Wide), B(LdaSmi), I16(340), B(Star1), B(LdaConstant), U8(0:"#h"), B(Star2), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodDeclaration.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodDeclaration.golden index 14e2e51478e8..f29a71b62b6c 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodDeclaration.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/StaticPrivateMethodDeclaration.golden @@ -19,11 +19,11 @@ bytecode array length: 35 bytecodes: [ /* 30 E> */ B(CreateBlockContext), U8(0:SCOPE_INFO_TYPE), B(PushContext), R(1), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -57,7 +57,7 @@ bytecode array length: 43 bytecodes: [ /* 30 E> */ B(CreateBlockContext), U8(0:SCOPE_INFO_TYPE), B(PushContext), R(1), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), B(LdaNull), B(Star4), @@ -65,7 +65,7 @@ bytecodes: [ B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -101,13 +101,13 @@ bytecodes: [ B(PushContext), R(1), B(LdaNull), B(Star3), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(3), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -142,15 +142,15 @@ bytecode array length: 46 bytecodes: [ /* 30 E> */ B(CreateBlockContext), U8(0:SCOPE_INFO_TYPE), B(PushContext), R(1), - B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(2:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star3), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(Star4), B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(3), RegCount8(2), B(StaCurrentContextSlotNoCell), C8(2), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), @@ -190,13 +190,13 @@ bytecodes: [ B(Star3), B(CallRuntime), U16(Runtime::kCreatePrivateBrandSymbol), R(3), RegCount8(1), B(StaCurrentContextSlotNoCell), C8(4), - B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + B(CreateClosure), U8(3:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(2), - B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x2), + B(CreateClosure), U8(4:SHARED_FUNCTION_INFO_TYPE), FBV(1), Flag8(0x1), B(StaCurrentContextSlotNoCell), C8(3), B(LdaTheHole), B(Star5), - B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x2), + B(CreateClosure), U8(5:SHARED_FUNCTION_INFO_TYPE), FBV(2), Flag8(0x1), B(Star2), B(LdaConstant), U8(1:CLASS_BOILERPLATE_TYPE), B(Star3), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/StringConcat.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/StringConcat.golden index 8a8cbf1e8361..f2a3e1486395 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/StringConcat.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/StringConcat.golden @@ -167,7 +167,7 @@ frame size: 4 parameter count: 1 bytecode array length: 35 bytecodes: [ - /* 30 E> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 30 E> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), /* 42 S> */ B(LdaSmi), I8(1), B(Star0), diff --git a/deps/v8/test/unittests/interpreter/bytecode_expectations/TemplateLiterals.golden b/deps/v8/test/unittests/interpreter/bytecode_expectations/TemplateLiterals.golden index d68b2ea01354..3c42b5513780 100644 --- a/deps/v8/test/unittests/interpreter/bytecode_expectations/TemplateLiterals.golden +++ b/deps/v8/test/unittests/interpreter/bytecode_expectations/TemplateLiterals.golden @@ -186,7 +186,7 @@ frame size: 4 parameter count: 1 bytecode array length: 38 bytecodes: [ - /* 30 E> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x2), + /* 30 E> */ B(CreateClosure), U8(0:SHARED_FUNCTION_INFO_TYPE), FBV(0), Flag8(0x1), B(Star2), /* 42 S> */ B(LdaSmi), I8(1), B(Star0), diff --git a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc index a318db574cc0..bb2353a1fb0e 100644 --- a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc @@ -4,6 +4,7 @@ #include "src/interpreter/bytecodes.h" +#include <bit> #include <vector> #include "src/init/v8.h" @@ -53,10 +54,9 @@ TEST(OperandConversion, Parameters) { TEST(OperandConversion, RegistersParametersNoOverlap) { int register_count = 128; int parameter_count = 100; - int32_t register_space_size = base::bits::RoundUpToPowerOfTwo32( - static_cast<uint32_t>(register_count + parameter_count)); - uint32_t range = static_cast<uint32_t>(register_space_size); - std::vector<uint8_t> operand_count(range); + uint32_t register_space_size = + std::bit_ceil<uint32_t>(register_count + parameter_count); + std::vector<uint8_t> operand_count(register_space_size); for (int i = 0; i < register_count; i += 1) { Register r = Register(i); diff --git a/deps/v8/test/unittests/interpreter/interpreter-unittest.cc b/deps/v8/test/unittests/interpreter/interpreter-unittest.cc index e39a97bef80f..996137d76feb 100644 --- a/deps/v8/test/unittests/interpreter/interpreter-unittest.cc +++ b/deps/v8/test/unittests/interpreter/interpreter-unittest.cc @@ -10,6 +10,7 @@ #include "src/base/overflowing-math.h" #include "src/codegen/compiler.h" #include "src/execution/execution.h" +#include "src/execution/frames-inl.h" #include "src/handles/handles.h" #include "src/heap/heap-inl.h" #include "src/init/v8.h" @@ -4917,6 +4918,136 @@ TEST_F(InterpreterTest, InterpreterLookupNameOfBytecodeHandler) { Builtins::name(extraWideLdaLookupSlot->builtin_id())); } +#ifdef V8_ENABLE_SPARKPLUG +TEST_F(InterpreterTest, UnoptimizedFrameSlotAlignment) { + if (v8_flags.jitless) return; + SaveFlags save_flags; + v8_flags.always_sparkplug = false; + v8_flags.sparkplug = true; + + static StackFrame::Type expected_frame_type = StackFrame::INTERPRETED; + static int expected_register_count = 0; + static int callback_count = 0; + callback_count = 0; + + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(i_isolate()); + v8::Local<v8::FunctionTemplate> check_frame_tmpl = v8::FunctionTemplate::New( + v8_isolate, [](const v8::FunctionCallbackInfo<v8::Value>& info) { + Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate()); + JavaScriptStackFrameIterator it(isolate); + CHECK(!it.done()); + JavaScriptFrame* frame = it.frame(); + CHECK_EQ(frame->type(), expected_frame_type); + + // Between the caller's register file and frame->sp() (which is the + // API_CALLBACK_EXIT frame's caller_sp()) are: + // - 2 outgoing JS argument slots (receiver + 1 argument) + // - 4 FunctionCallbackInfo implicit argument slots pushed by + // CallApiCallback before EnterExitFrame. + constexpr int kOutgoingCallSlots = + 2 + + ApiCallbackExitFrameConstants::kFunctionCallbackInfoApiArgsLength; + int slots_below_fp = + static_cast<int>((frame->fp() - frame->sp()) / kSystemPointerSize); + int fixed_and_register_slots_below_fp = + slots_below_fp - kOutgoingCallSlots; +#if V8_TARGET_ARCH_ARM64 || V8_X64_16BYTE_STACK_ALIGNMENT_BOOL + constexpr bool kAlignRegisterSlots = true; +#else + constexpr bool kAlignRegisterSlots = false; +#endif + int expected_register_slots = kAlignRegisterSlots + ? RoundUp(expected_register_count, 2) + : expected_register_count; + CHECK_EQ(fixed_and_register_slots_below_fp, + InterpreterFrameConstants::kFixedSlotCountFromFp + + expected_register_slots); + if (kAlignRegisterSlots) { + CHECK_EQ((InterpreterFrameConstants::kFixedSlotCount + + expected_register_slots) % + 2, + 0); + CHECK_EQ(fixed_and_register_slots_below_fp % 2, 0); + if (expected_register_count % 2 == 1) { + // Verify the register-file padding slot is initialized to + // undefined. + Address padding_addr = + frame->fp() - + fixed_and_register_slots_below_fp * kSystemPointerSize; + CHECK_EQ(base::Memory<Address>(padding_addr), + ReadOnlyRoots(isolate).undefined_value().ptr()); + } + } + info.GetReturnValue().Set(info[0]); + callback_count++; + }); + context() + ->Global() + ->Set(context(), + v8::String::NewFromUtf8(v8_isolate, "check_frame").ToLocalChecked(), + check_frame_tmpl->GetFunction(context()).ToLocalChecked()) + .FromJust(); + + // Include functions with: + // - small register counts (< 16, unrolled PrologueFillFrame path), even & odd + // - incoming new.target register, even & odd + // - large register counts (>= 16, looped PrologueFillFrame path), even & odd + const char* sources[] = { + "(function(a) { return check_frame(a); })", + "(function(a) { let x = a + 1; return check_frame(x); })", + "(function(a) { let x = a + 1, y = x + 2; return check_frame(x + y); })", + "(function(a) { let x = new.target ? 1 : a; return check_frame(x); })", + "(function(a) { let x = new.target ? 1 : a, y = x + 1;" + " return check_frame(y); })", + "(function(a) {" + " let r0 = a, r1 = a + 1, r2 = a + 2, r3 = a + 3," + " r4 = a + 4, r5 = a + 5, r6 = a + 6, r7 = a + 7," + " r8 = a + 8, r9 = a + 9, r10 = a + 10, r11 = a + 11," + " r12 = a + 12, r13 = a + 13, r14 = a + 14, r15 = a + 15;" + " return check_frame(r0 + r15);" + "})", + "(function(a) {" + " let r0 = a, r1 = a + 1, r2 = a + 2, r3 = a + 3," + " r4 = a + 4, r5 = a + 5, r6 = a + 6, r7 = a + 7," + " r8 = a + 8, r9 = a + 9, r10 = a + 10, r11 = a + 11," + " r12 = a + 12, r13 = a + 13, r14 = a + 14, r15 = a + 15," + " r16 = a + 16;" + " return check_frame(r0 + r16);" + "})", + }; + + for (const char* src : sources) { + Handle<JSFunction> func = Cast<JSFunction>( + v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(CompileRun(src)))); + expected_register_count = + func->shared()->GetBytecodeArray(i_isolate())->register_count(); + + DirectHandle<Object> args[] = { + direct_handle(Smi::FromInt(41), i_isolate())}; + + // 1. Call in Ignition (func starts with InterpreterEntryTrampoline). + expected_frame_type = StackFrame::INTERPRETED; + Execution::Call(i_isolate(), func, + i_isolate()->factory()->undefined_value(), + base::VectorOf(args, 1)) + .ToHandleChecked(); + + // 2. Compile to Sparkplug and call again (func now has BASELINE code). + IsCompiledScope is_compiled_scope( + func->shared()->is_compiled_scope(i_isolate())); + JSFunction::EnsureFeedbackVector(i_isolate(), func, &is_compiled_scope); + CHECK(Compiler::CompileBaseline( + i_isolate(), func, Compiler::CLEAR_EXCEPTION, &is_compiled_scope)); + expected_frame_type = StackFrame::BASELINE; + Execution::Call(i_isolate(), func, + i_isolate()->factory()->undefined_value(), + base::VectorOf(args, 1)) + .ToHandleChecked(); + } + CHECK_EQ(callback_count, static_cast<int>(arraysize(sources) * 2)); +} +#endif // V8_ENABLE_SPARKPLUG + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/js-atomics/js-atomics-synchronization-primitive-unittest.cc b/deps/v8/test/unittests/js-atomics/js-atomics-synchronization-primitive-unittest.cc deleted file mode 100644 index 1af24a5e8c7d..000000000000 --- a/deps/v8/test/unittests/js-atomics/js-atomics-synchronization-primitive-unittest.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2022 the V8 project 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 <optional> - -#include "src/base/platform/platform.h" -#include "src/base/platform/time.h" -#include "src/heap/parked-scope-inl.h" -#include "src/objects/js-atomics-synchronization-inl.h" -#include "test/unittests/test-utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -// In multi-cage mode we create one cage per isolate -// and we don't share objects between cages. -#if V8_CAN_CREATE_SHARED_HEAP_BOOL && !COMPRESS_POINTERS_IN_MULTIPLE_CAGES_BOOL - -namespace v8 { -namespace internal { - -using JSAtomicsMutexTest = TestJSSharedMemoryWithNativeContext; -using JSAtomicsConditionTest = TestJSSharedMemoryWithNativeContext; - -namespace { - -class LockingThread : public ParkingThread { - public: - LockingThread(Handle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_start, - ParkingSemaphore* sema_execute_complete) - : ParkingThread(Options("LockingThread")), - mutex_(mutex), - timeout_(timeout), - sema_ready_(sema_ready), - sema_execute_start_(sema_execute_start), - sema_execute_complete_(sema_execute_complete) {} - - void Run() override { - IsolateWithContextWrapper isolate_wrapper; - Isolate* isolate = isolate_wrapper.isolate(); - bool locked = LockJSMutexAndSignal(isolate); - base::OS::Sleep(base::TimeDelta::FromMilliseconds(1)); - if (locked) { - mutex_->Unlock(isolate); - } else { - EXPECT_TRUE(timeout_.has_value()); - } - sema_execute_complete_->Signal(); - } - - protected: - bool LockJSMutexAndSignal(Isolate* isolate) { - sema_ready_->Signal(); - sema_execute_start_->ParkedWait(isolate->main_thread_local_isolate()); - - HandleScope scope(isolate); - bool locked = JSAtomicsMutex::Lock(isolate, mutex_, timeout_); - if (locked) { - EXPECT_TRUE(mutex_->IsHeld()); - EXPECT_TRUE(mutex_->IsCurrentThreadOwner()); - } else { - EXPECT_FALSE(mutex_->IsCurrentThreadOwner()); - } - return locked; - } - - Handle<JSAtomicsMutex> mutex_; - std::optional<base::TimeDelta> timeout_; - ParkingSemaphore* sema_ready_; - ParkingSemaphore* sema_execute_start_; - ParkingSemaphore* sema_execute_complete_; -}; - -class BlockingLockingThread final : public LockingThread { - public: - BlockingLockingThread(Handle<JSAtomicsMutex> mutex, - std::optional<base::TimeDelta> timeout, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_start, - ParkingSemaphore* sema_execute_complete) - : LockingThread(mutex, timeout, sema_ready, sema_execute_start, - sema_execute_complete) {} - - void Run() override { - IsolateWithContextWrapper isolate_wrapper; - Isolate* isolate = isolate_wrapper.isolate(); - EXPECT_TRUE(LockJSMutexAndSignal(isolate)); - { - // Hold the js lock until the main thread notifies us. - base::MutexGuard guard(&mutex_for_cv_); - sema_execute_complete_->Signal(); - should_wait_ = true; - while (should_wait_) { - cv_.ParkedWait(isolate->main_thread_local_isolate(), &mutex_for_cv_); - } - } - mutex_->Unlock(isolate); - sema_execute_complete_->Signal(); - } - - void NotifyCV() { - base::MutexGuard guard(&mutex_for_cv_); - should_wait_ = false; - cv_.NotifyOne(); - } - - private: - base::Mutex mutex_for_cv_; - ParkingConditionVariable cv_; - bool should_wait_; -}; - -} // namespace - -TEST_F(JSAtomicsMutexTest, Contention) { - constexpr int kThreads = 32; - - Isolate* i_main_isolate = i_isolate(); - Handle<JSAtomicsMutex> contended_mutex = - i_main_isolate->factory()->NewJSAtomicsMutex(); - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<LockingThread>> threads; - for (int i = 0; i < kThreads; i++) { - auto thread = std::make_unique<LockingThread>( - contended_mutex, std::nullopt, &sema_ready, &sema_execute_start, - &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - - LocalIsolate* local_isolate = i_main_isolate->main_thread_local_isolate(); - for (int i = 0; i < kThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - for (int i = 0; i < kThreads; i++) sema_execute_start.Signal(); - for (int i = 0; i < kThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); - } - - ParkingThread::ParkedJoinAll(local_isolate, threads); - - EXPECT_FALSE(contended_mutex->IsHeld()); -} - -TEST_F(JSAtomicsMutexTest, Timeout) { - constexpr int kThreads = 32; - - Isolate* i_main_isolate = i_isolate(); - Handle<JSAtomicsMutex> contended_mutex = - i_main_isolate->factory()->NewJSAtomicsMutex(); - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_start(0); - ParkingSemaphore sema_execute_complete(0); - std::unique_ptr<BlockingLockingThread> blocking_thread = - std::make_unique<BlockingLockingThread>(contended_mutex, std::nullopt, - &sema_ready, &sema_execute_start, - &sema_execute_complete); - - LocalIsolate* local_isolate = i_main_isolate->main_thread_local_isolate(); - CHECK(blocking_thread->Start()); - sema_ready.ParkedWait(local_isolate); - sema_execute_start.Signal(); - sema_execute_complete.ParkedWait(local_isolate); - - std::vector<std::unique_ptr<LockingThread>> threads; - for (int i = 1; i < kThreads; i++) { - auto thread = std::make_unique<LockingThread>( - contended_mutex, base::TimeDelta::FromMilliseconds(1), &sema_ready, - &sema_execute_start, &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - - for (int i = 1; i < kThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - for (int i = 1; i < kThreads; i++) sema_execute_start.Signal(); - for (int i = 1; i < kThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); - } - - ParkingThread::ParkedJoinAll(local_isolate, threads); - EXPECT_TRUE(contended_mutex->IsHeld()); - blocking_thread->NotifyCV(); - sema_execute_complete.ParkedWait(local_isolate); - EXPECT_FALSE(contended_mutex->IsHeld()); - blocking_thread->ParkedJoin(local_isolate); -} - -namespace { -class WaitOnConditionThread final : public ParkingThread { - public: - WaitOnConditionThread(Handle<JSAtomicsMutex> mutex, - Handle<JSAtomicsCondition> condition, - uint32_t* waiting_threads_count, - ParkingSemaphore* sema_ready, - ParkingSemaphore* sema_execute_complete) - : ParkingThread(Options("WaitOnConditionThread")), - mutex_(mutex), - condition_(condition), - waiting_threads_count_(waiting_threads_count), - sema_ready_(sema_ready), - sema_execute_complete_(sema_execute_complete) {} - - void Run() override { - IsolateWithContextWrapper isolate_wrapper; - Isolate* isolate = isolate_wrapper.isolate(); - - sema_ready_->Signal(); - - HandleScope scope(isolate); - JSAtomicsMutex::Lock(isolate, mutex_); - while (keep_waiting) { - (*waiting_threads_count_)++; - EXPECT_TRUE(JSAtomicsCondition::WaitFor(isolate, condition_, mutex_, - std::nullopt)); - (*waiting_threads_count_)--; - } - mutex_->Unlock(isolate); - - sema_execute_complete_->Signal(); - } - - bool keep_waiting = true; - - private: - Handle<JSAtomicsMutex> mutex_; - Handle<JSAtomicsCondition> condition_; - uint32_t* waiting_threads_count_; - ParkingSemaphore* sema_ready_; - ParkingSemaphore* sema_execute_complete_; -}; -} // namespace - -TEST_F(JSAtomicsConditionTest, NotifyAll) { - constexpr uint32_t kThreads = 32; - - Isolate* i_main_isolate = i_isolate(); - Handle<JSAtomicsMutex> mutex = i_main_isolate->factory()->NewJSAtomicsMutex(); - Handle<JSAtomicsCondition> condition = - i_main_isolate->factory()->NewJSAtomicsCondition(); - - uint32_t waiting_threads_count = 0; - ParkingSemaphore sema_ready(0); - ParkingSemaphore sema_execute_complete(0); - std::vector<std::unique_ptr<WaitOnConditionThread>> threads; - for (uint32_t i = 0; i < kThreads; i++) { - auto thread = std::make_unique<WaitOnConditionThread>( - mutex, condition, &waiting_threads_count, &sema_ready, - &sema_execute_complete); - CHECK(thread->Start()); - threads.push_back(std::move(thread)); - } - - LocalIsolate* local_isolate = i_main_isolate->main_thread_local_isolate(); - for (uint32_t i = 0; i < kThreads; i++) { - sema_ready.ParkedWait(local_isolate); - } - - // Wait until all threads are waiting on the condition. - for (;;) { - JSAtomicsMutex::LockGuard lock_guard(i_main_isolate, mutex); - uint32_t count = waiting_threads_count; - if (count == kThreads) break; - } - - // Wake all the threads up. - for (uint32_t i = 0; i < kThreads; i++) { - threads[i]->keep_waiting = false; - } - EXPECT_EQ(kThreads, - JSAtomicsCondition::Notify(i_main_isolate, condition, - JSAtomicsCondition::kAllWaiters)); - - for (uint32_t i = 0; i < kThreads; i++) { - sema_execute_complete.ParkedWait(local_isolate); - } - - ParkingThread::ParkedJoinAll(local_isolate, threads); - - EXPECT_EQ(0U, waiting_threads_count); - EXPECT_FALSE(mutex->IsHeld()); -} - -} // namespace internal -} // namespace v8 - -#endif // V8_CAN_CREATE_SHARED_HEAP diff --git a/deps/v8/test/unittests/libplatform/tracing-unittest.cc b/deps/v8/test/unittests/libplatform/tracing-unittest.cc index f7d8a195e113..9d9f61284555 100644 --- a/deps/v8/test/unittests/libplatform/tracing-unittest.cc +++ b/deps/v8/test/unittests/libplatform/tracing-unittest.cc @@ -632,7 +632,7 @@ class TestListener : public TraceEventListener { } else if (it.has_string_value()) { value << "(string)" << it.string_value(); } else if (it.has_pointer_value()) { - value << "(pointer)0x" << std::hex << it.pointer_value(); + value << "(pointer)0x" << std::hex << it.pointer_value() << std::dec; } else if (it.has_legacy_json_value()) { value << "(json)" << it.legacy_json_value(); } else if (it.has_nested_value()) { @@ -853,6 +853,7 @@ TEST_F(PlatformTracingTest, MultipleArgsAndCopy) { for (size_t i = 0; i < 20; i++) CHECK_EQ("E:.", harness.get_event(24 + i)); } +#if defined(V8_USE_PERFETTO_JSON_EXPORT) TEST_F(PlatformTracingTest, JsonIntegrationTest) { // Check that tricky values are rendered correctly in the JSON output. double big_num = 1e100; @@ -887,6 +888,7 @@ TEST_F(PlatformTracingTest, JsonIntegrationTest) { CHECK_EQ("\"3\":\"Infinity\"", all_args[i++]); CHECK_EQ("\"4\":\"-Infinity\"", all_args[i++]); } +#endif // V8_USE_PERFETTO_JSON_EXPORT #endif // V8_USE_PERFETTO diff --git a/deps/v8/test/unittests/libsampler/sampler-unittest.cc b/deps/v8/test/unittests/libsampler/sampler-unittest.cc index 23ef95537cc4..977d21d4dc91 100644 --- a/deps/v8/test/unittests/libsampler/sampler-unittest.cc +++ b/deps/v8/test/unittests/libsampler/sampler-unittest.cc @@ -219,6 +219,31 @@ TEST_F(SamplerTest, AtomicGuard_GetBlockingSuccess) { CHECK(guard.is_success()); } +TEST_F(SamplerTest, StopSamplerWhileSignalPendingDoesNotCrash) { + class SampleAndStopThread : public base::Thread { + public: + explicit SampleAndStopThread(Sampler* sampler) + : Thread(base::Thread::Options("SampleAndStopThread")), + sampler_(sampler) {} + + void Run() override { + sampler_->DoSample(); + sampler_->Stop(); + } + + private: + Sampler* sampler_; + }; + + for (int i = 0; i < 100; ++i) { + CountingSampler sampler(isolate()); + sampler.Start(); + SampleAndStopThread thread(&sampler); + CHECK(thread.Start()); + thread.Join(); + } +} + #endif // USE_SIGNALS } // namespace sampler diff --git a/deps/v8/test/unittests/logging/log-unittest.cc b/deps/v8/test/unittests/logging/log-unittest.cc index 48524f3c1534..707415648ce9 100644 --- a/deps/v8/test/unittests/logging/log-unittest.cc +++ b/deps/v8/test/unittests/logging/log-unittest.cc @@ -29,12 +29,14 @@ #include "src/logging/log.h" +#include <array> #include <unordered_set> #include <vector> #include "include/v8-function.h" #include "src/api/api-inl.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/builtins/builtins.h" #include "src/codegen/compilation-cache.h" #include "src/execution/vm-state-inl.h" @@ -47,7 +49,6 @@ #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" -using v8::base::EmbeddedVector; using v8::internal::Address; using v8::internal::V8FileLogger; @@ -299,7 +300,7 @@ class SimpleExternalString : public v8::String::ExternalStringResource { public: explicit SimpleExternalString(const char* source) { size_t len = strlen(source); - utf_source_ = base::OwnedVector<uint16_t>::NewForOverwrite(len); + utf_source_ = base::UniqueArray<uint16_t>::NewForOverwrite(len); std::copy(source, source + len, utf_source_.data()); } ~SimpleExternalString() override = default; @@ -307,7 +308,7 @@ class SimpleExternalString : public v8::String::ExternalStringResource { const uint16_t* data() const override { return utf_source_.begin(); } private: - v8::base::OwnedVector<uint16_t> utf_source_; + v8::base::UniqueArray<uint16_t> utf_source_; }; } // namespace @@ -370,11 +371,11 @@ TEST_F(LogTest, LogCallbacks) { #if USES_FUNCTION_DESCRIPTORS ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry); #endif - v8::base::EmbeddedVector<char, 100> suffix_buffer; + std::array<char, 100> suffix_buffer; v8::base::SNPrintF(suffix_buffer, ",0x%" V8PRIxPTR ",1,method1", ObjMethod1_entry); CHECK(logger.ContainsLine( - {"code-creation,Callback,-2,", std::string(suffix_buffer.begin())})); + {"code-creation,Callback,-2,", std::string(suffix_buffer.data())})); } } @@ -407,31 +408,31 @@ TEST_F(LogTest, LogAccessorCallbacks) { #if USES_FUNCTION_DESCRIPTORS Prop1Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Getter_entry); #endif - v8::base::EmbeddedVector<char, 100> prop1_getter_record; + std::array<char, 100> prop1_getter_record; v8::base::SNPrintF(prop1_getter_record, ",0x%" V8PRIxPTR ",1,get prop1", Prop1Getter_entry); CHECK(logger.ContainsLine({"code-creation,Callback,-2,", - std::string(prop1_getter_record.begin())})); + std::string(prop1_getter_record.data())})); Address Prop1Setter_entry = reinterpret_cast<Address>(Prop1Setter); #if USES_FUNCTION_DESCRIPTORS Prop1Setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Setter_entry); #endif - v8::base::EmbeddedVector<char, 100> prop1_setter_record; + std::array<char, 100> prop1_setter_record; v8::base::SNPrintF(prop1_setter_record, ",0x%" V8PRIxPTR ",1,set prop1", Prop1Setter_entry); CHECK(logger.ContainsLine({"code-creation,Callback,-2,", - std::string(prop1_setter_record.begin())})); + std::string(prop1_setter_record.data())})); Address Prop2Getter_entry = reinterpret_cast<Address>(Prop2Getter); #if USES_FUNCTION_DESCRIPTORS Prop2Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop2Getter_entry); #endif - v8::base::EmbeddedVector<char, 100> prop2_getter_record; + std::array<char, 100> prop2_getter_record; v8::base::SNPrintF(prop2_getter_record, ",0x%" V8PRIxPTR ",1,get prop2", Prop2Getter_entry); CHECK(logger.ContainsLine({"code-creation,Callback,-2,", - std::string(prop2_getter_record.begin())})); + std::string(prop2_getter_record.data())})); } } @@ -440,12 +441,12 @@ TEST_F(LogTest, LogVersion) { ScopedLoggerInitializer logger(isolate()); logger.StopLogging(); - v8::base::EmbeddedVector<char, 100> line_buffer; + std::array<char, 100> line_buffer; v8::base::SNPrintF(line_buffer, "%d,%d,%d,%d,%d", i::Version::GetMajor(), i::Version::GetMinor(), i::Version::GetBuild(), i::Version::GetPatch(), i::Version::IsCandidate()); CHECK( - logger.ContainsLine({"v8-version,", std::string(line_buffer.begin())})); + logger.ContainsLine({"v8-version,", std::string(line_buffer.data())})); } } @@ -1214,7 +1215,7 @@ TEST_F(LogTest, BuiltinsNotLoggedAsLazyCompile) { i::Isolate* i_isolate = logger.i_isolate(); i::DirectHandle<i::Code> builtin = BUILTIN_CODE(i_isolate, BooleanConstructor); - v8::base::EmbeddedVector<char, 100> buffer; + std::array<char, 100> buffer; // Should only be logged as "Builtin" with a name, never as "Function". v8::base::SNPrintF(buffer, ",0x%" V8PRIxPTR ",%d,BooleanConstructor", @@ -1223,13 +1224,13 @@ TEST_F(LogTest, BuiltinsNotLoggedAsLazyCompile) { static_assert(static_cast<int>(i::CodeKind::BUILTIN) == 3, "Update ',3,' below to proper value"); CHECK(logger.ContainsLine( - {"code-creation,Builtin,3,", std::string(buffer.begin())})); + {"code-creation,Builtin,3,", std::string(buffer.data())})); v8::base::SNPrintF(buffer, ",0x%" V8PRIxPTR ",%d,", builtin->instruction_start(), builtin->instruction_size()); CHECK(!logger.ContainsLine( - {"code-creation,JS,3,", std::string(buffer.begin())})); + {"code-creation,JS,3,", std::string(buffer.data())})); } } } // namespace v8 diff --git a/deps/v8/test/unittests/maglev/maglev-assembler-unittest.cc b/deps/v8/test/unittests/maglev/maglev-assembler-unittest.cc index 7784ff036024..f36621f21a13 100644 --- a/deps/v8/test/unittests/maglev/maglev-assembler-unittest.cc +++ b/deps/v8/test/unittests/maglev/maglev-assembler-unittest.cc @@ -294,6 +294,105 @@ TEST_F(MaglevAssemblerTest, SetSlotAddressForFixedArrayElementLargeIndex) { } #endif // V8_TARGET_ARCH_LOONG64 || V8_TARGET_ARCH_RISCV64 +#if V8_TARGET_ARCH_ARM64 +// Compares against read-only roots, which arm64 reads as immediates under +// static roots instead of loading them from the constant pool. +class MaglevAssemblerReadOnlyCompareTest : public MaglevAssemblerTest { + public: + // Test code has no prologue. A compare against a root reads the root + // register, and under --debug-code checks the cage base register, so set + // both up as JSEntry does, saving the callee-saved registers, and restore + // them before returning. + void SetUpRootRegisters() { +#ifdef V8_COMPRESS_POINTERS + as.MacroAssembler::Push(kRootRegister, kPtrComprCageBaseRegister); + as.Move(kRootRegister, ExternalReference::isolate_root(isolate())); + as.LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); +#else + as.MacroAssembler::Push(kRootRegister, padreg); + as.Move(kRootRegister, ExternalReference::isolate_root(isolate())); +#endif + } + void RestoreRootRegisters() { +#ifdef V8_COMPRESS_POINTERS + as.MacroAssembler::Pop(kPtrComprCageBaseRegister, kRootRegister); +#else + as.MacroAssembler::Pop(padreg, kRootRegister); +#endif + } + + // The code bytes that {emit} adds, to check the shape of a compare and its + // branch. + template <typename Emit> + int EmittedBytes(Emit emit) { + int start = as.pc_offset(); + emit(); + return as.pc_offset() - start; + } + + // Whether a read-only root compares as `cmp w, #imm` and branches, without + // a pool load: under static roots, unless --debug-code adds its checks. + bool ExpectImmediateCompare() { + return V8_STATIC_ROOTS_BOOL && !v8_flags.debug_code; + } +}; + +TEST_F(MaglevAssemblerReadOnlyCompareTest, MapCompareReadOnlyMap) { + // A FixedArray's map and the COW map are read-only; a JSObject's map is not. + Handle<FixedArray> array = isolate()->factory()->NewFixedArray(2); + Handle<Map> map = isolate()->factory()->fixed_array_map(); + Handle<Map> cow_map = isolate()->factory()->fixed_cow_array_map(); + Handle<JSObject> object = + isolate()->factory()->NewJSObject(isolate()->object_function()); + Handle<Map> object_map(object->map(), isolate()); + Label pass, fail; + as.CodeEntry(); + SetUpRootRegisters(); + MaglevAssembler::TemporaryRegisterScope temps(&as); + as.Move(kReturnRegister0, array); + MapCompare map_compare(&as, kReturnRegister0, 3); + int bytes = + EmittedBytes([&] { map_compare.Generate(cow_map, kEqual, &fail); }); + map_compare.Generate(object_map, kEqual, &fail); + map_compare.Generate(map, kNotEqual, &fail); + RestoreRootRegisters(); + as.Jump(&pass); + if (ExpectImmediateCompare()) EXPECT_EQ(2 * kInstrSize, bytes); + FinalizeAndRun(&pass, &fail); +} + +TEST_F(MaglevAssemblerReadOnlyCompareTest, CompareTaggedAndJumpIfReadOnly) { + // true and null sit low in the read-only heap, the "object" string higher, + // and a fresh JSObject outside it. + Handle<HeapObject> value = isolate()->factory()->true_value(); + Handle<HeapObject> other = isolate()->factory()->null_value(); + Handle<HeapObject> string = isolate()->factory()->object_string(); + Handle<HeapObject> object = + isolate()->factory()->NewJSObject(isolate()->object_function()); + Label pass, fail; + as.CodeEntry(); + SetUpRootRegisters(); + as.Move(kReturnRegister0, value); + int bytes = EmittedBytes([&] { + as.CompareTaggedAndJumpIf(kReturnRegister0, other, kEqual, &fail); + }); + as.CompareTaggedAndJumpIf(kReturnRegister0, string, kEqual, &fail); + as.CompareTaggedAndJumpIf(kReturnRegister0, object, kEqual, &fail); + as.CompareTaggedAndJumpIf(kReturnRegister0, value, kNotEqual, &fail); + as.Move(kReturnRegister0, string); + as.CompareTaggedAndJumpIf(kReturnRegister0, value, kEqual, &fail); + as.CompareTaggedAndJumpIf(kReturnRegister0, string, kNotEqual, &fail); + as.Move(kReturnRegister0, object); + as.CompareTaggedAndJumpIf(kReturnRegister0, string, kEqual, &fail); + as.CompareTaggedAndJumpIf(kReturnRegister0, object, kNotEqual, &fail); + RestoreRootRegisters(); + as.Jump(&pass); + if (ExpectImmediateCompare()) EXPECT_EQ(2 * kInstrSize, bytes); + FinalizeAndRun(&pass, &fail); +} +#endif // V8_TARGET_ARCH_ARM64 + } // namespace maglev } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/maglev/maglev-graph-builder-unittest.cc b/deps/v8/test/unittests/maglev/maglev-graph-builder-unittest.cc index caeb4f984b97..6dc5374beb6c 100644 --- a/deps/v8/test/unittests/maglev/maglev-graph-builder-unittest.cc +++ b/deps/v8/test/unittests/maglev/maglev-graph-builder-unittest.cc @@ -51,10 +51,10 @@ TEST_F(MaglevGraphBuilderTest, LoopEffectEpochComparison) { MaglevGraphLabellerScope graph_labeller_scope(info->graph_labeller()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); ASSERT_TRUE(graph_builder.Build()); int loop_count = 0; for (BasicBlock* block : graph->blocks()) { @@ -105,9 +105,9 @@ TEST_F(MaglevGraphBuilderTest, TrailingArgumentsRemoval) { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); CHECK(graph_builder.Build()); CallKnownJSFunction* func = getUniqueNode<CallKnownJSFunction>(graph); CHECK_EQ(strict ? 2 : 4, func->num_args()); @@ -133,9 +133,9 @@ TEST_F(MaglevGraphBuilderTest, UnusedArgumentsRemoval) { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); CHECK(graph_builder.Build()); CallKnownJSFunction* func = getUniqueNode<CallKnownJSFunction>(graph); CHECK_EQ(2, func->num_args()); @@ -167,9 +167,9 @@ TEST_F(MaglevGraphBuilderTest, UnusedArgumentsRemovalHighIndex) { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); CHECK(graph_builder.Build()); CallKnownJSFunction* func = getUniqueNode<CallKnownJSFunction>(graph); // No trailing arguments to remove: all 6 are formal parameters. @@ -204,9 +204,9 @@ TEST_F(MaglevGraphBuilderTest, UnusedArgumentsRemovalWithTruncation) { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); CHECK(graph_builder.Build()); CallKnownJSFunction* func = getUniqueNode<CallKnownJSFunction>(graph); // The trailing 6th argument has been dropped, leaving the 5 formal params. @@ -250,9 +250,9 @@ TEST_F(MaglevGraphBuilderTest, UnusedArgumentsRemovalSignExtension) { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); CHECK(graph_builder.Build()); CallKnownJSFunction* func = getUniqueNode<CallKnownJSFunction>(graph); CHECK_EQ(32, func->num_args()); diff --git a/deps/v8/test/unittests/maglev/maglev-graph-processor-unittest.cc b/deps/v8/test/unittests/maglev/maglev-graph-processor-unittest.cc index df1ad514d802..44da0f48e688 100644 --- a/deps/v8/test/unittests/maglev/maglev-graph-processor-unittest.cc +++ b/deps/v8/test/unittests/maglev/maglev-graph-processor-unittest.cc @@ -37,9 +37,9 @@ class MaglevGraphProcessorTest : public TestWithNativeContextAndZone { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); ASSERT_TRUE(graph_builder.Build()); ReachableExceptionHandlerTracker tracker(graph); @@ -139,9 +139,9 @@ TEST_F(MaglevGraphProcessorTest, GraphBackwardMultiProcessorOrder) { MaglevCompilationInfo::New(isolate(), function, BytecodeOffset::None()); Graph* graph = Graph::New(info.get()); compiler::CurrentHeapBrokerScope current_broker(info->broker()); + PersistentHandlesScope persistent_scope(isolate()); MaglevGraphBuilder graph_builder(isolate()->AsLocalIsolate(), info->toplevel_compilation_unit(), graph); - PersistentHandlesScope persistent_scope(isolate()); ASSERT_TRUE(graph_builder.Build()); EventRecorder recorder; diff --git a/deps/v8/test/unittests/numbers/strtod-unittest.cc b/deps/v8/test/unittests/numbers/strtod-unittest.cc index 37f324b3e366..00487a91d52c 100644 --- a/deps/v8/test/unittests/numbers/strtod-unittest.cc +++ b/deps/v8/test/unittests/numbers/strtod-unittest.cc @@ -29,6 +29,8 @@ #include <stdlib.h> +#include <string_view> + #include "src/base/numbers/bignum.h" #include "src/base/numbers/diy-fp.h" #include "src/base/numbers/double.h" @@ -43,20 +45,20 @@ namespace base { using StrtodTest = ::testing::Test; static double StrtodChar(const char* str, int exponent) { - return Strtod(CStrVector(str), exponent); + return Strtod(str, exponent); } TEST_F(StrtodTest, Strtod) { - Vector<const char> vector; + std::string_view vector; - vector = CStrVector("0"); + vector = "0"; CHECK_EQ(0.0, Strtod(vector, 1)); CHECK_EQ(0.0, Strtod(vector, 2)); CHECK_EQ(0.0, Strtod(vector, -2)); CHECK_EQ(0.0, Strtod(vector, -999)); CHECK_EQ(0.0, Strtod(vector, +999)); - vector = CStrVector("1"); + vector = "1"; CHECK_EQ(1.0, Strtod(vector, 0)); CHECK_EQ(10.0, Strtod(vector, 1)); CHECK_EQ(100.0, Strtod(vector, 2)); @@ -75,7 +77,7 @@ TEST_F(StrtodTest, Strtod) { CHECK_EQ(1e-25, Strtod(vector, -25)); CHECK_EQ(1e-39, Strtod(vector, -39)); - vector = CStrVector("2"); + vector = "2"; CHECK_EQ(2.0, Strtod(vector, 0)); CHECK_EQ(20.0, Strtod(vector, 1)); CHECK_EQ(200.0, Strtod(vector, 2)); @@ -94,7 +96,7 @@ TEST_F(StrtodTest, Strtod) { CHECK_EQ(2e-25, Strtod(vector, -25)); CHECK_EQ(2e-39, Strtod(vector, -39)); - vector = CStrVector("9"); + vector = "9"; CHECK_EQ(9.0, Strtod(vector, 0)); CHECK_EQ(90.0, Strtod(vector, 1)); CHECK_EQ(900.0, Strtod(vector, 2)); @@ -113,7 +115,7 @@ TEST_F(StrtodTest, Strtod) { CHECK_EQ(9e-25, Strtod(vector, -25)); CHECK_EQ(9e-39, Strtod(vector, -39)); - vector = CStrVector("12345"); + vector = "12345"; CHECK_EQ(12345.0, Strtod(vector, 0)); CHECK_EQ(123450.0, Strtod(vector, 1)); CHECK_EQ(1234500.0, Strtod(vector, 2)); @@ -135,7 +137,7 @@ TEST_F(StrtodTest, Strtod) { CHECK_EQ(12345e-25, Strtod(vector, -25)); CHECK_EQ(12345e-39, Strtod(vector, -39)); - vector = CStrVector("12345678901234"); + vector = "12345678901234"; CHECK_EQ(12345678901234.0, Strtod(vector, 0)); CHECK_EQ(123456789012340.0, Strtod(vector, 1)); CHECK_EQ(1234567890123400.0, Strtod(vector, 2)); @@ -157,7 +159,7 @@ TEST_F(StrtodTest, Strtod) { CHECK_EQ(12345678901234e-25, Strtod(vector, -25)); CHECK_EQ(12345678901234e-39, Strtod(vector, -39)); - vector = CStrVector("123456789012345"); + vector = "123456789012345"; CHECK_EQ(123456789012345.0, Strtod(vector, 0)); CHECK_EQ(1234567890123450.0, Strtod(vector, 1)); CHECK_EQ(12345678901234500.0, Strtod(vector, 2)); @@ -390,7 +392,7 @@ static int CompareBignumToDiyFp(const Bignum& bignum_digits, return Bignum::Compare(bignum, other); } -static bool CheckDouble(Vector<const char> buffer, int exponent, +static bool CheckDouble(std::string_view buffer, int exponent, double to_check) { DiyFp lower_boundary; DiyFp upper_boundary; @@ -453,9 +455,9 @@ TEST_F(StrtodTest, RandomStrtod) { } int exponent = DeterministicRandom() % (25 * 2 + 1) - 25 - length; buffer[pos] = '\0'; - Vector<const char> vector(buffer, pos); - double strtod_result = Strtod(vector, exponent); - CHECK(CheckDouble(vector, exponent, strtod_result)); + std::string_view str(buffer, pos); + double strtod_result = Strtod(str, exponent); + CHECK(CheckDouble(str, exponent, strtod_result)); } } for (int length = 15; length < 800; length += 2) { @@ -466,9 +468,9 @@ TEST_F(StrtodTest, RandomStrtod) { } int exponent = DeterministicRandom() % (308 * 2 + 1) - 308 - length; buffer[pos] = '\0'; - Vector<const char> vector(buffer, pos); - double strtod_result = Strtod(vector, exponent); - CHECK(CheckDouble(vector, exponent, strtod_result)); + std::string_view str(buffer, pos); + double strtod_result = Strtod(str, exponent); + CHECK(CheckDouble(str, exponent, strtod_result)); } } } diff --git a/deps/v8/test/unittests/objects/casting-unittest.cc b/deps/v8/test/unittests/objects/casting-unittest.cc new file mode 100644 index 000000000000..641fd5079053 --- /dev/null +++ b/deps/v8/test/unittests/objects/casting-unittest.cc @@ -0,0 +1,215 @@ +// Copyright 2026 the V8 project 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 "src/objects/casting.h" + +#include "src/heap/factory.h" +#include "src/heap/heap-layout-inl.h" +#include "src/objects/objects-inl.h" +#include "test/unittests/test-utils.h" + +namespace v8::internal { +namespace { + +using CastingTest = TestWithNativeContext; + +struct Expected { + bool smi; + bool fixed_array; + bool byte_array; + bool weak_fixed_array; + bool weak_byte_array; + bool cleared; + bool read_only = false; +}; + +template <typename To, typename From> +void CheckCast(Tagged<From> value, bool expected) { + SCOPED_TRACE(V8_PRETTY_FUNCTION_VALUE_OR("CheckCast")); + EXPECT_EQ(expected, Is<To>(value)); + EXPECT_EQ(expected, CastTraitsImpl<To>::AllowFrom(value)); + Tagged<To> result = UncheckedCast<To>(Smi::zero()); + ASSERT_EQ(expected, TryCast<To>(value, &result)); + if (expected) { + EXPECT_EQ(value.ptr(), result.ptr()); + EXPECT_EQ(value.ptr(), Cast<To>(value).ptr()); + EXPECT_EQ(value.ptr(), CheckedCast<To>(value).ptr()); + } else { + EXPECT_EQ(Smi::zero().ptr(), result.ptr()); + } +} + +template <typename From> +void CheckTargets(Tagged<From> value, Expected e) { + CheckCast<Smi>(value, e.smi); + CheckCast<Number>(value, e.smi); + CheckCast<FixedArray>(value, e.fixed_array); + CheckCast<ByteArray>(value, e.byte_array); + CheckCast<HeapObject>(value, e.fixed_array || e.byte_array); + CheckCast<Object>(value, e.smi || e.fixed_array || e.byte_array); + CheckCast<ReadOnly<FixedArray>>(value, e.read_only && e.fixed_array); + CheckCast<ReadOnly<ByteArray>>(value, e.read_only && e.byte_array); + CheckCast<ReadOnly<HeapObject>>( + value, e.read_only && (e.fixed_array || e.byte_array)); + CheckCast<UnionOf<Smi, ReadOnly<FixedArray>>>( + value, e.smi || (e.read_only && e.fixed_array)); + CheckCast<UnionOf<ReadOnly<FixedArray>, ByteArray>>( + value, (e.read_only && e.fixed_array) || e.byte_array); + CheckCast<UnionOf<ReadOnly<FixedArray>, Weak<ByteArray>>>( + value, (e.read_only && e.fixed_array) || e.weak_byte_array || e.cleared); + CheckCast<Weak<FixedArray>>(value, e.weak_fixed_array || e.cleared); + CheckCast<Weak<ByteArray>>(value, e.weak_byte_array || e.cleared); + CheckCast<Weak<HeapObject>>( + value, e.weak_fixed_array || e.weak_byte_array || e.cleared); + CheckCast<ClearedWeakValue>(value, e.cleared); + CheckCast<MaybeObject>(value, true); + CheckCast<MaybeWeak<FixedArray>>( + value, e.fixed_array || e.weak_fixed_array || e.cleared); + CheckCast<UnionOf<Smi, FixedArray>>(value, e.smi || e.fixed_array); + CheckCast<UnionOf<FixedArray, ByteArray>>(value, + e.fixed_array || e.byte_array); + CheckCast<UnionOf<FixedArray, Weak<ByteArray>>>( + value, e.fixed_array || e.weak_byte_array || e.cleared); + CheckCast<UnionOf<Weak<FixedArray>, ByteArray>>( + value, e.weak_fixed_array || e.byte_array || e.cleared); + CheckCast<UnionOf<Weak<FixedArray>, Weak<ByteArray>>>( + value, e.weak_fixed_array || e.weak_byte_array || e.cleared); + CheckCast<UnionOf<Smi, Weak<FixedArray>>>( + value, e.smi || e.weak_fixed_array || e.cleared); + CheckCast<JSPrimitive>(value, e.smi); + CheckCast<JSAny>(value, e.smi); +} + +template <typename From> +void CheckSourceTypes(Tagged<From> value, Expected expected) { + CheckTargets(value, expected); + auto check = [&]<typename U>() { + if constexpr (is_subtype_v<From, U>) { + CheckTargets(Tagged<U>(value), expected); + } + }; + check.template operator()<Object>(); + check.template operator()<HeapObject>(); + check.template operator()<ReadOnly<FixedArray>>(); + check.template operator()<ReadOnly<ByteArray>>(); + check.template operator()<ReadOnly<HeapObject>>(); + check.template operator()<Weak<HeapObject>>(); + check.template operator()<MaybeObject>(); + check.template operator()<MaybeWeak<HeapObject>>(); + check.template operator()<MaybeWeak<FixedArray>>(); + check.template operator()<UnionOf<Smi, FixedArray>>(); + check.template operator()<UnionOf<FixedArray, ByteArray>>(); + check.template operator()<UnionOf<FixedArray, Weak<ByteArray>>>(); + check.template operator()<UnionOf<Weak<FixedArray>, ByteArray>>(); + check.template operator()<UnionOf<Weak<FixedArray>, Weak<ByteArray>>>(); + check.template operator()<UnionOf<Smi, Weak<FixedArray>>>(); + check.template operator()<UnionOf<ReadOnly<FixedArray>, ByteArray>>(); + check.template operator()<UnionOf<ReadOnly<FixedArray>, Weak<ByteArray>>>(); +} + +TEST_F(CastingTest, StrongFixedArray) { + auto value = *isolate()->factory()->empty_fixed_array(); + ASSERT_TRUE(HeapLayout::InReadOnlySpace(value)); + Expected expected{false, true, false, false, false, false, true}; + CheckSourceTypes(value, expected); + CheckSourceTypes(Cast<ReadOnly<FixedArray>>(value), expected); +} + +TEST_F(CastingTest, MutableFixedArray) { + auto value = *isolate()->factory()->NewFixedArray(1); + ASSERT_FALSE(HeapLayout::InReadOnlySpace(value)); + CheckSourceTypes(value, {false, true, false, false, false, false}); +} + +TEST_F(CastingTest, ReadOnlyByteArray) { + auto value = ReadOnlyRoots(isolate()).empty_byte_array(); + ASSERT_TRUE(HeapLayout::InReadOnlySpace(value)); + Expected expected{false, false, true, false, false, false, true}; + CheckSourceTypes(value, expected); + CheckSourceTypes(Cast<ReadOnly<ByteArray>>(value), expected); +} + +TEST_F(CastingTest, WeakFixedArray) { + CheckSourceTypes(MakeWeak(*isolate()->factory()->empty_fixed_array()), + {false, false, false, true, false, false}); +} + +TEST_F(CastingTest, StrongByteArray) { + CheckSourceTypes(*isolate()->factory()->NewByteArray(1), + {false, false, true, false, false, false}); +} + +TEST_F(CastingTest, WeakByteArray) { + CheckSourceTypes(MakeWeak(*isolate()->factory()->NewByteArray(1)), + {false, false, false, false, true, false}); +} + +TEST_F(CastingTest, Smi) { + for (int n : {0, 1, -1}) { + CheckSourceTypes(Smi::FromInt(n), + {true, false, false, false, false, false}); + } +} + +TEST_F(CastingTest, Cleared) { + CheckSourceTypes(kClearedWeakValue, + {false, false, false, false, false, true}); +} + +TEST_F(CastingTest, Number) { + Tagged<HeapNumber> number = *isolate()->factory()->NewHeapNumber(1.5); + CheckCast<Number>(number, true); + CheckCast<Number>(Tagged<Object>(number), true); + CheckCast<Number>(Tagged<MaybeObject>(number), true); + CheckCast<Number>(MakeWeak(number), false); + CheckCast<Number>(Tagged<MaybeObject>(MakeWeak(number)), false); +} + +// FieldType's predicate depends on the Smi value, so it detects Smi payload +// corruption when stripping strength from maybe-weak sources (Any() is Smi(1), +// whose payload bit overlaps the weak tag bit under 31-bit Smi tagging). +TEST_F(CastingTest, FieldType) { + Tagged<Map> map = ReadOnlyRoots(isolate()).fixed_array_map(); + auto check = [](Tagged<MaybeObject> value, bool expected) { + CheckCast<FieldType>(value, expected); + CheckCast<FieldType>(Cast<UnionOf<Smi, Map, Weak<Map>>>(value), expected); + }; + check(FieldType::Any(), true); + check(FieldType::None(), true); + check(Smi::zero(), false); + check(Smi::FromInt(3), false); + check(map, true); + check(MakeWeak(map), false); +} + +TEST_F(CastingTest, JSUnionPredicates) { + auto check = [](Tagged<Object> value) { + if (IsHeapObject(value) && IsInaccessible(Cast<HeapObject>(value))) return; + bool primitive = IsPrimitive(value); + bool js_any = primitive || IsJSReceiver(value); + CheckCast<JSPrimitive>(value, primitive); + CheckCast<JSAny>(value, js_any); + CheckCast<JSPrimitive>(Tagged<MaybeObject>(value), primitive); + CheckCast<JSAny>(Tagged<MaybeObject>(value), js_any); + if (IsHeapObject(value)) { + auto weak = MakeWeak(Cast<HeapObject>(value)); + CheckCast<JSPrimitive>(weak, false); + CheckCast<JSAny>(weak, false); + CheckCast<JSPrimitive>(Tagged<MaybeObject>(weak), false); + CheckCast<JSAny>(Tagged<MaybeObject>(weak), false); + } + }; + ReadOnlyRoots roots(isolate()); +#define CHECK_ROOT(type, name, CamelName) \ + { \ + SCOPED_TRACE(#name); \ + check(roots.name()); \ + } + READ_ONLY_ROOT_LIST(CHECK_ROOT) +#undef CHECK_ROOT + check(*isolate()->factory()->NewJSObject(isolate()->object_function())); +} + +} // namespace +} // namespace v8::internal diff --git a/deps/v8/test/unittests/objects/managed-unittest.cc b/deps/v8/test/unittests/objects/managed-unittest.cc index d10be9101eeb..ba3190487b6d 100644 --- a/deps/v8/test/unittests/objects/managed-unittest.cc +++ b/deps/v8/test/unittests/objects/managed-unittest.cc @@ -256,4 +256,38 @@ TEST_F(ManagedTest, CollectAcrossIsolates) { CHECK_EQ(1, deleted); } +TEST_F(ManagedTest, TrustedManaged) { + int deleted = 0; + { + HandleScope scope(isolate()); + auto shared = std::make_shared<DeleteCounter>(&deleted); + DeleteCounter* expected = shared.get(); + CHECK_EQ(1, shared.use_count()); + + DirectHandle<TrustedManaged<DeleteCounter>> trusted_managed = + TrustedManaged<DeleteCounter>::From(isolate(), 0, shared); + CHECK_EQ(2, shared.use_count()); + CHECK_EQ(expected, trusted_managed->raw(DisallowGarbageCollection{})); + CHECK_EQ(expected, trusted_managed->unsafe_raw()); + CHECK_EQ(2, shared.use_count()); + { + std::shared_ptr<DeleteCounter> copy = trusted_managed->get(); + CHECK_EQ(expected, copy.get()); + CHECK_EQ(3, shared.use_count()); + } + CHECK_EQ(2, shared.use_count()); + + shared.reset(); + CHECK_EQ(0, deleted); + InvokeMemoryReducingMajorGCs(isolate()); + CHECK_EQ(0, deleted); + CHECK_EQ(expected, trusted_managed->raw(DisallowGarbageCollection{})); + CHECK_EQ(expected, trusted_managed->unsafe_raw()); + } + + DisableConservativeStackScanningScopeForTesting scope(isolate()->heap()); + InvokeMemoryReducingMajorGCs(isolate()); + CHECK_EQ(1, deleted); +} + } // namespace v8::internal diff --git a/deps/v8/test/unittests/objects/modules-unittest.cc b/deps/v8/test/unittests/objects/modules-unittest.cc index c88c211e5fc5..52ba824b4333 100644 --- a/deps/v8/test/unittests/objects/modules-unittest.cc +++ b/deps/v8/test/unittests/objects/modules-unittest.cc @@ -2029,4 +2029,91 @@ TEST_F(ModuleTest, DeferredModuleRejectionInsideApiCallback) { isolate()->SetPromiseRejectCallback(nullptr); } +static v8::Global<Module> errored_synthetic_dependency; +MaybeLocal<Module> ResolveErroredSyntheticDependency( + Local<Context> context, Local<String> specifier, + Local<FixedArray> import_attributes, Local<Module> referrer) { + return errored_synthetic_dependency.Get(Isolate::GetCurrent()); +} + +static int synthetic_unhandled_rejections = 0; +void CountSyntheticUnhandledRejections(v8::PromiseRejectMessage message) { + if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) { + ++synthetic_unhandled_rejections; + } else if (message.GetEvent() == v8::kPromiseHandlerAddedAfterReject) { + --synthetic_unhandled_rejections; + } +} + +TEST_F(ModuleTest, ErroredSyntheticModuleDependency) { + i::FlagScope<bool> defer_imports(&i::v8_flags.js_defer_import_eval, true); + HandleScope scope(isolate()); + synthetic_unhandled_rejections = 0; + isolate()->SetPromiseRejectCallback(CountSyntheticUnhandledRejections); + + Local<String> export_name = NewString("x"); + Local<Module> synthetic = Module::CreateSyntheticModule( + isolate(), NewString("errored_synthetic"), {&export_name, 1}, + [](Local<Context> context, Local<Module> module) -> MaybeLocal<Promise> { + Isolate* isolate = Isolate::GetCurrent(); + // Re-entrantly evaluating a kEvaluating synthetic module via its + // deferred namespace must fail ReadyForSyncExecution with a TypeError. + { + v8::TryCatch reentrant_catch(isolate); + Local<v8::Object> deferred_ns = + module->GetModuleNamespace(v8::ModuleImportPhase::kDefer) + .As<v8::Object>(); + CHECK(deferred_ns + ->Get(context, String::NewFromUtf8Literal(isolate, "x")) + .IsEmpty()); + CHECK(reentrant_catch.HasCaught()); + } + isolate->ThrowException(v8::Exception::Error( + String::NewFromUtf8Literal(isolate, "synthetic eval error"))); + return MaybeLocal<Promise>(); + }); + CHECK(synthetic + ->InstantiateModule(context(), + ResolveModuleByIndexUnreachableCallback) + .FromJust()); + { + v8::TryCatch try_catch(isolate()); + CHECK(synthetic->Evaluate(context()).IsEmpty()); + CHECK(try_catch.HasCaught()); + } + CHECK_EQ(Module::kErrored, synthetic->GetStatus()); + CHECK_EQ(0, synthetic_unhandled_rejections); + errored_synthetic_dependency.Reset(isolate(), synthetic); + + ScriptOrigin origin = ModuleOrigin(NewString("importer.js"), isolate()); + ScriptCompiler::Source source(NewString("import 'errored_synthetic';\n"), + origin); + Local<Module> importer = + ScriptCompiler::CompileModule(isolate(), &source).ToLocalChecked(); + CHECK( + importer->InstantiateModule(context(), ResolveErroredSyntheticDependency) + .FromJust()); + + Local<Value> eval_result = importer->Evaluate(context()).ToLocalChecked(); + Local<Promise> promise = eval_result.As<Promise>(); + CHECK_EQ(Module::kErrored, importer->GetStatus()); + CHECK_EQ(Promise::kRejected, promise->State()); + CHECK_EQ(synthetic->GetException(), importer->GetException()); + // Only the outer importer's top-level capability remains unhandled; + // EvaluateModuleSync marks the synthetic module's capability as handled when + // converting its rejection into a throw. + CHECK_EQ(1, synthetic_unhandled_rejections); + + // Re-evaluating the errored synthetic module returns the cached capability + // without materializing a second rejected promise. + Local<Promise> synthetic_promise = + synthetic->Evaluate(context()).ToLocalChecked().As<Promise>(); + CHECK_EQ(Promise::kRejected, synthetic_promise->State()); + CHECK_EQ(synthetic->GetException(), synthetic_promise->Result()); + CHECK_EQ(1, synthetic_unhandled_rejections); + + errored_synthetic_dependency.Reset(); + isolate()->SetPromiseRejectCallback(nullptr); +} + } // anonymous namespace diff --git a/deps/v8/test/unittests/objects/object-unittest.cc b/deps/v8/test/unittests/objects/object-unittest.cc index 404b56c6138b..36b9b5c585a3 100644 --- a/deps/v8/test/unittests/objects/object-unittest.cc +++ b/deps/v8/test/unittests/objects/object-unittest.cc @@ -212,7 +212,7 @@ TEST_F(TestWithNativeContext, EmptyFunctionScopeInfo) { DirectHandle<ScopeInfo> empty_function_scope_info( isolate()->empty_function()->shared()->scope_info(), i_isolate()); - EXPECT_EQ(scope_info->Flags(), empty_function_scope_info->Flags()); + EXPECT_EQ(scope_info->flags(), empty_function_scope_info->flags()); EXPECT_EQ(scope_info->ParameterCount(), empty_function_scope_info->ParameterCount()); EXPECT_EQ(scope_info->ContextLocalCount(), @@ -224,8 +224,9 @@ TEST_F(TestWithNativeContext, CanOnlyAccessFixedFormalParameters) { DirectHandle<JSFunction> function = RunJS<JSFunction>(f); DirectHandle<ScopeInfo> scope_info(function->shared()->scope_info(), i_isolate()); - auto flags = scope_info->Flags(); - EXPECT_EQ(allocates, ScopeInfo::AllocatesArgumentsBit::decode(flags)); + auto flags = scope_info->flags(); + EXPECT_EQ(allocates, + ScopeInfo::Flags::AllocatesArgumentsBit::decode(flags)); EXPECT_EQ(only_fixed, scope_info->CanOnlyAccessFixedFormalParameters()); }; run("(function(){})", false, false); @@ -286,7 +287,7 @@ static void CheckObject(Isolate* isolate, DirectHandle<Object> obj, DirectHandle<String> print_string = String::Flatten( isolate, indirect_handle(Object::NoSideEffectsToString(isolate, obj), isolate)); - CHECK(print_string->IsOneByteEqualTo(base::CStrVector(string))); + CHECK(print_string->IsOneByteEqualTo(string)); } static void CheckSmi(Isolate* isolate, int value, const char* string) { @@ -562,6 +563,26 @@ TEST_F(ObjectTest, ObjectMethodsThatTruncateMinusZero) { CHECK(IsZero(*result)); } +TEST_F(ObjectTest, ToUint32) { + Factory* factory = i_isolate()->factory(); + + DirectHandle<Object> pos_smi(Smi::FromInt(42), i_isolate()); + DirectHandle<Number> pos_res = + Object::ToUint32(i_isolate(), pos_smi).ToHandleChecked(); + EXPECT_TRUE(IsSmi(*pos_res)); + EXPECT_EQ(42.0, Object::NumberValue(*pos_res)); + + DirectHandle<Object> neg_smi(Smi::FromInt(-37), i_isolate()); + DirectHandle<Number> neg_res = + Object::ToUint32(i_isolate(), neg_smi).ToHandleChecked(); + EXPECT_EQ(4294967259.0, Object::NumberValue(*neg_res)); + + DirectHandle<Object> neg_str = factory->NewStringFromAsciiChecked("-37"); + DirectHandle<Number> str_res = + Object::ToUint32(i_isolate(), neg_str).ToHandleChecked(); + EXPECT_EQ(4294967259.0, Object::NumberValue(*str_res)); +} + #define TEST_FUNCTION_KIND(Name) \ TEST_F(ObjectTest, Name) { \ for (uint32_t i = 0; \ @@ -735,11 +756,11 @@ bool FunctionKindIsConstructable(FunctionKind kind) { } TEST_FUNCTION_KIND(IsConstructable) -bool FunctionKindIsStrictFunctionWithoutPrototype(FunctionKind kind) { +bool FunctionKindIsFunctionWithoutPrototype(FunctionKind kind) { return IsArrowFunction(kind) || IsConciseMethod(kind) || IsAccessorFunction(kind); } -TEST_FUNCTION_KIND(IsStrictFunctionWithoutPrototype) +TEST_FUNCTION_KIND(IsFunctionWithoutPrototype) #undef TEST_FUNCTION_KIND @@ -1010,5 +1031,15 @@ TEST_F(ObjectTest, JSObjectCopy) { EXPECT_EQ(*value1, *value2); } +TEST_F(ObjectTest, CorrectnessFuzzerSuppressionsFatalNoSecurityImpact) { + v8::HandleScope scope(isolate()); + SaveFlags save_flags; + v8_flags.correctness_fuzzer_suppressions = true; + EXPECT_DEATH_IF_SUPPORTED( + RunJS("1n << (1n << 30n)"), + "Fatal error with no security impact:\n# Aborting on invalid BigInt " + "length"); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/objects/string-table-unittest.cc b/deps/v8/test/unittests/objects/string-table-unittest.cc index 903d0093c03d..26d1f386a3b0 100644 --- a/deps/v8/test/unittests/objects/string-table-unittest.cc +++ b/deps/v8/test/unittests/objects/string-table-unittest.cc @@ -67,14 +67,14 @@ TEST_F(StringTableTest, InternalizeUtf8String) { const char* string = *ptr; HandleScope scope(isolate()); DirectHandle<String> a = - factory()->InternalizeUtf8String(base::CStrVector(string)); + factory()->InternalizeUtf8String(std::string_view(string)); EXPECT_TRUE(IsInternalizedString(*a)); DirectHandle<String> b = factory()->InternalizeUtf8String(string); EXPECT_EQ(*b, *a); - EXPECT_TRUE(b->IsOneByteEqualTo(base::CStrVector(string))); - b = factory()->InternalizeUtf8String(base::CStrVector(string)); + EXPECT_TRUE(b->IsOneByteEqualTo(string)); + b = factory()->InternalizeUtf8String(std::string_view(string)); EXPECT_EQ(*b, *a); - EXPECT_TRUE(b->IsOneByteEqualTo(base::CStrVector(string))); + EXPECT_TRUE(b->IsOneByteEqualTo(string)); } }; diff --git a/deps/v8/test/unittests/objects/value-serializer-unittest.cc b/deps/v8/test/unittests/objects/value-serializer-unittest.cc index befa5e60d487..4a456d838a96 100644 --- a/deps/v8/test/unittests/objects/value-serializer-unittest.cc +++ b/deps/v8/test/unittests/objects/value-serializer-unittest.cc @@ -19,6 +19,7 @@ #include "include/v8-wasm.h" #include "src/api/api-inl.h" #include "src/base/build_config.h" +#include "src/base/unique-array.h" #include "src/objects/backing-store.h" #include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-buffer.h" @@ -2623,6 +2624,39 @@ TEST_F(ValueSerializerTest, DecodeTypedArrayBrokenData) { ExpectScriptTrue("result.b === 13"); } +TEST_F(ValueSerializerTest, DecodeTypedArrayBrokenDataMultiValue) { + // Multi-value stream: Value 1 is a JSObject (assigned ID 0), Value 2 has a + // TypedArray with broken v13 flags (triggering the ReadObjectWrapper retry) + // and an ObjectReference back to Value 1 (ID 0). + const uint8_t data[] = { + 0xFF, 0x0D, // Version 13 header + 0x6F, 0x7B, 0x00, // Value 1: {} (ID 0) + 0x6F, // Value 2: BeginJSObject (ID 1) + 0x22, 0x01, 'a', // key "a" + 0x42, 0x00, // ArrayBuffer(0) (ID 2) + 0x56, 0x42, 0x00, 0x00, 0xE8, 0x47, // Uint8Array with v13 flags (ID 3) + 0x22, 0x03, 'r', 'e', 'f', // key "ref" + 0x5E, 0x00, // ObjectReference(0) -> Value 1 + 0x7B, 0x02, // EndJSObject(2 properties) + }; + Local<Context> context = deserialization_context(); + Context::Scope scope(context); + ValueDeserializer deserializer(isolate(), data, sizeof(data), nullptr); + ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false)); + + Local<Value> first; + ASSERT_TRUE(deserializer.ReadValue(context).ToLocal(&first)); + ASSERT_TRUE(first->IsObject()); + + Local<Value> second; + ASSERT_TRUE(deserializer.ReadValue(context).ToLocal(&second)); + ASSERT_TRUE(second->IsObject()); + + Local<Value> ref = + second.As<Object>()->Get(context, StringFromUtf8("ref")).ToLocalChecked(); + EXPECT_TRUE(ref->StrictEquals(first)); +} + TEST_F(ValueSerializerTest, DecodeInvalidTypedArray) { // Byte offset out of range. InvalidDecodeTest( @@ -2646,7 +2680,7 @@ TEST_F(ValueSerializerTest, RoundTripDataView) { ASSERT_TRUE(value->IsDataView()); EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset()); EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength()); - EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength()); + EXPECT_EQ(4u, DataView::Cast(*value)->GetBuffer()->ByteLength()); ExpectScriptTrue("Object.getPrototypeOf(result) === DataView.prototype"); // TODO(v8:11111): Use API functions for testing is_length_tracking and // is_backed_by_rab, once they're exposed @@ -2665,7 +2699,7 @@ TEST_F(ValueSerializerTest, DecodeDataView) { ASSERT_TRUE(value->IsDataView()); EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset()); EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength()); - EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength()); + EXPECT_EQ(4u, DataView::Cast(*value)->GetBuffer()->ByteLength()); ExpectScriptTrue( "Object.getPrototypeOf(result) === DataView.prototype"); }); @@ -2677,7 +2711,7 @@ TEST_F(ValueSerializerTest, RoundTripRabBackedDataView) { ASSERT_TRUE(value->IsDataView()); EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset()); EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength()); - EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength()); + EXPECT_EQ(4u, DataView::Cast(*value)->GetBuffer()->ByteLength()); ExpectScriptTrue("Object.getPrototypeOf(result) === DataView.prototype"); // TODO(v8:11111): Use API functions for testing is_length_tracking and // is_backed_by_rab, once they're exposed via the API. @@ -2693,7 +2727,7 @@ TEST_F(ValueSerializerTest, RoundTripRabBackedLengthTrackingDataView) { ASSERT_TRUE(value->IsDataView()); EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset()); EXPECT_EQ(3u, DataView::Cast(*value)->ByteLength()); - EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength()); + EXPECT_EQ(4u, DataView::Cast(*value)->GetBuffer()->ByteLength()); ExpectScriptTrue("Object.getPrototypeOf(result) === DataView.prototype"); // TODO(v8:11111): Use API functions for testing is_length_tracking and // is_backed_by_rab, once they're exposed via the API. @@ -2712,7 +2746,7 @@ TEST_F(ValueSerializerTest, DecodeDataViewBackwardsCompatibility) { ASSERT_TRUE(value->IsDataView()); EXPECT_EQ(1u, DataView::Cast(*value)->ByteOffset()); EXPECT_EQ(2u, DataView::Cast(*value)->ByteLength()); - EXPECT_EQ(4u, DataView::Cast(*value)->Buffer()->ByteLength()); + EXPECT_EQ(4u, DataView::Cast(*value)->GetBuffer()->ByteLength()); ExpectScriptTrue( "Object.getPrototypeOf(result) === DataView.prototype"); }); @@ -3480,8 +3514,8 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest { i::wasm::ErrorThrower thrower(i_isolate(), "MakeWasm"); auto enabled_features = i::wasm::WasmEnabledFeatures::FromIsolate(i_isolate()); - base::OwnedVector<const uint8_t> wire_bytes = - base::OwnedCopyOf(kIncrementerWasm); + base::UniqueArray<const uint8_t> wire_bytes = + base::UniqueCopyOf(kIncrementerWasm); i::MaybeDirectHandle<i::JSObject> compiled = i::wasm::GetWasmEngine()->SyncCompile(i_isolate(), enabled_features, i::wasm::CompileTimeImports{}, diff --git a/deps/v8/test/unittests/objects/weakarraylist-unittest.cc b/deps/v8/test/unittests/objects/weakarraylist-unittest.cc index 6a640a8ff4a8..232793854a6d 100644 --- a/deps/v8/test/unittests/objects/weakarraylist-unittest.cc +++ b/deps/v8/test/unittests/objects/weakarraylist-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/heap/factory.h" +#include "src/objects/casting.h" #include "test/unittests/test-utils.h" namespace v8 { @@ -10,6 +11,18 @@ namespace internal { using WeakArrayListTest = TestWithIsolate; +TEST_F(WeakArrayListTest, CastMaybeObjectToUnion) { + using Target = UnionOf<Smi, Weak<FixedArray>>; + Tagged<MaybeObject> weak = + MakeWeak(*isolate()->factory()->empty_fixed_array()); + Tagged<MaybeObject> smi = Smi::FromInt(1); + Tagged<MaybeObject> cleared = kClearedWeakValue; + + EXPECT_TRUE(Cast<Target>(weak).IsWeak()); + EXPECT_TRUE(Cast<Target>(smi).IsSmi()); + EXPECT_TRUE(Cast<Target>(cleared).IsCleared()); +} + TEST_F(WeakArrayListTest, Compact) { DirectHandle<WeakArrayList> list = isolate()->factory()->NewWeakArrayList(10); EXPECT_EQ(list->length().value(), 0u); diff --git a/deps/v8/test/unittests/parser/parsing-unittest.cc b/deps/v8/test/unittests/parser/parsing-unittest.cc index 4c3331c8fafb..f57ad6a52ed1 100644 --- a/deps/v8/test/unittests/parser/parsing-unittest.cc +++ b/deps/v8/test/unittests/parser/parsing-unittest.cc @@ -15,6 +15,7 @@ #include "src/ast/ast.h" #include "src/base/enum-set.h" #include "src/base/strings.h" +#include "src/base/unique-array.h" #include "src/execution/execution.h" #include "src/execution/isolate.h" #include "src/flags/flags.h" @@ -189,8 +190,7 @@ class ParsingTest : public TestWithContextAndZone { full_source += "; }"; i::DirectHandle<i::String> source_code = - factory->NewStringFromUtf8(base::CStrVector(full_source.c_str())) - .ToHandleChecked(); + factory->NewStringFromUtf8(full_source).ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source_code); @@ -347,11 +347,8 @@ class ParsingTest : public TestWithContextAndZone { size_t always_false_flags_length = 0, bool is_module = false, bool test_preparser = true, bool ignore_error_msg = false) { - i::Handle<i::String> str = i_isolate() - ->factory() - ->NewStringFromUtf8(base::Vector<const char>( - source, strlen(source))) - .ToHandleChecked(); + i::Handle<i::String> str = + i_isolate()->factory()->NewStringFromUtf8(source).ToHandleChecked(); for (int bits = 0; bits < (1 << varying_flags_length); bits++) { base::EnumSet<ParserFlag> flags; for (size_t flag_index = 0; flag_index < varying_flags_length; @@ -422,9 +419,9 @@ class ParsingTest : public TestWithContextAndZone { // Plug the source code pieces together. auto program = - base::OwnedVector<char>::NewForOverwrite(kProgramSize + 1); + base::UniqueArray<char>::NewForOverwrite(kProgramSize + 1); int length = - base::SNPrintF(program.as_vector(), "%s%s%s", context_data[i][0], + base::SNPrintF(program.as_span(), "%s%s%s", context_data[i][0], statement_data[j], context_data[i][1]); PrintF("%s\n", program.begin()); CHECK_EQ(length, kProgramSize); @@ -1420,12 +1417,11 @@ TEST_F(ParsingTest, ScopeUsesArgumentsSuperThis) { strlen(surroundings[j].suffix) + strlen(source_data[i].body)); auto program = - base::OwnedVector<char>::NewForOverwrite(kProgramByteSize + 1); - base::SNPrintF(program.as_vector(), "%s%s%s", surroundings[j].prefix, + base::UniqueArray<char>::NewForOverwrite(kProgramByteSize + 1); + base::SNPrintF(program.as_span(), "%s%s%s", surroundings[j].prefix, source_data[i].body, surroundings[j].suffix); i::DirectHandle<i::String> source = - factory->NewStringFromUtf8(base::CStrVector(program.begin())) - .ToHandleChecked(); + factory->NewStringFromUtf8(program.begin()).ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source); i::UnoptimizedCompileState compile_state; i::ReusableUnoptimizedCompileState reusable_state(isolate); @@ -1751,14 +1747,13 @@ TEST_F(ParsingTest, ScopePositions) { int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen; int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen; auto program = - base::OwnedVector<char>::NewForOverwrite(kProgramByteSize + 1); - base::SNPrintF(program.as_vector(), "%s%s%s", source_data[i].outer_prefix, + base::UniqueArray<char>::NewForOverwrite(kProgramByteSize + 1); + base::SNPrintF(program.as_span(), "%s%s%s", source_data[i].outer_prefix, source_data[i].inner_source, source_data[i].outer_suffix); // Parse program source. i::DirectHandle<i::String> source = - factory->NewStringFromUtf8(base::CStrVector(program.begin())) - .ToHandleChecked(); + factory->NewStringFromUtf8(program.begin()).ToHandleChecked(); CHECK_EQ(source->length(), kProgramSize); i::Handle<i::Script> script = factory->NewScript(source); @@ -1807,7 +1802,7 @@ TEST_F(ParsingTest, DiscardFunctionBody) { for (int i = 0; discard_sources[i]; i++) { const char* source = discard_sources[i]; i::DirectHandle<i::String> source_code = - factory->NewStringFromUtf8(base::CStrVector(source)).ToHandleChecked(); + factory->NewStringFromUtf8(source).ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source_code); i::UnoptimizedCompileState compile_state; i::ReusableUnoptimizedCompileState reusable_state(isolate); @@ -1919,9 +1914,9 @@ TEST_F(ParsingTest, ParserSync) { // Plug the source code pieces together. auto program = - base::OwnedVector<char>::NewForOverwrite(kProgramSize + 1); + base::UniqueArray<char>::NewForOverwrite(kProgramSize + 1); int length = - base::SNPrintF(program.as_vector(), "label: for (;;) { %s%s%s%s }", + base::SNPrintF(program.as_span(), "label: for (;;) { %s%s%s%s }", context_data[i][0], statement_data[j], termination_data[k], context_data[i][1]); CHECK_EQ(length, kProgramSize); @@ -3115,17 +3110,22 @@ TEST_F(ParsingTest, InvalidLeftHandSide) { const char* postfix_context_data[][2] = { {"", "++;"}, {"\"use strict\"; ", "++;"}, {nullptr, nullptr}}; + const char* sloppy_call_context_data[][2] = { + {"", " = 1;"}, {"++", ";"}, {"", "++;"}, {nullptr, nullptr}}; + + const char* strict_call_context_data[][2] = {{"\"use strict\"; ", " = 1;"}, + {"\"use strict\"; ++", ";"}, + {"\"use strict\"; ", "++;"}, + {nullptr, nullptr}}; + // Good left hand sides for assigment or prefix / postfix operations. - const char* good_statement_data[] = {"foo", - "foo.bar", - "foo[bar]", - "foo()[bar]", - "foo().bar", - "this.foo", - "this[foo]", - "new foo()[bar]", - "new foo().bar", - "foo()", + const char* good_statement_data[] = { + "foo", "foo.bar", "foo[bar]", "foo()[bar]", "foo().bar", + "this.foo", "this[foo]", "new foo()[bar]", "new foo().bar", nullptr}; + + // Call expressions are accepted as left hand sides only in sloppy mode for + // legacy web compatibility. + const char* call_statement_data[] = {"foo()", "foo(bar)", "foo[bar]()", "foo.bar()", @@ -3164,6 +3164,9 @@ TEST_F(ParsingTest, InvalidLeftHandSide) { RunParserSyncTest(postfix_context_data, good_statement_data, kSuccess); RunParserSyncTest(postfix_context_data, bad_statement_data_common, kError); + + RunParserSyncTest(sloppy_call_context_data, call_statement_data, kSuccess); + RunParserSyncTest(strict_call_context_data, call_statement_data, kError); } TEST_F(ParsingTest, FuncNameInferrerBasic) { @@ -3270,8 +3273,8 @@ TEST_F(ParsingTest, SerializationOfMaybeAssignmentFlag) { "h();"; auto program = - base::OwnedVector<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); - base::SNPrintF(program.as_vector(), "%s", src); + base::UniqueArray<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); + base::SNPrintF(program.as_span(), "%s", src); i::DirectHandle<i::String> source = factory->InternalizeUtf8String(program.begin()); source->PrintOn(stdout); @@ -3318,8 +3321,8 @@ TEST_F(ParsingTest, IfArgumentsArrayAccessedThenParametersMaybeAssigned) { "f(0);"; auto program = - base::OwnedVector<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); - base::SNPrintF(program.as_vector(), "%s", src); + base::UniqueArray<char>::NewForOverwrite(Utf8LengthHelper(src) + 1); + base::SNPrintF(program.as_span(), "%s", src); i::DirectHandle<i::String> source = factory->InternalizeUtf8String(program.begin()); source->PrintOn(stdout); @@ -3370,16 +3373,27 @@ TEST_F(ParsingTest, InnerAssignment) { {"var x = {a: 4, b: (x = 5)};", true, false}, {"var {x=1} = {a: 4, b: (x = 5)};", true, false}, {"var {x} = {x: 4, b: (x = 5)};", true, false}, + {"var [x = (x = 2)] = [];", true, false}, + {"'use strict'; let [x = (x = 2)] = [];", true, true}, + {"'use strict'; let {x = (x = 2)} = {};", true, true}, // Actual non-assignments. {"var x;", false, false}, {"var x = 5;", false, false}, + {"var [x = 5] = [];", false, false}, + {"var {x = 5} = {};", false, false}, + {"var {a: x = 5} = {};", false, false}, {"'use strict'; let x;", false, true}, {"'use strict'; let x = 6;", false, true}, + {"'use strict'; let [x = 6] = [];", false, true}, + {"'use strict'; let {x = 6} = {};", false, true}, + {"'use strict'; let {a: x = 6} = {};", false, true}, {"'use strict'; var x = 0; { let x = 6; }", false, true}, {"'use strict'; var x = 0; { let x; x = 6; }", false, true}, {"'use strict'; let x = 0; { let x = 6; }", false, true}, {"'use strict'; let x = 0; { let x; x = 6; }", false, true}, {"var x; try {} catch (x) { x = 5; }", false, false}, + {"var x; try {} catch ([x = 1]) { x = 5; }", false, false}, + {"var x; try {} catch ({x = 1}) { x = 5; }", false, false}, {"function x() {}", false, false}, // Eval approximation. {"var x; eval('');", true, false}, @@ -3424,22 +3438,39 @@ TEST_F(ParsingTest, InnerAssignment) { {"for (x of [1,2,3]) {}", true, false, false}, {"for (x in {a: 1}) {}", true, false, false}, {"for ([x] of [[1],[2],[3]]) {}", true, false, false}, + {"for ([x = 1] of [[]]) {}", true, false, false}, + {"for ({x = 1} of [{}]) {}", true, false, false}, {"for ([x] in {ab: 1}) {}", true, false, false}, {"for ([...x] in {ab: 1}) {}", true, false, false}, {"[x] = [1]", true, false, false}, + {"[x = 1] = []", true, false, false}, + {"({x = 1} = {})", true, false, false}, + {"({a: x = 1} = {})", true, false, false}, + {"let [y = (x = 1)] = [];", true, false, false}, + {"let {y = (x = 1)} = {};", true, false, false}, // Actual non-assignments. {"", false, false, false}, {"x;", false, false, false}, {"var x;", false, false, false}, {"var x = 8;", false, false, false}, + {"var [x = 8] = [];", false, false, false}, + {"var {x = 8} = {};", false, false, false}, + {"var {a: x = 8} = {};", false, false, false}, {"var x; x = 8;", false, false, false}, {"'use strict'; let x;", false, false, false}, {"'use strict'; let x = 8;", false, false, false}, + {"'use strict'; let [x = 8] = [];", false, false, false}, + {"'use strict'; let {x = 8} = {};", false, false, false}, + {"'use strict'; let {a: x = 8} = {};", false, false, false}, {"'use strict'; let x; x = 8;", false, false, false}, {"'use strict'; const x = 8;", false, false, false}, {"function x() {}", false, false, false}, {"function x() { x = 0; }", false, false, true}, {"function h(x) { x = 0; }", false, false, false}, + {"function h([x = 1]) { x = 0; }", false, false, false}, + {"function h({x = 1}) { x = 0; }", false, false, false}, + {"([x = 1]) => { x = 0; };", false, false, false}, + {"({x = 1}) => { x = 0; };", false, false, false}, {"'use strict'; { let x; x = 0; }", false, false, false}, {"{ var x; }; x = 0;", false, false, false}, {"with ({}) {}", false, true, false}, @@ -3471,9 +3502,9 @@ TEST_F(ParsingTest, InnerAssignment) { int inner_len = Utf8LengthHelper(inner); int len = prefix_len + outer_len + midfix_len + inner_len + suffix_len; - auto program = base::OwnedVector<char>::NewForOverwrite(len + 1); + auto program = base::UniqueArray<char>::NewForOverwrite(len + 1); - base::SNPrintF(program.as_vector(), "%s%s%s%s%s", prefix, outer, midfix, + base::SNPrintF(program.as_span(), "%s%s%s%s%s", prefix, outer, midfix, inner, suffix); UnoptimizedCompileState compile_state; @@ -3583,9 +3614,21 @@ TEST_F(ParsingTest, MaybeAssignedParameters) { {false, "function f({x:arg = 1}) {}"}, {true, "function f({x:arg = 1}, {y:b=(arg=2)}) {}"}, {true, "function f({x:arg = (arg = 2)}) {}"}, + {false, "function f({arg = 1}) {}"}, + {true, "function f({arg = 1}, {b=(arg=2)}) {}"}, + {true, "function f({arg = (arg = 2)}) {}"}, + {false, "function f([arg = 1]) {}"}, + {true, "function f([arg = 1], [b=(arg=2)]) {}"}, + {true, "function f([arg = (arg = 2)]) {}"}, {false, "var f = ({x:arg = 1}) => {}"}, {true, "var f = ({x:arg = 1}, {y:b=(arg=2)}) => {}"}, {true, "var f = ({x:arg = (arg = 2)}) => {}"}, + {false, "var f = ({arg = 1}) => {}"}, + {true, "var f = ({arg = 1}, {b=(arg=2)}) => {}"}, + {true, "var f = ({arg = (arg = 2)}) => {}"}, + {false, "var f = ([arg = 1]) => {}"}, + {true, "var f = ([arg = 1], [b=(arg=2)]) => {}"}, + {true, "var f = ([arg = (arg = 2)]) => {}"}, }; const char* suffix = "; f"; @@ -3594,9 +3637,9 @@ TEST_F(ParsingTest, MaybeAssignedParameters) { bool assigned = tests[i].arg_assigned; const char* source = tests[i].source; for (unsigned allow_lazy = 0; allow_lazy < 2; ++allow_lazy) { - auto program = base::OwnedVector<char>::NewForOverwrite( + auto program = base::UniqueArray<char>::NewForOverwrite( Utf8LengthHelper(source) + Utf8LengthHelper(suffix) + 1); - base::SNPrintF(program.as_vector(), "%s%s", source, suffix); + base::SNPrintF(program.as_span(), "%s%s", source, suffix); printf("%s\n", program.begin()); v8::Local<v8::Value> v = RunJS(program.begin()); i::DirectHandle<i::Object> o = v8::Utils::OpenDirectHandle(*v); @@ -3653,6 +3696,8 @@ TEST_F(ParsingTest, MaybeAssignedInsideLoop) { {true, "for (j=x; j<10; ++j) { let foo; [[foo]=[42]] = [] }", {0}}, {false, "for (j=x; j<10; ++j) { let foo = j }", {0}}, {false, "for (j=x; j<10; ++j) { let [foo] = [j] }", {0}}, + {false, "for (j=x; j<10; ++j) { let [foo = j] = [] }", {0}}, + {false, "for (j=x; j<10; ++j) { let {foo = j} = {} }", {0}}, {false, "for (j=x; j<10; ++j) { const foo = j }", {0}}, {false, "for (j=x; j<10; ++j) { const [foo] = [j] }", {0}}, {false, "for (j=x; j<10; ++j) { function foo() {return j} }", {0}}, @@ -12350,12 +12395,12 @@ TEST_F(ParsingTest, NoPessimisticContextAllocation) { int len = prefix_len + inner_function_len + params_len + source_len + suffix_len; - auto program = base::OwnedVector<char>::NewForOverwrite(len + 1); - base::SNPrintF(program.as_vector(), "%s", prefix); - base::SNPrintF(program.as_vector() + prefix_len, inner_function, + auto program = base::UniqueArray<char>::NewForOverwrite(len + 1); + base::SNPrintF(program.as_span(), "%s", prefix); + base::SNPrintF(program.as_span().subspan(prefix_len), inner_function, inners[i].params, inners[i].source); - base::SNPrintF(program.as_vector() + prefix_len + inner_function_len + - params_len + source_len, + base::SNPrintF(program.as_span().subspan(prefix_len + inner_function_len + + params_len + source_len), "%s", suffix); i::DirectHandle<i::String> source = @@ -12923,7 +12968,7 @@ TEST_F(ParsingTest, LexicalLoopVariable) { auto TestProgram = [isolate](const char* program, TestCB test) { i::Factory* const factory = isolate->factory(); i::DirectHandle<i::String> source = - factory->NewStringFromUtf8(base::CStrVector(program)).ToHandleChecked(); + factory->NewStringFromUtf8(program).ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source); i::UnoptimizedCompileState compile_state; i::ReusableUnoptimizedCompileState reusable_state(isolate); diff --git a/deps/v8/test/unittests/parser/preparser-unittest.cc b/deps/v8/test/unittests/parser/preparser-unittest.cc index dd38c7148b85..c8b655bd731e 100644 --- a/deps/v8/test/unittests/parser/preparser-unittest.cc +++ b/deps/v8/test/unittests/parser/preparser-unittest.cc @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/parsing/preparser.h" + #include "src/api/api-inl.h" #include "src/ast/ast.h" #include "src/base/strings.h" -#include "src/base/vector.h" +#include "src/base/unique-array.h" #include "src/codegen/compiler.h" #include "src/objects/objects-inl.h" #include "src/parsing/parse-info.h" @@ -35,8 +37,6 @@ enum SkipTests { enum class PreciseMaybeAssigned { YES, NO }; -enum class Bailout { BAILOUT_IF_OUTER_SLOPPY, NO }; - } // namespace class PreParserTest : public TestWithNativeContext { @@ -133,14 +133,11 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { Inner(const char* p, const char* s, SkipTests skip, PreciseMaybeAssigned precise) : params(p), source(s), skip(skip), precise_maybe_assigned(precise) {} - Inner(const char* p, const char* s, SkipTests skip, Bailout bailout) - : params(p), source(s), skip(skip), bailout(bailout) {} const char* params = ""; const char* source; SkipTests skip = DONT_SKIP; PreciseMaybeAssigned precise_maybe_assigned = PreciseMaybeAssigned::YES; - Bailout bailout = Bailout::NO; std::function<void()> prologue = nullptr; std::function<void()> epilogue = nullptr; } inners[] = { @@ -280,6 +277,13 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { {"const {var1: var2, var3: {var4: var5}} = {var1: 1, var3: {var4: 2}};"}, {"const {var1: var2, var3: [var4, var5]} = {var1: 1, var3: [2, 3]};"}, + {"var [var1 = 1, var2 = 2] = [1, 2]; function f() { var1; var2; }"}, + {"var {var1 = 1, var2: var3 = 2} = {}; function f() { var1; var3; }"}, + {"let [var1 = 1, var2 = 2] = [1, 2]; function f() { var1; var2; }"}, + {"let {var1 = 1, var2: var3 = 2} = {}; function f() { var1; var3; }"}, + {"const [var1 = 1, var2 = 2] = [1, 2]; function f() { var1; var2; }"}, + {"const {var1 = 1, var2: var3 = 2} = {}; function f() { var1; var3; }"}, + // Referencing the function variable. {"test;"}, {"function f1() { f1; }"}, @@ -511,10 +515,9 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { {"var1, ...var2", "function f1() { var2 = 9; }", SKIP_STRICT_FUNCTION}, // Default parameters. - {"var1 = 3", "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, - {"var1, var2 = var1", "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, - {"var1, var2 = 4, ...var3", "", SKIP_STRICT_FUNCTION, - PreciseMaybeAssigned::NO}, + {"var1 = 3", "", SKIP_STRICT_FUNCTION}, + {"var1, var2 = var1", "", SKIP_STRICT_FUNCTION}, + {"var1, var2 = 4, ...var3", "", SKIP_STRICT_FUNCTION}, // Destructuring parameters. Because of the search space explosion, we // cannot test all interesting cases. Let's try to test a relevant subset. @@ -558,10 +561,10 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { // Complicated params. {"var1, [var2], var3 = 24, [var4, var5] = [2, 4], var6, {var7}, var8, " "{name9: var9, name10: var10}, ...var11", - "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, + "", SKIP_STRICT_FUNCTION}, // Complicated cases from bugs. - {"var1 = {} = {}", "", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, + {"var1 = {} = {}", "", SKIP_STRICT_FUNCTION}, // Destructuring rest. Because we can. {"var1, ...[var2]", "", SKIP_STRICT_FUNCTION}, @@ -574,16 +577,12 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { {"var1, ...{0: var2, 1: var3}", "", SKIP_STRICT_FUNCTION}, // Default parameters for destruring parameters. - {"[var1, var2] = [2, 4]", "", SKIP_STRICT_FUNCTION, - PreciseMaybeAssigned::NO}, - {"{var1, var2} = {var1: 3, var2: 3}", "", SKIP_STRICT_FUNCTION, - PreciseMaybeAssigned::NO}, + {"[var1, var2] = [2, 4]", "", SKIP_STRICT_FUNCTION}, + {"{var1, var2} = {var1: 3, var2: 3}", "", SKIP_STRICT_FUNCTION}, // Default parameters inside destruring parameters. - {"[var1 = 4, var2 = var1]", "", SKIP_STRICT_FUNCTION, - PreciseMaybeAssigned::NO}, - {"{var1 = 4, var2 = var1}", "", SKIP_STRICT_FUNCTION, - PreciseMaybeAssigned::NO}, + {"[var1 = 4, var2 = var1]", "", SKIP_STRICT_FUNCTION}, + {"{var1 = 4, var2 = var1}", "", SKIP_STRICT_FUNCTION}, // Locals shadowing parameters. {"var1, var2", "var var1 = 16; () => { var1 = 17; };"}, @@ -596,7 +595,7 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { {"var1, var2, ...var3", "var var3 = 16; () => { var3 = 17; };", SKIP_STRICT_FUNCTION}, {"var1, var2 = var1", "var var1 = 16; () => { var1 = 17; };", - SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, + SKIP_STRICT_FUNCTION}, // Hoisted sloppy block function shadowing a parameter. // FIXME(marja): why is maybe_assigned inaccurate? @@ -605,14 +604,14 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { // Sloppy eval in default parameter. {"var1, var2 = eval(''), var3", "let var4 = 0;", SKIP_STRICT_FUNCTION, - Bailout::BAILOUT_IF_OUTER_SLOPPY}, + PreciseMaybeAssigned::NO}, {"var1, var2 = eval(''), var3 = eval('')", "let var4 = 0;", - SKIP_STRICT_FUNCTION, Bailout::BAILOUT_IF_OUTER_SLOPPY}, + SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, // Sloppy eval in arrow function parameter list which is inside another // arrow function parameter list. {"var1, var2 = (var3, var4 = eval(''), var5) => { let var6; }, var7", - "let var8 = 0;", SKIP_STRICT_FUNCTION, Bailout::BAILOUT_IF_OUTER_SLOPPY}, + "let var8 = 0;", SKIP_STRICT_FUNCTION, PreciseMaybeAssigned::NO}, // Sloppy eval in a function body with non-simple parameters. {"var1 = 1, var2 = 2", "eval('');", SKIP_STRICT_FUNCTION}, @@ -626,6 +625,9 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { {"try { } catch({var1, var2}) { function f() { var1 = 3; } }"}, {"try { } catch([var1, var2]) { function f() { var1 = 3; } }"}, + {"try { } catch({var1 = 1, var2: var3 = 2}) { function f() { var1; var3; " + "} }"}, + {"try { } catch([var1 = 1, var2 = 2]) { function f() { var1; var2; } }"}, {"try { } catch({}) { }"}, {"try { } catch([]) { }"}, @@ -706,8 +708,8 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { int source_len = Utf8LengthHelper(inner.source); int len = code_len + params_len + source_len; - auto program = v8::base::OwnedVector<char>::NewForOverwrite(len + 1); - v8::base::SNPrintF(program.as_vector(), code, inner.params, inner.source); + auto program = v8::base::UniqueArray<char>::NewForOverwrite(len + 1); + v8::base::SNPrintF(program.as_span(), code, inner.params, inner.source); i::HandleScope scope(isolate); i::ReusableUnoptimizedCompileState reusable_state(isolate); @@ -723,12 +725,6 @@ TEST_F(PreParserTest, PreParserScopeAnalysis) { i::DirectHandle<i::JSFunction> f = i::Cast<i::JSFunction>(o); i::DirectHandle<i::SharedFunctionInfo> shared(f->shared(), isolate); - if (inner.bailout == Bailout::BAILOUT_IF_OUTER_SLOPPY && - !outer.strict_outer) { - CHECK(!shared->HasUncompiledDataWithPreparseData(isolate)); - continue; - } - CHECK(shared->HasUncompiledDataWithPreparseData(isolate)); i::Handle<i::PreparseData> produced_data_on_heap( shared->uncompiled_data_with_preparse_data(isolate)->preparse_data(), @@ -1011,5 +1007,14 @@ TEST_F(PreParserTest, ProducingAndConsumingByteData) { } } +TEST_F(PreParserTest, DefaultExpressionIsNotThis) { + CHECK(!PreParserExpression::Default().IsThis()); + CHECK(PreParserExpression::This().IsThis()); + CHECK(!PreParserExpression::Property().IsThisProperty()); + CHECK(PreParserExpression::ThisProperty().IsThisProperty()); + CHECK(!PreParserExpression::PrivateReference().IsThisProperty()); + CHECK(PreParserExpression::ThisPrivateReference().IsThisProperty()); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/parser/scanner-unittest.cc b/deps/v8/test/unittests/parser/scanner-unittest.cc index 3315fd512d83..4fd6497f8964 100644 --- a/deps/v8/test/unittests/parser/scanner-unittest.cc +++ b/deps/v8/test/unittests/parser/scanner-unittest.cc @@ -53,6 +53,48 @@ const char src_simple[] = "function foo() { var x = 2 * a() + b; }"; // names. That should have the same result, but has much nicer error messaages. #define CHECK_TOK(a, b) CHECK_EQ(Token::Name(a), Token::Name(b)) +TEST_F(ScannerTest, HasImmediateCommaOrRightBracket) { + const struct { + const char* source; + Token::Value literal; + Token::Value following; + bool is_immediate_delimiter; + } cases[] = { + {"1,2", Token::kSmi, Token::kComma, true}, + {"1]", Token::kSmi, Token::kRightBracket, true}, + {"1 ,2", Token::kSmi, Token::kComma, false}, + {"1\n]", Token::kSmi, Token::kRightBracket, false}, + {"1/*comment*/,2", Token::kSmi, Token::kComma, false}, + {"1//comment\n]", Token::kSmi, Token::kRightBracket, false}, + {"1n]", Token::kBigInt, Token::kRightBracket, true}, + {"'s',2", Token::kString, Token::kComma, true}, + {"null]", Token::kNullLiteral, Token::kRightBracket, true}, + {"1", Token::kSmi, Token::kEos, false}, + {"1/*", Token::kSmi, Token::kIllegal, false}, + {"1+2]", Token::kSmi, Token::kAdd, false}, + {"1/*]*/+2", Token::kSmi, Token::kAdd, false}, + {"'s'.length]", Token::kString, Token::kPeriod, false}, + }; + for (const auto& test_case : cases) { + for (int lookahead = 0; lookahead < 3; ++lookahead) { + auto scanner = make_scanner(test_case.source); + if (lookahead > 0) scanner->PeekAhead(); + if (lookahead > 1) scanner->PeekAheadAhead(); + CHECK_EQ(test_case.is_immediate_delimiter && lookahead == 0, + scanner->HasImmediateCommaOrRightBracket()); + CHECK_TOK(test_case.literal, scanner->Next()); + CHECK_TOK(test_case.following, scanner->Next()); + + auto error_scanner = make_scanner(test_case.source); + if (lookahead > 0) error_scanner->PeekAhead(); + if (lookahead > 1) error_scanner->PeekAheadAhead(); + error_scanner->set_parser_error(); + CHECK(!error_scanner->HasImmediateCommaOrRightBracket()); + CHECK_TOK(Token::kIllegal, error_scanner->Next()); + } + } +} + TEST_F(ScannerTest, Bookmarks) { // Scan through the given source and record the tokens for use as reference // below. diff --git a/deps/v8/test/unittests/profiler/heap-snapshot-scopes-unittest.cc b/deps/v8/test/unittests/profiler/heap-snapshot-scopes-unittest.cc index 7aef01eeed4f..29dd653885e2 100644 --- a/deps/v8/test/unittests/profiler/heap-snapshot-scopes-unittest.cc +++ b/deps/v8/test/unittests/profiler/heap-snapshot-scopes-unittest.cc @@ -285,8 +285,8 @@ class HeapSnapshotScopesTest : public TestWithContext { EXPECT_EQ(curr_scope->scope_id, ctx_scope_id); if (curr_scope->variables.empty()) { - // Context variable emission was disabled for this scope (e.g., class - // scope or a scope containing/enclosing direct eval). + // Context variable emission was disabled for this scope (e.g., script + // scope, class scope, or a scope containing/enclosing direct eval). } else { int local_count = scope_info->ContextLocalCount(); EXPECT_EQ(curr_scope->variables.size(), @@ -506,20 +506,15 @@ TEST_F(HeapSnapshotScopesTest, GlobalVariables) { TakeHeapSnapshot(); const SnapshotSourceScopeData* inner = GetScopeForClosure(*inner_fn); - // Script scope contains lexical variables (let and const) in context vars. + // Script scope contains global lexical variables (let and const) that can be + // accessed across different scripts, for which uses are not tracked. + // Therefore, context variables are omitted for script scopes to disable dead + // context analysis. const SnapshotSourceScopeData* script_scope = inner->parent; ASSERT_NE(nullptr, script_scope); EXPECT_EQ(0, script_scope->depth); EXPECT_EQ(nullptr, script_scope->parent); - EXPECT_NE(nullptr, script_scope->FindVariable("scriptConst")); - // Global var is on the global object, not in script context. - EXPECT_EQ(nullptr, script_scope->FindVariable("scriptVar")); - - const VariableDefinition* let_var = script_scope->FindVariable("scriptLet"); - const VariableDefinition* const_var = - script_scope->FindVariable("scriptConst"); - AssertUses(let_var, {inner}); - AssertUses(const_var, {inner}); + EXPECT_TRUE(script_scope->variables.empty()); CheckContextSlots(inner_fn); } diff --git a/deps/v8/test/unittests/profiler/heap-snapshot-unittest.cc b/deps/v8/test/unittests/profiler/heap-snapshot-unittest.cc index 439db008c0a9..792a87c4cbfa 100644 --- a/deps/v8/test/unittests/profiler/heap-snapshot-unittest.cc +++ b/deps/v8/test/unittests/profiler/heap-snapshot-unittest.cc @@ -13,6 +13,15 @@ #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" +#if V8_ENABLE_WEBASSEMBLY +#include "src/wasm/canonical-types.h" +#include "src/wasm/struct-types.h" +#include "src/wasm/wasm-module.h" +#include "src/wasm/wasm-objects-inl.h" +#include "src/wasm/wasm-value.h" +#include "test/common/flag-utils.h" +#endif // V8_ENABLE_WEBASSEMBLY + namespace v8::internal { template <typename TMixin> @@ -432,6 +441,27 @@ TEST_F(HeapSnapshotTest, StringProperties) { EXPECT_TRUE(HasNamedEdge(*sliced, "parent")); } +TEST_F(HeapSnapshotTest, SlicedStringOffset) { + if (!v8_flags.string_slices) return; + Factory* factory = i_isolate()->factory(); + HandleScope scope(i_isolate()); + + Handle<String> parent = + factory->NewStringFromAsciiChecked("abcdefghijklmnopqrstuvwxyz"); + Handle<String> sliced = factory->NewProperSubString(parent, 5, 20); + + HeapSnapshot* snapshot = TakeHeapSnapshot(); + + // The value of a sliced string can be reconstructed from its parent, offset + // and length. + const HeapEntry* entry = GetEntryFor(i_isolate(), snapshot, *sliced); + ASSERT_NE(nullptr, entry); + EXPECT_EQ(HeapEntry::kSlicedString, entry->type()); + EXPECT_TRUE(HasNamedEdge(*entry, "parent")); + EXPECT_EQ(5, GetIntEdge(entry, "offset")); + EXPECT_EQ(15, GetIntEdge(entry, "length")); +} + TEST_F(HeapSnapshotTest, ScriptName) { v8::HandleScope scope(v8_isolate()); v8::Local<v8::Context> context = v8_context(); @@ -1038,4 +1068,112 @@ TEST_F(HeapSnapshotTest, ScriptSourceStringsUntruncated) { EXPECT_TRUE(regular_truncated.value()); } +#if V8_ENABLE_WEBASSEMBLY +TEST_F(HeapSnapshotTest, WasmStructAndCustomMapReferences) { + FlagScope<bool> merged_descriptors(&v8_flags.wasm_merged_descriptors, true); + HandleScope scope(i_isolate()); + Factory* factory = i_isolate()->factory(); + + wasm::WasmModule module; + // Type 0: regular struct (described by Type 1) with an i32 and an externref. + wasm::StructType::Builder<wasm::WasmModuleSignatureStorage> struct_builder( + &module.signature_storage, 2, false, SharedFlag{false}); + struct_builder.AddField(wasm::kWasmI32, false); + struct_builder.AddField(wasm::kWasmExternRef, false); + const wasm::StructType* struct_type = struct_builder.Build(); + wasm::TypeDefinition struct_def(struct_type, wasm::kNoSuperType, false, + SharedFlag{false}); + struct_def.descriptor = wasm::ModuleTypeIndex{1}; + module.AddTypeForTesting(struct_def); + + // Type 1: descriptor struct (describes Type 0) with an i64 and an externref. + wasm::StructType::Builder<wasm::WasmModuleSignatureStorage> desc_builder( + &module.signature_storage, 2, true, SharedFlag{false}); + desc_builder.AddField(wasm::kWasmI64, false); + desc_builder.AddField(wasm::kWasmExternRef, false); + const wasm::StructType* desc_type = desc_builder.Build(); + wasm::TypeDefinition desc_def(desc_type, wasm::kNoSuperType, false, + SharedFlag{false}); + desc_def.describes = wasm::ModuleTypeIndex{0}; + module.AddTypeForTesting(desc_def); + + wasm::GetTypeCanonicalizer()->AddRecursiveGroup(&module, 2); + wasm::CanonicalTypeIndex struct_canon_index = + module.canonical_type_id(wasm::ModuleTypeIndex{0}); + wasm::CanonicalTypeIndex desc_canon_index = + module.canonical_type_id(wasm::ModuleTypeIndex{1}); + + DirectHandle<Map> struct_map = + CreateStructMap(i_isolate(), struct_canon_index, DirectHandle<Map>(), 0, + DirectHandle<NativeContext>()); + DirectHandle<Map> desc_map = + CreateStructMap(i_isolate(), desc_canon_index, DirectHandle<Map>(), 0, + DirectHandle<NativeContext>()); + + Handle<JSObject> struct_ref_target = factory->NewJSObjectWithNullProto(); + Handle<JSObject> desc_ref_target = factory->NewJSObjectWithNullProto(); + + Handle<WasmCustomMap> custom_map = factory->NewWasmCustomMapUninitialized( + desc_type, struct_canon_index, WasmStruct::Size(struct_type), + WASM_STRUCT_TYPE, struct_map, 1, desc_map); + { + DisallowGarbageCollection no_gc; + base::WriteUnalignedValue<int64_t>( + custom_map->RawFieldAddress(desc_type->field_offset(0)), 9876543210LL); + int ref_offset = WasmCustomMap::kHeaderSize + desc_type->field_offset(1); + TaggedField<Object>::store(*custom_map, ref_offset, *desc_ref_target); + WriteBarrier::ForValue(*custom_map, + custom_map->RawMaybeWeakField(ref_offset), + *desc_ref_target, UPDATE_WRITE_BARRIER); + } + + wasm::WasmValue struct_fields[2] = { + wasm::WasmValue(int32_t{42}), + wasm::WasmValue(struct_ref_target, + wasm::CanonicalValueType{wasm::kWasmExternRef})}; + DirectHandle<WasmStruct> wasm_struct = + factory->NewWasmStruct(struct_type, struct_fields, custom_map); + + HeapSnapshot* snapshot = TakeHeapSnapshot(); + + // Verify WasmStruct entry and its field edges. + const HeapEntry* struct_entry = + GetEntryFor(i_isolate(), snapshot, *wasm_struct); + ASSERT_NE(nullptr, struct_entry); + + const HeapGraphEdge* struct_field0 = GetNamedEdge(*struct_entry, "$field0"); + ASSERT_NE(nullptr, struct_field0); + EXPECT_EQ(HeapGraphEdge::kInternal, struct_field0->type()); + EXPECT_EQ(HeapEntry::kString, struct_field0->to()->type()); + EXPECT_STREQ("42", struct_field0->to()->name()); + + const HeapEntry* struct_ref_entry = + GetEntryFor(i_isolate(), snapshot, *struct_ref_target); + ASSERT_NE(nullptr, struct_ref_entry); + const HeapGraphEdge* struct_field1 = GetNamedEdge(*struct_entry, "$field1"); + ASSERT_NE(nullptr, struct_field1); + EXPECT_EQ(HeapGraphEdge::kProperty, struct_field1->type()); + EXPECT_EQ(struct_ref_entry, struct_field1->to()); + + // Verify WasmCustomMap entry and its field edges. + const HeapEntry* custom_map_entry = + GetEntryFor(i_isolate(), snapshot, *custom_map); + ASSERT_NE(nullptr, custom_map_entry); + + const HeapGraphEdge* desc_field0 = GetNamedEdge(*custom_map_entry, "$field0"); + ASSERT_NE(nullptr, desc_field0); + EXPECT_EQ(HeapGraphEdge::kInternal, desc_field0->type()); + EXPECT_EQ(HeapEntry::kString, desc_field0->to()->type()); + EXPECT_STREQ("9876543210", desc_field0->to()->name()); + + const HeapEntry* desc_ref_entry = + GetEntryFor(i_isolate(), snapshot, *desc_ref_target); + ASSERT_NE(nullptr, desc_ref_entry); + const HeapGraphEdge* desc_field1 = GetNamedEdge(*custom_map_entry, "$field1"); + ASSERT_NE(nullptr, desc_field1); + EXPECT_EQ(HeapGraphEdge::kProperty, desc_field1->type()); + EXPECT_EQ(desc_ref_entry, desc_field1->to()); +} +#endif // V8_ENABLE_WEBASSEMBLY + } // namespace v8::internal diff --git a/deps/v8/test/unittests/regexp/regexp-fuzzer.cc b/deps/v8/test/unittests/regexp/regexp-fuzzer.cc index 34b1dbe5955c..523b4e8f639e 100644 --- a/deps/v8/test/unittests/regexp/regexp-fuzzer.cc +++ b/deps/v8/test/unittests/regexp/regexp-fuzzer.cc @@ -116,7 +116,7 @@ void RegExpTest<T>::RunRegExp(const std::string& regexp_input, // Convert input string. i::MaybeDirectHandle<i::String> maybe_source = - factory_->NewStringFromUtf8(v8::base::CStrVector(regexp_input.c_str())); + factory_->NewStringFromUtf8(regexp_input); i::DirectHandle<i::String> source; if (!maybe_source.ToHandle(&source)) { i_isolate_->clear_exception(); diff --git a/deps/v8/test/unittests/regexp/regexp-unittest.cc b/deps/v8/test/unittests/regexp/regexp-unittest.cc index e734bac8d75c..13082cd73297 100644 --- a/deps/v8/test/unittests/regexp/regexp-unittest.cc +++ b/deps/v8/test/unittests/regexp/regexp-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/regexp/regexp.h" +#include <array> #include <cstdlib> #include <memory> #include <sstream> @@ -594,13 +595,9 @@ static regexp::Node* Compile(const char* input, bool multiline, bool unicode, return nullptr; } DirectHandle<String> pattern = - isolate->factory() - ->NewStringFromUtf8(base::CStrVector(input)) - .ToHandleChecked(); + isolate->factory()->NewStringFromUtf8(input).ToHandleChecked(); DirectHandle<String> sample_subject = - isolate->factory() - ->NewStringFromUtf8(base::CStrVector("")) - .ToHandleChecked(); + isolate->factory()->NewStringFromUtf8("").ToHandleChecked(); DirectHandle<IrRegExpData> re_data = TrustedCast<IrRegExpData>(isolate->factory()->NewIrRegExpData( pattern, pattern, JSRegExp::AsJSRegExpFlags(flags), @@ -1512,6 +1509,31 @@ TEST_F(RegExpTest, NonUnicodeCaseEquivalence) { ASSERT_TRUE(expected == actual) << c; } } + +TEST_F(RegExpTest, SupplementaryCaseEquivalents) { + using CaseFolding = regexp::CaseFolding; + icu::UnicodeSet expected; + for (UChar32 c = 0; c <= 0xffff; ++c) { + icu::UnicodeSet closure(c, c); + closure.closeOver(USET_SIMPLE_CASE_INSENSITIVE); + const bool has_supplementary = closure.containsSome(0x10000, 0x10ffff); + if (has_supplementary) expected.add(c); + const bool actual = + CaseFolding::HasSupplementaryEquivalents(static_cast<base::uc16>(c)); + ASSERT_EQ(has_supplementary, actual) << c; + + // Non-unicode closure must never yield supplementary code points. + icu::UnicodeSet non_unicode(c, c); + CaseFolding::CloseOver(non_unicode, CaseFolding::Mode::kNonUnicode); + ASSERT_FALSE(non_unicode.containsSome(0x10000, 0x10ffff)) << c; + } + // U+1DF95 LATIN SMALL LIGATURE LONG S WITH DESCENDER S (Unicode 18) + // case-folds to U+00DF LATIN SMALL LETTER SHARP S. + if (u_foldCase(0x1df95, U_FOLD_CASE_DEFAULT) == 0xdf) { + EXPECT_TRUE(expected.contains(0xdf)); + EXPECT_TRUE(expected.contains(0x1e9e)); + } +} #endif // !DEBUG TEST_F(RegExpTest, CaseClosureMixedSets) { @@ -1524,6 +1546,10 @@ TEST_F(RegExpTest, CaseClosureMixedSets) { expected.add('A', 'C').add('K'); if (mode == CaseFolding::Mode::kUnicode) { expected.add('s').add('S').add(0x212a).add(0x1e9e); + // Since Unicode 18, U+1DF95 case-folds to U+00DF. + if (u_foldCase(0x1df95, U_FOLD_CASE_DEFAULT) == 0xdf) { + expected.add(0x1df95); + } actual.add(0x10400); expected.add(0x10400).add(0x10428); } @@ -1651,7 +1677,7 @@ static void TestRangeCaseIndependence( static void TestSimpleRangeCaseIndependence(Isolate* isolate, regexp::CharacterRange input, regexp::CharacterRange expected) { - base::EmbeddedVector<regexp::CharacterRange, 1> vector; + std::array<regexp::CharacterRange, 1> vector; vector[0] = expected; TestRangeCaseIndependence(isolate, input, vector); } diff --git a/deps/v8/test/unittests/regress/regress-536954139-unittest.cc b/deps/v8/test/unittests/regress/regress-536954139-unittest.cc index 8d3943b3180a..e0cf39b5c0e4 100644 --- a/deps/v8/test/unittests/regress/regress-536954139-unittest.cc +++ b/deps/v8/test/unittests/regress/regress-536954139-unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <array> + #include "src/base/vector.h" #include "src/diagnostics/disasm.h" #include "src/diagnostics/disassembler.h" @@ -19,12 +21,12 @@ TEST_F(DisasmX64RegressTest, Regress536954139) { disasm::NameConverter converter; disasm::Disassembler disassembler(converter); - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; buffer[0] = '\0'; disassembler.InstructionDecode(buffer, code); // The disassembled string should contain "vpminsd". - EXPECT_NE(nullptr, strstr(buffer.begin(), "vpminsd")) << buffer.begin(); + EXPECT_NE(nullptr, strstr(buffer.data(), "vpminsd")) << buffer.data(); } } // namespace internal diff --git a/deps/v8/test/unittests/run-all-unittests.cc b/deps/v8/test/unittests/run-all-unittests.cc index 1e2a561b0992..29fdf38db3c4 100644 --- a/deps/v8/test/unittests/run-all-unittests.cc +++ b/deps/v8/test/unittests/run-all-unittests.cc @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cstring> #include <memory> +#include <string> #if defined(_WIN32) #include <windows.h> @@ -11,11 +13,24 @@ #include "include/cppgc/platform.h" #include "include/libplatform/libplatform.h" #include "include/v8-initialization.h" +#include "include/v8config.h" #include "src/base/compiler-specific.h" #include "src/base/logging.h" #include "src/base/page-allocator.h" #include "testing/gmock/include/gmock/gmock.h" +#if defined(V8_OS_POSIX) && !defined(V8_OS_FUCHSIA) && !defined(V8_OS_IOS) && \ + !defined(THREAD_SANITIZER) +#define V8_SUPPORTS_FORK_SERVER 1 +#include <fcntl.h> +#include <poll.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <cerrno> +#include <csignal> +#endif + #ifdef V8_ENABLE_FUZZTEST #include "test/unittests/fuzztest-init-adapter.h" #endif // V8_ENABLE_FUZZTEST @@ -45,6 +60,193 @@ class CppGCEnvironment final : public ::testing::Environment { void TearDown() override { cppgc::ShutdownProcess(); } }; +bool ExtractForkServerFlag(int* argc, char** argv) { + if (*argc <= 1) return false; + bool found = false; + int write_idx = 1; + for (int read_idx = 1; read_idx < *argc; ++read_idx) { + if (strcmp(argv[read_idx], "--fork-server") == 0) { + found = true; + } else { + argv[write_idx++] = argv[read_idx]; + } + } + argv[write_idx] = nullptr; + *argc = write_idx; + return found; +} + +#ifdef V8_SUPPORTS_FORK_SERVER + +bool WriteAll(int fd, const void* data, size_t len) { + const char* ptr = static_cast<const char*>(data); + size_t remaining = len; + while (remaining > 0) { + ssize_t written = write(fd, ptr, remaining); + if (written < 0) { + if (errno == EINTR) continue; + return false; + } + ptr += written; + remaining -= static_cast<size_t>(written); + } + return true; +} + +bool ReadLine(int fd, std::string* line) { + line->clear(); + char ch; + while (true) { + ssize_t n = read(fd, &ch, 1); + if (n < 0) { + if (errno == EINTR) continue; + return false; + } + if (n == 0) { + return false; + } + if (ch == '\n') { + return true; + } + line->push_back(ch); + } +} + +bool DrainPipes(int ctrl_fd, int out_fd, int err_fd, std::string* out_str, + std::string* err_str) { + struct pollfd fds[3] = { + {out_fd, POLLIN, 0}, {err_fd, POLLIN, 0}, {ctrl_fd, POLLIN, 0}}; + int open_fds = 2; + char buf[4096]; + while (open_fds > 0) { + if (poll(fds, 3, -1) < 0) { + if (errno == EINTR) continue; + break; + } + if (fds[2].revents) return false; + for (int i = 0; i < 2; ++i) { + if (fds[i].fd < 0 || !fds[i].revents) continue; + ssize_t n = read(fds[i].fd, buf, sizeof(buf)); + if (n > 0) { + (i == 0 ? out_str : err_str)->append(buf, static_cast<size_t>(n)); + } else if (n == 0 || errno != EINTR) { + fds[i].fd = -1; + --open_fds; + } + } + } + return true; +} + +// Runs a persistent fork-server loop over the original stdin/stdout pipes: +// Request (on stdin): "<gtest_filter>\n" +// Response (on stdout): "RES <exit_code> <stdout_len> <stderr_len>\n" +// followed by <stdout_len> raw stdout bytes and +// <stderr_len> raw stderr bytes. +// <exit_code> is the child's exit status, or -<signal> if terminated by a +// signal (matching Python's subprocess.Popen.returncode convention). +// The protocol is synchronous (one request in flight at a time). Any +// activity or EOF on the control pipe while a child is running indicates +// that the parent testrunner aborted or died and makes the server kill +// the child and exit without a response (hence e.g. +// "echo Foo.Bar | v8_unittests --fork-server" produces no output). +int RunForkServer() { + fflush(stdout); + fflush(stderr); + + int ctrl_in_fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0); + int ctrl_out_fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0); + CHECK_GE(ctrl_in_fd, 0); + CHECK_GE(ctrl_out_fd, 0); + + int devnull = open("/dev/null", O_RDWR); + CHECK_GE(devnull, 0); + CHECK_NE(dup2(devnull, STDIN_FILENO), -1); + CHECK_NE(dup2(devnull, STDOUT_FILENO), -1); + close(devnull); + + std::string test_filter; + while (ReadLine(ctrl_in_fd, &test_filter)) { + if (test_filter.empty()) continue; + + int out_pipe[2]; + int err_pipe[2]; + CHECK_EQ(pipe(out_pipe), 0); + CHECK_EQ(pipe(err_pipe), 0); + + pid_t pid = fork(); + CHECK_GE(pid, 0); + if (pid == 0) { + close(ctrl_in_fd); + close(ctrl_out_fd); + close(out_pipe[0]); + close(err_pipe[0]); + CHECK_NE(dup2(out_pipe[1], STDOUT_FILENO), -1); + CHECK_NE(dup2(err_pipe[1], STDERR_FILENO), -1); + close(out_pipe[1]); + close(err_pipe[1]); + + GTEST_FLAG_SET(filter, test_filter); + return RUN_ALL_TESTS(); + } + + close(out_pipe[1]); + close(err_pipe[1]); + + std::string stdout_data; + std::string stderr_data; + bool parent_alive = DrainPipes(ctrl_in_fd, out_pipe[0], err_pipe[0], + &stdout_data, &stderr_data); + close(out_pipe[0]); + close(err_pipe[0]); + + if (!parent_alive) { + if (getpgrp() == getpid()) { + // Under the testrunner, the server is always its own process group + // leader (start_new_session). Kill the whole group, including the + // child, any grandchildren and ourselves. + kill(0, SIGKILL); + } else { + kill(pid, SIGKILL); + while (waitpid(pid, nullptr, 0) < 0 && errno == EINTR) { + } + } + break; + } + + int status = 0; + pid_t waited; + while ((waited = waitpid(pid, &status, 0)) < 0 && errno == EINTR) { + } + + int exit_code = -1; + if (waited == pid) { + if (WIFEXITED(status)) { + exit_code = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + exit_code = -WTERMSIG(status); + } + } + + std::string header = "RES " + std::to_string(exit_code) + " " + + std::to_string(stdout_data.size()) + " " + + std::to_string(stderr_data.size()) + "\n"; + if (!WriteAll(ctrl_out_fd, header.data(), header.size()) || + !WriteAll(ctrl_out_fd, stdout_data.data(), stdout_data.size()) || + !WriteAll(ctrl_out_fd, stderr_data.data(), stderr_data.size())) { + break; + } + } + + close(ctrl_in_fd); + close(ctrl_out_fd); + // The server itself never ran a test, so skip static destructors and + // sanitizer exit hooks (e.g. LSan). Children return from RUN_ALL_TESTS(). + _exit(0); +} + +#endif // V8_SUPPORTS_FORK_SERVER + } // namespace @@ -54,6 +256,9 @@ int main(int argc, char** argv) { ::LoadLibraryW(L"dbghelp.dll"); ::LoadLibraryW(L"msdia140.dll"); #endif + // Strip --fork-server before InitGoogleMock records argv for death tests. + bool use_fork_server = ExtractForkServerFlag(&argc, argv); + // Don't catch SEH exceptions and continue as the following tests might hang // in an broken environment on windows. GTEST_FLAG_SET(catch_exceptions, false); @@ -77,5 +282,13 @@ int main(int argc, char** argv) { fuzztest::InitFuzzTest(&argc, &argv); #endif // V8_ENABLE_FUZZTEST + if (use_fork_server) { +#ifdef V8_SUPPORTS_FORK_SERVER + return RunForkServer(); +#else + FATAL("--fork-server is not supported on this build"); +#endif // V8_SUPPORTS_FORK_SERVER + } + return RUN_ALL_TESTS(); } diff --git a/deps/v8/test/unittests/sandbox/bytecode-verifier-unittest.cc b/deps/v8/test/unittests/sandbox/bytecode-verifier-unittest.cc index f171c54f3d00..fdce073cc007 100644 --- a/deps/v8/test/unittests/sandbox/bytecode-verifier-unittest.cc +++ b/deps/v8/test/unittests/sandbox/bytecode-verifier-unittest.cc @@ -714,7 +714,7 @@ INSTANTIATE_TEST_SUITE_P(BytecodeVerifierTest, BytecodeVerifierForbiddenRuntimeFunctionTest, ::testing::Values( #if V8_ENABLE_WEBASSEMBLY - Runtime::kTrapHandlerThrowWasmError, + Runtime::kThrowWasmError, Runtime::kWasmAllocateFeedbackVector, #endif Runtime::kLoadLookupSlotForCall_Baseline)); @@ -866,6 +866,156 @@ TEST_F(BytecodeVerifierTest, SpecialRegistersAreNegative) { EXPECT_LT(interpreter::Register::argument_count().index(), 0); } +TEST_F(BytecodeVerifierTest, RegisterListInParameterRegisters) { + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + + Handle<TrustedFixedArray> constant_pool = factory->NewTrustedFixedArray(0); + Handle<TrustedByteArray> handler_table = factory->NewTrustedByteArray(0); + + uint8_t param0_operand = static_cast<uint8_t>( + interpreter::Register::FromParameterIndex(0).ToOperand()); + uint8_t param2_operand = static_cast<uint8_t>( + interpreter::Register::FromParameterIndex(2).ToOperand()); + uint8_t reg0_operand = + static_cast<uint8_t>(interpreter::Register(0).ToOperand()); + uint16_t runtime_id = static_cast<uint16_t>(Runtime::kIsSmi); + + // 1. Output register triple (kForInPrepare) in parameter registers fails. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kForInPrepare), + param2_operand, 0, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Register list cannot use parameter registers"); + } + + // 2. Output register list (kResumeGenerator) in parameter registers fails + // even with count == 1. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kResumeGenerator), + reg0_operand, param0_operand, 1, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Register list cannot use parameter registers"); + } + + // 3. Input register list (kCallRuntime) with count > 1 in parameter registers + // fails. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kCallRuntime), + static_cast<uint8_t>(runtime_id & 0xFF), + static_cast<uint8_t>((runtime_id >> 8) & 0xFF), + param2_operand, + 2, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Register list cannot use parameter registers"); + } + + // 4. Input register list (kCallRuntime) with count == 1 in parameter + // registers succeeds. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kCallRuntime), + static_cast<uint8_t>(runtime_id & 0xFF), + static_cast<uint8_t>((runtime_id >> 8) & 0xFF), + param0_operand, + 1, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + VerifyFull(isolate, bc); + } + + // 5. Empty register list with non-zero start register fails. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kCallRuntime), + static_cast<uint8_t>(runtime_id & 0xFF), + static_cast<uint8_t>((runtime_id >> 8) & 0xFF), + param0_operand, + 0, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Invalid empty register list"); + } +} + +TEST_F(BytecodeVerifierTest, GeneratorRegisterInParameterRegisters) { + Isolate* isolate = i_isolate(); + Factory* factory = isolate->factory(); + + Handle<TrustedFixedArray> constant_pool = factory->NewTrustedFixedArray(1); + constant_pool->set(0, Smi::FromInt(5)); + Handle<TrustedByteArray> handler_table = factory->NewTrustedByteArray(0); + + uint8_t param0_operand = static_cast<uint8_t>( + interpreter::Register::FromParameterIndex(0).ToOperand()); + uint8_t context_operand = static_cast<uint8_t>( + interpreter::Register::current_context().ToOperand()); + uint8_t reg0_operand = + static_cast<uint8_t>(interpreter::Register(0).ToOperand()); + + // 1. kSuspendGenerator with parameter generator register fails. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kSuspendGenerator), + param0_operand, + reg0_operand, + 1, + 0, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Generator register cannot be a parameter"); + } + + // 2. kResumeGenerator with parameter generator register fails. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kResumeGenerator), + context_operand, reg0_operand, 1, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Generator register cannot be a parameter"); + } + + // 3. kSwitchOnGeneratorState with parameter generator register fails. + { + std::vector<uint8_t> kRawBytes = { + static_cast<uint8_t>(interpreter::Bytecode::kSwitchOnGeneratorState), + param0_operand, 0, 1, + static_cast<uint8_t>(interpreter::Bytecode::kReturn)}; + Handle<BytecodeArray> bc = + MakeBytecodeArray(isolate, kRawBytes, constant_pool, handler_table, + /*frame_size=*/32, /*parameter_count=*/3); + ASSERT_DEATH_IF_SUPPORTED(VerifyFull(isolate, bc), + "Generator register cannot be a parameter"); + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/sandbox/code-cache-unittest.cc b/deps/v8/test/unittests/sandbox/code-cache-unittest.cc new file mode 100644 index 000000000000..13c6be3a96e2 --- /dev/null +++ b/deps/v8/test/unittests/sandbox/code-cache-unittest.cc @@ -0,0 +1,296 @@ +// Copyright 2026 the V8 project 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 <algorithm> +#include <memory> +#include <string> +#include <vector> + +#include "include/v8-script.h" +#include "src/base/memory.h" +#include "src/codegen/compilation-cache.h" +#include "src/codegen/external-reference.h" +#include "src/heap/factory-inl.h" +#include "src/objects/bytecode-array.h" +#include "src/objects/code.h" +#include "src/roots/roots.h" +#include "src/snapshot/code-serializer.h" +#include "src/snapshot/serializer-deserializer.h" +#include "src/snapshot/snapshot-source-sink.h" +#include "src/snapshot/snapshot-utils.h" +#include "test/common/flag-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +#ifdef V8_ENABLE_SANDBOX + +namespace v8::internal { + +// In official builds we drop the message in CHECK so we cannot check for it in +// these tests. +#ifdef OFFICIAL_BUILD +#define EXPECTED_CHECK_WITH_MSG(msg) "" +#else +#define EXPECTED_CHECK_WITH_MSG(msg) msg +#endif + +namespace { + +constexpr char kSource[] = "function f() { return 42; }; f();"; + +// Exposes the bytecodes of the serializer. +struct Bytecodes : public SerializerDeserializer { + using SerializerDeserializer::Bytecode; + using enum Bytecode; + using SerializerDeserializer::IsTrustedBytecode; + using SerializerDeserializer::NewObject; +}; + +void SetHeaderValue(std::vector<uint8_t>* data, uint32_t offset, + uint32_t value) { + base::WriteLittleEndianValue<uint32_t>( + reinterpret_cast<Address>(data->data() + offset), value); +} + +uint32_t UntrustedSectionOffset(const std::vector<uint8_t>& data) { + return SerializedCodeData::kHeaderSize + + base::ReadLittleEndianValue<uint32_t>(reinterpret_cast<Address>( + data.data() + SerializedCodeData::kTrustedPayloadLengthOffset)); +} + +// Updates the payload length and the checksum after changing the payload. +void UpdateHeader(std::vector<uint8_t>* data) { + base::Vector<const uint8_t> payload = + base::VectorOf(*data).SubVectorFrom(SerializedCodeData::kHeaderSize); + SetHeaderValue(data, SerializedCodeData::kPayloadLengthOffset, + static_cast<uint32_t>(payload.size())); + SetHeaderValue(data, SerializedCodeData::kChecksumOffset, Checksum(payload)); +} + +// Returns a BytecodeWrapper that refers to the trusted export at |index|, as +// the serializer encodes it. +std::vector<uint8_t> BytecodeWrapperWithExport(uint32_t index) { + SnapshotByteSink object; + object.Put(Bytecodes::NewObject::Encode(SnapshotSpace::kOld), ""); + object.Put(Bytecodes::kRootArray, ""); + object.PutUint30(static_cast<uint32_t>(RootIndex::kBytecodeWrapperMap), ""); + object.Put(Bytecodes::kTrustedPointerPrefix, ""); + object.Put(Bytecodes::kTrustedExportRef, ""); + object.PutUint30(index, ""); + return *object.data(); +} + +} // namespace + +// Corrupted in-sandbox objects must not make the code serializer put arbitrary +// trusted objects or external pointers into the trusted section. +class CodeCacheTrustedSectionTest : public TestWithContext { + protected: + // Compiles kSource. The script name is an in-sandbox object that the code + // serializer visits. + void Compile() { + v8::ScriptOrigin origin(NewString(std::string(256, 'n').c_str())); + v8::ScriptCompiler::Source source(NewString(kSource), origin); + sfi_ = indirect_handle( + Utils::OpenDirectHandle( + *v8::ScriptCompiler::CompileUnboundScript(isolate(), &source) + .ToLocalChecked()), + i_isolate()); + name_ = handle(Cast<HeapObject>(Cast<Script>(sfi_->script())->name()), + i_isolate()); + } + + ScriptCompiler::CachedData* Serialize() { + return CodeSerializer::Serialize(i_isolate(), sfi_); + } + + // Serializes with the script name disguised as an object with |map|. + ScriptCompiler::CachedData* SerializeWithNameMap(Tagged<Map> map) { + name_->set_map_word(map, kRelaxedStore); + return Serialize(); + } + + Handle<SharedFunctionInfo> sfi_; + Handle<HeapObject> name_; +}; + +TEST_F(CodeCacheTrustedSectionTest, InSandboxBaselineCode) { + Compile(); + ASSERT_DEATH_IF_SUPPORTED( + { + name_->WriteField<uint32_t>( + Code::kFlagsOffset, Code::KindField::encode(CodeKind::BASELINE)); + SerializeWithNameMap(ReadOnlyRoots(i_isolate()).code_map()); + }, + EXPECTED_CHECK_WITH_MSG("OutsideSandbox")); +} + +TEST_F(CodeCacheTrustedSectionTest, InSandboxBuiltinCode) { + Compile(); + ASSERT_DEATH_IF_SUPPORTED( + { + name_->WriteField<uint32_t>(Code::kFlagsOffset, + Code::KindField::encode(CodeKind::BUILTIN)); + SerializeWithNameMap(ReadOnlyRoots(i_isolate()).code_map()); + }, + EXPECTED_CHECK_WITH_MSG("OutsideSandbox")); +} + +TEST_F(CodeCacheTrustedSectionTest, InSandboxInterpreterData) { + FlagScope<bool> flag_scope(&v8_flags.interpreted_frames_native_stack, true); + Compile(); + ASSERT_DEATH_IF_SUPPORTED( + SerializeWithNameMap(ReadOnlyRoots(i_isolate()).interpreter_data_map()), + EXPECTED_CHECK_WITH_MSG("OutsideSandbox")); +} + +TEST_F(CodeCacheTrustedSectionTest, InSandboxExposedTrustedObject) { + Compile(); + ASSERT_DEATH_IF_SUPPORTED( + SerializeWithNameMap(ReadOnlyRoots(i_isolate()).bytecode_array_map()), + EXPECTED_CHECK_WITH_MSG("OutsideSandbox")); +} + +// The address of the Foreign is a known external reference, but its tag must +// not be in a code cache. +TEST_F(CodeCacheTrustedSectionTest, NonSerializableExternalPointerTag) { + Compile(); + ASSERT_DEATH_IF_SUPPORTED( + { + Cast<Script>(sfi_->script()) + ->set_name(*i_isolate()->factory()->NewForeign<kGenericForeignTag>( + ExternalReference::isolate_address(i_isolate()).address())); + Serialize(); + }, + EXPECTED_CHECK_WITH_MSG("kSerializableExternalPointerTags")); +} + +// Out-of-bounds indices into the deserializer's vectors are caught by the +// libc++ hardening, which crashes without a message. +class CodeCacheUntrustedSectionTest : public TestWithContext { + protected: + std::vector<uint8_t> ProduceCodeCache() { + i_isolate()->compilation_cache()->DisableScriptAndEval(); + v8::ScriptCompiler::Source source(NewString(kSource)); + std::unique_ptr<v8::ScriptCompiler::CachedData> cache( + v8::ScriptCompiler::CreateCodeCache( + v8::ScriptCompiler::CompileUnboundScript(isolate(), &source) + .ToLocalChecked())); + return std::vector<uint8_t>(cache->data, cache->data + cache->length); + } + + // Returns a code cache for kSource whose untrusted section is replaced by + // |root|. + std::vector<uint8_t> MakeCodeCache(const SnapshotByteSink& root) { + std::vector<uint8_t> data = ProduceCodeCache(); + data.resize(UntrustedSectionOffset(data)); + data.insert(data.end(), root.data()->begin(), root.data()->end()); + // End of the root's deferred objects and of the untrusted section. + data.insert(data.end(), 2, Bytecodes::kSynchronize); + // Padding as added by Serializer::Pad. + data.insert(data.end(), 3, Bytecodes::kNop); + while (!IsAligned(data.size(), kPointerAlignment)) { + data.push_back(Bytecodes::kNop); + } + UpdateHeader(&data); + return data; + } + + void Consume(const std::vector<uint8_t>& data) { + v8::ScriptCompiler::Source source( + NewString(kSource), new v8::ScriptCompiler::CachedData( + data.data(), static_cast<int>(data.size()))); + USE(v8::ScriptCompiler::CompileUnboundScript( + isolate(), &source, v8::ScriptCompiler::kConsumeCodeCache)); + } +}; + +TEST_F(CodeCacheUntrustedSectionTest, RootIndexOutOfBounds) { + SnapshotByteSink untrusted; + untrusted.Put(Bytecodes::kRootArray, ""); + untrusted.PutUint30(RootsTable::kEntriesCount, ""); + std::vector<uint8_t> cache = MakeCodeCache(untrusted); + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), + EXPECTED_CHECK_WITH_MSG("kEntriesCount")); +} + +TEST_F(CodeCacheUntrustedSectionTest, ExternalReferenceIndexOutOfBounds) { + // kSource has no external references. + SnapshotByteSink untrusted; + untrusted.Put(Bytecodes::kTrustedExternalRef, ""); + untrusted.PutUint30(0, ""); + std::vector<uint8_t> cache = MakeCodeCache(untrusted); + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), ""); +} + +TEST_F(CodeCacheUntrustedSectionTest, BackingStoreLongerThanSection) { + SnapshotByteSink untrusted; + untrusted.Put(Bytecodes::kOffHeapBackingStore, ""); + untrusted.PutUint32(1024, ""); + std::vector<uint8_t> cache = MakeCodeCache(untrusted); + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), + EXPECTED_CHECK_WITH_MSG("byte_length")); +} + +TEST_F(CodeCacheUntrustedSectionTest, TrustedExportIndexOutOfBounds) { + std::vector<uint8_t> cache = ProduceCodeCache(); + // The wrapper of the top-level bytecode, which is export 0. + std::vector<uint8_t> wrapper = BytecodeWrapperWithExport(0); + auto it = std::search(cache.begin() + UntrustedSectionOffset(cache), + cache.end(), wrapper.begin(), wrapper.end()); + CHECK(it != cache.end()); + // Out of bounds, and encoded in one byte like 0. + std::vector<uint8_t> out_of_bounds = BytecodeWrapperWithExport(63); + CHECK_EQ(out_of_bounds.size(), wrapper.size()); + std::copy(out_of_bounds.begin(), out_of_bounds.end(), it); + UpdateHeader(&cache); + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), ""); +} + +// Untrusted references are only valid in the trusted section, so there are no +// objects to refer to yet. +TEST_F(CodeCacheUntrustedSectionTest, UntrustedRefInUntrustedSection) { + SnapshotByteSink untrusted; + untrusted.Put(Bytecodes::kUntrustedRef, ""); + untrusted.PutUint30(0, ""); + std::vector<uint8_t> cache = MakeCodeCache(untrusted); + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), ""); +} + +TEST_F(CodeCacheUntrustedSectionTest, DisallowedSpaces) { + std::vector<std::vector<uint8_t>> caches; + for (SnapshotSpace space : {SnapshotSpace::kTrusted, SnapshotSpace::kCode}) { + SnapshotByteSink object; + object.Put(Bytecodes::NewObject::Encode(space), ""); + object.Put(Bytecodes::kRootArray, ""); + object.PutUint30(static_cast<uint32_t>(RootIndex::kFixedArrayMap), ""); + object.PutUint30(2, ""); + caches.push_back(MakeCodeCache(object)); + } + // Allocated in read-only space. + SnapshotByteSink meta_map; + meta_map.Put(Bytecodes::kNewContextlessMetaMap, ""); + meta_map.PutUint30(MAP_TYPE, ""); + caches.push_back(MakeCodeCache(meta_map)); + for (const std::vector<uint8_t>& cache : caches) { + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), + EXPECTED_CHECK_WITH_MSG("AllocationType::kOld")); + } +} + +TEST_F(CodeCacheUntrustedSectionTest, TrustedBytecodes) { + for (int i = 0; i <= kMaxUInt8; i++) { + Bytecodes::Bytecode bytecode = static_cast<Bytecodes::Bytecode>(i); + if (!Bytecodes::IsTrustedBytecode(bytecode)) continue; + SnapshotByteSink untrusted; + untrusted.Put(bytecode, ""); + std::vector<uint8_t> cache = MakeCodeCache(untrusted); + ASSERT_DEATH_IF_SUPPORTED(Consume(cache), + EXPECTED_CHECK_WITH_MSG("InTrustedSection")); + } +} + +} // namespace v8::internal + +#endif // V8_ENABLE_SANDBOX diff --git a/deps/v8/test/unittests/sandbox/generated-code-validator-unittest.cc b/deps/v8/test/unittests/sandbox/generated-code-validator-unittest.cc index 6f726415a5a3..9012c494ddc9 100644 --- a/deps/v8/test/unittests/sandbox/generated-code-validator-unittest.cc +++ b/deps/v8/test/unittests/sandbox/generated-code-validator-unittest.cc @@ -199,6 +199,324 @@ TEST_F(GeneratedCodeValidatorTest, ValidateDecompressionPasses) { CheckValidationSucceeds(i_isolate, masm); } +TEST_F(GeneratedCodeValidatorTest, ValidateControlFlowJumpToInitSucceeds) { + Isolate* i_isolate = this->i_isolate(); + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label init, use_root_reg; +#if V8_TARGET_ARCH_X64 + __ jmp(&init); + + __ bind(&use_root_reg); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); + + __ bind(&init); + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ jmp(&use_root_reg); +#elif V8_TARGET_ARCH_ARM64 + __ B(&init); + + __ Bind(&use_root_reg); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); + + __ Bind(&init); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ B(&use_root_reg); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationSucceeds(i_isolate, masm); +} + +TEST_F(GeneratedCodeValidatorTest, ValidateControlFlowJumpOverInitFails) { + Isolate* i_isolate = this->i_isolate(); + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label skip_init; +#if V8_TARGET_ARCH_X64 + __ jmp(&skip_init); + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ ret(0); + + __ bind(&skip_init); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ B(&skip_init); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ ret(); + + __ Bind(&skip_init); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationFails( + i_isolate, masm, + "Cage base register initialization uses invalid root register"); +} + +TEST_F(GeneratedCodeValidatorTest, + ValidateControlFlowConditionalBranchSeparatePathsSucceeds) { + Isolate* i_isolate = this->i_isolate(); + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label second_path; +#if V8_TARGET_ARCH_X64 + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ j(equal, &second_path); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); + + __ bind(&second_path); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ Cbz(x0, &second_path); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); + + __ Bind(&second_path); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationSucceeds(i_isolate, masm); +} + +TEST_F(GeneratedCodeValidatorTest, ValidateControlFlowMergeStatesSucceeds) { + Isolate* i_isolate = this->i_isolate(); + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label second_path, merge_block; +#if V8_TARGET_ARCH_X64 + __ j(equal, &second_path); + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ jmp(&merge_block); + + __ bind(&second_path); + __ movq_imm64(kRootRegister, + ExternalReference::isolate_root(i_isolate).raw()); + + __ bind(&merge_block); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ B(eq, &second_path); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ B(&merge_block); + + __ Bind(&second_path); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + + __ Bind(&merge_block); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationSucceeds(i_isolate, masm); +} + +TEST_F(GeneratedCodeValidatorTest, ValidateControlFlowMergeStatesFails) { + Isolate* i_isolate = this->i_isolate(); + + // Case 1: One path skips root register initialization before converging at + // `merge_block`. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label merge_block; +#if V8_TARGET_ARCH_X64 + __ j(equal, &merge_block); + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + + __ bind(&merge_block); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ B(eq, &merge_block); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + + __ Bind(&merge_block); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationFails( + i_isolate, masm, + "Cage base register initialization uses invalid root register"); + } + + // Case 2: Root register is valid on the first incoming edge to `merge_block`, + // but invalidated on the second incoming edge. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label merge_block; +#if V8_TARGET_ARCH_X64 + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ j(equal, &merge_block); + __ popq(kRootRegister); + + __ bind(&merge_block); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ B(eq, &merge_block); + __ Ldp(kRootRegister, xzr, MemOperand(sp, 16, PostIndex)); + + __ Bind(&merge_block); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationFails( + i_isolate, masm, + "Cage base register initialization uses invalid root register"); + } + + // Case 3: One path initializes the root register and the other skips it + // before converging at `merge_block`, where re-initializing the root + // register overwrites the valid path. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label merge_block; +#if V8_TARGET_ARCH_X64 + __ j(equal, &merge_block); + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + + __ bind(&merge_block); + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ B(eq, &merge_block); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + + __ Bind(&merge_block); + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + + CheckValidationFails(i_isolate, masm, + "Instruction overwrites a valid root register"); + } +} + +TEST_F(GeneratedCodeValidatorTest, ValidateControlFlowLoop) { + Isolate* i_isolate = this->i_isolate(); + + // Valid loop: state converges at `loop` header and fixed-point terminates. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + Label loop; +#if V8_TARGET_ARCH_X64 + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ bind(&loop); + __ nop(); + __ j(equal, &loop); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ Bind(&loop); + __ nop(); + __ B(eq, &loop); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + CheckValidationSucceeds(i_isolate, masm); + } + + // Invalid loop: back-edge invalidates the root register, which propagates to + // the loop header and then to the loop exit. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + Label loop, loop_exit; +#if V8_TARGET_ARCH_X64 + __ Move(kRootRegister, ExternalReference::isolate_root(i_isolate)); + __ bind(&loop); + __ j(equal, &loop_exit); + __ popq(kRootRegister); + __ jmp(&loop); + + __ bind(&loop_exit); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(0); +#elif V8_TARGET_ARCH_ARM64 + __ Mov(kRootRegister, Operand(ExternalReference::isolate_root(i_isolate))); + __ Bind(&loop); + __ B(eq, &loop_exit); + __ Ldp(kRootRegister, xzr, MemOperand(sp, 16, PostIndex)); + __ B(&loop); + + __ Bind(&loop_exit); + __ LoadRootRelative(kPtrComprCageBaseRegister, + IsolateData::cage_base_offset()); + __ ret(); +#else +#error "Unsupported architecture for GeneratedCodeValidatorTest" +#endif + CheckValidationFails( + i_isolate, masm, + "Cage base register initialization uses invalid root register"); + } +} + #if V8_TARGET_ARCH_ARM64 TEST_F(GeneratedCodeValidatorTest, ValidateCageBaseWritebackFails) { @@ -219,15 +537,115 @@ TEST_F(GeneratedCodeValidatorTest, ValidateCageBaseWritebackFails) { TEST_F(GeneratedCodeValidatorTest, ValidateRootRegisterPartialInitFails) { static_assert(kRootRegister != no_reg); Isolate* i_isolate = this->i_isolate(); - auto buffer = AllocateAssemblerBuffer(); - MacroAssembler masm(i_isolate, CodeObjectRequired{false}, - buffer->CreateView()); + const Address isolate_root = ExternalReference::isolate_root(i_isolate).raw(); - __ Mov(kRootRegister, 0); - __ ret(); + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); - CheckValidationFails(i_isolate, masm, - "Root register initialization interrupted"); + __ movz(kRootRegister, isolate_root & 0xFFFF, 0); + __ ret(); + + CheckValidationFails(i_isolate, masm, + "Root register initialization interrupted"); + } + + // `movk` without a preceding `movz`. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + __ movk(kRootRegister, isolate_root & 0xFFFF, 0); + __ ret(); + + CheckValidationFails(i_isolate, masm, + "Instruction accesses root register at operand 0"); + } + + // `movz` while root register initialization is already in progress. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + __ movz(kRootRegister, isolate_root & 0xFFFF, 0); + __ movz(kRootRegister, (isolate_root >> 16) & 0xFFFF, 16); + __ ret(); + + CheckValidationFails(i_isolate, masm, + "Instruction accesses root register at operand 0"); + } +} + +TEST_F(GeneratedCodeValidatorTest, ValidateRootRegisterPartialInitMergeFails) { + static_assert(kRootRegister != no_reg); + Isolate* i_isolate = this->i_isolate(); + const Address isolate_root = ExternalReference::isolate_root(i_isolate).raw(); + + // Case 1: One incoming path to `merge_block` has partially initialized the + // root register while the other has not started initialization. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + Label merge_block; + __ B(eq, &merge_block); + __ movz(kRootRegister, isolate_root & 0xFFFF, 0); + + __ Bind(&merge_block); + __ ret(); + + CheckValidationFails(i_isolate, masm, + "Root register initialization interrupted"); + } + + // Case 2: Two incoming paths to `merge_block` both partially initialize the + // root register, but set different 16-bit chunks via `movz`, so the root + // register initialization remains incomplete after the remaining `movk` + // instructions. + { + auto buffer = AllocateAssemblerBuffer(); + MacroAssembler masm(i_isolate, CodeObjectRequired{false}, + buffer->CreateView()); + + int first_shift = -1; + int second_shift = -1; + for (int shift = 0; shift < 64; shift += 16) { + uint64_t chunk = (isolate_root >> shift) & 0xFFFF; + if (chunk == 0) continue; + if (first_shift == -1) { + first_shift = shift; + } else if (second_shift == -1) { + second_shift = shift; + break; + } + } + CHECK_NE(first_shift, -1); + CHECK_NE(second_shift, -1); + + Label else_block, merge_block; + __ B(eq, &else_block); + __ movz(kRootRegister, (isolate_root >> first_shift) & 0xFFFF, first_shift); + __ B(&merge_block); + + __ Bind(&else_block); + __ movz(kRootRegister, (isolate_root >> second_shift) & 0xFFFF, + second_shift); + + __ Bind(&merge_block); + for (int shift = 0; shift < 64; shift += 16) { + uint64_t chunk = (isolate_root >> shift) & 0xFFFF; + if (chunk == 0 || shift == first_shift) continue; + __ Movk(kRootRegister, chunk, shift); + } + __ ret(); + + CheckValidationFails(i_isolate, masm, + "Root register initialization interrupted"); + } } TEST_F(GeneratedCodeValidatorTest, ValidateSystemRegisterWrites) { diff --git a/deps/v8/test/unittests/test-utils.h b/deps/v8/test/unittests/test-utils.h index 720e244aae66..4c3a60272aec 100644 --- a/deps/v8/test/unittests/test-utils.h +++ b/deps/v8/test/unittests/test-utils.h @@ -5,6 +5,7 @@ #ifndef V8_UNITTESTS_TEST_UTILS_H_ #define V8_UNITTESTS_TEST_UTILS_H_ +#include <array> #include <memory> #include <vector> @@ -87,7 +88,7 @@ class WithDefaultPlatformMixin : public TMixin { template <typename TMixin> class WithJSSharedMemoryFeatureFlagsMixin : public TMixin { public: - WithJSSharedMemoryFeatureFlagsMixin() { i::v8_flags.harmony_struct = true; } + WithJSSharedMemoryFeatureFlagsMixin() { i::v8_flags.shared_strings = true; } }; template <typename TMixin> @@ -204,9 +205,9 @@ class WithIsolateScopeMixin : public TMixin { } i::DirectHandle<i::String> MakeName(const char* str, int suffix) { - v8::base::EmbeddedVector<char, 128> buffer; + std::array<char, 128> buffer; v8::base::SNPrintF(buffer, "%s%d", str, suffix); - return MakeString(buffer.begin()); + return MakeString(buffer.data()); } i::Handle<i::String> MakeString(const char* str) { @@ -358,7 +359,7 @@ using TestWithContext = // ::testing::Test>>>>; // Use v8::internal::TestJSSharedMemoryWithNativeContext if you are testing -// internals, aka. directly work with Handles and require --harmony-struct +// internals, aka. directly work with Handles and require --shared-strings // feature. // // Using this will FATAL when !V8_CAN_CREATE_SHARED_HEAP_BOOL diff --git a/deps/v8/test/unittests/testcfg.py b/deps/v8/test/unittests/testcfg.py index a0b8dfff7d19..864b4277c420 100644 --- a/deps/v8/test/unittests/testcfg.py +++ b/deps/v8/test/unittests/testcfg.py @@ -3,6 +3,7 @@ # found in the LICENSE file. import base64 +import os from testrunner.local import testsuite from testrunner.objects import testcase @@ -112,6 +113,18 @@ def _get_suite_flags(self): def get_shell(self): return SHELL + @property + def use_fork_server(self): + # Exclude TSan (no thread creation after a multi-threaded fork), Clang + # coverage (default LLVM_PROFILE_FILE without %p is overwritten by forked + # children), per-subtest random seeds (e.g. seed stress) and num_fuzzer + # (per-subtest random flags would only churn the server cache). + v = self.suite.statusfile.variables + env_disabled = os.environ.get('V8_NO_FORK_SERVER', '') not in ('', '0') + return not (self.suite.test_config.no_fork_server or env_disabled or + self._random_seed is not None or v.get('tsan', False) or + v.get('clang_coverage', False) or v.get('num_fuzzer', False)) + def _get_cmd_env(self): # FuzzTest uses this seed when running fuzz tests as normal gtests. # We derive this base64 encoded seed from our random seed. diff --git a/deps/v8/test/unittests/torque/torque-unittest.cc b/deps/v8/test/unittests/torque/torque-unittest.cc index 42e711046f1e..9f7a6980ee5c 100644 --- a/deps/v8/test/unittests/torque/torque-unittest.cc +++ b/deps/v8/test/unittests/torque/torque-unittest.cc @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <fstream> #include <optional> +#include <sstream> +#include "src/common/globals.h" #include "src/torque/torque-compiler.h" #include "src/torque/utils.h" #include "test/unittests/test-utils.h" @@ -42,6 +45,42 @@ namespace torque_internal { } } +namespace torque_internal { + intrinsic %SizeOf<T: type>(): constexpr int31; + macro TimesSizeOf<T: type>(i: intptr): intptr { + return i * %SizeOf<T>(); + } + struct Slice<T: type, Reference: type> { + macro AtIndex(index: intptr): Reference { + return unsafe::NewReference<T>( + this.object, this.offset + TimesSizeOf<T>(index)); + } + const object: HeapObject; + const offset: intptr; + const length: intptr; + } + namespace unsafe { + macro NewReference<T: type>(object: HeapObject, offset: intptr): &T { + return %RawDownCast<&T>(Reference<T>{object: object, offset: offset}); + } + macro NewMutableSlice<T: type>( + object: HeapObject, offset: intptr, length: intptr): MutableSlice<T> { + return %RawDownCast<MutableSlice<T>>( + Slice<T, &T>{object: object, offset: offset, length: length}); + } + macro NewConstSlice<T: type>( + object: HeapObject, offset: intptr, length: intptr): ConstSlice<T> { + return %RawDownCast<ConstSlice<T>>( + Slice<T, const &T>{object: object, offset: offset, length: length}); + } + } + intrinsic %IndexedFieldLength<T: type>(o: T, f: constexpr string): intptr; + intrinsic %FieldSlice<T: type, TSlice: type>(o: T, f: constexpr string): + TSlice; +} +type MutableSlice<T : type> extends torque_internal::Slice<T, &T>; +type ConstSlice<T : type> extends torque_internal::Slice<T, const &T>; + type Tagged generates 'TNode<MaybeObject>' constexpr 'MaybeObject'; type StrongTagged extends Tagged generates 'TNode<Object>' constexpr 'Object'; @@ -108,10 +147,22 @@ struct float64_or_undefined_or_hole { } extern operator '+' macro IntPtrAdd(intptr, intptr): intptr; +extern operator '*' macro IntPtrMul(intptr, intptr): intptr; extern operator '!' macro Word32BinaryNot(bool): bool; extern operator '==' macro Word32Equal(int32, int32): bool; intrinsic %FromConstexpr<To: type, From: type>(b: From): To; +macro Convert<To: type, From: type>(i: From): To; +extern macro SmiUntag(Smi): intptr; +Convert<intptr, Smi>(s: Smi): intptr { + return SmiUntag(s); +} +Convert<intptr, intptr>(i: intptr): intptr { + return i; +} +Convert<intptr, constexpr int31>(i: constexpr int31): intptr { + return %FromConstexpr<intptr>(i); +} intrinsic %RawDownCast<To: type, From: type>(x: From): To; intrinsic %RawConstexprCast<To: type, From: type>(f: From): To; extern macro SmiConstant(constexpr Smi): Smi; @@ -138,6 +189,10 @@ FromConstexpr<intptr, constexpr int31>(i: constexpr int31): intptr { FromConstexpr<intptr, constexpr intptr>(i: constexpr intptr): intptr { return %FromConstexpr<intptr>(i); } +FromConstexpr<intptr, constexpr IntegerLiteral>( + i: constexpr IntegerLiteral): intptr { + return %FromConstexpr<intptr>(i); +} extern macro BoolConstant(constexpr bool): bool; FromConstexpr<bool, constexpr bool>(b: constexpr bool): bool { return BoolConstant(b); @@ -862,6 +917,22 @@ TEST(Torque, CatchFirstHandler) { "catch handler always has to be first, before any label handler")); } +TEST(Torque, OverlappingBitFieldInitializers) { + const std::string source = R"( + extern macro Unsigned(int32): uint32; + bitfield struct S extends uint32 { + a: uint32: 3 bit; + b: uint32: 3 bit at 2; + } + @export + macro Test(a: uint32, b: uint32): S { + return S{a: a, b: b}; + } + )"; + ExpectFailingCompilation(source, + HasSubstr("Overlapping bitfield initializer: b")); +} + TEST(Torque, BitFieldLogicalAnd) { std::string prelude = R"( bitfield struct S extends uint32 { @@ -1018,6 +1089,905 @@ TEST(Torque, BuiltinReturnsNever) { )"); } +namespace { + +// The build configuration every layout JSON carries. The loader checks it +// against TargetArchitecture, which under the test options resolves to +// the host build's sizes. +std::string TestConfig() { + std::stringstream s; + s << R"("config": {"tagged_size": )" << kTaggedSize << R"(, "pointer_size": )" + << kSystemPointerSize << R"(, "external_pointer_size": )" + << kExternalPointerSlotSize << R"(, "cpp_heap_pointer_size": )" + << kCppHeapPointerSlotSize << R"(, "trusted_pointer_size": )" + << kTrustedPointerSize << R"(}, )"; + return s.str(); +} + +// A class with its layout defined in C++, as the layout JSON and the +// loader see it: two tagged fields a and b on top of the prelude's +// HeapObject. +constexpr const char* kTestLayoutClass = R"( + @cppObjectLayoutDefinition + extern class TestLayout extends HeapObject { + a: Smi; + b: Map; + } +)"; + +constexpr const char* kTestLayoutBodyLessClass = R"( + @cppObjectLayoutDefinition + extern class TestLayout extends HeapObject; +)"; + +// The layout JSON record matching kTestLayoutClass, with the variations +// the failure tests need. +std::string TestLayoutJson(int schema_version, size_t offset_b_delta = 0, + const char* type_b = "Map", + const char* type_a = "Smi", + const char* type_override_a = nullptr) { + // What TargetArchitecture::TaggedSize() resolves to under the + // force_32bit_output=false options every test here compiles with. + size_t t = kTaggedSize; + std::stringstream s; + s << R"({"schema_version": )" << schema_version << R"(, )" << TestConfig() + << R"("classes": [{)" + << R"("cpp_name": "v8::internal::TestLayout", )" + << R"("base": "v8::internal::HeapObject", )" + << R"("base_size": )" << t << R"(, "size": )" << 3 * t + << R"(, "alignment": )" << t << R"(, "fields": [)" + << R"({"cpp_name": "a_", "cpp_type": "TaggedMember<Object>", "offset": )" + << t << R"(, "size": )" << t << R"(, "storage": {"kind": "tagged", "arg": )" + << R"({"kind": "name", "name": ")" << type_a << R"("}})"; + if (type_override_a != nullptr) { + s << R"(, "annotations": [{"name": "V8_TQ_TYPE", "arg": ")" + << type_override_a << R"("}])"; + } + s << R"(}, )" + << R"({"cpp_name": "b_", "cpp_type": "TaggedMember<Object>", "offset": )" + << 2 * t + offset_b_delta << R"(, "size": )" << t + << R"(, "storage": {"kind": "tagged", "arg": )" + << R"({"kind": "name", "name": ")" << type_b << R"("}}})" + << R"(]}]})"; + return s.str(); +} + +TorqueCompilerResult TestCompileTorqueWithLayout( + std::string source, const std::string& layout_json, bool use_cpp_layouts, + const char* positions = nullptr) { + // Parallel test runners share TempDir; the test name keys the file. + std::string path = + ::testing::TempDir() + "/torque-unittest-layout-" + + ::testing::UnitTest::GetInstance()->current_test_info()->name() + ".json"; + { + std::ofstream out(path); + out << layout_json; + } + + TorqueCompilerOptions options; + options.output_directory = ""; + options.collect_language_server_data = false; + options.force_assert_statements = false; + options.v8_root = "."; + options.layout_json_path = path; + options.use_cpp_layouts = use_cpp_layouts; + if (positions != nullptr) { + std::string positions_path = path + "-positions.json"; + std::ofstream out(positions_path); + out << positions; + options.layout_positions_path = positions_path; + } + + source = kTestTorquePrelude + source; + return CompileTorque(source, options); +} + +void ExpectSuccessfulLayoutCompilation(const std::string& source, + const std::string& layout_json, + bool use_cpp_layouts) { + TorqueCompilerResult result = + TestCompileTorqueWithLayout(source, layout_json, use_cpp_layouts); + std::vector<std::string> messages; + for (const auto& message : result.messages) { + messages.push_back(message.message); + } + EXPECT_EQ(messages, std::vector<std::string>{}); +} + +void ExpectFailingLayoutCompilation(const std::string& source, + const std::string& layout_json, + bool use_cpp_layouts, + const std::string& expected_substring) { + TorqueCompilerResult result = + TestCompileTorqueWithLayout(source, layout_json, use_cpp_layouts); + ASSERT_FALSE(result.messages.empty()); + EXPECT_THAT(result.messages.front().message, HasSubstr(expected_substring)); +} + +} // namespace + +TEST(TorqueLayoutLoader, VerifierAcceptsMatchingRecord) { + ExpectSuccessfulLayoutCompilation(kTestLayoutClass, TestLayoutJson(1), + /*use_cpp_layouts=*/false); +} + +TEST(TorqueLayoutLoader, VerifierRejectsOffsetMismatch) { + ExpectFailingLayoutCompilation(kTestLayoutClass, + TestLayoutJson(1, /*offset_b_delta=*/4), + /*use_cpp_layouts=*/false, "offset is"); +} + +TEST(TorqueLayoutLoader, SchemaVersionMismatchAborts) { + ExpectFailingLayoutCompilation(kTestLayoutClass, TestLayoutJson(99), + /*use_cpp_layouts=*/false, + "unsupported schema version"); +} + +TEST(TorqueLayoutLoader, RejectsAMismatchedBuildConfiguration) { + // A layout JSON generated for another configuration describes offsets + // this Torque run does not target. While the .tq field blocks exist a + // mismatch also shows up as a field mismatch; once they are gone this + // check is all that catches a stale layout JSON. + std::string layout_json = TestLayoutJson(1); + std::string tagged = R"("tagged_size": )" + std::to_string(kTaggedSize); + size_t pos = layout_json.find(tagged); + ASSERT_NE(pos, std::string::npos); + layout_json.replace(pos, tagged.size(), + R"("tagged_size": )" + std::to_string(kTaggedSize * 2)); + ExpectFailingLayoutCompilation(kTestLayoutClass, layout_json, + /*use_cpp_layouts=*/false, + "does not match this build configuration"); +} + +TEST(TorqueLayoutLoader, RejectsALayoutJsonWithoutAConfig) { + std::string layout_json = TestLayoutJson(1); + size_t start = layout_json.find(R"("config": {)"); + size_t end = layout_json.find(R"("classes")"); + ASSERT_NE(start, std::string::npos); + ASSERT_LT(start, end); + layout_json.erase(start, end - start); + ExpectFailingLayoutCompilation(kTestLayoutClass, layout_json, + /*use_cpp_layouts=*/false, + "missing key \"config\""); +} + +TEST(TorqueLayoutLoader, RecordsWithoutConsumerAreSkipped) { + // No TestLayout class in the source at all; the record is unconsumed. + ExpectSuccessfulLayoutCompilation("", TestLayoutJson(1), + /*use_cpp_layouts=*/false); +} + +TEST(TorqueLayoutLoader, ImporterImportsBodyLessClass) { + // Import builds the fields from the record; the verifier then + // cross-checks the computed layout against the same record. + ExpectSuccessfulLayoutCompilation(kTestLayoutBodyLessClass, TestLayoutJson(1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterRequiresRecordForBodyLessClass) { + ExpectFailingLayoutCompilation( + kTestLayoutBodyLessClass, + (R"({"schema_version": 1, )" + TestConfig() + R"("classes": []})"), + /*use_cpp_layouts=*/true, "has no layout record"); +} + +TEST(TorqueLayoutLoader, ImporterReplacesMatchingTqFieldBlock) { + ExpectSuccessfulLayoutCompilation(kTestLayoutClass, TestLayoutJson(1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ClassTemplateArgumentIsTypedByItsBase) { + // A class template in the layout JSON maps to the base class of its + // instantiations, since Torque has no generic class types. + constexpr const char* kSource = R"( + extern class CppGCManagedBase extends HeapObject; + @cppObjectLayoutDefinition + extern class TestLayout extends HeapObject { + a: Smi; + b: CppGCManagedBase; + } + )"; + ExpectSuccessfulLayoutCompilation( + kSource, TestLayoutJson(1, 0, /*type_b=*/"CppGCManaged"), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterRejectsMismatchedTqFieldBlock) { + // The record has b: Smi, the .tq field block b: Map. The strict + // comparison must fail rather than silently replace the block. + ExpectFailingLayoutCompilation( + kTestLayoutClass, TestLayoutJson(1, 0, /*type_b=*/"Smi"), + /*use_cpp_layouts=*/true, "differs from C++ field"); +} + +TEST(TorqueLayoutLoader, ImporterReportsEveryMismatchedField) { + // Both fields differ; the comparison reports each one instead of + // stopping at the first. + TorqueCompilerResult result = TestCompileTorqueWithLayout( + kTestLayoutClass, + TestLayoutJson(1, /*offset_b_delta=*/0, /*type_b=*/"Smi", + /*type_a=*/"HeapObject"), + /*use_cpp_layouts=*/true); + std::vector<std::string> mismatches; + for (const auto& message : result.messages) { + if (message.message.find("differs from C++ field") != std::string::npos) { + mismatches.push_back(message.message); + } + } + ASSERT_EQ(mismatches.size(), 2u); + EXPECT_THAT(mismatches[0], HasSubstr("a: Smi")); + EXPECT_THAT(mismatches[0], HasSubstr("a: HeapObject")); + EXPECT_THAT(mismatches[1], HasSubstr("b: Map")); + EXPECT_THAT(mismatches[1], HasSubstr("b: Smi")); +} + +namespace { + +// The tail exercises the flexible-array path of the verifier and the +// importer; the length field indexes it. +constexpr const char* kTestLayoutTailClass = R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject { + const length: Smi; + bytes[length]: uint8; + } +)"; + +constexpr const char* kTestLayoutTailBodyLessClass = R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject; +)"; + +std::string TestTailJson(const char* length_field = "length", + bool no_tail = false) { + size_t t = kTaggedSize; + std::stringstream s; + s << R"({"schema_version": 1, )" << TestConfig() << R"("classes": [{)" + << R"("cpp_name": "v8::internal::TestBlob", )" + << R"("base": "v8::internal::HeapObject", )" + << R"("base_size": )" << t << R"(, "size": )" << 2 * t + << R"(, "alignment": )" << t << R"(, "fields": [)" + << R"({"cpp_name": "length_", "cpp_type": "TaggedMember<Smi>", "offset": )" + << t << R"(, "size": )" << t << R"(, "storage": {"kind": "tagged", "arg": )" + << R"({"kind": "name", "name": "Smi"}}, )" + << R"("annotations": [{"name": "V8_TQ_CONST"}]}], )" + << R"("tail": {"cpp_name": "flexible_array_member_data_", )" + << R"("cpp_element_type": "uint8_t", )" + << R"("offset": )" << 2 * t << R"(, "element_size": 1, )" + << R"("element_storage": {"kind": "int", "width": 1, "signed": false}, )" + << R"("annotations": [{"name": "V8_TQ_NAME", "arg": "bytes"}]}, )" + << R"("annotations": [)"; + if (length_field != nullptr) { + s << R"({"name": "V8_TQ_TAIL_LENGTH", "arg": ")" << length_field << R"("})"; + } + if (no_tail) { + if (length_field != nullptr) s << ", "; + s << R"({"name": "V8_TQ_NO_TAIL"})"; + } + s << "]}]}"; + return s.str(); +} + +// A named-constant array extent cannot be folded into a static class +// size; the record carries both the numeric extent and the Torque +// constant name. +constexpr const char* kTestLayoutNamedExtentClass = R"( + const kTestExtent: constexpr int31 generates '2'; + @cppObjectLayoutDefinition + extern class TestExtent extends HeapObject { + a[kTestExtent]: Smi; + } +)"; + +std::string TestNamedExtentJson() { + size_t t = kTaggedSize; + std::stringstream s; + s << R"({"schema_version": 1, )" << TestConfig() << R"("classes": [{)" + << R"("cpp_name": "v8::internal::TestExtent", )" + << R"("base": "v8::internal::HeapObject", )" + << R"("base_size": )" << t << R"(, "size": )" << 3 * t + << R"(, "alignment": )" << t << R"(, "fields": [)" + << R"({"cpp_name": "a_", "cpp_type": "TaggedMember<Object>", "offset": )" + << t << R"(, "size": )" << 2 * t + << R"(, "storage": {"kind": "tagged", "arg": )" + << R"({"kind": "name", "name": "Smi"}}, "array_extent": 2, )" + << R"("annotations": [{"name": "V8_TQ_EXTENT_NAME", )" + << R"("arg": "kTestExtent"}]}]}]})"; + return s.str(); +} + +// kTestLayoutClass with field a declared as the override target. +constexpr const char* kTestLayoutOverrideClass = R"( + @cppObjectLayoutDefinition + extern class TestLayout extends HeapObject { + a: SmiTagged<uint31>; + b: Map; + } +)"; + +// One scalar field on top of HeapObject. The storage record is the +// only input the Torque type is derived from, so declaring the class +// with the expected type turns the strict comparison into an assertion +// on the derivation. +std::string TestScalarClass(const std::string& field) { + // "T" names a field called value of type T; "n: T" names it n. + std::string spelled = + field.find(':') == std::string::npos ? "value: " + field : field; + return "@cppObjectLayoutDefinition\nextern class TestScalar extends " + "HeapObject {\n " + + spelled + ";\n}\n"; +} + +std::string TestScalarJson(const std::string& storage, size_t size, + const char* annotations = nullptr) { + size_t t = kTaggedSize; + std::stringstream s; + s << R"({"schema_version": 1, )" << TestConfig() << R"("classes": [{)" + << R"("cpp_name": "v8::internal::TestScalar", )" + << R"("base": "v8::internal::HeapObject", )" + << R"("base_size": )" << t << R"(, "size": )" << t + size + << R"(, "alignment": )" << t << R"(, "fields": [)" + << R"({"cpp_name": "value_", "offset": )" << t << R"(, "size": )" << size + << R"(, "storage": )" << storage; + if (annotations != nullptr) s << R"(, "annotations": )" << annotations; + s << R"(}]}]})"; + return s.str(); +} + +// A "bitfield" storage named Test::BitFields; by default one bit followed by a +// three-bit field. +std::string TestBitFieldStorage( + const std::string& bits = R"({"cpp_name": "IsFooBit", "type": "bool", )" + R"("offset": 0, "num_bits": 1}, )" + R"({"cpp_name": "BarBits", "type": "uint8_t", )" + R"("offset": 1, "num_bits": 3})") { + return R"({"kind": "bitfield", "name": "Test::BitFields", "width": 1, )" + R"("bits": [)" + + bits + R"(]})"; +} + +// The positions JSON for kTestLayoutClass and its variants. +constexpr const char* kTestLayoutPositions = R"({"schema_version": 1, + "classes": [{"cpp_name": "v8::internal::TestLayout", + "position": "src/objects/test-layout.h:10:1", + "members": {"a_": "src/objects/test-layout.h:11:3", + "b_": "src/objects/test-layout.h:12:3"}}]})"; + +} // namespace + +// The same layout, with the class omitting its tail (V8_TQ_NO_TAIL) +// instead of indexing it: only the fixed header becomes Torque fields. +std::string TestNoTailJson(bool also_index_the_tail = false) { + return TestTailJson(also_index_the_tail ? "length" : nullptr, + /*no_tail=*/true); +} + +constexpr const char* kTestLayoutNoTailClass = R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject { + const length: Smi; + } +)"; + +// Tail lengths can be expressions over preceding fields. +constexpr const char* kTestLayoutExpressionTailClass = R"( + @cppObjectLayoutDefinition + extern class TestBlob extends HeapObject { + const length: Smi; + bytes[Convert<intptr>(length) * 2]: uint8; + } +)"; + +TEST(TorqueLayoutLoader, ImportsATailWithAnExpressionLength) { + ExpectSuccessfulLayoutCompilation(kTestLayoutExpressionTailClass, + TestTailJson("Convert<intptr>(length) * 2"), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImportsABodyLessTailWithAnExpressionLength) { + ExpectSuccessfulLayoutCompilation(kTestLayoutTailBodyLessClass, + TestTailJson("Convert<intptr>(length) * 2"), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, RejectsAComplexExtentThatDiffers) { + // A compound extent must compare on its structure. Mapping every + // unsupported expression to one placeholder would let these two match. + ExpectFailingLayoutCompilation(kTestLayoutExpressionTailClass, + TestTailJson("Convert<intptr>(length) * 4"), + /*use_cpp_layouts=*/true, + "(Convert<intptr>(length) * 4)"); +} + +TEST(TorqueLayoutLoader, VerifierRejectsAComplexExtentThatDiffers) { + ExpectFailingLayoutCompilation(kTestLayoutExpressionTailClass, + TestTailJson("Convert<intptr>(length) * 4"), + /*use_cpp_layouts=*/false, + "Torque uses a different index expression"); +} + +TEST(TorqueLayoutLoader, RejectsAMalformedTailLength) { + ExpectFailingLayoutCompilation(kTestLayoutTailClass, TestTailJson("length +"), + /*use_cpp_layouts=*/true, + "unexpected end of input"); +} + +TEST(TorqueLayoutLoader, ImportsFixedHeaderWithNoTail) { + // V8_TQ_NO_TAIL: the C++ class has a flexible array member Torque + // does not model, so the fields stop at the fixed header. + ExpectSuccessfulLayoutCompilation(kTestLayoutNoTailClass, TestNoTailJson(), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, RejectsATailThatIsBothIndexedAndOmitted) { + ExpectFailingLayoutCompilation( + kTestLayoutNoTailClass, TestNoTailJson(/*also_index_the_tail=*/true), + /*use_cpp_layouts=*/true, + "V8_TQ_TAIL_LENGTH and V8_TQ_NO_TAIL are exclusive"); +} + +TEST(TorqueLayoutLoader, OmittedTailStillRejectsAnIndexedField) { + // The tail contributes no field, so a Torque class that does declare + // one no longer matches the record. + ExpectFailingLayoutCompilation(kTestLayoutTailClass, TestNoTailJson(), + /*use_cpp_layouts=*/true, + ".tq declares 2 field(s), C++ 1"); +} + +TEST(TorqueLayoutLoader, VerifierAcceptsTailedRecord) { + ExpectSuccessfulLayoutCompilation(kTestLayoutTailClass, TestTailJson(), + /*use_cpp_layouts=*/false); +} + +TEST(TorqueLayoutLoader, VerifierRejectsTailIndexMismatch) { + ExpectFailingLayoutCompilation(kTestLayoutTailClass, TestTailJson("other"), + /*use_cpp_layouts=*/false, "indexed by"); +} + +TEST(TorqueLayoutLoader, ImporterImportsTailedBodyLessClass) { + // Import builds the indexed field from the tail record; the + // verifier then cross-checks element size, index, and header size. + ExpectSuccessfulLayoutCompilation(kTestLayoutTailBodyLessClass, + TestTailJson(), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterAppliesTypeOverride) { + // The type derived from the record's storage is Smi; only the + // V8_TQ_TYPE override makes the strict comparison pass. + ExpectSuccessfulLayoutCompilation( + kTestLayoutOverrideClass, + TestLayoutJson(1, 0, "Map", "Smi", + /*type_override_a=*/"SmiTagged<uint31>"), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterRejectsMalformedTypeOverride) { + // The grammar reports the parse failure itself; with the positions + // JSON the error points at the annotation's C++ header. + TorqueCompilerResult result = TestCompileTorqueWithLayout( + kTestLayoutOverrideClass, + TestLayoutJson(1, 0, "Map", "Smi", /*type_override_a=*/"Smi |"), + /*use_cpp_layouts=*/true, kTestLayoutPositions); + ASSERT_FALSE(result.messages.empty()); + const TorqueMessage& message = result.messages.front(); + EXPECT_THAT(message.message, HasSubstr("unexpected end of input")); + ASSERT_TRUE(message.position.has_value()); + SourceFileMap::Scope source_map_scope(*result.source_file_map); + EXPECT_EQ(SourceFileMap::PathFromV8Root(message.position->source), + "src/objects/test-layout.h"); +} + +TEST(TorqueLayoutLoader, ImporterFallsBackToClassPosition) { + // Without the positions JSON the same error points at the .tq class + // declaration. + TorqueCompilerResult result = TestCompileTorqueWithLayout( + kTestLayoutOverrideClass, + TestLayoutJson(1, 0, "Map", "Smi", /*type_override_a=*/"Smi |"), + /*use_cpp_layouts=*/true); + ASSERT_FALSE(result.messages.empty()); + const TorqueMessage& message = result.messages.front(); + EXPECT_THAT(message.message, HasSubstr("unexpected end of input")); + ASSERT_TRUE(message.position.has_value()); + SourceFileMap::Scope source_map_scope(*result.source_file_map); + EXPECT_THAT(SourceFileMap::PathFromV8Root(message.position->source), + ::testing::EndsWith(".tq")); +} + +TEST(TorqueLayoutLoader, DerivesIntTypeFromWidthAndSign) { + ExpectSuccessfulLayoutCompilation( + TestScalarClass("uint32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": false})", 4), + /*use_cpp_layouts=*/true); + ExpectSuccessfulLayoutCompilation( + TestScalarClass("int32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": true})", 4), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, DerivesPointerWidthAliasAsUintptr) { + // A member written through uintptr_t: the layout JSON names the C++ + // alias, and the loader maps it to a Torque type. The width alone + // would give uint64 here and uint32 on a 32-bit target. + ExpectSuccessfulLayoutCompilation( + TestScalarClass("uintptr"), + TestScalarJson( + R"({"kind": "int", "width": )" + std::to_string(kSystemPointerSize) + + R"(, "signed": false, "pointer_width_alias": "uintptr_t"})", + kSystemPointerSize), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, PointerSizedIntIsNotItsFixedWidthType) { + // The same storage without the alias would derive uint64, so + // declaring uint64 must be rejected. + ExpectFailingLayoutCompilation( + TestScalarClass("uint64"), + TestScalarJson( + R"({"kind": "int", "width": )" + std::to_string(kSystemPointerSize) + + R"(, "signed": false, "pointer_width_alias": "uintptr_t"})", + kSystemPointerSize), + /*use_cpp_layouts=*/true, "differs from C++ field"); +} + +TEST(TorqueLayoutLoader, DerivesVoidForZeroSizedField) { + // The zero-length-array padding idiom. + ExpectSuccessfulLayoutCompilation( + TestScalarClass("void"), + TestScalarJson(R"({"kind": "int", "width": 1, "signed": true})", 0), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, DerivesNamedTypeForEnumStorage) { + ExpectSuccessfulLayoutCompilation( + TestScalarClass("uint8"), + TestScalarJson( + R"({"kind": "enum", "name": "uint8", "width": 1, "signed": false})", + 1), + /*use_cpp_layouts=*/true); +} + +// A .tq declaration matching TestBitFieldStorage(), with a configurable +// second field. +std::string TestBitFieldStruct(const std::string& bar = "bar: uint8: 3 bit;") { + return R"( + @cppScope('TestScalar::Bits') + bitfield struct TestBitFields extends uint8 { + is_foo: bool: 1 bit; + )" + bar + + R"( + } +)"; +} + +TEST(TorqueLayoutLoader, ImporterDeclaresBitFieldStructFromRecord) { + ExpectSuccessfulLayoutCompilation(TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterReplacesMatchingBitFieldStruct) { + ExpectSuccessfulLayoutCompilation( + TestBitFieldStruct() + TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterRejectsMismatchedBitFieldStruct) { + ExpectFailingLayoutCompilation( + TestBitFieldStruct("bar: uint8: 2 bit;") + + TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/true, + ".tq field \"bar: uint8: 2 bit at 1\" differs from C++ field " + "\"bar: uint8: 3 bit at 1\""); +} + +TEST(TorqueLayoutLoader, VerifierAcceptsMatchingBitFieldStruct) { + ExpectSuccessfulLayoutCompilation( + TestBitFieldStruct() + TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/false); +} + +TEST(TorqueLayoutLoader, VerifierRejectsBitFieldCountMismatch) { + ExpectFailingLayoutCompilation( + TestBitFieldStruct("") + TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/false, "C++ declares 2 bit field(s), Torque has 1"); +} + +TEST(TorqueLayoutLoader, VerifierRejectsBitFieldNameMismatch) { + ExpectFailingLayoutCompilation(TestBitFieldStruct("baz: uint8: 3 bit;") + + TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/false, + "C++ bit field 1 is bar, Torque declares baz"); +} + +TEST(TorqueLayoutLoader, VerifierRejectsBitFieldWidthMismatch) { + ExpectFailingLayoutCompilation(TestBitFieldStruct("bar: uint8: 2 bit;") + + TestScalarClass("TestBitFields"), + TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/false, + "3 bit(s) at 1 in C++, 2 at 1 in Torque"); +} + +TEST(TorqueLayoutLoader, VerifierRejectsNonBitFieldTorqueType) { + // Same size and category, but the Torque field is a plain integer. + ExpectFailingLayoutCompilation( + TestScalarClass("uint8"), TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/false, "a bit field group in C++, uint8 in Torque"); +} + +TEST(TorqueLayoutLoader, VerifierRejectsBitFieldStructNameMismatch) { + // The Torque struct is not named after the C++ group (MapBits1 for + // Map::Bits1). + std::string source = TestBitFieldStruct() + TestScalarClass("TestBitFields"); + size_t pos; + while ((pos = source.find("TestBitFields")) != std::string::npos) { + source.replace(pos, std::string("TestBitFields").size(), "OtherBits"); + } + ExpectFailingLayoutCompilation( + source, TestScalarJson(TestBitFieldStorage(), 1), + /*use_cpp_layouts=*/false, + "the C++ bit field group is Test::BitFields, Torque uses OtherBits"); +} + +// The class-scoped enum TestScalar::Mode, named in Torque by dropping the +// "::". +std::string TestModeEnum(const std::string& name = "TestScalarMode") { + return "extern enum " + name + + " extends uint8 constexpr 'TestScalar::Mode' { kA, kB }\n"; +} + +// TestBitFieldStorage() with a bit of type TestScalar::Mode in place of bar. +std::string TestModeBitFieldStorage() { + return TestBitFieldStorage( + R"({"cpp_name": "IsFooBit", "type": "bool", )" + R"("offset": 0, "num_bits": 1}, )" + R"({"cpp_name": "ModeBit", "type": "TestScalar::Mode", )" + R"("offset": 1, "num_bits": 1})"); +} + +TEST(TorqueLayoutLoader, ImporterDerivesClassScopedEnumBitFieldType) { + ExpectSuccessfulLayoutCompilation( + TestModeEnum() + TestScalarClass("TestBitFields"), + TestScalarJson(TestModeBitFieldStorage(), 1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterReplacesBitFieldStructWithClassScopedEnum) { + ExpectSuccessfulLayoutCompilation( + TestModeEnum() + TestBitFieldStruct("mode: TestScalarMode: 1 bit;") + + TestScalarClass("TestBitFields"), + TestScalarJson(TestModeBitFieldStorage(), 1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterRejectsEnumNotNamedAfterCppType) { + ExpectFailingLayoutCompilation( + TestModeEnum("TestMode") + TestScalarClass("TestBitFields"), + TestScalarJson(TestModeBitFieldStorage(), 1), + /*use_cpp_layouts=*/true, "cannot find \"TestScalarMode\""); +} + +TEST(TorqueLayoutLoader, AcceptsBitFieldNamedType) { + for (bool use_cpp_layouts : {true, false}) { + ExpectSuccessfulLayoutCompilation( + TestBitFieldStruct("type: uint8: 3 bit;") + + TestScalarClass("TestBitFields"), + TestScalarJson( + TestBitFieldStorage(R"({"cpp_name": "IsFooBit", "type": "bool", )" + R"("offset": 0, "num_bits": 1}, )" + R"({"cpp_name": "TypeBits", )" + R"("type": "uint8_t", )" + R"("offset": 1, "num_bits": 3})"), + 1), + use_cpp_layouts); + } +} + +TEST(TorqueLayoutLoader, ImporterDeclaresBitFieldStructFromCppOnlyBase) { + // TestBase has no Torque declaration. Import its fields into TestScalar, + // including the bitfield struct used by value_. + size_t t = kTaggedSize; + std::stringstream json; + json << R"({"schema_version": 1, )" << TestConfig() << R"("classes": [)" + << R"({"cpp_name": "v8::internal::TestBase", )" + << R"("base": "v8::internal::HeapObject", "base_size": )" << t + << R"(, "size": )" << t + 1 << R"(, "alignment": )" << t + << R"(, "fields": [{"cpp_name": "value_", "offset": )" << t + << R"(, "size": 1, "storage": )" << TestBitFieldStorage() << R"(}]}, )" + << R"({"cpp_name": "v8::internal::TestScalar", )" + << R"("base": "v8::internal::TestBase", "base_size": )" << t + 1 + << R"(, "size": )" << t + 2 << R"(, "alignment": )" << t + << R"(, "fields": [{"cpp_name": "other_", "offset": )" << t + 1 + << R"(, "size": 1, "storage": {"kind": "int", "width": 1, )" + << R"("signed": false}}]}]})"; + ExpectSuccessfulLayoutCompilation( + R"( + @cppObjectLayoutDefinition + extern class TestScalar extends HeapObject { + value: TestBitFields; + other: uint8; + } +)", + json.str(), /*use_cpp_layouts=*/true); +} + +std::string TestSmiBitFieldStorage() { + return R"({"kind": "smi_bitfield", "name": "TestFlags", "bits": [)" + R"({"cpp_name": "IsFooBit", "type": "bool", )" + R"("offset": 0, "num_bits": 1}, )" + R"({"cpp_name": "CountBits", "type": "uint32_t", )" + R"("offset": 1, "num_bits": 30}]})"; +} + +std::string TestSmiBitFieldStruct( + const std::string& count = "count: uint32: 30 bit;") { + return R"( + @cppScope('TestScalar::Flags') + bitfield struct TestFlags extends uint31 { + is_foo: bool: 1 bit; + )" + count + + R"( + } +)"; +} + +TEST(TorqueLayoutLoader, ImporterDeclaresSmiBitFieldStructFromRecord) { + ExpectSuccessfulLayoutCompilation( + TestScalarClass("SmiTagged<TestFlags>"), + TestScalarJson(TestSmiBitFieldStorage(), kTaggedSize), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterReplacesMatchingSmiBitFieldStruct) { + ExpectSuccessfulLayoutCompilation( + TestSmiBitFieldStruct() + TestScalarClass("SmiTagged<TestFlags>"), + TestScalarJson(TestSmiBitFieldStorage(), kTaggedSize), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterRejectsSmiBitFieldStructWithWrongParent) { + std::string source = TestSmiBitFieldStruct(); + size_t pos = source.find("uint31"); + CHECK_NE(pos, std::string::npos); + source.replace(pos, 6, "uint32"); + ExpectFailingLayoutCompilation( + source + TestScalarClass("SmiTagged<TestFlags>"), + TestScalarJson(TestSmiBitFieldStorage(), kTaggedSize), + /*use_cpp_layouts=*/true, ".tq extends uint32, C++ uint31"); +} + +TEST(TorqueLayoutLoader, VerifierAcceptsMatchingSmiBitFieldStruct) { + ExpectSuccessfulLayoutCompilation( + TestSmiBitFieldStruct() + TestScalarClass("SmiTagged<TestFlags>"), + TestScalarJson(TestSmiBitFieldStorage(), kTaggedSize), + /*use_cpp_layouts=*/false); +} + +TEST(TorqueLayoutLoader, VerifierRejectsSmiBitFieldWidthMismatch) { + ExpectFailingLayoutCompilation( + TestSmiBitFieldStruct("count: uint32: 29 bit;") + + TestScalarClass("SmiTagged<TestFlags>"), + TestScalarJson(TestSmiBitFieldStorage(), kTaggedSize), + /*use_cpp_layouts=*/false, "30 bit(s) at 1 in C++, 29 at 1 in Torque"); +} + +TEST(TorqueLayoutLoader, VerifierRejectsSmiBitFieldWithoutSmiTagged) { + ExpectFailingLayoutCompilation( + TestSmiBitFieldStruct() + TestScalarClass("Smi"), + TestScalarJson(TestSmiBitFieldStorage(), kTaggedSize), + /*use_cpp_layouts=*/false, + "a bit field group in a Smi in C++, Smi in Torque"); +} + +TEST(TorqueLayoutLoader, AcceptsBitFieldGap) { + ExpectSuccessfulLayoutCompilation( + TestScalarClass("TestBitFields"), + TestScalarJson( + TestBitFieldStorage(R"({"cpp_name": "IsFooBit", "type": "bool", )" + R"("offset": 0, "num_bits": 1}, )" + R"({"cpp_name": "BarBits", "type": "uint8_t", )" + R"("offset": 2, "num_bits": 3})"), + 1), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, RejectsBitFieldNameThatDoesNotRoundTrip) { + // The C++ alias name must be one Torque's naming rule can produce. + ExpectFailingLayoutCompilation( + TestScalarClass("TestBitFields"), + TestScalarJson( + TestBitFieldStorage(R"({"cpp_name": "isFooBit", "type": "bool", )" + R"("offset": 0, "num_bits": 1})"), + 1), + /*use_cpp_layouts=*/true, "cannot be derived from a Torque field name"); +} + +TEST(TorqueLayoutLoader, RejectsBitFieldNameWithoutTheExpectedSuffix) { + // "Bits" suffix on a single bit. + ExpectFailingLayoutCompilation( + TestScalarClass("TestBitFields"), + TestScalarJson( + TestBitFieldStorage(R"({"cpp_name": "IsFooBits", "type": "bool", )" + R"("offset": 0, "num_bits": 1})"), + 1), + /*use_cpp_layouts=*/true, "does not end in \"Bit\""); +} + +TEST(TorqueLayoutLoader, DerivesWrappedPointerTypes) { + ExpectSuccessfulLayoutCompilation( + TestScalarClass("ExternalPointer"), + TestScalarJson(R"({"kind": "external_pointer", "tag": "kTestTag"})", + kExternalPointerSlotSize), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, RejectsUnknownStorageKind) { + ExpectFailingLayoutCompilation( + TestScalarClass("uint32"), TestScalarJson(R"({"kind": "quantum"})", 4), + /*use_cpp_layouts=*/true, "unknown storage kind"); +} + +TEST(TorqueLayoutLoader, RejectsUnknownAnnotation) { + ExpectFailingLayoutCompilation( + TestScalarClass("uint32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": false})", 4, + R"([{"name": "V8_TQ_BOGUS"}])"), + /*use_cpp_layouts=*/true, "unknown annotation V8_TQ_BOGUS"); +} + +TEST(TorqueLayoutLoader, RejectsAnnotationWithWrongArity) { + ExpectFailingLayoutCompilation( + TestScalarClass("uint32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": false})", 4, + R"([{"name": "V8_TQ_CONST", "arg": "x"}])"), + /*use_cpp_layouts=*/true, "V8_TQ_CONST takes no argument"); + ExpectFailingLayoutCompilation( + TestScalarClass("uint32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": false})", 4, + R"([{"name": "V8_TQ_NAME"}])"), + /*use_cpp_layouts=*/true, "V8_TQ_NAME needs an argument"); +} + +TEST(TorqueLayoutLoader, RejectsAnnotationOnTheWrongDeclaration) { + // Tail length annotations belong on the class, not on a field. + ExpectFailingLayoutCompilation( + TestScalarClass("uint32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": false})", 4, + R"([{"name": "V8_TQ_TAIL_LENGTH", "arg": "length"}])"), + /*use_cpp_layouts=*/true, "V8_TQ_TAIL_LENGTH is not allowed here"); +} + +TEST(TorqueLayoutLoader, RejectsConflictingSynchronizationAnnotations) { + ExpectFailingLayoutCompilation( + TestScalarClass("uint32"), + TestScalarJson( + R"({"kind": "int", "width": 4, "signed": false})", 4, + R"([{"name": "V8_TQ_RELAXED"}, {"name": "V8_TQ_ACQ_REL"}])"), + /*use_cpp_layouts=*/true, "on the same member"); +} + +TEST(TorqueLayoutLoader, AppliesFieldNameAnnotation) { + ExpectSuccessfulLayoutCompilation( + TestScalarClass("renamed: uint32"), + TestScalarJson(R"({"kind": "int", "width": 4, "signed": false})", 4, + R"([{"name": "V8_TQ_NAME", "arg": "renamed"}])"), + /*use_cpp_layouts=*/true); +} + +TEST(TorqueLayoutLoader, ImporterAppliesNamedExtent) { + // The extent expression comes from V8_TQ_EXTENT_NAME through the + // expression parser; the class size stays dynamic in Torque, so the + // verifier checks that the array spans from the header to sizeof. + ExpectSuccessfulLayoutCompilation(kTestLayoutNamedExtentClass, + TestNamedExtentJson(), + /*use_cpp_layouts=*/true); +} + } // namespace torque } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/unittests.status b/deps/v8/test/unittests/unittests.status index f32d348d3fe0..c1443197430c 100644 --- a/deps/v8/test/unittests/unittests.status +++ b/deps/v8/test/unittests/unittests.status @@ -30,11 +30,14 @@ 'ParsingTest.ParserSync': [PASS, NO_VARIANTS], # Slow tests. + 'ConcurrentAllocationUninitializedTest.ConcurrentAllocationInLargeSpace': [PASS, SLOW], 'Mutex.SharedMutexThreadsFuzz': [PASS, SLOW], 'ParsingTest.ObjectRestNegativeTestSlow': [PASS, ['mode == debug', SKIP]], 'SignalAndMutexTest.SignalsPlusSharedMutexes': [PASS, SLOW], + 'TestWithHeapInternals.TestInternalWeakLists': [PASS, SLOW], # Tests that need to run sequentially (e.g. due to memory consumption). + 'JumpTableAssemblerTest.JumpTablePatchingStress': [PASS, HEAVY], 'LogAllTest.LogAll': [PASS, SLOW, HEAVY], 'WasmModuleVerifyTest.NGlobals': [PASS, HEAVY], @@ -60,6 +63,8 @@ ['mode == debug', { 'PersistentHandlesTest.NewPersistentHandleFailsWhenParked': [FAIL], 'PersistentHandlesTest.NewPersistentHandleFailsWhenParkedExplicit': [FAIL], + + 'ConcurrentAllocationUninitializedTest.ConcurrentAllocationWhileMainThreadParksAndUnparks': [PASS, SLOW], }], ############################################################################## @@ -102,6 +107,9 @@ # Apple silicon. See: # https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html 'AssemblerArm64Test.printf_no_preserve': [SKIP], + + # https://crbug.com/42204313 + 'ConcurrentAllocationUninitializedTest.ConcurrentAllocationInOldSpace': [PASS, ['mode == debug', SKIP]], }], # arch == arm64 and system == macos and not simulator_run ############################################################################## @@ -112,8 +120,44 @@ 'ApiWasmTest.WasmStreaming*': [SKIP], 'ApiWasmTest.WasmCompileToWasmModuleObject': [SKIP], 'ApiWasmTest.WasmStreamingCallback': [SKIP], + 'WasmBackingStoreTest.Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree': [SKIP], + 'CompilationCache*': [SKIP], + 'CWasmEntryTest.*': [SKIP], + 'FuzzerStepsTest.*': [SKIP], + 'WasmGCTest.*': [SKIP], + 'GrowMemoryTest.*': [SKIP], + 'JumpTableAssemblerTest.*': [SKIP], + 'LiftoffForFuzzingTest.*': [SKIP], + 'LiftoffInspectionTest.*': [SKIP], + 'RunWasm*': [SKIP], + 'StreamingCompilationTest.*': [SKIP], + 'WasmBreakpointsTest.*': [SKIP], + 'WasmCodegenTest.*': [SKIP], + 'WasmImportWrapperCacheTest.*': [SKIP], + 'WasmMetricsTest.*': [SKIP], + 'WasmSerialization*': [SKIP], + 'WasmSharedEngineTest.*': [SKIP], + 'WasmStackTest.*': [SKIP], + 'WasmTrapPositionTest.*': [SKIP], }], # not has_webassembly or variant == jitless +############################################################################## +['has_wasm_interpreter', { + # Skip tests that require Wasm experimental features not supported by the + # Wasm interpreter. + + # --wasm-memory64 + 'RunWasmMemory64Test.*': [SKIP], + + # --wasm-fp16 + 'RunWasmF16Test.*': [SKIP], + 'RunWasmTest.RunWasmInterpreter_Float32*': [SKIP], + + # --wasm-wide-arithmetic + 'RunWasm64Test.RunWasmInterpreter_I64MulWideS': [SKIP], + 'RunWasm64Test.RunWasmInterpreter_I64MulWideU': [SKIP], +}], # has_wasm_interpreter + ############################################################################## ['system == aix', { # PASE does not support detecting physical memory size @@ -139,11 +183,22 @@ 'AllGolden/BytecodeGeneratorTest.CompilationMatchesExpectation/WideRegisters': [SKIP], }], # arch == ppc64 +['arch == arm64', { + # BUG(v8:3154). + 'HeapTest.ReleaseOverReservedPages': [PASS, FAIL], +}], # arch == arm64 + ############################################################################## -['arch == mips64el', { +['arch == mips64el or arch == mips64', { # TODO(mips-team): mips64 do not allocate odd register in liftoff. 'WasmRegisterTest.SpreadSetBitsToAdjacentFpRegs': [SKIP], -}], # 'arch == mips64' + + # BUG(v8:3154). + 'HeapTest.ReleaseOverReservedPages': [PASS, FAIL], + + # TODO(mips-team): Improve code-size on large RegExp's. + 'HeapTest.TestSizeOfRegExpCode': [SKIP], +}], # 'arch == mips64el or arch == mips64' ############################################################################## ['system == windows and asan', { @@ -180,8 +235,103 @@ # These tests need a lot of memory on TSan. 'ModuleGenerationTest.*': [PASS, HEAVY], + + # Slow tests on TSAN. + 'HeapTest.Regress8014': [SKIP], + + # BUG(v8:8296). The tests allocate a lot of objects and timeout in + # the --stress-concurrent-allocation variant. + 'TestWithPlatform.OutOfMemorySmallObjects': [PASS, NO_VARIANTS], + 'TestWithPlatform.OutOfMemory': [PASS, NO_VARIANTS], + + 'RunWasmTest.RunWasmTurbofan_Float32Add_Consts': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Float32Sub_Consts': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Float32Mul_Consts': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Float32Div_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Add_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Sub_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Mul_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Div_Consts': [SKIP], }], # tsan == True +############################################################################## +['asan or tsan', { + # Tests that need to run sequentially (e.g. due to memory consumption). + 'RunWasmTest.RunWasmLiftoff_I32Binop_Add': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_DivS': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_DivU': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_Eq': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_GeS': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_GeU': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_GtS': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_Ior': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_LeU': [PASS, HEAVY], + 'RunWasmTest.RunWasmLiftoff_I32Binop_LtU': [PASS, HEAVY], + + # Slow tests. + 'RunWasmTest.RunWasmTurbofan_Float32*': [PASS, SLOW], +}], # 'asan or tsan' + +############################################################################## +['ubsan', { + # https://crbug.com/v8/14309 + 'RunWasmSimdTest.RunWasm*': [SKIP], +}], # 'ubsan' + +############################################################################## +['arch == arm and not simulator_run', { + # Fails on ODROID: https://crbug.com/v8/11634 + 'WasmMetricsTest.*': [SKIP], +}], # arch == arm and not simulator_run + +############################################################################## +['variant == nooptimization', { + # Wasm serialization relies on TurboFan to be available, hence does not work + # in the 'nooptimization' variant. + 'WasmSerialization*': [SKIP], + 'StreamingCompilationTest.SingleThreadedTestDeserializationBypassesCompilation': [SKIP], + 'StreamingCompilationTest.SingleThreadedTestDeserializationFails': [SKIP], + 'StreamingCompilationTest.SingleThreadedTestIncrementalCaching': [SKIP], + 'StreamingCompilationTest.AsyncTestDeserializationFails': [SKIP], + 'StreamingCompilationTest.AsyncTestDeserializationBypassesCompilation': [SKIP], + 'StreamingCompilationTest.AsyncTestIncrementalCaching': [SKIP], +}], # variant == nooptimization + +############################################################################## +['arch == mips64', { + # TODO(mips-team): Currently fails on mips64 board. + 'RunWasmTest.RunWasmLiftoff_I32Binop*': [SKIP], +}], # 'arch == mips64' + +############################################################################## +['(arch == mips64el or arch == mips64) and not simd_mips', { + # Skip tests that fail on MIPS architectures which don't support SIMD, + # because lowering mechanism doesn't work properly + 'RunWasmSimdTest.RunWasm_ReductionTest4_compiled': [SKIP], + 'RunWasmSimdTest.RunWasm_ReductionTest8_compiled': [SKIP], + 'RunWasmSimdTest.RunWasm_ReductionTest16_compiled': [SKIP], + 'RunWasmSimdLiftoffTest.*': [SKIP], + 'WasmGCTest.RunWasmLiftoff_RefTrivialCasts': [SKIP], + 'WasmGCTest.RunWasmTurbofan_RefTrivialCasts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Select_s128_parameters': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Select_s128_parameters': [SKIP], +}], # '(arch == mips64el or arch == mips64) and not simd_mips' + +############################################################################## +['system == aix or (arch == ppc64 and byteorder == big)', { + # TODO(ppc): Fix for platforms with function desciptors. + 'RunWasmModuleTest.Run_WasmModule_Return114': [SKIP], + 'RunWasmModuleTest.Run_WasmModule_CallAdd': [SKIP], + 'RunWasmModuleTest.Run_WasmModule_CallMain_recursive': [SKIP], +}], # 'system == aix or (arch == ppc64 and byteorder == big)' + +############################################################################## +['arch == ppc64 or arch == s390x', { + # TODO(ppc/s390): support concurrent patching of jump table + 'JumpTableAssemblerTest.*': [SKIP], + 'WasmBreakpointsTest.*': [SKIP], +}], # 'arch == ppc64 or arch == s390x' + ############################################################################## ['variant == stress_js_bg_compile_wasm_code_gc', { # The test relies on deterministic allocation during compilation. @@ -199,6 +349,15 @@ # BUG(v8:11820): the test adjusts GC flags, which does not work # if GC starts before the test. 'RuntimeCallStatsTest.GarbageCollection': [SKIP], + # Tests time out in stress_incremental_marking. + 'RunWasmTest.RunWasmTurbofan_Float32Add_Consts': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Float32Sub_Consts': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Float32Mul_Consts': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Float32Div_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Add_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Sub_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Mul_Consts': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Float32Div_Consts': [SKIP], }], # variant == stress_incremental_marking ################################################################################ @@ -213,8 +372,21 @@ # f32.{min,max,neg} and friends. 'Float32CrossCompilerDeterminismTest.TestBinOp': [PASS, FAIL], 'Float32CrossCompilerDeterminismTest.TestUnOp': [PASS, FAIL], + + # According to riscv's NaN generation and propagation scheme, the payload + # is not guaranteed. So the test fails when src bits has payload. + 'RunWasmTest.RunWasmLiftoff_F32ReinterpretI32': [SKIP], + 'RunWasmTest.RunWasmTurbofan_F32ReinterpretI32': [SKIP], + + # Some Wasm functionality is not implemented yet. + 'RunWasmF16Test.*': [SKIP], }], # arch == riscv64 or arch == riscv32 +['arch == riscv32', { + # Some Wasm functionality is not implemented yet. + 'RunWasm64Test.*': [SKIP], +}], # 'arch == riscv32' + ['(arch == riscv64 or arch == riscv32) and not clang', { 'LoggingTest.SourceLocation': [SKIP] # issue-174 }], # (arch == riscv64 or arch == riscv32) and not clang @@ -237,15 +409,30 @@ 'LogInterpretedFramesNativeStackWithSerializationTest.LogInterpretedFramesNativeStackWithSerialization': [SKIP], 'InterpreterTest.InterpreterWithNativeStack': [SKIP], + # https://crbug.com/v8/7777 + 'HeapTest.OptimizeAfterBytecodeFlushingCandidate': [SKIP], + # Crashes on native arm. 'MacroAssemblerTest.ExtractLane': [PASS, ['arch == arm and not simulator_run', SKIP]], 'MacroAssemblerTest.ReplaceLane': [PASS, ['arch == arm and not simulator_run', SKIP]], + + 'RunWasmExceptionsTest.RunWasmLiftoff_TryCatchCallDirect': [SKIP], + 'RunWasmExceptionsTest.RunWasmLiftoff_TryCatchCallExternal': [SKIP], + 'RunWasmExceptionsTest.RunWasmLiftoff_TryCatchCallIndirect': [SKIP], + 'RunWasmExceptionsTest.RunWasmLiftoff_TryCatchThrow': [SKIP], + 'RunWasmExceptionsTest.RunWasmLiftoff_TryCatchTrapTypeError': [SKIP], + 'RunWasmExceptionsTest.RunWasmTurbofan_TryCatchCallDirect': [SKIP], + 'RunWasmExceptionsTest.RunWasmTurbofan_TryCatchCallExternal': [SKIP], + 'RunWasmExceptionsTest.RunWasmTurbofan_TryCatchCallIndirect': [SKIP], + 'RunWasmExceptionsTest.RunWasmTurbofan_TryCatchThrow': [SKIP], + 'RunWasmExceptionsTest.RunWasmTurbofan_TryCatchTrapTypeError': [SKIP], }], # jitless ############################################################################## ['has_jitless', { # Feedback collection maintenance is (mostly) disabled. 'FeedbackVectorTest.Vector*': [SKIP], + 'HeapTest.IncrementalMarkingPreservesMonomorphicCallIC': [SKIP], 'InterpreterTest.InterpreterBigIntComparisons': [SKIP], 'InterpreterTest.InterpreterBinaryOpSmiTypeFeedback': [SKIP], 'InterpreterTest.InterpreterUnaryOpFeedback': [SKIP], @@ -269,11 +456,21 @@ ############################################################################## ['lite_mode or variant == jitless', { + # Slow tests. + 'HeapTest.IncrementalMarkingStepMakesBigProgressWithLargeObjects': [SKIP], # Tests that generate code at runtime. 'Assembler*': [SKIP], 'SyncPrimitivesArmTest*': [SKIP], 'CodePagesTest.*': [SKIP], + 'ConcurrentAllocationUninitializedTest.*': [SKIP], + 'HeapTest.CodeLargeObjectSpace': [SKIP], + 'TestWithPlatform.CodeLargeObjectSpace64k': [SKIP], + 'HeapTest.CodeObjectRegistry': [SKIP], + 'HeapTest.FindCodeForInnerPointer': [SKIP], + 'HeapTest.Regress10900': [SKIP], + 'HeapTest.StressHandles': [SKIP], + 'HeapTest.StressJS': [SKIP], 'MacroAssemblerX64Test.EmbeddedObj': [SKIP], 'RegExpTest.AssertionMergingToNode': [SKIP], 'RegExpTest.MacroAssemblernativeAtStart': [SKIP], @@ -297,6 +494,7 @@ 'RunJSObjectsTest.*': [SKIP], 'RunJSOpsTest.*': [SKIP], 'RunTailCallsTest.*': [SKIP], + 'WeakReferencesTest.WeakReferencesBasic': [SKIP], # Tests generated irregexp code. 'RegExpTestWithContext.RegExpInterruptReentrantExecution': [SKIP], @@ -332,8 +530,37 @@ ['no_simd_hardware == True', { 'WasmDisassemblerTest.Simd': [SKIP], 'SimdCrossCompilerDeterminismTest.*': [SKIP], + 'RunWasmRelaxedSimdTest.*': [SKIP], + 'RunWasmSimdLiftoffTest.*': [SKIP], + 'RunWasmSimdTest.*': [SKIP], + 'RunWasmF16Test.*': [SKIP], + 'WasmGCTest.RunWasmLiftoff_RefTrivialCasts': [SKIP], + 'WasmGCTest.RunWasmTurbofan_RefTrivialCasts': [SKIP], + 'WasmGCTest.RunWasmLiftoff_RefTrivialCastsStatic': [SKIP], + 'WasmGCTest.RunWasmTurbofan_RefTrivialCastsStatic': [SKIP], + 'RunWasmTest.RunWasmLiftoff_Select_s128_parameters': [SKIP], + 'RunWasmTest.RunWasmTurbofan_Select_s128_parameters': [SKIP], + 'LiftoffForFuzzingTest.NondeterminismUnopF32x4AllNaN': [SKIP], + 'LiftoffForFuzzingTest.NondeterminismUnopF32x4OneNaN': [SKIP], + 'LiftoffForFuzzingTest.NondeterminismUnopF64x2AllNaN': [SKIP], + 'LiftoffForFuzzingTest.NondeterminismUnopF64x2OneNaN': [SKIP], }], # no_simd_hardware == True +################################################################################ +['variant == stress or variant == wasm_assert_types or variant == instruction_scheduling or variant == stress_instruction_scheduling or variant == turbofan_random_rescheduling', { + # The 'stress' variant (and the other listed variants) sets the '--no-liftoff' + # flag, which means that Wasm compiles directly to TurboFan. This makes the + # cache no longer incremental, and these tests don't make sense. + 'StreamingCompilationTest.AsyncTestIncrementalCaching': [SKIP], + 'StreamingCompilationTest.SingleThreadedTestIncrementalCaching': [SKIP], +}], + +############################################################################## +['variant == conservative_stack_scanning', { + 'RunWasm64Test.RunWasmLiftoff_I64WasmRunner': [SLOW], + 'RunWasm64Test.RunWasmTurbofan_I64WasmRunner': [SLOW], +}], # variant == conservative_stack_scanning + ['tsan and mode == debug', { 'LazyCompileDispatcherTest.CompileLazy2FinishesDispatcherJob': [SKIP], 'LogAllTest.LogAll': [SKIP], @@ -365,9 +592,37 @@ 'LogTimerTest.ConsoleTimeEvents': [SKIP], }], # 'system == android' +['variant == stress_concurrent_inlining', { + # crbug.com/v8/11513: Flakily failing due to the additional compile task. + 'HeapTest.CellsInOptimizedCodeAreWeak': [PASS, FAIL], + 'HeapTest.EnsureAllocationSiteDependentCodesProcessed': [PASS, FAIL], + 'TestWithHeapInternals.LeakNativeContextVia*': [PASS, FAIL], + 'HeapTest.NewSpaceObjectsInOptimizedCode': [PASS, FAIL], + 'HeapTest.ObjectsInEagerlyDeoptimizedCodeAreWeak': [PASS, FAIL], + 'HeapTest.ObjectsInOptimizedCodeAreWeak': [PASS, FAIL], +}], # variant == stress_concurrent_inlining + +['variant == assert_types', { + # Type assertions add strong pointers, breaking these tests. + 'HeapTest.ObjectsInOptimizedCodeAreWeak': [SKIP], + 'HeapTest.ObjectsInEagerlyDeoptimizedCodeAreWeak': [SKIP], + 'HeapTest.NewSpaceObjectsInOptimizedCode': [SKIP], + 'TestWithHeapInternals.LeakNativeContextViaMapKeyed': [SKIP], + 'HeapTest.CellsInOptimizedCodeAreWeak': [SKIP], +}], # variant == assert_types + +['clang_coverage', { + # Slow tests. + 'TestWithPlatform.OutOfMemory': [PASS, SLOW], + 'TestWithPlatform.OutOfMemoryIneffectiveGC': [PASS, SLOW], +}], # 'clang_coverage' + ['clang_coverage and mode == debug', { # Too slow tests. + 'ConcurrentAllocationUninitializedTest.ConcurrentAllocationInLargeSpace': [SKIP], 'LogAllTest.LogAll': [SKIP], + 'HeapTest.Regress8014': [SKIP], + 'TestWithHeapInternals.TestInternalWeakLists': [SKIP], }], # 'clang_coverage and mode == debug' ['device_type == bullhead', { @@ -386,6 +641,10 @@ ############################################################################## ['sandbox_hardware_support', { + # The liftoff-for-fuzzing configuration is currently incompatible with + # sandbox hardware support. See https://crbug.com/431949927. + 'LiftoffForFuzzingTest.*': [SKIP], + # Tests that require the sampler/profiler, which doesn't work on older kernel # versions if hardware sandboxing is active. See https://crbug.com/429173713. 'LogTest.*': [SKIP], @@ -400,12 +659,21 @@ 'LogMapsCodeTest.LogMapsDetailsCode': [SKIP], 'LogFunctionEventsTest.LogFunctionEvents': [SKIP], 'CompilerTest.ProfilerEnabledDuringBackgroundCompile': [SKIP], + 'StreamingCompilationTest.*': [SKIP], + + # Tests that rely on Wasm trap handling, which is similarly not supported on + # older kernel versions. See again https://crbug.com/429173713. + 'RunWasmSimdTest.*': [SKIP], + 'RunWasmRelaxedSimdTest.*': [SKIP], }], ############################################################################## ['full_debug', { # Tests too slow in non-optimized debug mode. + 'ConcurrentAllocationUninitializedTest.ConcurrentAllocationInLargeSpace': [SKIP], 'LogAllTest.LogAll': [SKIP], + 'HeapTest.Regress8014': [SKIP], + 'TestWithHeapInternals.TestInternalWeakLists': [SKIP], }], # 'full_debug' ############################################################################## diff --git a/deps/v8/test/unittests/utils/bit-vector-unittest.cc b/deps/v8/test/unittests/utils/bit-vector-unittest.cc index e5b04557691d..bbe97cd2c56e 100644 --- a/deps/v8/test/unittests/utils/bit-vector-unittest.cc +++ b/deps/v8/test/unittests/utils/bit-vector-unittest.cc @@ -304,5 +304,51 @@ TEST_F(BitVectorTest, MoveAssignLarge) { EXPECT_FALSE(a.Contains(134)); } +TEST_F(BitVectorTest, BoundedAddRemoveAndCopyFrom) { + constexpr int kLength = 250; + for (int start : {0, 1, 7, 31, 32, 63, 64, 65, 127, 128, 190}) { + for (int count : {0, 1, 2, 5, 31, 32, 33, 63, 64, 65, 128, 135}) { + if (start + count > kLength) continue; + + BitVector added(kLength, zone()); + added.Add(start, count); + for (int i = 0; i < kLength; ++i) { + bool expected = (i >= start && i < start + count); + EXPECT_EQ(expected, added.Contains(i)); + } + + BitVector removed(kLength, zone()); + removed.AddAll(); + removed.Remove(start, count); + for (int i = 0; i < kLength; ++i) { + bool expected = (i < start || i >= start + count); + EXPECT_EQ(expected, removed.Contains(i)); + } + + BitVector src(kLength, zone()); + for (int i = 0; i < kLength; ++i) { + if ((i * 7 + 3) % 5 < 2) src.Add(i); + } + + BitVector dst_ones(kLength, zone()); + dst_ones.AddAll(); + dst_ones.CopyFrom(src, start, count); + + BitVector dst_zeros(kLength, zone()); + dst_zeros.CopyFrom(src, start, count); + + for (int i = 0; i < kLength; ++i) { + if (i >= start && i < start + count) { + EXPECT_EQ(src.Contains(i), dst_ones.Contains(i)); + EXPECT_EQ(src.Contains(i), dst_zeros.Contains(i)); + } else { + EXPECT_TRUE(dst_ones.Contains(i)); + EXPECT_FALSE(dst_zeros.Contains(i)); + } + } + } + } +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/utils/sparse-bit-vector-unittest.cc b/deps/v8/test/unittests/utils/sparse-bit-vector-unittest.cc index ae290c03d62c..0fbf2d9a3fc5 100644 --- a/deps/v8/test/unittests/utils/sparse-bit-vector-unittest.cc +++ b/deps/v8/test/unittests/utils/sparse-bit-vector-unittest.cc @@ -93,4 +93,41 @@ TEST_F(SparseBitVectorTest, Remove) { ElementsAre(6000, 8000)); } +TEST_F(SparseBitVectorTest, ReuseEmptySegments) { + SparseBitVector vec(zone()); + vec.Add(1000); + size_t allocated_with_one_segment = zone()->allocation_size(); + EXPECT_GT(allocated_with_one_segment, 0u); + + // Removing bit 1000 leaves an empty segment that should be reused for the + // next out-of-range bits (both higher and lower). + vec.Remove(1000); + vec.Add(2000); + EXPECT_EQ(allocated_with_one_segment, zone()->allocation_size()); + vec.Remove(2000); + vec.Add(500); + EXPECT_EQ(allocated_with_one_segment, zone()->allocation_size()); + EXPECT_THAT(std::vector<int>(vec.begin(), vec.end()), ElementsAre(500)); + + // Allocate a second segment while 500 is still set, then remove 500 and add + // 3000; the empty segment for 500 should be reused for 3000. + vec.Add(2000); + size_t allocated_with_two_segments = zone()->allocation_size(); + EXPECT_GT(allocated_with_two_segments, allocated_with_one_segment); + vec.Remove(500); + vec.Add(3000); + EXPECT_EQ(allocated_with_two_segments, zone()->allocation_size()); + EXPECT_THAT(std::vector<int>(vec.begin(), vec.end()), + ElementsAre(2000, 3000)); + + // If both segments become empty, both are preserved and reused. + vec.Remove(2000); + vec.Remove(3000); + vec.Add(4000); + vec.Add(5000); + EXPECT_EQ(allocated_with_two_segments, zone()->allocation_size()); + EXPECT_THAT(std::vector<int>(vec.begin(), vec.end()), + ElementsAre(4000, 5000)); +} + } // namespace v8::internal diff --git a/deps/v8/test/unittests/utils/utils-unittest.cc b/deps/v8/test/unittests/utils/utils-unittest.cc index a0fab8490254..d6d187f72835 100644 --- a/deps/v8/test/unittests/utils/utils-unittest.cc +++ b/deps/v8/test/unittests/utils/utils-unittest.cc @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/utils/utils.h" + #include <limits> #include "src/base/bounds.h" -#include "src/utils/utils.h" +#include "src/base/unique-array.h" #include "testing/gtest-support.h" namespace v8 { @@ -111,46 +113,36 @@ TYPED_TEST(UtilsTest, SaturateAdd) { } TEST(UtilsTest, PassesFilterTest) { - EXPECT_TRUE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("abcdefg"))); - EXPECT_TRUE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("abcdefg*"))); - EXPECT_TRUE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("abc*"))); - EXPECT_TRUE(PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("*"))); - EXPECT_TRUE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("-~"))); - EXPECT_TRUE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("-abcdefgh"))); - EXPECT_TRUE(PassesFilter(base::CStrVector("abdefg"), base::CStrVector("-"))); - EXPECT_FALSE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("-abcdefg"))); - EXPECT_FALSE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("-abcdefg*"))); - EXPECT_FALSE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("-abc*"))); - EXPECT_FALSE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("-*"))); - EXPECT_FALSE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("~"))); - EXPECT_FALSE(PassesFilter(base::CStrVector("abcdefg"), base::CStrVector(""))); - EXPECT_FALSE( - PassesFilter(base::CStrVector("abcdefg"), base::CStrVector("abcdefgh"))); - - EXPECT_TRUE(PassesFilter(base::CStrVector(""), base::CStrVector(""))); - EXPECT_TRUE(PassesFilter(base::CStrVector(""), base::CStrVector("*"))); - EXPECT_FALSE(PassesFilter(base::CStrVector(""), base::CStrVector("-"))); - EXPECT_FALSE(PassesFilter(base::CStrVector(""), base::CStrVector("-*"))); - EXPECT_FALSE(PassesFilter(base::CStrVector(""), base::CStrVector("a"))); + EXPECT_TRUE(PassesFilter("abcdefg", "abcdefg")); + EXPECT_TRUE(PassesFilter("abcdefg", "abcdefg*")); + EXPECT_TRUE(PassesFilter("abcdefg", "abc*")); + EXPECT_TRUE(PassesFilter("abcdefg", "*")); + EXPECT_TRUE(PassesFilter("abcdefg", "-~")); + EXPECT_TRUE(PassesFilter("abcdefg", "-abcdefgh")); + EXPECT_TRUE(PassesFilter("abdefg", "-")); + EXPECT_FALSE(PassesFilter("abcdefg", "-abcdefg")); + EXPECT_FALSE(PassesFilter("abcdefg", "-abcdefg*")); + EXPECT_FALSE(PassesFilter("abcdefg", "-abc*")); + EXPECT_FALSE(PassesFilter("abcdefg", "-*")); + EXPECT_FALSE(PassesFilter("abcdefg", "~")); + EXPECT_FALSE(PassesFilter("abcdefg", "")); + EXPECT_FALSE(PassesFilter("abcdefg", "abcdefgh")); + + EXPECT_TRUE(PassesFilter("", "")); + EXPECT_TRUE(PassesFilter("", "*")); + EXPECT_FALSE(PassesFilter("", "-")); + EXPECT_FALSE(PassesFilter("", "-*")); + EXPECT_FALSE(PassesFilter("", "a")); // Copy the vectors to give ASan a chance to catch off-by-one OOB reads, // which are hidden when the string literal is embedded into the binary // and hence always null-terminated. - base::OwnedVector<const char> name = - base::OwnedCopyOf(base::CStrVector("abcdefgh")); - base::OwnedVector<const char> filter = - base::OwnedCopyOf(base::CStrVector("abcdefgh*")); - EXPECT_TRUE(PassesFilter(name.as_vector(), filter.as_vector())); + base::UniqueArray<const char> name = + base::UniqueCopyOf(std::string_view("abcdefgh")); + base::UniqueArray<const char> filter = + base::UniqueCopyOf(std::string_view("abcdefgh*")); + EXPECT_TRUE(PassesFilter({name.begin(), name.size()}, + {filter.begin(), filter.size()})); } TEST(UtilsTest, IsInBounds) { diff --git a/deps/v8/test/unittests/utils/version-unittest.cc b/deps/v8/test/unittests/utils/version-unittest.cc index 28415a090a45..d0d017dc05ed 100644 --- a/deps/v8/test/unittests/utils/version-unittest.cc +++ b/deps/v8/test/unittests/utils/version-unittest.cc @@ -27,6 +27,8 @@ #include "src/utils/version.h" +#include <array> + #include "src/init/v8.h" #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,23 +53,23 @@ static void CheckVersion(int major, int minor, int build, int patch, const char* embedder, bool candidate, const char* expected_version_string, const char* expected_generic_soname) { - static v8::base::EmbeddedVector<char, 128> version_str; - static v8::base::EmbeddedVector<char, 128> soname_str; + static std::array<char, 128> version_str; + static std::array<char, 128> soname_str; // Test version without specific SONAME. SetVersion(major, minor, build, patch, embedder, candidate, ""); Version::GetString(version_str); - CHECK_EQ(0, strcmp(expected_version_string, version_str.begin())); + CHECK_EQ(0, strcmp(expected_version_string, version_str.data())); Version::GetSONAME(soname_str); - CHECK_EQ(0, strcmp(expected_generic_soname, soname_str.begin())); + CHECK_EQ(0, strcmp(expected_generic_soname, soname_str.data())); // Test version with specific SONAME. const char* soname = "libv8.so.1"; SetVersion(major, minor, build, patch, embedder, candidate, soname); Version::GetString(version_str); - CHECK_EQ(0, strcmp(expected_version_string, version_str.begin())); + CHECK_EQ(0, strcmp(expected_version_string, version_str.data())); Version::GetSONAME(soname_str); - CHECK_EQ(0, strcmp(soname, soname_str.begin())); + CHECK_EQ(0, strcmp(soname, soname_str.data())); } TEST_F(VersionTest, VersionString) { diff --git a/deps/v8/test/cctest/wasm/DEPS b/deps/v8/test/unittests/wasm/DEPS similarity index 67% rename from deps/v8/test/cctest/wasm/DEPS rename to deps/v8/test/unittests/wasm/DEPS index 2cfbed27bb06..d8e540bf3003 100644 --- a/deps/v8/test/cctest/wasm/DEPS +++ b/deps/v8/test/unittests/wasm/DEPS @@ -1,5 +1,5 @@ specific_include_rules = { - "test-wasm-strings.cc": [ + "wasm-strings-unittest.cc": [ "+third_party/utf8-decoder", ], } diff --git a/deps/v8/test/cctest/wasm/test-backing-store.cc b/deps/v8/test/unittests/wasm/backing-store-unittest.cc similarity index 78% rename from deps/v8/test/cctest/wasm/test-backing-store.cc rename to deps/v8/test/unittests/wasm/backing-store-unittest.cc index a442f046a5fb..b254d93806bf 100644 --- a/deps/v8/test/cctest/wasm/test-backing-store.cc +++ b/deps/v8/test/unittests/wasm/backing-store-unittest.cc @@ -2,23 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/api/api-inl.h" #include "src/objects/backing-store.h" + +#include "src/api/api-inl.h" #include "src/objects/js-array-buffer-inl.h" #include "src/wasm/wasm-objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" -#include "test/cctest/manually-externalized-buffer.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/wasm/manually-externalized-buffer.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { -using testing::ManuallyExternalizedBuffer; +class WasmBackingStoreTest + : public WithWasmTrapHandlerMixin<TestWithHeapInternalsAndContext> {}; -TEST(Run_WasmModule_Buffer_Externalized_Detach) { +TEST_F(WasmBackingStoreTest, Run_WasmModule_Buffer_Externalized_Detach) { { // Regression test for // https://bugs.chromium.org/p/chromium/issues/detail?id=731046 - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = i_isolate(); HandleScope scope(isolate); MaybeHandle<JSArrayBuffer> result = isolate->factory()->NewJSArrayBufferAndBackingStore( @@ -37,13 +39,14 @@ TEST(Run_WasmModule_Buffer_Externalized_Detach) { int_buffer[0] = 0; // Embedder frees contents. } - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); + InvokeMemoryReducingMajorGCs(); } -TEST(Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree) { +TEST_F(WasmBackingStoreTest, + Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree) { { // Regression test for https://crbug.com/813876 - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = i_isolate(); HandleScope scope(isolate); MaybeDirectHandle<WasmMemoryObject> result = WasmMemoryObject::New( isolate, 1, 1, SharedFlag{false}, wasm::AddressType::kI32); @@ -67,13 +70,13 @@ TEST(Run_WasmModule_Buffer_Externalized_Regression_UseAfterFree) { memory_object->backing_store()->buffer_start()); int_buffer[0] = 0; } - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); + InvokeMemoryReducingMajorGCs(); } #if V8_TARGET_ARCH_64_BIT -TEST(BackingStore_Reclaim) { +TEST_F(WasmBackingStoreTest, BackingStore_Reclaim) { // Make sure we can allocate memories without running out of address space. - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = i_isolate(); for (int i = 0; i < 256; ++i) { auto backing_store = BackingStore::AllocateWasmMemory( isolate, 1, 1, WasmMemoryFlag::kWasmMemory32, SharedFlag{false}); diff --git a/deps/v8/test/unittests/wasm/basic-block-calculator-unittest.cc b/deps/v8/test/unittests/wasm/basic-block-calculator-unittest.cc index 600a12ab9d52..64cd1cf01455 100644 --- a/deps/v8/test/unittests/wasm/basic-block-calculator-unittest.cc +++ b/deps/v8/test/unittests/wasm/basic-block-calculator-unittest.cc @@ -4,6 +4,7 @@ #include "src/wasm/basic-block-calculator.h" +#include "src/base/unique-array.h" #include "src/wasm/compilation-environment-inl.h" #include "src/wasm/module-compiler.h" #include "src/wasm/module-decoder.h" @@ -19,19 +20,19 @@ namespace v8::internal::wasm { namespace { class TestWireBytesStorage final : public WireBytesStorage { public: - explicit TestWireBytesStorage(base::OwnedVector<const uint8_t>& wire_bytes) - : wire_bytes_(base::OwnedCopyOf(wire_bytes)) {} + explicit TestWireBytesStorage(base::UniqueArray<const uint8_t>& wire_bytes) + : wire_bytes_(base::UniqueCopyOf(wire_bytes)) {} base::Vector<const uint8_t> GetCode(WireBytesRef ref) const final { - return wire_bytes_.as_vector().SubVector(ref.offset(), ref.end_offset()); + return wire_bytes_.subspan(ref.offset(), ref.length()); } std::optional<ModuleWireBytes> GetModuleBytes() const final { - return std::optional<ModuleWireBytes>(wire_bytes_.as_vector()); + return std::optional<ModuleWireBytes>(wire_bytes_.as_span()); } private: - const base::OwnedVector<const uint8_t> wire_bytes_; + const base::UniqueArray<const uint8_t> wire_bytes_; }; } // namespace @@ -42,10 +43,10 @@ class WasmBasicBlockCalculatorTest : public TestWithIsolateAndZone { protected: std::shared_ptr<NativeModule> CompileNativeModule( - base::OwnedVector<const uint8_t>& module_bytes, + base::UniqueArray<const uint8_t>& module_bytes, WasmDetectedFeatures* detected_features) { ModuleResult result = - DecodeWasmModule(WasmEnabledFeatures::All(), module_bytes.as_vector(), + DecodeWasmModule(WasmEnabledFeatures::All(), module_bytes.as_span(), false, detected_features); CHECK(result.ok()); @@ -91,7 +92,7 @@ class WasmBasicBlockCalculatorTest : public TestWithIsolateAndZone { ZoneBuffer buffer{zone()}; builder_.WriteTo(&buffer); - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(buffer); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(buffer); TestWireBytesStorage wire_bytes_storage(bytes); WasmDetectedFeatures detected_features; @@ -408,7 +409,7 @@ TEST_F(WasmBasicBlockCalculatorTest, TestBasicBlockCalculator) { // kExprEnd // 13 //------------------------------------------- ModuleTypeIndex array_type_index = builder_.AddArrayType( - zone()->New<ArrayType>(kWasmI32, false /*mutability*/), + zone()->New<ArrayType>(kWasmI32, false /*mutability*/, SharedFlag{false}), false /*is_final*/, kNoSuperType); TestFunction(sigs.i_v(), diff --git a/deps/v8/test/cctest/wasm/test-c-wasm-entry.cc b/deps/v8/test/unittests/wasm/c-wasm-entry-unittest.cc similarity index 93% rename from deps/v8/test/cctest/wasm/test-c-wasm-entry.cc rename to deps/v8/test/unittests/wasm/c-wasm-entry-unittest.cc index be5013fcf0ff..2bfb65727fd6 100644 --- a/deps/v8/test/cctest/wasm/test-c-wasm-entry.cc +++ b/deps/v8/test/unittests/wasm/c-wasm-entry-unittest.cc @@ -11,10 +11,9 @@ #include "src/wasm/wasm-arguments.h" #include "src/wasm/wasm-code-pointer-table-inl.h" #include "src/wasm/wasm-objects.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -88,8 +87,10 @@ class CWasmEntryArgTester { } // namespace +using CWasmEntryTest = WasmExecutionTestBase; + // Pass int32_t, return int32_t. -TEST(TestCWasmEntryArgPassing_int32) { +TEST_F(CWasmEntryTest, TestCWasmEntryArgPassing_int32) { CWasmEntryArgTester<int32_t, int32_t> tester( {// Return 2*<0> + 1. WASM_I32_ADD(WASM_I32_MUL(WASM_I32V_1(2), WASM_LOCAL_GET(0)), WASM_ONE)}, @@ -101,7 +102,7 @@ TEST(TestCWasmEntryArgPassing_int32) { } // Pass int64_t, return double. -TEST(TestCWasmEntryArgPassing_double_int64) { +TEST_F(CWasmEntryTest, TestCWasmEntryArgPassing_double_int64) { CWasmEntryArgTester<double, int64_t> tester( {// Return (double)<0>. WASM_F64_SCONVERT_I64(WASM_LOCAL_GET(0))}, @@ -111,7 +112,7 @@ TEST(TestCWasmEntryArgPassing_double_int64) { } // Pass double, return int64_t. -TEST(TestCWasmEntryArgPassing_int64_double) { +TEST_F(CWasmEntryTest, TestCWasmEntryArgPassing_int64_double) { CWasmEntryArgTester<int64_t, double> tester( {// Return (int64_t)<0>. WASM_I64_SCONVERT_F64(WASM_LOCAL_GET(0))}, @@ -125,7 +126,7 @@ TEST(TestCWasmEntryArgPassing_int64_double) { } // Pass float, return double. -TEST(TestCWasmEntryArgPassing_float_double) { +TEST_F(CWasmEntryTest, TestCWasmEntryArgPassing_float_double) { CWasmEntryArgTester<double, float> tester( {// Return 2*(double)<0> + 1. WASM_F64_ADD( @@ -137,7 +138,7 @@ TEST(TestCWasmEntryArgPassing_float_double) { } // Pass two doubles, return double. -TEST(TestCWasmEntryArgPassing_double_double) { +TEST_F(CWasmEntryTest, TestCWasmEntryArgPassing_double_double) { CWasmEntryArgTester<double, double, double> tester( {// Return <0> + <1>. WASM_F64_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}, @@ -149,7 +150,7 @@ TEST(TestCWasmEntryArgPassing_double_double) { } // Pass int32_t, int64_t, float and double, return double. -TEST(TestCWasmEntryArgPassing_AllTypes) { +TEST_F(CWasmEntryTest, TestCWasmEntryArgPassing_AllTypes) { CWasmEntryArgTester<double, int32_t, int64_t, float, double> tester( { // Convert all arguments to double, add them and return the sum. diff --git a/deps/v8/test/cctest/wasm/test-compilation-cache.cc b/deps/v8/test/unittests/wasm/compilation-cache-unittest.cc similarity index 79% rename from deps/v8/test/cctest/wasm/test-compilation-cache.cc rename to deps/v8/test/unittests/wasm/compilation-cache-unittest.cc index 151bdd28a3b2..e7704539e8d5 100644 --- a/deps/v8/test/cctest/wasm/test-compilation-cache.cc +++ b/deps/v8/test/unittests/wasm/compilation-cache-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/init/v8.h" #include "src/objects/managed.h" #include "src/wasm/streaming-decoder.h" @@ -12,14 +13,17 @@ #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-result.h" #include "src/zone/zone.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { +using CompilationCacheTest = WasmExecutionTestBase; +using CompilationCacheUninitializedTest = WasmUninitializedTestBase; + namespace { class TestResolver : public CompilationResultResolver { @@ -51,8 +55,9 @@ class TestResolver : public CompilationResultResolver { class StreamTester { public: explicit StreamTester(std::shared_ptr<TestResolver> test_resolver) - : internal_scope_(CcTest::i_isolate()), test_resolver_(test_resolver) { - i::Isolate* i_isolate = CcTest::i_isolate(); + : internal_scope_(WasmExecutionTestBase::current_i_isolate()), + test_resolver_(test_resolver) { + i::Isolate* i_isolate = WasmExecutionTestBase::current_i_isolate(); stream_ = GetWasmEngine()->StartStreamingCompilation( WasmEnabledFeatures::FromIsolate(i_isolate), CompileTimeImports{}, @@ -86,13 +91,14 @@ ZoneBuffer GetValidModuleBytes(Zone* zone, uint8_t n) { } CppGCManaged<NativeModule>::Ptr SyncCompile(base::Vector<const uint8_t> bytes) { - ErrorThrower thrower(CcTest::i_isolate(), "Test"); - auto enabled_features = WasmEnabledFeatures::FromIsolate(CcTest::i_isolate()); + ErrorThrower thrower(WasmExecutionTestBase::current_i_isolate(), "Test"); + auto enabled_features = WasmEnabledFeatures::FromIsolate( + WasmExecutionTestBase::current_i_isolate()); DirectHandle<WasmModuleObject> module = GetWasmEngine() - ->SyncCompile(CcTest::i_isolate(), enabled_features, - CompileTimeImports{}, &thrower, - base::OwnedCopyOf(bytes)) + ->SyncCompile(WasmExecutionTestBase::current_i_isolate(), + enabled_features, CompileTimeImports{}, &thrower, + base::UniqueCopyOf(bytes)) .ToHandleChecked(); return module->native_module(); } @@ -126,9 +132,9 @@ constexpr size_t kFunctionSize = arraysize(kFunctionA); } // namespace -TEST(TestAsyncCache) { - CcTest::InitializeVM(); - i::HandleScope internal_scope(CcTest::i_isolate()); +TEST_F(CompilationCacheTest, TestAsyncCache) { + WasmExecutionTestBase::InitIsolateOnce(); + i::HandleScope internal_scope(WasmExecutionTestBase::current_i_isolate()); AccountingAllocator allocator; Zone zone(&allocator, "CompilationCacheTester"); @@ -141,26 +147,29 @@ TEST(TestAsyncCache) { auto resolverB = std::make_shared<TestResolver>(&pending); GetWasmEngine()->AsyncCompile( - CcTest::i_isolate(), WasmEnabledFeatures::All(), CompileTimeImports{}, - resolverA1, base::OwnedCopyOf(bufferA), "WebAssembly.compile"); + WasmExecutionTestBase::current_i_isolate(), WasmEnabledFeatures::All(), + CompileTimeImports{}, resolverA1, base::UniqueCopyOf(bufferA), + "WebAssembly.compile"); GetWasmEngine()->AsyncCompile( - CcTest::i_isolate(), WasmEnabledFeatures::All(), CompileTimeImports{}, - resolverA2, base::OwnedCopyOf(bufferA), "WebAssembly.compile"); + WasmExecutionTestBase::current_i_isolate(), WasmEnabledFeatures::All(), + CompileTimeImports{}, resolverA2, base::UniqueCopyOf(bufferA), + "WebAssembly.compile"); GetWasmEngine()->AsyncCompile( - CcTest::i_isolate(), WasmEnabledFeatures::All(), CompileTimeImports{}, - resolverB, base::OwnedCopyOf(bufferB), "WebAssembly.compile"); + WasmExecutionTestBase::current_i_isolate(), WasmEnabledFeatures::All(), + CompileTimeImports{}, resolverB, base::UniqueCopyOf(bufferB), + "WebAssembly.compile"); while (pending > 0) { v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), - CcTest::isolate()); + WasmExecutionTestBase::current_isolate()); } CHECK_EQ(resolverA1->native_module(), resolverA2->native_module()); CHECK_NE(resolverA1->native_module(), resolverB->native_module()); } -TEST(TestStreamingCache) { - CcTest::InitializeVM(); +TEST_F(CompilationCacheTest, TestStreamingCache) { + WasmExecutionTestBase::InitIsolateOnce(); std::atomic<int> pending(3); auto resolverA1 = std::make_shared<TestResolver>(&pending); @@ -186,7 +195,7 @@ TEST(TestStreamingCache) { while (pending > 0) { v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), - CcTest::isolate()); + WasmExecutionTestBase::current_isolate()); } NativeModule* native_module_A1 = resolverA1->native_module(); @@ -196,8 +205,8 @@ TEST(TestStreamingCache) { CHECK_NE(native_module_A1, native_module_B); } -TEST(TestStreamingAndSyncCache) { - CcTest::InitializeVM(); +TEST_F(CompilationCacheTest, TestStreamingAndSyncCache) { + WasmExecutionTestBase::InitIsolateOnce(); std::atomic<int> pending(1); auto resolver = std::make_shared<TestResolver>(&pending); @@ -208,11 +217,11 @@ TEST(TestStreamingAndSyncCache) { // Compile the same module synchronously to make sure we don't deadlock // waiting for streaming compilation to finish. auto full_bytes = - base::OwnedVector<uint8_t>::New(kPrefixSize + kFunctionSize); + base::UniqueArray<uint8_t>::New(kPrefixSize + kFunctionSize); memcpy(full_bytes.begin(), kPrefix, kPrefixSize); memcpy(full_bytes.begin() + kPrefixSize, kFunctionA, kFunctionSize); CppGCManaged<NativeModule>::Ptr native_module_sync = - SyncCompile(full_bytes.as_vector()); + SyncCompile(full_bytes.as_span()); // Streaming compilation should just discard its native module now and use the // one inserted in the cache by sync compilation. @@ -221,7 +230,7 @@ TEST(TestStreamingAndSyncCache) { while (pending > 0) { v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(), - CcTest::isolate()); + WasmExecutionTestBase::current_isolate()); } NativeModule* native_module_streaming = resolver->native_module(); @@ -249,7 +258,7 @@ void TestModuleSharingBetweenIsolates() { i::HandleScope handle_scope(i_isolate); v8::Context::New(isolate)->Enter(); auto full_bytes = - base::OwnedVector<uint8_t>::New(kPrefixSize + kFunctionSize); + base::UniqueArray<uint8_t>::New(kPrefixSize + kFunctionSize); memcpy(full_bytes.begin(), kPrefix, kPrefixSize); memcpy(full_bytes.begin() + kPrefixSize, kFunctionA, kFunctionSize); ErrorThrower thrower(i_isolate, "Test"); @@ -298,14 +307,14 @@ void TestModuleSharingBetweenIsolates() { CHECK_EQ(modules[0].get(), modules[1].get()); } -UNINITIALIZED_TEST(TwoIsolatesShareNativeModule) { - v8_flags.wasm_lazy_compilation = false; +TEST_F(CompilationCacheUninitializedTest, TwoIsolatesShareNativeModule) { + FlagScope<bool> no_lazy_compilation(&v8_flags.wasm_lazy_compilation, false); TestModuleSharingBetweenIsolates(); } -UNINITIALIZED_TEST(TwoIsolatesShareNativeModuleWithPku) { - v8_flags.wasm_lazy_compilation = false; - v8_flags.memory_protection_keys = true; +TEST_F(CompilationCacheUninitializedTest, TwoIsolatesShareNativeModuleWithPku) { + FlagScope<bool> no_lazy_compilation(&v8_flags.wasm_lazy_compilation, false); + FlagScope<bool> enable_pku(&v8_flags.memory_protection_keys, true); TestModuleSharingBetweenIsolates(); } diff --git a/deps/v8/test/unittests/wasm/compilation-hints-unittest.cc b/deps/v8/test/unittests/wasm/compilation-hints-unittest.cc index 8cc7f393bf0b..6b2652843016 100644 --- a/deps/v8/test/unittests/wasm/compilation-hints-unittest.cc +++ b/deps/v8/test/unittests/wasm/compilation-hints-unittest.cc @@ -46,7 +46,7 @@ class WasmCompilationHintsBuilder { } void AddExport(const char* name, uint32_t index) { - builder_.AddExport(base::CStrVector(name), kExternalFunction, index); + builder_.AddExport(name, kExternalFunction, index); } void CompileModule() { diff --git a/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc index 94ab2eaf96cf..702b0d79cccb 100644 --- a/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/function-body-decoder-unittest.cc @@ -162,7 +162,8 @@ class TestModuleBuilder { HeapType AddArray(ValueType type, bool mutability, SharedFlag is_shared = SharedFlag{false}) { - ArrayType* array = mod.signature_storage.New<ArrayType>(type, mutability); + ArrayType* array = + mod.signature_storage.New<ArrayType>(type, mutability, is_shared); const bool is_final = true; mod.AddArrayTypeForTesting(array, kNoSuperType, is_final, is_shared); GetTypeCanonicalizer()->AddRecursiveSingletonGroup(module()); @@ -812,11 +813,33 @@ TEST_F(FunctionBodyDecoderTest, BlockBrBinop) { } TEST_F(FunctionBodyDecoderTest, VoidBlockTypeVariants) { - // Valid kVoidCode encoded in 2 bytes. - ExpectValidates(sigs.v_v(), {kExprBlock, kVoidCode | 0x80, 0x7F, kExprEnd}); + // Single-byte kVoidCode is valid. + ExpectValidates(sigs.v_v(), {kExprBlock, kVoidCode, kExprEnd}); + // Multi-byte s33 encodings of kVoidCode (-64) are invalid. + ExpectFailure(sigs.v_v(), {kExprBlock, kVoidCode | 0x80, 0x7F, kExprEnd}, + kAppendEnd, "invalid block type -64"); + ExpectFailure(sigs.v_v(), + {kExprBlock, kVoidCode | 0x80, 0xFF, 0x7F, kExprEnd}, + kAppendEnd, "invalid block type -64"); + ExpectFailure( + sigs.v_v(), + {kExprBlock, kVoidCode | 0x80, 0xFF, 0xFF, 0xFF, 0x7F, kExprEnd}, + kAppendEnd, "invalid block type -64"); + // Multi-byte s33 encodings of value type opcodes (e.g. kI32Code = -1) are + // invalid. + ExpectFailure(sigs.i_v(), + {kExprBlock, kI32Code | 0x80, 0x7F, WASM_ZERO, kExprEnd}, + kAppendEnd, "invalid block type -1"); // Invalid code, whose last 7 bits coincide with kVoidCode. ExpectFailure(sigs.v_v(), {kExprBlock, kVoidCode | 0x80, 0x45, kExprEnd}, kAppendEnd, "invalid block type"); + // Concrete signature indices (non-negative s33) can use 1- to 5-byte LEB128. + ModuleTypeIndex sig_index = builder.AddSignature(sigs.v_v()); + ASSERT_EQ(0u, sig_index.index); + ExpectValidates(sigs.v_v(), {kExprBlock, 0x00, kExprEnd}); + ExpectValidates(sigs.v_v(), {kExprBlock, 0x80, 0x00, kExprEnd}); + ExpectValidates(sigs.v_v(), + {kExprBlock, 0x80, 0x80, 0x80, 0x80, 0x00, kExprEnd}); } TEST_F(FunctionBodyDecoderTest, If_empty1) { @@ -2879,6 +2902,12 @@ TEST_F(FunctionBodyDecoderTest, SelectWithType_fail) { {WASM_SELECT_L(WASM_F64(0.0), WASM_F64(0.0), WASM_ZERO)}); ExpectFailure(sigs.l_l(), {WASM_SELECT_I(WASM_I64V_1(0), WASM_I64V_1(0), WASM_ZERO)}); + // Select with type count > 255 whose low byte is 1 (e.g. 257 = 0x81, 0x02). + ExpectFailure(sigs.i_i(), + {WASM_LOCAL_GET(0), WASM_LOCAL_GET(0), WASM_ZERO, + kExprSelectWithType, U32V_2(257), kI32Code}, + kAppendEnd, + "Invalid number of types. Select accepts exactly one type"); } TEST_F(FunctionBodyDecoderTest, Throw) { @@ -3902,6 +3931,35 @@ TEST_F(FunctionBodyDecoderTest, RefNull) { "Type index 42 is out of bounds"); } +TEST_F(FunctionBodyDecoderTest, ExactHeapTypeEncoding) { + WASM_FEATURE_SCOPE(custom_descriptors); + WASM_FEATURE_SCOPE(shared); + HeapType struct_heap_type = builder.AddStruct({F(kWasmI32, true)}); + uint8_t struct_index = struct_heap_type.ref_index().index; + const ValueType exact_type = ValueType::RefNull(struct_heap_type.AsExact()); + const FunctionSig sig(1, 0, &exact_type); + + // 1-byte kExactCode followed by 1-byte or multi-byte u32v type index. + ExpectValidates(&sig, {kExprRefNull, kExactCode, struct_index}); + ExpectValidates(&sig, {kExprRefNull, kExactCode, U32V_2(struct_index)}); + + // Multi-byte encodings of kExactCode (0x62 = -30) are invalid. + ExpectFailure( + sigs.v_v(), + {kExprRefNull, kExactCode | 0x80, 0x7f, struct_index, kExprDrop}, + kAppendEnd, "Unknown heap type -30"); + ExpectFailure(sigs.v_v(), + {kExprRefNull, kExactCode | 0x80, 0xff, 0xff, 0xff, 0x7f, + struct_index, kExprDrop}, + kAppendEnd, "Unknown heap type -30"); + + // 'shared' prefix before 'exact' is invalid. + ExpectFailure( + sigs.v_v(), + {kExprRefNull, kSharedFlagCode, kExactCode, struct_index, kExprDrop}, + kAppendEnd, "invalid heap type 'shared exact'"); +} + TEST_F(FunctionBodyDecoderTest, RefIsNull) { ExpectValidates(sigs.i_i(), {WASM_REF_IS_NULL(WASM_REF_NULL(kExternRefCode))}); @@ -5455,32 +5513,53 @@ class TypeReaderTest : public TestWithZone { TEST_F(TypeReaderTest, HeapTypeDecodingTest) { HeapType heap_func = kWasmFuncRef; HeapType heap_bottom = kWasmBottom; + HeapType heap_index_0 = + HeapType::Index(ModuleTypeIndex{0}, SharedFlag{false}, + RefTypeKind::kOther, Exactness::kAnySubtype); - // 1- to 5-byte representation of kFuncRefCode. + // Abstract heap types must be encoded as a single byte; multi-byte s33 + // encodings of kFuncRefCode are invalid. { const uint8_t data[] = {kFuncRefCode}; HeapType result = DecodeHeapType(data, data + sizeof(data)); - EXPECT_TRUE(result == heap_func); + EXPECT_EQ(result, heap_func); } { const uint8_t data[] = {kFuncRefCode | 0x80, 0x7F}; HeapType result = DecodeHeapType(data, data + sizeof(data)); - EXPECT_EQ(result, heap_func); + EXPECT_EQ(result, heap_bottom); } { const uint8_t data[] = {kFuncRefCode | 0x80, 0xFF, 0x7F}; HeapType result = DecodeHeapType(data, data + sizeof(data)); - EXPECT_EQ(result, heap_func); + EXPECT_EQ(result, heap_bottom); } { const uint8_t data[] = {kFuncRefCode | 0x80, 0xFF, 0xFF, 0x7F}; HeapType result = DecodeHeapType(data, data + sizeof(data)); - EXPECT_EQ(result, heap_func); + EXPECT_EQ(result, heap_bottom); } { const uint8_t data[] = {kFuncRefCode | 0x80, 0xFF, 0xFF, 0xFF, 0x7F}; HeapType result = DecodeHeapType(data, data + sizeof(data)); - EXPECT_EQ(result, heap_func); + EXPECT_EQ(result, heap_bottom); + } + + // Concrete type indices (non-negative s33) can use 1- to 5-byte LEB128. + { + const uint8_t data[] = {0x00}; + HeapType result = DecodeHeapType(data, data + sizeof(data)); + EXPECT_EQ(result, heap_index_0); + } + { + const uint8_t data[] = {0x80, 0x00}; + HeapType result = DecodeHeapType(data, data + sizeof(data)); + EXPECT_EQ(result, heap_index_0); + } + { + const uint8_t data[] = {0x80, 0x80, 0x80, 0x80, 0x00}; + HeapType result = DecodeHeapType(data, data + sizeof(data)); + EXPECT_EQ(result, heap_index_0); } { diff --git a/deps/v8/test/cctest/wasm/test-fuzzer-steps.cc b/deps/v8/test/unittests/wasm/fuzzer-steps-unittest.cc similarity index 85% rename from deps/v8/test/cctest/wasm/test-fuzzer-steps.cc rename to deps/v8/test/unittests/wasm/fuzzer-steps-unittest.cc index 0db90da5f48f..a2f4ddea606c 100644 --- a/deps/v8/test/cctest/wasm/test-fuzzer-steps.cc +++ b/deps/v8/test/unittests/wasm/fuzzer-steps-unittest.cc @@ -3,14 +3,15 @@ // found in the LICENSE file. #include "src/wasm/wasm-engine.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { -TEST(FuzzerStepsPrefixedOpcode) { +using FuzzerStepsTest = WasmExecutionTestBase; + +TEST_F(FuzzerStepsTest, FuzzerStepsPrefixedOpcode) { WasmRunner<uint32_t> r(TestExecutionTier::kLiftoffForFuzzing); // Entry: 16. MemoryCopy: 1000. Constant: 1. Total: 1017. r.builder().AddMemory(kWasmPageSize); @@ -27,7 +28,7 @@ TEST(FuzzerStepsPrefixedOpcode) { r.CheckCallViaJSTraps(); } -TEST(FuzzerStepsNonPrefixedOpcode) { +TEST_F(FuzzerStepsTest, FuzzerStepsNonPrefixedOpcode) { WasmRunner<uint32_t> r(TestExecutionTier::kLiftoffForFuzzing); // Entry: 16. MemoryGrow: 10000. Constant: 1. Total: 10017. r.builder().AddMemory(kWasmPageSize); diff --git a/deps/v8/test/cctest/wasm/test-gc.cc b/deps/v8/test/unittests/wasm/gc-unittest.cc similarity index 99% rename from deps/v8/test/cctest/wasm/test-gc.cc rename to deps/v8/test/unittests/wasm/gc-unittest.cc index e3dd84d58414..06e6ef89a649 100644 --- a/deps/v8/test/cctest/wasm/test-gc.cc +++ b/deps/v8/test/unittests/wasm/gc-unittest.cc @@ -14,17 +14,19 @@ #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" -#include "test/common/wasm/wasm-run-utils.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_gc { +using WasmGCTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE WasmGCTest + using F = std::pair<ValueType, bool>; class WasmGCTester { @@ -44,10 +46,9 @@ class WasmGCTester { v8_flags.wasm_deopt && v8_flags.liftoff), zone_(&allocator, ZONE_NAME), builder_(&zone_), - isolate_(CcTest::InitIsolateOnce()), + isolate_(WasmExecutionTestBase::InitIsolateOnce()), scope(isolate_), - thrower(isolate_, "Test wasm GC") { - } + thrower(isolate_, "Test wasm GC") {} uint8_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init) { return builder_.AddGlobal(type, mutability, init); @@ -69,7 +70,7 @@ class WasmGCTester { std::initializer_list<const uint8_t> code) { WasmFunctionBuilder* fun = builder_.AddFunction(sig); fun->EmitCode(code); - builder_.AddExport(base::CStrVector(name), fun); + builder_.AddExport(name, fun); } MaybeDirectHandle<Object> CallExportedFunction( @@ -98,8 +99,9 @@ class WasmGCTester { ModuleTypeIndex supertype = kNoSuperType, bool is_final = false) { return HeapType::Index( - builder_.AddArrayType(zone_.New<ArrayType>(element_type, mutability), - is_final, supertype), + builder_.AddArrayType( + zone_.New<ArrayType>(element_type, mutability, SharedFlag{false}), + is_final, supertype), SharedFlag{false}, RefTypeKind::kArray); } @@ -945,7 +947,7 @@ WASM_COMPILED_EXEC_TEST(WasmBasicArray) { &sig_q_v, {}, {WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(kLongLength)), kExprEnd}); - ArrayType array_type(kWasmI32, true); + ArrayType array_type(kWasmI32, true, SharedFlag{false}); const uint32_t kTooLong = WasmArray::MaxLength(&array_type) + 1; const uint8_t kAllocateTooLarge = tester.DefineFunction( &sig_q_v, {}, @@ -1535,7 +1537,7 @@ WASM_COMPILED_EXEC_TEST(FunctionRefs) { tester.CompileModule(); - i::Isolate* i_isolate = CcTest::i_isolate(); + i::Isolate* i_isolate = WasmExecutionTestBase::current_i_isolate(); DirectHandle<Object> result_cast = tester.GetResultObject(cast).ToHandleChecked(); CHECK(IsWasmFuncRef(*result_cast)); @@ -2168,6 +2170,8 @@ WASM_COMPILED_EXEC_TEST(WasmExternConvertAny) { tester.CheckResult(kNull, 1); } +#undef WASM_EXEC_TEST_SUITE + } // namespace test_gc } // namespace wasm } // namespace internal diff --git a/deps/v8/test/cctest/wasm/test-grow-memory.cc b/deps/v8/test/unittests/wasm/grow-memory-unittest.cc similarity index 86% rename from deps/v8/test/cctest/wasm/test-grow-memory.cc rename to deps/v8/test/unittests/wasm/grow-memory-unittest.cc index a6e051587970..f1644b7460da 100644 --- a/deps/v8/test/cctest/wasm/test-grow-memory.cc +++ b/deps/v8/test/unittests/wasm/grow-memory-unittest.cc @@ -6,27 +6,27 @@ #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/cctest.h" -#include "test/cctest/manually-externalized-buffer.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/manually-externalized-buffer.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_grow_memory { +using GrowMemoryTest = WasmExecutionTestBase; using testing::CompileAndInstantiateForTesting; -using v8::internal::testing::ManuallyExternalizedBuffer; namespace { void ExportAsMain(WasmFunctionBuilder* f) { - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); } -void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) { +void Cleanup(Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce()) { // By sending a low memory notifications, we will try hard to collect all // garbage and will therefore also invoke all weak callbacks of actually // unreachable persistent handles. @@ -34,9 +34,9 @@ void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) { } } // namespace -TEST(GrowMemDetaches) { +TEST_F(GrowMemoryTest, GrowMemDetaches) { { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); DirectHandle<WasmMemoryObject> memory_object = WasmMemoryObject::New(isolate, 16, 100, SharedFlag{false}, @@ -52,9 +52,9 @@ TEST(GrowMemDetaches) { Cleanup(); } -TEST(Externalized_GrowMemMemSize) { +TEST_F(GrowMemoryTest, Externalized_GrowMemMemSize) { { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); DirectHandle<WasmMemoryObject> memory_object = WasmMemoryObject::New(isolate, 16, 100, SharedFlag{false}, @@ -70,9 +70,9 @@ TEST(Externalized_GrowMemMemSize) { Cleanup(); } -TEST(Run_WasmModule_Buffer_Externalized_GrowMem) { +TEST_F(GrowMemoryTest, Run_WasmModule_Buffer_Externalized_GrowMem) { { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); TestSignatures sigs; v8::internal::AccountingAllocator allocator; diff --git a/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc b/deps/v8/test/unittests/wasm/jump-table-assembler-unittest.cc similarity index 89% rename from deps/v8/test/cctest/wasm/test-jump-table-assembler.cc rename to deps/v8/test/unittests/wasm/jump-table-assembler-unittest.cc index a88d8a5fa95d..b98f3b501b7e 100644 --- a/deps/v8/test/cctest/wasm/test-jump-table-assembler.cc +++ b/deps/v8/test/unittests/wasm/jump-table-assembler-unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/wasm/jump-table-assembler.h" + #include <bitset> #include "src/base/utils/random-number-generator.h" @@ -10,14 +12,15 @@ #include "src/execution/simulator.h" #include "src/utils/utils.h" #include "src/wasm/code-space-access.h" -#include "src/wasm/jump-table-assembler.h" -#include "test/cctest/cctest.h" #include "test/common/assembler-tester.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { +using JumpTableAssemblerTest = WithWasmTrapHandlerMixin<TestWithIsolate>; + #if 0 #define TRACE(...) PrintF(__VA_ARGS__) #else @@ -58,7 +61,7 @@ constexpr uint32_t kBufferSlotStartOffset = 0; #endif Address AllocateJumpTableThunk( - Address jump_target, uint8_t* thunk_slot_buffer, + Isolate* isolate, Address jump_target, uint8_t* thunk_slot_buffer, std::bitset<kAvailableBufferSlots>* used_slots, std::vector<std::unique_ptr<TestingAssemblerBuffer>>* thunk_buffers) { #if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_LOONG64 || \ @@ -70,8 +73,7 @@ Address AllocateJumpTableThunk( // Allocate a slot that we haven't already used. This is necessary because // each test iteration expects to generate two unique addresses and we leave // each slot executable (and not writable). - base::RandomNumberGenerator* rng = - CcTest::i_isolate()->random_number_generator(); + base::RandomNumberGenerator* rng = isolate->random_number_generator(); // Ensure a chance of completion without too much thrashing. DCHECK(used_slots->count() < (used_slots->size() / 2)); int buffer_index; @@ -83,6 +85,7 @@ Address AllocateJumpTableThunk( buffer_index * kThunkBufferSize); #else + USE(isolate); USE(thunk_slot_buffer); USE(used_slots); thunk_buffers->emplace_back( @@ -91,9 +94,10 @@ Address AllocateJumpTableThunk( #endif } -void CompileJumpTableThunk(Address thunk, Address jump_target) { +void CompileJumpTableThunk(Isolate* isolate, Address thunk, + Address jump_target) { RwxMemoryWriteScopeForTesting write_scope; - MacroAssembler masm(CcTest::i_isolate()->allocator(), AssemblerOptions{}, + MacroAssembler masm(isolate->allocator(), AssemblerOptions{}, CodeObjectRequired{false}, ExternalAssemblerBuffer(reinterpret_cast<void*>(thunk), kThunkBufferSize)); @@ -181,28 +185,32 @@ void CompileJumpTableThunk(Address thunk, Address jump_target) { class JumpTableRunner : public v8::base::Thread { public: - JumpTableRunner(Address slot_address, int runner_id) + JumpTableRunner(Isolate* isolate, Address slot_address, int runner_id) : Thread(Options("JumpTableRunner")), + isolate_(isolate), slot_address_(slot_address), runner_id_(runner_id) {} void Run() override { TRACE("Runner #%d is starting ...\n", runner_id_); - GeneratedCode<void>::FromAddress(CcTest::i_isolate(), slot_address_).Call(); + GeneratedCode<void>::FromAddress(isolate_, slot_address_).Call(); TRACE("Runner #%d is stopping ...\n", runner_id_); USE(runner_id_); } private: + Isolate* isolate_; Address slot_address_; int runner_id_; }; class JumpTablePatcher : public v8::base::Thread { public: - JumpTablePatcher(Address slot_start, uint32_t slot_index, Address thunk1, - Address thunk2, base::Mutex* jump_table_mutex) + JumpTablePatcher(Isolate* isolate, Address slot_start, uint32_t slot_index, + Address thunk1, Address thunk2, + base::Mutex* jump_table_mutex) : Thread(Options("JumpTablePatcher")), + isolate_(isolate), slot_start_(slot_start), slot_index_(slot_index), thunks_{thunk1, thunk2}, @@ -214,7 +222,7 @@ class JumpTablePatcher : public v8::base::Thread { slot_start_ + JumpTableAssembler::JumpSlotIndexToOffset(slot_index_); // First, emit code to the two thunks. for (Address thunk : thunks_) { - CompileJumpTableThunk(thunk, slot_address); + CompileJumpTableThunk(isolate_, thunk, slot_address); } // Then, repeatedly patch the jump table to jump to one of the two thunks. WritableJumpTablePair jump_table_pair = WritableJumpTablePair::ForTesting( @@ -237,6 +245,7 @@ class JumpTablePatcher : public v8::base::Thread { } private: + Isolate* isolate_; Address slot_start_; uint32_t slot_index_; Address thunks_[2]; @@ -255,7 +264,7 @@ class JumpTablePatcher : public v8::base::Thread { // 3) Start a patcher that repeatedly patches the jump-table slot back and // forth between two thunk. If there is a race then chances are high that // one of the runners is currently executing the jump-table slot. -TEST(JumpTablePatchingStress) { +TEST_F(JumpTableAssemblerTest, JumpTablePatchingStress) { constexpr int kNumberOfRunnerThreads = 5; constexpr int kNumberOfPatcherThreads = 3; @@ -293,9 +302,9 @@ TEST(JumpTablePatchingStress) { // For each patcher, generate two thunks where this patcher can emit code // which finally jumps back to {slot} in the jump table. for (int i = 0; i < 2 * kNumberOfPatcherThreads; ++i) { - Address thunk = - AllocateJumpTableThunk(slot_start + slot_offset, thunk_slot_buffer, - &used_thunk_slots, &thunk_buffers); + Address thunk = AllocateJumpTableThunk( + i_isolate(), slot_start + slot_offset, thunk_slot_buffer, + &used_thunk_slots, &thunk_buffers); { RwxMemoryWriteScopeForTesting write_scope; ZapCode(thunk, kThunkBufferSize); @@ -309,7 +318,7 @@ TEST(JumpTablePatchingStress) { // concurrently. std::list<JumpTableRunner> runners; for (int runner = 0; runner < kNumberOfRunnerThreads; ++runner) { - runners.emplace_back(slot_start + slot_offset, runner); + runners.emplace_back(i_isolate(), slot_start + slot_offset, runner); } // Start multiple patcher thread that concurrently generate code and insert // jumps to that into the jump table slot. @@ -317,8 +326,9 @@ TEST(JumpTablePatchingStress) { // Only one patcher should modify the jump table at a time. base::Mutex jump_table_mutex; for (int i = 0; i < kNumberOfPatcherThreads; ++i) { - patchers.emplace_back(slot_start, slot, patcher_thunks[2 * i], - patcher_thunks[2 * i + 1], &jump_table_mutex); + patchers.emplace_back(i_isolate(), slot_start, slot, + patcher_thunks[2 * i], patcher_thunks[2 * i + 1], + &jump_table_mutex); } global_stop_bit = 0; // Signal runners to keep going. for (auto& runner : runners) CHECK(runner.Start()); diff --git a/deps/v8/test/cctest/wasm/test-liftoff-for-fuzzing.cc b/deps/v8/test/unittests/wasm/liftoff-for-fuzzing-unittest.cc similarity index 78% rename from deps/v8/test/cctest/wasm/test-liftoff-for-fuzzing.cc rename to deps/v8/test/unittests/wasm/liftoff-for-fuzzing-unittest.cc index edddfcd369db..0213d4d0bff9 100644 --- a/deps/v8/test/cctest/wasm/test-liftoff-for-fuzzing.cc +++ b/deps/v8/test/unittests/wasm/liftoff-for-fuzzing-unittest.cc @@ -3,14 +3,15 @@ // found in the LICENSE file. #include "src/wasm/wasm-engine.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { -TEST(MaxSteps) { +using LiftoffForFuzzingTest = WasmExecutionTestBase; + +TEST_F(LiftoffForFuzzingTest, MaxSteps) { WasmRunner<uint32_t> r(TestExecutionTier::kLiftoffForFuzzing); r.Build({WASM_LOOP(WASM_BR(0)), WASM_I32V(23)}); diff --git a/deps/v8/test/cctest/wasm/test-liftoff-inspection.cc b/deps/v8/test/unittests/wasm/liftoff-inspection-unittest.cc similarity index 94% rename from deps/v8/test/cctest/wasm/test-liftoff-inspection.cc rename to deps/v8/test/unittests/wasm/liftoff-inspection-unittest.cc index 29b2535cb1dd..f6a8955e60ee 100644 --- a/deps/v8/test/cctest/wasm/test-liftoff-inspection.cc +++ b/deps/v8/test/unittests/wasm/liftoff-inspection-unittest.cc @@ -5,10 +5,9 @@ #include "src/wasm/baseline/liftoff-compiler.h" #include "src/wasm/compilation-environment-inl.h" #include "src/wasm/wasm-debug.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -19,7 +18,7 @@ namespace { class LiftoffCompileEnvironment { public: LiftoffCompileEnvironment() - : isolate_(CcTest::InitIsolateOnce()), + : isolate_(WasmExecutionTestBase::InitIsolateOnce()), handle_scope_(isolate_), zone_(isolate_->allocator(), ZONE_NAME), wasm_runner_(nullptr, TestExecutionTier::kLiftoff, 0, isolate_) { @@ -264,14 +263,16 @@ void CheckDebugSideTable(std::vector<DebugSideTableEntry> expected_entries, } // namespace -TEST(Liftoff_deterministic_simple) { +using LiftoffInspectionTest = WasmExecutionTestBase; + +TEST_F(LiftoffInspectionTest, Liftoff_deterministic_simple) { LiftoffCompileEnvironment env; env.CheckDeterministicCompilation( {kWasmI32}, {kWasmI32, kWasmI32}, {WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}); } -TEST(Liftoff_deterministic_call) { +TEST_F(LiftoffInspectionTest, Liftoff_deterministic_call) { LiftoffCompileEnvironment env; env.CheckDeterministicCompilation( {kWasmI32}, {kWasmI32}, @@ -279,7 +280,7 @@ TEST(Liftoff_deterministic_call) { WASM_LOCAL_GET(0))}); } -TEST(Liftoff_deterministic_indirect_call) { +TEST_F(LiftoffInspectionTest, Liftoff_deterministic_indirect_call) { LiftoffCompileEnvironment env; env.CheckDeterministicCompilation( {kWasmI32}, {kWasmI32}, @@ -287,21 +288,21 @@ TEST(Liftoff_deterministic_indirect_call) { WASM_LOCAL_GET(0))}); } -TEST(Liftoff_deterministic_loop) { +TEST_F(LiftoffInspectionTest, Liftoff_deterministic_loop) { LiftoffCompileEnvironment env; env.CheckDeterministicCompilation( {kWasmI32}, {kWasmI32}, {WASM_LOOP(WASM_BR_IF(0, WASM_LOCAL_GET(0))), WASM_LOCAL_GET(0)}); } -TEST(Liftoff_deterministic_trap) { +TEST_F(LiftoffInspectionTest, Liftoff_deterministic_trap) { LiftoffCompileEnvironment env; env.CheckDeterministicCompilation( {kWasmI32}, {kWasmI32, kWasmI32}, {WASM_I32_DIVS(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}); } -TEST(Liftoff_debug_side_table_simple) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_simple) { LiftoffCompileEnvironment env; auto debug_side_table = env.GenerateDebugSideTable( {kWasmI32}, {kWasmI32, kWasmI32}, @@ -316,7 +317,7 @@ TEST(Liftoff_debug_side_table_simple) { debug_side_table.get()); } -TEST(Liftoff_debug_side_table_call) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_call) { LiftoffCompileEnvironment env; auto debug_side_table = env.GenerateDebugSideTable( {kWasmI32}, {kWasmI32}, @@ -334,7 +335,7 @@ TEST(Liftoff_debug_side_table_call) { debug_side_table.get()); } -TEST(Liftoff_debug_side_table_call_const) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_call_const) { LiftoffCompileEnvironment env; constexpr int kConst = 13; auto debug_side_table = env.GenerateDebugSideTable( @@ -354,7 +355,7 @@ TEST(Liftoff_debug_side_table_call_const) { debug_side_table.get()); } -TEST(Liftoff_debug_side_table_indirect_call) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_indirect_call) { LiftoffCompileEnvironment env; constexpr int kConst = 47; auto debug_side_table = env.GenerateDebugSideTable( @@ -383,7 +384,7 @@ TEST(Liftoff_debug_side_table_indirect_call) { debug_side_table.get()); } -TEST(Liftoff_debug_side_table_loop) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_loop) { LiftoffCompileEnvironment env; constexpr int kConst = 42; auto debug_side_table = env.GenerateDebugSideTable( @@ -401,7 +402,7 @@ TEST(Liftoff_debug_side_table_loop) { debug_side_table.get()); } -TEST(Liftoff_debug_side_table_trap) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_trap) { LiftoffCompileEnvironment env; auto debug_side_table = env.GenerateDebugSideTable( {kWasmI32}, {kWasmI32, kWasmI32}, @@ -426,7 +427,7 @@ TEST(Liftoff_debug_side_table_trap) { debug_side_table.get()); } -TEST(Liftoff_breakpoint_simple) { +TEST_F(LiftoffInspectionTest, Liftoff_breakpoint_simple) { LiftoffCompileEnvironment env; // Set two breakpoints. At both locations, values are live in registers. auto debug_side_table = env.GenerateDebugSideTable( @@ -448,7 +449,7 @@ TEST(Liftoff_breakpoint_simple) { debug_side_table.get()); } -TEST(Liftoff_debug_side_table_catch_all) { +TEST_F(LiftoffInspectionTest, Liftoff_debug_side_table_catch_all) { LiftoffCompileEnvironment env; TestSignatures sigs; int ex = env.builder()->AddException(sigs.v_v()); @@ -474,7 +475,7 @@ TEST(Liftoff_debug_side_table_catch_all) { debug_side_table.get()); } -TEST(Regress1199526) { +TEST_F(LiftoffInspectionTest, Regress1199526) { LiftoffCompileEnvironment env; ValueType exception_type = kWasmAnyRef.AsNonNull(); auto debug_side_table = env.GenerateDebugSideTable( diff --git a/deps/v8/test/unittests/wasm/liftoff-register-unittests.cc b/deps/v8/test/unittests/wasm/liftoff-register-unittests.cc index 9aa33ab9fc0d..8af6f0d49ad0 100644 --- a/deps/v8/test/unittests/wasm/liftoff-register-unittests.cc +++ b/deps/v8/test/unittests/wasm/liftoff-register-unittests.cc @@ -82,12 +82,8 @@ TEST_F(WasmRegisterTest, SpreadSetBitsToAdjacentFpRegs) { using LiftoffFrameAlignmentTest = TestWithIsolateAndZone; TEST_F(LiftoffFrameAlignmentTest, AlignFrameSizeAndPatchPrepareStackFrame) { - auto check_frame_alignment = [&](bool enforce_16byte_alignment, - bool feedback_vector_slot, + auto check_frame_alignment = [&](bool feedback_vector_slot, int used_spill_offset) { - FlagScope<bool> flag_scope(&v8_flags.enforce_x64_16byte_alignment, - enforce_16byte_alignment); - auto buffer = AllocateAssemblerBuffer(); LiftoffAssembler assm(zone(), buffer->CreateView()); assm.set_root_array_available(false); @@ -97,20 +93,30 @@ TEST_F(LiftoffFrameAlignmentTest, AlignFrameSizeAndPatchPrepareStackFrame) { // - Without feedback_vector_slot: EnterFrame(StackFrame::WASM) pushes 2 // slots (frame type marker and instance data). // - With feedback_vector_slot: WasmLiftoffFrameSetup pushes 3 slots (frame - // type marker, instance data, and feedback vector). + // type marker, instance data, and feedback vector), plus a zero into the + // 4th slot (the OSR target slot at rbp - kOSRTargetOffset) when + // V8_X64_16BYTE_STACK_ALIGNMENT_BOOL is enabled. assm.EnterFrame(StackFrame::WASM); if (feedback_vector_slot) { assm.Push(Immediate(0)); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + assm.Push(Immediate(0)); + } } int prepare_offset = assm.PrepareStackFrame(); assm.RecordUsedSpillOffset(used_spill_offset); assm.AlignFrameSize(); assm.PatchPrepareStackFrame(prepare_offset, &safepoint_table_builder, - feedback_vector_slot, /*stack_param_slots=*/0); + feedback_vector_slot, /*stack_param_slots=*/0, + /*stack_return_slots=*/0); assm.movq(rax, rbp); assm.subq(rax, rsp); + assm.movq(rcx, rsp); + assm.andq(rcx, Immediate(0xF)); + assm.shlq(rcx, Immediate(32)); + assm.orq(rax, rcx); assm.LeaveFrame(StackFrame::WASM); assm.ret(0); @@ -118,13 +124,17 @@ TEST_F(LiftoffFrameAlignmentTest, AlignFrameSizeAndPatchPrepareStackFrame) { assm.GetCode(isolate(), &desc); buffer->MakeExecutable(); auto fn = GeneratedCode<int64_t>::FromBuffer(isolate(), buffer->start()); - int64_t allocated_bytes_below_rbp = fn.Call(); + int64_t result = fn.Call(); + int32_t allocated_bytes_below_rbp = + static_cast<int32_t>(result & 0xFFFFFFFF); + int32_t rsp_misalignment = static_cast<int32_t>(result >> 32); EXPECT_EQ(allocated_bytes_below_rbp, assm.GetTotalFrameSize()); - if (enforce_16byte_alignment) { + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { int expected_bytes = RoundUp(used_spill_offset, 2 * kSystemPointerSize); EXPECT_EQ(expected_bytes, assm.GetTotalFrameSize()); EXPECT_EQ(0, allocated_bytes_below_rbp % (2 * kSystemPointerSize)); + EXPECT_EQ(0, rsp_misalignment); } else { int expected_bytes = RoundUp(used_spill_offset, kSystemPointerSize); EXPECT_EQ(expected_bytes, assm.GetTotalFrameSize()); @@ -136,8 +146,118 @@ TEST_F(LiftoffFrameAlignmentTest, AlignFrameSizeAndPatchPrepareStackFrame) { // 44 bytes (5.5 slots), 48 bytes (6 slots, even). for (bool feedback_vector_slot : {false, true}) { for (int spill_offset : {32, 36, 40, 44, 48}) { - check_frame_alignment(false, feedback_vector_slot, spill_offset); - check_frame_alignment(true, feedback_vector_slot, spill_offset); + check_frame_alignment(feedback_vector_slot, spill_offset); + } + } +} + +TEST_F(LiftoffFrameAlignmentTest, PushAndPopRegistersAlignment) { + auto check_push_pop = [&](LiftoffRegList regs) { + auto buffer = AllocateAssemblerBuffer(); + LiftoffAssembler assm(zone(), buffer->CreateView()); + assm.set_root_array_available(false); + SafepointTableBuilder safepoint_table_builder(zone()); + + assm.EnterFrame(StackFrame::WASM); + assm.movq(r8, rsp); + assm.PushRegisters(regs); + SafepointTableBuilder::Safepoint safepoint = + safepoint_table_builder.DefineSafepoint(&assm); + assm.RecordSpillsInSafepoint(safepoint, regs, LiftoffRegList{}, 0); + // Measure how many bytes PushRegisters allocated on the stack and check + // {rsp & 15 == 0} while registers are pushed. + assm.movq(r9, r8); + assm.subq(r9, rsp); + assm.movq(r11, rsp); + assm.andq(r11, Immediate(0xF)); + assm.PopRegisters(regs); + // Verify PopRegisters restored rsp back to r8. + assm.subq(r8, rsp); + assm.shlq(r8, Immediate(16)); + assm.orq(r8, r11); + assm.shlq(r8, Immediate(32)); + assm.orq(r9, r8); + assm.movq(rax, r9); + assm.LeaveFrame(StackFrame::WASM); + assm.ret(0); + + CodeDesc desc; + assm.GetCode(isolate(), &desc); + buffer->MakeExecutable(); + auto fn = GeneratedCode<int64_t>::FromBuffer(isolate(), buffer->start()); + int64_t result = fn.Call(); + int32_t pushed_bytes = static_cast<int32_t>(result & 0xFFFFFFFF); + int32_t rsp_misalignment = static_cast<int32_t>((result >> 32) & 0xFFFF); + int32_t leftover_bytes = static_cast<int32_t>(result >> 48); + + EXPECT_EQ(0, leftover_bytes); + int expected_gp_slots = (regs & kGpCacheRegList).GetNumRegsSet(); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL && (expected_gp_slots & 1) != 0) { + ++expected_gp_slots; + } + int expected_fp_bytes = + (regs & kFpCacheRegList).GetNumRegsSet() * kSimd128Size; + int expected_bytes = + expected_gp_slots * kSystemPointerSize + expected_fp_bytes; + EXPECT_EQ(expected_bytes, pushed_bytes); + EXPECT_EQ(expected_bytes / kSystemPointerSize, assm.OolSpillCount()); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + EXPECT_EQ(0, pushed_bytes % (2 * kSystemPointerSize)); + EXPECT_EQ(0, rsp_misalignment); + } + }; + + LiftoffRegister gp0 = LiftoffRegister(rax); + LiftoffRegister gp1 = LiftoffRegister(rcx); + LiftoffRegister gp2 = LiftoffRegister(rdx); + LiftoffRegister fp0 = LiftoffRegister(xmm0); + + check_push_pop(LiftoffRegList{gp0}); + check_push_pop(LiftoffRegList{gp0, gp1}); + check_push_pop(LiftoffRegList{gp0, gp1, gp2}); + check_push_pop(LiftoffRegList{gp0, fp0}); + check_push_pop(LiftoffRegList{gp0, gp1, fp0}); +} + +TEST_F(LiftoffFrameAlignmentTest, AllocateAndDeallocateStackSlotAlignment) { + for (uint32_t size : {8u, 16u, 40u}) { + auto buffer = AllocateAssemblerBuffer(); + LiftoffAssembler assm(zone(), buffer->CreateView()); + assm.set_root_array_available(false); + + assm.EnterFrame(StackFrame::WASM); + assm.movq(r8, rsp); + assm.AllocateStackSlot(rcx, size); + assm.movq(rax, r8); + assm.subq(rax, rsp); + assm.movq(r9, rsp); + assm.andq(r9, Immediate(0xF)); + assm.DeallocateStackSlot(size); + assm.subq(r8, rsp); + assm.shlq(r8, Immediate(16)); + assm.orq(r8, r9); + assm.shlq(r8, Immediate(32)); + assm.orq(rax, r8); + assm.LeaveFrame(StackFrame::WASM); + assm.ret(0); + + CodeDesc desc; + assm.GetCode(isolate(), &desc); + buffer->MakeExecutable(); + auto fn = GeneratedCode<int64_t>::FromBuffer(isolate(), buffer->start()); + int64_t result = fn.Call(); + int32_t allocated_bytes = static_cast<int32_t>(result & 0xFFFFFFFF); + int32_t rsp_misalignment = static_cast<int32_t>((result >> 32) & 0xFFFF); + int32_t leftover_bytes = static_cast<int32_t>(result >> 48); + + EXPECT_EQ(0, leftover_bytes); + if (V8_X64_16BYTE_STACK_ALIGNMENT_BOOL) { + int expected_bytes = RoundUp(size, 2 * kSystemPointerSize); + EXPECT_EQ(expected_bytes, allocated_bytes); + EXPECT_EQ(0, allocated_bytes % (2 * kSystemPointerSize)); + EXPECT_EQ(0, rsp_misalignment); + } else { + EXPECT_EQ(static_cast<int32_t>(size), allocated_bytes); } } } diff --git a/deps/v8/test/cctest/manually-externalized-buffer.h b/deps/v8/test/unittests/wasm/manually-externalized-buffer.h similarity index 76% rename from deps/v8/test/cctest/manually-externalized-buffer.h rename to deps/v8/test/unittests/wasm/manually-externalized-buffer.h index f26a7bccc053..8034e640e4b5 100644 --- a/deps/v8/test/cctest/manually-externalized-buffer.h +++ b/deps/v8/test/unittests/wasm/manually-externalized-buffer.h @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef V8_CCTEST_MANUALLY_EXTERNALIZED_BUFFER_H_ -#define V8_CCTEST_MANUALLY_EXTERNALIZED_BUFFER_H_ +#ifndef V8_UNITTESTS_WASM_MANUALLY_EXTERNALIZED_BUFFER_H_ +#define V8_UNITTESTS_WASM_MANUALLY_EXTERNALIZED_BUFFER_H_ #include "src/api/api-inl.h" -namespace v8::internal::testing { +namespace v8::internal::wasm { // Utility to free the allocated memory for a buffer that is manually // externalized in a test. @@ -25,6 +25,6 @@ struct ManuallyExternalizedBuffer { void* backing_store() { return backing_store_->Data(); } }; -} // namespace v8::internal::testing +} // namespace v8::internal::wasm -#endif // V8_CCTEST_MANUALLY_EXTERNALIZED_BUFFER_H_ +#endif // V8_UNITTESTS_WASM_MANUALLY_EXTERNALIZED_BUFFER_H_ diff --git a/deps/v8/test/unittests/wasm/memory-protection-unittest.cc b/deps/v8/test/unittests/wasm/memory-protection-unittest.cc index 6ac766961c80..ec00f119b576 100644 --- a/deps/v8/test/unittests/wasm/memory-protection-unittest.cc +++ b/deps/v8/test/unittests/wasm/memory-protection-unittest.cc @@ -12,6 +12,7 @@ #endif // V8_OS_POSIX && !V8_OS_FUCHSIA #include "src/base/macros.h" +#include "src/base/unique-array.h" #include "src/flags/flags.h" #include "src/wasm/code-space-access.h" #include "src/wasm/module-compiler.h" @@ -81,12 +82,11 @@ class MemoryProtectionTest : public TestWithNativeContext { SECTION(Function, ENTRY_COUNT(1), SIG_INDEX(0)), SECTION(Code, ENTRY_COUNT(1), ADD_COUNT(0 /* locals */, kExprEnd))}; - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(module_bytes); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(module_bytes); WasmDetectedFeatures detected_features; - ModuleResult result = - DecodeWasmModule(WasmEnabledFeatures::All(), bytes.as_vector(), false, - &detected_features); + ModuleResult result = DecodeWasmModule( + WasmEnabledFeatures::All(), bytes.as_span(), false, &detected_features); CHECK(result.ok()); ErrorThrower thrower(isolate(), ""); diff --git a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc index 6b82e0543703..124aeff8c079 100644 --- a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc @@ -4142,11 +4142,18 @@ TEST_F(WasmModuleVerifyTest, ContTypesBasic) { TEST_F(WasmModuleVerifyTest, ContTypesNonFunc) { WASM_FEATURE_SCOPE(wasmfx); + WASM_FEATURE_SCOPE(custom_descriptors); // Invalid cont type definition: must reference a function type static const uint8_t bad_cont_group[] = {SECTION( Type, ENTRY_COUNT(2), WASM_STRUCT_DEF(FIELD_COUNT(0)), CONT_ENTRY(0))}; EXPECT_FAILURE(bad_cont_group); + + // 'exact' prefix is not allowed in a cont type definition. + static const uint8_t exact_cont_group[] = {SECTION( + Type, ENTRY_COUNT(2), SIG_ENTRY_v_v, kWasmContTypeCode, kExactCode, 0)}; + EXPECT_FAILURE_WITH_MSG(exact_cont_group, + "cont type must refer to a signature index"); } TEST_F(WasmModuleVerifyTest, ContTypesSubtype) { diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-64.cc b/deps/v8/test/unittests/wasm/run-wasm-64-unittest.cc similarity index 99% rename from deps/v8/test/cctest/wasm/test-run-wasm-64.cc rename to deps/v8/test/unittests/wasm/run-wasm-64-unittest.cc index 6467f6eea8ad..87aa5e921339 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-64.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-64-unittest.cc @@ -11,17 +11,19 @@ #include "src/base/overflowing-math.h" #include "src/codegen/assembler-inl.h" #include "src/objects/objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_run_wasm_64 { +using RunWasm64Test = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasm64Test + WASM_EXEC_TEST(I64Const) { WasmRunner<int64_t> r(execution_tier); const int64_t kExpectedValue = 0x1122334455667788LL; @@ -1649,6 +1651,8 @@ WASM_EXEC_TEST(Regression_6858) { CHECK_TRAP64(r.Call(dividend, divisor, filler, filler)); } +#undef WASM_EXEC_TEST_SUITE + // clang-format gets confused about these closing parentheses (wants to change // the first comment to "// namespace v8". Disable it. // clang-format off diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc b/deps/v8/test/unittests/wasm/run-wasm-atomics-unittest.cc similarity index 99% rename from deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc rename to deps/v8/test/unittests/wasm/run-wasm-atomics-unittest.cc index b53f6f8247c9..b407fa471910 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-atomics.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-atomics-unittest.cc @@ -2,14 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/cctest/wasm/wasm-atomics-utils.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-atomics-utils.h" namespace v8 { namespace internal { namespace wasm { namespace test_run_wasm_atomics { +using RunWasmAtomicsTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmAtomicsTest + void RunU32BinOp(TestExecutionTier execution_tier, WasmOpcode wasm_op, Uint32BinOp expected_op) { WasmRunner<uint32_t, uint32_t> r(execution_tier); @@ -574,6 +577,8 @@ WASM_EXEC_TEST(I64AtomicCompareExchange_trap) { CHECK_TRAP64(r.Call()); } +#undef WASM_EXEC_TEST_SUITE + } // namespace test_run_wasm_atomics } // namespace wasm } // namespace internal diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc b/deps/v8/test/unittests/wasm/run-wasm-atomics64-unittest.cc similarity index 99% rename from deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc rename to deps/v8/test/unittests/wasm/run-wasm-atomics64-unittest.cc index ffc567d7500c..a59d271ae6c0 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-atomics64.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-atomics64-unittest.cc @@ -2,14 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/cctest/wasm/wasm-atomics-utils.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-atomics-utils.h" namespace v8 { namespace internal { namespace wasm { namespace test_run_wasm_atomics_64 { +using RunWasmAtomics64Test = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmAtomics64Test + void RunU64BinOp(TestExecutionTier execution_tier, WasmOpcode wasm_op, Uint64BinOp expected_op) { WasmRunner<uint64_t, uint64_t> r(execution_tier); @@ -814,6 +817,8 @@ WASM_EXEC_TEST(I64AtomicCompareExchange32UZeroExtended) { CHECK_EQ(1, r.Call()); } +#undef WASM_EXEC_TEST_SUITE + } // namespace test_run_wasm_atomics_64 } // namespace wasm } // namespace internal diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-bulk-memory.cc b/deps/v8/test/unittests/wasm/run-wasm-bulk-memory-unittest.cc similarity index 98% rename from deps/v8/test/cctest/wasm/test-run-wasm-bulk-memory.cc rename to deps/v8/test/unittests/wasm/run-wasm-bulk-memory-unittest.cc index b95da6014af2..4dd01edf6df7 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-bulk-memory.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-bulk-memory-unittest.cc @@ -3,16 +3,18 @@ // found in the LICENSE file. #include "src/wasm/wasm-module-builder.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_run_wasm_bulk_memory { +using RunWasmBulkMemoryTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmBulkMemoryTest + namespace { void CheckMemoryEquals(TestingModuleBuilder* builder, size_t index, const std::vector<uint8_t>& expected) { @@ -385,7 +387,7 @@ void CheckTableCall(Isolate* isolate, DirectHandle<WasmTableObject> table, void TestTableCopyElems(TestExecutionTier execution_tier, int table_dst, int table_src) { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); TestSignatures sigs; WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier); @@ -462,7 +464,7 @@ WASM_COMPILED_EXEC_TEST(TableCopyElemsFrom6To6) { void TestTableCopyCalls(TestExecutionTier execution_tier, int table_dst, int table_src) { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); TestSignatures sigs; WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier); @@ -532,7 +534,7 @@ WASM_COMPILED_EXEC_TEST(TableCopyCallsTo6From6) { void TestTableCopyOobWrites(TestExecutionTier execution_tier, int table_dst, int table_src) { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); TestSignatures sigs; WasmRunner<uint32_t, uint32_t, uint32_t, uint32_t> r(execution_tier); @@ -655,6 +657,8 @@ WASM_COMPILED_EXEC_TEST(TableCopyOob1From6To6) { TestTableCopyOob1(execution_tier, 6, 6); } +#undef WASM_EXEC_TEST_SUITE + } // namespace test_run_wasm_bulk_memory } // namespace wasm } // namespace internal diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-exceptions.cc b/deps/v8/test/unittests/wasm/run-wasm-exceptions-unittest.cc similarity index 95% rename from deps/v8/test/cctest/wasm/test-run-wasm-exceptions.cc rename to deps/v8/test/unittests/wasm/run-wasm-exceptions-unittest.cc index c89a58cac835..f8d8fc71a647 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-exceptions.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-exceptions-unittest.cc @@ -4,12 +4,17 @@ #include "include/v8-function.h" #include "src/api/api-inl.h" -#include "test/cctest/wasm/wasm-atomics-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-atomics-utils.h" namespace v8::internal::wasm { +using RunWasmExceptionsTest = WasmExecutionTestBase; +using RunWasmExceptionsUninitializedTest = WasmUninitializedTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmExceptionsTest +#define WASM_UNINITIALIZED_EXEC_TEST_SUITE RunWasmExceptionsUninitializedTest + WASM_EXEC_TEST(TryCatchThrow) { TestSignatures sigs; WasmRunner<uint32_t, uint32_t> r(execution_tier); @@ -348,7 +353,7 @@ WASM_EXEC_TEST(TryCatchAllCallIndirect) { WASM_COMPILED_EXEC_TEST(TryCatchCallExternal) { TestSignatures sigs; - HandleScope scope(CcTest::InitIsolateOnce()); + HandleScope scope(WasmExecutionTestBase::InitIsolateOnce()); const char* source = "(function() { throw 'ball'; })"; DirectHandle<JSFunction> js_function = Cast<JSFunction>(v8::Utils::OpenDirectHandle( @@ -376,7 +381,7 @@ WASM_COMPILED_EXEC_TEST(TryCatchCallExternal) { WASM_COMPILED_EXEC_TEST(TryCatchAllCallExternal) { TestSignatures sigs; - HandleScope scope(CcTest::InitIsolateOnce()); + HandleScope scope(WasmExecutionTestBase::InitIsolateOnce()); const char* source = "(function() { throw 'ball'; })"; DirectHandle<JSFunction> js_function = Cast<JSFunction>(v8::Utils::OpenDirectHandle( @@ -466,39 +471,14 @@ WASM_EXEC_TEST(TryCatchTrapTableFill) { TestTrapNotCaught(code, arraysize(code), execution_tier); } -namespace { -// TODO(cleanup): Define in cctest.h and reuse where appropriate. -class IsolateScope { - public: - IsolateScope() { - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - isolate_ = v8::Isolate::New(create_params); - isolate_->Enter(); - } - - ~IsolateScope() { - isolate_->Exit(); - isolate_->Dispose(); - } - - v8::Isolate* isolate() { return isolate_; } - Isolate* i_isolate() { return reinterpret_cast<Isolate*>(isolate_); } - - private: - v8::Isolate* isolate_; -}; -} // namespace - UNINITIALIZED_WASM_EXEC_TEST(TestStackOverflowNotCaught) { TestSignatures sigs; // v8_flags.stack_size must be set before isolate initialization. FlagScope<int32_t> stack_size(&v8_flags.stack_size, 8); - IsolateScope isolate_scope; - LocalContext context(isolate_scope.isolate()); + IsolateWithContextWrapper isolate_scope; - WasmRunner<uint32_t> r(isolate_scope.i_isolate(), execution_tier); + WasmRunner<uint32_t> r(isolate_scope.isolate(), execution_tier); // Build a function that calls itself until stack overflow. WasmFunctionCompiler& stack_overflow = r.NewFunction(sigs.v_v()); @@ -516,4 +496,7 @@ UNINITIALIZED_WASM_EXEC_TEST(TestStackOverflowNotCaught) { r.CheckCallViaJSTraps(); } +#undef WASM_EXEC_TEST_SUITE +#undef WASM_UNINITIALIZED_EXEC_TEST_SUITE + } // namespace v8::internal::wasm diff --git a/deps/v8/test/unittests/wasm/run-wasm-f16-unittest.cc b/deps/v8/test/unittests/wasm/run-wasm-f16-unittest.cc new file mode 100644 index 000000000000..8c155c4d5fa2 --- /dev/null +++ b/deps/v8/test/unittests/wasm/run-wasm-f16-unittest.cc @@ -0,0 +1,855 @@ +// Copyright 2024 the V8 project 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 "src/base/overflowing-math.h" +#include "src/base/utils/random-number-generator.h" +#include "src/codegen/assembler-inl.h" +#include "src/numbers/conversions.h" +#include "src/wasm/wasm-opcodes.h" +#include "test/common/wasm/test-signatures.h" +#include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" +#include "test/unittests/wasm/wasm-simd-utils.h" +#include "third_party/fp16/src/include/fp16.h" + +namespace v8 { +namespace internal { +namespace wasm { +namespace test_run_wasm_f16 { + +using RunWasmF16Test = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmF16Test + +WASM_EXEC_TEST(F16Load) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<float> r(execution_tier); + uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(4); + r.Build({WASM_F16_LOAD_MEM(WASM_I32V_1(4))}); + r.builder().WriteMemory(&memory[2], fp16_ieee_from_fp32_value(2.75)); + CHECK_EQ(2.75f, r.Call()); +} + +WASM_EXEC_TEST(F16Store) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t> r(execution_tier); + uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(4); + r.Build({WASM_F16_STORE_MEM(WASM_I32V_1(4), WASM_F32(2.75)), WASM_ZERO}); + r.Call(); + CHECK_EQ(r.builder().ReadMemory(&memory[2]), fp16_ieee_from_fp32_value(2.75)); +} + +WASM_EXEC_TEST(F16x8Splat) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, float> r(execution_tier); + // Set up a global to hold output vector. + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + uint8_t param1 = 0; + r.Build({WASM_GLOBAL_SET(0, WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(param1))), + WASM_ONE}); + + FOR_FLOAT32_INPUTS(x) { + r.Call(x); + uint16_t expected = fp16_ieee_from_fp32_value(x); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 8; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + if (std::isnan(x)) { + CHECK(isnan(actual_lane)); + } else { + CHECK_EQ(actual_lane, expected); + } + } + } +} + +WASM_EXEC_TEST(F16x8ReplaceLane) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t> r(execution_tier); + // Set up a global to hold output vector. + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + // Build function to replace each lane with its (FP) index. + r.Build({WASM_SIMD_F16x8_SPLAT(WASM_F32(3.14159f)), + WASM_F32(0.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 0, + WASM_F32(1.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 1, + WASM_F32(2.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 2, + WASM_F32(3.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 3, + WASM_F32(4.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 4, + WASM_F32(5.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 5, + WASM_F32(6.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 6, + WASM_F32(7.0f), + WASM_SIMD_OP(kExprF16x8ReplaceLane), + 7, + kExprGlobalSet, + 0, + WASM_ONE}); + + r.Call(); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 8; i++) { + CHECK_EQ(fp16_ieee_from_fp32_value(static_cast<float>(i)), + LANE(actual.to_i16x8(), i)); + } +} + +WASM_EXEC_TEST(F16x8ExtractLane) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t> r(execution_tier); + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + const WasmGlobal* globals[8]; + std::array<int16_t, 8> g_val; + for (int i = 0; i < 8; i++) { + LANE(g_val, i) = + static_cast<int16_t>(fp16_ieee_from_fp32_value(static_cast<float>(i))); + globals[i] = r.builder().AddGlobal(kWasmF32); + } + r.builder().WriteGlobal(*g, WasmValue(Simd128(g_val))); + + r.Build( + {WASM_GLOBAL_SET(1, WASM_SIMD_F16x8_EXTRACT_LANE(0, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(2, WASM_SIMD_F16x8_EXTRACT_LANE(1, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(3, WASM_SIMD_F16x8_EXTRACT_LANE(2, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(4, WASM_SIMD_F16x8_EXTRACT_LANE(3, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(5, WASM_SIMD_F16x8_EXTRACT_LANE(4, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(6, WASM_SIMD_F16x8_EXTRACT_LANE(5, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(7, WASM_SIMD_F16x8_EXTRACT_LANE(6, WASM_GLOBAL_GET(0))), + WASM_GLOBAL_SET(8, WASM_SIMD_F16x8_EXTRACT_LANE(7, WASM_GLOBAL_GET(0))), + WASM_ONE}); + + r.Call(); + for (int i = 0; i < 8; i++) { + CHECK_EQ(r.builder().ReadGlobal(*globals[i]).to_f32(), i); + } +} + +#define UN_OP_LIST(V) \ + V(Abs, std::abs) \ + V(Neg, -) \ + V(Sqrt, std::sqrt) \ + V(Ceil, ceilf) \ + V(Floor, floorf) \ + V(Trunc, truncf) \ + V(NearestInt, nearbyintf) + +#define TEST_UN_OP(WasmName, COp) \ + uint16_t WasmName##F16(uint16_t a) { \ + return fp16_ieee_from_fp32_value(COp(fp16_ieee_to_fp32_value(a))); \ + } \ + WASM_EXEC_TEST(F16x8##WasmName) { \ + i::v8_flags.wasm_fp16 = true; \ + RunF16x8UnOpTest(execution_tier, kExprF16x8##WasmName, WasmName##F16); \ + } + +UN_OP_LIST(TEST_UN_OP) + +#undef TEST_UN_OP +#undef UN_OP_LIST + +#define CMP_OP_LIST(V) \ + V(Eq, ==) \ + V(Ne, !=) \ + V(Gt, >) \ + V(Ge, >=) \ + V(Lt, <) \ + V(Le, <=) + +#define TEST_CMP_OP(WasmName, COp) \ + int16_t WasmName(uint16_t a, uint16_t b) { \ + return fp16_ieee_to_fp32_value(a) COp fp16_ieee_to_fp32_value(b) ? -1 : 0; \ + } \ + WASM_EXEC_TEST(F16x8##WasmName) { \ + i::v8_flags.wasm_fp16 = true; \ + RunF16x8CompareOpTest(execution_tier, kExprF16x8##WasmName, WasmName); \ + } + +CMP_OP_LIST(TEST_CMP_OP) + +#undef TEST_CMP_OP +#undef UN_CMP_LIST + +float Add(float a, float b) { return a + b; } +float Sub(float a, float b) { return a - b; } +float Mul(float a, float b) { return a * b; } + +#define BIN_OP_LIST(V) \ + V(Add, Add) \ + V(Sub, Sub) \ + V(Mul, Mul) \ + V(Div, base::Divide) \ + V(Min, JSMin) \ + V(Max, JSMax) \ + V(Pmin, Minimum) \ + V(Pmax, Maximum) + +#define TEST_BIN_OP(WasmName, COp) \ + uint16_t WasmName##F16(uint16_t a, uint16_t b) { \ + return fp16_ieee_from_fp32_value( \ + COp(fp16_ieee_to_fp32_value(a), fp16_ieee_to_fp32_value(b))); \ + } \ + WASM_EXEC_TEST(F16x8##WasmName) { \ + i::v8_flags.wasm_fp16 = true; \ + RunF16x8BinOpTest(execution_tier, kExprF16x8##WasmName, WasmName##F16); \ + } + +BIN_OP_LIST(TEST_BIN_OP) + +#undef TEST_BIN_OP +#undef BIN_OP_LIST + +WASM_COMPILED_EXEC_TEST(F16x8AddRaw) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t> r(execution_tier); + constexpr int kLanes = 8; + // Two inputs and three outputs: a+b, a+a, and (a+b)+a. + uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(5 * kLanes); + uint8_t lhs = r.AllocateLocal(kWasmS128); + uint8_t rhs = r.AllocateLocal(kWasmS128); + uint8_t sum = r.AllocateLocal(kWasmS128); + r.Build( + {WASM_LOCAL_SET(lhs, WASM_SIMD_LOAD_MEM(WASM_ZERO)), + WASM_LOCAL_SET(rhs, WASM_SIMD_LOAD_MEM(WASM_I32V(16))), + WASM_LOCAL_SET(sum, WASM_SIMD_BINOP(kExprF16x8Add, WASM_LOCAL_GET(lhs), + WASM_LOCAL_GET(rhs))), + WASM_SIMD_STORE_MEM(WASM_I32V(32), WASM_LOCAL_GET(sum)), + WASM_SIMD_STORE_MEM(WASM_I32V(48), + WASM_SIMD_BINOP(kExprF16x8Add, WASM_LOCAL_GET(lhs), + WASM_LOCAL_GET(lhs))), + WASM_SIMD_STORE_MEM(WASM_I32V(64), + WASM_SIMD_BINOP(kExprF16x8Add, WASM_LOCAL_GET(sum), + WASM_LOCAL_GET(lhs))), + WASM_ONE}); + + auto check_lane = [](uint16_t a, uint16_t b, uint16_t expected, + uint16_t actual) { + if (!isnan(expected)) { + CHECK_EQ(expected, actual); // Includes the sign of zero. + return; + } + // The reference FP32-to-FP16 conversion canonicalizes NaNs. Check raw + // operands instead: Wasm requires a canonical NaN if all NaN inputs are + // canonical, and otherwise permits any arithmetic (quiet) NaN. + CHECK_EQ(0x7e00, actual & 0x7e00); + if ((!isnan(a) || IsCanonical(a)) && (!isnan(b) || IsCanonical(b))) { + CHECK(IsCanonical(actual)); + } + }; + auto check = [&]() { + CHECK_EQ(1, r.Call()); + for (int lane = 0; lane < kLanes; ++lane) { + uint16_t a = r.builder().ReadMemory(&memory[lane]); + uint16_t b = r.builder().ReadMemory(&memory[kLanes + lane]); + uint16_t expected_sum = AddF16(a, b); + uint16_t actual_sum = r.builder().ReadMemory(&memory[2 * kLanes + lane]); + check_lane(a, b, expected_sum, actual_sum); + check_lane(a, a, AddF16(a, a), + r.builder().ReadMemory(&memory[3 * kLanes + lane])); + // Use the already-checked intermediate's actual NaN class. + check_lane(actual_sum, a, AddF16(expected_sum, a), + r.builder().ReadMemory(&memory[4 * kLanes + lane])); + } + }; + + // Raw bits avoid splat conversions quieting NaNs or hiding subnormals. + constexpr uint16_t inputs[] = { + 0x0000, 0x8000, // +/- zero + 0x0001, 0x8001, 0x03ff, 0x83ff, // Subnormal boundaries + 0x0400, 0x8400, 0x0401, 0x8401, // Normal/subnormal cancellation + 0x1000, 0x9000, // Half an ULP at 1: ties to even + 0x3bff, 0x3c00, 0xbc00, 0x3c01, 0xbc01, 0x4000, 0xc000, // Around +/-1 + 0x7bff, 0xfbff, // Largest finite values / overflow + 0x7c00, 0xfc00, // Infinities + 0x7c01, 0xfc01, 0x7dff, 0xfdff, // Signaling NaNs + 0x7e00, 0xfe00, 0x7e55, 0xfe55, 0x7fff, 0xffff}; // Quiet NaNs + for (size_t i = 0; i < arraysize(inputs); i += kLanes) { + for (size_t j = 0; j < arraysize(inputs); ++j) { + for (int lane = 0; lane < kLanes; ++lane) { + r.builder().WriteMemory(&memory[lane], + inputs[(i + lane) % arraysize(inputs)]); + r.builder().WriteMemory(&memory[kLanes + lane], + inputs[(j + 3 * lane) % arraysize(inputs)]); + } + check(); + } + } + + base::RandomNumberGenerator rng(v8_flags.random_seed); + for (int trial = 0; trial < 512; ++trial) { + for (int lane = 0; lane < 2 * kLanes; ++lane) { + r.builder().WriteMemory(&memory[lane], + static_cast<uint16_t>(rng.NextInt(65536))); + } + check(); + } +} + +WASM_COMPILED_EXEC_TEST(F16x8SubRaw) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t> runner(execution_tier); + constexpr int kLanes = 8; + uint16_t* memory = runner.builder().AddMemoryElems<uint16_t>(10 * kLanes); + uint8_t lhs = runner.AllocateLocal(kWasmS128); + uint8_t rhs = runner.AllocateLocal(kWasmS128); + uint8_t difference = runner.AllocateLocal(kWasmS128); + runner.Build( + {WASM_LOCAL_SET(lhs, WASM_SIMD_LOAD_MEM(WASM_ZERO)), + WASM_LOCAL_SET(rhs, WASM_SIMD_LOAD_MEM(WASM_I32V(16))), + WASM_LOCAL_SET(difference, + WASM_SIMD_BINOP(kExprF16x8Sub, WASM_LOCAL_GET(lhs), + WASM_LOCAL_GET(rhs))), + WASM_SIMD_STORE_MEM(WASM_I32V(32), WASM_LOCAL_GET(difference)), + WASM_SIMD_STORE_MEM(WASM_I32V(48), + WASM_SIMD_BINOP(kExprF16x8Sub, WASM_LOCAL_GET(lhs), + WASM_LOCAL_GET(lhs))), + WASM_SIMD_STORE_MEM(WASM_I32V(64), + WASM_SIMD_BINOP(kExprF16x8Sub, WASM_LOCAL_GET(rhs), + WASM_LOCAL_GET(lhs))), + WASM_SIMD_STORE_MEM(WASM_I32V(80), + WASM_SIMD_BINOP(kExprF16x8Sub, WASM_LOCAL_GET(lhs), + WASM_LOCAL_GET(difference))), + WASM_SIMD_STORE_MEM( + WASM_I32V(96), + WASM_SIMD_BINOP(kExprF16x8Sub, WASM_SIMD_LOAD_MEM(WASM_ZERO), + WASM_LOCAL_GET(rhs))), + WASM_SIMD_STORE_MEM(WASM_I32V(112), + WASM_SIMD_BINOP(kExprF16x8Sub, WASM_LOCAL_GET(lhs), + WASM_SIMD_LOAD_MEM(WASM_I32V(16)))), + WASM_SIMD_STORE_MEM(WASM_I32V(128), WASM_LOCAL_GET(lhs)), + WASM_SIMD_STORE_MEM(WASM_I32V(144), WASM_LOCAL_GET(rhs)), WASM_ONE}); + + auto check_lane = [](uint16_t lhs_bits, uint16_t rhs_bits, uint16_t expected, + uint16_t actual) { + if (!isnan(expected)) { + CHECK_EQ(expected, actual); + return; + } + CHECK_EQ(0x7e00, actual & 0x7e00); + if ((!isnan(lhs_bits) || IsCanonical(lhs_bits)) && + (!isnan(rhs_bits) || IsCanonical(rhs_bits))) { + CHECK(IsCanonical(actual)); + } + }; + auto check = [&]() { + CHECK_EQ(1, runner.Call()); + for (int lane = 0; lane < kLanes; ++lane) { + uint16_t lhs_bits = runner.builder().ReadMemory(&memory[lane]); + uint16_t rhs_bits = runner.builder().ReadMemory(&memory[kLanes + lane]); + uint16_t expected_difference = SubF16(lhs_bits, rhs_bits); + uint16_t actual_difference = + runner.builder().ReadMemory(&memory[2 * kLanes + lane]); + check_lane(lhs_bits, rhs_bits, expected_difference, actual_difference); + check_lane(lhs_bits, lhs_bits, SubF16(lhs_bits, lhs_bits), + runner.builder().ReadMemory(&memory[3 * kLanes + lane])); + check_lane(rhs_bits, lhs_bits, SubF16(rhs_bits, lhs_bits), + runner.builder().ReadMemory(&memory[4 * kLanes + lane])); + check_lane(lhs_bits, actual_difference, + SubF16(lhs_bits, expected_difference), + runner.builder().ReadMemory(&memory[5 * kLanes + lane])); + for (int slot : {6, 7}) { + check_lane(lhs_bits, rhs_bits, expected_difference, + runner.builder().ReadMemory(&memory[slot * kLanes + lane])); + } + CHECK_EQ(lhs_bits, + runner.builder().ReadMemory(&memory[8 * kLanes + lane])); + CHECK_EQ(rhs_bits, + runner.builder().ReadMemory(&memory[9 * kLanes + lane])); + } + }; + + constexpr uint16_t inputs[] = { + 0x0000, 0x8000, 0x0001, 0x8001, 0x03ff, 0x83ff, 0x0400, 0x8400, 0x0401, + 0x8401, 0x1000, 0x9000, 0x3bff, 0x3c00, 0xbc00, 0x3c01, 0xbc01, 0x4000, + 0xc000, 0x7bff, 0xfbff, 0x7c00, 0xfc00, 0x7c01, 0xfc01, 0x7dff, 0xfdff, + 0x7e00, 0xfe00, 0x7e55, 0xfe55, 0x7fff, 0xffff}; + for (size_t left = 0; left < arraysize(inputs); left += kLanes) { + for (size_t right = 0; right < arraysize(inputs); ++right) { + for (int lane = 0; lane < kLanes; ++lane) { + runner.builder().WriteMemory(&memory[lane], + inputs[(left + lane) % arraysize(inputs)]); + runner.builder().WriteMemory( + &memory[kLanes + lane], + inputs[(right + 3 * lane) % arraysize(inputs)]); + } + check(); + } + } + + base::RandomNumberGenerator rng(v8_flags.random_seed); + for (int trial = 0; trial < 512; ++trial) { + for (int lane = 0; lane < 2 * kLanes; ++lane) { + runner.builder().WriteMemory(&memory[lane], + static_cast<uint16_t>(rng.NextInt(65536))); + } + check(); + } +} + +WASM_EXEC_TEST(F16x8ConvertI16x8) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, int32_t> r(execution_tier); + // Create two output vectors to hold signed and unsigned results. + const WasmGlobal* g0 = r.builder().AddGlobal(kWasmS128); + const WasmGlobal* g1 = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform conversions, and write the results. + uint8_t value = 0; + uint8_t temp1 = r.AllocateLocal(kWasmS128); + r.Build({WASM_LOCAL_SET(temp1, WASM_SIMD_I16x8_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(kExprF16x8SConvertI16x8, + WASM_LOCAL_GET(temp1))), + WASM_GLOBAL_SET(1, WASM_SIMD_UNOP(kExprF16x8UConvertI16x8, + WASM_LOCAL_GET(temp1))), + WASM_ONE}); + + FOR_INT16_INPUTS(x) { + r.Call(x); + uint16_t expected_signed = fp16_ieee_from_fp32_value(static_cast<float>(x)); + uint16_t expected_unsigned = + fp16_ieee_from_fp32_value(static_cast<float>(static_cast<uint16_t>(x))); + Simd128 actual0 = r.builder().ReadGlobal(*g0).to_s128(); + Simd128 actual1 = r.builder().ReadGlobal(*g1).to_s128(); + for (int i = 0; i < 8; i++) { + CHECK_EQ(expected_signed, ULANE(actual0.to_i16x8(), i)); + CHECK_EQ(expected_unsigned, LANE(actual1.to_i16x8(), i)); + } + } +} + +int16_t ConvertToInt(uint16_t f16, bool unsigned_result) { + float f32 = fp16_ieee_to_fp32_value(f16); + if (std::isnan(f32)) return 0; + if (unsigned_result) { + if (f32 > float{kMaxUInt16}) return static_cast<uint16_t>(kMaxUInt16); + if (f32 < 0) return 0; + return static_cast<uint16_t>(f32); + } else { + if (f32 > float{kMaxInt16}) return static_cast<int16_t>(kMaxInt16); + if (f32 < float{kMinInt16}) return static_cast<int16_t>(kMinInt16); + return static_cast<int16_t>(f32); + } +} + +// Tests both signed and unsigned conversion. +WASM_EXEC_TEST(I16x8ConvertF16x8) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, float> r(execution_tier); + // Create two output vectors to hold signed and unsigned results. + const WasmGlobal* g0 = r.builder().AddGlobal(kWasmS128); + const WasmGlobal* g1 = r.builder().AddGlobal(kWasmS128); + // Build fn to splat test value, perform conversions, and write the results. + uint8_t value = 0; + uint8_t temp1 = r.AllocateLocal(kWasmS128); + r.Build({WASM_LOCAL_SET(temp1, WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value))), + WASM_GLOBAL_SET(0, WASM_SIMD_UNOP(kExprI16x8SConvertF16x8, + WASM_LOCAL_GET(temp1))), + WASM_GLOBAL_SET(1, WASM_SIMD_UNOP(kExprI16x8UConvertF16x8, + WASM_LOCAL_GET(temp1))), + WASM_ONE}); + + FOR_FLOAT32_INPUTS(x) { + if (!PlatformCanRepresent(x)) continue; + r.Call(x); + int16_t expected_signed = ConvertToInt(fp16_ieee_from_fp32_value(x), false); + uint16_t expected_unsigned = + ConvertToInt(fp16_ieee_from_fp32_value(x), true); + Simd128 actual0 = r.builder().ReadGlobal(*g0).to_s128(); + Simd128 actual1 = r.builder().ReadGlobal(*g1).to_s128(); + for (int i = 0; i < 8; i++) { + CHECK_EQ(expected_signed, LANE(actual0.to_i16x8(), i)); + CHECK_EQ(expected_unsigned, ULANE(actual1.to_i16x8(), i)); + } + } +} + +WASM_EXEC_TEST(F16x8DemoteF32x4Zero) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, float> r(execution_tier); + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + r.Build({WASM_GLOBAL_SET( + 0, WASM_SIMD_UNOP(kExprF16x8DemoteF32x4Zero, + WASM_SIMD_F32x4_SPLAT(WASM_LOCAL_GET(0)))), + WASM_ONE}); + + FOR_FLOAT32_INPUTS(x) { + r.Call(x); + uint16_t expected = fp16_ieee_from_fp32_value(x); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 4; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + CheckFloat16LaneResult(x, x, expected, actual_lane, true); + } + for (int i = 4; i < 8; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + CheckFloat16LaneResult(x, x, 0, actual_lane, true); + } + } +} + +WASM_EXEC_TEST(F16x8DemoteF64x2Zero) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, double> r(execution_tier); + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + r.Build({WASM_GLOBAL_SET( + 0, WASM_SIMD_UNOP(kExprF16x8DemoteF64x2Zero, + WASM_SIMD_F64x2_SPLAT(WASM_LOCAL_GET(0)))), + WASM_ONE}); + + FOR_FLOAT64_INPUTS(x) { + r.Call(x); + uint16_t expected = DoubleToFloat16(x); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 2; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + CheckFloat16LaneResult(x, x, expected, actual_lane, true); + } + for (int i = 2; i < 8; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + CheckFloat16LaneResult(x, x, 0, actual_lane, true); + } + } +} + +WASM_EXEC_TEST(F32x4PromoteLowF16x8) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, float> r(execution_tier); + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + r.Build({WASM_GLOBAL_SET( + 0, WASM_SIMD_UNOP(kExprF32x4PromoteLowF16x8, + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(0)))), + WASM_ONE}); + + FOR_FLOAT32_INPUTS(x) { + r.Call(x); + float expected = fp16_ieee_to_fp32_value(fp16_ieee_from_fp32_value(x)); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 4; i++) { + float actual_lane = LANE(actual.to_f32x4(), i); + CheckFloatResult(x, x, expected, actual_lane, true); + } + } +} + +// A binary16 product has at most 22 significant bits. Binary64 retains the +// product and any addend capable of affecting binary16 rounding, including +// perturbations of a halfway product. Convert directly to half: going through +// float can erase those perturbations and introduce double rounding. +uint16_t FmaF16(uint16_t a, uint16_t b, uint16_t c, bool negate, + bool through_float = false) { + double lhs = fp16_ieee_to_fp32_value(a); + double rhs = fp16_ieee_to_fp32_value(b); + double acc = fp16_ieee_to_fp32_value(c); + if (negate) lhs = -lhs; + if (through_float) { + return fp16_ieee_from_fp32_value(std::fma(static_cast<float>(lhs), + static_cast<float>(rhs), + static_cast<float>(acc))); + } + return DoubleToFloat16(std::fma(lhs, rhs, acc)); +} + +TEST_F(RunWasmF16Test, F16x8FmaReference) { + for (bool negate : {false, true}) { + uint16_t sign = negate ? 0x8000 : 0; + // A tiny addend changes which side of a half-way product is rounded. + CHECK_EQ(0x3e01, FmaF16(0x3e00 ^ sign, 0x3c01, 0x8001, negate)); + CHECK_EQ(0x3e02, FmaF16(0x3e00 ^ sign, 0x3c01, 0x8001, negate, true)); + CHECK_EQ(0x3e05, FmaF16(0x3e00 ^ sign, 0x3c03, 0x0001, negate)); + CHECK_EQ(0x3e04, FmaF16(0x3e00 ^ sign, 0x3c03, 0x0001, negate, true)); + // (1 + 2^-10) * (1 - 2^-10) - 1 = -2^-20, not zero. + CHECK_EQ(0x8010, FmaF16(0x3c01 ^ sign, 0x3bfe, 0xbc00, negate)); + CHECK_EQ(0x0000, FmaF16(0x3c00 ^ sign, 0x3c00, 0xbc00, negate)); + CHECK_EQ(0x8000, FmaF16(0x8000 ^ sign, 0x3c00, 0x8000, negate)); + CHECK_EQ(0x0000, FmaF16(0x0001 ^ sign, 0x3800, 0x0000, negate)); + CHECK_EQ(0x0002, FmaF16(0x0003 ^ sign, 0x3800, 0x0000, negate)); + } +} + +void RunF16x8FmaRaw(TestExecutionTier execution_tier, bool negate) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t> r(execution_tier); + constexpr int kLanes = 8; + // Three inputs, thirteen FMA results, and three copies of the live inputs. + uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(19 * kLanes); + uint8_t a = r.AllocateLocal(kWasmS128); + uint8_t b = r.AllocateLocal(kWasmS128); + uint8_t c = r.AllocateLocal(kWasmS128); + uint8_t result = r.AllocateLocal(kWasmS128); + WasmOpcode opcode = negate ? kExprF16x8Qfms : kExprF16x8Qfma; + r.Build( + {WASM_LOCAL_SET(a, WASM_SIMD_LOAD_MEM(WASM_ZERO)), + WASM_LOCAL_SET(b, WASM_SIMD_LOAD_MEM(WASM_I32V(16))), + WASM_LOCAL_SET(c, WASM_SIMD_LOAD_MEM(WASM_I32V(32))), + WASM_LOCAL_SET(result, + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), + WASM_LOCAL_GET(b), WASM_LOCAL_GET(c))), + WASM_SIMD_STORE_MEM(WASM_I32V(48), WASM_LOCAL_GET(result)), + WASM_SIMD_STORE_MEM( + WASM_I32V(64), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(a), + WASM_LOCAL_GET(c))), + WASM_SIMD_STORE_MEM( + WASM_I32V(80), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(b), + WASM_LOCAL_GET(a))), + WASM_SIMD_STORE_MEM( + WASM_I32V(96), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(b), + WASM_LOCAL_GET(b))), + WASM_SIMD_STORE_MEM( + WASM_I32V(112), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(a), + WASM_LOCAL_GET(a))), + WASM_SIMD_STORE_MEM( + WASM_I32V(128), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(b), + WASM_LOCAL_GET(result))), + WASM_SIMD_STORE_MEM( + WASM_I32V(192), + WASM_SIMD_TERNOP(opcode, WASM_SIMD_LOAD_MEM(WASM_ZERO), + WASM_LOCAL_GET(b), WASM_LOCAL_GET(c))), + WASM_SIMD_STORE_MEM(WASM_I32V(208), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), + WASM_SIMD_LOAD_MEM(WASM_I32V(16)), + WASM_LOCAL_GET(c))), + WASM_SIMD_STORE_MEM( + WASM_I32V(224), + WASM_SIMD_TERNOP(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(b), + WASM_SIMD_LOAD_MEM(WASM_I32V(32)))), + WASM_SIMD_STORE_MEM(WASM_I32V(144), WASM_LOCAL_GET(a)), + WASM_SIMD_STORE_MEM(WASM_I32V(160), WASM_LOCAL_GET(b)), + WASM_SIMD_STORE_MEM(WASM_I32V(176), WASM_LOCAL_GET(c)), + WASM_SIMD_STORE_MEM( + WASM_I32V(240), + WASM_SIMD_OPN(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(a), + WASM_LOCAL_GET(a), + WASM_LOCAL_SET(a, WASM_SIMD_I32x4_SPLAT(WASM_ZERO)))), + WASM_LOCAL_SET(a, WASM_SIMD_LOAD_MEM(WASM_ZERO)), + WASM_SIMD_STORE_MEM( + WASM_I32V(256), + WASM_SIMD_OPN(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(a), + WASM_LOCAL_GET(b), + WASM_LOCAL_SET(a, WASM_SIMD_I32x4_SPLAT(WASM_ZERO)))), + WASM_LOCAL_SET(a, WASM_SIMD_LOAD_MEM(WASM_ZERO)), + WASM_SIMD_STORE_MEM( + WASM_I32V(272), + WASM_SIMD_OPN(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(b), + WASM_LOCAL_GET(a), + WASM_LOCAL_SET(a, WASM_SIMD_I32x4_SPLAT(WASM_ZERO)))), + WASM_LOCAL_SET(a, WASM_SIMD_LOAD_MEM(WASM_ZERO)), + WASM_SIMD_STORE_MEM( + WASM_I32V(288), + WASM_SIMD_OPN(opcode, WASM_LOCAL_GET(a), WASM_LOCAL_GET(b), + WASM_LOCAL_GET(b), + WASM_LOCAL_SET(b, WASM_SIMD_I32x4_SPLAT(WASM_ZERO)))), + WASM_ONE}); + + auto check_lane = [=](uint16_t lhs, uint16_t rhs, uint16_t acc, + uint16_t actual) { + uint16_t fused = FmaF16(lhs, rhs, acc, negate); + uint16_t widened = FmaF16(lhs, rhs, acc, negate, true); + if (!isnan(fused)) { + // The proposal's native-half and FP32-widened lowerings can differ. + // Keep both references separate; neither is an oracle for the other. +#if V8_TARGET_ARCH_X64 + bool native = + UseAvx10_1() && (execution_tier == TestExecutionTier::kLiftoff || + CpuFeatures::IsSupported(F16C)); + CHECK_EQ(native ? fused : widened, actual); +#else + CHECK(actual == fused || actual == widened); +#endif + return; + } + CHECK_EQ(0x7e00, actual & 0x7e00); + if ((!isnan(lhs) || IsCanonical(lhs)) && + (!isnan(rhs) || IsCanonical(rhs)) && + (!isnan(acc) || IsCanonical(acc))) { + CHECK(IsCanonical(actual)); + } + }; + auto check = [&]() { + CHECK_EQ(1, r.Call()); + for (int lane = 0; lane < kLanes; ++lane) { + auto read = [&](int slot) { + return r.builder().ReadMemory(&memory[slot * kLanes + lane]); + }; + uint16_t lhs = read(0), rhs = read(1), acc = read(2); + check_lane(lhs, rhs, acc, read(3)); + check_lane(lhs, lhs, acc, read(4)); + check_lane(lhs, rhs, lhs, read(5)); + check_lane(lhs, rhs, rhs, read(6)); + check_lane(lhs, lhs, lhs, read(7)); + // Use the checked intermediate, including its actual NaN class. + check_lane(lhs, rhs, read(3), read(8)); + CHECK_EQ(lhs, read(9)); + CHECK_EQ(rhs, read(10)); + CHECK_EQ(acc, read(11)); + check_lane(lhs, rhs, acc, read(12)); + check_lane(lhs, rhs, acc, read(13)); + check_lane(lhs, rhs, acc, read(14)); + check_lane(lhs, lhs, lhs, read(15)); + check_lane(lhs, lhs, rhs, read(16)); + check_lane(lhs, rhs, lhs, read(17)); + check_lane(lhs, rhs, rhs, read(18)); + } + }; + + constexpr uint16_t rounding[][3] = { + {0x3e00, 0x3c01, 0x8001}, {0x3e00, 0x3c03, 0x0001}, + {0x3c01, 0x3bfe, 0xbc00}, {0x7bff, 0x4000, 0xfbff}, + {0x0001, 0x3800, 0x0000}, {0x0003, 0x3800, 0x0000}, + {0x8000, 0x3c00, 0x8000}, {0x3c00, 0x3c00, 0xbc00}}; + for (int lane = 0; lane < kLanes; ++lane) { + for (int input = 0; input < 3; ++input) { + uint16_t bits = rounding[lane][input]; + if (negate && input == 0) bits ^= 0x8000; + r.builder().WriteMemory(&memory[input * kLanes + lane], bits); + } + } + check(); + + constexpr uint16_t edges[] = {0x0000, 0x8000, 0x0001, 0x8001, 0x03ff, 0x83ff, + 0x0400, 0x8400, 0x3800, 0xb800, 0x3bff, 0x3c00, + 0xbc00, 0x3c01, 0x4000, 0xc000, 0x7bff, 0xfbff, + 0x7c00, 0xfc00, 0x7c01, 0xfc01, 0x7dff, 0xfdff, + 0x7e00, 0xfe00, 0x7e55, 0xfe55, 0x7fff, 0xffff}; + for (uint16_t lhs : edges) { + for (uint16_t rhs : edges) { + for (size_t acc = 0; acc < arraysize(edges); acc += kLanes) { + for (int lane = 0; lane < kLanes; ++lane) { + r.builder().WriteMemory(&memory[lane], lhs); + r.builder().WriteMemory(&memory[kLanes + lane], rhs); + r.builder().WriteMemory(&memory[2 * kLanes + lane], + edges[(acc + lane) % arraysize(edges)]); + } + check(); + } + } + } + base::RandomNumberGenerator rng(0xf16f00); + for (int trial = 0; trial < 1024; ++trial) { + for (int lane = 0; lane < 3 * kLanes; ++lane) { + r.builder().WriteMemory(&memory[lane], + static_cast<uint16_t>(rng.NextInt(65536))); + } + check(); + } +} + +WASM_COMPILED_EXEC_TEST(F16x8QfmaRaw) { RunF16x8FmaRaw(execution_tier, false); } +WASM_COMPILED_EXEC_TEST(F16x8QfmsRaw) { RunF16x8FmaRaw(execution_tier, true); } + +struct FMOperation { + const float a; + const float b; + const float c; + const float fused_result; +}; + +constexpr float large_n = 1e4; +constexpr float finf = std::numeric_limits<float>::infinity(); +constexpr float qNan = std::numeric_limits<float>::quiet_NaN(); + +// Fused Multiply-Add performs a * b + c. +static FMOperation qfma_array[] = { + {2.0f, 3.0f, 1.0f, 7.0f}, + // fused: a * b + c = (positive overflow) + -inf = -inf + // unfused: a * b + c = inf + -inf = NaN + {large_n, large_n, -finf, -finf}, + // fused: a * b + c = (negative overflow) + inf = inf + // unfused: a * b + c = -inf + inf = NaN + {-large_n, large_n, finf, finf}, + // NaN + {2.0f, 3.0f, qNan, qNan}, + // -NaN + {2.0f, 3.0f, -qNan, qNan}}; + +base::Vector<const FMOperation> qfma_vector() { + return base::ArrayVector(qfma_array); +} + +// Fused Multiply-Subtract performs -(a * b) + c. +static FMOperation qfms_array[]{ + {2.0f, 3.0f, 1.0f, -5.0f}, + // fused: -(a * b) + c = - (positive overflow) + inf = inf + // unfused: -(a * b) + c = - inf + inf = NaN + {large_n, large_n, finf, finf}, + // fused: -(a * b) + c = (negative overflow) + -inf = -inf + // unfused: -(a * b) + c = -inf - -inf = NaN + {-large_n, large_n, -finf, -finf}, + // NaN + {2.0f, 3.0f, qNan, qNan}, + // -NaN + {2.0f, 3.0f, -qNan, qNan}}; + +base::Vector<const FMOperation> qfms_vector() { + return base::ArrayVector(qfms_array); +} + +WASM_EXEC_TEST(F16x8Qfma) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, float, float, float> r(execution_tier); + // Set up global to hold output. + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + uint8_t value1 = 0, value2 = 1, value3 = 2; + r.Build( + {WASM_GLOBAL_SET(0, WASM_SIMD_F16x8_QFMA( + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value1)), + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value2)), + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value3)))), + WASM_ONE}); + for (FMOperation x : qfma_vector()) { + r.Call(x.a, x.b, x.c); + uint16_t expected = fp16_ieee_from_fp32_value(x.fused_result); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 8; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + CheckFloat16LaneResult(x.a, x.b, x.c, expected, actual_lane, + true /* exact */); + } + } +} + +WASM_EXEC_TEST(F16x8Qfms) { + i::v8_flags.wasm_fp16 = true; + WasmRunner<int32_t, float, float, float> r(execution_tier); + // Set up global to hold output. + const WasmGlobal* g = r.builder().AddGlobal(kWasmS128); + uint8_t value1 = 0, value2 = 1, value3 = 2; + r.Build( + {WASM_GLOBAL_SET(0, WASM_SIMD_F16x8_QFMS( + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value1)), + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value2)), + WASM_SIMD_F16x8_SPLAT(WASM_LOCAL_GET(value3)))), + WASM_ONE}); + + for (FMOperation x : qfms_vector()) { + r.Call(x.a, x.b, x.c); + uint16_t expected = fp16_ieee_from_fp32_value(x.fused_result); + Simd128 actual = r.builder().ReadGlobal(*g).to_s128(); + for (int i = 0; i < 8; i++) { + uint16_t actual_lane = LANE(actual.to_i16x8(), i); + CheckFloat16LaneResult(x.a, x.b, x.c, expected, actual_lane, + true /* exact */); + } + } +} + +#undef WASM_EXEC_TEST_SUITE + +} // namespace test_run_wasm_f16 +} // namespace wasm +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-js.cc b/deps/v8/test/unittests/wasm/run-wasm-js-unittest.cc similarity index 87% rename from deps/v8/test/cctest/wasm/test-run-wasm-js.cc rename to deps/v8/test/unittests/wasm/run-wasm-js-unittest.cc index 1e90333e968c..11a03598fc6f 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-js.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-js-unittest.cc @@ -7,20 +7,24 @@ #include <stdlib.h> #include <string.h> +#include <array> + #include "include/v8-function.h" #include "src/api/api-inl.h" #include "src/codegen/assembler-inl.h" #include "src/objects/heap-number-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { +using RunWasmJsTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmJsTest + namespace { // A helper for generating predictable but unique argument values that // are easy to debug (e.g. with misaligned stacks). @@ -52,14 +56,14 @@ ManuallyImportedJSFunction CreateJSSelector(FunctionSig* sig, int which) { CHECK_LT(which, static_cast<int>(sig->parameter_count())); CHECK_LT(static_cast<int>(sig->parameter_count()), kMaxParams); - base::EmbeddedVector<char, 256> source; + std::array<char, 256> source; char param = 'a' + which; - SNPrintF(source, "(function(%s) { return %c; })", - formals[sig->parameter_count()], param); + base::SNPrintF(source, "(function(%s) { return %c; })", + formals[sig->parameter_count()], param); DirectHandle<JSFunction> js_function = Cast<JSFunction>(v8::Utils::OpenDirectHandle( - *v8::Local<v8::Function>::Cast(CompileRun(source.begin())))); + *v8::Local<v8::Function>::Cast(CompileRun(source.data())))); ManuallyImportedJSFunction import = {sig, js_function}; return import; @@ -101,7 +105,7 @@ WASM_COMPILED_EXEC_TEST(Run_I32Popcount_jswrapped) { WASM_COMPILED_EXEC_TEST(Run_CallJS_Add_jswrapped) { TestSignatures sigs; - HandleScope scope(CcTest::InitIsolateOnce()); + HandleScope scope(WasmExecutionTestBase::InitIsolateOnce()); const char* source = "(function(a) { return a + 99; })"; DirectHandle<JSFunction> js_function = Cast<JSFunction>(v8::Utils::OpenDirectHandle( @@ -123,7 +127,7 @@ void RunJSSelectTest(TestExecutionTier tier, int which) { ValueType types[kMaxParams + 1] = {type, type, type, type, type, type, type, type, type}; for (int num_params = which + 1; num_params < kMaxParams; num_params++) { - HandleScope scope(CcTest::InitIsolateOnce()); + HandleScope scope(WasmExecutionTestBase::InitIsolateOnce()); FunctionSig sig(1, num_params, types); ManuallyImportedJSFunction import = CreateJSSelector(&sig, which); @@ -152,48 +156,48 @@ void RunJSSelectTest(TestExecutionTier tier, int which) { } WASM_COMPILED_EXEC_TEST(Run_JSSelect_0) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 0); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_1) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 1); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_2) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 2); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_3) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 3); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_4) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 4); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_5) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 5); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_6) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 6); } WASM_COMPILED_EXEC_TEST(Run_JSSelect_7) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectTest(execution_tier, 7); } void RunWASMSelectTest(TestExecutionTier tier, int which) { PredictableInputValues inputs(0x200); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); const int kMaxParams = 8; for (int num_params = which + 1; num_params < kMaxParams; num_params++) { ValueType type = kWasmF64; @@ -222,49 +226,49 @@ void RunWASMSelectTest(TestExecutionTier tier, int which) { } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_0) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 0); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_1) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 1); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_2) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 2); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_3) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 3); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_4) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 4); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_5) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 5); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_6) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 6); } WASM_COMPILED_EXEC_TEST(Run_WASMSelect_7) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectTest(execution_tier, 7); } void RunWASMSelectAlignTest(TestExecutionTier tier, int num_args, int num_params) { PredictableInputValues inputs(0x300); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); const int kMaxParams = 10; DCHECK_LE(num_args, kMaxParams); ValueType type = kWasmF64; @@ -297,44 +301,44 @@ void RunWASMSelectAlignTest(TestExecutionTier tier, int num_args, } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_0) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 0, 1); RunWASMSelectAlignTest(execution_tier, 0, 2); } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_1) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 1, 2); RunWASMSelectAlignTest(execution_tier, 1, 3); } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_2) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 2, 3); RunWASMSelectAlignTest(execution_tier, 2, 4); } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_3) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 3, 3); RunWASMSelectAlignTest(execution_tier, 3, 4); } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_4) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 4, 3); RunWASMSelectAlignTest(execution_tier, 4, 4); } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_7) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 7, 5); RunWASMSelectAlignTest(execution_tier, 7, 6); RunWASMSelectAlignTest(execution_tier, 7, 7); } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_8) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 8, 5); RunWASMSelectAlignTest(execution_tier, 8, 6); RunWASMSelectAlignTest(execution_tier, 8, 7); @@ -342,7 +346,7 @@ WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_8) { } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_9) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 9, 6); RunWASMSelectAlignTest(execution_tier, 9, 7); RunWASMSelectAlignTest(execution_tier, 9, 8); @@ -350,7 +354,7 @@ WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_9) { } WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_10) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunWASMSelectAlignTest(execution_tier, 10, 7); RunWASMSelectAlignTest(execution_tier, 10, 8); RunWASMSelectAlignTest(execution_tier, 10, 9); @@ -360,7 +364,7 @@ WASM_COMPILED_EXEC_TEST(Run_WASMSelectAlign_10) { void RunJSSelectAlignTest(TestExecutionTier tier, int num_args, int num_params) { PredictableInputValues inputs(0x400); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); Factory* factory = isolate->factory(); const int kMaxParams = 10; CHECK_LE(num_args, kMaxParams); @@ -414,37 +418,37 @@ void RunJSSelectAlignTest(TestExecutionTier tier, int num_args, } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_0) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 0, 1); RunJSSelectAlignTest(execution_tier, 0, 2); } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_1) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 1, 2); RunJSSelectAlignTest(execution_tier, 1, 3); } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_2) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 2, 3); RunJSSelectAlignTest(execution_tier, 2, 4); } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_3) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 3, 3); RunJSSelectAlignTest(execution_tier, 3, 4); } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_4) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 4, 3); RunJSSelectAlignTest(execution_tier, 4, 4); } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_7) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 7, 3); RunJSSelectAlignTest(execution_tier, 7, 4); RunJSSelectAlignTest(execution_tier, 7, 4); @@ -452,7 +456,7 @@ WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_7) { } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_8) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 8, 5); RunJSSelectAlignTest(execution_tier, 8, 6); RunJSSelectAlignTest(execution_tier, 8, 7); @@ -460,7 +464,7 @@ WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_8) { } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_9) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 9, 6); RunJSSelectAlignTest(execution_tier, 9, 7); RunJSSelectAlignTest(execution_tier, 9, 8); @@ -468,7 +472,7 @@ WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_9) { } WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_10) { - CcTest::InitializeVM(); + WasmExecutionTestBase::InitIsolateOnce(); RunJSSelectAlignTest(execution_tier, 10, 7); RunJSSelectAlignTest(execution_tier, 10, 8); RunJSSelectAlignTest(execution_tier, 10, 9); @@ -481,7 +485,7 @@ WASM_COMPILED_EXEC_TEST(Run_JSSelectAlign_10) { // function (a,b,c){ if(c)return a; return b; } void RunPickerTest(TestExecutionTier tier, bool indirect) { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); TestSignatures sigs; @@ -528,6 +532,8 @@ WASM_COMPILED_EXEC_TEST(Run_ReturnCallImportedFunction) { RunPickerTest(execution_tier, false); } +#undef WASM_EXEC_TEST_SUITE + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-memory64.cc b/deps/v8/test/unittests/wasm/run-wasm-memory64-unittest.cc similarity index 93% rename from deps/v8/test/cctest/wasm/test-run-wasm-memory64.cc rename to deps/v8/test/unittests/wasm/run-wasm-memory64-unittest.cc index 3c81d38dfdd8..4ae3deca1e32 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-memory64.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-memory64-unittest.cc @@ -3,14 +3,16 @@ // found in the LICENSE file. #include "src/wasm/wasm-opcodes-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { +using RunWasmMemory64Test = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmMemory64Test + template <typename ReturnType, typename... ParamTypes> class Memory64Runner : public WasmRunner<ReturnType, ParamTypes...> { public: @@ -59,7 +61,7 @@ WASM_EXEC_TEST(Load) { // TODO(clemensb): Test atomic instructions. WASM_EXEC_TEST(InitExpression) { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); ErrorThrower thrower(isolate, "TestMemory64InitExpression"); @@ -113,4 +115,6 @@ WASM_EXEC_TEST(MemoryGrow) { CHECK_EQ(8, r.Call(5)); // Just at the maximum of 13. } +#undef WASM_EXEC_TEST_SUITE + } // namespace v8::internal::wasm diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-module.cc b/deps/v8/test/unittests/wasm/run-wasm-module-unittest.cc similarity index 80% rename from deps/v8/test/cctest/wasm/test-run-wasm-module.cc rename to deps/v8/test/unittests/wasm/run-wasm-module-unittest.cc index d8e6d7247b69..89b9a2c3ae06 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-module.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-module-unittest.cc @@ -18,11 +18,11 @@ #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -32,9 +32,10 @@ namespace test_run_wasm_module { using base::ReadLittleEndianValue; using base::WriteLittleEndianValue; using testing::CompileAndInstantiateForTesting; +using RunWasmModuleTest = WasmExecutionTestBase; namespace { -void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) { +void Cleanup(Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce()) { // By sending a low memory notifications, we will try hard to collect all // garbage and will therefore also invoke all weak callbacks of actually // unreachable persistent handles. @@ -46,7 +47,7 @@ void TestModule(Zone* zone, WasmModuleBuilder* builder, ZoneBuffer buffer(zone); builder->WriteTo(&buffer); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); int32_t result = testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end()); @@ -57,7 +58,7 @@ void TestModuleException(Zone* zone, WasmModuleBuilder* builder) { ZoneBuffer buffer(zone); builder->WriteTo(&buffer); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end()); @@ -66,7 +67,7 @@ void TestModuleException(Zone* zone, WasmModuleBuilder* builder) { } void ExportAsMain(WasmFunctionBuilder* f) { - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); } #define EMIT_CODE_WITH_END(f, code) \ @@ -77,7 +78,7 @@ void ExportAsMain(WasmFunctionBuilder* f) { } // namespace -TEST(Run_WasmModule_Return114) { +TEST_F(RunWasmModuleTest, Run_WasmModule_Return114) { { static const int32_t kReturnValue = 114; TestSignatures sigs; @@ -94,7 +95,7 @@ TEST(Run_WasmModule_Return114) { Cleanup(); } -TEST(Run_WasmModule_CallAdd) { +TEST_F(RunWasmModuleTest, Run_WasmModule_CallAdd) { { v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); @@ -120,7 +121,7 @@ TEST(Run_WasmModule_CallAdd) { Cleanup(); } -TEST(Run_WasmModule_ReadLoadedDataSegment) { +TEST_F(RunWasmModuleTest, Run_WasmModule_ReadLoadedDataSegment) { { static const uint8_t kDataSegmentDest0 = 12; v8::internal::AccountingAllocator allocator; @@ -142,7 +143,7 @@ TEST(Run_WasmModule_ReadLoadedDataSegment) { Cleanup(); } -TEST(Run_WasmModule_CheckMemoryIsZero) { +TEST_F(RunWasmModuleTest, Run_WasmModule_CheckMemoryIsZero) { { static const int kCheckSize = 16 * 1024; v8::internal::AccountingAllocator allocator; @@ -169,7 +170,7 @@ TEST(Run_WasmModule_CheckMemoryIsZero) { Cleanup(); } -TEST(Run_WasmModule_CallMain_recursive) { +TEST_F(RunWasmModuleTest, Run_WasmModule_CallMain_recursive) { { v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); @@ -195,7 +196,7 @@ TEST(Run_WasmModule_CallMain_recursive) { Cleanup(); } -TEST(Run_WasmModule_Global) { +TEST_F(RunWasmModuleTest, Run_WasmModule_Global) { { v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); @@ -219,7 +220,7 @@ TEST(Run_WasmModule_Global) { Cleanup(); } -TEST(MemorySize) { +TEST_F(RunWasmModuleTest, MemorySize) { { // Initial memory size is 16, see wasm-module-builder.cc static const int kExpectedValue = 16; @@ -238,7 +239,7 @@ TEST(MemorySize) { Cleanup(); } -TEST(Run_WasmModule_MemSize_GrowMem) { +TEST_F(RunWasmModuleTest, Run_WasmModule_MemSize_GrowMem) { { // Initial memory size = 16 + MemoryGrow(10) static const int kExpectedValue = 26; @@ -258,7 +259,7 @@ TEST(Run_WasmModule_MemSize_GrowMem) { Cleanup(); } -TEST(MemoryGrowZero) { +TEST_F(RunWasmModuleTest, MemoryGrowZero) { { // Initial memory size is 16, see wasm-module-builder.cc static const int kExpectedValue = 16; @@ -308,7 +309,7 @@ class InterruptThread : public v8::base::Thread { static const int32_t signal_value_ = 1221; }; -TEST(TestInterruptLoop) { +TEST_F(RunWasmModuleTest, TestInterruptLoop) { { // Do not dump the module of this test because it contains an infinite loop. if (v8_flags.dump_wasm_module) return; @@ -326,7 +327,7 @@ TEST(TestInterruptLoop) { // InterruptCallback. Upon exeution, the InterruptCallback write into the // WebAssemblyMemory to end the loop in the WebAssembly program. TestSignatures sigs; - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); @@ -370,7 +371,7 @@ TEST(TestInterruptLoop) { Cleanup(); } -TEST(Run_WasmModule_MemoryGrowInIf) { +TEST_F(RunWasmModuleTest, Run_WasmModule_MemoryGrowInIf) { { TestSignatures sigs; v8::internal::AccountingAllocator allocator; @@ -387,7 +388,7 @@ TEST(Run_WasmModule_MemoryGrowInIf) { Cleanup(); } -TEST(Run_WasmModule_GrowMemOobOffset) { +TEST_F(RunWasmModuleTest, Run_WasmModule_GrowMemOobOffset) { { static const int kPageSize = 0x10000; // Initial memory size = 16 + MemoryGrow(10) @@ -409,14 +410,14 @@ TEST(Run_WasmModule_GrowMemOobOffset) { Cleanup(); } -TEST(Run_WasmModule_GrowMemOobFixedIndex) { +TEST_F(RunWasmModuleTest, Run_WasmModule_GrowMemOobFixedIndex) { { static const int kPageSize = 0x10000; // Initial memory size = 16 + MemoryGrow(10) static const int index = kPageSize * 26 + 4; int value = 0xACED; TestSignatures sigs; - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); Zone zone(isolate->allocator(), ZONE_NAME); WasmModuleBuilder* builder = zone.New<WasmModuleBuilder>(&zone); @@ -459,12 +460,12 @@ TEST(Run_WasmModule_GrowMemOobFixedIndex) { Cleanup(); } -TEST(Run_WasmModule_GrowMemOobVariableIndex) { +TEST_F(RunWasmModuleTest, Run_WasmModule_GrowMemOobVariableIndex) { { static const int kPageSize = 0x10000; int value = 0xACED; TestSignatures sigs; - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); @@ -519,7 +520,7 @@ TEST(Run_WasmModule_GrowMemOobVariableIndex) { Cleanup(); } -TEST(Run_WasmModule_Global_init) { +TEST_F(RunWasmModuleTest, Run_WasmModule_Global_init) { { v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); @@ -571,24 +572,24 @@ static void RunWasmModuleGlobalInitTest(ValueType type, CType expected) { Cleanup(); } -TEST(Run_WasmModule_Global_i32) { +TEST_F(RunWasmModuleTest, Run_WasmModule_Global_i32) { RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, -983489); RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, 11223344); } -TEST(Run_WasmModule_Global_f32) { +TEST_F(RunWasmModuleTest, Run_WasmModule_Global_f32) { RunWasmModuleGlobalInitTest<float>(kWasmF32, -983.9f); RunWasmModuleGlobalInitTest<float>(kWasmF32, 1122.99f); } -TEST(Run_WasmModule_Global_f64) { +TEST_F(RunWasmModuleTest, Run_WasmModule_Global_f64) { RunWasmModuleGlobalInitTest<double>(kWasmF64, -833.9); RunWasmModuleGlobalInitTest<double>(kWasmF64, 86374.25); } -TEST(InitDataAtTheUpperLimit) { +TEST_F(RunWasmModuleTest, InitDataAtTheUpperLimit) { { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit"); @@ -620,9 +621,9 @@ TEST(InitDataAtTheUpperLimit) { Cleanup(); } -TEST(EmptyMemoryNonEmptyDataSegment) { +TEST_F(RunWasmModuleTest, EmptyMemoryNonEmptyDataSegment) { { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit"); @@ -652,9 +653,9 @@ TEST(EmptyMemoryNonEmptyDataSegment) { Cleanup(); } -TEST(EmptyMemoryEmptyDataSegment) { +TEST_F(RunWasmModuleTest, EmptyMemoryEmptyDataSegment) { { - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit"); @@ -683,6 +684,81 @@ TEST(EmptyMemoryEmptyDataSegment) { Cleanup(); } +void TestFailedInstantiation(base::Vector<const uint8_t> module_bytes, + const char* scenario) { + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); + HandleScope scope(isolate); + ErrorThrower thrower(isolate, scenario); + DirectHandle<WasmModuleObject> module_object = + testing::CompileForTesting(isolate, &thrower, module_bytes) + .ToHandleChecked(); + DirectHandle<WasmMemoryObject> memory_object = + WasmMemoryObject::New(isolate, 1, WasmMemoryObject::kNoMaximum, + SharedFlag{false}, AddressType::kI32) + .ToHandleChecked(); + DirectHandle<JSObject> ffi = + isolate->factory()->NewJSObject(isolate->object_function()); + DirectHandle<JSObject> mod = + isolate->factory()->NewJSObject(isolate->object_function()); + DirectHandle<String> m = isolate->factory()->InternalizeUtf8String("m"); + JSObject::AddProperty(isolate, mod, m, memory_object, NONE); + JSObject::AddProperty(isolate, ffi, m, mod, NONE); + + MaybeDirectHandle<WasmInstanceObject> maybe_instance = + GetWasmEngine()->SyncInstantiate(isolate, &thrower, module_object, ffi); + CHECK(maybe_instance.is_null()); + CHECK(thrower.error()); + + // Failed instantiation in Build_Phase1 must not register the instance in + // any lists. + CHECK_EQ( + 0u, module_object->script()->wasm_weak_instance_list()->length().value()); + CHECK_EQ(0u, memory_object->instances()->length().value()); +} + +TEST_F(RunWasmModuleTest, FailedInitGlobalsAndTablesUnpublishesInstance) { + WasmExecutionTestBase::InitIsolateOnce(); + + // 1. Trapping constant expression in InitGlobals() (global 0 traps with + // kWasmTrapArrayTooLarge, leaving global 1 uninitialized). + const uint8_t data1[] = { + WASM_MODULE_HEADER, + SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI64Code, true)), + SECTION(Import, ENTRY_COUNT(1), ADD_COUNT('m'), ADD_COUNT('m'), + kExternalMemory, kNoMaximum, 1), + SECTION(Global, ENTRY_COUNT(2), + // global 0: (ref 0), traps with array.new_default -1 + kRefCode, 0, 0, kExprI32Const, 0x7f, + WASM_GC_OP(kExprArrayNewDefault), 0, kExprEnd, + // global 1: (ref 0), left uninitialized in tagged_globals_buffer + kRefCode, 0, 0, kExprI32Const, 0, + WASM_GC_OP(kExprArrayNewDefault), 0, kExprEnd), + }; + TestFailedInstantiation(base::VectorOf(data1), "FailedInitGlobals"); + + // 2. Trapping constant expression in SetTableInitialValues() (table 0 traps + // with kWasmTrapArrayTooLarge, leaving non-nullable table 1 uninitialized). + const uint8_t data2[] = { + WASM_MODULE_HEADER, + SECTION(Type, ENTRY_COUNT(2), SIG_ENTRY_v_v, + WASM_ARRAY_DEF(kI64Code, true)), + SECTION(Import, ENTRY_COUNT(1), ADD_COUNT('m'), ADD_COUNT('m'), + kExternalMemory, kNoMaximum, 1), + SECTION(Function, ENTRY_COUNT(1), 0), + SECTION(Table, ENTRY_COUNT(2), + // table 0: (ref 1) with trapping initializer + 0x40, 0x00, kRefCode, 1, kNoMaximum, 1, kExprI32Const, 0x7f, + WASM_GC_OP(kExprArrayNewDefault), 1, kExprEnd, + // table 1: non-nullable function table (ref 0) + 0x40, 0x00, kRefCode, 0, kNoMaximum, 1, kExprRefFunc, 0, + kExprEnd), + SECTION(Code, ENTRY_COUNT(1), ADD_COUNT(0, kExprEnd)), + }; + TestFailedInstantiation(base::VectorOf(data2), "FailedSetTableInitialValues"); + + Cleanup(); +} + #undef EMIT_CODE_WITH_END } // namespace test_run_wasm_module diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-relaxed-simd.cc b/deps/v8/test/unittests/wasm/run-wasm-relaxed-simd-unittest.cc similarity index 96% rename from deps/v8/test/cctest/wasm/test-run-wasm-relaxed-simd.cc rename to deps/v8/test/unittests/wasm/run-wasm-relaxed-simd-unittest.cc index 6e2148611a5e..b65f818c4e99 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-relaxed-simd.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-relaxed-simd-unittest.cc @@ -9,14 +9,16 @@ #include "src/codegen/cpu-features.h" #include "src/common/globals.h" #include "src/wasm/compilation-environment.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" -#include "test/cctest/wasm/wasm-simd-utils.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" +#include "test/unittests/wasm/wasm-simd-utils.h" namespace v8::internal::wasm { +using RunWasmRelaxedSimdTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmRelaxedSimdTest + // Only used for qfma and qfms tests below. // FMOperation holds the params (a, b, c) for a Multiply-Add or @@ -211,7 +213,7 @@ WASM_EXEC_TEST(F64x2Qfms) { } } -TEST(RunWasm_RegressFmaReg_liftoff) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_RegressFmaReg_liftoff) { FLAG_SCOPE(liftoff_only); TestExecutionTier execution_tier = TestExecutionTier::kLiftoff; WasmRunner<int32_t, float, float, float> r(execution_tier); @@ -514,7 +516,7 @@ WASM_EXEC_TEST(I32x4DotI8x16I7x16AddS) { } #ifdef V8_ENABLE_WASM_SIMD256_REVEC -TEST(RunWasm_F32x8Qfma_turbofan) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_F32x8Qfma_turbofan) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); WasmRunner<int32_t, float, float, float> r(TestExecutionTier::kTurbofan); @@ -551,7 +553,7 @@ TEST(RunWasm_F32x8Qfma_turbofan) { } } -TEST(RunWasm_F32x8Qfms_turbofan) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_F32x8Qfms_turbofan) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); WasmRunner<int32_t, float, float, float> r(TestExecutionTier::kTurbofan); @@ -588,7 +590,7 @@ TEST(RunWasm_F32x8Qfms_turbofan) { } } -TEST(RunWasm_F64x4Qfma_turbofan) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_F64x4Qfma_turbofan) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); WasmRunner<int32_t, double, double, double> r(TestExecutionTier::kTurbofan); @@ -625,7 +627,7 @@ TEST(RunWasm_F64x4Qfma_turbofan) { } } -TEST(RunWasm_F64x4Qfms_turbofan) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_F64x4Qfms_turbofan) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); WasmRunner<int32_t, double, double, double> r(TestExecutionTier::kTurbofan); @@ -715,7 +717,7 @@ void RelaxedLaneSelectRevecTest(const T l1[kElems], const T l2[kElems], } } -TEST(RunWasm_I64x4RelaxedLaneSelect) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_I64x4RelaxedLaneSelect) { constexpr int kElems = 2; uint64_t l1[kElems] = {0, 1}; uint64_t l2[kElems] = {2, 3}; @@ -728,7 +730,7 @@ TEST(RunWasm_I64x4RelaxedLaneSelect) { kExprI64x2RelaxedLaneSelect); } -TEST(RunWasm_I32x8RelaxedLaneSelect) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_I32x8RelaxedLaneSelect) { constexpr int kElems = 4; uint32_t l1[kElems] = {0, 1, 2, 3}; uint32_t l2[kElems] = {8, 9, 10, 11}; @@ -741,7 +743,7 @@ TEST(RunWasm_I32x8RelaxedLaneSelect) { kExprI32x4RelaxedLaneSelect); } -TEST(RunWasm_I16x16RelaxedLaneSelect) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_I16x16RelaxedLaneSelect) { constexpr int kElems = 8; uint16_t l1[kElems] = {0, 1, 2, 3, 4, 5, 6, 7}; uint16_t r1[kElems] = {8, 9, 10, 11, 12, 13, 14, 15}; @@ -755,7 +757,7 @@ TEST(RunWasm_I16x16RelaxedLaneSelect) { kExprI16x8RelaxedLaneSelect); } -TEST(RunWasm_I8x32RelaxedLaneSelect) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_I8x32RelaxedLaneSelect) { constexpr int kElems = 16; uint8_t l1[kElems] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; uint8_t r1[kElems] = {16, 17, 18, 19, 20, 21, 22, 23, @@ -776,7 +778,7 @@ TEST(RunWasm_I8x32RelaxedLaneSelect) { kExprI8x16RelaxedLaneSelect); } -TEST(RunWasm_I32x8DotI8x32I7x32AddS) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_I32x8DotI8x32I7x32AddS) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); WasmRunner<int32_t, int8_t, int8_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -812,7 +814,7 @@ TEST(RunWasm_I32x8DotI8x32I7x32AddS) { } } -TEST(RunWasm_I16x16DotI8x32I7x32S) { +TEST_F(RunWasmRelaxedSimdTest, RunWasm_I16x16DotI8x32I7x32S) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); WasmRunner<int32_t, int8_t, int8_t> r(TestExecutionTier::kTurbofan); @@ -842,19 +844,19 @@ TEST(RunWasm_I16x16DotI8x32I7x32S) { } } -TEST(RunWasmTurbofan_F32x8RelaxedMin) { +TEST_F(RunWasmRelaxedSimdTest, RunWasmTurbofan_F32x8RelaxedMin) { RunF32x8BinOpRevecTest(kExprF32x4RelaxedMin, Minimum); } -TEST(RunWasmTurbofan_F32x8RelaxedMax) { +TEST_F(RunWasmRelaxedSimdTest, RunWasmTurbofan_F32x8RelaxedMax) { RunF32x8BinOpRevecTest(kExprF32x4RelaxedMax, Maximum); } -TEST(RunWasmTurbofan_F64x4RelaxedMin) { +TEST_F(RunWasmRelaxedSimdTest, RunWasmTurbofan_F64x4RelaxedMin) { RunF64x4BinOpRevecTest(kExprF64x2RelaxedMin, Minimum); } -TEST(RunWasmTurbofan_F64x4RelaxedMax) { +TEST_F(RunWasmRelaxedSimdTest, RunWasmTurbofan_F64x4RelaxedMax) { RunF64x4BinOpRevecTest(kExprF64x2RelaxedMax, Maximum); } @@ -891,14 +893,16 @@ void I32x8RelaxedTruncF32x8RevecTest(WasmOpcode trunc_op) { } } -TEST(RunWasmTurbofan_I32x8RelaxedTruncF32x8U) { +TEST_F(RunWasmRelaxedSimdTest, RunWasmTurbofan_I32x8RelaxedTruncF32x8U) { I32x8RelaxedTruncF32x8RevecTest<uint32_t>(kExprI32x4RelaxedTruncF32x4U); } -TEST(RunWasmTurbofan_I32x8RelaxedTruncF32x8S) { +TEST_F(RunWasmRelaxedSimdTest, RunWasmTurbofan_I32x8RelaxedTruncF32x8S) { I32x8RelaxedTruncF32x8RevecTest<int32_t>(kExprI32x4RelaxedTruncF32x4S); } #endif // V8_ENABLE_WASM_SIMD256_REVEC +#undef WASM_EXEC_TEST_SUITE + } // namespace v8::internal::wasm diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-sign-extension.cc b/deps/v8/test/unittests/wasm/run-wasm-sign-extension-unittest.cc similarity index 90% rename from deps/v8/test/cctest/wasm/test-run-wasm-sign-extension.cc rename to deps/v8/test/unittests/wasm/run-wasm-sign-extension-unittest.cc index 5e540a953196..ae40d5b2bf66 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-sign-extension.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-sign-extension-unittest.cc @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { +using RunWasmSignExtensionTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmSignExtensionTest + WASM_EXEC_TEST(I32SExtendI8) { WasmRunner<int32_t, int32_t> r(execution_tier); r.Build({WASM_I32_SIGN_EXT_I8(WASM_LOCAL_GET(0))}); @@ -60,6 +62,8 @@ WASM_EXEC_TEST(I64SExtendI32) { CHECK_EQ(-0x80000000LL, r.Call(0x80000000)); } +#undef WASM_EXEC_TEST_SUITE + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-simd-liftoff.cc b/deps/v8/test/unittests/wasm/run-wasm-simd-liftoff-unittest.cc similarity index 94% rename from deps/v8/test/cctest/wasm/test-run-wasm-simd-liftoff.cc rename to deps/v8/test/unittests/wasm/run-wasm-simd-liftoff-unittest.cc index 4cb420fdfcad..920c8e18fac9 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-simd-liftoff.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-simd-liftoff-unittest.cc @@ -11,24 +11,25 @@ #include "src/codegen/assembler-inl.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_run_wasm_simd_liftoff { -TEST(S128Local) { +using RunWasmSimdLiftoffTest = WasmExecutionTestBase; + +TEST_F(RunWasmSimdLiftoffTest, S128Local) { WasmRunner<int32_t> r(TestExecutionTier::kLiftoff); uint8_t temp1 = r.AllocateLocal(kWasmS128); r.Build({WASM_LOCAL_SET(temp1, WASM_LOCAL_GET(temp1)), WASM_ONE}); CHECK_EQ(1, r.Call()); } -TEST(S128Global) { +TEST_F(RunWasmSimdLiftoffTest, S128Global) { WasmRunner<int32_t> r(TestExecutionTier::kLiftoff); const WasmGlobal* g0 = r.builder().AddGlobal(kWasmS128); @@ -48,7 +49,7 @@ TEST(S128Global) { } } -TEST(S128Param) { +TEST_F(RunWasmSimdLiftoffTest, S128Param) { // Test how SIMD parameters in functions are processed. There is no easy way // to specify a SIMD value when initializing a WasmRunner, so we manually // add a new function with the right signature, and call it from main. @@ -66,7 +67,7 @@ TEST(S128Param) { CHECK_EQ(1, r.Call()); } -TEST(S128Return) { +TEST_F(RunWasmSimdLiftoffTest, S128Return) { // Test how functions returning SIMD values are processed. WasmRunner<int32_t> r(TestExecutionTier::kLiftoff); TestSignatures sigs; @@ -80,7 +81,7 @@ TEST(S128Return) { CHECK_EQ(1, r.Call()); } -TEST(REGRESS_1088273) { +TEST_F(RunWasmSimdLiftoffTest, REGRESS_1088273) { // TODO(v8:9418): This is a regression test for Liftoff, translated from a // mjsunit test. We do not have I64x2Mul lowering yet, so this will cause a // crash on arch that don't support SIMD 128 and require lowering, thus @@ -102,7 +103,7 @@ TEST(REGRESS_1088273) { // A test to exercise logic in Liftoff's implementation of shuffle. The // implementation in Liftoff is a bit more tricky due to shuffle requiring // adjacent registers in ARM/ARM64. -TEST(I8x16Shuffle) { +TEST_F(RunWasmSimdLiftoffTest, I8x16Shuffle) { WasmRunner<int32_t> r(TestExecutionTier::kLiftoff); // Temps to use up registers and force non-adjacent registers for shuffle. uint8_t local0 = r.AllocateLocal(kWasmS128); @@ -151,7 +152,7 @@ TEST(I8x16Shuffle) { // Exercise logic in Liftoff's implementation of shuffle when inputs to the // shuffle are the same register. -TEST(I8x16Shuffle_SingleOperand) { +TEST_F(RunWasmSimdLiftoffTest, I8x16Shuffle_SingleOperand) { WasmRunner<int32_t> r(TestExecutionTier::kLiftoff); uint8_t local0 = r.AllocateLocal(kWasmS128); @@ -190,7 +191,7 @@ TEST(I8x16Shuffle_SingleOperand) { // Exercise Liftoff's logic for zero-initializing stack slots. We were using an // incorrect instruction for storing zeroes into the slot when the slot offset // was too large to fit in the instruction as an immediate. -TEST(FillStackSlotsWithZero_CheckStartOffset) { +TEST_F(RunWasmSimdLiftoffTest, FillStackSlotsWithZero_CheckStartOffset) { WasmRunner<int64_t> r(TestExecutionTier::kLiftoff); // Function that takes in 32 i64 arguments, returns i64. This gets us a large // enough starting offset from which we spill locals. diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-simd.cc b/deps/v8/test/unittests/wasm/run-wasm-simd-unittest.cc similarity index 96% rename from deps/v8/test/cctest/wasm/test-run-wasm-simd.cc rename to deps/v8/test/unittests/wasm/run-wasm-simd-unittest.cc index 96a4661b2794..48bc66b8c408 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-simd.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-simd-unittest.cc @@ -32,19 +32,21 @@ #include "src/wasm/value-type.h" #include "src/wasm/wasm-constants.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" -#include "test/cctest/wasm/wasm-simd-utils.h" #include "test/common/flag-utils.h" #include "test/common/value-helper.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" +#include "test/unittests/wasm/wasm-simd-utils.h" namespace v8 { namespace internal { namespace wasm { namespace test_run_wasm_simd { +using RunWasmSimdTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmSimdTest + namespace { using Shuffle = std::array<int8_t, kSimd128Size>; @@ -1118,6 +1120,42 @@ WASM_EXEC_TEST(I64x2Mul) { RunI64x2BinOpTest(execution_tier, kExprI64x2Mul, base::MulWithWraparound); } +struct I64x2MulTestCase { + std::array<int64_t, 2> lhs; + std::array<int64_t, 2> rhs; +}; + +const I64x2MulTestCase i64x2_mul_test_cases[] = { + {{1, 2}, {3, 4}}, + {{INT64_C(0x100000001), INT64_C(0x100000002)}, + {INT64_C(0x100000003), INT64_C(0x100000004)}}, + {{INT64_MAX, INT64_MIN}, {2, -1}}, + {{0, -1}, {INT64_MIN, 1}}, +}; + +WASM_EXEC_TEST(I64x2MulDistinctLanes) { + WasmRunner<int32_t> r(execution_tier); + // Distinct lanes to detect lane mix-ups. + const WasmGlobal* g0 = r.builder().AddGlobal(kWasmS128); + const WasmGlobal* g1 = r.builder().AddGlobal(kWasmS128); + const WasmGlobal* g2 = r.builder().AddGlobal(kWasmS128); + r.Build({WASM_GLOBAL_SET(2, WASM_SIMD_BINOP(kExprI64x2Mul, WASM_GLOBAL_GET(0), + WASM_GLOBAL_GET(1))), + WASM_ONE}); + + for (const I64x2MulTestCase& test : i64x2_mul_test_cases) { + r.builder().WriteGlobal(*g0, WasmValue(SimdForGlobal(test.lhs))); + r.builder().WriteGlobal(*g1, WasmValue(SimdForGlobal(test.rhs))); + + CHECK_EQ(1, r.Call()); + Simd128 actual = r.builder().ReadGlobal(*g2).to_s128(); + CHECK_EQ(base::MulWithWraparound(test.lhs[0], test.rhs[0]), + LANE(actual.to_i64x2(), 0)); + CHECK_EQ(base::MulWithWraparound(test.lhs[1], test.rhs[1]), + LANE(actual.to_i64x2(), 1)); + } +} + WASM_EXEC_TEST(I32x4Splat) { WasmRunner<int32_t, int32_t> r(execution_tier); // Set up a global to hold output vector. @@ -2984,7 +3022,8 @@ const Shuffle& GetRandomTestShuffle(v8::base::RandomNumberGenerator* rng) { // random shuffles almost always generate the slow general shuffle code, so // don't exercise as many code paths. WASM_EXEC_TEST(I8x16ShuffleFuzz) { - v8::base::RandomNumberGenerator* rng = CcTest::random_number_generator(); + v8::base::RandomNumberGenerator* rng = + WasmExecutionTestBase::random_number_generator(); static const int kTests = 100; for (int i = 0; i < kTests; ++i) { auto shuffle = Combine(GetRandomTestShuffle(rng), GetRandomTestShuffle(rng), @@ -4192,7 +4231,9 @@ WASM_EXEC_TEST(Regress_12237) { WASM_ONE}); \ FOR_##Type##_INPUTS(x) { CHECK_EQ(1, r.Call(x)); } \ } -WASM_EXTRACT_I16x8_TEST(S, UINT16) WASM_EXTRACT_I16x8_TEST(I, INT16) +// clang-format off +WASM_EXTRACT_I16x8_TEST(S, UINT16) +WASM_EXTRACT_I16x8_TEST(I, INT16) #undef WASM_EXTRACT_I16x8_TEST #define WASM_EXTRACT_I8x16_TEST(Sign, Type) \ @@ -4213,12 +4254,14 @@ WASM_EXTRACT_I16x8_TEST(S, UINT16) WASM_EXTRACT_I16x8_TEST(I, INT16) WASM_ONE}); \ FOR_##Type##_INPUTS(x) { CHECK_EQ(1, r.Call(x)); } \ } - WASM_EXTRACT_I8x16_TEST(S, UINT8) WASM_EXTRACT_I8x16_TEST(I, INT8) +WASM_EXTRACT_I8x16_TEST(S, UINT8) +WASM_EXTRACT_I8x16_TEST(I, INT8) #undef WASM_EXTRACT_I8x16_TEST #ifdef V8_ENABLE_WASM_SIMD256_REVEC void RunSimd256ConstTest(const std::array<uint8_t, kSimd128Size>& expected) { + // clang-format on EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -4242,7 +4285,7 @@ void RunSimd256ConstTest(const std::array<uint8_t, kSimd128Size>& expected) { } } -TEST(RunWasmTurbofan_S256Const) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Const) { // All zeroes std::array<uint8_t, kSimd128Size> expected = {0}; RunSimd256ConstTest(expected); @@ -4275,7 +4318,7 @@ TEST(RunWasmTurbofan_S256Const) { RunSimd256ConstTest(expected); } -TEST(RunWasmTurbofan_ExtractF128) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtractF128) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int64_t, int32_t, int32_t, int32_t> r( @@ -4334,204 +4377,230 @@ TEST(RunWasmTurbofan_ExtractF128) { } } -TEST(RunWasmTurbofan_F32x8Abs) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Abs) { RunF32x8UnOpRevecTest(kExprF32x4Abs, std::abs); } -TEST(RunWasmTurbofan_F32x8Neg) { RunF32x8UnOpRevecTest(kExprF32x4Neg, Negate); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Neg) { + RunF32x8UnOpRevecTest(kExprF32x4Neg, Negate); +} -TEST(RunWasmTurbofan_F32x8Sqrt) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Sqrt) { RunF32x8UnOpRevecTest(kExprF32x4Sqrt, std::sqrt); } -TEST(RunWasmTurbofan_F32x8Ceil) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Ceil) { RunF32x8UnOpRevecTest(kExprF32x4Ceil, ceilf); } -TEST(RunWasmTurbofan_F32x8Floor) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Floor) { RunF32x8UnOpRevecTest(kExprF32x4Floor, floorf); } -TEST(RunWasmTurbofan_F32x8Trunc) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Trunc) { RunF32x8UnOpRevecTest(kExprF32x4Trunc, truncf); } -TEST(RunWasmTurbofan_F32x8NearestInt) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8NearestInt) { RunF32x8UnOpRevecTest(kExprF32x4NearestInt, nearbyintf); } -TEST(RunWasmTurbofan_F32x8Add) { RunF32x8BinOpRevecTest(kExprF32x4Add, Add); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Add) { + RunF32x8BinOpRevecTest(kExprF32x4Add, Add); +} -TEST(RunWasmTurbofan_F32x8Sub) { RunF32x8BinOpRevecTest(kExprF32x4Sub, Sub); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Sub) { + RunF32x8BinOpRevecTest(kExprF32x4Sub, Sub); +} -TEST(RunWasmTurbofan_F32x8Mul) { RunF32x8BinOpRevecTest(kExprF32x4Mul, Mul); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Mul) { + RunF32x8BinOpRevecTest(kExprF32x4Mul, Mul); +} -TEST(RunWasmTurbofan_F32x8Div) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Div) { RunF32x8BinOpRevecTest(kExprF32x4Div, base::Divide); } -TEST(RunWasmTurbofan_F32x8Min) { RunF32x8BinOpRevecTest(kExprF32x4Min, JSMin); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Min) { + RunF32x8BinOpRevecTest(kExprF32x4Min, JSMin); +} -TEST(RunWasmTurbofan_F32x8Max) { RunF32x8BinOpRevecTest(kExprF32x4Max, JSMax); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Max) { + RunF32x8BinOpRevecTest(kExprF32x4Max, JSMax); +} -TEST(RunWasmTurbofan_F32x8Pmin) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Pmin) { RunF32x8BinOpRevecTest(kExprF32x4Pmin, Minimum); } -TEST(RunWasmTurbofan_F32x8Pmax) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Pmax) { RunF32x8BinOpRevecTest(kExprF32x4Pmax, Maximum); } -TEST(RunWasmTurbofan_F32x8Eq) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Eq) { RunF32x8CompareOpRevecTest(kExprF32x4Eq, Equal); } -TEST(RunWasmTurbofan_F32x8Ne) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Ne) { RunF32x8CompareOpRevecTest(kExprF32x4Ne, NotEqual); } -TEST(RunWasmTurbofan_F32x8Lt) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Lt) { RunF32x8CompareOpRevecTest(kExprF32x4Lt, Less); } -TEST(RunWasmTurbofan_F32x8Le) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Le) { RunF32x8CompareOpRevecTest(kExprF32x4Le, LessEqual); } -TEST(RunWasmTurbofan_I64x4Shl) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Shl) { RunI64x4ShiftOpRevecTest(kExprI64x2Shl, LogicalShiftLeft); } -TEST(RunWasmTurbofan_I64x4ShrU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4ShrU) { RunI64x4ShiftOpRevecTest(kExprI64x2ShrU, LogicalShiftRight); } -TEST(RunWasmTurbofan_I64x4Add) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Add) { RunI64x4BinOpRevecTest(kExprI64x2Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_I64x4Sub) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Sub) { RunI64x4BinOpRevecTest(kExprI64x2Sub, base::SubWithWraparound); } -TEST(RunWasmTurbofan_I64x4Mul) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Mul) { RunI64x4BinOpRevecTest(kExprI64x2Mul, base::MulWithWraparound); } -TEST(RunWasmTurbofan_I64x4Eq) { RunI64x4BinOpRevecTest(kExprI64x2Eq, Equal); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Eq) { + RunI64x4BinOpRevecTest(kExprI64x2Eq, Equal); +} -TEST(RunWasmTurbofan_I64x4Ne) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Ne) { RunI64x4BinOpRevecTest(kExprI64x2Ne, NotEqual); } -TEST(RunWasmTurbofan_I64x4GtS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4GtS) { RunI64x4BinOpRevecTest(kExprI64x2GtS, Greater); } -TEST(RunWasmTurbofan_I64x4GeS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4GeS) { RunI64x4BinOpRevecTest(kExprI64x2GeS, GreaterEqual); } -TEST(RunWasmTurbofan_F64x4Abs) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Abs) { RunF64x4UnOpRevecTest(kExprF64x2Abs, std::abs); } -TEST(RunWasmTurbofan_F64x4Neg) { RunF64x4UnOpRevecTest(kExprF64x2Neg, Negate); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Neg) { + RunF64x4UnOpRevecTest(kExprF64x2Neg, Negate); +} -TEST(RunWasmTurbofan_F64x4Sqrt) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Sqrt) { RunF64x4UnOpRevecTest(kExprF64x2Sqrt, std::sqrt); } -TEST(RunWasmTurbofan_F64x4Add) { RunF64x4BinOpRevecTest(kExprF64x2Add, Add); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Add) { + RunF64x4BinOpRevecTest(kExprF64x2Add, Add); +} -TEST(RunWasmTurbofan_F64x4Sub) { RunF64x4BinOpRevecTest(kExprF64x2Sub, Sub); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Sub) { + RunF64x4BinOpRevecTest(kExprF64x2Sub, Sub); +} -TEST(RunWasmTurbofan_F64x4Mul) { RunF64x4BinOpRevecTest(kExprF64x2Mul, Mul); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Mul) { + RunF64x4BinOpRevecTest(kExprF64x2Mul, Mul); +} -TEST(RunWasmTurbofan_F64x4Div) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Div) { RunF64x4BinOpRevecTest(kExprF64x2Div, base::Divide); } -TEST(RunWasmTurbofan_F64x4Min) { RunF64x4BinOpRevecTest(kExprF64x2Min, JSMin); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Min) { + RunF64x4BinOpRevecTest(kExprF64x2Min, JSMin); +} -TEST(RunWasmTurbofan_F64x4Max) { RunF64x4BinOpRevecTest(kExprF64x2Max, JSMax); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Max) { + RunF64x4BinOpRevecTest(kExprF64x2Max, JSMax); +} -TEST(RunWasmTurbofan_F64x4Pmin) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Pmin) { RunF64x4BinOpRevecTest(kExprF64x2Pmin, Minimum); } -TEST(RunWasmTurbofan_F64x4Pmax) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Pmax) { RunF64x4BinOpRevecTest(kExprF64x2Pmax, Maximum); } -TEST(RunWasmTurbofan_F64x4Eq) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Eq) { RunF64x4CompareOpRevecTest(kExprF64x2Eq, Equal); } -TEST(RunWasmTurbofan_F64x4Ne) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Ne) { RunF64x4CompareOpRevecTest(kExprF64x2Ne, NotEqual); } -TEST(RunWasmTurbofan_F64x4Lt) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Lt) { RunF64x4CompareOpRevecTest(kExprF64x2Lt, Less); } -TEST(RunWasmTurbofan_F64x4Le) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Le) { RunF64x4CompareOpRevecTest(kExprF64x2Le, LessEqual); } -TEST(RunWasmTurbofan_I32x8SConvertF32x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8SConvertF32x8) { RunI32x8ConvertF32x8RevecTest<int32_t>(kExprI32x4SConvertF32x4, ConvertToInt); } -TEST(RunWasmTurbofan_I32x8UConvertF32x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8UConvertF32x8) { RunI32x8ConvertF32x8RevecTest<uint32_t>(kExprI32x4UConvertF32x4, ConvertToInt); } -TEST(RunWasmTurbofan_F32x8SConvertI32x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8SConvertI32x8) { RunF32x8ConvertI32x8RevecTest<int32_t>(kExprF32x4SConvertI32x4); } -TEST(RunWasmTurbofan_F32x8UConvertI32x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8UConvertI32x8) { RunF32x8ConvertI32x8RevecTest<uint32_t>(kExprF32x4UConvertI32x4); } -TEST(RunWasmTurbofan_I64x4SConvertI32x4) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4SConvertI32x4) { RunIntExtensionRevecTest<int32_t, int64_t>( kExprI64x2SConvertI32x4Low, kExprI64x2SConvertI32x4High, kExprI32x4Splat); } -TEST(RunWasmTurbofan_I64x4UConvertI32x4) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4UConvertI32x4) { RunIntExtensionRevecTest<uint32_t, uint64_t>( kExprI64x2UConvertI32x4Low, kExprI64x2UConvertI32x4High, kExprI32x4Splat); } -TEST(RunWasmTurbofan_I32x8SConvertI16x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8SConvertI16x8) { RunIntExtensionRevecTest<int16_t, int32_t>( kExprI32x4SConvertI16x8Low, kExprI32x4SConvertI16x8High, kExprI16x8Splat); } -TEST(RunWasmTurbofan_I32x8UConvertI16x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8UConvertI16x8) { RunIntExtensionRevecTest<uint16_t, uint32_t>( kExprI32x4UConvertI16x8Low, kExprI32x4UConvertI16x8High, kExprI16x8Splat); } -TEST(RunWasmTurbofan_I16x16SConvertI8x16) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16SConvertI8x16) { RunIntExtensionRevecTest<int8_t, int16_t>( kExprI16x8SConvertI8x16Low, kExprI16x8SConvertI8x16High, kExprI8x16Splat); } -TEST(RunWasmTurbofan_I16x16UConvertI8x16) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16UConvertI8x16) { RunIntExtensionRevecTest<uint8_t, uint16_t>( kExprI16x8UConvertI8x16Low, kExprI16x8UConvertI8x16High, kExprI8x16Splat); } -TEST(RunWasmTurbofan_I32x8Neg) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Neg) { RunI32x8UnOpRevecTest(kExprI32x4Neg, base::NegateWithWraparound); } -TEST(RunWasmTurbofan_I32x8Abs) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Abs) { RunI32x8UnOpRevecTest(kExprI32x4Abs, std::abs); } @@ -4580,42 +4649,44 @@ void RunExtAddPairwiseRevecTest(WasmOpcode ext_add_pairwise) { } } -TEST(RunWasmTurbofan_I16x16ExtAddPairwiseI8x32S) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16ExtAddPairwiseI8x32S) { RunExtAddPairwiseRevecTest<int8_t, int16_t>(kExprI16x8ExtAddPairwiseI8x16S); } -TEST(RunWasmTurbofan_I16x16ExtAddPairwiseI8x32U) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16ExtAddPairwiseI8x32U) { RunExtAddPairwiseRevecTest<uint8_t, uint16_t>(kExprI16x8ExtAddPairwiseI8x16U); } -TEST(RunWasmTurbofan_I32x8ExtAddPairwiseI16x16S) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8ExtAddPairwiseI16x16S) { RunExtAddPairwiseRevecTest<int16_t, int32_t>(kExprI32x4ExtAddPairwiseI16x8S); } -TEST(RunWasmTurbofan_I32x8ExtAddPairwiseI16x16U) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8ExtAddPairwiseI16x16U) { RunExtAddPairwiseRevecTest<uint16_t, uint32_t>( kExprI32x4ExtAddPairwiseI16x8U); } -TEST(RunWasmTurbofan_S256Not) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Not) { RunI32x8UnOpRevecTest(kExprS128Not, BitwiseNot); } -TEST(RunWasmTurbofan_S256And) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256And) { RunI32x8BinOpRevecTest(kExprS128And, BitwiseAnd); } -TEST(RunWasmTurbofan_S256Or) { RunI32x8BinOpRevecTest(kExprS128Or, BitwiseOr); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Or) { + RunI32x8BinOpRevecTest(kExprS128Or, BitwiseOr); +} -TEST(RunWasmTurbofan_S256Xor) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Xor) { RunI32x8BinOpRevecTest(kExprS128Xor, BitwiseXor); } -TEST(RunWasmTurbofan_S256AndNot) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256AndNot) { RunI32x8BinOpRevecTest(kExprS128AndNot, BitwiseAndNot); } -TEST(RunWasmTurbofan_S256Select) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Select) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t, int32_t, int32_t> r( @@ -4680,139 +4751,147 @@ TEST(RunWasmTurbofan_S256Select) { } } -TEST(RunWasmTurbofan_I32x8Add) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Add) { RunI32x8BinOpRevecTest(kExprI32x4Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_I32x8Sub) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Sub) { RunI32x8BinOpRevecTest(kExprI32x4Sub, base::SubWithWraparound); } -TEST(RunWasmTurbofan_I32x8Mul) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Mul) { RunI32x8BinOpRevecTest(kExprI32x4Mul, base::MulWithWraparound); } -TEST(RunWasmTurbofan_I32x8MinS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8MinS) { RunI32x8BinOpRevecTest(kExprI32x4MinS, Minimum); } -TEST(RunWasmTurbofan_I32x8MinU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8MinU) { RunI32x8BinOpRevecTest(kExprI32x4MinU, UnsignedMinimum); } -TEST(RunWasmTurbofan_I32x8MaxS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8MaxS) { RunI32x8BinOpRevecTest(kExprI32x4MaxS, Maximum); } -TEST(RunWasmTurbofan_I32x8MaxU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8MaxU) { RunI32x8BinOpRevecTest(kExprI32x4MaxU, UnsignedMaximum); } -TEST(RunWasmTurbofan_I32x8Eq) { RunI32x8BinOpRevecTest(kExprI32x4Eq, Equal); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Eq) { + RunI32x8BinOpRevecTest(kExprI32x4Eq, Equal); +} -TEST(RunWasmTurbofan_I32x8Ne) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Ne) { RunI32x8BinOpRevecTest(kExprI32x4Ne, NotEqual); } -TEST(RunWasmTurbofan_I32x8GtS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8GtS) { RunI32x8BinOpRevecTest(kExprI32x4GtS, Greater); } -TEST(RunWasmTurbofan_I32x8GtU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8GtU) { RunI32x8BinOpRevecTest<uint32_t>(kExprI32x4GtU, UnsignedGreater); } -TEST(RunWasmTurbofan_I32x8GeS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8GeS) { RunI32x8BinOpRevecTest(kExprI32x4GeS, GreaterEqual); } -TEST(RunWasmTurbofan_I32x8GeU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8GeU) { RunI32x8BinOpRevecTest<uint32_t>(kExprI32x4GeU, UnsignedGreaterEqual); } -TEST(RunWasmTurbofan_I32x8Shl) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Shl) { RunI32x8ShiftOpRevecTest(kExprI32x4Shl, LogicalShiftLeft); } -TEST(RunWasmTurbofan_I32x8ShrS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8ShrS) { RunI32x8ShiftOpRevecTest(kExprI32x4ShrS, ArithmeticShiftRight); } -TEST(RunWasmTurbofan_I32x8ShrU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8ShrU) { RunI32x8ShiftOpRevecTest(kExprI32x4ShrU, LogicalShiftRight); } -TEST(RunWasmTurbofan_I16x16Neg) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Neg) { RunI16x16UnOpRevecTest(kExprI16x8Neg, base::NegateWithWraparound); } -TEST(RunWasmTurbofan_I16x16Abs) { RunI16x16UnOpRevecTest(kExprI16x8Abs, Abs); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Abs) { + RunI16x16UnOpRevecTest(kExprI16x8Abs, Abs); +} -TEST(RunWasmTurbofan_I16x16Add) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Add) { RunI16x16BinOpRevecTest(kExprI16x8Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_I16x16Sub) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Sub) { RunI16x16BinOpRevecTest(kExprI16x8Sub, base::SubWithWraparound); } -TEST(RunWasmTurbofan_I16x16Mul) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Mul) { RunI16x16BinOpRevecTest(kExprI16x8Mul, base::MulWithWraparound); } -TEST(RunWasmTurbofan_I16x16AddSatS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16AddSatS) { RunI16x16BinOpRevecTest<int16_t>(kExprI16x8AddSatS, SaturateAdd); } -TEST(RunWasmTurbofan_I16x16SubSatS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16SubSatS) { RunI16x16BinOpRevecTest<int16_t>(kExprI16x8SubSatS, SaturateSub); } -TEST(RunWasmTurbofan_I16x16AddSatU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16AddSatU) { RunI16x16BinOpRevecTest<uint16_t>(kExprI16x8AddSatU, SaturateAdd); } -TEST(RunWasmTurbofan_I16x16SubSatU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16SubSatU) { RunI16x16BinOpRevecTest<uint16_t>(kExprI16x8SubSatU, SaturateSub); } -TEST(WasmTurbofan_I16x16Eq) { RunI16x16BinOpRevecTest(kExprI16x8Eq, Equal); } +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16Eq) { + RunI16x16BinOpRevecTest(kExprI16x8Eq, Equal); +} -TEST(WasmTurbofan_I16x16Ne) { RunI16x16BinOpRevecTest(kExprI16x8Ne, NotEqual); } +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16Ne) { + RunI16x16BinOpRevecTest(kExprI16x8Ne, NotEqual); +} -TEST(WasmTurbofan_I16x16GtS) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16GtS) { RunI16x16BinOpRevecTest(kExprI16x8GtS, Greater); } -TEST(WasmTurbofan_I16x16GtU) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16GtU) { RunI16x16BinOpRevecTest<uint16_t>(kExprI16x8GtU, UnsignedGreater); } -TEST(WasmTurbofan_I16x16GeS) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16GeS) { RunI16x16BinOpRevecTest(kExprI16x8GeS, GreaterEqual); } -TEST(WasmTurbofan_I16x16GeU) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16GeU) { RunI16x16BinOpRevecTest<uint16_t>(kExprI16x8GeU, UnsignedGreaterEqual); } -TEST(WasmTurbofan_I16x16MinS) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16MinS) { RunI16x16BinOpRevecTest(kExprI16x8MinS, Minimum); } -TEST(WasmTurbofan_I16x16MinU) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16MinU) { RunI16x16BinOpRevecTest(kExprI16x8MinU, UnsignedMinimum); } -TEST(WasmTurbofan_I16x16MaxS) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16MaxS) { RunI16x16BinOpRevecTest(kExprI16x8MaxS, Maximum); } -TEST(WasmTurbofan_I16x16MaxU) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16MaxU) { RunI16x16BinOpRevecTest(kExprI16x8MaxU, UnsignedMaximum); } -TEST(WasmTurbofan_I16x16RoundingAverageU) { +TEST_F(RunWasmSimdTest, WasmTurbofan_I16x16RoundingAverageU) { RunI16x16BinOpRevecTest<uint16_t>(kExprI16x8RoundingAverageU, RoundingAverageUnsigned); } @@ -4933,7 +5012,7 @@ void RunExtMulRevecTest(WasmOpcode opcode_low, WasmOpcode opcode_high, // (high, high) extmul, force pack, revec succeed. // (high, low) extmul, revec failed, not // supported yet. -TEST(RunWasmTurbofan_ForcePackExtMul) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackExtMul) { // 8x16 to 16x8. RunExtMulRevecTest<int8_t, int16_t, compiler::turboshaft::Opcode::kSimd256Binop>( @@ -5101,7 +5180,7 @@ void RunExtMulRevecTestSplat(WasmOpcode opcode, OpType expected_op) { } } -TEST(RunWasmTurbofan_ForcePackExtMulSplat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackExtMulSplat) { // 8x16 to 16x8. RunExtMulRevecTestSplat<int8_t, int16_t, compiler::turboshaft::Opcode::kSimdPack128To256>( @@ -5145,7 +5224,7 @@ TEST(RunWasmTurbofan_ForcePackExtMulSplat) { kExprI64x2ExtMulHighI32x4U, MultiplyLong); } -TEST(RunWasmTurbofan_ExtMulContinuousLoadRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtMulContinuousLoadRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -5218,92 +5297,96 @@ TEST(RunWasmTurbofan_ExtMulContinuousLoadRevec) { } } -TEST(RunWasmTurbofan_I16x16Shl) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Shl) { RunI16x16ShiftOpRevecTest(kExprI16x8Shl, LogicalShiftLeft); } -TEST(RunWasmTurbofan_I16x16ShrS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16ShrS) { RunI16x16ShiftOpRevecTest(kExprI16x8ShrS, ArithmeticShiftRight); } -TEST(RunWasmTurbofan_I16x16ShrU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16ShrU) { RunI16x16ShiftOpRevecTest(kExprI16x8ShrU, LogicalShiftRight); } -TEST(RunWasmTurbofan_I8x32Neg) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Neg) { RunI8x32UnOpRevecTest(kExprI8x16Neg, base::NegateWithWraparound); } -TEST(RunWasmTurbofan_I8x32Abs) { RunI8x32UnOpRevecTest(kExprI8x16Abs, Abs); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Abs) { + RunI8x32UnOpRevecTest(kExprI8x16Abs, Abs); +} -TEST(RunWasmTurbofan_I8x32Add) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Add) { RunI8x32BinOpRevecTest(kExprI8x16Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_I8x32Sub) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Sub) { RunI8x32BinOpRevecTest(kExprI8x16Sub, base::SubWithWraparound); } -TEST(RunWasmTurbofan_I8x32AddSatS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32AddSatS) { RunI8x32BinOpRevecTest<int8_t>(kExprI8x16AddSatS, SaturateAdd); } -TEST(RunWasmTurbofan_I8x32SubSatS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32SubSatS) { RunI8x32BinOpRevecTest<int8_t>(kExprI8x16SubSatS, SaturateSub); } -TEST(RunWasmTurbofan_I8x32AddSatU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32AddSatU) { RunI8x32BinOpRevecTest<uint8_t>(kExprI8x16AddSatU, SaturateAdd); } -TEST(RunWasmTurbofan_I8x32SubSatU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32SubSatU) { RunI8x32BinOpRevecTest<uint8_t>(kExprI8x16SubSatU, SaturateSub); } -TEST(RunWasmTurbofan_I8x32Eq) { RunI8x32BinOpRevecTest(kExprI8x16Eq, Equal); } +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Eq) { + RunI8x32BinOpRevecTest(kExprI8x16Eq, Equal); +} -TEST(RunWasmTurbofan_I8x32Ne) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Ne) { RunI8x32BinOpRevecTest(kExprI8x16Ne, NotEqual); } -TEST(RunWasmTurbofan_I8x32GtS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32GtS) { RunI8x32BinOpRevecTest(kExprI8x16GtS, Greater); } -TEST(RunWasmTurbofan_I8x32GtU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32GtU) { RunI8x32BinOpRevecTest<uint8_t>(kExprI8x16GtU, UnsignedGreater); } -TEST(RunWasmTurbofan_I8x32GeS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32GeS) { RunI8x32BinOpRevecTest(kExprI8x16GeS, GreaterEqual); } -TEST(RunWasmTurbofan_I8x32GeU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32GeU) { RunI8x32BinOpRevecTest<uint8_t>(kExprI8x16GeU, UnsignedGreaterEqual); } -TEST(RunWasmTurbofan_I8x32MinS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32MinS) { RunI8x32BinOpRevecTest(kExprI8x16MinS, Minimum); } -TEST(RunWasmTurbofan_I8x32MinU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32MinU) { RunI8x32BinOpRevecTest(kExprI8x16MinU, UnsignedMinimum); } -TEST(RunWasmTurbofan_I8x32MaxS) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32MaxS) { RunI8x32BinOpRevecTest(kExprI8x16MaxS, Maximum); } -TEST(RunWasmTurbofan_I8x32MaxU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32MaxU) { RunI8x32BinOpRevecTest(kExprI8x16MaxU, UnsignedMaximum); } -TEST(RunWasmTurbofan_I8x32RoundingAverageU) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32RoundingAverageU) { RunI8x32BinOpRevecTest<uint8_t>(kExprI8x16RoundingAverageU, RoundingAverageUnsigned); } -TEST(RunWasmTurbofan_F32x4AddRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x4AddRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5352,7 +5435,7 @@ TEST(RunWasmTurbofan_F32x4AddRevec) { CHECK_EQ(23.0f, r.Call(0, 32)); } -TEST(RunWasmTurbofan_LoadStoreExtractRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_LoadStoreExtractRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5395,7 +5478,7 @@ TEST(RunWasmTurbofan_LoadStoreExtractRevec) { } #ifdef V8_TARGET_ARCH_X64 -TEST(RunWasmTurbofan_LoadStoreExtract2Revec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_LoadStoreExtract2Revec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5440,7 +5523,7 @@ TEST(RunWasmTurbofan_LoadStoreExtract2Revec) { CHECK_EQ(2.0f, r.Call(0, 32)); } -TEST(RunWasmTurbofan_ExtractCallParameterRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtractCallParameterRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5560,14 +5643,14 @@ void RunExtractByShuffleRevecTest( } } -TEST(RunWasmTurbofan_Extract128LowForUnzipLow) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_Extract128LowForUnzipLow) { ShuffleMap::const_iterator it = test_shuffles.find(kS8x16UnzipLeft); DCHECK_NE(it, test_shuffles.end()); // ExtractF128 used by S8x16UnzipLow and checked in ASSEMBLE_SIMD_INSTR. RunExtractByShuffleRevecTest(it->second); } -TEST(RunWasmTurbofan_Extract128LowForUnpackLow) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_Extract128LowForUnpackLow) { // shuffle32x4 [0,4,1,5] const std::array<int8_t, 16> shuffle_unpack_low = { 0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23}; @@ -5576,7 +5659,7 @@ TEST(RunWasmTurbofan_Extract128LowForUnpackLow) { RunExtractByShuffleRevecTest(shuffle_unpack_low); } -TEST(RunWasmTurbofan_Extract128LowForS32x4Shuffle) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_Extract128LowForS32x4Shuffle) { // shuffle32x4 [0,1,2,4] const std::array<int8_t, 16> shuffle = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19}; @@ -5584,14 +5667,14 @@ TEST(RunWasmTurbofan_Extract128LowForS32x4Shuffle) { RunExtractByShuffleRevecTest(shuffle); } -TEST(RunWasmTurbofan_Extract128LowForS16x8Blend) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_Extract128LowForS16x8Blend) { const std::array<int8_t, 16> shuffle_16x8_blend = { 0, 1, 18, 19, 4, 5, 22, 23, 8, 9, 26, 27, 12, 13, 30, 31}; // ExtractF128 used by S16x8Blend and checked in ASSEMBLE_SIMD_IMM_SHUFFLE. RunExtractByShuffleRevecTest(shuffle_16x8_blend); } -TEST(RunWasmTurbofan_LoadStoreOOBRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_LoadStoreOOBRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5624,7 +5707,7 @@ TEST(RunWasmTurbofan_LoadStoreOOBRevec) { } #endif // V8_TARGET_ARCH_X64 -TEST(RunWasmTurbofan_ReversedLoadStoreExtractRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ReversedLoadStoreExtractRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5664,7 +5747,7 @@ TEST(RunWasmTurbofan_ReversedLoadStoreExtractRevec) { CHECK_EQ(4.0f, r.Call(0, 32)); } -TEST(RunWasmTurbofan_ReturnUseSimd128Revec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ReturnUseSimd128Revec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5713,7 +5796,7 @@ TEST(RunWasmTurbofan_ReturnUseSimd128Revec) { CHECK_EQ(3.0f, r.Call(0, 32)); } -TEST(RunWasmTurbofan_TupleUseSimd128Revec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_TupleUseSimd128Revec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5757,7 +5840,7 @@ TEST(RunWasmTurbofan_TupleUseSimd128Revec) { CHECK_EQ(2.0f, r.builder().ReadMemory(&memory[14])); } -TEST(RunWasmTurbofan_F32x4ShuffleForSplatRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x4ShuffleForSplatRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5810,7 +5893,7 @@ TEST(RunWasmTurbofan_F32x4ShuffleForSplatRevec) { CHECK_EQ(23.0f, r.Call(0, 32)); } -TEST(RunWasmTurbofan_I32x4ShuffleSplatRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x4ShuffleSplatRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -5864,7 +5947,7 @@ TEST(RunWasmTurbofan_I32x4ShuffleSplatRevec) { CHECK_EQ(23, r.Call(0, 32)); } -TEST(RunWasmTurbofan_I64x2ShuffleForSplatRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x2ShuffleForSplatRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t, int64_t> r( @@ -5915,7 +5998,7 @@ TEST(RunWasmTurbofan_I64x2ShuffleForSplatRevec) { } } -TEST(RunWasmTurbofan_ShuffleVpshufd) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleVpshufd) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; int32_t* memory; @@ -5992,7 +6075,7 @@ TEST(RunWasmTurbofan_ShuffleVpshufd) { // Can't merge Shuffle(a, a) and shuffle(b,b) // if a and b have different opcodes -TEST(RunWasmTurbofan_ShuffleVpshufdExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleVpshufdExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -6044,7 +6127,7 @@ TEST(RunWasmTurbofan_ShuffleVpshufdExpectFail) { } } -TEST(RunWasmTurbofan_I8x32ShuffleShufps) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32ShuffleShufps) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -6095,7 +6178,7 @@ TEST(RunWasmTurbofan_I8x32ShuffleShufps) { } } -TEST(RunWasmTurbofan_I8x32ShuffleS32x8UnpackLow) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32ShuffleS32x8UnpackLow) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -6147,7 +6230,7 @@ TEST(RunWasmTurbofan_I8x32ShuffleS32x8UnpackLow) { } } -TEST(RunWasmTurbofan_I8x32ShuffleS32x8UnpackHigh) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32ShuffleS32x8UnpackHigh) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -6199,7 +6282,7 @@ TEST(RunWasmTurbofan_I8x32ShuffleS32x8UnpackHigh) { } } -TEST(RunWasmTurbofan_ShuffleToS256Load8x8U) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8U) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int8_t> r(TestExecutionTier::kTurbofan); @@ -6272,7 +6355,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8U) { // cases where the conditions are not met. // Shuffle with same input e, shuffle(e, e, x). -TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail1) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail1) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int8_t> r(TestExecutionTier::kTurbofan); @@ -6312,7 +6395,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail1) { } // Not the same left, c.left_idx != d.left_idx. -TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail2) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail2) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int8_t> r(TestExecutionTier::kTurbofan); @@ -6358,7 +6441,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail2) { } // Shuffle left is not Simd128LoadTransformOp, a != S128Load64Zero(memory). -TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail3) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail3) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int8_t> r(TestExecutionTier::kTurbofan); @@ -6401,7 +6484,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail3) { } // a = S128Load32Zero(memory), not S128Load64Zero(memory). -TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail4) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail4) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int8_t> r(TestExecutionTier::kTurbofan); @@ -6446,7 +6529,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail4) { // Shuffle indices s1/s2 don't met the conditions, or // b != S128Zero. -TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail5) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail5) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -6561,7 +6644,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8UExpectFail5) { // shuffles. The vector load-transform is emitted at the load's own // position (see WasmRevecReducer::REDUCE_INPUT_GRAPH // (Simd128LoadTransform)), so it can't observe the later store. -TEST(RunWasmTurbofan_ShuffleToS256Load8x8USideEffectCheck) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8USideEffectCheck) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int8_t> r(TestExecutionTier::kTurbofan); @@ -6625,7 +6708,7 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8USideEffectCheck) { // the vector load-transform at the load's own position is only sound when // it and the shuffles are reduced in the same relative order as they // appear here, which requires them to be in the same block. -TEST(RunWasmTurbofan_ShuffleToS256Load8x8UDifferentBlock) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ShuffleToS256Load8x8UDifferentBlock) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -6667,7 +6750,8 @@ TEST(RunWasmTurbofan_ShuffleToS256Load8x8UDifferentBlock) { // Test that Load splat revectorization is rejected when the shared load and // its consuming shuffle are not in the same basic block, similar to Load8x8U. -TEST(RunWasmTurbofan_ShuffleToS256Load32SplatDifferentBlock) { +TEST_F(RunWasmSimdTest, + RunWasmTurbofan_ShuffleToS256Load32SplatDifferentBlock) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -6778,48 +6862,48 @@ void RunLoadSplatRevecTest(WasmOpcode op, WasmOpcode bin_op, #undef BUILD_LOADSPLAT } -TEST(RunWasmTurbofan_S256Load8Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load8Splat) { RunLoadSplatRevecTest<int8_t>(kExprS128Load8Splat, kExprI8x16Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load16Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load16Splat) { RunLoadSplatRevecTest<int16_t>(kExprS128Load16Splat, kExprI16x8Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load32Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load32Splat) { RunLoadSplatRevecTest<int32_t>(kExprS128Load32Splat, kExprI32x4Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load64Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load64Splat) { RunLoadSplatRevecTest<int64_t>(kExprS128Load64Splat, kExprI64x2Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load8SplatMemory64) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load8SplatMemory64) { RunLoadSplatRevecTest<int8_t, true>(kExprS128Load8Splat, kExprI8x16Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load16SplatMemory64) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load16SplatMemory64) { RunLoadSplatRevecTest<int16_t, true>(kExprS128Load16Splat, kExprI16x8Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load32SplatMemory64) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load32SplatMemory64) { RunLoadSplatRevecTest<int32_t, true>(kExprS128Load32Splat, kExprI32x4Add, base::AddWithWraparound); } -TEST(RunWasmTurbofan_S256Load64SplatMemory64) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256Load64SplatMemory64) { RunLoadSplatRevecTest<int64_t, true>(kExprS128Load64Splat, kExprI64x2Add, base::AddWithWraparound); } // Use load32splat for the reordered loadsplat test. -TEST(RunWasmTurbofan_S256ReorderedLoad32Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_S256ReorderedLoad32Splat) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); @@ -6973,36 +7057,36 @@ void RunLoadExtendRevecTest(WasmOpcode op) { #undef BUILD_LOADEXTEND } -TEST(S128Load8x8U) { +TEST_F(RunWasmSimdTest, S128Load8x8U) { RunLoadExtendRevecTest<uint8_t, uint16_t>(kExprS128Load8x8U); } -TEST(S128Load8x8S) { +TEST_F(RunWasmSimdTest, S128Load8x8S) { RunLoadExtendRevecTest<int8_t, int16_t>(kExprS128Load8x8S); } -TEST(S128Load16x4U) { +TEST_F(RunWasmSimdTest, S128Load16x4U) { RunLoadExtendRevecTest<uint16_t, uint32_t>(kExprS128Load16x4U); } -TEST(S128Load16x4S) { +TEST_F(RunWasmSimdTest, S128Load16x4S) { RunLoadExtendRevecTest<int16_t, int32_t>(kExprS128Load16x4S); } -TEST(S128Load32x2U) { +TEST_F(RunWasmSimdTest, S128Load32x2U) { RunLoadExtendRevecTest<uint32_t, uint64_t>(kExprS128Load32x2U); } -TEST(S128Load32x2S) { +TEST_F(RunWasmSimdTest, S128Load32x2S) { RunLoadExtendRevecTest<int32_t, int64_t>(kExprS128Load32x2S); } // Use Load8x8U for reorder test. -TEST(S128Load8x8UReorder) { +TEST_F(RunWasmSimdTest, S128Load8x8UReorder) { RunLoadExtendRevecTest<uint8_t, uint16_t, true>(kExprS128Load8x8U); } -TEST(RunWasmTurbofan_I8x32Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int8_t> r(TestExecutionTier::kTurbofan); @@ -7027,7 +7111,7 @@ TEST(RunWasmTurbofan_I8x32Splat) { } } -TEST(RunWasmTurbofan_I16x16Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int16_t> r(TestExecutionTier::kTurbofan); @@ -7052,7 +7136,7 @@ TEST(RunWasmTurbofan_I16x16Splat) { } } -TEST(RunWasmTurbofan_I32x8Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -7079,7 +7163,7 @@ TEST(RunWasmTurbofan_I32x8Splat) { } } -TEST(RunWasmTurbofan_I32x8SplatConst) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x8SplatConst) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7104,7 +7188,7 @@ TEST(RunWasmTurbofan_I32x8SplatConst) { } } -TEST(RunWasmTurbofan_Simd256AsSimd128) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_Simd256AsSimd128) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7149,7 +7233,7 @@ TEST(RunWasmTurbofan_Simd256AsSimd128) { } } -TEST(RunWasmTurbofan_I64x4Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I64x4Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int64_t> r(TestExecutionTier::kTurbofan); @@ -7175,7 +7259,7 @@ TEST(RunWasmTurbofan_I64x4Splat) { } } -TEST(RunWasmTurbofan_F16x16Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F16x16Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); EXPERIMENTAL_FLAG_SCOPE(fp16); if (!CpuFeatures::IsSupported(AVX2) || !CpuFeatures::IsSupported(F16C)) { @@ -7209,7 +7293,7 @@ TEST(RunWasmTurbofan_F16x16Splat) { } } -TEST(RunWasmTurbofan_F32x8Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F32x8Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, float> r(TestExecutionTier::kTurbofan); @@ -7239,7 +7323,7 @@ TEST(RunWasmTurbofan_F32x8Splat) { } } -TEST(RunWasmTurbofan_F64x4Splat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_F64x4Splat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, double> r(TestExecutionTier::kTurbofan); @@ -7269,7 +7353,7 @@ TEST(RunWasmTurbofan_F64x4Splat) { } } -TEST(RunWasmTurbofan_Phi) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_Phi) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -7334,7 +7418,7 @@ TEST(RunWasmTurbofan_Phi) { } } -TEST(RunWasmTurbofan_ForcePackIdenticalLoad) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackIdenticalLoad) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7373,7 +7457,7 @@ TEST(RunWasmTurbofan_ForcePackIdenticalLoad) { } } -TEST(RunWasmTurbofan_ForcePackedNodesNoExtract) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackedNodesNoExtract) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7413,7 +7497,7 @@ TEST(RunWasmTurbofan_ForcePackedNodesNoExtract) { } } -TEST(RunWasmTurbofan_ForcePackLoadsAtSameAddr) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackLoadsAtSameAddr) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7452,7 +7536,7 @@ TEST(RunWasmTurbofan_ForcePackLoadsAtSameAddr) { } } -TEST(RunWasmTurbofan_ForcePackInContinuousLoad) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackInContinuousLoad) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7498,7 +7582,7 @@ TEST(RunWasmTurbofan_ForcePackInContinuousLoad) { } } -TEST(RunWasmTurbofan_ForcePackIncontinuousLoadsReversed) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackIncontinuousLoadsReversed) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -7542,7 +7626,7 @@ TEST(RunWasmTurbofan_ForcePackIncontinuousLoadsReversed) { } } -TEST(RunWasmTurbofan_RevecReduce) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_RevecReduce) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int64_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -7587,7 +7671,7 @@ TEST(RunWasmTurbofan_RevecReduce) { } } -TEST(RunWasmTurbofan_ForcePackLoadSplat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackLoadSplat) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; // Use Load32Splat for the force packing test. @@ -7634,7 +7718,7 @@ TEST(RunWasmTurbofan_ForcePackLoadSplat) { } } -TEST(RunWasmTurbofan_ForcePackLoadExtend) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackLoadExtend) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; // Use load32x2_s for the force packing test. @@ -7757,7 +7841,7 @@ TEST(RunWasmTurbofan_ForcePackLoadExtend) { } } -TEST(RunWasmTurbofan_ForcePackLoadLane) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackLoadLane) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -7932,7 +8016,7 @@ void RunIntToIntExtensionRevecForcePack( // (high, high) sign extend, revec succeed. // (high, low) unsign extend, revec failed, not supported yet. // (high, low) sign extend, revec failed, not supported yet. -TEST(RunWasmTurbofan_ForcePackIntToIntExtension) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackIntToIntExtension) { // Extend 8 bits to 16 bits. RunIntToIntExtensionRevecForcePack<uint8_t, uint16_t>( kExprI16x8UConvertI8x16Low, kExprI16x8UConvertI8x16Low); @@ -8054,7 +8138,7 @@ void RunIntToIntExtensionRevecForcePackSplat(WasmOpcode opcode) { } } -TEST(RunWasmTurbofan_ForcePackIntToIntExtensionSplat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackIntToIntExtensionSplat) { // Extend 8 bits to 16 bits. RunIntToIntExtensionRevecForcePackSplat<uint8_t, uint16_t>( kExprI16x8UConvertI8x16Low); @@ -8139,7 +8223,7 @@ void RunIntToIntExtensionRevecLoadSplat(WasmOpcode opcode1) { } } -TEST(RunWasmTurbofan_IntToIntExtensionLoadSplat) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_IntToIntExtensionLoadSplat) { // Extend 8 bits to 16 bits. RunIntToIntExtensionRevecLoadSplat<uint8_t, uint16_t>( kExprI16x8UConvertI8x16Low); @@ -8171,7 +8255,7 @@ TEST(RunWasmTurbofan_IntToIntExtensionLoadSplat) { kExprI64x2SConvertI32x4High); } -TEST(RunWasmTurbofan_ExtendLowHighRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendLowHighRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -8251,7 +8335,7 @@ TEST(RunWasmTurbofan_ExtendLowHighRevec) { ExpectedResult::kFail); } -TEST(RunWasmTurbofan_ForcePackI16x16ConvertI8x16ExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackI16x16ConvertI8x16ExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -8293,7 +8377,7 @@ TEST(RunWasmTurbofan_ForcePackI16x16ConvertI8x16ExpectFail) { } } -TEST(RunWasmTurbofan_ForcePackInternalI16x16ConvertI8x16) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackInternalI16x16ConvertI8x16) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -8356,7 +8440,7 @@ TEST(RunWasmTurbofan_ForcePackInternalI16x16ConvertI8x16) { } } -TEST(RunWasmTurbofan_ForcePackLoadZero) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackLoadZero) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; // Use load32_zero for the force packing test. @@ -8446,7 +8530,7 @@ TEST(RunWasmTurbofan_ForcePackLoadZero) { } } -TEST(RunWasmTurbofan_ForcePackInputWithSideEffect) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackInputWithSideEffect) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -8509,7 +8593,7 @@ TEST(RunWasmTurbofan_ForcePackInputWithSideEffect) { } } -TEST(RunWasmTurbofan_ForcePackWithForcePackedInputs) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackWithForcePackedInputs) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -8584,7 +8668,7 @@ TEST(RunWasmTurbofan_ForcePackWithForcePackedInputs) { } } -TEST(RunWasmTurbofan_ForcePackWithForcePackedInputs2) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackWithForcePackedInputs2) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -8633,7 +8717,7 @@ TEST(RunWasmTurbofan_ForcePackWithForcePackedInputs2) { } } -TEST(RunWasmTurbofan_ForcePackInputsExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackInputsExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -8702,7 +8786,7 @@ TEST(RunWasmTurbofan_ForcePackInputsExpectFail) { } } -TEST(RunWasmTurbofan_TwoForcePackExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_TwoForcePackExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -8757,7 +8841,7 @@ TEST(RunWasmTurbofan_TwoForcePackExpectFail) { } } -TEST(RunWasmTurbofan_ForcePackInputsRevisited) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackInputsRevisited) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -8885,15 +8969,15 @@ void RunForcePackF32x4ReplaceLaneIntersectTest() { CHECK_EQ(Mul(Add(3.14f, 2.0f), 2.0f), memory[14]); } -TEST(RunWasmTurbofan_ForcePackF32x4ReplaceLaneIntersect1) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackF32x4ReplaceLaneIntersect1) { RunForcePackF32x4ReplaceLaneIntersectTest<false>(); } -TEST(RunWasmTurbofan_ForcePackF32x4ReplaceLaneIntersect2) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackF32x4ReplaceLaneIntersect2) { RunForcePackF32x4ReplaceLaneIntersectTest<true>(); } -TEST(RunWasmTurbofan_ForcePackWithIntersectedInputs) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackWithIntersectedInputs) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -8951,7 +9035,7 @@ TEST(RunWasmTurbofan_ForcePackWithIntersectedInputs) { } } -TEST(RunWasmTurbofan_IntersectPackNodeMerge1) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_IntersectPackNodeMerge1) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -9025,7 +9109,7 @@ TEST(RunWasmTurbofan_IntersectPackNodeMerge1) { CHECK_EQ(Add(Add(2.0f, 2.0f), 2.0f), memory[22]); } -TEST(RunWasmTurbofan_IntersectPackNodeMerge2) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_IntersectPackNodeMerge2) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -9104,7 +9188,7 @@ TEST(RunWasmTurbofan_IntersectPackNodeMerge2) { CHECK_EQ(Add(Add(3.14f, 2.0f), 2.0f), memory[22]); } -TEST(RunWasmTurbofan_IntersectPackNodeMerge3) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_IntersectPackNodeMerge3) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -9191,7 +9275,7 @@ TEST(RunWasmTurbofan_IntersectPackNodeMerge3) { CHECK_EQ(Add(Add(3.14f, 3.0f), 2.0f), memory[23]); } -TEST(RunWasmTurbofan_ForcePackExtractInputsTest) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ForcePackExtractInputsTest) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -9259,7 +9343,7 @@ TEST(RunWasmTurbofan_ForcePackExtractInputsTest) { CHECK_EQ(0.1f, memory[16]); } -TEST(RunWasmTurbofan_RevecCommutativeOp) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_RevecCommutativeOp) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t, int32_t> r( @@ -9314,26 +9398,27 @@ TEST(RunWasmTurbofan_RevecCommutativeOp) { } } -TEST(RunWasmTurbofan_I16x16SConvertI32x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16SConvertI32x8) { RunIntToIntNarrowingRevecTest<int32_t, int16_t>(kExprI16x8SConvertI32x4); } -TEST(RunWasmTurbofan_I16x16UConvertI32x8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I16x16UConvertI32x8) { RunIntToIntNarrowingRevecTest<int32_t, uint16_t>(kExprI16x8UConvertI32x4); } -TEST(RunWasmTurbofan_I8x32SConvertI16x16) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32SConvertI16x16) { RunIntToIntNarrowingRevecTest<int16_t, int8_t>(kExprI8x16SConvertI16x8); } -TEST(RunWasmTurbofan_I8x32UConvertI16x16) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I8x32UConvertI16x16) { RunIntToIntNarrowingRevecTest<int16_t, uint8_t>(kExprI8x16UConvertI16x8); } #define RunExtendIntToF32x4RevecTest(format, sign, convert_opcode, \ convert_sign, param_type, extract_type, \ convert_type) \ - TEST(RunWasmTurbofan_Extend##format##sign##ConvertF32x8##convert_sign) { \ + TEST_F(RunWasmSimdTest, \ + RunWasmTurbofan_Extend##format##sign##ConvertF32x8##convert_sign) { \ EXPERIMENTAL_FLAG_SCOPE(revectorize); \ if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) \ return; \ @@ -9500,7 +9585,7 @@ RunExtendIntToF32x4RevecTest(I16x8, , kExprF32SConvertI32, S, int16_t, // are the cases where the conditions are not met. // Data type is f64x2, not f32x4. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail1) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail1) { WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); int64_t* memory = r.builder().AddMemoryElems<int64_t>(4); uint8_t temp1 = r.AllocateLocal(kWasmS128); @@ -9534,7 +9619,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail1) { // clang-format on // Convert i32 constant to f32, not extracted from v128. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail2) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail2) { WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); float* memory = r.builder().AddMemoryElems<float>(8); uint8_t temp1 = r.AllocateLocal(kWasmS128); @@ -9575,7 +9660,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail2) { // v0/w0 is constructed from a directly, extract_lane is not used. // v0 = f32x4.convert_i32x4_s(i32x4.extend_low_i16x8_s(a)); // w0 = f32x4.convert_i32x4_s(i32x4.extend_high_i16x8_s(a)); -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail3) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail3) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -9663,7 +9748,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail3) { // f32x4.extract_lane(f32x4.convert_i32x4_s(i32x4.extend_low_i16x8_s(a)),0)); // w0 = f32x4.splat( // f32x4.extract_lane(f32x4.convert_i32x4_s(i32x4.extend_high_i16x8_s(a)),0)); -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail4) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail4) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -9752,7 +9837,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail4) { // A additional load is used to construct v0/w0, a is not used. // v0 = f32x4.splat(f32.convert_i32_s(I32LoadMem16S(mem))); // w0 = f32x4.splat(f32.convert_i32_s(I32LoadMem16S(mem+8))); -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail5) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail5) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -9838,7 +9923,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail5) { // Mixed use of sign and unsign covert i32 to f32: // Unsign convert is used in lane 0 2 4 6 of a. // Sign convert is used in lane 1 3 5 7 of a. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail6) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail6) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -9929,7 +10014,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail6) { // Mixed use of sign and unsign covert i32 to f32: // Unsign convert is used in lane 0 1 2 3 of a. // Sign convert is used in lane 4 5 6 7 of a. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail7) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail7) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -10020,7 +10105,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail7) { // Mixed use of sign and unsign extract_lane: // Unsign extract_lane is used in lane 0 2 4 6 of a. // Sign extract_lane is used in lane 1 3 5 7 of a. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail8) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail8) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -10111,7 +10196,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail8) { // Two different inputs are used: // a0 = S128Load64Zero(mem); // a1 = S128Load64Zero(mem+8); -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail9) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail9) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -10210,7 +10295,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail9) { // Unsign extract i8x16 lane to i32 and unsign convert i32 to float. // Lane indices are not continuous or the minimal index is not 0/8. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail10) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail10) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; uint8_t* memory; @@ -10423,7 +10508,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail10) { // Similar to ExtendIntToF32x4RevecExpectedFail10, // but sign extract i8x16 lane to i32 and sign convert i32 to float. // Lane indices are not continuous or the minimal index is not 0/8. -TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail11) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail11) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; uint8_t* memory; @@ -10633,7 +10718,7 @@ TEST(RunWasmTurbofan_ExtendIntToF32x4RevecExpectedFail11) { } } -TEST(RunWasmTurbofan_ChangeIndexFromI32ToI64ExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ChangeIndexFromI32ToI64ExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -10662,7 +10747,7 @@ TEST(RunWasmTurbofan_ChangeIndexFromI32ToI64ExpectFail) { } // Two splat have same constant value, may be revectorized. -TEST(RunWasmTurbofan_ConstSplatRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ConstSplatRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; @@ -10713,7 +10798,7 @@ TEST(RunWasmTurbofan_ConstSplatRevec) { } // Two Splat from different value, not constant -TEST(RunWasmTurbofan_I32x4SplatRevecExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_I32x4SplatRevecExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -10747,7 +10832,7 @@ TEST(RunWasmTurbofan_I32x4SplatRevecExpectFail) { } // Can't merge different opcode, I32x4Splat(i32) and S128Const -TEST(RunWasmTurbofan_DifferentOpcodeRevecExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_DifferentOpcodeRevecExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int8_t> r(TestExecutionTier::kTurbofan); @@ -10778,7 +10863,7 @@ TEST(RunWasmTurbofan_DifferentOpcodeRevecExpectFail) { } // Signed overflow in offset + index. -TEST(RunWasmTurbofan_OffsetAddIndexMayOverflowRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_OffsetAddIndexMayOverflowRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX) || !CpuFeatures::IsSupported(AVX2)) return; uint32_t mem_size = (max_mem32_pages() - 1) * kWasmPageSize; @@ -10841,7 +10926,7 @@ TEST(RunWasmTurbofan_OffsetAddIndexMayOverflowRevec) { } } -TEST(RunWasmTurbofan_StoreContantIndexRevec) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_StoreContantIndexRevec) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float> r(TestExecutionTier::kTurbofan); @@ -10880,7 +10965,7 @@ TEST(RunWasmTurbofan_StoreContantIndexRevec) { CHECK_EQ(3.0f, r.Call()); } -TEST(RunWasmTurbofan_GlobalGetRevecExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_GlobalGetRevecExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; @@ -10925,7 +11010,7 @@ TEST(RunWasmTurbofan_GlobalGetRevecExpectFail) { CHECK_EQ(3.0f, r.Call()); } -TEST(RunWasmTurbofan_CallParameterRevecExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_CallParameterRevecExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<float> r(TestExecutionTier::kTurbofan); @@ -10968,7 +11053,7 @@ TEST(RunWasmTurbofan_CallParameterRevecExpectFail) { CHECK_EQ(2.0f, r.Call()); } -TEST(RunWasmTurbofan_DidntTrowRevecExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_DidntTrowRevecExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t> r(TestExecutionTier::kTurbofan); @@ -10994,7 +11079,7 @@ TEST(RunWasmTurbofan_DidntTrowRevecExpectFail) { CHECK_EQ(2, r.Call()); } -TEST(RunWasmTurbofan_ProjectionRevecExpectFail) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_ProjectionRevecExpectFail) { EXPERIMENTAL_FLAG_SCOPE(revectorize); if (!CpuFeatures::IsSupported(AVX2)) return; WasmRunner<int32_t, int32_t> r(TestExecutionTier::kTurbofan); @@ -11029,7 +11114,7 @@ TEST(RunWasmTurbofan_ProjectionRevecExpectFail) { #undef CALL_FUNCTION_WITH_DROP } -TEST(RunWasmTurbofan_RegressStoreInfoCompareCollision) { +TEST_F(RunWasmSimdTest, RunWasmTurbofan_RegressStoreInfoCompareCollision) { if (!CpuFeatures::IsSupported(AVX2)) return; EXPERIMENTAL_FLAG_SCOPE(revectorize); @@ -11116,6 +11201,7 @@ TEST(RunWasmTurbofan_RegressStoreInfoCompareCollision) { #undef WASM_SIMD_LOAD_OP #undef WASM_SIMD_LOAD_OP_OFFSET #undef WASM_SIMD_LOAD_OP_ALIGNMENT +#undef WASM_EXEC_TEST_SUITE } // namespace test_run_wasm_simd } // namespace wasm diff --git a/deps/v8/test/cctest/wasm/test-run-wasm.cc b/deps/v8/test/unittests/wasm/run-wasm-unittest.cc similarity index 98% rename from deps/v8/test/cctest/wasm/test-run-wasm.cc rename to deps/v8/test/unittests/wasm/run-wasm-unittest.cc index ad0a25ab4acf..3e4a3420c81f 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-unittest.cc @@ -12,14 +12,18 @@ #include "src/wasm/code-space-access.h" #include "src/wasm/compilation-environment-inl.h" #include "src/wasm/wasm-opcodes-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { +using RunWasmTest = WasmExecutionTestBase; +using RunWasmUninitializedTest = WasmUninitializedTestBase; +#define WASM_EXEC_TEST_SUITE RunWasmTest +#define WASM_UNINITIALIZED_EXEC_TEST_SUITE RunWasmUninitializedTest + // for even shorter tests. #define B1(a) WASM_BLOCK(a) #define B2(a, b) WASM_BLOCK(a, b) @@ -615,7 +619,6 @@ WASM_EXEC_TEST(I32Eqz) { TestInt32Unop(execution_tier, kExprI32Eqz, 1, 0); } - WASM_EXEC_TEST(Int32DivS_trap) { WasmRunner<int32_t, int32_t, int32_t> r(execution_tier); r.Build({WASM_I32_DIVS(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}); @@ -2725,30 +2728,6 @@ WASM_EXEC_TEST(Regular_Factorial) { } } -namespace { -// TODO(cleanup): Define in cctest.h and reuse where appropriate. -class IsolateScope { - public: - IsolateScope() { - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - isolate_ = v8::Isolate::New(create_params); - isolate_->Enter(); - } - - ~IsolateScope() { - isolate_->Exit(); - isolate_->Dispose(); - } - - v8::Isolate* isolate() { return isolate_; } - Isolate* i_isolate() { return reinterpret_cast<Isolate*>(isolate_); } - - private: - v8::Isolate* isolate_; -}; -} // namespace - // Tail-recursive variation on factorial: // fact(N) => f(N,1). // @@ -2765,10 +2744,9 @@ UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_Factorial) { // Run in bounded amount of stack - 8kb. FlagScope<int32_t> stack_size(&v8_flags.stack_size, GetStackSizeKB() + 8); - IsolateScope isolate_scope; - LocalContext current(isolate_scope.isolate()); + IsolateWithContextWrapper isolate_scope; - WasmRunner<uint32_t, uint32_t> r(isolate_scope.i_isolate(), execution_tier); + WasmRunner<uint32_t, uint32_t> r(isolate_scope.isolate(), execution_tier); WasmFunctionCompiler& fact_aux_fn = r.NewFunction<uint32_t, uint32_t, uint32_t>("fact_aux"); @@ -2799,10 +2777,9 @@ UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_MutualFactorial) { // Run in bounded amount of stack - 8kb. FlagScope<int32_t> stack_size(&v8_flags.stack_size, GetStackSizeKB() + 8); - IsolateScope isolate_scope; - LocalContext current(isolate_scope.isolate()); + IsolateWithContextWrapper isolate_scope; - WasmRunner<uint32_t, uint32_t> r(isolate_scope.i_isolate(), execution_tier); + WasmRunner<uint32_t, uint32_t> r(isolate_scope.isolate(), execution_tier); WasmFunctionCompiler& f_fn = r.NewFunction<uint32_t, uint32_t, uint32_t>("f"); WasmFunctionCompiler& g_fn = r.NewFunction<uint32_t, uint32_t, uint32_t>("g"); @@ -2840,10 +2817,9 @@ UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_IndirectFactorial) { // Run in bounded amount of stack - 8kb. FlagScope<int32_t> stack_size(&v8_flags.stack_size, GetStackSizeKB() + 8); - IsolateScope isolate_scope; - LocalContext current(isolate_scope.isolate()); + IsolateWithContextWrapper isolate_scope; - WasmRunner<uint32_t, uint32_t> r(isolate_scope.i_isolate(), execution_tier); + WasmRunner<uint32_t, uint32_t> r(isolate_scope.isolate(), execution_tier); TestSignatures sigs; @@ -2885,10 +2861,9 @@ UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_Sum) { // Run in bounded amount of stack - 8kb. FlagScope<int32_t> stack_size(&v8_flags.stack_size, GetStackSizeKB() + 8); - IsolateScope isolate_scope; - LocalContext current(isolate_scope.isolate()); + IsolateWithContextWrapper isolate_scope; - WasmRunner<int32_t, int32_t> r(isolate_scope.i_isolate(), execution_tier); + WasmRunner<int32_t, int32_t> r(isolate_scope.isolate(), execution_tier); TestSignatures sigs; WasmFunctionCompiler& sum_aux_fn = r.NewFunction(sigs.i_ii(), "sum_aux"); @@ -2923,10 +2898,9 @@ UNINITIALIZED_WASM_EXEC_TEST(ReturnCall_Bounce_Sum) { // Run in bounded amount of stack - 8kb. FlagScope<int32_t> stack_size(&v8_flags.stack_size, GetStackSizeKB() + 8); - IsolateScope isolate_scope; - LocalContext current(isolate_scope.isolate()); + IsolateWithContextWrapper isolate_scope; - WasmRunner<int32_t, int32_t> r(isolate_scope.i_isolate(), execution_tier); + WasmRunner<int32_t, int32_t> r(isolate_scope.isolate(), execution_tier); TestSignatures sigs; WasmFunctionCompiler& b1_fn = r.NewFunction(sigs.i_ii(), "b1"); @@ -3583,12 +3557,10 @@ WASM_EXEC_TEST(I32SConvertSatF32) { r.Build({WASM_I32_SCONVERT_SAT_F32(WASM_LOCAL_GET(0))}); FOR_FLOAT32_INPUTS(i) { - int32_t expected = - is_inbounds<int32_t>(i) - ? static_cast<int32_t>(i) - : std::isnan(i) ? 0 - : i < 0.0 ? std::numeric_limits<int32_t>::min() - : std::numeric_limits<int32_t>::max(); + int32_t expected = is_inbounds<int32_t>(i) ? static_cast<int32_t>(i) + : std::isnan(i) ? 0 + : i < 0.0 ? std::numeric_limits<int32_t>::min() + : std::numeric_limits<int32_t>::max(); int32_t found = r.Call(i); CHECK_EQ(expected, found); } @@ -3611,12 +3583,10 @@ WASM_EXEC_TEST(I32SConvertSatF64) { WasmRunner<int32_t, double> r(execution_tier); r.Build({WASM_I32_SCONVERT_SAT_F64(WASM_LOCAL_GET(0))}); FOR_FLOAT64_INPUTS(i) { - int32_t expected = - is_inbounds<int32_t>(i) - ? static_cast<int32_t>(i) - : std::isnan(i) ? 0 - : i < 0.0 ? std::numeric_limits<int32_t>::min() - : std::numeric_limits<int32_t>::max(); + int32_t expected = is_inbounds<int32_t>(i) ? static_cast<int32_t>(i) + : std::isnan(i) ? 0 + : i < 0.0 ? std::numeric_limits<int32_t>::min() + : std::numeric_limits<int32_t>::max(); int32_t found = r.Call(i); CHECK_EQ(expected, found); } @@ -3638,12 +3608,10 @@ WASM_EXEC_TEST(I32UConvertSatF32) { WasmRunner<uint32_t, float> r(execution_tier); r.Build({WASM_I32_UCONVERT_SAT_F32(WASM_LOCAL_GET(0))}); FOR_FLOAT32_INPUTS(i) { - int32_t expected = - is_inbounds<uint32_t>(i) - ? static_cast<uint32_t>(i) - : std::isnan(i) ? 0 - : i < 0.0 ? std::numeric_limits<uint32_t>::min() - : std::numeric_limits<uint32_t>::max(); + int32_t expected = is_inbounds<uint32_t>(i) ? static_cast<uint32_t>(i) + : std::isnan(i) ? 0 + : i < 0.0 ? std::numeric_limits<uint32_t>::min() + : std::numeric_limits<uint32_t>::max(); int32_t found = r.Call(i); CHECK_EQ(expected, found); } @@ -3665,12 +3633,10 @@ WASM_EXEC_TEST(I32UConvertSatF64) { WasmRunner<uint32_t, double> r(execution_tier); r.Build({WASM_I32_UCONVERT_SAT_F64(WASM_LOCAL_GET(0))}); FOR_FLOAT64_INPUTS(i) { - int32_t expected = - is_inbounds<uint32_t>(i) - ? static_cast<uint32_t>(i) - : std::isnan(i) ? 0 - : i < 0.0 ? std::numeric_limits<uint32_t>::min() - : std::numeric_limits<uint32_t>::max(); + int32_t expected = is_inbounds<uint32_t>(i) ? static_cast<uint32_t>(i) + : std::isnan(i) ? 0 + : i < 0.0 ? std::numeric_limits<uint32_t>::min() + : std::numeric_limits<uint32_t>::max(); int32_t found = r.Call(i); CHECK_EQ(expected, found); } @@ -3962,9 +3928,9 @@ void BinOpOnDifferentRegisters( for (ctype rhs_value : inputs) { if (lhs == rhs) lhs_value = rhs_value; for (int i = 0; i < num_locals; ++i) { - ctype value = - i == lhs ? lhs_value - : i == rhs ? rhs_value : static_cast<ctype>(i + 47); + ctype value = i == lhs ? lhs_value + : i == rhs ? rhs_value + : static_cast<ctype>(i + 47); WriteLittleEndianValue<ctype>(&memory[i], value); } bool trap = false; @@ -3976,9 +3942,9 @@ void BinOpOnDifferentRegisters( CHECK_EQ(0, r.Call()); CHECK_EQ(expect, ReadLittleEndianValue<ctype>(&memory[0])); for (int i = 0; i < num_locals; ++i) { - ctype value = - i == lhs ? lhs_value - : i == rhs ? rhs_value : static_cast<ctype>(i + 47); + ctype value = i == lhs ? lhs_value + : i == rhs ? rhs_value + : static_cast<ctype>(i + 47); CHECK_EQ(value, ReadLittleEndianValue<ctype>(&memory[i + 1])); } } @@ -4162,5 +4128,7 @@ WASM_EXEC_TEST(I64RemUOnDifferentRegisters) { #undef B2 #undef RET #undef RET_I8 +#undef WASM_EXEC_TEST_SUITE +#undef WASM_UNINITIALIZED_EXEC_TEST_SUITE } // namespace v8::internal::wasm diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-wrappers.cc b/deps/v8/test/unittests/wasm/run-wasm-wrappers-unittest.cc similarity index 94% rename from deps/v8/test/cctest/wasm/test-run-wasm-wrappers.cc rename to deps/v8/test/unittests/wasm/run-wasm-wrappers-unittest.cc index 730c17717c0a..e6c51f738c69 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-wrappers.cc +++ b/deps/v8/test/unittests/wasm/run-wasm-wrappers-unittest.cc @@ -5,11 +5,11 @@ #include "src/wasm/wasm-export-wrapper-cache.h" #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-objects-inl.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -48,6 +48,7 @@ int WasmExportWrapperCache::CountWrappersForTesting(Isolate* isolate) { namespace test_run_wasm_wrappers { using testing::CompileAndInstantiateForTesting; +using RunWasmWrappersTest = WasmExecutionTestBase; #if V8_COMPRESS_POINTERS && \ (V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_IA32 || \ @@ -94,13 +95,13 @@ void Cleanup() { // By sending a low memory notifications, we will try hard to collect all // garbage and will therefore also invoke all weak callbacks of actually // unreachable persistent handles. - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification(); } } // namespace -TEST(WrapperBudget) { +TEST_F(RunWasmWrappersTest, WrapperBudget) { { // This test assumes use of the generic wrapper. FlagScope<bool> use_wasm_generic_wrapper(&v8_flags.wasm_generic_wrapper, @@ -109,14 +110,14 @@ TEST(WrapperBudget) { // Initialize the environment and create a module builder. AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); WasmModuleBuilder* builder = zone.New<WasmModuleBuilder>(&zone); // Define the Wasm function. TestSignatures sigs; WasmFunctionBuilder* f = builder->AddFunction(sigs.i_ii()); - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); f->EmitCode({WASM_I32_MUL(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)), WASM_END}); // Compile the module. @@ -148,7 +149,7 @@ TEST(WrapperBudget) { Cleanup(); } -TEST(WrapperReplacement) { +TEST_F(RunWasmWrappersTest, WrapperReplacement) { { // This test assumes use of the generic wrapper. FlagScope<bool> use_wasm_generic_wrapper(&v8_flags.wasm_generic_wrapper, @@ -157,14 +158,14 @@ TEST(WrapperReplacement) { // Initialize the environment and create a module builder. AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); WasmModuleBuilder* builder = zone.New<WasmModuleBuilder>(&zone); // Define the Wasm function. TestSignatures sigs; WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i()); - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); f->EmitCode({WASM_LOCAL_GET(0), WASM_END}); // Compile the module. @@ -222,7 +223,7 @@ TEST(WrapperReplacement) { Cleanup(); } -TEST(EagerWrapperReplacement) { +TEST_F(RunWasmWrappersTest, EagerWrapperReplacement) { { // This test assumes use of the generic wrapper. FlagScope<bool> use_wasm_generic_wrapper(&v8_flags.wasm_generic_wrapper, @@ -231,7 +232,7 @@ TEST(EagerWrapperReplacement) { // Initialize the environment and create a module builder. AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); WasmModuleBuilder* builder = zone.New<WasmModuleBuilder>(&zone); @@ -240,15 +241,15 @@ TEST(EagerWrapperReplacement) { // while the other one (id) won't. TestSignatures sigs; WasmFunctionBuilder* add = builder->AddFunction(sigs.i_ii()); - add->builder()->AddExport(base::CStrVector("add"), add); + add->builder()->AddExport("add", add); add->EmitCode( {WASM_I32_ADD(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)), WASM_END}); WasmFunctionBuilder* mult = builder->AddFunction(sigs.i_ii()); - mult->builder()->AddExport(base::CStrVector("mult"), mult); + mult->builder()->AddExport("mult", mult); mult->EmitCode( {WASM_I32_MUL(WASM_LOCAL_GET(0), WASM_LOCAL_GET(1)), WASM_END}); WasmFunctionBuilder* id = builder->AddFunction(sigs.i_i()); - id->builder()->AddExport(base::CStrVector("id"), id); + id->builder()->AddExport("id", id); id->EmitCode({WASM_LOCAL_GET(0), WASM_END}); // Compile the module. @@ -331,7 +332,7 @@ TEST(EagerWrapperReplacement) { Cleanup(); } -TEST(WrapperReplacement_IndirectExport) { +TEST_F(RunWasmWrappersTest, WrapperReplacement_IndirectExport) { { // This test assumes use of the generic wrapper. FlagScope<bool> use_wasm_generic_wrapper(&v8_flags.wasm_generic_wrapper, @@ -340,7 +341,7 @@ TEST(WrapperReplacement_IndirectExport) { // Initialize the environment and create a module builder. AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); HandleScope scope(isolate); WasmModuleBuilder* builder = zone.New<WasmModuleBuilder>(&zone); @@ -354,7 +355,7 @@ TEST(WrapperReplacement_IndirectExport) { const uint32_t table_size = 2; const uint32_t table_index = builder->AddTable(kWasmFuncRef, table_size, table_size); - builder->AddExport(base::CStrVector("exported_table"), kExternalTable, 0); + builder->AddExport("exported_table", kExternalTable, 0); // Point from the exported table to the Wasm function. builder->SetIndirectFunction(table_index, 0, function_index); @@ -403,8 +404,8 @@ TEST(WrapperReplacement_IndirectExport) { Cleanup(); } -TEST(JSToWasmWrapperGarbageCollection) { - Isolate* isolate = CcTest::InitIsolateOnce(); +TEST_F(RunWasmWrappersTest, JSToWasmWrapperGarbageCollection) { + Isolate* isolate = WasmExecutionTestBase::InitIsolateOnce(); { // Initialize the environment and create a module builder. AccountingAllocator allocator; @@ -415,7 +416,7 @@ TEST(JSToWasmWrapperGarbageCollection) { // Define an exported Wasm function. TestSignatures sigs; WasmFunctionBuilder* f = builder.AddFunction(sigs.i_v()); - builder.AddExport(base::CStrVector("main"), f); + builder.AddExport("main", f); f->EmitCode({WASM_ONE, WASM_END}); // Before compilation there should be no compiled wrappers. diff --git a/deps/v8/test/unittests/wasm/simd-cross-compiler-determinism-fuzztest.cc b/deps/v8/test/unittests/wasm/simd-cross-compiler-determinism-fuzztest.cc index 3e9da1115c6a..699c376482a7 100644 --- a/deps/v8/test/unittests/wasm/simd-cross-compiler-determinism-fuzztest.cc +++ b/deps/v8/test/unittests/wasm/simd-cross-compiler-determinism-fuzztest.cc @@ -82,6 +82,13 @@ class SimdCrossCompilerDeterminismTest FuzzExtMulPairwiseTree tree, int preconsumed_liftoff_regs, bool allow_avx); + void TestHalvingAdd(WasmOpcode add_opcode, WasmOpcode shift_opcode, + WasmOpcode bitwise_opcode, + WasmOpcode shifted_bitwise_opcode, + std::array<Simd128, 2> inputs, int32_t shift, + uint8_t operand_choices, int preconsumed_liftoff_regs, + bool allow_avx); + static constexpr int kMaxPreconsumedLiftoffRegs = kFpCacheRegList.GetNumRegsSet(); @@ -111,6 +118,72 @@ class SimdCrossCompilerDeterminismTest std::array<InputLocation, sizeof...(locations)>{ locations...}>; + template <typename Config> + Simd128 GetHalvingAddResult(TestExecutionTier tier, WasmOpcode add_opcode, + WasmOpcode shift_opcode, + WasmOpcode bitwise_opcode, + WasmOpcode shifted_bitwise_opcode, + std::array<Simd128, 2> inputs, int32_t shift, + uint8_t operand_choices, + int preconsumed_liftoff_regs = 0) { + CommonWasmRunner<void> runner(isolate(), tier); + Simd128* memory = runner.builder().AddMemoryElems<Simd128>(2); + uint8_t lhs = runner.AllocateLocal(kWasmS128); + uint8_t rhs = runner.AllocateLocal(kWasmS128); + + constexpr size_t kMaxBytecodeSize = 80 + 19 * kMaxPreconsumedLiftoffRegs; + base::SmallVector<uint8_t, kMaxBytecodeSize> bytecode; + + DCHECK_LE(preconsumed_liftoff_regs, kMaxPreconsumedLiftoffRegs); + DCHECK_IMPLIES(tier != TestExecutionTier::kLiftoff, + preconsumed_liftoff_regs == 0); + for (int i = 0; i < preconsumed_liftoff_regs; ++i) { + bytecode.insert(bytecode.end(), {WASM_SIMD_CONSTANT(Simd128{}.bytes())}); + } + + bytecode.insert(bytecode.end(), + Config::template GetInput<0>(memory, inputs[0])); + bytecode.insert(bytecode.end(), {kExprLocalSet, lhs}); + bytecode.insert(bytecode.end(), + Config::template GetInput<1>(memory, inputs[1])); + bytecode.insert(bytecode.end(), {kExprLocalSet, rhs}); + bytecode.insert(bytecode.end(), {WASM_ZERO}); + + // Construct a variant of (a & b) + ((a ^ b) >> shift). + // Bits 0-1 select lhs (0) or rhs (1) for the bitwise and's operands. + // Bits 2-3 do the same for the shifted bitwise xor's operands. + // Bit 4 swaps the operands of the add/sub operation. + auto emit_bitwise = [&] { + bytecode.insert(bytecode.end(), + {WASM_LOCAL_GET((operand_choices & 1) ? rhs : lhs), + WASM_LOCAL_GET((operand_choices & 2) ? rhs : lhs), + WASM_SIMD_OP(bitwise_opcode)}); + }; + auto emit_shift = [&] { + bytecode.insert(bytecode.end(), + {WASM_LOCAL_GET((operand_choices & 4) ? rhs : lhs), + WASM_LOCAL_GET((operand_choices & 8) ? rhs : lhs), + WASM_SIMD_OP(shifted_bitwise_opcode), WASM_I32V(shift), + WASM_SIMD_OP(shift_opcode)}); + }; + if (operand_choices & 16) { + emit_shift(); + emit_bitwise(); + } else { + emit_bitwise(); + emit_shift(); + } + bytecode.insert(bytecode.end(), {WASM_SIMD_OP(add_opcode)}); + bytecode.insert(bytecode.end(), {WASM_SIMD_OP(kExprS128StoreMem), + ZERO_ALIGNMENT, ZERO_OFFSET}); + bytecode.push_back(kExprReturn); + + DCHECK_GE(kMaxBytecodeSize, bytecode.size()); + runner.Build(base::VectorOf(bytecode)); + runner.Call(); + return memory[0]; + } + template <typename Config> Simd128 GetTernOpResult(TestExecutionTier tier, WasmOpcode opcode, std::array<Simd128, 3> inputs, @@ -648,6 +721,152 @@ V8_FUZZ_TEST_F(SimdCrossCompilerDeterminismTest, TestTernOp) fuzztest::Arbitrary<bool>()) .WithSeeds(kTernOpSeeds); +void SimdCrossCompilerDeterminismTest::TestHalvingAdd( + WasmOpcode add_opcode, WasmOpcode shift_opcode, WasmOpcode bitwise_opcode, + WasmOpcode shifted_bitwise_opcode, std::array<Simd128, 2> inputs, + int32_t shift, uint8_t operand_choices, int preconsumed_liftoff_regs, + bool allow_avx) { +#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 + AVXSupport avx_support(allow_avx); +#endif // V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 + + Simd128 results[] = { + // Liftoff reference. + GetHalvingAddResult<InputLocations<kConstant, kConstant>>( + TestExecutionTier::kLiftoff, add_opcode, shift_opcode, bitwise_opcode, + shifted_bitwise_opcode, inputs, shift, operand_choices, + preconsumed_liftoff_regs), + // Use both constant folding and mixed input. + GetHalvingAddResult<InputLocations<kConstant, kConstant>>( + TestExecutionTier::kTurbofan, add_opcode, shift_opcode, + bitwise_opcode, shifted_bitwise_opcode, inputs, shift, + operand_choices), + GetHalvingAddResult<InputLocations<kConstant, kDynamic>>( + TestExecutionTier::kTurbofan, add_opcode, shift_opcode, + bitwise_opcode, shifted_bitwise_opcode, inputs, shift, + operand_choices), + GetHalvingAddResult<InputLocations<kDynamic, kConstant>>( + TestExecutionTier::kTurbofan, add_opcode, shift_opcode, + bitwise_opcode, shifted_bitwise_opcode, inputs, shift, + operand_choices), + // Dynamic inputs to stop the pattern being constant-folded. + GetHalvingAddResult<InputLocations<kDynamic, kDynamic>>( + TestExecutionTier::kTurbofan, add_opcode, shift_opcode, + bitwise_opcode, shifted_bitwise_opcode, inputs, shift, + operand_choices)}; + + ASSERT_TRUE(AllResultsEqual<Simd128>(base::VectorOf(results))) + << absl::StrFormat( + "HalvingAdd with arithmetic %s, shift %s, bitwise %s, shifted " + "bitwise %s, shift %d, operand_choices %d on inputs %v, %v\n", + WasmOpcodes::OpcodeName(add_opcode), + WasmOpcodes::OpcodeName(shift_opcode), + WasmOpcodes::OpcodeName(bitwise_opcode), + WasmOpcodes::OpcodeName(shifted_bitwise_opcode), shift, + operand_choices, inputs[0], inputs[1]) + << "Different results for different configs: " + << PrintCollection(base::VectorOf(results)); +} + +constexpr std::array kHalvingAddArithmeticOps = { + kExprI8x16Add, kExprI8x16Sub, kExprI16x8Add, kExprI16x8Sub, + kExprI32x4Add, kExprI32x4Sub, kExprI64x2Add, kExprI64x2Sub}; + +constexpr std::array kHalvingAddShiftOps = { + kExprI8x16Shl, kExprI8x16ShrS, kExprI8x16ShrU, kExprI16x8Shl, + kExprI16x8ShrS, kExprI16x8ShrU, kExprI32x4Shl, kExprI32x4ShrS, + kExprI32x4ShrU, kExprI64x2Shl, kExprI64x2ShrS, kExprI64x2ShrU}; + +constexpr std::array kHalvingAddBitwiseOps = {kExprS128And, kExprS128Or, + kExprS128Xor}; + +// Use signed min/max values to check handling of unsigned sum overflows. +constexpr std::array<Simd128, 2> kHalvingAddInputs8 = { + Simd128{Simd128::int8x16{-128, 127, -1, 0, 1, -128, 127, -3, -128, 127, -1, + 0, 1, -128, 127, -3}}, + Simd128{Simd128::int8x16{-128, 127, -1, -1, 0, 127, -128, 0, -128, 127, -1, + -1, 0, 127, -128, 0}}}; +constexpr std::array<Simd128, 2> kHalvingAddInputs16 = { + Simd128{Simd128::int16x8{-32768, 32767, -1, 0, 1, -32768, 32767, -3}}, + Simd128{Simd128::int16x8{-32768, 32767, -1, -1, 0, 32767, -32768, 0}}}; +constexpr std::array<Simd128, 2> kHalvingAddInputs32 = { + Simd128{Simd128::int32x4{INT32_MIN, INT32_MAX, -1, -3}}, + Simd128{Simd128::int32x4{INT32_MIN, INT32_MAX, -1, 0}}}; + +constexpr std::tuple<WasmOpcode, WasmOpcode, WasmOpcode, WasmOpcode, + std::array<Simd128, 2>, int32_t, uint8_t, int, bool> + kHalvingAddSeeds[] = { + // Addition. + {kExprI8x16Add, kExprI8x16ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs8, 1, 10, 0, true}, + {kExprI8x16Add, kExprI8x16ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs8, 9, 9, 0, true}, + {kExprI16x8Add, kExprI16x8ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs16, -15, 6, 0, true}, + {kExprI16x8Add, kExprI16x8ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs16, 17, 5, 0, true}, + {kExprI32x4Add, kExprI32x4ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 33, 26, 0, true}, + {kExprI32x4Add, kExprI32x4ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, -31, 25, 0, true}, + {kExprI64x2Add, kExprI64x2ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 22, 0, true}, + {kExprI64x2Add, kExprI64x2ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 65, 21, 0, true}, + // Subtraction. + {kExprI16x8Sub, kExprI16x8ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs16, 1, 10, 0, true}, + {kExprI32x4Sub, kExprI32x4ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 26, 0, true}, + // Left shifts. + {kExprI8x16Add, kExprI8x16Shl, kExprS128And, kExprS128Xor, + kHalvingAddInputs8, 1, 10, 0, true}, + {kExprI16x8Add, kExprI16x8Shl, kExprS128And, kExprS128Xor, + kHalvingAddInputs16, 1, 10, 0, true}, + {kExprI32x4Add, kExprI32x4Shl, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 10, 0, true}, + {kExprI64x2Add, kExprI64x2Shl, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 10, 0, true}, + // Alternate bitwise operations. + {kExprI16x8Add, kExprI16x8ShrS, kExprS128Or, kExprS128Xor, + kHalvingAddInputs16, 1, 10, 0, true}, + {kExprI16x8Add, kExprI16x8ShrS, kExprS128And, kExprS128Or, + kHalvingAddInputs16, 1, 10, 0, true}, + {kExprI16x8Add, kExprI16x8ShrS, kExprS128Xor, kExprS128And, + kHalvingAddInputs16, 1, 10, 0, true}, + {kExprI16x8Add, kExprI8x16ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs16, 1, 10, 0, true}, + // Mismatched input pairs between 'xor' and 'and' operations. + {kExprI32x4Add, kExprI32x4ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 2, 0, true}, + {kExprI32x4Add, kExprI32x4ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 14, 0, true}, + {kExprI32x4Add, kExprI32x4ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs32, 1, 8, 0, true}, + // All operands are lhs or rhs. + {kExprI8x16Add, kExprI8x16ShrS, kExprS128And, kExprS128Xor, + kHalvingAddInputs8, 1, 0, 0, true}, + {kExprI16x8Add, kExprI16x8ShrU, kExprS128And, kExprS128Xor, + kHalvingAddInputs16, 1, 31, 0, true}}; + +V8_FUZZ_TEST_F(SimdCrossCompilerDeterminismTest, TestHalvingAdd) + .WithDomains( + // 64-bit to test the fallback, S/UHADD supports 8, 16 and 32-bit lanes. + fuzztest::ElementOf<WasmOpcode>(kHalvingAddArithmeticOps), + fuzztest::ElementOf<WasmOpcode>(kHalvingAddShiftOps), + fuzztest::ElementOf<WasmOpcode>(kHalvingAddBitwiseOps), + fuzztest::ElementOf<WasmOpcode>(kHalvingAddBitwiseOps), + fuzztest::ArrayOf<2>(ArbitrarySimd()), + // Check the optimization only runs for shifts of 1. + fuzztest::OneOf(fuzztest::ElementOf<int32_t>({1, 9, 17, 33, 65, -7, -15, + -31, -63}), + fuzztest::Arbitrary<int32_t>()), + fuzztest::InRange<uint8_t>(0, 31), + fuzztest::InRange( + 0, SimdCrossCompilerDeterminismTest::kMaxPreconsumedLiftoffRegs), + fuzztest::Arbitrary<bool>()) + .WithSeeds(kHalvingAddSeeds); + void SimdCrossCompilerDeterminismTest::TestExtMulPairwiseTree( std::array<Simd128, 4> inputs, FuzzExtMulPairwiseTree tree, int preconsumed_liftoff_regs, bool allow_avx) { diff --git a/deps/v8/test/cctest/wasm/test-streaming-compilation.cc b/deps/v8/test/unittests/wasm/streaming-compilation-unittest.cc similarity index 88% rename from deps/v8/test/cctest/wasm/test-streaming-compilation.cc rename to deps/v8/test/unittests/wasm/streaming-compilation-unittest.cc index f7f19c5aee4f..753d1e7f6b9b 100644 --- a/deps/v8/test/cctest/wasm/test-streaming-compilation.cc +++ b/deps/v8/test/unittests/wasm/streaming-compilation-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "include/libplatform/libplatform.h" +#include "include/v8-profiler.h" #include "src/api/api-inl.h" #include "src/base/vector.h" #include "src/handles/global-handles-inl.h" @@ -18,20 +19,42 @@ #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-objects.h" #include "src/wasm/wasm-serialization.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { -class MockPlatform final : public TestPlatform { +namespace { + +class MockPlatform final : public v8::Platform { public: - MockPlatform() : task_runner_(std::make_shared<MockTaskRunner>()) {} + explicit MockPlatform(v8::Platform* default_platform) + : default_platform_(default_platform), + task_runner_(std::make_shared<MockTaskRunner>()) { + CHECK_NOT_NULL(default_platform_); + i::V8::SetPlatformForTesting(this); + } - ~MockPlatform() { + ~MockPlatform() override { for (auto* job_handle : job_handles_) job_handle->ResetPlatform(); + if (i::V8::GetCurrentPlatform() == this) { + i::V8::SetPlatformForTesting(default_platform_); + } + } + + v8::PageAllocator* GetPageAllocator() override { + return default_platform_->GetPageAllocator(); + } + + void OnCriticalMemoryPressure() override { + default_platform_->OnCriticalMemoryPressure(); + } + + int NumberOfWorkerThreads() override { + return default_platform_->NumberOfWorkerThreads(); } std::unique_ptr<v8::JobHandle> CreateJobImpl( @@ -56,8 +79,30 @@ class MockPlatform final : public TestPlatform { task_runner_->PostTask(std::move(task)); } + void PostDelayedTaskOnWorkerThreadImpl( + v8::TaskPriority priority, std::unique_ptr<v8::Task> task, + double delay_in_seconds, const v8::SourceLocation& location) override { + task_runner_->PostDelayedTask(std::move(task), delay_in_seconds); + } + + double MonotonicallyIncreasingTime() override { + return default_platform_->MonotonicallyIncreasingTime(); + } + + double CurrentClockTimeMillis() override { + return default_platform_->CurrentClockTimeMillis(); + } + bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; } + v8::TracingController* GetTracingController() override { + return default_platform_->GetTracingController(); + } + + v8::ThreadIsolatedAllocator* GetThreadIsolatedAllocator() override { + return default_platform_->GetThreadIsolatedAllocator(); + } + void ExecuteTasks() { task_runner_->ExecuteTasks(); } private: @@ -163,12 +208,13 @@ class MockPlatform final : public TestPlatform { MockPlatform* platform_; }; + v8::Platform* default_platform_; + FlagScope<bool> no_stress_concurrent_allocation_{ + &v8_flags.stress_concurrent_allocation, false}; std::shared_ptr<MockTaskRunner> task_runner_; std::unordered_set<MockJobHandle*> job_handles_; }; -namespace { - enum class CompilationState { kPending, kFinished, @@ -276,26 +322,52 @@ class StreamTester { IndirectHandle<WasmModuleObject> module_object_; std::shared_ptr<StreamingDecoder> stream_; }; + +template <typename TMixin> +class WithMockPlatformMixin : public TMixin { + public: + WithMockPlatformMixin() : mock_platform_(this->platform()) {} + WithMockPlatformMixin(const WithMockPlatformMixin&) = delete; + WithMockPlatformMixin& operator=(const WithMockPlatformMixin&) = delete; + + void TearDown() override { + // Restore default_platform_ before ~IsolateWrapper() calls + // v8::platform::PumpMessageLoop. + if (i::V8::GetCurrentPlatform() == &mock_platform_) { + i::V8::SetPlatformForTesting(this->platform()); + } + TMixin::TearDown(); + } + + MockPlatform& mock_platform() { return mock_platform_; } + + private: + MockPlatform mock_platform_; +}; + } // namespace +using StreamingCompilationTest = WithIsolateScopeMixin<WithIsolateMixin< + WithMockPlatformMixin<WithWasmTrapHandlerMixin<TestWithPlatform>>>>; + #define RUN_STREAM(name) \ - v8::Isolate* isolate = CcTest::isolate(); \ + v8::Isolate* isolate = v8_isolate(); \ v8::HandleScope handle_scope(isolate); \ v8::Local<v8::Context> context = v8::Context::New(isolate); \ v8::Context::Scope context_scope(context); \ /* Reduce tiering budget so we do not need to execute too long. */ \ i::FlagScope<int> reduced_tiering_budget(&i::v8_flags.wasm_tiering_budget, \ 1); \ - RunStream_##name(&platform, isolate); + RunStream_##name(&mock_platform(), isolate); #define STREAM_TEST(name) \ void RunStream_##name(MockPlatform*, v8::Isolate*); \ - TEST_WITH_PLATFORM(Async##name, MockPlatform) { \ + TEST_F(StreamingCompilationTest, Async##name) { \ if (i::v8_flags.memory_balancer) return; \ RUN_STREAM(name); \ } \ \ - TEST_WITH_PLATFORM(SingleThreaded##name, MockPlatform) { \ + TEST_F(StreamingCompilationTest, SingleThreaded##name) { \ if (i::v8_flags.memory_balancer) return; \ i::FlagScope<bool> single_threaded_scope(&i::v8_flags.single_threaded, \ true); \ @@ -315,7 +387,7 @@ ZoneBuffer GetValidModuleBytes(Zone* zone) { WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii()); f->EmitCode({kExprLocalGet, i, kExprEnd}); CHECK_GE(3, ++i); - builder.AddExport(base::CStrVector(export_name), f); + builder.AddExport(export_name, f); } builder.WriteTo(&buffer); return buffer; @@ -1212,7 +1284,7 @@ STREAM_TEST(TestModuleWithImportedFunction) { ZoneBuffer buffer(tester.zone()); TestSignatures sigs; WasmModuleBuilder builder(tester.zone()); - builder.AddImport(base::ArrayVector("Test"), sigs.i_iii()); + builder.AddImport("Test", sigs.i_iii()); { WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii()); f->EmitCode({kExprLocalGet, 0, kExprEnd}); @@ -1246,8 +1318,7 @@ STREAM_TEST(TestIncrementalCaching) { WasmModuleBuilder builder(tester.zone()); builder.AddMemory(1); - base::Vector<const char> function_names[] = { - base::CStrVector("f0"), base::CStrVector("f1"), base::CStrVector("f2")}; + std::string_view function_names[] = {"f0", "f1", "f2"}; for (int i = 0; i < 3; ++i) { WasmFunctionBuilder* f = builder.AddFunction(sigs.v_v()); @@ -1274,7 +1345,7 @@ STREAM_TEST(TestIncrementalCaching) { tester.RunCompilerTasks(); CHECK(tester.IsPromiseFulfilled()); tester.native_module(); - constexpr base::Vector<const char> kNoSourceUrl{"", 0}; + constexpr std::string_view kNoSourceUrl{"", 0}; Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); IndirectHandle<WasmInstanceObject> instance; { @@ -1472,7 +1543,7 @@ STREAM_TEST(TestMoreFunctionsCanBeSerializedCallback) { // Continue executing functions (eventually triggering tier-up) until the // callback is called at least once. - auto* i_isolate = CcTest::i_isolate(); + auto* i_isolate = reinterpret_cast<i::Isolate*>(isolate); std::vector<IndirectHandle<WasmExportedFunction>> exported_functions; { ErrorThrower thrower{i_isolate, "TestMoreFunctionsCanBeSerializedCallback"}; @@ -1586,7 +1657,7 @@ STREAM_TEST(TestMoreFunctionsCanBeSerializedCallbackWithTimeout) { tester.RunCompilerTasks(); CHECK(tester.IsPromiseFulfilled()); - auto* i_isolate = CcTest::i_isolate(); + auto* i_isolate = reinterpret_cast<i::Isolate*>(isolate); IndirectHandle<WasmInstanceObject> instance; { // Create an instance. @@ -1691,7 +1762,7 @@ STREAM_TEST(TestHardCachingThreshold) { { // Create an instance. - auto* i_isolate = CcTest::i_isolate(); + auto* i_isolate = reinterpret_cast<i::Isolate*>(isolate); ErrorThrower thrower{i_isolate, "TestMoreFunctionsCanBeSerializedCallback"}; DirectHandle<WasmInstanceObject> instance = GetWasmEngine() @@ -1718,6 +1789,149 @@ STREAM_TEST(TestHardCachingThreshold) { CHECK(caching_was_triggered); } +// Regression test: if the hard caching threshold is reached while a delayed +// {TriggerCodeCachingAfterTimeoutTask} is pending, the task finds +// {bytes_since_last_chunk_} below the threshold and returns early. It must +// still reset {last_top_tier_compilation_timestamp_}, otherwise no further +// timeout task is ever posted for subsequent tier-up batches. +STREAM_TEST(RegressCachingTimeoutStuckAfterHardThreshold) { + // The "more functions can be serialized" callback will only be triggered with + // dynamic tiering, so skip this test if dynamic tiering is disabled. + if (!v8_flags.wasm_dynamic_tiering) return; + // With {single_threaded}, caching is always triggered immediately and no + // timeout task is involved. + if (v8_flags.single_threaded) return; + + // The soft threshold is tiny, so that tiering up a single function reaches + // it. The hard threshold is initially huge and lowered after Step 1 once we + // know the compiled size of a single function. + FlagScope<int> caching_threshold(&v8_flags.wasm_caching_threshold, 1); + constexpr int kCachingTimeoutMs = 50; + FlagScope<int> caching_timeout(&v8_flags.wasm_caching_timeout_ms, + kCachingTimeoutMs); + FlagScope<int> caching_hard_threshold(&v8_flags.wasm_caching_hard_threshold, + 1'000'000); + + base::Semaphore caching_was_triggered{0}; + StreamTester tester(isolate); + tester.stream()->SetMoreFunctionsCanBeSerializedCallback( + [&](const std::shared_ptr<NativeModule>& module) { + caching_was_triggered.Signal(); + }); + + // Wait for up to {ms} milliseconds for a caching event, running compiler + // tasks in between. + auto WaitForCaching = [&caching_was_triggered, &tester](int ms) { + constexpr base::TimeDelta kOneMs = base::TimeDelta::FromMilliseconds(1); + for (int waited_ms = 0; waited_ms < ms; ++waited_ms) { + if (caching_was_triggered.WaitFor(kOneMs)) return true; + tester.RunCompilerTasks(); + } + return false; + }; + + uint8_t code[] = { + ADD_COUNT(U32V_1(0), // locals count + kExprLocalGet, 0, kExprEnd) // body + }; + + const uint8_t bytes[] = { + WASM_MODULE_HEADER, // module header + SECTION(Type, + ENTRY_COUNT(1), // type count + SIG_ENTRY_x_x(kI32Code, kI32Code)), // signature entry + SECTION(Function, ENTRY_COUNT(4), SIG_INDEX(0), SIG_INDEX(0), + SIG_INDEX(0), SIG_INDEX(0)), + SECTION(Export, ENTRY_COUNT(4), // 4 exports + ADD_COUNT('a'), kExternalFunction, FUNC_INDEX(0), // "a" (0) + ADD_COUNT('b'), kExternalFunction, FUNC_INDEX(1), // "b" (1) + ADD_COUNT('c'), kExternalFunction, FUNC_INDEX(2), // "c" (2) + ADD_COUNT('d'), kExternalFunction, FUNC_INDEX(3)), // "d" (3) + kCodeSectionCode, // section code + U32V_1(1 + arraysize(code) * 4), // section size + U32V_1(4), // functions count + }; + + tester.OnBytesReceived(bytes, arraysize(bytes)); + for (int i = 0; i < 4; ++i) { + tester.OnBytesReceived(code, arraysize(code)); + } + tester.FinishStream(); + tester.RunCompilerTasks(); + CHECK(tester.IsPromiseFulfilled()); + + Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + IndirectHandle<WasmInstanceObject> instance; + { + ErrorThrower thrower{i_isolate, "RegressCachingTimeoutStuckAfterHard"}; + instance = indirect_handle( + GetWasmEngine() + ->SyncInstantiate(i_isolate, &thrower, tester.module_object(), {}) + .ToHandleChecked(), + i_isolate); + CHECK(!thrower.error()); + } + + // Step 1: Tier up one function. This passes the soft threshold (but not the + // hard threshold), hence schedules a delayed caching task and sets + // {last_top_tier_compilation_timestamp_}. + { + DisallowGarbageCollection no_gc; + i::wasm::TriggerTierUp(i_isolate, instance->trusted_data(i_isolate), 0); + } + tester.RunCompilerTasks(); + size_t one_func_size = 0; + { + WasmCodeRefScope code_scope; + CppGCManaged<NativeModule>::Ptr module = tester.native_module(); + CHECK(module->GetCode(0) != nullptr && !module->GetCode(0)->is_liftoff()); + one_func_size = module->GetCode(0)->instructions().size(); + CHECK_LT(0, one_func_size); + } + + // Set the hard threshold to 2x a single function's code size, so that a + // single function stays below it while two or more functions reach it. + v8_flags.wasm_caching_hard_threshold = static_cast<int>(2 * one_func_size); + + // Step 2: Before the timeout expires, tier up more functions such that the + // hard threshold is reached. This triggers caching immediately and resets + // {bytes_since_last_chunk_}, while the delayed task from Step 1 is still + // pending. + { + DisallowGarbageCollection no_gc; + i::wasm::TriggerTierUp(i_isolate, instance->trusted_data(i_isolate), 1); + i::wasm::TriggerTierUp(i_isolate, instance->trusted_data(i_isolate), 2); + } + tester.RunCompilerTasks(); + { + WasmCodeRefScope code_scope; + CppGCManaged<NativeModule>::Ptr module = tester.native_module(); + size_t total = 0; + for (int i = 0; i < 3; ++i) { + CHECK(module->GetCode(i) != nullptr && !module->GetCode(i)->is_liftoff()); + total += module->GetCode(i)->instructions().size(); + } + CHECK_LE(static_cast<size_t>(v8_flags.wasm_caching_hard_threshold), total); + } + CHECK(WaitForCaching(10'000)); + + // Step 3: Wait for the pending delayed task to run. It finds + // {bytes_since_last_chunk_ == 0} and returns early without triggering + // another caching event. + CHECK(!WaitForCaching(3 * kCachingTimeoutMs)); + + // Step 4: Tier up another function, passing the soft (but not the hard) + // threshold again. This must schedule a new timeout task and eventually + // trigger caching. + { + DisallowGarbageCollection no_gc; + i::wasm::TriggerTierUp(i_isolate, instance->trusted_data(i_isolate), 3); + } + tester.RunCompilerTasks(); + CHECK_WITH_MSG(WaitForCaching(10'000), + "no caching event after the timeout task returned early"); +} + // Test that a compile error contains the name of the function, even if the name // section is not present at the time the error is detected. STREAM_TEST(TestCompileErrorFunctionName) { @@ -1820,7 +2034,7 @@ STREAM_TEST(TestProfilingMidStreaming) { WasmModuleBuilder builder(zone); WasmFunctionBuilder* f = builder.AddFunction(sigs.v_v()); f->EmitCode({kExprEnd}); - builder.AddExport(base::VectorOf("foo", 3), f); + builder.AddExport("foo", f); builder.WriteTo(&buffer); } diff --git a/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc b/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc index e3b44391786d..242676260f54 100644 --- a/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/streaming-decoder-unittest.cc @@ -4,6 +4,7 @@ #include "src/wasm/streaming-decoder.h" +#include "src/base/unique-array.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-engine.h" #include "test/common/flag-utils.h" @@ -18,7 +19,7 @@ struct MockStreamingResult { size_t num_sections = 0; size_t num_functions = 0; bool error; - base::OwnedVector<const uint8_t> received_bytes; + base::UniqueArray<const uint8_t> received_bytes; bool ok() const { return !error; } @@ -79,7 +80,7 @@ class MockStreamingProcessor : public StreamingProcessor { void OnFinishedChunk() override {} // Finish the processing of the stream. - void OnFinishedStream(base::OwnedVector<const uint8_t> bytes, + void OnFinishedStream(base::UniqueArray<const uint8_t> bytes, bool after_error) override { result_->received_bytes = std::move(bytes); result_->error = after_error; @@ -88,7 +89,7 @@ class MockStreamingProcessor : public StreamingProcessor { void OnAbort() override {} bool Deserialize(base::Vector<const uint8_t> module_bytes, - base::OwnedVector<const uint8_t>& wire_bytes) override { + base::UniqueArray<const uint8_t>& wire_bytes) override { return false; } @@ -110,7 +111,7 @@ class WasmStreamingDecoderTest : public ::testing::Test { EXPECT_TRUE(result.ok()); EXPECT_EQ(expected_sections, result.num_sections); EXPECT_EQ(expected_functions, result.num_functions); - EXPECT_EQ(data, result.received_bytes.as_vector()); + EXPECT_EQ(data, result.received_bytes); } } diff --git a/deps/v8/test/unittests/wasm/struct-types-unittest.cc b/deps/v8/test/unittests/wasm/struct-types-unittest.cc index 12d9a0eab0f6..27aacfa2273a 100644 --- a/deps/v8/test/unittests/wasm/struct-types-unittest.cc +++ b/deps/v8/test/unittests/wasm/struct-types-unittest.cc @@ -25,7 +25,11 @@ TEST_F(StructTypesTest, Empty) { StructType::Builder<Zone> desc_builder(this->zone(), 0, true, SharedFlag{false}); StructType* desc_type = desc_builder.Build(); - EXPECT_EQ(uint32_t{kTaggedSize}, desc_type->total_fields_size()); + if (v8_flags.wasm_merged_descriptors) { + EXPECT_EQ(0u, desc_type->total_fields_size()); + } else { + EXPECT_EQ(uint32_t{kTaggedSize}, desc_type->total_fields_size()); + } } TEST_F(StructTypesTest, OneField) { @@ -40,9 +44,14 @@ TEST_F(StructTypesTest, OneField) { SharedFlag{false}); desc_builder.AddField(kWasmI32, true); StructType* desc_type = desc_builder.Build(); - EXPECT_EQ(uint32_t{kTaggedSize + std::max(kUInt32Size, kTaggedSize)}, - desc_type->total_fields_size()); - EXPECT_EQ(uint32_t{kTaggedSize}, desc_type->field_offset(0)); + if (v8_flags.wasm_merged_descriptors) { + EXPECT_EQ(expected, desc_type->total_fields_size()); + EXPECT_EQ(0u, desc_type->field_offset(0)); + } else { + EXPECT_EQ(uint32_t{kTaggedSize + std::max(kUInt32Size, kTaggedSize)}, + desc_type->total_fields_size()); + EXPECT_EQ(uint32_t{kTaggedSize}, desc_type->field_offset(0)); + } } TEST_F(StructTypesTest, Packing) { diff --git a/deps/v8/test/unittests/wasm/subtyping-unittest.cc b/deps/v8/test/unittests/wasm/subtyping-unittest.cc index de78de3143c3..150e69cec227 100644 --- a/deps/v8/test/unittests/wasm/subtyping-unittest.cc +++ b/deps/v8/test/unittests/wasm/subtyping-unittest.cc @@ -73,9 +73,10 @@ void DefineArray(WasmModule* module, FieldInit element_type, bool is_final = false, SharedFlag is_shared = SharedFlag{false}, bool in_singleton_rec_group = true) { - module->AddArrayTypeForTesting(module->signature_storage.New<ArrayType>( - element_type.first, element_type.second), - supertype, is_final, is_shared); + module->AddArrayTypeForTesting( + module->signature_storage.New<ArrayType>(element_type.first, + element_type.second, is_shared), + supertype, is_final, is_shared); if (in_singleton_rec_group) { GetTypeCanonicalizer()->AddRecursiveSingletonGroup(module); } diff --git a/deps/v8/test/unittests/wasm/type-canonicalization-fuzztest.cc b/deps/v8/test/unittests/wasm/type-canonicalization-fuzztest.cc index d26b05f4b14c..b6be76aa60ce 100644 --- a/deps/v8/test/unittests/wasm/type-canonicalization-fuzztest.cc +++ b/deps/v8/test/unittests/wasm/type-canonicalization-fuzztest.cc @@ -4,8 +4,10 @@ #include "src/utils/ostreams.h" #include "src/wasm/canonical-types.h" +#include "src/wasm/function-body-decoder.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-module-builder.h" +#include "src/wasm/wasm-subtyping.h" #include "test/unittests/fuzztest.h" #include "test/unittests/test-utils.h" @@ -15,6 +17,12 @@ namespace v8::internal::wasm { // fuzz test. namespace test { +constexpr std::array kAllGenericKinds = { + GenericKind::kFunc, GenericKind::kNoFunc, GenericKind::kAny, + GenericKind::kEq, GenericKind::kI31, GenericKind::kStruct, + GenericKind::kArray, GenericKind::kNone, GenericKind::kExtern, + GenericKind::kNoExtern, GenericKind::kExn, GenericKind::kNoExn}; + // Provide operator<<(std::ostream&, T> for types with T.Print(std::ostream*). template <typename T> requires requires(const T& t, std::ostream& os) { t.Print(os); } @@ -23,50 +31,81 @@ std::ostream& operator<<(std::ostream& os, const T& t) { return os; } -// `reftype` in the spec. +struct SubType; + +// Variance for type adaptation when deriving a subtype from a supertype. +enum class Variance { kInvariant, kCovariant, kContravariant }; + +// `reftype` in the spec (`ref null? heaptype`, where `heaptype` is either +// `absheaptype` or `typeidx`). struct RefType { - // The fuzzer domain initially chooses an unconstrained `index`. - // `FixupRefTypes` will restrict this index to be within [0, - // current_rec_group_end) and will potentially set `index_in_recgroup`. - // `CanonicalizeIndexes` will replace `index` by a canonical index if it + // For indexed heap types (`uint32_t`), the fuzzer domain initially chooses an + // unconstrained index. `FixupRefType` will restrict this index to be within + // [0, current_rec_group_end) and will potentially set `index_in_recgroup`. + // `CanonicalizeIndexes` will replace the index by a canonical index if it // references a type from an earlier recgroup (i.e. if `index_in_recgroup` is // not set). - uint32_t index; + std::variant<GenericKind, uint32_t> heap_type; SharedFlag shared; Nullability nullable; - // `ref_type_kind` and `index_in_recgroup` will be set by `FixupRefType`. - RefTypeKind ref_type_kind; + // `ref_type_kind` and `index_in_recgroup` will be set by `FixupRefType` for + // indexed heap types. + RefTypeKind ref_type_kind = RefTypeKind::kOther; std::optional<uint32_t> index_in_recgroup; // Construction only passes the first three fields. - RefType(uint32_t index, SharedFlag shared, Nullability nullable) - : index(index), shared(shared), nullable(nullable) {} + RefType(std::variant<GenericKind, uint32_t> heap_type, SharedFlag shared, + Nullability nullable) + : heap_type(heap_type), shared(shared), nullable(nullable) {} void FixupRefType(const std::vector<RefTypeKind>& available_ref_types, uint32_t recgroup_start) { + uint32_t* index = std::get_if<uint32_t>(&heap_type); + if (index == nullptr) { + // Abstract heap types never have a `RefTypeKind` or recgroup offset. + DCHECK_EQ(RefTypeKind::kOther, ref_type_kind); + DCHECK(!index_in_recgroup.has_value()); + return; + } DCHECK(!available_ref_types.empty()); // Restrict the index to anything until the end of the current rec group. - index %= base::checked_cast<uint32_t>(available_ref_types.size()); + *index %= base::checked_cast<uint32_t>(available_ref_types.size()); // Populate the ref type kind, which is encoded in the `ValueType` returned // by `value_type()`. - ref_type_kind = available_ref_types[index]; + ref_type_kind = available_ref_types[*index]; DCHECK(ref_type_kind == RefTypeKind::kFunction || ref_type_kind == RefTypeKind::kStruct || ref_type_kind == RefTypeKind::kArray); - if (index >= recgroup_start) index_in_recgroup = index - recgroup_start; + if (*index >= recgroup_start) { + index_in_recgroup = *index - recgroup_start; + } else { + // `this` may have been copied from a supertype in an earlier recgroup; + // clear any inherited intra-recgroup offset. + index_in_recgroup.reset(); + } } + void AdaptToSupertype(const RefType& super_ref, Variance variance, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types); + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { if (index_in_recgroup.has_value()) return; - // Update the index to the canonical index from a previous recgroup. - DCHECK_LT(index, canonical_indexes.size()); - index = canonical_indexes[index]; + if (uint32_t* index = std::get_if<uint32_t>(&heap_type)) { + // Update the index to the canonical index from a previous recgroup. + DCHECK_LT(*index, canonical_indexes.size()); + *index = canonical_indexes[*index]; + } } ValueType value_type() const { - return ValueType::RefMaybeNull(ModuleTypeIndex{index}, nullable, shared, - ref_type_kind); + if (const uint32_t* index = std::get_if<uint32_t>(&heap_type)) { + return ValueType::RefMaybeNull(ModuleTypeIndex{*index}, nullable, shared, + ref_type_kind); + } + return ValueType::Generic(std::get<GenericKind>(heap_type), nullable, + shared); } void Print(std::ostream& os) const { @@ -74,16 +113,26 @@ struct RefType { if (shared) os << "shared "; if (index_in_recgroup.has_value()) { os << "recref " << index_in_recgroup.value(); + } else if (const uint32_t* index = std::get_if<uint32_t>(&heap_type)) { + os << "ref " << *index; } else { - os << "ref " << index; + os << "ref " << value_type().generic_heaptype_name(); } } }; -// `numtype` in the spec. +// `numtype` or `vectype` in the spec. struct NumType { ValueType type; + void Fixup() { + // Fall back to `i32` if the host CPU does not support SIMD, as the module + // decoder rejects `v128` without hardware SIMD support. + if (type == kWasmS128 && !CheckHardwareSupportsSimd()) { + type = kWasmI32; + } + } + void Print(std::ostream& os) const { os << type.name(); } ValueType value_type() const { @@ -99,13 +148,31 @@ struct ValType : public std::variant<NumType, RefType> { void FixupRefType(const std::vector<RefTypeKind>& available_ref_types, uint32_t recgroup_start) { - if (auto* ref_type = std::get_if<RefType>(this)) { + if (RefType* ref_type = std::get_if<RefType>(this)) { ref_type->FixupRefType(available_ref_types, recgroup_start); + } else { + std::get<NumType>(*this).Fixup(); } } + void AdaptToSupertype(const ValType& super_val, Variance variance, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + const RefType* super_ref = std::get_if<RefType>(&super_val); + RefType* sub_ref = std::get_if<RefType>(this); + if (super_ref != nullptr && sub_ref != nullptr && + variance != Variance::kInvariant) { + sub_ref->AdaptToSupertype(*super_ref, variance, available_ref_types, + previous_types); + return; + } + // Numeric types and invariant positions must match the supertype's value + // type; also fall back to copying if only one of the two is a `RefType`. + *this = super_val; + } + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { - if (auto* ref_type = std::get_if<RefType>(this)) { + if (RefType* ref_type = std::get_if<RefType>(this)) { ref_type->CanonicalizeIndexes(canonical_indexes); } } @@ -129,6 +196,17 @@ struct FieldType { val_type.FixupRefType(available_ref_types, recgroup_start); } + void AdaptToSupertype(const FieldType& super_field, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + mutability = super_field.mutability; + // Mutable fields are invariant; immutable fields are covariant. + Variance variance = + mutability ? Variance::kInvariant : Variance::kCovariant; + val_type.AdaptToSupertype(super_field.val_type, variance, + available_ref_types, previous_types); + } + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { val_type.CanonicalizeIndexes(canonical_indexes); } @@ -150,6 +228,25 @@ struct StructType { } } + void AdaptToSupertype(const StructType& supertype, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + // Struct subtyping allows depth subtyping on existing fields and width + // subtyping by appending extra fields (which remain at the end of + // `field_types` if `field_types.size() > supertype.field_types.size()`). + size_t generated_fields = + std::min(field_types.size(), supertype.field_types.size()); + for (size_t i = 0; i < generated_fields; ++i) { + field_types[i].AdaptToSupertype(supertype.field_types[i], + available_ref_types, previous_types); + } + if (field_types.size() < supertype.field_types.size()) { + field_types.insert(field_types.end(), + supertype.field_types.begin() + generated_fields, + supertype.field_types.end()); + } + } + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { for (FieldType& field_type : field_types) { field_type.CanonicalizeIndexes(canonical_indexes); @@ -158,12 +255,10 @@ struct StructType { static RefTypeKind ref_type_kind() { return RefTypeKind::kStruct; } - void BuildType(Zone* zone, WasmModuleBuilder* builder) const { - // TODO(381687256): Populate final and supertype. - constexpr bool kNotFinal = false; - constexpr ModuleTypeIndex kNoSupertype = ModuleTypeIndex::Invalid(); + void BuildType(Zone* zone, WasmModuleBuilder* builder, bool is_final, + ModuleTypeIndex supertype) const { // If this fails, we need to constrain vector sizes in the fuzzer domains. - DCHECK_GE(kMaxUInt32, field_types.size()); + DCHECK_GE(kV8MaxWasmStructFields, field_types.size()); uint32_t field_count = static_cast<uint32_t>(field_types.size()); // Offsets are not used and never accessed, hence we can pass nullptr. constexpr uint32_t* kNoOffsets = nullptr; @@ -178,7 +273,7 @@ struct StructType { builder->AddStructType( zone->New<wasm::StructType>(field_count, kNoOffsets, reps, mutabilities, is_descriptor, SharedFlag{false}), - kNotFinal, kNoSupertype); + is_final, supertype); } void Print(std::ostream& os) const { @@ -197,18 +292,23 @@ struct ArrayType { field_type.val_type.FixupRefType(available_ref_types, recgroup_start); } + void AdaptToSupertype(const ArrayType& supertype, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + field_type.AdaptToSupertype(supertype.field_type, available_ref_types, + previous_types); + } + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { field_type.val_type.CanonicalizeIndexes(canonical_indexes); } - void BuildType(Zone* zone, WasmModuleBuilder* builder) const { - // TODO(381687256): Populate final and supertype. - constexpr bool kNotFinal = false; - constexpr ModuleTypeIndex kNoSupertype = ModuleTypeIndex::Invalid(); + void BuildType(Zone* zone, WasmModuleBuilder* builder, bool is_final, + ModuleTypeIndex supertype) const { builder->AddArrayType( zone->New<wasm::ArrayType>(field_type.val_type.value_type(), - field_type.mutability), - kNotFinal, kNoSupertype); + field_type.mutability, SharedFlag{false}), + is_final, supertype); } void Print(std::ostream& os) const { os << "array(" << field_type << ")"; } @@ -231,20 +331,48 @@ struct FunctionType { } } + void AdaptToSupertype(const FunctionType& supertype, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + // Function subtyping is contravariant in parameters and covariant in + // returns, with matching arities. + AdaptVector(params, supertype.params, Variance::kContravariant, + available_ref_types, previous_types); + AdaptVector(returns, supertype.returns, Variance::kCovariant, + available_ref_types, previous_types); + } + + static void AdaptVector(std::vector<ValType>& sub_vec, + const std::vector<ValType>& super_vec, + Variance variance, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + // Adapt the overlapping prefix and resize to match the supertype's arity. + size_t generated = std::min(sub_vec.size(), super_vec.size()); + for (size_t i = 0; i < generated; ++i) { + sub_vec[i].AdaptToSupertype(super_vec[i], variance, available_ref_types, + previous_types); + } + if (sub_vec.size() > super_vec.size()) { + sub_vec.erase(sub_vec.begin() + super_vec.size(), sub_vec.end()); + } else if (sub_vec.size() < super_vec.size()) { + sub_vec.insert(sub_vec.end(), super_vec.begin() + generated, + super_vec.end()); + } + } + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { for (ValType& t : params) t.CanonicalizeIndexes(canonical_indexes); for (ValType& t : returns) t.CanonicalizeIndexes(canonical_indexes); } - void BuildType(Zone* zone, WasmModuleBuilder* builder) const { - // TODO(381687256): Populate final and supertype. - constexpr bool kNotFinal = false; - constexpr ModuleTypeIndex kNoSupertype = ModuleTypeIndex::Invalid(); + void BuildType(Zone* zone, WasmModuleBuilder* builder, bool is_final, + ModuleTypeIndex supertype) const { FunctionSig::Builder sig_builder(zone, returns.size(), params.size()); for (ValType param : params) sig_builder.AddParam(param.value_type()); for (ValType ret : returns) sig_builder.AddReturn(ret.value_type()); FunctionSig* sig = sig_builder.Get(); - builder->ForceAddSignature(sig, kNotFinal, kNoSupertype); + builder->ForceAddSignature(sig, is_final, supertype); } void Print(std::ostream& os) const { @@ -262,48 +390,223 @@ std::ostream& operator<<(std::ostream& os, const CompType& type) { return os; } +// `subtype` in the spec (`sub final? typeidx* comptype`). +struct SubType { + CompType type; + bool is_final; + // The fuzzer domain initially chooses either `kNoSuperType.index` or an + // unconstrained non-negative index. + // `Fixup` will restrict this index to a valid earlier supertype index (or + // reset it to `kNoSuperType.index` if none exists) and will potentially set + // `supertype_in_recgroup`. + // `CanonicalizeIndexes` will replace `supertype` by a canonical index if it + // references a type from an earlier recgroup (i.e. if `supertype_in_recgroup` + // is not set). + uint32_t supertype; + + // `supertype_in_recgroup` and `subtyping_depth` will be set by `Fixup`. + std::optional<uint32_t> supertype_in_recgroup; + uint32_t subtyping_depth = 0; + + // Construction only passes the first three fields. + SubType(CompType type, bool is_final, uint32_t supertype) + : type(std::move(type)), is_final(is_final), supertype(supertype) {} + + RefTypeKind ref_type_kind() const { + return std::visit([](const auto& t) { return t.ref_type_kind(); }, type); + } + + void Fixup(const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types, + uint32_t recgroup_start) { + if (supertype != kNoSuperType.index) { + // Collect all valid non-final earlier types of the same kind and within + // the maximum subtyping depth. + RefTypeKind kind = ref_type_kind(); + base::SmallVector<uint32_t, 16> candidates; + for (uint32_t i = 0; i < previous_types.size(); ++i) { + const SubType* cand = previous_types[i]; + if (!cand->is_final && + cand->subtyping_depth < kV8MaxRttSubtypingDepth && + cand->ref_type_kind() == kind) { + candidates.push_back(i); + } + } + if (candidates.empty()) { + supertype = kNoSuperType.index; + } else { + supertype = candidates[supertype % candidates.size()]; + const SubType* super = previous_types[supertype]; + subtyping_depth = super->subtyping_depth + 1; + if (supertype >= recgroup_start) { + supertype_in_recgroup = supertype - recgroup_start; + } + // Adapt to the supertype before fixing up reference types so that any + // fields/parameters/returns added by subtyping are also fixed up. + std::visit( + [&]<typename T>(T& t) { + t.AdaptToSupertype(std::get<T>(super->type), available_ref_types, + previous_types); + }, + type); + } + } + + std::visit( + [&](auto& t) { t.FixupRefTypes(available_ref_types, recgroup_start); }, + type); + } + + void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { + if (supertype != kNoSuperType.index && !supertype_in_recgroup.has_value()) { + // Update the supertype index to the canonical index from an earlier + // recgroup. + DCHECK_LT(supertype, canonical_indexes.size()); + supertype = canonical_indexes[supertype]; + } + std::visit([&](auto& t) { t.CanonicalizeIndexes(canonical_indexes); }, + type); + } + + void BuildType(Zone* zone, WasmModuleBuilder* builder) const { + std::visit( + [&](const auto& t) { + t.BuildType(zone, builder, is_final, ModuleTypeIndex{supertype}); + }, + type); + } + + void Print(std::ostream& os) const { + if (is_final) os << "final "; + if (supertype_in_recgroup.has_value()) { + os << "sub rec " << supertype_in_recgroup.value() << " "; + } else if (supertype != kNoSuperType.index) { + os << "sub " << supertype << " "; + } + os << type; + } +}; + +void RefType::AdaptToSupertype( + const RefType& super_ref, Variance variance, + const std::vector<RefTypeKind>& available_ref_types, + const std::vector<const SubType*>& previous_types) { + shared = super_ref.shared; + // Non-nullable covariant references must remain non-nullable; nullable + // contravariant references must remain nullable. + if (variance == Variance::kCovariant && + super_ref.nullable == Nullability::kNonNullable) { + nullable = Nullability::kNonNullable; + } else if (variance == Variance::kContravariant && + super_ref.nullable == Nullability::kNullable) { + nullable = Nullability::kNullable; + } + + HeapType super_heap = super_ref.value_type().heap_type(); + if (uint32_t* sub_idx = std::get_if<uint32_t>(&heap_type)) { + base::SmallVector<uint32_t, 8> candidates; + if (const uint32_t* super_idx = + std::get_if<uint32_t>(&super_ref.heap_type)) { + candidates.push_back(*super_idx); + if (variance == Variance::kCovariant) { + // Collect all earlier types that transitively have `*super_idx` as a + // supertype. + for (uint32_t i = *super_idx + 1; i < previous_types.size(); ++i) { + for (uint32_t cur = previous_types[i]->supertype; + cur != kNoSuperType.index; + cur = previous_types[cur]->supertype) { + if (cur == *super_idx) { + candidates.push_back(i); + break; + } + } + } + } else { + DCHECK_EQ(Variance::kContravariant, variance); + // If `*super_idx` is not a forward reference within the supertype's + // recgroup, collect all of its transitive supertypes. + if (*super_idx < previous_types.size()) { + for (uint32_t cur = previous_types[*super_idx]->supertype; + cur != kNoSuperType.index; + cur = previous_types[cur]->supertype) { + candidates.push_back(cur); + } + } + } + } else { + // `super_ref` has an abstract heap type; check which indexed types up to + // the end of the current recgroup are valid subtypes/supertypes (e.g. a + // struct/array/func type refining `any`, `eq`, `struct`, `array`, or + // `func`). + for (uint32_t i = 0; i < available_ref_types.size(); ++i) { + HeapType cand_heap = + HeapType::Index(ModuleTypeIndex{i}, shared, available_ref_types[i]); + bool match = variance == Variance::kCovariant + ? IsHeapSubtypeOf(cand_heap, super_heap, nullptr) + : IsHeapSubtypeOf(super_heap, cand_heap, nullptr); + if (match) candidates.push_back(i); + } + } + if (!candidates.empty()) { + *sub_idx = candidates[*sub_idx % candidates.size()]; + return; + } + } + + // Either `this` was generated as an abstract heap type, or no indexed type + // matched (e.g. `super_ref` is `i31`, `none`, `extern`, or contravariant from + // an abstract supertype). Pick a matching abstract heap type using a + // deterministic seed derived from `this`. + uint32_t seed = std::holds_alternative<uint32_t>(heap_type) + ? std::get<uint32_t>(heap_type) + : static_cast<uint32_t>(value_type().standard_type()); + base::SmallVector<GenericKind, 8> generic_candidates; + for (GenericKind cand : kAllGenericKinds) { + HeapType cand_heap = HeapType::Generic(cand, shared); + bool match = variance == Variance::kCovariant + ? IsHeapSubtypeOf(cand_heap, super_heap, nullptr) + : IsHeapSubtypeOf(super_heap, cand_heap, nullptr); + if (match) generic_candidates.push_back(cand); + } + DCHECK(!generic_candidates.empty()); + heap_type = generic_candidates[seed % generic_candidates.size()]; +} + // `rectype` in the spec. struct RecursionGroup { - std::vector<CompType> types; + std::vector<SubType> types; // If {single_type} is false, this type will be outside any recursion group. // This is only allowed if {types.size() == 1}. bool single_type = false; - void UpdateAvailableRefTypesAndFixupRefTypes( - std::vector<RefTypeKind>& available_ref_types) { + void UpdateAvailableTypesAndFixup( + std::vector<RefTypeKind>& available_ref_types, + std::vector<const SubType*>& previous_types) { uint32_t recgroup_start = base::checked_cast<uint32_t>(available_ref_types.size()); - for (const CompType& type : types) { - available_ref_types.push_back( - std::visit([](auto& t) { return t.ref_type_kind(); }, type)); + for (const SubType& type : types) { + available_ref_types.push_back(type.ref_type_kind()); } - for (CompType& type : types) { - std::visit( - [&](auto& t) { - t.FixupRefTypes(available_ref_types, recgroup_start); - }, - type); + for (SubType& type : types) { + type.Fixup(available_ref_types, previous_types, recgroup_start); + previous_types.push_back(&type); } } void CanonicalizeIndexes(const std::vector<uint32_t>& canonical_indexes) { - for (CompType& type : types) { - std::visit([&](auto& t) { t.CanonicalizeIndexes(canonical_indexes); }, - type); + for (SubType& type : types) { + type.CanonicalizeIndexes(canonical_indexes); } } void BuildTypes(Zone* zone, WasmModuleBuilder* builder) const { - auto build_type = [zone, builder](const auto& t) { - t.BuildType(zone, builder); - }; if (single_type) { DCHECK_EQ(1, types.size()); - std::visit(build_type, types[0]); + types[0].BuildType(zone, builder); } else { builder->StartRecursiveTypeGroup(); - for (const CompType& type : types) { - std::visit(build_type, type); + for (const SubType& type : types) { + type.BuildType(zone, builder); } builder->EndRecursiveTypeGroup(); } @@ -320,10 +623,12 @@ struct RecursionGroup { struct Module { std::vector<RecursionGroup> rec_groups; - void FixupRefTypes() { + void Fixup() { std::vector<RefTypeKind> available_ref_types; + std::vector<const SubType*> previous_types; for (RecursionGroup& rec_group : rec_groups) { - rec_group.UpdateAvailableRefTypesAndFixupRefTypes(available_ref_types); + rec_group.UpdateAvailableTypesAndFixup(available_ref_types, + previous_types); } } @@ -371,11 +676,14 @@ class TypeCanonicalizerTest // FuzzTest domain construction. static fuzztest::Domain<test::Module> ArbitraryModule() { - // reftype ::= ref null? heaptype + // absheaptype + auto abs_heap_type_domain = fuzztest::ElementOf(test::kAllGenericKinds); // heaptype ::= absheaptype | typeidx - // TODO(381687256): Introduce abstract heap types. + auto heap_type_domain = fuzztest::VariantOf( + abs_heap_type_domain, fuzztest::InRange<uint32_t>(0, kMaxInt)); + // reftype ::= ref null? heaptype auto ref_type_domain = fuzztest::ConstructorOf<test::RefType>( - /* index */ fuzztest::NonNegative<int>(), + heap_type_domain, // TODO(clemensb): Support shared types; the bit currently gets lost in // the module builder. /* shared */ @@ -384,10 +692,11 @@ static fuzztest::Domain<test::Module> ArbitraryModule() { fuzztest::ElementOf({Nullability::kNullable, Nullability::kNonNullable})); // numtype ::= i32 | i64 | f32 | f64 - auto num_type_domain = fuzztest::StructOf<test::NumType>( - fuzztest::ElementOf<ValueType>({kWasmI32, kWasmI64, kWasmF32, kWasmF64})); + // vectype ::= v128 + auto num_type_domain = + fuzztest::StructOf<test::NumType>(fuzztest::ElementOf<ValueType>( + {kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmS128})); // valtype ::= numtype | vectype | reftype - // TODO(381687256): Add vectype (kS128) on SIMD-enabled hosts. auto val_type_domain = fuzztest::ConstructorOf<test::ValType>( fuzztest::VariantOf(num_type_domain, ref_type_domain)); // resulttype ::= [vec(valtype)] @@ -420,17 +729,22 @@ static fuzztest::Domain<test::Module> ArbitraryModule() { auto comptype_domain = fuzztest::VariantOf<test::CompType>( function_type_domain, struct_type_domain, array_type_domain); - // rectype ::= rec subtype* // subtype ::= sub final? typeidx* comptype - // TODO(381687256): support final types and subtyping. + auto subtype_domain = fuzztest::ConstructorOf<test::SubType>( + comptype_domain, + /* is_final */ fuzztest::Arbitrary<bool>(), + /* supertype */ + fuzztest::OneOf(fuzztest::Just(kNoSuperType.index), + fuzztest::InRange<uint32_t>(0, kMaxInt))); + + // rectype ::= rec subtype* auto recgroup_domain = fuzztest::OneOf( // A single type declared outside any recursion group. fuzztest::StructOf<test::RecursionGroup>( - fuzztest::VectorOf(comptype_domain).WithSize(1), - fuzztest::Just(true)), + fuzztest::VectorOf(subtype_domain).WithSize(1), fuzztest::Just(true)), // An actual recursion group of arbitrary size. fuzztest::StructOf<test::RecursionGroup>( - fuzztest::VectorOf(comptype_domain), fuzztest::Just(false))); + fuzztest::VectorOf(subtype_domain), fuzztest::Just(false))); auto module_domain = fuzztest::StructOf<test::Module>(fuzztest::VectorOf(recgroup_domain)); @@ -467,9 +781,9 @@ void TypeCanonicalizerTest::TestCanonicalization( // 2) we want to avoid relying on `WasmModule` internals. std::vector<uint32_t> canonical_indexes; - // After module generation by the fuzzer, fix up ref types to include the - // correct ref type kind and restrict indexes to the valid index space. - test_module.FixupRefTypes(); + // After module generation by the fuzzer, fix up ref types and supertypes + // to restrict indexes to the valid index space and ensure valid subtyping. + test_module.Fixup(); WasmModuleBuilder builder(&zone_); test_module.BuildTypes(&zone_, &builder); @@ -484,7 +798,7 @@ void TypeCanonicalizerTest::TestCanonicalization( // If this fails due to too many types, we need to constrain vector sizes in // the fuzzer domains. - ASSERT_TRUE(result.ok()); + ASSERT_TRUE(result.ok()) << result.error().message(); std::shared_ptr<WasmModule> module = std::move(result).value(); size_t total_types = 0; for (const test::RecursionGroup& rec_group : test_module.rec_groups) { @@ -518,8 +832,24 @@ void TypeCanonicalizerTest::TestCanonicalization( ModuleTypeIndex{first_type_id.index + i})); } for (uint32_t i = 0; i < rec_group.types.size(); ++i) { + CanonicalTypeIndex canonical_id{first_canonical_id.index + i}; // This canonical ID can be used by successive recgroups. - canonical_indexes.push_back(first_canonical_id.index + i); + canonical_indexes.push_back(canonical_id.index); + + // Verify that the canonicalized subtype is recognized as a heap subtype + // of its canonical supertype (and not vice versa). + const test::SubType& subtype = rec_group.types[i]; + if (subtype.supertype != kNoSuperType.index) { + CanonicalTypeIndex canonical_supertype{ + subtype.supertype_in_recgroup.has_value() + ? first_canonical_id.index + + subtype.supertype_in_recgroup.value() + : subtype.supertype}; + ASSERT_TRUE(GetTypeCanonicalizer()->IsHeapSubtype( + canonical_id, canonical_supertype)); + ASSERT_FALSE(GetTypeCanonicalizer()->IsHeapSubtype( + canonical_supertype, canonical_id)); + } } std::string recgroup_str = (std::ostringstream{} << rec_group).str(); auto [it, added] = canonical_types.insert( diff --git a/deps/v8/test/cctest/wasm/wasm-atomics-utils.h b/deps/v8/test/unittests/wasm/wasm-atomics-utils.h similarity index 86% rename from deps/v8/test/cctest/wasm/wasm-atomics-utils.h rename to deps/v8/test/unittests/wasm/wasm-atomics-utils.h index 98fe2ff29ea3..a96b5fcc20d2 100644 --- a/deps/v8/test/cctest/wasm/wasm-atomics-utils.h +++ b/deps/v8/test/unittests/wasm/wasm-atomics-utils.h @@ -2,12 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef WASM_ATOMICOP_UTILS_H -#define WASM_ATOMICOP_UTILS_H +#ifndef V8_UNITTESTS_WASM_WASM_ATOMICS_UTILS_H_ +#define V8_UNITTESTS_WASM_WASM_ATOMICS_UTILS_H_ -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -66,4 +65,4 @@ T CompareExchange(T initial, T a, T b) { } // namespace internal } // namespace v8 -#endif +#endif // V8_UNITTESTS_WASM_WASM_ATOMICS_UTILS_H_ diff --git a/deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc b/deps/v8/test/unittests/wasm/wasm-breakpoints-unittest.cc similarity index 86% rename from deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc rename to deps/v8/test/unittests/wasm/wasm-breakpoints-unittest.cc index c7a2ce60ae59..d153912af7e9 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-breakpoints.cc +++ b/deps/v8/test/unittests/wasm/wasm-breakpoints-unittest.cc @@ -8,12 +8,12 @@ #include "src/objects/property-descriptor.h" #include "src/utils/utils.h" #include "src/wasm/wasm-debug.h" +#include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-objects-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -176,30 +176,23 @@ struct WasmValWrapper { bool operator==(const WasmValWrapper& other) const { return val == other.val; } -}; -// Only needed in debug builds. Avoid unused warning otherwise. -#ifdef DEBUG -std::ostream& operator<<(std::ostream& out, const WasmValWrapper& wrapper) { - switch (wrapper.val.type().kind()) { - case kI32: - out << "i32: " << wrapper.val.to<int32_t>(); - break; - case kI64: - out << "i64: " << wrapper.val.to<int64_t>(); - break; - case kF32: - out << "f32: " << wrapper.val.to<float>(); - break; - case kF64: - out << "f64: " << wrapper.val.to<double>(); - break; - default: - UNIMPLEMENTED(); + [[maybe_unused]] friend std::ostream& operator<<( + std::ostream& out, const WasmValWrapper& wrapper) { + switch (wrapper.val.type().kind()) { + case kI32: + return out << "i32: " << wrapper.val.to<int32_t>(); + case kI64: + return out << "i64: " << wrapper.val.to<int64_t>(); + case kF32: + return out << "f32: " << wrapper.val.to<float>(); + case kF64: + return out << "f64: " << wrapper.val.to<double>(); + default: + UNIMPLEMENTED(); + } } - return out; -} -#endif +}; class CollectValuesBreakHandler : public debug::DebugDelegate { public: @@ -283,6 +276,9 @@ int GetIntReturnValue(MaybeDirectHandle<Object> retval) { } // namespace +using WasmBreakpointsTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE WasmBreakpointsTest + WASM_COMPILED_EXEC_TEST(WasmCollectPossibleBreakpoints) { WasmRunner<int> runner(execution_tier); @@ -586,6 +582,64 @@ WASM_COMPILED_EXEC_TEST(Regress10889) { SetBreakpoint(&runner, runner.function_index(), 1, 1); } +WASM_COMPILED_EXEC_TEST(WasmBreakpointMultipleScripts) { + WasmRunner<int> runner(execution_tier); + Isolate* isolate = runner.isolate(); + + runner.Build({WASM_NOP, WASM_I32_ADD(WASM_I32V_1(11), WASM_I32V_1(3))}); + runner.SwitchToDebug(); + + DirectHandle<WasmInstanceObject> instance = + runner.builder().instance_object(); + DirectHandle<WasmModuleObject> module_object(instance->module_object(), + isolate); + DirectHandle<Script> script1(module_object->script(), isolate); + std::shared_ptr<NativeModule> native_module = + module_object->managed_native_module()->get(); + DirectHandle<Script> script2 = GetWasmEngine()->GetOrCreateScript( + isolate, native_module, "custom://other-url.wasm"); + CHECK_NE(*script1, *script2); + + int func_offset = + runner.builder().GetFunctionAt(runner.function_index())->code.offset(); + int code_offset = func_offset + 1; + + DirectHandle<BreakPoint> bp1 = + isolate->factory()->NewBreakPoint(1, isolate->factory()->empty_string()); + DirectHandle<BreakPoint> bp2 = + isolate->factory()->NewBreakPoint(2, isolate->factory()->empty_string()); + DirectHandle<BreakPoint> bp3 = + isolate->factory()->NewBreakPoint(3, isolate->factory()->empty_string()); + + // Set two breakpoints at the same offset on script1, and one on script2. + CHECK(WasmScript::SetBreakPoint(script1, &code_offset, bp1)); + CHECK(WasmScript::SetBreakPoint(script1, &code_offset, bp2)); + CHECK(WasmScript::SetBreakPoint(script2, &code_offset, bp3)); + + // Clearing bp1 (on script1) and bp3 (on script2) must leave bp2 active on + // script1. + CHECK(WasmScript::ClearBreakPoint(script1, code_offset, bp1)); + CHECK(WasmScript::ClearBreakPoint(script2, code_offset, bp3)); + + BreakHandler count_breaks(isolate, {{1, BreakHandler::Continue}}); + + DirectHandle<JSFunction> main_fun_wrapper = + runner.builder().WrapCode(runner.function_index()); + DirectHandle<Object> global(isolate->context()->global_object(), isolate); + MaybeDirectHandle<Object> retval = + Execution::Call(isolate, main_fun_wrapper, global, {}); + CHECK_EQ(14, GetIntReturnValue(retval)); + + // Clearing the last remaining breakpoint (bp2 on script1) must remove it + // from DebugInfo, and clearing again must return false. + CHECK(WasmScript::ClearBreakPoint(script1, code_offset, bp2)); + CHECK(!WasmScript::ClearBreakPoint(script1, code_offset, bp2)); + retval = Execution::Call(isolate, main_fun_wrapper, global, {}); + CHECK_EQ(14, GetIntReturnValue(retval)); +} + +#undef WASM_EXEC_TEST_SUITE + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/wasm/test-wasm-codegen.cc b/deps/v8/test/unittests/wasm/wasm-codegen-unittest.cc similarity index 89% rename from deps/v8/test/cctest/wasm/test-wasm-codegen.cc rename to deps/v8/test/unittests/wasm/wasm-codegen-unittest.cc index e2a4b96842e1..6b42060fb589 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-codegen.cc +++ b/deps/v8/test/unittests/wasm/wasm-codegen-unittest.cc @@ -13,14 +13,17 @@ #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-objects.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { +class WasmCodegenTest + : public WithWasmTrapHandlerMixin<TestWithHeapInternalsAndContext> {}; + namespace { // Possible values for callback pointers. @@ -93,29 +96,28 @@ bool TestModule(Isolate* isolate, std::span<const uint8_t> wire_bytes) { } // namespace -TEST(PropertiesOfCodegenCallbacks) { +TEST_F(WasmCodegenTest, PropertiesOfCodegenCallbacks) { v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); ZoneBuffer buffer(&zone); BuildTrivialModule(&zone, &buffer); std::span<const uint8_t> wire_bytes{buffer}; - Isolate* isolate = CcTest::InitIsolateOnce(); - v8::Isolate* v8_isolate = CcTest::isolate(); + Isolate* isolate = i_isolate(); HandleScope scope(isolate); for (TestValue wasm_codegen : AllTestValues) { fprintf(stderr, "Test wasm_codegen = %s\n", TestValueName[wasm_codegen]); - v8_isolate->SetAllowWasmCodeGenerationCallback(Callback[wasm_codegen]); + v8_isolate()->SetAllowWasmCodeGenerationCallback(Callback[wasm_codegen]); bool found = TestModule(isolate, wire_bytes); bool expected = ExpectedResults[wasm_codegen]; CHECK_EQ(expected, found); - heap::InvokeMemoryReducingMajorGCs(isolate->heap()); + InvokeMemoryReducingMajorGCs(); } } -TEST(WasmModuleObjectCompileFailure) { +TEST_F(WasmCodegenTest, WasmModuleObjectCompileFailure) { const uint8_t wire_bytes[] = {0xDE, 0xAD, 0xBE, 0xEF}; - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = i_isolate(); HandleScope scope(isolate); CHECK(!TestModule(isolate, wire_bytes)); } diff --git a/deps/v8/test/unittests/wasm/wasm-compile-module.h b/deps/v8/test/unittests/wasm/wasm-compile-module.h index 6ad84a1694fc..a95ac99c5e5d 100644 --- a/deps/v8/test/unittests/wasm/wasm-compile-module.h +++ b/deps/v8/test/unittests/wasm/wasm-compile-module.h @@ -6,6 +6,7 @@ #define TEST_UNITTESTS_WASM_WASM_COMPILE_MODULE_H_ #include "include/libplatform/libplatform.h" +#include "src/base/unique-array.h" #include "src/base/vector.h" #include "src/execution/isolate.h" #include "src/handles/handles-inl.h" @@ -20,7 +21,7 @@ namespace v8::internal::wasm { class WasmCompileHelper : public AllStatic { public: static void SyncCompile(Isolate* isolate, - base::OwnedVector<const uint8_t> bytes) { + base::UniqueArray<const uint8_t> bytes) { ErrorThrower thrower(isolate, "WasmCompileHelper::SyncCompile"); GetWasmEngine()->SyncCompile(isolate, WasmEnabledFeatures::All(), CompileTimeImports{}, &thrower, @@ -29,7 +30,7 @@ class WasmCompileHelper : public AllStatic { } static void AsyncCompile(Isolate* isolate, - base::OwnedVector<const uint8_t> bytes) { + base::UniqueArray<const uint8_t> bytes) { std::shared_ptr<TestResolver> resolver = std::make_shared<TestResolver>(); GetWasmEngine()->AsyncCompile( diff --git a/deps/v8/test/cctest/wasm/test-wasm-import-wrapper-cache.cc b/deps/v8/test/unittests/wasm/wasm-import-wrapper-cache-unittest.cc similarity index 92% rename from deps/v8/test/cctest/wasm/test-wasm-import-wrapper-cache.cc rename to deps/v8/test/unittests/wasm/wasm-import-wrapper-cache-unittest.cc index 5ec9b5c66054..063a29f86660 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-import-wrapper-cache.cc +++ b/deps/v8/test/unittests/wasm/wasm-import-wrapper-cache-unittest.cc @@ -2,23 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/wasm/wasm-import-wrapper-cache.h" + #include "src/compiler/wasm-compiler.h" #include "src/wasm/function-compiler.h" #include "src/wasm/module-compiler.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-engine.h" -#include "src/wasm/wasm-import-wrapper-cache.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects.h" -#include "test/cctest/cctest.h" #include "test/common/flag-utils.h" #include "test/common/wasm/test-signatures.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_wasm_import_wrapper_cache { +using WasmImportWrapperCacheTest = WithWasmTrapHandlerMixin<TestWithIsolate>; + std::shared_ptr<NativeModule> NewModule(Isolate* isolate) { auto module = std::make_shared<WasmModule>(); size_t kCodeSizeEstimate = 0; @@ -29,9 +32,9 @@ std::shared_ptr<NativeModule> NewModule(Isolate* isolate) { return native_module; } -TEST(CacheHit) { +TEST_F(WasmImportWrapperCacheTest, CacheHit) { FlagScope<bool> cleanup_immediately(&v8_flags.stress_wasm_code_gc, true); - Isolate* isolate = CcTest::InitIsolateOnce(); + Isolate* isolate = i_isolate(); auto module = NewModule(isolate); TestSignatures sigs; @@ -64,8 +67,8 @@ TEST(CacheHit) { kind, canonical_sig, expected_arity, kNoSuspend)); } -TEST(CacheMissSig) { - Isolate* isolate = CcTest::InitIsolateOnce(); +TEST_F(WasmImportWrapperCacheTest, CacheMissSig) { + Isolate* isolate = i_isolate(); auto module = NewModule(isolate); TestSignatures sigs; WasmCodeRefScope wasm_code_ref_scope; @@ -94,8 +97,8 @@ TEST(CacheMissSig) { kind, canonical_sig2, expected_arity2, kNoSuspend)); } -TEST(CacheMissKind) { - Isolate* isolate = CcTest::InitIsolateOnce(); +TEST_F(WasmImportWrapperCacheTest, CacheMissKind) { + Isolate* isolate = i_isolate(); auto module = NewModule(isolate); TestSignatures sigs; WasmCodeRefScope wasm_code_ref_scope; @@ -119,8 +122,8 @@ TEST(CacheMissKind) { kind2, canonical_sig, expected_arity, kNoSuspend)); } -TEST(CacheHitMissSig) { - Isolate* isolate = CcTest::InitIsolateOnce(); +TEST_F(WasmImportWrapperCacheTest, CacheHitMissSig) { + Isolate* isolate = i_isolate(); auto module = NewModule(isolate); TestSignatures sigs; WasmCodeRefScope wasm_code_ref_scope; diff --git a/deps/v8/test/cctest/wasm/test-wasm-metrics.cc b/deps/v8/test/unittests/wasm/wasm-metrics-unittest.cc similarity index 74% rename from deps/v8/test/cctest/wasm/test-wasm-metrics.cc rename to deps/v8/test/unittests/wasm/wasm-metrics-unittest.cc index fc75c7cefa1e..5901335d4732 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-metrics.cc +++ b/deps/v8/test/unittests/wasm/wasm-metrics-unittest.cc @@ -3,34 +3,58 @@ // found in the LICENSE file. #include <memory> +#include <queue> +#include <string> +#include <unordered_set> +#include <vector> #include "include/libplatform/libplatform.h" #include "include/v8-metrics.h" #include "include/v8-platform.h" #include "src/api/api-inl.h" #include "src/base/platform/time.h" +#include "src/base/unique-array.h" #include "src/objects/managed.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-objects-inl.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { -namespace test { +namespace { -class MockPlatform final : public TestPlatform { +class MockPlatform final : public v8::Platform { public: - MockPlatform() - : no_memory_reducer_(&v8_flags.memory_reducer, false), - task_runner_(std::make_shared<MockTaskRunner>()) {} + explicit MockPlatform(v8::Platform* default_platform) + : default_platform_(default_platform), + no_memory_reducer_(&v8_flags.memory_reducer, false), + task_runner_(std::make_shared<MockTaskRunner>()) { + CHECK_NOT_NULL(default_platform_); + i::V8::SetPlatformForTesting(this); + } ~MockPlatform() override { for (auto* job_handle : job_handles_) job_handle->ResetPlatform(); + if (i::V8::GetCurrentPlatform() == this) { + i::V8::SetPlatformForTesting(default_platform_); + } + } + + v8::PageAllocator* GetPageAllocator() override { + return default_platform_->GetPageAllocator(); + } + + void OnCriticalMemoryPressure() override { + default_platform_->OnCriticalMemoryPressure(); + } + + int NumberOfWorkerThreads() override { + return default_platform_->NumberOfWorkerThreads(); } std::unique_ptr<v8::JobHandle> CreateJobImpl( @@ -55,12 +79,33 @@ class MockPlatform final : public TestPlatform { task_runner_->PostTask(std::move(task)); } + void PostDelayedTaskOnWorkerThreadImpl( + v8::TaskPriority priority, std::unique_ptr<v8::Task> task, + double delay_in_seconds, const v8::SourceLocation& location) override { + default_platform_->PostDelayedTaskOnWorkerThread(priority, std::move(task), + delay_in_seconds); + } + + double MonotonicallyIncreasingTime() override { + return default_platform_->MonotonicallyIncreasingTime(); + } + + double CurrentClockTimeMillis() override { + return default_platform_->CurrentClockTimeMillis(); + } + bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; } - void ExecuteTasks() { - task_runner_->ExecuteTasks(); + v8::TracingController* GetTracingController() override { + return default_platform_->GetTracingController(); + } + + v8::ThreadIsolatedAllocator* GetThreadIsolatedAllocator() override { + return default_platform_->GetThreadIsolatedAllocator(); } + void ExecuteTasks() { task_runner_->ExecuteTasks(); } + private: class MockTaskRunner final : public TaskRunner { public: @@ -144,6 +189,7 @@ class MockPlatform final : public TestPlatform { MockPlatform* platform_; }; + v8::Platform* default_platform_; FlagScope<bool> no_memory_reducer_; std::shared_ptr<MockTaskRunner> task_runner_; std::unordered_set<MockJobHandle*> job_handles_; @@ -182,7 +228,8 @@ class InstantiateResolver : public InstantiationResultResolver { class CompileResolver : public CompilationResultResolver { public: CompileResolver(CompilationStatus* status, std::string* error_message, - Isolate* isolate, CppGCManaged<NativeModule>::Ptr* native_module) + Isolate* isolate, + CppGCManaged<NativeModule>::Ptr* native_module) : status_(status), error_message_(error_message), isolate_(isolate), @@ -203,7 +250,7 @@ class CompileResolver : public CompilationResultResolver { void OnCompilationFailed(i::DirectHandle<i::JSAny> error_reason) override { *status_ = CompilationStatus::kFailed; DirectHandle<String> str = - Object::ToString(CcTest::i_isolate(), error_reason).ToHandleChecked(); + Object::ToString(isolate_, error_reason).ToHandleChecked(); error_message_->assign(str->ToCString().get()); } @@ -214,31 +261,55 @@ class CompileResolver : public CompilationResultResolver { CppGCManaged<NativeModule>::Ptr* const native_module_; }; -} // namespace test - -#define RUN_COMPILE(name) \ - v8::HandleScope handle_scope(CcTest::isolate()); \ - v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate()); \ - v8::Context::Scope context_scope(context); \ - Isolate* i_isolate = CcTest::i_isolate(); \ - RunCompile_##name(&platform, i_isolate); - -#define COMPILE_TEST(name) \ - void RunCompile_##name(test::MockPlatform*, i::Isolate*); \ - TEST_WITH_PLATFORM(Sync##name, test::MockPlatform) { \ - i::FlagScope<bool> single_threaded_scope(&i::v8_flags.single_threaded, \ - true); \ - RUN_COMPILE(name); \ - } \ - \ - TEST_WITH_PLATFORM(Async##name, test::MockPlatform) { RUN_COMPILE(name); } \ - \ - TEST_WITH_PLATFORM(Streaming##name, test::MockPlatform) { \ - i::FlagScope<bool> streaming_scope(&i::v8_flags.wasm_test_streaming, \ - true); \ - RUN_COMPILE(name); \ - } \ - void RunCompile_##name(test::MockPlatform* platform, i::Isolate* isolate) +template <typename TMixin> +class WithMockPlatformMixin : public TMixin { + public: + WithMockPlatformMixin() : mock_platform_(this->platform()) {} + WithMockPlatformMixin(const WithMockPlatformMixin&) = delete; + WithMockPlatformMixin& operator=(const WithMockPlatformMixin&) = delete; + + void TearDown() override { + // Restore default_platform_ before ~IsolateWrapper() calls + // v8::platform::PumpMessageLoop. + if (i::V8::GetCurrentPlatform() == &mock_platform_) { + i::V8::SetPlatformForTesting(this->platform()); + } + TMixin::TearDown(); + } + + MockPlatform* mock_platform() { return &mock_platform_; } + + private: + MockPlatform mock_platform_; +}; + +} // namespace + +using WasmMetricsTest = WithIsolateScopeMixin<WithIsolateMixin< + WithMockPlatformMixin<WithWasmTrapHandlerMixin<TestWithPlatform>>>>; + +#define RUN_COMPILE(name) \ + v8::HandleScope handle_scope(isolate()); \ + v8::Local<v8::Context> context = v8::Context::New(isolate()); \ + v8::Context::Scope context_scope(context); \ + RunCompile_##name(mock_platform(), i_isolate()); + +#define COMPILE_TEST(name) \ + void RunCompile_##name(MockPlatform*, i::Isolate*); \ + TEST_F(WasmMetricsTest, Sync##name) { \ + i::FlagScope<bool> single_threaded_scope(&i::v8_flags.single_threaded, \ + true); \ + RUN_COMPILE(name); \ + } \ + \ + TEST_F(WasmMetricsTest, Async##name) { RUN_COMPILE(name); } \ + \ + TEST_F(WasmMetricsTest, Streaming##name) { \ + i::FlagScope<bool> streaming_scope(&i::v8_flags.wasm_test_streaming, \ + true); \ + RUN_COMPILE(name); \ + } \ + void RunCompile_##name(MockPlatform* platform, i::Isolate* isolate) class MetricsRecorder : public v8::metrics::Recorder { public: @@ -280,28 +351,28 @@ COMPILE_TEST(TestEventMetrics) { WasmModuleBuilder* builder = zone.New<WasmModuleBuilder>(&zone); WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v()); - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); f->EmitCode({WASM_I32V_2(0), WASM_END}); ZoneBuffer buffer(&zone); builder->WriteTo(&buffer); auto enabled_features = WasmEnabledFeatures::FromIsolate(isolate); - test::CompilationStatus status = test::CompilationStatus::kPending; + CompilationStatus status = CompilationStatus::kPending; std::string error_message; CppGCManaged<NativeModule>::Ptr native_module; - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(buffer); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(buffer); GetWasmEngine()->AsyncCompile( isolate, enabled_features, CompileTimeImports{}, - std::make_shared<test::CompileResolver>(&status, &error_message, isolate, - &native_module), + std::make_shared<CompileResolver>(&status, &error_message, isolate, + &native_module), std::move(bytes), "CompileAndInstantiateWasmModuleForTesting"); // Finish compilation tasks. - while (status == test::CompilationStatus::kPending) { + while (status == CompilationStatus::kPending) { platform->ExecuteTasks(); } platform->ExecuteTasks(); // Complete pending tasks beyond compilation. - CHECK_EQ(test::CompilationStatus::kFinished, status); + CHECK_EQ(CompilationStatus::kFinished, status); CHECK_EQ(1, recorder->module_decoded_.size()); CHECK(recorder->module_decoded_.back().success); diff --git a/deps/v8/test/unittests/wasm/wasm-runner.h b/deps/v8/test/unittests/wasm/wasm-runner.h new file mode 100644 index 000000000000..de11ae51a62d --- /dev/null +++ b/deps/v8/test/unittests/wasm/wasm-runner.h @@ -0,0 +1,149 @@ +// Copyright 2026 the V8 project 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 V8_UNITTESTS_WASM_WASM_RUNNER_H_ +#define V8_UNITTESTS_WASM_WASM_RUNNER_H_ + +#include "src/api/api-inl.h" +#include "src/sandbox/hardware-support.h" +#include "src/trap-handler/trap-handler.h" +#include "test/common/wasm/wasm-run-utils.h" +#include "test/unittests/test-utils.h" + +namespace v8::internal::wasm { + +class WasmTrapHandlerInitializer { + protected: + WasmTrapHandlerInitializer() { +#if V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED + // SandboxHardwareSupport::InitializeBeforeThreadCreation() has already run + // in main(); enable the trap handler once per process before any call to + // IsTrapHandlerEnabled() (such as during Isolate::New). + if (HardwareSandboxingDisabledOrSupportsSignalDeliveryInSandbox() && + trap_handler::g_can_enable_trap_handler.load( + std::memory_order_relaxed)) { + constexpr bool kUseDefaultTrapHandler = true; + CHECK(v8::V8::EnableWebAssemblyTrapHandler(kUseDefaultTrapHandler)); + } +#endif // V8_ENABLE_WEBASSEMBLY && V8_TRAP_HANDLER_SUPPORTED + } +}; + +template <typename TMixin> +class WithWasmTrapHandlerMixin : private WasmTrapHandlerInitializer, + public TMixin {}; + +using WasmUninitializedTestBase = WithWasmTrapHandlerMixin<TestWithPlatform>; + +class WasmExecutionTestBase : public WithIsolateScopeMixin< + WithIsolateMixin<WasmUninitializedTestBase>> { + public: + ~WasmExecutionTestBase() override { + while (v8_isolate()->InContext()) { + v8_isolate()->GetCurrentContext()->Exit(); + } + } + + static Isolate* InitIsolateOnce() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + CHECK_NOT_NULL(isolate); + if (!isolate->InContext()) { + v8::Context::New(isolate)->Enter(); + } + return reinterpret_cast<Isolate*>(isolate); + } + + static Isolate* current_i_isolate() { + return reinterpret_cast<Isolate*>(v8::Isolate::GetCurrent()); + } + + static v8::Isolate* current_isolate() { return v8::Isolate::GetCurrent(); } + + static Heap* current_heap() { return current_i_isolate()->heap(); } + + static v8::base::RandomNumberGenerator* random_number_generator() { + return InitIsolateOnce()->random_number_generator(); + } +}; + +inline v8::Local<v8::Value> CompileRun(const char* source) { + WasmExecutionTestBase::InitIsolateOnce(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + v8::Local<v8::Script> script = + v8::Script::Compile( + context, v8::String::NewFromUtf8(isolate, source).ToLocalChecked()) + .ToLocalChecked(); + v8::Local<v8::Value> result; + if (script->Run(context).ToLocal(&result)) { + return result; + } + return v8::Local<v8::Value>(); +} + +template <typename ReturnType, typename... ParamTypes> +class WasmRunner : public CommonWasmRunner<ReturnType, ParamTypes...> { + public: + // If the caller does not provide an isolate, use the current test isolate. + template <typename... Args> + requires(... && !std::is_same_v<Args, Isolate*>) + explicit WasmRunner(TestExecutionTier execution_tier, Args&&... args) + : CommonWasmRunner<ReturnType, ParamTypes...>( + WasmExecutionTestBase::InitIsolateOnce(), execution_tier, + std::forward<Args&&>(args)...) {} + + // If an isolate is provided, use that. + template <typename... Args> + requires(... && !std::is_same_v<Args, Isolate*>) + explicit WasmRunner(Isolate* isolate, Args&&... args) + : CommonWasmRunner<ReturnType, ParamTypes...>( + isolate, std::forward<Args&&>(args)...) {} +}; + +#if V8_ENABLE_DRUMBRAKE +#define TEST_IF_DRUMBRAKE(name) \ + TEST_F(WASM_EXEC_TEST_SUITE, RunWasmInterpreter_##name) { \ + FLAG_SCOPE(wasm_jitless); \ + WasmInterpreterThread::Initialize(); \ + RunWasm_##name(TestExecutionTier::kInterpreter); \ + WasmInterpreterThread::Terminate(); \ + } +#else +#define TEST_IF_DRUMBRAKE(name) +#endif // V8_ENABLE_DRUMBRAKE + +#define WASM_EXEC_TEST(name) \ + void RunWasm_##name(TestExecutionTier execution_tier); \ + TEST_F(WASM_EXEC_TEST_SUITE, RunWasmTurbofan_##name) { \ + RunWasm_##name(TestExecutionTier::kTurbofan); \ + } \ + TEST_F(WASM_EXEC_TEST_SUITE, RunWasmLiftoff_##name) { \ + RunWasm_##name(TestExecutionTier::kLiftoff); \ + } \ + TEST_IF_DRUMBRAKE(name) \ + void RunWasm_##name(TestExecutionTier execution_tier) + +#define UNINITIALIZED_WASM_EXEC_TEST(name) \ + void RunWasm_##name(TestExecutionTier execution_tier); \ + TEST_F(WASM_UNINITIALIZED_EXEC_TEST_SUITE, RunWasmTurbofan_##name) { \ + RunWasm_##name(TestExecutionTier::kTurbofan); \ + } \ + TEST_F(WASM_UNINITIALIZED_EXEC_TEST_SUITE, RunWasmLiftoff_##name) { \ + RunWasm_##name(TestExecutionTier::kLiftoff); \ + } \ + void RunWasm_##name(TestExecutionTier execution_tier) + +#define WASM_COMPILED_EXEC_TEST(name) \ + void RunWasm_##name(TestExecutionTier execution_tier); \ + TEST_F(WASM_EXEC_TEST_SUITE, RunWasmTurbofan_##name) { \ + RunWasm_##name(TestExecutionTier::kTurbofan); \ + } \ + TEST_F(WASM_EXEC_TEST_SUITE, RunWasmLiftoff_##name) { \ + RunWasm_##name(TestExecutionTier::kLiftoff); \ + } \ + void RunWasm_##name(TestExecutionTier execution_tier) + +} // namespace v8::internal::wasm + +#endif // V8_UNITTESTS_WASM_WASM_RUNNER_H_ diff --git a/deps/v8/test/cctest/wasm/test-wasm-serialization.cc b/deps/v8/test/unittests/wasm/wasm-serialization-unittest.cc similarity index 74% rename from deps/v8/test/cctest/wasm/test-wasm-serialization.cc rename to deps/v8/test/unittests/wasm/wasm-serialization-unittest.cc index 586563809bdc..b98cb4ab9efe 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-serialization.cc +++ b/deps/v8/test/unittests/wasm/wasm-serialization-unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/wasm/wasm-serialization.h" + #include <stdlib.h> #include <string.h> @@ -9,9 +11,11 @@ #include "include/v8-wasm.h" #include "src/api/api-inl.h" +#include "src/base/unique-array.h" #include "src/objects/managed.h" #include "src/objects/objects-inl.h" #include "src/snapshot/code-serializer.h" +#include "src/trap-handler/trap-handler.h" #include "src/utils/version.h" #include "src/wasm/module-decoder.h" #include "src/wasm/wasm-engine.h" @@ -19,27 +23,33 @@ #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-opcodes.h" -#include "src/wasm/wasm-serialization.h" -#include "test/cctest/cctest.h" -#include "test/cctest/heap/heap-utils.h" #include "test/common/version-utils.h" #include "test/common/wasm/flag-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/heap/heap-utils.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8::internal::wasm { -// Approximate gtest TEST_F style, in case we adopt gtest. -class WasmSerializationTest { +using WasmSerializationTest = WasmExecutionTestBase; +using WasmSerializationUninitializedTest = WasmUninitializedTestBase; + +class WasmSerializationTester { public: - explicit WasmSerializationTest( + explicit WasmSerializationTester( const char* embedder_string = Version::GetEmbedder()) : zone_(&allocator_, ZONE_NAME) { - // Don't call here if we move to gtest. SetUp(embedder_string); } + ~WasmSerializationTester() { + while (WasmExecutionTestBase::current_isolate()->InContext()) { + WasmExecutionTestBase::current_isolate()->GetCurrentContext()->Exit(); + } + } + static constexpr const char* kFunctionName = "increment"; static void BuildWireBytes(Zone* zone, ZoneBuffer* buffer) { @@ -52,7 +62,7 @@ class WasmSerializationTest { f = builder->AddFunction(sigs.i_i()); f->EmitCode({WASM_LOCAL_GET(0), kExprI32Const, 1, kExprI32Add, kExprEnd}); } - builder->AddExport(base::CStrVector(kFunctionName), f); + builder->AddExport(kFunctionName, f); builder->WriteTo(buffer); } @@ -71,20 +81,21 @@ class WasmSerializationTest { } MaybeDirectHandle<WasmModuleObject> Deserialize( - base::Vector<const char> source_url = {}) { + std::string_view source_url = {}) { // Create a separate copy because some tests want to deserialize multiple // times. - base::OwnedVector<const uint8_t> wire_bytes_copy = - base::OwnedCopyOf(wire_bytes_); + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(wire_bytes_); return DeserializeNativeModule( - CcTest::i_isolate(), - WasmEnabledFeatures::FromIsolate(CcTest::i_isolate()), + WasmExecutionTestBase::current_i_isolate(), + WasmEnabledFeatures::FromIsolate( + WasmExecutionTestBase::current_i_isolate()), base::VectorOf(serialized_bytes_), wire_bytes_copy, compile_imports_, source_url); } void DeserializeAndRun() { - ErrorThrower thrower(CcTest::i_isolate(), ""); + ErrorThrower thrower(WasmExecutionTestBase::current_i_isolate(), ""); DirectHandle<WasmModuleObject> module_object; CHECK(Deserialize().ToHandle(&module_object)); { @@ -100,13 +111,14 @@ class WasmSerializationTest { } DirectHandle<WasmInstanceObject> instance = GetWasmEngine() - ->SyncInstantiate(CcTest::i_isolate(), &thrower, module_object, + ->SyncInstantiate(WasmExecutionTestBase::current_i_isolate(), + &thrower, module_object, DirectHandle<JSReceiver>::null()) .ToHandleChecked(); - DirectHandle<Object> params[] = { - direct_handle(Smi::FromInt(41), CcTest::i_isolate())}; + DirectHandle<Object> params[] = {direct_handle( + Smi::FromInt(41), WasmExecutionTestBase::current_i_isolate())}; int32_t result = testing::CallWasmFunctionForTesting( - CcTest::i_isolate(), instance, kFunctionName, + WasmExecutionTestBase::current_i_isolate(), instance, kFunctionName, base::ArrayVector(params)); CHECK_EQ(42, result); } @@ -114,7 +126,10 @@ class WasmSerializationTest { void CollectGarbage() { // Try hard to collect all garbage and will therefore also invoke all weak // callbacks of actually unreachable persistent handles. - heap::InvokeMemoryReducingMajorGCs(CcTest::heap()); + // We need to invoke GC without stack, otherwise some objects may survive. + DisableConservativeStackScanningScopeForTesting no_stack_scanning( + WasmExecutionTestBase::current_heap()); + InvokeMemoryReducingMajorGCs(WasmExecutionTestBase::current_i_isolate()); } std::span<const uint8_t> wire_bytes() const { return wire_bytes_; } @@ -125,13 +140,13 @@ class WasmSerializationTest { Zone* zone() { return &zone_; } void SetUp(const char* embedder_string) { - CcTest::InitIsolateOnce(); + WasmExecutionTestBase::InitIsolateOnce(); ZoneBuffer buffer(&zone_); - WasmSerializationTest::BuildWireBytes(zone(), &buffer); + WasmSerializationTester::BuildWireBytes(zone(), &buffer); v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = - CcTest::i_isolate()->array_buffer_allocator(); + WasmExecutionTestBase::current_i_isolate()->array_buffer_allocator(); v8::Isolate* serialization_v8_isolate = v8::Isolate::New(create_params); Isolate* serialization_isolate = @@ -151,7 +166,7 @@ class WasmSerializationTest { GetWasmEngine()->SyncCompile( serialization_isolate, WasmEnabledFeatures::FromIsolate(serialization_isolate), - MakeCompileTimeImports(), &thrower, base::OwnedCopyOf(buffer)); + MakeCompileTimeImports(), &thrower, base::UniqueCopyOf(buffer)); DirectHandle<WasmModuleObject> module_object = maybe_module_object.ToHandleChecked(); weak_native_module = module_object->native_module().as_shared_ptr(); @@ -179,14 +194,14 @@ class WasmSerializationTest { ->SyncInstantiate(serialization_isolate, &thrower, module_object, {}) .ToHandleChecked(); - CHECK_EQ(0, data_.size); - while (data_.size == 0) { + CHECK(data_.empty()); + while (data_.empty()) { testing::CallWasmFunctionForTesting(serialization_isolate, instance, kFunctionName, {}); ScopedVersionEmbedderString embedder(embedder_string); data_ = compiled_module.Serialize(); } - CHECK_LT(0, data_.size); + CHECK(!data_.empty()); } // Dispose of serialization isolate to destroy the reference to the // NativeModule, which removes it from the module cache in the wasm engine @@ -199,11 +214,11 @@ class WasmSerializationTest { while (weak_native_module.lock()) { } - serialized_bytes_ = {data_.buffer.get(), data_.size}; + serialized_bytes_ = data_.as_span(); - v8::HandleScope new_scope(CcTest::isolate()); + v8::HandleScope new_scope(WasmExecutionTestBase::current_isolate()); v8::Local<v8::Context> deserialization_context = - v8::Context::New(CcTest::isolate()); + v8::Context::New(WasmExecutionTestBase::current_isolate()); deserialization_context->Enter(); } @@ -218,43 +233,43 @@ class WasmSerializationTest { FlagScope<int> tier_up_quickly_{&v8_flags.wasm_tiering_budget, 1000}; }; -TEST(DeserializeValidModule) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, DeserializeValidModule) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); test.DeserializeAndRun(); } test.CollectGarbage(); } -TEST(DeserializeWithSourceUrl) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, DeserializeWithSourceUrl) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); const std::string url = "http://example.com/example.wasm"; DirectHandle<WasmModuleObject> module_object; - CHECK(test.Deserialize(base::VectorOf(url)).ToHandle(&module_object)); + CHECK(test.Deserialize(url).ToHandle(&module_object)); Tagged<String> url_str = Cast<String>(module_object->script()->name()); CHECK_EQ(url, url_str->ToCString().get()); } test.CollectGarbage(); } -TEST(DeserializeMismatchingVersion) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, DeserializeMismatchingVersion) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); test.InvalidateVersion(); CHECK(test.Deserialize().is_null()); } test.CollectGarbage(); } -TEST(DeserializeEmbedderString) { +TEST_F(WasmSerializationTest, DeserializeEmbedderString) { { - WasmSerializationTest test(""); + WasmSerializationTester test(""); { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); ScopedVersionEmbedderString embedder(""); CHECK(!test.Deserialize().is_null()); ScopedVersionEmbedderString mismatching_embedder("-test"); @@ -264,9 +279,9 @@ TEST(DeserializeEmbedderString) { } { - WasmSerializationTest test("-test"); + WasmSerializationTester test("-test"); { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); ScopedVersionEmbedderString embedder("-test"); CHECK(!test.Deserialize().is_null()); ScopedVersionEmbedderString mismatching_embedder("-test.2"); @@ -276,20 +291,20 @@ TEST(DeserializeEmbedderString) { } } -TEST(DeserializeNoSerializedData) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, DeserializeNoSerializedData) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); test.ClearSerializedData(); CHECK(test.Deserialize().is_null()); } test.CollectGarbage(); } -TEST(DeserializeWireBytesAndSerializedDataInvalid) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, DeserializeWireBytesAndSerializedDataInvalid) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); test.InvalidateVersion(); test.InvalidateWireBytes(); CHECK(test.Deserialize().is_null()); @@ -301,39 +316,43 @@ bool False(v8::Local<v8::Context> context, v8::Local<v8::String> source) { return false; } -TEST(BlockWasmCodeGenAtDeserialization) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, BlockWasmCodeGenAtDeserialization) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); - CcTest::isolate()->SetAllowWasmCodeGenerationCallback(False); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); + WasmExecutionTestBase::current_isolate() + ->SetAllowWasmCodeGenerationCallback(False); CHECK(test.Deserialize().is_null()); } test.CollectGarbage(); } -UNINITIALIZED_TEST(CompiledWasmModulesTransfer) { +TEST_F(WasmSerializationUninitializedTest, CompiledWasmModulesTransfer) { v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); ZoneBuffer buffer(&zone); - WasmSerializationTest::BuildWireBytes(&zone, &buffer); + WasmSerializationTester::BuildWireBytes(&zone, &buffer); + std::unique_ptr<v8::ArrayBuffer::Allocator> array_buffer_allocator( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()); v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + create_params.array_buffer_allocator = array_buffer_allocator.get(); v8::Isolate* from_isolate = v8::Isolate::New(create_params); std::vector<v8::CompiledWasmModule> store; CppGCManaged<NativeModule>::Ptr original_native_module; { v8::Isolate::Scope isolate_scope(from_isolate); v8::HandleScope scope(from_isolate); - LocalContext env(from_isolate); + v8::Local<v8::Context> env = v8::Context::New(from_isolate); + v8::Context::Scope context_scope(env); Isolate* from_i_isolate = reinterpret_cast<Isolate*>(from_isolate); ErrorThrower thrower(from_i_isolate, "TestCompiledWasmModulesTransfer"); MaybeDirectHandle<WasmModuleObject> maybe_module_object = GetWasmEngine()->SyncCompile( from_i_isolate, WasmEnabledFeatures::FromIsolate(from_i_isolate), - CompileTimeImports{}, &thrower, base::OwnedCopyOf(buffer)); + CompileTimeImports{}, &thrower, base::UniqueCopyOf(buffer)); DirectHandle<WasmModuleObject> module_object = maybe_module_object.ToHandleChecked(); v8::Local<v8::WasmModuleObject> v8_module = @@ -348,7 +367,8 @@ UNINITIALIZED_TEST(CompiledWasmModulesTransfer) { { v8::Isolate::Scope isolate_scope(to_isolate); v8::HandleScope scope(to_isolate); - LocalContext env(to_isolate); + v8::Local<v8::Context> env = v8::Context::New(to_isolate); + v8::Context::Scope context_scope(env); v8::MaybeLocal<v8::WasmModuleObject> transferred_module = v8::WasmModuleObject::FromCompiledModule(to_isolate, store[0]); @@ -365,10 +385,10 @@ UNINITIALIZED_TEST(CompiledWasmModulesTransfer) { from_isolate->Dispose(); } -TEST(TierDownAfterDeserialization) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, TierDownAfterDeserialization) { + WasmSerializationTester test; - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); HandleScope scope(isolate); DirectHandle<WasmModuleObject> module_object; CHECK(test.Deserialize().ToHandle(&module_object)); @@ -390,24 +410,25 @@ TEST(TierDownAfterDeserialization) { CHECK_NULL(native_module->GetCode(0)); } -TEST(SerializeLiftoffModuleFails) { +TEST_F(WasmSerializationTest, SerializeLiftoffModuleFails) { // Make sure that no function is tiered up to TurboFan. if (!v8_flags.liftoff) return; FlagScope<bool> no_tier_up(&v8_flags.wasm_tier_up, false); v8::internal::AccountingAllocator allocator; Zone zone(&allocator, "test_zone"); - CcTest::InitIsolateOnce(); - Isolate* isolate = CcTest::i_isolate(); + WasmExecutionTestBase::InitIsolateOnce(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); HandleScope scope(isolate); ZoneBuffer wire_bytes_buffer(&zone); - WasmSerializationTest::BuildWireBytes(&zone, &wire_bytes_buffer); + WasmSerializationTester::BuildWireBytes(&zone, &wire_bytes_buffer); ErrorThrower thrower(isolate, "Test"); MaybeDirectHandle<WasmModuleObject> maybe_module_object = - GetWasmEngine()->SyncCompile( - isolate, WasmEnabledFeatures::FromIsolate(isolate), - CompileTimeImports{}, &thrower, base::OwnedCopyOf(wire_bytes_buffer)); + GetWasmEngine()->SyncCompile(isolate, + WasmEnabledFeatures::FromIsolate(isolate), + CompileTimeImports{}, &thrower, + base::UniqueCopyOf(wire_bytes_buffer)); DirectHandle<WasmModuleObject> module_object = maybe_module_object.ToHandleChecked(); @@ -421,10 +442,10 @@ TEST(SerializeLiftoffModuleFails) { CHECK(!wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size})); } -TEST(SerializeTieringBudget) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, SerializeTieringBudget) { + WasmSerializationTester test; - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); v8::OwnedBuffer serialized_bytes; uint32_t mock_budget[3]{1, 2, 3}; { @@ -448,21 +469,16 @@ TEST(SerializeTieringBudget) { // the module gets deserialized and not just loaded from the module cache. native_module->tiering_budget_array()[0]++; } - // We need to invoke GC without stack, otherwise some objects may survive. - DisableConservativeStackScanningScopeForTesting no_stack_scanning( - isolate->heap()); test.CollectGarbage(); HandleScope scope(isolate); DirectHandle<WasmModuleObject> module_object; CompileTimeImports compile_imports = test.MakeCompileTimeImports(); - base::OwnedVector<const uint8_t> wire_bytes_copy = - base::OwnedCopyOf(test.wire_bytes()); - CHECK( - DeserializeNativeModule( - isolate, WasmEnabledFeatures::FromIsolate(isolate), - base::VectorOf(serialized_bytes.buffer.get(), serialized_bytes.size), - wire_bytes_copy, compile_imports, {}) - .ToHandle(&module_object)); + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(test.wire_bytes()); + CHECK(DeserializeNativeModule( + isolate, WasmEnabledFeatures::FromIsolate(isolate), + serialized_bytes.as_span(), wire_bytes_copy, compile_imports, {}) + .ToHandle(&module_object)); CppGCManaged<wasm::NativeModule>::Ptr native_module = module_object->native_module(); @@ -471,10 +487,10 @@ TEST(SerializeTieringBudget) { } } -TEST(SerializationFailsOnChangedFlags) { - WasmSerializationTest test; +TEST_F(WasmSerializationTest, SerializationFailsOnChangedFlags) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); FlagScope<bool> no_bounds_checks(&v8_flags.wasm_bounds_checks, false); CHECK(test.Deserialize().is_null()); @@ -484,22 +500,59 @@ TEST(SerializationFailsOnChangedFlags) { } } -TEST(SerializationFailsOnChangedFeatures) { - WasmSerializationTest test; +namespace { + +// {g_is_trap_handler_enabled} is not a {FlagValue}, so {FlagScope} does not +// apply here. +class V8_NODISCARD TrapHandlerScope { + public: + explicit TrapHandlerScope(bool enabled) + : previous_value_(trap_handler::g_is_trap_handler_enabled) { + trap_handler::g_is_trap_handler_enabled = enabled; + } + ~TrapHandlerScope() { + trap_handler::g_is_trap_handler_enabled = previous_value_; + } + + private: + const bool previous_value_; +}; + +} // namespace + +TEST_F(WasmSerializationTest, SerializationFailsOnChangedTrapHandler) { + // The trap handler can only be enabled once per process, and embedders + // decide whether to enable it independently of the flags. Emulate + // deserializing in a process that decided differently. + if (!V8_TRAP_HANDLER_SUPPORTED) return; + WasmSerializationTester test; + { + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); + + { + TrapHandlerScope flipped(!trap_handler::g_is_trap_handler_enabled); + CHECK(test.Deserialize().is_null()); + } + CHECK(!test.Deserialize().is_null()); + } +} + +TEST_F(WasmSerializationTest, SerializationFailsOnChangedFeatures) { + WasmSerializationTester test; { - HandleScope scope(CcTest::i_isolate()); + HandleScope scope(WasmExecutionTestBase::current_i_isolate()); - CcTest::isolate()->SetWasmCustomDescriptorsEnabledCallback( - [](auto) { return true; }); + WasmExecutionTestBase::current_isolate() + ->SetWasmCustomDescriptorsEnabledCallback([](auto) { return true; }); CHECK(test.Deserialize().is_null()); - CcTest::isolate()->SetWasmCustomDescriptorsEnabledCallback( - [](auto) { return false; }); + WasmExecutionTestBase::current_isolate() + ->SetWasmCustomDescriptorsEnabledCallback([](auto) { return false; }); CHECK(!test.Deserialize().is_null()); } } -TEST(DeserializeIndirectCallWithDifferentCanonicalId) { +TEST_F(WasmSerializationTest, DeserializeIndirectCallWithDifferentCanonicalId) { // This test compiles and serializes a module with an indirect call, then // resets the type canonicalizer, compiles another module, and then // deserializes the original module. This ensures that a different canonical @@ -512,8 +565,8 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { FlagScope<bool> no_lazy_compilation{&v8_flags.wasm_lazy_compilation, false}; FlagScope<bool> expose_gc{&v8_flags.expose_gc, true}; - i::Isolate* i_isolate = CcTest::InitIsolateOnce(); - v8::Isolate* v8_isolate = CcTest::isolate(); + i::Isolate* i_isolate = WasmExecutionTestBase::InitIsolateOnce(); + v8::Isolate* v8_isolate = WasmExecutionTestBase::current_isolate(); v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); HandleScope handle_scope(i_isolate); @@ -538,7 +591,7 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { // if_false: WASM_I32V_1(42)), WASM_END}); - builder.AddExport(base::CStrVector("call_indirect"), f); + builder.AddExport("call_indirect", f); // Add a function table. uint32_t table_id = builder.AddTable(kWasmFuncRef, 1); builder.SetIndirectFunction(table_id, 0, f->func_index()); @@ -566,7 +619,7 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { ->SyncCompile(i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), CompileTimeImports{}, &thrower, - base::OwnedCopyOf(zone_buffer)) + base::UniqueCopyOf(zone_buffer)) .ToHandleChecked(); CppGCManaged<wasm::NativeModule>::Ptr native_module = module_object->native_module(); @@ -596,7 +649,7 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { serialized_module = v8_module_object->GetCompiledModule().Serialize(); } - CHECK_LT(0, serialized_module.size); + CHECK(!serialized_module.empty()); // Run GC until the NativeModule died. Add a manual timeout of 60 seconds to // get a better error message than just a test timeout if this fails. @@ -630,7 +683,8 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { ErrorThrower thrower(i_isolate, ""); GetWasmEngine() ->SyncCompile(i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), - CompileTimeImports{}, &thrower, base::OwnedCopyOf(buffer)) + CompileTimeImports{}, &thrower, + base::UniqueCopyOf(buffer)) .ToHandleChecked(); } @@ -639,18 +693,17 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { canonical_sig_id_before_serialization.index + 1}; { v8::Local<v8::Context> deserialization_context = - v8::Context::New(CcTest::isolate()); + v8::Context::New(WasmExecutionTestBase::current_isolate()); deserialization_context->Enter(); ErrorThrower thrower(i_isolate, ""); - base::Vector<const char> kNoSourceUrl; - base::OwnedVector<const uint8_t> wire_bytes_copy = - base::OwnedCopyOf(zone_buffer); + std::string_view kNoSourceUrl; + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(zone_buffer); DirectHandle<WasmModuleObject> module_object = - DeserializeNativeModule( - i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), - base::VectorOf(serialized_module.buffer.get(), - serialized_module.size), - wire_bytes_copy, CompileTimeImports{}, kNoSourceUrl) + DeserializeNativeModule(i_isolate, + WasmEnabledFeatures::FromIsolate(i_isolate), + serialized_module.as_span(), wire_bytes_copy, + CompileTimeImports{}, kNoSourceUrl) .ToHandleChecked(); // Check that the signature ID got canonicalized to index 1. @@ -688,7 +741,7 @@ TEST(DeserializeIndirectCallWithDifferentCanonicalId) { // Regression test for https://crbug.com/372840600 / // https://crbug.com/369793713 / https://crbug.com/369869947. -TEST(SerializeDetectedFeatures) { +TEST_F(WasmSerializationTest, SerializeDetectedFeatures) { // This test compiles and serializes a module which uses a use-counter-tracked // feature (tail calls). We check that the set of detected features is // preserved across serialization and deserialization. Otherwise we would @@ -697,8 +750,8 @@ TEST(SerializeDetectedFeatures) { FlagScope<int> tier_up_quickly{&v8_flags.wasm_tiering_budget, 10}; FlagScope<bool> expose_gc{&v8_flags.expose_gc, true}; - i::Isolate* i_isolate = CcTest::InitIsolateOnce(); - v8::Isolate* v8_isolate = CcTest::isolate(); + i::Isolate* i_isolate = WasmExecutionTestBase::InitIsolateOnce(); + v8::Isolate* v8_isolate = WasmExecutionTestBase::current_isolate(); v8::internal::AccountingAllocator allocator; Zone zone(&allocator, ZONE_NAME); HandleScope handle_scope(i_isolate); @@ -712,11 +765,11 @@ TEST(SerializeDetectedFeatures) { ModuleTypeIndex sig_i_v = builder.AddSignature(TestSignatures::i_v(), true); WasmFunctionBuilder* a = builder.AddFunction(sig_i_v); a->EmitCode({WASM_I32V_1(11), WASM_END}); - builder.AddExport(base::CStrVector("a"), a); + builder.AddExport("a", a); // Add the function which tail-calls the first one. WasmFunctionBuilder* b = builder.AddFunction(sig_i_v); b->EmitCode({WASM_RETURN_CALL_FUNCTION0(a->func_index()), WASM_END}); - builder.AddExport(base::CStrVector("b"), b); + builder.AddExport("b", b); // Write the final module into {buffer}. builder.WriteTo(&buffer); } @@ -739,7 +792,7 @@ TEST(SerializeDetectedFeatures) { GetWasmEngine() ->SyncCompile( i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), - CompileTimeImports{}, &thrower, base::OwnedCopyOf(buffer)) + CompileTimeImports{}, &thrower, base::UniqueCopyOf(buffer)) .ToHandleChecked(); // Check that "return_call" is in the set of detected features. CHECK_EQ(WasmDetectedFeatures{{WasmDetectedFeature::return_call}}, @@ -766,7 +819,7 @@ TEST(SerializeDetectedFeatures) { testing::CallWasmFunctionForTesting(i_isolate, instance, "a", {}); CHECK_EQ(11, result); serialized_module = v8_module_object->GetCompiledModule().Serialize(); - if (serialized_module.size != 0) break; + if (!serialized_module.empty()) break; v8_isolate->RequestGarbageCollectionForTesting( v8::Isolate::kFullGarbageCollection); if (std::chrono::steady_clock::now() > end_time) { @@ -775,7 +828,7 @@ TEST(SerializeDetectedFeatures) { } } - CHECK_LT(0, serialized_module.size); + CHECK(!serialized_module.empty()); // Run GC until the NativeModule died. Add a manual timeout of 60 seconds to // get a better error message than just a test timeout if this fails. @@ -797,18 +850,17 @@ TEST(SerializeDetectedFeatures) { // Now deserialize the module and check the detected features again. { v8::Local<v8::Context> deserialization_context = - v8::Context::New(CcTest::isolate()); + v8::Context::New(WasmExecutionTestBase::current_isolate()); deserialization_context->Enter(); ErrorThrower thrower(i_isolate, ""); - base::Vector<const char> kNoSourceUrl; - base::OwnedVector<const uint8_t> wire_bytes_copy = - base::OwnedCopyOf(buffer); + std::string_view kNoSourceUrl; + base::UniqueArray<const uint8_t> wire_bytes_copy = + base::UniqueCopyOf(buffer); DirectHandle<WasmModuleObject> module_object = - DeserializeNativeModule( - i_isolate, WasmEnabledFeatures::FromIsolate(i_isolate), - base::VectorOf(serialized_module.buffer.get(), - serialized_module.size), - wire_bytes_copy, CompileTimeImports{}, kNoSourceUrl) + DeserializeNativeModule(i_isolate, + WasmEnabledFeatures::FromIsolate(i_isolate), + serialized_module.as_span(), wire_bytes_copy, + CompileTimeImports{}, kNoSourceUrl) .ToHandleChecked(); CHECK_EQ(WasmDetectedFeatures{{WasmDetectedFeature::return_call}}, diff --git a/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc b/deps/v8/test/unittests/wasm/wasm-shared-engine-unittest.cc similarity index 77% rename from deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc rename to deps/v8/test/unittests/wasm/wasm-shared-engine-unittest.cc index f1e12776bd96..3bd9014c2a54 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-shared-engine.cc +++ b/deps/v8/test/unittests/wasm/wasm-shared-engine-unittest.cc @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <list> #include <memory> -#include "src/base/fpu.h" +#include "src/base/unique-array.h" #include "src/execution/microtask-queue.h" #include "src/objects/objects-inl.h" #include "src/sandbox/sandboxable-thread.h" @@ -13,16 +14,18 @@ #include "src/wasm/wasm-module-builder.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-objects-inl.h" -#include "test/cctest/cctest.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" #include "test/common/wasm/wasm-module-runner.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_wasm_shared_engine { +using WasmSharedEngineTest = WasmUninitializedTestBase; + // Helper type definition representing a WebAssembly module shared between // multiple Isolates with implicit reference counting. using SharedModule = std::shared_ptr<NativeModule>; @@ -30,9 +33,12 @@ using SharedModule = std::shared_ptr<NativeModule>; // Create a new Isolate and a context and enter both. class NewIsolateScope { public: - NewIsolateScope() : isolate_(v8::Isolate::Allocate()) { + NewIsolateScope() + : isolate_(v8::Isolate::Allocate()), + array_buffer_allocator_( + v8::ArrayBuffer::Allocator::NewDefaultAllocator()) { v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + create_params.array_buffer_allocator = array_buffer_allocator_.get(); v8::Isolate::Initialize(isolate_, create_params); v8_isolate()->Enter(); v8::HandleScope handle_scope(v8_isolate()); @@ -59,9 +65,7 @@ class NewIsolateScope { DirectHandle<WasmInstanceObject> ImportInstance(SharedModule shared_module) { DirectHandle<WasmModuleObject> module_object = - GetWasmEngine() - ->ImportNativeModule(isolate(), shared_module, {}) - .ToHandleChecked(); + GetWasmEngine()->ImportNativeModule(isolate(), shared_module, {}); ErrorThrower thrower(isolate(), "ImportInstance"); MaybeDirectHandle<WasmInstanceObject> instance = GetWasmEngine()->SyncInstantiate(isolate(), &thrower, module_object, @@ -79,6 +83,7 @@ class NewIsolateScope { private: v8::Isolate* isolate_; + std::unique_ptr<v8::ArrayBuffer::Allocator> array_buffer_allocator_; std::unique_ptr<Zone> zone_; }; @@ -105,7 +110,7 @@ ZoneBuffer* BuildReturnConstantModule(Zone* zone, int constant) { ZoneBuffer* buffer = zone->New<ZoneBuffer>(zone); WasmModuleBuilder* builder = zone->New<WasmModuleBuilder>(zone); WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v()); - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); f->EmitCode({WASM_I32V_2(constant), WASM_END}); builder->WriteTo(buffer); return buffer; @@ -162,7 +167,7 @@ DirectHandle<WasmInstanceObject> CompileAndInstantiateAsync( GetWasmEngine()->AsyncCompile( isolate->isolate(), enabled_features, CompileTimeImports{}, std::make_unique<MockCompilationResolver>(isolate, &maybe_instance), - base::OwnedCopyOf(*buffer), kAPIMethodName); + base::UniqueCopyOf(*buffer), kAPIMethodName); while (!IsWasmInstanceObject(*maybe_instance)) PumpMessageLoop(isolate); DirectHandle<WasmInstanceObject> instance = Cast<WasmInstanceObject>(maybe_instance); @@ -171,7 +176,7 @@ DirectHandle<WasmInstanceObject> CompileAndInstantiateAsync( } // namespace -TEST(RunSeparated) { +TEST_F(WasmSharedEngineTest, RunSeparated) { { NewIsolateScope isolate; HandleScope scope(isolate.isolate()); @@ -190,7 +195,7 @@ TEST(RunSeparated) { } } -TEST(RunImported) { +TEST_F(WasmSharedEngineTest, RunImported) { SharedModule module; { NewIsolateScope isolate; @@ -209,7 +214,7 @@ TEST(RunImported) { } } -TEST(RunThreadedBuildingSync) { +TEST_F(WasmSharedEngineTest, RunThreadedBuildingSync) { ThreadWithNewIsolate thread1([](NewIsolateScope* isolate) { HandleScope scope(isolate->isolate()); ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 23); @@ -230,7 +235,7 @@ TEST(RunThreadedBuildingSync) { thread2.Join(); } -TEST(RunThreadedBuildingAsync) { +TEST_F(WasmSharedEngineTest, RunThreadedBuildingAsync) { ThreadWithNewIsolate thread1([](NewIsolateScope* isolate) { HandleScope scope(isolate->isolate()); ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 23); @@ -251,7 +256,7 @@ TEST(RunThreadedBuildingAsync) { thread2.Join(); } -TEST(RunThreadedExecution) { +TEST_F(WasmSharedEngineTest, RunThreadedExecution) { SharedModule module; { NewIsolateScope isolate; @@ -277,7 +282,7 @@ TEST(RunThreadedExecution) { thread2.Join(); } -TEST(RunThreadedTierUp) { +TEST_F(WasmSharedEngineTest, RunThreadedTierUp) { SharedModule module; { NewIsolateScope isolate; @@ -313,68 +318,6 @@ TEST(RunThreadedTierUp) { for (auto& thread : threads) thread.Join(); } -TEST(RunImportedWithDenormalsMismatchAndSourceUrl) { - SharedModule module; - bool default_flush = base::FPU::GetFlushDenormals(); - constexpr char kSourceUrl[] = "wasm://test/source_url"; - { - NewIsolateScope isolate; - HandleScope scope(isolate.isolate()); - ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23); - DirectHandle<WasmInstanceObject> instance = - isolate.CompileAndInstantiate(buffer); - module = isolate.ExportInstance(instance); - CHECK_EQ(23, isolate.Run(instance)); - } - std::shared_ptr<NativeModule> recompiled_native_module; - { - base::FlushDenormalsScope flush_denormals_scope(!default_flush); - NewIsolateScope isolate; - HandleScope scope(isolate.isolate()); - - // Call ImportNativeModule directly with a source URL - DirectHandle<WasmModuleObject> module_object = - GetWasmEngine() - ->ImportNativeModule(isolate.isolate(), module, - base::CStrVector(kSourceUrl)) - .ToHandleChecked(); - - // Verify that the import succeeded and we have a WasmModuleObject - CHECK(!module_object.is_null()); - - recompiled_native_module = module_object->native_module().as_shared_ptr(); - // Verify that it's not the same module as the original one. - CHECK_NE(module.get(), recompiled_native_module.get()); - - // Verify that the source URL is preserved - Tagged<Script> script = module_object->script(); - DirectHandle<String> script_name(Cast<String>(script->name()), - isolate.isolate()); - size_t length; - std::unique_ptr<char[]> cstring = script_name->ToCString(&length); - CHECK_EQ(0, strcmp(cstring.get(), kSourceUrl)); - - // Verify that the imported module has the new flags in its NativeModule. - CHECK_EQ(!default_flush, - module_object->native_module()->compile_imports().contains( - CompileTimeImport::kDisableDenormalFloats)); - } - { - base::FlushDenormalsScope flush_denormals_scope(!default_flush); - NewIsolateScope isolate3; - HandleScope scope(isolate3.isolate()); - DirectHandle<WasmModuleObject> module_object3 = - GetWasmEngine() - ->ImportNativeModule(isolate3.isolate(), module, - base::CStrVector(kSourceUrl)) - .ToHandleChecked(); - - // Verify that it reused the NativeModule created by isolate2! - CHECK_EQ(recompiled_native_module.get(), - module_object3->native_module().raw()); - } -} - } // namespace test_wasm_shared_engine } // namespace wasm } // namespace internal diff --git a/deps/v8/test/cctest/wasm/wasm-simd-utils.cc b/deps/v8/test/unittests/wasm/wasm-simd-utils.cc similarity index 99% rename from deps/v8/test/cctest/wasm/wasm-simd-utils.cc rename to deps/v8/test/unittests/wasm/wasm-simd-utils.cc index be42493dbc86..c677e8e47793 100644 --- a/deps/v8/test/cctest/wasm/wasm-simd-utils.cc +++ b/deps/v8/test/unittests/wasm/wasm-simd-utils.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/cctest/wasm/wasm-simd-utils.h" +#include "test/unittests/wasm/wasm-simd-utils.h" #include <cmath> #include <type_traits> @@ -14,10 +14,10 @@ #include "src/wasm/value-type.h" #include "src/wasm/wasm-opcodes-inl.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/c-signature.h" #include "test/common/value-helper.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" #include "third_party/fp16/src/include/fp16.h" namespace v8 { diff --git a/deps/v8/test/cctest/wasm/wasm-simd-utils.h b/deps/v8/test/unittests/wasm/wasm-simd-utils.h similarity index 98% rename from deps/v8/test/cctest/wasm/wasm-simd-utils.h rename to deps/v8/test/unittests/wasm/wasm-simd-utils.h index c025af8afcfd..c79463c7634a 100644 --- a/deps/v8/test/cctest/wasm/wasm-simd-utils.h +++ b/deps/v8/test/unittests/wasm/wasm-simd-utils.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef V8_TEST_CCTEST_WASM_WASM_SIMD_UTILS_H_ -#define V8_TEST_CCTEST_WASM_WASM_SIMD_UTILS_H_ +#ifndef V8_UNITTESTS_WASM_WASM_SIMD_UTILS_H_ +#define V8_UNITTESTS_WASM_WASM_SIMD_UTILS_H_ #include <stddef.h> #include <stdint.h> @@ -13,8 +13,8 @@ #include "src/compiler/opcodes.h" #include "src/wasm/compilation-environment.h" #include "src/wasm/wasm-opcodes.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" #ifdef V8_ENABLE_WASM_SIMD256_REVEC #include "src/compiler/turboshaft/wasm-revec-phase.h" #endif // V8_ENABLE_WASM_SIMD256_REVEC @@ -82,7 +82,7 @@ class TSSimd256VerifyScope { verifier_ = std::make_unique<compiler::turboshaft::WasmRevecVerifier>(handler); - isolate_ = CcTest::InitIsolateOnce(); + isolate_ = wasm::WasmExecutionTestBase::InitIsolateOnce(); DCHECK_EQ(isolate_->wasm_revec_verifier_for_test(), nullptr); isolate_->set_wasm_revec_verifier_for_test(verifier_.get()); } @@ -356,4 +356,4 @@ void RunIntToIntNarrowingRevecTest(WasmOpcode opcode); } // namespace internal } // namespace v8 -#endif // V8_TEST_CCTEST_WASM_WASM_SIMD_UTILS_H_ +#endif // V8_UNITTESTS_WASM_WASM_SIMD_UTILS_H_ diff --git a/deps/v8/test/cctest/wasm/test-wasm-stack.cc b/deps/v8/test/unittests/wasm/wasm-stack-unittest.cc similarity index 96% rename from deps/v8/test/cctest/wasm/test-wasm-stack.cc rename to deps/v8/test/unittests/wasm/wasm-stack-unittest.cc index b663e4f29e22..25d4bf53ccf9 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-stack.cc +++ b/deps/v8/test/unittests/wasm/wasm-stack-unittest.cc @@ -6,11 +6,10 @@ #include "src/api/api-inl.h" #include "src/codegen/assembler-inl.h" #include "src/objects/call-site-info-inl.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { @@ -20,6 +19,9 @@ namespace test_wasm_stack { using v8::Local; using v8::Utils; +using WasmStackTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE WasmStackTest + namespace { #define CHECK_CSTREQ(exp, found) \ @@ -126,7 +128,7 @@ void CheckComputeLocation(v8::internal::Isolate* i_isolate, // Call from JS to wasm to JS and throw an Error from JS. WASM_COMPILED_EXEC_TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) { TestSignatures sigs; - HandleScope scope(CcTest::InitIsolateOnce()); + HandleScope scope(WasmExecutionTestBase::InitIsolateOnce()); const char* source = "(function js() {\n function a() {\n throw new Error(); };\n a(); })"; DirectHandle<JSFunction> js_function = @@ -150,7 +152,7 @@ WASM_COMPILED_EXEC_TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) { v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( CompileRun("(function callFn(fn) { fn(); })")))); - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, v8::StackTrace::kOverview); DirectHandle<Object> global(isolate->context()->global_object(), isolate); @@ -190,7 +192,7 @@ WASM_COMPILED_EXEC_TEST(CollectDetailedWasmStack_WasmUrl) { v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( CompileRun("(function callFn(fn) { fn(); })")))); - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, v8::StackTrace::kOverview); @@ -255,7 +257,7 @@ WASM_COMPILED_EXEC_TEST(CollectDetailedWasmStack_WasmError) { v8::Utils::OpenDirectHandle(*v8::Local<v8::Function>::Cast( CompileRun("(function callFn(fn) { fn(); })")))); - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); isolate->SetCaptureStackTraceForUncaughtExceptions( true, 10, v8::StackTrace::kOverview); DirectHandle<Object> global(isolate->context()->global_object(), isolate); @@ -287,6 +289,8 @@ WASM_COMPILED_EXEC_TEST(CollectDetailedWasmStack_WasmError) { } } +#undef WASM_EXEC_TEST_SUITE + } // namespace test_wasm_stack } // namespace wasm } // namespace internal diff --git a/deps/v8/test/cctest/wasm/test-wasm-strings.cc b/deps/v8/test/unittests/wasm/wasm-strings-unittest.cc similarity index 98% rename from deps/v8/test/cctest/wasm/test-wasm-strings.cc rename to deps/v8/test/unittests/wasm/wasm-strings-unittest.cc index efee2d3ef9d7..071f1b67bc62 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-strings.cc +++ b/deps/v8/test/unittests/wasm/wasm-strings-unittest.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "src/strings/unicode.h" -#include "test/cctest/cctest.h" +#include "test/unittests/test-utils.h" #include "third_party/utf8-decoder/generalized-utf8-decoder.h" #include "third_party/utf8-decoder/utf8-decoder.h" @@ -12,6 +12,8 @@ namespace internal { namespace wasm { namespace test_wasm_strings { +using WasmStringsTest = ::testing::Test; + struct Utf8Decoder { Utf8DfaDecoder::State state = Utf8DfaDecoder::kAccept; uint32_t codepoint = 0; @@ -65,7 +67,7 @@ struct DecodingOracle { } }; -TEST(GeneralizedUTF8Decode) { +TEST_F(WasmStringsTest, GeneralizedUTF8Decode) { // Exhaustive check that the generalized UTF-8 decoder matches the strict // UTF-8 encoder, except for surrogates. Each production should end the // decoders accepting or rejecting the production. diff --git a/deps/v8/test/unittests/wasm/wasm-tracing-unittest.cc b/deps/v8/test/unittests/wasm/wasm-tracing-unittest.cc index f88e6eab4dcc..4facc375735c 100644 --- a/deps/v8/test/unittests/wasm/wasm-tracing-unittest.cc +++ b/deps/v8/test/unittests/wasm/wasm-tracing-unittest.cc @@ -133,7 +133,7 @@ class WasmTracingTest : public TestWithContextAndZone { WasmFunctionBuilder* f = builder.AddFunction(sig); f->AddLocal(ValueType::Primitive(kI32)); - f->builder()->AddExport(base::CStrVector("main"), f); + f->builder()->AddExport("main", f); f->EmitCode(code.data(), static_cast<uint32_t>(code.size())); diff --git a/deps/v8/test/cctest/wasm/test-wasm-trap-position.cc b/deps/v8/test/unittests/wasm/wasm-trap-position-unittest.cc similarity index 94% rename from deps/v8/test/cctest/wasm/test-wasm-trap-position.cc rename to deps/v8/test/unittests/wasm/wasm-trap-position-unittest.cc index 328746a8271a..58a536f2241c 100644 --- a/deps/v8/test/cctest/wasm/test-wasm-trap-position.cc +++ b/deps/v8/test/unittests/wasm/wasm-trap-position-unittest.cc @@ -7,17 +7,19 @@ #include "src/codegen/assembler-inl.h" #include "src/objects/call-site-info-inl.h" #include "src/trap-handler/trap-handler.h" -#include "test/cctest/cctest.h" -#include "test/cctest/wasm/wasm-runner.h" #include "test/common/value-helper.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" +#include "test/unittests/wasm/wasm-runner.h" namespace v8 { namespace internal { namespace wasm { namespace test_wasm_trap_position { +using WasmTrapPositionTest = WasmExecutionTestBase; +#define WASM_EXEC_TEST_SUITE WasmTrapPositionTest + using v8::Local; using v8::Utils; @@ -80,7 +82,7 @@ WASM_COMPILED_EXEC_TEST(Unreachable) { Cast<JSFunction>(v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( CompileRun("(function callFn(fn) { fn(); })")))); - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, v8::StackTrace::kOverview); DirectHandle<Object> global(isolate->context()->global_object(), isolate); @@ -121,7 +123,7 @@ WASM_COMPILED_EXEC_TEST(IllegalLoad) { Cast<JSFunction>(v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( CompileRun("(function callFn(fn) { fn(); })")))); - Isolate* isolate = CcTest::i_isolate(); + Isolate* isolate = WasmExecutionTestBase::current_i_isolate(); isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10, v8::StackTrace::kOverview); DirectHandle<Object> global(isolate->context()->global_object(), isolate); @@ -141,6 +143,8 @@ WASM_COMPILED_EXEC_TEST(IllegalLoad) { expected_exceptions); } +#undef WASM_EXEC_TEST_SUITE + } // namespace test_wasm_trap_position } // namespace wasm } // namespace internal diff --git a/deps/v8/test/unittests/wasm/wasm-usecounters.cc b/deps/v8/test/unittests/wasm/wasm-usecounters.cc index afc750ac72b5..e15120d6b8b5 100644 --- a/deps/v8/test/unittests/wasm/wasm-usecounters.cc +++ b/deps/v8/test/unittests/wasm/wasm-usecounters.cc @@ -6,6 +6,7 @@ #include "include/v8-isolate.h" #include "src/base/logging.h" +#include "src/base/unique-array.h" #include "src/wasm/wasm-module-builder.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" @@ -44,15 +45,14 @@ class WasmUseCounterTest } void Compile() { - base::OwnedVector<const uint8_t> bytes = base::OwnedCopyOf(buffer_); + base::UniqueArray<const uint8_t> bytes = base::UniqueCopyOf(buffer_); switch (GetParam()) { case kSync: return WasmCompileHelper::SyncCompile(isolate(), std::move(bytes)); case kAsync: return WasmCompileHelper::AsyncCompile(isolate(), std::move(bytes)); case kStreaming: - return WasmCompileHelper::StreamingCompile(isolate(), - bytes.as_vector()); + return WasmCompileHelper::StreamingCompile(isolate(), bytes.as_span()); } } diff --git a/deps/v8/test/unittests/zone/zone-chunk-list-unittest.cc b/deps/v8/test/unittests/zone/zone-chunk-list-unittest.cc deleted file mode 100644 index f550c5c6a1e6..000000000000 --- a/deps/v8/test/unittests/zone/zone-chunk-list-unittest.cc +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright 2016 the V8 project 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 "src/zone/zone-chunk-list.h" - -#include "src/base/iterator.h" -#include "src/zone/accounting-allocator.h" -#include "src/zone/zone.h" -#include "test/unittests/test-utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace v8 { -namespace internal { - -const size_t kItemCount = size_t(1) << 10; - -class ZoneChunkListTest : public TestWithPlatform {}; - -TEST_F(ZoneChunkListTest, ForwardIterationTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - EXPECT_EQ(zone_chunk_list.begin(), zone_chunk_list.end()); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - EXPECT_NE(zone_chunk_list.begin(), zone_chunk_list.end()); - - size_t count = 0; - - for (uintptr_t item : zone_chunk_list) { - EXPECT_EQ(static_cast<size_t>(item), count); - count++; - } - - EXPECT_EQ(count, kItemCount); -} - -TEST_F(ZoneChunkListTest, ReverseIterationTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - EXPECT_EQ(zone_chunk_list.rbegin(), zone_chunk_list.rend()); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - EXPECT_NE(zone_chunk_list.rbegin(), zone_chunk_list.rend()); - - size_t count = 0; - - for (uintptr_t item : base::Reversed(zone_chunk_list)) { - EXPECT_EQ(static_cast<size_t>(item), kItemCount - count - 1); - count++; - } - - EXPECT_EQ(count, kItemCount); -} - -TEST_F(ZoneChunkListTest, PushFrontTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_front(static_cast<uintptr_t>(i)); - } - - size_t count = 0; - - for (uintptr_t item : zone_chunk_list) { - EXPECT_EQ(static_cast<size_t>(item), kItemCount - count - 1); - count++; - } - - EXPECT_EQ(count, kItemCount); -} - -TEST_F(ZoneChunkListTest, RewindTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - zone_chunk_list.Rewind(42); - - size_t count = 0; - - for (uintptr_t item : zone_chunk_list) { - EXPECT_EQ(static_cast<size_t>(item), count); - count++; - } - - EXPECT_EQ(count, 42u); - EXPECT_EQ(count, zone_chunk_list.size()); - - zone_chunk_list.Rewind(0); - - count = 0; - - for (uintptr_t item : zone_chunk_list) { - USE(item); - count++; - } - - EXPECT_EQ(count, 0u); - EXPECT_EQ(count, zone_chunk_list.size()); - - zone_chunk_list.Rewind(100); - - count = 0; - - for (uintptr_t item : zone_chunk_list) { - EXPECT_EQ(static_cast<size_t>(item), count); - count++; - } - - EXPECT_EQ(count, 0u); - EXPECT_EQ(count, zone_chunk_list.size()); -} - -TEST_F(ZoneChunkListTest, FindTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - const size_t index = kItemCount / 2 + 42; - - EXPECT_EQ(*zone_chunk_list.Find(index), static_cast<uintptr_t>(index)); - - *zone_chunk_list.Find(index) = 42; - - EXPECT_EQ(*zone_chunk_list.Find(index), 42u); -} - -TEST_F(ZoneChunkListTest, CopyToTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - uintptr_t* array = zone.AllocateArray<uintptr_t>(kItemCount); - - zone_chunk_list.CopyTo(array); - - for (size_t i = 0; i < kItemCount; ++i) { - EXPECT_EQ(array[i], static_cast<uintptr_t>(i)); - } -} - -TEST_F(ZoneChunkListTest, SmallCopyToTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uint8_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uint8_t>(i & 0xFF)); - } - - uint8_t* array = zone.AllocateArray<uint8_t>(kItemCount); - - zone_chunk_list.CopyTo(array); - - for (size_t i = 0; i < kItemCount; ++i) { - EXPECT_EQ(array[i], static_cast<uint8_t>(i & 0xFF)); - } -} - -struct Fubar { - size_t a_; - size_t b_; -}; - -TEST_F(ZoneChunkListTest, BigCopyToTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<Fubar> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back({i, i + 5}); - } - - Fubar* array = zone.AllocateArray<Fubar>(kItemCount); - - zone_chunk_list.CopyTo(array); - - for (size_t i = 0; i < kItemCount; ++i) { - EXPECT_EQ(array[i].a_, i); - EXPECT_EQ(array[i].b_, i + 5); - } -} - -void TestForwardIterationOfConstList( - const ZoneChunkList<uintptr_t>& zone_chunk_list) { - size_t count = 0; - - for (uintptr_t item : zone_chunk_list) { - EXPECT_EQ(static_cast<size_t>(item), count); - count++; - } - - EXPECT_EQ(count, kItemCount); -} - -TEST_F(ZoneChunkListTest, ConstForwardIterationTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - TestForwardIterationOfConstList(zone_chunk_list); -} - -TEST_F(ZoneChunkListTest, RewindAndIterate) { - // Regression test for https://bugs.chromium.org/p/v8/issues/detail?id=7478 - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<int> zone_chunk_list(&zone); - - // Fill the list enough so that it will contain 2 chunks. - int chunk_size = static_cast<int>(ZoneChunkList<int>::kInitialChunkCapacity); - for (int i = 0; i < chunk_size + 1; ++i) { - zone_chunk_list.push_back(i); - } - - // Rewind and fill the first chunk again. - zone_chunk_list.Rewind(); - for (int i = 0; i < chunk_size; ++i) { - zone_chunk_list.push_back(i); - } - - std::vector<int> expected; - for (int i = 0; i < chunk_size; ++i) { - expected.push_back(i); - } - std::vector<int> got; - - // Iterate. This used to not yield the expected result, since the end iterator - // was in a weird state, and the running iterator didn't reach it after the - // first chunk. - auto it = zone_chunk_list.begin(); - while (it != zone_chunk_list.end()) { - int value = *it; - got.push_back(value); - ++it; - } - CHECK_EQ(expected.size(), got.size()); - for (size_t i = 0; i < expected.size(); ++i) { - CHECK_EQ(expected[i], got[i]); - } -} - -TEST_F(ZoneChunkListTest, AdvanceZeroTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - auto iterator_advance = zone_chunk_list.begin(); - - iterator_advance.Advance(0); - - CHECK_EQ(iterator_advance, zone_chunk_list.begin()); -} - -TEST_F(ZoneChunkListTest, AdvancePartwayTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - auto iterator_advance = zone_chunk_list.begin(); - auto iterator_one_by_one = zone_chunk_list.begin(); - - iterator_advance.Advance(kItemCount / 2); - for (size_t i = 0; i < kItemCount / 2; ++i) { - ++iterator_one_by_one; - } - - CHECK_EQ(iterator_advance, iterator_one_by_one); -} - -TEST_F(ZoneChunkListTest, AdvanceEndTest) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<uintptr_t> zone_chunk_list(&zone); - - for (size_t i = 0; i < kItemCount; ++i) { - zone_chunk_list.push_back(static_cast<uintptr_t>(i)); - } - - auto iterator_advance = zone_chunk_list.begin(); - - iterator_advance.Advance(kItemCount); - - CHECK_EQ(iterator_advance, zone_chunk_list.end()); -} - -TEST_F(ZoneChunkListTest, FindOverChunkBoundary) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<int> zone_chunk_list(&zone); - - // Make sure we get two chunks. - int chunk_size = static_cast<int>(ZoneChunkList<int>::kInitialChunkCapacity); - for (int i = 0; i < chunk_size + 1; ++i) { - zone_chunk_list.push_back(i); - } - - for (int i = 0; i < chunk_size + 1; ++i) { - CHECK_EQ(i, *zone_chunk_list.Find(i)); - } -} - -TEST_F(ZoneChunkListTest, SplitAt) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<size_t> zone_chunk_list(&zone); - - // Make sure we get two chunks. - for (size_t i = 0; i < kItemCount + 1; ++i) { - zone_chunk_list.push_back(i); - } - - ZoneChunkList<size_t> split_end = - zone_chunk_list.SplitAt(zone_chunk_list.end()); - - CHECK(split_end.empty()); - size_t count = 0; - for (size_t item : zone_chunk_list) { - CHECK_EQ(item, count); - count++; - } - CHECK_EQ(count, kItemCount + 1); - - ZoneChunkList<size_t> split_begin = - zone_chunk_list.SplitAt(zone_chunk_list.begin()); - - CHECK(zone_chunk_list.empty()); - count = 0; - for (size_t item : split_begin) { - CHECK_EQ(item, count); - count++; - } - CHECK_EQ(count, kItemCount + 1); - - size_t mid = kItemCount / 2 + 42; - ZoneChunkList<size_t> split_mid = split_begin.SplitAt(split_begin.Find(mid)); - - count = 0; - for (size_t item : split_begin) { - CHECK_EQ(item, count); - count++; - } - CHECK_EQ(count, kItemCount / 2 + 42); - for (size_t item : split_mid) { - CHECK_EQ(item, count); - count++; - } - CHECK_EQ(count, kItemCount + 1); -} - -TEST_F(ZoneChunkListTest, SplitAtLastChunk) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<size_t> zone_chunk_list(&zone); - zone_chunk_list.push_back(0); - zone_chunk_list.push_back(1); - - ZoneChunkList<size_t> split_last = - zone_chunk_list.SplitAt(++zone_chunk_list.begin()); - CHECK_EQ(zone_chunk_list.size(), 1); - CHECK_EQ(zone_chunk_list.front(), 0); - CHECK_EQ(split_last.size(), 1); - CHECK_EQ(split_last.front(), 1); -} - -TEST_F(ZoneChunkListTest, Append) { - AccountingAllocator allocator; - Zone zone(&allocator, ZONE_NAME); - - ZoneChunkList<size_t> zone_chunk_list(&zone); - zone_chunk_list.push_back(0); - - ZoneChunkList<size_t> other(&zone); - other.push_back(1); - - zone_chunk_list.Append(other); - - size_t count = 0; - for (size_t item : zone_chunk_list) { - CHECK_EQ(item, count++); - } - CHECK_EQ(count, zone_chunk_list.size()); - CHECK(other.empty()); -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/wasm-api-tests/callbacks.cc b/deps/v8/test/wasm-api-tests/callbacks.cc index 92604dfbf1ec..a52c42cb7544 100644 --- a/deps/v8/test/wasm-api-tests/callbacks.cc +++ b/deps/v8/test/wasm-api-tests/callbacks.cc @@ -40,16 +40,15 @@ class WasmCapiCallbacksTest : public WasmCapiTest { WasmCapiCallbacksTest() : WasmCapiTest() { // Build the following function: // int32 stage1(int32 arg0) { return stage2(arg0); } - uint32_t stage2_index = - builder()->AddImport(base::CStrVector("stage2"), wasm_i_i_sig()); + uint32_t stage2_index = builder()->AddImport("stage2", wasm_i_i_sig()); uint8_t code[] = {WASM_CALL_FUNCTION(stage2_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("stage1"), code, sizeof(code)); + AddExportedFunction("stage1", code, sizeof(code)); stage2_ = Func::make(store(), cpp_i_i_sig(), Stage2, this); } Func* stage2() { return stage2_.get(); } - void AddExportedFunction(base::Vector<const char> name, uint8_t code[], + void AddExportedFunction(std::string_view name, uint8_t code[], size_t code_size) { WasmCapiTest::AddExportedFunction(name, code, code_size, wasm_i_i_sig()); } @@ -64,7 +63,7 @@ TEST_F(WasmCapiCallbacksTest, Trap) { // Build the following function: // int32 stage3_trap(int32 arg0) { unreachable(); } uint8_t code[] = {WASM_UNREACHABLE}; - AddExportedFunction(base::CStrVector("stage3_trap"), code, sizeof(code)); + AddExportedFunction("stage3_trap", code, sizeof(code)); vec<Extern*> imports = vec<Extern*>::make(stage2()); Instantiate(imports); @@ -78,10 +77,9 @@ TEST_F(WasmCapiCallbacksTest, Trap) { TEST_F(WasmCapiCallbacksTest, GC) { // Build the following function: // int32 stage3_to4(int32 arg0) { return stage4(arg0); } - uint32_t stage4_index = - builder()->AddImport(base::CStrVector("stage4"), wasm_i_i_sig()); + uint32_t stage4_index = builder()->AddImport("stage4", wasm_i_i_sig()); uint8_t code[] = {WASM_CALL_FUNCTION(stage4_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("stage3_to4"), code, sizeof(code)); + AddExportedFunction("stage3_to4", code, sizeof(code)); i::Isolate* isolate = reinterpret_cast<::wasm::StoreImpl*>(store())->i_isolate(); @@ -131,8 +129,7 @@ TEST_F(WasmCapiTest, Recursion) { // if (arg0 == 1) return 1; // return fibonacci_c(arg0 - 1) + fibonacci_c(arg0 - 2); // } - uint32_t fibo_c_index = - builder()->AddImport(base::CStrVector("fibonacci_c"), wasm_i_i_sig()); + uint32_t fibo_c_index = builder()->AddImport("fibonacci_c", wasm_i_i_sig()); uint8_t code_fibo[] = { WASM_IF(WASM_I32_EQ(WASM_LOCAL_GET(0), WASM_ZERO), WASM_RETURN(WASM_ZERO)), @@ -143,8 +140,8 @@ TEST_F(WasmCapiTest, Recursion) { WASM_CALL_FUNCTION(fibo_c_index, WASM_LOCAL_GET(0)), WASM_CALL_FUNCTION(fibo_c_index, WASM_I32_SUB(WASM_LOCAL_GET(0), WASM_ONE))))}; - AddExportedFunction(base::CStrVector("fibonacci_wasm"), code_fibo, - sizeof(code_fibo), wasm_i_i_sig()); + AddExportedFunction("fibonacci_wasm", code_fibo, sizeof(code_fibo), + wasm_i_i_sig()); own<Func> fibonacci = Func::make(store(), cpp_i_i_sig(), FibonacciC, this); vec<Extern*> imports = vec<Extern*>::make(fibonacci.get()); @@ -222,8 +219,8 @@ TEST_F(WasmCapiTest, DirectCallCapiFunction) { kWasmExternRef, kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmExternRef}; FunctionSig wasm_sig(5, 5, wasm_types); - int func_index = builder()->AddImport(base::CStrVector("func"), &wasm_sig); - builder()->ExportImportedFunction(base::CStrVector("func"), func_index); + int func_index = builder()->AddImport("func", &wasm_sig); + builder()->ExportImportedFunction("func", func_index); Instantiate(imports); int32_t a0 = 42; int64_t a1 = 0x1234c0ffee; @@ -292,8 +289,8 @@ TEST_F(WasmCapiTest, DirectCallCapiFunctionWithManyArgs) { kWasmExternRef, kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmI32}; FunctionSig wasm_sig(14, 14, wasm_types); - int func_index = builder()->AddImport(base::CStrVector("func"), &wasm_sig); - builder()->ExportImportedFunction(base::CStrVector("func"), func_index); + int func_index = builder()->AddImport("func", &wasm_sig); + builder()->ExportImportedFunction("func", func_index); Instantiate(imports); int32_t a0 = 42; int64_t a1 = 0x1234c0ffee; diff --git a/deps/v8/test/wasm-api-tests/finalize.cc b/deps/v8/test/wasm-api-tests/finalize.cc index 5fcd78bc0f60..9db1dc64de34 100644 --- a/deps/v8/test/wasm-api-tests/finalize.cc +++ b/deps/v8/test/wasm-api-tests/finalize.cc @@ -69,8 +69,7 @@ void RunInStore(Store* store, base::Vector<const uint8_t> wire_bytes, TEST_F(WasmCapiTest, InstanceFinalization) { // Add a dummy function: f(x) { return x; } uint8_t code[] = {WASM_RETURN(WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("f"), code, sizeof(code), - wasm_i_i_sig()); + AddExportedFunction("f", code, sizeof(code), wasm_i_i_sig()); Compile(); g_instances_finalized = 0; g_functions_finalized = 0; @@ -121,9 +120,8 @@ void FinalizeHostData(void* data) { } // namespace TEST_F(WasmCapiTest, CapiFunctionLifetimes) { - uint32_t func_index = - builder()->AddImport(base::CStrVector("f"), wasm_i_i_sig()); - builder()->ExportImportedFunction(base::CStrVector("f"), func_index); + uint32_t func_index = builder()->AddImport("f", wasm_i_i_sig()); + builder()->ExportImportedFunction("f", func_index); Compile(); own<Instance> instance; void* kHostData = reinterpret_cast<void*>(1234); diff --git a/deps/v8/test/wasm-api-tests/globals.cc b/deps/v8/test/wasm-api-tests/globals.cc index fa0ef535200d..3a1fa34b51e3 100644 --- a/deps/v8/test/wasm-api-tests/globals.cc +++ b/deps/v8/test/wasm-api-tests/globals.cc @@ -15,32 +15,30 @@ TEST_F(WasmCapiTest, Globals) { const bool kImmutable = false; // Define imported and exported globals in the module. - const uint32_t cfi_index = builder()->AddGlobalImport( - base::CStrVector("const f32"), kWasmF32, kImmutable); - const uint32_t cii_index = builder()->AddGlobalImport( - base::CStrVector("const i64"), kWasmI64, kImmutable); - const uint32_t vfi_index = builder()->AddGlobalImport( - base::CStrVector("var f32"), kWasmF32, kMutable); - const uint32_t vii_index = builder()->AddGlobalImport( - base::CStrVector("var i64"), kWasmI64, kMutable); + const uint32_t cfi_index = + builder()->AddGlobalImport("const f32", kWasmF32, kImmutable); + const uint32_t cii_index = + builder()->AddGlobalImport("const i64", kWasmI64, kImmutable); + const uint32_t vfi_index = + builder()->AddGlobalImport("var f32", kWasmF32, kMutable); + const uint32_t vii_index = + builder()->AddGlobalImport("var i64", kWasmI64, kMutable); const int kNumImported = 4; const uint32_t cfe_index = - kNumImported + - builder()->AddExportedGlobal(kWasmF32, kImmutable, WasmInitExpr(5.f), - base::CStrVector("const f32")); - const uint32_t cie_index = kNumImported + builder()->AddExportedGlobal( - kWasmI64, kImmutable, WasmInitExpr(int64_t{6}), - base::CStrVector("const i64")); + kWasmF32, kImmutable, WasmInitExpr(5.f), "const f32"); + const uint32_t cie_index = + kNumImported + builder()->AddExportedGlobal(kWasmI64, kImmutable, + WasmInitExpr(int64_t{6}), + "const i64"); const uint32_t vfe_index = kNumImported + builder()->AddExportedGlobal(kWasmF32, kMutable, - WasmInitExpr(7.f), - base::CStrVector("var f32")); + WasmInitExpr(7.f), "var f32"); const uint32_t vie_index = kNumImported + builder()->AddExportedGlobal(kWasmI64, kMutable, WasmInitExpr(int64_t{8}), - base::CStrVector("var i64")); + "var i64"); // Define functions for inspecting globals. ValueType f32_type[] = {kWasmF32}; @@ -48,46 +46,34 @@ TEST_F(WasmCapiTest, Globals) { FunctionSig return_f32(1, 0, f32_type); FunctionSig return_i64(1, 0, i64_type); uint8_t gcfi[] = {WASM_GLOBAL_GET(cfi_index)}; - AddExportedFunction(base::CStrVector("get const f32 import"), gcfi, - sizeof(gcfi), &return_f32); + AddExportedFunction("get const f32 import", gcfi, sizeof(gcfi), &return_f32); uint8_t gcii[] = {WASM_GLOBAL_GET(cii_index)}; - AddExportedFunction(base::CStrVector("get const i64 import"), gcii, - sizeof(gcii), &return_i64); + AddExportedFunction("get const i64 import", gcii, sizeof(gcii), &return_i64); uint8_t gvfi[] = {WASM_GLOBAL_GET(vfi_index)}; - AddExportedFunction(base::CStrVector("get var f32 import"), gvfi, - sizeof(gvfi), &return_f32); + AddExportedFunction("get var f32 import", gvfi, sizeof(gvfi), &return_f32); uint8_t gvii[] = {WASM_GLOBAL_GET(vii_index)}; - AddExportedFunction(base::CStrVector("get var i64 import"), gvii, - sizeof(gvii), &return_i64); + AddExportedFunction("get var i64 import", gvii, sizeof(gvii), &return_i64); uint8_t gcfe[] = {WASM_GLOBAL_GET(cfe_index)}; - AddExportedFunction(base::CStrVector("get const f32 export"), gcfe, - sizeof(gcfe), &return_f32); + AddExportedFunction("get const f32 export", gcfe, sizeof(gcfe), &return_f32); uint8_t gcie[] = {WASM_GLOBAL_GET(cie_index)}; - AddExportedFunction(base::CStrVector("get const i64 export"), gcie, - sizeof(gcie), &return_i64); + AddExportedFunction("get const i64 export", gcie, sizeof(gcie), &return_i64); uint8_t gvfe[] = {WASM_GLOBAL_GET(vfe_index)}; - AddExportedFunction(base::CStrVector("get var f32 export"), gvfe, - sizeof(gvfe), &return_f32); + AddExportedFunction("get var f32 export", gvfe, sizeof(gvfe), &return_f32); uint8_t gvie[] = {WASM_GLOBAL_GET(vie_index)}; - AddExportedFunction(base::CStrVector("get var i64 export"), gvie, - sizeof(gvie), &return_i64); + AddExportedFunction("get var i64 export", gvie, sizeof(gvie), &return_i64); // Define functions for manipulating globals. FunctionSig param_f32(0, 1, f32_type); FunctionSig param_i64(0, 1, i64_type); uint8_t svfi[] = {WASM_GLOBAL_SET(vfi_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("set var f32 import"), svfi, - sizeof(svfi), ¶m_f32); + AddExportedFunction("set var f32 import", svfi, sizeof(svfi), ¶m_f32); uint8_t svii[] = {WASM_GLOBAL_SET(vii_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("set var i64 import"), svii, - sizeof(svii), ¶m_i64); + AddExportedFunction("set var i64 import", svii, sizeof(svii), ¶m_i64); uint8_t svfe[] = {WASM_GLOBAL_SET(vfe_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("set var f32 export"), svfe, - sizeof(svfe), ¶m_f32); + AddExportedFunction("set var f32 export", svfe, sizeof(svfe), ¶m_f32); uint8_t svie[] = {WASM_GLOBAL_SET(vie_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("set var i64 export"), svie, - sizeof(svie), ¶m_i64); + AddExportedFunction("set var i64 export", svie, sizeof(svie), ¶m_i64); // Create imported globals. own<GlobalType> const_f32_type = GlobalType::make( diff --git a/deps/v8/test/wasm-api-tests/hostref.cc b/deps/v8/test/wasm-api-tests/hostref.cc index dacd4b9d1cbe..6fbd4a4fcead 100644 --- a/deps/v8/test/wasm-api-tests/hostref.cc +++ b/deps/v8/test/wasm-api-tests/hostref.cc @@ -32,31 +32,31 @@ TEST_F(WasmCapiTest, HostRef) { FunctionSig r_v_sig(1, 0, rr_reps); FunctionSig v_ir_sig(0, 2, ir_reps); FunctionSig r_i_sig(1, 1, ri_reps); - uint32_t func_index = builder()->AddImport(base::CStrVector("f"), &r_r_sig); + uint32_t func_index = builder()->AddImport("f", &r_r_sig); const bool kMutable = true; uint32_t global_index = builder()->AddExportedGlobal( kWasmExternRef, kMutable, WasmInitExpr::RefNullConst(kWasmExternRef), - base::CStrVector("global")); + "global"); uint32_t table_index = builder()->AddTable(kWasmExternRef, 10); - builder()->AddExport(base::CStrVector("table"), kExternalTable, table_index); + builder()->AddExport("table", kExternalTable, table_index); uint8_t global_set_code[] = { WASM_GLOBAL_SET(global_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("global.set"), global_set_code, - sizeof(global_set_code), &v_r_sig); + AddExportedFunction("global.set", global_set_code, sizeof(global_set_code), + &v_r_sig); uint8_t global_get_code[] = {WASM_GLOBAL_GET(global_index)}; - AddExportedFunction(base::CStrVector("global.get"), global_get_code, - sizeof(global_get_code), &r_v_sig); + AddExportedFunction("global.get", global_get_code, sizeof(global_get_code), + &r_v_sig); uint8_t table_set_code[] = { WASM_TABLE_SET(table_index, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}; - AddExportedFunction(base::CStrVector("table.set"), table_set_code, - sizeof(table_set_code), &v_ir_sig); + AddExportedFunction("table.set", table_set_code, sizeof(table_set_code), + &v_ir_sig); uint8_t table_get_code[] = {WASM_TABLE_GET(table_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("table.get"), table_get_code, - sizeof(table_get_code), &r_i_sig); + AddExportedFunction("table.get", table_get_code, sizeof(table_get_code), + &r_i_sig); uint8_t func_call_code[] = { WASM_CALL_FUNCTION(func_index, WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("func.call"), func_call_code, - sizeof(func_call_code), &r_r_sig); + AddExportedFunction("func.call", func_call_code, sizeof(func_call_code), + &r_r_sig); own<FuncType> func_type = FuncType::make( ownvec<ValType>::make(ValType::make(::wasm::ValKind::EXTERNREF)), diff --git a/deps/v8/test/wasm-api-tests/memory.cc b/deps/v8/test/wasm-api-tests/memory.cc index 603ea4677810..f59f70c97f0f 100644 --- a/deps/v8/test/wasm-api-tests/memory.cc +++ b/deps/v8/test/wasm-api-tests/memory.cc @@ -13,22 +13,20 @@ using ::wasm::MemoryType; TEST_F(WasmCapiTest, Memory) { builder()->AddMemory(2, 3); - builder()->AddExport(base::CStrVector("memory"), kExternalMemory, 0); + builder()->AddExport("memory", kExternalMemory, 0); ValueType i32_type[] = {kWasmI32, kWasmI32}; FunctionSig return_i32(1, 0, i32_type); FunctionSig param_i32_return_i32(1, 1, i32_type); FunctionSig param_i32_i32(0, 2, i32_type); uint8_t size_code[] = {WASM_MEMORY_SIZE}; - AddExportedFunction(base::CStrVector("size"), size_code, sizeof(size_code), - &return_i32); + AddExportedFunction("size", size_code, sizeof(size_code), &return_i32); uint8_t load_code[] = {WASM_LOAD_MEM(MachineType::Int8(), WASM_LOCAL_GET(0))}; - AddExportedFunction(base::CStrVector("load"), load_code, sizeof(load_code), + AddExportedFunction("load", load_code, sizeof(load_code), ¶m_i32_return_i32); uint8_t store_code[] = {WASM_STORE_MEM(MachineType::Int8(), WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}; - AddExportedFunction(base::CStrVector("store"), store_code, sizeof(store_code), - ¶m_i32_i32); + AddExportedFunction("store", store_code, sizeof(store_code), ¶m_i32_i32); uint8_t data[] = {0x1, 0x2, 0x3, 0x4}; builder()->AddDataSegment(data, sizeof(data), 0x1000); diff --git a/deps/v8/test/wasm-api-tests/multi-return.cc b/deps/v8/test/wasm-api-tests/multi-return.cc index 6a6a96655546..6c8e9e02eeea 100644 --- a/deps/v8/test/wasm-api-tests/multi-return.cc +++ b/deps/v8/test/wasm-api-tests/multi-return.cc @@ -27,11 +27,11 @@ TEST_F(WasmCapiTest, MultiReturn) { ValueType reps[] = {kWasmI32, kWasmI64, kWasmI64, kWasmI32, kWasmI32, kWasmI64, kWasmI64, kWasmI32}; FunctionSig sig(4, 4, reps); - uint32_t func_index = builder()->AddImport(base::CStrVector("f"), &sig); + uint32_t func_index = builder()->AddImport("f", &sig); uint8_t code[] = {WASM_CALL_FUNCTION(func_index, WASM_LOCAL_GET(0), WASM_LOCAL_GET(2), WASM_LOCAL_GET(1), WASM_LOCAL_GET(3))}; - AddExportedFunction(base::CStrVector("g"), code, sizeof(code), &sig); + AddExportedFunction("g", code, sizeof(code), &sig); ownvec<ValType> types = ownvec<ValType>::make(ValType::make(I32), ValType::make(I64), diff --git a/deps/v8/test/wasm-api-tests/reflect.cc b/deps/v8/test/wasm-api-tests/reflect.cc index dc5b7e3db95d..0e3ddc87a3c6 100644 --- a/deps/v8/test/wasm-api-tests/reflect.cc +++ b/deps/v8/test/wasm-api-tests/reflect.cc @@ -39,16 +39,15 @@ TEST_F(WasmCapiTest, Reflect) { ValueType types[] = {kWasmI32, kWasmExternRef, kWasmI32, kWasmI64, kWasmF32, kWasmF64}; FunctionSig sig(2, 4, types); - AddExportedFunction(base::CStrVector(kFuncName), code, sizeof(code), &sig); + AddExportedFunction(kFuncName, code, sizeof(code), &sig); - builder()->AddExportedGlobal(kWasmF64, false, WasmInitExpr(0.0), - base::CStrVector(kGlobalName)); + builder()->AddExportedGlobal(kWasmF64, false, WasmInitExpr(0.0), kGlobalName); builder()->AddTable(kWasmFuncRef, 12, 12); - builder()->AddExport(base::CStrVector(kTableName), kExternalTable, 0); + builder()->AddExport(kTableName, kExternalTable, 0); builder()->AddMemory(1); - builder()->AddExport(base::CStrVector(kMemoryName), kExternalMemory, 0); + builder()->AddExport(kMemoryName, kExternalMemory, 0); vec<Extern*> imports = vec<Extern*>::make_uninitialized(); Instantiate(imports); diff --git a/deps/v8/test/wasm-api-tests/regressions.cc b/deps/v8/test/wasm-api-tests/regressions.cc index b5892860c47f..66f5e8623063 100644 --- a/deps/v8/test/wasm-api-tests/regressions.cc +++ b/deps/v8/test/wasm-api-tests/regressions.cc @@ -13,7 +13,7 @@ TEST_F(WasmCapiTest, Regressions) { WasmFunctionBuilder* start_func = builder()->AddFunction(&sig); start_func->EmitCode({WASM_UNREACHABLE, WASM_END}); builder()->MarkStartFunction(start_func); - builder()->AddImport(base::CStrVector("dummy"), &sig); + builder()->AddImport("dummy", &sig); // Ensure we can validate. bool valid = Validate(); diff --git a/deps/v8/test/wasm-api-tests/serialize.cc b/deps/v8/test/wasm-api-tests/serialize.cc index 2fdd2c17fba3..0c2762a987b3 100644 --- a/deps/v8/test/wasm-api-tests/serialize.cc +++ b/deps/v8/test/wasm-api-tests/serialize.cc @@ -24,10 +24,9 @@ own<Trap> Callback(const vec<Val>& args, vec<Val>& results) { TEST_F(WasmCapiTest, Serialize) { FunctionSig sig(0, 0, nullptr); - uint32_t callback_index = - builder()->AddImport(base::CStrVector("callback"), &sig); + uint32_t callback_index = builder()->AddImport("callback", &sig); uint8_t code[] = {WASM_CALL_FUNCTION0(callback_index)}; - AddExportedFunction(base::CStrVector("run"), code, sizeof(code), &sig); + AddExportedFunction("run", code, sizeof(code), &sig); Compile(); vec<byte_t> serialized = module()->serialize(); @@ -45,6 +44,9 @@ TEST_F(WasmCapiTest, Serialize) { // Ensure cage bases are initialized so that the V8 heap can be accessed. i::PtrComprCageAccessScope ptr_compr_cage_access_scope(isolate); Heap* heap = isolate->heap(); + // We need to invoke GC without stack, otherwise the native module may + // survive. + DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap); heap->PreciseCollectAllGarbage(GCFlag::kForced, GarbageCollectionReason::kTesting); heap->PreciseCollectAllGarbage(GCFlag::kForced, diff --git a/deps/v8/test/wasm-api-tests/startup-errors.cc b/deps/v8/test/wasm-api-tests/startup-errors.cc index 6f25fd6ae842..222142da480f 100644 --- a/deps/v8/test/wasm-api-tests/startup-errors.cc +++ b/deps/v8/test/wasm-api-tests/startup-errors.cc @@ -21,7 +21,7 @@ TEST_F(WasmCapiTest, StartupErrors) { WasmFunctionBuilder* start_func = builder()->AddFunction(&sig); start_func->EmitCode({WASM_UNREACHABLE, WASM_END}); builder()->MarkStartFunction(start_func); - builder()->AddImport(base::CStrVector("dummy"), &sig); + builder()->AddImport("dummy", &sig); Compile(); own<Trap> trap; diff --git a/deps/v8/test/wasm-api-tests/table.cc b/deps/v8/test/wasm-api-tests/table.cc index cf87ef0de309..eb8107ccbff7 100644 --- a/deps/v8/test/wasm-api-tests/table.cc +++ b/deps/v8/test/wasm-api-tests/table.cc @@ -39,21 +39,18 @@ void ExpectResult(int expected, const Func* func, int arg1, int arg2) { TEST_F(WasmCapiTest, Table) { const uint32_t table_index = builder()->AddTable(kWasmFuncRef, 2, 10); - builder()->AddExport(base::CStrVector("table"), kExternalTable, table_index); + builder()->AddExport("table", kExternalTable, table_index); const ModuleTypeIndex sig_i_i_index = builder()->AddSignature(wasm_i_i_sig(), true); ValueType reps[] = {kWasmI32, kWasmI32, kWasmI32}; FunctionSig call_sig(1, 2, reps); uint8_t call_code[] = { WASM_CALL_INDIRECT(sig_i_i_index, WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}; - AddExportedFunction(base::CStrVector("call_indirect"), call_code, - sizeof(call_code), &call_sig); + AddExportedFunction("call_indirect", call_code, sizeof(call_code), &call_sig); uint8_t f_code[] = {WASM_LOCAL_GET(0)}; - AddExportedFunction(base::CStrVector("f"), f_code, sizeof(f_code), - wasm_i_i_sig()); + AddExportedFunction("f", f_code, sizeof(f_code), wasm_i_i_sig()); uint8_t g_code[] = {WASM_I32V_1(42)}; - AddExportedFunction(base::CStrVector("g"), g_code, sizeof(g_code), - wasm_i_i_sig()); + AddExportedFunction("g", g_code, sizeof(g_code), wasm_i_i_sig()); // Set table[1] to {f}, which has function index 1. builder()->SetIndirectFunction(table_index, 1, 1); diff --git a/deps/v8/test/wasm-api-tests/threads.cc b/deps/v8/test/wasm-api-tests/threads.cc index b9158f4f3d63..e281dd02994c 100644 --- a/deps/v8/test/wasm-api-tests/threads.cc +++ b/deps/v8/test/wasm-api-tests/threads.cc @@ -28,6 +28,7 @@ own<Trap> Callback(void* env, const vec<Val>& args, vec<Val>& results) { } void Main(Engine* engine, Shared<Module>* shared, std::mutex* mutex, int id) { + v8::StackStartScope stack_start_scope; own<Store> store = Store::make(engine); // The physical stack size for std::thread on macOS is 512KB. @@ -74,15 +75,13 @@ TEST_F(WasmCapiTest, Threads) { // Create module. ValueType i32_type[] = {kWasmI32}; FunctionSig param_i32(0, 1, i32_type); - uint32_t callback_index = - builder()->AddImport(base::CStrVector("callback"), ¶m_i32); - uint32_t global_index = - builder()->AddGlobalImport(base::CStrVector("id"), kWasmI32, false); + uint32_t callback_index = builder()->AddImport("callback", ¶m_i32); + uint32_t global_index = builder()->AddGlobalImport("id", kWasmI32, false); uint8_t code[] = { WASM_CALL_FUNCTION(callback_index, WASM_GLOBAL_GET(global_index))}; FunctionSig empty_sig(0, 0, nullptr); - AddExportedFunction(base::CStrVector("run"), code, sizeof(code), &empty_sig); + AddExportedFunction("run", code, sizeof(code), &empty_sig); Compile(); own<Shared<Module>> shared = module()->share(); diff --git a/deps/v8/test/wasm-api-tests/traps.cc b/deps/v8/test/wasm-api-tests/traps.cc index cfd3fa17d2d8..709f70efd33c 100644 --- a/deps/v8/test/wasm-api-tests/traps.cc +++ b/deps/v8/test/wasm-api-tests/traps.cc @@ -36,14 +36,12 @@ void ExpectMessage(const char* expected, const Message& message) { TEST_F(WasmCapiTest, Traps) { ValueType i32_type[] = {kWasmI32}; FunctionSig sig(1, 0, i32_type); - uint32_t callback_index = - builder()->AddImport(base::CStrVector("callback"), &sig); + uint32_t callback_index = builder()->AddImport("callback", &sig); uint8_t code[] = {WASM_CALL_FUNCTION0(callback_index)}; - AddExportedFunction(base::CStrVector("callback"), code, sizeof(code), &sig); + AddExportedFunction("callback", code, sizeof(code), &sig); uint8_t code2[] = {WASM_CALL_FUNCTION0(3)}; - AddExportedFunction(base::CStrVector("unreachable"), code2, sizeof(code2), - &sig); + AddExportedFunction("unreachable", code2, sizeof(code2), &sig); // The first constant is a 4-byte dummy so that the {unreachable} trap // has a more interesting offset. This is called by code2. uint8_t code3[] = {WASM_I32V_3(0), WASM_UNREACHABLE, WASM_I32V_1(1)}; @@ -52,8 +50,7 @@ TEST_F(WasmCapiTest, Traps) { // Check that traps returned from a C callback are uncatchable in Wasm. uint8_t code4[] = {WASM_TRY_CATCH_ALL_T( kWasmI32, WASM_CALL_FUNCTION0(callback_index), WASM_I32V(42))}; - AddExportedFunction(base::CStrVector("uncatchable"), code4, sizeof(code4), - &sig); + AddExportedFunction("uncatchable", code4, sizeof(code4), &sig); own<FuncType> func_type = FuncType::make( ownvec<ValType>::make(), diff --git a/deps/v8/test/wasm-api-tests/wasm-api-test.h b/deps/v8/test/wasm-api-tests/wasm-api-test.h index 3211dcb7e216..9a283fb65acf 100644 --- a/deps/v8/test/wasm-api-tests/wasm-api-test.h +++ b/deps/v8/test/wasm-api-tests/wasm-api-test.h @@ -88,7 +88,7 @@ class WasmCapiTest : public ::testing::Test { exports_ = instance_->exports(); } - void AddExportedFunction(base::Vector<const char> name, uint8_t code[], + void AddExportedFunction(std::string_view name, uint8_t code[], size_t code_size, FunctionSig* sig) { WasmFunctionBuilder* fun = builder()->AddFunction(sig); fun->EmitCode(code, static_cast<uint32_t>(code_size)); diff --git a/deps/v8/testing/gtest-support.h b/deps/v8/testing/gtest-support.h index 21c8ebf4d3fb..efa68a94695f 100644 --- a/deps/v8/testing/gtest-support.h +++ b/deps/v8/testing/gtest-support.h @@ -43,7 +43,6 @@ GET_TYPE_NAME(double) // TRACED_FORRANGE(type, var, low, high) expands to a loop that assigns |var| // every value in the range |low| to (including) |high| and adds a // SCOPED_TRACE() message for the |var| while inside the loop body. -// TODO(bmeurer): Migrate to C++11 once we're ready. #define TRACED_FORRANGE(_type, _var, _low, _high) \ for (_type _var##_i = _low; _var##_i <= _high; ++_var##_i) \ for (bool _var##_done = false; !_var##_done;) \ diff --git a/deps/v8/third_party/abseil-cpp/.bazelrc b/deps/v8/third_party/abseil-cpp/.bazelrc new file mode 100644 index 000000000000..3427eb28f004 --- /dev/null +++ b/deps/v8/third_party/abseil-cpp/.bazelrc @@ -0,0 +1,122 @@ +# Copyright 2026 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +common --show_timestamps + +# Retry longer to avoid flakes when fetching external dependencies. +common --http_connector_attempts=10 +common --http_timeout_scaling=2.0 + +# Link GoogleTest against Abseil. +build --define=absl=1 + +test --keep_going +test --test_env=GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1 +test --test_env=TZDIR=absl/time/internal/cctz/testdata/zoneinfo +test --test_output=errors +test --test_tag_filters=-benchmark + +# Configure our Linux Docker toolchain setup. +common --extra_toolchains=@docker_toolchain//:all +build:linux --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 +build:linux --copt=-fno-exceptions +build:linux --copt=-Werror +build:linux --copt=-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1 +build:linux --features=external_include_paths +build:linux --per_file_copt=external/.*@-w +build:linux --host_per_file_copt=external/.*@-w + +# Configure our Windows MSVC and ClangCL setup. +common:windows-msvc --enable_runfiles +build:windows-msvc --cxxopt=/std:c++17 --host_cxxopt=/std:c++17 +build:windows-msvc --copt=/WX +build:windows-msvc --per_file_copt=external/.*@/w +build:windows-msvc --host_per_file_copt=external/.*@/w + +build:windows-clangcl --config=windows-msvc +build:windows-clangcl --compiler=clang-cl +build:windows-clangcl --copt=-Wno-microsoft-cast +build:windows-clangcl --extra_execution_platforms=//:x64_windows-clang-cl +build:windows-clangcl --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl + +# Configure our macOS Xcode setup. +build:macos --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 +build:macos --copt=-Werror +build:macos --copt=-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1 +build:macos --features=external_include_paths +build:macos --per_file_copt=external/.*@-w +build:macos --host_per_file_copt=external/.*@-w + +build:gcc --config=linux --platforms=//ci:linux_gcc +build:gcc-exceptions --config=gcc --copt=-fexceptions +build:clang --config=linux --platforms=//ci:linux_clang --conlyopt=-Wno-unused-command-line-argument +build:clang-exceptions --config=clang --copt=-fexceptions +build:clang-arm --config=linux --platforms=//ci:linux_arm_clang --conlyopt=-Wno-unused-command-line-argument +build:libstdc++ --config=clang --features=libstdc++ --copt=-march=haswell + +# Sanitizer configurations. +build:ubsan --features=ubsan +build:ubsan --copt=-fsanitize=float-divide-by-zero,nullability,undefined +build:ubsan --copt=-fno-sanitize-recover=float-divide-by-zero,nullability,undefined +build:ubsan --copt=-fno-sanitize-blacklist +test:ubsan --test_env=UBSAN_OPTIONS=print_stacktrace=1 + +build:asan --config=clang --config=ubsan --features=asan +build:asan --copt=-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG +build:asan --linkopt=-fsanitize-link-c++-runtime +test:asan --test_tag_filters=-benchmark,-noasan + +build:tsan --config=clang --features=tsan +build:tsan --copt=-fno-sanitize-blacklist +build:tsan --build_tag_filters=-notsan +test:tsan --test_tag_filters=-benchmark,-notsan + +# Remote build configuration for CI. +build:remote-cache --remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache +build:remote-cache --remote_timeout=1200 --bes_timeout=600s +build:remote-cache --remote_download_minimal +# cc_test puts Windows .pdb files in the pdb_file output group rather than +# runfiles, so explicitly download symbolize_test.pdb when linking hits the +# remote cache. +build:remote-cache --remote_download_regex=.*symbolize_test\.pdb$ +# Retry up for up to 15 minutes under heavy load (exponential backoff). +build:remote-cache --remote_retries=20 --remote_retry_max_delay=60s + +build:remote-base --define=EXECUTOR=remote +build:remote-base --remote_timeout=1200 --bes_timeout=600s +build:remote-base --jobs=50 +build:remote-base --remote_download_minimal +# Retry up for up to 15 minutes under heavy load (exponential backoff). +build:remote-base --remote_retries=20 --remote_retry_max_delay=60s + +build:remote --config=remote-base +build:remote --extra_execution_platforms=//ci:rbe +build:remote --host_platform=//ci:rbe +build:remote --platforms=//ci:rbe +build:remote --remote_cache=grpcs://us-east1-remotebuildexecution.googleapis.com +build:remote --remote_executor=grpcs://us-east1-remotebuildexecution.googleapis.com +build:remote --remote_instance_name=projects/google.com:absl-177019/instances/absl-ci-east + +build:remote-floor --config=remote +build:remote-floor --extra_execution_platforms=//ci:rbe-floor +build:remote-floor --host_platform=//ci:rbe-floor +build:remote-floor --platforms=//ci:rbe-floor + +build:remote-arm --config=remote-base +build:remote-arm --extra_execution_platforms=//ci:rbe-arm +build:remote-arm --host_platform=//ci:rbe-arm +build:remote-arm --platforms=//ci:rbe-arm +build:remote-arm --remote_cache=grpcs://us-central1-remotebuildexecution.googleapis.com +build:remote-arm --remote_executor=grpcs://us-central1-remotebuildexecution.googleapis.com +build:remote-arm --remote_instance_name=projects/google.com:absl-177019/instances/gloop-ci-central diff --git a/deps/v8/third_party/abseil-cpp/BUILD.gn b/deps/v8/third_party/abseil-cpp/BUILD.gn index 72c1655fee05..307a5684145a 100644 --- a/deps/v8/third_party/abseil-cpp/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/BUILD.gn @@ -154,8 +154,34 @@ group("absl_component_deps") { # Abseil testing utilities should only be included in test binaries. source_set("test_support") { testonly = true - public_deps = [ "//third_party/abseil-cpp/absl/hash:hash_testing" ] - deps = [ ":absl" ] + # In component builds, depending on `absl/hash:hash_testing` (`source_set`) + # would statically link a duplicate copy of `absl/hash` (and + # `MixingHashState::kSeed`) into test binaries alongside `:absl`. Because + # `hash_testing` is header-only and its compiled Abseil deps are already in + # `:absl`, expose `hash_testing.h` directly and keep its internal headers in + # `sources` (private). + + # When `absl/hash:hash_testing` deps change: + # - Public Abseil deps are synced into `:absl` automatically by + # `convert_bazel_to_gn.py`. + # - Internal headers not in `:absl` will be flagged by `gn check` and should + # be updated in `sources` below. + # - Non-testonly internal `.cc` deps should be added to `absl_component_deps`. + if (is_component_build) { + public = [ "absl/hash/hash_testing.h" ] + sources = [ + "absl/hash/internal/spy_hash_state.h", + "absl/hash/internal/weakly_mixed_integer.h", + ] + public_deps = [ + ":absl", + "//third_party/googletest:gmock", + "//third_party/googletest:gtest", + ] + } else { + public_deps = [ "//third_party/abseil-cpp/absl/hash:hash_testing" ] + deps = [ ":absl" ] + } } # Some third-party libraries use additional parts of absl that are banned in @@ -306,6 +332,7 @@ if (absl_build_tests) { "absl/base:tracing_internal_weak_test", "absl/base:unique_small_name_test", "absl/cleanup:cleanup_test", + "absl/container:btree_instantiate_test", "absl/container:chunked_queue_test", "absl/container:common_policy_traits_test", "absl/container:compressed_tuple_test", diff --git a/deps/v8/third_party/abseil-cpp/CMake/AbseilDll.cmake b/deps/v8/third_party/abseil-cpp/CMake/AbseilDll.cmake index fa89c82b2185..0312f1f4b3a7 100644 --- a/deps/v8/third_party/abseil-cpp/CMake/AbseilDll.cmake +++ b/deps/v8/third_party/abseil-cpp/CMake/AbseilDll.cmake @@ -99,7 +99,6 @@ set(ABSL_INTERNAL_DLL_FILES "container/internal/raw_hash_set.cc" "container/internal/raw_hash_set.h" "container/internal/raw_hash_set_resize_impl.h" - "container/internal/tracked.h" "container/linked_hash_map.h" "container/linked_hash_set.h" "container/node_hash_map.h" @@ -137,8 +136,6 @@ set(ABSL_INTERNAL_DLL_FILES "debugging/internal/elf_mem_image.h" "debugging/internal/examine_stack.cc" "debugging/internal/examine_stack.h" - "debugging/internal/stack_consumption.cc" - "debugging/internal/stack_consumption.h" "debugging/internal/stacktrace_config.h" "debugging/internal/symbolize.h" "debugging/internal/utf8_for_code_point.cc" @@ -164,7 +161,6 @@ set(ABSL_INTERNAL_DLL_FILES "hash/internal/city.h" "hash/internal/hash.cc" "hash/internal/hash.h" - "hash/internal/spy_hash_state.h" "hash/internal/weakly_mixed_integer.h" "log/absl_check.h" "log/absl_log.h" @@ -266,7 +262,6 @@ set(ABSL_INTERNAL_DLL_FILES "random/internal/salted_seed_seq.h" "random/internal/seed_material.cc" "random/internal/seed_material.h" - "random/internal/sequence_urbg.h" "random/internal/traits.h" "random/internal/uniform_helper.h" "random/internal/wide_multiply.h" @@ -347,8 +342,6 @@ set(ABSL_INTERNAL_DLL_FILES "strings/internal/memutil.h" "strings/internal/ostringstream.cc" "strings/internal/ostringstream.h" - "strings/internal/pow10_helper.cc" - "strings/internal/pow10_helper.h" "strings/internal/resize_uninitialized.h" "strings/internal/str_format/arg.cc" "strings/internal/str_format/arg.h" @@ -409,7 +402,6 @@ set(ABSL_INTERNAL_DLL_FILES "synchronization/internal/sem_waiter.h" "synchronization/internal/stdcpp_waiter.cc" "synchronization/internal/stdcpp_waiter.h" - "synchronization/internal/thread_pool.h" "synchronization/internal/waiter.h" "synchronization/internal/waiter_base.cc" "synchronization/internal/waiter_base.h" @@ -448,8 +440,6 @@ set(ABSL_INTERNAL_DLL_FILES "time/internal/cctz/src/time_zone_posix.h" "time/internal/cctz/src/tzfile.h" "time/internal/cctz/src/zone_info_source.cc" - "time/simulated_clock.cc" - "time/simulated_clock.h" "time/time.cc" "time/time.h" "types/any.h" @@ -512,186 +502,6 @@ if(NOT MSVC) ) endif() -set(ABSL_INTERNAL_DLL_TARGETS - "absl_check" - "absl_log" - "absl_vlog_is_on" - "algorithm" - "algorithm_container" - "any" - "any_invocable" - "atomic_hook" - "base" - "base_internal" - "bind_front" - "bits" - "btree" - "check" - "city" - "civil_time" - "compare" - "compressed_tuple" - "config" - "container" - "container_common" - "container_memory" - "cord" - "cord_internal" - "cordz_functions" - "cordz_handle" - "cordz_info" - "cordz_sample_token" - "core_headers" - "counting_allocator" - "crc_cord_state" - "crc_cpu_detect" - "crc_internal" - "crc32c" - "debugging" - "debugging_internal" - "demangle_internal" - "die_if_null" - "dynamic_annotations" - "endian" - "examine_stack" - "exponential_biased" - "failure_signal_handler" - "fixed_array" - "flat_hash_map" - "flat_hash_set" - "function_ref" - "graphcycles_internal" - "hash" - "hash_function_defaults" - "hash_policy_traits" - "hashtable_debug" - "hashtable_debug_hooks" - "hashtablez_sampler" - "inlined_vector" - "inlined_vector_internal" - "int128" - "kernel_timeout_internal" - "layout" - "leak_check" - "log_internal_check_impl" - "log_internal_check_op" - "log_internal_conditions" - "log_internal_config" - "log_internal_fnmatch" - "log_internal_format" - "log_internal_globals" - "log_internal_log_impl" - "log_internal_proto" - "log_internal_message" - "log_internal_log_sink_set" - "log_internal_nullguard" - "log_internal_nullstream" - "log_internal_strip" - "log_internal_voidify" - "log_internal_append_truncated" - "log_globals" - "log_initialize" - "log" - "log_entry" - "log_sink" - "log_sink_registry" - "log_streamer" - "log_internal_structured" - "log_severity" - "log_structured" - "low_level_hash" - "malloc_internal" - "memory" - "meta" - "node_hash_map" - "node_hash_set" - "node_slot_policy" - "non_temporal_arm_intrinsics" - "non_temporal_memcpy" - "numeric" - "optional" - "periodic_sampler" - "pow10_helper" - "pretty_function" - "random_bit_gen_ref" - "random_distributions" - "random_internal_distribution_caller" - "random_internal_distributions" - "random_internal_explicit_seed_seq" - "random_internal_fastmath" - "random_internal_fast_uniform_bits" - "random_internal_generate_real" - "random_internal_iostream_state_saver" - "random_internal_nonsecure_base" - "random_internal_pcg_engine" - "random_internal_platform" - "random_internal_pool_urbg" - "random_internal_randen" - "random_internal_randen_engine" - "random_internal_randen_hwaes" - "random_internal_randen_hwaes_impl" - "random_internal_randen_slow" - "random_internal_salted_seed_seq" - "random_internal_seed_material" - "random_internal_sequence_urbg" - "random_internal_traits" - "random_internal_uniform_helper" - "random_internal_wide_multiply" - "random_random" - "random_seed_gen_exception" - "random_seed_sequences" - "raw_hash_map" - "raw_hash_set" - "raw_logging_internal" - "sample_recorder" - "scoped_set_env" - "span" - "spinlock_wait" - "spy_hash_state" - "stack_consumption" - "stacktrace" - "status" - "statusor" - "str_format" - "str_format_internal" - "strerror" - "strings" - "strings_internal" - "string_view" - "symbolize" - "synchronization" - "thread_pool" - "throw_delegate" - "time" - "time_zone" - "tracked" - "type_traits" - "utility" - "variant" - "vlog_config_internal" - "vlog_is_on" -) - -if(NOT MSVC) - list(APPEND ABSL_INTERNAL_DLL_TARGETS - "flags" - "flags_commandlineflag" - "flags_commandlineflag_internal" - "flags_config" - "flags_internal" - "flags_marshalling" - "flags_parse" - "flags_path_util" - "flags_private_handle_accessor" - "flags_program_name" - "flags_reflection" - "flags_usage" - "flags_usage_internal" - "log_internal_flags" - "log_flags" - ) -endif() - set(ABSL_INTERNAL_TEST_DLL_FILES "hash/hash_testing.h" "log/scoped_mock_log.cc" @@ -711,17 +521,6 @@ set(ABSL_INTERNAL_TEST_DLL_FILES "strings/cord_test_helpers.h" ) -set(ABSL_INTERNAL_TEST_DLL_TARGETS - "cord_test_helpers" - "cordz_test_helpers" - "hash_testing" - "random_mocking_bit_gen" - "random_internal_distribution_test_util" - "random_internal_mock_overload_set" - "scoped_mock_log" - "status_matchers" -) - if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD_REQUIRED) if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) set(ABSL_INTERNAL_AT_LEAST_CXX20 ON) @@ -768,63 +567,29 @@ else() endif() function(absl_internal_dll_contains) - cmake_parse_arguments(ABSL_INTERNAL_DLL - "" - "OUTPUT;TARGET" - "" + cmake_parse_arguments(ABSL_INTERNAL_DLL_CONTAINS + "TEST" + "OUTPUT" + "FILES" ${ARGN} ) - STRING(REGEX REPLACE "^absl::" "" _target ${ABSL_INTERNAL_DLL_TARGET}) - - if (_target IN_LIST ABSL_INTERNAL_DLL_TARGETS) - set(${ABSL_INTERNAL_DLL_OUTPUT} 1 PARENT_SCOPE) + if(ABSL_INTERNAL_DLL_CONTAINS_TEST) + set(_dll_files "${ABSL_INTERNAL_TEST_DLL_FILES}") else() - set(${ABSL_INTERNAL_DLL_OUTPUT} 0 PARENT_SCOPE) + set(_dll_files "${ABSL_INTERNAL_DLL_FILES}") endif() -endfunction() -function(absl_internal_test_dll_contains) - cmake_parse_arguments(ABSL_INTERNAL_TEST_DLL - "" - "OUTPUT;TARGET" - "" - ${ARGN} - ) - - STRING(REGEX REPLACE "^absl::" "" _target ${ABSL_INTERNAL_TEST_DLL_TARGET}) - - if (_target IN_LIST ABSL_INTERNAL_TEST_DLL_TARGETS) - set(${ABSL_INTERNAL_TEST_DLL_OUTPUT} 1 PARENT_SCOPE) - else() - set(${ABSL_INTERNAL_TEST_DLL_OUTPUT} 0 PARENT_SCOPE) - endif() -endfunction() - -function(absl_internal_dll_targets) - cmake_parse_arguments(ABSL_INTERNAL_DLL - "" - "OUTPUT" - "DEPS" - ${ARGN} - ) - - set(_deps "") - foreach(dep IN LISTS ABSL_INTERNAL_DLL_DEPS) - absl_internal_dll_contains(TARGET ${dep} OUTPUT _dll_contains) - absl_internal_test_dll_contains(TARGET ${dep} OUTPUT _test_dll_contains) - if (_dll_contains) - list(APPEND _deps abseil_dll) - elseif (_test_dll_contains) - list(APPEND _deps abseil_test_dll) - else() - list(APPEND _deps ${dep}) + file(RELATIVE_PATH _rel_dir "${absl_SOURCE_DIR}/absl" "${CMAKE_CURRENT_SOURCE_DIR}") + foreach(_file IN LISTS ABSL_INTERNAL_DLL_CONTAINS_FILES) + string(REGEX REPLACE "^\\$<\\$<[^>]+>:(.+)>$" "\\1" _file "${_file}") + if("${_rel_dir}/${_file}" IN_LIST _dll_files) + set(${ABSL_INTERNAL_DLL_CONTAINS_OUTPUT} 1 PARENT_SCOPE) + return() endif() endforeach() - # Because we may have added the DLL multiple times - list(REMOVE_DUPLICATES _deps) - set(${ABSL_INTERNAL_DLL_OUTPUT} "${_deps}" PARENT_SCOPE) + set(${ABSL_INTERNAL_DLL_CONTAINS_OUTPUT} 0 PARENT_SCOPE) endfunction() function(absl_make_dll) diff --git a/deps/v8/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/deps/v8/third_party/abseil-cpp/CMake/AbseilHelpers.cmake index 61e1ae421169..e4fda157275d 100644 --- a/deps/v8/third_party/abseil-cpp/CMake/AbseilHelpers.cmake +++ b/deps/v8/third_party/abseil-cpp/CMake/AbseilHelpers.cmake @@ -130,13 +130,15 @@ function(absl_cc_library) # 4. "static" -- This target does not depend on the DLL and should be built # statically. if (${ABSL_BUILD_DLL}) - if(ABSL_ENABLE_INSTALL) - absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll) - absl_internal_test_dll_contains(TARGET ${_NAME} OUTPUT _in_test_dll) - else() - absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll) - absl_internal_test_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_test_dll) - endif() + absl_internal_dll_contains( + FILES ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS} + OUTPUT _in_dll + ) + absl_internal_dll_contains( + TEST + FILES ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS} + OUTPUT _in_test_dll + ) if (${_in_dll} OR ${_in_test_dll}) # This target should be replaced by the DLL set(_build_type "dll") @@ -227,17 +229,11 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") if(NOT ABSL_CC_LIB_IS_INTERFACE) if(_build_type STREQUAL "dll_dep") - # This target depends on the DLL. When adding dependencies to this target, - # any depended-on-target which is contained inside the DLL is replaced - # with a dependency on the DLL. + # This target depends on the DLL. add_library(${_NAME} STATIC "") target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) - absl_internal_dll_targets( - DEPS ${ABSL_CC_LIB_DEPS} - OUTPUT _dll_deps - ) target_link_libraries(${_NAME} - PUBLIC ${_dll_deps} + PUBLIC ${ABSL_CC_LIB_DEPS} PRIVATE ${ABSL_CC_LIB_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS} @@ -372,6 +368,7 @@ endfunction() # COPTS: List of private compile options # DEFINES: List of public defines # LINKOPTS: List of link options +# SHARD_COUNT: Number of shards to split the test into for ctest # # Note: # By default, absl_cc_test will always create a binary named absl_${NAME}. @@ -405,7 +402,7 @@ function(absl_cc_test) cmake_parse_arguments(ABSL_CC_TEST "" - "NAME" + "NAME;SHARD_COUNT" "SRCS;COPTS;DEFINES;LINKOPTS;DEPS" ${ARGN} ) @@ -427,16 +424,6 @@ function(absl_cc_test) ABSL_CONSUME_TEST_DLL GTEST_LINKED_AS_SHARED_LIBRARY=1 ) - - # Replace dependencies on targets inside the DLL with abseil_dll itself. - absl_internal_dll_targets( - DEPS ${ABSL_CC_TEST_DEPS} - OUTPUT ABSL_CC_TEST_DEPS - ) - absl_internal_dll_targets( - DEPS ${ABSL_CC_TEST_LINKOPTS} - OUTPUT ABSL_CC_TEST_LINKOPTS - ) else() target_compile_definitions(${_NAME} PUBLIC @@ -461,5 +448,16 @@ function(absl_cc_test) target_compile_features(${_NAME} PUBLIC ${ABSL_INTERNAL_CXX_STD_FEATURE}) endif() - add_test(NAME ${_NAME} COMMAND ${_NAME}) + if(ABSL_CC_TEST_SHARD_COUNT AND ABSL_CC_TEST_SHARD_COUNT GREATER 1) + math(EXPR _LAST_SHARD "${ABSL_CC_TEST_SHARD_COUNT} - 1") + foreach(_SHARD RANGE 0 ${_LAST_SHARD}) + add_test(NAME "${_NAME}_shard_${_SHARD}" COMMAND ${_NAME}) + set_tests_properties("${_NAME}_shard_${_SHARD}" PROPERTIES + ENVIRONMENT "GTEST_TOTAL_SHARDS=${ABSL_CC_TEST_SHARD_COUNT};GTEST_SHARD_INDEX=${_SHARD}" + COST 100 + ) + endforeach() + else() + add_test(NAME ${_NAME} COMMAND ${_NAME}) + endif() endfunction() diff --git a/deps/v8/third_party/abseil-cpp/CMake/install_test_project/test.sh b/deps/v8/third_party/abseil-cpp/CMake/install_test_project/test.sh index 962bc8d2d832..2d25696f1510 100755 --- a/deps/v8/third_party/abseil-cpp/CMake/install_test_project/test.sh +++ b/deps/v8/third_party/abseil-cpp/CMake/install_test_project/test.sh @@ -19,8 +19,9 @@ # Fail on any error. Treat unset variables an error. Print commands as executed. set -euox pipefail -absl_dir=/abseil-cpp +absl_dir="${PWD}" absl_build_dir=/buildfs +mkdir -p "${absl_build_dir}" googletest_builddir=/googletest_builddir googletest_archive="googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" project_dir="${absl_dir}/CMake/install_test_project" @@ -40,8 +41,8 @@ pushd "googletest-${ABSL_GOOGLETEST_VERSION}" mkdir build pushd build cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS="${build_shared_libs}" .. -make -j $(nproc) -make install +cmake --build . +cmake --install . ldconfig popd popd @@ -57,10 +58,12 @@ cmake "${absl_dir}" \ -DABSL_FIND_GOOGLETEST=ON \ -DCMAKE_BUILD_TYPE=Release \ -DABSL_BUILD_TESTING=ON \ - -DBUILD_SHARED_LIBS="${build_shared_libs}" -make -j $(nproc) -ctest -j $(nproc) --output-on-failure -make install + -DBUILD_SHARED_LIBS="${build_shared_libs}" \ + -DCMAKE_JOB_POOLS="link=$(nproc)" \ + -DCMAKE_JOB_POOL_LINK=link +cmake --build . +ctest --output-on-failure --repeat until-pass:3 +cmake --install . ldconfig popd diff --git a/deps/v8/third_party/abseil-cpp/MODULE.bazel b/deps/v8/third_party/abseil-cpp/MODULE.bazel index 00ab4c35ddaa..d4096d2813d2 100644 --- a/deps/v8/third_party/abseil-cpp/MODULE.bazel +++ b/deps/v8/third_party/abseil-cpp/MODULE.bazel @@ -50,3 +50,9 @@ bazel_dep( version = "20260708.rc1", repo_name = "do_not_use_for_gloop_visibility_only", ) + +bazel_dep(name = "docker_toolchain", version = "0.1", dev_dependency = True) +local_path_override( + module_name = "docker_toolchain", + path = "ci/docker_toolchain", +) diff --git a/deps/v8/third_party/abseil-cpp/README.chromium b/deps/v8/third_party/abseil-cpp/README.chromium index f224841baee7..9de9cd0bcd21 100644 --- a/deps/v8/third_party/abseil-cpp/README.chromium +++ b/deps/v8/third_party/abseil-cpp/README.chromium @@ -4,7 +4,7 @@ URL: https://github.com/abseil/abseil-cpp License: Apache-2.0 License File: LICENSE Version: N/A -Revision: a1b9918b18364077b32a820862c63e14c1edb70b +Revision: f55358c60f517763307c09ae57c3eadb6d23985e Update Mechanism: Manual Security Critical: yes Shipped: yes diff --git a/deps/v8/third_party/abseil-cpp/absl/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/BUILD.bazel index 980563a9f122..c358647c298e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/BUILD.bazel @@ -44,6 +44,17 @@ config_setting( visibility = [":__subpackages__"], ) +config_setting( + name = "mingw-clang_compiler", + constraint_values = [ + "@platforms//os:windows", + ], + flag_values = { + "@bazel_tools//tools/cpp:compiler": "clang", + }, + visibility = [":__subpackages__"], +) + config_setting( name = "fuchsia", constraint_values = [ @@ -57,6 +68,7 @@ selects.config_setting_group( match_any = [ ":mingw_unspecified_compiler", ":mingw-gcc_compiler", + ":mingw-clang_compiler", ], visibility = [":__subpackages__"], ) diff --git a/deps/v8/third_party/abseil-cpp/absl/algorithm/container.h b/deps/v8/third_party/abseil-cpp/absl/algorithm/container.h index 9d2b48e9f142..5c2d37639358 100644 --- a/deps/v8/third_party/abseil-cpp/absl/algorithm/container.h +++ b/deps/v8/third_party/abseil-cpp/absl/algorithm/container.h @@ -1169,7 +1169,9 @@ constexpr container_algorithm_internal::ContainerIter<C> c_partition_point( // Container-based version of the <algorithm> `std::sort()` function // to sort elements in ascending order of their values. template <typename C> -constexpr void c_sort(C& c) { +constexpr std::enable_if_t< + container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void> +c_sort(C&& c) { std::sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c)); } @@ -1177,7 +1179,9 @@ constexpr void c_sort(C& c) { // Overload of c_sort() for performing a `comp` comparison other than the // default `operator<`. template <typename C, typename LessThan> -constexpr void c_sort(C& c, LessThan&& comp) { +constexpr std::enable_if_t< + container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void> +c_sort(C&& c, LessThan&& comp) { std::sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), std::forward<LessThan>(comp)); @@ -1189,7 +1193,9 @@ constexpr void c_sort(C& c, LessThan&& comp) { // to sort elements in ascending order of their values, preserving the order // of equivalents. template <typename C> -void c_stable_sort(C& c) { +std::enable_if_t< + container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void> +c_stable_sort(C&& c) { std::stable_sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c)); } @@ -1197,7 +1203,9 @@ void c_stable_sort(C& c) { // Overload of c_stable_sort() for performing a `comp` comparison other than the // default `operator<`. template <typename C, typename LessThan> -void c_stable_sort(C& c, LessThan&& comp) { +std::enable_if_t< + container_algorithm_internal::IsPermissibleDestinationRange<C>::value, void> +c_stable_sort(C&& c, LessThan&& comp) { std::stable_sort(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), std::forward<LessThan>(comp)); diff --git a/deps/v8/third_party/abseil-cpp/absl/algorithm/container_test.cc b/deps/v8/third_party/abseil-cpp/absl/algorithm/container_test.cc index e0253827a328..50a621e53568 100644 --- a/deps/v8/third_party/abseil-cpp/absl/algorithm/container_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/algorithm/container_test.cc @@ -1338,6 +1338,18 @@ TEST(MutatingTest, SortWithPredicate) { EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1)); } +TEST(MutatingTest, SortTemporarySpan) { + std::vector<int> test_vector = {2, 3, 1, 4}; + absl::c_sort(absl::MakeSpan(test_vector)); + EXPECT_THAT(test_vector, ElementsAre(1, 2, 3, 4)); +} + +TEST(MutatingTest, SortTemporarySpanWithPredicate) { + std::vector<int> test_vector = {2, 3, 1, 4}; + absl::c_sort(absl::MakeSpan(test_vector), std::greater<int>()); + EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1)); +} + // For absl::c_stable_sort tests. Needs an operator< that does not cover all // fields so that the test can check the sort preserves order of equal elements. struct Element { @@ -1374,6 +1386,24 @@ TEST(MutatingTest, StableSortWithPredicate) { IsElement(1, 1), IsElement(1, 0))); } +TEST(MutatingTest, StableSortTemporarySpan) { + std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; + absl::c_stable_sort(absl::MakeSpan(test_vector)); + EXPECT_THAT(test_vector, + ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1), + IsElement(2, 0), IsElement(2, 2))); +} + +TEST(MutatingTest, StableSortTemporarySpanWithPredicate) { + std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; + absl::c_stable_sort( + absl::MakeSpan(test_vector), + [](const Element& e1, const Element& e2) { return e2 < e1; }); + EXPECT_THAT(test_vector, + ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2), + IsElement(1, 1), IsElement(1, 0))); +} + TEST(MutatingTest, ReplaceCopyIf) { const std::vector<int> initial = {1, 2, 3, 4, 5}; const std::vector<int> expected = {0, 2, 0, 4, 0}; diff --git a/deps/v8/third_party/abseil-cpp/absl/base/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/base/BUILD.bazel index e37b5b48ce86..475e002e1bcd 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/base/BUILD.bazel @@ -70,6 +70,7 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", + "@do_not_use_for_gloop_visibility_only//gloop/util/coding/elias_fano:__subpackages__", "@do_not_use_for_gloop_visibility_only//gloop/util/sysinfo/topology:__subpackages__", ], deps = [ @@ -272,6 +273,7 @@ cc_library( "@rules_cc//cc/compiler:msvc-cl": [], "@rules_cc//cc/compiler:clang-cl": [], "@rules_cc//cc/compiler:emscripten": [], + "@platforms//os:wasi": [], "//conditions:default": ["-pthread"], }) + ABSL_DEFAULT_LINKOPTS, visibility = [ @@ -340,6 +342,7 @@ cc_library( "-ladvapi32", ], "@rules_cc//cc/compiler:emscripten": [], + "@platforms//os:wasi": [], "//conditions:default": ["-pthread"], }) + ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:public"], @@ -508,6 +511,7 @@ cc_library( visibility = ["//absl:__subpackages__"], deps = [ ":config", + ":core_headers", ":pretty_function", "//absl/memory", "//absl/meta:type_traits", @@ -559,6 +563,7 @@ cc_test( srcs = ["spinlock_test_common.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, tags = [ "no_test_wasm", ], diff --git a/deps/v8/third_party/abseil-cpp/absl/base/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/base/BUILD.gn index 65447916b376..2494889d0af2 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/base/BUILD.gn @@ -306,6 +306,7 @@ absl_source_set("exception_safety_testing") { visibility = [ "//third_party/abseil-cpp/absl/*" ] deps = [ ":config", + ":core_headers", ":pretty_function", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/meta:type_traits", diff --git a/deps/v8/third_party/abseil-cpp/absl/base/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/base/CMakeLists.txt index 77dde8ab274f..b3de35a82408 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/base/CMakeLists.txt @@ -365,6 +365,7 @@ absl_cc_library( ${ABSL_TEST_COPTS} DEPS absl::config + absl::core_headers absl::memory absl::meta absl::pretty_function @@ -531,6 +532,8 @@ absl_cc_test( absl::core_headers absl::synchronization GTest::gtest_main + SHARD_COUNT + 4 ) # Internal-only target, do not depend on directly. diff --git a/deps/v8/third_party/abseil-cpp/absl/base/attributes.h b/deps/v8/third_party/abseil-cpp/absl/base/attributes.h index 6c788ac1b5d7..7d0f27237255 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/attributes.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/attributes.h @@ -85,7 +85,12 @@ // Note: As the GCC manual states, "[s]ince non-static C++ methods // have an implicit 'this' argument, the arguments of such methods // should be counted from two, not one." -#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__)) +#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::format) +#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \ + [[gnu::format(printf, string_index, first_to_check)]] +#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \ + [[gnu::format(scanf, string_index, first_to_check)]] +#elif ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \ __attribute__((__format__(__printf__, string_index, first_to_check))) #define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \ @@ -99,10 +104,19 @@ // ABSL_ATTRIBUTE_NOINLINE // // Forces functions to either inline or not inline. Introduced in gcc 3.1. +// +// Note that guarantees are ultimately toolchain-dependent. For example, MSVC +// will not inline any function by default, meaning at least /Ob1 or a higher +// levels of optimization is necessary. #if ABSL_HAVE_ATTRIBUTE(always_inline) || \ (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) #define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 +#elif defined(_MSC_VER) && \ + (_MSC_VER >= 1937 || \ + (_MSC_VER >= 1927 && ABSL_INTERNAL_CPLUSPLUS_LANG > 201703L)) +#define ABSL_ATTRIBUTE_ALWAYS_INLINE [[msvc::forceinline]] +#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 #else #define ABSL_ATTRIBUTE_ALWAYS_INLINE #endif @@ -110,6 +124,11 @@ #if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline)) #define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 +#elif defined(_MSC_VER) && \ + (_MSC_VER >= 1937 || \ + (_MSC_VER >= 1927 && ABSL_INTERNAL_CPLUSPLUS_LANG > 201703L)) +#define ABSL_ATTRIBUTE_NOINLINE [[msvc::noinline]] +#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 #else #define ABSL_ATTRIBUTE_NOINLINE #endif @@ -375,9 +394,9 @@ // link. // #define ABSL_ATTRIBUTE_SECTION_START(name) \ - (reinterpret_cast<void *>(__start_##name)) + (reinterpret_cast<void*>(__start_##name)) #define ABSL_ATTRIBUTE_SECTION_STOP(name) \ - (reinterpret_cast<void *>(__stop_##name)) + (reinterpret_cast<void*>(__stop_##name)) #else // !ABSL_HAVE_ATTRIBUTE_SECTION @@ -389,8 +408,8 @@ #define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) #define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) #define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) -#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0)) -#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0)) +#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(0)) +#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(0)) #endif // ABSL_ATTRIBUTE_SECTION @@ -419,8 +438,7 @@ // // Tells the compiler to warn about unused results. // -// For code or headers that are assured to only build with C++17 and up, prefer -// just using the standard `[[nodiscard]]` directly over this macro. +// Deprecated: Use the standard C++17 `[[nodiscard]]` instead. // // When annotating a function, it must appear as the first part of the // declaration or definition. The compiler will warn if the return value from @@ -442,15 +460,6 @@ // // Sprocket* SprocketPointer(); // SprocketPointer(); // Does *not* trigger a warning. -// -// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result -// warning. For that, warn_unused_result is used only for clang but not for gcc. -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 -// -// Note: past advice was to place the macro after the argument list. -// -// TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is -// compliant with the stricter [[nodiscard]]. #if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) #define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) #else @@ -467,13 +476,17 @@ // Example: // // int foo() ABSL_ATTRIBUTE_HOT; -#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__)) +#if defined(__cplusplus) && ABSL_HAVE_CPP_ATTRIBUTE(gnu::hot) +#define ABSL_ATTRIBUTE_HOT [[gnu::hot]] +#elif ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_HOT __attribute__((hot)) #else #define ABSL_ATTRIBUTE_HOT #endif -#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__)) +#if defined(__cplusplus) && ABSL_HAVE_CPP_ATTRIBUTE(gnu::cold) +#define ABSL_ATTRIBUTE_COLD [[gnu::cold]] +#elif ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__)) #define ABSL_ATTRIBUTE_COLD __attribute__((cold)) #else #define ABSL_ATTRIBUTE_COLD @@ -577,11 +590,26 @@ // Due to differences in positioning requirements between the old, compiler // specific __attribute__ syntax and the now standard `[[maybe_unused]]`, this // macro does not attempt to take advantage of `[[maybe_unused]]`. -#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) -#undef ABSL_ATTRIBUTE_UNUSED -#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#ifdef ABSL_ATTRIBUTE_UNUSED +#error "ABSL_ATTRIBUTE_UNUSED should not be defined." +#endif +#if defined(__cplusplus) && defined(__clang__) && \ + ABSL_HAVE_ATTRIBUTE(diagnose_if) && !defined(SWIG) +struct [[deprecated("Use [[maybe_unused]] instead.")]] _absl_unused_macro; +// Trick: We use __attribute__((diagnose_if(...))) to refer to our own +// deprecated symbol, which then causes a deprecation message to be emitted when +// the macro is used. Since diagnose_if() isn't valid on every declaration, we +// also suppress the warning regarding that. +#define ABSL_ATTRIBUTE_UNUSED \ + [[maybe_unused]] \ + _Pragma("clang diagnostic push") /* */ \ + _Pragma("clang diagnostic ignored \"-Wignored-attributes\"") \ + __attribute__((diagnose_if( \ + sizeof(_absl_unused_macro*) == 0, "", \ + "warning"))) /* */ \ + _Pragma("clang diagnostic pop") #else -#define ABSL_ATTRIBUTE_UNUSED +#define ABSL_ATTRIBUTE_UNUSED [[maybe_unused]] #endif // ABSL_ATTRIBUTE_INITIAL_EXEC @@ -659,8 +687,7 @@ // declarations. The macro argument is used as a custom diagnostic message (e.g. // suggestion of a better alternative). // -// For code or headers that are assured to only build with C++14 and up, prefer -// just using the standard `[[deprecated("message")]]` directly over this macro. +// Deprecated: Use the standard `[[deprecated("message")]]` macro instead. // // Examples: // @@ -680,8 +707,11 @@ // GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain // turns this warning off by default, instead relying on clang-tidy to report // new uses of deprecated code. +#ifdef ABSL_DEPRECATED +#error "ABSL_DEPRECATED should not be defined." +#endif #if ABSL_HAVE_ATTRIBUTE(deprecated) -#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) +#define ABSL_DEPRECATED(message) [[deprecated(message)]] #else #define ABSL_DEPRECATED(message) #endif @@ -691,7 +721,7 @@ // deprecated code can be surrounded with these directives to achieve that // result. // -// class ABSL_DEPRECATED("Use Bar instead") Foo; +// class [[deprecated("Use Bar instead")]] Foo; // // ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING // Baz ComputeBazFromFoo(Foo f); @@ -699,8 +729,8 @@ #if defined(__GNUC__) || defined(__clang__) // Clang also supports these GCC pragmas. #define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") #define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \ _Pragma("GCC diagnostic pop") #elif defined(_MSC_VER) @@ -736,40 +766,36 @@ // // See the upstream documentation for more details: // https://clang.llvm.org/docs/AttributeReference.html#require-explicit-initialization -#ifdef __cplusplus -#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_explicit_initialization) -// clang-format off -#define ABSL_REQUIRE_EXPLICIT_INIT \ +#if defined(__cplusplus) && !defined(SWIG) +#if defined(_MSC_VER) && !defined(__clang__) +// Workaround for MSVC: https://github.com/abseil/abseil-cpp/issues/2157 +#define ABSL_REQUIRE_EXPLICIT_INIT +#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_explicit_initialization) +#define ABSL_REQUIRE_EXPLICIT_INIT \ [[clang::require_explicit_initialization]] = \ - AbslInternal_YouForgotToExplicitlyInitializeAField::v + AbslInternal_YouForgotToExplicitlyInitializeAField::v #else #define ABSL_REQUIRE_EXPLICIT_INIT \ = AbslInternal_YouForgotToExplicitlyInitializeAField::v #endif -// clang-format on #else -// clang-format off #if ABSL_HAVE_ATTRIBUTE(require_explicit_initialization) #define ABSL_REQUIRE_EXPLICIT_INIT \ __attribute__((require_explicit_initialization)) #else -#define ABSL_REQUIRE_EXPLICIT_INIT \ - /* No portable fallback for C is available */ +// No portable fallback for C is available +#define ABSL_REQUIRE_EXPLICIT_INIT #endif -// clang-format on #endif -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(SWIG) struct AbslInternal_YouForgotToExplicitlyInitializeAField { // A portable version of [[clang::require_explicit_initialization]] that // never builds, as a last resort for all toolchains. // The error messages are poor, so we don't rely on this unless we have to. template <class T> -#if !defined(SWIG) - constexpr -#endif - operator T() const /* NOLINT */ { - const void *volatile deliberately_volatile_ptr = nullptr; + constexpr operator T() const /* NOLINT */ { + const void* volatile deliberately_volatile_ptr = nullptr; // Infinite loop to prevent constexpr compilation for (;;) { // This assignment ensures the 'this' pointer is not optimized away, so @@ -815,7 +841,7 @@ struct AbslInternal_YouForgotToExplicitlyInitializeAField { // Note that `ABSL_CONST_INIT` must not be used on a variable declared // constexpr. #if defined(__cpp_constinit) && __cpp_constinit >= 201907L -#define ABSL_CONST_INIT constinit +#define ABSL_CONST_INIT constinit // NOLINT(clang-diagnostic-pre-c++20-compat) #elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) #define ABSL_CONST_INIT [[clang::require_constant_initialization]] #else @@ -1046,7 +1072,8 @@ struct AbslInternal_YouForgotToExplicitlyInitializeAField { // overriding the compiler flag. // // See https://clang.llvm.org/docs/AttributeReference.html#uninitialized -// and https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-uninitialized-variable-attribute +// and +// https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-uninitialized-variable-attribute #if ABSL_HAVE_CPP_ATTRIBUTE(clang::uninitialized) #define ABSL_ATTRIBUTE_UNINITIALIZED [[clang::uninitialized]] #elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::uninitialized) @@ -1085,4 +1112,52 @@ struct AbslInternal_YouForgotToExplicitlyInitializeAField { #define ABSL_ATTRIBUTE_WARN_UNUSED #endif +// ABSL_UNSAFE_BUFFERS() +// +// Wraps code that performs unsafe buffer accesses or pointer arithmetic. Used +// to suppress warnings when `-Wunsafe-buffer-usage` is enabled. +// +// **WARNING**: This macro should be used when unavoidable. Applying it means +// the compiler is unable to prove that your code avoids out-of-bounds reads or +// writes, forcing reliance on manual review. Over time, code evolves and +// undocumented assumptions can silently break, introducing vulnerabilities. +// Always prioritize refactoring to safer alternatives (e.g. std::array, +// absl::Span, or bounds-checked containers) over using this suppression. +// +// When using this macro is unavoidable, restrict its scope to the smallest +// possible expression or statement. You must also add a `// SAFETY: ...` +// comment explaining why the operation is actually safe. +// Justifications include: +// * Explicit bounds checks (e.g., `CHECK()`) immediately preceding the access. +// * Invariants strictly enforced by surrounding types or functions. +// * Preconditions required of the caller (though this is heavily discouraged). +// +// Example (expression): +// +// // SAFETY: `buf` is NUL-terminated so `strdup` won't read past the end. +// return ABSL_UNSAFE_BUFFERS(strdup(buf)); +// +// Example (single-line statement): +// +// // SAFETY: `offset` is bounds-checked above to be within `buffer`. +// ABSL_UNSAFE_BUFFERS(buffer += offset;) +// +// Example (multi-line statement): +// +// // SAFETY: `offset` is bounds-checked above to be within `buffer`. +// ABSL_UNSAFE_BUFFERS( +// char* p = buffer + offset; +// p[0] = 'a'; +// ) +// +// Note: When wrapping a multi-line statement, placing a semicolon after the +// closing parenthesis may produce an extra semicolon warning. +#if defined(__clang__) +#define ABSL_UNSAFE_BUFFERS(...) \ + _Pragma("clang unsafe_buffer_usage begin") \ + __VA_ARGS__ _Pragma("clang unsafe_buffer_usage end") +#else +#define ABSL_UNSAFE_BUFFERS(...) __VA_ARGS__ +#endif + #endif // ABSL_BASE_ATTRIBUTES_H_ diff --git a/deps/v8/third_party/abseil-cpp/absl/base/attributes_test.cc b/deps/v8/third_party/abseil-cpp/absl/base/attributes_test.cc index 5d213a4263af..e87b66e542f8 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/attributes_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/attributes_test.cc @@ -14,6 +14,8 @@ #include "absl/base/attributes.h" +#include <type_traits> + #include "gtest/gtest.h" #include "absl/base/config.h" @@ -24,20 +26,50 @@ TEST(Attributes, RequireExplicitInit) { int f1; int f2 ABSL_REQUIRE_EXPLICIT_INIT; }; - Agg good1 ABSL_ATTRIBUTE_UNUSED = {1, 2}; + Agg good1 [[maybe_unused]] = {1, 2}; #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - Agg good2 ABSL_ATTRIBUTE_UNUSED(1, 2); + Agg good2 [[maybe_unused]] (1, 2); #endif - Agg good3 ABSL_ATTRIBUTE_UNUSED{1, 2}; - Agg good4 ABSL_ATTRIBUTE_UNUSED = {1, 2}; - Agg good5 ABSL_ATTRIBUTE_UNUSED = Agg{1, 2}; - Agg good6[1] ABSL_ATTRIBUTE_UNUSED = {{1, 2}}; - Agg good7[1] ABSL_ATTRIBUTE_UNUSED = {Agg{1, 2}}; + Agg good3 [[maybe_unused]]{1, 2}; + Agg good4 [[maybe_unused]] = {1, 2}; + Agg good5 [[maybe_unused]] = Agg{1, 2}; + Agg good6 [[maybe_unused]][1] = {{1, 2}}; + Agg good7 [[maybe_unused]][1] = {Agg{1, 2}}; union { Agg agg; - } good8 ABSL_ATTRIBUTE_UNUSED = {{1, 2}}; - constexpr Agg good9 ABSL_ATTRIBUTE_UNUSED = {1, 2}; - constexpr Agg good10 ABSL_ATTRIBUTE_UNUSED{1, 2}; + } good8 [[maybe_unused]] = {{1, 2}}; + constexpr Agg good9 [[maybe_unused]] = {1, 2}; + constexpr Agg good10 [[maybe_unused]]{1, 2}; +} + +TEST(Attributes, MSVCBug) { + struct ImplicitlyConstructible { + // NOLINTNEXTLINE(google-explicit-constructor) + ImplicitlyConstructible(const char*) {} + }; + struct Agg { + ImplicitlyConstructible f1 ABSL_REQUIRE_EXPLICIT_INIT; + }; + static_assert(std::is_convertible_v<const char*, ImplicitlyConstructible>); + Agg good1 [[maybe_unused]] = {ImplicitlyConstructible("hello")}; +} + +TEST(Attributes, UnsafeBuffers) { + int buffer[10] = {0}; + int offset = 1; + + // Expression example + int* p1 = ABSL_UNSAFE_BUFFERS(buffer + offset); + EXPECT_EQ(p1, &buffer[1]); + + // Single-line statement example + int* p2 = buffer; + ABSL_UNSAFE_BUFFERS(p2 += offset;) + EXPECT_EQ(p2, &buffer[1]); + + // Multi-line statement example + ABSL_UNSAFE_BUFFERS(int* p3 = buffer + offset; p3[0] = 1;) + EXPECT_EQ(buffer[1], 1); } } // namespace diff --git a/deps/v8/third_party/abseil-cpp/absl/base/config.h b/deps/v8/third_party/abseil-cpp/absl/base/config.h index e3e2c96a39cd..4761f25d4db3 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/config.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/config.h @@ -328,7 +328,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // AsmJS __asmjs__ // WebAssembly (Emscripten) __EMSCRIPTEN__ // Fuchsia __Fuchsia__ -// WebAssembly (WASI) _WASI_EMULATED_MMAN (implies __wasi__) +// WebAssembly (WASI) __wasi__ // // Note that since Android defines both __ANDROID__ and __linux__, one // may probe for either Linux or Android by simply testing for __linux__. @@ -339,13 +339,12 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // POSIX.1-2001. #ifdef ABSL_HAVE_MMAP #error ABSL_HAVE_MMAP cannot be directly set -#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(_AIX) || defined(__ros__) || defined(__asmjs__) || \ - defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || defined(__sun) || \ - defined(__myriad2__) || defined(__HAIKU__) || defined(__OpenBSD__) || \ - defined(__NetBSD__) || defined(__QNX__) || defined(__VXWORKS__) || \ - defined(__hexagon__) || defined(__XTENSA__) || \ - defined(_WASI_EMULATED_MMAN) +#elif defined(__wasi__) +// Avoid mmap on WASI unless _WASI_EMULATED_MMAN is defined. +#if defined(_WASI_EMULATED_MMAN) +#define ABSL_HAVE_MMAP 1 +#endif +#elif __has_include(<sys/mman.h>) #define ABSL_HAVE_MMAP 1 #endif diff --git a/deps/v8/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/deps/v8/third_party/abseil-cpp/absl/base/dynamic_annotations.h index cac11f31613d..4edaa84eacec 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/dynamic_annotations.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/dynamic_annotations.h @@ -83,9 +83,7 @@ #if defined(__clang__) #define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1 -#if !defined(SWIG) #define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1 -#endif #else #define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0 #endif diff --git a/deps/v8/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc b/deps/v8/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc index 24b12d45222a..9aa4dce27cd6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc @@ -842,7 +842,7 @@ struct ExhaustivenessTester { return true; } - static unsigned char successes; + static unsigned char successes [[maybe_unused]]; }; struct { diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.cc b/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.cc index a939bbfaa78d..43b6c4b3bb48 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.cc @@ -221,6 +221,8 @@ CpuType GetAmdCpuType() { return CpuType::kAmdGenoa; case 0x44: // Stepping A0 return CpuType::kAmdRyzenV3000; + case 0xA0: // Stepping A0 + return CpuType::kAmdSiena; default: return CpuType::kUnknown; } @@ -229,6 +231,8 @@ CpuType GetAmdCpuType() { switch (model_num) { case 0x2: return CpuType::kAmdTurin; + case 0x50: + return CpuType::kAmdVenice; default: return CpuType::kUnknown; } @@ -302,8 +306,12 @@ CpuType GetCpuType() { } return CpuType::kArmNeoverseV2; } + case 0xd84: + return CpuType::kArmNeoverseV3; case 0xd8e: return CpuType::kArmNeoverseN3; + case 0xd94: + return CpuType::kArmNeoverseN4; default: return CpuType::kUnknown; } diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.h b/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.h index 43c7c382d1d6..06eb72a91fd6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/cpu_detect.h @@ -30,7 +30,9 @@ enum class CpuType { kAmdNaples, kAmdMilan, kAmdGenoa, + kAmdSiena, kAmdTurin, + kAmdVenice, kAmdRyzenV3000, kIntelCascadelakeXeon, kIntelSkylakeXeon, @@ -48,7 +50,9 @@ enum class CpuType { kAmpereSiryn, kArmNeoverseN2, kArmNeoverseV2, + kArmNeoverseV3, kArmNeoverseN3, + kArmNeoverseN4, kNvidiaGrace, }; diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h b/deps/v8/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h index e600b8526b00..b4be3ec373fa 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h @@ -40,6 +40,7 @@ #include <vector> #include "gtest/gtest.h" +#include "absl/base/attributes.h" #include "absl/base/internal/pretty_function.h" #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" @@ -547,7 +548,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject { } // Memory management operators - static void* operator new(size_t s) noexcept( + ABSL_ATTRIBUTE_NOINLINE static void* operator new(size_t s) noexcept( IsSpecified(TypeSpec::kNoThrowNew)) { if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_INTERNAL_PRETTY_FUNCTION, true); @@ -555,7 +556,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject { return ::operator new(s); } - static void* operator new[](size_t s) noexcept( + ABSL_ATTRIBUTE_NOINLINE static void* operator new[](size_t s) noexcept( IsSpecified(TypeSpec::kNoThrowNew)) { if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_INTERNAL_PRETTY_FUNCTION, true); @@ -564,8 +565,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject { } template <typename... Args> - static void* operator new(size_t s, Args&&... args) noexcept( - IsSpecified(TypeSpec::kNoThrowNew)) { + ABSL_ATTRIBUTE_NOINLINE static void* operator new( + size_t s, Args&&... args) noexcept(IsSpecified(TypeSpec::kNoThrowNew)) { if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_INTERNAL_PRETTY_FUNCTION, true); } @@ -573,8 +574,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject { } template <typename... Args> - static void* operator new[](size_t s, Args&&... args) noexcept( - IsSpecified(TypeSpec::kNoThrowNew)) { + ABSL_ATTRIBUTE_NOINLINE static void* operator new[]( + size_t s, Args&&... args) noexcept(IsSpecified(TypeSpec::kNoThrowNew)) { if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_INTERNAL_PRETTY_FUNCTION, true); } @@ -583,17 +584,23 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // Abseil doesn't support throwing overloaded operator delete. These are // provided so a throwing operator-new can clean up after itself. - void operator delete(void* p) noexcept { ::operator delete(p); } + ABSL_ATTRIBUTE_NOINLINE void operator delete(void* p) noexcept { + ::operator delete(p); + } template <typename... Args> - void operator delete(void* p, Args&&... args) noexcept { + ABSL_ATTRIBUTE_NOINLINE void operator delete(void* p, + Args&&... args) noexcept { ::operator delete(p, std::forward<Args>(args)...); } - void operator delete[](void* p) noexcept { return ::operator delete[](p); } + ABSL_ATTRIBUTE_NOINLINE void operator delete[](void* p) noexcept { + return ::operator delete[](p); + } template <typename... Args> - void operator delete[](void* p, Args&&... args) noexcept { + ABSL_ATTRIBUTE_NOINLINE void operator delete[](void* p, + Args&&... args) noexcept { return ::operator delete[](p, std::forward<Args>(args)...); } diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc b/deps/v8/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc index 2f3a3fd860cd..4cf469d5277e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc @@ -66,7 +66,7 @@ static void RandomizeBlockDesc(BlockDesc *d) { // Use to indicate to the malloc hooks that // this calls is from LowLevelAlloc. -static bool using_low_level_alloc = false; +static bool using_low_level_alloc [[maybe_unused]] = false; // n times, toss a coin, and based on the outcome // either allocate a new block or deallocate an old block. diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.cc index 7c39f6d3ce75..f705a38ecd68 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.cc @@ -89,13 +89,13 @@ constexpr char kTruncated[] = " ... (message truncated)\n"; // consumed bytes, and return whether the message fit without truncation. If // truncation occurred, if possible leave room in the buffer for the message // kTruncated[]. -bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) - ABSL_PRINTF_ATTRIBUTE(3, 0); +ABSL_PRINTF_ATTRIBUTE(3, 0) +bool VADoRawLog(char** buf, int* size, const char* format, va_list ap); bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) { if (*size < 0) return false; int n = vsnprintf(*buf, static_cast<size_t>(*size), format, ap); bool result = true; - if (n < 0 || n > *size) { + if (n < 0 || n >= *size) { result = false; if (static_cast<size_t>(*size) > sizeof(kTruncated)) { n = *size - static_cast<int>(sizeof(kTruncated)); @@ -117,15 +117,15 @@ constexpr int kLogBufSize = 3000; // Helper for RawLog below. // *DoRawLog writes to *buf of *size and move them past the written portion. // It returns true iff there was no overflow or error. -bool DoRawLog(char** buf, int* size, const char* format, ...) - ABSL_PRINTF_ATTRIBUTE(3, 4); +ABSL_PRINTF_ATTRIBUTE(3, 4) +bool DoRawLog(char** buf, int* size, const char* format, ...); bool DoRawLog(char** buf, int* size, const char* format, ...) { if (*size < 0) return false; va_list ap; va_start(ap, format); int n = vsnprintf(*buf, static_cast<size_t>(*size), format, ap); va_end(ap); - if (n < 0 || n > *size) return false; + if (n < 0 || n >= *size) return false; *size -= n; *buf += n; return true; @@ -143,8 +143,9 @@ absl::base_internal::AtomicHook<LogFilterAndPrefixHook> ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<AbortHook> abort_hook; +ABSL_PRINTF_ATTRIBUTE(4, 0) void RawLogVA(absl::LogSeverity severity, const char* file, int line, - const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0); + const char* format, va_list ap); void RawLogVA(absl::LogSeverity severity, const char* file, int line, const char* format, va_list ap) { char buffer[kLogBufSize]; diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.h b/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.h index 8637030f70fd..9cc270b992cd 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/raw_logging.h @@ -128,8 +128,9 @@ namespace raw_log_internal { // Logs format... at "severity" level, reporting it // as called from file:line. // This does not allocate memory or acquire locks. +ABSL_PRINTF_ATTRIBUTE(4, 5) void RawLog(absl::LogSeverity severity, const char* file, int line, - const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); + const char* format, ...); // Writes the provided buffer directly to stderr, in a signal-safe, low-level // manner. Preserves errno. diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.cc b/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.cc index 41d2b482f64f..9046a0097a16 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.cc @@ -62,12 +62,12 @@ ABSL_NAMESPACE_BEGIN namespace base_internal { ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void (*)( - const void *lock, int64_t wait_cycles)> - submit_profile_data; + const void* lock, int64_t wait_cycles)> + submit_unlock_profile_data; -void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock, +void RegisterSpinLockProfiler(void (*fn)(const void* contendedlock, int64_t wait_cycles)) { - submit_profile_data.Store(fn); + submit_unlock_profile_data.Store(fn); } // Monitor the lock to see if its value changes within some time period @@ -173,7 +173,7 @@ void SpinLock::SlowUnlock(uint32_t lock_value) { if ((lock_value & kWaitTimeMask) != kSpinLockSleeper) { const int64_t wait_cycles = DecodeWaitCycles(lock_value); ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); - submit_profile_data(this, wait_cycles); + submit_unlock_profile_data(this, wait_cycles); ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); } } diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.h b/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.h index 81210ca30caf..93a9f1c584e9 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/spinlock.h @@ -231,8 +231,8 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock { } uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles); - void SlowLock() ABSL_ATTRIBUTE_COLD; - void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD void SlowLock(); + ABSL_ATTRIBUTE_COLD void SlowUnlock(uint32_t lock_value); uint32_t SpinLoop(); inline bool TryLockImpl() { diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/deps/v8/third_party/abseil-cpp/absl/base/internal/sysinfo.cc index 1f380bcc60b8..19fef81c60b5 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/sysinfo.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/sysinfo.cc @@ -69,6 +69,10 @@ #include <zircon/process.h> #endif +#if defined(__FREERTOS__) +#include <task.h> +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace base_internal { @@ -471,6 +475,12 @@ pid_t GetTID() { return static_cast<pid_t>(zx_thread_self()); } +#elif defined(__FREERTOS__) + +pid_t GetTID() { + return static_cast<pid_t>(uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle())); +} + #else // Fallback implementation of `GetTID` using `pthread_self`. diff --git a/deps/v8/third_party/abseil-cpp/absl/base/internal/thread_identity.h b/deps/v8/third_party/abseil-cpp/absl/base/internal/thread_identity.h index a9f26d06557a..385df997801b 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/internal/thread_identity.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/internal/thread_identity.h @@ -275,10 +275,11 @@ void ClearCurrentThreadIdentity(); #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 #elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL) #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 -#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ - (__GOOGLE_GRTE_VERSION__ >= 20140228L) -// Support for async-safe TLS was specifically added in GRTEv4. It's not -// present in the upstream eglibc. +#elif ABSL_PER_THREAD_TLS && \ + (!defined(__GLIBC__) || defined(__GOOGLE_GRTE_VERSION__)) +// Check that the libc implementation provides async-signal-safe TLS. Upstream +// glibc (without GRTE patches) may call malloc() in __tls_get_addr() for +// dlopen()'d modules and must use pthread_getspecific() instead. // Note: Current default for production systems. #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS #else diff --git a/deps/v8/third_party/abseil-cpp/absl/base/raw_logging_test.cc b/deps/v8/third_party/abseil-cpp/absl/base/raw_logging_test.cc index 48158c024e55..6d76d7be115e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/raw_logging_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/base/raw_logging_test.cc @@ -18,10 +18,17 @@ #include "absl/base/internal/raw_logging.h" +#include <cstddef> #include <string> -#include <tuple> + +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__EMSCRIPTEN__) +#include <unistd.h> + +#endif #include "gtest/gtest.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" namespace { @@ -75,6 +82,47 @@ TEST(RawLoggingDeathTest, LogFatal) { kExpectedDeathOutput); } +// Raw logging writes to STDERR_FILENO via write()/syscall on POSIX platforms, +// so the truncation path can be exercised directly by capturing stderr, without +// relying on death tests. +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__EMSCRIPTEN__) +TEST(RawLoggingTest, TruncationMarkerAtExactBufferBoundary) { + if (!absl::raw_log_internal::RawLoggingFullySupported()) { + GTEST_SKIP() << "Raw logging output is not supported on this platform."; + } + // kLogBufSize in raw_logging.cc. + constexpr int kLogBufSize = 3000; + + // The space left for the message depends on the log prefix, which a prefix + // hook can change, so try every length up to the buffer size. Each message + // must come out either whole or ending in the truncation marker. + for (int len = 1; len <= kLogBufSize; ++len) { + int fds[2]; + ASSERT_EQ(pipe(fds), 0); + int saved_stderr = dup(STDERR_FILENO); + ASSERT_NE(saved_stderr, -1); + ASSERT_NE(dup2(fds[1], STDERR_FILENO), -1); + + const std::string msg(static_cast<size_t>(len), 'x'); + ABSL_RAW_LOG(ERROR, "%s", msg.c_str()); + + ASSERT_NE(dup2(saved_stderr, STDERR_FILENO), -1); + close(saved_stderr); + close(fds[1]); + char buf[kLogBufSize + 64]; + ssize_t n = read(fds[0], buf, sizeof(buf)); + close(fds[0]); + ASSERT_GT(n, 0); + const std::string output(buf, static_cast<size_t>(n)); + + ASSERT_TRUE(absl::StrContains(output, msg) || + absl::EndsWith(output, " ... (message truncated)\n")) + << "message length " << len; + } +} +#endif + TEST(InternalLog, CompilationTest) { ABSL_INTERNAL_LOG(INFO, "Internal Log"); std::string log_msg = "Internal Log"; diff --git a/deps/v8/third_party/abseil-cpp/absl/base/thread_annotations.h b/deps/v8/third_party/abseil-cpp/absl/base/thread_annotations.h index 4a3f3e33e9e6..cede48c7daba 100644 --- a/deps/v8/third_party/abseil-cpp/absl/base/thread_annotations.h +++ b/deps/v8/third_party/abseil-cpp/absl/base/thread_annotations.h @@ -188,7 +188,9 @@ // acquired, and the destructor should use `UNLOCK_FUNCTION()` with no // arguments; the analysis will assume that the destructor unlocks whatever the // constructor locked. -#if ABSL_HAVE_ATTRIBUTE(scoped_lockable) +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::scoped_lockable) +#define ABSL_SCOPED_LOCKABLE [[clang::scoped_lockable]] +#elif ABSL_HAVE_ATTRIBUTE(scoped_lockable) #define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable)) #else #define ABSL_SCOPED_LOCKABLE diff --git a/deps/v8/third_party/abseil-cpp/absl/container/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/container/BUILD.bazel index 91f79d6650bf..7792be02514d 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/container/BUILD.bazel @@ -458,6 +458,7 @@ cc_test( ":test_instance_tracker", "//absl/base:config", "//absl/base:no_destructor", + "//absl/functional:overload", "//absl/meta:type_traits", "//absl/strings:string_view", "@googletest//:gtest", @@ -732,6 +733,7 @@ cc_library( "//absl/base:core_headers", "//absl/base:throw_delegate", "//absl/meta:type_traits", + "//absl/numeric:bits", ], ) @@ -833,6 +835,7 @@ cc_library( "//absl/memory", "//absl/meta:type_traits", "//absl/numeric:bits", + "//absl/strings:string_view", "//absl/utility", ], ) @@ -842,6 +845,7 @@ cc_test( srcs = ["internal/raw_hash_set_test.cc"], copts = ABSL_TEST_COPTS, linkstatic = 1, + shard_count = 4, tags = NOTEST_TAGS_MOBILE + [ "no_test_chromiumos_arm", "no_test_chromiumos_armv7", @@ -1279,7 +1283,6 @@ cc_test( "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", - "//absl/flags:flag", "//absl/hash:hash_testing", "//absl/memory", "//absl/random", @@ -1292,6 +1295,33 @@ cc_test( ], ) +cc_test( + name = "btree_instantiate_test", + size = "large", + srcs = [ + "btree_instantiate_test.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 10, + tags = [ + "no_test:os:ios", + "no_test_ios", + "no_test_wasm", + ], + visibility = ["//visibility:private"], + deps = [ + ":btree", + ":btree_test_common", + "//absl/base:config", + "//absl/base:raw_logging_internal", + "//absl/flags:flag", + "//absl/strings:cord", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_binary( name = "btree_benchmark", testonly = True, @@ -1459,6 +1489,7 @@ cc_library( "//absl/base:core_headers", "//absl/base:hardening", "//absl/base:iterator_traits_internal", + "//absl/cleanup", ], ) diff --git a/deps/v8/third_party/abseil-cpp/absl/container/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/container/BUILD.gn index f54c4d95d099..4cf6c49defc4 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/container/BUILD.gn @@ -461,6 +461,7 @@ absl_source_set("raw_hash_map") { "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/base:throw_delegate", "//third_party/abseil-cpp/absl/meta:type_traits", + "//third_party/abseil-cpp/absl/numeric:bits", ] } @@ -535,6 +536,7 @@ absl_source_set("raw_hash_set") { "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/meta:type_traits", "//third_party/abseil-cpp/absl/numeric:bits", + "//third_party/abseil-cpp/absl/strings:string_view", "//third_party/abseil-cpp/absl/utility", ] } @@ -772,6 +774,18 @@ absl_source_set("btree_test_common") { # TODO(mbonadei): Fix issue with EXPECT_DEATH and uncomment. # absl_test("btree_test") +absl_test("btree_instantiate_test") { + sources = [ "btree_instantiate_test.cc" ] + deps = [ + ":btree", + ":btree_test_common", + "//third_party/abseil-cpp/absl/base:config", + "//third_party/abseil-cpp/absl/base:raw_logging_internal", + "//third_party/abseil-cpp/absl/flags:flag", + "//third_party/abseil-cpp/absl/strings:cord", + ] +} + absl_source_set("heterogeneous_lookup_testing") { testonly = true public = [ "internal/heterogeneous_lookup_testing.h" ] @@ -851,6 +865,7 @@ absl_source_set("chunked_queue") { "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/base:hardening", "//third_party/abseil-cpp/absl/base:iterator_traits_internal", + "//third_party/abseil-cpp/absl/cleanup", ] check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE } diff --git a/deps/v8/third_party/abseil-cpp/absl/container/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/container/CMakeLists.txt index cf460f03d8cf..82548bc64234 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/container/CMakeLists.txt @@ -49,7 +49,7 @@ absl_cc_library( absl_cc_library( NAME btree_test_common - hdrs + HDRS "btree_test.h" COPTS ${ABSL_TEST_COPTS} @@ -87,6 +87,29 @@ absl_cc_test( absl::test_allocator absl::test_instance_tracker GTest::gmock_main + SHARD_COUNT + 10 +) + +absl_cc_test( + NAME + btree_instantiate_test + SRCS + "btree_instantiate_test.cc" + COPTS + ${ABSL_TEST_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::btree + absl::btree_test_common + absl::cord + absl::core_headers + absl::flags + absl::raw_logging_internal + GTest::gmock_main + SHARD_COUNT + 10 ) # Internal-only target, do not depend on directly. @@ -485,6 +508,7 @@ absl_cc_test( absl::config absl::container_memory absl::no_destructor + absl::overload absl::string_view absl::test_instance_tracker absl::type_traits @@ -726,6 +750,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::bits absl::common_policy_traits absl::config absl::container_memory @@ -810,6 +835,7 @@ absl_cc_library( absl::optional absl::prefetch absl::raw_logging_internal + absl::string_view absl::utility absl::weakly_mixed_integer PUBLIC @@ -849,6 +875,8 @@ absl_cc_test( absl::test_instance_tracker absl::type_traits GTest::gmock_main + SHARD_COUNT + 4 ) # Internal-only target, do not depend on directly. @@ -1217,6 +1245,7 @@ absl_cc_library( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::cleanup absl::config absl::core_headers absl::hardening diff --git a/deps/v8/third_party/abseil-cpp/absl/container/btree_instantiate_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/btree_instantiate_test.cc new file mode 100644 index 000000000000..e9e198f01184 --- /dev/null +++ b/deps/v8/third_party/abseil-cpp/absl/container/btree_instantiate_test.cc @@ -0,0 +1,731 @@ +// Copyright 2026 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: btree_instantiate_test.cc +// ----------------------------------------------------------------------------- +// +// Various tests for btree containers with diverse value types and +// configurations. +// NOTE: There are more tests in btree_test.cc. +// The main reason to have this file separate is to improve build times. + +#include <cstdint> +#include <functional> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/container/btree_map.h" +#include "absl/container/btree_set.h" +#include "absl/container/btree_test.h" +#include "absl/flags/flag.h" +#include "absl/strings/cord.h" + +ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests"); + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace container_internal { + +namespace { + +template <typename T, typename U> +void CheckPairEquals(const T& x, const U& y) { + ABSL_INTERNAL_CHECK(x == y, "Values are unequal."); +} + +template <typename T, typename U, typename V, typename W> +void CheckPairEquals(const std::pair<T, U>& x, const std::pair<V, W>& y) { + CheckPairEquals(x.first, y.first); + CheckPairEquals(x.second, y.second); +} + +} // namespace + +// The base class for a sorted associative container checker. TreeType is the +// container type to check and CheckerType is the container type to check +// against. TreeType is expected to be btree_{set,map,multiset,multimap} and +// CheckerType is expected to be {set,map,multiset,multimap}. +template <typename TreeType, typename CheckerType> +class base_checker { + public: + using key_type = typename TreeType::key_type; + using value_type = typename TreeType::value_type; + using key_compare = typename TreeType::key_compare; + using pointer = typename TreeType::pointer; + using const_pointer = typename TreeType::const_pointer; + using reference = typename TreeType::reference; + using const_reference = typename TreeType::const_reference; + using size_type = typename TreeType::size_type; + using difference_type = typename TreeType::difference_type; + using iterator = typename TreeType::iterator; + using const_iterator = typename TreeType::const_iterator; + using reverse_iterator = typename TreeType::reverse_iterator; + using const_reverse_iterator = typename TreeType::const_reverse_iterator; + + public: + base_checker() : const_tree_(tree_) {} + base_checker(const base_checker& other) + : tree_(other.tree_), const_tree_(tree_), checker_(other.checker_) {} + template <typename InputIterator> + base_checker(InputIterator b, InputIterator e) + : tree_(b, e), const_tree_(tree_), checker_(b, e) {} + + iterator begin() { return tree_.begin(); } + const_iterator begin() const { return tree_.begin(); } + iterator end() { return tree_.end(); } + const_iterator end() const { return tree_.end(); } + reverse_iterator rbegin() { return tree_.rbegin(); } + const_reverse_iterator rbegin() const { return tree_.rbegin(); } + reverse_iterator rend() { return tree_.rend(); } + const_reverse_iterator rend() const { return tree_.rend(); } + + template <typename IterType, typename CheckerIterType> + IterType iter_check(IterType tree_iter, CheckerIterType checker_iter) const { + if (tree_iter == tree_.end()) { + ABSL_INTERNAL_CHECK(checker_iter == checker_.end(), + "Checker iterator not at end."); + } else { + CheckPairEquals(*tree_iter, *checker_iter); + } + return tree_iter; + } + template <typename IterType, typename CheckerIterType> + IterType riter_check(IterType tree_iter, CheckerIterType checker_iter) const { + if (tree_iter == tree_.rend()) { + ABSL_INTERNAL_CHECK(checker_iter == checker_.rend(), + "Checker iterator not at rend."); + } else { + CheckPairEquals(*tree_iter, *checker_iter); + } + return tree_iter; + } + void value_check(const value_type& v) { + typename KeyOfValue<typename TreeType::key_type, + typename TreeType::value_type>::type key_of_value; + const key_type& key = key_of_value(v); + CheckPairEquals(*find(key), v); + lower_bound(key); + upper_bound(key); + equal_range(key); + contains(key); + count(key); + } + void erase_check(const key_type& key) { + EXPECT_FALSE(tree_.contains(key)); + EXPECT_EQ(tree_.find(key), const_tree_.end()); + EXPECT_FALSE(const_tree_.contains(key)); + EXPECT_EQ(const_tree_.find(key), tree_.end()); + EXPECT_EQ(tree_.equal_range(key).first, + const_tree_.equal_range(key).second); + } + + iterator lower_bound(const key_type& key) { + return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); + } + const_iterator lower_bound(const key_type& key) const { + return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); + } + iterator upper_bound(const key_type& key) { + return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); + } + const_iterator upper_bound(const key_type& key) const { + return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); + } + std::pair<iterator, iterator> equal_range(const key_type& key) { + std::pair<typename CheckerType::iterator, typename CheckerType::iterator> + checker_res = checker_.equal_range(key); + std::pair<iterator, iterator> tree_res = tree_.equal_range(key); + iter_check(tree_res.first, checker_res.first); + iter_check(tree_res.second, checker_res.second); + return tree_res; + } + std::pair<const_iterator, const_iterator> equal_range( + const key_type& key) const { + std::pair<typename CheckerType::const_iterator, + typename CheckerType::const_iterator> + checker_res = checker_.equal_range(key); + std::pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key); + iter_check(tree_res.first, checker_res.first); + iter_check(tree_res.second, checker_res.second); + return tree_res; + } + iterator find(const key_type& key) { + return iter_check(tree_.find(key), checker_.find(key)); + } + const_iterator find(const key_type& key) const { + return iter_check(tree_.find(key), checker_.find(key)); + } + bool contains(const key_type& key) const { return find(key) != end(); } + size_type count(const key_type& key) const { + size_type res = checker_.count(key); + EXPECT_EQ(res, tree_.count(key)); + return res; + } + + base_checker& operator=(const base_checker& other) { + tree_ = other.tree_; + checker_ = other.checker_; + return *this; + } + + int erase(const key_type& key) { + int size = tree_.size(); + int res = checker_.erase(key); + EXPECT_EQ(res, tree_.count(key)); + EXPECT_EQ(res, tree_.erase(key)); + EXPECT_EQ(tree_.count(key), 0); + EXPECT_EQ(tree_.size(), size - res); + erase_check(key); + return res; + } + iterator erase(iterator iter) { + key_type key = iter.key(); + int size = tree_.size(); + int count = tree_.count(key); + auto checker_iter = checker_.lower_bound(key); + for (iterator tmp(tree_.lower_bound(key)); tmp != iter; ++tmp) { + ++checker_iter; + } + auto checker_next = checker_iter; + ++checker_next; + checker_.erase(checker_iter); + iter = tree_.erase(iter); + EXPECT_EQ(tree_.size(), checker_.size()); + EXPECT_EQ(tree_.size(), size - 1); + EXPECT_EQ(tree_.count(key), count - 1); + if (count == 1) { + erase_check(key); + } + return iter_check(iter, checker_next); + } + + void erase(iterator begin, iterator end) { + int size = tree_.size(); + int count = std::distance(begin, end); + auto checker_begin = checker_.lower_bound(begin.key()); + for (iterator tmp(tree_.lower_bound(begin.key())); tmp != begin; ++tmp) { + ++checker_begin; + } + auto checker_end = + end == tree_.end() ? checker_.end() : checker_.lower_bound(end.key()); + if (end != tree_.end()) { + for (iterator tmp(tree_.lower_bound(end.key())); tmp != end; ++tmp) { + ++checker_end; + } + } + const auto checker_ret = checker_.erase(checker_begin, checker_end); + const auto tree_ret = tree_.erase(begin, end); + EXPECT_EQ(std::distance(checker_.begin(), checker_ret), + std::distance(tree_.begin(), tree_ret)); + EXPECT_EQ(tree_.size(), checker_.size()); + EXPECT_EQ(tree_.size(), size - count); + } + + void clear() { + tree_.clear(); + checker_.clear(); + } + void swap(base_checker& other) { + tree_.swap(other.tree_); + checker_.swap(other.checker_); + } + + void verify() const { + tree_.verify(); + EXPECT_EQ(tree_.size(), checker_.size()); + + // Move through the forward iterators using increment. + auto checker_iter = checker_.begin(); + const_iterator tree_iter(tree_.begin()); + for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { + CheckPairEquals(*tree_iter, *checker_iter); + } + + // Move through the forward iterators using decrement. + for (int n = tree_.size() - 1; n >= 0; --n) { + iter_check(tree_iter, checker_iter); + --tree_iter; + --checker_iter; + } + EXPECT_EQ(tree_iter, tree_.begin()); + EXPECT_EQ(checker_iter, checker_.begin()); + + // Move through the reverse iterators using increment. + auto checker_riter = checker_.rbegin(); + const_reverse_iterator tree_riter(tree_.rbegin()); + for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { + CheckPairEquals(*tree_riter, *checker_riter); + } + + // Move through the reverse iterators using decrement. + for (int n = tree_.size() - 1; n >= 0; --n) { + riter_check(tree_riter, checker_riter); + --tree_riter; + --checker_riter; + } + EXPECT_EQ(tree_riter, tree_.rbegin()); + EXPECT_EQ(checker_riter, checker_.rbegin()); + } + + const TreeType& tree() const { return tree_; } + + size_type size() const { + EXPECT_EQ(tree_.size(), checker_.size()); + return tree_.size(); + } + size_type max_size() const { return tree_.max_size(); } + bool empty() const { + EXPECT_EQ(tree_.empty(), checker_.empty()); + return tree_.empty(); + } + + protected: + TreeType tree_; + const TreeType& const_tree_; + CheckerType checker_; +}; + +namespace { + +// A checker for unique sorted associative containers. TreeType is expected to +// be btree_{set,map} and CheckerType is expected to be {set,map}. +template <typename TreeType, typename CheckerType> +class unique_checker : public base_checker<TreeType, CheckerType> { + using super_type = base_checker<TreeType, CheckerType>; + + public: + using iterator = typename super_type::iterator; + using value_type = typename super_type::value_type; + + public: + unique_checker() : super_type() {} + unique_checker(const unique_checker& other) : super_type(other) {} + template <class InputIterator> + unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} + unique_checker& operator=(const unique_checker&) = default; + + // Insertion routines. + std::pair<iterator, bool> insert(const value_type& v) { + int size = this->tree_.size(); + std::pair<typename CheckerType::iterator, bool> checker_res = + this->checker_.insert(v); + std::pair<iterator, bool> tree_res = this->tree_.insert(v); + CheckPairEquals(*tree_res.first, *checker_res.first); + EXPECT_EQ(tree_res.second, checker_res.second); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + tree_res.second); + return tree_res; + } + iterator insert(iterator position, const value_type& v) { + int size = this->tree_.size(); + std::pair<typename CheckerType::iterator, bool> checker_res = + this->checker_.insert(v); + iterator tree_res = this->tree_.insert(position, v); + CheckPairEquals(*tree_res, *checker_res.first); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + checker_res.second); + return tree_res; + } + template <typename InputIterator> + void insert(InputIterator b, InputIterator e) { + for (; b != e; ++b) { + insert(*b); + } + } +}; + +// A checker for multiple sorted associative containers. TreeType is expected +// to be btree_{multiset,multimap} and CheckerType is expected to be +// {multiset,multimap}. +template <typename TreeType, typename CheckerType> +class multi_checker : public base_checker<TreeType, CheckerType> { + using super_type = base_checker<TreeType, CheckerType>; + + public: + using iterator = typename super_type::iterator; + using value_type = typename super_type::value_type; + + public: + multi_checker() : super_type() {} + multi_checker(const multi_checker& other) : super_type(other) {} + template <class InputIterator> + multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} + multi_checker& operator=(const multi_checker&) = default; + + // Insertion routines. + iterator insert(const value_type& v) { + int size = this->tree_.size(); + auto checker_res = this->checker_.insert(v); + iterator tree_res = this->tree_.insert(v); + CheckPairEquals(*tree_res, *checker_res); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + 1); + return tree_res; + } + iterator insert(iterator position, const value_type& v) { + int size = this->tree_.size(); + auto checker_res = this->checker_.insert(v); + iterator tree_res = this->tree_.insert(position, v); + CheckPairEquals(*tree_res, *checker_res); + EXPECT_EQ(this->tree_.size(), this->checker_.size()); + EXPECT_EQ(this->tree_.size(), size + 1); + return tree_res; + } + template <typename InputIterator> + void insert(InputIterator b, InputIterator e) { + for (; b != e; ++b) { + insert(*b); + } + } +}; + +template <typename T, typename V> +void DoTest(const char* name, T* b, const std::vector<V>& values) { + typename KeyOfValue<typename T::key_type, V>::type key_of_value; + + T& mutable_b = *b; + const T& const_b = *b; + + // Test insert. + for (int i = 0; i < values.size(); ++i) { + mutable_b.insert(values[i]); + mutable_b.value_check(values[i]); + } + ASSERT_EQ(mutable_b.size(), values.size()); + + const_b.verify(); + + // Test copy constructor. + T b_copy(const_b); + EXPECT_EQ(b_copy.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_copy.find(key_of_value(values[i])), values[i]); + } + + // Test range constructor. + T b_range(const_b.begin(), const_b.end()); + EXPECT_EQ(b_range.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } + + // Test range insertion for values that already exist. + b_range.insert(b_copy.begin(), b_copy.end()); + b_range.verify(); + + // Test range insertion for new values. + b_range.clear(); + b_range.insert(b_copy.begin(), b_copy.end()); + EXPECT_EQ(b_range.size(), b_copy.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } + + // Test assignment to self. Nothing should change. + b_range.operator=(b_range); + EXPECT_EQ(b_range.size(), b_copy.size()); + + // Test assignment of new values. + b_range.clear(); + b_range = b_copy; + EXPECT_EQ(b_range.size(), b_copy.size()); + + // Test swap. + b_range.clear(); + b_range.swap(b_copy); + EXPECT_EQ(b_copy.size(), 0); + EXPECT_EQ(b_range.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } + b_range.swap(b_copy); + + // Test non-member function swap. + swap(b_range, b_copy); + EXPECT_EQ(b_copy.size(), 0); + EXPECT_EQ(b_range.size(), const_b.size()); + for (int i = 0; i < values.size(); ++i) { + CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); + } + swap(b_range, b_copy); + + // Test erase via values. + for (int i = 0; i < values.size(); ++i) { + mutable_b.erase(key_of_value(values[i])); + // Erasing a non-existent key should have no effect. + ASSERT_EQ(mutable_b.erase(key_of_value(values[i])), 0); + } + + const_b.verify(); + EXPECT_EQ(const_b.size(), 0); + + // Test erase via iterators. + mutable_b = b_copy; + for (int i = 0; i < values.size(); ++i) { + mutable_b.erase(mutable_b.find(key_of_value(values[i]))); + } + + const_b.verify(); + EXPECT_EQ(const_b.size(), 0); + + // Test insert with hint. + for (int i = 0; i < values.size(); i++) { + mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); + } + + const_b.verify(); + + // Test range erase. + mutable_b.erase(mutable_b.begin(), mutable_b.end()); + EXPECT_EQ(mutable_b.size(), 0); + const_b.verify(); + + // First half. + mutable_b = b_copy; + typename T::iterator mutable_iter_end = mutable_b.begin(); + for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; + mutable_b.erase(mutable_b.begin(), mutable_iter_end); + EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); + const_b.verify(); + + // Second half. + mutable_b = b_copy; + typename T::iterator mutable_iter_begin = mutable_b.begin(); + for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; + mutable_b.erase(mutable_iter_begin, mutable_b.end()); + EXPECT_EQ(mutable_b.size(), values.size() / 2); + const_b.verify(); + + // Second quarter. + mutable_b = b_copy; + mutable_iter_begin = mutable_b.begin(); + for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; + mutable_iter_end = mutable_iter_begin; + for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; + mutable_b.erase(mutable_iter_begin, mutable_iter_end); + EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); + const_b.verify(); + + mutable_b.clear(); +} + +template <typename T> +void ConstTest() { + using value_type = typename T::value_type; + typename KeyOfValue<typename T::key_type, value_type>::type key_of_value; + + T mutable_b; + const T& const_b = mutable_b; + + // Insert a single value into the container and test looking it up. + value_type value = Generator<value_type>(2)(2); + mutable_b.insert(value); + EXPECT_TRUE(mutable_b.contains(key_of_value(value))); + EXPECT_NE(mutable_b.find(key_of_value(value)), const_b.end()); + EXPECT_TRUE(const_b.contains(key_of_value(value))); + EXPECT_NE(const_b.find(key_of_value(value)), mutable_b.end()); + EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); + EXPECT_EQ(const_b.upper_bound(key_of_value(value)), const_b.end()); + EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); + + // We can only create a non-const iterator from a non-const container. + typename T::iterator mutable_iter(mutable_b.begin()); + EXPECT_EQ(mutable_iter, const_b.begin()); + EXPECT_NE(mutable_iter, const_b.end()); + EXPECT_EQ(const_b.begin(), mutable_iter); + EXPECT_NE(const_b.end(), mutable_iter); + typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); + EXPECT_EQ(mutable_riter, const_b.rbegin()); + EXPECT_NE(mutable_riter, const_b.rend()); + EXPECT_EQ(const_b.rbegin(), mutable_riter); + EXPECT_NE(const_b.rend(), mutable_riter); + + // We can create a const iterator from a non-const iterator. + typename T::const_iterator const_iter(mutable_iter); + EXPECT_EQ(const_iter, mutable_b.begin()); + EXPECT_NE(const_iter, mutable_b.end()); + EXPECT_EQ(mutable_b.begin(), const_iter); + EXPECT_NE(mutable_b.end(), const_iter); + typename T::const_reverse_iterator const_riter(mutable_riter); + EXPECT_EQ(const_riter, mutable_b.rbegin()); + EXPECT_NE(const_riter, mutable_b.rend()); + EXPECT_EQ(mutable_b.rbegin(), const_riter); + EXPECT_NE(mutable_b.rend(), const_riter); + + // Make sure various methods can be invoked on a const container. + const_b.verify(); + ASSERT_TRUE(!const_b.empty()); + EXPECT_EQ(const_b.size(), 1); + EXPECT_GT(const_b.max_size(), 0); + EXPECT_TRUE(const_b.contains(key_of_value(value))); + EXPECT_EQ(const_b.count(key_of_value(value)), 1); +} + +template <typename T, typename C> +void BtreeTest() { + ConstTest<T>(); + + using V = typename remove_pair_const<typename T::value_type>::type; + const std::vector<V> random_values = GenerateValuesWithSeed<V>( + absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), + GTEST_FLAG_GET(random_seed)); + + unique_checker<T, C> container; + + // Test key insertion/deletion in sorted order. + std::vector<V> sorted_values(random_values); + std::sort(sorted_values.begin(), sorted_values.end()); + DoTest("sorted: ", &container, sorted_values); + + // Test key insertion/deletion in reverse sorted order. + std::reverse(sorted_values.begin(), sorted_values.end()); + DoTest("rsorted: ", &container, sorted_values); + + // Test key insertion/deletion in random order. + DoTest("random: ", &container, random_values); +} + +template <typename T, typename C> +void BtreeMultiTest() { + ConstTest<T>(); + + using V = typename remove_pair_const<typename T::value_type>::type; + const std::vector<V> random_values = GenerateValuesWithSeed<V>( + absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), + GTEST_FLAG_GET(random_seed)); + + multi_checker<T, C> container; + + // Test keys in sorted order. + std::vector<V> sorted_values(random_values); + std::sort(sorted_values.begin(), sorted_values.end()); + DoTest("sorted: ", &container, sorted_values); + + // Test keys in reverse sorted order. + std::reverse(sorted_values.begin(), sorted_values.end()); + DoTest("rsorted: ", &container, sorted_values); + + // Test keys in random order. + DoTest("random: ", &container, random_values); + + // Test keys in random order w/ duplicates. + std::vector<V> duplicate_values(random_values); + duplicate_values.insert(duplicate_values.end(), random_values.begin(), + random_values.end()); + DoTest("duplicates:", &container, duplicate_values); + + // Test all identical keys. + std::vector<V> identical_values(100); + std::fill(identical_values.begin(), identical_values.end(), + Generator<V>(2)(2)); + DoTest("identical: ", &container, identical_values); +} + +template <typename T> +void BtreeMapTest() { + using value_type = typename T::value_type; + using mapped_type = typename T::mapped_type; + + mapped_type m = Generator<mapped_type>(0)(0); + (void)m; + + T b; + + // Verify we can insert using operator[]. + for (int i = 0; i < 1000; i++) { + value_type v = Generator<value_type>(1000)(i); + b[v.first] = v.second; + } + EXPECT_EQ(b.size(), 1000); + + // Test whether we can use the "->" operator on iterators and + // reverse_iterators. This stresses the btree_map_params::pair_pointer + // mechanism. + EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first); + EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second); + EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first); + EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second); +} + +template <typename T> +void BtreeMultiMapTest() { + using mapped_type = typename T::mapped_type; + mapped_type m = Generator<mapped_type>(0)(0); + (void)m; +} + +template <typename K, int N = 256> +void SetTest() { + EXPECT_EQ(sizeof(absl::btree_set<K>), + 2 * sizeof(void*) + sizeof(typename absl::btree_set<K>::size_type)); + using BtreeSet = absl::btree_set<K>; + BtreeTest<BtreeSet, std::set<K>>(); +} + +template <typename K, int N = 256> +void MapTest() { + EXPECT_EQ( + sizeof(absl::btree_map<K, K>), + 2 * sizeof(void*) + sizeof(typename absl::btree_map<K, K>::size_type)); + using BtreeMap = absl::btree_map<K, K>; + BtreeTest<BtreeMap, std::map<K, K>>(); + BtreeMapTest<BtreeMap>(); +} + +TEST(Btree, set_int32) { SetTest<int32_t>(); } +TEST(Btree, set_string) { SetTest<std::string>(); } +TEST(Btree, set_cord) { SetTest<absl::Cord>(); } +TEST(Btree, map_int32) { MapTest<int32_t>(); } +TEST(Btree, map_string) { MapTest<std::string>(); } +TEST(Btree, map_cord) { MapTest<absl::Cord>(); } + +template <typename K, int N = 256> +void MultiSetTest() { + EXPECT_EQ( + sizeof(absl::btree_multiset<K>), + 2 * sizeof(void*) + sizeof(typename absl::btree_multiset<K>::size_type)); + using BtreeMSet = absl::btree_multiset<K>; + BtreeMultiTest<BtreeMSet, std::multiset<K>>(); +} + +template <typename K, int N = 256> +void MultiMapTest() { + EXPECT_EQ(sizeof(absl::btree_multimap<K, K>), + 2 * sizeof(void*) + + sizeof(typename absl::btree_multimap<K, K>::size_type)); + using BtreeMMap = absl::btree_multimap<K, K>; + BtreeMultiTest<BtreeMMap, std::multimap<K, K>>(); + BtreeMultiMapTest<BtreeMMap>(); +} + +TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); } +TEST(Btree, multiset_string) { MultiSetTest<std::string>(); } +TEST(Btree, multiset_cord) { MultiSetTest<absl::Cord>(); } +TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); } +TEST(Btree, multimap_string) { MultiMapTest<std::string>(); } +TEST(Btree, multimap_cord) { MultiMapTest<absl::Cord>(); } + +} // namespace +} // namespace container_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/deps/v8/third_party/abseil-cpp/absl/container/btree_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/btree_test.cc index a2c8648502f5..fd078d25e590 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/btree_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/btree_test.cc @@ -11,6 +11,14 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: btree_test.cc +// ----------------------------------------------------------------------------- +// +// General tests for btree containers without many diverse value types. +// NOTE: There are more tests in btree_instantiate_test.cc that test +// diverse value types. #include "absl/container/btree_test.h" @@ -43,7 +51,6 @@ #include "absl/container/btree_set.h" #include "absl/container/internal/test_allocator.h" #include "absl/container/internal/test_instance_tracker.h" -#include "absl/flags/flag.h" #include "absl/hash/hash_testing.h" #include "absl/memory/memory.h" #include "absl/random/random.h" @@ -53,8 +60,6 @@ #include "absl/strings/string_view.h" #include "absl/types/compare.h" -ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests"); - namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { @@ -70,681 +75,9 @@ using ::testing::IsNull; using ::testing::Pair; using ::testing::SizeIs; -template <typename T, typename U> -void CheckPairEquals(const T &x, const U &y) { - ABSL_INTERNAL_CHECK(x == y, "Values are unequal."); -} - -template <typename T, typename U, typename V, typename W> -void CheckPairEquals(const std::pair<T, U> &x, const std::pair<V, W> &y) { - CheckPairEquals(x.first, y.first); - CheckPairEquals(x.second, y.second); -} } // namespace -// The base class for a sorted associative container checker. TreeType is the -// container type to check and CheckerType is the container type to check -// against. TreeType is expected to be btree_{set,map,multiset,multimap} and -// CheckerType is expected to be {set,map,multiset,multimap}. -template <typename TreeType, typename CheckerType> -class base_checker { - public: - using key_type = typename TreeType::key_type; - using value_type = typename TreeType::value_type; - using key_compare = typename TreeType::key_compare; - using pointer = typename TreeType::pointer; - using const_pointer = typename TreeType::const_pointer; - using reference = typename TreeType::reference; - using const_reference = typename TreeType::const_reference; - using size_type = typename TreeType::size_type; - using difference_type = typename TreeType::difference_type; - using iterator = typename TreeType::iterator; - using const_iterator = typename TreeType::const_iterator; - using reverse_iterator = typename TreeType::reverse_iterator; - using const_reverse_iterator = typename TreeType::const_reverse_iterator; - - public: - base_checker() : const_tree_(tree_) {} - base_checker(const base_checker &other) - : tree_(other.tree_), const_tree_(tree_), checker_(other.checker_) {} - template <typename InputIterator> - base_checker(InputIterator b, InputIterator e) - : tree_(b, e), const_tree_(tree_), checker_(b, e) {} - - iterator begin() { return tree_.begin(); } - const_iterator begin() const { return tree_.begin(); } - iterator end() { return tree_.end(); } - const_iterator end() const { return tree_.end(); } - reverse_iterator rbegin() { return tree_.rbegin(); } - const_reverse_iterator rbegin() const { return tree_.rbegin(); } - reverse_iterator rend() { return tree_.rend(); } - const_reverse_iterator rend() const { return tree_.rend(); } - - template <typename IterType, typename CheckerIterType> - IterType iter_check(IterType tree_iter, CheckerIterType checker_iter) const { - if (tree_iter == tree_.end()) { - ABSL_INTERNAL_CHECK(checker_iter == checker_.end(), - "Checker iterator not at end."); - } else { - CheckPairEquals(*tree_iter, *checker_iter); - } - return tree_iter; - } - template <typename IterType, typename CheckerIterType> - IterType riter_check(IterType tree_iter, CheckerIterType checker_iter) const { - if (tree_iter == tree_.rend()) { - ABSL_INTERNAL_CHECK(checker_iter == checker_.rend(), - "Checker iterator not at rend."); - } else { - CheckPairEquals(*tree_iter, *checker_iter); - } - return tree_iter; - } - void value_check(const value_type &v) { - typename KeyOfValue<typename TreeType::key_type, - typename TreeType::value_type>::type key_of_value; - const key_type &key = key_of_value(v); - CheckPairEquals(*find(key), v); - lower_bound(key); - upper_bound(key); - equal_range(key); - contains(key); - count(key); - } - void erase_check(const key_type &key) { - EXPECT_FALSE(tree_.contains(key)); - EXPECT_EQ(tree_.find(key), const_tree_.end()); - EXPECT_FALSE(const_tree_.contains(key)); - EXPECT_EQ(const_tree_.find(key), tree_.end()); - EXPECT_EQ(tree_.equal_range(key).first, - const_tree_.equal_range(key).second); - } - - iterator lower_bound(const key_type &key) { - return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); - } - const_iterator lower_bound(const key_type &key) const { - return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); - } - iterator upper_bound(const key_type &key) { - return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); - } - const_iterator upper_bound(const key_type &key) const { - return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); - } - std::pair<iterator, iterator> equal_range(const key_type &key) { - std::pair<typename CheckerType::iterator, typename CheckerType::iterator> - checker_res = checker_.equal_range(key); - std::pair<iterator, iterator> tree_res = tree_.equal_range(key); - iter_check(tree_res.first, checker_res.first); - iter_check(tree_res.second, checker_res.second); - return tree_res; - } - std::pair<const_iterator, const_iterator> equal_range( - const key_type &key) const { - std::pair<typename CheckerType::const_iterator, - typename CheckerType::const_iterator> - checker_res = checker_.equal_range(key); - std::pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key); - iter_check(tree_res.first, checker_res.first); - iter_check(tree_res.second, checker_res.second); - return tree_res; - } - iterator find(const key_type &key) { - return iter_check(tree_.find(key), checker_.find(key)); - } - const_iterator find(const key_type &key) const { - return iter_check(tree_.find(key), checker_.find(key)); - } - bool contains(const key_type &key) const { return find(key) != end(); } - size_type count(const key_type &key) const { - size_type res = checker_.count(key); - EXPECT_EQ(res, tree_.count(key)); - return res; - } - - base_checker &operator=(const base_checker &other) { - tree_ = other.tree_; - checker_ = other.checker_; - return *this; - } - - int erase(const key_type &key) { - int size = tree_.size(); - int res = checker_.erase(key); - EXPECT_EQ(res, tree_.count(key)); - EXPECT_EQ(res, tree_.erase(key)); - EXPECT_EQ(tree_.count(key), 0); - EXPECT_EQ(tree_.size(), size - res); - erase_check(key); - return res; - } - iterator erase(iterator iter) { - key_type key = iter.key(); - int size = tree_.size(); - int count = tree_.count(key); - auto checker_iter = checker_.lower_bound(key); - for (iterator tmp(tree_.lower_bound(key)); tmp != iter; ++tmp) { - ++checker_iter; - } - auto checker_next = checker_iter; - ++checker_next; - checker_.erase(checker_iter); - iter = tree_.erase(iter); - EXPECT_EQ(tree_.size(), checker_.size()); - EXPECT_EQ(tree_.size(), size - 1); - EXPECT_EQ(tree_.count(key), count - 1); - if (count == 1) { - erase_check(key); - } - return iter_check(iter, checker_next); - } - - void erase(iterator begin, iterator end) { - int size = tree_.size(); - int count = std::distance(begin, end); - auto checker_begin = checker_.lower_bound(begin.key()); - for (iterator tmp(tree_.lower_bound(begin.key())); tmp != begin; ++tmp) { - ++checker_begin; - } - auto checker_end = - end == tree_.end() ? checker_.end() : checker_.lower_bound(end.key()); - if (end != tree_.end()) { - for (iterator tmp(tree_.lower_bound(end.key())); tmp != end; ++tmp) { - ++checker_end; - } - } - const auto checker_ret = checker_.erase(checker_begin, checker_end); - const auto tree_ret = tree_.erase(begin, end); - EXPECT_EQ(std::distance(checker_.begin(), checker_ret), - std::distance(tree_.begin(), tree_ret)); - EXPECT_EQ(tree_.size(), checker_.size()); - EXPECT_EQ(tree_.size(), size - count); - } - - void clear() { - tree_.clear(); - checker_.clear(); - } - void swap(base_checker &other) { - tree_.swap(other.tree_); - checker_.swap(other.checker_); - } - - void verify() const { - tree_.verify(); - EXPECT_EQ(tree_.size(), checker_.size()); - - // Move through the forward iterators using increment. - auto checker_iter = checker_.begin(); - const_iterator tree_iter(tree_.begin()); - for (; tree_iter != tree_.end(); ++tree_iter, ++checker_iter) { - CheckPairEquals(*tree_iter, *checker_iter); - } - - // Move through the forward iterators using decrement. - for (int n = tree_.size() - 1; n >= 0; --n) { - iter_check(tree_iter, checker_iter); - --tree_iter; - --checker_iter; - } - EXPECT_EQ(tree_iter, tree_.begin()); - EXPECT_EQ(checker_iter, checker_.begin()); - - // Move through the reverse iterators using increment. - auto checker_riter = checker_.rbegin(); - const_reverse_iterator tree_riter(tree_.rbegin()); - for (; tree_riter != tree_.rend(); ++tree_riter, ++checker_riter) { - CheckPairEquals(*tree_riter, *checker_riter); - } - - // Move through the reverse iterators using decrement. - for (int n = tree_.size() - 1; n >= 0; --n) { - riter_check(tree_riter, checker_riter); - --tree_riter; - --checker_riter; - } - EXPECT_EQ(tree_riter, tree_.rbegin()); - EXPECT_EQ(checker_riter, checker_.rbegin()); - } - - const TreeType &tree() const { return tree_; } - - size_type size() const { - EXPECT_EQ(tree_.size(), checker_.size()); - return tree_.size(); - } - size_type max_size() const { return tree_.max_size(); } - bool empty() const { - EXPECT_EQ(tree_.empty(), checker_.empty()); - return tree_.empty(); - } - - protected: - TreeType tree_; - const TreeType &const_tree_; - CheckerType checker_; -}; - namespace { -// A checker for unique sorted associative containers. TreeType is expected to -// be btree_{set,map} and CheckerType is expected to be {set,map}. -template <typename TreeType, typename CheckerType> -class unique_checker : public base_checker<TreeType, CheckerType> { - using super_type = base_checker<TreeType, CheckerType>; - - public: - using iterator = typename super_type::iterator; - using value_type = typename super_type::value_type; - - public: - unique_checker() : super_type() {} - unique_checker(const unique_checker &other) : super_type(other) {} - template <class InputIterator> - unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {} - unique_checker &operator=(const unique_checker &) = default; - - // Insertion routines. - std::pair<iterator, bool> insert(const value_type &v) { - int size = this->tree_.size(); - std::pair<typename CheckerType::iterator, bool> checker_res = - this->checker_.insert(v); - std::pair<iterator, bool> tree_res = this->tree_.insert(v); - CheckPairEquals(*tree_res.first, *checker_res.first); - EXPECT_EQ(tree_res.second, checker_res.second); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + tree_res.second); - return tree_res; - } - iterator insert(iterator position, const value_type &v) { - int size = this->tree_.size(); - std::pair<typename CheckerType::iterator, bool> checker_res = - this->checker_.insert(v); - iterator tree_res = this->tree_.insert(position, v); - CheckPairEquals(*tree_res, *checker_res.first); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + checker_res.second); - return tree_res; - } - template <typename InputIterator> - void insert(InputIterator b, InputIterator e) { - for (; b != e; ++b) { - insert(*b); - } - } -}; - -// A checker for multiple sorted associative containers. TreeType is expected -// to be btree_{multiset,multimap} and CheckerType is expected to be -// {multiset,multimap}. -template <typename TreeType, typename CheckerType> -class multi_checker : public base_checker<TreeType, CheckerType> { - using super_type = base_checker<TreeType, CheckerType>; - - public: - using iterator = typename super_type::iterator; - using value_type = typename super_type::value_type; - - public: - multi_checker() : super_type() {} - multi_checker(const multi_checker &other) : super_type(other) {} - template <class InputIterator> - multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {} - multi_checker &operator=(const multi_checker &) = default; - - // Insertion routines. - iterator insert(const value_type &v) { - int size = this->tree_.size(); - auto checker_res = this->checker_.insert(v); - iterator tree_res = this->tree_.insert(v); - CheckPairEquals(*tree_res, *checker_res); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + 1); - return tree_res; - } - iterator insert(iterator position, const value_type &v) { - int size = this->tree_.size(); - auto checker_res = this->checker_.insert(v); - iterator tree_res = this->tree_.insert(position, v); - CheckPairEquals(*tree_res, *checker_res); - EXPECT_EQ(this->tree_.size(), this->checker_.size()); - EXPECT_EQ(this->tree_.size(), size + 1); - return tree_res; - } - template <typename InputIterator> - void insert(InputIterator b, InputIterator e) { - for (; b != e; ++b) { - insert(*b); - } - } -}; - -template <typename T, typename V> -void DoTest(const char *name, T *b, const std::vector<V> &values) { - typename KeyOfValue<typename T::key_type, V>::type key_of_value; - - T &mutable_b = *b; - const T &const_b = *b; - - // Test insert. - for (int i = 0; i < values.size(); ++i) { - mutable_b.insert(values[i]); - mutable_b.value_check(values[i]); - } - ASSERT_EQ(mutable_b.size(), values.size()); - - const_b.verify(); - - // Test copy constructor. - T b_copy(const_b); - EXPECT_EQ(b_copy.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_copy.find(key_of_value(values[i])), values[i]); - } - - // Test range constructor. - T b_range(const_b.begin(), const_b.end()); - EXPECT_EQ(b_range.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } - - // Test range insertion for values that already exist. - b_range.insert(b_copy.begin(), b_copy.end()); - b_range.verify(); - - // Test range insertion for new values. - b_range.clear(); - b_range.insert(b_copy.begin(), b_copy.end()); - EXPECT_EQ(b_range.size(), b_copy.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } - - // Test assignment to self. Nothing should change. - b_range.operator=(b_range); - EXPECT_EQ(b_range.size(), b_copy.size()); - - // Test assignment of new values. - b_range.clear(); - b_range = b_copy; - EXPECT_EQ(b_range.size(), b_copy.size()); - - // Test swap. - b_range.clear(); - b_range.swap(b_copy); - EXPECT_EQ(b_copy.size(), 0); - EXPECT_EQ(b_range.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } - b_range.swap(b_copy); - - // Test non-member function swap. - swap(b_range, b_copy); - EXPECT_EQ(b_copy.size(), 0); - EXPECT_EQ(b_range.size(), const_b.size()); - for (int i = 0; i < values.size(); ++i) { - CheckPairEquals(*b_range.find(key_of_value(values[i])), values[i]); - } - swap(b_range, b_copy); - - // Test erase via values. - for (int i = 0; i < values.size(); ++i) { - mutable_b.erase(key_of_value(values[i])); - // Erasing a non-existent key should have no effect. - ASSERT_EQ(mutable_b.erase(key_of_value(values[i])), 0); - } - - const_b.verify(); - EXPECT_EQ(const_b.size(), 0); - - // Test erase via iterators. - mutable_b = b_copy; - for (int i = 0; i < values.size(); ++i) { - mutable_b.erase(mutable_b.find(key_of_value(values[i]))); - } - - const_b.verify(); - EXPECT_EQ(const_b.size(), 0); - - // Test insert with hint. - for (int i = 0; i < values.size(); i++) { - mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); - } - - const_b.verify(); - - // Test range erase. - mutable_b.erase(mutable_b.begin(), mutable_b.end()); - EXPECT_EQ(mutable_b.size(), 0); - const_b.verify(); - - // First half. - mutable_b = b_copy; - typename T::iterator mutable_iter_end = mutable_b.begin(); - for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; - mutable_b.erase(mutable_b.begin(), mutable_iter_end); - EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); - const_b.verify(); - - // Second half. - mutable_b = b_copy; - typename T::iterator mutable_iter_begin = mutable_b.begin(); - for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; - mutable_b.erase(mutable_iter_begin, mutable_b.end()); - EXPECT_EQ(mutable_b.size(), values.size() / 2); - const_b.verify(); - - // Second quarter. - mutable_b = b_copy; - mutable_iter_begin = mutable_b.begin(); - for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; - mutable_iter_end = mutable_iter_begin; - for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; - mutable_b.erase(mutable_iter_begin, mutable_iter_end); - EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); - const_b.verify(); - - mutable_b.clear(); -} - -template <typename T> -void ConstTest() { - using value_type = typename T::value_type; - typename KeyOfValue<typename T::key_type, value_type>::type key_of_value; - - T mutable_b; - const T &const_b = mutable_b; - - // Insert a single value into the container and test looking it up. - value_type value = Generator<value_type>(2)(2); - mutable_b.insert(value); - EXPECT_TRUE(mutable_b.contains(key_of_value(value))); - EXPECT_NE(mutable_b.find(key_of_value(value)), const_b.end()); - EXPECT_TRUE(const_b.contains(key_of_value(value))); - EXPECT_NE(const_b.find(key_of_value(value)), mutable_b.end()); - EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); - EXPECT_EQ(const_b.upper_bound(key_of_value(value)), const_b.end()); - EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); - - // We can only create a non-const iterator from a non-const container. - typename T::iterator mutable_iter(mutable_b.begin()); - EXPECT_EQ(mutable_iter, const_b.begin()); - EXPECT_NE(mutable_iter, const_b.end()); - EXPECT_EQ(const_b.begin(), mutable_iter); - EXPECT_NE(const_b.end(), mutable_iter); - typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); - EXPECT_EQ(mutable_riter, const_b.rbegin()); - EXPECT_NE(mutable_riter, const_b.rend()); - EXPECT_EQ(const_b.rbegin(), mutable_riter); - EXPECT_NE(const_b.rend(), mutable_riter); - - // We can create a const iterator from a non-const iterator. - typename T::const_iterator const_iter(mutable_iter); - EXPECT_EQ(const_iter, mutable_b.begin()); - EXPECT_NE(const_iter, mutable_b.end()); - EXPECT_EQ(mutable_b.begin(), const_iter); - EXPECT_NE(mutable_b.end(), const_iter); - typename T::const_reverse_iterator const_riter(mutable_riter); - EXPECT_EQ(const_riter, mutable_b.rbegin()); - EXPECT_NE(const_riter, mutable_b.rend()); - EXPECT_EQ(mutable_b.rbegin(), const_riter); - EXPECT_NE(mutable_b.rend(), const_riter); - - // Make sure various methods can be invoked on a const container. - const_b.verify(); - ASSERT_TRUE(!const_b.empty()); - EXPECT_EQ(const_b.size(), 1); - EXPECT_GT(const_b.max_size(), 0); - EXPECT_TRUE(const_b.contains(key_of_value(value))); - EXPECT_EQ(const_b.count(key_of_value(value)), 1); -} - -template <typename T, typename C> -void BtreeTest() { - ConstTest<T>(); - - using V = typename remove_pair_const<typename T::value_type>::type; - const std::vector<V> random_values = GenerateValuesWithSeed<V>( - absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), - GTEST_FLAG_GET(random_seed)); - - unique_checker<T, C> container; - - // Test key insertion/deletion in sorted order. - std::vector<V> sorted_values(random_values); - std::sort(sorted_values.begin(), sorted_values.end()); - DoTest("sorted: ", &container, sorted_values); - - // Test key insertion/deletion in reverse sorted order. - std::reverse(sorted_values.begin(), sorted_values.end()); - DoTest("rsorted: ", &container, sorted_values); - - // Test key insertion/deletion in random order. - DoTest("random: ", &container, random_values); -} - -template <typename T, typename C> -void BtreeMultiTest() { - ConstTest<T>(); - - using V = typename remove_pair_const<typename T::value_type>::type; - const std::vector<V> random_values = GenerateValuesWithSeed<V>( - absl::GetFlag(FLAGS_test_values), 4 * absl::GetFlag(FLAGS_test_values), - GTEST_FLAG_GET(random_seed)); - - multi_checker<T, C> container; - - // Test keys in sorted order. - std::vector<V> sorted_values(random_values); - std::sort(sorted_values.begin(), sorted_values.end()); - DoTest("sorted: ", &container, sorted_values); - - // Test keys in reverse sorted order. - std::reverse(sorted_values.begin(), sorted_values.end()); - DoTest("rsorted: ", &container, sorted_values); - - // Test keys in random order. - DoTest("random: ", &container, random_values); - - // Test keys in random order w/ duplicates. - std::vector<V> duplicate_values(random_values); - duplicate_values.insert(duplicate_values.end(), random_values.begin(), - random_values.end()); - DoTest("duplicates:", &container, duplicate_values); - - // Test all identical keys. - std::vector<V> identical_values(100); - std::fill(identical_values.begin(), identical_values.end(), - Generator<V>(2)(2)); - DoTest("identical: ", &container, identical_values); -} - -template <typename T> -void BtreeMapTest() { - using value_type = typename T::value_type; - using mapped_type = typename T::mapped_type; - - mapped_type m = Generator<mapped_type>(0)(0); - (void)m; - - T b; - - // Verify we can insert using operator[]. - for (int i = 0; i < 1000; i++) { - value_type v = Generator<value_type>(1000)(i); - b[v.first] = v.second; - } - EXPECT_EQ(b.size(), 1000); - - // Test whether we can use the "->" operator on iterators and - // reverse_iterators. This stresses the btree_map_params::pair_pointer - // mechanism. - EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first); - EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second); - EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first); - EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second); -} - -template <typename T> -void BtreeMultiMapTest() { - using mapped_type = typename T::mapped_type; - mapped_type m = Generator<mapped_type>(0)(0); - (void)m; -} - -template <typename K, int N = 256> -void SetTest() { - EXPECT_EQ( - sizeof(absl::btree_set<K>), - 2 * sizeof(void *) + sizeof(typename absl::btree_set<K>::size_type)); - using BtreeSet = absl::btree_set<K>; - BtreeTest<BtreeSet, std::set<K>>(); -} - -template <typename K, int N = 256> -void MapTest() { - EXPECT_EQ( - sizeof(absl::btree_map<K, K>), - 2 * sizeof(void *) + sizeof(typename absl::btree_map<K, K>::size_type)); - using BtreeMap = absl::btree_map<K, K>; - BtreeTest<BtreeMap, std::map<K, K>>(); - BtreeMapTest<BtreeMap>(); -} - -TEST(Btree, set_int32) { SetTest<int32_t>(); } -TEST(Btree, set_string) { SetTest<std::string>(); } -TEST(Btree, set_cord) { SetTest<absl::Cord>(); } -TEST(Btree, map_int32) { MapTest<int32_t>(); } -TEST(Btree, map_string) { MapTest<std::string>(); } -TEST(Btree, map_cord) { MapTest<absl::Cord>(); } - -template <typename K, int N = 256> -void MultiSetTest() { - EXPECT_EQ( - sizeof(absl::btree_multiset<K>), - 2 * sizeof(void *) + sizeof(typename absl::btree_multiset<K>::size_type)); - using BtreeMSet = absl::btree_multiset<K>; - BtreeMultiTest<BtreeMSet, std::multiset<K>>(); -} - -template <typename K, int N = 256> -void MultiMapTest() { - EXPECT_EQ(sizeof(absl::btree_multimap<K, K>), - 2 * sizeof(void *) + - sizeof(typename absl::btree_multimap<K, K>::size_type)); - using BtreeMMap = absl::btree_multimap<K, K>; - BtreeMultiTest<BtreeMMap, std::multimap<K, K>>(); - BtreeMultiMapTest<BtreeMMap>(); -} - -TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); } -TEST(Btree, multiset_string) { MultiSetTest<std::string>(); } -TEST(Btree, multiset_cord) { MultiSetTest<absl::Cord>(); } -TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); } -TEST(Btree, multimap_string) { MultiMapTest<std::string>(); } -TEST(Btree, multimap_cord) { MultiMapTest<absl::Cord>(); } struct CompareIntToString { bool operator()(const std::string &a, const std::string &b) const { diff --git a/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue.h b/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue.h index 8ada20853fa9..54cb6d873441 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue.h @@ -35,6 +35,8 @@ // shrink_to_fit() // resize() // assign() +// push_front() +// emplace_front() // push_back() // emplace_back() // pop_front() @@ -110,6 +112,7 @@ #include "absl/base/internal/hardening.h" #include "absl/base/internal/iterator_traits.h" #include "absl/base/macros.h" +#include "absl/cleanup/cleanup.h" #include "absl/container/internal/chunked_queue.h" #include "absl/container/internal/layout.h" @@ -142,20 +145,20 @@ class chunked_queue { protected: iterator_common() = default; - explicit iterator_common(Block* b) - : block(b), ptr(b->start()), limit(b->limit()) {} + explicit iterator_common(Block* b) : block(b), ptr(b->start()) {} void Incr() { // If we do not have a next block, make ptr point one past the end of this // block. If we do have a next block, make ptr point to the first element // of the next block. ++ptr; - if (ptr == limit && block->next()) *this = iterator_common(block->next()); + if (ptr == block->limit() && block->next()) + *this = iterator_common(block->next()); } void IncrBy(size_t n) { - while (n > static_cast<size_t>(limit - ptr)) { - n -= static_cast<size_t>(limit - ptr); + while (n > static_cast<size_t>(block->limit() - ptr)) { + n -= static_cast<size_t>(block->limit() - ptr); *this = iterator_common(block->next()); } ptr += n; @@ -163,7 +166,6 @@ class chunked_queue { Block* block = nullptr; T* ptr = nullptr; - T* limit = nullptr; }; // CT can be either T or const T. @@ -403,6 +405,20 @@ class chunked_queue { // Replaces the contents with the elements from the initializer list `il`. void assign(std::initializer_list<T> il) { assign(il.begin(), il.end()); } + // Prepends the given element value to the beginning of the container. + // Invalidates `end()` iterator if the container was empty. References to + // other elements remain valid. + void push_front(const T& val) { emplace_front(val); } + void push_front(T&& val) { emplace_front(std::move(val)); } + + // Prepends a new element to the beginning of the container. + // The element is constructed in-place with `args`. + // Returns a reference to the new element. + // Invalidates `end()` iterator if the container was empty. References to + // other elements remain valid. + template <typename... A> + T& emplace_front(A&&... args); + // Appends the given element value to the end of the container. // Invalidates `end()` iterator. References to other elements remain valid. void push_back(const T& val) { emplace_back(val); } @@ -502,7 +518,7 @@ class chunked_queue { void RangeInit(Iter first, Iter last, std::input_iterator_tag) { while (first != last) { AddTailBlock(); - for (; first != last && tail_.ptr != tail_.limit; + for (; first != last && tail_.ptr != tail_.block->limit(); ++alloc_and_size_.size, ++tail_.ptr, ++first) { AllocatorTraits::construct(alloc_and_size_.allocator(), tail_.ptr, *first); @@ -538,10 +554,13 @@ class chunked_queue { } void AddTailBlock(); - size_t NewBlockSize() { - // Double the last block size and bound to [kBlockSizeMin, kBlockSizeMax]. - if (!tail_.block) return kBlockSizeMin; - return (std::min)(kBlockSizeMax, 2 * tail_.block->size()); + // Returns the capacity (in elements) to allocate for a new block adjacent to + // `b` (`head_.block` when prepending or `tail_.block` when appending). Starts + // at `kBlockSizeMin` when `b` is null, otherwise doubles `b->size()` and + // clamps to `[kBlockSizeMin, kBlockSizeMax]`. + size_t NewBlockSize(Block* b) { + if (!b) return kBlockSizeMin; + return (std::min)(kBlockSizeMax, 2 * b->size()); } T* AllocateBack(); @@ -556,16 +575,17 @@ class chunked_queue { // (1) When we have just one block: // [head_.ptr .. tail_.ptr-1] // (2) When we have multiple blocks: - // [head_.ptr .. head_.limit-1] + // [head_.ptr .. head_.block->limit()-1] // ... concatenation of all elements from interior blocks ... - // [tail_.ptr .. tail_.limit-1] + // [tail_.block->start() .. tail_.ptr-1] // // Rep invariants: // When have just one block: - // head_.limit == tail_.limit == &head_.block->element[kBlockSize] - // Always: - // head_.ptr <= head_.limit - // tail_.ptr <= tail_.limit + // head_.block->limit() == tail_.block->limit() == + // &head_.block->element[kBlockSize] + // Always (when non-empty): + // head_.ptr <= head_.block->limit() + // tail_.ptr <= tail_.block->limit() iterator head_; iterator tail_; @@ -628,11 +648,12 @@ inline chunked_queue<T, BLo, BHi, Allocator>::~chunked_queue() { template <typename T, size_t BLo, size_t BHi, typename Allocator> void chunked_queue<T, BLo, BHi, Allocator>::resize(size_t new_size) { while (new_size > size()) { - if (tail_.ptr == tail_.limit) { + if (!tail_.block || tail_.ptr == tail_.block->limit()) { AddTailBlock(); } - size_t to_add = (std::min)(new_size - size(), - static_cast<size_t>(tail_.limit - tail_.ptr)); + size_t to_add = + (std::min)(new_size - size(), + static_cast<size_t>(tail_.block->limit() - tail_.ptr)); T* start = tail_.ptr; T* limit = start + to_add; Construct(start, limit); @@ -649,10 +670,71 @@ void chunked_queue<T, BLo, BHi, Allocator>::resize(size_t new_size) { EraseAllFrom(new_end); } +template <typename T, size_t BLo, size_t BHi, typename Allocator> +template <typename... A> +T& chunked_queue<T, BLo, BHi, Allocator>::emplace_front(A&&... args) { + // Per "The set of elements in the queue" / "Rep invariants" (documented above + // `head_` and `tail_`), in a multi-block queue the head block holds + // `[head_.ptr .. head_.block->limit()-1]`, interior blocks hold all elements + // `[b->start() .. b->limit()-1]`, and the tail block holds + // `[tail_.block->start() .. tail_.ptr-1]` (as also assumed by `block_begin()` + // and `iterator_common::Incr()`). Therefore, a head block is populated from + // `b->limit() - 1` down to `b->start()` before a new head block can be + // prepended. + + // Determine the target block `b` and element slot `storage`, allocating a new + // head block if needed. + Block* b = head_.block; + T* storage; + if (empty()) { + // Empty queue: allocate the first block if none exists, or reuse the empty + // block retained by `clear()` / `pop_front()`. + if (!b) { + b = Block::New(NewBlockSize(b), &alloc_and_size_.allocator()); + } + storage = b->limit() - 1; + } else if (head_.ptr == head_.block->start()) { + // Full head block (no spare capacity before `head_.ptr`): allocate a new + // head block to prepend. + b = Block::New(NewBlockSize(b), &alloc_and_size_.allocator()); + storage = b->limit() - 1; + } else { + // Partially filled head block: use the slot immediately before `head_.ptr`. + storage = head_.ptr - 1; + } + + // Construct the new element in `storage`. + { + // Exception safety: Unlike `emplace_back()` (where `AddTailBlock()` links + // the new block into `tail_` before construction with `tail_.ptr == + // b->start()`, so the container owns it if construction throws), `b` is not + // linked into `head_` until after construction succeeds so that `head_` + // remains valid on throw. Delete `b` if construction throws. + absl::Cleanup cleanup = [&] { + if (b != head_.block) Block::Delete(b, &alloc_and_size_.allocator()); + }; + AllocatorTraits::construct(alloc_and_size_.allocator(), storage, + std::forward<A>(args)...); + std::move(cleanup).Cancel(); + } + + // Link the new block (if allocated) and update queue iterators and size. + if (empty()) { + tail_.block = b; + tail_.ptr = b->limit(); + } else if (b != head_.block) { + b->set_next(head_.block); + } + head_.block = b; + head_.ptr = storage; + ++alloc_and_size_.size; + return *storage; +} + template <typename T, size_t BLo, size_t BHi, typename Allocator> inline void chunked_queue<T, BLo, BHi, Allocator>::AddTailBlock() { - ABSL_ASSERT(tail_.ptr == tail_.limit); - auto* b = Block::New(NewBlockSize(), &alloc_and_size_.allocator()); + ABSL_ASSERT(!tail_.block || tail_.ptr == tail_.block->limit()); + auto* b = Block::New(NewBlockSize(tail_.block), &alloc_and_size_.allocator()); if (!head_.block) { ABSL_ASSERT(!tail_.block); head_ = iterator(b); @@ -665,7 +747,7 @@ inline void chunked_queue<T, BLo, BHi, Allocator>::AddTailBlock() { template <typename T, size_t BLo, size_t BHi, typename Allocator> inline T* chunked_queue<T, BLo, BHi, Allocator>::AllocateBack() { - if (tail_.ptr == tail_.limit) { + if (!tail_.block || tail_.ptr == tail_.block->limit()) { AddTailBlock(); } return tail_.ptr; @@ -677,7 +759,7 @@ inline void chunked_queue<T, BLo, BHi, Allocator>::EraseAllFrom(iterator i) { return; } ABSL_ASSERT(i.ptr); - ABSL_ASSERT(i.limit); + ABSL_ASSERT(i.block->limit()); alloc_and_size_.size -= Destroy(i.ptr, block_end(i.block)); Block* b = i.block->next(); while (b) { @@ -717,7 +799,7 @@ inline void chunked_queue<T, BLo, BHi, Allocator>::pop_front() { head_.ptr = tail_.ptr = head_.block->start(); return; } - if (head_.ptr == head_.limit) { + if (head_.ptr == head_.block->limit()) { Block* n = head_.block->next(); Block::Delete(head_.block, &alloc_and_size_.allocator()); head_ = iterator(n); diff --git a/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_benchmark.cc b/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_benchmark.cc index ee4d3c150f79..3c031edc36cc 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_benchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_benchmark.cc @@ -37,6 +37,16 @@ class forward_list_queue { forward_list_queue() = default; ~forward_list_queue() = default; + template <typename... Args> + void emplace_front(Args&&... args) { + if (list_.empty()) { + list_.emplace_front(std::forward<Args>(args)...); + tail_ = list_.begin(); + } else { + list_.emplace_front(std::forward<Args>(args)...); + } + } + template <typename... Args> void emplace_back(Args&&... args) { if (list_.empty()) { @@ -48,6 +58,7 @@ class forward_list_queue { } } + void push_front(const T& value) { emplace_front(value); } void push_back(const T& value) { emplace_back(value); } iterator begin() { return list_.begin(); } iterator end() { return list_.end(); } @@ -145,6 +156,31 @@ BENCHMARK_TEMPLATE(BM_destroy, FwdList<Element>)->Apply(CustomArgs); BENCHMARK_TEMPLATE(BM_destroy, Chunked<Element>)->Apply(CustomArgs); BENCHMARK_TEMPLATE(BM_destroy, ExpChunked<Element>)->Apply(CustomArgs); +template <class Q> +void BM_push_front(benchmark::State& state) { + const int64_t num_elements = state.range(0); + + state.SetItemsProcessed(state.max_iterations * num_elements); + for (auto s : state) { + state.PauseTiming(); + Q q; + state.ResumeTiming(); + for (int j = 0; j < num_elements; j++) q.push_front(j); + benchmark::DoNotOptimize(q); + } +} + +BENCHMARK_TEMPLATE(BM_push_front, Deque<int64_t>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, List<int64_t>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, FwdList<int64_t>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, Chunked<int64_t>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, ExpChunked<int64_t>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, Deque<Element>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, List<Element>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, FwdList<Element>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, Chunked<Element>)->Apply(CustomArgs); +BENCHMARK_TEMPLATE(BM_push_front, ExpChunked<Element>)->Apply(CustomArgs); + template <class Q> void BM_push_back(benchmark::State& state) { const int64_t num_elements = state.range(0); diff --git a/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_test.cc index 22ce94427862..b4604b6afd06 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/chunked_queue_test.cc @@ -346,6 +346,59 @@ TEST(ChunkedQueue, PushAndPop) { EXPECT_EQ(0, q.size()); } +TEST(ChunkedQueue, PushFrontAndPop) { + absl::chunked_queue<int64_t> q; + EXPECT_TRUE(q.empty()); + EXPECT_EQ(0, q.size()); + // Push enough elements to exercise exponential block growth from + // `kBlockSizeMin` (1) up to `kBlockSizeMax` (128) across multiple max-sized + // head blocks (`1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 = 255`). + constexpr int kNumElements = 500; + for (int i = 0; i < kNumElements; i++) { + q.push_front(i); + EXPECT_EQ(q.front(), i) << ": iteration " << i; + EXPECT_EQ(q.back(), 0) << ": iteration " << i; + EXPECT_FALSE(q.empty()); + EXPECT_EQ(i + 1, q.size()); + } + for (int i = 0; i < kNumElements; i++) { + EXPECT_FALSE(q.empty()); + EXPECT_EQ(kNumElements - i, q.size()); + EXPECT_EQ(q.front(), kNumElements - 1 - i); + EXPECT_EQ(q.back(), 0); + q.pop_front(); + } + EXPECT_TRUE(q.empty()); + EXPECT_EQ(0, q.size()); +} + +TEST(ChunkedQueue, PushFrontAndPushBack) { + absl::chunked_queue<int64_t, 4> q; + q.push_front(2); + q.push_back(3); + q.push_front(1); + q.push_back(4); + q.push_front(0); + q.push_back(5); + EXPECT_THAT(q, ElementsAre(0, 1, 2, 3, 4, 5)); + EXPECT_EQ(q.front(), 0); + EXPECT_EQ(q.back(), 5); + + q.pop_front(); + q.push_front(-1); + EXPECT_THAT(q, ElementsAre(-1, 1, 2, 3, 4, 5)); + + q.clear(); + EXPECT_TRUE(q.empty()); + q.push_front(10); + EXPECT_THAT(q, ElementsAre(10)); + EXPECT_EQ(q.front(), 10); + EXPECT_EQ(q.back(), 10); + q.push_front(9); + q.push_back(11); + EXPECT_THAT(q, ElementsAre(9, 10, 11)); +} + TEST(ChunkedQueue, Swap) { absl::chunked_queue<int64_t> q1; absl::chunked_queue<int64_t> q2; @@ -662,6 +715,28 @@ TEST(ChunkedQueue, Iterator_PushBackInvalidate) { EXPECT_EQ(*++i, 2); } +// Verifies that `push_front` on a non-empty queue does not invalidate +// iterators to existing elements, both when prepending into remaining space in +// the current head block (`1`) and when allocating a new head block (`0`), and +// that advancing `begin()` across the block boundary reaches the existing +// iterator `i`. +TEST(ChunkedQueue, Iterator_PushFrontInvalidate) { + absl::chunked_queue<int64_t, 2> q; + q.push_front(2); + auto i = q.begin(); + EXPECT_EQ(*i, 2); + q.push_front(1); + EXPECT_EQ(*i, 2); + q.push_front(0); + EXPECT_EQ(*i, 2); + auto j = q.begin(); + EXPECT_EQ(*j, 0); + EXPECT_EQ(*++j, 1); + EXPECT_EQ(*++j, 2); + EXPECT_TRUE(j == i); + EXPECT_TRUE(++j == q.end()); +} + struct MyType { static int constructor_calls; static int destructor_calls; @@ -707,13 +782,56 @@ TEST(ChunkedQueue, MoveObjects) { absl::chunked_queue<std::unique_ptr<int>> q; q.push_back(std::make_unique<int>(10)); q.push_back(std::make_unique<int>(11)); + q.push_front(std::make_unique<int>(9)); + EXPECT_EQ(9, *q.front()); + q.pop_front(); EXPECT_EQ(10, *q.front()); q.pop_front(); EXPECT_EQ(11, *q.front()); q.pop_front(); } +// Verifies that `emplace_front` constructs elements in-place at the front of +// the queue, returns a reference to the newly inserted element, and preserves +// existing elements at the back. +TEST(ChunkedQueue, EmplaceFrontUpdatesFrontAndReturnsReference) { + absl::chunked_queue<std::pair<int, int>> q; + auto& v1 = q.emplace_front(1, 2); + EXPECT_THAT(v1, Pair(1, 2)); + EXPECT_THAT(q.front(), Pair(1, 2)); + EXPECT_EQ(&v1, &q.front()); + EXPECT_EQ(&v1, &q.back()); + + auto& v2 = q.emplace_front(3, 4); + EXPECT_THAT(v2, Pair(3, 4)); + EXPECT_THAT(q.front(), Pair(3, 4)); + EXPECT_THAT(q.back(), Pair(1, 2)); + EXPECT_EQ(&v2, &q.front()); + EXPECT_EQ(&v1, &q.back()); +} + +// Verifies that `emplace_front` forwards move-only arguments to construct the +// element in-place. +TEST(ChunkedQueue, EmplaceFrontMoveOnlyType) { + absl::chunked_queue<std::pair<std::unique_ptr<int>, std::string>> q; + auto& v = q.emplace_front(std::make_unique<int>(11), "val12"); + EXPECT_THAT(v, Pair(Pointee(11), "val12")); + EXPECT_THAT(q.front(), Pair(Pointee(11), "val12")); +} + +TEST(ChunkedQueue, OveralignmentEmplaceFront) { + struct alignas(64) Overaligned { + int x; + int y; + }; + absl::chunked_queue<Overaligned, 1, 8> q; + for (int i = 0; i < 10; ++i) { + auto& v = q.emplace_front(Overaligned{i, i}); + EXPECT_EQ(reinterpret_cast<uintptr_t>(&v) % 64, 0); + } +} + TEST(ChunkedQueue, EmplaceBack1) { absl::chunked_queue<std::pair<int, int>> q; auto& v = q.emplace_back(1, 2); @@ -756,7 +874,6 @@ TEST(ChunkedQueue, StatelessAllocatorDoesntAffectObjectSizes) { struct MockIterator { void* block; void* ptr; - void* limit; }; MockIterator head; MockIterator tail; @@ -866,4 +983,111 @@ TEST(ChunkedQueue, StrongExceptionSafetyEmplaceBack) { } #endif +TEST(ChunkedQueue, StrongExceptionSafetyEmplaceFrontEmptyQueue) { +#ifndef ABSL_HAVE_EXCEPTIONS + GTEST_SKIP() << "Exceptions are not enabled."; +#else + int ctor_count = 0; + int dtor_count = 0; + absl::chunked_queue<ThrowingCtor> q; + + try { + q.emplace_front(5, true, &ctor_count, &dtor_count); + } catch (...) { + } + + EXPECT_TRUE(q.empty()); + EXPECT_EQ(ctor_count, 0); + EXPECT_EQ(dtor_count, 0); +#endif +} + +TEST(ChunkedQueue, StrongExceptionSafetyEmplaceFrontNewHeadBlock) { +#ifndef ABSL_HAVE_EXCEPTIONS + GTEST_SKIP() << "Exceptions are not enabled."; +#else + int ctor_count = 0; + int dtor_count = 0; + absl::chunked_queue<ThrowingCtor> q; + q.emplace_front(10, false, &ctor_count, &dtor_count); + ASSERT_EQ(q.size(), 1); + ASSERT_EQ(ctor_count, 1); + ASSERT_EQ(dtor_count, 0); + + // The first block has size 1, so the next emplace_front allocates a new head + // block and must delete it if element construction throws. + try { + q.emplace_front(15, true, &ctor_count, &dtor_count); + } catch (...) { + } + + EXPECT_EQ(q.size(), 1); + EXPECT_EQ(ctor_count, 1); + EXPECT_EQ(dtor_count, 0); + EXPECT_EQ(q.front().value, 10); + EXPECT_EQ(q.back().value, 10); + + q.clear(); + EXPECT_EQ(q.size(), 0); + EXPECT_EQ(dtor_count, 1); +#endif +} + +TEST(ChunkedQueue, StrongExceptionSafetyEmplaceFrontExistingHeadBlock) { +#ifndef ABSL_HAVE_EXCEPTIONS + GTEST_SKIP() << "Exceptions are not enabled."; +#else + int ctor_count = 0; + int dtor_count = 0; + absl::chunked_queue<ThrowingCtor, 2> q; + q.emplace_front(10, false, &ctor_count, &dtor_count); + ASSERT_EQ(q.size(), 1); + ASSERT_EQ(ctor_count, 1); + ASSERT_EQ(dtor_count, 0); + + // The head block has capacity 2 with 1 element, so the next emplace_front + // constructs into the remaining slot in the existing head block. + try { + q.emplace_front(20, true, &ctor_count, &dtor_count); + } catch (...) { + } + + EXPECT_EQ(q.size(), 1); + EXPECT_EQ(ctor_count, 1); + EXPECT_EQ(dtor_count, 0); + EXPECT_EQ(q.front().value, 10); + EXPECT_EQ(q.back().value, 10); + + q.clear(); + EXPECT_EQ(q.size(), 0); + EXPECT_EQ(dtor_count, 1); +#endif +} + +TEST(ChunkedQueue, StrongExceptionSafetyEmplaceFrontClearedQueue) { +#ifndef ABSL_HAVE_EXCEPTIONS + GTEST_SKIP() << "Exceptions are not enabled."; +#else + int ctor_count = 0; + int dtor_count = 0; + absl::chunked_queue<ThrowingCtor> q; + q.emplace_front(10, false, &ctor_count, &dtor_count); + q.clear(); + ASSERT_TRUE(q.empty()); + ASSERT_EQ(ctor_count, 1); + ASSERT_EQ(dtor_count, 1); + + // `clear()` leaves one empty block allocated; throwing while constructing + // into that retained block must leave the queue empty and valid. + try { + q.emplace_front(20, true, &ctor_count, &dtor_count); + } catch (...) { + } + + EXPECT_TRUE(q.empty()); + EXPECT_EQ(ctor_count, 1); + EXPECT_EQ(dtor_count, 1); +#endif +} + } // namespace diff --git a/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_map.h b/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_map.h index 82334094aa43..fa9194905190 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_map.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_map.h @@ -650,8 +650,33 @@ std::decay_t<Function> c_for_each_fast(flat_hash_map<K, V, H, E, A>&& c, namespace container_internal { +// These members are common to all template instantiations, so we factor them +// out into this base class to avoid re-instantiating similar templates multiple +// times, reducing compilation time. +struct FlatHashMapPolicyBase { + template <class F, class... Args> + static decltype(absl::container_internal::DecomposePair( + std::declval<F>(), std::declval<Args>()...)) + apply(F&& f, Args&&... args) { + return absl::container_internal::DecomposePair(std::forward<F>(f), + std::forward<Args>(args)...); + } + + static size_t space_used(const void*) { return 0; } + + template <class K, class V> + static V& value(std::pair<const K, V>* kv) { + return kv->second; + } + + template <class K, class V> + static const V& value(const std::pair<const K, V>* kv) { + return kv->second; + } +}; + template <class K, class V> -struct FlatHashMapPolicy { +struct FlatHashMapPolicy : FlatHashMapPolicyBase { using slot_policy = container_internal::map_slot_policy<K, V>; using slot_type = typename slot_policy::slot_type; using key_type = K; @@ -679,14 +704,6 @@ struct FlatHashMapPolicy { return slot_policy::transfer(alloc, new_slot, old_slot); } - template <class F, class... Args> - static decltype(absl::container_internal::DecomposePair( - std::declval<F>(), std::declval<Args>()...)) - apply(F&& f, Args&&... args) { - return absl::container_internal::DecomposePair(std::forward<F>(f), - std::forward<Args>(args)...); - } - template <class Hash, bool kIsDefault, size_t kSeedShift> static constexpr HashSlotFn get_hash_slot_fn() { return memory_internal::IsLayoutCompatible<K, V>::value @@ -694,12 +711,7 @@ struct FlatHashMapPolicy { : nullptr; } - static size_t space_used(const slot_type*) { return 0; } - static std::pair<const K, V>& element(slot_type* slot) { return slot->value; } - - static V& value(std::pair<const K, V>* kv) { return kv->second; } - static const V& value(const std::pair<const K, V>* kv) { return kv->second; } }; } // namespace container_internal diff --git a/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc index 6c99e8d510a2..df448a14918a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/flat_hash_set_test.cc @@ -392,6 +392,16 @@ TEST(FlatHashSet, IsDefaultHash) { EXPECT_EQ(HashtableDebugAccess<flat_hash_set<int>>::kIsAbslHash, true); EXPECT_EQ(HashtableDebugAccess<flat_hash_set<std::string>>::kIsAbslHash, true); + EXPECT_EQ(HashtableDebugAccess<flat_hash_set<std::wstring>>::kIsAbslHash, + true); + EXPECT_EQ(HashtableDebugAccess<flat_hash_set<int*>>::kIsAbslHash, true); + EXPECT_EQ( + HashtableDebugAccess<flat_hash_set<std::unique_ptr<int>>>::kIsAbslHash, + true); + using TransparentStringHashSet = + flat_hash_set<std::string, + absl::TransparentHash<std::string, std::string_view>>; + EXPECT_EQ(HashtableDebugAccess<TransparentStringHashSet>::kIsAbslHash, true); struct Hash { size_t operator()(size_t i) const { return i; } diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory.h b/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory.h index b03eb952de29..c40813141c85 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory.h @@ -195,17 +195,18 @@ decltype(std::declval<F>()(std::declval<T>())) WithConstructed(Tuple&& t, inline std::pair<std::tuple<>, std::tuple<>> PairArgs() { return {}; } template <class F, class S> std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s) { - return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)), + return {std::forward_as_tuple(std::forward<F>(f)), std::forward_as_tuple(std::forward<S>(s))}; } template <class F, class S> std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs( const std::pair<F, S>& p) { - return PairArgs(p.first, p.second); + return container_internal::PairArgs(p.first, p.second); } template <class F, class S> std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p) { - return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second)); + return container_internal::PairArgs(std::forward<F>(p.first), + std::forward<S>(p.second)); } template <class F, class S> auto PairArgs(std::piecewise_construct_t, F&& f, S&& s) @@ -215,13 +216,61 @@ auto PairArgs(std::piecewise_construct_t, F&& f, S&& s) memory_internal::TupleRef(std::forward<S>(s))); } +// Ensures the argument is a std::pair, and returns std::pair::first as const&. +// Necessary for proper handling of public subclasses of std::pair. +template <class T1, class T2> +const T1& PairConstFirst(const std::pair<T1, T2>* p) { + return p->first; +} + +template <class Ref, class Else> +using IfReference = std::conditional_t<std::is_reference_v<Ref>, Ref, Else>; + // A helper function for implementing apply() in map policies. -template <class F, class... Args> -auto DecomposePair(F&& f, Args&&... args) - -> decltype(memory_internal::DecomposePairImpl( - std::forward<F>(f), PairArgs(std::forward<Args>(args)...))) { - return memory_internal::DecomposePairImpl( - std::forward<F>(f), PairArgs(std::forward<Args>(args)...)); +template <class F, class Pair> +auto DecomposePair(F&& f, Pair&& p) -> decltype(std::forward<F>(f)( + container_internal::PairConstFirst(std::addressof(p)), + static_cast<IfReference<typename std::remove_reference_t<Pair>::first_type, + decltype((std::forward<Pair>(p).first))>>(p.first), + static_cast<IfReference<typename std::remove_reference_t<Pair>::second_type, + decltype((std::forward<Pair>(p).second))>>( + p.second))) { + // The code here is tricky because a naive std::forward<Pair>(p).second would + // incorrectly turn into an lvalue when second_type is an rvalue reference. + return std::forward<F>(f)( + container_internal::PairConstFirst(std::addressof(p)), + static_cast< + IfReference<typename std::remove_reference_t<Pair>::first_type, + decltype((std::forward<Pair>(p).first))>>(p.first), + static_cast< + IfReference<typename std::remove_reference_t<Pair>::second_type, + decltype((std::forward<Pair>(p).second))>>(p.second)); +} + +template <class F, class K, class V> +auto DecomposePair(F&& f, K&& k, V&& v) + -> decltype(std::forward<F>(f)(std::declval<const K&>(), std::forward<K>(k), + std::forward<V>(v))) { + const auto& key = k; + return std::forward<F>(f)(key, std::forward<K>(k), std::forward<V>(v)); +} + +template <class F, class TK, class TV> +auto DecomposePair( + F&& f, + std::enable_if_t<(std::tuple_size_v<remove_cvref_t<TK>> == 1 && + std::tuple_size_v<remove_cvref_t<TV>> >= 0), + std::piecewise_construct_t>, + TK&& tk, TV&& tv) + -> decltype(std::forward<F>(f)( + std::declval<const std::tuple_element_t<0, remove_cvref_t<TK>>&>(), + std::piecewise_construct, + memory_internal::TupleRef(std::forward<TK>(tk)), + memory_internal::TupleRef(std::forward<TV>(tv)))) { + const auto& key = std::get<0>(tk); + return std::forward<F>(f)(key, std::piecewise_construct, + memory_internal::TupleRef(std::forward<TK>(tk)), + memory_internal::TupleRef(std::forward<TV>(tv))); } // A helper function for implementing apply() in set policies. @@ -513,6 +562,11 @@ struct HashKey { size_t operator()(size_t seed) const { return HashElement<Hash, kIsAbsl, kSeedShift>{hash, seed}(key); } + + // Static version of the above to pass to type erased functions. + static size_t GetHash(void* data, size_t seed) { + return (*static_cast<const HashKey*>(data))(seed); + } const Hash& hash; const Key& key; }; diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc index 70fc0eab6367..f6fdd5c85589 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/container_memory_test.cc @@ -23,7 +23,6 @@ #include <tuple> #include <type_traits> #include <typeindex> -#include <typeinfo> #include <utility> #include "gmock/gmock.h" @@ -31,6 +30,7 @@ #include "absl/base/config.h" #include "absl/base/no_destructor.h" #include "absl/container/internal/test_instance_tracker.h" +#include "absl/functional/overload.h" #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" @@ -174,7 +174,7 @@ DecomposeValueImpl(int, F&& f, Arg&& arg) { } template <class F, class Arg> -const char* DecomposeValueImpl(char, F&& f, Arg&& arg) { +const char* DecomposeValueImpl(char, F&&, Arg&&) { return "not decomposable"; } @@ -208,7 +208,7 @@ DecomposePairImpl(int, F&& f, Args&&... args) { } template <class F, class... Args> -const char* DecomposePairImpl(char, F&& f, Args&&... args) { +const char* DecomposePairImpl(char, F&&, Args&&...) { return "not decomposable"; } @@ -219,14 +219,21 @@ TryDecomposePair(F&& f, Args&&... args) { } TEST(DecomposePair, Decomposable) { - auto f = [](const int& x, // NOLINT - std::piecewise_construct_t, std::tuple<int&&> k, - std::tuple<double>&& v) { - EXPECT_EQ(&x, &std::get<0>(k)); + static constexpr auto f0 = [](const int& x, // NOLINT + int&& k, double&& v) { + EXPECT_EQ(&x, &k); EXPECT_EQ(42, x); - EXPECT_EQ(0.5, std::get<0>(v)); + EXPECT_EQ(0.5, v); return 'A'; }; + static constexpr auto f = absl::Overload( + [](const int& x, // NOLINT + std::piecewise_construct_t, std::tuple<int&&> k, + std::tuple<double>&& v) { + return f0(x, std::get<0>(std::move(k)), std::get<0>(std::move(v))); + }, + f0); + EXPECT_EQ('A', TryDecomposePair(f, std::pair<int&&, double&&>(42, 0.5))); EXPECT_EQ('A', TryDecomposePair(f, 42, 0.5)); EXPECT_EQ('A', TryDecomposePair(f, std::make_pair(42, 0.5))); EXPECT_EQ('A', TryDecomposePair(f, std::piecewise_construct, diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h b/deps/v8/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h index dcf7dbd5c515..6db9e57120db 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/hash_function_defaults.h @@ -129,6 +129,14 @@ struct BasicStringHash { size_t operator()(std::basic_string_view<TChar> v) const { return absl::Hash<std::basic_string_view<TChar>>{}(v); } + + private: + friend struct absl::hash_internal::HashWithSeed; + + size_t hash_with_seed(std::basic_string_view<TChar> v, size_t seed) const { + return absl::hash_internal::HashWithSeed().hash( + absl::Hash<std::basic_string_view<TChar>>{}, v, seed); + } }; template <typename TChar> @@ -175,6 +183,15 @@ struct HashEq<T*> { size_t operator()(const U& ptr) const { return absl::Hash<const T*>{}(HashEq::ToPtr(ptr)); } + + private: + friend struct absl::hash_internal::HashWithSeed; + + template <class U> + size_t hash_with_seed(const U& ptr, size_t seed) const { + return absl::hash_internal::HashWithSeed().hash(absl::Hash<const T*>{}, + HashEq::ToPtr(ptr), seed); + } }; struct Eq { using is_transparent = void; diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/hashtable_control_bytes.h b/deps/v8/third_party/abseil-cpp/absl/container/internal/hashtable_control_bytes.h index b70ac8c827d2..34df1d4b57c1 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/hashtable_control_bytes.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/hashtable_control_bytes.h @@ -59,7 +59,7 @@ namespace container_internal { template <typename T> -uint32_t TrailingZeros(T x) { +constexpr uint32_t TrailingZeros(T x) { ABSL_ASSUME(x != 0); return static_cast<uint32_t>(countr_zero(x)); } diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h index 8301b50d0843..8984dfa046c2 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_map.h @@ -15,6 +15,8 @@ #ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_ +#include <cstddef> +#include <memory> #include <tuple> #include <type_traits> #include <utility> @@ -26,6 +28,7 @@ #include "absl/container/internal/container_memory.h" #include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export #include "absl/meta/type_traits.h" +#include "absl/numeric/bits.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -76,20 +79,27 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { // // TODO(b/402804213): Remove these traits and simplify the overloads whenever // we have a better mechanism available to handle lifetime analysis. - template <class K, bool Value, typename = void> - using LifetimeBoundK = HasValue< - Value, std::conditional_t<policy_trait_element_is_owner<Policy>::value, - std::false_type, - type_traits_internal::IsLifetimeBoundAssignment< - typename Policy::key_type, K>>>; - template <class V, bool Value, typename = void> + // + // MovableOrVoid is an optional, extra constraint (via SFINAE) to guard + // separate move-only overloads. + template <class K, bool Value, bool ExtraConstraint = true> + using LifetimeBoundK = std::bool_constant< + (ExtraConstraint || + !IsAllocMoveSameAsCopy<absl::remove_cvref_t<K>, Alloc>::value) && + HasValue<Value, std::conditional_t< + policy_trait_element_is_owner<Policy>::value, + std::false_type, + type_traits_internal::IsLifetimeBoundAssignment< + typename Policy::key_type, K>>>::value>; + template <class V, bool Value> using LifetimeBoundV = HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment< typename Policy::mapped_type, V>>; - template <class K, bool KValue, class V, bool VValue, typename... Dummy> - using LifetimeBoundKV = - std::conjunction<LifetimeBoundK<K, KValue, std::void_t<Dummy...>>, - LifetimeBoundV<V, VValue>>; + template <class K, bool KValue, class V, bool VValue, + bool ExtraConstraintK = true, bool ExtraConstraintV = true> + using LifetimeBoundKV = std::conjunction< + LifetimeBoundK<K, KValue, ExtraConstraintK && ExtraConstraintV>, + LifetimeBoundV<V, VValue>>; public: using key_type = typename Policy::key_type; @@ -122,8 +132,10 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { typename K = key_type, class V = mapped_type, \ ABSL_INTERNAL_IF_##KValue##_NOR_##VValue( \ int = (EnableIf<LifetimeBoundKV<K, KValue, V, VValue, \ - IfRRef<int KQual>::AddPtr<K>, \ - IfRRef<int VQual>::AddPtr<V>>>()), \ + !std::is_reference_v<int KQual> || \ + !std::is_reference_v<K>, \ + !std::is_reference_v<int VQual> || \ + !std::is_reference_v<V>>>()), \ ABSL_INTERNAL_SINGLE_ARG( \ int&..., \ decltype(EnableIf<LifetimeBoundKV<K, KValue, V, VValue>>()) = \ @@ -217,7 +229,8 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { // arguments as `std::unordered_map::try_emplace()`, namely that these // functions will not move from rvalue arguments if insertions do not happen. template < - class K = key_type, int = EnableIf<LifetimeBoundK<K, false, K*>>(), + class K = key_type, + int = EnableIf<LifetimeBoundK<K, false, !std::is_reference_v<K>>>(), class... Args, std::enable_if_t<!std::is_convertible_v<K, const_iterator>, int> = 0> std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args) @@ -228,7 +241,7 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { template < class K = key_type, class... Args, - EnableIf<LifetimeBoundK<K, true, K*>> = 0, + EnableIf<LifetimeBoundK<K, true, !std::is_reference_v<K>>> = 0, std::enable_if_t<!std::is_convertible_v<K, const_iterator>, int> = 0> std::pair<iterator, bool> try_emplace( key_arg<K>&& k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY_THIS, @@ -254,7 +267,8 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { return this->template try_emplace<K, 0>(k, std::forward<Args>(args)...); } - template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false, K*>>(), + template <class K = key_type, + int = EnableIf<LifetimeBoundK<K, false, !std::is_reference_v<K>>>(), class... Args> iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { @@ -262,7 +276,7 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { .first; } template <class K = key_type, class... Args, - EnableIf<LifetimeBoundK<K, true, K*>> = 0> + EnableIf<LifetimeBoundK<K, true, !std::is_reference_v<K>>> = 0> iterator try_emplace(const_iterator hint, key_arg<K>&& k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY_THIS, Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { @@ -306,7 +320,7 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { } template <class K = key_type, class P = Policy, - int = EnableIf<LifetimeBoundK<K, false, K*>>()> + int = EnableIf<LifetimeBoundK<K, false, !std::is_reference_v<K>>>()> MappedReference<P> operator[](key_arg<K>&& key) ABSL_ATTRIBUTE_LIFETIME_BOUND { // It is safe to use unchecked_deref here because try_emplace @@ -316,7 +330,7 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { try_emplace(std::forward<key_arg<K>>(key)).first)); } template <class K = key_type, class P = Policy, int&..., - EnableIf<LifetimeBoundK<K, true, K*>> = 0> + EnableIf<LifetimeBoundK<K, true, !std::is_reference_v<K>>> = 0> MappedReference<P> operator[]( key_arg<K>&& key ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY_THIS) ABSL_ATTRIBUTE_LIFETIME_BOUND { @@ -365,9 +379,33 @@ class raw_hash_map : public raw_hash_set<Policy, Params...> { ABSL_ATTRIBUTE_LIFETIME_BOUND { auto res = this->find_or_prepare_insert(k); if (res.second) { - this->emplace_at(res.first, std::piecewise_construct, - std::forward_as_tuple(std::forward<K>(k)), - std::forward_as_tuple(std::forward<Args>(args)...)); + // Try to avoid using std::tuple since that slows compilation. + // (example: https://godbolt.org/z/nefW93T6K) + + if constexpr (ShouldPreferPassByValue<std::conditional_t< + sizeof...(Args) == 0 && + std::is_same_v< + typename std::allocator_traits< + Alloc>::template rebind_alloc<char>, + std::allocator<char>>, + mapped_type, + // Trick to avoid unnecessary template instantiations. + void>>::value) { + // Common case: operator[] + // Note: This has a different run-time performance characteristic than + // the other branches, due to the usage of a temporary object. In the + // event that this causes problems (such as a performance regression or + // a stack overflow), this branch should be modified or removed. + this->emplace_at(res.first, std::forward<K>(k), mapped_type()); + } else if constexpr (sizeof...(Args) == 1) { + this->emplace_at(res.first, std::forward<K>(k), + std::forward<Args>(args)...); + } else { + // This is expensive to compile, so only use it as a last resort. + this->emplace_at(res.first, std::piecewise_construct, + std::forward_as_tuple(std::forward<K>(k)), + std::forward_as_tuple(std::forward<Args>(args)...)); + } } return {this->non_iterable_iterator_at_slot(res.first), res.second}; } diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc index fb684681a168..0837bf9c713f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc @@ -102,20 +102,12 @@ bool ShouldRehashForBugDetection(size_t capacity) { .offset() < RehashProbabilityConstant(); } -// Find a non-deterministic hash for single group table. -// Last two bits are used to find a position for a newly inserted element after -// resize. -// This function basically using H2 last bits to save on shift operation. -size_t SingleGroupTableH1(size_t hash, PerTableSeed seed) { - return hash ^ seed.seed(); -} - // Returns the offset of the new element after resize from capacity 1 to 3. -size_t Resize1To3NewOffset(size_t hash, PerTableSeed seed) { +size_t Resize1To3NewOffset(size_t hash) { // After resize from capacity 1 to 3, we always have exactly the slot with // index 1 occupied, so we need to insert either at index 0 or index 2. static_assert(SooSlotIndex() == 1); - return SingleGroupTableH1(hash, seed) & 2; + return hash & 2; } // Returns the address of the ith slot in slots where each slot occupies @@ -183,13 +175,11 @@ inline Group::NonIterableBitMaskType probe_till_first_non_full_group( return mask; } seq.next(); - ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity && "full table!"); } } -FindInfo find_first_non_full_from_h1(const ctrl_t* ctrl, size_t h1, - HashtableCapacity capacity) { - const size_t cap = capacity.capacity(); +FindInfo find_first_non_full_from_h1(size_t cap, const ctrl_t* ctrl, + size_t h1) { auto seq = probe_h1(ProbeCapacity{cap}, h1); if (IsEmptyOrDeleted(ctrl[seq.offset()])) { return {seq.offset(), /*probe_length=*/0}; @@ -205,9 +195,8 @@ FindInfo find_first_non_full_from_h1(const ctrl_t* ctrl, size_t h1, // // NOTE: this function must work with tables having both empty and deleted // slots in the same group. Such tables appear during `erase()`. -FindInfo find_first_non_full(const CommonFields& common, size_t hash) { - return find_first_non_full_from_h1(common.control(), H1(hash), - common.capacity_impl()); +FindInfo find_first_non_full(size_t cap, const ctrl_t* ctrl, size_t hash) { + return find_first_non_full_from_h1(cap, ctrl, H1(hash)); } // Same as `find_first_non_full`, but returns the mask corresponding to the @@ -285,11 +274,22 @@ void IterateOverFullSlotsImpl(const CommonFields& c, size_t slot_size, Fn cb) { } // namespace +#ifndef NDEBUG +ReentranceGuard::ReentranceGuard(CommonFields& common) + : common_(common), capacity_(common.maybe_invalid_capacity()) { + common_.set_capacity(HashtableCapacity::CreateReentrance()); +} + +ReentranceGuard::~ReentranceGuard() { common_.set_capacity(capacity_); } +#endif // NDEBUG + +void CommonFields::AssertInSooModeImpl() const { + ABSL_SWISSTABLE_ASSERT(capacity() == SooCapacity()); + ABSL_SWISSTABLE_ASSERT(!has_infoz()); +} + void CommonFields::AssertNotDebugCapacityImpl() const { const HashtableCapacity cap = maybe_invalid_capacity(); - if (ABSL_PREDICT_TRUE(cap.IsValid())) { - return; - } assert(!cap.IsReentrance() && "Reentrant container access during element construction/destruction " "is not allowed."); @@ -306,6 +306,23 @@ void CommonFields::AssertNotDebugCapacityImpl() const { } } +void CommonFields::AnnotateForBugDetectionOnMoveImpl( + CommonFields& that, const PolicyFunctions& policy) { + if (!SwisstableGenerationsEnabled()) { + return; + } + that.set_capacity(this == &that ? HashtableCapacity::CreateSelfMovedFrom() + : HashtableCapacity::CreateMovedFrom()); + if (!maybe_invalid_capacity().IsValid() || + capacity() == policy.soo_capacity()) { + return; + } + increment_generation(); + if (!empty() && should_rehash_for_bug_detection_on_move()) { + ResizeAllocatedTableWithSeedChange(*this, policy, capacity()); + } +} + void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) { ABSL_SWISSTABLE_ASSERT(ctrl[capacity] == ctrl_t::kSentinel); ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity)); @@ -387,16 +404,20 @@ CommonFields::RebalanceGrowthLeftLowerBoundLargeCapacity() { return result; } -HashtablezInfoHandle CommonFields::infoz_ptr() const { +HashtablezInfoHandle CommonFields::infoz_from_control(ctrl_t* ctrl) const { // growth_info is stored before control bytes. ABSL_SWISSTABLE_ASSERT(has_infoz()); HashtablezInfoHandle res; - void* src = reinterpret_cast<char*>(control()) - + void* src = reinterpret_cast<char*>(ctrl) - MetadataBeforeControlSize(/*has_infoz=*/true, capacity()); std::memcpy(&res, src, sizeof(HashtablezInfoHandle)); return res; } +HashtablezInfoHandle CommonFields::infoz_ptr() const { + return infoz_from_control(control()); +} + void CommonFields::set_infoz(HashtablezInfoHandle infoz) { ABSL_SWISSTABLE_ASSERT(has_infoz()); void* dst = reinterpret_cast<char*>(control()) - @@ -495,81 +516,73 @@ inline void DoSanitizeOnSetCtrl(const CommonFields& c, size_t i, ctrl_t h, // // Unlike setting it directly, this function will perform bounds checks and // mirror the value to the cloned tail if necessary. -inline void SetCtrlNoSanitizeImpl(const CommonFields& c, size_t i, ctrl_t h) { - ABSL_SWISSTABLE_ASSERT(i < c.capacity()); - ctrl_t* ctrl = c.control(); - const size_t cap = c.capacity(); +inline void SetCtrlNoSanitizeImpl(size_t cap, ctrl_t* ctrl, size_t i, + ctrl_t h) { + ABSL_SWISSTABLE_ASSERT(i < cap); + // Select the base pointer rather than the index so `ctrl + cap + 1` does not + // depend on `i`. When inlined, it can reuse `ctrl + cap` from `slot_array` + // and be hoisted out of loops. + ctrl_t* cloned_ctrl_base = i < NumClonedBytes() ? ctrl + cap + 1 : ctrl; ctrl[i] = h; - ctrl[((i - NumClonedBytes()) & cap) + (NumClonedBytes() & cap)] = h; + cloned_ctrl_base[i] = h; } -inline void SetCtrl(const CommonFields& c, size_t i, ctrl_t h, - size_t slot_size) { +inline void SetCtrl(const CommonFields& c, size_t cap, ctrl_t* ctrl, size_t i, + ctrl_t h, size_t slot_size) { ABSL_SWISSTABLE_ASSERT(!c.is_small()); DoSanitizeOnSetCtrl(c, i, h, slot_size); - SetCtrlNoSanitizeImpl(c, i, h); + SetCtrlNoSanitizeImpl(cap, ctrl, i, h); } -// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`. -inline void SetCtrl(const CommonFields& c, size_t i, h2_t h, size_t slot_size) { - SetCtrl(c, i, static_cast<ctrl_t>(h), slot_size); + +inline void SetCtrl(const CommonFields& c, size_t cap, ctrl_t* ctrl, size_t i, + h2_t h, size_t slot_size) { + SetCtrl(c, cap, ctrl, i, static_cast<ctrl_t>(h), slot_size); } // Sets `ctrl[i]` to `ctrl_t::kSentinel`. // // Unlike setting it directly, this function will perform bounds checks and // mirror the value to the cloned tail if necessary. -inline void BlockCtrl(const CommonFields& c, size_t i) { - ABSL_SWISSTABLE_ASSERT(!c.is_small()); - SetCtrlNoSanitizeImpl(c, i, ctrl_t::kSentinel); +inline void BlockCtrl(size_t cap, ctrl_t* ctrl, size_t i) { + ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(cap)); + SetCtrlNoSanitizeImpl(cap, ctrl, i, ctrl_t::kSentinel); } // Like SetCtrl, but in a single group table, we can save some operations when // setting the cloned control byte. -inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, ctrl_t h, +inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t cap, + ctrl_t* ctrl, size_t i, ctrl_t h, size_t slot_size) { - const size_t cap = c.capacity(); ABSL_SWISSTABLE_ASSERT(!c.is_small()); + ABSL_SWISSTABLE_ASSERT(cap == c.capacity()); + ABSL_SWISSTABLE_ASSERT(ctrl == c.control()); ABSL_SWISSTABLE_ASSERT(is_single_group(cap)); DoSanitizeOnSetCtrl(c, i, h, slot_size); - ctrl_t* ctrl = c.control(); ctrl[i] = h; ctrl[i + cap + 1] = h; } // Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`. -inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, h2_t h, +inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t cap, + ctrl_t* ctrl, size_t i, h2_t h, size_t slot_size) { - SetCtrlInSingleGroupTable(c, i, static_cast<ctrl_t>(h), slot_size); + SetCtrlInSingleGroupTable(c, cap, ctrl, i, static_cast<ctrl_t>(h), slot_size); } -// Like SetCtrl, but in a table with capacity >= Group::kWidth - 1, -// we can save some operations when setting the cloned control byte. -inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, ctrl_t h, - size_t slot_size) { - ABSL_SWISSTABLE_ASSERT(c.capacity() >= Group::kWidth - 1); - DoSanitizeOnSetCtrl(c, i, h, slot_size); - ctrl_t* ctrl = c.control(); - ctrl[i] = h; - ctrl[((i - NumClonedBytes()) & c.capacity()) + NumClonedBytes()] = h; -} -// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`. -inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, h2_t h, - size_t slot_size) { - SetCtrlInLargeTable(c, i, static_cast<ctrl_t>(h), slot_size); -} - -void BlockControlBytes(CommonFields& common, size_t blocked_element_count) { - const size_t capacity = common.capacity(); +void BlockControlBytes(size_t capacity, ctrl_t* ctrl, + size_t blocked_element_count) { + ABSL_ASSUME(blocked_element_count <= + HashtableInlineData::kMaxBlockedElementCount); while (blocked_element_count > 0) { - BlockCtrl(common, capacity - blocked_element_count); + BlockCtrl(capacity, ctrl, capacity - blocked_element_count); --blocked_element_count; } } void* DropDeletesWithoutResizeAndPrepareInsert( CommonFields& common, const PolicyFunctions& __restrict policy, - size_t new_hash) { + size_t new_hash, size_t capacity) { void* set = &common; - const size_t capacity = common.capacity(); + ABSL_SWISSTABLE_ASSERT(common.capacity() == capacity); ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity)); ABSL_SWISSTABLE_ASSERT(!is_single_group(capacity)); ABSL_ASSUME(capacity > kMaxSmallCapacity); @@ -594,7 +607,7 @@ void* DropDeletesWithoutResizeAndPrepareInsert( // repeat procedure for current slot with moved from element (target) const size_t blocked_element_count = common.blocked_element_count(); ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity); - BlockControlBytes(common, blocked_element_count); + BlockControlBytes(capacity, ctrl, blocked_element_count); const void* hash_fn = policy.hash_fn(common); auto hasher = policy.hash_slot; auto transfer_n = policy.transfer_n; @@ -617,14 +630,14 @@ void* DropDeletesWithoutResizeAndPrepareInsert( } if (!IsDeleted(ctrl[i])) continue; const size_t hash = (*hasher)(hash_fn, slot_ptr, common.seed().seed()); - const FindInfo target = find_first_non_full(common, hash); + const FindInfo target = find_first_non_full(capacity, ctrl, hash); const size_t new_i = target.offset; total_probe_length += target.probe_length; // Verify if the old and new i fall within the same group wrt the hash. // If they do, we don't need to move the object as it falls already in the // best probe we can. - const size_t probe_offset = probe(common, hash).offset(); + const size_t probe_offset = probe(ProbeCapacity{capacity}, hash).offset(); const h2_t h2 = H2(hash); const auto probe_index = [probe_offset, capacity](size_t pos) { return ((pos - probe_offset) & capacity) / Group::kWidth; @@ -632,7 +645,7 @@ void* DropDeletesWithoutResizeAndPrepareInsert( // Element doesn't move. if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) { - SetCtrlInLargeTable(common, i, h2, slot_size); + SetCtrl(common, capacity, ctrl, i, h2, slot_size); continue; } @@ -641,14 +654,14 @@ void* DropDeletesWithoutResizeAndPrepareInsert( // Transfer element to the empty spot. // SetCtrl poisons/unpoisons the slots so we have to call it at the // right time. - SetCtrlInLargeTable(common, new_i, h2, slot_size); + SetCtrl(common, capacity, ctrl, new_i, h2, slot_size); (*transfer_n)(set, new_slot_ptr, slot_ptr, 1); - SetCtrlInLargeTable(common, i, ctrl_t::kEmpty, slot_size); + SetCtrl(common, capacity, ctrl, i, ctrl_t::kEmpty, slot_size); // Initialize or change empty space id. tmp_space_id = i; } else { ABSL_SWISSTABLE_ASSERT(IsDeleted(ctrl[new_i])); - SetCtrlInLargeTable(common, new_i, h2, slot_size); + SetCtrl(common, capacity, ctrl, new_i, h2, slot_size); // Until we are done rehashing, DELETED marks previously FULL slots. if (tmp_space_id == kUnknownId) { @@ -672,20 +685,20 @@ void* DropDeletesWithoutResizeAndPrepareInsert( // Prepare insert for the new element. PrepareInsertCommon(common); ResetGrowthLeft(capacity, common.size() + blocked_element_count, common); - FindInfo find_info = find_first_non_full(common, new_hash); - SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), slot_size); + FindInfo find_info = find_first_non_full(capacity, ctrl, new_hash); + SetCtrl(common, capacity, ctrl, find_info.offset, H2(new_hash), slot_size); common.infoz().RecordInsertMiss(new_hash, find_info.probe_length); common.infoz().RecordRehash(total_probe_length); return SlotAddress(slot_array, find_info.offset, slot_size); } -bool WasNeverFull(CommonFields& c, size_t index) { - if (is_single_group(c.capacity())) { +bool WasNeverFull(size_t capacity, ctrl_t* ctrl, size_t index) { + if (is_single_group(capacity)) { return true; } - const size_t index_before = (index - Group::kWidth) & c.capacity(); - const auto empty_after = Group(c.control() + index).MaskEmpty(); - const auto empty_before = Group(c.control() + index_before).MaskEmpty(); + const size_t index_before = (index - Group::kWidth) & capacity; + const auto empty_after = Group(ctrl + index).MaskEmpty(); + const auto empty_before = Group(ctrl + index_before).MaskEmpty(); // We count how many consecutive non empties we have to the right and to the // left of `it`. If the sum is >= kWidth then there is at least one probe @@ -700,12 +713,10 @@ bool WasNeverFull(CommonFields& c, size_t index) { // control bytes are kEmpty except for the kSentinel bytes. // If the table has blocked elements, last `blocked_element_count` are set to // kSentinel. -void ResetCtrl(CommonFields& common, size_t slot_size, - size_t blocked_element_count) { - ABSL_SWISSTABLE_ASSERT(IsCapacityValidForBlockedElements(common.capacity()) || +void ResetCtrl(size_t capacity, ctrl_t* ctrl, void* slot_array, + size_t slot_size, size_t blocked_element_count) { + ABSL_SWISSTABLE_ASSERT(IsCapacityValidForBlockedElements(capacity) || blocked_element_count == 0); - const size_t capacity = common.capacity(); - ctrl_t* ctrl = common.control(); static constexpr size_t kTwoGroupCapacity = 2 * Group::kWidth - 1; if (ABSL_PREDICT_TRUE(capacity <= kTwoGroupCapacity)) { if (IsSmallCapacity(capacity)) return; @@ -721,9 +732,9 @@ void ResetCtrl(CommonFields& common, size_t slot_size, capacity + 1 + NumClonedBytes()); } ctrl[capacity] = ctrl_t::kSentinel; - SanitizerPoisonMemoryRegion(common.slot_array(capacity), + SanitizerPoisonMemoryRegion(slot_array, slot_size * (capacity - blocked_element_count)); - BlockControlBytes(common, blocked_element_count); + BlockControlBytes(capacity, ctrl, blocked_element_count); } // Initializes control bytes for growing from capacity 1 to 3. @@ -811,7 +822,7 @@ void ClearBackingArrayNoReuse(CommonFields& c, template <bool kSooEnabled> void* SingleSlotAddress(CommonFields& c) { - return kSooEnabled ? c.soo_data() : c.slot_array(/*capacity=*/1); + return kSooEnabled ? c.soo_data() : c.single_non_soo_slot(); } template <bool kSooEnabled> @@ -844,7 +855,7 @@ void DestructNonSoo(CommonFields& c, const DtorPolicy& __restrict policy, if (c.is_small()) { if (!c.empty()) { static_assert(kMaxSmallCapacity == 1); - policy.destroy_slot(&c, c.slot_array(/*capacity=*/1)); + policy.destroy_slot(&c, c.single_non_soo_slot()); } } else { DestroySlots(c, policy.slot_size, policy.destroy_slot); @@ -874,14 +885,16 @@ void EraseMetaOnlyLarge(CommonFields& c, size_t index, size_t slot_size) { c.decrement_size(); c.infoz().RecordErase(); - if (WasNeverFull(c, index)) { - SetCtrl(c, index, ctrl_t::kEmpty, slot_size); + const size_t cap = c.capacity(); + ctrl_t* ctrl = c.control(); + if (WasNeverFull(cap, ctrl, index)) { + SetCtrl(c, cap, ctrl, index, ctrl_t::kEmpty, slot_size); c.OverwriteFullAsEmpty(); return; } c.OverwriteFullAsDeleted(); - SetCtrlInLargeTable(c, index, ctrl_t::kDeleted, slot_size); + SetCtrl(c, cap, ctrl, index, ctrl_t::kDeleted, slot_size); } void ClearBackingArray(CommonFields& c, @@ -891,9 +904,12 @@ void ClearBackingArray(CommonFields& c, if (reuse) { const size_t blocked_element_count = c.blocked_element_count(); c.set_size_to_zero(); - ABSL_SWISSTABLE_ASSERT(c.capacity() > policy.soo_capacity()); - ResetCtrl(c, policy.slot_size, blocked_element_count); - ResetGrowthLeft(c.capacity(), blocked_element_count, c); + size_t cap = c.capacity(); + ctrl_t* ctrl = c.control(); + void* slot_array = c.slot_array(cap); + ABSL_SWISSTABLE_ASSERT(cap > policy.soo_capacity()); + ResetCtrl(cap, ctrl, slot_array, policy.slot_size, blocked_element_count); + ResetGrowthLeft(cap, blocked_element_count, c); ABSL_SWISSTABLE_ASSERT(c.blocked_element_count() == blocked_element_count); c.infoz().RecordStorageChanged(0, c.capacity()); } else { @@ -974,6 +990,35 @@ void Destruct(CommonFields& c, const DtorPolicy& __restrict policy) { Destruct<kSooEnabled>(c, policy, kStandardDeallocBackingArrayFn); } +void AssertHashEqConsistentImpl(CommonFields& common, const void* hash_fn, + HashSlotFn hash_slot, size_t slot_size, + bool soo_enabled, size_t hash, const void* key, + EqualToKeyFn equal) { + const size_t seed = common.seed().seed(); + + const auto assert_consistent = [&](const ctrl_t*, void* slot) { + const bool is_key_equal = equal(&common, key, slot); + if (!is_key_equal) return; + + [[maybe_unused]] const bool is_hash_equal = + hash == hash_slot(hash_fn, slot, seed); + assert((!is_key_equal || is_hash_equal) && + "eq(k1, k2) must imply that hash(k1) == hash(k2). " + "hash/eq functors are inconsistent."); + }; + + if (common.is_small()) { + assert_consistent( + /*unused*/ nullptr, + soo_enabled ? SingleSlotAddress</*kSooEnabled=*/true>(common) + : SingleSlotAddress</*kSooEnabled=*/false>(common)); + return; + } + // We only do validation for small tables so that it's constant time. + if (common.capacity() > 16) return; + IterateOverFullSlots(common, slot_size, assert_consistent); +} + namespace { // Iterates over full slots in old table, finds new positions for them and @@ -984,7 +1029,8 @@ namespace { size_t FindNewPositionsAndTransferSlots( CommonFields& common, const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, void* old_slots, size_t old_capacity) { - void* new_slots = common.slot_array(common.capacity()); + void* new_slots = common.is_small() ? common.single_non_soo_slot() + : common.slot_array(common.capacity()); const void* hash_fn = policy.hash_fn(common); const size_t slot_size = policy.slot_size; const size_t seed = common.seed().seed(); @@ -995,8 +1041,10 @@ size_t FindNewPositionsAndTransferSlots( if (common.is_small()) { target = FindInfo{0, 0}; } else { - target = find_first_non_full(common, hash); - SetCtrl(common, target.offset, H2(hash), slot_size); + const size_t cap = common.capacity(); + ctrl_t* ctrl = common.control(); + target = find_first_non_full(cap, ctrl, hash); + SetCtrl(common, cap, ctrl, target.offset, H2(hash), slot_size); } policy.transfer_n(&common, SlotAddress(new_slots, target.offset, slot_size), slot, 1); @@ -1016,10 +1064,9 @@ size_t FindNewPositionsAndTransferSlots( return total_probe_length; } -void ReportGrowthToInfozImpl(CommonFields& common, HashtablezInfoHandle infoz, - size_t hash, size_t total_probe_length, - size_t distance_from_desired) { - ABSL_SWISSTABLE_ASSERT(infoz.IsSampled()); +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void ReportGrowthToInfozImpl( + CommonFields& common, HashtablezInfoHandle infoz, size_t hash, + size_t total_probe_length, size_t distance_from_desired) { infoz.RecordStorageChanged(common.size() - 1, common.capacity()); infoz.RecordRehash(total_probe_length); infoz.RecordInsertMiss(hash, distance_from_desired); @@ -1028,25 +1075,88 @@ void ReportGrowthToInfozImpl(CommonFields& common, HashtablezInfoHandle infoz, } // Specialization to avoid passing two 0s from hot function. -ABSL_ATTRIBUTE_NOINLINE void ReportSingleGroupTableGrowthToInfoz( - CommonFields& common, HashtablezInfoHandle infoz, size_t hash) { - ReportGrowthToInfozImpl(common, infoz, hash, /*total_probe_length=*/0, +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void +ReportSingleGroupTableGrowthToInfoz(CommonFields& common, ctrl_t* old_ctrl, + size_t hash) { + ReportGrowthToInfozImpl(common, common.infoz_from_control(old_ctrl), hash, + /*total_probe_length=*/0, /*distance_from_desired=*/0); } -ABSL_ATTRIBUTE_NOINLINE void ReportGrowthToInfoz(CommonFields& common, - HashtablezInfoHandle infoz, - size_t hash, - size_t total_probe_length, - size_t distance_from_desired) { - ReportGrowthToInfozImpl(common, infoz, hash, total_probe_length, - distance_from_desired); +// Specialization that computes hash and generates new seed. +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void +ReportSingleElementTableGrowthToInfozAndForceSample( + CommonFields& common, const PolicyFunctions& __restrict policy, + void* hasher, HashForKeyFn get_hash) { + HashtablezInfoHandle infoz = + ForcedTrySample(policy.slot_size, policy.key_size, policy.value_size, + policy.soo_capacity()); + common.generate_new_seed(/*has_infoz=*/true); + ReportGrowthToInfozImpl(common, infoz, get_hash(hasher, common.seed().seed()), + /*total_probe_length=*/0, + /*distance_from_desired=*/0); } -ABSL_ATTRIBUTE_NOINLINE void ReportResizeToInfoz(CommonFields& common, - HashtablezInfoHandle infoz, - size_t total_probe_length) { - ABSL_SWISSTABLE_ASSERT(infoz.IsSampled()); +// Outlines cold infoz recording so callers do not inline infoz extraction +// or spill registers across SetCtrl. `common` is first and `hash` is third to +// match argument order in callers. +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void ReportInsertMissToInfoz( + CommonFields& common, size_t probe_length, size_t hash) { + common.infoz().RecordInsertMiss(hash, probe_length); +} + +// Outlines cold infoz recording with computation of hash so callers can +// avoid calling the hash function and seed extraction in the hot path. +// `common` is first and `get_hash` is third to match argument order in callers. +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void +ReportInsertMissToInfozAndComputeHash(CommonFields& common, size_t probe_length, + void* hasher, HashForKeyFn get_hash) { + common.infoz().RecordInsertMiss(get_hash(hasher, common.seed().seed()), + probe_length); +} + +// Outlines cold infoz recording with computation of probe_length and slot +// address so callers can skip tracking probe_length and tail-call without +// keeping the slot address live across a call (which would cost a callee-saved +// register and a stack frame on every insert). +// (Returning a value passed in by the caller doesn't work: the compiler infers +// that and keeps the caller's copy alive across the call instead.) +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void* +ReportInsertMissToInfozAndGetSlot(CommonFields& common, + const PolicyFunctions& __restrict policy, + size_t hash, size_t target) { + const size_t cap = common.capacity(); + auto seq = probe(ProbeCapacity{cap}, hash); + while (((target - seq.offset()) & cap) >= Group::kWidth) { + seq.next(); + } + common.infoz().RecordInsertMiss(hash, seq.index()); + return SlotAddress(common.slot_array(cap), target, policy.slot_size); +} + +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void ReportGrowthToInfoz( + CommonFields& common, ctrl_t* old_ctrl, size_t hash, + size_t total_probe_length, size_t distance_from_desired) { + ReportGrowthToInfozImpl(common, common.infoz_from_control(old_ctrl), hash, + total_probe_length, distance_from_desired); +} + +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void ReportResizeToInfoz( + CommonFields& common, HashtablezInfoHandle infoz, + size_t total_probe_length) { + infoz.RecordStorageChanged(common.size(), common.capacity()); + infoz.RecordRehash(total_probe_length); + common.set_has_infoz(); + common.set_infoz(infoz); +} + +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void +ReportResizeToInfozAndForceSample(CommonFields& common, + const PolicyFunctions& __restrict policy, + size_t total_probe_length) { + HashtablezInfoHandle infoz = + ForcedTrySample(policy.slot_size, policy.key_size, policy.value_size, + policy.soo_capacity()); infoz.RecordStorageChanged(common.size(), common.capacity()); infoz.RecordRehash(total_probe_length); common.set_has_infoz(); @@ -1060,10 +1170,8 @@ struct BackingArrayPtrs { BackingArrayPtrs AllocBackingArray(CommonFields& common, const PolicyFunctions& __restrict policy, - size_t new_capacity, bool has_infoz, - void* alloc, size_t blocked_element_count) { - RawHashSetLayout layout(new_capacity, policy.slot_size, policy.slot_align, - has_infoz, blocked_element_count); + const RawHashSetLayout& layout, + void* alloc) { // Perform a direct call in the common case to allow for profile-guided // heap optimization (PGHO) to understand which allocation function is used. constexpr size_t kDefaultAlignment = BackingArrayAlignment(alignof(size_t)); @@ -1083,6 +1191,17 @@ BackingArrayPtrs AllocBackingArray(CommonFields& common, mem + layout.slot_offset()}; } +BackingArrayPtrs AllocBackingArray(CommonFields& common, + const PolicyFunctions& __restrict policy, + size_t new_capacity, bool has_infoz, + void* alloc, size_t blocked_element_count) { + return AllocBackingArray( + common, policy, + RawHashSetLayout(new_capacity, policy.slot_size, policy.slot_align, + has_infoz, blocked_element_count), + alloc); +} + void ResizeEmptyNonAllocatedTableImpl(CommonFields& common, const PolicyFunctions& __restrict policy, size_t new_capacity, @@ -1094,14 +1213,8 @@ void ResizeEmptyNonAllocatedTableImpl(CommonFields& common, ABSL_SWISSTABLE_ASSERT(common.capacity() == policy.soo_capacity()); ABSL_SWISSTABLE_ASSERT(common.empty()); const size_t slot_size = policy.slot_size; - HashtablezInfoHandle infoz; - const bool should_sample = - policy.is_hashtablez_eligible && (force_infoz || ShouldSampleNextTable()); - if (ABSL_PREDICT_FALSE(should_sample)) { - infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size, - policy.soo_capacity()); - } - const bool has_infoz = infoz.IsSampled(); + const bool has_infoz = + policy.is_hashtablez_enabled && (force_infoz || ShouldSampleNextTable()); void* alloc = policy.get_char_alloc(common); common.set_capacity(new_capacity); @@ -1111,11 +1224,12 @@ void ResizeEmptyNonAllocatedTableImpl(CommonFields& common, common.set_control(new_ctrl); common.generate_new_seed(has_infoz); - ResetCtrl(common, slot_size, blocked_element_count); + ResetCtrl(new_capacity, new_ctrl, new_slots, slot_size, + blocked_element_count); ResetGrowthLeft(new_capacity, blocked_element_count, common); if (ABSL_PREDICT_FALSE(has_infoz)) { - ReportResizeToInfoz(common, infoz, 0); + ReportResizeToInfozAndForceSample(common, policy, 0); } } @@ -1141,8 +1255,10 @@ void InsertOldSooSlotAndInitializeControlBytes( SanitizerUnpoisonMemoryRegion(target_slot, policy.slot_size); policy.transfer_n(&c, target_slot, c.soo_data(), 1); c.set_control(new_ctrl); - ResetCtrl(c, policy.slot_size, /*blocked_element_count=*/0); - SetCtrl(c, offset, H2(soo_slot_hash), policy.slot_size); + ResetCtrl(new_capacity, new_ctrl, new_slots, policy.slot_size, + /*blocked_element_count=*/0); + SetCtrl(c, new_capacity, new_ctrl, offset, H2(soo_slot_hash), + policy.slot_size); } enum class ResizeFullSooTableSamplingMode { @@ -1175,11 +1291,12 @@ void ResizeFullSooTable(CommonFields& common, bool has_infoz = false; if (sampling_mode == ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled) { - if (ABSL_PREDICT_FALSE(policy.is_hashtablez_eligible)) { + if (policy.is_hashtablez_enabled) { infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size, policy.soo_capacity()); } + // If the table was not sampled, do not resize. if (!infoz.IsSampled()) return; has_infoz = true; } @@ -1358,9 +1475,10 @@ template <typename ProbedItem> ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertImpl( CommonFields& c, const PolicyFunctions& __restrict policy, const ProbedItem* start, const ProbedItem* end, void* old_slots) { - const HashtableCapacity new_capacity = c.capacity_impl(); + ABSL_SWISSTABLE_ASSERT(!c.is_small()); + const size_t new_capacity = c.capacity(); - void* new_slots = c.slot_array(new_capacity.capacity()); + void* new_slots = c.slot_array(new_capacity); ctrl_t* new_ctrl = c.control(); size_t total_probe_length = 0; @@ -1369,18 +1487,19 @@ ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertImpl( for (; start < end; ++start) { const FindInfo target = find_first_non_full_from_h1( - new_ctrl, static_cast<size_t>(start->h1), new_capacity); + new_capacity, new_ctrl, static_cast<size_t>(start->h1)); total_probe_length += target.probe_length; const size_t old_index = static_cast<size_t>(start->source_offset); const size_t new_i = target.offset; - ABSL_SWISSTABLE_ASSERT(old_index < new_capacity.capacity() / 2); - ABSL_SWISSTABLE_ASSERT(new_i < new_capacity.capacity()); + ABSL_SWISSTABLE_ASSERT(old_index < new_capacity / 2); + ABSL_SWISSTABLE_ASSERT(new_i < new_capacity); ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[new_i])); void* src_slot = SlotAddress(old_slots, old_index, slot_size); void* dst_slot = SlotAddress(new_slots, new_i, slot_size); SanitizerUnpoisonMemoryRegion(dst_slot, slot_size); transfer_n(&c, dst_slot, src_slot, 1); - SetCtrlInLargeTable(c, new_i, static_cast<h2_t>(start->h2), slot_size); + SetCtrl(c, new_capacity, new_ctrl, new_i, static_cast<h2_t>(start->h2), + slot_size); } return total_probe_length; } @@ -1396,7 +1515,7 @@ constexpr size_t kNoMarkedElementsSentinel = ~size_t{}; ABSL_ATTRIBUTE_NOINLINE size_t ProcessProbedMarkedElements( CommonFields& c, const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl, void* old_slots, size_t start) { - size_t old_capacity = PreviousCapacity(c.capacity()); + const size_t old_capacity = PreviousCapacity(c.capacity()); const size_t slot_size = policy.slot_size; void* new_slots = c.slot_array(c.capacity()); size_t total_probe_length = 0; @@ -1410,11 +1529,13 @@ ABSL_ATTRIBUTE_NOINLINE size_t ProcessProbedMarkedElements( } void* src_slot = SlotAddress(old_slots, old_index, slot_size); const size_t hash = hash_slot(hash_fn, src_slot, seed); - const FindInfo target = find_first_non_full(c, hash); + const size_t new_capacity = c.capacity(); + ctrl_t* new_ctrl = c.control(); + const FindInfo target = find_first_non_full(new_capacity, new_ctrl, hash); total_probe_length += target.probe_length; const size_t new_i = target.offset; void* dst_slot = SlotAddress(new_slots, new_i, slot_size); - SetCtrlInLargeTable(c, new_i, H2(hash), slot_size); + SetCtrl(c, new_capacity, new_ctrl, new_i, H2(hash), slot_size); transfer_n(&c, dst_slot, src_slot, 1); } return total_probe_length; @@ -1587,17 +1708,19 @@ class ProbedItemEncoder { template <typename Encoder> size_t GrowToNextCapacity(CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { + ctrl_t* old_ctrl, void* old_slots, + size_t new_capacity) { using ProbedItem = typename Encoder::ProbedItem; - ABSL_SWISSTABLE_ASSERT(common.capacity() <= ProbedItem::kMaxNewCapacity); + ABSL_SWISSTABLE_ASSERT(common.capacity() == new_capacity); + ABSL_SWISSTABLE_ASSERT(new_capacity <= ProbedItem::kMaxNewCapacity); Encoder encoder(old_ctrl); policy.transfer_unprobed_elements_to_next_capacity( - common, old_ctrl, old_slots, &encoder, - [](void* probed_storage, h2_t h2, size_t source_offset, size_t h1) { + common, old_ctrl, &encoder, old_slots, PreviousCapacity(new_capacity), + [](void* probed_storage, size_t hash, size_t source_offset) { auto encoder_ptr = static_cast<Encoder*>(probed_storage); - encoder_ptr->EncodeItem(ProbedItem(h2, source_offset, h1)); + encoder_ptr->EncodeItem(ProbedItem(H2(hash), source_offset, H1(hash))); }); - InitializeMirroredControlBytes(common.control(), common.capacity()); + InitializeMirroredControlBytes(common.control(), new_capacity); return encoder.DecodeAndInsertToTable(common, policy, old_slots); } @@ -1606,32 +1729,34 @@ size_t GrowToNextCapacity(CommonFields& common, // Returns total probe length. size_t GrowToNextCapacityThatFitsInLocalBuffer( CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { - ABSL_SWISSTABLE_ASSERT(common.capacity() <= kMaxLocalBufferNewCapacity); + ctrl_t* old_ctrl, void* old_slots, size_t new_capacity) { + ABSL_SWISSTABLE_ASSERT(new_capacity <= kMaxLocalBufferNewCapacity); return GrowToNextCapacity< ProbedItemEncoder<ProbedItem4Bytes, /*kGuaranteedFitToBuffer=*/true>>( - common, policy, old_ctrl, old_slots); + common, policy, old_ctrl, old_slots, new_capacity); } // Grows to next capacity with different encodings. Returns total probe length. // These functions are useful to simplify profile analysis. size_t GrowToNextCapacity4BytesEncoder(CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { + ctrl_t* old_ctrl, void* old_slots, + size_t new_capacity) { return GrowToNextCapacity<ProbedItemEncoder<ProbedItem4Bytes>>( - common, policy, old_ctrl, old_slots); + common, policy, old_ctrl, old_slots, new_capacity); } size_t GrowToNextCapacity8BytesEncoder(CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { + ctrl_t* old_ctrl, void* old_slots, + size_t new_capacity) { return GrowToNextCapacity<ProbedItemEncoder<ProbedItem8Bytes>>( - common, policy, old_ctrl, old_slots); + common, policy, old_ctrl, old_slots, new_capacity); } size_t GrowToNextCapacity16BytesEncoder( CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { + ctrl_t* old_ctrl, void* old_slots, size_t new_capacity) { return GrowToNextCapacity<ProbedItemEncoder<ProbedItem16Bytes>>( - common, policy, old_ctrl, old_slots); + common, policy, old_ctrl, old_slots, new_capacity); } // Grows to next capacity for tables with relatively large capacity so that we @@ -1639,16 +1764,19 @@ size_t GrowToNextCapacity16BytesEncoder( // total probe length. size_t GrowToNextCapacityOverflowLocalBuffer( CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { - const size_t new_capacity = common.capacity(); + ctrl_t* old_ctrl, void* old_slots, size_t new_capacity) { + ABSL_SWISSTABLE_ASSERT(common.capacity() == new_capacity); if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem4Bytes::kMaxNewCapacity)) { - return GrowToNextCapacity4BytesEncoder(common, policy, old_ctrl, old_slots); + return GrowToNextCapacity4BytesEncoder(common, policy, old_ctrl, old_slots, + new_capacity); } if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem8Bytes::kMaxNewCapacity)) { - return GrowToNextCapacity8BytesEncoder(common, policy, old_ctrl, old_slots); + return GrowToNextCapacity8BytesEncoder(common, policy, old_ctrl, old_slots, + new_capacity); } // 16 bytes encoding supports the maximum swisstable capacity. - return GrowToNextCapacity16BytesEncoder(common, policy, old_ctrl, old_slots); + return GrowToNextCapacity16BytesEncoder(common, policy, old_ctrl, old_slots, + new_capacity); } // Dispatches to the appropriate `GrowToNextCapacity*` function based on the @@ -1656,14 +1784,15 @@ size_t GrowToNextCapacityOverflowLocalBuffer( ABSL_ATTRIBUTE_NOINLINE size_t GrowToNextCapacityDispatch(CommonFields& common, const PolicyFunctions& __restrict policy, - ctrl_t* old_ctrl, void* old_slots) { - const size_t new_capacity = common.capacity(); + ctrl_t* old_ctrl, void* old_slots, + size_t new_capacity) { + ABSL_SWISSTABLE_ASSERT(common.capacity() == new_capacity); if (ABSL_PREDICT_TRUE(new_capacity <= kMaxLocalBufferNewCapacity)) { return GrowToNextCapacityThatFitsInLocalBuffer(common, policy, old_ctrl, - old_slots); + old_slots, new_capacity); } else { return GrowToNextCapacityOverflowLocalBuffer(common, policy, old_ctrl, - old_slots); + old_slots, new_capacity); } } @@ -1687,7 +1816,8 @@ void IncrementSmallSize(CommonFields& common, void* Grow1To3AndPrepareInsert(CommonFields& common, const PolicyFunctions& __restrict policy, - absl::FunctionRef<size_t(size_t)> get_hash) { + void* hasher, HashForKeyFn get_hash, void* alloc, + bool has_infoz, void* new_slots) { // TODO(b/413062340): Refactor to reuse more code with // GrowSooTableToNextCapacityAndPrepareInsert. ABSL_SWISSTABLE_ASSERT(common.capacity() == 1); @@ -1697,51 +1827,55 @@ void* Grow1To3AndPrepareInsert(CommonFields& common, ABSL_SWISSTABLE_ASSERT(common.blocked_element_count() == 0); constexpr size_t kOldCapacity = 1; constexpr size_t kNewCapacity = NextCapacity(kOldCapacity); - void* old_slots = common.slot_array(kOldCapacity); - - const size_t slot_size = policy.slot_size; - const size_t slot_align = policy.slot_align; - void* alloc = policy.get_char_alloc(common); - HashtablezInfoHandle infoz = common.infoz(); - const bool has_infoz = infoz.IsSampled(); - common.set_capacity(kNewCapacity); - - const auto [new_ctrl, new_slots] = - AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc, - /*blocked_element_count=*/0); - common.set_control(new_ctrl); - SanitizerPoisonMemoryRegion(new_slots, kNewCapacity * slot_size); + ctrl_t* new_ctrl = + static_cast<ctrl_t*>(new_slots) - NumControlBytes(kNewCapacity); if (ABSL_PREDICT_TRUE(!has_infoz)) { // When we're sampled, we already have a seed. common.generate_new_seed(/*has_infoz=*/false); } - const size_t new_hash = get_hash(common.seed().seed()); + const size_t new_hash = get_hash(hasher, common.seed().seed()); h2_t new_h2 = H2(new_hash); - size_t orig_hash = - policy.hash_slot(policy.hash_fn(common), old_slots, common.seed().seed()); - size_t offset = Resize1To3NewOffset(new_hash, common.seed()); + // `hash_fn` is in separate statement, so the hash_slot function pointer is + // not loaded before the hash_fn call. + const void* hash_fn = policy.hash_fn(common); + size_t orig_hash = policy.hash_slot( + hash_fn, common.single_non_soo_slot(), common.seed().seed()); + size_t offset = Resize1To3NewOffset(new_hash); InitializeThreeElementsControlBytes(H2(orig_hash), new_h2, offset, new_ctrl); + // Read `old_slots` and `slot_size` after the hash calls to avoid keeping + // them live across indirect calls. + void* old_slots = common.single_non_soo_slot(); + // old_slots == old_ctrl in case of capacity == 1. + ctrl_t* old_ctrl = static_cast<ctrl_t*>(old_slots); + common.set_control(new_ctrl); + const size_t slot_size = policy.slot_size; + SanitizerPoisonMemoryRegion(new_slots, kNewCapacity * slot_size); + void* old_element_target = NextSlot(new_slots, slot_size); + // Compute `new_element_target_slot` before `transfer_n` to free up registers + // of `new_slots` and `offset`. + void* new_element_target_slot = SlotAddress(new_slots, offset, slot_size); SanitizerUnpoisonMemoryRegion(old_element_target, slot_size); policy.transfer_n(&common, old_element_target, old_slots, 1); - - void* new_element_target_slot = SlotAddress(new_slots, offset, slot_size); SanitizerUnpoisonMemoryRegion(new_element_target_slot, slot_size); - DeallocBackingArrayImpl(alloc, kOldCapacity, - // old_slots == old_ctrl in case of capacity == 1. - static_cast<ctrl_t*>(old_slots), slot_size, - slot_align, has_infoz, - /*blocked_element_count=*/0, policy.dealloc); + // Group `common` updates together so `inline_data_` is modified in a single + // load-store sequence. + common.set_capacity(kNewCapacity); + common.InitGrowthLeftNoDeleted(kNewCapacity - 2, kNewCapacity); PrepareInsertCommon(common); ABSL_SWISSTABLE_ASSERT(common.size() == 2); - common.InitGrowthLeftNoDeleted(kNewCapacity - 2, kNewCapacity); if (ABSL_PREDICT_FALSE(has_infoz)) { - ReportSingleGroupTableGrowthToInfoz(common, infoz, new_hash); + ReportSingleGroupTableGrowthToInfoz(common, old_ctrl, new_hash); } + // Deallocate after `ReportSingleGroupTableGrowthToInfoz`, because it reads + // infoz from old_ctrl. + DeallocBackingArrayImpl(alloc, kOldCapacity, old_ctrl, slot_size, + policy.slot_align, has_infoz, + /*blocked_element_count=*/0, policy.dealloc); return new_element_target_slot; } @@ -1749,30 +1883,37 @@ void* Grow1To3AndPrepareInsert(CommonFields& common, // Returns the offset of the new element. void* GrowToNextCapacityAndPrepareInsert( CommonFields& common, const PolicyFunctions& __restrict policy, - size_t new_hash) { - const size_t old_capacity = common.capacity(); + size_t new_hash, size_t old_capacity) { + ABSL_SWISSTABLE_ASSERT(common.capacity() == old_capacity); ABSL_SWISSTABLE_ASSERT(common.GetGrowthLeftTotalSlow(old_capacity) == 0); ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity()); ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(old_capacity)); ABSL_ASSUME(old_capacity > kMaxSmallCapacity); + // Call `get_char_alloc` first so no local variables need to be spilled + // across the indirect call, which may alias `common`. + void* alloc = policy.get_char_alloc(common); const size_t new_capacity = NextCapacity(old_capacity); + ABSL_ASSUME(new_capacity > kMaxSmallCapacity); + + const auto [new_ctrl, new_slots] = + AllocBackingArray(common, policy, new_capacity, common.has_infoz(), alloc, + /*blocked_element_count=*/0); + // Read old `common` fields after `AllocBackingArray` to avoid spilling them + // across the call. ctrl_t* old_ctrl = common.control(); void* old_slots = common.slot_array(old_capacity); size_t old_blocked_element_count = common.blocked_element_count(); + const size_t old_size = common.size(); - HashtablezInfoHandle infoz = common.infoz(); - const bool has_infoz = infoz.IsSampled(); + // Group all `common` updates together so `inline_data_` is modified in a + // single load-store sequence. common.set_capacity(new_capacity); common.set_blocked_element_count_to_zero(); - const size_t slot_size = policy.slot_size; - const size_t slot_align = policy.slot_align; - void* alloc = policy.get_char_alloc(common); - - const auto [new_ctrl, new_slots] = - AllocBackingArray(common, policy, new_capacity, has_infoz, alloc, - /*blocked_element_count=*/0); common.set_control(new_ctrl); + PrepareInsertCommon(common); + ResetGrowthLeft(new_capacity, old_size + 1, common); + const size_t slot_size = policy.slot_size; SanitizerPoisonMemoryRegion(new_slots, new_capacity * slot_size); h2_t new_h2 = H2(new_hash); @@ -1780,105 +1921,141 @@ void* GrowToNextCapacityAndPrepareInsert( FindInfo find_info; if (ABSL_PREDICT_TRUE(is_single_group(new_capacity))) { size_t offset; - const size_t old_size = common.size(); GrowIntoSingleGroupShuffleControlBytes(old_ctrl, old_capacity, old_blocked_element_count, new_ctrl, new_capacity); // We put the new element either at the beginning or at the end of the // table with approximately equal probability. - offset = - SingleGroupTableH1(new_hash, common.seed()) & 1 ? 0 : new_capacity - 1; + offset = new_hash & 1 ? 0 : new_capacity - 1; ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[offset])); - SetCtrlInSingleGroupTable(common, offset, new_h2, policy.slot_size); + SetCtrlInSingleGroupTable(common, new_capacity, new_ctrl, offset, new_h2, + slot_size); find_info = FindInfo{offset, 0}; // Single group tables have all slots full on resize. So we can transfer // all slots without checking the control bytes. - ABSL_SWISSTABLE_ASSERT(common.size() + old_blocked_element_count == + ABSL_SWISSTABLE_ASSERT(old_size + old_blocked_element_count == old_capacity); void* target = NextSlot(new_slots, slot_size); SanitizerUnpoisonMemoryRegion(target, old_size * slot_size); policy.transfer_n(&common, target, old_slots, old_size); } else { - total_probe_length = - GrowToNextCapacityDispatch(common, policy, old_ctrl, old_slots); - find_info = find_first_non_full(common, new_hash); - SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.slot_size); + total_probe_length = GrowToNextCapacityDispatch(common, policy, old_ctrl, + old_slots, new_capacity); + find_info = find_first_non_full(new_capacity, new_ctrl, new_hash); + SetCtrl(common, new_capacity, new_ctrl, find_info.offset, new_h2, + slot_size); } ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity()); - DeallocBackingArrayImpl(alloc, old_capacity, old_ctrl, slot_size, slot_align, - has_infoz, old_blocked_element_count, policy.dealloc); - PrepareInsertCommon(common); - ResetGrowthLeft(new_capacity, common.size(), common); + // Reload `has_infoz` to avoid spilling across the indirect call. + const bool has_infoz = common.has_infoz(); if (ABSL_PREDICT_FALSE(has_infoz)) { - ReportGrowthToInfoz(common, infoz, new_hash, total_probe_length, + ReportGrowthToInfoz(common, old_ctrl, new_hash, total_probe_length, find_info.probe_length); } - return SlotAddress(new_slots, find_info.offset, policy.slot_size); + // Deallocate after `ReportGrowthToInfoz`, because it reads infoz from + // old_ctrl. + DeallocBackingArrayImpl(alloc, old_capacity, old_ctrl, slot_size, + policy.slot_align, has_infoz, + old_blocked_element_count, policy.dealloc); + return SlotAddress(new_slots, find_info.offset, slot_size); } } // namespace +RawHashSetLayout RawHashSetLayout::CreateForSmallNonSooGrowth(size_t size, + size_t slot_size, + size_t slot_align, + bool has_infoz) { + ABSL_SWISSTABLE_ASSERT(size <= 1); + static_assert(NumControlBytes(1) == 0); + const size_t num_control_bytes = size * NumControlBytes(3); + static_assert(NextCapacity(0) == 1); + static_assert(NextCapacity(1) == 3); + const size_t new_capacity = NextCapacity(size); + const size_t slots_size = new_capacity * slot_size; + + // Since `GrowthInfoSizeForCapacity` is 0 for capacities 1 and 3, compute + // `metadata_size` directly without `MetadataBeforeControlSize` to avoid its + // `ABSL_PREDICT_FALSE(has_infoz)` branch and allow a branchless shift. + static_assert(GrowthInfoSizeForCapacity(1) == 0); + static_assert(GrowthInfoSizeForCapacity(3) == 0); + const size_t metadata_size = + (has_infoz ? sizeof(HashtablezInfoHandle) + sizeof(uint64_t) : 0) + + NumGenerationBytes(); + ABSL_SWISSTABLE_ASSERT(metadata_size == + MetadataBeforeControlSize(has_infoz, new_capacity)); + + RawHashSetLayout layout(uninitialized_tag_t{}); + layout.slot_offset_ = + AlignUpTo(metadata_size + num_control_bytes, slot_align); + layout.control_offset_ = layout.slot_offset_ - num_control_bytes; + layout.generation_offset_ = layout.control_offset_ - NumGenerationBytes(); + layout.alloc_size_ = layout.slot_offset_ + slots_size; + return layout; +} + void* PrepareInsertSmallNonSoo(CommonFields& common, const PolicyFunctions& __restrict policy, - absl::FunctionRef<size_t(size_t)> get_hash) { + void* hasher, HashForKeyFn get_hash) { ABSL_SWISSTABLE_ASSERT(common.is_small()); ABSL_SWISSTABLE_ASSERT(!policy.soo_enabled); - if (common.capacity() == 1) { - if (common.empty()) { - IncrementSmallSizeNonSoo(common, policy); - if (common.has_infoz()) { - common.infoz().RecordInsertMiss(get_hash(common.seed().seed()), - /*distance_from_desired=*/0); - } - return common.slot_array(/*capacity=*/1); - } else { - return Grow1To3AndPrepareInsert(common, policy, get_hash); + const bool is_empty = common.empty(); + if (common.capacity() == 1 && is_empty) { + IncrementSmallSizeNonSoo(common, policy); + // Compute before `RecordInsertMissCold` to avoid reloading `control_`. + void* res = common.single_non_soo_slot(); + // Call NOINLINE function to move infoz instructions out of line. + if (common.has_infoz()) { + ReportInsertMissToInfozAndComputeHash(common, /*probe_length=*/0, hasher, + get_hash); } + return res; } - // Growing from 0 to 1 capacity. - ABSL_SWISSTABLE_ASSERT(common.capacity() == 0); - constexpr size_t kNewCapacity = 1; - - common.set_capacity(kNewCapacity); - HashtablezInfoHandle infoz; - const bool should_sample = - policy.is_hashtablez_eligible && ShouldSampleNextTable(); - if (ABSL_PREDICT_FALSE(should_sample)) { - infoz = ForcedTrySample(policy.slot_size, policy.key_size, - policy.value_size, policy.soo_capacity()); - } - const bool has_infoz = infoz.IsSampled(); + const size_t size = common.size(); + const bool has_infoz = + is_empty ? (policy.is_hashtablez_enabled && ShouldSampleNextTable()) + : common.has_infoz(); void* alloc = policy.get_char_alloc(common); - - const auto [new_ctrl, new_slots] = - AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc, - /*blocked_element_count=*/0); - common.set_control(new_ctrl); - - static_assert(NextCapacity(0) == 1); - PrepareInsertCommon(common); - - if (ABSL_PREDICT_FALSE(has_infoz)) { - common.generate_new_seed(/*has_infoz=*/true); - ReportSingleGroupTableGrowthToInfoz(common, infoz, - get_hash(common.seed().seed())); + void* new_slots = + AllocBackingArray( + common, policy, + RawHashSetLayout::CreateForSmallNonSooGrowth( + size, policy.slot_size, policy.slot_align, has_infoz), + alloc) + .slots; + if (is_empty) { + // Growing from 0 to 1 capacity. + ABSL_SWISSTABLE_ASSERT(common.capacity() == 0); + constexpr size_t kNewCapacity = 1; + common.set_capacity(kNewCapacity); + common.set_control(static_cast<ctrl_t*>(new_slots)); + + static_assert(NextCapacity(0) == 1); + PrepareInsertCommon(common); + + if (ABSL_PREDICT_FALSE(has_infoz)) { + ReportSingleElementTableGrowthToInfozAndForceSample( + common, policy, hasher, get_hash); + } + return new_slots; } - return new_slots; + return Grow1To3AndPrepareInsert(common, policy, hasher, get_hash, alloc, + has_infoz, new_slots); } namespace { // Called whenever the table needs to vacate empty slots either by removing // tombstones via rehash or growth to next capacity. -ABSL_ATTRIBUTE_NOINLINE -void* RehashOrGrowToNextCapacityAndPrepareInsert( +ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void* +RehashOrGrowToNextCapacityAndPrepareInsert( CommonFields& common, const PolicyFunctions& __restrict policy, - size_t new_hash) { + size_t new_hash, size_t cap) { ABSL_SWISSTABLE_ASSERT(!common.GetGrowthInfoLowerBound().HasNoDeleted()); - const size_t cap = common.capacity(); + ABSL_SWISSTABLE_ASSERT(common.capacity() == cap); ABSL_ASSUME(cap > 0); // Do these calculations in 64-bit to avoid overflow. if (common.size() * uint64_t{32} <= @@ -1924,10 +2101,11 @@ void* RehashOrGrowToNextCapacityAndPrepareInsert( // 762 | 149836 0.37 13 | 148559 0.74 190 // 807 | 149736 0.39 14 | 151107 0.39 14 // 852 | 150204 0.42 15 | 151019 0.42 15 - return DropDeletesWithoutResizeAndPrepareInsert(common, policy, new_hash); + return DropDeletesWithoutResizeAndPrepareInsert(common, policy, new_hash, + cap); } else { // Otherwise grow the container. - return GrowToNextCapacityAndPrepareInsert(common, policy, new_hash); + return GrowToNextCapacityAndPrepareInsert(common, policy, new_hash, cap); } } @@ -1944,23 +2122,31 @@ void* PrepareInsertLargeSlow(CommonFields& common, if (ABSL_PREDICT_TRUE( growth_info_lower_bound.HasNoGrowthLeftAndNoDeleted())) { // Table without deleted slots (>95% cases) that needs to be resized. - return GrowToNextCapacityAndPrepareInsert(common, policy, hash); + return GrowToNextCapacityAndPrepareInsert(common, policy, hash, cap); } if (ABSL_PREDICT_FALSE( growth_info_lower_bound.HasNoGrowthLeftAndHaveDeleted())) { // Table with deleted slots that needs to be rehashed or resized. - return RehashOrGrowToNextCapacityAndPrepareInsert(common, policy, hash); + return RehashOrGrowToNextCapacityAndPrepareInsert(common, policy, hash, + cap); } // Covers two cases: // 1. Table with deleted slots that has space for the inserting element. // 2. Table without deleted slots that has space and GrowthInfoView was // rebalanced. - FindInfo target = find_first_non_full(common, hash); + const size_t slot_size = policy.slot_size; + ctrl_t* ctrl = common.control(); + FindInfo target = find_first_non_full(cap, ctrl, hash); + // Read `ctrl` before `PrepareInsertCommon` so `common` updates coalesce. + common.OverwriteControlAsFull(ctrl[target.offset]); PrepareInsertCommon(common); - common.OverwriteControlAsFull(common.control()[target.offset]); - SetCtrlInLargeTable(common, target.offset, H2(hash), policy.slot_size); - common.infoz().RecordInsertMiss(hash, target.probe_length); - return SlotAddress(common.slot_array(cap), target.offset, policy.slot_size); + // Compute before `SetCtrl*` to avoid reloading `control_`. + void* res = SlotAddress(common.slot_array(cap), target.offset, slot_size); + SetCtrl(common, cap, ctrl, target.offset, H2(hash), slot_size); + if (common.has_infoz()) { + ReportInsertMissToInfoz(common, target.probe_length, hash); + } + return res; } // Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()), @@ -1972,19 +2158,23 @@ void* PrepareInsertLargeSlow(CommonFields& common, ABSL_ATTRIBUTE_NOINLINE void* GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert( CommonFields& common, const PolicyFunctions& __restrict policy, - absl::FunctionRef<size_t(size_t)> get_hash) { + void* hasher, HashForKeyFn get_hash) { const size_t kNewCapacity = NextCapacity(SooCapacity()); ResizeEmptyNonAllocatedTableImpl(common, policy, kNewCapacity, /*blocked_element_count=*/0, /*force_infoz=*/true); PrepareInsertCommon(common); common.OverwriteEmptyAsFull(); - const size_t new_hash = get_hash(common.seed().seed()); - SetCtrlInSingleGroupTable(common, SooSlotIndex(), H2(new_hash), - policy.slot_size); - common.infoz().RecordInsertMiss(new_hash, /*distance_from_desired=*/0); - return SlotAddress(common.slot_array(kNewCapacity), SooSlotIndex(), - policy.slot_size); + const size_t new_hash = get_hash(hasher, common.seed().seed()); + // Compute before `SetCtrl*` to avoid reloading `control_`. + void* res = SlotAddress(common.slot_array(kNewCapacity), SooSlotIndex(), + policy.slot_size); + SetCtrlInSingleGroupTable(common, kNewCapacity, common.control(), + SooSlotIndex(), H2(new_hash), policy.slot_size); + if (common.has_infoz()) { + ReportInsertMissToInfoz(common, /*probe_length=*/0, new_hash); + } + return res; } // Returns the number of elements to block for the given capacity and reserved @@ -2077,13 +2267,15 @@ void ResizeAllocatedTableWithSeedChange( const size_t old_capacity = common.capacity(); ctrl_t* const old_ctrl = common.control(); - void* const old_slots = common.slot_array(old_capacity); + void* const old_slots = IsSmallCapacity(old_capacity) + ? common.single_non_soo_slot() + : common.slot_array(old_capacity); const size_t old_blocked_element_count = common.blocked_element_count(); const size_t slot_size = policy.slot_size; const size_t slot_align = policy.slot_align; HashtablezInfoHandle infoz = common.infoz(); - const bool has_infoz = infoz.IsSampled(); + const bool has_infoz = common.has_infoz(); void* alloc = policy.get_char_alloc(common); common.set_capacity(new_capacity); @@ -2095,7 +2287,8 @@ void ResizeAllocatedTableWithSeedChange( common.generate_new_seed(has_infoz); size_t total_probe_length = 0; - ResetCtrl(common, slot_size, /*blocked_element_count=*/0); + ResetCtrl(new_capacity, new_ctrl, new_slots, slot_size, + /*blocked_element_count=*/0); ABSL_SWISSTABLE_ASSERT(old_capacity > 0); total_probe_length = FindNewPositionsAndTransferSlots( common, policy, old_ctrl, old_slots, old_capacity); @@ -2112,19 +2305,25 @@ void ResizeAllocatedTableWithSeedChange( template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy> void* GrowSooTableToNextCapacityAndPrepareInsert( CommonFields& common, const PolicyFunctions& __restrict policy, - absl::FunctionRef<size_t(size_t)> get_hash, bool force_sampling) { + void* hasher, HashForKeyFn get_hash, bool force_sampling) { AssertSoo(common, policy); if (ABSL_PREDICT_FALSE(force_sampling)) { // The table is empty, it is only used for forced sampling of SOO tables. return GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert( - common, policy, get_hash); + common, policy, hasher, get_hash); } ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity()); static constexpr size_t kNewCapacity = NextCapacity(SooCapacity()); - const size_t slot_size = policy.slot_size; - void* alloc = policy.get_char_alloc(common); - common.set_capacity(kNewCapacity); + // Generate the seed and compute hashes before `AllocBackingArray` so + // `hasher`, `get_hash`, and `new_ctrl`/`new_slots` do not need to be spilled + // across calls. + common.generate_new_seed(/*has_infoz=*/false); + const size_t new_hash = get_hash(hasher, common.seed().seed()); + const void* hash_fn = policy.hash_fn(common); + const h2_t soo_slot_h2 = + H2(policy.hash_slot(hash_fn, common.soo_data(), common.seed().seed())); + void* alloc = policy.get_char_alloc(common); // Since the table is not empty, it will not be sampled. // The decision to sample was already made during the first insertion. // @@ -2133,21 +2332,21 @@ void* GrowSooTableToNextCapacityAndPrepareInsert( const auto [new_ctrl, new_slots] = AllocBackingArray( common, policy, kNewCapacity, /*has_infoz=*/false, alloc, /*blocked_element_count=*/0); - + // Group `common` updates together after `AllocBackingArray` so `inline_data_` + // is modified in a single load-store sequence. + common.set_capacity(kNewCapacity); + common.InitGrowthLeftNoDeleted(kNewCapacity - 2, kNewCapacity); PrepareInsertCommon(common); ABSL_SWISSTABLE_ASSERT(common.size() == 2); - common.InitGrowthLeftNoDeleted(kNewCapacity - 2, kNewCapacity); - common.generate_new_seed(/*has_infoz=*/false); - const h2_t soo_slot_h2 = H2(policy.hash_slot( - policy.hash_fn(common), common.soo_data(), common.seed().seed())); - const size_t new_hash = get_hash(common.seed().seed()); - const size_t offset = Resize1To3NewOffset(new_hash, common.seed()); + const size_t offset = Resize1To3NewOffset(new_hash); InitializeThreeElementsControlBytes(soo_slot_h2, H2(new_hash), offset, new_ctrl); + const size_t slot_size = policy.slot_size; SanitizerPoisonMemoryRegion(new_slots, slot_size * kNewCapacity); void* target_slot = SlotAddress(new_slots, SooSlotIndex(), slot_size); + void* new_slot = SlotAddress(new_slots, offset, slot_size); SanitizerUnpoisonMemoryRegion(target_slot, slot_size); if constexpr (TransferUsesMemcpy) { // Target slot is placed at index 1, but capacity is at @@ -2171,7 +2370,6 @@ void* GrowSooTableToNextCapacityAndPrepareInsert( // Full SOO table couldn't be sampled. If SOO table is sampled, it would // have been resized to the next capacity. ABSL_SWISSTABLE_ASSERT(!common.infoz().IsSampled()); - void* new_slot = SlotAddress(new_slots, offset, slot_size); SanitizerUnpoisonMemoryRegion(new_slot, slot_size); return new_slot; } @@ -2194,7 +2392,7 @@ void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy, } if (common.size() <= policy.soo_capacity()) { // When the table is already sampled, we keep it sampled. - if (common.infoz().IsSampled()) { + if (common.has_infoz()) { static constexpr size_t kInitialSampledCapacity = NextCapacity(SooCapacity()); if (cap > kInitialSampledCapacity) { @@ -2202,11 +2400,13 @@ void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy, kInitialSampledCapacity); } // This asserts that we didn't lose sampling coverage in `resize`. - ABSL_SWISSTABLE_ASSERT(common.infoz().IsSampled()); + ABSL_SWISSTABLE_ASSERT(common.has_infoz()); return; } + // Reducing from large capacity to SOO. ABSL_SWISSTABLE_ASSERT(slot_size <= sizeof(HeapOrSoo)); ABSL_SWISSTABLE_ASSERT(policy.slot_align <= alignof(HeapOrSoo)); + ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(cap)); HeapOrSoo tmp_slot; size_t begin_offset = FindFirstFullSlot(0, cap, common.control()); policy.transfer_n( @@ -2246,9 +2446,10 @@ void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy, void Copy(CommonFields& common, const PolicyFunctions& __restrict policy, const CommonFields& other, - absl::FunctionRef<void(void*, const void*)> copy_fn) { + void (*copy_fn)(void* set, void* dst, const void* src)) { + other.AssertNotDebugCapacity(); const size_t size = other.size(); - ABSL_SWISSTABLE_ASSERT(size > 0); + if (size == 0) return; const size_t soo_capacity = policy.soo_capacity(); const size_t slot_size = policy.slot_size; const bool soo_enabled = policy.soo_enabled; @@ -2262,15 +2463,16 @@ void Copy(CommonFields& common, const PolicyFunctions& __restrict policy, const void* other_slot = other_capacity <= soo_capacity ? other.soo_data() : IsSmallCapacity(other_capacity) - ? other.slot_array(other_capacity) + ? other.single_non_soo_slot() : SlotAddress(other.slot_array(other_capacity), FindFirstFullSlot(0, other_capacity, other.control()), slot_size); - copy_fn(soo_enabled ? common.soo_data() + copy_fn(&common, + soo_enabled ? common.soo_data() : SingleSlotAddress</*kSooEnabled=*/false>(common), other_slot); - if (soo_enabled && policy.is_hashtablez_eligible && + if (soo_enabled && policy.is_hashtablez_enabled && ShouldSampleNextTable()) { GrowFullSooTableToNextCapacityForceSampling(common, policy); } @@ -2294,11 +2496,13 @@ void Copy(CommonFields& common, const PolicyFunctions& __restrict policy, // The table is guaranteed to be empty, so we can do faster than // a full `insert`. const size_t hash = (*hasher)(hash_fn, that_slot, seed); - FindInfo target = find_first_non_full(common, hash); - infoz.RecordInsertMiss(hash, target.probe_length); + ctrl_t* ctrl = common.control(); + FindInfo target = find_first_non_full(cap, ctrl, hash); offset = target.offset; - SetCtrl(common, offset, H2(hash), slot_size); - copy_fn(SlotAddress(target_slot_array, offset, slot_size), that_slot); + SetCtrl(common, cap, ctrl, offset, H2(hash), slot_size); + infoz.RecordInsertMiss(hash, target.probe_length); + copy_fn(&common, SlotAddress(target_slot_array, offset, slot_size), + that_slot); common.maybe_increment_generation_on_insert(); }); common.increment_size(size); @@ -2334,7 +2538,7 @@ void* PrepareInsertLargeImpl(CommonFields& common, const PolicyFunctions& __restrict policy, size_t hash, Group::NonIterableBitMaskType mask_empty, - FindInfo target_group) { + size_t target_group_offset) { ABSL_SWISSTABLE_ASSERT(!common.is_small()); // When there are no deleted slots in the table // and growth_left is positive, we can insert at the first @@ -2347,27 +2551,35 @@ void* PrepareInsertLargeImpl(CommonFields& common, common.OverwriteEmptyAsFull(); const size_t cap = common.capacity(); ABSL_ASSUME(cap > kMaxSmallCapacity); - target_group.offset += mask_empty.LowestBitSet(); - target_group.offset &= cap; - SetCtrl(common, target_group.offset, H2(hash), policy.slot_size); - common.infoz().RecordInsertMiss(hash, target_group.probe_length); - return SlotAddress(common.slot_array(cap), target_group.offset, - policy.slot_size); + target_group_offset += mask_empty.LowestBitSet(); + target_group_offset &= cap; + // Compute before `SetCtrl` to avoid reloading `control_`. + void* res = SlotAddress(common.slot_array(cap), target_group_offset, + policy.slot_size); + SetCtrl(common, cap, common.control(), target_group_offset, H2(hash), + policy.slot_size); + // Call NOINLINE function to move infoz instructions out of line. + if (common.has_infoz()) { + return ReportInsertMissToInfozAndGetSlot(common, policy, hash, + target_group_offset); + } + return res; } } // namespace void* PrepareInsertLarge(CommonFields& common, const PolicyFunctions& __restrict policy, size_t hash, Group::NonIterableBitMaskType mask_empty, - FindInfo target_group) { + size_t target_group_offset) { // NOLINTNEXTLINE(misc-static-assert) ABSL_SWISSTABLE_ASSERT(!SwisstableGenerationsEnabled()); - return PrepareInsertLargeImpl(common, policy, hash, mask_empty, target_group); + return PrepareInsertLargeImpl(common, policy, hash, mask_empty, + target_group_offset); } void* PrepareInsertLargeGenerationsEnabled( CommonFields& common, const PolicyFunctions& __restrict policy, size_t hash, - Group::NonIterableBitMaskType mask_empty, FindInfo target_group, + Group::NonIterableBitMaskType mask_empty, size_t target_group_offset, absl::FunctionRef<size_t(size_t)> recompute_hash) { // NOLINTNEXTLINE(misc-static-assert) ABSL_SWISSTABLE_ASSERT(SwisstableGenerationsEnabled()); @@ -2379,10 +2591,13 @@ void* PrepareInsertLargeGenerationsEnabled( // Move to a different heap allocation in order to detect bugs. ResizeAllocatedTableWithSeedChange(common, policy, cap); hash = recompute_hash(common.seed().seed()); + FindInfo target_group; std::tie(target_group, mask_empty) = find_first_non_full_group(common, hash); + target_group_offset = target_group.offset; } - return PrepareInsertLargeImpl(common, policy, hash, mask_empty, target_group); + return PrepareInsertLargeImpl(common, policy, hash, mask_empty, + target_group_offset); } namespace { @@ -2410,27 +2625,20 @@ constexpr bool VerifyOptimalMemcpySizeForSooSlotTransferRange(size_t left, } } // namespace -// Extern template instantiation for inline function. -template size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index, - size_t old_capacity, - ctrl_t* new_ctrl, - size_t new_capacity); - // We need to instantiate ALL possible template combinations because we define // the function in the cc file. template void* GrowSooTableToNextCapacityAndPrepareInsert<0, false>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, - bool); + CommonFields&, const PolicyFunctions&, void*, HashForKeyFn, bool); template void* GrowSooTableToNextCapacityAndPrepareInsert< - OptimalMemcpySizeForSooSlotTransfer(1), true>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, - bool); + OptimalMemcpySizeForSooSlotTransfer(1), true>(CommonFields&, + const PolicyFunctions&, void*, + HashForKeyFn, bool); static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(2, 3)); template void* GrowSooTableToNextCapacityAndPrepareInsert< - OptimalMemcpySizeForSooSlotTransfer(3), true>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, - bool); + OptimalMemcpySizeForSooSlotTransfer(3), true>(CommonFields&, + const PolicyFunctions&, void*, + HashForKeyFn, bool); #if UINTPTR_MAX == UINT32_MAX static_assert(MaxSooSlotSize() == 4); @@ -2438,9 +2646,9 @@ static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(2, 4)); #else static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(4, 8)); template void* GrowSooTableToNextCapacityAndPrepareInsert< - OptimalMemcpySizeForSooSlotTransfer(8), true>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, - bool); + OptimalMemcpySizeForSooSlotTransfer(8), true>(CommonFields&, + const PolicyFunctions&, void*, + HashForKeyFn, bool); static_assert(MaxSooSlotSize() == 8); #endif @@ -2480,6 +2688,28 @@ template void Destruct</*kSooEnabled=*/false>(CommonFields& c, template void Destruct</*kSooEnabled=*/false>(CommonFields& c, const DtorPolicy& policy); +// Extern template instantiation for inline functions. +template size_t TryFindNewIndexWithoutProbing(size_t hash, size_t old_index, + size_t old_capacity, + ctrl_t* new_ctrl, + size_t new_capacity); +template void AssertIsFull(const ctrl_t* const& ctrl, const void* slot, + GenerationType generation, + const GenerationType* generation_ptr, + const char* operation); +template void AssertIsValidForComparison(const ctrl_t* const& ctrl, + const void* slot, + GenerationType generation, + const GenerationType* generation_ptr); +template bool AreItersFromSameContainer(const ctrl_t* const& ctrl_a, + const ctrl_t* const& ctrl_b, + const void* slot_a, const void* slot_b); +template void AssertSameContainer(const ctrl_t* const& ctrl_a, + const ctrl_t* const& ctrl_b, + const void* slot_a, const void* slot_b, + const GenerationType* generation_ptr_a, + const GenerationType* generation_ptr_b); + } // namespace container_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h index ca0e83d3b1fa..2d43ec49552a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h @@ -181,6 +181,7 @@ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ #include <algorithm> +#include <array> #include <cassert> #include <cmath> #include <cstddef> @@ -191,9 +192,12 @@ #include <iterator> #include <limits> #include <memory> +#include <optional> #include <tuple> #include <type_traits> +#include <typeindex> #include <utility> +#include <variant> #include "absl/base/attributes.h" #include "absl/base/casts.h" @@ -222,6 +226,7 @@ #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" #include "absl/numeric/bits.h" +#include "absl/strings/string_view.h" #include "absl/utility/utility.h" #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L @@ -255,6 +260,63 @@ namespace container_internal { assert((CONDITION) && "Try enabling sanitizers.") #endif +// ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE(a, b) +// +// Informs the compiler that the two pointer arguments point into separately +// allocated storage (either different variable definitions or different dynamic +// storage allocations), allowing the compiler to assume they do not alias for +// optimization purposes. Differences from __restrict: +// - __restrict only applies to the pointer itself, not the pointed-to object. +// - This macro allows the compiler to optimize caller code, not just the +// pointer dereferences of a function argument within that function. +// +// WARNING: If the arguments point into the same storage, the program has +// undefined behavior. Note that the definition of "storage" here refers to the +// outermost enclosing allocation of any particular object (for example, it is +// never correct to call this macro passing the addresses of fields in the same +// struct, elements of the same array, objects on the same arena block, etc.). +// Note that in the example below, the annotation will affect callers of +// SetFirstAndGetSize as well (they may be mis-compiled if the arguments are not +// from separate allocations). +// +// See +// https://clang.llvm.org/docs/LanguageExtensions.html#builtin-assume-separate-storage +// +// Example: +// +// class Buffer { +// public: +// size_t* data() { +// // Safe because `data_` is allocated via `::operator new`, so it is +// // guaranteed to be in a separate allocation from `*this`. +// ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE(data_, this); +// return data_; +// } +// size_t size() const { return size_; } +// +// private: +// size_t* data_ = new size_t[10]; +// size_t size_ = 10; +// }; +// +// size_t SetFirstAndGetSize(Buffer& buf) { +// size_t n = buf.size(); +// buf.data()[0] = n; +// // After inlining, the compiler knows storing to `buf.data()[0]` cannot +// // clobber `buf.size_`, and can return `n` without reloading `buf.size_`. +// return buf.size(); +// } +#if ABSL_HAVE_BUILTIN(__builtin_assume_separate_storage) +#define ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE(a, b) \ + __builtin_assume_separate_storage(a, b) +#elif ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L +#define ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE(a, b) \ + (decltype((void)(a), (void)(b))()) +#else +#define ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE(a, b) \ + (false ? ((void)(a), (void)(b)) : void()) +#endif + // We use uint8_t so we don't need to worry about padding. using GenerationType = uint8_t; @@ -266,6 +328,20 @@ constexpr GenerationType NextGeneration(GenerationType generation) { return ++generation == SentinelEmptyGeneration() ? ++generation : generation; } +#ifdef NDEBUG +inline constexpr bool kIsDebug = false; +#else +inline constexpr bool kIsDebug = true; +#endif + +constexpr bool SwisstableDebugEnabled() { +#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || ABSL_OPTION_HARDENED == 1 + return true; +#else + return kIsDebug; +#endif +} + #ifdef ABSL_SWISSTABLE_ENABLE_GENERATIONS constexpr bool SwisstableGenerationsEnabled() { return true; } constexpr size_t NumGenerationBytes() { return sizeof(GenerationType); } @@ -275,10 +351,11 @@ constexpr size_t NumGenerationBytes() { return 0; } #endif constexpr bool SwisstableGenerationsOrDebugEnabled() { -#ifndef NDEBUG - return true; -#endif - return SwisstableGenerationsEnabled(); + if constexpr (kIsDebug) { + return true; + } else { + return SwisstableGenerationsEnabled(); + } } template <typename AllocType> @@ -484,47 +561,28 @@ constexpr size_t SizeToCapacity(size_t size) { return (~size_t{}) >> leading_zeros; } -// The mode we store capacity in the table. -enum HashtableCapacityStorageMode { - // Capacity stored as size_t as a full number. - kCapacityByValue, - // Capacity stored as uint8_t as log2, i.e. capacity = 2^capacity_ - 1. - kCapacityByLog, -}; - // The number of slots in the backing array. This is always 2^N-1 for an // integer N. // NOTE: this class exists to simplify experiments with different ways to store // capacity within size. -// NOTE: we tried experimenting with compressing the capacity and storing it -// together with size_: (a) using 6 bits to store the corresponding power (N in -// 2^N-1), and (b) storing 2^N as the most significant bit of size_ and storing -// size in the low bits. Both of these experiments were regressions, presumably -// because we need capacity to do find operations. -template <HashtableCapacityStorageMode StorageMode> -class HashtableCapacityImpl { - using IntType = - std::conditional_t<StorageMode == kCapacityByValue, size_t, uint8_t>; - +class HashtableCapacity { public: - static constexpr HashtableCapacityImpl CreateDestroyed() { - return HashtableCapacityImpl(kDestroyed); + static constexpr HashtableCapacity CreateDestroyed() { + return HashtableCapacity(kDestroyed); } - static constexpr HashtableCapacityImpl CreateReentrance() { - return HashtableCapacityImpl(kReentrance); + static constexpr HashtableCapacity CreateReentrance() { + return HashtableCapacity(kReentrance); } - static constexpr HashtableCapacityImpl CreateMovedFrom() { - return HashtableCapacityImpl(kMovedFrom); + static constexpr HashtableCapacity CreateMovedFrom() { + return HashtableCapacity(kMovedFrom); } - static constexpr HashtableCapacityImpl CreateSelfMovedFrom() { - return HashtableCapacityImpl(kSelfMovedFrom); + static constexpr HashtableCapacity CreateSelfMovedFrom() { + return HashtableCapacity(kSelfMovedFrom); } - explicit HashtableCapacityImpl(uninitialized_tag_t) {} - explicit constexpr HashtableCapacityImpl(size_t capacity) - : capacity_data_(static_cast<IntType>( - StorageMode == kCapacityByValue ? capacity - : TrailingZeros(capacity + 1))) { + explicit HashtableCapacity(uninitialized_tag_t) {} + explicit constexpr HashtableCapacity(size_t capacity) + : capacity_data_(static_cast<uint8_t>(TrailingZeros(capacity + 1))) { ABSL_SWISSTABLE_ASSERT(capacity == 0 || IsValidCapacity(capacity)); } @@ -532,12 +590,12 @@ class HashtableCapacityImpl { // This is needed to use bitfield for capacity. // At least on Windows combination uint8_t and uint64_t bitfield in one struct // is not optimized by compiler. - static HashtableCapacityImpl FromRawData(uint64_t capacity) { - auto cap = HashtableCapacityImpl(uninitialized_tag_t{}); - cap.capacity_data_ = static_cast<IntType>(capacity); + static HashtableCapacity FromRawData(uint64_t capacity) { + auto cap = HashtableCapacity(uninitialized_tag_t{}); + cap.capacity_data_ = static_cast<uint8_t>(capacity); return cap; } - IntType ToRawData() const { return capacity_data_; } + uint8_t ToRawData() const { return capacity_data_; } constexpr bool IsValid() const { return capacity_data_ <= kAboveMaxValidCapacity; @@ -553,13 +611,11 @@ class HashtableCapacityImpl { constexpr size_t capacity() const { ABSL_SWISSTABLE_ASSERT(IsValid()); - return StorageMode == kCapacityByValue ? capacity_data_ - : (size_t{1} << capacity_data_) - 1; + return (size_t{1} << capacity_data_) - 1; } constexpr bool is_small() const { - // Small tables have capacity 0 or 1. This expression is valid for both - // capacity storage modes. + // Small tables have capacity 0 or 1. // Comparing capacity_data_ directly leads to a better generated code. // One byte comparison is used before computing the capacity in order to // detect small tables faster for critical path. @@ -570,10 +626,8 @@ class HashtableCapacityImpl { private: // We use these sentinel capacity values in debug mode to indicate different // classes of bugs. - enum InvalidCapacity : IntType { - kAboveMaxValidCapacity = StorageMode == kCapacityByValue - ? (std::numeric_limits<IntType>::max)() - 100 - : 64 - 10, + enum InvalidCapacity : uint8_t { + kAboveMaxValidCapacity = 64 - 10, kReentrance, kDestroyed, @@ -582,18 +636,15 @@ class HashtableCapacityImpl { kSelfMovedFrom, }; - explicit constexpr HashtableCapacityImpl(InvalidCapacity capacity) + explicit constexpr HashtableCapacity(InvalidCapacity capacity) : capacity_data_(capacity) { ABSL_SWISSTABLE_ASSERT(capacity_data_ > kAboveMaxValidCapacity); } - // Capacity is stored as a value or as a log2 depending on `StorageMode`. - IntType capacity_data_; + // Capacity stored as uint8_t as log2, i.e. capacity = 2^capacity_data_ - 1. + uint8_t capacity_data_; }; -template <HashtableCapacityStorageMode StorageMode> -class HashtableInlineDataImpl; - // Returns next per-table seed. uint8_t NextHashTableSeed(); @@ -606,8 +657,7 @@ class PerTableSeed { size_t seed() const { return seed_; } private: - template <HashtableCapacityStorageMode StorageModeOfData> - friend class HashtableInlineDataImpl; + friend class HashtableInlineData; explicit PerTableSeed(uint64_t seed) : seed_(static_cast<uint16_t>(seed)) {} @@ -750,46 +800,52 @@ class GrowthInfoLowerBound { // the table. // 3) kSeedBitCount bits for the seed. (For SOO tables, the lowest bit of the // seed is repurposed to track if sampling has been tried). -template <HashtableCapacityStorageMode StorageMode> -class HashtableInlineDataImpl { +class HashtableInlineData { // The number of bits in the seed. It is big enough to ensure // non-determinism of iteration order. We store the seed inside a uint64_t - // together with size and other metadata. When absl::Hash is inlined, it can - // have lower latency knowing that the high bits of the seed are zero. - static constexpr size_t kSeedBitCount = 5; + // together with size and other metadata. The seed occupies the entire second + // byte of `data_` so that on the critical path of lookups it can be loaded + // with a single byte load and passed to the hash function without any + // masking. When absl::Hash is inlined, it can have lower latency knowing that + // the high bits of the seed are zero. + static constexpr size_t kSeedBitCount = 8; public: - static constexpr HashtableCapacityStorageMode kStorageMode = StorageMode; - using HashtableCapacity = HashtableCapacityImpl<StorageMode>; static constexpr size_t kGrowthInfoLowerBoundBitCount = 8; static constexpr size_t kBlockedElementBitCount = 3; static constexpr size_t kMaxBlockedElementCount = (uint64_t{1} << kBlockedElementBitCount) - 1; - static constexpr size_t kCapacityBitCount = - StorageMode == kCapacityByValue ? sizeof(HashtableCapacity) * 8 : 6; - static constexpr size_t kCapacityBitStoredInDataCount = - StorageMode == kCapacityByValue ? 0 : kCapacityBitCount; + static constexpr size_t kCapacityBitCount = 6; static constexpr size_t kSizeBitCount = 64 - (kBlockedElementBitCount + kSeedBitCount + kGrowthInfoLowerBoundBitCount + - /*has_infoz*/ 1 + kCapacityBitStoredInDataCount); - - explicit HashtableInlineDataImpl(uninitialized_tag_t) {} - explicit HashtableInlineDataImpl(HashtableCapacity capacity, - no_seed_empty_tag_t) - : capacity_internal_(capacity.ToRawData()), data_(0) {} - HashtableInlineDataImpl(HashtableCapacity capacity, full_soo_tag_t, - bool has_tried_sampling) - : capacity_internal_(capacity.ToRawData()), - data_(kSizeOneNoMetadata | + /*unused*/ 1 + /*has_infoz*/ 1 + kCapacityBitCount); + + explicit HashtableInlineData(uninitialized_tag_t) {} + explicit HashtableInlineData(HashtableCapacity capacity, no_seed_empty_tag_t) + : data_(CapacityBits(capacity)) {} + HashtableInlineData(HashtableCapacity capacity, full_soo_tag_t, + bool has_tried_sampling) + : data_(CapacityBits(capacity) | kSizeOneNoMetadata | (has_tried_sampling ? kSooHasTriedSamplingMask : 0)) {} HashtableCapacity capacity() const { - return HashtableCapacity::FromRawData(capacity_internal_); + // Reading the capacity via a single byte load (rather than a wide load of + // `data_` followed by masking) allows the compiler to also use a single + // byte load for the seed on the critical path of lookups. The high bits of + // the byte are not part of the capacity. + return HashtableCapacity::FromRawData( + static_cast<uint8_t>(read_byte(kCapacityByteIndex) & kCapacityMask)); } bool is_small() const { return capacity().is_small(); } - void set_capacity(HashtableCapacity c) { capacity_internal_ = c.ToRawData(); } + void set_capacity(HashtableCapacity c) { + data_ = (data_ & ~kCapacityMask) | CapacityBits(c); + } + // Allow for preventing the compiler from optimizing away the store. + void set_capacity(HashtableCapacity c) volatile { + data_ = (data_ & ~kCapacityMask) | CapacityBits(c); + } void set_capacity(size_t c) { set_capacity(HashtableCapacity(c)); } // Returns actual size of the table. @@ -817,7 +873,10 @@ class HashtableInlineDataImpl { } PerTableSeed seed() const { - return PerTableSeed(ToPublicSeed(data_ & kSeedMask)); + // The seed is stored in exactly one byte, so we read it with a single byte + // load. This lets the compiler feed it directly into the hash function + // without a masking instruction on the critical path of lookups. + return PerTableSeed(read_byte(kSeedByteIndex)); } void generate_new_seed() { set_seed(NextHashTableSeed()); } @@ -826,9 +885,7 @@ class HashtableInlineDataImpl { // hashes use the same seed and can e.g. identify stuck bits accurately. void set_sampled_seed() { set_seed(kSampledSeed); } - bool is_sampled_seed() const { - return seed().seed() == ToPublicSeed(kSampledSeed); - } + bool is_sampled_seed() const { return seed().seed() == kSampledSeed; } // Returns true if the table has infoz. bool has_infoz() const { @@ -907,24 +964,32 @@ class HashtableInlineDataImpl { void set_no_seed_for_testing() { data_ &= ~kSeedMask; } private: - // Bit layout of `data_` and `capacity_internal_` from MSB to LSB: - // (47/41 bits) : size + // Bit layout of `data_` from MSB to LSB: + // (37 bits) : size // (8 bits) : growth_info_lower_bound // (3 bits) : blocked_element_count + // (8 bits) : seed (the whole second byte) + // (1 bit) : unused // (1 bit) : has_infoz - // (5 bits) : seed - // (6 bits) : capacity (only for kCapacityByLog) - // We don't split these components of `data_` into separate bit field elements - // because we get worse generated code that way. - - static constexpr size_t kDataBitCount = 64 - kCapacityBitStoredInDataCount; - static constexpr size_t kSizeShift = kDataBitCount - kSizeBitCount; + // (6 bits) : capacity (the low 6 bits of the first byte) + // Note: for size to overflow would require ~2^40 bytes of RAM, which is + // impractical. The seed and the capacity are deliberately byte-aligned and + // accessed with byte loads: this lets lookups avoid a wide load plus masking + // on the critical path. We don't split these components of `data_` into + // separate bit field elements because we get worse generated code that way + // (the compiler loads the whole word and extracts the fields). + + static constexpr size_t kSizeShift = 64 - kSizeBitCount; static constexpr uint64_t kSizeOneNoMetadata = uint64_t{1} << kSizeShift; static constexpr uint64_t kMetadataMask = kSizeOneNoMetadata - 1; - static constexpr uint64_t kSeedMask = (uint64_t{1} << kSeedBitCount) - 1; - // The next bit after the seed. - static constexpr uint64_t kHasInfozMask = kSeedMask + 1; - static constexpr uint64_t kBlockedElementsShift = kSeedBitCount + 1; + static constexpr uint64_t kCapacityMask = (1 << kCapacityBitCount) - 1; + static constexpr size_t kHasInfozShift = kCapacityBitCount; + static constexpr uint64_t kHasInfozMask = uint64_t{1} << kHasInfozShift; + static constexpr size_t kSeedShift = + kHasInfozShift + /*has_infoz*/ 1 + /*unused*/ 1; + static constexpr uint64_t kSeedMask = ((uint64_t{1} << kSeedBitCount) - 1) + << kSeedShift; + static constexpr uint64_t kBlockedElementsShift = kSeedShift + kSeedBitCount; static constexpr uint64_t kBlockedElementMask = kMaxBlockedElementCount << kBlockedElementsShift; static constexpr uint64_t kGrowthInfoLowerBoundShift = @@ -933,46 +998,60 @@ class HashtableInlineDataImpl { uint64_t{1} << kGrowthInfoLowerBoundShift; static constexpr uint64_t kGrowthInfoLowerBoundMask = uint64_t{0xff} << kGrowthInfoLowerBoundShift; - // For SOO tables, the seed is unused, and bit 0 is repurposed to track - // whether the table has already queried should_sample_soo(). - static constexpr uint64_t kSooHasTriedSamplingMask = 1; + static_assert(kGrowthInfoLowerBoundShift + kGrowthInfoLowerBoundBitCount == + kSizeShift); + // For SOO tables, the seed is unused, and its lowest bit is repurposed to + // track whether the table has already queried should_sample_soo(). + static constexpr uint64_t kSooHasTriedSamplingMask = uint64_t{1} + << kSeedShift; // We need to use a constant seed when the table is sampled so that sampled // hashes use the same seed and can e.g. identify stuck bits accurately. static constexpr uint8_t kSampledSeed = (1 << kSeedBitCount) - 1; - static constexpr uint64_t ToPublicSeed(uint64_t seed) { - // In kCapacityByLog mode, we shift public seed to the left to keep bits of - // the seed in the original place. It allows us to use single instruction to - // access the seed (e.g., `andl $0x7c0, %r8d`). - return seed << kCapacityBitStoredInDataCount; + // Indices of the bytes of `data_` that hold the capacity and the seed. + static_assert(kSeedShift == 8); + static_assert(kSeedBitCount == 8); +#ifdef ABSL_IS_LITTLE_ENDIAN + static constexpr size_t kCapacityByteIndex = 0; + static constexpr size_t kSeedByteIndex = 1; +#else + static constexpr size_t kCapacityByteIndex = 7; + static constexpr size_t kSeedByteIndex = 6; +#endif + + // Returns the `index`-th byte of `data_`. Accessing the storage through + // `unsigned char` is always allowed by the aliasing rules. Note: on x86, the + // reason we read the data this way rather than using bit manipulations as + // with other fields is that it results in better generated code (we get + // movzbl to read the seed this way). On other architectures (such as + // AArch64), byte loads prevent load-pair (ldp) of `inline_data_` with + // `control_` and introduce narrow loads after 64-bit stores to `data_`, so we + // use bit shifts on the wide word instead. + uint8_t read_byte(size_t index) const { +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ + defined(_M_IX86) + return reinterpret_cast<const unsigned char*>(&data_)[index]; +#else + return static_cast<uint8_t>(little_endian::FromHost64(data_) >> + (8 * index)); +#endif + } + + // Returns the bits of `data_` that encode `capacity`. + static uint64_t CapacityBits(HashtableCapacity capacity) { + return uint64_t{capacity.ToRawData()}; } void set_seed(uint8_t seed) { - data_ = (data_ & ~kSeedMask) | (seed & kSeedMask); + data_ = (data_ & ~kSeedMask) | ((uint64_t{seed} << kSeedShift) & kSeedMask); } - uint64_t capacity_internal_ : kCapacityBitCount; - uint64_t data_ : kDataBitCount; + uint64_t data_; }; -static_assert( - sizeof(HashtableInlineDataImpl<kCapacityByValue>::HashtableCapacity) == - sizeof(size_t)); -// NOTE: some platforms have this size to be equal to 12 for two reasons: -// 1) alignof(uint64_t) == 4. -// 2) sizeof(size_t) == sizeof(HashtableCapacityImpl<kCapacityByValue>) == 4. -static_assert(sizeof(HashtableInlineDataImpl<kCapacityByValue>) <= 16); -static_assert( - sizeof(HashtableInlineDataImpl<kCapacityByLog>::HashtableCapacity) == 1); -static_assert(sizeof(HashtableInlineDataImpl<kCapacityByLog>) == 8); - -#ifndef ABSL_SWISSTABLE_INTERNAL_ENABLE_CAPACITY_BY_VALUE -using HashtableInlineData = HashtableInlineDataImpl<kCapacityByLog>; -#else -using HashtableInlineData = HashtableInlineDataImpl<kCapacityByValue>; -#endif // ABSL_SWISSTABLE_INTERNAL_ENABLE_CAPACITY_BY_VALUE -using HashtableCapacity = HashtableInlineData::HashtableCapacity; +static_assert(sizeof(HashtableCapacity) == 1); +static_assert(sizeof(HashtableInlineData) == 8); // For large tables, we limit the number of blocked elements to maintain O(1) // average case lookup complexity. @@ -1135,9 +1214,14 @@ using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; // `Group::kWidth`-width probe window starting from any control byte. constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } +// Returns the number of control bytes including cloned assuming large table. +constexpr size_t NumControlBytesForLargeTable(size_t capacity) { + ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(capacity)); + return capacity + 1 + NumClonedBytes(); +} // Returns the number of control bytes including cloned. constexpr size_t NumControlBytes(size_t capacity) { - return IsSmallCapacity(capacity) ? 0 : capacity + 1 + NumClonedBytes(); + return IsSmallCapacity(capacity) ? 0 : NumControlBytesForLargeTable(capacity); } // Returns the size in bytes table with given capacity use to store GrowthInfo. @@ -1189,6 +1273,13 @@ class RawHashSetLayout { alloc_size_ = slot_offset_ + (capacity - blocked_element_count) * slot_size; } + // Creates a layout for a small non-SOO table growing from capacity + // 0 -> 1 (`size == 0`) or 1 -> 3 (`size == 1`). + static RawHashSetLayout CreateForSmallNonSooGrowth(size_t size, + size_t slot_size, + size_t slot_align, + bool has_infoz); + // Returns precomputed offset from the start of the backing allocation of // control. size_t control_offset() const { return control_offset_; } @@ -1206,6 +1297,8 @@ class RawHashSetLayout { size_t alloc_size() const { return alloc_size_; } private: + explicit RawHashSetLayout(uninitialized_tag_t) {} + size_t control_offset_; size_t generation_offset_; size_t slot_offset_; @@ -1258,6 +1351,25 @@ union HeapOrSoo { unsigned char soo_data[MaxSooSlotSize()]; }; +class CommonFields; +struct PolicyFunctions; + +// RAII object that guards against reentrant calls to hash table methods in +// debug mode. +class ReentranceGuard { + public: +#ifdef NDEBUG + explicit ReentranceGuard(CommonFields&) {} +#else // NDEBUG + explicit ReentranceGuard(CommonFields& common); + ~ReentranceGuard(); + + private: + CommonFields& common_; + HashtableCapacity capacity_; +#endif // NDEBUG +}; + // CommonFields hold the fields in raw_hash_set that do not depend // on template parameters. This allows us to conveniently pass all // of this state to helper functions as a single argument. @@ -1298,14 +1410,7 @@ class CommonFields : public CommonFieldsGenerationInfo { ctrl_t* control() const { ABSL_SWISSTABLE_ASSERT(capacity() > 0); - // Assume that the control bytes don't alias `this`. - ctrl_t* ctrl = heap_or_soo_.control().get(); - [[maybe_unused]] size_t num_control_bytes = NumControlBytes(capacity()); - ABSL_ASSUME(reinterpret_cast<uintptr_t>(ctrl + num_control_bytes) <= - reinterpret_cast<uintptr_t>(this) || - reinterpret_cast<uintptr_t>(this + 1) <= - reinterpret_cast<uintptr_t>(ctrl)); - ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(ctrl); + ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(heap_or_soo_.control().get()); } void set_control(ctrl_t* c) { heap_or_soo_.control().set(c); } @@ -1313,13 +1418,17 @@ class CommonFields : public CommonFieldsGenerationInfo { // Note: we can't use slots() because Qt defines "slots" as a macro. // Returns pointer to the slots of a table with explicit capacity that must be // equal to the actual capacity of the table. - // Capacity is often known at compile time or already in register with some - // ABSL_ASSUME conditions. We require passing it explicitly to eliminate - // branches inside of NumControlBytes in majority of cases. + // Table must be large. void* slot_array(size_t capacity) const { ABSL_SWISSTABLE_ASSERT(capacity == this->capacity()); + ABSL_ASSUME(capacity > kMaxSmallCapacity); ctrl_t* ctrl = control(); - return ctrl + NumControlBytes(capacity); + return ctrl + NumControlBytesForLargeTable(capacity); + } + // Returns pointer to the single slot of a table with capacity 1. + void* single_non_soo_slot() const { + ABSL_SWISSTABLE_ASSERT(capacity() == 1); + return control(); } // The number of filled slots. @@ -1368,7 +1477,10 @@ class CommonFields : public CommonFieldsGenerationInfo { } inline_data_.generate_new_seed(); } - void set_no_seed_for_testing() { inline_data_.set_no_seed_for_testing(); } + void set_no_seed_for_testing() { + ABSL_SWISSTABLE_ASSERT(!has_infoz()); + inline_data_.set_no_seed_for_testing(); + } HashtableCapacity capacity_impl() const { HashtableCapacity cap = inline_data_.capacity(); @@ -1382,6 +1494,10 @@ class CommonFields : public CommonFieldsGenerationInfo { return inline_data_.capacity(); } void set_capacity(HashtableCapacity c) { inline_data_.set_capacity(c); } + // Allow for preventing the compiler from optimizing away the store. + void set_capacity(HashtableCapacity c) volatile { + inline_data_.set_capacity(c); + } void set_capacity(size_t c) { set_capacity(HashtableCapacity(c)); } @@ -1435,6 +1551,7 @@ class CommonFields : public CommonFieldsGenerationInfo { inline_data_.set_has_infoz(); } + HashtablezInfoHandle infoz_from_control(ctrl_t* ctrl) const; HashtablezInfoHandle infoz_ptr() const; HashtablezInfoHandle infoz() { @@ -1453,6 +1570,15 @@ class CommonFields : public CommonFieldsGenerationInfo { return CommonFieldsGenerationInfo::should_rehash_for_bug_detection_on_move( capacity()); } + void annotate_for_bug_detection_on_move(CommonFields& that, + const PolicyFunctions& policy) { + // We only enable moved-from validation when generations are enabled (rather + // than using NDEBUG) to avoid issues in which NDEBUG is enabled in some + // translation units but not in others. + if constexpr (SwisstableGenerationsEnabled()) { + AnnotateForBugDetectionOnMoveImpl(that, policy); + } + } void reset_reserved_growth(size_t reservation) { CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size()); } @@ -1495,26 +1621,13 @@ class CommonFields : public CommonFieldsGenerationInfo { std::count(control(), control() + capacity(), ctrl_t::kDeleted)); } - // Helper to enable sanitizer mode validation to protect against reentrant - // calls during element constructor/destructor. - template <typename F> - void RunWithReentrancyGuard(F f) { -#ifdef NDEBUG - f(); - return; -#endif - const HashtableCapacity cap = maybe_invalid_capacity(); - set_capacity(HashtableCapacity::CreateReentrance()); - f(); - set_capacity(cap); - } - // Asserts that the capacity is not a sentinel invalid value. void AssertNotDebugCapacity() const { - if (!SwisstableGenerationsOrDebugEnabled()) { - return; + if constexpr (SwisstableGenerationsOrDebugEnabled()) { + if (ABSL_PREDICT_FALSE(!maybe_invalid_capacity().IsValid())) { + AssertNotDebugCapacityImpl(); + } } - AssertNotDebugCapacityImpl(); } private: @@ -1548,11 +1661,15 @@ class CommonFields : public CommonFieldsGenerationInfo { // We can't assert that SOO is enabled because we don't have SooEnabled(), but // we assert what we can. void AssertInSooMode() const { - ABSL_SWISSTABLE_ASSERT(capacity() == SooCapacity()); - ABSL_SWISSTABLE_ASSERT(!has_infoz()); + if constexpr (kIsDebug) { + AssertInSooModeImpl(); + } } + void AssertInSooModeImpl() const; void AssertNotDebugCapacityImpl() const; + void AnnotateForBugDetectionOnMoveImpl(CommonFields& that, + const PolicyFunctions& policy); HashtableInlineData inline_data_; @@ -1586,15 +1703,6 @@ size_t SelectReservationSizeForIterRange(InputIter first, InputIter last, return 0; } -constexpr bool SwisstableDebugEnabled() { -#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || \ - ABSL_OPTION_HARDENED == 1 || !defined(NDEBUG) - return true; -#else - return false; -#endif -} - // Dereferences `ptr`. The function is named in order to provide a helpful error // message when users see crashing stack traces. Note that this function is not // guaranteed to crash when `ptr` is invalid if sanitizer mode is not enabled. @@ -1619,6 +1727,7 @@ T CrashIfIteratorIsInvalid(const T* ptr) { // so that it's not UB if they're uninitialized as long as we don't read them // (when slot is null). +template <typename = void> inline void AssertIsFull(const ctrl_t* const& ctrl, const void* slot, GenerationType generation, const GenerationType* generation_ptr, @@ -1663,6 +1772,7 @@ inline void AssertIsFull(const ctrl_t* const& ctrl, const void* slot, } // Note that for comparisons, null/end iterators are valid. +template <typename = void> inline void AssertIsValidForComparison(const ctrl_t* const& ctrl, const void* slot, GenerationType generation, @@ -1698,6 +1808,7 @@ inline void AssertIsValidForComparison(const ctrl_t* const& ctrl, // If the two iterators come from the same container, then their pointers will // interleave such that ctrl_a <= ctrl_b < slot_a <= slot_b or vice/versa. +template <typename = void> inline bool AreItersFromSameContainer(const ctrl_t* const& ctrl_a, const ctrl_t* const& ctrl_b, const void* slot_a, const void* slot_b) { @@ -1723,6 +1834,7 @@ inline bool AreItersFromSameContainer(const ctrl_t* const& ctrl_a, // Asserts that two iterators come from the same container. // Note: we take slots by reference so that it's not UB if they're uninitialized // as long as we don't read them (when ctrl is null). +template <typename = void> inline void AssertSameContainer(const ctrl_t* const& ctrl_a, const ctrl_t* const& ctrl_b, const void* slot_a, const void* slot_b, @@ -1819,17 +1931,20 @@ class probe_seq { size_t offset(size_t i) const { return (offset_ + i) & capacity_; } void next() { - index_ += Width; - offset_ += index_; + ABSL_SWISSTABLE_ASSERT(next_index_ <= capacity_ && "full table!"); + offset_ += next_index_; offset_ &= capacity_; + next_index_ += Width; } // 0-based probe index, a multiple of `Width`. - size_t index() const { return index_; } + size_t index() const { return next_index_ - Width; } private: size_t capacity_; size_t offset_; - size_t index_ = 0; + // We keep track of the next index rather than the current index to get better + // generated code. See e.g. https://godbolt.org/z/6jvWd135G. + size_t next_index_ = Width; }; // Begins a probing operation on `common.control`, using `hash`. @@ -1846,8 +1961,8 @@ inline probe_seq<Group::kWidth> probe(const CommonFields& common, size_t hash) { constexpr size_t kProbedElementIndexSentinel = ~size_t{}; // Implementation detail of transfer_unprobed_elements_to_next_capacity_fn. -// Tries to find the new index for an element whose hash corresponds to -// `h1` for growth to the next capacity. +// Tries to find the new index for an element with `hash` for growth to the next +// capacity. // Returns kProbedElementIndexSentinel if full probing is required. // // If element is located in the first probing group in the table before growth, @@ -1857,23 +1972,18 @@ constexpr size_t kProbedElementIndexSentinel = ~size_t{}; // table. We only attempt to do so if the first probe group is already // initialized. template <typename = void> -inline size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index, +inline size_t TryFindNewIndexWithoutProbing(size_t hash, size_t old_index, size_t old_capacity, ctrl_t* new_ctrl, size_t new_capacity) { - size_t index_diff = old_index - h1; + size_t h1 = H1(hash); // The first probe group starts with h1 & capacity. // All following groups start at (h1 + Group::kWidth * K) & capacity. - // We can find an index within the floating group as index_diff modulo - // Group::kWidth. - // Both old and new capacity are larger than Group::kWidth so we can avoid - // computing `& capacity`. - size_t in_floating_group_index = index_diff & (Group::kWidth - 1); - // By subtracting we will get the difference between the first probe group - // and the probe group corresponding to old_index. - index_diff -= in_floating_group_index; - if (ABSL_PREDICT_TRUE((index_diff & old_capacity) == 0)) { - size_t new_index = (h1 + in_floating_group_index) & new_capacity; + // If old_index is in the first probe group, (old_index - h1) & old_capacity + // is the index within the floating group (< Group::kWidth). + size_t index_diff = (old_index - h1) & old_capacity; + if (ABSL_PREDICT_TRUE(index_diff < Group::kWidth)) { + size_t new_index = (h1 + index_diff) & new_capacity; ABSL_ASSUME(new_index != kProbedElementIndexSentinel); return new_index; } @@ -1897,15 +2007,6 @@ inline size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index, return kProbedElementIndexSentinel; } -// Extern template for inline function keeps possibility of inlining. -// When compiler decided to not inline, no symbols will be added to the -// corresponding translation unit. -extern template size_t TryFindNewIndexWithoutProbing(size_t h1, - size_t old_index, - size_t old_capacity, - ctrl_t* new_ctrl, - size_t new_capacity); - // The HashtablezInfoHandle is stored before the control bytes. // NOTE: The growth_info is also stored before the backing array, but it doesn't // have alignment requirements. For small tables it is 1 byte, for larger tables @@ -1962,7 +2063,7 @@ struct PolicyFunctions { uint32_t slot_size; uint16_t slot_align; bool soo_enabled; - bool is_hashtablez_eligible; + bool is_hashtablez_enabled; // Returns the pointer to the hash function stored in the set. void* (*hash_fn)(CommonFields& common); @@ -1993,11 +2094,11 @@ struct PolicyFunctions { // Different encoding is used depending on the capacity of the table. // See ProbedItem*Bytes classes for details. void (*transfer_unprobed_elements_to_next_capacity)( - CommonFields& common, const ctrl_t* old_ctrl, void* old_slots, + CommonFields& common, const ctrl_t* old_ctrl, // TODO(b/382423690): Try to use absl::FunctionRef here. - void* probed_storage, - void (*encode_probed_element)(void* probed_storage, h2_t h2, - size_t source_offset, size_t h1)); + void* probed_storage, void* old_slots, size_t old_capacity, + void (*encode_probed_element)(void* probed_storage, size_t hash, + size_t source_offset)); uint8_t soo_capacity() const { return static_cast<uint8_t>(soo_enabled ? SooCapacity() : 0); @@ -2122,7 +2223,7 @@ void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n); // Type erased version of copy constructor. void Copy(CommonFields& common, const PolicyFunctions& policy, const CommonFields& other, - absl::FunctionRef<void(void*, const void*)> copy_fn); + void (*copy_fn)(void* set, void* dst, const void* src)); // Returns the optimal size for memcpy when transferring SOO slot. // Otherwise, returns the optimal size for memcpy SOO slot transfer @@ -2150,22 +2251,24 @@ constexpr size_t OptimalMemcpySizeForSooSlotTransfer( return 8; } +using HashForKeyFn = size_t (*)(void* hasher, size_t seed); + // Resizes SOO table to the NextCapacity(SooCapacity()) and prepares insert for // the given new_hash. Returns the new slot. // All possible template combinations are defined in cc file to improve // compilation time. template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy> void* GrowSooTableToNextCapacityAndPrepareInsert( - CommonFields& common, const PolicyFunctions& policy, - absl::FunctionRef<size_t(size_t)> get_hash, bool force_sampling); + CommonFields& common, const PolicyFunctions& policy, void* hasher, + HashForKeyFn get_hash, bool force_sampling); // PrepareInsert for small tables (is_small()==true). // Returns the new slot. // Hash is only computed if the table is sampled or grew to large size // (is_small()==false). void* PrepareInsertSmallNonSoo(CommonFields& common, - const PolicyFunctions& policy, - absl::FunctionRef<size_t(size_t)> get_hash); + const PolicyFunctions& policy, void* hasher, + HashForKeyFn get_hash); // Resizes table with allocated slots and change the table seed. // Tables with SOO enabled must have capacity > policy.soo_capacity. @@ -2214,6 +2317,15 @@ void Destruct(CommonFields& c, const DtorPolicy& policy, template <bool kSooEnabled> void Destruct(CommonFields& c, const DtorPolicy& policy); +using EqualToKeyFn = bool (*)(void* set, const void* key, void* slot); + +// Asserts that hash and equal functors provided by the user are consistent, +// meaning that `eq(k1, k2)` implies `hash(k1)==hash(k2)`. +void AssertHashEqConsistentImpl(CommonFields& common, const void* hash_fn, + HashSlotFn hash_slot, size_t slot_size, + bool soo_enabled, size_t hash, const void* key, + EqualToKeyFn equal); + // Type-erased versions of raw_hash_set::erase_meta_only_{small,large}. void EraseMetaOnlySmall(CommonFields& c, bool soo_enabled, size_t slot_size); void EraseMetaOnlyLarge(CommonFields& c, size_t index, size_t slot_size); @@ -2255,13 +2367,13 @@ void* GetRefForEmptyClass(CommonFields& common); // at least one empty slot. void* PrepareInsertLarge(CommonFields& common, const PolicyFunctions& policy, size_t hash, Group::NonIterableBitMaskType mask_empty, - FindInfo target_group); + size_t target_group_offset); // Same as above, but with generations enabled, we may end up changing the seed, // which means we need to be able to recompute the hash. void* PrepareInsertLargeGenerationsEnabled( CommonFields& common, const PolicyFunctions& policy, size_t hash, - Group::NonIterableBitMaskType mask_empty, FindInfo target_group, + Group::NonIterableBitMaskType mask_empty, size_t target_group_offset, absl::FunctionRef<size_t(size_t)> recompute_hash); template <typename Policy, typename Hash, typename Eq, typename Alloc> @@ -2273,6 +2385,95 @@ struct InstantiateRawHashSet { TypeList<Policy, Hash, Eq, Alloc>>::type; }; +template <class T> +using HasTrivialCopyAndMove = + std::bool_constant<std::is_trivially_copy_constructible_v<T> && + std::is_trivially_move_constructible_v<T>>; + +// In principle, being trivially copy- and move-constructible is sufficient +// (though not necessary) for proving copy and move equivalence. However, we +// can't even test that for all types, because not all types are complete at the +// point of evaluation of this trait. Therefore, we restrict this trait to a +// subset of common types that we know to be complete at the point of evaluation +// of this trait. +template <class T> +inline constexpr bool kIsMoveSameAsCopy = HasTrivialCopyAndMove< + std::conditional_t<(!std::is_class_v<T> && !std::is_union_v<T>) || + std::is_same_v<T, std::type_index> || + std::is_same_v<T, absl::string_view>, + T, void>>::value; + +template <class T, class Traits> +inline constexpr bool kIsMoveSameAsCopy<std::basic_string_view<T, Traits>> = + std::is_trivially_copy_constructible_v<std::basic_string_view<T, Traits>>; + +template <class T, size_t N> +inline constexpr bool kIsMoveSameAsCopy<std::array<T, N>> = + kIsMoveSameAsCopy<T>; + +template <class T> +inline constexpr bool kIsMoveSameAsCopy<std::optional<T>> = + kIsMoveSameAsCopy<T>; + +template <class T1, class T2> +inline constexpr bool kIsMoveSameAsCopy<std::pair<T1, T2>> = + kIsMoveSameAsCopy<T1> && kIsMoveSameAsCopy<T2>; + +template <class... T> +inline constexpr bool kIsMoveSameAsCopy<std::tuple<T...>> = + (true && ... && kIsMoveSameAsCopy<T>); + +template <class... T> +inline constexpr bool kIsMoveSameAsCopy<std::variant<T...>> = + (true && ... && kIsMoveSameAsCopy<T>); + +template <class T, class Alloc = std::allocator<T>> +using IsAllocMoveSameAsCopy = + std::bool_constant<kIsMoveSameAsCopy<std::conditional_t< + std::is_same_v<std::allocator<T>, typename std::allocator_traits< + Alloc>::template rebind_alloc<T>>, + T, void>>>; + +template <class T> +using ShouldStructurallyPreferPassByValue = std::bool_constant< + // Check if size is a power of 2, to ensure cheap calls. + absl::has_single_bit(sizeof(T)) && + // Check if copying 1-2 registers is enough. We don't want (for example) 32 + // one-byte values to move around, since that sometimes results in poor + // codegen. + alignof(T) * 2 >= sizeof(T) && + sizeof(T) <= sizeof(std::pair<void*, size_t>)>; + +template <class T> +using ShouldSemanticallyPreferPassByValue = + std::bool_constant<std::is_trivially_move_constructible_v<T> && + std::is_trivially_destructible_v<T>>; + +// Checks the given type to see if it is a good candidate for accepting by value +// instead of by rvalue-reference. This includes both a semantic constraint +// (to ensure correctness), as well as a structural constraint (to ensure +// performance). +template <class T> +using ShouldPreferPassByValue = + std::bool_constant<ShouldSemanticallyPreferPassByValue<T>::value && + ShouldStructurallyPreferPassByValue<std::conditional_t< + std::is_void_v<T>, char, T>>::value>; + +// This is a 'struct' instead of 'using' in order to avoid eager evaluation for +// callers that may be passing incomplete types. +template <class T> +struct AddConstRefIfExpensive + : std::conditional<ShouldPreferPassByValue<T>::value, T, const T&> { + static_assert(std::is_same_v<remove_cvref_t<T>, T>, + "passed types must be unqualified"); +}; + +template <class T, class Alloc = std::allocator<T>> +using PreferredParamType = + typename std::conditional_t<IsAllocMoveSameAsCopy<T, Alloc>::value, + AddConstRefIfExpensive<T>, + std::add_rvalue_reference<T>>::type; + // A SwissTable. // // Policy: a policy defines how to perform different operations on @@ -2349,20 +2550,23 @@ class raw_hash_set { constexpr static bool kIsAbslHash = std::is_same_v<hasher, absl::Hash<key_type>> || + (!HasAbslContainerHash<key_type>::value && + std::is_same_v<hasher, typename absl::container_internal::HashEq< + key_type>::Hash>) || + // Note: this is useful (in addition to the above case) for cases of + // `absl_container_hash = DefaultHashContainerHash<absl::string_view>`. std::is_same_v<hasher, absl::container_internal::StringHash> || // TODO(b/384509507): resolve `no header providing // "absl::hash_internal::TransparentHash" is directly included`. // Maybe we should make "internal/hash.h" be a separate library. is_instance_of<hasher, absl::hash_internal::TransparentHash>::value; - // For non-default hashers it is required to have low bits entropy because - // (a) in such cases, the seed is xor'ed with the hash value rather than being - // used as a seed for the hash function, (b) the seed has low bits that are - // all 0s, and (c) we require random iteration order for small tables. - // In ToPublicSeed we shift the seed by kCapacityBitStoredInDataCount as - // performance optimization for default hashers. For non-default hashers, we - // shift it back. - constexpr static size_t kSeedShift = - kIsAbslHash ? 0 : HashtableInlineData::kCapacityBitStoredInDataCount; + // For non-default hashers the seed is xor'ed with the hash value rather than + // being used as a seed for the hash function. Because we require random + // iteration order for small tables, the seed must have entropy in its low + // bits. The seed is loaded as a single byte from the inline data, so it + // already has low bits entropy and no shift is needed. + // TODO(ezb): get rid of kSeedShift. + constexpr static size_t kSeedShift = 0; constexpr static bool SooEnabled() { return PolicyTraits::soo_enabled() && @@ -2370,6 +2574,14 @@ class raw_hash_set { alignof(slot_type) <= alignof(HeapOrSoo); } + constexpr static bool HashtablezForTableEnabled() { +#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) + return ShouldSampleHashtablezInfoForAlloc<CharAlloc>(); +#else + return false; +#endif + } + constexpr static size_t DefaultCapacity() { return SooEnabled() ? SooCapacity() : 0; } @@ -2425,8 +2637,13 @@ class raw_hash_set { using Insertable = std::disjunction< std::is_same<absl::remove_cvref_t<reference>, absl::remove_cvref_t<T>>, std::is_convertible<T, init_type>>; + + // Bit-fields cannot be moved, and types with trivial copy and move + // constructors should also not be moved. template <class T> - using IsNotBitField = std::is_pointer<T*>; + using EnableElementMoveFrom = + std::bool_constant<std::is_pointer_v<T*> && + !IsAllocMoveSameAsCopy<T, Alloc>::value>; // RequiresNotInit is a workaround for gcc prior to 7.1. // See https://godbolt.org/g/Y4xsUh. @@ -2499,12 +2716,14 @@ class raw_hash_set { } friend bool operator==(const iterator& a, const iterator& b) { - AssertIsValidForComparison(a.ctrl_, a.slot_, a.generation(), - a.generation_ptr()); - AssertIsValidForComparison(b.ctrl_, b.slot_, b.generation(), - b.generation_ptr()); - AssertSameContainer(a.ctrl_, b.ctrl_, a.slot_, b.slot_, - a.generation_ptr(), b.generation_ptr()); + if constexpr (SwisstableDebugEnabled()) { + AssertIsValidForComparison(a.ctrl_, a.slot_, a.generation(), + a.generation_ptr()); + AssertIsValidForComparison(b.ctrl_, b.slot_, b.generation(), + b.generation_ptr()); + AssertSameContainer(a.ctrl_, b.ctrl_, a.slot_, b.slot_, + a.generation_ptr(), b.generation_ptr()); + } return a.unchecked_equals(b); } friend bool operator!=(const iterator& a, const iterator& b) { @@ -2755,16 +2974,7 @@ class raw_hash_set { raw_hash_set(const raw_hash_set& that, const allocator_type& a) : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) { - that.AssertNotDebugCapacity(); - if (that.empty()) return; - Copy(common(), GetPolicyFunctions(), that.common(), - [this](void* dst, const void* src) { - // TODO(b/413598253): type erase for trivially copyable types via - // PolicyTraits. - construct(to_slot(dst), - PolicyTraits::element( - static_cast<slot_type*>(const_cast<void*>(src)))); - }); + Copy(common(), GetPolicyFunctions(), that.common(), ©_slot_fn); } ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept( @@ -2780,11 +2990,14 @@ class raw_hash_set { : CommonFields{full_soo_tag_t{}, that.common().soo_has_tried_sampling()}, that.hash_ref(), that.eq_ref(), that.char_alloc_ref()) { - if (!PolicyTraits::transfer_uses_memcpy() && that.is_full_soo()) { - transfer(soo_slot(), that.soo_slot()); + if constexpr (SooEnabled() && !PolicyTraits::transfer_uses_memcpy()) { + if (that.is_full_soo()) { + transfer(soo_slot(), that.soo_slot()); + } } that.common() = CommonFields::CreateDefault<SooEnabled()>(); - annotate_for_bug_detection_on_move(that); + common().annotate_for_bug_detection_on_move(that.common(), + GetPolicyFunctions()); } raw_hash_set(raw_hash_set&& that, const allocator_type& a) @@ -2792,7 +3005,8 @@ class raw_hash_set { that.eq_ref(), a) { if (CharAlloc(a) == that.char_alloc_ref()) { swap_common(that); - annotate_for_bug_detection_on_move(that); + common().annotate_for_bug_detection_on_move(that.common(), + GetPolicyFunctions()); } else { move_elements_allocs_unequal(std::move(that)); } @@ -2829,7 +3043,9 @@ class raw_hash_set { ~raw_hash_set() { destructor_impl(); if constexpr (SwisstableGenerationsOrDebugEnabled()) { - common().set_capacity(HashtableCapacity::CreateDestroyed()); + // Prevent the compiler from optimizing away the store. + const_cast<volatile CommonFields&>(common()).set_capacity( + HashtableCapacity::CreateDestroyed()); } } @@ -2891,7 +3107,7 @@ class raw_hash_set { // m.insert(std::make_pair("abc", 42)); template <class T, int = std::enable_if_t<IsDecomposableAndInsertable<T>::value && - IsNotBitField<T>::value && + EnableElementMoveFrom<T>::value && !IsLifetimeBoundAssignmentFrom<T>::value, int>()> std::pair<iterator, bool> insert(T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND { @@ -2900,7 +3116,7 @@ class raw_hash_set { template <class T, int&..., std::enable_if_t<IsDecomposableAndInsertable<T>::value && - IsNotBitField<T>::value && + EnableElementMoveFrom<T>::value && IsLifetimeBoundAssignmentFrom<T>::value, int> = 0> std::pair<iterator, bool> insert( @@ -2943,7 +3159,7 @@ class raw_hash_set { // // flat_hash_map<std::string, int> s; // s.insert({"abc", 42}); - std::pair<iterator, bool> insert(init_type&& value) + std::pair<iterator, bool> insert(PreferredParamType<init_type, Alloc> value) ABSL_ATTRIBUTE_LIFETIME_BOUND #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L requires(!IsLifetimeBoundAssignmentFrom<init_type>::value) @@ -2952,8 +3168,8 @@ class raw_hash_set { return emplace(std::move(value)); } #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L - std::pair<iterator, bool> insert( - init_type&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY_THIS) + std::pair<iterator, bool> insert(PreferredParamType<init_type, Alloc> value + ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY_THIS) ABSL_ATTRIBUTE_LIFETIME_BOUND requires(IsLifetimeBoundAssignmentFrom<init_type>::value) { @@ -2963,7 +3179,7 @@ class raw_hash_set { template <class T, int = std::enable_if_t<IsDecomposableAndInsertable<T>::value && - IsNotBitField<T>::value && + EnableElementMoveFrom<T>::value && !IsLifetimeBoundAssignmentFrom<T>::value, int>()> iterator insert(const_iterator, T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND { @@ -2971,7 +3187,7 @@ class raw_hash_set { } template <class T, int&..., std::enable_if_t<IsDecomposableAndInsertable<T>::value && - IsNotBitField<T>::value && + EnableElementMoveFrom<T>::value && IsLifetimeBoundAssignmentFrom<T>::value, int> = 0> iterator insert(const_iterator hint, @@ -2987,8 +3203,8 @@ class raw_hash_set { return insert(value).first; } - iterator insert(const_iterator, - init_type&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND { + iterator insert(const_iterator, PreferredParamType<init_type, Alloc> value) + ABSL_ATTRIBUTE_LIFETIME_BOUND { return insert(std::move(value)).first; } @@ -3309,7 +3525,7 @@ class raw_hash_set { AssertOnFind(key); if (is_small()) return find_small(key); prefetch_heap_block(); - return find_large(key); + return find_large<FindLargeKey<key_arg<K>>>(key); } template <class K = key_type> @@ -3447,55 +3663,54 @@ class raw_hash_set { template <typename... Args> void construct(slot_type* slot, Args&&... args) { - common().RunWithReentrancyGuard([&] { - allocator_type alloc(char_alloc_ref()); - PolicyTraits::construct(&alloc, slot, std::forward<Args>(args)...); - }); + ReentranceGuard guard(common()); + allocator_type alloc(char_alloc_ref()); + PolicyTraits::construct(&alloc, slot, std::forward<Args>(args)...); } void destroy(slot_type* slot) { - common().RunWithReentrancyGuard([&] { - allocator_type alloc(char_alloc_ref()); - PolicyTraits::destroy(&alloc, slot); - }); + ReentranceGuard guard(common()); + allocator_type alloc(char_alloc_ref()); + PolicyTraits::destroy(&alloc, slot); } void transfer(slot_type* to, slot_type* from) { - common().RunWithReentrancyGuard([&] { - allocator_type alloc(char_alloc_ref()); - PolicyTraits::transfer(&alloc, to, from); - }); + ReentranceGuard guard(common()); + allocator_type alloc(char_alloc_ref()); + PolicyTraits::transfer(&alloc, to, from); } // TODO(b/289225379): consider having a helper class that has the impls for // SOO functionality. - template <class K = key_type> - ABSL_ATTRIBUTE_ALWAYS_INLINE iterator find_small(const key_arg<K>& key) { - ABSL_SWISSTABLE_ASSERT(is_small()); + template <class K> + ABSL_ATTRIBUTE_ALWAYS_INLINE iterator find_small(const K& key) { return empty() || !equal_to(key, single_slot()) ? end() : single_iterator(); } - template <class K = key_type> - iterator find_large(const key_arg<K>& key) { - ABSL_SWISSTABLE_ASSERT(!is_small()); + template <class K> + iterator find_large(absl::type_identity_t<K> key) { + static_assert(std::is_same_v<K, FindLargeKey<K>>); const size_t cap = common().capacity(); ABSL_ASSUME(cap > kMaxSmallCapacity); const size_t hash = hash_of(key); auto seq = probe(ProbeCapacity{cap}, hash); const h2_t h2 = H2(hash); ctrl_t* ctrl = control(); - slot_type* slot_array = to_slot(common().slot_array(cap)); + slot_type* slot_array = this->slot_array(cap); while (true) { + // Loading the group before slot prefetch decreases critical path latency. + Group g{ctrl + seq.offset()}; #ifndef ABSL_HAVE_MEMORY_SANITIZER absl::PrefetchToLocalCache(slot_array + seq.offset()); #endif - Group g{ctrl + seq.offset()}; - for (uint32_t i : g.Match(h2)) { - const size_t offset = seq.offset(i); - if (ABSL_PREDICT_TRUE(equal_to(key, slot_array + offset))) - return iterator_at_ptr(ctrl + offset, slot_array + offset); + // Predict one iteration (common case for find-hit). + if (auto match = g.Match(h2); ABSL_PREDICT_TRUE(match)) { + do { + const size_t offset = seq.offset(*match); + if (ABSL_PREDICT_TRUE(equal_to(key, slot_array + offset))) + return iterator_at_ptr(ctrl + offset, slot_array + offset); + } while (ABSL_PREDICT_FALSE(++match)); } if (ABSL_PREDICT_TRUE(g.MaskEmpty())) return end(); seq.next(); - ABSL_SWISSTABLE_ASSERT(seq.index() <= cap && "full table!"); } } @@ -3507,7 +3722,7 @@ class raw_hash_set { // construction when the size can fit in SOO capacity. bool should_sample_soo() { ABSL_SWISSTABLE_ASSERT(is_soo()); - if constexpr (!ShouldSampleHashtablezInfoForAlloc<CharAlloc>()) { + if constexpr (!HashtablezForTableEnabled()) { return false; } if (common().soo_has_tried_sampling()) { @@ -3604,7 +3819,7 @@ class raw_hash_set { // Casting directly from e.g. char* to slot_type* can cause compilation errors // on objective-C. This function converts to void* first, avoiding the issue. - static ABSL_ATTRIBUTE_ALWAYS_INLINE slot_type* to_slot(void* buf) { + ABSL_ATTRIBUTE_ALWAYS_INLINE static slot_type* to_slot(void* buf) { return static_cast<slot_type*>(buf); } @@ -3615,12 +3830,10 @@ class raw_hash_set { lhs = std::move(rhs); } else { lhs.move_non_heap_or_soo_fields(rhs); - rhs.RunWithReentrancyGuard([&] { - lhs.RunWithReentrancyGuard([&] { - PolicyTraits::transfer(&rhs_alloc, to_slot(lhs.soo_data()), - to_slot(rhs.soo_data())); - }); - }); + ReentranceGuard lhs_guard(lhs); + ReentranceGuard rhs_guard(rhs); + PolicyTraits::transfer(&rhs_alloc, to_slot(lhs.soo_data()), + to_slot(rhs.soo_data())); } } @@ -3642,27 +3855,6 @@ class raw_hash_set { std::move(tmp)); } - void annotate_for_bug_detection_on_move([[maybe_unused]] raw_hash_set& that) { - // We only enable moved-from validation when generations are enabled (rather - // than using NDEBUG) to avoid issues in which NDEBUG is enabled in some - // translation units but not in others. - if (SwisstableGenerationsEnabled()) { - that.common().set_capacity(this == &that - ? HashtableCapacity::CreateSelfMovedFrom() - : HashtableCapacity::CreateMovedFrom()); - } - if (!SwisstableGenerationsEnabled() || - !maybe_invalid_capacity().IsValid() || - capacity() == DefaultCapacity()) { - return; - } - common().increment_generation(); - if (!empty() && common().should_rehash_for_bug_detection_on_move()) { - ResizeAllocatedTableWithSeedChange(common(), GetPolicyFunctions(), - capacity()); - } - } - template <bool propagate_alloc> raw_hash_set& assign_impl(raw_hash_set&& that) { // We don't bother checking for this/that aliasing. We just need to avoid @@ -3675,7 +3867,8 @@ class raw_hash_set { CopyAlloc(char_alloc_ref(), that.char_alloc_ref(), std::bool_constant<propagate_alloc>()); that.common() = CommonFields::CreateDefault<SooEnabled()>(); - annotate_for_bug_detection_on_move(that); + common().annotate_for_bug_detection_on_move(that.common(), + GetPolicyFunctions()); return *this; } @@ -3693,7 +3886,8 @@ class raw_hash_set { &that.char_alloc_ref()); } that.common() = CommonFields::CreateDefault<SooEnabled()>(); - annotate_for_bug_detection_on_move(that); + common().annotate_for_bug_detection_on_move(that.common(), + GetPolicyFunctions()); return *this; } @@ -3709,6 +3903,10 @@ class raw_hash_set { // Aliasing can't happen here because allocs would compare equal above. assert(this != &that); destructor_impl(); + // destructor_impl() leaves common() pointing at the freed backing array + // (or at the stale small-table state), so reset it to the default state + // before re-inserting elements. + common() = CommonFields::CreateDefault<SooEnabled()>(); // We can't take over that's memory so we need to move each element. // While moving elements, this should have that's hash/eq so copy hash/eq // before moving elements. @@ -3720,7 +3918,6 @@ class raw_hash_set { template <class K> ABSL_ATTRIBUTE_ALWAYS_INLINE std::pair<slot_type*, bool> find_or_prepare_insert_soo(const K& key) { - ABSL_SWISSTABLE_ASSERT(is_soo()); bool force_sampling; slot_type* slot = single_slot(); if (empty()) { @@ -3734,24 +3931,22 @@ class raw_hash_set { } else { force_sampling = false; } - ABSL_SWISSTABLE_ASSERT(capacity() == 1); constexpr bool kUseMemcpy = PolicyTraits::transfer_uses_memcpy() && SooEnabled(); + using Hasher = HashKey<hasher, K, kIsAbslHash, kSeedShift>; + Hasher hash_key{hash_ref(), key}; slot = to_slot( GrowSooTableToNextCapacityAndPrepareInsert< kUseMemcpy ? OptimalMemcpySizeForSooSlotTransfer(sizeof(slot_type)) : 0, - kUseMemcpy>( - common(), GetPolicyFunctions(), - HashKey<hasher, K, kIsAbslHash, kSeedShift>{hash_ref(), key}, - force_sampling)); + kUseMemcpy>(common(), GetPolicyFunctions(), &hash_key, + &Hasher::GetHash, force_sampling)); return {slot, true}; } template <class K> ABSL_ATTRIBUTE_ALWAYS_INLINE std::pair<slot_type*, bool> find_or_prepare_insert_small(const K& key) { - ABSL_SWISSTABLE_ASSERT(is_small()); if constexpr (SooEnabled()) { return find_or_prepare_insert_soo(key); } @@ -3760,50 +3955,52 @@ class raw_hash_set { return {single_slot(), false}; } } - return {to_slot(PrepareInsertSmallNonSoo( - common(), GetPolicyFunctions(), - HashKey<hasher, K, kIsAbslHash, kSeedShift>{hash_ref(), key})), + using Hasher = HashKey<hasher, K, kIsAbslHash, kSeedShift>; + Hasher hash_key{hash_ref(), key}; + return {to_slot(PrepareInsertSmallNonSoo(common(), GetPolicyFunctions(), + &hash_key, &Hasher::GetHash)), true}; } template <class K> - std::pair<slot_type*, bool> find_or_prepare_insert_large(const K& key) { - ABSL_SWISSTABLE_ASSERT(!is_soo()); + std::pair<slot_type*, bool> find_or_prepare_insert_large( + absl::type_identity_t<K> key) { + static_assert(std::is_same_v<K, FindLargeKey<K>>); prefetch_heap_block(); const size_t cap = capacity(); - ABSL_ASSUME(cap > kMaxSmallCapacity); const size_t hash = hash_of(key); auto seq = probe(ProbeCapacity{cap}, hash); const h2_t h2 = H2(hash); const ctrl_t* ctrl = control(); - slot_type* slot_array = to_slot(common().slot_array(cap)); + slot_type* slot_array = this->slot_array(cap); while (true) { + // Loading the group before slot prefetch decreases critical path latency. + Group g{ctrl + seq.offset()}; #ifndef ABSL_HAVE_MEMORY_SANITIZER absl::PrefetchToLocalCache(slot_array + seq.offset()); #endif - Group g{ctrl + seq.offset()}; - for (uint32_t i : g.Match(h2)) { - slot_type* slot = slot_array + seq.offset(i); - if (ABSL_PREDICT_TRUE(equal_to(key, slot))) { - return {slot, false}; - } + // Predict one iteration (common case for insert-hit). + if (auto match = g.Match(h2); ABSL_PREDICT_TRUE(match)) { + do { + slot_type* slot = slot_array + seq.offset(*match); + if (ABSL_PREDICT_TRUE(equal_to(key, slot))) return {slot, false}; + } while (ABSL_PREDICT_FALSE(++match)); } auto mask_empty = g.MaskEmpty(); if (ABSL_PREDICT_TRUE(mask_empty)) { size_t target_group_offset = seq.offset(); - void* slot = SwisstableGenerationsEnabled() - ? PrepareInsertLargeGenerationsEnabled( - common(), GetPolicyFunctions(), hash, mask_empty, - FindInfo{target_group_offset, seq.index()}, - HashKey<hasher, K, kIsAbslHash, kSeedShift>{ - hash_ref(), key}) - : PrepareInsertLarge( - common(), GetPolicyFunctions(), hash, mask_empty, - FindInfo{target_group_offset, seq.index()}); + void* slot = + SwisstableGenerationsEnabled() + ? PrepareInsertLargeGenerationsEnabled( + common(), GetPolicyFunctions(), hash, mask_empty, + target_group_offset, + HashKey<hasher, absl::remove_cvref_t<K>, kIsAbslHash, + kSeedShift>{hash_ref(), key}) + : PrepareInsertLarge(common(), GetPolicyFunctions(), hash, + mask_empty, target_group_offset); return {to_slot(slot), true}; } seq.next(); - ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!"); } } @@ -3823,44 +4020,32 @@ class raw_hash_set { // Asserts that the capacity is not a sentinel invalid value. void AssertNotDebugCapacity() const { common().AssertNotDebugCapacity(); } + template <class K> + static bool equal_to_key_fn(void* set, const void* key, void* slot) { + return static_cast<const raw_hash_set*>(set)->equal_to( + *static_cast<const K*>(key), to_slot(slot)); + } + // Asserts that hash and equal functors provided by the user are consistent, // meaning that `eq(k1, k2)` implies `hash(k1)==hash(k2)`. template <class K> void AssertHashEqConsistent(const K& key) { -#ifdef NDEBUG - return; -#endif - // If the hash/eq functors are known to be consistent, then skip validation. - if (std::is_same_v<hasher, absl::container_internal::StringHash> && - std::is_same_v<key_equal, absl::container_internal::StringEq>) { - return; - } - if (std::is_scalar_v<key_type> && + // If the hash/eq functors are known to be consistent, then skip + // validation. + constexpr bool kIsStringAbslHashEq = + std::is_same_v<hasher, absl::container_internal::StringHash> && + std::is_same_v<key_equal, absl::container_internal::StringEq>; + constexpr bool kIsScalarAbslHashEq = + std::is_scalar_v<key_type> && std::is_same_v<hasher, absl::Hash<key_type>> && - std::is_same_v<key_equal, std::equal_to<key_type>>) { - return; - } - if (empty()) return; - - const size_t hash_of_arg = hash_of(key); - const auto assert_consistent = [&](const ctrl_t*, void* slot) { - const bool is_key_equal = equal_to(key, to_slot(slot)); - if (!is_key_equal) return; - - [[maybe_unused]] const bool is_hash_equal = - hash_of_arg == hash_of(to_slot(slot)); - assert((!is_key_equal || is_hash_equal) && - "eq(k1, k2) must imply that hash(k1) == hash(k2). " - "hash/eq functors are inconsistent."); - }; - - if (is_small()) { - assert_consistent(/*unused*/ nullptr, single_slot()); - return; + std::is_same_v<key_equal, std::equal_to<key_type>>; + if constexpr (kIsDebug && !kIsStringAbslHashEq && !kIsScalarAbslHashEq) { + if (empty()) return; + AssertHashEqConsistentImpl( + common(), get_hash_ref_fn(common()), get_hash_slot_fn(), + sizeof(slot_type), SooEnabled(), hash_of(key), &key, + &equal_to_key_fn<K>); } - // We only do validation for small tables so that it's constant time. - if (capacity() > 16) return; - IterateOverFullSlots(common(), sizeof(slot_type), assert_consistent); } // Attempts to find `key` in the table; if it isn't found, returns an iterator @@ -3869,8 +4054,10 @@ class raw_hash_set { template <class K> std::pair<slot_type*, bool> find_or_prepare_insert(const K& key) { AssertOnFind(key); + // TODO(ezb): add ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE that the returned + // slot doesn't alias `this` for non-SOO tables with default allocators. return is_small() ? find_or_prepare_insert_small(key) - : find_or_prepare_insert_large(key); + : find_or_prepare_insert_large<FindLargeKey<K>>(key); } // Constructs the value in the space pointed by the iterator. This only works @@ -3915,6 +4102,23 @@ class raw_hash_set { private: friend struct RawHashSetTestOnlyAccess; + // For string-like keys, we convert to string_view when calling find*_large() + // operations to (a) avoid repeatedly (i) branching on SSO or (ii) calling + // strlen(), (b) share code between the string-like types, (c) avoid + // materializing string_view on the stack just to pass a reference to it. Note + // that we don't pass FindLargeKey to find*_small() to avoid unnecessarily + // constructing string_view for small empty tables. Note: we use + // type_identity_t and static_asserts to ensure that the key type in + // find*_large is FindLargeKey. (type_identity_t ensures that the template + // argument is not deduced and must be specified explicitly.) + // TODO(ezb): extend this to other types (e.g. small trivial types). + template <class K> + using FindLargeKey = std::conditional_t< + std::is_same_v<hasher, absl::container_internal::StringHash> && + std::is_same_v<key_equal, absl::container_internal::StringEq> && + std::is_convertible_v<const K&, absl::string_view>, + const absl::string_view, const K&>; + // Prefetch the heap-allocated memory region to resolve potential TLB and // cache misses. This is intended to overlap with execution of calculating the // hash for a key. @@ -3935,10 +4139,26 @@ class raw_hash_set { } ctrl_t* control() const { ABSL_SWISSTABLE_ASSERT(!is_soo()); - return common().control(); + ctrl_t* ctrl = common().control(); + if constexpr (std::is_same_v<CharAlloc, std::allocator<char>>) { + // Assume that the control bytes don't alias `this`. Example benefit: when + // a caller mutates an element via an iterator returned by find(), the + // compiler can now prove that the store to the slot does not clobber + // CommonFields metadata (size, capacity, etc.). + // Example of benefitting user code: + // if (auto it = m.find(k1); it != m.end()) it->second = v; + // if (auto it = m.find(k2); it != m.end()) it->second = v; + // With this assumption, the second lookup avoids reloading capacity. + // Note: for custom allocators, `this` may be part of the same allocation + // as the control bytes so we cannot make this assumption. + // TODO(ezb): we could move this assumption into CommonFields::control() + // if we template the type-erased functions on whether the allocator is + // default or not. + ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE(ctrl, this); + } + return ctrl; } slot_type* slot_array(size_t capacity) const { - ABSL_SWISSTABLE_ASSERT(!is_soo()); return static_cast<slot_type*>(common().slot_array(capacity)); } slot_type* soo_slot() { @@ -3952,9 +4172,9 @@ class raw_hash_set { } slot_type* single_slot() { ABSL_SWISSTABLE_ASSERT(is_small()); - return SooEnabled() - ? soo_slot() - : to_slot(common().slot_array(/*capacity=*/1)); + // Note: we don't use common().single_non_soo_slot() here because + // control() is more efficient (due to separate storage assume). + return SooEnabled() ? soo_slot() : to_slot(control()); } const slot_type* single_slot() const { return const_cast<raw_hash_set*>(this)->single_slot(); @@ -3995,6 +4215,11 @@ class raw_hash_set { // TODO(b/397453582): Remove support for const hasher. return const_cast<std::remove_const_t<hasher>*>(&h->hash_ref()); } + static constexpr HashSlotFn get_hash_slot_fn() { + return PolicyTraits::template get_hash_slot_fn<hasher, kIsAbslHash, + kSeedShift>(); + } + static void transfer_n_slots_fn(void* set, void* dst, void* src, size_t count) { auto* src_slot = to_slot(src); @@ -4006,6 +4231,14 @@ class raw_hash_set { } } + static void copy_slot_fn(void* set, void* dst, const void* src) { + // TODO(b/413598253): type erase for trivially copyable types via + // PolicyTraits. + static_cast<raw_hash_set*>(set)->construct( + to_slot(dst), + PolicyTraits::element(static_cast<slot_type*>(const_cast<void*>(src)))); + } + static void destroy_slot_fn_impl(void* set, void* slot) { auto* h = static_cast<raw_hash_set*>(set); h->destroy(to_slot(slot)); @@ -4020,15 +4253,15 @@ class raw_hash_set { // by GetKey + Hash for memcpyable types. // TODO(b/382423690): Try to type erase for big slots: sizeof(slot_type) > 16. static void transfer_unprobed_elements_to_next_capacity_fn( - CommonFields& common, const ctrl_t* old_ctrl, void* old_slots, - void* probed_storage, - void (*encode_probed_element)(void* probed_storage, h2_t h2, - size_t source_offset, size_t h1)) { - const size_t new_capacity = common.capacity(); - ABSL_ASSUME(new_capacity > kMaxSmallCapacity); - const size_t old_capacity = PreviousCapacity(new_capacity); + CommonFields& common, const ctrl_t* old_ctrl, void* probed_storage, + void* old_slots, size_t old_capacity, + void (*encode_probed_element)(void* probed_storage, size_t hash, + size_t source_offset)) { ABSL_ASSUME(old_capacity + 1 >= Group::kWidth); ABSL_ASSUME((old_capacity + 1) % Group::kWidth == 0); + const size_t new_capacity = NextCapacity(old_capacity); + ABSL_ASSUME(new_capacity > kMaxSmallCapacity); + ABSL_SWISSTABLE_ASSERT(common.capacity() == new_capacity); auto* set = reinterpret_cast<raw_hash_set*>(&common); slot_type* old_slots_ptr = to_slot(old_slots); @@ -4050,19 +4283,17 @@ class raw_hash_set { // TODO(b/382423690): try to avoid entire hash calculation since we need // only one new bit of h1. size_t hash = set->hash_of(old_slot); - size_t h1 = H1(hash); - h2_t h2 = H2(hash); size_t new_index = TryFindNewIndexWithoutProbing( - h1, old_index, old_capacity, new_ctrl, new_capacity); + hash, old_index, old_capacity, new_ctrl, new_capacity); // Note that encode_probed_element is allowed to use old_ctrl buffer // till and included the old_index. if (ABSL_PREDICT_FALSE(new_index == kProbedElementIndexSentinel)) { - encode_probed_element(probed_storage, h2, old_index, h1); + encode_probed_element(probed_storage, hash, old_index); continue; } ABSL_SWISSTABLE_ASSERT((new_index & old_capacity) <= old_index); ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[new_index])); - new_ctrl[new_index] = static_cast<ctrl_t>(h2); + new_ctrl[new_index] = static_cast<ctrl_t>(H2(hash)); auto* new_slot = new_slots + new_index; SanitizerUnpoisonMemoryRegion(new_slot, sizeof(slot_type)); set->transfer(new_slot, old_slot); @@ -4108,13 +4339,12 @@ class raw_hash_set { static_cast<uint32_t>(sizeof(value_type)), static_cast<uint32_t>(sizeof(slot_type)), static_cast<uint16_t>(alignof(slot_type)), SooEnabled(), - ShouldSampleHashtablezInfoForAlloc<CharAlloc>(), + HashtablezForTableEnabled(), // TODO(b/328722020): try to type erase // for standard layout and alignof(Hash) <= alignof(CommonFields). std::is_empty_v<hasher> ? &GetRefForEmptyClass : &raw_hash_set::get_hash_ref_fn, - PolicyTraits::template get_hash_slot_fn<hasher, kIsAbslHash, - kSeedShift>(), + get_hash_slot_fn(), PolicyTraits::transfer_uses_memcpy() ? TransferNRelocatable<sizeof(slot_type)> : &raw_hash_set::transfer_n_slots_fn, @@ -4265,17 +4495,17 @@ struct HashtableDebugAccess<Set, std::void_t<typename Set::raw_hash_set>> { // Extern template instantiations reduce binary size and linker input size. // Function definition is in raw_hash_set.cc. extern template void* GrowSooTableToNextCapacityAndPrepareInsert<0, false>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, + CommonFields&, const PolicyFunctions&, void*, HashForKeyFn, bool); extern template void* GrowSooTableToNextCapacityAndPrepareInsert<1, true>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, + CommonFields&, const PolicyFunctions&, void*, HashForKeyFn, bool); extern template void* GrowSooTableToNextCapacityAndPrepareInsert<4, true>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, + CommonFields&, const PolicyFunctions&, void*, HashForKeyFn, bool); #if UINTPTR_MAX == UINT64_MAX extern template void* GrowSooTableToNextCapacityAndPrepareInsert<8, true>( - CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>, + CommonFields&, const PolicyFunctions&, void*, HashForKeyFn, bool); #endif @@ -4310,11 +4540,37 @@ extern template void Destruct</*kSooEnabled=*/false>( extern template void Destruct</*kSooEnabled=*/false>(CommonFields& c, const DtorPolicy& policy); +// Extern template for inline function keeps possibility of inlining. +// When compiler decided to not inline, no symbols will be added to the +// corresponding translation unit. +extern template size_t TryFindNewIndexWithoutProbing(size_t hash, + size_t old_index, + size_t old_capacity, + ctrl_t* new_ctrl, + size_t new_capacity); +extern template void AssertIsFull(const ctrl_t* const& ctrl, const void* slot, + GenerationType generation, + const GenerationType* generation_ptr, + const char* operation); +extern template void AssertIsValidForComparison( + const ctrl_t* const& ctrl, const void* slot, GenerationType generation, + const GenerationType* generation_ptr); +extern template bool AreItersFromSameContainer(const ctrl_t* const& ctrl_a, + const ctrl_t* const& ctrl_b, + const void* slot_a, + const void* slot_b); +extern template void AssertSameContainer( + const ctrl_t* const& ctrl_a, const ctrl_t* const& ctrl_b, + const void* slot_a, const void* slot_b, + const GenerationType* generation_ptr_a, + const GenerationType* generation_ptr_b); + } // namespace container_internal ABSL_NAMESPACE_END } // namespace absl #undef ABSL_SWISSTABLE_ENABLE_GENERATIONS #undef ABSL_SWISSTABLE_ASSERT +#undef ABSL_SWISSTABLE_ASSUME_SEPARATE_STORAGE #endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc index eaee003409bf..d14f9c6902db 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc @@ -439,6 +439,17 @@ TEST_F(NoPropagateOnMove, MoveAssignmentWithDifferentAlloc) { EXPECT_EQ(0, it->num_copies()); } +TEST_F(NoPropagateOnMove, MoveAssignmentWithDifferentAllocToNonEmptyTable) { + t1.insert(0); + Table u(0, a2); + for (int32_t i = 1; i <= 16; ++i) u.insert(i); + u = std::move(t1); + EXPECT_EQ(a2, u.get_allocator()); + EXPECT_EQ(1, u.size()); + EXPECT_NE(u.find(0), u.end()); + EXPECT_EQ(u.find(1), u.end()); +} + TEST_F(PropagateOnAll, Swap) { t1.insert(0); Table u(0, a2); diff --git a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc index cc252b4b2e9f..ed25c05f2efc 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc @@ -36,11 +36,13 @@ #include <random> #include <set> #include <string> +#include <string_view> #include <tuple> #include <type_traits> #include <unordered_map> #include <unordered_set> #include <utility> +#include <variant> #include <vector> #include "gmock/gmock.h" @@ -82,8 +84,8 @@ struct RawHashSetTestOnlyAccess { return std::forward<C>(c).common(); } template <typename C> - static auto GetSlots(const C& c) -> decltype(c.slot_array(c.capacity())) { - return c.slot_array(c.capacity()); + static auto GetSlots(C& c) -> decltype(c.slot_array(c.capacity())) { + return c.is_small() ? c.single_slot() : c.slot_array(c.capacity()); } template <typename C> static size_t CountTombstones(const C& c) { @@ -145,6 +147,26 @@ TEST(RawHashSetLayout, SmallCapacity) { } } +TEST(RawHashSetLayout, CreateForSmallNonSooGrowth) { + for (size_t size : {0u, 1u}) { + for (size_t slot_align : {1u, 2u, 4u, 8u, 16u}) { + for (size_t slot_size : {slot_align, slot_align * 2, slot_align * 3}) { + for (bool has_infoz : {false, true}) { + RawHashSetLayout expected(NextCapacity(size), slot_size, slot_align, + has_infoz, /*blocked_element_count=*/0); + RawHashSetLayout actual = + RawHashSetLayout::CreateForSmallNonSooGrowth( + size, slot_size, slot_align, has_infoz); + EXPECT_EQ(actual.control_offset(), expected.control_offset()); + EXPECT_EQ(actual.generation_offset(), expected.generation_offset()); + EXPECT_EQ(actual.slot_offset(), expected.slot_offset()); + EXPECT_EQ(actual.alloc_size(), expected.alloc_size()); + } + } + } + } +} + void VerifyMiddleSizeTableLayout(size_t capacity, size_t slot_size, size_t slot_align, bool has_infoz, size_t blocked_element_count, @@ -723,34 +745,21 @@ TEST(Util, probe_seq) { size_t capacity = 127; probe_seq<16> seq(ProbeCapacity{capacity}, /*hash=*/0); auto gen = [&]() { - size_t res = seq.offset(); seq.next(); - return res; + return seq.offset(); }; std::vector<size_t> offsets(8); - std::generate_n(offsets.begin(), 8, gen); + offsets[0] = seq.offset(); + std::generate_n(offsets.begin() + 1, 7, gen); EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64)); seq = probe_seq<16>(ProbeCapacity{capacity}, /*hash=*/128); - std::generate_n(offsets.begin(), 8, gen); + offsets[0] = seq.offset(); + std::generate_n(offsets.begin() + 1, 7, gen); EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64)); } -template <typename T> -class HashtableDataTest : public ::testing::Test {}; - -using StorageModes = ::testing::Types< - std::integral_constant<HashtableCapacityStorageMode, - HashtableCapacityStorageMode::kCapacityByValue>, - std::integral_constant<HashtableCapacityStorageMode, - HashtableCapacityStorageMode::kCapacityByLog>>; - -TYPED_TEST_SUITE(HashtableDataTest, StorageModes); - -TYPED_TEST(HashtableDataTest, HashtableCapacity) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using Capacity = HashtableCapacityImpl<kMode>; - - Capacity cap0(0); +TEST(HashtableDataTest, HashtableCapacity) { + HashtableCapacity cap0(0); EXPECT_TRUE(cap0.IsValid()); EXPECT_EQ(cap0.capacity(), 0); EXPECT_FALSE(cap0.IsDestroyed()); @@ -759,51 +768,46 @@ TYPED_TEST(HashtableDataTest, HashtableCapacity) { EXPECT_FALSE(cap0.IsSelfMovedFrom()); for (size_t i = 0, cap = 0; i < 20; ++i, cap = NextCapacity(cap)) { - Capacity capacity(cap); + HashtableCapacity capacity(cap); ASSERT_TRUE(capacity.IsValid()); ASSERT_EQ(capacity.capacity(), cap); } - auto destroyed = Capacity::CreateDestroyed(); + auto destroyed = HashtableCapacity::CreateDestroyed(); EXPECT_FALSE(destroyed.IsValid()); EXPECT_TRUE(destroyed.IsDestroyed()); - auto reentrance = Capacity::CreateReentrance(); + auto reentrance = HashtableCapacity::CreateReentrance(); EXPECT_FALSE(reentrance.IsValid()); EXPECT_TRUE(reentrance.IsReentrance()); - auto moved_from = Capacity::CreateMovedFrom(); + auto moved_from = HashtableCapacity::CreateMovedFrom(); EXPECT_FALSE(moved_from.IsValid()); EXPECT_TRUE(moved_from.IsMovedFrom()); EXPECT_FALSE(moved_from.IsSelfMovedFrom()); - auto self_moved_from = Capacity::CreateSelfMovedFrom(); + auto self_moved_from = HashtableCapacity::CreateSelfMovedFrom(); EXPECT_FALSE(self_moved_from.IsValid()); EXPECT_TRUE(self_moved_from.IsSelfMovedFrom()); EXPECT_TRUE(self_moved_from.IsMovedFrom()); } -TYPED_TEST(HashtableDataTest, RawData) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using Capacity = HashtableCapacityImpl<kMode>; - +TEST(HashtableDataTest, RawData) { for (size_t i = 0, cap = 0; i < 20; ++i, cap = NextCapacity(cap)) { - Capacity orig_capacity(cap); - Capacity capacity = Capacity::FromRawData(orig_capacity.ToRawData()); + HashtableCapacity orig_capacity(cap); + HashtableCapacity capacity = + HashtableCapacity::FromRawData(orig_capacity.ToRawData()); ASSERT_TRUE(capacity.IsValid()); ASSERT_EQ(capacity.capacity(), cap); } - auto orig_reentrance = Capacity::CreateReentrance(); - Capacity reentrance = Capacity::FromRawData(orig_reentrance.ToRawData()); + auto orig_reentrance = HashtableCapacity::CreateReentrance(); + HashtableCapacity reentrance = + HashtableCapacity::FromRawData(orig_reentrance.ToRawData()); EXPECT_TRUE(reentrance.IsReentrance()); } -TYPED_TEST(HashtableDataTest, HashtableInlineDataCapacity) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; - - InlineData data(Capacity(0), no_seed_empty_tag_t{}); +TEST(HashtableDataTest, HashtableInlineDataCapacity) { + HashtableInlineData data(HashtableCapacity(0), no_seed_empty_tag_t{}); EXPECT_EQ(data.capacity().capacity(), 0); EXPECT_EQ(data.size(), 0); EXPECT_TRUE(data.empty()); @@ -813,23 +817,19 @@ TYPED_TEST(HashtableDataTest, HashtableInlineDataCapacity) { ASSERT_EQ(data.capacity().capacity(), cap); } - // Test overload from `Capacity` object. + // Test overload from `HashtableCapacity` object. for (size_t i = 0, cap = 0; i < 20; ++i, cap = NextCapacity(cap)) { - data.set_capacity(Capacity(cap)); + data.set_capacity(HashtableCapacity(cap)); ASSERT_EQ(data.capacity().capacity(), cap); } - auto reentrance = Capacity::CreateReentrance(); + auto reentrance = HashtableCapacity::CreateReentrance(); data.set_capacity(reentrance); EXPECT_TRUE(data.capacity().IsReentrance()); } -TYPED_TEST(HashtableDataTest, HashtableInlineDataSize) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; - - InlineData data(Capacity(0), no_seed_empty_tag_t{}); +TEST(HashtableDataTest, HashtableInlineDataSize) { + HashtableInlineData data(HashtableCapacity(0), no_seed_empty_tag_t{}); EXPECT_EQ(data.size(), 0); data.increment_size(); EXPECT_EQ(data.size(), 1); @@ -842,7 +842,9 @@ TYPED_TEST(HashtableDataTest, HashtableInlineDataSize) { EXPECT_EQ(data.size(), 5); constexpr size_t kHugeIncrement = - (size_t(1) << (sizeof(size_t) == 4 ? 31 : 39)); + (size_t(1) << (sizeof(size_t) == 4 + ? 31 + : HashtableInlineData::kSizeBitCount - 2)); data.increment_size(kHugeIncrement); EXPECT_EQ(data.size(), kHugeIncrement + 5); @@ -853,18 +855,14 @@ TYPED_TEST(HashtableDataTest, HashtableInlineDataSize) { EXPECT_TRUE(data.has_infoz()); } -TYPED_TEST(HashtableDataTest, BlockedElementCount) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; - +TEST(HashtableDataTest, BlockedElementCount) { { - InlineData data(Capacity(0), no_seed_empty_tag_t{}); + HashtableInlineData data(HashtableCapacity(0), no_seed_empty_tag_t{}); EXPECT_EQ(data.blocked_element_count(), 0); } - for (size_t i = 0; i <= InlineData::kMaxBlockedElementCount; ++i) { - InlineData data(Capacity(0), no_seed_empty_tag_t{}); + for (size_t i = 0; i <= HashtableInlineData::kMaxBlockedElementCount; ++i) { + HashtableInlineData data(HashtableCapacity(0), no_seed_empty_tag_t{}); data.init_blocked_element_count(i); EXPECT_EQ(data.blocked_element_count(), i); data.set_blocked_element_count_to_zero(); @@ -872,15 +870,12 @@ TYPED_TEST(HashtableDataTest, BlockedElementCount) { } } -TYPED_TEST(HashtableDataTest, MaxStorableSize) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; - - InlineData data(Capacity(0), no_seed_empty_tag_t{}); +TEST(HashtableDataTest, MaxStorableSize) { + HashtableInlineData data(HashtableCapacity(0), no_seed_empty_tag_t{}); constexpr uint64_t kMaxSize = - sizeof(size_t) == 4 ? ~uint32_t{} - : (uint64_t{1} << InlineData::kSizeBitCount) - 1; + sizeof(size_t) == 4 + ? ~uint32_t{} + : (uint64_t{1} << HashtableInlineData::kSizeBitCount) - 1; data.init_blocked_element_count(3); data.increment_size(kMaxSize); EXPECT_EQ(data.size(), kMaxSize); @@ -889,12 +884,8 @@ TYPED_TEST(HashtableDataTest, MaxStorableSize) { EXPECT_EQ(data.blocked_element_count(), 3); } -TYPED_TEST(HashtableDataTest, HashtableInlineDataMetadata) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; - - InlineData data(Capacity(0), no_seed_empty_tag_t{}); +TEST(HashtableDataTest, HashtableInlineDataMetadata) { + HashtableInlineData data(HashtableCapacity(0), no_seed_empty_tag_t{}); // SOO sampling (test this first before seed messes with bit 0) EXPECT_FALSE(data.soo_has_tried_sampling()); @@ -913,35 +904,29 @@ TYPED_TEST(HashtableDataTest, HashtableInlineDataMetadata) { EXPECT_TRUE(data.has_infoz()); } -TYPED_TEST(HashtableDataTest, HashtableInlineDataFullSooConstructor) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; - +TEST(HashtableDataTest, HashtableInlineDataFullSooConstructor) { { - InlineData data_soo(Capacity(1), full_soo_tag_t{}, - /*has_tried_sampling=*/true); + HashtableInlineData data_soo(HashtableCapacity(1), full_soo_tag_t{}, + /*has_tried_sampling=*/true); EXPECT_EQ(data_soo.capacity().capacity(), 1); EXPECT_EQ(data_soo.size(), 1); EXPECT_TRUE(data_soo.soo_has_tried_sampling()); } { - InlineData data_soo(Capacity(1), full_soo_tag_t{}, - /*has_tried_sampling=*/false); + HashtableInlineData data_soo(HashtableCapacity(1), full_soo_tag_t{}, + /*has_tried_sampling=*/false); EXPECT_EQ(data_soo.capacity().capacity(), 1); EXPECT_EQ(data_soo.size(), 1); EXPECT_FALSE(data_soo.soo_has_tried_sampling()); } } -TYPED_TEST(HashtableDataTest, GenerateNewSeedDoesntChangeSize) { - constexpr HashtableCapacityStorageMode kMode = TypeParam::value; - using InlineData = HashtableInlineDataImpl<kMode>; - using Capacity = HashtableCapacityImpl<kMode>; +TEST(HashtableDataTest, GenerateNewSeedDoesntChangeSize) { size_t size = 1; do { - InlineData inline_data(Capacity(15), no_seed_empty_tag_t{}); + HashtableInlineData inline_data(HashtableCapacity(15), + no_seed_empty_tag_t{}); inline_data.increment_size(size); EXPECT_EQ(inline_data.size(), size); inline_data.generate_new_seed(); @@ -1362,18 +1347,10 @@ TEST(Table, EmptyFunctorOptimization) { static_assert(std::is_empty_v<std::equal_to<absl::string_view>>); static_assert(std::is_empty_v<std::allocator<int>>); - struct MockTableByValue { - size_t capacity; + struct MockTable { uint64_t size; void* ctrl; }; - struct MockTableByLog { - uint64_t size; - void* ctrl; - }; - using MockTable = - std::conditional_t<HashtableInlineData::kStorageMode == kCapacityByValue, - MockTableByValue, MockTableByLog>; struct StatelessHash { size_t operator()(absl::string_view) const { return 0; } }; @@ -1547,6 +1524,7 @@ TEST(Table, ReservedTableRehashWithoutGrowthWorksWell) { if (SwisstableGenerationsEnabled()) { GTEST_SKIP() << "Generations enabled, so rehash happening earlier."; } + DisableSampling(); constexpr int64_t kCoef = 17; int retries = 0; for (size_t capacity = 31; capacity < 256; @@ -1629,6 +1607,7 @@ TEST(Table, << "Note that reservation doesn't prevent rehashing since we " "are erasing one element."; } + DisableSampling(); constexpr int64_t kCoef = 17; constexpr size_t kCapacity = 31; constexpr size_t kReserveSize = @@ -1964,6 +1943,94 @@ TEST(Table, InsertOverloads) { Pair("DEF", "!!!"))); } +struct CopyTracker { + static inline int num_copies = 0; + CopyTracker() = default; + CopyTracker(const CopyTracker&) { ++num_copies; } + CopyTracker(CopyTracker&&) = default; + + bool operator==(const CopyTracker&) const { return true; } + + template <typename H> + friend H AbslHashValue(H h, const CopyTracker&) { + return H::combine(std::move(h)); + } +}; + +struct MoveTracker { + static inline int num_destructions = 0; + static inline int num_moves = 0; + ~MoveTracker() { ++num_destructions; } + MoveTracker() = default; + MoveTracker(const MoveTracker&) = default; + MoveTracker(MoveTracker&&) { ++num_moves; } + + bool operator==(const MoveTracker&) const { return true; } + + template <typename H> + friend H AbslHashValue(H h, const MoveTracker&) { + return H::combine(std::move(h)); + } +}; + +TEST(Table, InsertDoesNotAccidentallyCopy) { + CopyTracker::num_copies = 0; + { + ValueTable<CopyTracker> tc; + EXPECT_TRUE(tc.insert(CopyTracker()).second); + tc.insert(tc.end(), CopyTracker()); + } + EXPECT_EQ(CopyTracker::num_copies, 0); + + int num_default_constructs = 0; + MoveTracker::num_moves = 0; + MoveTracker::num_destructions = 0; + { + ValueTable<MoveTracker> tm; + EXPECT_TRUE(tm.insert((++num_default_constructs, MoveTracker())).second); + tm.insert(tm.end(), (++num_default_constructs, MoveTracker())); + } + EXPECT_EQ(MoveTracker::num_destructions - num_default_constructs, + MoveTracker::num_moves); +} + +TEST(Table, InsertWithMovesCollapsedIntoCopy) { + { + ValueTable<std::string_view> t; + EXPECT_TRUE(t.insert(std::string_view("a")).second); + EXPECT_EQ(*t.insert(t.end(), std::string_view("b")), "b"); + } + { + ValueTable<std::array<int, 2>> t; + EXPECT_TRUE(t.insert(std::array<int, 2>{1, 2}).second); + EXPECT_EQ(*t.insert(t.end(), std::array<int, 2>{3, 4}), + (std::array<int, 2>{3, 4})); + } + { + ValueTable<std::optional<int>> t; + EXPECT_TRUE(t.insert(std::optional<int>(1)).second); + EXPECT_EQ(*t.insert(t.end(), std::optional<int>(2)), 2); + } + { + ValueTable<std::pair<int, int>> t; + EXPECT_TRUE(t.insert(std::pair<int, int>{1, 2}).second); + EXPECT_EQ(*t.insert(t.end(), std::pair<int, int>{3, 4}), + (std::pair<int, int>{3, 4})); + } + { + ValueTable<std::tuple<int, int>> t; + EXPECT_TRUE(t.insert(std::tuple<int, int>{1, 2}).second); + EXPECT_EQ(*t.insert(t.end(), std::tuple<int, int>{3, 4}), + (std::tuple<int, int>{3, 4})); + } + { + ValueTable<std::variant<int, double>> t; + EXPECT_TRUE(t.insert(std::variant<int, double>{1}).second); + EXPECT_EQ(*t.insert(t.end(), std::variant<int, double>{2.5}), + (std::variant<int, double>{2.5})); + } +} + TYPED_TEST(SooTest, LargeTable) { TypeParam t; for (int64_t i = 0; i != 10000; ++i) { @@ -3750,6 +3817,90 @@ TEST(Table, HeterogeneousLookupOverloads) { EXPECT_TRUE((VerifyResultOf<CallCount, TransparentTable>())); } +TEST(Table, StringViewConversionCount) { + DisableSampling(); + + struct ConvertibleToStringView { + absl::string_view value; + mutable int num_conversions = 0; + + operator absl::string_view() const { // NOLINT(runtime/explicit) + ++num_conversions; + return value; + } + }; + + const auto test_table = [](auto soo) { + using Policy = ValuePolicy<absl::string_view, /*kTransferable=*/true, + /*kSoo=*/decltype(soo)::value>; + using Table = raw_hash_set<Policy, hash_default_hash<absl::string_view>, + hash_default_eq<absl::string_view>>; + Table t; + + // Empty table: no conversion to string_view. + { + ConvertibleToStringView k{"a"}; + EXPECT_EQ(t.find(k), t.end()); + EXPECT_EQ(k.num_conversions, 0); + } + { + ConvertibleToStringView k{"a"}; + t.lazy_emplace(k, [&](const auto& ctor) { + EXPECT_EQ(k.num_conversions, 0); + ctor("a"); + }); + } + + // Single-element table: 1 conversion to string_view. + ASSERT_TRUE(RawHashSetTestOnlyAccess::GetCommon(t).is_small()); + { + ConvertibleToStringView k{"a"}; + EXPECT_NE(t.find(k), t.end()); + EXPECT_EQ(k.num_conversions, 1); + } + { + ConvertibleToStringView k{"b"}; + EXPECT_EQ(t.find(k), t.end()); + EXPECT_EQ(k.num_conversions, 1); + } + { + ConvertibleToStringView k{"a"}; + EXPECT_FALSE(t.emplace(k).second); + EXPECT_EQ(k.num_conversions, 1); + } + + // Many-element table: 1 conversion to string_view. + t.insert("b"); + t.insert("c"); + ASSERT_FALSE(RawHashSetTestOnlyAccess::GetCommon(t).is_small()); + { + ConvertibleToStringView k{"a"}; + EXPECT_NE(t.find(k), t.end()); + EXPECT_EQ(k.num_conversions, 1); + } + { + ConvertibleToStringView k{"z"}; + EXPECT_EQ(t.find(k), t.end()); + EXPECT_EQ(k.num_conversions, 1); + } + { + ConvertibleToStringView k{"a"}; + EXPECT_FALSE(t.emplace(k).second); + EXPECT_EQ(k.num_conversions, 1); + } + { + ConvertibleToStringView k{"d"}; + t.lazy_emplace(k, [&](const auto& ctor) { + EXPECT_EQ(k.num_conversions, 1); + ctor("d"); + }); + } + }; + + test_table(/*soo=*/std::false_type{}); + test_table(/*soo=*/std::true_type{}); +} + TEST(Iterator, IsDefaultConstructible) { StringTable::iterator i; EXPECT_TRUE(i == StringTable::iterator()); @@ -4089,6 +4240,23 @@ TEST(RawHashSamplerTest, SooTableInsertToEmpty) { } } +TEST(RawHashSamplerTest, NonSooTableInsertToEmpty) { + std::vector<const HashtablezInfo*> infos = + SampleNonSooMutation([](NonSooIntTable& t) { t.insert(1); }); + + for (const HashtablezInfo* info : infos) { + ASSERT_EQ(info->inline_element_size, + sizeof(typename NonSooIntTable::value_type)); + ASSERT_EQ(info->soo_capacity, 0); + ASSERT_EQ(info->capacity, 1); + ASSERT_EQ(info->size, 1); + ASSERT_EQ(info->max_reserve, 0); + ASSERT_EQ(info->num_erases, 0); + ASSERT_EQ(info->max_probe_length, 0); + ASSERT_EQ(info->total_probe_length, 0); + } +} + // Verifies that repeated insertions and erasures on an SOO table do not cause // the sampling decision to be evaluated multiple times, preventing // oversampling. @@ -5148,7 +5316,9 @@ TEST(Table, MaxValidSize) { if (key_size <= 4) { ASSERT_EQ(max_size, uint64_t{1} << 8 * key_size); } else if (i <= 21) { - ASSERT_GE(max_size, uint64_t{1} << 40); + // Small slot sizes are limited only by the number of size bits. + ASSERT_GE(max_size, + (uint64_t{1} << HashtableInlineData::kSizeBitCount) - 1); } ASSERT_LE(max_size, uint64_t{1} << HashtableInlineData::kSizeBitCount); ASSERT_LT(absl::uint128(max_size) * slot_size, uint64_t{1} << 63); @@ -5264,6 +5434,7 @@ TEST(Table, GrowExtremelyLargeTable) { NextCapacity(ProbedItem8Bytes::kMaxNewCapacity); #endif + DisableSampling(); absl::flat_hash_set<UnalignedInt32, ZeroHash> t(21); CommonFields& common = RawHashSetTestOnlyAccess::GetCommon(t); // Set 0 seed so that H1 is always 0. diff --git a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map.h b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map.h index 6d0e320cafc7..60d53d35a2ee 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map.h @@ -248,6 +248,7 @@ class linked_hash_map { if (get_allocator() == other.get_allocator()) { *this = std::move(other); } else { + reserve(other.size()); CopyFrom(std::move(other)); } } @@ -267,11 +268,32 @@ class linked_hash_map { linked_hash_map& operator=(linked_hash_map&& other) noexcept { if (this != &other) { - // underlying containers will handle progagate_on_container_move details - set_ = std::move(other.set_); - list_ = std::move(other.list_); - other.set_.clear(); - other.list_.clear(); + using AllocTraits = std::allocator_traits<Alloc>; + if constexpr (AllocTraits::propagate_on_container_move_assignment:: + value) { + set_ = std::move(other.set_); + list_ = std::move(other.list_); + other.clear(); + } else if (AllocTraits::is_always_equal::value || + get_allocator() == other.get_allocator()) { + // The allocators are equal, so the list can take over other's nodes. + // std::list's move assignment can not be used here: with an allocator + // that does not propagate on move assignment it element-assigns, which + // is ill-formed for value_type, std::pair<const K, V>. + clear(); + set_ = std::move(other.set_); + list_.splice(list_.end(), other.list_); + other.set_.clear(); + } else if constexpr (!AllocTraits::is_always_equal::value) { + // The list can not take over other's nodes, so move each element into + // a new node allocated with this map's allocator and rebuild the index + // over them, adopting other's hash and equality state. This is the + // same pattern as raw_hash_set::move_assign. + clear(); + set_ = SetType(other.size(), other.set_.hash_function(), + other.set_.key_eq(), get_allocator()); + CopyFrom(std::move(other)); + } } return *this; } @@ -414,7 +436,8 @@ class linked_hash_map { return LazyEmplaceInternal(key).first->second; } - template <class K = key_type, K* = nullptr> + template <class K = key_type, + std::enable_if_t<!std::is_reference_v<K>, int> = 0> mapped_type& operator[](key_arg<K>&& key) { return LazyEmplaceInternal(std::forward<key_arg<K>>(key)).first->second; } @@ -463,19 +486,22 @@ class linked_hash_map { // union { int n : 1; }; // linked_hash_map<int, int> m; // m.insert_or_assign(n, n); - template <class K = key_type, class V = mapped_type, K* = nullptr, - V* = nullptr> + template <class K = key_type, class V = mapped_type, + std::enable_if_t<!std::is_reference_v<K> && !std::is_reference_v<V>, + int> = 0> std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) { return InsertOrAssignInternal(std::forward<key_arg<K>>(k), std::forward<V>(v)); } - template <class K = key_type, class V = mapped_type, K* = nullptr> + template <class K = key_type, class V = mapped_type, + std::enable_if_t<!std::is_reference_v<K>, int> = 0> std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) { return InsertOrAssignInternal(std::forward<key_arg<K>>(k), v); } - template <class K = key_type, class V = mapped_type, V* = nullptr> + template <class K = key_type, class V = mapped_type, + std::enable_if_t<!std::is_reference_v<V>, int> = 0> std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) { return InsertOrAssignInternal(k, std::forward<V>(v)); } @@ -485,19 +511,22 @@ class linked_hash_map { return InsertOrAssignInternal(k, v); } - template <class K = key_type, class V = mapped_type, K* = nullptr, - V* = nullptr> + template <class K = key_type, class V = mapped_type, + std::enable_if_t<!std::is_reference_v<K> && !std::is_reference_v<V>, + int> = 0> iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) { return insert_or_assign(std::forward<key_arg<K>>(k), std::forward<V>(v)) .first; } - template <class K = key_type, class V = mapped_type, K* = nullptr> + template <class K = key_type, class V = mapped_type, + std::enable_if_t<!std::is_reference_v<K>, int> = 0> iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v) { return insert_or_assign(std::forward<key_arg<K>>(k), v).first; } - template <class K = key_type, class V = mapped_type, V* = nullptr> + template <class K = key_type, class V = mapped_type, + std::enable_if_t<!std::is_reference_v<V>, int> = 0> iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v) { return insert_or_assign(k, std::forward<V>(v)).first; } @@ -518,7 +547,8 @@ class linked_hash_map { return {list_iter, true}; } - template <class K = key_type, class... Args, K* = nullptr> + template <class K = key_type, class... Args, + std::enable_if_t<!std::is_reference_v<K>, int> = 0> iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) { return try_emplace(std::forward<key_arg<K>>(k), std::forward<Args>(args)...) .first; @@ -529,7 +559,8 @@ class linked_hash_map { return emplace(std::forward<Args>(args)...).first; } - template <class K = key_type, typename... Args, K* = nullptr> + template <class K = key_type, typename... Args, + std::enable_if_t<!std::is_reference_v<K>, int> = 0> std::pair<iterator, bool> try_emplace(key_arg<K>&& key, Args&&... args) { return LazyEmplaceInternal(std::forward<key_arg<K>>(key), std::forward<Args>(args)...); @@ -621,6 +652,12 @@ class linked_hash_map { for (auto& elem : other.list_) { set_.insert(list_.insert(list_.end(), std::move(elem))); } + if constexpr (!std::is_const_v<std::remove_reference_t<Other>>) { + // When moving from `other`, `std::move(elem)` above mutates the elements + // of `other.list_` in place, invalidating `other.set_`'s index over them. + // Clear `other` so its `set_` and `list_` remain consistent and empty. + other.clear(); + } assert(set_.size() == list_.size()); } diff --git a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map_test.cc index a905e920c4cd..ef03e13884cb 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_map_test.cc @@ -47,6 +47,7 @@ namespace container_internal { namespace { using ::testing::ElementsAre; +using ::testing::IsEmpty; using ::testing::Pair; using ::testing::Pointee; @@ -821,6 +822,136 @@ TEST(LinkedHashMap, ExtractAndEmplaceUseSameStatefulAllocator) { << "extract(key) failed to use the same allocator"; } +// Move-assigning with an unequal, non-propagating allocator must move each +// element into a node allocated with the destination's allocator and rebuild +// the index over those nodes. Previously the index kept pointing at the +// source's nodes, which the source then freed, so the first lookup read freed +// memory (heap-use-after-free). +TEST(LinkedHashMap, MoveAssignWithUnequalNonPropagatingAllocator) { + using Alloc = + absl::container_internal::CountingAllocator<std::pair<const int, int>>; + int64_t bytes_used_a = 0; + int64_t bytes_used_b = 0; + Alloc alloc_a(&bytes_used_a); + Alloc alloc_b(&bytes_used_b); + ASSERT_NE(alloc_a, alloc_b); + using Map = linked_hash_map<int, int, linked_hash_map<int, int>::hasher, + std::equal_to<>, Alloc>; + + { + Map a(alloc_a); + a.insert({11, 110}); + a.insert({22, 220}); + a.insert({33, 330}); + const int64_t bytes_used_a_before = bytes_used_a; + EXPECT_GT(bytes_used_a_before, 0); + EXPECT_EQ(bytes_used_b, 0); + + // Move-assign into an empty map. + Map b(alloc_b); + b = std::move(a); + EXPECT_EQ(b.get_allocator(), alloc_b); + EXPECT_LT(bytes_used_a, bytes_used_a_before); + EXPECT_GT(bytes_used_b, 0); + EXPECT_THAT(b, ElementsAre(Pair(11, 110), Pair(22, 220), Pair(33, 330))); + auto found = b.find(22); + ASSERT_NE(found, b.end()); + EXPECT_EQ(found->second, 220); + EXPECT_EQ(b.erase(22), 1); + EXPECT_THAT(b, ElementsAre(Pair(11, 110), Pair(33, 330))); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + + // Move-assign into a non-empty map: the old elements must be gone. + Map c(alloc_b); + c.insert({1, 10}); + c.insert({2, 20}); + a.clear(); + a.insert({44, 440}); + a.insert({55, 550}); + c = std::move(a); + EXPECT_EQ(c.get_allocator(), alloc_b); + EXPECT_THAT(c, ElementsAre(Pair(44, 440), Pair(55, 550))); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + } + EXPECT_EQ(bytes_used_a, 0); + EXPECT_EQ(bytes_used_b, 0); +} + +// Move-assigning with equal allocators must keep taking over the source's +// nodes (and its index) without allocating. +TEST(LinkedHashMap, MoveAssignWithEqualAllocatorTakesOverNodes) { + using Alloc = + absl::container_internal::CountingAllocator<std::pair<const int, int>>; + int64_t bytes_used = 0; + Alloc alloc(&bytes_used); + using Map = linked_hash_map<int, int, linked_hash_map<int, int>::hasher, + std::equal_to<>, Alloc>; + + { + // Note: some STL implementations (e.g. MSVC) allocate a sentinel node + // (and debug proxy) in std::list's default constructor. + Map a(alloc); + const int64_t empty_map_bytes = bytes_used; + a.insert({11, 110}); + a.insert({22, 220}); + Map b(alloc); + const int64_t bytes_used_before = bytes_used; + b = std::move(a); + EXPECT_EQ(bytes_used, bytes_used_before); + EXPECT_THAT(b, ElementsAre(Pair(11, 110), Pair(22, 220))); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + + // Move-assign into a non-empty map: the old elements must be freed and the + // source's nodes taken over without new allocations. + Map c(alloc); + c.insert({1, 10}); + c.insert({2, 20}); + c.insert({3, 30}); + EXPECT_GT(bytes_used, bytes_used_before + empty_map_bytes); + c = std::move(b); + EXPECT_EQ(bytes_used, bytes_used_before + empty_map_bytes); + EXPECT_THAT(c, ElementsAre(Pair(11, 110), Pair(22, 220))); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(b, IsEmpty()); + } + EXPECT_EQ(bytes_used, 0); +} + +// Move-assigning with an allocator that propagates on move assignment must +// propagate the allocator, even when the allocators are unequal. +TEST(LinkedHashMap, MoveAssignWithPropagatingAllocatorPropagates) { + using Alloc = absl::container_internal::MoveAssignPropagatingCountingAlloc< + std::pair<const int, int>>; + int64_t bytes_used_a = 0; + int64_t bytes_used_b = 0; + Alloc alloc_a(&bytes_used_a); + Alloc alloc_b(&bytes_used_b); + ASSERT_NE(alloc_a, alloc_b); + using Map = linked_hash_map<int, int, linked_hash_map<int, int>::hasher, + std::equal_to<>, Alloc>; + + { + Map a(alloc_a); + a.insert({11, 110}); + a.insert({22, 220}); + const int64_t bytes_used_a_before = bytes_used_a; + Map b(alloc_b); + const int64_t empty_map_bytes = bytes_used_b; + b = std::move(a); + EXPECT_EQ(b.get_allocator(), alloc_a); + EXPECT_EQ(bytes_used_a, bytes_used_a_before + empty_map_bytes); + EXPECT_EQ(bytes_used_b, 0); + EXPECT_THAT(b, ElementsAre(Pair(11, 110), Pair(22, 220))); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + } + EXPECT_EQ(bytes_used_a, 0); + EXPECT_EQ(bytes_used_b, 0); +} + TEST(LinkedHashMap, Merge) { linked_hash_map<int, int> m = {{1, 7}, {3, 6}}; linked_hash_map<int, int> src = {{1, 10}, {2, 9}, {4, 16}}; diff --git a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set.h b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set.h index 7fe0adc09d68..18bee87efc41 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set.h +++ b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set.h @@ -237,6 +237,7 @@ class linked_hash_set { if (get_allocator() == other.get_allocator()) { *this = std::move(other); } else { + reserve(other.size()); CopyFrom(std::move(other)); } } @@ -256,10 +257,33 @@ class linked_hash_set { linked_hash_set& operator=(linked_hash_set&& other) noexcept { if (this != &other) { - set_ = std::move(other.set_); - list_ = std::move(other.list_); - other.set_.clear(); - other.list_.clear(); + using AllocTraits = std::allocator_traits<Alloc>; + if constexpr (AllocTraits::propagate_on_container_move_assignment:: + value) { + set_ = std::move(other.set_); + list_ = std::move(other.list_); + other.clear(); + } else if (AllocTraits::is_always_equal::value || + get_allocator() == other.get_allocator()) { + // The allocators are equal, so the list can take over other's nodes. + // std::list's move assignment can not be used here: with an allocator + // that does not propagate on move assignment it element-assigns, which + // is ill-formed for value types that are not assignable, such as + // linked_hash_map's std::pair<const K, V>. + clear(); + set_ = std::move(other.set_); + list_.splice(list_.end(), other.list_); + other.set_.clear(); + } else if constexpr (!AllocTraits::is_always_equal::value) { + // The list can not take over other's nodes, so move each element into + // a new node allocated with this set's allocator and rebuild the index + // over them, adopting other's hash and equality state. This is the + // same pattern as raw_hash_set::move_assign. + clear(); + set_ = SetType(other.size(), other.set_.hash_function(), + other.set_.key_eq(), get_allocator()); + CopyFrom(std::move(other)); + } } return *this; } @@ -377,7 +401,8 @@ class linked_hash_set { std::pair<iterator, bool> insert(const key_arg<K>& k) { return InsertInternal(list_.end(), k); } - template <typename K = key_type, K* = nullptr> + template <typename K = key_type, + std::enable_if_t<!std::is_reference_v<K>, int> = 0> std::pair<iterator, bool> insert(key_arg<K>&& k) { return InsertInternal(list_.end(), std::move(k)); } @@ -390,11 +415,12 @@ class linked_hash_set { iterator insert(const_iterator hint, const key_arg<K>& k) { return InsertInternal(hint, k).first; } - template < - typename K = key_type, K* = nullptr, - std::enable_if_t<!std::is_convertible_v<key_arg<K>&&, const_iterator> && - !std::is_convertible_v<key_arg<K>&&, iterator>, - int> = 0> + template <typename K = key_type, + std::enable_if_t< + !std::is_reference_v<K> && + !std::is_convertible_v<key_arg<K>&&, const_iterator> && + !std::is_convertible_v<key_arg<K>&&, iterator>, + int> = 0> iterator insert(const_iterator hint, key_arg<K>&& k) { return InsertInternal(hint, std::move(k)).first; } @@ -494,6 +520,12 @@ class linked_hash_set { for (auto& elem : other.list_) { set_.insert(list_.insert(list_.end(), std::move(elem))); } + if constexpr (!std::is_const_v<std::remove_reference_t<Other>>) { + // When moving from `other`, `std::move(elem)` above mutates the elements + // of `other.list_` in place, invalidating `other.set_`'s index over them. + // Clear `other` so its `set_` and `list_` remain consistent and empty. + other.clear(); + } assert(set_.size() == list_.size()); } diff --git a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set_test.cc b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set_test.cc index 340d6e3f5930..5e4c176a5bc2 100644 --- a/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/container/linked_hash_set_test.cc @@ -45,6 +45,7 @@ namespace { using ::testing::ElementsAre; using ::testing::ElementsAreArray; +using ::testing::IsEmpty; using ::testing::Pointee; template <class T> @@ -851,6 +852,134 @@ TEST(LinkedHashSet, ExtractAndEmplaceUseSameStatefulAllocator) { << "extract(key) failed to use the same allocator"; } +// Move-assigning with an unequal, non-propagating allocator must move each +// element into a node allocated with the destination's allocator and rebuild +// the index over those nodes. Previously the index kept pointing at the +// source's nodes, which the source then freed, so the first lookup read freed +// memory (heap-use-after-free). +TEST(LinkedHashSet, MoveAssignWithUnequalNonPropagatingAllocator) { + using Alloc = absl::container_internal::CountingAllocator<int>; + int64_t bytes_used_a = 0; + int64_t bytes_used_b = 0; + Alloc alloc_a(&bytes_used_a); + Alloc alloc_b(&bytes_used_b); + ASSERT_NE(alloc_a, alloc_b); + using Set = linked_hash_set<int, linked_hash_set<int>::hasher, + std::equal_to<>, Alloc>; + + { + Set a(alloc_a); + a.insert(11); + a.insert(22); + a.insert(33); + const int64_t bytes_used_a_before = bytes_used_a; + EXPECT_GT(bytes_used_a_before, 0); + EXPECT_EQ(bytes_used_b, 0); + + // Move-assign into an empty set. + Set b(alloc_b); + b = std::move(a); + EXPECT_EQ(b.get_allocator(), alloc_b); + EXPECT_LT(bytes_used_a, bytes_used_a_before); + EXPECT_GT(bytes_used_b, 0); + EXPECT_THAT(b, ElementsAre(11, 22, 33)); + auto found = b.find(22); + ASSERT_NE(found, b.end()); + EXPECT_EQ(*found, 22); + EXPECT_EQ(b.erase(22), 1); + EXPECT_THAT(b, ElementsAre(11, 33)); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + + // Move-assign into a non-empty set: the old elements must be gone. + Set c(alloc_b); + c.insert(1); + c.insert(2); + a.clear(); + a.insert(44); + a.insert(55); + c = std::move(a); + EXPECT_EQ(c.get_allocator(), alloc_b); + EXPECT_THAT(c, ElementsAre(44, 55)); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + } + EXPECT_EQ(bytes_used_a, 0); + EXPECT_EQ(bytes_used_b, 0); +} + +// Move-assigning with equal allocators must keep taking over the source's +// nodes (and its index) without allocating. +TEST(LinkedHashSet, MoveAssignWithEqualAllocatorTakesOverNodes) { + using Alloc = absl::container_internal::CountingAllocator<int>; + int64_t bytes_used = 0; + Alloc alloc(&bytes_used); + using Set = linked_hash_set<int, linked_hash_set<int>::hasher, + std::equal_to<>, Alloc>; + + { + // Note: some STL implementations (e.g. MSVC) allocate a sentinel node + // (and debug proxy) in std::list's default constructor. + Set a(alloc); + const int64_t empty_set_bytes = bytes_used; + a.insert(11); + a.insert(22); + Set b(alloc); + const int64_t bytes_used_before = bytes_used; + b = std::move(a); + EXPECT_EQ(bytes_used, bytes_used_before); + EXPECT_THAT(b, ElementsAre(11, 22)); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + + // Move-assign into a non-empty set: the old elements must be freed and the + // source's nodes taken over without new allocations. + Set c(alloc); + c.insert(1); + c.insert(2); + c.insert(3); + EXPECT_GT(bytes_used, bytes_used_before + empty_set_bytes); + c = std::move(b); + EXPECT_EQ(bytes_used, bytes_used_before + empty_set_bytes); + EXPECT_THAT(c, ElementsAre(11, 22)); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(b, IsEmpty()); + } + EXPECT_EQ(bytes_used, 0); +} + +// Move-assigning with an allocator that propagates on move assignment must +// propagate the allocator, even when the allocators are unequal. +TEST(LinkedHashSet, MoveAssignWithPropagatingAllocatorPropagates) { + using Alloc = + absl::container_internal::MoveAssignPropagatingCountingAlloc<int>; + int64_t bytes_used_a = 0; + int64_t bytes_used_b = 0; + Alloc alloc_a(&bytes_used_a); + Alloc alloc_b(&bytes_used_b); + ASSERT_NE(alloc_a, alloc_b); + using Set = linked_hash_set<int, linked_hash_set<int>::hasher, + std::equal_to<>, Alloc>; + + { + Set a(alloc_a); + a.insert(11); + a.insert(22); + const int64_t bytes_used_a_before = bytes_used_a; + Set b(alloc_b); + const int64_t empty_set_bytes = bytes_used_b; + b = std::move(a); + EXPECT_EQ(b.get_allocator(), alloc_a); + EXPECT_EQ(bytes_used_a, bytes_used_a_before + empty_set_bytes); + EXPECT_EQ(bytes_used_b, 0); + EXPECT_THAT(b, ElementsAre(11, 22)); + // NOLINTNEXTLINE(bugprone-use-after-move) + EXPECT_THAT(a, IsEmpty()); + } + EXPECT_EQ(bytes_used_a, 0); + EXPECT_EQ(bytes_used_b, 0); +} + TEST(LinkedHashSet, Merge) { linked_hash_set<int> m = {1, 7, 3, 6, 10}; linked_hash_set<int> src = {1, 2, 9, 10, 4, 16}; diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.bazel index 10b5a5f5399b..7d634ce6ea67 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.bazel @@ -143,6 +143,9 @@ cc_test( visibility = ["//visibility:private"], deps = [ ":crc32c", + ":crc_internal", + "//absl/base:config", + "//absl/base:core_headers", "//absl/memory", "//absl/random", "//absl/random:distributions", diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.gn index f0c8e74715f8..44dc7ced26b6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/crc/BUILD.gn @@ -86,6 +86,9 @@ absl_test("crc_memcpy_test") { sources = [ "internal/crc_memcpy_test.cc" ] deps = [ ":crc32c", + ":crc_internal", + "//third_party/abseil-cpp/absl/base:config", + "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/random", "//third_party/abseil-cpp/absl/random:distributions", diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/crc/CMakeLists.txt index 426939626523..e50b2429cd71 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/crc/CMakeLists.txt @@ -112,13 +112,18 @@ absl_cc_test( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::config + absl::core_headers absl::crc32c + absl::crc_internal absl::memory absl::random_distributions absl::random_random absl::string_view absl::strings GTest::gtest_main + SHARD_COUNT + 3 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/crc32c.cc b/deps/v8/third_party/abseil-cpp/absl/crc/crc32c.cc index ed826e21e0fa..902056373c4a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/crc32c.cc +++ b/deps/v8/third_party/abseil-cpp/absl/crc/crc32c.cc @@ -17,7 +17,6 @@ #include <cstddef> #include <cstdint> -#include "absl/base/config.h" #include "absl/crc/internal/crc.h" #include "absl/crc/internal/crc32c.h" #include "absl/crc/internal/crc_memcpy.h" diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.cc b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.cc index d135e3c87be0..6041c4319979 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.cc +++ b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.cc @@ -43,9 +43,10 @@ #include <cstddef> #include <cstdint> +#include <cstring> #include <iterator> -#include "absl/base/config.h" +#include "absl/base/attributes.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/prefetch.h" @@ -291,8 +292,7 @@ void CRC32::Extend(uint32_t* crc, const void* bytes, size_t length) const { // starting at `ptr` and twelve zero bytes, so that four CRCs can be // built incrementally and combined at the end. const auto step_swath = [this](uint32_t crc_in, const std::uint8_t* ptr) { - return absl::little_endian::Load32(ptr) ^ - this->table_[3][crc_in & 0xff] ^ + return absl::little_endian::Load32(ptr) ^ this->table_[3][crc_in & 0xff] ^ this->table_[2][(crc_in >> 8) & 0xff] ^ this->table_[1][(crc_in >> 16) & 0xff] ^ this->table_[0][crc_in >> 24]; @@ -426,12 +426,29 @@ void CRC32::Unscramble(uint32_t* crc) const { CRC::~CRC() {} CRC::CRC() {} +void CRC::ExtendAndCopy(uint32_t* crc, void* __restrict dst, + const void* __restrict src, size_t length, + bool /*non_temporal*/) const { + std::memcpy(dst, src, length); + Extend(crc, dst, length); +} + // The "constructor" for a CRC32C with a standard polynomial. CRC* CRC::Crc32c() { static CRC* singleton = CRCImpl::NewInternal(); return singleton; } +#ifndef NDEBUG +ABSL_ATTRIBUTE_WEAK +#endif +void DebugReportNonTemporalStore() {} + +#ifndef NDEBUG +ABSL_ATTRIBUTE_WEAK +#endif +void DebugReportStoreFence() {} + } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.h b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.h index 90e05f1a89bb..5f9306cbaee3 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.h +++ b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc.h @@ -18,6 +18,7 @@ #include <cstddef> #include <cstdint> +#include "absl/base/attributes.h" #include "absl/base/config.h" // This class implements CRCs (aka Rabin Fingerprints). @@ -47,6 +48,12 @@ class CRC { virtual void Extend(uint32_t* crc, const void* bytes, size_t length) const = 0; + // Copy 'length' bytes from 'src' to 'dst' and extend the CRC with the copied + // bytes. + virtual void ExtendAndCopy(uint32_t* crc, void* __restrict dst, + const void* __restrict src, size_t length, + bool non_temporal) const; + // Equivalent to Extend(crc, bytes, length) where "bytes" // points to an array of "length" zero bytes. virtual void ExtendByZeroes(uint32_t* crc, size_t length) const = 0; @@ -76,6 +83,10 @@ class CRC { CRC(const CRC&) = delete; CRC& operator=(const CRC&) = delete; }; +// Bookkeeping hooks called by non-temporal store functions and +// NonTemporalStoreFence(), for use in tests. +void DebugReportNonTemporalStore(); +void DebugReportStoreFence(); } // namespace crc_internal ABSL_NAMESPACE_END diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h index c50a3013c741..f1bb85b4baf7 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h +++ b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h @@ -16,9 +16,13 @@ #define ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ #include <array> +#include <cstddef> #include <cstdint> +#include <cstring> +#include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/crc/internal/crc.h" #ifdef __SSE4_2__ #include <immintrin.h> @@ -55,26 +59,44 @@ #endif +// We try to force AVX instructions so that we can use them when AVX is +// available at runtime even if the translation unit isn't built with AVX +// support. Clang on Windows has gnu::target but does not make AVX types like +// __m256i available when trying to force specific functions to use AVX +// compiles. +#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::target) && !defined(_MSC_VER) && \ + (defined(__x86_64__) || defined(__i386__)) +#define ABSL_INTERNAL_CAN_FORCE_AVX 1 +#endif + +#if defined(ABSL_INTERNAL_CAN_FORCE_AVX) +#define ABSL_INTERNAL_ATTRIBUTE_AVX [[gnu::target("avx")]] +#else +#define ABSL_INTERNAL_ATTRIBUTE_AVX +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { -#if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \ - defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) - #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) using V128 = uint64x2_t; -#else +#elif defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) // Note: Do not use __m128i_u, it is not portable. // Use V128_LoadU() perform an unaligned load from __m128i*. using V128 = __m128i; +#else +using V128 = std::array<uint64_t, 2>; #endif -#if defined(__AVX__) +#if (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \ + defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) using V256 = __m256i; #else // Placeholder for V256 when AVX is not available. -using V256 = std::array<uint64_t, 4>; +struct alignas(32) V256 { + std::array<uint64_t, 4> val; +}; #endif // Starting with the initial value in |crc|, accumulates a CRC32 value for @@ -137,19 +159,47 @@ int64_t V128_Low64(const V128 l); // Add packed 64-bit integers in |l| and |r|. V128 V128_Add64(const V128 l, const V128 r); -#if defined(__AVX__) -inline V256 V256_LoadU(const V256* src); -inline V256 V256_Broadcast128(const V128* src); +// Performs a store fence on architectures that require it (x86) after +// non-temporal stores. +// +// Debug builds track that this function is called after all tracked +// non-temporal store functions, via the weak hooks +// DebugReportNonTemporalStore() and DebugReportStoreFence() in crc.h. +void NonTemporalStoreFence(); + +#if (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \ + defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) +ABSL_INTERNAL_ATTRIBUTE_AVX inline V256 V256_LoadU(const void* src); +ABSL_INTERNAL_ATTRIBUTE_AVX inline V256 V256_Broadcast128(const V128* src); +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StoreU(void* dst, V256 data); +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StoreNonTemporal(void* dst, + V256 data); #else template <typename T = V256> -T V256_LoadU(const T* src); +T V256_LoadU(const void* src); template <typename T = V256> T V256_Broadcast128(const V128* src); -#endif +template <typename T = V256> +void V256_StoreU(void* dst, const T& data); + +template <typename T = V256> +void V256_StoreNonTemporal(void* dst, const T& data); #endif +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_LoadPairU(const void* src, + V256* v0, V256* v1); +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StorePairU(void* dst, V256 v0, + V256 v1); +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StorePairNonTemporal(void* dst, + V256 v0, + V256 v1); +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_CopyPairU(void* dst, + const void* src); +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_CopyPairNonTemporal( + void* dst, const void* src); + #if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { @@ -216,7 +266,6 @@ inline int64_t V128_Low64(const V128 l) { return _mm_cvtsi128_si64(l); } inline V128 V128_Add64(const V128 l, const V128 r) { return _mm_add_epi64(l, r); } - #elif defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { return __crc32cb(crc, v); } @@ -303,12 +352,11 @@ inline V128 V128_Xor3(const V128 a, const V128 b, const V128 c) { return V128_Xor(V128_Xor(a, b), c); } -inline V128 V128_From64WithZeroFill(const uint64_t r){ +inline V128 V128_From64WithZeroFill(const uint64_t r) { constexpr uint64x2_t kZero = {0, 0}; return vsetq_lane_u64(r, kZero, 0); } - template <int imm> inline int V128_Extract32(const V128 l) { return vgetq_lane_s32(vreinterpretq_s32_u64(l), imm); @@ -324,22 +372,43 @@ inline int64_t V128_Low64(const V128 l) { } inline V128 V128_Add64(const V128 l, const V128 r) { return vaddq_u64(l, r); } +#endif // ABSL_CRC_INTERNAL_HAVE_X86_SIMD || ABSL_CRC_INTERNAL_HAVE_ARM_SIMD +inline void NonTemporalStoreFence() { +#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) + _mm_sfence(); #endif + // Despite other architectures not needing an actual fence instruction, we + // note the fence in debug builds for consistency with x86. + DebugReportStoreFence(); +} -#if defined(__AVX__) && defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) -inline V256 V256_LoadU(const V256* src) { return _mm256_loadu_si256(src); } +#if (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \ + defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) +ABSL_INTERNAL_ATTRIBUTE_AVX inline V256 V256_LoadU(const void* src) { + return _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src)); +} -inline V256 V256_Broadcast128(const V128* src) { +ABSL_INTERNAL_ATTRIBUTE_AVX inline V256 V256_Broadcast128(const V128* src) { return _mm256_castps_si256( _mm256_broadcast_ps(reinterpret_cast<const __m128*>(src))); } -#elif defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) || \ - defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StoreU(void* dst, V256 data) { + _mm256_storeu_si256(reinterpret_cast<__m256i*>(dst), data); +} + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StoreNonTemporal(void* dst, + V256 data) { + _mm256_stream_si256(reinterpret_cast<__m256i*>(dst), data); + DebugReportNonTemporalStore(); +} +#else template <typename T> -inline T V256_LoadU(const T* src) { - (void)src; - return T{}; +inline T V256_LoadU(const void* src) { + T res; + std::memcpy(&res, src, sizeof(T)); + return res; } template <typename T> @@ -347,7 +416,58 @@ inline T V256_Broadcast128(const V128* src) { (void)src; return T{}; } -#endif + +template <typename T> +inline void V256_StoreU(void* dst, const T& data) { + std::memcpy(dst, &data, sizeof(T)); +} + +template <typename T> +inline void V256_StoreNonTemporal(void* dst, const T& data) { + // This architecture has no streaming store, so the data goes through the + // cache and is already strongly ordered. It is still counted, so that the + // StoreFence() contract is checked identically on every architecture. + std::memcpy(dst, &data, sizeof(T)); + DebugReportNonTemporalStore(); +} +#endif // (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && + // defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_LoadPairU(const void* src, + V256* v0, V256* v1) { + const char* src_ptr = reinterpret_cast<const char*>(src); + *v0 = V256_LoadU(src_ptr); + *v1 = V256_LoadU(src_ptr + sizeof(V256)); +} + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StorePairU(void* dst, V256 v0, + V256 v1) { + char* dst_ptr = reinterpret_cast<char*>(dst); + V256_StoreU(dst_ptr, v0); + V256_StoreU(dst_ptr + sizeof(V256), v1); +} + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_StorePairNonTemporal(void* dst, + V256 v0, + V256 v1) { + char* dst_ptr = reinterpret_cast<char*>(dst); + V256_StoreNonTemporal(dst_ptr, v0); + V256_StoreNonTemporal(dst_ptr + sizeof(V256), v1); +} + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_CopyPairU(void* dst, + const void* src) { + V256 v0, v1; + V256_LoadPairU(src, &v0, &v1); + V256_StorePairU(dst, v0, v1); +} + +ABSL_INTERNAL_ATTRIBUTE_AVX inline void V256_CopyPairNonTemporal( + void* dst, const void* src) { + V256 v0, v1; + V256_LoadPairU(src, &v0, &v1); + V256_StorePairNonTemporal(dst, v0, v1); +} } // namespace crc_internal ABSL_NAMESPACE_END diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy.h b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy.h index a0fed65afa2c..04eafced6905 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy.h +++ b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy.h @@ -16,10 +16,12 @@ #define ABSL_CRC_INTERNAL_CRC_MEMCPY_H_ #include <cstddef> +#include <cstdint> #include <memory> #include "absl/base/config.h" #include "absl/crc/crc32c.h" +#include "absl/crc/internal/crc.h" #include "absl/crc/internal/crc32_x86_arm_combined_simd.h" // Defined if the class AcceleratedCrcMemcpyEngine exists. @@ -52,9 +54,11 @@ class CrcMemcpy { std::size_t length, crc32c_t initial_crc = crc32c_t{0}, bool non_temporal = false) { - static const ArchSpecificEngines engines = GetArchSpecificEngines(); - auto* engine = non_temporal ? engines.non_temporal : engines.temporal; - return engine->Compute(dst, src, length, initial_crc); + uint32_t crc = static_cast<uint32_t>(initial_crc); + crc ^= 0xffffffffU; + CRC::Crc32c()->ExtendAndCopy(&crc, dst, src, length, non_temporal); + crc ^= 0xffffffffU; + return crc32c_t{crc}; } // For testing only: get an architecture-specific engine for tests. diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_test.cc b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_test.cc index 045a1e5e189b..021f5e513866 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_memcpy_test.cc @@ -14,6 +14,7 @@ #include "absl/crc/internal/crc_memcpy.h" +#include <array> #include <cstddef> #include <cstdint> #include <cstring> @@ -21,15 +22,49 @@ #include <memory> #include <string> #include <utility> +#include <vector> #include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/crc/crc32c.h" +#include "absl/crc/internal/crc.h" +#include "absl/crc/internal/crc32_x86_arm_combined_simd.h" #include "absl/memory/memory.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +static int64_t g_num_fences = 0; +static int64_t g_num_unfenced_stores = 0; + +#if !defined(NDEBUG) && ABSL_HAVE_ATTRIBUTE_WEAK +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace crc_internal { +// The following definitions are overrides for weak symbols in crc.h. +void DebugReportNonTemporalStore() { ++g_num_unfenced_stores; } +void DebugReportStoreFence() { + ++g_num_fences; + g_num_unfenced_stores = 0; +} +} // namespace crc_internal +ABSL_NAMESPACE_END +} // namespace absl +#endif // !defined(NDEBUG) && ABSL_HAVE_ATTRIBUTE_WEAK +// Check whether we can test non-temporal stores and store fences, which are +// only used when AVX is supported. These tests also rely on weak symbols, so we +// skip these tests when the weak attribute is not supported. Since these tests +// rely on bookkeeping that is disabled in optimized builds, we also skip them +// in that case. +#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && defined(__AVX__) && \ + ABSL_HAVE_ATTRIBUTE_WEAK && !defined(NDEBUG) +constexpr bool kCanTestNonTemporalStores = true; +#else +constexpr bool kCanTestNonTemporalStores = false; +#endif + namespace { enum CrcEngine { @@ -174,4 +209,153 @@ INSTANTIATE_TEST_SUITE_P(EngineParamTest, EngineParamTest, // Non Temporal TestParams{NONTEMPORAL, 0, 0})); +// AVX2 loads and stores need 32-byte alignment. +template <size_t N> +struct alignas(32) SimdTestBuffer : std::array<char, N> {}; + +template <size_t N> +SimdTestBuffer<N> MakeSimdTestBuffer(char first, char last) { + SimdTestBuffer<N> source = {}; + std::fill(source.begin(), source.end(), 0); + source[0] = first; + source[N - 1] = last; + return source; +} + +// Test that bookkeeping for non-temporal stores is correct. +TEST(CrcMemcpyNonTemporalFenceTest, V256_StoreNonTemporal) { + if (!kCanTestNonTemporalStores) { + GTEST_SKIP() << "Test does not support this build configuration."; + } + const auto source = MakeSimdTestBuffer<32>( + /*first=*/0x12, /*last=*/0x45); + auto destination = MakeSimdTestBuffer<32>( + /*first=*/0, /*last=*/0); + g_num_fences = 0; + g_num_unfenced_stores = 0; + absl::crc_internal::V256_StoreNonTemporal( + destination.data(), absl::crc_internal::V256_LoadU(source.data())); + EXPECT_EQ(g_num_fences, 0); + EXPECT_EQ(g_num_unfenced_stores, 1); + absl::crc_internal::NonTemporalStoreFence(); + EXPECT_EQ(g_num_fences, 1); + EXPECT_EQ(g_num_unfenced_stores, 0); + EXPECT_EQ(destination, source); +} + +TEST(CrcMemcpyNonTemporalFenceTest, V256_StorePairNonTemporal) { + if (!kCanTestNonTemporalStores) { + GTEST_SKIP() << "Test does not support this build configuration."; + } + const auto source = MakeSimdTestBuffer<64>( + /*first=*/0x12, /*last=*/0x45); + auto destination = MakeSimdTestBuffer<64>( + /*first=*/0, /*last=*/0); + g_num_fences = 0; + g_num_unfenced_stores = 0; + absl::crc_internal::V256_StorePairNonTemporal( + destination.data(), absl::crc_internal::V256_LoadU(source.data()), + absl::crc_internal::V256_LoadU(source.data() + 32)); + EXPECT_EQ(g_num_fences, 0); + EXPECT_EQ(g_num_unfenced_stores, 2); + absl::crc_internal::NonTemporalStoreFence(); + EXPECT_EQ(g_num_fences, 1); + EXPECT_EQ(g_num_unfenced_stores, 0); + EXPECT_EQ(destination, source); +} + +TEST(CrcMemcpyNonTemporalFenceTest, V256_CopyPairNonTemporal) { + if (!kCanTestNonTemporalStores) { + GTEST_SKIP() << "Test does not support this build configuration."; + } + const auto source = MakeSimdTestBuffer<64>( + /*first=*/0x12, /*last=*/0x45); + auto destination = MakeSimdTestBuffer<64>( + /*first=*/0, /*last=*/0); + g_num_fences = 0; + g_num_unfenced_stores = 0; + absl::crc_internal::V256_CopyPairNonTemporal(destination.data(), + source.data()); + EXPECT_EQ(g_num_fences, 0); + EXPECT_EQ(g_num_unfenced_stores, 2); + absl::crc_internal::NonTemporalStoreFence(); + EXPECT_EQ(g_num_fences, 1); + EXPECT_EQ(g_num_unfenced_stores, 0); + EXPECT_EQ(destination, source); +} + +TEST(CrcMemcpyNonTemporalFenceTest, V256_StoreU) { + if (!kCanTestNonTemporalStores) { + GTEST_SKIP() << "Test does not support this build configuration."; + } + const auto source = MakeSimdTestBuffer<32>( + /*first=*/0x12, /*last=*/0x45); + auto destination = MakeSimdTestBuffer<32>( + /*first=*/0, /*last=*/0); + g_num_fences = 0; + g_num_unfenced_stores = 0; + // Regular (temporal) stores should not change the counts. + absl::crc_internal::V256_StoreU( + destination.data(), absl::crc_internal::V256_LoadU(source.data())); + EXPECT_EQ(g_num_fences, 0); + EXPECT_EQ(g_num_unfenced_stores, 0); + EXPECT_EQ(destination, source); +} + +TEST(CrcMemcpyNonTemporalFenceTest, NonTemporalStoreFence) { + if (!kCanTestNonTemporalStores) { + GTEST_SKIP() << "Test does not support this build configuration."; + } + g_num_unfenced_stores = 1; + g_num_fences = 0; + absl::crc_internal::NonTemporalStoreFence(); + EXPECT_EQ(g_num_fences, 1); + EXPECT_EQ(g_num_unfenced_stores, 0); +} + +// Non-temporal stores are weakly ordered, so Crc32CAndCopy() has to fence them +// before it returns, or the copy is not guaranteed to be visible to the thread +// that reads it next. This checks that it always does, across the sizes and +// alignments that select between the implementation's code paths. +// +// Only the accelerated implementation issues non-temporal stores, and only for +// copies large enough to reach its PCLMUL path, so a fence is not expected +// after every call; what is checked is that no call ever leaves a non-temporal +// store unfenced. +TEST(CrcMemcpyNonTemporalFenceTest, Crc32CAndCopyMemoryFence) { + if (!kCanTestNonTemporalStores) { + GTEST_SKIP() << "Test does not support this build configuration."; + } + // Enough room for the largest copy below, plus the largest alignment + // offset. + constexpr size_t kMaxCopySize = size_t{1} << 16; + constexpr size_t kMaxAlignment = 64; + const std::vector<char> source(kMaxCopySize + kMaxAlignment, 0x45); + auto destination = std::make_unique<char[]>(kMaxCopySize + kMaxAlignment); + + // Sizes straddling the cutoffs between the memcpy-based path and the PCLMUL + // path, which is the one that stores non-temporally. + constexpr size_t kSizes[] = {0, 1, 63, 64, 255, 256, + 1024, 2047, 2048, 4096, kMaxCopySize}; + // Offsets that leave the destination variously cache-line aligned and + // misaligned, since the implementation peels a differently sized head off + // the copy depending on the alignment. + constexpr size_t kOffsets[] = {0, 1, 8, 63}; + + g_num_unfenced_stores = 0; + for (size_t size : kSizes) { + for (size_t destination_offset : kOffsets) { + for (size_t source_offset : kOffsets) { + absl::crc_internal::Crc32CAndCopy( + destination.get() + destination_offset, + source.data() + source_offset, size, absl::crc32c_t{0}, + /*non_temporal=*/true); + EXPECT_EQ(g_num_unfenced_stores, 0) + << "Crc32CAndCopy() returned with non-temporal stores that were " + "never fenced, so the copy may not be visible to other " + "threads."; + } + } + } +} } // namespace diff --git a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc index edffd36717d4..98f532ba8dad 100644 --- a/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc +++ b/deps/v8/third_party/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc @@ -16,7 +16,9 @@ #include <cstddef> #include <cstdint> +#include <cstring> #include <memory> +#include <type_traits> #include <vector> #include "absl/base/attributes.h" @@ -200,7 +202,7 @@ void CRC32AcceleratedX86ARMCombined::ExtendByZeroes(uint32_t* crc, // Instruction" // https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/crc-iscsi-polynomial-crc32-instruction-paper.pdf // We only need every 4th value, because we unroll loop by 4. -constexpr uint64_t kClmulConstants[] = { +alignas(16) constexpr uint64_t kClmulConstants[] = { 0x09e4addf8, 0x0ba4fc28e, 0x00d3b6092, 0x09e4addf8, 0x0ab7aff2a, 0x102f9b8a2, 0x0b9e02b86, 0x00d3b6092, 0x1bf2e8b8a, 0x18266e456, 0x0d270f1a2, 0x0ab7aff2a, 0x11eef4f8e, 0x083348832, 0x0dd7e3b0c, @@ -217,61 +219,84 @@ constexpr uint64_t kClmulConstants[] = { }; enum class PclmulStreamType { + NONE, PCLMUL, VPCLMUL, NEON_PCLMUL, NEON_PCLMUL_EOR3, }; +// Selects the kind of stores used to write the destination buffer when the CRC +// is computed while copying. +enum class CopyType { + // Don't copy at all, just compute the CRC of the input. + kNone, + // Copy with regular stores, leaving the destination in the cache. + kTemporal, + // Copy with non-temporal stores, which bypass some levels of cache. + kNonTemporal, +}; + // Base class for CRC32AcceleratedX86ARMCombinedMultipleStreams containing the // methods and data that don't need the template arguments. class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase : public CRC32AcceleratedX86ARMCombined { protected: - // Update partialCRC with crc of 64 byte block. Calling FinalizePclmulStream - // would produce a single crc checksum, but it is expensive. PCLMULQDQ has a - // high latency, so we run 4 128-bit partial checksums that can be reduced to - // a single value by FinalizePclmulStream later. Computing crc for arbitrary - // polynomialas with PCLMULQDQ is described in Intel paper "Fast CRC - // Computation for Generic Polynomials Using PCLMULQDQ Instruction" + // Copies 64 bytes from `src` to `dst`, using the kind of stores selected by + // `copy_type`. Does nothing if `copy_type` is NONE. + template <CopyType copy_type> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE static void + Copy64Bytes(uint8_t* dst, const uint8_t* src) { + if constexpr (copy_type == CopyType::kNonTemporal) { + V256_CopyPairNonTemporal(dst, src); + } else if constexpr (copy_type == CopyType::kTemporal) { + V256_CopyPairU(dst, src); + } else { + static_assert(copy_type == CopyType::kNone); + } + } + + // Stores the 64 bytes held in `v0` and `v1` to `dst`, using the kind of + // stores selected by `copy_type`. Does nothing if `copy_type` is NONE. + template <CopyType copy_type> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE static void + Store64Bytes(uint8_t* dst, V256 v0, V256 v1) { + if constexpr (copy_type == CopyType::kNonTemporal) { + V256_StorePairNonTemporal(dst, v0, v1); + } else if constexpr (copy_type == CopyType::kTemporal) { + V256_StorePairU(dst, v0, v1); + } else { + static_assert(copy_type == CopyType::kNone); + } + } + + // Update a single 128-bit element of partialCRC with crc of 16 byte block. + // Calling FinalizePclmulStream would produce a single crc checksum, but it is + // expensive. PCLMULQDQ has a high latency, so we run 4 128-bit partial + // checksums that can be reduced to a single value by FinalizePclmulStream + // later. Computing crc for arbitrary polynomials with PCLMULQDQ is described + // in Intel paper "Fast CRC Computation for Generic Polynomials Using + // PCLMULQDQ Instruction" // https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf // We are applying it to CRC32C polynomial. -#if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) - template <bool kUseEor3 = false> - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesNeonPclmul( - const uint8_t* p, V128* partialCRC) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE V128 Pclmul16Bytes(V128* partialCRC) const { V128 loopMultiplicands = V128_Load(reinterpret_cast<const V128*>(kFoldAcross512Bits)); + V128 tmp = V128_PMulHi(*partialCRC, loopMultiplicands); + *partialCRC = V128_PMulLow(*partialCRC, loopMultiplicands); + return tmp; + } - V128 partialCRC1 = partialCRC[0]; - V128 partialCRC2 = partialCRC[1]; - V128 partialCRC3 = partialCRC[2]; - V128 partialCRC4 = partialCRC[3]; - - V128 tmp1 = V128_PMulHi(partialCRC1, loopMultiplicands); - V128 tmp2 = V128_PMulHi(partialCRC2, loopMultiplicands); - V128 tmp3 = V128_PMulHi(partialCRC3, loopMultiplicands); - V128 tmp4 = V128_PMulHi(partialCRC4, loopMultiplicands); - V128 data1 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 0)); - V128 data2 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 1)); - V128 data3 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 2)); - V128 data4 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 3)); - partialCRC1 = V128_PMulLow(partialCRC1, loopMultiplicands); - partialCRC2 = V128_PMulLow(partialCRC2, loopMultiplicands); - partialCRC3 = V128_PMulLow(partialCRC3, loopMultiplicands); - partialCRC4 = V128_PMulLow(partialCRC4, loopMultiplicands); - partialCRC1 = V128_Xor3<kUseEor3>(tmp1, partialCRC1, data1); - partialCRC2 = V128_Xor3<kUseEor3>(tmp2, partialCRC2, data2); - partialCRC3 = V128_Xor3<kUseEor3>(tmp3, partialCRC3, data3); - partialCRC4 = V128_Xor3<kUseEor3>(tmp4, partialCRC4, data4); - partialCRC[0] = partialCRC1; - partialCRC[1] = partialCRC2; - partialCRC[2] = partialCRC3; - partialCRC[3] = partialCRC4; +#if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) + template <bool kUseEor3 = false> + ABSL_ATTRIBUTE_ALWAYS_INLINE void Xor16BytesNeonPclmul( + V128 data, V128 tmp, V128* partialCRC) const { + *partialCRC = V128_Xor3<kUseEor3>(tmp, *partialCRC, data); } - // Reduce partialCRC produced by Process64BytesNeonPclmul into a single value, - // that represents crc checksum of all the processed bytes. + // Reduce partialCRC produced by Pclmul16Bytes and Xor16BytesNeonPclmul + // into a single value, that represents crc checksum of all the processed + // bytes. template <bool kUseEor3 = false> ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizeNeonPclmulStream(V128* partialCRC) const { @@ -308,51 +333,19 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase return crc; } - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul(const uint8_t*, - V128*) const {} + ABSL_ATTRIBUTE_ALWAYS_INLINE void Xor16BytesPclmul(V128, V128, V128*) const {} ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizePclmulStream(V128*) const { return 0; } #else - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul( - const uint8_t* p, V128* partialCRC) const { - V128 loopMultiplicands = - V128_Load(reinterpret_cast<const V128*>(kFoldAcross512Bits)); - - V128 partialCRC1 = partialCRC[0]; - V128 partialCRC2 = partialCRC[1]; - V128 partialCRC3 = partialCRC[2]; - V128 partialCRC4 = partialCRC[3]; - - V128 tmp1 = V128_PMulHi(partialCRC1, loopMultiplicands); - V128 tmp2 = V128_PMulHi(partialCRC2, loopMultiplicands); - V128 tmp3 = V128_PMulHi(partialCRC3, loopMultiplicands); - V128 tmp4 = V128_PMulHi(partialCRC4, loopMultiplicands); - V128 data1 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 0)); - V128 data2 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 1)); - V128 data3 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 2)); - V128 data4 = V128_LoadU(reinterpret_cast<const V128*>(p + 16 * 3)); - partialCRC1 = V128_PMulLow(partialCRC1, loopMultiplicands); - partialCRC2 = V128_PMulLow(partialCRC2, loopMultiplicands); - partialCRC3 = V128_PMulLow(partialCRC3, loopMultiplicands); - partialCRC4 = V128_PMulLow(partialCRC4, loopMultiplicands); - partialCRC1 = V128_Xor(tmp1, partialCRC1); - partialCRC2 = V128_Xor(tmp2, partialCRC2); - partialCRC3 = V128_Xor(tmp3, partialCRC3); - partialCRC4 = V128_Xor(tmp4, partialCRC4); - partialCRC1 = V128_Xor(partialCRC1, data1); - partialCRC2 = V128_Xor(partialCRC2, data2); - partialCRC3 = V128_Xor(partialCRC3, data3); - partialCRC4 = V128_Xor(partialCRC4, data4); - partialCRC[0] = partialCRC1; - partialCRC[1] = partialCRC2; - partialCRC[2] = partialCRC3; - partialCRC[3] = partialCRC4; + ABSL_ATTRIBUTE_ALWAYS_INLINE void Xor16BytesPclmul(V128 data, V128 tmp, + V128* partialCRC) const { + *partialCRC = V128_Xor(V128_Xor(tmp, *partialCRC), data); } - // Reduce partialCRC produced by Process64BytesPclmul into a single value, - // that represents crc checksum of all the processed bytes. + // Reduce partialCRC produced by Pclmul16Bytes and Xor16BytesPclmul into a + // single value, that represents crc checksum of all the processed bytes. ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizePclmulStream(V128* partialCRC) const { V128 partialCRC1 = partialCRC[0]; @@ -392,67 +385,33 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase } template <bool kUseEor3 = false> - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesNeonPclmul(const uint8_t*, - V128*) const {} + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void + Xor16BytesNeonPclmul(V128, V128, V128*) const {} template <bool kUseEor3 = false> - ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizeNeonPclmulStream(V128*) const { + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t + FinalizeNeonPclmulStream(V128*) const { return 0; } #endif - // Update crc with 64 bytes of data from p. - ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t Process64BytesCRC(const uint8_t* p, - uint64_t crc) const { - for (int i = 0; i < 8; i++) { - crc = - CRC32_u64(static_cast<uint32_t>(crc), absl::little_endian::Load64(p)); - p += 8; - } - return crc; - } - - // Same as Process64BytesCRC, but just interleaved for 2 streams. - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesCRC2Streams( - const uint8_t* p0, const uint8_t* p1, uint64_t* crc) const { - uint64_t crc0 = crc[0]; - uint64_t crc1 = crc[1]; - for (int i = 0; i < 8; i++) { - crc0 = CRC32_u64(static_cast<uint32_t>(crc0), - absl::little_endian::Load64(p0)); - crc1 = CRC32_u64(static_cast<uint32_t>(crc1), - absl::little_endian::Load64(p1)); - p0 += 8; - p1 += 8; - } - crc[0] = crc0; - crc[1] = crc1; + // Update crc with 8 bytes of data from p. + ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t Process8BytesCRC(const uint8_t* p, + uint64_t crc) const { + return CRC32_u64(static_cast<uint32_t>(crc), + absl::little_endian::Load64(p)); } - // Same as Process64BytesCRC, but just interleaved for 3 streams. - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesCRC3Streams( - const uint8_t* p0, const uint8_t* p1, const uint8_t* p2, - uint64_t* crc) const { - uint64_t crc0 = crc[0]; - uint64_t crc1 = crc[1]; - uint64_t crc2 = crc[2]; - for (int i = 0; i < 8; i++) { - crc0 = CRC32_u64(static_cast<uint32_t>(crc0), - absl::little_endian::Load64(p0)); - crc1 = CRC32_u64(static_cast<uint32_t>(crc1), - absl::little_endian::Load64(p1)); - crc2 = CRC32_u64(static_cast<uint32_t>(crc2), - absl::little_endian::Load64(p2)); - p0 += 8; - p1 += 8; - p2 += 8; - } - crc[0] = crc0; - crc[1] = crc1; - crc[2] = crc2; + // Update crc with 16 bytes of data from p. + ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t Process16BytesCRC(const uint8_t* p, + uint64_t crc) const { + crc = Process8BytesCRC(p, crc); + crc = Process8BytesCRC(p + 8, crc); + return crc; } -#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && defined(__AVX__) && \ +#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && \ + (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \ (!defined(_MSC_VER) || defined(__clang__)) // This is only used if we have vector version of PCLMULQDQ. // We don't have it on arm, and it isn't supported by default @@ -461,7 +420,7 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase // with new and default flags or use inline asm. // The code below is the same as FinalizePclmulStream, but with // PCLMUL and XOR operating on 2 values in a vector at the same time. - ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizeVpclmulStream(V256* partialCRC) const { uint64_t crc = 0; uint64_t low64, high64; @@ -492,32 +451,45 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase return crc; } - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesVpclmul( - const uint8_t* p, V256* vpartialCRC, V256 loopMultiplicands) const { + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE V256 + Pclmul32BytesVpclmul(V256* partialCRC) const { + V256 loopMultiplicands = + V256_Broadcast128(reinterpret_cast<const V128*>(kFoldAcross512Bits)); + V256 tmp; + __asm__ volatile( + "vpclmulqdq $0x11, %2, %0, %1 \n" + "vpclmulqdq $0x00, %2, %0, %0 \n" + : "+x"(*partialCRC), "=&x"(tmp) + : "x"(loopMultiplicands)); + return tmp; + } + + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void + Xor32BytesVpclmul(const uint8_t* p, V256 tmp, V256* partialCRC) const { + V256 v = V256_LoadU(p); __asm__ volatile( - "vpclmulqdq $0x11, %3, %0, %%ymm0 \n" - "vpclmulqdq $0x11, %3, %1, %%ymm1 \n" - "vpclmulqdq $0x00, %3, %0, %0 \n" - "vpclmulqdq $0x00, %3, %1, %1 \n" - "vpxor %%ymm0, %0, %0 \n" - "vpxor %%ymm1, %1, %1 \n" - "vpxor (%2), %0, %0 \n" - "vpxor 32(%2), %1, %1 \n" - : "+x"(vpartialCRC[0]), "+x"(vpartialCRC[1]) - : "r"(p), "x"(loopMultiplicands) - : "ymm0", "ymm1"); + "vpxor %2, %0, %0 \n" + "vpxor %1, %0, %0 \n" + : "+x"(*partialCRC) + : "x"(v), "x"(tmp)); } #else template <typename T = V256> - ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesVpclmul(const uint8_t*, T*, - T) const { + ABSL_ATTRIBUTE_ALWAYS_INLINE T Pclmul32BytesVpclmul(T*) const { + static_assert(sizeof(T) == 0, "Vector PCLMUL not supported"); + return T{}; + } + template <typename T = V256> + ABSL_ATTRIBUTE_ALWAYS_INLINE void Xor32BytesVpclmul(const uint8_t*, T, + T*) const { static_assert(sizeof(T) == 0, "Vector PCLMUL not supported"); } ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizeVpclmulStream(V256*) const { return 0; } -#endif // defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && defined(__AVX__) && - // (!defined(_MSC_VER) || defined(__clang__)) +#endif // defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && (defined(__AVX__) || + // defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && (!defined(_MSC_VER) || + // defined(__clang__)) // Constants generated by './scripts/gen-crc-consts.py x86_pclmul // crc32_lsb_0x82f63b78' from the Linux kernel. @@ -545,205 +517,345 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase // instruction, and up to kMaxStreams blocks computed with PCLMULQDQ, which // are combined in the end. static constexpr size_t kMaxStreams = 3; + // When copying, at most kMaxCopyStreams streams are used in total. + static constexpr size_t kMaxCopyStreams = 3; }; template <size_t num_crc_streams, size_t num_pclmul_streams, PclmulStreamType pclmul_stream_type> class CRC32AcceleratedX86ARMCombinedMultipleStreams : public CRC32AcceleratedX86ARMCombinedMultipleStreamsBase { - ABSL_ATTRIBUTE_HOT + public: void Extend(uint32_t* crc, const void* bytes, const size_t length) const override { + Extend<CopyType::kNone>(crc, bytes, length); + } + + void ExtendAndCopy(uint32_t* crc, void* __restrict dst, + const void* __restrict src, size_t length, + bool non_temporal) const override { + if (non_temporal) { + Extend<CopyType::kNonTemporal>(crc, src, length, dst); + } else { + Extend<CopyType::kTemporal>(crc, src, length, dst); + } + } + + template <CopyType copy_type> + ABSL_ATTRIBUTE_HOT void Extend(uint32_t* crc, const void* bytes, + const size_t length, + void* __restrict dst = nullptr) const { + if constexpr (pclmul_stream_type != PclmulStreamType::NONE) { + if (length >= kMediumCutoff) { + ExtendWithPclmul<copy_type>(crc, bytes, length, dst); + return; + } + } + ExtendWithoutPclmul<copy_type != CopyType::kNone>(crc, bytes, length, dst); + } + + template <bool copy> + ABSL_ATTRIBUTE_HOT void ExtendWithoutPclmul( + uint32_t* crc, const void* bytes, const size_t length, + void* __restrict dst = nullptr) const { static_assert(num_crc_streams >= 1 && num_crc_streams <= kMaxStreams, "Invalid number of crc streams"); static_assert(num_pclmul_streams >= 0 && num_pclmul_streams <= kMaxStreams, "Invalid number of pclmul streams"); const uint8_t* p = static_cast<const uint8_t*>(bytes); const uint8_t* e = p + length; + char* d = static_cast<char*>(dst); uint32_t l = *crc; uint64_t l64; + if constexpr (copy) { + std::memcpy(d, p, length); + } // For small blocks just run simple loop, because cost of combining multiple // streams is significant. - if (num_crc_streams > 1 && (length < kSmallCutoff)) { + if (num_crc_streams == 1 || (length < kSmallCutoff)) { // fallthrough; Use the same strategy as we do for processing the // remaining bytes after any other strategy. - } else if (length < kMediumCutoff) { - // For medium blocks we run 3 crc streams and combine them as described in - // Intel paper above. Running 4th stream doesn't help, because crc - // instruction has latency 3 and throughput 1. + } else { l64 = l; - if (num_crc_streams > 1) { - uint64_t l641 = 0; - uint64_t l642 = 0; - const size_t blockSize = 32; - size_t bs = static_cast<size_t>(e - p) / kGroupsSmall / blockSize; - const uint8_t* p1 = p + bs * blockSize; - const uint8_t* p2 = p1 + bs * blockSize; - - for (size_t i = 0; i + 1 < bs; ++i) { - ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); - ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); - ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); - ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); - PrefetchToLocalCache( - reinterpret_cast<const char*>(p + kPrefetchHorizonMedium)); - PrefetchToLocalCache( - reinterpret_cast<const char*>(p1 + kPrefetchHorizonMedium)); - PrefetchToLocalCache( - reinterpret_cast<const char*>(p2 + kPrefetchHorizonMedium)); - } - // Don't run crc on last 8 bytes. + const size_t blockSize = 32; + size_t bs = static_cast<size_t>(e - p) / kGroupsSmall / blockSize; + uint64_t l641 = 0; + uint64_t l642 = 0; + const uint8_t* p1 = p + bs * blockSize; + const uint8_t* p2 = p1 + bs * blockSize; + + for (size_t i = 0; i + 1 < bs; ++i) { + ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); - ABSL_INTERNAL_STEP8BY2(l64, l641, p, p1); + PrefetchToLocalCache( + reinterpret_cast<const char*>(p + kPrefetchHorizonMedium)); + PrefetchToLocalCache( + reinterpret_cast<const char*>(p1 + kPrefetchHorizonMedium)); + PrefetchToLocalCache( + reinterpret_cast<const char*>(p2 + kPrefetchHorizonMedium)); + } + // Don't run crc on last 8 bytes. + ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); + ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); + ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); + ABSL_INTERNAL_STEP8BY2(l64, l641, p, p1); + + // kClmulConstants stores precomputed constants for up to 32 blocks + // (bs <= 32). + constexpr size_t kMaxPrecomputedBlocks = std::size(kClmulConstants) / 2; + V128 magic; + if (bs <= kMaxPrecomputedBlocks) { + magic = + V128_Load(reinterpret_cast<const V128*>(kClmulConstants) + bs - 1); + } else { + uint32_t high = ComputeZeroConstant(32 * bs); + uint32_t low = MultiplyWithExtraX33(high, high); + alignas(16) uint64_t dynamic_magic[2] = {low, high}; + magic = V128_Load(reinterpret_cast<const V128*>(dynamic_magic)); + } - V128 magic = *(reinterpret_cast<const V128*>(kClmulConstants) + bs - 1); + V128 tmp = V128_From64WithZeroFill(l64); - V128 tmp = V128_From64WithZeroFill(l64); + V128 res1 = V128_PMulLow(tmp, magic); - V128 res1 = V128_PMulLow(tmp, magic); + tmp = V128_From64WithZeroFill(l641); - tmp = V128_From64WithZeroFill(l641); + V128 res2 = V128_PMul10(tmp, magic); + V128 x = V128_Xor(res1, res2); + l64 = static_cast<uint64_t>(V128_Low64(x)) ^ + absl::little_endian::Load64(p2); + l64 = CRC32_u64(static_cast<uint32_t>(l642), l64); - V128 res2 = V128_PMul10(tmp, magic); - V128 x = V128_Xor(res1, res2); - l64 = static_cast<uint64_t>(V128_Low64(x)) ^ - absl::little_endian::Load64(p2); - l64 = CRC32_u64(static_cast<uint32_t>(l642), l64); + p = p2 + 8; + l = static_cast<uint32_t>(l64); + } - p = p2 + 8; - } else { - while ((e - p) >= 64) { - l64 = Process64BytesCRC(p, l64); - p += 64; - } + uint64_t remaining_bytes = static_cast<uint64_t>(e - p); + // Process the remaining bytes. + while ((e - p) >= 16) { + ABSL_INTERNAL_STEP8(l, p); + ABSL_INTERNAL_STEP8(l, p); + } + + if (remaining_bytes & 8) { + ABSL_INTERNAL_STEP8(l, p); + } + if (remaining_bytes & 4) { + ABSL_INTERNAL_STEP4(l, p); + } + if (remaining_bytes & 2) { + ABSL_INTERNAL_STEP2(l, p); + } + if (remaining_bytes & 1) { + ABSL_INTERNAL_STEP1(l, p); + } + + *crc = l; + } + + template <CopyType copy_type> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_HOT void ExtendWithPclmul( + uint32_t* crc, const void* bytes, const size_t length, + void* __restrict dst = nullptr) const { + static_assert(num_crc_streams >= 1 && num_crc_streams <= kMaxStreams, + "Invalid number of crc streams"); + static_assert(num_pclmul_streams >= 0 && num_pclmul_streams <= kMaxStreams, + "Invalid number of pclmul streams"); + constexpr StreamCounts kStreams = GetStreamCounts(copy_type); + constexpr size_t kNumActiveCrcStreams = kStreams.crc; + constexpr size_t kNumActivePclmulStreams = kStreams.pclmul; + const uint8_t* p = static_cast<const uint8_t*>(bytes); + const uint8_t* e = p + length; + char* d = static_cast<char*>(dst); + uint32_t l = *crc; + uint64_t l64; + + if constexpr (copy_type != CopyType::kNone) { + // Align the destination pointer to a cache line. Non-temporal stores + // require the destination to be aligned to the store size, and aligning + // regular stores avoids writes that straddle two cache lines. + constexpr size_t kAlignment = 64; + uintptr_t dst_addr = reinterpret_cast<uintptr_t>(d); + size_t bytes_to_align = + (kAlignment - (dst_addr & (kAlignment - 1))) & (kAlignment - 1); + std::memcpy(d, p, bytes_to_align); + d += bytes_to_align; + while (bytes_to_align >= 8) { + ABSL_INTERNAL_STEP8(l, p); + bytes_to_align -= 8; + } + while (bytes_to_align > 0) { + ABSL_INTERNAL_STEP1(l, p); + bytes_to_align -= 1; } - l = static_cast<uint32_t>(l64); } else { - // There is a lot of data, we can ignore combine costs and run all - // requested streams (num_crc_streams + num_pclmul_streams), - // using prefetch. CRC and PCLMULQDQ use different cpu execution units, - // so on some cpus it makes sense to execute both of them for different - // streams. - // Point x at first 8-byte aligned byte in string. const uint8_t* x = RoundUp<8>(p); // Process bytes until p is 8-byte aligned, if that isn't past the end. while (p != x) { ABSL_INTERNAL_STEP1(l, p); } + } + + size_t bs = static_cast<size_t>(e - p) / + (kNumActiveCrcStreams + kNumActivePclmulStreams) / 64; + + const uint8_t* stream_start = p; + const uint8_t* crc_streams[kMaxStreams]; + for (size_t i = 0; i < kNumActiveCrcStreams; i++) { + crc_streams[i] = stream_start; + stream_start += bs * 64; + } + const uint8_t* pclmul_streams[kMaxStreams]; + for (size_t i = 0; i < kNumActivePclmulStreams; i++) { + pclmul_streams[i] = stream_start; + stream_start += bs * 64; + } - size_t bs = static_cast<size_t>(e - p) / - (num_crc_streams + num_pclmul_streams) / 64; - const uint8_t* stream_start = p; - const uint8_t* crc_streams[kMaxStreams]; - for (size_t i = 0; i < num_crc_streams; i++) { - crc_streams[i] = stream_start; - stream_start += bs * 64; + uint8_t* dst_crc_streams[kMaxStreams]; + uint8_t* dst_pclmul_streams[kMaxStreams]; + if constexpr (copy_type != CopyType::kNone) { + uint8_t* dst_stream_start = reinterpret_cast<uint8_t*>(d); + for (size_t i = 0; i < kNumActiveCrcStreams; i++) { + dst_crc_streams[i] = dst_stream_start; + dst_stream_start += bs * 64; } - const uint8_t* pclmul_streams[kMaxStreams]; - for (size_t i = 0; i < num_pclmul_streams; i++) { - pclmul_streams[i] = stream_start; - stream_start += bs * 64; + for (size_t i = 0; i < kNumActivePclmulStreams; i++) { + dst_pclmul_streams[i] = dst_stream_start; + dst_stream_start += bs * 64; } + } - // Per stream crc sums. - uint64_t l64_crc[kMaxStreams] = {l}; - uint64_t l64_pclmul[kMaxStreams] = {0}; - - // Peel first iteration, because PCLMULQDQ stream, needs setup. - if (num_crc_streams == 1) { - l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]); - crc_streams[0] += 16 * 4; - } else if (num_crc_streams == 2) { - Process64BytesCRC2Streams(crc_streams[0], crc_streams[1], l64_crc); - crc_streams[0] += 16 * 4; - crc_streams[1] += 16 * 4; - } else { - Process64BytesCRC3Streams(crc_streams[0], crc_streams[1], - crc_streams[2], l64_crc); - crc_streams[0] += 16 * 4; - crc_streams[1] += 16 * 4; - crc_streams[2] += 16 * 4; + // Per stream crc sums. + uint64_t l64_crc[kMaxStreams] = {l}; + uint64_t l64_pclmul[kMaxStreams] = {0}; + + V256 pclmul_v[kMaxStreams][2]; + for (size_t j = 0; j < kNumActivePclmulStreams; j++) { + V256_LoadPairU(pclmul_streams[j], &pclmul_v[j][0], &pclmul_v[j][1]); + } + + if constexpr (copy_type != CopyType::kNone) { + for (size_t j = 0; j < kNumActiveCrcStreams; j++) { + Copy64Bytes<copy_type>(dst_crc_streams[j], crc_streams[j]); + dst_crc_streams[j] += 64; } + for (size_t j = 0; j < kNumActivePclmulStreams; j++) { + Store64Bytes<copy_type>(dst_pclmul_streams[j], pclmul_v[j][0], + pclmul_v[j][1]); + dst_pclmul_streams[j] += 64; + } + } - // Align to 32 bytes for vpclmul implementation. - alignas(32) V128 partialCRC[kMaxStreams][4]; - for (size_t i = 0; i < num_pclmul_streams; i++) { - InitPclmulStream(&pclmul_streams[i], partialCRC[i]); + for (size_t offset = 0; offset < 64; offset += 16) { + for (size_t j = 0; j < kNumActiveCrcStreams; j++) { + l64_crc[j] = Process16BytesCRC(crc_streams[j] + offset, l64_crc[j]); } + } + for (size_t j = 0; j < kNumActiveCrcStreams; j++) { + crc_streams[j] += 64; + } - for (size_t i = 1; i < bs; i++) { - // Prefetch data for next iterations. - for (size_t j = 0; j < num_crc_streams; j++) { - PrefetchToLocalCache( - reinterpret_cast<const char*>(crc_streams[j] + kPrefetchHorizon)); - } - for (size_t j = 0; j < num_pclmul_streams; j++) { - PrefetchToLocalCache(reinterpret_cast<const char*>(pclmul_streams[j] + - kPrefetchHorizon)); - } + // Align to 32 bytes for vpclmul implementation. + alignas(32) V128 partialCRC[kMaxStreams][4]; + for (size_t i = 0; i < kNumActivePclmulStreams; i++) { + InitPclmulStream(pclmul_v[i][0], pclmul_v[i][1], partialCRC[i]); + pclmul_streams[i] += 64; + } - // We process each stream in 64 byte blocks. This can be written as - // for (int i = 0; i < num_pclmul_streams; i++) { - // Process64BytesPclmul(pclmul_streams[i], partialCRC[i]); - // pclmul_streams[i] += 16 * 4; - // } - // for (int i = 0; i < num_crc_streams; i++) { - // l64_crc[i] = Process64BytesCRC(crc_streams[i], l64_crc[i]); - // crc_streams[i] += 16*4; - // } - // But unrolling and interleaving PCLMULQDQ and CRC blocks manually - // gives ~2% performance boost. - if (num_crc_streams == 1) { - l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]); - crc_streams[0] += 16 * 4; - } else if (num_crc_streams == 2) { - Process64BytesCRC2Streams(crc_streams[0], crc_streams[1], l64_crc); - crc_streams[0] += 16 * 4; - crc_streams[1] += 16 * 4; - } else { - Process64BytesCRC3Streams(crc_streams[0], crc_streams[1], - crc_streams[2], l64_crc); - crc_streams[0] += 16 * 4; - crc_streams[1] += 16 * 4; - crc_streams[2] += 16 * 4; - } - for (size_t j = 0; j < num_pclmul_streams; j++) { - ProcessPclmulStream(&pclmul_streams[j], partialCRC[j]); - } + for (size_t i = 1; i < bs; i++) { + // Prefetch data for next iterations. + for (size_t j = 0; j < kNumActiveCrcStreams; j++) { + PrefetchToLocalCache(crc_streams[j] + kPrefetchHorizon); } - - // PCLMULQDQ based streams require special final step; - // CRC based don't. - for (size_t i = 0; i < num_pclmul_streams; i++) { - l64_pclmul[i] = FinalizePclmulStream(partialCRC[i]); + for (size_t j = 0; j < kNumActivePclmulStreams; j++) { + PrefetchToLocalCache(pclmul_streams[j] + kPrefetchHorizon); } - // Combine all streams into single result. - static_assert(64 % (1 << kNumDroppedBits) == 0); - uint32_t magic = ComputeZeroConstant(bs * 64); - l64 = l64_crc[0]; - for (size_t i = 1; i < num_crc_streams; i++) { - l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); - l64 ^= l64_crc[i]; + const uint8_t* pclmul_copy[kMaxStreams]; + if constexpr (copy_type != CopyType::kNone) { + for (size_t j = 0; j < kNumActivePclmulStreams; j++) { + V256_LoadPairU(pclmul_streams[j], &pclmul_v[j][0], &pclmul_v[j][1]); + Store64Bytes<copy_type>(dst_pclmul_streams[j], pclmul_v[j][0], + pclmul_v[j][1]); + dst_pclmul_streams[j] += 64; + pclmul_streams[j] += 64; + pclmul_copy[j] = reinterpret_cast<const uint8_t*>(pclmul_v[j]); + } } - for (size_t i = 0; i < num_pclmul_streams; i++) { - l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); - l64 ^= l64_pclmul[i]; + const uint8_t** pclmul_src = + copy_type != CopyType::kNone ? pclmul_copy : pclmul_streams; + // Fold the four 16-byte blocks of each PCLMUL stream into + // partialCRC[0..3]. For VPCLMUL, 32 bytes are folded every other block. + ProcessAllStreams16<kNumActiveCrcStreams, kNumActivePclmulStreams, + /*kVpclmulBytes=*/32>( + crc_streams, l64_crc, pclmul_src, partialCRC, /*lane=*/0); + ProcessAllStreams16<kNumActiveCrcStreams, kNumActivePclmulStreams, + /*kVpclmulBytes=*/0>(crc_streams, l64_crc, pclmul_src, + partialCRC, /*lane=*/1); + ProcessAllStreams16<kNumActiveCrcStreams, kNumActivePclmulStreams, + /*kVpclmulBytes=*/32>( + crc_streams, l64_crc, pclmul_src, partialCRC, /*lane=*/2); + ProcessAllStreams16<kNumActiveCrcStreams, kNumActivePclmulStreams, + /*kVpclmulBytes=*/0>(crc_streams, l64_crc, pclmul_src, + partialCRC, /*lane=*/3); + + // Copy the 64 bytes just processed only now, as whole cache lines, + // instead of 16 bytes at a time as they are processed. Otherwise, when + // the destination is slightly ahead of the source modulo 4096, the load + // of the next 16 bytes of a stream would wait for the store of the + // previous 16 bytes, since their addresses have the same lowest 12 bits + // (4K aliasing). + if constexpr (copy_type != CopyType::kNone) { + for (size_t j = 0; j < kNumActiveCrcStreams; j++) { + Copy64Bytes<copy_type>(dst_crc_streams[j], crc_streams[j] - 64); + dst_crc_streams[j] += 64; + } } + } - // Update p. - if constexpr (num_pclmul_streams > 0) { - p = pclmul_streams[num_pclmul_streams - 1]; - } else { - p = crc_streams[num_crc_streams - 1]; + // PCLMULQDQ based streams require special final step; + // CRC based don't. + for (size_t i = 0; i < kNumActivePclmulStreams; i++) { + l64_pclmul[i] = FinalizePclmulStream(partialCRC[i]); + } + + // Combine all streams into single result. + static_assert(64 % (1 << kNumDroppedBits) == 0); + uint32_t magic = ComputeZeroConstant(bs * 64); + l64 = l64_crc[0]; + for (size_t i = 1; i < kNumActiveCrcStreams; i++) { + l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); + l64 ^= l64_crc[i]; + } + for (size_t i = 0; i < kNumActivePclmulStreams; i++) { + l64 = MultiplyWithExtraX33(static_cast<uint32_t>(l64), magic); + l64 ^= l64_pclmul[i]; + } + + // Update p and d. + if constexpr (kNumActivePclmulStreams > 0) { + p = pclmul_streams[kNumActivePclmulStreams - 1]; + if constexpr (copy_type != CopyType::kNone) { + d = reinterpret_cast<char*>( + dst_pclmul_streams[kNumActivePclmulStreams - 1]); + size_t remaining_to_copy = static_cast<size_t>(e - p); + std::memcpy(d, p, remaining_to_copy); + } + } else { + p = crc_streams[kNumActiveCrcStreams - 1]; + if constexpr (copy_type != CopyType::kNone) { + d = reinterpret_cast<char*>(dst_crc_streams[kNumActiveCrcStreams - 1]); + size_t remaining_to_copy = static_cast<size_t>(e - p); + std::memcpy(d, p, remaining_to_copy); } - l = static_cast<uint32_t>(l64); } + l = static_cast<uint32_t>(l64); + uint64_t remaining_bytes = static_cast<uint64_t>(e - p); // Process the remaining bytes. while ((e - p) >= 16) { @@ -765,52 +877,171 @@ class CRC32AcceleratedX86ARMCombinedMultipleStreams } *crc = l; + + if constexpr (copy_type == CopyType::kNonTemporal) { + // According to the Intel 64 Software Developer's Manual + // (https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html), + // non-temporal stores are weakly ordered due to bypassing caches, so + // they have to be fenced before the copy is visible to other threads. + // Regular stores are ordered and need no fence. Note that the fence is + // placed after all stores, to avoid unnecessary serialization and a + // performance hit. + NonTemporalStoreFence(); + } } private: - ABSL_ATTRIBUTE_ALWAYS_INLINE void InitPclmulStream( - const uint8_t** pclmul_stream, V128* partialCRC) const { - if constexpr (pclmul_stream_type == PclmulStreamType::VPCLMUL) { + struct StreamCounts { + size_t crc; + size_t pclmul; + }; + + // Returns the number of crc and pclmul streams to use. Copying adds loads and + // stores, so fewer streams are needed to saturate the dispatch width. In copy + // mode, at most kMaxCopyStreams of the configured streams are used, taken in + // the order: pclmul 1, crc 1, pclmul 2, crc 2, pclmul 3, crc 3. + static constexpr StreamCounts GetStreamCounts(CopyType copy_type) { + if (copy_type == CopyType::kNone) { + return {num_crc_streams, num_pclmul_streams}; + } + StreamCounts counts = {0, 0}; + for (size_t i = 0; i < kMaxStreams; i++) { + if (i < num_pclmul_streams && + counts.crc + counts.pclmul < kMaxCopyStreams) { + counts.pclmul++; + } + if (i < num_crc_streams && counts.crc + counts.pclmul < kMaxCopyStreams) { + counts.crc++; + } + } + return counts; + } + + // Whether PCLMUL streams are folded with 256-bit `vpclmulqdq`. + static constexpr bool kIsVpclmul = + (pclmul_stream_type == PclmulStreamType::VPCLMUL); + + // The high product of a fold, which is returned by `PclmulStream` and + // consumed by `XorPclmulStream`. Folding 32 bytes with 256-bit `vpclmulqdq` + // produces a V256; every other PclmulStreamType produces a V128. + template <size_t kVpclmulBytes> + using PclmulProduct = + std::conditional_t<kIsVpclmul && kVpclmulBytes == 32, V256, V128>; + + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void + InitPclmulStream(V256 v0, V256 v1, V128* partialCRC) const { + if constexpr (pclmul_stream_type == PclmulStreamType::NONE) { + return; + } else if constexpr (kIsVpclmul) { V256* vpartialCRC = reinterpret_cast<V256*>(partialCRC); - vpartialCRC[0] = - V256_LoadU(reinterpret_cast<const V256*>(*pclmul_stream + 32 * 0)); - vpartialCRC[1] = - V256_LoadU(reinterpret_cast<const V256*>(*pclmul_stream + 32 * 1)); + vpartialCRC[0] = v0; + vpartialCRC[1] = v1; } else { - partialCRC[0] = - V128_LoadU(reinterpret_cast<const V128*>(*pclmul_stream + 16 * 0)); - partialCRC[1] = - V128_LoadU(reinterpret_cast<const V128*>(*pclmul_stream + 16 * 1)); - partialCRC[2] = - V128_LoadU(reinterpret_cast<const V128*>(*pclmul_stream + 16 * 2)); - partialCRC[3] = - V128_LoadU(reinterpret_cast<const V128*>(*pclmul_stream + 16 * 3)); - } - *pclmul_stream += 16 * 4; + const V128* data_ptr0 = reinterpret_cast<const V128*>(&v0); + const V128* data_ptr1 = reinterpret_cast<const V128*>(&v1); + partialCRC[0] = data_ptr0[0]; + partialCRC[1] = data_ptr0[1]; + partialCRC[2] = data_ptr1[0]; + partialCRC[3] = data_ptr1[1]; + } } - ABSL_ATTRIBUTE_ALWAYS_INLINE void ProcessPclmulStream( - const uint8_t** pclmul_stream, V128* partialCRC) const { - if constexpr (pclmul_stream_type == PclmulStreamType::VPCLMUL) { - V256 loopMultiplicands = - V256_Broadcast128(reinterpret_cast<const V128*>(kFoldAcross512Bits)); - Process64BytesVpclmul(*pclmul_stream, reinterpret_cast<V256*>(partialCRC), - loopMultiplicands); - } else if constexpr (pclmul_stream_type == PclmulStreamType::NEON_PCLMUL || - pclmul_stream_type == - PclmulStreamType::NEON_PCLMUL_EOR3) { - constexpr bool kUseEor3 = - (pclmul_stream_type == PclmulStreamType::NEON_PCLMUL_EOR3); - Process64BytesNeonPclmul<kUseEor3>(*pclmul_stream, partialCRC); + // Performs the polynomial multiplications to fold `partialCRC` by 512 bits, + // storing the low product in `partialCRC` and returning the high product, + // which must be passed to `XorPclmulStream` to complete the fold. + template <size_t kVpclmulBytes> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE + PclmulProduct<kVpclmulBytes> + PclmulStream(V128* partialCRC) const { + if constexpr (pclmul_stream_type == PclmulStreamType::NONE || + (kIsVpclmul && kVpclmulBytes == 0)) { + return {}; + } else if constexpr (kIsVpclmul && kVpclmulBytes == 32) { + return Pclmul32BytesVpclmul(reinterpret_cast<V256*>(partialCRC)); } else { - Process64BytesPclmul(*pclmul_stream, partialCRC); + return Pclmul16Bytes(partialCRC); } - *pclmul_stream += 16 * 4; } - ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t + // Completes folding the next bytes at `*stream` into `partialCRC` by XORing + // the high product returned by `PclmulStream`, the low product in + // `partialCRC`, and the loaded data, and advances `*stream`. + template <size_t kVpclmulBytes> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void XorPclmulStream( + const uint8_t** stream, const PclmulProduct<kVpclmulBytes>& high, + V128* partialCRC) const { + if constexpr (pclmul_stream_type == PclmulStreamType::NONE || + (kIsVpclmul && kVpclmulBytes == 0)) { + return; + } else if constexpr (kIsVpclmul && kVpclmulBytes == 32) { + Xor32BytesVpclmul(*stream, high, reinterpret_cast<V256*>(partialCRC)); + *stream += 32; + } else { + V128 data = V128_LoadU(reinterpret_cast<const V128*>(*stream)); + if constexpr (pclmul_stream_type == PclmulStreamType::NEON_PCLMUL || + pclmul_stream_type == PclmulStreamType::NEON_PCLMUL_EOR3) { + constexpr bool kUseEor3 = + (pclmul_stream_type == PclmulStreamType::NEON_PCLMUL_EOR3); + Xor16BytesNeonPclmul<kUseEor3>(data, high, partialCRC); + } else { + static_assert(pclmul_stream_type == PclmulStreamType::PCLMUL || + (kIsVpclmul && kVpclmulBytes == 16)); + Xor16BytesPclmul(data, high, partialCRC); + } + *stream += 16; + } + } + + // Processes the next 16 bytes of every CRC and PCLMUL stream, folding each + // PCLMUL stream into `partialCRC[lane]`, and advances the stream pointers. + // + // PCLMUL, vector XOR, and CRC32 instructions are interleaved across the two + // 8-byte halves of each 16-byte CRC step (8B CRC -> PCLMUL -> 8B CRC -> XOR) + // to keep the execution units busy. + // + // When `pclmul_stream_type` is `VPCLMUL`, a single 256-bit `vpclmulqdq` + // instruction folds 32 bytes at once across two 16-byte calls. + // `kVpclmulBytes` controls how many bytes of each VPCLMUL stream to process + // in this call: + // - 32: Fold 32 bytes into `partialCRC[lane..lane + 1]` (used on the first + // half of a 32-byte block). + // - 0: Skip the VPCLMUL streams (used on the second half of a 32-byte + // block, since the first half already folded all 32 bytes). + // - 16: Fold 16 bytes into `partialCRC[lane]` using 128-bit `pclmulqdq` + // (used for the standalone 16-byte tail). + // For non-VPCLMUL stream types, `kVpclmulBytes` is ignored and 16 bytes are + // always folded. + template <size_t kNumActiveCrcStreams, size_t kNumActivePclmulStreams, + size_t kVpclmulBytes> + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE void + ProcessAllStreams16(const uint8_t** crc_streams, uint64_t* l64_crc, + const uint8_t** pclmul_streams, V128 (*partialCRC)[4], + size_t lane) const { + for (size_t j = 0; j < kMaxStreams; j++) { + if (j < kNumActiveCrcStreams) { + l64_crc[j] = Process8BytesCRC(crc_streams[j], l64_crc[j]); + crc_streams[j] += 8; + } + PclmulProduct<kVpclmulBytes> high; + if (j < kNumActivePclmulStreams) { + high = PclmulStream<kVpclmulBytes>(&partialCRC[j][lane]); + } + if (j < kNumActiveCrcStreams) { + l64_crc[j] = Process8BytesCRC(crc_streams[j], l64_crc[j]); + crc_streams[j] += 8; + } + if (j < kNumActivePclmulStreams) { + XorPclmulStream<kVpclmulBytes>(&pclmul_streams[j], high, + &partialCRC[j][lane]); + } + } + } + + ABSL_INTERNAL_ATTRIBUTE_AVX ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizePclmulStream(V128* partialCRC) const { - if constexpr (pclmul_stream_type == PclmulStreamType::VPCLMUL) { + if constexpr (pclmul_stream_type == PclmulStreamType::NONE) { + return 0; + } else if constexpr (kIsVpclmul) { return FinalizeVpclmulStream(reinterpret_cast<V256*>(partialCRC)); } else if constexpr (pclmul_stream_type == PclmulStreamType::NEON_PCLMUL || pclmul_stream_type == @@ -848,16 +1079,31 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { 3, 1, PclmulStreamType::PCLMUL>(); case CpuType::kAmdMilan: case CpuType::kAmdGenoa: + case CpuType::kAmdRyzenV3000: + case CpuType::kAmdSiena: case CpuType::kAmdTurin: -#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && defined(__AVX__) && \ + case CpuType::kAmdVenice: +#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && \ + (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \ (!defined(_MSC_VER) || defined(__clang__)) // We don't have vector pclmul on arm, but this still needs to // compile. return new CRC32AcceleratedX86ARMCombinedMultipleStreams< - 3, 1, PclmulStreamType::VPCLMUL>(); + 2, 2, PclmulStreamType::VPCLMUL>(); #else return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 1, PclmulStreamType::PCLMUL>(); +#endif + case CpuType::kIntelSapphirerapids: + case CpuType::kIntelEmeraldrapids: + case CpuType::kIntelGraniterapids: +#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) && \ + (defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \ + (!defined(_MSC_VER) || defined(__clang__)) + return new CRC32AcceleratedX86ARMCombinedMultipleStreams< + 3, 3, PclmulStreamType::VPCLMUL>(); +#else + [[fallthrough]]; #endif // PCLMULQDQ is fast, use combined PCLMULQDQ + CRC implementation. case CpuType::kIntelCascadelakeXeon: @@ -865,9 +1111,6 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { case CpuType::kIntelBroadwell: case CpuType::kIntelSkylake: case CpuType::kIntelIcelake: - case CpuType::kIntelSapphirerapids: - case CpuType::kIntelEmeraldrapids: - case CpuType::kIntelGraniterapids: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 2, PclmulStreamType::PCLMUL>(); // PCLMULQDQ is slow, don't use it. @@ -875,13 +1118,14 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { case CpuType::kIntelSandybridge: case CpuType::kIntelWestmere: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< - 3, 0, PclmulStreamType::PCLMUL>(); + 3, 0, PclmulStreamType::NONE>(); case CpuType::kArmNeoverseN1: case CpuType::kArmNeoverseV1: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 1, 1, PclmulStreamType::NEON_PCLMUL>(); case CpuType::kArmNeoverseN2: case CpuType::kArmNeoverseN3: + case CpuType::kArmNeoverseN4: case CpuType::kNvidiaGrace: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 1, 1, PclmulStreamType::NEON_PCLMUL_EOR3>(); @@ -889,6 +1133,7 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 2, PclmulStreamType::NEON_PCLMUL_EOR3>(); case CpuType::kArmNeoverseV2: + case CpuType::kArmNeoverseV3: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 1, 2, PclmulStreamType::NEON_PCLMUL_EOR3>(); #if defined(__aarch64__) @@ -896,8 +1141,13 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { // Not all ARM processors support the needed instructions, so check here // before trying to use an accelerated implementation. if (SupportsArmCRC32PMULL()) { +#if defined(__APPLE__) + return new CRC32AcceleratedX86ARMCombinedMultipleStreams< + 3, 3, PclmulStreamType::NEON_PCLMUL>(); +#else return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 1, 1, PclmulStreamType::NEON_PCLMUL>(); +#endif } else { return nullptr; } @@ -905,7 +1155,7 @@ CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { default: // Something else, play it safe and assume slow PCLMULQDQ. return new CRC32AcceleratedX86ARMCombinedMultipleStreams< - 3, 0, PclmulStreamType::PCLMUL>(); + 3, 0, PclmulStreamType::NONE>(); #endif } } diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/debugging/BUILD.bazel index b36967a399ca..265133a41a54 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/BUILD.bazel @@ -127,6 +127,9 @@ cc_test( "@rules_cc//cc/compiler:clang-cl": ["/Z7"], "//conditions:default": [], }), + # Ensure symbolize_test.pdb is declared as a linker output on Windows even + # in opt builds so it is uploaded to the remote cache. + features = ["generate_pdb_file"], linkopts = ABSL_DEFAULT_LINKOPTS + select({ "@rules_cc//cc/compiler:msvc-cl": ["/DEBUG"], "@rules_cc//cc/compiler:clang-cl": ["/DEBUG"], @@ -198,6 +201,7 @@ cc_test( "@rules_cc//cc/compiler:msvc-cl": [], "@rules_cc//cc/compiler:clang-cl": [], "@rules_cc//cc/compiler:emscripten": [], + "@platforms//os:wasi": [], "//conditions:default": ["-pthread"], }) + ABSL_DEFAULT_LINKOPTS, deps = [ diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h b/deps/v8/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h index 4d31a474cfdd..f24aa26f2aca 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h @@ -42,10 +42,20 @@ #ifdef ABSL_HAVE_ELF_MEM_IMAGE +#if __has_include(<link.h>) #include <link.h> // for ElfW +#else +#include <elf.h> +#endif -#if defined(__FreeBSD__) && !defined(ElfW) -#define ElfW(x) __ElfN(x) +#ifndef ElfW +#if defined(__FreeBSD__) +#define ElfW(type) __ElfN(type) +#elif __SIZEOF_POINTER__ == 8 +#define ElfW(type) Elf64_##type +#else +#define ElfW(type) Elf32_##type +#endif #endif namespace absl { diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc b/deps/v8/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc index 3c125e2f3c5c..ce0ac22e51df 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc @@ -51,7 +51,7 @@ static __thread int recursive = 0; static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. // Waiting until static initializers run seems to be late enough. // This file is included into stacktrace.cc so this will only run once. -ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { +[[maybe_unused]] static int stacktraces_enabler = []() { disable_stacktraces.store(false, std::memory_order_relaxed); return 0; }(); diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/deps/v8/third_party/abseil-cpp/absl/debugging/internal/symbolize.h index fd655449c3ee..22bed14ddaeb 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/internal/symbolize.h +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/internal/symbolize.h @@ -30,8 +30,7 @@ #ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set -#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__asmjs__) \ - && !defined(__wasm__) +#elif defined(__ELF__) && defined(__linux__) && !defined(__ANDROID__) #define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1 #include <elf.h> diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace.cc b/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace.cc index 9689337099d7..6dc366ce65bf 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace.cc +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace.cc @@ -161,8 +161,14 @@ void SetStackUnwinder(Unwinder w) { custom.store(w, std::memory_order_release); } -int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip, - const void* uc, int* min_dropped_frames) { +// As of LLVM commit go/compilers/fc1afa6edce98a973ce2ce969c589da4f3aee975, +// CFI functions are inlinable in the ThinLTO backend. As a result, these +// wrappers were inlined into their callers, causing stack unwinding to skip an +// extra caller frame. Prevent inlining to ensure their stack frames are +// preserved when calculating `skip_count`. +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int DefaultStackUnwinder( + void** pcs, int* sizes, int depth, int skip, const void* uc, + int* min_dropped_frames) { skip++; // For this function decltype(&UnwindImpl<false, false>) f; if (sizes == nullptr) { diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc b/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc index 02950bcedade..3cdd999f8d43 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/stacktrace_test.cc @@ -339,13 +339,13 @@ ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS void SigUsr1Handler(int, siginfo_t*, void*) { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); } -ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NOINLINE void RaiseSignal() { +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS void RaiseSignal() { g_return_address = __builtin_return_address(0); raise(SIGUSR1); ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); } -ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NOINLINE void +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS void TestNestedSignal() { constexpr size_t kAltstackSize = 1 << 14; // Allocate altstack on regular stack to make sure it'll have a higher diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc index 182d0fd19a92..07b116703bd5 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc @@ -80,10 +80,6 @@ #include "absl/debugging/internal/vdso_support.h" #include "absl/strings/string_view.h" -#if defined(__FreeBSD__) && !defined(ElfW) -#define ElfW(x) __ElfN(x) -#endif - namespace absl { ABSL_NAMESPACE_BEGIN @@ -296,8 +292,8 @@ class Symbolizer { memcpy(dst, s, len + 1); return dst; } - ObjFile *FindObjFile(const void *const start, - size_t size) ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_NOINLINE ObjFile* FindObjFile(const void* const start, + size_t size); static bool RegisterObjFile(const char *filename, const void *const start_addr, const void *const end_addr, uint64_t offset, @@ -386,11 +382,7 @@ static std::atomic<Symbolizer *> g_cached_symbolizer; } // namespace static size_t SymbolizerSize() { -#if defined(__wasm__) || defined(__asmjs__) - auto pagesize = static_cast<size_t>(getpagesize()); -#else auto pagesize = static_cast<size_t>(sysconf(_SC_PAGESIZE)); -#endif return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize; } @@ -555,9 +547,9 @@ static int FileGetElfType(CachingFile *file) { // and return true. Otherwise, return false. // To keep stack consumption low, we would like this function to not get // inlined. -static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType( - CachingFile *file, ElfW(Half) sh_num, const off_t sh_offset, - ElfW(Word) type, ElfW(Shdr) * out, char *tmp_buf, size_t tmp_buf_size) { +ABSL_ATTRIBUTE_NOINLINE static bool GetSectionHeaderByType( + CachingFile* file, ElfW(Half) sh_num, const off_t sh_offset, + ElfW(Word) type, ElfW(Shdr) * out, char* tmp_buf, size_t tmp_buf_size) { ElfW(Shdr) *buf = reinterpret_cast<ElfW(Shdr) *>(tmp_buf); const size_t buf_entries = tmp_buf_size / sizeof(buf[0]); const size_t buf_bytes = buf_entries * sizeof(buf[0]); @@ -766,14 +758,33 @@ static const char *ComputeOffset(const char *base, ptrdiff_t offset) { // If the symbol is not found, SYMBOL_NOT_FOUND is returned; // To keep stack consumption low, we would like this function to not get // inlined. -static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( - const void *const pc, CachingFile *file, char *out, size_t out_size, +ABSL_ATTRIBUTE_NOINLINE static FindSymbolResult FindSymbol( + const void* const pc, CachingFile* file, char* out, size_t out_size, ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab, - const ElfW(Shdr) * opd, char *tmp_buf, size_t tmp_buf_size) { + const ElfW(Shdr) * opd, char* tmp_buf, size_t tmp_buf_size) { if (symtab == nullptr) { return SYMBOL_NOT_FOUND; } + // In the ELF specification, sh_entsize is a generic section header field that + // holds the entry size in bytes for sections containing fixed-size entries. + // For symbol tables (SHT_SYMTAB and SHT_DYNSYM), the ELF specification + // mandates that each entry is an ElfW(Sym), so sh_entsize should always equal + // sizeof(ElfW(Sym)). + // + // However, because sh_entsize is read directly from the untrusted object + // file, a crafted or corrupt file can specify an unexpected value: + // 1. Setting sh_entsize to 0 would cause a division-by-zero (SIGFPE) in the + // num_symbols calculation below. + // 2. Setting sh_entsize to a value other than sizeof(ElfW(Sym)) would + // desynchronize our fixed-size ElfW(Sym) buffer reads from the per-entry + // stride in the file. + // Reject such malformed tables, mirroring the e_shentsize check we apply to + // section headers. + if (symtab->sh_entsize != sizeof(ElfW(Sym))) { + return SYMBOL_NOT_FOUND; + } + // Read multiple symbols at once to save read() calls. ElfW(Sym) *buf = reinterpret_cast<ElfW(Sym) *>(tmp_buf); const size_t buf_entries = tmp_buf_size / sizeof(buf[0]); @@ -1081,10 +1092,10 @@ static bool ShouldUseMapping(const char *const flags) { // Read /proc/self/maps and run "callback" for each mmapped file found. If // "callback" returns false, stop scanning and return true. Else continue // scanning /proc/self/maps. Return true if no parse error is found. -static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap( - bool (*callback)(const char *filename, const void *const start_addr, - const void *const end_addr, uint64_t offset, void *arg), - void *arg, void *tmp_buf, size_t tmp_buf_size) { +ABSL_ATTRIBUTE_NOINLINE static bool ReadAddrMap( + bool (*callback)(const char* filename, const void* const start_addr, + const void* const end_addr, uint64_t offset, void* arg), + void* arg, void* tmp_buf, size_t tmp_buf_size) { // Use /proc/self/task/<pid>/maps instead of /proc/self/maps. The latter // requires kernel to stop all threads, and is significantly slower when there // are 1000s of threads. @@ -1289,8 +1300,8 @@ bool Symbolizer::RegisterObjFile(const char *filename, // where the input symbol is demangled in-place. // To keep stack consumption low, we would like this function to not // get inlined. -static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size, - char *tmp_buf, +ABSL_ATTRIBUTE_NOINLINE static void DemangleInplace(char* out, size_t out_size, + char* tmp_buf, size_t tmp_buf_size) { if (Demangle(out, tmp_buf, tmp_buf_size)) { // Demangling succeeded. Copy to out if the space allows. diff --git a/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_test.cc index 2cb16381b6f5..9ee0abd8d638 100644 --- a/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/debugging/symbolize_test.cc @@ -14,6 +14,7 @@ #include "absl/debugging/symbolize.h" +#include <cerrno> #include <cstddef> #include <cstdint> #include <cstring> @@ -27,6 +28,7 @@ #include "absl/base/attributes.h" #include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/internal/direct_mmap.h" #include "absl/base/internal/low_level_alloc.h" #include "absl/base/internal/per_thread_tls.h" #include "absl/base/optimization.h" @@ -46,6 +48,7 @@ #ifndef _WIN32 #include <fcntl.h> #include <sys/mman.h> +#include <unistd.h> #endif #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) @@ -163,7 +166,7 @@ static const char *TrySymbolize(void *pc) { defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) // Test with a return address. -void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { +ABSL_ATTRIBUTE_NOINLINE static void TestWithReturnAddress() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) void *return_address = __builtin_return_address(0); const char *symbol = TrySymbolize(return_address); @@ -418,10 +421,13 @@ TEST(Symbolize, SetSymbolDecorator) { // to optimize away the .data section if no variables live in the // section. This variable should get placed in the .data section, and // the test below checks for the existence of a .data section. -static int in_data_section = 1; +static int in_data_section [[maybe_unused]] = 1; TEST(Symbolize, ForEachSection) { - int fd = TEMP_FAILURE_RETRY(open("/proc/self/exe", O_RDONLY)); + int fd; + do { + fd = open("/proc/self/exe", O_RDONLY); + } while (fd == -1 && errno == EINTR); ASSERT_NE(fd, -1); std::vector<std::string> sections; @@ -440,6 +446,120 @@ TEST(Symbolize, ForEachSection) { close(fd); } + +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) +// Builds a minimal ELF image whose SHT_SYMTAB section header carries the given +// sh_entsize. Everything else is just enough to reach FindSymbol(): a single +// executable PT_LOAD segment (so the object is initialized) and a symbol table +// whose sh_link points at the null section header. +static std::string MakeElfWithSymtabEntSize(uint64_t sym_entsize) { + ElfW(Ehdr) ehdr; + memset(&ehdr, 0, sizeof(ehdr)); + memcpy(ehdr.e_ident, ELFMAG, SELFMAG); + ehdr.e_ident[EI_CLASS] = (sizeof(void*) == 8) ? ELFCLASS64 : ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_type = ET_DYN; + ehdr.e_version = EV_CURRENT; + ehdr.e_phoff = sizeof(ElfW(Ehdr)); + ehdr.e_phentsize = sizeof(ElfW(Phdr)); + ehdr.e_phnum = 1; + ehdr.e_shoff = sizeof(ElfW(Ehdr)) + sizeof(ElfW(Phdr)); + ehdr.e_shentsize = sizeof(ElfW(Shdr)); + ehdr.e_shnum = 2; + ehdr.e_shstrndx = 0; + + ElfW(Phdr) phdr; + memset(&phdr, 0, sizeof(phdr)); + phdr.p_type = PT_LOAD; + phdr.p_flags = PF_R | PF_X; + phdr.p_filesz = 0x1000; + phdr.p_memsz = 0x1000; + phdr.p_align = 0x1000; + + // Section 0 is the mandatory null header, which also serves as the string + // table referenced by sh_link below (its contents are irrelevant here). + ElfW(Shdr) null_shdr; + memset(&null_shdr, 0, sizeof(null_shdr)); + + ElfW(Shdr) symtab; + memset(&symtab, 0, sizeof(symtab)); + symtab.sh_type = SHT_SYMTAB; + symtab.sh_link = 0; + symtab.sh_size = sizeof(ElfW(Sym)); + symtab.sh_entsize = sym_entsize; + symtab.sh_offset = ehdr.e_shoff + 2 * sizeof(ElfW(Shdr)); + + std::string image; + image.append(reinterpret_cast<const char*>(&ehdr), sizeof(ehdr)); + image.append(reinterpret_cast<const char*>(&phdr), sizeof(phdr)); + image.append(reinterpret_cast<const char*>(&null_shdr), sizeof(null_shdr)); + image.append(reinterpret_cast<const char*>(&symtab), sizeof(symtab)); + // Pad so the symtab sh_offset lands inside the file. + image.resize(image.size() + sizeof(ElfW(Sym)), '\0'); + return image; +} + +// Helper class that creates a temporary file on disk with the given content +// and unlinks it upon destruction. +class TempFile { + public: + explicit TempFile(absl::string_view content) { + std::string dir = testing::TempDir(); + if (dir.empty() || dir.back() != '/') { + dir.push_back('/'); + } + path_ = dir + "absl_bad_symtab_XXXXXX"; + int fd = mkstemp(path_.data()); + CHECK_NE(fd, -1); + CHECK_EQ(write(fd, content.data(), content.size()), + static_cast<ssize_t>(content.size())); + close(fd); + } + ~TempFile() { unlink(path_.c_str()); } + + TempFile(const TempFile&) = delete; + TempFile& operator=(const TempFile&) = delete; + + const char* path() const { return path_.c_str(); } + + private: + std::string path_; +}; + +// A crafted object file can set the symbol table's sh_entsize to zero, which is +// used verbatim as the divisor for the symbol count in FindSymbol(). Before +// the fix this divided by zero (SIGFPE) while symbolizing; now the malformed +// table is skipped and the address simply fails to resolve. +TEST(Symbolize, InvalidSymtabEntSizeDoesNotCrash) { + TempFile file(MakeElfWithSymtabEntSize(/*sym_entsize=*/0)); + + // Map an executable page to provide a memory address to symbolize. + const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE)); + void* region = + absl::base_internal::DirectMmap(nullptr, page_size, PROT_READ | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (region == MAP_FAILED) { + GTEST_SKIP() << "Unable to map an executable page: errno=" << errno; + } + absl::Cleanup unmap = [&] { + absl::base_internal::DirectMunmap(region, page_size); + }; + + // absl::Symbolize() needs this file mapping hint to associate addresses + // within the mapped region with the ELF file on disk and attempt + // symbolization. + ASSERT_TRUE(absl::debugging_internal::RegisterFileMappingHint( + region, static_cast<char*>(region) + page_size, 0, file.path())); + + // Output buffer for absl::Symbolize(). 512 bytes is arbitrarily chosen to + // receive any demangled symbol name for the purposes of this test. + char symbol_buf[512]; + // The point of the test is that this returns instead of crashing with SIGFPE. + EXPECT_FALSE(absl::Symbolize(static_cast<char*>(region) + 8, symbol_buf, + sizeof(symbol_buf))); +} +#endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE #endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE && // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE @@ -455,7 +575,7 @@ inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { return pc; } -void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { +ABSL_ATTRIBUTE_NOINLINE void* non_inline_func() { void *pc = nullptr; #if defined(__i386__) __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [PC] "=r"(pc)); @@ -465,7 +585,7 @@ void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { return pc; } -void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { +ABSL_ATTRIBUTE_NOINLINE void TestWithPCInsideNonInlineFunction() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) && \ (defined(__i386__) || defined(__x86_64__)) void *pc = non_inline_func(); @@ -476,7 +596,7 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { #endif } -void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { +ABSL_ATTRIBUTE_NOINLINE void TestWithPCInsideInlineFunction() { #if defined(ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE) && \ (defined(__i386__) || defined(__x86_64__)) void *pc = inline_func(); // Must be inlined. @@ -520,7 +640,7 @@ __attribute__((target("arm"))) int ArmThumbOverlapArm(int x) { return x * x * x; } -void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { +ABSL_ATTRIBUTE_NOINLINE void TestArmThumbOverlap() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm); ASSERT_NE(symbol, nullptr) << "TestArmThumbOverlap failed"; diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.bazel index 59cae9978a0f..59771c7f47c7 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.bazel @@ -208,6 +208,7 @@ cc_library( "//absl/base:core_headers", "//absl/base:fast_type_id", "//absl/base:no_destructor", + "//absl/base:nullability", "//absl/container:flat_hash_map", "//absl/strings", "//absl/strings:string_view", diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.gn index fd9ab729cd15..7d30f38d80bb 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/flags/BUILD.gn @@ -126,6 +126,7 @@ absl_source_set("reflection") { "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/base:fast_type_id", "//third_party/abseil-cpp/absl/base:no_destructor", + "//third_party/abseil-cpp/absl/base:nullability", "//third_party/abseil-cpp/absl/container:flat_hash_map", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/strings:string_view", diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/flags/CMakeLists.txt index a96e294cb305..162b654ede1c 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/flags/CMakeLists.txt @@ -174,6 +174,7 @@ absl_cc_library( absl::flags_private_handle_accessor absl::flat_hash_map absl::no_destructor + absl::nullability absl::string_view absl::strings absl::synchronization @@ -454,6 +455,8 @@ absl_cc_test( absl::flags_internal absl::time GTest::gmock_main + SHARD_COUNT + 31 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/flag.h b/deps/v8/third_party/abseil-cpp/absl/flags/flag.h index 2a950491c054..2e9a9e6c4762 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/flag.h +++ b/deps/v8/third_party/abseil-cpp/absl/flags/flag.h @@ -298,10 +298,20 @@ ABSL_NAMESPACE_END // `default_value` and `explanation` are unused. // TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of // retired flags are cleaned up. +#if ABSL_FLAGS_STRIP_NAMES +// When flag names are stripped, retired flags are not registered. Define an +// unused type alias instead of an object so that no runtime constructor or +// storage is emitted, the trailing semicolon is consumed, and `type` (along +// with this header) remains referenced to avoid unused-type/include warnings. +#define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \ + using RETIRED_FLAGS_##name [[maybe_unused]] = \ + ::absl::flags_internal::RetiredFlag<type> +#else #define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \ static absl::flags_internal::RetiredFlag<type> RETIRED_FLAGS_##name; \ [[maybe_unused]] static const auto RETIRED_FLAGS_REG_##name = \ (RETIRED_FLAGS_##name.Retire(#name), \ ::absl::flags_internal::FlagRegistrarEmpty{}) +#endif #endif // ABSL_FLAGS_FLAG_H_ diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/flag_benchmark.cc b/deps/v8/third_party/abseil-cpp/absl/flags/flag_benchmark.cc index be435d92e7f9..2a356ee1eaec 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/flag_benchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/flags/flag_benchmark.cc @@ -76,8 +76,8 @@ std::string AbslUnparseFlag(const OptionalString& flag) { struct UDT { UDT() = default; - UDT(const UDT&) {} - UDT& operator=(const UDT&) { return *this; } + UDT(const UDT&) = default; + UDT& operator=(const UDT&) = default; }; // Next two functions represent Abseil Flags marshalling for UDT. bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; } diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/flag_test.cc b/deps/v8/third_party/abseil-cpp/absl/flags/flag_test.cc index 7cbce8876bc7..5cacf6470de8 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/flag_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/flags/flag_test.cc @@ -51,6 +51,7 @@ ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag); namespace { namespace flags = absl::flags_internal; +constexpr bool kStrippedFlagNames = ABSL_FLAGS_STRIP_NAMES != 0; std::string TestHelpMsg() { return "dynamic help"; } #if defined(_MSC_VER) && !defined(__clang__) @@ -230,9 +231,9 @@ ABSL_DECLARE_FLAG(absl::uint128, test_flag_14); namespace { TEST_F(FlagTest, TestFlagDeclaration) { -#if ABSL_FLAGS_STRIP_NAMES - GTEST_SKIP() << "This test requires flag names to be present"; -#endif + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } // test that we can access flag objects. EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), "test_flag_01"); @@ -266,7 +267,7 @@ TEST_F(FlagTest, TestFlagDeclaration) { } // namespace -#if ABSL_FLAGS_STRIP_NAMES +#if ABSL_FLAGS_STRIP_NAMES && defined(__cpp_consteval) // The intent of this helper struct and an expression below is to make sure that // in the configuration where ABSL_FLAGS_STRIP_NAMES=1 registrar construction // (in cases of no Tail calls like OnUpdate) is constexpr and thus can and @@ -280,7 +281,7 @@ struct VerifyConsteval { }; ABSL_FLAG(int, test_registrar_const_init, 0, "") + VerifyConsteval(); -#endif +#endif // ABSL_FLAGS_STRIP_NAMES && defined(__cpp_consteval) // -------------------------------------------------------------------- @@ -303,9 +304,9 @@ ABSL_FLAG(absl::uint128, test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD), namespace { TEST_F(FlagTest, TestFlagDefinition) { -#if ABSL_FLAGS_STRIP_NAMES - GTEST_SKIP() << "This test requires flag names to be present"; -#endif + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } absl::string_view expected_file_name = "absl/flags/flag_test.cc"; EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(), @@ -626,9 +627,9 @@ TEST_F(FlagTest, TestGetSet) { // -------------------------------------------------------------------- TEST_F(FlagTest, TestGetViaReflection) { -#if ABSL_FLAGS_STRIP_NAMES - GTEST_SKIP() << "This test requires flag names to be present"; -#endif + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } auto* handle = absl::FindCommandLineFlag("test_flag_01"); EXPECT_EQ(*handle->TryGet<bool>(), true); handle = absl::FindCommandLineFlag("test_flag_02"); @@ -663,9 +664,9 @@ TEST_F(FlagTest, TestGetViaReflection) { // -------------------------------------------------------------------- TEST_F(FlagTest, ConcurrentSetAndGet) { -#if ABSL_FLAGS_STRIP_NAMES - GTEST_SKIP() << "This test requires flag names to be present"; -#endif + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } static constexpr int kNumThreads = 8; // Two arbitrary durations. One thread will concurrently flip the flag // between these two values, while the other threads read it and verify @@ -816,9 +817,9 @@ TEST_F(FlagTest, TestCustomUDT) { using FlagDeathTest = FlagTest; TEST_F(FlagDeathTest, TestTypeMismatchValidations) { -#if ABSL_FLAGS_STRIP_NAMES - GTEST_SKIP() << "This test requires flag names to be present"; -#endif + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } #if !defined(NDEBUG) EXPECT_DEATH_IF_SUPPORTED( static_cast<void>(absl::GetFlag(FLAGS_mistyped_int_flag)), @@ -950,14 +951,23 @@ bool initialization_order_fiasco_test [[maybe_unused]] = [] { TEST_F(FlagTest, TestRetiredFlagRegistration) { auto* handle = absl::FindCommandLineFlag("old_bool_flag"); - EXPECT_TRUE(handle->IsOfType<bool>()); - EXPECT_TRUE(handle->IsRetired()); - handle = absl::FindCommandLineFlag("old_int_flag"); - EXPECT_TRUE(handle->IsOfType<int>()); - EXPECT_TRUE(handle->IsRetired()); - handle = absl::FindCommandLineFlag("old_str_flag"); - EXPECT_TRUE(handle->IsOfType<std::string>()); - EXPECT_TRUE(handle->IsRetired()); + if constexpr (kStrippedFlagNames) { + EXPECT_EQ(handle, nullptr); + EXPECT_EQ(absl::FindCommandLineFlag("old_int_flag"), nullptr); + EXPECT_EQ(absl::FindCommandLineFlag("old_str_flag"), nullptr); + } else { + ASSERT_NE(handle, nullptr); + EXPECT_TRUE(handle->IsOfType<bool>()); + EXPECT_TRUE(handle->IsRetired()); + handle = absl::FindCommandLineFlag("old_int_flag"); + ASSERT_NE(handle, nullptr); + EXPECT_TRUE(handle->IsOfType<int>()); + EXPECT_TRUE(handle->IsRetired()); + handle = absl::FindCommandLineFlag("old_str_flag"); + ASSERT_NE(handle, nullptr); + EXPECT_TRUE(handle->IsOfType<std::string>()); + EXPECT_TRUE(handle->IsRetired()); + } } } // namespace @@ -1012,13 +1022,11 @@ struct NonTriviallyCopyableUDT { NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) { s_num_instance++; } - NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) { - c = rhs.c; - return *this; - } + NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) = + default; ~NonTriviallyCopyableUDT() { s_num_instance--; } - static uint64_t s_num_instance; + static uint64_t s_num_instance [[maybe_unused]]; char c; }; @@ -1069,7 +1077,7 @@ TEST_F(FlagTest, TestNonTriviallyCopyableGetSetSet) { absl::GetFlag(FLAGS_test_flag_ntc_udt1); EXPECT_EQ(value.c, 'A'); }, - 0); + 0, kStrippedFlagNames ? 1 : 0); TestExpectedLeaks<1>( [&] { @@ -1090,6 +1098,9 @@ TEST_F(FlagTest, TestNonTriviallyCopyableGetSetSet) { } TEST_F(FlagTest, TestNonTriviallyCopyableParseSet) { + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } TestExpectedLeaks<2>( [&] { const char* in_argv[] = {"testbin", "--test_flag_ntc_udt2=A"}; @@ -1115,7 +1126,7 @@ TEST_F(FlagTest, TestNonTriviallyCopyableSet) { absl::SetFlag(&FLAGS_test_flag_ntc_udt3, value); EXPECT_EQ(value.c, 'B'); }, - 0); + 0, kStrippedFlagNames ? 1 : 0); } // One new instance created during initialization and stored in the flag. @@ -1125,6 +1136,9 @@ auto premain_utd4_get = false); TEST_F(FlagTest, TestNonTriviallyCopyableGetBeforeMainParseGet) { + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } TestExpectedLeaks<4>( [&] { const char* in_argv[] = {"testbin", "--test_flag_ntc_udt4=C"}; @@ -1153,6 +1167,9 @@ auto premain_utd5_set = (TestExpectedLeaks<5>( false); TEST_F(FlagTest, TestNonTriviallyCopyableSetParseGet) { + if constexpr (kStrippedFlagNames) { + GTEST_SKIP() << "This test requires flag names to be present"; + } TestExpectedLeaks<5>( [&] { const char* in_argv[] = {"testbin", "--test_flag_ntc_udt5=C"}; diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/reflection.cc b/deps/v8/third_party/abseil-cpp/absl/flags/reflection.cc index 0729ba0a2e8e..e7eeaa32d5af 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/reflection.cc +++ b/deps/v8/third_party/abseil-cpp/absl/flags/reflection.cc @@ -28,6 +28,7 @@ #include "absl/base/config.h" #include "absl/base/no_destructor.h" +#include "absl/base/nullability.h" #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/flags/commandlineflag.h" @@ -339,7 +340,8 @@ class FlagSaverImpl { } // namespace flags_internal -FlagSaver::FlagSaver() : impl_(new flags_internal::FlagSaverImpl) { +FlagSaver::FlagSaver() + : impl_(std::make_unique<flags_internal::FlagSaverImpl>()) { impl_->SaveFromRegistry(); } @@ -347,12 +349,11 @@ FlagSaver::~FlagSaver() { if (!impl_) return; std::move(*impl_).RestoreToRegistry(); - delete impl_; } // -------------------------------------------------------------------- -CommandLineFlag* FindCommandLineFlag(absl::string_view name) { +CommandLineFlag* absl_nullable FindCommandLineFlag(absl::string_view name) { if (name.empty()) return nullptr; flags_internal::FlagRegistry& registry = flags_internal::FlagRegistry::GlobalRegistry(); @@ -361,7 +362,8 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) { // -------------------------------------------------------------------- -absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags() { +absl::flat_hash_map<absl::string_view, absl::CommandLineFlag* absl_nonnull> +GetAllFlags() { absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> res; flags_internal::ForEachFlag([&](CommandLineFlag& flag) { if (!flag.IsRetired()) res.insert({flag.Name(), &flag}); diff --git a/deps/v8/third_party/abseil-cpp/absl/flags/reflection.h b/deps/v8/third_party/abseil-cpp/absl/flags/reflection.h index 54b3e9aef9c8..aeaf728ab267 100644 --- a/deps/v8/third_party/abseil-cpp/absl/flags/reflection.h +++ b/deps/v8/third_party/abseil-cpp/absl/flags/reflection.h @@ -23,9 +23,11 @@ #ifndef ABSL_FLAGS_REFLECTION_H_ #define ABSL_FLAGS_REFLECTION_H_ +#include <memory> #include <string> #include "absl/base/config.h" +#include "absl/base/nullability.h" #include "absl/container/flat_hash_map.h" #include "absl/flags/commandlineflag.h" #include "absl/flags/internal/commandlineflag.h" @@ -42,11 +44,13 @@ class FlagSaverImpl; // Returns the reflection handle of an Abseil flag of the specified name, or // `nullptr` if not found. This function will emit a warning if the name of a // 'retired' flag is specified. -absl::CommandLineFlag* FindCommandLineFlag(absl::string_view name); +absl::CommandLineFlag* absl_nullable FindCommandLineFlag( + absl::string_view name); // Returns current state of the Flags registry in a form of mapping from flag // name to a flag reflection handle. -absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags(); +absl::flat_hash_map<absl::string_view, absl::CommandLineFlag* absl_nonnull> +GetAllFlags(); //------------------------------------------------------------------------------ // FlagSaver @@ -77,10 +81,11 @@ class FlagSaver { ~FlagSaver(); FlagSaver(const FlagSaver&) = delete; - void operator=(const FlagSaver&) = delete; + FlagSaver& operator=(const FlagSaver&) = delete; private: - flags_internal::FlagSaverImpl* impl_; + // Null if no flags restoration is needed. + absl_nullable std::unique_ptr<flags_internal::FlagSaverImpl> impl_; }; //----------------------------------------------------------------------------- diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.bazel index d1b46c79b1ec..0cad083ec16f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.bazel @@ -124,6 +124,7 @@ cc_test( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":bind_front", + "//absl/base:config", "//absl/memory", "@googletest//:gtest", "@googletest//:gtest_main", diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.gn index 3b592b5a66cf..5eb826d7f92d 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/functional/BUILD.gn @@ -73,6 +73,7 @@ absl_test("bind_front_test") { sources = [ "bind_front_test.cc" ] deps = [ ":bind_front", + "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/memory", ] } diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/functional/CMakeLists.txt index 1ddfa291b1cd..231c9dd4f9d3 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/functional/CMakeLists.txt @@ -105,6 +105,7 @@ absl_cc_test( ${ABSL_DEFAULT_COPTS} DEPS absl::bind_front + absl::config absl::memory GTest::gmock_main ) diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/bind_front.h b/deps/v8/third_party/abseil-cpp/absl/functional/bind_front.h index 45ca4fc45da1..06b6e5250937 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/bind_front.h +++ b/deps/v8/third_party/abseil-cpp/absl/functional/bind_front.h @@ -21,10 +21,11 @@ // it does not require the use of argument placeholders. The simpler syntax of // `absl::bind_front()` allows you to avoid known misuses with `std::bind()`. // -// `absl::bind_front()` is meant as a drop-in replacement for C++20's upcoming -// `std::bind_front()`, which similarly resolves these issues with -// `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`, allow -// partial function application. (See +// `absl::bind_front()` is meant as a drop-in replacement for C++20's +// `std::bind_front(func, args...)` and C++26's +// `std::bind_front<ConstFn>(args...)`, which similarly resolve these issues +// with `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`, +// allow partial function application. (See // https://en.wikipedia.org/wiki/Partial_application). #ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_ @@ -39,17 +40,40 @@ #include <functional> // For std::bind_front. #endif // defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L +#include <type_traits> #include <utility> #include "absl/functional/internal/front_binder.h" #include "absl/utility/utility.h" +// ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT +// +// Defined if the standard library implements C++26 `std::bind_front<ConstFn>`, +// which `absl::bind_front<ConstFn>` then aliases. +// +// libc++ 17 through 22 define `__cpp_lib_bind_front` as 202306L in C++26 mode, +// but `std::bind_front<ConstFn>` was first implemented in libc++ 23: +// https://github.com/llvm/llvm-project/pull/165096#issuecomment-4487517016 +#ifdef ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT +#error ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT cannot be directly set +#elif defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 202306L && \ + (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 230000) +#define ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT 1 +#endif + namespace absl { ABSL_NAMESPACE_BEGIN // bind_front() // // Binds the first N arguments of an invocable object and stores them by value. +// The target invocable can be passed either as a runtime argument +// `absl::bind_front(func, args...)` (C++20 `std::bind_front`) or as a +// compile-time non-type template parameter `absl::bind_front<ConstFn>(args...)` +// (C++26 `std::bind_front`). +// +// Passing `ConstFn` as a non-type template parameter avoids storing a function +// pointer or pointer-to-member at runtime. // // Like `std::bind()`, `absl::bind_front()` is implicitly convertible to // `std::function`. In particular, it may be used as a simpler replacement for @@ -57,7 +81,8 @@ ABSL_NAMESPACE_BEGIN // specified. More importantly, it provides more reliable correctness guarantees // than `std::bind()`; while `std::bind()` will silently ignore passing more // parameters than expected, for example, `absl::bind_front()` will report such -// mis-uses as errors. In C++20, `absl::bind_front` is replaced by +// mis-uses as errors. In C++20 (for runtime callables) and C++26 (for +// non-type template parameter callables), `absl::bind_front` aliases // `std::bind_front`. // // absl::bind_front(a...) can be seen as storing the results of @@ -70,6 +95,8 @@ ABSL_NAMESPACE_BEGIN // assert(absl::bind_front(Minus)(3, 2) == 3 - 2); // assert(absl::bind_front(Minus, 3)(2) == 3 - 2); // assert(absl::bind_front(Minus, 3, 2)() == 3 - 2); +// assert(absl::bind_front<&Minus>()(3, 2) == 3 - 2); +// assert(absl::bind_front<&Minus>(3)(2) == 3 - 2); // // Example: Binding a member function. // @@ -80,8 +107,10 @@ ABSL_NAMESPACE_BEGIN // Math math; // // assert(absl::bind_front(&Math::Double)(&math, 3) == 2 * 3); +// assert(absl::bind_front<&Math::Double>()(&math, 3) == 2 * 3); // // Stores a pointer to math inside the functor. // assert(absl::bind_front(&Math::Double, &math)(3) == 2 * 3); +// assert(absl::bind_front<&Math::Double>(&math)(3) == 2 * 3); // // Stores a copy of math inside the functor. // assert(absl::bind_front(&Math::Double, math)(3) == 2 * 3); // // Stores std::unique_ptr<Math> inside the functor. @@ -193,7 +222,23 @@ constexpr functional_internal::bind_front_t<F, BoundArgs...> bind_front( } #endif // defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L +#ifndef ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT +template <auto ConstFn, class... BoundArgs> +constexpr auto bind_front(BoundArgs&&... args) { + using F = decltype(ConstFn); + if constexpr (std::is_pointer_v<F> || std::is_member_pointer_v<F>) { + static_assert(ConstFn != nullptr, + "bind_front: ConstFn cannot be equal to nullptr"); + } + // The runtime `bind_front` checks the requirements on `BoundArgs`. + return absl::bind_front(functional_internal::ConstFnInvoker<ConstFn>{}, + std::forward<BoundArgs>(args)...); +} +#endif // ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT + ABSL_NAMESPACE_END } // namespace absl +#undef ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT + #endif // ABSL_FUNCTIONAL_BIND_FRONT_H_ diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/bind_front_test.cc b/deps/v8/third_party/abseil-cpp/absl/functional/bind_front_test.cc index 6e87d43c422a..300466c64950 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/bind_front_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/functional/bind_front_test.cc @@ -19,15 +19,17 @@ #include <functional> #include <memory> #include <string> +#include <type_traits> #include <utility> #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/memory/memory.h" namespace { -char CharAt(const char* s, size_t index) { return s[index]; } +constexpr char CharAt(const char* s, size_t index) { return s[index]; } TEST(BindTest, Basics) { EXPECT_EQ('C', absl::bind_front(CharAt)("ABC", 2)); @@ -200,7 +202,7 @@ TEST(BindTest, WrappedMoveOnly) { EXPECT_EQ(42, std::move(f)()); } -int Plus(int a, int b) { return a + b; } +constexpr int Plus(int a, int b) { return a + b; } TEST(BindTest, ConstExpr) { constexpr auto f = absl::bind_front(CharAt); @@ -223,4 +225,224 @@ TEST(BindTest, Mangling) { absl::bind_front(ManglingCall{}, 1, 3.3)("A"); } +struct Math { + constexpr int Add(int a, int b) const noexcept { return base + a + b; } + int base = 10; +}; + +TEST(BindConstFnTest, Basics) { + EXPECT_EQ('C', absl::bind_front<&CharAt>()("ABC", 2)); + EXPECT_EQ('C', absl::bind_front<&CharAt>("ABC")(2)); + EXPECT_EQ('C', absl::bind_front<&CharAt>("ABC", 2)()); +} + +TEST(BindConstFnTest, MemberPointers) { + Math m{10}; + auto bound_ptr = absl::bind_front<&Math::Add>(&m); + EXPECT_EQ(15, bound_ptr(2, 3)); + + auto bound_ptr_and_arg = absl::bind_front<&Math::Add>(&m, 2); + EXPECT_EQ(15, bound_ptr_and_arg(3)); + + auto bound_zero_args = absl::bind_front<&Math::Add>(); + EXPECT_EQ(15, bound_zero_args(&m, 2, 3)); + EXPECT_EQ(15, bound_zero_args(m, 2, 3)); +} + +TEST(BindConstFnTest, StoreByCopyRefAndPointer) { + Struct s = {"hello"}; + auto by_copy = absl::bind_front<&Struct::value>(s); + EXPECT_EQ("hello", by_copy()); + EXPECT_NE(&s.value, &by_copy()); + + NonCopyable nc("hello"); + auto by_ref = absl::bind_front<&GetNonCopyableValue>(std::ref(nc)); + EXPECT_EQ("hello", by_ref()); + EXPECT_EQ(&nc.value, &by_ref()); + + auto by_cref = absl::bind_front<&GetNonCopyableValue>(std::cref(nc)); + EXPECT_EQ("hello", by_cref()); + EXPECT_EQ(&nc.value, &by_cref()); + + auto by_ptr = absl::bind_front<&NonCopyable::value>(&nc); + EXPECT_EQ("hello", by_ptr()); + EXPECT_EQ(&nc.value, &by_ptr()); + nc.value = "goodbye"; + EXPECT_EQ("goodbye", by_ref()); + EXPECT_EQ("goodbye", by_cref()); + EXPECT_EQ("goodbye", by_ptr()); +} + +TEST(BindConstFnTest, MoveOnlyArgsAndResult) { + EXPECT_EQ(42, absl::bind_front<&Sink>()(std::make_unique<int>(42))); + EXPECT_EQ(42, absl::bind_front<&Sink>(std::make_unique<int>(42))()); + EXPECT_THAT(absl::bind_front<&Factory>()(42), ::testing::Pointee(42)); + EXPECT_THAT(absl::bind_front<&Factory>(42)(), ::testing::Pointee(42)); + + FalseCopyable<std::unique_ptr<int>> x; + x.m = std::make_unique<int>(42); + auto f = absl::bind_front<&GetMember>(std::move(x)); + EXPECT_EQ(42, std::move(f)()); +} + +TEST(BindConstFnTest, ConstExpr) { + constexpr auto f = absl::bind_front<&CharAt>(); + EXPECT_EQ(f("ABC", 1), 'B'); + + constexpr auto plus5 = absl::bind_front<&Plus>(5); + EXPECT_EQ(plus5(1), 6); + + constexpr auto plus5_1 = absl::bind_front<&Plus>(5, 1); + EXPECT_EQ(plus5_1(), 6); + + constexpr Math m{10}; + constexpr auto add_m = absl::bind_front<&Math::Add>(m, 2); + EXPECT_EQ(add_m(3), 15); + + // Invoking the results is `constexpr` only where the runtime `bind_front` + // that produces them is `std::bind_front` (C++20). The pre-C++20 fallback's + // call operators and `std::invoke` are not `constexpr`. +#if defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L + static_assert(f("ABC", 1) == 'B'); + static_assert(plus5(1) == 6); + static_assert(plus5_1() == 6); + static_assert(add_m(3) == 15); +#endif // __cpp_lib_bind_front >= 201907L +} + +// The results come from the runtime `bind_front`, which propagates `noexcept` +// where it is `std::bind_front` (C++20). +#if defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L +int NoexceptPlus(int a, int b) noexcept { return a + b; } +int PotentiallyThrowingPlus(int a, int b) { return a + b; } + +TEST(BindConstFnTest, NoexceptPropagation) { + auto noexcept_0 = absl::bind_front<&NoexceptPlus>(); + static_assert(noexcept(noexcept_0(1, 2))); + + auto throwing_0 = absl::bind_front<&PotentiallyThrowingPlus>(); + static_assert(!noexcept(throwing_0(1, 2))); + + Math m{10}; + auto math_0 = absl::bind_front<&Math::Add>(); + static_assert(noexcept(math_0(m, 1, 2))); +} +#endif // __cpp_lib_bind_front >= 201907L + +// Invalid calls must be substitution failures rather than hard errors, so that +// `std::is_invocable` works on the result. +TEST(BindConstFnTest, SfinaeFriendly) { + using PlusBinder = decltype(absl::bind_front<&Plus>()); + static_assert(std::is_invocable_v<PlusBinder, int, int>); + static_assert(!std::is_invocable_v<PlusBinder, std::string, int>); + static_assert(!std::is_invocable_v<PlusBinder, int>); + + using Plus1Binder = decltype(absl::bind_front<&Plus>(1)); + static_assert(std::is_invocable_v<Plus1Binder, int>); + static_assert(!std::is_invocable_v<Plus1Binder, std::string>); +} + +// These tests pass class-type objects as template arguments (P0732R2, +// P1907R1), and `StatelessLambdaNTTP` puts a lambda in a template argument +// (P0315R4, which has no feature-test macro). +// +// We check the language version rather than +// `__cpp_nontype_template_args >= 201911L` because Clang (through at least +// 24) still defines it as 201411L: its P1907R1 support is incomplete, though +// everything used here works. Checking the feature macro would silently skip +// these tests on Clang. If a toolchain claims C++20 but can't compile these +// tests, exclude it here. +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L +TEST(BindConstFnTest, StatelessLambdaNTTP) { + constexpr auto f = absl::bind_front<[](int x, int y) { return x + y; }>(); + EXPECT_EQ(f(2, 3), 5); + + constexpr auto f2 = absl::bind_front<[](int x, int y) { return x + y; }>(2); + EXPECT_EQ(f2(3), 5); +} + +struct Adder { + constexpr int operator()(int x) const& { return base + x; } + // `ConstFn` names a template parameter object, which is a `const` lvalue + // ([temp.param]), so it must never be invoked as an rvalue. + int operator()(int) const&& = delete; + + int base; +}; + +TEST(BindConstFnTest, StatefulObjectNTTP) { + constexpr auto add5 = absl::bind_front<Adder{5}>(); + EXPECT_EQ(add5(1), 6); + + constexpr auto add5_1 = absl::bind_front<Adder{5}>(1); + EXPECT_EQ(add5_1(), 6); +} + +struct DescribeCall { + template <class... Args> + std::string operator()(Args&&...) & { + return "&"; + } + template <class... Args> + std::string operator()(Args&&...) const& { + return "const&"; + } + template <class... Args> + std::string operator()(Args&&...) && { + return "&&"; + } + template <class... Args> + std::string operator()(Args&&...) const&& { + return "const&&"; + } +}; + +// Since `ConstFn` is a `const` lvalue, it is invoked through its `const&` +// overload whatever the value category of the result. Both zero and nonzero +// bound arguments are tested, since the standard library's +// `std::bind_front<ConstFn>` may implement them differently. +TEST(BindConstFnTest, InvokesConstFnAsConstLvalue) { + auto f0 = absl::bind_front<DescribeCall{}>(); + const auto& cf0 = f0; + EXPECT_EQ("const&", f0()); + EXPECT_EQ("const&", cf0()); + EXPECT_EQ("const&", std::move(f0)()); + EXPECT_EQ("const&", std::move(cf0)()); + + auto f1 = absl::bind_front<DescribeCall{}>(1); + const auto& cf1 = f1; + EXPECT_EQ("const&", f1()); + EXPECT_EQ("const&", cf1()); + EXPECT_EQ("const&", std::move(f1)()); + EXPECT_EQ("const&", std::move(cf1)()); +} + +struct DeletedConstLvalueCall { + template <class... Args> + void operator()(Args&&...) &; + template <class... Args> + void operator()(Args&&...) const& = delete; + template <class... Args> + void operator()(Args&&...) &&; + template <class... Args> + void operator()(Args&&...) const&&; +}; + +// If `ConstFn`'s `const&` overload is deleted, the result isn't invocable, +// rather than falling back to another overload. +TEST(BindConstFnTest, NotInvocableIfConstLvalueCallDeleted) { + using F0 = decltype(absl::bind_front<DeletedConstLvalueCall{}>()); + static_assert(!std::is_invocable_v<F0&>); + static_assert(!std::is_invocable_v<const F0&>); + static_assert(!std::is_invocable_v<F0>); + static_assert(!std::is_invocable_v<const F0>); + + using F1 = decltype(absl::bind_front<DeletedConstLvalueCall{}>(1)); + static_assert(!std::is_invocable_v<F1&>); + static_assert(!std::is_invocable_v<const F1&>); + static_assert(!std::is_invocable_v<F1>); + static_assert(!std::is_invocable_v<const F1>); +} +#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L + } // namespace diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/function_type_benchmark.cc b/deps/v8/third_party/abseil-cpp/absl/functional/function_type_benchmark.cc index e4ba3a5ed1ec..cc8b817c7ab8 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/function_type_benchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/functional/function_type_benchmark.cc @@ -40,7 +40,7 @@ struct LargeFunctor { }; template <typename Function, typename... Args> -void ABSL_ATTRIBUTE_NOINLINE CallFunction(Function f, Args&&... args) { +ABSL_ATTRIBUTE_NOINLINE void CallFunction(Function f, Args&&... args) { f(std::forward<Args>(args)...); } diff --git a/deps/v8/third_party/abseil-cpp/absl/functional/internal/front_binder.h b/deps/v8/third_party/abseil-cpp/absl/functional/internal/front_binder.h index fcada9ceca02..33d4fb45b207 100644 --- a/deps/v8/third_party/abseil-cpp/absl/functional/internal/front_binder.h +++ b/deps/v8/third_party/abseil-cpp/absl/functional/internal/front_binder.h @@ -18,6 +18,7 @@ #define ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_ #include <cstddef> +#include <functional> #include <type_traits> #include <utility> @@ -87,6 +88,34 @@ class FrontBinder { template <class F, class... BoundArgs> using bind_front_t = FrontBinder<std::decay_t<F>, std::decay_t<BoundArgs>...>; +// Stateless invoker for the compile-time constant target `ConstFn` of +// `absl::bind_front<ConstFn>(args...)` (C++26 [func.bind.front]). +// +// `operator()` has a trailing `decltype(std::invoke(ConstFn, ...))` return type +// rather than `decltype(auto)` so that an invalid call is a substitution +// failure instead of a hard error. Deducing a `decltype(auto)` return type +// instantiates the body, so merely checking whether a call is valid would fail +// to compile. That would break `std::is_invocable` and overload resolution, +// including among the call operators of a `bind_front` result wrapping the +// invoker: e.g. calling such a result as an rvalue fails if it holds a +// move-only bound argument, because its `const&` overload is also considered. +// +// The return type is `decltype(std::invoke(ConstFn, ...))` rather than +// `std::invoke_result_t<decltype(ConstFn), ...>` because for C++20 class-type +// non-type template parameters, `decltype(ConstFn)` is the unqualified type `F` +// (which `std::invoke_result_t` treats as an rvalue `F&&`), whereas the +// template parameter expression `ConstFn` is a `const F` lvalue as specified by +// [func.bind.front]. +template <auto ConstFn> +struct ConstFnInvoker { + template <class... FreeArgs> + constexpr auto operator()(FreeArgs&&... free_args) const noexcept( + noexcept(std::invoke(ConstFn, std::forward<FreeArgs>(free_args)...))) + -> decltype(std::invoke(ConstFn, std::forward<FreeArgs>(free_args)...)) { + return std::invoke(ConstFn, std::forward<FreeArgs>(free_args)...); + } +}; + } // namespace functional_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel index 5fae4e2a2724..010668d28531 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.bazel @@ -89,6 +89,7 @@ cc_test( ], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, deps = [ ":hash", ":hash_testing", @@ -96,9 +97,8 @@ cc_test( "//absl/base:config", "//absl/container:flat_hash_map", "//absl/container:flat_hash_set", - "//absl/memory", - "//absl/meta:type_traits", "//absl/numeric:bits", + "//absl/strings", "//absl/strings:cord", "//absl/strings:cord_test_helpers", "//absl/strings:string_view", diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.gn index 02ddb5370fda..223e59c6f421 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/hash/BUILD.gn @@ -58,9 +58,8 @@ absl_test("hash_test") { "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/container:flat_hash_map", "//third_party/abseil-cpp/absl/container:flat_hash_set", - "//third_party/abseil-cpp/absl/memory", - "//third_party/abseil-cpp/absl/meta:type_traits", "//third_party/abseil-cpp/absl/numeric:bits", + "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/strings:cord", "//third_party/abseil-cpp/absl/strings:cord_test_helpers", "//third_party/abseil-cpp/absl/strings:string_view", diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/hash/CMakeLists.txt index 0c7e7f43b60e..f8e7afae36da 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/hash/CMakeLists.txt @@ -74,11 +74,12 @@ absl_cc_test( absl::flat_hash_set absl::hash absl::hash_testing - absl::memory - absl::meta absl::spy_hash_state absl::string_view + absl::strings GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/hash.h b/deps/v8/third_party/abseil-cpp/absl/hash/hash.h index bfccf2774f65..126c96f10e29 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/hash.h +++ b/deps/v8/third_party/abseil-cpp/absl/hash/hash.h @@ -326,7 +326,7 @@ using Hash = absl::hash_internal::Hash<T>; // return H::combine(std::move(h), n.first, n.last); // } // friend bool operator==(const Name& a, const Name& b); -// friend bool operator==(const Name& a, const NameView& b); +// operator NameView() const; // // using absl_container_hash = absl::TransparentHash<Name, NameView>; // }; diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/hash_test.cc b/deps/v8/third_party/abseil-cpp/absl/hash/hash_test.cc index 2afa986303c9..28cb10853afb 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/hash_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/hash/hash_test.cc @@ -25,6 +25,7 @@ #include <initializer_list> #include <ios> #include <limits> +#include <map> #include <memory> #include <optional> #include <ostream> @@ -50,6 +51,7 @@ #include "absl/numeric/bits.h" #include "absl/strings/cord.h" #include "absl/strings/cord_test_helpers.h" +#include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #ifdef ABSL_INTERNAL_STD_FILESYSTEM_PATH_HASH_AVAILABLE @@ -1267,23 +1269,27 @@ TEST(PrecombineLengthMix, ShortStringCollision) { #if defined(__ANDROID__) && defined(__arm__) GTEST_SKIP() << "Fails on 32-bit Android due to layout changes."; #endif - std::string s1 = "00"; - std::string s2 = "000"; constexpr char kMinChar = 0; - constexpr char kMaxChar = 32; - for (s1[0] = kMinChar; s1[0] < kMaxChar; ++s1[0]) { - for (s1[1] = kMinChar; s1[1] < kMaxChar; ++s1[1]) { - for (s2[0] = kMinChar; s2[0] < kMaxChar; ++s2[0]) { - for (s2[1] = kMinChar; s2[1] < kMaxChar; ++s2[1]) { - for (s2[2] = kMinChar; s2[2] < kMaxChar; ++s2[2]) { - ASSERT_NE(absl::HashOf(s1), absl::HashOf(s2)) - << "s1[0]: " << static_cast<int>(s1[0]) - << "; s1[1]: " << static_cast<int>(s1[1]) - << "; s2[0]: " << static_cast<int>(s2[0]) - << "; s2[1]: " << static_cast<int>(s2[1]) - << "; s2[2]: " << static_cast<int>(s2[2]); - } - } + constexpr char kMaxChar = sizeof(size_t) * 4; + // We use standard map to avoid the second dependency on the same hash. + std::map<size_t, std::string> hashes; + { + std::string s1 = "00"; + for (s1[0] = kMinChar; s1[0] < kMaxChar; ++s1[0]) { + for (s1[1] = kMinChar; s1[1] < kMaxChar; ++s1[1]) { + auto [it, inserted] = hashes.insert({absl::HashOf(s1), s1}); + ASSERT_TRUE(inserted) << "Collision found for " << absl::CEscape(s1) + << " and " << absl::CEscape(it->second); + } + } + } + std::string s2 = "000"; + for (s2[0] = kMinChar; s2[0] < kMaxChar; ++s2[0]) { + for (s2[1] = kMinChar; s2[1] < kMaxChar; ++s2[1]) { + for (s2[2] = kMinChar; s2[2] < kMaxChar; ++s2[2]) { + auto [it, inserted] = hashes.insert({absl::HashOf(s2), s2}); + ASSERT_TRUE(inserted) << "Collision found for " << absl::CEscape(s2) + << " and " << absl::CEscape(it->second); } } } @@ -1352,36 +1358,32 @@ TEST(SwisstableCollisions, LowEntropyInts) { } struct NameView { - absl::string_view name; - absl::string_view lang; + absl::string_view first; + absl::string_view last; friend bool operator==(const NameView& lhs, const NameView& rhs) { - return lhs.name == rhs.name && lhs.lang == rhs.lang; + return lhs.first == rhs.first && lhs.last == rhs.last; } template <typename H> friend H AbslHashValue(H h, const NameView& name) { - return H::combine(std::move(h), name.name, name.lang); + return H::combine(std::move(h), name.first, name.last); } }; struct Name { - std::string name; - std::string lang; + std::string first; + std::string last; friend bool operator==(const Name& lhs, const Name& rhs) { - return lhs.name == rhs.name && lhs.lang == rhs.lang; - } - friend bool operator==(const NameView& lhs, const Name& rhs) { - return lhs.name == rhs.name && lhs.lang == rhs.lang; - } - friend bool operator==(const Name& lhs, const NameView& rhs) { - return lhs.name == rhs.name && lhs.lang == rhs.lang; + return lhs.first == rhs.first && lhs.last == rhs.last; } + operator NameView() const { return NameView{first, last}; } // NOLINT + template <typename H> friend H AbslHashValue(H h, const Name& name) { - return H::combine(std::move(h), name.name, name.lang); + return H::combine(std::move(h), name.first, name.last); } using absl_container_hash = absl::TransparentHash<NameView, Name>; @@ -1406,29 +1408,29 @@ TYPED_TEST(TransparentHashTest, BasicUsage) { EXPECT_FALSE((std::is_convertible_v<NameHash, absl::Hash<Name>>)); EXPECT_FALSE((std::is_convertible_v<NameHash, absl::Hash<NameView>>)); - EXPECT_EQ(NameHash{}(Name{"foo", "en"}), NameHash{}(NameView{"foo", "en"})); + EXPECT_EQ(NameHash{}(Name{"John", "Doe"}), + NameHash{}(NameView{"John", "Doe"})); - EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( - std::make_tuple(Name{"foo", "en"}, NameView{"foo", "en"}, - Name{"bar", "en"}, NameView{"bar", "en"}, - Name{"foo", "de"}, NameView{"foo", "de"}, - Name{"bar", "de"}, NameView{"bar", "de"}))); + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( + Name{"John", "Doe"}, NameView{"John", "Doe"}, Name{"Jack", "Doe"}, + NameView{"Jack", "Doe"}, Name{"John", "Smith"}, NameView{"John", "Smith"}, + Name{"Jack", "Smith"}, NameView{"Jack", "Smith"}))); absl::flat_hash_set<Name, NameHash, std::equal_to<>> set; - set.insert(Name{"foo", "en"}); - EXPECT_TRUE(set.contains(NameView{"foo", "en"})); - EXPECT_TRUE(set.contains(Name{"foo", "en"})); + set.insert(Name{"John", "Doe"}); + EXPECT_TRUE(set.contains(NameView{"John", "Doe"})); + EXPECT_TRUE(set.contains(Name{"John", "Doe"})); std::unordered_set<Name, NameHash, std::equal_to<>> std_set; - std_set.insert(Name{"foo", "en"}); - EXPECT_TRUE(std_set.find(Name{"foo", "en"}) != std_set.end()); + std_set.insert(Name{"John", "Doe"}); + EXPECT_TRUE(std_set.find(Name{"John", "Doe"}) != std_set.end()); } TEST(HashTest, TransparentHashDefaultLookUp) { absl::flat_hash_set<Name> set; - set.insert(Name{"foo", "en"}); - EXPECT_TRUE(set.contains(NameView{"foo", "en"})); - EXPECT_TRUE(set.contains(Name{"foo", "en"})); + set.insert(Name{"John", "Doe"}); + EXPECT_TRUE(set.contains(NameView{"John", "Doe"})); + EXPECT_TRUE(set.contains(Name{"John", "Doe"})); } struct MyString { diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.cc b/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.cc index 43cb561b954b..df75c256c185 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.cc +++ b/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.cc @@ -235,21 +235,28 @@ LowLevelHashLenGt64(uint64_t seed, const void* data, size_t len) { // We combine state and data with _mm_add_epi64/_mm_sub_epi64 before applying // AES encryption to make hash function dependent on the order of the blocks. // See comments in LowLevelHash33To64 for more considerations. - auto mix_ab = [&state0, - &state1](const uint8_t* p) ABSL_ATTRIBUTE_ALWAYS_INLINE { - Vector128 a = Load128(p); - Vector128 b = Load128(p + 16); - state0 = MixA(a, state0); - state1 = MixB(b, state1); + struct MixerAB { + Vector128& state0; + Vector128& state1; + ABSL_ATTRIBUTE_ALWAYS_INLINE auto operator()(const uint8_t* p) const { + Vector128 a = Load128(p); + Vector128 b = Load128(p + 16); + state0 = MixA(a, state0); + state1 = MixB(b, state1); + } }; - auto mix_cd = [&state2, - &state3](const uint8_t* p) ABSL_ATTRIBUTE_ALWAYS_INLINE { - Vector128 c = Load128(p); - Vector128 d = Load128(p + 16); - state2 = MixC(c, state2); - state3 = MixD(d, state3); + MixerAB mix_ab = {state0, state1}; + struct MixerCD { + Vector128& state2; + Vector128& state3; + ABSL_ATTRIBUTE_ALWAYS_INLINE auto operator()(const uint8_t* p) const { + Vector128 c = Load128(p); + Vector128 d = Load128(p + 16); + state2 = MixC(c, state2); + state3 = MixD(d, state3); + } }; - + MixerCD mix_cd = {state2, state3}; do { PrefetchFutureDataToLocalCache(ptr); mix_ab(ptr); diff --git a/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.h b/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.h index 590bf7f033c8..025e57caad0d 100644 --- a/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.h +++ b/deps/v8/third_party/abseil-cpp/absl/hash/internal/hash.h @@ -335,8 +335,9 @@ class HashStateBase { }; }; -// `is_uniquely_represented<T>` is a trait class that indicates whether `T` -// is uniquely represented. +// `is_uniquely_represented` is like `std::has_unique_object_representations`, +// but with a few differences for legacy reasons that predate cl/989071457, such +// as disallowing pointers or Booleans. // // A type is "uniquely represented" if two equal values of that type are // guaranteed to have the same bytes in their underlying storage. In other @@ -367,24 +368,11 @@ class HashStateBase { // The Enable parameter is meaningless; it is provided as a convenience, // to support certain SFINAE techniques when defining specializations. template <typename T, typename Enable = void> -struct is_uniquely_represented : std::false_type {}; - -// unsigned char is a synonym for "byte", so it is guaranteed to be -// uniquely represented. -template <> -struct is_uniquely_represented<unsigned char> : std::true_type {}; - -// is_uniquely_represented for non-standard integral types -// -// Integral types other than bool should be uniquely represented on any -// platform that this will plausibly be ported to. -template <typename Integral> -struct is_uniquely_represented<Integral, - std::enable_if_t<std::is_integral_v<Integral>>> - : std::true_type {}; - -template <> -struct is_uniquely_represented<bool> : std::false_type {}; +struct is_uniquely_represented + : std::conditional_t<(std::is_integral_v<T> && !std::is_same_v<bool, T>) || + std::is_enum_v<T>, + std::has_unique_object_representations<T>, + std::false_type> {}; #ifdef ABSL_HAVE_INTRINSIC_INT128 // Specialize the trait for GNU extension types. @@ -395,7 +383,11 @@ struct is_uniquely_represented<unsigned __int128> : std::true_type {}; #endif // ABSL_HAVE_INTRINSIC_INT128 template <typename T> -struct FitsIn64Bits : std::bool_constant<sizeof(T) <= 8> {}; +using FitsIn64Bits = + std::bool_constant<sizeof(T) <= sizeof(uint64_t) && + // Check that sizeof(T) is a power of 2, since unaligned + // operations require it. + (sizeof(T) & (sizeof(T) - 1)) == 0>; struct CombineRaw { template <typename H> @@ -1332,6 +1324,26 @@ inline uint64_t CombineContiguousImpl( #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0 #endif +template <typename T, typename... Args> +using InvokeResultOrVoid = + typename std::conditional_t<std::is_invocable_v<T, Args...>, + std::invoke_result<T, Args...>, + std::enable_if<true>>::type; + +template <typename State, typename T, typename = void> +struct AbslHashValueResultOrVoid { + using type = void; +}; + +template <typename State, typename T> +struct AbslHashValueResultOrVoid< + State, T, + std::void_t<decltype(AbslHashValue(std::declval<State>(), + std::declval<T&>()))>> { + using type = + decltype(AbslHashValue(std::declval<State>(), std::declval<T&>())); +}; + // Type trait to select the appropriate hash implementation to use. // HashSelect::type<T> will give the proper hash implementation, to be invoked // as: @@ -1341,13 +1353,6 @@ inline uint64_t CombineContiguousImpl( // `false`. struct HashSelect { private: - struct WeaklyMixedIntegerProbe { - template <typename H> - static H Invoke(H state, WeaklyMixedInteger value) { - return hash_internal::hash_weakly_mixed_integer(std::move(state), value); - } - }; - struct State : HashStateBase<State> { static State combine_contiguous(State hash_state, const unsigned char*, size_t); @@ -1357,19 +1362,23 @@ struct HashSelect { WeaklyMixedInteger value); }; + struct WeaklyMixedIntegerProbe { + template <typename H> + static H Invoke(H state, WeaklyMixedInteger value) { + return hash_internal::hash_weakly_mixed_integer(std::move(state), value); + } + }; + struct UniquelyRepresentedProbe { template <typename H, typename T> - static auto Invoke(H state, const T& value) - -> std::enable_if_t<is_uniquely_represented<T>::value, H> { + static H Invoke(H state, const T& value) { return hash_internal::hash_bytes(std::move(state), value); } }; struct HashValueProbe { template <typename H, typename T> - static auto Invoke(H state, const T& value) -> std::enable_if_t< - std::is_same_v<H, decltype(AbslHashValue(std::move(state), value))>, - H> { + static H Invoke(H state, const T& value) { return AbslHashValue(std::move(state), value); } }; @@ -1377,11 +1386,7 @@ struct HashSelect { struct LegacyHashProbe { #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ template <typename H, typename T> - static auto Invoke(H state, const T& value) -> std::enable_if_t< - std::is_convertible_v< - decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>()(value)), - size_t>, - H> { + static H Invoke(H state, const T& value) { return hash_internal::hash_bytes( std::move(state), ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value)); @@ -1391,41 +1396,39 @@ struct HashSelect { struct StdHashProbe { template <typename H, typename T> - static auto Invoke(H state, const T& value) - -> std::enable_if_t<type_traits_internal::IsHashable<T>::value, H> { + static H Invoke(H state, const T& value) { return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value)); } }; - template <typename Hash, typename T> - struct Probe : Hash { - private: - template <typename H, typename = decltype(H::Invoke( - std::declval<State>(), std::declval<const T&>()))> - static std::true_type Test(int); - template <typename U> - static std::false_type Test(char); - - public: - static constexpr bool value = decltype(Test<Hash>(0))::value; - }; - public: - // Probe each implementation in order. - // disjunction provides short circuiting wrt instantiation. template <typename T> - using Apply = std::disjunction< // - Probe<WeaklyMixedIntegerProbe, T>, // - Probe<UniquelyRepresentedProbe, T>, // - Probe<HashValueProbe, T>, // - Probe<LegacyHashProbe, T>, // - Probe<StdHashProbe, T>, // - std::false_type>; + static auto Apply() { + if constexpr (std::is_same_v<T, WeaklyMixedInteger>) { + return WeaklyMixedIntegerProbe(); + } else if constexpr (is_uniquely_represented<T>::value) { + return UniquelyRepresentedProbe(); + } else if constexpr (std::is_same_v<State, + typename AbslHashValueResultOrVoid< + State, const T&>::type>) { + return HashValueProbe(); +#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ + } else if constexpr (std::is_convertible_v< + InvokeResultOrVoid< + ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>, + const T&>, + size_t>) { + return LegacyHashProbe(); +#endif + } else if constexpr (type_traits_internal::IsHashable<T>::value) { + return StdHashProbe(); + } + } }; template <typename T> -struct is_hashable : std::bool_constant<HashSelect::template Apply<T>::value> { -}; +struct is_hashable + : std::is_class<decltype(HashSelect::Apply<absl::remove_cvref_t<T>>())> {}; class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> { template <typename T> @@ -1461,8 +1464,12 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> { // The result should be the same as running the whole algorithm, but faster. template <typename T, std::enable_if_t<IntegralFastPath<T>::value, int> = 0> static size_t hash_with_seed(T value, size_t seed) { - return static_cast<size_t>( - CombineRawImpl(seed, static_cast<std::make_unsigned_t<T>>(value))); + return static_cast<size_t>(CombineRawImpl( + seed, + static_cast<typename std::conditional_t< + std::is_signed_v<T>, std::make_unsigned<T>, + // Special case for `bool`, which `make_unsigned` does not support. + type_identity<T>>::type>(value))); } template <typename T, std::enable_if_t<!IntegralFastPath<T>::value, int> = 0> @@ -1646,7 +1653,7 @@ class TransparentHash : private TransparentHashBase<Ts...> { template <typename H> template <typename T, typename... Ts> H HashStateBase<H>::combine(H state, const T& value, const Ts&... values) { - return H::combine(hash_internal::HashSelect::template Apply<T>::Invoke( + return H::combine(decltype(hash_internal::HashSelect::Apply<T>())::Invoke( std::move(state), value), values...); } diff --git a/deps/v8/third_party/abseil-cpp/absl/log/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/log/BUILD.bazel index 2c0a8ffef4d0..3e15e0be3e28 100644 --- a/deps/v8/third_party/abseil-cpp/absl/log/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/log/BUILD.bazel @@ -315,6 +315,7 @@ cc_test( srcs = ["absl_check_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, tags = [ "no_test:os:ios", "no_test_ios", @@ -350,6 +351,7 @@ cc_test( srcs = ["check_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, tags = [ "no_test:os:ios", "no_test_ios", diff --git a/deps/v8/third_party/abseil-cpp/absl/log/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/log/CMakeLists.txt index ebc24f3bbf3b..1da38e4f39aa 100644 --- a/deps/v8/third_party/abseil-cpp/absl/log/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/log/CMakeLists.txt @@ -838,6 +838,8 @@ absl_cc_test( absl::string_view absl::strings GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( @@ -883,6 +885,8 @@ absl_cc_test( absl::string_view absl::strings GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/log/check_test_impl.inc b/deps/v8/third_party/abseil-cpp/absl/log/check_test_impl.inc index c78bbd412a72..9ec35065bcd6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/log/check_test_impl.inc +++ b/deps/v8/third_party/abseil-cpp/absl/log/check_test_impl.inc @@ -48,7 +48,7 @@ using ::testing::ContainsRegex; using ::testing::HasSubstr; using ::testing::Not; -auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment( +auto* test_env [[maybe_unused]] = ::testing::AddGlobalTestEnvironment( new absl::log_internal::LogTestEnvironment); #if GTEST_HAS_DEATH_TEST diff --git a/deps/v8/third_party/abseil-cpp/absl/log/internal/check_op.h b/deps/v8/third_party/abseil-cpp/absl/log/internal/check_op.h index 66050f0a69e9..69f0c3b9a31b 100644 --- a/deps/v8/third_party/abseil-cpp/absl/log/internal/check_op.h +++ b/deps/v8/third_party/abseil-cpp/absl/log/internal/check_op.h @@ -425,8 +425,8 @@ using CheckOpStreamType = // Build the error message string. Specify no inlining for code size. template <typename T1, typename T2> -ABSL_ATTRIBUTE_RETURNS_NONNULL const char* absl_nonnull MakeCheckOpString( - T1 v1, T2 v2, const char* absl_nonnull exprtext) ABSL_ATTRIBUTE_NOINLINE; +ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_RETURNS_NONNULL const char* absl_nonnull +MakeCheckOpString(T1 v1, T2 v2, const char* absl_nonnull exprtext); template <typename T1, typename T2> const char* absl_nonnull MakeCheckOpString(T1 v1, T2 v2, @@ -485,8 +485,9 @@ ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void* absl_nonnull); // type. #define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \ template <typename T1, typename T2> \ - inline constexpr const char* absl_nullable name##Impl( \ - const T1& v1, const T2& v2, const char* absl_nonnull exprtext) { \ + ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr const char* absl_nullable \ + name##Impl(const T1& v1, const T2& v2, \ + const char* absl_nonnull exprtext) { \ using U1 = CheckOpStreamType<T1, T2>; \ using U2 = CheckOpStreamType<T2, T1>; \ return ABSL_PREDICT_TRUE(v1 op v2) \ @@ -494,8 +495,8 @@ ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void* absl_nonnull); : ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \ U2(v2), exprtext); \ } \ - inline constexpr const char* absl_nullable name##Impl( \ - int v1, int v2, const char* absl_nonnull exprtext) { \ + ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr const char* absl_nullable \ + name##Impl(int v1, int v2, const char* absl_nonnull exprtext) { \ return name##Impl<int, int>(v1, v2, exprtext); \ } diff --git a/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.cc b/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.cc index 4e5da95a0aa0..e56ef25919fc 100644 --- a/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.cc +++ b/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.cc @@ -605,7 +605,8 @@ void LogMessage::LogBacktraceIfNeeded() { // `str_type`. Truncates `str` if necessary, but emits nothing and marks the // buffer full if even the field headers do not fit. template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBuffer(absl::string_view str) { +ABSL_ATTRIBUTE_NOINLINE void LogMessage::CopyToEncodedBuffer( + absl::string_view str) { auto encoded_remaining_copy = data_->encoded_remaining(); constexpr uint8_t tag_value = str_type == StringType::kLiteral ? ValueTag::kStringLiteral @@ -632,7 +633,8 @@ template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>( template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(absl::string_view str); template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBuffer(char ch, size_t num) { +ABSL_ATTRIBUTE_NOINLINE void LogMessage::CopyToEncodedBuffer(char ch, + size_t num) { auto encoded_remaining_copy = data_->encoded_remaining(); constexpr uint8_t tag_value = str_type == StringType::kLiteral ? ValueTag::kStringLiteral @@ -660,7 +662,8 @@ template void LogMessage::CopyToEncodedBuffer< LogMessage::StringType::kNotLiteral>(char ch, size_t num); template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBuffer(std::wstring_view str) { +ABSL_ATTRIBUTE_NOINLINE void LogMessage::CopyToEncodedBuffer( + std::wstring_view str) { auto encoded_remaining_copy = data_->encoded_remaining(); constexpr uint8_t tag_value = str_type == StringType::kLiteral ? ValueTag::kStringLiteral @@ -698,7 +701,8 @@ template void LogMessage::CopyToEncodedBufferWithStructuredProtoField< absl::string_view str); template <LogMessage::StringType str_type> -void LogMessage::CopyToEncodedBufferWithStructuredProtoField( +ABSL_ATTRIBUTE_NOINLINE void +LogMessage::CopyToEncodedBufferWithStructuredProtoField( StructuredProtoField field, absl::string_view str) { auto encoded_remaining_copy = data_->encoded_remaining(); size_t encoded_field_size = BufferSizeForStructuredProtoField(field); diff --git a/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.h b/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.h index b9b533ea5b15..cd12833d18f1 100644 --- a/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.h +++ b/deps/v8/third_party/abseil-cpp/absl/log/internal/log_message.h @@ -68,22 +68,22 @@ class LogMessage { // Used for `LOG`. Taking `const char *` instead of `string_view` keeps // callsites a little bit smaller at the cost of doing `strlen` at runtime. - LogMessage(const char* absl_nonnull file, int line, - absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD LogMessage(const char* absl_nonnull file, int line, + absl::LogSeverity severity); // Used for FFI integrations that don't have a NUL-terminated string. - LogMessage(absl::string_view file, int line, - absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD LogMessage(absl::string_view file, int line, + absl::LogSeverity severity); // These constructors are slightly smaller/faster to call; the severity is // curried into the function pointer. - LogMessage(const char* absl_nonnull file, int line, - InfoTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE; - LogMessage(const char* absl_nonnull file, int line, - WarningTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE; - LogMessage(const char* absl_nonnull file, int line, - ErrorTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE + LogMessage(const char* absl_nonnull file, int line, InfoTag); + ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE + LogMessage(const char* absl_nonnull file, int line, WarningTag); + ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE + LogMessage(const char* absl_nonnull file, int line, ErrorTag); LogMessage(const LogMessage&) = delete; LogMessage& operator=(const LogMessage&) = delete; - ~LogMessage() ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD ~LogMessage(); // Overrides the location inferred from the callsite. The string pointed to // by `file` must be valid until the end of the statement. @@ -209,14 +209,14 @@ class LogMessage { // This prevents non-const `char[]` arrays from looking like literals. template <int SIZE> - LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_NOINLINE LogMessage& operator<<(char (&buf)[SIZE]); // `wchar_t[SIZE]` is handled by `operator<< <const wchar_t*>`. // Types that support `AbslStringify()` are serialized that way. // Types that don't support `AbslStringify()` but do support streaming into a // `std::ostream&` are serialized that way. template <typename T> - LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE; + ABSL_ATTRIBUTE_NOINLINE LogMessage& operator<<(const T& v); // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s. void Flush(); @@ -271,18 +271,17 @@ class LogMessage { kNotLiteral, }; template <StringType str_type> - void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(absl::string_view str); template <StringType str_type> - void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(char ch, size_t num); template <StringType str_type> - void CopyToEncodedBuffer(std::wstring_view str) ABSL_ATTRIBUTE_NOINLINE; + void CopyToEncodedBuffer(std::wstring_view str); // Copies `field` to the encoded buffer, then appends `str` after it // (truncating `str` if necessary to fit). template <StringType str_type> void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field, - absl::string_view str) - ABSL_ATTRIBUTE_NOINLINE; + absl::string_view str); // Returns `true` if the message is fatal or enabled debug-fatal. bool IsFatal() const; @@ -422,9 +421,9 @@ extern template void LogMessage::CopyToEncodedBuffer< // message. class LogMessageFatal final : public LogMessage { public: - LogMessageFatal(const char* absl_nonnull file, int line) ABSL_ATTRIBUTE_COLD; - LogMessageFatal(const char* absl_nonnull file, int line, - const char* absl_nonnull failure_msg) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD LogMessageFatal(const char* absl_nonnull file, int line); + ABSL_ATTRIBUTE_COLD LogMessageFatal(const char* absl_nonnull file, int line, + const char* absl_nonnull failure_msg); [[noreturn]] ~LogMessageFatal(); }; @@ -433,8 +432,8 @@ class LogMessageFatal final : public LogMessage { // for DLOG(FATAL) variants. class LogMessageDebugFatal final : public LogMessage { public: - LogMessageDebugFatal(const char* absl_nonnull file, - int line) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD LogMessageDebugFatal(const char* absl_nonnull file, + int line); ~LogMessageDebugFatal(); }; @@ -443,19 +442,19 @@ class LogMessageQuietlyDebugFatal final : public LogMessage { // DLOG(QFATAL) calls this instead of LogMessageQuietlyFatal to make sure the // destructor is not [[noreturn]] even if this is always FATAL as this is only // invoked when DLOG() is enabled. - LogMessageQuietlyDebugFatal(const char* absl_nonnull file, - int line) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD LogMessageQuietlyDebugFatal(const char* absl_nonnull file, + int line); ~LogMessageQuietlyDebugFatal(); }; // Used for LOG(QFATAL) to make sure it's properly understood as [[noreturn]]. class LogMessageQuietlyFatal final : public LogMessage { public: - LogMessageQuietlyFatal(const char* absl_nonnull file, - int line) ABSL_ATTRIBUTE_COLD; - LogMessageQuietlyFatal(const char* absl_nonnull file, int line, - const char* absl_nonnull failure_msg) - ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD LogMessageQuietlyFatal(const char* absl_nonnull file, + int line); + ABSL_ATTRIBUTE_COLD LogMessageQuietlyFatal( + const char* absl_nonnull file, int line, + const char* absl_nonnull failure_msg); [[noreturn]] ~LogMessageQuietlyFatal(); }; diff --git a/deps/v8/third_party/abseil-cpp/absl/numeric/int128.cc b/deps/v8/third_party/abseil-cpp/absl/numeric/int128.cc index a58b772f068a..54e2a8c7545f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/numeric/int128.cc +++ b/deps/v8/third_party/abseil-cpp/absl/numeric/int128.cc @@ -42,7 +42,7 @@ namespace { // For example: // Given: 5 (decimal) == 101 (binary) // Returns: 2 -inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Fls128(uint128 n) { if (uint64_t hi = Uint128High64(n)) { ABSL_ASSUME(hi != 0); return 127 - countl_zero(hi); diff --git a/deps/v8/third_party/abseil-cpp/absl/profiling/internal/sample_recorder.h b/deps/v8/third_party/abseil-cpp/absl/profiling/internal/sample_recorder.h index 0d14027957eb..8663d6c49a10 100644 --- a/deps/v8/third_party/abseil-cpp/absl/profiling/internal/sample_recorder.h +++ b/deps/v8/third_party/abseil-cpp/absl/profiling/internal/sample_recorder.h @@ -169,23 +169,29 @@ void SampleRecorder<T>::PushDead(T* sample) { template <typename T> template <typename... Targs> T* SampleRecorder<T>::PopDead(Targs... args) { - absl::ReleasableMutexLock graveyard_lock(graveyard_.init_mu); - - // The list is circular, so eventually it collapses down to - // graveyard_.dead == &graveyard_ - // when it is empty. - T* sample = graveyard_.dead; - if (sample == &graveyard_) return nullptr; - + T* sample; + { + absl::MutexLock graveyard_lock(graveyard_.init_mu); + + // The list is circular, so eventually it collapses down to + // graveyard_.dead == &graveyard_ + // when it is empty. + sample = graveyard_.dead; + if (sample == &graveyard_) return nullptr; + + graveyard_.dead = ABSL_TS_UNCHECKED_READ(sample->dead); + // Release the global graveyard lock early, before the potentially slow + // preparation. + } + // `sample` is detached from the graveyard and will not be used in PopDead. + // SampleRecorder<T>::Iterate will acquire per sample lock, so there will be + // no data race either. absl::MutexLock sample_lock(sample->init_mu); - graveyard_.dead = sample->dead; - // Release the global graveyard lock early, before the potentially slow - // preparation. - graveyard_lock.Release(); - // Prepare the sample while still holding the per-sample lock. - // `Iterate` will wait for the lock to be released. - sample->dead = nullptr; + // Note: consider PrepareForSampling out of the lock. + // Currently many clients have PrepareForSampling marked as + // ABSL_EXCLUSIVE_LOCKS_REQUIRED. sample->PrepareForSampling(std::forward<Targs>(args)...); + sample->dead = nullptr; return sample; } diff --git a/deps/v8/third_party/abseil-cpp/absl/random/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/random/BUILD.bazel index edc4e9393a72..d63f8f3fa0cc 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/random/BUILD.bazel @@ -199,6 +199,7 @@ cc_test( srcs = ["bernoulli_distribution_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, deps = [ ":distributions", ":random", @@ -217,6 +218,7 @@ cc_test( copts = ABSL_TEST_COPTS, flaky = 1, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, tags = [ "no_test_wasm", ], @@ -326,6 +328,7 @@ cc_test( ], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, tags = [ # Too Slow. "no_test_android_arm", diff --git a/deps/v8/third_party/abseil-cpp/absl/random/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/random/CMakeLists.txt index 914ba0fcf1be..f9d2d601ed62 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/random/CMakeLists.txt @@ -272,6 +272,8 @@ absl_cc_test( absl::random_random GTest::gmock GTest::gtest_main + SHARD_COUNT + 4 ) absl_cc_test( @@ -295,6 +297,8 @@ absl_cc_test( absl::strings GTest::gmock GTest::gtest_main + SHARD_COUNT + 4 ) absl_cc_test( @@ -398,6 +402,8 @@ absl_cc_test( absl::strings GTest::gmock GTest::gtest_main + SHARD_COUNT + 4 ) absl_cc_test( @@ -873,6 +879,7 @@ absl_cc_library( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config + absl::core_headers absl::random_internal_platform absl::random_internal_randen_hwaes_impl ) diff --git a/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.bazel index efd013e65c26..04f9a27c2b61 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.bazel @@ -189,6 +189,7 @@ cc_library( "@rules_cc//cc/compiler:msvc-cl": [], "@rules_cc//cc/compiler:clang-cl": [], "@rules_cc//cc/compiler:emscripten": [], + "@platforms//os:wasi": [], "//conditions:default": ["-pthread"], }) + ABSL_DEFAULT_LINKOPTS, deps = [ @@ -430,6 +431,7 @@ cc_library( deps = [ ":platform", "//absl/base:config", + "//absl/base:core_headers", "//absl/numeric:int128", ], ) diff --git a/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.gn index 4985844d9e9d..bddf849e2131 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/random/internal/BUILD.gn @@ -298,6 +298,7 @@ absl_source_set("randen_hwaes_impl") { deps = [ ":platform", "//third_party/abseil-cpp/absl/base:config", + "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/numeric:int128", ] } diff --git a/deps/v8/third_party/abseil-cpp/absl/random/internal/nanobenchmark.cc b/deps/v8/third_party/abseil-cpp/absl/random/internal/nanobenchmark.cc index 0cf657b4851d..08e7f15f05b4 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/internal/nanobenchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/random/internal/nanobenchmark.cc @@ -61,15 +61,6 @@ #include <time.h> // NOLINT #endif -// ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE prevents inlining of the method. -#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE __attribute__((noinline)) -#elif defined(_MSC_VER) -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE __declspec(noinline) -#else -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE -#endif - namespace absl { ABSL_NAMESPACE_BEGIN namespace random_internal_nanobenchmark { @@ -670,8 +661,8 @@ Ticks TotalDuration(const Func func, const void* arg, const InputVec* inputs, } // (Nearly) empty Func for measuring timer overhead/resolution. -ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE FuncOutput -EmptyFunc(const void* arg, const FuncInput input) { +ABSL_ATTRIBUTE_NOINLINE FuncOutput EmptyFunc(const void* arg [[maybe_unused]], + const FuncInput input) { return input; } diff --git a/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_detect.cc b/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_detect.cc index 83bde75f3c8c..888e36fe76db 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_detect.cc +++ b/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_detect.cc @@ -243,8 +243,8 @@ bool CPUSupportsRandenHwAes() { // * Rely on compiler-generated target-based dispatch. // Using x86/gcc it might look something like this: // - // int __attribute__((target("aes"))) HasAes() { return 1; } - // int __attribute__((target("default"))) HasAes() { return 0; } + // __attribute__((target("aes"))) int HasAes() { return 1; } + // __attribute__((target("default"))) int HasAes() { return 0; } // // This does not work on all architecture/compiler combinations. // diff --git a/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_hwaes.cc b/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_hwaes.cc index f8dd358c8f6e..b632aa9a1aaf 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_hwaes.cc +++ b/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_hwaes.cc @@ -21,6 +21,7 @@ #include <cstring> +#include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/numeric/int128.h" #include "absl/random/internal/platform.h" @@ -97,9 +98,17 @@ using absl::random_internal::RandenTraits; // NOTE: Evaluate whether we should eliminate ABSL_TARGET_CRYPTO. #if (defined(__clang__) || defined(__GNUC__)) #if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32) +#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::target) +#define ABSL_TARGET_CRYPTO [[gnu::target("aes")]] +#else #define ABSL_TARGET_CRYPTO __attribute__((target("aes"))) +#endif #elif defined(ABSL_ARCH_PPC) +#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::target) +#define ABSL_TARGET_CRYPTO [[gnu::target("crypto")]] +#else #define ABSL_TARGET_CRYPTO __attribute__((target("crypto"))) +#endif #else #define ABSL_TARGET_CRYPTO #endif @@ -125,7 +134,7 @@ using absl::random_internal::RandenTraits; using Vector128 = __vector unsigned long long; // NOLINT(runtime/int) namespace { -inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) { +ABSL_TARGET_CRYPTO inline Vector128 ReverseBytes(const Vector128& v) { // Reverses the bytes of the vector. const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; @@ -135,23 +144,23 @@ inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) { // WARNING: these load/store in native byte order. It is OK to load and then // store an unchanged vector, but interpreting the bits as a number or input // to AES will have undefined results. -inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { +ABSL_TARGET_CRYPTO inline Vector128 Vector128Load(const void* from) { return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from)); } -inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { +ABSL_TARGET_CRYPTO inline void Vector128Store(const Vector128& v, void* to) { vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to)); } // One round of AES. "round_key" is a public constant for breaking the // symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, +ABSL_TARGET_CRYPTO inline Vector128 AesRound(const Vector128& state, const Vector128& round_key) { return Vector128(__builtin_crypto_vcipher(state, round_key)); } // Enables native loads in the round loop by pre-swapping. -inline ABSL_TARGET_CRYPTO void SwapEndian(absl::uint128* state) { +ABSL_TARGET_CRYPTO inline void SwapEndian(absl::uint128* state) { for (uint32_t block = 0; block < RandenTraits::kFeistelBlocks; ++block) { Vector128Store(ReverseBytes(Vector128Load(state + block)), state + block); } @@ -182,17 +191,17 @@ using Vector128 = uint8x16_t; namespace { -inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { +ABSL_TARGET_CRYPTO inline Vector128 Vector128Load(const void* from) { return vld1q_u8(reinterpret_cast<const uint8_t*>(from)); } -inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { +ABSL_TARGET_CRYPTO inline void Vector128Store(const Vector128& v, void* to) { vst1q_u8(reinterpret_cast<uint8_t*>(to), v); } // One round of AES. "round_key" is a public constant for breaking the // symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, +ABSL_TARGET_CRYPTO inline Vector128 AesRound(const Vector128& state, const Vector128& round_key) { // It is important to always use the full round function - omitting the // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf] @@ -204,7 +213,7 @@ inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key; } -inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {} +ABSL_TARGET_CRYPTO inline void SwapEndian(void*) {} } // namespace @@ -232,17 +241,17 @@ class Vector128 { __m128i data_; }; -inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) { +ABSL_TARGET_CRYPTO inline Vector128 Vector128Load(const void* from) { return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from))); } -inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) { +ABSL_TARGET_CRYPTO inline void Vector128Store(const Vector128& v, void* to) { _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data()); } // One round of AES. "round_key" is a public constant for breaking the // symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, +ABSL_TARGET_CRYPTO inline Vector128 AesRound(const Vector128& state, const Vector128& round_key) { // It is important to always use the full round function - omitting the // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf] @@ -250,7 +259,7 @@ inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state, return Vector128(_mm_aesenc_si128(state.data(), round_key.data())); } -inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {} +ABSL_TARGET_CRYPTO inline void SwapEndian(void*) {} } // namespace @@ -276,7 +285,7 @@ namespace { // Block shuffles applies a shuffle to the entire state between AES rounds. // Improved odd-even shuffle from "New criterion for diffusion property". -inline ABSL_TARGET_CRYPTO void BlockShuffle(absl::uint128* state) { +ABSL_TARGET_CRYPTO inline void BlockShuffle(absl::uint128* state) { static_assert(RandenTraits::kFeistelBlocks == 16, "Expecting 16 FeistelBlocks."); @@ -323,7 +332,7 @@ inline ABSL_TARGET_CRYPTO void BlockShuffle(absl::uint128* state) { // per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel // XORs are 'free' (included in the second AES instruction). -inline ABSL_TARGET_CRYPTO const absl::uint128* FeistelRound( +ABSL_TARGET_CRYPTO inline const absl::uint128* FeistelRound( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { static_assert(RandenTraits::kFeistelBlocks == 16, @@ -385,7 +394,7 @@ inline ABSL_TARGET_CRYPTO const absl::uint128* FeistelRound( // Indistinguishable from ideal by chosen-ciphertext adversaries using less than // 2^64 queries if the round function is a PRF. This is similar to the b=8 case // of Simpira v2, but more efficient than its generic construction for b=16. -inline ABSL_TARGET_CRYPTO void Permute( +ABSL_TARGET_CRYPTO inline void Permute( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { // (Successfully unrolled; the first iteration jumps into the second half) @@ -406,7 +415,7 @@ namespace random_internal { bool HasRandenHwAesImplementation() { return true; } -const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() { +ABSL_TARGET_CRYPTO const void* RandenHwAes::GetKeys() { // Round keys for one AES per Feistel round and branch. // The canonical implementation uses first digits of Pi. #if defined(ABSL_ARCH_PPC) @@ -417,7 +426,7 @@ const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() { } // NOLINTNEXTLINE -void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void, +ABSL_TARGET_CRYPTO void RandenHwAes::Absorb(const void* seed_void, void* state_void) { static_assert(RandenTraits::kCapacityBytes / sizeof(Vector128) == 1, "Unexpected Randen kCapacityBlocks"); @@ -492,7 +501,7 @@ void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void, } // NOLINTNEXTLINE -void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys_void, +ABSL_TARGET_CRYPTO void RandenHwAes::Generate(const void* keys_void, void* state_void) { static_assert(RandenTraits::kCapacityBytes == sizeof(Vector128), "Capacity mismatch"); diff --git a/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_slow.cc b/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_slow.cc index d2b7da3c2cbb..12aa4b17fe03 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_slow.cc +++ b/deps/v8/third_party/abseil-cpp/absl/random/internal/randen_slow.cc @@ -25,19 +25,6 @@ #include "absl/random/internal/platform.h" #include "absl/random/internal/randen_traits.h" -#if ABSL_HAVE_ATTRIBUTE(always_inline) || \ - (defined(__GNUC__) && !defined(__clang__)) -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE \ - __attribute__((always_inline)) -#elif defined(_MSC_VER) -// We can achieve something similar to attribute((always_inline)) with MSVC by -// using the __forceinline keyword, however this is not perfect. MSVC is -// much less aggressive about inlining, and even with the __forceinline keyword. -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE __forceinline -#else -#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE -#endif - namespace { // AES portions based on rijndael-alg-fst.c, @@ -236,22 +223,21 @@ struct alignas(16) Vector128 { uint32_t s[4]; }; -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 -Vector128Load(const void* from) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline Vector128 Vector128Load(const void* from) { Vector128 result; std::memcpy(result.s, from, sizeof(Vector128)); return result; } -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store( - const Vector128& v, void* to) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void Vector128Store(const Vector128& v, + void* to) { std::memcpy(to, v.s, sizeof(Vector128)); } // One round of AES. "round_key" is a public constant for breaking the // symmetry of AES (ensures previously equal columns differ afterwards). -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128 -AesRound(const Vector128& state, const Vector128& round_key) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline Vector128 AesRound( + const Vector128& state, const Vector128& round_key) { Vector128 result; #ifdef ABSL_IS_LITTLE_ENDIAN result.s[0] = round_key.s[0] ^ // @@ -302,8 +288,7 @@ AesRound(const Vector128& state, const Vector128& round_key) { using ::absl::random_internal::RandenTraits; // The improved Feistel block shuffle function for 16 blocks. -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( - absl::uint128* state) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void BlockShuffle(absl::uint128* state) { static_assert(RandenTraits::kFeistelBlocks == 16, "Feistel block shuffle only works for 16 blocks."); @@ -361,9 +346,9 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle( // per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel // XORs are 'free' (included in the second AES instruction). -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE const absl::uint128* -FeistelRound(absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT state, - const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline const absl::uint128* FeistelRound( + absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT state, + const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { for (size_t branch = 0; branch < RandenTraits::kFeistelBlocks; branch += 4) { const Vector128 s0 = Vector128Load(state + branch); const Vector128 s1 = Vector128Load(state + branch + 1); @@ -387,7 +372,7 @@ FeistelRound(absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT state, // Indistinguishable from ideal by chosen-ciphertext adversaries using less than // 2^64 queries if the round function is a PRF. This is similar to the b=8 case // of Simpira v2, but more efficient than its generic construction for b=16. -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void Permute( absl::uint128* state, const absl::uint128* ABSL_RANDOM_INTERNAL_RESTRICT keys) { for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) { @@ -397,8 +382,7 @@ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute( } // Enables native loads in the round loop by pre-swapping. -inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void SwapEndian( - absl::uint128* state) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void SwapEndian(absl::uint128* state) { #ifdef ABSL_IS_BIG_ENDIAN for (uint32_t block = 0; block < RandenTraits::kFeistelBlocks; ++block) { uint64_t new_lo = absl::little_endian::ToHost64( diff --git a/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h b/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h index cbd5e0ca2ba0..99abe05abb41 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h +++ b/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution.h @@ -16,13 +16,14 @@ #define ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_ #include <algorithm> -#include <cassert> #include <cmath> +#include <ios> #include <istream> #include <limits> #include <ostream> #include "absl/base/config.h" +#include "absl/base/macros.h" #include "absl/random/internal/iostream_state_saver.h" #include "absl/random/internal/traits.h" #include "absl/random/uniform_int_distribution.h" @@ -60,15 +61,18 @@ class log_uniform_int_distribution { range_(static_cast<unsigned_type>(max_) - static_cast<unsigned_type>(min_)), log_range_(0) { - assert(max_ >= min_); - assert(base_ > 1); + ABSL_HARDENING_ASSERT(max_ >= min_); + ABSL_HARDENING_ASSERT(base_ > 1); if (base_ == 2) { // Determine where the first set bit is on range(), giving a log2(range) // value which can be used to construct bounds. log_range_ = (std::min)(random_internal::BitWidth(range()), std::numeric_limits<unsigned_type>::digits); - } else { + } else if (base_ > 2) { + // An out-of-contract base_ (<= 1) skips this branch entirely so that + // no floating-point undefined behavior is reached. + // // NOTE: Computing the logN(x) introduces error from 2 sources: // 1. Conversion of int to double loses precision for values >= // 2^53, which may cause some log() computations to operate on @@ -240,9 +244,16 @@ std::basic_istream<CharT, Traits>& operator>>( auto saver = random_internal::make_istream_state_saver(is); is >> min >> max >> base; if (!is.fail()) { - x.param(param_type(static_cast<result_type>(min), - static_cast<result_type>(max), - static_cast<result_type>(base))); + const result_type min_val = static_cast<result_type>(min); + const result_type max_val = static_cast<result_type>(max); + const result_type base_val = static_cast<result_type>(base); + if (max_val < min_val || base_val <= 1) { + // The input violates the param_type preconditions; signal failure by + // setting the failbit instead of constructing an invalid param_type. + is.setstate(is.rdstate() | std::ios_base::failbit); + } else { + x.param(param_type(min_val, max_val, base_val)); + } } return is; } diff --git a/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution_test.cc b/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution_test.cc index 591b5b37e489..4404111b1f4a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/random/log_uniform_int_distribution_test.cc @@ -116,6 +116,26 @@ TYPED_TEST(LogUniformIntDistributionTypeTest, SerializeTest) { } } +// operator>> must reject input that violates the param_type preconditions +// (max >= min and base > 1) by setting failbit and leaving the distribution +// unchanged, rather than constructing an out-of-contract param_type. +TYPED_TEST(LogUniformIntDistributionTypeTest, DeserializeRejectsInvalidParams) { + for (const char* input : { + "0 100 1", // base == 1 + "0 100 0", // base == 0 + "100 0 2", // max < min + }) { + absl::log_uniform_int_distribution<TypeParam> dist(3, 6, 17); + const auto before = dist.param(); + + std::istringstream is(input); + is >> dist; + + EXPECT_TRUE(is.fail()) << input; + EXPECT_EQ(dist.param(), before) << input; + } +} + using log_uniform_i32 = absl::log_uniform_int_distribution<int32_t>; class LogUniformIntChiSquaredTest diff --git a/deps/v8/third_party/abseil-cpp/absl/status/internal/status_internal.h b/deps/v8/third_party/abseil-cpp/absl/status/internal/status_internal.h index 1cc87aba4eac..07a5679de3fa 100644 --- a/deps/v8/third_party/abseil-cpp/absl/status/internal/status_internal.h +++ b/deps/v8/third_party/abseil-cpp/absl/status/internal/status_internal.h @@ -37,8 +37,6 @@ #include "absl/types/source_location.h" #include "absl/types/span.h" -#ifndef SWIG -// Disabled for SWIG as it doesn't parse attributes correctly. namespace absl { ABSL_NAMESPACE_BEGIN // Returned Status objects may not be ignored. Codesearch doesn't handle ifdefs @@ -54,13 +52,6 @@ class ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_TRIVIAL_ABI Status; #endif -ABSL_NAMESPACE_END -} // namespace absl -#endif // !SWIG - -namespace absl { -ABSL_NAMESPACE_BEGIN - enum class StatusCode : int; enum class StatusToStringMode : int; @@ -69,12 +60,9 @@ template <typename T> class StatusOr; namespace status_internal { -#ifndef SWIG class StatusPrivateAccessor; class StatusPrivateAccessorForStatusBuilder; -#endif // !SWIG -#ifndef SWIG // Container for status payloads. struct Payload { std::string type_url; @@ -124,6 +112,11 @@ class StatusRep { absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor) const; + // Returns the raw payload list, or nullptr if there are none. Unlike + // `ForEachPayload`, this does not hide `kStackTraceUrl` payloads and does not + // invalidate `type_url` lifetimes in debug builds; callers must handle both. + const Payloads* absl_nullable payloads() const { return payloads_.get(); } + absl::Span<const SourceLocation> GetSourceLocations() const; void AddSourceLocation(absl::SourceLocation loc); @@ -178,7 +171,6 @@ const char* absl_nonnull MakeCheckFailString( const absl::Status* absl_nonnull status, const char* absl_nonnull prefix); } // namespace status_internal -#endif // SWIG ABSL_NAMESPACE_END } // namespace absl diff --git a/deps/v8/third_party/abseil-cpp/absl/status/status.cc b/deps/v8/third_party/abseil-cpp/absl/status/status.cc index e9b0eab3f6d5..bb031577c8c9 100644 --- a/deps/v8/third_party/abseil-cpp/absl/status/status.cc +++ b/deps/v8/third_party/abseil-cpp/absl/status/status.cc @@ -18,6 +18,7 @@ #include <cstddef> #include <cstdint> #include <memory> +#include <optional> #include <ostream> #include <string> #include <type_traits> @@ -28,6 +29,7 @@ #include "absl/base/no_destructor.h" #include "absl/base/nullability.h" #include "absl/status/internal/status_internal.h" +#include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/types/source_location.h" @@ -424,7 +426,9 @@ StatusCode ErrnoToStatusCode(int error_number) { case ENETRESET: // Connection aborted by network case ENETUNREACH: // Network unreachable case ENOLCK: // No locks available +#ifdef ENOLINK case ENOLINK: // Link has been severed +#endif #ifdef ENONET case ENONET: // Machine is not on the network #endif diff --git a/deps/v8/third_party/abseil-cpp/absl/status/status_macros.h b/deps/v8/third_party/abseil-cpp/absl/status/status_macros.h index b823e0dd89f2..965ea8e7d690 100644 --- a/deps/v8/third_party/abseil-cpp/absl/status/status_macros.h +++ b/deps/v8/third_party/abseil-cpp/absl/status/status_macros.h @@ -22,6 +22,7 @@ #define ABSL_STATUS_STATUS_MACROS_H_ #include <cstddef> +#include <string> #include <type_traits> #include <utility> @@ -174,13 +175,9 @@ ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_2_)) \ (return_keyword, __VA_ARGS__) -constexpr bool HasPotentialConditionalOperator(const char* lhs, int size) { - for (int i = 0; i < size; ++i) { - if (lhs[i] == '?') { - return true; - } - } - return false; +constexpr bool HasPotentialConditionalOperator(const char* lhs, size_t size) { + return lhs[0] == '(' && lhs[size - 1] == ')' && + std::char_traits<char>::find(lhs, size, '?') != nullptr; } template <std::size_t N> @@ -241,26 +238,24 @@ ABSL_NAMESPACE_END (void)_; /* error_expression is allowed to not use this variable */ \ return_keyword(error_expression)) -#define ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \ - statusor, lhs, rexpr, error_expression) \ - auto statusor = (rexpr); \ - if (ABSL_PREDICT_FALSE(!statusor.ok())) { \ - error_expression; \ - } \ - { \ - static_assert( \ - !IsEnclosedByParentheses(#lhs) || \ - !HasPotentialConditionalOperator(#lhs, sizeof(#lhs) - 2), \ - "Identified potential conditional operator, consider not " \ - "using ABSL_ASSIGN_OR_RETURN"); \ - } \ - { \ - static_assert( \ - absl::status_macro_internal::IsAllowedStatusOrMacroType< \ - std::remove_const_t<decltype(statusor)>>(), \ - "ABSL_ASSIGN_OR_RETURN should only be used with absl::StatusOr<>"); \ - } \ - ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED(lhs) = \ +#define ABSL_INTERNAL_STATUS_MACROS_IMPL_ASSIGN_OR_RETURN_( \ + statusor, lhs, rexpr, error_expression) \ + auto statusor = (rexpr); \ + if (ABSL_PREDICT_FALSE(!statusor.ok())) { \ + error_expression; \ + } \ + { \ + static_assert(!HasPotentialConditionalOperator(#lhs, sizeof(#lhs) - 1), \ + "Identified potential conditional operator, consider not " \ + "using ABSL_ASSIGN_OR_RETURN"); \ + } \ + { \ + static_assert( \ + absl::status_macro_internal::IsAllowedStatusOrMacroType< \ + std::remove_const_t<decltype(statusor)>>(), \ + "ABSL_ASSIGN_OR_RETURN should only be used with absl::StatusOr<>"); \ + } \ + ABSL_INTERNAL_STATUS_MACROS_IMPL_UNPARENTHESIZE_IF_PARENTHESIZED(lhs) = \ (*std::move(statusor)) // Internal helpers for macro expansion. diff --git a/deps/v8/third_party/abseil-cpp/absl/status/statusor.h b/deps/v8/third_party/abseil-cpp/absl/status/statusor.h index e56656ab5e93..e54c61b6a3bd 100644 --- a/deps/v8/third_party/abseil-cpp/absl/status/statusor.h +++ b/deps/v8/third_party/abseil-cpp/absl/status/statusor.h @@ -724,7 +724,7 @@ template <typename T, std::enable_if_t<absl::HasOstreamOperator<T>::value, int> = 0> std::ostream& operator<<(std::ostream& os, const StatusOr<T>& status_or) { if (status_or.ok()) { - os << status_or.value(); + os << *status_or; } else { os << internal_statusor::StringifyRandom::OpenBrackets() << status_or.status() @@ -741,7 +741,7 @@ template <typename Sink, typename T, std::enable_if_t<absl::HasAbslStringify<T>::value, int> = 0> void AbslStringify(Sink& sink, const StatusOr<T>& status_or) { if (status_or.ok()) { - absl::Format(&sink, "%v", status_or.value()); + absl::Format(&sink, "%v", *status_or); } else { absl::Format(&sink, "%s%v%s", internal_statusor::StringifyRandom::OpenBrackets(), diff --git a/deps/v8/third_party/abseil-cpp/absl/status/statusor_benchmark.cc b/deps/v8/third_party/abseil-cpp/absl/status/statusor_benchmark.cc index ac353bb15621..0a9d29d7a4c4 100644 --- a/deps/v8/third_party/abseil-cpp/absl/status/statusor_benchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/status/statusor_benchmark.cc @@ -360,12 +360,12 @@ BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Ok); // below for the variants. bool bm_cond = true; -bool SimpleIntInterface(int64_t* v) ABSL_ATTRIBUTE_NOINLINE; -bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) - ABSL_ATTRIBUTE_NOINLINE; -absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) - ABSL_ATTRIBUTE_NOINLINE; -absl::StatusOr<int64_t> SimpleIntStatusOrInterface() ABSL_ATTRIBUTE_NOINLINE; +ABSL_ATTRIBUTE_NOINLINE bool SimpleIntInterface(int64_t* v); +ABSL_ATTRIBUTE_NOINLINE bool SimpleIntInterfaceWithErrorMessage( + int64_t* v, std::string* msg); +ABSL_ATTRIBUTE_NOINLINE absl::Status SimpleIntInterfaceWithErrorStatus( + int64_t* v); +ABSL_ATTRIBUTE_NOINLINE absl::StatusOr<int64_t> SimpleIntStatusOrInterface(); // (a): Just a boolean return value with an out int64* parameter bool SimpleIntInterface(int64_t* v) { diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.bazel index 450593236c31..756300ef14ff 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.bazel @@ -104,6 +104,7 @@ cc_library( ":internal", ":resize_and_overwrite", ":string_view", + "//absl/algorithm:container", "//absl/base", "//absl/base:config", "//absl/base:core_headers", @@ -597,6 +598,7 @@ cc_test( timeout = "long", srcs = ["internal/cord_rep_btree_test.cc"], copts = ABSL_TEST_COPTS, + shard_count = 4, visibility = ["//visibility:private"], deps = [ ":cord_internal", @@ -709,10 +711,10 @@ cc_library( ":cordz_info", ":cordz_update_scope", ":cordz_update_tracker", - ":internal", ":resize_and_overwrite", ":string_view", ":strings", + "//absl/algorithm:container", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", @@ -1038,6 +1040,7 @@ cc_test( timeout = "long", srcs = ["cord_test.cc"], copts = ABSL_TEST_COPTS, + shard_count = 4, visibility = ["//visibility:private"], deps = [ ":cord", @@ -1169,6 +1172,7 @@ cc_test( deps = [ ":string_view", ":strings", + "//absl/algorithm:container", "//absl/base:core_headers", "//absl/base:dynamic_annotations", "//absl/container:btree", @@ -1563,6 +1567,7 @@ cc_test( timeout = "long", srcs = ["internal/str_format/convert_test.cc"], copts = ABSL_TEST_COPTS, + shard_count = 4, visibility = ["//visibility:private"], deps = [ ":str_format", diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.gn b/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.gn index c639fa6199df..d0f752134a6a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.gn +++ b/deps/v8/third_party/abseil-cpp/absl/strings/BUILD.gn @@ -61,6 +61,7 @@ absl_source_set("strings") { ":internal", ":resize_and_overwrite", ":string_view", + "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/base", "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/base:core_headers", @@ -411,10 +412,10 @@ absl_source_set("cord") { ":cordz_info", ":cordz_update_scope", ":cordz_update_tracker", - ":internal", ":resize_and_overwrite", ":string_view", ":strings", + "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/base:config", "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/base:endian", @@ -733,6 +734,7 @@ absl_test("str_split_test") { deps = [ ":string_view", ":strings", + "//third_party/abseil-cpp/absl/algorithm:container", "//third_party/abseil-cpp/absl/base:core_headers", "//third_party/abseil-cpp/absl/base:dynamic_annotations", "//third_party/abseil-cpp/absl/container:btree", diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/strings/CMakeLists.txt index 2d301d816aec..8ba84b5bc0a5 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/strings/CMakeLists.txt @@ -70,6 +70,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::algorithm_container absl::base absl::bits absl::charset @@ -400,6 +401,7 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::algorithm_container absl::btree absl::core_headers absl::dynamic_annotations @@ -712,6 +714,8 @@ absl_cc_test( absl::string_view absl::strings GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( @@ -1194,6 +1198,8 @@ absl_cc_test( absl::string_view absl::strings GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( @@ -1231,6 +1237,8 @@ absl_cc_test( absl::string_view absl::strings GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/cord.cc b/deps/v8/third_party/abseil-cpp/absl/strings/cord.cc index 6d9dd10414a5..f9f576a22a50 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/cord.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/cord.cc @@ -15,6 +15,7 @@ #include "absl/strings/cord.h" #include <algorithm> +#include <array> #include <cassert> #include <cstddef> #include <cstdint> @@ -558,6 +559,7 @@ void Cord::Append(T&& src) { if (src.size() <= kMaxBytesToCopy) { Append(absl::string_view(src)); } else { + contents_.MaybeRemoveEmptyCrcNode(); CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.AppendTree(rep, CordzUpdateTracker::kAppendString); } @@ -637,6 +639,7 @@ inline void Cord::Prepend(T&& src) { if (src.size() <= kMaxBytesToCopy) { Prepend(absl::string_view(src)); } else { + contents_.MaybeRemoveEmptyCrcNode(); CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.PrependTree(rep, CordzUpdateTracker::kPrependString); } @@ -1201,6 +1204,182 @@ bool IsSubstringInCordAt(absl::Cord::CharIterator position, } } +// Tests whether the sequence of chunks beginning at `haystack` starts with the +// sequence of chunks beginning at `needle_begin` and extending to `needle_end`. +// +// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or +// equal to `needle_end - needle_begin` and `advance`. +bool IsSubcordInCordAt(absl::Cord::CharIterator haystack, + absl::Cord::CharIterator needle_begin, + absl::Cord::CharIterator needle_end) { + while (needle_begin != needle_end) { + auto haystack_chunk = absl::Cord::ChunkRemaining(haystack); + assert(!haystack_chunk.empty()); + auto needle_chunk = absl::Cord::ChunkRemaining(needle_begin); + auto min_length = std::min(haystack_chunk.size(), needle_chunk.size()); + if (haystack_chunk.substr(0, min_length) != + needle_chunk.substr(0, min_length)) { + return false; + } + absl::Cord::Advance(&haystack, min_length); + absl::Cord::Advance(&needle_begin, min_length); + } + return true; +} + +// Tests whether the sequence of chunks beginning at `position` starts with the +// cord `needle`. +// +// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or +// equal to `needle.size()`. +bool IsSubstringInCordAt(absl::Cord::CharIterator position, + const absl::Cord& needle) { + return IsSubcordInCordAt(position, needle.char_begin(), needle.char_end()); +} + +// Returns the character located `offset` bytes past `it`. +char CharacterAt(absl::Cord::CharIterator it, size_t offset) { + absl::Cord::Advance(&it, offset); + return *it; +} + +inline size_t BytesRemaining(const absl::Cord::CharIterator& it) { + return static_cast<size_t>( + absl::Cord::Distance(it, absl::Cord::CharIterator())); +} + +// Returns whether the sequence of chunks beginning at `chunk` + `idx` starts +// with the first `chunk_rem` bytes of `needle`. +// +// REQUIRES: `chunk.size() - idx >= chunk_rem`. +inline bool IsPrefixMatch(absl::string_view chunk, size_t idx, size_t chunk_rem, + absl::string_view needle) { + return chunk.substr(idx) == needle.substr(0, chunk_rem); +} + +// Returns whether the sequence of chunks beginning at `chunk` + `idx` starts +// with the first `chunk_rem` bytes of `needle`, where `needle` is a Cord. +// +// REQUIRES: `chunk.size() - idx >= chunk_rem` and `needle` is not empty. +inline bool IsPrefixMatch(absl::string_view chunk, size_t idx, size_t chunk_rem, + const absl::Cord& needle) { + auto needle_chunk = absl::Cord::ChunkRemaining(needle.char_begin()); + size_t check_len = std::min(chunk_rem, needle_chunk.size()); + return chunk.substr(idx, check_len) == needle_chunk.substr(0, check_len); +} + +// Initializes the Boyer-Moore-Horspool shift table for a string_view needle +// with a maximum scan length of `kMaxScan`. +inline void InitShift(std::array<uint16_t, 256>& shift, + absl::string_view needle, uint16_t default_shift, + size_t kMaxScan) { + shift.fill(default_shift); + const size_t m = needle.size(); + for (size_t i = kMaxScan; i > 0; --i) { + shift[static_cast<unsigned char>(needle[m - 1 - i])] = + static_cast<uint16_t>(i); + } +} + +// Initializes the Boyer-Moore-Horspool shift table for a Cord needle with a +// maximum scan length of `kMaxScan`. +inline void InitShift(std::array<uint16_t, 256>& shift, + const absl::Cord& needle, uint16_t default_shift, + size_t kMaxScan) { + shift.fill(default_shift); + auto needle_it = needle.char_begin(); + const size_t needle_size = needle.size(); + absl::Cord::Advance(&needle_it, needle_size - 1 - kMaxScan); + for (size_t i = 0; i < kMaxScan; ++i) { + shift[static_cast<unsigned char>(*needle_it)] = + static_cast<uint16_t>(kMaxScan - i); + absl::Cord::Advance(&needle_it, 1); + } +} + +template <typename Needle> +absl::Cord::CharIterator FindBMH(absl::Cord::CharIterator it, + const Needle& needle) { + const size_t needle_size = needle.size(); + const char first_needle = needle[0]; + std::array<uint16_t, 256> shift; + bool shift_initialized = false; + const size_t kMaxScan = std::min(needle_size - 1, size_t{256}); + const uint16_t default_shift = static_cast<uint16_t>(kMaxScan + 1); + const unsigned char last_needle = + static_cast<unsigned char>(needle[needle_size - 1]); + + while (BytesRemaining(it) >= needle_size) { + absl::string_view chunk = absl::Cord::ChunkRemaining(it); + auto idx = chunk.find(first_needle); + if (idx == absl::string_view::npos) { + // No potential match in this chunk, advance past it. + absl::Cord::Advance(&it, chunk.size()); + continue; + } + // Check if there is enough haystack remaining to actually have a match. + if (BytesRemaining(it) - idx < needle_size) { + break; + } + // We found the start of a potential match in the chunk. Advance the + // iterator to the match position. + absl::Cord::Advance(&it, idx); + size_t chunk_rem = chunk.size() - idx; + unsigned char last_hay; + if (chunk_rem >= needle_size) { + last_hay = static_cast<unsigned char>(chunk[idx + needle_size - 1]); + } else { + if (!IsPrefixMatch(chunk, idx, chunk_rem, needle)) { + absl::Cord::Advance(&it, 1); + continue; + } + last_hay = static_cast<unsigned char>(CharacterAt(it, needle_size - 1)); + } + // Check if the rightmost byte of the candidate window (`last_hay`) matches + // the rightmost byte of `needle` before performing a full equality check. + if (last_hay != last_needle) { + if (!shift_initialized) { + InitShift(shift, needle, default_shift, kMaxScan); + shift_initialized = true; + } + // Mismatch on the rightmost byte. Advance candidate position according + // to the Boyer-Moore-Horspool shift table. + absl::Cord::Advance(&it, shift[last_hay]); + continue; + } + // Check if this is `needle`. + if (IsSubstringInCordAt(it, needle)) { + return it; + } + if (!shift_initialized) { + InitShift(shift, needle, default_shift, kMaxScan); + shift_initialized = true; + } + last_hay = last_needle; + // Match check failed; advance candidate position according to the shift + // table. + absl::Cord::Advance(&it, shift[last_hay]); + } + // If we got here, we did not find `needle`. + return absl::Cord::CharIterator(); +} + +absl::Cord::CharIterator FindChar(absl::Cord::CharIterator it, char target) { + while (BytesRemaining(it) > 0) { + absl::string_view chunk = absl::Cord::ChunkRemaining(it); + auto idx = chunk.find(target); + if (idx != absl::string_view::npos) { + // Found target inside the current chunk. Advance the iterator to its + // position. + absl::Cord::Advance(&it, idx); + return it; + } + // Target is not inside this chunk; advance past the entire chunk. + absl::Cord::Advance(&it, chunk.size()); + } + return absl::Cord::CharIterator(); +} + } // namespace // A few options how this could be implemented: @@ -1219,15 +1398,38 @@ bool IsSubstringInCordAt(absl::Cord::CharIterator position, // boundaries. // // This currently implements option (b). +template <typename T> absl::Cord::CharIterator absl::Cord::FindImpl(CharIterator it, - absl::string_view needle) const { + const T& needle) const { // Ensure preconditions are met by callers first. + if (needle.empty()) { + return char_begin(); + } + if (needle.size() > size()) { + return char_end(); + } + if (needle.size() == size()) { + return *this == needle ? char_begin() : char_end(); + } + // Needle must not be empty. assert(!needle.empty()); // Haystack must be at least as large as needle. assert(it.chunk_iterator_.bytes_remaining_ >= needle.size()); + const size_t m = needle.size(); + const char first_needle = needle[0]; + // Fast path for single-character needles. + if (m == 1) { + return FindChar(it, first_needle); + } + + // Fast path for long needles. + if (m >= 256) { + return FindBMH(it, needle); + } + // Cord is a sequence of chunks. To find `needle` we go chunk by chunk looking // for the first char of needle, up until we have advanced `N` defined as // `haystack.size() - needle.size()`. If we find the first char of needle at @@ -1237,7 +1439,7 @@ absl::Cord::CharIterator absl::Cord::FindImpl(CharIterator it, auto haystack_chunk = Cord::ChunkRemaining(it); assert(!haystack_chunk.empty()); // Look for the first char of `needle` in the current chunk. - auto idx = haystack_chunk.find(needle.front()); + auto idx = haystack_chunk.find(first_needle); if (idx == absl::string_view::npos) { // No potential match in this chunk, advance past it. Cord::Advance(&it, haystack_chunk.size()); @@ -1262,97 +1464,11 @@ absl::Cord::CharIterator absl::Cord::FindImpl(CharIterator it, } absl::Cord::CharIterator absl::Cord::Find(absl::string_view needle) const { - if (needle.empty()) { - return char_begin(); - } - if (needle.size() > size()) { - return char_end(); - } - if (needle.size() == size()) { - return *this == needle ? char_begin() : char_end(); - } return FindImpl(char_begin(), needle); } -namespace { - -// Tests whether the sequence of chunks beginning at `haystack` starts with the -// sequence of chunks beginning at `needle_begin` and extending to `needle_end`. -// -// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or -// equal to `needle_end - needle_begin` and `advance`. -bool IsSubcordInCordAt(absl::Cord::CharIterator haystack, - absl::Cord::CharIterator needle_begin, - absl::Cord::CharIterator needle_end) { - while (needle_begin != needle_end) { - auto haystack_chunk = absl::Cord::ChunkRemaining(haystack); - assert(!haystack_chunk.empty()); - auto needle_chunk = absl::Cord::ChunkRemaining(needle_begin); - auto min_length = std::min(haystack_chunk.size(), needle_chunk.size()); - if (haystack_chunk.substr(0, min_length) != - needle_chunk.substr(0, min_length)) { - return false; - } - absl::Cord::Advance(&haystack, min_length); - absl::Cord::Advance(&needle_begin, min_length); - } - return true; -} - -// Tests whether the sequence of chunks beginning at `position` starts with the -// cord `needle`. -// -// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or -// equal to `needle.size()`. -bool IsSubcordInCordAt(absl::Cord::CharIterator position, - const absl::Cord& needle) { - return IsSubcordInCordAt(position, needle.char_begin(), needle.char_end()); -} - -} // namespace - absl::Cord::CharIterator absl::Cord::Find(const absl::Cord& needle) const { - if (needle.empty()) { - return char_begin(); - } - const auto needle_size = needle.size(); - if (needle_size > size()) { - return char_end(); - } - if (needle_size == size()) { - return *this == needle ? char_begin() : char_end(); - } - const auto needle_chunk = Cord::ChunkRemaining(needle.char_begin()); - auto haystack_it = char_begin(); - while (true) { - haystack_it = FindImpl(haystack_it, needle_chunk); - if (haystack_it == char_end() || - haystack_it.chunk_iterator_.bytes_remaining_ < needle_size) { - break; - } - // We found the first chunk of `needle` at `haystack_it` but not the entire - // subcord. Advance past the first chunk and check for the remainder. - auto haystack_advanced_it = haystack_it; - auto needle_it = needle.char_begin(); - Cord::Advance(&haystack_advanced_it, needle_chunk.size()); - Cord::Advance(&needle_it, needle_chunk.size()); - if (IsSubcordInCordAt(haystack_advanced_it, needle_it, needle.char_end())) { - return haystack_it; - } - Cord::Advance(&haystack_it, 1); - if (haystack_it.chunk_iterator_.bytes_remaining_ < needle_size) { - break; - } - if (haystack_it.chunk_iterator_.bytes_remaining_ == needle_size) { - // Special case, if there is exactly `needle_size` bytes remaining, the - // subcord is either at `haystack_it` or not at all. - if (IsSubcordInCordAt(haystack_it, needle)) { - return haystack_it; - } - break; - } - } - return char_end(); + return FindImpl(char_begin(), needle); } bool Cord::Contains(absl::string_view rhs) const { diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/cord.h b/deps/v8/third_party/abseil-cpp/absl/strings/cord.h index ef900f8a7a09..8fe8e9f8a1c3 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/cord.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/cord.h @@ -1120,7 +1120,8 @@ class ABSL_ATTRIBUTE_TRIVIAL_ABI Cord { void SetCrcCordState(crc_internal::CrcCordState state); const crc_internal::CrcCordState* absl_nullable MaybeGetCrcCordState() const; - CharIterator FindImpl(CharIterator it, absl::string_view needle) const; + template <typename T> + CharIterator FindImpl(CharIterator it, const T& needle) const; void CopyToArrayImpl(char* absl_nonnull dst) const; }; diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/cord_test.cc b/deps/v8/third_party/abseil-cpp/absl/strings/cord_test.cc index 1ff172ee2443..aed23efb4617 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/cord_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/cord_test.cc @@ -588,6 +588,482 @@ TEST_P(CordTest, Find) { std::next(fragmented_haystack.char_begin(), 5)); } +TEST_P(CordTest, FindLinearScaling) { + // Verifies that finding a mismatching string in an adversarial haystack + // scales sub-linearly/linearly via Boyer-Moore-Horspool without quadratic + // DoS. This uses a 1MB haystack and a slightly smaller needle that should + // timeout for quadratic behavior. + constexpr size_t kSize = 256 * 1024; + std::string haystack_str(kSize, 'a'); + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, kSize / 2), haystack_str.substr(kSize / 2)}); + + std::string needle_str(kSize / 2 - 1, 'a'); + needle_str.push_back('b'); + absl::Cord needle_cord = + absl::MakeFragmentedCord({needle_str.substr(0, needle_str.size() / 2), + needle_str.substr(needle_str.size() / 2)}); + + EXPECT_EQ(haystack.Find(needle_str), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_str)); + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHCrossChunkMatch) { + // Test finding a large needle (M >= 256) in a fragmented Cord haystack where + // the match spans across chunk boundaries. + const size_t kChunkSize = 512; + const size_t kNeedleSize = 300; + + std::string needle_str(kNeedleSize, 'x'); + for (size_t i = 0; i < kNeedleSize; ++i) { + needle_str[i] = static_cast<char>('A' + (i % 26)); + } + + std::vector<std::string> chunks; + chunks.push_back(std::string(kChunkSize, '.')); + chunks.push_back(std::string(kChunkSize, '.')); + chunks.push_back(std::string(kChunkSize, '.')); + absl::Cord haystack = absl::MakeFragmentedCord(chunks); + + std::string flat_haystack(haystack); + flat_haystack.replace(400, kNeedleSize, needle_str); + + std::vector<std::string> modified_chunks = { + flat_haystack.substr(0, kChunkSize), + flat_haystack.substr(kChunkSize, kChunkSize), + flat_haystack.substr(2 * kChunkSize, kChunkSize)}; + haystack = absl::MakeFragmentedCord(modified_chunks); + + // Test string_view needle + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 400); + EXPECT_TRUE(haystack.Contains(needle_str)); + + // Test Cord needle + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 400); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHChunkBoundaryPrefixMismatch) { + // Test BMH search when the first character of needle matches near the end of + // a chunk (chunk_rem < M), but the rest of the chunk prefix mismatches. + // Exercises the `chunk.substr(idx) != needle.substr(0, chunk_rem)` branch in + // FindImplBMH and FindCordBMH. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str[1] = 'B'; + + std::string chunk0(512, '.'); + chunk0[500] = 'Z'; + std::string chunk1(512, '.'); + + absl::Cord haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + + EXPECT_EQ(haystack.Find(needle_str), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_str)); + + absl::Cord needle_cord(needle_str); + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHCrossChunkLastByteMismatch) { + // Test BMH search when the first character and chunk prefix match near the + // end of a chunk, but the last byte across the chunk boundary mismatches. + // Exercises `last_hay != last_needle` after CharacterAt(it, m - 1) in + // FindImplBMH and FindCordBMH. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str.back() = 'Y'; + + std::string chunk0(512, '.'); + chunk0.replace(500, 12, 12, 'A'); + chunk0[500] = 'Z'; + + std::string chunk1(512, '.'); + chunk1[287] = 'W'; // Mismatches needle_str.back() ('Y') + + absl::Cord haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + + EXPECT_EQ(haystack.Find(needle_str), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_str)); + + absl::Cord needle_cord(needle_str); + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHCrossChunkInteriorMismatch) { + // Test BMH search when first and last characters match across chunk + // boundaries, but an interior character inside the second chunk mismatches. + // Exercises IsSubstringInCordAt / IsSubcordInCordAt returning false across + // chunks. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str.back() = 'Y'; + + std::string chunk0(512, '.'); + chunk0.replace(500, 12, 12, 'A'); + chunk0[500] = 'Z'; + + std::string chunk1(512, 'A'); + chunk1[287] = 'Y'; // Last char matches + chunk1[100] = 'W'; // Interior byte mismatches + + absl::Cord haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + + EXPECT_EQ(haystack.Find(needle_str), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_str)); + + // Verify valid match when interior byte is restored + chunk1[100] = 'A'; + haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 500); + EXPECT_TRUE(haystack.Contains(needle_str)); +} + +TEST_P(CordTest, FindBMHNearEndRemainingBytesBreak) { + // Test BMH search when the first character of needle matches near the end of + // haystack, but remaining bytes are less than needle size (bytes_remaining < + // M). Exercises the `idx + m > bytes_remaining` break condition in + // FindImplBMH and FindCordBMH. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + + std::string chunk0(500, '.'); + std::string chunk1(500, '.'); + chunk1[300] = 'Z'; // Offset 800 in haystack, remaining bytes = 200 (< 300) + + absl::Cord haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + + EXPECT_EQ(haystack.Find(needle_str), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_str)); + + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindCordBMHCrossChunkInteriorMismatch) { + // Test FindCordBMH when needle is a fragmented Cord (M >= 256), last byte + // matches, but IsSubcordInCordAt returns false due to an interior mismatch + // across chunks. Exercises lazy shift table initialization after + // IsSubcordInCordAt failure in FindCordBMH. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str.back() = 'Y'; + + std::string chunk0(512, '.'); + chunk0.replace(500, 12, 12, 'A'); + chunk0[500] = 'Z'; + + std::string chunk1(512, 'A'); + chunk1[287] = 'Y'; // Last char matches + chunk1[150] = 'W'; // Interior mismatch in chunk 1 + + absl::Cord haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); + + // Restore interior byte and verify match + chunk1[150] = 'A'; + haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + auto it = haystack.Find(needle_cord); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 500); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHNonAsciiBytes) { + // Test BMH search with high-bit non-ASCII bytes (values > 127) in Cord + // haystack and needle across chunk boundaries. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, '\0'); + for (size_t i = 0; i < kNeedleSize; ++i) { + needle_str[i] = static_cast<char>(128 + (i % 128)); + } + + std::string chunk0(512, '\x7F'); + std::string chunk1(512, '\x7F'); + + // Place needle straddling chunk 0 and chunk 1 at offset 400 + std::string flat_haystack = chunk0 + chunk1; + flat_haystack.replace(400, kNeedleSize, needle_str); + + absl::Cord haystack = absl::MakeFragmentedCord( + {flat_haystack.substr(0, 512), flat_haystack.substr(512)}); + + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 400); + EXPECT_TRUE(haystack.Contains(needle_str)); + + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 400); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindSingleCharNeedle) { + // Test single-character string_view and Cord needles (M = 1) in fragmented + // Cord, exercising the FindChar fast path. + absl::Cord haystack = absl::MakeFragmentedCord({"hello", " ", "world"}); + + // string_view needle + auto it_sv = haystack.Find("w"); + EXPECT_NE(it_sv, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_sv), 6); + EXPECT_TRUE(haystack.Contains("w")); + + EXPECT_EQ(haystack.Find("z"), haystack.char_end()); + EXPECT_FALSE(haystack.Contains("z")); + + // Cord needle + auto it_cord = haystack.Find(absl::Cord("w")); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 6); + EXPECT_TRUE(haystack.Contains(absl::Cord("w"))); + + EXPECT_EQ(haystack.Find(absl::Cord("z")), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(absl::Cord("z"))); +} + +TEST_P(CordTest, FindStringViewNeedleSizeLargerThanHaystack) { + absl::Cord haystack("hello"); + EXPECT_EQ(haystack.Find("hello world"), haystack.char_end()); + EXPECT_FALSE(haystack.Contains("hello world")); +} + +TEST_P(CordTest, FindStringViewNeedleSizeEqualToHaystack) { + absl::Cord haystack("hello world"); + EXPECT_EQ(haystack.Find("hello world"), haystack.char_begin()); + EXPECT_TRUE(haystack.Contains("hello world")); + + EXPECT_EQ(haystack.Find("hello WOrld"), haystack.char_end()); + EXPECT_FALSE(haystack.Contains("hello WOrld")); +} + +TEST_P(CordTest, FindCordNeedleSizeEqualToHaystack) { + absl::Cord haystack("hello world"); + absl::Cord needle_match("hello world"); + absl::Cord needle_mismatch("hello WOrld"); + + EXPECT_EQ(haystack.Find(needle_match), haystack.char_begin()); + EXPECT_TRUE(haystack.Contains(needle_match)); + + EXPECT_EQ(haystack.Find(needle_mismatch), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_mismatch)); +} + +TEST_P(CordTest, FindImplNearEndRemainingBytesBreak) { + std::string haystack_str(50, '.'); + haystack_str[47] = 'a'; + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, 25), haystack_str.substr(25)}); + + EXPECT_EQ(haystack.Find("abcde"), haystack.char_end()); + EXPECT_FALSE(haystack.Contains("abcde")); +} + +TEST_P(CordTest, FindCordNearEndRemainingBytesBreak) { + std::string haystack_str(50, '.'); + haystack_str[47] = 'a'; + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, 25), haystack_str.substr(25)}); + absl::Cord needle_cord("abcde"); + + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindImplBMHSingleChunkInteriorMismatch) { + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str.back() = 'Y'; + + std::string haystack_str(1000, 'A'); + haystack_str.replace(100, kNeedleSize, needle_str); + haystack_str[100 + 10] = 'W'; + + absl::Cord haystack(haystack_str); + EXPECT_EQ(haystack.Find(needle_str), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_str)); +} + +TEST_P(CordTest, FindCordBMHSingleChunkInteriorMismatch) { + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str.back() = 'Y'; + + std::string haystack_str(1000, 'A'); + haystack_str.replace(100, kNeedleSize, needle_str); + haystack_str[100 + 10] = 'W'; + + absl::Cord haystack(haystack_str); + absl::Cord needle_cord(needle_str); + + EXPECT_EQ(haystack.Find(needle_cord), haystack.char_end()); + EXPECT_FALSE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHDuplicateCharsInNeedle) { + // Test BMH shift table calculation when needle contains duplicate characters + // at different distances from the end. Verifies that the smallest shift + // distance (rightmost occurrence) is preserved and prevents over-shifting. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + needle_str[kNeedleSize - 50] = 'Q'; + needle_str[kNeedleSize - 3] = 'Q'; + needle_str.back() = 'Y'; + + std::string haystack_str(1000, '.'); + haystack_str.replace(202, kNeedleSize, needle_str); + haystack_str[200] = 'Z'; + haystack_str[499] = 'Q'; + + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, 500), haystack_str.substr(500)}); + + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 202); + EXPECT_TRUE(haystack.Contains(needle_str)); + + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 202); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHBoundaryThreshold256) { + // Test BMH search at the exact boundary size of 256 bytes for string_view + // and Cord needles. Verifies correct shift table boundary bounds. + const size_t kNeedleSize = 256; + std::string needle_str(kNeedleSize, 'B'); + needle_str[0] = 'X'; + needle_str[kNeedleSize - 2] = 'Y'; + needle_str.back() = 'Z'; + + std::string haystack_str(1000, '.'); + haystack_str.replace(500, kNeedleSize, needle_str); + + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, 400), haystack_str.substr(400)}); + + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 500); + EXPECT_TRUE(haystack.Contains(needle_str)); + + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 100), needle_str.substr(100)}); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 500); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHMatchAtVeryEndOfCord) { + // Test BMH search when the needle is located at the very end of haystack + // (idx + m == bytes_remaining_). Verifies that boundary check uses > instead + // of >=. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'M'); + needle_str[0] = 'S'; + needle_str.back() = 'E'; + + std::string haystack_str = std::string(500, '.') + needle_str; + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, 400), haystack_str.substr(400)}); + + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 500); + EXPECT_TRUE(haystack.Contains(needle_str)); + + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 500); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindBMHMatchInLaterChunkAfterEmptyChunk) { + // Test BMH search when the first chunk of a fragmented Cord haystack does NOT + // contain needle[0]. Verifies that idx == npos advances past the entire first + // chunk and continues searching subsequent chunks. + const size_t kNeedleSize = 300; + std::string needle_str(kNeedleSize, 'A'); + needle_str[0] = 'Z'; + + std::string chunk0(512, '.'); + std::string chunk1 = needle_str + std::string(212, '.'); + + absl::Cord haystack = absl::MakeFragmentedCord({chunk0, chunk1}); + + auto it = haystack.Find(needle_str); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 512); + EXPECT_TRUE(haystack.Contains(needle_str)); + + absl::Cord needle_cord = absl::MakeFragmentedCord( + {needle_str.substr(0, 150), needle_str.substr(150)}); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 512); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + +TEST_P(CordTest, FindShortNeedleConsecutiveCandidates) { + // Test short needle (2 <= M < 256) when consecutive positions in haystack + // start with needle.front(), where position 10 mismatches but position 11 + // matches. Verifies that failing IsSubstringInCordAt advances by exactly 1. + std::string needle = "ABZ"; + std::string haystack_str(100, '.'); + haystack_str.replace(10, 3, "ABW"); + haystack_str.replace(11, 3, "ABZ"); + + absl::Cord haystack = absl::MakeFragmentedCord( + {haystack_str.substr(0, 50), haystack_str.substr(50)}); + + auto it = haystack.Find(needle); + EXPECT_NE(it, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it), 11); + EXPECT_TRUE(haystack.Contains(needle)); + + absl::Cord needle_cord(needle); + auto it_cord = haystack.Find(needle_cord); + EXPECT_NE(it_cord, haystack.char_end()); + EXPECT_EQ(std::distance(haystack.char_begin(), it_cord), 11); + EXPECT_TRUE(haystack.Contains(needle_cord)); +} + TEST_P(CordTest, Subcord) { RandomEngine rng(GTEST_FLAG_GET(random_seed)); const std::string s = RandomLowercaseString(&rng, 1024); @@ -3030,6 +3506,11 @@ CordMutator cord_mutators[] = { [](absl::Cord& c) { c.Append("0123456789"); }, [](absl::Cord& c) { c.RemoveSuffix(10); } }, + { + "append large string", + [](absl::Cord& c) { c.Append(std::string(1000, 'x')); }, + [](absl::Cord& c) { c.RemoveSuffix(1000); } + }, { "append cord", [](absl::Cord& c) { @@ -3075,6 +3556,11 @@ CordMutator cord_mutators[] = { [](absl::Cord& c) { c.Prepend("9876543210"); }, [](absl::Cord& c) { c.RemovePrefix(10); } }, + { + "prepend large string", + [](absl::Cord& c) { c.Prepend(std::string(1000, 'x')); }, + [](absl::Cord& c) { c.RemovePrefix(1000); } + }, { "prepend cord", [](absl::Cord& c) { diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/append_and_overwrite_test.cc b/deps/v8/third_party/abseil-cpp/absl/strings/internal/append_and_overwrite_test.cc index aa9c7a173bca..c3a7b4f79213 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/append_and_overwrite_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/append_and_overwrite_test.cc @@ -49,7 +49,7 @@ TEST_P(StringAppendAndOverwriteTest, StringAppendAndOverwrite) { 'b'); EXPECT_EQ(s, expected); - EXPECT_EQ(s.c_str()[s.size()], '\0'); + EXPECT_EQ(s[s.size()], '\0'); } // clang-format off diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/cordz_info.h b/deps/v8/third_party/abseil-cpp/absl/strings/internal/cordz_info.h index 04609cd3092f..b3d88a879c22 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/cordz_info.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/cordz_info.h @@ -252,7 +252,7 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle { const int64_t sampling_stride_; }; -inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CordzInfo::MaybeTrackCord( InlineData& cord, MethodIdentifier method) { auto stride = cordz_should_profile(); if (ABSL_PREDICT_FALSE(stride > 0)) { @@ -260,14 +260,14 @@ inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( } } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CordzInfo::MaybeTrackCord( InlineData& cord, const InlineData& src, MethodIdentifier method) { if (ABSL_PREDICT_FALSE(InlineData::is_either_profiled(cord, src))) { MaybeTrackCordImpl(cord, src, method); } } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeUntrackCord( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CordzInfo::MaybeUntrackCord( CordzInfo* info) { if (ABSL_PREDICT_FALSE(info)) { info->Untrack(); diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/generic_printer_test.cc b/deps/v8/third_party/abseil-cpp/absl/strings/internal/generic_printer_test.cc index e7ecc09d8a42..47a11dbd2f1f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/generic_printer_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/generic_printer_test.cc @@ -330,9 +330,9 @@ TEST(GenericPrinterTest, Map) { TEST(GenericPrinterTest, StreamAdapter) { std::stringstream ss; static_assert( - std::is_same<std::remove_reference_t<decltype(ss << GenericPrint())>, - internal_generic_printer::GenericPrintStreamAdapter::Impl< - std::stringstream>>::value, + std::is_same_v<std::remove_reference_t<decltype(ss << GenericPrint())>, + internal_generic_printer::GenericPrintStreamAdapter::Impl< + std::stringstream>>, "expected ostream << GenericPrint() to yield adapter impl"); ss << GenericPrint() << "again, " << "back-up, " << "cue, " diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h index 1c87e1edaa0d..b5a312e4a23e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h @@ -22,6 +22,7 @@ #include <utility> #include "absl/base/config.h" +#include "absl/base/macros.h" #include "absl/container/inlined_vector.h" #include "absl/strings/internal/str_format/arg.h" #include "absl/strings/internal/str_format/checker.h" @@ -127,23 +128,17 @@ class FormatSpecTemplate #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER // Honeypot overload for when the string is not constexpr. - // We use the 'unavailable' attribute to give a better compiler error than - // just 'method is deleted'. FormatSpecTemplate(...) // NOLINT - __attribute__((unavailable("Format string is not constexpr."))); + ABSL_BAD_CALL_IF(true, "Format string is not constexpr."); // Honeypot overload for when the format is constexpr and invalid. - // We use the 'unavailable' attribute to give a better compiler error than - // just 'method is deleted'. // To avoid checking the format twice, we just check that the format is // constexpr. If it is valid, then the overload below will kick in. // We add the template here to make this overload have lower priority. template <typename = void> FormatSpecTemplate(const char* s) // NOLINT - __attribute__(( - enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), - unavailable( - "Format specified does not match the arguments passed."))); + ABSL_BAD_CALL_IF(str_format_internal::EnsureConstexpr(s), + "Format specified does not match the arguments passed."); template <typename T = void> FormatSpecTemplate(string_view s) // NOLINT diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc index fc7d9ba35e6a..9aa56718581f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc @@ -47,6 +47,8 @@ #include "absl/strings/internal/str_format/arg.h" #include "absl/strings/internal/str_format/bind.h" #include "absl/strings/match.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" @@ -213,7 +215,7 @@ void StrAppendV(std::string *dst, const char *format, va_list ap) { delete[] buf; } -void StrAppend(std::string *, const char *, ...) ABSL_PRINTF_ATTRIBUTE(2, 3); +ABSL_PRINTF_ATTRIBUTE(2, 3) void StrAppend(std::string*, const char*, ...); void StrAppend(std::string *out, const char *format, ...) { va_list ap; va_start(ap, format); @@ -221,7 +223,7 @@ void StrAppend(std::string *out, const char *format, ...) { va_end(ap); } -std::string StrPrint(const char *, ...) ABSL_PRINTF_ATTRIBUTE(1, 2); +ABSL_PRINTF_ATTRIBUTE(1, 2) std::string StrPrint(const char*, ...); std::string StrPrint(const char *format, ...) { va_list ap; va_start(ap, format); @@ -414,11 +416,11 @@ MATCHER_P(MatchesPointerString, ptr, "") { if (ptr == nullptr && arg == "(nil)") { return true; } - void* parsed = nullptr; - if (sscanf(arg.c_str(), "%p", &parsed) != 1) { + uintptr_t parsed = 0; + if (!absl::SimpleHexAtoi(arg, &parsed)) { LOG(FATAL) << "Could not parse " << arg; } - return ptr == parsed; + return ptr == reinterpret_cast<void*>(parsed); } TEST_F(FormatConvertTest, Pointer) { @@ -1017,6 +1019,35 @@ TEST_F(FormatConvertTest, Double) { } } +TEST_F(FormatConvertTest, ScientificZeroPadding) { + struct Case { + absl::string_view format; + // Positive and negative expected prefixes. + absl::string_view positive; + absl::string_view negative; + } cases[] = { + {"%010.0e", "000003e", "-00003e"}, {"%010.1g", "000003e", "-00003e"}, + {"%010.0E", "000003E", "-00003E"}, {"%010.1G", "000003E", "-00003E"}, + {"%+010.0e", "+00003e", "-00003e"}, {"%+010.1g", "+00003e", "-00003e"}, + {"% 010.0e", " 00003e", "-00003e"}, {"% 010.1g", " 00003e", "-00003e"}, + {"%#010.0e", "00003.e", "-0003.e"}, {"%#010.1g", "00003.e", "-0003.e"}, + }; + + // These exact values exercise both slow scientific conversion paths. + for (double value : {0x1p128, 0x1p-128}) { + const absl::string_view exponent = value > 1 ? "+38" : "-39"; + for (const auto& c : cases) { + SCOPED_TRACE(absl::StrCat(value, ", ", c.format)); + EXPECT_EQ( + FormatPack(UntypedFormatSpecImpl(c.format), {FormatArgImpl(value)}), + absl::StrCat(c.positive, exponent)); + EXPECT_EQ( + FormatPack(UntypedFormatSpecImpl(c.format), {FormatArgImpl(-value)}), + absl::StrCat(c.negative, exponent)); + } + } +} + TEST_F(FormatConvertTest, DoubleRound) { std::string s; const auto format = [&](const char *fmt, double d) -> std::string & { diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc index 137e159d7100..0895c3122b1f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc @@ -1496,6 +1496,7 @@ void FormatENegativeExpSlow(uint128 mantissa, int exp, bool uppercase, if (state.sign_char != '\0') { state.sink->Append(1, state.sign_char); } + state.sink->Append(padding.zeros, '0'); state.sink->Append(1, static_cast<char>(first_digit + '0')); if (precision > 0 || state.conv.has_alt_flag()) { @@ -1599,6 +1600,7 @@ void FormatEPositiveExpSlow(uint128 mantissa, int exp, bool uppercase, if (state.sign_char != '\0') { state.sink->Append(1, state.sign_char); } + state.sink->Append(padding.zeros, '0'); state.sink->Append(1, static_cast<char>(first_digit + '0')); --digits_to_go; if (print_dot) { diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h index 7698cfaf2fcd..8f9c11a19741 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h @@ -42,6 +42,7 @@ #include <type_traits> #include <utility> +#include "absl/algorithm/container.h" #include "absl/base/config.h" #include "absl/base/internal/iterator_traits.h" #include "absl/base/internal/raw_logging.h" @@ -231,7 +232,7 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, template <typename Iterator, typename = std::enable_if_t< base_internal::IsAtLeastForwardIterator<Iterator>::value>> -std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, +std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view sep, NoFormatter) { std::string result; if (start != end) { @@ -241,7 +242,7 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, // in memory strings to overflow a uint64_t. uint64_t result_size = start_value.size(); for (Iterator it = start; ++it != end;) { - result_size += s.size(); + result_size += sep.size(); result_size += (*it).size(); } @@ -252,17 +253,14 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, StringResizeAndOverwrite( result, static_cast<size_t>(result_size), - [&start, &end, &start_value, s](char* result_buf, - size_t result_buf_size) { + [&start, &end, &start_value, sep](char* result_buf, + size_t result_buf_size) { // Joins strings - memcpy(result_buf, start_value.data(), start_value.size()); - result_buf += start_value.size(); + result_buf = absl::c_copy(start_value, result_buf); for (Iterator it = start; ++it != end;) { - memcpy(result_buf, s.data(), s.size()); - result_buf += s.size(); + result_buf = absl::c_copy(sep, result_buf); auto&& value = *it; - memcpy(result_buf, value.data(), value.size()); - result_buf += value.size(); + result_buf = absl::c_copy(value, result_buf); } return result_buf_size; }); diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/match.h b/deps/v8/third_party/abseil-cpp/absl/strings/match.h index 431d4f5fb348..65bd8aa8bc22 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/match.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/match.h @@ -80,7 +80,8 @@ inline constexpr bool EndsWith(absl::string_view text, if (text.size() < suffix.size()) { return false; } - absl::string_view possible_match = text.substr(text.size() - suffix.size()); + absl::string_view possible_match = + text.substr(text.size() - suffix.size(), suffix.size()); return possible_match == suffix; } // StrContainsIgnoreCase() diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/numbers.cc b/deps/v8/third_party/abseil-cpp/absl/strings/numbers.cc index 924c9122f996..c574dee3f48a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/numbers.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/numbers.cc @@ -256,7 +256,7 @@ inline char* EncodePadded16(uint64_t v, char* absl_nonnull buffer) { return buffer + 16; } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU32( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline char* absl_nonnull EncodeFullU32( uint32_t n, char* absl_nonnull out_str) { if (n < 10) { *out_str = static_cast<char>('0' + n); @@ -279,7 +279,7 @@ inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU32( return out_str + sizeof(bottom); } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU64( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline char* absl_nonnull EncodeFullU64( uint64_t i, char* absl_nonnull buffer) { if (i <= std::numeric_limits<uint32_t>::max()) { return EncodeFullU32(static_cast<uint32_t>(i), buffer); @@ -304,7 +304,7 @@ inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU64( return buffer + sizeof(mod_result); } -inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU128( +ABSL_ATTRIBUTE_ALWAYS_INLINE inline char* absl_nonnull EncodeFullU128( uint128 i, char* absl_nonnull buffer) { if (absl::Uint128High64(i) == 0) { return EncodeFullU64(absl::Uint128Low64(i), buffer); diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/str_cat.h b/deps/v8/third_party/abseil-cpp/absl/strings/str_cat.h index 3ae1197d75b7..11e3bf63cd1a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/str_cat.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/str_cat.h @@ -382,7 +382,8 @@ class AlphaNum { &digits_[0])) {} AlphaNum(float f) // NOLINT(runtime/explicit) - : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} + : piece_(digits_, numbers_internal::SixDigitsToBuffer( + static_cast<double>(f), digits_)) {} AlphaNum(double f) // NOLINT(runtime/explicit) : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} @@ -517,8 +518,8 @@ std::string FloatToString(Float f) { std::string result; StringResizeAndOverwrite(result, numbers_internal::kSixDigitsToBufferSize, [f](char* start, size_t buf_size) { - size_t size = - numbers_internal::SixDigitsToBuffer(f, start); + size_t size = numbers_internal::SixDigitsToBuffer( + static_cast<double>(f), start); ABSL_ASSERT(size < buf_size); return size; }); diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/str_join_test.cc b/deps/v8/third_party/abseil-cpp/absl/strings/str_join_test.cc index 66572489b298..6e7fe613f58e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/str_join_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/str_join_test.cc @@ -136,6 +136,16 @@ TEST(StrJoin, APIExamples) { // A few examples of edge cases // + { + // Test the code path where default-constructed string_views are + // used. Hopefully a sanitizer will flag it if nullptr gets passed to + // memcpy. + std::vector<absl::string_view> v = {absl::string_view(), + absl::string_view()}; + EXPECT_EQ(absl::StrJoin(v, absl::string_view()), ""); + EXPECT_EQ(absl::StrJoin(v, ":"), ":"); + } + { // Empty range yields an empty string. std::vector<std::string> v; diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/str_split.h b/deps/v8/third_party/abseil-cpp/absl/strings/str_split.h index e86b29a344b9..dc32af18165e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/str_split.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/str_split.h @@ -96,7 +96,7 @@ ABSL_NAMESPACE_BEGIN // function: // // struct SimpleDelimiter { -// const char c_; +// char c_; // explicit SimpleDelimiter(char c) : c_(c) {} // absl::string_view Find(absl::string_view text, size_t pos) { // auto found = text.find(c_, pos); @@ -206,7 +206,7 @@ class ByAnyChar { absl::string_view Find(absl::string_view text, size_t pos) const; private: - const std::string delimiters_; + std::string delimiters_; }; // ByLength @@ -237,7 +237,7 @@ class ByLength { absl::string_view Find(absl::string_view text, size_t pos) const; private: - const ptrdiff_t length_; + ptrdiff_t length_; }; namespace strings_internal { @@ -291,7 +291,7 @@ class MaxSplitsImpl { private: Delimiter delimiter_; - const int limit_; + int limit_; int count_; }; diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/str_split_test.cc b/deps/v8/third_party/abseil-cpp/absl/strings/str_split_test.cc index 81553112957e..7487e0091c48 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/str_split_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/strings/str_split_test.cc @@ -14,6 +14,7 @@ #include "absl/strings/str_split.h" +#include <algorithm> #include <array> #include <cstddef> #include <cstdint> @@ -32,6 +33,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/algorithm/container.h" #include "absl/base/macros.h" #include "absl/container/btree_map.h" #include "absl/container/btree_set.h" @@ -1036,6 +1038,36 @@ TEST(Delimiter, ByLength) { EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0)); } +TEST(Split, ByAnyCharWorksWithRepeatedFind) { + auto splitter = absl::StrSplit("a,b;a", absl::ByAnyChar(",;")); + auto it = absl::c_find(splitter, "a"); + ASSERT_NE(it, splitter.end()); + // Search on from the next piece, which assigns the iterator. + it = std::find(std::next(it), splitter.end(), "a"); + ASSERT_NE(it, splitter.end()); + EXPECT_EQ(std::next(it), splitter.end()); +} + +TEST(Split, ByLengthWorksWithRepeatedFind) { + auto splitter = absl::StrSplit("aba", absl::ByLength(1)); + auto it = absl::c_find(splitter, "a"); + ASSERT_NE(it, splitter.end()); + // Search on from the next piece, which assigns the iterator. + it = std::find(std::next(it), splitter.end(), "a"); + ASSERT_NE(it, splitter.end()); + EXPECT_EQ(std::next(it), splitter.end()); +} + +TEST(Split, MaxSplitsWorksWithRepeatedFind) { + auto splitter = absl::StrSplit("a,a,b,c", absl::MaxSplits(',', 2)); + auto it = absl::c_find(splitter, "a"); + ASSERT_NE(it, splitter.end()); + // Search on from the next piece, which assigns the iterator. + it = std::find(std::next(it), splitter.end(), "a"); + ASSERT_NE(it, splitter.end()); + EXPECT_EQ(*std::next(it), "b,c"); +} + TEST(Split, WorksWithLargeStrings) { #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) diff --git a/deps/v8/third_party/abseil-cpp/absl/strings/string_view.h b/deps/v8/third_party/abseil-cpp/absl/strings/string_view.h index 4855e5bfdf1f..97f7729db9f6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/strings/string_view.h +++ b/deps/v8/third_party/abseil-cpp/absl/strings/string_view.h @@ -25,7 +25,6 @@ #define ABSL_STRINGS_STRING_VIEW_H_ #include <algorithm> -#include <string> #include <string_view> #include "absl/base/attributes.h" diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/synchronization/BUILD.bazel index c63ba865f890..7acbec493ac0 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/BUILD.bazel @@ -127,6 +127,7 @@ cc_library( "@rules_cc//cc/compiler:msvc-cl": [], "@rules_cc//cc/compiler:clang-cl": [], "@rules_cc//cc/compiler:emscripten": [], + "@platforms//os:wasi": [], "//conditions:default": ["-pthread"], }) + ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:public"], @@ -381,6 +382,7 @@ cc_test( copts = ABSL_TEST_COPTS, flaky = 1, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, deps = [ ":kernel_timeout_internal", ":synchronization", diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt index 3502d11f0d14..50129ce34cf5 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt @@ -198,6 +198,8 @@ absl_cc_test( absl::thread_pool absl::time GTest::gmock_main + SHARD_COUNT + 25 ) absl_cc_test( @@ -278,6 +280,8 @@ absl_cc_test( absl::thread_pool absl::time GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc index 25b51ffe0b87..707908145f1a 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc @@ -27,6 +27,9 @@ // implies rank[x] < rank[y]. // (2) When a new edge (x->y) is inserted, do nothing if rank[x] < rank[y]. // (3) Otherwise: adjust ranks in the neighborhood of x and y. +// +// Unlike in the paper, ranks are spaced apart, which often lets step (3) move +// just x or just y (see "Rank allocation" below). #include "absl/base/internal/low_level_alloc.h" // IWYU pragma: keep // This file is a no-op if the required LowLevelAlloc support is missing. @@ -282,7 +285,9 @@ inline uint32_t NodeVersion(GraphId id) { } struct Node { - int32_t rank; // rank number assigned by Pearce-Kelly algorithm + int64_t rank; // Unique rank (see "Rank allocation") + int32_t prev_slot; // Slot with the next lower rank, or -1 if none + int32_t next_slot; // Slot with the next higher rank, or -1 if none uint32_t version; // Current version number int32_t next_hash; // Next entry in hash table bool visited; // Temporary marker used by depth-first-search @@ -348,17 +353,53 @@ class PointerMap { } // namespace +// Rank allocation +// +// Ranks are unique int64_t values. All slots, including free slots, are kept in +// a doubly linked list sorted by rank (Node::prev_slot and Node::next_slot, +// from Rep::lowest_slot to Rep::highest_slot). Free slots keep their rank and +// their place in the list, which are reused along with the slot. New slots get +// ranks kRankStride above the highest rank. +// +// When a new edge x->y violates the rank order, InsertEdge first tries to move +// just x below y, or just y above x (see TryMoveXBelowY()): either to the +// midpoint between two ranks that are adjacent in the list, or kRankStride +// beyond the lowest or highest rank. No other slot can have such a rank, so +// ranks stay unique. +// +// kRankStride leaves room for about 32 moves, one after another, into the gap +// between two adjacent new slots. When a gap has no room left, Respace() first +// spreads out the ranks around it. Ranks beyond the lowest and highest ones +// stay within [kMinRank, kMaxRank], which leaves room for about 2^30 moves at +// each end before all slots are respaced. +static constexpr int64_t kRankStride = int64_t{1} << 32; +static constexpr int64_t kMinRank = -(int64_t{1} << 62); +static constexpr int64_t kMaxRank = int64_t{1} << 62; +// Respace() spreads out ranks until they can be at least this far apart. +static constexpr uint64_t kMinRespacedGap = uint64_t{1} << 16; +// Maximum number of in-neighbors of x (or out-neighbors of y) that +// TryMoveXBelowY() (or TryMoveYAboveX()) will examine. +static constexpr int kMaxSingleNodeDegree = 16; + struct GraphCycles::Rep { Vec<Node*> nodes_; Vec<int32_t> free_nodes_; // Indices for unused entries in nodes_ PointerMap ptrmap_; + int32_t lowest_slot = -1; // Slot with the lowest rank, or -1 if none + int32_t highest_slot = -1; // Slot with the highest rank, or -1 if none + int64_t rank_stride = kRankStride; // See TestOnlySetRankStride() // Temporary state. Vec<int32_t> deltaf_; // Results of forward DFS Vec<int32_t> deltab_; // Results of backward DFS Vec<int32_t> list_; // All nodes to reprocess - Vec<int32_t> merged_; // Rank values to assign to list_ entries Vec<int32_t> stack_; // Emulates recursion stack for depth-first searches + // Used by Reorder(): the slots to reorder, sorted by their current ranks, and + // the rank, prev_slot and next_slot of each. + Vec<int32_t> sorted_slots; + Vec<int64_t> sorted_ranks; + Vec<int32_t> old_prev_slots; + Vec<int32_t> old_next_slots; Rep() : ptrmap_(&nodes_) {} }; @@ -368,6 +409,119 @@ static Node* FindNode(GraphCycles::Rep* rep, GraphId id) { return (n->version == NodeVersion(id)) ? n : nullptr; } +static Node* NodeAt(GraphCycles::Rep* r, int32_t slot) { + return r->nodes_[static_cast<uint32_t>(slot)]; +} + +// Makes next_slot follow prev_slot in the rank list. prev_slot == -1 makes +// next_slot the lowest slot, and next_slot == -1 makes prev_slot the highest. +static void Link(GraphCycles::Rep* r, int32_t prev_slot, int32_t next_slot) { + if (prev_slot == -1) { + r->lowest_slot = next_slot; + } else { + NodeAt(r, prev_slot)->next_slot = next_slot; + } + if (next_slot == -1) { + r->highest_slot = prev_slot; + } else { + NodeAt(r, next_slot)->prev_slot = prev_slot; + } +} + +// Removes slot from the rank list. +static void Unlink(GraphCycles::Rep* r, int32_t slot) { + Link(r, NodeAt(r, slot)->prev_slot, NodeAt(r, slot)->next_slot); +} + +// Returns upper - lower, for lower <= upper, without overflow. +static uint64_t RankDistance(int64_t lower, int64_t upper) { + return static_cast<uint64_t>(upper) - static_cast<uint64_t>(lower); +} + +// Gives the run of adjacent slots from first_slot to last_slot in the rank list +// evenly spaced ranks, keeping their order. First grows the run on both sides +// until its slots can be at least kMinRespacedGap apart between the ranks just +// outside it (kMinRank and kMaxRank beyond the ends of the list), or until it +// covers the whole list. The whole list is spaced across +// [kMinRank / 2, kMaxRank / 2], which leaves room beyond both of its ends. +static void Respace(GraphCycles::Rep* r, int32_t first_slot, + int32_t last_slot) { + uint64_t count = 1; + for (int32_t slot = first_slot; slot != last_slot; + slot = NodeAt(r, slot)->next_slot) { + count++; + } + int64_t lower; + int64_t upper; + while (true) { + const int32_t before_slot = NodeAt(r, first_slot)->prev_slot; + const int32_t after_slot = NodeAt(r, last_slot)->next_slot; + if (before_slot == -1 && after_slot == -1) { + lower = kMinRank / 2; + upper = kMaxRank / 2; + break; + } + lower = before_slot == -1 ? kMinRank : NodeAt(r, before_slot)->rank; + upper = after_slot == -1 ? kMaxRank : NodeAt(r, after_slot)->rank; + if (RankDistance(lower, upper) / (count + 1) >= kMinRespacedGap) break; + // Double the size of the run, as far as the ends of the list allow. + for (const uint64_t target = 2 * count; count < target;) { + const int32_t prev_slot = NodeAt(r, first_slot)->prev_slot; + const int32_t next_slot = NodeAt(r, last_slot)->next_slot; + if (prev_slot == -1 && next_slot == -1) break; + if (prev_slot != -1) { + first_slot = prev_slot; + count++; + } + if (next_slot != -1) { + last_slot = next_slot; + count++; + } + } + } + const uint64_t step = RankDistance(lower, upper) / (count + 1); + int64_t rank = lower; + for (int32_t slot = first_slot;; slot = NodeAt(r, slot)->next_slot) { + rank += static_cast<int64_t>(step); + NodeAt(r, slot)->rank = rank; + if (slot == last_slot) return; + } +} + +// Links slot, which is not in the rank list, between prev_slot and next_slot, +// which are adjacent in it (-1 beyond its ends), with a rank between theirs: +// rank_stride (kRankStride by default) beyond prev_slot or next_slot at the +// ends of the list, and halfway between them otherwise. If there is no room +// for such a rank, respaces ranks first. +static void LinkBetween(GraphCycles::Rep* r, int32_t slot, int32_t prev_slot, + int32_t next_slot) { + int64_t rank; + if (prev_slot == -1 && next_slot == -1) { + rank = 0; + } else if (prev_slot == -1) { + if (NodeAt(r, next_slot)->rank < kMinRank + r->rank_stride) { + Respace(r, r->lowest_slot, r->highest_slot); + } + rank = NodeAt(r, next_slot)->rank - r->rank_stride; + } else if (next_slot == -1) { + if (NodeAt(r, prev_slot)->rank > kMaxRank - r->rank_stride) { + Respace(r, r->lowest_slot, r->highest_slot); + } + rank = NodeAt(r, prev_slot)->rank + r->rank_stride; + } else { + const Node* prev_node = NodeAt(r, prev_slot); + const Node* next_node = NodeAt(r, next_slot); + if (RankDistance(prev_node->rank, next_node->rank) < 2) { + Respace(r, prev_slot, next_slot); + } + const uint64_t gap = RankDistance(prev_node->rank, next_node->rank); + rank = prev_node->rank + static_cast<int64_t>(gap / 2); + } + NodeAt(r, slot)->rank = rank; + Link(r, prev_slot, slot); + Link(r, slot, next_slot); +} + void GraphCycles::TestOnlyAddNodes(uint32_t n) { uint32_t old_size = rep_->nodes_.size(); rep_->nodes_.resize(n); @@ -376,6 +530,13 @@ void GraphCycles::TestOnlyAddNodes(uint32_t n) { } } +void GraphCycles::TestOnlySetRankStride(int64_t stride) { + // After Respace() of the whole list, there is room for a stride of 2^61 + // beyond each end. + ABSL_RAW_CHECK(stride >= 1 && stride <= kMaxRank / 2, "Bad rank stride"); + rep_->rank_stride = stride; +} + GraphCycles::GraphCycles() { InitArenaIfNecessary(); rep_ = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Rep), arena)) @@ -396,7 +557,6 @@ GraphCycles::~GraphCycles() { bool GraphCycles::CheckInvariants() const { Rep* r = rep_; - NodeSet ranks; // Set of ranks seen so far. for (uint32_t x = 0; x < r->nodes_.size(); x++) { Node* nx = r->nodes_[x]; void* ptr = base_internal::UnhidePtr<void>(nx->masked_ptr); @@ -407,19 +567,44 @@ bool GraphCycles::CheckInvariants() const { if (nx->visited) { ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %" PRIu32, x); } - if (!ranks.insert(nx->rank)) { - ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %" PRId32, nx->rank); - } HASH_FOR_EACH(y, nx->out) { Node* ny = r->nodes_[static_cast<uint32_t>(y)]; if (nx->rank >= ny->rank) { ABSL_RAW_LOG(FATAL, "Edge %" PRIu32 " ->%" PRId32 - " has bad rank assignment %" PRId32 "->%" PRId32, + " has bad rank assignment %" PRId64 "->%" PRId64, x, y, nx->rank, ny->rank); } } } + // The rank list holds each slot once, in increasing rank order, so ranks are + // unique. + const uint32_t num_slots = r->nodes_.size(); + uint32_t num_listed = 0; + int32_t prev_slot = -1; + for (int32_t slot = r->lowest_slot; slot != -1; + slot = NodeAt(r, slot)->next_slot) { + if (NodeAt(r, slot)->prev_slot != prev_slot) { + ABSL_RAW_LOG(FATAL, + "Slot %" PRId32 " has prev_slot %" PRId32 + " instead of %" PRId32, + slot, NodeAt(r, slot)->prev_slot, prev_slot); + } + if (prev_slot != -1 && + NodeAt(r, prev_slot)->rank >= NodeAt(r, slot)->rank) { + ABSL_RAW_LOG( + FATAL, "Rank of slot %" PRId32 " is not above rank of slot %" PRId32, + slot, prev_slot); + } + if (++num_listed > num_slots) { + ABSL_RAW_LOG(FATAL, "Rank list has more entries than there are slots"); + } + prev_slot = slot; + } + if (prev_slot != r->highest_slot || num_listed != num_slots) { + ABSL_RAW_LOG(FATAL, "Rank list has %" PRIu32 " of %" PRIu32 " slots", + num_listed, num_slots); + } return true; } @@ -428,29 +613,29 @@ GraphId GraphCycles::GetId(void* ptr) { if (i != -1) { return MakeId(i, rep_->nodes_[static_cast<uint32_t>(i)]->version); } else if (rep_->free_nodes_.empty()) { + const int32_t slot = static_cast<int32_t>(rep_->nodes_.size()); Node* n = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Node), arena)) Node; n->version = 1; // Avoid 0 since it is used by InvalidGraphId() n->visited = false; - n->rank = static_cast<int32_t>(rep_->nodes_.size()); n->masked_ptr = base_internal::HidePtr(ptr); n->nstack = 0; n->priority = 0; rep_->nodes_.push_back(n); - rep_->ptrmap_.Add(ptr, n->rank); - return MakeId(n->rank, n->version); + LinkBetween(rep_, slot, rep_->highest_slot, /*next_slot=*/-1); + rep_->ptrmap_.Add(ptr, slot); + return MakeId(slot, n->version); } else { - // Preserve preceding rank since the set of ranks in use must be - // a permutation of [0,rep_->nodes_.size()-1]. - int32_t r = rep_->free_nodes_.back(); + // The slot keeps its rank (see "Rank allocation"). + int32_t slot = rep_->free_nodes_.back(); rep_->free_nodes_.pop_back(); - Node* n = rep_->nodes_[static_cast<uint32_t>(r)]; + Node* n = rep_->nodes_[static_cast<uint32_t>(slot)]; n->masked_ptr = base_internal::HidePtr(ptr); n->nstack = 0; n->priority = 0; - rep_->ptrmap_.Add(ptr, r); - return MakeId(r, n->version); + rep_->ptrmap_.Add(ptr, slot); + return MakeId(slot, n->version); } } @@ -502,13 +687,65 @@ void GraphCycles::RemoveEdge(GraphId x, GraphId y) { } } -static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound); -static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound); +static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int64_t upper_bound); +static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int64_t lower_bound); static void Reorder(GraphCycles::Rep* r); static void Sort(const Vec<Node*>&, Vec<int32_t>* delta); static void MoveToList(GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst); +// TryMoveXBelowY() and TryMoveYAboveX() are called by InsertEdge(x, y) when +// rank(x) > rank(y). They try to restore the rank order by moving only x below +// y, or only y above x, which is much cheaper than the Pearce-Kelly search and +// reorder. +// +// x can move below y if all of x's in-neighbors rank below y. This also shows +// that the new edge does not close a cycle: every node reachable from y ranks +// at or above y, so a path from y to x would have to enter x from such a node. +// Similarly, y can move above x if all of y's out-neighbors rank above x. +// +// Each returns false, changing nothing, if the move is not possible or if +// there are more than kMaxSingleNodeDegree neighbors to check. +static bool TryMoveXBelowY(GraphCycles::Rep* r, int32_t x, int32_t y) { + Node* nx = NodeAt(r, x); + Node* ny = NodeAt(r, y); + int degree = 0; + HASH_FOR_EACH(u, nx->in) { + if (++degree > kMaxSingleNodeDegree) return false; + if (NodeAt(r, u)->rank >= ny->rank) return false; + } + Unlink(r, x); + if (degree == 0) { + // Move x below all other nodes. + LinkBetween(r, x, /*prev_slot=*/-1, r->lowest_slot); + } else { + // Move x right below y. Its in-neighbors rank below y, so they rank no + // higher than the node right below y. + LinkBetween(r, x, ny->prev_slot, y); + } + return true; +} + +static bool TryMoveYAboveX(GraphCycles::Rep* r, int32_t x, int32_t y) { + Node* nx = NodeAt(r, x); + Node* ny = NodeAt(r, y); + int degree = 0; + HASH_FOR_EACH(w, ny->out) { + if (++degree > kMaxSingleNodeDegree) return false; + if (NodeAt(r, w)->rank <= nx->rank) return false; + } + Unlink(r, y); + if (degree == 0) { + // Move y above all other nodes. + LinkBetween(r, y, r->highest_slot, /*next_slot=*/-1); + } else { + // Move y right above x. Its out-neighbors rank above x, so they rank no + // lower than the node right above x. + LinkBetween(r, y, x, nx->next_slot); + } + return true; +} + bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) { Rep* r = rep_; const int32_t x = NodeIndex(idx); @@ -530,6 +767,9 @@ bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) { return true; } + // Try moving just x or just y. + if (TryMoveXBelowY(r, x, y) || TryMoveYAboveX(r, x, y)) return true; + // Current rank assignments are incompatible with the new edge. Recompute. // We only need to consider nodes that fall in the range [ny->rank,nx->rank]. if (!ForwardDFS(r, y, nx->rank)) { @@ -548,7 +788,7 @@ bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) { return true; } -static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) { +static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int64_t upper_bound) { // Avoid recursion since stack space might be limited. // We instead keep a stack of nodes to visit. r->deltaf_.clear(); @@ -576,7 +816,7 @@ static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) { return true; } -static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound) { +static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int64_t lower_bound) { r->deltab_.clear(); r->stack_.clear(); r->stack_.push_back(n); @@ -602,19 +842,48 @@ static void Reorder(GraphCycles::Rep* r) { Sort(r->nodes_, &r->deltab_); Sort(r->nodes_, &r->deltaf_); + // The slots to reorder, sorted by their current ranks. In their new order + // (list_), they take over the same ranks and places in the rank list. + const uint32_t count = r->deltab_.size() + r->deltaf_.size(); + r->sorted_slots.resize(count); + std::merge(r->deltab_.begin(), r->deltab_.end(), r->deltaf_.begin(), + r->deltaf_.end(), r->sorted_slots.begin(), + [r](int32_t a, int32_t b) { + return NodeAt(r, a)->rank < NodeAt(r, b)->rank; + }); + // Adds contents of delta lists to list_ (backwards deltas first). r->list_.clear(); MoveToList(r, &r->deltab_, &r->list_); MoveToList(r, &r->deltaf_, &r->list_); - // Produce sorted list of all ranks that will be reassigned. - r->merged_.resize(r->deltab_.size() + r->deltaf_.size()); - std::merge(r->deltab_.begin(), r->deltab_.end(), r->deltaf_.begin(), - r->deltaf_.end(), r->merged_.begin()); - - // Assign the ranks in order to the collected list. - for (uint32_t i = 0; i < r->list_.size(); i++) { - r->nodes_[static_cast<uint32_t>(r->list_[i])]->rank = r->merged_[i]; + // Record the rank, prev_slot and next_slot of each place before changing + // them. + r->sorted_ranks.resize(count); + r->old_prev_slots.resize(count); + r->old_next_slots.resize(count); + for (uint32_t i = 0; i < count; i++) { + const Node* p = NodeAt(r, r->sorted_slots[i]); + r->sorted_ranks[i] = p->rank; + r->old_prev_slots[i] = p->prev_slot; + r->old_next_slots[i] = p->next_slot; + } + + // Assign the ranks and places in order to the collected list. A prev_slot + // (or next_slot) that is also being reordered must be the previous (or next) + // place in sorted_slots, so link to the slot that now takes that place + // instead. + for (uint32_t i = 0; i < count; i++) { + const int32_t slot = r->list_[i]; + NodeAt(r, slot)->rank = r->sorted_ranks[i]; + if (i > 0 && r->old_prev_slots[i] == r->sorted_slots[i - 1]) { + Link(r, r->list_[i - 1], slot); + } else { + Link(r, r->old_prev_slots[i], slot); + } + if (i + 1 == count || r->old_next_slots[i] != r->sorted_slots[i + 1]) { + Link(r, slot, r->old_next_slots[i]); + } } } @@ -633,10 +902,7 @@ static void Sort(const Vec<Node*>& nodes, Vec<int32_t>* delta) { static void MoveToList(GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) { - for (auto& v : *src) { - int32_t w = v; - // Replace v entry with its rank - v = r->nodes_[static_cast<uint32_t>(w)]->rank; + for (int32_t w : *src) { // Prepare for future DFS calls r->nodes_[static_cast<uint32_t>(w)]->visited = false; dst->push_back(w); diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h index da0650405308..27eaa6c61be0 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h @@ -131,6 +131,12 @@ class GraphCycles { // very full. void TestOnlyAddNodes(uint32_t n); + // Test-only method to set how far apart the ranks of new nodes are, and how + // far below (above) all other nodes a node is moved. The default is 2^32. A + // stride of up to 2^61 makes the ranks beyond the lowest and highest ones run + // out after a few new nodes or moves. + void TestOnlySetRankStride(int64_t stride); + // ---------------------------------------------------- struct Rep; private: diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc index 9012801f7805..9d11c38071f2 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc @@ -40,4 +40,65 @@ void BM_StressTest(benchmark::State& state) { } BENCHMARK(BM_StressTest)->Range(2048, 1048576); +using absl::synchronization_internal::GraphCycles; +using absl::synchronization_internal::GraphId; + +// Returns a node for a new pointer value, next_ptr, and increments next_ptr. +GraphId NewNode(GraphCycles& g, uintptr_t& next_ptr) { + return g.GetId(reinterpret_cast<void*>(next_ptr++)); +} + +// Adds a chain of n new nodes after node. +void AddChain(GraphCycles& g, GraphId node, int n, uintptr_t& next_ptr) { + for (int i = 0; i < n; i++) { + const GraphId next = NewNode(g, next_ptr); + ABSL_RAW_CHECK(g.InsertEdge(node, next), ""); + node = next; + } +} + +// Inserts edges from new nodes to an old node that has a chain of +// state.range(0) descendants. New nodes rank above old ones, so each edge +// violates the rank order. Deadlock detection sees this pattern whenever a +// newly created Mutex is held while an older one is acquired. +void BM_NewNodeToOldNode(benchmark::State& state) { + const int num_descendants = static_cast<int>(state.range(0)); + constexpr int kNewNodes = 10000; + while (state.KeepRunningBatch(kNewNodes)) { + GraphCycles g; + uintptr_t next_ptr = 1; + const GraphId old_node = NewNode(g, next_ptr); + AddChain(g, old_node, num_descendants, next_ptr); + for (int i = 0; i < kNewNodes; i++) { + const GraphId new_node = NewNode(g, next_ptr); + ABSL_RAW_CHECK(g.InsertEdge(new_node, old_node), ""); + } + } +} +BENCHMARK(BM_NewNodeToOldNode)->Arg(256); + +// Inserts edges u -> new node -> y, where u -> y are old nodes and y has a +// chain of state.range(0) descendants. Each new node must move between u and y, +// so these moves all go into the same gap. Deadlock detection sees this +// pattern when newly created Mutexes are each acquired while one Mutex is held, +// and then held while another one is acquired. +void BM_NewNodesBetweenOldNodes(benchmark::State& state) { + const int num_descendants = static_cast<int>(state.range(0)); + constexpr int kNewNodes = 10000; + while (state.KeepRunningBatch(kNewNodes)) { + GraphCycles g; + uintptr_t next_ptr = 1; + const GraphId u = NewNode(g, next_ptr); + const GraphId y = NewNode(g, next_ptr); + ABSL_RAW_CHECK(g.InsertEdge(u, y), ""); + AddChain(g, y, num_descendants, next_ptr); + for (int i = 0; i < kNewNodes; i++) { + const GraphId new_node = NewNode(g, next_ptr); + ABSL_RAW_CHECK(g.InsertEdge(u, new_node), ""); + ABSL_RAW_CHECK(g.InsertEdge(new_node, y), ""); + } + } +} +BENCHMARK(BM_NewNodesBetweenOldNodes)->Arg(256); + } // namespace diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc index d4ba0f6edd88..b1a6daf0825d 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc @@ -483,6 +483,167 @@ TEST(GraphCycles, IntegerOverflow) { graph_cycles.RemoveNode(reinterpret_cast<void*>(buf)); } +// Returns ids for n new nodes. A new GraphCycles ranks nodes in creation order, +// so InsertEdge(ids[i], ids[j]) with i > j violates the rank order and makes +// InsertEdge reorder nodes. +static std::vector<GraphId> NewNodes(GraphCycles* g, size_t n) { + std::vector<GraphId> ids(n); + for (size_t i = 0; i < n; ++i) { + ids[i] = g->GetId(reinterpret_cast<void*>(static_cast<uintptr_t>(i + 1))); + } + return ids; +} + +// Each group of edges below violates the rank order in a different way. The +// comments say how InsertEdge is expected to restore the order. +TEST(GraphCycles, RankOrderRepairs) { + GraphCycles g; + std::vector<GraphId> n = NewNodes(&g, 16); + + // x has no in-neighbors: move x below all nodes. + ASSERT_TRUE(g.InsertEdge(n[1], n[0])); + + // x's in-neighbors rank below y: move x into the gap below y. + ASSERT_TRUE(g.InsertEdge(n[2], n[4])); + ASSERT_TRUE(g.InsertEdge(n[4], n[3])); + + // y has no out-neighbors: move y above all nodes. + ASSERT_TRUE(g.InsertEdge(n[6], n[7])); + ASSERT_TRUE(g.InsertEdge(n[7], n[5])); + + // y's out-neighbors rank above x: move y into the gap above x. + ASSERT_TRUE(g.InsertEdge(n[8], n[11])); + ASSERT_TRUE(g.InsertEdge(n[9], n[10])); + ASSERT_TRUE(g.InsertEdge(n[10], n[8])); + + // Neither x nor y can move alone: Pearce-Kelly reorder. + ASSERT_TRUE(g.InsertEdge(n[12], n[13])); + ASSERT_TRUE(g.InsertEdge(n[14], n[15])); + ASSERT_TRUE(g.InsertEdge(n[15], n[12])); + CheckInvariants(g); + + // Edges that would close a cycle are still rejected. + EXPECT_FALSE(g.InsertEdge(n[0], n[1])); + EXPECT_FALSE(g.InsertEdge(n[3], n[2])); + EXPECT_FALSE(g.InsertEdge(n[5], n[6])); + EXPECT_FALSE(g.InsertEdge(n[8], n[9])); + EXPECT_FALSE(g.InsertEdge(n[13], n[14])); + CheckInvariants(g); +} + +// InsertEdge(x, y) does not move x if x has too many in-neighbors to check, +// even if moving it would restore the rank order. Here y cannot move either, so +// InsertEdge falls back to the Pearce-Kelly reorder. +TEST(GraphCycles, TooManyNeighborsToMove) { + GraphCycles g; + std::vector<GraphId> n = NewNodes(&g, 41); + + // x is 40, which has 17 in-neighbors. y is 30, which cannot move above x + // because of its out-neighbor 31. + for (size_t i = 0; i <= 16; ++i) { + ASSERT_TRUE(g.InsertEdge(n[i], n[40])); + } + ASSERT_TRUE(g.InsertEdge(n[30], n[31])); + ASSERT_TRUE(g.InsertEdge(n[40], n[30])); + CheckInvariants(g); + + EXPECT_FALSE(g.InsertEdge(n[30], n[0])); + CheckInvariants(g); +} + +// Each move of a node right below the same node halves the gap below it. Check +// that InsertEdge keeps working when that gap runs out and the ranks around it +// are respaced. +TEST(GraphCycles, RespacesCrowdedGapBelow) { + GraphCycles g; + std::vector<GraphId> n = NewNodes(&g, 2000); + + // Each n[i] has in-neighbor 50, which ranks below 51, so each n[i] -> n[51] + // edge below moves n[i] right below 51. + for (size_t i = 100; i < 2000; ++i) { + ASSERT_TRUE(g.InsertEdge(n[50], n[i])); + ASSERT_TRUE(g.InsertEdge(n[i], n[51])); + if (i % 100 == 0) CheckInvariants(g); + } + CheckInvariants(g); + + EXPECT_FALSE(g.InsertEdge(n[51], n[50])); + EXPECT_FALSE(g.InsertEdge(n[51], n[100])); + EXPECT_FALSE(g.InsertEdge(n[1999], n[50])); + CheckInvariants(g); +} + +// Same, for moves of a node right above the same node. +TEST(GraphCycles, RespacesCrowdedGapAbove) { + GraphCycles g; + constexpr size_t kNumMoved = 1000; + std::vector<GraphId> n = NewNodes(&g, 2 * kNumMoved + 18); + + // x ranks above each n[i], i < kNumMoved, and has too many in-neighbors to + // move. n[i] has an out-neighbor that ranks above x, so each x -> n[i] edge + // below moves n[i] right above x. + const GraphId x = n[kNumMoved + 17]; + for (size_t j = 0; j <= 16; ++j) { + ASSERT_TRUE(g.InsertEdge(n[kNumMoved + j], x)); + } + for (size_t i = 0; i < kNumMoved; ++i) { + ASSERT_TRUE(g.InsertEdge(n[i], n[kNumMoved + 18 + i])); + ASSERT_TRUE(g.InsertEdge(x, n[i])); + if (i % 100 == 0) CheckInvariants(g); + } + CheckInvariants(g); + + EXPECT_FALSE(g.InsertEdge(n[0], x)); + EXPECT_FALSE(g.InsertEdge(n[kNumMoved + 18], x)); + EXPECT_FALSE(g.InsertEdge(n[kNumMoved - 1], n[kNumMoved])); + CheckInvariants(g); +} + +// With a rank stride this large, the ranks beyond the lowest and highest ones +// run out after a few new nodes, or a few moves of a node below or above all +// other nodes, and then all ranks are respaced. Check that the rank order stays +// valid. +TEST(GraphCycles, RanksRunOut) { + GraphCycles g; + g.TestOnlySetRankStride(int64_t{1} << 60); + std::vector<GraphId> n = NewNodes(&g, 50); + for (size_t i = 0; i < 9; ++i) { + ASSERT_TRUE(g.InsertEdge(n[i], n[i + 1])); + } + CheckInvariants(g); + const GraphId a = n[10]; + const GraphId b = n[11]; + + // a and b have no in-neighbors, so each InsertEdge call below moves one of + // them below all other nodes. + for (int i = 0; i < 1000; ++i) { + ASSERT_TRUE(g.InsertEdge(b, a)); + g.RemoveEdge(b, a); + ASSERT_TRUE(g.InsertEdge(a, b)); + g.RemoveEdge(a, b); + } + CheckInvariants(g); + + // Now a and b have too many in-neighbors to move, so each InsertEdge call + // below moves the other one above all other nodes. + for (size_t i = 12; i < 50; ++i) { + ASSERT_TRUE(g.InsertEdge(n[i], i % 2 == 0 ? a : b)); + } + for (int i = 0; i < 1000; ++i) { + ASSERT_TRUE(g.InsertEdge(b, a)); + g.RemoveEdge(b, a); + ASSERT_TRUE(g.InsertEdge(a, b)); + g.RemoveEdge(a, b); + } + CheckInvariants(g); + + EXPECT_TRUE(g.IsReachable(n[0], n[9])); + EXPECT_FALSE(g.InsertEdge(n[9], n[0])); + ASSERT_TRUE(g.InsertEdge(n[9], a)); + EXPECT_FALSE(g.InsertEdge(a, n[0])); + CheckInvariants(g); +} + } // namespace synchronization_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.cc b/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.cc index d6e2aace10c7..d5c1a3c46e5f 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.cc +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.cc @@ -538,7 +538,14 @@ struct SynchLocksHeld { struct { Mutex* mu; // lock acquired int32_t count; // times acquired - GraphId id; // deadlock_graph id of acquired lock + // True iff this thread called mu->ForgetDeadlockInfo() while holding mu. + // The entry is then ignored for lock ordering until it is released. + bool forgotten; + // deadlock_graph id of mu, or InvalidGraphId() until DeadlockCheck() + // needs it, which is when this thread acquires another lock while + // holding mu. This way, acquiring a lock while holding no others, and + // releasing a lock, do not need deadlock_graph_mu. + GraphId id; } locks[40]; // If a thread overfills the array during deadlock detection, we // continue, discarding information as needed. If no overflow has @@ -559,6 +566,14 @@ static SynchLocksHeld* LocksHeldAlloc() { return ret; } +static void RemoveHeldLockEntry(SynchLocksHeld* held_locks, int i) { + const int last = --held_locks->n; + held_locks->locks[i] = held_locks->locks[last]; + held_locks->locks[last].id = InvalidGraphId(); + held_locks->locks[last].mu = + nullptr; // clear mu to please the leak detector. +} + // Return the PerThreadSynch-struct for this thread. static PerThreadSynch* Synch_GetPerThread() { ThreadIdentity* identity = GetOrCreateCurrentThreadIdentity(); @@ -757,6 +772,20 @@ Mutex::~Mutex() { Dtor(); } defined(ABSL_BUILD_DLL) void Mutex::Dtor() { if (kDebugMode) { + // If this thread is destroying a locked Mutex, remove any held-lock + // entries for it so their slots are not leaked. + ThreadIdentity* identity = CurrentThreadIdentityIfPresent(); + if (identity != nullptr && + identity->per_thread_synch.all_locks != nullptr) { + SynchLocksHeld* held_locks = identity->per_thread_synch.all_locks; + for (int i = 0; i < held_locks->n;) { + if (held_locks->locks[i].mu == this) { + RemoveHeldLockEntry(held_locks, i); + } else { + i++; + } + } + } this->ForgetDeadlockInfo(); } ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); @@ -1231,28 +1260,35 @@ static GraphId GetGraphIdLocked(Mutex* mu) return deadlock_graph->GetId(mu); } -static GraphId GetGraphId(Mutex* mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) { - base_internal::SpinLockHolder l(deadlock_graph_mu); - GraphId id = GetGraphIdLocked(mu); - return id; +// Returns the index of the entry for mu in held_locks, or -1 if there is none. +// Prefers the entry that is not marked forgotten (there is at most one), and +// otherwise returns the first entry that is. +static int FindHeldLock(const SynchLocksHeld* held_locks, const Mutex* mu) { + int forgotten_index = -1; + for (int i = 0; i != held_locks->n; i++) { + if (held_locks->locks[i].mu == mu) { + if (!held_locks->locks[i].forgotten) return i; + if (forgotten_index == -1) forgotten_index = i; + } + } + return forgotten_index; } // Record a lock acquisition. This is used in debug mode for deadlock // detection. The held_locks pointer points to the relevant data // structure for each case. -static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld* held_locks) { +static void LockEnter(Mutex* mu, SynchLocksHeld* held_locks) { int n = held_locks->n; - int i = 0; - while (i != n && held_locks->locks[i].id != id) { - i++; - } - if (i == n) { + int i = FindHeldLock(held_locks, mu); + // A forgotten hold stays ignored, so a new hold of mu gets its own entry. + if (i == -1 || held_locks->locks[i].forgotten) { if (n == static_cast<int>(std::size(held_locks->locks))) { held_locks->overflow = true; // lost some data } else { // we have room for lock - held_locks->locks[i].mu = mu; - held_locks->locks[i].count = 1; - held_locks->locks[i].id = id; + held_locks->locks[n].mu = mu; + held_locks->locks[n].count = 1; + held_locks->locks[n].forgotten = false; + held_locks->locks[n].id = InvalidGraphId(); held_locks->n = n + 1; } } else { @@ -1260,39 +1296,28 @@ static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld* held_locks) { } } -// Record a lock release. Each call to LockEnter(mu, id, x) should be -// eventually followed by a call to LockLeave(mu, id, x) by the same thread. +// Record a lock release. Each call to LockEnter(mu, x) should be +// eventually followed by a call to LockLeave(mu, x) by the same thread. // It does not process the event if is not needed when deadlock detection is // disabled. -static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld* held_locks) { - int n = held_locks->n; - int i = 0; - while (i != n && held_locks->locks[i].id != id) { - i++; - } - if (i == n) { - if (!held_locks->overflow) { - // The deadlock id may have been reassigned after ForgetDeadlockInfo, - // but in that case mu should still be present. - i = 0; - while (i != n && held_locks->locks[i].mu != mu) { - i++; - } - if (i == n) { // mu missing means releasing unheld lock - SynchEvent* mu_events = GetSynchEvent(mu); - ABSL_RAW_LOG(FATAL, - "thread releasing lock it does not hold: %p %s; " - , - static_cast<void*>(mu), - mu_events == nullptr ? "" : mu_events->name); - } +static void LockLeave(Mutex* mu, SynchLocksHeld* held_locks) { + // If mu was forgotten while held, this releases the forgotten entry. + int i = FindHeldLock(held_locks, mu); + if (i == -1) { + // The thread does not hold mu, unless held_locks was full when mu was + // acquired. + if (held_locks->overflow) { + return; } - } else if (held_locks->locks[i].count == 1) { - held_locks->n = n - 1; - held_locks->locks[i] = held_locks->locks[n - 1]; - held_locks->locks[n - 1].id = InvalidGraphId(); - held_locks->locks[n - 1].mu = - nullptr; // clear mu to please the leak detector. + SynchEvent* mu_events = GetSynchEvent(mu); + ABSL_RAW_LOG(FATAL, + "thread releasing lock it does not hold: %p %s; " + , + static_cast<void*>(mu), + mu_events == nullptr ? "" : mu_events->name); + } + if (held_locks->locks[i].count == 1) { + RemoveHeldLockEntry(held_locks, i); } else { assert(held_locks->locks[i].count > 0); held_locks->locks[i].count--; @@ -1304,17 +1329,7 @@ static inline void DebugOnlyLockEnter(Mutex* mu) { if (kDebugMode) { if (synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { - LockEnter(mu, GetGraphId(mu), Synch_GetAllLocks()); - } - } -} - -// Call LockEnter() if in debug mode and deadlock detection is enabled. -static inline void DebugOnlyLockEnter(Mutex* mu, GraphId id) { - if (kDebugMode) { - if (synch_deadlock_detection.load(std::memory_order_acquire) != - OnDeadlockCycle::kIgnore) { - LockEnter(mu, id, Synch_GetAllLocks()); + LockEnter(mu, Synch_GetAllLocks()); } } } @@ -1324,7 +1339,7 @@ static inline void DebugOnlyLockLeave(Mutex* mu) { if (kDebugMode) { if (synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { - LockLeave(mu, GetGraphId(mu), Synch_GetAllLocks()); + LockLeave(mu, Synch_GetAllLocks()); } } } @@ -1384,26 +1399,55 @@ int GetStack(void** stack, int max_depth) { } } // anonymous namespace +// Returns true iff held_locks has an entry that counts for lock ordering, that +// is, one that is not marked forgotten. +static bool HoldsUnforgottenLock(const SynchLocksHeld* held_locks) { + for (int i = 0; i != held_locks->n; i++) { + if (!held_locks->locks[i].forgotten) return true; + } + return false; +} + +// Looks up ids for the entries in held_locks that are not marked forgotten and +// do not have a current id, because this thread has not needed it yet, or +// because another thread called ForgetDeadlockInfo() on that Mutex. +static void UpdateHeldLockIds(SynchLocksHeld* held_locks) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) { + for (int i = 0; i != held_locks->n; i++) { + if (held_locks->locks[i].forgotten) continue; + const GraphId id = held_locks->locks[i].id; + if (id == InvalidGraphId() || deadlock_graph->Ptr(id) == nullptr) { + held_locks->locks[i].id = GetGraphIdLocked(held_locks->locks[i].mu); + } + } +} + // Called in debug mode when a thread is about to acquire a lock in a way that // may block. -static GraphId DeadlockCheck(Mutex* mu) { +static void DeadlockCheck(Mutex* mu) { if (synch_deadlock_detection.load(std::memory_order_acquire) == OnDeadlockCycle::kIgnore) { - return InvalidGraphId(); + return; } SynchLocksHeld* all_locks = Synch_GetAllLocks(); + if (!HoldsUnforgottenLock(all_locks)) { + // There are no other locks held, so there are no edges to add. Return now + // so that we don't need to take deadlock_graph_mu or call GetSynchEvent(). + // This way we do not record the stack trace for this Mutex. It's ok, since + // if this Mutex is involved in a deadlock, it can't always be the first + // lock acquired by a thread. + return; + } + absl::base_internal::SpinLockHolder lock(deadlock_graph_mu); - const GraphId mu_id = GetGraphIdLocked(mu); - if (all_locks->n == 0) { - // There are no other locks held. Return now so that we don't need to - // call GetSynchEvent(). This way we do not record the stack trace - // for this Mutex. It's ok, since if this Mutex is involved in a deadlock, - // it can't always be the first lock acquired by a thread. - return mu_id; - } + // Look up the held locks' ids before mu's, so that when both need new graph + // slots, the held lock's slot ranks below mu's and the edge between them is + // already in rank order. + UpdateHeldLockIds(all_locks); + const GraphId mu_id = GetGraphIdLocked(mu); // We prefer to keep stack traces that show a thread holding and acquiring // as many locks as possible. This increases the chances that a given edge @@ -1413,6 +1457,7 @@ static GraphId DeadlockCheck(Mutex* mu) { // For each other mutex already held by this thread: for (int i = 0; i != all_locks->n; i++) { + if (all_locks->locks[i].forgotten) continue; const GraphId other_node_id = all_locks->locks[i].id; const Mutex* other = static_cast<const Mutex*>(deadlock_graph->Ptr(other_node_id)); @@ -1433,6 +1478,7 @@ static GraphId DeadlockCheck(Mutex* mu) { CurrentStackString(b->buf, sizeof (b->buf), symbolize)); size_t len = 0; for (int j = 0; j != all_locks->n; j++) { + if (all_locks->locks[j].forgotten) continue; void* pr = deadlock_graph->Ptr(all_locks->locks[j].id); if (pr != nullptr) { snprintf(b->buf + len, sizeof(b->buf) - len, " %p", pr); @@ -1467,29 +1513,37 @@ static GraphId DeadlockCheck(Mutex* mu) { OnDeadlockCycle::kAbort) { deadlock_graph_mu.unlock(); // avoid deadlock in fatal sighandler ABSL_RAW_LOG(FATAL, "dying due to potential deadlock"); - return mu_id; } break; // report at most one potential deadlock per acquisition } } - - return mu_id; } // Invoke DeadlockCheck() iff we're in debug mode and // deadlock checking has been enabled. -static inline GraphId DebugOnlyDeadlockCheck(Mutex* mu) { +static inline void DebugOnlyDeadlockCheck(Mutex* mu) { if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { - return DeadlockCheck(mu); - } else { - return InvalidGraphId(); + DeadlockCheck(mu); } } void Mutex::ForgetDeadlockInfo() { if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { + // If this thread holds this Mutex, ignore that hold from now on (see + // SynchLocksHeld::forgotten). Holds by other threads keep counting: + // RemoveNode() makes their ids stale, and DeadlockCheck() looks up the + // new id when they are next needed. + ThreadIdentity* identity = CurrentThreadIdentityIfPresent(); + if (identity != nullptr && + identity->per_thread_synch.all_locks != nullptr) { + SynchLocksHeld* held_locks = identity->per_thread_synch.all_locks; + int i = FindHeldLock(held_locks, this); + if (i != -1) { + held_locks->locks[i].forgotten = true; + } + } deadlock_graph_mu.lock(); if (deadlock_graph != nullptr) { deadlock_graph->RemoveNode(this); @@ -1505,10 +1559,9 @@ void Mutex::AssertNotHeld() const { (mu_.load(std::memory_order_relaxed) & (kMuWriter | kMuReader)) != 0 && synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { - GraphId id = GetGraphId(const_cast<Mutex*>(this)); SynchLocksHeld* locks = Synch_GetAllLocks(); for (int i = 0; i != locks->n; i++) { - if (locks->locks[i].id == id) { + if (locks->locks[i].mu == this) { SynchEvent* mu_events = GetSynchEvent(this); ABSL_RAW_LOG(FATAL, "thread should not hold mutex %p %s", static_cast<const void*>(this), @@ -1538,7 +1591,7 @@ static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) { void Mutex::lock() { ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); - GraphId id = DebugOnlyDeadlockCheck(this); + DebugOnlyDeadlockCheck(this); intptr_t v = mu_.load(std::memory_order_relaxed); // try fast acquire, then spin loop if (ABSL_PREDICT_FALSE((v & (kMuWriter | kMuReader | kMuEvent)) != 0) || @@ -1550,13 +1603,13 @@ void Mutex::lock() { this->LockSlow(kExclusive, nullptr, 0); } } - DebugOnlyLockEnter(this, id); + DebugOnlyLockEnter(this); ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); } void Mutex::lock_shared() { ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); - GraphId id = DebugOnlyDeadlockCheck(this); + DebugOnlyDeadlockCheck(this); intptr_t v = mu_.load(std::memory_order_relaxed); for (;;) { // If there are non-readers holding the lock, use the slow loop. @@ -1572,7 +1625,7 @@ void Mutex::lock_shared() { break; } } - DebugOnlyLockEnter(this, id); + DebugOnlyLockEnter(this); ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0); } @@ -1581,9 +1634,9 @@ bool Mutex::LockWhenCommon(const Condition& cond, bool write) { MuHow how = write ? kExclusive : kShared; ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how)); - GraphId id = DebugOnlyDeadlockCheck(this); + DebugOnlyDeadlockCheck(this); bool res = LockSlowWithDeadline(how, &cond, t, 0); - DebugOnlyLockEnter(this, id); + DebugOnlyLockEnter(this); ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0); return res; } diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.h b/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.h index a2ac32f3eb61..4212d54bd9ce 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.h +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex.h @@ -559,10 +559,11 @@ class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED Mutex { const Condition* absl_nullable cond, synchronization_internal::KernelTimeout t, int flags); - void LockSlow(MuHow absl_nonnull how, const Condition* absl_nullable cond, - int flags) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD void LockSlow(MuHow absl_nonnull how, + const Condition* absl_nullable cond, + int flags); // slow path release - void UnlockSlow(SynchWaitParams* absl_nullable waitp) ABSL_ATTRIBUTE_COLD; + ABSL_ATTRIBUTE_COLD void UnlockSlow(SynchWaitParams* absl_nullable waitp); // TryLock slow path. bool TryLockSlow(); // ReaderTryLock slow path. diff --git a/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex_test.cc b/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex_test.cc index a96bcff7ebf8..50b982ee4e6c 100644 --- a/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/synchronization/mutex_test.cc @@ -1357,6 +1357,288 @@ TEST(Mutex, DeadlockIdBug) ABSL_NO_THREAD_SAFETY_ANALYSIS { c.unlock(); } +// The tests below check what the deadlock detector reports, so they need it to +// be compiled in. Under TSAN, the lock cycles they create would also trigger +// TSAN's own reports. +#if !defined(NDEBUG) && !defined(ABSL_HAVE_THREAD_SANITIZER) +TEST(Mutex, DeadlockDetectorReportsCycle) ABSL_NO_THREAD_SAFETY_ANALYSIS { + EXPECT_DEATH_IF_SUPPORTED( + { + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex a; + absl::Mutex b; + // Record a -> b. a is acquired with try_lock() while no other lock is + // held, so its hold must be recorded without a deadlock check. + ASSERT_TRUE(a.try_lock()); + b.lock(); + b.unlock(); + a.unlock(); + // Acquiring a while holding b closes the cycle. + b.lock(); + a.lock(); + }, + "dying due to potential deadlock"); +} + +// ForgetDeadlockInfo(), which ~Mutex() also calls, must remove the lock order +// recorded for the Mutex, including by other threads. +TEST(Mutex, ForgetDeadlockInfoForgetsLockOrder) +ABSL_NO_THREAD_SAFETY_ANALYSIS { + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex a; + absl::Mutex b; + std::thread other([&]() ABSL_NO_THREAD_SAFETY_ANALYSIS { + a.lock(); + b.lock(); // Records a -> b. + b.unlock(); + a.unlock(); + }); + other.join(); + a.ForgetDeadlockInfo(); + // With a -> b forgotten, acquiring a while holding b is not a cycle. + b.lock(); + a.lock(); + a.unlock(); + b.unlock(); +} + +TEST(Mutex, ForgetDeadlockInfoWhileHeldDoesNotMaskOtherHeldLocks) +ABSL_NO_THREAD_SAFETY_ANALYSIS { + EXPECT_DEATH_IF_SUPPORTED( + { + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex a; + absl::Mutex b; + absl::Mutex c; + // Record c -> a. + c.lock(); + a.lock(); + a.unlock(); + c.unlock(); + // Forgetting b while holding a and b must ignore only the hold of b. + a.lock(); + ASSERT_TRUE(b.try_lock_shared()); + b.ForgetDeadlockInfo(); + b.unlock_shared(); + // Acquiring c while holding a closes the cycle. + c.lock(); + }, + "dying due to potential deadlock"); +} + +// Forgetting a Mutex while another thread is blocked acquiring it must not +// hide the lock order of that thread's hold once it acquires the Mutex. +TEST(Mutex, ForgetDeadlockInfoWhileWaiterBlockedDoesNotMaskSubsequentHold) +ABSL_NO_THREAD_SAFETY_ANALYSIS { + for (bool waiter_holds_other_lock : {false, true}) { + EXPECT_DEATH_IF_SUPPORTED( + { + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex other; + absl::Mutex a; + absl::Mutex b; + std::atomic<bool> about_to_lock{false}; + { + a.lock_shared(); + absl::synchronization_internal::ThreadPool pool(1); + pool.Schedule([&]() ABSL_NO_THREAD_SAFETY_ANALYSIS { + // If the waiter holds another lock, the deadlock check looks up + // the deadlock graph node of a before the waiter blocks. + if (waiter_holds_other_lock) other.lock(); + about_to_lock.store(true, std::memory_order_release); + a.lock(); // Blocks until a.unlock_shared() below. + b.lock(); // Records a -> b. + b.unlock(); + a.unlock(); + if (waiter_holds_other_lock) other.unlock(); + }); + while (!about_to_lock.load(std::memory_order_acquire)) { + absl::SleepFor(absl::Milliseconds(1)); + } + absl::SleepFor(absl::Milliseconds(20)); // Let the waiter block. + a.ForgetDeadlockInfo(); + a.unlock_shared(); + } + // Acquiring a while holding b closes the cycle. + b.lock(); + a.lock(); + }, + "dying due to potential deadlock"); + } +} + +// A hold by another thread keeps counting for lock ordering after +// ForgetDeadlockInfo(), even if that thread already used it to record lock +// order before the Mutex was forgotten. +TEST(Mutex, ForgetDeadlockInfoDoesNotMaskOtherThreadsHold) +ABSL_NO_THREAD_SAFETY_ANALYSIS { + EXPECT_DEATH_IF_SUPPORTED( + { + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex a; + absl::Mutex b; + absl::Mutex c; + std::atomic<bool> recorded{false}; + std::atomic<bool> forgotten{false}; + std::thread holder([&]() ABSL_NO_THREAD_SAFETY_ANALYSIS { + a.lock(); + b.lock(); // Records a -> b. + b.unlock(); + recorded.store(true, std::memory_order_release); + while (!forgotten.load(std::memory_order_acquire)) { + absl::SleepFor(absl::Milliseconds(1)); + } + c.lock(); // Records a -> c, although a was forgotten. + c.unlock(); + a.unlock(); + }); + while (!recorded.load(std::memory_order_acquire)) { + absl::SleepFor(absl::Milliseconds(1)); + } + a.ForgetDeadlockInfo(); + forgotten.store(true, std::memory_order_release); + holder.join(); + // Acquiring a while holding c closes the cycle. + c.lock(); + a.lock(); + }, + "dying due to potential deadlock"); +} + +// Same, for a thread that waits on a CondVar: it is still considered to hold +// the Mutex while it waits. +TEST(Mutex, ForgetDeadlockInfoDuringCondVarWaitDoesNotMaskReacquiredHold) +ABSL_NO_THREAD_SAFETY_ANALYSIS { + EXPECT_DEATH_IF_SUPPORTED( + { + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex a; + absl::Mutex b; + absl::CondVar cv; + bool ready = false; + std::atomic<bool> waiting{false}; + { + absl::synchronization_internal::ThreadPool pool(1); + pool.Schedule([&]() ABSL_NO_THREAD_SAFETY_ANALYSIS { + a.lock(); + waiting.store(true, std::memory_order_release); + while (!ready) { + cv.Wait(&a); + } + b.lock(); // Records a -> b. + b.unlock(); + a.unlock(); + }); + while (!waiting.load(std::memory_order_acquire)) { + absl::SleepFor(absl::Milliseconds(1)); + } + absl::SleepFor(absl::Milliseconds(20)); // Let the waiter wait. + a.ForgetDeadlockInfo(); + a.lock(); + ready = true; + cv.Signal(); + a.unlock(); + } + // Acquiring a while holding b closes the cycle. + b.lock(); + a.lock(); + }, + "dying due to potential deadlock"); +} + +TEST(Mutex, ForgetDeadlockInfoWhileHoldingManyLocks) +ABSL_NO_THREAD_SAFETY_ANALYSIS { + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + // Use a new thread: the list of held locks overflows and sets the thread's + // overflow flag. + std::thread thread([]() ABSL_NO_THREAD_SAFETY_ANALYSIS { + // More locks than the deadlock detector can track per thread. + constexpr int kNumLocks = 42; + absl::Mutex mutexes[kNumLocks]; + mutexes[0].lock(); + mutexes[0].ForgetDeadlockInfo(); + for (int i = 1; i < kNumLocks; ++i) { + mutexes[i].lock(); + } + for (int i = kNumLocks - 1; i >= 0; --i) { + mutexes[i].unlock(); + } + }); + thread.join(); + + // Repeatedly forgetting a held lock and unlocking it, or destroying a locked + // Mutex, must not leak slots in the thread's held-locks array. + EXPECT_DEATH_IF_SUPPORTED( + { + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex m; + for (int i = 0; i < 50; ++i) { + m.lock(); + m.ForgetDeadlockInfo(); + m.unlock(); + } + auto destroyed_locked = std::make_unique<absl::Mutex[]>(50); + for (size_t i = 0; i < 50; ++i) { + destroyed_locked[i].lock(); + } + destroyed_locked.reset(); + absl::Mutex a; + absl::Mutex b; + a.lock(); + b.lock(); + b.unlock(); + a.unlock(); + b.lock(); + a.lock(); + }, + "dying due to potential deadlock"); +} + +TEST(Mutex, AssertNotHeld) ABSL_NO_THREAD_SAFETY_ANALYSIS { + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); + absl::Mutex mu; + mu.AssertNotHeld(); + + // A hold by another thread does not count. + std::atomic<bool> held{false}; + std::atomic<bool> release{false}; + std::thread holder([&]() ABSL_NO_THREAD_SAFETY_ANALYSIS { + mu.lock(); + held.store(true, std::memory_order_release); + while (!release.load(std::memory_order_acquire)) { + absl::SleepFor(absl::Milliseconds(1)); + } + mu.unlock(); + }); + while (!held.load(std::memory_order_acquire)) { + absl::SleepFor(absl::Milliseconds(1)); + } + mu.AssertNotHeld(); + release.store(true, std::memory_order_release); + holder.join(); + + EXPECT_DEATH_IF_SUPPORTED( + { + mu.lock(); + mu.AssertNotHeld(); + }, + "thread should not hold mutex"); + EXPECT_DEATH_IF_SUPPORTED( + { + mu.lock(); + mu.ForgetDeadlockInfo(); + mu.AssertNotHeld(); + }, + "thread should not hold mutex"); +} +#endif // !defined(NDEBUG) && !defined(ABSL_HAVE_THREAD_SANITIZER) + // -------------------------------------------------------- // Test for timeouts/deadlines on condition waits that are specified using // absl::Duration and absl::Time. For each waiting function we test with diff --git a/deps/v8/third_party/abseil-cpp/absl/time/BUILD.bazel b/deps/v8/third_party/abseil-cpp/absl/time/BUILD.bazel index eaea38ab32cf..347e24b2154c 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/BUILD.bazel +++ b/deps/v8/third_party/abseil-cpp/absl/time/BUILD.bazel @@ -181,6 +181,7 @@ cc_test( ], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + shard_count = 4, deps = [ ":clock_interface", ":simulated_clock", diff --git a/deps/v8/third_party/abseil-cpp/absl/time/CMakeLists.txt b/deps/v8/third_party/abseil-cpp/absl/time/CMakeLists.txt index b141b62d73d6..79b99e84826d 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/CMakeLists.txt +++ b/deps/v8/third_party/abseil-cpp/absl/time/CMakeLists.txt @@ -202,6 +202,8 @@ absl_cc_test( absl::synchronization absl::time GTest::gmock_main + SHARD_COUNT + 4 ) absl_cc_test( diff --git a/deps/v8/third_party/abseil-cpp/absl/time/civil_time.cc b/deps/v8/third_party/abseil-cpp/absl/time/civil_time.cc index a70424793371..76dbcafad966 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/civil_time.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/civil_time.cc @@ -16,6 +16,7 @@ #include <cerrno> #include <cstdlib> +#include <limits> #include <ostream> #include <string> @@ -68,7 +69,15 @@ bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) { // end-of-year rollover) can carry into the year. The other fields are taken // from `cs`, so the same carry must be applied to the original year; // otherwise the reconstructed value would use the wrong (un-carried) year. - const civil_year_t year = y + (cs.year() - normalized_year); + // `cs.year()` and `normalized_year` both lie in the normalized range, so + // the carry is small, but applying it to `y` can overflow civil_year_t when + // `y` is at the extreme representable year; reject that rather than wrap. + const civil_year_t carry = cs.year() - normalized_year; + if ((carry > 0 && y > (std::numeric_limits<civil_year_t>::max)() - carry) || + (carry < 0 && y < (std::numeric_limits<civil_year_t>::min)() - carry)) { + return false; + } + const civil_year_t year = y + carry; *c = CivilT(year, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second()); return true; diff --git a/deps/v8/third_party/abseil-cpp/absl/time/civil_time_test.cc b/deps/v8/third_party/abseil-cpp/absl/time/civil_time_test.cc index 3f03fc1c5900..53f52a508cff 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/civil_time_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/civil_time_test.cc @@ -873,6 +873,19 @@ TEST(CivilTime, ParseFieldNormalizationCarriesYear) { EXPECT_EQ(absl::CivilSecond(0, 1, 1, 0, 0, 0), ss); } +TEST(CivilTime, ParseYearCarryDoesNotOverflow) { + // A ":60" leap second on the last second of the maximum representable year + // carries into the year, which would be civil_year_t(max) + 1 and is not + // representable, so the parse must fail cleanly rather than overflow. + absl::CivilSecond ss; + EXPECT_FALSE(absl::ParseCivilTime("9223372036854775807-12-31T23:59:60", &ss)) + << ss; + // The same year without a carry remains valid and round-trips. + EXPECT_TRUE(absl::ParseCivilTime("9223372036854775807-12-31T23:59:59", &ss)) + << ss; + EXPECT_EQ("9223372036854775807-12-31T23:59:59", absl::FormatCivilTime(ss)); +} + TEST(CivilTime, AbslStringify) { static_assert(absl::HasAbslStringify<absl::CivilSecond>::value); static_assert(absl::HasAbslStringify<absl::CivilMinute>::value); diff --git a/deps/v8/third_party/abseil-cpp/absl/time/clock.cc b/deps/v8/third_party/abseil-cpp/absl/time/clock.cc index d368659e0163..1e0f6a03d5b1 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/clock.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/clock.cc @@ -271,7 +271,7 @@ static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock, return current_time_nanos_from_system; } -static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD; +ABSL_ATTRIBUTE_COLD static int64_t GetCurrentTimeNanosSlowPath(); // Read the contents of *atomic into *sample. // Each field is read atomically, but to maintain atomicity between fields, @@ -399,9 +399,9 @@ static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) { return quotient; } -static uint64_t UpdateLastSample( +ABSL_ATTRIBUTE_COLD static uint64_t UpdateLastSample( uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles, - const struct TimeSample* sample) ABSL_ATTRIBUTE_COLD; + const struct TimeSample* sample); // The slow path of GetCurrentTimeNanos(). This is taken while gathering // initial samples, when enough time has elapsed since the last sample, and if diff --git a/deps/v8/third_party/abseil-cpp/absl/time/clock_interface.h b/deps/v8/third_party/abseil-cpp/absl/time/clock_interface.h index a14d85291a2b..ef3be13e17f2 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/clock_interface.h +++ b/deps/v8/third_party/abseil-cpp/absl/time/clock_interface.h @@ -55,7 +55,7 @@ ABSL_NAMESPACE_BEGIN // MyTestClock test_clock(SATURDAY); // IsWeekend(test_clock); // -class Clock { +class ABSL_DLL Clock { public: // Returns a reference to the global realtime clock. // The returned clock is thread-safe. diff --git a/deps/v8/third_party/abseil-cpp/absl/time/duration.cc b/deps/v8/third_party/abseil-cpp/absl/time/duration.cc index 487ccdd87b2d..160e25336750 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/duration.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/duration.cc @@ -64,6 +64,7 @@ #include "absl/base/attributes.h" #include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/optimization.h" #include "absl/numeric/int128.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" @@ -417,9 +418,15 @@ int64_t IDivDuration(Duration num, Duration den, Duration* rem) { Duration& Duration::operator+=(Duration rhs) { if (time_internal::IsInfiniteDuration(*this)) return *this; if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs; + // Once we know the operands are finite, we can assume the low (subsecond) + // part of the representation is less than kTicksPerSecond. + ABSL_ASSUME(rep_lo_ < kTicksPerSecond); + ABSL_ASSUME(rhs.rep_lo_ < kTicksPerSecond); const int64_t orig_rep_hi = rep_hi_.Get(); rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_.Get()) + EncodeTwosComp(rhs.rep_hi_.Get())); + // The ABSL_ASSUMEs above prevent the compiler from emitting unreachable carry + // logic for the next line. if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) { rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_.Get()) + 1); rep_lo_ -= kTicksPerSecond; @@ -897,7 +904,16 @@ bool ParseDuration(absl::string_view dur_sv, Duration* d) { return false; } if (int_part != 0) dur += sign * int_part * unit; - if (frac_part != 0) dur += sign * frac_part * unit / frac_scale; + if (frac_part != 0) { + // Scale the unit's tick count directly rather than forming + // frac_part * unit as a Duration first: for a long fraction of a large + // unit (e.g. "0.3000000000000000h") that product saturates to infinity + // before the division by frac_scale can bring it back into range. + const uint128 ticks = MakeU128Ticks(unit) * + static_cast<uint64_t>(frac_part) / + static_cast<uint64_t>(frac_scale); + dur += MakeDurationFromU128(ticks, sign < 0); + } } *d = dur; return true; diff --git a/deps/v8/third_party/abseil-cpp/absl/time/duration_test.cc b/deps/v8/third_party/abseil-cpp/absl/time/duration_test.cc index 8fffa954f1c0..6645c53c1337 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/duration_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/duration_test.cc @@ -1831,6 +1831,17 @@ TEST(Duration, ParseDuration) { EXPECT_TRUE(absl::ParseDuration("0.429496729501234567890123456789s", &d)); EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d); + // Huge fractional counts of a large unit. The scaled intermediate must not + // saturate to infinity before it is divided back down. + EXPECT_TRUE(absl::ParseDuration("0.3000000000000000h", &d)); + EXPECT_EQ(absl::Minutes(18), d); + EXPECT_TRUE(absl::ParseDuration("0.200000000000000000m", &d)); + EXPECT_EQ(absl::Seconds(12), d); + EXPECT_TRUE(absl::ParseDuration("0.999999999999999999h", &d)); + EXPECT_EQ(absl::Hours(1) - absl::Nanoseconds(1) / 4, d); + EXPECT_TRUE(absl::ParseDuration("-0.999999999999999999h", &d)); + EXPECT_EQ(-(absl::Hours(1) - absl::Nanoseconds(1) / 4), d); + // Negative durations. EXPECT_TRUE(absl::ParseDuration("-1s", &d)); EXPECT_EQ(absl::Seconds(-1), d); diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h index 5b232f51b839..7acce2f62be6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h @@ -25,6 +25,7 @@ #include <limits> #include <ratio> // NOLINT: We use std::ratio in this header #include <string> +#include <type_traits> #include <utility> #include "absl/base/config.h" @@ -271,15 +272,20 @@ std::string format(const std::string&, const time_point<seconds>&, bool parse(const std::string&, const std::string&, const time_zone&, time_point<seconds>*, femtoseconds*, std::string* err = nullptr); template <typename Rep, std::intmax_t Denom> -bool join_seconds( +typename std::enable_if<std::is_integral<Rep>::value, bool>::type join_seconds( const time_point<seconds>& sec, const femtoseconds& fs, time_point<std::chrono::duration<Rep, std::ratio<1, Denom>>>* tpp); +template <typename Rep, std::intmax_t Num, std::intmax_t Denom> +typename std::enable_if<std::is_floating_point<Rep>::value, bool>::type +join_seconds( + const time_point<seconds>& sec, const femtoseconds& fs, + time_point<std::chrono::duration<Rep, std::ratio<Num, Denom>>>* tpp); template <typename Rep, std::intmax_t Num> -bool join_seconds( +typename std::enable_if<std::is_integral<Rep>::value, bool>::type join_seconds( const time_point<seconds>& sec, const femtoseconds& fs, time_point<std::chrono::duration<Rep, std::ratio<Num, 1>>>* tpp); template <typename Rep> -bool join_seconds( +typename std::enable_if<std::is_integral<Rep>::value, bool>::type join_seconds( const time_point<seconds>& sec, const femtoseconds& fs, time_point<std::chrono::duration<Rep, std::ratio<1, 1>>>* tpp); bool join_seconds(const time_point<seconds>& sec, const femtoseconds&, @@ -369,13 +375,19 @@ inline std::string format(const std::string& fmt, const time_point<D>& tp, // if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) { // ... // } -template <typename D> -inline bool parse(const std::string& fmt, const std::string& input, - const time_zone& tz, time_point<D>* tpp) { +template <typename Rep, typename Period> +bool parse(const std::string& fmt, const std::string& input, + const time_zone& tz, + time_point<std::chrono::duration<Rep, Period>>* tpp) { time_point<seconds> sec; detail::femtoseconds fs; - return detail::parse(fmt, input, tz, &sec, &fs) && - detail::join_seconds(sec, fs, tpp); + if (!detail::parse(fmt, input, tz, &sec, &fs)) return false; + + time_point<std::chrono::duration<Rep, typename Period::type>> tp; + if (!detail::join_seconds(sec, fs, &tp)) return false; + + *tpp = tp; + return true; } namespace detail { @@ -389,9 +401,15 @@ template <typename D> std::pair<time_point<seconds>, D> split_seconds(const time_point<D>& tp) { auto sec = std::chrono::time_point_cast<seconds>(tp); auto sub = tp - sec; - if (sub.count() < 0) { - sec -= seconds(1); - sub += seconds(1); + // time_point_cast truncates towards zero, so for negative tp with fractional + // seconds (e.g., -1.5s), sec is truncated (-1s) and sub is negative (-0.5s). + // Adjust sec and sub so that sec is floored (-2s) and sub is in [0, 1s) + // (+0.5s). This adjustment is done after computing sub to avoid overflow + // when tp is near time_point<D>::min(), where floored sec cannot be converted + // to D. + if (sub < D::zero()) { + sec -= seconds{1}; + sub += seconds{1}; } return {sec, std::chrono::duration_cast<D>(sub)}; } @@ -405,18 +423,58 @@ inline std::pair<time_point<seconds>, seconds> split_seconds( // Floors to the resolution of time_point<D>. Returns false if time_point<D> // is not of sufficient range. template <typename Rep, std::intmax_t Denom> -bool join_seconds( +typename std::enable_if<std::is_integral<Rep>::value, bool>::type join_seconds( const time_point<seconds>& sec, const femtoseconds& fs, time_point<std::chrono::duration<Rep, std::ratio<1, Denom>>>* tpp) { using D = std::chrono::duration<Rep, std::ratio<1, Denom>>; - // TODO(#199): Return false if result unrepresentable as a time_point<D>. + using D_check = std::chrono::duration<std::intmax_t, std::ratio<1, Denom>>; + const std::intmax_t count = sec.time_since_epoch().count(); + const auto sub = + std::chrono::duration_cast<D_check>(fs).count(); // [0, Denom) + + // Check for overflow. + if (sub > (std::numeric_limits<Rep>::max)()) { + // If subseconds alone exceed the max representable value, any non-negative + // seconds count will cause overflow. Negative seconds might bring it back + // into range, which is handled by the underflow check below. + if (count >= 0) return false; + } else { + // Equivalent to: count * Denom + sub > max, but safe from overflow. + if (count > ((std::numeric_limits<Rep>::max)() - sub) / Denom) return false; + } + + // Check for underflow. + // Equivalent to: count * Denom + sub < lowest, but safe from underflow. + // We cannot use "lowest - sub" directly as it would underflow. + const auto min_div = (std::numeric_limits<Rep>::lowest)() / Denom; + if (count < min_div) { + // If count is less than min_div - 1, it's definitely underflow. + if (count < min_div - 1) return false; + // If count is exactly min_div - 1, we must check if subseconds are + // sufficient to bring the total value back above lowest. + const auto min_mod = (std::numeric_limits<Rep>::lowest)() % Denom; + if (sub < Denom + min_mod) return false; + *tpp = + time_point<D>() + D{static_cast<Rep>(min_div * Denom + (sub - Denom))}; + return true; + } + *tpp = time_point<D>() + D{static_cast<Rep>(count * Denom + sub)}; + return true; +} + +template <typename Rep, std::intmax_t Num, std::intmax_t Denom> +typename std::enable_if<std::is_floating_point<Rep>::value, bool>::type +join_seconds( + const time_point<seconds>& sec, const femtoseconds& fs, + time_point<std::chrono::duration<Rep, std::ratio<Num, Denom>>>* tpp) { + using D = std::chrono::duration<Rep, std::ratio<Num, Denom>>; *tpp = std::chrono::time_point_cast<D>(sec); *tpp += std::chrono::duration_cast<D>(fs); return true; } template <typename Rep, std::intmax_t Num> -bool join_seconds( +typename std::enable_if<std::is_integral<Rep>::value, bool>::type join_seconds( const time_point<seconds>& sec, const femtoseconds&, time_point<std::chrono::duration<Rep, std::ratio<Num, 1>>>* tpp) { using D = std::chrono::duration<Rep, std::ratio<Num, 1>>; @@ -428,19 +486,19 @@ bool join_seconds( count -= 1; } if (count > (std::numeric_limits<Rep>::max)()) return false; - if (count < (std::numeric_limits<Rep>::min)()) return false; + if (count < (std::numeric_limits<Rep>::lowest)()) return false; *tpp = time_point<D>() + D{static_cast<Rep>(count)}; return true; } template <typename Rep> -bool join_seconds( +typename std::enable_if<std::is_integral<Rep>::value, bool>::type join_seconds( const time_point<seconds>& sec, const femtoseconds&, time_point<std::chrono::duration<Rep, std::ratio<1, 1>>>* tpp) { using D = std::chrono::duration<Rep, std::ratio<1, 1>>; auto count = sec.time_since_epoch().count(); if (count > (std::numeric_limits<Rep>::max)()) return false; - if (count < (std::numeric_limits<Rep>::min)()) return false; + if (count < (std::numeric_limits<Rep>::lowest)()) return false; *tpp = time_point<D>() + D{static_cast<Rep>(count)}; return true; } diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc index 17ff576f79ef..94571140cbb2 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc @@ -262,7 +262,7 @@ void BM_Time_ToCivil_Libc(benchmark::State& state) { while (state.KeepRunning()) { std::swap(t, t2); t += 1; -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) benchmark::DoNotOptimize(localtime_s(&tm, &t)); #else benchmark::DoNotOptimize(localtime_r(&t, &tm)); @@ -287,7 +287,7 @@ void BM_Time_ToCivilUTC_Libc(benchmark::State& state) { struct tm tm; while (state.KeepRunning()) { t += 1; -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) benchmark::DoNotOptimize(gmtime_s(&tm, &t)); #else benchmark::DoNotOptimize(gmtime_r(&t, &tm)); diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc index f97de2f95927..c2839eafd482 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc @@ -34,6 +34,7 @@ // declare strptime. #include <time.h> +#include <cassert> #include <cctype> #include <chrono> #include <cstddef> @@ -197,7 +198,7 @@ char* FormatOffset(char* ep, int offset, const char* mode) { // as the result of a failed load_time_zone(). char sign = '+'; if (offset < 0) { - offset = -offset; // bounded by 24h so no overflow + offset = -offset; // bounded by -25h so no overflow sign = '-'; } const int seconds = offset % 60; @@ -218,7 +219,7 @@ char* FormatOffset(char* ep, int offset, const char* mode) { ep = Format02d(ep, minutes); if (sep != '\0') *--ep = sep; } - ep = Format02d(ep, hours); + ep = Format02d(ep, hours); // bounded by 26h so fits in two digits *--ep = sign; return ep; } @@ -708,6 +709,14 @@ bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) { bool parse(const std::string& format, const std::string& input, const time_zone& tz, time_point<seconds>* sec, detail::femtoseconds* fs, std::string* err) { +#if __cplusplus < 202002L + // Assert that the std::chrono::system_clock epoch is the Unix epoch. + // This is required by C++20, but was also ubiquitous before that. + // We use this in join_seconds() to simplify overflow detection. + assert(std::chrono::system_clock::from_time_t(0).time_since_epoch() == + std::chrono::system_clock::duration::zero()); +#endif + // The unparsed input. Even though we allow NULs in input, and // match them against corresponding NULs in format, we depend on // *edata being a NUL so that we can call strptime(). This also diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc index 8793a805c662..da3ff5022f41 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -15,6 +15,7 @@ #include <chrono> #include <cstdint> #include <iomanip> +#include <ratio> // NOLINT: We use std::ratio in this header #include <sstream> #include <string> @@ -229,6 +230,10 @@ TEST(Format, LocaleSpecific) { TestFormatSpecifier(tp, tz, "%x", "01/01/70"); TestFormatSpecifier(tp, tz, "%X", "00:00:00"); + // %I renders midnight and noon as 12, with %p disambiguating them. + TestFormatSpecifier(tp, tz, "%I %p", "12 AM"); + TestFormatSpecifier(tp + chrono::hours(12), tz, "%I %p", "12 PM"); + #if defined(__linux__) // SU/C99/TZ extensions TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b @@ -863,9 +868,19 @@ TEST(Parse, TimePointResolution) { EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m)); EXPECT_EQ("03:04:00", absl::time_internal::cctz::format(kFmt, tp_m, utc)); + // Verify that pre-epoch times floor towards negative infinity. + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:59:05+00:00", utc, &tp_m)); + EXPECT_EQ("1969-12-31T23:59:00+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp_m, utc)); + time_point<chrono::hours> tp_h; EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h)); EXPECT_EQ("03:00:00", absl::time_internal::cctz::format(kFmt, tp_h, utc)); + + // Verify that pre-epoch times floor towards negative infinity. + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:59:05+00:00", utc, &tp_h)); + EXPECT_EQ("1969-12-31T23:00:00+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp_h, utc)); } TEST(Parse, TimePointExtendedResolution) { @@ -1161,6 +1176,22 @@ TEST(Parse, LocaleSpecific) { EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp)); EXPECT_EQ(17, convert(tp, tz).hour()); + // %I maps 12 to 0 and a following %p shifts to the afternoon, + // so "12 AM" is midnight and "12 PM" is noon. + tp = reset; + EXPECT_TRUE(parse("%I %p", "12 AM", tz, &tp)); + EXPECT_EQ(0, convert(tp, tz).hour()); + tp = reset; + EXPECT_TRUE(parse("%I %p", "12 PM", tz, &tp)); + EXPECT_EQ(12, convert(tp, tz).hour()); + + tp = reset; + EXPECT_TRUE(parse("%I %p", "01 AM", tz, &tp)); + EXPECT_EQ(1, convert(tp, tz).hour()); + tp = reset; + EXPECT_TRUE(parse("%I %p", "11 PM", tz, &tp)); + EXPECT_EQ(23, convert(tp, tz).hour()); + tp = reset; EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp)); if (convert(tp, tz).month() == 2) { @@ -1196,6 +1227,19 @@ TEST(Parse, LocaleSpecific) { EXPECT_EQ(44, convert(tp, tz).minute()); EXPECT_EQ(55, convert(tp, tz).second()); + // %r must land on the correct side of the AM/PM boundary too. + tp = reset; + EXPECT_TRUE(parse("%r", "12:00:00 AM", tz, &tp)); + EXPECT_EQ(0, convert(tp, tz).hour()); + EXPECT_EQ(0, convert(tp, tz).minute()); + EXPECT_EQ(0, convert(tp, tz).second()); + + tp = reset; + EXPECT_TRUE(parse("%r", "12:00:00 PM", tz, &tp)); + EXPECT_EQ(12, convert(tp, tz).hour()); + EXPECT_EQ(0, convert(tp, tz).minute()); + EXPECT_EQ(0, convert(tp, tz).second()); + #if defined(__GLIBC__) tp = reset; EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp)); @@ -1708,57 +1752,193 @@ TEST(Parse, MaxRange) { TEST(Parse, TimePointOverflow) { const time_zone utc = utc_time_zone(); + { + // Test with nanosecond resolution (typical 64-bit time_point). + using D = chrono::duration<std::int64_t, std::nano>; + time_point<D> tp; + + // Max time_point<D> is 2262-04-11T23:47:16.854775807+00:00. + EXPECT_TRUE( + parse(RFC3339_full, "2262-04-11T23:47:16.8547758079+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::max()); + EXPECT_EQ("2262-04-11T23:47:16.854775807+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 nanosecond beyond max should fail. + EXPECT_FALSE( + parse(RFC3339_full, "2262-04-11T23:47:16.8547758080+00:00", utc, &tp)); + + // Min time_point<D> is 1677-09-21T00:12:43.145224192+00:00. + EXPECT_TRUE( + parse(RFC3339_full, "1677-09-21T00:12:43.1452241920+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::min()); + EXPECT_EQ("1677-09-21T00:12:43.145224192+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 nanosecond below min should fail. + EXPECT_FALSE( + parse(RFC3339_full, "1677-09-21T00:12:43.1452241919+00:00", utc, &tp)); + } + { + // Test with femtosecond resolution. + using D = chrono::duration<std::int64_t, std::femto>; + time_point<D> tp; + + // Max time_point<D> is 1970-01-01T02:33:43.372036854775807+00:00. + EXPECT_TRUE(parse(RFC3339_full, + "1970-01-01T02:33:43.3720368547758079+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), time_point<D>::max().time_since_epoch()); + EXPECT_EQ("1970-01-01T02:33:43.372036854775807+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 femtosecond beyond max should fail. + EXPECT_FALSE(parse(RFC3339_full, + "1970-01-01T02:33:43.3720368547758080+00:00", utc, &tp)); + + // Min time_point<D> is 1969-12-31T21:26:16.627963145224192+00:00. + EXPECT_TRUE(parse(RFC3339_full, + "1969-12-31T21:26:16.6279631452241920+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), time_point<D>::min().time_since_epoch()); + EXPECT_EQ("1969-12-31T21:26:16.627963145224192+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 femtosecond below min should fail. + EXPECT_FALSE(parse(RFC3339_full, + "1969-12-31T21:26:16.6279631452241919+00:00", utc, &tp)); + } + { + // Test with attosecond resolution. + using D = chrono::duration<std::int64_t, std::atto>; + time_point<D> tp; + + // Max time_point<D> is 1970-01-01T00:00:09.223372036854775807+00:00, + // but cctz::parse() truncates (towards zero) to a femtosecond boundary, + // so the last three decimal places are lost. + EXPECT_TRUE(parse(RFC3339_full, + "1970-01-01T00:00:09.223372036854775807+00:00", utc, + &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{9223372036854775000LL}); + EXPECT_EQ("1970-01-01T00:00:09.223372036854775+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // Moving into the next femtosecond should fail. + EXPECT_FALSE(parse(RFC3339_full, + "1970-01-01T00:00:09.223372036854776000+00:00", utc, + &tp)); + + // Min time_point<D> is 1969-12-31T23:59:50.776627963145224192+00:00, + // but cctz::parse() truncates (towards zero) to a femtosecond boundary, + // so we must round up. + EXPECT_TRUE(parse(RFC3339_full, + "1969-12-31T23:59:50.776627963145225000+00:00", utc, + &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{-9223372036854775000LL}); + EXPECT_EQ("1969-12-31T23:59:50.776627963145225+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 attosecond below min should fail. + EXPECT_FALSE(parse(RFC3339_full, + "1969-12-31T23:59:50.776627963145224999+00:00", utc, + &tp)); + } + { + // Test with 1-second resolution using int8_t ([-128, 127] seconds). + using D = chrono::duration<std::int8_t>; + time_point<D> tp; + + // Max time_point<D> is 1970-01-01T00:02:07+00:00. + EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T00:02:07.9+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::max()); + EXPECT_EQ("1970-01-01T00:02:07+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 second beyond max should fail. + EXPECT_FALSE(parse(RFC3339_full, "1970-01-01T00:02:08+00:00", utc, &tp)); + + // Min time_point<D> is 1969-12-31T23:57:52+00:00. + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:57:52+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::min()); + EXPECT_EQ("1969-12-31T23:57:52+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 second below min should fail. + EXPECT_FALSE(parse(RFC3339_full, "1969-12-31T23:57:51+00:00", utc, &tp)); + } + { + // Test with 1-minute resolution using int8_t ([-128, 127] minutes). + using D = chrono::duration<std::int8_t, std::ratio<60>>; + time_point<D> tp; + + // Max time_point<D> is 1970-01-01T02:07:00+00:00. + EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T02:07:00+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::max()); + EXPECT_EQ("1970-01-01T02:07:00+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 minute beyond max should fail. + EXPECT_FALSE(parse(RFC3339_full, "1970-01-01T02:08:00+00:00", utc, &tp)); + + // Min time_point<D> is 1969-12-31T21:52:00+00:00. + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T21:52:00+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::min()); + EXPECT_EQ("1969-12-31T21:52:00+00:00", + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); + // 1 minute below min should fail. + EXPECT_FALSE(parse(RFC3339_full, "1969-12-31T21:51:00+00:00", utc, &tp)); + } + { + // Test with millisecond resolution using int8_t ([-128, 127] milliseconds). + // This tests the case where Denom (1000) is larger than Rep max/min. + using D = chrono::duration<std::int8_t, std::milli>; + time_point<D> tp; + + // Max time_point<D> is 1970-01-01T00:00:00.127+00:00. + EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T00:00:00.127+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::max()); + // 1 millisecond beyond max should fail (tests sub > max check). + EXPECT_FALSE( + parse(RFC3339_full, "1970-01-01T00:00:00.128+00:00", utc, &tp)); + + // Min time_point<D> is 1969-12-31T23:59:59.872+00:00. + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:59:59.872+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<D>::min()); + // 1 millisecond below min should fail (tests min with Denom > -min). + EXPECT_FALSE( + parse(RFC3339_full, "1969-12-31T23:59:59.871+00:00", utc, &tp)); + } +} - using D = chrono::duration<std::int64_t, std::nano>; - time_point<D> tp; +TEST(Parse, TimePointFloatingPoint) { + const time_zone utc = utc_time_zone(); + { + using D = chrono::duration<double>; + time_point<D> tp; - EXPECT_TRUE( - parse(RFC3339_full, "2262-04-11T23:47:16.8547758079+00:00", utc, &tp)); - EXPECT_EQ(tp, time_point<D>::max()); - EXPECT_EQ("2262-04-11T23:47:16.854775807+00:00", - absl::time_internal::cctz::format(RFC3339_full, tp, utc)); -#if 0 - // TODO(#199): Will fail until cctz::parse() properly detects overflow. - EXPECT_FALSE( - parse(RFC3339_full, "2262-04-11T23:47:16.8547758080+00:00", utc, &tp)); - EXPECT_TRUE( - parse(RFC3339_full, "1677-09-21T00:12:43.1452241920+00:00", utc, &tp)); - EXPECT_EQ(tp, time_point<D>::min()); - EXPECT_EQ("1677-09-21T00:12:43.145224192+00:00", - absl::time_internal::cctz::format(RFC3339_full, tp, utc)); - EXPECT_FALSE( - parse(RFC3339_full, "1677-09-21T00:12:43.1452241919+00:00", utc, &tp)); -#endif + EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T00:00:59.25+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{59.25}); + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:59:00.75+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{-59.25}); + } + { + using D = chrono::duration<double, std::milli>; + time_point<D> tp; + + EXPECT_TRUE( + parse(RFC3339_full, "1970-01-01T00:00:00.015625+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{15.625}); + EXPECT_TRUE( + parse(RFC3339_full, "1969-12-31T23:59:59.984375+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{-15.625}); + } + { + using D = chrono::duration<double, std::ratio<60>>; + time_point<D> tp; + + EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T00:01:15+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{1.25}); + EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:58:45+00:00", utc, &tp)); + EXPECT_EQ(tp.time_since_epoch(), D{-1.25}); + } +} + +TEST(Parse, RatioNonLowestTerms) { + const time_zone utc = utc_time_zone(); + using D = chrono::duration<std::int64_t, std::ratio<2, 2>>; + time_point<D> tp; - using DS = chrono::duration<std::int8_t, chrono::seconds::period>; - time_point<DS> stp; - - EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T00:02:07.9+00:00", utc, &stp)); - EXPECT_EQ(stp, time_point<DS>::max()); - EXPECT_EQ("1970-01-01T00:02:07+00:00", - absl::time_internal::cctz::format(RFC3339_full, stp, utc)); - EXPECT_FALSE(parse(RFC3339_full, "1970-01-01T00:02:08+00:00", utc, &stp)); - - EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:57:52+00:00", utc, &stp)); - EXPECT_EQ(stp, time_point<DS>::min()); - EXPECT_EQ("1969-12-31T23:57:52+00:00", - absl::time_internal::cctz::format(RFC3339_full, stp, utc)); - EXPECT_FALSE(parse(RFC3339_full, "1969-12-31T23:57:51.9+00:00", utc, &stp)); - - using DM = chrono::duration<std::int8_t, chrono::minutes::period>; - time_point<DM> mtp; - - EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T02:07:59+00:00", utc, &mtp)); - EXPECT_EQ(mtp, time_point<DM>::max()); - EXPECT_EQ("1970-01-01T02:07:00+00:00", - absl::time_internal::cctz::format(RFC3339_full, mtp, utc)); - EXPECT_FALSE(parse(RFC3339_full, "1970-01-01T02:08:00+00:00", utc, &mtp)); - - EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T21:52:00+00:00", utc, &mtp)); - EXPECT_EQ(mtp, time_point<DM>::min()); - EXPECT_EQ("1969-12-31T21:52:00+00:00", - absl::time_internal::cctz::format(RFC3339_full, mtp, utc)); - EXPECT_FALSE(parse(RFC3339_full, "1969-12-31T21:51:59+00:00", utc, &mtp)); + EXPECT_TRUE(parse(RFC3339_full, "2026-08-17T11:42:16-04:00", utc, &tp)); + ExpectTime(tp, utc, 2026, 8, 17, 15, 42, 16, 0, false, "UTC"); } TEST(Parse, TimePointOverflowFloor) { @@ -1772,8 +1952,6 @@ TEST(Parse, TimePointOverflowFloor) { EXPECT_EQ(tp, time_point<D>::max()); EXPECT_EQ("294247-01-10T04:00:54.775807+00:00", absl::time_internal::cctz::format(RFC3339_full, tp, utc)); -#if 0 - // TODO(#199): Will fail until cctz::parse() properly detects overflow. EXPECT_FALSE( parse(RFC3339_full, "294247-01-10T04:00:54.7758080+00:00", utc, &tp)); EXPECT_TRUE( @@ -1783,7 +1961,6 @@ TEST(Parse, TimePointOverflowFloor) { absl::time_internal::cctz::format(RFC3339_full, tp, utc)); EXPECT_FALSE( parse(RFC3339_full, "-290308-12-21T19:59:05.2241919+00:00", utc, &tp)); -#endif } // @@ -1821,7 +1998,7 @@ TEST(FormatParse, RoundTrip) { EXPECT_EQ(in, out); // RFC1123_full includes %z } -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) // Initial investigations indicate the %c does not roundtrip on Windows. // TODO: Figure out what is going on here (perhaps a locale problem). #elif defined(__EMSCRIPTEN__) diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc index 9abbde72d627..c04b68051704 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc @@ -414,6 +414,9 @@ inline FilePtr FOpen(const char* path) { // absolute path) would block indefinitely or read unbounded data. #ifndef O_CLOEXEC #define O_CLOEXEC 0 +#endif +#ifndef O_NONBLOCK +#define O_NONBLOCK 0 #endif const int fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); if (fd >= 0) { @@ -787,8 +790,8 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) { for (std::size_t i = 0; i != hdr.typecnt; ++i) { transition_types_[i].utc_offset = static_cast<std::int_least32_t>(Decode32(bp)); - if (transition_types_[i].utc_offset >= kSecsPerDay || - transition_types_[i].utc_offset <= -kSecsPerDay) + if (transition_types_[i].utc_offset >= 26 * 60 * 60 || + transition_types_[i].utc_offset <= -25 * 60 * 60) return false; bp += 4; transition_types_[i].is_dst = (Decode8(bp++) != 0); diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc index 362da1ab58be..4e2680a8312e 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc @@ -40,11 +40,11 @@ namespace cctz { namespace { -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) // Uses the globals: '_timezone', '_dstbias' and '_tzname'. -auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) { +auto tm_gmtoff(const std::tm& tm) -> decltype(-_timezone + -_dstbias) { const bool is_dst = tm.tm_isdst > 0; - return _timezone + (is_dst ? _dstbias : 0); + return -_timezone + (is_dst ? -_dstbias : 0); } auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) { const bool is_dst = tm.tm_isdst > 0; @@ -52,9 +52,9 @@ auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) { } #elif defined(__sun) || defined(_AIX) // Uses the globals: 'timezone', 'altzone' and 'tzname'. -auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) { +auto tm_gmtoff(const std::tm& tm) -> decltype(-timezone) { const bool is_dst = tm.tm_isdst > 0; - return is_dst ? altzone : timezone; + return is_dst ? -altzone : -timezone; } auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { const bool is_dst = tm.tm_isdst > 0; @@ -63,9 +63,9 @@ auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { #elif defined(__native_client__) || defined(__myriad2__) || \ defined(__EMSCRIPTEN__) // Uses the globals: '_timezone' and 'tzname'. -auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) { +auto tm_gmtoff(const std::tm& tm) -> decltype(-_timezone + 0) { const bool is_dst = tm.tm_isdst > 0; - return _timezone + (is_dst ? 60 * 60 : 0); + return -_timezone + (is_dst ? 60 * 60 : 0); } auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { const bool is_dst = tm.tm_isdst > 0; @@ -73,14 +73,38 @@ auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { } #elif defined(__VXWORKS__) // Uses the globals: 'timezone' and 'tzname'. -auto tm_gmtoff(const std::tm& tm) -> decltype(timezone + 0) { +auto tm_gmtoff(const std::tm& tm) -> decltype(-timezone + 0) { const bool is_dst = tm.tm_isdst > 0; - return timezone + (is_dst ? 60 * 60 : 0); + return -timezone + (is_dst ? 60 * 60 : 0); } auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { const bool is_dst = tm.tm_isdst > 0; return tzname[is_dst]; } +#elif defined(__NEWLIB__) +// The struct std::tm extension fields are named by __TM_GMTOFF and __TM_ZONE, +// either of which the configuration may leave undefined. Where it does, fall +// back on the globals: '_timezone' and 'tzname'. +#if defined(__TM_GMTOFF) +auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__TM_GMTOFF) { + return tm.__TM_GMTOFF; +} +#else +auto tm_gmtoff(const std::tm& tm) -> decltype(-_timezone + 0) { + const bool is_dst = tm.tm_isdst > 0; + return -_timezone + (is_dst ? 60 * 60 : 0); +} +#endif +#if defined(__TM_ZONE) +auto tm_zone(const std::tm& tm) -> decltype(tm.__TM_ZONE) { + return tm.__TM_ZONE; +} +#else +auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { + const bool is_dst = tm.tm_isdst > 0; + return tzname[is_dst]; +} +#endif #else // Adapt to different spellings of the struct std::tm extension fields. #if defined(tm_gmtoff) @@ -121,7 +145,7 @@ auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) { using tm_gmtoff_t = decltype(tm_gmtoff(std::tm{})); inline std::tm* gm_time(const std::time_t* timep, std::tm* result) { -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) return gmtime_s(result, timep) ? nullptr : result; #else return gmtime_r(timep, result); @@ -129,7 +153,7 @@ inline std::tm* gm_time(const std::time_t* timep, std::tm* result) { } inline std::tm* local_time(const std::time_t* timep, std::tm* result) { -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) return localtime_s(result, timep) ? nullptr : result; #else return localtime_r(timep, result); diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc index f53ac03eaf86..ab9a432f4ce6 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -470,7 +470,7 @@ TEST(MakeTime, SysSecondsLimits) { if (sizeof(std::time_t) >= 8) { // Checks that "tm_year + 1900", as used by the "libc" implementation, // can produce year values beyond the range on an int without overflow. -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) // localtime_s() and gmtime_s() don't believe in years outside [1970:3000]. #else const time_zone cut = LoadZone("libc:UTC"); @@ -1087,6 +1087,22 @@ std::unique_ptr<ZoneInfoSource> ExtendedTestFactory( return std::unique_ptr<ZoneInfoSource>(new StringZoneInfoSource( MakeExtendedTzif(0, -5 * 3600, "EST", "EST5EDT,M3.2.0,M11.1.0"))); } + if (name == "test:ExtendedLargeOffset") { + // A file-supplied UTC offset of 25h is more than a day from UTC but still + // within the (-25h < utoff < 26h) range RFC 9636 allows, so the reader + // must accept it. + return std::unique_ptr<ZoneInfoSource>( + new StringZoneInfoSource(MakeExtendedTzif( + 0, 25 * 3600, std::string{"EST", 4}, "EST5EDT,M3.2.0,M11.1.0"))); + } + if (name == "test:MinUtcOffset") { + // The minimum 32-bit UTC offset is far outside the (-25h < utoff < 26h) + // range RFC 9636 allows, and is the one offset whose negation overflows + // in FormatOffset(), so the reader must reject it. + const std::int_fast32_t min_offset = -2147483647 - 1; + return std::unique_ptr<ZoneInfoSource>(new StringZoneInfoSource( + MakeExtendedTzif(0, min_offset, std::string{"X", 2}, ""))); + } return fallback(name); } @@ -1129,6 +1145,31 @@ TEST(TimeZoneEdgeCase, ExtendedOverlappingRules) { cctz_extension::zone_info_source_factory = prev_factory; } +// A file-supplied UTC offset more than a day from UTC is still valid per +// RFC 9636 (which allows -25h < utoff < 26h), so loading must succeed. +TEST(TimeZoneEdgeCase, ExtendedLargeOffset) { + auto prev_factory = cctz_extension::zone_info_source_factory; + cctz_extension::zone_info_source_factory = ExtendedTestFactory; + + time_zone tz; + EXPECT_TRUE(load_time_zone("test:ExtendedLargeOffset", &tz)); + + cctz_extension::zone_info_source_factory = prev_factory; +} + +// A file-supplied UTC offset outside the range RFC 9636 allows (which is +// -25h < utoff < 26h) would break the fixed-width offset formatting, so +// loading must fail. +TEST(TimeZoneEdgeCase, MinUtcOffset) { + auto prev_factory = cctz_extension::zone_info_source_factory; + cctz_extension::zone_info_source_factory = ExtendedTestFactory; + + time_zone tz; + EXPECT_FALSE(load_time_zone("test:MinUtcOffset", &tz)); + + cctz_extension::zone_info_source_factory = prev_factory; +} + // Looking up the maximum time in an extended zone must fold back through the // 400-year cycle without overflowing when BreakTime() computes the shift. TEST(TimeZoneEdgeCase, ExtendedFarFuture) { diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version index 9217a2da674e..2c2d640a0f1c 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/version @@ -1 +1 @@ -2026c +2026e diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota index 85b903333eb6325aa8343f6e9aee38447495303f..8b37a3d6217ec9c2ddd82a66fc648f81b37d7891 100644 GIT binary patch delta 13 UcmdnYxS4T62{V)8g^A@h03dz@rvLx| delta 13 UcmdnYxS4T62{UtXz{GMJ03aR&dH?_b diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik index 86639f6ecb4c424911e5bdbca81a9e39c86e850c..20b2ad1ebe5733b29d27f78da6b3ea5808dc8485 100644 GIT binary patch delta 386 zcmdnU*1<U;j5D8sfq@N(B{s%8Fx3MY4DPx$Ad12L@^S$X?a3Plq8L0kcY^s|ZymsV z?>S2+fEYg4Vj4iSZ%sRx@3+kk%=eGU1oH!?DS-KbHr`-<P#F`LA1tE_=7)qn0rNxt z@YjO{!c32W1;U={2rvLagxq5g#Sn3n56qAJcNENzTJizRkG{7Y%#Ufg1m?%?>jd-T zQnrBk@$<65`~=?%6F`i__Vxx4ous=7%ui0w1oKmPt)_qlQr*450;zAy!2EP|T`)iW zYy_B}$<7bvXRfsZ^Ru3PY?wTs$z$?<CN)OZ$<LYORQ~^8y?{YP*T8@wz$JtsAUK4< P7leUqXCTc5B+R$~9%WSz delta 73 zcmeC++{iW|jMIaGfq@l>MK;DeFipPB>@nGmMNUW8z<?pZC4?a$IE29$gn?`>Aj2HU V(D60aGtx8A@ijEmGt@KS0sv=C5HbJ& diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River index 7e646d18e18851bfde743b379e52df4ec5b5a20f..0ca15092f96bd057fca3e078adcdf14d82bf146c 100644 GIT binary patch delta 411 zcmeC<ddf2)jB^PC0|OfnOKgmP!CVhyFu3dHegM;#XM!jOPhNj8-*a;{nD6!05X|?U zGra*M;B(Ed07U!NR5pNUzikF!zJE+Km>)1r2+R+(u?6#kO22^l!7}n-en{vwFhArE zV?9_P%yb7>And6e0|-ROUHJf}kAk@jk^i=V`B6(Afd!)P%>eUbT8@DEvHPmP{J4~5 zV1E3(7%)G<_fP{!AhEr&07NJ0E@=SK$?4HxehRNu8(1LK-4-m6`Zfd1Pgj=*^V83I zf%%#2j9`A|S{*Py>)GRi$?hz*lM`6foLT?>U-E{5;s5`g8yH#s|6jd;fdkCu0h0nC el0n4BH-y321&D)zI2?!rLKs|uY%U;S$^`(IglaPY delta 99 zcmaFL)5kR-jI)-3fq@l>MK;F2V4hshTI==y|B^Qh4FCV{+`!24|NrU*3>;uK51172 p@eN^cb^+pGAPxuOfDi^QAjb?SsN-v_XQXGK<7;TBXQ*eu1prP>A-4bk diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg index 7e646d18e18851bfde743b379e52df4ec5b5a20f..0ca15092f96bd057fca3e078adcdf14d82bf146c 100644 GIT binary patch delta 411 zcmeC<ddf2)jB^PC0|OfnOKgmP!CVhyFu3dHegM;#XM!jOPhNj8-*a;{nD6!05X|?U zGra*M;B(Ed07U!NR5pNUzikF!zJE+Km>)1r2+R+(u?6#kO22^l!7}n-en{vwFhArE zV?9_P%yb7>And6e0|-ROUHJf}kAk@jk^i=V`B6(Afd!)P%>eUbT8@DEvHPmP{J4~5 zV1E3(7%)G<_fP{!AhEr&07NJ0E@=SK$?4HxehRNu8(1LK-4-m6`Zfd1Pgj=*^V83I zf%%#2j9`A|S{*Py>)GRi$?hz*lM`6foLT?>U-E{5;s5`g8yH#s|6jd;fdkCu0h0nC el0n4BH-y321&D)zI2?!rLKs|uY%U;S$^`(IglaPY delta 99 zcmaFL)5kR-jI)-3fq@l>MK;F2V4hshTI==y|B^Qh4FCV{+`!24|NrU*3>;uK51172 p@eN^cb^+pGAPxuOfDi^QAjb?SsN-v_XQXGK<7;TBXQ*eu1prP>A-4bk diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran index 6fd31e075a29223eeea3f9a1a747b4531775f8ef..2a46cf7c133770db40a3efe96b76af43a0ba602d 100644 GIT binary patch delta 14 WcmZ3(wuWuO9OgAyCpOOSWdZ;$9|lnX delta 14 WcmZ3(wuWuO9OkuqJT}hnWdZ;#k_IFI diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT index b016880653929aa40dd5ac0e82e4094a9d787cdf..cc2cb2753c328f875e42430bb5a329ba82c39fa3 100644 GIT binary patch delta 146 zcmcb`JBxin7-u*G0|OHfb4*NE;Xd8*ui-xsTuS8J?8n^6l*!0I6ZrrC>IDoe|NrmY Rz{ue262jmdJox~d6aZ{~7sdbp literal 1754 zcmb``YfzL`7{Kwv{UQjZBm$vHxgogR;v%kz!4Ba>SgseW(IHKuX<|#1ai+m_B26cw zG{@}1#anoxMK?ksVMQVaYbHU74c!*9l`v%$Qv}*=&;OI(^h4*J^FHVIT+aLH)vPF3 z8!zs=T$~+p%cZ&hh~C-e>D<8%=UVAzuavR;P_$0Qitp}fWvtvX5m$ZIi}#%^5;DL4 z-8(iJ52!n-A6#w1hZdWte-*Tc{_2EATx~Z{KQie{e8jvPA06I=k2MwJnyx(jb$Kq< z8`5!Y$y|K=i&Z-L-4prCwK5vsS%AOEOvQCCN8oQ2VYpu9flqqcaYN`8++elfMh|x( z?`dpn!QWrD;!}FFP3D_g+i`Q55gS)@<I}Y&`ddmrz-Mwwskg3q6aNsi7Pn<@*U5W+ z40sl|&wc~9kG#r!hyU}qqbC!eecz5dBW~f&JRjz|)(;DL&-t{g_`;G4xO@7~_}9dG z+#~eZ6towcEFa_F>~%Uh-)mflFPit@ONT$w%DlO0BmRBc+t^b667DO|;Qo?%_>Zh4 ze0k+G{O2;2P0m|0RYJxq$>DfF5sv?wBJiM>z=OB@@l|U-{=2&sUu$c{*PHva@}42R zMJJ=J;tak~)`D+tI*5l058zv?w&H(sw&2_I3-Fzo*YL=b@7d%%cLNsUQSW>_I+8DB zerzBMkN0HZf7_$5{bUq&RQucH|0F*3C%9}K!mh<b*zGMptvtBrP0-2cvFJMXOuL4? zVt>J2I~3R_@C5d$*)Q9Luk8~&!Lp0GpQ+X+^Zv&5cw)m&9B_E2OpCz1Mfjm@Mfl;3 zOYx+FrFe2~3J%Ij!H>)d!BZkbaPW*|tvpQi9>*cBQ*p@6V4X~a_Ko4NbEEjt)0c4g z@r!s`RWqKxAwaf^$2M2t8B1>9h}Tcq<l*teF8sv83OqBY4l8DD#tQp6olHdfuEvpO z1D-Xg#!*eXadg)!TG=<dycjDD891gS7su|JiR1D&$Tktb&KoCWF2_&3IEWJ!sW>VA zC!FjRhEqZZZ1Rv|wc|Ns9XPekg6H-g!z%r_PA29xeu$qgGvoQ6YjIkk5icm+p_P5l z<m|)gYYK5jOet1pynxli^}^NV0Uoz|dfYwk!GjF{uRRV&&3X9~H`KbgI~+$Vg||El xKQe*5CqI|15$PGuy;vjE&Yix@xff}KuQQS4EJSA~DC3o}(b;iv$~a}L?|+gw5kdd} diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central index 7e646d18e18851bfde743b379e52df4ec5b5a20f..0ca15092f96bd057fca3e078adcdf14d82bf146c 100644 GIT binary patch delta 411 zcmeC<ddf2)jB^PC0|OfnOKgmP!CVhyFu3dHegM;#XM!jOPhNj8-*a;{nD6!05X|?U zGra*M;B(Ed07U!NR5pNUzikF!zJE+Km>)1r2+R+(u?6#kO22^l!7}n-en{vwFhArE zV?9_P%yb7>And6e0|-ROUHJf}kAk@jk^i=V`B6(Afd!)P%>eUbT8@DEvHPmP{J4~5 zV1E3(7%)G<_fP{!AhEr&07NJ0E@=SK$?4HxehRNu8(1LK-4-m6`Zfd1Pgj=*^V83I zf%%#2j9`A|S{*Py>)GRi$?hz*lM`6foLT?>U-E{5;s5`g8yH#s|6jd;fdkCu0h0nC el0n4BH-y321&D)zI2?!rLKs|uY%U;S$^`(IglaPY delta 99 zcmaFL)5kR-jI)-3fq@l>MK;F2V4hshTI==y|B^Qh4FCV{+`!24|NrU*3>;uK51172 p@eN^cb^+pGAPxuOfDi^QAjb?SsN-v_XQXGK<7;TBXQ*eu1prP>A-4bk diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT index 2b6c2eea14df07392729ae9f5712a44ec4f02bae..cc944f0eaa6f266c8fd25eed85dc9cee3f47baeb 100644 GIT binary patch delta 169 zcmcb>JBxin7-u*G0|OHfb4*NE;Xd8*q2NCdTuS)8*^jxCsh*L6Ch-6Nof{Zf{{KII lfRVw~C4|8>ID~-<NSFdSI=;qwMtTN1zJ`W+EQWdpTmU<T9Nqu` literal 1744 zcmb8vc~FdD90%~HLuD)FSXb_AZECl}O63S8VJF8nxh5}Dn&pq)VT2iS6v+%R8pbh8 zbU9ZSR%{`w$+%iaIr5f-h*vpM?0TNB|CxR}&wlswdw;)Y|Jv0o(ys6$|1BFj!450U z|5x;MtP4H8th8e6#JwzaIfHnX$F6+fSRUU&;LO8!;S+K7@X6%&0(+jd@;sca%Ej}X z`IRE;=StJyJpZ$Bo+TUer+e;!PuHfxXIgpqtWgV}GtYz1>t@0F!m;p$ByTwX=v<!N zUl2c&V_CS-A1(^_f{T|(;fu0v@TK4%@MQ-PHh9#)hQ=zm#QvMe?kO=9!B-oe!q@Z< z1lBi}8{pFP0=O*e2z)&u1HO^63BDPb2$#n$g>NYrz$W!Zp51fXEeNjgj)5!MqB+*D zbPa(ks{`RXJ4Lu^_}9P5bzslDwn1d`k3wF;kE2ZRlOd(>Q&k>ZO)}vc=`OfNNQR$T za(TA@yetlWQJV(8JhhEu{aWKH_*GggEa=p5opw50pQMCeM~sFWV!Fd`q7?$$Zw&Vq zS-uT$hu_KE;P<^-;3kJJaMSlk@P|e-{PD>}xY<+;e=0R|?4Hm1DxRfytQh{1UIe#n zJ_xra9Du(r-2i`!Tn~SrycqtWTm-j`UMH}7e!5M7+npA|?QIK0*6(;14F9SQf`3;G zge{i`z}8%=Kz}2I9JGimY*On4mbU8z*p9bw%=X-Go@JLg0>{!J<Q44ba|3qV-4E{S zo&|S3mw|nWxC3?;w&S@=%?W|faxII8yBShow^PZOcR#cO?w%G0_t-E4?x_ujdoA>Y zr4e$tcc2U0NA3*w9VX`pt$t3;aDQ88xPOa;XMK;lW_ZBEkMO|j_u)bL_u#>q`S6fL zg8iXe_rt@Y>fzxl^#Y+aLRAiroVgDkCC!0lo@-#4<tESO<dP^@UYiYjHU+?AjH$4f zS;NsW;;qxdio$WQGHDj<v%fFw8y_#SIltBIuzz?2Ja*m-SS1?+kMlFa0gkTlc#mfS zp*6noGaT4)6%H~zgoB^!;0gLqJe!+XvIU-${s5kQWH}s?PykO!+04-~GBq*-o))_d z4pk<?VWHFDu+}`$)~1s$JNr&9boLAWId8RI(Gf!b%F1l)tyaSY;)KsGcz2(z){wAJ gdgjv;P0t(+kx-~;(@X8I@KgABseOGFz6u}7AFmWIC;$Ke diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Eire b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Eire index 17d2b1582df89d5794f20fb028956dd9da154922..df91cd5dd57fdc2eeaf4c3aa48d7a0e3416c3348 100644 GIT binary patch delta 15 Xcmcb?eS>=g3nSB(@0-~eFR=gsFqQ?m delta 15 Wcmcb?eS>=g3nSC<oXu>EmskKT*#$uW diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin index 17d2b1582df89d5794f20fb028956dd9da154922..df91cd5dd57fdc2eeaf4c3aa48d7a0e3416c3348 100644 GIT binary patch delta 15 Xcmcb?eS>=g3nSB(@0-~eFR=gsFqQ?m delta 15 Wcmcb?eS>=g3nSC<oXu>EmskKT*#$uW diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Iran b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Iran index 6fd31e075a29223eeea3f9a1a747b4531775f8ef..2a46cf7c133770db40a3efe96b76af43a0ba602d 100644 GIT binary patch delta 14 WcmZ3(wuWuO9OgAyCpOOSWdZ;$9|lnX delta 14 WcmZ3(wuWuO9OkuqJT}hnWdZ;#k_IFI diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT index 09e54e5c7c5bb2384e37626d4b985cfad29ed29b..f155fa9a2f5bdb45fb67ec2d6526db0d9d9d5c35 100644 GIT binary patch delta 168 zcmbQlF^hdd7-u*G0|OHfb4*NE;Xd8TGvPlFTuPMKc(0SGo{@nj@c;k06Bt<j|6jd; kk-^s`guypBgn<i4m;*UFzQ%e+dImbahK719hI$5E08>~SD*ylh delta 266 zcmbQmK8a&Om|!9U0|P4%i~I+II2N7_6XR8a7p4B20OBuhVPgQ%OI#m-`AhnjHGuf1 zJ9)tTOUhpgK>SOI5@2=T^~=EGKQyL*`9Jw1!2DkvWgGiCnd+Gsp^%vc&V&h3h5rA4 q?i2=~)vFgUvH;l=7&yRe9xy2&<l`H{;Ohd!!9W}i!~v5Vn56)T179)# diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT index aaf07787ad92b65eadae63b64bba290f9f961507..6a27aeb92877e8706985377686ad7161524e0c98 100644 GIT binary patch delta 160 zcmeC<n#DdLj5C~pfq@B#IVPs-G9{{Q-pAO<RL{sj6Zrpse**){|NnC*Ffs(VgfIjI dhcIvf2@4=c$JbcTNY6mW*U(Up#Zb?H3jkkl6fFP% delta 511 zcmbQm-p4f|Ot6-Lfq@l>Mg9Xp9E;R}iSfGi%3lgV+)IgS0wDU@zmgabeWPLR1Q31e z-(fI)`@jUS{GEGC!Th@`*MRAJ``W?u{mwox{a{`un0}a90Hz<+d4uW4o<U&xNt`a2 zeyV8#rt6=%dkKIndM*?QreCP*K<H1#VEPq1AB4Un3Z`E_`v9ijZ2S(U-yXXJrr%Ax z38vq#e>VYS-iN~7VE)Jc3t;}I`h#HlbN(hU{Uv@eh}QZ4)qe_D;G2CbnEtL`2Bv># zED``2^pigV%>TvFvazp|sh)`u2$@;H6o^Sz`2WA&L^TG6|NrMsU}X9KzrTTj1I*?D YlL9`zAq)X7KpYIj;XoWPxq(><0L~E$HUIzs diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab index 635eabcbf2d3..1aed9b5e3060 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab @@ -107,14 +107,14 @@ CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA,BS +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba +CA +4953-09709 America/Winnipeg EST - Manitoba, ON (northwest) CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) CA +5333-11328 America/Edmonton CST - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) -CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +682059-1334300 America/Inuvik CST - NT (west) CA +4916-12307 America/Vancouver MST - BC (most areas) CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) diff --git a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab index 9c3a8cf3c1b5..bd3a27874326 100644 --- a/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab +++ b/deps/v8/third_party/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab @@ -65,10 +65,10 @@ XX +4916-12307 America/Vancouver Mountain Standard (MST) - British Columbia (mos XX +332654-1120424 America/Phoenix Mountain Standard (MST) - Arizona; western Mexico; Yukon # # -07/-06 - MST/MDT (North America DST) -XX +394421-1045903 America/Denver Mountain (MST/MDT) - US; Mexico near US border; northern Canada +XX +394421-1045903 America/Denver Mountain (MST/MDT) - US; Mexico near US border; western Nunavut # # -07/-06 - MST/MDT (North America DST) until 2026-11-01 02:00; then CST -XX +5333-11328 America/Edmonton Central Standard (CST) - Alberta and some neighbors +XX +5333-11328 America/Edmonton Central Standard (CST) - Alberta, NWT, and some neighbors # # -06 XX -0054-08936 Pacific/Galapagos Galápagos @@ -80,7 +80,10 @@ XX +1924-09909 America/Mexico_City Central Standard (CST) - Saskatchewan; centra XX -2709-10926 Pacific/Easter Easter Island # # -06/-05 - CST/CDT (North America DST) -XX +415100-0873900 America/Chicago Central (CST/CDT) - US & Canada; Mexico near US border +XX +415100-0873900 America/Chicago Central (CST/CDT) - US; Mexico near US border; central Nunavut +# +# -06/-05 - CST/CDT (North America DST) until 2026-11-01 02:00; then EST +XX +4953-09709 America/Winnipeg Eastern Standard (EST) - Manitoba, northwestern Ontario # # -05 XX -1203-07703 America/Lima eastern South America diff --git a/deps/v8/third_party/abseil-cpp/convert_bazel_to_gn.py b/deps/v8/third_party/abseil-cpp/convert_bazel_to_gn.py index 19fd6e71efb6..2fb07aa82d8c 100755 --- a/deps/v8/third_party/abseil-cpp/convert_bazel_to_gn.py +++ b/deps/v8/third_party/abseil-cpp/convert_bazel_to_gn.py @@ -105,14 +105,30 @@ '}', # Closes extra '{' opened by prefix. 'cleanup:cleanup_internal': 'visibility = [ "//third_party/abseil-cpp/absl/*" ]', + 'container:btree': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'container:chunked_queue': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', 'container:hashtablez_sampler_test': 'if (is_win) { sources = [] }', 'container:test_allocator': 'deps += [ "//third_party/googletest:gtest" ]', + 'crc:crc32c': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', 'flags:config': 'public_configs = [ ":absl_flags_config" ]', 'flags:parse_test': 'if (is_ios) { sources = [] }', + 'functional:any_invocable': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'functional:bind_back': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'functional:bind_front': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'functional:function_ref': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'hash:hash': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', 'log:absl_check_test': 'if (is_ios) { sources = [] }', 'log:log_sink_test': @@ -127,6 +143,12 @@ 'if (is_ios) { sources = [] }', 'random/internal:seed_material': 'if (is_win) { libs = [ "bcrypt.lib" ]}', + 'status:status': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'status:statusor': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'status:status_matchers': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', 'strings:strings': '''public_deps = [ # string_view.h was once part of :strings, so string_view.h is @@ -134,9 +156,14 @@ # New code should directly depend on :string_view. # TODO(crbug.com/40276308): Remove once all targets are migrated to # :string_view. - ":string_view" ]''', + ":string_view" ] + check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE''', 'strings:str_format_convert_test': 'if (is_fuchsia) { sources = [] }', + 'strings:cord': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'strings:generic_printer': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', # Instead of parsing 'select', add platform-specific rules manually while there are few of those. 'time/internal/cctz:time_zone': ''' @@ -159,6 +186,10 @@ }''', 'time/internal/cctz:time_zone_name_win_test': 'if (is_win) { sources = [ "src/time_zone_name_win_test.cc" ] }', + 'types:span': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', + 'types:any_span': + 'check_includes_strict = CHECK_INCLUDES_STRICT_PUBLIC_INCLUDES_PRIVATE', } diff --git a/deps/v8/third_party/abseil-cpp/patches/0001-Undeprecate-deprecated.patch b/deps/v8/third_party/abseil-cpp/patches/0001-Undeprecate-deprecated.patch index cae1904208ae..79e086ffa9fa 100644 --- a/deps/v8/third_party/abseil-cpp/patches/0001-Undeprecate-deprecated.patch +++ b/deps/v8/third_party/abseil-cpp/patches/0001-Undeprecate-deprecated.patch @@ -194,4 +194,44 @@ index 72614172586f3..6c788ac1b5d79 100644 + struct _absl_fallthrough_intended_macro; \ (void)sizeof(_absl_fallthrough_intended_macro*); \ [[fallthrough]] + +diff --git a/third_party/abseil-cpp/absl/base/attributes.h b/third_party/abseil-cpp/absl/base/attributes.h +index 8385bf9bef1ab..5bccfc51db78f 100644 +--- a/third_party/abseil-cpp/absl/base/attributes.h ++++ b/third_party/abseil-cpp/absl/base/attributes.h +@@ -202,10 +202,13 @@ + // + // Deprecated: Prefer the `[[noreturn]]` attribute standardized by C++11 over + // this macro. +-#ifdef ABSL_ATTRIBUTE_NORETURN +-#error "ABSL_ATTRIBUTE_NORETURN should not be defined." ++#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__)) ++#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn)) ++#elif defined(_MSC_VER) ++#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn) ++#else ++#define ABSL_ATTRIBUTE_NORETURN + #endif +-#define ABSL_ATTRIBUTE_NORETURN [[noreturn]] + + // ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS + // +diff --git a/third_party/abseil-cpp/absl/base/attributes.h b/third_party/abseil-cpp/absl/base/attributes.h +index 5bccfc51db78f..00a3eb033aba4 100644 +--- a/third_party/abseil-cpp/absl/base/attributes.h ++++ b/third_party/abseil-cpp/absl/base/attributes.h +@@ -441,10 +441,11 @@ + // + // Sprocket* SprocketPointer(); + // SprocketPointer(); // Does *not* trigger a warning. +-#ifdef ABSL_MUST_USE_RESULT +-#error "ABSL_MUST_USE_RESULT should not be defined." ++#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) ++#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) ++#else ++#define ABSL_MUST_USE_RESULT + #endif +-#define ABSL_MUST_USE_RESULT [[nodiscard]] + // ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD + // diff --git a/deps/v8/third_party/abseil-cpp/patches/0003-delete-static-initializer-in-stacktrace.patch b/deps/v8/third_party/abseil-cpp/patches/0003-delete-static-initializer-in-stacktrace.patch index ad3f5ab8a77d..3fa539705d96 100644 --- a/deps/v8/third_party/abseil-cpp/patches/0003-delete-static-initializer-in-stacktrace.patch +++ b/deps/v8/third_party/abseil-cpp/patches/0003-delete-static-initializer-in-stacktrace.patch @@ -1,7 +1,7 @@ TODO: crbug.com/40148384, b/156075691#comment18 - Remove this static initializer upstream --- diff --git a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc -index b2792a1f3ada..b94c61233ba3 100644 +index 36a65601072b8..fa6ab73162c2e 100644 --- a/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc +++ b/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc @@ -43,17 +43,6 @@ static __thread int recursive = 0; @@ -10,7 +10,7 @@ index b2792a1f3ada..b94c61233ba3 100644 static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy. -// Waiting until static initializers run seems to be late enough. -// This file is included into stacktrace.cc so this will only run once. --ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() { +-[[maybe_unused]] static int stacktraces_enabler = []() { - void* unused_stack[1]; - // Force the first backtrace to happen early to get the one-time shared lib - // loading (allocation) out of the way. After the first call it is much safer @@ -21,8 +21,8 @@ index b2792a1f3ada..b94c61233ba3 100644 -}(); template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> - static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, -@@ -99,7 +88,7 @@ namespace absl { + static int UnwindImpl(void** result, uintptr_t* frames, int* sizes, +@@ -112,7 +101,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { bool StackTraceWorksForTest() { diff --git a/deps/v8/third_party/abseil-cpp/patches/0004-string-view-transitive-includes b/deps/v8/third_party/abseil-cpp/patches/0004-string-view-transitive-includes deleted file mode 100644 index 05ba1c1c721c..000000000000 --- a/deps/v8/third_party/abseil-cpp/patches/0004-string-view-transitive-includes +++ /dev/null @@ -1,13 +0,0 @@ -TODO: crbug.com/472445608 - Remove when when third_party project would stop relying on these transitive includes. -diff --git a/third_party/abseil-cpp/absl/strings/string_view.h b/third_party/abseil-cpp/absl/strings/string_view.h -index 97f7729db9f67..4855e5bfdf1f1 100644 ---- a/third_party/abseil-cpp/absl/strings/string_view.h -+++ b/third_party/abseil-cpp/absl/strings/string_view.h -@@ -25,6 +25,7 @@ - #define ABSL_STRINGS_STRING_VIEW_H_ - - #include <algorithm> -+#include <string> - #include <string_view> - - #include "absl/base/attributes.h" diff --git a/deps/v8/third_party/abseil-cpp/roll_abseil.py b/deps/v8/third_party/abseil-cpp/roll_abseil.py index 15c1ed0ded2d..9f5bd2a497ac 100755 --- a/deps/v8/third_party/abseil-cpp/roll_abseil.py +++ b/deps/v8/third_party/abseil-cpp/roll_abseil.py @@ -59,6 +59,7 @@ def _UpdateAbseilInChromium(abseil_dir, chromium_dir): '.clang-format-ignore', '.git', '.gitignore', + '.github', '.style.yapf', '*.gni', '*clang-format', diff --git a/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg.def b/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg.def index c22828fe2d05..54f79d056446 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg.def +++ b/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg.def @@ -1,20 +1,13 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$CBD$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEBD@Z ??$?0$$CBU?$atomic@_N@__Cr@std@@@Condition@absl@@QEAA@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z0@Z ??$?0$$CBUCordRep@cord_internal@absl@@@Hex@absl@@QEAA@PEBUCordRep@cord_internal@1@W4PadSpec@1@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$?0$$CBVFormatArgImpl@str_format_internal@absl@@$$CBV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEAA@V?$initializer_list@VFormatArgImpl@str_format_internal@absl@@@std@@@Z ??$?0$$CB_W$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEB_W@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z ??$?0$$T@?$Storage@PEAPEAUCordRep@cord_internal@absl@@$00U?$StorageTag@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAPEAVLogSink@absl@@$00U?$StorageTag@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@PEAPEAVLogSink@absl@@@internal_compressed_tuple@container_internal@2@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAUPayload@status_internal@absl@@$00U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@PEAUPayload@status_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z @@ -35,7 +28,6 @@ EXPORTS ??$?0$$V@PlacementImpl@?$NoDestructor@VMutex@absl@@@absl@@QEAA@XZ ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@QEAA@AEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@23@@__Cr@std@@QEAA@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@45@@Z - ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEAPEAPEAVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEAVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAPEBVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEBVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEBVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N$0A@@?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@QEAA@AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$QEA_N@Z @@ -67,8 +59,6 @@ EXPORTS ??$?0AEA_K@?$Storage@_K$0A@U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_K@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@$00@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEAA@AEA_KAEBV?$allocator@D@__Cr@std@@@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@@?$CompressedTupleImpl@V?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@U?$integer_sequence@_K$0A@$00@__Cr@std@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_KAEBV?$allocator@D@56@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEBV?$allocator@D@__Cr@std@@@?$Storage@V?$allocator@D@__Cr@std@@$00U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@D@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$0A@U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@UPayload@status_internal@absl@@@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEAA@AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$$QEAI@Z @@ -80,8 +70,6 @@ EXPORTS ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@Z ??$?0D@?$allocator@U?$AlignedType@$07@container_internal@absl@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@FormatArgImpl@str_format_internal@absl@@QEAA@AEBD@Z @@ -107,15 +95,10 @@ EXPORTS ??$?0PEAUTransitionType@cctz@time_internal@absl@@$0A@@?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@__Cr@std@@QEAA@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z ??$?0PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@PEAU0?1???R1234@QEBA?AV567@0@Z@$0A@@?$pair@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@PEAU1?1???R2345@QEBA?AV678@0@Z@@__Cr@std@@QEAA@$$QEAPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV567@@Z@1@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$tuple@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@$$QEAPEAVCommandLineFlag@absl@@@Z ??$?0PEAX@FlagState@flags_internal@absl@@QEAA@AEAVFlagImpl@12@AEBQEAX_N2_J@Z ??$?0PEBD@FormatArgImpl@str_format_internal@absl@@QEAA@AEBQEBD@Z ??$?0PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU0123@$0A@@?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@__Cr@std@@QEAA@$$QEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$?0PEBVFormatArgImpl@str_format_internal@absl@@$0A@@?$InlinedVector@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@absl@@QEAA@PEBVFormatArgImpl@str_format_internal@1@0AEBV?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@?$FunctionRef@$$A6A_K_K@Z@absl@@IEAA@Uin_place_t@__Cr@std@@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@X@?$FunctionRef@$$A6A_K_K@Z@absl@@QEAA@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z ??$?0U?$__check_pair_construction@UFindInfo@container_internal@absl@@V?$NonIterableBitMask@_K$07$02@23@@__Cr@std@@$0A@@?$pair@UFindInfo@container_internal@absl@@V?$NonIterableBitMask@_K$07$02@23@@__Cr@std@@QEAA@AEBUFindInfo@container_internal@absl@@AEBV?$NonIterableBitMask@_K$07$02@45@@Z ??$?0U?$array@D$0DKJI@@__Cr@std@@XU012@H@?$Span@D@absl@@QEAA@AEAU?$array@D$0DKJI@@__Cr@std@@@Z ??$?0U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -126,6 +109,7 @@ EXPORTS ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??$?0U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??$?0U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagSaverImpl@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagState@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@$$T@Z ??$?0U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVTimeZoneInfo@cctz@time_internal@absl@@@Z @@ -281,6 +265,7 @@ EXPORTS ??$?DPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@12@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@12@XZ + ??$?DPEAVFlagSaverImpl@flags_internal@absl@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagSaverImpl@flags_internal@absl@@XZ ??$?DPEAVFlagStateInterface@flags_internal@absl@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagStateInterface@flags_internal@absl@@XZ ??$?D_J@absl@@YA?AVDuration@0@_JV10@@Z ??$?GPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@@__Cr@std@@YA_JAEBV?$move_iterator@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@01@0@Z @@ -293,7 +278,6 @@ EXPORTS ??$?GPEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@__Cr@std@@YA_JAEBV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?GPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@01@0@Z ??$?GPEBQEAVLogSink@absl@@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEBQEAVLogSink@absl@@@01@0@Z - ??$?K_J@absl@@YA?AVDuration@0@V10@_J@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z @@ -303,10 +287,6 @@ EXPORTS ??$?RAEAPEAVLogSink@absl@@@__identity@__Cr@std@@QEBAAEAPEAVLogSink@absl@@AEAPEAV34@@Z ??$?RAEAPEBDAEAHAEAY0LLI@DAEBQEBDPEAD@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEBAXAEAPEBDAEAHAEAY0LLI@DAEBQEBD$$QEAPEAD@Z ??$?RAEAPEBVCommandLineFlag@absl@@@__identity@__Cr@std@@QEBAAEAPEBVCommandLineFlag@absl@@AEAPEBV34@@Z - ??$?RAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$01V?$Span@$$CBD@absl@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$01V?$Span@$$CBD@absl@@@345@@Z - ??$?RAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@345@@Z ??$?RAEAW4LogSeverity@absl@@AEAPEBDAEAHPEAPEADPEAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEBA_NAEAW4LogSeverity@2@AEAPEBDAEAH$$QEAPEAPEAD$$QEAPEAH@Z ??$?RAEAY04$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY04$$CBD$$QEAPEAVCondVar@2@@Z ??$?RAEAY06$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY06$$CBD$$QEAPEAVCondVar@2@@Z @@ -335,12 +315,12 @@ EXPORTS ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_backward_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@12@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEAPEAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEBQEAVCommandLineFlag@3@@Z ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$V@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@67@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@3@@Z ??$?RVDuration@absl@@V01@@?$__less@XX@__Cr@std@@QEBA_NAEBVDuration@absl@@0@Z ??$?RVMixingHashState@hash_internal@absl@@@CombineRaw@hash_internal@absl@@QEBA?AVMixingHashState@12@V312@_K@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z @@ -375,6 +355,7 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z ??$ArgumentToConv@C@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@D@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@E@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ @@ -410,8 +391,10 @@ EXPORTS ??$AsciiStrCaseFoldImpl@$0A@$00@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AsciiStrCaseFoldImpl@$0A@$0A@@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AssertHashEqConsistent@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$AssertNonNull@U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@functional_internal@absl@@YAXAEBU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z ??$AssertOnFind@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$AssignElements@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAUPayload@status_internal@1@AEAV?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@01@_K@Z ??$AssignElements@V?$allocator@VSourceLocation@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAVSourceLocation@1@AEAV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@01@_K@Z @@ -462,14 +445,9 @@ EXPORTS ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX0_K@Z ??$DecomposePair@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$DecomposePair@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAUFindElement@301@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z2@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z@Z @@ -542,6 +520,8 @@ EXPORTS ??$FastTypeId@_J@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_K@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_N@absl@@YA?AVFastTypeIdType@0@XZ + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -577,10 +557,10 @@ EXPORTS ??$GetDataImpl@V?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@@span_internal@absl@@YAPEAPEAVLogSink@1@AEAV?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@D@Z ??$GetFlag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@absl@@YA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@0@@Z ??$GetTrivialDestructRef@$0BI@$07@DtorPolicy@container_internal@absl@@SAAEBU012@XZ - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$HardeningAssertGE@PEBUPayload@status_internal@absl@@PEBU123@@base_internal@absl@@YAXPEBUPayload@status_internal@1@0@Z ??$HardeningAssertGE@_K_K@base_internal@absl@@YAX_K0@Z ??$HardeningAssertGT@_K_K@base_internal@absl@@YAX_K0@Z @@ -622,7 +602,6 @@ EXPORTS ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVBufferRawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVFILERawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeGet@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@@FlagImplPeer@flags_internal@absl@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@12@@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z ??$InvokeParseFlag@H@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@M@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@N@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -739,12 +718,8 @@ EXPORTS ??$OffsetValue@U?$atomic@_K@__Cr@std@@@FlagImpl@flags_internal@absl@@AEBAPEAU?$atomic@_K@__Cr@std@@XZ ??$OffsetValue@UFlagMaskedPointerValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagMaskedPointerValue@12@XZ ??$OffsetValue@UFlagOneWordValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagOneWordValue@12@XZ - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBQEAVCommandLineFlag@1@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z + ??$PairConstFirst@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z + ??$PairConstFirst@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$ParseFlag@H@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@M@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@N@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z @@ -765,9 +740,6 @@ EXPORTS ??$ReadCallback@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Condition@absl@@AEBAXPEAP6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Z ??$Register@AEB_JAEA_KAEA_KAEA_KAEAG@?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@QEAAPEAUHashtablezInfo@container_internal@2@AEB_JAEA_K11AEAG@Z ??$RoundUp@$03@crc_internal@absl@@YAPEBEPEBE@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@0@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@0@Z@@Z ??$SNPrintF@DHHH@absl@@YAHPEAD_KAEBV?$FormatSpecTemplate@$0BPPPL@$0JPPPL@$0JPPPL@$0JPPPL@@str_format_internal@0@AEBDAEBH44@Z ??$Seconds@H$0A@@absl@@YA?AVDuration@0@H@Z ??$Seconds@J$0A@@absl@@YA?AVDuration@0@J@Z @@ -932,14 +904,20 @@ EXPORTS ??$__append_with_size@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_K@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z - ??$__as_variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@YAAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@AEAV201@@Z ??$__assign_with_size_random_access@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_J@Z ??$__assume_aligned@$07PEAVLogSink@absl@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@@Z ??$__assume_valid_range@AEAPEAPEAVLogSink@absl@@AEAPEAPEAV12@@__Cr@std@@YAXAEAPEAPEAVLogSink@absl@@0@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03$$V@__base@__visitation@__variant_detail@__Cr@std@@CA$$QEA_PAEBU?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@34@_K@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z@__base@__visitation@__variant_detail@__Cr@std@@CAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@ZAEBQ6A_K01@Z@Z ??$__call@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@?$__invoke_void_return_wrapper@X$00@__Cr@std@@SAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@7@@Z ??$__call_func@V<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@@?$__policy_func@$$A6AXAEAVCommandLineFlag@absl@@@Z@__function@__Cr@std@@CAXPEBT__policy_storage@123@AEAVCommandLineFlag@absl@@@Z + ??$__clear_padding_if_needed@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z$0A@@__Cr@std@@YAAEAP6AXAEBUHashtablezInfo@container_internal@absl@@@ZAEAP6AX0@Z@Z + ??$__clear_padding_if_needed@PEAUHashtablezInfo@container_internal@absl@@$0A@@__Cr@std@@YAAEAPEAUHashtablezInfo@container_internal@absl@@AEAPEAU234@@Z + ??$__clear_padding_if_needed@PEAVCordzHandle@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzHandle@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVCordzInfo@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzInfo@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVVLogSite@log_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVVLogSite@log_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@VMaskedPointer@flags_internal@absl@@$0A@@__Cr@std@@YAAEAVMaskedPointer@flags_internal@absl@@AEAV234@@Z + ??$__clear_padding_if_needed@W4OnDeadlockCycle@absl@@$0A@@__Cr@std@@YAAEAW4OnDeadlockCycle@absl@@AEAW423@@Z + ??$__clear_padding_if_needed@W4State@PerThreadSynch@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4State@PerThreadSynch@base_internal@absl@@AEAW42345@@Z + ??$__clear_padding_if_needed@W4WaitState@ThreadIdentity@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4WaitState@ThreadIdentity@base_internal@absl@@AEAW42345@@Z ??$__constexpr_memmove@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@__Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAVLogSink@absl@@PEAV12@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0W4__element_count@01@@Z @@ -967,8 +945,8 @@ EXPORTS ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$__construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$__construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$__construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1082,10 +1060,6 @@ EXPORTS ??$__destroy_at@UUnrecognizedFlag@absl@@@__Cr@std@@YAXPEAUUnrecognizedFlag@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@@__Cr@std@@YAXPEAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@YAXPEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@01@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$00@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$01@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$02@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$0A@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z ??$__distance@PEBUPayload@status_internal@absl@@$0A@@__Cr@std@@YA_JPEBUPayload@status_internal@absl@@0@Z ??$__distance@PEBUTransition@cctz@time_internal@absl@@$0A@@__Cr@std@@YA_JPEBUTransition@cctz@time_internal@absl@@0@Z ??$__distance@PEBVFormatArgImpl@str_format_internal@absl@@$0A@@__Cr@std@@YA_JPEBVFormatArgImpl@str_format_internal@absl@@0@Z @@ -1135,10 +1109,14 @@ EXPORTS ??$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0AEBQEAV23@AEAU__identity@01@@Z ??$__find_if@PEAPEAVLogSink@absl@@PEAPEAV12@V<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAV12@PEAPEAV12@0AEBQEAV12@AEAU__identity@45@@Z@AEAU645@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0$$QEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAV23@00AEBQEAV23@AEAU__identity@01@@Z@2@Z ??$__for_each_segment@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@23@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V123@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@@__Cr@std@@YAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@01@0V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@01@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@01@00V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@01@@Z@@Z - ??$__get_alt@$00AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$01AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$02AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$0A@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$01AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$01AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$02AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$02AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$0A@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$0A@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$00@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$00@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$01@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$01@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$0A@@34@@Z @@ -1164,7 +1142,6 @@ EXPORTS ??$__in_bounds@V?$__bucket_list_deallocator@V?$allocator@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@23@$0A@@__unique_ptr_array_bounds_stateless@__Cr@std@@QEBA_NPEAPEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@_K@Z ??$__insert_assign_n_unchecked@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAAXV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@_JPEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$__insert_with_size@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@V423@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1_J@Z - ??$__invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$__invoke@AEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAU__identity@__Cr@std@@AEAPEAVLogSink@absl@@@__Cr@std@@YAAEAPEAVLogSink@absl@@AEAU__identity@01@AEAPEAV23@@Z @@ -1173,10 +1150,6 @@ EXPORTS ??$__invoke@AEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV45@0AEBQEAV45@AEAU__identity@23@@Z@AEAPEAV45@@__Cr@std@@YA_NAEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAVLogSink@absl@@PEAPEAV34@0AEBQEAV34@AEAU__identity@01@@Z@AEAPEAV34@@Z ??$__invoke@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@__Cr@std@@YAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@6@@Z ??$__invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@501@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$Span@$$CBD@5@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@IHM@01@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@_K_JIH_N@01@@Z @@ -1245,7 +1218,6 @@ EXPORTS ??$__lower_bound_bisecting@U_ClassicAlgPolicy@__Cr@std@@PEBUTransition@cctz@time_internal@absl@@U4567@U__identity@23@UByUnixTime@4567@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@AEBU2345@_JAEAUByUnixTime@2345@AEAU__identity@01@@Z ??$__make_exception_guard@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@01@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@AEAAX_K@Z@@Z ??$__make_exception_guard@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@01@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@01@@Z - ??$__make_value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@CA?A_P$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@@Z ??$__memberwise_forward_assign@V?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@V?$tuple@PEAVCommandLineFlag@absl@@_N@23@PEAVCommandLineFlag@absl@@_N$$Z$0A@$00@__Cr@std@@YAXAEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@U?$__type_list@PEAVCommandLineFlag@absl@@_N@01@U?$__integer_sequence@_K$0A@$00@01@@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z @@ -1283,17 +1255,12 @@ EXPORTS ??$__static_fancy_pointer_cast@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@PEAV?$__tree_node_base@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@AEBQEAV?$__tree_node_base@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@@Z - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JN@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0@Z ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0U?$integral_constant@_N$0A@@01@@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z - ??$__throw_if_valueless@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__Cr@std@@YAXAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__to_address@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z ??$__to_address@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@YAPEAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@01@PEAPEAU201@@Z @@ -1364,24 +1331,21 @@ EXPORTS ??$__validate_iter_reference@AEAPEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEAVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@56@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@01234@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z - ??$__visit_value@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J_J$0A@@__Cr@std@@YAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@V?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@01@_J@Z ??$advance@V?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@_J@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAV?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@12@_J@Z ??$advance@V?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@01@_J@Z ??$advance@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@01@_J@Z - ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$assign@PEBVSourceLocation@absl@@$0A@@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEAAXPEBVSourceLocation@1@0@Z ??$assign@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@$0A@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0@Z @@ -1392,9 +1356,15 @@ EXPORTS ??$bit_cast@U?$FlagValueAndInitBit@_N@flags_internal@absl@@_J@__Cr@std@@YA?AU?$FlagValueAndInitBit@_N@flags_internal@absl@@AEB_J@Z ??$bit_cast@VFastTypeIdType@absl@@PEAX@__Cr@std@@YA?AVFastTypeIdType@absl@@AEBQEAX@Z ??$c_begin@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_begin@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_begin@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_begin@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$c_copy@V?$Span@$$CBI@absl@@PEAI@absl@@YAPEAIAEBV?$Span@$$CBI@0@$$QEAPEAI@Z + ??$c_copy@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@Z + ??$c_copy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@Z ??$c_end@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_end@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_end@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_end@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$call_once@A6AXXZ$$V@absl@@YAXAEAVonce_flag@0@A6AXXZ@Z ??$call_once@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@absl@@YAXAEAVonce_flag@0@$$QEAP8FlagImpl@flags_internal@0@EAAXXZ$$QEAPEAV230@@Z @@ -1405,8 +1375,8 @@ EXPORTS ??$combine@V?$tuple@AEB_K@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEBV?$tuple@AEB_K@__Cr@std@@@Z ??$combine@_K$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEB_K@Z ??$combine_contiguous@D@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@PEBD_K@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV45678@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEBV45678@@Z ??$construct@PEAUCordRep@cord_internal@absl@@AEBQEAU123@$0A@@?$allocator_traits@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@12@PEAPEAUCordRep@cord_internal@absl@@AEBQEAU456@@Z @@ -1425,8 +1395,8 @@ EXPORTS ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@$0A@@?$allocator_traits@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$$QEAU4567@@Z ??$construct@UPayload@status_internal@absl@@AEBU123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@AEBU456@@Z ??$construct@UPayload@status_internal@absl@@U123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@$$QEAU456@@Z @@ -1442,12 +1412,12 @@ EXPORTS ??$construct@UUnrecognizedFlag@absl@@U12@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAU45@@Z ??$construct@UUnrecognizedFlag@absl@@W4Source@12@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$construct@UViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV456@AEA_K$0A@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@PEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEBV712@AEA_K@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@23@AEBV678@@Z@$0A@@?$allocator_traits@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV789@@Z@@Z ??$construct@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V123@$0A@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@12@$$QEAV412@@Z ??$construct@VFormatArgImpl@str_format_internal@absl@@AEBV123@$0A@@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@12@PEAVFormatArgImpl@str_format_internal@absl@@AEBV456@@Z @@ -1473,8 +1443,8 @@ EXPORTS ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1534,13 +1504,13 @@ EXPORTS ??$distance@V?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z ??$distance@V?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$element@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@@Z + ??$emplace@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$emplace@$$V@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransition@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransition@cctz@time_internal@absl@@@12@@Z ??$emplace@$$V@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@12@@Z ??$emplace@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@?$optional@VStream@status_internal@absl@@@__Cr@std@@QEAAAEAVStream@status_internal@absl@@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$emplace@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$emplace_back@$$V@?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAXAEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -1575,11 +1545,9 @@ EXPORTS ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$forward_as_tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@AEBQEAVCommandLineFlag@absl@@@Z - ??$forward_as_tuple@PEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAPEAPEAUCordRep@cord_internal@2@XZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEA_KXZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEB_KXZ @@ -1602,7 +1570,6 @@ EXPORTS ??$get@$00PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEA_NAEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$01@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEBUStringEq@12@XZ ??$get@$02@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGAAAEAV?$allocator@D@__Cr@std@@XZ - ??$get@$0A@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEBV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ @@ -1622,7 +1589,6 @@ EXPORTS ??$get@$0A@@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEB_KXZ ??$get@$0A@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@@Z ??$get@$0A@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@23@@__Cr@std@@YAAEAUFindInfo@container_internal@absl@@AEAV?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@23@@01@@Z - ??$get@$0A@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YAAEBQEAVCommandLineFlag@absl@@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YA$$QEAPEAVCommandLineFlag@absl@@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$hash@H@MixingHashState@hash_internal@absl@@SA_KAEBH@Z @@ -1641,7 +1607,6 @@ EXPORTS ??$hash_with_seed@V?$tuple@AEB_K@__Cr@std@@$0A@@MixingHashState@hash_internal@absl@@SA_KAEBV?$tuple@AEB_K@__Cr@std@@_K@Z ??$insert@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$insert@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@__Cr@std@@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1@Z - ??$invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@AEAPEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@0@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@PEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@$$QEAPEAPEAV34@@Z @@ -1667,6 +1632,7 @@ EXPORTS ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@XZ ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@AEAV12@$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@AEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$make_unique@VFallbackCrcMemcpyEngine@crc_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@01@XZ + ??$make_unique@VFlagSaverImpl@flags_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@01@XZ ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@AEAPEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@AEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@PEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@_JAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEA_JAEA_N21@Z @@ -1750,6 +1716,7 @@ EXPORTS ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?A_PPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer_impl@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@CA?AU?$integral_constant@_N$00@__Cr@std@@PEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@45@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1URank2@012@@Z + ??$ts_unchecked_read@PEAUHashtablezInfo@container_internal@absl@@@base_internal@absl@@YAAEAPEAUHashtablezInfo@container_internal@1@AEAPEAU231@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByCivilTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByCivilTime@2345@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z ??$value_or@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$optional_ref@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -1775,10 +1742,6 @@ EXPORTS ??0?$FormatSpecTemplate@$0JPPPL@@str_format_internal@absl@@QEAA@PEBD@Z ??0?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@_K@Z ??0?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@_K@Z - ??0?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAA@V?$HashtableCapacityImpl@$00@12@Uno_seed_empty_tag_t@12@@Z ??0?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAA@AEBV01@@Z @@ -2120,6 +2083,10 @@ EXPORTS ??0GroupPortableImpl@container_internal@absl@@QEAA@PEBW4ctrl_t@12@@Z ??0GrowthInfoLowerBound@container_internal@absl@@QEAA@E@Z ??0HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEAA@PEBE@Z + ??0HashtableCapacity@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@_K@Z + ??0HashtableInlineData@container_internal@absl@@QEAA@VHashtableCapacity@12@Uno_seed_empty_tag_t@12@@Z ??0HashtablezInfo@container_internal@absl@@QEAA@XZ ??0HashtablezInfoHandle@container_internal@absl@@QEAA@$$T@Z ??0Hex@absl@@AEAA@W4PadSpec@1@_K@Z @@ -2168,11 +2135,12 @@ EXPORTS ??0PrefixCrc@CrcCordState@crc_internal@absl@@QEAA@_KVcrc32c_t@3@@Z ??0ProtoField@log_internal@absl@@QEAA@XZ ??0Randen@random_internal@absl@@QEAA@XZ + ??0RawHashSetLayout@container_internal@absl@@AEAA@Uuninitialized_tag_t@12@@Z ??0RawHashSetLayout@container_internal@absl@@QEAA@_K00_N0@Z ??0ReaderMutexLock@absl@@QEAA@AEAVMutex@1@@Z + ??0ReentranceGuard@container_internal@absl@@QEAA@AEAVCommonFields@12@@Z ??0RefcountAndFlags@cord_internal@absl@@QEAA@XZ ??0RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??0ReleasableMutexLock@absl@@QEAA@AEAVMutex@1@@Z ??0Rep@CordBuffer@absl@@QEAA@PEAUCordRepFlat@cord_internal@2@@Z ??0Rep@CordBuffer@absl@@QEAA@XZ ??0Rep@CrcCordState@crc_internal@absl@@QEAA@XZ @@ -2371,6 +2339,7 @@ EXPORTS ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ + ??1?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ @@ -2432,8 +2401,8 @@ EXPORTS ??1Payload@status_internal@absl@@QEAA@XZ ??1PosixTimeZone@cctz@time_internal@absl@@QEAA@XZ ??1ReaderMutexLock@absl@@QEAA@XZ + ??1ReentranceGuard@container_internal@absl@@QEAA@XZ ??1RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??1ReleasableMutexLock@absl@@QEAA@XZ ??1Rep@CrcCordState@crc_internal@absl@@QEAA@XZ ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ @@ -2571,7 +2540,6 @@ EXPORTS ??8strings_internal@absl@@YA_NAEBV?$SplitIterator@V?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z ??9CharIterator@Cord@absl@@QEBA_NAEBV012@@Z ??9ChunkIterator@Cord@absl@@QEBA_NAEBV012@@Z - ??9GraphId@synchronization_internal@absl@@QEBA_NAEBU012@@Z ??9__Cr@std@@YA_NAEBU__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z @@ -2581,7 +2549,6 @@ EXPORTS ??9absl@@YA_NVFastTypeIdType@0@0@Z ??9absl@@YA_NVint128@0@0@Z ??9absl@@YA_NVuint128@0@0@Z - ??9container_internal@absl@@YA_NAEBV?$BitMask@_K$07$02$00@01@0@Z ??9container_internal@absl@@YA_NAEBV?$BitMask@_K$07$02$0A@@01@0@Z ??9container_internal@absl@@YA_NAEBViterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@0@Z ??9strings_internal@absl@@YA_NAEBV?$SplitIterator@V?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z @@ -2594,7 +2561,6 @@ EXPORTS ??A?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEBAAEBVFormatArgImpl@str_format_internal@1@_K@Z ??A?$Span@D@absl@@QEBAAEAD_K@Z ??A?$Span@I@absl@@QEBAAEAI_K@Z - ??A?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@__Cr@std@@QEBAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@12@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@612@@Z_K@Z ??A?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEBAAEAPEAVCommandLineFlag@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@__Cr@std@@QEBAAEAPEAVCordzHandle@cord_internal@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVLogSink@absl@@@__Cr@std@@QEBAAEAPEAVLogSink@absl@@_J@Z @@ -2626,6 +2592,7 @@ EXPORTS ??B?$function@$$A6A_NAEBVCommandLineFlag@absl@@@Z@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ??B?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ @@ -2665,6 +2632,7 @@ EXPORTS ??C?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAULogMessageData@LogMessage@log_internal@absl@@XZ ??C?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAURep@StatusBuilder@absl@@XZ ??C?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ + ??C?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVFlagSaverImpl@flags_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneIf@cctz@time_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneInfo@cctz@time_internal@absl@@XZ ??CChunkIterator@Cord@absl@@QEBAPEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ @@ -2706,6 +2674,7 @@ EXPORTS ??D?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAVSourceLocation@absl@@@__Cr@std@@QEBA$$QEAVSourceLocation@absl@@XZ + ??DCharIterator@Cord@absl@@QEBAAEBDXZ ??DChunkIterator@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ??D__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU__deque_block_range@123@XZ ??Dabsl@@YA?AVint128@0@V10@0@Z @@ -2791,6 +2760,7 @@ EXPORTS ??Pabsl@@YA_NVint128@0@0@Z ??Pabsl@@YA_NVuint128@0@0@Z ??R<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@23@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@QEBA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@2@Z + ??R<lambda_1>@?0???$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@QEBA?A?<auto>@@PEAD_K@Z @@ -2802,8 +2772,6 @@ EXPORTS ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2817,11 +2785,9 @@ EXPORTS ??R<lambda_1>@?0???$emplace_back@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@$$QEAV423@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@W4Source@UnrecognizedFlag@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??Append@FormatSinkImpl@str_format_internal@absl@@QEAAX_KD@Z@QEBA?A?<auto>@@0@Z - ??R<lambda_1>@?0??AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@23@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHAEBV23@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV456@@Z ??R<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@QEBA?A?<auto>@@AEAVCommandLineFlag@4@@Z - ??R<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@0@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2837,7 +2803,6 @@ EXPORTS ??R?$ConvertToContainer@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$FunctionRef@$$A6AXPEAUCordRep@cord_internal@absl@@_K1@Z@absl@@QEBAXPEAUCordRep@cord_internal@1@_K1@Z - ??R?$FunctionRef@$$A6AXPEAXPEBX@Z@absl@@QEBAXPEAXPEBX@Z ??R?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@absl@@QEBAXPEBW4ctrl_t@container_internal@1@PEAX@Z ??R?$FunctionRef@$$A6AXV?$Span@I@absl@@@Z@absl@@QEBAXV?$Span@I@1@@Z ??R?$FunctionRef@$$A6AXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z@absl@@QEBAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -2867,6 +2832,7 @@ EXPORTS ??R?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@QEBAXPEAURep@StatusBuilder@absl@@@Z ??R?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@QEBAXPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??R?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@QEBAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??R?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ??R?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagState@flags_internal@absl@@@Z ??R?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagStateInterface@flags_internal@absl@@@Z ??R?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@QEBAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -2933,6 +2899,7 @@ EXPORTS ??_5uint128@absl@@QEAAAEAV01@V01@@Z ??_6uint128@absl@@QEAAAEAV01@V01@@Z ??_DOStringStream@strings_internal@absl@@QEAAXXZ + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbsDuration@absl@@YA?AVDuration@1@V21@@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3021,6 +2988,7 @@ EXPORTS ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z ?AnnotateConstruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z ?AnnotateDestruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@Cord@absl@@QEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3048,24 +3016,22 @@ EXPORTS ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AEAAX_K@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z - ?AreItersFromSameContainer@container_internal@absl@@YA_NAEBQEBW4ctrl_t@12@0PEBX1@Z ?AsValueType@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@CAPEADPEAD@Z ?AsciiStrToLower@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@CordzInfo@cord_internal@absl@@QEAAXXZ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertHeld@SpinLock@base_internal@absl@@QEBAXXZ ?AssertInSooMode@CommonFields@container_internal@absl@@AEBAXXZ - ?AssertIsFull@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBEPEBD@Z - ?AssertIsValidForComparison@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBE@Z + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEBAXXZ ?AssertNotDebugCapacity@CommonFields@container_internal@absl@@QEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ - ?AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@_N@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEBV123@PEBV123@_N@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QEBAXVFastTypeIdType@3@P6APEBVtype_info@@XZ@Z @@ -3104,6 +3070,7 @@ EXPORTS ?CalculateBase64EscapedLenInternal@strings_internal@absl@@YA_K_K_N@Z ?CallVoidPtrFunction@Condition@absl@@CA_NPEBV12@@Z ?Capacity@CordRepFlat@cord_internal@absl@@QEBA_KXZ + ?CapacityBits@HashtableInlineData@container_internal@absl@@CA_KVHashtableCapacity@23@@Z ?CapacityToGrowth@container_internal@absl@@YA_K_K@Z ?CappedDamerauLevenshteinDistance@strings_internal@absl@@YAEV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0E@Z ?CatPieces@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$initializer_list@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@5@@Z @@ -3177,7 +3144,7 @@ EXPORTS ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?ConvertSpecialToEmptyAndFullToDeleted@GroupAArch64Impl@container_internal@absl@@QEBAXPEAW4ctrl_t@23@@Z ?Copy@CordRepBtree@cord_internal@absl@@AEBAPEAV123@XZ - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?Copy@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z ?CopyBeginTo@CordRepBtree@cord_internal@absl@@AEBAPEAV123@_K0@Z ?CopyConstruct@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z @@ -3198,8 +3165,9 @@ EXPORTS ?CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PEIAXPEIBX_KV43@_N@Z ?Create@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAUCordRep@23@@Z ?Create@CordRepFlat@cord_internal@absl@@SAPEAU123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z - ?CreateDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ - ?CreateReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ + ?CreateDestroyed@HashtableCapacity@container_internal@absl@@SA?AV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z + ?CreateReentrance@HashtableCapacity@container_internal@absl@@SA?AV123@XZ ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -3223,6 +3191,8 @@ EXPORTS ?DeallocateIfAllocated@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -3272,6 +3242,7 @@ EXPORTS ?Digits10@?$BigUnsigned@$0FE@@strings_internal@absl@@SAHXZ ?DisableFlagfileAndEnvParsing@absl@@YAXXZ ?DisableRescheduling@SchedulingGuard@base_internal@absl@@SA_NXZ + ?Distance@Cord@absl@@SA_JAEBVCharIterator@12@0@Z ?DoIgnoreLeak@absl@@YAXPEBX@Z ?DoLoad@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBVCord@absl@@@Z@base_internal@absl@@AEBAP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBVCord@3@@ZXZ ?DoLoad@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@AEBAP6AXPEBDH000@ZXZ @@ -3360,6 +3331,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32c@absl@@YA?AVcrc32c_t@1@V21@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3400,7 +3372,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -3489,7 +3460,7 @@ EXPORTS ?FromHost64@little_endian@absl@@YA_K_K@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0DM@$00@__Cr@std@@@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0OBA@$00@__Cr@std@@@Z - ?FromRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@_K@Z + ?FromRawData@HashtableCapacity@container_internal@absl@@SA?AV123@_K@Z ?FromTM@absl@@YA?AVTime@1@AEBUtm@@VTimeZone@1@@Z ?FromUDate@absl@@YA?AVTime@1@N@Z ?FromUniversal@absl@@YA?AVTime@1@_J@Z @@ -3565,6 +3536,7 @@ EXPORTS ?GetGrowthLeft@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ ?GetGrowthLeftLowerBound@CommonFields@container_internal@absl@@QEBA_KXZ ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -3757,7 +3729,7 @@ EXPORTS ?IsDataLoss@absl@@YA_NAEBVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NAEBVStatus@1@@Z ?IsDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z - ?IsDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsDestroyed@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsEmpty@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsEmptyOrDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsExternal@CordRep@cord_internal@absl@@QEBA_NXZ @@ -3785,7 +3757,7 @@ EXPORTS ?IsPermissionDenied@absl@@YA_NAEBVStatus@1@@Z ?IsPow2@CordBuffer@absl@@CA_N_K@Z ?IsReachable@GraphCycles@synchronization_internal@absl@@QEBA_NUGraphId@23@0@Z - ?IsReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsReentrance@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsResourceExhausted@absl@@YA_NAEBVStatus@1@@Z ?IsRetired@CommandLineFlag@absl@@UEBA_NXZ ?IsSMTEnabled@base_internal@absl@@YA_NXZ @@ -3801,8 +3773,8 @@ EXPORTS ?IsUnimplemented@absl@@YA_NAEBVStatus@1@@Z ?IsUnknown@absl@@YA_NAEBVStatus@1@@Z ?IsUnprotectedReadCandidate@MaskedPointer@flags_internal@absl@@QEBA_NXZ - ?IsValid@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ ?IsValid@CordRepBtree@cord_internal@absl@@SA_NPEBV123@_N@Z + ?IsValid@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsValidCapacity@container_internal@absl@@YA_N_K@Z ?IterateOverFullSlots@container_internal@absl@@YAXAEBVCommonFields@12@_KV?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@2@@Z ?JoinMessageToStatus@StatusPrivateAccessorForStatusBuilder@status_internal@absl@@SA?AVStatus@3@V43@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@W4MessageJoinStyle@3@@Z @@ -3958,6 +3930,7 @@ EXPORTS ?NumClonedBytes@container_internal@absl@@YA_KXZ ?NumContextsPerCPU@base_internal@absl@@YAHXZ ?NumControlBytes@container_internal@absl@@YA_K_K@Z + ?NumControlBytesForLargeTable@container_internal@absl@@YA_K_K@Z ?NumGenerationBytes@container_internal@absl@@YA_KXZ ?NumLeakedFlagValues@flags_internal@absl@@YA_KXZ ?ODRCheck@CordzInfo@cord_internal@absl@@AEBAXXZ @@ -4010,9 +3983,9 @@ EXPORTS ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrecombineLengthMix@hash_internal@absl@@YA_K_K0@Z ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -4342,6 +4315,7 @@ EXPORTS ?TakeRep@Cord@absl@@AEHAAPEAUCordRep@cord_internal@2@XZ ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -4405,9 +4379,8 @@ EXPORTS ?ToInt64Nanoseconds@absl@@YA_JVDuration@1@@Z ?ToInt64Seconds@absl@@YA_JVDuration@1@@Z ?ToOpResult@CordRepBtree@cord_internal@absl@@AEAA?AUOpResult@123@_N@Z - ?ToPublicSeed@?$HashtableInlineDataImpl@$00@container_internal@absl@@CA_K_K@Z - ?ToRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBAEXZ ?ToRawData@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ + ?ToRawData@HashtableCapacity@container_internal@absl@@QEBAEXZ ?ToSinkAlso@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToSinkOnly@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToString@?$BigUnsigned@$03@strings_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -4690,7 +4663,6 @@ EXPORTS ?__annotate_shrink_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_K0@Z ?__annotate_whole_block@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z ?__annotate_whole_block@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z - ?__as_base@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@IEGAA@XZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_size_layout@V?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -4797,6 +4769,17 @@ EXPORTS ?__destruct_at_end@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransition@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransitionType@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUViableSubstitution@strings_internal@absl@@@Z + ?__empty@?$__vector_layout@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end_node@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAPEAV?$__tree_end_node@PEAV?$__tree_node_base@PEAX@__Cr@std@@@23@XZ @@ -5153,7 +5136,6 @@ EXPORTS ?base@?$move_iterator@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@QEGBAAEBQEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ ?base@?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@QEGBAAEBQEAUTransition@cctz@time_internal@absl@@XZ ?base@?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEGBAAEBQEAUTransitionType@cctz@time_internal@absl@@XZ - ?begin@?$BitMask@_K$07$02$00@container_internal@absl@@QEBA?AV123@XZ ?begin@?$BitMask@_K$07$02$0A@@container_internal@absl@@QEBA?AV123@XZ ?begin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAAPEAUPayload@status_internal@2@XZ ?begin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ @@ -5207,8 +5189,8 @@ EXPORTS ?begin@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?begin@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?begin@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?blocked_element_count@CommonFields@container_internal@absl@@QEBA_KXZ + ?blocked_element_count@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?btree@CordRep@cord_internal@absl@@QEAAPEAVCordRepBtree@23@XZ ?btree@CordRep@cord_internal@absl@@QEBAPEBVCordRepBtree@23@XZ ?btree@CordRepBtreeNavigator@cord_internal@absl@@QEBAPEAVCordRepBtree@23@XZ @@ -5216,8 +5198,6 @@ EXPORTS ?bucket_count@?$__hash_table@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEBA_KXZ ?bucket_count@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?bytes_value@ProtoField@log_internal@absl@@QEBA?AV?$Span@$$CBD@3@XZ - ?capacity@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_KXZ - ?capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_size_layout@V?$__split_buffer@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@V__split_buffer_size_layout@45@@__Cr@std@@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -5246,7 +5226,9 @@ EXPORTS ?capacity@CommonFields@container_internal@absl@@QEBA_KXZ ?capacity@CordBuffer@absl@@QEBA_KXZ ?capacity@CordRepBtree@cord_internal@absl@@QEBA_KXZ - ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?capacity@HashtableCapacity@container_internal@absl@@QEBA_KXZ + ?capacity@HashtableInlineData@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ + ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?cbegin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ ?cbegin@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA?AV?$__wrap_iter@PEBQEAVLogSink@absl@@@23@XZ ?cend@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ @@ -5409,8 +5391,8 @@ EXPORTS ?deallocate@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@23@PEAVFormatArgImpl@str_format_internal@absl@@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VSourceLocation@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VSourceLocation@absl@@@23@PEAVSourceLocation@absl@@_K@Z - ?decrement_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?decrement_size@CommonFields@container_internal@absl@@QEAAXXZ + ?decrement_size@HashtableInlineData@container_internal@absl@@QEAAXXZ ?delimiter@?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByChar@3@XZ @@ -5425,7 +5407,6 @@ EXPORTS ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ ?element@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z ?emplace@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@CAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z - ?empty@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?empty@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEBA_NXZ @@ -5450,9 +5431,9 @@ EXPORTS ?empty@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?empty@CommonFields@container_internal@absl@@QEBA_NXZ ?empty@Cord@absl@@QEBA_NXZ + ?empty@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?encoded_message@LogEntry@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?encoded_remaining@LogMessageData@LogMessage@log_internal@absl@@QEAAAEAV?$Span@D@4@XZ - ?end@?$BitMask@_K$07$02$00@container_internal@absl@@QEBA?AV123@XZ ?end@?$BitMask@_K$07$02$0A@@container_internal@absl@@QEBA?AV123@XZ ?end@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ ?end@?$Span@$$CBI@absl@@QEBAPEBIXZ @@ -5504,7 +5485,6 @@ EXPORTS ?end@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?end@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?end@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?eq_ref@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBAAEBUStringEq@23@XZ ?erase@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAAPEAUPayload@status_internal@2@PEBU342@@Z ?erase@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAPEAVLogSink@absl@@@23@V?$__wrap_iter@PEBQEAVLogSink@absl@@@23@@Z @@ -5528,8 +5508,8 @@ EXPORTS ?gbswap_16@absl@@YAGG@Z ?gbswap_32@absl@@YAII@Z ?gbswap_64@absl@@YA_K_K@Z - ?generate_new_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?generate_new_seed@CommonFields@container_internal@absl@@QEAAX_N@Z + ?generate_new_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ ?generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation@HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation_offset@RawHashSetLayout@container_internal@absl@@QEBA_KXZ @@ -5581,10 +5561,8 @@ EXPORTS ?get@?$__temp_value@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransition@cctz@time_internal@absl@@XZ ?get@?$__temp_value@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransitionType@cctz@time_internal@absl@@XZ ?get@?$__tuple_leaf@$00AEAV?$NonIterableBitMask@_K$07$02@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAV?$NonIterableBitMask@_K$07$02@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAUFindInfo@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAUFindInfo@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEBQEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@PEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?get@?$unique_ptr@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$__allocator_destructor@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ @@ -5624,10 +5602,10 @@ EXPORTS ?get_soo_data@HeapOrSoo@container_internal@absl@@QEBAPEBXXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z ?get_yearday@detail@cctz@time_internal@absl@@YAHAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z - ?growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ + ?growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ ?has_alt_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ - ?has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?has_infoz@CommonFields@container_internal@absl@@QEBA_NXZ + ?has_infoz@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?has_left_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_show_pos_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ @@ -5647,22 +5625,24 @@ EXPORTS ?hour@?$civil_time@Uhour_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?increment_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?increment_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?increment_size@CommonFields@container_internal@absl@@QEAAXXZ ?increment_size@CommonFields@container_internal@absl@@QEAAX_K@Z + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?index@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_KXZ ?index@?$probe_seq@$07@container_internal@absl@@QEBA_KXZ + ?index@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_KXZ ?index@CordRepBtree@cord_internal@absl@@QEBA_KW4EdgeType@123@@Z ?infoz@CommonFields@container_internal@absl@@QEAA?AVHashtablezInfoHandle@23@XZ + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ - ?init_blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z ?init_blocked_element_count@CommonFields@container_internal@absl@@QEAAX_K@Z + ?init_blocked_element_count@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?inline_size@InlineData@cord_internal@absl@@QEBA_KXZ ?inline_size@InlineRep@Cord@absl@@AEBA_KXZ ?inline_size@Rep@InlineData@cord_internal@absl@@QEBA_KXZ - ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z + ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z ?insert@?$unordered_set@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEAA?AU?$pair@V?$__hash_const_iterator@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBQEBUCordRep@cord_internal@absl@@@Z ?int32_value@ProtoField@log_internal@absl@@QEBAHXZ ?int64_value@ProtoField@log_internal@absl@@QEBA_JXZ @@ -5677,13 +5657,13 @@ EXPORTS ?is_length@ConvTag@str_format_internal@absl@@QEBA_NXZ ?is_profiled@InlineData@cord_internal@absl@@QEBA_NXZ ?is_relative_timeout@KernelTimeout@synchronization_internal@absl@@QEBA_NXZ - ?is_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ + ?is_sampled_seed@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_short@Rep@CordBuffer@absl@@QEBA_NXZ ?is_single_group@container_internal@absl@@YA_N_K@Z - ?is_small@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ - ?is_small@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?is_small@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_small@CommonFields@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableCapacity@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QEBA_NXZ ?is_soo@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_tree@InlineData@cord_internal@absl@@QEBA_NXZ @@ -5742,8 +5722,8 @@ EXPORTS ?max_size@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_KXZ ?max_size@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?maybe_increment_generation_on_insert@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXXZ - ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AV?$HashtableCapacityImpl@$00@23@XZ - ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AVHashtableCapacity@23@XZ + ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?memcasecmp@strings_internal@absl@@YAHPEBD0_K@Z ?message@Status@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?message@StatusRep@status_internal@absl@@QEBAAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -5775,10 +5755,10 @@ EXPORTS ?ok@Status@absl@@QEBA_NXZ ?ok@Utf8ForCodePoint@debugging_internal@absl@@QEBA_NXZ ?overflow@Streambuf@OStringStream@strings_internal@absl@@MEAAHH@Z - ?overwrite_control_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXW4ctrl_t@23@@Z - ?overwrite_empty_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_deleted@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_empty_in_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?overwrite_control_as_full@HashtableInlineData@container_internal@absl@@QEAAXW4ctrl_t@23@@Z + ?overwrite_empty_as_full@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_deleted@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_empty_in_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXXZ ?parse@detail@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0AEBVtime_zone@234@PEAV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@PEAV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@chrono@67@PEAV567@@Z ?parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBAPEBVParsedFormatBase@23@XZ ?pointer_to@?$pointer_traits@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@23@AEAU423@@Z @@ -5821,6 +5801,7 @@ EXPORTS ?push_back@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUTransition@cctz@time_internal@absl@@@Z ?push_back@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUUnrecognizedFlag@absl@@@Z ?raw_code@Status@absl@@QEBAHXZ + ?read_byte@HashtableInlineData@container_internal@absl@@AEBAE_K@Z ?reduce_size@InlineRep@Cord@absl@@QEAAX_K@Z ?release@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?release@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEAAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ @@ -5864,6 +5845,7 @@ EXPORTS ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagState@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagStateInterface@flags_internal@absl@@@Z ?reset@?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -5889,17 +5871,19 @@ EXPORTS ?scale_add@impl@detail@cctz@time_internal@absl@@YA_J_J00@Z ?second@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?second@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@CommonFields@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ + ?seed@HashtableInlineData@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@PerTableSeed@container_internal@absl@@QEBA_KXZ ?set@?$MaybeInitializedPtr@W4ctrl_t@container_internal@absl@@@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_arg@BoundConversion@str_format_internal@absl@@QEAAXPEBVFormatArgImpl@23@@Z ?set_begin@CordRepBtree@cord_internal@absl@@AEAAX_K@Z - ?set_blocked_element_count_to_zero@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?set_blocked_element_count_to_zero@CommonFields@container_internal@absl@@QEAAXXZ - ?set_capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z - ?set_capacity@CommonFields@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z + ?set_blocked_element_count_to_zero@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_capacity@CommonFields@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z ?set_capacity@CommonFields@container_internal@absl@@QEAAX_K@Z + ?set_capacity@CommonFields@container_internal@absl@@QECAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QECAXVHashtableCapacity@23@@Z ?set_control@CommonFields@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_conversion_char@FormatConversionSpecImpl@str_format_internal@absl@@QEAAXW4FormatConversionChar@3@@Z ?set_cordz_info@InlineData@cord_internal@absl@@QEAAXPEAVCordzInfo@23@@Z @@ -5913,9 +5897,9 @@ EXPORTS ?set_full_soo@CommonFields@container_internal@absl@@QEAAXXZ ?set_generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXE@Z ?set_generation_ptr@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXPEAE@Z - ?set_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z - ?set_has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?set_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z ?set_has_infoz@CommonFields@container_internal@absl@@QEAAXXZ + ?set_has_infoz@HashtableInlineData@container_internal@absl@@QEAAXXZ ?set_infoz@CommonFields@container_internal@absl@@QEAAXVHashtablezInfoHandle@23@@Z ?set_inline_data@InlineData@cord_internal@absl@@QEAAXPEBD_K@Z ?set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z @@ -5923,10 +5907,10 @@ EXPORTS ?set_inline_size@Rep@InlineData@cord_internal@absl@@QEAAX_K@Z ?set_reservation_size@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z ?set_reserved_growth@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z - ?set_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?set_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@AEAAXE@Z + ?set_sampled_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_seed@HashtableInlineData@container_internal@absl@@AEAAXE@Z ?set_short_length@Rep@CordBuffer@absl@@QEAAX_K@Z - ?set_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?set_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?set_size_to_zero@CommonFields@container_internal@absl@@QEAAXXZ ?set_tag@Rep@InlineData@cord_internal@absl@@QEAAXC@Z ?set_tree@InlineData@cord_internal@absl@@QEAAXPEAUCordRep@23@@Z @@ -5939,11 +5923,11 @@ EXPORTS ?shrink_to_fit@?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?single_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@123@XZ + ?single_non_soo_slot@CommonFields@container_internal@absl@@QEBAPEAXXZ ?single_slot@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@XZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?size@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ - ?size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ @@ -5988,6 +5972,7 @@ EXPORTS ?size@CommonFields@container_internal@absl@@QEBA_KXZ ?size@Cord@absl@@QEBA_KXZ ?size@CordRepBtree@cord_internal@absl@@QEBA_KXZ + ?size@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?size@InlineRep@Cord@absl@@QEBA_KXZ ?size@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ ?skip_empty_or_deleted@iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXXZ @@ -6037,7 +6022,7 @@ EXPORTS ?timestamp@LogEntry@absl@@QEBA?AVTime@2@XZ ?total_written@BufferRawSink@str_format_internal@absl@@QEBA_KXZ ?transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@0@Z - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?tree@InlineRep@Cord@absl@@QEBAPEAUCordRep@cord_internal@3@XZ ?tree@Rep@InlineData@cord_internal@absl@@QEBAPEAUCordRep@34@XZ ?try_lock@Mutex@absl@@QEAA_NXZ @@ -6056,8 +6041,6 @@ EXPORTS ?value@InputValue@UnboundConversion@str_format_internal@absl@@QEBAHXZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ - ?valueless_by_exception@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_NXZ - ?valueless_by_exception@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_NXZ ?verbosity@LogEntry@absl@@QEBAHXZ ?version@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?what@BadStatusOrAccess@absl@@UEBAPEBDXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg_cxx23.def index 8caeab8e1946..669d332e57f3 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_arm64_dbg_cxx23.def @@ -1,20 +1,13 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$CBD$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEBD@Z ??$?0$$CBU?$atomic@_N@__Cr@std@@@Condition@absl@@QEAA@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z0@Z ??$?0$$CBUCordRep@cord_internal@absl@@@Hex@absl@@QEAA@PEBUCordRep@cord_internal@1@W4PadSpec@1@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$?0$$CBVFormatArgImpl@str_format_internal@absl@@$$CBV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEAA@V?$initializer_list@VFormatArgImpl@str_format_internal@absl@@@std@@@Z ??$?0$$CB_W$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEB_W@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z ??$?0$$T@?$Storage@PEAPEAUCordRep@cord_internal@absl@@$00U?$StorageTag@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAPEAVLogSink@absl@@$00U?$StorageTag@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@PEAPEAVLogSink@absl@@@internal_compressed_tuple@container_internal@2@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAUPayload@status_internal@absl@@$00U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@PEAUPayload@status_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z @@ -35,7 +28,6 @@ EXPORTS ??$?0$$V@PlacementImpl@?$NoDestructor@VMutex@absl@@@absl@@QEAA@XZ ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@QEAA@AEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@23@@__Cr@std@@QEAA@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@45@@Z - ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEAPEAPEAVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEAVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAPEBVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEBVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEBVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N$0A@@?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@QEAA@AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$QEA_N@Z @@ -67,8 +59,6 @@ EXPORTS ??$?0AEA_K@?$Storage@_K$0A@U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_K@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@$00@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEAA@AEA_KAEBV?$allocator@D@__Cr@std@@@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@@?$CompressedTupleImpl@V?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@U?$integer_sequence@_K$0A@$00@__Cr@std@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_KAEBV?$allocator@D@56@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEBV?$allocator@D@__Cr@std@@@?$Storage@V?$allocator@D@__Cr@std@@$00U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@D@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$0A@U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@UPayload@status_internal@absl@@@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEAA@AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$$QEAI@Z @@ -80,8 +70,6 @@ EXPORTS ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@Z ??$?0D@?$allocator@U?$AlignedType@$07@container_internal@absl@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@FormatArgImpl@str_format_internal@absl@@QEAA@AEBD@Z @@ -107,15 +95,10 @@ EXPORTS ??$?0PEAUTransitionType@cctz@time_internal@absl@@$0A@@?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@__Cr@std@@QEAA@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z ??$?0PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@PEAU0?1???R1234@QEBA?AV567@0@Z@$0A@@?$pair@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@PEAU1?1???R2345@QEBA?AV678@0@Z@@__Cr@std@@QEAA@$$QEAPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV567@@Z@1@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$tuple@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@$$QEAPEAVCommandLineFlag@absl@@@Z ??$?0PEAX@FlagState@flags_internal@absl@@QEAA@AEAVFlagImpl@12@AEBQEAX_N2_J@Z ??$?0PEBD@FormatArgImpl@str_format_internal@absl@@QEAA@AEBQEBD@Z ??$?0PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU0123@$0A@@?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@__Cr@std@@QEAA@$$QEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$?0PEBVFormatArgImpl@str_format_internal@absl@@$0A@@?$InlinedVector@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@absl@@QEAA@PEBVFormatArgImpl@str_format_internal@1@0AEBV?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@?$FunctionRef@$$A6A_K_K@Z@absl@@IEAA@Uin_place_t@__Cr@std@@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@X@?$FunctionRef@$$A6A_K_K@Z@absl@@QEAA@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z ??$?0U?$array@D$0DKJI@@__Cr@std@@XU012@H@?$Span@D@absl@@QEAA@AEAU?$array@D$0DKJI@@__Cr@std@@@Z ??$?0U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAULogMessageData@LogMessage@log_internal@absl@@@Z @@ -125,6 +108,7 @@ EXPORTS ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??$?0U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??$?0U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagSaverImpl@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagState@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@$$T@Z ??$?0U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVTimeZoneInfo@cctz@time_internal@absl@@@Z @@ -281,6 +265,7 @@ EXPORTS ??$?DPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@12@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@12@XZ + ??$?DPEAVFlagSaverImpl@flags_internal@absl@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagSaverImpl@flags_internal@absl@@XZ ??$?DPEAVFlagStateInterface@flags_internal@absl@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagStateInterface@flags_internal@absl@@XZ ??$?D_J@absl@@YA?AVDuration@0@_JV10@@Z ??$?GPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@@__Cr@std@@YA_JAEBV?$move_iterator@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@01@0@Z @@ -293,7 +278,6 @@ EXPORTS ??$?GPEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@__Cr@std@@YA_JAEBV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?GPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@01@0@Z ??$?GPEBQEAVLogSink@absl@@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEBQEAVLogSink@absl@@@01@0@Z - ??$?K_J@absl@@YA?AVDuration@0@V10@_J@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z @@ -303,10 +287,6 @@ EXPORTS ??$?RAEAPEAVLogSink@absl@@@__identity@__Cr@std@@QEBAAEAPEAVLogSink@absl@@AEAPEAV34@@Z ??$?RAEAPEBDAEAHAEAY0LLI@DAEBQEBDPEAD@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEBAXAEAPEBDAEAHAEAY0LLI@DAEBQEBD$$QEAPEAD@Z ??$?RAEAPEBVCommandLineFlag@absl@@@__identity@__Cr@std@@QEBAAEAPEBVCommandLineFlag@absl@@AEAPEBV34@@Z - ??$?RAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$01V?$Span@$$CBD@absl@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$01V?$Span@$$CBD@absl@@@345@@Z - ??$?RAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@345@@Z ??$?RAEAW4LogSeverity@absl@@AEAPEBDAEAHPEAPEADPEAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEBA_NAEAW4LogSeverity@2@AEAPEBDAEAH$$QEAPEAPEAD$$QEAPEAH@Z ??$?RAEAY04$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY04$$CBD$$QEAPEAVCondVar@2@@Z ??$?RAEAY06$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY06$$CBD$$QEAPEAVCondVar@2@@Z @@ -335,12 +315,12 @@ EXPORTS ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_backward_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@12@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEAPEAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEBQEAVCommandLineFlag@3@@Z ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$V@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@67@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@3@@Z ??$?RVDuration@absl@@V01@@?$__less@XX@__Cr@std@@QEBA_NAEBVDuration@absl@@0@Z ??$?RVMixingHashState@hash_internal@absl@@@CombineRaw@hash_internal@absl@@QEBA?AVMixingHashState@12@V312@_K@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z @@ -375,6 +355,7 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z ??$ArgumentToConv@C@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@D@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@E@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ @@ -410,8 +391,10 @@ EXPORTS ??$AsciiStrCaseFoldImpl@$0A@$00@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AsciiStrCaseFoldImpl@$0A@$0A@@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AssertHashEqConsistent@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$AssertNonNull@U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@functional_internal@absl@@YAXAEBU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z ??$AssertOnFind@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$AssignElements@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAUPayload@status_internal@1@AEAV?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@01@_K@Z ??$AssignElements@V?$allocator@VSourceLocation@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAVSourceLocation@1@AEAV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@01@_K@Z @@ -462,14 +445,9 @@ EXPORTS ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX0_K@Z ??$DecomposePair@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$DecomposePair@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAUFindElement@301@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z2@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z@Z @@ -542,6 +520,8 @@ EXPORTS ??$FastTypeId@_J@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_K@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_N@absl@@YA?AVFastTypeIdType@0@XZ + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -577,10 +557,10 @@ EXPORTS ??$GetDataImpl@V?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@@span_internal@absl@@YAPEAPEAVLogSink@1@AEAV?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@D@Z ??$GetFlag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@absl@@YA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@0@@Z ??$GetTrivialDestructRef@$0BI@$07@DtorPolicy@container_internal@absl@@SAAEBU012@XZ - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$HardeningAssertGE@PEBUPayload@status_internal@absl@@PEBU123@@base_internal@absl@@YAXPEBUPayload@status_internal@1@0@Z ??$HardeningAssertGE@_K_K@base_internal@absl@@YAX_K0@Z ??$HardeningAssertGT@_K_K@base_internal@absl@@YAX_K0@Z @@ -622,7 +602,6 @@ EXPORTS ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVBufferRawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVFILERawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeGet@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@@FlagImplPeer@flags_internal@absl@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@12@@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z ??$InvokeParseFlag@H@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@M@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@N@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -739,12 +718,8 @@ EXPORTS ??$OffsetValue@U?$atomic@_K@__Cr@std@@@FlagImpl@flags_internal@absl@@AEBAPEAU?$atomic@_K@__Cr@std@@XZ ??$OffsetValue@UFlagMaskedPointerValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagMaskedPointerValue@12@XZ ??$OffsetValue@UFlagOneWordValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagOneWordValue@12@XZ - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBQEAVCommandLineFlag@1@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z + ??$PairConstFirst@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z + ??$PairConstFirst@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$ParseFlag@H@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@M@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@N@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z @@ -765,9 +740,6 @@ EXPORTS ??$ReadCallback@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Condition@absl@@AEBAXPEAP6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Z ??$Register@AEB_JAEA_KAEA_KAEA_KAEAG@?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@QEAAPEAUHashtablezInfo@container_internal@2@AEB_JAEA_K11AEAG@Z ??$RoundUp@$03@crc_internal@absl@@YAPEBEPEBE@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@0@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@0@Z@@Z ??$SNPrintF@DHHH@absl@@YAHPEAD_KAEBV?$FormatSpecTemplate@$0BPPPL@$0JPPPL@$0JPPPL@$0JPPPL@@str_format_internal@0@AEBDAEBH44@Z ??$Seconds@H$0A@@absl@@YA?AVDuration@0@H@Z ??$Seconds@J$0A@@absl@@YA?AVDuration@0@J@Z @@ -925,14 +897,20 @@ EXPORTS ??$__append_with_size@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_K@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z - ??$__as_variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@YAAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@AEAV201@@Z ??$__assign_with_size_random_access@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_J@Z ??$__assume_aligned@$07PEAVLogSink@absl@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@@Z ??$__assume_valid_range@AEAPEAPEAVLogSink@absl@@AEAPEAPEAV12@@__Cr@std@@YAXAEAPEAPEAVLogSink@absl@@0@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03$$V@__base@__visitation@__variant_detail@__Cr@std@@CA$$QEA_PAEBU?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@34@_K@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z@__base@__visitation@__variant_detail@__Cr@std@@CAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@ZAEBQ6A_K01@Z@Z ??$__call@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@?$__invoke_void_return_wrapper@X$00@__Cr@std@@SAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@7@@Z ??$__call_func@V<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@@?$__policy_func@$$A6AXAEAVCommandLineFlag@absl@@@Z@__function@__Cr@std@@CAXPEBT__policy_storage@123@AEAVCommandLineFlag@absl@@@Z + ??$__clear_padding_if_needed@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z$0A@@__Cr@std@@YAAEAP6AXAEBUHashtablezInfo@container_internal@absl@@@ZAEAP6AX0@Z@Z + ??$__clear_padding_if_needed@PEAUHashtablezInfo@container_internal@absl@@$0A@@__Cr@std@@YAAEAPEAUHashtablezInfo@container_internal@absl@@AEAPEAU234@@Z + ??$__clear_padding_if_needed@PEAVCordzHandle@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzHandle@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVCordzInfo@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzInfo@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVVLogSite@log_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVVLogSite@log_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@VMaskedPointer@flags_internal@absl@@$0A@@__Cr@std@@YAAEAVMaskedPointer@flags_internal@absl@@AEAV234@@Z + ??$__clear_padding_if_needed@W4OnDeadlockCycle@absl@@$0A@@__Cr@std@@YAAEAW4OnDeadlockCycle@absl@@AEAW423@@Z + ??$__clear_padding_if_needed@W4State@PerThreadSynch@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4State@PerThreadSynch@base_internal@absl@@AEAW42345@@Z + ??$__clear_padding_if_needed@W4WaitState@ThreadIdentity@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4WaitState@ThreadIdentity@base_internal@absl@@AEAW42345@@Z ??$__constexpr_memmove@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@__Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAVLogSink@absl@@PEAV12@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0W4__element_count@01@@Z @@ -960,8 +938,8 @@ EXPORTS ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$__construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$__construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$__construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1075,10 +1053,6 @@ EXPORTS ??$__destroy_at@UUnrecognizedFlag@absl@@@__Cr@std@@YAXPEAUUnrecognizedFlag@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@@__Cr@std@@YAXPEAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@YAXPEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@01@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$00@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$01@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$02@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$0A@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z ??$__distance@PEBUPayload@status_internal@absl@@$0A@@__Cr@std@@YA_JPEBUPayload@status_internal@absl@@0@Z ??$__distance@PEBUTransition@cctz@time_internal@absl@@$0A@@__Cr@std@@YA_JPEBUTransition@cctz@time_internal@absl@@0@Z ??$__distance@PEBVFormatArgImpl@str_format_internal@absl@@$0A@@__Cr@std@@YA_JPEBVFormatArgImpl@str_format_internal@absl@@0@Z @@ -1128,10 +1102,14 @@ EXPORTS ??$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0AEBQEAV23@AEAU__identity@01@@Z ??$__find_if@PEAPEAVLogSink@absl@@PEAPEAV12@V<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAV12@PEAPEAV12@0AEBQEAV12@AEAU__identity@45@@Z@AEAU645@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0$$QEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAV23@00AEBQEAV23@AEAU__identity@01@@Z@2@Z ??$__for_each_segment@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@23@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V123@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@@__Cr@std@@YAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@01@0V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@01@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@01@00V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@01@@Z@@Z - ??$__get_alt@$00AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$01AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$02AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$0A@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$01AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$01AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$02AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$02AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$0A@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$0A@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$00@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$00@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$01@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$01@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$0A@@34@@Z @@ -1157,7 +1135,6 @@ EXPORTS ??$__in_bounds@V?$__bucket_list_deallocator@V?$allocator@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@23@$0A@@__unique_ptr_array_bounds_stateless@__Cr@std@@QEBA_NPEAPEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@_K@Z ??$__insert_assign_n_unchecked@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAAXV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@_JPEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$__insert_with_size@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@V423@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1_J@Z - ??$__invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$__invoke@AEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAU__identity@__Cr@std@@AEAPEAVLogSink@absl@@@__Cr@std@@YAAEAPEAVLogSink@absl@@AEAU__identity@01@AEAPEAV23@@Z @@ -1166,10 +1143,6 @@ EXPORTS ??$__invoke@AEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV45@0AEBQEAV45@AEAU__identity@23@@Z@AEAPEAV45@@__Cr@std@@YA_NAEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAVLogSink@absl@@PEAPEAV34@0AEBQEAV34@AEAU__identity@01@@Z@AEAPEAV34@@Z ??$__invoke@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@__Cr@std@@YAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@6@@Z ??$__invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@501@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$Span@$$CBD@5@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@IHM@01@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@_K_JIH_N@01@@Z @@ -1238,7 +1211,6 @@ EXPORTS ??$__lower_bound_bisecting@U_ClassicAlgPolicy@__Cr@std@@PEBUTransition@cctz@time_internal@absl@@U4567@U__identity@23@UByUnixTime@4567@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@AEBU2345@_JAEAUByUnixTime@2345@AEAU__identity@01@@Z ??$__make_exception_guard@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@01@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@AEAAX_K@Z@@Z ??$__make_exception_guard@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@01@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@01@@Z - ??$__make_value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@CA?A_P$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@@Z ??$__memberwise_forward_assign@V?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@V?$tuple@PEAVCommandLineFlag@absl@@_N@23@PEAVCommandLineFlag@absl@@_N$$Z$0A@$00@__Cr@std@@YAXAEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@U?$__type_list@PEAVCommandLineFlag@absl@@_N@01@U?$__integer_sequence@_K$0A@$00@01@@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z @@ -1276,17 +1248,12 @@ EXPORTS ??$__static_fancy_pointer_cast@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@PEAV?$__tree_node_base@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@AEBQEAV?$__tree_node_base@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@@Z - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JN@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0@Z ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0U?$integral_constant@_N$0A@@01@@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z - ??$__throw_if_valueless@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__Cr@std@@YAXAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__to_address@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z ??$__to_address@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@YAPEAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@01@PEAPEAU201@@Z @@ -1357,9 +1324,6 @@ EXPORTS ??$__validate_iter_reference@AEAPEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEAVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@56@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@01234@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z - ??$__visit_value@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J_J$0A@@__Cr@std@@YAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@V?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@01@_J@Z @@ -1379,15 +1343,15 @@ EXPORTS ??$allocate_at_least@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PEAUUnrecognizedFlag@absl@@_K@12@AEAV?$allocator@UUnrecognizedFlag@absl@@@12@_K@Z ??$allocate_at_least@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PEAUViableSubstitution@strings_internal@absl@@_K@12@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@_K@Z ??$allocate_at_least@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@_K@12@AEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@_K@Z - ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$assign@PEBVSourceLocation@absl@@$0A@@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEAAXPEBVSourceLocation@1@0@Z ??$assign@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@$0A@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0@Z @@ -1398,9 +1362,15 @@ EXPORTS ??$bit_cast@U?$FlagValueAndInitBit@_N@flags_internal@absl@@_J@__Cr@std@@YA?AU?$FlagValueAndInitBit@_N@flags_internal@absl@@AEB_J@Z ??$bit_cast@VFastTypeIdType@absl@@PEAX@__Cr@std@@YA?AVFastTypeIdType@absl@@AEBQEAX@Z ??$c_begin@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_begin@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_begin@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_begin@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$c_copy@V?$Span@$$CBI@absl@@PEAI@absl@@YAPEAIAEBV?$Span@$$CBI@0@$$QEAPEAI@Z + ??$c_copy@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@Z + ??$c_copy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@Z ??$c_end@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_end@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_end@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_end@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$call_once@A6AXXZ$$V@absl@@YAXAEAVonce_flag@0@A6AXXZ@Z ??$call_once@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@absl@@YAXAEAVonce_flag@0@$$QEAP8FlagImpl@flags_internal@0@EAAXXZ$$QEAPEAV230@@Z @@ -1411,8 +1381,8 @@ EXPORTS ??$combine@V?$tuple@AEB_K@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEBV?$tuple@AEB_K@__Cr@std@@@Z ??$combine@_K$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEB_K@Z ??$combine_contiguous@D@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@PEBD_K@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV45678@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEBV45678@@Z ??$construct@PEAUCordRep@cord_internal@absl@@AEBQEAU123@$0A@@?$allocator_traits@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@12@PEAPEAUCordRep@cord_internal@absl@@AEBQEAU456@@Z @@ -1431,8 +1401,8 @@ EXPORTS ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@$0A@@?$allocator_traits@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$$QEAU4567@@Z ??$construct@UPayload@status_internal@absl@@AEBU123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@AEBU456@@Z ??$construct@UPayload@status_internal@absl@@U123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@$$QEAU456@@Z @@ -1448,12 +1418,12 @@ EXPORTS ??$construct@UUnrecognizedFlag@absl@@U12@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAU45@@Z ??$construct@UUnrecognizedFlag@absl@@W4Source@12@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$construct@UViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV456@AEA_K$0A@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@PEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEBV712@AEA_K@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@23@AEBV678@@Z@$0A@@?$allocator_traits@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV789@@Z@@Z ??$construct@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V123@$0A@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@12@$$QEAV412@@Z ??$construct@VFormatArgImpl@str_format_internal@absl@@AEBV123@$0A@@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@12@PEAVFormatArgImpl@str_format_internal@absl@@AEBV456@@Z @@ -1479,8 +1449,8 @@ EXPORTS ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1540,13 +1510,13 @@ EXPORTS ??$distance@V?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z ??$distance@V?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$element@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@@Z + ??$emplace@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$emplace@$$V@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransition@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransition@cctz@time_internal@absl@@@12@@Z ??$emplace@$$V@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@12@@Z ??$emplace@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@?$optional@VStream@status_internal@absl@@@__Cr@std@@QEAAAEAVStream@status_internal@absl@@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$emplace@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$emplace_back@$$V@?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAXAEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -1581,11 +1551,9 @@ EXPORTS ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$forward_as_tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@AEBQEAVCommandLineFlag@absl@@@Z - ??$forward_as_tuple@PEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAPEAPEAUCordRep@cord_internal@2@XZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEA_KXZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEB_KXZ @@ -1608,7 +1576,6 @@ EXPORTS ??$get@$00PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEA_NAEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$01@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEBUStringEq@12@XZ ??$get@$02@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGAAAEAV?$allocator@D@__Cr@std@@XZ - ??$get@$0A@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEBV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ @@ -1628,7 +1595,6 @@ EXPORTS ??$get@$0A@@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEB_KXZ ??$get@$0A@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@@Z ??$get@$0A@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@23@@__Cr@std@@YAAEAUFindInfo@container_internal@absl@@AEAV?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@_K$07$02@23@@01@@Z - ??$get@$0A@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YAAEBQEAVCommandLineFlag@absl@@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YA$$QEAPEAVCommandLineFlag@absl@@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$hash@H@MixingHashState@hash_internal@absl@@SA_KAEBH@Z @@ -1647,7 +1613,6 @@ EXPORTS ??$hash_with_seed@V?$tuple@AEB_K@__Cr@std@@$0A@@MixingHashState@hash_internal@absl@@SA_KAEBV?$tuple@AEB_K@__Cr@std@@_K@Z ??$insert@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$insert@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@__Cr@std@@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1@Z - ??$invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@AEAPEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@0@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@PEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@$$QEAPEAPEAV34@@Z @@ -1673,6 +1638,7 @@ EXPORTS ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@XZ ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@AEAV12@$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@AEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$make_unique@VFallbackCrcMemcpyEngine@crc_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@01@XZ + ??$make_unique@VFlagSaverImpl@flags_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@01@XZ ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@AEAPEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@AEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@PEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@_JAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEA_JAEA_N21@Z @@ -1763,6 +1729,7 @@ EXPORTS ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?A_PPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer_impl@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@CA?AU?$integral_constant@_N$00@__Cr@std@@PEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@45@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1URank2@012@@Z + ??$ts_unchecked_read@PEAUHashtablezInfo@container_internal@absl@@@base_internal@absl@@YAAEAPEAUHashtablezInfo@container_internal@1@AEAPEAU231@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByCivilTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByCivilTime@2345@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z ??$value_or@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$optional_ref@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -1788,10 +1755,6 @@ EXPORTS ??0?$FormatSpecTemplate@$0JPPPL@@str_format_internal@absl@@QEAA@PEBD@Z ??0?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@_K@Z ??0?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@_K@Z - ??0?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAA@V?$HashtableCapacityImpl@$00@12@Uno_seed_empty_tag_t@12@@Z ??0?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAA@AEBV01@@Z @@ -2133,6 +2096,10 @@ EXPORTS ??0GroupPortableImpl@container_internal@absl@@QEAA@PEBW4ctrl_t@12@@Z ??0GrowthInfoLowerBound@container_internal@absl@@QEAA@E@Z ??0HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEAA@PEBE@Z + ??0HashtableCapacity@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@_K@Z + ??0HashtableInlineData@container_internal@absl@@QEAA@VHashtableCapacity@12@Uno_seed_empty_tag_t@12@@Z ??0HashtablezInfo@container_internal@absl@@QEAA@XZ ??0HashtablezInfoHandle@container_internal@absl@@QEAA@$$T@Z ??0Hex@absl@@AEAA@W4PadSpec@1@_K@Z @@ -2181,11 +2148,12 @@ EXPORTS ??0PrefixCrc@CrcCordState@crc_internal@absl@@QEAA@_KVcrc32c_t@3@@Z ??0ProtoField@log_internal@absl@@QEAA@XZ ??0Randen@random_internal@absl@@QEAA@XZ + ??0RawHashSetLayout@container_internal@absl@@AEAA@Uuninitialized_tag_t@12@@Z ??0RawHashSetLayout@container_internal@absl@@QEAA@_K00_N0@Z ??0ReaderMutexLock@absl@@QEAA@AEAVMutex@1@@Z + ??0ReentranceGuard@container_internal@absl@@QEAA@AEAVCommonFields@12@@Z ??0RefcountAndFlags@cord_internal@absl@@QEAA@XZ ??0RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??0ReleasableMutexLock@absl@@QEAA@AEAVMutex@1@@Z ??0Rep@CordBuffer@absl@@QEAA@PEAUCordRepFlat@cord_internal@2@@Z ??0Rep@CordBuffer@absl@@QEAA@XZ ??0Rep@CrcCordState@crc_internal@absl@@QEAA@XZ @@ -2384,6 +2352,7 @@ EXPORTS ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ + ??1?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ @@ -2445,8 +2414,8 @@ EXPORTS ??1Payload@status_internal@absl@@QEAA@XZ ??1PosixTimeZone@cctz@time_internal@absl@@QEAA@XZ ??1ReaderMutexLock@absl@@QEAA@XZ + ??1ReentranceGuard@container_internal@absl@@QEAA@XZ ??1RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??1ReleasableMutexLock@absl@@QEAA@XZ ??1Rep@CrcCordState@crc_internal@absl@@QEAA@XZ ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ @@ -2584,7 +2553,6 @@ EXPORTS ??8strings_internal@absl@@YA_NAEBV?$SplitIterator@V?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z ??9CharIterator@Cord@absl@@QEBA_NAEBV012@@Z ??9ChunkIterator@Cord@absl@@QEBA_NAEBV012@@Z - ??9GraphId@synchronization_internal@absl@@QEBA_NAEBU012@@Z ??9__Cr@std@@YA_NAEBU__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z @@ -2594,7 +2562,6 @@ EXPORTS ??9absl@@YA_NVFastTypeIdType@0@0@Z ??9absl@@YA_NVint128@0@0@Z ??9absl@@YA_NVuint128@0@0@Z - ??9container_internal@absl@@YA_NAEBV?$BitMask@_K$07$02$00@01@0@Z ??9container_internal@absl@@YA_NAEBV?$BitMask@_K$07$02$0A@@01@0@Z ??9container_internal@absl@@YA_NAEBViterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@0@Z ??9strings_internal@absl@@YA_NAEBV?$SplitIterator@V?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z @@ -2607,7 +2574,6 @@ EXPORTS ??A?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEBAAEBVFormatArgImpl@str_format_internal@1@_K@Z ??A?$Span@D@absl@@QEBAAEAD_K@Z ??A?$Span@I@absl@@QEBAAEAI_K@Z - ??A?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@__Cr@std@@QEBAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@12@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@612@@Z_K@Z ??A?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEBAAEAPEAVCommandLineFlag@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@__Cr@std@@QEBAAEAPEAVCordzHandle@cord_internal@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVLogSink@absl@@@__Cr@std@@QEBAAEAPEAVLogSink@absl@@_J@Z @@ -2639,6 +2605,7 @@ EXPORTS ??B?$function@$$A6A_NAEBVCommandLineFlag@absl@@@Z@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ??B?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ @@ -2678,6 +2645,7 @@ EXPORTS ??C?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAULogMessageData@LogMessage@log_internal@absl@@XZ ??C?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAURep@StatusBuilder@absl@@XZ ??C?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ + ??C?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVFlagSaverImpl@flags_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneIf@cctz@time_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneInfo@cctz@time_internal@absl@@XZ ??CChunkIterator@Cord@absl@@QEBAPEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ @@ -2719,6 +2687,7 @@ EXPORTS ??D?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAVSourceLocation@absl@@@__Cr@std@@QEBA$$QEAVSourceLocation@absl@@XZ + ??DCharIterator@Cord@absl@@QEBAAEBDXZ ??DChunkIterator@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ??D__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU__deque_block_range@123@XZ ??Dabsl@@YA?AVint128@0@V10@0@Z @@ -2804,6 +2773,7 @@ EXPORTS ??Pabsl@@YA_NVint128@0@0@Z ??Pabsl@@YA_NVuint128@0@0@Z ??R<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@23@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@QEBA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@2@Z + ??R<lambda_1>@?0???$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@QEBA?A?<auto>@@PEAD_K@Z @@ -2815,8 +2785,6 @@ EXPORTS ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2830,11 +2798,9 @@ EXPORTS ??R<lambda_1>@?0???$emplace_back@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@$$QEAV423@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@W4Source@UnrecognizedFlag@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??Append@FormatSinkImpl@str_format_internal@absl@@QEAAX_KD@Z@QEBA?A?<auto>@@0@Z - ??R<lambda_1>@?0??AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@23@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHAEBV23@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV456@@Z ??R<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@QEBA?A?<auto>@@AEAVCommandLineFlag@4@@Z - ??R<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@0@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2850,7 +2816,6 @@ EXPORTS ??R?$ConvertToContainer@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$FunctionRef@$$A6AXPEAUCordRep@cord_internal@absl@@_K1@Z@absl@@QEBAXPEAUCordRep@cord_internal@1@_K1@Z - ??R?$FunctionRef@$$A6AXPEAXPEBX@Z@absl@@QEBAXPEAXPEBX@Z ??R?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@absl@@QEBAXPEBW4ctrl_t@container_internal@1@PEAX@Z ??R?$FunctionRef@$$A6AXV?$Span@I@absl@@@Z@absl@@QEBAXV?$Span@I@1@@Z ??R?$FunctionRef@$$A6AXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z@absl@@QEBAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -2880,6 +2845,7 @@ EXPORTS ??R?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@QEBAXPEAURep@StatusBuilder@absl@@@Z ??R?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@QEBAXPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??R?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@QEBAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??R?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ??R?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagState@flags_internal@absl@@@Z ??R?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagStateInterface@flags_internal@absl@@@Z ??R?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@QEBAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -2946,6 +2912,7 @@ EXPORTS ??_5uint128@absl@@QEAAAEAV01@V01@@Z ??_6uint128@absl@@QEAAAEAV01@V01@@Z ??_DOStringStream@strings_internal@absl@@QEAAXXZ + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbsDuration@absl@@YA?AVDuration@1@V21@@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3034,6 +3001,7 @@ EXPORTS ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z ?AnnotateConstruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z ?AnnotateDestruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@Cord@absl@@QEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3061,24 +3029,22 @@ EXPORTS ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AEAAX_K@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z - ?AreItersFromSameContainer@container_internal@absl@@YA_NAEBQEBW4ctrl_t@12@0PEBX1@Z ?AsValueType@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@CAPEADPEAD@Z ?AsciiStrToLower@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@CordzInfo@cord_internal@absl@@QEAAXXZ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertHeld@SpinLock@base_internal@absl@@QEBAXXZ ?AssertInSooMode@CommonFields@container_internal@absl@@AEBAXXZ - ?AssertIsFull@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBEPEBD@Z - ?AssertIsValidForComparison@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBE@Z + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEBAXXZ ?AssertNotDebugCapacity@CommonFields@container_internal@absl@@QEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ - ?AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@_N@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEBV123@PEBV123@_N@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QEBAXVFastTypeIdType@3@P6APEBVtype_info@@XZ@Z @@ -3117,6 +3083,7 @@ EXPORTS ?CalculateBase64EscapedLenInternal@strings_internal@absl@@YA_K_K_N@Z ?CallVoidPtrFunction@Condition@absl@@CA_NPEBV12@@Z ?Capacity@CordRepFlat@cord_internal@absl@@QEBA_KXZ + ?CapacityBits@HashtableInlineData@container_internal@absl@@CA_KVHashtableCapacity@23@@Z ?CapacityToGrowth@container_internal@absl@@YA_K_K@Z ?CappedDamerauLevenshteinDistance@strings_internal@absl@@YAEV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0E@Z ?CatPieces@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$initializer_list@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@5@@Z @@ -3190,7 +3157,7 @@ EXPORTS ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?ConvertSpecialToEmptyAndFullToDeleted@GroupAArch64Impl@container_internal@absl@@QEBAXPEAW4ctrl_t@23@@Z ?Copy@CordRepBtree@cord_internal@absl@@AEBAPEAV123@XZ - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?Copy@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z ?CopyBeginTo@CordRepBtree@cord_internal@absl@@AEBAPEAV123@_K0@Z ?CopyConstruct@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z @@ -3211,8 +3178,9 @@ EXPORTS ?CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PEIAXPEIBX_KV43@_N@Z ?Create@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAUCordRep@23@@Z ?Create@CordRepFlat@cord_internal@absl@@SAPEAU123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z - ?CreateDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ - ?CreateReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ + ?CreateDestroyed@HashtableCapacity@container_internal@absl@@SA?AV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z + ?CreateReentrance@HashtableCapacity@container_internal@absl@@SA?AV123@XZ ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -3236,6 +3204,8 @@ EXPORTS ?DeallocateIfAllocated@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -3285,6 +3255,7 @@ EXPORTS ?Digits10@?$BigUnsigned@$0FE@@strings_internal@absl@@SAHXZ ?DisableFlagfileAndEnvParsing@absl@@YAXXZ ?DisableRescheduling@SchedulingGuard@base_internal@absl@@SA_NXZ + ?Distance@Cord@absl@@SA_JAEBVCharIterator@12@0@Z ?DoIgnoreLeak@absl@@YAXPEBX@Z ?DoLoad@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBVCord@absl@@@Z@base_internal@absl@@AEBAP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBVCord@3@@ZXZ ?DoLoad@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@AEBAP6AXPEBDH000@ZXZ @@ -3373,6 +3344,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32c@absl@@YA?AVcrc32c_t@1@V21@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3413,7 +3385,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -3502,7 +3473,7 @@ EXPORTS ?FromHost64@little_endian@absl@@YA_K_K@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0DM@$00@__Cr@std@@@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0OBA@$00@__Cr@std@@@Z - ?FromRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@_K@Z + ?FromRawData@HashtableCapacity@container_internal@absl@@SA?AV123@_K@Z ?FromTM@absl@@YA?AVTime@1@AEBUtm@@VTimeZone@1@@Z ?FromUDate@absl@@YA?AVTime@1@N@Z ?FromUniversal@absl@@YA?AVTime@1@_J@Z @@ -3578,6 +3549,7 @@ EXPORTS ?GetGrowthLeft@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ ?GetGrowthLeftLowerBound@CommonFields@container_internal@absl@@QEBA_KXZ ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -3769,7 +3741,7 @@ EXPORTS ?IsDataLoss@absl@@YA_NAEBVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NAEBVStatus@1@@Z ?IsDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z - ?IsDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsDestroyed@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsEmpty@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsEmptyOrDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsExternal@CordRep@cord_internal@absl@@QEBA_NXZ @@ -3797,7 +3769,7 @@ EXPORTS ?IsPermissionDenied@absl@@YA_NAEBVStatus@1@@Z ?IsPow2@CordBuffer@absl@@CA_N_K@Z ?IsReachable@GraphCycles@synchronization_internal@absl@@QEBA_NUGraphId@23@0@Z - ?IsReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsReentrance@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsResourceExhausted@absl@@YA_NAEBVStatus@1@@Z ?IsRetired@CommandLineFlag@absl@@UEBA_NXZ ?IsSMTEnabled@base_internal@absl@@YA_NXZ @@ -3813,8 +3785,8 @@ EXPORTS ?IsUnimplemented@absl@@YA_NAEBVStatus@1@@Z ?IsUnknown@absl@@YA_NAEBVStatus@1@@Z ?IsUnprotectedReadCandidate@MaskedPointer@flags_internal@absl@@QEBA_NXZ - ?IsValid@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ ?IsValid@CordRepBtree@cord_internal@absl@@SA_NPEBV123@_N@Z + ?IsValid@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsValidCapacity@container_internal@absl@@YA_N_K@Z ?IterateOverFullSlots@container_internal@absl@@YAXAEBVCommonFields@12@_KV?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@2@@Z ?JoinMessageToStatus@StatusPrivateAccessorForStatusBuilder@status_internal@absl@@SA?AVStatus@3@V43@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@W4MessageJoinStyle@3@@Z @@ -3970,6 +3942,7 @@ EXPORTS ?NumClonedBytes@container_internal@absl@@YA_KXZ ?NumContextsPerCPU@base_internal@absl@@YAHXZ ?NumControlBytes@container_internal@absl@@YA_K_K@Z + ?NumControlBytesForLargeTable@container_internal@absl@@YA_K_K@Z ?NumGenerationBytes@container_internal@absl@@YA_KXZ ?NumLeakedFlagValues@flags_internal@absl@@YA_KXZ ?ODRCheck@CordzInfo@cord_internal@absl@@AEBAXXZ @@ -4022,9 +3995,9 @@ EXPORTS ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrecombineLengthMix@hash_internal@absl@@YA_K_K0@Z ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -4354,6 +4327,7 @@ EXPORTS ?TakeRep@Cord@absl@@AEHAAPEAUCordRep@cord_internal@2@XZ ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -4417,9 +4391,8 @@ EXPORTS ?ToInt64Nanoseconds@absl@@YA_JVDuration@1@@Z ?ToInt64Seconds@absl@@YA_JVDuration@1@@Z ?ToOpResult@CordRepBtree@cord_internal@absl@@AEAA?AUOpResult@123@_N@Z - ?ToPublicSeed@?$HashtableInlineDataImpl@$00@container_internal@absl@@CA_K_K@Z - ?ToRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBAEXZ ?ToRawData@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ + ?ToRawData@HashtableCapacity@container_internal@absl@@QEBAEXZ ?ToSinkAlso@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToSinkOnly@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToString@?$BigUnsigned@$03@strings_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -4702,7 +4675,6 @@ EXPORTS ?__annotate_shrink_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_K0@Z ?__annotate_whole_block@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z ?__annotate_whole_block@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z - ?__as_base@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@IEGAA@XZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_size_layout@V?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -4809,6 +4781,17 @@ EXPORTS ?__destruct_at_end@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransition@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransitionType@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUViableSubstitution@strings_internal@absl@@@Z + ?__empty@?$__vector_layout@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end_node@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAPEAV?$__tree_end_node@PEAV?$__tree_node_base@PEAX@__Cr@std@@@23@XZ @@ -5178,7 +5161,6 @@ EXPORTS ?base@?$move_iterator@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@QEGBAAEBQEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ ?base@?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@QEGBAAEBQEAUTransition@cctz@time_internal@absl@@XZ ?base@?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEGBAAEBQEAUTransitionType@cctz@time_internal@absl@@XZ - ?begin@?$BitMask@_K$07$02$00@container_internal@absl@@QEBA?AV123@XZ ?begin@?$BitMask@_K$07$02$0A@@container_internal@absl@@QEBA?AV123@XZ ?begin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAAPEAUPayload@status_internal@2@XZ ?begin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ @@ -5232,8 +5214,8 @@ EXPORTS ?begin@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?begin@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?begin@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?blocked_element_count@CommonFields@container_internal@absl@@QEBA_KXZ + ?blocked_element_count@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?btree@CordRep@cord_internal@absl@@QEAAPEAVCordRepBtree@23@XZ ?btree@CordRep@cord_internal@absl@@QEBAPEBVCordRepBtree@23@XZ ?btree@CordRepBtreeNavigator@cord_internal@absl@@QEBAPEAVCordRepBtree@23@XZ @@ -5241,8 +5223,6 @@ EXPORTS ?bucket_count@?$__hash_table@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEBA_KXZ ?bucket_count@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?bytes_value@ProtoField@log_internal@absl@@QEBA?AV?$Span@$$CBD@3@XZ - ?capacity@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_KXZ - ?capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_size_layout@V?$__split_buffer@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@V__split_buffer_size_layout@45@@__Cr@std@@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -5271,7 +5251,9 @@ EXPORTS ?capacity@CommonFields@container_internal@absl@@QEBA_KXZ ?capacity@CordBuffer@absl@@QEBA_KXZ ?capacity@CordRepBtree@cord_internal@absl@@QEBA_KXZ - ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?capacity@HashtableCapacity@container_internal@absl@@QEBA_KXZ + ?capacity@HashtableInlineData@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ + ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?cbegin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ ?cbegin@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA?AV?$__wrap_iter@PEBQEAVLogSink@absl@@@23@XZ ?cend@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ @@ -5434,8 +5416,8 @@ EXPORTS ?deallocate@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@23@PEAVFormatArgImpl@str_format_internal@absl@@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VSourceLocation@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VSourceLocation@absl@@@23@PEAVSourceLocation@absl@@_K@Z - ?decrement_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?decrement_size@CommonFields@container_internal@absl@@QEAAXXZ + ?decrement_size@HashtableInlineData@container_internal@absl@@QEAAXXZ ?delimiter@?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByChar@3@XZ @@ -5450,7 +5432,6 @@ EXPORTS ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ ?element@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z ?emplace@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@CAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z - ?empty@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?empty@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEBA_NXZ @@ -5475,9 +5456,9 @@ EXPORTS ?empty@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?empty@CommonFields@container_internal@absl@@QEBA_NXZ ?empty@Cord@absl@@QEBA_NXZ + ?empty@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?encoded_message@LogEntry@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?encoded_remaining@LogMessageData@LogMessage@log_internal@absl@@QEAAAEAV?$Span@D@4@XZ - ?end@?$BitMask@_K$07$02$00@container_internal@absl@@QEBA?AV123@XZ ?end@?$BitMask@_K$07$02$0A@@container_internal@absl@@QEBA?AV123@XZ ?end@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ ?end@?$Span@$$CBI@absl@@QEBAPEBIXZ @@ -5529,7 +5510,6 @@ EXPORTS ?end@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?end@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?end@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?eq_ref@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBAAEBUStringEq@23@XZ ?erase@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAAPEAUPayload@status_internal@2@PEBU342@@Z ?erase@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAPEAVLogSink@absl@@@23@V?$__wrap_iter@PEBQEAVLogSink@absl@@@23@@Z @@ -5553,8 +5533,8 @@ EXPORTS ?gbswap_16@absl@@YAGG@Z ?gbswap_32@absl@@YAII@Z ?gbswap_64@absl@@YA_K_K@Z - ?generate_new_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?generate_new_seed@CommonFields@container_internal@absl@@QEAAX_N@Z + ?generate_new_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ ?generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation@HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation_offset@RawHashSetLayout@container_internal@absl@@QEBA_KXZ @@ -5606,10 +5586,8 @@ EXPORTS ?get@?$__temp_value@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransition@cctz@time_internal@absl@@XZ ?get@?$__temp_value@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransitionType@cctz@time_internal@absl@@XZ ?get@?$__tuple_leaf@$00AEAV?$NonIterableBitMask@_K$07$02@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAV?$NonIterableBitMask@_K$07$02@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAUFindInfo@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAUFindInfo@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEBQEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@PEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?get@?$unique_ptr@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$__allocator_destructor@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ @@ -5649,10 +5627,10 @@ EXPORTS ?get_soo_data@HeapOrSoo@container_internal@absl@@QEBAPEBXXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z ?get_yearday@detail@cctz@time_internal@absl@@YAHAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z - ?growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ + ?growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ ?has_alt_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ - ?has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?has_infoz@CommonFields@container_internal@absl@@QEBA_NXZ + ?has_infoz@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?has_left_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_show_pos_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ @@ -5672,22 +5650,24 @@ EXPORTS ?hour@?$civil_time@Uhour_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?increment_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?increment_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?increment_size@CommonFields@container_internal@absl@@QEAAXXZ ?increment_size@CommonFields@container_internal@absl@@QEAAX_K@Z + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?index@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_KXZ ?index@?$probe_seq@$07@container_internal@absl@@QEBA_KXZ + ?index@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_KXZ ?index@CordRepBtree@cord_internal@absl@@QEBA_KW4EdgeType@123@@Z ?infoz@CommonFields@container_internal@absl@@QEAA?AVHashtablezInfoHandle@23@XZ + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ - ?init_blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z ?init_blocked_element_count@CommonFields@container_internal@absl@@QEAAX_K@Z + ?init_blocked_element_count@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?inline_size@InlineData@cord_internal@absl@@QEBA_KXZ ?inline_size@InlineRep@Cord@absl@@AEBA_KXZ ?inline_size@Rep@InlineData@cord_internal@absl@@QEBA_KXZ - ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z + ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z ?insert@?$unordered_set@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEAA?AU?$pair@V?$__hash_const_iterator@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBQEBUCordRep@cord_internal@absl@@@Z ?int32_value@ProtoField@log_internal@absl@@QEBAHXZ ?int64_value@ProtoField@log_internal@absl@@QEBA_JXZ @@ -5702,13 +5682,13 @@ EXPORTS ?is_length@ConvTag@str_format_internal@absl@@QEBA_NXZ ?is_profiled@InlineData@cord_internal@absl@@QEBA_NXZ ?is_relative_timeout@KernelTimeout@synchronization_internal@absl@@QEBA_NXZ - ?is_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ + ?is_sampled_seed@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_short@Rep@CordBuffer@absl@@QEBA_NXZ ?is_single_group@container_internal@absl@@YA_N_K@Z - ?is_small@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ - ?is_small@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?is_small@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_small@CommonFields@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableCapacity@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QEBA_NXZ ?is_soo@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_tree@InlineData@cord_internal@absl@@QEBA_NXZ @@ -5767,8 +5747,8 @@ EXPORTS ?max_size@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_KXZ ?max_size@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?maybe_increment_generation_on_insert@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXXZ - ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AV?$HashtableCapacityImpl@$00@23@XZ - ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AVHashtableCapacity@23@XZ + ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?memcasecmp@strings_internal@absl@@YAHPEBD0_K@Z ?message@Status@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?message@StatusRep@status_internal@absl@@QEBAAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -5800,10 +5780,10 @@ EXPORTS ?ok@Status@absl@@QEBA_NXZ ?ok@Utf8ForCodePoint@debugging_internal@absl@@QEBA_NXZ ?overflow@Streambuf@OStringStream@strings_internal@absl@@MEAAHH@Z - ?overwrite_control_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXW4ctrl_t@23@@Z - ?overwrite_empty_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_deleted@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_empty_in_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?overwrite_control_as_full@HashtableInlineData@container_internal@absl@@QEAAXW4ctrl_t@23@@Z + ?overwrite_empty_as_full@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_deleted@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_empty_in_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXXZ ?parse@detail@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0AEBVtime_zone@234@PEAV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@PEAV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@chrono@67@PEAV567@@Z ?parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBAPEBVParsedFormatBase@23@XZ ?pointer_to@?$pointer_traits@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@23@AEAU423@@Z @@ -5846,6 +5826,7 @@ EXPORTS ?push_back@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUTransition@cctz@time_internal@absl@@@Z ?push_back@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUUnrecognizedFlag@absl@@@Z ?raw_code@Status@absl@@QEBAHXZ + ?read_byte@HashtableInlineData@container_internal@absl@@AEBAE_K@Z ?reduce_size@InlineRep@Cord@absl@@QEAAX_K@Z ?release@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?release@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEAAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ @@ -5889,6 +5870,7 @@ EXPORTS ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagState@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagStateInterface@flags_internal@absl@@@Z ?reset@?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -5914,17 +5896,19 @@ EXPORTS ?scale_add@impl@detail@cctz@time_internal@absl@@YA_J_J00@Z ?second@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?second@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@CommonFields@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ + ?seed@HashtableInlineData@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@PerTableSeed@container_internal@absl@@QEBA_KXZ ?set@?$MaybeInitializedPtr@W4ctrl_t@container_internal@absl@@@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_arg@BoundConversion@str_format_internal@absl@@QEAAXPEBVFormatArgImpl@23@@Z ?set_begin@CordRepBtree@cord_internal@absl@@AEAAX_K@Z - ?set_blocked_element_count_to_zero@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?set_blocked_element_count_to_zero@CommonFields@container_internal@absl@@QEAAXXZ - ?set_capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z - ?set_capacity@CommonFields@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z + ?set_blocked_element_count_to_zero@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_capacity@CommonFields@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z ?set_capacity@CommonFields@container_internal@absl@@QEAAX_K@Z + ?set_capacity@CommonFields@container_internal@absl@@QECAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QECAXVHashtableCapacity@23@@Z ?set_control@CommonFields@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_conversion_char@FormatConversionSpecImpl@str_format_internal@absl@@QEAAXW4FormatConversionChar@3@@Z ?set_cordz_info@InlineData@cord_internal@absl@@QEAAXPEAVCordzInfo@23@@Z @@ -5938,9 +5922,9 @@ EXPORTS ?set_full_soo@CommonFields@container_internal@absl@@QEAAXXZ ?set_generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXE@Z ?set_generation_ptr@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXPEAE@Z - ?set_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z - ?set_has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?set_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z ?set_has_infoz@CommonFields@container_internal@absl@@QEAAXXZ + ?set_has_infoz@HashtableInlineData@container_internal@absl@@QEAAXXZ ?set_infoz@CommonFields@container_internal@absl@@QEAAXVHashtablezInfoHandle@23@@Z ?set_inline_data@InlineData@cord_internal@absl@@QEAAXPEBD_K@Z ?set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z @@ -5948,10 +5932,10 @@ EXPORTS ?set_inline_size@Rep@InlineData@cord_internal@absl@@QEAAX_K@Z ?set_reservation_size@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z ?set_reserved_growth@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z - ?set_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?set_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@AEAAXE@Z + ?set_sampled_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_seed@HashtableInlineData@container_internal@absl@@AEAAXE@Z ?set_short_length@Rep@CordBuffer@absl@@QEAAX_K@Z - ?set_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?set_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?set_size_to_zero@CommonFields@container_internal@absl@@QEAAXXZ ?set_tag@Rep@InlineData@cord_internal@absl@@QEAAXC@Z ?set_tree@InlineData@cord_internal@absl@@QEAAXPEAUCordRep@23@@Z @@ -5964,11 +5948,11 @@ EXPORTS ?shrink_to_fit@?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?single_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@123@XZ + ?single_non_soo_slot@CommonFields@container_internal@absl@@QEBAPEAXXZ ?single_slot@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@XZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?size@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ - ?size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ @@ -6013,6 +5997,7 @@ EXPORTS ?size@CommonFields@container_internal@absl@@QEBA_KXZ ?size@Cord@absl@@QEBA_KXZ ?size@CordRepBtree@cord_internal@absl@@QEBA_KXZ + ?size@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?size@InlineRep@Cord@absl@@QEBA_KXZ ?size@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ ?skip_empty_or_deleted@iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXXZ @@ -6062,7 +6047,7 @@ EXPORTS ?timestamp@LogEntry@absl@@QEBA?AVTime@2@XZ ?total_written@BufferRawSink@str_format_internal@absl@@QEBA_KXZ ?transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@0@Z - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?tree@InlineRep@Cord@absl@@QEBAPEAUCordRep@cord_internal@3@XZ ?tree@Rep@InlineData@cord_internal@absl@@QEBAPEAUCordRep@34@XZ ?try_lock@Mutex@absl@@QEAA_NXZ @@ -6081,8 +6066,6 @@ EXPORTS ?value@InputValue@UnboundConversion@str_format_internal@absl@@QEBAHXZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ - ?valueless_by_exception@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_NXZ - ?valueless_by_exception@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_NXZ ?verbosity@LogEntry@absl@@QEBAHXZ ?version@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?what@BadStatusOrAccess@absl@@UEBAPEBDXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_arm64_rel.def b/deps/v8/third_party/abseil-cpp/symbols_arm64_rel.def index 97e5b964ea76..fc40f3fbfadc 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_arm64_rel.def +++ b/deps/v8/third_party/abseil-cpp/symbols_arm64_rel.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QEAA@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$?6C@LogMessage@log_internal@absl@@QEAAAEAV012@AEBC@Z @@ -22,8 +21,6 @@ EXPORTS ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CC@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CG@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CG@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CH@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CH@$$CBD@Z @@ -41,6 +38,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QEAP8FlagImpl@flags_internal@1@EAAXXZ$$QEAPEAV671@@Z @@ -105,6 +106,8 @@ EXPORTS ??$EmplaceBackSlow@AEBQEAVLogSink@absl@@@?$Storage@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAPEAVLogSink@2@AEBQEAV32@@Z ??$EmplaceBackSlow@AEBVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAVSourceLocation@2@AEBV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -114,11 +117,10 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHAEBVCord@0@0_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$MakeCheckOpString@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@DD@log_internal@absl@@YAPEBDDDPEBD@Z @@ -223,8 +225,8 @@ EXPORTS ??$emplace_front@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$emplace_front@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QEAAX$$QEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@XZ @@ -304,7 +306,6 @@ EXPORTS ??0uint128@absl@@QEAA@O@Z ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1CRC@crc_internal@absl@@UEAA@XZ ??1Clock@absl@@UEAA@XZ ??1Cord@absl@@QEAA@XZ @@ -324,6 +325,7 @@ EXPORTS ??1Mutex@absl@@QEAA@XZ ??1Notification@absl@@QEAA@XZ ??1OstreamView@LogMessage@log_internal@absl@@UEAA@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ ??1ScopedMinLogLevel@log_internal@absl@@QEAA@XZ ??1ScopedStderrThreshold@absl@@QEAA@XZ @@ -373,7 +375,6 @@ EXPORTS ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ??BStatusBuilder@absl@@QEGBA?AVStatus@1@XZ - ??BStatusBuilder@absl@@QEHAA?AVStatus@1@XZ ??Bint128@absl@@QEBANXZ ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??Eiterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAAAEAV0123@XZ @@ -412,6 +413,7 @@ EXPORTS ??_0Duration@absl@@QEAAAEAV01@N@Z ??_0Duration@absl@@QEAAAEAV01@_J@Z ??_1Duration@absl@@QEAAAEAV01@V01@@Z + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAEAVStatusBuilder@1@W4StatusCode@1@@Z @@ -466,6 +468,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPEAX_K@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z @@ -490,7 +493,9 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -566,7 +571,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NNAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?CopyCordToSpan@absl@@YA_KAEBVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXAEBVCord@1@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AEAA?AUCopyResult@123@_K_N@Z @@ -574,6 +579,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@AEBAXPEAD@Z ?Crash@Helper@internal_statusor@absl@@SAXAEBVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPEAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -581,6 +587,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPEAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@AEBAAEAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -663,6 +671,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@_K@Z @@ -702,7 +711,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -798,6 +806,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPEAUCordRep@cord_internal@2@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -1026,9 +1035,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -1226,6 +1235,7 @@ EXPORTS ?Symbolize@absl@@YA_NPEBXPEADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1394,13 +1404,13 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@AEBV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV567@AEBV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@AEBV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@AEBVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEAMW4chars_format@1@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEANW4chars_format@1@@Z ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEAVtime_zone@123@@Z @@ -1423,6 +1433,7 @@ EXPORTS ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?resize@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?resize@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?safe_strto128_base@numbers_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVint128@2@H@Z @@ -1445,7 +1456,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?status@BadStatusOrAccess@absl@@QEBAAEBVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QEAAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?try_lock@Mutex@absl@@QEAA_NXZ ?try_lock_shared@Mutex@absl@@QEAA_NXZ ?unlock@Mutex@absl@@QEAAXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_arm64_rel_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_arm64_rel_cxx23.def index e7f19e230c53..0caf4f54d55b 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_arm64_rel_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_arm64_rel_cxx23.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QEAA@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$?6C@LogMessage@log_internal@absl@@QEAAAEAV012@AEBC@Z @@ -22,8 +21,6 @@ EXPORTS ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CC@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CG@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CG@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CH@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CH@$$CBD@Z @@ -41,6 +38,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QEAP8FlagImpl@flags_internal@1@EAAXXZ$$QEAPEAV671@@Z @@ -105,6 +106,8 @@ EXPORTS ??$EmplaceBackSlow@AEBQEAVLogSink@absl@@@?$Storage@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAPEAVLogSink@2@AEBQEAV32@@Z ??$EmplaceBackSlow@AEBVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAVSourceLocation@2@AEBV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -114,11 +117,10 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHAEBVCord@0@0_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$MakeCheckOpString@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@DD@log_internal@absl@@YAPEBDDDPEBD@Z @@ -222,8 +224,8 @@ EXPORTS ??$emplace_front@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$emplace_front@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QEAAX$$QEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$resize_and_overwrite@V<lambda_1>@?0???$JoinAlgorithm@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@56@0V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@UNoFormatter@23@@Z@@?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@QEAAX_KV<lambda_1>@?0???$JoinAlgorithm@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV012@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@1V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@UNoFormatter@45@@Z@@Z ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -304,7 +306,6 @@ EXPORTS ??0uint128@absl@@QEAA@O@Z ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1CRC@crc_internal@absl@@UEAA@XZ ??1Clock@absl@@UEAA@XZ ??1Cord@absl@@QEAA@XZ @@ -324,6 +325,7 @@ EXPORTS ??1Mutex@absl@@QEAA@XZ ??1Notification@absl@@QEAA@XZ ??1OstreamView@LogMessage@log_internal@absl@@UEAA@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ ??1ScopedMinLogLevel@log_internal@absl@@QEAA@XZ ??1ScopedStderrThreshold@absl@@QEAA@XZ @@ -373,7 +375,6 @@ EXPORTS ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ??BStatusBuilder@absl@@QEGBA?AVStatus@1@XZ - ??BStatusBuilder@absl@@QEHAA?AVStatus@1@XZ ??Bint128@absl@@QEBANXZ ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??Eiterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAAAEAV0123@XZ @@ -412,6 +413,7 @@ EXPORTS ??_0Duration@absl@@QEAAAEAV01@N@Z ??_0Duration@absl@@QEAAAEAV01@_J@Z ??_1Duration@absl@@QEAAAEAV01@V01@@Z + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAEAVStatusBuilder@1@W4StatusCode@1@@Z @@ -466,6 +468,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPEAX_K@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z @@ -490,7 +493,9 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -566,7 +571,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NNAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?CopyCordToSpan@absl@@YA_KAEBVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXAEBVCord@1@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AEAA?AUCopyResult@123@_K_N@Z @@ -574,6 +579,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@AEBAXPEAD@Z ?Crash@Helper@internal_statusor@absl@@SAXAEBVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPEAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -581,6 +587,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPEAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@AEBAAEAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -663,6 +671,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@_K@Z @@ -702,7 +711,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -798,6 +806,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPEAUCordRep@cord_internal@2@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -1026,9 +1035,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@_K$07$02@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -1226,6 +1235,7 @@ EXPORTS ?Symbolize@absl@@YA_NPEBXPEADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1394,13 +1404,13 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@AEBV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV567@AEBV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@AEBV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@AEBVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEAMW4chars_format@1@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEANW4chars_format@1@@Z ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEAVtime_zone@123@@Z @@ -1423,6 +1433,7 @@ EXPORTS ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?resize@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?resize@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?safe_strto128_base@numbers_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVint128@2@H@Z @@ -1445,7 +1456,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?status@BadStatusOrAccess@absl@@QEBAAEBVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QEAAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?try_lock@Mutex@absl@@QEAA_NXZ ?try_lock_shared@Mutex@absl@@QEAA_NXZ ?unlock@Mutex@absl@@QEAAXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x64_dbg.def b/deps/v8/third_party/abseil-cpp/symbols_x64_dbg.def index cd2cb4f8c5dc..05189254baaa 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x64_dbg.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x64_dbg.def @@ -1,20 +1,13 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$CBD$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEBD@Z ??$?0$$CBU?$atomic@_N@__Cr@std@@@Condition@absl@@QEAA@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z0@Z ??$?0$$CBUCordRep@cord_internal@absl@@@Hex@absl@@QEAA@PEBUCordRep@cord_internal@1@W4PadSpec@1@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$?0$$CBVFormatArgImpl@str_format_internal@absl@@$$CBV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEAA@V?$initializer_list@VFormatArgImpl@str_format_internal@absl@@@std@@@Z ??$?0$$CB_W$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEB_W@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z ??$?0$$T@?$Storage@PEAPEAUCordRep@cord_internal@absl@@$00U?$StorageTag@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAPEAVLogSink@absl@@$00U?$StorageTag@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@PEAPEAVLogSink@absl@@@internal_compressed_tuple@container_internal@2@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAUPayload@status_internal@absl@@$00U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@PEAUPayload@status_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z @@ -35,7 +28,6 @@ EXPORTS ??$?0$$V@PlacementImpl@?$NoDestructor@VMutex@absl@@@absl@@QEAA@XZ ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@QEAA@AEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@QEAA@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@45@@Z - ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEAPEAPEAVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEAVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAPEBVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEBVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEBVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N$0A@@?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@QEAA@AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$QEA_N@Z @@ -67,8 +59,6 @@ EXPORTS ??$?0AEA_K@?$Storage@_K$0A@U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_K@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@$00@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEAA@AEA_KAEBV?$allocator@D@__Cr@std@@@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@@?$CompressedTupleImpl@V?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@U?$integer_sequence@_K$0A@$00@__Cr@std@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_KAEBV?$allocator@D@56@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEBV?$allocator@D@__Cr@std@@@?$Storage@V?$allocator@D@__Cr@std@@$00U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@D@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$0A@U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@UPayload@status_internal@absl@@@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEAA@AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$$QEAI@Z @@ -80,8 +70,6 @@ EXPORTS ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@Z ??$?0D@?$allocator@U?$AlignedType@$07@container_internal@absl@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@FormatArgImpl@str_format_internal@absl@@QEAA@AEBD@Z @@ -107,15 +95,10 @@ EXPORTS ??$?0PEAUTransitionType@cctz@time_internal@absl@@$0A@@?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@__Cr@std@@QEAA@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z ??$?0PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@PEAU0?1???R1234@QEBA?AV567@0@Z@$0A@@?$pair@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@PEAU1?1???R2345@QEBA?AV678@0@Z@@__Cr@std@@QEAA@$$QEAPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV567@@Z@1@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$tuple@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@$$QEAPEAVCommandLineFlag@absl@@@Z ??$?0PEAX@FlagState@flags_internal@absl@@QEAA@AEAVFlagImpl@12@AEBQEAX_N2_J@Z ??$?0PEBD@FormatArgImpl@str_format_internal@absl@@QEAA@AEBQEBD@Z ??$?0PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU0123@$0A@@?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@__Cr@std@@QEAA@$$QEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$?0PEBVFormatArgImpl@str_format_internal@absl@@$0A@@?$InlinedVector@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@absl@@QEAA@PEBVFormatArgImpl@str_format_internal@1@0AEBV?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@?$FunctionRef@$$A6A_K_K@Z@absl@@IEAA@Uin_place_t@__Cr@std@@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@X@?$FunctionRef@$$A6A_K_K@Z@absl@@QEAA@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z ??$?0U?$__check_pair_construction@UFindInfo@container_internal@absl@@V?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@$0A@@?$pair@UFindInfo@container_internal@absl@@V?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@QEAA@AEBUFindInfo@container_internal@absl@@AEBV?$NonIterableBitMask@I$0BA@$0A@@45@@Z ??$?0U?$array@D$0DKJI@@__Cr@std@@XU012@H@?$Span@D@absl@@QEAA@AEAU?$array@D$0DKJI@@__Cr@std@@@Z ??$?0U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -126,6 +109,7 @@ EXPORTS ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??$?0U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??$?0U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagSaverImpl@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagState@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@$$T@Z ??$?0U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVTimeZoneInfo@cctz@time_internal@absl@@@Z @@ -281,6 +265,7 @@ EXPORTS ??$?DPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@12@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@12@XZ + ??$?DPEAVFlagSaverImpl@flags_internal@absl@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagSaverImpl@flags_internal@absl@@XZ ??$?DPEAVFlagStateInterface@flags_internal@absl@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagStateInterface@flags_internal@absl@@XZ ??$?D_J@absl@@YA?AVDuration@0@_JV10@@Z ??$?GPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@@__Cr@std@@YA_JAEBV?$move_iterator@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@01@0@Z @@ -293,7 +278,6 @@ EXPORTS ??$?GPEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@__Cr@std@@YA_JAEBV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?GPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@01@0@Z ??$?GPEBQEAVLogSink@absl@@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEBQEAVLogSink@absl@@@01@0@Z - ??$?K_J@absl@@YA?AVDuration@0@V10@_J@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z @@ -303,10 +287,6 @@ EXPORTS ??$?RAEAPEAVLogSink@absl@@@__identity@__Cr@std@@QEBAAEAPEAVLogSink@absl@@AEAPEAV34@@Z ??$?RAEAPEBDAEAHAEAY0LLI@DAEBQEBDPEAD@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEBAXAEAPEBDAEAHAEAY0LLI@DAEBQEBD$$QEAPEAD@Z ??$?RAEAPEBVCommandLineFlag@absl@@@__identity@__Cr@std@@QEBAAEAPEBVCommandLineFlag@absl@@AEAPEBV34@@Z - ??$?RAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$01V?$Span@$$CBD@absl@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$01V?$Span@$$CBD@absl@@@345@@Z - ??$?RAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@345@@Z ??$?RAEAW4LogSeverity@absl@@AEAPEBDAEAHPEAPEADPEAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEBA_NAEAW4LogSeverity@2@AEAPEBDAEAH$$QEAPEAPEAD$$QEAPEAH@Z ??$?RAEAY04$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY04$$CBD$$QEAPEAVCondVar@2@@Z ??$?RAEAY06$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY06$$CBD$$QEAPEAVCondVar@2@@Z @@ -335,12 +315,12 @@ EXPORTS ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_backward_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@12@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEAPEAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEBQEAVCommandLineFlag@3@@Z ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$V@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@67@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@3@@Z ??$?RVDuration@absl@@V01@@?$__less@XX@__Cr@std@@QEBA_NAEBVDuration@absl@@0@Z ??$?RVMixingHashState@hash_internal@absl@@@CombineRaw@hash_internal@absl@@QEBA?AVMixingHashState@12@V312@_K@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z @@ -375,6 +355,7 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z ??$ArgumentToConv@C@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@D@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@E@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ @@ -410,8 +391,10 @@ EXPORTS ??$AsciiStrCaseFoldImpl@$0A@$00@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AsciiStrCaseFoldImpl@$0A@$0A@@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AssertHashEqConsistent@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$AssertNonNull@U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@functional_internal@absl@@YAXAEBU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z ??$AssertOnFind@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$AssignElements@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAUPayload@status_internal@1@AEAV?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@01@_K@Z ??$AssignElements@V?$allocator@VSourceLocation@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAVSourceLocation@1@AEAV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@01@_K@Z @@ -462,14 +445,9 @@ EXPORTS ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX0_K@Z ??$DecomposePair@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$DecomposePair@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAUFindElement@301@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z2@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z@Z @@ -542,6 +520,8 @@ EXPORTS ??$FastTypeId@_J@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_K@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_N@absl@@YA?AVFastTypeIdType@0@XZ + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -577,10 +557,10 @@ EXPORTS ??$GetDataImpl@V?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@@span_internal@absl@@YAPEAPEAVLogSink@1@AEAV?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@D@Z ??$GetFlag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@absl@@YA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@0@@Z ??$GetTrivialDestructRef@$0BI@$07@DtorPolicy@container_internal@absl@@SAAEBU012@XZ - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$HardeningAssertGE@PEBUPayload@status_internal@absl@@PEBU123@@base_internal@absl@@YAXPEBUPayload@status_internal@1@0@Z ??$HardeningAssertGE@_K_K@base_internal@absl@@YAX_K0@Z ??$HardeningAssertGT@_K_K@base_internal@absl@@YAX_K0@Z @@ -622,7 +602,6 @@ EXPORTS ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVBufferRawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVFILERawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeGet@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@@FlagImplPeer@flags_internal@absl@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@12@@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z ??$InvokeParseFlag@H@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@M@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@N@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -739,12 +718,8 @@ EXPORTS ??$OffsetValue@U?$atomic@_K@__Cr@std@@@FlagImpl@flags_internal@absl@@AEBAPEAU?$atomic@_K@__Cr@std@@XZ ??$OffsetValue@UFlagMaskedPointerValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagMaskedPointerValue@12@XZ ??$OffsetValue@UFlagOneWordValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagOneWordValue@12@XZ - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBQEAVCommandLineFlag@1@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z + ??$PairConstFirst@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z + ??$PairConstFirst@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$ParseFlag@H@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@M@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@N@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z @@ -764,9 +739,6 @@ EXPORTS ??$ReadCallback@P6A_NPEAUSynchEvent@absl@@@Z@Condition@absl@@AEBAXPEAP6A_NPEAUSynchEvent@1@@Z@Z ??$ReadCallback@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Condition@absl@@AEBAXPEAP6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Z ??$Register@AEB_JAEA_KAEA_KAEA_KAEAG@?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@QEAAPEAUHashtablezInfo@container_internal@2@AEB_JAEA_K11AEAG@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@0@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@0@Z@@Z ??$SNPrintF@DHHH@absl@@YAHPEAD_KAEBV?$FormatSpecTemplate@$0BPPPL@$0JPPPL@$0JPPPL@$0JPPPL@@str_format_internal@0@AEBDAEBH44@Z ??$Seconds@H$0A@@absl@@YA?AVDuration@0@H@Z ??$Seconds@J$0A@@absl@@YA?AVDuration@0@J@Z @@ -932,14 +904,20 @@ EXPORTS ??$__append_with_size@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_K@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z - ??$__as_variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@YAAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@AEAV201@@Z ??$__assign_with_size_random_access@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_J@Z ??$__assume_aligned@$07PEAVLogSink@absl@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@@Z ??$__assume_valid_range@AEAPEAPEAVLogSink@absl@@AEAPEAPEAV12@@__Cr@std@@YAXAEAPEAPEAVLogSink@absl@@0@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03$$V@__base@__visitation@__variant_detail@__Cr@std@@CA$$QEA_PAEBU?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@34@_K@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z@__base@__visitation@__variant_detail@__Cr@std@@CAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@ZAEBQ6A_K01@Z@Z ??$__call@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@?$__invoke_void_return_wrapper@X$00@__Cr@std@@SAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@7@@Z ??$__call_func@V<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@@?$__policy_func@$$A6AXAEAVCommandLineFlag@absl@@@Z@__function@__Cr@std@@CAXPEBT__policy_storage@123@AEAVCommandLineFlag@absl@@@Z + ??$__clear_padding_if_needed@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z$0A@@__Cr@std@@YAAEAP6AXAEBUHashtablezInfo@container_internal@absl@@@ZAEAP6AX0@Z@Z + ??$__clear_padding_if_needed@PEAUHashtablezInfo@container_internal@absl@@$0A@@__Cr@std@@YAAEAPEAUHashtablezInfo@container_internal@absl@@AEAPEAU234@@Z + ??$__clear_padding_if_needed@PEAVCordzHandle@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzHandle@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVCordzInfo@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzInfo@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVVLogSite@log_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVVLogSite@log_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@VMaskedPointer@flags_internal@absl@@$0A@@__Cr@std@@YAAEAVMaskedPointer@flags_internal@absl@@AEAV234@@Z + ??$__clear_padding_if_needed@W4OnDeadlockCycle@absl@@$0A@@__Cr@std@@YAAEAW4OnDeadlockCycle@absl@@AEAW423@@Z + ??$__clear_padding_if_needed@W4State@PerThreadSynch@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4State@PerThreadSynch@base_internal@absl@@AEAW42345@@Z + ??$__clear_padding_if_needed@W4WaitState@ThreadIdentity@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4WaitState@ThreadIdentity@base_internal@absl@@AEAW42345@@Z ??$__constexpr_memmove@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@__Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAVLogSink@absl@@PEAV12@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0W4__element_count@01@@Z @@ -967,8 +945,8 @@ EXPORTS ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$__construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$__construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$__construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1082,10 +1060,6 @@ EXPORTS ??$__destroy_at@UUnrecognizedFlag@absl@@@__Cr@std@@YAXPEAUUnrecognizedFlag@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@@__Cr@std@@YAXPEAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@YAXPEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@01@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$00@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$01@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$02@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$0A@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z ??$__distance@PEBUPayload@status_internal@absl@@$0A@@__Cr@std@@YA_JPEBUPayload@status_internal@absl@@0@Z ??$__distance@PEBUTransition@cctz@time_internal@absl@@$0A@@__Cr@std@@YA_JPEBUTransition@cctz@time_internal@absl@@0@Z ??$__distance@PEBVFormatArgImpl@str_format_internal@absl@@$0A@@__Cr@std@@YA_JPEBVFormatArgImpl@str_format_internal@absl@@0@Z @@ -1135,10 +1109,14 @@ EXPORTS ??$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0AEBQEAV23@AEAU__identity@01@@Z ??$__find_if@PEAPEAVLogSink@absl@@PEAPEAV12@V<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAV12@PEAPEAV12@0AEBQEAV12@AEAU__identity@45@@Z@AEAU645@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0$$QEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAV23@00AEBQEAV23@AEAU__identity@01@@Z@2@Z ??$__for_each_segment@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@23@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V123@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@@__Cr@std@@YAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@01@0V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@01@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@01@00V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@01@@Z@@Z - ??$__get_alt@$00AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$01AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$02AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$0A@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$01AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$01AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$02AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$02AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$0A@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$0A@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$00@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$00@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$01@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$01@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$0A@@34@@Z @@ -1164,7 +1142,6 @@ EXPORTS ??$__in_bounds@V?$__bucket_list_deallocator@V?$allocator@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@23@$0A@@__unique_ptr_array_bounds_stateless@__Cr@std@@QEBA_NPEAPEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@_K@Z ??$__insert_assign_n_unchecked@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAAXV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@_JPEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$__insert_with_size@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@V423@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1_J@Z - ??$__invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$__invoke@AEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAU__identity@__Cr@std@@AEAPEAVLogSink@absl@@@__Cr@std@@YAAEAPEAVLogSink@absl@@AEAU__identity@01@AEAPEAV23@@Z @@ -1173,10 +1150,6 @@ EXPORTS ??$__invoke@AEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV45@0AEBQEAV45@AEAU__identity@23@@Z@AEAPEAV45@@__Cr@std@@YA_NAEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAVLogSink@absl@@PEAPEAV34@0AEBQEAV34@AEAU__identity@01@@Z@AEAPEAV34@@Z ??$__invoke@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@__Cr@std@@YAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@6@@Z ??$__invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@501@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$Span@$$CBD@5@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@IHM@01@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@_K_JIH_N@01@@Z @@ -1245,7 +1218,6 @@ EXPORTS ??$__lower_bound_bisecting@U_ClassicAlgPolicy@__Cr@std@@PEBUTransition@cctz@time_internal@absl@@U4567@U__identity@23@UByUnixTime@4567@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@AEBU2345@_JAEAUByUnixTime@2345@AEAU__identity@01@@Z ??$__make_exception_guard@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@01@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@AEAAX_K@Z@@Z ??$__make_exception_guard@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@01@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@01@@Z - ??$__make_value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@CA?A_P$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@@Z ??$__memberwise_forward_assign@V?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@V?$tuple@PEAVCommandLineFlag@absl@@_N@23@PEAVCommandLineFlag@absl@@_N$$Z$0A@$00@__Cr@std@@YAXAEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@U?$__type_list@PEAVCommandLineFlag@absl@@_N@01@U?$__integer_sequence@_K$0A@$00@01@@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z @@ -1283,17 +1255,12 @@ EXPORTS ??$__static_fancy_pointer_cast@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@PEAV?$__tree_node_base@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@AEBQEAV?$__tree_node_base@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@@Z - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JN@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0@Z ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0U?$integral_constant@_N$0A@@01@@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z - ??$__throw_if_valueless@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__Cr@std@@YAXAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__to_address@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z ??$__to_address@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@YAPEAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@01@PEAPEAU201@@Z @@ -1364,24 +1331,21 @@ EXPORTS ??$__validate_iter_reference@AEAPEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEAVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@56@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@01234@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z - ??$__visit_value@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J_J$0A@@__Cr@std@@YAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@V?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@01@_J@Z ??$advance@V?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@_J@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAV?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@12@_J@Z ??$advance@V?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAPEBVCommandLineFlag@absl@@@01@_J@Z ??$advance@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@01@_J@Z - ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$assign@PEBVSourceLocation@absl@@$0A@@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEAAXPEBVSourceLocation@1@0@Z ??$assign@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@$0A@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0@Z @@ -1392,9 +1356,15 @@ EXPORTS ??$bit_cast@U?$FlagValueAndInitBit@_N@flags_internal@absl@@_J@__Cr@std@@YA?AU?$FlagValueAndInitBit@_N@flags_internal@absl@@AEB_J@Z ??$bit_cast@VFastTypeIdType@absl@@PEAX@__Cr@std@@YA?AVFastTypeIdType@absl@@AEBQEAX@Z ??$c_begin@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_begin@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_begin@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_begin@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$c_copy@V?$Span@$$CBI@absl@@PEAI@absl@@YAPEAIAEBV?$Span@$$CBI@0@$$QEAPEAI@Z + ??$c_copy@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@Z + ??$c_copy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@Z ??$c_end@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_end@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_end@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_end@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$call_once@A6AXXZ$$V@absl@@YAXAEAVonce_flag@0@A6AXXZ@Z ??$call_once@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@absl@@YAXAEAVonce_flag@0@$$QEAP8FlagImpl@flags_internal@0@EAAXXZ$$QEAPEAV230@@Z @@ -1405,8 +1375,8 @@ EXPORTS ??$combine@V?$tuple@AEB_K@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEBV?$tuple@AEB_K@__Cr@std@@@Z ??$combine@_K$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEB_K@Z ??$combine_contiguous@D@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@PEBD_K@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV45678@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEBV45678@@Z ??$construct@PEAUCordRep@cord_internal@absl@@AEBQEAU123@$0A@@?$allocator_traits@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@12@PEAPEAUCordRep@cord_internal@absl@@AEBQEAU456@@Z @@ -1425,8 +1395,8 @@ EXPORTS ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@$0A@@?$allocator_traits@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$$QEAU4567@@Z ??$construct@UPayload@status_internal@absl@@AEBU123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@AEBU456@@Z ??$construct@UPayload@status_internal@absl@@U123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@$$QEAU456@@Z @@ -1442,12 +1412,12 @@ EXPORTS ??$construct@UUnrecognizedFlag@absl@@U12@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAU45@@Z ??$construct@UUnrecognizedFlag@absl@@W4Source@12@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$construct@UViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV456@AEA_K$0A@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@PEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEBV712@AEA_K@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@23@AEBV678@@Z@$0A@@?$allocator_traits@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV789@@Z@@Z ??$construct@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V123@$0A@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@12@$$QEAV412@@Z ??$construct@VFormatArgImpl@str_format_internal@absl@@AEBV123@$0A@@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@12@PEAVFormatArgImpl@str_format_internal@absl@@AEBV456@@Z @@ -1473,8 +1443,8 @@ EXPORTS ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1534,13 +1504,13 @@ EXPORTS ??$distance@V?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z ??$distance@V?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$element@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@@Z + ??$emplace@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$emplace@$$V@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransition@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransition@cctz@time_internal@absl@@@12@@Z ??$emplace@$$V@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@12@@Z ??$emplace@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@?$optional@VStream@status_internal@absl@@@__Cr@std@@QEAAAEAVStream@status_internal@absl@@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$emplace@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$emplace_back@$$V@?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAXAEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -1575,11 +1545,9 @@ EXPORTS ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$forward_as_tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@AEBQEAVCommandLineFlag@absl@@@Z - ??$forward_as_tuple@PEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAPEAPEAUCordRep@cord_internal@2@XZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEA_KXZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEB_KXZ @@ -1602,7 +1570,6 @@ EXPORTS ??$get@$00PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEA_NAEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$01@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEBUStringEq@12@XZ ??$get@$02@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGAAAEAV?$allocator@D@__Cr@std@@XZ - ??$get@$0A@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEBV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ @@ -1622,7 +1589,6 @@ EXPORTS ??$get@$0A@@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEB_KXZ ??$get@$0A@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@@Z ??$get@$0A@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@YAAEAUFindInfo@container_internal@absl@@AEAV?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@23@@01@@Z - ??$get@$0A@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YAAEBQEAVCommandLineFlag@absl@@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YA$$QEAPEAVCommandLineFlag@absl@@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$hash@H@MixingHashState@hash_internal@absl@@SA_KAEBH@Z @@ -1641,7 +1607,6 @@ EXPORTS ??$hash_with_seed@V?$tuple@AEB_K@__Cr@std@@$0A@@MixingHashState@hash_internal@absl@@SA_KAEBV?$tuple@AEB_K@__Cr@std@@_K@Z ??$insert@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$insert@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@__Cr@std@@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1@Z - ??$invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@AEAPEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@0@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@PEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@$$QEAPEAPEAV34@@Z @@ -1667,6 +1632,7 @@ EXPORTS ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@XZ ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@AEAV12@$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@AEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$make_unique@VFallbackCrcMemcpyEngine@crc_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@01@XZ + ??$make_unique@VFlagSaverImpl@flags_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@01@XZ ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@AEAPEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@AEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@PEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@_JAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEA_JAEA_N21@Z @@ -1750,6 +1716,7 @@ EXPORTS ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?A_PPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer_impl@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@CA?AU?$integral_constant@_N$00@__Cr@std@@PEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@45@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1URank2@012@@Z + ??$ts_unchecked_read@PEAUHashtablezInfo@container_internal@absl@@@base_internal@absl@@YAAEAPEAUHashtablezInfo@container_internal@1@AEAPEAU231@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByCivilTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByCivilTime@2345@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z ??$value_or@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$optional_ref@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -1775,10 +1742,6 @@ EXPORTS ??0?$FormatSpecTemplate@$0JPPPL@@str_format_internal@absl@@QEAA@PEBD@Z ??0?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@_K@Z ??0?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@_K@Z - ??0?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAA@V?$HashtableCapacityImpl@$00@12@Uno_seed_empty_tag_t@12@@Z ??0?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAA@AEBV01@@Z @@ -2121,6 +2084,10 @@ EXPORTS ??0GroupSse2Impl@container_internal@absl@@QEAA@PEBW4ctrl_t@12@@Z ??0GrowthInfoLowerBound@container_internal@absl@@QEAA@E@Z ??0HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEAA@PEBE@Z + ??0HashtableCapacity@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@_K@Z + ??0HashtableInlineData@container_internal@absl@@QEAA@VHashtableCapacity@12@Uno_seed_empty_tag_t@12@@Z ??0HashtablezInfo@container_internal@absl@@QEAA@XZ ??0HashtablezInfoHandle@container_internal@absl@@QEAA@$$T@Z ??0Hex@absl@@AEAA@W4PadSpec@1@_K@Z @@ -2169,11 +2136,12 @@ EXPORTS ??0PrefixCrc@CrcCordState@crc_internal@absl@@QEAA@_KVcrc32c_t@3@@Z ??0ProtoField@log_internal@absl@@QEAA@XZ ??0Randen@random_internal@absl@@QEAA@XZ + ??0RawHashSetLayout@container_internal@absl@@AEAA@Uuninitialized_tag_t@12@@Z ??0RawHashSetLayout@container_internal@absl@@QEAA@_K00_N0@Z ??0ReaderMutexLock@absl@@QEAA@AEAVMutex@1@@Z + ??0ReentranceGuard@container_internal@absl@@QEAA@AEAVCommonFields@12@@Z ??0RefcountAndFlags@cord_internal@absl@@QEAA@XZ ??0RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??0ReleasableMutexLock@absl@@QEAA@AEAVMutex@1@@Z ??0Rep@CordBuffer@absl@@QEAA@PEAUCordRepFlat@cord_internal@2@@Z ??0Rep@CordBuffer@absl@@QEAA@XZ ??0Rep@CrcCordState@crc_internal@absl@@QEAA@XZ @@ -2372,6 +2340,7 @@ EXPORTS ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ + ??1?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ @@ -2433,8 +2402,8 @@ EXPORTS ??1Payload@status_internal@absl@@QEAA@XZ ??1PosixTimeZone@cctz@time_internal@absl@@QEAA@XZ ??1ReaderMutexLock@absl@@QEAA@XZ + ??1ReentranceGuard@container_internal@absl@@QEAA@XZ ??1RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??1ReleasableMutexLock@absl@@QEAA@XZ ??1Rep@CrcCordState@crc_internal@absl@@QEAA@XZ ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ @@ -2572,7 +2541,6 @@ EXPORTS ??8strings_internal@absl@@YA_NAEBV?$SplitIterator@V?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z ??9CharIterator@Cord@absl@@QEBA_NAEBV012@@Z ??9ChunkIterator@Cord@absl@@QEBA_NAEBV012@@Z - ??9GraphId@synchronization_internal@absl@@QEBA_NAEBU012@@Z ??9__Cr@std@@YA_NAEBU__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z @@ -2595,7 +2563,6 @@ EXPORTS ??A?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEBAAEBVFormatArgImpl@str_format_internal@1@_K@Z ??A?$Span@D@absl@@QEBAAEAD_K@Z ??A?$Span@I@absl@@QEBAAEAI_K@Z - ??A?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@__Cr@std@@QEBAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@12@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@612@@Z_K@Z ??A?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEBAAEAPEAVCommandLineFlag@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@__Cr@std@@QEBAAEAPEAVCordzHandle@cord_internal@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVLogSink@absl@@@__Cr@std@@QEBAAEAPEAVLogSink@absl@@_J@Z @@ -2627,6 +2594,7 @@ EXPORTS ??B?$function@$$A6A_NAEBVCommandLineFlag@absl@@@Z@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ??B?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ @@ -2666,6 +2634,7 @@ EXPORTS ??C?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAULogMessageData@LogMessage@log_internal@absl@@XZ ??C?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAURep@StatusBuilder@absl@@XZ ??C?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ + ??C?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVFlagSaverImpl@flags_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneIf@cctz@time_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneInfo@cctz@time_internal@absl@@XZ ??CChunkIterator@Cord@absl@@QEBAPEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ @@ -2707,6 +2676,7 @@ EXPORTS ??D?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAVSourceLocation@absl@@@__Cr@std@@QEBA$$QEAVSourceLocation@absl@@XZ + ??DCharIterator@Cord@absl@@QEBAAEBDXZ ??DChunkIterator@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ??D__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU__deque_block_range@123@XZ ??Dabsl@@YA?AVint128@0@V10@0@Z @@ -2792,6 +2762,7 @@ EXPORTS ??Pabsl@@YA_NVint128@0@0@Z ??Pabsl@@YA_NVuint128@0@0@Z ??R<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@23@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@QEBA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@2@Z + ??R<lambda_1>@?0???$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@QEBA?A?<auto>@@PEAD_K@Z @@ -2803,8 +2774,6 @@ EXPORTS ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2818,11 +2787,9 @@ EXPORTS ??R<lambda_1>@?0???$emplace_back@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@$$QEAV423@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@W4Source@UnrecognizedFlag@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??Append@FormatSinkImpl@str_format_internal@absl@@QEAAX_KD@Z@QEBA?A?<auto>@@0@Z - ??R<lambda_1>@?0??AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@23@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHAEBV23@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV456@@Z ??R<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@QEBA?A?<auto>@@AEAVCommandLineFlag@4@@Z - ??R<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@0@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2838,7 +2805,6 @@ EXPORTS ??R?$ConvertToContainer@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$FunctionRef@$$A6AXPEAUCordRep@cord_internal@absl@@_K1@Z@absl@@QEBAXPEAUCordRep@cord_internal@1@_K1@Z - ??R?$FunctionRef@$$A6AXPEAXPEBX@Z@absl@@QEBAXPEAXPEBX@Z ??R?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@absl@@QEBAXPEBW4ctrl_t@container_internal@1@PEAX@Z ??R?$FunctionRef@$$A6AXV?$Span@I@absl@@@Z@absl@@QEBAXV?$Span@I@1@@Z ??R?$FunctionRef@$$A6AXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z@absl@@QEBAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -2868,6 +2834,7 @@ EXPORTS ??R?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@QEBAXPEAURep@StatusBuilder@absl@@@Z ??R?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@QEBAXPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??R?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@QEBAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??R?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ??R?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagState@flags_internal@absl@@@Z ??R?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagStateInterface@flags_internal@absl@@@Z ??R?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@QEBAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -2934,6 +2901,7 @@ EXPORTS ??_5uint128@absl@@QEAAAEAV01@V01@@Z ??_6uint128@absl@@QEAAAEAV01@V01@@Z ??_DOStringStream@strings_internal@absl@@QEAAXXZ + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbsDuration@absl@@YA?AVDuration@1@V21@@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3022,6 +2990,7 @@ EXPORTS ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z ?AnnotateConstruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z ?AnnotateDestruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@Cord@absl@@QEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3049,24 +3018,22 @@ EXPORTS ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AEAAX_K@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z - ?AreItersFromSameContainer@container_internal@absl@@YA_NAEBQEBW4ctrl_t@12@0PEBX1@Z ?AsValueType@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@CAPEADPEAD@Z ?AsciiStrToLower@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@CordzInfo@cord_internal@absl@@QEAAXXZ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertHeld@SpinLock@base_internal@absl@@QEBAXXZ ?AssertInSooMode@CommonFields@container_internal@absl@@AEBAXXZ - ?AssertIsFull@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBEPEBD@Z - ?AssertIsValidForComparison@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBE@Z + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEBAXXZ ?AssertNotDebugCapacity@CommonFields@container_internal@absl@@QEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ - ?AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@_N@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEBV123@PEBV123@_N@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QEBAXVFastTypeIdType@3@P6APEBVtype_info@@XZ@Z @@ -3105,6 +3072,7 @@ EXPORTS ?CalculateBase64EscapedLenInternal@strings_internal@absl@@YA_K_K_N@Z ?CallVoidPtrFunction@Condition@absl@@CA_NPEBV12@@Z ?Capacity@CordRepFlat@cord_internal@absl@@QEBA_KXZ + ?CapacityBits@HashtableInlineData@container_internal@absl@@CA_KVHashtableCapacity@23@@Z ?CapacityToGrowth@container_internal@absl@@YA_K_K@Z ?CappedDamerauLevenshteinDistance@strings_internal@absl@@YAEV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0E@Z ?CatPieces@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$initializer_list@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@5@@Z @@ -3178,7 +3146,7 @@ EXPORTS ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?ConvertSpecialToEmptyAndFullToDeleted@GroupSse2Impl@container_internal@absl@@QEBAXPEAW4ctrl_t@23@@Z ?Copy@CordRepBtree@cord_internal@absl@@AEBAPEAV123@XZ - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?Copy@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z ?CopyBeginTo@CordRepBtree@cord_internal@absl@@AEBAPEAV123@_K0@Z ?CopyConstruct@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z @@ -3199,8 +3167,9 @@ EXPORTS ?CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PEIAXPEIBX_KV43@_N@Z ?Create@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAUCordRep@23@@Z ?Create@CordRepFlat@cord_internal@absl@@SAPEAU123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z - ?CreateDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ - ?CreateReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ + ?CreateDestroyed@HashtableCapacity@container_internal@absl@@SA?AV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z + ?CreateReentrance@HashtableCapacity@container_internal@absl@@SA?AV123@XZ ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -3224,6 +3193,8 @@ EXPORTS ?DeallocateIfAllocated@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -3273,6 +3244,7 @@ EXPORTS ?Digits10@?$BigUnsigned@$0FE@@strings_internal@absl@@SAHXZ ?DisableFlagfileAndEnvParsing@absl@@YAXXZ ?DisableRescheduling@SchedulingGuard@base_internal@absl@@SA_NXZ + ?Distance@Cord@absl@@SA_JAEBVCharIterator@12@0@Z ?DoIgnoreLeak@absl@@YAXPEBX@Z ?DoLoad@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBVCord@absl@@@Z@base_internal@absl@@AEBAP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBVCord@3@@ZXZ ?DoLoad@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@AEBAP6AXPEBDH000@ZXZ @@ -3361,6 +3333,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32c@absl@@YA?AVcrc32c_t@1@V21@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3401,7 +3374,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -3490,7 +3462,7 @@ EXPORTS ?FromHost64@little_endian@absl@@YA_K_K@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0DM@$00@__Cr@std@@@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0OBA@$00@__Cr@std@@@Z - ?FromRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@_K@Z + ?FromRawData@HashtableCapacity@container_internal@absl@@SA?AV123@_K@Z ?FromTM@absl@@YA?AVTime@1@AEBUtm@@VTimeZone@1@@Z ?FromUDate@absl@@YA?AVTime@1@N@Z ?FromUniversal@absl@@YA?AVTime@1@_J@Z @@ -3566,6 +3538,7 @@ EXPORTS ?GetGrowthLeft@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ ?GetGrowthLeftLowerBound@CommonFields@container_internal@absl@@QEBA_KXZ ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -3758,7 +3731,7 @@ EXPORTS ?IsDataLoss@absl@@YA_NAEBVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NAEBVStatus@1@@Z ?IsDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z - ?IsDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsDestroyed@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsEmpty@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsEmptyOrDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsExternal@CordRep@cord_internal@absl@@QEBA_NXZ @@ -3786,7 +3759,7 @@ EXPORTS ?IsPermissionDenied@absl@@YA_NAEBVStatus@1@@Z ?IsPow2@CordBuffer@absl@@CA_N_K@Z ?IsReachable@GraphCycles@synchronization_internal@absl@@QEBA_NUGraphId@23@0@Z - ?IsReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsReentrance@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsResourceExhausted@absl@@YA_NAEBVStatus@1@@Z ?IsRetired@CommandLineFlag@absl@@UEBA_NXZ ?IsSMTEnabled@base_internal@absl@@YA_NXZ @@ -3802,8 +3775,8 @@ EXPORTS ?IsUnimplemented@absl@@YA_NAEBVStatus@1@@Z ?IsUnknown@absl@@YA_NAEBVStatus@1@@Z ?IsUnprotectedReadCandidate@MaskedPointer@flags_internal@absl@@QEBA_NXZ - ?IsValid@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ ?IsValid@CordRepBtree@cord_internal@absl@@SA_NPEBV123@_N@Z + ?IsValid@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsValidCapacity@container_internal@absl@@YA_N_K@Z ?IterateOverFullSlots@container_internal@absl@@YAXAEBVCommonFields@12@_KV?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@2@@Z ?JoinMessageToStatus@StatusPrivateAccessorForStatusBuilder@status_internal@absl@@SA?AVStatus@3@V43@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@W4MessageJoinStyle@3@@Z @@ -3962,6 +3935,7 @@ EXPORTS ?NumClonedBytes@container_internal@absl@@YA_KXZ ?NumContextsPerCPU@base_internal@absl@@YAHXZ ?NumControlBytes@container_internal@absl@@YA_K_K@Z + ?NumControlBytesForLargeTable@container_internal@absl@@YA_K_K@Z ?NumGenerationBytes@container_internal@absl@@YA_KXZ ?NumLeakedFlagValues@flags_internal@absl@@YA_KXZ ?ODRCheck@CordzInfo@cord_internal@absl@@AEBAXXZ @@ -4014,9 +3988,9 @@ EXPORTS ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrecombineLengthMix@hash_internal@absl@@YA_K_K0@Z ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -4346,6 +4320,7 @@ EXPORTS ?TakeRep@Cord@absl@@AEHAAPEAUCordRep@cord_internal@2@XZ ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -4409,9 +4384,8 @@ EXPORTS ?ToInt64Nanoseconds@absl@@YA_JVDuration@1@@Z ?ToInt64Seconds@absl@@YA_JVDuration@1@@Z ?ToOpResult@CordRepBtree@cord_internal@absl@@AEAA?AUOpResult@123@_N@Z - ?ToPublicSeed@?$HashtableInlineDataImpl@$00@container_internal@absl@@CA_K_K@Z - ?ToRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBAEXZ ?ToRawData@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ + ?ToRawData@HashtableCapacity@container_internal@absl@@QEBAEXZ ?ToSinkAlso@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToSinkOnly@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToString@?$BigUnsigned@$03@strings_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -4694,7 +4668,6 @@ EXPORTS ?__annotate_shrink_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_K0@Z ?__annotate_whole_block@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z ?__annotate_whole_block@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z - ?__as_base@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@IEGAA@XZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_size_layout@V?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -4801,6 +4774,17 @@ EXPORTS ?__destruct_at_end@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransition@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransitionType@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUViableSubstitution@strings_internal@absl@@@Z + ?__empty@?$__vector_layout@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end_node@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAPEAV?$__tree_end_node@PEAV?$__tree_node_base@PEAX@__Cr@std@@@23@XZ @@ -5212,8 +5196,8 @@ EXPORTS ?begin@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?begin@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?begin@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?blocked_element_count@CommonFields@container_internal@absl@@QEBA_KXZ + ?blocked_element_count@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?btree@CordRep@cord_internal@absl@@QEAAPEAVCordRepBtree@23@XZ ?btree@CordRep@cord_internal@absl@@QEBAPEBVCordRepBtree@23@XZ ?btree@CordRepBtreeNavigator@cord_internal@absl@@QEBAPEAVCordRepBtree@23@XZ @@ -5221,8 +5205,6 @@ EXPORTS ?bucket_count@?$__hash_table@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEBA_KXZ ?bucket_count@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?bytes_value@ProtoField@log_internal@absl@@QEBA?AV?$Span@$$CBD@3@XZ - ?capacity@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_KXZ - ?capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_size_layout@V?$__split_buffer@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@V__split_buffer_size_layout@45@@__Cr@std@@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -5251,7 +5233,9 @@ EXPORTS ?capacity@CommonFields@container_internal@absl@@QEBA_KXZ ?capacity@CordBuffer@absl@@QEBA_KXZ ?capacity@CordRepBtree@cord_internal@absl@@QEBA_KXZ - ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?capacity@HashtableCapacity@container_internal@absl@@QEBA_KXZ + ?capacity@HashtableInlineData@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ + ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?cbegin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ ?cbegin@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA?AV?$__wrap_iter@PEBQEAVLogSink@absl@@@23@XZ ?cend@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ @@ -5414,8 +5398,8 @@ EXPORTS ?deallocate@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@23@PEAVFormatArgImpl@str_format_internal@absl@@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VSourceLocation@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VSourceLocation@absl@@@23@PEAVSourceLocation@absl@@_K@Z - ?decrement_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?decrement_size@CommonFields@container_internal@absl@@QEAAXXZ + ?decrement_size@HashtableInlineData@container_internal@absl@@QEAAXXZ ?delimiter@?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByChar@3@XZ @@ -5430,7 +5414,6 @@ EXPORTS ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ ?element@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z ?emplace@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@CAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z - ?empty@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?empty@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEBA_NXZ @@ -5455,6 +5438,7 @@ EXPORTS ?empty@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?empty@CommonFields@container_internal@absl@@QEBA_NXZ ?empty@Cord@absl@@QEBA_NXZ + ?empty@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?encoded_message@LogEntry@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?encoded_remaining@LogMessageData@LogMessage@log_internal@absl@@QEAAAEAV?$Span@D@4@XZ ?end@?$BitMask@I$0BA@$0A@$0A@@container_internal@absl@@QEBA?AV123@XZ @@ -5509,7 +5493,6 @@ EXPORTS ?end@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?end@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?end@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?eq_ref@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBAAEBUStringEq@23@XZ ?erase@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAAPEAUPayload@status_internal@2@PEBU342@@Z ?erase@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAPEAVLogSink@absl@@@23@V?$__wrap_iter@PEBQEAVLogSink@absl@@@23@@Z @@ -5533,8 +5516,8 @@ EXPORTS ?gbswap_16@absl@@YAGG@Z ?gbswap_32@absl@@YAII@Z ?gbswap_64@absl@@YA_K_K@Z - ?generate_new_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?generate_new_seed@CommonFields@container_internal@absl@@QEAAX_N@Z + ?generate_new_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ ?generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation@HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation_offset@RawHashSetLayout@container_internal@absl@@QEBA_KXZ @@ -5586,10 +5569,8 @@ EXPORTS ?get@?$__temp_value@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransition@cctz@time_internal@absl@@XZ ?get@?$__temp_value@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransitionType@cctz@time_internal@absl@@XZ ?get@?$__tuple_leaf@$00AEAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAUFindInfo@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAUFindInfo@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEBQEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@PEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?get@?$unique_ptr@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$__allocator_destructor@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ @@ -5629,10 +5610,10 @@ EXPORTS ?get_soo_data@HeapOrSoo@container_internal@absl@@QEBAPEBXXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z ?get_yearday@detail@cctz@time_internal@absl@@YAHAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z - ?growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ + ?growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ ?has_alt_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ - ?has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?has_infoz@CommonFields@container_internal@absl@@QEBA_NXZ + ?has_infoz@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?has_left_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_show_pos_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ @@ -5652,22 +5633,24 @@ EXPORTS ?hour@?$civil_time@Uhour_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?increment_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?increment_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?increment_size@CommonFields@container_internal@absl@@QEAAXXZ ?increment_size@CommonFields@container_internal@absl@@QEAAX_K@Z + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?index@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_KXZ ?index@?$probe_seq@$0BA@@container_internal@absl@@QEBA_KXZ + ?index@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_KXZ ?index@CordRepBtree@cord_internal@absl@@QEBA_KW4EdgeType@123@@Z ?infoz@CommonFields@container_internal@absl@@QEAA?AVHashtablezInfoHandle@23@XZ + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ - ?init_blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z ?init_blocked_element_count@CommonFields@container_internal@absl@@QEAAX_K@Z + ?init_blocked_element_count@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?inline_size@InlineData@cord_internal@absl@@QEBA_KXZ ?inline_size@InlineRep@Cord@absl@@AEBA_KXZ ?inline_size@Rep@InlineData@cord_internal@absl@@QEBA_KXZ - ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z + ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z ?insert@?$unordered_set@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEAA?AU?$pair@V?$__hash_const_iterator@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBQEBUCordRep@cord_internal@absl@@@Z ?int32_value@ProtoField@log_internal@absl@@QEBAHXZ ?int64_value@ProtoField@log_internal@absl@@QEBA_JXZ @@ -5682,13 +5665,13 @@ EXPORTS ?is_length@ConvTag@str_format_internal@absl@@QEBA_NXZ ?is_profiled@InlineData@cord_internal@absl@@QEBA_NXZ ?is_relative_timeout@KernelTimeout@synchronization_internal@absl@@QEBA_NXZ - ?is_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ + ?is_sampled_seed@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_short@Rep@CordBuffer@absl@@QEBA_NXZ ?is_single_group@container_internal@absl@@YA_N_K@Z - ?is_small@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ - ?is_small@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?is_small@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_small@CommonFields@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableCapacity@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QEBA_NXZ ?is_soo@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_tree@InlineData@cord_internal@absl@@QEBA_NXZ @@ -5747,8 +5730,8 @@ EXPORTS ?max_size@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_KXZ ?max_size@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?maybe_increment_generation_on_insert@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXXZ - ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AV?$HashtableCapacityImpl@$00@23@XZ - ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AVHashtableCapacity@23@XZ + ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?memcasecmp@strings_internal@absl@@YAHPEBD0_K@Z ?message@Status@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?message@StatusRep@status_internal@absl@@QEBAAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -5780,10 +5763,10 @@ EXPORTS ?ok@Status@absl@@QEBA_NXZ ?ok@Utf8ForCodePoint@debugging_internal@absl@@QEBA_NXZ ?overflow@Streambuf@OStringStream@strings_internal@absl@@MEAAHH@Z - ?overwrite_control_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXW4ctrl_t@23@@Z - ?overwrite_empty_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_deleted@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_empty_in_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?overwrite_control_as_full@HashtableInlineData@container_internal@absl@@QEAAXW4ctrl_t@23@@Z + ?overwrite_empty_as_full@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_deleted@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_empty_in_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXXZ ?parse@detail@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0AEBVtime_zone@234@PEAV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@PEAV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@chrono@67@PEAV567@@Z ?parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBAPEBVParsedFormatBase@23@XZ ?pointer_to@?$pointer_traits@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@23@AEAU423@@Z @@ -5826,6 +5809,7 @@ EXPORTS ?push_back@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUTransition@cctz@time_internal@absl@@@Z ?push_back@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUUnrecognizedFlag@absl@@@Z ?raw_code@Status@absl@@QEBAHXZ + ?read_byte@HashtableInlineData@container_internal@absl@@AEBAE_K@Z ?reduce_size@InlineRep@Cord@absl@@QEAAX_K@Z ?release@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?release@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEAAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ @@ -5869,6 +5853,7 @@ EXPORTS ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagState@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagStateInterface@flags_internal@absl@@@Z ?reset@?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -5894,17 +5879,19 @@ EXPORTS ?scale_add@impl@detail@cctz@time_internal@absl@@YA_J_J00@Z ?second@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?second@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@CommonFields@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ + ?seed@HashtableInlineData@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@PerTableSeed@container_internal@absl@@QEBA_KXZ ?set@?$MaybeInitializedPtr@W4ctrl_t@container_internal@absl@@@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_arg@BoundConversion@str_format_internal@absl@@QEAAXPEBVFormatArgImpl@23@@Z ?set_begin@CordRepBtree@cord_internal@absl@@AEAAX_K@Z - ?set_blocked_element_count_to_zero@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?set_blocked_element_count_to_zero@CommonFields@container_internal@absl@@QEAAXXZ - ?set_capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z - ?set_capacity@CommonFields@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z + ?set_blocked_element_count_to_zero@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_capacity@CommonFields@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z ?set_capacity@CommonFields@container_internal@absl@@QEAAX_K@Z + ?set_capacity@CommonFields@container_internal@absl@@QECAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QECAXVHashtableCapacity@23@@Z ?set_control@CommonFields@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_conversion_char@FormatConversionSpecImpl@str_format_internal@absl@@QEAAXW4FormatConversionChar@3@@Z ?set_cordz_info@InlineData@cord_internal@absl@@QEAAXPEAVCordzInfo@23@@Z @@ -5918,9 +5905,9 @@ EXPORTS ?set_full_soo@CommonFields@container_internal@absl@@QEAAXXZ ?set_generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXE@Z ?set_generation_ptr@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXPEAE@Z - ?set_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z - ?set_has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?set_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z ?set_has_infoz@CommonFields@container_internal@absl@@QEAAXXZ + ?set_has_infoz@HashtableInlineData@container_internal@absl@@QEAAXXZ ?set_infoz@CommonFields@container_internal@absl@@QEAAXVHashtablezInfoHandle@23@@Z ?set_inline_data@InlineData@cord_internal@absl@@QEAAXPEBD_K@Z ?set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z @@ -5928,10 +5915,10 @@ EXPORTS ?set_inline_size@Rep@InlineData@cord_internal@absl@@QEAAX_K@Z ?set_reservation_size@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z ?set_reserved_growth@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z - ?set_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?set_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@AEAAXE@Z + ?set_sampled_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_seed@HashtableInlineData@container_internal@absl@@AEAAXE@Z ?set_short_length@Rep@CordBuffer@absl@@QEAAX_K@Z - ?set_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?set_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?set_size_to_zero@CommonFields@container_internal@absl@@QEAAXXZ ?set_tag@Rep@InlineData@cord_internal@absl@@QEAAXC@Z ?set_tree@InlineData@cord_internal@absl@@QEAAXPEAUCordRep@23@@Z @@ -5944,11 +5931,11 @@ EXPORTS ?shrink_to_fit@?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?single_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@123@XZ + ?single_non_soo_slot@CommonFields@container_internal@absl@@QEBAPEAXXZ ?single_slot@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@XZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?size@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ - ?size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ @@ -5993,6 +5980,7 @@ EXPORTS ?size@CommonFields@container_internal@absl@@QEBA_KXZ ?size@Cord@absl@@QEBA_KXZ ?size@CordRepBtree@cord_internal@absl@@QEBA_KXZ + ?size@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?size@InlineRep@Cord@absl@@QEBA_KXZ ?size@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ ?skip_empty_or_deleted@iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXXZ @@ -6042,7 +6030,7 @@ EXPORTS ?timestamp@LogEntry@absl@@QEBA?AVTime@2@XZ ?total_written@BufferRawSink@str_format_internal@absl@@QEBA_KXZ ?transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@0@Z - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?tree@InlineRep@Cord@absl@@QEBAPEAUCordRep@cord_internal@3@XZ ?tree@Rep@InlineData@cord_internal@absl@@QEBAPEAUCordRep@34@XZ ?try_lock@Mutex@absl@@QEAA_NXZ @@ -6061,8 +6049,6 @@ EXPORTS ?value@InputValue@UnboundConversion@str_format_internal@absl@@QEBAHXZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ - ?valueless_by_exception@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_NXZ - ?valueless_by_exception@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_NXZ ?verbosity@LogEntry@absl@@QEBAHXZ ?version@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?what@BadStatusOrAccess@absl@@UEBAPEBDXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x64_dbg_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_x64_dbg_cxx23.def index 6680d6630f05..696898eb5516 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x64_dbg_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x64_dbg_cxx23.def @@ -1,20 +1,13 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$CBD$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEBD@Z ??$?0$$CBU?$atomic@_N@__Cr@std@@@Condition@absl@@QEAA@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z0@Z ??$?0$$CBUCordRep@cord_internal@absl@@@Hex@absl@@QEAA@PEBUCordRep@cord_internal@1@W4PadSpec@1@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$?0$$CBVFormatArgImpl@str_format_internal@absl@@$$CBV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEAA@V?$initializer_list@VFormatArgImpl@str_format_internal@absl@@@std@@@Z ??$?0$$CB_W$0A@@VoidPtr@str_format_internal@absl@@QEAA@PEB_W@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QEAPEAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z ??$?0$$T@?$Storage@PEAPEAUCordRep@cord_internal@absl@@$00U?$StorageTag@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAPEAVLogSink@absl@@$00U?$StorageTag@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@PEAPEAVLogSink@absl@@@internal_compressed_tuple@container_internal@2@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z ??$?0$$T@?$Storage@PEAUPayload@status_internal@absl@@$00U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@PEAUPayload@status_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@$$QEA$$T@Z @@ -35,7 +28,6 @@ EXPORTS ??$?0$$V@PlacementImpl@?$NoDestructor@VMutex@absl@@@absl@@QEAA@XZ ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@QEAA@AEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@QEAA@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@45@@Z - ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEAPEAPEAVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEAVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEAVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAPEBVCommandLineFlag@absl@@AEA_N$0A@@?$pair@PEAPEBVCommandLineFlag@absl@@_N@__Cr@std@@QEAA@AEAPEAPEBVCommandLineFlag@absl@@AEA_N@Z ??$?0AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N$0A@@?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@QEAA@AEAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$QEA_N@Z @@ -67,8 +59,6 @@ EXPORTS ??$?0AEA_K@?$Storage@_K$0A@U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$0A@@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_K@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@$00@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEAA@AEA_KAEBV?$allocator@D@__Cr@std@@@Z ??$?0AEA_KAEBV?$allocator@D@__Cr@std@@@?$CompressedTupleImpl@V?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@U?$integer_sequence@_K$0A@$00@__Cr@std@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEA_KAEBV?$allocator@D@56@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@AEBQEAVCommandLineFlag@absl@@@Z - ??$?0AEBQEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@AEBQEAVCommandLineFlag@absl@@@Z ??$?0AEBV?$allocator@D@__Cr@std@@@?$Storage@V?$allocator@D@__Cr@std@@$00U?$StorageTag@_KV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@D@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$0A@U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QEAA@Uin_place_t@__Cr@std@@AEBV?$allocator@UPayload@status_internal@absl@@@56@@Z ??$?0AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEAA@AEBV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$$QEAI@Z @@ -80,8 +70,6 @@ EXPORTS ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AEAV?$tuple@$$V@12@U?$__integer_sequence@_K$0A@@12@U?$__integer_sequence@_K$S@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z ??$?0AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEAA@Upiecewise_construct_t@12@AEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@12@U?$__integer_sequence@_K$0A@@12@3@Z - ??$?0AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZAEBQEAVCommandLineFlag@absl@@@?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEAA@Upiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@Z ??$?0D@?$allocator@U?$AlignedType@$07@container_internal@absl@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAA@AEBV?$allocator@D@12@@Z ??$?0D@FormatArgImpl@str_format_internal@absl@@QEAA@AEBD@Z @@ -107,15 +95,10 @@ EXPORTS ??$?0PEAUTransitionType@cctz@time_internal@absl@@$0A@@?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEAA@AEBV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0PEAUTransitionType@cctz@time_internal@absl@@PEAU0123@$0A@@?$pair@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@__Cr@std@@QEAA@$$QEAPEAUTransitionType@cctz@time_internal@absl@@0@Z ??$?0PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@PEAU0?1???R1234@QEBA?AV567@0@Z@$0A@@?$pair@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@PEAU1?1???R2345@QEBA?AV678@0@Z@@__Cr@std@@QEAA@$$QEAPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV567@@Z@1@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@$0A@@?$tuple@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@$$QEAPEAVCommandLineFlag@absl@@@Z - ??$?0PEAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@_K$0A@@__Cr@std@@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEAA@U__forward_args@12@$$QEAPEAVCommandLineFlag@absl@@@Z ??$?0PEAX@FlagState@flags_internal@absl@@QEAA@AEAVFlagImpl@12@AEBQEAX_N2_J@Z ??$?0PEBD@FormatArgImpl@str_format_internal@absl@@QEAA@AEBQEBD@Z ??$?0PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU0123@$0A@@?$pair@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@@__Cr@std@@QEAA@$$QEAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$?0PEBVFormatArgImpl@str_format_internal@absl@@$0A@@?$InlinedVector@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@absl@@QEAA@PEBVFormatArgImpl@str_format_internal@1@0AEBV?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@?$FunctionRef@$$A6A_K_K@Z@absl@@IEAA@Uin_place_t@__Cr@std@@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@X@?$FunctionRef@$$A6A_K_K@Z@absl@@QEAA@$$QEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z ??$?0U?$array@D$0DKJI@@__Cr@std@@XU012@H@?$Span@D@absl@@QEAA@AEAU?$array@D$0DKJI@@__Cr@std@@@Z ??$?0U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAULogMessageData@LogMessage@log_internal@absl@@@Z @@ -125,6 +108,7 @@ EXPORTS ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??$?0U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??$?0U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagSaverImpl@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVFlagState@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@$$T@Z ??$?0U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@PEAVTimeZoneInfo@cctz@time_internal@absl@@@Z @@ -281,6 +265,7 @@ EXPORTS ??$?DPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@12@XZ ??$?DPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBAAEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@12@XZ + ??$?DPEAVFlagSaverImpl@flags_internal@absl@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagSaverImpl@flags_internal@absl@@XZ ??$?DPEAVFlagStateInterface@flags_internal@absl@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAAEAVFlagStateInterface@flags_internal@absl@@XZ ??$?D_J@absl@@YA?AVDuration@0@_JV10@@Z ??$?GPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV01234@@__Cr@std@@YA_JAEBV?$move_iterator@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@01@0@Z @@ -293,7 +278,6 @@ EXPORTS ??$?GPEAUTransitionType@cctz@time_internal@absl@@PEAU0123@@__Cr@std@@YA_JAEBV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?GPEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV234@@Z@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@01@0@Z ??$?GPEBQEAVLogSink@absl@@@__Cr@std@@YA_JAEBV?$__wrap_iter@PEBQEAVLogSink@absl@@@01@0@Z - ??$?K_J@absl@@YA?AVDuration@0@V10@_J@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z @@ -303,10 +287,6 @@ EXPORTS ??$?RAEAPEAVLogSink@absl@@@__identity@__Cr@std@@QEBAAEAPEAVLogSink@absl@@AEAPEAV34@@Z ??$?RAEAPEBDAEAHAEAY0LLI@DAEBQEBDPEAD@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@QEBAXAEAPEBDAEAHAEAY0LLI@DAEBQEBD$$QEAPEAD@Z ??$?RAEAPEBVCommandLineFlag@absl@@@__identity@__Cr@std@@QEBAAEAPEBVCommandLineFlag@absl@@AEAPEBV34@@Z - ??$?RAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$01V?$Span@$$CBD@absl@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$01V?$Span@$$CBD@absl@@@345@@Z - ??$?RAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@345@@Z - ??$?RAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QEBA_KAEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@345@@Z ??$?RAEAW4LogSeverity@absl@@AEAPEBDAEAHPEAPEADPEAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PEBDHPEAPEADPEAH@Z@base_internal@absl@@QEBA_NAEAW4LogSeverity@2@AEAPEBDAEAH$$QEAPEAPEAD$$QEAPEAH@Z ??$?RAEAY04$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY04$$CBD$$QEAPEAVCondVar@2@@Z ??$?RAEAY06$$CBDPEAVCondVar@absl@@@?$AtomicHook@P6AXPEBDPEBX@Z@base_internal@absl@@QEBAXAEAY06$$CBD$$QEAPEAVCondVar@2@@Z @@ -335,12 +315,12 @@ EXPORTS ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_backward_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QEBA?AU?$__in_out_result@PEAUTransitionType@cctz@time_internal@absl@@PEAU1234@@12@PEAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@12@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEAPEAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEBQEAVCommandLineFlag@3@@Z ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$V@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@AEBQEAVCommandLineFlag@absl@@@12@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@67@$$QEAV?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QEBA_NAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEBA_KAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV012@AEAPEAVCommandLineFlag@absl@@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@123@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AEAPEAVCommandLineFlag@3@@Z ??$?RVDuration@absl@@V01@@?$__less@XX@__Cr@std@@QEBA_NAEBVDuration@absl@@0@Z ??$?RVMixingHashState@hash_internal@absl@@@CombineRaw@hash_internal@absl@@QEBA?AVMixingHashState@12@V312@_K@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAPEBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAPEBD@Z @@ -375,6 +355,7 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z ??$ArgumentToConv@C@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@D@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@E@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ @@ -410,8 +391,10 @@ EXPORTS ??$AsciiStrCaseFoldImpl@$0A@$00@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AsciiStrCaseFoldImpl@$0A@$0A@@ascii_internal@absl@@YAXPEADPEBD_K@Z ??$AssertHashEqConsistent@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$AssertNonNull@U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@functional_internal@absl@@YAXAEBU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z ??$AssertOnFind@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$AssignElements@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAUPayload@status_internal@1@AEAV?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PEAUPayload@status_internal@absl@@@23@@01@_K@Z ??$AssignElements@V?$allocator@VSourceLocation@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPEAVSourceLocation@1@AEAV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@01@_K@Z @@ -462,14 +445,9 @@ EXPORTS ??$DeallocateBackingArray@$07V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPEAX0_K@Z ??$DecomposePair@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$DecomposePair@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@01@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QEAUFindElement@301@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@U?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z2@Z ??$Destruct@$00@container_internal@absl@@YAXAEAVCommonFields@01@AEBUDtorPolicy@01@P6AXPEAX2_K@Z@Z @@ -542,6 +520,8 @@ EXPORTS ??$FastTypeId@_J@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_K@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_N@absl@@YA?AVFastTypeIdType@0@XZ + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -577,10 +557,10 @@ EXPORTS ??$GetDataImpl@V?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@@span_internal@absl@@YAPEAPEAVLogSink@1@AEAV?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@D@Z ??$GetFlag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@absl@@YA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@0@@Z ??$GetTrivialDestructRef@$0BI@$07@DtorPolicy@container_internal@absl@@SAAEBU012@XZ - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$HardeningAssertGE@PEBUPayload@status_internal@absl@@PEBU123@@base_internal@absl@@YAXPEBUPayload@status_internal@1@0@Z ??$HardeningAssertGE@_K_K@base_internal@absl@@YAX_K0@Z ??$HardeningAssertGT@_K_K@base_internal@absl@@YAX_K0@Z @@ -622,7 +602,6 @@ EXPORTS ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVBufferRawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPEAVFILERawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeGet@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@@FlagImplPeer@flags_internal@absl@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@12@@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z ??$InvokeParseFlag@H@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@M@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@N@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -739,12 +718,8 @@ EXPORTS ??$OffsetValue@U?$atomic@_K@__Cr@std@@@FlagImpl@flags_internal@absl@@AEBAPEAU?$atomic@_K@__Cr@std@@XZ ??$OffsetValue@UFlagMaskedPointerValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagMaskedPointerValue@12@XZ ??$OffsetValue@UFlagOneWordValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@AEBAPEAUFlagOneWordValue@12@XZ - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBQEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@AEBQEAVCommandLineFlag@absl@@@23@@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBQEAVCommandLineFlag@1@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QEAPEAVCommandLineFlag@1@@Z + ??$PairConstFirst@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z + ??$PairConstFirst@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@YAAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@Z ??$ParseFlag@H@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAHPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@M@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAMPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@N@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEANPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z @@ -764,9 +739,6 @@ EXPORTS ??$ReadCallback@P6A_NPEAUSynchEvent@absl@@@Z@Condition@absl@@AEBAXPEAP6A_NPEAUSynchEvent@1@@Z@Z ??$ReadCallback@P6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Condition@absl@@AEBAXPEAP6A_NPEBU?$atomic@_N@__Cr@std@@@Z@Z ??$Register@AEB_JAEA_KAEA_KAEA_KAEAG@?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@QEAAPEAUHashtablezInfo@container_internal@2@AEB_JAEA_K11AEAG@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@0@Z@@CommonFields@container_internal@absl@@QEAAXV<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@0@Z@@Z ??$SNPrintF@DHHH@absl@@YAHPEAD_KAEBV?$FormatSpecTemplate@$0BPPPL@$0JPPPL@$0JPPPL@$0JPPPL@@str_format_internal@0@AEBDAEBH44@Z ??$Seconds@H$0A@@absl@@YA?AVDuration@0@H@Z ??$Seconds@J$0A@@absl@@YA?AVDuration@0@J@Z @@ -925,14 +897,20 @@ EXPORTS ??$__append_with_size@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_K@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@X@23@@01@AEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z - ??$__as_variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@YAAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@AEAV201@@Z ??$__assign_with_size_random_access@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@_J@Z ??$__assume_aligned@$07PEAVLogSink@absl@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@@Z ??$__assume_valid_range@AEAPEAPEAVLogSink@absl@@AEAPEAPEAV12@@__Cr@std@@YAXAEAPEAPEAVLogSink@absl@@0@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03$$V@__base@__visitation@__variant_detail@__Cr@std@@CA$$QEA_PAEBU?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@34@_K@Z - ??$__at@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z@__base@__visitation@__variant_detail@__Cr@std@@CAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@ZAEBQ6A_K01@Z@Z ??$__call@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@?$__invoke_void_return_wrapper@X$00@__Cr@std@@SAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@7@@Z ??$__call_func@V<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@@?$__policy_func@$$A6AXAEAVCommandLineFlag@absl@@@Z@__function@__Cr@std@@CAXPEBT__policy_storage@123@AEAVCommandLineFlag@absl@@@Z + ??$__clear_padding_if_needed@P6AXAEBUHashtablezInfo@container_internal@absl@@@Z$0A@@__Cr@std@@YAAEAP6AXAEBUHashtablezInfo@container_internal@absl@@@ZAEAP6AX0@Z@Z + ??$__clear_padding_if_needed@PEAUHashtablezInfo@container_internal@absl@@$0A@@__Cr@std@@YAAEAPEAUHashtablezInfo@container_internal@absl@@AEAPEAU234@@Z + ??$__clear_padding_if_needed@PEAVCordzHandle@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzHandle@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVCordzInfo@cord_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVCordzInfo@cord_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@PEAVVLogSite@log_internal@absl@@$0A@@__Cr@std@@YAAEAPEAVVLogSite@log_internal@absl@@AEAPEAV234@@Z + ??$__clear_padding_if_needed@VMaskedPointer@flags_internal@absl@@$0A@@__Cr@std@@YAAEAVMaskedPointer@flags_internal@absl@@AEAV234@@Z + ??$__clear_padding_if_needed@W4OnDeadlockCycle@absl@@$0A@@__Cr@std@@YAAEAW4OnDeadlockCycle@absl@@AEAW423@@Z + ??$__clear_padding_if_needed@W4State@PerThreadSynch@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4State@PerThreadSynch@base_internal@absl@@AEAW42345@@Z + ??$__clear_padding_if_needed@W4WaitState@ThreadIdentity@base_internal@absl@@$0A@@__Cr@std@@YAAEAW4WaitState@ThreadIdentity@base_internal@absl@@AEAW42345@@Z ??$__constexpr_memmove@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@@__Cr@std@@YAPEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU2345@0W4__element_count@01@@Z ??$__constexpr_memmove@PEAVLogSink@absl@@PEAV12@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0W4__element_count@01@@Z @@ -960,8 +938,8 @@ EXPORTS ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$__construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$__construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$__construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1075,10 +1053,6 @@ EXPORTS ??$__destroy_at@UUnrecognizedFlag@absl@@@__Cr@std@@YAXPEAUUnrecognizedFlag@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@@__Cr@std@@YAXPEAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@YAXPEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@01@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$00@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$01@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$02@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$0A@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@2345@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z ??$__distance@PEBUPayload@status_internal@absl@@$0A@@__Cr@std@@YA_JPEBUPayload@status_internal@absl@@0@Z ??$__distance@PEBUTransition@cctz@time_internal@absl@@$0A@@__Cr@std@@YA_JPEBUTransition@cctz@time_internal@absl@@0@Z ??$__distance@PEBVFormatArgImpl@str_format_internal@absl@@$0A@@__Cr@std@@YA_JPEBVFormatArgImpl@str_format_internal@absl@@0@Z @@ -1128,10 +1102,14 @@ EXPORTS ??$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0AEBQEAV23@AEAU__identity@01@@Z ??$__find_if@PEAPEAVLogSink@absl@@PEAPEAV12@V<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAV12@PEAPEAV12@0AEBQEAV12@AEAU__identity@45@@Z@AEAU645@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV23@0$$QEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAV23@00AEBQEAV23@AEAU__identity@01@@Z@2@Z ??$__for_each_segment@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@23@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V123@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@@__Cr@std@@YAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@01@0V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@01@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@01@00V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@01@@Z@@Z - ??$__get_alt@$00AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$01AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$02AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$0A@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$01AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$01AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$02AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$02AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$0A@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$0A@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$00@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$00@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$01@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$01@34@@Z ??$__get_alt@AEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__union@__access@__variant_detail@__Cr@std@@SA$$QEA_PAEAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$0A@@34@@Z @@ -1157,7 +1135,6 @@ EXPORTS ??$__in_bounds@V?$__bucket_list_deallocator@V?$allocator@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@PEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@23@$0A@@__unique_ptr_array_bounds_stateless@__Cr@std@@QEBA_NPEAPEAU?$__hash_node_base@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@_K@Z ??$__insert_assign_n_unchecked@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAAXV?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@_JPEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$__insert_with_size@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@23@V423@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1_J@Z - ??$__invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$__invoke@AEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByCivilTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU2345@AEBU2345@@__Cr@std@@YA_NAEAUByUnixTime@Transition@cctz@time_internal@absl@@AEBU3456@1@Z ??$__invoke@AEAU__identity@__Cr@std@@AEAPEAVLogSink@absl@@@__Cr@std@@YAAEAPEAVLogSink@absl@@AEAU__identity@01@AEAPEAV23@@Z @@ -1166,10 +1143,6 @@ EXPORTS ??$__invoke@AEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@__Cr@std@@YAPEAPEAVLogSink@absl@@PEAPEAV45@0AEBQEAV45@AEAU__identity@23@@Z@AEAPEAV45@@__Cr@std@@YA_NAEAV<lambda_1>@?0???$__find_generic@PEAPEAVLogSink@absl@@PEAPEAV12@PEAV12@U__identity@__Cr@std@@@01@YAPEAPEAVLogSink@absl@@PEAPEAV34@0AEBQEAV34@AEAU__identity@01@@Z@AEAPEAV34@@Z ??$__invoke@AEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@5@@__Cr@std@@YAXAEAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@AEAVCommandLineFlag@6@@Z ??$__invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$01V?$Span@$$CBD@absl@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$02V?$variant@IHM@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@456@@__Cr@std@@YA_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AEAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@501@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$Span@$$CBD@5@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@IHM@01@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__Cr@std@@YA_K$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@_K_JIH_N@01@@Z @@ -1238,7 +1211,6 @@ EXPORTS ??$__lower_bound_bisecting@U_ClassicAlgPolicy@__Cr@std@@PEBUTransition@cctz@time_internal@absl@@U4567@U__identity@23@UByUnixTime@4567@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@AEBU2345@_JAEAUByUnixTime@2345@AEAU__identity@01@@Z ??$__make_exception_guard@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAX_K@Z@@01@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@AEAAX_K@Z@@Z ??$__make_exception_guard@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@__Cr@std@@@01@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PEAUUnrecognizedFlag@absl@@@01@@Z - ??$__make_value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@CA?A_P$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@@Z ??$__memberwise_forward_assign@V?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@V?$tuple@PEAVCommandLineFlag@absl@@_N@23@PEAVCommandLineFlag@absl@@_N$$Z$0A@$00@__Cr@std@@YAXAEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@U?$__type_list@PEAVCommandLineFlag@absl@@_N@01@U?$__integer_sequence@_K$0A@$00@01@@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV45678@PEAPEAPEBV45678@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV12345@@01@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@00@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU4567@PEAPEAU4567@@__Cr@std@@YA?AU?$__in_out_result@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEAPEAU1234@@01@PEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z @@ -1276,17 +1248,12 @@ EXPORTS ??$__static_fancy_pointer_cast@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@PEAV?$__tree_node_base@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@AEBQEAV?$__tree_node_base@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@01@@Z ??$__static_fancy_pointer_cast@PEAV?$__tree_node_base@PEAX@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@__Cr@std@@YAPEAV?$__tree_node_base@PEAX@01@AEBQEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@01@@Z - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$Span@$$CBD@4@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@IHM@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JIH_N@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@_K_JN@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0@Z ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAEAV?$allocator@UUnrecognizedFlag@absl@@@01@0U?$integral_constant@_N$0A@@01@@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEAVCommandLineFlag@absl@@0AEA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PEAPEBVCommandLineFlag@absl@@@__Cr@std@@YAXAEAPEAPEBVCommandLineFlag@absl@@0AEA_K1@Z - ??$__throw_if_valueless@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__Cr@std@@YAXAEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@YAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBU2345@@Z ??$__to_address@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@YAPEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEAPEBV23456@@Z ??$__to_address@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@YAPEAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@01@PEAPEAU201@@Z @@ -1357,9 +1324,6 @@ EXPORTS ??$__validate_iter_reference@AEAPEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEAVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PEAPEBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@1234@AEAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@56@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@01234@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z - ??$__visit_value@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@78@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@PEBUTransition@cctz@time_internal@absl@@_J_J$0A@@__Cr@std@@YAXAEAPEBUTransition@cctz@time_internal@absl@@_J@Z ??$advance@V?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@_J_J$0A@@__Cr@std@@YAXAEAV?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@01@_J@Z @@ -1379,15 +1343,15 @@ EXPORTS ??$allocate_at_least@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PEAUUnrecognizedFlag@absl@@_K@12@AEAV?$allocator@UUnrecognizedFlag@absl@@@12@_K@Z ??$allocate_at_least@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PEAUViableSubstitution@strings_internal@absl@@_K@12@AEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@_K@Z ??$allocate_at_least@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@_K@12@AEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@_K@Z - ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_N$$QEAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_K$$QEAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QEAUFindElement@412@AEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$assign@PEBVSourceLocation@absl@@$0A@@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEAAXPEBVSourceLocation@1@0@Z ??$assign@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@$0A@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@12@0@Z @@ -1398,9 +1362,15 @@ EXPORTS ??$bit_cast@U?$FlagValueAndInitBit@_N@flags_internal@absl@@_J@__Cr@std@@YA?AU?$FlagValueAndInitBit@_N@flags_internal@absl@@AEB_J@Z ??$bit_cast@VFastTypeIdType@absl@@PEAX@__Cr@std@@YA?AVFastTypeIdType@absl@@AEBQEAX@Z ??$c_begin@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_begin@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_begin@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_begin@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$c_copy@V?$Span@$$CBI@absl@@PEAI@absl@@YAPEAIAEBV?$Span@$$CBI@0@$$QEAPEAI@Z + ??$c_copy@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEAPEAD@Z + ??$c_copy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@absl@@YAPEADAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAPEAD@Z ??$c_end@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPEBIAEBV?$Span@$$CBI@1@@Z + ??$c_end@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_end@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEBD@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_end@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AEAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$call_once@A6AXXZ$$V@absl@@YAXAEAVonce_flag@0@A6AXXZ@Z ??$call_once@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@absl@@YAXAEAVonce_flag@0@$$QEAP8FlagImpl@flags_internal@0@EAAXXZ$$QEAPEAV230@@Z @@ -1411,8 +1381,8 @@ EXPORTS ??$combine@V?$tuple@AEB_K@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEBV?$tuple@AEB_K@__Cr@std@@@Z ??$combine@_K$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@AEB_K@Z ??$combine_contiguous@D@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@PEBD_K@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@AEAPEAPEBV45678@@Z ??$construct@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@PEAPEBV12345@$0A@@?$allocator_traits@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@12@PEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@$$QEAPEAPEBV45678@@Z ??$construct@PEAUCordRep@cord_internal@absl@@AEBQEAU123@$0A@@?$allocator_traits@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@12@PEAPEAUCordRep@cord_internal@absl@@AEBQEAU456@@Z @@ -1431,8 +1401,8 @@ EXPORTS ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@12@PEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QEAV?$tuple@$$V@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@12@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@12@PEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@$0A@@?$allocator_traits@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@PEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$$QEAU4567@@Z ??$construct@UPayload@status_internal@absl@@AEBU123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@AEBU456@@Z ??$construct@UPayload@status_internal@absl@@U123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UPayload@status_internal@absl@@@12@PEAUPayload@status_internal@absl@@$$QEAU456@@Z @@ -1448,12 +1418,12 @@ EXPORTS ??$construct@UUnrecognizedFlag@absl@@U12@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAU45@@Z ??$construct@UUnrecognizedFlag@absl@@W4Source@12@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UUnrecognizedFlag@absl@@@12@PEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$construct@UViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV456@AEA_K$0A@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@PEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEBV712@AEA_K@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@45@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@45@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEAPEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QEBQEAVCommandLineFlag@2@@Z ??$construct@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@23@AEBV678@@Z@$0A@@?$allocator_traits@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@AEBV789@@Z@@Z ??$construct@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V123@$0A@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@12@$$QEAV412@@Z ??$construct@VFormatArgImpl@str_format_internal@absl@@AEBV123@$0A@@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@12@PEAVFormatArgImpl@str_format_internal@absl@@AEBV456@@Z @@ -1479,8 +1449,8 @@ EXPORTS ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PEAU123@@__Cr@std@@YAPEAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QEAV?$tuple@$$V@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@AEBUpiecewise_construct_t@23@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@AEBUpiecewise_construct_t@01@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QEAVCommandLineFlag@absl@@PEAU123@@__Cr@std@@YAPEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@01@PEAU201@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QEBQEAVCommandLineFlag@absl@@@Z ??$construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PEAU1234@@__Cr@std@@YAPEAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PEAU2345@$$QEAU2345@@Z ??$construct_at@UPayload@status_internal@absl@@AEBU123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@AEBU234@@Z ??$construct_at@UPayload@status_internal@absl@@U123@PEAU123@@__Cr@std@@YAPEAUPayload@status_internal@absl@@PEAU234@$$QEAU234@@Z @@ -1540,13 +1510,13 @@ EXPORTS ??$distance@V?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@01@0@Z ??$distance@V?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YA_JV?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$element@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@@Z + ??$emplace@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$emplace@$$V@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransition@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransition@cctz@time_internal@absl@@@12@@Z ??$emplace@$$V@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAUTransitionType@cctz@time_internal@absl@@@12@V?$__wrap_iter@PEBUTransitionType@cctz@time_internal@absl@@@12@@Z ??$emplace@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@?$optional@VStream@status_internal@absl@@@__Cr@std@@QEAAAEAVStream@status_internal@absl@@AEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$emplace@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$emplace_at@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEAPEAVCommandLineFlag@2@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QEAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QEBQEAVCommandLineFlag@2@@Z ??$emplace_back@$$V@?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QEAAXXZ ??$emplace_back@AEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAXAEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -1581,11 +1551,9 @@ EXPORTS ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AVconst_iterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$forward_as_tuple@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@AEBQEAVCommandLineFlag@absl@@@Z - ??$forward_as_tuple@PEAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@$$QEAPEAVCommandLineFlag@absl@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAPEAPEAUCordRep@cord_internal@2@XZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEA_KXZ ??$get@$00@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEB_KXZ @@ -1608,7 +1576,6 @@ EXPORTS ??$get@$00PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEA_NAEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$01@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEBUStringEq@12@XZ ??$get@$02@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QEGAAAEAV?$allocator@D@__Cr@std@@XZ - ??$get@$0A@$$QEAPEAVCommandLineFlag@absl@@@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@PEAPEAUCordRep@cord_internal@absl@@@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGAAAEAV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@_K@container_internal@absl@@QEGBAAEBV?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@XZ @@ -1628,7 +1595,6 @@ EXPORTS ??$get@$0A@@?$CompressedTuple@_KV?$allocator@D@__Cr@std@@@container_internal@absl@@QEGBAAEB_KXZ ??$get@$0A@AEAPEAVCommandLineFlag@absl@@AEA_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@AEAPEAVCommandLineFlag@absl@@AEA_N@01@@Z ??$get@$0A@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@YAAEAUFindInfo@container_internal@absl@@AEAV?$tuple@AEAUFindInfo@container_internal@absl@@AEAV?$NonIterableBitMask@I$0BA@$0A@@23@@01@@Z - ??$get@$0A@AEBQEAVCommandLineFlag@absl@@@__Cr@std@@YAAEBQEAVCommandLineFlag@absl@@AEAV?$tuple@AEBQEAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YA$$QEAPEAVCommandLineFlag@absl@@$$QEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$get@$0A@PEAVCommandLineFlag@absl@@_N@__Cr@std@@YAAEAPEAVCommandLineFlag@absl@@AEAV?$tuple@PEAVCommandLineFlag@absl@@_N@01@@Z ??$hash@H@MixingHashState@hash_internal@absl@@SA_KAEBH@Z @@ -1647,7 +1613,6 @@ EXPORTS ??$hash_with_seed@V?$tuple@AEB_K@__Cr@std@@$0A@@MixingHashState@hash_internal@absl@@SA_KAEBV?$tuple@AEB_K@__Cr@std@@_K@Z ??$insert@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@45@@Z ??$insert@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@__Cr@std@@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PEAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV345@@Z@@12@1@Z - ??$invoke@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K@__Cr@std@@YA_KAEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QEA_K@Z ??$invoke@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@__Cr@std@@YAX$$QEAP8FlagImpl@flags_internal@absl@@EAAXXZ$$QEAPEAV234@@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@AEAPEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@0@Z ??$iter_swap@AEAPEAPEAVCommandLineFlag@absl@@PEAPEAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAEAPEAPEAVCommandLineFlag@absl@@$$QEAPEAPEAV34@@Z @@ -1673,6 +1638,7 @@ EXPORTS ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@XZ ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@AEAV12@$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@AEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$make_unique@VFallbackCrcMemcpyEngine@crc_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@01@XZ + ??$make_unique@VFlagSaverImpl@flags_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@01@XZ ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@AEAPEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@AEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@PEAXAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEAPEAXAEA_N2$$QEA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AEAVFlagImpl@23@_JAEA_NAEA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AEAVFlagImpl@flags_internal@absl@@$$QEA_JAEA_N21@Z @@ -1763,6 +1729,7 @@ EXPORTS ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SA?A_PPEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1@Z ??$transfer_impl@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@CA?AU?$integral_constant@_N$00@__Cr@std@@PEAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@@45@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@12@1URank2@012@@Z + ??$ts_unchecked_read@PEAUHashtablezInfo@container_internal@absl@@@base_internal@absl@@YAAEAPEAUHashtablezInfo@container_internal@1@AEAPEAU231@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByCivilTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByCivilTime@2345@@Z ??$upper_bound@PEBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__Cr@std@@YAPEBUTransition@cctz@time_internal@absl@@PEBU2345@0AEBU2345@UByUnixTime@2345@@Z ??$value_or@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$optional_ref@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -1788,10 +1755,6 @@ EXPORTS ??0?$FormatSpecTemplate@$0JPPPL@@str_format_internal@absl@@QEAA@PEBD@Z ??0?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@_K@Z ??0?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@QEAA@AEBUStringHash@12@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QEAA@_K@Z - ??0?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAA@V?$HashtableCapacityImpl@$00@12@Uno_seed_empty_tag_t@12@@Z ??0?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEAA@XZ ??0?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAA@AEBV01@@Z @@ -2134,6 +2097,10 @@ EXPORTS ??0GroupSse2Impl@container_internal@absl@@QEAA@PEBW4ctrl_t@12@@Z ??0GrowthInfoLowerBound@container_internal@absl@@QEAA@E@Z ??0HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEAA@PEBE@Z + ??0HashtableCapacity@container_internal@absl@@AEAA@W4InvalidCapacity@012@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@Uuninitialized_tag_t@12@@Z + ??0HashtableCapacity@container_internal@absl@@QEAA@_K@Z + ??0HashtableInlineData@container_internal@absl@@QEAA@VHashtableCapacity@12@Uno_seed_empty_tag_t@12@@Z ??0HashtablezInfo@container_internal@absl@@QEAA@XZ ??0HashtablezInfoHandle@container_internal@absl@@QEAA@$$T@Z ??0Hex@absl@@AEAA@W4PadSpec@1@_K@Z @@ -2182,11 +2149,12 @@ EXPORTS ??0PrefixCrc@CrcCordState@crc_internal@absl@@QEAA@_KVcrc32c_t@3@@Z ??0ProtoField@log_internal@absl@@QEAA@XZ ??0Randen@random_internal@absl@@QEAA@XZ + ??0RawHashSetLayout@container_internal@absl@@AEAA@Uuninitialized_tag_t@12@@Z ??0RawHashSetLayout@container_internal@absl@@QEAA@_K00_N0@Z ??0ReaderMutexLock@absl@@QEAA@AEAVMutex@1@@Z + ??0ReentranceGuard@container_internal@absl@@QEAA@AEAVCommonFields@12@@Z ??0RefcountAndFlags@cord_internal@absl@@QEAA@XZ ??0RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??0ReleasableMutexLock@absl@@QEAA@AEAVMutex@1@@Z ??0Rep@CordBuffer@absl@@QEAA@PEAUCordRepFlat@cord_internal@2@@Z ??0Rep@CordBuffer@absl@@QEAA@XZ ??0Rep@CrcCordState@crc_internal@absl@@QEAA@XZ @@ -2385,6 +2353,7 @@ EXPORTS ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ + ??1?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ @@ -2446,8 +2415,8 @@ EXPORTS ??1Payload@status_internal@absl@@QEAA@XZ ??1PosixTimeZone@cctz@time_internal@absl@@QEAA@XZ ??1ReaderMutexLock@absl@@QEAA@XZ + ??1ReentranceGuard@container_internal@absl@@QEAA@XZ ??1RefcountedRep@CrcCordState@crc_internal@absl@@QEAA@XZ - ??1ReleasableMutexLock@absl@@QEAA@XZ ??1Rep@CrcCordState@crc_internal@absl@@QEAA@XZ ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ @@ -2585,7 +2554,6 @@ EXPORTS ??8strings_internal@absl@@YA_NAEBV?$SplitIterator@V?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z ??9CharIterator@Cord@absl@@QEBA_NAEBV012@@Z ??9ChunkIterator@Cord@absl@@QEBA_NAEBV012@@Z - ??9GraphId@synchronization_internal@absl@@QEBA_NAEBU012@@Z ??9__Cr@std@@YA_NAEBU__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NAEBV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@@01@0@Z @@ -2608,7 +2576,6 @@ EXPORTS ??A?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QEBAAEBVFormatArgImpl@str_format_internal@1@_K@Z ??A?$Span@D@absl@@QEBAAEAD_K@Z ??A?$Span@I@absl@@QEBAAEAI_K@Z - ??A?$__farray@P6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@__Cr@std@@QEBAAEBQ6A_K$$QEAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@12@AEAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@612@@Z_K@Z ??A?$__wrap_iter@PEAPEAVCommandLineFlag@absl@@@__Cr@std@@QEBAAEAPEAVCommandLineFlag@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVCordzHandle@cord_internal@absl@@@__Cr@std@@QEBAAEAPEAVCordzHandle@cord_internal@absl@@_J@Z ??A?$__wrap_iter@PEAPEAVLogSink@absl@@@__Cr@std@@QEBAAEAPEAVLogSink@absl@@_J@Z @@ -2640,6 +2607,7 @@ EXPORTS ??B?$function@$$A6A_NAEBVCommandLineFlag@absl@@@Z@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ??B?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ ??B?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ @@ -2679,6 +2647,7 @@ EXPORTS ??C?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAULogMessageData@LogMessage@log_internal@absl@@XZ ??C?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAURep@StatusBuilder@absl@@XZ ??C?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ + ??C?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVFlagSaverImpl@flags_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneIf@cctz@time_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBAPEAVTimeZoneInfo@cctz@time_internal@absl@@XZ ??CChunkIterator@Cord@absl@@QEBAPEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ @@ -2720,6 +2689,7 @@ EXPORTS ??D?$move_iterator@PEAUTransition@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QEBA$$QEAUTransitionType@cctz@time_internal@absl@@XZ ??D?$move_iterator@PEAVSourceLocation@absl@@@__Cr@std@@QEBA$$QEAVSourceLocation@absl@@XZ + ??DCharIterator@Cord@absl@@QEBAAEBDXZ ??DChunkIterator@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ??D__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU__deque_block_range@123@XZ ??Dabsl@@YA?AVint128@0@V10@0@Z @@ -2805,6 +2775,7 @@ EXPORTS ??Pabsl@@YA_NVint128@0@0@Z ??Pabsl@@YA_NVuint128@0@0@Z ??R<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@12@$0A@@__copy_impl@__Cr@std@@QEBA?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@23@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@23@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@23@@Z@QEBA?A?<auto>@@PEBUPrefixCrc@CrcCordState@crc_internal@absl@@2@Z + ??R<lambda_1>@?0???$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@QEBA?A?<auto>@@PEAD_K@Z ??R<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@QEBA?A?<auto>@@PEAD_K@Z @@ -2816,8 +2787,6 @@ EXPORTS ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAA?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@_J@__Cr@std@@_N@23@AEBUpiecewise_construct_t@23@$$QEAV?$tuple@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QEAV?$tuple@$$V@23@@Z@QEBA?A?<auto>@@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ - ??R<lambda_1>@?0???$construct@AEBUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@AEBUpiecewise_construct_t@__Cr@std@@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@67@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2831,11 +2800,9 @@ EXPORTS ??R<lambda_1>@?0???$emplace_back@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@$$QEAV423@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@W4Source@UnrecognizedFlag@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUUnrecognizedFlag@absl@@$$QEAW4Source@45@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@@Z@QEBA?A?<auto>@@XZ ??R<lambda_1>@?0??Append@FormatSinkImpl@str_format_internal@absl@@QEAAX_KD@Z@QEBA?A?<auto>@@0@Z - ??R<lambda_1>@?0??AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@23@0PEBX1PEBE2@Z@QEBA?A?<auto>@@_NPEBD@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHAEBV23@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@AEBAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K1@Z@QEBA?A?<auto>@@PEAVChunkIterator@23@PEAV456@@Z ??R<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QEAAXXZ@QEBA?A?<auto>@@AEAVCommandLineFlag@4@@Z - ??R<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@34@0@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@AEA_K@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUViableSubstitution@strings_internal@absl@@AEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBV723@AEA_K@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCommandLineFlag@absl@@@?$vector@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@AEBQEAV45@@Z@QEBA?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AEBQEAVCordzHandle@cord_internal@absl@@@?$vector@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAPEAVCordzHandle@cord_internal@absl@@AEBQEAV456@@Z@QEBA?A?<auto>@@XZ @@ -2851,7 +2818,6 @@ EXPORTS ??R?$ConvertToContainer@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBA?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AEBV123@@Z ??R?$FunctionRef@$$A6AXPEAUCordRep@cord_internal@absl@@_K1@Z@absl@@QEBAXPEAUCordRep@cord_internal@1@_K1@Z - ??R?$FunctionRef@$$A6AXPEAXPEBX@Z@absl@@QEBAXPEAXPEBX@Z ??R?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@absl@@QEBAXPEBW4ctrl_t@container_internal@1@PEAX@Z ??R?$FunctionRef@$$A6AXV?$Span@I@absl@@@Z@absl@@QEBAXV?$Span@I@1@@Z ??R?$FunctionRef@$$A6AXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z@absl@@QEBAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -2881,6 +2847,7 @@ EXPORTS ??R?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@QEBAXPEAURep@StatusBuilder@absl@@@Z ??R?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@QEBAXPEAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??R?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@QEBAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??R?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ??R?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagState@flags_internal@absl@@@Z ??R?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@QEBAXPEAVFlagStateInterface@flags_internal@absl@@@Z ??R?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@QEBAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -2947,6 +2914,7 @@ EXPORTS ??_5uint128@absl@@QEAAAEAV01@V01@@Z ??_6uint128@absl@@QEAAAEAV01@V01@@Z ??_DOStringStream@strings_internal@absl@@QEAAXXZ + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbsDuration@absl@@YA?AVDuration@1@V21@@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3035,6 +3003,7 @@ EXPORTS ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z ?AnnotateConstruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z ?AnnotateDestruct@NonEmptyInlinedStorage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAAX_K@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@Cord@absl@@QEAAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3062,24 +3031,22 @@ EXPORTS ?AppendTruncated@log_internal@absl@@YA_KV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AEAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AEAAX_K@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z - ?AreItersFromSameContainer@container_internal@absl@@YA_NAEBQEBW4ctrl_t@12@0PEBX1@Z ?AsValueType@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@CAPEADPEAD@Z ?AsciiStrToLower@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@CordzInfo@cord_internal@absl@@QEAAXXZ ?AssertHeld@Mutex@absl@@QEBAXXZ ?AssertHeld@SpinLock@base_internal@absl@@QEBAXXZ ?AssertInSooMode@CommonFields@container_internal@absl@@AEBAXXZ - ?AssertIsFull@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBEPEBD@Z - ?AssertIsValidForComparison@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@PEBXEPEBE@Z + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEBAXXZ ?AssertNotDebugCapacity@CommonFields@container_internal@absl@@QEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ - ?AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@_N@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPEBV123@PEBV123@_N@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QEBAXVFastTypeIdType@3@P6APEBVtype_info@@XZ@Z @@ -3118,6 +3085,7 @@ EXPORTS ?CalculateBase64EscapedLenInternal@strings_internal@absl@@YA_K_K_N@Z ?CallVoidPtrFunction@Condition@absl@@CA_NPEBV12@@Z ?Capacity@CordRepFlat@cord_internal@absl@@QEBA_KXZ + ?CapacityBits@HashtableInlineData@container_internal@absl@@CA_KVHashtableCapacity@23@@Z ?CapacityToGrowth@container_internal@absl@@YA_K_K@Z ?CappedDamerauLevenshteinDistance@strings_internal@absl@@YAEV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0E@Z ?CatPieces@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$initializer_list@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@5@@Z @@ -3191,7 +3159,7 @@ EXPORTS ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?ConvertSpecialToEmptyAndFullToDeleted@GroupSse2Impl@container_internal@absl@@QEBAXPEAW4ctrl_t@23@@Z ?Copy@CordRepBtree@cord_internal@absl@@AEBAPEAV123@XZ - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?Copy@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z ?CopyBeginTo@CordRepBtree@cord_internal@absl@@AEBAPEAV123@_K0@Z ?CopyConstruct@flags_internal@absl@@YAXP6APEAXW4FlagOp@12@PEBXPEAX2@Z12@Z @@ -3212,8 +3180,9 @@ EXPORTS ?CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PEIAXPEIBX_KV43@_N@Z ?Create@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAUCordRep@23@@Z ?Create@CordRepFlat@cord_internal@absl@@SAPEAU123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z - ?CreateDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ - ?CreateReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ + ?CreateDestroyed@HashtableCapacity@container_internal@absl@@SA?AV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z + ?CreateReentrance@HashtableCapacity@container_internal@absl@@SA?AV123@XZ ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -3237,6 +3206,8 @@ EXPORTS ?DeallocateIfAllocated@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ ?DeallocateIfAllocated@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXXZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -3286,6 +3257,7 @@ EXPORTS ?Digits10@?$BigUnsigned@$0FE@@strings_internal@absl@@SAHXZ ?DisableFlagfileAndEnvParsing@absl@@YAXXZ ?DisableRescheduling@SchedulingGuard@base_internal@absl@@SA_NXZ + ?Distance@Cord@absl@@SA_JAEBVCharIterator@12@0@Z ?DoIgnoreLeak@absl@@YAXPEBX@Z ?DoLoad@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@AEBVCord@absl@@@Z@base_internal@absl@@AEBAP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBVCord@3@@ZXZ ?DoLoad@?$AtomicHook@P6AXPEBDH000@Z@base_internal@absl@@AEBAP6AXPEBDH000@ZXZ @@ -3374,6 +3346,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32c@absl@@YA?AVcrc32c_t@1@V21@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3414,7 +3387,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -3503,7 +3475,7 @@ EXPORTS ?FromHost64@little_endian@absl@@YA_K_K@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0DM@$00@__Cr@std@@@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0OBA@$00@__Cr@std@@@Z - ?FromRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@_K@Z + ?FromRawData@HashtableCapacity@container_internal@absl@@SA?AV123@_K@Z ?FromTM@absl@@YA?AVTime@1@AEBUtm@@VTimeZone@1@@Z ?FromUDate@absl@@YA?AVTime@1@N@Z ?FromUniversal@absl@@YA?AVTime@1@_J@Z @@ -3579,6 +3551,7 @@ EXPORTS ?GetGrowthLeft@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ ?GetGrowthLeftLowerBound@CommonFields@container_internal@absl@@QEBA_KXZ ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -3770,7 +3743,7 @@ EXPORTS ?IsDataLoss@absl@@YA_NAEBVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NAEBVStatus@1@@Z ?IsDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z - ?IsDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsDestroyed@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsEmpty@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsEmptyOrDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsExternal@CordRep@cord_internal@absl@@QEBA_NXZ @@ -3798,7 +3771,7 @@ EXPORTS ?IsPermissionDenied@absl@@YA_NAEBVStatus@1@@Z ?IsPow2@CordBuffer@absl@@CA_N_K@Z ?IsReachable@GraphCycles@synchronization_internal@absl@@QEBA_NUGraphId@23@0@Z - ?IsReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ + ?IsReentrance@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsResourceExhausted@absl@@YA_NAEBVStatus@1@@Z ?IsRetired@CommandLineFlag@absl@@UEBA_NXZ ?IsSMTEnabled@base_internal@absl@@YA_NXZ @@ -3814,8 +3787,8 @@ EXPORTS ?IsUnimplemented@absl@@YA_NAEBVStatus@1@@Z ?IsUnknown@absl@@YA_NAEBVStatus@1@@Z ?IsUnprotectedReadCandidate@MaskedPointer@flags_internal@absl@@QEBA_NXZ - ?IsValid@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ ?IsValid@CordRepBtree@cord_internal@absl@@SA_NPEBV123@_N@Z + ?IsValid@HashtableCapacity@container_internal@absl@@QEBA_NXZ ?IsValidCapacity@container_internal@absl@@YA_N_K@Z ?IterateOverFullSlots@container_internal@absl@@YAXAEBVCommonFields@12@_KV?$FunctionRef@$$A6AXPEBW4ctrl_t@container_internal@absl@@PEAX@Z@2@@Z ?JoinMessageToStatus@StatusPrivateAccessorForStatusBuilder@status_internal@absl@@SA?AVStatus@3@V43@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@W4MessageJoinStyle@3@@Z @@ -3974,6 +3947,7 @@ EXPORTS ?NumClonedBytes@container_internal@absl@@YA_KXZ ?NumContextsPerCPU@base_internal@absl@@YAHXZ ?NumControlBytes@container_internal@absl@@YA_K_K@Z + ?NumControlBytesForLargeTable@container_internal@absl@@YA_K_K@Z ?NumGenerationBytes@container_internal@absl@@YA_KXZ ?NumLeakedFlagValues@flags_internal@absl@@YA_KXZ ?ODRCheck@CordzInfo@cord_internal@absl@@AEBAXXZ @@ -4026,9 +4000,9 @@ EXPORTS ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrecombineLengthMix@hash_internal@absl@@YA_K_K0@Z ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -4358,6 +4332,7 @@ EXPORTS ?TakeRep@Cord@absl@@AEHAAPEAUCordRep@cord_internal@2@XZ ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -4421,9 +4396,8 @@ EXPORTS ?ToInt64Nanoseconds@absl@@YA_JVDuration@1@@Z ?ToInt64Seconds@absl@@YA_JVDuration@1@@Z ?ToOpResult@CordRepBtree@cord_internal@absl@@AEAA?AUOpResult@123@_N@Z - ?ToPublicSeed@?$HashtableInlineDataImpl@$00@container_internal@absl@@CA_K_K@Z - ?ToRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBAEXZ ?ToRawData@GrowthInfoLowerBound@container_internal@absl@@QEBAEXZ + ?ToRawData@HashtableCapacity@container_internal@absl@@QEBAEXZ ?ToSinkAlso@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToSinkOnly@LogMessage@log_internal@absl@@QEAAAEAV123@PEAVLogSink@3@@Z ?ToString@?$BigUnsigned@$03@strings_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -4706,7 +4680,6 @@ EXPORTS ?__annotate_shrink_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_K0@Z ?__annotate_whole_block@?$deque@PEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z ?__annotate_whole_block@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AEBAX_KW4__asan_annotation_type@123@@Z - ?__as_base@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@IEGAA@XZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?__back_spare@?$__split_buffer_size_layout@V?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -4813,6 +4786,17 @@ EXPORTS ?__destruct_at_end@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransition@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUTransitionType@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@AEAAXPEAUViableSubstitution@strings_internal@absl@@@Z + ?__empty@?$__vector_layout@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVCordzHandle@cord_internal@absl@@V?$allocator@PEAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@PEBVCordzHandle@cord_internal@absl@@V?$allocator@PEBVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_NXZ + ?__empty@?$__vector_layout@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEAU1234@AEAU1234@PEAPEAU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PEBU1234@AEBU1234@PEBQEBU1234@_J$0A@@__Cr@std@@@__Cr@std@@SAPEBUPrefixCrc@CrcCordState@crc_internal@absl@@PEBQEAU4567@@Z ?__end_node@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAPEAV?$__tree_end_node@PEAV?$__tree_node_base@PEAX@__Cr@std@@@23@XZ @@ -5237,8 +5221,8 @@ EXPORTS ?begin@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?begin@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?begin@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?blocked_element_count@CommonFields@container_internal@absl@@QEBA_KXZ + ?blocked_element_count@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?btree@CordRep@cord_internal@absl@@QEAAPEAVCordRepBtree@23@XZ ?btree@CordRep@cord_internal@absl@@QEBAPEBVCordRepBtree@23@XZ ?btree@CordRepBtreeNavigator@cord_internal@absl@@QEBAPEAVCordRepBtree@23@XZ @@ -5246,8 +5230,6 @@ EXPORTS ?bucket_count@?$__hash_table@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEBA_KXZ ?bucket_count@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?bytes_value@ProtoField@log_internal@absl@@QEBA?AV?$Span@$$CBD@3@XZ - ?capacity@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_KXZ - ?capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QEBA_KXZ ?capacity@?$__split_buffer_size_layout@V?$__split_buffer@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@__Cr@std@@V__split_buffer_size_layout@45@@__Cr@std@@PEAVCommandLineFlag@absl@@V?$allocator@PEAVCommandLineFlag@absl@@@23@@__Cr@std@@QEBA_KXZ @@ -5276,7 +5258,9 @@ EXPORTS ?capacity@CommonFields@container_internal@absl@@QEBA_KXZ ?capacity@CordBuffer@absl@@QEBA_KXZ ?capacity@CordRepBtree@cord_internal@absl@@QEBA_KXZ - ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?capacity@HashtableCapacity@container_internal@absl@@QEBA_KXZ + ?capacity@HashtableInlineData@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ + ?capacity_impl@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?cbegin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ ?cbegin@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEBA?AV?$__wrap_iter@PEBQEAVLogSink@absl@@@23@XZ ?cend@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBAPEBUPayload@status_internal@2@XZ @@ -5439,8 +5423,8 @@ EXPORTS ?deallocate@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@PEAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@23@PEAVFormatArgImpl@str_format_internal@absl@@_K@Z ?deallocate@?$allocator_traits@V?$allocator@VSourceLocation@absl@@@__Cr@std@@@__Cr@std@@SAXAEAV?$allocator@VSourceLocation@absl@@@23@PEAVSourceLocation@absl@@_K@Z - ?decrement_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?decrement_size@CommonFields@container_internal@absl@@QEAAXXZ + ?decrement_size@HashtableInlineData@container_internal@absl@@QEAAXXZ ?delimiter@?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByAnyChar@3@XZ ?delimiter@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QEBAAEBVByChar@3@XZ @@ -5455,7 +5439,6 @@ EXPORTS ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ ?element@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@SAAEAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@__Cr@std@@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z ?emplace@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@CAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@@Z - ?empty@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?empty@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_NXZ ?empty@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QEBA_NXZ @@ -5480,6 +5463,7 @@ EXPORTS ?empty@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_NXZ ?empty@CommonFields@container_internal@absl@@QEBA_NXZ ?empty@Cord@absl@@QEBA_NXZ + ?empty@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?encoded_message@LogEntry@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?encoded_remaining@LogMessageData@LogMessage@log_internal@absl@@QEAAAEAV?$Span@D@4@XZ ?end@?$BitMask@I$0BA@$0A@$0A@@container_internal@absl@@QEBA?AV123@XZ @@ -5534,7 +5518,6 @@ EXPORTS ?end@CordRepBtree@cord_internal@absl@@QEBA_KXZ ?end@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBAPEADXZ ?end@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA?AU1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?eq_ref@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBAAEBUStringEq@23@XZ ?erase@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEAAPEAUPayload@status_internal@2@PEBU342@@Z ?erase@?$vector@PEAVLogSink@absl@@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QEAA?AV?$__wrap_iter@PEAPEAVLogSink@absl@@@23@V?$__wrap_iter@PEBQEAVLogSink@absl@@@23@@Z @@ -5558,8 +5541,8 @@ EXPORTS ?gbswap_16@absl@@YAGG@Z ?gbswap_32@absl@@YAII@Z ?gbswap_64@absl@@YA_K_K@Z - ?generate_new_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?generate_new_seed@CommonFields@container_internal@absl@@QEAAX_N@Z + ?generate_new_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ ?generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation@HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QEBAEXZ ?generation_offset@RawHashSetLayout@container_internal@absl@@QEBA_KXZ @@ -5611,10 +5594,8 @@ EXPORTS ?get@?$__temp_value@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransition@cctz@time_internal@absl@@XZ ?get@?$__temp_value@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransitionType@cctz@time_internal@absl@@XZ ?get@?$__tuple_leaf@$00AEAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@$$QEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAPEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AEAUFindInfo@container_internal@absl@@$0A@@__Cr@std@@QEAAAEAUFindInfo@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@AEBQEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEBQEAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@PEAVCommandLineFlag@absl@@$0A@@__Cr@std@@QEAAAEAPEAVCommandLineFlag@absl@@XZ ?get@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?get@?$unique_ptr@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$__allocator_destructor@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEBAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ @@ -5654,10 +5635,10 @@ EXPORTS ?get_soo_data@HeapOrSoo@container_internal@absl@@QEBAPEBXXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z ?get_yearday@detail@cctz@time_internal@absl@@YAHAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z - ?growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ + ?growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEBA?AVGrowthInfoLowerBound@23@XZ ?has_alt_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ - ?has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?has_infoz@CommonFields@container_internal@absl@@QEBA_NXZ + ?has_infoz@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?has_left_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBA_NXZ ?has_show_pos_flag@FormatConversionSpecImpl@str_format_internal@absl@@QEBA_NXZ @@ -5677,22 +5658,24 @@ EXPORTS ?hour@?$civil_time@Uhour_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?hour@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?increment_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?increment_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?increment_size@CommonFields@container_internal@absl@@QEAAXXZ ?increment_size@CommonFields@container_internal@absl@@QEAAX_K@Z + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?increment_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?index@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_KXZ ?index@?$probe_seq@$0BA@@container_internal@absl@@QEBA_KXZ + ?index@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_KXZ ?index@CordRepBtree@cord_internal@absl@@QEBA_KW4EdgeType@123@@Z ?infoz@CommonFields@container_internal@absl@@QEAA?AVHashtablezInfoHandle@23@XZ + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ - ?init_blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z ?init_blocked_element_count@CommonFields@container_internal@absl@@QEAAX_K@Z + ?init_blocked_element_count@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?inline_size@InlineData@cord_internal@absl@@QEBA_KXZ ?inline_size@InlineRep@Cord@absl@@AEBA_KXZ ?inline_size@Rep@InlineData@cord_internal@absl@@QEBA_KXZ - ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QEAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z + ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@56@@Z ?insert@?$unordered_set@PEBUCordRep@cord_internal@absl@@U?$hash@PEBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PEBUCordRep@cord_internal@absl@@@56@V?$allocator@PEBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QEAA?AU?$pair@V?$__hash_const_iterator@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@_N@23@AEBQEBUCordRep@cord_internal@absl@@@Z ?int32_value@ProtoField@log_internal@absl@@QEBAHXZ ?int64_value@ProtoField@log_internal@absl@@QEBA_JXZ @@ -5707,13 +5690,13 @@ EXPORTS ?is_length@ConvTag@str_format_internal@absl@@QEBA_NXZ ?is_profiled@InlineData@cord_internal@absl@@QEBA_NXZ ?is_relative_timeout@KernelTimeout@synchronization_internal@absl@@QEBA_NXZ - ?is_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ + ?is_sampled_seed@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_short@Rep@CordBuffer@absl@@QEBA_NXZ ?is_single_group@container_internal@absl@@YA_N_K@Z - ?is_small@?$HashtableCapacityImpl@$00@container_internal@absl@@QEBA_NXZ - ?is_small@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_NXZ ?is_small@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_small@CommonFields@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableCapacity@container_internal@absl@@QEBA_NXZ + ?is_small@HashtableInlineData@container_internal@absl@@QEBA_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QEBA_NXZ ?is_soo@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA_NXZ ?is_tree@InlineData@cord_internal@absl@@QEBA_NXZ @@ -5772,8 +5755,8 @@ EXPORTS ?max_size@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QEBA_KXZ ?max_size@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEBA_KXZ ?maybe_increment_generation_on_insert@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXXZ - ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AV?$HashtableCapacityImpl@$00@23@XZ - ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AV?$HashtableCapacityImpl@$00@23@XZ + ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEBA?AVHashtableCapacity@23@XZ + ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QEBA?AVHashtableCapacity@23@XZ ?memcasecmp@strings_internal@absl@@YAHPEBD0_K@Z ?message@Status@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?message@StatusRep@status_internal@absl@@QEBAAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -5805,10 +5788,10 @@ EXPORTS ?ok@Status@absl@@QEBA_NXZ ?ok@Utf8ForCodePoint@debugging_internal@absl@@QEBA_NXZ ?overflow@Streambuf@OStringStream@strings_internal@absl@@MEAAHH@Z - ?overwrite_control_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXW4ctrl_t@23@@Z - ?overwrite_empty_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_deleted@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?overwrite_full_as_empty_in_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?overwrite_control_as_full@HashtableInlineData@container_internal@absl@@QEAAXW4ctrl_t@23@@Z + ?overwrite_empty_as_full@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_deleted@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?overwrite_full_as_empty_in_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXXZ ?parse@detail@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0AEBVtime_zone@234@PEAV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@PEAV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@chrono@67@PEAV567@@Z ?parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QEBAPEBVParsedFormatBase@23@XZ ?pointer_to@?$pointer_traits@PEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAPEAU?$__hash_node_base@PEAU?$__hash_node@PEBUCordRep@cord_internal@absl@@PEAX@__Cr@std@@@23@AEAU423@@Z @@ -5851,6 +5834,7 @@ EXPORTS ?push_back@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUTransition@cctz@time_internal@absl@@@Z ?push_back@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXAEBUUnrecognizedFlag@absl@@@Z ?raw_code@Status@absl@@QEBAHXZ + ?read_byte@HashtableInlineData@container_internal@absl@@AEBAE_K@Z ?reduce_size@InlineRep@Cord@absl@@QEAAX_K@Z ?release@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ ?release@?$unique_ptr@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QEAAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@XZ @@ -5894,6 +5878,7 @@ EXPORTS ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QEAAXPEAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PEAX@23@@Z ?reset@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagState@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagStateInterface@flags_internal@absl@@@Z ?reset@?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -5919,17 +5904,19 @@ EXPORTS ?scale_add@impl@detail@cctz@time_internal@absl@@YA_J_J00@Z ?second@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ ?second@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QEBAHXZ - ?seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@CommonFields@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ + ?seed@HashtableInlineData@container_internal@absl@@QEBA?AVPerTableSeed@23@XZ ?seed@PerTableSeed@container_internal@absl@@QEBA_KXZ ?set@?$MaybeInitializedPtr@W4ctrl_t@container_internal@absl@@@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_arg@BoundConversion@str_format_internal@absl@@QEAAXPEBVFormatArgImpl@23@@Z ?set_begin@CordRepBtree@cord_internal@absl@@AEAAX_K@Z - ?set_blocked_element_count_to_zero@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ ?set_blocked_element_count_to_zero@CommonFields@container_internal@absl@@QEAAXXZ - ?set_capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z - ?set_capacity@CommonFields@container_internal@absl@@QEAAXV?$HashtableCapacityImpl@$00@23@@Z + ?set_blocked_element_count_to_zero@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_capacity@CommonFields@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z ?set_capacity@CommonFields@container_internal@absl@@QEAAX_K@Z + ?set_capacity@CommonFields@container_internal@absl@@QECAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QEAAXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QECAXVHashtableCapacity@23@@Z ?set_control@CommonFields@container_internal@absl@@QEAAXPEAW4ctrl_t@23@@Z ?set_conversion_char@FormatConversionSpecImpl@str_format_internal@absl@@QEAAXW4FormatConversionChar@3@@Z ?set_cordz_info@InlineData@cord_internal@absl@@QEAAXPEAVCordzInfo@23@@Z @@ -5943,9 +5930,9 @@ EXPORTS ?set_full_soo@CommonFields@container_internal@absl@@QEAAXXZ ?set_generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXE@Z ?set_generation_ptr@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAXPEAE@Z - ?set_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z - ?set_has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ + ?set_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QEAAXVGrowthInfoLowerBound@23@@Z ?set_has_infoz@CommonFields@container_internal@absl@@QEAAXXZ + ?set_has_infoz@HashtableInlineData@container_internal@absl@@QEAAXXZ ?set_infoz@CommonFields@container_internal@absl@@QEAAXVHashtablezInfoHandle@23@@Z ?set_inline_data@InlineData@cord_internal@absl@@QEAAXPEBD_K@Z ?set_inline_size@InlineData@cord_internal@absl@@QEAAX_K@Z @@ -5953,10 +5940,10 @@ EXPORTS ?set_inline_size@Rep@InlineData@cord_internal@absl@@QEAAX_K@Z ?set_reservation_size@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z ?set_reserved_growth@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QEAAX_K@Z - ?set_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAXXZ - ?set_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@AEAAXE@Z + ?set_sampled_seed@HashtableInlineData@container_internal@absl@@QEAAXXZ + ?set_seed@HashtableInlineData@container_internal@absl@@AEAAXE@Z ?set_short_length@Rep@CordBuffer@absl@@QEAAX_K@Z - ?set_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEAAX_K@Z + ?set_size@HashtableInlineData@container_internal@absl@@QEAAX_K@Z ?set_size_to_zero@CommonFields@container_internal@absl@@QEAAXXZ ?set_tag@Rep@InlineData@cord_internal@absl@@QEAAXC@Z ?set_tree@InlineData@cord_internal@absl@@QEAAXPEAUCordRep@23@@Z @@ -5969,11 +5956,11 @@ EXPORTS ?shrink_to_fit@?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXXZ ?single_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@123@XZ + ?single_non_soo_slot@CommonFields@container_internal@absl@@QEBAPEAXXZ ?single_slot@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@XZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QEBAHXZ ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?size@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ - ?size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAUCordRep@cord_internal@absl@@$01V?$allocator@PEAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@absl@@QEBA_KXZ ?size@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QEBA_KXZ @@ -6018,6 +6005,7 @@ EXPORTS ?size@CommonFields@container_internal@absl@@QEBA_KXZ ?size@Cord@absl@@QEBA_KXZ ?size@CordRepBtree@cord_internal@absl@@QEBA_KXZ + ?size@HashtableInlineData@container_internal@absl@@QEBA_KXZ ?size@InlineRep@Cord@absl@@QEBA_KXZ ?size@Storage@?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEBA_KXZ ?skip_empty_or_deleted@iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXXZ @@ -6067,7 +6055,7 @@ EXPORTS ?timestamp@LogEntry@absl@@QEBA?AVTime@2@XZ ?total_written@BufferRawSink@str_format_internal@absl@@QEBA_KXZ ?transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAAXPEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@23@0@Z - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?tree@InlineRep@Cord@absl@@QEBAPEAUCordRep@cord_internal@3@XZ ?tree@Rep@InlineData@cord_internal@absl@@QEBAPEAUCordRep@34@XZ ?try_lock@Mutex@absl@@QEAA_NXZ @@ -6086,8 +6074,6 @@ EXPORTS ?value@InputValue@UnboundConversion@str_format_internal@absl@@QEBAHXZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QEAAAEAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PEBVCommandLineFlag@absl@@V?$allocator@PEBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ - ?valueless_by_exception@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QEBA_NXZ - ?valueless_by_exception@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QEBA_NXZ ?verbosity@LogEntry@absl@@QEBAHXZ ?version@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?what@BadStatusOrAccess@absl@@UEBAPEBDXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x64_rel.def b/deps/v8/third_party/abseil-cpp/symbols_x64_rel.def index 09e82a473640..0df77f662366 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x64_rel.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x64_rel.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QEAA@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$?6C@LogMessage@log_internal@absl@@QEAAAEAV012@AEBC@Z @@ -22,8 +21,8 @@ EXPORTS ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEAPEAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEBQEAVCommandLineFlag@3@@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CC@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CG@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CG@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CH@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CH@$$CBD@Z @@ -41,6 +40,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QEAP8FlagImpl@flags_internal@1@EAAXXZ$$QEAPEAV671@@Z @@ -105,6 +108,8 @@ EXPORTS ??$EmplaceBackSlow@AEBQEAVLogSink@absl@@@?$Storage@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAPEAVLogSink@2@AEBQEAV32@@Z ??$EmplaceBackSlow@AEBVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAVSourceLocation@2@AEBV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -114,11 +119,10 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHAEBVCord@0@0_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$MakeCheckOpString@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@DD@log_internal@absl@@YAPEBDDDPEBD@Z @@ -224,8 +228,9 @@ EXPORTS ??$emplace_front@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$emplace_front@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QEAAX$$QEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@XZ ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@_K@Z @@ -304,7 +309,6 @@ EXPORTS ??0uint128@absl@@QEAA@O@Z ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1CRC@crc_internal@absl@@UEAA@XZ ??1Clock@absl@@UEAA@XZ ??1Cord@absl@@QEAA@XZ @@ -324,6 +328,7 @@ EXPORTS ??1Mutex@absl@@QEAA@XZ ??1Notification@absl@@QEAA@XZ ??1OstreamView@LogMessage@log_internal@absl@@UEAA@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ ??1ScopedMinLogLevel@log_internal@absl@@QEAA@XZ ??1ScopedStderrThreshold@absl@@QEAA@XZ @@ -373,7 +378,6 @@ EXPORTS ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ??BStatusBuilder@absl@@QEGBA?AVStatus@1@XZ - ??BStatusBuilder@absl@@QEHAA?AVStatus@1@XZ ??Bint128@absl@@QEBANXZ ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??Eiterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAAAEAV0123@XZ @@ -411,6 +415,7 @@ EXPORTS ??_0Duration@absl@@QEAAAEAV01@N@Z ??_0Duration@absl@@QEAAAEAV01@_J@Z ??_1Duration@absl@@QEAAAEAV01@V01@@Z + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAEAVStatusBuilder@1@W4StatusCode@1@@Z @@ -465,6 +470,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPEAX_K@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z @@ -489,7 +495,9 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -564,7 +572,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NNAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?CopyCordToSpan@absl@@YA_KAEBVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXAEBVCord@1@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AEAA?AUCopyResult@123@_K_N@Z @@ -572,6 +580,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@AEBAXPEAD@Z ?Crash@Helper@internal_statusor@absl@@SAXAEBVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPEAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -579,6 +588,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPEAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@AEBAAEAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -661,6 +672,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@_K@Z @@ -700,7 +712,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -796,6 +807,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPEAUCordRep@cord_internal@2@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -1024,9 +1036,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -1224,6 +1236,7 @@ EXPORTS ?Symbolize@absl@@YA_NPEBXPEADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1393,13 +1406,13 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@AEBV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV567@AEBV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@AEBV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@AEBVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEAMW4chars_format@1@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEANW4chars_format@1@@Z ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEAVtime_zone@123@@Z @@ -1420,6 +1433,7 @@ EXPORTS ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?resize@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?resize@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?safe_strto128_base@numbers_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVint128@2@H@Z @@ -1442,7 +1456,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?status@BadStatusOrAccess@absl@@QEBAAEBVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QEAAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?try_lock@Mutex@absl@@QEAA_NXZ ?try_lock_shared@Mutex@absl@@QEAA_NXZ ?unlock@Mutex@absl@@QEAAXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan.def b/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan.def index 6382393a1120..1fe19acce6f6 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QEAA@XZ ??$?0$$V$0A@@?$NoDestructor@VFlagRegistry@flags_internal@absl@@@absl@@QEAA@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z @@ -40,6 +39,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QEAP8FlagImpl@flags_internal@1@EAAXXZ$$QEAPEAV671@@Z @@ -104,6 +107,8 @@ EXPORTS ??$EmplaceBackSlow@AEBQEAVLogSink@absl@@@?$Storage@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAPEAVLogSink@2@AEBQEAV32@@Z ??$EmplaceBackSlow@AEBVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAVSourceLocation@2@AEBV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -113,10 +118,10 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHAEBVCord@0@0_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z ??$MakeCheckOpString@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PEBD@Z @@ -186,8 +191,6 @@ EXPORTS ??$StrCat@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$BY0BO@DV123@@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBVAlphaNum@0@0000AEBV123@AEAY0BO@$$CBD1@Z ??$StrCat@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$BY0LD@D@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBVAlphaNum@0@0000AEBV123@AEAY0LD@$$CBD@Z ??$StrReplaceAll@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@absl@@YAHAEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@2@@Z - ??$StrSplit@VByAnyChar@absl@@@absl@@YA?AV?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@0@VConvertibleToStringView@20@VByAnyChar@0@@Z - ??$StrSplit@VByAnyChar@absl@@USkipEmpty@2@@absl@@YA?AV?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@0@VConvertibleToStringView@20@VByAnyChar@0@USkipEmpty@0@@Z ??$StringResizeAndOverwriteFallback@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV123@H@Z@@strings_internal@absl@@YAXAEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@_KV<lambda_1>@?0???$IntegerToString@H@01@YA?AV234@H@Z@@Z ??$StringResizeAndOverwriteFallback@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV123@I@Z@@strings_internal@absl@@YAXAEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@_KV<lambda_1>@?0???$IntegerToString@I@01@YA?AV234@I@Z@@Z ??$StringResizeAndOverwriteFallback@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV123@J@Z@@strings_internal@absl@@YAXAEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@_KV<lambda_1>@?0???$IntegerToString@J@01@YA?AV234@J@Z@@Z @@ -255,9 +258,9 @@ EXPORTS ??$emplace_front@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QEAAX$$QEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@XZ @@ -340,7 +343,6 @@ EXPORTS ??1?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAA@XZ ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1CRC@crc_internal@absl@@UEAA@XZ ??1Clock@absl@@UEAA@XZ ??1Cord@absl@@QEAA@XZ @@ -360,6 +362,7 @@ EXPORTS ??1Mutex@absl@@QEAA@XZ ??1Notification@absl@@QEAA@XZ ??1OstreamView@LogMessage@log_internal@absl@@UEAA@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ ??1ScopedMinLogLevel@log_internal@absl@@QEAA@XZ ??1ScopedStderrThreshold@absl@@QEAA@XZ @@ -410,7 +413,6 @@ EXPORTS ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ??BStatusBuilder@absl@@QEGBA?AVStatus@1@XZ - ??BStatusBuilder@absl@@QEHAA?AVStatus@1@XZ ??Bint128@absl@@QEBANXZ ??E?$SplitIterator@V?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@strings_internal@absl@@QEAAAEAV012@XZ ??E?$SplitIterator@V?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@strings_internal@absl@@QEAAAEAV012@XZ @@ -446,6 +448,7 @@ EXPORTS ??_0Duration@absl@@QEAAAEAV01@N@Z ??_0Duration@absl@@QEAAAEAV01@_J@Z ??_1Duration@absl@@QEAAAEAV01@V01@@Z + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAEAVStatusBuilder@1@W4StatusCode@1@@Z @@ -500,6 +503,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPEAX_K@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z @@ -523,11 +527,12 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ - ?AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QEBAXVFastTypeIdType@3@P6APEBVtype_info@@XZ@Z ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z @@ -598,7 +603,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NMAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NNAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?CopyCordToSpan@absl@@YA_KAEBVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXAEBVCord@1@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AEAA?AUCopyResult@123@_K_N@Z @@ -606,6 +611,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@AEBAXPEAD@Z ?Crash@Helper@internal_statusor@absl@@SAXAEBVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPEAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -613,6 +619,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPEAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@AEBAAEAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -695,6 +703,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@_K@Z @@ -734,7 +743,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -829,6 +837,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPEAUCordRep@cord_internal@2@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -1059,9 +1068,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -1259,6 +1268,7 @@ EXPORTS ?Symbolize@absl@@YA_NPEBXPEADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1439,7 +1449,6 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@AEBV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV567@AEBV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@AEBV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@AEBVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEAMW4chars_format@1@@Z @@ -1447,6 +1456,7 @@ EXPORTS ?front@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransition@cctz@time_internal@absl@@XZ ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEAVtime_zone@123@@Z @@ -1495,7 +1505,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?status@BadStatusOrAccess@absl@@QEBAAEBVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QEAAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?try_lock@Mutex@absl@@QEAA_NXZ ?try_lock_shared@Mutex@absl@@QEAA_NXZ ?unlock@Mutex@absl@@QEAAXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan_cxx23.def index 7bed4c6322d9..956a33d5206e 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x64_rel_asan_cxx23.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QEAA@XZ ??$?0$$V$0A@@?$NoDestructor@VFlagRegistry@flags_internal@absl@@@absl@@QEAA@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z @@ -40,6 +39,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QEAP8FlagImpl@flags_internal@1@EAAXXZ$$QEAPEAV671@@Z @@ -104,6 +107,8 @@ EXPORTS ??$EmplaceBackSlow@AEBQEAVLogSink@absl@@@?$Storage@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAPEAVLogSink@2@AEBQEAV32@@Z ??$EmplaceBackSlow@AEBVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAVSourceLocation@2@AEBV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -113,10 +118,10 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHAEBVCord@0@0_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z ??$MakeCheckOpString@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PEBD@Z @@ -186,8 +191,6 @@ EXPORTS ??$StrCat@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$BY0BO@DV123@@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBVAlphaNum@0@0000AEBV123@AEAY0BO@$$CBD1@Z ??$StrCat@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$BY0LD@D@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBVAlphaNum@0@0000AEBV123@AEAY0LD@$$CBD@Z ??$StrReplaceAll@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@absl@@YAHAEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@2@@Z - ??$StrSplit@VByAnyChar@absl@@@absl@@YA?AV?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@0@VConvertibleToStringView@20@VByAnyChar@0@@Z - ??$StrSplit@VByAnyChar@absl@@USkipEmpty@2@@absl@@YA?AV?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@0@VConvertibleToStringView@20@VByAnyChar@0@USkipEmpty@0@@Z ??$TransferNRelocatable@$0BI@@container_internal@absl@@YAXPEAX00_K@Z ??$TryFindNewIndexWithoutProbing@X@container_internal@absl@@YA_K_K00PEAW4ctrl_t@01@0@Z ??$TypeErasedApplyToSlotFn@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@YA_KPEBXPEAX_K@Z @@ -248,9 +251,9 @@ EXPORTS ??$emplace_front@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QEAAX$$QEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$resize_and_overwrite@V<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@@?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@QEAAX_KV<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV012@H@Z@@Z ??$resize_and_overwrite@V<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@@?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@QEAAX_KV<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV012@I@Z@@Z ??$resize_and_overwrite@V<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@@?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@QEAAX_KV<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV012@J@Z@@Z @@ -340,7 +343,6 @@ EXPORTS ??1?$FixedArray@D$0?0V?$allocator@D@__Cr@std@@@absl@@QEAA@XZ ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1CRC@crc_internal@absl@@UEAA@XZ ??1Clock@absl@@UEAA@XZ ??1Cord@absl@@QEAA@XZ @@ -360,6 +362,7 @@ EXPORTS ??1Mutex@absl@@QEAA@XZ ??1Notification@absl@@QEAA@XZ ??1OstreamView@LogMessage@log_internal@absl@@UEAA@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ ??1ScopedMinLogLevel@log_internal@absl@@QEAA@XZ ??1ScopedStderrThreshold@absl@@QEAA@XZ @@ -410,7 +413,6 @@ EXPORTS ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ??BStatusBuilder@absl@@QEGBA?AVStatus@1@XZ - ??BStatusBuilder@absl@@QEHAA?AVStatus@1@XZ ??Bint128@absl@@QEBANXZ ??E?$SplitIterator@V?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@strings_internal@absl@@QEAAAEAV012@XZ ??E?$SplitIterator@V?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@strings_internal@absl@@QEAAAEAV012@XZ @@ -446,6 +448,7 @@ EXPORTS ??_0Duration@absl@@QEAAAEAV01@N@Z ??_0Duration@absl@@QEAAAEAV01@_J@Z ??_1Duration@absl@@QEAAAEAV01@V01@@Z + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAEAVStatusBuilder@1@W4StatusCode@1@@Z @@ -500,6 +503,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPEAX_K@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z @@ -523,11 +527,12 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ - ?AssertSameContainer@container_internal@absl@@YAXAEBQEBW4ctrl_t@12@0PEBX1PEBE2@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QEBAXVFastTypeIdType@3@P6APEBVtype_info@@XZ@Z ?AssignLargeString@Cord@absl@@AEAAAEAV12@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AssignSlow@InlineRep@Cord@absl@@AEAAXAEBV123@@Z @@ -598,7 +603,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NMAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NNAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?CopyCordToSpan@absl@@YA_KAEBVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXAEBVCord@1@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AEAA?AUCopyResult@123@_K_N@Z @@ -606,6 +611,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@AEBAXPEAD@Z ?Crash@Helper@internal_statusor@absl@@SAXAEBVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPEAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -613,6 +619,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPEAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@AEBAAEAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -695,6 +703,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@_K@Z @@ -734,7 +743,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -829,6 +837,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPEAUCordRep@cord_internal@2@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -1059,9 +1068,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -1259,6 +1268,7 @@ EXPORTS ?Symbolize@absl@@YA_NPEBXPEADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1439,7 +1449,6 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@AEBV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV567@AEBV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@AEBV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@AEBVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEAMW4chars_format@1@@Z @@ -1447,6 +1456,7 @@ EXPORTS ?front@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAAEAUTransition@cctz@time_internal@absl@@XZ ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEAVtime_zone@123@@Z @@ -1495,7 +1505,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?status@BadStatusOrAccess@absl@@QEBAAEBVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QEAAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?try_lock@Mutex@absl@@QEAA_NXZ ?try_lock_shared@Mutex@absl@@QEAA_NXZ ?unlock@Mutex@absl@@QEAAXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x64_rel_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_x64_rel_cxx23.def index 6b4c8061d073..ab838b3b755f 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x64_rel_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x64_rel_cxx23.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QEAA@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAA@$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$?6C@LogMessage@log_internal@absl@@QEAAAEAV012@AEBC@Z @@ -22,8 +21,8 @@ EXPORTS ??$?6_N@LogMessage@log_internal@absl@@QEAAAEAV012@AEB_N@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NAEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBUpiecewise_construct_t@12@V?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QEAPEAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@AEBUpiecewise_construct_t@56@$$QEAV?$tuple@$$QEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QEAV?$tuple@$$QEAPEAVCommandLineFlag@absl@@@56@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEAPEAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QEAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEBA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QEBV756@$$QEBQEAVCommandLineFlag@3@@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CC@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CG@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CG@$$CBD@Z ??$?RW4LogSeverity@absl@@AEBQEBDHAEAY0CH@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PEBDHAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QEBAX$$QEAW4LogSeverity@2@AEBQEBD$$QEAHAEAY0CH@$$CBD@Z @@ -41,6 +40,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QEAAX$$QEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@AEBVCord@absl@@@Cord@absl@@AEAAXAEBV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AEAAX$$QEAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NAEBQEBW4ctrl_t@01@0PEBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBEPEBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@PEBXEPEBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXAEBQEBW4ctrl_t@01@0PEBX1PEBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QEAAXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PEBVSourceLocation@absl@@@12@_K@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@EAAXXZPEAV123@@base_internal@absl@@YAXPEAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QEAP8FlagImpl@flags_internal@1@EAAXXZ$$QEAPEAV671@@Z @@ -105,6 +108,8 @@ EXPORTS ??$EmplaceBackSlow@AEBQEAVLogSink@absl@@@?$Storage@PEAVLogSink@absl@@$0BA@V?$allocator@PEAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAPEAVLogSink@2@AEBQEAV32@@Z ??$EmplaceBackSlow@AEBVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAVSourceLocation@2@AEBV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AEAAAEAUPayload@status_internal@2@$$QEAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@AEBA?AVCharIterator@01@V201@AEBV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@AEBV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEAXW4FlagOp@01@PEBXPEAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPEAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -114,11 +119,10 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPEBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHAEBVCord@0@0_K@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NAEBVCord@0@0_K@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@V?$FunctionRef@$$A6A_K_K@Z@1@_N@Z - ??$InvokeObject@AEAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@_K_K@functional_internal@absl@@YA_KTVoidPtr@01@_K@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$07$00@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPEAXAEAVCommonFields@01@AEBUPolicyFunctions@01@PEAXP6A_K2_K@Z_N@Z ??$MakeCheckOpString@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AEBV123@@log_internal@absl@@YAPEBDAEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PEBD@Z ??$MakeCheckOpString@DD@log_internal@absl@@YAPEBDDDPEBD@Z @@ -223,9 +227,10 @@ EXPORTS ??$emplace_front@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PEAPEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QEAAX$$QEAPEAPEBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$emplace_front@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PEAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QEAAX$$QEAPEAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QEAA?AV?$__hash_iterator@PEAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PEAX@__Cr@std@@@12@AEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@AEBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AEAA?AU?$pair@PEAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$resize_and_overwrite@V<lambda_1>@?0???$JoinAlgorithm@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@56@0V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@UNoFormatter@23@@Z@@?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@QEAAX_KV<lambda_1>@?0???$JoinAlgorithm@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV012@V?$__wrap_iter@PEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@1V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@UNoFormatter@45@@Z@@Z + ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@34@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QEAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YA_KUStructuredProtoField@45@@Z@AEAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@XZ ??0?$BigUnsigned@$03@strings_internal@absl@@QEAA@_K@Z @@ -304,7 +309,6 @@ EXPORTS ??0uint128@absl@@QEAA@O@Z ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QEAA@XZ ??1CRC@crc_internal@absl@@UEAA@XZ ??1Clock@absl@@UEAA@XZ ??1Cord@absl@@QEAA@XZ @@ -324,6 +328,7 @@ EXPORTS ??1Mutex@absl@@QEAA@XZ ??1Notification@absl@@QEAA@XZ ??1OstreamView@LogMessage@log_internal@absl@@UEAA@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QEAA@XZ ??1Rep@StatusBuilder@absl@@QEAA@XZ ??1ScopedMinLogLevel@log_internal@absl@@QEAA@XZ ??1ScopedStderrThreshold@absl@@QEAA@XZ @@ -373,7 +378,6 @@ EXPORTS ??ACord@absl@@QEBAD_K@Z ??BCord@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ??BStatusBuilder@absl@@QEGBA?AVStatus@1@XZ - ??BStatusBuilder@absl@@QEHAA?AVStatus@1@XZ ??Bint128@absl@@QEBANXZ ??EChunkIterator@Cord@absl@@QEAAAEAV012@XZ ??Eiterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QEAAAEAV0123@XZ @@ -411,6 +415,7 @@ EXPORTS ??_0Duration@absl@@QEAAAEAV01@N@Z ??_0Duration@absl@@QEAAAEAV01@_J@Z ??_1Duration@absl@@QEAAAEAV01@V01@@Z + ??_EClock@absl@@UEAAPEAXI@Z ??_ECordzHandle@cord_internal@absl@@MEAAPEAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPEAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAEAVStatusBuilder@1@W4StatusCode@1@@Z @@ -465,6 +470,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPEAX_K@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPEAX_KPEAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPEBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AEAAXAEAV123@AEBUPolicyFunctions@23@@Z ?Append@Cord@absl@@QEAAX$$QEAV12@@Z ?Append@Cord@absl@@QEAAXAEBV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPEAV123@PEAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@_K@Z @@ -489,7 +495,9 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPEADPEBD_K@Z ?AsciiStrToUpper@absl@@YAXPEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPEADPEBD_K@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAEAVCommonFields@12@PEBXP6A_K1PEAX_K@Z3_N31P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QEBAXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@AEBAXXZ ?AssertNotHeld@Mutex@absl@@QEBAXXZ ?AssertReaderHeld@Mutex@absl@@QEBAXXZ @@ -564,7 +572,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NNAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOAEBVFormatConversionSpecImpl@12@PEAVFormatSinkImpl@12@@Z ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QEAA_NAEBUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@V?$FunctionRef@$$A6AXPEAXPEBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAEAVCommonFields@12@AEBUPolicyFunctions@12@AEBV312@P6AXPEAX3PEBX@Z@Z ?CopyCordToSpan@absl@@YA_KAEBVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXAEBVCord@1@PEAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AEAA?AUCopyResult@123@_K_N@Z @@ -572,6 +580,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@AEBAXPEAD@Z ?Crash@Helper@internal_statusor@absl@@SAXAEBVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPEAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@_K00_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPEAV123@PEAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPEAUThreadIdentity@base_internal@2@XZ @@ -579,6 +588,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPEAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@AEBAAEAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QEAA_NPEAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPEADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -661,6 +672,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QEBA?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UEBAXPEAIPEBX_K@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UEBAXPEAIPEIAXPEIBX_K_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UEBAXPEAI_K@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPEAI_KQEBI2@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@_K@Z @@ -700,7 +712,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPEAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QEAAPEAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QEBA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@AEBA?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QEBAHUGraphId@23@0HQEAU423@@Z @@ -796,6 +807,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPEAUCordRep@cord_internal@2@PEAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QEBA_K_K@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SA_KPEAX_K@Z ?GetHashtablezMaxSamples@container_internal@absl@@YA_KXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QEAA?AUGraphId@23@PEAX@Z @@ -1024,9 +1036,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QEAAXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QEAAXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QEAAX_J_K11G@Z - ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@_KV?$NonIterableBitMask@I$0BA@$0A@@12@2V?$FunctionRef@$$A6A_K_K@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPEAXAEAVCommonFields@12@AEBUPolicyFunctions@12@PEAXP6A_K2_K@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AEAAXXZ ?PrepareToModify@Status@absl@@CAPEAVStatusRep@status_internal@2@_K@Z ?Prepend@Cord@absl@@QEAAXAEBV12@@Z @@ -1224,6 +1236,7 @@ EXPORTS ?Symbolize@absl@@YA_NPEBXPEADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QEAAXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QEAAX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1393,13 +1406,13 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QEBA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@AEBAAEBVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PEIAXPEIBX_KV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@AEBV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AEBV567@AEBV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@AEBV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@AEBVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEAMW4chars_format@1@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PEBD0AEANW4chars_format@1@@Z ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@AEBV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@PEAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QEBA?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NAEBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PEAVtime_zone@123@@Z @@ -1420,6 +1433,7 @@ EXPORTS ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?reserve@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAXPEAVFlagSaverImpl@flags_internal@absl@@@Z ?resize@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?resize@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QEAAX_K@Z ?safe_strto128_base@numbers_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVint128@2@H@Z @@ -1442,7 +1456,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QEBAHXZ ?status@BadStatusOrAccess@absl@@QEBAAEBVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QEAAAEAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2P6AX2E_K3@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PEAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAEAVCommonFields@23@PEBW4ctrl_t@23@PEAX2_KP6AX233@Z@Z ?try_lock@Mutex@absl@@QEAA_NXZ ?try_lock_shared@Mutex@absl@@QEAA_NXZ ?unlock@Mutex@absl@@QEAAXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x86_dbg.def b/deps/v8/third_party/abseil-cpp/symbols_x86_dbg.def index 800e14885a45..fda898510b76 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x86_dbg.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x86_dbg.def @@ -1,20 +1,13 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4HA ??$?0$$CBD$0A@@VoidPtr@str_format_internal@absl@@QAE@PBD@Z ??$?0$$CBU?$atomic@_N@__Cr@std@@@Condition@absl@@QAE@P6A_NPBU?$atomic@_N@__Cr@std@@@Z0@Z ??$?0$$CBUCordRep@cord_internal@absl@@@Hex@absl@@QAE@PBUCordRep@cord_internal@1@W4PadSpec@1@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QAPAVCommandLineFlag@absl@@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QBQAVCommandLineFlag@absl@@@Z ??$?0$$CBVFormatArgImpl@str_format_internal@absl@@$$CBV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QAE@V?$initializer_list@VFormatArgImpl@str_format_internal@absl@@@std@@@Z ??$?0$$CB_W$0A@@VoidPtr@str_format_internal@absl@@QAE@PB_W@Z ??$?0$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AAV?$tuple@$$V@12@U?$__integer_sequence@I$0A@@12@U?$__integer_sequence@I$S@12@@Z ??$?0$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z ??$?0$$T@?$Storage@PAPAUCordRep@cord_internal@absl@@$00U?$StorageTag@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@PAPAUCordRep@cord_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@$$QA$$T@Z ??$?0$$T@?$Storage@PAPAVLogSink@absl@@$00U?$StorageTag@V?$allocator@PAVLogSink@absl@@@__Cr@std@@PAPAVLogSink@absl@@@internal_compressed_tuple@container_internal@2@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@$$QA$$T@Z ??$?0$$T@?$Storage@PAUPayload@status_internal@absl@@$00U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@PAUPayload@status_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@$$QA$$T@Z @@ -35,7 +28,6 @@ EXPORTS ??$?0$$V@PlacementImpl@?$NoDestructor@VMutex@absl@@@absl@@QAE@XZ ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AAPAVCommandLineFlag@absl@@AA_N@__Cr@std@@QAE@AAPAVCommandLineFlag@absl@@AA_N@Z ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@QAE@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@45@@Z - ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@ABQAVCommandLineFlag@absl@@@__Cr@std@@QAE@ABQAVCommandLineFlag@absl@@@Z ??$?0AAI@?$Storage@I$0A@U?$StorageTag@IV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@AAI@Z ??$?0AAIABV?$allocator@D@__Cr@std@@$00@?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@QAE@AAIABV?$allocator@D@__Cr@std@@@Z ??$?0AAIABV?$allocator@D@__Cr@std@@@?$CompressedTupleImpl@V?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@U?$integer_sequence@I$0A@$00@__Cr@std@@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@AAIABV?$allocator@D@56@@Z @@ -67,8 +59,6 @@ EXPORTS ??$?0AAVCord@absl@@@?$__optional_destruct_base@VCord@absl@@$0A@@__Cr@std@@QAE@Uin_place_t@12@AAVCord@absl@@@Z ??$?0AAY0BM@$$CBD$0A@@?$NoDestructor@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@absl@@QAE@AAY0BM@$$CBD@Z ??$?0AAY0BM@$$CBD@PlacementImpl@?$NoDestructor@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@absl@@QAE@AAY0BM@$$CBD@Z - ??$?0ABQAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@ABQAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAE@ABQAVCommandLineFlag@absl@@@Z - ??$?0ABQAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@I$0A@@__Cr@std@@ABQAVCommandLineFlag@absl@@@__Cr@std@@QAE@U__forward_args@12@ABQAVCommandLineFlag@absl@@@Z ??$?0ABV?$allocator@D@__Cr@std@@@?$Storage@V?$allocator@D@__Cr@std@@$00U?$StorageTag@IV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@ABV?$allocator@D@56@@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$0A@U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@ABV?$allocator@UPayload@status_internal@absl@@@56@@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I@container_internal@absl@@QAE@ABV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$$QAI@Z @@ -80,8 +70,6 @@ EXPORTS ??$?0ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AAV?$tuple@$$V@12@U?$__integer_sequence@I$0A@@12@U?$__integer_sequence@I$S@12@@Z ??$?0ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z ??$?0ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZABQAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@ABQAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZABQAVCommandLineFlag@absl@@@?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@Z ??$?0D@?$allocator@U?$AlignedType@$03@container_internal@absl@@@__Cr@std@@QAE@ABV?$allocator@D@12@@Z ??$?0D@?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAE@ABV?$allocator@D@12@@Z ??$?0D@FormatArgImpl@str_format_internal@absl@@QAE@ABD@Z @@ -107,15 +95,10 @@ EXPORTS ??$?0PAUTransitionType@cctz@time_internal@absl@@$0A@@?$__wrap_iter@PBUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QAE@ABV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0PAUTransitionType@cctz@time_internal@absl@@PAU0123@$0A@@?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@__Cr@std@@QAE@$$QAPAUTransitionType@cctz@time_internal@absl@@0@Z ??$?0PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV234@@Z@PAU0?1???R1234@QBE?AV567@0@Z@$0A@@?$pair@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@PAU1?1???R2345@QBE?AV678@0@Z@@__Cr@std@@QAE@$$QAPAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@ABV567@@Z@1@Z - ??$?0PAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@$$QAPAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAE@$$QAPAVCommandLineFlag@absl@@@Z - ??$?0PAVCommandLineFlag@absl@@$0A@@?$tuple@$$QAPAVCommandLineFlag@absl@@@__Cr@std@@QAE@$$QAPAVCommandLineFlag@absl@@@Z - ??$?0PAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@I$0A@@__Cr@std@@$$QAPAVCommandLineFlag@absl@@@__Cr@std@@QAE@U__forward_args@12@$$QAPAVCommandLineFlag@absl@@@Z ??$?0PAX@FlagState@flags_internal@absl@@QAE@AAVFlagImpl@12@ABQAX_N2_J@Z ??$?0PBD@FormatArgImpl@str_format_internal@absl@@QAE@ABQBD@Z ??$?0PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU0123@$0A@@?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@@__Cr@std@@QAE@$$QAPBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$?0PBVFormatArgImpl@str_format_internal@absl@@$0A@@?$InlinedVector@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@absl@@QAE@PBVFormatArgImpl@str_format_internal@1@0ABV?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@?$FunctionRef@$$A6AII@Z@absl@@IAE@Uin_place_t@__Cr@std@@$$QAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@X@?$FunctionRef@$$A6AII@Z@absl@@QAE@$$QAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z ??$?0U?$__check_pair_construction@UFindInfo@container_internal@absl@@V?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@$0A@@?$pair@UFindInfo@container_internal@absl@@V?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@QAE@ABUFindInfo@container_internal@absl@@ABV?$NonIterableBitMask@I$0BA@$0A@@45@@Z ??$?0U?$array@D$0DKJI@@__Cr@std@@XU012@H@?$Span@D@absl@@QAE@AAU?$array@D$0DKJI@@__Cr@std@@@Z ??$?0U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -126,6 +109,7 @@ EXPORTS ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QAE@PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??$?0U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??$?0U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVFlagSaverImpl@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVFlagState@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@$$T@Z ??$?0U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVTimeZoneInfo@cctz@time_internal@absl@@@Z @@ -281,6 +265,7 @@ EXPORTS ??$?DPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QBEAAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ ??$?DPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBEAAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@12@XZ ??$?DPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBEAAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@12@XZ + ??$?DPAVFlagSaverImpl@flags_internal@absl@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBEAAVFlagSaverImpl@flags_internal@absl@@XZ ??$?DPAVFlagStateInterface@flags_internal@absl@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBEAAVFlagStateInterface@flags_internal@absl@@XZ ??$?D_J@absl@@YA?AVDuration@0@_JV10@@Z ??$?GPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV01234@@__Cr@std@@YAHABV?$move_iterator@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@@01@0@Z @@ -293,7 +278,6 @@ EXPORTS ??$?GPAUTransitionType@cctz@time_internal@absl@@PAU0123@@__Cr@std@@YAHABV?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?GPAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV234@@Z@@__Cr@std@@YAHABV?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@01@0@Z ??$?GPBQAVLogSink@absl@@@__Cr@std@@YAHABV?$__wrap_iter@PBQAVLogSink@absl@@@01@0@Z - ??$?K_J@absl@@YA?AVDuration@0@V10@_J@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z @@ -303,10 +287,6 @@ EXPORTS ??$?RAAPAVLogSink@absl@@@__identity@__Cr@std@@QBEAAPAVLogSink@absl@@AAPAV34@@Z ??$?RAAPBDAAHAAY0LLI@DABQBDPAD@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@QBEXAAPBDAAHAAY0LLI@DABQBD$$QAPAD@Z ??$?RAAPBVCommandLineFlag@absl@@@__identity@__Cr@std@@QBEAAPBVCommandLineFlag@absl@@AAPBV34@@Z - ??$?RAAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@345@@Z - ??$?RAAU?$__alt@$01V?$Span@$$CBD@absl@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$01V?$Span@$$CBD@absl@@@345@@Z - ??$?RAAU?$__alt@$02V?$variant@IHM@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$02V?$variant@IHM@__Cr@std@@@345@@Z - ??$?RAAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@345@@Z ??$?RAAW4LogSeverity@absl@@AAPBDAAHPAPADPAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@QBE_NAAW4LogSeverity@2@AAPBDAAH$$QAPAPAD$$QAPAH@Z ??$?RAAY04$$CBDPAVCondVar@absl@@@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@QBEXAAY04$$CBD$$QAPAVCondVar@2@@Z ??$?RAAY06$$CBDPAVCondVar@absl@@@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@QBEXAAY06$$CBD$$QAPAVCondVar@2@@Z @@ -335,12 +315,12 @@ EXPORTS ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_backward_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QBE?AU?$__in_out_result@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@12@PAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QBE?AU?$__in_out_result@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@12@PAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@__Cr@std@@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@12@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QBV756@$$QAPAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QBV756@$$QBQAVCommandLineFlag@3@@Z ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$V@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QBEIABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QBE_NABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@45@$$QAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@ABQAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QBEIABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@45@$$QAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@ABQAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AVconst_iterator@123@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@67@$$QAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QAV?$tuple@ABQAVCommandLineFlag@absl@@@67@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV012@AAPAVCommandLineFlag@absl@@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QBE_NABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AAPAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV012@AAPAVCommandLineFlag@absl@@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QBEIABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AAPAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV012@AAPAVCommandLineFlag@absl@@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AVconst_iterator@123@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AAPAVCommandLineFlag@3@@Z ??$?RVDuration@absl@@V01@@?$__less@XX@__Cr@std@@QBE_NABVDuration@absl@@0@Z ??$?RVMixingHashState@hash_internal@absl@@@CombineRaw@hash_internal@absl@@QBE?AVMixingHashState@12@V312@_K@Z ??$?RW4LogSeverity@absl@@ABQBDHAAPBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAPBD@Z @@ -375,6 +355,7 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QAEX$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@ABVCord@absl@@@Cord@absl@@AAEXABV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AAEX$$QAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NABQBW4ctrl_t@01@0PBX1@Z ??$ArgumentToConv@C@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@D@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@E@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ @@ -410,8 +391,10 @@ EXPORTS ??$AsciiStrCaseFoldImpl@$0A@$00@ascii_internal@absl@@YAXPADPBDI@Z ??$AsciiStrCaseFoldImpl@$0A@$0A@@ascii_internal@absl@@YAXPADPBDI@Z ??$AssertHashEqConsistent@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$AssertNonNull@U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@functional_internal@absl@@YAXABU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z + ??$AssertIsFull@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBEPBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBE@Z ??$AssertOnFind@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXABQBW4ctrl_t@01@0PBX1PBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@12@I@Z ??$AssignElements@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPAUPayload@status_internal@1@AAV?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PAUPayload@status_internal@absl@@@23@@01@I@Z ??$AssignElements@V?$allocator@VSourceLocation@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPAVSourceLocation@1@AAV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@01@I@Z @@ -462,14 +445,9 @@ EXPORTS ??$DeallocateBackingArray@$03V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPAX0I@Z ??$DecomposePair@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@01@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$DecomposePair@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@01@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QAUFindElement@301@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@U?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@U?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@U?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z ??$Destruct@$00@container_internal@absl@@YAXAAVCommonFields@01@ABUDtorPolicy@01@@Z ??$Destruct@$00@container_internal@absl@@YAXAAVCommonFields@01@ABUDtorPolicy@01@P6AXPAX2I@Z2@Z ??$Destruct@$00@container_internal@absl@@YAXAAVCommonFields@01@ABUDtorPolicy@01@P6AXPAX2I@Z@Z @@ -542,6 +520,8 @@ EXPORTS ??$FastTypeId@_J@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_K@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_N@absl@@YA?AVFastTypeIdType@0@XZ + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@ABV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPAXW4FlagOp@01@PBXPAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -577,9 +557,9 @@ EXPORTS ??$GetDataImpl@V?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@@span_internal@absl@@YAPAPAVLogSink@1@AAV?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@D@Z ??$GetFlag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@absl@@YA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@ABV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@0@@Z ??$GetTrivialDestructRef@$0M@$03@DtorPolicy@container_internal@absl@@SAABU012@XZ - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z ??$HardeningAssertGE@II@base_internal@absl@@YAXII@Z ??$HardeningAssertGE@PBUPayload@status_internal@absl@@PBU123@@base_internal@absl@@YAXPBUPayload@status_internal@1@0@Z ??$HardeningAssertGT@II@base_internal@absl@@YAXII@Z @@ -621,7 +601,6 @@ EXPORTS ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPAVBufferRawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPAVFILERawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeGet@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@@FlagImplPeer@flags_internal@absl@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@ABV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@12@@Z - ??$InvokeObject@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@II@functional_internal@absl@@YAITVoidPtr@01@I@Z ??$InvokeParseFlag@H@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAHPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@M@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAMPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@N@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PANPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -738,12 +717,8 @@ EXPORTS ??$OffsetValue@U?$atomic@_K@__Cr@std@@@FlagImpl@flags_internal@absl@@ABEPAU?$atomic@_K@__Cr@std@@XZ ??$OffsetValue@UFlagMaskedPointerValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@ABEPAUFlagMaskedPointerValue@12@XZ ??$OffsetValue@UFlagOneWordValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@ABEPAUFlagOneWordValue@12@XZ - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QAPAVCommandLineFlag@1@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@ABU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABQAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@ABQAVCommandLineFlag@1@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QAPAVCommandLineFlag@1@@Z + ??$PairConstFirst@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YAABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z + ??$PairConstFirst@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YAABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z ??$ParseFlag@H@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAHPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@M@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAMPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@N@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PANPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z @@ -763,9 +738,6 @@ EXPORTS ??$ReadCallback@P6A_NPAUSynchEvent@absl@@@Z@Condition@absl@@ABEXPAP6A_NPAUSynchEvent@1@@Z@Z ??$ReadCallback@P6A_NPBU?$atomic@_N@__Cr@std@@@Z@Condition@absl@@ABEXPAP6A_NPBU?$atomic@_N@__Cr@std@@@Z@Z ??$Register@AB_JAAIAAIAAIAAG@?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@QAEPAUHashtablezInfo@container_internal@2@AB_JAAI11AAG@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QAEXV<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QAEXV<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@0@Z@@CommonFields@container_internal@absl@@QAEXV<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@0@Z@@Z ??$SNPrintF@DHHH@absl@@YAHPADIABV?$FormatSpecTemplate@$0BPPPL@$0JPPPL@$0JPPPL@$0JPPPL@@str_format_internal@0@ABDABH33@Z ??$Seconds@H$0A@@absl@@YA?AVDuration@0@H@Z ??$Seconds@J$0A@@absl@@YA?AVDuration@0@J@Z @@ -931,14 +903,20 @@ EXPORTS ??$__append_with_size@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@I@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@X@23@@01@AAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@X@23@@01@AAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z - ??$__as_variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@YAAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@AAV201@@Z ??$__assign_with_size_random_access@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@H@Z ??$__assume_aligned@$03PAVLogSink@absl@@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@@Z ??$__assume_valid_range@AAPAPAVLogSink@absl@@AAPAPAV12@@__Cr@std@@YAXAAPAPAVLogSink@absl@@0@Z - ??$__at@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03$$V@__base@__visitation@__variant_detail@__Cr@std@@CA$$QA_PABU?$__farray@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@34@I@Z - ??$__at@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z@__base@__visitation@__variant_detail@__Cr@std@@CAABQ6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@1234@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@ZABQ6AI01@Z@Z ??$__call@AAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@5@@?$__invoke_void_return_wrapper@X$00@__Cr@std@@SAXAAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@7@@Z ??$__call_func@V<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@@?$__policy_func@$$A6AXAAVCommandLineFlag@absl@@@Z@__function@__Cr@std@@CAXPBT__policy_storage@123@AAVCommandLineFlag@absl@@@Z + ??$__clear_padding_if_needed@P6AXABUHashtablezInfo@container_internal@absl@@@Z$0A@@__Cr@std@@YAAAP6AXABUHashtablezInfo@container_internal@absl@@@ZAAP6AX0@Z@Z + ??$__clear_padding_if_needed@PAUHashtablezInfo@container_internal@absl@@$0A@@__Cr@std@@YAAAPAUHashtablezInfo@container_internal@absl@@AAPAU234@@Z + ??$__clear_padding_if_needed@PAVCordzHandle@cord_internal@absl@@$0A@@__Cr@std@@YAAAPAVCordzHandle@cord_internal@absl@@AAPAV234@@Z + ??$__clear_padding_if_needed@PAVCordzInfo@cord_internal@absl@@$0A@@__Cr@std@@YAAAPAVCordzInfo@cord_internal@absl@@AAPAV234@@Z + ??$__clear_padding_if_needed@PAVVLogSite@log_internal@absl@@$0A@@__Cr@std@@YAAAPAVVLogSite@log_internal@absl@@AAPAV234@@Z + ??$__clear_padding_if_needed@VMaskedPointer@flags_internal@absl@@$0A@@__Cr@std@@YAAAVMaskedPointer@flags_internal@absl@@AAV234@@Z + ??$__clear_padding_if_needed@W4OnDeadlockCycle@absl@@$0A@@__Cr@std@@YAAAW4OnDeadlockCycle@absl@@AAW423@@Z + ??$__clear_padding_if_needed@W4State@PerThreadSynch@base_internal@absl@@$0A@@__Cr@std@@YAAAW4State@PerThreadSynch@base_internal@absl@@AAW42345@@Z + ??$__clear_padding_if_needed@W4WaitState@ThreadIdentity@base_internal@absl@@$0A@@__Cr@std@@YAAAW4WaitState@ThreadIdentity@base_internal@absl@@AAW42345@@Z ??$__constexpr_memmove@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV12345@@__Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@0W4__element_count@01@@Z ??$__constexpr_memmove@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@__Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@0W4__element_count@01@@Z ??$__constexpr_memmove@PAVLogSink@absl@@PAV12@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0W4__element_count@01@@Z @@ -966,8 +944,8 @@ EXPORTS ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QAPAVCommandLineFlag@absl@@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QBQAVCommandLineFlag@absl@@@Z ??$__construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PAU1234@@__Cr@std@@YAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU2345@$$QAU2345@@Z ??$__construct_at@UPayload@status_internal@absl@@ABU123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@ABU234@@Z ??$__construct_at@UPayload@status_internal@absl@@U123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@$$QAU234@@Z @@ -1081,10 +1059,6 @@ EXPORTS ??$__destroy_at@UUnrecognizedFlag@absl@@@__Cr@std@@YAXPAUUnrecognizedFlag@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@@__Cr@std@@YAXPAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@YAXPAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@01@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$00@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$01@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$02@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$0A@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z ??$__distance@PBUPayload@status_internal@absl@@$0A@@__Cr@std@@YAHPBUPayload@status_internal@absl@@0@Z ??$__distance@PBUTransition@cctz@time_internal@absl@@$0A@@__Cr@std@@YAHPBUTransition@cctz@time_internal@absl@@0@Z ??$__distance@PBVFormatArgImpl@str_format_internal@absl@@$0A@@__Cr@std@@YAHPBVFormatArgImpl@str_format_internal@absl@@0@Z @@ -1134,10 +1108,14 @@ EXPORTS ??$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0ABQAV23@AAU__identity@01@@Z ??$__find_if@PAPAVLogSink@absl@@PAPAV12@V<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@__Cr@std@@YAPAPAV12@PAPAV12@0ABQAV12@AAU__identity@45@@Z@AAU645@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0$$QAV<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@01@YAPAPAV23@00ABQAV23@AAU__identity@01@@Z@2@Z ??$__for_each_segment@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@23@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@23@V123@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@Z@@__Cr@std@@YAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@01@0V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@01@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@01@00V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@01@@Z@@Z - ??$__get_alt@$00AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$01AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$02AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$0A@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$01AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$01AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$02AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$02AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$0A@AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$0A@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$__get_alt@AAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$00@__union@__access@__variant_detail@__Cr@std@@SA$$QA_PAAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$00@34@@Z ??$__get_alt@AAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$01@__union@__access@__variant_detail@__Cr@std@@SA$$QA_PAAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$01@34@@Z ??$__get_alt@AAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__union@__access@__variant_detail@__Cr@std@@SA$$QA_PAAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$0A@@34@@Z @@ -1163,7 +1141,6 @@ EXPORTS ??$__in_bounds@V?$__bucket_list_deallocator@V?$allocator@PAU?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@PAU?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@23@$0A@@__unique_ptr_array_bounds_stateless@__Cr@std@@QBE_NPAPAU?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@I@Z ??$__insert_assign_n_unchecked@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@23@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AAEXV?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@12@HPAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$__insert_with_size@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@23@V423@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AAE?AV?$__wrap_iter@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@12@1H@Z - ??$__invoke@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@I@__Cr@std@@YAIAAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QAI@Z ??$__invoke@AAUByCivilTime@Transition@cctz@time_internal@absl@@ABU2345@ABU2345@@__Cr@std@@YA_NAAUByCivilTime@Transition@cctz@time_internal@absl@@ABU3456@1@Z ??$__invoke@AAUByUnixTime@Transition@cctz@time_internal@absl@@ABU2345@ABU2345@@__Cr@std@@YA_NAAUByUnixTime@Transition@cctz@time_internal@absl@@ABU3456@1@Z ??$__invoke@AAU__identity@__Cr@std@@AAPAVLogSink@absl@@@__Cr@std@@YAAAPAVLogSink@absl@@AAU__identity@01@AAPAV23@@Z @@ -1172,10 +1149,6 @@ EXPORTS ??$__invoke@AAV<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV45@0ABQAV45@AAU__identity@23@@Z@AAPAV45@@__Cr@std@@YA_NAAV<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@01@YAPAPAVLogSink@absl@@PAPAV34@0ABQAV34@AAU__identity@01@@Z@AAPAV34@@Z ??$__invoke@AAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@5@@__Cr@std@@YAXAAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@6@@Z ??$__invoke@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@__Cr@std@@YAX$$QAP8FlagImpl@flags_internal@absl@@AEXXZ$$QAPAV234@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$01V?$Span@$$CBD@absl@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$01V?$Span@$$CBD@absl@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$02V?$variant@IHM@__Cr@std@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$02V?$variant@IHM@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@501@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$Span@$$CBD@4@@__Cr@std@@YAI$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$Span@$$CBD@5@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@IHM@__Cr@std@@@__Cr@std@@YAI$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$variant@IHM@01@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@_K_JIH_N@__Cr@std@@@__Cr@std@@YAI$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$variant@_K_JIH_N@01@@Z @@ -1244,7 +1217,6 @@ EXPORTS ??$__lower_bound_bisecting@U_ClassicAlgPolicy@__Cr@std@@PBUTransition@cctz@time_internal@absl@@U4567@U__identity@23@UByUnixTime@4567@@__Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@ABU2345@HAAUByUnixTime@2345@AAU__identity@01@@Z ??$__make_exception_guard@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXI@Z@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXI@Z@@01@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@AAEXI@Z@@Z ??$__make_exception_guard@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PAUUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PAUUnrecognizedFlag@absl@@@__Cr@std@@@01@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PAUUnrecognizedFlag@absl@@@01@@Z - ??$__make_value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@CA?A_P$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@78@@Z@@Z ??$__memberwise_forward_assign@V?$tuple@AAPAVCommandLineFlag@absl@@AA_N@__Cr@std@@V?$tuple@PAVCommandLineFlag@absl@@_N@23@PAVCommandLineFlag@absl@@_N$$Z$0A@$00@__Cr@std@@YAXAAV?$tuple@AAPAVCommandLineFlag@absl@@AA_N@01@$$QAV?$tuple@PAVCommandLineFlag@absl@@_N@01@U?$__type_list@PAVCommandLineFlag@absl@@_N@01@U?$__integer_sequence@I$0A@$00@01@@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@PAPAPBV45678@@__Cr@std@@YA?AU?$__in_out_result@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@PAPAU4567@@__Cr@std@@YA?AU?$__in_out_result@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z @@ -1282,17 +1254,12 @@ EXPORTS ??$__static_fancy_pointer_cast@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@PAV?$__tree_node_base@PAX@23@@__Cr@std@@YAPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@01@ABQAV?$__tree_node_base@PAX@01@@Z ??$__static_fancy_pointer_cast@PAV?$__tree_node_base@PAX@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@@__Cr@std@@YAPAV?$__tree_node_base@PAX@01@ABQAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@01@@Z ??$__static_fancy_pointer_cast@PAV?$__tree_node_base@PAX@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@@__Cr@std@@YAPAV?$__tree_node_base@PAX@01@ABQAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@01@@Z - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$Span@$$CBD@4@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@IHM@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@_K_JIH_N@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@_K_JN@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAAV?$allocator@UUnrecognizedFlag@absl@@@01@0@Z ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAAV?$allocator@UUnrecognizedFlag@absl@@@01@0U?$integral_constant@_N$0A@@01@@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PAPAVCommandLineFlag@absl@@@__Cr@std@@YAXPAPAVCommandLineFlag@absl@@0AA_K1@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PAPBVCommandLineFlag@absl@@@__Cr@std@@YAXPAPBVCommandLineFlag@absl@@0AA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PAPAVCommandLineFlag@absl@@@__Cr@std@@YAXAAPAPAVCommandLineFlag@absl@@0AA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PAPBVCommandLineFlag@absl@@@__Cr@std@@YAXAAPAPBVCommandLineFlag@absl@@0AA_K1@Z - ??$__throw_if_valueless@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__Cr@std@@YAXAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@YAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU2345@@Z ??$__to_address@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@@Z ??$__to_address@PAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@YAPAPAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@01@PAPAU201@@Z @@ -1363,24 +1330,21 @@ EXPORTS ??$__validate_iter_reference@AAPAPBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PAPAVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PAPBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@1234@AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@56@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@01234@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z - ??$__visit_value@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@78@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$advance@PBUTransition@cctz@time_internal@absl@@H@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAPBUTransition@cctz@time_internal@absl@@H@Z ??$advance@PBUTransition@cctz@time_internal@absl@@HH$0A@@__Cr@std@@YAXAAPBUTransition@cctz@time_internal@absl@@H@Z ??$advance@V?$__wrap_iter@PAPAVCommandLineFlag@absl@@@__Cr@std@@HH$0A@@__Cr@std@@YAXAAV?$__wrap_iter@PAPAVCommandLineFlag@absl@@@01@H@Z ??$advance@V?$__wrap_iter@PAPBVCommandLineFlag@absl@@@__Cr@std@@H@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAV?$__wrap_iter@PAPBVCommandLineFlag@absl@@@12@H@Z ??$advance@V?$__wrap_iter@PAPBVCommandLineFlag@absl@@@__Cr@std@@HH$0A@@__Cr@std@@YAXAAV?$__wrap_iter@PAPBVCommandLineFlag@absl@@@01@H@Z ??$advance@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@__Cr@std@@HH$0A@@__Cr@std@@YAXAAV?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@01@H@Z - ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$assign@PBVSourceLocation@absl@@$0A@@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QAEXPBVSourceLocation@1@0@Z ??$assign@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@$0A@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@0@Z @@ -1391,9 +1355,15 @@ EXPORTS ??$bit_cast@U?$FlagValueAndInitBit@_N@flags_internal@absl@@_J@__Cr@std@@YA?AU?$FlagValueAndInitBit@_N@flags_internal@absl@@AB_J@Z ??$bit_cast@VFastTypeIdType@absl@@PAX@__Cr@std@@YA?AVFastTypeIdType@absl@@ABQAX@Z ??$c_begin@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPBIABV?$Span@$$CBI@1@@Z + ??$c_begin@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_begin@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_begin@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$c_copy@V?$Span@$$CBI@absl@@PAI@absl@@YAPAIABV?$Span@$$CBI@0@$$QAPAI@Z + ??$c_copy@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AAPAD@absl@@YAPADABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AAPAD@Z + ??$c_copy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAPAD@absl@@YAPADABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAPAD@Z ??$c_end@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPBIABV?$Span@$$CBI@1@@Z + ??$c_end@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_end@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_end@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$call_once@A6AXXZ$$V@absl@@YAXAAVonce_flag@0@A6AXXZ@Z ??$call_once@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@absl@@YAXAAVonce_flag@0@$$QAP8FlagImpl@flags_internal@0@AEXXZ$$QAPAV230@@Z @@ -1404,8 +1374,8 @@ EXPORTS ??$combine@V?$tuple@ABI@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@ABV?$tuple@ABI@__Cr@std@@@Z ??$combine@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@ABV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@@Z ??$combine_contiguous@D@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@PBDI@Z - ??$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QAPAVCommandLineFlag@2@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QBQAVCommandLineFlag@2@@Z ??$construct@PAPBVImpl@time_zone@cctz@time_internal@absl@@AAPAPBV12345@$0A@@?$allocator_traits@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@12@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@AAPAPBV45678@@Z ??$construct@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV12345@$0A@@?$allocator_traits@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@12@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@$$QAPAPBV45678@@Z ??$construct@PAUCordRep@cord_internal@absl@@ABQAU123@$0A@@?$allocator_traits@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@PAUCordRep@cord_internal@absl@@@12@PAPAUCordRep@cord_internal@absl@@ABQAU456@@Z @@ -1424,8 +1394,8 @@ EXPORTS ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@PAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@12@PAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@12@PAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QAV?$tuple@$$V@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QAPAVCommandLineFlag@absl@@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QBQAVCommandLineFlag@absl@@@Z ??$construct@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@$0A@@?$allocator_traits@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$$QAU4567@@Z ??$construct@UPayload@status_internal@absl@@ABU123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UPayload@status_internal@absl@@@12@PAUPayload@status_internal@absl@@ABU456@@Z ??$construct@UPayload@status_internal@absl@@U123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UPayload@status_internal@absl@@@12@PAUPayload@status_internal@absl@@$$QAU456@@Z @@ -1441,12 +1411,12 @@ EXPORTS ??$construct@UUnrecognizedFlag@absl@@U12@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UUnrecognizedFlag@absl@@@12@PAUUnrecognizedFlag@absl@@$$QAU45@@Z ??$construct@UUnrecognizedFlag@absl@@W4Source@12@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UUnrecognizedFlag@absl@@@12@PAUUnrecognizedFlag@absl@@$$QAW4Source@45@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$construct@UViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV456@AAI$0A@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@PAUViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@ABV712@AAI@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QAPAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QAPAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QAPAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QBQAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QBQAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QBQAVCommandLineFlag@2@@Z ??$construct@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@23@ABV678@@Z@$0A@@?$allocator_traits@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@ABV789@@Z@@Z ??$construct@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V123@$0A@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@PAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@12@$$QAV412@@Z ??$construct@VFormatArgImpl@str_format_internal@absl@@ABV123@$0A@@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@12@PAVFormatArgImpl@str_format_internal@absl@@ABV456@@Z @@ -1472,8 +1442,8 @@ EXPORTS ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QAPAVCommandLineFlag@absl@@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QBQAVCommandLineFlag@absl@@@Z ??$construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PAU1234@@__Cr@std@@YAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU2345@$$QAU2345@@Z ??$construct_at@UPayload@status_internal@absl@@ABU123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@ABU234@@Z ??$construct_at@UPayload@status_internal@absl@@U123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@$$QAU234@@Z @@ -1533,13 +1503,13 @@ EXPORTS ??$distance@V?$move_iterator@PAUTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YAHV?$move_iterator@PAUTransition@cctz@time_internal@absl@@@01@0@Z ??$distance@V?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YAHV?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$element@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAAAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@@Z + ??$emplace@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z ??$emplace@$$V@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE?AV?$__wrap_iter@PAUTransition@cctz@time_internal@absl@@@12@V?$__wrap_iter@PBUTransition@cctz@time_internal@absl@@@12@@Z ??$emplace@$$V@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE?AV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@12@V?$__wrap_iter@PBUTransitionType@cctz@time_internal@absl@@@12@@Z ??$emplace@AAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@?$optional@VStream@status_internal@absl@@@__Cr@std@@QAEAAVStream@status_internal@absl@@AAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$emplace@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$emplace@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$emplace_at@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$emplace_at@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QAPAVCommandLineFlag@2@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QBQAVCommandLineFlag@2@@Z ??$emplace_back@$$V@?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QAEXXZ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QAEXXZ ??$emplace_back@AAPAPBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QAEXAAPAPBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -1574,11 +1544,9 @@ EXPORTS ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QAE?AV?$__hash_iterator@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AViterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AVconst_iterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$forward_as_tuple@ABQAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@ABQAVCommandLineFlag@absl@@@01@ABQAVCommandLineFlag@absl@@@Z - ??$forward_as_tuple@PAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@$$QAPAVCommandLineFlag@absl@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$get@$00@?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@QGAEAAV?$allocator@D@__Cr@std@@XZ ??$get@$00@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGAEAAIXZ ??$get@$00@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGBEABIXZ @@ -1601,7 +1569,6 @@ EXPORTS ??$get@$00PAVCommandLineFlag@absl@@_N@__Cr@std@@YAAA_NAAV?$tuple@PAVCommandLineFlag@absl@@_N@01@@Z ??$get@$01@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QGBEABUStringEq@12@XZ ??$get@$02@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QGAEAAV?$allocator@D@__Cr@std@@XZ - ??$get@$0A@$$QAPAVCommandLineFlag@absl@@@__Cr@std@@YAAAPAVCommandLineFlag@absl@@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@@?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@QGBEABIXZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGAEAAV?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGBEABV?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@XZ @@ -1621,7 +1588,6 @@ EXPORTS ??$get@$0A@@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QGBEABVCommonFields@12@XZ ??$get@$0A@AAPAVCommandLineFlag@absl@@AA_N@__Cr@std@@YAAAPAVCommandLineFlag@absl@@AAV?$tuple@AAPAVCommandLineFlag@absl@@AA_N@01@@Z ??$get@$0A@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@YAAAUFindInfo@container_internal@absl@@AAV?$tuple@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@23@@01@@Z - ??$get@$0A@ABQAVCommandLineFlag@absl@@@__Cr@std@@YAABQAVCommandLineFlag@absl@@AAV?$tuple@ABQAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@PAVCommandLineFlag@absl@@_N@__Cr@std@@YA$$QAPAVCommandLineFlag@absl@@$$QAV?$tuple@PAVCommandLineFlag@absl@@_N@01@@Z ??$get@$0A@PAVCommandLineFlag@absl@@_N@__Cr@std@@YAAAPAVCommandLineFlag@absl@@AAV?$tuple@PAVCommandLineFlag@absl@@_N@01@@Z ??$hash@H@MixingHashState@hash_internal@absl@@SAIABH@Z @@ -1640,7 +1606,6 @@ EXPORTS ??$hash_with_seed@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@$0A@@MixingHashState@hash_internal@absl@@SAIABV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@I@Z ??$insert@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z ??$insert@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@__Cr@std@@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAE?AV?$__wrap_iter@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@12@1@Z - ??$invoke@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@I@__Cr@std@@YAIAAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QAI@Z ??$invoke@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@__Cr@std@@YAX$$QAP8FlagImpl@flags_internal@absl@@AEXXZ$$QAPAV234@@Z ??$iter_swap@AAPAPAVCommandLineFlag@absl@@AAPAPAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAPAPAVCommandLineFlag@absl@@0@Z ??$iter_swap@AAPAPAVCommandLineFlag@absl@@PAPAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAPAPAVCommandLineFlag@absl@@$$QAPAPAV34@@Z @@ -1666,6 +1631,7 @@ EXPORTS ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@XZ ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@AAV12@$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@AAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$make_unique@VFallbackCrcMemcpyEngine@crc_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@01@XZ + ??$make_unique@VFlagSaverImpl@flags_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@01@XZ ??$make_unique@VFlagState@flags_internal@absl@@AAVFlagImpl@23@AAPAXAA_NAA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AAVFlagImpl@flags_internal@absl@@AAPAXAA_N2$$QA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AAVFlagImpl@23@PAXAA_NAA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AAVFlagImpl@flags_internal@absl@@$$QAPAXAA_N2$$QA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AAVFlagImpl@23@_JAA_NAA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AAVFlagImpl@flags_internal@absl@@$$QA_JAA_N21@Z @@ -1749,6 +1715,7 @@ EXPORTS ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@1@Z ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?A_PPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@1@Z ??$transfer_impl@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@CA?AU?$integral_constant@_N$00@__Cr@std@@PAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@45@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@1URank2@012@@Z + ??$ts_unchecked_read@PAUHashtablezInfo@container_internal@absl@@@base_internal@absl@@YAAAPAUHashtablezInfo@container_internal@1@AAPAU231@@Z ??$upper_bound@PBUTransition@cctz@time_internal@absl@@U1234@UByCivilTime@1234@@__Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@UByCivilTime@2345@@Z ??$upper_bound@PBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@UByUnixTime@2345@@Z ??$value_or@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$optional_ref@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -1774,10 +1741,6 @@ EXPORTS ??0?$FormatSpecTemplate@$0JPPPL@@str_format_internal@absl@@QAE@PBD@Z ??0?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QAE@ABUStringHash@12@I@Z ??0?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@QAE@ABUStringHash@12@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@AAE@W4InvalidCapacity@012@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QAE@I@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QAE@Uuninitialized_tag_t@12@@Z - ??0?$HashtableInlineDataImpl@$00@container_internal@absl@@QAE@V?$HashtableCapacityImpl@$00@12@Uno_seed_empty_tag_t@12@@Z ??0?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QAE@XZ ??0?$InlinedVector@PAVLogSink@absl@@$0BA@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@absl@@QAE@XZ ??0?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QAE@ABV01@@Z @@ -2119,6 +2082,10 @@ EXPORTS ??0GroupSse2Impl@container_internal@absl@@QAE@PBW4ctrl_t@12@@Z ??0GrowthInfoLowerBound@container_internal@absl@@QAE@E@Z ??0HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QAE@PBE@Z + ??0HashtableCapacity@container_internal@absl@@AAE@W4InvalidCapacity@012@@Z + ??0HashtableCapacity@container_internal@absl@@QAE@I@Z + ??0HashtableCapacity@container_internal@absl@@QAE@Uuninitialized_tag_t@12@@Z + ??0HashtableInlineData@container_internal@absl@@QAE@VHashtableCapacity@12@Uno_seed_empty_tag_t@12@@Z ??0HashtablezInfo@container_internal@absl@@QAE@XZ ??0HashtablezInfoHandle@container_internal@absl@@QAE@$$T@Z ??0Hex@absl@@AAE@W4PadSpec@1@_K@Z @@ -2167,11 +2134,12 @@ EXPORTS ??0PrefixCrc@CrcCordState@crc_internal@absl@@QAE@XZ ??0ProtoField@log_internal@absl@@QAE@XZ ??0Randen@random_internal@absl@@QAE@XZ + ??0RawHashSetLayout@container_internal@absl@@AAE@Uuninitialized_tag_t@12@@Z ??0RawHashSetLayout@container_internal@absl@@QAE@III_NI@Z ??0ReaderMutexLock@absl@@QAE@AAVMutex@1@@Z + ??0ReentranceGuard@container_internal@absl@@QAE@AAVCommonFields@12@@Z ??0RefcountAndFlags@cord_internal@absl@@QAE@XZ ??0RefcountedRep@CrcCordState@crc_internal@absl@@QAE@XZ - ??0ReleasableMutexLock@absl@@QAE@AAVMutex@1@@Z ??0Rep@CordBuffer@absl@@QAE@PAUCordRepFlat@cord_internal@2@@Z ??0Rep@CordBuffer@absl@@QAE@XZ ??0Rep@CrcCordState@crc_internal@absl@@QAE@XZ @@ -2370,6 +2338,7 @@ EXPORTS ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAE@XZ ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ + ??1?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ @@ -2431,8 +2400,8 @@ EXPORTS ??1Payload@status_internal@absl@@QAE@XZ ??1PosixTimeZone@cctz@time_internal@absl@@QAE@XZ ??1ReaderMutexLock@absl@@QAE@XZ + ??1ReentranceGuard@container_internal@absl@@QAE@XZ ??1RefcountedRep@CrcCordState@crc_internal@absl@@QAE@XZ - ??1ReleasableMutexLock@absl@@QAE@XZ ??1Rep@CrcCordState@crc_internal@absl@@QAE@XZ ??1Rep@GraphCycles@synchronization_internal@absl@@QAE@XZ ??1Rep@StatusBuilder@absl@@QAE@XZ @@ -2570,7 +2539,6 @@ EXPORTS ??8strings_internal@absl@@YA_NABV?$SplitIterator@V?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z ??9CharIterator@Cord@absl@@QBE_NABV012@@Z ??9ChunkIterator@Cord@absl@@QBE_NABV012@@Z - ??9GraphId@synchronization_internal@absl@@QBE_NABU012@@Z ??9__Cr@std@@YA_NABU__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NABV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@H@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NABV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@H@__Cr@std@@@01@0@Z @@ -2593,7 +2561,6 @@ EXPORTS ??A?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QBEABVFormatArgImpl@str_format_internal@1@I@Z ??A?$Span@D@absl@@QBEAADI@Z ??A?$Span@I@absl@@QBEAAII@Z - ??A?$__farray@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@__Cr@std@@QBEABQ6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@12@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@612@@ZI@Z ??A?$__wrap_iter@PAPAVCommandLineFlag@absl@@@__Cr@std@@QBEAAPAVCommandLineFlag@absl@@H@Z ??A?$__wrap_iter@PAPAVCordzHandle@cord_internal@absl@@@__Cr@std@@QBEAAPAVCordzHandle@cord_internal@absl@@H@Z ??A?$__wrap_iter@PAPAVLogSink@absl@@@__Cr@std@@QBEAAPAVLogSink@absl@@H@Z @@ -2625,6 +2592,7 @@ EXPORTS ??B?$function@$$A6A_NABVCommandLineFlag@absl@@@Z@__Cr@std@@QBE_NXZ ??B?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ??B?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ @@ -2664,6 +2632,7 @@ EXPORTS ??C?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAULogMessageData@LogMessage@log_internal@absl@@XZ ??C?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QBEPAURep@StatusBuilder@absl@@XZ ??C?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QBEPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ + ??C?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAVFlagSaverImpl@flags_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAVTimeZoneIf@cctz@time_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAVTimeZoneInfo@cctz@time_internal@absl@@XZ ??CChunkIterator@Cord@absl@@QBEPBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ @@ -2705,6 +2674,7 @@ EXPORTS ??D?$move_iterator@PAUTransition@cctz@time_internal@absl@@@__Cr@std@@QBE$$QAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QBE$$QAUTransitionType@cctz@time_internal@absl@@XZ ??D?$move_iterator@PAVSourceLocation@absl@@@__Cr@std@@QBE$$QAVSourceLocation@absl@@XZ + ??DCharIterator@Cord@absl@@QBEABDXZ ??DChunkIterator@Cord@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ??D__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QBE?AU__deque_block_range@123@XZ ??Dabsl@@YA?AVint128@0@V10@0@Z @@ -2790,6 +2760,7 @@ EXPORTS ??Pabsl@@YA_NVint128@0@0@Z ??Pabsl@@YA_NVuint128@0@0@Z ??R<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@__Cr@std@@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@23@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@23@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@Z@QBE?A?<auto>@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@2@Z + ??R<lambda_1>@?0???$AssertSameContainer@X@container_internal@absl@@YAXABQBW4ctrl_t@12@0PBX1PBE2@Z@QBE?A?<auto>@@_NPBD@Z ??R<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@QBE?A?<auto>@@PADI@Z ??R<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@QBE?A?<auto>@@PADI@Z ??R<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@QBE?A?<auto>@@PADI@Z @@ -2801,8 +2772,6 @@ EXPORTS ??R<lambda_1>@?0???$__emplace_unique@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QAE?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@H@__Cr@std@@_N@23@ABUpiecewise_construct_t@23@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QAV?$tuple@$$V@23@@Z@QBE?A?<auto>@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QAE?AU?$pair@V?$__hash_iterator@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@_N@23@ABUpiecewise_construct_t@23@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QAV?$tuple@$$V@23@@Z@QBE?A?<auto>@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QAE?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@H@__Cr@std@@_N@23@ABUpiecewise_construct_t@23@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QAV?$tuple@$$V@23@@Z@QBE?A?<auto>@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z - ??R<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@Z@QBE?A?<auto>@@XZ - ??R<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV123@AAI@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@ABV723@AAI@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@ABQAVCommandLineFlag@absl@@@?$vector@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@ABQAV45@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@ABQAVCordzHandle@cord_internal@absl@@@?$vector@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCordzHandle@cord_internal@absl@@ABQAV456@@Z@QBE?A?<auto>@@XZ @@ -2816,11 +2785,9 @@ EXPORTS ??R<lambda_1>@?0???$emplace_back@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAEAAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@$$QAV423@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@W4Source@UnrecognizedFlag@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QAEAAUUnrecognizedFlag@absl@@$$QAW4Source@45@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0??Append@FormatSinkImpl@str_format_internal@absl@@QAEXID@Z@QBE?A?<auto>@@I@Z - ??R<lambda_1>@?0??AssertSameContainer@container_internal@absl@@YAXABQBW4ctrl_t@23@0PBX1PBE2@Z@QBE?A?<auto>@@_NPBD@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@ABEHABV23@II@Z@QBE?A?<auto>@@PAVChunkIterator@23@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@ABEHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@II@Z@QBE?A?<auto>@@PAVChunkIterator@23@PAV456@@Z ??R<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@QBE?A?<auto>@@AAVCommandLineFlag@4@@Z - ??R<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@0@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV123@AAI@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@ABV723@AAI@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@ABQAVCommandLineFlag@absl@@@?$vector@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@ABQAV45@@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@ABQAVCordzHandle@cord_internal@absl@@@?$vector@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCordzHandle@cord_internal@absl@@ABQAV456@@Z@QBE?A?<auto>@@XZ @@ -2837,7 +2804,6 @@ EXPORTS ??R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV123@@Z ??R?$FunctionRef@$$A6AII@Z@absl@@QBEII@Z ??R?$FunctionRef@$$A6AXPAUCordRep@cord_internal@absl@@II@Z@absl@@QBEXPAUCordRep@cord_internal@1@II@Z - ??R?$FunctionRef@$$A6AXPAXPBX@Z@absl@@QBEXPAXPBX@Z ??R?$FunctionRef@$$A6AXPBW4ctrl_t@container_internal@absl@@PAX@Z@absl@@QBEXPBW4ctrl_t@container_internal@1@PAX@Z ??R?$FunctionRef@$$A6AXV?$Span@I@absl@@@Z@absl@@QBEXV?$Span@I@1@@Z ??R?$FunctionRef@$$A6AXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z@absl@@QBEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -2866,6 +2832,7 @@ EXPORTS ??R?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@QBEXPAURep@StatusBuilder@absl@@@Z ??R?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@QBEXPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??R?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@QBEXPAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??R?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@QBEXPAVFlagSaverImpl@flags_internal@absl@@@Z ??R?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@QBEXPAVFlagState@flags_internal@absl@@@Z ??R?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@QBEXPAVFlagStateInterface@flags_internal@absl@@@Z ??R?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@QBEXPAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -2932,6 +2899,7 @@ EXPORTS ??_5uint128@absl@@QAEAAV01@V01@@Z ??_6uint128@absl@@QAEAAV01@V01@@Z ??_DOStringStream@strings_internal@absl@@QAEXXZ + ??_EClock@absl@@UAEPAXI@Z ??_ECordzHandle@cord_internal@absl@@MAEPAXI@Z ?AbsDuration@absl@@YA?AVDuration@1@V21@@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3020,6 +2988,7 @@ EXPORTS ?AlwaysTrue@Condition@absl@@CA_NPBV12@@Z ?AnnotateConstruct@NonEmptyInlinedStorage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QAEXI@Z ?AnnotateDestruct@NonEmptyInlinedStorage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QAEXI@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AAEXAAV123@ABUPolicyFunctions@23@@Z ?Append@Cord@absl@@QAEX$$QAV12@@Z ?Append@Cord@absl@@QAEXABV12@@Z ?Append@Cord@absl@@QAEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3047,24 +3016,22 @@ EXPORTS ?AppendTruncated@log_internal@absl@@YAIV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AAEXI@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z - ?AreItersFromSameContainer@container_internal@absl@@YA_NABQBW4ctrl_t@12@0PBX1@Z ?AsValueType@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@CAPADPAD@Z ?AsciiStrToLower@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToLower@ascii_internal@absl@@YAXPADPBDI@Z ?AsciiStrToUpper@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPADPBDI@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAAVCommonFields@12@PBXP6AI1PAXI@ZI_NI1P6A_N212@Z@Z ?AssertHeld@CordzInfo@cord_internal@absl@@QAEXXZ ?AssertHeld@Mutex@absl@@QBEXXZ ?AssertHeld@SpinLock@base_internal@absl@@QBEXXZ ?AssertInSooMode@CommonFields@container_internal@absl@@ABEXXZ - ?AssertIsFull@container_internal@absl@@YAXABQBW4ctrl_t@12@PBXEPBEPBD@Z - ?AssertIsValidForComparison@container_internal@absl@@YAXABQBW4ctrl_t@12@PBXEPBE@Z + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotDebugCapacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IBEXXZ ?AssertNotDebugCapacity@CommonFields@container_internal@absl@@QBEXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotHeld@Mutex@absl@@QBEXXZ ?AssertReaderHeld@Mutex@absl@@QBEXXZ - ?AssertSameContainer@container_internal@absl@@YAXABQBW4ctrl_t@12@0PBX1PBE2@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPAV123@PAV123@_N@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPBV123@PBV123@_N@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QBEXVFastTypeIdType@3@P6APBVtype_info@@XZ@Z @@ -3103,6 +3070,7 @@ EXPORTS ?CalculateBase64EscapedLenInternal@strings_internal@absl@@YAII_N@Z ?CallVoidPtrFunction@Condition@absl@@CA_NPBV12@@Z ?Capacity@CordRepFlat@cord_internal@absl@@QBEIXZ + ?CapacityBits@HashtableInlineData@container_internal@absl@@CA_KVHashtableCapacity@23@@Z ?CapacityToGrowth@container_internal@absl@@YAII@Z ?CappedDamerauLevenshteinDistance@strings_internal@absl@@YAEV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0E@Z ?CatPieces@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$initializer_list@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@5@@Z @@ -3176,7 +3144,7 @@ EXPORTS ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QAE_NABUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?ConvertSpecialToEmptyAndFullToDeleted@GroupSse2Impl@container_internal@absl@@QBEXPAW4ctrl_t@23@@Z ?Copy@CordRepBtree@cord_internal@absl@@ABEPAV123@XZ - ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@V?$FunctionRef@$$A6AXPAXPBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@P6AXPAX3PBX@Z@Z ?Copy@flags_internal@absl@@YAXP6APAXW4FlagOp@12@PBXPAX2@Z12@Z ?CopyBeginTo@CordRepBtree@cord_internal@absl@@ABEPAV123@II@Z ?CopyConstruct@flags_internal@absl@@YAXP6APAXW4FlagOp@12@PBXPAX2@Z12@Z @@ -3197,8 +3165,9 @@ EXPORTS ?CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PIAXPIBXIV43@_N@Z ?Create@CordRepBtree@cord_internal@absl@@SAPAV123@PAUCordRep@23@@Z ?Create@CordRepFlat@cord_internal@absl@@SAPAU123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@I@Z - ?CreateDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ - ?CreateReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ + ?CreateDestroyed@HashtableCapacity@container_internal@absl@@SA?AV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@III_N@Z + ?CreateReentrance@HashtableCapacity@container_internal@absl@@SA?AV123@XZ ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPAV123@PAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPAUThreadIdentity@base_internal@2@XZ @@ -3222,6 +3191,8 @@ EXPORTS ?DeallocateIfAllocated@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXXZ ?DeallocateIfAllocated@?$Storage@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXXZ ?DeallocateIfAllocated@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXXZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QAE_NPAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -3271,6 +3242,7 @@ EXPORTS ?Digits10@?$BigUnsigned@$0FE@@strings_internal@absl@@SAHXZ ?DisableFlagfileAndEnvParsing@absl@@YAXXZ ?DisableRescheduling@SchedulingGuard@base_internal@absl@@SA_NXZ + ?Distance@Cord@absl@@SAHABVCharIterator@12@0@Z ?DoIgnoreLeak@absl@@YAXPBX@Z ?DoLoad@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@ABVCord@absl@@@Z@base_internal@absl@@ABEP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABVCord@3@@ZXZ ?DoLoad@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@ABEP6AXPBDH000@ZXZ @@ -3359,6 +3331,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QBE?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UBEXPAIPBXI@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UBEXPAIPIAXPIBXI_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UBEXPAII@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPAIIQBI1@Z ?ExtendCrc32c@absl@@YA?AVcrc32c_t@1@V21@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3399,7 +3372,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QAEPAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@ABE?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QBEHUGraphId@23@0HQAU423@@Z @@ -3488,7 +3460,7 @@ EXPORTS ?FromHost64@little_endian@absl@@YA_K_K@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0DM@$00@__Cr@std@@@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0OBA@$00@__Cr@std@@@Z - ?FromRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@_K@Z + ?FromRawData@HashtableCapacity@container_internal@absl@@SA?AV123@_K@Z ?FromTM@absl@@YA?AVTime@1@ABUtm@@VTimeZone@1@@Z ?FromUDate@absl@@YA?AVTime@1@N@Z ?FromUniversal@absl@@YA?AVTime@1@_J@Z @@ -3564,6 +3536,7 @@ EXPORTS ?GetGrowthLeft@GrowthInfoLowerBound@container_internal@absl@@QBEEXZ ?GetGrowthLeftLowerBound@CommonFields@container_internal@absl@@QBEIXZ ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QBEII@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SAIPAXI@Z ?GetHashtablezMaxSamples@container_internal@absl@@YAIXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QAE?AUGraphId@23@PAX@Z @@ -3756,7 +3729,7 @@ EXPORTS ?IsDataLoss@absl@@YA_NABVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NABVStatus@1@@Z ?IsDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z - ?IsDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ + ?IsDestroyed@HashtableCapacity@container_internal@absl@@QBE_NXZ ?IsEmpty@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsEmptyOrDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsExternal@CordRep@cord_internal@absl@@QBE_NXZ @@ -3784,7 +3757,7 @@ EXPORTS ?IsPermissionDenied@absl@@YA_NABVStatus@1@@Z ?IsPow2@CordBuffer@absl@@CA_NI@Z ?IsReachable@GraphCycles@synchronization_internal@absl@@QBE_NUGraphId@23@0@Z - ?IsReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ + ?IsReentrance@HashtableCapacity@container_internal@absl@@QBE_NXZ ?IsResourceExhausted@absl@@YA_NABVStatus@1@@Z ?IsRetired@CommandLineFlag@absl@@UBE_NXZ ?IsSMTEnabled@base_internal@absl@@YA_NXZ @@ -3800,8 +3773,8 @@ EXPORTS ?IsUnimplemented@absl@@YA_NABVStatus@1@@Z ?IsUnknown@absl@@YA_NABVStatus@1@@Z ?IsUnprotectedReadCandidate@MaskedPointer@flags_internal@absl@@QBE_NXZ - ?IsValid@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ ?IsValid@CordRepBtree@cord_internal@absl@@SA_NPBV123@_N@Z + ?IsValid@HashtableCapacity@container_internal@absl@@QBE_NXZ ?IsValidCapacity@container_internal@absl@@YA_NI@Z ?IterateOverFullSlots@container_internal@absl@@YAXABVCommonFields@12@IV?$FunctionRef@$$A6AXPBW4ctrl_t@container_internal@absl@@PAX@Z@2@@Z ?JoinMessageToStatus@StatusPrivateAccessorForStatusBuilder@status_internal@absl@@SA?AVStatus@3@V43@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@W4MessageJoinStyle@3@@Z @@ -3959,6 +3932,7 @@ EXPORTS ?NumClonedBytes@container_internal@absl@@YAIXZ ?NumContextsPerCPU@base_internal@absl@@YAHXZ ?NumControlBytes@container_internal@absl@@YAII@Z + ?NumControlBytesForLargeTable@container_internal@absl@@YAII@Z ?NumGenerationBytes@container_internal@absl@@YAIXZ ?NumLeakedFlagValues@flags_internal@absl@@YA_KXZ ?ODRCheck@CordzInfo@cord_internal@absl@@ABEXXZ @@ -4011,9 +3985,9 @@ EXPORTS ?Post@Win32Waiter@synchronization_internal@absl@@QAEXXZ ?PrecombineLengthMix@hash_internal@absl@@YA_K_KI@Z ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QAEX_JIIIG@Z - ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6AII@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@V?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@I@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@IV?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@PAXP6AI2I@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z ?Prepend@Cord@absl@@QAEXABV12@@Z @@ -4343,6 +4317,7 @@ EXPORTS ?TakeRep@Cord@absl@@AHAEPAUCordRep@cord_internal@2@XZ ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QAEXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QAEX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -4406,9 +4381,8 @@ EXPORTS ?ToInt64Nanoseconds@absl@@YA_JVDuration@1@@Z ?ToInt64Seconds@absl@@YA_JVDuration@1@@Z ?ToOpResult@CordRepBtree@cord_internal@absl@@AAE?AUOpResult@123@_N@Z - ?ToPublicSeed@?$HashtableInlineDataImpl@$00@container_internal@absl@@CA_K_K@Z - ?ToRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@QBEEXZ ?ToRawData@GrowthInfoLowerBound@container_internal@absl@@QBEEXZ + ?ToRawData@HashtableCapacity@container_internal@absl@@QBEEXZ ?ToSinkAlso@LogMessage@log_internal@absl@@QAEAAV123@PAVLogSink@3@@Z ?ToSinkOnly@LogMessage@log_internal@absl@@QAEAAV123@PAVLogSink@3@@Z ?ToString@?$BigUnsigned@$03@strings_internal@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -4691,7 +4665,6 @@ EXPORTS ?__annotate_shrink_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@ABEXII@Z ?__annotate_whole_block@?$deque@PBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@ABEXIW4__asan_annotation_type@123@@Z ?__annotate_whole_block@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@ABEXIW4__asan_annotation_type@123@@Z - ?__as_base@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@IGAE@XZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QBEIXZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QBEIXZ ?__back_spare@?$__split_buffer_size_layout@V?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@23@@__Cr@std@@QBEIXZ @@ -4798,6 +4771,17 @@ EXPORTS ?__destruct_at_end@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXPAUTransition@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXPAUTransitionType@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXPAUViableSubstitution@strings_internal@absl@@@Z + ?__empty@?$__vector_layout@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PBVCordzHandle@cord_internal@absl@@V?$allocator@PBVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBE_NXZ ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@__Cr@std@@@__Cr@std@@SAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PBQAU4567@@Z ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@@__Cr@std@@SAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBQAU4567@@Z ?__end_node@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QAEPAV?$__tree_end_node@PAV?$__tree_node_base@PAX@__Cr@std@@@23@XZ @@ -5209,8 +5193,8 @@ EXPORTS ?begin@CordRepBtree@cord_internal@absl@@QBEIXZ ?begin@Storage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEPADXZ ?begin@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QBE?AU1234@XZ - ?blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBEIXZ ?blocked_element_count@CommonFields@container_internal@absl@@QBEIXZ + ?blocked_element_count@HashtableInlineData@container_internal@absl@@QBEIXZ ?btree@CordRep@cord_internal@absl@@QAEPAVCordRepBtree@23@XZ ?btree@CordRep@cord_internal@absl@@QBEPBVCordRepBtree@23@XZ ?btree@CordRepBtreeNavigator@cord_internal@absl@@QBEPAVCordRepBtree@23@XZ @@ -5218,8 +5202,6 @@ EXPORTS ?bucket_count@?$__hash_table@PBUCordRep@cord_internal@absl@@U?$hash@PBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PBUCordRep@cord_internal@absl@@@56@V?$allocator@PBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QBEIXZ ?bucket_count@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QBEIXZ ?bytes_value@ProtoField@log_internal@absl@@QBE?AV?$Span@$$CBD@3@XZ - ?capacity@?$HashtableCapacityImpl@$00@container_internal@absl@@QBEIXZ - ?capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE?AV?$HashtableCapacityImpl@$00@23@XZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QBEIXZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QBEIXZ ?capacity@?$__split_buffer_size_layout@V?$__split_buffer@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@V__split_buffer_size_layout@45@@__Cr@std@@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@23@@__Cr@std@@QBEIXZ @@ -5248,7 +5230,9 @@ EXPORTS ?capacity@CommonFields@container_internal@absl@@QBEIXZ ?capacity@CordBuffer@absl@@QBEIXZ ?capacity@CordRepBtree@cord_internal@absl@@QBEIXZ - ?capacity_impl@CommonFields@container_internal@absl@@QBE?AV?$HashtableCapacityImpl@$00@23@XZ + ?capacity@HashtableCapacity@container_internal@absl@@QBEIXZ + ?capacity@HashtableInlineData@container_internal@absl@@QBE?AVHashtableCapacity@23@XZ + ?capacity_impl@CommonFields@container_internal@absl@@QBE?AVHashtableCapacity@23@XZ ?cbegin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBEPBUPayload@status_internal@2@XZ ?cbegin@?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QBE?AV?$__wrap_iter@PBQAVLogSink@absl@@@23@XZ ?cend@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBEPBUPayload@status_internal@2@XZ @@ -5411,8 +5395,8 @@ EXPORTS ?deallocate@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@PAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@I@Z ?deallocate@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@23@PAVFormatArgImpl@str_format_internal@absl@@I@Z ?deallocate@?$allocator_traits@V?$allocator@VSourceLocation@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@VSourceLocation@absl@@@23@PAVSourceLocation@absl@@I@Z - ?decrement_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ ?decrement_size@CommonFields@container_internal@absl@@QAEXXZ + ?decrement_size@HashtableInlineData@container_internal@absl@@QAEXXZ ?delimiter@?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBEABVByAnyChar@3@XZ ?delimiter@?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBEABVByAnyChar@3@XZ ?delimiter@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBEABVByChar@3@XZ @@ -5427,7 +5411,6 @@ EXPORTS ?effective_impl@time_zone@cctz@time_internal@absl@@ABEABVImpl@1234@XZ ?element@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAAAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@Z ?emplace@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@CAXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@Z - ?empty@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ ?empty@?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QBE_NXZ ?empty@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBE_NXZ ?empty@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QBE_NXZ @@ -5452,6 +5435,7 @@ EXPORTS ?empty@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBE_NXZ ?empty@CommonFields@container_internal@absl@@QBE_NXZ ?empty@Cord@absl@@QBE_NXZ + ?empty@HashtableInlineData@container_internal@absl@@QBE_NXZ ?encoded_message@LogEntry@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?encoded_remaining@LogMessageData@LogMessage@log_internal@absl@@QAEAAV?$Span@D@4@XZ ?end@?$BitMask@I$0BA@$0A@$0A@@container_internal@absl@@QBE?AV123@XZ @@ -5506,7 +5490,6 @@ EXPORTS ?end@CordRepBtree@cord_internal@absl@@QBEIXZ ?end@Storage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEPADXZ ?end@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QBE?AU1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4UArchSpecificEngines@234@B ?eq_ref@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABEABUStringEq@23@XZ ?erase@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QAEPAUPayload@status_internal@2@PBU342@@Z ?erase@?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QAE?AV?$__wrap_iter@PAPAVLogSink@absl@@@23@V?$__wrap_iter@PBQAVLogSink@absl@@@23@@Z @@ -5530,8 +5513,8 @@ EXPORTS ?gbswap_16@absl@@YAGG@Z ?gbswap_32@absl@@YAII@Z ?gbswap_64@absl@@YA_K_K@Z - ?generate_new_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ ?generate_new_seed@CommonFields@container_internal@absl@@QAEX_N@Z + ?generate_new_seed@HashtableInlineData@container_internal@absl@@QAEXXZ ?generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QBEEXZ ?generation@HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QBEEXZ ?generation_offset@RawHashSetLayout@container_internal@absl@@QBEIXZ @@ -5583,10 +5566,8 @@ EXPORTS ?get@?$__temp_value@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUTransition@cctz@time_internal@absl@@XZ ?get@?$__temp_value@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUTransitionType@cctz@time_internal@absl@@XZ ?get@?$__tuple_leaf@$00AAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@$0A@@__Cr@std@@QAEAAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@$$QAPAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AAPAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AAUFindInfo@container_internal@absl@@$0A@@__Cr@std@@QAEAAUFindInfo@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@ABQAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEABQAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@PAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@XZ ?get@?$unique_ptr@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QBEPAPBVImpl@time_zone@cctz@time_internal@absl@@XZ ?get@?$unique_ptr@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$__allocator_destructor@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QBEPAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ @@ -5626,10 +5607,10 @@ EXPORTS ?get_soo_data@HeapOrSoo@container_internal@absl@@QBEPBXXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@ABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z ?get_yearday@detail@cctz@time_internal@absl@@YAHABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z - ?growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE?AVGrowthInfoLowerBound@23@XZ + ?growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QBE?AVGrowthInfoLowerBound@23@XZ ?has_alt_flag@FormatConversionSpecImpl@str_format_internal@absl@@QBE_NXZ - ?has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ ?has_infoz@CommonFields@container_internal@absl@@QBE_NXZ + ?has_infoz@HashtableInlineData@container_internal@absl@@QBE_NXZ ?has_left_flag@FormatConversionSpecImpl@str_format_internal@absl@@QBE_NXZ ?has_parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QBE_NXZ ?has_show_pos_flag@FormatConversionSpecImpl@str_format_internal@absl@@QBE_NXZ @@ -5649,22 +5630,24 @@ EXPORTS ?hour@?$civil_time@Uhour_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ ?hour@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ ?hour@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ - ?increment_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXI@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXI@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ + ?increment_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QAEXI@Z ?increment_size@CommonFields@container_internal@absl@@QAEXI@Z ?increment_size@CommonFields@container_internal@absl@@QAEXXZ + ?increment_size@HashtableInlineData@container_internal@absl@@QAEXI@Z + ?increment_size@HashtableInlineData@container_internal@absl@@QAEXXZ ?index@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QBEIXZ ?index@?$probe_seq@$0BA@@container_internal@absl@@QBEIXZ + ?index@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QBEIXZ ?index@CordRepBtree@cord_internal@absl@@QBEIW4EdgeType@123@@Z ?infoz@CommonFields@container_internal@absl@@QAE?AVHashtablezInfoHandle@23@XZ + ?infoz_from_control@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@PAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@XZ - ?init_blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEX_K@Z ?init_blocked_element_count@CommonFields@container_internal@absl@@QAEXI@Z + ?init_blocked_element_count@HashtableInlineData@container_internal@absl@@QAEX_K@Z ?inline_size@InlineData@cord_internal@absl@@QBEIXZ ?inline_size@InlineRep@Cord@absl@@ABEIXZ ?inline_size@Rep@InlineData@cord_internal@absl@@QBEIXZ - ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@56@@Z + ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@56@@Z ?insert@?$unordered_set@PBUCordRep@cord_internal@absl@@U?$hash@PBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PBUCordRep@cord_internal@absl@@@56@V?$allocator@PBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QAE?AU?$pair@V?$__hash_const_iterator@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@__Cr@std@@_N@23@ABQBUCordRep@cord_internal@absl@@@Z ?int32_value@ProtoField@log_internal@absl@@QBEHXZ ?int64_value@ProtoField@log_internal@absl@@QBE_JXZ @@ -5679,13 +5662,13 @@ EXPORTS ?is_length@ConvTag@str_format_internal@absl@@QBE_NXZ ?is_profiled@InlineData@cord_internal@absl@@QBE_NXZ ?is_relative_timeout@KernelTimeout@synchronization_internal@absl@@QBE_NXZ - ?is_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ + ?is_sampled_seed@HashtableInlineData@container_internal@absl@@QBE_NXZ ?is_short@Rep@CordBuffer@absl@@QBE_NXZ ?is_single_group@container_internal@absl@@YA_NI@Z - ?is_small@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ - ?is_small@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ ?is_small@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE_NXZ ?is_small@CommonFields@container_internal@absl@@QBE_NXZ + ?is_small@HashtableCapacity@container_internal@absl@@QBE_NXZ + ?is_small@HashtableInlineData@container_internal@absl@@QBE_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QBE_NXZ ?is_soo@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE_NXZ ?is_tree@InlineData@cord_internal@absl@@QBE_NXZ @@ -5744,8 +5727,8 @@ EXPORTS ?max_size@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QBEIXZ ?max_size@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBEIXZ ?maybe_increment_generation_on_insert@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXXZ - ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE?AV?$HashtableCapacityImpl@$00@23@XZ - ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QBE?AV?$HashtableCapacityImpl@$00@23@XZ + ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE?AVHashtableCapacity@23@XZ + ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QBE?AVHashtableCapacity@23@XZ ?memcasecmp@strings_internal@absl@@YAHPBD0I@Z ?message@Status@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?message@StatusRep@status_internal@absl@@QBEABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -5777,10 +5760,10 @@ EXPORTS ?ok@Status@absl@@QBE_NXZ ?ok@Utf8ForCodePoint@debugging_internal@absl@@QBE_NXZ ?overflow@Streambuf@OStringStream@strings_internal@absl@@MAEHH@Z - ?overwrite_control_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXW4ctrl_t@23@@Z - ?overwrite_empty_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ - ?overwrite_full_as_deleted@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ - ?overwrite_full_as_empty_in_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ + ?overwrite_control_as_full@HashtableInlineData@container_internal@absl@@QAEXW4ctrl_t@23@@Z + ?overwrite_empty_as_full@HashtableInlineData@container_internal@absl@@QAEXXZ + ?overwrite_full_as_deleted@HashtableInlineData@container_internal@absl@@QAEXXZ + ?overwrite_full_as_empty_in_lower_bound@HashtableInlineData@container_internal@absl@@QAEXXZ ?parse@detail@cctz@time_internal@absl@@YA_NABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0ABVtime_zone@234@PAV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@PAV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@chrono@67@PAV567@@Z ?parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QBEPBVParsedFormatBase@23@XZ ?pointer_to@?$pointer_traits@PAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAPAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@23@AAU423@@Z @@ -5823,6 +5806,7 @@ EXPORTS ?push_back@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXABUTransition@cctz@time_internal@absl@@@Z ?push_back@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QAEXABUUnrecognizedFlag@absl@@@Z ?raw_code@Status@absl@@QBEHXZ + ?read_byte@HashtableInlineData@container_internal@absl@@ABEEI@Z ?reduce_size@InlineRep@Cord@absl@@QAEXI@Z ?release@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEPBVImpl@time_zone@cctz@time_internal@absl@@XZ ?release@?$unique_ptr@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QAEPAPBVImpl@time_zone@cctz@time_internal@absl@@XZ @@ -5866,6 +5850,7 @@ EXPORTS ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAEXPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@@Z ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAEXPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@@Z ?reset@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagSaverImpl@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagState@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagStateInterface@flags_internal@absl@@@Z ?reset@?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -5891,17 +5876,19 @@ EXPORTS ?scale_add@impl@detail@cctz@time_internal@absl@@YA_J_J00@Z ?second@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ ?second@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ - ?seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE?AVPerTableSeed@23@XZ ?seed@CommonFields@container_internal@absl@@QBE?AVPerTableSeed@23@XZ + ?seed@HashtableInlineData@container_internal@absl@@QBE?AVPerTableSeed@23@XZ ?seed@PerTableSeed@container_internal@absl@@QBEIXZ ?set@?$MaybeInitializedPtr@W4ctrl_t@container_internal@absl@@@container_internal@absl@@QAEXPAW4ctrl_t@23@@Z ?set_arg@BoundConversion@str_format_internal@absl@@QAEXPBVFormatArgImpl@23@@Z ?set_begin@CordRepBtree@cord_internal@absl@@AAEXI@Z - ?set_blocked_element_count_to_zero@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ ?set_blocked_element_count_to_zero@CommonFields@container_internal@absl@@QAEXXZ - ?set_capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXV?$HashtableCapacityImpl@$00@23@@Z + ?set_blocked_element_count_to_zero@HashtableInlineData@container_internal@absl@@QAEXXZ ?set_capacity@CommonFields@container_internal@absl@@QAEXI@Z - ?set_capacity@CommonFields@container_internal@absl@@QAEXV?$HashtableCapacityImpl@$00@23@@Z + ?set_capacity@CommonFields@container_internal@absl@@QAEXVHashtableCapacity@23@@Z + ?set_capacity@CommonFields@container_internal@absl@@QCEXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QAEXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QCEXVHashtableCapacity@23@@Z ?set_control@CommonFields@container_internal@absl@@QAEXPAW4ctrl_t@23@@Z ?set_conversion_char@FormatConversionSpecImpl@str_format_internal@absl@@QAEXW4FormatConversionChar@3@@Z ?set_cordz_info@InlineData@cord_internal@absl@@QAEXPAVCordzInfo@23@@Z @@ -5915,9 +5902,9 @@ EXPORTS ?set_full_soo@CommonFields@container_internal@absl@@QAEXXZ ?set_generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXE@Z ?set_generation_ptr@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXPAE@Z - ?set_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXVGrowthInfoLowerBound@23@@Z - ?set_has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ + ?set_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QAEXVGrowthInfoLowerBound@23@@Z ?set_has_infoz@CommonFields@container_internal@absl@@QAEXXZ + ?set_has_infoz@HashtableInlineData@container_internal@absl@@QAEXXZ ?set_infoz@CommonFields@container_internal@absl@@QAEXVHashtablezInfoHandle@23@@Z ?set_inline_data@InlineData@cord_internal@absl@@QAEXPBDI@Z ?set_inline_size@InlineData@cord_internal@absl@@QAEXI@Z @@ -5925,10 +5912,10 @@ EXPORTS ?set_inline_size@Rep@InlineData@cord_internal@absl@@QAEXI@Z ?set_reservation_size@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXI@Z ?set_reserved_growth@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXI@Z - ?set_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ - ?set_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@AAEXE@Z + ?set_sampled_seed@HashtableInlineData@container_internal@absl@@QAEXXZ + ?set_seed@HashtableInlineData@container_internal@absl@@AAEXE@Z ?set_short_length@Rep@CordBuffer@absl@@QAEXI@Z - ?set_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXI@Z + ?set_size@HashtableInlineData@container_internal@absl@@QAEXI@Z ?set_size_to_zero@CommonFields@container_internal@absl@@QAEXXZ ?set_tag@Rep@InlineData@cord_internal@absl@@QAEXC@Z ?set_tree@InlineData@cord_internal@absl@@QAEXPAUCordRep@23@@Z @@ -5941,11 +5928,11 @@ EXPORTS ?shrink_to_fit@?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAEXXZ ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXXZ ?single_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@123@XZ + ?single_non_soo_slot@CommonFields@container_internal@absl@@QBEPAXXZ ?single_slot@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@XZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QBEHXZ ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QBEHXZ ?size@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEIXZ - ?size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBEIXZ ?size@?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QBEIXZ ?size@?$InlinedVector@PAVLogSink@absl@@$0BA@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@absl@@QBEIXZ ?size@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBEIXZ @@ -5990,6 +5977,7 @@ EXPORTS ?size@CommonFields@container_internal@absl@@QBEIXZ ?size@Cord@absl@@QBEIXZ ?size@CordRepBtree@cord_internal@absl@@QBEIXZ + ?size@HashtableInlineData@container_internal@absl@@QBEIXZ ?size@InlineRep@Cord@absl@@QBEIXZ ?size@Storage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEIXZ ?skip_empty_or_deleted@iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXXZ @@ -6039,7 +6027,7 @@ EXPORTS ?timestamp@LogEntry@absl@@QBE?AVTime@2@XZ ?total_written@BufferRawSink@str_format_internal@absl@@QBEIXZ ?transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@0@Z - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2P6AX2EII@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2IP6AX2II@Z@Z ?tree@InlineRep@Cord@absl@@QBEPAUCordRep@cord_internal@3@XZ ?tree@Rep@InlineData@cord_internal@absl@@QBEPAUCordRep@34@XZ ?try_lock@Mutex@absl@@QAE_NXZ @@ -6058,8 +6046,6 @@ EXPORTS ?value@InputValue@UnboundConversion@str_format_internal@absl@@QBEHXZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QAEAAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QAEAAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ - ?valueless_by_exception@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QBE_NXZ - ?valueless_by_exception@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QBE_NXZ ?verbosity@LogEntry@absl@@QBEHXZ ?version@time_zone@cctz@time_internal@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?what@BadStatusOrAccess@absl@@UBEPBDXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x86_dbg_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_x86_dbg_cxx23.def index 1195fdc489a0..c6b740389db1 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x86_dbg_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x86_dbg_cxx23.def @@ -1,20 +1,13 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4HA ??$?0$$CBD$0A@@VoidPtr@str_format_internal@absl@@QAE@PBD@Z ??$?0$$CBU?$atomic@_N@__Cr@std@@@Condition@absl@@QAE@P6A_NPBU?$atomic@_N@__Cr@std@@@Z0@Z ??$?0$$CBUCordRep@cord_internal@absl@@@Hex@absl@@QAE@PBUCordRep@cord_internal@1@W4PadSpec@1@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QAPAVCommandLineFlag@absl@@@Z + ??$?0$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QAVCommandLineFlag@absl@@$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QBQAVCommandLineFlag@absl@@@Z ??$?0$$CBVFormatArgImpl@str_format_internal@absl@@$$CBV012@@?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QAE@V?$initializer_list@VFormatArgImpl@str_format_internal@absl@@@std@@@Z ??$?0$$CB_W$0A@@VoidPtr@str_format_internal@absl@@QAE@PB_W@Z ??$?0$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AAV?$tuple@$$V@12@U?$__integer_sequence@I$0A@@12@U?$__integer_sequence@I$S@12@@Z ??$?0$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$?0$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$Z$$QAPAVCommandLineFlag@absl@@@?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z ??$?0$$T@?$Storage@PAPAUCordRep@cord_internal@absl@@$00U?$StorageTag@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@PAPAUCordRep@cord_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@$$QA$$T@Z ??$?0$$T@?$Storage@PAPAVLogSink@absl@@$00U?$StorageTag@V?$allocator@PAVLogSink@absl@@@__Cr@std@@PAPAVLogSink@absl@@@internal_compressed_tuple@container_internal@2@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@$$QA$$T@Z ??$?0$$T@?$Storage@PAUPayload@status_internal@absl@@$00U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@PAUPayload@status_internal@absl@@@internal_compressed_tuple@container_internal@3@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@$$QA$$T@Z @@ -35,7 +28,6 @@ EXPORTS ??$?0$$V@PlacementImpl@?$NoDestructor@VMutex@absl@@@absl@@QAE@XZ ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AAPAVCommandLineFlag@absl@@AA_N@__Cr@std@@QAE@AAPAVCommandLineFlag@absl@@AA_N@Z ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@QAE@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@45@@Z - ??$?0$$Y_And@__Cr@std@@$0A@@?$tuple@ABQAVCommandLineFlag@absl@@@__Cr@std@@QAE@ABQAVCommandLineFlag@absl@@@Z ??$?0AAI@?$Storage@I$0A@U?$StorageTag@IV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$0A@@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@AAI@Z ??$?0AAIABV?$allocator@D@__Cr@std@@$00@?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@QAE@AAIABV?$allocator@D@__Cr@std@@@Z ??$?0AAIABV?$allocator@D@__Cr@std@@@?$CompressedTupleImpl@V?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@U?$integer_sequence@I$0A@$00@__Cr@std@@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@AAIABV?$allocator@D@56@@Z @@ -67,8 +59,6 @@ EXPORTS ??$?0AAVCord@absl@@@?$__optional_destruct_base@VCord@absl@@$0A@@__Cr@std@@QAE@Uin_place_t@12@AAVCord@absl@@@Z ??$?0AAY0BM@$$CBD$0A@@?$NoDestructor@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@absl@@QAE@AAY0BM@$$CBD@Z ??$?0AAY0BM@$$CBD@PlacementImpl@?$NoDestructor@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@absl@@QAE@AAY0BM@$$CBD@Z - ??$?0ABQAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@ABQAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAE@ABQAVCommandLineFlag@absl@@@Z - ??$?0ABQAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@I$0A@@__Cr@std@@ABQAVCommandLineFlag@absl@@@__Cr@std@@QAE@U__forward_args@12@ABQAVCommandLineFlag@absl@@@Z ??$?0ABV?$allocator@D@__Cr@std@@@?$Storage@V?$allocator@D@__Cr@std@@$00U?$StorageTag@IV?$allocator@D@__Cr@std@@@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@ABV?$allocator@D@56@@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@?$Storage@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$0A@U?$StorageTag@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I@internal_compressed_tuple@container_internal@absl@@$00@internal_compressed_tuple@container_internal@absl@@QAE@Uin_place_t@__Cr@std@@ABV?$allocator@UPayload@status_internal@absl@@@56@@Z ??$?0ABV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I$00@?$CompressedTuple@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@I@container_internal@absl@@QAE@ABV?$allocator@UPayload@status_internal@absl@@@__Cr@std@@$$QAI@Z @@ -80,8 +70,6 @@ EXPORTS ??$?0ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V$$Z$0A@$$Z$S@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@AAV?$tuple@$$V@12@U?$__integer_sequence@I$0A@@12@U?$__integer_sequence@I$S@12@@Z ??$?0ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z ??$?0ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$$Z$$V@?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@V?$tuple@$$V@12@@Z - ??$?0ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZABQAVCommandLineFlag@absl@@$$Z$0A@$$Z$0A@@?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@AAE@Upiecewise_construct_t@12@AAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@AAV?$tuple@ABQAVCommandLineFlag@absl@@@12@U?$__integer_sequence@I$0A@@12@3@Z - ??$?0ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$ZABQAVCommandLineFlag@absl@@@?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@QAE@Upiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@Z ??$?0D@?$allocator@U?$AlignedType@$03@container_internal@absl@@@__Cr@std@@QAE@ABV?$allocator@D@12@@Z ??$?0D@?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAE@ABV?$allocator@D@12@@Z ??$?0D@FormatArgImpl@str_format_internal@absl@@QAE@ABD@Z @@ -107,15 +95,10 @@ EXPORTS ??$?0PAUTransitionType@cctz@time_internal@absl@@$0A@@?$__wrap_iter@PBUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QAE@ABV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@12@@Z ??$?0PAUTransitionType@cctz@time_internal@absl@@PAU0123@$0A@@?$pair@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@__Cr@std@@QAE@$$QAPAUTransitionType@cctz@time_internal@absl@@0@Z ??$?0PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV234@@Z@PAU0?1???R1234@QBE?AV567@0@Z@$0A@@?$pair@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@PAU1?1???R2345@QBE?AV678@0@Z@@__Cr@std@@QAE@$$QAPAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@ABV567@@Z@1@Z - ??$?0PAVCommandLineFlag@absl@@$0A@@?$__tuple_leaf@$0A@$$QAPAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAE@$$QAPAVCommandLineFlag@absl@@@Z - ??$?0PAVCommandLineFlag@absl@@$0A@@?$tuple@$$QAPAVCommandLineFlag@absl@@@__Cr@std@@QAE@$$QAPAVCommandLineFlag@absl@@@Z - ??$?0PAVCommandLineFlag@absl@@@?$__tuple_impl@U?$__integer_sequence@I$0A@@__Cr@std@@$$QAPAVCommandLineFlag@absl@@@__Cr@std@@QAE@U__forward_args@12@$$QAPAVCommandLineFlag@absl@@@Z ??$?0PAX@FlagState@flags_internal@absl@@QAE@AAVFlagImpl@12@ABQAX_N2_J@Z ??$?0PBD@FormatArgImpl@str_format_internal@absl@@QAE@ABQBD@Z ??$?0PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU0123@$0A@@?$pair@PBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@@__Cr@std@@QAE@$$QAPBUPrefixCrc@CrcCordState@crc_internal@absl@@0@Z ??$?0PBVFormatArgImpl@str_format_internal@absl@@$0A@@?$InlinedVector@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@absl@@QAE@PBVFormatArgImpl@str_format_internal@1@0ABV?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@?$FunctionRef@$$A6AII@Z@absl@@IAE@Uin_place_t@__Cr@std@@$$QAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z - ??$?0U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@X@?$FunctionRef@$$A6AII@Z@absl@@QAE@$$QAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z ??$?0U?$array@D$0DKJI@@__Cr@std@@XU012@H@?$Span@D@absl@@QAE@AAU?$array@D$0DKJI@@__Cr@std@@@Z ??$?0U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$?0U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAULogMessageData@LogMessage@log_internal@absl@@@Z @@ -125,6 +108,7 @@ EXPORTS ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QAE@PAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$?0U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??$?0U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??$?0U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVFlagSaverImpl@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVFlagState@flags_internal@absl@@@Z ??$?0U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@$$T@Z ??$?0U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@$0A@@?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@PAVTimeZoneInfo@cctz@time_internal@absl@@@Z @@ -281,6 +265,7 @@ EXPORTS ??$?DPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$0A@@?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QBEAAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ ??$?DPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBEAAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@12@XZ ??$?DPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@$0A@@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBEAAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@12@XZ + ??$?DPAVFlagSaverImpl@flags_internal@absl@@$0A@@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBEAAVFlagSaverImpl@flags_internal@absl@@XZ ??$?DPAVFlagStateInterface@flags_internal@absl@@$0A@@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBEAAVFlagStateInterface@flags_internal@absl@@XZ ??$?D_J@absl@@YA?AVDuration@0@_JV10@@Z ??$?GPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV01234@@__Cr@std@@YAHABV?$move_iterator@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@@01@0@Z @@ -293,7 +278,6 @@ EXPORTS ??$?GPAUTransitionType@cctz@time_internal@absl@@PAU0123@@__Cr@std@@YAHABV?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$?GPAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV234@@Z@@__Cr@std@@YAHABV?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@01@0@Z ??$?GPBQAVLogSink@absl@@@__Cr@std@@YAHABV?$__wrap_iter@PBQAVLogSink@absl@@@01@0@Z - ??$?K_J@absl@@YA?AVDuration@0@V10@_J@Z ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?NUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z @@ -303,10 +287,6 @@ EXPORTS ??$?RAAPAVLogSink@absl@@@__identity@__Cr@std@@QBEAAPAVLogSink@absl@@AAPAV34@@Z ??$?RAAPBDAAHAAY0LLI@DABQBDPAD@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@QBEXAAPBDAAHAAY0LLI@DABQBD$$QAPAD@Z ??$?RAAPBVCommandLineFlag@absl@@@__identity@__Cr@std@@QBEAAPBVCommandLineFlag@absl@@AAPBV34@@Z - ??$?RAAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@345@@Z - ??$?RAAU?$__alt@$01V?$Span@$$CBD@absl@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$01V?$Span@$$CBD@absl@@@345@@Z - ??$?RAAU?$__alt@$02V?$variant@IHM@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$02V?$variant@IHM@__Cr@std@@@345@@Z - ??$?RAAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@__variant_detail@__Cr@std@@@?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@QBEIAAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@345@@Z ??$?RAAW4LogSeverity@absl@@AAPBDAAHPAPADPAH@?$AtomicHook@P6A_NW4LogSeverity@absl@@PBDHPAPADPAH@Z@base_internal@absl@@QBE_NAAW4LogSeverity@2@AAPBDAAH$$QAPAPAD$$QAPAH@Z ??$?RAAY04$$CBDPAVCondVar@absl@@@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@QBEXAAY04$$CBD$$QAPAVCondVar@2@@Z ??$?RAAY06$$CBDPAVCondVar@absl@@@?$AtomicHook@P6AXPBDPBX@Z@base_internal@absl@@QBEXAAY06$$CBD$$QAPAVCondVar@2@@Z @@ -335,12 +315,12 @@ EXPORTS ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_backward_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QBE?AU?$__in_out_result@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@12@PAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RUTransitionType@cctz@time_internal@absl@@U0123@$0A@@?$__move_impl@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@QBE?AU?$__in_out_result@PAUTransitionType@cctz@time_internal@absl@@PAU1234@@12@PAUTransitionType@cctz@time_internal@absl@@00@Z ??$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@__Cr@std@@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@12@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@PAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QBV756@$$QAPAVCommandLineFlag@3@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$CBV012@QAVCommandLineFlag@absl@@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@$$QBV756@$$QBQAVCommandLineFlag@3@@Z ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$V@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QBEIABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QBE_NABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@45@$$QAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@ABQAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QBEIABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@45@$$QAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@ABQAVCommandLineFlag@absl@@@45@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@ABQAVCommandLineFlag@absl@@@12@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AVconst_iterator@123@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@67@$$QAV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QAV?$tuple@ABQAVCommandLineFlag@absl@@@67@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV012@AAPAVCommandLineFlag@absl@@@?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@QBE_NABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AAPAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV012@AAPAVCommandLineFlag@absl@@@?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QBEIABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AAPAVCommandLineFlag@2@@Z + ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV012@AAPAVCommandLineFlag@absl@@@FindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AVconst_iterator@123@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0AAPAVCommandLineFlag@3@@Z ??$?RVDuration@absl@@V01@@?$__less@XX@__Cr@std@@QBE_NABVDuration@absl@@0@Z ??$?RVMixingHashState@hash_internal@absl@@@CombineRaw@hash_internal@absl@@QBE?AVMixingHashState@12@V312@_K@Z ??$?RW4LogSeverity@absl@@ABQBDHAAPBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAPBD@Z @@ -375,6 +355,7 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QAEX$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@ABVCord@absl@@@Cord@absl@@AAEXABV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AAEX$$QAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NABQBW4ctrl_t@01@0PBX1@Z ??$ArgumentToConv@C@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@D@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ ??$ArgumentToConv@E@str_format_internal@absl@@YA?AW4FormatConversionCharSet@1@XZ @@ -410,8 +391,10 @@ EXPORTS ??$AsciiStrCaseFoldImpl@$0A@$00@ascii_internal@absl@@YAXPADPBDI@Z ??$AsciiStrCaseFoldImpl@$0A@$0A@@ascii_internal@absl@@YAXPADPBDI@Z ??$AssertHashEqConsistent@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$AssertNonNull@U?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@@functional_internal@absl@@YAXABU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@1@@Z + ??$AssertIsFull@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBEPBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBE@Z ??$AssertOnFind@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXABQBW4ctrl_t@01@0PBX1PBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@12@I@Z ??$AssignElements@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PAUPayload@status_internal@absl@@@23@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPAUPayload@status_internal@1@AAV?$IteratorValueAdapter@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@V?$move_iterator@PAUPayload@status_internal@absl@@@23@@01@I@Z ??$AssignElements@V?$allocator@VSourceLocation@absl@@@__Cr@std@@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@inlined_vector_internal@absl@@@inlined_vector_internal@absl@@YAXPAVSourceLocation@1@AAV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@01@I@Z @@ -462,14 +445,9 @@ EXPORTS ??$DeallocateBackingArray@$03V?$allocator@D@__Cr@std@@@container_internal@absl@@YAXPAX0I@Z ??$DecomposePair@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@01@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$DecomposePair@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@01@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$DecomposePair@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z ??$DecomposePair@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@01@$$QAUFindElement@301@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@U?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@56@@memory_internal@container_internal@absl@@YAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@U?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@U?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@45@@Z - ??$DecomposePairImpl@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@67@@memory_internal@container_internal@absl@@YA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@U?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@@Z ??$Destruct@$00@container_internal@absl@@YAXAAVCommonFields@01@ABUDtorPolicy@01@@Z ??$Destruct@$00@container_internal@absl@@YAXAAVCommonFields@01@ABUDtorPolicy@01@P6AXPAX2I@Z2@Z ??$Destruct@$00@container_internal@absl@@YAXAAVCommonFields@01@ABUDtorPolicy@01@P6AXPAX2I@Z@Z @@ -542,6 +520,8 @@ EXPORTS ??$FastTypeId@_J@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_K@absl@@YA?AVFastTypeIdType@0@XZ ??$FastTypeId@_N@absl@@YA?AVFastTypeIdType@0@XZ + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@ABV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPAXW4FlagOp@01@PBXPAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -577,9 +557,9 @@ EXPORTS ??$GetDataImpl@V?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@@span_internal@absl@@YAPAPAVLogSink@1@AAV?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@D@Z ??$GetFlag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@absl@@YA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@ABV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@0@@Z ??$GetTrivialDestructRef@$0M@$03@DtorPolicy@container_internal@absl@@SAABU012@XZ - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z ??$HardeningAssertGE@II@base_internal@absl@@YAXII@Z ??$HardeningAssertGE@PBUPayload@status_internal@absl@@PBU123@@base_internal@absl@@YAXPBUPayload@status_internal@1@0@Z ??$HardeningAssertGT@II@base_internal@absl@@YAXII@Z @@ -621,7 +601,6 @@ EXPORTS ??$InvokeFlush@VBufferRawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPAVBufferRawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeFlush@VFILERawSink@str_format_internal@absl@@@str_format_internal@absl@@YAXPAVFILERawSink@01@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$InvokeGet@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@V?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@@FlagImplPeer@flags_internal@absl@@SA?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@ABV?$Flag@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@12@@Z - ??$InvokeObject@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@II@functional_internal@absl@@YAITVoidPtr@01@I@Z ??$InvokeParseFlag@H@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAHPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@M@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAMPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z ??$InvokeParseFlag@N@flags_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PANPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -738,12 +717,8 @@ EXPORTS ??$OffsetValue@U?$atomic@_K@__Cr@std@@@FlagImpl@flags_internal@absl@@ABEPAU?$atomic@_K@__Cr@std@@XZ ??$OffsetValue@UFlagMaskedPointerValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@ABEPAUFlagMaskedPointerValue@12@XZ ??$OffsetValue@UFlagOneWordValue@flags_internal@absl@@@FlagImpl@flags_internal@absl@@ABEPAUFlagOneWordValue@12@XZ - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QAPAVCommandLineFlag@1@@Z - ??$PairArgs@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@ABU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABQAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@ABQAVCommandLineFlag@absl@@@23@@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@ABQAVCommandLineFlag@1@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z - ??$PairArgs@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YA?AU?$pair@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@__Cr@std@@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@$$QAPAVCommandLineFlag@1@@Z + ??$PairConstFirst@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YAABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PBU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z + ??$PairConstFirst@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@YAABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@Z ??$ParseFlag@H@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAHPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@M@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAMPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z ??$ParseFlag@N@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PANPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@@Z @@ -763,9 +738,6 @@ EXPORTS ??$ReadCallback@P6A_NPAUSynchEvent@absl@@@Z@Condition@absl@@ABEXPAP6A_NPAUSynchEvent@1@@Z@Z ??$ReadCallback@P6A_NPBU?$atomic@_N@__Cr@std@@@Z@Condition@absl@@ABEXPAP6A_NPBU?$atomic@_N@__Cr@std@@@Z@Z ??$Register@AB_JAAIAAIAAIAAG@?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@QAEPAUHashtablezInfo@container_internal@2@AB_JAAI11AAG@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QAEXV<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@CommonFields@container_internal@absl@@QAEXV<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@78@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@78@@Z@@Z - ??$RunWithReentrancyGuard@V<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@0@Z@@CommonFields@container_internal@absl@@QAEXV<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@0@Z@@Z ??$SNPrintF@DHHH@absl@@YAHPADIABV?$FormatSpecTemplate@$0BPPPL@$0JPPPL@$0JPPPL@$0JPPPL@@str_format_internal@0@ABDABH33@Z ??$Seconds@H$0A@@absl@@YA?AVDuration@0@H@Z ??$Seconds@J$0A@@absl@@YA?AVDuration@0@J@Z @@ -924,14 +896,20 @@ EXPORTS ??$__append_with_size@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@I@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@X@23@@01@AAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z ??$__as_transparent@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@$0A@@__Cr@std@@YA?AV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@X@23@@01@AAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@01@@Z - ??$__as_variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@YAAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@AAV201@@Z ??$__assign_with_size_random_access@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@H@Z ??$__assume_aligned@$03PAVLogSink@absl@@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@@Z ??$__assume_valid_range@AAPAPAVLogSink@absl@@AAPAPAV12@@__Cr@std@@YAXAAPAPAVLogSink@absl@@0@Z - ??$__at@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03$$V@__base@__visitation@__variant_detail@__Cr@std@@CA$$QA_PABU?$__farray@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@34@I@Z - ??$__at@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z@__base@__visitation@__variant_detail@__Cr@std@@CAABQ6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@1234@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@ZABQ6AI01@Z@Z ??$__call@AAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@5@@?$__invoke_void_return_wrapper@X$00@__Cr@std@@SAXAAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@7@@Z ??$__call_func@V<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@@?$__policy_func@$$A6AXAAVCommandLineFlag@absl@@@Z@__function@__Cr@std@@CAXPBT__policy_storage@123@AAVCommandLineFlag@absl@@@Z + ??$__clear_padding_if_needed@P6AXABUHashtablezInfo@container_internal@absl@@@Z$0A@@__Cr@std@@YAAAP6AXABUHashtablezInfo@container_internal@absl@@@ZAAP6AX0@Z@Z + ??$__clear_padding_if_needed@PAUHashtablezInfo@container_internal@absl@@$0A@@__Cr@std@@YAAAPAUHashtablezInfo@container_internal@absl@@AAPAU234@@Z + ??$__clear_padding_if_needed@PAVCordzHandle@cord_internal@absl@@$0A@@__Cr@std@@YAAAPAVCordzHandle@cord_internal@absl@@AAPAV234@@Z + ??$__clear_padding_if_needed@PAVCordzInfo@cord_internal@absl@@$0A@@__Cr@std@@YAAAPAVCordzInfo@cord_internal@absl@@AAPAV234@@Z + ??$__clear_padding_if_needed@PAVVLogSite@log_internal@absl@@$0A@@__Cr@std@@YAAAPAVVLogSite@log_internal@absl@@AAPAV234@@Z + ??$__clear_padding_if_needed@VMaskedPointer@flags_internal@absl@@$0A@@__Cr@std@@YAAAVMaskedPointer@flags_internal@absl@@AAV234@@Z + ??$__clear_padding_if_needed@W4OnDeadlockCycle@absl@@$0A@@__Cr@std@@YAAAW4OnDeadlockCycle@absl@@AAW423@@Z + ??$__clear_padding_if_needed@W4State@PerThreadSynch@base_internal@absl@@$0A@@__Cr@std@@YAAAW4State@PerThreadSynch@base_internal@absl@@AAW42345@@Z + ??$__clear_padding_if_needed@W4WaitState@ThreadIdentity@base_internal@absl@@$0A@@__Cr@std@@YAAAW4WaitState@ThreadIdentity@base_internal@absl@@AAW42345@@Z ??$__constexpr_memmove@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV12345@@__Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@0W4__element_count@01@@Z ??$__constexpr_memmove@PAUPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@@__Cr@std@@YAPAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU2345@0W4__element_count@01@@Z ??$__constexpr_memmove@PAVLogSink@absl@@PAV12@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0W4__element_count@01@@Z @@ -959,8 +937,8 @@ EXPORTS ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$__construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z - ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QAPAVCommandLineFlag@absl@@@Z + ??$__construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QBQAVCommandLineFlag@absl@@@Z ??$__construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PAU1234@@__Cr@std@@YAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU2345@$$QAU2345@@Z ??$__construct_at@UPayload@status_internal@absl@@ABU123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@ABU234@@Z ??$__construct_at@UPayload@status_internal@absl@@U123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@$$QAU234@@Z @@ -1074,10 +1052,6 @@ EXPORTS ??$__destroy_at@UUnrecognizedFlag@absl@@@__Cr@std@@YAXPAUUnrecognizedFlag@absl@@@Z ??$__destroy_at@UViableSubstitution@strings_internal@absl@@@__Cr@std@@YAXPAUViableSubstitution@strings_internal@absl@@@Z ??$__destroy_at@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@YAXPAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@01@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$00@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$01@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$02@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z - ??$__dispatch@$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@?$__dispatcher@$0A@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@2345@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@345@@Z ??$__distance@PBUPayload@status_internal@absl@@$0A@@__Cr@std@@YAHPBUPayload@status_internal@absl@@0@Z ??$__distance@PBUTransition@cctz@time_internal@absl@@$0A@@__Cr@std@@YAHPBUTransition@cctz@time_internal@absl@@0@Z ??$__distance@PBVFormatArgImpl@str_format_internal@absl@@$0A@@__Cr@std@@YAHPBVFormatArgImpl@str_format_internal@absl@@0@Z @@ -1127,10 +1101,14 @@ EXPORTS ??$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0ABQAV23@AAU__identity@01@@Z ??$__find_if@PAPAVLogSink@absl@@PAPAV12@V<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@__Cr@std@@YAPAPAV12@PAPAV12@0ABQAV12@AAU__identity@45@@Z@AAU645@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV23@0$$QAV<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@01@YAPAPAV23@00ABQAV23@AAU__identity@01@@Z@2@Z ??$__for_each_segment@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@23@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@23@V123@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@Z@@__Cr@std@@YAXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@01@0V<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@01@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@01@00V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@01@@Z@@Z - ??$__get_alt@$00AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$01AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$02AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__get_alt@$0A@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$00AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$01AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$01AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$02AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$02AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z + ??$__get_alt@$0A@AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__base@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z + ??$__get_alt@$0A@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__access@__variant_detail@__Cr@std@@SA$$QA_PAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$__get_alt@AAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$00@__union@__access@__variant_detail@__Cr@std@@SA$$QA_PAAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$00@34@@Z ??$__get_alt@AAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@$01@__union@__access@__variant_detail@__Cr@std@@SA$$QA_PAAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$01@34@@Z ??$__get_alt@AAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@@__union@__access@__variant_detail@__Cr@std@@SA$$QA_PAAT?$__union@$0A@$00V?$variant@_K_JN@__Cr@std@@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@U?$in_place_index_t@$0A@@34@@Z @@ -1156,7 +1134,6 @@ EXPORTS ??$__in_bounds@V?$__bucket_list_deallocator@V?$allocator@PAU?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@PAU?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@23@$0A@@__unique_ptr_array_bounds_stateless@__Cr@std@@QBE_NPAPAU?$__hash_node_base@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@I@Z ??$__insert_assign_n_unchecked@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@23@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AAEXV?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@12@HPAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$__insert_with_size@U_ClassicAlgPolicy@__Cr@std@@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@23@V423@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@AAE?AV?$__wrap_iter@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@12@1H@Z - ??$__invoke@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@I@__Cr@std@@YAIAAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QAI@Z ??$__invoke@AAUByCivilTime@Transition@cctz@time_internal@absl@@ABU2345@ABU2345@@__Cr@std@@YA_NAAUByCivilTime@Transition@cctz@time_internal@absl@@ABU3456@1@Z ??$__invoke@AAUByUnixTime@Transition@cctz@time_internal@absl@@ABU2345@ABU2345@@__Cr@std@@YA_NAAUByUnixTime@Transition@cctz@time_internal@absl@@ABU3456@1@Z ??$__invoke@AAU__identity@__Cr@std@@AAPAVLogSink@absl@@@__Cr@std@@YAAAPAVLogSink@absl@@AAU__identity@01@AAPAV23@@Z @@ -1165,10 +1142,6 @@ EXPORTS ??$__invoke@AAV<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@__Cr@std@@YAPAPAVLogSink@absl@@PAPAV45@0ABQAV45@AAU__identity@23@@Z@AAPAV45@@__Cr@std@@YA_NAAV<lambda_1>@?0???$__find_generic@PAPAVLogSink@absl@@PAPAV12@PAV12@U__identity@__Cr@std@@@01@YAPAPAVLogSink@absl@@PAPAV34@0ABQAV34@AAU__identity@01@@Z@AAPAV34@@Z ??$__invoke@AAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@5@@__Cr@std@@YAXAAV<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@AAVCommandLineFlag@6@@Z ??$__invoke@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@__Cr@std@@YAX$$QAP8FlagImpl@flags_internal@absl@@AEXXZ$$QAPAV234@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$00V?$variant@_K_JN@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$01V?$Span@$$CBD@absl@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$01V?$Span@$$CBD@absl@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$02V?$variant@IHM@__Cr@std@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$02V?$variant@IHM@__Cr@std@@@501@@Z - ??$__invoke@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@456@@__Cr@std@@YAI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@01@AAU?$__alt@$0A@V?$variant@_K_JIH_N@__Cr@std@@@501@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$Span@$$CBD@4@@__Cr@std@@YAI$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$Span@$$CBD@5@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@IHM@__Cr@std@@@__Cr@std@@YAI$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$variant@IHM@01@@Z ??$__invoke@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@_K_JIH_N@__Cr@std@@@__Cr@std@@YAI$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$variant@_K_JIH_N@01@@Z @@ -1237,7 +1210,6 @@ EXPORTS ??$__lower_bound_bisecting@U_ClassicAlgPolicy@__Cr@std@@PBUTransition@cctz@time_internal@absl@@U4567@U__identity@23@UByUnixTime@4567@@__Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@ABU2345@HAAUByUnixTime@2345@AAU__identity@01@@Z ??$__make_exception_guard@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXI@Z@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXI@Z@@01@V<lambda_1>@?0??__add_back_capacity@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@AAEXI@Z@@Z ??$__make_exception_guard@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PAUUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YA?AU?$__exception_guard_noexceptions@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PAUUnrecognizedFlag@absl@@@__Cr@std@@@01@V?$_AllocatorDestroyRangeReverse@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@PAUUnrecognizedFlag@absl@@@01@@Z - ??$__make_value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@CA?A_P$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@78@@Z@@Z ??$__memberwise_forward_assign@V?$tuple@AAPAVCommandLineFlag@absl@@AA_N@__Cr@std@@V?$tuple@PAVCommandLineFlag@absl@@_N@23@PAVCommandLineFlag@absl@@_N$$Z$0A@$00@__Cr@std@@YAXAAV?$tuple@AAPAVCommandLineFlag@absl@@AA_N@01@$$QAV?$tuple@PAVCommandLineFlag@absl@@_N@01@U?$__type_list@PAVCommandLineFlag@absl@@_N@01@U?$__integer_sequence@I$0A@$00@01@@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV45678@PAPAPBV45678@@__Cr@std@@YA?AU?$__in_out_result@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV12345@@01@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@00@Z ??$__move@U_ClassicAlgPolicy@__Cr@std@@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU4567@PAPAU4567@@__Cr@std@@YA?AU?$__in_out_result@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PAPAU1234@@01@PAPAUPrefixCrc@CrcCordState@crc_internal@absl@@00@Z @@ -1275,17 +1247,12 @@ EXPORTS ??$__static_fancy_pointer_cast@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@PAV?$__tree_node_base@PAX@23@@__Cr@std@@YAPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@01@ABQAV?$__tree_node_base@PAX@01@@Z ??$__static_fancy_pointer_cast@PAV?$__tree_node_base@PAX@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@@__Cr@std@@YAPAV?$__tree_node_base@PAX@01@ABQAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@01@@Z ??$__static_fancy_pointer_cast@PAV?$__tree_node_base@PAX@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@@__Cr@std@@YAPAV?$__tree_node_base@PAX@01@ABQAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@01@@Z - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$Span@$$CBD@4@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@IHM@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@_K_JIH_N@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ - ??$__std_visit_exhaustive_visitor_check@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@_K_JN@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@CAXXZ ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAAV?$allocator@UUnrecognizedFlag@absl@@@01@0@Z ??$__swap_allocator@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@YAXAAV?$allocator@UUnrecognizedFlag@absl@@@01@0U?$integral_constant@_N$0A@@01@@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PAPAVCommandLineFlag@absl@@@__Cr@std@@YAXPAPAVCommandLineFlag@absl@@0AA_K1@Z ??$__swap_bitmap_pos@U_ClassicAlgPolicy@__Cr@std@@PAPBVCommandLineFlag@absl@@@__Cr@std@@YAXPAPBVCommandLineFlag@absl@@0AA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PAPAVCommandLineFlag@absl@@@__Cr@std@@YAXAAPAPAVCommandLineFlag@absl@@0AA_K1@Z ??$__swap_bitmap_pos_within@U_ClassicAlgPolicy@__Cr@std@@PAPBVCommandLineFlag@absl@@@__Cr@std@@YAXAAPAPBVCommandLineFlag@absl@@0AA_K1@Z - ??$__throw_if_valueless@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__Cr@std@@YAXAAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??$__to_address@$$CBUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@YAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBU2345@@Z ??$__to_address@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@YAPAPAPBVImpl@time_zone@cctz@time_internal@absl@@PAPAPBV23456@@Z ??$__to_address@PAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@YAPAPAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@01@PAPAU201@@Z @@ -1356,9 +1323,6 @@ EXPORTS ??$__validate_iter_reference@AAPAPBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PAPAVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ ??$__validate_iter_reference@PAPBVCommandLineFlag@absl@@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXXZ - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@__base@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@1234@AAV?$__impl@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@234@@Z - ??$__visit_alt@U?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@56@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@01234@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z - ??$__visit_value@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@@__variant@__visitation@__variant_detail@__Cr@std@@SA?A_T$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@78@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@34@@Z ??$advance@PBUTransition@cctz@time_internal@absl@@H@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAPBUTransition@cctz@time_internal@absl@@H@Z ??$advance@PBUTransition@cctz@time_internal@absl@@HH$0A@@__Cr@std@@YAXAAPBUTransition@cctz@time_internal@absl@@H@Z ??$advance@V?$__wrap_iter@PAPAVCommandLineFlag@absl@@@__Cr@std@@HH$0A@@__Cr@std@@YAXAAV?$__wrap_iter@PAPAVCommandLineFlag@absl@@@01@H@Z @@ -1378,15 +1342,15 @@ EXPORTS ??$allocate_at_least@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PAUUnrecognizedFlag@absl@@I@12@AAV?$allocator@UUnrecognizedFlag@absl@@@12@I@Z ??$allocate_at_least@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PAUViableSubstitution@strings_internal@absl@@I@12@AAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@I@Z ??$allocate_at_least@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SA?AU?$allocation_result@PAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@I@12@AAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@I@Z - ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA_N$$QAU?$EqualElement@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@UStringEq@container_internal@absl@@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@U?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAI$$QAU?$HashElement@UStringHash@container_internal@absl@@$00$0A@@12@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z + ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$apply@UEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAUEmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z + ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@FlatHashMapPolicyBase@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$apply@UFindElement@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@@?$hash_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SA?AVconst_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@12@$$QAUFindElement@412@AAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@Z ??$assign@PBVSourceLocation@absl@@$0A@@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QAEXPBVSourceLocation@1@0@Z ??$assign@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@$0A@@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@12@0@Z @@ -1397,9 +1361,15 @@ EXPORTS ??$bit_cast@U?$FlagValueAndInitBit@_N@flags_internal@absl@@_J@__Cr@std@@YA?AU?$FlagValueAndInitBit@_N@flags_internal@absl@@AB_J@Z ??$bit_cast@VFastTypeIdType@absl@@PAX@__Cr@std@@YA?AVFastTypeIdType@absl@@ABQAX@Z ??$c_begin@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPBIABV?$Span@$$CBI@1@@Z + ??$c_begin@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_begin@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_begin@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$c_copy@V?$Span@$$CBI@absl@@PAI@absl@@YAPAIABV?$Span@$$CBI@0@$$QAPAI@Z + ??$c_copy@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AAPAD@absl@@YAPADABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@AAPAD@Z + ??$c_copy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAPAD@absl@@YAPADABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAPAD@Z ??$c_end@$$CBV?$Span@$$CBI@absl@@@container_algorithm_internal@absl@@YAPBIABV?$Span@$$CBI@1@@Z + ??$c_end@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z + ??$c_end@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PBD@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@@Z ??$c_end@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@container_algorithm_internal@absl@@YA?AV?$__wrap_iter@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@AAV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@34@@Z ??$call_once@A6AXXZ$$V@absl@@YAXAAVonce_flag@0@A6AXXZ@Z ??$call_once@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@absl@@YAXAAVonce_flag@0@$$QAP8FlagImpl@flags_internal@0@AEXXZ$$QAPAV230@@Z @@ -1410,8 +1380,8 @@ EXPORTS ??$combine@V?$tuple@ABI@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@ABV?$tuple@ABI@__Cr@std@@@Z ??$combine@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@$$V@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@ABV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@@Z ??$combine_contiguous@D@?$HashStateBase@VMixingHashState@hash_internal@absl@@@hash_internal@absl@@SA?AVMixingHashState@12@V312@PBDI@Z - ??$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QAPAVCommandLineFlag@2@@Z + ??$construct@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QBQAVCommandLineFlag@2@@Z ??$construct@PAPBVImpl@time_zone@cctz@time_internal@absl@@AAPAPBV12345@$0A@@?$allocator_traits@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@12@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@AAPAPBV45678@@Z ??$construct@PAPBVImpl@time_zone@cctz@time_internal@absl@@PAPBV12345@$0A@@?$allocator_traits@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@12@PAPAPBVImpl@time_zone@cctz@time_internal@absl@@$$QAPAPBV45678@@Z ??$construct@PAUCordRep@cord_internal@absl@@ABQAU123@$0A@@?$allocator_traits@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@PAUCordRep@cord_internal@absl@@@12@PAPAUCordRep@cord_internal@absl@@ABQAU456@@Z @@ -1430,8 +1400,8 @@ EXPORTS ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@PAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@12@PAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QAV?$tuple@$$V@12@@Z ??$construct@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@$0A@@?$allocator_traits@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@12@PAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@$$QAV?$tuple@$$V@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z - ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@12@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QAPAVCommandLineFlag@absl@@@Z + ??$construct@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@$0A@@?$allocator_traits@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@12@PAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@$$QBQAVCommandLineFlag@absl@@@Z ??$construct@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@$0A@@?$allocator_traits@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@12@PAUConversionItem@ParsedFormatBase@str_format_internal@absl@@$$QAU4567@@Z ??$construct@UPayload@status_internal@absl@@ABU123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UPayload@status_internal@absl@@@12@PAUPayload@status_internal@absl@@ABU456@@Z ??$construct@UPayload@status_internal@absl@@U123@$0A@@?$allocator_traits@V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UPayload@status_internal@absl@@@12@PAUPayload@status_internal@absl@@$$QAU456@@Z @@ -1447,12 +1417,12 @@ EXPORTS ??$construct@UUnrecognizedFlag@absl@@U12@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UUnrecognizedFlag@absl@@@12@PAUUnrecognizedFlag@absl@@$$QAU45@@Z ??$construct@UUnrecognizedFlag@absl@@W4Source@12@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$0A@@?$allocator_traits@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UUnrecognizedFlag@absl@@@12@PAUUnrecognizedFlag@absl@@$$QAW4Source@45@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@@Z ??$construct@UViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV456@AAI$0A@@?$allocator_traits@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@UViableSubstitution@strings_internal@absl@@@12@PAUViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@ABV712@AAI@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z - ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@45@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@45@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@45@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QAPAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QAPAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QAPAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QBQAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QBQAVCommandLineFlag@2@@Z + ??$construct@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@$$QBQAVCommandLineFlag@2@@Z ??$construct@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@AAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@23@ABV678@@Z@$0A@@?$allocator_traits@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@AAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@12@ABV789@@Z@@Z ??$construct@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V123@$0A@@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@12@PAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@12@$$QAV412@@Z ??$construct@VFormatArgImpl@str_format_internal@absl@@ABV123@$0A@@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@12@PAVFormatArgImpl@str_format_internal@absl@@ABV456@@Z @@ -1478,8 +1448,8 @@ EXPORTS ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z ??$construct_at@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@PAU123@@__Cr@std@@YAPAU?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@01@$$QAV?$tuple@$$V@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z - ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@ABUpiecewise_construct_t@23@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@ABUpiecewise_construct_t@01@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@01@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@PAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QAPAVCommandLineFlag@absl@@@Z + ??$construct_at@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@QAVCommandLineFlag@absl@@PAU123@@__Cr@std@@YAPAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@01@PAU201@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@01@$$QBQAVCommandLineFlag@absl@@@Z ??$construct_at@UConversionItem@ParsedFormatBase@str_format_internal@absl@@U1234@PAU1234@@__Cr@std@@YAPAUConversionItem@ParsedFormatBase@str_format_internal@absl@@PAU2345@$$QAU2345@@Z ??$construct_at@UPayload@status_internal@absl@@ABU123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@ABU234@@Z ??$construct_at@UPayload@status_internal@absl@@U123@PAU123@@__Cr@std@@YAPAUPayload@status_internal@absl@@PAU234@$$QAU234@@Z @@ -1539,13 +1509,13 @@ EXPORTS ??$distance@V?$move_iterator@PAUTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YAHV?$move_iterator@PAUTransition@cctz@time_internal@absl@@@01@0@Z ??$distance@V?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@YAHV?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@01@0@Z ??$element@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAAAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@@Z + ??$emplace@$$CBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QBU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z ??$emplace@$$V@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE?AV?$__wrap_iter@PAUTransition@cctz@time_internal@absl@@@12@V?$__wrap_iter@PBUTransition@cctz@time_internal@absl@@@12@@Z ??$emplace@$$V@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE?AV?$__wrap_iter@PAUTransitionType@cctz@time_internal@absl@@@12@V?$__wrap_iter@PBUTransitionType@cctz@time_internal@absl@@@12@@Z ??$emplace@AAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@?$optional@VStream@status_internal@absl@@@__Cr@std@@QAEAAVStream@status_internal@absl@@AAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$emplace@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$emplace@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z - ??$emplace_at@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$emplace_at@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QAPAVCommandLineFlag@2@@Z + ??$emplace_at@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@QAVCommandLineFlag@absl@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$$QBQAVCommandLineFlag@2@@Z ??$emplace_back@$$V@?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QAEXXZ ??$emplace_back@$$V@?$__split_buffer@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@QAEXXZ ??$emplace_back@AAPAPBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QAEXAAPAPBVImpl@time_zone@cctz@time_internal@absl@@@Z @@ -1580,11 +1550,9 @@ EXPORTS ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QAE?AV?$__hash_iterator@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AViterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AVconst_iterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??$find_or_prepare_insert@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$forward_as_tuple@ABQAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@ABQAVCommandLineFlag@absl@@@01@ABQAVCommandLineFlag@absl@@@Z - ??$forward_as_tuple@PAVCommandLineFlag@absl@@@__Cr@std@@YA?AV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@$$QAPAVCommandLineFlag@absl@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z ??$get@$00@?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@QGAEAAV?$allocator@D@__Cr@std@@XZ ??$get@$00@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGAEAAIXZ ??$get@$00@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGBEABIXZ @@ -1607,7 +1575,6 @@ EXPORTS ??$get@$00PAVCommandLineFlag@absl@@_N@__Cr@std@@YAAA_NAAV?$tuple@PAVCommandLineFlag@absl@@_N@01@@Z ??$get@$01@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QGBEABUStringEq@12@XZ ??$get@$02@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QGAEAAV?$allocator@D@__Cr@std@@XZ - ??$get@$0A@$$QAPAVCommandLineFlag@absl@@@__Cr@std@@YAAAPAVCommandLineFlag@absl@@AAV?$tuple@$$QAPAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@@?$CompressedTuple@IV?$allocator@D@__Cr@std@@@container_internal@absl@@QGBEABIXZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGAEAAV?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@XZ ??$get@$0A@@?$CompressedTuple@V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@I@container_internal@absl@@QGBEABV?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@XZ @@ -1627,7 +1594,6 @@ EXPORTS ??$get@$0A@@?$CompressedTuple@VCommonFields@container_internal@absl@@UStringHash@23@UStringEq@23@V?$allocator@D@__Cr@std@@@container_internal@absl@@QGBEABVCommonFields@12@XZ ??$get@$0A@AAPAVCommandLineFlag@absl@@AA_N@__Cr@std@@YAAAPAVCommandLineFlag@absl@@AAV?$tuple@AAPAVCommandLineFlag@absl@@AA_N@01@@Z ??$get@$0A@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@23@@__Cr@std@@YAAAUFindInfo@container_internal@absl@@AAV?$tuple@AAUFindInfo@container_internal@absl@@AAV?$NonIterableBitMask@I$0BA@$0A@@23@@01@@Z - ??$get@$0A@ABQAVCommandLineFlag@absl@@@__Cr@std@@YAABQAVCommandLineFlag@absl@@AAV?$tuple@ABQAVCommandLineFlag@absl@@@01@@Z ??$get@$0A@PAVCommandLineFlag@absl@@_N@__Cr@std@@YA$$QAPAVCommandLineFlag@absl@@$$QAV?$tuple@PAVCommandLineFlag@absl@@_N@01@@Z ??$get@$0A@PAVCommandLineFlag@absl@@_N@__Cr@std@@YAAAPAVCommandLineFlag@absl@@AAV?$tuple@PAVCommandLineFlag@absl@@_N@01@@Z ??$hash@H@MixingHashState@hash_internal@absl@@SAIABH@Z @@ -1646,7 +1612,6 @@ EXPORTS ??$hash_with_seed@V?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@$0A@@MixingHashState@hash_internal@absl@@SAIABV?$tuple@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABH@__Cr@std@@I@Z ??$insert@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@$0A@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@45@@Z ??$insert@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@__Cr@std@@$0A@@?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAE?AV?$__wrap_iter@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$__wrap_iter@PAUraw_view@?1???R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV345@@Z@@12@1@Z - ??$invoke@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@I@__Cr@std@@YAIAAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@$$QAI@Z ??$invoke@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@__Cr@std@@YAX$$QAP8FlagImpl@flags_internal@absl@@AEXXZ$$QAPAV234@@Z ??$iter_swap@AAPAPAVCommandLineFlag@absl@@AAPAPAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAPAPAVCommandLineFlag@absl@@0@Z ??$iter_swap@AAPAPAVCommandLineFlag@absl@@PAPAV12@@?$_IterOps@U_ClassicAlgPolicy@__Cr@std@@@__Cr@std@@SAXAAPAPAVCommandLineFlag@absl@@$$QAPAPAV34@@Z @@ -1672,6 +1637,7 @@ EXPORTS ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@XZ ??$make_unique@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@AAV12@$0A@@__Cr@std@@YA?AV?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@01@AAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??$make_unique@VFallbackCrcMemcpyEngine@crc_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@01@XZ + ??$make_unique@VFlagSaverImpl@flags_internal@absl@@$$V$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@01@XZ ??$make_unique@VFlagState@flags_internal@absl@@AAVFlagImpl@23@AAPAXAA_NAA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AAVFlagImpl@flags_internal@absl@@AAPAXAA_N2$$QA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AAVFlagImpl@23@PAXAA_NAA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AAVFlagImpl@flags_internal@absl@@$$QAPAXAA_N2$$QA_J@Z ??$make_unique@VFlagState@flags_internal@absl@@AAVFlagImpl@23@_JAA_NAA_N_J$0A@@__Cr@std@@YA?AV?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@01@AAVFlagImpl@flags_internal@absl@@$$QA_JAA_N21@Z @@ -1762,6 +1728,7 @@ EXPORTS ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@SAXPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@1@Z ??$transfer@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SA?A_PPAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@1@Z ??$transfer_impl@V?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@@?$common_policy_traits@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@X@container_internal@absl@@CA?AU?$integral_constant@_N$00@__Cr@std@@PAV?$allocator@U?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@@45@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@12@1URank2@012@@Z + ??$ts_unchecked_read@PAUHashtablezInfo@container_internal@absl@@@base_internal@absl@@YAAAPAUHashtablezInfo@container_internal@1@AAPAU231@@Z ??$upper_bound@PBUTransition@cctz@time_internal@absl@@U1234@UByCivilTime@1234@@__Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@UByCivilTime@2345@@Z ??$upper_bound@PBUTransition@cctz@time_internal@absl@@U1234@UByUnixTime@1234@@__Cr@std@@YAPBUTransition@cctz@time_internal@absl@@PBU2345@0ABU2345@UByUnixTime@2345@@Z ??$value_or@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$optional_ref@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@34@@Z @@ -1787,10 +1754,6 @@ EXPORTS ??0?$FormatSpecTemplate@$0JPPPL@@str_format_internal@absl@@QAE@PBD@Z ??0?$HashElement@UStringHash@container_internal@absl@@$00$0A@@container_internal@absl@@QAE@ABUStringHash@12@I@Z ??0?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@QAE@ABUStringHash@12@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@AAE@W4InvalidCapacity@012@@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QAE@I@Z - ??0?$HashtableCapacityImpl@$00@container_internal@absl@@QAE@Uuninitialized_tag_t@12@@Z - ??0?$HashtableInlineDataImpl@$00@container_internal@absl@@QAE@V?$HashtableCapacityImpl@$00@12@Uno_seed_empty_tag_t@12@@Z ??0?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QAE@XZ ??0?$InlinedVector@PAVLogSink@absl@@$0BA@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@absl@@QAE@XZ ??0?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QAE@ABV01@@Z @@ -2132,6 +2095,10 @@ EXPORTS ??0GroupSse2Impl@container_internal@absl@@QAE@PBW4ctrl_t@12@@Z ??0GrowthInfoLowerBound@container_internal@absl@@QAE@E@Z ??0HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QAE@PBE@Z + ??0HashtableCapacity@container_internal@absl@@AAE@W4InvalidCapacity@012@@Z + ??0HashtableCapacity@container_internal@absl@@QAE@I@Z + ??0HashtableCapacity@container_internal@absl@@QAE@Uuninitialized_tag_t@12@@Z + ??0HashtableInlineData@container_internal@absl@@QAE@VHashtableCapacity@12@Uno_seed_empty_tag_t@12@@Z ??0HashtablezInfo@container_internal@absl@@QAE@XZ ??0HashtablezInfoHandle@container_internal@absl@@QAE@$$T@Z ??0Hex@absl@@AAE@W4PadSpec@1@_K@Z @@ -2180,11 +2147,12 @@ EXPORTS ??0PrefixCrc@CrcCordState@crc_internal@absl@@QAE@XZ ??0ProtoField@log_internal@absl@@QAE@XZ ??0Randen@random_internal@absl@@QAE@XZ + ??0RawHashSetLayout@container_internal@absl@@AAE@Uuninitialized_tag_t@12@@Z ??0RawHashSetLayout@container_internal@absl@@QAE@III_NI@Z ??0ReaderMutexLock@absl@@QAE@AAVMutex@1@@Z + ??0ReentranceGuard@container_internal@absl@@QAE@AAVCommonFields@12@@Z ??0RefcountAndFlags@cord_internal@absl@@QAE@XZ ??0RefcountedRep@CrcCordState@crc_internal@absl@@QAE@XZ - ??0ReleasableMutexLock@absl@@QAE@AAVMutex@1@@Z ??0Rep@CordBuffer@absl@@QAE@PAUCordRepFlat@cord_internal@2@@Z ??0Rep@CordBuffer@absl@@QAE@XZ ??0Rep@CrcCordState@crc_internal@absl@@QAE@XZ @@ -2383,6 +2351,7 @@ EXPORTS ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAE@XZ ??1?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ + ??1?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ @@ -2444,8 +2413,8 @@ EXPORTS ??1Payload@status_internal@absl@@QAE@XZ ??1PosixTimeZone@cctz@time_internal@absl@@QAE@XZ ??1ReaderMutexLock@absl@@QAE@XZ + ??1ReentranceGuard@container_internal@absl@@QAE@XZ ??1RefcountedRep@CrcCordState@crc_internal@absl@@QAE@XZ - ??1ReleasableMutexLock@absl@@QAE@XZ ??1Rep@CrcCordState@crc_internal@absl@@QAE@XZ ??1Rep@GraphCycles@synchronization_internal@absl@@QAE@XZ ??1Rep@StatusBuilder@absl@@QAE@XZ @@ -2583,7 +2552,6 @@ EXPORTS ??8strings_internal@absl@@YA_NABV?$SplitIterator@V?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@@01@0@Z ??9CharIterator@Cord@absl@@QBE_NABV012@@Z ??9ChunkIterator@Cord@absl@@QBE_NABV012@@Z - ??9GraphId@synchronization_internal@absl@@QBE_NABU012@@Z ??9__Cr@std@@YA_NABU__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NABV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@H@__Cr@std@@@01@0@Z ??9__Cr@std@@YA_NABV?$__map_iterator@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@H@__Cr@std@@@01@0@Z @@ -2606,7 +2574,6 @@ EXPORTS ??A?$Span@$$CBVFormatArgImpl@str_format_internal@absl@@@absl@@QBEABVFormatArgImpl@str_format_internal@1@I@Z ??A?$Span@D@absl@@QBEAADI@Z ??A?$Span@I@absl@@QBEAAII@Z - ??A?$__farray@P6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@__Cr@std@@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@456@@Z$03@__Cr@std@@QBEABQ6AI$$QAU?$__value_visitor@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@@__variant@__visitation@__variant_detail@12@AAV?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@612@@ZI@Z ??A?$__wrap_iter@PAPAVCommandLineFlag@absl@@@__Cr@std@@QBEAAPAVCommandLineFlag@absl@@H@Z ??A?$__wrap_iter@PAPAVCordzHandle@cord_internal@absl@@@__Cr@std@@QBEAAPAVCordzHandle@cord_internal@absl@@H@Z ??A?$__wrap_iter@PAPAVLogSink@absl@@@__Cr@std@@QBEAAPAVLogSink@absl@@H@Z @@ -2638,6 +2605,7 @@ EXPORTS ??B?$function@$$A6A_NABVCommandLineFlag@absl@@@Z@__Cr@std@@QBE_NXZ ??B?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ??B?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ ??B?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ @@ -2677,6 +2645,7 @@ EXPORTS ??C?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAULogMessageData@LogMessage@log_internal@absl@@XZ ??C?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QBEPAURep@StatusBuilder@absl@@XZ ??C?$unique_ptr@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@U?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@@__Cr@std@@QBEPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@XZ + ??C?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAVFlagSaverImpl@flags_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAVTimeZoneIf@cctz@time_internal@absl@@XZ ??C?$unique_ptr@VTimeZoneInfo@cctz@time_internal@absl@@U?$default_delete@VTimeZoneInfo@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBEPAVTimeZoneInfo@cctz@time_internal@absl@@XZ ??CChunkIterator@Cord@absl@@QBEPBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ @@ -2718,6 +2687,7 @@ EXPORTS ??D?$move_iterator@PAUTransition@cctz@time_internal@absl@@@__Cr@std@@QBE$$QAUTransition@cctz@time_internal@absl@@XZ ??D?$move_iterator@PAUTransitionType@cctz@time_internal@absl@@@__Cr@std@@QBE$$QAUTransitionType@cctz@time_internal@absl@@XZ ??D?$move_iterator@PAVSourceLocation@absl@@@__Cr@std@@QBE$$QAVSourceLocation@absl@@XZ + ??DCharIterator@Cord@absl@@QBEABDXZ ??DChunkIterator@Cord@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ??D__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QBE?AU__deque_block_range@123@XZ ??Dabsl@@YA?AVint128@0@V10@0@Z @@ -2803,6 +2773,7 @@ EXPORTS ??Pabsl@@YA_NVint128@0@0@Z ??Pabsl@@YA_NVuint128@0@0@Z ??R<lambda_1>@?0???$?RV?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@12@$0A@@__copy_impl@__Cr@std@@QBE?AU?$__in_out_result@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@23@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@23@0V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@23@@Z@QBE?A?<auto>@@PBUPrefixCrc@CrcCordState@crc_internal@absl@@2@Z + ??R<lambda_1>@?0???$AssertSameContainer@X@container_internal@absl@@YAXABQBW4ctrl_t@12@0PBX1PBE2@Z@QBE?A?<auto>@@_NPBD@Z ??R<lambda_1>@?0???$IntegerToString@H@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@H@Z@QBE?A?<auto>@@PADI@Z ??R<lambda_1>@?0???$IntegerToString@I@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@I@Z@QBE?A?<auto>@@PADI@Z ??R<lambda_1>@?0???$IntegerToString@J@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@J@Z@QBE?A?<auto>@@PADI@Z @@ -2814,8 +2785,6 @@ EXPORTS ??R<lambda_1>@?0???$__emplace_unique@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QAE?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@H@__Cr@std@@_N@23@ABUpiecewise_construct_t@23@$$QAV?$tuple@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QAV?$tuple@$$V@23@@Z@QBE?A?<auto>@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QAE?AU?$pair@V?$__hash_iterator@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@_N@23@ABUpiecewise_construct_t@23@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QAV?$tuple@$$V@23@@Z@QBE?A?<auto>@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z ??R<lambda_1>@?0???$__emplace_unique@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$tuple@$$V@23@@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QAE?AU?$pair@V?$__tree_iterator@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@H@__Cr@std@@_N@23@ABUpiecewise_construct_t@23@$$QAV?$tuple@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@$$QAV?$tuple@$$V@23@@Z@QBE?A?<auto>@@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@23@012@Z - ??R<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@Z@QBE?A?<auto>@@XZ - ??R<lambda_1>@?0???$construct@ABUpiecewise_construct_t@__Cr@std@@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@V?$tuple@$$QAPAVCommandLineFlag@absl@@@23@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@ABUpiecewise_construct_t@__Cr@std@@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@67@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@67@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV123@AAI@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@ABV723@AAI@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@ABQAVCommandLineFlag@absl@@@?$vector@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@ABQAV45@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@ABQAVCordzHandle@cord_internal@absl@@@?$vector@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCordzHandle@cord_internal@absl@@ABQAV456@@Z@QBE?A?<auto>@@XZ @@ -2829,11 +2798,9 @@ EXPORTS ??R<lambda_1>@?0???$emplace_back@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAEAAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@$$QAV423@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0???$emplace_back@W4Source@UnrecognizedFlag@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QAEAAUUnrecognizedFlag@absl@@$$QAW4Source@45@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@@Z@QBE?A?<auto>@@XZ ??R<lambda_1>@?0??Append@FormatSinkImpl@str_format_internal@absl@@QAEXID@Z@QBE?A?<auto>@@I@Z - ??R<lambda_1>@?0??AssertSameContainer@container_internal@absl@@YAXABQBW4ctrl_t@23@0PBX1PBE2@Z@QBE?A?<auto>@@_NPBD@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@ABEHABV23@II@Z@QBE?A?<auto>@@PAVChunkIterator@23@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??R<lambda_1>@?0??CompareSlowPath@Cord@absl@@ABEHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@II@Z@QBE?A?<auto>@@PAVChunkIterator@23@PAV456@@Z ??R<lambda_1>@?0??SaveFromRegistry@FlagSaverImpl@flags_internal@absl@@QAEXXZ@QBE?A?<auto>@@AAVCommandLineFlag@4@@Z - ??R<lambda_1>@?0??transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@34@0@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV123@AAI@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUViableSubstitution@strings_internal@absl@@AAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@ABV723@AAI@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@ABQAVCommandLineFlag@absl@@@?$vector@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@ABQAV45@@Z@QBE?A?<auto>@@XZ ??R<lambda_2>@?0???$emplace_back@ABQAVCordzHandle@cord_internal@absl@@@?$vector@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAPAVCordzHandle@cord_internal@absl@@ABQAV456@@Z@QBE?A?<auto>@@XZ @@ -2850,7 +2817,6 @@ EXPORTS ??R?$ConvertToContainer@V?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V?$allocator@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@ABV123@@Z ??R?$FunctionRef@$$A6AII@Z@absl@@QBEII@Z ??R?$FunctionRef@$$A6AXPAUCordRep@cord_internal@absl@@II@Z@absl@@QBEXPAUCordRep@cord_internal@1@II@Z - ??R?$FunctionRef@$$A6AXPAXPBX@Z@absl@@QBEXPAXPBX@Z ??R?$FunctionRef@$$A6AXPBW4ctrl_t@container_internal@absl@@PAX@Z@absl@@QBEXPBW4ctrl_t@container_internal@1@PAX@Z ??R?$FunctionRef@$$A6AXV?$Span@I@absl@@@Z@absl@@QBEXV?$Span@I@1@@Z ??R?$FunctionRef@$$A6AXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z@absl@@QBEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -2879,6 +2845,7 @@ EXPORTS ??R?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@QBEXPAURep@StatusBuilder@absl@@@Z ??R?$default_delete@V?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@__Cr@std@@QBEXPAV?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@@Z ??R?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@QBEXPAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ??R?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@QBEXPAVFlagSaverImpl@flags_internal@absl@@@Z ??R?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@QBEXPAVFlagState@flags_internal@absl@@@Z ??R?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@QBEXPAVFlagStateInterface@flags_internal@absl@@@Z ??R?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@QBEXPAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -2945,6 +2912,7 @@ EXPORTS ??_5uint128@absl@@QAEAAV01@V01@@Z ??_6uint128@absl@@QAEAAV01@V01@@Z ??_DOStringStream@strings_internal@absl@@QAEXXZ + ??_EClock@absl@@UAEPAXI@Z ??_ECordzHandle@cord_internal@absl@@MAEPAXI@Z ?AbsDuration@absl@@YA?AVDuration@1@V21@@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3033,6 +3001,7 @@ EXPORTS ?AlwaysTrue@Condition@absl@@CA_NPBV12@@Z ?AnnotateConstruct@NonEmptyInlinedStorage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QAEXI@Z ?AnnotateDestruct@NonEmptyInlinedStorage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QAEXI@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AAEXAAV123@ABUPolicyFunctions@23@@Z ?Append@Cord@absl@@QAEX$$QAV12@@Z ?Append@Cord@absl@@QAEXABV12@@Z ?Append@Cord@absl@@QAEXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3060,24 +3029,22 @@ EXPORTS ?AppendTruncated@log_internal@absl@@YAIV?$basic_string_view@_WU?$char_traits@_W@__Cr@std@@@__Cr@std@@AAV?$Span@D@2@@Z ?ApplyMask@MaskedPointer@flags_internal@absl@@AAEXI@Z ?ApplySubstitutions@strings_internal@absl@@YAHV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@45@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@45@@Z - ?AreItersFromSameContainer@container_internal@absl@@YA_NABQBW4ctrl_t@12@0PBX1@Z ?AsValueType@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@CAPADPAD@Z ?AsciiStrToLower@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToLower@ascii_internal@absl@@YAXPADPBDI@Z ?AsciiStrToUpper@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPADPBDI@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAAVCommonFields@12@PBXP6AI1PAXI@ZI_NI1P6A_N212@Z@Z ?AssertHeld@CordzInfo@cord_internal@absl@@QAEXXZ ?AssertHeld@Mutex@absl@@QBEXXZ ?AssertHeld@SpinLock@base_internal@absl@@QBEXXZ ?AssertInSooMode@CommonFields@container_internal@absl@@ABEXXZ - ?AssertIsFull@container_internal@absl@@YAXABQBW4ctrl_t@12@PBXEPBEPBD@Z - ?AssertIsValidForComparison@container_internal@absl@@YAXABQBW4ctrl_t@12@PBXEPBE@Z + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotDebugCapacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@IBEXXZ ?AssertNotDebugCapacity@CommonFields@container_internal@absl@@QBEXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotHeld@Mutex@absl@@QBEXXZ ?AssertReaderHeld@Mutex@absl@@QBEXXZ - ?AssertSameContainer@container_internal@absl@@YAXABQBW4ctrl_t@12@0PBX1PBE2@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPAV123@PAV123@_N@Z ?AssertValid@CordRepBtree@cord_internal@absl@@SAPBV123@PBV123@_N@Z ?AssertValidType@FlagImpl@flags_internal@absl@@QBEXVFastTypeIdType@3@P6APBVtype_info@@XZ@Z @@ -3116,6 +3083,7 @@ EXPORTS ?CalculateBase64EscapedLenInternal@strings_internal@absl@@YAII_N@Z ?CallVoidPtrFunction@Condition@absl@@CA_NPBV12@@Z ?Capacity@CordRepFlat@cord_internal@absl@@QBEIXZ + ?CapacityBits@HashtableInlineData@container_internal@absl@@CA_KVHashtableCapacity@23@@Z ?CapacityToGrowth@container_internal@absl@@YAII@Z ?CappedDamerauLevenshteinDistance@strings_internal@absl@@YAEV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0E@Z ?CatPieces@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$initializer_list@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@5@@Z @@ -3189,7 +3157,7 @@ EXPORTS ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QAE_NABUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?ConvertSpecialToEmptyAndFullToDeleted@GroupSse2Impl@container_internal@absl@@QBEXPAW4ctrl_t@23@@Z ?Copy@CordRepBtree@cord_internal@absl@@ABEPAV123@XZ - ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@V?$FunctionRef@$$A6AXPAXPBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@P6AXPAX3PBX@Z@Z ?Copy@flags_internal@absl@@YAXP6APAXW4FlagOp@12@PBXPAX2@Z12@Z ?CopyBeginTo@CordRepBtree@cord_internal@absl@@ABEPAV123@II@Z ?CopyConstruct@flags_internal@absl@@YAXP6APAXW4FlagOp@12@PBXPAX2@Z12@Z @@ -3210,8 +3178,9 @@ EXPORTS ?CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@3@PIAXPIBXIV43@_N@Z ?Create@CordRepBtree@cord_internal@absl@@SAPAV123@PAUCordRep@23@@Z ?Create@CordRepFlat@cord_internal@absl@@SAPAU123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@I@Z - ?CreateDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ - ?CreateReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@XZ + ?CreateDestroyed@HashtableCapacity@container_internal@absl@@SA?AV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@III_N@Z + ?CreateReentrance@HashtableCapacity@container_internal@absl@@SA?AV123@XZ ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPAV123@PAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPAUThreadIdentity@base_internal@2@XZ @@ -3235,6 +3204,8 @@ EXPORTS ?DeallocateIfAllocated@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXXZ ?DeallocateIfAllocated@?$Storage@VFormatArgImpl@str_format_internal@absl@@$03V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXXZ ?DeallocateIfAllocated@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXXZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QAE_NPAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -3284,6 +3255,7 @@ EXPORTS ?Digits10@?$BigUnsigned@$0FE@@strings_internal@absl@@SAHXZ ?DisableFlagfileAndEnvParsing@absl@@YAXXZ ?DisableRescheduling@SchedulingGuard@base_internal@absl@@SA_NXZ + ?Distance@Cord@absl@@SAHABVCharIterator@12@0@Z ?DoIgnoreLeak@absl@@YAXPBX@Z ?DoLoad@?$AtomicHook@P6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@23@ABVCord@absl@@@Z@base_internal@absl@@ABEP6A?AV?$optional@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABVCord@3@@ZXZ ?DoLoad@?$AtomicHook@P6AXPBDH000@Z@base_internal@absl@@ABEP6AXPBDH000@ZXZ @@ -3372,6 +3344,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QBE?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UBEXPAIPBXI@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UBEXPAIPIAXPIBXI_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UBEXPAII@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPAIIQBI1@Z ?ExtendCrc32c@absl@@YA?AVcrc32c_t@1@V21@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -3412,7 +3385,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QAEPAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@ABE?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QBEHUGraphId@23@0HQAU423@@Z @@ -3501,7 +3473,7 @@ EXPORTS ?FromHost64@little_endian@absl@@YA_K_K@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0DM@$00@__Cr@std@@@Z ?FromInt64@time_internal@absl@@YA?AVDuration@2@_JV?$ratio@$0OBA@$00@__Cr@std@@@Z - ?FromRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@SA?AV123@_K@Z + ?FromRawData@HashtableCapacity@container_internal@absl@@SA?AV123@_K@Z ?FromTM@absl@@YA?AVTime@1@ABUtm@@VTimeZone@1@@Z ?FromUDate@absl@@YA?AVTime@1@N@Z ?FromUniversal@absl@@YA?AVTime@1@_J@Z @@ -3577,6 +3549,7 @@ EXPORTS ?GetGrowthLeft@GrowthInfoLowerBound@container_internal@absl@@QBEEXZ ?GetGrowthLeftLowerBound@CommonFields@container_internal@absl@@QBEIXZ ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QBEII@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SAIPAXI@Z ?GetHashtablezMaxSamples@container_internal@absl@@YAIXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QAE?AUGraphId@23@PAX@Z @@ -3768,7 +3741,7 @@ EXPORTS ?IsDataLoss@absl@@YA_NABVStatus@1@@Z ?IsDeadlineExceeded@absl@@YA_NABVStatus@1@@Z ?IsDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z - ?IsDestroyed@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ + ?IsDestroyed@HashtableCapacity@container_internal@absl@@QBE_NXZ ?IsEmpty@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsEmptyOrDeleted@container_internal@absl@@YA_NW4ctrl_t@12@@Z ?IsExternal@CordRep@cord_internal@absl@@QBE_NXZ @@ -3796,7 +3769,7 @@ EXPORTS ?IsPermissionDenied@absl@@YA_NABVStatus@1@@Z ?IsPow2@CordBuffer@absl@@CA_NI@Z ?IsReachable@GraphCycles@synchronization_internal@absl@@QBE_NUGraphId@23@0@Z - ?IsReentrance@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ + ?IsReentrance@HashtableCapacity@container_internal@absl@@QBE_NXZ ?IsResourceExhausted@absl@@YA_NABVStatus@1@@Z ?IsRetired@CommandLineFlag@absl@@UBE_NXZ ?IsSMTEnabled@base_internal@absl@@YA_NXZ @@ -3812,8 +3785,8 @@ EXPORTS ?IsUnimplemented@absl@@YA_NABVStatus@1@@Z ?IsUnknown@absl@@YA_NABVStatus@1@@Z ?IsUnprotectedReadCandidate@MaskedPointer@flags_internal@absl@@QBE_NXZ - ?IsValid@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ ?IsValid@CordRepBtree@cord_internal@absl@@SA_NPBV123@_N@Z + ?IsValid@HashtableCapacity@container_internal@absl@@QBE_NXZ ?IsValidCapacity@container_internal@absl@@YA_NI@Z ?IterateOverFullSlots@container_internal@absl@@YAXABVCommonFields@12@IV?$FunctionRef@$$A6AXPBW4ctrl_t@container_internal@absl@@PAX@Z@2@@Z ?JoinMessageToStatus@StatusPrivateAccessorForStatusBuilder@status_internal@absl@@SA?AVStatus@3@V43@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@W4MessageJoinStyle@3@@Z @@ -3971,6 +3944,7 @@ EXPORTS ?NumClonedBytes@container_internal@absl@@YAIXZ ?NumContextsPerCPU@base_internal@absl@@YAHXZ ?NumControlBytes@container_internal@absl@@YAII@Z + ?NumControlBytesForLargeTable@container_internal@absl@@YAII@Z ?NumGenerationBytes@container_internal@absl@@YAIXZ ?NumLeakedFlagValues@flags_internal@absl@@YA_KXZ ?ODRCheck@CordzInfo@cord_internal@absl@@ABEXXZ @@ -4023,9 +3997,9 @@ EXPORTS ?Post@Win32Waiter@synchronization_internal@absl@@QAEXXZ ?PrecombineLengthMix@hash_internal@absl@@YA_K_KI@Z ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QAEX_JIIIG@Z - ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6AII@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@V?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@I@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@IV?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@PAXP6AI2I@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z ?Prepend@Cord@absl@@QAEXABV12@@Z @@ -4355,6 +4329,7 @@ EXPORTS ?TakeRep@Cord@absl@@AHAEPAUCordRep@cord_internal@2@XZ ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QAEXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QAEX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -4418,9 +4393,8 @@ EXPORTS ?ToInt64Nanoseconds@absl@@YA_JVDuration@1@@Z ?ToInt64Seconds@absl@@YA_JVDuration@1@@Z ?ToOpResult@CordRepBtree@cord_internal@absl@@AAE?AUOpResult@123@_N@Z - ?ToPublicSeed@?$HashtableInlineDataImpl@$00@container_internal@absl@@CA_K_K@Z - ?ToRawData@?$HashtableCapacityImpl@$00@container_internal@absl@@QBEEXZ ?ToRawData@GrowthInfoLowerBound@container_internal@absl@@QBEEXZ + ?ToRawData@HashtableCapacity@container_internal@absl@@QBEEXZ ?ToSinkAlso@LogMessage@log_internal@absl@@QAEAAV123@PAVLogSink@3@@Z ?ToSinkOnly@LogMessage@log_internal@absl@@QAEAAV123@PAVLogSink@3@@Z ?ToString@?$BigUnsigned@$03@strings_internal@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -4703,7 +4677,6 @@ EXPORTS ?__annotate_shrink_back@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@ABEXII@Z ?__annotate_whole_block@?$deque@PBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@ABEXIW4__asan_annotation_type@123@@Z ?__annotate_whole_block@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@ABEXIW4__asan_annotation_type@123@@Z - ?__as_base@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@IGAE@XZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QBEIXZ ?__back_spare@?$__split_buffer_pointer_layout@V?$__split_buffer@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QBEIXZ ?__back_spare@?$__split_buffer_size_layout@V?$__split_buffer@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_size_layout@67@@__Cr@std@@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@23@@__Cr@std@@QBEIXZ @@ -4810,6 +4783,17 @@ EXPORTS ?__destruct_at_end@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXPAUTransition@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXPAUTransitionType@cctz@time_internal@absl@@@Z ?__destruct_at_end@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@AAEXPAUViableSubstitution@strings_internal@absl@@@Z + ?__empty@?$__vector_layout@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PAVCordzHandle@cord_internal@absl@@V?$allocator@PAVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@PBVCordzHandle@cord_internal@absl@@V?$allocator@PBVCordzHandle@cord_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UConversionItem@ParsedFormatBase@str_format_internal@absl@@V?$allocator@UConversionItem@ParsedFormatBase@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QBE_NXZ + ?__empty@?$__vector_layout@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBE_NXZ ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PAU1234@AAU1234@PAPAU1234@H$0A@@__Cr@std@@@__Cr@std@@SAPAUPrefixCrc@CrcCordState@crc_internal@absl@@PBQAU4567@@Z ?__end@?$__segmented_iterator_traits@V?$__deque_iterator@UPrefixCrc@CrcCordState@crc_internal@absl@@PBU1234@ABU1234@PBQBU1234@H$0A@@__Cr@std@@@__Cr@std@@SAPBUPrefixCrc@CrcCordState@crc_internal@absl@@PBQAU4567@@Z ?__end_node@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QAEPAV?$__tree_end_node@PAV?$__tree_node_base@PAX@__Cr@std@@@23@XZ @@ -5234,8 +5218,8 @@ EXPORTS ?begin@CordRepBtree@cord_internal@absl@@QBEIXZ ?begin@Storage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEPADXZ ?begin@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QBE?AU1234@XZ - ?blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBEIXZ ?blocked_element_count@CommonFields@container_internal@absl@@QBEIXZ + ?blocked_element_count@HashtableInlineData@container_internal@absl@@QBEIXZ ?btree@CordRep@cord_internal@absl@@QAEPAVCordRepBtree@23@XZ ?btree@CordRep@cord_internal@absl@@QBEPBVCordRepBtree@23@XZ ?btree@CordRepBtreeNavigator@cord_internal@absl@@QBEPAVCordRepBtree@23@XZ @@ -5243,8 +5227,6 @@ EXPORTS ?bucket_count@?$__hash_table@PBUCordRep@cord_internal@absl@@U?$hash@PBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PBUCordRep@cord_internal@absl@@@56@V?$allocator@PBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QBEIXZ ?bucket_count@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QBEIXZ ?bytes_value@ProtoField@log_internal@absl@@QBE?AV?$Span@$$CBD@3@XZ - ?capacity@?$HashtableCapacityImpl@$00@container_internal@absl@@QBEIXZ - ?capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE?AV?$HashtableCapacityImpl@$00@23@XZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@23@@__Cr@std@@QBEIXZ ?capacity@?$__split_buffer_pointer_layout@V?$__split_buffer@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@23@@__Cr@std@@QBEIXZ ?capacity@?$__split_buffer_size_layout@V?$__split_buffer@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@__Cr@std@@V__split_buffer_size_layout@45@@__Cr@std@@PAVCommandLineFlag@absl@@V?$allocator@PAVCommandLineFlag@absl@@@23@@__Cr@std@@QBEIXZ @@ -5273,7 +5255,9 @@ EXPORTS ?capacity@CommonFields@container_internal@absl@@QBEIXZ ?capacity@CordBuffer@absl@@QBEIXZ ?capacity@CordRepBtree@cord_internal@absl@@QBEIXZ - ?capacity_impl@CommonFields@container_internal@absl@@QBE?AV?$HashtableCapacityImpl@$00@23@XZ + ?capacity@HashtableCapacity@container_internal@absl@@QBEIXZ + ?capacity@HashtableInlineData@container_internal@absl@@QBE?AVHashtableCapacity@23@XZ + ?capacity_impl@CommonFields@container_internal@absl@@QBE?AVHashtableCapacity@23@XZ ?cbegin@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBEPBUPayload@status_internal@2@XZ ?cbegin@?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QBE?AV?$__wrap_iter@PBQAVLogSink@absl@@@23@XZ ?cend@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBEPBUPayload@status_internal@2@XZ @@ -5436,8 +5420,8 @@ EXPORTS ?deallocate@?$allocator_traits@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@PAV?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@23@I@Z ?deallocate@?$allocator_traits@V?$allocator@VFormatArgImpl@str_format_internal@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@VFormatArgImpl@str_format_internal@absl@@@23@PAVFormatArgImpl@str_format_internal@absl@@I@Z ?deallocate@?$allocator_traits@V?$allocator@VSourceLocation@absl@@@__Cr@std@@@__Cr@std@@SAXAAV?$allocator@VSourceLocation@absl@@@23@PAVSourceLocation@absl@@I@Z - ?decrement_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ ?decrement_size@CommonFields@container_internal@absl@@QAEXXZ + ?decrement_size@HashtableInlineData@container_internal@absl@@QAEXXZ ?delimiter@?$Splitter@VByAnyChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBEABVByAnyChar@3@XZ ?delimiter@?$Splitter@VByAnyChar@absl@@USkipEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBEABVByAnyChar@3@XZ ?delimiter@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBEABVByChar@3@XZ @@ -5452,7 +5436,6 @@ EXPORTS ?effective_impl@time_zone@cctz@time_internal@absl@@ABEABVImpl@1234@XZ ?element@?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@SAAAU?$pair@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@__Cr@std@@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@Z ?emplace@?$map_slot_policy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@CAXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@@Z - ?empty@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ ?empty@?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QBE_NXZ ?empty@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBE_NXZ ?empty@?$InlinedVector@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@absl@@QBE_NXZ @@ -5477,6 +5460,7 @@ EXPORTS ?empty@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBE_NXZ ?empty@CommonFields@container_internal@absl@@QBE_NXZ ?empty@Cord@absl@@QBE_NXZ + ?empty@HashtableInlineData@container_internal@absl@@QBE_NXZ ?encoded_message@LogEntry@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?encoded_remaining@LogMessageData@LogMessage@log_internal@absl@@QAEAAV?$Span@D@4@XZ ?end@?$BitMask@I$0BA@$0A@$0A@@container_internal@absl@@QBE?AV123@XZ @@ -5531,7 +5515,6 @@ EXPORTS ?end@CordRepBtree@cord_internal@absl@@QBEIXZ ?end@Storage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEPADXZ ?end@__deque_range@?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QBE?AU1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4UArchSpecificEngines@234@B ?eq_ref@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABEABUStringEq@23@XZ ?erase@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QAEPAUPayload@status_internal@2@PBU342@@Z ?erase@?$vector@PAVLogSink@absl@@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@__Cr@std@@QAE?AV?$__wrap_iter@PAPAVLogSink@absl@@@23@V?$__wrap_iter@PBQAVLogSink@absl@@@23@@Z @@ -5555,8 +5538,8 @@ EXPORTS ?gbswap_16@absl@@YAGG@Z ?gbswap_32@absl@@YAII@Z ?gbswap_64@absl@@YA_K_K@Z - ?generate_new_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ ?generate_new_seed@CommonFields@container_internal@absl@@QAEX_N@Z + ?generate_new_seed@HashtableInlineData@container_internal@absl@@QAEXXZ ?generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QBEEXZ ?generation@HashSetIteratorGenerationInfoDisabled@container_internal@absl@@QBEEXZ ?generation_offset@RawHashSetLayout@container_internal@absl@@QBEIXZ @@ -5608,10 +5591,8 @@ EXPORTS ?get@?$__temp_value@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUTransition@cctz@time_internal@absl@@XZ ?get@?$__temp_value@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEAAUTransitionType@cctz@time_internal@absl@@XZ ?get@?$__tuple_leaf@$00AAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@$0A@@__Cr@std@@QAEAAV?$NonIterableBitMask@I$0BA@$0A@@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@$$QAPAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AAPAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@AAUFindInfo@container_internal@absl@@$0A@@__Cr@std@@QAEAAUFindInfo@container_internal@absl@@XZ - ?get@?$__tuple_leaf@$0A@ABQAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEABQAVCommandLineFlag@absl@@XZ ?get@?$__tuple_leaf@$0A@PAVCommandLineFlag@absl@@$0A@@__Cr@std@@QAEAAPAVCommandLineFlag@absl@@XZ ?get@?$unique_ptr@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QBEPAPBVImpl@time_zone@cctz@time_internal@absl@@XZ ?get@?$unique_ptr@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$__allocator_destructor@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QBEPAUPrefixCrc@CrcCordState@crc_internal@absl@@XZ @@ -5651,10 +5632,10 @@ EXPORTS ?get_soo_data@HeapOrSoo@container_internal@absl@@QBEPBXXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@ABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z ?get_yearday@detail@cctz@time_internal@absl@@YAHABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z - ?growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE?AVGrowthInfoLowerBound@23@XZ + ?growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QBE?AVGrowthInfoLowerBound@23@XZ ?has_alt_flag@FormatConversionSpecImpl@str_format_internal@absl@@QBE_NXZ - ?has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ ?has_infoz@CommonFields@container_internal@absl@@QBE_NXZ + ?has_infoz@HashtableInlineData@container_internal@absl@@QBE_NXZ ?has_left_flag@FormatConversionSpecImpl@str_format_internal@absl@@QBE_NXZ ?has_parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QBE_NXZ ?has_show_pos_flag@FormatConversionSpecImpl@str_format_internal@absl@@QBE_NXZ @@ -5674,22 +5655,24 @@ EXPORTS ?hour@?$civil_time@Uhour_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ ?hour@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ ?hour@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ - ?increment_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXI@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXI@Z - ?increment_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ + ?increment_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QAEXI@Z ?increment_size@CommonFields@container_internal@absl@@QAEXI@Z ?increment_size@CommonFields@container_internal@absl@@QAEXXZ + ?increment_size@HashtableInlineData@container_internal@absl@@QAEXI@Z + ?increment_size@HashtableInlineData@container_internal@absl@@QAEXXZ ?index@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QBEIXZ ?index@?$probe_seq@$0BA@@container_internal@absl@@QBEIXZ + ?index@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QBEIXZ ?index@CordRepBtree@cord_internal@absl@@QBEIW4EdgeType@123@@Z ?infoz@CommonFields@container_internal@absl@@QAE?AVHashtablezInfoHandle@23@XZ + ?infoz_from_control@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@PAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@XZ - ?init_blocked_element_count@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEX_K@Z ?init_blocked_element_count@CommonFields@container_internal@absl@@QAEXI@Z + ?init_blocked_element_count@HashtableInlineData@container_internal@absl@@QAEX_K@Z ?inline_size@InlineData@cord_internal@absl@@QBEIXZ ?inline_size@InlineRep@Cord@absl@@ABEIXZ ?inline_size@Rep@InlineData@cord_internal@absl@@QBEIXZ - ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@$$QAU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@56@@Z + ?insert@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QAE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABU?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@56@@Z ?insert@?$unordered_set@PBUCordRep@cord_internal@absl@@U?$hash@PBUCordRep@cord_internal@absl@@@__Cr@std@@U?$equal_to@PBUCordRep@cord_internal@absl@@@56@V?$allocator@PBUCordRep@cord_internal@absl@@@56@@__Cr@std@@QAE?AU?$pair@V?$__hash_const_iterator@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@__Cr@std@@_N@23@ABQBUCordRep@cord_internal@absl@@@Z ?int32_value@ProtoField@log_internal@absl@@QBEHXZ ?int64_value@ProtoField@log_internal@absl@@QBE_JXZ @@ -5704,13 +5687,13 @@ EXPORTS ?is_length@ConvTag@str_format_internal@absl@@QBE_NXZ ?is_profiled@InlineData@cord_internal@absl@@QBE_NXZ ?is_relative_timeout@KernelTimeout@synchronization_internal@absl@@QBE_NXZ - ?is_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ + ?is_sampled_seed@HashtableInlineData@container_internal@absl@@QBE_NXZ ?is_short@Rep@CordBuffer@absl@@QBE_NXZ ?is_single_group@container_internal@absl@@YA_NI@Z - ?is_small@?$HashtableCapacityImpl@$00@container_internal@absl@@QBE_NXZ - ?is_small@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE_NXZ ?is_small@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE_NXZ ?is_small@CommonFields@container_internal@absl@@QBE_NXZ + ?is_small@HashtableCapacity@container_internal@absl@@QBE_NXZ + ?is_small@HashtableInlineData@container_internal@absl@@QBE_NXZ ?is_snapshot@CordzHandle@cord_internal@absl@@QBE_NXZ ?is_soo@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE_NXZ ?is_tree@InlineData@cord_internal@absl@@QBE_NXZ @@ -5769,8 +5752,8 @@ EXPORTS ?max_size@?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@QBEIXZ ?max_size@?$vector@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@V?$allocator@V?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QBEIXZ ?maybe_increment_generation_on_insert@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXXZ - ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE?AV?$HashtableCapacityImpl@$00@23@XZ - ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QBE?AV?$HashtableCapacityImpl@$00@23@XZ + ?maybe_invalid_capacity@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@ABE?AVHashtableCapacity@23@XZ + ?maybe_invalid_capacity@CommonFields@container_internal@absl@@QBE?AVHashtableCapacity@23@XZ ?memcasecmp@strings_internal@absl@@YAHPBD0I@Z ?message@Status@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ ?message@StatusRep@status_internal@absl@@QBEABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ @@ -5802,10 +5785,10 @@ EXPORTS ?ok@Status@absl@@QBE_NXZ ?ok@Utf8ForCodePoint@debugging_internal@absl@@QBE_NXZ ?overflow@Streambuf@OStringStream@strings_internal@absl@@MAEHH@Z - ?overwrite_control_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXW4ctrl_t@23@@Z - ?overwrite_empty_as_full@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ - ?overwrite_full_as_deleted@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ - ?overwrite_full_as_empty_in_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ + ?overwrite_control_as_full@HashtableInlineData@container_internal@absl@@QAEXW4ctrl_t@23@@Z + ?overwrite_empty_as_full@HashtableInlineData@container_internal@absl@@QAEXXZ + ?overwrite_full_as_deleted@HashtableInlineData@container_internal@absl@@QAEXXZ + ?overwrite_full_as_empty_in_lower_bound@HashtableInlineData@container_internal@absl@@QAEXXZ ?parse@detail@cctz@time_internal@absl@@YA_NABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0ABVtime_zone@234@PAV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@PAV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@chrono@67@PAV567@@Z ?parsed_conversion@UntypedFormatSpecImpl@str_format_internal@absl@@QBEPBVParsedFormatBase@23@XZ ?pointer_to@?$pointer_traits@PAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@__Cr@std@@@__Cr@std@@SAPAU?$__hash_node_base@PAU?$__hash_node@PBUCordRep@cord_internal@absl@@PAX@__Cr@std@@@23@AAU423@@Z @@ -5848,6 +5831,7 @@ EXPORTS ?push_back@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXABUTransition@cctz@time_internal@absl@@@Z ?push_back@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QAEXABUUnrecognizedFlag@absl@@@Z ?raw_code@Status@absl@@QBEHXZ + ?read_byte@HashtableInlineData@container_internal@absl@@ABEEI@Z ?reduce_size@InlineRep@Cord@absl@@QAEXI@Z ?release@?$unique_ptr@$$CBVImpl@time_zone@cctz@time_internal@absl@@U?$default_delete@$$CBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEPBVImpl@time_zone@cctz@time_internal@absl@@XZ ?release@?$unique_ptr@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$__allocator_destructor@V?$allocator@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@@__Cr@std@@QAEPAPBVImpl@time_zone@cctz@time_internal@absl@@XZ @@ -5891,6 +5875,7 @@ EXPORTS ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAEXPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@PAX@23@@Z ?reset@?$unique_ptr@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@V?$__tree_node_destructor@V?$allocator@V?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@__Cr@std@@@__Cr@std@@@23@@__Cr@std@@QAEXPAV?$__tree_node@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@PAX@23@@Z ?reset@?$unique_ptr@VFallbackCrcMemcpyEngine@crc_internal@absl@@U?$default_delete@VFallbackCrcMemcpyEngine@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFallbackCrcMemcpyEngine@crc_internal@absl@@@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagSaverImpl@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagState@flags_internal@absl@@U?$default_delete@VFlagState@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagState@flags_internal@absl@@@Z ?reset@?$unique_ptr@VFlagStateInterface@flags_internal@absl@@U?$default_delete@VFlagStateInterface@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagStateInterface@flags_internal@absl@@@Z ?reset@?$unique_ptr@VTimeZoneIf@cctz@time_internal@absl@@U?$default_delete@VTimeZoneIf@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVTimeZoneIf@cctz@time_internal@absl@@@Z @@ -5916,17 +5901,19 @@ EXPORTS ?scale_add@impl@detail@cctz@time_internal@absl@@YA_J_J00@Z ?second@?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ ?second@?$civil_time@Usecond_tag@time_internal@absl@@@detail@cctz@time_internal@absl@@QBEHXZ - ?seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBE?AVPerTableSeed@23@XZ ?seed@CommonFields@container_internal@absl@@QBE?AVPerTableSeed@23@XZ + ?seed@HashtableInlineData@container_internal@absl@@QBE?AVPerTableSeed@23@XZ ?seed@PerTableSeed@container_internal@absl@@QBEIXZ ?set@?$MaybeInitializedPtr@W4ctrl_t@container_internal@absl@@@container_internal@absl@@QAEXPAW4ctrl_t@23@@Z ?set_arg@BoundConversion@str_format_internal@absl@@QAEXPBVFormatArgImpl@23@@Z ?set_begin@CordRepBtree@cord_internal@absl@@AAEXI@Z - ?set_blocked_element_count_to_zero@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ ?set_blocked_element_count_to_zero@CommonFields@container_internal@absl@@QAEXXZ - ?set_capacity@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXV?$HashtableCapacityImpl@$00@23@@Z + ?set_blocked_element_count_to_zero@HashtableInlineData@container_internal@absl@@QAEXXZ ?set_capacity@CommonFields@container_internal@absl@@QAEXI@Z - ?set_capacity@CommonFields@container_internal@absl@@QAEXV?$HashtableCapacityImpl@$00@23@@Z + ?set_capacity@CommonFields@container_internal@absl@@QAEXVHashtableCapacity@23@@Z + ?set_capacity@CommonFields@container_internal@absl@@QCEXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QAEXVHashtableCapacity@23@@Z + ?set_capacity@HashtableInlineData@container_internal@absl@@QCEXVHashtableCapacity@23@@Z ?set_control@CommonFields@container_internal@absl@@QAEXPAW4ctrl_t@23@@Z ?set_conversion_char@FormatConversionSpecImpl@str_format_internal@absl@@QAEXW4FormatConversionChar@3@@Z ?set_cordz_info@InlineData@cord_internal@absl@@QAEXPAVCordzInfo@23@@Z @@ -5940,9 +5927,9 @@ EXPORTS ?set_full_soo@CommonFields@container_internal@absl@@QAEXXZ ?set_generation@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXE@Z ?set_generation_ptr@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXPAE@Z - ?set_growth_info_lower_bound@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXVGrowthInfoLowerBound@23@@Z - ?set_has_infoz@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ + ?set_growth_info_lower_bound@HashtableInlineData@container_internal@absl@@QAEXVGrowthInfoLowerBound@23@@Z ?set_has_infoz@CommonFields@container_internal@absl@@QAEXXZ + ?set_has_infoz@HashtableInlineData@container_internal@absl@@QAEXXZ ?set_infoz@CommonFields@container_internal@absl@@QAEXVHashtablezInfoHandle@23@@Z ?set_inline_data@InlineData@cord_internal@absl@@QAEXPBDI@Z ?set_inline_size@InlineData@cord_internal@absl@@QAEXI@Z @@ -5950,10 +5937,10 @@ EXPORTS ?set_inline_size@Rep@InlineData@cord_internal@absl@@QAEXI@Z ?set_reservation_size@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXI@Z ?set_reserved_growth@CommonFieldsGenerationInfoDisabled@container_internal@absl@@QAEXI@Z - ?set_sampled_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXXZ - ?set_seed@?$HashtableInlineDataImpl@$00@container_internal@absl@@AAEXE@Z + ?set_sampled_seed@HashtableInlineData@container_internal@absl@@QAEXXZ + ?set_seed@HashtableInlineData@container_internal@absl@@AAEXE@Z ?set_short_length@Rep@CordBuffer@absl@@QAEXI@Z - ?set_size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QAEXI@Z + ?set_size@HashtableInlineData@container_internal@absl@@QAEXI@Z ?set_size_to_zero@CommonFields@container_internal@absl@@QAEXXZ ?set_tag@Rep@InlineData@cord_internal@absl@@QAEXC@Z ?set_tree@InlineData@cord_internal@absl@@QAEXPAUCordRep@23@@Z @@ -5966,11 +5953,11 @@ EXPORTS ?shrink_to_fit@?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@__Cr@std@@QAEXXZ ?shrink_to_fit@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXXZ ?single_iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@123@XZ + ?single_non_soo_slot@CommonFields@container_internal@absl@@QBEPAXXZ ?single_slot@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@XZ ?size@?$BigUnsigned@$03@strings_internal@absl@@QBEHXZ ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QBEHXZ ?size@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEIXZ - ?size@?$HashtableInlineDataImpl@$00@container_internal@absl@@QBEIXZ ?size@?$InlinedVector@PAUCordRep@cord_internal@absl@@$01V?$allocator@PAUCordRep@cord_internal@absl@@@__Cr@std@@@absl@@QBEIXZ ?size@?$InlinedVector@PAVLogSink@absl@@$0BA@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@absl@@QBEIXZ ?size@?$InlinedVector@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@absl@@QBEIXZ @@ -6015,6 +6002,7 @@ EXPORTS ?size@CommonFields@container_internal@absl@@QBEIXZ ?size@Cord@absl@@QBEIXZ ?size@CordRepBtree@cord_internal@absl@@QBEIXZ + ?size@HashtableInlineData@container_internal@absl@@QBEIXZ ?size@InlineRep@Cord@absl@@QBEIXZ ?size@Storage@?$FixedArray@D$0PPPPPPPP@V?$allocator@D@__Cr@std@@@absl@@QBEIXZ ?skip_empty_or_deleted@iterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXXZ @@ -6064,7 +6052,7 @@ EXPORTS ?timestamp@LogEntry@absl@@QBE?AVTime@2@XZ ?total_written@BufferRawSink@str_format_internal@absl@@QBEIXZ ?transfer@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAEXPAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@23@0@Z - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2P6AX2EII@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2IP6AX2II@Z@Z ?tree@InlineRep@Cord@absl@@QBEPAUCordRep@cord_internal@3@XZ ?tree@Rep@InlineData@cord_internal@absl@@QBEPAUCordRep@34@XZ ?try_lock@Mutex@absl@@QAE_NXZ @@ -6083,8 +6071,6 @@ EXPORTS ?value@InputValue@UnboundConversion@str_format_internal@absl@@QBEHXZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@__Cr@std@@@23@@__Cr@std@@QAEAAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$map@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ ?value_comp@?$__tree@U?$__value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@V?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@__Cr@std@@@23@@__Cr@std@@QAEAAV?$__map_value_compare@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$vector@PBVCommandLineFlag@absl@@V?$allocator@PBVCommandLineFlag@absl@@@__Cr@std@@@23@@23@U?$less@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@XZ - ?valueless_by_exception@?$__base@$0A@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__variant_detail@__Cr@std@@QBE_NXZ - ?valueless_by_exception@?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@QBE_NXZ ?verbosity@LogEntry@absl@@QBEHXZ ?version@time_zone@cctz@time_internal@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?what@BadStatusOrAccess@absl@@UBEPBDXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x86_rel.def b/deps/v8/third_party/abseil-cpp/symbols_x86_rel.def index 21daed61911d..9ccdf3f5609a 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x86_rel.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x86_rel.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QAE@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$?6C@LogMessage@log_internal@absl@@QAEAAV012@ABC@Z @@ -23,8 +22,6 @@ EXPORTS ??$?BV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@XZ ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CC@$$CBD@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CG@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CG@$$CBD@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CH@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CH@$$CBD@Z @@ -42,6 +39,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QAEX$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@ABVCord@absl@@@Cord@absl@@AAEXABV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AAEX$$QAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NABQBW4ctrl_t@01@0PBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBEPBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXABQBW4ctrl_t@01@0PBX1PBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@12@I@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@base_internal@absl@@YAXPAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QAP8FlagImpl@flags_internal@1@AEXXZ$$QAPAV671@@Z @@ -107,6 +108,8 @@ EXPORTS ??$EmplaceBackSlow@ABQAVLogSink@absl@@@?$Storage@PAVLogSink@absl@@$0BA@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AAEAAPAVLogSink@2@ABQAV32@@Z ??$EmplaceBackSlow@ABVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AAEAAVSourceLocation@2@ABV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AAEAAUPayload@status_internal@2@$$QAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@ABV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPAXW4FlagOp@01@PBXPAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -116,10 +119,9 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHABVCord@0@0I@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NABVCord@0@0I@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$InvokeObject@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@II@functional_internal@absl@@YAITVoidPtr@01@I@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z ??$JoinAlgorithm@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@34@0V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@UNoFormatter@01@@Z ??$MakeCheckOpString@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@ABV123@@log_internal@absl@@YAPBDABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PBD@Z ??$MakeCheckOpString@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV123@@log_internal@absl@@YAPBDABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PBD@Z @@ -230,8 +232,9 @@ EXPORTS ??$emplace_front@PAPBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QAEX$$QAPAPBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$emplace_front@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QAEX$$QAPAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QAE?AV?$__hash_iterator@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QAE@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QAE@XZ ??0?$BigUnsigned@$03@strings_internal@absl@@QAE@_K@Z @@ -310,7 +313,6 @@ EXPORTS ??0uint128@absl@@QAE@O@Z ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1CRC@crc_internal@absl@@UAE@XZ ??1Clock@absl@@UAE@XZ ??1Cord@absl@@QAE@XZ @@ -330,6 +332,7 @@ EXPORTS ??1Mutex@absl@@QAE@XZ ??1Notification@absl@@QAE@XZ ??1OstreamView@LogMessage@log_internal@absl@@UAE@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QAE@XZ ??1Rep@StatusBuilder@absl@@QAE@XZ ??1ScopedMinLogLevel@log_internal@absl@@QAE@XZ ??1ScopedStderrThreshold@absl@@QAE@XZ @@ -413,6 +416,7 @@ EXPORTS ??_0Duration@absl@@QAEAAV01@N@Z ??_0Duration@absl@@QAEAAV01@_J@Z ??_1Duration@absl@@QAEAAV01@V01@@Z + ??_EClock@absl@@UAEPAXI@Z ??_ECordzHandle@cord_internal@absl@@MAEPAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAAVStatusBuilder@1@W4StatusCode@1@@Z @@ -467,6 +471,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPAXI@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPAXIPAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AAEXAAV123@ABUPolicyFunctions@23@@Z ?Append@Cord@absl@@QAEX$$QAV12@@Z ?Append@Cord@absl@@QAEXABV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPAV123@PAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@I@Z @@ -491,7 +496,9 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPADPBDI@Z ?AsciiStrToUpper@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPADPBDI@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAAVCommonFields@12@PBXP6AI1PAXI@ZI_NI1P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QBEXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotHeld@Mutex@absl@@QBEXXZ ?AssertReaderHeld@Mutex@absl@@QBEXXZ @@ -567,7 +574,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NNABVFormatConversionSpecImpl@12@PAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOABVFormatConversionSpecImpl@12@PAVFormatSinkImpl@12@@Z ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QAE_NABUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@V?$FunctionRef@$$A6AXPAXPBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@P6AXPAX3PBX@Z@Z ?CopyCordToSpan@absl@@YAIABVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXABVCord@1@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AAE?AUCopyResult@123@I_N@Z @@ -575,6 +582,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@ABEXPAD@Z ?Crash@Helper@internal_statusor@absl@@SAXABVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@III_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPAV123@PAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPAUThreadIdentity@base_internal@2@XZ @@ -582,6 +590,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@ABEAAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QAE_NPAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -664,6 +674,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QBE?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UBEXPAIPBXI@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UBEXPAIPIAXPIBXI_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UBEXPAII@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPAIIQBI1@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@I@Z @@ -703,7 +714,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QAEPAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@ABE?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QBEHUGraphId@23@0HQAU423@@Z @@ -799,6 +809,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPAUCordRep@cord_internal@2@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QBEII@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SAIPAXI@Z ?GetHashtablezMaxSamples@container_internal@absl@@YAIXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QAE?AUGraphId@23@PAX@Z @@ -1028,9 +1039,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QAEXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QAEXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QAEX_JIIIG@Z - ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6AII@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@V?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@I@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@IV?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@PAXP6AI2I@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z ?Prepend@Cord@absl@@QAEXABV12@@Z @@ -1230,6 +1241,7 @@ EXPORTS ?Symbolize@absl@@YA_NPBXPADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QAEXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QAEX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1398,13 +1410,13 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@ABEABVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@ABV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@ABV567@ABV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@ABV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@ABVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PBD0AAMW4chars_format@1@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PBD0AANW4chars_format@1@@Z ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@ABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@PAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PAVtime_zone@123@@Z @@ -1425,6 +1437,7 @@ EXPORTS ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?reserve@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagSaverImpl@flags_internal@absl@@@Z ?resize@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?resize@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?safe_strto128_base@numbers_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVint128@2@H@Z @@ -1447,7 +1460,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QBEHXZ ?status@BadStatusOrAccess@absl@@QBEABVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QAEAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2P6AX2EII@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2IP6AX2II@Z@Z ?try_lock@Mutex@absl@@QAE_NXZ ?try_lock_shared@Mutex@absl@@QAE_NXZ ?unlock@Mutex@absl@@QAEXXZ diff --git a/deps/v8/third_party/abseil-cpp/symbols_x86_rel_cxx23.def b/deps/v8/third_party/abseil-cpp/symbols_x86_rel_cxx23.def index f944dd5b7d4d..4f591baba727 100644 --- a/deps/v8/third_party/abseil-cpp/symbols_x86_rel_cxx23.def +++ b/deps/v8/third_party/abseil-cpp/symbols_x86_rel_cxx23.def @@ -1,5 +1,4 @@ EXPORTS - ?$TSS0@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4HA ??$?0$$V$0A@@?$NoDestructor@V?$SampleRecorder@UHashtablezInfo@container_internal@absl@@@profiling_internal@absl@@@absl@@QAE@XZ ??$?0V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QAE@$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$?6C@LogMessage@log_internal@absl@@QAEAAV012@ABC@Z @@ -23,8 +22,6 @@ EXPORTS ??$?BV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@$0A@@?$Splitter@VByChar@absl@@UAllowEmpty@2@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@strings_internal@absl@@QBE?AV?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@XZ ??$?MUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z ??$?OUsecond_tag@detail@cctz@time_internal@absl@@U01234@@detail@cctz@time_internal@absl@@YA_NABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@0123@0@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z - ??$?RV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABUpiecewise_construct_t@12@V?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@12@V?$tuple@$$QAPAVCommandLineFlag@absl@@@12@@EmplaceDecomposable@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@QBE?AU?$pair@Viterator@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@ABUpiecewise_construct_t@56@$$QAV?$tuple@$$QBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@56@$$QAV?$tuple@$$QAPAVCommandLineFlag@absl@@@56@@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CC@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CC@$$CBD@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CG@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CG@$$CBD@Z ??$?RW4LogSeverity@absl@@ABQBDHAAY0CH@$$CBD@?$AtomicHook@P6AXW4LogSeverity@absl@@PBDHABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z@base_internal@absl@@QBEX$$QAW4LogSeverity@2@ABQBD$$QAHAAY0CH@$$CBD@Z @@ -42,6 +39,10 @@ EXPORTS ??$Append@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@$0A@@Cord@absl@@QAEX$$QAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ??$AppendImpl@ABVCord@absl@@@Cord@absl@@AAEXABV01@@Z ??$AppendImpl@VCord@absl@@@Cord@absl@@AAEX$$QAV01@@Z + ??$AreItersFromSameContainer@X@container_internal@absl@@YA_NABQBW4ctrl_t@01@0PBX1@Z + ??$AssertIsFull@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBEPBD@Z + ??$AssertIsValidForComparison@X@container_internal@absl@@YAXABQBW4ctrl_t@01@PBXEPBE@Z + ??$AssertSameContainer@X@container_internal@absl@@YAXABQBW4ctrl_t@01@0PBX1PBE2@Z ??$Assign@V?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@inlined_vector_internal@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@QAEXV?$IteratorValueAdapter@V?$allocator@VSourceLocation@absl@@@__Cr@std@@PBVSourceLocation@absl@@@12@I@Z ??$CallOnceImpl@A6AXXZ$$V@base_internal@absl@@YAXPAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@A6AXXZ@Z ??$CallOnceImpl@P8FlagImpl@flags_internal@absl@@AEXXZPAV123@@base_internal@absl@@YAXPAU?$atomic@I@__Cr@std@@W4SchedulingMode@01@$$QAP8FlagImpl@flags_internal@1@AEXXZ$$QAPAV671@@Z @@ -107,6 +108,8 @@ EXPORTS ??$EmplaceBackSlow@ABQAVLogSink@absl@@@?$Storage@PAVLogSink@absl@@$0BA@V?$allocator@PAVLogSink@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AAEAAPAVLogSink@2@ABQAV32@@Z ??$EmplaceBackSlow@ABVSourceLocation@absl@@@?$Storage@VSourceLocation@absl@@$00V?$allocator@VSourceLocation@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AAEAAVSourceLocation@2@ABV32@@Z ??$EmplaceBackSlow@UPayload@status_internal@absl@@@?$Storage@UPayload@status_internal@absl@@$00V?$allocator@UPayload@status_internal@absl@@@__Cr@std@@@inlined_vector_internal@absl@@AAEAAUPayload@status_internal@2@$$QAU342@@Z + ??$FindImpl@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$FindImpl@VCord@absl@@@Cord@absl@@ABE?AVCharIterator@01@V201@ABV01@@Z ??$FindSubstitutions@V?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@std@@@strings_internal@absl@@YA?AV?$vector@UViableSubstitution@strings_internal@absl@@V?$allocator@UViableSubstitution@strings_internal@absl@@@__Cr@std@@@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@ABV?$initializer_list@U?$pair@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V123@@__Cr@std@@@4@@Z ??$FlagOps@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPAXW4FlagOp@01@PBXPAX2@Z ??$Flush@V?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@FormatRawSinkImpl@str_format_internal@absl@@CAXPAXV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z @@ -116,10 +119,9 @@ EXPORTS ??$GenRuntimeTypeId@V?$vector@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@__Cr@std@@@flags_internal@absl@@YAPBVtype_info@@XZ ??$GenericCompare@HVCord@absl@@@absl@@YAHABVCord@0@0I@Z ??$GenericCompare@_NVCord@absl@@@absl@@YA_NABVCord@0@0I@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@V?$FunctionRef@$$A6AII@Z@1@_N@Z - ??$InvokeObject@AAU?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@II@functional_internal@absl@@YAITVoidPtr@01@I@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$00$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$03$00@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z + ??$GrowSooTableToNextCapacityAndPrepareInsert@$0A@$0A@@container_internal@absl@@YAPAXAAVCommonFields@01@ABUPolicyFunctions@01@PAXP6AI2I@Z_N@Z ??$JoinAlgorithm@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@34@0V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@34@UNoFormatter@01@@Z ??$MakeCheckOpString@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@ABV123@@log_internal@absl@@YAPBDABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@0PBD@Z ??$MakeCheckOpString@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@ABV123@@log_internal@absl@@YAPBDABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@0PBD@Z @@ -229,9 +231,9 @@ EXPORTS ??$emplace_front@PAPBVImpl@time_zone@cctz@time_internal@absl@@@?$__split_buffer@PAPBVImpl@time_zone@cctz@time_internal@absl@@V?$allocator@PAPBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@78@@__Cr@std@@QAEX$$QAPAPBVImpl@time_zone@cctz@time_internal@absl@@@Z ??$emplace_front@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@?$__split_buffer@PAUPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@PAUPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@V__split_buffer_pointer_layout@67@@__Cr@std@@QAEX$$QAPAUPrefixCrc@CrcCordState@crc_internal@absl@@@Z ??$find@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@?$__hash_table@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@V?$__unordered_map_hasher@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$__unordered_map_equal@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@23@U?$equal_to@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@U?$hash@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@23@@23@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@@23@@__Cr@std@@QAE?AV?$__hash_iterator@PAU?$__hash_node@U?$__hash_value_type@V?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PBVImpl@time_zone@cctz@time_internal@absl@@@__Cr@std@@PAX@__Cr@std@@@12@ABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@12@@Z - ??$find_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ??$find_or_prepare_insert_large@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@ABV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z - ??$resize_and_overwrite@V<lambda_1>@?0???$JoinAlgorithm@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@56@0V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@56@UNoFormatter@23@@Z@@?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@QAEXIV<lambda_1>@?0???$JoinAlgorithm@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@__Cr@std@@X@strings_internal@absl@@YA?AV012@V?$__wrap_iter@PBV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@12@0V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@12@UNoFormatter@45@@Z@@Z + ??$find_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AViterator@012@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z + ??$find_or_prepare_insert_large@$$CBV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@AAE?AU?$pair@PAT?$map_slot_type@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@_N@__Cr@std@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@45@@Z + ??$visit@UBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@34@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@__Cr@std@@X@__Cr@std@@YA?A_T$$QAUBufferSizeVisitor@?1??BufferSizeForStructuredProtoField@log_internal@absl@@YAIUStructuredProtoField@45@@Z@AAV?$variant@V?$variant@_K_JIH_N@__Cr@std@@V?$variant@_K_JN@23@V?$Span@$$CBD@absl@@V?$variant@IHM@23@@01@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QAE@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ??0?$BigUnsigned@$03@strings_internal@absl@@QAE@XZ ??0?$BigUnsigned@$03@strings_internal@absl@@QAE@_K@Z @@ -310,7 +312,6 @@ EXPORTS ??0uint128@absl@@QAE@O@Z ??1?$deque@UPrefixCrc@CrcCordState@crc_internal@absl@@V?$allocator@UPrefixCrc@CrcCordState@crc_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1?$unique_ptr@ULogMessageData@LogMessage@log_internal@absl@@U?$default_delete@ULogMessageData@LogMessage@log_internal@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ - ??1?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@QAE@XZ ??1CRC@crc_internal@absl@@UAE@XZ ??1Clock@absl@@UAE@XZ ??1Cord@absl@@QAE@XZ @@ -330,6 +331,7 @@ EXPORTS ??1Mutex@absl@@QAE@XZ ??1Notification@absl@@QAE@XZ ??1OstreamView@LogMessage@log_internal@absl@@UAE@XZ + ??1Rep@GraphCycles@synchronization_internal@absl@@QAE@XZ ??1Rep@StatusBuilder@absl@@QAE@XZ ??1ScopedMinLogLevel@log_internal@absl@@QAE@XZ ??1ScopedStderrThreshold@absl@@QAE@XZ @@ -413,6 +415,7 @@ EXPORTS ??_0Duration@absl@@QAEAAV01@N@Z ??_0Duration@absl@@QAEAAV01@_J@Z ??_1Duration@absl@@QAEAAV01@V01@@Z + ??_EClock@absl@@UAEPAXI@Z ??_ECordzHandle@cord_internal@absl@@MAEPAXI@Z ?AbslFormatFlush@detect_specialization@log_internal@absl@@YAXPAVStringifySink@123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?AbslInternalSetErrorCode@absl@@YAXAAVStatusBuilder@1@W4StatusCode@1@@Z @@ -467,6 +470,7 @@ EXPORTS ?Alloc@LowLevelAlloc@base_internal@absl@@SAPAXI@Z ?AllocWithArena@LowLevelAlloc@base_internal@absl@@SAPAXIPAUArena@123@@Z ?AlwaysTrue@Condition@absl@@CA_NPBV12@@Z + ?AnnotateForBugDetectionOnMoveImpl@CommonFields@container_internal@absl@@AAEXAAV123@ABUPolicyFunctions@23@@Z ?Append@Cord@absl@@QAEX$$QAV12@@Z ?Append@Cord@absl@@QAEXABV12@@Z ?Append@CordRepBtree@cord_internal@absl@@SAPAV123@PAV123@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@I@Z @@ -491,7 +495,9 @@ EXPORTS ?AsciiStrToLower@ascii_internal@absl@@YAXPADPBDI@Z ?AsciiStrToUpper@absl@@YAXPAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?AsciiStrToUpper@ascii_internal@absl@@YAXPADPBDI@Z + ?AssertHashEqConsistentImpl@container_internal@absl@@YAXAAVCommonFields@12@PBXP6AI1PAXI@ZI_NI1P6A_N212@Z@Z ?AssertHeld@Mutex@absl@@QBEXXZ + ?AssertInSooModeImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotDebugCapacityImpl@CommonFields@container_internal@absl@@ABEXXZ ?AssertNotHeld@Mutex@absl@@QBEXXZ ?AssertReaderHeld@Mutex@absl@@QBEXXZ @@ -567,7 +573,7 @@ EXPORTS ?ConvertFloatImpl@str_format_internal@absl@@YA_NNABVFormatConversionSpecImpl@12@PAVFormatSinkImpl@12@@Z ?ConvertFloatImpl@str_format_internal@absl@@YA_NOABVFormatConversionSpecImpl@12@PAVFormatSinkImpl@12@@Z ?ConvertOne@ParsedFormatConsumer@ParsedFormatBase@str_format_internal@absl@@QAE_NABUUnboundConversion@34@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z - ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@V?$FunctionRef@$$A6AXPAXPBX@Z@2@@Z + ?Copy@container_internal@absl@@YAXAAVCommonFields@12@ABUPolicyFunctions@12@ABV312@P6AXPAX3PBX@Z@Z ?CopyCordToSpan@absl@@YAIABVCord@1@V?$Span@D@1@@Z ?CopyCordToString@absl@@YAXABVCord@1@PAV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@@Z ?CopyPrefix@CordRepBtree@cord_internal@absl@@AAE?AUCopyResult@123@I_N@Z @@ -575,6 +581,7 @@ EXPORTS ?CopyToArraySlowPath@Cord@absl@@ABEXPAD@Z ?Crash@Helper@internal_statusor@absl@@SAXABVStatus@3@@Z ?Crc32c@CRC@crc_internal@absl@@SAPAV123@XZ + ?CreateForSmallNonSooGrowth@RawHashSetLayout@container_internal@absl@@SA?AV123@III_N@Z ?CreateSlow@CordRepBtree@cord_internal@absl@@CAPAV123@PAUCordRep@23@@Z ?CreateStatusAndConditionallyLog@StatusBuilder@absl@@CA?AVStatus@2@VSourceLocation@2@V?$unique_ptr@URep@StatusBuilder@absl@@U?$default_delete@URep@StatusBuilder@absl@@@__Cr@std@@@__Cr@std@@@Z ?CreateThreadIdentity@synchronization_internal@absl@@YAPAUThreadIdentity@base_internal@2@XZ @@ -582,6 +589,8 @@ EXPORTS ?CurrentThreadIdentityIfPresent@base_internal@absl@@YAPAUThreadIdentity@12@XZ ?CurrentValue@FlagImpl@flags_internal@absl@@EBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?DataGuard@FlagImpl@flags_internal@absl@@ABEAAVMutex@3@XZ + ?DebugReportNonTemporalStore@crc_internal@absl@@YAXXZ + ?DebugReportStoreFence@crc_internal@absl@@YAXXZ ?DecodeFrom@ProtoField@log_internal@absl@@QAE_NPAV?$Span@$$CBD@3@@Z ?DecodeRustPunycode@debugging_internal@absl@@YAPADUDecodeRustPunycodeOptions@12@@Z ?DecodeWaitCycles@SpinLock@base_internal@absl@@KA_JI@Z @@ -664,6 +673,7 @@ EXPORTS ?ExitOnDFatal@log_internal@absl@@YA_NXZ ?ExpectedChecksum@Cord@absl@@QBE?AV?$optional@I@__Cr@std@@XZ ?Extend@CRC32@crc_internal@absl@@UBEXPAIPBXI@Z + ?ExtendAndCopy@CRC@crc_internal@absl@@UBEXPAIPIAXPIBXI_N@Z ?ExtendByZeroes@CRC32@crc_internal@absl@@UBEXPAII@Z ?ExtendByZeroesImpl@CRC32@crc_internal@absl@@CAXPAIIQBI1@Z ?ExtendCrc32cByZeroes@absl@@YA?AVcrc32c_t@1@V21@I@Z @@ -703,7 +713,6 @@ EXPORTS ?FindCommandLineFlag@absl@@YAPAVCommandLineFlag@1@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlag@FlagRegistry@flags_internal@absl@@QAEPAVCommandLineFlag@3@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindFlatStartPiece@InlineRep@Cord@absl@@QBE?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?FindImpl@Cord@absl@@ABE?AVCharIterator@12@V312@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?FindLongestCommonPrefix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindLongestCommonSuffix@absl@@YA?AV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@V234@0@Z ?FindPath@GraphCycles@synchronization_internal@absl@@QBEHUGraphId@23@0HQAU423@@Z @@ -799,6 +808,7 @@ EXPORTS ?GetFlagsHelpMode@flags_internal@absl@@YA?AW4HelpMode@12@XZ ?GetFlatAux@Cord@absl@@CA_NPAUCordRep@cord_internal@2@PAV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@@Z ?GetGrowthLeftTotalSlow@CommonFields@container_internal@absl@@QBEII@Z + ?GetHash@?$HashKey@UStringHash@container_internal@absl@@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@$00$0A@@container_internal@absl@@SAIPAXI@Z ?GetHashtablezMaxSamples@container_internal@absl@@YAIXZ ?GetHashtablezSampleParameter@container_internal@absl@@YAHXZ ?GetId@GraphCycles@synchronization_internal@absl@@QAE?AUGraphId@23@PAX@Z @@ -1028,9 +1038,9 @@ EXPORTS ?Post@StdcppWaiter@synchronization_internal@absl@@QAEXXZ ?Post@Win32Waiter@synchronization_internal@absl@@QAEXXZ ?PrepareForSampling@HashtablezInfo@container_internal@absl@@QAEX_JIIIG@Z - ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@@Z - ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@UFindInfo@12@V?$FunctionRef@$$A6AII@Z@2@@Z - ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@V?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertLarge@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@I@Z + ?PrepareInsertLargeGenerationsEnabled@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@IV?$NonIterableBitMask@I$0BA@$0A@@12@IV?$FunctionRef@$$A6AII@Z@2@@Z + ?PrepareInsertSmallNonSoo@container_internal@absl@@YAPAXAAVCommonFields@12@ABUPolicyFunctions@12@PAXP6AI2I@Z@Z ?PrepareToDie@LogMessage@log_internal@absl@@AAEXXZ ?PrepareToModify@Status@absl@@CAPAVStatusRep@status_internal@2@I@Z ?Prepend@Cord@absl@@QAEXABV12@@Z @@ -1230,6 +1240,7 @@ EXPORTS ?Symbolize@absl@@YA_NPBXPADH@Z ?TestOnlyAddNodes@GraphCycles@synchronization_internal@absl@@QAEXI@Z ?TestOnlyRefreshSamplingStateForCurrentThread@container_internal@absl@@YAXXZ + ?TestOnlySetRankStride@GraphCycles@synchronization_internal@absl@@QAEX_J@Z ?ThreadIsLoggingToLogSink@log_internal@absl@@YA_NXZ ?ThrowBadStatusOrAccess@internal_statusor@absl@@YAXVStatus@2@@Z ?ThrowSeedGenException@random_internal@absl@@YAXXZ @@ -1398,13 +1409,13 @@ EXPORTS ?day_difference@impl@detail@cctz@time_internal@absl@@YA_J_JCC0CC@Z ?description@time_zone@cctz@time_internal@absl@@QBE?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@XZ ?effective_impl@time_zone@cctz@time_internal@absl@@ABEABVImpl@1234@XZ - ?engines@?1??CrcAndCopy@CrcMemcpy@crc_internal@absl@@SA?AVcrc32c_t@4@PIAXPIBXIV54@_N@Z@4UArchSpecificEngines@234@B ?fixed_time_zone@cctz@time_internal@absl@@YA?AVtime_zone@123@ABV?$duration@_JV?$ratio@$00$00@__Cr@std@@@chrono@__Cr@std@@@Z ?format@detail@cctz@time_internal@absl@@YA?AV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@ABV567@ABV?$time_point@Vsystem_clock@chrono@__Cr@std@@V?$duration@_JV?$ratio@$00$00@__Cr@std@@@234@@chrono@67@ABV?$duration@_JV?$ratio@$00$0DINHOKEMGIAAA@@__Cr@std@@@967@ABVtime_zone@234@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PBD0AAMW4chars_format@1@@Z ?from_chars@absl@@YA?AUfrom_chars_result@1@PBD0AANW4chars_format@1@@Z ?get_cordz_mean_interval@cord_internal@absl@@YAHXZ ?get_weekday@detail@cctz@time_internal@absl@@YA?AW4weekday@1234@ABV?$civil_time@Usecond_tag@detail@cctz@time_internal@absl@@@1234@@Z + ?infoz_from_control@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@PAW4ctrl_t@23@@Z ?infoz_ptr@CommonFields@container_internal@absl@@QBE?AVHashtablezInfoHandle@23@XZ ?kDefaultIterSlot@container_internal@absl@@3DA ?load_time_zone@cctz@time_internal@absl@@YA_NABV?$basic_string@DU?$char_traits@D@__Cr@std@@V?$allocator@D@23@@__Cr@std@@PAVtime_zone@123@@Z @@ -1425,6 +1436,7 @@ EXPORTS ?reserve@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?reserve@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?reserve@?$vector@UUnrecognizedFlag@absl@@V?$allocator@UUnrecognizedFlag@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z + ?reset@?$unique_ptr@VFlagSaverImpl@flags_internal@absl@@U?$default_delete@VFlagSaverImpl@flags_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXPAVFlagSaverImpl@flags_internal@absl@@@Z ?resize@?$vector@UTransition@cctz@time_internal@absl@@V?$allocator@UTransition@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?resize@?$vector@UTransitionType@cctz@time_internal@absl@@V?$allocator@UTransitionType@cctz@time_internal@absl@@@__Cr@std@@@__Cr@std@@QAEXI@Z ?safe_strto128_base@numbers_internal@absl@@YA_NV?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVint128@2@H@Z @@ -1447,7 +1459,7 @@ EXPORTS ?size@?$BigUnsigned@$0FE@@strings_internal@absl@@QBEHXZ ?status@BadStatusOrAccess@absl@@QBEABVStatus@2@XZ ?stream@OstreamView@LogMessage@log_internal@absl@@QAEAAV?$basic_ostream@DU?$char_traits@D@__Cr@std@@@__Cr@std@@XZ - ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2P6AX2EII@Z@Z + ?transfer_unprobed_elements_to_next_capacity_fn@?$raw_hash_set@U?$FlatHashMapPolicy@V?$basic_string_view@DU?$char_traits@D@__Cr@std@@@__Cr@std@@PAVCommandLineFlag@absl@@@container_internal@absl@@$$V@container_internal@absl@@CAXAAVCommonFields@23@PBW4ctrl_t@23@PAX2IP6AX2II@Z@Z ?try_lock@Mutex@absl@@QAE_NXZ ?try_lock_shared@Mutex@absl@@QAE_NXZ ?unlock@Mutex@absl@@QAEXXZ diff --git a/deps/v8/third_party/fast_float/src/include/fast_float/ascii_number.h b/deps/v8/third_party/fast_float/src/include/fast_float/ascii_number.h index 52f1e8425f70..28d61130d827 100644 --- a/deps/v8/third_party/fast_float/src/include/fast_float/ascii_number.h +++ b/deps/v8/third_party/fast_float/src/include/fast_float/ascii_number.h @@ -32,7 +32,13 @@ template <typename UC> fastfloat_really_inline constexpr bool has_simd_opt() { // able to optimize it well. template <typename UC> fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { - return static_cast<unsigned>(c - UC('0')) <= 9u; + // UC can be signed (wchar_t is a signed int on Linux and macOS), and the + // subtraction is then promoted to int and overflows for code units near the + // bottom of the range. Subtracting in the unsigned type wraps instead, which + // selects the same code units, as ch_to_digit already does. + using UnsignedUC = typename std::make_unsigned<UC>::type; + return static_cast<UnsignedUC>(static_cast<UnsignedUC>(c) - + static_cast<UnsignedUC>(UC('0'))) <= 9u; } fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { @@ -308,13 +314,16 @@ template <typename UC> struct parsed_number_string_t { int64_t exponent{0}; uint64_t mantissa{0}; UC const *lastmatch{nullptr}; + // The field order matters: placing 'error' next to the booleans avoids + // padding, keeping the struct at 64 bytes on 64-bit systems instead of 72. + // See https://github.com/fastfloat/fast_float/issues/418 + parse_error error{parse_error::no_error}; bool negative{false}; bool valid{false}; bool too_many_digits{false}; // contains the range of the significant digits span<UC const> integer{}; // non-nullable span<UC const> fraction{}; // nullable - parse_error error{parse_error::no_error}; }; using byte_span = span<char const>; @@ -339,10 +348,11 @@ report_parse_error(UC const *p, parse_error error) { // spans (read only by the rare digit_comp slow path) are not materialized, // which keeps the fat parsed_number_string_t off the hot path. The caller // re-parses with store_spans=true if the slow path is actually reached. -template <bool basic_json_fmt, typename UC> +template <bool basic_json_fmt, bool basic_javascript_fmt, typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC> -parse_number_string(UC const *p, UC const *pend, parse_options_t<UC> options, - bool store_spans = true) noexcept { +parse_number_string_impl(UC const *p, UC const *pend, + parse_options_t<UC> options, + bool store_spans) noexcept { chars_format const fmt = detail::adjust_for_feature_macros(options.format); UC const decimal_point = options.decimal_point; @@ -424,7 +434,7 @@ parse_number_string(UC const *p, UC const *pend, parse_options_t<UC> options, parse_error::leading_zeros_in_integer_part); } } - else if (uint64_t(fmt & detail::basic_javascript_fmt)) { + else FASTFLOAT_IF_CONSTEXPR17(basic_javascript_fmt) { // ECMAScript DecimalIntegerLiteral is "0" or a non-zero digit followed by // digits: no leading zeros. Unlike JSON, the integer part may be empty // (".5"); the no_digits_in_mantissa check below still rejects ".". @@ -587,6 +597,40 @@ parse_number_string(UC const *p, UC const *pend, parse_options_t<UC> options, return answer; } +// Cold instantiation of the parser: the ECMAScript integer-part rule costs two +// error returns plus the Annex B octal scan, and parse_number_string_impl is +// force-inlined, so an inlined javascript body would enlarge the frame of every +// caller that never asks for it. Out of line, it costs those callers nothing. +template <typename UC> +fastfloat_never_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC> +parse_number_string_javascript(UC const *p, UC const *pend, + parse_options_t<UC> options, + bool store_spans) noexcept { + return parse_number_string_impl<false, true, UC>(p, pend, options, + store_spans); +} + +// Public entry point, behaviour unchanged: chars_format::javascript is still +// honoured, it is just selected here once instead of being re-tested inside the +// parser loop. Callers that have already ruled the format out (see +// from_chars_float_advanced) should call parse_number_string_impl directly so +// that not even this test reaches their hot path. +template <bool basic_json_fmt, typename UC> +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC> +parse_number_string(UC const *p, UC const *pend, parse_options_t<UC> options, + bool store_spans = true) noexcept { + // JSON and JavaScript are mutually exclusive, so only the non-JSON + // instantiation has to look at the flag. + FASTFLOAT_IF_CONSTEXPR17(!basic_json_fmt) { + if fastfloat_unlikely (uint64_t(options.format & + detail::basic_javascript_fmt)) { + return parse_number_string_javascript<UC>(p, pend, options, store_spans); + } + } + return parse_number_string_impl<basic_json_fmt, false, UC>(p, pend, options, + store_spans); +} + template <typename T, typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC> parse_int_string(UC const *p, UC const *pend, T &value, diff --git a/deps/v8/third_party/fast_float/src/include/fast_float/decimal_to_binary.h b/deps/v8/third_party/fast_float/src/include/fast_float/decimal_to_binary.h index 948768265eb3..5389701b7834 100644 --- a/deps/v8/third_party/fast_float/src/include/fast_float/decimal_to_binary.h +++ b/deps/v8/third_party/fast_float/src/include/fast_float/decimal_to_binary.h @@ -156,10 +156,21 @@ compute_float(int64_t q, uint64_t w) noexcept { return answer; } // next line is safe because -answer.power2 + 1 < 64 - answer.mantissa >>= -answer.power2 + 1; - // Thankfully, we can't have both "round-to-even" and subnormals because - // "round-to-even" only occurs for powers close to 0 in the 32-bit and - // and 64-bit case (with no more than 19 digits). + int const subnormal_shift = -answer.power2 + 1; + answer.mantissa >>= subnormal_shift; + // A subnormal result can also fall exactly between two floats. With at + // most 19 digits this never happens for float and double, but it does for + // std::float16_t (e.g., 2^-25 = 298023223876953125e-25), so we apply the + // same round-to-even test as in the normal case below. + // See script/format_parameters.py. + if (binary::subnormal_ties_possible() && (product.low <= 1) && + (q >= binary::min_exponent_round_to_even()) && + (q <= binary::max_exponent_round_to_even()) && + ((answer.mantissa & 3) == 1)) { + if (((answer.mantissa << subnormal_shift) << shift) == product.high) { + answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up + } + } answer.mantissa += (answer.mantissa & 1); // round up answer.mantissa >>= 1; // There is a weird scenario where we don't have a subnormal but just. @@ -194,16 +205,31 @@ compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa += (answer.mantissa & 1); // round up answer.mantissa >>= 1; - if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) { + // Both fix-ups below are rare. They are marked unlikely so that clang keeps + // them as branches instead of folding them into conditional moves that + // every conversion pays for. +#ifdef __clang__ +#pragma clang diagnostic push +#if (!defined(__APPLE_CC__) && __clang_major__ >= 10) || (__clang_major__ >= 13) +#pragma clang diagnostic ignored "-Wc++20-extensions" +#endif +#endif + if fastfloat_clang_unlikely (answer.mantissa >= + (uint64_t(2) + << binary::mantissa_explicit_bits())) { answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits()); answer.power2++; // undo previous addition } answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits()); - if (answer.power2 >= binary::infinite_power()) { // infinity + if fastfloat_clang_unlikely (answer.power2 >= binary::infinite_power()) { + // infinity answer.power2 = binary::infinite_power(); answer.mantissa = 0; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif return answer; } diff --git a/deps/v8/third_party/fast_float/src/include/fast_float/digit_comparison.h b/deps/v8/third_party/fast_float/src/include/fast_float/digit_comparison.h index 70085bed22b1..6aac9522ee52 100644 --- a/deps/v8/third_party/fast_float/src/include/fast_float/digit_comparison.h +++ b/deps/v8/third_party/fast_float/src/include/fast_float/digit_comparison.h @@ -330,10 +330,6 @@ parse_mantissa(bigint &result, parsed_number_string_t<UC> &num, } } } - - if (counter != 0) { - add_native(result, limb(powers_of_ten_uint64[counter]), value); - } } template <typename T> diff --git a/deps/v8/third_party/fast_float/src/include/fast_float/float_common.h b/deps/v8/third_party/fast_float/src/include/fast_float/float_common.h index 87c72b0ebda8..60c28c7bcb2d 100644 --- a/deps/v8/third_party/fast_float/src/include/fast_float/float_common.h +++ b/deps/v8/third_party/fast_float/src/include/fast_float/float_common.h @@ -18,7 +18,7 @@ #define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MINOR 3 -#define FASTFLOAT_VERSION_PATCH 0 +#define FASTFLOAT_VERSION_PATCH 2 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) @@ -217,6 +217,38 @@ using parse_options = parse_options_t<char>; #define fastfloat_really_inline inline __attribute__((always_inline)) #endif +// Opposite of fastfloat_really_inline. Used for a rare, format-specific variant +// of a force-inlined function, so that its body does not land in the frame of +// every caller that will never execute it. +#ifdef FASTFLOAT_VISUAL_STUDIO +#define fastfloat_never_inline __declspec(noinline) +#elif defined(__GNUC__) || defined(__clang__) +#define fastfloat_never_inline __attribute__((noinline)) +#else +#define fastfloat_never_inline +#endif + +// fastfloat_really_inline under clang only, a no-op elsewhere. Clang declines +// to inline the parser into its callers, so the parser instantiation with a +// compile-time format (from_chars_fixed_format) must force the one thin +// forwarder between it and the parser body. GCC inlines the chain on its own, +// and forcing it there changes its inlining order for the worse. +#ifdef __clang__ +#define fastfloat_clang_really_inline fastfloat_really_inline +#else +#define fastfloat_clang_really_inline +#endif + +// fastfloat_unlikely under clang only, a plain condition elsewhere. Clang +// if-converts rare checks into chains of conditional moves that every +// conversion executes; the hint keeps them as branches. GCC already emits +// branches there, and the hint only reorders its blocks, for the worse. +#ifdef __clang__ +#define fastfloat_clang_unlikely(x) fastfloat_unlikely(x) +#else +#define fastfloat_clang_unlikely(x) (x) +#endif + // Branch-probability hint marking the rare slow-path branches as cold, so the // optimizer keeps the out-of-line slow-path re-parse off the hot path (and does // not duplicate the force-inlined hot scanner into the caller, which bloated @@ -314,147 +346,22 @@ struct is_supported_char_type > { }; -template <typename UC> -inline FASTFLOAT_CONSTEXPR14 bool -fastfloat_strncasecmp3(UC const *actual_mixedcase, - UC const *expected_lowercase) { - uint64_t mask{0}; - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { - mask = 0x0020002000200020; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - mask = 0x0000002000000020; - } - else { - return false; - } - - uint64_t val1{0}, val2{0}; - if (cpp20_and_in_constexpr()) { - for (size_t i = 0; i < 3; i++) { - if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { - return false; - } - } - return true; - } else { - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) { - ::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 3 * sizeof(UC)); - val1 |= mask; - val2 |= mask; - return val1 == val2; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - return (actual_mixedcase[2] | 32) == (expected_lowercase[2]); - } - else { - return false; - } - } -} - -template <typename UC> -inline FASTFLOAT_CONSTEXPR14 bool -fastfloat_strncasecmp5(UC const *actual_mixedcase, - UC const *expected_lowercase) { - uint64_t mask{0}; - uint64_t val1{0}, val2{0}; - if (cpp20_and_in_constexpr()) { - for (size_t i = 0; i < 5; i++) { - if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { - return false; - } - } - return true; - } else { - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { - mask = 0x2020202020202020; - ::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 5 * sizeof(UC)); - val1 |= mask; - val2 |= mask; - return val1 == val2; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { - mask = 0x0020002000200020; - ::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 4 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - mask = 0x0000002000000020; - ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - ::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase + 2, 2 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); - } - else { - return false; - } - } -} - -// Compares two ASCII strings in a case insensitive manner. +// Compares two ASCII strings in a case insensitive manner. The expected +// string is lowercase ASCII, so OR-ing 0x20 into each actual character maps +// 'A'..'Z' onto 'a'..'z' and leaves everything else mismatched. The lengths +// used are tiny constants (3 and 5), so the compiler unrolls this loop; keep +// it small so that the (rarely executed) inf/nan path does not bloat the hot +// parser it is inlined into. template <typename UC> inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, size_t length) { - uint64_t mask{0}; - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { - mask = 0x0020002000200020; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - mask = 0x0000002000000020; - } - else { - return false; - } - - if (cpp20_and_in_constexpr()) { - for (size_t i = 0; i < length; i++) { - if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { - return false; - } - } - return true; - } else { - uint64_t val1{0}, val2{0}; - size_t sz{8 / (sizeof(UC))}; - for (size_t i = 0; i < length; i += sz) { - val1 = val2 = 0; - sz = sz < (length - i) ? sz : length - i; - ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); - ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); - val1 |= mask; - val2 |= mask; - if (val1 != val2) { - return false; - } + for (size_t i = 0; i < length; ++i) { + if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { + return false; } - return true; } + return true; } #ifndef FLT_EVAL_METHOD @@ -681,6 +588,8 @@ template <typename T> struct binary_format : binary_format_lookup_tables<T> { static constexpr uint64_t max_mantissa_fast_path(int64_t power); static constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST + static constexpr bool fast_path_can_overflow(); + static constexpr bool subnormal_ties_possible(); static constexpr int largest_power_of_ten(); static constexpr int smallest_power_of_ten(); static constexpr T exact_power_of_ten(int64_t power); @@ -712,6 +621,7 @@ template <typename U> struct binary_format_lookup_tables<double, U> { 0x20000000000000 / (constant_55555 * constant_55555 * 5), 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5), 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5 * 5), 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555), 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5), 0x20000000000000 / @@ -727,9 +637,7 @@ template <typename U> struct binary_format_lookup_tables<double, U> { 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5), 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * - constant_55555 * 5 * 5 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * - constant_55555 * 5 * 5 * 5 * 5)}; + constant_55555 * 5 * 5 * 5)}; }; #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE @@ -946,7 +854,9 @@ binary_format<std::float16_t>::max_mantissa_fast_path(int64_t power) { template <> inline constexpr int binary_format<std::float16_t>::min_exponent_fast_path() { - return 0; + // w / 10^k with w <= 2^11 and k <= 4 rounds correctly even when evaluated + // in float or double first (checked in script/format_parameters.py). + return -4; } template <> @@ -958,7 +868,9 @@ binary_format<std::float16_t>::max_exponent_round_to_even() { template <> inline constexpr int binary_format<std::float16_t>::min_exponent_round_to_even() { - return -22; + // -22 covers the normal ties; subnormal ties such as + // 2^-25 = 298023223876953125e-25 need q = -25 and q = -26. + return -26; } template <> @@ -982,7 +894,8 @@ inline constexpr int binary_format<std::float16_t>::largest_power_of_ten() { template <> inline constexpr int binary_format<std::float16_t>::smallest_power_of_ten() { - return -27; + // (10^19 - 1) * 10^-27 < 2^-25, so any q < -26 rounds to zero. + return -26; } template <> @@ -1069,7 +982,8 @@ binary_format<std::bfloat16_t>::max_mantissa_fast_path(int64_t power) { template <> inline constexpr int binary_format<std::bfloat16_t>::min_exponent_fast_path() { - return 0; + // Same argument as for std::float16_t (w <= 2^8, k <= 3). + return -3; } template <> @@ -1105,7 +1019,8 @@ inline constexpr int binary_format<std::bfloat16_t>::largest_power_of_ten() { template <> inline constexpr int binary_format<std::bfloat16_t>::smallest_power_of_ten() { - return -60; + // (10^19 - 1) * 10^-60 < 2^-134, so any q < -59 rounds to zero. + return -59; } template <> @@ -1114,6 +1029,25 @@ inline constexpr size_t binary_format<std::bfloat16_t>::max_digits() { } #endif // __STDCPP_BFLOAT16_T__ +// Whether Clinger's fast path can overflow: only for std::float16_t, where +// 2^11 * 10^4 > 65504. +template <typename T> +inline constexpr bool binary_format<T>::fast_path_can_overflow() { + return double(max_mantissa_fast_path()) * + double(exact_power_of_ten(max_exponent_fast_path())) > + double((std::numeric_limits<T>::max)()); +} + +// A subnormal needs w * 10^q < 2^(minimum_exponent() + 1), so q is at most +// (minimum_exponent() + 1) * log10(2), with 1233/4096 < log10(2). Only +// std::float16_t has such q in its round-to-even range. We compare +// 4096 * q with (minimum_exponent() + 1) * 1233 to avoid right-shifting a +// negative value (implementation-defined before C++20). +template <typename T> +inline constexpr bool binary_format<T>::subnormal_ties_possible() { + return min_exponent_round_to_even() * 4096 <= (minimum_exponent() + 1) * 1233; +} + template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) { diff --git a/deps/v8/third_party/fast_float/src/include/fast_float/parse_number.h b/deps/v8/third_party/fast_float/src/include/fast_float/parse_number.h index 58cdafd51c5b..f8409d040f9f 100644 --- a/deps/v8/third_party/fast_float/src/include/fast_float/parse_number.h +++ b/deps/v8/third_party/fast_float/src/include/fast_float/parse_number.h @@ -35,7 +35,7 @@ from_chars_result_t<UC> ++first; } if (last - first >= 3) { - if (fastfloat_strncasecmp3(first, str_const_nan<UC>())) { + if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) { answer.ptr = (first += 3); value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN(); @@ -54,9 +54,9 @@ from_chars_result_t<UC> } return answer; } - if (fastfloat_strncasecmp3(first, str_const_inf<UC>())) { + if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) { if ((last - first >= 8) && - fastfloat_strncasecmp5(first + 3, str_const_inf<UC>() + 3)) { + fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) { answer.ptr = first + 8; } else { answer.ptr = first + 3; @@ -139,9 +139,10 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept { template <typename T> struct from_chars_caller { template <typename UC> - FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC> - call(UC const *first, UC const *last, T &value, - parse_options_t<UC> options) noexcept { + fastfloat_clang_really_inline + FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC> + call(UC const *first, UC const *last, T &value, + parse_options_t<UC> options) noexcept { return from_chars_advanced(first, last, value, options); } }; @@ -180,10 +181,29 @@ template <> struct from_chars_caller<std::float64_t> { }; #endif +#ifdef __clang__ +// Parser instantiated for a format fixed at compile time, so that every test +// on the format folds away inside it. GCC gets the same effect by inlining the +// whole parser into each caller, where the format is a constant; clang keeps +// it out of line and would otherwise re-test each format flag per conversion. +template <typename T, typename UC, chars_format Fmt> +FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC> +from_chars_fixed_format(UC const *first, UC const *last, T &value) noexcept { + return from_chars_caller<T>::call(first, last, value, + parse_options_t<UC>(Fmt)); +} +#endif + template <typename T, typename UC, typename> FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC> from_chars(UC const *first, UC const *last, T &value, chars_format fmt /*= chars_format::general*/) noexcept { +#ifdef __clang__ + if (fmt == chars_format::general) { + return from_chars_fixed_format<T, UC, chars_format::general>(first, last, + value); + } +#endif return from_chars_caller<T>::call(first, last, value, parse_options_t<UC>(fmt)); } @@ -221,6 +241,12 @@ clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative, value = value / binary_format<T>::exact_power_of_ten(-exponent); } else { value = value * binary_format<T>::exact_power_of_ten(exponent); + // Only std::float16_t can overflow here (e.g., "656e2"); let the + // slow path report result_out_of_range. + if (binary_format<T>::fast_path_can_overflow() && + value > (std::numeric_limits<T>::max)()) { + return false; + } } if (is_negative) { value = -value; @@ -306,8 +332,41 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC> parse_number_slow_path(UC const *first, UC const *last, T &value, parse_options_t<UC> options, bool bjf) noexcept { parsed_number_string_t<UC> pns = - bjf ? parse_number_string<true, UC>(first, last, options, true) - : parse_number_string<false, UC>(first, last, options, true); + bjf ? parse_number_string_impl<true, false, UC>(first, last, options, + true) + : parse_number_string_impl<false, false, UC>(first, last, options, + true); + return from_chars_advanced(pns, value); +} + +// Cold: the whole chars_format::javascript conversion. Kept out of line and out +// of from_chars_float_advanced so the common frame holds neither the javascript +// parser body nor a call that would force the parsed number string onto the +// stack. Mirrors the main path, only with the javascript parser. +template <typename T, typename UC> +fastfloat_never_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC> +from_chars_float_javascript(UC const *first, UC const *last, T &value, + parse_options_t<UC> options) noexcept { + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + if (uint64_t(fmt & chars_format::skip_white_space)) { + while ((first != last) && fast_float::is_space(*first)) { + first++; + } + } + from_chars_result_t<UC> answer; + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + if (first == last) { + return answer; + } + parsed_number_string_t<UC> pns = + parse_number_string_javascript<UC>(first, last, options, true); + if (!pns.valid) { + if (uint64_t(fmt & chars_format::no_infnan)) { + return answer; + } + return detail::parse_infnan(first, last, value, fmt); + } return from_chars_advanced(pns, value); } @@ -323,6 +382,13 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, chars_format const fmt = detail::adjust_for_feature_macros(options.format); + // Leave for the javascript conversion before anything else is live, so this + // compiles to a tail call and the common path keeps its registers. The cold + // function repeats the leading-whitespace and empty-input handling below. + if fastfloat_unlikely (uint64_t(fmt & detail::basic_javascript_fmt)) { + return from_chars_float_javascript<T, UC>(first, last, value, options); + } + from_chars_result_t<UC> answer; if (uint64_t(fmt & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { @@ -339,10 +405,12 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, // Fast path: parse WITHOUT materializing the integer/fraction spans (read // only by the rare slow paths). Skipping their stores keeps the fat // parsed_number_string_t off the hot path. store_spans is a runtime argument, - // so this reuses the single parse_number_string instantiation. + // so this reuses the single parse_number_string_impl instantiation. parsed_number_string_t<UC> pns = - bjf ? parse_number_string<true, UC>(first, last, options, false) - : parse_number_string<false, UC>(first, last, options, false); + bjf ? parse_number_string_impl<true, false, UC>(first, last, options, + false) + : parse_number_string_impl<false, false, UC>(first, last, options, + false); if (!pns.valid) { if (uint64_t(fmt & chars_format::no_infnan)) { answer.ec = std::errc::invalid_argument; @@ -386,15 +454,19 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, if fastfloat_unlikely (am.power2 < 0) { return parse_number_slow_path<T, UC>(first, last, value, options, bjf); } -#ifdef __clang__ -#pragma clang diagnostic pop -#endif to_float(pns.negative, am, value); - // Test for over/underflow. - if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || - am.power2 == binary_format<T>::infinite_power()) { + // Test for over/underflow. Marked unlikely so that clang keeps it as a + // branch instead of folding it into a chain of conditional moves that + // every conversion pays for. + if fastfloat_clang_unlikely ((pns.mantissa != 0 && am.mantissa == 0 && + am.power2 == 0) || + am.power2 == + binary_format<T>::infinite_power()) { answer.ec = std::errc::result_out_of_range; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif return answer; } @@ -431,7 +503,9 @@ FASTFLOAT_CONSTEXPR20 typename std::enable_if<is_supported_float_type<T>::value, T>::type integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept { const bool is_negative = mantissa < 0; - const uint64_t m = static_cast<uint64_t>(is_negative ? -mantissa : mantissa); + // Negate as unsigned: -mantissa overflows for the most negative int64_t. + const uint64_t m = is_negative ? uint64_t(0) - static_cast<uint64_t>(mantissa) + : static_cast<uint64_t>(mantissa); T value; if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value)) diff --git a/deps/v8/third_party/inspector_protocol/crdtp/error_support.cc b/deps/v8/third_party/inspector_protocol/crdtp/error_support.cc index caf3009a7aee..5b1881c4a984 100644 --- a/deps/v8/third_party/inspector_protocol/crdtp/error_support.cc +++ b/deps/v8/third_party/inspector_protocol/crdtp/error_support.cc @@ -33,8 +33,7 @@ void ErrorSupport::AddError(const char* error) { if (!errors_.empty()) errors_ += "; "; for (size_t ii = 0; ii < stack_.size(); ++ii) { - if (ii) - errors_ += "."; + if (ii) errors_ += '.'; const Segment& s = stack_[ii]; switch (s.type) { case NAME: diff --git a/deps/v8/third_party/inspector_protocol/crdtp/json_platform_v8.cc b/deps/v8/third_party/inspector_protocol/crdtp/json_platform_v8.cc index b3050427bf0a..65f352020482 100644 --- a/deps/v8/third_party/inspector_protocol/crdtp/json_platform_v8.cc +++ b/deps/v8/third_party/inspector_protocol/crdtp/json_platform_v8.cc @@ -6,8 +6,8 @@ #include "json_platform.h" +#include <array> #include <cmath> -#include "../../../src/base/vector.h" #include "../../../src/numbers/conversions.h" namespace v8_crdtp { @@ -22,10 +22,8 @@ bool StrToD(const char* str, double* result) { // Prints |value| in a format suitable for JSON. std::string DToStr(double value) { - auto buffer = v8::base::OwnedVector<char>::NewForOverwrite( - v8::internal::kDoubleToStringMinBufferSize); - return std::string( - v8::internal::DoubleToStringView(value, buffer.as_vector())); + std::array<char, v8::internal::kDoubleToStringMinBufferSize> buffer; + return std::string(v8::internal::DoubleToStringView(value, buffer)); } } // namespace platform } // namespace json diff --git a/deps/v8/third_party/llvm-libc/src/hdr/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/hdr/CMakeLists.txt index fa01bc55785d..fbf2cc81b160 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/hdr/CMakeLists.txt @@ -120,6 +120,17 @@ add_proxy_header_library( libc.include.llvm-libc-macros.netinet_in_macros ) +add_header_library(poll_overlay HDRS poll_overlay.h) +add_proxy_header_library( + poll_macros + HDRS + poll_macros.h + DEPENDS + .poll_overlay + FULL_BUILD_DEPENDS + libc.include.llvm-libc-macros.poll-macros +) + add_proxy_header_library( pthread_macros HDRS @@ -186,6 +197,14 @@ add_proxy_header_library( libc.include.llvm-libc-macros.sys_epoll_macros ) +add_proxy_header_library( + sys_eventfd_macros + HDRS + sys_eventfd_macros.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-macros.sys_eventfd_macros +) + add_proxy_header_library( sys_file_macros HDRS @@ -194,6 +213,14 @@ add_proxy_header_library( libc.include.llvm-libc-macros.sys_file_macros ) +add_proxy_header_library( + sys_inotify_macros + HDRS + sys_inotify_macros.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-macros.sys_inotify_macros +) + add_proxy_header_library( sys_ioctl_macros HDRS @@ -226,10 +253,13 @@ add_proxy_header_library( libc.include.llvm-libc-macros.sys_sem_macros ) +add_header_library(sys_socket_overlay HDRS sys_socket_overlay.h) add_proxy_header_library( sys_socket_macros HDRS sys_socket_macros.h + DEPENDS + .sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-macros.sys_socket_macros ) @@ -274,6 +304,14 @@ add_proxy_header_library( libc.include.llvm-libc-macros.sys_wait_macros ) +add_proxy_header_library( + sys_xattr_macros + HDRS + sys_xattr_macros.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-macros.sys_xattr_macros +) + add_proxy_header_library( termios_macros HDRS @@ -290,6 +328,7 @@ add_proxy_header_library( DEPENDS .unistd_overlay FULL_BUILD_DEPENDS + libc.include.llvm-libc-macros.file_seek_macros libc.include.llvm-libc-macros.unistd_macros ) diff --git a/deps/v8/third_party/llvm-libc/src/hdr/poll_macros.h b/deps/v8/third_party/llvm-libc/src/hdr/poll_macros.h new file mode 100644 index 000000000000..0a3fbb18a723 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/poll_macros.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for poll.h macros. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_POLL_MACROS_H +#define LLVM_LIBC_HDR_POLL_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/poll-macros.h" + +#else // Overlay mode + +#include "hdr/poll_overlay.h" + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_POLL_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/poll_overlay.h b/deps/v8/third_party/llvm-libc/src/hdr/poll_overlay.h new file mode 100644 index 000000000000..6ffa3e1d89a2 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/poll_overlay.h @@ -0,0 +1,69 @@ +//===-- Including poll.h in overlay mode ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_POLL_OVERLAY_H +#define LLVM_LIBC_HDR_POLL_OVERLAY_H + +#ifdef LIBC_FULL_BUILD +#error "This header should only be included in overlay mode" +#endif + +// Overlay mode + +// glibc <poll.h> header might provide extern inline definitions for few +// functions, causing external alias errors. They are guarded by +// `__USE_EXTERN_INLINES` macro. We temporarily disable `__USE_EXTERN_INLINES` +// macro by defining `__NO_INLINE__` before including <poll.h>. +// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled +// with `_FORTIFY_SOURCE`. + +#ifdef _FORTIFY_SOURCE +#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE +#undef _FORTIFY_SOURCE +#endif + +#ifndef __NO_INLINE__ +#define __NO_INLINE__ 1 +#define LIBC_SET_NO_INLINE +#endif + +#ifdef __USE_EXTERN_INLINES +#define LIBC_OLD_USE_EXTERN_INLINES +#undef __USE_EXTERN_INLINES +#endif + +#ifdef __USE_FORTIFY_LEVEL +#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL 0 +#endif + +#include <poll.h> + +#ifdef LIBC_OLD_FORTIFY_SOURCE +#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE +#undef LIBC_OLD_FORTIFY_SOURCE +#endif + +#ifdef LIBC_SET_NO_INLINE +#undef __NO_INLINE__ +#undef LIBC_SET_NO_INLINE +#endif + +#ifdef LIBC_OLD_USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL +#undef LIBC_OLD_USE_FORTIFY_LEVEL +#endif + +#ifdef LIBC_OLD_USE_EXTERN_INLINES +#define __USE_EXTERN_INLINES +#undef LIBC_OLD_USE_EXTERN_INLINES +#endif + +#endif // LLVM_LIBC_HDR_POLL_OVERLAY_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/sys_eventfd_macros.h b/deps/v8/third_party/llvm-libc/src/hdr/sys_eventfd_macros.h new file mode 100644 index 000000000000..8be30c84dc5f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/sys_eventfd_macros.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for macro values defined in sys/eventfd.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_SYS_EVENTFD_MACROS_H +#define LLVM_LIBC_HDR_SYS_EVENTFD_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/sys-eventfd-macros.h" + +#else // Overlay mode + +#include <sys/eventfd.h> + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_SYS_EVENTFD_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/sys_inotify_macros.h b/deps/v8/third_party/llvm-libc/src/hdr/sys_inotify_macros.h new file mode 100644 index 000000000000..997a21bde9e8 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/sys_inotify_macros.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for macro values defined in sys/inotify.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_SYS_INOTIFY_MACROS_H +#define LLVM_LIBC_HDR_SYS_INOTIFY_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/sys-inotify-macros.h" + +#else // Overlay mode + +#include <sys/inotify.h> + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_SYS_INOTIFY_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_macros.h b/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_macros.h index 48fe13186449..1517c7134fa6 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_macros.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_macros.h @@ -15,7 +15,7 @@ #else // Overlay mode -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_overlay.h b/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_overlay.h new file mode 100644 index 000000000000..122bc0cef46f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/sys_socket_overlay.h @@ -0,0 +1,69 @@ +//===-- Including sys/socket.h in overlay mode ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_SYS_SOCKET_OVERLAY_H +#define LLVM_LIBC_HDR_SYS_SOCKET_OVERLAY_H + +#ifdef LIBC_FULL_BUILD +#error "This header should only be included in overlay mode" +#endif + +// Overlay mode + +// glibc <sys/socket.h> header might provide extern inline definitions for few +// functions, causing external alias errors. They are guarded by +// `__USE_EXTERN_INLINES` macro. We temporarily disable `__USE_EXTERN_INLINES` +// macro by defining `__NO_INLINE__` before including <sys/socket.h>. +// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled +// with `_FORTIFY_SOURCE`. + +#ifdef _FORTIFY_SOURCE +#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE +#undef _FORTIFY_SOURCE +#endif + +#ifndef __NO_INLINE__ +#define __NO_INLINE__ 1 +#define LIBC_SET_NO_INLINE +#endif + +#ifdef __USE_EXTERN_INLINES +#define LIBC_OLD_USE_EXTERN_INLINES +#undef __USE_EXTERN_INLINES +#endif + +#ifdef __USE_FORTIFY_LEVEL +#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL 0 +#endif + +#include <sys/socket.h> + +#ifdef LIBC_OLD_FORTIFY_SOURCE +#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE +#undef LIBC_OLD_FORTIFY_SOURCE +#endif + +#ifdef LIBC_SET_NO_INLINE +#undef __NO_INLINE__ +#undef LIBC_SET_NO_INLINE +#endif + +#ifdef LIBC_OLD_USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL +#undef LIBC_OLD_USE_FORTIFY_LEVEL +#endif + +#ifdef LIBC_OLD_USE_EXTERN_INLINES +#define __USE_EXTERN_INLINES +#undef LIBC_OLD_USE_EXTERN_INLINES +#endif + +#endif // LLVM_LIBC_HDR_SYS_SOCKET_OVERLAY_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/sys_xattr_macros.h b/deps/v8/third_party/llvm-libc/src/hdr/sys_xattr_macros.h new file mode 100644 index 000000000000..b65fa7958511 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/sys_xattr_macros.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for macro values defined in sys/xattr.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_SYS_XATTR_MACROS_H +#define LLVM_LIBC_HDR_SYS_XATTR_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/sys-xattr-macros.h" + +#else // Overlay mode + +#include <sys/xattr.h> + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_SYS_XATTR_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/hdr/types/CMakeLists.txt index 6949e73a78da..4c65ebc13937 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/CMakeLists.txt @@ -24,12 +24,19 @@ add_proxy_header_library( mbstate_t HDRS mbstate_t.h - DEPENDS - libc.include.llvm-libc-types.mbstate_t FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.mbstate_t libc.include.uchar ) +add_proxy_header_library( + fpos_t + HDRS + fpos_t.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.fpos_t +) + add_proxy_header_library( div_t HDRS @@ -57,6 +64,14 @@ add_proxy_header_library( libc.include.llvm-libc-types.struct_link_map ) +add_proxy_header_library( + struct___pthread_cleanup_frame + HDRS + struct___pthread_cleanup_frame.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.struct___pthread_cleanup_frame +) + add_proxy_header_library( struct_r_debug HDRS @@ -550,6 +565,8 @@ add_proxy_header_library( struct_linger HDRS struct_linger.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_linger libc.include.sys_socket @@ -559,6 +576,8 @@ add_proxy_header_library( struct_cmsghdr HDRS struct_cmsghdr.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_cmsghdr libc.include.sys_socket @@ -568,6 +587,8 @@ add_proxy_header_library( struct_mmsghdr HDRS struct_mmsghdr.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_mmsghdr libc.include.sys_socket @@ -577,6 +598,8 @@ add_proxy_header_library( struct_msghdr HDRS struct_msghdr.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_msghdr libc.include.sys_socket @@ -703,6 +726,8 @@ add_proxy_header_library( struct_sockaddr HDRS struct_sockaddr.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_sockaddr libc.include.sys_socket @@ -720,6 +745,8 @@ add_proxy_header_library( struct_sockaddr_storage HDRS struct_sockaddr_storage.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_sockaddr_storage libc.include.sys_socket @@ -761,6 +788,14 @@ add_proxy_header_library( libc.include.netinet_udp ) +add_proxy_header_library( + struct_ether_addr + HDRS + struct_ether_addr.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.struct_ether_addr +) + add_proxy_header_library( struct_sysinfo HDRS @@ -783,6 +818,8 @@ add_proxy_header_library( sa_family_t HDRS sa_family_t.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.sa_family_t libc.include.sys_socket @@ -792,6 +829,8 @@ add_proxy_header_library( socklen_t HDRS socklen_t.h + DEPENDS + libc.hdr.sys_socket_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.socklen_t libc.include.sys_socket @@ -848,6 +887,8 @@ add_proxy_header_library( nfds_t HDRS nfds_t.h + DEPENDS + libc.hdr.poll_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.nfds_t ) @@ -856,6 +897,8 @@ add_proxy_header_library( struct_pollfd HDRS struct_pollfd.h + DEPENDS + libc.hdr.poll_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-types.struct_pollfd ) @@ -1407,3 +1450,11 @@ add_proxy_header_library( FULL_BUILD_DEPENDS libc.include.llvm-libc-types.id_t ) + +add_proxy_header_library( + idtype_t + HDRS + idtype_t.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.idtype_t +) diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/fpos_t.h b/deps/v8/third_party/llvm-libc/src/hdr/types/fpos_t.h new file mode 100644 index 000000000000..abb07083a3aa --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/fpos_t.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for fpos_t. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_FPOS_T_H +#define LLVM_LIBC_HDR_TYPES_FPOS_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/fpos_t.h" + +#else // Overlay mode + +#error "Cannot overlay fpos_t" + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_FPOS_T_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/idtype_t.h b/deps/v8/third_party/llvm-libc/src/hdr/types/idtype_t.h new file mode 100644 index 000000000000..35f9165c28b0 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/idtype_t.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy for idtype_t. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_IDTYPE_T_H +#define LLVM_LIBC_HDR_TYPES_IDTYPE_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/idtype_t.h" + +#else // Overlay mode + +#include <sys/wait.h> + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_IDTYPE_T_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/nfds_t.h b/deps/v8/third_party/llvm-libc/src/hdr/types/nfds_t.h index f390bbe60377..22db1ffdf4e1 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/nfds_t.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/nfds_t.h @@ -16,7 +16,7 @@ #else // overlay mode -#include <poll.h> +#include "hdr/poll_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/sa_family_t.h b/deps/v8/third_party/llvm-libc/src/hdr/types/sa_family_t.h index af26df226be8..cec1d639901a 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/sa_family_t.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/sa_family_t.h @@ -20,7 +20,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/socklen_t.h b/deps/v8/third_party/llvm-libc/src/hdr/types/socklen_t.h index 547a6a6a0cbe..cf75fccafc5e 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/socklen_t.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/socklen_t.h @@ -14,7 +14,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct___pthread_cleanup_frame.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct___pthread_cleanup_frame.h new file mode 100644 index 000000000000..c49934451571 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct___pthread_cleanup_frame.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for struct __pthread_cleanup_frame. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_STRUCT___PTHREAD_CLEANUP_FRAME_H +#define LLVM_LIBC_HDR_TYPES_STRUCT___PTHREAD_CLEANUP_FRAME_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/struct___pthread_cleanup_frame.h" + +#else // Overlay mode + +#error "pthread_cleanup functionality not available in overlay mode" + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_STRUCT___PTHREAD_CLEANUP_FRAME_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_cmsghdr.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_cmsghdr.h index b84a1a2ede79..a494f7217ecc 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_cmsghdr.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_cmsghdr.h @@ -14,7 +14,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_ether_addr.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_ether_addr.h new file mode 100644 index 000000000000..6cb544c4e445 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_ether_addr.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for struct ether_addr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_ETHER_ADDR_H +#define LLVM_LIBC_HDR_TYPES_STRUCT_ETHER_ADDR_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/struct_ether_addr.h" + +#else + +#include <net/ethernet.h> + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_STRUCT_ETHER_ADDR_H diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_linger.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_linger.h index 6343e7dda2bd..c0e48c912913 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_linger.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_linger.h @@ -15,7 +15,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_mmsghdr.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_mmsghdr.h index 84473bbd4668..5a28e43ef826 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_mmsghdr.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_mmsghdr.h @@ -19,7 +19,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_msghdr.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_msghdr.h index 6a36af791e21..29a4fb6bccb7 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_msghdr.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_msghdr.h @@ -14,7 +14,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_pollfd.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_pollfd.h index ec56d841aced..1d9d30a67122 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_pollfd.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_pollfd.h @@ -16,7 +16,7 @@ #else // overlay mode -#include <poll.h> +#include "hdr/poll_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr.h index 0fc31d537485..b006233692ca 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr.h @@ -14,7 +14,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr_storage.h b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr_storage.h index c8559f2f84fb..f1790d09bfcb 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr_storage.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/types/struct_sockaddr_storage.h @@ -14,7 +14,7 @@ #else -#include <sys/socket.h> +#include "hdr/sys_socket_overlay.h" #endif // LIBC_FULL_BUILD diff --git a/deps/v8/third_party/llvm-libc/src/hdr/unistd_macros.h b/deps/v8/third_party/llvm-libc/src/hdr/unistd_macros.h index bda16224608b..b1a63b2dd1e7 100644 --- a/deps/v8/third_party/llvm-libc/src/hdr/unistd_macros.h +++ b/deps/v8/third_party/llvm-libc/src/hdr/unistd_macros.h @@ -11,6 +11,7 @@ #ifdef LIBC_FULL_BUILD +#include "include/llvm-libc-macros/file-seek-macros.h" #include "include/llvm-libc-macros/unistd-macros.h" #else // Overlay mode diff --git a/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt index a45026de31ee..0130ba1d72e0 100644 --- a/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/include/CMakeLists.txt @@ -194,6 +194,15 @@ add_header_macro( .llvm_libc_common_h ) +add_header_macro( + libintl + ../libc/include/libintl.yaml + libintl.h + DEPENDS + .llvm_libc_common_h + .llvm-libc-types.locale_t +) + add_header_macro( limits ../libc/include/limits.yaml @@ -438,6 +447,7 @@ add_header_macro( threads.h DEPENDS .llvm_libc_common_h + .llvm-libc-macros.threads_macros .llvm-libc-types.__call_once_func_t .llvm-libc-types.once_flag .llvm-libc-types.cnd_t @@ -516,6 +526,7 @@ add_header_macro( .llvm-libc-types.FILE .llvm-libc-types.cookie_io_functions_t .llvm-libc-types.errno_t + .llvm-libc-types.fpos_t .llvm-libc-types.off_t .llvm-libc-types.rsize_t .llvm-libc-types.size_t @@ -584,6 +595,7 @@ add_header_macro( .llvm-libc-types.__pthread_once_func_t .llvm-libc-types.__pthread_start_t .llvm-libc-types.__pthread_tss_dtor_t + .llvm-libc-types.struct___pthread_cleanup_frame .llvm-libc-types.clockid_t .llvm-libc-types.pthread_attr_t .llvm-libc-types.pthread_cond_t @@ -726,6 +738,15 @@ add_header_macro( .llvm-libc-macros.sys_epoll_macros ) +add_header_macro( + sys_eventfd + ../libc/include/sys/eventfd.yaml + sys/eventfd.h + DEPENDS + .llvm_libc_common_h + .llvm-libc-macros.sys_eventfd_macros +) + add_header_macro( sys_file ../libc/include/sys/file.yaml @@ -745,6 +766,17 @@ add_header_macro( .llvm-libc-types.struct_winsize ) +add_header_macro( + sys_inotify + ../libc/include/sys/inotify.yaml + sys/inotify.h + DEPENDS + .llvm_libc_common_h + .llvm-libc-macros.sys_inotify_macros + .llvm-libc-types.struct_inotify_event + .stdint +) + add_header_macro( sys_ipc ../libc/include/sys/ipc.yaml @@ -1095,6 +1127,8 @@ add_header_macro( .llvm-libc-types.pid_t .llvm-libc-types.struct_rusage .llvm-libc-types.siginfo_t + .llvm-libc-types.id_t + .llvm-libc-types.idtype_t ) add_header_macro( @@ -1103,12 +1137,22 @@ add_header_macro( sys/xattr.h DEPENDS .llvm_libc_common_h + .llvm-libc-macros.sys_xattr_macros .llvm-libc-types.size_t .llvm-libc-types.ssize_t ) file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/net) +add_header_macro( + net_ethernet + ../libc/include/net/ethernet.yaml + net/ethernet.h + DEPENDS + .llvm-libc-types.struct_ether_addr + .llvm_libc_common_h +) + add_header_macro( net_if ../libc/include/net/if.yaml @@ -1123,6 +1167,15 @@ add_header_macro( # TODO: This should be conditional on POSIX networking being included. file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/netinet) +add_header_macro( + netinet_ether + ../libc/include/netinet/ether.yaml + netinet/ether.h + DEPENDS + .llvm-libc-types.struct_ether_addr + .llvm_libc_common_h +) + add_header_macro( netinet_in ../libc/include/netinet/in.yaml @@ -1194,6 +1247,7 @@ add_header_macro( .llvm-libc-types.pid_t .llvm-libc-types.speed_t .llvm-libc-types.struct_termios + .llvm-libc-types.struct_winsize .llvm-libc-types.tcflag_t ) @@ -1256,6 +1310,8 @@ add_header_macro( DEPENDS .llvm-libc-types.struct_pollfd .llvm-libc-types.nfds_t + .llvm-libc-types.struct_timespec + .llvm-libc-types.sigset_t .llvm-libc-macros.poll-macros ) diff --git a/deps/v8/third_party/llvm-libc/src/include/arpa/inet.yaml b/deps/v8/third_party/llvm-libc/src/include/arpa/inet.yaml index 662997484418..b533382fedf4 100644 --- a/deps/v8/third_party/llvm-libc/src/include/arpa/inet.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/arpa/inet.yaml @@ -53,3 +53,11 @@ functions: - type: const void *__restrict - type: char *__restrict - type: socklen_t + - name: inet_pton + standards: + - posix + return_type: int + arguments: + - type: int + - type: const char *__restrict + - type: void *__restrict diff --git a/deps/v8/third_party/llvm-libc/src/include/dirent.yaml b/deps/v8/third_party/llvm-libc/src/include/dirent.yaml index e752b564d8d4..8dc939fa1158 100644 --- a/deps/v8/third_party/llvm-libc/src/include/dirent.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/dirent.yaml @@ -64,3 +64,12 @@ functions: return_type: struct dirent * arguments: - type: DIR * + - name: scandir + standards: + - posix + return_type: int + arguments: + - type: const char * + - type: struct dirent *** + - type: int (*)(const struct dirent *) + - type: int (*)(const struct dirent **, const struct dirent **) diff --git a/deps/v8/third_party/llvm-libc/src/include/fcntl.yaml b/deps/v8/third_party/llvm-libc/src/include/fcntl.yaml index 49aac448e707..160e25a304ac 100644 --- a/deps/v8/third_party/llvm-libc/src/include/fcntl.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/fcntl.yaml @@ -2,13 +2,87 @@ header: fcntl.h standards: - posix macros: + - macro_name: O_CLOEXEC + macro_header: fcntl-macros.h + - macro_name: O_CREAT + macro_header: fcntl-macros.h + - macro_name: O_DIRECTORY + macro_header: fcntl-macros.h + - macro_name: O_EXCL + macro_header: fcntl-macros.h + - macro_name: O_NOCTTY + macro_header: fcntl-macros.h + - macro_name: O_NOFOLLOW + macro_header: fcntl-macros.h + - macro_name: O_TRUNC + macro_header: fcntl-macros.h + - macro_name: O_APPEND + macro_header: fcntl-macros.h + - macro_name: O_DSYNC + macro_header: fcntl-macros.h + - macro_name: O_NONBLOCK + macro_header: fcntl-macros.h + - macro_name: O_RSYNC + macro_header: fcntl-macros.h + - macro_name: O_SYNC + macro_header: fcntl-macros.h + - macro_name: O_ACCMODE + macro_header: fcntl-macros.h + - macro_name: O_RDONLY + macro_header: fcntl-macros.h + - macro_name: O_RDWR + macro_header: fcntl-macros.h + - macro_name: O_WRONLY + macro_header: fcntl-macros.h - macro_name: AT_FDCWD macro_header: fcntl-macros.h - - macro_name: AT_REMOVEDIR + - macro_name: AT_EACCESS macro_header: fcntl-macros.h - macro_name: AT_SYMLINK_NOFOLLOW macro_header: fcntl-macros.h - - macro_name: AT_EACCESS + - macro_name: AT_SYMLINK_FOLLOW + macro_header: fcntl-macros.h + - macro_name: AT_REMOVEDIR + macro_header: fcntl-macros.h + - macro_name: F_DUPFD + macro_header: fcntl-macros.h + - macro_name: F_DUPFD_CLOEXEC + macro_header: fcntl-macros.h + - macro_name: F_GETFD + macro_header: fcntl-macros.h + - macro_name: F_SETFD + macro_header: fcntl-macros.h + - macro_name: F_GETFL + macro_header: fcntl-macros.h + - macro_name: F_SETFL + macro_header: fcntl-macros.h + - macro_name: F_GETLK + macro_header: fcntl-macros.h + - macro_name: F_SETLK + macro_header: fcntl-macros.h + - macro_name: F_SETLKW + macro_header: fcntl-macros.h + - macro_name: F_OFD_GETLK + macro_header: fcntl-macros.h + - macro_name: F_OFD_SETLK + macro_header: fcntl-macros.h + - macro_name: F_OFD_SETLKW + macro_header: fcntl-macros.h + - macro_name: F_GETOWN + macro_header: fcntl-macros.h + - macro_name: F_GETOWN_EX + macro_header: fcntl-macros.h + - macro_name: F_SETOWN + macro_header: fcntl-macros.h + - macro_name: F_SETOWN_EX + macro_header: fcntl-macros.h + - macro_name: FD_CLOEXEC + macro_header: fcntl-macros.h + - macro_name: F_RDLCK + macro_header: fcntl-macros.h + - macro_name: F_UNLCK + macro_header: fcntl-macros.h + - macro_name: F_WRLCK macro_header: fcntl-macros.h - macro_name: POSIX_FADV_NORMAL macro_header: fcntl-macros.h @@ -92,3 +166,11 @@ functions: - type: off64_t - type: off64_t - type: int + - name: posix_fallocate + standards: + - posix + return_type: int + arguments: + - type: int + - type: off_t + - type: off_t diff --git a/deps/v8/third_party/llvm-libc/src/include/grp.yaml b/deps/v8/third_party/llvm-libc/src/include/grp.yaml index e1ace37cb9b2..a4c9cbc78bc7 100644 --- a/deps/v8/third_party/llvm-libc/src/include/grp.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/grp.yaml @@ -18,6 +18,12 @@ functions: - posix return_type: struct group * arguments: [] + - name: getgrgid + standards: + - posix + return_type: struct group * + arguments: + - type: gid_t - name: getgrgid_r standards: - posix @@ -28,6 +34,12 @@ functions: - type: char * - type: size_t - type: struct group ** + - name: getgrnam + standards: + - posix + return_type: struct group * + arguments: + - type: const char * - name: getgrnam_r standards: - posix @@ -38,8 +50,31 @@ functions: - type: char * - type: size_t - type: struct group ** + - name: getgrouplist + standards: + - gnu + return_type: int + arguments: + - type: const char * + - type: gid_t + - type: gid_t * + - type: int * + - name: initgroups + standards: + - gnu + return_type: int + arguments: + - type: const char * + - type: gid_t - name: setgrent standards: - posix return_type: void arguments: [] + - name: setgroups + standards: + - gnu + return_type: int + arguments: + - type: size_t + - type: const gid_t * diff --git a/deps/v8/third_party/llvm-libc/src/include/libintl.yaml b/deps/v8/third_party/llvm-libc/src/include/libintl.yaml new file mode 100644 index 000000000000..60fe467e86d4 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/libintl.yaml @@ -0,0 +1,131 @@ +header: libintl.h +standards: + - posix +macros: [] +types: + - type_name: locale_t +enums: [] +objects: [] +functions: + - name: bind_textdomain_codeset + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - name: bindtextdomain + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - name: dcgettext + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: int + - name: dcgettext_l + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: int + - type: locale_t + - name: dcngettext + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: const char * + - type: unsigned long int + - type: int + - name: dcngettext_l + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: const char * + - type: unsigned long int + - type: int + - type: locale_t + - name: dgettext + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - name: dgettext_l + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: locale_t + - name: dngettext + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: const char * + - type: unsigned long int + - name: dngettext_l + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: const char * + - type: unsigned long int + - type: locale_t + - name: gettext + standards: + - posix + return_type: char * + arguments: + - type: const char * + - name: gettext_l + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: locale_t + - name: ngettext + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: unsigned long int + - name: ngettext_l + standards: + - posix + return_type: char * + arguments: + - type: const char * + - type: const char * + - type: unsigned long int + - type: locale_t + - name: textdomain + standards: + - posix + return_type: char * + arguments: + - type: const char * diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/CMakeLists.txt index 9e9559056dae..ed934df81886 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/CMakeLists.txt @@ -153,10 +153,26 @@ add_macro_header( float16-macros.h ) +add_macro_header( + common_threads_macros + HDR + common-threads-macros.h +) + +add_macro_header( + threads_macros + HDR + threads-macros.h + DEPENDS + .common_threads_macros +) + add_macro_header( limits_macros HDR limits-macros.h + DEPENDS + .common_threads_macros ) add_macro_header( @@ -264,6 +280,12 @@ add_macro_header( .fcntl_macros ) +add_macro_header( + sys_eventfd_macros + HDR + sys-eventfd-macros.h +) + add_macro_header( sys_file_macros HDR @@ -276,6 +298,12 @@ add_macro_header( sys-ioctl-macros.h ) +add_macro_header( + sys_inotify_macros + HDR + sys-inotify-macros.h +) + add_macro_header( sys_ipc_macros HDR @@ -383,6 +411,12 @@ add_macro_header( sys-wait-macros.h ) +add_macro_header( + sys_xattr_macros + HDR + sys-xattr-macros.h +) + add_macro_header( sys_sysmacros_macros HDR diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/common-threads-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/common-threads-macros.h new file mode 100644 index 000000000000..04d86c1438c4 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/common-threads-macros.h @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of common (C and POSIX) thread macros. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_COMMON_THREADS_MACROS_H +#define LLVM_LIBC_MACROS_COMMON_THREADS_MACROS_H + +#define __LLVM_LIBC_TSS_DTOR_ITERATIONS 4 + +#endif // LLVM_LIBC_MACROS_COMMON_THREADS_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/generic-error-number-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/generic-error-number-macros.h index 199a86217b34..56e2bff9137f 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/generic-error-number-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/generic-error-number-macros.h @@ -43,6 +43,7 @@ #define EPIPE 32 #define EDOM 33 #define ERANGE 34 +#define EOVERFLOW 35 #define EILSEQ 84 #endif // LLVM_LIBC_MACROS_GENERIC_ERROR_NUMBER_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/limits-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/limits-macros.h index 8a341e45e7c3..64f1b507ab38 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/limits-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/limits-macros.h @@ -14,6 +14,8 @@ #ifndef LLVM_LIBC_MACROS_LIMITS_MACROS_H #define LLVM_LIBC_MACROS_LIMITS_MACROS_H +#include "common-threads-macros.h" + // Define all C23 macro constants of limits.h #ifndef CHAR_BIT @@ -249,7 +251,7 @@ #endif #ifndef PTHREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS __LLVM_LIBC_TSS_DTOR_ITERATIONS #endif #ifndef _POSIX_HOST_NAME_MAX diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/CMakeLists.txt index 5a032252d989..7d92c1389d06 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/CMakeLists.txt @@ -10,10 +10,18 @@ add_header( dirent-macros.h ) +add_header( + sys_stat_macros + HDR + sys-stat-macros.h +) + add_header( fcntl_macros HDR fcntl-macros.h + DEPENDS + .sys_stat_macros ) add_header( @@ -34,6 +42,14 @@ add_header( sys-epoll-macros.h ) +add_header( + sys_eventfd_macros + HDR + sys-eventfd-macros.h + DEPENDS + .fcntl_macros +) + add_header( sys_file_macros HDR @@ -46,6 +62,14 @@ add_header( sys-ioctl-macros.h ) +add_header( + sys_inotify_macros + HDR + sys-inotify-macros.h + DEPENDS + .fcntl_macros +) + add_header( sys_ipc_macros HDR @@ -100,6 +124,12 @@ add_header( sys-wait-macros.h ) +add_header( + sys_xattr_macros + HDR + sys-xattr-macros.h +) + add_header( sys_sysmacros_macros HDR @@ -118,12 +148,6 @@ add_header( sys-resource-macros.h ) -add_header( - sys_stat_macros - HDR - sys-stat-macros.h -) - add_header( sys_statfs_macros HDR diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/fcntl-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/fcntl-macros.h index 648c4a9ec00d..e4c93b314963 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/fcntl-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/fcntl-macros.h @@ -9,6 +9,8 @@ #ifndef LLVM_LIBC_MACROS_LINUX_FCNTL_MACROS_H #define LLVM_LIBC_MACROS_LINUX_FCNTL_MACROS_H +#include "sys-stat-macros.h" + // File creation and file status flags. #define O_APPEND 000002000 #define O_ASYNC 000020000 @@ -22,6 +24,7 @@ #define O_NDELAY O_NONBLOCK #define O_PATH 010000000 #define O_SYNC 004010000 +#define O_RSYNC O_SYNC #define O_TRUNC 000001000 #ifdef __aarch64__ @@ -58,6 +61,10 @@ // should not be followed. #define AT_SYMLINK_NOFOLLOW 0x100 +// Special flag for functions like linkat to convey that symlinks +// should be followed. +#define AT_SYMLINK_FOLLOW 0x400 + // Allow empty relative pathname. #define AT_EMPTY_PATH 0x1000 @@ -82,6 +89,7 @@ #define F_SETLKW64 14 #define F_SETOWN_EX 15 #define F_GETOWN_EX 16 +#define F_DUPFD_CLOEXEC 1030 // Open File Description Locks. #define F_OFD_GETLK 36 diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/net-if-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/net-if-macros.h index b5cd2c2ef144..c8ac72c0ebd3 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/net-if-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/net-if-macros.h @@ -14,6 +14,10 @@ #ifndef LLVM_LIBC_MACROS_LINUX_NET_IF_MACROS_H #define LLVM_LIBC_MACROS_LINUX_NET_IF_MACROS_H +// Prevent the linux headers from defining this macro. +#define __UAPI_DEF_IF_IFNAMSIZ 0 + #define IF_NAMESIZE 16 +#define IFNAMSIZ IF_NAMESIZE #endif // LLVM_LIBC_MACROS_LINUX_NET_IF_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-eventfd-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-eventfd-macros.h new file mode 100644 index 000000000000..a41f6ad04b4e --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-eventfd-macros.h @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Linux specific declarations of macros from sys/eventfd.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_LINUX_SYS_EVENTFD_MACROS_H +#define LLVM_LIBC_MACROS_LINUX_SYS_EVENTFD_MACROS_H + +#include "fcntl-macros.h" + +#define EFD_SEMAPHORE (1 << 0) +#define EFD_CLOEXEC O_CLOEXEC +#define EFD_NONBLOCK O_NONBLOCK + +#endif // LLVM_LIBC_MACROS_LINUX_SYS_EVENTFD_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-inotify-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-inotify-macros.h new file mode 100644 index 000000000000..03679938d0d4 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-inotify-macros.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Macros defined in sys/inotify.h header file. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_LINUX_SYS_INOTIFY_MACROS_H +#define LLVM_LIBC_MACROS_LINUX_SYS_INOTIFY_MACROS_H + +#include "fcntl-macros.h" + +#define IN_CLOEXEC O_CLOEXEC +#define IN_NONBLOCK O_NONBLOCK + +#define IN_ACCESS 0x00000001 +#define IN_MODIFY 0x00000002 +#define IN_ATTRIB 0x00000004 +#define IN_CLOSE_WRITE 0x00000008 +#define IN_CLOSE_NOWRITE 0x00000010 +#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) +#define IN_OPEN 0x00000020 +#define IN_MOVED_FROM 0x00000040 +#define IN_MOVED_TO 0x00000080 +#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) +#define IN_CREATE 0x00000100 +#define IN_DELETE 0x00000200 +#define IN_DELETE_SELF 0x00000400 +#define IN_MOVE_SELF 0x00000800 + +#define IN_UNMOUNT 0x00002000 +#define IN_Q_OVERFLOW 0x00004000 +#define IN_IGNORED 0x00008000 + +#define IN_ONLYDIR 0x01000000 +#define IN_DONT_FOLLOW 0x02000000 +#define IN_EXCL_UNLINK 0x04000000 +#define IN_MASK_CREATE 0x10000000 +#define IN_MASK_ADD 0x20000000 +#define IN_ISDIR 0x40000000 +#define IN_ONESHOT 0x80000000 + +#define IN_ALL_EVENTS \ + (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE | \ + IN_OPEN | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE | \ + IN_DELETE_SELF | IN_MOVE_SELF) + +#endif // LLVM_LIBC_MACROS_LINUX_SYS_INOTIFY_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-socket-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-socket-macros.h index 2c7d55c11432..0ee66284427d 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-socket-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-socket-macros.h @@ -143,6 +143,9 @@ #define SHUT_RDWR 2 #define SCM_RIGHTS 1 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SCM_TIMESTAMPING SO_TIMESTAMPING #define MSG_OOB 0x01 #define MSG_PEEK 0x02 diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-xattr-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-xattr-macros.h new file mode 100644 index 000000000000..37fcb5b47a2b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/sys-xattr-macros.h @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Linux specific declarations of macros from sys/xattr.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_LINUX_SYS_XATTR_MACROS_H +#define LLVM_LIBC_MACROS_LINUX_SYS_XATTR_MACROS_H + +#define XATTR_CREATE 1 +#define XATTR_REPLACE 2 + +#endif // LLVM_LIBC_MACROS_LINUX_SYS_XATTR_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/unistd-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/unistd-macros.h index 9a0b8209d170..e14d44960de0 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/unistd-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/linux/unistd-macros.h @@ -20,6 +20,12 @@ #define W_OK 2 #define R_OK 4 +// Values for command argument to the lockf(...) function. +#define F_ULOCK 0 +#define F_LOCK 1 +#define F_TLOCK 2 +#define F_TEST 3 + #define _SC_ARG_MAX 0 #define _SC_CLK_TCK 2 #define _SC_OPEN_MAX 4 @@ -30,6 +36,7 @@ #define _SC_THREAD_SAFE_FUNCTIONS 68 #define _SC_GETGR_R_SIZE_MAX 69 #define _SC_GETPW_R_SIZE_MAX 70 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 73 #define _SC_THREAD_ATTR_STACKADDR 77 #define _SC_THREAD_ATTR_STACKSIZE 78 #define _SC_THREAD_PRIORITY_SCHEDULING 79 diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/pthread-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/pthread-macros.h index 5f9630546829..33d80291fb12 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/pthread-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/pthread-macros.h @@ -77,6 +77,16 @@ /* .__write_tid = */ 0, \ } +#define pthread_cleanup_push(routine, arg) \ + do { \ + struct __pthread_cleanup_frame __cleanup_frame; \ + __pthread_cleanup_push(&__cleanup_frame, (routine), (arg)) + +#define pthread_cleanup_pop(execute) \ + __pthread_cleanup_pop((execute)); \ + } \ + while (0) + // glibc extensions #define PTHREAD_STACK_MIN (1 << 14) // 16KB #define PTHREAD_RWLOCK_PREFER_READER_NP 0 diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdbit-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdbit-macros.h index c5b2f0977834..d665ebc071b7 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdbit-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdbit-macros.h @@ -213,104 +213,105 @@ inline unsigned long long stdc_bit_ceil(unsigned long long x) { return stdc_bit_ceil_ull(x); } #else -#define stdc_leading_zeros(x) \ - _Generic((x), \ +// Use variadic macros to accept compound literals containing commas. +#define stdc_leading_zeros(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_leading_zeros_uc, \ unsigned short: stdc_leading_zeros_us, \ unsigned: stdc_leading_zeros_ui, \ unsigned long: stdc_leading_zeros_ul, \ - unsigned long long: stdc_leading_zeros_ull)(x) -#define stdc_leading_ones(x) \ - _Generic((x), \ + unsigned long long: stdc_leading_zeros_ull)(__VA_ARGS__) +#define stdc_leading_ones(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_leading_ones_uc, \ unsigned short: stdc_leading_ones_us, \ unsigned: stdc_leading_ones_ui, \ unsigned long: stdc_leading_ones_ul, \ - unsigned long long: stdc_leading_ones_ull)(x) -#define stdc_trailing_zeros(x) \ - _Generic((x), \ + unsigned long long: stdc_leading_ones_ull)(__VA_ARGS__) +#define stdc_trailing_zeros(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_trailing_zeros_uc, \ unsigned short: stdc_trailing_zeros_us, \ unsigned: stdc_trailing_zeros_ui, \ unsigned long: stdc_trailing_zeros_ul, \ - unsigned long long: stdc_trailing_zeros_ull)(x) -#define stdc_trailing_ones(x) \ - _Generic((x), \ + unsigned long long: stdc_trailing_zeros_ull)(__VA_ARGS__) +#define stdc_trailing_ones(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_trailing_ones_uc, \ unsigned short: stdc_trailing_ones_us, \ unsigned: stdc_trailing_ones_ui, \ unsigned long: stdc_trailing_ones_ul, \ - unsigned long long: stdc_trailing_ones_ull)(x) -#define stdc_first_leading_zero(x) \ - _Generic((x), \ + unsigned long long: stdc_trailing_ones_ull)(__VA_ARGS__) +#define stdc_first_leading_zero(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_first_leading_zero_uc, \ unsigned short: stdc_first_leading_zero_us, \ unsigned: stdc_first_leading_zero_ui, \ unsigned long: stdc_first_leading_zero_ul, \ - unsigned long long: stdc_first_leading_zero_ull)(x) -#define stdc_first_leading_one(x) \ - _Generic((x), \ + unsigned long long: stdc_first_leading_zero_ull)(__VA_ARGS__) +#define stdc_first_leading_one(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_first_leading_one_uc, \ unsigned short: stdc_first_leading_one_us, \ unsigned: stdc_first_leading_one_ui, \ unsigned long: stdc_first_leading_one_ul, \ - unsigned long long: stdc_first_leading_one_ull)(x) -#define stdc_first_trailing_zero(x) \ - _Generic((x), \ + unsigned long long: stdc_first_leading_one_ull)(__VA_ARGS__) +#define stdc_first_trailing_zero(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_first_trailing_zero_uc, \ unsigned short: stdc_first_trailing_zero_us, \ unsigned: stdc_first_trailing_zero_ui, \ unsigned long: stdc_first_trailing_zero_ul, \ - unsigned long long: stdc_first_trailing_zero_ull)(x) -#define stdc_first_trailing_one(x) \ - _Generic((x), \ + unsigned long long: stdc_first_trailing_zero_ull)(__VA_ARGS__) +#define stdc_first_trailing_one(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_first_trailing_one_uc, \ unsigned short: stdc_first_trailing_one_us, \ unsigned: stdc_first_trailing_one_ui, \ unsigned long: stdc_first_trailing_one_ul, \ - unsigned long long: stdc_first_trailing_one_ull)(x) -#define stdc_count_zeros(x) \ - _Generic((x), \ + unsigned long long: stdc_first_trailing_one_ull)(__VA_ARGS__) +#define stdc_count_zeros(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_count_zeros_uc, \ unsigned short: stdc_count_zeros_us, \ unsigned: stdc_count_zeros_ui, \ unsigned long: stdc_count_zeros_ul, \ - unsigned long long: stdc_count_zeros_ull)(x) -#define stdc_count_ones(x) \ - _Generic((x), \ + unsigned long long: stdc_count_zeros_ull)(__VA_ARGS__) +#define stdc_count_ones(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_count_ones_uc, \ unsigned short: stdc_count_ones_us, \ unsigned: stdc_count_ones_ui, \ unsigned long: stdc_count_ones_ul, \ - unsigned long long: stdc_count_ones_ull)(x) -#define stdc_has_single_bit(x) \ - _Generic((x), \ + unsigned long long: stdc_count_ones_ull)(__VA_ARGS__) +#define stdc_has_single_bit(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_has_single_bit_uc, \ unsigned short: stdc_has_single_bit_us, \ unsigned: stdc_has_single_bit_ui, \ unsigned long: stdc_has_single_bit_ul, \ - unsigned long long: stdc_has_single_bit_ull)(x) -#define stdc_bit_width(x) \ - _Generic((x), \ + unsigned long long: stdc_has_single_bit_ull)(__VA_ARGS__) +#define stdc_bit_width(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_bit_width_uc, \ unsigned short: stdc_bit_width_us, \ unsigned: stdc_bit_width_ui, \ unsigned long: stdc_bit_width_ul, \ - unsigned long long: stdc_bit_width_ull)(x) -#define stdc_bit_floor(x) \ - _Generic((x), \ + unsigned long long: stdc_bit_width_ull)(__VA_ARGS__) +#define stdc_bit_floor(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_bit_floor_uc, \ unsigned short: stdc_bit_floor_us, \ unsigned: stdc_bit_floor_ui, \ unsigned long: stdc_bit_floor_ul, \ - unsigned long long: stdc_bit_floor_ull)(x) -#define stdc_bit_ceil(x) \ - _Generic((x), \ + unsigned long long: stdc_bit_floor_ull)(__VA_ARGS__) +#define stdc_bit_ceil(...) \ + _Generic((__VA_ARGS__), \ unsigned char: stdc_bit_ceil_uc, \ unsigned short: stdc_bit_ceil_us, \ unsigned: stdc_bit_ceil_ui, \ unsigned long: stdc_bit_ceil_ul, \ - unsigned long long: stdc_bit_ceil_ull)(x) + unsigned long long: stdc_bit_ceil_ull)(__VA_ARGS__) #endif // __cplusplus #endif // __LLVM_LIBC_MACROS_STDBIT_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdio-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdio-macros.h index 96f0e6933ade..e419a6aed5bc 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdio-macros.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/stdio-macros.h @@ -55,4 +55,33 @@ extern FILE *stderr; #define SEEK_END 2 #endif +/* + * L_tmpnam = 20 ("/tmp/" + 14 random chars + '\0'). + * Suffix length 14 (base-64) ensures a < 10^-12 collision + * probability for up to 10^6 calls (via birthday bound). + */ +#ifndef L_tmpnam +#define L_tmpnam 20 +#endif + +/* + * TMP_MAX = 1,000,000 (10^6 calls per process). + * Generous decimal call ceiling for the L_tmpnam guarantee; + * provides a 6x safety margin below the 6.2M limit (P ~= 2.6 x 10^-14). + */ +#ifndef TMP_MAX +#define TMP_MAX 1000000 +#endif + +// match linux/limits.h PATH_MAX +#ifndef FILENAME_MAX +#define FILENAME_MAX 4096 +#endif + +// Actually a lower bound on how many files we guarantee can be open at once. +// POSIX says "at least eight", which seems like a fine number to me. +#ifndef FOPEN_MAX +#define FOPEN_MAX 8 +#endif + #endif // LLVM_LIBC_MACROS_STDIO_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-eventfd-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-eventfd-macros.h new file mode 100644 index 000000000000..a0c9a46bce08 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-eventfd-macros.h @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Macros defined in sys/eventfd.h header file. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_SYS_EVENTFD_MACROS_H +#define LLVM_LIBC_MACROS_SYS_EVENTFD_MACROS_H + +#ifdef __linux__ +#include "linux/sys-eventfd-macros.h" +#endif + +#endif // LLVM_LIBC_MACROS_SYS_EVENTFD_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-inotify-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-inotify-macros.h new file mode 100644 index 000000000000..b77e9842ad14 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-inotify-macros.h @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Macros defined in sys/inotify.h header file. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_SYS_INOTIFY_MACROS_H +#define LLVM_LIBC_MACROS_SYS_INOTIFY_MACROS_H + +#ifdef __linux__ +#include "linux/sys-inotify-macros.h" +#endif + +#endif // LLVM_LIBC_MACROS_SYS_INOTIFY_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-xattr-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-xattr-macros.h new file mode 100644 index 000000000000..37eba8674962 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/sys-xattr-macros.h @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Macros defined in sys/xattr.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_SYS_XATTR_MACROS_H +#define LLVM_LIBC_MACROS_SYS_XATTR_MACROS_H + +#ifdef __linux__ +#include "linux/sys-xattr-macros.h" +#endif + +#endif // LLVM_LIBC_MACROS_SYS_XATTR_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/threads-macros.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/threads-macros.h new file mode 100644 index 000000000000..edc042a6cfbc --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-macros/threads-macros.h @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of macros from threads.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_MACROS_THREADS_MACROS_H +#define LLVM_LIBC_MACROS_THREADS_MACROS_H + +#include "common-threads-macros.h" + +/// Maximum number of destructor iterations for thread-specific storage. +#define TSS_DTOR_ITERATIONS __LLVM_LIBC_TSS_DTOR_ITERATIONS + +#endif // LLVM_LIBC_MACROS_THREADS_MACROS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/CMakeLists.txt index cc7b4df1202f..46a1a5bcfe6e 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/CMakeLists.txt @@ -30,6 +30,9 @@ function(add_type_header name) ) endfunction() +add_header(sa_family_t HDR sa_family_t.h) +add_header(struct_sockaddr HDR struct_sockaddr.h DEPENDS .sa_family_t) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) endif() @@ -60,6 +63,7 @@ add_header(__barrier_type HDR __barrier_type.h) add_header(__pthread_once_func_t HDR __pthread_once_func_t.h) add_header(__pthread_start_t HDR __pthread_start_t.h) add_header(__pthread_tss_dtor_t HDR __pthread_tss_dtor_t.h) +add_header(struct___pthread_cleanup_frame HDR struct___pthread_cleanup_frame.h) add_header(__qsortcompare_t HDR __qsortcompare_t.h) add_header(__qsortrcompare_t HDR __qsortrcompare_t.h) add_header(__thread_type HDR __thread_type.h) @@ -77,6 +81,7 @@ add_header(caddr_t HDR caddr_t.h) add_header(dev_t HDR dev_t.h) add_header(div_t HDR div_t.h) add_header(id_t HDR id_t.h) +add_header(idtype_t HDR idtype_t.h) add_header(ino64_t HDR ino64_t.h) add_header(u_int HDR u_int.h) add_header(u_int16_t HDR u_int16_t.h) @@ -133,6 +138,7 @@ add_header(nfds_t HDR nfds_t.h) add_header(nl_catd HDR nl_catd.h) add_header(nl_item HDR nl_item.h) add_header(nlink_t HDR nlink_t.h) +add_header(fpos_t HDR fpos_t.h DEPENDS .off_t .mbstate_t) add_header(once_flag HDR once_flag.h DEPENDS .__futex_word) add_header(posix_spawn_file_actions_t HDR posix_spawn_file_actions_t.h) add_header(posix_spawnattr_t HDR posix_spawnattr_t.h) @@ -262,9 +268,7 @@ add_header( ) add_header(wint_t HDR wint_t.h) add_header(wctype_t HDR wctype_t.h) -add_header(sa_family_t HDR sa_family_t.h) add_header(socklen_t HDR socklen_t.h) -add_header(struct_sockaddr HDR struct_sockaddr.h DEPENDS .sa_family_t) add_header(struct_addrinfo HDR struct_addrinfo.h DEPENDS .socklen_t .struct_sockaddr) add_header(struct_sockaddr_in HDR struct_sockaddr_in.h DEPENDS .in_port_t .sa_family_t .struct_in_addr) add_header( @@ -295,7 +299,11 @@ add_header( libc.include.llvm-libc-macros.stdint_macros ) add_header(struct_sockaddr_un HDR struct_sockaddr_un.h DEPENDS .sa_family_t) -add_header(struct_ifreq HDR struct_ifreq.h DEPENDS libc.include.llvm-libc-macros.net_if_macros .struct_sockaddr) +add_type_header( + struct_ifreq + HDR + struct_ifreq.h +) add_header(struct_if_nameindex HDR struct_if_nameindex.h) add_header(struct_iovec HDR struct_iovec.h DEPENDS .size_t) add_header(struct_linger HDR struct_linger.h) @@ -304,6 +312,7 @@ add_header(struct_cmsghdr HDR struct_cmsghdr.h DEPENDS .size_t) add_header(struct_msghdr HDR struct_msghdr.h DEPENDS .size_t .socklen_t .struct_iovec) add_header(struct_mmsghdr HDR struct_mmsghdr.h DEPENDS .struct_msghdr) add_header(struct_udphdr HDR struct_udphdr.h DEPENDS libc.include.llvm-libc-macros.stdint_macros) +add_header(struct_ether_addr HDR struct_ether_addr.h DEPENDS libc.include.llvm-libc-macros.stdint_macros) add_header(ACTION HDR ACTION.h) add_header(ENTRY HDR ENTRY.h) add_header(VISIT HDR VISIT.h) @@ -314,6 +323,7 @@ add_header(regoff_t HDR regoff_t.h) add_header(regmatch_t HDR regmatch_t.h DEPENDS .regoff_t) add_header(struct_epoll_event HDR struct_epoll_event.h) add_header(struct_epoll_data HDR struct_epoll_data.h) +add_header(struct_inotify_event HDR struct_inotify_event.h DEPENDS libc.include.llvm-libc-macros.stdint_macros) add_header( float128 HDR diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_ALLOCATE_TYPE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_ALLOCATE_TYPE.h index 90f23969678f..bf9d1249e6a1 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_ALLOCATE_TYPE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_ALLOCATE_TYPE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_ALLOCATE_TYPE type ------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_ALLOCATE_TYPE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_ALLOCATE_TYPE_H #define LLVM_LIBC_TYPES_EFI_ALLOCATE_TYPE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_BOOT_SERVICES.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_BOOT_SERVICES.h index 8b7a6aadd7a2..5a3e457822c6 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_BOOT_SERVICES.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_BOOT_SERVICES.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_BOOT_SERVICES type ------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_BOOT_SERVICES type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_BOOT_SERVICES_H #define LLVM_LIBC_TYPES_EFI_BOOT_SERVICES_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CAPSULE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CAPSULE.h index c7440c9b03b7..caf092fbe29c 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CAPSULE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CAPSULE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_CAPSULE type ------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_CAPSULE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_CAPSULE_H #define LLVM_LIBC_TYPES_EFI_CAPSULE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CONFIGURATION_TABLE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CONFIGURATION_TABLE.h index 56cd3e4fbb58..75c94a925611 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CONFIGURATION_TABLE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_CONFIGURATION_TABLE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_CONFIGURATION_TABLE type ------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_CONFIGURATION_TABLE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_CONFIGURATION_TABLE_H #define LLVM_LIBC_TYPES_EFI_CONFIGURATION_TABLE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_DEVICE_PATH_PROTOCOL.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_DEVICE_PATH_PROTOCOL.h index f6a0b2e1f45c..0fd0fc0e140b 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_DEVICE_PATH_PROTOCOL.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_DEVICE_PATH_PROTOCOL.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_DEVICE_PATH_PROTOCOL type -----------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_DEVICE_PATH_PROTOCOL type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_DEVICE_PATH_PROTOCOL_H #define LLVM_LIBC_TYPES_EFI_DEVICE_PATH_PROTOCOL_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_EVENT.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_EVENT.h index 938856b8e791..b491bbd226d6 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_EVENT.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_EVENT.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_EVENT type --------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_EVENT type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_EVENT_H #define LLVM_LIBC_TYPES_EFI_EVENT_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_GUID.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_GUID.h index b3530008384d..ef334da49595 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_GUID.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_GUID.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_GUID type -----------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_GUID type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_GUID_H #define LLVM_LIBC_TYPES_EFI_GUID_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_HANDLE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_HANDLE.h index d4376dd24753..bd5780f72945 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_HANDLE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_HANDLE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_HANDLE type ---------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_HANDLE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_HANDLE_H #define LLVM_LIBC_TYPES_EFI_HANDLE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_INTERFACE_TYPE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_INTERFACE_TYPE.h index d463c5381b3f..4c173098e652 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_INTERFACE_TYPE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_INTERFACE_TYPE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_INTERFACE_TYPE type -----------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_INTERFACE_TYPE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_INTERFACE_TYPE_H #define LLVM_LIBC_TYPES_EFI_INTERFACE_TYPE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_LOCATE_SEARCH_TYPE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_LOCATE_SEARCH_TYPE.h index 3a8fd7bc3e77..cff00e8597c9 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_LOCATE_SEARCH_TYPE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_LOCATE_SEARCH_TYPE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_LOCATE_SEARCH_TYPE type -------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_LOCATE_SEARCH_TYPE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_LOCATE_SEARCH_TYPE_H #define LLVM_LIBC_TYPES_EFI_LOCATE_SEARCH_TYPE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_DESCRIPTOR.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_DESCRIPTOR.h index 72d0579aef76..df43d88444ab 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_DESCRIPTOR.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_DESCRIPTOR.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_MEMORY_DESCRIPTOR type --------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_MEMORY_DESCRIPTOR type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_MEMORY_DESCRIPTOR_H #define LLVM_LIBC_TYPES_EFI_MEMORY_DESCRIPTOR_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_TYPE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_TYPE.h index c8921cda2c38..732c5ca14fa2 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_TYPE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_MEMORY_TYPE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_MEMORY_TYPE type --------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_MEMORY_TYPE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_MEMORY_TYPE_H #define LLVM_LIBC_TYPES_EFI_MEMORY_TYPE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_OPEN_PROTOCOL_INFORMATION_ENTRY.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_OPEN_PROTOCOL_INFORMATION_ENTRY.h index de0c59c139ef..8c22be4d8537 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_OPEN_PROTOCOL_INFORMATION_ENTRY.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_OPEN_PROTOCOL_INFORMATION_ENTRY.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY type ------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_OPEN_PROTOCOL_INFORMATION_ENTRY type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_OPEN_PROTOCOL_INFORMATION_ENTRY_H #define LLVM_LIBC_TYPES_EFI_OPEN_PROTOCOL_INFORMATION_ENTRY_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_PHYSICAL_ADDRESS.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_PHYSICAL_ADDRESS.h index 8880ee66c0f8..c5e2398ddbb9 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_PHYSICAL_ADDRESS.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_PHYSICAL_ADDRESS.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_PHYSICAL_ADDRESS type ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_PHYSICAL_ADDRESS type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_PHYSICAL_ADDRESS_H #define LLVM_LIBC_TYPES_EFI_PHYSICAL_ADDRESS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h index 8913118b0844..9483d261a0ea 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_RUNTIME_SERVICES.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_RUNTIME_SERVICES type ---------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_RUNTIME_SERVICES type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_RUNTIME_SERVICES_H #define LLVM_LIBC_TYPES_EFI_RUNTIME_SERVICES_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h index a6dc0952b631..d13e67a45f35 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_INPUT_PROTOCOL.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_SIMPLE_TEXT_INPUT_PROTOCOL type -----------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_SIMPLE_TEXT_INPUT_PROTOCOL type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_SIMPLE_TEXT_INPUT_PROTOCOL_H #define LLVM_LIBC_TYPES_EFI_SIMPLE_TEXT_INPUT_PROTOCOL_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h index 91d169f018db..48a95bdbbeee 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL type ----------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_H #define LLVM_LIBC_TYPES_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_STATUS.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_STATUS.h index bb9542bed8ef..a8819326e712 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_STATUS.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_STATUS.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_STATUS type ---------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_STATUS type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_STATUS_H #define LLVM_LIBC_TYPES_EFI_STATUS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SYSTEM_TABLE.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SYSTEM_TABLE.h index 290067ad862e..53b42f2457ce 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SYSTEM_TABLE.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_SYSTEM_TABLE.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_SYSTEM_TABLE type -------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_SYSTEM_TABLE type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_SYSTEM_TABLE_H #define LLVM_LIBC_TYPES_EFI_SYSTEM_TABLE_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TABLE_HEADER.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TABLE_HEADER.h index 293968ecc4d1..27e1be954eeb 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TABLE_HEADER.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TABLE_HEADER.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_TABLE_HEADER type -------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_TABLE_HEADER type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_TABLE_HEADER_H #define LLVM_LIBC_TYPES_EFI_TABLE_HEADER_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIME.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIME.h index b0e38b987d44..8df551fafdfb 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIME.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIME.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_TIME type ---------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_TIME type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_TIME_H #define LLVM_LIBC_TYPES_EFI_TIME_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIMER_DELAY.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIMER_DELAY.h index 2a6872c69c8b..0785d60bef57 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIMER_DELAY.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TIMER_DELAY.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_TIMER_DELAY type --------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_TIMER_DELAY type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_TIMER_DELAY_H #define LLVM_LIBC_TYPES_EFI_TIMER_DELAY_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TPL.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TPL.h index 8361ccfacd6f..477efaf24294 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TPL.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_TPL.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_TPL type ----------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_TPL type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_TPL_H #define LLVM_LIBC_TYPES_EFI_TPL_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_VIRTUAL_ADDRESS.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_VIRTUAL_ADDRESS.h index 46cbec734dad..4fbf1807865e 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_VIRTUAL_ADDRESS.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/EFI_VIRTUAL_ADDRESS.h @@ -1,10 +1,15 @@ -//===-- Definition of EFI_VIRTUAL_ADDRESS type ----------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of EFI_VIRTUAL_ADDRESS type. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_TYPES_EFI_VIRTUAL_ADDRESS_H #define LLVM_LIBC_TYPES_EFI_VIRTUAL_ADDRESS_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/__jmp_buf.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/__jmp_buf.h index 266d2ffffa8b..91f7305222c2 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/__jmp_buf.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/__jmp_buf.h @@ -60,6 +60,12 @@ typedef struct { #if __ARM_FP long fopaque[8]; // d8-d15 #endif +#elif defined(__hexagon__) + // Callee-saved registers r16-r27, followed by sp (r29), fp (r30) and lr + // (r31). r16-r27 are saved and restored as register pairs using memd, which + // requires the buffer to be 8-byte aligned, hence long long rather than + // long. That also rounds the size up, leaving one word of tail padding. + long long opaque[8]; #else #error "__jmp_buf not available for your target architecture." #endif diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fenv_t.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fenv_t.h index f9b10762a02b..3fc6a92ec9a6 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fenv_t.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fenv_t.h @@ -32,6 +32,8 @@ typedef struct { } fenv_t; #elif defined(__riscv) typedef unsigned int fenv_t; +#elif defined(__hexagon__) +typedef unsigned int fenv_t; #elif defined(__AMDGPU__) || defined(__NVPTX__) || defined(__SPIRV__) typedef struct { unsigned int __fpc; diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fpos_t.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fpos_t.h new file mode 100644 index 000000000000..15ad67806a08 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/fpos_t.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of fpos_t type. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_FPOS_T_H +#define LLVM_LIBC_TYPES_FPOS_T_H + +#include "mbstate_t.h" +#include "off_t.h" + +typedef struct { + off_t __pos; + mbstate_t __state; +} fpos_t; + +#endif // LLVM_LIBC_TYPES_FPOS_T_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/idtype_t.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/idtype_t.h new file mode 100644 index 000000000000..c3c5d117b08f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/idtype_t.h @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of idtype_t type. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_IDTYPE_T_H +#define LLVM_LIBC_TYPES_IDTYPE_T_H + +typedef int idtype_t; + +#endif // LLVM_LIBC_TYPES_IDTYPE_T_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/CMakeLists.txt index d937ffe30e6e..3796f597596d 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/CMakeLists.txt @@ -9,3 +9,19 @@ add_header( HDR struct_sysinfo.h ) + +add_header( + struct_ifmap + HDR + struct_ifmap.h +) + +add_header( + struct_ifreq + HDR + struct_ifreq.h + DEPENDS + .struct_ifmap + libc.include.llvm-libc-macros.net_if_macros + libc.include.llvm-libc-types.struct_sockaddr +) diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifmap.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifmap.h new file mode 100644 index 000000000000..2546bb832743 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifmap.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of struct ifmap for Linux. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_LINUX_STRUCT_IFMAP_H +#define LLVM_LIBC_TYPES_LINUX_STRUCT_IFMAP_H + +// Prevent the linux headers from defining this type. +#define __UAPI_DEF_IF_IFMAP 0 + +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +#endif // LLVM_LIBC_TYPES_LINUX_STRUCT_IFMAP_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifreq.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifreq.h new file mode 100644 index 000000000000..eb0163e47a0f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/linux/struct_ifreq.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of struct ifreq for Linux. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_LINUX_STRUCT_IFREQ_H +#define LLVM_LIBC_TYPES_LINUX_STRUCT_IFREQ_H + +#include "../../llvm-libc-macros/net-if-macros.h" +#include "../struct_sockaddr.h" +#include "struct_ifmap.h" + +// Prevent the linux headers from defining this type. +#define __UAPI_DEF_IF_IFREQ 0 + +struct ifreq { + union { + char ifrn_name[IF_NAMESIZE]; + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short int ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IF_NAMESIZE]; + char ifru_newname[IF_NAMESIZE]; + char *ifru_data; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name +#define ifr_hwaddr ifr_ifru.ifru_hwaddr +#define ifr_addr ifr_ifru.ifru_addr +#define ifr_dstaddr ifr_ifru.ifru_dstaddr +#define ifr_broadaddr ifr_ifru.ifru_broadaddr +#define ifr_netmask ifr_ifru.ifru_netmask +#define ifr_flags ifr_ifru.ifru_flags +#define ifr_metric ifr_ifru.ifru_ivalue +#define ifr_mtu ifr_ifru.ifru_mtu +#define ifr_map ifr_ifru.ifru_map +#define ifr_slave ifr_ifru.ifru_slave +#define ifr_data ifr_ifru.ifru_data +#define ifr_ifindex ifr_ifru.ifru_ivalue +#define ifr_bandwidth ifr_ifru.ifru_ivalue +#define ifr_qlen ifr_ifru.ifru_ivalue +#define ifr_newname ifr_ifru.ifru_newname + +#endif // LLVM_LIBC_TYPES_LINUX_STRUCT_IFREQ_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/sighandler_t.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/sighandler_t.h index f39ab0468520..d42168093fa9 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/sighandler_t.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/sighandler_t.h @@ -9,9 +9,6 @@ #ifndef LLVM_LIBC_TYPES_SIGHANDLER_T_H #define LLVM_LIBC_TYPES_SIGHANDLER_T_H -#ifdef __linux__ -// For compatibility with glibc. typedef void (*sighandler_t)(int); -#endif #endif // LLVM_LIBC_TYPES_SIGHANDLER_T_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct___pthread_cleanup_frame.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct___pthread_cleanup_frame.h new file mode 100644 index 000000000000..0623830f9b05 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct___pthread_cleanup_frame.h @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of struct __pthread_cleanup_frame. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_STRUCT___PTHREAD_CLEANUP_FRAME_H +#define LLVM_LIBC_TYPES_STRUCT___PTHREAD_CLEANUP_FRAME_H + +struct __pthread_cleanup_frame { + void (*__routine)(void *); + void *__arg; + struct __pthread_cleanup_frame *__next; +}; + +#endif // LLVM_LIBC_TYPES_STRUCT___PTHREAD_CLEANUP_FRAME_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ether_addr.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ether_addr.h new file mode 100644 index 000000000000..4af8e7f3f8eb --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ether_addr.h @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of struct ether_addr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_STRUCT_ETHER_ADDR_H +#define LLVM_LIBC_TYPES_STRUCT_ETHER_ADDR_H + +#include "../llvm-libc-macros/stdint-macros.h" + +struct ether_addr { + uint8_t ether_addr_octet[6]; +}; + +#endif // LLVM_LIBC_TYPES_STRUCT_ETHER_ADDR_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ifreq.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ifreq.h index b9ad182f9780..0a08f94eefb7 100644 --- a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ifreq.h +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_ifreq.h @@ -14,27 +14,8 @@ #ifndef LLVM_LIBC_TYPES_STRUCT_IFREQ_H #define LLVM_LIBC_TYPES_STRUCT_IFREQ_H -#include "../llvm-libc-macros/net-if-macros.h" -#include "struct_sockaddr.h" - -struct ifreq { - char ifr_name[IF_NAMESIZE]; - __extension__ union { - struct sockaddr ifr_hwaddr; - struct sockaddr ifr_addr; - struct sockaddr ifr_dstaddr; - struct sockaddr ifr_broadaddr; - struct sockaddr ifr_netmask; - short int ifr_flags; - int ifr_metric; - int ifr_mtu; - int ifr_ifindex; - int ifr_bandwidth; - int ifr_qlen; - char ifr_newname[IF_NAMESIZE]; - char ifr_slave[IF_NAMESIZE]; - char *ifr_data; - }; -}; +#if defined(__linux__) +#include "linux/struct_ifreq.h" +#endif #endif // LLVM_LIBC_TYPES_STRUCT_IFREQ_H diff --git a/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_inotify_event.h b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_inotify_event.h new file mode 100644 index 000000000000..08c505b7954b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/llvm-libc-types/struct_inotify_event.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of struct inotify_event. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TYPES_STRUCT_INOTIFY_EVENT_H +#define LLVM_LIBC_TYPES_STRUCT_INOTIFY_EVENT_H + +#include "../llvm-libc-macros/stdint-macros.h" + +struct inotify_event { + int wd; + uint32_t mask; + uint32_t cookie; + uint32_t len; + char name[]; +}; + +#endif // LLVM_LIBC_TYPES_STRUCT_INOTIFY_EVENT_H diff --git a/deps/v8/third_party/llvm-libc/src/include/net/ethernet.yaml b/deps/v8/third_party/llvm-libc/src/include/net/ethernet.yaml new file mode 100644 index 000000000000..b6de7563f23b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/net/ethernet.yaml @@ -0,0 +1,10 @@ +header: net/ethernet.h +standards: + - bsd +macros: [] +types: + - type_name: struct_ether_addr +enums: [] +objects: [] +functions: [] + diff --git a/deps/v8/third_party/llvm-libc/src/include/net/if.yaml b/deps/v8/third_party/llvm-libc/src/include/net/if.yaml index 3b6d807e2fce..2a8f33c0738f 100644 --- a/deps/v8/third_party/llvm-libc/src/include/net/if.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/net/if.yaml @@ -2,6 +2,10 @@ header: net/if.h standards: - posix macros: + - macro_name: IFNAMSIZ + standards: + - bsd + macro_header: net-if-macros.h - macro_name: IF_NAMESIZE macro_header: net-if-macros.h types: diff --git a/deps/v8/third_party/llvm-libc/src/include/netinet/ether.yaml b/deps/v8/third_party/llvm-libc/src/include/netinet/ether.yaml new file mode 100644 index 000000000000..99a65a781c11 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/netinet/ether.yaml @@ -0,0 +1,21 @@ +header: netinet/ether.h +standards: + - bsd +macros: [] +types: [] +enums: [] +objects: [] +functions: + - name: ether_ntoa + standards: + - bsd + return_type: char * + arguments: + - type: const struct ether_addr * + - name: ether_ntoa_r + standards: + - gnu + return_type: char * + arguments: + - type: const struct ether_addr * + - type: char * diff --git a/deps/v8/third_party/llvm-libc/src/include/poll.yaml b/deps/v8/third_party/llvm-libc/src/include/poll.yaml index bb7d99e87aa0..1bf1a4e2448a 100644 --- a/deps/v8/third_party/llvm-libc/src/include/poll.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/poll.yaml @@ -25,6 +25,8 @@ macros: types: - type_name: struct_pollfd - type_name: nfds_t + - type_name: struct_timespec + - type_name: sigset_t enums: [] functions: - name: poll @@ -35,3 +37,12 @@ functions: - type: struct pollfd * - type: nfds_t - type: int + - name: ppoll + standards: + - posix + return_type: int + arguments: + - type: struct pollfd * + - type: nfds_t + - type: const struct timespec *__restrict + - type: const sigset_t *__restrict diff --git a/deps/v8/third_party/llvm-libc/src/include/pthread.yaml b/deps/v8/third_party/llvm-libc/src/include/pthread.yaml index 875dec99f7fd..23f9dc4926e3 100644 --- a/deps/v8/third_party/llvm-libc/src/include/pthread.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/pthread.yaml @@ -62,6 +62,10 @@ macros: standards: - llvm_libc_ext macro_header: pthread-macros.h + - macro_name: "pthread_cleanup_pop" + macro_header: pthread-macros.h + - macro_name: "pthread_cleanup_push" + macro_header: pthread-macros.h types: - type_name: pthread_t - type_name: pthread_once_t @@ -79,7 +83,24 @@ types: - type_name: pthread_id_np_t standards: - llvm_libc_ext + - type_name: struct___pthread_cleanup_frame + standards: + - llvm_libc_ext functions: + - name: __pthread_cleanup_pop + standards: + - llvm_libc_ext + return_type: void + arguments: + - type: int + - name: __pthread_cleanup_push + standards: + - llvm_libc_ext + return_type: void + arguments: + - type: struct __pthread_cleanup_frame * + - type: void (*)(void *) + - type: void * - name: pthread_atfork return_type: int arguments: diff --git a/deps/v8/third_party/llvm-libc/src/include/pwd.yaml b/deps/v8/third_party/llvm-libc/src/include/pwd.yaml index 9301307d22d3..3dfc58967e4b 100644 --- a/deps/v8/third_party/llvm-libc/src/include/pwd.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/pwd.yaml @@ -14,6 +14,15 @@ functions: - posix return_type: struct passwd * arguments: [] + - name: getpwent_r + standards: + - gnu + return_type: int + arguments: + - type: struct passwd * + - type: char * + - type: size_t + - type: struct passwd ** - name: setpwent standards: - posix diff --git a/deps/v8/third_party/llvm-libc/src/include/sched.yaml b/deps/v8/third_party/llvm-libc/src/include/sched.yaml index 812f528bcaaf..6997753144a8 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sched.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sched.yaml @@ -1,6 +1,7 @@ header: sched.h standards: - posix + - linux macros: - macro_name: SCHED_OTHER macro_header: sched-macros.h @@ -18,6 +19,16 @@ types: enums: [] objects: [] functions: + - name: clone + standards: + - linux + return_type: int + arguments: + - type: int (*)(void *) + - type: void * + - type: int + - type: void * + - type: '...' - name: __sched_andcpuset standards: - llvm_libc_ext diff --git a/deps/v8/third_party/llvm-libc/src/include/signal.yaml b/deps/v8/third_party/llvm-libc/src/include/signal.yaml index f5f110915cfc..b763da7eeb60 100644 --- a/deps/v8/third_party/llvm-libc/src/include/signal.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/signal.yaml @@ -37,6 +37,7 @@ types: - type_name: sighandler_t standards: - gnu + - llvm_libc_ext - type_name: siginfo_t - type_name: sigset_t - type_name: stack_t @@ -103,18 +104,21 @@ functions: return_type: int arguments: - type: sigset_t * + - name: sigismember + standards: + - posix + return_type: int + arguments: + - type: const sigset_t * + - type: int + - name: signal standards: - stdc - # May the Geneva Convention have mercy on my soul... Why this insanity? - # Well: signal returns a function pointer to a function with no return - # value and which accepts an int. The parameter list appears on the far - # right of the declaration. i.e. - # void (*signal(int, void (*)(int)))(int); - return_type: void (* + return_type: sighandler_t arguments: - type: int - - type: void (*)(int)))(int + - type: sighandler_t - name: sigprocmask standards: - posix diff --git a/deps/v8/third_party/llvm-libc/src/include/stdio.yaml b/deps/v8/third_party/llvm-libc/src/include/stdio.yaml index bb28dadd29b3..251840d8670a 100644 --- a/deps/v8/third_party/llvm-libc/src/include/stdio.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/stdio.yaml @@ -26,6 +26,14 @@ macros: macro_header: stdio-macros.h - macro_name: _IOFBF macro_header: stdio-macros.h + - macro_name: L_tmpnam + macro_header: stdio-macros.h + - macro_name: TMP_MAX + macro_header: stdio-macros.h + - macro_name: FILENAME_MAX + macro_header: stdio-macros.h + - macro_name: FOPEN_MAX + macro_header: stdio-macros.h types: - type_name: rsize_t - type_name: size_t @@ -33,6 +41,7 @@ types: - type_name: cookie_io_functions_t - type_name: FILE - type_name: errno_t + - type_name: fpos_t enums: [] objects: - object_name: stdin @@ -226,6 +235,20 @@ functions: - type: FILE *__restrict - type: const char *__restrict - type: va_list + - name: fgetpos + standards: + - stdc + return_type: int + arguments: + - type: FILE *__restrict + - type: fpos_t *__restrict + - name: fsetpos + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - type: const fpos_t * - name: fseek standards: - stdc @@ -306,12 +329,25 @@ functions: - posix return_type: int arguments: [] + - name: pclose + standards: + - posix + return_type: int + arguments: + - type: FILE * - name: perror standards: - stdc return_type: void arguments: - type: const char * + - name: popen + standards: + - posix + return_type: FILE * + arguments: + - type: const char * + - type: const char * - name: printf standards: - stdc @@ -353,6 +389,15 @@ functions: arguments: - type: const char * - type: const char * + - name: renameat + standards: + - posix + return_type: int + arguments: + - type: int + - type: const char * + - type: int + - type: const char * - name: scanf standards: - stdc @@ -418,6 +463,12 @@ functions: return_type: FILE * arguments: - type: void + - name: tmpnam + standards: + - stdc + return_type: char * + arguments: + - type: char * - name: ungetc standards: - stdc diff --git a/deps/v8/third_party/llvm-libc/src/include/stdlib.yaml b/deps/v8/third_party/llvm-libc/src/include/stdlib.yaml index aabb9dd106af..d278b8daa67a 100644 --- a/deps/v8/third_party/llvm-libc/src/include/stdlib.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/stdlib.yaml @@ -97,6 +97,12 @@ functions: - type: size_t - type: size_t - type: __search_compare_t + - name: clearenv + standards: + - gnu + return_type: int + arguments: + - type: void - name: div standards: - stdc @@ -255,6 +261,12 @@ functions: return_type: void arguments: - type: unsigned int + - name: secure_getenv + standards: + - posix + return_type: char * + arguments: + - type: const char * - name: setenv standards: - posix @@ -281,6 +293,16 @@ functions: - type: size_t - type: const char *__restrict - type: float + - name: strfromf128 + standards: + - stdc + return_type: int + arguments: + - type: char *__restrict + - type: size_t + - type: const char *__restrict + - type: float128 + guard: LIBC_TYPES_HAS_NATIVE_FLOAT128 - name: strfroml standards: - stdc diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/eventfd.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/eventfd.yaml new file mode 100644 index 000000000000..2106a1d5292c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/sys/eventfd.yaml @@ -0,0 +1,19 @@ +header: sys/eventfd.h +standards: + - linux +macros: + - macro_name: EFD_CLOEXEC + macro_header: sys-eventfd-macros.h + - macro_name: EFD_NONBLOCK + macro_header: sys-eventfd-macros.h + - macro_name: EFD_SEMAPHORE + macro_header: sys-eventfd-macros.h +types: [] +enums: [] +objects: [] +functions: + - name: eventfd + return_type: int + arguments: + - type: unsigned int + - type: int diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/inotify.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/inotify.yaml new file mode 100644 index 000000000000..d102f19a5efb --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/include/sys/inotify.yaml @@ -0,0 +1,82 @@ +header: sys/inotify.h +standards: + - linux +macros: + - macro_name: IN_ACCESS + macro_header: sys-inotify-macros.h + - macro_name: IN_MODIFY + macro_header: sys-inotify-macros.h + - macro_name: IN_ATTRIB + macro_header: sys-inotify-macros.h + - macro_name: IN_CLOSE_WRITE + macro_header: sys-inotify-macros.h + - macro_name: IN_CLOSE_NOWRITE + macro_header: sys-inotify-macros.h + - macro_name: IN_CLOSE + macro_header: sys-inotify-macros.h + - macro_name: IN_OPEN + macro_header: sys-inotify-macros.h + - macro_name: IN_MOVED_FROM + macro_header: sys-inotify-macros.h + - macro_name: IN_MOVED_TO + macro_header: sys-inotify-macros.h + - macro_name: IN_MOVE + macro_header: sys-inotify-macros.h + - macro_name: IN_CREATE + macro_header: sys-inotify-macros.h + - macro_name: IN_DELETE + macro_header: sys-inotify-macros.h + - macro_name: IN_DELETE_SELF + macro_header: sys-inotify-macros.h + - macro_name: IN_MOVE_SELF + macro_header: sys-inotify-macros.h + - macro_name: IN_UNMOUNT + macro_header: sys-inotify-macros.h + - macro_name: IN_Q_OVERFLOW + macro_header: sys-inotify-macros.h + - macro_name: IN_IGNORED + macro_header: sys-inotify-macros.h + - macro_name: IN_ONLYDIR + macro_header: sys-inotify-macros.h + - macro_name: IN_DONT_FOLLOW + macro_header: sys-inotify-macros.h + - macro_name: IN_EXCL_UNLINK + macro_header: sys-inotify-macros.h + - macro_name: IN_MASK_CREATE + macro_header: sys-inotify-macros.h + - macro_name: IN_MASK_ADD + macro_header: sys-inotify-macros.h + - macro_name: IN_ISDIR + macro_header: sys-inotify-macros.h + - macro_name: IN_ONESHOT + macro_header: sys-inotify-macros.h + - macro_name: IN_ALL_EVENTS + macro_header: sys-inotify-macros.h + - macro_name: IN_CLOEXEC + macro_header: sys-inotify-macros.h + - macro_name: IN_NONBLOCK + macro_header: sys-inotify-macros.h +types: + - type_name: struct_inotify_event +enums: [] +objects: [] +functions: + - name: inotify_init + return_type: int + arguments: + - type: void + - name: inotify_init1 + return_type: int + arguments: + - type: int + - name: inotify_add_watch + return_type: int + arguments: + - type: int + - type: const char * + - type: uint32_t + - name: inotify_rm_watch + return_type: int + arguments: + - type: int + - type: int diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/mman.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/mman.yaml index bbd3ebaf72d4..8e58a3e0496f 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sys/mman.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sys/mman.yaml @@ -41,14 +41,14 @@ functions: - posix return_type: int arguments: - - type: void * + - type: const void * - type: size_t - name: mlock2 standards: - linux return_type: int arguments: - - type: void * + - type: const void * - type: size_t - type: unsigned int - name: mlockall @@ -99,7 +99,7 @@ functions: - posix return_type: int arguments: - - type: void * + - type: const void * - type: size_t - name: munlockall standards: diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/random.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/random.yaml index c57a6fe7ccc7..0b3ecd650784 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sys/random.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sys/random.yaml @@ -18,7 +18,7 @@ functions: - type: unsigned int - name: getentropy standards: - - gnu + - posix return_type: int arguments: - type: void * diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/select.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/select.yaml index 3c0a026c13ed..017ce0b4ca4a 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sys/select.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sys/select.yaml @@ -24,3 +24,14 @@ functions: - type: fd_set *__restrict - type: fd_set *__restrict - type: struct timeval *__restrict + - name: pselect + standards: + - posix + return_type: int + arguments: + - type: int + - type: fd_set *__restrict + - type: fd_set *__restrict + - type: fd_set *__restrict + - type: const struct timespec *__restrict + - type: const sigset_t *__restrict diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/stat.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/stat.yaml index 3c75ce3d796c..718aff2946ea 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sys/stat.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sys/stat.yaml @@ -42,6 +42,13 @@ functions: arguments: - type: int - type: struct stat * + - name: fstatat + return_type: int + arguments: + - type: int + - type: const char *__restrict + - type: struct stat *__restrict + - type: int - name: lstat return_type: int arguments: @@ -63,6 +70,25 @@ functions: arguments: - type: const char * - type: mode_t + - name: mkfifoat + return_type: int + arguments: + - type: int + - type: const char * + - type: mode_t + - name: mknod + return_type: int + arguments: + - type: const char * + - type: mode_t + - type: dev_t + - name: mknodat + return_type: int + arguments: + - type: int + - type: const char * + - type: mode_t + - type: dev_t - name: stat return_type: int arguments: diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/wait.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/wait.yaml index c5928cc1502a..bf296381a337 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sys/wait.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sys/wait.yaml @@ -8,6 +8,8 @@ types: - type_name: siginfo_t - type_name: struct_rusage - type_name: pid_t + - type_name: id_t + - type_name: idtype_t enums: [] objects: [] functions: @@ -27,6 +29,15 @@ functions: - type: int * - type: int - type: struct rusage * + - name: waitid + standards: + - posix + return_type: int + arguments: + - type: idtype_t + - type: id_t + - type: siginfo_t * + - type: int - name: waitpid standards: - posix diff --git a/deps/v8/third_party/llvm-libc/src/include/sys/xattr.yaml b/deps/v8/third_party/llvm-libc/src/include/sys/xattr.yaml index 5f8b6174af02..3d1f30bd4337 100644 --- a/deps/v8/third_party/llvm-libc/src/include/sys/xattr.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/sys/xattr.yaml @@ -1,13 +1,74 @@ header: sys/xattr.h standards: - linux -macros: [] +macros: + - macro_name: XATTR_CREATE + macro_header: sys-xattr-macros.h + - macro_name: XATTR_REPLACE + macro_header: sys-xattr-macros.h types: - type_name: size_t - type_name: ssize_t enums: [] objects: [] functions: + - name: getxattr + standards: + - linux + return_type: ssize_t + arguments: + - type: const char * + - type: const char * + - type: void * + - type: size_t + - name: lgetxattr + standards: + - linux + return_type: ssize_t + arguments: + - type: const char * + - type: const char * + - type: void * + - type: size_t + - name: fgetxattr + standards: + - linux + return_type: ssize_t + arguments: + - type: int + - type: const char * + - type: void * + - type: size_t + - name: setxattr + standards: + - linux + return_type: int + arguments: + - type: const char * + - type: const char * + - type: const void * + - type: size_t + - type: int + - name: lsetxattr + standards: + - linux + return_type: int + arguments: + - type: const char * + - type: const char * + - type: const void * + - type: size_t + - type: int + - name: fsetxattr + standards: + - linux + return_type: int + arguments: + - type: int + - type: const char * + - type: const void * + - type: size_t + - type: int - name: listxattr standards: - linux diff --git a/deps/v8/third_party/llvm-libc/src/include/termios.yaml b/deps/v8/third_party/llvm-libc/src/include/termios.yaml index 21ee25d700d9..16173beb742b 100644 --- a/deps/v8/third_party/llvm-libc/src/include/termios.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/termios.yaml @@ -10,6 +10,7 @@ types: - type_name: speed_t - type_name: pid_t - type_name: cc_t + - type_name: struct_winsize enums: [] objects: [] functions: @@ -87,3 +88,17 @@ functions: - type: int - type: int - type: struct termios * + - name: tcgetwinsize + standards: + - posix + return_type: int + arguments: + - type: int + - type: struct winsize * + - name: tcsetwinsize + standards: + - posix + return_type: int + arguments: + - type: int + - type: const struct winsize * diff --git a/deps/v8/third_party/llvm-libc/src/include/threads.yaml b/deps/v8/third_party/llvm-libc/src/include/threads.yaml index 1e8e42c80587..6b41524e587c 100644 --- a/deps/v8/third_party/llvm-libc/src/include/threads.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/threads.yaml @@ -4,6 +4,8 @@ standards: macros: - macro_name: ONCE_FLAG_INIT macro_value: '{0}' + - macro_name: TSS_DTOR_ITERATIONS + macro_header: threads-macros.h types: - type_name: once_flag - type_name: __call_once_func_t diff --git a/deps/v8/third_party/llvm-libc/src/include/time.yaml b/deps/v8/third_party/llvm-libc/src/include/time.yaml index 44044604a647..d63dc20e46e5 100644 --- a/deps/v8/third_party/llvm-libc/src/include/time.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/time.yaml @@ -77,6 +77,13 @@ functions: return_type: clock_t arguments: - type: void + - name: clock_getres + standards: + - posix + return_type: int + arguments: + - type: clockid_t + - type: struct timespec * - name: clock_gettime standards: - posix @@ -178,6 +185,12 @@ functions: return_type: int arguments: - type: timer_t + - name: timer_getoverrun + standards: + - posix + return_type: int + arguments: + - type: timer_t - name: timer_gettime standards: - posix diff --git a/deps/v8/third_party/llvm-libc/src/include/unistd.yaml b/deps/v8/third_party/llvm-libc/src/include/unistd.yaml index 890a4ae21f19..96ce15eee40b 100644 --- a/deps/v8/third_party/llvm-libc/src/include/unistd.yaml +++ b/deps/v8/third_party/llvm-libc/src/include/unistd.yaml @@ -34,6 +34,8 @@ macros: macro_header: unistd-macros.h - macro_name: _SC_GETPW_R_SIZE_MAX macro_header: unistd-macros.h + - macro_name: _SC_THREAD_DESTRUCTOR_ITERATIONS + macro_header: unistd-macros.h - macro_name: _SC_THREAD_ATTR_STACKADDR macro_header: unistd-macros.h - macro_name: _SC_THREAD_ATTR_STACKSIZE @@ -86,6 +88,14 @@ macros: macro_header: unistd-macros.h - macro_name: _POSIX_THREAD_SPORADIC_SERVER macro_header: unistd-macros.h + - macro_name: F_ULOCK + macro_header: unistd-macros.h + - macro_name: F_LOCK + macro_header: unistd-macros.h + - macro_name: F_TLOCK + macro_header: unistd-macros.h + - macro_name: F_TEST + macro_header: unistd-macros.h types: - type_name: uid_t - type_name: gid_t @@ -212,6 +222,14 @@ functions: - type: const char * - type: const char * - type: '...' + - name: execlp + standards: + - posix + return_type: int + arguments: + - type: const char * + - type: const char * + - type: '...' - name: execv standards: - posix @@ -227,6 +245,21 @@ functions: - type: const char * - type: __exec_argv_t - type: __exec_envp_t + - name: execvp + standards: + - posix + return_type: int + arguments: + - type: const char * + - type: __exec_argv_t + - name: execvpe + standards: + - gnu + return_type: int + arguments: + - type: const char * + - type: __exec_argv_t + - type: __exec_envp_t - name: faccessat standards: - posix @@ -250,6 +283,30 @@ functions: - type: int - type: uid_t - type: gid_t + - name: fchownat + standards: + - posix + return_type: int + arguments: + - type: int + - type: const char * + - type: uid_t + - type: gid_t + - type: int + - name: fdatasync + standards: + - posix + return_type: int + arguments: + - type: int + - name: fexecve + standards: + - posix + return_type: int + arguments: + - type: int + - type: char *const [] + - type: char *const [] - name: fpathconf standards: - posix @@ -379,6 +436,14 @@ functions: - type: int guard: null attributes: [] + - name: lchown + standards: + - posix + return_type: int + arguments: + - type: const char * + - type: uid_t + - type: gid_t - name: link standards: - posix @@ -396,6 +461,14 @@ functions: - type: int - type: const char * - type: int + - name: lockf + standards: + - posix + return_type: int + arguments: + - type: int + - type: int + - type: off_t - name: lseek standards: - posix @@ -417,6 +490,12 @@ functions: arguments: - type: const char * - type: int + - name: pause + standards: + - posix + return_type: int + arguments: + - type: void - name: pipe standards: - posix @@ -487,6 +566,18 @@ functions: - type: const void *__restrict - type: void * - type: ssize_t + - name: setegid + standards: + - posix + return_type: int + arguments: + - type: gid_t + - name: seteuid + standards: + - posix + return_type: int + arguments: + - type: uid_t - name: setgid standards: - posix @@ -507,6 +598,14 @@ functions: arguments: - type: gid_t - type: gid_t + - name: setresgid + standards: + - linux + return_type: int + arguments: + - type: gid_t + - type: gid_t + - type: gid_t - name: setreuid standards: - posix @@ -514,6 +613,14 @@ functions: arguments: - type: uid_t - type: uid_t + - name: setresuid + standards: + - linux + return_type: int + arguments: + - type: uid_t + - type: uid_t + - type: uid_t - name: setsid standards: - posix @@ -547,6 +654,18 @@ functions: - type: const char * - type: int - type: const char * + - name: sync + standards: + - posix + return_type: void + arguments: + - type: void + - name: syncfs + standards: + - linux + return_type: int + arguments: + - type: int - name: sysconf standards: - posix diff --git a/deps/v8/third_party/llvm-libc/src/shared/bit.h b/deps/v8/third_party/llvm-libc/src/shared/bit.h new file mode 100644 index 000000000000..57b5a0c8a835 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/bit.h @@ -0,0 +1,23 @@ +//===-- Bit manipulation utils ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BIT_H +#define LLVM_LIBC_SHARED_BIT_H + +#include "libc_common.h" +#include "src/__support/CPP/bit.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using cpp::bit_cast; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_BIT_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins.h b/deps/v8/third_party/llvm-libc/src/shared/builtins.h index 21c2bed4a0af..1cfbf999a22e 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/builtins.h +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins.h @@ -24,6 +24,9 @@ #include "builtins/divsf3.h" #include "builtins/divtf3.h" #include "builtins/extenddftf2.h" +#include "builtins/extendhfdf2.h" +#include "builtins/extendhfsf2.h" +#include "builtins/extendhftf2.h" #include "builtins/extendsfdf2.h" #include "builtins/extendsftf2.h" #include "builtins/extendxftf2.h" @@ -59,8 +62,11 @@ #include "builtins/subdf3.h" #include "builtins/subsf3.h" #include "builtins/subtf3.h" +#include "builtins/truncdfhf2.h" #include "builtins/truncdfsf2.h" +#include "builtins/truncsfhf2.h" #include "builtins/trunctfdf2.h" +#include "builtins/trunctfhf2.h" #include "builtins/trunctfsf2.h" #include "builtins/trunctfxf2.h" diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfdf2.h b/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfdf2.h new file mode 100644 index 000000000000..e9eaaca15e11 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfdf2.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __extendhfdf2 implementation as +/// shared::extendhfdf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BUILTINS_EXTENDHFDF2_H +#define LLVM_LIBC_SHARED_BUILTINS_EXTENDHFDF2_H + +#include "shared/libc_common.h" +#include "src/__support/builtins/extendhfdf2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using builtins::extendhfdf2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_BUILTINS_EXTENDHFDF2_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfsf2.h b/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfsf2.h new file mode 100644 index 000000000000..cc31bc7bd666 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhfsf2.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __extendhfsf2 implementation as +/// shared::extendhfsf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BUILTINS_EXTENDHFSF2_H +#define LLVM_LIBC_SHARED_BUILTINS_EXTENDHFSF2_H + +#include "shared/libc_common.h" +#include "src/__support/builtins/extendhfsf2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using builtins::extendhfsf2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_BUILTINS_EXTENDHFSF2_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhftf2.h b/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhftf2.h new file mode 100644 index 000000000000..dd3c72ee53fe --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins/extendhftf2.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __extendhftf2 implementation as +/// shared::extendhftf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BUILTINS_EXTENDHFTF2_H +#define LLVM_LIBC_SHARED_BUILTINS_EXTENDHFTF2_H + +#include "include/llvm-libc-types/float128.h" +#include "src/__support/macros/properties/types.h" + +#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#include "shared/libc_common.h" +#include "src/__support/builtins/extendhftf2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using builtins::extendhftf2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#endif // LLVM_LIBC_SHARED_BUILTINS_EXTENDHFTF2_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins/truncdfhf2.h b/deps/v8/third_party/llvm-libc/src/shared/builtins/truncdfhf2.h new file mode 100644 index 000000000000..426c3eef674e --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins/truncdfhf2.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __truncdfhf2 implementation as +/// shared::truncdfhf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BUILTINS_TRUNCDFHF2_H +#define LLVM_LIBC_SHARED_BUILTINS_TRUNCDFHF2_H + +#include "shared/libc_common.h" +#include "src/__support/builtins/truncdfhf2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using builtins::truncdfhf2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_BUILTINS_TRUNCDFHF2_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins/truncsfhf2.h b/deps/v8/third_party/llvm-libc/src/shared/builtins/truncsfhf2.h new file mode 100644 index 000000000000..0671d437b72c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins/truncsfhf2.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __truncsfhf2 implementation as +/// shared::truncsfhf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BUILTINS_TRUNCSFHF2_H +#define LLVM_LIBC_SHARED_BUILTINS_TRUNCSFHF2_H + +#include "shared/libc_common.h" +#include "src/__support/builtins/truncsfhf2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using builtins::truncsfhf2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_BUILTINS_TRUNCSFHF2_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/builtins/trunctfhf2.h b/deps/v8/third_party/llvm-libc/src/shared/builtins/trunctfhf2.h new file mode 100644 index 000000000000..d6aa0211c22f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/builtins/trunctfhf2.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __trunctfhf2 implementation as +/// shared::trunctfhf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_BUILTINS_TRUNCTFHF2_H +#define LLVM_LIBC_SHARED_BUILTINS_TRUNCTFHF2_H + +#include "include/llvm-libc-types/float128.h" +#include "src/__support/macros/properties/types.h" + +#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#include "shared/libc_common.h" +#include "src/__support/builtins/trunctfhf2.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using builtins::trunctfhf2; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#endif // LLVM_LIBC_SHARED_BUILTINS_TRUNCTFHF2_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math.h b/deps/v8/third_party/llvm-libc/src/shared/math.h index 7b52cedf99c2..eb72bebcb53b 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/math.h +++ b/deps/v8/third_party/llvm-libc/src/shared/math.h @@ -110,6 +110,7 @@ #include "math/exp10m1f.h" #include "math/exp10m1f16.h" #include "math/exp2.h" +#include "math/exp2bf16.h" #include "math/exp2f.h" #include "math/exp2f16.h" #include "math/exp2m1f.h" diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/exp2bf16.h b/deps/v8/third_party/llvm-libc/src/shared/math/exp2bf16.h new file mode 100644 index 000000000000..fa7a760c14e5 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/math/exp2bf16.h @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared header for the exp2bf16 function. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_MATH_EXP2BF16_H +#define LLVM_LIBC_SHARED_MATH_EXP2BF16_H + +#include "shared/libc_common.h" +#include "src/__support/math/exp2bf16.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::exp2bf16; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_EXP2BF16_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/getpayloadf128.h b/deps/v8/third_party/llvm-libc/src/shared/math/getpayloadf128.h index 1a3845e631a8..e1f2d0faedbc 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/math/getpayloadf128.h +++ b/deps/v8/third_party/llvm-libc/src/shared/math/getpayloadf128.h @@ -1,18 +1,19 @@ -//===-- Shared getpayloadf128 function --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Shared getpayloadf128 function. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SHARED_MATH_GETPAYLOADF128_H #define LLVM_LIBC_SHARED_MATH_GETPAYLOADF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "shared/libc_common.h" #include "src/__support/math/getpayloadf128.h" @@ -24,6 +25,4 @@ using math::getpayloadf128; } // namespace shared } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SHARED_MATH_GETPAYLOADF128_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/nanf128.h b/deps/v8/third_party/llvm-libc/src/shared/math/nanf128.h index 313b6ed6234c..9d80936c14c2 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/math/nanf128.h +++ b/deps/v8/third_party/llvm-libc/src/shared/math/nanf128.h @@ -1,18 +1,19 @@ -//===-- Shared nanf128 function ---------------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Shared nanf128 function. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SHARED_MATH_NANF128_H #define LLVM_LIBC_SHARED_MATH_NANF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "shared/libc_common.h" #include "src/__support/math/nanf128.h" @@ -24,6 +25,4 @@ using math::nanf128; } // namespace shared } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SHARED_MATH_NANF128_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadf128.h b/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadf128.h index a1f889e89ed3..ceb339e80ac4 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadf128.h +++ b/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadf128.h @@ -1,18 +1,19 @@ -//===-- Shared setpayloadf128 function --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Shared setpayloadf128 function. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SHARED_MATH_SETPAYLOADF128_H #define LLVM_LIBC_SHARED_MATH_SETPAYLOADF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "shared/libc_common.h" #include "src/__support/math/setpayloadf128.h" @@ -24,6 +25,4 @@ using math::setpayloadf128; } // namespace shared } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SHARED_MATH_SETPAYLOADF128_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadsigf128.h b/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadsigf128.h index 3169b610ccb4..92f17abd033a 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadsigf128.h +++ b/deps/v8/third_party/llvm-libc/src/shared/math/setpayloadsigf128.h @@ -1,18 +1,19 @@ -//===-- Shared setpayloadsigf128 function -----------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Shared setpayloadsigf128 function. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SHARED_MATH_SETPAYLOADSIGF128_H #define LLVM_LIBC_SHARED_MATH_SETPAYLOADSIGF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "shared/libc_common.h" #include "src/__support/math/setpayloadsigf128.h" @@ -24,6 +25,4 @@ using math::setpayloadsigf128; } // namespace shared } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SHARED_MATH_SETPAYLOADSIGF128_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/exp2f.h b/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/exp2f.h new file mode 100644 index 000000000000..142031e4daf9 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/exp2f.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the shared statically-rounded exp2f(x) function +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SHARED_MATH_STATIC_ROUNDING_EXP2F_H +#define LLVM_LIBC_SHARED_MATH_STATIC_ROUNDING_EXP2F_H + +#include "shared/libc_common.h" +#include "src/__support/math/exp2f_integer_eval.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { +namespace static_rounding { + +using math::static_rounding::exp2f; + +} // namespace static_rounding +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_STATIC_ROUNDING_EXP2F_H diff --git a/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/expf.h b/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/expf.h index 0f4aeef673ba..78dd010f7be4 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/expf.h +++ b/deps/v8/third_party/llvm-libc/src/shared/math/static_rounding/expf.h @@ -19,9 +19,11 @@ namespace LIBC_NAMESPACE_DECL { namespace shared { +namespace static_rounding { using math::static_rounding::expf; +} // namespace static_rounding } // namespace shared } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/shared/static_rounding_math.h b/deps/v8/third_party/llvm-libc/src/shared/static_rounding_math.h index 5488354a9b55..9fc00ade2be9 100644 --- a/deps/v8/third_party/llvm-libc/src/shared/static_rounding_math.h +++ b/deps/v8/third_party/llvm-libc/src/shared/static_rounding_math.h @@ -15,6 +15,7 @@ #define LLVM_LIBC_SHARED_STATIC_ROUNDING_MATH_H #include "shared/libc_common.h" +#include "shared/math/static_rounding/exp2f.h" #include "shared/math/static_rounding/expf.h" #endif // LLVM_LIBC_SHARED_STATIC_ROUNDING_MATH_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/CMakeLists.txt index f6d998fee2ef..dfb1ed0e13ff 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CMakeLists.txt @@ -17,6 +17,7 @@ add_header_library( DEPENDS libc.hdr.stdint_proxy libc.src.__support.CPP.algorithm + libc.src.__support.CPP.bit libc.src.__support.CPP.limits libc.src.__support.CPP.new libc.src.__support.CPP.optional @@ -236,13 +237,16 @@ add_header_library( integer_to_string.h DEPENDS .big_int + .common + .ctype_utils + .wctype_utils libc.hdr.stdint_proxy - libc.src.__support.common libc.src.__support.CPP.algorithm libc.src.__support.CPP.limits libc.src.__support.CPP.span libc.src.__support.CPP.string_view libc.src.__support.CPP.type_traits + libc.src.__support.macros.config ) add_header_library( @@ -412,6 +416,7 @@ add_header_library( frac64.h DEPENDS .big_int + libc.src.__support.macros.attributes libc.src.__support.macros.config ) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/CMakeLists.txt index 16d9db567abf..0a793e897fb8 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/CMakeLists.txt @@ -117,6 +117,9 @@ add_header_library( DEPENDS .type_traits .utility + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization ) add_header_library( @@ -210,6 +213,23 @@ add_header_library( expected HDRS expected.h + DEPENDS + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + unique_ptr + HDRS + unique_ptr.h + DEPENDS + .new + .type_traits + .utility + libc.hdr.types.size_t + libc.src.__support.macros.attributes + libc.src.__support.macros.config ) add_object_library( @@ -253,20 +273,3 @@ add_header_library( .utility .tuple ) - -add_header_library( - vector - HDRS - vector.h - DEPENDS - .new - .type_traits - .utility - libc.hdr.func.free - libc.hdr.func.malloc - libc.hdr.func.realloc - libc.hdr.types.size_t - libc.src.__support.common - libc.src.__support.libc_assert - libc.src.__support.macros.config -) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/bitset.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/bitset.h index db193f414abd..e264a363b9da 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/bitset.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/bitset.h @@ -29,6 +29,10 @@ template <size_t NumberOfBits> struct bitset { Data[i] = 0; } + LIBC_INLINE constexpr void reset(size_t Index) { + Data[Index / BITS_PER_UNIT] &= ~mask(Index); + } + LIBC_INLINE constexpr bool test(size_t Index) const { return Data[Index / BITS_PER_UNIT] & mask(Index); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/cstddef.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/cstddef.h index 559a2c2494b3..1507789cb1b1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/cstddef.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/cstddef.h @@ -20,7 +20,7 @@ namespace cpp { // `::std::byte` type (see `Type::isStdByteType()`), so `cpp::byte` would // otherwise get its own TBAA node. `may_alias` makes accesses through // `cpp::byte *` char-aliasing as callers expect. -enum class [[gnu::may_alias]] byte : unsigned char {}; +enum class LIBC_MAY_ALIAS byte : unsigned char {}; template <class IntegerType> LIBC_INLINE constexpr enable_if_t<is_integral_v<IntegerType>, byte> diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/expected.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/expected.h index 165ac72002d3..d4382d0db13a 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/expected.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/expected.h @@ -16,6 +16,7 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -47,17 +48,57 @@ template <class T, class E> class expected { LIBC_INLINE constexpr bool has_value() const { return is_expected; } - LIBC_INLINE constexpr T &value() { return exp; } - LIBC_INLINE constexpr E &error() { return unexp; } - LIBC_INLINE constexpr const T &value() const { return exp; } - LIBC_INLINE constexpr const E &error() const { return unexp; } + LIBC_INLINE constexpr T &value() { + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); + return exp; + } + LIBC_INLINE constexpr E &error() { + if (LIBC_UNLIKELY(is_expected)) + __builtin_trap(); + return unexp; + } + LIBC_INLINE constexpr const T &value() const { + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); + return exp; + } + LIBC_INLINE constexpr const E &error() const { + if (LIBC_UNLIKELY(is_expected)) + __builtin_trap(); + return unexp; + } LIBC_INLINE constexpr explicit operator bool() const { return is_expected; } - LIBC_INLINE constexpr T &operator*() { return exp; } - LIBC_INLINE constexpr const T &operator*() const { return exp; } - LIBC_INLINE constexpr T *operator->() { return &exp; } - LIBC_INLINE constexpr const T *operator->() const { return &exp; } + LIBC_INLINE constexpr T &operator*() { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); +#endif + return exp; + } + LIBC_INLINE constexpr const T &operator*() const { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); +#endif + return exp; + } + LIBC_INLINE constexpr T *operator->() { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); +#endif + return &exp; + } + LIBC_INLINE constexpr const T *operator->() const { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); +#endif + return &exp; + } }; template <class E> class expected<void, E> { @@ -74,13 +115,29 @@ template <class E> class expected<void, E> { LIBC_INLINE constexpr bool has_value() const { return is_expected; } - LIBC_INLINE constexpr void value() const {} - LIBC_INLINE constexpr E &error() { return unexp; } - LIBC_INLINE constexpr const E &error() const { return unexp; } + LIBC_INLINE constexpr void value() const { + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); + } + LIBC_INLINE constexpr E &error() { + if (LIBC_UNLIKELY(is_expected)) + __builtin_trap(); + return unexp; + } + LIBC_INLINE constexpr const E &error() const { + if (LIBC_UNLIKELY(is_expected)) + __builtin_trap(); + return unexp; + } LIBC_INLINE constexpr explicit operator bool() const { return is_expected; } - LIBC_INLINE constexpr void operator*() const {} + LIBC_INLINE constexpr void operator*() const { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!is_expected)) + __builtin_trap(); +#endif + } }; } // namespace cpp diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.cpp index 65f80de37348..345811181878 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.cpp @@ -8,13 +8,17 @@ #include "new.h" #include "hdr/func/free.h" - +// Replaceable global allocation functions must live in the global namespace. +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete(void *mem) noexcept { ::free(mem); } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete(void *mem, std::align_val_t) noexcept { ::free(mem); } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete(void *mem, size_t) noexcept { ::free(mem); } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete(void *mem, size_t, std::align_val_t) noexcept { #ifdef LIBC_TARGET_OS_IS_WINDOWS ::_aligned_free(mem); @@ -23,8 +27,10 @@ void operator delete(void *mem, size_t, std::align_val_t) noexcept { #endif } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete[](void *mem) noexcept { ::free(mem); } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete[](void *mem, std::align_val_t) noexcept { #ifdef LIBC_TARGET_OS_IS_WINDOWS ::_aligned_free(mem); @@ -33,8 +39,10 @@ void operator delete[](void *mem, std::align_val_t) noexcept { #endif } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete[](void *mem, size_t) noexcept { ::free(mem); } +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace): global namespace void operator delete[](void *mem, size_t, std::align_val_t) noexcept { #ifdef LIBC_TARGET_OS_IS_WINDOWS ::_aligned_free(mem); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.h index 47a8f1b9b830..44ec105b5887 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/new.h @@ -30,8 +30,10 @@ namespace LIBC_NAMESPACE_DECL { namespace cpp { template <class T> [[nodiscard]] constexpr T *launder(T *p) { +#ifndef LIBC_COMPILER_IS_MSVC static_assert(__has_builtin(__builtin_launder), "cpp::launder requires __builtin_launder"); +#endif // !LIBC_COMPILER_IS_MSVC return __builtin_launder(p); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/optional.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/optional.h index 3b3153f6f192..c3758c1312da 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/optional.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/optional.h @@ -13,6 +13,7 @@ #include "src/__support/CPP/utility.h" #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -109,26 +110,60 @@ template <typename T> class optional { LIBC_INLINE constexpr void reset() { storage.reset(); } LIBC_INLINE constexpr const T &value() const & { + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); return storage.stored_value; } - LIBC_INLINE constexpr T &value() & { return storage.stored_value; } + LIBC_INLINE constexpr T &value() & { + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); + return storage.stored_value; + } LIBC_INLINE constexpr explicit operator bool() const { return storage.in_use; } LIBC_INLINE constexpr bool has_value() const { return storage.in_use; } LIBC_INLINE constexpr const T *operator->() const { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); +#endif + return &storage.stored_value; + } + LIBC_INLINE constexpr T *operator->() { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); +#endif return &storage.stored_value; } - LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; } LIBC_INLINE constexpr const T &operator*() const & { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); +#endif + return storage.stored_value; + } + LIBC_INLINE constexpr T &operator*() & { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); +#endif return storage.stored_value; } - LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; } - LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); } + LIBC_INLINE constexpr T &&value() && { + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); + return move(storage.stored_value); + } LIBC_INLINE constexpr T &&operator*() && { +#ifndef NDEBUG + if (LIBC_UNLIKELY(!storage.in_use)) + __builtin_trap(); +#endif return move(storage.stored_value); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/type_traits.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/type_traits.h index d48ee23aeae0..4bf5acdccd92 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/type_traits.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/type_traits.h @@ -1,10 +1,15 @@ -//===-- Self contained C++ type_traits --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Self contained C++ type_traits. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_H #define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_H @@ -24,6 +29,7 @@ #include "src/__support/CPP/type_traits/invoke_result.h" #include "src/__support/CPP/type_traits/is_arithmetic.h" #include "src/__support/CPP/type_traits/is_array.h" +#include "src/__support/CPP/type_traits/is_assignable.h" #include "src/__support/CPP/type_traits/is_base_of.h" #include "src/__support/CPP/type_traits/is_class.h" #include "src/__support/CPP/type_traits/is_complex.h" diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/unique_ptr.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/unique_ptr.h new file mode 100644 index 000000000000..ebba21299f4b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/unique_ptr.h @@ -0,0 +1,208 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Standalone implementation of std::unique_ptr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H + +#include "hdr/types/size_t.h" +#include "src/__support/CPP/new.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/CPP/utility.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +/// A wrapper for deleting objects by default. +template <typename T> struct default_delete { + LIBC_INLINE constexpr default_delete() = default; + + template <typename U, typename = enable_if_t<is_convertible_v<U *, T *>>> + LIBC_INLINE constexpr default_delete(const default_delete<U> &) {} + + LIBC_INLINE constexpr void operator()(T *ptr) const { + static_assert(sizeof(T) > 0, "cannot delete an incomplete type"); + delete ptr; + } +}; + +/// A wrapper for deleting array objects by default. +template <typename T> struct default_delete<T[]> { + LIBC_INLINE constexpr default_delete() = default; + + template <typename U, + typename = enable_if_t<is_convertible_v<U (*)[], T (*)[]>>> + LIBC_INLINE constexpr default_delete(const default_delete<U[]> &) {} + + template <typename U, + typename = enable_if_t<is_convertible_v<U (*)[], T (*)[]>>> + LIBC_INLINE constexpr void operator()(U *ptr) const { + static_assert(sizeof(U) > 0, "cannot delete an incomplete type"); + delete[] ptr; + } +}; + +/// A smart pointer that owns and manages another object through a pointer. +template <typename T, typename Deleter = default_delete<T>> +class LIBC_TRIVIAL_ABI unique_ptr { + T *ptr = nullptr; + LIBC_NO_UNIQUE_ADDRESS Deleter deleter; + +public: + using element_type = T; + using deleter_type = Deleter; + using pointer = T *; + + LIBC_INLINE constexpr unique_ptr() = default; + LIBC_INLINE constexpr unique_ptr(decltype(nullptr)) : ptr(nullptr) {} + LIBC_INLINE constexpr explicit unique_ptr(pointer p) : ptr(p) {} + + LIBC_INLINE constexpr unique_ptr(pointer p, const deleter_type &d) + : ptr(p), deleter(d) {} + LIBC_INLINE constexpr unique_ptr(pointer p, deleter_type &&d) + : ptr(p), deleter(move(d)) {} + + // Move constructor + LIBC_INLINE constexpr unique_ptr(unique_ptr &&other) + : ptr(other.release()), deleter(forward<Deleter>(other.get_deleter())) {} + + // Move assignment + LIBC_INLINE constexpr unique_ptr &operator=(unique_ptr &&other) { + reset(other.release()); + deleter = forward<Deleter>(other.get_deleter()); + return *this; + } + + // Conversion move constructor + template <typename U, typename E, + typename = enable_if_t< + is_convertible_v<typename unique_ptr<U, E>::pointer, pointer> && + !is_array<U>::value && is_convertible_v<E, Deleter>>> + LIBC_INLINE constexpr unique_ptr(unique_ptr<U, E> &&other) + : ptr(other.release()), deleter(forward<E>(other.get_deleter())) {} + + // Conversion move assignment + template <typename U, typename E, + typename = enable_if_t< + is_convertible_v<typename unique_ptr<U, E>::pointer, pointer> && + !is_array<U>::value && is_assignable_v<Deleter &, E &&>>> + LIBC_INLINE constexpr unique_ptr &operator=(unique_ptr<U, E> &&other) { + reset(other.release()); + deleter = forward<E>(other.get_deleter()); + return *this; + } + + // Disable copy + unique_ptr(const unique_ptr &) = delete; + unique_ptr &operator=(const unique_ptr &) = delete; + + LIBC_INLINE ~unique_ptr() { reset(); } + + LIBC_INLINE constexpr pointer get() const { return ptr; } + LIBC_INLINE constexpr deleter_type &get_deleter() { return deleter; } + LIBC_INLINE constexpr const deleter_type &get_deleter() const { + return deleter; + } + + LIBC_INLINE constexpr explicit operator bool() const { + return ptr != nullptr; + } + + LIBC_INLINE constexpr pointer release() { + pointer temp = ptr; + ptr = nullptr; + return temp; + } + + LIBC_INLINE constexpr void reset(pointer p = pointer()) { + pointer old_ptr = ptr; + ptr = p; + if (old_ptr) + deleter(old_ptr); + } + + LIBC_INLINE constexpr typename add_lvalue_reference<T>::type + operator*() const { + return *ptr; + } + LIBC_INLINE constexpr pointer operator->() const { return ptr; } +}; + +/// A smart pointer that owns and manages an array of objects through a pointer. +template <typename T, typename Deleter> +class LIBC_TRIVIAL_ABI unique_ptr<T[], Deleter> { + T *ptr = nullptr; + LIBC_NO_UNIQUE_ADDRESS Deleter deleter; + +public: + using element_type = T; + using deleter_type = Deleter; + using pointer = T *; + + LIBC_INLINE constexpr unique_ptr() = default; + LIBC_INLINE constexpr unique_ptr(decltype(nullptr)) : ptr(nullptr) {} + LIBC_INLINE constexpr explicit unique_ptr(pointer p) : ptr(p) {} + + LIBC_INLINE constexpr unique_ptr(pointer p, const deleter_type &d) + : ptr(p), deleter(d) {} + LIBC_INLINE constexpr unique_ptr(pointer p, deleter_type &&d) + : ptr(p), deleter(move(d)) {} + + // Move constructor + LIBC_INLINE constexpr unique_ptr(unique_ptr &&other) + : ptr(other.release()), deleter(forward<Deleter>(other.get_deleter())) {} + + // Move assignment + LIBC_INLINE constexpr unique_ptr &operator=(unique_ptr &&other) { + reset(other.release()); + deleter = forward<Deleter>(other.get_deleter()); + return *this; + } + + // Disable copy + unique_ptr(const unique_ptr &) = delete; + unique_ptr &operator=(const unique_ptr &) = delete; + + LIBC_INLINE ~unique_ptr() { reset(); } + + LIBC_INLINE constexpr pointer get() const { return ptr; } + LIBC_INLINE constexpr deleter_type &get_deleter() { return deleter; } + LIBC_INLINE constexpr const deleter_type &get_deleter() const { + return deleter; + } + + LIBC_INLINE constexpr explicit operator bool() const { + return ptr != nullptr; + } + + LIBC_INLINE constexpr pointer release() { + pointer temp = ptr; + ptr = nullptr; + return temp; + } + + LIBC_INLINE constexpr void reset(pointer p = pointer()) { + pointer old_ptr = ptr; + ptr = p; + if (old_ptr) + deleter(old_ptr); + } + + LIBC_INLINE constexpr T &operator[](size_t i) const { return ptr[i]; } +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UNIQUE_PTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/vector.h b/deps/v8/third_party/llvm-libc/src/src/__support/CPP/vector.h deleted file mode 100644 index 839a93750567..000000000000 --- a/deps/v8/third_party/llvm-libc/src/src/__support/CPP/vector.h +++ /dev/null @@ -1,309 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implementation of vector container. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_VECTOR_H -#define LLVM_LIBC_SRC___SUPPORT_CPP_VECTOR_H - -#include "hdr/func/free.h" -#include "hdr/func/malloc.h" -#include "hdr/func/realloc.h" -#include "hdr/types/size_t.h" -#include "src/__support/CPP/new.h" -#include "src/__support/CPP/type_traits.h" -#include "src/__support/CPP/utility.h" -#include "src/__support/common.h" -#include "src/__support/libc_assert.h" -#include "src/__support/macros/config.h" - -#include <stddef.h> // For max_align_t, ptrdiff_t - -namespace LIBC_NAMESPACE_DECL { -namespace cpp { - -template <typename T> class vector { - static_assert(alignof(T) <= alignof(max_align_t), - "Overaligned types are not supported by cpp::vector"); - -public: - using value_type = T; - using size_type = size_t; - using difference_type = ptrdiff_t; - using reference = T &; - using const_reference = const T &; - using pointer = T *; - using const_pointer = const T *; - using iterator = T *; - using const_iterator = const T *; - - [[nodiscard]] LIBC_INLINE constexpr size_type max_size() const noexcept { - return static_cast<size_type>(-1) / sizeof(T); - } - -private: - T *data_ = nullptr; - size_t size_ = 0; - size_t capacity_ = 0; - - static constexpr size_t DEFAULT_INITIAL_CAPACITY = 16; - - LIBC_INLINE void destroy_elements(size_t from, size_t to) { - if constexpr (!is_trivially_destructible_v<T>) { - while (to > from) { - --to; - data_[to].~T(); - } - } - } - - LIBC_INLINE void deallocate() { - if (data_) { - destroy_elements(0, size_); - ::free(data_); - data_ = nullptr; - size_ = 0; - capacity_ = 0; - } - } - - [[nodiscard]] LIBC_INLINE bool reallocate(size_t new_cap) { - if constexpr (is_trivially_copyable_v<T>) { - void *new_data = ::realloc(data_, new_cap * sizeof(T)); - if (!new_data) - return false; - data_ = static_cast<T *>(new_data); - capacity_ = new_cap; - return true; - } else { - void *new_raw = ::malloc(new_cap * sizeof(T)); - if (!new_raw) - return false; - T *new_data = static_cast<T *>(new_raw); - for (size_t i = 0; i < size_; ++i) { - new (new_data + i) T(cpp::move(data_[i])); - data_[i].~T(); - } - ::free(data_); - data_ = new_data; - capacity_ = new_cap; - return true; - } - } - -public: - LIBC_INLINE constexpr vector() = default; - - LIBC_INLINE ~vector() { deallocate(); } - - // Move constructor - LIBC_INLINE vector(vector &&other) noexcept - : data_(other.data_), size_(other.size_), capacity_(other.capacity_) { - other.data_ = nullptr; - other.size_ = 0; - other.capacity_ = 0; - } - - // Move assignment - LIBC_INLINE vector &operator=(vector &&other) noexcept { - if (this != &other) { - deallocate(); - data_ = other.data_; - size_ = other.size_; - capacity_ = other.capacity_; - other.data_ = nullptr; - other.size_ = 0; - other.capacity_ = 0; - } - return *this; - } - - // Copy operations are deleted to prevent accidental implicit allocations. - vector(const vector &) = delete; - vector &operator=(const vector &) = delete; - - // Element access - [[nodiscard]] LIBC_INLINE reference operator[](size_t i) { - LIBC_ASSERT(i < size_); - return data_[i]; - } - - [[nodiscard]] LIBC_INLINE const_reference operator[](size_t i) const { - LIBC_ASSERT(i < size_); - return data_[i]; - } - - [[nodiscard]] LIBC_INLINE pointer data() { return data_; } - [[nodiscard]] LIBC_INLINE const_pointer data() const { return data_; } - - [[nodiscard]] LIBC_INLINE reference front() { - LIBC_ASSERT(size_ > 0); - return data_[0]; - } - - [[nodiscard]] LIBC_INLINE const_reference front() const { - LIBC_ASSERT(size_ > 0); - return data_[0]; - } - - [[nodiscard]] LIBC_INLINE reference back() { - LIBC_ASSERT(size_ > 0); - return data_[size_ - 1]; - } - - [[nodiscard]] LIBC_INLINE const_reference back() const { - LIBC_ASSERT(size_ > 0); - return data_[size_ - 1]; - } - - // Iterators - [[nodiscard]] LIBC_INLINE iterator begin() { return data_; } - [[nodiscard]] LIBC_INLINE const_iterator begin() const { return data_; } - [[nodiscard]] LIBC_INLINE const_iterator cbegin() const { return data_; } - [[nodiscard]] LIBC_INLINE iterator end() { return data_ + size_; } - [[nodiscard]] LIBC_INLINE const_iterator end() const { return data_ + size_; } - [[nodiscard]] LIBC_INLINE const_iterator cend() const { - return data_ + size_; - } - - // Capacity - [[nodiscard]] LIBC_INLINE bool empty() const { return size_ == 0; } - [[nodiscard]] LIBC_INLINE size_t size() const { return size_; } - [[nodiscard]] LIBC_INLINE size_t capacity() const { return capacity_; } - - // Reserves at least new_cap elements. Returns true on success, false on OOM. - [[nodiscard]] LIBC_INLINE bool reserve(size_t new_cap) { - if (new_cap <= capacity_) - return true; - if (new_cap > max_size()) - return false; - return reallocate(new_cap); - } - - LIBC_INLINE void shrink_to_fit() { - if (size_ == capacity_) - return; - if (size_ == 0) { - reset(); - return; - } - static_cast<void>(reallocate(size_)); - } - - // Modifiers - template <typename... Args> - [[nodiscard]] LIBC_INLINE bool emplace_back(Args &&...args) { - if (size_ < capacity_) { - new (data_ + size_) T(cpp::forward<Args>(args)...); - ++size_; - return true; - } - - size_t new_cap = DEFAULT_INITIAL_CAPACITY; - if (capacity_ > 0) { - if (capacity_ > max_size() / 2) - return false; - new_cap = capacity_ * 2; - } - - void *new_raw = ::malloc(new_cap * sizeof(T)); - if (!new_raw) - return false; - T *new_data = static_cast<T *>(new_raw); - - // Construct the new element before moving/freeing old storage so that - // arguments referencing the vector's own buffer remain valid. - new (new_data + size_) T(cpp::forward<Args>(args)...); - - for (size_t i = 0; i < size_; ++i) { - new (new_data + i) T(cpp::move(data_[i])); - data_[i].~T(); - } - ::free(data_); - data_ = new_data; - capacity_ = new_cap; - ++size_; - return true; - } - - [[nodiscard]] LIBC_INLINE bool push_back(const T &val) { - return emplace_back(val); - } - - [[nodiscard]] LIBC_INLINE bool push_back(T &&val) { - return emplace_back(cpp::move(val)); - } - - LIBC_INLINE void pop_back() { - LIBC_ASSERT(size_ > 0); - --size_; - if constexpr (!is_trivially_destructible_v<T>) - data_[size_].~T(); - } - - LIBC_INLINE void clear() { - destroy_elements(0, size_); - size_ = 0; - } - - // Deallocates backing memory and resets size and capacity to 0. - LIBC_INLINE void reset() { deallocate(); } - - [[nodiscard]] LIBC_INLINE bool resize(size_t new_size) { - if (new_size < size_) { - destroy_elements(new_size, size_); - size_ = new_size; - return true; - } - if (new_size > size_) { - if (!reserve(new_size)) - return false; - for (size_t i = size_; i < new_size; ++i) - new (data_ + i) T(); - size_ = new_size; - } - return true; - } - - [[nodiscard]] LIBC_INLINE bool resize(size_t new_size, const T &value) { - if (new_size < size_) { - destroy_elements(new_size, size_); - size_ = new_size; - return true; - } - if (new_size > size_) { - // Copy value before reserve in case value references this vector's data. - T val_copy(value); - if (!reserve(new_size)) - return false; - for (size_t i = size_; i < new_size; ++i) - new (data_ + i) T(val_copy); - size_ = new_size; - } - return true; - } - - LIBC_INLINE void swap(vector &other) noexcept { - cpp::swap(data_, other.data_); - cpp::swap(size_, other.size_); - cpp::swap(capacity_, other.capacity_); - } -}; - -template <typename T> -LIBC_INLINE void swap(vector<T> &lhs, vector<T> &rhs) noexcept { - lhs.swap(rhs); -} - -} // namespace cpp -} // namespace LIBC_NAMESPACE_DECL - -#endif // LLVM_LIBC_SRC___SUPPORT_CPP_VECTOR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/CMakeLists.txt index 8856d5e525bd..97b907cb0e58 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/CMakeLists.txt @@ -45,6 +45,19 @@ add_header_library( libc.src.__support.uint128 ) +add_header_library( + fp_bitwise + HDRS + fp_bitwise.h + DEPENDS + .fp_bits + libc.src.__support.CPP.type_traits + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.properties.architectures + libc.src.__support.macros.properties.cpu_features +) + add_header_library( fpbits_str HDRS @@ -160,6 +173,7 @@ add_header_library( nearest_integer.h DEPENDS libc.src.__support.common + libc.src.__support.CPP.type_traits libc.src.__support.macros.optimization libc.src.__support.macros.properties.cpu_features FLAGS @@ -244,6 +258,17 @@ add_header_library( libc.src.__support.uint128 ) +add_header_library( + is_integer + HDRS + is_integer.h + DEPENDS + .fp_bits + libc.src.__support.CPP.bit + libc.src.__support.macros.attributes + libc.src.__support.macros.config +) + add_header_library( manipulation_functions HDRS diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FEnvImpl.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FEnvImpl.h index 4c897e724382..d556a3cbf4d3 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FEnvImpl.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FEnvImpl.h @@ -32,7 +32,7 @@ #undef LIBC_MATH_USE_SYSTEM_FENV #endif // LIBC_FULL_BUILD -#if defined(LIBC_MATH_USE_SYSTEM_FENV) +#if defined(LIBC_MATH_USE_SYSTEM_FENV) && !defined(LIBC_MATH_HAS_NO_EXCEPT) // Simply call the system libc fenv.h functions, only for those that are used in // math function implementations. @@ -119,6 +119,8 @@ LIBC_INLINE int set_env(const fenv_t *env) { #include "arm/FEnvImpl.h" #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) && defined(__riscv_flen) #include "riscv/FEnvImpl.h" +#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON) +#include "hexagon/FEnvImpl.h" #else namespace LIBC_NAMESPACE_DECL { @@ -165,7 +167,6 @@ clear_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT - LIBC_FENV_ACCESS_ON if (math_errhandling & MATH_ERREXCEPT) return clear_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -179,7 +180,6 @@ set_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT - LIBC_FENV_ACCESS_ON if (math_errhandling & MATH_ERREXCEPT) return set_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -193,7 +193,6 @@ raise_except_if_required([[maybe_unused]] int excepts) { return 0; } else { #ifndef LIBC_MATH_HAS_NO_EXCEPT - LIBC_FENV_ACCESS_ON if (math_errhandling & MATH_ERREXCEPT) return raise_except(excepts); #endif // LIBC_MATH_HAS_NO_EXCEPT @@ -221,6 +220,7 @@ LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_underflow_except_if_required() { raise_except_if_required(FE_UNDERFLOW | FE_INEXACT); } +#ifndef LIBC_MATH_HAS_NO_EXCEPT #if defined(LIBC_TARGET_CPU_HAS_FPU_FLOAT) template <> LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void @@ -268,6 +268,7 @@ raise_underflow_except_if_required<double>() { } } #endif // LIBC_TARGET_CPU_HAS_FPU_DOUBLE +#endif // !LIBC_MATH_HAS_NO_EXCEPT } // namespace fputil } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FMA.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FMA.h index 2cafb4c0974e..a5201f321b77 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FMA.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FMA.h @@ -13,8 +13,19 @@ #include "src/__support/FPUtil/generic/FMA.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#if defined(LIBC_TARGET_CPU_HAS_FMA) && \ + !__has_builtin(__builtin_elementwise_fma) && \ + defined(LIBC_COMPILER_IS_MSVC) +#if defined(LIBC_TARGET_ARCH_IS_X86) +#include <immintrin.h> +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) +#include <arm64_neon.h> +#endif +#endif + namespace LIBC_NAMESPACE_DECL { namespace fputil { @@ -29,6 +40,12 @@ LIBC_INLINE OutType fma(InType x, InType y, InType z) { template <> LIBC_INLINE float fma(float x, float y, float z) { #if __has_builtin(__builtin_elementwise_fma) return __builtin_elementwise_fma(x, y, z); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_X86) + return _mm_cvtss_f32( + _mm_fmadd_ss(_mm_set_ss(x), _mm_set_ss(y), _mm_set_ss(z))); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_AARCH64) + return vget_lane_f32(vfma_f32(vdup_n_f32(z), vdup_n_f32(x), vdup_n_f32(y)), + 0); #else return __builtin_fmaf(x, y, z); #endif @@ -39,6 +56,12 @@ template <> LIBC_INLINE float fma(float x, float y, float z) { template <> LIBC_INLINE double fma(double x, double y, double z) { #if __has_builtin(__builtin_elementwise_fma) return __builtin_elementwise_fma(x, y, z); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_X86) + return _mm_cvtsd_f64( + _mm_fmadd_sd(_mm_set_sd(x), _mm_set_sd(y), _mm_set_sd(z))); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_AARCH64) + return vget_lane_f64(vfma_f64(vdup_n_f64(z), vdup_n_f64(x), vdup_n_f64(y)), + 0); #else return __builtin_fma(x, y, z); #endif diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FPBits.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FPBits.h index 6127dede03f4..83dedeb45d4f 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FPBits.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/FPBits.h @@ -127,7 +127,7 @@ template <> struct FPLayout<FPType::IEEE754_Binary128> { }; template <> struct FPLayout<FPType::X86_Binary80> { -#if __SIZEOF_LONG_DOUBLE__ == 12 +#if defined(__SIZEOF_LONG_DOUBLE__) && (__SIZEOF_LONG_DOUBLE__ == 12) using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>; #else using StorageType = UInt128; @@ -786,6 +786,9 @@ struct FPRep : public FPRepImpl<fp_type, FPRep<fp_type>> { } // namespace internal +// Like 'FPBits' but named by 'FPType', so no native C++ type need exist. +template <FPType fp_type> using FPRep = internal::FPRep<fp_type>; + // Returns the FPType corresponding to C++ type T on the host. template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() { using UnqualT = cpp::remove_cv_t<T>; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/PolyEval.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/PolyEval.h index 58a3f4e24fde..55583cca70c3 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/PolyEval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/PolyEval.h @@ -1,10 +1,15 @@ -//===-- Common header for PolyEval implementations --------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Common header for PolyEval implementations. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_POLYEVAL_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_POLYEVAL_H @@ -67,13 +72,15 @@ altpolyeval(T, T a0) { template <typename T, typename... Ts> LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) > sizeof(void *)), T> altpolyeval(const T &x, const T &a0, const Ts &...a) { - return a0 - x * altpolyeval(x, a...); + T prod = x * altpolyeval(x, a...); + return a0 - prod; } template <typename T, typename... Ts> LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) <= sizeof(void *)), T> altpolyeval(T x, T a0, Ts... a) { - return a0 - x * altpolyeval(x, a...); + T prod = x * altpolyeval(x, a...); + return a0 - prod; } } // namespace fputil diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/nearest_integer.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/nearest_integer.h index d5ea0678825f..9f6a5b97d64e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/nearest_integer.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/nearest_integer.h @@ -12,24 +12,37 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" #if !defined(LIBC_TARGET_ARCH_IS_AARCH64) #error "Invalid include" #endif +#ifdef LIBC_COMPILER_IS_MSVC +#include <arm64_neon.h> +#endif + namespace LIBC_NAMESPACE_DECL { namespace fputil { LIBC_INLINE float nearest_integer(float x) { +#ifdef LIBC_COMPILER_IS_MSVC + return vget_lane_f32(vrndn_f32(vdup_n_f32(x)), 0); +#else float result; __asm__ __volatile__("frintn %s0, %s1\n\t" : "=w"(result) : "w"(x)); return result; +#endif } LIBC_INLINE double nearest_integer(double x) { +#ifdef LIBC_COMPILER_IS_MSVC + return vget_lane_f64(vrndn_f64(vdup_n_f64(x)), 0); +#else double result; __asm__ __volatile__("frintn %d0, %d1\n\t" : "=w"(result) : "w"(x)); return result; +#endif } } // namespace fputil diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/sqrt.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/sqrt.h index 4eb576bf2244..be9cb1f1cea4 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/sqrt.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/aarch64/sqrt.h @@ -12,6 +12,7 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/cpu_features.h" #if !defined(LIBC_TARGET_ARCH_IS_AARCH64) @@ -20,22 +21,34 @@ #include "src/__support/FPUtil/generic/sqrt.h" +#ifdef LIBC_COMPILER_IS_MSVC +#include <arm64_neon.h> +#endif + namespace LIBC_NAMESPACE_DECL { namespace fputil { #ifdef LIBC_TARGET_CPU_HAS_FPU_FLOAT template <> LIBC_INLINE float sqrt<float>(float x) { +#ifdef LIBC_COMPILER_IS_MSVC + return vget_lane_f32(vsqrt_f32(vdup_n_f32(x)), 0); +#else float y; asm("fsqrt %s0, %s1\n\t" : "=w"(y) : "w"(x)); return y; +#endif } #endif // LIBC_TARGET_CPU_HAS_FPU_FLOAT #ifdef LIBC_TARGET_CPU_HAS_FPU_DOUBLE template <> LIBC_INLINE double sqrt<double>(double x) { +#ifdef LIBC_COMPILER_IS_MSVC + return vget_lane_f64(vsqrt_f64(vdup_n_f64(x)), 0); +#else double y; asm("fsqrt %d0, %d1\n\t" : "=w"(y) : "w"(x)); return y; +#endif } #endif // LIBC_TARGET_CPU_HAS_FPU_DOUBLE diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/cast.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/cast.h index 2a9bfd5a9f62..7c1c3114f70b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/cast.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/cast.h @@ -16,7 +16,8 @@ #include "src/__support/CPP/type_traits.h" #include "src/__support/macros/properties/types.h" -namespace LIBC_NAMESPACE::fputil { +namespace LIBC_NAMESPACE_DECL { +namespace fputil { // TODO: Add optimization for known good targets with fast // float to float16 conversion: @@ -55,7 +56,7 @@ cast(InType x) { } InStorageType x_mant = x_bits.get_mantissa(); - if (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN) + if constexpr (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN) x_mant >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN; return OutFPBits::quiet_nan(x_bits.sign(), static_cast<OutStorageType>(x_mant)) @@ -75,6 +76,7 @@ cast(InType x) { } } -} // namespace LIBC_NAMESPACE::fputil +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_CAST_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/double_double.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/double_double.h index 87b3887716b0..6e41bb9b2a4b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/double_double.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/double_double.h @@ -71,19 +71,21 @@ LIBC_INLINE constexpr NumberPair<T> exact_add(T a, T b) { // If `lsb(a.hi) >= ulp(b.hi)`, then the errors: // err = (a.hi + a.lo + b.hi + b.lo) - (r.hi - r.lo) is bounded by: // |err| < 2^(-2p) * ufp(r.hi) + 2^(-p + 2) * ufp(a.lo + b.lo). -template <typename T> +template <bool FAST2SUM = true, typename T> LIBC_INLINE constexpr NumberPair<T> add(const NumberPair<T> &a, const NumberPair<T> &b) { - NumberPair<T> r = exact_add(a.hi, b.hi); + NumberPair<T> r = exact_add<FAST2SUM>(a.hi, b.hi); T lo = a.lo + b.lo; - return exact_add(r.hi, r.lo + lo); + T r_lo = r.lo + lo; + return exact_add<FAST2SUM>(r.hi, r_lo); } -// Assumption: |a.hi| >= |b| -template <typename T> +// Assumption: when FAST2SUM = true, |a.hi| >= |b| +template <bool FAST2SUM = true, typename T> LIBC_INLINE constexpr NumberPair<T> add(const NumberPair<T> &a, T b) { - NumberPair<T> r = exact_add<false>(a.hi, b); - return exact_add(r.hi, r.lo + a.lo); + NumberPair<T> r = exact_add<FAST2SUM>(a.hi, b); + T r_lo = r.lo + a.lo; + return exact_add<FAST2SUM>(r.hi, r_lo); } // Veltkamp's Splitting for double precision. diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/dyadic_float.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/dyadic_float.h index 80335cc9f780..e3f1f4757527 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/dyadic_float.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/dyadic_float.h @@ -183,42 +183,50 @@ template <size_t Bits> struct DyadicFloat { return DyadicFloat(result_sign, result_exponent, result_mantissa); } - template <typename T, bool ShouldSignalExceptions = true> - LIBC_INLINE LIBC_CONSTEXPR_DEFAULT cpp::enable_if_t< - cpp::is_floating_point_v<T> && (FPBits<T>::FRACTION_LEN < Bits), T> - generic_as() const { - using FPBits = FPBits<T>; - using StorageType = typename FPBits::StorageType; - - constexpr int EXTRA_FRACTION_LEN = Bits - 1 - FPBits::FRACTION_LEN; + // The integer core of generic_as(). The destination is named by FPType, so + // it also covers formats with no usable native type (float16 without + // _Float16). + template <FPType DstType, bool ShouldSignalExceptions> + LIBC_INLINE LIBC_CONSTEXPR_DEFAULT typename FPRep<DstType>::StorageType + generic_as_bits() const { + using DstRep = FPRep<DstType>; + using StorageType = typename DstRep::StorageType; + // Native type used to pick the exception-raising specialization; formats + // without one fall back to the generic version. + using ExceptT = cpp::conditional_t< + DstType == FPType::IEEE754_Binary32, float, + cpp::conditional_t<DstType == FPType::IEEE754_Binary64, double, void>>; + static_assert(DstRep::FRACTION_LEN < Bits); + + constexpr int EXTRA_FRACTION_LEN = Bits - 1 - DstRep::FRACTION_LEN; if (mantissa == 0) - return FPBits::zero(sign).get_val(); + return DstRep::zero(sign).uintval(); int unbiased_exp = get_unbiased_exponent(); - if (unbiased_exp + FPBits::EXP_BIAS >= FPBits::MAX_BIASED_EXPONENT) { + if (unbiased_exp + DstRep::EXP_BIAS >= DstRep::MAX_BIASED_EXPONENT) { if constexpr (ShouldSignalExceptions) { set_errno_if_required(ERANGE); - raise_overflow_except_if_required<T>(); + raise_overflow_except_if_required<ExceptT>(); } #ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - return FPBits::inf(sign).get_val(); + return DstRep::inf(sign).uintval(); #else // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY switch (quick_get_round()) { case FE_TONEAREST: - return FPBits::inf(sign).get_val(); + return DstRep::inf(sign).uintval(); case FE_TOWARDZERO: - return FPBits::max_normal(sign).get_val(); + return DstRep::max_normal(sign).uintval(); case FE_DOWNWARD: if (sign.is_pos()) - return FPBits::max_normal(Sign::POS).get_val(); - return FPBits::inf(Sign::NEG).get_val(); + return DstRep::max_normal(Sign::POS).uintval(); + return DstRep::inf(Sign::NEG).uintval(); case FE_UPWARD: if (sign.is_neg()) - return FPBits::max_normal(Sign::NEG).get_val(); - return FPBits::inf(Sign::POS).get_val(); + return DstRep::max_normal(Sign::NEG).uintval(); + return DstRep::inf(Sign::POS).uintval(); default: __builtin_unreachable(); } @@ -231,10 +239,10 @@ template <size_t Bits> struct DyadicFloat { bool sticky = false; bool underflow = false; - if (unbiased_exp < -FPBits::EXP_BIAS - FPBits::FRACTION_LEN) { + if (unbiased_exp < -DstRep::EXP_BIAS - DstRep::FRACTION_LEN) { sticky = true; underflow = true; - } else if (unbiased_exp == -FPBits::EXP_BIAS - FPBits::FRACTION_LEN) { + } else if (unbiased_exp == -DstRep::EXP_BIAS - DstRep::FRACTION_LEN) { round = true; // underflow is detected pre-rounding FE_UNDERFLOW may be raised // even if rounding produces a non-underflow result @@ -244,12 +252,12 @@ template <size_t Bits> struct DyadicFloat { } else { int extra_fraction_len = EXTRA_FRACTION_LEN; - if (unbiased_exp < 1 - FPBits::EXP_BIAS) { + if (unbiased_exp < 1 - DstRep::EXP_BIAS) { underflow = true; - extra_fraction_len += 1 - FPBits::EXP_BIAS - unbiased_exp; + extra_fraction_len += 1 - DstRep::EXP_BIAS - unbiased_exp; } else { out_biased_exp = - static_cast<StorageType>(unbiased_exp + FPBits::EXP_BIAS); + static_cast<StorageType>(unbiased_exp + DstRep::EXP_BIAS); } if (extra_fraction_len > 0) { @@ -265,7 +273,7 @@ template <size_t Bits> struct DyadicFloat { bool lsb = (out_mantissa & 1) != 0; StorageType result = - FPBits::create_value(sign, out_biased_exp, out_mantissa).uintval(); + DstRep::create_value(sign, out_biased_exp, out_mantissa).uintval(); #ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY if (round && (lsb || sticky)) @@ -290,18 +298,27 @@ template <size_t Bits> struct DyadicFloat { #endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY if (ShouldSignalExceptions && (round || sticky)) { - if (FPBits(result).is_inf()) { + if (DstRep(result).is_inf()) { set_errno_if_required(ERANGE); - raise_overflow_except_if_required<T>(); + raise_overflow_except_if_required<ExceptT>(); } else if (underflow) { set_errno_if_required(ERANGE); - raise_underflow_except_if_required<T>(); + raise_underflow_except_if_required<ExceptT>(); } else { raise_except_if_required(FE_INEXACT); } } - return FPBits(result).get_val(); + return result; + } + + template <typename T, bool ShouldSignalExceptions> + LIBC_INLINE LIBC_CONSTEXPR_DEFAULT cpp::enable_if_t< + cpp::is_floating_point_v<T> && (FPBits<T>::FRACTION_LEN < Bits), T> + generic_as() const { + return FPBits<T>( + generic_as_bits<get_fp_type<T>(), ShouldSignalExceptions>()) + .get_val(); } template <typename T, bool ShouldSignalExceptions = true, diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/float80.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/float80.h index c0bc40cd6c1a..56f3434122ba 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/float80.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/float80.h @@ -26,7 +26,7 @@ namespace LIBC_NAMESPACE_DECL { namespace fputil { struct Float80 { -#if __SIZEOF_LONG_DOUBLE__ == 12 +#if defined(__SIZEOF_LONG_DOUBLE__) && (__SIZEOF_LONG_DOUBLE__ == 12) UInt<96> bits; #else UInt128 bits; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/fp_bitwise.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/fp_bitwise.h new file mode 100644 index 000000000000..c46972ddb0a2 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/fp_bitwise.h @@ -0,0 +1,250 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Bitwise operations on floating-point numbers. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FP_BITWISE_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FP_BITWISE_H + +#include "src/__support/CPP/type_traits.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" +#include "src/__support/macros/properties/cpu_features.h" + +#ifdef LIBC_TARGET_CPU_HAS_SSE2 +#include <immintrin.h> +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_ARM_NEON) +#ifdef LIBC_COMPILER_IS_MSVC +#include <arm64_neon.h> +#else +#include <arm_neon.h> +#endif +#endif // LIBC_TARGET_CPU_HAS_SSE2 + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +// Bitwise AND of two floating-point values (a & b), performed directly in +// FP/SIMD registers when SSE2 or AArch64 NEON is available to avoid GPR +// round-trips. +template <typename T> +LIBC_ALWAYS_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T> +fp_and(T a, T b) { + if (!cpp::is_constant_evaluated()) { +#ifdef LIBC_TARGET_CPU_HAS_SSE2 + if constexpr (cpp::is_same_v<T, float>) + return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(a), _mm_set_ss(b))); + if constexpr (cpp::is_same_v<T, double>) + return _mm_cvtsd_f64(_mm_and_pd(_mm_set_sd(a), _mm_set_sd(b))); +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_ARM_NEON) + if constexpr (cpp::is_same_v<T, float>) + return vget_lane_f32( + vreinterpret_f32_u32(vand_u32(vreinterpret_u32_f32(vdup_n_f32(a)), + vreinterpret_u32_f32(vdup_n_f32(b)))), + 0); + if constexpr (cpp::is_same_v<T, double>) + return vget_lane_f64( + vreinterpret_f64_u64(vand_u64(vreinterpret_u64_f64(vdup_n_f64(a)), + vreinterpret_u64_f64(vdup_n_f64(b)))), + 0); +#endif + } + using StorageType = typename FPBits<T>::StorageType; + return FPBits<T>(static_cast<StorageType>(FPBits<T>(a).uintval() & + FPBits<T>(b).uintval())) + .get_val(); +} + +// Bitwise OR of two floating-point values (a | b), performed directly in +// FP/SIMD registers when SSE2 or AArch64 NEON is available to avoid GPR +// round-trips. +template <typename T> +LIBC_ALWAYS_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T> +fp_or(T a, T b) { + if (!cpp::is_constant_evaluated()) { +#ifdef LIBC_TARGET_CPU_HAS_SSE2 + if constexpr (cpp::is_same_v<T, float>) + return _mm_cvtss_f32(_mm_or_ps(_mm_set_ss(a), _mm_set_ss(b))); + if constexpr (cpp::is_same_v<T, double>) + return _mm_cvtsd_f64(_mm_or_pd(_mm_set_sd(a), _mm_set_sd(b))); +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_ARM_NEON) + if constexpr (cpp::is_same_v<T, float>) + return vget_lane_f32( + vreinterpret_f32_u32(vorr_u32(vreinterpret_u32_f32(vdup_n_f32(a)), + vreinterpret_u32_f32(vdup_n_f32(b)))), + 0); + if constexpr (cpp::is_same_v<T, double>) + return vget_lane_f64( + vreinterpret_f64_u64(vorr_u64(vreinterpret_u64_f64(vdup_n_f64(a)), + vreinterpret_u64_f64(vdup_n_f64(b)))), + 0); +#endif + } + using StorageType = typename FPBits<T>::StorageType; + return FPBits<T>(static_cast<StorageType>(FPBits<T>(a).uintval() | + FPBits<T>(b).uintval())) + .get_val(); +} + +// Bitwise XOR of two floating-point values (a ^ b), performed directly in +// FP/SIMD registers when SSE2 or AArch64 NEON is available to avoid GPR +// round-trips. +template <typename T> +LIBC_ALWAYS_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T> +fp_xor(T a, T b) { + if (!cpp::is_constant_evaluated()) { +#ifdef LIBC_TARGET_CPU_HAS_SSE2 + if constexpr (cpp::is_same_v<T, float>) + return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(a), _mm_set_ss(b))); + if constexpr (cpp::is_same_v<T, double>) + return _mm_cvtsd_f64(_mm_xor_pd(_mm_set_sd(a), _mm_set_sd(b))); +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_ARM_NEON) + if constexpr (cpp::is_same_v<T, float>) + return vget_lane_f32( + vreinterpret_f32_u32(veor_u32(vreinterpret_u32_f32(vdup_n_f32(a)), + vreinterpret_u32_f32(vdup_n_f32(b)))), + 0); + if constexpr (cpp::is_same_v<T, double>) + return vget_lane_f64( + vreinterpret_f64_u64(veor_u64(vreinterpret_u64_f64(vdup_n_f64(a)), + vreinterpret_u64_f64(vdup_n_f64(b)))), + 0); +#endif + } + using StorageType = typename FPBits<T>::StorageType; + return FPBits<T>(static_cast<StorageType>(FPBits<T>(a).uintval() ^ + FPBits<T>(b).uintval())) + .get_val(); +} + +// Bitwise AND-NOT of two floating-point values (a & ~b), clearing the bits set +// in b from a. Performed directly in FP/SIMD registers when SSE2 or AArch64 +// NEON is available to avoid GPR round-trips. +template <typename T> +LIBC_ALWAYS_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T> +fp_andnot(T a, T b) { + if (!cpp::is_constant_evaluated()) { +#ifdef LIBC_TARGET_CPU_HAS_SSE2 + if constexpr (cpp::is_same_v<T, float>) + return _mm_cvtss_f32(_mm_andnot_ps(_mm_set_ss(b), _mm_set_ss(a))); + if constexpr (cpp::is_same_v<T, double>) + return _mm_cvtsd_f64(_mm_andnot_pd(_mm_set_sd(b), _mm_set_sd(a))); +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_ARM_NEON) + if constexpr (cpp::is_same_v<T, float>) + return vget_lane_f32( + vreinterpret_f32_u32(vbic_u32(vreinterpret_u32_f32(vdup_n_f32(a)), + vreinterpret_u32_f32(vdup_n_f32(b)))), + 0); + if constexpr (cpp::is_same_v<T, double>) + return vget_lane_f64( + vreinterpret_f64_u64(vbic_u64(vreinterpret_u64_f64(vdup_n_f64(a)), + vreinterpret_u64_f64(vdup_n_f64(b)))), + 0); +#endif + } + using StorageType = typename FPBits<T>::StorageType; + return FPBits<T>(static_cast<StorageType>(FPBits<T>(a).uintval() & + ~FPBits<T>(b).uintval())) + .get_val(); +} + +// Bitwise NOT of a floating-point value (~a), performed directly in FP/SIMD +// registers when SSE2 or AArch64 NEON is available to avoid GPR round-trips. +template <typename T> +LIBC_ALWAYS_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T> +fp_not(T a) { + if (!cpp::is_constant_evaluated()) { +#ifdef LIBC_TARGET_CPU_HAS_SSE2 + if constexpr (cpp::is_same_v<T, float>) + return _mm_cvtss_f32( + _mm_xor_ps(_mm_set_ss(a), _mm_castsi128_ps(_mm_set1_epi32(-1)))); + if constexpr (cpp::is_same_v<T, double>) + return _mm_cvtsd_f64( + _mm_xor_pd(_mm_set_sd(a), _mm_castsi128_pd(_mm_set1_epi64x(-1)))); +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_ARM_NEON) + if constexpr (cpp::is_same_v<T, float>) + return vget_lane_f32( + vreinterpret_f32_u32(vmvn_u32(vreinterpret_u32_f32(vdup_n_f32(a)))), + 0); + if constexpr (cpp::is_same_v<T, double>) + return vget_lane_f64( + vreinterpret_f64_u32(vmvn_u32(vreinterpret_u32_f64(vdup_n_f64(a)))), + 0); +#endif + } + using StorageType = typename FPBits<T>::StorageType; + FPBits<T> res(a); + res.set_uintval(static_cast<StorageType>(~res.uintval())); + return res.get_val(); +} + +// Directly add an integer `hi` to the exponent field of a floating-point value +// `r`. It is equivalent to scaling `r` by 2^hi when both `r` and the resulting +// bits are normal. +// The default implementation bit-casts `r` to its unsigned storage type, shifts +// `hi` to the exponent field, adds the shifted `hi` to `r`'s bits, and +// bit-casts the result back to `T`. +// When SSE2 or AArch64 NEON is available, `float` and `double` use SIMD +// intrinsics to keep `r` in the FP/SIMD register and perform the shift and +// integer addition directly in the FP/SIMD registers, avoiding a GPR +// round-trip. +template <typename T> +LIBC_ALWAYS_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<T>, T> +scale_exp2(T r, int hi) { + if (!cpp::is_constant_evaluated()) { +#ifdef LIBC_TARGET_CPU_HAS_SSE2 + if constexpr (cpp::is_same_v<T, float>) { + __m128i v_exp = + _mm_slli_epi32(_mm_cvtsi32_si128(hi), FPBits<T>::FRACTION_LEN); + __m128i v_r = _mm_castps_si128(_mm_set_ss(r)); + return _mm_cvtss_f32(_mm_castsi128_ps(_mm_add_epi32(v_exp, v_r))); + } + if constexpr (cpp::is_same_v<T, double>) { + __m128i v_exp = + _mm_slli_epi64(_mm_cvtsi32_si128(hi), FPBits<T>::FRACTION_LEN); + __m128i v_r = _mm_castpd_si128(_mm_set_sd(r)); + return _mm_cvtsd_f64(_mm_castsi128_pd(_mm_add_epi64(v_exp, v_r))); + } +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_NEON) + if constexpr (cpp::is_same_v<T, float>) { + uint32x2_t v_exp = vshl_n_u32(vdup_n_u32(static_cast<uint32_t>(hi)), + FPBits<T>::FRACTION_LEN); + uint32x2_t v_r = vreinterpret_u32_f32(vdup_n_f32(r)); + return vget_lane_f32(vreinterpret_f32_u32(vadd_u32(v_exp, v_r)), 0); + } + if constexpr (cpp::is_same_v<T, double>) { + uint64x1_t v_exp = vshl_n_u64(vdup_n_u64(static_cast<uint64_t>(hi)), + FPBits<T>::FRACTION_LEN); + uint64x1_t v_r = vreinterpret_u64_f64(vdup_n_f64(r)); + return vget_lane_f64(vreinterpret_f64_u64(vadd_u64(v_exp, v_r)), 0); + } +#endif + } + using StorageType = typename FPBits<T>::StorageType; + StorageType exp_hi = static_cast<StorageType>(static_cast<StorageType>(hi) + << FPBits<T>::FRACTION_LEN); + return FPBits<T>(static_cast<StorageType>(exp_hi + FPBits<T>(r).uintval())) + .get_val(); +} + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FP_BITWISE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/hexagon/FEnvImpl.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/hexagon/FEnvImpl.h new file mode 100644 index 000000000000..15d081e54f8c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/hexagon/FEnvImpl.h @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the Hexagon implementation of floating-point +/// environment manipulation functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_HEXAGON_FENVIMPL_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_HEXAGON_FENVIMPL_H + +#include "hdr/fenv_macros.h" +#include "hdr/stdint_proxy.h" +#include "hdr/types/fenv_t.h" +#include "src/__support/macros/attributes.h" // For LIBC_INLINE_ASM +#include "src/__support/macros/config.h" // For LIBC_INLINE + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +// Hexagon keeps all floating-point state in the User Status Register (USR): +// +// bits 5:1 sticky exception status flags +// bit 1 FPINVF invalid +// bit 2 FPDBZF divide-by-zero +// bit 3 FPOVFF overflow +// bit 4 FPUNFF underflow +// bit 5 FPINPF inexact +// bits 23:22 FPRND rounding mode +// 00 round to nearest (ties to even) +// 01 toward zero +// 10 downward (toward -inf) +// 11 upward (toward +inf) +// bits 29:25 exception trap-enable bits (status flag << 24) +// bit 25 FPINVE, bit 26 FPDBZE, bit 27 FPOVFE, +// bit 28 FPUNFE, bit 29 FPINEE +// +// Note the hardware status/enable bit positions do NOT match the FE_* macro +// values used by llvm-libc, so we translate between the two below. +struct FEnv { + // Hardware status-flag bit positions within USR. + static constexpr uint32_t INVALID = 0x02; // bit 1 + static constexpr uint32_t DIVBYZERO = 0x04; // bit 2 + static constexpr uint32_t OVERFLOW = 0x08; // bit 3 + static constexpr uint32_t UNDERFLOW = 0x10; // bit 4 + static constexpr uint32_t INEXACT = 0x20; // bit 5 + static constexpr uint32_t STATUS_MASK = + INVALID | DIVBYZERO | OVERFLOW | UNDERFLOW | INEXACT; + + // The trap-enable bits sit STATUS bits shifted up by this amount. + static constexpr uint32_t ENABLE_SHIFT = 24; + static constexpr uint32_t ENABLE_MASK = STATUS_MASK << ENABLE_SHIFT; + + // Rounding mode field. + static constexpr uint32_t RND_SHIFT = 22; + static constexpr uint32_t RND_MASK = 0x3; + static constexpr uint32_t RND_TONEAREST = 0x0; + static constexpr uint32_t RND_TOWARDZERO = 0x1; + static constexpr uint32_t RND_DOWNWARD = 0x2; + static constexpr uint32_t RND_UPWARD = 0x3; + + // Combined mask of all FP-relevant USR bits. fegetenv/fesetenv only touch + // these so that non-FP USR fields (loop counters, prefetch state, etc.) are + // never disturbed. + static constexpr uint32_t FP_MASK = + STATUS_MASK | (RND_MASK << RND_SHIFT) | ENABLE_MASK; + + LIBC_INLINE static uint32_t get_usr() { + uint32_t usr; + LIBC_INLINE_ASM("%0 = usr\n\t" : "=r"(usr)); + return usr; + } + + LIBC_INLINE static void set_usr(uint32_t usr) { + LIBC_INLINE_ASM("usr = %0\n\t" : : "r"(usr)); + } + + // Translate a set of FE_* exception macros into hardware status-flag bits. + LIBC_INLINE static uint32_t exception_macro_to_bits(int except) { + return ((except & FE_INVALID) ? INVALID : 0) | + ((except & FE_DIVBYZERO) ? DIVBYZERO : 0) | + ((except & FE_OVERFLOW) ? OVERFLOW : 0) | + ((except & FE_UNDERFLOW) ? UNDERFLOW : 0) | + ((except & FE_INEXACT) ? INEXACT : 0); + } + + // Translate hardware status-flag bits back into FE_* exception macros. + LIBC_INLINE static int exception_bits_to_macro(uint32_t status) { + return ((status & INVALID) ? FE_INVALID : 0) | + ((status & DIVBYZERO) ? FE_DIVBYZERO : 0) | + ((status & OVERFLOW) ? FE_OVERFLOW : 0) | + ((status & UNDERFLOW) ? FE_UNDERFLOW : 0) | + ((status & INEXACT) ? FE_INEXACT : 0); + } +}; + +LIBC_INLINE int enable_except(int excepts) { + uint32_t usr = FEnv::get_usr(); + uint32_t old_enabled = (usr >> FEnv::ENABLE_SHIFT) & FEnv::STATUS_MASK; + uint32_t new_enabled = old_enabled | FEnv::exception_macro_to_bits(excepts); + FEnv::set_usr((usr & ~FEnv::ENABLE_MASK) | + (new_enabled << FEnv::ENABLE_SHIFT)); + return FEnv::exception_bits_to_macro(old_enabled); +} + +LIBC_INLINE int disable_except(int excepts) { + uint32_t usr = FEnv::get_usr(); + uint32_t old_enabled = (usr >> FEnv::ENABLE_SHIFT) & FEnv::STATUS_MASK; + uint32_t new_enabled = old_enabled & ~FEnv::exception_macro_to_bits(excepts); + FEnv::set_usr((usr & ~FEnv::ENABLE_MASK) | + (new_enabled << FEnv::ENABLE_SHIFT)); + return FEnv::exception_bits_to_macro(old_enabled); +} + +LIBC_INLINE int get_except() { + uint32_t enabled = + (FEnv::get_usr() >> FEnv::ENABLE_SHIFT) & FEnv::STATUS_MASK; + return FEnv::exception_bits_to_macro(enabled); +} + +LIBC_INLINE int clear_except(int excepts) { + uint32_t usr = FEnv::get_usr(); + usr &= ~FEnv::exception_macro_to_bits(excepts); + FEnv::set_usr(usr); + return 0; +} + +LIBC_INLINE int test_except(int excepts) { + uint32_t to_test = FEnv::exception_macro_to_bits(excepts); + uint32_t status = FEnv::get_usr() & FEnv::STATUS_MASK; + return FEnv::exception_bits_to_macro(status & to_test); +} + +LIBC_INLINE int set_except(int excepts) { + uint32_t usr = FEnv::get_usr(); + FEnv::set_usr(usr | FEnv::exception_macro_to_bits(excepts)); + return 0; +} + +LIBC_INLINE int raise_except(int excepts) { + // Setting the sticky status flag triggers a trap if the corresponding + // enable bit is set; otherwise it simply records the exception. + uint32_t usr = FEnv::get_usr(); + FEnv::set_usr(usr | FEnv::exception_macro_to_bits(excepts)); + return 0; +} + +LIBC_INLINE int get_round() { + uint32_t rm = (FEnv::get_usr() >> FEnv::RND_SHIFT) & FEnv::RND_MASK; + switch (rm) { + case FEnv::RND_TONEAREST: + return FE_TONEAREST; + case FEnv::RND_TOWARDZERO: + return FE_TOWARDZERO; + case FEnv::RND_DOWNWARD: + return FE_DOWNWARD; + case FEnv::RND_UPWARD: + return FE_UPWARD; + default: + return -1; // Error value. + } +} + +LIBC_INLINE int set_round(int mode) { + uint32_t rm; + switch (mode) { + case FE_TONEAREST: + rm = FEnv::RND_TONEAREST; + break; + case FE_TOWARDZERO: + rm = FEnv::RND_TOWARDZERO; + break; + case FE_DOWNWARD: + rm = FEnv::RND_DOWNWARD; + break; + case FE_UPWARD: + rm = FEnv::RND_UPWARD; + break; + default: + return -1; // To indicate failure. + } + uint32_t usr = FEnv::get_usr(); + FEnv::set_usr((usr & ~(FEnv::RND_MASK << FEnv::RND_SHIFT)) | + (rm << FEnv::RND_SHIFT)); + return 0; +} + +LIBC_INLINE int get_env(fenv_t *envp) { + uint32_t *state = reinterpret_cast<uint32_t *>(envp); + *state = FEnv::get_usr() & FEnv::FP_MASK; + return 0; +} + +LIBC_INLINE int set_env(const fenv_t *envp) { + uint32_t usr = FEnv::get_usr(); + if (envp == FE_DFL_ENV) { + // Default environment: round to nearest, no exceptions raised or enabled. + FEnv::set_usr(usr & ~FEnv::FP_MASK); + return 0; + } + uint32_t state = *reinterpret_cast<const uint32_t *>(envp); + // Preserve non-FP USR bits; only load the FP-relevant fields. + FEnv::set_usr((usr & ~FEnv::FP_MASK) | (state & FEnv::FP_MASK)); + return 0; +} + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_HEXAGON_FENVIMPL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/is_integer.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/is_integer.h new file mode 100644 index 000000000000..7864ee901123 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/is_integer.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Floating-point integer check functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_IS_INTEGER_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_IS_INTEGER_H + +#include "src/__support/CPP/bit.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +// These helpers require finite inputs. + +// Check if x is an odd integer: its lowest set significand bit must be at the +// unit position, so x_e + lsb == UNIT_EXPONENT. +template <typename T> LIBC_INLINE constexpr bool is_odd_integer(T x) { + using FPBits = FPBits<T>; + using StorageType = typename FPBits::StorageType; + FPBits xbits(x); + StorageType x_u = xbits.uintval(); + unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent()); + unsigned lsb = static_cast<unsigned>( + cpp::countr_zero(static_cast<StorageType>(x_u | FPBits::EXP_MASK))); + constexpr unsigned UNIT_EXPONENT = + static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN); + return x_e + lsb == UNIT_EXPONENT; +} + +// Check if x is an integer: its lowest set significand bit must be at or above +// the unit position, so x_e + lsb >= UNIT_EXPONENT. +template <typename T> LIBC_INLINE constexpr bool is_integer(T x) { + using FPBits = FPBits<T>; + using StorageType = typename FPBits::StorageType; + FPBits xbits(x); + if (xbits.is_zero()) + return true; + StorageType x_u = xbits.uintval(); + unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent()); + unsigned lsb = static_cast<unsigned>( + cpp::countr_zero(static_cast<StorageType>(x_u | FPBits::EXP_MASK))); + constexpr unsigned UNIT_EXPONENT = + static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN); + return x_e + lsb >= UNIT_EXPONENT; +} + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_IS_INTEGER_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/multiply_add.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/multiply_add.h index dce09622cd66..f7f30035c773 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/multiply_add.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/multiply_add.h @@ -1,10 +1,15 @@ -//===-- Common header for multiply-add implementations ----------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Common header for multiply-add implementations. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_MULTIPLY_ADD_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_MULTIPLY_ADD_H @@ -13,6 +18,7 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA namespace LIBC_NAMESPACE_DECL { @@ -25,13 +31,15 @@ namespace fputil { template <typename T> LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) > sizeof(void *)), T> multiply_add(const T &x, const T &y, const T &z) { - return x * y + z; + T prod = x * y; + return prod + z; } template <typename T> LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) <= sizeof(void *)), T> multiply_add(T x, T y, T z) { - return x * y + z; + T prod = x * y; + return prod + z; } } // namespace fputil @@ -39,6 +47,14 @@ multiply_add(T x, T y, T z) { #if defined(LIBC_TARGET_CPU_HAS_FMA) && !defined(LIBC_USE_CONSTEXPR) +#if !__has_builtin(__builtin_elementwise_fma) && defined(LIBC_COMPILER_IS_MSVC) +#if defined(LIBC_TARGET_ARCH_IS_X86) +#include <immintrin.h> +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) +#include <arm64_neon.h> +#endif +#endif + // FMA instructions are available. // We use builtins directly instead of including FMA.h to avoid a circular // dependency: multiply_add.h -> FMA.h -> generic/FMA.h -> dyadic_float.h. @@ -56,6 +72,12 @@ namespace fputil { LIBC_INLINE float multiply_add(float x, float y, float z) { #if __has_builtin(__builtin_elementwise_fma) return __builtin_elementwise_fma(x, y, z); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_X86) + return _mm_cvtss_f32( + _mm_fmadd_ss(_mm_set_ss(x), _mm_set_ss(y), _mm_set_ss(z))); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_AARCH64) + return vget_lane_f32(vfma_f32(vdup_n_f32(z), vdup_n_f32(x), vdup_n_f32(y)), + 0); #else return __builtin_fmaf(x, y, z); #endif @@ -66,6 +88,12 @@ LIBC_INLINE float multiply_add(float x, float y, float z) { LIBC_INLINE double multiply_add(double x, double y, double z) { #if __has_builtin(__builtin_elementwise_fma) return __builtin_elementwise_fma(x, y, z); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_X86) + return _mm_cvtsd_f64( + _mm_fmadd_sd(_mm_set_sd(x), _mm_set_sd(y), _mm_set_sd(z))); +#elif defined(LIBC_COMPILER_IS_MSVC) && defined(LIBC_TARGET_ARCH_IS_AARCH64) + return vget_lane_f64(vfma_f64(vdup_n_f64(z), vdup_n_f64(x), vdup_n_f64(y)), + 0); #else return __builtin_fma(x, y, z); #endif diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/nearest_integer.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/nearest_integer.h index fabd309bd352..c9d55a2e61af 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/nearest_integer.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/nearest_integer.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_NEAREST_INTEGER_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_NEAREST_INTEGER_H +#include "src/__support/CPP/type_traits.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/macros/properties/architectures.h" @@ -16,7 +17,9 @@ #if (defined(LIBC_TARGET_ARCH_IS_X86_64) && defined(LIBC_TARGET_CPU_HAS_SSE4_2)) #include "x86_64/nearest_integer.h" -#elif (defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP)) +#elif (defined(LIBC_TARGET_ARCH_IS_AARCH64) && \ + defined(LIBC_TARGET_CPU_HAS_FPU_FLOAT) && \ + defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE)) #include "aarch64/nearest_integer.h" #elif defined(LIBC_TARGET_ARCH_IS_GPU) @@ -40,9 +43,15 @@ namespace fputil { // Notice that for AARCH64 and x86-64 with SSE4.2 support, we will use their // corresponding rounding instruction instead. And in those cases, the results // are rounded to the nearest integer, tie-to-even. -LIBC_INLINE static constexpr float nearest_integer(float x) { +LIBC_INLINE constexpr float nearest_integer(float x) { +#if __has_builtin(__builtin_roundevenf) && defined(__ARM_ARCH) && \ + (__ARM_ARCH >= 8) && defined(LIBC_TARGET_CPU_HAS_ARM_FPU_FLOAT) + if (!cpp::is_constant_evaluated()) + return __builtin_roundevenf(x); +#endif if (x < 0x1p24f && x > -0x1p24f) { float r = x < 0 ? (x - 0x1.0p23f) + 0x1.0p23f : (x + 0x1.0p23f) - 0x1.0p23f; +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY float diff = x - r; // The expression above is correct for the default rounding mode, round-to- // nearest, tie-to-even. For other rounding modes, it might be off by 1, @@ -51,14 +60,21 @@ LIBC_INLINE static constexpr float nearest_integer(float x) { return r + 1.0f; if (LIBC_UNLIKELY(diff < -0.5f)) return r - 1.0f; +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY return r; } return x; } -LIBC_INLINE static constexpr double nearest_integer(double x) { +LIBC_INLINE constexpr double nearest_integer(double x) { +#if __has_builtin(__builtin_roundeven) && defined(__ARM_ARCH) && \ + (__ARM_ARCH >= 8) && defined(LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE) + if (!cpp::is_constant_evaluated()) + return __builtin_roundeven(x); +#endif if (x < 0x1p53 && x > -0x1p53) { double r = x < 0 ? (x - 0x1.0p52) + 0x1.0p52 : (x + 0x1.0p52) - 0x1.0p52; +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY double diff = x - r; // The expression above is correct for the default rounding mode, round-to- // nearest, tie-to-even. For other rounding modes, it might be off by 1, @@ -67,6 +83,7 @@ LIBC_INLINE static constexpr double nearest_integer(double x) { return r + 1.0; if (LIBC_UNLIKELY(diff < -0.5)) return r - 1.0; +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY return r; } return x; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/sqrt.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/sqrt.h index fbc279a128ff..e8540adc753b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/sqrt.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/sqrt.h @@ -50,7 +50,7 @@ template <> LIBC_INLINE long double sqrt<long double>(long double x) { // Use inline assembly when __builtin_elementwise_sqrt is not available. #if defined(LIBC_TARGET_CPU_HAS_SSE2) && defined(LIBC_TARGET_ARCH_IS_X86_64) #include "x86_64/sqrt.h" -#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP) +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) #include "aarch64/sqrt.h" #elif defined(LIBC_TARGET_ARCH_IS_ARM) #include "arm/sqrt.h" diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/nearest_integer.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/nearest_integer.h index 4eae5ffe816b..a011e7321e43 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/nearest_integer.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/nearest_integer.h @@ -12,12 +12,14 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" +#include "src/__support/macros/properties/cpu_features.h" #if !defined(LIBC_TARGET_ARCH_IS_X86_64) #error "Invalid include" #endif -#if !defined(__SSE4_2__) +#if !defined(LIBC_TARGET_CPU_HAS_SSE4_2) #error "SSE4.2 instruction set is not supported" #endif @@ -26,18 +28,41 @@ namespace LIBC_NAMESPACE_DECL { namespace fputil { +// The legacy SSE4.1 `roundss` and `roundsd` are 2-operand instructions that +// preserve the upper bits of the destination XMM register (unlike AVX's +// 3-operand `vroundss` and `vroundsd`, where `_mm_round_ss(xmm, xmm, ...)` +// explicitly passes `xmm` as the source for the upper bits). Without AVX, +// because only lane 0 of `_mm_round_ss` / `_mm_round_sd` is used, the compiler +// may allocate a different destination register than the source register, +// creating a false dependency on the destination register's previous value +// (see https://github.com/llvm/llvm-project/issues/230589). Using inline +// assembly with `"+x"(x)` forces identical source and destination registers +// without the extra lane-zeroing instructions required by `_mm_round_ps` / +// `_mm_round_pd`. LIBC_INLINE float nearest_integer(float x) { +#if defined(__AVX__) || defined(LIBC_COMPILER_IS_MSVC) __m128 xmm = _mm_set_ss(x); // NOLINT __m128 ymm = _mm_round_ss(xmm, xmm, _MM_ROUND_NEAREST | _MM_FROUND_NO_EXC); // NOLINT - return ymm[0]; + return _mm_cvtss_f32(ymm); +#else + LIBC_INLINE_ASM("roundss %1, %0, %0" : "+x"(x) : "i"(_MM_ROUND_NEAREST | + _MM_FROUND_NO_EXC)); + return x; +#endif } LIBC_INLINE double nearest_integer(double x) { +#if defined(__AVX__) || defined(LIBC_COMPILER_IS_MSVC) __m128d xmm = _mm_set_sd(x); // NOLINT __m128d ymm = _mm_round_sd(xmm, xmm, _MM_ROUND_NEAREST | _MM_FROUND_NO_EXC); // NOLINT - return ymm[0]; + return _mm_cvtsd_f64(ymm); +#else + LIBC_INLINE_ASM("roundsd %1, %0, %0" : "+x"(x) : "i"(_MM_ROUND_NEAREST | + _MM_FROUND_NO_EXC)); + return x; +#endif } } // namespace fputil diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/sqrt.h b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/sqrt.h index 68ce627a5702..9c8545c1b8fd 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/sqrt.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/FPUtil/x86_64/sqrt.h @@ -12,6 +12,7 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" #include "src/__support/macros/properties/cpu_features.h" #if !defined(LIBC_TARGET_CPU_HAS_SSE2) @@ -20,26 +21,44 @@ #include "src/__support/FPUtil/generic/sqrt.h" +#ifdef LIBC_COMPILER_IS_MSVC +#include <immintrin.h> +#endif + namespace LIBC_NAMESPACE_DECL { namespace fputil { template <> LIBC_INLINE float sqrt<float>(float x) { +#ifdef LIBC_COMPILER_IS_MSVC + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(x))); +#else float result; __asm__ __volatile__("sqrtss %x1, %x0" : "=x"(result) : "x"(x)); return result; +#endif } template <> LIBC_INLINE double sqrt<double>(double x) { +#ifdef LIBC_COMPILER_IS_MSVC + __m128d xmm = _mm_set_sd(x); + return _mm_cvtsd_f64(_mm_sqrt_sd(xmm, xmm)); +#else double result; __asm__ __volatile__("sqrtsd %x1, %x0" : "=x"(result) : "x"(x)); return result; +#endif } #ifdef LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 template <> LIBC_INLINE long double sqrt<long double>(long double x) { +#ifdef LIBC_COMPILER_IS_MSVC + __m128d xmm = _mm_set_sd(static_cast<double>(x)); + return _mm_cvtsd_f64(_mm_sqrt_sd(xmm, xmm)); +#else long double result; __asm__ __volatile__("sqrtsd %x1, %x0" : "=x"(result) : "x"(x)); return result; +#endif } #else template <> LIBC_INLINE long double sqrt<long double>(long double x) { diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/File/CMakeLists.txt index f369fec9a915..ca2670281a92 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/CMakeLists.txt @@ -1,3 +1,9 @@ +add_header_library( + file_io_result + HDRS + file_io_result.h +) + if(NOT (TARGET libc.src.__support.threads.mutex) OR LIBC_TARGET_OS_IS_GPU) # Not all platforms have a mutex implementation. If mutex is unvailable, @@ -12,24 +18,40 @@ add_object_library( HDRS file.h DEPENDS - libc.hdr.stdio_macros - libc.hdr.stdint_proxy + .file_io_result + libc.hdr.errno_macros libc.hdr.func.realloc + libc.hdr.stdint_proxy + libc.hdr.stdio_macros + libc.hdr.types.char32_t + libc.hdr.types.char8_t libc.hdr.types.off_t libc.hdr.types.wchar_t libc.hdr.types.wint_t libc.hdr.wchar_macros + libc.src.__support.alloc_checker libc.src.__support.CPP.new libc.src.__support.CPP.span - libc.src.__support.threads.mutex libc.src.__support.error_or - libc.src.__support.macros.config - libc.src.__support.macros.properties.architectures + libc.src.__support.macros.attributes + libc.src.__support.threads.mutex + libc.src.__support.wchar.character_converter libc.src.__support.wchar.mbstate libc.src.__support.wchar.wcrtomb - libc.src.__support.wchar.character_converter + libc.src.string.memory_utils.inline_memcpy +) + +add_header_library( + dir_scan_impl + HDRS + dir_scan_impl.h + DEPENDS + libc.src.__support.error_or + libc.src.__support.CPP.limits + libc.src.stdlib.qsort_util libc.src.string.memory_utils.inline_memcpy libc.hdr.errno_macros + libc.hdr.types.struct_dirent ) add_object_library( @@ -39,12 +61,12 @@ add_object_library( HDRS dir.h DEPENDS + .dir_scan_impl libc.src.__support.CPP.mutex libc.src.__support.CPP.new libc.src.__support.CPP.span libc.src.__support.threads.mutex libc.src.__support.error_or - libc.src.__support.macros.config libc.src.__support.alloc_checker libc.hdr.errno_macros libc.hdr.types.struct_dirent diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.cpp index eeb44c945b3f..a7fb56945bd6 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.cpp @@ -16,6 +16,7 @@ #include "hdr/errno_macros.h" #include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/CPP/new.h" +#include "src/__support/File/dir_scan_impl.h" #include "src/__support/alloc-checker.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -78,4 +79,11 @@ int Dir::close() { return 0; } +ErrorOr<int> Dir::scan(const char *name, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compare)(const struct dirent **, + const struct dirent **)) { + return internal::scan_impl<Dir>(name, namelist, filter, compare); +} + } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.h index 287e6b7e52f7..58f5276cc9ea 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/dir.h @@ -78,8 +78,15 @@ class Dir { public: static ErrorOr<Dir *> open(const char *path); static ErrorOr<Dir *> fdopen(int fd); - ErrorOr<struct dirent *> read(); + static ErrorOr<int> scan(const char *name, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compare)(const struct dirent **, + const struct dirent **)); + + LIBC_INLINE static size_t reclen(struct dirent *d) { + return platform_dir_reclen(d); + } // Returns 0 on success or the error number on failure. If an error number // was returned, then the resources associated with the directory are not diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/dir_scan_impl.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/dir_scan_impl.h new file mode 100644 index 000000000000..d00a04be3fe0 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/dir_scan_impl.h @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Templated implementation of the scandir logic for dependency injection. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_SCAN_IMPL_H +#define LLVM_LIBC_SRC___SUPPORT_FILE_SCAN_IMPL_H + +#include "hdr/errno_macros.h" +#include "hdr/func/free.h" +#include "hdr/func/malloc.h" +#include "hdr/func/realloc.h" +#include "hdr/types/struct_dirent.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/error_or.h" +#include "src/stdlib/qsort_util.h" +#include "src/string/memory_utils/inline_memcpy.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +template <typename DirType> +ErrorOr<int> scan_impl(const char *name, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compare)(const struct dirent **, + const struct dirent **)) { + auto res_open = DirType::open(name); + if (!res_open) + return LIBC_NAMESPACE::Error(res_open.error()); + + DirType *dir = res_open.value(); + + int error_code = 0; + struct dirent **entries = nullptr; + size_t count = 0; + size_t buffer_capacity = 0; + + auto free_entries = [&entries, &count]() { + if (entries == nullptr) + return; + + for (size_t i = 0; i < count; ++i) + ::free(entries[i]); + + ::free(entries); + }; + + while (true) { + auto res_read = dir->read(); + if (!res_read) { + error_code = res_read.error(); + break; + } + + struct dirent *entry = res_read.value(); + if (entry == nullptr) + break; + + if (filter != nullptr && !filter(entry)) + continue; + + // Scandir must return the number of entries as int, anything + // above that is non-representable. + if (count == cpp::numeric_limits<int>::max()) { + error_code = EOVERFLOW; + break; + } + + if (count >= buffer_capacity) { + size_t new_capacity = (buffer_capacity == 0) ? 8 : buffer_capacity * 2; + + // Overflow check + if (new_capacity > + cpp::numeric_limits<size_t>::max() / sizeof(struct dirent *)) { + error_code = ENOMEM; + break; + } + + struct dirent **bigger_buffer = static_cast<struct dirent **>( + ::realloc(entries, new_capacity * sizeof(struct dirent *))); + if (bigger_buffer == nullptr) { + error_code = ENOMEM; + break; + } + buffer_capacity = new_capacity; + entries = bigger_buffer; + } + + size_t reclen = DirType::reclen(entry); + + struct dirent *new_entry = static_cast<struct dirent *>(::malloc(reclen)); + if (new_entry == nullptr) { + error_code = ENOMEM; + break; + } + inline_memcpy(new_entry, entry, reclen); + + entries[count] = new_entry; + count++; + } + + dir->close(); + + if (error_code != 0) { + free_entries(); + return LIBC_NAMESPACE::Error(error_code); + } + + if (compare != nullptr && count > 1) { + auto cmp_fn = [compare](const void *a, const void *b) { + auto left = static_cast<const struct dirent **>(const_cast<void *>(a)); + auto right = static_cast<const struct dirent **>(const_cast<void *>(b)); + return compare(left, right); + }; + internal::unstable_sort(entries, count, sizeof(struct dirent *), cmp_fn); + } + + *namelist = entries; + return static_cast<int>(count); +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FILE_SCAN_IMPL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/file.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/File/file.cpp index d0366100525a..f8ff4a6e52f2 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/file.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/file.cpp @@ -1,27 +1,43 @@ -//===--- Implementation of a platform independent file data structure -----===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of a platform independent file data structure. +/// +//===----------------------------------------------------------------------===// #include "file.h" +#include "file_io_result.h" +#include "file_mode.h" #include "hdr/errno_macros.h" #include "hdr/func/realloc.h" +#include "hdr/stdint_proxy.h" #include "hdr/stdio_macros.h" +#include "hdr/types/char32_t.h" +#include "hdr/types/char8_t.h" #include "hdr/types/off_t.h" +#include "hdr/types/wchar_t.h" +#include "hdr/types/wint_t.h" #include "hdr/wchar_macros.h" #include "src/__support/CPP/new.h" #include "src/__support/CPP/span.h" #include "src/__support/alloc-checker.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" +#include "src/__support/threads/mutex.h" #include "src/__support/wchar/character_converter.h" +#include "src/__support/wchar/mbstate.h" #include "src/__support/wchar/wcrtomb.h" #include "src/string/memory_utils/inline_memcpy.h" +#include <stddef.h> + namespace LIBC_NAMESPACE_DECL { File *File::list_all = nullptr; Mutex File::list_lock(/*timed=*/false, /*recursive=*/false, /*robust=*/false, @@ -76,7 +92,11 @@ FileIOResult File::write_unlocked_impl(const void *data, size_t len) { return {0, EBADF}; } - prev_op = FileOp::WRITE; + if (prev_op != FileOp::WRITE) { + pos = 0; + read_limit = 0; + prev_op = FileOp::WRITE; + } if (bufmode == _IONBF) { // unbuffered. size_t ret_val = @@ -388,20 +408,20 @@ int File::ungetc_unlocked(int c) { bufref[pos] = static_cast<unsigned char>(c); } + prev_op = FileOp::READ; eof = false; // There is atleast one character that can be read now. err = false; // This operation was a success. return c; } -ErrorOr<int> File::seek(off_t offset, int whence) { - FileLock lock(this); +ErrorOr<int> File::seek_unlocked(off_t offset, int whence) { if (prev_op == FileOp::WRITE && pos > 0) { - FileIOResult buf_result = platform_write(this, buf, pos); if (buf_result.has_error() || buf_result.value < pos) { err = true; return Error(buf_result.error); } + pos = 0; } else if (prev_op == FileOp::READ && whence == SEEK_CUR) { // More data could have been read out from the platform file than was // required. So, we have to adjust the offset we pass to platform seek @@ -424,20 +444,43 @@ ErrorOr<int> File::seek(off_t offset, int whence) { return 0; } -ErrorOr<off_t> File::tell() { - FileLock lock(this); - auto seek_target = eof ? SEEK_END : SEEK_CUR; +ErrorOr<off_t> File::tell_unlocked() { + int seek_target = (eof || (mode.is_append() && prev_op == FileOp::WRITE)) + ? SEEK_END + : SEEK_CUR; auto result = platform_seek(this, 0, seek_target); - if (!result.has_value() || result.value() < 0) + if (!result.has_value()) return Error(result.error()); - off_t platform_offset = result.value(); - if (prev_op == FileOp::READ) - return platform_offset - (read_limit - pos); + if (result.value() < 0) + return Error(EOVERFLOW); + const off_t platform_offset = result.value(); if (prev_op == FileOp::WRITE) - return platform_offset + pos; + return platform_offset + static_cast<off_t>(pos); + if (prev_op == FileOp::READ) + return platform_offset - static_cast<off_t>(read_limit - pos); return platform_offset; } +ErrorOr<File::Position> File::get_pos_unlocked() { + auto pos_result = tell_unlocked(); + if (!pos_result.has_value()) + return Error(pos_result.error()); + + return Position{ + pos_result.value(), + orientation == Orientation::WIDE ? mbstate : internal::mbstate(), + }; +} + +ErrorOr<int> File::set_pos_unlocked(const Position &fpos) { + auto result = seek_unlocked(fpos.offset, SEEK_SET); + if (!result.has_value()) + return Error(result.error()); + + mbstate = fpos.state; + return 0; +} + int File::flush_unlocked() { if (prev_op == FileOp::WRITE && pos > 0) { FileIOResult buf_result = platform_write(this, buf, pos); @@ -459,6 +502,35 @@ int File::flush_unlocked() { return 0; } +// Does the following: +// 1. If in write mode, Write out any data present in the buffer. +// 2. Call platform_close. +// platform_close is expected to cleanup the complete file object. +int File::close() { + { + FileLock lock(this); + if (prev_op == FileOp::WRITE && pos > 0) { + auto buf_result = platform_write(this, buf, pos); + if (buf_result.has_error() || buf_result.value < pos) { + err = true; + return buf_result.error; + } + } + } + + // If we own the buffer, delete it before calling the platform close + // implementation. The platform close should not need to access the buffer + // and we need to clean it up before the entire structure is removed. + if (own_buf) + delete buf; + + // Platform close is expected to cleanup the file data structure which + // includes the file mutex. Hence, we call platform_close after releasing + // the file lock. Another thread doing file operations while a thread is + // closing the file is undefined behavior as per POSIX. + return platform_close(this); +} + int File::set_buffer(void *buffer, size_t size, int buffer_mode) { // We do not need to lock the file as this method should be called before // other operations are performed on the file. @@ -639,6 +711,7 @@ ErrorOr<wint_t> File::ungetwc_unlocked(wint_t wc) { for (size_t i = 0; i < n; ++i) buf[pos + i] = static_cast<uint8_t>(mb_buf[i]); } + prev_op = FileOp::READ; eof = false; err = false; return wc; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/file.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/file.h index 072f5d38c7c9..d4a16c582a3d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/file.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/file.h @@ -1,24 +1,29 @@ -//===--- A platform independent file data structure -------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Platform independent file data structure. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_H #define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_H +#include "file_io_result.h" #include "file_mode.h" #include "hdr/stdint_proxy.h" #include "hdr/stdio_macros.h" #include "hdr/types/off_t.h" #include "hdr/types/wchar_t.h" #include "hdr/types/wint_t.h" -#include "src/__support/CPP/new.h" #include "src/__support/error_or.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/properties/architectures.h" #include "src/__support/threads/mutex.h" #include "src/__support/wchar/mbstate.h" @@ -26,18 +31,6 @@ namespace LIBC_NAMESPACE_DECL { -struct FileIOResult { - size_t value; - int error; - - constexpr FileIOResult(size_t val) : value(val), error(0) {} - constexpr FileIOResult(size_t val, int error) : value(val), error(error) {} - - constexpr bool has_error() { return error != 0; } - - constexpr operator size_t() { return value; } -}; - // This a generic base class to encapsulate a platform independent file data // structure. Platform specific specializations should create a subclass as // suitable for their platform. @@ -52,7 +45,7 @@ class File { static File *list_all; static Mutex list_lock; - File *get_next() const { return next; } + LIBC_INLINE File *get_next() const { return next; } static constexpr size_t DEFAULT_BUFFER_SIZE = 1024; @@ -73,12 +66,12 @@ class File { File *file; public: - explicit FileLock(File *f) : file(f) { file->lock(); } + LIBC_INLINE explicit FileLock(File *f) : file(f) { file->lock(); } - ~FileLock() { file->unlock(); } + LIBC_INLINE ~FileLock() { file->unlock(); } - FileLock(const FileLock &) = delete; - FileLock(FileLock &&) = delete; + LIBC_INLINE FileLock(const FileLock &) = delete; + LIBC_INLINE FileLock(FileLock &&) = delete; }; private: @@ -130,11 +123,15 @@ class File { internal::mbstate mbstate; protected: - constexpr bool write_allowed() const { return mode.write_allowed(); } + LIBC_INLINE constexpr bool write_allowed() const { + return mode.write_allowed(); + } - constexpr bool read_allowed() const { return mode.read_allowed(); } + LIBC_INLINE constexpr bool read_allowed() const { + return mode.read_allowed(); + } - void reset_stream_state_unlocked(FileMode new_mode) { + LIBC_INLINE void reset_stream_state_unlocked(FileMode new_mode) { mode = new_mode; pos = 0; prev_op = FileOp::NONE; @@ -154,9 +151,9 @@ class File { // meaningful - that is, |buffer| is nullptr if and only if |buffer_size| // is zero. This way, we will not have to employ the semantics of // the set_buffer method and allocate a buffer. - constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf, - uint8_t *buffer, size_t buffer_size, int buffer_mode, - bool owned, FileMode mode) + LIBC_INLINE constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, + CloseFunc *cf, uint8_t *buffer, size_t buffer_size, + int buffer_mode, bool owned, FileMode mode) : platform_write(wf), platform_read(rf), platform_seek(sf), platform_close(cf), mutex(/*timed=*/false, /*recursive=*/false, /*robust=*/false, /*pshared=*/false), @@ -172,7 +169,7 @@ class File { FileIOResult write_unlocked(const void *data, size_t len); // Buffered write of |len| bytes from |data| under the file lock. - FileIOResult write(const void *data, size_t len) { + LIBC_INLINE FileIOResult write(const void *data, size_t len) { FileLock l(this); return write_unlocked(data, len); } @@ -181,18 +178,48 @@ class File { FileIOResult read_unlocked(void *data, size_t len); // Buffered read of |len| bytes into |data| under the file lock. - FileIOResult read(void *data, size_t len) { + LIBC_INLINE FileIOResult read(void *data, size_t len) { FileLock l(this); return read_unlocked(data, len); } - ErrorOr<int> seek(off_t offset, int whence); + ErrorOr<int> seek_unlocked(off_t offset, int whence); + + LIBC_INLINE ErrorOr<int> seek(off_t offset, int whence) { + FileLock lock(this); + return seek_unlocked(offset, whence); + } + + ErrorOr<off_t> tell_unlocked(); + + LIBC_INLINE ErrorOr<off_t> tell() { + FileLock lock(this); + return tell_unlocked(); + } + + // An internal representation of the stream's position and parse state. + struct Position { + off_t offset; + internal::mbstate state; + }; + + ErrorOr<Position> get_pos_unlocked(); - ErrorOr<off_t> tell(); + LIBC_INLINE ErrorOr<Position> get_pos() { + FileLock lock(this); + return get_pos_unlocked(); + } + + ErrorOr<int> set_pos_unlocked(const Position &fpos); + + LIBC_INLINE ErrorOr<int> set_pos(const Position &fpos) { + FileLock lock(this); + return set_pos_unlocked(fpos); + } // If buffer has data written to it, flush it out. Does nothing if the // buffer is currently being used as a read buffer. - int flush() { + LIBC_INLINE int flush() { FileLock lock(this); return flush_unlocked(); } @@ -202,60 +229,34 @@ class File { // Returns EOF on error and keeps the file unchanged. int ungetc_unlocked(int c); - int ungetc(int c) { + LIBC_INLINE int ungetc(int c) { FileLock lock(this); return ungetc_unlocked(c); } FileIOResult write_unlocked(const wchar_t *ws, size_t len); - FileIOResult write(const wchar_t *ws, size_t len) { + LIBC_INLINE FileIOResult write(const wchar_t *ws, size_t len) { FileLock l(this); return write_unlocked(ws, len); } FileIOResult read_unlocked(wchar_t *ws, size_t len); - FileIOResult read(wchar_t *ws, size_t len) { + LIBC_INLINE FileIOResult read(wchar_t *ws, size_t len) { FileLock l(this); return read_unlocked(ws, len); } ErrorOr<wint_t> ungetwc_unlocked(wint_t wc); - ErrorOr<wint_t> ungetwc(wint_t wc) { + LIBC_INLINE ErrorOr<wint_t> ungetwc(wint_t wc) { FileLock lock(this); return ungetwc_unlocked(wc); } - // Does the following: - // 1. If in write mode, Write out any data present in the buffer. - // 2. Call platform_close. - // platform_close is expected to cleanup the complete file object. - int close() { - { - FileLock lock(this); - if (prev_op == FileOp::WRITE && pos > 0) { - auto buf_result = platform_write(this, buf, pos); - if (buf_result.has_error() || buf_result.value < pos) { - err = true; - return buf_result.error; - } - } - } - - // If we own the buffer, delete it before calling the platform close - // implementation. The platform close should not need to access the buffer - // and we need to clean it up before the entire structure is removed. - if (own_buf) - delete buf; - - // Platform close is expected to cleanup the file data structure which - // includes the file mutex. Hence, we call platform_close after releasing - // the file lock. Another thread doing file operations while a thread is - // closing the file is undefined behavior as per POSIX. - return platform_close(this); - } + // Closes the file stream and frees up all resources owned by it. + int close(); // Sets the internal buffer to |buffer| with buffering mode |mode|. // |size| is the size of |buffer|. If |size| is non-zero, but |buffer| @@ -271,12 +272,12 @@ class File { // is ENOMEM. int set_buffer(void *buffer, size_t size, int buffer_mode); - void lock() { mutex.lock(); } - void unlock() { mutex.unlock(); } + LIBC_INLINE void lock() { mutex.lock(); } + LIBC_INLINE void unlock() { mutex.unlock(); } - bool error_unlocked() const { return err; } + LIBC_INLINE bool error_unlocked() const { return err; } - bool error() { + LIBC_INLINE bool error() { FileLock l(this); return error_unlocked(); } @@ -288,35 +289,37 @@ class File { // for the pre-processor. #pragma push_macro("clearerr_unlocked") #undef clearerr_unlocked - void clearerr_unlocked() { err = false; } + LIBC_INLINE void clearerr_unlocked() { err = false; } #pragma pop_macro("clearerr_unlocked") - void clearerr() { + LIBC_INLINE void clearerr() { FileLock l(this); clearerr_unlocked(); } - bool iseof_unlocked() { return eof; } + LIBC_INLINE bool iseof_unlocked() { return eof; } - bool iseof() { + LIBC_INLINE bool iseof() { FileLock l(this); return iseof_unlocked(); } - Orientation get_orientation_unlocked() const { return orientation; } + LIBC_INLINE Orientation get_orientation_unlocked() const { + return orientation; + } - Orientation get_orientation() { + LIBC_INLINE Orientation get_orientation() { FileLock l(this); return get_orientation_unlocked(); } - Orientation try_set_orientation_unlocked(Orientation o) { + LIBC_INLINE Orientation try_set_orientation_unlocked(Orientation o) { if (orientation == Orientation::UNORIENTED) orientation = o; return orientation; } - Orientation try_set_orientation(Orientation o) { + LIBC_INLINE Orientation try_set_orientation(Orientation o) { FileLock l(this); return try_set_orientation_unlocked(o); } @@ -333,7 +336,7 @@ class File { FileIOResult read_unlocked_nbf(uint8_t *data, size_t len); size_t copy_data_from_buf(uint8_t *data, size_t len); - constexpr void adjust_buf() { + LIBC_INLINE constexpr void adjust_buf() { if (read_allowed() && (buf == nullptr || bufsize == 0)) { // We should allow atleast one ungetc operation. // This might give an impression that a buffer will be used even when diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/file_io_result.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/file_io_result.h new file mode 100644 index 000000000000..2a589113938d --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/file_io_result.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Result type for file I/O operations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_IO_RESULT_H +#define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_IO_RESULT_H + +#include "src/__support/macros/config.h" + +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +struct FileIOResult { + size_t value; + int error; + + constexpr FileIOResult(size_t val) : value(val), error(0) {} + constexpr FileIOResult(size_t val, int error) : value(val), error(error) {} + + constexpr bool has_error() { return error != 0; } + + constexpr operator size_t() { return value; } +}; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FILE_FILE_IO_RESULT_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/file_mode.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/file_mode.h index f9aece8d22a3..1c4c8b7b7e39 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/file_mode.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/file_mode.h @@ -62,6 +62,9 @@ class FileMode { case 'x': file_mode_ |= static_cast<Mode>(CreateType::EXCLUSIVE); break; + case 'e': + file_mode_ |= static_cast<Mode>(Extension::CLOSE_ON_EXEC); + break; default: file_mode_ = 0; } @@ -83,6 +86,10 @@ class FileMode { constexpr bool is_valid() const { return file_mode_ != 0; } + constexpr bool operator==(const FileMode &other) const { + return file_mode_ == other.file_mode_; + } + constexpr bool is_append() const { return (file_mode_ & static_cast<Mode>(OpenMode::APPEND)) != 0; } @@ -108,6 +115,10 @@ class FileMode { return (file_mode_ & static_cast<Mode>(CreateType::EXCLUSIVE)) != 0; } + constexpr bool is_close_on_exec() const { + return (file_mode_ & static_cast<Mode>(Extension::CLOSE_ON_EXEC)) != 0; + } + private: // Mode is a generic or abstract mode bit for all kinds of modes // (open-mode, 'content-mode', 'create-modes') @@ -115,7 +126,7 @@ class FileMode { // Denotes the mode of the file. // - // The three different types of flags below are to be used with '|' operator. + // The different types of flags below are to be used with '|' operator. // Their values correspond to mutually exclusive bits in a 32-bit unsigned // integer value. A flag set can include both READ and WRITE if the file // is opened in update mode (ie. if the file was opened with a '+' the mode @@ -138,6 +149,11 @@ class FileMode { EXCLUSIVE = 0x100, }; + // POSIX extensions to the ISO C file modes. + enum class Extension : Mode { + CLOSE_ON_EXEC = 0x1000, + }; + // This property tracks the mode for the particular file instance (i.e // currently opened file) Mode file_mode_; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/CMakeLists.txt index d0e1df252895..8ef9e2b761ed 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/CMakeLists.txt @@ -7,13 +7,17 @@ add_object_library( file.h DEPENDS libc.hdr.fcntl_macros + libc.hdr.func.free libc.hdr.stdio_macros libc.hdr.types.mode_t libc.hdr.sys_stat_macros libc.hdr.types.FILE libc.hdr.types.off_t + libc.src.__support.alloc_checker libc.src.__support.CPP.new + libc.src.__support.CPP.type_traits libc.src.__support.OSUtil.linux.syscall_wrappers.close + libc.src.__support.OSUtil.linux.syscall_wrappers.dup3 libc.src.__support.OSUtil.linux.syscall_wrappers.fcntl libc.src.__support.OSUtil.linux.syscall_wrappers.lseek libc.src.__support.OSUtil.linux.syscall_wrappers.open @@ -24,6 +28,21 @@ add_object_library( libc.src.errno.errno ) +add_object_library( + popen_file + SRCS + popen_file.cpp + HDRS + popen_file.h + DEPENDS + .file + libc.hdr.types.pid_t + libc.src.__support.CPP.new + libc.src.__support.File.file + libc.src.__support.macros.config + libc.src.__support.threads.mutex +) + add_object_library( linux_dir SRCS diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.cpp index cc6a1fcbd316..0bc3ba37a4a9 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.cpp @@ -1,10 +1,15 @@ -//===--- Implementation of the Linux specialization of File ---------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of the Linux specialization of File. +/// +//===----------------------------------------------------------------------===// #include "file.h" #include "file_flags.h" @@ -15,13 +20,12 @@ #include "src/__support/File/file.h" #include "src/__support/File/file_mode.h" #include "src/__support/OSUtil/linux/syscall_wrappers/close.h" -#include "src/__support/OSUtil/linux/syscall_wrappers/dup2.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/dup3.h" #include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h" #include "src/__support/OSUtil/linux/syscall_wrappers/lseek.h" #include "src/__support/OSUtil/linux/syscall_wrappers/open.h" #include "src/__support/OSUtil/linux/syscall_wrappers/read.h" #include "src/__support/OSUtil/linux/syscall_wrappers/write.h" -#include "src/__support/alloc-checker.h" #include "src/__support/libc_errno.h" // For error macros #include "src/__support/macros/config.h" @@ -50,20 +54,22 @@ ErrorOr<off_t> linux_file_seek(File *f, off_t offset, int whence) { return linux_syscalls::lseek(lf->get_fd(), offset, whence); } +int LinuxFile::close_fd() { + if (fd < 0) + return EBADF; + // Linux closes the file descriptor early in the syscall, so we assume it's + // always closed after the call. That means callers should also delete the + // file object on error. + auto result = linux_syscalls::close(fd); + if (!result) + return result.error(); + return 0; +} + int linux_file_close(File *f) { File::remove_file(f); auto *lf = reinterpret_cast<LinuxFile *>(f); - int retval = 0; - if (lf->get_fd() >= 0) { - // Linux closes the file descriptor early in the syscall, so we assume it's - // always closed after the call. That means we should also delete the - // LinuxFile on error. - auto result = linux_syscalls::close(lf->get_fd()); - if (!result) - retval = result.error(); - } else { - retval = EBADF; - } + int retval = lf->close_fd(); delete lf; return retval; } @@ -87,6 +93,14 @@ static int map_c_mode_flags_to_linux_open_flags(const FileMode &file_mode) { else if (file_mode.is_write()) open_flags |= LinuxFileFlags::CREATE_OR_TRUNCATE; + // Ignore 'x' for read modes: O_EXCL is only meaningful with O_CREAT here. + if (file_mode.is_exclusive_create() && + (file_mode.is_write() || file_mode.is_append())) + open_flags |= LinuxFileFlags::EXCLUSIVE_CREATE; + + if (file_mode.is_close_on_exec()) + open_flags |= LinuxFileFlags::CLOSE_ON_EXEC; + return open_flags; } @@ -103,20 +117,19 @@ ErrorOr<File *> openfile(const char *path, const char *mode) { if (!fd) return Error(fd.error()); - uint8_t *buffer; - { - AllocChecker ac; - buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE]; - if (!ac) - return Error(ENOMEM); - } - AllocChecker ac; - auto *file = new (ac) LinuxFile(fd.value(), buffer, File::DEFAULT_BUFFER_SIZE, - _IOFBF, true, file_mode); - if (!ac) - return Error(ENOMEM); - File::add_file(file); - return file; + ErrorOr<LinuxFile *> file = LinuxFile::create_buffered(fd.value(), file_mode); + if (!file) + return Error(file.error()); + File::add_file(file.value()); + return file.value(); +} + +static ErrorOr<int> set_close_on_exec(int fd) { + auto flags = linux_syscalls::fcntl(fd, F_GETFD); + if (!flags) + return Error(flags.error()); + return linux_syscalls::fcntl( + fd, F_SETFD, reinterpret_cast<void *>(flags.value() | FD_CLOEXEC)); } ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) { @@ -139,6 +152,12 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) { return Error(EINVAL); } + if (file_mode.is_close_on_exec()) { + auto cloexec_result = set_close_on_exec(fd); + if (!cloexec_result) + return Error(cloexec_result.error()); + } + bool do_seek = false; if (file_mode.is_append() && !LinuxFileFlags::file_has_append_flag(fd_flags)) { @@ -150,20 +169,10 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) { } } - uint8_t *buffer; - { - AllocChecker ac; - buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE]; - if (!ac) { - return Error(ENOMEM); - } - } - AllocChecker ac; - auto *file = new (ac) - LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, file_mode); - if (!ac) { - return Error(ENOMEM); - } + ErrorOr<LinuxFile *> new_file = LinuxFile::create_buffered(fd, file_mode); + if (!new_file) + return Error(new_file.error()); + LinuxFile *file = new_file.value(); File::add_file(file); if (do_seek) { result = file->seek(0, SEEK_END); @@ -195,6 +204,10 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) { int open_flags = map_c_mode_flags_to_linux_open_flags(file_mode); + // Prevent the temporary descriptor from being inherited across exec. + if (old_fd >= 0) + open_flags |= LinuxFileFlags::CLOSE_ON_EXEC; + ErrorOr<int> new_fd = linux_syscalls::open(path, open_flags, LinuxFileFlags::OPEN_MODE); @@ -215,7 +228,10 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) { // Else the new file successfully opened, so we move it into the fd the old // file was using if the old fd exists. if (old_fd >= 0) { - auto dup_result = linux_syscalls::dup2(new_fd.value(), old_fd); + // Preserve close-on-exec atomically when replacing the old descriptor. + int dup_flags = + file_mode.is_close_on_exec() ? LinuxFileFlags::CLOSE_ON_EXEC : 0; + auto dup_result = linux_syscalls::dup3(new_fd.value(), old_fd, dup_flags); if (!dup_result) { linux_syscalls::close(new_fd.value()); reset_stream_state_unlocked(file_mode); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.h index 539957b8b22c..41fc54fac0eb 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file.h @@ -1,14 +1,28 @@ -//===--- Linux specialization of the File data structure ------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux specialization of the File data structure. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_LINUX_FILE_H +#define LLVM_LIBC_SRC___SUPPORT_FILE_LINUX_FILE_H +#include "hdr/func/free.h" +#include "hdr/stdio_macros.h" #include "hdr/types/off_t.h" +#include "src/__support/CPP/new.h" +#include "src/__support/CPP/type_traits.h" #include "src/__support/File/file.h" #include "src/__support/File/file_mode.h" +#include "src/__support/alloc-checker.h" +#include "src/__support/error_or.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -21,12 +35,50 @@ int linux_file_close(File *); class LinuxFile : public File { int fd; + friend int linux_file_close(File *); + +protected: + // For subclasses which need to do extra cleanup when the file is closed. + constexpr LinuxFile(int file_descriptor, uint8_t *buffer, size_t buffer_size, + int buffer_mode, bool owned, FileMode mode, + CloseFunc *close_func) + : File(&linux_file_write, &linux_file_read, &linux_file_seek, close_func, + buffer, buffer_size, buffer_mode, owned, mode), + fd(file_descriptor) {} + + // Closes the underlying file descriptor. Returns 0 on success, or an error + // code. This does not free the file object. + int close_fd(); + public: constexpr LinuxFile(int file_descriptor, uint8_t *buffer, size_t buffer_size, int buffer_mode, bool owned, FileMode mode) - : File(&linux_file_write, &linux_file_read, &linux_file_seek, - &linux_file_close, buffer, buffer_size, buffer_mode, owned, mode), - fd(file_descriptor) {} + : LinuxFile(file_descriptor, buffer, buffer_size, buffer_mode, owned, + mode, &linux_file_close) {} + + // Allocates a FileT owning a new default-size buffer. FileT must be + // LinuxFile or a subclass with LinuxFile's constructor signature. + template <typename FileT = LinuxFile> + LIBC_INLINE static ErrorOr<FileT *> create_buffered(int fd, FileMode mode) { + static_assert(cpp::is_base_of_v<LinuxFile, FileT>, + "FileT must be LinuxFile or derive from it"); + uint8_t *buffer; + { + AllocChecker ac; + buffer = new (ac) uint8_t[DEFAULT_BUFFER_SIZE]; + if (!ac) + return Error(ENOMEM); + } + AllocChecker ac; + auto *file = new (ac) FileT(fd, buffer, DEFAULT_BUFFER_SIZE, _IOFBF, + /*owned=*/true, mode); + if (!ac) { + // Use free instead of delete[] to avoid a GCC 12 ICE in the waccess pass. + free(buffer); + return Error(ENOMEM); + } + return file; + } int get_fd() const { return fd; } void set_fd(int new_fd) { fd = new_fd; } @@ -38,3 +90,5 @@ class LinuxFile : public File { ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode); } // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FILE_LINUX_FILE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file_flags.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file_flags.h index deb357c261d5..ce6849610163 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file_flags.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/file_flags.h @@ -27,6 +27,8 @@ class LinuxFileFlags { static constexpr int WRITE_ONLY = O_WRONLY; static constexpr int READ_ONLY = O_RDONLY; static constexpr int CREATE_OR_TRUNCATE = O_CREAT | O_TRUNC; + static constexpr int EXCLUSIVE_CREATE = O_EXCL; + static constexpr int CLOSE_ON_EXEC = O_CLOEXEC; // File created will have 0666 permissions. LIBC_INLINE static constexpr mode_t OPEN_MODE = diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.cpp new file mode 100644 index 000000000000..66d1d3967245 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of the Linux File specialization for popen streams. +/// +//===----------------------------------------------------------------------===// + +#include "src/__support/File/linux/popen_file.h" + +#include "src/__support/CPP/new.h" +#include "src/__support/File/file.h" +#include "src/__support/macros/config.h" +#include "src/__support/threads/mutex.h" + +namespace LIBC_NAMESPACE_DECL { + +PopenFile *PopenFile::popen_list = nullptr; +Mutex PopenFile::popen_list_lock(/*timed=*/false, /*recursive=*/false, + /*robust=*/false, /*pshared=*/false); + +void PopenFile::add_to_popen_list_unlocked(PopenFile *f) { + f->popen_prev = nullptr; + f->popen_next = popen_list; + if (popen_list != nullptr) + popen_list->popen_prev = f; + popen_list = f; +} + +void PopenFile::close_popen_list_fds_unlocked() { + for (PopenFile *f = popen_list; f != nullptr; f = f->popen_next) + f->close_fd(); +} + +int PopenFile::popen_file_close(File *f) { + File::remove_file(f); + + auto *pf = reinterpret_cast<PopenFile *>(f); + lock_popen_list(); + if (pf->popen_prev != nullptr) + pf->popen_prev->popen_next = pf->popen_next; + if (pf->popen_next != nullptr) + pf->popen_next->popen_prev = pf->popen_prev; + if (popen_list == pf) + popen_list = pf->popen_next; + // Close the fd before unlocking so a concurrent popen cannot fork and + // inherit an fd that has already been removed from popen_list. + int retval = pf->close_fd(); + unlock_popen_list(); + + delete pf; + return retval; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.h b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.h new file mode 100644 index 000000000000..9c959b069c52 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/File/linux/popen_file.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Linux File specialization for streams created by popen. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_LINUX_POPEN_FILE_H +#define LLVM_LIBC_SRC___SUPPORT_FILE_LINUX_POPEN_FILE_H + +#include "hdr/types/pid_t.h" +#include "src/__support/File/file.h" +#include "src/__support/File/file_mode.h" +#include "src/__support/File/linux/file.h" +#include "src/__support/macros/config.h" +#include "src/__support/threads/mutex.h" + +namespace LIBC_NAMESPACE_DECL { + +// A LinuxFile connected to a pipe to a child process created by popen. Open +// popen streams are kept on their own list, so that each new popen child can +// close the streams of earlier popen calls. +class PopenFile : public LinuxFile { + pid_t pid = -1; + PopenFile *popen_prev = nullptr; + PopenFile *popen_next = nullptr; + + static PopenFile *popen_list; + static Mutex popen_list_lock; + + // Removes |f| from the popen list, then closes and frees it like a + // LinuxFile. This does not wait for the child process. + static int popen_file_close(File *f); + +public: + PopenFile(int file_descriptor, uint8_t *buffer, size_t buffer_size, + int buffer_mode, bool owned, FileMode mode) + : LinuxFile(file_descriptor, buffer, buffer_size, buffer_mode, owned, + mode, &popen_file_close) {} + + pid_t get_pid() const { return pid; } + void set_pid(pid_t new_pid) { pid = new_pid; } + + // The popen list lock must be held while calling the *_unlocked functions + // below. popen holds it from before forking until the new stream is on the + // list, so that the child sees a consistent list. + static void lock_popen_list() { popen_list_lock.lock(); } + static void unlock_popen_list() { popen_list_lock.unlock(); } + + // Adds |f| to the popen list. + static void add_to_popen_list_unlocked(PopenFile *f); + + // Closes the file descriptors of every stream on the popen list without + // freeing anything. This is meant to be called in a newly forked child. + static void close_popen_list_fds_unlocked(); +}; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FILE_LINUX_POPEN_FILE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/GPU/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/GPU/CMakeLists.txt index c99c4716c0b4..5ae4eac3d0f2 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/GPU/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/GPU/CMakeLists.txt @@ -7,12 +7,17 @@ add_header_library( utils HDRS utils.h + DEPENDS + libc.hdr.stdint_proxy ) add_header_library( fixedbuffer HDRS fixedbuffer.h + DEPENDS + libc.hdr.stdint_proxy + libc.src.__support.CPP.atomic ) add_object_library( diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/GPU/fixedbuffer.h b/deps/v8/third_party/llvm-libc/src/src/__support/GPU/fixedbuffer.h index 05a4a01be7ea..069cf179fc28 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/GPU/fixedbuffer.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/GPU/fixedbuffer.h @@ -9,10 +9,9 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_GPU_FIXEDBUFFER_H #define LLVM_LIBC_SRC___SUPPORT_GPU_FIXEDBUFFER_H +#include "hdr/stdint_proxy.h" #include "src/__support/CPP/atomic.h" -#include <stdint.h> - namespace LIBC_NAMESPACE_DECL { // A lock-free fixed capacity buffer for caching pointer-like values. Uses a diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/CMakeLists.txt index 93f3d6d5190a..93d24f80ecda 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/CMakeLists.txt @@ -18,6 +18,7 @@ add_object_library( libc.src.__support.common libc.src.__support.CPP.string_view libc.include.sys_syscall + libc.src.__support.OSUtil.linux.syscall_wrappers.exit_group ) add_header_library( @@ -65,6 +66,40 @@ add_header_library( libc.src.__support.CPP.string_view ) +add_header_library( + shell_fork + HDRS + shell_fork.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.signal_macros + libc.hdr.types.pid_t + libc.src.__support.common + libc.src.__support.CPP.functional + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.osutil + libc.src.__support.OSUtil.linux.syscall_wrappers.clone3 + libc.src.__support.OSUtil.linux.syscall_wrappers.execle + libc.src.__support.OSUtil.linux.syscall_wrappers.wait4 + libc.src.unistd.environ +) + +add_header_library( + sigmask + HDRS + sigmask.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.signal_macros + libc.hdr.types.sigset_t + libc.hdr.types.size_t + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.linux.syscall_wrappers.rt_sigprocmask +) + add_header_library( sysinfo HDRS diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/exit.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/exit.cpp index e26b90f6b18e..8e51d4d3c74d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/exit.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/exit.cpp @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall_wrappers/exit_group.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" -#include <sys/syscall.h> // For syscall numbers. namespace LIBC_NAMESPACE_DECL { namespace internal { @@ -21,10 +20,7 @@ __attribute__((no_stack_protector)) #endif __attribute__((noreturn)) void exit(int status) { - for (;;) { - LIBC_NAMESPACE::syscall_impl<long>(SYS_exit_group, status); - LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, status); - } + linux_syscalls::exit_group(status); } } // namespace internal diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/shell_fork.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/shell_fork.h new file mode 100644 index 000000000000..223fc8322007 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/shell_fork.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Helpers for running a command with the shell in a child process, shared by +/// functions like system and popen. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SHELL_FORK_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SHELL_FORK_H + +#include "hdr/errno_macros.h" +#include "hdr/signal_macros.h" +#include "hdr/types/pid_t.h" +#include "src/__support/CPP/functional.h" +#include "src/__support/OSUtil/exit.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/clone3.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/execle.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/wait4.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/unistd/environ.h" + +#include <linux/sched.h> // For struct clone_args + +namespace LIBC_NAMESPACE_DECL { + +// TODO: Move SHELL_PATH into its own header so it can be shared with functions +// like execvp. +LIBC_INLINE_VAR constexpr char SHELL_PATH[] = "/bin/sh"; + +// Work to do in the child process after forking and before executing the +// shell. Returns false if the setup failed and the shell should not be run. +using ShellChildSetup = cpp::function<bool()>; + +// Forks a child process which runs |setup| and then executes +// "sh -c -- |command|" with the current environment. If |setup| or the exec +// fails, the child exits with status 127. Returns the child's pid in the +// parent. +LIBC_INLINE ErrorOr<pid_t> shell_fork(const char *command, + ShellChildSetup setup) { + struct clone_args cl_args{}; + cl_args.exit_signal = SIGCHLD; + ErrorOr<pid_t> fork_res = linux_syscalls::clone3(&cl_args, sizeof(cl_args)); + if (!fork_res.has_value()) + return Error(fork_res.error()); + + if (fork_res.value() == 0) { + // Error checking isn't helpful since this is the forked process, so we + // can't set errno. All we can meaningfully do is exit with status 127. + if (setup()) + linux_syscalls::execle(SHELL_PATH, "sh", "-c", "--", command, 0, environ); + internal::exit(127); + } + + return fork_res.value(); +} + +// Waits for the child process |pid| to terminate, retrying if interrupted by +// a signal. Returns the child's wait status. +LIBC_INLINE ErrorOr<int> shell_wait(pid_t pid) { + int status = 0; + while (true) { + ErrorOr<pid_t> wait_res = linux_syscalls::wait4(pid, &status, 0, nullptr); + if (wait_res.has_value()) + return status; + if (wait_res.error() != EINTR) + return Error(wait_res.error()); + } +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SHELL_FORK_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/sigmask.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/sigmask.h new file mode 100644 index 000000000000..8c06199233ef --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/sigmask.h @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Internal Linux signal mask helpers. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SIGMASK_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SIGMASK_H + +#include "hdr/errno_macros.h" +#include "hdr/signal_macros.h" +#include "hdr/types/sigset_t.h" +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/rt_sigprocmask.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace signals { + +static constexpr size_t BITS_PER_SIGWORD = sizeof(unsigned long) * 8; + +/// Return a signal set with all signals set. +LIBC_INLINE constexpr sigset_t full_set() { + sigset_t set{}; + for (unsigned long &sigword : set.__signals) + sigword = -1UL; + return set; +} + +/// Return an empty signal set with no signals set. +LIBC_INLINE constexpr sigset_t empty_set() { return sigset_t{}; } + +/// Set or clear the bit corresponding to |signal| in |set| according to +/// |value|. Return true on success and false if |signal| is out of range. +LIBC_INLINE constexpr bool set_bit(sigset_t &set, int signal, bool value) { + if (signal >= NSIG || signal <= 0) + return false; + size_t n = static_cast<size_t>(signal) - 1; + size_t word = n / BITS_PER_SIGWORD; + size_t bit = n % BITS_PER_SIGWORD; + if (value) + set.__signals[word] |= (1UL << bit); + else + set.__signals[word] &= ~(1UL << bit); + return true; +} + +/// Set the bit corresponding to |signal| in |set|. Return true on success +/// and false on failure. |signal| must be less than NSIG and be positive. +LIBC_INLINE constexpr bool add(sigset_t &set, int signal) { + return set_bit(set, signal, true); +} + +/// Clear the bit corresponding to |signal| in |set|. Return true on success +/// and false on failure. |signal| must be less than NSIG and be positive. +LIBC_INLINE constexpr bool remove(sigset_t &set, int signal) { + return set_bit(set, signal, false); +} + +/// Test if the bit corresponding to |signal| in |set| is set. +/// Returns 1 if set, 0 if not set, or Error(EINVAL) if |signal| is invalid. +LIBC_INLINE constexpr ErrorOr<int> is_member(const sigset_t &set, int signal) { + if (signal >= NSIG || signal <= 0) + return Error(EINVAL); + size_t n = static_cast<size_t>(signal) - 1; + size_t word = n / BITS_PER_SIGWORD; + size_t bit = n % BITS_PER_SIGWORD; + return (set.__signals[word] & (1UL << bit)) ? 1 : 0; +} + +/// Block the signals in |set|. If |old_set| is non-null, store the previous +/// signal mask in |*old_set|. +LIBC_INLINE ErrorOr<int> block(const sigset_t &set, + sigset_t *old_set = nullptr) { + return linux_syscalls::rt_sigprocmask(SIG_BLOCK, &set, old_set); +} + +/// Block a single |signal|. If |old_set| is non-null, store the previous +/// signal mask in |*old_set|. +LIBC_INLINE ErrorOr<int> block(int signal, sigset_t *old_set = nullptr) { + sigset_t set = empty_set(); + if (!add(set, signal)) + return Error(EINVAL); + return block(set, old_set); +} + +/// Block all signals. If |old_set| is non-null, store the previous signal mask +/// in |*old_set|. +LIBC_INLINE ErrorOr<int> block_all(sigset_t *old_set = nullptr) { + return block(full_set(), old_set); +} + +/// Set the signal mask to |set|. If |old_set| is non-null, store the previous +/// signal mask in |*old_set|. +LIBC_INLINE ErrorOr<int> set_mask(const sigset_t &set, + sigset_t *old_set = nullptr) { + return linux_syscalls::rt_sigprocmask(SIG_SETMASK, &set, old_set); +} + +/// Store the current signal mask in |set|. +LIBC_INLINE ErrorOr<int> get_mask(sigset_t &set) { + return linux_syscalls::rt_sigprocmask(SIG_SETMASK, nullptr, &set); +} + +/// Unblock the signals in |set|. If |old_set| is non-null, store the previous +/// signal mask in |*old_set|. +LIBC_INLINE ErrorOr<int> unblock(const sigset_t &set, + sigset_t *old_set = nullptr) { + return linux_syscalls::rt_sigprocmask(SIG_UNBLOCK, &set, old_set); +} + +/// Unblock a single |signal|. If |old_set| is non-null, store the previous +/// signal mask in |*old_set|. +LIBC_INLINE ErrorOr<int> unblock(int signal, sigset_t *old_set = nullptr) { + sigset_t set = empty_set(); + if (!add(set, signal)) + return Error(EINVAL); + return unblock(set, old_set); +} + +} // namespace signals +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SIGMASK_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt index f5f28f51f49f..c7c1f4b9d204 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt @@ -38,6 +38,42 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + getcpu + HDRS + getcpu.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + sched_get_priority_max + HDRS + sched_get_priority_max.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + sched_get_priority_min + HDRS + sched_get_priority_min.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( sched_getaffinity HDRS @@ -53,9 +89,9 @@ add_header_library( ) add_header_library( - sched_setscheduler + sched_getparam HDRS - sched_setscheduler.h + sched_getparam.h DEPENDS libc.hdr.types.pid_t libc.hdr.types.struct_sched_param @@ -80,9 +116,51 @@ add_header_library( ) add_header_library( - sched_getparam + sched_rr_get_interval HDRS - sched_getparam.h + sched_rr_get_interval.h + DEPENDS + libc.hdr.types.pid_t + libc.hdr.types.struct_timespec + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + sched_setaffinity + HDRS + sched_setaffinity.h + DEPENDS + libc.hdr.types.pid_t + libc.src.__support.CPP.span + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + sched_setparam + HDRS + sched_setparam.h + DEPENDS + libc.hdr.types.pid_t + libc.hdr.types.struct_sched_param + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + sched_setscheduler + HDRS + sched_setscheduler.h DEPENDS libc.hdr.types.pid_t libc.hdr.types.struct_sched_param @@ -93,6 +171,18 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + sched_yield + HDRS + sched_yield.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( close HDRS @@ -215,6 +305,87 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + fgetxattr + HDRS + fgetxattr.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.ssize_t + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + getxattr + HDRS + getxattr.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.ssize_t + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + lgetxattr + HDRS + lgetxattr.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.ssize_t + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + fsetxattr + HDRS + fsetxattr.h + DEPENDS + libc.hdr.types.size_t + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + setxattr + HDRS + setxattr.h + DEPENDS + libc.hdr.types.size_t + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + lsetxattr + HDRS + lsetxattr.h + DEPENDS + libc.hdr.types.size_t + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( flistxattr HDRS @@ -495,6 +666,19 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + pipe2 + HDRS + pipe2.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.macros.sanitizer + libc.include.sys_syscall +) + add_header_library( posix_fadvise HDRS @@ -694,6 +878,35 @@ add_header_library( libc.src.__support.macros.config ) +add_header_library( + fchownat + HDRS + fchownat.h + DEPENDS + libc.hdr.types.gid_t + libc.hdr.types.uid_t + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + +add_header_library( + lchown + HDRS + lchown.h + DEPENDS + libc.hdr.fcntl_macros + libc.hdr.types.gid_t + libc.hdr.types.uid_t + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + add_header_library( ftruncate HDRS @@ -759,6 +972,32 @@ add_header_library( libc.src.__support.OSUtil.osutil ) +add_header_library( + setresgid + HDRS + setresgid.h + DEPENDS + libc.hdr.types.gid_t + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.osutil +) + +add_header_library( + setresuid + HDRS + setresuid.h + DEPENDS + libc.hdr.types.uid_t + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.osutil +) + add_header_library( setreuid HDRS @@ -798,6 +1037,20 @@ add_header_library( libc.src.__support.OSUtil.osutil ) +add_header_library( + setgroups + HDRS + setgroups.h + DEPENDS + libc.hdr.types.gid_t + libc.hdr.types.size_t + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.osutil +) + add_header_library( setpgid HDRS @@ -928,6 +1181,18 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + fdatasync + HDRS + fdatasync.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( fsync HDRS @@ -940,6 +1205,29 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + sync + HDRS + sync.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.macros.config + libc.include.sys_syscall +) + +add_header_library( + syncfs + HDRS + syncfs.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( dup HDRS @@ -978,6 +1266,19 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + epoll_ctl + HDRS + epoll_ctl.h + DEPENDS + libc.hdr.types.struct_epoll_event + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( access HDRS @@ -1056,6 +1357,18 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + renameat + HDRS + renameat.h + DEPENDS + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( lseek HDRS @@ -1137,6 +1450,23 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + ppoll + HDRS + ppoll.h + DEPENDS + libc.hdr.signal_macros + libc.hdr.types.nfds_t + libc.hdr.types.sigset_t + libc.hdr.types.struct_pollfd + libc.hdr.types.struct_timespec + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( rt_sigaction HDRS @@ -1150,6 +1480,28 @@ add_header_library( libc.include.sys_syscall ) +set(clone_arch_header "") +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}/clone.h) + set(clone_arch_header ${LIBC_TARGET_ARCHITECTURE}/clone.h) +endif() + +add_header_library( + clone + HDRS + clone.h + ${clone_arch_header} + DEPENDS + libc.hdr.stdint_proxy + libc.hdr.types.pid_t + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.libc_assert + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.properties.architectures +) + add_header_library( clone3 HDRS @@ -1192,6 +1544,22 @@ add_header_library( libc.include.sys_syscall ) +add_header_library( + waitid + HDRS + waitid.h + DEPENDS + libc.hdr.types.id_t + libc.hdr.types.idtype_t + libc.hdr.types.siginfo_t + libc.hdr.types.struct_rusage + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.include.sys_syscall +) + add_header_library( execve HDRS @@ -1235,6 +1603,19 @@ add_header_library( libc.src.__support.macros.config ) +add_header_library( + timer_getoverrun + HDRS + timer_getoverrun.h + DEPENDS + libc.hdr.types.timer_t + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + add_header_library( timer_gettime HDRS @@ -1356,3 +1737,125 @@ add_header_library( libc.src.__support.CPP.bit libc.src.__support.error_or ) + +add_header_library( + pause + HDRS + pause.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.osutil +) + +add_header_library( + pselect6 + HDRS + pselect6.h + DEPENDS + libc.hdr.signal_macros + libc.hdr.types.fd_set + libc.hdr.types.sigset_t + libc.hdr.types.size_t + libc.hdr.types.struct_timespec + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + +add_header_library( + inotify_init + HDRS + inotify_init.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + +add_header_library( + inotify_init1 + HDRS + inotify_init1.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + +add_header_library( + inotify_add_watch + HDRS + inotify_add_watch.h + DEPENDS + libc.hdr.stdint_proxy + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + +add_header_library( + inotify_rm_watch + HDRS + inotify_rm_watch.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) + +add_header_library( + exit + HDRS + exit.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( + exit_group + HDRS + exit_group.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( + execveat + HDRS + execveat.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config + libc.src.__support.OSUtil.osutil +) + +add_header_library( + eventfd + HDRS + eventfd.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.common + libc.src.__support.error_or + libc.src.__support.macros.config +) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/aarch64/clone.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/aarch64/clone.h new file mode 100644 index 000000000000..527cd4d4cf8d --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/aarch64/clone.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of aarch64 clone. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_AARCH64_CLONE_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_AARCH64_CLONE_H + +#include "hdr/types/pid_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For SYS_clone, SYS_exit + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +constexpr uintptr_t CLONE_STACK_ALIGNMENT = 16; + +namespace detail { + +LIBC_INLINE long clone_impl(int flags, void *child_stack, pid_t *parent_tid, + void *tls, pid_t *child_tid) { + register long x8 asm("x8") = SYS_clone; + register long x0 asm("x0") = flags; + register void *x1 asm("x1") = child_stack; + register pid_t *x2 asm("x2") = parent_tid; + register void *x3 asm("x3") = tls; + register pid_t *x4 asm("x4") = child_tid; + + LIBC_INLINE_ASM("svc #0\n\t" + "cbnz x0, 1f\n\t" + // Child execution: + // Zero frame pointer to terminate call stack unwinding. + "mov x29, #0\n\t" + "ldp x1, x0, [sp], #16\n\t" + "blr x1\n\t" + "mov x8, %[sys_exit]\n\t" + // Does not return. + "svc #0\n\t" + // Just in case it does.. + "brk #0\n\t" + "1:\n\t" : "+r"(x0) : "r"(x8), + "r"(x1), "r"(x2), "r"(x3), + "r"(x4), [sys_exit] "i"(SYS_exit) : "memory", "cc"); + return x0; +} + +} // namespace detail +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_AARCH64_CLONE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/access.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/access.h index 8fa68109cfed..5548875bd8d6 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/access.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/access.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_ACCESS_H #include "hdr/fcntl_macros.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,15 +26,12 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> access(const char *path, int mode) { #ifdef SYS_faccessat - int ret = syscall_impl<int>(SYS_faccessat, AT_FDCWD, path, mode, 0); + return syscall_checked<int>(SYS_faccessat, AT_FDCWD, path, mode, 0); #elif defined(SYS_access) - int ret = syscall_impl<int>(SYS_access, path, mode); + return syscall_checked<int>(SYS_access, path, mode); #else #error "access and faccessat syscalls not available." #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chdir.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chdir.h index 3bd87ca0f488..cb6e149a5945 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chdir.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chdir.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CHDIR_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CHDIR_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> chdir(const char *path) { - int ret = syscall_impl<int>(SYS_chdir, path); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_chdir, path); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chmod.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chmod.h index 42b0d3db9832..e936b8ffd798 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chmod.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/chmod.h @@ -16,7 +16,7 @@ #include "hdr/fcntl_macros.h" #include "hdr/types/mode_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,19 +26,15 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> chmod(const char *path, mode_t mode) { -#ifdef SYS_fchmodat - int ret = syscall_impl<int>(SYS_fchmodat, AT_FDCWD, path, mode, 0); -#elif defined(SYS_fchmodat2) - int ret = syscall_impl<int>(SYS_fchmodat2, AT_FDCWD, path, mode, 0, - AT_SYMLINK_NOFOLLOW); +#if defined(SYS_fchmodat2) + return syscall_checked<int>(SYS_fchmodat2, AT_FDCWD, path, mode, 0); +#elif defined(SYS_fchmodat) + return syscall_checked<int>(SYS_fchmodat, AT_FDCWD, path, mode); #elif defined(SYS_chmod) - int ret = syscall_impl<int>(SYS_chmod, path, mode); + return syscall_checked<int>(SYS_chmod, path, mode); #else #error "chmod, fchmodat and fchmodat2 syscalls not available." #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/clone.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/clone.h new file mode 100644 index 000000000000..c2b13f77e7aa --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/clone.h @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for clone. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_CLONE_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_CLONE_H + +#include "hdr/stdint_proxy.h" +#include "hdr/types/pid_t.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_assert.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/architectures.h" + +#if defined(LIBC_TARGET_ARCH_IS_X86_64) +#include "src/__support/OSUtil/linux/syscall_wrappers/x86_64/clone.h" +#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) +#include "src/__support/OSUtil/linux/syscall_wrappers/aarch64/clone.h" +#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) +#include "src/__support/OSUtil/linux/syscall_wrappers/riscv/clone.h" +#else +#error "clone is not supported for this architecture" +#endif + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +struct ChildStackFrame { + int (*func)(void *); + void *arg; +}; + +LIBC_INLINE ErrorOr<pid_t> clone(int (*func)(void *), void *stack, int flags, + void *arg, pid_t *parent_tid = nullptr, + void *tls = nullptr, + pid_t *child_tid = nullptr) { + uintptr_t sp = reinterpret_cast<uintptr_t>(stack); + LIBC_ASSERT(sp % CLONE_STACK_ALIGNMENT == 0); + + // Set up func and arg at the top of the child stack in C++ so the assembly + // only needs to pass the standard system call arguments. + static_assert(sizeof(ChildStackFrame) <= CLONE_STACK_ALIGNMENT); + sp -= CLONE_STACK_ALIGNMENT; + auto *child_stack = reinterpret_cast<ChildStackFrame *>(sp); + child_stack->func = func; + child_stack->arg = arg; + + // We don't use the syscall function because the child thread will "return" to + // a different stack. Any attempt to access local variables or spilled values + // (which can be implicitly added by the compiler) will crash or cause other + // sorts of problems. + long ret = detail::clone_impl(flags, child_stack, parent_tid, tls, child_tid); + + if (ret < 0) + return Error(static_cast<int>(-ret)); + return static_cast<pid_t>(ret); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_CLONE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/close.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/close.h index fe305af5051c..88c71d9d5af7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/close.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/close.h @@ -1,15 +1,20 @@ -//===-- Implementation header for close -------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for close. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CLOSE_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CLOSE_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -19,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> close(int fd) { - int ret = syscall_impl<int>(SYS_close, fd); - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; + return syscall_checked<int>(SYS_close, fd); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup.h index 3d54b684bd66..9d6141499307 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_DUP_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_DUP_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> dup(int fd) { - int ret = syscall_impl<int>(SYS_dup, fd); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_dup, fd); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup2.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup2.h index 78da9801895a..55687c3dad9c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup2.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup2.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_DUP2_H #include "hdr/fcntl_macros.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h" #include "src/__support/common.h" #include "src/__support/error_or.h" @@ -27,7 +27,7 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> dup2(int oldfd, int newfd) { #ifdef SYS_dup2 - int ret = syscall_impl<int>(SYS_dup2, oldfd, newfd); + return syscall_checked<int>(SYS_dup2, oldfd, newfd); #elif defined(SYS_dup3) if (oldfd == newfd) { auto ret = fcntl(oldfd, F_GETFD); @@ -35,13 +35,10 @@ LIBC_INLINE ErrorOr<int> dup2(int oldfd, int newfd) { return Error(ret.error()); return oldfd; } - int ret = syscall_impl<int>(SYS_dup3, oldfd, newfd, 0); + return syscall_checked<int>(SYS_dup3, oldfd, newfd, 0); #else #error "dup2 and dup3 syscalls not available." #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup3.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup3.h index 3be0ad4526e9..e112cb85d8f6 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup3.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/dup3.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_DUP3_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_DUP3_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> dup3(int oldfd, int newfd, int flags) { - int ret = syscall_impl<int>(SYS_dup3, oldfd, newfd, flags); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_dup3, oldfd, newfd, flags); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/epoll_ctl.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/epoll_ctl.h new file mode 100644 index 000000000000..06464e009a90 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/epoll_ctl.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for epoll_ctl. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EPOLL_CTL_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EPOLL_CTL_H + +#include "hdr/types/struct_epoll_event.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> epoll_ctl(int epfd, int op, int fd, + epoll_event *event) { + return syscall_checked<int>(SYS_epoll_ctl, epfd, op, fd, event); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EPOLL_CTL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/eventfd.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/eventfd.h new file mode 100644 index 000000000000..4fcc45951c9a --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/eventfd.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for eventfd. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EVENTFD_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EVENTFD_H + +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> eventfd(unsigned int initval, int flags) { + return syscall_checked<int>(SYS_eventfd2, initval, flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EVENTFD_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/execveat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/execveat.h new file mode 100644 index 000000000000..375f1ebf646c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/execveat.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for execveat. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_EXECVEAT_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_EXECVEAT_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> execveat(int dirfd, const char *pathname, + char *const argv[], char *const envp[], + int flags) { + return syscall_checked<int>(SYS_execveat, dirfd, pathname, argv, envp, flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_EXECVEAT_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit.h new file mode 100644 index 000000000000..a6df15b007e8 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for exit. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +[[noreturn]] LIBC_INLINE void exit(int status) { + syscall_impl<long>(SYS_exit, status); + __builtin_trap(); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h new file mode 100644 index 000000000000..cf1a6fd086a2 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/exit_group.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for exit_group. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_GROUP_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_GROUP_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +[[noreturn]] LIBC_INLINE void exit_group(int status) { + syscall_impl<long>(SYS_exit_group, status); + __builtin_trap(); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_EXIT_GROUP_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/faccessat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/faccessat.h index 83fd7e617fb8..038613c05805 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/faccessat.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/faccessat.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FACCESSAT_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FACCESSAT_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,15 +26,12 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> faccessat(int dfd, const char *path, int mode, int flags) { #ifdef SYS_faccessat2 - int ret = syscall_impl<int>(SYS_faccessat2, dfd, path, mode, flags); + return syscall_checked<int>(SYS_faccessat2, dfd, path, mode, flags); #elif defined(SYS_faccessat) - int ret = syscall_impl<int>(SYS_faccessat, dfd, path, mode, flags); + return syscall_checked<int>(SYS_faccessat, dfd, path, mode, flags); #else #error "faccessat2 and faccessat syscalls not available." #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchdir.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchdir.h index 2830bb763a86..25b78880b18e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchdir.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchdir.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHDIR_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHDIR_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> fchdir(int fd) { - int ret = syscall_impl<int>(SYS_fchdir, fd); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_fchdir, fd); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchmod.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchmod.h index 4760a821726e..a83257bbe709 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchmod.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchmod.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHMOD_H #include "hdr/types/mode_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -25,10 +25,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> fchmod(int fd, mode_t mode) { - int ret = syscall_impl<int>(SYS_fchmod, fd, mode); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_fchmod, fd, mode); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchownat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchownat.h new file mode 100644 index 000000000000..894621b0ff26 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fchownat.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for fchownat. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHOWNAT_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHOWNAT_H + +#include "hdr/types/gid_t.h" +#include "hdr/types/uid_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> fchownat(int dirfd, const char *pathname, uid_t owner, + gid_t group, int flags) { + return syscall_checked<int>(SYS_fchownat, dirfd, pathname, owner, group, + flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FCHOWNAT_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fcntl.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fcntl.h index 0581693f9612..5bc3482bfe19 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fcntl.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fcntl.h @@ -20,7 +20,7 @@ #include "hdr/types/struct_f_owner_ex.h" #include "hdr/types/struct_flock.h" #include "hdr/types/struct_flock64.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -49,10 +49,7 @@ LIBC_INLINE ErrorOr<int> fcntl(int fd, int cmd, void *arg = nullptr) { flk64.l_len = flk->l_len; flk64.l_pid = flk->l_pid; // create a syscall - int ret = syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64); } case F_OFD_GETLK: case F_OFD_SETLK: { @@ -65,10 +62,10 @@ LIBC_INLINE ErrorOr<int> fcntl(int fd, int cmd, void *arg = nullptr) { flk64.l_len = flk->l_len; flk64.l_pid = flk->l_pid; // create a syscall - int ret = syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64); + auto ret = syscall_checked<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64); // On failure, return - if (ret < 0) - return Error(-ret); + if (!ret) + return ret; // Check for overflow, i.e. the offsets are not the same when cast // to off_t from off64_t. if (static_cast<off_t>(flk64.l_len) != flk64.l_len || @@ -85,9 +82,9 @@ LIBC_INLINE ErrorOr<int> fcntl(int fd, int cmd, void *arg = nullptr) { } case F_GETOWN: { struct f_owner_ex fex; - int ret = syscall_impl<int>(FCNTL_SYSCALL_ID, fd, F_GETOWN_EX, &fex); - if (ret < 0) - return Error(-ret); + auto ret = syscall_checked<int>(FCNTL_SYSCALL_ID, fd, F_GETOWN_EX, &fex); + if (!ret) + return ret; return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid; } #ifdef SYS_fcntl64 @@ -112,10 +109,7 @@ LIBC_INLINE ErrorOr<int> fcntl(int fd, int cmd, void *arg = nullptr) { // Plain passthrough for all other commands. When only SYS_fcntl64 is // available, F_GETLK/F_SETLK/F_SETLKW have been rewritten to their 64-bit // variants by the cases above. - int ret = syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, arg); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(FCNTL_SYSCALL_ID, fd, cmd, arg); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fdatasync.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fdatasync.h new file mode 100644 index 000000000000..f59edfc1a239 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fdatasync.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for fdatasync. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FDATASYNC_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FDATASYNC_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> fdatasync(int fd) { + return syscall_checked<int>(SYS_fdatasync, fd); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FDATASYNC_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h new file mode 100644 index 000000000000..f5c30e1fcd6b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for fgetxattr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H + +#include "hdr/types/size_t.h" +#include "hdr/types/ssize_t.h" +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<ssize_t> fgetxattr(int fd, const char *name, void *value, + size_t size) { + return syscall_checked<ssize_t>(SYS_fgetxattr, fd, name, value, size); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h new file mode 100644 index 000000000000..81c90978d620 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for fsetxattr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H + +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> fsetxattr(int fd, const char *name, const void *value, + size_t size, int flags) { + return syscall_checked<int>(SYS_fsetxattr, fd, name, value, size, flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsync.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsync.h index 1ebbca23f301..4b0a864b6992 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsync.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/fsync.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSYNC_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSYNC_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> fsync(int fd) { - int ret = syscall_impl<int>(SYS_fsync, fd); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_fsync, fd); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h index 6835de85d332..76d692d589ec 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ftruncate.h @@ -1,16 +1,21 @@ -//===-- Implementation header for ftruncate ---------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for ftruncate. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_FTRUNCATE_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_FTRUNCATE_H #include "hdr/types/off_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -21,18 +26,15 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> ftruncate(int fd, off_t len) { #ifdef SYS_ftruncate - int ret = syscall_impl<int>(SYS_ftruncate, fd, len); + return syscall_checked<int>(SYS_ftruncate, fd, len); #elif defined(SYS_ftruncate64) // Same as ftruncate but can handle large offsets on 32-bit systems. static_assert(sizeof(off_t) == 8); - int ret = syscall_impl<int>(SYS_ftruncate64, fd, (long)len, + return syscall_checked<int>(SYS_ftruncate64, fd, (long)len, (long)(((uint64_t)(len)) >> 32)); #else #error "ftruncate and ftruncate64 syscalls not available." #endif - if (ret < 0) - return Error(-static_cast<int>(ret)); - return 0; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcpu.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcpu.h new file mode 100644 index 000000000000..0eb83a3d9d11 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcpu.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for getcpu. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_GETCPU_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_GETCPU_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +// The third argument of the raw syscall (the obsolete tcache pointer) is left +// out: per getcpu(2), it is unused since Linux 2.6.24 and should be specified +// as NULL when invoking the system call directly. +// https://man7.org/linux/man-pages/man2/getcpu.2.html +LIBC_INLINE ErrorOr<int> getcpu(unsigned int *cpu, unsigned int *node) { + return syscall_checked<int>(SYS_getcpu, cpu, node, nullptr); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_GETCPU_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h index f0aa9cb3fbab..19b8d9bc7811 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getcwd.h @@ -16,28 +16,25 @@ #include "hdr/errno_macros.h" #include "hdr/types/ssize_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" - #include <sys/syscall.h> // For syscall numbers namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<ssize_t> getcwd(char *buf, size_t size) { - ssize_t ret = syscall_impl<ssize_t>(SYS_getcwd, buf, size); - if (ret < 0) { - return Error(static_cast<int>(-ret)); - } + auto ret = syscall_checked<ssize_t>(SYS_getcwd, buf, size); + if (!ret) + return ret; // Return ENOENT for unreachable paths. This can occur, for example, // when getcwd is called in a directory after `chroot` has switched // the filesystem root. - if (ret == 0 || buf[0] != '/') { + if (*ret == 0 || buf[0] != '/') return Error(ENOENT); - } return ret; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getegid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getegid.h index 4451ce0993bc..807d622b75af 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getegid.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getegid.h @@ -25,7 +25,13 @@ namespace linux_syscalls { LIBC_INLINE gid_t getegid() { // getegid is expected to always succeed, thus no error checking here. +#if defined(SYS_getegid32) + return syscall_impl<gid_t>(SYS_getegid32); +#elif defined(SYS_getegid) return syscall_impl<gid_t>(SYS_getegid); +#else +#error "SYS_getegid and SYS_getegid32 syscalls not available." +#endif } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h new file mode 100644 index 000000000000..2e90f4aab072 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for getxattr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H + +#include "hdr/types/size_t.h" +#include "hdr/types/ssize_t.h" +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<ssize_t> getxattr(const char *path, const char *name, + void *value, size_t size) { + return syscall_checked<ssize_t>(SYS_getxattr, path, name, value, size); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_add_watch.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_add_watch.h new file mode 100644 index 000000000000..dc0b65f1a17d --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_add_watch.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for inotify_add_watch. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_ADD_WATCH_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_ADD_WATCH_H + +#include "hdr/stdint_proxy.h" +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> inotify_add_watch(int fd, const char *pathname, + uint32_t mask) { + return syscall_checked<int>(SYS_inotify_add_watch, fd, pathname, mask); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_ADD_WATCH_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init.h new file mode 100644 index 000000000000..ebb2c924862f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for inotify_init. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_INIT_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_INIT_H + +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> inotify_init(void) { +#ifdef SYS_inotify_init + return syscall_checked<int>(SYS_inotify_init); +#elif defined(SYS_inotify_init1) + return syscall_checked<int>(SYS_inotify_init1, 0); +#else +#error \ + "inotify_init and inotify_init1 are unavailable. Unable to build inotify_init." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_INIT_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init1.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init1.h new file mode 100644 index 000000000000..68a2dc5fb492 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_init1.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for inotify_init1. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_INIT1_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_INIT1_H + +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> inotify_init1(int flags) { + return syscall_checked<int>(SYS_inotify_init1, flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_INIT1_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_rm_watch.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_rm_watch.h new file mode 100644 index 000000000000..c10746cf7e8c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/inotify_rm_watch.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for inotify_rm_watch. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_RM_WATCH_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_RM_WATCH_H + +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> inotify_rm_watch(int fd, int wd) { + return syscall_checked<int>(SYS_inotify_rm_watch, fd, wd); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_INOTIFY_RM_WATCH_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lchown.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lchown.h new file mode 100644 index 000000000000..c06cbd253d79 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lchown.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for lchown. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LCHOWN_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LCHOWN_H + +#include "hdr/fcntl_macros.h" +#include "hdr/types/gid_t.h" +#include "hdr/types/uid_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> lchown(const char *path, uid_t owner, gid_t group) { +#if defined(SYS_fchownat) + return syscall_checked<int>(SYS_fchownat, AT_FDCWD, path, owner, group, + AT_SYMLINK_NOFOLLOW); +#elif defined(SYS_lchown32) + return syscall_checked<int>(SYS_lchown32, path, owner, group); +#elif defined(SYS_lchown) + return syscall_checked<int>(SYS_lchown, path, owner, group); +#else +#error "fchownat, lchown32, and lchown syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LCHOWN_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h new file mode 100644 index 000000000000..fec3700c4b38 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for lgetxattr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H + +#include "hdr/types/size_t.h" +#include "hdr/types/ssize_t.h" +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<ssize_t> lgetxattr(const char *path, const char *name, + void *value, size_t size) { + return syscall_checked<ssize_t>(SYS_lgetxattr, path, name, value, size); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/link.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/link.h index 7e721e46d420..b542e17e2790 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/link.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/link.h @@ -1,16 +1,21 @@ -//===-- Implementation header for link --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for link. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LINK_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_LINK_H -#include "hdr/fcntl_macros.h" // AT_FDCWD -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "hdr/fcntl_macros.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -21,16 +26,13 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> link(const char *oldpath, const char *newpath) { #ifdef SYS_linkat - int ret = - syscall_impl<int>(SYS_linkat, AT_FDCWD, oldpath, AT_FDCWD, newpath, 0); + return syscall_checked<int>(SYS_linkat, AT_FDCWD, oldpath, AT_FDCWD, newpath, + 0); #elif defined(SYS_link) - int ret = syscall_impl<int>(SYS_link, oldpath, newpath); + return syscall_checked<int>(SYS_link, oldpath, newpath); #else #error "link and linkat syscalls not available." #endif - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lseek.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lseek.h index 861a1174d367..30b17328a8f1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lseek.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lseek.h @@ -16,7 +16,7 @@ #include "hdr/stdint_proxy.h" #include "hdr/types/off_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,27 +26,25 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<off_t> lseek(int fd, off_t offset, int whence) { - off_t result; #ifdef SYS_lseek - result = syscall_impl<off_t>(SYS_lseek, fd, offset, whence); - if (result < 0) - return Error(-static_cast<int>(result)); + return syscall_checked<off_t>(SYS_lseek, fd, offset, whence); #elif defined(SYS_llseek) || defined(SYS__llseek) #ifdef SYS_llseek constexpr long LLSEEK_SYSCALL_NO = SYS_llseek; #elif defined(SYS__llseek) constexpr long LLSEEK_SYSCALL_NO = SYS__llseek; #endif + off_t result; uint64_t offset_64 = static_cast<uint64_t>(offset); - int ret = syscall_impl<int>(LLSEEK_SYSCALL_NO, fd, - static_cast<long>(offset_64 >> 32), - static_cast<long>(offset_64), &result, whence); - if (ret < 0) - return Error(-ret); + auto ret = syscall_checked<int>( + LLSEEK_SYSCALL_NO, fd, static_cast<long>(offset_64 >> 32), + static_cast<long>(offset_64), &result, whence); + if (!ret) + return Error(ret.error()); + return result; #else #error "lseek, llseek and _llseek syscalls not available." #endif - return result; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h new file mode 100644 index 000000000000..776a80698640 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for lsetxattr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H + +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> lsetxattr(const char *path, const char *name, + const void *value, size_t size, int flags) { + return syscall_checked<int>(SYS_lsetxattr, path, name, value, size, flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/memfd_create.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/memfd_create.h index e748c3c6fb80..b54ffbbf6e8f 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/memfd_create.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/memfd_create.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MEMFD_CREATE_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MEMFD_CREATE_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> memfd_create(const char *name, unsigned int flags) { - int ret = syscall_impl<int>(SYS_memfd_create, name, flags); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_memfd_create, name, flags); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdir.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdir.h index b5002914c5ec..4b281a0134f2 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdir.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdir.h @@ -16,7 +16,7 @@ #include "hdr/fcntl_macros.h" #include "hdr/types/mode_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -27,13 +27,10 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> mkdir(const char *path, mode_t mode) { #ifdef SYS_mkdirat - int ret = syscall_impl<int>(SYS_mkdirat, AT_FDCWD, path, mode); + return syscall_checked<int>(SYS_mkdirat, AT_FDCWD, path, mode); #else - int ret = syscall_impl<int>(SYS_mkdir, path, mode); + return syscall_checked<int>(SYS_mkdir, path, mode); #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdirat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdirat.h index 70e67e3fb780..224364f1af98 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdirat.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/mkdirat.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MKDIRAT_H #include "hdr/types/mode_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -25,10 +25,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> mkdirat(int dfd, const char *path, mode_t mode) { - int ret = syscall_impl<int>(SYS_mkdirat, dfd, path, mode); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_mkdirat, dfd, path, mode); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pause.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pause.h new file mode 100644 index 000000000000..c5dcb01bb86e --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pause.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for pause. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_PAUSE_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_PAUSE_H + +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> pause() { + return syscall_checked<int>(SYS_ppoll, nullptr, 0, nullptr, nullptr, 0); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_PAUSE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pipe2.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pipe2.h new file mode 100644 index 000000000000..8187f0022850 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pipe2.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for pipe2. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PIPE2_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PIPE2_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/sanitizer.h" // LIBC_MSAN_UNPOISON +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> pipe2(int pipefd[2], int flags) { + ErrorOr<int> result = syscall_checked<int>(SYS_pipe2, pipefd, flags); + if (result.has_value()) { + LIBC_MSAN_UNPOISON(pipefd, sizeof(int) * 2); + } + return result; +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PIPE2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ppoll.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ppoll.h new file mode 100644 index 000000000000..8ac3a1f070c7 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/ppoll.h @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for ppoll. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PPOLL_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PPOLL_H + +#include "hdr/signal_macros.h" +#include "hdr/types/nfds_t.h" +#include "hdr/types/sigset_t.h" +#include "hdr/types/struct_pollfd.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +// Note: On Linux, the raw ppoll syscall modifies its timeout argument to +// return the remaining time if interrupted. Therefore, this wrapper accepts +// a mutable timespec pointer. The POSIX ppoll entrypoint is responsible for +// making a copy to prevent mutating the user's const timeout argument. +LIBC_INLINE ErrorOr<int> ppoll(struct pollfd *fds, nfds_t nfds, + struct timespec *__restrict tmo_p, + const sigset_t *__restrict sigmask) { + // The kernel expects the signal mask size in bytes, not the number of + // signals. NSIG is the signal count, so NSIG / 8 gives the byte size. + const size_t SIGSETSIZE = NSIG / 8; + +#if defined(SYS_ppoll_time64) + static_assert( + sizeof(time_t) == sizeof(int64_t), + "SYS_ppoll_time64 requires struct timespec with 64-bit members."); + return syscall_checked<int>(SYS_ppoll_time64, fds, nfds, tmo_p, sigmask, + SIGSETSIZE); +#elif defined(SYS_ppoll) + static_assert( + sizeof(timespec::tv_nsec) == sizeof(long), + "This legacy syscall fallback is only safe on platforms where tv_nsec " + "matches the register size (long). It is unsafe on 32-bit platforms " + "with 64-bit tv_nsec."); + return syscall_checked<int>(SYS_ppoll, fds, nfds, tmo_p, sigmask, SIGSETSIZE); +#else +#error "ppoll and ppoll_time64 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PPOLL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h new file mode 100644 index 000000000000..41ef28e024cc --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for pselect6. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PSELECT6_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PSELECT6_H + +#include "hdr/signal_macros.h" +#include "hdr/types/fd_set.h" +#include "hdr/types/sigset_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +// Note: On Linux, the raw pselect6 syscall modifies its timeout argument to +// return the remaining time if interrupted. Therefore, this wrapper accepts +// a mutable timespec pointer. The POSIX pselect entrypoint is responsible for +// making a copy to prevent mutating the user's const timeout argument. +LIBC_INLINE ErrorOr<int> pselect6(int nfds, fd_set *__restrict readfds, + fd_set *__restrict writefds, + fd_set *__restrict exceptfds, + struct timespec *__restrict timeout, + const sigset_t *__restrict sigmask) { + // The kernel expects the signal mask size in bytes, not the number of + // signals. NSIG is the signal count, so NSIG / 8 gives the byte size. + const size_t SIGSETSIZE = NSIG / 8; + struct pselect6_sigset_t { + const sigset_t *ss; + size_t ss_len; + }; + pselect6_sigset_t pss{sigmask, SIGSETSIZE}; + +#if defined(SYS_pselect6_time64) + static_assert( + sizeof(time_t) == sizeof(int64_t), + "SYS_pselect6_time64 requires struct timespec with 64-bit members."); + return syscall_checked<int>(SYS_pselect6_time64, nfds, readfds, writefds, + exceptfds, timeout, &pss); +#elif defined(SYS_pselect6) + static_assert( + sizeof(timespec::tv_nsec) == sizeof(long), + "This legacy syscall fallback is only safe on platforms where tv_nsec " + "matches the register size (long). It is unsafe on 32-bit platforms " + "with 64-bit tv_nsec."); + return syscall_checked<int>(SYS_pselect6, nfds, readfds, writefds, exceptfds, + timeout, &pss); +#else +#error "pselect6 and pselect6_time64 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PSELECT6_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/read.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/read.h index 86123904fc6b..c30a0bb3480e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/read.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/read.h @@ -1,16 +1,21 @@ -//===-- Implementation header for read --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for read. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READ_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READ_H #include "hdr/types/ssize_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -20,10 +25,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<ssize_t> read(int fd, void *buf, size_t count) { - ssize_t ret = syscall_impl<ssize_t>(SYS_read, fd, buf, count); - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; + return syscall_checked<ssize_t>(SYS_read, fd, buf, count); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlink.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlink.h index 0c2e01b2b4d8..60178bc1e843 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlink.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlink.h @@ -16,7 +16,7 @@ #include "hdr/fcntl_macros.h" #include "hdr/types/ssize_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -28,16 +28,12 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<ssize_t> readlink(const char *path, char *buf, size_t bufsiz) { #ifdef SYS_readlinkat - ssize_t ret = - syscall_impl<ssize_t>(SYS_readlinkat, AT_FDCWD, path, buf, bufsiz); + return syscall_checked<ssize_t>(SYS_readlinkat, AT_FDCWD, path, buf, bufsiz); #elif defined(SYS_readlink) - ssize_t ret = syscall_impl<ssize_t>(SYS_readlink, path, buf, bufsiz); + return syscall_checked<ssize_t>(SYS_readlink, path, buf, bufsiz); #else #error "readlink and readlinkat syscalls not available." #endif - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlinkat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlinkat.h index d65573c9d8ae..2ab6fe984614 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlinkat.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/readlinkat.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READLINKAT_H #include "hdr/types/ssize_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,10 +26,7 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<ssize_t> readlinkat(int dfd, const char *path, char *buf, size_t bufsiz) { - ssize_t ret = syscall_impl<ssize_t>(SYS_readlinkat, dfd, path, buf, bufsiz); - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; + return syscall_checked<ssize_t>(SYS_readlinkat, dfd, path, buf, bufsiz); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rename.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rename.h index ec0be35b27ab..25c307e4d9bd 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rename.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rename.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_RENAME_H #include "hdr/fcntl_macros.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,19 +26,16 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> rename(const char *oldpath, const char *newpath) { #ifdef SYS_renameat2 - int ret = - syscall_impl<int>(SYS_renameat2, AT_FDCWD, oldpath, AT_FDCWD, newpath, 0); + return syscall_checked<int>(SYS_renameat2, AT_FDCWD, oldpath, AT_FDCWD, + newpath, 0); #elif defined(SYS_renameat) - int ret = - syscall_impl<int>(SYS_renameat, AT_FDCWD, oldpath, AT_FDCWD, newpath); + return syscall_checked<int>(SYS_renameat, AT_FDCWD, oldpath, AT_FDCWD, + newpath); #elif defined(SYS_rename) - int ret = syscall_impl<int>(SYS_rename, oldpath, newpath); + return syscall_checked<int>(SYS_rename, oldpath, newpath); #else #error "rename, renameat and renameat2 syscalls not available." #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/renameat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/renameat.h new file mode 100644 index 000000000000..519f94723ad6 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/renameat.h @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for renameat. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_RENAMEAT_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_RENAMEAT_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> renameat(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) { +#if defined(SYS_renameat2) + return syscall_checked<int>(SYS_renameat2, olddirfd, oldpath, newdirfd, + newpath, 0); +#elif defined(SYS_renameat) + return syscall_checked<int>(SYS_renameat, olddirfd, oldpath, newdirfd, + newpath); +#else +#error "renameat and renameat2 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_RENAMEAT_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/riscv/clone.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/riscv/clone.h new file mode 100644 index 000000000000..34bfdfc94750 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/riscv/clone.h @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of riscv clone. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_RISCV_CLONE_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_RISCV_CLONE_H + +#include "hdr/stdint_proxy.h" +#include "hdr/types/pid_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For SYS_clone, SYS_exit + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +constexpr uintptr_t CLONE_STACK_ALIGNMENT = 16; + +namespace detail { + +LIBC_INLINE long clone_impl(int flags, void *child_stack, pid_t *parent_tid, + void *tls, pid_t *child_tid) { + register long a7 asm("a7") = SYS_clone; + register long a0 asm("a0") = flags; + register void *a1 asm("a1") = child_stack; + register pid_t *a2 asm("a2") = parent_tid; + register void *a3 asm("a3") = tls; + register pid_t *a4 asm("a4") = child_tid; + + LIBC_INLINE_ASM("ecall\n\t" + "bnez a0, 1f\n\t" + // Child execution: + // Zero frame pointer to terminate call stack unwinding. + "mv s0, zero\n\t" +#if __riscv_xlen == 64 + "ld a1, 0(sp)\n\t" + "ld a0, 8(sp)\n\t" +#else + "lw a1, 0(sp)\n\t" + "lw a0, 4(sp)\n\t" +#endif + "addi sp, sp, %c[stack_adj]\n\t" + "jalr a1\n\t" + "li a7, %[sys_exit]\n\t" + // Does not return. + "ecall\n\t" + // Just in case it does.. + "unimp\n\t" + "1:\n\t" : "+r"(a0) : "r"(a7), + "r"(a1), "r"(a2), "r"(a3), "r"(a4), [sys_exit] "i"(SYS_exit), + [stack_adj] "i"(CLONE_STACK_ALIGNMENT) : "memory"); + return a0; +} + +} // namespace detail +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_RISCV_CLONE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rmdir.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rmdir.h index 0d1cf7a0e367..9ff7abd263f5 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rmdir.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/rmdir.h @@ -15,7 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_RMDIR_H #include "hdr/fcntl_macros.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -26,15 +26,12 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> rmdir(const char *path) { #ifdef SYS_unlinkat - int ret = syscall_impl<int>(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); + return syscall_checked<int>(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); #elif defined(SYS_rmdir) - int ret = syscall_impl<int>(SYS_rmdir, path); + return syscall_checked<int>(SYS_rmdir, path); #else #error "rmdir and unlinkat syscalls not available." #endif - if (ret < 0) - return Error(-ret); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_max.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_max.h new file mode 100644 index 000000000000..2cb60e8f908f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_max.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sched_get_priority_max. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GET_PRIORITY_MAX_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GET_PRIORITY_MAX_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> sched_get_priority_max(int policy) { + return syscall_checked<int>(SYS_sched_get_priority_max, policy); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GET_PRIORITY_MAX_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_min.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_min.h new file mode 100644 index 000000000000..bc2c2946ba88 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_get_priority_min.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sched_get_priority_min. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GET_PRIORITY_MIN_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GET_PRIORITY_MIN_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> sched_get_priority_min(int policy) { + return syscall_checked<int>(SYS_sched_get_priority_min, policy); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GET_PRIORITY_MIN_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_rr_get_interval.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_rr_get_interval.h new file mode 100644 index 000000000000..b22d5507d58f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_rr_get_interval.h @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sched_rr_get_interval. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_RR_GET_INTERVAL_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_RR_GET_INTERVAL_H + +#include "hdr/types/pid_t.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> sched_rr_get_interval(pid_t tid, struct timespec *tp) { +#if defined(SYS_sched_rr_get_interval_time64) + static_assert( + sizeof(time_t) == sizeof(int64_t), + "SYS_sched_rr_get_interval_time64 requires struct timespec with 64-bit " + "members."); + return syscall_checked<int>(SYS_sched_rr_get_interval_time64, tid, tp); +#elif defined(SYS_sched_rr_get_interval) + static_assert( + sizeof(timespec::tv_nsec) == sizeof(long), + "This legacy syscall fallback is only safe on platforms where tv_nsec " + "matches the register size (long). It is unsafe on 32-bit platforms " + "with 64-bit tv_nsec."); + return syscall_checked<int>(SYS_sched_rr_get_interval, tid, tp); +#else +#error \ + "SYS_sched_rr_get_interval and SYS_sched_rr_get_interval_time64 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_RR_GET_INTERVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setaffinity.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setaffinity.h new file mode 100644 index 000000000000..ca3ac8496922 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setaffinity.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sched_setaffinity. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_SETAFFINITY_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_SETAFFINITY_H + +#include "hdr/types/pid_t.h" +#include "src/__support/CPP/span.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> +sched_setaffinity(pid_t tid, cpp::span<const unsigned char> mask) { + return syscall_checked<int>(SYS_sched_setaffinity, tid, mask.size(), + mask.data()); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_SETAFFINITY_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setparam.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setparam.h new file mode 100644 index 000000000000..6ce49c98af62 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_setparam.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sched_setparam. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_SETPARAM_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_SETPARAM_H + +#include "hdr/types/pid_t.h" +#include "hdr/types/struct_sched_param.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" + +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> sched_setparam(pid_t tid, + const struct sched_param *param) { + return syscall_checked<int>(SYS_sched_setparam, tid, param); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_SETPARAM_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_yield.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_yield.h new file mode 100644 index 000000000000..b7d761f01962 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sched_yield.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sched_yield. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_YIELD_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_YIELD_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> sched_yield() { + return syscall_checked<int>(SYS_sched_yield); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SCHED_YIELD_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgid.h index 09a86b332a15..44cd3d5912b2 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgid.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgid.h @@ -25,7 +25,13 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> setgid(gid_t gid) { +#if defined(SYS_setgid32) + return syscall_checked<int>(SYS_setgid32, gid); +#elif defined(SYS_setgid) return syscall_checked<int>(SYS_setgid, gid); +#else +#error "SYS_setgid and SYS_setgid32 syscalls not available." +#endif } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgroups.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgroups.h new file mode 100644 index 000000000000..c316d64623ff --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setgroups.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for setgroups. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETGROUPS_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETGROUPS_H + +#include "hdr/types/gid_t.h" +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> setgroups(size_t size, const gid_t *list) { + // Confusingly, 32-bit is the newer syscall, replacing the 16-bit legacy + // version. +#if defined(SYS_setgroups32) + return syscall_checked<int>(SYS_setgroups32, size, list); +#elif defined(SYS_setgroups) + return syscall_checked<int>(SYS_setgroups, size, list); +#else +#error "SYS_setgroups and SYS_setgroups32 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETGROUPS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setregid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setregid.h index 02ebc2187dc8..9ee5794715fe 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setregid.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setregid.h @@ -25,7 +25,13 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> setregid(gid_t rgid, gid_t egid) { +#if defined(SYS_setregid32) + return syscall_checked<int>(SYS_setregid32, rgid, egid); +#elif defined(SYS_setregid) return syscall_checked<int>(SYS_setregid, rgid, egid); +#else +#error "SYS_setregid and SYS_setregid32 syscalls not available." +#endif } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresgid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresgid.h new file mode 100644 index 000000000000..df68ca97d78e --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresgid.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for setresgid. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETRESGID_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETRESGID_H + +#include "hdr/types/gid_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> setresgid(gid_t rgid, gid_t egid, gid_t sgid) { +#if defined(SYS_setresgid32) + return syscall_checked<int>(SYS_setresgid32, rgid, egid, sgid); +#elif defined(SYS_setresgid) + return syscall_checked<int>(SYS_setresgid, rgid, egid, sgid); +#else +#error "SYS_setresgid and SYS_setresgid32 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETRESGID_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresuid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresuid.h new file mode 100644 index 000000000000..4574e9a28a6f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setresuid.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for setresuid. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETRESUID_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETRESUID_H + +#include "hdr/types/uid_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> setresuid(uid_t ruid, uid_t euid, uid_t suid) { +#if defined(SYS_setresuid32) + return syscall_checked<int>(SYS_setresuid32, ruid, euid, suid); +#elif defined(SYS_setresuid) + return syscall_checked<int>(SYS_setresuid, ruid, euid, suid); +#else +#error "SYS_setresuid and SYS_setresuid32 syscalls not available." +#endif +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETRESUID_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setreuid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setreuid.h index 68f08b24d3f2..4aa124316258 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setreuid.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setreuid.h @@ -25,7 +25,13 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> setreuid(uid_t ruid, uid_t euid) { +#if defined(SYS_setreuid32) + return syscall_checked<int>(SYS_setreuid32, ruid, euid); +#elif defined(SYS_setreuid) return syscall_checked<int>(SYS_setreuid, ruid, euid); +#else +#error "SYS_setreuid and SYS_setreuid32 syscalls not available." +#endif } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setuid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setuid.h index 8d99551b9739..ba911d1273ce 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setuid.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setuid.h @@ -25,7 +25,13 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> setuid(uid_t uid) { +#if defined(SYS_setuid32) + return syscall_checked<int>(SYS_setuid32, uid); +#elif defined(SYS_setuid) return syscall_checked<int>(SYS_setuid, uid); +#else +#error "SYS_setuid and SYS_setuid32 syscalls not available." +#endif } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h new file mode 100644 index 000000000000..dda33e6a0e1a --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for setxattr. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H + +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/linux/syscall.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> setxattr(const char *path, const char *name, + const void *value, size_t size, int flags) { + return syscall_checked<int>(SYS_setxattr, path, name, value, size, flags); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/statx.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/statx.h index c65a74fc3ec0..ae40dab3594d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/statx.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/statx.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_STATX_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_STATX_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -25,10 +25,7 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> statx(int dirfd, const char *path, int flags, unsigned int mask, void *statxbuf) { - int ret = syscall_impl<int>(SYS_statx, dirfd, path, flags, mask, statxbuf); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_statx, dirfd, path, flags, mask, statxbuf); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sync.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sync.h new file mode 100644 index 000000000000..29761002d71d --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/sync.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for sync. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SYNC_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SYNC_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE void sync() { syscall_impl<int>(SYS_sync); } + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SYNC_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/syncfs.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/syncfs.h new file mode 100644 index 000000000000..0585f0663417 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/syncfs.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for syncfs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SYNCFS_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SYNCFS_H + +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> syncfs(int fd) { + return syscall_checked<int>(SYS_syncfs, fd); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_SYNCFS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/timer_getoverrun.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/timer_getoverrun.h new file mode 100644 index 000000000000..c94313675980 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/timer_getoverrun.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for timer_getoverrun syscall wrapper. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_GETOVERRUN_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_GETOVERRUN_H + +#include "hdr/types/timer_t.h" +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> timer_getoverrun(timer_t timerid) { + return syscall_checked<int>(SYS_timer_getoverrun, timerid); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_TIMER_GETOVERRUN_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlink.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlink.h index e04ebada8cb8..b235c18a0a05 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlink.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlink.h @@ -1,16 +1,21 @@ -//===-- Implementation header for unlink ------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for unlink. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_UNLINK_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_UNLINK_H -#include "hdr/fcntl_macros.h" // AT_FDCWD -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "hdr/fcntl_macros.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -21,15 +26,12 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> unlink(const char *path) { #ifdef SYS_unlinkat - int ret = syscall_impl<int>(SYS_unlinkat, AT_FDCWD, path, 0); + return syscall_checked<int>(SYS_unlinkat, AT_FDCWD, path, 0); #elif defined(SYS_unlink) - int ret = syscall_impl<int>(SYS_unlink, path); + return syscall_checked<int>(SYS_unlink, path); #else #error "unlink and unlinkat syscalls not available." #endif - if (ret < 0) - return Error(-static_cast<int>(ret)); - return 0; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlinkat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlinkat.h index ffba729333fb..1e2155e5891d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlinkat.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/unlinkat.h @@ -14,7 +14,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_UNLINKAT_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_UNLINKAT_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -24,10 +24,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<int> unlinkat(int dfd, const char *path, int flags) { - int ret = syscall_impl<int>(SYS_unlinkat, dfd, path, flags); - if (ret < 0) - return Error(-ret); - return ret; + return syscall_checked<int>(SYS_unlinkat, dfd, path, flags); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/utimensat.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/utimensat.h index cbf79f5de2cb..635eef05cb01 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/utimensat.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/utimensat.h @@ -1,20 +1,24 @@ -//===-- Implementation header for utimensat ---------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for utimensat. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_UTIMENSAT_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_UTIMENSAT_H -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "hdr/types/struct_timespec.h" +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" - -#include "hdr/types/struct_timespec.h" #include <sys/syscall.h> // For syscall numbers namespace LIBC_NAMESPACE_DECL { @@ -23,21 +27,17 @@ namespace linux_syscalls { LIBC_INLINE ErrorOr<int> utimensat(int dirfd, const char *path, const struct timespec times[2], int flags) { #if defined(SYS_utimensat_time64) - int ret = syscall_impl<int>(SYS_utimensat_time64, dirfd, path, times, flags); + return syscall_checked<int>(SYS_utimensat_time64, dirfd, path, times, flags); #elif defined(SYS_utimensat) static_assert( sizeof(timespec::tv_nsec) == sizeof(long), "This legacy syscall fallback is only safe on platforms where tv_nsec " "matches the register size (long). It is unsafe on 32-bit platforms " "with 64-bit tv_nsec."); - int ret = syscall_impl<int>(SYS_utimensat, dirfd, path, times, flags); + return syscall_checked<int>(SYS_utimensat, dirfd, path, times, flags); #else #error "utimensat or utimensat_time64 syscalls not available." #endif - - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/waitid.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/waitid.h new file mode 100644 index 000000000000..bec799ee7eaf --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/waitid.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for waitid. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_WAITID_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_WAITID_H + +#include "hdr/types/id_t.h" +#include "hdr/types/idtype_t.h" +#include "hdr/types/siginfo_t.h" +#include "hdr/types/struct_rusage.h" +#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For syscall numbers + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +LIBC_INLINE ErrorOr<int> waitid(idtype_t idtype, id_t id, siginfo_t *infop, + int options, struct rusage *rusage = nullptr) { + return syscall_checked<int>(SYS_waitid, idtype, id, infop, options, rusage); +} + +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_WAITID_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/write.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/write.h index e57986d357a2..d253ee68d764 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/write.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/write.h @@ -1,16 +1,21 @@ -//===-- Implementation header for write -------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Syscall wrapper for write. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WRITE_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WRITE_H #include "hdr/types/ssize_t.h" -#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl +#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked #include "src/__support/common.h" #include "src/__support/error_or.h" #include "src/__support/macros/config.h" @@ -20,10 +25,7 @@ namespace LIBC_NAMESPACE_DECL { namespace linux_syscalls { LIBC_INLINE ErrorOr<ssize_t> write(int fd, const void *buf, size_t count) { - ssize_t ret = syscall_impl<ssize_t>(SYS_write, fd, buf, count); - if (ret < 0) - return Error(-static_cast<int>(ret)); - return ret; + return syscall_checked<ssize_t>(SYS_write, fd, buf, count); } } // namespace linux_syscalls diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/x86_64/clone.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/x86_64/clone.h new file mode 100644 index 000000000000..229cc7a7e78b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/linux/syscall_wrappers/x86_64/clone.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of x86_64 clone. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_X86_64_CLONE_H +#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_X86_64_CLONE_H + +#include "hdr/types/pid_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include <sys/syscall.h> // For SYS_clone, SYS_exit + +namespace LIBC_NAMESPACE_DECL { +namespace linux_syscalls { + +constexpr uintptr_t CLONE_STACK_ALIGNMENT = 16; + +namespace detail { + +LIBC_INLINE long clone_impl(int flags, void *child_stack, pid_t *parent_tid, + void *tls, pid_t *child_tid) { + long ret; + register pid_t *r10 __asm__("r10") = child_tid; + register void *r8 __asm__("r8") = tls; + + LIBC_INLINE_ASM("syscall\n\t" + "testq %%rax, %%rax\n\t" + "jnz 1f\n\t" + // Child execution: + // Zero frame pointer to terminate call stack unwinding. + "xorl %%ebp, %%ebp\n\t" + "popq %%rax\n\t" + "popq %%rdi\n\t" + "call *%%rax\n\t" + "movl %%eax, %%edi\n\t" + "movl %[sys_exit], %%eax\n\t" + // Does not return. + "syscall\n\t" + // Just in case it does.. + "ud2\n\t" + "1:\n\t" : "=a"(ret) : "0"(SYS_clone), + "D"(flags), "S"(child_stack), "d"(parent_tid), "r"(r10), + "r"(r8), [sys_exit] "i"(SYS_exit) : "rcx", "r11", "memory"); + return ret; +} + +} // namespace detail +} // namespace linux_syscalls +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_WRAPPERS_X86_64_CLONE_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/error.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/error.h index 9fdc569bab57..370327580380 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/error.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/error.h @@ -1,10 +1,15 @@ -//===----------- UEFI implementation of error utils --------------*- C++-*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// UEFI implementation of error utils. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_ERROR_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/exit.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/exit.cpp index e734983cd125..f28ccff36bd1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/exit.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/exit.cpp @@ -1,21 +1,31 @@ -//===-------- UEFI implementation of an exit function ------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===-----------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// UEFI implementation of the internal exit function. +/// +//===----------------------------------------------------------------------===// #include "src/__support/OSUtil/exit.h" -#include "config/uefi.h" -#include "include/llvm-libc-types/EFI_SYSTEM_TABLE.h" +#include "config/app.h" +#include "include/llvm-libc-types/EFI_STATUS.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace internal { [[noreturn]] void exit(int status) { - app.system_table->BootServices->Exit(__llvm_libc_efi_image_handle, status, 0, + // The exit status is handed back to the firmware as the image's EFI_STATUS. + // Zero maps to EFI_SUCCESS; any other value is reported as EFI_ABORTED so + // that it is reported as an error by the loader instead of being misread + // as an unrelated EFI status or warning code. + EFI_STATUS efi_status = status == 0 ? EFI_SUCCESS : EFI_ABORTED; + app.system_table->BootServices->Exit(app.image_handle, efi_status, 0, nullptr); __builtin_unreachable(); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.cpp index e1e50fbad393..8bcb87cbd0ee 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.cpp @@ -1,10 +1,15 @@ -//===---------- UEFI implementation of IO utils ------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===-----------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// UEFI implementation of IO utils. +/// +//===----------------------------------------------------------------------===// #include "io.h" diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.h b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.h index 088ae09b8c60..9ffc76e724af 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/OSUtil/uefi/io.h @@ -1,10 +1,15 @@ -//===---------- UEFI implementation of IO utils ------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===-----------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +/// +/// \file +/// UEFI implementation of IO utils. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_IO_H #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_UEFI_IO_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/RPC/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/RPC/CMakeLists.txt index cac9c4e05e36..cbf20fa0e920 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/RPC/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/RPC/CMakeLists.txt @@ -9,5 +9,6 @@ add_object_library( HDRS rpc_client.h DEPENDS + libc.hdr.stdint_proxy libc.src.__support.GPU.utils ) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/big_int.h b/deps/v8/third_party/llvm-libc/src/src/__support/big_int.h index 3bc9833664c1..3461cd23728c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/big_int.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/big_int.h @@ -50,7 +50,7 @@ template <typename T> struct DoubleWide final : cpp::array<T, 2> { }; // Converts an unsigned value into a DoubleWide<half_width_t<T>>. -template <typename T> LIBC_INLINE constexpr auto split(T value) { +template <typename T> LIBC_ALWAYS_INLINE constexpr auto split(T value) { static_assert(cpp::is_unsigned_v<T>); using half_type = half_width_t<T>; return DoubleWide<half_type>( @@ -59,19 +59,21 @@ template <typename T> LIBC_INLINE constexpr auto split(T value) { } // The low part of a DoubleWide value. -template <typename T> LIBC_INLINE constexpr T lo(const DoubleWide<T> &value) { +template <typename T> +LIBC_ALWAYS_INLINE constexpr T lo(const DoubleWide<T> &value) { return value[0]; } // The high part of a DoubleWide value. -template <typename T> LIBC_INLINE constexpr T hi(const DoubleWide<T> &value) { +template <typename T> +LIBC_ALWAYS_INLINE constexpr T hi(const DoubleWide<T> &value) { return value[1]; } // The low part of an unsigned value. -template <typename T> LIBC_INLINE constexpr half_width_t<T> lo(T value) { +template <typename T> LIBC_ALWAYS_INLINE constexpr half_width_t<T> lo(T value) { return lo(split(value)); } // The high part of an unsigned value. -template <typename T> LIBC_INLINE constexpr half_width_t<T> hi(T value) { +template <typename T> LIBC_ALWAYS_INLINE constexpr half_width_t<T> hi(T value) { return hi(split(value)); } @@ -239,9 +241,40 @@ LIBC_INLINE constexpr word multiply_with_carry(cpp::array<word, O> &dst, } template <typename word, size_t N> -LIBC_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst, - const cpp::array<word, N> &lhs, - const cpp::array<word, N> &rhs) { +LIBC_ALWAYS_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst, + const cpp::array<word, N> &lhs, + const cpp::array<word, N> &rhs) { + if constexpr (N == 1) { + if constexpr (cpp::is_same_v<word, uint8_t>) { + dst[0] = hi<uint16_t>(uint16_t(lhs[0]) * uint16_t(rhs[0])); + } else if constexpr (cpp::is_same_v<word, uint16_t>) { + dst[0] = hi<uint32_t>(uint32_t(lhs[0]) * uint32_t(rhs[0])); + } +#ifdef LIBC_TYPES_HAS_INT64 + else if constexpr (cpp::is_same_v<word, uint32_t>) { + dst[0] = hi<uint64_t>(uint64_t(lhs[0]) * uint64_t(rhs[0])); + } +#endif // LIBC_TYPES_HAS_INT64 +#ifdef LIBC_TYPES_HAS_INT128 + else if constexpr (cpp::is_same_v<word, uint64_t>) { + dst[0] = hi<__uint128_t>(__uint128_t(lhs[0]) * __uint128_t(rhs[0])); + } +#endif // LIBC_TYPES_HAS_INT128 + else { + // Split the single word into half-words and perform 3 half-word + // multiplications instead of 4. + word a = lhs[0]; + word b = rhs[0]; + word a_lo = lo(a); + word a_hi = hi(a); + word b_lo = lo(b); + word b_hi = hi(b); + word t1 = a_hi * b_lo; + word t2 = a_lo * b_hi + lo(t1); + dst[0] = a_hi * b_hi + hi(t1) + hi(t2); + } + return; + } Accumulator<word> acc; word carry = 0; // First round of accumulation for those at N - 1 in the full product. @@ -638,7 +671,11 @@ struct BigInt { // `Bits` least significant bits of the full product, while this function will // approximate `Bits` most significant bits of the full product with errors // bounded by: - // 0 <= (a.full_mul(b) >> Bits) - a.quick_mul_hi(b)) <= WORD_COUNT - 1. + // 0 <= (a.full_mul(b) >> Bits) - a.quick_mul_hi(b)) <= max(WORD_COUNT - 1, + // 1) + // (when WORD_COUNT == 1 and WordType is natively supported by a double-width + // integer type, the error is 0; otherwise when split into half-words, the + // error is bounded by 1). // // An example usage of this is to quickly (but less accurately) compute the // product of (normalized) mantissas of floating point numbers: @@ -651,11 +688,12 @@ struct BigInt { // Performance summary: // Number of 64-bit x 64-bit -> 128-bit multiplications performed. // Bits WORD_COUNT ful_mul quick_mul_hi Error bound + // 64 1 1 1 0 (1 without int128) // 128 2 4 3 1 // 196 3 9 6 2 // 256 4 16 10 3 // 512 8 64 36 7 - LIBC_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const { + LIBC_ALWAYS_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const { BigInt result{}; multiword::quick_mul_hi(result.val, val, other.val); return result; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/block.h b/deps/v8/third_party/llvm-libc/src/src/__support/block.h index be2a71f32a23..d002dae2c162 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/block.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/block.h @@ -17,6 +17,7 @@ #include "hdr/stdint_proxy.h" #include "hdr/types/size_t.h" #include "src/__support/CPP/algorithm.h" +#include "src/__support/CPP/bit.h" #include "src/__support/CPP/cstddef.h" #include "src/__support/CPP/limits.h" #include "src/__support/CPP/new.h" @@ -99,9 +100,22 @@ using cpp::optional; /// The next offset of a block matches the previous offset of its next block. /// The first block in a list is denoted by having a previous offset of `0`. class BlockRef { - // Masks for the contents of the next field. - static constexpr size_t PREV_FREE_MASK = 1 << 0; - static constexpr size_t LAST_MASK = 1 << 1; +public: + /// The number of free stores that free blocks are distributed over. + /// + /// Every free block records which store owns it, which lets an allocator + /// hold several stores and rotate between them; see FreeListHeap. Each + /// additional store widens the free field below, and hence MIN_ALIGN. +#ifdef LIBC_COPT_BAREMETAL_HEAP_ENABLE_FREESTORE_ROTATION + static constexpr size_t NUM_FREE_STORES = 2; +#else + static constexpr size_t NUM_FREE_STORES = 1; +#endif + +private: + static constexpr size_t PREV_FREE_BITS = cpp::bit_width(NUM_FREE_STORES); + static constexpr size_t PREV_FREE_MASK = (size_t{1} << PREV_FREE_BITS) - 1; + static constexpr size_t LAST_MASK = size_t{1} << PREV_FREE_BITS; static constexpr size_t SIZE_MASK = ~(PREV_FREE_MASK | LAST_MASK); // Header field offsets. The value at PREV_OFFSET is only meaningful when the @@ -112,10 +126,10 @@ class BlockRef { public: static constexpr size_t HEADER_SIZE = NEXT_OFFSET + sizeof(size_t); - // To ensure block sizes have two lower unused bits, ensure usable space is - // always aligned to at least 4 bytes. (The distances between usable spaces, - // the outer size, is then always also 4-aligned.) - static constexpr size_t MIN_ALIGN = cpp::max(size_t{4}, alignof(max_align_t)); + // The flag bits above live in the lower bits of a block's size, so the + // usable space must be aligned to the first bit they leave unused. + static constexpr size_t MIN_ALIGN = + cpp::max(LAST_MASK << 1, alignof(max_align_t)); LIBC_INLINE constexpr BlockRef() = default; LIBC_INLINE explicit constexpr BlockRef(cpp::byte *header_ptr) @@ -237,6 +251,12 @@ class BlockRef { return BlockRef(nonnull_header_ptr() - load_prev()); } + /// @returns The index of the free store owning the block immediately before + /// this one, or a negative value if that block is not free. + LIBC_INLINE int prev_free_store_index() const { + return static_cast<int>(load_next() & PREV_FREE_MASK) - 1; + } + /// @returns Whether the block is unavailable for allocation. LIBC_INLINE bool used() const { return !next() || !next().prev_free(); } @@ -247,11 +267,14 @@ class BlockRef { next_block.store_next(next_block.load_next() & ~PREV_FREE_MASK); } - /// Marks this block as free. - LIBC_INLINE void mark_free() const { + /// Marks this block as free and owned by the given free store. + LIBC_INLINE void mark_free(size_t store_index = 0) const { LIBC_ASSERT(next() && "last block is always considered used"); + LIBC_ASSERT(store_index < NUM_FREE_STORES && "invalid free store index"); BlockRef next_block = next(); - next_block.store_next(next_block.load_next() | PREV_FREE_MASK); + // Replace the free field with `store_index + 1`, as 0 encodes "in use". + next_block.store_next((next_block.load_next() & ~PREV_FREE_MASK) | + (store_index + 1)); next_block.store_prev(outer_size()); } @@ -460,9 +483,13 @@ BlockRef::BlockInfo BlockRef::allocate(BlockRef block, size_t alignment, LIBC_ASSERT(maybe_aligned_block.has_value() && "it should always be possible to split for alignment"); - if (BlockRef prev = original.prev_free()) { - // If there is a free block before this, we can merge the current one with - // the newly created one. + // If the block before the padding is free and owned by the same free store, + // the two can be merged; blocks owned by different stores must be kept + // apart. Otherwise the padding is handed back to the caller, which decides + // which store it belongs to. + BlockRef prev = original.prev_free(); + if (prev && original.prev_free_store_index() == + original.next().prev_free_store_index()) { prev.merge_next(); } else { info.prev = original; @@ -505,14 +532,20 @@ optional<BlockRef> BlockRef::split(size_t new_inner_size, return {}; bool was_free = !used(); + // The block split off below is always free. If this block is free too, both + // halves must stay in the same store to remain mergeable; if it is in use, + // the caller owns the new block and will move it to whichever store it + // wants, so any valid index will do. + size_t store_index = + was_free ? static_cast<size_t>(next().prev_free_store_index()) : 0; ByteSpan new_region = region().subspan(new_outer_size); store_next((load_next() & ~SIZE_MASK) | new_outer_size); BlockRef new_block = as_block(new_region); - new_block.mark_free(); + new_block.mark_free(store_index); if (was_free) - mark_free(); + mark_free(store_index); LIBC_ASSERT(new_block.is_usable_space_aligned(usable_space_alignment) && "usable space must have requested alignment"); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/CMakeLists.txt index 366b35bd0de3..def0fed3c30c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/CMakeLists.txt @@ -497,3 +497,71 @@ add_header_library( libc.src.__support.macros.config libc.src.__support.macros.properties.types ) + +add_header_library( + extendhfsf2 + HDRS + extendhfsf2.h + DEPENDS + libc.hdr.stdint_proxy + libc.src.__support.builtins.fpconvert_helper + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) + +add_header_library( + extendhfdf2 + HDRS + extendhfdf2.h + DEPENDS + libc.hdr.stdint_proxy + libc.src.__support.builtins.fpconvert_helper + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) + +add_header_library( + extendhftf2 + HDRS + extendhftf2.h + DEPENDS + libc.hdr.stdint_proxy + libc.include.llvm-libc-types.float128 + libc.src.__support.builtins.fpconvert_helper + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) + +add_header_library( + truncsfhf2 + HDRS + truncsfhf2.h + DEPENDS + libc.hdr.stdint_proxy + libc.src.__support.builtins.fpconvert_helper + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) + +add_header_library( + truncdfhf2 + HDRS + truncdfhf2.h + DEPENDS + libc.hdr.stdint_proxy + libc.src.__support.builtins.fpconvert_helper + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) + +add_header_library( + trunctfhf2 + HDRS + trunctfhf2.h + DEPENDS + libc.hdr.stdint_proxy + libc.include.llvm-libc-types.float128 + libc.src.__support.builtins.fpconvert_helper + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfdf2.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfdf2.h new file mode 100644 index 000000000000..65eddd46338b --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfdf2.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __extendhfdf2 implementation as +/// builtins::extendhfdf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFDF2_H +#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFDF2_H + +#include "hdr/stdint_proxy.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtins/fpconvert_helper.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace builtins { + +// Extend float16 to double; mirrors compiler-rt's __extendhfdf2. +LIBC_INLINE double extendhfdf2(uint16_t bits) { + return fpconvert_from_bits<double, fputil::FPType::IEEE754_Binary16>(bits); +} + +} // namespace builtins +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFDF2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfsf2.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfsf2.h new file mode 100644 index 000000000000..fc3636f1db31 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhfsf2.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __extendhfsf2 implementation as +/// builtins::extendhfsf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFSF2_H +#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFSF2_H + +#include "hdr/stdint_proxy.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtins/fpconvert_helper.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace builtins { + +// Extend float16 to float; mirrors compiler-rt's __extendhfsf2. +LIBC_INLINE float extendhfsf2(uint16_t bits) { + return fpconvert_from_bits<float, fputil::FPType::IEEE754_Binary16>(bits); +} + +} // namespace builtins +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFSF2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhftf2.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhftf2.h new file mode 100644 index 000000000000..01afaf1c20e7 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/extendhftf2.h @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __extendhftf2 implementation as +/// builtins::extendhftf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFTF2_H +#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFTF2_H + +#include "include/llvm-libc-types/float128.h" +#include "src/__support/macros/properties/types.h" + +#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#include "hdr/stdint_proxy.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtins/fpconvert_helper.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace builtins { + +// Extend float16 to float128; mirrors compiler-rt's __extendhftf2. +LIBC_INLINE float128 extendhftf2(uint16_t bits) { + return fpconvert_from_bits<float128, fputil::FPType::IEEE754_Binary16>(bits); +} + +} // namespace builtins +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_EXTENDHFTF2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/fpconvert_helper.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/fpconvert_helper.h index f892bc4d2a1c..c6d52b283a32 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/fpconvert_helper.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/fpconvert_helper.h @@ -17,6 +17,7 @@ #define LLVM_LIBC_SRC___SUPPORT_BUILTINS_FPCONVERT_HELPER_H #include "hdr/fenv_macros.h" +#include "hdr/stdint_proxy.h" #include "src/__support/CPP/algorithm.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" @@ -42,41 +43,100 @@ namespace builtins { // Convert the floating-point value x from From to To (extend or truncate). // Narrowing rounds to nearest, ties to even; mirrors compiler-rt __extend* / // __trunc*. -template <typename To, typename From> -LIBC_INLINE constexpr To fpconvert(From x) { - using FromBits = fputil::FPBits<From>; +namespace internal { + +// Shared conversion body. The source is named by FPType, so it needs no +// native C++ type; only the destination does. +template <typename To, fputil::FPType FromFPType> +LIBC_INLINE constexpr To +fpconvert(typename fputil::FPRep<FromFPType>::StorageType bits) { + using FromRep = fputil::FPRep<FromFPType>; using ToBits = fputil::FPBits<To>; using ToStorageType = typename ToBits::StorageType; - FromBits x_bits(x); - - if constexpr (cpp::is_same_v<To, From>) - return x; + FromRep x_bits(bits); if (x_bits.is_nan()) { - typename FromBits::StorageType x_frac = x_bits.get_mantissa(); - if constexpr (ToBits::FRACTION_LEN >= FromBits::FRACTION_LEN) { - ToStorageType to_frac = - static_cast<ToStorageType>(x_frac) - << (ToBits::FRACTION_LEN - FromBits::FRACTION_LEN); + typename FromRep::StorageType x_frac = x_bits.get_mantissa(); + if constexpr (ToBits::FRACTION_LEN >= FromRep::FRACTION_LEN) { + ToStorageType to_frac = static_cast<ToStorageType>(x_frac) + << (ToBits::FRACTION_LEN - FromRep::FRACTION_LEN); return ToBits::signaling_nan(x_bits.sign(), to_frac).get_val(); } ToStorageType to_frac = static_cast<ToStorageType>( - x_frac >> (FromBits::FRACTION_LEN - ToBits::FRACTION_LEN)); + x_frac >> (FromRep::FRACTION_LEN - ToBits::FRACTION_LEN)); return ToBits::quiet_nan(x_bits.sign(), to_frac).get_val(); } if (x_bits.is_inf()) return ToBits::inf(x_bits.sign()).get_val(); - // Zero and subnormals fall through: DyadicFloat(x) gives a zero mantissa for - // zero, which as<To>() maps back to a correctly-signed zero. + // Zero and subnormals fall through: DyadicFloat gives a zero mantissa for + // zero, which as<To>() maps back to a correctly-signed zero. Built from + // parts so no From value is materialized. constexpr size_t MAX_FRACTION_LEN = - cpp::max(ToBits::FRACTION_LEN, FromBits::FRACTION_LEN); - fputil::DyadicFloat<cpp::bit_ceil(MAX_FRACTION_LEN)> xd(x); + cpp::max(ToBits::FRACTION_LEN, FromRep::FRACTION_LEN); + using DyadicType = fputil::DyadicFloat<cpp::bit_ceil(MAX_FRACTION_LEN)>; + DyadicType xd( + x_bits.sign(), x_bits.get_explicit_exponent() - FromRep::FRACTION_LEN, + typename DyadicType::MantissaType(x_bits.get_explicit_mantissa())); return xd.template as<To, /*ShouldSignalExceptions=*/true>(); } +} // namespace internal + +// Convert a floating-point value from From to To (extend or truncate). +template <typename To, typename From> +LIBC_INLINE constexpr To fpconvert(From x) { + if constexpr (cpp::is_same_v<To, From>) + return x; + else + return internal::fpconvert<To, fputil::get_fp_type<From>()>( + cpp::bit_cast<typename fputil::FPBits<From>::StorageType>(x)); +} + +// Same, for a source delivered as raw bits. Keeps _Float16 out of the +// signature, which would otherwise lower to a circular __extendhfsf2. +template <typename To, fputil::FPType FromFPType> +LIBC_INLINE constexpr To +fpconvert_from_bits(typename fputil::FPRep<FromFPType>::StorageType bits) { + return internal::fpconvert<To, FromFPType>(bits); +} + +// Same, for a destination delivered as raw bits. Keeps _Float16 out of the +// signature, which would otherwise lower to a circular __trunc*hf2. +template <fputil::FPType ToFPType, typename From> +LIBC_INLINE constexpr typename fputil::FPRep<ToFPType>::StorageType +fpconvert_to_bits(From x) { + using ToRep = fputil::FPRep<ToFPType>; + using ToStorageType = typename ToRep::StorageType; + using FromBits = fputil::FPBits<From>; + + FromBits x_bits(x); + + if (x_bits.is_nan()) { + typename FromBits::StorageType x_frac = x_bits.get_mantissa(); + if constexpr (ToRep::FRACTION_LEN >= FromBits::FRACTION_LEN) { + ToStorageType to_frac = static_cast<ToStorageType>(x_frac) + << (ToRep::FRACTION_LEN - FromBits::FRACTION_LEN); + return ToRep::signaling_nan(x_bits.sign(), to_frac).uintval(); + } else { + ToStorageType to_frac = static_cast<ToStorageType>( + x_frac >> (FromBits::FRACTION_LEN - ToRep::FRACTION_LEN)); + return ToRep::quiet_nan(x_bits.sign(), to_frac).uintval(); + } + } + + if (x_bits.is_inf()) + return ToRep::inf(x_bits.sign()).uintval(); + + constexpr size_t MAX_FRACTION_LEN = + cpp::max(ToRep::FRACTION_LEN, FromBits::FRACTION_LEN); + fputil::DyadicFloat<cpp::bit_ceil(MAX_FRACTION_LEN)> xd(x); + return xd.template generic_as_bits<ToFPType, + /*ShouldSignalExceptions=*/true>(); +} + } // namespace builtins } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncdfhf2.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncdfhf2.h new file mode 100644 index 000000000000..cdadeef1d87a --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncdfhf2.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __truncdfhf2 implementation as +/// builtins::truncdfhf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCDFHF2_H +#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCDFHF2_H + +#include "hdr/stdint_proxy.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtins/fpconvert_helper.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace builtins { + +// Truncate double to float16; mirrors compiler-rt's __truncdfhf2. +LIBC_INLINE uint16_t truncdfhf2(double x) { + return fpconvert_to_bits<fputil::FPType::IEEE754_Binary16>(x); +} + +} // namespace builtins +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCDFHF2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncsfhf2.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncsfhf2.h new file mode 100644 index 000000000000..72419452fbf3 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/truncsfhf2.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __truncsfhf2 implementation as +/// builtins::truncsfhf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCSFHF2_H +#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCSFHF2_H + +#include "hdr/stdint_proxy.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtins/fpconvert_helper.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace builtins { + +// Truncate float to float16; mirrors compiler-rt's __truncsfhf2. +LIBC_INLINE uint16_t truncsfhf2(float x) { + return fpconvert_to_bits<fputil::FPType::IEEE754_Binary16>(x); +} + +} // namespace builtins +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCSFHF2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/builtins/trunctfhf2.h b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/trunctfhf2.h new file mode 100644 index 000000000000..94869000255d --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/builtins/trunctfhf2.h @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This header exposes LLVM-libc's __trunctfhf2 implementation as +/// builtins::trunctfhf2 so that it can be reused by compiler-rt's builtins. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCTFHF2_H +#define LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCTFHF2_H + +#include "include/llvm-libc-types/float128.h" +#include "src/__support/macros/properties/types.h" + +#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#include "hdr/stdint_proxy.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/builtins/fpconvert_helper.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace builtins { + +// Truncate float128 to float16; mirrors compiler-rt's __trunctfhf2. +LIBC_INLINE uint16_t trunctfhf2(float128 x) { + return fpconvert_to_bits<fputil::FPType::IEEE754_Binary16>(x); +} + +} // namespace builtins +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_BUILTINS_TRUNCTFHF2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/frac64.h b/deps/v8/third_party/llvm-libc/src/src/__support/frac64.h index 350b0a8b701b..14fd5999f119 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/frac64.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/frac64.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the declaration of 64-bit unsigned fractional type +/// This file contains the declaration of 64-bit unsigned fractional type. /// //===----------------------------------------------------------------------===// @@ -15,6 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_FRAC64_H #include "src/__support/big_int.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -22,41 +23,44 @@ namespace LIBC_NAMESPACE_DECL { struct Frac64 : public UInt<64> { using UInt<64>::UInt; - LIBC_INLINE constexpr Frac64 operator~() const { return Frac64(~val[0]); } + LIBC_ALWAYS_INLINE constexpr Frac64 operator~() const { + return Frac64(~val[0]); + } - LIBC_INLINE constexpr Frac64 operator+(Frac64 other) const { + LIBC_ALWAYS_INLINE constexpr Frac64 operator+(Frac64 other) const { return Frac64(val[0] + other.val[0]); } - LIBC_INLINE constexpr Frac64 operator-(Frac64 other) const { + LIBC_ALWAYS_INLINE constexpr Frac64 operator-(Frac64 other) const { return Frac64(val[0] - other.val[0]); } - LIBC_INLINE constexpr Frac64 operator*(Frac64 other) const { - UInt<64> r = UInt<64>::quick_mul_hi(UInt<64>(other)); - return Frac64(r.val[0]); + // Fast hi part of the 128-bit product: + // 0 <= ((a * b) >> 64) - (Frac64(a) * Frac64(b)).val[0] <= 1. + LIBC_ALWAYS_INLINE constexpr Frac64 operator*(Frac64 other) const { + return Frac64(UInt<64>::quick_mul_hi(other).val); } - LIBC_INLINE constexpr Frac64 &operator+=(Frac64 other) { + LIBC_ALWAYS_INLINE constexpr Frac64 &operator+=(Frac64 other) { *this = *this + other; return *this; } - LIBC_INLINE constexpr Frac64 &operator-=(Frac64 other) { + LIBC_ALWAYS_INLINE constexpr Frac64 &operator-=(Frac64 other) { *this = *this - other; return *this; } - LIBC_INLINE constexpr Frac64 &operator*=(Frac64 other) { + LIBC_ALWAYS_INLINE constexpr Frac64 &operator*=(Frac64 other) { *this = *this * other; return *this; } - LIBC_INLINE constexpr Frac64 operator<<(size_t s) const { + LIBC_ALWAYS_INLINE constexpr Frac64 operator<<(size_t s) const { return Frac64(val[0] << s); } - LIBC_INLINE constexpr Frac64 operator>>(size_t s) const { + LIBC_ALWAYS_INLINE constexpr Frac64 operator>>(size_t s) const { return Frac64(val[0] >> s); } }; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/freelist_heap.h b/deps/v8/third_party/llvm-libc/src/src/__support/freelist_heap.h index d2ec9339d72e..74c13332486c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/freelist_heap.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/freelist_heap.h @@ -38,6 +38,21 @@ LIBC_INLINE constexpr bool IsPow2(size_t x) { return x && (x & (x - 1)) == 0; } class FreeListHeap { public: + /// The heap keeps its free blocks in NUM_FREE_STORES stores and rotates + /// between them: allocations are served from the active store, while frees + /// go to the next one, quarantining the memory there. Only once the active + /// store cannot satisfy a request does rotate() make the quarantined memory + /// available again. Delaying reuse this way makes use-after-free bugs much + /// more likely to be caught, e.g. by a sanitizer. + /// + /// A request the active store cannot serve thus ends the quarantine period + /// early, whether or not it succeeds afterwards. + /// + /// With a single store (the default) the quarantine store is the active + /// store, no rotation ever happens, and this degenerates into the usual + /// immediate-reuse behavior. + static constexpr size_t NUM_FREE_STORES = BlockRef::NUM_FREE_STORES; + constexpr FreeListHeap() : begin(&_end), end(&__llvm_libc_heap_limit) {} constexpr FreeListHeap(span<cpp::byte> region) @@ -51,7 +66,10 @@ class FreeListHeap { void *realloc(void *ptr, size_t size); void *calloc(size_t num, size_t size); size_t allocation_size(const void *ptr) const; - LIBC_INLINE void integrity_check() const { free_store.integrity_check(); } + LIBC_INLINE void integrity_check() const { + for (const FreeStore &store : free_stores) + store.integrity_check(); + } cpp::span<cpp::byte> region() const { return {begin, end}; } @@ -68,15 +86,80 @@ class FreeListHeap { bool is_valid_ptr(const void *ptr) const { return ptr >= begin && ptr < end; } + /// The store that allocations are served from. + LIBC_INLINE FreeStore &active_free_store() { return free_stores[active]; } + + /// @returns The index of the store that receives newly freed blocks. With a + /// single free store this is the active store itself, so freed memory is + /// immediately available again. + LIBC_INLINE size_t quarantine_store_index() const { + return (active + 1) % NUM_FREE_STORES; + } + + /// Whether the free block `neighbor` can be merged into a block owned by + /// `store_index`. Merging across stores would hand quarantined memory back + /// out through the active store, so only blocks of the same store merge, + /// plus blocks too small for any store to track (see FreeStore::too_small), + /// which are owned by no store. + LIBC_INLINE static bool can_merge(BlockRef neighbor, size_t store_index) { + return FreeStore::too_small(neighbor) || + neighbor.next().prev_free_store_index() == + static_cast<int>(store_index); + } + + /// Inserts `block` into store `store_index`, coalescing it with the + /// neighbors that can be merged into that store. The block may be in use or + /// free in another store. + LIBC_INLINE void insert(BlockRef block, size_t store_index) { + block.mark_free(store_index); + + // Absorbing an untracked neighbor may expose another mergeable one beyond + // it, so keep going. + for (BlockRef prev = block.prev_free(); + prev && can_merge(prev, store_index); prev = block.prev_free()) { + free_stores[store_index].remove(prev); + block = prev; + block.merge_next(); + } + + for (BlockRef next = block.next(); + !next.used() && can_merge(next, store_index); next = block.next()) { + free_stores[store_index].remove(next); + block.merge_next(); + } + + // Merging moved the block boundaries, and an absorbed block may have been + // owned by another store, so record the ownership of the result again. + block.mark_free(store_index); + free_stores[store_index].insert(block); + } + + /// Ends the current quarantine period: the store that has been collecting + /// freed blocks becomes the active one, and whatever is left in the + /// previously active store is migrated (and coalesced) into it, so that the + /// newly active store holds all the free memory of the heap. Returns false + /// without doing anything if nothing is quarantined. + LIBC_INLINE bool rotate() { + if (NUM_FREE_STORES < 2 || free_stores[quarantine_store_index()].empty()) + return false; + + size_t prev_active = active; + active = quarantine_store_index(); + while (BlockRef block = free_stores[prev_active].remove_any()) + insert(block, active); + return true; + } + cpp::byte *begin; cpp::byte *end; bool is_initialized = false; - FreeStore free_store; + FreeStore free_stores[NUM_FREE_STORES]; + size_t active = 0; }; template <size_t BUFF_SIZE> class FreeListHeapBuffer : public FreeListHeap { public: - constexpr FreeListHeapBuffer() : FreeListHeap{buffer}, buffer{} {} + LIBC_INLINE constexpr FreeListHeapBuffer() : FreeListHeap{buffer}, buffer{} {} private: cpp::byte buffer[BUFF_SIZE]; @@ -86,8 +169,9 @@ LIBC_INLINE void FreeListHeap::init() { LIBC_ASSERT(!is_initialized && "duplicate initialization"); auto result = BlockRef::init(region()); BlockRef block = *result; - free_store.set_range({0, cpp::bit_ceil(block.inner_size())}); - free_store.insert(block); + for (FreeStore &store : free_stores) + store.set_range({0, cpp::bit_ceil(block.inner_size())}); + free_stores[active].insert(block); is_initialized = true; } @@ -99,20 +183,26 @@ LIBC_INLINE void *FreeListHeap::allocate_impl(size_t alignment, size_t size) { init(); size_t request_size = BlockRef::min_size_for_allocation(alignment, size); - if (!request_size) + // Don't disturb the quarantine for a request the heap could never serve. + if (!request_size || request_size > region().size()) return nullptr; - BlockRef block = free_store.remove_best_fit(request_size); + BlockRef block = active_free_store().remove_best_fit(request_size); + // The active store is out of memory; make the quarantined blocks available + // again and retry. + if (!block && rotate()) + block = active_free_store().remove_best_fit(request_size); if (!block) return nullptr; auto block_info = BlockRef::allocate(block, alignment, size); + block_info.block.mark_used(); + // The leftovers of the block were never handed out, so they stay in the + // active store rather than being quarantined. if (block_info.next) - free_store.insert(block_info.next); + insert(block_info.next, active); if (block_info.prev) - free_store.insert(block_info.prev); - - block_info.block.mark_used(); + insert(block_info.prev, active); return block_info.block.usable_space(); } @@ -147,24 +237,7 @@ LIBC_INLINE void FreeListHeap::free(void *ptr) { BlockRef block = BlockRef::from_usable_space(bytes); LIBC_ASSERT(block.next() && "sentinel last block cannot be freed"); LIBC_ASSERT(block.used() && "double free"); - block.mark_free(); - - // Can we combine with the left or right blocks? - BlockRef prev_free = block.prev_free(); - BlockRef next = block.next(); - - if (prev_free) { - // Remove from free store and merge. - free_store.remove(prev_free); - block = prev_free; - block.merge_next(); - } - if (!next.used()) { - free_store.remove(next); - block.merge_next(); - } - // Add back to the freelist - free_store.insert(block); + insert(block, quarantine_store_index()); } LIBC_INLINE size_t FreeListHeap::allocation_size(const void *ptr) const { @@ -186,17 +259,13 @@ LIBC_INLINE bool FreeListHeap::shrink_in_place(BlockRef block, size_t size) { // register the new block on successful split if (next.has_value()) { BlockRef next_block = *next; - BlockRef right = next_block.next(); // Since the original block was not the last block (the sentinel last // block is never split), the split-off remainder block `next_block` is - // also not the last block. Thus, its next block `right` is guaranteed - // to be non-null. - LIBC_ASSERT(right && "right block must be non-null"); - if (!right.used()) { - free_store.remove(right); - next_block.merge_next(); - } - free_store.insert(next_block); + // also not the last block. Thus, its next block is guaranteed to be + // non-null. + LIBC_ASSERT(next_block.next() && "right block must be non-null"); + // The remainder is memory the caller has given up, so quarantine it. + insert(next_block, quarantine_store_index()); } return true; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/freestore.h b/deps/v8/third_party/llvm-libc/src/src/__support/freestore.h index ccc4f9555c64..59e0de2380c1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/freestore.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/freestore.h @@ -73,6 +73,44 @@ template <typename CONFIG> class TLSFFreeStoreImpl { list.integrity_check(); } + /// Removes and returns any block from the store. + /// @returns The block removed, or BlockRef() if empty. + LIBC_INLINE BlockRef remove_any() { + for (size_t i = 0; i < TOTAL_BITS - 1; ++i) { + if (!free_lists[i].empty()) { + BlockRef block = free_lists[i].front(); + free_lists[i].pop(); + if (free_lists[i].empty()) + free_sizes.mark_vacant(i); + return block; + } + } + if constexpr (USE_TRIE) { + if (BlockRef block = trie.pop_any()) { + if (trie.empty()) + free_sizes.mark_vacant(TOTAL_BITS - 1); + return block; + } + } else { + if (!overflow_list.empty()) { + BlockRef block = overflow_list.front(); + overflow_list.pop(); + if (overflow_list.empty()) + free_sizes.mark_vacant(TOTAL_BITS - 1); + return block; + } + } + return BlockRef(); + } + + /// Whether `block` is too small to hold a free list node. insert() and + /// remove() ignore such blocks, so they are owned by no store. + LIBC_INLINE static bool too_small(BlockRef block) { + return block.outer_size() < MIN_OUTER_SIZE; + } + + LIBC_INLINE bool empty() const { return free_sizes.empty(); } + private: LIBC_INLINE constexpr TLSFFreeStoreImpl(cpp::bool_constant<true>) : trie() {} LIBC_INLINE constexpr TLSFFreeStoreImpl(cpp::bool_constant<false>) @@ -100,10 +138,6 @@ template <typename CONFIG> class TLSFFreeStoreImpl { } protected: - LIBC_INLINE static bool too_small(BlockRef block) { - return block.outer_size() < MIN_OUTER_SIZE; - } - Table free_sizes; cpp::array<FreeList, TOTAL_BITS - 1> free_lists; union { diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.cpp index d0392342f223..f15664db2f12 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.cpp @@ -79,4 +79,12 @@ void FreeTrie::integrity_check() const { integrity_check_trie_node(integrity_check_trie_node, root()); } +BlockRef FreeTrie::pop_any() { + if (!root_) + return BlockRef(); + Node *node = root_; + remove(node); + return node->block(); +} + } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.h b/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.h index 1be34f456021..bdb115eeb184 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/freetrie.h @@ -132,6 +132,10 @@ class FreeTrie { /// Verify integrity of all nodes in the trie. void integrity_check() const; + /// Removes and returns any block from the trie. + /// @returns The block removed, or BlockRef() if empty. + BlockRef pop_any(); + private: /// @returns Whether a node is the head of its containing freelist. bool is_head(Node *node) const { return node->parent || node == root_; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/integer_to_string.h b/deps/v8/third_party/llvm-libc/src/src/__support/integer_to_string.h index 5e7369de0096..f392fa65ac77 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/integer_to_string.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/integer_to_string.h @@ -70,6 +70,7 @@ #include "src/__support/common.h" #include "src/__support/ctype_utils.h" #include "src/__support/macros/config.h" +#include "src/__support/wctype_utils.h" namespace LIBC_NAMESPACE_DECL { @@ -82,7 +83,7 @@ struct Fmt { static constexpr size_t MIN_DIGITS = min_digits; static constexpr bool IS_UPPERCASE = is_uppercase; static constexpr bool PREFIX = prefix; - static constexpr char FORCE_SIGN = force_sign; + static constexpr bool FORCE_SIGN = force_sign; using WithPrefix = Fmt<BASE, true, FORCE_SIGN, IS_UPPERCASE, MIN_DIGITS>; using WithSign = Fmt<BASE, PREFIX, true, IS_UPPERCASE, MIN_DIGITS>; @@ -101,56 +102,34 @@ struct Fmt { "WithPrefix is only for radix == 2, 8 or 16"); }; -// Move this to a separate header since it might be useful elsewhere. -template <bool forward> class StringBufferWriterImpl { - cpp::span<char> buffer; - size_t index = 0; +template <typename CharT> class BackwardStringBufferWriter { + cpp::span<CharT> buffer; + size_t remaining = 0; bool out_of_range = false; - LIBC_INLINE size_t location() const { - return forward ? index : buffer.size() - 1 - index; - } - public: - StringBufferWriterImpl(const StringBufferWriterImpl &) = delete; - StringBufferWriterImpl(cpp::span<char> buffer) : buffer(buffer) {} + BackwardStringBufferWriter(cpp::span<CharT> buffer) + : buffer(buffer), remaining(buffer.size()) {} - LIBC_INLINE size_t size() const { return index; } - LIBC_INLINE size_t remainder_size() const { return buffer.size() - size(); } - LIBC_INLINE bool empty() const { return size() == 0; } - LIBC_INLINE bool full() const { return size() == buffer.size(); } + LIBC_INLINE size_t size() const { return buffer.size() - remaining; } + LIBC_INLINE bool full() const { return remaining == 0; } LIBC_INLINE bool ok() const { return !out_of_range; } - LIBC_INLINE StringBufferWriterImpl &push(char c) { - if (ok()) { - if (!full()) { - buffer[location()] = c; - ++index; - } else { - out_of_range = true; - } + LIBC_INLINE void push(CharT c) { + if (remaining == 0) { + out_of_range = true; + return; } - return *this; + --remaining; + buffer[remaining] = c; } - LIBC_INLINE cpp::span<char> remainder_span() const { - return forward ? buffer.last(remainder_size()) - : buffer.first(remainder_size()); - } - - LIBC_INLINE cpp::span<char> buffer_span() const { - return forward ? buffer.first(size()) : buffer.last(size()); - } - - LIBC_INLINE cpp::string_view buffer_view() const { - const auto s = buffer_span(); + LIBC_INLINE cpp::basic_string_view<CharT> buffer_view() const { + cpp::span<CharT> s = buffer.last(size()); return {s.data(), s.size()}; } }; -using StringBufferWriter = StringBufferWriterImpl<true>; -using BackwardStringBufferWriter = StringBufferWriterImpl<false>; - } // namespace details namespace radix { @@ -328,8 +307,10 @@ extract_decimal_digit(T &value) { } // See file header for documentation. -template <typename T, typename Fmt = radix::Dec> class IntegerToString { +template <typename T, typename Fmt = radix::Dec, typename CharT = char> +class IntegerToString { static_assert(cpp::is_integral_v<T> || is_big_int_v<T>); + static_assert(cpp::is_same_v<CharT, char> || cpp::is_same_v<CharT, wchar_t>); LIBC_INLINE static constexpr size_t compute_buffer_size() { constexpr auto MAX_DIGITS = []() -> size_t { @@ -377,23 +358,26 @@ template <typename T, typename Fmt = radix::Dec> class IntegerToString { static_assert(cpp::is_integral_v<T> || is_big_int_v<T>); using UNSIGNED_T = make_integral_or_big_int_unsigned_t<T>; - LIBC_INLINE static char digit_char(uint8_t digit) { - const char result = internal::int_to_b36_char(digit); - return Fmt::IS_UPPERCASE ? internal::toupper(result) : result; + LIBC_INLINE static CharT digit_char(uint8_t digit) { + const CharT result = internal::int_to_b36_char(digit); + if constexpr (Fmt::BASE <= 10) { + return result; + } else { + return Fmt::IS_UPPERCASE ? internal::toupper(result) : result; + } } LIBC_INLINE static void write_unsigned_number(UNSIGNED_T value, - details::BackwardStringBufferWriter &sink) { + details::BackwardStringBufferWriter<CharT> &sink) { for (; sink.ok() && value != 0; value /= Fmt::BASE) { const uint8_t digit(static_cast<uint8_t>(value % Fmt::BASE)); sink.push(digit_char(digit)); } } - LIBC_INLINE static void - write_unsigned_number_dec(UNSIGNED_T value, - details::BackwardStringBufferWriter &sink) { + LIBC_INLINE static void write_unsigned_number_dec( + UNSIGNED_T value, details::BackwardStringBufferWriter<CharT> &sink) { while (sink.ok() && value != 0) { const uint8_t digit = extract_decimal_digit(value); sink.push(digit_char(digit)); @@ -425,8 +409,8 @@ template <typename T, typename Fmt = radix::Dec> class IntegerToString { } } - LIBC_INLINE static void write(T value, - details::BackwardStringBufferWriter &sink) { + LIBC_INLINE static void + write(T value, details::BackwardStringBufferWriter<CharT> &sink) { if constexpr (Fmt::BASE == 10) { write_unsigned_number_dec(abs(value), sink); } else { @@ -434,60 +418,61 @@ template <typename T, typename Fmt = radix::Dec> class IntegerToString { } // width while (sink.ok() && sink.size() < Fmt::MIN_DIGITS) - sink.push('0'); + sink.push(CharT{'0'}); // sign if constexpr (Fmt::BASE == 10) { if (value < 0) - sink.push('-'); + sink.push(CharT{'-'}); else if (Fmt::FORCE_SIGN) - sink.push('+'); + sink.push(CharT{'+'}); } // prefix if constexpr (Fmt::PREFIX) { if constexpr (Fmt::BASE == 2) { - sink.push('b'); - sink.push('0'); + sink.push(CharT{'b'}); + sink.push(CharT{'0'}); } if constexpr (Fmt::BASE == 16) { - sink.push('x'); - sink.push('0'); + sink.push(CharT{'x'}); + sink.push(CharT{'0'}); } if constexpr (Fmt::BASE == 8) { - const cpp::string_view written = sink.buffer_view(); - if (written.empty() || written.front() != '0') - sink.push('0'); + const cpp::basic_string_view<CharT> written = sink.buffer_view(); + if (written.empty() || written.front() != CharT{'0'}) + sink.push(CharT{'0'}); } } } }; - cpp::array<char, BUFFER_SIZE> array; + cpp::array<CharT, BUFFER_SIZE> array; size_t written = 0; public: IntegerToString(const IntegerToString &) = delete; IntegerToString(T value) { - details::BackwardStringBufferWriter writer(array); + details::BackwardStringBufferWriter<CharT> writer(array); IntegerWriter::write(value, writer); written = writer.size(); } - [[nodiscard]] LIBC_INLINE static cpp::optional<cpp::string_view> - format_to(cpp::span<char> buffer, T value) { - details::BackwardStringBufferWriter writer(buffer); + [[nodiscard]] LIBC_INLINE static cpp::optional<cpp::basic_string_view<CharT>> + format_to(cpp::span<CharT> buffer, T value) { + details::BackwardStringBufferWriter<CharT> writer(buffer); IntegerWriter::write(value, writer); if (writer.ok()) - return cpp::string_view(buffer.data() + buffer.size() - writer.size(), - writer.size()); + return cpp::basic_string_view<CharT>( + buffer.data() + buffer.size() - writer.size(), writer.size()); return cpp::nullopt; } LIBC_INLINE static constexpr size_t buffer_size() { return BUFFER_SIZE; } LIBC_INLINE size_t size() const { return written; } - LIBC_INLINE cpp::string_view view() && = delete; - LIBC_INLINE cpp::string_view view() const & { - return cpp::string_view(array.data() + array.size() - size(), size()); + LIBC_INLINE cpp::basic_string_view<CharT> view() && = delete; + LIBC_INLINE cpp::basic_string_view<CharT> view() const & { + return cpp::basic_string_view<CharT>(array.data() + array.size() - size(), + size()); } }; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/macros/CMakeLists.txt index c9afc2829dbc..c600b453af51 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/CMakeLists.txt @@ -60,4 +60,3 @@ add_header_library( HDRS hardening.h ) - diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/attributes.h b/deps/v8/third_party/llvm-libc/src/src/__support/macros/attributes.h index 1e8ebc13fea9..6e6e359ae4c1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/attributes.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/attributes.h @@ -24,10 +24,20 @@ #define __has_attribute(x) 0 #endif +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + #define LIBC_INLINE inline #define LIBC_INLINE_VAR inline #define LIBC_INLINE_ASM __asm__ __volatile__ -#define LIBC_UNUSED __attribute__((unused)) +#define LIBC_UNUSED [[maybe_unused]] + +#if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__linux__) +#define LIBC_VECTOR_PCS __attribute__((aarch64_vector_pcs)) +#else +#define LIBC_VECTOR_PCS +#endif #if __has_attribute(always_inline) #define LIBC_ALWAYS_INLINE LIBC_INLINE __attribute__((always_inline)) @@ -37,6 +47,32 @@ #define LIBC_ALWAYS_INLINE LIBC_INLINE #endif // __has_attribute(always_inline) +#if __has_attribute(noinline) +#define LIBC_NOINLINE __attribute__((noinline)) +#elif defined(LIBC_COMPILER_IS_MSVC) || defined(_MSC_VER) +#define LIBC_NOINLINE __declspec(noinline) +#else +#define LIBC_NOINLINE +#endif // __has_attribute(noinline) + +#if __has_attribute(cold) +#define LIBC_COLD __attribute__((cold)) +#else +#define LIBC_COLD +#endif // __has_attribute(cold) + +#if __has_attribute(flatten) +#define LIBC_FLATTEN __attribute__((flatten)) +#else +#define LIBC_FLATTEN +#endif // __has_attribute(flatten) + +#if __has_attribute(may_alias) +#define LIBC_MAY_ALIAS __attribute__((may_alias)) +#else +#define LIBC_MAY_ALIAS +#endif // __has_attribute(may_alias) + #ifndef LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED #if (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 900)) || \ (defined(LIBC_COMPILER_IS_CLANG) && LIBC_COMPILER_CLANG_VER >= 900) @@ -156,6 +192,18 @@ LIBC_THREAD_MODE_EXTERNAL. #define LIBC_PREFERED_TYPE(TYPE) #endif +#if __has_cpp_attribute(no_unique_address) +#define LIBC_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else +#define LIBC_NO_UNIQUE_ADDRESS +#endif + +#if __has_attribute(trivial_abi) +#define LIBC_TRIVIAL_ABI [[clang::trivial_abi]] +#else +#define LIBC_TRIVIAL_ABI +#endif + #if __has_attribute(ext_vector_type) && \ LIBC_HAS_FEATURE(ext_vector_type_boolean) #define LIBC_HAS_VECTOR_TYPE 1 diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/optimization.h b/deps/v8/third_party/llvm-libc/src/src/__support/macros/optimization.h index 51091b6d4640..3d4b830ae5c5 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/optimization.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/optimization.h @@ -16,17 +16,24 @@ // We use a template to implement likely/unlikely to make sure that we don't // accidentally pass an integer. +// Note that `__builtin_expect` requires the second argument to be a constant +// expression. namespace LIBC_NAMESPACE_DECL { namespace details { template <typename T> -LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { - return __builtin_expect(value, expected); +LIBC_ALWAYS_INLINE constexpr bool expects_bool_condition(T value) = delete; + +template <> +LIBC_ALWAYS_INLINE constexpr bool expects_bool_condition<bool>(bool value) { + return value; } } // namespace details } // namespace LIBC_NAMESPACE_DECL -#define LIBC_LIKELY(x) LIBC_NAMESPACE::details::expects_bool_condition(x, true) +#define LIBC_LIKELY(x) \ + (__builtin_expect(LIBC_NAMESPACE::details::expects_bool_condition((x)), true)) #define LIBC_UNLIKELY(x) \ - LIBC_NAMESPACE::details::expects_bool_condition(x, false) + (__builtin_expect(LIBC_NAMESPACE::details::expects_bool_condition((x)), \ + false)) #if defined(LIBC_COMPILER_IS_CLANG) #define LIBC_LOOP_NOUNROLL _Pragma("nounroll") @@ -69,6 +76,9 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #if ((LIBC_MATH) & LIBC_MATH_SMALL_TABLES) #define LIBC_MATH_HAS_SMALL_TABLES +#define LIBC_MATH_SMALL_TABLES_INLINE LIBC_NOINLINE LIBC_INLINE +#else +#define LIBC_MATH_SMALL_TABLES_INLINE LIBC_ALWAYS_INLINE #endif #if ((LIBC_MATH) & LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/architectures.h b/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/architectures.h index f73fa7a7643a..c1c425067ddd 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/architectures.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/architectures.h @@ -70,4 +70,8 @@ #define LIBC_TARGET_ARCH_IS_ANY_RISCV #endif +#if defined(__hexagon__) +#define LIBC_TARGET_ARCH_IS_HEXAGON +#endif + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_ARCHITECTURES_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/compiler.h b/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/compiler.h index 592f6c2ba1c9..ddea49ebbaa5 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/compiler.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/compiler.h @@ -40,7 +40,7 @@ #define LIBC_COMPILER_MSVC_VER (_MSC_VER) #ifdef _M_X64 #define LIBC_COMPILER_IS_MSVC_X64 -#else +#elif defined(_M_IX86) #define LIBC_COMPILER_IS_MSVC_X86 #endif #endif diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/cpu_features.h b/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/cpu_features.h index 77daeb7c1fcc..f22a61ec70c9 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/cpu_features.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/properties/cpu_features.h @@ -13,6 +13,7 @@ #define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CPU_FEATURES_H #include "architectures.h" +#include "compiler.h" #if defined(__ARM_FEATURE_FP16_SCALAR_ARITHMETIC) #define LIBC_TARGET_CPU_HAS_FULLFP16 @@ -40,22 +41,27 @@ #define LIBC_TARGET_CPU_HAS_MOPS #endif -#if defined(__SSE2__) +#if defined(__SSE2__) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP >= 2) #define LIBC_TARGET_CPU_HAS_SSE2 #define LIBC_TARGET_CPU_HAS_FPU_FLOAT #define LIBC_TARGET_CPU_HAS_FPU_DOUBLE +#if defined(__SSE2__) #define LIBC_TARGET_CPU_GENERIC_VECTOR_SIZE_MAX 128 #endif +#endif -#if defined(__SSE4_2__) +#if defined(__SSE4_2__) || defined(__AVX__) #define LIBC_TARGET_CPU_HAS_SSE4_2 #endif #if defined(__AVX__) #define LIBC_TARGET_CPU_HAS_AVX +#ifndef LIBC_COMPILER_IS_MSVC #undef LIBC_TARGET_CPU_GENERIC_VECTOR_SIZE_MAX #define LIBC_TARGET_CPU_GENERIC_VECTOR_SIZE_MAX 256 #endif +#endif #if defined(__AVX2__) #define LIBC_TARGET_CPU_HAS_AVX2 @@ -63,9 +69,11 @@ #if defined(__AVX512F__) #define LIBC_TARGET_CPU_HAS_AVX512F +#ifndef LIBC_COMPILER_IS_MSVC #undef LIBC_TARGET_CPU_GENERIC_VECTOR_SIZE_MAX #define LIBC_TARGET_CPU_GENERIC_VECTOR_SIZE_MAX 512 #endif +#endif #if defined(__AVX512BW__) #define LIBC_TARGET_CPU_HAS_AVX512BW @@ -88,12 +96,19 @@ #define LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE #define LIBC_TARGET_CPU_HAS_FPU_DOUBLE #endif // LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE +#elif defined(_M_ARM64) || defined(_M_ARM64EC) +#define LIBC_TARGET_CPU_HAS_ARM_FPU_FLOAT +#define LIBC_TARGET_CPU_HAS_FPU_FLOAT +#define LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE +#define LIBC_TARGET_CPU_HAS_FPU_DOUBLE #endif // __ARM_FP -#if defined(__ARM_NEON) +#if defined(__ARM_NEON) || defined(_M_ARM64) || defined(_M_ARM64EC) #define LIBC_TARGET_CPU_HAS_ARM_NEON +#if defined(__ARM_NEON) #define LIBC_TARGET_CPU_GENERIC_VECTOR_SIZE_MAX 512 #endif +#endif #if defined(__riscv_flen) // https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/src/c-api.adoc @@ -120,7 +135,9 @@ #define LIBC_TARGET_CPU_HAS_FPU_DOUBLE #endif -#if defined(__ARM_FEATURE_FMA) || (defined(__AVX2__) && defined(__FMA__)) || \ +#if defined(__ARM_FEATURE_FMA) || defined(_M_ARM64) || defined(_M_ARM64EC) || \ + (defined(__AVX2__) && defined(__FMA__)) || \ + (defined(LIBC_COMPILER_IS_MSVC) && defined(__AVX2__)) || \ defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen) || \ defined(__SPIRV__) #define LIBC_TARGET_CPU_HAS_FMA diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/macros/sanitizer.h b/deps/v8/third_party/llvm-libc/src/src/__support/macros/sanitizer.h index abed7a20a35b..f92088ac245f 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/macros/sanitizer.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/macros/sanitizer.h @@ -32,7 +32,11 @@ __msan_unpoison(addr, size); \ } while (0) #else -#define LIBC_MSAN_UNPOISON(ptr, size) +#define LIBC_MSAN_UNPOISON(ptr, size) \ + do { \ + (void)(ptr); \ + (void)(size); \ + } while (0) #endif #ifdef LIBC_HAS_ADDRESS_SANITIZER diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/math/CMakeLists.txt index 8d6a1495e1c1..400e5e2d6aea 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/CMakeLists.txt @@ -2181,10 +2181,10 @@ add_header_library( HDRS nanf128.h DEPENDS - libc.include.llvm-libc-types.float128 + libc.src.__support.FPUtil.float128 + libc.src.__support.libc_errno libc.src.__support.macros.config libc.src.__support.str_to_float - libc.src.__support.libc_errno ) add_header_library( @@ -2826,9 +2826,9 @@ add_header_library( ) add_header_library( - cosf + cosf_double_eval HDRS - cosf.h + cosf_double_eval.h DEPENDS .sincosf_utils libc.src.__support.FPUtil.basic_operations @@ -2840,6 +2840,33 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + cosf_float_eval + HDRS + cosf_float_eval.h + DEPENDS + .sincosf_utils + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( + cosf + HDRS + cosf.h + DEPENDS + .cosf_double_eval + .cosf_float_eval + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + add_header_library( cosf16 HDRS @@ -3078,10 +3105,26 @@ add_header_library( DEPENDS libc.src.__support.CPP.bit libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval libc.src.__support.macros.config libc.src.__support.macros.optimization ) +add_header_library( + exp2f_integer_utils + HDRS + exp2f_integer_utils.h + DEPENDS + libc.hdr.fenv_macros + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.frac64 + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types +) + add_header_library( expf_double_eval HDRS @@ -3097,6 +3140,20 @@ add_header_library( libc.src.__support.common libc.src.__support.macros.config libc.src.__support.macros.optimization + libc.src.__support.math.check.exp_exceptions +) + +add_header_library( + expf_float_utils + HDRS + expf_float_utils.h + DEPENDS + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.common + libc.src.__support.macros.config ) add_header_library( @@ -3105,6 +3162,7 @@ add_header_library( expf_float_eval.h DEPENDS .exp2f_float_utils + .expf_float_utils libc.src.__support.FPUtil.double_double libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits @@ -3115,6 +3173,7 @@ add_header_library( libc.src.__support.macros.config libc.src.__support.macros.optimization libc.src.__support.macros.properties.cpu_features + libc.src.__support.math.check.exp_exceptions ) add_header_library( @@ -3137,12 +3196,14 @@ add_header_library( HDRS expf_integer_eval.h DEPENDS - .exp_constants + .exp2f_integer_utils + libc.hdr.fenv_macros libc.src.__support.CPP.bit libc.src.__support.FPUtil.fp_bits + libc.src.__support.frac64 + libc.src.__support.macros.attributes libc.src.__support.macros.config libc.src.__support.macros.optimization - libc.src.__support.frac64 ) add_header_library( @@ -3857,9 +3918,9 @@ add_header_library( HDRS gamma_util.h DEPENDS - libc.src.__support.CPP.bit libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add + libc.src.__support.macros.attributes libc.src.__support.macros.config ) @@ -3896,8 +3957,8 @@ add_header_library( HDRS getpayloadf128.h DEPENDS - libc.include.llvm-libc-types.float128 libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.float128 libc.src.__support.macros.config ) @@ -4034,6 +4095,7 @@ add_header_library( libc.src.__support.FPUtil.except_value_utils libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.is_integer libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.nearest_integer_operations libc.src.__support.FPUtil.polyeval @@ -4052,6 +4114,7 @@ add_header_library( libc.src.__support.FPUtil.cast libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.is_integer libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.nearest_integer_operations libc.src.__support.FPUtil.polyeval @@ -4168,35 +4231,77 @@ add_header_library( libc.src.__support.FPUtil.triple_double ) +add_header_library( + exp2_accurate_128 + HDRS + exp2_accurate_128.h + DEPENDS + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.fp_bits + libc.src.__support.common + libc.src.__support.frac128 + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.uint128 +) + add_header_library( exp_utils HDRS exp_utils.h DEPENDS - libc.src.__support.CPP.optional + .exp2_accurate_128 + libc.hdr.errno_macros + libc.hdr.fenv_macros libc.src.__support.CPP.bit + libc.src.__support.CPP.optional + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.fp_bitwise + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.common + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features ) add_header_library( - exp + exp_double_utils HDRS - exp.h + exp_double_utils.h DEPENDS - .exp_constants .exp_utils - libc.src.__support.CPP.bit - libc.src.__support.CPP.optional - libc.src.__support.FPUtil.dyadic_float + libc.hdr.errno_macros libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.fp_bitwise + libc.src.__support.FPUtil.multiply_add + libc.src.__support.common + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + exp2_double_eval + HDRS + exp2_double_eval.h + DEPENDS + .exp_double_utils + .exp_utils + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.nearest_integer - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.FPUtil.triple_double - libc.src.__support.integer_literals + libc.src.__support.common + libc.src.__support.macros.attributes + libc.src.__support.macros.config libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features ) add_header_library( @@ -4204,21 +4309,39 @@ add_header_library( HDRS exp2.h DEPENDS - .common_constants + .exp2_double_eval + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + exp_double_eval + HDRS + exp_double_eval.h + DEPENDS + .exp_double_utils .exp_utils - libc.src.__support.CPP.bit - libc.src.__support.CPP.optional - libc.src.__support.FPUtil.dyadic_float - libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.double_double libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.nearest_integer - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.FPUtil.triple_double - libc.src.__support.integer_literals + libc.src.__support.common + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + +add_header_library( + exp + HDRS + exp.h + DEPENDS + .exp_double_eval + libc.src.__support.common + libc.src.__support.macros.config libc.src.__support.macros.optimization - libc.src.errno.errno ) add_header_library( @@ -4256,6 +4379,21 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + exp2f_integer_eval + HDRS + exp2f_integer_eval.h + DEPENDS + .exp2f_integer_utils + libc.hdr.fenv_macros + libc.src.__support.CPP.bit + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types +) + add_header_library( exp2f HDRS @@ -4263,9 +4401,32 @@ add_header_library( DEPENDS .exp2f_double_eval .exp2f_float_eval + .exp2f_integer_eval libc.src.__support.common libc.src.__support.macros.config libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + +add_header_library( + exp2bf16 + HDRS + exp2bf16.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.bfloat16 + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types ) add_header_library( @@ -4875,8 +5036,8 @@ add_header_library( HDRS setpayloadf128.h DEPENDS - libc.include.llvm-libc-types.float128 libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.float128 libc.src.__support.macros.config ) @@ -4932,8 +5093,8 @@ add_header_library( HDRS setpayloadsigf128.h DEPENDS - libc.include.llvm-libc-types.float128 libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.float128 libc.src.__support.macros.config ) @@ -5388,6 +5549,7 @@ add_header_library( libc.src.__support.FPUtil.dyadic_float libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.is_integer libc.src.__support.FPUtil.multiply_add libc.src.__support.FPUtil.nearest_integer libc.src.__support.FPUtil.polyeval @@ -5402,24 +5564,83 @@ add_header_library( ) add_header_library( - powf + powf_utils HDRS - powf.h - powf_small_tables.h + powf_utils.h DEPENDS .common_constants .exp10f .exp2f - libc.src.__support.CPP.algorithm + libc.hdr.errno_macros + libc.hdr.fenv_macros libc.src.__support.CPP.bit + libc.src.__support.CPP.optional + libc.src.__support.FPUtil.double_double libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.is_integer libc.src.__support.FPUtil.nearest_integer - libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode libc.src.__support.FPUtil.sqrt libc.src.__support.FPUtil.triple_double + libc.src.__support.common + libc.src.__support.macros.attributes + libc.src.__support.macros.config libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + +add_header_library( + powf_double_eval + HDRS + powf_double_eval.h + DEPENDS + .common_constants + .exp_constants + .powf_utils + libc.src.__support.CPP.bit + libc.src.__support.CPP.optional + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + +add_header_library( + powf_float_eval + HDRS + powf_float_eval.h + DEPENDS + .exp2f_float_utils + .powf_utils + libc.src.__support.CPP.bit + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + +add_header_library( + powf + HDRS + powf.h + DEPENDS + .powf_double_eval + .powf_float_eval + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features ) add_header_library( @@ -5453,9 +5674,9 @@ add_header_library( ) add_header_library( - sinf + sinf_double_eval HDRS - sinf.h + sinf_double_eval.h DEPENDS .range_reduction .sincosf_utils @@ -5468,6 +5689,33 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + sinf_float_eval + HDRS + sinf_float_eval.h + DEPENDS + .sincosf_utils + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( + sinf + HDRS + sinf.h + DEPENDS + .sinf_double_eval + .sinf_float_eval + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + add_header_library( sinf16 HDRS @@ -5621,9 +5869,9 @@ add_header_library( ) add_header_library( - tanf + tanf_double_eval HDRS - tanf.h + tanf_double_eval.h DEPENDS .range_reduction .sincosf_utils @@ -5636,6 +5884,32 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + tanf_float_eval + HDRS + tanf_float_eval.h + DEPENDS + .sincosf_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + tanf + HDRS + tanf.h + DEPENDS + .tanf_double_eval + .tanf_float_eval + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + add_header_library( tanf16 HDRS @@ -5695,11 +5969,12 @@ add_header_library( HDRS tanpif.h DEPENDS - .sincosf16_utils - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits + .sincosf_utils libc.src.__support.FPUtil.cast libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.is_integer libc.src.__support.FPUtil.multiply_add libc.src.__support.common libc.src.__support.macros.config @@ -5719,6 +5994,7 @@ add_header_library( libc.src.__support.FPUtil.except_value_utils libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.is_integer libc.src.__support.FPUtil.multiply_add libc.src.__support.macros.optimization ) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/acosbf16.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/acosbf16.h index 7b78bd34dd28..e0fb861accb4 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/acosbf16.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/acosbf16.h @@ -35,6 +35,14 @@ LIBC_INLINE bfloat16 acosbf16(bfloat16 x) { uint16_t x_u = xbits.uintval(); uint16_t x_abs = x_u & 0x7fff; bool sign = (x_u >> 15); + + // For |x| <= 2^-12, 0x1.92p0 < acos(x) < 0x1.93p0: the lower bound is + // a bfloat16 value and the upper bound is the midpoint to its successor. + // Thus acos(x) rounds like pi/2 in every rounding mode. Return before + // squaring x or evaluating the polynomial to avoid intermediate underflow. + if (LIBC_UNLIKELY(x_abs <= 0x3980)) + return fputil::cast<bfloat16>(PI_2); + float xf = x; float xf_abs = (xf < 0 ? -xf : xf); @@ -42,12 +50,7 @@ LIBC_INLINE bfloat16 acosbf16(bfloat16 x) { // case 1: x <= 0.5 if (x_abs <= 0x3F00) { - // |x| = {0} - if (LIBC_UNLIKELY(x_abs == 0)) - return fputil::cast<bfloat16>(PI_2); - - float xp = fputil::cast<float>(asin_internal::asin_eval(x_sq)); - float result = xf * fputil::multiply_add(x_sq, xp, 1.0f); + float result = xf * asin_internal::asin_eval_float(x_sq); return fputil::cast<bfloat16>(PI_2 - result); } @@ -66,11 +69,7 @@ LIBC_INLINE bfloat16 acosbf16(bfloat16 x) { // and acos(x) = acos(|x|) for x >= 0, pi - acos(|x|) for x < 0 float t = fputil::multiply_add<float>(xf_abs, -0.5f, 0.5f); float t_sqrt = fputil::sqrt<float>(t); - // TODO: Use bfloat16 version for inv_trigf_utils_internals after they are - // available Tracking issue : - // https://github.com/llvm/llvm-project/issues/202079 - float tp = fputil::cast<float>(asin_internal::asin_eval(t)); - float asin_sqrt_t = t_sqrt * (fputil::multiply_add(t, tp, 1.0f)); + float asin_sqrt_t = t_sqrt * asin_internal::asin_eval_float(t); return fputil::cast<bfloat16>( (sign) ? fputil::multiply_add(asin_sqrt_t, -2.0f, PI) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/asin_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/asin_utils.h index f6f19baa312f..59d3df2e32b1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/asin_utils.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/asin_utils.h @@ -21,6 +21,22 @@ namespace LIBC_NAMESPACE_DECL { namespace asin_internal { +// Single-precision approximation of asin(x) / x for |x| <= 0.5, evaluated +// at xsq = x * x. The coefficients are the same as those used by asinf16, +// generated with Sollya: +// > prec = 200; +// > display = hexadecimal; +// > P = fpminimax(asin(x)/x, [|0, 2, 4, 6, 8|], [|SG...|], [0, 0.5]); +// > dirtyinfnorm(asin(x)/x - P, [0, 0.5]); +// 0x1p-23 +// This approximation is intended for 16-bit results, not float results. +LIBC_INLINE LIBC_CONSTEXPR float asin_eval_float(float xsq) { + float x4 = xsq * xsq; + float c0 = fputil::multiply_add(xsq, 0x1.554c2ap-3f, 0x1.000002p0f); + float c1 = fputil::multiply_add(xsq, 0x1.43b2d6p-5f, 0x1.3541ccp-4f); + return fputil::polyeval(x4, c0, c1, 0x1.a0d73ep-5f); +} + using DoubleDouble = fputil::DoubleDouble; using DFloat128 = fputil::DyadicFloat<128>; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/asinbf16.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/asinbf16.h index 64c113e68856..9083ca9adcce 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/asinbf16.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/asinbf16.h @@ -55,8 +55,7 @@ LIBC_INLINE LIBC_CONSTEXPR bfloat16 asinbf16(bfloat16 x) { return x; } - float xp = fputil::cast<float>(asin_internal::asin_eval(x_sq)); - float result = xf * (fputil::multiply_add<float>(x_sq, xp, 1.0f)); + float result = xf * asin_internal::asin_eval_float(x_sq); return fputil::cast<bfloat16>(result); } @@ -70,8 +69,7 @@ LIBC_INLINE LIBC_CONSTEXPR bfloat16 asinbf16(bfloat16 x) { float t = fputil::multiply_add<float>(xf_abs, -0.5f, 0.5f); float t_sqrt = fputil::sqrt<float>(t); - float tp = fputil::cast<float>(asin_internal::asin_eval(t)); - float asin_sqrt_t = t_sqrt * (fputil::multiply_add<float>(t, tp, 1.0f)); + float asin_sqrt_t = t_sqrt * asin_internal::asin_eval_float(t); float result = fputil::multiply_add<float>(-2.0f, asin_sqrt_t, PI_2); return fputil::cast<bfloat16>(x_sign * result); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16sub.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16sub.h index a6aa1dfd6e65..ad402f0423f0 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16sub.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16sub.h @@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE bfloat16 bf16sub(double x, double y) { +LIBC_INLINE constexpr bfloat16 bf16sub(double x, double y) { return fputil::generic::sub<bfloat16>(x, y); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf.h index 347626f3eaf1..3e5cf1ea6bba 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf.h @@ -17,7 +17,7 @@ namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE bfloat16 bf16subf(float x, float y) { +LIBC_INLINE constexpr bfloat16 bf16subf(float x, float y) { return fputil::generic::sub<bfloat16>(x, y); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf128.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf128.h index 18c1f568e281..16da075a6f93 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf128.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/bf16subf128.h @@ -21,7 +21,7 @@ namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE bfloat16 bf16subf128(float128 x, float128 y) { +LIBC_INLINE constexpr bfloat16 bf16subf128(float128 x, float128 y) { return fputil::generic::sub<bfloat16>(x, y); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/cbrtf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/cbrtf.h index 5f0c413088a3..d73fb001b636 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/cbrtf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/cbrtf.h @@ -12,6 +12,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY @@ -19,69 +20,76 @@ namespace LIBC_NAMESPACE_DECL { namespace math { +namespace cbrtf_internal { + +// Look up table for 2^(i/3) for i = 0, 1, 2. +LIBC_INLINE_VAR constexpr double CBRT2[3] = {1.0, 0x1.428a2f98d728bp0, + 0x1.965fea53d6e3dp0}; + +// Degree-7 polynomials approximation of ((1 + x)^(1/3) - 1)/x for 0 <= x <= 1 +// generated by Sollya with: +// > for i from 0 to 15 do { +// P = fpminimax(((1 + x)^(1/3) - 1)/x, 6, [|D...|], [i/16, (i + 1)/16]); +// print("{", coeff(P, 0), ",", coeff(P, 1), ",", coeff(P, 2), ",", +// coeff(P, 3), ",", coeff(P, 4), ",", coeff(P, 5), ",", +// coeff(P, 6), "},"); +// }; +// Then (1 + x)^(1/3) ~ 1 + x * P(x). +LIBC_INLINE_VAR constexpr double COEFFS[16][7] = { + {0x1.55555555554ebp-2, -0x1.c71c71c678c0cp-4, 0x1.f9add2776de81p-5, + -0x1.511e10aa964a7p-5, 0x1.ee44165937fa2p-6, -0x1.7c5c9e059345dp-6, + 0x1.047f75e0aff14p-6}, + {0x1.5555554d1149ap-2, -0x1.c71c676fcb5bp-4, 0x1.f9ab127dc57ebp-5, + -0x1.50ea8fd1d4c15p-5, 0x1.e9d68f28ced43p-6, -0x1.60e0e1e661311p-6, + 0x1.716eca1d6e3bcp-7}, + {0x1.5555546377d45p-2, -0x1.c71bc1c6d49d2p-4, 0x1.f9924cc0ed24dp-5, + -0x1.4fea3beb53b3bp-5, 0x1.de028a9a07b1bp-6, -0x1.3b090d2233524p-6, + 0x1.0aeca34893785p-7}, + {0x1.55554dce9f649p-2, -0x1.c7188b34b98f8p-4, 0x1.f93e1af34af49p-5, + -0x1.4d9a06be75c63p-5, 0x1.cb943f4f68992p-6, -0x1.139a685a5e3c4p-6, + 0x1.88410674c6a5dp-8}, + {0x1.5555347d211c3p-2, -0x1.c70f2a4b1a5fap-4, 0x1.f88420e8602c3p-5, + -0x1.49becfa4ed3ep-5, 0x1.b475cd9013162p-6, -0x1.dcfee1dd2f8efp-7, + 0x1.249bb51a1c498p-8}, + {0x1.5554f01b33dbap-2, -0x1.c6facb929dbf1p-4, 0x1.f73fb7861252ep-5, + -0x1.4459a4a0071fap-5, 0x1.9a8df2b504fc2p-6, -0x1.9a7ce3006d06ep-7, + 0x1.ba9230918fa2ep-9}, + {0x1.55545c695db5fp-2, -0x1.c6d6089f20275p-4, 0x1.f556e0ea80efp-5, + -0x1.3d91372d083f4p-5, 0x1.7f66cff331f4p-6, -0x1.606a562491737p-7, + 0x1.52e3e17c71069p-9}, + {0x1.55534a879232ap-2, -0x1.c69b836998b84p-4, 0x1.f2bb26dac0e4cp-5, + -0x1.359eed43716d7p-5, 0x1.64218cd824fbcp-6, -0x1.2e703e2e091e8p-7, + 0x1.0677d9af6aad4p-9}, + {0x1.5551836bb5494p-2, -0x1.c64658c15353bp-4, 0x1.ef68517451a6ep-5, + -0x1.2cc20a980dceep-5, 0x1.49843e0fad93ap-6, -0x1.03c59ccb68e54p-7, + 0x1.9ad325dc7adcbp-10}, + {0x1.554ecacb0d035p-2, -0x1.c5d2664026ffcp-4, 0x1.eb624796ba809p-5, + -0x1.233803d19a535p-5, 0x1.300decb1c3c28p-6, -0x1.befe18031ec3dp-8, + 0x1.449f5ee175c69p-10}, + {0x1.554ae1f5ae815p-2, -0x1.c53c6b14ff6b2p-4, 0x1.e6b2d5127bb5bp-5, + -0x1.19387336788a3p-5, 0x1.180955a6ab255p-6, -0x1.81696703ba369p-8, + 0x1.02cb36389bd79p-10}, + {0x1.55458a59f356ep-2, -0x1.c4820dd631ae9p-4, 0x1.e167af818bd15p-5, + -0x1.0ef35f6f72e52p-5, 0x1.019c33b65e4ebp-6, -0x1.4d25bdd52d3a5p-8, + 0x1.a008ae91f5936p-11}, + {0x1.553e878eafee1p-2, -0x1.c3a1d0b2a3db2p-4, 0x1.db90d8ed9f89bp-5, + -0x1.0490e20f1ae91p-5, 0x1.d9a5d1fc42fe3p-7, -0x1.20bf8227c2abfp-8, + 0x1.50f8174cdb6e9p-11}, + {0x1.5535a0dedf1b1p-2, -0x1.c29afb8bd01a1p-4, 0x1.d53f6371c1e27p-5, + -0x1.f463209b433e2p-6, 0x1.b35222a17e44p-7, -0x1.f5efbf505e133p-9, + 0x1.12e0e94e8586dp-11}, + {0x1.552aa25e57bfdp-2, -0x1.c16d811e4acadp-4, 0x1.ce8489b47aa51p-5, + -0x1.dfde7ff758ea8p-6, 0x1.901f43aac38c8p-7, -0x1.b581d07df5ad5p-9, + 0x1.c3726535f1fc6p-12}, + {0x1.551d5d9b204d3p-2, -0x1.c019e328f8db1p-4, 0x1.c7710f44fc3cep-5, + -0x1.cbbbe25ea8ba4p-6, 0x1.6fe270088623dp-7, -0x1.7e6fc79733761p-9, + 0x1.75077abf18d84p-12}, +}; + +} // namespace cbrtf_internal + LIBC_INLINE float cbrtf(float x) { - // Look up table for 2^(i/3) for i = 0, 1, 2. - constexpr double CBRT2[3] = {1.0, 0x1.428a2f98d728bp0, 0x1.965fea53d6e3dp0}; - - // Degree-7 polynomials approximation of ((1 + x)^(1/3) - 1)/x for 0 <= x <= 1 - // generated by Sollya with: - // > for i from 0 to 15 do { - // P = fpminimax(((1 + x)^(1/3) - 1)/x, 6, [|D...|], [i/16, (i + 1)/16]); - // print("{", coeff(P, 0), ",", coeff(P, 1), ",", coeff(P, 2), ",", - // coeff(P, 3), ",", coeff(P, 4), ",", coeff(P, 5), ",", - // coeff(P, 6), "},"); - // }; - // Then (1 + x)^(1/3) ~ 1 + x * P(x). - constexpr double COEFFS[16][7] = { - {0x1.55555555554ebp-2, -0x1.c71c71c678c0cp-4, 0x1.f9add2776de81p-5, - -0x1.511e10aa964a7p-5, 0x1.ee44165937fa2p-6, -0x1.7c5c9e059345dp-6, - 0x1.047f75e0aff14p-6}, - {0x1.5555554d1149ap-2, -0x1.c71c676fcb5bp-4, 0x1.f9ab127dc57ebp-5, - -0x1.50ea8fd1d4c15p-5, 0x1.e9d68f28ced43p-6, -0x1.60e0e1e661311p-6, - 0x1.716eca1d6e3bcp-7}, - {0x1.5555546377d45p-2, -0x1.c71bc1c6d49d2p-4, 0x1.f9924cc0ed24dp-5, - -0x1.4fea3beb53b3bp-5, 0x1.de028a9a07b1bp-6, -0x1.3b090d2233524p-6, - 0x1.0aeca34893785p-7}, - {0x1.55554dce9f649p-2, -0x1.c7188b34b98f8p-4, 0x1.f93e1af34af49p-5, - -0x1.4d9a06be75c63p-5, 0x1.cb943f4f68992p-6, -0x1.139a685a5e3c4p-6, - 0x1.88410674c6a5dp-8}, - {0x1.5555347d211c3p-2, -0x1.c70f2a4b1a5fap-4, 0x1.f88420e8602c3p-5, - -0x1.49becfa4ed3ep-5, 0x1.b475cd9013162p-6, -0x1.dcfee1dd2f8efp-7, - 0x1.249bb51a1c498p-8}, - {0x1.5554f01b33dbap-2, -0x1.c6facb929dbf1p-4, 0x1.f73fb7861252ep-5, - -0x1.4459a4a0071fap-5, 0x1.9a8df2b504fc2p-6, -0x1.9a7ce3006d06ep-7, - 0x1.ba9230918fa2ep-9}, - {0x1.55545c695db5fp-2, -0x1.c6d6089f20275p-4, 0x1.f556e0ea80efp-5, - -0x1.3d91372d083f4p-5, 0x1.7f66cff331f4p-6, -0x1.606a562491737p-7, - 0x1.52e3e17c71069p-9}, - {0x1.55534a879232ap-2, -0x1.c69b836998b84p-4, 0x1.f2bb26dac0e4cp-5, - -0x1.359eed43716d7p-5, 0x1.64218cd824fbcp-6, -0x1.2e703e2e091e8p-7, - 0x1.0677d9af6aad4p-9}, - {0x1.5551836bb5494p-2, -0x1.c64658c15353bp-4, 0x1.ef68517451a6ep-5, - -0x1.2cc20a980dceep-5, 0x1.49843e0fad93ap-6, -0x1.03c59ccb68e54p-7, - 0x1.9ad325dc7adcbp-10}, - {0x1.554ecacb0d035p-2, -0x1.c5d2664026ffcp-4, 0x1.eb624796ba809p-5, - -0x1.233803d19a535p-5, 0x1.300decb1c3c28p-6, -0x1.befe18031ec3dp-8, - 0x1.449f5ee175c69p-10}, - {0x1.554ae1f5ae815p-2, -0x1.c53c6b14ff6b2p-4, 0x1.e6b2d5127bb5bp-5, - -0x1.19387336788a3p-5, 0x1.180955a6ab255p-6, -0x1.81696703ba369p-8, - 0x1.02cb36389bd79p-10}, - {0x1.55458a59f356ep-2, -0x1.c4820dd631ae9p-4, 0x1.e167af818bd15p-5, - -0x1.0ef35f6f72e52p-5, 0x1.019c33b65e4ebp-6, -0x1.4d25bdd52d3a5p-8, - 0x1.a008ae91f5936p-11}, - {0x1.553e878eafee1p-2, -0x1.c3a1d0b2a3db2p-4, 0x1.db90d8ed9f89bp-5, - -0x1.0490e20f1ae91p-5, 0x1.d9a5d1fc42fe3p-7, -0x1.20bf8227c2abfp-8, - 0x1.50f8174cdb6e9p-11}, - {0x1.5535a0dedf1b1p-2, -0x1.c29afb8bd01a1p-4, 0x1.d53f6371c1e27p-5, - -0x1.f463209b433e2p-6, 0x1.b35222a17e44p-7, -0x1.f5efbf505e133p-9, - 0x1.12e0e94e8586dp-11}, - {0x1.552aa25e57bfdp-2, -0x1.c16d811e4acadp-4, 0x1.ce8489b47aa51p-5, - -0x1.dfde7ff758ea8p-6, 0x1.901f43aac38c8p-7, -0x1.b581d07df5ad5p-9, - 0x1.c3726535f1fc6p-12}, - {0x1.551d5d9b204d3p-2, -0x1.c019e328f8db1p-4, 0x1.c7710f44fc3cep-5, - -0x1.cbbbe25ea8ba4p-6, 0x1.6fe270088623dp-7, -0x1.7e6fc79733761p-9, - 0x1.75077abf18d84p-12}, - }; + using namespace cbrtf_internal; using FloatBits = typename fputil::FPBits<float>; using DoubleBits = typename fputil::FPBits<double>; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf.h index affff7117562..592ddbc0e4ed 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf.h @@ -1,175 +1,42 @@ -//===-- Implementation header for cosf --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation selector for cosf. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSF_H #define LLVM_LIBC_SRC___SUPPORT_MATH_COSF_H -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" #if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ - defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT) && \ + (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ + defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)) && \ defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - -#include "sincosf_float_eval.h" +#include "cosf_float_eval.h" +#define LIBC_MATH_COSF_IMPL float_eval +#else +#include "cosf_double_eval.h" +#define LIBC_MATH_COSF_IMPL double_eval +#endif namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE float cosf(float x) { - return sincosf_float_eval::sincosf_eval</*IS_SIN*/ false>(x); -} +using LIBC_MATH_COSF_IMPL::cosf; } // namespace math } // namespace LIBC_NAMESPACE_DECL -#else // !LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT - -#include "sincosf_utils.h" - -namespace LIBC_NAMESPACE_DECL { - -namespace math { - -LIBC_INLINE float cosf(float x) { - using namespace sincosf_utils_internal; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Exceptional cases for cosf. - constexpr size_t N_EXCEPTS = 6; - - constexpr fputil::ExceptValues<float, N_EXCEPTS> COSF_EXCEPTS{{ - // (inputs, RZ output, RU offset, RD offset, RN offset) - // x = 0x1.64a032p43, cos(x) = 0x1.9d4ba4p-1 (RZ) - {0x55325019, 0x3f4ea5d2, 1, 0, 0}, - // x = 0x1.4555p51, cos(x) = 0x1.115d7cp-1 (RZ) - {0x5922aa80, 0x3f08aebe, 1, 0, 1}, - // x = 0x1.48a858p54, cos(x) = 0x1.f48148p-2 (RZ) - {0x5aa4542c, 0x3efa40a4, 1, 0, 0}, - // x = 0x1.3170fp63, cos(x) = 0x1.fe2976p-1 (RZ) - {0x5f18b878, 0x3f7f14bb, 1, 0, 0}, - // x = 0x1.2b9622p67, cos(x) = 0x1.f0285cp-1 (RZ) - {0x6115cb11, 0x3f78142e, 1, 0, 1}, - // x = 0x1.ddebdep120, cos(x) = 0x1.114438p-1 (RZ) - {0x7beef5ef, 0x3f08a21c, 1, 0, 0}, - }}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - using FPBits = typename fputil::FPBits<float>; - - FPBits xbits(x); - xbits.set_sign(Sign::POS); - - uint32_t x_abs = xbits.uintval(); - - // Range reduction: - // For |x| > pi/16, we perform range reduction as follows: - // Find k and y such that: - // x = (k + y) * pi/32 - // k is an integer - // |y| < 0.5 - // For small range (|x| < 2^45 when FMA instructions are available, 2^22 - // otherwise), this is done by performing: - // k = round(x * 32/pi) - // y = x * 32/pi - k - // For large range, we will omit all the higher parts of 16/pi such that the - // least significant bits of their full products with x are larger than 63, - // since cos((k + y + 64*i) * pi/32) = cos(x + i * 2pi) = cos(x). - // - // When FMA instructions are not available, we store the digits of 32/pi in - // chunks of 28-bit precision. This will make sure that the products: - // x * THIRTYTWO_OVER_PI_28[i] are all exact. - // When FMA instructions are available, we simply store the digits of 32/pi in - // chunks of doubles (53-bit of precision). - // So when multiplying by the largest values of single precision, the - // resulting output should be correct up to 2^(-208 + 128) ~ 2^-80. By the - // worst-case analysis of range reduction, |y| >= 2^-38, so this should give - // us more than 40 bits of accuracy. For the worst-case estimation of range - // reduction, see for instances: - // Elementary Functions by J-M. Muller, Chapter 11, - // Handbook of Floating-Point Arithmetic by J-M. Muller et. al., - // Chapter 10.2. - // - // Once k and y are computed, we then deduce the answer by the cosine of sum - // formula: - // cos(x) = cos((k + y)*pi/32) - // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) - // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..63 are precomputed - // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are - // computed using degree-7 and degree-6 minimax polynomials generated by - // Sollya respectively. - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // |x| < 0x1.0p-12f - if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { - // When |x| < 2^-12, the relative error of the approximation cos(x) ~ 1 - // is: - // |cos(x) - 1| < |x^2 / 2| = 2^-25 < epsilon(1)/2. - // So the correctly rounded values of cos(x) are: - // = 1 - eps(x) if rounding mode = FE_TOWARDZERO or FE_DOWWARD, - // = 1 otherwise. - // To simplify the rounding decision and make it more efficient and to - // prevent compiler to perform constant folding, we use - // fma(x, -2^-25, 1) instead. - // Note: to use the formula 1 - 2^-25*x to decide the correct rounding, we - // do need fma(x, -2^-25, 1) to prevent underflow caused by -2^-25*x when - // |x| < 2^-125. For targets without FMA instructions, we simply use - // double for intermediate results as it is more efficient than using an - // emulated version of FMA. -#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - return fputil::multiply_add(xbits.get_val(), -0x1.0p-25f, 1.0f); -#else // !LIBC_TARGET_CPU_HAS_FMA_FLOAT - double xd = static_cast<double>(xbits.get_val()); - return static_cast<float>(fputil::multiply_add(xd, -0x1.0p-25, 1.0)); -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - } - - if (auto r = COSF_EXCEPTS.lookup(x_abs); LIBC_UNLIKELY(r.has_value())) - return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // x is inf or nan. - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - return x + FPBits::quiet_nan().get_val(); - } - - double xd = static_cast<double>(xbits.get_val()); - // Combine the results with the sine of sum formula: - // cos(x) = cos((k + y)*pi/32) - // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) - // = cosm1_y * cos_k + sin_y * sin_k - // = (cosm1_y * cos_k + cos_k) + sin_y * sin_k - double sin_k = 0, cos_k = 0, sin_y = 0, cosm1_y = 0; - - sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); - - return static_cast<float>(fputil::multiply_add( - sin_y, -sin_k, fputil::multiply_add(cosm1_y, cos_k, cos_k))); -} - -} // namespace math - -} // namespace LIBC_NAMESPACE_DECL - -#endif // LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT +#undef LIBC_MATH_COSF_IMPL #endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_double_eval.h new file mode 100644 index 000000000000..aa7132df9378 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_double_eval.h @@ -0,0 +1,162 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Double-precision implementation of cosf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSF_DOUBLE_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_COSF_DOUBLE_EVAL_H + +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA + +#include "sincosf_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +namespace double_eval { + +LIBC_INLINE float cosf(float x) { + using namespace sincosf_utils_internal; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Exceptional cases for cosf. + constexpr size_t N_EXCEPTS = 6; + + constexpr fputil::ExceptValues<float, N_EXCEPTS> COSF_EXCEPTS{{ + // (inputs, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.64a032p43, cos(x) = 0x1.9d4ba4p-1 (RZ) + {0x55325019, 0x3f4ea5d2, 1, 0, 0}, + // x = 0x1.4555p51, cos(x) = 0x1.115d7cp-1 (RZ) + {0x5922aa80, 0x3f08aebe, 1, 0, 1}, + // x = 0x1.48a858p54, cos(x) = 0x1.f48148p-2 (RZ) + {0x5aa4542c, 0x3efa40a4, 1, 0, 0}, + // x = 0x1.3170fp63, cos(x) = 0x1.fe2976p-1 (RZ) + {0x5f18b878, 0x3f7f14bb, 1, 0, 0}, + // x = 0x1.2b9622p67, cos(x) = 0x1.f0285cp-1 (RZ) + {0x6115cb11, 0x3f78142e, 1, 0, 1}, + // x = 0x1.ddebdep120, cos(x) = 0x1.114438p-1 (RZ) + {0x7beef5ef, 0x3f08a21c, 1, 0, 0}, + }}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + using FPBits = typename fputil::FPBits<float>; + + FPBits xbits(x); + xbits.set_sign(Sign::POS); + + uint32_t x_abs = xbits.uintval(); + + // Range reduction: + // For |x| > pi/16, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * pi/32 + // k is an integer + // |y| < 0.5 + // For small range (|x| < 2^45 when FMA instructions are available, 2^22 + // otherwise), this is done by performing: + // k = round(x * 32/pi) + // y = x * 32/pi - k + // For large range, we will omit all the higher parts of 16/pi such that the + // least significant bits of their full products with x are larger than 63, + // since cos((k + y + 64*i) * pi/32) = cos(x + i * 2pi) = cos(x). + // + // When FMA instructions are not available, we store the digits of 32/pi in + // chunks of 28-bit precision. This will make sure that the products: + // x * THIRTYTWO_OVER_PI_28[i] are all exact. + // When FMA instructions are available, we simply store the digits of 32/pi in + // chunks of doubles (53-bit of precision). + // So when multiplying by the largest values of single precision, the + // resulting output should be correct up to 2^(-208 + 128) ~ 2^-80. By the + // worst-case analysis of range reduction, |y| >= 2^-38, so this should give + // us more than 40 bits of accuracy. For the worst-case estimation of range + // reduction, see for instances: + // Elementary Functions by J-M. Muller, Chapter 11, + // Handbook of Floating-Point Arithmetic by J-M. Muller et. al., + // Chapter 10.2. + // + // Once k and y are computed, we then deduce the answer by the cosine of sum + // formula: + // cos(x) = cos((k + y)*pi/32) + // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) + // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..63 are precomputed + // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are + // computed using degree-7 and degree-6 minimax polynomials generated by + // Sollya respectively. + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // |x| < 0x1.0p-12f + if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { + // When |x| < 2^-12, the relative error of the approximation cos(x) ~ 1 + // is: + // |cos(x) - 1| < |x^2 / 2| = 2^-25 < epsilon(1)/2. + // So the correctly rounded values of cos(x) are: + // = 1 - eps(x) if rounding mode = FE_TOWARDZERO or FE_DOWWARD, + // = 1 otherwise. + // To simplify the rounding decision and make it more efficient and to + // prevent compiler to perform constant folding, we use + // fma(x, -2^-25, 1) instead. + // Note: to use the formula 1 - 2^-25*x to decide the correct rounding, we + // do need fma(x, -2^-25, 1) to prevent underflow caused by -2^-25*x when + // |x| < 2^-125. For targets without FMA instructions, we simply use + // double for intermediate results as it is more efficient than using an + // emulated version of FMA. +#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + return fputil::multiply_add(xbits.get_val(), -0x1.0p-25f, 1.0f); +#else // !LIBC_TARGET_CPU_HAS_FMA_FLOAT + double xd = static_cast<double>(xbits.get_val()); + return static_cast<float>(fputil::multiply_add(xd, -0x1.0p-25, 1.0)); +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + } + + if (auto r = COSF_EXCEPTS.lookup(x_abs); LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // x is inf or nan. + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + double xd = static_cast<double>(xbits.get_val()); + // Combine the results with the sine of sum formula: + // cos(x) = cos((k + y)*pi/32) + // = cos(y*pi/32) * cos(k*pi/32) - sin(y*pi/32) * sin(k*pi/32) + // = cosm1_y * cos_k + sin_y * sin_k + // = (cosm1_y * cos_k + cos_k) + sin_y * sin_k + double sin_k = 0, cos_k = 0, sin_y = 0, cosm1_y = 0; + + sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); + + return static_cast<float>(fputil::multiply_add( + sin_y, -sin_k, fputil::multiply_add(cosm1_y, cos_k, cos_k))); +} + +} // namespace double_eval +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSF_DOUBLE_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_float_eval.h new file mode 100644 index 000000000000..5cf0b1b07d12 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/cosf_float_eval.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Float-only implementation of cosf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSF_FLOAT_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_COSF_FLOAT_EVAL_H + +#include "sincosf_float_eval.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace float_eval { + +LIBC_INLINE float cosf(float x) { + return sincosf_float_eval::sincosf_eval</*IS_SIN*/ false>(x); +} + +} // namespace float_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSF_FLOAT_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/erff.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/erff.h index 63919734cf74..e19997af28cd 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/erff.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/erff.h @@ -12,6 +12,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/except_value_utils.h" #include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY @@ -19,111 +20,116 @@ namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE float erff(float x) { +namespace erff_internal { + +// Polynomials approximating erf(x)/x on ( k/8, (k + 1)/8 ) generated by +// Sollya with: > P = fpminimax(erf(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], +// [|D...|], +// [k/8, (k + 1)/8]); +// for k = 0..31. +LIBC_INLINE_VAR constexpr double COEFFS[32][8] = { + {0x1.20dd750429b6dp0, -0x1.812746b037753p-2, 0x1.ce2f219e8596ap-4, + -0x1.b82cdacb78fdap-6, 0x1.56479297dfda5p-8, -0x1.8b3ac5455ef02p-11, + -0x1.126fcac367e3bp-8, 0x1.2d0bdb3ba4984p-4}, + {0x1.20dd750429b6dp0, -0x1.812746b0379a8p-2, 0x1.ce2f21a03cf2ap-4, + -0x1.b82ce30de083ep-6, 0x1.565bcad3eb60fp-8, -0x1.c02c66f659256p-11, + 0x1.f92f673385229p-14, -0x1.def402648ae9p-17}, + {0x1.20dd750429b34p0, -0x1.812746b032dcep-2, 0x1.ce2f219d84aaep-4, + -0x1.b82ce22dcf139p-6, 0x1.565b9efcd4af1p-8, -0x1.c021f1af414bcp-11, + 0x1.f7c6d177eff82p-14, -0x1.c9e4410dcf865p-17}, + {0x1.20dd750426eabp0, -0x1.812746ae592c7p-2, 0x1.ce2f211525f14p-4, + -0x1.b82ccc125e63fp-6, 0x1.56596f261cfd3p-8, -0x1.bfde1ff8eeecfp-11, + 0x1.f31a9d15dc5d8p-14, -0x1.a5a4362844b3cp-17}, + {0x1.20dd75039c705p0, -0x1.812746777e74dp-2, 0x1.ce2f17af98a1bp-4, + -0x1.b82be4b817cbep-6, 0x1.564bec2e2962ep-8, -0x1.bee86f9da3558p-11, + 0x1.e9443689dc0ccp-14, -0x1.79c0f230805d8p-17}, + {0x1.20dd74f811211p0, -0x1.81274371a3e8fp-2, 0x1.ce2ec038262e5p-4, + -0x1.b8265b82c5e1fp-6, 0x1.5615a2e239267p-8, -0x1.bc63ae023dcebp-11, + 0x1.d87c2102f7e06p-14, -0x1.49584bea41d62p-17}, + {0x1.20dd746d063e3p0, -0x1.812729a8a950fp-2, 0x1.ce2cb0a2df232p-4, + -0x1.b80eca1f51278p-6, 0x1.5572e26c46815p-8, -0x1.b715e5638b65ep-11, + 0x1.bfbb195484968p-14, -0x1.177a565c15c52p-17}, + {0x1.20dd701b44486p0, -0x1.812691145f237p-2, 0x1.ce23a06b8cfd9p-4, + -0x1.b7c1dc7245288p-6, 0x1.53e92f7f397ddp-8, -0x1.ad97cc4acf0b2p-11, + 0x1.9f028b2b09b71p-14, -0x1.cdc4da08da8c1p-18}, + {0x1.20dd5715ac332p0, -0x1.8123e680bd0ebp-2, 0x1.ce0457aded691p-4, + -0x1.b6f52d52bed4p-6, 0x1.50c291b84414cp-8, -0x1.9ea246b1ad4a9p-11, + 0x1.77654674e0cap-14, -0x1.737c11a1bcebbp-18}, + {0x1.20dce6593e114p0, -0x1.811a59c02eadcp-2, 0x1.cdab53c7cd7d5p-4, + -0x1.b526d2e321eedp-6, 0x1.4b1d32cd8b994p-8, -0x1.8963143ec0a1ep-11, + 0x1.4ad5700e4db91p-14, -0x1.231e100e43ef2p-18}, + {0x1.20db48bfd5a62p0, -0x1.80fdd84f9e308p-2, 0x1.ccd340d462983p-4, + -0x1.b196a2928768p-6, 0x1.4210c2c13a0f7p-8, -0x1.6dbdfb4ff71aep-11, + 0x1.1bca2d17fbd71p-14, -0x1.bca36f90c7cf5p-19}, + {0x1.20d64b2f8f508p0, -0x1.80b4d4f19fa8bp-2, 0x1.cb088197262e3p-4, + -0x1.ab51fd02e5b99p-6, 0x1.34e1e5e81a632p-8, -0x1.4c66377b502cep-11, + 0x1.d9ad25066213cp-15, -0x1.4b0df7dd0cfa1p-19}, + {0x1.20c8fc1243576p0, -0x1.8010cb2009e27p-2, 0x1.c7a47e9299315p-4, + -0x1.a155be5683654p-6, 0x1.233502694997bp-8, -0x1.26c94b7d813p-11, + 0x1.8094f1de25fb9p-15, -0x1.e0e3d776c6eefp-20}, + {0x1.20a9bd1611bc1p0, -0x1.7ec7fbce83f9p-2, 0x1.c1d757d7317b7p-4, + -0x1.92c160cd589fp-6, 0x1.0d307269cc5c2p-8, -0x1.fda5b0d2d1879p-12, + 0x1.2fdd7b3b14a7fp-15, -0x1.54eed4a26af5ap-20}, + {0x1.20682834f943dp0, -0x1.7c73f747bf5a9p-2, 0x1.b8c2db4a9ffd1p-4, + -0x1.7f0e4ffe989ecp-6, 0x1.e7061eae4166ep-9, -0x1.ad36e873fff2dp-12, + 0x1.d39222396128ep-16, -0x1.d83dacec5ea6bp-21}, + {0x1.1feb8d12676d7p0, -0x1.7898347284afep-2, 0x1.aba3466b34451p-4, + -0x1.663adc573e2f9p-6, 0x1.ae99fb17c3e08p-9, -0x1.602f950ad5535p-12, + 0x1.5e9717490609dp-16, -0x1.3fca107bbc8d5p-21}, + {0x1.1f12fe3c536fap0, -0x1.72b1d1f22e6d3p-2, 0x1.99fc0eed4a896p-4, + -0x1.48db0a87bd8c6p-6, 0x1.73e368895aa61p-9, -0x1.19b35d5301fc8p-12, + 0x1.007987e4bb033p-16, -0x1.a7edcd4c2dc7p-22}, + {0x1.1db7b0df84d5dp0, -0x1.6a4e4a41cde02p-2, 0x1.83bbded16455dp-4, + -0x1.2809b3b36977ep-6, 0x1.39c08bab44679p-9, -0x1.b7b45a70ed119p-13, + 0x1.6e99b36410e7bp-17, -0x1.13619bb7ebc0cp-22}, + {0x1.1bb1c85c4a527p0, -0x1.5f23b99a249a3p-2, 0x1.694c91fa0d12cp-4, + -0x1.053e1ce11c72dp-6, 0x1.02bf72c50ea78p-9, -0x1.4f478fb56cb02p-13, + 0x1.005f80ecbe213p-17, -0x1.5f2446bde7f5bp-23}, + {0x1.18dec3bd51f9dp0, -0x1.5123f58346186p-2, 0x1.4b8a1ca536ab4p-4, + -0x1.c4243015cc723p-7, 0x1.a1a8a01d351efp-10, -0x1.f466b34f1d86bp-14, + 0x1.5f835eea0bf6ap-18, -0x1.b83165b939234p-24}, + {0x1.152804c3369f4p0, -0x1.4084cd4afd4bcp-2, 0x1.2ba2e836e47aap-4, + -0x1.800f2dfc6904bp-7, 0x1.4a6daf0669c59p-10, -0x1.6e326ab872317p-14, + 0x1.d9761a6a755a5p-19, -0x1.0fca33f9dd4b5p-24}, + {0x1.1087ad68356aap0, -0x1.2dbb044707459p-2, 0x1.0aea8ceaa0384p-4, + -0x1.40b516d52b3d2p-7, 0x1.00c9e05f01d22p-10, -0x1.076afb0dc0ff7p-14, + 0x1.39fadec400657p-19, -0x1.4b5761352e7e3p-25}, + {0x1.0b0a7a8ba4a22p0, -0x1.196990d22d4a1p-2, 0x1.d5551e6ac0c4dp-5, + -0x1.07cce1770bd1ap-7, 0x1.890347b8848bfp-11, -0x1.757ec96750b6ap-15, + 0x1.9b258a1e06bcep-20, -0x1.8fc6d22da7572p-26}, + {0x1.04ce2be70fb47p0, -0x1.0449e4b0b9cacp-2, 0x1.97f7424f4b0e7p-5, + -0x1.ac825439c42f4p-8, 0x1.28f5f65426dfbp-11, -0x1.05b699a90f90fp-15, + 0x1.0a888eecf4593p-20, -0x1.deace2b32bb31p-27}, + {0x1.fbf9fb0e11cc8p-1, -0x1.de2640856545ap-3, 0x1.5f5b1f47f851p-5, + -0x1.588bc71eb41b9p-8, 0x1.bc6a0a772f56dp-12, -0x1.6b9fad1f1657ap-16, + 0x1.573204ba66504p-21, -0x1.1d38065c94e44p-27}, + {0x1.ed8f18c99e031p-1, -0x1.b4cb6acd903b4p-3, 0x1.2c7f3dddd6fc1p-5, + -0x1.13052067df4ep-8, 0x1.4a5027444082fp-12, -0x1.f672bab0e2554p-17, + 0x1.b83c756348cc9p-22, -0x1.534f1a1079499p-28}, + {0x1.debd33044166dp-1, -0x1.8d7cd9053f7d8p-3, 0x1.ff9957fb3d6e7p-6, + -0x1.b50be55de0f36p-9, 0x1.e92c8ec53a628p-13, -0x1.5a4b88d508007p-17, + 0x1.1a27737559e26p-22, -0x1.942ae62cb2c14p-29}, + {0x1.cfdbf0386f3bdp-1, -0x1.68e33d93b0dc4p-3, 0x1.b2683d58f53dep-6, + -0x1.5a9174e70d26fp-9, 0x1.69ddd326d49cdp-13, -0x1.dd8f397a8219cp-18, + 0x1.6a755016ad4ddp-23, -0x1.e366e0139187dp-30}, + {0x1.c132adb8d7464p-1, -0x1.475a899f61b46p-3, 0x1.70a431397a77cp-6, + -0x1.12e3d35beeee2p-9, 0x1.0c16b05738333p-13, -0x1.4a47f873e144ep-18, + 0x1.d3d494c698c02p-24, -0x1.2302c59547fe5p-30}, + {0x1.b2f5fd05555e7p-1, -0x1.28feefbe03ec7p-3, 0x1.3923acbb3a676p-6, + -0x1.b4ff793cd6358p-10, 0x1.8ea0eb8c913bcp-14, -0x1.cb31ec2baceb1p-19, + 0x1.30011e7e80c04p-24, -0x1.617710635cb1dp-31}, + {0x1.a54853cd9593ep-1, -0x1.0dbdbaea4dc8ep-3, 0x1.0a93e2c20a0fdp-6, + -0x1.5c969ff401ea8p-10, 0x1.29e0cc64fe627p-14, -0x1.4160d8e9d3c2ap-19, + 0x1.8e7b67594624ap-25, -0x1.b1cf2c975b09bp-32}, + {0x1.983ceece09ff8p-1, -0x1.eacc78f7a2dp-4, 0x1.c74418410655fp-7, + -0x1.1756a050e441ep-10, 0x1.bff3650f7f548p-15, -0x1.c56c0217d3adap-20, + 0x1.07b4918d0b489p-25, -0x1.0d4be8c1c50f8p-32}, +}; + +} // namespace erff_internal - // Polynomials approximating erf(x)/x on ( k/8, (k + 1)/8 ) generated by - // Sollya with: > P = fpminimax(erf(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14|], - // [|D...|], - // [k/8, (k + 1)/8]); - // for k = 0..31. - constexpr double COEFFS[32][8] = { - {0x1.20dd750429b6dp0, -0x1.812746b037753p-2, 0x1.ce2f219e8596ap-4, - -0x1.b82cdacb78fdap-6, 0x1.56479297dfda5p-8, -0x1.8b3ac5455ef02p-11, - -0x1.126fcac367e3bp-8, 0x1.2d0bdb3ba4984p-4}, - {0x1.20dd750429b6dp0, -0x1.812746b0379a8p-2, 0x1.ce2f21a03cf2ap-4, - -0x1.b82ce30de083ep-6, 0x1.565bcad3eb60fp-8, -0x1.c02c66f659256p-11, - 0x1.f92f673385229p-14, -0x1.def402648ae9p-17}, - {0x1.20dd750429b34p0, -0x1.812746b032dcep-2, 0x1.ce2f219d84aaep-4, - -0x1.b82ce22dcf139p-6, 0x1.565b9efcd4af1p-8, -0x1.c021f1af414bcp-11, - 0x1.f7c6d177eff82p-14, -0x1.c9e4410dcf865p-17}, - {0x1.20dd750426eabp0, -0x1.812746ae592c7p-2, 0x1.ce2f211525f14p-4, - -0x1.b82ccc125e63fp-6, 0x1.56596f261cfd3p-8, -0x1.bfde1ff8eeecfp-11, - 0x1.f31a9d15dc5d8p-14, -0x1.a5a4362844b3cp-17}, - {0x1.20dd75039c705p0, -0x1.812746777e74dp-2, 0x1.ce2f17af98a1bp-4, - -0x1.b82be4b817cbep-6, 0x1.564bec2e2962ep-8, -0x1.bee86f9da3558p-11, - 0x1.e9443689dc0ccp-14, -0x1.79c0f230805d8p-17}, - {0x1.20dd74f811211p0, -0x1.81274371a3e8fp-2, 0x1.ce2ec038262e5p-4, - -0x1.b8265b82c5e1fp-6, 0x1.5615a2e239267p-8, -0x1.bc63ae023dcebp-11, - 0x1.d87c2102f7e06p-14, -0x1.49584bea41d62p-17}, - {0x1.20dd746d063e3p0, -0x1.812729a8a950fp-2, 0x1.ce2cb0a2df232p-4, - -0x1.b80eca1f51278p-6, 0x1.5572e26c46815p-8, -0x1.b715e5638b65ep-11, - 0x1.bfbb195484968p-14, -0x1.177a565c15c52p-17}, - {0x1.20dd701b44486p0, -0x1.812691145f237p-2, 0x1.ce23a06b8cfd9p-4, - -0x1.b7c1dc7245288p-6, 0x1.53e92f7f397ddp-8, -0x1.ad97cc4acf0b2p-11, - 0x1.9f028b2b09b71p-14, -0x1.cdc4da08da8c1p-18}, - {0x1.20dd5715ac332p0, -0x1.8123e680bd0ebp-2, 0x1.ce0457aded691p-4, - -0x1.b6f52d52bed4p-6, 0x1.50c291b84414cp-8, -0x1.9ea246b1ad4a9p-11, - 0x1.77654674e0cap-14, -0x1.737c11a1bcebbp-18}, - {0x1.20dce6593e114p0, -0x1.811a59c02eadcp-2, 0x1.cdab53c7cd7d5p-4, - -0x1.b526d2e321eedp-6, 0x1.4b1d32cd8b994p-8, -0x1.8963143ec0a1ep-11, - 0x1.4ad5700e4db91p-14, -0x1.231e100e43ef2p-18}, - {0x1.20db48bfd5a62p0, -0x1.80fdd84f9e308p-2, 0x1.ccd340d462983p-4, - -0x1.b196a2928768p-6, 0x1.4210c2c13a0f7p-8, -0x1.6dbdfb4ff71aep-11, - 0x1.1bca2d17fbd71p-14, -0x1.bca36f90c7cf5p-19}, - {0x1.20d64b2f8f508p0, -0x1.80b4d4f19fa8bp-2, 0x1.cb088197262e3p-4, - -0x1.ab51fd02e5b99p-6, 0x1.34e1e5e81a632p-8, -0x1.4c66377b502cep-11, - 0x1.d9ad25066213cp-15, -0x1.4b0df7dd0cfa1p-19}, - {0x1.20c8fc1243576p0, -0x1.8010cb2009e27p-2, 0x1.c7a47e9299315p-4, - -0x1.a155be5683654p-6, 0x1.233502694997bp-8, -0x1.26c94b7d813p-11, - 0x1.8094f1de25fb9p-15, -0x1.e0e3d776c6eefp-20}, - {0x1.20a9bd1611bc1p0, -0x1.7ec7fbce83f9p-2, 0x1.c1d757d7317b7p-4, - -0x1.92c160cd589fp-6, 0x1.0d307269cc5c2p-8, -0x1.fda5b0d2d1879p-12, - 0x1.2fdd7b3b14a7fp-15, -0x1.54eed4a26af5ap-20}, - {0x1.20682834f943dp0, -0x1.7c73f747bf5a9p-2, 0x1.b8c2db4a9ffd1p-4, - -0x1.7f0e4ffe989ecp-6, 0x1.e7061eae4166ep-9, -0x1.ad36e873fff2dp-12, - 0x1.d39222396128ep-16, -0x1.d83dacec5ea6bp-21}, - {0x1.1feb8d12676d7p0, -0x1.7898347284afep-2, 0x1.aba3466b34451p-4, - -0x1.663adc573e2f9p-6, 0x1.ae99fb17c3e08p-9, -0x1.602f950ad5535p-12, - 0x1.5e9717490609dp-16, -0x1.3fca107bbc8d5p-21}, - {0x1.1f12fe3c536fap0, -0x1.72b1d1f22e6d3p-2, 0x1.99fc0eed4a896p-4, - -0x1.48db0a87bd8c6p-6, 0x1.73e368895aa61p-9, -0x1.19b35d5301fc8p-12, - 0x1.007987e4bb033p-16, -0x1.a7edcd4c2dc7p-22}, - {0x1.1db7b0df84d5dp0, -0x1.6a4e4a41cde02p-2, 0x1.83bbded16455dp-4, - -0x1.2809b3b36977ep-6, 0x1.39c08bab44679p-9, -0x1.b7b45a70ed119p-13, - 0x1.6e99b36410e7bp-17, -0x1.13619bb7ebc0cp-22}, - {0x1.1bb1c85c4a527p0, -0x1.5f23b99a249a3p-2, 0x1.694c91fa0d12cp-4, - -0x1.053e1ce11c72dp-6, 0x1.02bf72c50ea78p-9, -0x1.4f478fb56cb02p-13, - 0x1.005f80ecbe213p-17, -0x1.5f2446bde7f5bp-23}, - {0x1.18dec3bd51f9dp0, -0x1.5123f58346186p-2, 0x1.4b8a1ca536ab4p-4, - -0x1.c4243015cc723p-7, 0x1.a1a8a01d351efp-10, -0x1.f466b34f1d86bp-14, - 0x1.5f835eea0bf6ap-18, -0x1.b83165b939234p-24}, - {0x1.152804c3369f4p0, -0x1.4084cd4afd4bcp-2, 0x1.2ba2e836e47aap-4, - -0x1.800f2dfc6904bp-7, 0x1.4a6daf0669c59p-10, -0x1.6e326ab872317p-14, - 0x1.d9761a6a755a5p-19, -0x1.0fca33f9dd4b5p-24}, - {0x1.1087ad68356aap0, -0x1.2dbb044707459p-2, 0x1.0aea8ceaa0384p-4, - -0x1.40b516d52b3d2p-7, 0x1.00c9e05f01d22p-10, -0x1.076afb0dc0ff7p-14, - 0x1.39fadec400657p-19, -0x1.4b5761352e7e3p-25}, - {0x1.0b0a7a8ba4a22p0, -0x1.196990d22d4a1p-2, 0x1.d5551e6ac0c4dp-5, - -0x1.07cce1770bd1ap-7, 0x1.890347b8848bfp-11, -0x1.757ec96750b6ap-15, - 0x1.9b258a1e06bcep-20, -0x1.8fc6d22da7572p-26}, - {0x1.04ce2be70fb47p0, -0x1.0449e4b0b9cacp-2, 0x1.97f7424f4b0e7p-5, - -0x1.ac825439c42f4p-8, 0x1.28f5f65426dfbp-11, -0x1.05b699a90f90fp-15, - 0x1.0a888eecf4593p-20, -0x1.deace2b32bb31p-27}, - {0x1.fbf9fb0e11cc8p-1, -0x1.de2640856545ap-3, 0x1.5f5b1f47f851p-5, - -0x1.588bc71eb41b9p-8, 0x1.bc6a0a772f56dp-12, -0x1.6b9fad1f1657ap-16, - 0x1.573204ba66504p-21, -0x1.1d38065c94e44p-27}, - {0x1.ed8f18c99e031p-1, -0x1.b4cb6acd903b4p-3, 0x1.2c7f3dddd6fc1p-5, - -0x1.13052067df4ep-8, 0x1.4a5027444082fp-12, -0x1.f672bab0e2554p-17, - 0x1.b83c756348cc9p-22, -0x1.534f1a1079499p-28}, - {0x1.debd33044166dp-1, -0x1.8d7cd9053f7d8p-3, 0x1.ff9957fb3d6e7p-6, - -0x1.b50be55de0f36p-9, 0x1.e92c8ec53a628p-13, -0x1.5a4b88d508007p-17, - 0x1.1a27737559e26p-22, -0x1.942ae62cb2c14p-29}, - {0x1.cfdbf0386f3bdp-1, -0x1.68e33d93b0dc4p-3, 0x1.b2683d58f53dep-6, - -0x1.5a9174e70d26fp-9, 0x1.69ddd326d49cdp-13, -0x1.dd8f397a8219cp-18, - 0x1.6a755016ad4ddp-23, -0x1.e366e0139187dp-30}, - {0x1.c132adb8d7464p-1, -0x1.475a899f61b46p-3, 0x1.70a431397a77cp-6, - -0x1.12e3d35beeee2p-9, 0x1.0c16b05738333p-13, -0x1.4a47f873e144ep-18, - 0x1.d3d494c698c02p-24, -0x1.2302c59547fe5p-30}, - {0x1.b2f5fd05555e7p-1, -0x1.28feefbe03ec7p-3, 0x1.3923acbb3a676p-6, - -0x1.b4ff793cd6358p-10, 0x1.8ea0eb8c913bcp-14, -0x1.cb31ec2baceb1p-19, - 0x1.30011e7e80c04p-24, -0x1.617710635cb1dp-31}, - {0x1.a54853cd9593ep-1, -0x1.0dbdbaea4dc8ep-3, 0x1.0a93e2c20a0fdp-6, - -0x1.5c969ff401ea8p-10, 0x1.29e0cc64fe627p-14, -0x1.4160d8e9d3c2ap-19, - 0x1.8e7b67594624ap-25, -0x1.b1cf2c975b09bp-32}, - {0x1.983ceece09ff8p-1, -0x1.eacc78f7a2dp-4, 0x1.c74418410655fp-7, - -0x1.1756a050e441ep-10, 0x1.bff3650f7f548p-15, -0x1.c56c0217d3adap-20, - 0x1.07b4918d0b489p-25, -0x1.0d4be8c1c50f8p-32}, - }; +LIBC_INLINE float erff(float x) { + using namespace erff_internal; using FPBits = typename fputil::FPBits<float>; FPBits xbits(x); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp.h index dfb2a2efc5e7..b2bcb2fd3ded 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp.h @@ -1,454 +1,34 @@ -//===-- Implementation header for exp ---------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for exp. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP_H #define LLVM_LIBC_SRC___SUPPORT_MATH_EXP_H -#include "exp_constants.h" -#include "exp_utils.h" -#include "src/__support/CPP/bit.h" -#include "src/__support/CPP/optional.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/dyadic_float.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/FPUtil/triple_double.h" #include "src/__support/common.h" -#include "src/__support/integer_literals.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/optimization.h" -namespace LIBC_NAMESPACE_DECL { +#include "src/__support/math/exp_double_eval.h" +#define LIBC_MATH_EXP_IMPL double_eval +namespace LIBC_NAMESPACE_DECL { namespace math { -namespace exp_internal { - -using fputil::DoubleDouble; -using fputil::TripleDouble; -using DFloat128 = typename fputil::DyadicFloat<128>; - -using LIBC_NAMESPACE::operator""_u128; - -// log2(e) -LIBC_INLINE_VAR constexpr double LOG2_E = 0x1.71547652b82fep+0; - -// Error bounds: -// Errors when using double precision. -LIBC_INLINE_VAR constexpr double EXP_ERR_D = 0x1.8p-63; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Errors when using double-double precision. -LIBC_INLINE_VAR constexpr double EXP_ERR_DD = 0x1.0p-99; -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -// -2^-12 * log(2) -// > a = -2^-12 * log(2); -// > b = round(a, 30, RN); -// > c = round(a - b, 30, RN); -// > d = round(a - b - c, D, RN); -// Errors < 1.5 * 2^-133 -LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_M12_HI = -0x1.62e42ffp-13; -LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_M12_MID = 0x1.718432a1b0e26p-47; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_M12_MID_30 = 0x1.718432ap-47; -LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_M12_LO = 0x1.b0e2633fe0685p-79; -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -// Polynomial approximations with double precision: -// Return expm1(dx) / x ~ 1 + dx / 2 + dx^2 / 6 + dx^3 / 24. -// For |dx| < 2^-13 + 2^-30: -// | output - expm1(dx) / dx | < 2^-51. -LIBC_INLINE double poly_approx_d(double dx) { - // dx^2 - double dx2 = dx * dx; - // c0 = 1 + dx / 2 - double c0 = fputil::multiply_add(dx, 0.5, 1.0); - // c1 = 1/6 + dx / 24 - double c1 = - fputil::multiply_add(dx, 0x1.5555555555555p-5, 0x1.5555555555555p-3); - // p = dx^2 * c1 + c0 = 1 + dx / 2 + dx^2 / 6 + dx^3 / 24 - double p = fputil::multiply_add(dx2, c1, c0); - return p; -} - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Polynomial approximation with double-double precision: -// Return exp(dx) ~ 1 + dx + dx^2 / 2 + ... + dx^6 / 720 -// For |dx| < 2^-13 + 2^-30: -// | output - exp(dx) | < 2^-101 -LIBC_INLINE DoubleDouble poly_approx_dd(const DoubleDouble &dx) { - // Taylor polynomial. - constexpr DoubleDouble COEFFS[] = { - {0, 0x1p0}, // 1 - {0, 0x1p0}, // 1 - {0, 0x1p-1}, // 1/2 - {0x1.5555555555555p-57, 0x1.5555555555555p-3}, // 1/6 - {0x1.5555555555555p-59, 0x1.5555555555555p-5}, // 1/24 - {0x1.1111111111111p-63, 0x1.1111111111111p-7}, // 1/120 - {-0x1.f49f49f49f49fp-65, 0x1.6c16c16c16c17p-10}, // 1/720 - }; - - DoubleDouble p = fputil::polyeval(dx, COEFFS[0], COEFFS[1], COEFFS[2], - COEFFS[3], COEFFS[4], COEFFS[5], COEFFS[6]); - return p; -} - -// Polynomial approximation with 128-bit precision: -// Return exp(dx) ~ 1 + dx + dx^2 / 2 + ... + dx^7 / 5040 -// For |dx| < 2^-13 + 2^-30: -// | output - exp(dx) | < 2^-126. -LIBC_INLINE DFloat128 poly_approx_f128(const DFloat128 &dx) { - constexpr DFloat128 COEFFS_128[]{ - {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0 - {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0 - {Sign::POS, -128, 0x80000000'00000000'00000000'00000000_u128}, // 0.5 - {Sign::POS, -130, 0xaaaaaaaa'aaaaaaaa'aaaaaaaa'aaaaaaab_u128}, // 1/6 - {Sign::POS, -132, 0xaaaaaaaa'aaaaaaaa'aaaaaaaa'aaaaaaab_u128}, // 1/24 - {Sign::POS, -134, 0x88888888'88888888'88888888'88888889_u128}, // 1/120 - {Sign::POS, -137, 0xb60b60b6'0b60b60b'60b60b60'b60b60b6_u128}, // 1/720 - {Sign::POS, -140, 0xd00d00d0'0d00d00d'00d00d00'd00d00d0_u128}, // 1/5040 - }; - - DFloat128 p = fputil::polyeval(dx, COEFFS_128[0], COEFFS_128[1], - COEFFS_128[2], COEFFS_128[3], COEFFS_128[4], - COEFFS_128[5], COEFFS_128[6], COEFFS_128[7]); - return p; -} - -// Compute exp(x) using 128-bit precision. -// TODO(lntue): investigate triple-double precision implementation for this -// step. -LIBC_INLINE DFloat128 exp_f128(double x, double kd, int idx1, int idx2) { - // Recalculate dx: - - double t1 = fputil::multiply_add(kd, MLOG_2_EXP2_M12_HI, x); // exact - double t2 = kd * MLOG_2_EXP2_M12_MID_30; // exact - double t3 = kd * MLOG_2_EXP2_M12_LO; // Error < 2^-133 - - DFloat128 dx = fputil::quick_add( - DFloat128(t1), fputil::quick_add(DFloat128(t2), DFloat128(t3))); - - // TODO: Skip recalculating exp_mid1 and exp_mid2. - DFloat128 exp_mid1 = - fputil::quick_add(DFloat128(EXP2_MID1[idx1].hi), - fputil::quick_add(DFloat128(EXP2_MID1[idx1].mid), - DFloat128(EXP2_MID1[idx1].lo))); - - DFloat128 exp_mid2 = - fputil::quick_add(DFloat128(EXP2_MID2[idx2].hi), - fputil::quick_add(DFloat128(EXP2_MID2[idx2].mid), - DFloat128(EXP2_MID2[idx2].lo))); - - DFloat128 exp_mid = fputil::quick_mul(exp_mid1, exp_mid2); - - DFloat128 p = poly_approx_f128(dx); - - DFloat128 r = fputil::quick_mul(exp_mid, p); - - r.exponent += static_cast<int>(kd) >> 12; - - return r; -} - -// Compute exp(x) with double-double precision. -LIBC_INLINE DoubleDouble exp_double_double(double x, double kd, - const DoubleDouble &exp_mid) { - // Recalculate dx: - // dx = x - k * 2^-12 * log(2) - double t1 = fputil::multiply_add(kd, MLOG_2_EXP2_M12_HI, x); // exact - double t2 = kd * MLOG_2_EXP2_M12_MID_30; // exact - double t3 = kd * MLOG_2_EXP2_M12_LO; // Error < 2^-130 - - DoubleDouble dx = fputil::exact_add(t1, t2); - dx.lo += t3; - - // Degree-6 Taylor polynomial approximation in double-double precision. - // | p - exp(x) | < 2^-100. - DoubleDouble p = poly_approx_dd(dx); - - // Error bounds: 2^-99. - DoubleDouble r = fputil::quick_mult(exp_mid, p); - - return r; -} -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -// Check for exceptional cases when -// |x| <= 2^-53 or x < log(2^-1075) or x >= 0x1.6232bdd7abcd3p+9 -LIBC_INLINE double set_exceptional(double x) { - using FPBits = typename fputil::FPBits<double>; - FPBits xbits(x); - - uint64_t x_u = xbits.uintval(); - uint64_t x_abs = xbits.abs().uintval(); - - // |x| <= 2^-53 - if (x_abs <= 0x3ca0'0000'0000'0000ULL) { - // exp(x) ~ 1 + x - return 1 + x; - } - - // x <= log(2^-1075) || x >= 0x1.6232bdd7abcd3p+9 or inf/nan. - - // x <= log(2^-1075) or -inf/nan - if (x_u >= 0xc087'4910'd52d'3052ULL) { - // exp(-Inf) = 0 - if (xbits.is_inf()) - return 0.0; - - // exp(nan) = nan - if (xbits.is_nan()) - return x; - -#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (fputil::quick_get_round() == FE_UPWARD) - return FPBits::min_subnormal().get_val(); -#endif - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_UNDERFLOW); - return 0.0; - } - - // x >= round(log(MAX_NORMAL), D, RU) = 0x1.62e42fefa39fp+9 or +inf/nan - // x is finite - if (x_u < 0x7ff0'0000'0000'0000ULL) { -#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - int rounding = fputil::quick_get_round(); - if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) - return FPBits::max_normal().get_val(); -#endif - - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW); - } - // x is +inf or nan - return x + FPBits::inf().get_val(); -} - -} // namespace exp_internal - -LIBC_INLINE double exp(double x) { - using namespace exp_internal; - using FPBits = typename fputil::FPBits<double>; - FPBits xbits(x); - - uint64_t x_u = xbits.uintval(); - - // Upper bound: max normal number = 2^1023 * (2 - 2^-52) - // > round(log (2^1023 ( 2 - 2^-52 )), D, RU) = 0x1.62e42fefa39fp+9 - // > round(log (2^1023 ( 2 - 2^-52 )), D, RD) = 0x1.62e42fefa39efp+9 - // > round(log (2^1023 ( 2 - 2^-52 )), D, RN) = 0x1.62e42fefa39efp+9 - // > round(exp(0x1.62e42fefa39fp+9), D, RN) = infty - - // Lower bound: min denormal number / 2 = 2^-1075 - // > round(log(2^-1075), D, RN) = -0x1.74910d52d3052p9 - - // Another lower bound: min normal number = 2^-1022 - // > round(log(2^-1022), D, RN) = -0x1.6232bdd7abcd2p9 - - // x < log(2^-1075) or x >= 0x1.6232bdd7abcd3p+9 or |x| < 2^-53. - if (LIBC_UNLIKELY(x_u >= 0xc0874910d52d3052 || - (x_u < 0xbca0000000000000 && x_u >= 0x40862e42fefa39f0) || - x_u < 0x3ca0000000000000)) { - return set_exceptional(x); - } - - // Now log(2^-1075) <= x <= -2^-53 or 2^-53 <= x < log(2^1023 * (2 - 2^-52)) - - // Range reduction: - // Let x = log(2) * (hi + mid1 + mid2) + lo - // in which: - // hi is an integer - // mid1 * 2^6 is an integer - // mid2 * 2^12 is an integer - // then: - // exp(x) = 2^hi * 2^(mid1) * 2^(mid2) * exp(lo). - // With this formula: - // - multiplying by 2^hi is exact and cheap, simply by adding the exponent - // field. - // - 2^(mid1) and 2^(mid2) are stored in 2 x 64-element tables. - // - exp(lo) ~ 1 + lo + a0 * lo^2 + ... - // - // They can be defined by: - // hi + mid1 + mid2 = 2^(-12) * round(2^12 * log_2(e) * x) - // If we store L2E = round(log2(e), D, RN), then: - // log2(e) - L2E ~ 1.5 * 2^(-56) - // So the errors when computing in double precision is: - // | x * 2^12 * log_2(e) - D(x * 2^12 * L2E) | <= - // <= | x * 2^12 * log_2(e) - x * 2^12 * L2E | + - // + | x * 2^12 * L2E - D(x * 2^12 * L2E) | - // <= 2^12 * ( |x| * 1.5 * 2^-56 + eps(x)) for RN - // 2^12 * ( |x| * 1.5 * 2^-56 + 2*eps(x)) for other rounding modes. - // So if: - // hi + mid1 + mid2 = 2^(-12) * round(x * 2^12 * L2E) is computed entirely - // in double precision, the reduced argument: - // lo = x - log(2) * (hi + mid1 + mid2) is bounded by: - // |lo| <= 2^-13 + (|x| * 1.5 * 2^-56 + 2*eps(x)) - // < 2^-13 + (1.5 * 2^9 * 1.5 * 2^-56 + 2*2^(9 - 52)) - // < 2^-13 + 2^-41 - // - - // The following trick computes the round(x * L2E) more efficiently - // than using the rounding instructions, with the tradeoff for less accuracy, - // and hence a slightly larger range for the reduced argument `lo`. - // - // To be precise, since |x| < |log(2^-1075)| < 1.5 * 2^9, - // |x * 2^12 * L2E| < 1.5 * 2^9 * 1.5 < 2^23, - // So we can fit the rounded result round(x * 2^12 * L2E) in int32_t. - // Thus, the goal is to be able to use an additional addition and fixed width - // shift to get an int32_t representing round(x * 2^12 * L2E). - // - // Assuming int32_t using 2-complement representation, since the mantissa part - // of a double precision is unsigned with the leading bit hidden, if we add an - // extra constant C = 2^e1 + 2^e2 with e1 > e2 >= 2^25 to the product, the - // part that are < 2^e2 in resulted mantissa of (x*2^12*L2E + C) can be - // considered as a proper 2-complement representations of x*2^12*L2E. - // - // One small problem with this approach is that the sum (x*2^12*L2E + C) in - // double precision is rounded to the least significant bit of the dorminant - // factor C. In order to minimize the rounding errors from this addition, we - // want to minimize e1. Another constraint that we want is that after - // shifting the mantissa so that the least significant bit of int32_t - // corresponds to the unit bit of (x*2^12*L2E), the sign is correct without - // any adjustment. So combining these 2 requirements, we can choose - // C = 2^33 + 2^32, so that the sign bit corresponds to 2^31 bit, and hence - // after right shifting the mantissa, the resulting int32_t has correct sign. - // With this choice of C, the number of mantissa bits we need to shift to the - // right is: 52 - 33 = 19. - // - // Moreover, since the integer right shifts are equivalent to rounding down, - // we can add an extra 0.5 so that it will become round-to-nearest, tie-to- - // +infinity. So in particular, we can compute: - // hmm = x * 2^12 * L2E + C, - // where C = 2^33 + 2^32 + 2^-1, then if - // k = int32_t(lower 51 bits of double(x * 2^12 * L2E + C) >> 19), - // the reduced argument: - // lo = x - log(2) * 2^-12 * k is bounded by: - // |lo| <= 2^-13 + 2^-41 + 2^-12*2^-19 - // = 2^-13 + 2^-31 + 2^-41. - // - // Finally, notice that k only uses the mantissa of x * 2^12 * L2E, so the - // exponent 2^12 is not needed. So we can simply define - // C = 2^(33 - 12) + 2^(32 - 12) + 2^(-13 - 12), and - // k = int32_t(lower 51 bits of double(x * L2E + C) >> 19). - - // Rounding errors <= 2^-31 + 2^-41. - double tmp = fputil::multiply_add(x, LOG2_E, 0x1.8000'0000'4p21); - int k = static_cast<int>(cpp::bit_cast<uint64_t>(tmp) >> 19); - double kd = static_cast<double>(k); - - uint32_t idx1 = (k >> 6) & 0x3f; - uint32_t idx2 = k & 0x3f; - int hi = k >> 12; - - bool denorm = (hi <= -1022); - - DoubleDouble exp_mid1{EXP2_MID1[idx1].mid, EXP2_MID1[idx1].hi}; - DoubleDouble exp_mid2{EXP2_MID2[idx2].mid, EXP2_MID2[idx2].hi}; - - DoubleDouble exp_mid = fputil::quick_mult(exp_mid1, exp_mid2); - - // |x - (hi + mid1 + mid2) * log(2) - dx| < 2^11 * eps(M_LOG_2_EXP2_M12.lo) - // = 2^11 * 2^-13 * 2^-52 - // = 2^-54. - // |dx| < 2^-13 + 2^-30. - double lo_h = fputil::multiply_add(kd, MLOG_2_EXP2_M12_HI, x); // exact - double dx = fputil::multiply_add(kd, MLOG_2_EXP2_M12_MID, lo_h); - - // We use the degree-4 Taylor polynomial to approximate exp(lo): - // exp(lo) ~ 1 + lo + lo^2 / 2 + lo^3 / 6 + lo^4 / 24 = 1 + lo * P(lo) - // So that the errors are bounded by: - // |P(lo) - expm1(lo)/lo| < |lo|^4 / 64 < 2^(-13 * 4) / 64 = 2^-58 - // Let P_ be an evaluation of P where all intermediate computations are in - // double precision. Using either Horner's or Estrin's schemes, the evaluated - // errors can be bounded by: - // |P_(dx) - P(dx)| < 2^-51 - // => |dx * P_(dx) - expm1(lo) | < 1.5 * 2^-64 - // => 2^(mid1 + mid2) * |dx * P_(dx) - expm1(lo)| < 1.5 * 2^-63. - // Since we approximate - // 2^(mid1 + mid2) ~ exp_mid.hi + exp_mid.lo, - // We use the expression: - // (exp_mid.hi + exp_mid.lo) * (1 + dx * P_(dx)) ~ - // ~ exp_mid.hi + (exp_mid.hi * dx * P_(dx) + exp_mid.lo) - // with errors bounded by 1.5 * 2^-63. - - double mid_lo = dx * exp_mid.hi; - - // Approximate expm1(dx)/dx ~ 1 + dx / 2 + dx^2 / 6 + dx^3 / 24. - double p = poly_approx_d(dx); - - double lo = fputil::multiply_add(p, mid_lo, exp_mid.lo); - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - if (LIBC_UNLIKELY(denorm)) { - return ziv_test_denorm</*SKIP_ZIV_TEST=*/true>(hi, exp_mid.hi, lo, - EXP_ERR_D) - .value(); - } else { - // to multiply by 2^hi, a fast way is to simply add hi to the exponent - // field. - int64_t exp_hi = static_cast<int64_t>(hi) * (1LL << FPBits::FRACTION_LEN); - double r = - cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(exp_mid.hi + lo)); - return r; - } -#else - if (LIBC_UNLIKELY(denorm)) { - if (auto r = ziv_test_denorm(hi, exp_mid.hi, lo, EXP_ERR_D); - LIBC_LIKELY(r.has_value())) - return r.value(); - } else { - double upper = exp_mid.hi + (lo + EXP_ERR_D); - double lower = exp_mid.hi + (lo - EXP_ERR_D); - - if (LIBC_LIKELY(upper == lower)) { - // to multiply by 2^hi, a fast way is to simply add hi to the exponent - // field. - int64_t exp_hi = static_cast<int64_t>(hi) * (1LL << FPBits::FRACTION_LEN); - double r = cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(upper)); - return r; - } - } - - // Use double-double - DoubleDouble r_dd = exp_double_double(x, kd, exp_mid); - - if (LIBC_UNLIKELY(denorm)) { - if (auto r = ziv_test_denorm(hi, r_dd.hi, r_dd.lo, EXP_ERR_DD); - LIBC_LIKELY(r.has_value())) - return r.value(); - } else { - double upper_dd = r_dd.hi + (r_dd.lo + EXP_ERR_DD); - double lower_dd = r_dd.hi + (r_dd.lo - EXP_ERR_DD); - - if (LIBC_LIKELY(upper_dd == lower_dd)) { - int64_t exp_hi = static_cast<int64_t>(hi) * (1LL << FPBits::FRACTION_LEN); - double r = - cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(upper_dd)); - return r; - } - } - - // Use 128-bit precision - DFloat128 r_f128 = exp_f128(x, kd, idx1, idx2); - - return static_cast<double>(r_f128); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +using LIBC_MATH_EXP_IMPL::exp; } // namespace math - } // namespace LIBC_NAMESPACE_DECL +#undef LIBC_MATH_EXP_IMPL + #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp10f_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp10f_double_eval.h index e1a7cc9d68e9..a2d55f9b98b8 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp10f_double_eval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp10f_double_eval.h @@ -19,6 +19,7 @@ #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" #include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/math/exp10f_utils.h" @@ -27,67 +28,49 @@ namespace LIBC_NAMESPACE_DECL { namespace math { namespace double_eval { -LIBC_INLINE float exp10f(float x) { +LIBC_INLINE float exp10f_mid(float x) { + // Range reduction: 10^x = 2^(mid + hi) * 10^lo + auto rr = exp_b_range_reduc<Exp10Base>(x); + + // The low part is approximated by a degree-5 minimax polynomial. + using fputil::multiply_add; + double lo2 = rr.lo * rr.lo; + double c0 = multiply_add(rr.lo, Exp10Base::COEFFS[0], 1.0); + double c1 = multiply_add(rr.lo, Exp10Base::COEFFS[2], Exp10Base::COEFFS[1]); + double c2 = multiply_add(rr.lo, Exp10Base::COEFFS[4], Exp10Base::COEFFS[3]); + double p = multiply_add(lo2, c2, c1); + // 10^x = 2^(mid + hi) * 10^lo + // ~ mh * (1 + COEFFS[0] * lo + ... + COEFFS[4] * lo^5) + return static_cast<float>(multiply_add(p, lo2 * rr.mh, c0 * rr.mh)); +} + +LIBC_COLD LIBC_NOINLINE LIBC_INLINE float exp10f_slow(float x) { using FPBits = fputil::FPBits<float>; FPBits xbits(x); uint32_t x_u = xbits.uintval(); uint32_t x_abs = x_u & 0x7fff'ffffU; - // When |x| >= log10(2^128), or x is nan - if (LIBC_UNLIKELY(x_abs >= 0x421a'209bU)) { - // When x < log10(2^-150) or nan - if (x_u > 0xc234'9e35U) { - // exp(-Inf) = 0 - if (xbits.is_inf()) - return 0.0f; - // exp(nan) = nan - if (xbits.is_nan()) - return x; + // x >= log10(2^128), or positive NaN. + if (LIBC_UNLIKELY(x_u >= 0x421a'209bU && x_u < 0x8000'0000U)) { + // x is finite. + if (x_u < 0x7f80'0000U) { #ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (fputil::fenv_is_round_up()) - return FPBits::min_subnormal().get_val(); -#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_UNDERFLOW); - return 0.0f; - } - // x >= log10(2^128) or nan - if (xbits.is_pos() && (x_u >= 0x421a'209bU)) { - // x is finite - if (x_u < 0x7f80'0000U) { -#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - int rounding = fputil::quick_get_round(); - if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) - return FPBits::max_normal().get_val(); + int rounding = fputil::quick_get_round(); + if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) + return FPBits::max_normal().get_val(); #endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW); - } - // x is +inf or nan - return x + FPBits::inf().get_val(); + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_OVERFLOW); } + // x is +inf or nan + return x + FPBits::inf().get_val(); } // When |x| <= log10(2)*2^-6 - if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) { - if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) { // x = -0x1.bcb7b2p-27f -#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - return 0x1.fffffep-1f; -#else // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (fputil::fenv_is_round_to_nearest()) - return 0x1.fffffep-1f; -#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - } - // |x| < 2^-25 - // 10^x ~ 1 + log(10) * x - if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { - return fputil::multiply_add(x, 0x1.26bb1cp+1f, 1.0f); - } - + if (LIBC_UNLIKELY(x_abs <= 0x3b9a'209bU)) return static_cast<float>(Exp10Base::powb_lo(x)); - } // Exceptional value. if (LIBC_UNLIKELY(x_u == 0x3d14'd956U)) { // x = 0x1.29b2acp-5f @@ -124,28 +107,57 @@ LIBC_INLINE float exp10f(float x) { } } - // Range reduction: 10^x = 2^(mid + hi) * 10^lo - // rr = (2^(mid + hi), lo) - auto rr = exp_b_range_reduc<Exp10Base>(x); + // When |x| >= log10(2^128), or x is nan + if (LIBC_UNLIKELY(x_abs >= 0x421a'209bU)) { + // When x < log10(2^-150) or nan + if (x_u > 0xc234'9e35U) { + // exp(-Inf) = 0 + if (xbits.is_inf()) + return 0.0f; + // exp(nan) = nan + if (xbits.is_nan()) + return x; +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (fputil::fenv_is_round_up()) + return FPBits::min_subnormal().get_val(); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_UNDERFLOW); + return 0.0f; + } + } - // The low part is approximated by a degree-5 minimax polynomial. - // 10^lo ~ 1 + COEFFS[0] * lo + ... + COEFFS[4] * lo^5 - using fputil::multiply_add; - double lo2 = rr.lo * rr.lo; - // c0 = 1 + COEFFS[0] * lo - double c0 = multiply_add(rr.lo, Exp10Base::COEFFS[0], 1.0); - // c1 = COEFFS[1] + COEFFS[2] * lo - double c1 = multiply_add(rr.lo, Exp10Base::COEFFS[2], Exp10Base::COEFFS[1]); - // c2 = COEFFS[3] + COEFFS[4] * lo - double c2 = multiply_add(rr.lo, Exp10Base::COEFFS[4], Exp10Base::COEFFS[3]); - // p = c1 + c2 * lo^2 - // = COEFFS[1] + COEFFS[2] * lo + COEFFS[3] * lo^2 + COEFFS[4] * lo^3 - double p = multiply_add(lo2, c2, c1); - // 10^lo ~ c0 + p * lo^2 - // 10^x = 2^(mid + hi) * 10^lo - // ~ mh * (c0 + p * lo^2) - // = (mh * c0) + p * (mh * lo^2) - return static_cast<float>(multiply_add(p, lo2 * rr.mh, c0 * rr.mh)); + return exp10f_mid(x); +} + +LIBC_INLINE float exp10f(float x) { + using FPBits = fputil::FPBits<float>; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + + if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { + if (LIBC_UNLIKELY(x_u == 0xb25e'5bd9U)) { // x = -0x1.bcb7b2p-27f +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return 0x1.fffffep-1f; +#else // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (fputil::fenv_is_round_to_nearest()) + return 0x1.fffffep-1f; +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + } + // |x| < 2^-25 + // 10^x ~ 1 + log(10) * x + return fputil::multiply_add(x, 0x1.26bb1cp+1f, 1.0f); + } + + if (LIBC_LIKELY( + x_abs > 0x3b9a'209bU && + (x_u < 0x421a'209bU || (xbits.is_neg() && x_u <= 0xc234'9e35U)) && + x_u != 0x3d14'd956U && (x_u & 0x800f'ffffU) != 0)) + return exp10f_mid(x); + + return exp10f_slow(x); } } // namespace double_eval diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2.h index 084578796e42..12bad5db2a9b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2.h @@ -1,445 +1,34 @@ -//===-- Implementation header for exp2 --------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for exp2. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_H #define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_H -#include "common_constants.h" // Lookup tables EXP2_MID1 and EXP_M2. -#include "exp_constants.h" -#include "exp_utils.h" // ziv_test_denorm. -#include "src/__support/CPP/bit.h" -#include "src/__support/CPP/optional.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/dyadic_float.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/FPUtil/triple_double.h" #include "src/__support/common.h" -#include "src/__support/integer_literals.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/optimization.h" -namespace LIBC_NAMESPACE_DECL { +#include "src/__support/math/exp2_double_eval.h" +#define LIBC_MATH_EXP2_IMPL double_eval +namespace LIBC_NAMESPACE_DECL { namespace math { -namespace exp2_internal { - -using namespace common_constants_internal; - -using fputil::DoubleDouble; -using fputil::TripleDouble; -using DFloat128 = typename fputil::DyadicFloat<128>; - -using LIBC_NAMESPACE::operator""_u128; - -// Error bounds: -// Errors when using double precision. -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE -LIBC_INLINE_VAR constexpr double ERR_D = 0x1.0p-63; -#else -LIBC_INLINE_VAR constexpr double ERR_D = 0x1.8p-63; -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Errors when using double-double precision. -LIBC_INLINE_VAR constexpr double ERR_DD = 0x1.0p-100; -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -// Polynomial approximations with double precision. Generated by Sollya with: -// > P = fpminimax((2^x - 1)/x, 3, [|D...|], [-2^-13 - 2^-30, 2^-13 + 2^-30]); -// > P; -// Error bounds: -// | output - (2^dx - 1) / dx | < 1.5 * 2^-52. -LIBC_INLINE double poly_approx_d(double dx) { - // dx^2 - double dx2 = dx * dx; - double c0 = - fputil::multiply_add(dx, 0x1.ebfbdff82c58ep-3, 0x1.62e42fefa39efp-1); - double c1 = - fputil::multiply_add(dx, 0x1.3b2aba7a95a89p-7, 0x1.c6b08e8fc0c0ep-5); - double p = fputil::multiply_add(dx2, c1, c0); - return p; -} - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Polynomial approximation with double-double precision. Generated by Solya -// with: -// > P = fpminimax((2^x - 1)/x, 5, [|DD...|], [-2^-13 - 2^-30, 2^-13 + 2^-30]); -// Error bounds: -// | output - 2^(dx) | < 2^-101 -LIBC_INLINE DoubleDouble poly_approx_dd(const DoubleDouble &dx) { - // Taylor polynomial. - constexpr DoubleDouble COEFFS[] = { - {0, 0x1p0}, - {0x1.abc9e3b39824p-56, 0x1.62e42fefa39efp-1}, - {-0x1.5e43a53e4527bp-57, 0x1.ebfbdff82c58fp-3}, - {-0x1.d37963a9444eep-59, 0x1.c6b08d704a0cp-5}, - {0x1.4eda1a81133dap-62, 0x1.3b2ab6fba4e77p-7}, - {-0x1.c53fd1ba85d14p-64, 0x1.5d87fe7a265a5p-10}, - {0x1.d89250b013eb8p-70, 0x1.430912f86cb8ep-13}, - }; - - DoubleDouble p = fputil::polyeval(dx, COEFFS[0], COEFFS[1], COEFFS[2], - COEFFS[3], COEFFS[4], COEFFS[5], COEFFS[6]); - return p; -} - -// Polynomial approximation with 128-bit precision: -// Return exp(dx) ~ 1 + a0 * dx + a1 * dx^2 + ... + a6 * dx^7 -// For |dx| < 2^-13 + 2^-30: -// | output - exp(dx) | < 2^-126. -LIBC_INLINE DFloat128 poly_approx_f128(const DFloat128 &dx) { - constexpr DFloat128 COEFFS_128[]{ - {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0 - {Sign::POS, -128, 0xb17217f7'd1cf79ab'c9e3b398'03f2f6af_u128}, - {Sign::POS, -128, 0x3d7f7bff'058b1d50'de2d60dd'9c9a1d9f_u128}, - {Sign::POS, -132, 0xe35846b8'2505fc59'9d3b15d9'e7fb6897_u128}, - {Sign::POS, -134, 0x9d955b7d'd273b94e'184462f6'bcd2b9e7_u128}, - {Sign::POS, -137, 0xaec3ff3c'53398883'39ea1bb9'64c51a89_u128}, - {Sign::POS, -138, 0x2861225f'345c396a'842c5341'8fa8ae61_u128}, - {Sign::POS, -144, 0xffe5fe2d'109a319d'7abeb5ab'd5ad2079_u128}, - }; - - DFloat128 p = fputil::polyeval(dx, COEFFS_128[0], COEFFS_128[1], - COEFFS_128[2], COEFFS_128[3], COEFFS_128[4], - COEFFS_128[5], COEFFS_128[6], COEFFS_128[7]); - return p; -} - -// Compute 2^(x) using 128-bit precision. -// TODO(lntue): investigate triple-double precision implementation for this -// step. -LIBC_INLINE DFloat128 exp2_f128(double x, int hi, int idx1, int idx2) { - DFloat128 dx = DFloat128(x); - - // TODO: Skip recalculating exp_mid1 and exp_mid2. - DFloat128 exp_mid1 = - fputil::quick_add(DFloat128(EXP2_MID1[idx1].hi), - fputil::quick_add(DFloat128(EXP2_MID1[idx1].mid), - DFloat128(EXP2_MID1[idx1].lo))); - - DFloat128 exp_mid2 = - fputil::quick_add(DFloat128(EXP2_MID2[idx2].hi), - fputil::quick_add(DFloat128(EXP2_MID2[idx2].mid), - DFloat128(EXP2_MID2[idx2].lo))); - - DFloat128 exp_mid = fputil::quick_mul(exp_mid1, exp_mid2); - - DFloat128 p = poly_approx_f128(dx); - - DFloat128 r = fputil::quick_mul(exp_mid, p); - - r.exponent += hi; - - return r; -} - -// Compute 2^x with double-double precision. -LIBC_INLINE DoubleDouble exp2_double_double(double x, - const DoubleDouble &exp_mid) { - DoubleDouble dx({0, x}); - - // Degree-6 polynomial approximation in double-double precision. - // | p - 2^x | < 2^-103. - DoubleDouble p = poly_approx_dd(dx); - - // Error bounds: 2^-102. - DoubleDouble r = fputil::quick_mult(exp_mid, p); - - return r; -} -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -// When output is denormal. -LIBC_INLINE double exp2_denorm(double x) { - // Range reduction. - int k = - static_cast<int>(cpp::bit_cast<uint64_t>(x + 0x1.8000'0000'4p21) >> 19); - double kd = static_cast<double>(k); - - uint32_t idx1 = (k >> 6) & 0x3f; - uint32_t idx2 = k & 0x3f; - - int hi = k >> 12; - - DoubleDouble exp_mid1{EXP2_MID1[idx1].mid, EXP2_MID1[idx1].hi}; - DoubleDouble exp_mid2{EXP2_MID2[idx2].mid, EXP2_MID2[idx2].hi}; - DoubleDouble exp_mid = fputil::quick_mult(exp_mid1, exp_mid2); - - // |dx| < 2^-13 + 2^-30. - double dx = fputil::multiply_add(kd, -0x1.0p-12, x); // exact - - double mid_lo = dx * exp_mid.hi; - - // Approximate (2^dx - 1)/dx ~ 1 + a0*dx + a1*dx^2 + a2*dx^3 + a3*dx^4. - double p = poly_approx_d(dx); - - double lo = fputil::multiply_add(p, mid_lo, exp_mid.lo); - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - return ziv_test_denorm</*SKIP_ZIV_TEST=*/true>(hi, exp_mid.hi, lo, ERR_D) - .value(); -#else - using FPBits = fputil::FPBits<double>; - - if (auto r = ziv_test_denorm(hi, exp_mid.hi, lo, ERR_D); - LIBC_LIKELY(r.has_value())) { - double res = r.value(); - if (LIBC_UNLIKELY(FPBits(res).is_normal())) - return res; - if (x != fputil::nearest_integer(x)) { - fputil::set_errno_if_required(ERANGE); - fputil::raise_underflow_except_if_required<double>(); - } - return res; - } - - // Use double-double - DoubleDouble r_dd = exp2_double_double(dx, exp_mid); - - if (auto r = ziv_test_denorm(hi, r_dd.hi, r_dd.lo, ERR_DD); - LIBC_LIKELY(r.has_value())) { - double res = r.value(); - if (LIBC_UNLIKELY(FPBits(res).is_normal())) - return res; - if (x != fputil::nearest_integer(x)) { - fputil::set_errno_if_required(ERANGE); - fputil::raise_underflow_except_if_required<double>(); - } - return res; - } - - // Use 128-bit precision - DFloat128 r_f128 = exp2_f128(dx, hi, idx1, idx2); - - return static_cast<double>(r_f128); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} - -// Check for exceptional cases when: -// * log2(1 - 2^-54) < x < log2(1 + 2^-53) -// * x >= 1024 -// * x <= -1022 -// * x is inf or nan -LIBC_INLINE double set_exceptional(double x) { - using FPBits = typename fputil::FPBits<double>; - FPBits xbits(x); - - uint64_t x_u = xbits.uintval(); - uint64_t x_abs = xbits.abs().uintval(); - - // |x| < log2(1 + 2^-53) - if (x_abs <= 0x3ca71547652b82fd) { - // 2^(x) ~ 1 + x/2 - return fputil::multiply_add(x, 0.5, 1.0); - } - - // x <= -1022 || x >= 1024 or inf/nan. - if (x_u > 0xc08ff00000000000) { - // x <= -1075 or -inf/nan - if (x_u >= 0xc090cc0000000000) { - // exp(-Inf) = 0 - if (xbits.is_inf()) - return 0.0; - - // exp(nan) = nan - if (xbits.is_nan()) - return x + FPBits::inf().get_val(); - - fputil::set_errno_if_required(ERANGE); - fputil::raise_underflow_except_if_required<double>(); -#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (fputil::quick_get_round() == FE_UPWARD) - return FPBits::min_subnormal().get_val(); -#endif - return 0.0; - } - - return exp2_denorm(x); - } - - // x >= 1024 or +inf/nan - // x is finite - if (x_u < 0x7ff0'0000'0000'0000ULL) { - fputil::set_errno_if_required(ERANGE); - fputil::raise_overflow_except_if_required<double>(); -#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - int rounding = fputil::quick_get_round(); - if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) - return FPBits::max_normal().get_val(); -#endif - return FPBits::inf().get_val(); - } - // x is +inf or nan - return x + FPBits::inf().get_val(); -} - -} // namespace exp2_internal - -LIBC_INLINE double exp2(double x) { - using namespace exp2_internal; - using FPBits = typename fputil::FPBits<double>; - FPBits xbits(x); - - uint64_t x_u = xbits.uintval(); - - // x < -1022 or x >= 1024 or log2(1 - 2^-54) < x < log2(1 + 2^-53). - if (LIBC_UNLIKELY(x_u > 0xc08ff00000000000 || - (x_u <= 0xbc971547652b82fe && x_u >= 0x4090000000000000) || - x_u <= 0x3ca71547652b82fd)) { - return set_exceptional(x); - } - - // Now -1075 < x <= log2(1 - 2^-54) or log2(1 + 2^-53) < x < 1024 - - // Range reduction: - // Let x = (hi + mid1 + mid2) + lo - // in which: - // hi is an integer - // mid1 * 2^6 is an integer - // mid2 * 2^12 is an integer - // then: - // 2^(x) = 2^hi * 2^(mid1) * 2^(mid2) * 2^(lo). - // With this formula: - // - multiplying by 2^hi is exact and cheap, simply by adding the exponent - // field. - // - 2^(mid1) and 2^(mid2) are stored in 2 x 64-element tables. - // - 2^(lo) ~ 1 + a0*lo + a1 * lo^2 + ... - // - // We compute (hi + mid1 + mid2) together by perform the rounding on x * 2^12. - // Since |x| < |-1075)| < 2^11, - // |x * 2^12| < 2^11 * 2^12 < 2^23, - // So we can fit the rounded result round(x * 2^12) in int32_t. - // Thus, the goal is to be able to use an additional addition and fixed width - // shift to get an int32_t representing round(x * 2^12). - // - // Assuming int32_t using 2-complement representation, since the mantissa part - // of a double precision is unsigned with the leading bit hidden, if we add an - // extra constant C = 2^e1 + 2^e2 with e1 > e2 >= 2^25 to the product, the - // part that are < 2^e2 in resulted mantissa of (x*2^12*L2E + C) can be - // considered as a proper 2-complement representations of x*2^12. - // - // One small problem with this approach is that the sum (x*2^12 + C) in - // double precision is rounded to the least significant bit of the dorminant - // factor C. In order to minimize the rounding errors from this addition, we - // want to minimize e1. Another constraint that we want is that after - // shifting the mantissa so that the least significant bit of int32_t - // corresponds to the unit bit of (x*2^12*L2E), the sign is correct without - // any adjustment. So combining these 2 requirements, we can choose - // C = 2^33 + 2^32, so that the sign bit corresponds to 2^31 bit, and hence - // after right shifting the mantissa, the resulting int32_t has correct sign. - // With this choice of C, the number of mantissa bits we need to shift to the - // right is: 52 - 33 = 19. - // - // Moreover, since the integer right shifts are equivalent to rounding down, - // we can add an extra 0.5 so that it will become round-to-nearest, tie-to- - // +infinity. So in particular, we can compute: - // hmm = x * 2^12 + C, - // where C = 2^33 + 2^32 + 2^-1, then if - // k = int32_t(lower 51 bits of double(x * 2^12 + C) >> 19), - // the reduced argument: - // lo = x - 2^-12 * k is bounded by: - // |lo| <= 2^-13 + 2^-12*2^-19 - // = 2^-13 + 2^-31. - // - // Finally, notice that k only uses the mantissa of x * 2^12, so the - // exponent 2^12 is not needed. So we can simply define - // C = 2^(33 - 12) + 2^(32 - 12) + 2^(-13 - 12), and - // k = int32_t(lower 51 bits of double(x + C) >> 19). - - // Rounding errors <= 2^-31. - int k = - static_cast<int>(cpp::bit_cast<uint64_t>(x + 0x1.8000'0000'4p21) >> 19); - double kd = static_cast<double>(k); - - uint32_t idx1 = (k >> 6) & 0x3f; - uint32_t idx2 = k & 0x3f; - - int hi = k >> 12; - - DoubleDouble exp_mid1{EXP2_MID1[idx1].mid, EXP2_MID1[idx1].hi}; - DoubleDouble exp_mid2{EXP2_MID2[idx2].mid, EXP2_MID2[idx2].hi}; - DoubleDouble exp_mid = fputil::quick_mult(exp_mid1, exp_mid2); - - // |dx| < 2^-13 + 2^-30. - double dx = fputil::multiply_add(kd, -0x1.0p-12, x); // exact - - // We use the degree-4 polynomial to approximate 2^(lo): - // 2^(lo) ~ 1 + a0 * lo + a1 * lo^2 + a2 * lo^3 + a3 * lo^4 = 1 + lo * P(lo) - // So that the errors are bounded by: - // |P(lo) - (2^lo - 1)/lo| < |lo|^4 / 64 < 2^(-13 * 4) / 64 = 2^-58 - // Let P_ be an evaluation of P where all intermediate computations are in - // double precision. Using either Horner's or Estrin's schemes, the evaluated - // errors can be bounded by: - // |P_(lo) - P(lo)| < 2^-51 - // => |lo * P_(lo) - (2^lo - 1) | < 2^-64 - // => 2^(mid1 + mid2) * |lo * P_(lo) - expm1(lo)| < 2^-63. - // Since we approximate - // 2^(mid1 + mid2) ~ exp_mid.hi + exp_mid.lo, - // We use the expression: - // (exp_mid.hi + exp_mid.lo) * (1 + dx * P_(dx)) ~ - // ~ exp_mid.hi + (exp_mid.hi * dx * P_(dx) + exp_mid.lo) - // with errors bounded by 2^-63. - - double mid_lo = dx * exp_mid.hi; - - // Approximate (2^dx - 1)/dx ~ 1 + a0*dx + a1*dx^2 + a2*dx^3 + a3*dx^4. - double p = poly_approx_d(dx); - - double lo = fputil::multiply_add(p, mid_lo, exp_mid.lo); - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // To multiply by 2^hi, a fast way is to simply add hi to the exponent - // field. - int64_t exp_hi = static_cast<int64_t>(hi) * (1LL << FPBits::FRACTION_LEN); - double r = - cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(exp_mid.hi + lo)); - return r; -#else - double upper = exp_mid.hi + (lo + ERR_D); - double lower = exp_mid.hi + (lo - ERR_D); - - if (LIBC_LIKELY(upper == lower)) { - // To multiply by 2^hi, a fast way is to simply add hi to the exponent - // field. - int64_t exp_hi = static_cast<int64_t>(hi) * (1LL << FPBits::FRACTION_LEN); - double r = cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(upper)); - return r; - } - - // Use double-double - DoubleDouble r_dd = exp2_double_double(dx, exp_mid); - - double upper_dd = r_dd.hi + (r_dd.lo + ERR_DD); - double lower_dd = r_dd.hi + (r_dd.lo - ERR_DD); - - if (LIBC_LIKELY(upper_dd == lower_dd)) { - // To multiply by 2^hi, a fast way is to simply add hi to the exponent - // field. - int64_t exp_hi = static_cast<int64_t>(hi) * (1LL << FPBits::FRACTION_LEN); - double r = cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(upper_dd)); - return r; - } - - // Use 128-bit precision - DFloat128 r_f128 = exp2_f128(dx, hi, idx1, idx2); - - return static_cast<double>(r_f128); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +using LIBC_MATH_EXP2_IMPL::exp2; } // namespace math - } // namespace LIBC_NAMESPACE_DECL +#undef LIBC_MATH_EXP2_IMPL + #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_accurate_128.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_accurate_128.h new file mode 100644 index 000000000000..31c8bde42597 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_accurate_128.h @@ -0,0 +1,265 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// 128-bit accurate path for double-precision exp2(x). +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_ACCURATE_128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_ACCURATE_128_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/common.h" +#include "src/__support/frac128.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/uint128.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace double_eval { + +using DFloat128 = fputil::DyadicFloat<128>; + +// Table of 2^(i / 16) with i = 0..15 in 128-bit fixed-point format: +// Generated by Sollya with: +// > display = hexadecimal!; +// > prec = 256; +// > for i from 0 to 15 do { +// a = 2^(i / 16); +// c_int = round(a * 2^127, 256, RN); +// hi = floor(c_int * 2^(-64)); +// lo = c_int - hi * 2^64; +// print(" Frac128({", lo, "ULL,", hi, "ULL}), // 2^(", i, "/16)"); +// }; +LIBC_INLINE_VAR constexpr Frac128 EXP2_MID_FRAC128[16] = { + // lsb = 2^-127 + Frac128({0x0000000000000000ULL, 0x8000000000000000ULL}), // 2^(0/16) + Frac128({0xc5c95b8c2154c1b2ULL, 0x85aac367cc487b14ULL}), // 2^(1/16) + Frac128({0xfbe4628758a53c90ULL, 0x8b95c1e3ea8bd6e6ULL}), // 2^(2/16) + Frac128({0x0fd6d8e0ae5ac9d8ULL, 0x91c3d373ab11c336ULL}), // 2^(3/16) + Frac128({0x46ad23182e42f6f6ULL, 0x9837f0518db8a96fULL}), // 2^(4/16) + Frac128({0xa0911f09ebb9fdd1ULL, 0x9ef5326091a111adULL}), // 2^(5/16) + Frac128({0x1cbd7f621710701bULL, 0xa5fed6a9b15138eaULL}), // 2^(6/16) + Frac128({0x4980a8c8f59a2ec4ULL, 0xad583eea42a14ac6ULL}), // 2^(7/16) + Frac128({0x597d89b3754abe9fULL, 0xb504f333f9de6484ULL}), // 2^(8/16) + Frac128({0xa8811fb66d0faf7aULL, 0xbd08a39f580c36beULL}), // 2^(9/16) + Frac128({0x3e2ad0c964dd9f37ULL, 0xc5672a115506daddULL}), // 2^(10/16) + Frac128({0xe235838f95f2c6edULL, 0xce248c151f8480e3ULL}), // 2^(11/16) + Frac128({0x39a68bb9902d3fdeULL, 0xd744fccad69d6af4ULL}), // 2^(12/16) + Frac128({0x065895048dd333caULL, 0xe0ccdeec2a94e111ULL}), // 2^(13/16) + Frac128({0xd02d75b3706e54fbULL, 0xeac0c6e7dd24392eULL}), // 2^(14/16) + Frac128({0x7b9d0c7aed980fc3ULL, 0xf5257d152486cc2cULL}), // 2^(15/16) +}; + +// Polynomial approximation for (2^x - 1) / x: +// For x in [0, 2^-4], we approximate: +// P(x) ~ (2^x - 1) / x +// then: +// 2^x = 1 + x * P(x). +// +// Minimax polynomial coefficients generated by Sollya with: +// > prec = 500; +// > P = fpminimax((2^x - 1)/x, 14, [|128...|], [2^(-150), 2^(-4)], fixed); +// > for i from 0 to 14 do { +// c = coeff(P, i); +// c_int = round(c * 2^128, 256, RN); +// hi = floor(c_int * 2^(-64)); +// lo = c_int - hi * 2^64; +// print("Frac128({", lo, "ULL,", hi, "ULL}), // c_", i); +// }; +// > dirtyinfnorm(2^x - (1 + x * P), [0, 2^(-4)]); +// 0x1.278a...p-139 < 2^-138. +// +// Expanding P(x) in Horner form: +// P(x) = c_0 + x * (c_1 + x * (c_2 + ...)) +// where c_k ~ (log(2))^(k+1) / (k+1)! are all positive and in (0, 1). +LIBC_INLINE_VAR constexpr Frac128 EXP2_POLY_128[15] = { + // lsb = 2^-128 + Frac128({0xc9e3b39803f2f6afULL, 0xb17217f7d1cf79abULL}), // c_0 + Frac128({0xde2d60dd92e6c1ceULL, 0x3d7f7bff058b1d50ULL}), // c_1 + Frac128({0x99d3b15d9958cfa0ULL, 0x0e35846b82505fc5ULL}), // c_2 + Frac128({0x39977c16aee20457ULL, 0x0276556df749cee5ULL}), // c_3 + Frac128({0x41c5fda1c13b8fb1ULL, 0x005761ff9e299cc4ULL}), // c_4 + Frac128({0xb7a58759e18c05e7ULL, 0x000a184897c363c3ULL}), // c_5 + Frac128({0x3434f0e418799c8bULL, 0x0000ffe5fe2c4586ULL}), // c_6 + Frac128({0x241c41f55c65febbULL, 0x0000162c0223a5c8ULL}), // c_7 + Frac128({0x77e77364ac415ce2ULL, 0x000001b5253d395eULL}), // c_8 + Frac128({0xfe79c174054850e2ULL, 0x0000001e4cf5158bULL}), // c_9 + Frac128({0x29d719d4d61d89c9ULL, 0x00000001e8cac72dULL}), // c_10 + Frac128({0xd15314bfa6b56886ULL, 0x000000001c3bd6b4ULL}), // c_11 + Frac128({0xd8de7d5b7789dd3aULL, 0x0000000001815e5dULL}), // c_12 + Frac128({0x491912c310d5531bULL, 0x0000000000132403ULL}), // c_13 + Frac128({0x8d1d877caeba1cfcULL, 0x000000000000c220ULL}), // c_14 +}; + +struct ExpBase192 { + int base_exp; + UInt<192> log2_b; // lsb = 2^(base_exp - 191) +}; + +// log2(e) in 192-bit fixed-point format (lsb = 2^-191), generated by Sollya +// with: +// > display = hexadecimal!; +// > prec = 500; +// > c = round(log2(exp(1)) * 2^191, 192, RN); +// > d2 = floor(c * 2^(-128)); +// > c = c - d2 * 2^128; +// > d1 = floor(c * 2^(-64)); +// > d0 = c - d1 * 2^64; +// > print("{", d0, ",", d1, ",", d2, "}"); +LIBC_INLINE_VAR constexpr ExpBase192 LOG2_E_192 = { + 0, + UInt<192>({ + 0xeb577aa8dd695a59ULL, + 0xbe87fed0691d3e88ULL, + 0xb8aa3b295c17f0bbULL, + }), +}; + +// Evaluate 2^(idx * 2^-4 + u) in [1, 2) as Frac128 (lsb = 2^-127) for +// idx in [0, 15] and u in [0, 2^-4) (lsb = 2^-128). +LIBC_INLINE Frac128 exp2_eval_frac128(unsigned idx, const Frac128 &u) { + // p ~ (2^u - 1) / u + Frac128 p = EXP2_POLY_128[14]; // lsb = 2^-128 + LIBC_LOOP_NOUNROLL + for (int i = 13; i >= 0; --i) + p = p * u + EXP2_POLY_128[i]; // lsb = 2^-128 + + // Reconstruction: + // u * p ~ 2^u - 1 (lsb = 2^-128) + // m = 2^(idx * 2^-4) (lsb = 2^-127) + // m + m * (u * p) ~ m * 2^u (lsb = 2^-127) + Frac128 m = EXP2_MID_FRAC128[idx]; // lsb = 2^-127 + return m + m * (u * p); // lsb = 2^-127 +} + +// Compute 2^z in 128-bit precision for a DyadicFloat<128> z with leading bit at +// bit 126 or 127 of z.mantissa, 2^-54 < |z| < 2^11 (z.exponent in +// [-181, -117]), and optional extra low limb lo (lsb = 2^(z.exponent - 64)): +// z = k * 2^-4 + u, 0 <= u < 2^-4 +// hi = k >> 4 +// idx = k & 0x0f +// 2^z = 2^hi * EXP2_MID_FRAC128[idx] * (1 + u * P(u)). +LIBC_INLINE DFloat128 exp2_df128(const DFloat128 &z, uint64_t lo = 0) { + // z.mantissa has lsb = 2^z.exponent, so the 2^-4 bit of |z| is at bit + // (-4 - z.exponent) of z.mantissa, leaving + // shift = 128 - (-4 - z.exponent) = z.exponent + 132 bits + // at or above 2^-4 in z.mantissa.val[1]. + // After range reduction, 2^-54 < |z| < 2^11 and z.exponent is in + // [-181, -117], so shift is in [-49, 15]. + int shift = z.exponent + 132; + int k = 0; + UInt<128> frac; + if (LIBC_LIKELY(shift > 0)) { + // |z| >= 2^-5 (all |z| >= 2^-4, plus 2^-5 <= |z| < 2^-4 with k = 0 when + // bit 127 of z.mantissa is 0): split + // |z| = k * 2^-4 + frac * 2^-132. + // Here shift is in [1, 15] and shr = 64 - shift is in [49, 63], so all + // 64-bit shifts below are strictly in [1, 63] (no undefined behavior). + int shr = 64 - shift; // in [49, 63] + // k = floor(|z| * 2^4) + k = static_cast<int>(z.mantissa.val[1] >> shr); // lsb = 2^-4 + // Shift z.mantissa left by shift and fill the low shift bits from lo: + frac = UInt<128>({(z.mantissa.val[0] << shift) | (lo >> shr), + (z.mantissa.val[1] << shift) | + (z.mantissa.val[0] >> shr)}); // lsb = 2^-132 + } else { + // |z| < 2^-4: k = 0 and frac = |z| * 2^132, with -shift in [0, 49]. + frac = z.mantissa >> (-shift); // lsb = 2^-132 + } + + if (z.sign.is_neg()) { + if (LIBC_UNLIKELY(frac.is_zero())) { + k = -k; + } else { + // One's-complement negation on frac (differs from two's-complement by + // 2^-132 = 2^-4 * lsb(u)): + // -|z| ~ (-k - 1) * 2^-4 + (2^-4 - (frac + 1) * 2^-132). + frac = ~frac; + k = ~k; + } + } + + // Decompose: + // k * 2^-4 = hi + idx * 2^-4 + // and scale frac from lsb = 2^-132 to u in [0, 2^-4) with lsb = 2^-128: + int hi = k >> 4; // lsb = 1 + unsigned idx = static_cast<unsigned>(k & 0x0f); // lsb = 2^-4 + Frac128 u((frac >> 4).val); // lsb = 2^-128 + Frac128 m_final = exp2_eval_frac128(idx, u); // lsb = 2^-127 + + // For tiny negative inputs x = -a - a^2 / 2 (where 1 - a is an exact double), + // exp(x) = (1 - a) + a^3 / 3 + O(a^4) + // is strictly greater than 1 - a by a residual that can be smaller than + // 2^-128 (down to ~2^-155 for a = 2^-51). + // + // When z in (-2^-4, 0) (shift <= 0 and z < 0), the downward truncations of + // u, u * p, and m * (u * p) bias m_final by: + // (-5, 0) * lsb(m_final). + // Adding 5 shifts this error to: + // (0, 5) * lsb(m_final), + // so 2^-1 * m_final is strictly above 1 - a (preserving a non-zero sticky bit + // in all rounding modes). + if (shift <= 0 && z.sign.is_neg()) + m_final += Frac128(5); + + // Since m_final is in [1, 2) with lsb = 2^-127, its leading bit is already + // at bit 127, so r is normalized with exponent = hi - 127: + DFloat128 r; + r.sign = Sign::POS; + r.exponent = hi - 127; + r.mantissa = UInt<128>(m_final.val); + return r; +} + +// Compute b^x (for b = 2, e, or 10) in 128-bit precision using direct base-2 +// 192-bit fixed-point range reduction. Here log2_base->log2_b holds: +// round(log2(b) * 2^(191 - base_exp)), +// or log2_base is nullptr when b = 2. +LIBC_NOINLINE LIBC_INLINE double +exp_accurate_128(double x, const ExpBase192 *log2_base = nullptr) { + using FPBits = fputil::FPBits<double>; + FPBits xbits(x); + int exp_x = xbits.get_exponent(); + + // Normalize |x|'s 53-bit mantissa to [2^63, 2^64): + uint64_t mant_x = (xbits.get_mantissa() | (1ULL << 52)) << 11; + + DFloat128 z; + z.sign = xbits.sign(); + uint64_t w0 = 0; + + if (log2_base != nullptr) { + // 1-limb x 3-limb product: + // mant_x has lsb = 2^(exp_x - 63) + // log2_base->log2_b has lsb = 2^(base_exp - 191) + // p = mant_x * log2_base->log2_b has lsb = 2^(exp_x + base_exp - 254) + UInt<256> p = log2_base->log2_b.ful_mul(UInt<64>(mant_x)); + // Extract the top 192 bits (p.val[3], p.val[2], p.val[1]) as + // (z.mantissa, w0): + z.exponent = exp_x + log2_base->base_exp - 126; + z.mantissa = UInt<128>({p.val[2], p.val[3]}); // lsb = 2^z.exponent + w0 = p.val[1]; // lsb = 2^(z.exponent - 64) + } else { + // For b = 2, log2(b) = 1, so z = x directly: + z.exponent = exp_x - 127; + z.mantissa = UInt<128>({0, mant_x}); // lsb = 2^(exp_x - 127) + } + + return static_cast<double>(exp2_df128(z, w0)); +} + +} // namespace double_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_ACCURATE_128_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_double_eval.h new file mode 100644 index 000000000000..8e2e372b58fb --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2_double_eval.h @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Double-precision implementation of exp2. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_DOUBLE_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_DOUBLE_EVAL_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#include "src/__support/math/exp_double_utils.h" +#else +#include "src/__support/math/exp_utils.h" +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace double_eval { + +LIBC_ALWAYS_INLINE double exp2(double x) { + using FPBits = fputil::FPBits<double>; + FPBits xbits(x); + + uint64_t x_u = xbits.uintval(); + uint64_t x_abs = xbits.abs().uintval(); + + // Bound constants (with biased exponent and mantissa bits): + // - Tiny bound: nextafter(2^-54, +inf) = 0x1.0000000000001p-54 + // (since |x| <= 2^-54 is handled by 1.0 + x in set_exceptional) + constexpr uint64_t TINY_BOUND = 0x3c90'0000'0000'0001ULL; + // - Overflow bound: 1024.0 + constexpr uint64_t OVERFLOW_BOUND = 0x4090'0000'0000'0000ULL; + // -1024.0 + constexpr uint64_t NEG_OVERFLOW_BOUND = 0xc090'0000'0000'0000ULL; + // - Underflow bound: -1075.0 + constexpr uint64_t UNDERFLOW_BOUND = 0xc090'cc00'0000'0000ULL; + + // Normal range: 2^-54 <= |x| < 1024. + if (LIBC_UNLIKELY(x_abs - TINY_BOUND >= OVERFLOW_BOUND - TINY_BOUND)) { + // Exclude non-underflowing negative inputs in (-1075, -1024]. + if (LIBC_LIKELY(x_u < NEG_OVERFLOW_BOUND || x_u >= UNDERFLOW_BOUND)) + return set_exceptional(x); + } + + // Now -1075 < x < -2^-54 or 2^-54 < x < 1024. + + // Range reduction: + // Let x = k * 2^-N + dx + // in which: + // k = round(x * 2^N) + // hi = k >> N + // idx = k & (2^N - 1) + // then: + // 2^x = 2^hi * 2^(idx / 2^N) * 2^dx. + + double kd = fputil::nearest_integer(x * EXP_SCALE); + int k = static_cast<int>(kd); + + int hi = k >> EXP_N_BITS; + unsigned idx = static_cast<unsigned>(k & EXP_MASK); + + double dx = fputil::multiply_add(kd, -EXP_SCALE_INV, x); // exact + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + double u = dx * LOG_2.hi; + return exp2_eval(x, u, hi, idx, /*is_exp2=*/true); +#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + DoubleDouble u = fputil::exact_mult(dx, LOG_2.hi); + u.lo = fputil::multiply_add(dx, LOG_2.lo, u.lo); +#else // !LIBC_TARGET_CPU_HAS_FMA_DOUBLE + // Without FMA, we use fixed-point splitting to avoid Veltkamp's splitting: + // Let: + // m = 2^(idx / 2^7) = m_hi + m_lo + // u = dx * log(2) = u_hi + u_lo + // + // In exp2_eval, we approximate 2^(idx / 2^7) * 2^dx = m * exp(u) by: + // m * (1 + u + u^2 * P(u)) ~ r_hi + r_lo + // where: + // r_hi = m_hi + m_hi * u_hi + // r_lo = m * (u_lo + u^2 * P(u)) + m_lo * (1 + u_hi) + // + // Since r_hi is in [1 - 2^-8, 2), for r_hi to be exact in double precision, + // we need: + // lsb(m_hi * u_hi) >= 2^-52. + // We choose: + // lsb(m_hi) >= 2^-22 => |m_lo| < 2^-22 + // lsb(u_hi) >= 2^-30 + // so that lsb(m_hi * u_hi) >= 2^-52, and the rounding errors from + // m_lo * (1 + u_hi) are bounded by 2^(-22 - 52) = 2^-74. + // + // To get lsb(u_hi) >= 2^-30 from u = dx * log(2), since |dx| <= 2^-8 and + // log(2) < 1, we split dx at 2^-18 and log(2) at 2^-12: + // dx = dx_hi + dx_lo (|dx_lo| <= 2^-19) + // log(2) = LOG_2_HI_12 + LOG_2_LO_12 (|LOG_2_LO_12| < 2^-13) + // Then: + // u_hi = dx_hi * LOG_2_HI_12 + // is an exact multiple of 2^-30, and the two remainder products in: + // u_lo = dx_lo * LOG_2_HI_12 + dx * LOG_2_LO_12 + // are both bounded by 2^-19, keeping the rounding errors of u_lo below 2^-71. + double dx_hi = (dx + SPLIT_18) - SPLIT_18; // lsb = 2^-18 + double dx_lo = dx - dx_hi; + double u_hi = dx_hi * LOG_2_HI_12; // exact, lsb = 2^-30 + double t0 = dx_lo * LOG_2_HI_12; + double t1 = dx * LOG_2_LO_12; + double u_lo = t0 + t1; + DoubleDouble u = {u_lo, u_hi}; +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + return exp2_eval(x, u, hi, idx); +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace double_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2_DOUBLE_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2bf16.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2bf16.h new file mode 100644 index 000000000000..44fa5da0ebe4 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2bf16.h @@ -0,0 +1,211 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of the exp2bf16 function, which computes 2^x for bfloat16. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2BF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2BF16_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/bfloat16.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +namespace exp2bf16_internal { +// Generated by Sollya with the following commands: +// > display = hexadecimal; +// > for i in [|-126.5, -127, -127.5, -128, -129, -130, -131, -132, -133|] +// do print(round(2^i, SG, RN) @ "f,"); +LIBC_INLINE_VAR constexpr float EXP2_DENORMAL[9] = { + 0x1.6a09e8p-127f, 0x1p-127f, 0x1.6a09e8p-128f, 0x1p-128f, 0x1p-129f, + 0x1p-130f, 0x1p-131f, 0x1p-132f, 0x1p-133f, +}; + +// Generated by Sollya with the following commands: +// > display = hexadecimal; +// > for i from 0 to 15 do print(round(2^(i/16), SG, RN) @ "f,"); +LIBC_INLINE_VAR constexpr float EXP2_MID[16] = { + 0x1p0f, 0x1.0b5586p0f, 0x1.172b84p0f, 0x1.2387a6p0f, + 0x1.306fep0f, 0x1.3dea64p0f, 0x1.4bfdaep0f, 0x1.5ab07ep0f, + 0x1.6a09e6p0f, 0x1.7a1148p0f, 0x1.8ace54p0f, 0x1.9c4918p0f, + 0x1.ae89fap0f, 0x1.c199bep0f, 0x1.d5818ep0f, 0x1.ea4afap0f, +}; +} // namespace exp2bf16_internal + +LIBC_INLINE bfloat16 exp2bf16(bfloat16 x) { + using FPBits = fputil::FPBits<bfloat16>; + FPBits x_bits(x); + uint16_t x_uint = x_bits.uintval(); + + // We first check for NaN + if (LIBC_UNLIKELY(x_bits.is_nan())) { + // If it is a signaling NaN, then we raise an FE_INVALID exception + // and return a quiet NaN + if (x_bits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + // If not, just return the NaN + return x; + } + + // exp2bf16 may only give numeric output for input x in (-134.0, 128.0). + // All the remaining exceptional cases (overflow, underflow and denormal + // outputs) have |x| >= 126.5, so we filter them with a single check. + constexpr uint16_t EXCEPTIONAL_ABS_BASE = 0x42FD; // 0x1.fap6 = 126.5 + if (LIBC_UNLIKELY(x_bits.abs().uintval() >= EXCEPTIONAL_ABS_BASE)) { + if (x_bits.is_pos()) { + // Overflow: x >= 128.0 (0x4300 = 0x1p7) + if (x_uint >= 0x4300) { + // exp2(Inf) = Inf + if (x_bits.is_inf()) + return x; + +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + // If we can only RN, then it'll go towards INF + fputil::set_errno_if_required(ERANGE); + fputil::raise_overflow_except_if_required<float>(); + return FPBits::inf().get_val(); +#else + // If not, get what other rounding modes are available + switch (fputil::quick_get_round()) { + case FE_TONEAREST: + case FE_UPWARD: + // Both of these go to Inf + fputil::set_errno_if_required(ERANGE); + fputil::raise_overflow_except_if_required<float>(); + return FPBits::inf().get_val(); + default: + // RD and RZ go to the maximum possible value in the + // range of the function, being the maximum normal. + return FPBits::max_normal().get_val(); + } +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + } + } else { + // Underflow: x <= -134.0 (0xC306 = -0x1.0cp7) + if (x_uint >= 0xC306) { + // exp2(-Inf) = 0 + if (x_bits.is_inf()) + return FPBits::zero().get_val(); + + // Need these for every output now. + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); +#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return FPBits::zero().get_val(); +#else + switch (fputil::quick_get_round()) { + case FE_UPWARD: + // RU rounds up to the minimum subnormal + return FPBits::min_subnormal().get_val(); + default: + // All other rounding modes go down to zero + return FPBits::zero().get_val(); + } +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + } + + // Handle denormal output separately, by using a LUT + // We are handling these separately because the trick of adding hi + // directly to the exponent of the result will not work if the + // output is denormal. There are only 9 such inputs and they are + // all back-to-back when expressed as an uint16_t, with + // x_uint >= 0xC2FD (-0x1.fap6 = -126.5) and + // x_uint <= 0xC305 (-0x1.0ap7 = -133.0). + constexpr uint16_t DENORMAL_LUT_BASE = 0xC2FD; + return fputil::cast<bfloat16>( + exp2bf16_internal::EXP2_DENORMAL[x_uint - DENORMAL_LUT_BASE]); + } + } + + // For inputs not handled above in -134.0 < x < 128.0, + // we perform the following range reduction: + // x = hi + mid + lo + // where, + // hi is an integer + // mid is a grid point of the form j / 2^n in [0, 1) + // lo is what's leftover ie x - k / 2^n + // and |lo| <= 2^(-n-1) + // with, + // n = 4 + // k = round(2^n * x) + // hi = k >> n + // j = k & (2^n - 1) + // then, + // exp2(x) = exp2(hi + mid + lo) + // = exp2(hi) * exp2(mid) * exp2(lo) + // + // To get exp2(hi), we'll just add hi to the exponent bits of the + // result of exp2(mid) * exp2(lo), which is exact. + // exp2(mid) we shall obtain by consulting our LUT, + // exp2(lo) by the polynomial. + + float x_float = fputil::cast<float>(x); + float k_float = fputil::nearest_integer(x_float * 16.0f); + + int k_int = static_cast<int>(k_float); + int hi = k_int >> 4; + int j = k_int & (16 - 1); + + // lo = x - (hi + mid) = x - k / 2^n + // = k * (-2^(-n)) + x + float lo = fputil::multiply_add(k_float, -0.0625f, x_float); + + float exp2_mid = exp2bf16_internal::EXP2_MID[j]; + + // Degree-3 minimax polynomial generated by Sollya with the following + // commands: + // > display = hexadecimal; + // > P = fpminimax(2^x, [|1, 2, 3|], [|SG...|], [-2^-5, 2^-5], relative, + // floating, 1); + // 0x1p0 + x * (0x1.62e43p-1 + x * (0x1.ebfff4p-3 + x * 0x1.c6aceep-5)) + float exp2_lo = fputil::polyeval(lo, 0x1p0f, 0x1.62e43p-1f, 0x1.ebfff4p-3f, + 0x1.c6aceep-5f); + + // We tried using Estrin's scheme as follows, + // float lo2 = lo * lo; + // float p0 = fputil::multiply_add(lo, 0x1.62e43p-1f, 0x1p0f); + // float p1 = fputil::multiply_add(lo, 0x1.c6aceep-5f, 0x1.ebfff4p-3f); + // float exp2_lo = fputil::multiply_add(lo2, p1, p0); + // however that led to a 1-ULP error in all RU, negative, small input cases. + // The latency increase wasn't significant (~1%) so we reverted back + // to Horner's scheme. + + float res = exp2_mid * exp2_lo; + + fputil::FPBits<float> res_bits(res); + uint32_t res_int = res_bits.uintval(); + + uint32_t exp_hi = hi << fputil::FPBits<float>::FRACTION_LEN; + res_int += exp_hi; + + res = fputil::FPBits<float>(res_int).get_val(); + return fputil::cast<bfloat16>(res); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2BF16_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f.h index e7ce1ec29c03..0d08fa6c1176 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f.h @@ -17,6 +17,7 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" #if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ @@ -25,11 +26,19 @@ #include "src/__support/math/exp2f_float_eval.h" #define LIBC_MATH_EXP2F_IMPL float_eval -#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#elif !defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE) && \ + defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) && \ + defined(LIBC_MATH_HAS_NO_EXCEPT) && defined(LIBC_MATH_HAS_NO_ERRNO) + +#include "src/__support/math/exp2f_integer_eval.h" +#define LIBC_MATH_EXP2F_IMPL integer_eval + +#else + #include "src/__support/math/exp2f_double_eval.h" #define LIBC_MATH_EXP2F_IMPL double_eval -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#endif namespace LIBC_NAMESPACE_DECL { namespace math { diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_double_eval.h index e0387f32e193..c9548712ab37 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_double_eval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_double_eval.h @@ -38,15 +38,59 @@ LIBC_INLINE float exp2f(float x) { uint32_t x_u = xbits.uintval(); uint32_t x_abs = x_u & 0x7fff'ffffU; + // |x| < 2^-25 + if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) + return 1.0f + x; + + auto exp2f_mid = [&]() -> float { + // kf = (hi + mid) * 2^5 = round(x * 2^5) + float kf = 0; + int k = 0; +#ifdef LIBC_TARGET_CPU_HAS_NEAREST_INT + kf = fputil::nearest_integer(x * 32.0f); + k = static_cast<int>(kf); +#else // !LIBC_TARGET_CPU_HAS_NEAREST_INT + constexpr float HALF[2] = {0.5f, -0.5f}; + k = static_cast<int>(fputil::multiply_add(x, 32.0f, HALF[x < 0.0f])); + kf = static_cast<float>(k); +#endif // LIBC_TARGET_CPU_HAS_NEAREST_INT + + // dx = lo = x - (hi + mid) = x - kf * 2^(-5) + double dx = fputil::multiply_add(-0x1.0p-5f, kf, x); + + // hi = floor(kf * 2^(-4)) + // exp_hi = shift hi to the exponent field of double precision. + int64_t exp_hi = + static_cast<int64_t>(static_cast<uint64_t>(k >> ExpBase::MID_BITS) + << fputil::FPBits<double>::FRACTION_LEN); + // mh = 2^hi * 2^mid + // mh_bits = bit field of mh + int64_t mh_bits = ExpBase::EXP_2_MID[k & ExpBase::MID_MASK] + exp_hi; + double mh = fputil::FPBits<double>(uint64_t(mh_bits)).get_val(); + + // Degree-5 polynomial approximating (2^x - 1)/x generated by Sollya. + constexpr double COEFFS[5] = {0x1.62e42fefa39efp-1, 0x1.ebfbdff8131c4p-3, + 0x1.c6b08d7061695p-5, 0x1.3b2b1bee74b2ap-7, + 0x1.5d88091198529p-10}; + double dx_sq = dx * dx; + double c1 = fputil::multiply_add(dx, COEFFS[0], 1.0); + double c2 = fputil::multiply_add(dx, COEFFS[2], COEFFS[1]); + double c3 = fputil::multiply_add(dx, COEFFS[4], COEFFS[3]); + double p = fputil::multiply_add(dx_sq, c3, c2); + // 2^x = 2^(hi + mid + lo) + // = 2^(hi + mid) * 2^lo + // ~ mh * (1 + lo * P(lo)) + // = mh + (mh*lo) * P(lo) + return static_cast<float>(fputil::multiply_add(p, dx_sq * mh, c1 * mh)); + }; + + if (LIBC_LIKELY(x_abs > 0x3d00'0000U && x_abs < 0x4300'0000U)) + return exp2f_mid(); + // When |x| >= 128, or x is nan, or |x| <= 2^-5 if (LIBC_UNLIKELY(x_abs >= 0x4300'0000U || x_abs <= 0x3d00'0000U)) { // |x| <= 2^-5 if (x_abs <= 0x3d00'0000) { - // |x| < 2^-25 - if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { - return 1.0f + x; - } - #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS constexpr uint32_t EXVAL1 = 0x3b42'9d37U; constexpr uint32_t EXVAL2 = 0xbcf3'a937U; @@ -128,47 +172,7 @@ LIBC_INLINE float exp2f(float x) { // generated by Sollya. // We perform 2^hi * 2^mid by simply add hi to the exponent field // of 2^mid. - - // kf = (hi + mid) * 2^5 = round(x * 2^5) - float kf = 0; - int k = 0; -#ifdef LIBC_TARGET_CPU_HAS_NEAREST_INT - kf = fputil::nearest_integer(x * 32.0f); - k = static_cast<int>(kf); -#else // !LIBC_TARGET_CPU_HAS_NEAREST_INT - constexpr float HALF[2] = {0.5f, -0.5f}; - k = static_cast<int>(fputil::multiply_add(x, 32.0f, HALF[x < 0.0f])); - kf = static_cast<float>(k); -#endif // LIBC_TARGET_CPU_HAS_NEAREST_INT - - // dx = lo = x - (hi + mid) = x - kf * 2^(-5) - double dx = fputil::multiply_add(-0x1.0p-5f, kf, x); - - // hi = floor(kf * 2^(-4)) - // exp_hi = shift hi to the exponent field of double precision. - int64_t exp_hi = - static_cast<int64_t>(static_cast<uint64_t>(k >> ExpBase::MID_BITS) - << fputil::FPBits<double>::FRACTION_LEN); - // mh = 2^hi * 2^mid - // mh_bits = bit field of mh - int64_t mh_bits = ExpBase::EXP_2_MID[k & ExpBase::MID_MASK] + exp_hi; - double mh = fputil::FPBits<double>(uint64_t(mh_bits)).get_val(); - - // Degree-5 polynomial approximating (2^x - 1)/x generating by Sollya with: - // > P = fpminimax((2^x - 1)/x, 5, [|D...|], [-1/32. 1/32]); - constexpr double COEFFS[5] = {0x1.62e42fefa39efp-1, 0x1.ebfbdff8131c4p-3, - 0x1.c6b08d7061695p-5, 0x1.3b2b1bee74b2ap-7, - 0x1.5d88091198529p-10}; - double dx_sq = dx * dx; - double c1 = fputil::multiply_add(dx, COEFFS[0], 1.0); - double c2 = fputil::multiply_add(dx, COEFFS[2], COEFFS[1]); - double c3 = fputil::multiply_add(dx, COEFFS[4], COEFFS[3]); - double p = fputil::multiply_add(dx_sq, c3, c2); - // 2^x = 2^(hi + mid + lo) - // = 2^(hi + mid) * 2^lo - // ~ mh * (1 + lo * P(lo)) - // = mh + (mh*lo) * P(lo) - return static_cast<float>(fputil::multiply_add(p, dx_sq * mh, c1 * mh)); + return exp2f_mid(); } } // namespace double_eval diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_float_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_float_utils.h index 1c96050bea37..28bad5a92dd7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_float_utils.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_float_utils.h @@ -15,6 +15,7 @@ #define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_FLOAT_UTILS_H #include "src/__support/CPP/bit.h" +#include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" @@ -70,9 +71,8 @@ LIBC_INLINE float scale_exp2f(float y, int m) { return (y * scale) * 0x1.0p-25f; } -// Degree-6 polynomial approximating 2^u - 1 = u * P(u) on [-0.5, 0.5] using -// Estrin's scheme and exponent scaling. -// Evaluates 2^x = 2^m * 2^u. +// Degree-6 polynomial approximating 2^u - 1 = u * P(u) on [-0.5, 0.5] and +// exponent scaling to evaluate 2^x = 2^m * 2^u. // Generated by Sollya with: // > display = hexadecimal; // > P = fpminimax((2^x - 1)/x, 5, [|SG...|], [-0.5, 0.5]); @@ -80,6 +80,15 @@ LIBC_INLINE float scale_exp2f(float y, int m) { // 0x1.68cb...p-28 // > dirtyinfnorm((1 + x * P - 2^x) / 2^x, [-0.5, 0.5]); // 0x1.5109...p-28 +// +// Instead of using pure Estrin's scheme on P(u), we evaluate the degree-4 +// part p = c1 + c2 * u + c3 * u^2 + c4 * u^3 + c5 * u^4 with Estrin's +// scheme, and then evaluate y = 1.0f + u * (c0 + u * p) with Horner's +// scheme. +// In pure Estrin's scheme, p0 = c0 + c1 * u, q0 = p0 + u^2 * p1, and +// p = q0 + u^4 * p2 all round at the exponent of c0 (~2^-1), accumulating +// rounding errors on non-FMA targets. Evaluating c1..c5 first keeps only a +// single rounding at c0's scale. LIBC_INLINE float exp2f_eval(float u, int m) { constexpr float COEFFS[6] = {0x1.62e430p-1f, 0x1.ebfbdep-3f, 0x1.c6af9ep-5f, 0x1.3b2c58p-7f, @@ -88,14 +97,12 @@ LIBC_INLINE float exp2f_eval(float u, int m) { float u2 = u * u; float u4 = u2 * u2; - float p0 = fputil::multiply_add(u, COEFFS[1], COEFFS[0]); - float p1 = fputil::multiply_add(u, COEFFS[3], COEFFS[2]); - float p2 = fputil::multiply_add(u, COEFFS[5], COEFFS[4]); - + float p0 = fputil::multiply_add(u, COEFFS[2], COEFFS[1]); + float p1 = fputil::multiply_add(u, COEFFS[4], COEFFS[3]); float q0 = fputil::multiply_add(u2, p1, p0); - float p = fputil::multiply_add(u4, p2, q0); + float p = fputil::multiply_add(u4, COEFFS[5], q0); - float y = fputil::multiply_add(u, p, 1.0f); + float y = fputil::polyeval(u, 1.0f, COEFFS[0], p); return scale_exp2f(y, m); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_eval.h new file mode 100644 index 000000000000..5d60a465fd75 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_eval.h @@ -0,0 +1,131 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Integer-only implementation of exp2f. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_INTEGER_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_INTEGER_EVAL_H + +#include "hdr/fenv_macros.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/types.h" +#include "src/__support/math/exp2f_integer_utils.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace static_rounding { + +LIBC_ALWAYS_INLINE uint32_t exp2f_bits(uint32_t x_u, + [[maybe_unused]] int rounding) { + using FPBits = fputil::FPBits<float>; + + bool is_neg = (x_u >> 31) != 0; + uint32_t x_abs = x_u & 0x7fff'ffffU; + uint32_t x_e = x_abs >> FPBits::FRACTION_LEN; + + // When |x| < 2^-24 (x_e <= 102) or |x| >= 128 (x_e >= 134): + if (LIBC_UNLIKELY(x_e - 103U >= 31U)) { + // |x| < 2^-24 + if (x_e <= 102U) { +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (LIBC_UNLIKELY(rounding != FE_TONEAREST)) { + if (x_abs == 0) + return 0x3f80'0000U; // 1.0f + + if (rounding == FE_UPWARD && !is_neg) + return 0x3f80'0001U; // 0x1.000002p+0f = 1.0f + 2^-23f + + if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && is_neg) + return 0x3f7f'ffffU; // 0x1.fffffep-1f = 1.0f - 2^-24f + + return 0x3f80'0000U; // 1.0f + } +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + // For FE_TONEAREST, 2^x rounds to 1.0f (0x3f80'0000U) or + // 1.0f - 2^-24f (0x3f7f'ffffU) when + // x < log2(1 - 2^-25) ~ -0x1.715476p-25f (0xb338'aa3bU). + return 0x3f80'0000U - static_cast<uint32_t>(x_u > 0xb338'aa3bU); + } + + // exp2(nan) = nan + if (x_abs > 0x7f80'0000U) // |x| > +inf (x is NaN) + return x_u | 0x0040'0000U; // silence signaling NaN + + // x >= 128 or +inf: + // exp2(x) = +inf for FE_TONEAREST, FE_UPWARD + // = FLT_MAX for FE_TOWARDZERO, FE_DOWNWARD + if (!is_neg) { +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && + x_u < 0x7f80'0000U) // x < +inf + return 0x7f7f'ffffU; // 0x1.fffffep+127f (FLT_MAX) +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return 0x7f80'0000U; // +inf + } + + // x <= -150.0f (0xc316'0000U) or -inf: + // exp2(x) = 2^-149 for FE_UPWARD + // = +0.0f otherwise + if (x_u >= 0xc316'0000U) { +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (rounding == FE_UPWARD && x_u < 0xff80'0000U) // x > -inf + return 0x0000'0001U; // 0x1.0p-149f (FLT_TRUE_MIN) +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return 0x0000'0000U; // +0.0f + } + } + + // Range reduction: + // k = floor(x) + // x = k + u, with u in [0, 1) + // 2^x = 2^(k + u) = 2^k * 2^u + // + // For all remaining inputs, x_e is in [103, 134], so shifting the 24-bit + // significand of |x| places the binary point of |x| at bit 54. + // On 32-bit targets, s = 134 - x_e is in [0, 31], avoiding undefined 32-bit + // shift amounts. +#if defined(LIBC_TYPES_HAS_INT128) && !defined(LIBC_MATH_HAS_SMALL_TABLES) + uint64_t m = (x_u & 0x007f'ffffU) | 0x0080'0000U; + uint64_t u_bits = m << (x_e - 96U); +#else // !defined(LIBC_TYPES_HAS_INT128) || defined(LIBC_MATH_HAS_SMALL_TABLES) + uint32_t m_hi = ((x_u & 0x007f'ffffU) | 0x0080'0000U) << 6; + uint32_t s = 134U - x_e; + uint32_t u_lo = (m_hi << 1) << (31U - s); + uint32_t u_hi = m_hi >> s; + uint64_t u_bits = (static_cast<uint64_t>(u_hi) << 32) | u_lo; +#endif // defined(LIBC_TYPES_HAS_INT128) && !defined(LIBC_MATH_HAS_SMALL_TABLES) + + return exp2f_eval_bits(u_bits, is_neg, rounding); +} + +// Statically rounded, no-except implementation of exp2f using integer-only +// arithmetic. +LIBC_ALWAYS_INLINE float exp2f(float x, [[maybe_unused]] int rounding) { + return cpp::bit_cast<float>(exp2f_bits(cpp::bit_cast<uint32_t>(x), rounding)); +} + +} // namespace static_rounding + +namespace integer_eval { + +LIBC_ALWAYS_INLINE float exp2f(float x) { + return static_rounding::exp2f(x, FE_TONEAREST); +} + +} // namespace integer_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_INTEGER_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_utils.h new file mode 100644 index 000000000000..569674436a0e --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp2f_integer_utils.h @@ -0,0 +1,182 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared utilities and constants for integer-only single-precision exponential +/// functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_INTEGER_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_INTEGER_UTILS_H + +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/frac64.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace static_rounding { + +// Degree-11 minimax polynomial approximating 2^u - 1 on [0, 1], generated by +// Sollya with: +// > P = fpminimax(2^x, 11, [|1, 64...|], [0, 1], absolute, fixed); +// > dirtyinfnorm(2^x - P(x), [0, 1]); +// 0x1.6238...p-58 +// Store the fractional part of the coefficients below with LSB = 2^-64: +LIBC_INLINE_VAR constexpr Frac64 EXP2F_COEFFS[11] = { + Frac64(0xb172'17f7'd1cf'b7cf), // u + Frac64(0x3d7f'7bff'057d'4a5e), // u^2 + Frac64(0x0e35'846b'8363'9484), // u^3 + Frac64(0x0276'556d'ec97'dcd4), // u^4 + Frac64(0x0057'61ff'dc04'c7ff), // u^5 + Frac64(0x000a'1847'b6e7'92ec), // u^6 + Frac64(0x0000'ffe8'14e5'7033), // u^7 + Frac64(0x0000'1628'b6e9'70c8), // u^8 + Frac64(0x0000'01b8'8ce7'4088), // u^9 + Frac64(0x0000'001c'18d5'cb29), // u^10 + Frac64(0x0000'0002'b43f'4490), // u^11 +}; + +// Compute |x| * log2(b) in unsigned 64-bit fixed-point format with binary +// point at bit 54 (LSB = 2^-54), for x_e in [max_e - 31, max_e]. +// The binary point of log2_b is at bit (63 - (133 - max_e)). +LIBC_ALWAYS_INLINE uint64_t exp_b_scale(uint32_t x_u, uint32_t x_e, + Frac64 log2_b, uint32_t max_e) { +#if defined(LIBC_TYPES_HAS_INT128) && !defined(LIBC_MATH_HAS_SMALL_TABLES) + // When 128-bit integers are available (64-bit targets) and small code size is + // not requested, variable 64-bit shifts and 64x64 -> 128 multiplications are + // single native instructions. Shift the 24-bit significand of |x| into a + // 64-bit word and take the upper 64 bits of its 128-bit product with log2_b. + uint64_t m = static_cast<uint64_t>((x_u & 0x007f'ffffU) | 0x0080'0000U) + << (x_e - (max_e - 38U)); + return (Frac64(m) * log2_b).val[0]; +#else // !defined(LIBC_TYPES_HAS_INT128) || defined(LIBC_MATH_HAS_SMALL_TABLES) + // On 32-bit targets without native 128-bit integers (or when optimizing for + // size), avoid 64-bit variable shifts (which lower to branches on 32-bit + // targets) and 64x64 -> 128 multiplications: + // 1. Place the 24-bit significand of |x| at bits [8..31] (leading 1 at + // bit 31) and compute the upper 64 bits of the 32x64 -> 96 product with + // (log2_b >> 2) using only two 32x32 -> 64 multiplications. + // 2. Since x_e is in [max_e - 31, max_e], s = max_e - x_e is in [0, 31], so + // shifting the 64-bit product right by s using two 32-bit shifts places + // the binary point of |x| * log2(b) at bit 54 without branches or UB at + // s = 0. + uint64_t m = (x_u << 8) | 0x8000'0000U; + uint64_t log2_b_scaled = log2_b.val[0] >> 2; + uint64_t prod = m * (log2_b_scaled >> 32) + + ((m * static_cast<uint32_t>(log2_b_scaled)) >> 32); + uint32_t s = max_e - x_e; + uint32_t prod_lo = static_cast<uint32_t>(prod); + uint32_t prod_hi = static_cast<uint32_t>(prod >> 32); + uint32_t u_lo = (prod_lo >> s) | ((prod_hi << 1) << (31U - s)); + uint32_t u_hi = prod_hi >> s; + return (static_cast<uint64_t>(u_hi) << 32) | u_lo; +#endif // defined(LIBC_TYPES_HAS_INT128) && !defined(LIBC_MATH_HAS_SMALL_TABLES) +} + +// Evaluate 2^(x * log2(b)) from u_bits = |x| * log2(b) (with binary point at +// bit 54) and return the IEEE 754 single-precision bit representation. +LIBC_ALWAYS_INLINE uint32_t exp2f_eval_bits(uint64_t u_bits, bool is_neg, + [[maybe_unused]] int rounding) { + // Negate in two's complement when x < 0 so that floor(x * log2(b)) is the + // arithmetic right shift by 54, and the fractional part u in [0, 1) is the + // low 54 bits. + // Setting the LSB (| 1U) prevents InstCombine's demanded-bits analysis from + // narrowing the free 32-bit low-word extraction mask 0xffff'ffffU to + // 0xffff'fc00U inside quick_mul_hi on 32-bit targets. Even when the + // fractional part is 0, u = Frac64(1) satisfies (a * 1) >> 64 == 0, so p + // remains 0 in all rounding modes. + int64_t u_signed = + is_neg ? -static_cast<int64_t>(u_bits) : static_cast<int64_t>(u_bits); + int k = + (static_cast<int32_t>(static_cast<uint64_t>(u_signed) >> 32) >> 22) + 126; + Frac64 u((static_cast<uint64_t>(u_signed) << 10) | 1U); + +#if defined(LIBC_TYPES_HAS_INT128) && !defined(LIBC_MATH_HAS_SMALL_TABLES) + // When 128-bit integers are available (64-bit targets) and small code size is + // not requested, each Frac64 multiplication is a single native 64x64 -> 128 + // multiply-high instruction, and out-of-order 64-bit CPUs have ample + // registers and multiple integer multiplier pipelines: + // 1. Evaluate p ~ 2^u - 1 on [0, 1) using an unrolled 2-way Estrin/Horner + // scheme (evaluating even and odd powers in parallel in u^2) to halve the + // critical-path latency of the polynomial evaluation. + // 2. Take a fast return path for the common case of normal outputs in + // round-to-nearest mode (k >= 0 && rounding == FE_TONEAREST), bypassing + // the subnormal and directed-rounding logic below. + Frac64 u2 = u * u; + Frac64 p_even = + fputil::polyeval(u2, EXP2F_COEFFS[0], EXP2F_COEFFS[2], EXP2F_COEFFS[4], + EXP2F_COEFFS[6], EXP2F_COEFFS[8], EXP2F_COEFFS[10]); + Frac64 p_odd = + fputil::polyeval(u2, EXP2F_COEFFS[1], EXP2F_COEFFS[3], EXP2F_COEFFS[5], + EXP2F_COEFFS[7], EXP2F_COEFFS[9]); + Frac64 p = fputil::multiply_add(p_odd, u, p_even) * u; + + if (LIBC_LIKELY(k >= 0 && rounding == FE_TONEAREST)) + return (((static_cast<uint32_t>(p.val[0] >> 40) + 1U) >> 1) + + (static_cast<uint32_t>(k + 1) << 23)); +#else // !defined(LIBC_TYPES_HAS_INT128) || defined(LIBC_MATH_HAS_SMALL_TABLES) + // On 32-bit targets without native 128-bit integers (such as 32-bit ARM + // microcontrollers without hardware double-precision FPU), or when + // LIBC_MATH_HAS_SMALL_TABLES is enabled, unrolling or using Estrin's scheme + // would increase register pressure and bloat code size (by ~470-810 bytes on + // 32-bit targets and ~70-360 bytes on 64-bit targets). Instead, evaluate + // p ~ 2^u - 1 using a compact, non-unrolled Horner loop over EXP2F_COEFFS and + // share the unified normal/subnormal rounding epilogue below. + Frac64 p(0); + LIBC_LOOP_NOUNROLL + for (int i = 10; i >= 0; --i) + p = (p + EXP2F_COEFFS[i]) * u; +#endif // defined(LIBC_TYPES_HAS_INT128) && !defined(LIBC_MATH_HAS_SMALL_TABLES) + + // Combine 2^u = 1 + p with 2^(k - 126): + // Place the explicit leading 1 of 2^u at bit 31 and the top 31 bits of p in + // bits [0..30]. + // 1. Normal result (k >= 0, biased exponent k + 1 in [1, 254]): + // Shift right by 7 to place the leading 1 at bit 24 (which after >> 1 + // contributes +1 to the biased exponent field, added to k << 23). + // 2. Subnormal result (k < 0, i.e., k in [-24, -1]): + // Shift right by 7 - k in [8, 31] to place both the leading 1 and the + // fractional bits directly at their subnormal bit positions. + uint32_t mant = static_cast<uint32_t>(p.val[0] >> 33) | 0x8000'0000U; + uint32_t shift = 7; + uint32_t exp_bits = static_cast<uint32_t>(k) << 23; + + if (LIBC_UNLIKELY(k < 0)) { + shift = static_cast<uint32_t>(7 - k); + exp_bits = 0; + } + +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (LIBC_UNLIKELY(rounding != FE_TONEAREST)) { + uint32_t round_up = 0; + if (LIBC_UNLIKELY(rounding == FE_UPWARD)) { + uint32_t mask = ~0U >> (31U - shift); + round_up = static_cast<uint32_t>( + ((mant & mask) | static_cast<uint32_t>(p.val[0])) != 0); + } + + return ((mant >> shift) >> 1) + round_up + exp_bits; + } +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + + // Round to nearest. + return (((mant >> shift) + 1U) >> 1) + exp_bits; +} + +} // namespace static_rounding +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP2F_INTEGER_UTILS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_eval.h new file mode 100644 index 000000000000..ef75ee37c5be --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_eval.h @@ -0,0 +1,153 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Double-precision implementation of exp. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP_DOUBLE_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP_DOUBLE_EVAL_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#include "src/__support/math/exp_double_utils.h" +#else +#include "src/__support/math/exp_utils.h" +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace double_eval { + +LIBC_ALWAYS_INLINE double exp(double x) { + using FPBits = fputil::FPBits<double>; + FPBits xbits(x); + + uint64_t x_u = xbits.uintval(); + uint64_t x_abs = xbits.abs().uintval(); + + // Bound constants (with biased exponent and mantissa bits): + // - Tiny bound: 2^-53 = 0x1.0p-53 (for |x| < 2^-53, exp(x) rounds to 1.0 + x) + constexpr uint64_t TINY_BOUND = 0x3ca0'0000'0000'0000ULL; + // - Overflow bound: + // > round(log(2^1023 * (2 - 2^-52)), D, RU) = 0x1.62e42fefa39f0p+9 + // > round(log(2^1023 * (2 - 2^-52)), D, RD) = 0x1.62e42fefa39efp+9 + // > round(log(2^1023 * (2 - 2^-52)), D, RN) = 0x1.62e42fefa39efp+9 + // > round(exp(0x1.62e42fefa39f0p+9), D, RN) = +inf + constexpr uint64_t OVERFLOW_BOUND = 0x4086'2e42'fefa'39f0ULL; + // -0x1.62e42fefa39f0p+9: + constexpr uint64_t NEG_OVERFLOW_BOUND = 0xc086'2e42'fefa'39f0ULL; + // - Underflow bound: min denormal number / 2 = 2^-1075 + // > round(log(2^-1075), D, RN) = -0x1.74910d52d3052p+9 + constexpr uint64_t UNDERFLOW_BOUND = 0xc087'4910'd52d'3052ULL; + + // Normal range: 2^-53 <= |x| < 0x1.62e42fefa39f0p+9. + if (LIBC_UNLIKELY(x_abs - TINY_BOUND >= OVERFLOW_BOUND - TINY_BOUND)) { + // Exclude non-underflowing negative inputs in + // (UNDERFLOW_BOUND, NEG_OVERFLOW_BOUND]. + if (LIBC_LIKELY(x_u < NEG_OVERFLOW_BOUND || x_u >= UNDERFLOW_BOUND)) + return set_exceptional(x); + } + + // Now -0x1.74910d52d3052p+9 < x <= -0x1.0p-53 or + // 0x1.0p-53 <= x < 0x1.62e42fefa39f0p+9. + + // Range reduction: + // Let x = k * (log(2) / 2^N) + u + // in which: + // k = round(x * 2^N * log2(e)) + // hi = k >> N + // idx = k & (2^N - 1) + // then: + // exp(x) = 2^hi * 2^(idx / 2^N) * exp(u). + double x_scaled = x * (EXP_SCALE * LOG2_E.hi); + double kd = fputil::nearest_integer(x_scaled); + int k = static_cast<int>(kd); + + int hi = k >> EXP_N_BITS; + unsigned idx = static_cast<unsigned>(k & EXP_MASK); + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + double t1 = fputil::multiply_add(kd, MLOG_2_EXP2_HI, x); // exact + double u = fputil::multiply_add(kd, MLOG_2_EXP2_MID, t1); + return exp2_eval(x, u, hi, idx); +#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + // With FMA, we use the full 53-bit: + // MLOG_2_HI_53 = -2^-7 * log(2) = -LOG_2.hi * EXP_SCALE_INV (lsb = 2^-60) + // to compute: + // u = x - k * 2^-7 * log(2) ~ t1 + d + // where: + // t1 = fma(kd, MLOG_2_HI_53, x) + // d = kd * MLOG_2_LO_53 (|d| < 2^18 * 2^-62 = 2^-44). + // + // For k != 0, |x| >= 2^-8 * log(2) > 2^-9 so lsb(x) >= 2^-61, and since kd is + // an integer, lsb(kd * MLOG_2_HI_53) >= 2^-60. Because |t1| < 2^-8, every + // non-zero bit of x + kd * MLOG_2_HI_53 lies in [2^-61, 2^-9] (at most 53 + // bits), so: + // t1 = fma(kd, MLOG_2_HI_53, x) + // is exact. + // + // In exp2_eval, P(u.hi) is evaluated at u.hi = t1 alone. Writing: + // exp(t1 + d) = exp(t1) * exp(d) + // ~ (1 + t1 + t1^2 * P(t1)) * (1 + d) + // ~ 1 + t1 + d * (1 + t1) + t1^2 * P(t1), + // we fold the linear cross-term t1 * d into: + // u.lo = fma(t1, d, d), + // bounding the omitted term: + // |t1^2 * P(t1) * d| < 2^-63. + constexpr double MLOG_2_HI_53 = -LOG_2.hi * EXP_SCALE_INV; + constexpr double MLOG_2_LO_53 = -LOG_2.lo * EXP_SCALE_INV; + + double t1 = fputil::multiply_add(kd, MLOG_2_HI_53, x); // exact + double d = kd * MLOG_2_LO_53; + double u_lo = fputil::multiply_add(t1, d, d); + DoubleDouble u = {u_lo, t1}; +#else // !LIBC_TARGET_CPU_HAS_FMA_DOUBLE + // Without FMA, we use a 35-bit-precision high part MLOG_2_EXP2_HI (with lsb = + // 2^-42) so that: + // kd * MLOG_2_EXP2_HI + // has at most 18 + 35 = 53 significant bits and is exact in double precision + // for |kd| < 2^18, and: + // t1 = x + kd * MLOG_2_EXP2_HI + // is exact by Sterbenz's lemma. + // + // We then split t1 at 2^-30 before adding t2 = kd * MLOG_2_EXP2_MID: + // u_hi = (t1 + SPLIT_30) - SPLIT_30 (exact, lsb = 2^-30) + // t1_lo = t1 - u_hi (exact, |t1_lo| <= 2^-31) + // u_lo = t1_lo + t2 (|u_lo| < 2^-26). + // This gives lsb(u_hi) >= 2^-30 so that m_hi * u_hi is exact in exp2_eval, + // while keeping |u_lo| < 2^-26 so the rounding error of: + // u_lo = t1_lo + t2 + // is bounded by 2^(-26 - 53) = 2^-79. + double t1 = fputil::multiply_add(kd, MLOG_2_EXP2_HI, x); // exact + double t2 = kd * MLOG_2_EXP2_MID; + double u_hi = (t1 + SPLIT_30) - SPLIT_30; // exact, lsb = 2^-30 + double t1_lo = t1 - u_hi; // exact + double u_lo = t1_lo + t2; + DoubleDouble u = {u_lo, u_hi}; +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + return exp2_eval(x, u, hi, idx, EXP_ERR_D, &LOG2_E_192); +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace double_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP_DOUBLE_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_utils.h new file mode 100644 index 000000000000..00c43235f63e --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_double_utils.h @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Shared double-precision utilities and tables for exponential functions when +/// LIBC_MATH_HAS_SKIP_ACCURATE_PASS is enabled. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP_DOUBLE_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXP_DOUBLE_UTILS_H + +#include "hdr/errno_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/fp_bitwise.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/math/exp_utils.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace double_eval { + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +#ifdef LIBC_MATH_HAS_SMALL_TABLES + +LIBC_INLINE_VAR constexpr int EXP_N_BITS = 3; +LIBC_INLINE_VAR constexpr double EXP_SCALE = 8.0; +LIBC_INLINE_VAR constexpr double EXP_SCALE_INV = 0x1.0p-3; +LIBC_INLINE_VAR constexpr int EXP_MASK = 0x07; + +// Degree-5 polynomial approximation for (exp(x) - 1 - x) / x^2 on +// [-2^-4 * log(2), 2^-4 * log(2)]: +// Generated by Sollya with: +// > display = hexadecimal!; +// > prec = 500; +// > P = fpminimax((exp(x) - 1 - x)/x^2, 5, [|D...|], +// [-2^(-4) * log(2), 2^(-4) * log(2)]); +// > dirtyinfnorm(exp(x) - (1 + x + x^2 * P), +// [-2^(-4) * log(2), 2^(-4) * log(2)]); +// 0x1.6828...p-57 < 2^-56. +LIBC_INLINE_VAR constexpr double EXP_P_COEFFS[6] = { + 0x1.000000000002ep-1, // p_0 + 0x1.555555555549cp-3, // p_1 + 0x1.5555554e95a5p-5, // p_2 + 0x1.11111114c1e11p-7, // p_3 + 0x1.6c1b70af254c4p-10, // p_4 + 0x1.a01b62c901438p-13, // p_5 +}; + +// Evaluate P(u) ~ (e^u - 1 - u) / u^2 using Estrin's scheme: +LIBC_ALWAYS_INLINE double exp_poly(double u, double u2) { + double c0 = fputil::multiply_add(u, EXP_P_COEFFS[1], EXP_P_COEFFS[0]); + double c1 = fputil::multiply_add(u, EXP_P_COEFFS[3], EXP_P_COEFFS[2]); + double u4 = u2 * u2; + double c2 = fputil::multiply_add(u, EXP_P_COEFFS[5], EXP_P_COEFFS[4]); + double c01 = fputil::multiply_add(u2, c1, c0); + return fputil::multiply_add(u4, c2, c01); +} + +// Lookup table for 2^(k * 2^-3) with k = 0..7. +// Generated by Sollya with: +// > display = hexadecimal!; +// > for i from 0 to 7 do print(round(2^(i * 2^-3), D, RN), ","); +LIBC_INLINE_VAR constexpr double EXP2_MID[8] = { + 0x1.0000000000000p0, 0x1.172b83c7d517bp0, 0x1.306fe0a31b715p0, + 0x1.4bfdad5362a27p0, 0x1.6a09e667f3bcdp0, 0x1.8ace5422aa0dbp0, + 0x1.ae89f995ad3adp0, 0x1.d5818dcfba487p0, +}; + +// Splitting -2^-3 * log(2) ~ hi + lo with 38-bit-precision hi part so that +// kd * MLOG_2_EXP2_HI is exact for |kd| < 2^14: +// > hi = round(-2^-3 * log(2), 38, RN); +// > lo = round(-2^-3 * log(2) - hi, D, RN); +LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_HI = -0x1.62e42fefap-4; +LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_MID = -0x1.cf79abc9e3b3ap-43; + +#else // !LIBC_MATH_HAS_SMALL_TABLES + +// Lookup table for 2^(k * 2^-7) with k = 0..127. +// Generated by Sollya with: +// > display = hexadecimal!; +// > for i from 0 to 127 do print(round(2^(i * 2^-7), D, RN), ","); +LIBC_INLINE_VAR constexpr double EXP2_MID[128] = { + 0x1.0000000000000p0, 0x1.0163da9fb3335p0, 0x1.02c9a3e778061p0, + 0x1.04315e86e7f85p0, 0x1.059b0d3158574p0, 0x1.0706b29ddf6dep0, + 0x1.0874518759bc8p0, 0x1.09e3ecac6f383p0, 0x1.0b5586cf9890fp0, + 0x1.0cc922b7247f7p0, 0x1.0e3ec32d3d1a2p0, 0x1.0fb66affed31bp0, + 0x1.11301d0125b51p0, 0x1.12abdc06c31ccp0, 0x1.1429aaea92dep0, + 0x1.15a98c8a58e51p0, 0x1.172b83c7d517bp0, 0x1.18af9388c8deap0, + 0x1.1a35beb6fcb75p0, 0x1.1bbe084045cd4p0, 0x1.1d4873168b9aap0, + 0x1.1ed5022fcd91dp0, 0x1.2063b88628cd6p0, 0x1.21f49917ddc96p0, + 0x1.2387a6e756238p0, 0x1.251ce4fb2a63fp0, 0x1.26b4565e27cddp0, + 0x1.284dfe1f56381p0, 0x1.29e9df51fdee1p0, 0x1.2b87fd0dad99p0, + 0x1.2d285a6e4030bp0, 0x1.2ecafa93e2f56p0, 0x1.306fe0a31b715p0, + 0x1.32170fc4cd831p0, 0x1.33c08b26416ffp0, 0x1.356c55f929ff1p0, + 0x1.371a7373aa9cbp0, 0x1.38cae6d05d866p0, 0x1.3a7db34e59ff7p0, + 0x1.3c32dc313a8e5p0, 0x1.3dea64c123422p0, 0x1.3fa4504ac801cp0, + 0x1.4160a21f72e2ap0, 0x1.431f5d950a897p0, 0x1.44e086061892dp0, + 0x1.46a41ed1d0057p0, 0x1.486a2b5c13cdp0, 0x1.4a32af0d7d3dep0, + 0x1.4bfdad5362a27p0, 0x1.4dcb299fddd0dp0, 0x1.4f9b2769d2ca7p0, + 0x1.516daa2cf6642p0, 0x1.5342b569d4f82p0, 0x1.551a4ca5d920fp0, + 0x1.56f4736b527dap0, 0x1.58d12d497c7fdp0, 0x1.5ab07dd485429p0, + 0x1.5c9268a5946b7p0, 0x1.5e76f15ad2148p0, 0x1.605e1b976dc09p0, + 0x1.6247eb03a5585p0, 0x1.6434634ccc32p0, 0x1.6623882552225p0, + 0x1.68155d44ca973p0, 0x1.6a09e667f3bcdp0, 0x1.6c012750bdabfp0, + 0x1.6dfb23c651a2fp0, 0x1.6ff7df9519484p0, 0x1.71f75e8ec5f74p0, + 0x1.73f9a48a58174p0, 0x1.75feb564267c9p0, 0x1.780694fde5d3fp0, + 0x1.7a11473eb0187p0, 0x1.7c1ed0130c132p0, 0x1.7e2f336cf4e62p0, + 0x1.80427543e1a12p0, 0x1.82589994cce13p0, 0x1.8471a4623c7adp0, + 0x1.868d99b4492edp0, 0x1.88ac7d98a6699p0, 0x1.8ace5422aa0dbp0, + 0x1.8cf3216b5448cp0, 0x1.8f1ae99157736p0, 0x1.9145b0b91ffc6p0, + 0x1.93737b0cdc5e5p0, 0x1.95a44cbc8520fp0, 0x1.97d829fde4e5p0, + 0x1.9a0f170ca07bap0, 0x1.9c49182a3f09p0, 0x1.9e86319e32323p0, + 0x1.a0c667b5de565p0, 0x1.a309bec4a2d33p0, 0x1.a5503b23e255dp0, + 0x1.a799e1330b358p0, 0x1.a9e6b5579fdbfp0, 0x1.ac36bbfd3f37ap0, + 0x1.ae89f995ad3adp0, 0x1.b0e07298db666p0, 0x1.b33a2b84f15fbp0, + 0x1.b59728de5593ap0, 0x1.b7f76f2fb5e47p0, 0x1.ba5b030a1064ap0, + 0x1.bcc1e904bc1d2p0, 0x1.bf2c25bd71e09p0, 0x1.c199bdd85529cp0, + 0x1.c40ab5fffd07ap0, 0x1.c67f12e57d14bp0, 0x1.c8f6d9406e7b5p0, + 0x1.cb720dcef9069p0, 0x1.cdf0b555dc3fap0, 0x1.d072d4a07897cp0, + 0x1.d2f87080d89f2p0, 0x1.d5818dcfba487p0, 0x1.d80e316c98398p0, + 0x1.da9e603db3285p0, 0x1.dd321f301b46p0, 0x1.dfc97337b9b5fp0, + 0x1.e264614f5a129p0, 0x1.e502ee78b3ff6p0, 0x1.e7a51fbc74c83p0, + 0x1.ea4afa2a490dap0, 0x1.ecf482d8e67f1p0, 0x1.efa1bee615a27p0, + 0x1.f252b376bba97p0, 0x1.f50765b6e454p0, 0x1.f7bfdad9cbe14p0, + 0x1.fa7c1819e90d8p0, 0x1.fd3c22b8f71f1p0, +}; + +#endif // LIBC_MATH_HAS_SMALL_TABLES + +LIBC_NOINLINE LIBC_INLINE double exp_denorm(double x, int hi, double r, + bool is_exp2) { + using FPBits = fputil::FPBits<double>; + if (is_exp2 && LIBC_UNLIKELY(static_cast<double>(hi) == x)) + return FPBits(uint64_t(1) << (hi + 1074)).get_val(); + + double res = ziv_test_denorm</*SKIP_ZIV_TEST=*/true>(hi, r, 0.0, 0.0).value(); + if (LIBC_UNLIKELY(FPBits(res).is_normal())) + return res; + + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<double>(); + return res; +} + +LIBC_MATH_SMALL_TABLES_INLINE double +exp2_eval(double x, double u, int hi, unsigned idx, bool is_exp2 = false) { + double exp2_mid = EXP2_MID[idx]; + double u2 = u * u; + double p = exp_poly(u, u2); + // u + u^2 * p + double poly_lo = fputil::multiply_add(u2, p, u); + double r = fputil::multiply_add(exp2_mid, poly_lo, exp2_mid); + + if (LIBC_UNLIKELY(hi <= -1022)) + return exp_denorm(x, hi, r, is_exp2); + + return scale_exp2(r, hi); +} + +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace double_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP_DOUBLE_UTILS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_utils.h index e46ede2ed8e2..fa909c824efc 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_utils.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/exp_utils.h @@ -1,17 +1,38 @@ -//===-- Common utils for exp function ---------------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Shared utilities and tables for double-precision exponential functions. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXP_UTILS_H #define LLVM_LIBC_SRC___SUPPORT_MATH_EXP_UTILS_H +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/optional.h" +#include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/fp_bitwise.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#include "src/__support/math/exp2_accurate_128.h" +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS namespace LIBC_NAMESPACE_DECL { @@ -24,35 +45,29 @@ namespace LIBC_NAMESPACE_DECL { template <bool SKIP_ZIV_TEST = false> LIBC_INLINE constexpr cpp::optional<double> ziv_test_denorm(int hi, double mid, double lo, double err) { - using FPBits = typename fputil::FPBits<double>; - // Scaling factor = 1/(min normal number) = 2^1022 - int64_t exp_hi = - static_cast<int64_t>(hi + 1022) * (1LL << FPBits::FRACTION_LEN); - double mid_hi = cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(mid)); - double lo_scaled = - (lo != 0.0) ? cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(lo)) - : 0.0; + int scale_up = hi + 1022; + double mid_hi = fputil::scale_exp2(mid, scale_up); + double lo_scaled = (lo != 0.0) ? fputil::scale_exp2(lo, scale_up) : 0.0; double extra_factor = 0.0; - uint64_t scale_down = 0x3FE0'0000'0000'0000; // 1022 in the exponent field. + int scale_down = -1022; // Result is denormal if (mid_hi + lo_scale < 1.0). if ((1.0 - mid_hi) > lo_scaled) { // Extra rounding step is needed, which adds more rounding errors. err += 0x1.0p-52; extra_factor = 1.0; - scale_down = 0x3FF0'0000'0000'0000; // 1023 in the exponent field. + scale_down = -1023; } // By adding 1.0, the results will have similar rounding points as denormal // outputs. if constexpr (SKIP_ZIV_TEST) { double r = extra_factor + (mid_hi + lo_scaled); - return cpp::bit_cast<double>(cpp::bit_cast<uint64_t>(r) - scale_down); + return fputil::scale_exp2(r, scale_down); } else { - double err_scaled = - cpp::bit_cast<double>(exp_hi + cpp::bit_cast<int64_t>(err)); + double err_scaled = fputil::scale_exp2(err, scale_up); double lo_u = lo_scaled + err_scaled; double lo_l = lo_scaled - err_scaled; @@ -60,14 +75,484 @@ ziv_test_denorm(int hi, double mid, double lo, double err) { double upper = extra_factor + (mid_hi + lo_u); double lower = extra_factor + (mid_hi + lo_l); - if (LIBC_LIKELY(upper == lower)) { - return cpp::bit_cast<double>(cpp::bit_cast<uint64_t>(upper) - scale_down); - } + if (LIBC_LIKELY(upper == lower)) + return fputil::scale_exp2(upper, scale_down); return cpp::nullopt; } } +namespace math { +namespace double_eval { + +using fputil::DoubleDouble; +using fputil::scale_exp2; + +// log(2) in double-double precision, generated by Sollya with: +// > display = hexadecimal!; +// > prec = 500; +// > hi = round(log(2), D, RN); +// > lo = round(log(2) - hi, D, RN); +// > print("{", lo, ",", hi, "};"); +LIBC_INLINE_VAR constexpr DoubleDouble LOG_2 = {0x1.abc9e3b39803fp-56, + 0x1.62e42fefa39efp-1}; + +// log2(e) in double-double precision, generated by Sollya with: +// > display = hexadecimal!; +// > prec = 500; +// > hi = round(log2(exp(1)), D, RN); +// > lo = round(log2(exp(1)) - hi, D, RN); +// > print("{", lo, ",", hi, "};"); +LIBC_INLINE_VAR constexpr DoubleDouble LOG2_E = {0x1.777d0ffda0d24p-56, + 0x1.71547652b82fep+0}; + +// Check for exceptional cases (tiny, overflow, underflow, inf, or nan) for +// exp, exp2, and exp10. Callers have already verified that x is in the exact +// tiny, underflow, or overflow/inf/nan range for the specific function before +// calling this helper. +LIBC_NOINLINE LIBC_INLINE double set_exceptional(double x) { + using FPBits = fputil::FPBits<double>; + FPBits xbits(x); + + // |x| <= 0x1.0p-53 (caller has already checked the exact tiny bound): + constexpr uint64_t TINY_BOUND = 0x3ca0'0000'0000'0000ULL; + if (xbits.abs().uintval() <= TINY_BOUND) { + // b^x ~ 1 + x + return 1.0 + x; + } + + // Negative underflow or -inf/nan (caller has already excluded + // non-underflowing negative inputs): + if (xbits.is_neg()) { + // b^(-Inf) = 0 + if (xbits.is_inf()) + return 0.0; + + // b^(nan) = nan + // Adding 0.0 to silence signaling nan. + if (xbits.is_nan()) + return x + 0.0; + + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<double>(); +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (fputil::quick_get_round() == FE_UPWARD) + return FPBits::min_subnormal().get_val(); +#endif + return 0.0; + } + + // Positive overflow or +inf/nan (caller has already checked the exact + // overflow bound) + + // x is finite and positive + if (xbits.uintval() < FPBits::inf().uintval()) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_overflow_except_if_required<double>(); +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + int rounding = fputil::quick_get_round(); + if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) + return FPBits::max_normal().get_val(); +#endif + return FPBits::inf().get_val(); + } + // x is +inf or nan + // Adding `inf` to silence signaling nan. + return x + FPBits::inf().get_val(); +} + +#if !defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) || \ + !defined(LIBC_MATH_HAS_SMALL_TABLES) + +LIBC_INLINE_VAR constexpr int EXP_N_BITS = 7; +LIBC_INLINE_VAR constexpr double EXP_SCALE = 128.0; // 2^EXP_N_BITS = 2^7 +LIBC_INLINE_VAR constexpr double EXP_SCALE_INV = 0x1.0p-7; +LIBC_INLINE_VAR constexpr int EXP_MASK = 0x7f; + +// Polynomial approximation for (exp(x) - 1 - x) / x^2 on +// [-B, B] with B = 2^-8 * log(2): +// +// 1) A degree-3 minimax polynomial P0 for (exp(x) - 1 - x) / x^2 on [-B, B] +// (which minimizes the error of exp(x) - (1 + x + x^2 * P0(x)) weighted by +// 1 / x^2, i.e., relative error with respect to x^2): +// > display = hexadecimal!; +// > prec = 500; +// > B = 2^(-8) * log(2); +// > P0 = fpminimax((exp(x) - 1 - x)/x^2, 3, [|D...|], [-B, B]); +// > dirtyinfnorm(exp(x) - (1 + x + x^2 * P0), [-B, B]); +// 0x1.4362...p-64 < 2^-63. +// +// Some explanation for the errors (from Chebyshev polynomials): +// Because P0 minimizes |(exp(x) - 1 - x) / x^2 - P0(x)|, its error is governed +// by the degree-4 Chebyshev polynomial: +// T_4(x / B) = 8*(x / B)^4 - 8*(x / B)^2 + 1 +// approximating the leading omitted Taylor term x^4 / 720, with magnitude: +// B^4 / (720 * 8). +// Multiplying by x^2 gives an absolute error of: +// x^2 * B^4 / (720 * 8) * T_4(x / B), +// peaking at x = +-B with: +// B^6 / (720 * 8) ~ 0x1.4309...p-64 < 2^-63. +// +// 2) If we instead minimize the absolute error of exp(x) - (1 + x + P(x)) +// directly on [-B, B] with monomials [|2, 3, 4, 5|]: +// > P = fpminimax(exp(x) - 1 - x, [|2, 3, 4, 5|], [|D...|], [-B, B], +// absolute); +// > dirtyinfnorm(exp(x) - (1 + x + P), [-B, B]); +// 0x1.8e05...p-66 < 2^-65. +// +// Some explanation for the better errors from Chebyshev polynomials: +// The free x^2 and x^4 coefficients in P(x) approximate the omitted x^6 / 720 +// term on [-B, B] subject to vanishing at x = 0. Setting t = (x / B)^2 in +// [0, 1], this is equivalent to approximating t^3 on [0, 1] by: +// a_2 * t^2 + a_1 * t +// vanishing at t = 0. +// The degree-3 Chebyshev polynomial: +// T_3(z) = 4*z^3 - 3*z +// has a root at z = -sqrt(3)/2 and three alternating extrema +-1 on +// [-sqrt(3)/2, 1] at z = -1/2, 1/2, 1. +// Mapping t in [0, 1] affinely onto z in [-sqrt(3)/2, 1] via: +// z = ((2 + sqrt(3)) / 2) * t - sqrt(3) / 2 +// gives an error curve T_3(z) that vanishes at t = 0 and equioscillates three +// times on (0, 1], with leading coefficient: +// 4 * ((2 + sqrt(3)) / 2)^3 = (2 + sqrt(3))^3 / 2. +// Dividing by this leading coefficient gives a maximum error on [-B, B] of: +// (2 / (2 + sqrt(3))^3) * B^6 / 720 = 2 * (2 - sqrt(3))^3 * B^6 / 720 +// ~ 0x1.8dba...p-66 < 2^-65, +// reducing the maximum error compared to P0 by: +// (2 + sqrt(3))^3 / 16 > 3x. +LIBC_INLINE_VAR constexpr double EXP_P_COEFFS[4] = { + 0x1.ffffffffffdbdp-2, // p_0 + 0x1.555555555543dp-3, // p_1 + 0x1.55555cf16d6eep-5, // p_2 + 0x1.111116782220ap-7, // p_3 +}; + +// Evaluate P(u) ~ (e^u - 1 - u) / u^2 using Estrin's scheme: +LIBC_ALWAYS_INLINE double exp_poly(double u, double u2) { + double c0 = fputil::multiply_add(u, EXP_P_COEFFS[1], EXP_P_COEFFS[0]); + double c1 = fputil::multiply_add(u, EXP_P_COEFFS[3], EXP_P_COEFFS[2]); + return fputil::multiply_add(u2, c1, c0); +} + +// Splitting -2^-7 * log(2) ~ hi + lo with 35-bit-precision hi part so that +// kd * MLOG_2_EXP2_HI is exact for |kd| < 2^18: +// > hi = round(-2^-7 * log(2), 35, RN); +// > lo = round(-2^-7 * log(2) - hi, D, RN); +LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_HI = -0x1.62e42fefcp-8; +LIBC_INLINE_VAR constexpr double MLOG_2_EXP2_MID = 0x1.c610ca86c3899p-44; + +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS || !LIBC_MATH_HAS_SMALL_TABLES + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +// Fixed-point splitting constants (ulp = 2^-18, 2^-30) and pre-split +// 12-bit + 53-bit logarithm constants for exact non-FMA multiplication without +// Veltkamp splitting: +LIBC_INLINE_VAR constexpr double SPLIT_18 = 0x1.8p34; // 1.5 * 2^(-18 + 52) +LIBC_INLINE_VAR constexpr double SPLIT_30 = 0x1.8p22; // 1.5 * 2^(-30 + 52) + +// Splitting log(2) ~ hi + lo with 12-bit-precision hi part. +// > hi = round(log(2), 12, RN); +// > lo = round(log(2) - hi, D, RN); +LIBC_INLINE_VAR constexpr double LOG_2_HI_12 = 0x1.62ep-1; +LIBC_INLINE_VAR constexpr double LOG_2_LO_12 = 0x1.0bfbe8e7bcd5ep-15; + +// Error bounds for double precision fast path (N = 7, Ziv failure rate < +// 0.05%): +LIBC_INLINE_VAR constexpr double EXP_ERR_D = 0x1.4p-62; +LIBC_INLINE_VAR constexpr double EXP2_ERR_D = 0x1.0p-64; + +// Lookup table for 2^(i * 2^-7) with i = 0..127. +// Generated by Sollya with: +// > for i from 0 to 127 do { +// a = 2^(i * 2^-7); +// b = round(a, D, RN); +// c = round(a - b, D, RN); +// print("{", c, ",", b, "},"); +// }; +LIBC_INLINE_VAR constexpr DoubleDouble EXP2_MID[128] = { + {0, 0x1p0}, + {0x1.b61299ab8cdb7p-54, 0x1.0163da9fb3335p0}, + {-0x1.19083535b085dp-56, 0x1.02c9a3e778061p0}, + {-0x1.0a31c1977c96ep-54, 0x1.04315e86e7f85p0}, + {0x1.d73e2a475b465p-55, 0x1.059b0d3158574p0}, + {-0x1.c91dfe2b13c27p-55, 0x1.0706b29ddf6dep0}, + {0x1.186be4bb284ffp-57, 0x1.0874518759bc8p0}, + {0x1.1487818316136p-54, 0x1.09e3ecac6f383p0}, + {0x1.8a62e4adc610bp-54, 0x1.0b5586cf9890fp0}, + {0x1.01edc16e24f71p-54, 0x1.0cc922b7247f7p0}, + {0x1.03a1727c57b53p-59, 0x1.0e3ec32d3d1a2p0}, + {-0x1.b9bedc44ebd7bp-57, 0x1.0fb66affed31bp0}, + {-0x1.6c51039449b3ap-54, 0x1.11301d0125b51p0}, + {-0x1.1b514b36ca5c7p-58, 0x1.12abdc06c31ccp0}, + {-0x1.32fbf9af1369ep-54, 0x1.1429aaea92dep0}, + {0x1.2406ab9eeab0ap-55, 0x1.15a98c8a58e51p0}, + {-0x1.19041b9d78a76p-55, 0x1.172b83c7d517bp0}, + {-0x1.11023d1970f6cp-54, 0x1.18af9388c8deap0}, + {0x1.e5b4c7b4968e4p-55, 0x1.1a35beb6fcb75p0}, + {-0x1.95386352ef607p-54, 0x1.1bbe084045cd4p0}, + {0x1.e016e00a2643cp-54, 0x1.1d4873168b9aap0}, + {-0x1.1df98027bb78cp-54, 0x1.1ed5022fcd91dp0}, + {0x1.dc775814a8495p-55, 0x1.2063b88628cd6p0}, + {0x1.2a97e9494a5eep-55, 0x1.21f49917ddc96p0}, + {0x1.9b07eb6c70573p-54, 0x1.2387a6e756238p0}, + {0x1.ac155bef4f4a4p-55, 0x1.251ce4fb2a63fp0}, + {0x1.2bd339940e9d9p-55, 0x1.26b4565e27cddp0}, + {-0x1.a4c3a8c3f0d7ep-54, 0x1.284dfe1f56381p0}, + {0x1.612e8afad1255p-55, 0x1.29e9df51fdee1p0}, + {-0x1.10adcd6381aa4p-59, 0x1.2b87fd0dad99p0}, + {0x1.0024754db41d5p-54, 0x1.2d285a6e4030bp0}, + {0x1.1ca0f45d52383p-56, 0x1.2ecafa93e2f56p0}, + {0x1.6f46ad23182e4p-55, 0x1.306fe0a31b715p0}, + {0x1.a9ce78e18047cp-55, 0x1.32170fc4cd831p0}, + {0x1.32721843659a6p-54, 0x1.33c08b26416ffp0}, + {-0x1.b5cee5c4e4628p-55, 0x1.356c55f929ff1p0}, + {-0x1.63aeabf42eae2p-54, 0x1.371a7373aa9cbp0}, + {-0x1.e958d3c9904bdp-54, 0x1.38cae6d05d866p0}, + {-0x1.5e436d661f5e3p-56, 0x1.3a7db34e59ff7p0}, + {-0x1.efff8375d29c3p-54, 0x1.3c32dc313a8e5p0}, + {0x1.ada0911f09ebcp-55, 0x1.3dea64c123422p0}, + {-0x1.7d023f956f9f3p-54, 0x1.3fa4504ac801cp0}, + {-0x1.ef3691c309278p-58, 0x1.4160a21f72e2ap0}, + {-0x1.1c7dde35f7999p-55, 0x1.431f5d950a897p0}, + {0x1.89b7a04ef80dp-59, 0x1.44e086061892dp0}, + {0x1.c944bd1648a76p-54, 0x1.46a41ed1d0057p0}, + {0x1.3c1a3b69062fp-56, 0x1.486a2b5c13cdp0}, + {0x1.9cb62f3d1be56p-54, 0x1.4a32af0d7d3dep0}, + {0x1.d4397afec42e2p-56, 0x1.4bfdad5362a27p0}, + {0x1.8ecdbbc6a7833p-54, 0x1.4dcb299fddd0dp0}, + {-0x1.4b309d25957e3p-54, 0x1.4f9b2769d2ca7p0}, + {-0x1.f768569bd93efp-55, 0x1.516daa2cf6642p0}, + {-0x1.07abe1db13cadp-55, 0x1.5342b569d4f82p0}, + {-0x1.d689cefede59bp-55, 0x1.551a4ca5d920fp0}, + {0x1.9bb2c011d93adp-54, 0x1.56f4736b527dap0}, + {0x1.295e15b9a1de8p-55, 0x1.58d12d497c7fdp0}, + {0x1.6324c054647adp-54, 0x1.5ab07dd485429p0}, + {0x1.c4b1b816986a2p-60, 0x1.5c9268a5946b7p0}, + {0x1.ba6f93080e65ep-54, 0x1.5e76f15ad2148p0}, + {-0x1.3e2429b56de47p-54, 0x1.605e1b976dc09p0}, + {-0x1.383c17e40b497p-54, 0x1.6247eb03a5585p0}, + {-0x1.c483c759d8933p-55, 0x1.6434634ccc32p0}, + {-0x1.bb60987591c34p-54, 0x1.6623882552225p0}, + {0x1.038ae44f73e65p-57, 0x1.68155d44ca973p0}, + {-0x1.bdd3413b26456p-54, 0x1.6a09e667f3bcdp0}, + {-0x1.2895667ff0b0dp-56, 0x1.6c012750bdabfp0}, + {-0x1.bbe3a683c88abp-57, 0x1.6dfb23c651a2fp0}, + {-0x1.83c0f25860ef6p-55, 0x1.6ff7df9519484p0}, + {-0x1.16e4786887a99p-55, 0x1.71f75e8ec5f74p0}, + {-0x1.0a8d96c65d53cp-54, 0x1.73f9a48a58174p0}, + {-0x1.0245957316dd3p-54, 0x1.75feb564267c9p0}, + {0x1.866b80a02162dp-54, 0x1.780694fde5d3fp0}, + {-0x1.41577ee04992fp-55, 0x1.7a11473eb0187p0}, + {0x1.f124cd1164dd6p-54, 0x1.7c1ed0130c132p0}, + {0x1.05d02ba15797ep-56, 0x1.7e2f336cf4e62p0}, + {-0x1.27c86626d972bp-54, 0x1.80427543e1a12p0}, + {-0x1.d4c1dd41532d8p-54, 0x1.82589994cce13p0}, + {-0x1.8d684a341cdfbp-55, 0x1.8471a4623c7adp0}, + {-0x1.fc6f89bd4f6bap-54, 0x1.868d99b4492edp0}, + {0x1.994c2f37cb53ap-54, 0x1.88ac7d98a6699p0}, + {0x1.6e9f156864b27p-54, 0x1.8ace5422aa0dbp0}, + {-0x1.0d55e32e9e3aap-56, 0x1.8cf3216b5448cp0}, + {0x1.5cc13a2e3976cp-55, 0x1.8f1ae99157736p0}, + {-0x1.dd6792e582524p-54, 0x1.9145b0b91ffc6p0}, + {-0x1.75fc781b57ebcp-57, 0x1.93737b0cdc5e5p0}, + {-0x1.64b7c96a5f039p-56, 0x1.95a44cbc8520fp0}, + {-0x1.d185b7c1b85d1p-54, 0x1.97d829fde4e5p0}, + {-0x1.173bd91cee632p-54, 0x1.9a0f170ca07bap0}, + {0x1.c7c46b071f2bep-56, 0x1.9c49182a3f09p0}, + {0x1.824ca78e64c6ep-56, 0x1.9e86319e32323p0}, + {-0x1.359495d1cd533p-54, 0x1.a0c667b5de565p0}, + {0x1.6305c7ddc36abp-54, 0x1.a309bec4a2d33p0}, + {-0x1.d2f6edb8d41e1p-54, 0x1.a5503b23e255dp0}, + {0x1.bcb7ecac563c7p-54, 0x1.a799e1330b358p0}, + {0x1.0fac90ef7fd31p-54, 0x1.a9e6b5579fdbfp0}, + {-0x1.f9234cae76cdp-55, 0x1.ac36bbfd3f37ap0}, + {0x1.7a1cd345dcc81p-54, 0x1.ae89f995ad3adp0}, + {-0x1.bdef54c80e425p-54, 0x1.b0e07298db666p0}, + {-0x1.2805e3084d708p-57, 0x1.b33a2b84f15fbp0}, + {-0x1.c71dfbbba6de3p-54, 0x1.b59728de5593ap0}, + {-0x1.5584f7e54ac3bp-56, 0x1.b7f76f2fb5e47p0}, + {-0x1.efcd30e54292ep-54, 0x1.ba5b030a1064ap0}, + {0x1.23dd07a2d9e84p-55, 0x1.bcc1e904bc1d2p0}, + {-0x1.efdca3f6b9c73p-54, 0x1.bf2c25bd71e09p0}, + {0x1.11065895048ddp-55, 0x1.c199bdd85529cp0}, + {0x1.b4537e083c60ap-54, 0x1.c40ab5fffd07ap0}, + {0x1.2884dff483cadp-54, 0x1.c67f12e57d14bp0}, + {0x1.1acbc48805c44p-56, 0x1.c8f6d9406e7b5p0}, + {0x1.503cbd1e949dbp-56, 0x1.cb720dcef9069p0}, + {-0x1.dd83b53829d72p-55, 0x1.cdf0b555dc3fap0}, + {-0x1.cbc3743797a9cp-54, 0x1.d072d4a07897cp0}, + {-0x1.d487b719d8578p-54, 0x1.d2f87080d89f2p0}, + {0x1.2ed02d75b3707p-55, 0x1.d5818dcfba487p0}, + {-0x1.11ec18beddfe8p-54, 0x1.d80e316c98398p0}, + {0x1.c2300696db532p-54, 0x1.da9e603db3285p0}, + {0x1.2da5778f018c3p-54, 0x1.dd321f301b46p0}, + {-0x1.1a5cd4f184b5cp-54, 0x1.dfc97337b9b5fp0}, + {-0x1.7b627817a1496p-54, 0x1.e264614f5a129p0}, + {0x1.39e8980a9cc8fp-55, 0x1.e502ee78b3ff6p0}, + {0x1.2d522ca0c8de2p-54, 0x1.e7a51fbc74c83p0}, + {-0x1.e9c23179c2893p-54, 0x1.ea4afa2a490dap0}, + {-0x1.c93f3b411ad8cp-54, 0x1.ecf482d8e67f1p0}, + {0x1.dc7f486a4b6bp-54, 0x1.efa1bee615a27p0}, + {0x1.3a1a5bf0d8e43p-54, 0x1.f252b376bba97p0}, + {0x1.9d3e12dd8a18bp-54, 0x1.f50765b6e454p0}, + {-0x1.dbb12d006350ap-54, 0x1.f7bfdad9cbe14p0}, + {0x1.74853f3a5931ep-55, 0x1.fa7c1819e90d8p0}, + {0x1.2eb74966579e7p-57, 0x1.fd3c22b8f71f1p0}, +}; + +// Cold path for scaling and rounding: +// 2^hi * (r_hi + r_lo) ~ b^x +// when the result may be subnormal (hi <= -1022). Falls back to 128-bit +// evaluation exp_accurate_128(x, log2_base) if Ziv's denormal rounding test +// fails. +// +// Input expectations: +// - x: original input in the non-overflowing/non-underflowing range of b^x. +// - hi: integer exponent k >> 7 in [-1075, -1022]. +// - r_hi, lo_u: high part and upper-bounded low part (r_lo + err_d) of the +// unscaled mantissa: +// 2^(idx / 2^7) * exp(u) in [1 - 2^-8, 2), +// with |lo_u - err_d| << r_hi. +// - err_d: Ziv error bound on r_hi + r_lo. +// - log2_base: pointer to 192-bit log2(b) table (or nullptr when b = 2). +LIBC_NOINLINE LIBC_INLINE double +exp_denorm(double x, int hi, double r_hi, double lo_u, double err_d, + const ExpBase192 *log2_base = nullptr) { + using FPBits = fputil::FPBits<double>; + // Exact subnormal power of 2 when x is an integer in [-1074, -1022]. + if (log2_base == nullptr && LIBC_UNLIKELY(static_cast<double>(hi) == x)) + return FPBits(uint64_t(1) << (hi + 1074)).get_val(); + + if (auto r_denorm = ziv_test_denorm(hi, r_hi, lo_u - err_d, err_d); + LIBC_LIKELY(r_denorm.has_value())) { + double res = r_denorm.value(); + if (LIBC_UNLIKELY(FPBits(res).is_normal())) + return res; + + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<double>(); + return res; + } + return exp_accurate_128(x, log2_base); +} + +// Evaluate: +// b^x = 2^hi * 2^(idx / 2^7) * exp(u) +// in double-double precision and apply Ziv's rounding test, falling back to +// exp_denorm (when hi <= -1022) or exp_accurate_128 (when Ziv's test fails). +// +// Input expectations: +// - x: original input after filtering out tiny, overflow, underflow, and +// Inf/NaN cases. +// - u: reduced argument: +// u.hi + u.lo ~ x * log(b) - k * 2^-7 * log(2) +// with |u.hi + u.lo| <= 2^-8 * log(2). On targets without FMA, +// lsb(u.hi) >= 2^-30 and |u.lo| < 2^-18 +// so that m_hi * u.hi is exact in double. +// - hi: integer exponent k >> 7 in [-1075, 1024]. +// When hi == 1024, k = 1024 * 2^7 so +// idx = 0 (exp2_mid = 1.0) and u < -2^-46 < 0, +// since x is strictly below the overflow threshold, which keeps upper in +// [1 - 2^-8, 1) with unbiased exponent -1 (biased exponent 1022). Adding +// hi = 1024 in scale_exp2(upper, hi) then produces biased exponent 2046 +// (unbiased exponent 1023) without overflowing. +// - idx: table index k & 0x7f in [0, 127]. +// - err_d: Ziv error bound on the double-double approximation r_hi + r_lo. +// - log2_base: pointer to 192-bit log2(b) table (or nullptr when b = 2). +LIBC_ALWAYS_INLINE double exp2_eval(double x, DoubleDouble u, int hi, + unsigned idx, double err_d = EXP2_ERR_D, + const ExpBase192 *log2_base = nullptr) { + DoubleDouble exp2_mid = EXP2_MID[idx]; + + // Reconstruction of 2^(idx / 2^7) * exp(u) ~ exp2_mid * (1 + u + u^2 * P(u)) + // where: + // exp2_mid = 2^(idx / 2^7) = exp2_mid.hi + exp2_mid.lo + // u = dx * log(b) = u.hi + u.lo +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + // Decompose exp2_mid * (1 + u + u^2 * P(u)) ~ r_hi + (r_lo + tail): + // r_hi + r_lo = exp2_mid.hi * (1 + u.hi) + // tail = exp2_mid.hi * (u.lo + u^2 * P(u)) + // + exp2_mid.lo * (1 + u.hi) + // where the omitted term: + // exp2_mid.lo * (u.lo + u^2 * P(u)) + // is bounded by 2^(-54 - 18) = 2^-72 and absorbed into err_d. + + // p ~ (exp(u) - 1 - u) / u^2 + double u2 = u.hi * u.hi; + double p = exp_poly(u.hi, u2); + + // r_hi = round(exp2_mid.hi * (1 + u.hi)) + double r_hi = fputil::multiply_add(exp2_mid.hi, u.hi, exp2_mid.hi); + // mid_lo ~ exp2_mid.lo * (1 + u.hi) + double mid_lo = fputil::multiply_add(exp2_mid.lo, u.hi, exp2_mid.lo); + // poly_lo ~ u.lo + u^2 * P(u) + double poly_lo = fputil::multiply_add(u2, p, u.lo); + + // Fold +/-err_d into mid_lo so tail_u, tail_l, and r_lo can be evaluated in + // parallel: + // mid_u = mid_lo + err_d + // mid_l = mid_lo - err_d + double mid_u = mid_lo + err_d; + double mid_l = mid_lo - err_d; + // tail_{u,l} ~ exp2_mid.hi * (u.lo + u^2 * P(u)) + exp2_mid.lo * (1 + u.hi) + // +/- err_d + double tail_u = fputil::multiply_add(exp2_mid.hi, poly_lo, mid_u); + double tail_l = fputil::multiply_add(exp2_mid.hi, poly_lo, mid_l); + // r_lo = exp2_mid.hi * (1 + u.hi) - r_hi (exact to within 2^-105) + double r_lo = fputil::multiply_add(exp2_mid.hi, u.hi, exp2_mid.hi - r_hi); + + // lo_{u,l} ~ r_lo + tail +/- err_d + double lo_u = r_lo + tail_u; + double lo_l = r_lo + tail_l; +#else + // p ~ (exp(u) - 1 - u) / u^2 + double u_sum = u.hi + u.lo; + double u2 = u_sum * u_sum; + double p = exp_poly(u_sum, u2); + + // Split exp2_mid = m_hi + m_lo with lsb(m_hi) >= 2^-22 and |m_lo| < 2^-22: + LIBC_BIT_CAST_CONSTEXPR_VAR double HI_MASK_22 = + cpp::bit_cast<double>(0xffff'ffff'c000'0000ULL); + double m_hi = fputil::fp_and(exp2_mid.hi, HI_MASK_22); // lsb = 2^-22 + double m_lo = (exp2_mid.hi - m_hi) + exp2_mid.lo; + + // Since lsb(u.hi) >= 2^-30 and r_hi is in [1 - 2^-8, 2), both: + // m_hi * u.hi and r_hi = m_hi * (1 + u.hi) + // are exact: + double prod_hi = m_hi * u.hi; // exact, lsb = 2^-52 + double r_hi = m_hi + prod_hi; // exact + + // poly_lo ~ u.lo + u^2 * P(u) + double u2_p = u2 * p; + double poly_lo = u.lo + u2_p; + + // r_lo ~ exp2_mid.hi * (u.lo + u^2 * P(u)) + m_lo * (1 + u.hi) + double l0 = exp2_mid.hi * poly_lo; + double l1 = m_lo * (1.0 + u.hi); + double r_lo = l0 + l1; + + // lo_{u,l} = r_lo +/- err_d + double lo_u = r_lo + err_d; + double lo_l = r_lo - err_d; +#endif + // Ziv's rounding test in the current rounding mode: + double upper = r_hi + lo_u; + double lower = r_hi + lo_l; + + if (LIBC_LIKELY(upper == lower && hi > -1022)) + return scale_exp2(upper, hi); + + if (LIBC_UNLIKELY(hi <= -1022)) + return exp_denorm(x, hi, r_hi, lo_u, err_d, log2_base); + + return exp_accurate_128(x, log2_base); +} + +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace double_eval +} // namespace math } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXP_UTILS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf.h index a64b323e08b2..d53d19cfc784 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf.h @@ -19,30 +19,41 @@ #include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/cpu_features.h" -#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ +#if defined(LIBC_TARGET_ARCH_IS_GPU) && \ + !defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ + (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ + defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)) && \ + defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) && \ + defined(LIBC_MATH_HAS_NO_EXCEPT) && defined(LIBC_MATH_HAS_NO_ERRNO) + +#include "src/__support/math/expf_float_eval.h" +#define LIBC_MATH_EXPF_IMPL float_eval::cr_expf_rn + +#elif defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)) #include "src/__support/math/expf_float_eval.h" -#define LIBC_MATH_EXPF_IMPL float_eval +#define LIBC_MATH_EXPF_IMPL float_eval::expf #elif !defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE) && \ defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) && \ defined(LIBC_MATH_HAS_NO_EXCEPT) && defined(LIBC_MATH_HAS_NO_ERRNO) #include "src/__support/math/expf_integer_eval.h" -#define LIBC_MATH_EXPF_IMPL integer_eval +#define LIBC_MATH_EXPF_IMPL integer_eval::expf #else + #include "src/__support/math/expf_double_eval.h" -#define LIBC_MATH_EXPF_IMPL double_eval +#define LIBC_MATH_EXPF_IMPL double_eval::expf -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#endif namespace LIBC_NAMESPACE_DECL { namespace math { -using LIBC_MATH_EXPF_IMPL::expf; +LIBC_INLINE float expf(float x) { return LIBC_MATH_EXPF_IMPL(x); } } // namespace math } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_double_eval.h index 12f745a4bc60..bb5ea8a148c3 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_double_eval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_double_eval.h @@ -23,6 +23,7 @@ #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" +#include "src/__support/math/check/exp_exceptions.h" #include "src/__support/math/exp_float_constants.h" // Lookup tables EXP_M1 and EXP_M2. namespace LIBC_NAMESPACE_DECL { @@ -31,6 +32,8 @@ namespace double_eval { LIBC_INLINE float expf(float x) { using FPBits = fputil::FPBits<float>; + using FPBounds = math::check::exp_internal::Bounds<float>; + FPBits xbits(x); uint32_t x_u = xbits.uintval(); @@ -43,8 +46,8 @@ LIBC_INLINE float expf(float x) { } #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // When |x| >= 89, |x| < 2^-25, or x is nan - if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) { + // When |x| >= log(2^127 * (2 - 2^-23)), |x| < 2^-25, or x is nan + if (LIBC_UNLIKELY(x_abs >= FPBounds::UPPER_BITS || x_abs <= 0x3280'0000U)) { // |x| < 2^-25 if (xbits.get_biased_exponent() <= 101) { return 1.0f + x; @@ -66,8 +69,8 @@ LIBC_INLINE float expf(float x) { fputil::raise_except_if_required(FE_UNDERFLOW); return 0.0f; } - // x >= 89 or nan - if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) { + // x >= log(2^127 * (2 - 2^-23)) or nan + if (xbits.is_pos() && (xbits.uintval() >= FPBounds::UPPER_BITS)) { // x is finite if (xbits.uintval() < 0x7f80'0000U) { #ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_eval.h index e479cb58d2fe..a9f49751ac24 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_eval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_eval.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// Float-only implementation of expf. +/// Float-only implementations of expf. /// //===----------------------------------------------------------------------===// @@ -24,7 +24,9 @@ #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/cpu_features.h" +#include "src/__support/math/check/exp_exceptions.h" #include "src/__support/math/exp2f_float_utils.h" +#include "src/__support/math/expf_float_utils.h" namespace LIBC_NAMESPACE_DECL { namespace math { @@ -32,13 +34,15 @@ namespace float_eval { LIBC_INLINE float expf(float x) { using FPBits = fputil::FPBits<float>; + using FPBounds = math::check::exp_internal::Bounds<float>; + FPBits xbits(x); uint32_t x_u = xbits.uintval(); uint32_t x_abs = x_u & 0x7fff'ffffU; - // When |x| >= 89, |x| < 2^-25, or x is nan - if (LIBC_UNLIKELY(x_abs >= 0x42b2'0000U || x_abs <= 0x3280'0000U)) { + // When |x| >= log(2^127 * (2 - 2^-23)), |x| < 2^-25, or x is nan + if (LIBC_UNLIKELY(x_abs >= FPBounds::UPPER_BITS || x_abs <= 0x3280'0000U)) { // |x| < 2^-25 if (xbits.get_biased_exponent() <= 101) { return 1.0f + x; @@ -60,8 +64,8 @@ LIBC_INLINE float expf(float x) { fputil::raise_except_if_required(FE_UNDERFLOW); return 0.0f; } - // x >= 89 or nan - if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) { + // x >= log(2^127 * (2 - 2^-23)) or nan + if (xbits.is_pos() && (xbits.uintval() >= FPBounds::UPPER_BITS)) { // x is finite if (xbits.uintval() < 0x7f80'0000U) { #ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY @@ -100,11 +104,11 @@ LIBC_INLINE float expf(float x) { // Constants generated by Sollya with: // > display = hexadecimal; // > LOG2_E = round(log2(exp(1)), SG, RN); - // > LOG_2_HI = round(log(2), 12, RN); + // > LOG_2_HI = round(log(2), 16, RN); // > LOG_2_LO = round(log(2) - LOG_2_HI, SG, RN); constexpr float LOG2_E = 0x1.715476p+0f; - constexpr float LOG_2_HI = 0x1.62ep-1f; - constexpr float LOG_2_LO = 0x1.0bfbe8p-15f; + constexpr float LOG_2_HI = 0x1.62e4p-1f; + constexpr float LOG_2_LO = 0x1.7f7d1cp-20f; float kf = fputil::nearest_integer(x * LOG2_E); int k = static_cast<int>(kf); @@ -119,6 +123,77 @@ LIBC_INLINE float expf(float x) { return exp2f_eval(u, k); } +// Designed for GPU performance. Correctly rounded only in round-to-nearest, +// ties-to-even mode. Requires single-precision FMA. Does not support errno +// or floating-point exception reporting. +LIBC_INLINE float cr_expf_rn(float x) { + using FPBits = fputil::FPBits<float>; + using FPBounds = math::check::exp_internal::Bounds<float>; + + FPBits x_bits(x); + + uint32_t x_u = x_bits.uintval(); + uint32_t x_abs_u = x_u & 0x7fff'ffffU; + + // |x| <= 2^-25 + bool is_tiny = x_abs_u <= 0x3300'0000U; + + // x >= log(2^127 * (2 - 2^-23)) or x is nan + bool should_overflow = x_u >= FPBounds::UPPER_BITS && x_u < 0x8000'0000U; + + // x <= log(2^-150) or x is nan + bool should_underflow = x_u >= 0xc2cf'f1b5U; + + // x is nan with its sign bit set + bool is_neg_nan = should_underflow && x_bits.is_nan(); + + // log(2^-150) < x < log(2^-126) + bool produces_subnormal = x_u >= FPBounds::LOWER_BITS && !should_underflow; + + // Use x_safe for range reduction to keep the conversion to int defined + float x_safe = (should_underflow || should_overflow) ? 0.0f : x; + + // Range reduction: + // k = round(x * log2(e)) + // x * log2(e) = k + u * log2(e) + // e^x = 2^k * e^u + // + // Constants generated by Sollya with: + // > display = hexadecimal!; + // > LOG2_E = round(log2(exp(1)), SG, RN); + // > LOG_2_HI = round(log(2), SG, RN); + // > LOG_2_LO.hi = round(log(2) - LOG_2_HI, SG, RN); + // > LOG_2_LO.lo = round(log(2) - LOG_2_HI - LOG_2_LO.hi, SG, RN); + constexpr float LOG2_E = 0x1.715476p+0f; + constexpr float LOG_2_HI = 0x1.62e43p-1f; + constexpr fputil::FloatFloat LOG_2_LO = {/*lo=*/-0x1.950d88p-54f, + /*hi=*/-0x1.05c61p-29f}; + + float kf = fputil::nearest_integer(x_safe * LOG2_E); + int k = static_cast<int>(kf); + + float u_hi = fputil::multiply_add(-kf, LOG_2_HI, x_safe); + fputil::FloatFloat u_lo = fputil::quick_mult(-kf, LOG_2_LO); + + fputil::FloatFloat u = fputil::exact_add(u_hi, u_lo.hi); + u.lo += u_lo.lo; + + // Polynomial approximation: e^u + fputil::FloatFloat exp_u = cr_expf_rn_internal::exp_eval(u); + + // Reconstruction: 2^k * e^u + float res = cr_expf_rn_internal::scale_result(exp_u, k, produces_subnormal); + + // Special cases + constexpr float INF = FPBits::inf().get_val(); + + res = is_tiny ? 1.0f : res; + res = should_overflow ? x + INF : res; + res = should_underflow ? (is_neg_nan ? x : 0.0f) : res; + + return res; +} + } // namespace float_eval } // namespace math } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_utils.h new file mode 100644 index 000000000000..d65abda27af3 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_float_utils.h @@ -0,0 +1,149 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Utilities for float-only implementations of expf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_FLOAT_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_FLOAT_UTILS_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace float_eval { + +namespace cr_expf_rn_internal { + +using fputil::FloatFloat; + +LIBC_ALWAYS_INLINE FloatFloat horner_step(float x, const FloatFloat &poly, + const FloatFloat &coeff) { + float hi = fputil::multiply_add(x, poly.hi, coeff.hi); + float lo = fputil::multiply_add(x, poly.hi, coeff.hi - hi); + lo = fputil::multiply_add(x, poly.lo, lo + coeff.lo); + return {lo, hi}; +} + +// Approximates exp(u) on [-log(2)/2, log(2)/2] with the degree-10 +// polynomial P(u) = 1 + u + u^2 * Q(u) using Horner evaluation. +// +// Coefficients generated by Sollya with: +// > prec = 165!; +// > display = hexadecimal!; +// > p = fpminimax(exp(x), [|2, ..., 10|], +// [|49, 49, 49, 49, 49, 24, 24, 24, 24|], +// [-log(2)/2; log(2)/2], relative, +// floating, 1 + x); +// +// Float-float coefficients are split into: +// > hi = round(coeff(p, i), SG, RN); +// > lo = round(coeff(p, i) - hi, SG, RN); +LIBC_INLINE FloatFloat exp_eval(const FloatFloat &u) { + // Coefficients of u^2, ..., u^6, in {lo, hi} order. + constexpr FloatFloat COEFFS[] = { + {-0x1.dp-46f, 0x1p-1f}, + {-0x1.555edcp-28f, 0x1.555556p-3f}, + {-0x1.54c28ep-30f, 0x1.555556p-5f}, + {-0x1.b504e8p-32f, 0x1.111112p-7f}, + {0x1.158eb2p-35f, 0x1.6c16cp-10f}, + }; + + // The float-only tail contributes to degrees 7 through 10 of P. + float tail = fputil::polyeval(u.hi, 0x1.a0198ep-13f, 0x1.a01c0ap-16f, + 0x1.72e878p-19f, 0x1.2694cap-22f); + FloatFloat poly{0.0f, tail}; + for (int i = 4; i >= 0; --i) + poly = horner_step(u.hi, poly, COEFFS[i]); + + // Form expm1(u.hi) before adding 1, retaining its low component. + poly = horner_step(u.hi, poly, FloatFloat{0.0f, 1.0f}); + FloatFloat expm1_u_hi = fputil::quick_mult(u.hi, poly); + FloatFloat exp_u = fputil::exact_add(1.0f, expm1_u_hi.hi); + + // exp(u.hi + u.lo) = exp(u.hi) + u.lo * exp(u.hi) + O(u.lo^2). + // + // Combine the retained low part of expm1(u.hi) with the correction + // u.lo * exp(u.hi), approximating exp(u.hi) by exp_u.hi. + float corr = fputil::multiply_add(u.lo, exp_u.hi, expm1_u_hi.lo); + + // Rounding low sums, exp_u.lo + corr, to nearest can create a midpoint for + // exp_u.hi + RN(exp_u.lo + corr). + // + // Round inexact low sums to odd whenever their rounded value is a power of + // two. This covers all such midpoint cases in this evaluation and preserves + // which side of the midpoint the exact sum lies on. + // + // FastTwoSum here is exact in RN: for nonzero corr, exp_u.lo is an integer + // multiple of ulp(corr), as required by Theorem 1 of "FastTwoSum revisited". + FloatFloat lo_sum = fputil::exact_add(exp_u.lo, corr); + + uint32_t lo_sum_u = fputil::FPBits<float>(lo_sum.hi).uintval(); + bool should_round_to_odd = + (lo_sum_u & fputil::FPBits<float>::FRACTION_MASK) == 0 && + lo_sum.lo != 0.0f; + uint32_t rounding_adj = + ((lo_sum.hi > 0.0f) == (lo_sum.lo > 0.0f)) ? 1U : uint32_t(-1); + lo_sum_u += should_round_to_odd ? rounding_adj : 0U; + exp_u.lo = fputil::FPBits<float>(lo_sum_u).get_val(); + + return exp_u; +} + +// Computes 2^k * (exp_u.hi + exp_u.lo). +LIBC_INLINE float scale_result(const FloatFloat &exp_u, int k, + bool produces_subnormal) { + using FPBits = fputil::FPBits<float>; + + // Scaling the rounded sum by 2^k is exact for normal results: only the + // exponent changes. For subnormal results, the fixed spacing 2^-149 is + // coarser than the scaled spacing of the rounded sum. Scaling can then + // discard significand bits and round again. + // + // Choose B = 2^(-126 - k), so ulp(B) * 2^k = 2^-149. For inputs producing + // subnormals, B + exp_u.hi + exp_u.lo lies in B's binade [B, 2B). Rounding + // this biased sum therefore uses the desired spacing while staying normal. + // Use B = 0 for normal results to share the same arithmetic path. + uint32_t bias_u = produces_subnormal ? (1U - static_cast<uint32_t>(k)) + << FPBits::FRACTION_LEN + : 0U; + float bias = FPBits(bias_u).get_val(); + + // For inputs producing subnormals, B >= exp_u.hi, so FastTwoSum retains + // the rounding residual exactly in RN. It is also exact when B = 0, + // reducing the final addition to RN(exp_u.hi + exp_u.lo). + FloatFloat sum_biased = fputil::exact_add(bias, exp_u.hi); + float sum_rounded = sum_biased.hi + (sum_biased.lo + exp_u.lo); + uint32_t res_u = FPBits(sum_rounded).uintval(); + + // For subnormal results, sum_rounded lies in B's binade [B, 2B): + // sum_rounded = B + M * ulp(B), where M is the integer encoded by + // its fraction field. Clearing the exponent makes the same fraction + // bits represent M * 2^-149 = (sum_rounded - B) * 2^k. This removes + // the bias and applies the scale without further rounding. + uint32_t res_mask = produces_subnormal ? FPBits::FRACTION_MASK : ~0U; + uint32_t exponent_adj = produces_subnormal ? 0U + : static_cast<uint32_t>(k) + << FPBits::FRACTION_LEN; + return FPBits((res_u & res_mask) + exponent_adj).get_val(); +} + +} // namespace cr_expf_rn_internal + +} // namespace float_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_FLOAT_UTILS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_integer_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_integer_eval.h index 52736323d8d7..89b61870c4e9 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_integer_eval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/expf_integer_eval.h @@ -7,8 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the statically rounded, integer-only implementation of -/// expf(x) +/// Integer-only implementation of expf. /// //===----------------------------------------------------------------------===// @@ -18,278 +17,103 @@ #include "hdr/fenv_macros.h" #include "src/__support/CPP/bit.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" #include "src/__support/frac64.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" #include "src/__support/math/check/exp_exceptions.h" +#include "src/__support/math/exp2f_integer_utils.h" namespace LIBC_NAMESPACE_DECL { - -namespace shared { - namespace math { - namespace static_rounding { -// print(2+round(1/log(2), 64, RN)); -// LSB(INV_LN2) = 2^-63 -LIBC_INLINE_VAR constexpr Frac64 INV_LN2 = Frac64(0xb8aa'3b29'5c17'f0bc); - -// 64-bit polynomial approximation of 2^x coefficients generated with Sollya: -// > P = fpminimax(2^x, 11, [|1, 64...|], [0, 1], absolute, fixed); -// Store the fractional part of the coefficients below -// > dirtyinfnorm(2^x - P(x), [0, 1]); -// 0x1.6238...p-58 -// LSB(EXPF_COEFFS[i]) = 2^-64 -LIBC_INLINE_VAR constexpr Frac64 EXPF_COEFFS[] = { - Frac64(0xb172'17f7'd1cf'b7cf), // x - Frac64(0x3d7f'7bff'057d'4a5e), // x^2 - Frac64(0x0e35'846b'8363'9484), // x^3 - Frac64(0x0276'556d'ec97'dcd4), // x^4 - Frac64(0x0057'61ff'dc04'c7ff), // x^5 - Frac64(0x000a'1847'b6e7'92ec), // x^6 - Frac64(0x0000'ffe8'14e5'7033), // x^7 - Frac64(0x0000'1628'b6e9'70c8), // x^8 - Frac64(0x0000'01b8'8ce7'4088), // x^9 - Frac64(0x0000'001c'18d5'cb29), // x^10 - Frac64(0x0000'0002'b43f'4490), // x^11 -}; +// Constants generated by Sollya with: +// > display = hexadecimal; +// > round(log2(exp(1)) * 2^63, 64, RN); +// LSB(LOG2_E) = 2^-63 +LIBC_INLINE_VAR constexpr Frac64 LOG2_E = Frac64(0xb8aa'3b29'5c17'f0bc); -// Statically rounded, no except implementation of expf using integer-only -// arithmetic. -LIBC_INLINE float expf(float x, [[maybe_unused]] int rounding) { +LIBC_ALWAYS_INLINE uint32_t expf_bits(uint32_t x_u, + [[maybe_unused]] int rounding) { using FPBits = fputil::FPBits<float>; - using FPBounds = LIBC_NAMESPACE::math::check::exp_internal::Bounds<float>; - FPBits xbits(x); - - bool is_neg = xbits.is_neg(); - uint32_t x_val = xbits.uintval(); - uint32_t x_val_abs = x_val & 0x7fff'ffffU; - - // When |x| >= smallest value that will cause overflow, |x| <= 2^-25, or x is - // NaN - if (LIBC_UNLIKELY(x_val_abs >= FPBounds::UPPER_BITS || - x_val_abs <= 0x3300'0000U)) { - // |x| <= 2^-25 - if (x_val_abs <= 0x3300'0000U) { -#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - return 1.0f; -#else // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (x_val_abs == 0) - return 1.0f; - - if (rounding == FE_UPWARD && !is_neg) - return 0x1.000002p0f; - - if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && is_neg) - return 0x1.fffffep-1f; - - return 1.0f; -#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - } + using FPBounds = math::check::exp_internal::Bounds<float>; + + bool is_neg = (x_u >> 31) != 0; + uint32_t x_abs = x_u & 0x7fff'ffffU; + uint32_t x_e = x_abs >> FPBits::FRACTION_LEN; + + // When |x| < 2^-25 (x_e <= 101) or |x| >= 64 (x_e >= 133): + if (LIBC_UNLIKELY(x_e - 102U >= 31U)) { + // |x| < 2^-25 + // exp(x) = 1 + 2^-23 if x > 0 and FE_UPWARD + // = 1 - 2^-24 if x < 0 and FE_DOWNWARD or FE_TOWARDZERO + // = 1 otherwise. + if (x_e <= 101U) { +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + if (x_abs != 0) { + if (rounding == FE_UPWARD && !is_neg) + return 0x3f80'0001U; // 0x1.000002p+0f = 1.0f + 2^-23f - if (xbits.is_nan()) { - // Per conversation with lntue, we don't need to raise exception here, - // as we're assuming no FPUs/fenv in this kind of environment - if (xbits.is_signaling_nan()) { - // silencing - return FPBits::quiet_nan().get_val(); + if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && is_neg) + return 0x3f7f'ffffU; // 0x1.fffffep-1f = 1.0f - 2^-24f } - - // quiet NaN - return x; +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return 0x3f80'0000U; // 1.0f } - // e^-inf = 0 - // e^+inf = +inf - if (xbits.is_inf()) { - return is_neg ? 0.0f : FPBits::inf().get_val(); - } + // exp(nan) = nan + if (x_abs > 0x7f80'0000U) // |x| > +inf (x is NaN) + return x_u | 0x0040'0000U; // silence signaling NaN - // Large finite positive - if (!is_neg) { + // x >= log(2^127 * (2 - 2^-23)): + // exp(x) = +inf for FE_TONEAREST, FE_UPWARD + // = FLT_MAX for FE_TOWARDZERO, FE_DOWNWARD + if (!is_neg && x_u >= FPBounds::UPPER_BITS) { #ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) - return FPBits::max_normal().get_val(); - - return FPBits::inf().get_val(); -#else // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - return FPBits::inf().get_val(); + if ((rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) && + x_u < 0x7f80'0000U) // x < +inf + return 0x7f7f'ffffU; // 0x1.fffffep+127f (FLT_MAX) #endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return 0x7f80'0000U; // +inf } - // x < log(2^-150) or NaN (NaN is already handled above) - if (xbits.uintval() >= 0xc2cf'f1b5U) { + // x <= -0x1.9fe36ap+6f < log(2^-150) + // exp(x) = 2^-149 for FE_UPWARD + // = 0 otherwise + if (x_u >= 0xc2cf'f1b5U) { #ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (rounding == FE_UPWARD) - return FPBits::min_subnormal().get_val(); + if (rounding == FE_UPWARD && x_u < 0xff80'0000U) // x > -inf + return 0x0000'0001U; // 0x1.0p-149f (FLT_TRUE_MIN) #endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - - return 0.0f; - } - } - - // Main calculations - - uint16_t x_e = xbits.get_biased_exponent(); - uint64_t x_u = xbits.get_mantissa(); - - // Range reduction - // The algorithm near the end of this function estimates 2^r, - // where r is the fractional part of x * log2(e) and is in [0, 1]. - // See EXPF_COEFFS for more details on the approximation polynomial used. - - // add leading bit = 1 - x_u |= uint64_t(1) << FPBits::FRACTION_LEN; - - // shift to top 32 bit --> decimal point at hidden bit that we've added - x_u <<= 32; - - int x_e_unbiased = static_cast<int>(x_e) - FPBits::EXP_BIAS; - - // shift for the decimal point to be at the hidden bit - if (x_e_unbiased > 0) { - x_u <<= x_e_unbiased; - } else if (x_e_unbiased < 0) { - x_u >>= -x_e_unbiased; - } - - // LSB(x_u_frac) = 2^-55 - Frac64 x_u_frac(x_u); - - // LSB(x_ln2) = 2^-54 - Frac64 x_ln2 = x_u_frac * INV_LN2; - - constexpr uint64_t FRAC_MASK = (uint64_t(1) << 54) - 1; - uint64_t x_ln2_bit = x_ln2.val[0]; - - uint64_t e_y, l2y_r; - uint32_t e_y_unbiased; - - // As Frac64 can't store the sign, we need to handle the sign separately: - // - Both branches are computing floor(x * log2(e)). - // - For negative x, we round up to the next multiple of 2^54, then clear the - // last 54 bits. - // - For positive x, we round down (just clear) the last 54 bits. - // - // Then, l2y_r is the remainder of x * log2(e) after removing the integer - // part, which is used to compute 2^l2y_r_frac - 1. - // - // e_y_unbiased is biased exponent field, but already bit-positioned to the - // exponent field of the float representation. - if (LIBC_UNLIKELY(is_neg)) { - e_y = (x_ln2_bit + FRAC_MASK) & ~FRAC_MASK; - l2y_r = e_y - x_ln2_bit; - e_y_unbiased = (FPBits::EXP_BIAS << 23) - static_cast<uint32_t>(e_y >> 31); - } else { - e_y = x_ln2_bit & ~FRAC_MASK; - l2y_r = x_ln2_bit - e_y; - e_y_unbiased = (FPBits::EXP_BIAS << 23) + static_cast<uint32_t>(e_y >> 31); - } - - uint32_t k = static_cast<uint32_t>(e_y >> 54); - int d = static_cast<int>(k) - FPBits::EXP_BIAS; - - // d >= 24 --> k >= 151 - // --> guaranteed to below 2^-150 - // - // underflow - if (LIBC_UNLIKELY(is_neg && d >= 24)) { - return 0.0f; - } - - // LSB(l2y_r_frac) = LSB(l2y_r) * 2^-10 = 2^-64 - Frac64 l2y_r_frac(l2y_r << 10); - - // p = 2^l2y_r_frac - 1 - Frac64 p = l2y_r_frac * - fputil::polyeval(l2y_r_frac, EXPF_COEFFS[0], EXPF_COEFFS[1], - EXPF_COEFFS[2], EXPF_COEFFS[3], EXPF_COEFFS[4], - EXPF_COEFFS[5], EXPF_COEFFS[6], EXPF_COEFFS[7], - EXPF_COEFFS[8], EXPF_COEFFS[9], EXPF_COEFFS[10]); - - uint32_t shift_length = 40; - uint32_t leading_one = 0; - - // We're computing with errors < worst-cast errors, so tie-rounding never - // happens. Hence, round-to-nearest, tie-to-even is equivalent to - // round-to-nearest, tie-to-away. Which is what we're implementing below - // in the following order: - // - // 1. Shift so that the rounding bit is at bit-0 - // 2. Add 1 for rounding - // 3. Perform another shift by 1 - // 4. Depending on the rounding modes, adjust accoringly: - // a. Add 1 if rounding-up (0 if not) - // b. Add e_y_unbiased to the result (0 if the result is subnormal) - - // subnormal - if (LIBC_UNLIKELY(is_neg && d >= 0)) { - e_y_unbiased = 0; - leading_one = 1 << (23 - d); - - // In the below shifts, we're shifting by (shift_length + 1) at max, while - // shift_length is already 40, and if d = 23 --> shift_length + d = 63, and - // we'll shift by whole 64 bits, which is undefined behavior in C++. - // - // So, we'll truncate the last 2 bits. - if (d >= 22) { - d -= 2; - p.val[0] >>= 2; + return 0x0000'0000U; // 0.0f } - - shift_length += d + 1; } -#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - uint32_t result = - (static_cast<uint32_t>(p.val[0] >> shift_length) + (leading_one + 1)); - result >>= 1; - result += e_y_unbiased; - - return cpp::bit_cast<float>(result); -#else // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - if (rounding == FE_TONEAREST) { - uint32_t result = - (static_cast<uint32_t>(p.val[0] >> shift_length) + (leading_one + 1)); - result >>= 1; - result += e_y_unbiased; - - return cpp::bit_cast<float>(result); - } - - uint32_t should_round_up = 0; - - if (LIBC_UNLIKELY(rounding == FE_UPWARD)) { - uint64_t round_up_mask = (uint64_t(1) << (shift_length + 1)) - 1; - should_round_up = static_cast<uint32_t>((p.val[0] & round_up_mask) != 0); - } - - uint32_t result = (static_cast<uint32_t>(p.val[0] >> (shift_length + 1)) + - should_round_up + (leading_one >> 1)); - result += e_y_unbiased; + // Range reduction: + // k = floor(x * log2(e)) + // x * log2(e) = k + u, with u in [0, 1) + // e^x = 2^(k + u) = 2^k * 2^u + uint64_t u_bits = exp_b_scale(x_u, x_e, LOG2_E, 133U); + return exp2f_eval_bits(u_bits, is_neg, rounding); +} - return cpp::bit_cast<float>(result); -#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY +// Statically rounded, no-except implementation of expf using integer-only +// arithmetic. +LIBC_ALWAYS_INLINE float expf(float x, [[maybe_unused]] int rounding) { + return cpp::bit_cast<float>(expf_bits(cpp::bit_cast<uint32_t>(x), rounding)); } } // namespace static_rounding -} // namespace math - -} // namespace shared - -namespace math { namespace integer_eval { -LIBC_INLINE float expf(float x) { - return shared::math::static_rounding::expf(x, FE_TONEAREST); +LIBC_ALWAYS_INLINE float expf(float x) { + return static_rounding::expf(x, FE_TONEAREST); } } // namespace integer_eval } // namespace math - } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXPF_INTEGER_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/gamma_util.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/gamma_util.h index 007786368b7d..78ef9c8a330e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/gamma_util.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/gamma_util.h @@ -9,7 +9,6 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_GAMMA_UTIL_H #define LLVM_LIBC_SRC___SUPPORT_MATH_GAMMA_UTIL_H -#include "src/__support/CPP/bit.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/macros/attributes.h" @@ -21,19 +20,6 @@ namespace math { namespace gamma_internal { -template <typename T> LIBC_INLINE constexpr bool is_integer(T x) { - using FPBits = fputil::FPBits<T>; - using StorageType = typename FPBits::StorageType; - FPBits xbits(x); - StorageType x_u = xbits.uintval(); - unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent()); - unsigned lsb = static_cast<unsigned>( - cpp::countr_zero(static_cast<StorageType>(x_u | FPBits::EXP_MASK))); - constexpr unsigned UNIT_EXPONENT = - static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN); - return x_e + lsb >= UNIT_EXPONENT; -} - // sin(pi*x) for x in (0, 1), written as (0.25 - u^2) * P(u^2) where u = x-0.5. // Coefficients for P are a degree-7 polynomial in u^2 // approximating sin(pi*(u+0.5)) / (pi*(0.25-u^2)) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/getpayloadf128.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/getpayloadf128.h index aed53ee4adbc..b162f227b11c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/getpayloadf128.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/getpayloadf128.h @@ -1,32 +1,34 @@ -//===-- Implementation header for getpayloadf128 ----------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for getpayloadf128. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_GETPAYLOADF128_H #define LLVM_LIBC_SRC___SUPPORT_MATH_GETPAYLOADF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/float128.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE constexpr float128 getpayloadf128(const float128 *x) { +using LIBC_NAMESPACE::fputil::Float128; + +LIBC_INLINE constexpr Float128 getpayloadf128(const Float128 *x) { return fputil::getpayload(*x); } } // namespace math } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SRC___SUPPORT_MATH_GETPAYLOADF128_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf.h index 8749136ecf00..dbccad013273 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf.h @@ -15,6 +15,7 @@ #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/is_integer.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" @@ -89,7 +90,7 @@ LIBC_INLINE float lgammaf(float x) { } // Negative integers and lgamma(1) = lgamma(2) = 0. - if (LIBC_UNLIKELY(is_integer(x))) { + if (LIBC_UNLIKELY(fputil::is_integer(x))) { if (xbits.is_neg()) { fputil::raise_except_if_required(FE_DIVBYZERO); fputil::set_errno_if_required(ERANGE); @@ -435,9 +436,10 @@ LIBC_INLINE float lgammaf(float x) { lgamma_val += inv_x * fputil::multiply_add(inv_x4, p23, p01); } else { // Exceptional cases of this range. - constexpr fputil::ExceptValues<float, 2> LGAMMAF_EXCEPTS_B10{{ + constexpr fputil::ExceptValues<float, 3> LGAMMAF_EXCEPTS_B10{{ // input, toward-zero result, RU, RD, RN {0x42468b59u, 0x430f25a7u, 1, 0, 0}, + {0xc0c82481u, 0xc0b2a995u, 0, 1, 1}, {0xc134eb14u, 0xc1875615u, 0, 1, 0}, }}; if (auto r = LGAMMAF_EXCEPTS_B10.lookup(xbits.uintval()); @@ -469,11 +471,14 @@ LIBC_INLINE float lgammaf(float x) { lgamma_val += inv_x * poly; } } else { - constexpr fputil::ExceptValues<float, 3> LGAMMAF_EXCEPTS_HUGE{{ + constexpr fputil::ExceptValues<float, 6> LGAMMAF_EXCEPTS_HUGE{{ // input, toward-zero result, RU, RD, RN + {0x4f3f94c0u, 0x517a24a2u, 1, 0, 1}, + {0x50522f52u, 0x5292ee5du, 1, 0, 1}, {0x65fca09fu, 0x68cead59u, 1, 0, 1}, {0x716e5dd5u, 0x747e2bb9u, 1, 0, 0}, {0x77ac5674u, 0x7acf27b2u, 1, 0, 1}, + {0x7943def8u, 0x7c7232d7u, 1, 0, 0}, }}; if (auto r = LGAMMAF_EXCEPTS_HUGE.lookup(xbits.uintval()); LIBC_UNLIKELY(r.has_value())) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf16.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf16.h index 28660fe92d5a..6dccd9378904 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf16.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/lgammaf16.h @@ -18,6 +18,7 @@ #include "src/__support/FPUtil/NearestIntegerOperations.h" #include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/is_integer.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" @@ -53,7 +54,7 @@ LIBC_INLINE float16 lgammaf16(float16 x) { return FPBits::inf().get_val(); } - if (LIBC_UNLIKELY(is_integer(x))) { + if (LIBC_UNLIKELY(fputil::is_integer(x))) { if (xbits.is_neg()) { // pole -> +Inf fputil::raise_except_if_required(FE_DIVBYZERO); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/log10f.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/log10f.h index 1869a208393d..0c0488bad5f1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/log10f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/log10f.h @@ -17,6 +17,7 @@ #include "src/__support/FPUtil/except_value_utils.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/common.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/macros/properties/cpu_features.h" @@ -61,54 +62,67 @@ namespace LIBC_NAMESPACE_DECL { namespace math { +namespace log10f_internal { + +LIBC_INLINE_VAR constexpr double LOG10_2 = 0x1.34413509f79ffp-2; + +// Lookup table for -log10(r) where r is defined in common_constants.cpp. +LIBC_INLINE_VAR constexpr double LOG10_R[128] = { + 0x0.0000000000000p+0, 0x1.be76bd77b4fc3p-9, 0x1.c03a80ae5e054p-8, + 0x1.51824c7587ebp-7, 0x1.c3d0837784c41p-7, 0x1.1b85d6044e9aep-6, + 0x1.559bd2406c3bap-6, 0x1.902c31d62a843p-6, 0x1.cb38fccd8bfdbp-6, + 0x1.e8eeb09f2f6cbp-6, 0x1.125d0432ea20ep-5, 0x1.30838cdc2fbfdp-5, + 0x1.3faf7c663060ep-5, 0x1.5e3966b7e9295p-5, 0x1.7d070145f4fd7p-5, + 0x1.8c878eeb05074p-5, 0x1.abbcebd84fcap-5, 0x1.bb7209d1e24e5p-5, + 0x1.db11ed766abf4p-5, 0x1.eafd05035bd3bp-5, 0x1.0585283764178p-4, + 0x1.0d966cc6500fap-4, 0x1.1dd5460c8b16fp-4, 0x1.2603072a25f82p-4, + 0x1.367ba3aaa1883p-4, 0x1.3ec6ad5407868p-4, 0x1.4f7aad9bbcbafp-4, + 0x1.57e3d47c3af7bp-4, 0x1.605735ee985f1p-4, 0x1.715d0ce367afcp-4, + 0x1.79efb57b0f803p-4, 0x1.828cfed29a215p-4, 0x1.93e7de0fc3e8p-4, + 0x1.9ca5aa1729f45p-4, 0x1.a56e8325f5c87p-4, 0x1.ae4285509950bp-4, + 0x1.b721cd17157e3p-4, 0x1.c902a19e65111p-4, 0x1.d204698cb42bdp-4, + 0x1.db11ed766abf4p-4, 0x1.e42b4c16caaf3p-4, 0x1.ed50a4a26eafcp-4, + 0x1.ffbfc2bbc7803p-4, 0x1.0484e4942aa43p-3, 0x1.093025a19976cp-3, + 0x1.0de1b56356b04p-3, 0x1.1299a4fb3e306p-3, 0x1.175805d1587c1p-3, + 0x1.1c1ce9955c0c6p-3, 0x1.20e8624038fedp-3, 0x1.25ba8215af7fcp-3, + 0x1.2a935ba5f1479p-3, 0x1.2f7301cf4e87bp-3, 0x1.345987bfeea91p-3, + 0x1.394700f7953fdp-3, 0x1.3e3b8149739d4p-3, 0x1.43371cde076c2p-3, + 0x1.4839e83506c87p-3, 0x1.4d43f8275a483p-3, 0x1.525561e9256eep-3, + 0x1.576e3b0bde0a7p-3, 0x1.5c8e998072fe2p-3, 0x1.61b6939983048p-3, + 0x1.66e6400da3f77p-3, 0x1.6c1db5f9bb336p-3, 0x1.6c1db5f9bb336p-3, + 0x1.715d0ce367afcp-3, 0x1.76a45cbb7e6ffp-3, 0x1.7bf3bde099f3p-3, + 0x1.814b4921bd52bp-3, 0x1.86ab17c10bc7fp-3, 0x1.86ab17c10bc7fp-3, + 0x1.8c13437695532p-3, 0x1.9183e673394fap-3, 0x1.96fd1b639fc09p-3, + 0x1.9c7efd734a2f9p-3, 0x1.a209a84fbcff8p-3, 0x1.a209a84fbcff8p-3, + 0x1.a79d382bc21d9p-3, 0x1.ad39c9c2c608p-3, 0x1.b2df7a5c50299p-3, + 0x1.b2df7a5c50299p-3, 0x1.b88e67cf9798p-3, 0x1.be46b087354bcp-3, + 0x1.c4087384f4f8p-3, 0x1.c4087384f4f8p-3, 0x1.c9d3d065c5b42p-3, + 0x1.cfa8e765cbb72p-3, 0x1.cfa8e765cbb72p-3, 0x1.d587d96494759p-3, + 0x1.db70c7e96e7f3p-3, 0x1.db70c7e96e7f3p-3, 0x1.e163d527e68cfp-3, + 0x1.e76124046b3f3p-3, 0x1.e76124046b3f3p-3, 0x1.ed68d819191fcp-3, + 0x1.f37b15bab08d1p-3, 0x1.f37b15bab08d1p-3, 0x1.f99801fdb749dp-3, + 0x1.ffbfc2bbc7803p-3, 0x1.ffbfc2bbc7803p-3, 0x1.02f93f4c87101p-2, + 0x1.06182e84fd4acp-2, 0x1.06182e84fd4acp-2, 0x1.093cc32c90f84p-2, + 0x1.093cc32c90f84p-2, 0x1.0c6711d6abd7ap-2, 0x1.0f972f87ff3d6p-2, + 0x1.0f972f87ff3d6p-2, 0x1.12cd31b9c99ffp-2, 0x1.12cd31b9c99ffp-2, + 0x1.16092e5d3a9a6p-2, 0x1.194b3bdef6b9ep-2, 0x1.194b3bdef6b9ep-2, + 0x1.1c93712abc7ffp-2, 0x1.1c93712abc7ffp-2, 0x1.1fe1e5af2c141p-2, + 0x1.1fe1e5af2c141p-2, 0x1.2336b161b3337p-2, 0x1.2336b161b3337p-2, + 0x1.2691ecc29f042p-2, 0x1.2691ecc29f042p-2, 0x1.29f3b0e15584bp-2, + 0x1.29f3b0e15584bp-2, 0x1.2d5c1760b86bbp-2, 0x1.2d5c1760b86bbp-2, + 0x1.30cb3a7bb3625p-2, 0x1.34413509f79ffp-2}; + +// Degree-5 polynomial approximation of log10 generated by: +// > P = fpminimax(log10(1 + x)/x, 4, [|D...|], [-2^-8, 2^-7]); +LIBC_INLINE_VAR constexpr double COEFFS[5] = { + 0x1.bcb7b1526e2e5p-2, -0x1.bcb7b1528d43dp-3, 0x1.287a77eb4ca0dp-3, + -0x1.bcb8110a181b5p-4, 0x1.60e7e3e747129p-4}; + +} // namespace log10f_internal + LIBC_INLINE float log10f(float x) { using namespace common_constants_internal; - constexpr double LOG10_2 = 0x1.34413509f79ffp-2; - // Lookup table for -log10(r) where r is defined in common_constants.cpp. - constexpr double LOG10_R[128] = { - 0x0.0000000000000p+0, 0x1.be76bd77b4fc3p-9, 0x1.c03a80ae5e054p-8, - 0x1.51824c7587ebp-7, 0x1.c3d0837784c41p-7, 0x1.1b85d6044e9aep-6, - 0x1.559bd2406c3bap-6, 0x1.902c31d62a843p-6, 0x1.cb38fccd8bfdbp-6, - 0x1.e8eeb09f2f6cbp-6, 0x1.125d0432ea20ep-5, 0x1.30838cdc2fbfdp-5, - 0x1.3faf7c663060ep-5, 0x1.5e3966b7e9295p-5, 0x1.7d070145f4fd7p-5, - 0x1.8c878eeb05074p-5, 0x1.abbcebd84fcap-5, 0x1.bb7209d1e24e5p-5, - 0x1.db11ed766abf4p-5, 0x1.eafd05035bd3bp-5, 0x1.0585283764178p-4, - 0x1.0d966cc6500fap-4, 0x1.1dd5460c8b16fp-4, 0x1.2603072a25f82p-4, - 0x1.367ba3aaa1883p-4, 0x1.3ec6ad5407868p-4, 0x1.4f7aad9bbcbafp-4, - 0x1.57e3d47c3af7bp-4, 0x1.605735ee985f1p-4, 0x1.715d0ce367afcp-4, - 0x1.79efb57b0f803p-4, 0x1.828cfed29a215p-4, 0x1.93e7de0fc3e8p-4, - 0x1.9ca5aa1729f45p-4, 0x1.a56e8325f5c87p-4, 0x1.ae4285509950bp-4, - 0x1.b721cd17157e3p-4, 0x1.c902a19e65111p-4, 0x1.d204698cb42bdp-4, - 0x1.db11ed766abf4p-4, 0x1.e42b4c16caaf3p-4, 0x1.ed50a4a26eafcp-4, - 0x1.ffbfc2bbc7803p-4, 0x1.0484e4942aa43p-3, 0x1.093025a19976cp-3, - 0x1.0de1b56356b04p-3, 0x1.1299a4fb3e306p-3, 0x1.175805d1587c1p-3, - 0x1.1c1ce9955c0c6p-3, 0x1.20e8624038fedp-3, 0x1.25ba8215af7fcp-3, - 0x1.2a935ba5f1479p-3, 0x1.2f7301cf4e87bp-3, 0x1.345987bfeea91p-3, - 0x1.394700f7953fdp-3, 0x1.3e3b8149739d4p-3, 0x1.43371cde076c2p-3, - 0x1.4839e83506c87p-3, 0x1.4d43f8275a483p-3, 0x1.525561e9256eep-3, - 0x1.576e3b0bde0a7p-3, 0x1.5c8e998072fe2p-3, 0x1.61b6939983048p-3, - 0x1.66e6400da3f77p-3, 0x1.6c1db5f9bb336p-3, 0x1.6c1db5f9bb336p-3, - 0x1.715d0ce367afcp-3, 0x1.76a45cbb7e6ffp-3, 0x1.7bf3bde099f3p-3, - 0x1.814b4921bd52bp-3, 0x1.86ab17c10bc7fp-3, 0x1.86ab17c10bc7fp-3, - 0x1.8c13437695532p-3, 0x1.9183e673394fap-3, 0x1.96fd1b639fc09p-3, - 0x1.9c7efd734a2f9p-3, 0x1.a209a84fbcff8p-3, 0x1.a209a84fbcff8p-3, - 0x1.a79d382bc21d9p-3, 0x1.ad39c9c2c608p-3, 0x1.b2df7a5c50299p-3, - 0x1.b2df7a5c50299p-3, 0x1.b88e67cf9798p-3, 0x1.be46b087354bcp-3, - 0x1.c4087384f4f8p-3, 0x1.c4087384f4f8p-3, 0x1.c9d3d065c5b42p-3, - 0x1.cfa8e765cbb72p-3, 0x1.cfa8e765cbb72p-3, 0x1.d587d96494759p-3, - 0x1.db70c7e96e7f3p-3, 0x1.db70c7e96e7f3p-3, 0x1.e163d527e68cfp-3, - 0x1.e76124046b3f3p-3, 0x1.e76124046b3f3p-3, 0x1.ed68d819191fcp-3, - 0x1.f37b15bab08d1p-3, 0x1.f37b15bab08d1p-3, 0x1.f99801fdb749dp-3, - 0x1.ffbfc2bbc7803p-3, 0x1.ffbfc2bbc7803p-3, 0x1.02f93f4c87101p-2, - 0x1.06182e84fd4acp-2, 0x1.06182e84fd4acp-2, 0x1.093cc32c90f84p-2, - 0x1.093cc32c90f84p-2, 0x1.0c6711d6abd7ap-2, 0x1.0f972f87ff3d6p-2, - 0x1.0f972f87ff3d6p-2, 0x1.12cd31b9c99ffp-2, 0x1.12cd31b9c99ffp-2, - 0x1.16092e5d3a9a6p-2, 0x1.194b3bdef6b9ep-2, 0x1.194b3bdef6b9ep-2, - 0x1.1c93712abc7ffp-2, 0x1.1c93712abc7ffp-2, 0x1.1fe1e5af2c141p-2, - 0x1.1fe1e5af2c141p-2, 0x1.2336b161b3337p-2, 0x1.2336b161b3337p-2, - 0x1.2691ecc29f042p-2, 0x1.2691ecc29f042p-2, 0x1.29f3b0e15584bp-2, - 0x1.29f3b0e15584bp-2, 0x1.2d5c1760b86bbp-2, 0x1.2d5c1760b86bbp-2, - 0x1.30cb3a7bb3625p-2, 0x1.34413509f79ffp-2}; + using namespace log10f_internal; using FPBits = typename fputil::FPBits<float>; @@ -207,11 +221,6 @@ LIBC_INLINE float log10f(float x) { static_cast<double>(R[index]), -1.0); // Exact #endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - // Degree-5 polynomial approximation of log10 generated by: - // > P = fpminimax(log10(1 + x)/x, 4, [|D...|], [-2^-8, 2^-7]); - constexpr double COEFFS[5] = {0x1.bcb7b1526e2e5p-2, -0x1.bcb7b1528d43dp-3, - 0x1.287a77eb4ca0dp-3, -0x1.bcb8110a181b5p-4, - 0x1.60e7e3e747129p-4}; double v2 = v * v; // Exact double p2 = fputil::multiply_add(v, COEFFS[4], COEFFS[3]); double p1 = fputil::multiply_add(v, COEFFS[2], COEFFS[1]); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/log1p.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/log1p.h index f41d1cc9c052..7dd7c66802c8 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/log1p.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/log1p.h @@ -942,10 +942,14 @@ LIBC_INLINE double log1p(double x) { if (x + x == 0.0) return x + x; // Handle FTZ/DAZ correctly. - volatile float tp = 1.0f; - volatile float tn = -1.0f; - bool rdp = (tp - 0x1p-25f != tp); - bool rdn = (tn - 0x1p-24f != tn); + volatile float tpv = 1.0f; + volatile float tnv = -1.0f; + + float tp = tpv - 0x1p-25f; + float tn = tnv - 0x1p-25f; + + bool rdp = (tp != tpv); + bool rdn = (tn != tnv); if (x > 0 && rdp) { return FPBits_t(x_u - 1).get_val(); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/log2f.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/log2f.h index 138dd9fa29e0..5e7fb902ef99 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/log2f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/log2f.h @@ -25,8 +25,8 @@ // Step 1 - Range reduction: // For x = 2^m * 1.mant, log2(x) = m + log2(1.m) -// If x is denormal, we normalize it by multiplying x by 2^23 and subtracting -// m by 23. +// If x is denormal, convert its integer significand to float exactly and +// account for the 2^-149 subnormal scale in m. // Step 2 - Another range reduction: // To compute log(1.mant), let f be the highest 8 bits including the hidden @@ -91,8 +91,8 @@ LIBC_INLINE float log2f(float x) { return x; } // Normalize denormal inputs. - xbits = FPBits(xbits.get_val() * 0x1.0p23f); - m -= 23; + xbits = FPBits(static_cast<float>(static_cast<int32_t>(x_u))); + m -= 149; } m += xbits.get_biased_exponent(); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/nanf128.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/nanf128.h index 5cc1010939d3..4aaad176059f 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/nanf128.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/nanf128.h @@ -1,18 +1,20 @@ -//===-- Implementation header for nanf128 -----------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for nanf128. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_NANF128_H #define LLVM_LIBC_SRC___SUPPORT_MATH_NANF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - +#include "src/__support/FPUtil/float128.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_float.h" @@ -20,8 +22,10 @@ namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE constexpr float128 nanf128(const char *arg) { - auto result = internal::strtonan<float128>(arg); +using LIBC_NAMESPACE::fputil::Float128; + +LIBC_INLINE constexpr Float128 nanf128(const char *arg) { + auto result = internal::strtonan<Float128>(arg); if (result.has_error()) libc_errno = result.error; return result.value; @@ -30,6 +34,4 @@ LIBC_INLINE constexpr float128 nanf128(const char *arg) { } // namespace math } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SRC___SUPPORT_MATH_NANF128_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/pow.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/pow.h index 75125d789627..ae2772632c9e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/pow.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/pow.h @@ -16,6 +16,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/is_integer.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" #include "src/__support/common.h" @@ -456,7 +457,7 @@ LIBC_INLINE double pow(double x, double y) { // representable power of 2 in double precision). if (LIBC_UNLIKELY(x_mant == 0)) { double ex_y = e_x * y; - if (ex_y >= -1074.0 && pow_internal::is_integer(ex_y)) + if (ex_y >= -1074.0 && fputil::is_integer(ex_y)) return res; } else if (LIBC_UNLIKELY(y > 0.0 && y <= 35.0)) { // 2. If x is not a power of 2, exact results in double precision can diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_fast.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_fast.h index 5960bea60642..fb8d14bea8df 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_fast.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_fast.h @@ -36,14 +36,17 @@ LIBC_INLINE double pow(double x, double y) { FPBits xbits(x), ybits(y); uint64_t x_u = xbits.uintval(); - uint64_t y_u = ybits.uintval(); uint64_t y_a = ybits.abs().uintval(); +#ifndef LIBC_MATH_HAS_SMALL_TABLES + uint64_t y_u = ybits.uintval(); + if (LIBC_UNLIKELY((x_u & 0x0003'FFFF'FFFF'FFFF) == 0 || (y_u & 0x000F'FFFF'FFFF'FFFF) == 0)) { if (auto r = check_special_inputs(x, y); LIBC_UNLIKELY(r.has_value())) return r.value(); } +#endif // !LIBC_MATH_HAS_SMALL_TABLES double e_x = static_cast<double>(xbits.get_exponent()); uint64_t x_mant = xbits.get_mantissa(); @@ -51,6 +54,9 @@ LIBC_INLINE double pow(double x, double y) { double sign_d = 1.0; if (LIBC_UNLIKELY(y_a <= Y_LOWER_BOUND || y_a >= Y_UPPER_BOUND || +#ifdef LIBC_MATH_HAS_SMALL_TABLES + x_u == FPBits::one().uintval() || +#endif // LIBC_MATH_HAS_SMALL_TABLES x_u >= FPBits::inf().uintval() || x_u < FPBits::min_normal().uintval())) { if (auto r = check_exceptional_cases(x, y, e_x, x_mant, is_neg, sign_d); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_utils.h index 83eba6007e20..2c78e42f67d5 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_utils.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/pow_utils.h @@ -21,6 +21,7 @@ #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/is_integer.h" #include "src/__support/FPUtil/nearest_integer.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/FPUtil/sqrt.h" @@ -182,38 +183,6 @@ LIBC_INLINE_VAR constexpr DoubleDouble LOG2_R_DD[128] = { {0.0, 1.0}, }; -// Check if x is an odd integer: the lowest set bit must be at the unit -// position: -// x_e + lsb == UNIT_EXPONENT. -LIBC_INLINE bool is_odd_integer(double x) { - using FPBits = fputil::FPBits<double>; - FPBits xbits(x); - uint64_t x_u = xbits.uintval(); - unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent()); - unsigned lsb = - static_cast<unsigned>(cpp::countr_zero(x_u | FPBits::EXP_MASK)); - constexpr unsigned UNIT_EXPONENT = - static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN); - return (x_e + lsb == UNIT_EXPONENT); -} - -// Check if x is an integer: the lowest set bit must be at or above the unit -// position: -// x_e + lsb >= UNIT_EXPONENT. -LIBC_INLINE bool is_integer(double x) { - if (x == 0.0) - return true; - using FPBits = fputil::FPBits<double>; - FPBits xbits(x); - uint64_t x_u = xbits.uintval(); - unsigned x_e = static_cast<unsigned>(xbits.get_biased_exponent()); - unsigned lsb = - static_cast<unsigned>(cpp::countr_zero(x_u | FPBits::EXP_MASK)); - constexpr unsigned UNIT_EXPONENT = - static_cast<unsigned>(FPBits::EXP_BIAS + FPBits::FRACTION_LEN); - return (x_e + lsb >= UNIT_EXPONENT); -} - LIBC_INLINE double set_overflow(bool is_neg) { fputil::set_errno_if_required(ERANGE); fputil::raise_overflow_except_if_required<double>(); @@ -369,7 +338,7 @@ LIBC_ALWAYS_INLINE cpp::optional<double> check_special_inputs(double x, return y; if (y_abs.is_inf()) return y_sign ? FPBits::inf().get_val() : 0.0; - bool out_is_neg = x_sign && is_odd_integer(y); + bool out_is_neg = x_sign && fputil::is_odd_integer(y); if (y_sign) { // pow(0, negative number) = inf fputil::set_errno_if_required(EDOM); @@ -434,101 +403,115 @@ check_exceptional_cases(double &x, double &y, double &e_x, uint64_t &x_mant, FPBits x_abs = xbits.abs(); FPBits y_abs = ybits.abs(); - uint64_t x_u = xbits.uintval(); uint64_t y_mant = ybits.get_mantissa(); uint64_t x_a = x_abs.uintval(); uint64_t y_a = y_abs.uintval(); - if (LIBC_UNLIKELY(y_a <= Y_LOWER_BOUND || y_a >= Y_UPPER_BOUND || - x_u >= FPBits::inf().uintval() || - x_u < FPBits::min_normal().uintval())) { - // If x or y is signaling NaN - if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } + // If x or y is signaling NaN + if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } - // |y| > |1075 / log2(1 - 2^-53)|. - if (y_a > 0x43d7'4910'd52d'3052) { - if (y_a >= 0x7ff0'0000'0000'0000) { - // y is inf or nan - if (y_mant != 0) { - // y is NaN - // pow(1, NaN) = 1 is already dealt with. - // pow(x, NaN) = NaN - return y; - } - - // Now y is +-Inf - if (x_abs.is_nan()) { - // pow(NaN, +-Inf) = NaN - return x; - } - - if (x_a == 0x3ff0'0000'0000'0000) { - // pow(+-1, +-Inf) = 1.0 - return 1.0; - } - - // pow (|x| < 1, -inf) = +inf - // pow (|x| < 1, +inf) = 0.0 - // pow (|x| > 1, -inf) = 0.0 - // pow (|x| > 1, +inf) = +inf - return ((x_a < FPBits::one().uintval()) == y_sign) - ? FPBits::inf().get_val() - : 0.0; +#ifdef LIBC_MATH_HAS_SMALL_TABLES + if (x == 1.0 || y == 0.0) + return 1.0; +#endif // LIBC_MATH_HAS_SMALL_TABLES + + // |y| > |1075 / log2(1 - 2^-53)|. + if (y_a > Y_UPPER_BOUND) { + if (y_a >= FPBits::inf().uintval()) { + // y is inf or nan + if (y_mant != 0) { + // y is NaN + // pow(1, NaN) = 1 is already dealt with. + // pow(x, NaN) = NaN + return y; } - // x^y will overflow / underflow in double precision. Set y to a - // large enough exponent but not too large, so that the computations - // won't overflow in double precision. - y = y_sign ? -0x1.0p100 : 0x1.0p100; - } - // y is finite and non-zero. + // Now y is +-Inf + if (x_abs.is_nan()) { + // pow(NaN, +-Inf) = NaN + return x; + } - if (x_a == FPBits::inf().uintval()) { - bool out_is_neg = x_sign && is_odd_integer(y); - Sign out_sign = out_is_neg ? Sign::NEG : Sign::POS; - return y_sign ? FPBits::zero(out_sign).get_val() - : FPBits::inf(out_sign).get_val(); - } + if (x_a == FPBits::one().uintval()) { + // pow(+-1, +-Inf) = 1.0 + return 1.0; + } - if (x_a > FPBits::inf().uintval()) { - // x is NaN. - // pow (aNaN, 0) is already taken care above. - return x; + // pow (|x| < 1, -inf) = +inf + // pow (|x| < 1, +inf) = 0.0 + // pow (|x| > 1, -inf) = 0.0 + // pow (|x| > 1, +inf) = +inf + return ((x_a < FPBits::one().uintval()) == y_sign) + ? FPBits::inf().get_val() + : 0.0; } + // x^y will overflow / underflow in double precision. Set y to a + // large enough exponent but not too large, so that the computations + // won't overflow in double precision. + y = y_sign ? -0x1.0p100 : 0x1.0p100; + } - // Normalize denormal inputs. - if (x_a < FPBits::min_normal().uintval()) { - FPBits x_norm(x * 0x1.0p64); - e_x = static_cast<double>(x_norm.get_exponent()) - 64.0; - x_mant = x_norm.get_mantissa(); - } + // y is finite and non-zero. + if (x_a > FPBits::inf().uintval()) { + // x is NaN. + // pow (aNaN, 0) is already taken care above. + return x; + } - // x is finite and negative, and y is a finite integer. - if (x_sign) { - if (is_integer(y)) { - x = -x; - if (is_odd_integer(y)) { - is_neg = true; - sign_d = -1.0; - } - } else { - // pow( negative, non-integer ) = NaN - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); + if (x_sign) { + if (fputil::is_integer(y)) { + x = -x; + if (fputil::is_odd_integer(y)) { + is_neg = true; + sign_d = -1.0; } + } else if (x != 0.0 && x_a < FPBits::inf().uintval()) { + // pow( negative, non-integer ) = NaN + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); } + } - if (y_a <= Y_LOWER_BOUND) { - volatile double one = 1.0; - volatile double eps = ((x_a < FPBits::one().uintval()) == !y_sign) - ? -0x1.0p-100 - : 0x1.0p-100; - return one + eps; +#ifdef LIBC_MATH_HAS_SMALL_TABLES + if (x == 0.0) { + if (y_sign) { + // pow(0, negative number) = inf + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_DIVBYZERO); + return is_neg ? -FPBits::inf().get_val() : FPBits::inf().get_val(); } + // pow(0, positive number) = 0 + return is_neg ? -0.0 : 0.0; + } +#endif // LIBC_MATH_HAS_SMALL_TABLES + + if (x_a == FPBits::inf().uintval()) { + if (y_sign) + return is_neg ? -0.0 : 0.0; + return is_neg ? -FPBits::inf().get_val() : FPBits::inf().get_val(); + } + + if (y_a <= Y_LOWER_BOUND) { +#if defined(LIBC_MATH_HAS_NO_EXCEPT) && \ + defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) + return 1.0; +#else + volatile double one = 1.0; + volatile double eps = + ((x_a < FPBits::one().uintval()) == !y_sign) ? -0x1.0p-100 : 0x1.0p-100; + return one + eps; +#endif // LIBC_MATH_HAS_NO_EXCEPT && LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + } + + // Normalize denormal inputs. + if (x_a < FPBits::min_normal().uintval()) { + FPBits x_norm(x * 0x1.0p64); + e_x = static_cast<double>(x_norm.get_exponent()) - 64.0; + x_mant = x_norm.get_mantissa(); } return cpp::nullopt; @@ -583,7 +566,7 @@ LIBC_INLINE bool is_exact_rounding_boundary(double x, double y, if (x_mant == 0) { double e = static_cast<double>(x_e); double ey = e * y; - if (is_integer(ey)) { + if (fputil::is_integer(ey)) { exact_m = 1; exact_exp = static_cast<int>(ey); return true; @@ -615,7 +598,7 @@ LIBC_INLINE bool is_exact_rounding_boundary(double x, double y, if (f < 0) { // Non-integer exponent: y = n / 2^(-f) with -f in {1, ..., 5}. double ey = static_cast<double>(e) * y; - if (!is_integer(ey)) + if (!fputil::is_integer(ey)) return false; // Check if m^(2^f) is an integer by taking repeated square roots -f times. diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf.h index 944b477ac446..2671215d7d7c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf.h @@ -14,1051 +14,32 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_H #define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_H +#include "src/__support/common.h" +#include "src/__support/macros/config.h" #include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" #if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ - defined(LIBC_MATH_HAS_SMALL_TABLES) - -#include "src/__support/math/powf_small_tables.h" + (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ + defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)) -#else +#include "src/__support/math/powf_float_eval.h" +#define LIBC_MATH_POWF_IMPL float_eval -#include "common_constants.h" // Lookup tables EXP_M1 and EXP_M2. -#include "exp10f.h" // Speedup for powf(10, y) = exp10f(y) -#include "exp2f.h" // Speedup for powf(2, y) = exp2f(y) -#include "exp_constants.h" +#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#include "src/__support/math/powf_double_eval.h" +#define LIBC_MATH_POWF_IMPL double_eval -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS && LIBC_MATH_HAS_SMALL_TABLES - -#include "src/__support/CPP/algorithm.h" -#include "src/__support/CPP/bit.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/FPUtil/sqrt.h" // Speedup for powf(x, 1/2) = sqrtf(x) -#include "src/__support/FPUtil/triple_double.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS namespace LIBC_NAMESPACE_DECL { - namespace math { -namespace powf_internal { - -using fputil::DoubleDouble; -using fputil::TripleDouble; - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -alignas(16) LIBC_INLINE_VAR constexpr DoubleDouble LOG2_R_DD[128] = { - {0.0, 0.0}, - {-0x1.177c23362928cp-25, 0x1.72c8p-7}, - {-0x1.179e0caa9c9abp-22, 0x1.744p-6}, - {-0x1.c6cea541f5b7p-23, 0x1.184cp-5}, - {-0x1.66c4d4e554434p-22, 0x1.773ap-5}, - {-0x1.70700a00fdd55p-24, 0x1.d6ecp-5}, - {0x1.53002a4e86631p-23, 0x1.1bb3p-4}, - {0x1.fcd15f101c142p-25, 0x1.4c56p-4}, - {0x1.25b3eed319cedp-22, 0x1.7d6p-4}, - {-0x1.4195120d8486fp-22, 0x1.960dp-4}, - {0x1.45b878e27d0d9p-23, 0x1.c7b5p-4}, - {0x1.770744593a4cbp-22, 0x1.f9c9p-4}, - {0x1.c673032495d24p-22, 0x1.097ep-3}, - {-0x1.1eaa65b49696ep-22, 0x1.22dbp-3}, - {0x1.b2866f2850b22p-22, 0x1.3c6f8p-3}, - {0x1.8ee37cd2ea9d3p-25, 0x1.494f8p-3}, - {0x1.7e86f9c2154fbp-24, 0x1.633a8p-3}, - {0x1.8e3cfc25f0ce6p-26, 0x1.7046p-3}, - {0x1.57f7a64ccd537p-28, 0x1.8a898p-3}, - {-0x1.a761c09fbd2aep-22, 0x1.97c2p-3}, - {0x1.24bea9a2c66f3p-22, 0x1.b26p-3}, - {-0x1.60002ccfe43f5p-25, 0x1.bfc68p-3}, - {0x1.69f220e97f22cp-22, 0x1.dac2p-3}, - {-0x1.6164f64c210ep-22, 0x1.e858p-3}, - {-0x1.0c1678ae89767p-24, 0x1.01d9cp-2}, - {-0x1.f26a05c813d57p-22, 0x1.08bdp-2}, - {0x1.4d8fc561c8d44p-24, 0x1.169cp-2}, - {-0x1.362ad8f7ca2dp-22, 0x1.1d984p-2}, - {0x1.2b13cd6c4d042p-22, 0x1.249ccp-2}, - {-0x1.1c8f11979a5dbp-22, 0x1.32cp-2}, - {0x1.c2ab3edefe569p-23, 0x1.39de8p-2}, - {0x1.7c3eca28e69cap-26, 0x1.4106p-2}, - {-0x1.34c4e99e1c6c6p-24, 0x1.4f6fcp-2}, - {-0x1.194a871b63619p-22, 0x1.56b24p-2}, - {0x1.e3dd5c1c885aep-23, 0x1.5dfdcp-2}, - {-0x1.6ccf3b1129b7cp-23, 0x1.6552cp-2}, - {-0x1.2f346e2bf924bp-23, 0x1.6cb1p-2}, - {-0x1.fa61aaa59c1d8p-23, 0x1.7b8ap-2}, - {0x1.90c11fd32a3abp-22, 0x1.8304cp-2}, - {0x1.57f7a64ccd537p-27, 0x1.8a898p-2}, - {0x1.249ba76fee235p-27, 0x1.9218p-2}, - {-0x1.aad2729b21ae5p-23, 0x1.99b08p-2}, - {0x1.71810a5e1818p-22, 0x1.a8ff8p-2}, - {-0x1.6172fe015e13cp-27, 0x1.b0b68p-2}, - {0x1.5ec6c1bfbf89ap-24, 0x1.b877cp-2}, - {0x1.678bf6cdedf51p-24, 0x1.c0438p-2}, - {0x1.c2d45fe43895ep-22, 0x1.c819cp-2}, - {-0x1.9ee52ed49d71dp-22, 0x1.cffbp-2}, - {0x1.5786af187a96bp-27, 0x1.d7e6cp-2}, - {0x1.3ab0dc56138c9p-23, 0x1.dfdd8p-2}, - {0x1.fe538ab34efb5p-22, 0x1.e7df4p-2}, - {-0x1.e4fee07aa4b68p-22, 0x1.efec8p-2}, - {-0x1.172f32fe67287p-22, 0x1.f804cp-2}, - {-0x1.9a83ff9ab9cc8p-22, 0x1.00144p-1}, - {-0x1.68cb06cece193p-22, 0x1.042bep-1}, - {0x1.8cd71ddf82e2p-22, 0x1.08494p-1}, - {0x1.5e18ab2df3ae6p-22, 0x1.0c6cap-1}, - {0x1.5dee4d9d8a273p-25, 0x1.1096p-1}, - {0x1.fcd15f101c142p-26, 0x1.14c56p-1}, - {-0x1.2474b0f992ba1p-23, 0x1.18faep-1}, - {0x1.4b5a92a606047p-24, 0x1.1d368p-1}, - {0x1.16186fcf54bbdp-22, 0x1.21786p-1}, - {0x1.18efabeb7d722p-27, 0x1.25c0ap-1}, - {-0x1.e5fc7d238691dp-24, 0x1.2a0f4p-1}, - {0x1.f5809faf6283cp-22, 0x1.2e644p-1}, - {0x1.f5809faf6283cp-22, 0x1.2e644p-1}, - {0x1.c6e1dcd0cb449p-22, 0x1.32bfep-1}, - {0x1.76e0e8f74b4d5p-22, 0x1.37222p-1}, - {-0x1.cb82c89692d99p-24, 0x1.3b8b2p-1}, - {-0x1.63161c5432aebp-22, 0x1.3ffaep-1}, - {0x1.458104c41b901p-22, 0x1.44716p-1}, - {0x1.458104c41b901p-22, 0x1.44716p-1}, - {-0x1.cd9d0cde578d5p-22, 0x1.48efp-1}, - {0x1.b9884591add87p-26, 0x1.4d738p-1}, - {0x1.c6042978605ffp-22, 0x1.51ff2p-1}, - {-0x1.fc4c96b37dcf6p-22, 0x1.56922p-1}, - {-0x1.2f346e2bf924bp-24, 0x1.5b2c4p-1}, - {-0x1.2f346e2bf924bp-24, 0x1.5b2c4p-1}, - {0x1.c4e4fbb68a4d1p-22, 0x1.5fcdcp-1}, - {-0x1.9d499bd9b3226p-23, 0x1.6476ep-1}, - {-0x1.f89b355ede26fp-23, 0x1.69278p-1}, - {-0x1.f89b355ede26fp-23, 0x1.69278p-1}, - {0x1.53c7e319f6e92p-24, 0x1.6ddfcp-1}, - {-0x1.b291f070528c7p-22, 0x1.729fep-1}, - {0x1.2967a451a7b48p-25, 0x1.7767cp-1}, - {0x1.2967a451a7b48p-25, 0x1.7767cp-1}, - {0x1.244fcff690fcep-22, 0x1.7c37ap-1}, - {0x1.46fd97f5dc572p-23, 0x1.810fap-1}, - {0x1.46fd97f5dc572p-23, 0x1.810fap-1}, - {-0x1.f3a7352663e5p-22, 0x1.85efep-1}, - {0x1.b3cda690370b5p-23, 0x1.8ad84p-1}, - {0x1.b3cda690370b5p-23, 0x1.8ad84p-1}, - {0x1.3226b211bf1d9p-23, 0x1.8fc92p-1}, - {0x1.d24b136c101eep-23, 0x1.94c28p-1}, - {0x1.d24b136c101eep-23, 0x1.94c28p-1}, - {0x1.7c40c7907e82ap-22, 0x1.99c48p-1}, - {-0x1.e81781d97ee91p-22, 0x1.9ecf6p-1}, - {-0x1.e81781d97ee91p-22, 0x1.9ecf6p-1}, - {-0x1.6a77813f94e01p-22, 0x1.a3e3p-1}, - {-0x1.1cfdeb43cfdp-22, 0x1.a8ffap-1}, - {-0x1.1cfdeb43cfdp-22, 0x1.a8ffap-1}, - {-0x1.f983f74d3138fp-23, 0x1.ae256p-1}, - {-0x1.e278ae1a1f51fp-23, 0x1.b3546p-1}, - {-0x1.e278ae1a1f51fp-23, 0x1.b3546p-1}, - {-0x1.97552b7b5ea45p-23, 0x1.b88ccp-1}, - {-0x1.97552b7b5ea45p-23, 0x1.b88ccp-1}, - {-0x1.19b4f3c72c4f8p-24, 0x1.bdceap-1}, - {0x1.f7402d26f1a12p-23, 0x1.c31a2p-1}, - {0x1.f7402d26f1a12p-23, 0x1.c31a2p-1}, - {-0x1.2056d5dd31d96p-23, 0x1.c86f8p-1}, - {-0x1.2056d5dd31d96p-23, 0x1.c86f8p-1}, - {-0x1.6e46335aae723p-24, 0x1.cdcecp-1}, - {-0x1.beb244c59f331p-22, 0x1.d3382p-1}, - {-0x1.beb244c59f331p-22, 0x1.d3382p-1}, - {0x1.16c071e93fd97p-27, 0x1.d8abap-1}, - {0x1.16c071e93fd97p-27, 0x1.d8abap-1}, - {0x1.d8175819530c2p-22, 0x1.de298p-1}, - {0x1.d8175819530c2p-22, 0x1.de298p-1}, - {0x1.51bd552842c1cp-23, 0x1.e3b2p-1}, - {0x1.51bd552842c1cp-23, 0x1.e3b2p-1}, - {0x1.914e204f19d94p-22, 0x1.e9452p-1}, - {0x1.914e204f19d94p-22, 0x1.e9452p-1}, - {0x1.c55d997da24fdp-22, 0x1.eee32p-1}, - {0x1.c55d997da24fdp-22, 0x1.eee32p-1}, - {-0x1.685c2d2298a6ep-22, 0x1.f48c4p-1}, - {-0x1.685c2d2298a6ep-22, 0x1.f48c4p-1}, - {0x1.7a4887bd74039p-22, 0x1.fa406p-1}, - {0.0, 1.0}, -}; - -#else - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE -LIBC_INLINE_VAR constexpr uint64_t ERR = 64; -#else -LIBC_INLINE_VAR constexpr uint64_t ERR = 128; -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - -// We choose the precision of the high part to be 53 - 24 - 8, so that when -// y * (e_x + LOG2_R_DD[i].hi) is exact. -// Generated by Sollya with: -// > for i from 0 to 127 do { -// r = 2^-8 * ceil(2^8 * (1 - 2^-8) / (1 + i * 2^-7) ); -// a = -log2(r); -// b = round(1 + a, 53 - 24 - 8, RN) - 1; -// c = round(a - b, D, RN); -// d = round(a - b - c, D, RN); -// print("{", d, ",", c, ", ", b, "},"); -// }; -LIBC_INLINE_VAR constexpr TripleDouble LOG2_R_TD[128] = { - {0.0, 0.0, 0.0}, - {0x1.84a2c615b70adp-79, -0x1.177c23362928cp-25, 0x1.72c8p-7}, - {-0x1.f27b820fd03eap-76, -0x1.179e0caa9c9abp-22, 0x1.744p-6}, - {-0x1.f27ef487c8f34p-77, -0x1.c6cea541f5b7p-23, 0x1.184cp-5}, - {-0x1.e3f80fbc71454p-76, -0x1.66c4d4e554434p-22, 0x1.773ap-5}, - {-0x1.9f8ef14d5f6eep-79, -0x1.70700a00fdd55p-24, 0x1.d6ecp-5}, - {0x1.452bbce7398c1p-77, 0x1.53002a4e86631p-23, 0x1.1bb3p-4}, - {-0x1.990555535afdp-81, 0x1.fcd15f101c142p-25, 0x1.4c56p-4}, - {0x1.447e30ad393eep-78, 0x1.25b3eed319cedp-22, 0x1.7d6p-4}, - {0x1.b7759da88a2dap-76, -0x1.4195120d8486fp-22, 0x1.960dp-4}, - {0x1.cee7766ece702p-78, 0x1.45b878e27d0d9p-23, 0x1.c7b5p-4}, - {-0x1.a55c745ecdc2fp-77, 0x1.770744593a4cbp-22, 0x1.f9c9p-4}, - {0x1.f7ec992caa67fp-77, 0x1.c673032495d24p-22, 0x1.097ep-3}, - {-0x1.433638c6ece3ep-77, -0x1.1eaa65b49696ep-22, 0x1.22dbp-3}, - {0x1.58f27b6518824p-76, 0x1.b2866f2850b22p-22, 0x1.3c6f8p-3}, - {-0x1.86bdcfdfd4a4cp-79, 0x1.8ee37cd2ea9d3p-25, 0x1.494f8p-3}, - {-0x1.ff7044a68a7fap-80, 0x1.7e86f9c2154fbp-24, 0x1.633a8p-3}, - {-0x1.aa21694561327p-81, 0x1.8e3cfc25f0ce6p-26, 0x1.7046p-3}, - {-0x1.d209f2d4239c6p-87, 0x1.57f7a64ccd537p-28, 0x1.8a898p-3}, - {-0x1.a55e97e60e632p-76, -0x1.a761c09fbd2aep-22, 0x1.97c2p-3}, - {0x1.261179225541ep-76, 0x1.24bea9a2c66f3p-22, 0x1.b26p-3}, - {-0x1.08fa30510fca9p-82, -0x1.60002ccfe43f5p-25, 0x1.bfc68p-3}, - {-0x1.63ec8d56242f9p-76, 0x1.69f220e97f22cp-22, 0x1.dac2p-3}, - {0x1.8bcdaf0534365p-76, -0x1.6164f64c210ep-22, 0x1.e858p-3}, - {0x1.1003282896056p-78, -0x1.0c1678ae89767p-24, 0x1.01d9cp-2}, - {0x1.01bcc7025fa92p-78, -0x1.f26a05c813d57p-22, 0x1.08bdp-2}, - {-0x1.fe8a8648e9ebcp-80, 0x1.4d8fc561c8d44p-24, 0x1.169cp-2}, - {0x1.08dfb23650c75p-79, -0x1.362ad8f7ca2dp-22, 0x1.1d984p-2}, - {-0x1.f8d5a89861a5ep-79, 0x1.2b13cd6c4d042p-22, 0x1.249ccp-2}, - {-0x1.a1c872983511ep-76, -0x1.1c8f11979a5dbp-22, 0x1.32cp-2}, - {0x1.e8e21bff3336bp-77, 0x1.c2ab3edefe569p-23, 0x1.39de8p-2}, - {0x1.fd1994fb2c4a1p-80, 0x1.7c3eca28e69cap-26, 0x1.4106p-2}, - {0x1.6b94b51cf76b1p-80, -0x1.34c4e99e1c6c6p-24, 0x1.4f6fcp-2}, - {-0x1.31d55da1d0f66p-76, -0x1.194a871b63619p-22, 0x1.56b24p-2}, - {-0x1.378b22691e28bp-77, 0x1.e3dd5c1c885aep-23, 0x1.5dfdcp-2}, - {0x1.99e302970e411p-83, -0x1.6ccf3b1129b7cp-23, 0x1.6552cp-2}, - {0x1.20164a049664dp-82, -0x1.2f346e2bf924bp-23, 0x1.6cb1p-2}, - {-0x1.d14aac4d864c3p-77, -0x1.fa61aaa59c1d8p-23, 0x1.7b8ap-2}, - {0x1.496ab4e4b293fp-79, 0x1.90c11fd32a3abp-22, 0x1.8304cp-2}, - {-0x1.d209f2d4239c6p-86, 0x1.57f7a64ccd537p-27, 0x1.8a898p-2}, - {0x1.eae3326327babp-81, 0x1.249ba76fee235p-27, 0x1.9218p-2}, - {0x1.fa05bddfded8cp-77, -0x1.aad2729b21ae5p-23, 0x1.99b08p-2}, - {-0x1.624140d175ba2p-77, 0x1.71810a5e1818p-22, 0x1.a8ff8p-2}, - {0x1.f1c5160c515c1p-81, -0x1.6172fe015e13cp-27, 0x1.b0b68p-2}, - {-0x1.86a6204eec8cp-79, 0x1.5ec6c1bfbf89ap-24, 0x1.b877cp-2}, - {0x1.718f761dd3915p-78, 0x1.678bf6cdedf51p-24, 0x1.c0438p-2}, - {-0x1.d4ee66c3700e4p-76, 0x1.c2d45fe43895ep-22, 0x1.c819cp-2}, - {-0x1.7d14533586306p-77, -0x1.9ee52ed49d71dp-22, 0x1.cffbp-2}, - {0x1.5ce9fb5a7bb5bp-81, 0x1.5786af187a96bp-27, 0x1.d7e6cp-2}, - {-0x1.ae6face57ad3bp-77, 0x1.3ab0dc56138c9p-23, 0x1.dfdd8p-2}, - {0x1.5ac93b443d55fp-78, 0x1.fe538ab34efb5p-22, 0x1.e7df4p-2}, - {0x1.f1753e0ae1e8fp-76, -0x1.e4fee07aa4b68p-22, 0x1.efec8p-2}, - {0x1.cdfd4c297069bp-76, -0x1.172f32fe67287p-22, 0x1.f804cp-2}, - {0x1.97a0e8f3ba742p-79, -0x1.9a83ff9ab9cc8p-22, 0x1.00144p-1}, - {-0x1.800450f5b2357p-78, -0x1.68cb06cece193p-22, 0x1.042bep-1}, - {-0x1.a839041241fe7p-78, 0x1.8cd71ddf82e2p-22, 0x1.08494p-1}, - {0x1.ed0b8eeccca86p-78, 0x1.5e18ab2df3ae6p-22, 0x1.0c6cap-1}, - {0x1.3dd41df9689b3p-79, 0x1.5dee4d9d8a273p-25, 0x1.1096p-1}, - {-0x1.990555535afdp-82, 0x1.fcd15f101c142p-26, 0x1.14c56p-1}, - {-0x1.1773d02c9055cp-77, -0x1.2474b0f992ba1p-23, 0x1.18faep-1}, - {-0x1.4aeef330c53c1p-78, 0x1.4b5a92a606047p-24, 0x1.1d368p-1}, - {0x1.8e6ff749ebacbp-77, 0x1.16186fcf54bbdp-22, 0x1.21786p-1}, - {0x1.c09d761c548ebp-84, 0x1.18efabeb7d722p-27, 0x1.25c0ap-1}, - {0x1.aaa73a428e1e4p-78, -0x1.e5fc7d238691dp-24, 0x1.2a0f4p-1}, - {-0x1.af2f3d8b63fbap-79, 0x1.f5809faf6283cp-22, 0x1.2e644p-1}, - {-0x1.af2f3d8b63fbap-79, 0x1.f5809faf6283cp-22, 0x1.2e644p-1}, - {0x1.78de359f2bb88p-77, 0x1.c6e1dcd0cb449p-22, 0x1.32bfep-1}, - {-0x1.415ae1a715618p-76, 0x1.76e0e8f74b4d5p-22, 0x1.37222p-1}, - {-0x1.4991b5375621fp-79, -0x1.cb82c89692d99p-24, 0x1.3b8b2p-1}, - {-0x1.827d37deb2236p-76, -0x1.63161c5432aebp-22, 0x1.3ffaep-1}, - {0x1.9576edac01c78p-77, 0x1.458104c41b901p-22, 0x1.44716p-1}, - {0x1.9576edac01c78p-77, 0x1.458104c41b901p-22, 0x1.44716p-1}, - {-0x1.05a27b81e2219p-77, -0x1.cd9d0cde578d5p-22, 0x1.48efp-1}, - {0x1.237616778b4bap-82, 0x1.b9884591add87p-26, 0x1.4d738p-1}, - {0x1.3b7d7e5d148bbp-76, 0x1.c6042978605ffp-22, 0x1.51ff2p-1}, - {-0x1.cc3f936a5977cp-79, -0x1.fc4c96b37dcf6p-22, 0x1.56922p-1}, - {0x1.20164a049664dp-83, -0x1.2f346e2bf924bp-24, 0x1.5b2c4p-1}, - {0x1.20164a049664dp-83, -0x1.2f346e2bf924bp-24, 0x1.5b2c4p-1}, - {-0x1.a212919a92f7ap-77, 0x1.c4e4fbb68a4d1p-22, 0x1.5fcdcp-1}, - {-0x1.b64b03f7230ddp-77, -0x1.9d499bd9b3226p-23, 0x1.6476ep-1}, - {-0x1.1ec6379e6e3b9p-77, -0x1.f89b355ede26fp-23, 0x1.69278p-1}, - {-0x1.1ec6379e6e3b9p-77, -0x1.f89b355ede26fp-23, 0x1.69278p-1}, - {-0x1.4ba44c03bfbbdp-78, 0x1.53c7e319f6e92p-24, 0x1.6ddfcp-1}, - {-0x1.c36fc650d030fp-77, -0x1.b291f070528c7p-22, 0x1.729fep-1}, - {-0x1.69e5693a7f067p-80, 0x1.2967a451a7b48p-25, 0x1.7767cp-1}, - {-0x1.69e5693a7f067p-80, 0x1.2967a451a7b48p-25, 0x1.7767cp-1}, - {0x1.6598aae91499ap-76, 0x1.244fcff690fcep-22, 0x1.7c37ap-1}, - {0x1.99d61ec432837p-77, 0x1.46fd97f5dc572p-23, 0x1.810fap-1}, - {0x1.99d61ec432837p-77, 0x1.46fd97f5dc572p-23, 0x1.810fap-1}, - {0x1.855c42078f81bp-76, -0x1.f3a7352663e5p-22, 0x1.85efep-1}, - {-0x1.59408e815107p-77, 0x1.b3cda690370b5p-23, 0x1.8ad84p-1}, - {-0x1.59408e815107p-77, 0x1.b3cda690370b5p-23, 0x1.8ad84p-1}, - {0x1.33b318085e50ap-78, 0x1.3226b211bf1d9p-23, 0x1.8fc92p-1}, - {0x1.343fe7c9cb4aep-79, 0x1.d24b136c101eep-23, 0x1.94c28p-1}, - {0x1.343fe7c9cb4aep-79, 0x1.d24b136c101eep-23, 0x1.94c28p-1}, - {-0x1.d19522e56fe6p-76, 0x1.7c40c7907e82ap-22, 0x1.99c48p-1}, - {-0x1.23b9d8ea55c3ep-77, -0x1.e81781d97ee91p-22, 0x1.9ecf6p-1}, - {-0x1.23b9d8ea55c3ep-77, -0x1.e81781d97ee91p-22, 0x1.9ecf6p-1}, - {0x1.829440c24aeb6p-78, -0x1.6a77813f94e01p-22, 0x1.a3e3p-1}, - {-0x1.624140d175ba2p-76, -0x1.1cfdeb43cfdp-22, 0x1.a8ffap-1}, - {-0x1.624140d175ba2p-76, -0x1.1cfdeb43cfdp-22, 0x1.a8ffap-1}, - {0x1.afa6f024fb045p-77, -0x1.f983f74d3138fp-23, 0x1.ae256p-1}, - {-0x1.603ad3a5d326dp-78, -0x1.e278ae1a1f51fp-23, 0x1.b3546p-1}, - {-0x1.603ad3a5d326dp-78, -0x1.e278ae1a1f51fp-23, 0x1.b3546p-1}, - {-0x1.0c1e0e5855d6ap-77, -0x1.97552b7b5ea45p-23, 0x1.b88ccp-1}, - {-0x1.0c1e0e5855d6ap-77, -0x1.97552b7b5ea45p-23, 0x1.b88ccp-1}, - {0x1.c817ad56baa16p-78, -0x1.19b4f3c72c4f8p-24, 0x1.bdceap-1}, - {0x1.44c47ac1bf62bp-77, 0x1.f7402d26f1a12p-23, 0x1.c31a2p-1}, - {0x1.44c47ac1bf62bp-77, 0x1.f7402d26f1a12p-23, 0x1.c31a2p-1}, - {-0x1.69b9465eae1e6p-78, -0x1.2056d5dd31d96p-23, 0x1.c86f8p-1}, - {-0x1.69b9465eae1e6p-78, -0x1.2056d5dd31d96p-23, 0x1.c86f8p-1}, - {-0x1.24a6d9d1d1904p-79, -0x1.6e46335aae723p-24, 0x1.cdcecp-1}, - {-0x1.3826144575ac4p-76, -0x1.beb244c59f331p-22, 0x1.d3382p-1}, - {-0x1.3826144575ac4p-76, -0x1.beb244c59f331p-22, 0x1.d3382p-1}, - {0x1.dbc96b3b12b25p-81, 0x1.16c071e93fd97p-27, 0x1.d8abap-1}, - {0x1.dbc96b3b12b25p-81, 0x1.16c071e93fd97p-27, 0x1.d8abap-1}, - {0x1.68a8ccdbd1f33p-77, 0x1.d8175819530c2p-22, 0x1.de298p-1}, - {0x1.68a8ccdbd1f33p-77, 0x1.d8175819530c2p-22, 0x1.de298p-1}, - {0x1.e586711df5ea1p-79, 0x1.51bd552842c1cp-23, 0x1.e3b2p-1}, - {0x1.e586711df5ea1p-79, 0x1.51bd552842c1cp-23, 0x1.e3b2p-1}, - {-0x1.bc25adf042483p-79, 0x1.914e204f19d94p-22, 0x1.e9452p-1}, - {-0x1.bc25adf042483p-79, 0x1.914e204f19d94p-22, 0x1.e9452p-1}, - {0x1.d7d82b65c5686p-76, 0x1.c55d997da24fdp-22, 0x1.eee32p-1}, - {0x1.d7d82b65c5686p-76, 0x1.c55d997da24fdp-22, 0x1.eee32p-1}, - {-0x1.3f108c0857ca3p-77, -0x1.685c2d2298a6ep-22, 0x1.f48c4p-1}, - {-0x1.3f108c0857ca3p-77, -0x1.685c2d2298a6ep-22, 0x1.f48c4p-1}, - {-0x1.bd800bca7a221p-78, 0x1.7a4887bd74039p-22, 0x1.fa406p-1}, - {0.0, 0.0, 1.0}, -}; - -// Look up table for the second range reduction step: -// Generated by Sollya with: -// > for i from -64 to 128 do { -// r = 2^-16 * nearestint(2^16 / (1 + i * 2^-14) ); -// a = -log2(r); -// b = round(a, D, RN); -// c = round(a - b, D, RN); -// print("{", c, ", ", b, "},"); -// }; -LIBC_INLINE_VAR constexpr DoubleDouble LOG2_R2_DD[] = { - {0x1.ff25180953e64p-62, -0x1.720c2ab2312a9p-8}, - {-0x1.15ffd79560d8fp-62, -0x1.6c4c92b1478ffp-8}, - {0x1.b8d6d6f2e3579p-62, -0x1.668ce3c873549p-8}, - {-0x1.5bfc3f0d5ef71p-62, -0x1.60cd1df6fde91p-8}, - {-0x1.d1f7a8777984ap-64, -0x1.5b0d413c30b5ep-8}, - {0x1.8e858515b8343p-66, -0x1.554d4d97551abp-8}, - {0x1.e165c4014c1f2p-62, -0x1.4f8d4307b46ecp-8}, - {0x1.0f84b2cc14c7ep-63, -0x1.49cd218c9800bp-8}, - {0x1.de618ed0db9a6p-62, -0x1.440ce9254916cp-8}, - {-0x1.f6b8587e64f22p-62, -0x1.3e4c99d110ee7p-8}, - {-0x1.7f793c84cfa63p-64, -0x1.388c338f38bdp-8}, - {-0x1.7d7ecf6258c9ap-65, -0x1.32cbb65f09aeep-8}, - {-0x1.810bc5ac188f5p-62, -0x1.2d0b223fcce81p-8}, - {-0x1.950035fc5b67cp-62, -0x1.274a7730cb841p-8}, - {0x1.4f47f3048cdadp-62, -0x1.2189b5314e95dp-8}, - {0x1.269519861e298p-68, -0x1.1bc8dc409f279p-8}, - {-0x1.5c2b0a46a7e2fp-62, -0x1.1607ec5e063b3p-8}, - {0x1.5001ac8f0bda8p-63, -0x1.1046e588cccap-8}, - {0x1.106f246af5d41p-62, -0x1.0a85c7c03bc4ap-8}, - {0x1.82a00583b34bap-66, -0x1.0354423e3c666p-8}, - {0x1.b6f37deb3137p-65, -0x1.fb25e19f11aecp-9}, - {-0x1.44a2140444811p-63, -0x1.efa310d6550ecp-9}, - {0x1.f5e68a763133fp-63, -0x1.e4201220d4858p-9}, - {0x1.692083115f0b9p-63, -0x1.d89ce57d219a6p-9}, - {0x1.144bb17b9ac9cp-63, -0x1.cd198ae9cdc3dp-9}, - {0x1.ee7f086d32c05p-63, -0x1.c19602656a671p-9}, - {-0x1.d4f1167538dbep-63, -0x1.b6124bee88d82p-9}, - {0x1.7df8d226c67ep-63, -0x1.aa8e6783ba5a2p-9}, - {0x1.60545d61b9512p-63, -0x1.9f0a5523901ebp-9}, - {0x1.54c99c291702p-63, -0x1.938614cc9b468p-9}, - {-0x1.a7e678d7280dep-64, -0x1.8801a67d6ce1p-9}, - {-0x1.6d419bbeb223ap-64, -0x1.7c7d0a3495ec9p-9}, - {0x1.ce2b9892e27e9p-64, -0x1.70f83ff0a7565p-9}, - {-0x1.a4db4eff7bd61p-63, -0x1.657347b031fa2p-9}, - {0x1.5bb04682fab82p-63, -0x1.59ee2171c6a2fp-9}, - {-0x1.78b8bfe6a3adep-64, -0x1.4e68cd33f60a3p-9}, - {0x1.574c3ce9b89b1p-63, -0x1.42e34af550d87p-9}, - {0x1.08fb216647b7bp-63, -0x1.375d9ab467a4dp-9}, - {0x1.ed5a50e7b919cp-66, -0x1.2bd7bc6fcaf56p-9}, - {0x1.91ad7a23f86fep-63, -0x1.2051b0260b3fp-9}, - {0x1.3ab2c932b8b0ap-64, -0x1.14cb75d5b8e54p-9}, - {-0x1.c63bcdf120f7ap-63, -0x1.09450d7d643a9p-9}, - {0x1.8af8c4ab4e82dp-64, -0x1.fb7cee373b008p-10}, - {0x1.a52c2ca9d8b9bp-65, -0x1.e46f655de9cc6p-10}, - {-0x1.460b177a58742p-64, -0x1.cd61806bf5166p-10}, - {0x1.611089de8d12ap-66, -0x1.b6533f5e7cf9bp-10}, - {-0x1.4209853cee70cp-69, -0x1.9f44a232a16eep-10}, - {0x1.964e032541a28p-64, -0x1.8835a8e5824c3p-10}, - {-0x1.fa9f94392637bp-66, -0x1.712653743f454p-10}, - {-0x1.3293693721a53p-64, -0x1.5a16a1dbf7eb6p-10}, - {-0x1.6e2af03c83c6ep-68, -0x1.43069419cbad5p-10}, - {-0x1.b5f05b9d5bd29p-65, -0x1.2bf62a2ad9d74p-10}, - {0x1.3db883c072f72p-64, -0x1.14e5640c4193p-10}, - {-0x1.a675a1c045304p-68, -0x1.fba8837643cf6p-11}, - {0x1.3b9c2aeb00068p-66, -0x1.cd85866933743p-11}, - {-0x1.2911a381901ebp-66, -0x1.9f61d0eb8f98bp-11}, - {-0x1.5ea75a74def03p-68, -0x1.713d62f7957c3p-11}, - {-0x1.305b92f93ffep-67, -0x1.43183c878218dp-11}, - {0x1.b7c8c8dd40d35p-68, -0x1.14f25d959223ap-11}, - {0x1.dc915d58a62f6p-66, -0x1.cd978c3804191p-12}, - {0x1.c7bc3fe53cd94p-66, -0x1.7148ec2a1bfc9p-12}, - {-0x1.427ce595cc53cp-67, -0x1.14f8daf5e3bcfp-12}, - {-0x1.d523885ac824cp-67, -0x1.714eb11fa5363p-13}, - {-0x1.945957f63330ap-69, -0x1.715193b17d35dp-14}, - {0, 0}, - {-0x1.88fb2ea8bf9eap-70, 0x1.7157590356aeep-14}, - {-0x1.5aeaee345d04ep-68, 0x1.715a3bc3593d5p-13}, - {-0x1.7fce430230132p-66, 0x1.1505d6ee104c5p-12}, - {-0x1.9a480f204ff09p-70, 0x1.716001718cb2bp-12}, - {-0x1.00e7233f2d8bdp-68, 0x1.cdbb9d77ae5a8p-12}, - {0x1.09d379fa18c5dp-67, 0x1.150c5586012b8p-11}, - {0x1.b6b9d90a104d3p-65, 0x1.433b951d0b231p-11}, - {0x1.4d9a3ea651885p-65, 0x1.716b8d86bc285p-11}, - {-0x1.7590b3a76f0f9p-67, 0x1.9f9c3ec8db94fp-11}, - {0x1.f183ca5b21bfep-65, 0x1.cdcda8e93107fp-11}, - {-0x1.a7e3465ba127p-66, 0x1.fbffcbed8465fp-11}, - {-0x1.7821f738d1221p-64, 0x1.151953edceec6p-10}, - {0x1.3bb4c0fb95359p-65, 0x1.2c331e5ca2e7dp-10}, - {0x1.236028e962f8p-64, 0x1.434d4546227fcp-10}, - {0x1.aaaa64d30f184p-66, 0x1.5a67c8ad32315p-10}, - {-0x1.a821b7cc57a7ap-64, 0x1.7182a894b69c6p-10}, - {-0x1.13d9d78aace21p-64, 0x1.889de4ff94838p-10}, - {-0x1.2f249a6b923ap-64, 0x1.9fb97df0b0cc2p-10}, - {-0x1.d47dc3664be7ap-68, 0x1.b6d5736af07e6p-10}, - {0x1.bd1522c6418fbp-64, 0x1.cdf1c57138c53p-10}, - {-0x1.bacdbb22d2163p-64, 0x1.e50e74066eee6p-10}, - {-0x1.ca7604812d77bp-64, 0x1.fc2b7f2d786a5p-10}, - {-0x1.2b6832f8830bfp-63, 0x1.09a473749d663p-9}, - {0x1.4e712033d0457p-65, 0x1.1533559e4de55p-9}, - {-0x1.473dd044017b5p-66, 0x1.20c26615409f1p-9}, - {-0x1.e033bcac726d3p-63, 0x1.2c51a4dae8915p-9}, - {-0x1.4a47a2b18a0fap-63, 0x1.37e111f0b8cb5p-9}, - {0x1.6f3615771c17bp-66, 0x1.4370ad58246ddp-9}, - {0x1.c0ee6c32d6236p-65, 0x1.4f0077129eabp-9}, - {0x1.fa94c99761b8fp-64, 0x1.5a906f219ac67p-9}, - {-0x1.979e6b473fbf8p-64, 0x1.662095868c153p-9}, - {0x1.30edde8d24c7bp-64, 0x1.71b0ea42e5fdap-9}, - {-0x1.d01594fe1421cp-64, 0x1.7d416d581bf7cp-9}, - {0x1.50bf7b995b49ap-63, 0x1.88d21ec7a18cdp-9}, - {-0x1.28ea2bcec5018p-63, 0x1.9462fe92ea57cp-9}, - {0x1.ed6add489c30bp-65, 0x1.9ff40cbb6a04bp-9}, - {0x1.201d5c3bbeb69p-64, 0x1.ab85494294517p-9}, - {-0x1.a05d0d4461ea9p-64, 0x1.b716b429dd0d3p-9}, - {-0x1.7c974c8a392fdp-63, 0x1.c2a84d72b8189p-9}, - {-0x1.f068238451bdep-64, 0x1.ce3a151e9965bp-9}, - {-0x1.5e4d95c6259c3p-66, 0x1.d9cc0b2ef4f83p-9}, - {-0x1.1fc262efaad6cp-63, 0x1.e55e2fa53ee53p-9}, - {0x1.49eee7abc7716p-63, 0x1.f0f08282eb533p-9}, - {-0x1.903de284d2782p-65, 0x1.fc8303c96e7a6p-9}, - {-0x1.ec564845134cbp-63, 0x1.040ad9bd1e522p-8}, - {-0x1.7692b7791cf1fp-66, 0x1.0861eadabc3dcp-8}, - {-0x1.37829afb11c1p-62, 0x1.0e2b6b51e4f7ep-8}, - {0x1.6706b91c3b0bap-62, 0x1.13f5030033459p-8}, - {-0x1.7558ccd710756p-62, 0x1.19beb1e6616c9p-8}, - {0x1.79f72a5bbe9dep-62, 0x1.1f88780529bb1p-8}, - {-0x1.e1297c110b25p-62, 0x1.2552555d46886p-8}, - {0x1.29930d567ca26p-62, 0x1.2b1c49ef72343p-8}, - {0x1.a08cbd7592a17p-65, 0x1.30e655bc67275p-8}, - {0x1.e4f9d4ac5db83p-62, 0x1.36b078c4dfd31p-8}, - {-0x1.ed1b0aafd30c2p-62, 0x1.3c7ab30996b1cp-8}, - {0x1.e78f0aa014b32p-62, 0x1.4245048b46462p-8}, - {0x1.8594548038a0fp-69, 0x1.480f6d4aa91c2p-8}, - {0x1.3df498168a333p-63, 0x1.4dd9ed4879c82p-8}, - {0x1.b1c502544f82ap-62, 0x1.53a4848572e77p-8}, - {-0x1.dc50552fe0da9p-63, 0x1.596f33024f203p-8}, - {-0x1.671d85c357d5ep-62, 0x1.5f39f8bfc9212p-8}, - {0x1.1c670cabccefap-64, 0x1.6504d5be9ba1ep-8}, - {-0x1.9983a9e98f318p-62, 0x1.6acfc9ff8162fp-8}, - {0x1.ae1a26af3eebep-62, 0x1.709ad583352d6p-8}, - {0x1.655eb510bfda3p-62, 0x1.7665f84a71d35p-8}, - {-0x1.e287bc0192e15p-64, 0x1.7c313255f22f8p-8}, - {0x1.cc4944139ccbfp-63, 0x1.81fc83a671257p-8}, - {0x1.4e09b4cb8645bp-62, 0x1.87c7ec3ca9a19p-8}, - {-0x1.5becc991e3a5fp-64, 0x1.8d936c1956991p-8}, - {-0x1.ddfa3f1e15ba8p-62, 0x1.935f033d3309ep-8}, - {-0x1.b7b06ea3fb362p-62, 0x1.992ab1a8f9facp-8}, - {0x1.32d614904e46cp-62, 0x1.9ef6775d667b4p-8}, - {-0x1.7186892b5bfaep-64, 0x1.a4c2545b33a3ep-8}, - {-0x1.d4de10b28dfd8p-62, 0x1.aa8e48a31c95cp-8}, - {0x1.4bb4b3bdc8175p-62, 0x1.b05a5435dc7adp-8}, - {0x1.9cedbd1d7fba5p-62, 0x1.b62677142e86p-8}, - {-0x1.0ed3379beaffdp-66, 0x1.bbf2b13ecdf2fp-8}, - {0x1.6e86a125567a6p-62, 0x1.c1bf02b67606p-8}, - {-0x1.35038e0c0a52cp-62, 0x1.c6184f1b326d9p-8}, - {0x1.05ef8bf5adf5ep-67, 0x1.cbe4c95b6c5abp-8}, - {-0x1.b7338b99a6b26p-65, 0x1.d1b15aeab217cp-8}, - {0x1.9e901c30c427ep-63, 0x1.d77e03c9bf0a4p-8}, - {-0x1.1f28a9c0b3d47p-62, 0x1.dd4ac3f94ea0ap-8}, - {-0x1.140ef760d3b63p-62, 0x1.e3179b7a1c52p-8}, - {-0x1.ab65b1037f517p-63, 0x1.e8e48a4ce39e7p-8}, - {-0x1.76940c457ce6dp-63, 0x1.eeb19072600edp-8}, - {0x1.da3ae65a605cfp-64, 0x1.f47eadeb4d34dp-8}, - {0x1.b15d0bce2ede6p-62, 0x1.fa4be2b866abp-8}, - {0x1.e02aa1fa9dc57p-61, 0x1.000c976d340a6p-7}, - {0x1.6be971a5565b9p-62, 0x1.02f34929068f3p-7}, - {-0x1.8a9319a6ed164p-64, 0x1.05da069008be7p-7}, - {0x1.825079f1e0ec5p-62, 0x1.08c0cfa298771p-7}, - {0x1.60d5749321466p-63, 0x1.0ba7a461139c8p-7}, - {-0x1.5b8f4c479e2ep-61, 0x1.0e8e84cbd8169p-7}, - {-0x1.e3e1248004e29p-62, 0x1.117570e343d17p-7}, - {0x1.9ac06487c375p-63, 0x1.145c68a7b4bddp-7}, - {0x1.f657ea5c03ea4p-62, 0x1.17436c1988d0dp-7}, - {-0x1.5a965659a05e2p-61, 0x1.1a2a7b391e04p-7}, - {-0x1.21ce9b9bfc512p-61, 0x1.1d119606d2554p-7}, - {-0x1.30fda247ad0e1p-61, 0x1.1ff8bc8303c7p-7}, - {-0x1.382c78a45cdeap-62, 0x1.22dfeeae10601p-7}, - {0x1.46ae4a64073d4p-61, 0x1.250d5bf952374p-7}, - {-0x1.dcad2cec3b84bp-62, 0x1.27f4a29740a2fp-7}, - {-0x1.413fbeb0b0635p-61, 0x1.2adbf4e50cdf9p-7}, - {0x1.f28e6a48bcb9p-61, 0x1.2dc352e315049p-7}, - {-0x1.96f286e1eb086p-61, 0x1.30aabc91b72ep-7}, - {-0x1.f88c04206dfa1p-61, 0x1.339231f1517c1p-7}, - {-0x1.11ea20e195841p-61, 0x1.3679b30242139p-7}, - {-0x1.d6e71452b674ap-63, 0x1.39613fc4e71dcp-7}, - {-0x1.57c578233b1b3p-61, 0x1.3c48d8399ec85p-7}, - {-0x1.ec430f03b76ep-63, 0x1.3f307c60c7455p-7}, - {0x1.e00dd1902ffb9p-61, 0x1.42182c3abecb5p-7}, - {-0x1.f22bcd96afe38p-61, 0x1.44ffe7c7e3957p-7}, - {0x1.08fd90f841d3p-61, 0x1.47e7af0893e2fp-7}, - {0x1.09594c5552bccp-62, 0x1.4acf81fd2df7ep-7}, - {-0x1.01a8a652e5602p-61, 0x1.4db760a6101c9p-7}, - {-0x1.826168febb3dp-64, 0x1.509f4b03989dcp-7}, - {-0x1.7eb21a35021e3p-62, 0x1.5387411625cccp-7}, - {-0x1.66cbc818e175p-61, 0x1.566f42de15ff4p-7}, - {0x1.9b784dd6cebdap-64, 0x1.5957505bc78f6p-7}, - {0x1.2b121ab482456p-61, 0x1.5b8562298c65bp-7}, - {-0x1.5d29869dd8233p-62, 0x1.5e6d842633702p-7}, - {-0x1.572a1b6cd63cfp-61, 0x1.6155b1d99f672p-7}, - {-0x1.a1f355360e877p-62, 0x1.643deb442eb59p-7}, - {-0x1.b6f1cd2e1c03fp-61, 0x1.672630663fcadp-7}, - {-0x1.2aaa11ccddcaep-61, 0x1.6a0e8140311aap-7}, - {0x1.3d979ddf4746cp-61, 0x1.6cf6ddd2611d4p-7}, - {-0x1.dc930484501f8p-63, 0x1.6fdf461d2e4f8p-7}, -}; -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -LIBC_INLINE bool is_odd_integer(float x) { - using FPBits = typename fputil::FPBits<float>; - uint32_t x_u = cpp::bit_cast<uint32_t>(x); - int32_t x_e = - static_cast<int32_t>((x_u & FPBits::EXP_MASK) >> FPBits::FRACTION_LEN); - int32_t lsb = cpp::countr_zero(x_u | FPBits::EXP_MASK); - constexpr int32_t UNIT_EXPONENT = - FPBits::EXP_BIAS + static_cast<int32_t>(FPBits::FRACTION_LEN); - return (x_e + lsb == UNIT_EXPONENT); -} - -LIBC_INLINE bool is_integer(float x) { - using FPBits = typename fputil::FPBits<float>; - uint32_t x_u = cpp::bit_cast<uint32_t>(x); - int32_t x_e = - static_cast<int32_t>((x_u & FPBits::EXP_MASK) >> FPBits::FRACTION_LEN); - int32_t lsb = cpp::countr_zero(x_u | FPBits::EXP_MASK); - constexpr int32_t UNIT_EXPONENT = - FPBits::EXP_BIAS + static_cast<int32_t>(FPBits::FRACTION_LEN); - return (x_e + lsb >= UNIT_EXPONENT); -} - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -LIBC_INLINE bool larger_exponent(double a, double b) { - using DoubleBits = typename fputil::FPBits<double>; - return DoubleBits(a).get_biased_exponent() >= - DoubleBits(b).get_biased_exponent(); -} - -// Calculate 2^(y * log2(x)) in double-double precision. -// At this point we can reuse the following values: -// idx_x: index for extra precision of log2 for the middle part of log2(x). -// dx: the reduced argument for log2(x) -// y6: 2^6 * y. -// lo6_hi: the high part of 2^6 * (y - (hi + mid)) -// exp2_hi_mid: high part of 2^(hi + mid) -LIBC_INLINE double powf_double_double(int idx_x, double dx, double y6, - double lo6_hi, - const DoubleDouble &exp2_hi_mid) { - using DoubleBits = typename fputil::FPBits<double>; - - // Perform a second range reduction step: - // idx2 = round(2^14 * (dx + 2^-8)) = round ( dx * 2^14 + 2^6) - // dx2 = (1 + dx) * r2 - 1 - // Output range: - // -0x1.3ffcp-15 <= dx2 <= 0x1.3e3dp-15 - int idx2 = static_cast<int>( - fputil::nearest_integer(fputil::multiply_add(dx, 0x1.0p14, 0x1.0p6))); - double dx2 = fputil::multiply_add( - 1.0 + dx, common_constants_internal::R2[idx2], -1.0); // Exact - - // Degree-5 polynomial approximation of log2(1 + x)/x in double-double - // precision. Generate by Solya with: - // > P = fpminimax(log2(1 + x)/x, 5, [|DD...|], - // [-0x1.3ffcp-15, 0x1.3e3dp-15]); - // > dirtyinfnorm(log2(1 + x)/x - P, [-0x1.3ffcp-15, 0x1.3e3dp-15]); - // 0x1.8be5...p-96. - constexpr DoubleDouble COEFFS[] = { - {0x1.777d0ffda25ep-56, 0x1.71547652b82fep0}, - {-0x1.777d101cf0a84p-57, -0x1.71547652b82fep-1}, - {0x1.ce04b5140d867p-56, 0x1.ec709dc3a03fdp-2}, - {0x1.137b47e635be5p-56, -0x1.71547652b82fbp-2}, - {-0x1.b5a30b3bdb318p-58, 0x1.2776c516a92a2p-2}, - {0x1.2d2fbd081e657p-57, -0x1.ec70af1929ca6p-3}, - }; - - DoubleDouble dx_dd({0.0, dx2}); - DoubleDouble p = fputil::polyeval(dx_dd, COEFFS[0], COEFFS[1], COEFFS[2], - COEFFS[3], COEFFS[4], COEFFS[5]); - // log2(1 + dx2) ~ dx2 * P(dx2) - DoubleDouble log2_x_lo = fputil::quick_mult(dx2, p); - // Lower parts of (e_x - log2(r1)) of the first range reduction constant - DoubleDouble log2_x_mid({LOG2_R_TD[idx_x].lo, LOG2_R_TD[idx_x].mid}); - // -log2(r2) + lower part of (e_x - log2(r1)) - DoubleDouble log2_x_m = fputil::add(LOG2_R2_DD[idx2], log2_x_mid); - // log2(1 + dx2) - log2(r2) + lower part of (e_x - log2(r1)) - // Since we don't know which one has larger exponent to apply Fast2Sum - // algorithm, we need to check them before calling double-double addition. - DoubleDouble log2_x = larger_exponent(log2_x_m.hi, log2_x_lo.hi) - ? fputil::add(log2_x_m, log2_x_lo) - : fputil::add(log2_x_lo, log2_x_m); - DoubleDouble lo6_hi_dd({0.0, lo6_hi}); - // 2^6 * y * (log2(1 + dx2) - log2(r2) + lower part of (e_x - log2(r1))) - DoubleDouble prod = fputil::quick_mult(y6, log2_x); - // 2^6 * (y * log2(x) - (hi + mid)) = 2^6 * lo - DoubleDouble lo6 = larger_exponent(prod.hi, lo6_hi) - ? fputil::add(prod, lo6_hi_dd) - : fputil::add(lo6_hi_dd, prod); - - constexpr DoubleDouble EXP2_COEFFS[] = { - {0, 0x1p0}, - {0x1.abc9e3b398024p-62, 0x1.62e42fefa39efp-7}, - {-0x1.5e43a5429bddbp-69, 0x1.ebfbdff82c58fp-15}, - {-0x1.d33162491268fp-77, 0x1.c6b08d704a0cp-23}, - {0x1.4fb32d240a14ep-86, 0x1.3b2ab6fba4e77p-31}, - {0x1.e84e916be83ep-97, 0x1.5d87fe78a6731p-40}, - {-0x1.9a447bfddc5e6p-103, 0x1.430912f86bfb8p-49}, - {-0x1.31a55719de47fp-113, 0x1.ffcbfc588ded9p-59}, - {-0x1.0ba57164eb36bp-122, 0x1.62c034beb8339p-68}, - {-0x1.8483eabd9642dp-132, 0x1.b5251ff97bee1p-78}, - }; - - DoubleDouble pp = fputil::polyeval( - lo6, EXP2_COEFFS[0], EXP2_COEFFS[1], EXP2_COEFFS[2], EXP2_COEFFS[3], - EXP2_COEFFS[4], EXP2_COEFFS[5], EXP2_COEFFS[6], EXP2_COEFFS[7], - EXP2_COEFFS[8], EXP2_COEFFS[9]); - DoubleDouble rr = fputil::quick_mult(exp2_hi_mid, pp); - - // Make sure the sum is normalized: - DoubleDouble r = fputil::exact_add(rr.hi, rr.lo); - // Round to odd. - uint64_t r_bits = cpp::bit_cast<uint64_t>(r.hi); - if (LIBC_UNLIKELY(((r_bits & 0xfff'ffff) == 0) && (r.lo != 0.0))) { - Sign hi_sign = DoubleBits(r.hi).sign(); - Sign lo_sign = DoubleBits(r.lo).sign(); - if (hi_sign == lo_sign) { - ++r_bits; - } else if ((r_bits & DoubleBits::FRACTION_MASK) > 0) { - --r_bits; - } - } - - return cpp::bit_cast<double>(r_bits); -} -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -} // namespace powf_internal - -LIBC_INLINE float powf(float x, float y) { - using namespace powf_internal; - using FloatBits = typename fputil::FPBits<float>; - using DoubleBits [[maybe_unused]] = typename fputil::FPBits<double>; - - FloatBits xbits(x), ybits(y); - - uint32_t x_u = xbits.uintval(); - uint32_t x_abs = xbits.abs().uintval(); - uint32_t y_u = ybits.uintval(); - uint32_t y_abs = ybits.abs().uintval(); - - ///////// BEGIN - Check exceptional cases //////////////////////////////////// - - // The single precision number that is closest to 1 is (1 - 2^-24), which has - // log2(1 - 2^-24) ~ -1.715...p-24. - // So if |y| > 151 * 2^24, and x is finite: - // |y * log2(x)| = 0 or > 151. - // Hence x^y will either overflow or underflow if x is not zero. - if (LIBC_UNLIKELY((y_abs & 0x0007'ffff) == 0) || (y_abs > 0x4f170000)) { - // y is signaling NaN - if (xbits.is_signaling_nan() || ybits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FloatBits::quiet_nan().get_val(); - } - - // Exceptional exponents. - if (y == 0.0f) - return 1.0f; - - switch (y_abs) { - case 0x7f80'0000: { // y = +-Inf - if (x_abs > 0x7f80'0000) { - // pow(NaN, +-Inf) = NaN - return x; - } - if (x_abs == 0x3f80'0000) { - // pow(+-1, +-Inf) = 1.0f - return 1.0f; - } - if (x == 0.0f && y_u == 0xff80'0000) { - // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FloatBits::inf().get_val(); - } - // pow (|x| < 1, -inf) = +inf - // pow (|x| < 1, +inf) = 0.0f - // pow (|x| > 1, -inf) = 0.0f - // pow (|x| > 1, +inf) = +inf - return ((x_abs < 0x3f80'0000) == (y_u == 0xff80'0000)) - ? FloatBits::inf().get_val() - : 0.0f; - } - default: - // Speed up for common exponents - float r = fputil::sqrt<float>(x); - switch (y_u) { - case 0x3f00'0000: // y = 0.5f - // pow(x, 1/2) = sqrt(x) - if (LIBC_UNLIKELY(x == 0.0f || x_u == 0xff80'0000)) { - // pow(-0, 1/2) = +0 - // pow(-inf, 1/2) = +inf - // Make sure it is correct for FTZ/DAZ. - return x * x; - } - return (FloatBits(r).uintval() != 0x8000'0000) ? r : 0.0f; - case 0x3f80'0000: // y = 1.0f - return x; - case 0x4000'0000: // y = 2.0f - // pow(x, 2) = x^2 - return x * x; - // TODO: Enable special case speed-up for x^(-1/2) when rsqrt is ready. - // case 0xbf00'0000: // pow(x, -1/2) = rsqrt(x) - // return rsqrt(x); - } - if (is_integer(y) && (y_u > 0x4000'0000) && (y_u <= 0x41c0'0000)) { - // Check for exact cases when 2 < y < 25 and y is an integer. - int msb = - (x_abs == 0) ? (FloatBits::TOTAL_LEN - 2) : cpp::countl_zero(x_abs); - msb = (msb > FloatBits::EXP_LEN) ? msb : FloatBits::EXP_LEN; - int lsb = (x_abs == 0) ? 0 : cpp::countr_zero(x_abs); - lsb = (lsb > FloatBits::FRACTION_LEN) ? FloatBits::FRACTION_LEN : lsb; - int extra_bits = FloatBits::TOTAL_LEN - 2 - lsb - msb; - int iter = static_cast<int>(y); - - if (extra_bits * iter <= FloatBits::FRACTION_LEN + 2) { - // The result is either exact or exactly half-way. - // But it is exactly representable in double precision. - double x_d = static_cast<double>(x); - double result = x_d; - for (int i = 1; i < iter; ++i) - result *= x_d; - return static_cast<float>(result); - } - } - if (y_abs > 0x4f17'0000) { - // if y is NaN - if (y_abs > 0x7f80'0000) { - if (x_u == 0x3f80'0000) { // x = 1.0f - // pow(1, NaN) = 1 - return 1.0f; - } - // pow(x, NaN) = NaN - return y; - } - // x^y will be overflow / underflow in single precision. Set y to a - // large enough exponent but not too large, so that the computations - // won't be overflow in double precision. - y = cpp::bit_cast<float>((y_u & FloatBits::SIGN_MASK) + 0x4f800000U); - } - } - } - - int ex = -FloatBits::EXP_BIAS; - uint64_t sign = 0; - - // y is finite and non-zero. - if (LIBC_UNLIKELY(((x_u & 0x801f'ffffU) == 0) || x_u >= 0x7f80'0000U || - x_u < 0x0080'0000U)) { - // if x is signaling NaN - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FloatBits::quiet_nan().get_val(); - } - - switch (x_u) { - case 0x3f80'0000: // x = 1.0f - return 1.0f; - // TODO: Put these 2 entrypoint dependency under control flag. -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - case 0x4000'0000: // x = 2.0f - // pow(2, y) = exp2(y) - return math::exp2f(y); - case 0x4120'0000: // x = 10.0f - // pow(10, y) = exp10(y) - return math::exp10f(y); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - } - - const bool x_is_neg = x_u >= FloatBits::SIGN_MASK; - - if (x == 0.0f) { - const bool out_is_neg = - x_is_neg && is_odd_integer(FloatBits(y_u).get_val()); - if (y_u > 0x8000'0000U) { - // pow(0, negative number) = inf - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS).get_val(); - } - // pow(0, positive number) = 0 - return out_is_neg ? -0.0f : 0.0f; - } - - if (x_abs == 0x7f80'0000) { - // x = +-Inf - const bool out_is_neg = - x_is_neg && is_odd_integer(FloatBits(y_u).get_val()); - if (y_u >= FloatBits::SIGN_MASK) { - return out_is_neg ? -0.0f : 0.0f; - } - return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS).get_val(); - } - - if (x_abs > 0x7f80'0000) { - // x is NaN. - // pow (aNaN, 0) is already taken care above. - return x; - } - - // Normalize denormal inputs. - if (x_abs < 0x0080'0000U) { - ex -= 64; - x *= 0x1.0p64f; - } - - // x is finite and negative, and y is a finite integer. - if (x_is_neg) { - if (is_integer(y)) { - x = -x; - if (is_odd_integer(y)) { - // sign = -1.0; - sign = 0x8000'0000'0000'0000ULL; - } - } else { - // pow( negative, non-integer ) = NaN - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FloatBits::quiet_nan().get_val(); - } - } - } - - ///////// END - Check exceptional cases ////////////////////////////////////// - -#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ - defined(LIBC_MATH_HAS_SMALL_TABLES) - return powf_small_tables(x, ex, sign, y); -#else - using namespace common_constants_internal; - - // x^y = 2^( y * log2(x) ) - // = 2^( y * ( e_x + log2(m_x) ) ) - // First we compute log2(x) = e_x + log2(m_x) - x_u = FloatBits(x).uintval(); - - // Extract exponent field of x. - ex += (x_u >> FloatBits::FRACTION_LEN); - double e_x = static_cast<double>(ex); - // Use the highest 7 fractional bits of m_x as the index for look up tables. - uint32_t x_mant = x_u & FloatBits::FRACTION_MASK; - int idx_x = static_cast<int>(x_mant >> (FloatBits::FRACTION_LEN - 7)); - // Add the hidden bit to the mantissa. - // 1 <= m_x < 2 - float m_x = cpp::bit_cast<float>(x_mant | 0x3f800000); - - // Reduced argument for log2(m_x): - // dx = r * m_x - 1. - // The computation is exact, and -2^-8 <= dx < 2^-7. - // Then m_x = (1 + dx) / r, and - // log2(m_x) = log2( (1 + dx) / r ) - // = log2(1 + dx) - log2(r). -#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT - double dx = - static_cast<double>(fputil::multiply_add(m_x, R[idx_x], -1.0f)); // Exact -#else - double dx = - fputil::multiply_add(static_cast<double>(m_x), RD[idx_x], -1.0); // Exact -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - - // Degree-5 polynomial approximation: - // dx * P(dx) ~ log2(1 + dx) - // Generated by Sollya with: - // > P = fpminimax(log2(1 + x)/x, 5, [|D...|], [-2^-8, 2^-7]); - // > dirtyinfnorm(log2(1 + x)/x - P, [-2^-8, 2^-7]); - // 0x1.653...p-52 - constexpr double COEFFS[] = {0x1.71547652b82fep0, -0x1.71547652b7a07p-1, - 0x1.ec709dc458db1p-2, -0x1.715479c2266c9p-2, - 0x1.2776ae1ddf8fp-2, -0x1.e7b2178870157p-3}; - - double dx2 = dx * dx; // Exact - double c0 = fputil::multiply_add(dx, COEFFS[1], COEFFS[0]); - double c1 = fputil::multiply_add(dx, COEFFS[3], COEFFS[2]); - double c2 = fputil::multiply_add(dx, COEFFS[5], COEFFS[4]); - - double p = fputil::polyeval(dx2, c0, c1, c2); - - ////////////////////////////////////////////////////////////////////////////// - // NOTE: For some reason, this is significantly less efficient than above! - // - // > P = fpminimax(log2(1 + x)/x, 4, [|D...|], [-2^-8, 2^-7]); - // > dirtyinfnorm(log2(1 + x)/x - P, [-2^-8, 2^-7]); - // 0x1.d04...p-44 - // constexpr double COEFFS[] = {0x1.71547652b8133p0, -0x1.71547652d1e33p-1, - // 0x1.ec70a098473dep-2, -0x1.7154c5ccdf121p-2, - // 0x1.2514fd90a130ap-2}; - // - // double dx2 = dx * dx; - // double c0 = fputil::multiply_add(dx, COEFFS[1], COEFFS[0]); - // double c1 = fputil::multiply_add(dx, COEFFS[3], COEFFS[2]); - // double p = fputil::polyeval(dx2, c0, c1, COEFFS[4]); - ////////////////////////////////////////////////////////////////////////////// - - // s = e_x - log2(r) + dx * P(dx) - // Approximation errors: - // |log2(x) - s| < ulp(e_x) + (bounds on dx) * (error bounds of P(dx)) - // = ulp(e_x) + 2^-7 * 2^-51 - // < 2^8 * 2^-52 + 2^-7 * 2^-43 - // ~ 2^-44 + 2^-50 - double s = fputil::multiply_add(dx, p, LOG2_R[idx_x] + e_x); - - // To compute 2^(y * log2(x)), we break the exponent into 3 parts: - // y * log(2) = hi + mid + lo, where - // hi is an integer - // mid * 2^6 is an integer - // |lo| <= 2^-7 - // Then: - // x^y = 2^(y * log2(x)) = 2^hi * 2^mid * 2^lo, - // In which 2^mid is obtained from a look-up table of size 2^6 = 64 elements, - // and 2^lo ~ 1 + lo * P(lo). - // Thus, we have: - // hi + mid = 2^-6 * round( 2^6 * y * log2(x) ) - // If we restrict the output such that |hi| < 150, (hi + mid) uses (8 + 6) - // bits, hence, if we use double precision to perform - // round( 2^6 * y * log2(x)) - // the lo part is bounded by 2^-7 + 2^(-(52 - 14)) = 2^-7 + 2^-38 - - // In the following computations: - // y6 = 2^6 * y - // hm = 2^6 * (hi + mid) = round(2^6 * y * log2(x)) ~ round(y6 * s) - // lo6 = 2^6 * lo = 2^6 * (y - (hi + mid)) = y6 * log2(x) - hm. - double y6 = static_cast<double>(y * 0x1.0p6f); // Exact. - double hm = fputil::nearest_integer(s * y6); -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // lo6 = 2^6 * lo. - double lo6_hi = - fputil::multiply_add(y6, e_x + LOG2_R_DD[idx_x].hi, -hm); // Exact - // Error bounds: - // | (y*log2(x) - hm * 2^-6 - lo) / y| < err(dx * p) + err(LOG2_R_DD.lo) - // < 2^-51 + 2^-75 - double lo6 = fputil::multiply_add( - y6, fputil::multiply_add(dx, p, LOG2_R_DD[idx_x].lo), lo6_hi); -#else - // lo6 = 2^6 * lo. - double lo6_hi = - fputil::multiply_add(y6, e_x + LOG2_R_TD[idx_x].hi, -hm); // Exact - // Error bounds: - // | (y*log2(x) - hm * 2^-6 - lo) / y| < err(dx * p) + err(LOG2_R_DD.lo) - // < 2^-51 + 2^-75 - double lo6 = fputil::multiply_add( - y6, fputil::multiply_add(dx, p, LOG2_R_TD[idx_x].mid), lo6_hi); -#endif - - // |2^(hi + mid) - exp2_hi_mid| <= ulp(exp2_hi_mid) / 2 - // Clamp the exponent part into smaller range that fits double precision. - // For those exponents that are out of range, the final conversion will round - // them correctly to inf/max float or 0/min float accordingly. - int64_t hm_i = - cpp::clamp<int64_t>(static_cast<int64_t>(hm), -(1 << 15), 1 << 15); - - int idx_y = hm_i & 0x3f; - - // 2^hi - int64_t exp_hi_i = (hm_i >> 6) << DoubleBits::FRACTION_LEN; - // 2^mid - int64_t exp_mid_i = cpp::bit_cast<uint64_t>(EXP2_MID1[idx_y].hi); - // (-1)^sign * 2^hi * 2^mid - // Error <= 2^hi * 2^-53 - uint64_t exp2_hi_mid_i = static_cast<uint64_t>(exp_hi_i + exp_mid_i) + sign; - double exp2_hi_mid = cpp::bit_cast<double>(exp2_hi_mid_i); - - // Degree-5 polynomial approximation P(lo6) ~ 2^(lo6 / 2^6) = 2^(lo). - // Generated by Sollya with: - // > P = fpminimax(2^(x/64), 5, [|1, D...|], [-2^-1, 2^-1]); - // > dirtyinfnorm(2^(x/64) - P, [-0.5, 0.5]); - // 0x1.a2b77e618f5c4c176fd11b7659016cde5de83cb72p-60 - constexpr double EXP2_COEFFS[] = {0x1p0, - 0x1.62e42fefa39efp-7, - 0x1.ebfbdff82a23ap-15, - 0x1.c6b08d7076268p-23, - 0x1.3b2ad33f8b48bp-31, - 0x1.5d870c4d84445p-40}; - - double lo6_sqr = lo6 * lo6; - double d0 = fputil::multiply_add(lo6, EXP2_COEFFS[1], EXP2_COEFFS[0]); - double d1 = fputil::multiply_add(lo6, EXP2_COEFFS[3], EXP2_COEFFS[2]); - double d2 = fputil::multiply_add(lo6, EXP2_COEFFS[5], EXP2_COEFFS[4]); - double pp = fputil::polyeval(lo6_sqr, d0, d1, d2); - - double r = pp * exp2_hi_mid; - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - return static_cast<float>(r); -#else - // Ziv accuracy test. - uint64_t r_u = cpp::bit_cast<uint64_t>(r); - float r_upper = static_cast<float>(cpp::bit_cast<double>(r_u + ERR)); - float r_lower = static_cast<float>(cpp::bit_cast<double>(r_u - ERR)); - - if (LIBC_LIKELY(r_upper == r_lower)) { - // Check for overflow or underflow. - if (LIBC_UNLIKELY(FloatBits(r_upper).get_mantissa() == 0)) { - if (FloatBits(r_upper).is_inf()) { - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW); - } else if (r_upper == 0.0f) { - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_UNDERFLOW); - } - } - return r_upper; - } - - // Scale lower part of 2^(hi + mid) - DoubleDouble exp2_hi_mid_dd; - exp2_hi_mid_dd.lo = - (idx_y != 0) - ? cpp::bit_cast<double>(exp_hi_i + - cpp::bit_cast<int64_t>(EXP2_MID1[idx_y].mid)) - : 0.0; - exp2_hi_mid_dd.hi = exp2_hi_mid; - - double r_dd = powf_double_double(idx_x, dx, y6, lo6_hi, exp2_hi_mid_dd); - - return static_cast<float>(r_dd); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS && LIBC_MATH_HAS_SMALL_TABLES -} +using LIBC_MATH_POWF_IMPL::powf; } // namespace math } // namespace LIBC_NAMESPACE_DECL +#undef LIBC_MATH_POWF_IMPL + #endif // LLVM_LIBC_SRC___SUPPORT_MATH_POWF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_double_eval.h new file mode 100644 index 000000000000..3f78041f9dea --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_double_eval.h @@ -0,0 +1,558 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Double-precision evaluation implementation for powf(x, y). +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_DOUBLE_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_DOUBLE_EVAL_H + +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/optional.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" +#include "src/__support/math/common_constants.h" +#include "src/__support/math/exp_constants.h" +#include "src/__support/math/powf_utils.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace double_eval { + +namespace powf_internal = LIBC_NAMESPACE::math::powf_internal; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// Accurate evaluation in DoubleDouble precision when Ziv's test fails. +LIBC_INLINE double powf_accurate(float x, float y, double e_x, uint64_t sign) { + using FloatBits = fputil::FPBits<float>; + using DoubleBits = fputil::FPBits<double>; + using fputil::DoubleDouble; + + uint32_t x_u = FloatBits(x).uintval(); + uint32_t x_mant = x_u & FloatBits::FRACTION_MASK; + int idx_x = static_cast<int>(x_mant >> (FloatBits::FRACTION_LEN - 7)); + // Append hidden bit. + float m_x = cpp::bit_cast<float>(x_mant | 0x3f80'0000); + double dx = fputil::multiply_add( + static_cast<double>(m_x), + static_cast<double>(common_constants_internal::R[idx_x]), -1.0); + + // Degree-11 minimax polynomial for log2(1 + x)/x on [-2^-8, 2^-7] in + // double-double, generated by Sollya with: + // > display = hexadecimal; + // > prec = 256; + // > P = fpminimax(log2(1 + x)/x, 11, [|DD...|], [-2^(-8), 2^(-7)]); + // > for i from 0 to 11 do { + // c = coeff(P, i); + // hi = round(c, D, RN); + // lo = round(c - hi, D, RN); + // print("{", lo, ", ", hi, "},"); + // }; + // > dirtyinfnorm((log2(1 + x) - x * P) / x, [-2^(-8), 2^(-7)]); + // 0x1.c598...p-104 < 2^-103. + constexpr DoubleDouble LOG2_COEFFS[] = { + {0x1.777d0ffda0d34p-56, 0x1.71547652b82fep0}, + {-0x1.777d0ffd88ca8p-57, -0x1.71547652b82fep-1}, + {0x1.d27f052d9d41dp-56, 0x1.ec709dc3a03fdp-2}, + {-0x1.777f259c6c0ap-58, -0x1.71547652b82fep-2}, + {0x1.e5c055599afdbp-56, 0x1.2776c50ef9bfep-2}, + {0x1.e923056eef156p-58, -0x1.ec709dc3a03fdp-3}, + {0x1.1f24e26b5ad0dp-57, 0x1.a61762a7add76p-3}, + {0x1.16d9b5013b55ep-58, -0x1.71547652bf304p-3}, + {-0x1.1551148c3d1d8p-57, 0x1.484b13f00425ep-3}, + {-0x1.a1cf327c6703p-60, -0x1.2776ca937f335p-3}, + {-0x1.d24f6254c2e6ap-57, 0x1.0c9211efe6d7ep-3}, + {0x1.a81cff2946d7cp-59, -0x1.e1f45baaf7f1dp-4}, + }; + + // Evaluate P(dx) ~ log2(1 + dx) / dx using Horner's scheme. + DoubleDouble p = LOG2_COEFFS[11]; + for (int i = 10; i >= 0; --i) + p = fputil::add(LOG2_COEFFS[i], fputil::quick_mult(dx, p)); + + // log2(1 + dx) = dx * P(dx) in DoubleDouble. + DoubleDouble log2_1p = fputil::quick_mult(dx, p); + + // -log2(r) is represented in TripleDouble as {lo, mid, hi}. + // We decompose log2(x) = e_x - log2(r) + log2(1 + dx) into: + // log2(x) = (e_x + hi) + (log2_1p + mid + lo) + // = (e_x + hi) + log2_tail. + // The lower part log2_tail accumulates log2_1p, mid, and lo in DoubleDouble: + DoubleDouble log2_tail = + fputil::add<false>(log2_1p, powf_internal::LOG2_R_TD[idx_x].mid); + log2_tail = fputil::add<false>(log2_tail, powf_internal::LOG2_R_TD[idx_x].lo); + + // Range reduction for 2^(y * log2(x)): + // Scale by 2^6 = 64 to use the 64-entry EXP2_MID1 table: + // 64 * y * log2(x) = y6 * (e_x + hi) + y6 * log2_tail. + // + // Since e_x + hi has at most 8 + 20 = 28 bits of precision and y has 24 bits, + // the product y6 * (e_x + hi) has at most 28 + 24 = 52 bits, making y6_hi + // exact in double precision. + constexpr double SCALE = 0x1.0p6; + double y6 = static_cast<double>(y) * SCALE; + DoubleDouble prod = fputil::quick_mult(y6, log2_tail); + + double e_x_hi = e_x + powf_internal::LOG2_R_TD[idx_x].hi; + DoubleDouble y6_hi = fputil::exact_mult(y6, e_x_hi); + + // hm = round(64 * y * log2(x)) is the nearest integer index. + double hm_d = y6_hi.hi + prod.hi; + double hm = fputil::nearest_integer(hm_d); + + // lo6 = 64 * y * log2(x) - hm = (y6_hi - hm) + prod: + DoubleDouble lo6_hi = fputil::exact_add<false>(y6_hi.hi, -hm); + lo6_hi.lo += y6_hi.lo; + + DoubleDouble lo6 = fputil::add<false>(prod, lo6_hi); + + // lo = lo6 / 64, with |lo| <= 2^-7. + DoubleDouble lo = fputil::quick_mult(0x1.0p-6, lo6); + + int64_t hm_i = static_cast<int64_t>(hm); + int idx_y = static_cast<int>(hm_i & 0x3f); + int hi = static_cast<int>(hm_i >> 6); + int64_t exp_hi_i = static_cast<int64_t>(static_cast<uint64_t>(hi) + << DoubleBits::FRACTION_LEN); + + // Degree-8 minimax polynomial for (2^x - 1)/x on [-2^-7, 2^-7] in + // double-double, generated by Sollya with: + // > display = hexadecimal; + // > prec = 256; + // > P = fpminimax((2^x - 1)/x, 8, [|DD...|], [-2^(-7), 2^(-7)]); + // > for i from 0 to 8 do { + // c = coeff(P, i); + // hi = round(c, D, RN); + // lo = round(c - hi, D, RN); + // print("{", lo, ", ", hi, "},"); + // }; + // > dirtyinfnorm((2^x - (1 + x * P)) / (2^x), [-2^(-7), 2^(-7)]); + // 0x1.e62d...p-106 < 2^-105. + constexpr DoubleDouble EXP2_COEFFS_DD[] = { + {0x1.abc9e3b39803ep-56, 0x1.62e42fefa39efp-1}, + {-0x1.5e43a54066432p-57, 0x1.ebfbdff82c58fp-3}, + {-0x1.d331626e9fe04p-59, 0x1.c6b08d704a0cp-5}, + {0x1.4f492022eeb74p-62, 0x1.3b2ab6fba4e77p-7}, + {0x1.035733b00abdp-66, 0x1.5d87fe78a6731p-10}, + {0x1.9e4f81ec951dep-68, 0x1.430912f86c123p-13}, + {0x1.7be627c299948p-74, 0x1.ffcbfc588b997p-17}, + {-0x1.c8a006d5b39acp-74, 0x1.62c03345a64f6p-20}, + {-0x1.fd14495e4b96p-81, 0x1.b5253eef8c0a9p-24}, + }; + + DoubleDouble exp2_p = EXP2_COEFFS_DD[8]; + for (int i = 7; i >= 0; --i) + exp2_p = fputil::add(EXP2_COEFFS_DD[i], fputil::quick_mult(lo, exp2_p)); + + DoubleDouble p_lo = fputil::quick_mult(lo, exp2_p); + DoubleDouble exp2_lo = fputil::exact_add(1.0, p_lo.hi); + exp2_lo.lo += p_lo.lo; + + DoubleDouble exp2_hi_mid_dd; + exp2_hi_mid_dd.hi = cpp::bit_cast<double>( + exp_hi_i + cpp::bit_cast<int64_t>(EXP2_MID1[idx_y].hi) + sign); + exp2_hi_mid_dd.lo = + (idx_y != 0) + ? cpp::bit_cast<double>( + exp_hi_i + cpp::bit_cast<int64_t>(EXP2_MID1[idx_y].mid) + sign) + : 0.0; + + DoubleDouble rr = fputil::quick_mult(exp2_hi_mid_dd, exp2_lo); + + DoubleDouble r = fputil::exact_add(rr.hi, rr.lo); + + // Round to odd to avoid double rounding when converting to float. + uint64_t r_bits = cpp::bit_cast<uint64_t>(r.hi); + if (LIBC_UNLIKELY(((r_bits & 0x0fff'ffffULL) == 0) && (r.lo != 0.0))) { + if (DoubleBits(r.hi).sign() == DoubleBits(r.lo).sign()) { + ++r_bits; + } else if ((r_bits & DoubleBits::FRACTION_MASK) > 0) { + --r_bits; + } + } + + return cpp::bit_cast<double>(r_bits); +} +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +#if !defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ + !defined(LIBC_MATH_HAS_SMALL_TABLES) +// Check if x^y is an exact rounding boundary. +// When x^y = exact_m * 2^exact_exp with exact_m <= 2^25: +// - exact_m has at most 26 bits, so it fits in double precision without +// rounding. +// - For single precision, exact_exp is in [-200, 127], well within the normal +// range [-1022, 1023] of double precision. +// We compute exact_d = exact_m * 2^exact_exp in double precision and cast to +// float for the final rounded result. +LIBC_INLINE cpp::optional<float> +check_exact_boundary(float x, float y, uint64_t sign, + Sign out_sign = Sign::POS) { + uint32_t exact_m = 0; + int exact_exp = 0; + if (LIBC_UNLIKELY(powf_internal::is_exact_rounding_boundary(x, y, exact_m, + exact_exp))) { + // Number of bits in exact_m: 2^(l - 1) <= exact_m < 2^l. + int l = 32 - cpp::countl_zero(exact_m); + // Unbiased exponent of exact_m * 2^exact_exp. + int unbiased_exp = exact_exp + l - 1; + + if (LIBC_UNLIKELY(unbiased_exp > 127)) + return powf_internal::set_overflow(out_sign); + + // Below the minimum subnormal float (2^-149). + if (LIBC_UNLIKELY(unbiased_exp < -149)) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); + } + + // Scale factor = sign * 2^exact_exp. + using DoubleBits = fputil::FPBits<double>; + double scale = cpp::bit_cast<double>( + (static_cast<uint64_t>(exact_exp + DoubleBits::EXP_BIAS) + << DoubleBits::FRACTION_LEN) | + sign); + double exact_d = static_cast<double>(exact_m) * scale; + return static_cast<float>(exact_d); + } + return cpp::nullopt; +} +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS && !LIBC_MATH_HAS_SMALL_TABLES + +// Overview of powf(x, y) = x^y computation in double precision: +// +// Let x = 2^(e_x) * m_x > 0. Then: +// x^y = 2^( y * log2(x) ) +// = 2^( y * ( e_x + log2(m_x) ) ) +// = 2^( k + f ) +// = 2^k * 2^f, +// where: +// k = round(y * log2(x)), +// f = y * log2(x) - k. +// +// In particular, k is an integer, and |f| <= 0.5. +// For the final result to fit in single precision: +// -150 <= y * log2(x) <= 128, +// and anything outside that range overflows or underflows. +// +// Fast pass: +// 1. Range reduction for log2(m_x) using a 32-entry lookup table: +// dx = r * m_x - 1 in [-2^-6, 2^-5], +// log2(m_x) = log2(1 + dx) - log2(r), +// where -log2(r) is retrieved from LOG2_R_32[idx_x], and log2(1 + dx)/dx is +// approximated by a degree-6 polynomial in double precision with Estrin's +// scheme. +// 2. Exponent reduction: +// z = y * log2(x), +// k = round(z), +// f = z - k in [-0.5, 0.5]. +// 3. 2^f is evaluated using a degree-7 polynomial. +// Absorbing +-ERR into the constant term 1.0 +- ERR of the final FMA allows +// computing the upper and lower bounds for Ziv's rounding test in parallel. +// 4. If upper == lower in single precision, return upper. +// 5. If Ziv's test fails, fall back to check_exact_boundary and powf_accurate +// (DoubleDouble / 128-entry table). +// +// Accurate pass: +// 1. Range reduction using a 128-entry table: -log2(r) = {lo, mid, hi}. +// log2(1 + dx) is evaluated using a degree-11 polynomial in DoubleDouble. +// 2. Decompose: log2(x) = (e_x + hi) + log2_tail, where: +// log2_tail = log2(1 + dx) + mid + lo. +// Because e_x + hi has <= 28 bits of precision and y has 24 bits, +// y * (e_x + hi) is exact in double precision. +// 3. Exponent reduction with 64-entry EXP2_MID1 table and degree-8 polynomial +// in DoubleDouble. +LIBC_INLINE float powf(float x, float y) { + using FloatBits = fputil::FPBits<float>; + using DoubleBits = fputil::FPBits<double>; + using fputil::DoubleDouble; + using namespace common_constants_internal; + + FloatBits xbits(x), ybits(y); + uint32_t x_u = xbits.uintval(); + uint32_t y_u = ybits.uintval(); + uint32_t y_a = ybits.abs().uintval(); + + // Quick filter for special inputs: + // - x: 0, +-1, 2^k, +-Inf, NaN. + // - y: 0, +-1, +-2, +-0.5, +-Inf, NaN. + if (LIBC_UNLIKELY((x_u & 0x001F'FFFF) == 0 || (y_u & 0x007F'FFFF) == 0)) { + if (auto r = powf_internal::check_special_inputs(x, y); + LIBC_UNLIKELY(r.has_value())) + return r.value(); + } + +#if !defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ + !defined(LIBC_MATH_HAS_SMALL_TABLES) + float orig_x_abs = xbits.abs().get_val(); + float orig_y = y; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS && !LIBC_MATH_HAS_SMALL_TABLES + + int ex = -FloatBits::EXP_BIAS; + uint64_t sign = 0; + + // Check for exceptional cases: + // - |y| <= 2^-40 or |y| >= 2^40. + // - x < 0, x is subnormal, zero, Inf, or NaN. + if (LIBC_UNLIKELY(y_a <= powf_internal::Y_LOWER_BOUND || + y_a >= powf_internal::Y_UPPER_BOUND || + x_u >= FloatBits::inf().uintval() || + x_u < FloatBits::min_normal().uintval())) { + if (auto r = powf_internal::check_exceptional_cases(x, y, ex, sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); + } + + Sign out_sign = (sign == 0) ? Sign::POS : Sign::NEG; + + // x^y = 2^( y * log2(x) ) = 2^( y * ( e_x + log2(m_x) ) ) + // Compute log2(x) = e_x + log2(m_x) + x_u = FloatBits(x).uintval(); + + // Extract exponent field of x. + ex += (x_u >> FloatBits::FRACTION_LEN); + double e_x = static_cast<double>(ex); + uint32_t x_mant = x_u & FloatBits::FRACTION_MASK; + // Top 5 bits of mantissa for 32-entry table lookup. + int idx_x = static_cast<int>(x_mant >> (FloatBits::FRACTION_LEN - 5)); + // Embed mantissa into double format: m_x in [1.0, 2.0). + uint64_t m_x_u = + (static_cast<uint64_t>(x_mant) << 29) | 0x3ff0'0000'0000'0000ULL; + double m_x = cpp::bit_cast<double>(m_x_u); + + // Range reduction: dx = m_x * r - 1.0 in [-2^-6, 2^-5]. + // Since r has <= 7 bits and m_x has 24 bits, m_x * r - 1.0 is exact in + // double. + double dx = + fputil::multiply_add(m_x, powf_internal::R_32_D[idx_x], -1.0); // Exact + + // Degree-6 minimax polynomial approximation for log2(1 + dx)/dx on + // [-2^-6, 2^-5]. Generated by Sollya with: + // > display = hexadecimal; + // > p6 = fpminimax(log2(1 + x)/x, 6, [|D...|], [-2^-6, 2^-5]); + // > for i from 0 to 6 do print(round(coeff(p6, i), D, RN), ","); + // > dirtyinfnorm((log2(1 + x) - x * p6) / log2(1 + x), [-2^-6, 2^-5]); + // 0x1.050a...p-47 + // > dirtyinfnorm(log2(1 + x) - x * p6, [-2^-6, 2^-5]); + // 0x1.712b...p-52 + constexpr double COEFFS[] = { + 0x1.71547652b831fp0, -0x1.71547652b2ff5p-1, 0x1.ec709dbd02463p-2, + -0x1.7154787f73adep-2, 0x1.2777b7f57b29fp-2, -0x1.ec55ea50eaba7p-3, + 0x1.92c78e7d5a931p-3, + }; + + // Evaluate P(dx) ~ log2(1 + dx)/dx with Estrin's scheme: + double dx2 = dx * dx; + double lp0 = fputil::multiply_add(dx, COEFFS[1], COEFFS[0]); + double lp1 = fputil::multiply_add(dx, COEFFS[3], COEFFS[2]); + double lp2 = fputil::multiply_add(dx, COEFFS[5], COEFFS[4]); + + double dx4 = dx2 * dx2; + double lq0 = fputil::multiply_add(dx2, lp1, lp0); + double lq1 = fputil::multiply_add(dx2, COEFFS[6], lp2); + + double p = fputil::multiply_add(dx4, lq1, lq0); + + // log2(x) = e_x - log2(r) + dx * P(dx). + double log2_r_ex = powf_internal::LOG2_R_32[idx_x] + e_x; + double s = fputil::multiply_add(dx, p, log2_r_ex); + + double y_d = static_cast<double>(y); + double z = y_d * s; + + // y * log2(x) = k + f, with k integer and |f| <= 0.5. + double kd = fputil::nearest_integer(z); + int64_t k = static_cast<int64_t>(kd); + double f = fputil::multiply_add(y_d, s, -kd); + + // Degree-7 polynomial approximation P(f) ~ (2^f - 1)/f on [-0.5, 0.5] + // Generated by Sollya with: + // > display = hexadecimal; + // > p = fpminimax((2^x - 1)/x, 7, [|D...|], [-0.5, 0.5]); + // > for i from 0 to 7 do print(round(coeff(p, i), D, RN), ","); + // > dirtyinfnorm(2^x - (1 + x * p), [-0.5, 0.5]); + // 0x1.0496...p-39 + // > dirtyinfnorm((2^x - (1 + x * p)) / 2^x, [-0.5, 0.5]); + // 0x1.0496...p-39 + constexpr double EXP2_COEFFS[] = { + 0x1.62e42fef9cdf7p-1, 0x1.ebfbdff85f49p-3, 0x1.c6b08da69c963p-5, + 0x1.3b2ab6a0e1172p-7, 0x1.5d87762dfc134p-10, 0x1.43099b4e829a9p-13, + 0x1.00c080f7699bep-16, 0x1.62c0108a065d8p-20, + }; + + // Evaluate P(f) ~ (2^f - 1)/f on [-0.5, 0.5] with Estrin's scheme: + double f2 = f * f; + double f4 = f2 * f2; + + double p0 = fputil::multiply_add(f, EXP2_COEFFS[1], EXP2_COEFFS[0]); + double p1 = fputil::multiply_add(f, EXP2_COEFFS[3], EXP2_COEFFS[2]); + double p2 = fputil::multiply_add(f, EXP2_COEFFS[5], EXP2_COEFFS[4]); + double p3 = fputil::multiply_add(f, EXP2_COEFFS[7], EXP2_COEFFS[6]); + + double q0 = fputil::multiply_add(f2, p1, p0); + double q1 = fputil::multiply_add(f2, p3, p2); + + double poly = fputil::multiply_add(f4, q1, q0); + + // Normal range: -125 <= k <= 128. + // (k + 125) as unsigned <= 253 covers all normal outputs. + uint64_t k_u = static_cast<uint64_t>(k + 125); + + if (LIBC_LIKELY(k_u <= 253)) { + // Scale by 2^k. + uint64_t exp2_k_i = + (static_cast<uint64_t>(static_cast<int>(k) + DoubleBits::EXP_BIAS) + << DoubleBits::FRACTION_LEN) | + sign; + double exp2_k = cpp::bit_cast<double>(exp2_k_i); + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + double pp = fputil::multiply_add(f, poly, 1.0); + double r_d = pp * exp2_k; + return static_cast<float>(r_d); +#else // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#ifdef LIBC_TARGET_CPU_HAS_FMA + // Absorbing +-ERR into 1.0 computes both bounds using two parallel FMAs. + constexpr double ERR = 0x1.5p-39; + double pp_hi = fputil::multiply_add(f, poly, 1.0 + ERR); + double pp_lo = fputil::multiply_add(f, poly, 1.0 - ERR); + double r_d = pp_hi * exp2_k; +#else // !LIBC_TARGET_CPU_HAS_FMA + // Without FMA, compute unbiased pp = f * poly + 1.0 directly. + double pp = fputil::multiply_add(f, poly, 1.0); + double r_d = pp * exp2_k; +#endif // LIBC_TARGET_CPU_HAS_FMA + + float res = static_cast<float>(r_d); + + // Since 2^k is an exact power of 2, testing if the bounds round to the same + // float is equivalent to testing the fully scaled bounds. +#ifdef LIBC_TARGET_CPU_HAS_FMA + float upper = static_cast<float>(pp_hi); + float lower = static_cast<float>(pp_lo); +#else // !LIBC_TARGET_CPU_HAS_FMA + constexpr double ERR = 0x1.5p-39; + float upper = static_cast<float>(pp + ERR); + float lower = static_cast<float>(pp - ERR); +#endif // LIBC_TARGET_CPU_HAS_FMA + + if (LIBC_LIKELY(upper == lower)) + return res; + + // Accurate fallback when Ziv's test fails: +#ifndef LIBC_MATH_HAS_SMALL_TABLES + if (auto r = check_exact_boundary(orig_x_abs, orig_y, sign, out_sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SMALL_TABLES + + double r_dd = powf_accurate(x, y, e_x, sign); + res = static_cast<float>(r_dd); + if (LIBC_UNLIKELY(FloatBits(res).is_inf())) + return powf_internal::set_overflow(out_sign); + return res; +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Exceptional path: k > 128 (overflow), k < -155 (underflow), or denormal. + if (k > 128) + return powf_internal::set_overflow(out_sign); + + if (k < -155) + return powf_internal::set_underflow(out_sign); + + // Denormal and underflow path for -155 <= k <= -126: +#ifndef LIBC_MATH_HAS_SMALL_TABLES + if (auto r = check_exact_boundary(orig_x_abs, orig_y, sign, out_sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SMALL_TABLES + + int64_t exp2_k_i = (static_cast<uint64_t>(k + DoubleBits::EXP_BIAS) + << DoubleBits::FRACTION_LEN) | + sign; + double exp2_k = cpp::bit_cast<double>(exp2_k_i); + + // Add +-2^(-126 + (53 - 24)) = +-2^-97 to mimic single precision denormal + // rounding in double precision. + // For -155 <= k <= -126, the least significant bit of the double precision + // sum (r_d + denorm_bias) is aligned at 2^(-97 - 52) = 2^-149, matching the + // least significant bit of single precision denormals 2^(-126 - 23) = 2^-149. + // This keeps the values in the double precision normal range while performing + // rounding according to the current rounding mode. + double denorm_bias = cpp::bit_cast<double>(0x39e0'0000'0000'0000ULL | sign); + + constexpr double ERR = 0x1.5p-39; + +#ifdef LIBC_TARGET_CPU_HAS_FMA + // Absorbing +-ERR into 1.0 computes both bounds using two parallel FMAs. + double pp_hi = fputil::multiply_add(f, poly, 1.0 + ERR); + double pp_lo = fputil::multiply_add(f, poly, 1.0 - ERR); + double u_hi = fputil::multiply_add(pp_hi, exp2_k, denorm_bias); + double u_lo = fputil::multiply_add(pp_lo, exp2_k, denorm_bias); +#else // !LIBC_TARGET_CPU_HAS_FMA + // Without FMA, compute unbiased pp = f * poly + 1.0 directly. + double pp = fputil::multiply_add(f, poly, 1.0); + double r_d = pp * exp2_k; + double err = ERR * r_d; + double u_hi = (r_d + err) + denorm_bias; + double u_lo = (r_d - err) + denorm_bias; +#endif // LIBC_TARGET_CPU_HAS_FMA + + if (LIBC_LIKELY(u_hi == u_lo)) { + if (LIBC_UNLIKELY(u_hi == denorm_bias)) + return powf_internal::set_underflow(out_sign); + + float res = static_cast<float>(u_hi - denorm_bias); + if (LIBC_UNLIKELY(FloatBits(res).is_normal())) { +#ifdef LIBC_TARGET_CPU_HAS_FMA + double pp = fputil::multiply_add(f, poly, 1.0); +#endif // LIBC_TARGET_CPU_HAS_FMA + if (static_cast<float>(pp) < 1.0f) + fputil::raise_underflow_except_if_required<float>(); + return res; + } + + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); + return res; + } + + // Ziv's test failed for denormal input, fall back to accurate pass. + double r_dd = powf_accurate(x, y, e_x, sign); + float res = static_cast<float>(r_dd); + if (LIBC_UNLIKELY(FloatBits(res).is_normal())) { + if (static_cast<float>(r_dd * 0x1.0p126) < 1.0f) + fputil::raise_underflow_except_if_required<float>(); + return res; + } + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); + return res; +#else // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (k > 128) + return powf_internal::set_overflow(out_sign); + return powf_internal::set_underflow(out_sign); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace double_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_POWF_DOUBLE_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_float_eval.h new file mode 100644 index 000000000000..ae36b787c5a8 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_float_eval.h @@ -0,0 +1,236 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Float-only evaluation implementation for powf(x, y). +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_FLOAT_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_FLOAT_EVAL_H + +#include "src/__support/CPP/bit.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" +#include "src/__support/math/exp2f_float_utils.h" +#include "src/__support/math/powf_utils.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace float_eval { + +namespace powf_internal = LIBC_NAMESPACE::math::powf_internal; + +// Overview of float-precision pow(x, y) = x^y computation: +// +// Let x = 2^(e_x) * m_x > 0. Then: +// x^y = 2^( y * log2(x) ) +// = 2^( y * ( e_x + log2(m_x) ) ) +// = 2^( k + rem ) +// = 2^k * 2^rem, +// where: +// k = round(y * log2(x)), +// rem = y * log2(x) - k. +// +// In particular, k is an integer, and |rem| <= 0.5. +// +// For the final result to fit in single precision, the exponent field is +// bounded by: +// -150 <= y * log2(x) <= 128, +// and anything outside that range overflows or underflows. +// +// Since |rem| <= 0.5: +// 2^-0.5 <= 2^rem <= 2^0.5, +// the relative error of x^y = 2^k * 2^rem is approximately: +// ~ absolute error of rem * ln(2) +// ~ absolute error of y * log2(x) * ln(2) + rel_err(exp2f_eval) +// ~ relative error(log2(x)) * |y * log2(x)| * ln(2) + 2^-25. +// +// With exp2f_eval providing error ~ 2^-25, the budget for +// relative error(log2(x)) * |y * log2(x)| * ln(2) is <= 2^-25. +// For single-precision results, the 8-bit exponent field bounds: +// |y * log2(x)| < 2^8 = 256. +// Thus: +// relative error(log2(x)) <= 2^-25 / (2^8 * ln(2)) < 2^-33. +// +// To compute log2(x), we perform range reduction for log2(m_x) using a compact +// 4-bit lookup table (16 entries): +// dx = r * m_x - 1 in [-2^-5, 2^-4]. +// Then m_x = (1 + dx) / r, and: +// log2(m_x) = log2(1 + dx) - log2(r), +// where -log2(r) is obtained from the lookup table LOG2_R_FF_16 with +// FloatFloat precision (~48 bits). The computation of dx = r * m_x - 1 is +// exact. +// +// The expansion of log2(1 + dx) is: +// log2(1 + dx) = dx * log2(e) + dx^2 * Q(dx). +// +// We compute only the leading term dx * log2(e) in FloatFloat using +// exact_mult, and evaluate the tail Q(dx) using a degree-4 minimax polynomial +// purely in single precision: +// Q(dx) ~ (log2(1 + dx) - dx * log2(e)) / dx^2. +// Generated by Sollya with: +// > log2_e = 0x1.715476p0 + 0x1.4ae0cp-26; +// > f = (log2(1 + x) - x * log2_e) / x^2; +// > Q = fpminimax(f, 4, [|SG...|], [-2^-5, 2^-4]); +// > dirtyinfnorm(((log2(1 + x) - x * log2_e) - x^2 * Q) / x, [-2^-5, 2^-4]); +// 0x1.692c...p-34 +// +// Finally, we compute the product y * log2(x) in FloatFloat: +// y * log2(x) = y * ((e_x - log2(r)) + log2(1 + dx)). +// When x in [1 - 2^-4, 1) (where e_x = -1 and R[15] = 0.5 so +// -log2(R[15]) = 1.0f), e_x - log2(r) cancels to 0, avoiding cancellation. +// We decompose into integer k and fractional remainder rem: +// k = round(total_hi), +// rem = (total_hi - k) + total_lo, +// and evaluate 2^k * 2^rem via exp2f_eval(rem, k) from exp2f_float_utils.h, +// which provides a compact, code-size-friendly implementation without large +// exponent lookup tables. + +LIBC_INLINE float powf(float x, float y) { + using FPBits = fputil::FPBits<float>; + using namespace powf_internal; + + FPBits xbits(x), ybits(y); + uint32_t x_u = xbits.uintval(); + uint32_t y_a = ybits.abs().uintval(); + + int e_x = 0; + uint32_t sign = 0; + if (LIBC_UNLIKELY(y_a <= powf_internal::Y_LOWER_BOUND || + y_a >= powf_internal::Y_UPPER_BOUND || + x_u >= FPBits::inf().uintval() || + x_u < FPBits::min_normal().uintval())) { + if (auto r = powf_internal::check_exceptional_cases(x, y, e_x, sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); + } + + Sign out_sign = (sign == 0) ? Sign::POS : Sign::NEG; + + // Extract exponent field and mantissa of x. + xbits = FPBits(x); + e_x += xbits.get_biased_exponent() - FPBits::EXP_BIAS; + uint32_t x_mant = xbits.get_mantissa(); + unsigned idx_x = static_cast<unsigned>(x_mant >> (FPBits::FRACTION_LEN - 4)); + FPBits m_x = FPBits(x_mant | 0x3f80'0000U); + + // log2(e) in FloatFloat: + constexpr fputil::FloatFloat LOG2_E = {0x1.4ae0cp-26f, 0x1.715476p0f}; + + // Degree-4 Sollya minimax polynomial for: + // Q(dx) ~ (log2(1 + dx) - dx * log2(e)) / dx^2 + // Generated by Sollya with: + // > log2_e = 0x1.715476p0 + 0x1.4ae0cp-26; + // > f = (log2(1 + x) - x * log2_e) / x^2; + // > Q = fpminimax(f, 4, [|SG...|], [-2^-5, 2^-4]); + // > dirtyinfnorm(((log2(1 + x) - x * log2_e) - x^2 * Q) / x, [-2^-5, 2^-4]); + // 0x1.692c...p-34 + constexpr float COEFFS[] = {-0x1.715476p-1f, 0x1.ec70ap-2f, -0x1.715b5p-2f, + 0x1.279932p-2f, -0x1.cbc178p-3f}; + + // Range reduction for log2(m_x): + // dx = r * m_x - 1 in [-2^-5, 2^-4). + // The computation is exact: m_x = (1 + dx) / r. + float r = powf_internal::R_16[idx_x]; +#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + float dx = fputil::multiply_add(r, m_x.get_val(), -1.0f); // Exact +#else // !LIBC_TARGET_CPU_HAS_FMA_FLOAT + // Without FMA, split m_x = c + cd where c retains the high 14 bits + // to perform exact multiplication: r * c - 1.0f and r * cd. + float c = FPBits(m_x.uintval() & 0x3fff'e000U).get_val(); + float cd = m_x.get_val() - c; + float dx_hi = fputil::multiply_add(r, c, -1.0f); + float dx = fputil::multiply_add(r, cd, dx_hi); // Exact +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + + fputil::FloatFloat log2_r = powf_internal::LOG2_R_FF_16[idx_x]; + float e_xf = static_cast<float>(e_x); + // (e_xf + log2_r.hi) is exact since log2_r.hi has 16 bits of precision and + // |e_x| <= 150 < 2^8. + float e_x_hi = e_xf + log2_r.hi; + + // Early overflow and underflow check: + // z = y * log2(x) ~ y * (e_x_hi + dx * log2(e)) + // With |dx| < 2^-4, |log2(1 + dx) - dx * log2(e)| <= (dx^2 / 2) * log2(e) < + // 2^-8. For |y * log2(x)| <= 128, the error |z - y * log2(x)| < 4. Hence: + // z > 132 => overflow + // z < -155 => underflow + float z = y * fputil::multiply_add(dx, LOG2_E.hi, e_x_hi); + + if (LIBC_UNLIKELY(z > 132.0f)) + return set_overflow(out_sign); + + if (LIBC_UNLIKELY(z < -155.0f)) + return set_underflow(out_sign); + + // Approximate the tail Q(dx) using Estrin's scheme: + float dx2 = dx * dx; + float dx4 = dx2 * dx2; + + float p0 = fputil::multiply_add(dx, COEFFS[1], COEFFS[0]); + float p1 = fputil::multiply_add(dx, COEFFS[3], COEFFS[2]); + + float q0 = fputil::multiply_add(dx2, p1, p0); + float p = fputil::multiply_add(dx4, COEFFS[4], q0); + float p_tail = dx2 * p; + + // Compute dx * log2(e) in FloatFloat. + fputil::FloatFloat dx_log2_e = fputil::exact_mult<float>(dx, LOG2_E.hi); + float dx_log2_e_lo = fputil::multiply_add(dx, LOG2_E.lo, dx_log2_e.lo); + + // Combine with log2(1 + dx) in FloatFloat: + fputil::FloatFloat log2_x_hi = + fputil::exact_add<false, float>(e_x_hi, dx_log2_e.hi); + float log2_x_lo = (dx_log2_e_lo + p_tail) + log2_r.lo + log2_x_hi.lo; + fputil::FloatFloat log2_x = + fputil::exact_add<false, float>(log2_x_hi.hi, log2_x_lo); + + fputil::FloatFloat s = fputil::exact_mult<float>(y, log2_x.hi); + float total_hi = s.hi; + float total_lo = fputil::multiply_add(y, log2_x.lo, s.lo); + + // Exponent reduction for 2^(total_hi + total_lo): + // k = round(total_hi) + // rem = (total_hi - k) + total_lo, with |rem| <= 0.5. + float kf = fputil::nearest_integer(total_hi); + int k = static_cast<int>(kf); + + float rem_hi = total_hi - kf; + float rem = rem_hi + total_lo; + + if (LIBC_UNLIKELY(k > 128)) + return set_overflow(out_sign); + + if (LIBC_UNLIKELY(k < -150)) + return set_underflow(out_sign); + + float result = exp2f_eval(rem, k); + if (LIBC_UNLIKELY(k == 128 && FPBits(result).is_inf())) + return set_overflow(out_sign); + + if (LIBC_UNLIKELY(k <= -126 && !FPBits(result).is_normal())) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); + } + + return cpp::bit_cast<float>(cpp::bit_cast<uint32_t>(result) | sign); +} + +} // namespace float_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_POWF_FLOAT_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_small_tables.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_small_tables.h deleted file mode 100644 index 3c5abbe9190c..000000000000 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_small_tables.h +++ /dev/null @@ -1,120 +0,0 @@ -//===-- Implementation header for powf using less memory --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_SMALL_TABLES_H -#define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_SMALL_TABLES_H - -#include "src/__support/CPP/bit.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" - -namespace LIBC_NAMESPACE_DECL { - -namespace math { - -namespace powf_internal { - -LIBC_INLINE LIBC_CONSTEXPR float powf_small_tables(float x, int ex, - uint64_t sign, float y) { - using FloatBits = fputil::FPBits<float>; - using DoubleBits = fputil::FPBits<double>; - - constexpr double ONE_OVER_SQRT2 = 0x1.6a09e667f3bcdp-1; - - // x^y = 2^( y * log2(x) ) - // = 2^( y * ( e_x + log2(m_x) ) ) - // First we compute log2(x) = e_x + log2(m_x) - uint32_t x_u = FloatBits(x).uintval(); - - double yd = static_cast<double>(y); - - // Extract exponent field of x. - ex += (x_u >> FloatBits::FRACTION_LEN); - double e_x = static_cast<double>(ex); - - // Add the hidden bit to the mantissa. - // 1 <= m_x < 2 - uint32_t x_mant = (x_u & FloatBits::FRACTION_MASK); - double m_x = static_cast<double>(cpp::bit_cast<float>(x_mant | 0x3f800000)); - // Reduce to 1 <= mx <= sqrt(2). - if (x_mant > 0x0045'04f3) { - e_x += 0.5; - m_x *= ONE_OVER_SQRT2; - } - // 0 <= dx <= sqrt(2) - 1. - double dx = m_x - 1.0; - - // Degree-13 polynomial approximation: - // dx * P(dx) ~ log2(1 + dx) - // Generated by Sollya with: - // > P = fpminimax(log2(1 + x)/x, 13, [|D...|], [0, sqrt(2) - 1]); - // > dirtyinfnorm((log2(1 + x) - x*P)/log2(1 + x), [0, sqrt(2) - 1]); - // 0x1.b2d...p-53 - constexpr double LOG2_COEFFS[] = { - 0x1.71547652b82fdp0, -0x1.71547652b7a2ap-1, 0x1.ec709dc2edfa6p-2, - -0x1.71547626a9d98p-2, 0x1.2776bf5f6f40ep-2, -0x1.ec6fbbf289ce3p-3, - 0x1.a60bf904470a7p-3, -0x1.70ef61b01fc1ep-3, 0x1.45d3270454507p-3, - -0x1.1c5fc05b06e8fp-3, 0x1.d0f57944a937fp-4, -0x1.413e22be24d32p-4, - 0x1.3c84b66491ccp-5, -0x1.3df9cfe5e602ep-7}; - - double dx2 = dx * dx; - double c0 = fputil::multiply_add(dx, LOG2_COEFFS[1], LOG2_COEFFS[0]); - double c1 = fputil::multiply_add(dx, LOG2_COEFFS[3], LOG2_COEFFS[2]); - double c2 = fputil::multiply_add(dx, LOG2_COEFFS[5], LOG2_COEFFS[4]); - double c3 = fputil::multiply_add(dx, LOG2_COEFFS[7], LOG2_COEFFS[6]); - double c4 = fputil::multiply_add(dx, LOG2_COEFFS[9], LOG2_COEFFS[8]); - double c5 = fputil::multiply_add(dx, LOG2_COEFFS[11], LOG2_COEFFS[10]); - double c6 = fputil::multiply_add(dx, LOG2_COEFFS[13], LOG2_COEFFS[12]); - - double dx4 = dx2 * dx2; - double d0 = fputil::multiply_add(dx2, c1, c0); - double d1 = fputil::multiply_add(dx2, c3, c2); - double d2 = fputil::multiply_add(dx2, c5, c4); - - double p = fputil::polyeval(dx4, d0, d1, d2, c6); - // u ~ y * log2(x). - double u = yd * fputil::multiply_add(dx, p, e_x); - - double hi = fputil::nearest_integer(u); - double lo = u - hi; - int e_hi = static_cast<int>(hi) + DoubleBits::EXP_BIAS; - double exp_hi = cpp::bit_cast<double>( - (static_cast<uint64_t>(e_hi) << DoubleBits::FRACTION_LEN) | sign); - // Degree-6 polynomial approximation P(lo6) ~ 2^(lo6 / 2^6) = 2^(lo). - // Generated by Sollya with: - // > P = fpminimax(2^x, 6, [|1, D...|], [-0.5, 0.5]); - // > dirtyinfnorm(2^x - P, [-0.5, 0.5]); - // 0x1.5f7...p-29 - constexpr double EXP2_COEFFS[] = { - 0x1.62e430c7b13a8p-1, 0x1.ebfbdd2f82f6fp-3, 0x1.c6aed4f186f34p-5, - 0x1.3b2c96c9aa336p-7, 0x1.5f4553ff53f9p-10, 0x1.4278e5fa9de78p-13}; - - double lo2 = lo * lo; - double f0 = fputil::multiply_add(lo, EXP2_COEFFS[1], EXP2_COEFFS[0]); - double f1 = fputil::multiply_add(lo, EXP2_COEFFS[3], EXP2_COEFFS[2]); - double f2 = fputil::multiply_add(lo, EXP2_COEFFS[5], EXP2_COEFFS[4]); - - double pp = fputil::polyeval(lo2, f0, f1, f2); - - double r = fputil::multiply_add(lo, pp, 1.0); - - double result = r * exp_hi; - - return static_cast<float>(result); -} - -} // namespace powf_internal -} // namespace math -} // namespace LIBC_NAMESPACE_DECL - -#endif // LLVM_LIBC_SRC___SUPPORT_MATH_POWF_SMALL_TABLES_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_utils.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_utils.h new file mode 100644 index 000000000000..dc36fbffedea --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/powf_utils.h @@ -0,0 +1,721 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Common utilities and tables for single-precision powf(x, y). +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_POWF_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_POWF_UTILS_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/optional.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/is_integer.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/FPUtil/triple_double.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" +#include "src/__support/math/common_constants.h" + +#if defined(LIBC_TARGET_CPU_HAS_FPU_FLOAT) || \ + !defined(LIBC_MATH_HAS_SMALL_TABLES) +#include "src/__support/FPUtil/sqrt.h" +#endif // LIBC_TARGET_CPU_HAS_FPU_FLOAT || !LIBC_MATH_HAS_SMALL_TABLES + +#if !defined(LIBC_MATH_HAS_SMALL_TABLES) && \ + !defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT) +#include "src/__support/math/exp10f.h" +#include "src/__support/math/exp2f.h" +#endif // !LIBC_MATH_HAS_SMALL_TABLES && + // !LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace powf_internal { + +using fputil::DoubleDouble; +using fputil::FloatFloat; +using fputil::TripleDouble; + +// Table of -log2(R[i]) represented in triple-double precision {lo, mid, hi}, +// where R[i] = 2^-8 * ceil(2^8 * (1 - 2^-8) / (1 + i * 2^-7)) for i = 0..127. +// +// The least significant bit of the high part `hi` is chosen to be >= 2^-20, +// so that the total precision of (e_x + hi) is at most 8 + 20 = 28 bits +// (since |e_x| <= 150 < 2^8 fits in 8 bits). +// Because the single-precision exponent y has 24 bits of mantissa, the product +// y * (e_x + hi) spans at most 24 + 28 = 52 bits <= 53 bits, making it exact +// in double precision. +// The mid part provides 53 bits for fast evaluation, and the lo part provides +// another 53 bits for the accurate fallback, yielding >= 127 bits of precision. +// +// Generated by Sollya with: +// > display = hexadecimal; +// > prec = 200; +// > for i from 0 to 127 do { +// if (i == 0) then { +// print("{0.0, 0.0, 0.0},"); +// } else if (i == 127) then { +// print("{0.0, 0.0, 1.0},"); +// } else { +// r = 2^(-8) * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) ); +// l = -log2(r); +// h = nearestint(l * 2^20) * 2^(-20); +// m = round(l - h, D, RN); +// lo = round(l - h - m, D, RN); +// print("{", lo, ", ", m, ", ", h, "},"); +// }; +// }; +LIBC_INLINE_VAR constexpr TripleDouble LOG2_R_TD[128] = { + {0.0, 0.0, 0.0}, + {0x1.84a2c615b70adp-79, -0x1.177c23362928cp-25, 0x1.72c8p-7}, + {-0x1.f27b820fd03eap-76, -0x1.179e0caa9c9abp-22, 0x1.744p-6}, + {-0x1.f27ef487c8f34p-77, -0x1.c6cea541f5b7p-23, 0x1.184cp-5}, + {-0x1.e3f80fbc71454p-76, -0x1.66c4d4e554434p-22, 0x1.773ap-5}, + {-0x1.9f8ef14d5f6eep-79, -0x1.70700a00fdd55p-24, 0x1.d6ecp-5}, + {0x1.452bbce7398c1p-77, 0x1.53002a4e86631p-23, 0x1.1bb3p-4}, + {-0x1.990555535afdp-81, 0x1.fcd15f101c142p-25, 0x1.4c56p-4}, + {0x1.447e30ad393eep-78, 0x1.25b3eed319cedp-22, 0x1.7d6p-4}, + {0x1.b7759da88a2dap-76, -0x1.4195120d8486fp-22, 0x1.960dp-4}, + {0x1.cee7766ece702p-78, 0x1.45b878e27d0d9p-23, 0x1.c7b5p-4}, + {-0x1.a55c745ecdc2fp-77, 0x1.770744593a4cbp-22, 0x1.f9c9p-4}, + {0x1.f7ec992caa67fp-77, 0x1.c673032495d24p-22, 0x1.097ep-3}, + {-0x1.433638c6ece3ep-77, -0x1.1eaa65b49696ep-22, 0x1.22dbp-3}, + {0x1.58f27b6518824p-76, 0x1.b2866f2850b22p-22, 0x1.3c6f8p-3}, + {-0x1.86bdcfdfd4a4cp-79, 0x1.8ee37cd2ea9d3p-25, 0x1.494f8p-3}, + {-0x1.ff7044a68a7fap-80, 0x1.7e86f9c2154fbp-24, 0x1.633a8p-3}, + {-0x1.aa21694561327p-81, 0x1.8e3cfc25f0ce6p-26, 0x1.7046p-3}, + {-0x1.d209f2d4239c6p-87, 0x1.57f7a64ccd537p-28, 0x1.8a898p-3}, + {-0x1.a55e97e60e632p-76, -0x1.a761c09fbd2aep-22, 0x1.97c2p-3}, + {0x1.261179225541ep-76, 0x1.24bea9a2c66f3p-22, 0x1.b26p-3}, + {-0x1.08fa30510fca9p-82, -0x1.60002ccfe43f5p-25, 0x1.bfc68p-3}, + {-0x1.63ec8d56242f9p-76, 0x1.69f220e97f22cp-22, 0x1.dac2p-3}, + {0x1.8bcdaf0534365p-76, -0x1.6164f64c210ep-22, 0x1.e858p-3}, + {0x1.1003282896056p-78, -0x1.0c1678ae89767p-24, 0x1.01d9cp-2}, + {0x1.01bcc7025fa92p-78, -0x1.f26a05c813d57p-22, 0x1.08bdp-2}, + {-0x1.fe8a8648e9ebcp-80, 0x1.4d8fc561c8d44p-24, 0x1.169cp-2}, + {0x1.08dfb23650c75p-79, -0x1.362ad8f7ca2dp-22, 0x1.1d984p-2}, + {-0x1.f8d5a89861a5ep-79, 0x1.2b13cd6c4d042p-22, 0x1.249ccp-2}, + {-0x1.a1c872983511ep-76, -0x1.1c8f11979a5dbp-22, 0x1.32cp-2}, + {0x1.e8e21bff3336bp-77, 0x1.c2ab3edefe569p-23, 0x1.39de8p-2}, + {0x1.fd1994fb2c4a1p-80, 0x1.7c3eca28e69cap-26, 0x1.4106p-2}, + {0x1.6b94b51cf76b1p-80, -0x1.34c4e99e1c6c6p-24, 0x1.4f6fcp-2}, + {-0x1.31d55da1d0f66p-76, -0x1.194a871b63619p-22, 0x1.56b24p-2}, + {-0x1.378b22691e28bp-77, 0x1.e3dd5c1c885aep-23, 0x1.5dfdcp-2}, + {0x1.99e302970e411p-83, -0x1.6ccf3b1129b7cp-23, 0x1.6552cp-2}, + {0x1.20164a049664dp-82, -0x1.2f346e2bf924bp-23, 0x1.6cb1p-2}, + {-0x1.d14aac4d864c3p-77, -0x1.fa61aaa59c1d8p-23, 0x1.7b8ap-2}, + {0x1.496ab4e4b293fp-79, 0x1.90c11fd32a3abp-22, 0x1.8304cp-2}, + {-0x1.d209f2d4239c6p-86, 0x1.57f7a64ccd537p-27, 0x1.8a898p-2}, + {0x1.eae3326327babp-81, 0x1.249ba76fee235p-27, 0x1.9218p-2}, + {0x1.fa05bddfded8cp-77, -0x1.aad2729b21ae5p-23, 0x1.99b08p-2}, + {-0x1.624140d175ba2p-77, 0x1.71810a5e1818p-22, 0x1.a8ff8p-2}, + {0x1.f1c5160c515c1p-81, -0x1.6172fe015e13cp-27, 0x1.b0b68p-2}, + {-0x1.86a6204eec8cp-79, 0x1.5ec6c1bfbf89ap-24, 0x1.b877cp-2}, + {0x1.718f761dd3915p-78, 0x1.678bf6cdedf51p-24, 0x1.c0438p-2}, + {-0x1.d4ee66c3700e4p-76, 0x1.c2d45fe43895ep-22, 0x1.c819cp-2}, + {-0x1.7d14533586306p-77, -0x1.9ee52ed49d71dp-22, 0x1.cffbp-2}, + {0x1.5ce9fb5a7bb5bp-81, 0x1.5786af187a96bp-27, 0x1.d7e6cp-2}, + {-0x1.ae6face57ad3bp-77, 0x1.3ab0dc56138c9p-23, 0x1.dfdd8p-2}, + {0x1.5ac93b443d55fp-78, 0x1.fe538ab34efb5p-22, 0x1.e7df4p-2}, + {0x1.f1753e0ae1e8fp-76, -0x1.e4fee07aa4b68p-22, 0x1.efec8p-2}, + {0x1.cdfd4c297069bp-76, -0x1.172f32fe67287p-22, 0x1.f804cp-2}, + {0x1.97a0e8f3ba742p-79, -0x1.9a83ff9ab9cc8p-22, 0x1.00144p-1}, + {-0x1.800450f5b2357p-78, -0x1.68cb06cece193p-22, 0x1.042bep-1}, + {-0x1.a839041241fe7p-78, 0x1.8cd71ddf82e2p-22, 0x1.08494p-1}, + {0x1.ed0b8eeccca86p-78, 0x1.5e18ab2df3ae6p-22, 0x1.0c6cap-1}, + {0x1.3dd41df9689b3p-79, 0x1.5dee4d9d8a273p-25, 0x1.1096p-1}, + {-0x1.990555535afdp-82, 0x1.fcd15f101c142p-26, 0x1.14c56p-1}, + {-0x1.1773d02c9055cp-77, -0x1.2474b0f992ba1p-23, 0x1.18faep-1}, + {-0x1.4aeef330c53c1p-78, 0x1.4b5a92a606047p-24, 0x1.1d368p-1}, + {0x1.8e6ff749ebacbp-77, 0x1.16186fcf54bbdp-22, 0x1.21786p-1}, + {0x1.c09d761c548ebp-84, 0x1.18efabeb7d722p-27, 0x1.25c0ap-1}, + {0x1.aaa73a428e1e4p-78, -0x1.e5fc7d238691dp-24, 0x1.2a0f4p-1}, + {-0x1.af2f3d8b63fbap-79, 0x1.f5809faf6283cp-22, 0x1.2e644p-1}, + {-0x1.af2f3d8b63fbap-79, 0x1.f5809faf6283cp-22, 0x1.2e644p-1}, + {0x1.78de359f2bb88p-77, 0x1.c6e1dcd0cb449p-22, 0x1.32bfep-1}, + {-0x1.415ae1a715618p-76, 0x1.76e0e8f74b4d5p-22, 0x1.37222p-1}, + {-0x1.4991b5375621fp-79, -0x1.cb82c89692d99p-24, 0x1.3b8b2p-1}, + {-0x1.827d37deb2236p-76, -0x1.63161c5432aebp-22, 0x1.3ffaep-1}, + {0x1.9576edac01c78p-77, 0x1.458104c41b901p-22, 0x1.44716p-1}, + {0x1.9576edac01c78p-77, 0x1.458104c41b901p-22, 0x1.44716p-1}, + {-0x1.05a27b81e2219p-77, -0x1.cd9d0cde578d5p-22, 0x1.48efp-1}, + {0x1.237616778b4bap-82, 0x1.b9884591add87p-26, 0x1.4d738p-1}, + {0x1.3b7d7e5d148bbp-76, 0x1.c6042978605ffp-22, 0x1.51ff2p-1}, + {-0x1.cc3f936a5977cp-79, -0x1.fc4c96b37dcf6p-22, 0x1.56922p-1}, + {0x1.20164a049664dp-83, -0x1.2f346e2bf924bp-24, 0x1.5b2c4p-1}, + {0x1.20164a049664dp-83, -0x1.2f346e2bf924bp-24, 0x1.5b2c4p-1}, + {-0x1.a212919a92f7ap-77, 0x1.c4e4fbb68a4d1p-22, 0x1.5fcdcp-1}, + {-0x1.b64b03f7230ddp-77, -0x1.9d499bd9b3226p-23, 0x1.6476ep-1}, + {-0x1.1ec6379e6e3b9p-77, -0x1.f89b355ede26fp-23, 0x1.69278p-1}, + {-0x1.1ec6379e6e3b9p-77, -0x1.f89b355ede26fp-23, 0x1.69278p-1}, + {-0x1.4ba44c03bfbbdp-78, 0x1.53c7e319f6e92p-24, 0x1.6ddfcp-1}, + {-0x1.c36fc650d030fp-77, -0x1.b291f070528c7p-22, 0x1.729fep-1}, + {-0x1.69e5693a7f067p-80, 0x1.2967a451a7b48p-25, 0x1.7767cp-1}, + {-0x1.69e5693a7f067p-80, 0x1.2967a451a7b48p-25, 0x1.7767cp-1}, + {0x1.6598aae91499ap-76, 0x1.244fcff690fcep-22, 0x1.7c37ap-1}, + {0x1.99d61ec432837p-77, 0x1.46fd97f5dc572p-23, 0x1.810fap-1}, + {0x1.99d61ec432837p-77, 0x1.46fd97f5dc572p-23, 0x1.810fap-1}, + {0x1.855c42078f81bp-76, -0x1.f3a7352663e5p-22, 0x1.85efep-1}, + {-0x1.59408e815107p-77, 0x1.b3cda690370b5p-23, 0x1.8ad84p-1}, + {-0x1.59408e815107p-77, 0x1.b3cda690370b5p-23, 0x1.8ad84p-1}, + {0x1.33b318085e50ap-78, 0x1.3226b211bf1d9p-23, 0x1.8fc92p-1}, + {0x1.343fe7c9cb4aep-79, 0x1.d24b136c101eep-23, 0x1.94c28p-1}, + {0x1.343fe7c9cb4aep-79, 0x1.d24b136c101eep-23, 0x1.94c28p-1}, + {-0x1.d19522e56fe6p-76, 0x1.7c40c7907e82ap-22, 0x1.99c48p-1}, + {-0x1.23b9d8ea55c3ep-77, -0x1.e81781d97ee91p-22, 0x1.9ecf6p-1}, + {-0x1.23b9d8ea55c3ep-77, -0x1.e81781d97ee91p-22, 0x1.9ecf6p-1}, + {0x1.829440c24aeb6p-78, -0x1.6a77813f94e01p-22, 0x1.a3e3p-1}, + {-0x1.624140d175ba2p-76, -0x1.1cfdeb43cfdp-22, 0x1.a8ffap-1}, + {-0x1.624140d175ba2p-76, -0x1.1cfdeb43cfdp-22, 0x1.a8ffap-1}, + {0x1.afa6f024fb045p-77, -0x1.f983f74d3138fp-23, 0x1.ae256p-1}, + {-0x1.603ad3a5d326dp-78, -0x1.e278ae1a1f51fp-23, 0x1.b3546p-1}, + {-0x1.603ad3a5d326dp-78, -0x1.e278ae1a1f51fp-23, 0x1.b3546p-1}, + {-0x1.0c1e0e5855d6ap-77, -0x1.97552b7b5ea45p-23, 0x1.b88ccp-1}, + {-0x1.0c1e0e5855d6ap-77, -0x1.97552b7b5ea45p-23, 0x1.b88ccp-1}, + {0x1.c817ad56baa16p-78, -0x1.19b4f3c72c4f8p-24, 0x1.bdceap-1}, + {0x1.44c47ac1bf62bp-77, 0x1.f7402d26f1a12p-23, 0x1.c31a2p-1}, + {0x1.44c47ac1bf62bp-77, 0x1.f7402d26f1a12p-23, 0x1.c31a2p-1}, + {-0x1.69b9465eae1e6p-78, -0x1.2056d5dd31d96p-23, 0x1.c86f8p-1}, + {-0x1.69b9465eae1e6p-78, -0x1.2056d5dd31d96p-23, 0x1.c86f8p-1}, + {-0x1.24a6d9d1d1904p-79, -0x1.6e46335aae723p-24, 0x1.cdcecp-1}, + {-0x1.3826144575ac4p-76, -0x1.beb244c59f331p-22, 0x1.d3382p-1}, + {-0x1.3826144575ac4p-76, -0x1.beb244c59f331p-22, 0x1.d3382p-1}, + {0x1.dbc96b3b12b25p-81, 0x1.16c071e93fd97p-27, 0x1.d8abap-1}, + {0x1.dbc96b3b12b25p-81, 0x1.16c071e93fd97p-27, 0x1.d8abap-1}, + {0x1.68a8ccdbd1f33p-77, 0x1.d8175819530c2p-22, 0x1.de298p-1}, + {0x1.68a8ccdbd1f33p-77, 0x1.d8175819530c2p-22, 0x1.de298p-1}, + {0x1.e586711df5ea1p-79, 0x1.51bd552842c1cp-23, 0x1.e3b2p-1}, + {0x1.e586711df5ea1p-79, 0x1.51bd552842c1cp-23, 0x1.e3b2p-1}, + {-0x1.bc25adf042483p-79, 0x1.914e204f19d94p-22, 0x1.e9452p-1}, + {-0x1.bc25adf042483p-79, 0x1.914e204f19d94p-22, 0x1.e9452p-1}, + {0x1.d7d82b65c5686p-76, 0x1.c55d997da24fdp-22, 0x1.eee32p-1}, + {0x1.d7d82b65c5686p-76, 0x1.c55d997da24fdp-22, 0x1.eee32p-1}, + {-0x1.3f108c0857ca3p-77, -0x1.685c2d2298a6ep-22, 0x1.f48c4p-1}, + {-0x1.3f108c0857ca3p-77, -0x1.685c2d2298a6ep-22, 0x1.f48c4p-1}, + {-0x1.bd800bca7a221p-78, 0x1.7a4887bd74039p-22, 0x1.fa406p-1}, + {0.0, 0.0, 1.0}, +}; + +// Lookup table for 4-bit (16 entries) range reduction for float_eval: +// r(0) = 1.0f +// r(i) = 2^-5 * ceil(2^5 * (1 - 2^-5) / (1 + i * 2^-4)), i = 1..15. +// The constants are chosen so that dx = r * m_x - 1 is exact in +// single precision (with hardware FMA or 14-bit Sterbenz split), and +// -2^-5 <= dx < 2^-4. +// +// Generated by Sollya with: +// > display = hexadecimal; +// > for i from 0 to 15 do { +// if (i == 0) then { +// print("0x1.0p+0f,"); +// } else if (i == 15) then { +// print("0x1.0p-1f,"); +// } else { +// r = 2^(-5) * ceil( 2^5 * (1 - 2^(-5)) / (1 + i*2^(-4)) ); +// print(r @ "f,"); +// }; +// }; +LIBC_INLINE_VAR constexpr float R_16[16] = { + 0x1.0p+0f, 0x1.ep-1f, 0x1.cp-1f, 0x1.bp-1f, 0x1.9p-1f, 0x1.8p-1f, + 0x1.7p-1f, 0x1.6p-1f, 0x1.5p-1f, 0x1.4p-1f, 0x1.4p-1f, 0x1.3p-1f, + 0x1.2p-1f, 0x1.2p-1f, 0x1.1p-1f, 0x1.0p-1f, +}; + +// Lookup table for 5-bit (32 entries) range reduction for double_eval fast +// path: +// r(0) = 1.0 +// r(i) = 2^-6 * ceil(2^6 * (1 - 2^-6) / (1 + i * 2^-5)), i = 1..31. +LIBC_INLINE_VAR constexpr double R_32_D[32] = { + 0x1.0p+0, 0x1.fp-1, 0x1.ep-1, 0x1.dp-1, 0x1.cp-1, 0x1.b8p-1, 0x1.bp-1, + 0x1.ap-1, 0x1.98p-1, 0x1.9p-1, 0x1.8p-1, 0x1.78p-1, 0x1.7p-1, 0x1.68p-1, + 0x1.6p-1, 0x1.58p-1, 0x1.5p-1, 0x1.5p-1, 0x1.48p-1, 0x1.4p-1, 0x1.38p-1, + 0x1.38p-1, 0x1.3p-1, 0x1.28p-1, 0x1.2p-1, 0x1.2p-1, 0x1.18p-1, 0x1.18p-1, + 0x1.1p-1, 0x1.1p-1, 0x1.08p-1, 0x1.0p-1, +}; + +// Table of -log2(R_32_D[i]) represented in double precision for double_eval. +// +// Generated by Sollya with: +// > display = hexadecimal; +// > prec = 200; +// > for i from 0 to 31 do { +// if (i == 0) then { +// print("0x0.0000000000000p+0,"); +// } else if (i == 31) then { +// print("0x1.0000000000000p+0,"); +// } else { +// r = 2^(-6) * ceil( 2^6 * (1 - 2^(-6)) / (1 + i*2^(-5)) ); +// print(round(-log2(r), D, RN), ","); +// }; +// }; +LIBC_INLINE_VAR constexpr double LOG2_R_32[32] = { + 0x0.0000000000000p+0, 0x1.77394c9d958d5p-5, 0x1.7d60496cfbb4cp-4, + 0x1.22dadc2ab3497p-3, 0x1.8a8980abfbd32p-3, 0x1.bfc67a7fff4ccp-3, + 0x1.f5fd8a9063e35p-3, 0x1.32bfee370ee68p-2, 0x1.4f6fbb2cec598p-2, + 0x1.6cb0f6865c8eap-2, 0x1.a8ff971810a5ep-2, 0x1.c819dc2d45fe4p-2, + 0x1.e7df5fe538ab3p-2, 0x1.042bd4b9a7c99p-1, 0x1.14c560fe68af9p-1, + 0x1.25c0a0463bebp-1, 0x1.37222bb70747cp-1, 0x1.37222bb70747cp-1, + 0x1.48eef19317991p-1, 0x1.5b2c3da19723bp-1, 0x1.6ddfc2a78fc63p-1, + 0x1.6ddfc2a78fc63p-1, 0x1.810fa51bf65fdp-1, 0x1.94c287492c4dbp-1, + 0x1.a8ff971810a5ep-1, 0x1.a8ff971810a5ep-1, 0x1.bdce9dcc96187p-1, + 0x1.bdce9dcc96187p-1, 0x1.d338120a6dd9dp-1, 0x1.d338120a6dd9dp-1, + 0x1.e9452c8a71028p-1, 0x1.0000000000000p+0, +}; + +// Table of -log2(R_16[i]) represented in FloatFloat precision {lo, hi} for +// float_eval. +// We choose the precision of the high part to be 24 - 8 = 16 bits, so that +// e_xf + LOG2_R_FF_16[i].hi +// is exact in float for |e_x| <= 150. +// For i = 15, R_16[15] = 0.5, so -log2(R_16[15]) = 1.0f is exact. +// +// Generated by Sollya with: +// > display = hexadecimal; +// > prec = 200; +// > for i from 0 to 15 do { +// if (i == 0) then { +// print("{0x0.000000p+0f, 0x0.000000p+0f},"); +// } else if (i == 15) then { +// print("{0x0.000000p+0f, 0x1.000000p+0f},"); +// } else { +// r = 2^(-5) * ceil( 2^5 * (1 - 2^(-5)) / (1 + i*2^(-4)) ); +// l = -log2(r); +// h = round(1 + l, 17, RN) - 1; +// lo = round(l - h, SG, RN); +// print("{" @ lo @ "f, " @ h @ "f},"); +// }; +// }; +LIBC_INLINE_VAR constexpr FloatFloat LOG2_R_FF_16[16] = { + {0x0.000000p+0f, 0x0.000000p+0f}, {0x1.25b3eep-22f, 0x1.7d6p-4f}, + {0x1.80abfcp-19f, 0x1.8a88p-3f}, {-0x1.3ab7cep-18f, 0x1.f6p-3f}, + {0x1.ed0cbap-19f, 0x1.6cbp-2f}, {-0x1.a39fbep-20f, 0x1.a9p-2f}, + {-0x1.40358ep-19f, 0x1.e7ep-2f}, {-0x1.3e032ep-18f, 0x1.14c6p-1f}, + {0x1.5db83ap-20f, 0x1.3722p-1f}, {0x1.ed0cbap-20f, 0x1.5b2cp-1f}, + {0x1.ed0cbap-20f, 0x1.5b2cp-1f}, {-0x1.6b9026p-19f, 0x1.811p-1f}, + {-0x1.a39fbep-19f, 0x1.a9p-1f}, {-0x1.a39fbep-19f, 0x1.a9p-1f}, + {0x1.20a6dep-21f, 0x1.d338p-1f}, {0x0.000000p+0f, 0x1.000000p+0f}, +}; + +// Upper bound for y = 150 / |log2(1 - 2^-24)|, generated by Sollya: +// > y = round(-150 / log2(1 - 2^(-24)), SG, RU); +// > y; +// 0x1.9fe368p30 +// > printsingle(y); +// 0x4ecff1b4 +constexpr uint32_t Y_UPPER_BOUND = 0x4ecf'f1b4; +// Lower bound for y = 2^-25 / 150, generated by Sollya: +// > y = round(2^(-25) / 150, SG, RD); +// > y; +// 0x1.b4e81ap-33 +// > printsingle(y); +// 0x2f5a740d +constexpr uint32_t Y_LOWER_BOUND = 0x2f5a'740d; + +LIBC_INLINE float set_overflow(Sign sign = Sign::POS) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_overflow_except_if_required<float>(); + using FPBits = fputil::FPBits<float>; +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + int rounding = fputil::quick_get_round(); + if (rounding == FE_TOWARDZERO) + return FPBits::max_normal(sign).get_val(); + if (rounding == FE_DOWNWARD) + return sign.is_neg() ? FPBits::inf(Sign::NEG).get_val() + : FPBits::max_normal(Sign::POS).get_val(); + if (rounding == FE_UPWARD) + return sign.is_neg() ? FPBits::max_normal(Sign::NEG).get_val() + : FPBits::inf(Sign::POS).get_val(); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return sign.is_neg() ? FPBits::inf(Sign::NEG).get_val() + : FPBits::inf(Sign::POS).get_val(); +} + +LIBC_INLINE float set_underflow(Sign sign = Sign::POS) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_underflow_except_if_required<float>(); + +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + using FPBits = fputil::FPBits<float>; + int rounding = fputil::quick_get_round(); + if (rounding == FE_UPWARD && sign.is_pos()) + return FPBits::min_subnormal(Sign::POS).get_val(); + if (rounding == FE_DOWNWARD && sign.is_neg()) + return FPBits::min_subnormal(Sign::NEG).get_val(); +#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + + return sign.is_neg() ? -0.0f : 0.0f; +} + +// Fast checks for special inputs: +// x = 0, +-1, 2^k, 10, +- Inf +// y = 0, +-1, 2, 0.5 +LIBC_ALWAYS_INLINE cpp::optional<float> check_special_inputs(float x, float y) { + using FPBits = fputil::FPBits<float>; + FPBits xbits(x), ybits(y); + + bool x_sign = xbits.sign() == Sign::NEG; + bool y_sign = ybits.sign() == Sign::NEG; + + FPBits x_abs = xbits.abs(); + FPBits y_abs = ybits.abs(); + + // If x or y is signaling NaN + if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x == 1.0f || y == 0.0f) + return 1.0f; + + if (x == 0.0f) { + if (y_abs.is_nan()) + return y; + if (y_abs.is_inf()) + return y_sign ? FPBits::inf().get_val() : 0.0f; + bool out_is_neg = x_sign && fputil::is_odd_integer(y); + if (y_sign) { + // pow(0, negative number) = Inf + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_DIVBYZERO); + return out_is_neg ? FPBits::inf(Sign::NEG).get_val() + : FPBits::inf(Sign::POS).get_val(); + } + // pow(0, positive number) = 0 + return out_is_neg ? -0.0f : 0.0f; + } + + if (y == 1.0f) + return x; + + if (y == 2.0f) + return x * x; + +#ifdef LIBC_TARGET_CPU_HAS_FPU_FLOAT + if (y == 0.5f && !x_sign) + return fputil::sqrt<float>(x); +#endif // LIBC_TARGET_CPU_HAS_FPU_FLOAT + + // Exact power of 2: + // pow(2^k, y) = 2^(k * y). + // This is exact if k * y is an integer. + uint32_t y_a = y_abs.uintval(); + if (x_abs.is_normal() && xbits.get_mantissa() == 0 && y_a > Y_LOWER_BOUND && + y_a < Y_UPPER_BOUND) { + if (!x_sign || fputil::is_integer(y)) { + Sign out_sign = + (x_sign && fputil::is_odd_integer(y)) ? Sign::NEG : Sign::POS; + int e_x = xbits.get_exponent(); + double ey = static_cast<double>(e_x) * static_cast<double>(y); + double ey_int = fputil::nearest_integer(ey); + if (ey_int == ey) { + if (ey > 127.0) + return set_overflow(out_sign); + if (ey < -149.0) + return set_underflow(out_sign); + int k = static_cast<int>(ey); + if (k >= -126) + return FPBits::create_value(out_sign, static_cast<uint32_t>(k + 127), + 0) + .get_val(); + return FPBits::create_value(out_sign, 0, 1U << (k + 149)).get_val(); + } + } + } + +#if !defined(LIBC_MATH_HAS_SMALL_TABLES) && \ + !defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT) + if (x == 2.0f) + return math::exp2f(y); + + if (x == 10.0f) + return math::exp10f(y); + + // For x = 2^(+- 2^n): + // x^y = 2^(+- 2^n * y). + if (!x_sign && x_abs.is_normal() && xbits.get_mantissa() == 0 && + y_a > Y_LOWER_BOUND && y_a < Y_UPPER_BOUND) { + int e_x = xbits.get_exponent(); + uint32_t abs_e = static_cast<uint32_t>(e_x > 0 ? e_x : -e_x); + if (cpp::has_single_bit(abs_e)) { + float hi = static_cast<float>(e_x) * y; + if (hi >= 128.0f) + return set_overflow(); + if (hi < -150.0f) + return set_underflow(); + if (hi >= -126.0f) + return math::exp2f(hi); + } + } +#endif // !LIBC_MATH_HAS_SMALL_TABLES && + // !LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT + + return cpp::nullopt; +} + +// Filters out extreme input ranges, infinities, NaNs, normalizes denormal +// inputs, and handles negative bases. Returns a value if the result is +// determined, or nullopt if regular evaluation should proceed (in which case x, +// y, ex, sign may be updated). +template <typename SignType = uint64_t> +LIBC_ALWAYS_INLINE cpp::optional<float> +check_exceptional_cases(float &x, float &y, int &ex, SignType &sign) { + using FloatBits = fputil::FPBits<float>; + FloatBits xbits(x), ybits(y); + bool x_sign = xbits.sign() == Sign::NEG; + bool y_sign = ybits.sign() == Sign::NEG; + + FloatBits x_abs = xbits.abs(); + FloatBits y_abs = ybits.abs(); + + uint32_t x_a = x_abs.uintval(); + uint32_t y_a = y_abs.uintval(); + + // If x or y is signaling NaN + if (x_abs.is_signaling_nan() || y_abs.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FloatBits::quiet_nan().get_val(); + } + + if (x == 1.0f || y == 0.0f) + return 1.0f; + + // Extreme |y| >= Y_UPPER_BOUND: |y * log2(x)| >= 150 for all x != 1. + if (y_a >= Y_UPPER_BOUND) { + if (x_abs.is_nan()) + return x; + if (ybits.is_nan()) + return y; + + if (x_a == FloatBits::one().uintval()) + return 1.0f; + + bool is_overflow = (x_a < FloatBits::one().uintval()) == y_sign; + if (y_abs.is_inf() || x_a == FloatBits::inf().uintval()) + return is_overflow ? FloatBits::inf().get_val() : 0.0f; + + return is_overflow ? set_overflow() : set_underflow(); + } + + // y is finite and non-zero. + if (x_a > FloatBits::inf().uintval()) { + // x is NaN. + return x; + } + + // Handle negative base x < 0 (including -0.0f and -Inf): + // - If y is an integer: (-|x|)^y = (-1)^y * |x|^y. + // - If y is not an integer and x is finite non-zero: (-|x|)^y is undefined + // in real numbers; raises FE_INVALID, sets errno to EDOM, and returns + // quiet NaN. + if (x_sign) { + if (fputil::is_integer(y)) { + if (fputil::is_odd_integer(y)) { + if constexpr (sizeof(SignType) == 8) + sign = 0x8000'0000'0000'0000ULL; + else + sign = 0x8000'0000U; + } + } else if (x != 0.0f && x_a != FloatBits::inf().uintval()) { + // pow( negative, non-integer ) = NaN + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FloatBits::quiet_nan().get_val(); + } + x = -x; + } + + if (x_a == FloatBits::inf().uintval()) { + // pow(+-Inf, y): + // - y < 0: returns +-0.0 (negative if x = -Inf and y is odd integer). + // - y > 0: returns +-Inf (negative if x = -Inf and y is odd integer). + if (y_sign) + return (sign != 0) ? -0.0f : 0.0f; + return (sign != 0) ? FloatBits::inf(Sign::NEG).get_val() + : FloatBits::inf(Sign::POS).get_val(); + } + + if (x == 0.0f) { + if (y_sign) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_DIVBYZERO); + return (sign != 0) ? FloatBits::inf(Sign::NEG).get_val() + : FloatBits::inf(Sign::POS).get_val(); + } + return (sign != 0) ? -0.0f : 0.0f; + } + + if (y_a <= Y_LOWER_BOUND) { +#if defined(LIBC_MATH_HAS_NO_EXCEPT) && \ + defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY) + return 1.0f; +#else + volatile float one = 1.0f; + volatile float eps = ((x_a < FloatBits::one().uintval()) == !y_sign) + ? -0x1.0p-50f + : 0x1.0p-50f; + return one + eps; +#endif + } + + // Normalize denormal inputs. + if (x_a < FloatBits::min_normal().uintval()) { + int shift = cpp::countl_zero(x_a) - 8; +#ifdef LIBC_TARGET_CPU_HAS_FPU_DOUBLE + if (!y_sign && + static_cast<double>(y) * static_cast<double>(125 + shift) >= 150.0) + return set_underflow(sign == 0 ? Sign::POS : Sign::NEG); +#else + uint32_t log2_bound = static_cast<uint32_t>(125 + shift); + if (!y_sign && + (y_a >= 0x4000'0000U || (y_a >= FloatBits::one().uintval() && + (y_a - 0x3f00'0000U) * log2_bound >= + (150U << FloatBits::FRACTION_LEN)))) + return set_underflow(sign == 0 ? Sign::POS : Sign::NEG); +#endif + + ex -= shift; + x = cpp::bit_cast<float>(x_a << shift); + } + + return cpp::nullopt; +} + +#ifndef LIBC_MATH_HAS_SMALL_TABLES +// Check if x^y is an exact rounding boundary case (a 25-bit dyadic float, +// which is either an exact 24-bit float or an exact halfway midpoint). +// +// Reference: +// Lauter, C. and Lefevre, V., "Rounding Boundary Cases for Values of the +// Exponential and Power Functions," IEEE Trans. Comput. 58(8):1063-1074. +// +// 1. x = 2^e: x^y = 2^(e * y) is in F_25 iff e * y is an integer. +// 2. x = m * 2^e, y = n * 2^f with m, n odd integers: +// x^y in F_25 implies: +// - 0 <= y <= 15, n <= 15. +// - f >= -3. +// - e * y is an integer. +// - When f < 0 (i.e. y = n / 2^(-f)): m^(2^f) is an integer, verified +// by taking repeated square roots -f times. +// - The resulting significand (m^(2^f))^n <= 2^25. +// +// Returns true and sets exact_m and exact_exp if x^y is an exact boundary. +LIBC_INLINE bool is_exact_rounding_boundary(float x, float y, uint32_t &exact_m, + int &exact_exp) { + using FPBits = fputil::FPBits<float>; + + FPBits xbits(x); + int x_e = 0; + uint32_t x_mant = xbits.get_mantissa(); + if (LIBC_UNLIKELY(xbits.get_biased_exponent() == 0)) { + if (x_mant != 0) { + int shift = cpp::countl_zero(x_mant) - 8; + x_mant = (x_mant << shift) & FPBits::FRACTION_MASK; + x_e = -126 - shift; + } + } else { + x_e = xbits.get_exponent(); + } + + // Case 1: x = 2^e. + if (x_mant == 0) { + double e = static_cast<double>(x_e); + double ey = e * static_cast<double>(y); + if (fputil::nearest_integer(ey) == ey) { + exact_m = 1; + if (ey > 150.0) + exact_exp = 200; + else if (ey < -200.0) + exact_exp = -200; + else + exact_exp = static_cast<int>(ey); + return true; + } + return false; + } + + // Case 2: x is not a power of 2. + if (y < 0.0f || y > 15.0f) + return false; + + // Decompose y = n * 2^f with n odd. + FPBits ybits(y); + uint32_t y_mant = ybits.get_mantissa() | (1U << FPBits::FRACTION_LEN); + int y_exp = ybits.get_exponent() - static_cast<int>(FPBits::FRACTION_LEN); + int tz_y = cpp::countr_zero(y_mant); + uint32_t n = y_mant >> tz_y; + int f = y_exp + tz_y; + + if (n > 15 || f < -3) + return false; + + // Decompose x = m * 2^e with m odd. + uint32_t full_x_mant = x_mant | (1U << FPBits::FRACTION_LEN); + int tz_x = cpp::countr_zero(full_x_mant); + uint32_t m = full_x_mant >> tz_x; + int e = x_e - static_cast<int>(FPBits::FRACTION_LEN) + tz_x; + + if (f < 0) { + // Non-integer exponent: y = n / 2^(-f) with -f in {1, 2, 3}. + double ey = static_cast<double>(e) * static_cast<double>(y); + if (fputil::nearest_integer(ey) != ey) + return false; + + // Check if m^(2^f) is an integer by taking repeated square roots -f times. + int count = -f; + uint32_t cur = m; + for (int i = 0; i < count; ++i) { + uint32_t s = + static_cast<uint32_t>(fputil::sqrt<double>(static_cast<double>(cur))); + if (s * s != cur) + return false; + cur = s; + } + + // Compute res = cur^n and check if res <= 2^25. + uint32_t res = 1; + for (uint32_t i = 0; i < n; ++i) { + if (res > (1U << 25) / cur) + return false; + res *= cur; + } + exact_m = res; + exact_exp = static_cast<int>(ey); + return true; + } else { + // Integer exponent: f >= 0, so y is an integer. + int y_int = static_cast<int>(y); + uint32_t res = 1; + for (int i = 0; i < y_int; ++i) { + if (res > (1U << 25) / m) + return false; + res *= m; + } + exact_m = res; + exact_exp = e * y_int; + return true; + } +} +#endif // !LIBC_MATH_HAS_SMALL_TABLES + +} // namespace powf_internal +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_POWF_UTILS_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadf128.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadf128.h index 4e022d8ec91d..8feeef8b9fa9 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadf128.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadf128.h @@ -1,32 +1,34 @@ -//===-- Implementation header for setpayloadf128 ----------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for setpayloadf128. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SETPAYLOADF128_H #define LLVM_LIBC_SRC___SUPPORT_MATH_SETPAYLOADF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/float128.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE constexpr int setpayloadf128(float128 *res, float128 pl) { +using LIBC_NAMESPACE::fputil::Float128; + +LIBC_INLINE constexpr int setpayloadf128(Float128 *res, Float128 pl) { return static_cast<int>(fputil::setpayload</*IsSignaling=*/false>(*res, pl)); } } // namespace math } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SRC___SUPPORT_MATH_SETPAYLOADF128_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadsigf128.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadsigf128.h index c9bd9498cfb7..bb7ca8afc0d7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadsigf128.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/setpayloadsigf128.h @@ -1,32 +1,34 @@ -//===-- Implementation header for setpayloadsigf128 -------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation header for setpayloadsigf128. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SETPAYLOADSIGF128_H #define LLVM_LIBC_SRC___SUPPORT_MATH_SETPAYLOADSIGF128_H -#include "include/llvm-libc-types/float128.h" - -#ifdef LIBC_TYPES_HAS_NATIVE_FLOAT128 - #include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/float128.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE constexpr int setpayloadsigf128(float128 *res, float128 pl) { +using LIBC_NAMESPACE::fputil::Float128; + +LIBC_INLINE constexpr int setpayloadsigf128(Float128 *res, Float128 pl) { return static_cast<int>(fputil::setpayload</*IsSignaling=*/true>(*res, pl)); } } // namespace math } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128 - #endif // LLVM_LIBC_SRC___SUPPORT_MATH_SETPAYLOADSIGF128_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/sincosf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/sincosf_float_eval.h index 195ce373c0f0..d834f3d7cf23 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/sincosf_float_eval.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/sincosf_float_eval.h @@ -14,6 +14,7 @@ #include "src/__support/FPUtil/double_double.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { @@ -22,6 +23,45 @@ namespace math { namespace sincosf_float_eval { +// > for i from 0 to 13 do { +// if i < 2 then { pi_inv = 0.25 + 2^(8*(i - 2)) / pi; } +// else { pi_inv = 2^(8*(i-2)) / pi; }; +// pn = nearestint(pi_inv); +// pi_frac = pi_inv - pn; +// a = round(pi_frac, SG, RN); +// b = round(pi_frac - a, SG, RN); +// c = round(pi_frac - a - b, SG, RN); +// d = round(pi_frac - a - b - c, SG, RN); +// print("{", 2^3 * a, ",", 2^3 * b, ",", 2^3 * c, ",", 2^3 * d, "},"); +// }; +LIBC_INLINE_VAR constexpr float EIGHT_OVER_PI[14][4] = { + {0x1.000146p1f, -0x1.9f246cp-28f, -0x1.bbead6p-54f, -0x1.ec5418p-85f}, + {0x1.0145f4p1f, -0x1.f246c6p-24f, -0x1.df56bp-49f, -0x1.ec5418p-77f}, + {0x1.45f306p1f, 0x1.b9391p-24f, 0x1.529fc2p-50f, 0x1.d5f47ep-76f}, + {0x1.f306dcp1f, 0x1.391054p-24f, 0x1.4fe13ap-49f, 0x1.7d1f54p-74f}, + {-0x1.f246c6p0f, -0x1.df56bp-25f, -0x1.ec5418p-53f, 0x1.f534dep-78f}, + {-0x1.236378p1f, 0x1.529fc2p-26f, 0x1.d5f47ep-52f, -0x1.65912p-77f}, + {0x1.391054p0f, 0x1.4fe13ap-25f, 0x1.7d1f54p-50f, -0x1.6447e4p-75f}, + {0x1.1054a8p0f, -0x1.ec5418p-29f, 0x1.f534dep-54f, -0x1.f924ecp-81f}, + {0x1.529fc2p-2f, 0x1.d5f47ep-28f, -0x1.65912p-53f, 0x1.b6c52cp-79f}, + {-0x1.ac07b2p1f, 0x1.5f47d4p-24f, 0x1.a6ee06p-49f, 0x1.b6295ap-74f}, + {-0x1.ec5418p-5f, 0x1.f534dep-30f, -0x1.f924ecp-57f, 0x1.5993c4p-82f}, + {0x1.3abe9p-1f, -0x1.596448p-27f, 0x1.b6c52cp-55f, -0x1.9b0ef2p-80f}, + {-0x1.505c16p1f, 0x1.a6ee06p-25f, 0x1.b6295ap-50f, -0x1.b0ef1cp-76f}, + {-0x1.70565ap-1f, 0x1.dc0db6p-26f, 0x1.4acc9ep-53f, 0x1.0e4108p-80f}, +}; + +// sin(k * pi/8) for k = 0..15, generated by Sollya with: +// > for k from 0 to 16 do { +// print(round(sin(k * pi/8), SG, RN)); +// }; +LIBC_INLINE_VAR constexpr float SIN_K_PI_OVER_8[16] = { + 0.0f, 0x1.87de2ap-2f, 0x1.6a09e6p-1f, 0x1.d906bcp-1f, + 1.0f, 0x1.d906bcp-1f, 0x1.6a09e6p-1f, 0x1.87de2ap-2f, + 0.0f, -0x1.87de2ap-2f, -0x1.6a09e6p-1f, -0x1.d906bcp-1f, + -1.0f, -0x1.d906bcp-1f, -0x1.6a09e6p-1f, -0x1.87de2ap-2f, +}; + // Since the worst case of `x mod pi` in single precision is > 2^-28, in order // to be bounded by 1 ULP, the range reduction accuracy will need to be at // least 2^(-28 - 23) = 2^-51. @@ -60,34 +100,6 @@ LIBC_INLINE unsigned sincosf_range_reduction_small(float x, float &u) { // TODO: Add non-FMA version of large range reduction. LIBC_INLINE unsigned sincosf_range_reduction_large(float x, float &u) { - // > for i from 0 to 13 do { - // if i < 2 then { pi_inv = 0.25 + 2^(8*(i - 2)) / pi; } - // else { pi_inv = 2^(8*(i-2)) / pi; }; - // pn = nearestint(pi_inv); - // pi_frac = pi_inv - pn; - // a = round(pi_frac, SG, RN); - // b = round(pi_frac - a, SG, RN); - // c = round(pi_frac - a - b, SG, RN); - // d = round(pi_frac - a - b - c, SG, RN); - // print("{", 2^3 * a, ",", 2^3 * b, ",", 2^3 * c, ",", 2^3 * d, "},"); - // }; - constexpr float EIGHT_OVER_PI[14][4] = { - {0x1.000146p1f, -0x1.9f246cp-28f, -0x1.bbead6p-54f, -0x1.ec5418p-85f}, - {0x1.0145f4p1f, -0x1.f246c6p-24f, -0x1.df56bp-49f, -0x1.ec5418p-77f}, - {0x1.45f306p1f, 0x1.b9391p-24f, 0x1.529fc2p-50f, 0x1.d5f47ep-76f}, - {0x1.f306dcp1f, 0x1.391054p-24f, 0x1.4fe13ap-49f, 0x1.7d1f54p-74f}, - {-0x1.f246c6p0f, -0x1.df56bp-25f, -0x1.ec5418p-53f, 0x1.f534dep-78f}, - {-0x1.236378p1f, 0x1.529fc2p-26f, 0x1.d5f47ep-52f, -0x1.65912p-77f}, - {0x1.391054p0f, 0x1.4fe13ap-25f, 0x1.7d1f54p-50f, -0x1.6447e4p-75f}, - {0x1.1054a8p0f, -0x1.ec5418p-29f, 0x1.f534dep-54f, -0x1.f924ecp-81f}, - {0x1.529fc2p-2f, 0x1.d5f47ep-28f, -0x1.65912p-53f, 0x1.b6c52cp-79f}, - {-0x1.ac07b2p1f, 0x1.5f47d4p-24f, 0x1.a6ee06p-49f, 0x1.b6295ap-74f}, - {-0x1.ec5418p-5f, 0x1.f534dep-30f, -0x1.f924ecp-57f, 0x1.5993c4p-82f}, - {0x1.3abe9p-1f, -0x1.596448p-27f, 0x1.b6c52cp-55f, -0x1.9b0ef2p-80f}, - {-0x1.505c16p1f, 0x1.a6ee06p-25f, 0x1.b6295ap-50f, -0x1.b0ef1cp-76f}, - {-0x1.70565ap-1f, 0x1.dc0db6p-26f, 0x1.4acc9ep-53f, 0x1.0e4108p-80f}, - }; - using FPBits = typename fputil::FPBits<float>; using fputil::FloatFloat; FPBits xbits(x); @@ -134,17 +146,6 @@ LIBC_INLINE unsigned sincosf_range_reduction_large(float x, float &u) { } template <bool IS_SIN> LIBC_INLINE float sincosf_eval(float x) { - // sin(k * pi/8) for k = 0..15, generated by Sollya with: - // > for k from 0 to 16 do { - // print(round(sin(k * pi/8), SG, RN)); - // }; - constexpr float SIN_K_PI_OVER_8[16] = { - 0.0f, 0x1.87de2ap-2f, 0x1.6a09e6p-1f, 0x1.d906bcp-1f, - 1.0f, 0x1.d906bcp-1f, 0x1.6a09e6p-1f, 0x1.87de2ap-2f, - 0.0f, -0x1.87de2ap-2f, -0x1.6a09e6p-1f, -0x1.d906bcp-1f, - -1.0f, -0x1.d906bcp-1f, -0x1.6a09e6p-1f, -0x1.87de2ap-2f, - }; - using FPBits = fputil::FPBits<float>; FPBits xbits(x); uint32_t x_abs = cpp::bit_cast<uint32_t>(x) & 0x7fff'ffffU; @@ -206,8 +207,8 @@ template <bool IS_SIN> LIBC_INLINE float sincosf_eval(float x) { float s1 = fputil::multiply_add(y3, p1, y); if constexpr (IS_SIN) { - // sin(x) = cos(k * pi/8) * sin(y) + sin(k * pi/8) * cos(y). - return fputil::multiply_add(cos_k, s1, sin_k * c1); + // sin(x) = sin(k * pi/8) * cos(y) + cos(k * pi/8) * sin(y). + return fputil::multiply_add(sin_k, c1, cos_k * s1); } else { // cos(x) = cos(k * pi/8) * cos(y) - sin(k * pi/8) * sin(y). return fputil::multiply_add(cos_k, c1, -sin_k * s1); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf.h index 1f72618a2962..9a6f78e6a6d3 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf.h @@ -1,197 +1,42 @@ -//===-- Single-precision sin function -------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation selector for sinf. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINF_H #define LLVM_LIBC_SRC___SUPPORT_MATH_SINF_H -#include "src/__support/FPUtil/BasicOperations.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" #if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ - defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT) && \ + (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ + defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)) && \ defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - -#include "sincosf_float_eval.h" +#include "sinf_float_eval.h" +#define LIBC_MATH_SINF_IMPL float_eval +#else +#include "sinf_double_eval.h" +#define LIBC_MATH_SINF_IMPL double_eval +#endif namespace LIBC_NAMESPACE_DECL { - namespace math { -LIBC_INLINE float sinf(float x) { - return math::sincosf_float_eval::sincosf_eval</*IS_SIN*/ true>(x); -} +using LIBC_MATH_SINF_IMPL::sinf; } // namespace math - -} // namespace LIBC_NAMESPACE_DECL - -#else // !LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT - -#include "src/__support/math/sincosf_utils.h" - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE -#include "src/__support/math/range_reduction_fma.h" -#else // !LIBC_TARGET_CPU_HAS_FMA_DOUBLE -#include "src/__support/math/range_reduction.h" -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - -namespace LIBC_NAMESPACE_DECL { - -namespace math { - -LIBC_INLINE float sinf(float x) { - using namespace sincosf_utils_internal; - using FPBits = typename fputil::FPBits<float>; - FPBits xbits(x); - - uint32_t x_u = xbits.uintval(); - uint32_t x_abs = x_u & 0x7fff'ffffU; - double xd = static_cast<double>(x); - - // Range reduction: - // For |x| > pi/32, we perform range reduction as follows: - // Find k and y such that: - // x = (k + y) * pi/32 - // k is an integer - // |y| < 0.5 - // For small range (|x| < 2^45 when FMA instructions are available, 2^22 - // otherwise), this is done by performing: - // k = round(x * 32/pi) - // y = x * 32/pi - k - // For large range, we will omit all the higher parts of 32/pi such that the - // least significant bits of their full products with x are larger than 63, - // since sin((k + y + 64*i) * pi/32) = sin(x + i * 2pi) = sin(x). - // - // When FMA instructions are not available, we store the digits of 32/pi in - // chunks of 28-bit precision. This will make sure that the products: - // x * THIRTYTWO_OVER_PI_28[i] are all exact. - // When FMA instructions are available, we simply store the digits of 32/pi in - // chunks of doubles (53-bit of precision). - // So when multiplying by the largest values of single precision, the - // resulting output should be correct up to 2^(-208 + 128) ~ 2^-80. By the - // worst-case analysis of range reduction, |y| >= 2^-38, so this should give - // us more than 40 bits of accuracy. For the worst-case estimation of range - // reduction, see for instances: - // Elementary Functions by J-M. Muller, Chapter 11, - // Handbook of Floating-Point Arithmetic by J-M. Muller et. al., - // Chapter 10.2. - // - // Once k and y are computed, we then deduce the answer by the sine of sum - // formula: - // sin(x) = sin((k + y)*pi/32) - // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) - // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed - // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are - // computed using degree-7 and degree-6 minimax polynomials generated by - // Sollya respectively. - - // |x| <= pi/16 - if (LIBC_UNLIKELY(x_abs <= 0x3e49'0fdbU)) { - - // |x| < 0x1.d12ed2p-12f - if (LIBC_UNLIKELY(x_abs < 0x39e8'9769U)) { - if (LIBC_UNLIKELY(x_abs == 0U)) { - // For signed zeros. - return x; - } - // When |x| < 2^-12, the relative error of the approximation sin(x) ~ x - // is: - // |sin(x) - x| / |sin(x)| < |x^3| / (6|x|) - // = x^2 / 6 - // < 2^-25 - // < epsilon(1)/2. - // So the correctly rounded values of sin(x) are: - // = x - sign(x)*eps(x) if rounding mode = FE_TOWARDZERO, - // or (rounding mode = FE_UPWARD and x is - // negative), - // = x otherwise. - // To simplify the rounding decision and make it more efficient, we use - // fma(x, -2^-25, x) instead. - // An exhaustive test shows that this formula work correctly for all - // rounding modes up to |x| < 0x1.c555dep-11f. - // Note: to use the formula x - 2^-25*x to decide the correct rounding, we - // do need fma(x, -2^-25, x) to prevent underflow caused by -2^-25*x when - // |x| < 2^-125. For targets without FMA instructions, we simply use - // double for intermediate results as it is more efficient than using an - // emulated version of FMA. -#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - return fputil::multiply_add(x, -0x1.0p-25f, x); -#else - return static_cast<float>(fputil::multiply_add(xd, -0x1.0p-25, xd)); -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - } - - // |x| < pi/16. - double xsq = xd * xd; - - // Degree-9 polynomial approximation: - // sin(x) ~ x + a_3 x^3 + a_5 x^5 + a_7 x^7 + a_9 x^9 - // = x (1 + a_3 x^2 + ... + a_9 x^8) - // = x * P(x^2) - // generated by Sollya with the following commands: - // > display = hexadecimal; - // > Q = fpminimax(sin(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); - double result = - fputil::polyeval(xsq, 1.0, -0x1.55555555554c6p-3, 0x1.1111111085e65p-7, - -0x1.a019f70fb4d4fp-13, 0x1.718d179815e74p-19); - return static_cast<float>(xd * result); - } - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13 - float r = -0x1.63f4bap-2f; -#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - int rounding = fputil::quick_get_round(); - if ((rounding == FE_DOWNWARD && xbits.is_pos()) || - (rounding == FE_UPWARD && xbits.is_neg())) - r = -0x1.63f4bcp-2f; -#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY - return xbits.is_neg() ? -r : r; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - return x + FPBits::quiet_nan().get_val(); - } - - // Combine the results with the sine of sum formula: - // sin(x) = sin((k + y)*pi/32) - // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) - // = sin_y * cos_k + (1 + cosm1_y) * sin_k - // = sin_y * cos_k + (cosm1_y * sin_k + sin_k) - double sin_k, cos_k, sin_y, cosm1_y; - - sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); - - return static_cast<float>(fputil::multiply_add( - sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); -} - -} // namespace math - } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT +#undef LIBC_MATH_SINF_IMPL #endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_double_eval.h new file mode 100644 index 000000000000..4d4981092219 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_double_eval.h @@ -0,0 +1,182 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Double-precision implementation of sinf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINF_DOUBLE_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINF_DOUBLE_EVAL_H + +#include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA + +#include "src/__support/math/sincosf_utils.h" + +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "src/__support/math/range_reduction_fma.h" +#else // !LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "src/__support/math/range_reduction.h" +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +namespace double_eval { + +LIBC_INLINE float sinf(float x) { + using namespace sincosf_utils_internal; + using FPBits = typename fputil::FPBits<float>; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + double xd = static_cast<double>(x); + + // Range reduction: + // For |x| > pi/32, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * pi/32 + // k is an integer + // |y| < 0.5 + // For small range (|x| < 2^45 when FMA instructions are available, 2^22 + // otherwise), this is done by performing: + // k = round(x * 32/pi) + // y = x * 32/pi - k + // For large range, we will omit all the higher parts of 32/pi such that the + // least significant bits of their full products with x are larger than 63, + // since sin((k + y + 64*i) * pi/32) = sin(x + i * 2pi) = sin(x). + // + // When FMA instructions are not available, we store the digits of 32/pi in + // chunks of 28-bit precision. This will make sure that the products: + // x * THIRTYTWO_OVER_PI_28[i] are all exact. + // When FMA instructions are available, we simply store the digits of 32/pi in + // chunks of doubles (53-bit of precision). + // So when multiplying by the largest values of single precision, the + // resulting output should be correct up to 2^(-208 + 128) ~ 2^-80. By the + // worst-case analysis of range reduction, |y| >= 2^-38, so this should give + // us more than 40 bits of accuracy. For the worst-case estimation of range + // reduction, see for instances: + // Elementary Functions by J-M. Muller, Chapter 11, + // Handbook of Floating-Point Arithmetic by J-M. Muller et. al., + // Chapter 10.2. + // + // Once k and y are computed, we then deduce the answer by the sine of sum + // formula: + // sin(x) = sin((k + y)*pi/32) + // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) + // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed + // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are + // computed using degree-7 and degree-6 minimax polynomials generated by + // Sollya respectively. + + // |x| <= pi/16 + if (LIBC_UNLIKELY(x_abs <= 0x3e49'0fdbU)) { + + // |x| < 0x1.d12ed2p-12f + if (LIBC_UNLIKELY(x_abs < 0x39e8'9769U)) { + if (LIBC_UNLIKELY(x_abs == 0U)) { + // For signed zeros. + return x; + } + // When |x| < 2^-12, the relative error of the approximation sin(x) ~ x + // is: + // |sin(x) - x| / |sin(x)| < |x^3| / (6|x|) + // = x^2 / 6 + // < 2^-25 + // < epsilon(1)/2. + // So the correctly rounded values of sin(x) are: + // = x - sign(x)*eps(x) if rounding mode = FE_TOWARDZERO, + // or (rounding mode = FE_UPWARD and x is + // negative), + // = x otherwise. + // To simplify the rounding decision and make it more efficient, we use + // fma(x, -2^-25, x) instead. + // An exhaustive test shows that this formula work correctly for all + // rounding modes up to |x| < 0x1.c555dep-11f. + // Note: to use the formula x - 2^-25*x to decide the correct rounding, we + // do need fma(x, -2^-25, x) to prevent underflow caused by -2^-25*x when + // |x| < 2^-125. For targets without FMA instructions, we simply use + // double for intermediate results as it is more efficient than using an + // emulated version of FMA. +#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + return fputil::multiply_add(x, -0x1.0p-25f, x); +#else + return static_cast<float>(fputil::multiply_add(xd, -0x1.0p-25, xd)); +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + } + + // |x| < pi/16. + double xsq = xd * xd; + + // Degree-9 polynomial approximation: + // sin(x) ~ x + a_3 x^3 + a_5 x^5 + a_7 x^7 + a_9 x^9 + // = x (1 + a_3 x^2 + ... + a_9 x^8) + // = x * P(x^2) + // generated by Sollya with the following commands: + // > display = hexadecimal; + // > Q = fpminimax(sin(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); + double result = + fputil::polyeval(xsq, 1.0, -0x1.55555555554c6p-3, 0x1.1111111085e65p-7, + -0x1.a019f70fb4d4fp-13, 0x1.718d179815e74p-19); + return static_cast<float>(xd * result); + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13 + float r = -0x1.63f4bap-2f; +#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + int rounding = fputil::quick_get_round(); + if ((rounding == FE_DOWNWARD && xbits.is_pos()) || + (rounding == FE_UPWARD && xbits.is_neg())) + r = -0x1.63f4bcp-2f; +#endif // !LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY + return xbits.is_neg() ? -r : r; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + // Combine the results with the sine of sum formula: + // sin(x) = sin((k + y)*pi/32) + // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) + // = sin_y * cos_k + (1 + cosm1_y) * sin_k + // = sin_y * cos_k + (cosm1_y * sin_k + sin_k) + double sin_k, cos_k, sin_y, cosm1_y; + + sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); + + return static_cast<float>(fputil::multiply_add( + sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); +} + +} // namespace double_eval +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINF_DOUBLE_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_float_eval.h new file mode 100644 index 000000000000..cfb137044389 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/sinf_float_eval.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Float-only implementation of sinf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINF_FLOAT_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINF_FLOAT_EVAL_H + +#include "sincosf_float_eval.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace float_eval { + +LIBC_INLINE float sinf(float x) { + return sincosf_float_eval::sincosf_eval</*IS_SIN*/ true>(x); +} + +} // namespace float_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINF_FLOAT_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf.h index 3a1d8e8bd53b..90a717e5cbe6 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf.h @@ -1,165 +1,42 @@ -//===-- Single-precision tan function -------------------------------------===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation selector for tanf. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANF_H #define LLVM_LIBC_SRC___SUPPORT_MATH_TANF_H -#include "sincosf_utils.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" + +#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ + (defined(LIBC_MATH_HAS_SMALL_TABLES) || \ + defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT)) && \ + defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) +#include "src/__support/math/tanf_float_eval.h" +#define LIBC_MATH_TANF_IMPL float_eval +#else +#include "src/__support/math/tanf_double_eval.h" +#define LIBC_MATH_TANF_IMPL double_eval +#endif namespace LIBC_NAMESPACE_DECL { - namespace math { -namespace tanf_internal { - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Exceptional cases for tanf. -LIBC_INLINE_VAR constexpr size_t N_EXCEPTS = 6; - -LIBC_INLINE_VAR constexpr fputil::ExceptValues<float, N_EXCEPTS> TANF_EXCEPTS{{ - // (inputs, RZ output, RU offset, RD offset, RN offset) - // x = 0x1.ada6aap27, tan(x) = 0x1.e80304p-3 (RZ) - {0x4d56d355, 0x3e740182, 1, 0, 0}, - // x = 0x1.862064p33, tan(x) = -0x1.8dee56p-3 (RZ) - {0x50431032, 0xbe46f72b, 0, 1, 1}, - // x = 0x1.af61dap48, tan(x) = 0x1.60d1c6p-2 (RZ) - {0x57d7b0ed, 0x3eb068e3, 1, 0, 1}, - // x = 0x1.0088bcp52, tan(x) = 0x1.ca1edp0 (RZ) - {0x5980445e, 0x3fe50f68, 1, 0, 0}, - // x = 0x1.f90dfcp72, tan(x) = 0x1.597f9cp-1 (RZ) - {0x63fc86fe, 0x3f2cbfce, 1, 0, 0}, - // x = 0x1.a6ce12p86, tan(x) = -0x1.c5612ep-1 (RZ) - {0x6ad36709, 0xbf62b097, 0, 1, 0}, -}}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -} // namespace tanf_internal - -LIBC_INLINE float tanf(float x) { - using namespace sincosf_utils_internal; - using namespace tanf_internal; - using FPBits = typename fputil::FPBits<float>; - FPBits xbits(x); - uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU; - - // |x| < pi/32 - if (LIBC_UNLIKELY(x_abs <= 0x3dc9'0fdbU)) { - double xd = static_cast<double>(x); - - // |x| < 0x1.0p-12f - if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { - if (LIBC_UNLIKELY(x_abs == 0U)) { - // For signed zeros. - return x; - } - // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x - // is: - // |tan(x) - x| / |tan(x)| < |x^3| / (3|x|) - // = x^2 / 3 - // < 2^-25 - // < epsilon(1)/2. - // So the correctly rounded values of tan(x) are: - // = x + sign(x)*eps(x) if rounding mode = FE_UPWARD and x is positive, - // or (rounding mode = FE_DOWNWARD and x is - // negative), - // = x otherwise. - // To simplify the rounding decision and make it more efficient, we use - // fma(x, 2^-25, x) instead. - // Note: to use the formula x + 2^-25*x to decide the correct rounding, we - // do need fma(x, 2^-25, x) to prevent underflow caused by 2^-25*x when - // |x| < 2^-125. For targets without FMA instructions, we simply use - // double for intermediate results as it is more efficient than using an - // emulated version of FMA. -#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - return fputil::multiply_add(x, 0x1.0p-25f, x); -#else - return static_cast<float>(fputil::multiply_add(xd, 0x1.0p-25, xd)); -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - } - - // |x| < pi/32 - double xsq = xd * xd; - - // Degree-9 minimax odd polynomial of tan(x) generated by Sollya with: - // > P = fpminimax(tan(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); - double result = - fputil::polyeval(xsq, 1.0, 0x1.555555553d022p-2, 0x1.111111ce442c1p-3, - 0x1.ba180a6bbdecdp-5, 0x1.69c0a88a0b71fp-6); - return static_cast<float>(xd * result); - } - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - bool x_sign = xbits.uintval() >> 31; - // Check for exceptional values - if (LIBC_UNLIKELY(x_abs == 0x3f8a1f62U)) { - // |x| = 0x1.143ec4p0 - float sign = x_sign ? -1.0f : 1.0f; - - // volatile is used to prevent compiler (gcc) from optimizing the - // computation, making the results incorrect in different rounding modes. - volatile float tmp = 0x1.ddf9f4p0f; - tmp = fputil::multiply_add(sign, tmp, sign * 0x1.1p-24f); - - return tmp; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // |x| > 0x1.ada6a8p+27f - if (LIBC_UNLIKELY(x_abs > 0x4d56'd354U)) { - // Inf or NaN - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - return x + FPBits::quiet_nan().get_val(); - } -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Other large exceptional values - if (auto r = TANF_EXCEPTS.lookup_odd(x_abs, x_sign); - LIBC_UNLIKELY(r.has_value())) - return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - } - - // For |x| >= pi/32, we use the definition of tan(x) function: - // tan(x) = sin(x) / cos(x) - // The we follow the same computations of sin(x) and cos(x) as sinf, cosf, - // and sincosf. - - double xd = static_cast<double>(x); - double sin_k, cos_k, sin_y, cosm1_y; - - sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); - // tan(x) = sin(x) / cos(x) - // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k) - using fputil::multiply_add; - return static_cast<float>( - multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) / - multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k))); -} +using LIBC_MATH_TANF_IMPL::tanf; } // namespace math - } // namespace LIBC_NAMESPACE_DECL +#undef LIBC_MATH_TANF_IMPL + #endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_double_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_double_eval.h new file mode 100644 index 000000000000..e5ef67ed0d15 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_double_eval.h @@ -0,0 +1,172 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Double-precision implementation of tanf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANF_DOUBLE_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_TANF_DOUBLE_EVAL_H + +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/__support/math/sincosf_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +namespace double_eval { + +namespace tanf_internal { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// Exceptional cases for tanf. +LIBC_INLINE_VAR constexpr size_t N_EXCEPTS = 6; + +LIBC_INLINE_VAR constexpr fputil::ExceptValues<float, N_EXCEPTS> TANF_EXCEPTS{{ + // (inputs, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.ada6aap27, tan(x) = 0x1.e80304p-3 (RZ) + {0x4d56d355, 0x3e740182, 1, 0, 0}, + // x = 0x1.862064p33, tan(x) = -0x1.8dee56p-3 (RZ) + {0x50431032, 0xbe46f72b, 0, 1, 1}, + // x = 0x1.af61dap48, tan(x) = 0x1.60d1c6p-2 (RZ) + {0x57d7b0ed, 0x3eb068e3, 1, 0, 1}, + // x = 0x1.0088bcp52, tan(x) = 0x1.ca1edp0 (RZ) + {0x5980445e, 0x3fe50f68, 1, 0, 0}, + // x = 0x1.f90dfcp72, tan(x) = 0x1.597f9cp-1 (RZ) + {0x63fc86fe, 0x3f2cbfce, 1, 0, 0}, + // x = 0x1.a6ce12p86, tan(x) = -0x1.c5612ep-1 (RZ) + {0x6ad36709, 0xbf62b097, 0, 1, 0}, +}}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace tanf_internal + +LIBC_INLINE float tanf(float x) { + using namespace sincosf_utils_internal; + using namespace tanf_internal; + using FPBits = typename fputil::FPBits<float>; + FPBits xbits(x); + uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU; + + // |x| < pi/32 + if (LIBC_UNLIKELY(x_abs <= 0x3dc9'0fdbU)) { + double xd = static_cast<double>(x); + + // |x| < 0x1.0p-12f + if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { + if (LIBC_UNLIKELY(x_abs == 0U)) { + // For signed zeros. + return x; + } + // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x + // is: + // |tan(x) - x| / |tan(x)| < |x^3| / (3|x|) + // = x^2 / 3 + // < 2^-25 + // < epsilon(1)/2. + // So the correctly rounded values of tan(x) are: + // = x + sign(x)*eps(x) if rounding mode = FE_UPWARD and x is positive, + // or (rounding mode = FE_DOWNWARD and x is + // negative), + // = x otherwise. + // To simplify the rounding decision and make it more efficient, we use + // fma(x, 2^-25, x) instead. + // Note: to use the formula x + 2^-25*x to decide the correct rounding, we + // do need fma(x, 2^-25, x) to prevent underflow caused by 2^-25*x when + // |x| < 2^-125. For targets without FMA instructions, we simply use + // double for intermediate results as it is more efficient than using an + // emulated version of FMA. +#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + return fputil::multiply_add(x, 0x1.0p-25f, x); +#else + return static_cast<float>(fputil::multiply_add(xd, 0x1.0p-25, xd)); +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + } + + // |x| < pi/32 + double xsq = xd * xd; + + // Degree-9 minimax odd polynomial of tan(x) generated by Sollya with: + // > P = fpminimax(tan(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); + double result = + fputil::polyeval(xsq, 1.0, 0x1.555555553d022p-2, 0x1.111111ce442c1p-3, + 0x1.ba180a6bbdecdp-5, 0x1.69c0a88a0b71fp-6); + return static_cast<float>(xd * result); + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + bool x_sign = xbits.uintval() >> 31; + // Check for exceptional values + if (LIBC_UNLIKELY(x_abs == 0x3f8a1f62U)) { + // |x| = 0x1.143ec4p0 + float sign = x_sign ? -1.0f : 1.0f; + + // volatile is used to prevent compiler (gcc) from optimizing the + // computation, making the results incorrect in different rounding modes. + volatile float tmp = 0x1.ddf9f4p0f; + tmp = fputil::multiply_add(sign, tmp, sign * 0x1.1p-24f); + + return tmp; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // |x| > 0x1.ada6a8p+27f + if (LIBC_UNLIKELY(x_abs > 0x4d56'd354U)) { + // Inf or NaN + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Other large exceptional values + if (auto r = TANF_EXCEPTS.lookup_odd(x_abs, x_sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + } + + // For |x| >= pi/32, we use the definition of tan(x) function: + // tan(x) = sin(x) / cos(x) + // The we follow the same computations of sin(x) and cos(x) as sinf, cosf, + // and sincosf. + + double xd = static_cast<double>(x); + double sin_k, cos_k, sin_y, cosm1_y; + + sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); + // tan(x) = sin(x) / cos(x) + // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k) + using fputil::multiply_add; + return static_cast<float>( + multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) / + multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k))); +} + +} // namespace double_eval +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANF_DOUBLE_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_float_eval.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_float_eval.h new file mode 100644 index 000000000000..27f49c8e35bb --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanf_float_eval.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Float-only implementation of tanf. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANF_FLOAT_EVAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_TANF_FLOAT_EVAL_H + +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/math/sincosf_float_eval.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { +namespace float_eval { + +// Float-only tanf, requiring FMA. The maximum error, checked exhaustively in +// round-to-nearest mode against MPFR, is 3.37 ULP. +LIBC_INLINE float tanf(float x) { + using namespace sincosf_float_eval; + using FPBits = fputil::FPBits<float>; + FPBits xbits(x); + uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU; + + // |x| < 2^-12 + if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { + // For signed zeros. + if (LIBC_UNLIKELY(x_abs == 0U)) + return x; + // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x is: + // |tan(x) - x| / |tan(x)| < x^2 / 3 < 2^-25 < epsilon(1)/2. + // fma(x, 2^-25, x) gives the correctly rounded result in all rounding modes + // without underflowing for subnormal x. + return fputil::multiply_add(x, 0x1.0p-25f, x); + } + + float y; + unsigned k; + if (x_abs < 0x4880'0000U) { + k = sincosf_range_reduction_small(x, y); + } else { + // Inf or NaN + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + k = sincosf_range_reduction_large(x, y); + } + + // x = k * pi/8 + y with |y| <= pi/16. + float sin_k = SIN_K_PI_OVER_8[k & 15]; + // cos(k * pi/8) = sin((k + 4) * pi/8). + float cos_k = SIN_K_PI_OVER_8[(k + 4) & 15]; + + // Taylor polynomial of tan(y) for |y| <= pi/16: + // tan(y) ~ y + y^3/3 + 2y^5/15 + 17y^7/315 + 62y^9/2835. + // The coefficients of tan's Taylor series decrease by a factor of about + // (2/pi)^2 per term, so the relative truncation error is bounded by: + // 1.02 * 1382/155925 * (pi/16)^10 < 2^-30. + float y_sq = y * y; + float y3 = y_sq * y; + float p = fputil::multiply_add(y_sq, 0x1.664f48p-6f, 0x1.ba1ba2p-5f); + p = fputil::multiply_add(y_sq, p, 0x1.111112p-3f); + p = fputil::multiply_add(y_sq, p, 0x1.555556p-2f); + // t ~ tan(y) + float t = fputil::multiply_add(y3, p, y); + + // tan(x) = sin(x) / cos(x) + // = (sin_k * cos(y) + cos_k * sin(y)) / + // (cos_k * cos(y) - sin_k * sin(y)) + // = (sin_k + cos_k * tan(y)) / (cos_k - sin_k * tan(y)). + // Cancellation can only happen in the numerator when k = 0 (mod 8) and in + // the denominator when k = 4 (mod 8). In those cases, sin_k or cos_k is + // exactly 0 respectively, so the remaining term is computed with a small + // relative error. + float num = fputil::multiply_add(cos_k, t, sin_k); + float den = fputil::multiply_add(-sin_k, t, cos_k); + return num / den; +} + +} // namespace float_eval +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANF_FLOAT_EVAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif.h index 114fcb6053d3..99eec84c8661 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif.h @@ -14,6 +14,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/is_integer.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" @@ -41,43 +42,46 @@ LIBC_INLINE float tanpif(float x) { uint32_t x_u = xbits.uintval(); uint32_t x_abs = x_u & 0x7fff'ffffU; - double xd = static_cast<double>(xbits.get_val()); - // Handle exceptional values - if (LIBC_UNLIKELY(x_abs <= 0x3F3663FF)) { - if (LIBC_UNLIKELY(x_abs == 0U)) - return x; + // Handle NaN and Inf. + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + + return x + FPBits::quiet_nan().get_val(); + } + + // Handle signed zeros. + if (LIBC_UNLIKELY(x_abs == 0U)) + return x; + + if (LIBC_UNLIKELY(fputil::is_integer(x))) { + // Preserve the input sign for even integers and flip it for odd integers. + Sign sign = + fputil::is_odd_integer(x) ? xbits.sign().negate() : xbits.sign(); + return FPBits::zero(sign).get_val(); + } #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Handle exceptional values. + if (LIBC_UNLIKELY(x_abs <= 0x3F3663FF)) { bool x_sign = x_u >> 31; if (auto r = TANPIF_EXCEPTS.lookup_odd(x_abs, x_sign); LIBC_UNLIKELY(r.has_value())) return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - } - - // Numbers greater or equal to 2^23 are always integers, or infinity, or NaN - if (LIBC_UNLIKELY(x_abs >= 0x4B00'0000)) { - // x is inf or NaN. - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - - return x + FPBits::quiet_nan().get_val(); - } - - return FPBits::zero(xbits.sign()).get_val(); } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS // Range reduction: + // All remaining inputs are finite nonintegers, so |x| < 2^23. // For |x| > 1/32, we perform range reduction as follows: // Find k and y such that: // x = (k + y) * 1/32 @@ -91,6 +95,7 @@ LIBC_INLINE float tanpif(float x) { // Once k and y are computed, we then deduce the answer by the formula: // tan(x) = sin(x) / cos(x) // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k) + double xd = static_cast<double>(x); double sin_k, cos_k, sin_y, cosm1_y; sincospif_eval(xd, sin_k, cos_k, sin_y, cosm1_y); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif16.h b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif16.h index dff6b518cc95..bec8c17f2f0c 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif16.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/math/tanpif16.h @@ -20,6 +20,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/is_integer.h" #include "src/__support/FPUtil/multiply_add.h" #include "src/__support/macros/optimization.h" @@ -34,12 +35,34 @@ LIBC_INLINE float16 tanpif16(float16 x) { uint16_t x_u = xbits.uintval(); uint16_t x_abs = x_u & 0x7fff; - // Handle exceptional values - if (LIBC_UNLIKELY(x_abs <= 0x4335)) { - if (LIBC_UNLIKELY(x_abs == 0U)) - return x; + // Handle NaN and Inf. + if (LIBC_UNLIKELY(x_abs >= 0x7c00)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + if (x_abs == 0x7c00) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + + return x + FPBits::quiet_nan().get_val(); + } + + // Handle signed zeros. + if (LIBC_UNLIKELY(x_abs == 0U)) + return x; + + if (LIBC_UNLIKELY(fputil::is_integer(x))) { + // Preserve the input sign for even integers and flip it for odd integers. + Sign sign = + fputil::is_odd_integer(x) ? xbits.sign().negate() : xbits.sign(); + return FPBits::zero(sign).get_val(); + } #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Handle exceptional values. + if (LIBC_UNLIKELY(x_abs <= 0x4335)) { constexpr size_t N_EXCEPTS = 21; constexpr fputil::ExceptValues<float16, N_EXCEPTS> TANPIF16_EXCEPTS{{ @@ -62,29 +85,11 @@ LIBC_INLINE float16 tanpif16(float16 x) { if (auto r = TANPIF16_EXCEPTS.lookup_odd(x_abs, x_sign); LIBC_UNLIKELY(r.has_value())) return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Numbers greater or equal to 2^10 are integers, or infinity, or NaN - if (LIBC_UNLIKELY(x_abs >= 0x6400)) { - // Check for NaN or infinity values - if (LIBC_UNLIKELY(x_abs >= 0x7c00)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - // is inf - if (x_abs == 0x7c00) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - - return x + FPBits::quiet_nan().get_val(); - } - - return FPBits::zero(xbits.sign()).get_val(); - } // Range reduction: + // All remaining inputs are finite nonintegers, so |x| < 2^10. // For |x| > 1/32, we perform range reduction as follows: // Find k and y such that: // x = (k + y) * 1/32 diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/CMakeLists.txt index 431ad79f1050..dba7b6baba3d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/CMakeLists.txt @@ -87,7 +87,8 @@ add_header_library( cosf.h DEPENDS libc.src.__support.CPP.simd - libc.src.__support.math.cosf + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.properties.cpu_features ) add_header_library( diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acosf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acosf.h index 6e6f0314900d..2ee24d77b949 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acosf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acosf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD acos. +/// This file contains the implementation for single-precision SIMD acos. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acoshf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acoshf.h index 5bbb00aac43b..3b39396e10ac 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acoshf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acoshf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD acosh. +/// This file contains the implementation for single-precision SIMD acosh. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acospif.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acospif.h index 55252f427141..7e7d97b539ca 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acospif.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/acospif.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD acospi. +/// This file contains the implementation for single-precision SIMD acospi. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinf.h index d06df07e5a9a..e9ee5a3850db 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD asin. +/// This file contains the implementation for single-precision SIMD asin. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinhf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinhf.h index 82e6dc69406d..559ced53fe80 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinhf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinhf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD asinh. +/// This file contains the implementation for single-precision SIMD asinh. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinpif.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinpif.h index 4ee9d0df1ea5..40a70f835426 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinpif.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/asinpif.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD asinpi. +/// This file contains the implementation for single-precision SIMD asinpi. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanf.h index 37ad933c9977..6af4d3a9bcc9 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD atan. +/// This file contains the implementation for single-precision SIMD atan. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanhf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanhf.h index 6d0e238d2d79..043df313d6f8 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanhf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/atanhf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD atanh. +/// This file contains the implementation for single-precision SIMD atanh. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cbrtf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cbrtf.h index 835ff2242002..d3e9a02a5df7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cbrtf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cbrtf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD cbrt. +/// This file contains the implementation for single-precision SIMD cbrt. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/common_constants.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/common_constants.h index 89d9c3903d28..e0e41cfd5fb4 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/common_constants.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/common_constants.h @@ -38,6 +38,66 @@ LIBC_INLINE_VAR constexpr uint64_t EXP_MANTISSA[64] = { 0xea4afa2a490da, 0xefa1bee615a27, 0xf50765b6e4540, 0xfa7c1819e90d8, }; +// Lookup table for log(1 / R[i]), where R is the reciprocal from the table +// found in libc/src/__support/math/common_constants.h, specifically optimised +// for mathvec RN. There are two main differences: +// 1. The final entry has LOG_TABLE[127] = log(2), rather than 0 in the scalar +// table. +// 2. Some values in the table are adjusted to remove hard-to-round cases, +// making the main computation path branchless. +// The following adjustments are made, in FP64 ULP: +// LOG_TABLE[23] -15 +// LOG_TABLE[49] +47 +// LOG_TABLE[65] +2 +// LOG_TABLE[88] +51 +// LOG_TABLE[93] +21 +// LOG_TABLE[96] +3 +// LOG_TABLE[101] -2 +LIBC_INLINE_VAR constexpr double LOG_TABLE[128] = { + 0x0.0000000000000p+0, 0x1.010157588de71p-7, 0x1.0205658935847p-6, + 0x1.8492528c8cabfp-6, 0x1.0415d89e74444p-5, 0x1.466aed42de3eap-5, + 0x1.894aa149fb343p-5, 0x1.ccb73cdddb2ccp-5, 0x1.08598b59e3a07p-4, + 0x1.1973bd1465567p-4, 0x1.3bdf5a7d1ee64p-4, 0x1.5e95a4d9791cbp-4, + 0x1.700d30aeac0e1p-4, 0x1.9335e5d594989p-4, 0x1.b6ac88dad5b1cp-4, + 0x1.c885801bc4b23p-4, 0x1.ec739830a1120p-4, 0x1.fe89139dbd566p-4, + 0x1.1178e8227e47cp-3, 0x1.1aa2b7e23f72ap-3, 0x1.2d1610c86813ap-3, + 0x1.365fcb0159016p-3, 0x1.4913d8333b561p-3, 0x1.527e5e4a1b57ep-3, + 0x1.6574ebe8c133ap-3, 0x1.6f0128b756abcp-3, 0x1.823c16551a3c2p-3, + 0x1.8beafeb38fe8cp-3, 0x1.95a5adcf7017fp-3, 0x1.a93ed3c8ad9e3p-3, + 0x1.b31d8575bce3dp-3, 0x1.bd087383bd8adp-3, 0x1.d1037f2655e7bp-3, + 0x1.db13db0d48940p-3, 0x1.e530effe71012p-3, 0x1.ef5ade4dcffe6p-3, + 0x1.f991c6cb3b379p-3, 0x1.07138604d5862p-2, 0x1.0c42d676162e3p-2, + 0x1.1178e8227e47cp-2, 0x1.16b5ccbacfb73p-2, 0x1.1bf99635a6b95p-2, + 0x1.269621134db92p-2, 0x1.2bef07cdc9354p-2, 0x1.314f1e1d35ce4p-2, + 0x1.36b6776be1117p-2, 0x1.3c25277333184p-2, 0x1.419b423d5e8c7p-2, + 0x1.4718dc271c41bp-2, 0x1.4c9e09e172c6bp-2, 0x1.522ae0738a3d8p-2, + 0x1.57bf753c8d1fbp-2, 0x1.5d5bddf595f30p-2, 0x1.630030b3aac49p-2, + 0x1.68ac83e9c6a14p-2, 0x1.6e60ee6af1972p-2, 0x1.741d876c67bb1p-2, + 0x1.79e26687cfb3ep-2, 0x1.7fafa3bd8151cp-2, 0x1.85855776dcbfbp-2, + 0x1.8b639a88b2df5p-2, 0x1.914a8635bf68ap-2, 0x1.973a3431356aep-2, + 0x1.9d32bea15ed3bp-2, 0x1.a33440224fa79p-2, 0x1.a33440224fa7bp-2, + 0x1.a93ed3c8ad9e3p-2, 0x1.af5295248cdd0p-2, 0x1.b56fa04462909p-2, + 0x1.bb9611b80e2fbp-2, 0x1.c1c60693fa39ep-2, 0x1.c1c60693fa39ep-2, + 0x1.c7ff9c74554c9p-2, 0x1.ce42f18064743p-2, 0x1.d490246defa6bp-2, + 0x1.dae75484c9616p-2, 0x1.e148a1a2726cep-2, 0x1.e148a1a2726cep-2, + 0x1.e7b42c3ddad73p-2, 0x1.ee2a156b413e5p-2, 0x1.f4aa7ee03192dp-2, + 0x1.f4aa7ee03192dp-2, 0x1.fb358af7a4884p-2, 0x1.00e5ae5b207abp-1, + 0x1.04360be7603adp-1, 0x1.04360be7603adp-1, 0x1.078bf0533c568p-1, + 0x1.0ae76e2d054fap-1, 0x1.0ae76e2d0552dp-1, 0x1.0e4898611cce1p-1, + 0x1.11af823c75aa8p-1, 0x1.11af823c75aa8p-1, 0x1.151c3f6f29612p-1, + 0x1.188ee40f23cbbp-1, 0x1.188ee40f23ca6p-1, 0x1.1c07849ae6007p-1, + 0x1.1f8635fc6165cp-1, 0x1.1f8635fc61659p-1, 0x1.230b0d8bebc98p-1, + 0x1.269621134db92p-1, 0x1.269621134db92p-1, 0x1.2a2786d0ec105p-1, + 0x1.2dbf557b0df43p-1, 0x1.2dbf557b0df43p-1, 0x1.315da4434068bp-1, + 0x1.315da4434068bp-1, 0x1.35028ad9d8c86p-1, 0x1.38ae2171976e7p-1, + 0x1.38ae2171976e7p-1, 0x1.3c6080c36bfb5p-1, 0x1.3c6080c36bfb5p-1, + 0x1.4019c2125ca93p-1, 0x1.43d9ff2f923c5p-1, 0x1.43d9ff2f923c5p-1, + 0x1.47a1527e8a2d3p-1, 0x1.47a1527e8a2d3p-1, 0x1.4b6fd6f970c1fp-1, + 0x1.4b6fd6f970c1fp-1, 0x1.4f45a835a4e19p-1, 0x1.4f45a835a4e19p-1, + 0x1.5322e26867857p-1, 0x1.5322e26867857p-1, 0x1.5707a26bb8c66p-1, + 0x1.5707a26bb8c66p-1, 0x1.5af405c3649e0p-1, 0x1.5af405c3649e0p-1, + 0x1.5ee82aa241920p-1, 0x1.62e42fefa39eep-1}; + } // namespace mathvec } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cosf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cosf.h index b6ea0c848afd..7e1d99c01282 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cosf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cosf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD cos. +/// This file contains the implementation for single-precision SIMD cos. /// //===----------------------------------------------------------------------===// @@ -15,18 +15,132 @@ #define LLVM_LIBC_SRC___SUPPORT_MATHVEC_COSF_H #include "src/__support/CPP/simd.h" -#define LIBC_MATH_HAS_NO_ERRNO -#define LIBC_MATH_HAS_NO_EXCEPT -#define LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY -#include "src/__support/math/cosf.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/properties/cpu_features.h" + +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "src/__support/mathvec/trig_reductionf.h" +#else +#include "src/__support/mathvec/trig_reductionf_nofma.h" +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE namespace LIBC_NAMESPACE_DECL { namespace mathvec { +template <size_t N> +LIBC_INLINE static cpp::simd<double, N> cospif_poly(cpp::simd<double, N> r) { + // Approximate cos(pi * r) as (1/4 - r^2) * P(r^2) for |r| <= 0.5. + // These coefficients aren't produced directly via sollya, but rather + // are fine-tuned by iterative adjustment to remove hard to round cases. + // TODO: Create a tool to deterministically reproduce these coefficients. + // see https://github.com/llvm/llvm-project/issues/220984 + constexpr cpp::simd<double, N> c0 = 0x1p2; + constexpr cpp::simd<double, N> c1 = -0x1.de9e64df22f07p1; + constexpr cpp::simd<double, N> c2 = 0x1.472be1223eeadp0; + constexpr cpp::simd<double, N> c3 = -0x1.d4fcd82b511ebp-3; + constexpr cpp::simd<double, N> c4 = 0x1.9f05c866286ddp-6; + constexpr cpp::simd<double, N> c5 = -0x1.f308c07837812p-10; + constexpr cpp::simd<double, N> c6 = 0x1.b22004be59c73p-14; + constexpr cpp::simd<double, N> c7 = -0x1.14bd54572305fp-18; + constexpr cpp::simd<double, N> f = 0.25; + + cpp::simd<double, N> r2 = r * r; + cpp::simd<double, N> r4 = r2 * r2; + cpp::simd<double, N> p01 = cpp::multiply_add(r2, c1, c0); + cpp::simd<double, N> p23 = cpp::multiply_add(r2, c3, c2); + cpp::simd<double, N> p45 = cpp::multiply_add(r2, c5, c4); + cpp::simd<double, N> p67 = cpp::multiply_add(r2, c7, c6); + cpp::simd<double, N> p47 = cpp::multiply_add(r4, p67, p45); + cpp::simd<double, N> p27 = cpp::multiply_add(r4, p47, p23); + cpp::simd<double, N> p07 = cpp::multiply_add(r4, p27, p01); + + cpp::simd<double, N> factor = cpp::multiply_add(-r, r, f); + + return factor * p07; +} + +// Correct specific cases which aren't able to correctly round from the normal +// codepath. +template <size_t N> +LIBC_INLINE static cpp::simd<float, N> +repair_hard_to_round(cpp::simd<float, N> x, cpp::simd<float, N> y) { + y = (x == 0x1.fcd9eep+38f) ? 0x1.3371d2p-17f : y; + y = (x == 0x1.3170f0p+63f) ? 0x1.fe2976p-1f : y; + y = (x == 0x1.15313ep+69f) ? 0x1.f52484p-20f : y; + +#ifndef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + y = (x == 0x1.8db252p+25f) ? -0x1.527a0ap-5f : y; + y = (x == 0x1.aff73cp+32f) ? -0x1.d59e7ap-23f : y; + y = (x == 0x1.47d0fep+34f) ? -0x1.149dbp-29f : y; + y = (x == 0x1.455500p+51f) ? 0x1.115d7ep-1f : y; + y = (x == 0x1.407c74p+100f) ? 0x1.a4a122p-19f : y; +#endif + + return y; +} + +// Due to specific lane correction being expensive, we can perform a fast +// estimated check to determine if we should branch to specific hard to round +// case correction. Will return true for all hard to round cases, but can +// produce false positives. False positive rate in [0x1.90bdfap+20f, inf]: +// With FMA: 52/901,226,755 ~= 1/2^24 +// Without FMA: 7,040,869/901,226,755 ~= 1/2^7 +template <size_t N> +LIBC_INLINE static cpp::simd<bool, N> +is_maybe_hard_to_round(cpp::simd<float, N> x) { + cpp::simd<uint32_t, N> x_bits = cpp::bit_cast<cpp::simd<uint32_t>>(x); +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + return ((x_bits * 0xd6c4de5f) & 0xefffda56) == 0x46048000; +#else + return ((x_bits * 0x30d04f5f) & 0x8b002240) == 0x8002000; +#endif +} + template <size_t N> LIBC_INLINE cpp::simd<float, N> cosf(cpp::simd<float, N> x) { - return cpp::map(x, [](float a) { return math::cosf(a); }); + using FPBits = typename fputil::FPBits<float>; + cpp::simd<double, N> x_d = cpp::simd_cast<double>(x); + cpp::simd<float, N> ax = cpp::abs(x); + + // If all lanes are below pi/2, we can skip the reduction entirely. + cpp::simd<bool, N> is_small = ax <= 0x1.921fb6p+0f; + if (cpp::all_of(is_small)) { + constexpr cpp::simd<double, N> inv_pi = 0x1.45f306dc9c883p-2; + return cpp::simd_cast<float>(cospif_poly(x_d * inv_pi)); + } + + // Computes the main reduction pass + Reduction<N> reduce = fast_reduction(x_d); + + // Large inputs require a more involved reduction, as well as inf handling. + cpp::simd<bool, N> has_large_reduction = ax > 0x1.90bdfap+20f; + if (LIBC_UNLIKELY(cpp::any_of(has_large_reduction))) { + cpp::simd<bool, N> is_finite = ax < FPBits::inf().get_val(); + Reduction<N> large_reduce = large_reduction(x_d); + reduce.r = has_large_reduction ? large_reduce.r : reduce.r; + reduce.r = is_finite ? reduce.r : FPBits::quiet_nan().get_val(); + reduce.odd = has_large_reduction ? large_reduce.odd : reduce.odd; + } + + // Both reduction paths feed into a single polynomial evaluation + sign + // correction. + cpp::simd<float, N> poly = cpp::simd_cast<float>(cospif_poly(reduce.r)); + cpp::simd<uint32_t, N> sign = cpp::simd_cast<uint32_t>(reduce.odd) << 31; + + cpp::simd<float, N> y = cpp::bit_cast<cpp::simd<float>>( + cpp::bit_cast<cpp::simd<uint32_t>>(poly) ^ sign); + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#ifndef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + y = (ax == 0x1.d2eb54p+10) ? -0x1.633eb4p-13 : y; +#endif + if (LIBC_UNLIKELY(cpp::any_of(has_large_reduction))) { + if (LIBC_UNLIKELY(cpp::any_of(is_maybe_hard_to_round(ax)))) + return repair_hard_to_round(ax, y); + } +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + return y; } } // namespace mathvec diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/coshf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/coshf.h index d5a5c0ebf1f9..7fe5d266ffa7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/coshf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/coshf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD cosh. +/// This file contains the implementation for single-precision SIMD cosh. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cospif.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cospif.h index d638eff6d530..b24c0a3bd2c5 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cospif.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/cospif.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD cospi. +/// This file contains the implementation for single-precision SIMD cospi. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/erff.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/erff.h index 6b272013bf90..5b0782c08849 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/erff.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/erff.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD erf. +/// This file contains the implementation for single-precision SIMD erf. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10f.h index d22baf16b40a..09df5d87bc0e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD exp10. +/// This file contains the implementation for single-precision SIMD exp10. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10m1f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10m1f.h index 07f338ff6e82..67b968fcea13 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10m1f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp10m1f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD exp10m1. +/// This file contains the implementation for single-precision SIMD exp10m1. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2f.h index 848b9647dd61..eb73ce1c94e8 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD exp2. +/// This file contains the implementation for single-precision SIMD exp2. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2m1f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2m1f.h index b4ae0f6639e6..44bd4a667603 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2m1f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/exp2m1f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD exp2m1. +/// This file contains the implementation for single-precision SIMD exp2m1. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expf.h index 95f5a5dc7687..b78e99ada592 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD exp. +/// This file contains the implementation for single-precision SIMD exp. /// //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATHVEC_EXPF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expm1f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expm1f.h index 9e16a5a802b2..edf98a0ea36d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expm1f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/expm1f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD expm1. +/// This file contains the implementation for single-precision SIMD expm1. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log10f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log10f.h index 48c15bd7041a..616a7a1ff24b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log10f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log10f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD log10. +/// This file contains the implementation for single-precision SIMD log10. /// //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATHVEC_LOG10F_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log1pf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log1pf.h index ed097c0dcc6f..f58db55d46c7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log1pf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log1pf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD log1p. +/// This file contains the implementation for single-precision SIMD log1p. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log2f.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log2f.h index 6101bd989ff6..d11fd8ccb628 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log2f.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/log2f.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD log2. +/// This file contains the implementation for single-precision SIMD log2. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/logf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/logf.h index 0ff0c22fe59a..e0c30f6107b9 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/logf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/logf.h @@ -7,30 +7,117 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD log. +/// This file contains the implementation for single-precision SIMD log. /// //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATHVEC_LOGF_H #define LLVM_LIBC_SRC___SUPPORT_MATHVEC_LOGF_H +#include "src/__support/CPP/bit.h" #include "src/__support/CPP/simd.h" -#define LIBC_MATH_HAS_NO_ERRNO -#define LIBC_MATH_HAS_NO_EXCEPT -#define LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY -#include "src/__support/math/logf.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/properties/cpu_features.h" +#include "src/__support/math/common_constants.h" +#include "src/__support/mathvec/common_constants.h" namespace LIBC_NAMESPACE_DECL { namespace mathvec { template <size_t N> -LIBC_INLINE cpp::simd<float, N> logf(cpp::simd<float, N> x) { - return cpp::map(x, [](float a) { return math::logf(a); }); +LIBC_INLINE cpp::simd<float, N> +inline_logf(cpp::simd<uint32_t, N> ux, cpp::simd<int32_t, N> exponent_bias) { + using namespace common_constants_internal; + + // Extract the 7 leading bits of the mantissa + cpp::simd<uint32_t, N> index = (ux >> 16) & 0x7fU; + + // Compute unbiased exponent + cpp::simd<int32_t, N> m = cpp::simd_cast<int32_t>(ux >> 23); + m += exponent_bias; + + // Sets the exponent such that 1 <= u < 2 + cpp::simd<float, N> u = + cpp::bit_cast<cpp::simd<float, N>>((ux & 0x007f'ffffU) | 0x3f80'0000U); + + cpp::simd<double, N> log_r = + cpp::gather<cpp::simd<double, N>>(true, index, LOG_TABLE); + +#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT + cpp::simd<float, N> r = cpp::gather<cpp::simd<float, N>>(true, index, R); + cpp::simd<double, N> v = cpp::simd_cast<double>( + cpp::multiply_add(u, r, cpp::simd<float, N>(-1.0f))); +#else + cpp::simd<double, N> r = cpp::gather<cpp::simd<double, N>>(true, index, RD); + cpp::simd<double, N> v = cpp::simd_cast<double>(u) * r - 1.0; +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + + // Degree-5 polynomial approximation of log generated by Sollya with: + // > P = fpminimax(log(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); + constexpr cpp::simd<double, N> c0 = -0x1.000000000fe63p-1; + constexpr cpp::simd<double, N> c1 = 0x1.555556e963c16p-2; + constexpr cpp::simd<double, N> c2 = -0x1.000028dedf986p-2; + constexpr cpp::simd<double, N> c3 = 0x1.966681bfda7f7p-3; + constexpr cpp::simd<double, N> log2 = 0x1.62e42fefa39efp-1; + + // Evaluate log(1 + v) in double precision. + cpp::simd<double, N> v_squared = v * v; + cpp::simd<double, N> p2 = cpp::multiply_add(v, c3, c2); + cpp::simd<double, N> p1 = cpp::multiply_add(v, c1, c0); + + // Accumulate the exponent independently of the polynomial's FMA chain. + cpp::simd<double, N> exponent = cpp::simd_cast<double>(m); + cpp::simd<double, N> p0 = cpp::multiply_add(exponent, log2, log_r) + v; + cpp::simd<double, N> y_d = + cpp::multiply_add(v_squared, cpp::multiply_add(v_squared, p2, p1), p0); + cpp::simd<float, N> y = cpp::simd_cast<float>(y_d); + +#if !(defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) || \ + defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS)) + y = (ux == 0x6f31a8ec) ? 0x1.08b512p+6 : y; + y = (ux == 0x79e7ec37) ? 0x1.43ff6ep+6 : y; +#endif // !(LIBC_TARGET_CPU_HAS_FMA_FLOAT || LIBC_MATH_HAS_SKIP_ACCURATE_PASS) + + return y; } -} // namespace mathvec +template <size_t N> +LIBC_INLINE cpp::simd<float, N> special_case(cpp::simd<float, N> x) { + using FPBits = fputil::FPBits<float>; + cpp::simd<uint32_t, N> ux = cpp::bit_cast<cpp::simd<uint32_t, N>>(x); + + // If x is subnormal, multiply by 23 to produce a normalised x, + // and subtract 23 from the exponent_bias to account for this scaling. + cpp::simd<bool, N> is_subnormal = (ux < 0x0080'0000U); + cpp::simd<uint32_t, N> normalized = + cpp::bit_cast<cpp::simd<uint32_t, N>>(x * 0x1.0p23f); + cpp::simd<int32_t, N> exponent_bias = is_subnormal ? -150 : -127; + ux = is_subnormal ? normalized : ux; + + // Compute logf with the normalised input. + cpp::simd<float, N> y = inline_logf(ux, exponent_bias); + + // Handle remaining specialc cases. + cpp::simd<bool, N> is_negative = x < 0; + cpp::simd<float, N> special = is_negative ? FPBits::quiet_nan().get_val() : x; + special = x == 0 ? -FPBits::inf().get_val() : special; + + return ((ux >= 0x7f80'0000U) || (x == 0)) ? special : y; +} +template <size_t N> +LIBC_INLINE cpp::simd<float, N> logf(cpp::simd<float, N> x) { + cpp::simd<uint32_t, N> ux = cpp::bit_cast<cpp::simd<uint32_t, N>>(x); + + // Handle zero, inf, nan, and subnormals + cpp::simd<bool, N> is_special = (ux < 0x0080'0000U) || (ux >= 0x7f80'0000U); + if (LIBC_UNLIKELY(cpp::any_of(is_special))) + return special_case(x); + + return inline_logf(ux, cpp::simd<int32_t, N>(-127)); +} +} // namespace mathvec } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_MATHVEC_LOGF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/rsqrtf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/rsqrtf.h index 8018c7f96aa3..a912aad1b390 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/rsqrtf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/rsqrtf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD rsqrt. +/// This file contains the implementation for single-precision SIMD rsqrt. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinf.h index e99356165f6d..7291e884c889 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD sin. +/// This file contains the implementation for single-precision SIMD sin. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinhf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinhf.h index 122c7d990989..47533a516d90 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinhf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinhf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD sinh. +/// This file contains the implementation for single-precision SIMD sinh. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinpif.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinpif.h index a5898702e101..268b24863d76 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinpif.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sinpif.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD sinpi. +/// This file contains the implementation for single-precision SIMD sinpi. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sqrtf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sqrtf.h index c092cb2bfd2f..30e621a2709a 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sqrtf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/sqrtf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD sqrt. +/// This file contains the implementation for single-precision SIMD sqrt. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanf.h index 08b293e0b9ad..e5755df32fc1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD tan. +/// This file contains the implementation for single-precision SIMD tan. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanhf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanhf.h index a06d09f6a32b..b358a6bdfc68 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanhf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanhf.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD tanh. +/// This file contains the implementation for single-precision SIMD tanh. /// //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_MATHVEC_TANHF_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanpif.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanpif.h index 7e02d4f64f05..19498477c8ba 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanpif.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/tanpif.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// This file contains the implemenation for single-precision SIMD tanpi. +/// This file contains the implementation for single-precision SIMD tanpi. /// //===----------------------------------------------------------------------===// diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf.h index dac250668340..5df61fe65d1f 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf.h @@ -40,19 +40,19 @@ LIBC_INLINE static Reduction<N> fast_reduction(cpp::simd<double, N> x) { cpp::simd<double, N> t = shift - z; // r = x/pi - k - cpp::simd<double, N> r; - r = cpp::multiply_add(x, inv_pi, t); + cpp::simd<double, N> r = cpp::multiply_add(x, inv_pi, t); r = cpp::multiply_add(x, inv_pi_tail, r); return {r, cpp::bit_cast<cpp::simd<int64_t, N>>(z)}; } -// Two-double expansions of 2^(8*q) / pi reduced modulo an even integer, -// q = 3..12. Padded to a 16 length array for easier access. +// Two-double expansions of 2^(8*q) / pi reduced modulo an even integer. +// Entries 0..14 correspond to q = 0..14, and entry 15 corresponds to q = -1 +// after masking. Entry 13 and 14 act as padding for inactive lanes. LIBC_INLINE_VAR constexpr double INV_PI_HI[16] = { - 0, - 0, - 0, + 0x1.45f306dc9c883p-2, + -0x1.067c91b1bbeadp-1, + 0x1.836e4e44152ap-1, -0x1.236377d5ac07bp-2, -0x1.b1bbead603d8bp-1, -0x1.bbead603d8a83p-1, @@ -65,13 +65,13 @@ LIBC_INLINE_VAR constexpr double INV_PI_HI[16] = { 0x1.f534ddc0db629p-1, 0, 0, - 0, + 0x1.45f306dc9c883p-10, }; LIBC_INLINE_VAR constexpr double INV_PI_LO[16] = { - 0, - 0, - 0, + -0x1.6b01ec55ff4d6p-56, + -0x1.80f62a0b82b2dp-55, + -0x1.ec54170565912p-56, -0x1.505c1596447e5p-58, 0x1.f47d4d377036ep-55, 0x1.f534ddc0db629p-57, @@ -84,11 +84,12 @@ LIBC_INLINE_VAR constexpr double INV_PI_LO[16] = { 0x1.664f10e4107f9p-55, 0, 0, - 0, + -0x1.6b01e7abff3d6p-64, }; // Reduces non-negative large finite inputs x >= 0x1p49. // Decomposes x / pi into k + r, with k as an integer and |r| <= 0.5. +// Based on a paper written by Tue Ly, see https://arxiv.org/abs/2609.35015 template <size_t N> LIBC_INLINE static Reduction<N> large_reduction(cpp::simd<double, N> x) { constexpr cpp::simd<double, N> shift = 0x1.8p52; @@ -100,9 +101,8 @@ LIBC_INLINE static Reduction<N> large_reduction(cpp::simd<double, N> x) { cpp::simd<int64_t, N> q = cpp::simd_cast<int64_t>(ix >> 55) - cpp::simd<int64_t, N>(131); - // While sufficiently large x will always produce q within [3, 12], - // not all input lanes are guaranteed to require the large reduction, - // so we mask with 15 to keep all values within bounds. + // For float inputs requiring large reduction, q is in [-1, 12]. Masking + // maps q = -1 to entry 15 and keeps inactive lanes within bounds. cpp::simd<int64_t, N> idx = q & cpp::simd<int64_t, N>(15); cpp::simd<double, N> c_hi = cpp::gather<cpp::simd<double, N>>(true, idx, INV_PI_HI); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf_nofma.h b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf_nofma.h index ac2f029922c5..2d63e9c552fa 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf_nofma.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/mathvec/trig_reductionf_nofma.h @@ -55,12 +55,15 @@ LIBC_INLINE static Reduction<N> fast_reduction(cpp::simd<double, N> x) { return {r, cpp::bit_cast<cpp::simd<int64_t, N>>(z)}; } -// Three-double expansions of 2^(8*q) / pi, reduced modulo an even integer, -// q = 3..12. Padded to 16 length arrays for safe masked indexing. +// Three-double expansions of 2^(8*q) / pi reduced modulo an even integer. +// Entries 0..14 correspond to q = 0..14, and entry 15 corresponds to q = -1 +// after masking. Entry 13 and 14 act as padding for inactive lanes. +// The first two parts have 29 significant bits, such that the fp64 product +// is exact when multiplied by an fp32 input. LIBC_INLINE_VAR constexpr double INV_PI_HI[16] = { - 0, - 0, - 0, + 0x1.45f306ep-2, + -0x1.067c91bp-1, + 0x1.836e4e4p-1, -0x1.236377d000000p-2, -0x1.b1bbead000000p-1, -0x1.bbead60000000p-1, @@ -73,12 +76,13 @@ LIBC_INLINE_VAR constexpr double INV_PI_HI[16] = { 0x1.f534ddc000000p-1, 0, 0, + 0x1.45f306ep-10, }; LIBC_INLINE_VAR constexpr double INV_PI_MID[16] = { - 0, - 0, - 0, + -0x1.b1bbeadp-33, + -0x1.bbead6p-33, + 0x1.054a7f1p-31, -0x1.6b01ec5000000p-32, -0x1.80f62a1000000p-31, -0x1.ec54170000000p-32, @@ -91,12 +95,13 @@ LIBC_INLINE_VAR constexpr double INV_PI_MID[16] = { 0x1.b6c52b3000000p-34, 0, 0, + -0x1.b1bbeadp-41, }; LIBC_INLINE_VAR constexpr double INV_PI_LO[16] = { - 0, - 0, - 0, + -0x1.80f62a0b82b2dp-63, + -0x1.ec54170565912p-64, + -0x1.8a82e0acb223fp-61, -0x1.05c1596447e50p-62, 0x1.1f534ddc0db80p-61, -0x1.596447e493ae0p-62, @@ -109,10 +114,12 @@ LIBC_INLINE_VAR constexpr double INV_PI_LO[16] = { 0x1.3c439041fe400p-65, 0, 0, + -0x1.80f62a0b82b2dp-71, }; // Reduces non-negative large finite inputs x >= 0x1p49. // Decomposes x / pi into k + r, with k as an integer and |r| <= 0.5. +// Based on a paper written by Tue Ly, see https://arxiv.org/abs/2609.35015 template <size_t N> LIBC_INLINE static Reduction<N> large_reduction(cpp::simd<double, N> x) { constexpr cpp::simd<double, N> shift = 0x1.8p52; @@ -124,9 +131,8 @@ LIBC_INLINE static Reduction<N> large_reduction(cpp::simd<double, N> x) { cpp::simd<int64_t, N> q = cpp::simd_cast<int64_t>(ix >> 55) - cpp::simd<int64_t, N>(131); - // While sufficiently large x will always produce q within [3, 12], - // not all input lanes are guaranteed to require the large reduction, - // so we mask with 15 to keep all values within bounds. + // For float inputs requiring large reduction, q is in [-1, 12]. Masking + // maps q = -1 to entry 15 and keeps inactive lanes within bounds. cpp::simd<int64_t, N> idx = q & cpp::simd<int64_t, N>(15); cpp::simd<double, N> c_hi = cpp::gather<cpp::simd<double, N>>(true, idx, INV_PI_HI); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/memory_size.h b/deps/v8/third_party/llvm-libc/src/src/__support/memory_size.h index 49c359896088..f85956e0b11b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/memory_size.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/memory_size.h @@ -47,8 +47,11 @@ class SafeMemSize { type result; if (LIBC_UNLIKELY((value | other.value) < 0)) { result = -1; - } else { - result = value + other.value; + } else if (LIBC_UNLIKELY(add_overflow(value, other.value, result))) { + // Signed addition would overflow. Computing `value + other.value` + // directly is undefined behavior, so detect the overflow with the + // builtin and mark the result invalid instead. + result = -1; } return SafeMemSize{result}; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/net/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/net/CMakeLists.txt index 80b141d06cdd..39a34528199e 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/net/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/net/CMakeLists.txt @@ -9,12 +9,15 @@ add_object_library( libc.hdr.types.struct_in_addr libc.hdr.types.struct_in6_addr libc.hdr.inet_address_macros + libc.hdr.stdint_proxy libc.src.__support.common libc.src.__support.ctype_utils libc.src.__support.CPP.optional libc.src.__support.CPP.span libc.src.__support.CPP.string_view + libc.src.__support.fixedvector libc.src.__support.libc_assert libc.src.__support.str_to_integer + libc.src.string.memory_utils.inline_bzero libc.src.string.memory_utils.inline_memcpy ) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/net/address.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/net/address.cpp index 8e0554ccc298..bc18d927d7cd 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/net/address.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/net/address.cpp @@ -14,6 +14,7 @@ #include "src/__support/net/address.h" #include "hdr/inet-address-macros.h" +#include "hdr/stdint_proxy.h" #include "hdr/types/in_addr_t.h" #include "hdr/types/struct_in6_addr.h" #include "hdr/types/struct_in_addr.h" @@ -21,13 +22,143 @@ #include "src/__support/common.h" #include "src/__support/ctype_utils.h" #include "src/__support/endian_internal.h" +#include "src/__support/fixedvector.h" #include "src/__support/libc_assert.h" #include "src/__support/str_to_integer.h" +#include "src/string/memory_utils/inline_bzero.h" #include "src/string/memory_utils/inline_memcpy.h" namespace LIBC_NAMESPACE_DECL { + namespace net { +[[nodiscard]] bool str_to_ipv4(cpp::string_view src, struct in_addr &dst) { + uint8_t bytes[4]; + size_t idx = 0; + uint32_t current_val = 0; + size_t digits_in_octet = 0; + + for (char c : src) { + if (internal::isdigit(c)) { + // Reject octals and leading zeros + if (digits_in_octet > 0 && current_val == 0) + return false; + + current_val = current_val * 10 + internal::b36_char_to_int(c); + if (current_val > 255) + return false; + + ++digits_in_octet; + } else if (c == '.') { + if (digits_in_octet == 0 || idx == 3) + return false; // Empty part or too many dots + + bytes[idx++] = static_cast<uint8_t>(current_val); + current_val = 0; + digits_in_octet = 0; + } else { + return false; + } + } + + if (idx != 3 || digits_in_octet == 0) + return 0; + + bytes[3] = static_cast<uint8_t>(current_val); + inline_memcpy(&dst.s_addr, bytes, 4); + return true; +} + +[[nodiscard]] bool str_to_ipv6(cpp::string_view src, struct in6_addr &dst) { + constexpr size_t NUM_COMPONENTS = 8; + // `parts[0]` collects 16-bit groups preceding "::", while `parts[1]` collects + // groups following "::". When "::" is encountered, `part_idx` switches to 1. + // After parsing, any omitted zero groups are filled between the two parts. + FixedVector<uint16_t, NUM_COMPONENTS> parts[2]; + size_t part_idx = 0; + + while (!src.empty()) { + size_t non_colon = src.find_first_not_of(':'); + if (non_colon == cpp::string_view::npos) { + if (src.size() == 2 && part_idx == 0) { + part_idx = 1; + break; + } + return false; + } + + switch (non_colon) { + case 0: + if (part_idx > 0 || !parts[0].empty()) + return false; + break; + case 1: + if (part_idx == 0 && parts[0].empty()) + return false; + src.remove_prefix(1); + break; + case 2: + if (part_idx > 0) + return false; + part_idx = 1; + src.remove_prefix(2); + break; + default: + return false; + } + + size_t colon_pos = src.find_first_of(':'); + if (colon_pos == cpp::string_view::npos && src.contains('.')) { + struct in_addr in4; + if (!str_to_ipv4(src, in4)) + return false; + + uint16_t v4_words[2]; + inline_memcpy(v4_words, &in4.s_addr, sizeof(v4_words)); + if (!parts[part_idx].push_back(v4_words[0]) || + !parts[part_idx].push_back(v4_words[1])) + return false; + + break; + } + + if (internal::isspace(src[0]) || src[0] == '+' || src[0] == '-' || + src.starts_with("0x") || src.starts_with("0X")) + return false; + + auto result = internal::strtointeger<uint16_t>(src.data(), 16, src.size()); + if (result.has_error() || result.parsed_len == 0 || result.parsed_len > 4) + return false; + + if (!parts[part_idx].push_back(Endian::to_big_endian(result.value))) + return false; + + src.remove_prefix(static_cast<size_t>(result.parsed_len)); + } + + if (part_idx > 0) { + if (parts[0].size() + parts[1].size() >= NUM_COMPONENTS) + return false; + + size_t num_zeroes = NUM_COMPONENTS - parts[0].size() - parts[1].size(); + uint16_t *ptr = dst.s6_addr16; + if (!parts[0].empty()) { + inline_memcpy(ptr, parts[0].begin(), parts[0].size() * sizeof(uint16_t)); + ptr += parts[0].size(); + } + inline_bzero(ptr, num_zeroes * sizeof(uint16_t)); + ptr += num_zeroes; + if (!parts[1].empty()) + inline_memcpy(ptr, parts[1].begin(), parts[1].size() * sizeof(uint16_t)); + } else { + if (parts[0].size() != NUM_COMPONENTS) + return false; + inline_memcpy(dst.s6_addr16, parts[0].begin(), sizeof(dst)); + } + + return true; +} + cpp::optional<in_addr_t> inet_addr(cpp::string_view src) { constexpr int IPV4_MAX_DOT_NUM = 3; in_addr_t parts[IPV4_MAX_DOT_NUM + 1] = {0}; diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/net/address.h b/deps/v8/third_party/llvm-libc/src/src/__support/net/address.h index 7c799b122e46..065dd4f30fae 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/net/address.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/net/address.h @@ -31,11 +31,13 @@ cpp::optional<in_addr_t> inet_addr(cpp::string_view src); /// provided address into the destination buffer. In case of error, returns /// false and does not modify the buffer. [[nodiscard]] bool ipv4_to_str(const struct in_addr &src, cpp::span<char> dst); +[[nodiscard]] bool str_to_ipv4(cpp::string_view src, struct in_addr &dst); /// Writes a string representation (including the terminating \0) of the /// provided address into the destination buffer. In case of error, returns /// false and does not modify the buffer. [[nodiscard]] bool ipv6_to_str(const struct in6_addr &src, cpp::span<char> dst); +[[nodiscard]] bool str_to_ipv6(cpp::string_view src, struct in6_addr &dst); } // namespace net } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/CMakeLists.txt index 2634dab56eea..d059d8881c41 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/CMakeLists.txt @@ -54,6 +54,7 @@ endif() if(LIBC_CONF_PRINTF_DISABLE_WIDE) set(wchar_deps "") set(parser_wchar_deps "") + set(converter_wchar_deps "") else() set(wchar_deps libc.hdr.types.wchar_t @@ -68,6 +69,9 @@ else() set(parser_wchar_deps libc.hdr.types.wint_t ) + set(converter_wchar_deps + libc.src.__support.wctype_utils + ) endif() add_header_library( @@ -89,10 +93,20 @@ add_header_library( libc.hdr.errno_macros ) +set(parser_compile_options "") +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # Suppress GCC's warning about passing unions with 80-bit long double, + # which is triggered when Parser::get_arg_value returns + # cpp::optional<long double> by value on x86-64. + list(APPEND parser_compile_options "-Wno-psabi") +endif() + add_header_library( parser HDRS parser.h + COMPILE_OPTIONS + ${parser_compile_options} DEPENDS .core_structs libc.src.__support.arg_list @@ -142,11 +156,14 @@ add_header_library( libc.include.inttypes libc.hdr.limits_macros libc.src.string.string_utils - libc.src.__support.big_int - libc.src.__support.common libc.src.__support.CPP.limits libc.src.__support.CPP.span libc.src.__support.CPP.string_view + libc.src.__support.CPP.type_traits + libc.src.__support.StringUtil.error_to_string + libc.src.__support.big_int + libc.src.__support.common + libc.src.__support.ctype_utils libc.src.__support.float_to_string libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits @@ -154,9 +171,9 @@ add_header_library( libc.src.__support.integer_to_string libc.src.__support.libc_assert libc.src.__support.uint128 - libc.src.__support.StringUtil.error_to_string libc.src.string.memory_utils.inline_memcpy ${wchar_deps} + ${converter_wchar_deps} ) add_object_library( diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/char_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/char_converter.h index 7bad28d18d1b..c78eec54a0af 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/char_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/char_converter.h @@ -18,6 +18,7 @@ #endif // LIBC_COPT_PRINTF_DISABLE_WIDE #include "hdr/limits_macros.h" +#include "src/__support/CPP/type_traits.h" #include "src/__support/macros/config.h" #include "src/__support/printf_core/converter_utils.h" #include "src/__support/printf_core/core_structs.h" @@ -27,9 +28,8 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { template <OverflowMode mode> -LIBC_INLINE int convert_char(Writer<mode> *writer, - const FormatSection &to_conv) { - +LIBC_INLINE int write_character_as_char(Writer<mode, char> *writer, + const FormatSection<char> &to_conv) { char buffer[MB_LEN_MAX]; size_t write_size = 0; @@ -82,6 +82,65 @@ LIBC_INLINE int convert_char(Writer<mode> *writer, return WRITE_OK; } +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + +template <OverflowMode mode> +LIBC_INLINE int +write_character_as_wchar(Writer<mode, wchar_t> *writer, + const FormatSection<wchar_t> &to_conv) { + wchar_t write_char; + + if (to_conv.length_modifier == LengthModifier::l) { + wint_t wi = static_cast<wint_t>(to_conv.conv_val_raw); + if (wi == WEOF) + return ILLEGAL_WIDE_CHAR; + + write_char = static_cast<wchar_t>(wi); + } else { + int c = static_cast<int>(to_conv.conv_val_raw); + if (c < 0 || c > 127) + return MB_CONVERSION_ERROR; + + write_char = static_cast<wchar_t>(c); + } + + size_t padding_spaces = to_conv.min_width > 1 ? to_conv.min_width - 1 : 0; + + // If the padding is on the left side, write the spaces first. + if (padding_spaces > 0 && + (to_conv.flags & FormatFlags::LEFT_JUSTIFIED) == 0) { + RET_IF_RESULT_NEGATIVE(writer->write(L' ', padding_spaces)); + } + + RET_IF_RESULT_NEGATIVE(writer->write(write_char)); + + // If the padding is on the right side, write the spaces last. + if (padding_spaces > 0 && + (to_conv.flags & FormatFlags::LEFT_JUSTIFIED) != 0) { + RET_IF_RESULT_NEGATIVE(writer->write(L' ', padding_spaces)); + } + + return WRITE_OK; +} + +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_character(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { +#if defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + static_assert(cpp::is_same_v<CharT, char>, "wchar_t not supported."); + return write_character_as_char(writer, to_conv); +#else // LIBC_COPT_PRINTF_DISABLE_WIDE + if constexpr (cpp::is_same_v<CharT, char>) { + return write_character_as_char(writer, to_conv); + } else { + static_assert(cpp::is_same_v<CharT, wchar_t>); + return write_character_as_wchar(writer, to_conv); + } +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE +} + } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/converter.h index 05ef6829b3a5..a37966a22bd4 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/converter.h @@ -29,22 +29,22 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT -LIBC_PRINTF_MODULE((template <OverflowMode mode> - int convert_float(Writer<mode> *writer, - const FormatSection &to_conv)), +LIBC_PRINTF_MODULE((template <OverflowMode mode, typename CharT> + int convert_float(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv)), { switch (to_conv.conv_name) { - case 'f': - case 'F': + case CharT{'f'}: + case CharT{'F'}: return convert_float_decimal(writer, to_conv); - case 'e': - case 'E': + case CharT{'e'}: + case CharT{'E'}: return convert_float_dec_exp(writer, to_conv); - case 'a': - case 'A': + case CharT{'a'}: + case CharT{'A'}: return convert_float_hex_exp(writer, to_conv); - case 'g': - case 'G': + case CharT{'g'}: + case CharT{'G'}: return convert_float_dec_auto(writer, to_conv); } __builtin_unreachable(); @@ -53,17 +53,28 @@ LIBC_PRINTF_MODULE((template <OverflowMode mode> #ifdef LIBC_PRINTF_DEFINE_MODULES #define HANDLE_OVERFLOW_MODE(MODE) \ - template int convert_float<OverflowMode::MODE>( \ - Writer<OverflowMode::MODE> * writer, const FormatSection &to_conv); + template int convert_float<OverflowMode::MODE, char>( \ + Writer<OverflowMode::MODE, char> * writer, \ + const FormatSection<char> &to_conv); #include "src/__support/printf_core/overflow_modes.def" #undef HANDLE_OVERFLOW_MODE + +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) +#define HANDLE_OVERFLOW_MODE(MODE) \ + template int convert_float<OverflowMode::MODE, wchar_t>( \ + Writer<OverflowMode::MODE, wchar_t> * writer, \ + const FormatSection<wchar_t> &to_conv); +#include "src/__support/printf_core/overflow_modes.def" +#undef HANDLE_OVERFLOW_MODE +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + #endif // LIBC_PRINTF_DEFINE_MODULES // convert will call a conversion function to convert the FormatSection into // its string representation, and then that will write the result to the // writer. -template <OverflowMode mode> -int convert(Writer<mode> *writer, const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +int convert(Writer<mode, CharT> *writer, const FormatSection<CharT> &to_conv) { if (!to_conv.has_conv) return writer->write(to_conv.raw_string); @@ -71,12 +82,12 @@ int convert(Writer<mode> *writer, const FormatSection &to_conv) { defined(LIBC_COPT_PRINTF_HEX_LONG_DOUBLE) if (to_conv.length_modifier == LengthModifier::L) { switch (to_conv.conv_name) { - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': + case CharT{'f'}: + case CharT{'F'}: + case CharT{'e'}: + case CharT{'E'}: + case CharT{'g'}: + case CharT{'G'}: return convert_float_hex_exp(writer, to_conv); default: break; @@ -85,48 +96,49 @@ int convert(Writer<mode> *writer, const FormatSection &to_conv) { #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT switch (to_conv.conv_name) { - case '%': - return writer->write("%"); - case 'c': - return convert_char(writer, to_conv); - case 's': + case CharT{'%'}: + return writer->write(CharT{'%'}); + case CharT{'c'}: + return convert_character(writer, to_conv); + case CharT{'s'}: return convert_string(writer, to_conv); - case 'd': - case 'i': - case 'u': - case 'o': - case 'x': - case 'X': - case 'b': - case 'B': + case CharT{'d'}: + case CharT{'i'}: + case CharT{'u'}: + case CharT{'o'}: + case CharT{'x'}: + case CharT{'X'}: + case CharT{'b'}: + case CharT{'B'}: return convert_int(writer, to_conv); #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT - case 'f': - case 'F': - case 'e': - case 'E': - case 'a': - case 'A': - case 'g': - case 'G': + case CharT{'f'}: + case CharT{'F'}: + case CharT{'e'}: + case CharT{'E'}: + case CharT{'a'}: + case CharT{'A'}: + case CharT{'g'}: + case CharT{'G'}: return convert_float(writer, to_conv); #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT - case 'r': - case 'R': - case 'k': - case 'K': + case CharT{'r'}: + case CharT{'R'}: + case CharT{'k'}: + case CharT{'K'}: return convert_fixed(writer, to_conv); #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT #ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR - case 'm': + case CharT{'m'}: return convert_strerror(writer, to_conv); #endif // LIBC_COPT_PRINTF_DISABLE_STRERROR #ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case 'n': - return convert_write_int(writer, to_conv); + case CharT{'n'}: + return convert_write_int(writer->get_chars_written(), + to_conv.length_modifier, to_conv.conv_val_ptr); #endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case 'p': + case CharT{'p'}: return convert_pointer(writer, to_conv); default: return writer->write(to_conv.raw_string); diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/core_structs.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/core_structs.h index 13ba18b8ba15..a25b9e29ab84 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/core_structs.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/core_structs.h @@ -23,22 +23,6 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { -template <typename CharT, char ascii_value> struct CharConstant {}; - -template <char ascii_value> struct CharConstant<char, ascii_value> { - LIBC_INLINE_VAR static constexpr char value = ascii_value; -}; - -#if defined(LIBC_TYPES_WCHAR_T_IS_UTF32) -template <char ascii_value> struct CharConstant<wchar_t, ascii_value> { - LIBC_INLINE_VAR static constexpr wchar_t value = ascii_value; -}; -#endif // LIBC_TYPES_WCHAR_T_IS_UTF32 - -template <typename CharT, char ascii_value> -LIBC_INLINE_VAR constexpr CharT char_constant_v = - CharConstant<CharT, ascii_value>::value; - // These length modifiers match the length modifiers in the format string, which // is why they are formatted differently from the rest of the file. enum class LengthModifier { @@ -83,7 +67,7 @@ enum FormatFlags : uint8_t { // locale_digits = 0x40, // I }; -template <typename CharT> struct BasicFormatSection { +template <typename CharT> struct FormatSection { bool has_conv; cpp::basic_string_view<CharT> raw_string; @@ -102,7 +86,7 @@ template <typename CharT> struct BasicFormatSection { // This operator is only used for testing and should be automatically // optimized out for release builds. - LIBC_INLINE bool operator==(const BasicFormatSection &other) const { + LIBC_INLINE bool operator==(const FormatSection &other) const { if (has_conv != other.has_conv) return false; @@ -118,19 +102,16 @@ template <typename CharT> struct BasicFormatSection { (conv_name == other.conv_name))) return false; - if (conv_name == char_constant_v<CharT, 'p'> || - conv_name == char_constant_v<CharT, 'n'> || - conv_name == char_constant_v<CharT, 's'>) + if (conv_name == CharT{'p'} || conv_name == CharT{'n'} || + conv_name == CharT{'s'}) return (conv_val_ptr == other.conv_val_ptr); - else if (conv_name != char_constant_v<CharT, '%'>) + else if (conv_name != CharT{'%'}) return (conv_val_raw == other.conv_val_raw); } return true; } }; -using FormatSection = BasicFormatSection<char>; - enum PrimaryType : uint8_t { Unknown = 0, Float = 1, diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/fixed_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/fixed_converter.h index 04994a7729bc..03b8b8e8d6c6 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/fixed_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/fixed_converter.h @@ -10,7 +10,6 @@ #define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_FIXED_CONVERTER_H #include "include/llvm-libc-macros/stdfix-macros.h" -#include "src/__support/CPP/string_view.h" #include "src/__support/ctype_utils.h" #include "src/__support/fixed_point/fx_bits.h" #include "src/__support/fixed_point/fx_rep.h" @@ -21,6 +20,10 @@ #include "src/__support/printf_core/core_structs.h" #include "src/__support/printf_core/writer.h" +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) +#include "src/__support/wctype_utils.h" +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + #include <inttypes.h> #include <stddef.h> @@ -49,13 +52,13 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) { #define APPLY_FX_LENGTH_MODIFIER(LENGTH_MODIFIER) \ do { \ - if (to_conv.conv_name == 'r') { \ + if (to_conv.conv_name == CharT{'r'}) { \ READ_FX_BITS(LENGTH_MODIFIER fract); \ - } else if (to_conv.conv_name == 'R') { \ + } else if (to_conv.conv_name == CharT{'R'}) { \ READ_FX_BITS(unsigned LENGTH_MODIFIER fract); \ - } else if (to_conv.conv_name == 'k') { \ + } else if (to_conv.conv_name == CharT{'k'}) { \ READ_FX_BITS(LENGTH_MODIFIER accum); \ - } else if (to_conv.conv_name == 'K') { \ + } else if (to_conv.conv_name == CharT{'K'}) { \ READ_FX_BITS(unsigned LENGTH_MODIFIER accum); \ } else { \ LIBC_ASSERT(false && "Invalid conversion name passed to convert_fixed"); \ @@ -63,9 +66,9 @@ LIBC_INLINE constexpr uint32_t const_ten_exp(uint32_t exponent) { } \ } while (false) -template <OverflowMode mode> -LIBC_INLINE int convert_fixed(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_fixed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { // Long accum should be the largest type, so we can store all the smaller // numbers in things sized for it. using LARep = fixed_point::FXRep<unsigned long accum>; @@ -123,7 +126,7 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, constexpr size_t MAX_FRACTION_DIGITS = LARep::FRACTION_LEN; - char fraction_digits[MAX_FRACTION_DIGITS]; + CharT fraction_digits[MAX_FRACTION_DIGITS]; size_t valid_fraction_digits = 0; @@ -142,8 +145,8 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, // we add TEN_EXP_NINE to force leading zeroes to show up, then we skip the // first digit in the loop. - const IntegerToString<uint32_t> cur_fractional_digits(cur_digits + - TEN_EXP_NINE); + const IntegerToString<uint32_t, radix::Dec, CharT> cur_fractional_digits( + cur_digits + TEN_EXP_NINE); for (size_t i = 0; i < DIGITS_PER_BLOCK && valid_fraction_digits < MAX_FRACTION_DIGITS; ++i, ++valid_fraction_digits) @@ -177,7 +180,7 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, // Handle rounding. Just do round to nearest, tie to even since it's // unspecified. RoundDirection round; - char first_digit_after = fraction_digits[precision]; + CharT first_digit_after = fraction_digits[precision]; if (internal::b36_char_to_int(first_digit_after) > 5) { round = RoundDirection::Up; } else if (internal::b36_char_to_int(first_digit_after) < 5) { @@ -188,7 +191,7 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, round = RoundDirection::Even; for (size_t cur_digit_index = precision + 1; cur_digit_index + 1 < valid_fraction_digits; ++cur_digit_index) { - if (fraction_digits[cur_digit_index] != '0') { + if (fraction_digits[cur_digit_index] != CharT{'0'}) { round = RoundDirection::Up; break; } @@ -201,7 +204,7 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, int digit_to_round = static_cast<int>(precision) - 1; for (; digit_to_round >= 0 && keep_rounding; --digit_to_round) { keep_rounding = false; - char cur_digit = fraction_digits[digit_to_round]; + CharT cur_digit = fraction_digits[digit_to_round]; // if the digit should not be rounded up if (round == RoundDirection::Even && (internal::b36_char_to_int(cur_digit) % 2) == 0) { @@ -211,8 +214,8 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, fraction_digits[digit_to_round] += 1; // if the digit was a 9, instead replace with a 0. - if (cur_digit == '9') { - fraction_digits[digit_to_round] = '0'; + if (cur_digit == CharT{'9'}) { + fraction_digits[digit_to_round] = CharT{'0'}; keep_rounding = true; } } @@ -230,7 +233,7 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, valid_fraction_digits = precision; } - const IntegerToString<StorageType> integral_str(integral); + const IntegerToString<StorageType, radix::Dec, CharT> integral_str(integral); // these are signed to prevent underflow due to negative values. The // eventual values will always be non-negative. @@ -241,9 +244,9 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, if (precision > valid_fraction_digits) trailing_zeroes = precision - (valid_fraction_digits); - constexpr cpp::string_view DECIMAL_POINT("."); + constexpr CharT DECIMAL_POINT = CharT{'.'}; - char sign_char = 0; + CharT sign_char = 0; // Check if the conv name is uppercase if (internal::isupper(to_conv.conv_name)) { @@ -254,11 +257,11 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, } if (is_negative) - sign_char = '-'; + sign_char = CharT{'-'}; else if ((flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over SPACE_PREFIX else if ((flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; padding = static_cast<int>(to_conv.min_width - (sign_char > 0 ? 1 : 0) - integral_str.size() - @@ -278,20 +281,20 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, RET_IF_RESULT_NEGATIVE( writer->write({fraction_digits, valid_fraction_digits})); if (trailing_zeroes > 0) - RET_IF_RESULT_NEGATIVE(writer->write('0', trailing_zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, trailing_zeroes)); if (padding > 0) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding)); } else { // The pattern is (spaces), (sign), (zeroes), integral, (.), (fraction), // (zeroes) if ((padding > 0) && ((flags & FormatFlags::LEADING_ZEROES) != FormatFlags::LEADING_ZEROES)) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding)); if (sign_char > 0) RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); if ((padding > 0) && ((flags & FormatFlags::LEADING_ZEROES) == FormatFlags::LEADING_ZEROES)) - RET_IF_RESULT_NEGATIVE(writer->write('0', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, padding)); RET_IF_RESULT_NEGATIVE(writer->write(integral_str.view())); if (has_decimal_point) RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); @@ -299,7 +302,7 @@ LIBC_INLINE int convert_fixed(Writer<mode> *writer, RET_IF_RESULT_NEGATIVE( writer->write({fraction_digits, valid_fraction_digits})); if (trailing_zeroes > 0) - RET_IF_RESULT_NEGATIVE(writer->write('0', trailing_zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, trailing_zeroes)); } return WRITE_OK; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter.h index 89ea766e72f0..38746b411578 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter.h @@ -23,15 +23,22 @@ #include "src/__support/printf_core/float_inf_nan_converter.h" #include "src/__support/printf_core/writer.h" +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) +#include "src/__support/wctype_utils.h" +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + #include <inttypes.h> #include <stddef.h> namespace LIBC_NAMESPACE_DECL { namespace printf_core { -using DecimalString = IntegerToString<intmax_t>; +template <typename CharT> +using DecimalString = IntegerToString<intmax_t, radix::Dec, CharT>; + +template <typename CharT> using ExponentString = - IntegerToString<intmax_t, radix::Dec::WithWidth<2>::WithSign>; + IntegerToString<intmax_t, radix::Dec::WithWidth<2>::WithSign, CharT>; // Returns true if value is divisible by 2^p. template <typename T> @@ -41,8 +48,8 @@ multiple_of_power_of_2(T value, uint32_t p) { return (value & ((T(1) << p) - 1)) == 0; } -constexpr size_t BLOCK_SIZE = 9; -constexpr uint32_t MAX_BLOCK = 999999999; +LIBC_INLINE_VAR constexpr size_t BLOCK_SIZE = 9; +LIBC_INLINE_VAR constexpr uint32_t MAX_BLOCK = 999999999; // constexpr size_t BLOCK_SIZE = 18; // constexpr uint32_t MAX_BLOCK = 999999999999999999; @@ -99,21 +106,22 @@ zero_after_digits(int32_t base_2_exp, int32_t digits_after_point, T mantissa, return has_trailing_zeros; } -template <OverflowMode mode> class PaddingWriter { +template <OverflowMode mode, typename CharT> class PaddingWriter { bool left_justified = false; bool leading_zeroes = false; - char sign_char = 0; + CharT sign_char = 0; size_t min_width = 0; public: LIBC_INLINE PaddingWriter() {} - LIBC_INLINE PaddingWriter(const FormatSection &to_conv, char init_sign_char) + LIBC_INLINE PaddingWriter(const FormatSection<CharT> &to_conv, + CharT init_sign_char) : left_justified((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) > 0), leading_zeroes((to_conv.flags & FormatFlags::LEADING_ZEROES) > 0), sign_char(init_sign_char), min_width(to_conv.min_width > 0 ? to_conv.min_width : 0) {} - LIBC_INLINE int write_left_padding(Writer<mode> *writer, + LIBC_INLINE int write_left_padding(Writer<mode, CharT> *writer, size_t total_digits) { // The pattern is (spaces) (sign) (zeroes), but only one of spaces and // zeroes can be written, and only if the padding amount is positive. @@ -126,25 +134,25 @@ template <OverflowMode mode> class PaddingWriter { return 0; } if (!leading_zeroes) { - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_amount)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding_amount)); } if (sign_char > 0) { RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); } if (leading_zeroes) { - RET_IF_RESULT_NEGATIVE(writer->write('0', padding_amount)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, padding_amount)); } return 0; } - LIBC_INLINE int write_right_padding(Writer<mode> *writer, + LIBC_INLINE int write_right_padding(Writer<mode, CharT> *writer, size_t total_digits) { // If and only if the conversion is left justified, there may be trailing // spaces. int padding_amount = static_cast<int>(min_width - total_digits - (sign_char > 0 ? 1 : 0)); if (left_justified && padding_amount > 0) { - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_amount)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding_amount)); } return 0; } @@ -163,22 +171,22 @@ template <OverflowMode mode> class PaddingWriter { This FloatWriter class does the buffering and counting, and writes to the output when necessary. */ -template <OverflowMode mode> class FloatWriter { - char block_buffer[BLOCK_SIZE]; // The buffer that holds a block. - size_t buffered_digits = 0; // The number of digits held in the buffer. +template <OverflowMode mode, typename CharT> class FloatWriter { + CharT block_buffer[BLOCK_SIZE]; // The buffer that holds a block. bool has_written = false; // True once any digits have been output. + bool has_decimal_point; // True if the number has a decimal point. + size_t buffered_digits = 0; // The number of digits held in the buffer. size_t max_block_count = 0; // The # of blocks of all 9s currently buffered. size_t total_digits = 0; // The number of digits that will be output. size_t digits_before_decimal = 0; // The # of digits to write before the '.' size_t total_digits_written = 0; // The # of digits that have been output. - bool has_decimal_point; // True if the number has a decimal point. - Writer<mode> *writer; // Writes to the final output. - PaddingWriter<mode> + Writer<mode, CharT> *writer; // Writes to the final output. + PaddingWriter<mode, CharT> padding_writer; // Handles prefixes/padding, uses total_digits. LIBC_INLINE int flush_buffer(bool round_up_max_blocks = false) { - const char MAX_BLOCK_DIGIT = (round_up_max_blocks ? '0' : '9'); - constexpr char DECIMAL_POINT = '.'; + const CharT MAX_BLOCK_DIGIT = CharT{round_up_max_blocks ? '0' : '9'}; + constexpr CharT DECIMAL_POINT = CharT{'.'}; // Write the most recent buffered block, and mark has_written if (!has_written) { @@ -255,9 +263,9 @@ template <OverflowMode mode> class FloatWriter { #endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE public: - LIBC_INLINE FloatWriter(Writer<mode> *init_writer, + LIBC_INLINE FloatWriter(Writer<mode, CharT> *init_writer, bool init_has_decimal_point, - const PaddingWriter<mode> &init_padding_writer) + const PaddingWriter<mode, CharT> &init_padding_writer) : has_decimal_point(init_has_decimal_point), writer(init_writer), padding_writer(init_padding_writer) {} @@ -268,8 +276,8 @@ template <OverflowMode mode> class FloatWriter { } LIBC_INLINE void write_first_block(BlockInt block, bool exp_format = false) { - const DecimalString buf(block); - const cpp::string_view int_to_str = buf.view(); + const DecimalString<CharT> buf(block); + const cpp::basic_string_view<CharT> int_to_str = buf.view(); size_t digits_buffered = int_to_str.size(); // Block Buffer is guaranteed to not overflow since block cannot have more // than BLOCK_SIZE digits. @@ -297,8 +305,8 @@ template <OverflowMode mode> class FloatWriter { // Now buffer the current block. We add 1 + MAX_BLOCK to force the // leading zeroes, and drop the leading one. This is probably inefficient, // but it works. See https://xkcd.com/2021/ - const DecimalString buf(block + (MAX_BLOCK + 1)); - const cpp::string_view int_to_str = buf.view(); + const DecimalString<CharT> buf(block + (MAX_BLOCK + 1)); + const cpp::basic_string_view<CharT> int_to_str = buf.view(); // TODO: Replace with memcpy for (size_t count = 0; count < BLOCK_SIZE; ++count) { block_buffer[count] = int_to_str[count + 1]; @@ -311,14 +319,14 @@ template <OverflowMode mode> class FloatWriter { LIBC_INLINE int write_last_block(BlockInt block, size_t block_digits, RoundDirection round, int exponent = 0, - char exp_char = '\0') { + CharT exp_char = CharT{'\0'}) { bool has_exp = (exp_char != '\0'); - char end_buff[BLOCK_SIZE]; + CharT end_buff[BLOCK_SIZE]; { - const DecimalString buf(block + (MAX_BLOCK + 1)); - const cpp::string_view int_to_str = buf.view(); + const DecimalString<CharT> buf(block + (MAX_BLOCK + 1)); + const cpp::basic_string_view<CharT> int_to_str = buf.view(); // copy the last block_digits characters into the start of end_buff. // TODO: Replace with memcpy @@ -327,11 +335,11 @@ template <OverflowMode mode> class FloatWriter { } } - char low_digit = '0'; + CharT low_digit = CharT{'0'}; if (block_digits > 0) { low_digit = end_buff[block_digits - 1]; } else if (max_block_count > 0) { - low_digit = '9'; + low_digit = CharT{'9'}; } else if (buffered_digits > 0) { low_digit = block_buffer[buffered_digits - 1]; } @@ -348,8 +356,8 @@ template <OverflowMode mode> class FloatWriter { // handle the low block that we're adding for (int count = static_cast<int>(block_digits) - 1; count >= 0 && has_carry; --count) { - if (end_buff[count] == '9') { - end_buff[count] = '0'; + if (end_buff[count] == CharT{'9'}) { + end_buff[count] = CharT{'0'}; } else { end_buff[count] += 1; has_carry = false; @@ -360,8 +368,8 @@ template <OverflowMode mode> class FloatWriter { // handle the high block that's buffered for (int count = static_cast<int>(buffered_digits) - 1; count >= 0 && has_carry; --count) { - if (block_buffer[count] == '9') { - block_buffer[count] = '0'; + if (block_buffer[count] == CharT{'9'}) { + block_buffer[count] = CharT{'0'}; } else { block_buffer[count] += 1; has_carry = false; @@ -371,15 +379,15 @@ template <OverflowMode mode> class FloatWriter { // has_carry should only be true here if every previous digit is 9, which // implies that the number has never been written. if (has_carry /* && !has_written */) { - constexpr char DECIMAL_POINT = '.'; + constexpr CharT DECIMAL_POINT = CharT{'.'}; if (has_exp) { // This is in %e style // Since this is exponential notation, we don't write any more digits // but we do increment the exponent. ++exponent; - const ExponentString buf(exponent); - const cpp::string_view int_to_str = buf.view(); + const ExponentString<CharT> buf(exponent); + const cpp::basic_string_view<CharT> int_to_str = buf.view(); // TODO: also change this to calculate the width of the number more // efficiently. @@ -400,7 +408,7 @@ template <OverflowMode mode> class FloatWriter { padding_writer.write_left_padding(writer, total_digits)); // Now we know we need to print a leading 1, the decimal point, and // then zeroes after it. - RET_IF_RESULT_NEGATIVE(writer->write('1')); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'1'})); // digits_before_decimal - 1 to account for the leading '1' if (has_decimal_point) { RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); @@ -408,7 +416,8 @@ template <OverflowMode mode> class FloatWriter { // point, or exponent. if (number_digits > 1) { - RET_IF_RESULT_NEGATIVE(writer->write('0', number_digits - 1)); + RET_IF_RESULT_NEGATIVE( + writer->write(CharT{'0'}, number_digits - 1)); } } RET_IF_RESULT_NEGATIVE(writer->write(exp_char)); @@ -426,16 +435,17 @@ template <OverflowMode mode> class FloatWriter { padding_writer.write_left_padding(writer, total_digits)); // Now we know we need to print a leading 1, zeroes up to the decimal // point, the decimal point, and then finally digits after it. - RET_IF_RESULT_NEGATIVE(writer->write('1')); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'1'})); // digits_before_decimal - 1 to account for the leading '1' - RET_IF_RESULT_NEGATIVE(writer->write('0', digits_before_decimal - 1)); + RET_IF_RESULT_NEGATIVE( + writer->write(CharT{'0'}, digits_before_decimal - 1)); if (has_decimal_point) { RET_IF_RESULT_NEGATIVE(writer->write(DECIMAL_POINT)); // add one to digits_before_decimal to account for the decimal point // itself. if (total_digits > digits_before_decimal + 1) { RET_IF_RESULT_NEGATIVE(writer->write( - '0', total_digits - (digits_before_decimal + 1))); + CharT{'0'}, total_digits - (digits_before_decimal + 1))); } } total_digits_written = total_digits; @@ -460,7 +470,7 @@ template <OverflowMode mode> class FloatWriter { if (has_exp) { RET_IF_RESULT_NEGATIVE(writer->write(exp_char)); - const ExponentString buf(exponent); + const ExponentString<CharT> buf(exponent); RET_IF_RESULT_NEGATIVE(writer->write(buf.view())); } total_digits_written = total_digits; @@ -470,7 +480,7 @@ template <OverflowMode mode> class FloatWriter { LIBC_INLINE int write_zeroes(uint32_t num_zeroes) { RET_IF_RESULT_NEGATIVE(flush_buffer()); - RET_IF_RESULT_NEGATIVE(writer->write('0', num_zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, num_zeroes)); return 0; } @@ -479,32 +489,29 @@ template <OverflowMode mode> class FloatWriter { } }; -// Class-template auto deduction helpers, add more if needed. -template <OverflowMode mode> -FloatWriter(Writer<mode>, bool, const PaddingWriter<mode>) -> FloatWriter<mode>; - // This implementation is based on the Ryu Printf algorithm by Ulf Adams: // Ulf Adams. 2019. Ryū revisited: printf floating point conversion. // Proc. ACM Program. Lang. 3, OOPSLA, Article 169 (October 2019), 23 pages. // https://doi.org/10.1145/3360595 -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer, - const FormatSection &to_conv, - fputil::FPBits<T> float_bits) { +LIBC_INLINE int +convert_finite_float_decimal_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits) { // signed because later we use -FRACTION_LEN constexpr int32_t FRACTION_LEN = fputil::FPBits<T>::FRACTION_LEN; int exponent = float_bits.get_explicit_exponent(); - char sign_char = 0; + CharT sign_char = 0; if (float_bits.is_neg()) - sign_char = '-'; + sign_char = CharT{'-'}; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over SPACE_PREFIX else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; // If to_conv doesn't specify a precision, the precision defaults to 6. const unsigned int precision = to_conv.precision < 0 ? 6 : to_conv.precision; @@ -516,8 +523,9 @@ LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer, // ignored. bool nonzero = false; - PaddingWriter<mode> padding_writer(to_conv, sign_char); - FloatWriter float_writer(writer, has_decimal_point, padding_writer); + PaddingWriter<mode, CharT> padding_writer(to_conv, sign_char); + FloatWriter<mode, CharT> float_writer(writer, has_decimal_point, + padding_writer); FloatToString<T> float_converter(float_bits.get_val()); const size_t positive_blocks = float_converter.get_positive_blocks(); @@ -597,32 +605,34 @@ LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer, return WRITE_OK; } -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer, - const FormatSection &to_conv, - fputil::FPBits<T> float_bits) { +LIBC_INLINE int +convert_finite_float_dec_exp_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits) { // signed because later we use -FRACTION_LEN constexpr int32_t FRACTION_LEN = fputil::FPBits<T>::FRACTION_LEN; int exponent = float_bits.get_explicit_exponent(); - char sign_char = 0; + CharT sign_char = 0; if (float_bits.is_neg()) - sign_char = '-'; + sign_char = CharT{'-'}; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over SPACE_PREFIX else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; // If to_conv doesn't specify a precision, the precision defaults to 6. const unsigned int precision = to_conv.precision < 0 ? 6 : to_conv.precision; bool has_decimal_point = (precision > 0) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0); - PaddingWriter<mode> padding_writer(to_conv, sign_char); - FloatWriter float_writer(writer, has_decimal_point, padding_writer); + PaddingWriter<mode, CharT> padding_writer(to_conv, sign_char); + FloatWriter<mode, CharT> float_writer(writer, has_decimal_point, + padding_writer); FloatToString<T> float_converter(float_bits.get_val()); size_t digits_written = 0; @@ -653,13 +663,13 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer, cur_block = 0; } - const size_t block_width = IntegerToString<intmax_t>(digits).size(); + const size_t block_width = DecimalString<CharT>(digits).size(); final_exponent = static_cast<int>(cur_block * BLOCK_SIZE) + static_cast<int>(block_width - 1); int positive_exponent = final_exponent < 0 ? -final_exponent : final_exponent; - size_t exponent_width = IntegerToString<intmax_t>(positive_exponent).size(); + size_t exponent_width = DecimalString<CharT>(positive_exponent).size(); // Calculate the total number of digits in the number. // 1 - the digit before the decimal point @@ -694,7 +704,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer, // if the last block is also the first block, then ignore leading zeroes. if (digits_written == 0) { - last_block_size = IntegerToString<intmax_t>(digits).size(); + last_block_size = DecimalString<CharT>(digits).size(); } // This tracks if the number is truncated, that meaning that the digits after @@ -752,17 +762,18 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer, RET_IF_RESULT_NEGATIVE(float_writer.write_last_block( digits, maximum, round, final_exponent, - internal::islower(to_conv.conv_name) ? 'e' : 'E')); + internal::islower(to_conv.conv_name) ? CharT{'e'} : CharT{'E'})); RET_IF_RESULT_NEGATIVE(float_writer.right_pad()); return WRITE_OK; } -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, - const FormatSection &to_conv, - fputil::FPBits<T> float_bits) { +LIBC_INLINE int +convert_finite_float_dec_auto_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits) { // signed because later we use -FRACTION_LEN constexpr int32_t FRACTION_LEN = fputil::FPBits<T>::FRACTION_LEN; int exponent = float_bits.get_explicit_exponent(); @@ -810,7 +821,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, // In the case of 0.0, then it's always decimal format. If we don't have alt // form then the trailing zeroes are trimmed to make "0", else the precision // is 1 less than specified by the user. - FormatSection new_conv = to_conv; + FormatSection<CharT> new_conv = to_conv; if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) { // This is a style F conversion, making the precision P - 1 - X, but since // this is for the number 0, X (the base 10 exponent) is always 0. @@ -818,10 +829,10 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, } else { new_conv.precision = 0; } - return convert_float_decimal_typed<T>(writer, new_conv, float_bits); + return convert_finite_float_decimal_typed<T>(writer, new_conv, float_bits); } - const size_t block_width = IntegerToString<intmax_t>(digits).size(); + const size_t block_width = DecimalString<CharT>(digits).size(); size_t digits_checked = 0; // TODO: look into unifying trailing_zeroes and trailing_nines. The number can @@ -834,14 +845,14 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, // If the first block is not also the last block if (block_width <= exp_precision + 1) { - const DecimalString buf(digits); - const cpp::string_view int_to_str = buf.view(); + const DecimalString<CharT> buf(digits); + const cpp::basic_string_view<CharT> int_to_str = buf.view(); for (size_t i = 0; i < block_width; ++i) { - if (int_to_str[i] == '9') { + if (int_to_str[i] == CharT{'9'}) { ++trailing_nines; trailing_zeroes = 0; - } else if (int_to_str[i] == '0') { + } else if (int_to_str[i] == CharT{'0'}) { ++trailing_zeroes; trailing_nines = 0; } else { @@ -896,8 +907,8 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, size_t last_block_size = BLOCK_SIZE; - const DecimalString buf(digits); - const cpp::string_view int_to_str = buf.view(); + const DecimalString<CharT> buf(digits); + const cpp::basic_string_view<CharT> int_to_str = buf.view(); size_t implicit_leading_zeroes = BLOCK_SIZE - int_to_str.size(); @@ -931,10 +942,10 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, // Check the upper digits of this block. for (int i = 0; i < digits_to_check; ++i) { - if (int_to_str[i] == '9') { + if (int_to_str[i] == CharT{'9'}) { ++trailing_nines; trailing_zeroes = 0; - } else if (int_to_str[i] == '0') { + } else if (int_to_str[i] == CharT{'0'}) { ++trailing_zeroes; trailing_nines = 0; } else { @@ -1064,7 +1075,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, // if P > X >= -4, the conversion is with style f (or F) and precision equals // P - (X + 1). if (static_cast<int>(init_precision) > base_10_exp && base_10_exp >= -4) { - FormatSection new_conv = to_conv; + FormatSection<CharT> new_conv = to_conv; const int conv_precision = init_precision - (base_10_exp + 1); if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) { @@ -1100,12 +1111,12 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, : trimmed_precision; } - return convert_float_decimal_typed<T>(writer, new_conv, float_bits); + return convert_finite_float_decimal_typed<T>(writer, new_conv, float_bits); } else { // otherwise, the conversion is with style e (or E) and precision equals // P - 1 const int conv_precision = init_precision - 1; - FormatSection new_conv = to_conv; + FormatSection<CharT> new_conv = to_conv; if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) { new_conv.precision = conv_precision; } else { @@ -1120,22 +1131,26 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, ? conv_precision : trimmed_precision; } - return convert_float_dec_exp_typed<T>(writer, new_conv, float_bits); + return convert_finite_float_dec_exp_typed<T>(writer, new_conv, float_bits); } } // TODO: unify the float converters to remove the duplicated checks for inf/nan. -template <OverflowMode mode> -LIBC_INLINE int convert_float_decimal(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_decimal(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { + InfNanFPBitsProperties inf_nan_properties; #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) if (to_conv.length_modifier == LengthModifier::Q) { fputil::FPBits<float128>::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits<float128> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_decimal_typed<float128>(writer, to_conv, float_bits); + return convert_finite_float_decimal_typed<float128>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 #ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE @@ -1145,9 +1160,11 @@ LIBC_INLINE int convert_float_decimal(Writer<mode> *writer, to_conv.conv_val_raw); fputil::FPBits<long double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_decimal_typed<long double>(writer, to_conv, - float_bits); + return convert_finite_float_decimal_typed<long double>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE { @@ -1155,23 +1172,30 @@ LIBC_INLINE int convert_float_decimal(Writer<mode> *writer, static_cast<fputil::FPBits<double>::StorageType>(to_conv.conv_val_raw); fputil::FPBits<double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_decimal_typed<double>(writer, to_conv, float_bits); + return convert_finite_float_decimal_typed<double>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } - return convert_inf_nan(writer, to_conv); + return convert_inf_nan(writer, inf_nan_properties, to_conv); } -template <OverflowMode mode> -LIBC_INLINE int convert_float_dec_exp(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_dec_exp(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { + InfNanFPBitsProperties inf_nan_properties; #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) if (to_conv.length_modifier == LengthModifier::Q) { fputil::FPBits<float128>::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits<float128> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_dec_exp_typed<float128>(writer, to_conv, float_bits); + return convert_finite_float_dec_exp_typed<float128>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 #ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE @@ -1181,9 +1205,11 @@ LIBC_INLINE int convert_float_dec_exp(Writer<mode> *writer, to_conv.conv_val_raw); fputil::FPBits<long double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_dec_exp_typed<long double>(writer, to_conv, - float_bits); + return convert_finite_float_dec_exp_typed<long double>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE { @@ -1191,24 +1217,30 @@ LIBC_INLINE int convert_float_dec_exp(Writer<mode> *writer, static_cast<fputil::FPBits<double>::StorageType>(to_conv.conv_val_raw); fputil::FPBits<double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_dec_exp_typed<double>(writer, to_conv, float_bits); + return convert_finite_float_dec_exp_typed<double>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } - return convert_inf_nan(writer, to_conv); + return convert_inf_nan(writer, inf_nan_properties, to_conv); } -template <OverflowMode mode> -LIBC_INLINE int convert_float_dec_auto(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_dec_auto(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { + InfNanFPBitsProperties inf_nan_properties; #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) if (to_conv.length_modifier == LengthModifier::Q) { fputil::FPBits<float128>::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits<float128> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_dec_auto_typed<float128>(writer, to_conv, - float_bits); + return convert_finite_float_dec_auto_typed<float128>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 #ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE @@ -1218,9 +1250,11 @@ LIBC_INLINE int convert_float_dec_auto(Writer<mode> *writer, to_conv.conv_val_raw); fputil::FPBits<long double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_dec_auto_typed<long double>(writer, to_conv, - float_bits); + return convert_finite_float_dec_auto_typed<long double>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE { @@ -1228,11 +1262,14 @@ LIBC_INLINE int convert_float_dec_auto(Writer<mode> *writer, static_cast<fputil::FPBits<double>::StorageType>(to_conv.conv_val_raw); fputil::FPBits<double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_dec_auto_typed<double>(writer, to_conv, float_bits); + return convert_finite_float_dec_auto_typed<double>(writer, to_conv, + float_bits); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } - return convert_inf_nan(writer, to_conv); + return convert_inf_nan(writer, inf_nan_properties, to_conv); } } // namespace printf_core diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter_limited.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter_limited.h index 7aa886db37a3..0a21784c61b1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter_limited.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_dec_converter_limited.h @@ -47,6 +47,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/ctype_utils.h" #include "src/__support/integer_to_string.h" #include "src/__support/libc_assert.h" #include "src/__support/macros/config.h" @@ -55,6 +56,10 @@ #include "src/__support/printf_core/writer.h" #include "src/string/memory_utils/inline_memcpy.h" +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) +#include "src/__support/wctype_utils.h" +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + namespace LIBC_NAMESPACE_DECL { namespace printf_core { @@ -91,7 +96,7 @@ struct DigitsInput { } }; -struct DigitsOutput { +template <typename CharT> struct DigitsOutput { // Output from decimal_digits(). // // `digits` is a buffer containing nothing but ASCII digits. Even if the @@ -104,7 +109,7 @@ struct DigitsOutput { // and exponent = 3 then this represents 1.234e3, or just the integer 1234. size_t ndigits; int exponent; - char digits[MAX_DIGITS + 1]; + CharT digits[MAX_DIGITS + 1]; }; // Estimate log10 of a power of 2, by multiplying its exponent by @@ -127,12 +132,13 @@ LIBC_INLINE int estimate_log10(int exponent_of_2) { // `decimal_digits` has a place value of _at least_ 10^-precision. But also, at // most `MAX_DIGITS` digits are returned, so the caller may need to pad it at // the end with the appropriate number of extra 0s. -LIBC_INLINE -DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) { +template <typename CharT> +LIBC_INLINE DigitsOutput<CharT> decimal_digits(DigitsInput input, int precision, + bool e_mode) { if (input.mantissa == 0) { - // Special-case zero, by manually generating the right number of zero - // digits and setting an appropriate exponent. - DigitsOutput output; + // Special-case zero, by manually setting the right number of zero digits + // and setting an appropriate exponent. + DigitsOutput<CharT> output = {}; if (!e_mode) { // In F mode, it's enough to return an empty string of digits. That's the // same thing we do when given a nonzero number that rounds down to 0. @@ -140,7 +146,8 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) { output.exponent = -precision - 1; } else { // In E mode, generate a string containing the expected number of 0s. - __builtin_memset(output.digits, '0', precision); + for (int i = 0; i < precision; ++i) + output.digits[i] = CharT{'0'}; output.ndigits = precision; output.exponent = 0; } @@ -247,7 +254,7 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) { // Start making the output struct, by copying in the digits from the above // object. At this stage we may also have one digit too many (but that's OK, // there's space for it in the DigitsOutput buffer). - DigitsOutput output; + DigitsOutput<CharT> output; output.ndigits = view.size(); inline_memcpy(output.digits, view.data(), output.ndigits); @@ -360,12 +367,12 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) { // at a time. (A bit painful, but better than going back to the integer // we made it from and doing the decimal conversion all over again.) for (size_t i = output.ndigits; i-- > 0;) { - if (output.digits[i] != '9') { + if (output.digits[i] != CharT{'9'}) { output.digits[i] = internal::int_to_b36_char( internal::b36_char_to_int(output.digits[i]) + 1); break; } else { - output.digits[i] = '0'; + output.digits[i] = CharT{'0'}; } } } @@ -374,26 +381,26 @@ DigitsOutput decimal_digits(DigitsInput input, int precision, bool e_mode) { return output; } -template <OverflowMode mode> -LIBC_INLINE int convert_float_inner(Writer<mode> *writer, - const FormatSection &to_conv, - int32_t fraction_len, int exponent, - AnyFloatStorageType mantissa, Sign sign, - ConversionType ctype) { - constexpr char DECIMAL_POINT = '.'; +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_finite_float_inner(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + int32_t fraction_len, int exponent, + AnyFloatStorageType mantissa, + Sign sign, ConversionType ctype) { + constexpr CharT DECIMAL_POINT = CharT{'.'}; // If to_conv doesn't specify a precision, the precision defaults to 6. unsigned precision = to_conv.precision < 0 ? 6 : to_conv.precision; // Decide if we're displaying a sign character, depending on the format flags // and whether the input is negative. - char sign_char = 0; + CharT sign_char = 0; if (sign.is_neg()) - sign_char = '-'; + sign_char = CharT{'-'}; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over SPACE_PREFIX else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; // Prepare the input to decimal_digits(). DigitsInput input(fraction_len, mantissa, exponent, sign); @@ -403,7 +410,7 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // in the following variables: // The decimal digits, and the exponent of the topmost one. - DigitsOutput output; + DigitsOutput<CharT> output; // The start and end of the digit string we're displaying, as indices into // `output.digits`. The indices may be out of bounds in either direction, in // which case digits beyond the bounds of the buffer should be displayed as @@ -424,7 +431,8 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // (`%.6e` means six digits _after_ the decimal point, like 1.123456e+00). // // Also, bound the number of digits we request at MAX_DIGITS. - output = decimal_digits(input, cpp::min(precision + 1, MAX_DIGITS), true); + output = + decimal_digits<CharT>(input, cpp::min(precision + 1, MAX_DIGITS), true); // We display digits from the start of the buffer, and always output // `precision+1` of them (which will append zeroes if the user requested @@ -441,7 +449,7 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, case ConversionType::F: // In F mode, we provide decimal_digits() with the unmodified input // precision, and let it give us as many digits as we can. - output = decimal_digits(input, precision, false); + output = decimal_digits<CharT>(input, precision, false); // Initialize (start, limit) to display everything from the first nonzero // digit (necessarily at the start of the output buffer) to the digit at @@ -470,7 +478,8 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // // Also, a precision of 0 is treated the same as 1. precision = cpp::max(precision, 1u); - output = decimal_digits(input, cpp::min(precision, MAX_DIGITS), true); + output = + decimal_digits<CharT>(input, cpp::min(precision, MAX_DIGITS), true); // As in E mode, we default to displaying precisely the digits in the // output buffer. @@ -486,7 +495,7 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, limit = cpp::min(limit, int(output.ndigits)); // Then check the digits in the buffer and remove as many as possible. - while (limit > 1 && output.digits[limit - 1] == '0') + while (limit > 1 && output.digits[limit - 1] == CharT{'0'}) limit--; } @@ -543,14 +552,14 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // Format the exponent suffix (e+NN, e-NN) into a buffer, or leave the buffer // empty if we're not displaying one. - char expbuf[16]; // more than enough space for e+NNNN + CharT expbuf[16]; // more than enough space for e+NNNN size_t explen = 0; if (show_exponent) { const IntegerToString<decltype(output.exponent), radix::Dec::WithWidth<2>::WithSign> expcvt{output.exponent}; cpp::string_view expview = expcvt.view(); - expbuf[0] = internal::islower(to_conv.conv_name) ? 'e' : 'E'; + expbuf[0] = internal::islower(to_conv.conv_name) ? CharT{'e'} : CharT{'E'}; explen = expview.size() + 1; inline_memcpy(expbuf + 1, expview.data(), expview.size()); } @@ -583,7 +592,7 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // Leading-space padding, if any if (padding == Padding::LeadingSpace) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_amount)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding_amount)); // Sign, if any if (sign_char) @@ -591,7 +600,7 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // Zero padding, if any if (padding == Padding::Zero) - RET_IF_RESULT_NEGATIVE(writer->write('0', padding_amount)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, padding_amount)); // Mantissa digits, maybe with a decimal point for (int pos = start; pos < limit; ++pos) { @@ -600,7 +609,7 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, RET_IF_RESULT_NEGATIVE(writer->write(output.digits[pos])); } else { // This digit is outside the buffer, so write a zero - RET_IF_RESULT_NEGATIVE(writer->write('0')); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'})); } // Show the decimal point, if this is the digit it comes after @@ -613,34 +622,39 @@ LIBC_INLINE int convert_float_inner(Writer<mode> *writer, // Trailing-space padding, if any if (padding == Padding::TrailingSpace) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_amount)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding_amount)); return WRITE_OK; } -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int -convert_float_typed(Writer<mode> *writer, const FormatSection &to_conv, - fputil::FPBits<T> float_bits, ConversionType ctype) { - return convert_float_inner(writer, to_conv, float_bits.FRACTION_LEN, - float_bits.get_explicit_exponent(), - float_bits.get_explicit_mantissa(), - float_bits.sign(), ctype); +LIBC_INLINE int convert_finite_float_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits, + ConversionType ctype) { + return convert_finite_float_inner(writer, to_conv, float_bits.FRACTION_LEN, + float_bits.get_explicit_exponent(), + float_bits.get_explicit_mantissa(), + float_bits.sign(), ctype); } -template <OverflowMode mode> -LIBC_INLINE int convert_float_outer(Writer<mode> *writer, - const FormatSection &to_conv, +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_outer(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, ConversionType ctype) { + InfNanFPBitsProperties inf_nan_properties; #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) if (to_conv.length_modifier == LengthModifier::Q) { fputil::FPBits<float128> float_bits( static_cast<fputil::FPBits<float128>::StorageType>( to_conv.conv_val_raw)); if (!float_bits.is_inf_or_nan()) { - return convert_float_typed<float128>(writer, to_conv, float_bits, ctype); + return convert_finite_float_typed<float128>(writer, to_conv, float_bits, + ctype); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 #ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE @@ -649,9 +663,11 @@ LIBC_INLINE int convert_float_outer(Writer<mode> *writer, static_cast<fputil::FPBits<long double>::StorageType>( to_conv.conv_val_raw)); if (!float_bits.is_inf_or_nan()) { - return convert_float_typed<long double>(writer, to_conv, float_bits, - ctype); + return convert_finite_float_typed<long double>(writer, to_conv, + float_bits, ctype); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } else #endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE { @@ -659,52 +675,61 @@ LIBC_INLINE int convert_float_outer(Writer<mode> *writer, static_cast<fputil::FPBits<double>::StorageType>(to_conv.conv_val_raw); fputil::FPBits<double> float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { - return convert_float_typed<double>(writer, to_conv, float_bits, ctype); + return convert_finite_float_typed<double>(writer, to_conv, float_bits, + ctype); } + inf_nan_properties = {.is_negative = float_bits.is_neg(), + .mantissa_is_zero = float_bits.get_mantissa() == 0}; } - return convert_inf_nan(writer, to_conv); + return convert_inf_nan(writer, inf_nan_properties, to_conv); } -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int convert_float_decimal_typed(Writer<mode> *writer, - const FormatSection &to_conv, - fputil::FPBits<T> float_bits) { - return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::F); +LIBC_INLINE int +convert_finite_float_decimal_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits) { + return convert_finite_float_typed<T>(writer, to_conv, float_bits, + ConversionType::F); } -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int convert_float_dec_exp_typed(Writer<mode> *writer, - const FormatSection &to_conv, - fputil::FPBits<T> float_bits) { - return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::E); +LIBC_INLINE int +convert_finite_float_dec_exp_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits) { + return convert_finite_float_typed<T>(writer, to_conv, float_bits, + ConversionType::E); } -template <typename T, OverflowMode mode, +template <typename T, OverflowMode mode, typename CharT, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> -LIBC_INLINE int convert_float_dec_auto_typed(Writer<mode> *writer, - const FormatSection &to_conv, - fputil::FPBits<T> float_bits) { - return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::G); +LIBC_INLINE int +convert_finite_float_dec_auto_typed(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv, + fputil::FPBits<T> float_bits) { + return convert_finite_float_typed<T>(writer, to_conv, float_bits, + ConversionType::G); } -template <OverflowMode mode> -LIBC_INLINE int convert_float_decimal(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_decimal(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { return convert_float_outer(writer, to_conv, ConversionType::F); } -template <OverflowMode mode> -LIBC_INLINE int convert_float_dec_exp(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_dec_exp(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { return convert_float_outer(writer, to_conv, ConversionType::E); } -template <OverflowMode mode> -LIBC_INLINE int convert_float_dec_auto(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_dec_auto(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { return convert_float_outer(writer, to_conv, ConversionType::G); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_hex_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_hex_converter.h index 15f3d9f05a12..156f87518a0d 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_hex_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_hex_converter.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_FLOAT_HEX_CONVERTER_H #include "src/__support/CPP/string_view.h" +#include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/ctype_utils.h" @@ -19,6 +20,10 @@ #include "src/__support/printf_core/float_inf_nan_converter.h" #include "src/__support/printf_core/writer.h" +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) +#include "src/__support/wctype_utils.h" +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + #include <inttypes.h> #include <stddef.h> @@ -26,30 +31,53 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { struct FloatHexExpFPBitsProperties { - bool is_negative; - int exponent; AnyFloatStorageType mantissa; - bool is_inf_or_nan; + int exponent; uint32_t fraction_bits; + bool is_negative; + bool is_inf_or_nan; + bool mantissa_is_zero; }; template <typename T> -FloatHexExpFPBitsProperties -get_float_hex_exp_fp_bits_properties(AnyFloatStorageType float_raw) { - fputil::FPBits<T> float_bits( - static_cast<typename fputil::FPBits<T>::StorageType>(float_raw)); +LIBC_INLINE FloatHexExpFPBitsProperties +get_float_hex_exp_fp_bits_properties_typed(fputil::FPBits<T> float_bits) { return { - .is_negative = float_bits.is_neg(), - .exponent = float_bits.get_explicit_exponent(), .mantissa = float_bits.get_explicit_mantissa(), - .is_inf_or_nan = float_bits.is_inf_or_nan(), + .exponent = float_bits.get_explicit_exponent(), .fraction_bits = fputil::FPBits<T>::FRACTION_LEN, + .is_negative = float_bits.is_neg(), + .is_inf_or_nan = float_bits.is_inf_or_nan(), + .mantissa_is_zero = float_bits.get_mantissa() == 0, }; } -template <OverflowMode mode> -LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, - const FormatSection &to_conv) { +// Returns relevant floating point properties for conversion using +// `length_modifier` to infer the conversion value type. +LIBC_INLINE FloatHexExpFPBitsProperties get_float_hex_exp_fp_bits_properties_lm( + LengthModifier length_modifier, AnyFloatStorageType conv_val_raw) { +#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) + if (length_modifier == LengthModifier::Q) + return get_float_hex_exp_fp_bits_properties_typed<float128>( + fputil::FPBits<float128>(conv_val_raw)); +#endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + if (length_modifier == LengthModifier::L) + return get_float_hex_exp_fp_bits_properties_typed<long double>( + fputil::FPBits<long double>( + static_cast<fputil::FPBits<long double>::StorageType>( + conv_val_raw))); +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + return get_float_hex_exp_fp_bits_properties_typed<double>( + fputil::FPBits<double>( + static_cast<fputil::FPBits<double>::StorageType>(conv_val_raw))); +} + +template <OverflowMode mode, typename CharT> +LIBC_INLINE int +convert_finite_float_hex_exp(Writer<mode, CharT> *writer, + FloatHexExpFPBitsProperties fp_bits_properties, + const FormatSection<CharT> &to_conv) { #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) static constexpr uint32_t MAX_POSSIBLE_FRACTION_LEN = fputil::FPBits<float128>::FRACTION_LEN; @@ -67,36 +95,16 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, fputil::FPBits<double>::EXP_LEN; #endif - FloatHexExpFPBitsProperties properties; -#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) - if (to_conv.length_modifier == LengthModifier::Q) { - properties = - get_float_hex_exp_fp_bits_properties<float128>(to_conv.conv_val_raw); - } else -#endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 -#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE - if (to_conv.length_modifier == LengthModifier::L) { - properties = - get_float_hex_exp_fp_bits_properties<long double>(to_conv.conv_val_raw); - } else -#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE - { - properties = - get_float_hex_exp_fp_bits_properties<double>(to_conv.conv_val_raw); - } + CharT sign_char = 0; - if (properties.is_inf_or_nan) - return convert_inf_nan(writer, to_conv); - - char sign_char = 0; - - if (properties.is_negative) - sign_char = '-'; + if (fp_bits_properties.is_negative) + sign_char = CharT{'-'}; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over + // SPACE_PREFIX else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; constexpr size_t BITS_IN_HEX_DIGIT = 4; @@ -104,9 +112,10 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, // digits. This is primarily relevant for x86 80 bit long doubles, which have // 63 bit mantissas. In the case where the mantissa is 0, however, the // exponent should stay as 0. - if (properties.fraction_bits % BITS_IN_HEX_DIGIT != 0 && - properties.mantissa > 0) { - properties.exponent -= properties.fraction_bits % BITS_IN_HEX_DIGIT; + if (fp_bits_properties.fraction_bits % BITS_IN_HEX_DIGIT != 0 && + fp_bits_properties.mantissa > 0) { + fp_bits_properties.exponent -= + fp_bits_properties.fraction_bits % BITS_IN_HEX_DIGIT; } // This is the max number of digits it can take to represent the mantissa. @@ -115,9 +124,9 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, // since the size must be constant. constexpr size_t MANT_BUFF_LEN = (MAX_POSSIBLE_FRACTION_LEN / BITS_IN_HEX_DIGIT) + 1; - char mant_buffer[MANT_BUFF_LEN]; + CharT mant_buffer[MANT_BUFF_LEN]; - size_t mant_len = (properties.fraction_bits / BITS_IN_HEX_DIGIT) + 1; + size_t mant_len = (fp_bits_properties.fraction_bits / BITS_IN_HEX_DIGIT) + 1; // Precision only tracks the number of digits after the hexadecimal point, so // we have to add one to account for the digit before the hexadecimal point. @@ -128,34 +137,37 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, (mant_len - intended_digits) * BITS_IN_HEX_DIGIT; const AnyFloatStorageType truncated_bits = - properties.mantissa & ((AnyFloatStorageType(1) << shift_amount) - 1); + fp_bits_properties.mantissa & + ((AnyFloatStorageType(1) << shift_amount) - 1); const AnyFloatStorageType halfway_const = AnyFloatStorageType(1) << (shift_amount - 1); - properties.mantissa >>= shift_amount; + fp_bits_properties.mantissa >>= shift_amount; #ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY // Round to nearest, if it's exactly halfway then round to even. if (truncated_bits > halfway_const) - ++properties.mantissa; + ++fp_bits_properties.mantissa; else if (truncated_bits == halfway_const) - properties.mantissa = properties.mantissa + (properties.mantissa & 1); + fp_bits_properties.mantissa = + fp_bits_properties.mantissa + (fp_bits_properties.mantissa & 1); #else switch (fputil::quick_get_round()) { case FE_TONEAREST: // Round to nearest, if it's exactly halfway then round to even. if (truncated_bits > halfway_const) - ++properties.mantissa; + ++fp_bits_properties.mantissa; else if (truncated_bits == halfway_const) - properties.mantissa = properties.mantissa + (properties.mantissa & 1); + fp_bits_properties.mantissa = + fp_bits_properties.mantissa + (fp_bits_properties.mantissa & 1); break; case FE_DOWNWARD: - if (truncated_bits > 0 && properties.is_negative) - ++properties.mantissa; + if (truncated_bits > 0 && fp_bits_properties.is_negative) + ++fp_bits_properties.mantissa; break; case FE_UPWARD: - if (truncated_bits > 0 && !properties.is_negative) - ++properties.mantissa; + if (truncated_bits > 0 && !fp_bits_properties.is_negative) + ++fp_bits_properties.mantissa; break; case FE_TOWARDZERO: break; @@ -164,10 +176,10 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, // If the rounding caused an overflow, shift the mantissa and adjust the // exponent to match. - if (properties.mantissa >= + if (fp_bits_properties.mantissa >= (AnyFloatStorageType(1) << (intended_digits * BITS_IN_HEX_DIGIT))) { - properties.mantissa >>= BITS_IN_HEX_DIGIT; - properties.exponent += BITS_IN_HEX_DIGIT; + fp_bits_properties.mantissa >>= BITS_IN_HEX_DIGIT; + fp_bits_properties.exponent += BITS_IN_HEX_DIGIT; } mant_len = intended_digits; @@ -175,13 +187,24 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, size_t mant_cur = mant_len; size_t first_non_zero = 1; - for (; mant_cur > 0; --mant_cur, properties.mantissa >>= 4) { - char mant_mod_16 = static_cast<char>(properties.mantissa % 16); - char new_digit = internal::int_to_b36_char(mant_mod_16); - if (internal::isupper(to_conv.conv_name)) + bool is_upper = internal::isupper(to_conv.conv_name); + for (; mant_cur > 0; --mant_cur, fp_bits_properties.mantissa >>= 4) { + int mant_mod_16 = static_cast<int>(fp_bits_properties.mantissa % 16); + CharT new_digit; + if constexpr (cpp::is_same_v<CharT, char>) { + new_digit = internal::int_to_b36_char(mant_mod_16); + } else { +#if defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + static_assert(false, "wchar_t not supported."); +#else // LIBC_COPT_PRINTF_DISABLE_WIDE + static_assert(cpp::is_same_v<CharT, wchar_t>); + new_digit = internal::int_to_b36_wchar(mant_mod_16); +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + } + if (is_upper) new_digit = internal::toupper(new_digit); mant_buffer[mant_cur - 1] = new_digit; - if (new_digit != '0' && first_non_zero < mant_cur) + if (new_digit != CharT{'0'} && first_non_zero < mant_cur) first_non_zero = mant_cur; } @@ -197,25 +220,36 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, // 11 -> 4 // 8 -> 3 constexpr size_t EXP_LEN = (((MAX_POSSIBLE_EXP_LEN * 5) + 15) / 16) + 1; - char exp_buffer[EXP_LEN]; + CharT exp_buffer[EXP_LEN]; bool exp_is_negative = false; - if (properties.exponent < 0) { + if (fp_bits_properties.exponent < 0) { exp_is_negative = true; - properties.exponent = -properties.exponent; + fp_bits_properties.exponent = -fp_bits_properties.exponent; } size_t exp_cur = EXP_LEN; - for (; properties.exponent > 0; --exp_cur, properties.exponent /= 10) { - exp_buffer[exp_cur - 1] = - internal::int_to_b36_char(properties.exponent % 10); + for (; fp_bits_properties.exponent > 0; + --exp_cur, fp_bits_properties.exponent /= 10) { + if constexpr (cpp::is_same_v<CharT, char>) { + exp_buffer[exp_cur - 1] = + internal::int_to_b36_char(fp_bits_properties.exponent % 10); + } else { +#if defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + static_assert(false, "wchar_t not supported."); +#else // LIBC_COPT_PRINTF_DISABLE_WIDE + static_assert(cpp::is_same_v<CharT, wchar_t>); + exp_buffer[exp_cur - 1] = + internal::int_to_b36_wchar(fp_bits_properties.exponent % 10); +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + } } if (exp_cur == EXP_LEN) { // if nothing else was written, write a 0. - exp_buffer[EXP_LEN - 1] = '0'; + exp_buffer[EXP_LEN - 1] = CharT{'0'}; exp_cur = EXP_LEN - 1; } - exp_buffer[exp_cur - 1] = exp_is_negative ? '-' : '+'; + exp_buffer[exp_cur - 1] = exp_is_negative ? CharT{'-'} : CharT{'+'}; --exp_cur; // these are signed to prevent underflow due to negative values. The eventual @@ -225,10 +259,10 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, // prefix is "0x", and always appears. constexpr size_t PREFIX_LEN = 2; - char prefix[PREFIX_LEN]; - prefix[0] = '0'; - prefix[1] = internal::islower(to_conv.conv_name) ? 'x' : 'X'; - const cpp::string_view prefix_str(prefix, PREFIX_LEN); + CharT prefix[PREFIX_LEN]; + prefix[0] = CharT{'0'}; + prefix[1] = is_upper ? CharT{'X'} : CharT{'x'}; + const cpp::basic_string_view<CharT> prefix_str(prefix, PREFIX_LEN); // If the precision is greater than the actual result, pad with 0s if (to_conv.precision > static_cast<int>(mant_digits - 1)) @@ -237,10 +271,11 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, bool has_hexadecimal_point = (mant_digits > 1) || ((to_conv.flags & FormatFlags::ALTERNATE_FORM) == FormatFlags::ALTERNATE_FORM); - constexpr cpp::string_view HEXADECIMAL_POINT("."); + + constexpr CharT HEXADECIMAL_POINT = CharT{'.'}; // This is for the letter 'p' before the exponent. - const char exp_separator = internal::islower(to_conv.conv_name) ? 'p' : 'P'; + const CharT exp_separator = is_upper ? CharT{'P'} : CharT{'p'}; constexpr int EXP_SEPARATOR_LEN = 1; padding = static_cast<int>(to_conv.min_width - (sign_char > 0 ? 1 : 0) - @@ -263,31 +298,31 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, if (mant_digits > 1) RET_IF_RESULT_NEGATIVE(writer->write({mant_buffer + 1, mant_digits - 1})); if (trailing_zeroes > 0) - RET_IF_RESULT_NEGATIVE(writer->write('0', trailing_zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, trailing_zeroes)); RET_IF_RESULT_NEGATIVE(writer->write(exp_separator)); RET_IF_RESULT_NEGATIVE( writer->write({exp_buffer + exp_cur, EXP_LEN - exp_cur})); if (padding > 0) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding)); } else { // The pattern is (spaces), (sign), 0x, (zeroes), digit, (.), (other // digits), (zeroes), p, exponent if ((padding > 0) && ((to_conv.flags & FormatFlags::LEADING_ZEROES) != FormatFlags::LEADING_ZEROES)) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding)); if (sign_char > 0) RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); RET_IF_RESULT_NEGATIVE(writer->write(prefix_str)); if ((padding > 0) && ((to_conv.flags & FormatFlags::LEADING_ZEROES) == FormatFlags::LEADING_ZEROES)) - RET_IF_RESULT_NEGATIVE(writer->write('0', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, padding)); RET_IF_RESULT_NEGATIVE(writer->write(mant_buffer[0])); if (has_hexadecimal_point) RET_IF_RESULT_NEGATIVE(writer->write(HEXADECIMAL_POINT)); if (mant_digits > 1) RET_IF_RESULT_NEGATIVE(writer->write({mant_buffer + 1, mant_digits - 1})); if (trailing_zeroes > 0) - RET_IF_RESULT_NEGATIVE(writer->write('0', trailing_zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, trailing_zeroes)); RET_IF_RESULT_NEGATIVE(writer->write(exp_separator)); RET_IF_RESULT_NEGATIVE( writer->write({exp_buffer + exp_cur, EXP_LEN - exp_cur})); @@ -295,6 +330,22 @@ LIBC_INLINE int convert_float_hex_exp(Writer<mode> *writer, return WRITE_OK; } +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_float_hex_exp(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { + FloatHexExpFPBitsProperties fp_bits_properties = + get_float_hex_exp_fp_bits_properties_lm(to_conv.length_modifier, + to_conv.conv_val_raw); + if (fp_bits_properties.is_inf_or_nan) + return convert_inf_nan( + writer, + InfNanFPBitsProperties{.is_negative = fp_bits_properties.is_negative, + .mantissa_is_zero = + fp_bits_properties.mantissa_is_zero}, + to_conv); + return convert_finite_float_hex_exp(writer, fp_bits_properties, to_conv); +} + } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_inf_nan_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_inf_nan_converter.h index 40740c701d99..be16d515e472 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_inf_nan_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/float_inf_nan_converter.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_FLOAT_INF_NAN_CONVERTER_H #define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_FLOAT_INF_NAN_CONVERTER_H +#include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/ctype_utils.h" #include "src/__support/macros/config.h" @@ -16,6 +17,10 @@ #include "src/__support/printf_core/core_structs.h" #include "src/__support/printf_core/writer.h" +#if !defined(LIBC_COPT_PRINTF_DISABLE_WIDE) +#include "src/__support/wctype_utils.h" +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + #include <inttypes.h> #include <stddef.h> @@ -27,47 +32,22 @@ struct InfNanFPBitsProperties { bool mantissa_is_zero; }; -template <typename T> -InfNanFPBitsProperties -get_inf_nan_fp_bits_properties(AnyFloatStorageType float_raw) { - fputil::FPBits<T> float_bits( - static_cast<typename fputil::FPBits<T>::StorageType>(float_raw)); - return { - .is_negative = float_bits.is_neg(), - .mantissa_is_zero = float_bits.get_mantissa() == 0, - }; -} - -template <OverflowMode mode> -LIBC_INLINE int convert_inf_nan(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_inf_nan(Writer<mode, CharT> *writer, + InfNanFPBitsProperties fp_bits_properties, + const FormatSection<CharT> &to_conv) { // All of the letters will be defined relative to variable a, which will be // the appropriate case based on the case of the conversion. - InfNanFPBitsProperties properties; -#if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) - if (to_conv.length_modifier == LengthModifier::Q) { - properties = get_inf_nan_fp_bits_properties<float128>(to_conv.conv_val_raw); - } else -#endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 -#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE - if (to_conv.length_modifier == LengthModifier::L) { - properties = - get_inf_nan_fp_bits_properties<long double>(to_conv.conv_val_raw); - } else -#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE - { - properties = get_inf_nan_fp_bits_properties<double>(to_conv.conv_val_raw); - } - - char sign_char = 0; + CharT sign_char = 0; - if (properties.is_negative) - sign_char = '-'; + if (fp_bits_properties.is_negative) + sign_char = CharT{'-'}; else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over + // SPACE_PREFIX else if ((to_conv.flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; // Both "inf" and "nan" are the same number of characters, being 3. int padding = to_conv.min_width - (sign_char > 0 ? 1 : 0) - 3; @@ -77,21 +57,41 @@ LIBC_INLINE int convert_inf_nan(Writer<mode> *writer, if (padding > 0 && ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) != FormatFlags::LEFT_JUSTIFIED)) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding)); if (sign_char) RET_IF_RESULT_NEGATIVE(writer->write(sign_char)); - if (properties.mantissa_is_zero) { // inf - RET_IF_RESULT_NEGATIVE( - writer->write(internal::islower(to_conv.conv_name) ? "inf" : "INF")); + if (fp_bits_properties.mantissa_is_zero) { // inf + if constexpr (cpp::is_same_v<CharT, char>) { + RET_IF_RESULT_NEGATIVE( + writer->write(internal::islower(to_conv.conv_name) ? "inf" : "INF")); + } else { +#if defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + static_assert(false, "wchar_t not supported."); +#else // LIBC_COPT_PRINTF_DISABLE_WIDE + static_assert(cpp::is_same_v<CharT, wchar_t>); + RET_IF_RESULT_NEGATIVE(writer->write( + internal::islower(to_conv.conv_name) ? L"inf" : L"INF")); +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + } } else { // nan - RET_IF_RESULT_NEGATIVE( - writer->write(internal::islower(to_conv.conv_name) ? "nan" : "NAN")); + if constexpr (cpp::is_same_v<CharT, char>) { + RET_IF_RESULT_NEGATIVE( + writer->write(internal::islower(to_conv.conv_name) ? "nan" : "NAN")); + } else { +#if defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + static_assert(false, "wchar_t not supported."); +#else // LIBC_COPT_PRINTF_DISABLE_WIDE + static_assert(cpp::is_same_v<CharT, wchar_t>); + RET_IF_RESULT_NEGATIVE(writer->write( + internal::islower(to_conv.conv_name) ? L"nan" : L"NAN")); +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + } } if (padding > 0 && ((to_conv.flags & FormatFlags::LEFT_JUSTIFIED) == FormatFlags::LEFT_JUSTIFIED)) - RET_IF_RESULT_NEGATIVE(writer->write(' ', padding)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, padding)); return WRITE_OK; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/int_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/int_converter.h index 786d9ff2268f..97c29e0da3c1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/int_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/int_converter.h @@ -26,16 +26,27 @@ namespace printf_core { namespace details { -using HexFmt = IntegerToString<uintmax_t, radix::Hex>; -using HexFmtUppercase = IntegerToString<uintmax_t, radix::Hex::Uppercase>; -using OctFmt = IntegerToString<uintmax_t, radix::Oct>; -using DecFmt = IntegerToString<uintmax_t>; -using BinFmt = IntegerToString<uintmax_t, radix::Bin>; +template <typename CharT> +using HexFmt = IntegerToString<uintmax_t, radix::Hex, CharT>; -LIBC_INLINE constexpr size_t num_buf_size() { +template <typename CharT> +using HexFmtUppercase = + IntegerToString<uintmax_t, radix::Hex::Uppercase, CharT>; + +template <typename CharT> +using OctFmt = IntegerToString<uintmax_t, radix::Oct, CharT>; + +template <typename CharT> +using DecFmt = IntegerToString<uintmax_t, radix::Dec, CharT>; + +template <typename CharT> +using BinFmt = IntegerToString<uintmax_t, radix::Bin, CharT>; + +template <typename CharT> LIBC_INLINE constexpr size_t num_buf_size() { cpp::array<size_t, 5> sizes{ - HexFmt::buffer_size(), HexFmtUppercase::buffer_size(), - OctFmt::buffer_size(), DecFmt::buffer_size(), BinFmt::buffer_size()}; + HexFmt<CharT>::buffer_size(), HexFmtUppercase<CharT>::buffer_size(), + OctFmt<CharT>::buffer_size(), DecFmt<CharT>::buffer_size(), + BinFmt<CharT>::buffer_size()}; auto result = sizes[0]; for (size_t i = 1; i < sizes.size(); i++) @@ -43,27 +54,29 @@ LIBC_INLINE constexpr size_t num_buf_size() { return result; } -LIBC_INLINE cpp::optional<cpp::string_view> -num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) { - if (internal::tolower(conv_name) == 'x') { - if (internal::islower(conv_name)) - return HexFmt::format_to(bufref, num); - else - return HexFmtUppercase::format_to(bufref, num); - } else if (conv_name == 'o') { - return OctFmt::format_to(bufref, num); - } else if (internal::tolower(conv_name) == 'b') { - return BinFmt::format_to(bufref, num); - } else { - return DecFmt::format_to(bufref, num); +template <typename CharT> +LIBC_INLINE cpp::optional<cpp::basic_string_view<CharT>> +num_to_strview(uintmax_t num, cpp::span<CharT> bufref, CharT conv_name) { + switch (conv_name) { + case CharT{'x'}: + return HexFmt<CharT>::format_to(bufref, num); + case CharT{'X'}: + return HexFmtUppercase<CharT>::format_to(bufref, num); + case CharT{'o'}: + return OctFmt<CharT>::format_to(bufref, num); + case CharT('b'): + case CharT('B'): + return BinFmt<CharT>::format_to(bufref, num); + default: + return DecFmt<CharT>::format_to(bufref, num); } } } // namespace details -template <OverflowMode mode> -LIBC_INLINE int convert_int(Writer<mode> *writer, - const FormatSection &to_conv) { +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_int(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { static constexpr size_t BITS_IN_BYTE = 8; static constexpr size_t BITS_IN_NUM = sizeof(uintmax_t) * BITS_IN_BYTE; @@ -72,7 +85,7 @@ LIBC_INLINE int convert_int(Writer<mode> *writer, FormatFlags flags = to_conv.flags; // If the conversion is signed, then handle negative values. - if (to_conv.conv_name == 'd' || to_conv.conv_name == 'i') { + if (to_conv.conv_name == CharT{'d'} || to_conv.conv_name == CharT{'i'}) { // Check if the number is negative by checking the high bit. This works even // for smaller numbers because they're sign extended by default. if ((num & (uintmax_t(1) << (BITS_IN_NUM - 1))) > 0) { @@ -88,41 +101,38 @@ LIBC_INLINE int convert_int(Writer<mode> *writer, num = apply_length_modifier(num, {to_conv.length_modifier, to_conv.bit_width}); - cpp::array<char, details::num_buf_size()> buf; - auto str = details::num_to_strview(num, buf, to_conv.conv_name); + cpp::array<CharT, details::num_buf_size<CharT>()> buf; + auto str = details::num_to_strview<CharT>(num, buf, to_conv.conv_name); if (!str) return INT_CONVERSION_ERROR; size_t digits_written = str->size(); - char sign_char = 0; + CharT sign_char = 0; if (is_negative) - sign_char = '-'; + sign_char = CharT{'-'}; else if ((flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN) - sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX + sign_char = CharT{'+'}; // FORCE_SIGN has precedence over SPACE_PREFIX else if ((flags & FormatFlags::SPACE_PREFIX) == FormatFlags::SPACE_PREFIX) - sign_char = ' '; + sign_char = CharT{' '}; // These are signed to prevent underflow due to negative values. The eventual // values will always be non-negative. int zeroes; int spaces; - // prefix is "0x" for hexadecimal, or the sign character for signed - // conversions. Since hexadecimal is unsigned these will never conflict. + // Prefix is "0x" or "OX" for hexadecimal, "0b" or "0B" for binary, or the + // sign character for signed conversions. Since hexadecimal and binary are + // unsigned these will never conflict. size_t prefix_len; - char prefix[2]; - if ((internal::tolower(to_conv.conv_name) == 'x') && - ((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) { - prefix_len = 2; - prefix[0] = '0'; - prefix[1] = internal::islower(to_conv.conv_name) ? 'x' : 'X'; - } else if ((internal::tolower(to_conv.conv_name) == 'b') && - ((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) { + CharT prefix[2]; + if ((to_conv.conv_name == CharT{'x'} || to_conv.conv_name == CharT{'X'} || + to_conv.conv_name == CharT{'b'} || to_conv.conv_name == CharT{'B'}) && + (flags & FormatFlags::ALTERNATE_FORM) != 0 && num != 0) { prefix_len = 2; - prefix[0] = '0'; - prefix[1] = internal::islower(to_conv.conv_name) ? 'b' : 'B'; + prefix[0] = CharT{'0'}; + prefix[1] = to_conv.conv_name; } else { prefix_len = (sign_char == 0 ? 0 : 1); prefix[0] = sign_char; @@ -175,7 +185,7 @@ LIBC_INLINE int convert_int(Writer<mode> *writer, // 2b) ... because it is just "0", unless it will not write any digits. const bool has_leading_zero = (zeroes > 0) || ((num == 0) && (digits_written != 0)); - if ((to_conv.conv_name == 'o') && + if ((to_conv.conv_name == CharT{'o'}) && ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) && !has_leading_zero) { zeroes = 1; @@ -187,19 +197,19 @@ LIBC_INLINE int convert_int(Writer<mode> *writer, if (prefix_len != 0) RET_IF_RESULT_NEGATIVE(writer->write({prefix, prefix_len})); if (zeroes > 0) - RET_IF_RESULT_NEGATIVE(writer->write('0', zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, zeroes)); if (digits_written > 0) RET_IF_RESULT_NEGATIVE(writer->write(*str)); if (spaces > 0) - RET_IF_RESULT_NEGATIVE(writer->write(' ', spaces)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, spaces)); } else { // Else it goes spaces prefix zeroes digits if (spaces > 0) - RET_IF_RESULT_NEGATIVE(writer->write(' ', spaces)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{' '}, spaces)); if (prefix_len != 0) RET_IF_RESULT_NEGATIVE(writer->write({prefix, prefix_len})); if (zeroes > 0) - RET_IF_RESULT_NEGATIVE(writer->write('0', zeroes)); + RET_IF_RESULT_NEGATIVE(writer->write(CharT{'0'}, zeroes)); if (digits_written > 0) RET_IF_RESULT_NEGATIVE(writer->write(*str)); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/parser.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/parser.h index efc3f38c1083..e0129a98fb89 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/parser.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/parser.h @@ -116,10 +116,10 @@ template <typename ArgProvider, typename CharT> class Parser { // specified format section. This can either be a raw format section with no // conversion, or a format section with a conversion that has all of its // variables stored in the format section. - LIBC_INLINE BasicFormatSection<CharT> get_next_section() { - BasicFormatSection<CharT> section; + LIBC_INLINE FormatSection<CharT> get_next_section() { + FormatSection<CharT> section; size_t starting_pos = cur_pos; - if (str[cur_pos] == char_constant_v<CharT, '%'>) { + if (str[cur_pos] == CharT{'%'}) { // format section section.has_conv = true; @@ -134,7 +134,7 @@ template <typename ArgProvider, typename CharT> class Parser { // handle width section.min_width = 0; - if (str[cur_pos] == char_constant_v<CharT, '*'>) { + if (str[cur_pos] == CharT{'*'}) { ++cur_pos; WRITE_ARG_VAL_SIMPLEST(section.min_width, int, parse_index(&cur_pos)); @@ -152,11 +152,11 @@ template <typename ArgProvider, typename CharT> class Parser { // handle precision section.precision = -1; // negative precisions are ignored. - if (str[cur_pos] == char_constant_v<CharT, '.'>) { + if (str[cur_pos] == CharT{'.'}) { ++cur_pos; section.precision = 0; // if there's a . but no specified precision, the // precision is implicitly 0. - if (str[cur_pos] == char_constant_v<CharT, '*'>) { + if (str[cur_pos] == CharT{'*'}) { ++cur_pos; WRITE_ARG_VAL_SIMPLEST(section.precision, int, parse_index(&cur_pos)); @@ -173,7 +173,7 @@ template <typename ArgProvider, typename CharT> class Parser { section.conv_name = str[cur_pos]; section.bit_width = bw; switch (str[cur_pos]) { - case (char_constant_v<CharT, '%'>): + case (CharT{'%'}): // Regardless of options, a % conversion is always safe. The standard // says that "The complete conversion specification shall be %%" but it // also says that "If a conversion specification is invalid, the @@ -182,7 +182,7 @@ template <typename ArgProvider, typename CharT> class Parser { // valid or invalid options. section.has_conv = true; break; - case (char_constant_v<CharT, 'c'>): + case (CharT{'c'}): if (section.length_modifier == LengthModifier::l) { #ifdef LIBC_COPT_PRINTF_DISABLE_WIDE using WideCharArgType = int; @@ -195,14 +195,14 @@ template <typename ArgProvider, typename CharT> class Parser { WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); } break; - case (char_constant_v<CharT, 'd'>): - case (char_constant_v<CharT, 'i'>): - case (char_constant_v<CharT, 'o'>): - case (char_constant_v<CharT, 'x'>): - case (char_constant_v<CharT, 'X'>): - case (char_constant_v<CharT, 'u'>): - case (char_constant_v<CharT, 'b'>): - case (char_constant_v<CharT, 'B'>): + case (CharT{'d'}): + case (CharT{'i'}): + case (CharT{'o'}): + case (CharT{'x'}): + case (CharT{'X'}): + case (CharT{'u'}): + case (CharT{'b'}): + case (CharT{'B'}): switch (lm) { case (LengthModifier::hh): case (LengthModifier::h): @@ -255,14 +255,14 @@ template <typename ArgProvider, typename CharT> class Parser { } break; #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT - case (char_constant_v<CharT, 'f'>): - case (char_constant_v<CharT, 'F'>): - case (char_constant_v<CharT, 'e'>): - case (char_constant_v<CharT, 'E'>): - case (char_constant_v<CharT, 'a'>): - case (char_constant_v<CharT, 'A'>): - case (char_constant_v<CharT, 'g'>): - case (char_constant_v<CharT, 'G'>): + case (CharT{'f'}): + case (CharT{'F'}): + case (CharT{'e'}): + case (CharT{'E'}): + case (CharT{'a'}): + case (CharT{'A'}): + case (CharT{'g'}): + case (CharT{'G'}): switch (lm) { #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) case (LengthModifier::Q): @@ -283,15 +283,15 @@ template <typename ArgProvider, typename CharT> class Parser { #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT // Capitalization represents sign, but we only need to get the right // bitwidth here so we ignore that. - case (char_constant_v<CharT, 'r'>): - case (char_constant_v<CharT, 'R'>): + case (CharT{'r'}): + case (CharT{'R'}): // all fract sizes we support are less than 32 bits, and currently doing // va_args with fixed point types just doesn't work. // TODO: Move to fixed point types once va_args supports it. WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint32_t, conv_index); break; - case (char_constant_v<CharT, 'k'>): - case (char_constant_v<CharT, 'K'>): + case (CharT{'k'}): + case (CharT{'K'}): if (lm == LengthModifier::l) { WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, uint64_t, conv_index); } else { @@ -300,7 +300,7 @@ template <typename ArgProvider, typename CharT> class Parser { break; #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT #ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR - case (char_constant_v<CharT, 'm'>): + case (CharT{'m'}): // %m is an odd conversion in that it doesn't consume an argument, it // just takes the current value of errno as its argument. section.conv_val_raw = @@ -308,12 +308,12 @@ template <typename ArgProvider, typename CharT> class Parser { break; #endif // LIBC_COPT_PRINTF_DISABLE_STRERROR #ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case (char_constant_v<CharT, 'n'>): // Intentional fallthrough + case (CharT{'n'}): // Intentional fallthrough #endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case (char_constant_v<CharT, 'p'>): + case (CharT{'p'}): WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index); break; - case (char_constant_v<CharT, 's'>): + case (CharT{'s'}): WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index); break; default: @@ -323,14 +323,13 @@ template <typename ArgProvider, typename CharT> class Parser { } // If the end of the format section is on the '\0'. This means we need to // not advance the cur_pos. - if (str[cur_pos] != char_constant_v<CharT, '\0'>) + if (str[cur_pos] != CharT{'\0'}) ++cur_pos; } else { // raw section section.has_conv = false; - while (str[cur_pos] != char_constant_v<CharT, '%'> && - str[cur_pos] != char_constant_v<CharT, '\0'>) + while (str[cur_pos] != CharT{'%'} && str[cur_pos] != CharT{'\0'}) ++cur_pos; } section.raw_string = {str + starting_pos, cur_pos - starting_pos}; @@ -347,19 +346,19 @@ template <typename ArgProvider, typename CharT> class Parser { FormatFlags flags = FormatFlags(0); while (found_flag) { switch (str[*local_pos]) { - case char_constant_v<CharT, '-'>: + case CharT{'-'}: flags = static_cast<FormatFlags>(flags | FormatFlags::LEFT_JUSTIFIED); break; - case char_constant_v<CharT, '+'>: + case CharT{'+'}: flags = static_cast<FormatFlags>(flags | FormatFlags::FORCE_SIGN); break; - case char_constant_v<CharT, ' '>: + case CharT{' '}: flags = static_cast<FormatFlags>(flags | FormatFlags::SPACE_PREFIX); break; - case char_constant_v<CharT, '#'>: + case CharT{'#'}: flags = static_cast<FormatFlags>(flags | FormatFlags::ALTERNATE_FORM); break; - case char_constant_v<CharT, '0'>: + case CharT{'0'}: flags = static_cast<FormatFlags>(flags | FormatFlags::LEADING_ZEROES); break; default: @@ -377,8 +376,8 @@ template <typename ArgProvider, typename CharT> class Parser { // after the format specifier if one is found. LIBC_INLINE LengthSpec parse_length_modifier(size_t *local_pos) { switch (str[*local_pos]) { - case (char_constant_v<CharT, 'l'>): - if (str[*local_pos + 1] == char_constant_v<CharT, 'l'>) { + case (CharT{'l'}): + if (str[*local_pos + 1] == CharT{'l'}) { *local_pos += 2; return {LengthModifier::ll, 0}; } else { @@ -386,9 +385,9 @@ template <typename ArgProvider, typename CharT> class Parser { return {LengthModifier::l, 0}; } #ifndef LIBC_COPT_PRINTF_DISABLE_BITINT - case (char_constant_v<CharT, 'w'>): { + case (CharT{'w'}): { LengthModifier lm; - if (str[*local_pos + 1] == char_constant_v<CharT, 'f'>) { + if (str[*local_pos + 1] == CharT{'f'}) { *local_pos += 2; lm = LengthModifier::wf; } else { @@ -403,29 +402,29 @@ template <typename ArgProvider, typename CharT> class Parser { return {lm, 0}; } #endif // LIBC_COPT_PRINTF_DISABLE_BITINT - case (char_constant_v<CharT, 'h'>): - if (str[*local_pos + 1] == char_constant_v<CharT, 'h'>) { + case (CharT{'h'}): + if (str[*local_pos + 1] == CharT{'h'}) { *local_pos += 2; return {LengthModifier::hh, 0}; } else { ++*local_pos; return {LengthModifier::h, 0}; } - case (char_constant_v<CharT, 'L'>): + case (CharT{'L'}): ++*local_pos; return {LengthModifier::L, 0}; #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) - case (char_constant_v<CharT, 'Q'>): + case (CharT{'Q'}): ++*local_pos; return {LengthModifier::Q, 0}; #endif // LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128 - case (char_constant_v<CharT, 'j'>): + case (CharT{'j'}): ++*local_pos; return {LengthModifier::j, 0}; - case (char_constant_v<CharT, 'z'>): + case (CharT{'z'}): ++*local_pos; return {LengthModifier::z, 0}; - case (char_constant_v<CharT, 't'>): + case (CharT{'t'}): ++*local_pos; return {LengthModifier::t, 0}; default: @@ -454,7 +453,7 @@ template <typename ArgProvider, typename CharT> class Parser { auto result = internal::strtointeger<int>(str + *local_pos, 10); size_t index = static_cast<size_t>(result.value); if (str[*local_pos + static_cast<size_t>(result.parsed_len)] != - char_constant_v<CharT, '$'>) + CharT{'$'}) return 0; *local_pos = static_cast<size_t>(1 + result.parsed_len) + *local_pos; return index; @@ -564,7 +563,7 @@ template <typename ArgProvider, typename CharT> class Parser { size_t local_pos = 0; while (str[local_pos]) { - if (str[local_pos] == char_constant_v<CharT, '%'>) { + if (str[local_pos] == CharT{'%'}) { ++local_pos; size_t conv_index = parse_index(&local_pos); @@ -574,7 +573,7 @@ template <typename ArgProvider, typename CharT> class Parser { parse_flags(&local_pos); // handle width - if (str[local_pos] == char_constant_v<CharT, '*'>) { + if (str[local_pos] == CharT{'*'}) { ++local_pos; size_t width_index = parse_index(&local_pos); @@ -588,9 +587,9 @@ template <typename ArgProvider, typename CharT> class Parser { } // handle precision - if (str[local_pos] == char_constant_v<CharT, '.'>) { + if (str[local_pos] == CharT{'.'}) { ++local_pos; - if (str[local_pos] == char_constant_v<CharT, '*'>) { + if (str[local_pos] == CharT{'*'}) { ++local_pos; size_t precision_index = parse_index(&local_pos); @@ -611,17 +610,17 @@ template <typename ArgProvider, typename CharT> class Parser { // logic has been for skipping past this conversion properly to avoid // weirdness with %%. if (conv_index == 0) { - if (str[local_pos] != char_constant_v<CharT, '\0'>) + if (str[local_pos] != CharT{'\0'}) ++local_pos; continue; } TypeDesc conv_size = type_desc_from_type<void>(); switch (str[local_pos]) { - case (char_constant_v<CharT, '%'>): + case (CharT{'%'}): conv_size = type_desc_from_type<void>(); break; - case (char_constant_v<CharT, 'c'>): + case (CharT{'c'}): if (lm == LengthModifier::l) { #ifdef LIBC_COPT_PRINTF_DISABLE_WIDE using WideCharArgType = int; @@ -633,14 +632,14 @@ template <typename ArgProvider, typename CharT> class Parser { conv_size = type_desc_from_type<int>(); } break; - case (char_constant_v<CharT, 'd'>): - case (char_constant_v<CharT, 'i'>): - case (char_constant_v<CharT, 'o'>): - case (char_constant_v<CharT, 'x'>): - case (char_constant_v<CharT, 'X'>): - case (char_constant_v<CharT, 'u'>): - case (char_constant_v<CharT, 'b'>): - case (char_constant_v<CharT, 'B'>): + case (CharT{'d'}): + case (CharT{'i'}): + case (CharT{'o'}): + case (CharT{'x'}): + case (CharT{'X'}): + case (CharT{'u'}): + case (CharT{'b'}): + case (CharT{'B'}): switch (lm) { case (LengthModifier::hh): case (LengthModifier::h): @@ -686,14 +685,14 @@ template <typename ArgProvider, typename CharT> class Parser { } break; #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT - case (char_constant_v<CharT, 'f'>): - case (char_constant_v<CharT, 'F'>): - case (char_constant_v<CharT, 'e'>): - case (char_constant_v<CharT, 'E'>): - case (char_constant_v<CharT, 'a'>): - case (char_constant_v<CharT, 'A'>): - case (char_constant_v<CharT, 'g'>): - case (char_constant_v<CharT, 'G'>): + case (CharT{'f'}): + case (CharT{'F'}): + case (CharT{'e'}): + case (CharT{'E'}): + case (CharT{'a'}): + case (CharT{'A'}): + case (CharT{'g'}): + case (CharT{'G'}): switch (lm) { #if defined(LIBC_INTERNAL_PRINTF_CONVERT_FLOAT128) case LengthModifier::Q: @@ -714,12 +713,12 @@ template <typename ArgProvider, typename CharT> class Parser { #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT // Capitalization represents sign, but we only need to get the right // bitwidth here so we ignore that. - case (char_constant_v<CharT, 'r'>): - case (char_constant_v<CharT, 'R'>): + case (CharT{'r'}): + case (CharT{'R'}): conv_size = type_desc_from_type<uint32_t>(); break; - case (char_constant_v<CharT, 'k'>): - case (char_constant_v<CharT, 'K'>): + case (CharT{'k'}): + case (CharT{'K'}): if (lm == LengthModifier::l) { conv_size = type_desc_from_type<uint64_t>(); } else { @@ -728,10 +727,10 @@ template <typename ArgProvider, typename CharT> class Parser { break; #endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT #ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case (char_constant_v<CharT, 'n'>): + case (CharT{'n'}): #endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT - case (char_constant_v<CharT, 'p'>): - case (char_constant_v<CharT, 's'>): + case (CharT{'p'}): + case (CharT{'s'}): conv_size = type_desc_from_type<void *>(); break; default: @@ -745,7 +744,7 @@ template <typename ArgProvider, typename CharT> class Parser { } // If the end of the format section is on the '\0'. This means we need to // not advance the local_pos. - if (str[local_pos] != char_constant_v<CharT, '\0'>) + if (str[local_pos] != CharT{'\0'}) ++local_pos; } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/printf_main.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/printf_main.h index 401adb0735dd..58eac27c4c4b 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/printf_main.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/printf_main.h @@ -28,7 +28,7 @@ ErrorOr<size_t> printf_main_modular(Writer<mode> *writer, internal::ArgList &args) { Parser<internal::ArgList, char> parser(str, args); int result = 0; - for (FormatSection cur_section = parser.get_next_section(); + for (FormatSection<char> cur_section = parser.get_next_section(); !cur_section.raw_string.empty(); cur_section = parser.get_next_section()) { if (cur_section.has_conv) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/ptr_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/ptr_converter.h index 6415439bbb2a..8c0d49589d29 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/ptr_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/ptr_converter.h @@ -18,23 +18,21 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { -template <OverflowMode mode> -LIBC_INLINE int convert_pointer(Writer<mode> *writer, - const FormatSection &to_conv) { - FormatSection new_conv = to_conv; - +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_pointer(Writer<mode, CharT> *writer, + FormatSection<CharT> to_conv) { if (to_conv.conv_val_ptr == nullptr) { constexpr char NULLPTR_STR[] = "(nullptr)"; - new_conv.conv_name = 's'; - new_conv.conv_val_ptr = const_cast<char *>(NULLPTR_STR); - return convert_string(writer, new_conv); + to_conv.conv_name = 's'; + to_conv.conv_val_ptr = const_cast<char *>(NULLPTR_STR); + return convert_string(writer, to_conv); } - new_conv.conv_name = 'x'; - new_conv.flags = + to_conv.conv_name = 'x'; + to_conv.flags = static_cast<FormatFlags>(to_conv.flags | FormatFlags::ALTERNATE_FORM); - new_conv.length_modifier = LengthModifier::t; - new_conv.conv_val_raw = reinterpret_cast<uintptr_t>(to_conv.conv_val_ptr); - return convert_int(writer, new_conv); + to_conv.length_modifier = LengthModifier::t; + to_conv.conv_val_raw = reinterpret_cast<uintptr_t>(to_conv.conv_val_ptr); + return convert_int(writer, to_conv); } } // namespace printf_core diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/strerror_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/strerror_converter.h index 4e4e61295b53..bda1b022a1ca 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/strerror_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/strerror_converter.h @@ -19,10 +19,9 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { -template <OverflowMode mode> -LIBC_INLINE int convert_strerror(Writer<mode> *writer, - const FormatSection &to_conv) { - FormatSection new_conv = to_conv; +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_strerror(Writer<mode, CharT> *writer, + FormatSection<CharT> to_conv) { const int error_num = static_cast<int>(to_conv.conv_val_raw); // The %m conversion takes no arguments passes the result of strerror(errno) @@ -37,10 +36,10 @@ LIBC_INLINE int convert_strerror(Writer<mode> *writer, if ((to_conv.flags & FormatFlags::ALTERNATE_FORM) == 0) { char strerror_buff[64]; auto strerror_result = get_error_string(error_num, strerror_buff); - new_conv.conv_val_ptr = + to_conv.conv_val_ptr = reinterpret_cast<void *>(const_cast<char *>(strerror_result.data())); - new_conv.conv_name = 's'; - return convert_string(writer, new_conv); + to_conv.conv_name = CharT{'s'}; + return convert_string(writer, to_conv); } else { // alt form @@ -58,14 +57,14 @@ LIBC_INLINE int convert_strerror(Writer<mode> *writer, auto errno_name = try_get_errno_name(error_num); // if there's a name available, use it. if (errno_name) { - new_conv.conv_val_ptr = + to_conv.conv_val_ptr = reinterpret_cast<void *>(const_cast<char *>(errno_name->data())); - new_conv.conv_name = 's'; - return convert_string(writer, new_conv); + to_conv.conv_name = CharT{'s'}; + return convert_string(writer, to_conv); } else { // else do an int conversion - new_conv.conv_name = 'd'; - return convert_int(writer, new_conv); + to_conv.conv_name = CharT{'d'}; + return convert_int(writer, to_conv); } } } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/string_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/string_converter.h index 5352bd8306ba..c646ef8a3b4a 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/string_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/string_converter.h @@ -16,6 +16,7 @@ #include "src/__support/wchar/string_converter.h" #endif // LIBC_COPT_PRINTF_DISABLE_WIDE +#include "src/__support/CPP/type_traits.h" #include "src/__support/macros/config.h" #include "src/__support/printf_core/converter_utils.h" #include "src/__support/printf_core/core_structs.h" @@ -28,8 +29,8 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { template <OverflowMode mode> -LIBC_INLINE int char_writer(Writer<mode> *writer, - const FormatSection &to_conv) { +LIBC_INLINE int write_char_string_as_chars(Writer<mode, char> *writer, + const FormatSection<char> &to_conv) { const char *str_ptr = reinterpret_cast<const char *>(to_conv.conv_val_ptr); size_t string_len = 0; @@ -39,11 +40,14 @@ LIBC_INLINE int char_writer(Writer<mode> *writer, } #endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS - string_len = internal::string_length(str_ptr); - - if (to_conv.precision >= 0 && - static_cast<size_t>(to_conv.precision) < string_len) - string_len = to_conv.precision; + // If a precision is specified, it doesn't have to be null-terminated. + if (to_conv.precision >= 0) { + while (string_len < static_cast<size_t>(to_conv.precision) && + str_ptr[string_len] != '\0') + string_len++; + } else { + string_len = internal::string_length(str_ptr); + } size_t padding_spaces = to_conv.min_width > static_cast<int>(string_len) ? to_conv.min_width - string_len @@ -67,8 +71,9 @@ LIBC_INLINE int char_writer(Writer<mode> *writer, #ifndef LIBC_COPT_PRINTF_DISABLE_WIDE template <OverflowMode mode> -LIBC_INLINE int wchar_writer(Writer<mode> *writer, - const FormatSection &to_conv) { +LIBC_INLINE int +write_wchar_string_as_chars(Writer<mode, char> *writer, + const FormatSection<char> &to_conv) { size_t string_len = 0; const char32_t *wstr_ptr = reinterpret_cast<const char32_t *>(to_conv.conv_val_ptr); @@ -119,24 +124,121 @@ LIBC_INLINE int wchar_writer(Writer<mode> *writer, return WRITE_OK; } -#endif // LIBC_COPT_PRINTF_DISABLE_WIDE template <OverflowMode mode> -LIBC_INLINE int convert_string(Writer<mode> *writer, - const FormatSection &to_conv) { - int ret = 0; - if (to_conv.length_modifier == LengthModifier::l) { - // find length and print wide char characters -#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE - ret = wchar_writer(writer, to_conv); -#else - ret = char_writer(writer, to_conv); -#endif - } else { - ret = char_writer(writer, to_conv); +LIBC_INLINE int +write_char_string_as_wchars(Writer<mode, wchar_t> *writer, + const FormatSection<wchar_t> &to_conv) { + const char8_t *str_ptr = + reinterpret_cast<const char8_t *>(to_conv.conv_val_ptr); + +#if !defined(LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS) + if (str_ptr == nullptr) + str_ptr = reinterpret_cast<const char8_t *>(u8"(null)"); +#endif // !LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS + + size_t precision = + to_conv.precision < 0 ? SIZE_MAX : static_cast<size_t>(to_conv.precision); + + size_t converted_string_len = 0; + { + internal::mbstate mbstate; + internal::StringConverter<char8_t> length_counter(str_ptr, &mbstate, + precision); + for (auto converted = length_counter.pop<wchar_t>(); + converted.has_value() && converted.value() != L'\0'; + converted = length_counter.pop<wchar_t>()) { + ++converted_string_len; + } + } + + size_t padding_spaces = + to_conv.min_width > static_cast<int>(converted_string_len) + ? to_conv.min_width - converted_string_len + : 0; + + // If the padding is on the left side, write the spaces first. + if (padding_spaces > 0 && + (to_conv.flags & FormatFlags::LEFT_JUSTIFIED) == 0) { + RET_IF_RESULT_NEGATIVE(writer->write(L' ', padding_spaces)); + } + + { + internal::mbstate mbstate; + internal::StringConverter<char8_t> out_conv(str_ptr, &mbstate, precision); + for (size_t i = 0; i < converted_string_len; ++i) { + RET_IF_RESULT_NEGATIVE(writer->write(*out_conv.pop<wchar_t>())); + } + } + + // If the padding is on the right side, write the spaces last. + if (padding_spaces > 0 && + (to_conv.flags & FormatFlags::LEFT_JUSTIFIED) != 0) { + RET_IF_RESULT_NEGATIVE(writer->write(L' ', padding_spaces)); + } + return WRITE_OK; +} + +template <OverflowMode mode> +LIBC_INLINE int +write_wchar_string_as_wchars(Writer<mode, wchar_t> *writer, + const FormatSection<wchar_t> &to_conv) { + const wchar_t *wstr_ptr = + reinterpret_cast<const wchar_t *>(to_conv.conv_val_ptr); + size_t precision = + to_conv.precision < 0 ? SIZE_MAX : static_cast<size_t>(to_conv.precision); + +#ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS + if (wstr_ptr == nullptr) + wstr_ptr = L"(null)"; +#endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS + + size_t string_len = 0; + while (string_len < precision && wstr_ptr[string_len] != L'\0') { + ++string_len; } - return ret; + size_t padding_spaces = to_conv.min_width > static_cast<int>(string_len) + ? to_conv.min_width - string_len + : 0; + + // If the padding is on the left side, write the spaces first. + if (padding_spaces > 0 && + (to_conv.flags & FormatFlags::LEFT_JUSTIFIED) == 0) { + RET_IF_RESULT_NEGATIVE(writer->write(L' ', padding_spaces)); + } + + RET_IF_RESULT_NEGATIVE(writer->write({wstr_ptr, string_len})); + + // If the padding is on the right side, write the spaces last. + if (padding_spaces > 0 && + (to_conv.flags & FormatFlags::LEFT_JUSTIFIED) != 0) { + RET_IF_RESULT_NEGATIVE(writer->write(L' ', padding_spaces)); + } + + return WRITE_OK; +} + +#endif // !LIBC_COPT_PRINTF_DISABLE_WIDE + +template <OverflowMode mode, typename CharT> +LIBC_INLINE int convert_string(Writer<mode, CharT> *writer, + const FormatSection<CharT> &to_conv) { +#if defined(LIBC_COPT_PRINTF_DISABLE_WIDE) + static_assert(cpp::is_same_v<CharT, char>, "wchar_t not supported."); + return write_char_string_as_chars(writer, to_conv); +#else // LIBC_COPT_PRINTF_DISABLE_WIDE + if constexpr (cpp::is_same_v<CharT, char>) { + if (to_conv.length_modifier == LengthModifier::l) + return write_wchar_string_as_chars(writer, to_conv); + return write_char_string_as_chars(writer, to_conv); + } else { + static_assert(cpp::is_same_v<CharT, wchar_t>); + if (to_conv.length_modifier == LengthModifier::l) + return write_wchar_string_as_wchars(writer, to_conv); + return write_char_string_as_wchars(writer, to_conv); + } +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE } } // namespace printf_core diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/write_int_converter.h b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/write_int_converter.h index 882963c1c44e..5353d0db1229 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/write_int_converter.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/printf_core/write_int_converter.h @@ -9,9 +9,9 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_WRITE_INT_CONVERTER_H #define LLVM_LIBC_SRC___SUPPORT_PRINTF_CORE_WRITE_INT_CONVERTER_H +#include "hdr/types/size_t.h" #include "src/__support/macros/config.h" #include "src/__support/printf_core/core_structs.h" -#include "src/__support/printf_core/writer.h" #include <inttypes.h> #include <stddef.h> @@ -19,49 +19,46 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { -template <OverflowMode mode> -LIBC_INLINE int convert_write_int(Writer<mode> *writer, - const FormatSection &to_conv) { +LIBC_INLINE int convert_write_int(size_t written, + LengthModifier conv_length_modifier, + void *conv_val_ptr) { #ifndef LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS // This is an additional check added by LLVM-libc. - if (to_conv.conv_val_ptr == nullptr) + if (conv_val_ptr == nullptr) return NULLPTR_WRITE_ERROR; #endif // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS - size_t written = writer->get_chars_written(); - - switch (to_conv.length_modifier) { + switch (conv_length_modifier) { case LengthModifier::none: - *reinterpret_cast<int *>(to_conv.conv_val_ptr) = static_cast<int>(written); + *reinterpret_cast<int *>(conv_val_ptr) = static_cast<int>(written); break; case LengthModifier::l: - *reinterpret_cast<long *>(to_conv.conv_val_ptr) = written; + *reinterpret_cast<long *>(conv_val_ptr) = written; break; case LengthModifier::ll: case LengthModifier::L: - *reinterpret_cast<long long *>(to_conv.conv_val_ptr) = written; + *reinterpret_cast<long long *>(conv_val_ptr) = written; break; case LengthModifier::h: - *reinterpret_cast<short *>(to_conv.conv_val_ptr) = - static_cast<short>(written); + *reinterpret_cast<short *>(conv_val_ptr) = static_cast<short>(written); break; case LengthModifier::hh: - *reinterpret_cast<signed char *>(to_conv.conv_val_ptr) = + *reinterpret_cast<signed char *>(conv_val_ptr) = static_cast<signed char>(written); break; case LengthModifier::z: - *reinterpret_cast<size_t *>(to_conv.conv_val_ptr) = written; + *reinterpret_cast<size_t *>(conv_val_ptr) = written; break; case LengthModifier::t: - *reinterpret_cast<ptrdiff_t *>(to_conv.conv_val_ptr) = written; + *reinterpret_cast<ptrdiff_t *>(conv_val_ptr) = written; break; case LengthModifier::j: #ifndef LIBC_COPT_PRINTF_DISABLE_BITINT case LengthModifier::w: case LengthModifier::wf: #endif // LIBC_COPT_PRINTF_DISABLE_BITINT - *reinterpret_cast<uintmax_t *>(to_conv.conv_val_ptr) = written; + *reinterpret_cast<uintmax_t *>(conv_val_ptr) = written; break; #if defined(LIBC_TYPES_HAS_NATIVE_FLOAT128) case (LengthModifier::Q): // 'Q' is not valid for integer format; this case diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/pwd/flat_file_db.h b/deps/v8/third_party/llvm-libc/src/src/__support/pwd/flat_file_db.h index 319197872cd3..626fc9455fe2 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/pwd/flat_file_db.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/pwd/flat_file_db.h @@ -216,10 +216,14 @@ template <typename EntryType> class FlatFileDatabase { // Reads and parses the next record from the database into a fixed buffer. // Returns true if an entry was read, false if EOF was reached, or an Error on // failure. Blank lines are skipped. A record that does not fit in the buffer - // is reported as ERANGE. + // is reported as ERANGE and leaves the stream positioned at the start of + // that record so an iterating caller can retry with a larger buffer; single- + // shot lookup callers close their scoped stream on return. LIBC_INLINE ErrorOr<bool> getnext(EntryType *entry, cpp::span<char> buffer) { if (!entry) return Error(EINVAL); + if (buffer.size() < 2) + return Error(ERANGE); if (!file) { auto res = setdb(); @@ -228,6 +232,7 @@ template <typename EntryType> class FlatFileDatabase { } while (true) { + auto original_pos = file->tell(); auto result = read_line(file, buffer); if (!result.has_value()) return Error(result.error()); @@ -240,16 +245,22 @@ template <typename EntryType> class FlatFileDatabase { if (res.bytes_read == 0) continue; - if (res.truncated) + if (res.truncated) { + if (original_pos.has_value()) + file->seek(original_pos.value(), SEEK_SET); return Error(ERANGE); + } // Slicing at bytes_read + 1 includes the terminating null byte written // by read_line; the remainder of the buffer serves as scratch space. auto parse_res = parse_line<EntryType>(buffer.first(res.bytes_read + 1), buffer.subspan(res.bytes_read + 1), entry); - if (!parse_res.has_value()) + if (!parse_res.has_value()) { + if (parse_res.error() == ERANGE && original_pos.has_value()) + file->seek(original_pos.value(), SEEK_SET); return Error(parse_res.error()); + } return true; } } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/regex/CMakeLists.txt index 72483f2bfc47..870ec56993ec 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/regex/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/CMakeLists.txt @@ -6,10 +6,64 @@ add_object_library( regex_expr_pool.h regex_ast.h DEPENDS + libc.hdr.limits_macros + libc.hdr.regex_macros + libc.hdr.stdint_proxy + libc.src.__support.alloc_checker + libc.src.__support.CPP.array + libc.src.__support.CPP.bitset libc.src.__support.CPP.new + libc.src.__support.CPP.scope + libc.src.__support.CPP.span + libc.src.__support.CPP.utility + libc.src.__support.error_or libc.src.__support.hash + libc.src.__support.libc_assert libc.src.__support.macros.config - libc.src.__support.macros.null_check - libc.src.__support.alloc_checker + libc.src.string.memory_utils.inline_memset +) + +add_header_library( + regex_internal + HDRS + regex_internal.h + DEPENDS + .regex_expr_pool + libc.src.__support.macros.config + libc.src.__support.threads.spin_lock +) + +add_object_library( + regex_matcher + SRCS + regex_matcher.cpp + HDRS + regex_matcher.h + DEPENDS + .regex_expr_pool + .regex_internal + libc.hdr.regex_macros + libc.src.__support.common + libc.src.__support.CPP.string_view + libc.src.__support.error_or + libc.src.__support.libc_assert +) + +add_object_library( + regex_parser + SRCS + regex_parser.cpp + HDRS + regex_parser.h + DEPENDS + .regex_expr_pool libc.hdr.regex_macros + libc.src.__support.alloc_checker + libc.src.__support.CPP.array + libc.src.__support.CPP.new + libc.src.__support.CPP.scope + libc.src.__support.CPP.span + libc.src.__support.CPP.string_view + libc.src.__support.error_or + libc.src.__support.macros.config ) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_ast.h b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_ast.h index c00d665e63a7..5c5fa006bec7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_ast.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_ast.h @@ -14,23 +14,49 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_AST_H #define LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_AST_H +#include "hdr/limits_macros.h" +#include "hdr/stdint_proxy.h" +#include "src/__support/CPP/bitset.h" #include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { namespace regex { +/// 32-bit index identifying a unique node in an ExprPool. +using ExprId = uint32_t; +inline constexpr ExprId INVALID_EXPR_ID = 0; +inline constexpr ExprId EMPTY_SET_ID = 1; +inline constexpr ExprId EMPTY_STR_ID = 2; + +/// One bit per possible byte value (2^CHAR_BIT = 256), allowing O(1) +/// membership tests for wildcards and bracket expressions. +inline constexpr size_t BYTE_SET_BITS = size_t(1) << CHAR_BIT; +using ByteSet = cpp::bitset<BYTE_SET_BITS>; + +/// Bitmask flags identifying zero-width boundary assertions. +enum AnchorKind : uint8_t { + ANCHOR_BOL = 1 << 0, + ANCHOR_EOL = 1 << 1, +}; + /// Enumeration of Regular Expression AST node types. -enum class ExprKind { +enum class ExprKind : uint8_t { /// Represents the empty set (matches nothing). EmptySet, /// Represents the empty string (matches the empty string). EmptyStr, /// A literal character match. Literal, + /// A zero-width boundary assertion (^ or $). + Anchor, + /// A 256-bit character class or wildcard match. + ByteSet, /// Concatenation of two expressions (left followed by right). Concat, /// Alternation between two expressions (left or right). Alt, + /// Zero or more repetitions of a sub-expression (body*). + Star, }; /// A node in the Regular Expression Abstract Syntax Tree. @@ -40,38 +66,74 @@ enum class ExprKind { /// an ExprPool. struct Expr { /// The type of this expression node. - ExprKind kind; + ExprKind kind = ExprKind::EmptySet; + /// Whether this expression can match the empty string unconditionally. + bool nullable : 1; + /// Whether this expression or any child contains a context-sensitive Anchor. + bool has_anchors : 1; + /// The character for Literal nodes. + char ch = '\0'; + /// Precomputed 32-bit structural hash for O(1) lookup and rehashing. + uint32_t hash = 0; union { - /// Character value for Literal nodes. - char ch; /// Sub-expressions for Concat and Alt nodes. struct { - Expr *left; - Expr *right; - } bin; + ExprId left; + ExprId right; + } bin = {INVALID_EXPR_ID, INVALID_EXPR_ID}; + /// Sub-expression for Star nodes. + ExprId body; + /// Index into ExprPool::byte_sets for ByteSet nodes. + uint32_t byte_set_id; + /// Bitmask of AnchorKind flags for Anchor nodes. + uint8_t anchor_mask; }; /// Default constructor creates an EmptySet node. /// Public to allow array allocation in ExprPool::Block. - constexpr Expr() : kind(ExprKind::EmptySet), ch('\0') {} + constexpr Expr() : nullable(false), has_anchors(false) {} private: - /// Create a node of a specific kind with no data. - constexpr Expr(ExprKind k) : kind(k), ch('\0') {} - /// Create a Literal node. - constexpr Expr(char c) : kind(ExprKind::Literal), ch(c) {} + /// Create a leaf node with a specific nullability (and optional character). + constexpr Expr(ExprKind k, bool is_null, char c = '\0') + : kind(k), nullable(is_null), has_anchors(false), ch(c) {} + /// Create an Anchor node. + constexpr Expr(uint8_t mask) + : kind(ExprKind::Anchor), nullable(false), has_anchors(true), + anchor_mask(mask) {} + /// Create a ByteSet node. + constexpr Expr(uint32_t bs_id) + : kind(ExprKind::ByteSet), nullable(false), has_anchors(false), + byte_set_id(bs_id) {} + /// Create a Star node. + constexpr Expr(ExprId b, bool anchors) + : kind(ExprKind::Star), nullable(true), has_anchors(anchors), body(b) {} /// Create a binary node (Concat or Alt). - constexpr Expr(ExprKind k, Expr *l, Expr *r) : kind(k), bin{l, r} {} + constexpr Expr(ExprKind k, bool is_null, bool anchors, ExprId l, ExprId r) + : kind(k), nullable(is_null), has_anchors(anchors), bin{l, r} {} public: - static constexpr Expr make_empty_set() { return Expr(ExprKind::EmptySet); } - static constexpr Expr make_empty_str() { return Expr(ExprKind::EmptyStr); } - static constexpr Expr make_literal(char c) { return Expr(c); } - static constexpr Expr make_concat(Expr *l, Expr *r) { - return Expr(ExprKind::Concat, l, r); + static constexpr Expr make_empty_set() { + return Expr(ExprKind::EmptySet, false); + } + static constexpr Expr make_empty_str() { + return Expr(ExprKind::EmptyStr, true); + } + static constexpr Expr make_literal(char c) { + return Expr(ExprKind::Literal, false, c); + } + static constexpr Expr make_anchor(uint8_t mask) { return Expr(mask); } + static constexpr Expr make_byte_set(uint32_t bs_id) { return Expr(bs_id); } + static constexpr Expr make_star(ExprId b, bool anchors = false) { + return Expr(b, anchors); + } + static constexpr Expr make_concat(ExprId l, ExprId r, bool is_null = false, + bool anchors = false) { + return Expr(ExprKind::Concat, is_null, anchors, l, r); } - static constexpr Expr make_alt(Expr *l, Expr *r) { - return Expr(ExprKind::Alt, l, r); + static constexpr Expr make_alt(ExprId l, ExprId r, bool is_null = false, + bool anchors = false) { + return Expr(ExprKind::Alt, is_null, anchors, l, r); } /// Equivalence check for hash-consing. @@ -84,13 +146,20 @@ struct Expr { return true; case ExprKind::Literal: return ch == other.ch; + case ExprKind::Anchor: + return anchor_mask == other.anchor_mask; + case ExprKind::ByteSet: + return byte_set_id == other.byte_set_id; + case ExprKind::Star: + return body == other.body; case ExprKind::Concat: case ExprKind::Alt: return bin.left == other.bin.left && bin.right == other.bin.right; } - return false; + __builtin_unreachable(); } }; +static_assert(sizeof(Expr) == 16, "Expr must remain 16 bytes"); } // namespace regex } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.cpp index 2d91c62348a5..7f68619c4b27 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.cpp @@ -14,10 +14,11 @@ #include "src/__support/regex/regex_expr_pool.h" #include "hdr/regex_macros.h" #include "src/__support/CPP/new.h" +#include "src/__support/CPP/scope.h" +#include "src/__support/CPP/utility.h" #include "src/__support/alloc-checker.h" #include "src/__support/hash.h" #include "src/__support/macros/config.h" -#include "src/__support/macros/null_check.h" #include "src/string/memory_utils/inline_memset.h" namespace LIBC_NAMESPACE_DECL { @@ -26,7 +27,7 @@ namespace regex { namespace { // Hash an Expr node for hash-consing. -uint64_t hash_expr(const Expr &e) { +uint32_t hash_expr(const Expr &e) { // Initialise HashState with a constant seed. The specific value (0x12345678) // is an arbitrary placeholder; HashState immediately mixes this seed with // high-entropy constants (derived from aHash) to produce a strong hash, while @@ -38,6 +39,15 @@ uint64_t hash_expr(const Expr &e) { case ExprKind::Literal: hasher.update(&e.ch, sizeof(e.ch)); break; + case ExprKind::Anchor: + hasher.update(&e.anchor_mask, sizeof(e.anchor_mask)); + break; + case ExprKind::ByteSet: + hasher.update(&e.byte_set_id, sizeof(e.byte_set_id)); + break; + case ExprKind::Star: + hasher.update(&e.body, sizeof(e.body)); + break; case ExprKind::Concat: case ExprKind::Alt: hasher.update(&e.bin.left, sizeof(e.bin.left)); @@ -46,116 +56,311 @@ uint64_t hash_expr(const Expr &e) { default: break; } - return hasher.finish(); + uint64_t h = hasher.finish(); + return static_cast<uint32_t>(h ^ (h >> 32)); } +// Bounded linear-probing range over a power-of-two open-addressing table. +class BucketProber { + cpp::span<ExprId> table; + size_t start_idx; + + constexpr size_t mask() const { return table.size() - 1; } + +public: + struct Sentinel {}; + + struct Iterator { + cpp::span<ExprId> table; + size_t idx; + size_t step; + + constexpr size_t mask() const { return table.size() - 1; } + + ExprId &operator*() const { return table[idx]; } + Iterator &operator++() { + idx = (idx + 1) & mask(); + ++step; + return *this; + } + constexpr bool operator!=(Sentinel) const { return step != table.size(); } + }; + + BucketProber(cpp::span<ExprId> t, uint32_t hash) + : table(t), start_idx(hash & (t.size() - 1)) { + LIBC_ASSERT(!t.empty() && (t.size() & mask()) == 0); + } + + Iterator begin() const { return {table, start_idx, 0}; } + Sentinel end() const { return {}; } +}; + } // namespace -ExprPool::ExprPool() { +// TODO: When cpp::unique_ptr and cpp::make_unique are added to +// src/__support/CPP/, replace the manual AllocChecker + new[]/delete[] calls in +// ensure_initialized(), ~ExprPool(), allocate_block(), make_byte_set(), and +// grow_hashtable() with cpp::make_unique<ExprId[]>(...) and +// cpp::make_unique<Block>(), eliminating explicit zeroing via inline_memset and +// the destructor cleanup loop. +ExprPool::~ExprPool() { + delete[] byte_sets.data(); + delete[] hashtable.data(); + for (Block *blk : active_blocks()) + delete blk; + delete[] blocks.data(); +} + +bool ExprPool::ensure_initialized() { + if (block_count > 0) + return true; AllocChecker ac; - hashtable = new (ac) Expr *[HASH_TABLE_SIZE]; - if (ac) { - inline_memset(hashtable, 0, HASH_TABLE_SIZE * sizeof(Expr *)); - } + ExprId *raw_table = new (ac) ExprId[INITIAL_HASH_CAPACITY]; + if (!ac) + return false; + cpp::scope_exit table_guard([raw_table] { delete[] raw_table; }); + if (!allocate_block()) + return false; + table_guard.release(); + hashtable = cpp::span<ExprId>(raw_table, INITIAL_HASH_CAPACITY); + inline_memset(hashtable.data(), 0, hashtable.size_bytes()); + + [[maybe_unused]] auto empty_set_id = intern(Expr::make_empty_set()); + [[maybe_unused]] auto empty_str_id = intern(Expr::make_empty_str()); + LIBC_ASSERT(empty_set_id.has_value() && *empty_set_id == EMPTY_SET_ID); + LIBC_ASSERT(empty_str_id.has_value() && *empty_str_id == EMPTY_STR_ID); + return true; } -ExprPool::~ExprPool() { - if (hashtable) - delete[] hashtable; - Block *b = head; - while (b) { - Block *next_b = b->next; - delete b; - b = next_b; +ExprId &ExprPool::find_bucket(cpp::span<ExprId> table, const Expr &e) const { + for (ExprId &slot : BucketProber(table, e.hash)) { + if (slot == INVALID_EXPR_ID) + return slot; + const Expr &cand = get(slot); + if (cand.hash == e.hash && cand == e) + return slot; } + __builtin_unreachable(); } -cpp::expected<Expr *, int> ExprPool::intern(const Expr &e) { - if (!hashtable) - return cpp::unexpected(REG_ESPACE); - - // 1. Calculate the initial bucket for the given structural definition. - uint64_t h = hash_expr(e); - size_t idx = h % HASH_TABLE_SIZE; - - // 2. Linear Probing: Search for an existing node with identical content. - // Because pointers are unique, O(1) comparison is guaranteed if - // sub-expressions are already interned. - size_t start_idx = idx; - while (hashtable[idx]) { - if (*hashtable[idx] == e) - return hashtable[idx]; - idx = (idx + 1) % HASH_TABLE_SIZE; - if (idx == start_idx) { - // Table full (invariant check: HASH_TABLE_SIZE >> MAX_NODE_LIMIT) - return cpp::unexpected(REG_ESPACE); +bool ExprPool::allocate_block() { + AllocChecker ac; + if (block_count == blocks.size()) { + size_t new_cap = blocks.empty() ? INITIAL_BLOCKS_CAPACITY + : blocks.size() * GROWTH_FACTOR; + Block **new_blocks = new (ac) Block *[new_cap]; + if (!ac) + return false; + Block **dst = new_blocks; + for (Block *blk : active_blocks()) { + *dst = blk; + ++dst; } + delete[] blocks.data(); + blocks = cpp::span<Block *>(new_blocks, new_cap); } + Block *blk = new (ac) Block(); + if (!ac) + return false; + blocks[block_count] = blk; + ++block_count; + return true; +} + +bool ExprPool::grow_hashtable() { + size_t new_cap = hashtable.size() * GROWTH_FACTOR; + AllocChecker ac; + ExprId *raw_table = new (ac) ExprId[new_cap]; + if (!ac) + return false; + cpp::span<ExprId> new_table(raw_table, new_cap); + inline_memset(new_table.data(), 0, new_table.size_bytes()); + + for (ExprId id : hashtable) + if (id != INVALID_EXPR_ID) + find_bucket(new_table, get(id)) = id; + + delete[] hashtable.data(); + hashtable = new_table; + return true; +} + +ErrorOr<ExprId> ExprPool::intern(Expr e) { + if (!ensure_initialized()) + return Error(REG_ESPACE); - // 3. Admission Control: Check the hard limit on AST nodes. + // Probe for an existing node with identical content. + e.hash = hash_expr(e); + ExprId *bucket = &find_bucket(hashtable, e); + if (*bucket != INVALID_EXPR_ID) + return *bucket; + + // Admission Control: Check the hard limit on AST nodes. if (node_count >= MAX_NODE_LIMIT) - return cpp::unexpected(REG_ESPACE); + return Error(REG_ESPACE); - // 4. Arena Allocation: If no matching node found, allocate a stable slot. - if (!current || current->used == Block::BLOCK_SIZE) { - // New blocks are allocated on demand using AllocChecker. - AllocChecker ac; - Block *new_block = new (ac) Block(); - if (!ac) - return cpp::unexpected(REG_ESPACE); - if (!head) - head = new_block; - if (current) - current->next = new_block; - current = new_block; + if (node_count >= max_hashtable_nodes()) { + if (!grow_hashtable()) + return Error(REG_ESPACE); + bucket = &find_bucket(hashtable, e); } - // 5. Node Initialisation: Copy the structural definition into the arena. - Expr *new_node = ¤t->nodes[current->used]; - ++current->used; - *new_node = e; - hashtable[idx] = new_node; - node_count++; - return new_node; + // Arena Allocation: If no matching node found, allocate a stable slot. + if (node_count == block_count * NODES_PER_BLOCK) { + if (!allocate_block()) + return Error(REG_ESPACE); + } + + // Node Initialisation: Copy the structural definition into the arena. + ++node_count; + ExprId new_id = static_cast<ExprId>(node_count); + slot_at(new_id) = e; + *bucket = new_id; + return new_id; } -cpp::expected<Expr *, int> ExprPool::empty_set() { - return intern(Expr::make_empty_set()); +ErrorOr<ExprId> ExprPool::empty_set() { + if (!ensure_initialized()) + return Error(REG_ESPACE); + return EMPTY_SET_ID; } -cpp::expected<Expr *, int> ExprPool::empty_str() { - return intern(Expr::make_empty_str()); +ErrorOr<ExprId> ExprPool::empty_str() { + if (!ensure_initialized()) + return Error(REG_ESPACE); + return EMPTY_STR_ID; } -cpp::expected<Expr *, int> ExprPool::make_lit(char c) { +ErrorOr<ExprId> ExprPool::make_lit(char c) { return intern(Expr::make_literal(c)); } +ErrorOr<ExprId> ExprPool::make_anchor(uint8_t mask) { + return intern(Expr::make_anchor(mask)); +} + +ErrorOr<ExprId> ExprPool::make_byte_set(const ByteSet &bs) { + size_t count = 0; + size_t last_bit = 0; + for (size_t b = 0; b < BYTE_SET_BITS; ++b) { + if (bs.test(b)) { + ++count; + last_bit = b; + } + } + if (count == 0) + return empty_set(); + if (count == 1) + return make_lit(static_cast<char>(last_bit)); -cpp::expected<Expr *, int> ExprPool::make_concat(Expr *l, Expr *r) { - if (!l || !r) - return cpp::unexpected(REG_BADPAT); + uint32_t bs_id = 0; + for (const ByteSet &existing : active_byte_sets()) { + if (existing == bs) + return intern(Expr::make_byte_set(bs_id)); + ++bs_id; + } + + if (byte_set_count == byte_sets.size()) { + size_t new_cap = byte_sets.empty() ? INITIAL_BYTE_SETS_CAPACITY + : byte_sets.size() * GROWTH_FACTOR; + AllocChecker ac; + ByteSet *new_sets = new (ac) ByteSet[new_cap]; + if (!ac) + return Error(REG_ESPACE); + ByteSet *dst = new_sets; + for (const ByteSet &existing : active_byte_sets()) { + *dst = existing; + ++dst; + } + delete[] byte_sets.data(); + byte_sets = cpp::span<ByteSet>(new_sets, new_cap); + } + + ErrorOr<ExprId> id = intern(Expr::make_byte_set(bs_id)); + if (!id.has_value()) + return id; + byte_sets[byte_set_count] = bs; + ++byte_set_count; + return id; +} + +ErrorOr<ExprId> ExprPool::make_star(ExprId body) { + if (body == INVALID_EXPR_ID) + return Error(REG_BADPAT); + // Ø* = ε and ε* = ε + if (body == EMPTY_SET_ID || body == EMPTY_STR_ID) + return empty_str(); + // (R*)* = R* (Idempotency) + if (get(body).kind == ExprKind::Star) + return body; + return intern(Expr::make_star(body, has_anchors(body))); +} + +ErrorOr<ExprId> ExprPool::make_concat(ExprId l, ExprId r) { + if (l == INVALID_EXPR_ID || r == INVALID_EXPR_ID) + return Error(REG_BADPAT); // Apply basic algebraic identities for concatenation: - // 1. Ø · R = R · Ø = Ø (Identity: null set) - if (l->kind == ExprKind::EmptySet || r->kind == ExprKind::EmptySet) + // Ø · R = R · Ø = Ø (Identity: null set) + if (l == EMPTY_SET_ID || r == EMPTY_SET_ID) return empty_set(); - // 2. ε · R = R · ε = R (Identity: empty string) - if (l->kind == ExprKind::EmptyStr) + // ε · R = R · ε = R (Identity: empty string) + if (l == EMPTY_STR_ID) return r; - if (r->kind == ExprKind::EmptyStr) + if (r == EMPTY_STR_ID) return l; - return intern(Expr::make_concat(l, r)); + // (A · B) · C = A · (B · C) (Right-associative canonical form) + const Expr le = get(l); + if (le.kind == ExprKind::Concat) { + ErrorOr<ExprId> tail = make_concat(le.bin.right, r); + if (!tail.has_value()) + return tail; + return make_concat(le.bin.left, *tail); + } + return intern(Expr::make_concat(l, r, is_nullable(l) && is_nullable(r), + has_anchors(l) || has_anchors(r))); } -cpp::expected<Expr *, int> ExprPool::make_alt(Expr *l, Expr *r) { - if (!l || !r) - return cpp::unexpected(REG_BADPAT); + +ErrorOr<ExprId> ExprPool::make_alt(ExprId l, ExprId r) { + if (l == INVALID_EXPR_ID || r == INVALID_EXPR_ID) + return Error(REG_BADPAT); // Apply basic algebraic identities for alternation: - // 1. Ø | R = R | Ø = R (Identity: null set) - if (l->kind == ExprKind::EmptySet) + // Ø | R = R | Ø = R (Identity: null set) + if (l == EMPTY_SET_ID) return r; - if (r->kind == ExprKind::EmptySet) + if (r == EMPTY_SET_ID) return l; - // 2. R | R = R (Idempotency) + // R | R = R (Idempotency) if (l == r) return l; - return intern(Expr::make_alt(l, r)); + + const Expr le = get(l); + const Expr re = get(r); + if (le.kind != ExprKind::Alt && re.kind != ExprKind::Alt) { + if (l > r) + cpp::swap(l, r); + return intern(Expr::make_alt(l, r, is_nullable(l) || is_nullable(r), + has_anchors(l) || has_anchors(r))); + } + + // Merge two right-associated sorted Alt spines in ascending ExprId order so + // multi-way alternations canonicalize to a single deduplicated tree and + // derivative state spaces under '*' stay finite. + ExprId hl = (le.kind == ExprKind::Alt) ? le.bin.left : l; + ExprId tl = (le.kind == ExprKind::Alt) ? le.bin.right : EMPTY_SET_ID; + ExprId hr = (re.kind == ExprKind::Alt) ? re.bin.left : r; + ExprId tr = (re.kind == ExprKind::Alt) ? re.bin.right : EMPTY_SET_ID; + ExprId head = hl; + ErrorOr<ExprId> rest = EMPTY_SET_ID; + if (hl == hr) { + rest = make_alt(tl, tr); + } else if (hl < hr) { + rest = make_alt(tl, r); + } else { + head = hr; + rest = make_alt(l, tr); + } + if (!rest.has_value()) + return rest; + return intern(Expr::make_alt(head, *rest, + is_nullable(head) || is_nullable(*rest), + has_anchors(head) || has_anchors(*rest))); } } // namespace regex diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.h b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.h index 82994b9bbe34..37fc585e2e23 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_expr_pool.h @@ -14,7 +14,10 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_EXPR_POOL_H #define LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_EXPR_POOL_H -#include "src/__support/CPP/expected.h" +#include "src/__support/CPP/array.h" +#include "src/__support/CPP/span.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_assert.h" #include "src/__support/macros/config.h" #include "src/__support/regex/regex_ast.h" #include <stddef.h> @@ -27,89 +30,147 @@ namespace regex { /// This class manages the allocation and hash-consing of Expr nodes. All /// nodes created through this pool are owned by it and will be freed when /// the pool is destroyed. Hash-consing ensures that identical expressions -/// are represented by the same pointer, enabling fast comparison and +/// are represented by the same ExprId, enabling fast comparison and /// derivative normalization. class ExprPool { /// Internal storage block for AST nodes. /// - /// Blocks are allocated on demand to avoid large contiguous allocations - /// and are linked together in a list for cleanup. - /// TODO: Consider adopting cpp::forward_list for block management once - /// it is available in LLVM-libc. + /// Blocks are allocated on demand to avoid large contiguous allocations. struct Block { - /// Number of Expr nodes stored in each block. - static constexpr size_t BLOCK_SIZE = 256; + /// Number of Expr nodes stored in each block (32 nodes * 16B = 512B). + static constexpr size_t NODES_PER_BLOCK = 32; /// The actual storage for Expr nodes. - Expr nodes[BLOCK_SIZE]; - /// Pointer to the next block in the chain. - Block *next = nullptr; - /// Number of nodes currently used in this block. - size_t used = 0; + cpp::array<Expr, NODES_PER_BLOCK> nodes{}; }; - /// The first block in the allocation chain. - Block *head = nullptr; - /// The block currently being used for new node allocations. - Block *current = nullptr; + static constexpr size_t NODES_PER_BLOCK = Block::NODES_PER_BLOCK; + /// Initial directory capacity for 8 blocks (64B), holding up to 256 nodes + /// before directory growth. + static constexpr size_t INITIAL_BLOCKS_CAPACITY = 8; + /// Initial capacity for 4 unique ByteSets (4 * 32B = 128B), allocated lazily + /// on the first multi-bit ByteSet so pure literal patterns allocate 0 bytes. + static constexpr size_t INITIAL_BYTE_SETS_CAPACITY = 4; + /// Initial power-of-two hash table size: 64 slots (256B), holding up to 44 + /// unique nodes at 70% max load factor while keeping initial pool footprint + /// at 512B + 64B + 256B = 832B (< 1 KiB). + static constexpr size_t INITIAL_HASH_CAPACITY = 64; + /// Scaling factor used when growing dynamic pool arrays and hash tables. + static constexpr size_t GROWTH_FACTOR = 2; + /// Grow the hash table when occupancy reaches 70% to keep linear-probing + /// chains short. + static constexpr double MAX_LOAD_FACTOR = 0.7; + + // TODO: Once cpp::unique_ptr and AllocChecker-backed cpp::make_unique (and/or + // an owning unique_span) are available in src/__support/CPP/, replace raw + // Block* and span-backed manual new[]/delete[] ownership here so that Block + // lifecycles, directory growth, ByteSet growth, and hash-table growth are + // managed via RAII and ~ExprPool() can be defaulted. + + /// Span of allocated Block* slots (capacity = blocks.size()). + cpp::span<Block *> blocks; + size_t block_count = 0; /// Total number of nodes allocated across all blocks. size_t node_count = 0; - /// The size of the hash table used for hash-consing (interning) expression - /// nodes. Choosing 0x4000 (16,384) is the smallest power of two that keeps - /// the load factor below 70% when the pool reaches its limit of 10,000 nodes - /// (peak load factor is ~61%). Using a power of two allows the compiler to - /// optimize the modulo indexing into an efficient bitwise AND, while the low - /// load factor minimizes collisions and guarantees O(1) average interning - /// time. - static constexpr size_t HASH_TABLE_SIZE = 0x4000; + /// Lazily allocated array of deduplicated 256-bit character sets. + cpp::span<ByteSet> byte_sets; + size_t byte_set_count = 0; - /// The maximum number of nodes allowed in the pool to prevent memory - /// exhaustion during compilation of highly complex or maliciously crafted - /// regular expressions. A limit of 10,000 nodes provides a sufficient budget - /// for most practical regexes while keeping the peak memory footprint - /// manageable (approx. 320KB-500KB depending on architecture). - static constexpr size_t MAX_NODE_LIMIT = 10000; + /// Open-addressing hash table storing ExprIds (0 = empty bucket). + cpp::span<ExprId> hashtable; + + cpp::span<Block *const> active_blocks() const { + return blocks.first(block_count); + } - /// Hash table storing pointers to unique Expr nodes. - Expr **hashtable = nullptr; + cpp::span<const ByteSet> active_byte_sets() const { + return byte_sets.first(byte_set_count); + } + + /// Maximum number of nodes the current hash table can hold before rehashing. + size_t max_hashtable_nodes() const { + return static_cast<size_t>(static_cast<double>(hashtable.size()) * + MAX_LOAD_FACTOR); + } + + /// Single choke point mapping a 1-based ExprId to its 2D block/node slot. + Expr &slot_at(ExprId id) const { + LIBC_ASSERT(id != INVALID_EXPR_ID && id <= node_count); + size_t idx = static_cast<size_t>(id - 1); + return blocks[idx / NODES_PER_BLOCK]->nodes[idx % NODES_PER_BLOCK]; + } + + ExprId &find_bucket(cpp::span<ExprId> table, const Expr &e) const; + bool ensure_initialized(); + bool allocate_block(); + bool grow_hashtable(); /// Core hash-consing function (Interning). /// /// Guarantees that for any two identical structural definitions of an Expr, - /// this function will return the same pointer. This enables O(1) structural - /// equality via pointer comparison. + /// this function will return the same ExprId. This enables O(1) structural + /// equality via ID comparison. /// /// \param e A structural definition (proto-node) to intern. - /// \returns A pointer to the unique, stable instance in the arena, + /// \returns The ExprId of the unique, stable instance in the arena, /// or REG_ESPACE on failure. - cpp::expected<Expr *, int> intern(const Expr &e); + ErrorOr<ExprId> intern(Expr e); public: - ExprPool(); + /// The maximum number of nodes allowed in the pool to prevent memory + /// exhaustion during compilation of highly complex or maliciously crafted + /// regular expressions. + static constexpr size_t MAX_NODE_LIMIT = 10000; + + constexpr ExprPool() = default; ~ExprPool(); + /// Resolves an ExprId to a reference. + const Expr &get(ExprId id) const { return slot_at(id); } + + /// Resolves a ByteSet index to its 256-bit character set. + const ByteSet &get_byte_set(uint32_t id) const { + LIBC_ASSERT(id < byte_set_count); + return byte_sets[id]; + } + + /// O(1) unconditional nullability query for a valid ExprId. + bool is_nullable(ExprId id) const { return get(id).nullable; } + + /// O(1) query indicating whether the subtree at id contains an Anchor node. + bool has_anchors(ExprId id) const { return get(id).has_anchors; } + + /// Returns the number of unique AST nodes currently interned in this pool. + size_t size() const { return node_count; } + + /// Returns the number of unique multi-bit ByteSets interned in this pool. + size_t num_byte_sets() const { return byte_set_count; } + + /// Returns the current heap bytes allocated by this pool. + size_t allocated_bytes() const { + return (block_count * sizeof(Block)) + blocks.size_bytes() + + hashtable.size_bytes() + byte_sets.size_bytes(); + } + // TODO: Use fluent interface (and_then, transform) for these factories once - // implemented in cpp::expected. + // implemented in ErrorOr / cpp::expected. /// Returns an EmptySet node. - cpp::expected<Expr *, int> empty_set(); + ErrorOr<ExprId> empty_set(); /// Returns an EmptyStr node. - cpp::expected<Expr *, int> empty_str(); + ErrorOr<ExprId> empty_str(); /// Creates or returns an existing Literal node for the given character. - cpp::expected<Expr *, int> make_lit(char c); - /// Normalizing factory for Concatenation (L · R). - /// - /// Applies algebraic simplifications before interning: - /// - (Ø · R) or (R · Ø) => Ø - /// - (ε · R) or (R · ε) => R - cpp::expected<Expr *, int> make_concat(Expr *l, Expr *r); - - /// Normalizing factory for Alternation (L | R). - /// - /// Applies algebraic simplifications before interning: - /// - (Ø | R) or (R | Ø) => R - /// - (R | R) => R (Idempotency) - cpp::expected<Expr *, int> make_alt(Expr *l, Expr *r); + ErrorOr<ExprId> make_lit(char c); + /// Creates or returns an existing Anchor node for the given AnchorKind mask. + ErrorOr<ExprId> make_anchor(uint8_t mask); + /// Creates or returns an existing node for the given 256-bit character set. + ErrorOr<ExprId> make_byte_set(const ByteSet &bs); + /// Creates or returns a normalized Kleene star node (body*). + ErrorOr<ExprId> make_star(ExprId body); + /// Creates or returns a right-associated Concatenation node (l . r). + ErrorOr<ExprId> make_concat(ExprId l, ExprId r); + /// Creates or returns a canonical deduplicated Alternation node (l | r). + ErrorOr<ExprId> make_alt(ExprId l, ExprId r); }; } // namespace regex diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_internal.h b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_internal.h new file mode 100644 index 000000000000..d3fcac732b90 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_internal.h @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Internal compiled regular expression representation owned by regex_t. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_INTERNAL_H +#define LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_INTERNAL_H + +#include "src/__support/macros/config.h" +#include "src/__support/regex/regex_ast.h" +#include "src/__support/regex/regex_expr_pool.h" +#include "src/__support/threads/spin_lock.h" + +namespace LIBC_NAMESPACE_DECL { +namespace regex { + +/// Internal state stored in regex_t::__internal after a successful regcomp. +struct RegexInternal { + /// Arena and hash-consing table for the pattern AST and derivative states. + ExprPool pool; + /// Root ExprId of the compiled regular expression. + ExprId root = INVALID_EXPR_ID; + /// Compilation flags passed to regcomp. + int cflags = 0; + /// Spinlock serialising lazy derivative interning across concurrent regexec + /// calls sharing the same const regex_t*. + SpinLock lock{}; +}; + +} // namespace regex +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_INTERNAL_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.cpp new file mode 100644 index 000000000000..c58daf83294f --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Brzozowski derivative evaluation and regular expression matching +/// implementation. +/// +//===----------------------------------------------------------------------===// + +#include "src/__support/regex/regex_matcher.h" + +#include "hdr/regex_macros.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/error_or.h" +#include "src/__support/libc_assert.h" +#include "src/__support/macros/config.h" +#include "src/__support/regex/regex_ast.h" +#include "src/__support/regex/regex_expr_pool.h" + +namespace LIBC_NAMESPACE_DECL { +namespace regex { + +namespace { + +// Computes the active AnchorKind bitmask at fencepost position pos in input. +uint8_t ctx_at(cpp::string_view input, size_t pos, int cflags, int eflags) { + LIBC_ASSERT(pos <= input.size()); + uint8_t ctx = 0; + if ((pos == 0 && !(eflags & REG_NOTBOL)) || + (pos > 0 && (cflags & REG_NEWLINE) && input[pos - 1] == '\n')) + ctx |= ANCHOR_BOL; + if ((pos == input.size() && !(eflags & REG_NOTEOL)) || + (pos < input.size() && (cflags & REG_NEWLINE) && input[pos] == '\n')) + ctx |= ANCHOR_EOL; + return ctx; +} + +} // namespace + +bool nullable(ExprId id, uint8_t anchor_ctx, const ExprPool &pool) { + const Expr &e = pool.get(id); + if (!e.has_anchors) + return e.nullable; + switch (e.kind) { + case ExprKind::Anchor: + return (anchor_ctx & e.anchor_mask) == e.anchor_mask; + case ExprKind::Concat: + return nullable(e.bin.left, anchor_ctx, pool) && + nullable(e.bin.right, anchor_ctx, pool); + case ExprKind::Alt: + return nullable(e.bin.left, anchor_ctx, pool) || + nullable(e.bin.right, anchor_ctx, pool); + default: + return e.nullable; + } +} + +ErrorOr<ExprId> derivative(ExprId id, char c, ExprPool &pool, + uint8_t ctx_before) { + // Copy the 16-byte node by value as recursive calls below mutate pool. + const Expr e = pool.get(id); + switch (e.kind) { + case ExprKind::EmptySet: + case ExprKind::EmptyStr: + case ExprKind::Anchor: + return EMPTY_SET_ID; + case ExprKind::Literal: + return (c == e.ch) ? EMPTY_STR_ID : EMPTY_SET_ID; + case ExprKind::ByteSet: + return pool.get_byte_set(e.byte_set_id).test(static_cast<uint8_t>(c)) + ? EMPTY_STR_ID + : EMPTY_SET_ID; + case ExprKind::Concat: { + // Product Rule: + // D_c(L . R) = (D_c(L) . R) | (nullable(L, ctx_before) ? D_c(R) : EmptySet) + const bool left_nullable = nullable(e.bin.left, ctx_before, pool); + ErrorOr<ExprId> d_l = derivative(e.bin.left, c, pool, ctx_before); + if (!d_l.has_value()) + return d_l; + ErrorOr<ExprId> lhs = pool.make_concat(*d_l, e.bin.right); + if (!lhs.has_value() || !left_nullable) + return lhs; + ErrorOr<ExprId> d_r = derivative(e.bin.right, c, pool, ctx_before); + if (!d_r.has_value()) + return d_r; + return pool.make_alt(*lhs, *d_r); + } + case ExprKind::Alt: { + // Sum Rule: D_c(L | R) = D_c(L) | D_c(R) + ErrorOr<ExprId> d_l = derivative(e.bin.left, c, pool, ctx_before); + if (!d_l.has_value()) + return d_l; + ErrorOr<ExprId> d_r = derivative(e.bin.right, c, pool, ctx_before); + if (!d_r.has_value()) + return d_r; + return pool.make_alt(*d_l, *d_r); + } + case ExprKind::Star: { + // Kleene Rule: D_c(R*) = D_c(R) . R* + ErrorOr<ExprId> d_body = derivative(e.body, c, pool, ctx_before); + if (!d_body.has_value()) + return d_body; + return pool.make_concat(*d_body, id); + } + } + __builtin_unreachable(); +} + +MatchResult match(ExprPool &pool, const ExprId pattern, cpp::string_view input, + int cflags, int eflags) { + uint8_t ctx = ctx_at(input, 0, cflags, eflags); + if (nullable(pattern, ctx, pool)) + return MatchResult::Match; + + // Unanchored substring search: at each byte, step active partial matches via + // derivative(state, c, pool, ctx) and union with pattern so a new match can + // begin at the next fencepost (equivalent to matching .* . pattern without + // constructing a prefix wildcard node). + ExprId state = pattern; + for (size_t pos = 0; pos < input.size(); ++pos) { + ErrorOr<ExprId> d = derivative(state, input[pos], pool, ctx); + if (!d.has_value()) + return MatchResult::OutOfMemory; + ctx = ctx_at(input, pos + 1, cflags, eflags); + if (nullable(*d, ctx, pool) || nullable(pattern, ctx, pool)) + return MatchResult::Match; + ErrorOr<ExprId> next = pool.make_alt(pattern, *d); + if (!next.has_value()) + return MatchResult::OutOfMemory; + state = *next; + } + + return MatchResult::NoMatch; +} + +} // namespace regex +} // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.h b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.h new file mode 100644 index 000000000000..110633c66ef6 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_matcher.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Brzozowski derivative evaluation and regular expression matching interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_MATCHER_H +#define LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_MATCHER_H + +#include "src/__support/CPP/string_view.h" +#include "src/__support/common.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/regex/regex_ast.h" +#include "src/__support/regex/regex_expr_pool.h" +#include "src/__support/regex/regex_internal.h" + +namespace LIBC_NAMESPACE_DECL { +namespace regex { + +/// Outcome of evaluating a regular expression against an input string. +enum class MatchResult { + Match, + NoMatch, + OutOfMemory, +}; + +/// Evaluates whether id can match the empty string at a fencepost with the +/// given active AnchorKind bitmask. +bool nullable(ExprId id, uint8_t anchor_ctx, const ExprPool &pool); + +/// Computes the Brzozowski derivative D_c(id) with respect to character c +/// when stepping across c from a fencepost with active anchor mask ctx_before. +/// +/// Formally, D_c(L) = { w | c . w in L }. +ErrorOr<ExprId> derivative(ExprId id, char c, ExprPool &pool, + uint8_t ctx_before = 0); + +/// Evaluates whether pattern matches any substring of input using lazy +/// Brzozowski derivatives. +MatchResult match(ExprPool &pool, const ExprId pattern, cpp::string_view input, + int cflags = 0, int eflags = 0); + +/// Evaluates a compiled RegexInternal against input. +LIBC_INLINE MatchResult match(RegexInternal &internal, cpp::string_view input, + int eflags = 0) { + return match(internal.pool, internal.root, input, internal.cflags, eflags); +} + +} // namespace regex +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_MATCHER_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.cpp new file mode 100644 index 000000000000..7637183fb55a --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.cpp @@ -0,0 +1,276 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Regular expression parser implementation. +/// +//===----------------------------------------------------------------------===// + +#include "src/__support/regex/regex_parser.h" + +#include "hdr/regex_macros.h" +#include "src/__support/CPP/array.h" +#include "src/__support/CPP/new.h" +#include "src/__support/CPP/scope.h" +#include "src/__support/CPP/span.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/alloc-checker.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/regex/regex_ast.h" +#include "src/__support/regex/regex_expr_pool.h" + +namespace LIBC_NAMESPACE_DECL { +namespace regex { + +namespace { + +// Returns true for backslash escape sequences that represent backreferences, +// boundary assertions, or character-class shorthands rather than escaped +// literal characters. +constexpr bool is_unimplemented_ere_escape(char c) { + switch (c) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'b': + case 'B': + case '<': + case '>': + case 'A': + case 'Z': + case '`': + case '\'': + case 'w': + case 'W': + case 's': + case 'S': + case 'd': + case 'D': + return true; + default: + return false; + } +} + +// Parses a single collating element [[.c.]] or equivalence class [[=c=]]. +ErrorOr<uint8_t> parse_coll_elem(cpp::string_view &rem) { + cpp::string_view close_delim = rem.starts_with("[.") ? ".]" : "=]"; + rem.remove_prefix(2); + // TODO: Adopt cpp::string_view::find once implemented in + // src/__support/CPP/string_view.h. + size_t delim_pos = 0; + while (delim_pos + 2 <= rem.size() && + !rem.substr(delim_pos).starts_with(close_delim)) + ++delim_pos; + if (delim_pos + 2 > rem.size()) + return Error(REG_EBRACK); + cpp::string_view elem = rem.substr(0, delim_pos); + rem.remove_prefix(delim_pos + 2); + if (elem.size() == 1) + return static_cast<uint8_t>(elem.front()); + if (elem == "one") + return static_cast<uint8_t>('1'); + return Error(REG_ECOLLATE); +} + +// Parses a single bracket expression item (collating element or single byte). +ErrorOr<uint8_t> parse_bracket_elem(cpp::string_view &rem) { + if (rem.starts_with("[:")) + return Error(REG_BADPAT); + if (rem.starts_with("[.") || rem.starts_with("[=")) + return parse_coll_elem(rem); + uint8_t c = static_cast<uint8_t>(rem.front()); + rem.remove_prefix(1); + return c; +} + +// Parses a POSIX bracket expression [...], returning a ByteSet node. +ErrorOr<ExprId> parse_bracket_expr(cpp::string_view &rem, int cflags, + ExprPool &pool) { + bool negate = false; + if (rem.starts_with('^')) { + negate = true; + rem.remove_prefix(1); + } + + ByteSet bs; + bool first = true; + while (!rem.empty()) { + if (rem.starts_with(']') && !first) { + rem.remove_prefix(1); + if (negate) { + bs.flip(); + bs.reset(0); + if (cflags & REG_NEWLINE) + bs.reset('\n'); + } + return pool.make_byte_set(bs); + } + first = false; + + ErrorOr<uint8_t> c1 = parse_bracket_elem(rem); + if (!c1.has_value()) + return Error(c1.error()); + + if (rem.starts_with('-') && !rem.starts_with("-]")) { + rem.remove_prefix(1); + if (rem.empty()) + return Error(REG_ERANGE); + if (rem.starts_with("[:")) + return Error(REG_ERANGE); + ErrorOr<uint8_t> c2 = parse_bracket_elem(rem); + if (!c2.has_value()) + return Error(c2.error()); + if (*c1 > *c2) + return Error(REG_ERANGE); + bs.set_range(*c1, *c2); + if (rem.starts_with('-') && !rem.starts_with("-]")) + return Error(REG_ERANGE); + } else { + bs.set(*c1); + } + } + + return Error(REG_EBRACK); +} + +// Parses a single ERE atom and an optional trailing '*' quantifier. +ErrorOr<ExprId> parse_quantified_atom(cpp::string_view &rem, int cflags, + ExprPool &pool) { + char c = rem.front(); + rem.remove_prefix(1); + ErrorOr<ExprId> atom = INVALID_EXPR_ID; + bool can_repeat = true; + switch (c) { + case '\\': { + if (rem.empty()) + return Error(REG_EESCAPE); + c = rem.front(); + rem.remove_prefix(1); + if (is_unimplemented_ere_escape(c)) + return Error(REG_BADPAT); + atom = pool.make_lit(c); + break; + } + case '.': { + ByteSet bs; + if (cflags & REG_NEWLINE) { + bs.set_range(0, '\n' - 1); + bs.set_range('\n' + 1, BYTE_SET_BITS - 1); + } else { + bs.flip(); + } + atom = pool.make_byte_set(bs); + break; + } + case '^': + atom = pool.make_anchor(ANCHOR_BOL); + can_repeat = false; + break; + case '$': + atom = pool.make_anchor(ANCHOR_EOL); + can_repeat = false; + break; + // Valid postfix '*' is consumed after a repeatable atom below; reaching a + // quantifier at the start of an atom means it has no preceding repeatable + // atom (e.g. "*a", "^*", or doubled "a**"). + case '*': + case '+': + case '?': + return Error(REG_BADRPT); + case '{': + if (!rem.empty() && rem.front() >= '0' && rem.front() <= '9') + return Error(REG_BADRPT); + return Error(REG_BADPAT); + case '[': + atom = parse_bracket_expr(rem, cflags, pool); + break; + // TODO: Wire ERE metacharacters as each operator is implemented in + // subsequent patches. + case '(': + case ')': + case '|': + return Error(REG_BADPAT); + default: + atom = pool.make_lit(c); + break; + } + + if (!atom.has_value() || !can_repeat) + return atom; + if (rem.starts_with('*')) { + rem.remove_prefix(1); + return pool.make_star(*atom); + } + if (rem.starts_with('+') || rem.starts_with('?') || rem.starts_with('{')) + return Error(REG_BADPAT); + return atom; +} + +} // namespace + +ErrorOr<ExprId> parse_ere(cpp::string_view pattern, int cflags, + ExprPool &pool) { + // Collect quantified atoms in a 64-atom (256-byte) stack buffer, spilling to + // the heap only for longer chains, then fold right-to-left so + // right-associative make_concat stays O(1) without orphaned prefixes. + // TODO: Replace inline_atoms + heap_atoms with an AllocChecker-backed + // SmallVector / unique_ptr once available in src/__support/CPP/. + constexpr size_t INLINE_ATOM_COUNT = 64; + cpp::array<ExprId, INLINE_ATOM_COUNT> inline_atoms{}; + ExprId *heap_atoms = nullptr; + cpp::scope_exit cleanup([&heap_atoms] { delete[] heap_atoms; }); + cpp::span<ExprId> atoms(inline_atoms); + size_t atom_count = 0; + + cpp::string_view rem = pattern; + while (!rem.empty()) { + if (atom_count >= ExprPool::MAX_NODE_LIMIT) + return Error(REG_ESPACE); + if (atom_count == atoms.size()) { + size_t new_cap = atoms.size() * 2; + AllocChecker ac; + ExprId *new_atoms = new (ac) ExprId[new_cap]; + if (!ac) + return Error(REG_ESPACE); + ExprId *dst = new_atoms; + for (ExprId existing : atoms) { + *dst = existing; + ++dst; + } + delete[] heap_atoms; + heap_atoms = new_atoms; + atoms = cpp::span<ExprId>(heap_atoms, new_cap); + } + ErrorOr<ExprId> atom = parse_quantified_atom(rem, cflags, pool); + if (!atom.has_value()) + return atom; + atoms[atom_count] = *atom; + ++atom_count; + } + + ErrorOr<ExprId> acc = pool.empty_str(); + if (!acc.has_value()) + return acc; + for (size_t i = atom_count; i > 0; --i) { + acc = pool.make_concat(atoms[i - 1], *acc); + if (!acc.has_value()) + return acc; + } + return acc; +} + +} // namespace regex +} // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.h b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.h new file mode 100644 index 000000000000..2bf42cfdf2d8 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/regex/regex_parser.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Regular expression parser interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_PARSER_H +#define LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_PARSER_H + +#include "src/__support/CPP/string_view.h" +#include "src/__support/error_or.h" +#include "src/__support/macros/config.h" +#include "src/__support/regex/regex_ast.h" +#include "src/__support/regex/regex_expr_pool.h" + +namespace LIBC_NAMESPACE_DECL { +namespace regex { + +// Parses an Extended Regular Expression (ERE) into the given ExprPool. +ErrorOr<ExprId> parse_ere(cpp::string_view pattern, int cflags, ExprPool &pool); + +} // namespace regex +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_REGEX_REGEX_PARSER_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/str_to_float.h b/deps/v8/third_party/llvm-libc/src/src/__support/str_to_float.h index 877cfbf88a73..0c9c216ce88a 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/str_to_float.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/str_to_float.h @@ -94,7 +94,7 @@ eisel_lemire(ExpandedFloat<T> init_num, using StorageType = typename FPBits::StorageType; StorageType mantissa = init_num.mantissa; - int32_t exp10 = init_num.exponent; + int32_t exp_10 = init_num.exponent; if (sizeof(T) > 8) { // This algorithm cannot handle anything longer than a // double, so we skip straight to the fallback. @@ -102,8 +102,8 @@ eisel_lemire(ExpandedFloat<T> init_num, } // Exp10 Range - if (exp10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 || - exp10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) { + if (exp_10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 || + exp_10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) { return cpp::nullopt; } @@ -111,12 +111,12 @@ eisel_lemire(ExpandedFloat<T> init_num, uint32_t clz = static_cast<uint32_t>(cpp::countl_zero<StorageType>(mantissa)); mantissa <<= clz; - int32_t exp2 = exp10_to_exp2(exp10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - - static_cast<int32_t>(clz); + int32_t exp_2 = exp10_to_exp2(exp_10) + FPBits::STORAGE_LEN + + FPBits::EXP_BIAS - static_cast<int32_t>(clz); // Multiplication const uint64_t *power_of_ten = - DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; + DETAILED_POWERS_OF_TEN[exp_10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; UInt128 first_approx = static_cast<UInt128>(mantissa) * static_cast<UInt128>(power_of_ten[1]); @@ -153,7 +153,7 @@ eisel_lemire(ExpandedFloat<T> init_num, StorageType final_mantissa = static_cast<StorageType>( high64(final_approx) >> (msb + FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3))); - exp2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb + exp_2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb if (round == RoundDirection::Nearest) { // Half-way ambiguity @@ -180,18 +180,18 @@ eisel_lemire(ExpandedFloat<T> init_num, final_mantissa >>= 1; if ((final_mantissa >> (FPBits::FRACTION_LEN + 1)) > 0) { final_mantissa >>= 1; - ++exp2; + ++exp_2; } // The if block is equivalent to (but has fewer branches than): - // if exp2 <= 0 || exp2 >= 0x7FF { etc } - if (static_cast<uint32_t>(exp2) - 1 >= (1 << FPBits::EXP_LEN) - 2) { + // if exp_2 <= 0 || exp_2 >= 0x7FF { etc } + if (static_cast<uint32_t>(exp_2) - 1 >= (1 << FPBits::EXP_LEN) - 2) { return cpp::nullopt; } ExpandedFloat<T> output; output.mantissa = final_mantissa; - output.exponent = exp2; + output.exponent = exp_2; return output; } @@ -207,7 +207,7 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num, using StorageType = typename FPBits::StorageType; UInt128 mantissa = init_num.mantissa; - int32_t exp10 = init_num.exponent; + int32_t exp_10 = init_num.exponent; // Exp10 Range // This doesn't reach very far into the range for long doubles, since it's @@ -219,8 +219,8 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num, // uncommon path. In addition the exp10_to_exp2 function only approximates // multiplying by log(10)/log(2), and that approximation may not be accurate // out to the full long double range. - if (exp10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 || - exp10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) { + if (exp_10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 || + exp_10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) { return cpp::nullopt; } @@ -229,12 +229,12 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num, ((sizeof(UInt128) - sizeof(StorageType)) * CHAR_BIT); mantissa <<= clz; - int32_t exp2 = - exp10_to_exp2(exp10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - clz; + int32_t exp_2 = + exp10_to_exp2(exp_10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - clz; // Multiplication const uint64_t *power_of_ten = - DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; + DETAILED_POWERS_OF_TEN[exp_10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; // Since the input mantissa is more than 64 bits, we have to multiply with the // full 128 bits of the power of ten to get an approximation with the same @@ -279,7 +279,7 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num, static_cast<uint32_t>(final_approx_upper >> (FPBits::STORAGE_LEN - 1)); UInt128 final_mantissa = final_approx_upper >> (msb + FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3)); - exp2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb + exp_2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb if (round == RoundDirection::Nearest) { // Half-way ambiguity @@ -305,18 +305,18 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num, final_mantissa >>= 1; if ((final_mantissa >> (FPBits::FRACTION_LEN + 1)) > 0) { final_mantissa >>= 1; - ++exp2; + ++exp_2; } // The if block is equivalent to (but has fewer branches than): - // if exp2 <= 0 || exp2 >= MANTISSA_MAX { etc } - if (exp2 - 1 >= (1 << FPBits::EXP_LEN) - 2) { + // if exp_2 <= 0 || exp_2 >= MANTISSA_MAX { etc } + if (exp_2 - 1 >= (1 << FPBits::EXP_LEN) - 2) { return cpp::nullopt; } ExpandedFloat<long double> output; output.mantissa = static_cast<StorageType>(final_mantissa); - output.exponent = exp2; + output.exponent = exp_2; return output; } #endif // !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) && @@ -343,7 +343,7 @@ LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion( using FPBits = typename fputil::FPBits<T>; using StorageType = typename FPBits::StorageType; - int32_t exp2 = 0; + int32_t exp_2 = 0; HighPrecisionDecimal hpd = HighPrecisionDecimal(numStart, num_len); FloatConvertReturn<T> output; @@ -378,7 +378,7 @@ LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion( } else { shift_amount = POWERS_OF_TWO[hpd.get_decimal_point()]; } - exp2 += shift_amount; + exp_2 += shift_amount; hpd.shift(-shift_amount); } @@ -394,19 +394,19 @@ LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion( } else { // This handles the case of the number being between .1 and .5 shift_amount = 1; } - exp2 -= shift_amount; + exp_2 -= shift_amount; hpd.shift(shift_amount); } // Left shift once so that the number is between 1 and 2 - --exp2; + --exp_2; hpd.shift(1); // Get the biased exponent - exp2 += FPBits::EXP_BIAS; + exp_2 += FPBits::EXP_BIAS; // Handle the exponent being too large (and return inf). - if (exp2 >= FPBits::MAX_BIASED_EXPONENT) { + if (exp_2 >= FPBits::MAX_BIASED_EXPONENT) { output.num = {0, FPBits::MAX_BIASED_EXPONENT}; output.error = ERANGE; return output; @@ -417,37 +417,37 @@ LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion( StorageType final_mantissa = hpd.round_to_integer_type<StorageType>(); // Handle subnormals - if (exp2 <= 0) { + if (exp_2 <= 0) { // Shift right until there is a valid exponent, and once more to compensate // for the left shift to get it between 1 and 2. - hpd.shift(exp2 - 1); - exp2 = 0; + hpd.shift(exp_2 - 1); + exp_2 = 0; final_mantissa = hpd.round_to_integer_type<StorageType>(round); // Check if by shifting right we've caused this to round to a normal number. if ((final_mantissa >> FPBits::FRACTION_LEN) != 0) { - ++exp2; + ++exp_2; } } // Check if rounding added a bit, and shift down if that's the case. if (final_mantissa == StorageType(2) << FPBits::FRACTION_LEN) { final_mantissa >>= 1; - ++exp2; + ++exp_2; - // Check if this rounding causes exp2 to go out of range and make the result - // INF. If this is the case, then finalMantissa and exp2 are already the - // correct values for an INF result. - if (exp2 >= FPBits::MAX_BIASED_EXPONENT) { + // Check if this rounding causes exp_2 to go out of range and make the + // result INF. If this is the case, then finalMantissa and exp_2 are already + // the correct values for an INF result. + if (exp_2 >= FPBits::MAX_BIASED_EXPONENT) { output.error = ERANGE; } } - if (exp2 == 0) { + if (exp_2 == 0) { output.error = ERANGE; } - output.num = {final_mantissa, exp2}; + output.num = {final_mantissa, exp_2}; return output; } @@ -546,7 +546,7 @@ clinger_fast_path(ExpandedFloat<T> init_num, using StorageType = typename FPBits::StorageType; StorageType mantissa = init_num.mantissa; - int32_t exp10 = init_num.exponent; + int32_t exp_10 = init_num.exponent; if ((mantissa >> FPBits::FRACTION_LEN) > 0) { return cpp::nullopt; @@ -562,31 +562,31 @@ clinger_fast_path(ExpandedFloat<T> init_num, float_mantissa = static_cast<T>(mantissa); } - if (exp10 == 0) { + if (exp_10 == 0) { result = FPBits(float_mantissa); } - if (exp10 > 0) { - if (exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN + - ClingerConsts<T>::DIGITS_IN_MANTISSA) { + if (exp_10 > 0) { + if (exp_10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN + + ClingerConsts<T>::DIGITS_IN_MANTISSA) { return cpp::nullopt; } - if (exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) { + if (exp_10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) { float_mantissa = float_mantissa * ClingerConsts<T>::POWERS_OF_TEN_ARRAY - [exp10 - ClingerConsts<T>::EXACT_POWERS_OF_TEN]; - exp10 = ClingerConsts<T>::EXACT_POWERS_OF_TEN; + [exp_10 - ClingerConsts<T>::EXACT_POWERS_OF_TEN]; + exp_10 = ClingerConsts<T>::EXACT_POWERS_OF_TEN; } if (float_mantissa > ClingerConsts<T>::MAX_EXACT_INT) { return cpp::nullopt; } result = - FPBits(float_mantissa * ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp10]); - } else if (exp10 < 0) { - if (-exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) { + FPBits(float_mantissa * ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp_10]); + } else if (exp_10 < 0) { + if (exp_10 < -ClingerConsts<T>::EXACT_POWERS_OF_TEN) { return cpp::nullopt; } result = - FPBits(float_mantissa / ClingerConsts<T>::POWERS_OF_TEN_ARRAY[-exp10]); + FPBits(float_mantissa / ClingerConsts<T>::POWERS_OF_TEN_ARRAY[-exp_10]); } // If the rounding mode is not nearest, then the sign of the number may affect @@ -594,10 +594,12 @@ clinger_fast_path(ExpandedFloat<T> init_num, // calculation is redone with a negative result, and the rounding mode is used // to select the correct result. if (round != RoundDirection::Nearest) { - FPBits negative_result; // I'm 99% sure this will break under fast math optimizations. - negative_result = FPBits((-float_mantissa) * - ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp10]); + FPBits negative_result = + exp_10 < 0 ? FPBits((-float_mantissa) / + ClingerConsts<T>::POWERS_OF_TEN_ARRAY[-exp_10]) + : FPBits((-float_mantissa) * + ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp_10]); // If the results are equal, then we don't need to use the rounding mode. if (result.get_val() != -negative_result.get_val()) { @@ -681,7 +683,7 @@ LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float( const size_t num_len = cpp::numeric_limits<size_t>::max()) { using FPBits = typename fputil::FPBits<T>; - int32_t exp10 = init_num.exponent; + int32_t exp_10 = init_num.exponent; FloatConvertReturn<T> output; [[maybe_unused]] cpp::optional<ExpandedFloat<T>> opt_output; @@ -689,13 +691,13 @@ LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float( // If the exponent is too large and can't be represented in this size of // float, return inf. These bounds are relatively loose, but are mostly // serving as a first pass. Some close numbers getting through is okay. - if (exp10 > get_upper_bound<T>()) { + if (exp_10 > get_upper_bound<T>()) { output.num = {0, FPBits::MAX_BIASED_EXPONENT}; output.error = ERANGE; return output; } // If the exponent is too small even for a subnormal, return 0. - if (exp10 < get_lower_bound<T>()) { + if (exp_10 < get_lower_bound<T>()) { output.num = {0, 0}; output.error = ERANGE; return output; @@ -729,7 +731,7 @@ LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float( // If the mantissa is truncated, then the result may be off by the LSB, so // check if rounding the mantissa up changes the result. If not, then it's // safe, else use the fallback. - auto second_output = eisel_lemire<T>({mantissa + 1, exp10}, round); + auto second_output = eisel_lemire<T>({mantissa + 1, exp_10}, round); if (second_output.has_value()) { if (opt_output->mantissa == second_output->mantissa && opt_output->exponent == second_output->exponent) { @@ -765,7 +767,7 @@ LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num, using StorageType = typename FPBits::StorageType; StorageType mantissa = init_num.mantissa; - int32_t exp2 = init_num.exponent; + int32_t exp_2 = init_num.exponent; FloatConvertReturn<T> output; @@ -778,11 +780,11 @@ LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num, uint32_t amount_to_shift_left = cpp::countl_zero<StorageType>(mantissa); mantissa <<= amount_to_shift_left; - // Keep exp2 representing the exponent of the lowest bit of StorageType. - exp2 -= amount_to_shift_left; + // Keep exp_2 representing the exponent of the lowest bit of StorageType. + exp_2 -= amount_to_shift_left; // biased_exponent represents the biased exponent of the most significant bit. - int32_t biased_exponent = exp2 + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - 1; + int32_t biased_exponent = exp_2 + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - 1; // Handle numbers that're too large and get squashed to inf if (biased_exponent >= INF_EXP) { diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/str_to_integer.h b/deps/v8/third_party/llvm-libc/src/src/__support/str_to_integer.h index e6e599738bf4..282d26dee2de 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/str_to_integer.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/str_to_integer.h @@ -141,8 +141,8 @@ strtointeger(const CharType *__restrict src, int base, constexpr bool IS_UNSIGNED = cpp::is_unsigned_v<T>; ResultType constexpr NEGATIVE_MAX = - !IS_UNSIGNED ? static_cast<ResultType>(cpp::numeric_limits<T>::max()) + 1 - : cpp::numeric_limits<T>::max(); + static_cast<ResultType>(cpp::numeric_limits<T>::max()) + + (!IS_UNSIGNED ? 1 : 0); ResultType const abs_max = (is_positive ? cpp::numeric_limits<T>::max() : NEGATIVE_MAX); ResultType const abs_max_div_by_base = diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/threads/CMakeLists.txt index dde3ee34f3a3..4439cb811e7a 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/CMakeLists.txt @@ -19,11 +19,22 @@ add_header_library( libc.src.__support.CPP.atomic ) +add_header_library( + cleanup_stack + HDRS + cleanup_stack.h + DEPENDS + libc.hdr.types.struct___pthread_cleanup_frame + libc.src.__support.macros.attributes + libc.src.__support.macros.config +) + add_header_library( thread_attributes HDRS thread_attributes.h DEPENDS + .cleanup_stack libc.hdr.stdint_proxy libc.hdr.types.size_t libc.src.__support.CPP.atomic @@ -153,14 +164,17 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread) SRCS thread.cpp DEPENDS + .cleanup_stack .mutex .${LIBC_TARGET_OS}.thread - libc.hdr.stdint_proxy - libc.src.__support.common + libc.hdr.limits_macros + libc.hdr.types.struct___pthread_cleanup_frame libc.src.__support.fixedvector libc.src.__support.CPP.array libc.src.__support.CPP.mutex libc.src.__support.CPP.optional + libc.src.__support.macros.attributes + libc.src.__support.macros.config ) endif() diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/cleanup_stack.h b/deps/v8/third_party/llvm-libc/src/src/__support/threads/cleanup_stack.h new file mode 100644 index 000000000000..e2fecf648bb0 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/cleanup_stack.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Management of thread-specific cleanup handlers. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_CLEANUP_STACK_H +#define LLVM_LIBC_SRC___SUPPORT_THREADS_CLEANUP_STACK_H + +#include "hdr/types/struct___pthread_cleanup_frame.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +class CleanupStack { +public: + LIBC_INLINE void push(__pthread_cleanup_frame *frame) { + frame->__next = top; + top = frame; + } + + LIBC_INLINE __pthread_cleanup_frame *pop() { + __pthread_cleanup_frame *frame = top; + if (frame) { + top = frame->__next; + frame->__next = nullptr; + } + return frame; + } + +private: + __pthread_cleanup_frame *top = nullptr; +}; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_CLEANUP_STACK_H diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/CMakeLists.txt index ae449c1af799..2e539d489583 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/CMakeLists.txt @@ -40,18 +40,32 @@ add_header_library( libc.src.__support.time.abs_timeout ) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE}) + add_subdirectory(${LIBC_TARGET_ARCHITECTURE}) +endif() + +if(TARGET libc.src.__support.threads.linux.${LIBC_TARGET_ARCHITECTURE}.tls) + add_object_library( + tls + ALIAS + DEPENDS + .${LIBC_TARGET_ARCHITECTURE}.tls + ) + set(thread_tls_dep .tls) +endif() + add_object_library( thread SRCS thread.cpp DEPENDS .futex_utils + ${thread_tls_dep} libc.config.app_h libc.include.sys_syscall libc.hdr.fcntl_macros libc.hdr.errno_macros libc.hdr.sched_macros - libc.hdr.signal_macros libc.hdr.sys_mman_macros libc.src.errno.errno libc.src.__support.CPP.atomic @@ -59,7 +73,10 @@ add_object_library( libc.src.__support.CPP.string_view libc.src.__support.common libc.src.__support.error_or + libc.src.__support.OSUtil.linux.sigmask + libc.src.__support.OSUtil.linux.syscall_wrappers.clone libc.src.__support.OSUtil.linux.syscall_wrappers.close + libc.src.__support.OSUtil.linux.syscall_wrappers.exit libc.src.__support.OSUtil.linux.syscall_wrappers.getpid libc.src.__support.OSUtil.linux.syscall_wrappers.mmap libc.src.__support.OSUtil.linux.syscall_wrappers.mprotect @@ -73,12 +90,6 @@ add_object_library( libc.src.__support.OSUtil.linux.syscall_wrappers.write libc.src.__support.threads.thread_common libc.src.__support.threads.thread_attributes - COMPILE_OPTIONS - ${libc_opt_high_flag} - -fno-omit-frame-pointer # This allows us to sniff out the thread args from - # the new thread's stack reliably. - -Wno-frame-address # Yes, calling __builtin_return_address with a - # value other than 0 is dangerous. We know. ) add_header_library( diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/CMakeLists.txt new file mode 100644 index 000000000000..a2320f8d015c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/CMakeLists.txt @@ -0,0 +1,20 @@ +add_object_library( + tls + SRCS + tls.cpp + DEPENDS + libc.config.app_h + libc.hdr.sys_mman_macros + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.OSUtil.linux.syscall_wrappers.exit + libc.src.__support.OSUtil.linux.syscall_wrappers.mmap + libc.src.__support.OSUtil.linux.syscall_wrappers.munmap + libc.src.__support.threads.linux.tcb + libc.src.string.memory_utils.inline_memcpy + COMPILE_OPTIONS + -fno-stack-protector + -fno-omit-frame-pointer + -ffreestanding + -fno-builtin +) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/tls.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/tls.cpp new file mode 100644 index 000000000000..bf922aaf0b2c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/aarch64/tls.cpp @@ -0,0 +1,82 @@ +//===-- Implementation of tls for aarch64 ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "config/app.h" +#include "hdr/sys_mman_macros.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/macros/config.h" +#include "src/__support/threads/linux/tcb.h" +#include "src/string/memory_utils/inline_memcpy.h" + +#include <arm_acle.h> +#include <sys/syscall.h> + +// Source documentation: +// https://github.com/ARM-software/abi-aa/tree/main/sysvabi64 + +namespace LIBC_NAMESPACE_DECL { + +[[gnu::flatten]] void init_tls(TLSDescriptor &tls_descriptor) { + // aarch64 follows the variant 1 TLS layout: + // + // 1. First entry is the dynamic thread vector pointer + // 2. Second entry is a 8-byte reserved word (used for attrib). + // 3. Padding for alignment. + // 4. The TLS data from the ELF image. + // + // The thread pointer points to the first entry. + + const uintptr_t TCB_SIZE = sizeof(ThreadControlBlock); + uintptr_t padding = 0; + const uintptr_t ALIGNMENT_MASK = app.tls.align - 1; + uintptr_t diff = TCB_SIZE & ALIGNMENT_MASK; + if (diff != 0) + padding += (ALIGNMENT_MASK - diff) + 1; + + uintptr_t alloc_size = TCB_SIZE + padding + app.tls.size; + + ErrorOr<void *> mmap_ret = + linux_syscalls::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (!mmap_ret.has_value()) + linux_syscalls::exit(1); + uintptr_t thread_ptr = uintptr_t(mmap_ret.value()); + uintptr_t tls_addr = thread_ptr + TCB_SIZE + padding; + inline_memcpy(reinterpret_cast<char *>(tls_addr), + reinterpret_cast<const char *>(app.tls.address), + app.tls.init_size); + tls_descriptor.size = alloc_size; + tls_descriptor.addr = thread_ptr; + tls_descriptor.tp = thread_ptr; +} + +void cleanup_tls(uintptr_t addr, uintptr_t size) { + if (size == 0) + return; + linux_syscalls::munmap(reinterpret_cast<void *>(addr), size); +} + +bool set_thread_ptr(uintptr_t val) { +// The PR for __arm_wsr64 support in GCC was merged on Dec 6, 2023, and it is +// not yet usable in 13.3.0 +// https://github.com/gcc-mirror/gcc/commit/fc42900d21abd5eacb7537c3c8ffc5278d510195 +#if __has_builtin(__builtin_arm_wsr64) + __builtin_arm_wsr64("tpidr_el0", val); +#elif __has_builtin(__builtin_aarch64_wsr64) + __builtin_aarch64_wsr64("tpidr_el0", val); +#elif defined(__GNUC__) + asm volatile("msr tpidr_el0, %0" ::"r"(val)); +#else +#error "Unsupported compiler" +#endif + return true; +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/CMakeLists.txt new file mode 100644 index 000000000000..a2320f8d015c --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/CMakeLists.txt @@ -0,0 +1,20 @@ +add_object_library( + tls + SRCS + tls.cpp + DEPENDS + libc.config.app_h + libc.hdr.sys_mman_macros + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.OSUtil.linux.syscall_wrappers.exit + libc.src.__support.OSUtil.linux.syscall_wrappers.mmap + libc.src.__support.OSUtil.linux.syscall_wrappers.munmap + libc.src.__support.threads.linux.tcb + libc.src.string.memory_utils.inline_memcpy + COMPILE_OPTIONS + -fno-stack-protector + -fno-omit-frame-pointer + -ffreestanding + -fno-builtin +) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/tls.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/tls.cpp new file mode 100644 index 000000000000..88a45a09df10 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/riscv/tls.cpp @@ -0,0 +1,58 @@ +//===-- Implementation of tls for riscv -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "config/app.h" +#include "hdr/sys_mman_macros.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/macros/config.h" +#include "src/__support/threads/linux/tcb.h" +#include "src/string/memory_utils/inline_memcpy.h" +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { + +[[gnu::flatten]] void init_tls(TLSDescriptor &tls_descriptor) { + // riscv follows the variant 1 TLS layout: + const uintptr_t TCB_SIZE = sizeof(ThreadControlBlock); + uintptr_t padding = 0; + const uintptr_t ALIGNMENT_MASK = app.tls.align - 1; + uintptr_t diff = TCB_SIZE & ALIGNMENT_MASK; + if (diff != 0) + padding += (ALIGNMENT_MASK - diff) + 1; + + uintptr_t alloc_size = TCB_SIZE + padding + app.tls.size; + + ErrorOr<void *> mmap_ret = + linux_syscalls::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (!mmap_ret.has_value()) + linux_syscalls::exit(1); + uintptr_t thread_ptr = uintptr_t(mmap_ret.value()); + uintptr_t tls_addr = thread_ptr + TCB_SIZE + padding; + inline_memcpy(reinterpret_cast<char *>(tls_addr), + reinterpret_cast<const char *>(app.tls.address), + app.tls.init_size); + tls_descriptor.size = alloc_size; + tls_descriptor.addr = thread_ptr; + tls_descriptor.tp = tls_addr; +} + +void cleanup_tls(uintptr_t addr, uintptr_t size) { + if (size == 0) + return; + linux_syscalls::munmap(reinterpret_cast<void *>(addr), size); +} + +bool set_thread_ptr(uintptr_t val) { + LIBC_INLINE_ASM("mv tp, %0\n\t" : : "r"(val)); + return true; +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/thread.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/thread.cpp index efbdc4a45d37..db8f7ed103c7 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/thread.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/thread.cpp @@ -1,17 +1,25 @@ -//===--- Implementation of a Linux thread class -----------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of a Linux thread class. +/// +//===----------------------------------------------------------------------===// #include "src/__support/threads/thread.h" #include "config/app.h" #include "src/__support/CPP/atomic.h" #include "src/__support/CPP/string_view.h" #include "src/__support/CPP/stringstream.h" +#include "src/__support/OSUtil/linux/sigmask.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/clone.h" #include "src/__support/OSUtil/linux/syscall_wrappers/close.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h" #include "src/__support/OSUtil/linux/syscall_wrappers/getpid.h" #include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h" #include "src/__support/OSUtil/linux/syscall_wrappers/mprotect.h" @@ -32,14 +40,9 @@ #include "src/__support/threads/linux/futex_word.h" #include "src/__support/threads/thread_attributes.h" -#ifdef LIBC_TARGET_ARCH_IS_AARCH64 -#include <arm_acle.h> -#endif - #include "hdr/errno_macros.h" #include "hdr/fcntl_macros.h" #include "hdr/sched_macros.h" // For CLONE_* flags. -#include "hdr/signal_macros.h" #include "hdr/stdint_proxy.h" #include "hdr/sys_mman_macros.h" // For PROT_* and MAP_* definitions. #include <linux/param.h> // For EXEC_PAGESIZE. @@ -62,16 +65,6 @@ static constexpr unsigned CLONE_SYSCALL_FLAGS = // wake the joining thread. | CLONE_SETTLS; // Setup the thread pointer of the new thread. -#ifdef LIBC_TARGET_ARCH_IS_AARCH64 -#define CLONE_RESULT_REGISTER "x0" -#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) -#define CLONE_RESULT_REGISTER "t0" -#elif defined(LIBC_TARGET_ARCH_IS_X86_64) -#define CLONE_RESULT_REGISTER "rax" -#else -#error "CLONE_RESULT_REGISTER not defined for your target architecture" -#endif - static constexpr ErrorOr<size_t> add_no_overflow(size_t lhs, size_t rhs) { if (lhs > SIZE_MAX - rhs) return Error{EINVAL}; @@ -158,31 +151,8 @@ cleanup_thread_resources(ThreadAttributes *attrib) { free_stack(attrib->stack, attrib->stacksize, attrib->guardsize); } -[[gnu::always_inline]] LIBC_INLINE uintptr_t get_start_args_addr() { -// NOTE: For __builtin_frame_address to work reliably across compilers, -// architectures and various optimization levels, the TU including this file -// should be compiled with -fno-omit-frame-pointer. -#ifdef LIBC_TARGET_ARCH_IS_X86_64 - return reinterpret_cast<uintptr_t>(__builtin_frame_address(0)) - // The x86_64 call instruction pushes resume address on to the stack. - // Next, The x86_64 SysV ABI requires that the frame pointer be pushed - // on to the stack. So, we have to step past two 64-bit values to get - // to the start args. - + sizeof(uintptr_t) * 2; -#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) - // The frame pointer after cloning the new thread in the Thread::run method - // is set to the stack pointer where start args are stored. So, we fetch - // from there. - return reinterpret_cast<uintptr_t>(__builtin_frame_address(1)); -#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) - // The current frame pointer is the previous stack pointer where the start - // args are stored. - return reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); -#endif -} - -[[gnu::noinline]] void start_thread() { - auto *start_args = reinterpret_cast<StartArgs *>(get_start_args_addr()); +static int start_thread(void *arg) { + auto *start_args = reinterpret_cast<StartArgs *>(arg); auto *attrib = start_args->thread_attrib; if (attrib->style == ThreadStyle::POSIX) { @@ -192,6 +162,7 @@ cleanup_thread_resources(ThreadAttributes *attrib) { ThreadReturnValue retval = start_args->runner.stdc_runner(start_args->arg); thread_exit(retval, ThreadStyle::STDC); } + return 0; } int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, @@ -240,14 +211,11 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, init_tls(tls); // When the new thread is spawned by the kernel, the new thread gets the - // stack we pass to the clone syscall. However, this stack is empty and does - // not have any local vars present in this function. Hence, one cannot - // pass arguments to the thread start function, or use any local vars from - // here. So, we pack them into the new stack from where the thread can sniff - // them out. - // - // Likewise, the actual thread state information is also stored on the - // stack memory. + // stack we pass to the clone syscall. Thread initialization structures + // (StartArgs, ThreadAttributes, and the clear_tid Futex) are allocated on + // the new thread's stack memory so their lifetime is managed with the stack + // without requiring heap allocation. A pointer to StartArgs is passed + // directly to start_thread via the clone syscall wrapper's argument. static constexpr size_t INTERNAL_STACK_DATA_SIZE = sizeof(StartArgs) + sizeof(ThreadAttributes) + sizeof(Futex); @@ -298,48 +266,15 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, get_tcb(tls.tp)->attrib = attrib; - // The clone syscall takes arguments in an architecture specific order. - // Also, we want the result of the syscall to be in a register as the child - // thread gets a completely different stack after it is created. The stack - // variables from this function will not be availalbe to the child thread. -#if defined(LIBC_TARGET_ARCH_IS_X86_64) - long register clone_result asm(CLONE_RESULT_REGISTER); - clone_result = LIBC_NAMESPACE::syscall_impl<long>( - SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack, - &attrib->tid, // The address where the child tid is written - &clear_tid->val, // The futex where the child thread status is signalled - tls.tp // The thread pointer value for the new thread. - ); -#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) || \ - defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) - long register clone_result asm(CLONE_RESULT_REGISTER); - clone_result = LIBC_NAMESPACE::syscall_impl<long>( - SYS_clone, CLONE_SYSCALL_FLAGS, adjusted_stack, - &attrib->tid, // The address where the child tid is written - tls.tp, // The thread pointer value for the new thread. - &clear_tid->val // The futex where the child thread status is signalled - ); -#else -#error "Unsupported architecture for the clone syscall." -#endif - - if (clone_result == 0) { -#ifdef LIBC_TARGET_ARCH_IS_AARCH64 - // We set the frame pointer to be the same as the "sp" so that start args - // can be sniffed out from start_thread. -#ifdef __clang__ - // GCC does not currently implement __arm_wsr64/__arm_rsr64. - __arm_wsr64("x29", __arm_rsr64("sp")); -#else - asm volatile("mov x29, sp"); -#endif -#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) - asm volatile("mv fp, sp"); -#endif - start_thread(); - } else if (clone_result < 0) { + auto clone_result = linux_syscalls::clone( + start_thread, reinterpret_cast<void *>(adjusted_stack), + CLONE_SYSCALL_FLAGS, start_args, &attrib->tid, + reinterpret_cast<void *>(tls.tp), + reinterpret_cast<pid_t *>(&clear_tid->val)); + + if (!clone_result.has_value()) { cleanup_thread_resources(attrib); - return static_cast<int>(-clone_result); + return clone_result.error(); } return 0; @@ -408,10 +343,6 @@ void Thread::wait() { clear_tid->wait(clear_tid_value, cpp::nullopt, true); } -bool Thread::operator==(const Thread &thread) const { - return attrib->tid == thread.attrib->tid; -} - static constexpr cpp::string_view THREAD_NAME_PATH_PREFIX("/proc/self/task/"); static constexpr size_t THREAD_NAME_PATH_SIZE = THREAD_NAME_PATH_PREFIX.size() + @@ -574,6 +505,10 @@ void thread_exit(ThreadReturnValue retval, ThreadStyle style) { if (!attrib->detach_state.compare_exchange_strong( joinable_state, uint32_t(DetachState::EXITING))) { // Thread is detached so cleanup the resources. + // Signals must be blocked before unmapping the stack to prevent any signal + // handler from running without a stack. + (void)signals::block_all(); + cleanup_thread_resources(attrib); // Set the CLEAR_TID address to nullptr to prevent the kernel @@ -582,15 +517,14 @@ void thread_exit(ThreadReturnValue retval, ThreadStyle style) { // Return value for detached thread should be unused. We need to avoid // referencing `style` or `retval.*` because they may be stored on the stack // and we have deallocated our stack! - LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, 0); - __builtin_unreachable(); + linux_syscalls::exit(0); } if (style == ThreadStyle::POSIX) - LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, retval.posix_retval); + linux_syscalls::exit( + static_cast<int>(reinterpret_cast<uintptr_t>(retval.posix_retval))); else - LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, retval.stdc_retval); - __builtin_unreachable(); + linux_syscalls::exit(retval.stdc_retval); } } // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/CMakeLists.txt new file mode 100644 index 000000000000..cfd585033200 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/CMakeLists.txt @@ -0,0 +1,21 @@ +add_object_library( + tls + SRCS + tls.cpp + DEPENDS + libc.config.app_h + libc.hdr.sys_mman_macros + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.__support.OSUtil.linux.syscall_wrappers.exit + libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom + libc.src.__support.OSUtil.linux.syscall_wrappers.mmap + libc.src.__support.OSUtil.linux.syscall_wrappers.munmap + libc.src.__support.threads.linux.tcb + libc.src.string.memory_utils.inline_memcpy + COMPILE_OPTIONS + -fno-stack-protector + -fno-omit-frame-pointer + -ffreestanding + -fno-builtin +) diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/tls.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/tls.cpp new file mode 100644 index 000000000000..af2e16740681 --- /dev/null +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/linux/x86_64/tls.cpp @@ -0,0 +1,76 @@ +//===-- Implementation of tls for x86_64 ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "config/app.h" +#include "hdr/sys_mman_macros.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/exit.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h" +#include "src/__support/macros/config.h" +#include "src/__support/threads/linux/tcb.h" +#include "src/string/memory_utils/inline_memcpy.h" + +#include <asm/prctl.h> +#include <sys/syscall.h> + +namespace LIBC_NAMESPACE_DECL { + +// TODO: Also generalize this routine and handle dynamic loading properly. +[[gnu::flatten]] void init_tls(TLSDescriptor &tls_descriptor) { + // We will assume the alignment is always a power of two. + uintptr_t tls_size = app.tls.size & -app.tls.align; + if (tls_size != app.tls.size) + tls_size += app.tls.align; + + uintptr_t tls_size_with_tcb = tls_size + sizeof(ThreadControlBlock); + + ErrorOr<void *> mmap_ret = + linux_syscalls::mmap(nullptr, tls_size_with_tcb, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (!mmap_ret.has_value()) + linux_syscalls::exit(1); + uintptr_t *tls_addr = static_cast<uintptr_t *>(mmap_ret.value()); + + // x86_64 TLS faces down from the thread pointer with the first entry + // pointing to the address of the first real TLS byte. + uintptr_t end_ptr = reinterpret_cast<uintptr_t>(tls_addr) + tls_size; + auto *tcb = reinterpret_cast<ThreadControlBlock *>(end_ptr); + tcb->self = end_ptr; + + if (app.tls.init_size) { + inline_memcpy(reinterpret_cast<char *>(tls_addr), + reinterpret_cast<const char *>(app.tls.address), + app.tls.init_size); + } + // Setting the stack guard to a random value. + // We cannot call the get_random function here as the function sets errno on + // failure. Since errno is implemented via a thread local variable, we cannot + // use errno before TLS is setup. The linux_syscalls wrapper is safe as it + // reports errors via ErrorOr instead of errno. + ErrorOr<ssize_t> stack_guard_retval = + linux_syscalls::getrandom(&tcb->stack_guard, sizeof(tcb->stack_guard), 0); + if (!stack_guard_retval.has_value()) + linux_syscalls::exit(1); + + tls_descriptor = {tls_size_with_tcb, reinterpret_cast<uintptr_t>(tls_addr), + end_ptr}; + return; +} + +void cleanup_tls(uintptr_t addr, uintptr_t size) { + if (size == 0) + return; + linux_syscalls::munmap(reinterpret_cast<void *>(addr), size); +} + +// Sets the thread pointer to |val|. Returns true on success, false on failure. +bool set_thread_ptr(uintptr_t val) { + return syscall_impl(SYS_arch_prctl, ARCH_SET_FS, val) != -1; +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/raw_mutex.h b/deps/v8/third_party/llvm-libc/src/src/__support/threads/raw_mutex.h index c13194344c3d..d78908c54bdc 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/raw_mutex.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/raw_mutex.h @@ -19,8 +19,6 @@ #include "src/__support/threads/sleep.h" #include "src/__support/time/abs_timeout.h" -#include <stdio.h> - // TODO(bojle): check this for darwin impl #ifdef LIBC_COPT_TIMEOUT_ENSURE_MONOTONICITY #include "src/__support/time/monotonicity.h" diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.cpp b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.cpp index abcf7e399c16..828014507fee 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.cpp +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.cpp @@ -7,14 +7,16 @@ //===----------------------------------------------------------------------===// #include "src/__support/threads/thread.h" -#include "src/__support/macros/config.h" -#include "src/__support/threads/mutex.h" - +#include "hdr/limits_macros.h" +#include "hdr/types/struct___pthread_cleanup_frame.h" #include "src/__support/CPP/array.h" #include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/CPP/optional.h" #include "src/__support/fixedvector.h" #include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/threads/cleanup_stack.h" +#include "src/__support/threads/mutex.h" namespace LIBC_NAMESPACE_DECL { namespace { @@ -137,26 +139,35 @@ class ThreadAtExitCallbackMgr { static LIBC_THREAD_LOCAL ThreadAtExitCallbackMgr atexit_callback_mgr; -// The function __cxa_thread_atexit is provided by C++ runtimes like libcxxabi. -// It is used by thread local object runtime to register destructor calls. To -// actually register destructor call with the threading library, it calls -// __cxa_thread_atexit_impl, which is to be provided by the threading library. -// The semantics are very similar to the __cxa_atexit function except for the -// fact that the registered callback is thread specific. -extern "C" int __cxa_thread_atexit_impl(AtExitCallback *callback, void *obj, - void *) { +int add_thread_atexit_callback(AtExitCallback *callback, void *obj) { return atexit_callback_mgr.add_callback(callback, obj); } - namespace internal { void call_atexit_callbacks() { + // Cancellation cleanup handlers (pthread_cleanup_push). + __pthread_cleanup_frame *frame; + while ((frame = current_thread().attrib->cleanup_stack.pop()) != nullptr) + frame->__routine(frame->__arg); + + // thread exit callbacks (__cxa_thread_atexit). atexit_callback_mgr.call(); - for (size_t i = 0; i < TSS_KEY_COUNT; ++i) { - TSSValueUnit &unit = tss_values[i]; - // Both dtor and value need to nonnull to call dtor - if (unit.dtor != nullptr && unit.payload != nullptr) - unit.dtor(unit.payload); + + // Thread-specific keys (pthread_key_create). + for (size_t iter = 0; iter < PTHREAD_DESTRUCTOR_ITERATIONS; ++iter) { + bool called_dtor = false; + for (TSSValueUnit &unit : tss_values) { + // Both dtor and value need to be nonnull to call dtor + if (unit.dtor == nullptr || unit.payload == nullptr) + continue; + + void *val = unit.payload; + unit.payload = nullptr; + unit.dtor(val); + called_dtor = true; + } + if (!called_dtor) + break; } } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.h b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.h index 9971dc5f193a..afb18af39cd1 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread.h @@ -1,10 +1,15 @@ -//===--- A platform independent indirection for a thread class --*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +/// +/// \file +/// Platform-independent indirection for a thread class. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H #define LLVM_LIBC_SRC___SUPPORT_THREADS_THREAD_H @@ -137,7 +142,9 @@ struct Thread { void wait(); // Return true if this thread is equal to the other thread. - bool operator==(const Thread &other) const; + constexpr bool operator==(const Thread &other) const { + return attrib == other.attrib; + } // Set the name of the thread. Return the error number on error. int set_name(const cpp::string_view &name); @@ -170,6 +177,10 @@ void call_atexit_callbacks(); } // namespace internal +using AtExitCallback = void(void *); + +int add_thread_atexit_callback(AtExitCallback *callback, void *obj); + LIBC_INLINE Thread current_thread() { return Thread(get_current_thread_attrib()); } diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread_attributes.h b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread_attributes.h index 123b0d2a6c8c..bffdbc616ccb 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread_attributes.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/threads/thread_attributes.h @@ -20,6 +20,7 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/architectures.h" +#include "src/__support/threads/cleanup_stack.h" namespace LIBC_NAMESPACE_DECL { @@ -105,6 +106,7 @@ struct alignas(STACK_ALIGNMENT) ThreadAttributes { ThreadReturnValue retval; void *platform_data; cpp::Atomic<ThreadAttributes *> joiner; + CleanupStack cleanup_stack; LIBC_INLINE constexpr ThreadAttributes() : detach_state(uint32_t(DetachState::DETACHED)), stack(nullptr), diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/time/gpu/CMakeLists.txt b/deps/v8/third_party/llvm-libc/src/src/__support/time/gpu/CMakeLists.txt index fc465e0cea25..a15a9d26dc03 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/time/gpu/CMakeLists.txt +++ b/deps/v8/third_party/llvm-libc/src/src/__support/time/gpu/CMakeLists.txt @@ -7,6 +7,7 @@ add_object_library( DEPENDS libc.hdr.types.clock_t libc.hdr.time_macros + libc.src.__support.GPU.utils ) add_object_library( diff --git a/deps/v8/third_party/llvm-libc/src/src/__support/tlsf_table.h b/deps/v8/third_party/llvm-libc/src/src/__support/tlsf_table.h index e75f1074ca4b..906b75a32cd0 100644 --- a/deps/v8/third_party/llvm-libc/src/src/__support/tlsf_table.h +++ b/deps/v8/third_party/llvm-libc/src/src/__support/tlsf_table.h @@ -148,6 +148,13 @@ template <typename CONFIG> class TLSFTable { lookup_table[entry_index] &= ~(uintptr_t(1) << bit_offset); } + LIBC_INLINE bool empty() const { + for (uintptr_t entry : lookup_table) + if (entry != 0) + return false; + return true; + } + LIBC_INLINE bool is_occupied(size_t bin) const { size_t entry_index = bin / BITS_PER_ENTRY; size_t bit_offset = bin % BITS_PER_ENTRY; diff --git a/deps/v8/third_party/zlib/chromeconf.h b/deps/v8/third_party/zlib/chromeconf.h index c713e2119b44..e59a89966eb6 100644 --- a/deps/v8/third_party/zlib/chromeconf.h +++ b/deps/v8/third_party/zlib/chromeconf.h @@ -196,6 +196,7 @@ /* Symbols added by crc32_simd.c */ #define crc32_sse42_simd_ Cr_z_crc32_sse42_simd_ +#define crc32_avx512_simd_ Cr_z_crc32_avx512_simd_ /* Symbols added by armv8_crc32 */ #define arm_cpu_enable_crc32 Cr_z_arm_cpu_enable_crc32 diff --git a/deps/v8/third_party/zlib/contrib/optimizations/inffast_chunk.c b/deps/v8/third_party/zlib/contrib/optimizations/inffast_chunk.c index 3c93da05114d..c0c7e8977d68 100644 --- a/deps/v8/third_party/zlib/contrib/optimizations/inffast_chunk.c +++ b/deps/v8/third_party/zlib/contrib/optimizations/inffast_chunk.c @@ -132,12 +132,14 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { } while (0) #endif +#ifdef INFLATE_CHUNK_READ_64LE + REFILL(); +#endif + /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { -#ifdef INFLATE_CHUNK_READ_64LE - REFILL(); -#else +#ifndef INFLATE_CHUNK_READ_64LE if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; @@ -145,15 +147,20 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { bits += 8; } #endif + /* Worst case: previous iteration had 3 literals (56 - 20 (lits) - 15 (lit) = 21 bits) + or a match (56 - 15 (dist) - 13 (extra) = 28 bits), leaving bits >= lenbits (<= 10). */ + Assert(bits >= state->lenbits, "inflate_fast: short lit/len index"); here = lcode + (hold & lmask); #ifdef INFLATE_CHUNK_READ_64LE - if (here->op == 0) { /* literal */ + REFILL(); + if (here->op == 0) { /* literal */ Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here->val)); *out++ = (unsigned char)(here->val); hold >>= here->bits; bits -= here->bits; + Assert(bits >= state->lenbits, "inflate_fast: short 2nd lit/len index"); here = lcode + (hold & lmask); if (here->op == 0) { /* literal */ Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? @@ -162,6 +169,7 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { *out++ = (unsigned char)(here->val); hold >>= here->bits; bits -= here->bits; + Assert(bits >= state->lenbits, "inflate_fast: short 3rd lit/len index"); here = lcode + (hold & lmask); } } @@ -187,6 +195,7 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { bits += 8; } #endif + Assert(bits >= op, "inflate_fast: short length extra bits"); len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; @@ -200,7 +209,14 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { bits += 8; } #endif + /* Worst case: 56 - 20 (lits) - 15 (len) - 5 (extra) = 16 bits remain for distbits <= 9. */ + Assert(bits >= state->distbits, "inflate_fast: short dist index"); here = dcode + (hold & dmask); +#ifdef INFLATE_CHUNK_READ_64LE + /* Refill after the table load so the two can overlap, and so the + distance code and its extra bits start from a full 56 bits. */ + REFILL(); +#endif dodist: op = (unsigned)(here->bits); hold >>= op; @@ -209,20 +225,17 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { if (op & 16) { /* distance base */ dist = (unsigned)(here->val); op &= 15; /* number of extra bits */ - /* we have two fast-path loads: 10+10 + 15+5 + 15 = 55, - but we may need to refill here in the worst case */ +#ifndef INFLATE_CHUNK_READ_64LE if (bits < op) { -#ifdef INFLATE_CHUNK_READ_64LE - REFILL(); -#else hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } -#endif } +#endif + Assert(bits >= op, "inflate_fast: short distance extra bits"); dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { @@ -313,6 +326,7 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { } } else if ((op & 64) == 0) { /* 2nd level distance code */ + Assert(bits >= op, "inflate_fast: short 2nd level dist index"); here = dcode + here->val + (hold & ((1U << op) - 1)); goto dodist; } @@ -323,6 +337,7 @@ void ZLIB_INTERNAL inflate_fast_chunk_(z_streamp strm, unsigned start) { } } else if ((op & 64) == 0) { /* 2nd level length code */ + Assert(bits >= op, "inflate_fast: short 2nd level lit/len index"); here = lcode + here->val + (hold & ((1U << op) - 1)); goto dolen; } diff --git a/deps/v8/tools/clusterfuzz/foozzie/BUILD.gn b/deps/v8/tools/clusterfuzz/foozzie/BUILD.gn index 90113e5aa4f5..911b2f4ecb26 100644 --- a/deps/v8/tools/clusterfuzz/foozzie/BUILD.gn +++ b/deps/v8/tools/clusterfuzz/foozzie/BUILD.gn @@ -12,7 +12,9 @@ if (v8_correctness_fuzzer) { "v8_foozzie_harness_adjust.js", "v8_fuzz_config.py", "v8_fuzz_experiments.json", + "v8_fuzz_experiments_regexp.json", "v8_fuzz_flags.json", + "v8_fuzz_flags_regexp.json", "v8_mock.js", "v8_mock_archs.js", "v8_mock_webassembly.js", diff --git a/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_arch.txt b/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_arch.txt index b87ab07321f3..b4ad7986493f 100644 --- a/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_arch.txt +++ b/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_arch.txt @@ -8,7 +8,7 @@ # Compared x64 with x64 # # Common flags: ---correctness-fuzzer-suppressions --expose-gc --fuzzing --allow-natives-for-differential-fuzzing --invoke-weak-callbacks --omit-quit --harmony --experimental-fuzzing --js-staging --wasm-staging --wasm-num-compilation-tasks=0 --wasm-max-mem-pages=32767 --suppress-asm-messages --random-seed 12345 +--correctness-fuzzer-suppressions --expose-gc --fuzzing --allow-natives-for-differential-fuzzing --invoke-weak-callbacks --omit-quit --harmony --experimental-fuzzing --js-staging --wasm-staging --wasm-num-compilation-tasks=0 --wasm-max-mem-pages=32767 --suppress-asm-messages --correctness-fuzzer-cross-arch-suppressions --random-seed 12345 # Baseline flags: --turbo-filter=~ --no-turbofan --no-sparkplug --liftoff-only --no-wasm-tier-up --no-maglev # Comparison flags: diff --git a/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_second.txt b/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_second.txt index 10a942fe043c..821e570f4307 100644 --- a/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_second.txt +++ b/deps/v8/tools/clusterfuzz/foozzie/testdata/failure_output_second.txt @@ -8,7 +8,7 @@ # Compared x64 with ia32 # # Common flags: ---correctness-fuzzer-suppressions --expose-gc --fuzzing --allow-natives-for-differential-fuzzing --invoke-weak-callbacks --omit-quit --harmony --experimental-fuzzing --js-staging --wasm-staging --wasm-num-compilation-tasks=0 --wasm-max-mem-pages=32767 --suppress-asm-messages --random-seed 12345 +--correctness-fuzzer-suppressions --expose-gc --fuzzing --allow-natives-for-differential-fuzzing --invoke-weak-callbacks --omit-quit --harmony --experimental-fuzzing --js-staging --wasm-staging --wasm-num-compilation-tasks=0 --wasm-max-mem-pages=32767 --suppress-asm-messages --correctness-fuzzer-cross-arch-suppressions --random-seed 12345 # Baseline flags: --turbo-filter=~ --no-turbofan --no-sparkplug --liftoff-only --no-wasm-tier-up --no-maglev # Comparison flags: diff --git a/deps/v8/tools/clusterfuzz/foozzie/v8_commands.py b/deps/v8/tools/clusterfuzz/foozzie/v8_commands.py index be5f521f9b8c..dd8bf641369c 100644 --- a/deps/v8/tools/clusterfuzz/foozzie/v8_commands.py +++ b/deps/v8/tools/clusterfuzz/foozzie/v8_commands.py @@ -86,6 +86,8 @@ def __init__(self, options, label, executable, config_flags): self.executable = executable self.config_flags = config_flags self.common_flags = DEFAULT_FLAGS[:] + if options.first.arch != options.second.arch: + self.common_flags.append('--correctness-fuzzer-cross-arch-suppressions') self.common_flags.extend(['--random-seed', str(options.random_seed)]) self.files = _startup_files(options) diff --git a/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie.py b/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie.py index 359c04a8a1d7..ab2bedcd111a 100755 --- a/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie.py +++ b/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie.py @@ -142,10 +142,14 @@ FUZZ_TEST_RE = re.compile(r'.*fuzz(-\d+\.js)') -# The number of hex digits used from the hash of the original source file path. +# The number of hex digits used from the hash of the original source label. # Keep the number small to avoid duplicate explosion. SOURCE_HASH_LENGTH = 2 +# Keep regexp-fuzzer failures in a distinct ClusterFuzz key namespace. +REGEXP_FUZZER_SOURCE_PREFIX = 'regexp-fuzzer:' +REGEXP_FUZZER_KEY_PREFIX = 'regexp-' + # Placeholder string if no original source file could be determined. ORIGINAL_SOURCE_DEFAULT = 'none' @@ -189,9 +193,6 @@ '--expose-statistics', '--log', '--rcs', - - # https://crbug.com/430624025 - '--flush-denormals', ] # The same as above, but prefixes that either match multiple flags or flags @@ -443,7 +444,7 @@ def cluster_failures(source, known_failures=None): """Returns a string key for clustering duplicate failures. Args: - source: The original source path where the failure happened. + source: The source label preceding the failure. known_failures: Mapping from original source path to failure key. """ known_failures = known_failures or KNOWN_FAILURES @@ -463,8 +464,11 @@ def cluster_failures(source, known_failures=None): return 'smoke test failed' # We map all remaining failures to a short hash of the original source. + key_prefix = ( + REGEXP_FUZZER_KEY_PREFIX + if source.startswith(REGEXP_FUZZER_SOURCE_PREFIX) else '') long_key = hashlib.sha1(source.encode('utf-8')).hexdigest() - return long_key[:SOURCE_HASH_LENGTH] + return key_prefix + long_key[:SOURCE_HASH_LENGTH] class RepeatedRuns(object): diff --git a/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie_test.py b/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie_test.py index 95c9b685f030..b190775502c1 100755 --- a/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie_test.py +++ b/deps/v8/tools/clusterfuzz/foozzie/v8_foozzie_test.py @@ -3,6 +3,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import json import os import random import re @@ -38,34 +39,46 @@ def output(stdout, is_crash): exit_code=exit_code, stdout_bytes=stdout.encode('utf-8'), pid=0) +def load_json(filename): + with (BASE_DIR / filename).open() as f: + return json.load(f) + + +# Tables read by other fuzzers from the build directory, e.g. by +# tools/regexp/correctness_fuzzer/run.py. Checked for integrity like ours. +FUZZER_EXPERIMENTS = [load_json('v8_fuzz_experiments_regexp.json')] +FUZZER_ADDITIONAL_FLAGS = [load_json('v8_fuzz_flags_regexp.json')] + + class ConfigTest(unittest.TestCase): def testExperiments(self): - """Test integrity of probabilities and configs.""" + """Test integrity of probabilities and configs, for every table.""" CONFIGS = v8_foozzie.CONFIGS - EXPERIMENTS = v8_fuzz_config.FOOZZIE_EXPERIMENTS - FLAGS = v8_fuzz_config.ADDITIONAL_FLAGS - # Probabilities add up to 100%. - first_is_int = lambda x: type(x[0]) == int - assert all(map(first_is_int, EXPERIMENTS)) - assert sum(x[0] for x in EXPERIMENTS) == 100 - # Configs used in experiments are defined. - assert all(map(lambda x: x[1] in CONFIGS, EXPERIMENTS)) - assert all(map(lambda x: x[2] in CONFIGS, EXPERIMENTS)) - # The last config item points to a known build configuration. - assert all(map(lambda x: x[3] in KNOWN_BUILDS, EXPERIMENTS)) - # All flags have a probability. - first_is_float = lambda x: type(x[0]) == float - assert all(map(first_is_float, FLAGS)) - first_between_0_and_1 = lambda x: x[0] > 0 and x[0] < 1 - assert all(map(first_between_0_and_1, FLAGS)) - # Test consistent flags. - second_is_string = lambda x: isinstance(x[1], str) - assert all(map(second_is_string, FLAGS)) - # We allow spaces to separate more flags. We don't allow spaces in the flag - # value. - is_flag = lambda x: x.startswith('--') - all_parts_are_flags = lambda x: all(map(is_flag, x[1].split())) - assert all(map(all_parts_are_flags, FLAGS)) + for EXPERIMENTS in ([v8_fuzz_config.FOOZZIE_EXPERIMENTS] + + FUZZER_EXPERIMENTS): + # Probabilities add up to 100%. + first_is_int = lambda x: type(x[0]) == int + assert all(map(first_is_int, EXPERIMENTS)) + assert sum(x[0] for x in EXPERIMENTS) == 100 + # Configs used in experiments are defined. + assert all(map(lambda x: x[1] in CONFIGS, EXPERIMENTS)) + assert all(map(lambda x: x[2] in CONFIGS, EXPERIMENTS)) + # The last config item points to a known build configuration. + assert all(map(lambda x: x[3] in KNOWN_BUILDS, EXPERIMENTS)) + for FLAGS in ([v8_fuzz_config.ADDITIONAL_FLAGS] + FUZZER_ADDITIONAL_FLAGS): + # All flags have a probability. + first_is_float = lambda x: type(x[0]) == float + assert all(map(first_is_float, FLAGS)) + first_between_0_and_1 = lambda x: x[0] > 0 and x[0] < 1 + assert all(map(first_between_0_and_1, FLAGS)) + # Test consistent flags. + second_is_string = lambda x: isinstance(x[1], str) + assert all(map(second_is_string, FLAGS)) + # We allow spaces to separate more flags. We don't allow spaces in the + # flag value. + is_flag = lambda x: x.startswith('--') + all_parts_are_flags = lambda x: all(map(is_flag, x[1].split())) + assert all(map(all_parts_are_flags, FLAGS)) def testConfig(self): """Smoke test how to choose experiments.""" @@ -117,6 +130,8 @@ def testCluster(self): self.assertEqual( '98', v8_foozzie.cluster_failures('v8/test/mjsunit/apply.js')) + self.assertEqual('regexp-42', + v8_foozzie.cluster_failures('regexp-fuzzer:gi/()+|\\d')) def testDiff(self): def diff_fun(one, two, skip=False): diff --git a/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_experiments_regexp.json b/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_experiments_regexp.json new file mode 100644 index 000000000000..9c52399a0611 --- /dev/null +++ b/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_experiments_regexp.json @@ -0,0 +1,6 @@ +[ + [40, "jitless", "slow_path", "d8"], + [30, "jitless", "slow_path", "clang_x64_v8_arm64/d8"], + [15, "jitless", "slow_path", "clang_x86_v8_arm/d8"], + [15, "jitless", "slow_path", "clang_x86/d8"] +] diff --git a/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags.json b/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags.json index 048f8a835bc4..796546ef0620 100644 --- a/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags.json +++ b/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags.json @@ -47,7 +47,6 @@ [0.1, "--maglev-disable-builtin-reducers"], [0.0001, "--simulate-errors"], [0.1, "--minor-ms"], - [0.1, "--shared-string-table"], [0.1, "--shared-heap"], [0.1, "--stress-wasm-memory-moving"], [0.05, "--stress-maglev"], diff --git a/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags_regexp.json b/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags_regexp.json new file mode 100644 index 000000000000..180a2722bff7 --- /dev/null +++ b/deps/v8/tools/clusterfuzz/foozzie/v8_fuzz_flags_regexp.json @@ -0,0 +1,11 @@ +[ + [0.2, "--regexp-tier-up-ticks=1"], + [0.2, "--no-regexp-optimization"], + [0.2, "--no-regexp-atomic-loop"], + [0.2, "--no-regexp-quick-check"], + [0.2, "--no-regexp-masked-dispatch"], + [0.2, "--no-regexp-unroll"], + [0.2, "--no-regexp-peephole-optimization"], + [0.15, "--regexp-assemble-from-bytecode"], + [0.1, "--no-enable-regexp-unaligned-accesses"] +] diff --git a/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js b/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js index ba540912ea13..80af51fd1b6f 100644 --- a/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js +++ b/deps/v8/tools/clusterfuzz/js_fuzzer/exceptions.js @@ -175,6 +175,7 @@ const DISALLOWED_FLAGS = [ // Disallowed due to false positives. '--check-handle-count', + '--enable-inspector', '--expose-debug-as', '--expose-natives-as', '--mock-arraybuffer-allocator', diff --git a/deps/v8/tools/clusterfuzz/trials/clusterfuzz_trials_config.json b/deps/v8/tools/clusterfuzz/trials/clusterfuzz_trials_config.json index b6d05d29d6bf..9f508a0a656f 100644 --- a/deps/v8/tools/clusterfuzz/trials/clusterfuzz_trials_config.json +++ b/deps/v8/tools/clusterfuzz/trials/clusterfuzz_trials_config.json @@ -8,7 +8,6 @@ {"app_args": "--force-slow-path", "app_name": "d8", "probability": 0.05}, {"app_args": "--future", "app_name": "d8", "probability": 0.25}, {"app_args": "--harmony", "app_name": "d8", "probability": 0.5}, - {"app_args": "--harmony-struct", "app_name": "d8", "probability": 0.1}, {"app_args": "--hashes-collide", "app_name": "d8", "probability": 0.1}, {"app_args": "--jit-fuzzing", "app_name": "d8", "probability": 0.25}, {"app_args": "--jitless", "app_name": "d8", "probability": 0.1, "contradicts": ["--maglev-future", "--stress-concurrent-inlining", "--stress-concurrent-inlining-attach-code", "--stress-maglev"]}, @@ -50,7 +49,6 @@ {"app_args": "--regexp-tier-up-ticks=100", "app_name": "d8", "probability": 0.1}, {"app_args": "--no-regexp-quick-check", "app_name": "d8", "probability": 0.1}, {"app_args": "--no-regexp-unroll", "app_name": "d8", "probability": 0.1}, - {"app_args": "--shared-string-table", "app_name": "d8", "probability": 0.1}, {"app_args": "--shared-heap", "app_name": "d8", "probability": 0.1}, {"app_args": "--simulate-errors", "app_name": "d8", "probability": 0.001}, {"app_args": "--stress-compaction-random", "app_name": "d8", "probability": 0.05}, diff --git a/deps/v8/tools/compare-checked-in-headers.py b/deps/v8/tools/compare-checked-in-headers.py new file mode 100644 index 000000000000..a803c684594c --- /dev/null +++ b/deps/v8/tools/compare-checked-in-headers.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Build action behind the checked-in generated headers in src/gen/. + + compare-checked-in-headers.py (--verify | --update) --stamp STAMP + --pair GENERATED=CHECKED_IN ... + +Not meant to be run by hand; BUILD.gn invokes it after the generators, +with one --pair per checked-in header, as two targets: + + verify_checked_in_generated_headers (--verify) + Fails if any GENERATED file differs from its CHECKED_IN copy and + prints the regeneration command. Every build depends on it. + regen_checked_in_generated_headers (--update) + Overwrites each CHECKED_IN copy that differs. Nothing depends on + it; tools/dev/gen-checked-in-headers.py (`gm.py gen-checked-in-headers`) + builds it to regenerate. + +Both touch STAMP on success. See src/gen/README.md. +""" + +import argparse +import difflib +import itertools +import pathlib +import sys + +parser = argparse.ArgumentParser(allow_abbrev=False) +mode = parser.add_mutually_exclusive_group(required=True) +mode.add_argument( + '--verify', + action='store_true', + help='fail if any checked-in copy differs from the generated file') +mode.add_argument( + '--update', + action='store_true', + help='copy generated files over the checked-in copies') +parser.add_argument('--stamp', required=True, help='stamp file to touch') +parser.add_argument( + '--regen-cmd', + default='tools/dev/gm.py gen-checked-in-headers', + help='regeneration command named in the error message') +parser.add_argument( + '--pair', action='append', default=[], metavar='GENERATED=CHECKED_IN') +args = parser.parse_args() + +pairs = [pair.split('=', 1) for pair in args.pair] + + +def contents(path): + """The file contents as they should be checked in. The generators write + in text mode, so on Windows the files have CRLF line endings, while the + checked-in copies have LF (.gitattributes sets LF for the whole tree).""" + return pathlib.Path(path).read_bytes().replace(b'\r\n', b'\n') + + +def matches(generated, checked_in): + path = pathlib.Path(checked_in) + return path.exists() and path.read_bytes() == contents(generated) + + +# Usually only a few lines differ, and the diff shows which. Cap it so +# that a completely different file does not fill the build log. +DIFF_LINES = 40 + + +def diff(generated, checked_in): + + def lines(path): + if not pathlib.Path(path).exists(): + return [] + return contents(path).decode('utf-8', 'replace').splitlines(keepends=True) + + delta = difflib.unified_diff( + lines(checked_in), + lines(generated), + fromfile=checked_in, + tofile=generated) + head = list(itertools.islice(delta, DIFF_LINES)) + if next(delta, None) is not None: + head.append(f'[... truncated after {DIFF_LINES} lines]\n') + return ''.join(head) + + +if args.update: + for generated, checked_in in pairs: + if not matches(generated, checked_in): + pathlib.Path(checked_in).write_bytes(contents(generated)) + print(f'Updated {checked_in}') +else: + stale = [(g, c) for g, c in pairs if not matches(g, c)] + if stale: + for generated, checked_in in stale: + print( + f'Checked-in generated file is out of date: {checked_in}', + file=sys.stderr) + print(diff(generated, checked_in), end='', file=sys.stderr) + print( + f'Run `{args.regen_cmd}` and commit the result. This also happens ' + 'when main has changed the generated headers since you last ' + 'regenerated, e.g. on the CQ: rebase first.', + file=sys.stderr) + print( + 'If this build sets GN args that change the generated headers, add ' + 'them to the v8_use_checked_in_generated_headers condition in ' + 'BUILD.gn instead: see src/gen/README.md.', + file=sys.stderr) + sys.exit(1) + +pathlib.Path(args.stamp).touch() diff --git a/deps/v8/tools/debug_helper/BUILD.gn b/deps/v8/tools/debug_helper/BUILD.gn index 887990544f97..55e38558de39 100644 --- a/deps/v8/tools/debug_helper/BUILD.gn +++ b/deps/v8/tools/debug_helper/BUILD.gn @@ -98,9 +98,9 @@ _debug_helper_deps = [ "../..:v8_shared_internal_headers", "../..:v8_tracing", ] -if (v8_use_metagen_instance_types) { +if (v8_use_metagen) { _debug_helper_sources += [ "$target_gen_dir/../../metagen/instance-types.h" ] - _debug_helper_deps += [ "../..:metagen_instance_types_h" ] + _debug_helper_deps += [ "../..:run_metagen" ] } if (v8_enable_temporal_support) { _debug_helper_deps += [ "//third_party/rust/temporal_capi" ] diff --git a/deps/v8/tools/debug_helper/get-object-properties.cc b/deps/v8/tools/debug_helper/get-object-properties.cc index e962095ab434..721df7cf55d3 100644 --- a/deps/v8/tools/debug_helper/get-object-properties.cc +++ b/deps/v8/tools/debug_helper/get-object-properties.cc @@ -11,6 +11,7 @@ #include "src/execution/frame-constants.h" #include "src/execution/frames.h" #include "src/execution/isolate-utils.h" +#include "src/objects/scope-info.h" #include "src/objects/string-inl.h" #include "src/sandbox/external-pointer.h" #include "src/strings/unicode-inl.h" @@ -31,7 +32,8 @@ constexpr char kObjectAsStoredInHeap[] = std::string AppendAddressAndType(const std::string& brief, uintptr_t address, const char* type) { std::stringstream brief_stream; - brief_stream << "0x" << std::hex << address << " <" << type << ">"; + brief_stream << "0x" << std::hex << address << std::dec << " <" << type + << ">"; return brief.empty() ? brief_stream.str() : brief + " (" + brief_stream.str() + ")"; } @@ -724,7 +726,7 @@ std::unique_ptr<ObjectPropertiesResult> GetObjectProperties( // untagged value. int32_t value = i::PlatformSmiTagging::SmiToInt(address); std::stringstream stream; - stream << value << " (0x" << std::hex << value << ")"; + stream << value << " (0x" << std::hex << value << std::dec << ")"; return std::make_unique<ObjectPropertiesResult>(d::TypeCheckResult::kSmi, stream.str(), kSmi); } @@ -792,19 +794,39 @@ std::unique_ptr<StackFrameResult> GetStackFrame( if (IsTypedHeapObjectInstanceTypeOf( scope_info_address, memory_accessor, i::InstanceType::SCOPE_INFO_TYPE)) { - auto indexed_field_slice_function_variable_info = - TqDebugFieldSliceScopeInfoFunctionVariableInfo( - memory_accessor, scope_info_address); - if (indexed_field_slice_function_variable_info.validity == - d::MemoryAccessResult::kOk) { + TqScopeInfo scope_info(scope_info_address); + // Torque only models the fixed ScopeInfo header; locate the + // function_variable_info section by hand, mirroring + // ScopeInfo::FunctionVariableInfoOffset. + auto flags = scope_info.GetFlagsValue(memory_accessor); + auto context_local_count = + scope_info.GetContextLocalCountValue(memory_accessor); + if (flags.validity == d::MemoryAccessResult::kOk && + context_local_count.validity == d::MemoryAccessResult::kOk) { + const int local_count = + i::PlatformSmiTagging::SmiToInt(context_local_count.value); + const bool is_module = + i::ScopeInfo::Flags::ScopeTypeBits::decode(flags.value) == + i::ScopeType::MODULE_SCOPE; + const bool has_hashtable = + local_count >= i::kScopeInfoMaxInlinedLocalNamesSize; + const bool has_saved_class_variable = + i::ScopeInfo::Flags::HasSavedClassVariableBit::decode( + flags.value); + const bool has_function_variable = + i::ScopeInfo::Flags::FunctionVariableBits::decode( + flags.value) != i::VariableAllocationInfo::NONE; + const int preceding_slots = + (is_module ? 1 : 0) + (has_hashtable ? 1 : local_count) + + local_count + (has_saved_class_variable ? 1 : 0); + const uintptr_t function_variable_info_offset = + OFFSET_OF_DATA_START(i::ScopeInfo) + + preceding_slots * i::kTaggedSize; props.push_back(std::make_unique<ObjectProperty>( "function_name", kObjectAsStoredInHeap, scope_info_address - i::kHeapObjectTag + - std::get<1>( - indexed_field_slice_function_variable_info.value), - std::get<2>( - indexed_field_slice_function_variable_info.value), - i::kTaggedSize, + function_variable_info_offset, + has_function_variable ? 1 : 0, i::kTaggedSize, std::vector<std::unique_ptr<StructProperty>>(), d::PropertyKind::kSingle)); } @@ -816,7 +838,6 @@ std::unique_ptr<StackFrameResult> GetStackFrame( position_info_struct_field_list.push_back( std::make_unique<StructProperty>("end", kObjectAsStoredInHeap, 4, 0, 0)); - TqScopeInfo scope_info(scope_info_address); props.push_back(std::make_unique<ObjectProperty>( "function_character_offset", "", scope_info.GetPositionInfoAddress(), 1, 2 * i::kTaggedSize, @@ -826,6 +847,49 @@ std::unique_ptr<StackFrameResult> GetStackFrame( } } } + + // The receiver and the arguments are the caller's outgoing stack slots + // right above the return address. The slots hold uncompressed pointers + // even on pointer-compressed builds, so report them as Tagged values + // with the system pointer size. + props.push_back(std::make_unique<ObjectProperty>( + "receiver", + CheckTypeName<v8::internal::Tagged<v8::internal::Object>>( + "v8::internal::Tagged<v8::internal::Object>"), + frame_pointer + StandardFrameConstants::kCallerSPOffset, 1, + i::kSystemPointerSize, std::vector<std::unique_ptr<StructProperty>>(), + d::PropertyKind::kSingle)); + + // The argc slot counts the receiver. Report the user-visible arguments + // as an array. If the slot is unreadable or the count is out of range, + // report an array of unknown size so debug tools can still show the + // base address. + intptr_t argc = 0; + size_t argument_count = 0; + d::PropertyKind arguments_kind = + d::PropertyKind::kArrayOfUnknownSizeDueToInvalidMemory; + d::MemoryAccessResult argc_validity = + memory_accessor(frame_pointer + StandardFrameConstants::kArgCOffset, + reinterpret_cast<void*>(&argc), sizeof(intptr_t)); + if (argc_validity == d::MemoryAccessResult::kOk) { + intptr_t user_argc = argc - i::kJSArgcReceiverSlots; + if (user_argc >= 0 && user_argc <= i::Code::kMaxArguments) { + argument_count = static_cast<size_t>(user_argc); + arguments_kind = d::PropertyKind::kArrayOfKnownSize; + } + } else if (argc_validity == + d::MemoryAccessResult::kAddressValidButInaccessible) { + arguments_kind = + d::PropertyKind::kArrayOfUnknownSizeDueToValidButInaccessibleMemory; + } + props.push_back(std::make_unique<ObjectProperty>( + "arguments", + CheckTypeName<v8::internal::Tagged<v8::internal::Object>>( + "v8::internal::Tagged<v8::internal::Object>"), + frame_pointer + StandardFrameConstants::kCallerSPOffset + + i::kSystemPointerSize, + argument_count, i::kSystemPointerSize, + std::vector<std::unique_ptr<StructProperty>>(), arguments_kind)); } } diff --git a/deps/v8/tools/debug_helper/plugins/Makefile b/deps/v8/tools/debug_helper/plugins/Makefile index 30f2d3aa37c3..d1d1f645343f 100644 --- a/deps/v8/tools/debug_helper/plugins/Makefile +++ b/deps/v8/tools/debug_helper/plugins/Makefile @@ -18,6 +18,7 @@ TEST_DIR ?= ./test FIXTURES_DIR ?= $(TEST_DIR)/fixtures BACKTRACE_SCRIPT ?= $(FIXTURES_DIR)/throw.js INSPECT_SCRIPT ?= $(FIXTURES_DIR)/inspect-fixture.js +ARGS_MISMATCH_SCRIPT ?= $(FIXTURES_DIR)/args-mismatch.js CORRUPTION_SCRIPT ?= $(FIXTURES_DIR)/invalid-script-source.js # d8 enables --sandbox-prohibit-insecure-mode on macOS/Linux, which makes # sandbox initialization abort with a fatal OOM when launched under a debugger @@ -30,6 +31,7 @@ TEST_PACKAGE ?= test CORE_DIR ?= $(OUT_DIR)/debug_helper.cores BACKTRACE_CORE ?= $(CORE_DIR)/throw.core INSPECT_CORE ?= $(CORE_DIR)/inspect-fixture.core +ARGS_MISMATCH_CORE ?= $(CORE_DIR)/args-mismatch.core CORRUPTION_CORE ?= $(CORE_DIR)/$(basename $(notdir $(CORRUPTION_SCRIPT))).core CORRUPTION_CORE_CASES := invalid-script-source invalid-shared-function-info corrupted-map CORRUPTION_CORES := $(foreach case,$(CORRUPTION_CORE_CASES),$(CORE_DIR)/$(case).core) @@ -144,6 +146,9 @@ $(BACKTRACE_CORE): $(BACKTRACE_SCRIPT) $(D8) $(INSPECT_CORE): $(INSPECT_SCRIPT) $(D8) $(call generate_core,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(INSPECT_SCRIPT))",$(abspath $@)) +$(ARGS_MISMATCH_CORE): $(ARGS_MISMATCH_SCRIPT) $(D8) + $(call generate_core,$(abspath $(D8)),$(D8_ARGS) --abort-on-uncaught-exception "$(abspath $(ARGS_MISMATCH_SCRIPT))",$(abspath $@)) + # The corruption cores depend on the harness binary too, so they get # regenerated whenever the harness changes. $(CORE_DIR)/%.core: $(FIXTURES_DIR)/%.js $(CORRUPTION_BIN) @@ -183,7 +188,7 @@ run-core-corruption-lldb: $(CORRUPTION_CORE) run-core: run-core-gdb run-core-lldb -prepare-cores: $(BACKTRACE_CORE) $(INSPECT_CORE) $(CORRUPTION_CORES) +prepare-cores: $(BACKTRACE_CORE) $(INSPECT_CORE) $(ARGS_MISMATCH_CORE) $(CORRUPTION_CORES) clean-cores: rm -rf "$(CORE_DIR)" diff --git a/deps/v8/tools/debug_helper/plugins/README.md b/deps/v8/tools/debug_helper/plugins/README.md index b293853135c8..a4c4a028f73d 100644 --- a/deps/v8/tools/debug_helper/plugins/README.md +++ b/deps/v8/tools/debug_helper/plugins/README.md @@ -45,7 +45,8 @@ Once loaded, the plugins append JavaScript annotations to candidate V8 frames when you print a backtrace via `bt`, and adds a `v8` command. Currently, `v8` supports the following subcommands: ``` -v8 inspect <addr> [--type T] [--depth N] [--array-length N] +v8 inspect <addr>|this|[N] [--type T] [--depth N] [--array-length N] +v8 args [frame#] v8 isolate v8 source [frame#] [--max-lines N] ``` @@ -55,12 +56,14 @@ v8 source [frame#] [--max-lines N] The annotation format for frames displayed in `bt` is: ``` -[<function_name> @ <script_name>:<line>:<column>] (this=0xADDR, argc=N) +[<function_name> @ <script_name>:<line>:<column>] (this=0x..., [0]=<Smi: 1>, ...) ``` -The trailing `(this=0xADDR, argc=N)` shows the receiver tagged-pointer and -argument count for the JS frame. If the frame's slots are unreadable, the -trailer is dropped. +The annotation shows the receiver and a preview of the first few +arguments, labeled positionally as `[N]`. To see the full list +of arguments, use `v8 args <frame#>`. If the argument count is +unreadable, the annotation is `(this=0x..., argc=?)`. +If the receiver slot is unreadable, it will be omitted. If source text cannot be recovered but the script name still can, the annotation degrades to: @@ -75,9 +78,11 @@ normally the `(` of the parameter list (or position 1:1 for the top-level script scope), not where the function is called, which we cannot reliably recover in the debugger. -#### `v8 inspect <addr>` +#### `v8 inspect <addr>|this|[N]` -Inspects a tagged V8 object at `<addr>` and prints its properties. +Inspects a tagged V8 object at `<addr>` and prints its properties. Instead of +an address, `this` and `[N]` refer to the receiver or the Nth argument of the +selected JS frame. ``` (gdb) v8 inspect 0x34f49880471 @@ -99,6 +104,21 @@ Options: When the object's Map can't be read (e.g. due to memory corruption), the renderer adds a `could be one of ...` footer with ready-to-paste `--type` suggestions. +#### `v8 args [frame#]` + +Prints the receiver and all the arguments of a JS frame. `frame#` is the +frame number shown by `bt` and defaults to the selected frame. + +``` +(gdb) v8 args 5 +#5 test_func_3 @ throw.js:15:21 +this = 0x1d190100497d <JSGlobalProxy> +[0] = <Smi: 44> +[1] = 0x1d1900000071 <Oddball: TrueValue> +[2] = 0x1d19010492dd <JSObject> +[3] = 0x1d19010492ed <SeqOneByteString: "hello!"> +``` + #### `v8 isolate` Prints the current Isolate address of the selected thread. @@ -135,13 +155,14 @@ or after `--max-lines N` lines when the flag is given. #### Examples -To display the JS frames on stack, and inspect the receiver, paste the address -in the frame annotation into `v8 inspect`: +To look at the JS frames on the stack and inspect a receiver or argument, paste +an address from the frame annotation into `v8 inspect`, or select the frame and +use the `this`/`[N]` shorthands: ``` (gdb) bt ... -#5 0x... in Builtins_InterpreterEntryTrampoline [test_func_3 @ throw.js:15:21] (this=0x1d190100497d, argc=4) +#5 0x... in Builtins_InterpreterEntryTrampoline [test_func_3 @ throw.js:15:21] (this=0x1d190100497d, [0]=<Smi: 44>, [1]=0x1d1900000071 <Oddball: TrueValue>, [2]=0x1d19010492dd <JSObject>, [3]=0x1d19010492ed <SeqOneByteString: "hello!">) ... (gdb) v8 inspect 0x1d190100497d 0x1d190100497d <JSGlobalProxy> @@ -150,6 +171,10 @@ in the frame annotation into `v8 inspect`: .elements=0x1d19000007e5 <FixedArray: EmptyFixedArray> .cpp_heap_wrappable=0x00000000 (gdb) frame 5 +(gdb) v8 inspect [2] +0x1d19010492dd <JSObject> + .map=0x1d19010c95b5 <Map> + ... (gdb) v8 source #5 test_func_3 @ throw.js:15:21 (this=0x1d190100497d, argc=4) diff --git a/deps/v8/tools/debug_helper/plugins/gdb_plugin.py b/deps/v8/tools/debug_helper/plugins/gdb_plugin.py index e7fce6ec85b1..c2e5924f6495 100644 --- a/deps/v8/tools/debug_helper/plugins/gdb_plugin.py +++ b/deps/v8/tools/debug_helper/plugins/gdb_plugin.py @@ -217,12 +217,20 @@ class V8Command(gdb.Command): - inspect -- Inspect the heap object at <addr> with the V8 inspector. - v8 inspect <addr> [--type T] [--depth N] [--array-length N] + v8 inspect <addr>|this|[N] [--type T] [--depth N] [--array-length N] + * this / [N]: inspect the receiver or the Nth argument of the + selected JS frame instead of a raw address. * --type T: treat the object as if it has type T (e.g. `v8::internal::JSArray`). * --depth N: limit recursive inspection depth to N (default: 1). * --array-length N: for arrays, inspect up to N elements (default: 16). + - args -- Print the receiver and the arguments of a JS frame. + + v8 args [frame#] + + * frame#: the frame to show (default: the selected frame). + - isolate -- Print the current Isolate address of the selected thread. v8 isolate diff --git a/deps/v8/tools/debug_helper/plugins/lldb_plugin.py b/deps/v8/tools/debug_helper/plugins/lldb_plugin.py index 81b3ec256957..dc0d97ada4b5 100644 --- a/deps/v8/tools/debug_helper/plugins/lldb_plugin.py +++ b/deps/v8/tools/debug_helper/plugins/lldb_plugin.py @@ -507,12 +507,20 @@ def cmd_v8(debugger, command, result, _internal_dict): - inspect -- Inspect the heap object at <addr> with the V8 inspector. - v8 inspect <addr> [--type T] [--depth N] [--array-length N] + v8 inspect <addr>|this|[N] [--type T] [--depth N] [--array-length N] + * this / [N]: inspect the receiver or the Nth argument of the + selected JS frame instead of a raw address. * --type T: treat the object as if it has type T (e.g. `v8::internal::JSArray`). * --depth N: limit recursive inspection depth to N (default: 1). * --array-length N: for arrays, inspect up to N elements (default: 16). + - args -- Print the receiver and the arguments of a JS frame. + + v8 args [frame#] + + * frame#: the frame to show (default: the selected frame). + - isolate -- Print the current Isolate address of the selected thread. v8 isolate diff --git a/deps/v8/tools/debug_helper/plugins/test/fixtures/args-mismatch.js b/deps/v8/tools/debug_helper/plugins/test/fixtures/args-mismatch.js new file mode 100644 index 000000000000..c32aa7924d58 --- /dev/null +++ b/deps/v8/tools/debug_helper/plugins/test/fixtures/args-mismatch.js @@ -0,0 +1,13 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function under(a, b, c, d) { + throw new Error('v8dbg args test: ' + a); +} + +function over(a) { + return under('only-one'); +} + +over(1, 2, 3); diff --git a/deps/v8/tools/debug_helper/plugins/test/helpers/args.py b/deps/v8/tools/debug_helper/plugins/test/helpers/args.py new file mode 100644 index 000000000000..055801b2ec93 --- /dev/null +++ b/deps/v8/tools/debug_helper/plugins/test/helpers/args.py @@ -0,0 +1,155 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Assertions for `v8 args` and frame-relative `v8 inspect` integration tests.""" + +import re + +from .backtrace import check_backtrace + +# The innermost annotated frame: test_func_3(44, true, {inner: {...}}, "hello!"). +_FUNC_FRAME_RE = re.compile( + r"#(?P<frame>\d+)[^\n]*\[test_func_3 @ [^\]]+:15:21\]") + +# Expected `v8 args` lines for the test_func_3 frame, one regex per line. +# Without static roots (no pointer compression) or space hints the library +# can only narrow known objects down to candidates, so `arg1` accepts both +# the exact brief and a `maybe ..., maybe TrueValue` candidate list. +_EXPECTED_ARG_LINE_RES = ( + r"this = 0x[0-9a-f]+ <JSGlobalProxy[^\n]*>", + r"\[0\] = <Smi: 44>", + r"\[1\] = 0x[0-9a-f]+ <Oddball:[^\n>]*TrueValue>", + r"\[2\] = 0x[0-9a-f]+ <JSObject[^\n]*>", + r"\[3\] = 0x[0-9a-f]+ <[^\n]*\"hello!\"[^\n]*>", +) + + +def _find_frame(bt, frame_re): + """Return the frame number of the innermost frame annotated per `frame_re`.""" + m = frame_re.search(bt) + if not m: + raise AssertionError( + f"no frame matching {frame_re.pattern} in backtrace:\n{bt}") + return int(m.group("frame")) + + +def _find_func_frame(session): + """Return the frame number of the annotated test_func_3 frame.""" + return _find_frame(session.run_command("bt"), _FUNC_FRAME_RE) + + +def _assert_matches(pattern, output): + if not re.search(pattern, output): + raise AssertionError(f"expected /{pattern}/ in output:\n{output}") + + +def check_args(session): + """Check `v8 args` output, flags, and error handling.""" + frame = _find_func_frame(session) + + # Explicit frame number. + output = session.run_command(f"v8 args {frame}") + _assert_matches(rf"#{frame} test_func_3 @ [^\n]+:15:21", output) + for pattern in _EXPECTED_ARG_LINE_RES: + _assert_matches(pattern, output) + + # Plain `v8 args` uses the debugger's selected frame. + try: + session.select_frame(frame) + output = session.run_command("v8 args") + finally: + session.select_frame(0) + for pattern in _EXPECTED_ARG_LINE_RES: + _assert_matches(pattern, output) + + # Argument validation and non-JS frame handling. + checks = ( + ("v8 args 9999", "cannot resolve frame 9999"), + ("v8 args abc", "frame number must be a non-negative integer"), + ("v8 args --frame 1", "unknown flag '--frame'"), + # Frame 0 is the native abort frame, not a JS frame. + ("v8 args 0", "is not a JS frame"), + ) + for command, expected_error in checks: + output = session.run_command(command) + if expected_error not in output: + raise AssertionError( + f"`{command}` did not report {expected_error!r}, got:\n{output}") + + +# Expected annotations for the args-mismatch.js fixture. `under(a, b, c, d)` +# is called with one argument and `over(a)` with three. The trailer lists the +# call-site arguments. Padded formals of an under-applied frame are not +# listed, and all extra arguments of an over-applied frame are. +_MISMATCH_EXPECTED_ANNOTATIONS = ( + "[under @ <base>/args-mismatch.js:5:15] (this=<addr>, " + '[0]=<addr> <SeqOneByteString: "only-one">)', + "[over @ <base>/args-mismatch.js:9:14] (this=<addr>, [0]=<Smi: 1>, " + "[1]=<Smi: 2>, [2]=<Smi: 3>)", + "[<anonymous> @ <base>/args-mismatch.js:1:1] (this=<addr>, " + "[0]=<addr> <FixedArray>)", +) + +_UNDER_FRAME_RE = re.compile(r"#(?P<frame>\d+)[^\n]*\[under @ [^\]]+:5:15\]") +_OVER_FRAME_RE = re.compile(r"#(?P<frame>\d+)[^\n]*\[over @ [^\]]+:9:14\]") + + +def check_args_mismatch(session): + """Check argument-count mismatches against the args-mismatch.js fixture.""" + bt = session.run_command("bt") + failure = check_backtrace(bt, "args-mismatch", _MISMATCH_EXPECTED_ANNOTATIONS) + if failure is not None: + raise AssertionError(failure) + + # under(a, b, c, d) is called with one argument. Only [0] is listed, not + # the undefined-padded slots of the remaining formals. + output = session.run_command(f"v8 args {_find_frame(bt, _UNDER_FRAME_RE)}") + _assert_matches(r"\[0\] = 0x[0-9a-f]+ <[^\n]*\"only-one\"[^\n]*>", output) + if "[1]" in output: + raise AssertionError( + f"under-applied frame listed more than the passed argument:\n{output}") + + # over(a) is called with three arguments. The extras beyond the single + # formal are all on the stack and listed. + output = session.run_command(f"v8 args {_find_frame(bt, _OVER_FRAME_RE)}") + for pattern in (r"\[0\] = <Smi: 1>", r"\[1\] = <Smi: 2>", + r"\[2\] = <Smi: 3>"): + _assert_matches(pattern, output) + if "[3]" in output: + raise AssertionError( + f"over-applied frame listed too many arguments:\n{output}") + + # Frame-relative names resolve against the call-site count too. + try: + session.select_frame(_find_frame(bt, _UNDER_FRAME_RE)) + output = session.run_command("v8 inspect [1]") + finally: + session.select_frame(0) + if "has only 1 argument(s)" not in output: + raise AssertionError( + f"`v8 inspect [1]` on the under-applied frame did not report the " + f"argument count, got:\n{output}") + + +def check_frame_relative_inspect(session): + """Check `v8 inspect this|[N]` resolves against the selected frame.""" + frame = _find_func_frame(session) + try: + session.select_frame(frame) + this_out = session.run_command("v8 inspect this") + slot3_out = session.run_command("v8 inspect [3] --depth 0") + slot9_out = session.run_command("v8 inspect [9]") + finally: + session.select_frame(0) + _assert_matches(r"0x[0-9a-f]+ <JSGlobalProxy[^\n]*>", this_out) + _assert_matches(r"0x[0-9a-f]+ <[^\n]*\"hello!\"[^\n]*>", slot3_out) + if "has only 4 argument(s)" not in slot9_out: + raise AssertionError(f"`v8 inspect [9]` did not report the argument " + f"count, got:\n{slot9_out}") + + # Outside a JS frame the slot resolution reports a clear error. + output = session.run_command("v8 inspect [0]") + if "is not a JS frame" not in output: + raise AssertionError( + f"`v8 inspect [0]` on a non-JS frame did not report an error, " + f"got:\n{output}") diff --git a/deps/v8/tools/debug_helper/plugins/test/helpers/backtrace.py b/deps/v8/tools/debug_helper/plugins/test/helpers/backtrace.py index 5af02d7e1365..f1b25c4d545b 100644 --- a/deps/v8/tools/debug_helper/plugins/test/helpers/backtrace.py +++ b/deps/v8/tools/debug_helper/plugins/test/helpers/backtrace.py @@ -9,29 +9,52 @@ _BACKTRACE_ANNOTATION_LINE_RE = re.compile( r"(?P<annotation>\[(?:[^\]]+ @ .+?(?::\d+:\d+)?|<anonymous>)\])" - r"(?P<trailer>\s*\(this=[^\)]*\))?(?:\s*\([^\)]*\))?\s*$") + r"(?P<trailer>\s*\(this=[^\n]*)?\s*$") _SCRIPT_ANNOTATION_RE = re.compile( r"^\[(?P<function>[^\]]+?) @ (?P<script>.+?):(?P<line>\d+):(?P<column>\d+)\]$" ) _SCRIPT_ONLY_ANNOTATION_RE = re.compile( r"^\[(?P<function>[^\]]+?) @ (?P<script>.+)\]$") -# Receiver pointer in `(this=0xADDR, argc=N)`. +# Pointers in `(this=0xADDR, [0]=0xADDR <Type>, ...)`. _ADDR_RE = re.compile(r"0x[0-9a-fA-F]+") +# Known-object names in briefs, e.g. `<Oddball: TrueValue>` or +# `<Oddball: maybe NoElementsProtector, maybe TrueValue>`. The names depend on +# the build config (static roots) and the available heap hints, so mask them +# but keep the type. Quoted string contents and Smi values do not match and +# stay exact. +_KNOWN_OBJECT_RE = re.compile( + r"<(\w+): (?:maybe )?[A-Z]\w*(?:, maybe [A-Z]\w*)*>") _DEFAULT_EXPECTED_ANNOTATIONS = ( - "[test_func_3 @ <base>/throw.js:15:21] (this=<addr>, argc=4)", - "[<anonymous> @ <base>/throw.js:10:19] (this=<addr>, argc=4)", - "[test_func_2 @ <base>/throw.js:9:21] (this=<addr>, argc=4)", - "[test_func_1 @ <base>/throw.js:5:21] (this=<addr>, argc=4)", - "[<anonymous> @ <base>/throw.js:1:1] (this=<addr>, argc=1)", + "[test_func_3 @ <base>/throw.js:15:21] (this=<addr>, [0]=<Smi: 44>, " + "[1]=<addr> <Oddball>, [2]=<addr> <JSObject>, " + '[3]=<addr> <SeqOneByteString: "hello!">)', + "[<anonymous> @ <base>/throw.js:10:19] (this=<addr>, [0]=<Smi: 44>, " + "[1]=<addr> <Oddball>, [2]=<addr> <JSObject>, " + '[3]=<addr> <SeqOneByteString: "hello!">)', + "[test_func_2 @ <base>/throw.js:9:21] (this=<addr>, [0]=<Smi: 43>, " + "[1]=<addr> <Oddball>, [2]=<addr> <JSObject>, " + '[3]=<addr> <SeqOneByteString: "hello">)', + "[test_func_1 @ <base>/throw.js:5:21] (this=<addr>, [0]=<Smi: 42>, " + "[1]=<addr> <Oddball>, [2]=<addr> <JSObject>, " + '[3]=<addr> <SeqOneByteString: "hello">)', + "[<anonymous> @ <base>/throw.js:1:1] (this=<addr>, " + "[0]=<addr> <FixedArray>)", ) def _normalize_annotation(annotation, trailer): """Reduce debugger-specific paths to a stable, basename-only annotation.""" annotation = annotation.strip() - # Mask the receiver pointer so the trailer compares stably across runs. - suffix = "" if not trailer else " " + _ADDR_RE.sub("<addr>", trailer.strip()) + trailer = (trailer or "").strip() + # gdb appends a native argument list after the decorated function name, + # e.g. "(this=...) ()". Drop it so only the v8 trailer remains. + if trailer.endswith("()"): + trailer = trailer[:-2].strip() + # Mask the pointers so the trailer compares stably across runs. + trailer = _ADDR_RE.sub("<addr>", trailer) + trailer = _KNOWN_OBJECT_RE.sub(r"<\1>", trailer) + suffix = "" if not trailer else " " + trailer match = _SCRIPT_ANNOTATION_RE.match(annotation) if match: return (f"[{match.group('function').strip()} @ <base>/" diff --git a/deps/v8/tools/debug_helper/plugins/test/helpers/corruptions.py b/deps/v8/tools/debug_helper/plugins/test/helpers/corruptions.py index 88620f2c720c..5d964f8b1196 100644 --- a/deps/v8/tools/debug_helper/plugins/test/helpers/corruptions.py +++ b/deps/v8/tools/debug_helper/plugins/test/helpers/corruptions.py @@ -48,13 +48,13 @@ def resolve(self, test_dir): script_path="fixtures/invalid-script-source.js", expected_annotations=( "[test_func_3 @ <base>/invalid-script-source.js]" - " (this=<addr>, argc=0)", + " (this=<addr>)", "[test_func_2 @ <base>/invalid-script-source.js]" - " (this=<addr>, argc=0)", + " (this=<addr>)", "[test_func_1 @ <base>/invalid-script-source.js]" - " (this=<addr>, argc=0)", + " (this=<addr>)", "[<anonymous> @ <base>/invalid-script-source.js:1:1]" - " (this=<addr>, argc=1)", + " (this=<addr>, [0]=<addr> <FixedArray>)", ), ), CorruptionCase( @@ -62,11 +62,11 @@ def resolve(self, test_dir): script_path="fixtures/invalid-shared-function-info.js", expected_annotations=( "[test_func_2 @ <base>/invalid-shared-function-info.js:9:21]" - " (this=<addr>, argc=0)", + " (this=<addr>)", "[test_func_1 @ <base>/invalid-shared-function-info.js:13:21]" - " (this=<addr>, argc=0)", + " (this=<addr>)", "[<anonymous> @ <base>/invalid-shared-function-info.js:1:1]" - " (this=<addr>, argc=1)", + " (this=<addr>, [0]=<addr> <FixedArray>)", ), absent_output=("test_func_3",), ), diff --git a/deps/v8/tools/debug_helper/plugins/test/helpers/session.py b/deps/v8/tools/debug_helper/plugins/test/helpers/session.py index 3f51fdc3edab..68e99f7850a2 100644 --- a/deps/v8/tools/debug_helper/plugins/test/helpers/session.py +++ b/deps/v8/tools/debug_helper/plugins/test/helpers/session.py @@ -192,15 +192,25 @@ def v8_inspect(self, address): return self.run_command(f"v8 inspect {address}") def frame_trailer(self, function_name): - """Parse the `(this=0xADDR, argc=N)` trailer for one JS frame.""" + """Parse the `(this=0xADDR, ...)` trailer for one JS frame. + + Returns `(receiver, argc)`, where argc is the number of `[N]=` previews + or the total from the `... (argc=N)` tail when the previews were capped. + """ bt = self.run_command("bt") pattern = re.compile(rf"\[{re.escape(function_name)}[^\[\]]*\][^\n]*" - rf"this=(0x[0-9a-f]+), argc=(\d+)") + rf"this=(0x[0-9a-f]+)(?P<rest>[^\n]*)") m = pattern.search(bt) if not m: - raise AssertionError(f"no `(this=..., argc=...)` trailer for frame " + raise AssertionError(f"no `(this=..., ...)` trailer for frame " f"{function_name!r} in backtrace:\n{bt}") - return m.group(1), int(m.group(2)) + rest = m.group("rest") + tail = re.search(r"\.\.\. \(argc=(\d+)\)", rest) + if tail: + argc = int(tail.group(1)) + else: + argc = len(re.findall(r"\[\d+\]=", rest)) + return m.group(1), argc def frame_receiver(self, function_name): """Get the receiver address for the JS frame named `function_name`.""" diff --git a/deps/v8/tools/debug_helper/plugins/test/helpers/source.py b/deps/v8/tools/debug_helper/plugins/test/helpers/source.py index 0a0bf2d44d08..b719e851d013 100644 --- a/deps/v8/tools/debug_helper/plugins/test/helpers/source.py +++ b/deps/v8/tools/debug_helper/plugins/test/helpers/source.py @@ -7,10 +7,10 @@ _FUNC_FRAME_RE = re.compile( r"#(?P<frame>\d+)[^\n]*\[test_func_3 @ (?P<script>[^\]]+):15:21\]" - r" \(this=(?P<this>0x[0-9a-f]+), argc=(?P<argc>\d+)\)") + r" \(this=(?P<this>0x[0-9a-f]+)(?P<rest>[^\n]*)") _TOP_LEVEL_FRAME_RE = re.compile( r"#(?P<frame>\d+)[^\n]*\[<anonymous> @ (?P<script>[^\]]*throw\.js):1:1\]" - r" \(this=(?P<this>0x[0-9a-f]+), argc=(?P<argc>\d+)\)") + r" \(this=(?P<this>0x[0-9a-f]+)(?P<rest>[^\n]*)") def _match_frame(bt, frame_re): @@ -22,10 +22,22 @@ def _match_frame(bt, frame_re): return m +def _argc_from_trailer(rest): + """Recover argc from the bt trailer. + + This is the count of `[N]=` previews, or the total from the + `... (argc=N)` tail when the previews were capped. + """ + tail = re.search(r"\.\.\. \(argc=(\d+)\)", rest) + if tail: + return int(tail.group(1)) + return len(re.findall(r"\[\d+\]=", rest)) + + def _header(m, function_name, position): - """The `v8 source` first line, reproducing the frame's bt annotation.""" + """The `v8 source` first line: the frame's location plus the argc trailer.""" return (f"#{m['frame']} {function_name} @ {m['script']}:{position}" - f" (this={m['this']}, argc={m['argc']})\n\n") + f" (this={m['this']}, argc={_argc_from_trailer(m['rest'])})\n\n") def _expected_func_span(m): diff --git a/deps/v8/tools/debug_helper/plugins/test/test_gdb_core.py b/deps/v8/tools/debug_helper/plugins/test/test_gdb_core.py index b2538628b969..d6b86c5d121a 100644 --- a/deps/v8/tools/debug_helper/plugins/test/test_gdb_core.py +++ b/deps/v8/tools/debug_helper/plugins/test/test_gdb_core.py @@ -7,6 +7,9 @@ import unittest from typing import cast +from .helpers.args import check_args +from .helpers.args import check_args_mismatch +from .helpers.args import check_frame_relative_inspect from .helpers.backtrace import check_backtrace from .helpers.corruptions import check_corruption from .helpers.corruptions import check_corrupted_map_inspect @@ -130,6 +133,37 @@ def test_source(self): check_source(session) +class GdbArgsCoreTest(unittest.TestCase): + """Checks `v8 args` and frame-relative `v8 inspect` with a GDB core dump.""" + + def _session(self): + return GdbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + core_path=os.path.join(_CORE_DIR, "throw.core"), + ) + + def test_args(self): + """Checks `v8 args` rendering, flags, and error handling.""" + with self._session() as session: + check_args(session) + + def test_frame_relative_inspect(self): + """Checks `v8 inspect this|argN` against the selected frame.""" + with self._session() as session: + check_frame_relative_inspect(session) + + def test_args_mismatch(self): + """Checks under- and over-applied frames report call-site arguments.""" + session = GdbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + core_path=os.path.join(_CORE_DIR, "args-mismatch.core"), + ) + with session: + check_args_mismatch(session) + + class GdbCorruptedMapCoreTest(unittest.TestCase): """Checks `v8 inspect` on objects with corrupted Map from a core dump in GDB.""" diff --git a/deps/v8/tools/debug_helper/plugins/test/test_gdb_live.py b/deps/v8/tools/debug_helper/plugins/test/test_gdb_live.py index 50dc6fbb0e18..9b4f1b11e425 100644 --- a/deps/v8/tools/debug_helper/plugins/test/test_gdb_live.py +++ b/deps/v8/tools/debug_helper/plugins/test/test_gdb_live.py @@ -7,6 +7,9 @@ import unittest from typing import cast +from .helpers.args import check_args +from .helpers.args import check_args_mismatch +from .helpers.args import check_frame_relative_inspect from .helpers.backtrace import check_backtrace from .helpers.corruptions import check_corruption from .helpers.corruptions import check_corrupted_map_inspect @@ -139,6 +142,44 @@ def test_source(self): check_source(session) +class GdbArgsLiveTest(unittest.TestCase): + """Checks `v8 args` and frame-relative `v8 inspect` with a live d8 in GDB.""" + + def _session(self): + script = os.path.join(FIXTURES_DIR, "throw.js") + return GdbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + target_args=f'{_CONFIG.d8_args} --abort-on-uncaught-exception ' + f'"{script}"', + ) + + def test_args(self): + """Checks `v8 args` rendering, flags, and error handling.""" + with self._session() as session: + session.run_to_abort() + check_args(session) + + def test_frame_relative_inspect(self): + """Checks `v8 inspect this|argN` against the selected frame.""" + with self._session() as session: + session.run_to_abort() + check_frame_relative_inspect(session) + + def test_args_mismatch(self): + """Checks under- and over-applied frames report call-site arguments.""" + script = os.path.join(FIXTURES_DIR, "args-mismatch.js") + session = GdbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + target_args=f'{_CONFIG.d8_args} --abort-on-uncaught-exception ' + f'"{script}"', + ) + with session: + session.run_to_abort() + check_args_mismatch(session) + + class GdbCorruptedMapTest(unittest.TestCase): """Checks `v8 inspect` on objects with corrupted Map with a live d8 process in GDB.""" diff --git a/deps/v8/tools/debug_helper/plugins/test/test_lldb_core.py b/deps/v8/tools/debug_helper/plugins/test/test_lldb_core.py index 07d99afc33b1..6e4beb34f9ba 100644 --- a/deps/v8/tools/debug_helper/plugins/test/test_lldb_core.py +++ b/deps/v8/tools/debug_helper/plugins/test/test_lldb_core.py @@ -7,6 +7,9 @@ import unittest from typing import cast +from .helpers.args import check_args +from .helpers.args import check_args_mismatch +from .helpers.args import check_frame_relative_inspect from .helpers.backtrace import check_backtrace from .helpers.corruptions import check_corruption from .helpers.corruptions import check_corrupted_map_inspect @@ -123,6 +126,37 @@ def test_source(self): check_source(session) +class LldbArgsCoreTest(unittest.TestCase): + """Checks `v8 args` and frame-relative `v8 inspect` with an LLDB core dump.""" + + def _session(self): + return LldbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + core_path=os.path.join(_CORE_DIR, "throw.core"), + ) + + def test_args(self): + """Checks `v8 args` rendering, flags, and error handling.""" + with self._session() as session: + check_args(session) + + def test_frame_relative_inspect(self): + """Checks `v8 inspect this|argN` against the selected frame.""" + with self._session() as session: + check_frame_relative_inspect(session) + + def test_args_mismatch(self): + """Checks under- and over-applied frames report call-site arguments.""" + session = LldbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + core_path=os.path.join(_CORE_DIR, "args-mismatch.core"), + ) + with session: + check_args_mismatch(session) + + class LldbCorruptedMapCoreTest(unittest.TestCase): """Checks `v8 inspect` on objects with corrupted Map from a core dump in LLDB.""" diff --git a/deps/v8/tools/debug_helper/plugins/test/test_lldb_live.py b/deps/v8/tools/debug_helper/plugins/test/test_lldb_live.py index 64c58049c9ae..409360d622f4 100644 --- a/deps/v8/tools/debug_helper/plugins/test/test_lldb_live.py +++ b/deps/v8/tools/debug_helper/plugins/test/test_lldb_live.py @@ -7,6 +7,9 @@ import unittest from typing import cast +from .helpers.args import check_args +from .helpers.args import check_args_mismatch +from .helpers.args import check_frame_relative_inspect from .helpers.backtrace import check_backtrace from .helpers.corruptions import check_corruption from .helpers.corruptions import check_corrupted_map_inspect @@ -135,6 +138,44 @@ def test_source(self): check_source(session) +class LldbArgsLiveTest(unittest.TestCase): + """Checks `v8 args` and frame-relative `v8 inspect` with a live d8 in LLDB.""" + + def _session(self): + script = os.path.join(FIXTURES_DIR, "throw.js") + return LldbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + target_args=f'{_CONFIG.d8_args} --abort-on-uncaught-exception ' + f'"{script}"', + ) + + def test_args(self): + """Checks `v8 args` rendering, flags, and error handling.""" + with self._session() as session: + session.run_to_abort() + check_args(session) + + def test_frame_relative_inspect(self): + """Checks `v8 inspect this|argN` against the selected frame.""" + with self._session() as session: + session.run_to_abort() + check_frame_relative_inspect(session) + + def test_args_mismatch(self): + """Checks under- and over-applied frames report call-site arguments.""" + script = os.path.join(FIXTURES_DIR, "args-mismatch.js") + session = LldbSession( + _CONFIG, + target_binary=_CONFIG.d8_binary, + target_args=f'{_CONFIG.d8_args} --abort-on-uncaught-exception ' + f'"{script}"', + ) + with session: + session.run_to_abort() + check_args_mismatch(session) + + class LldbCorruptedMapTest(unittest.TestCase): """Checks `v8 inspect` on objects with corrupted Map with a live d8 process in LLDB.""" diff --git a/deps/v8/tools/debug_helper/plugins/v8dbg/commands.py b/deps/v8/tools/debug_helper/plugins/v8dbg/commands.py index aeeea1846556..46541620b834 100644 --- a/deps/v8/tools/debug_helper/plugins/v8dbg/commands.py +++ b/deps/v8/tools/debug_helper/plugins/v8dbg/commands.py @@ -9,18 +9,21 @@ import io import os +import re import traceback from .format import (format_frame_location, format_frame_trailer, render_function_span) from .hints import resolve_current_isolate, resolve_heap_hints -from .inspect import Formatter, read_frame_trailer +from .inspect import Formatter, preview_tagged_value from .models import HeapHints -_V8_USAGE = ("usage: v8 <subcommand>\n" - " v8 inspect <addr> [--type T] [--depth N] [--array-length N]\n" - " v8 isolate\n" - " v8 source [frame#] [--max-lines N]\n") +_V8_USAGE = ( + "usage: v8 <subcommand>\n" + " v8 inspect <addr>|this|[N] [--type T] [--depth N] [--array-length N]\n" + " v8 args [frame#]\n" + " v8 isolate\n" + " v8 source [frame#] [--max-lines N]\n") # Cap on the number of function span lines `v8 source` prints. Top-level # frames span the whole script, which can be arbitrarily large. @@ -52,7 +55,9 @@ def dispatch_v8_command(bridge, argv, *, read_memory, eval_address, resolver, try: if argv[0] == "inspect": _run_inspect(bridge, argv[1:], buffer, read_memory, eval_address, - resolver) + resolver, frame_fp) + elif argv[0] == "args": + _run_args(bridge, argv[1:], buffer, read_memory, frame_fp, resolver) elif argv[0] == "isolate": _run_isolate(argv[1:], buffer, resolver) elif argv[0] == "source": @@ -109,6 +114,30 @@ def _run_isolate(argv, output, resolver): output.write(f"isolate = 0x{isolate_addr:x}\n") +def _resolve_js_frame(bridge, command, frame_index, output, read_memory, + frame_fp): + """Resolve a frame number to the matching JS frame metadata. + + Returns `(frame_desc, frame_number, info)`. If the frame cannot be resolved, + it writes an error and returns None. + """ + frame_desc = ("the selected frame" + if frame_index is None else f"frame {frame_index}") + resolved = frame_fp(frame_index) + if resolved is None: + output.write(f"v8 {command}: cannot resolve {frame_desc}\n") + return None + frame_number, frame_pointer = resolved + if frame_number is not None: + frame_desc = f"frame {frame_number}" + + info = bridge.describe_js_frame(frame_pointer, read_memory) + if info is None: + output.write(f"v8 {command}: {frame_desc} is not a JS frame\n") + return None + return (frame_desc, frame_number, info) + + def _run_source(bridge, argv, output, read_memory, frame_fp): """Print the source span of the function a stack frame is running.""" frame_index = None @@ -134,24 +163,14 @@ def _run_source(bridge, argv, output, read_memory, frame_fp): f"got '{token}'\n") return - frame_desc = ("the selected frame" - if frame_index is None else f"frame {frame_index}") - resolved = frame_fp(frame_index) + resolved = _resolve_js_frame(bridge, "source", frame_index, output, + read_memory, frame_fp) if resolved is None: - output.write(f"v8 source: cannot resolve {frame_desc}\n") - return - frame_number, frame_pointer = resolved - if frame_number is not None: - frame_desc = f"frame {frame_number}" - - info = bridge.describe_js_frame(frame_pointer, read_memory) - if info is None: - output.write(f"v8 source: {frame_desc} is not a JS frame\n") return - receiver, argc = read_frame_trailer(frame_pointer, bridge.ptr_size, - read_memory) + frame_desc, frame_number, info = resolved - header = format_frame_location(info) + format_frame_trailer(receiver, argc) + header = format_frame_location(info) + format_frame_trailer( + info["receiver"], info["argc"]) if frame_number is not None: header = f"#{frame_number} {header}" output.write(header + "\n\n") @@ -164,7 +183,101 @@ def _run_source(bridge, argv, output, read_memory, frame_fp): output.write(span) -def _run_inspect(bridge, argv, output, read_memory, eval_address, resolver): +def _run_args(bridge, argv, output, read_memory, frame_fp, resolver): + """Print the receiver and the arguments of a JS stack frame.""" + frame_index = None + for token in argv: + if token.startswith("-"): + output.write(f"v8 args: unknown flag '{token}'\n") + return + if frame_index is not None: + output.write(f"v8 args: extra positional arg '{token}'\n") + return + if not token.isdigit(): + output.write(f"v8 args: frame number must be a non-negative integer, " + f"got '{token}'\n") + return + frame_index = int(token) + + resolved = _resolve_js_frame(bridge, "args", frame_index, output, read_memory, + frame_fp) + if resolved is None: + return + frame_desc, frame_number, info = resolved + + header = format_frame_location(info) + if frame_number is not None: + header = f"#{frame_number} {header}" + output.write(header + "\n") + + hints = resolve_heap_hints(resolver) if resolver is not None else HeapHints() + receiver = info["receiver"] + if receiver is None: + output.write("this = <unreadable slot>\n") + else: + output.write( + f"this = {preview_tagged_value(bridge, read_memory, receiver, hints)}\n" + ) + previews = bridge.argument_previews(info, read_memory, hints=hints) + if previews is None: + output.write(f"v8 args: the argument slots of {frame_desc} are " + "unreadable\n") + return + for index, preview in enumerate(previews): + output.write(f"[{index}] = {preview}\n") + + +# Frame-relative value tokens: this and the [N] labels shown in the frame +# annotations. +_FRAME_VALUE_RE = re.compile(r"^(?:this|\[(\d+)\])$") + + +def _read_argument_slot(info, index, read_memory): + """Read argument `index` of a frame. Returns `(value, error)`.""" + argc = info["argc"] + arguments = info["arguments"] + if argc is None or arguments is None: + return (None, "the argument slots are unreadable") + if index >= argc: + return (None, f"the selected frame has only {argc} argument(s)") + try: + data = read_memory(arguments.address + index * arguments.size, + arguments.size) + except Exception: + data = b"" + if len(data) != arguments.size: + return (None, f"the [{index}] slot is unreadable") + return (int.from_bytes(data, "little", signed=False), None) + + +def _resolve_frame_value(bridge, text, read_memory, frame_fp): + """Resolve `this`/`[N]` against the selected frame. + + Returns `(handled, value, error)`. `handled` is False when `text` is not a + frame-relative name. Otherwise `value` holds the tagged slot value, or + `error` holds the failure message. + """ + match = _FRAME_VALUE_RE.match(text or "") + if match is None: + return (False, None, None) + resolved = frame_fp(None) if frame_fp is not None else None + if resolved is None: + return (True, None, "cannot resolve the selected frame") + _, frame_pointer = resolved + info = bridge.describe_js_frame(frame_pointer, read_memory) + if info is None: + return (True, None, "the selected frame is not a JS frame") + if match.group(1) is None: + receiver = info["receiver"] + if receiver is None: + return (True, None, "the receiver slot is unreadable") + return (True, receiver, None) + value, error = _read_argument_slot(info, int(match.group(1)), read_memory) + return (True, value, error) + + +def _run_inspect(bridge, argv, output, read_memory, eval_address, resolver, + frame_fp): # TODO(joyee): per-flag error messages, reject negative ints. type_hint = None depth = 1 @@ -187,7 +300,13 @@ def _run_inspect(bridge, argv, output, read_memory, eval_address, resolver): output.write(f"v8 inspect: extra positional arg '{token}'\n") return - address = _parse_address(addr_text, eval_address) + handled, address, error = _resolve_frame_value(bridge, addr_text, read_memory, + frame_fp) + if error is not None: + output.write(f"v8 inspect: {error}\n") + return + if not handled: + address = _parse_address(addr_text, eval_address) if address is None: output.write(_V8_USAGE) return diff --git a/deps/v8/tools/debug_helper/plugins/v8dbg/format.py b/deps/v8/tools/debug_helper/plugins/v8dbg/format.py index f90ef480ebf3..c056cc61abd8 100644 --- a/deps/v8/tools/debug_helper/plugins/v8dbg/format.py +++ b/deps/v8/tools/debug_helper/plugins/v8dbg/format.py @@ -21,11 +21,23 @@ def format_frame_location(annotation): return location -def format_frame_trailer(receiver, argc): - """Format the " (this=0x..., argc=N)" frame trailer, or "" without one.""" +def format_frame_trailer(receiver, argc, arg_previews=None): + """Format the frame trailer as " (this=0x..., ...)" or an empty string. + + If `arg_previews` is given, the trailer lists them and adds a + "... (argc=N)" tail when the frame has more arguments. Without previews, + it prints " (this=0x..., argc=N)". + """ if receiver is None: return "" - return f" (this=0x{receiver:x}, argc={argc})" + parts = [f"this=0x{receiver:x}"] + if arg_previews is None: + parts.append(f"argc={argc if argc is not None else '?'}") + else: + parts.extend(f"[{i}]={preview}" for i, preview in enumerate(arg_previews)) + if argc is not None and argc > len(arg_previews): + parts.append(f"... (argc={argc})") + return " (" + ", ".join(parts) + ")" def render_function_span(info, label, max_lines): diff --git a/deps/v8/tools/debug_helper/plugins/v8dbg/inspect.py b/deps/v8/tools/debug_helper/plugins/v8dbg/inspect.py index 8221fcc257bf..1c518d870f90 100644 --- a/deps/v8/tools/debug_helper/plugins/v8dbg/inspect.py +++ b/deps/v8/tools/debug_helper/plugins/v8dbg/inspect.py @@ -4,9 +4,10 @@ """Conversion and renderers for `v8 inspect`.""" import ctypes +import dataclasses import re -from .models import PropertySummary, StructFieldSummary +from .models import HeapHints, PropertySummary, StructFieldSummary # Enum values from tools/debug_helper/debug-helper.h. PROPERTY_KIND_ARRAY_OF_KNOWN_SIZE = 1 @@ -68,22 +69,39 @@ def _is_tagged_type(type_name): type_name.startswith("v8::internal::TaggedMember<")) -def read_frame_trailer(frame_pointer, ptr_size, read_memory): - """Return (receiver_address, user_argc) for one JS frame, or (None, None) - if the slots are unreadable. user_argc excludes the receiver slot. +def preview_tagged_value(bridge, read_memory, raw, hints=None): + """Compact one-line preview of one tagged value, e.g. for a frame slot. + + Smis also go through the debug-helper inspect call. The library knows the + build's Smi encoding, which differs between pointer-compressed and + uncompressed builds for full-width slots. """ + if raw & 1: + if hints is None: + hints = HeapHints(any_heap_pointer=raw) + elif not hints.any_heap_pointer: + hints = dataclasses.replace(hints, any_heap_pointer=raw) + elif hints is None: + hints = HeapHints() + result = bridge.inspect(raw, hints, read_memory) + if result is None: + return f"0x{raw:x} <?>" + if result.type_check_result == TYPE_CHECK_SMI: + return _compact_brief(result) + display = result.display_address or raw + return f"0x{display:x} {_compact_brief(result)}" + + +def preview_tagged_slot(bridge, read_memory, address, size, hints=None): + """Compact preview of the tagged value stored in one memory slot.""" try: - # Offsets assume kCPSlotSize == 0 (x64, arm64). - receiver_bytes = read_memory(frame_pointer + 2 * ptr_size, ptr_size) - argc_bytes = read_memory(frame_pointer - 3 * ptr_size, ptr_size) + data = read_memory(address, size) except Exception: - return (None, None) - if len(receiver_bytes) != ptr_size or len(argc_bytes) != ptr_size: - return (None, None) - receiver = int.from_bytes(receiver_bytes, "little", signed=False) - # argc lives in the low 32 bits of the slot. - raw_argc = int.from_bytes(argc_bytes, "little", signed=False) & 0xFFFFFFFF - return (receiver, max(0, raw_argc - 1)) + return "<?>" + if len(data) != size: + return "<?>" + raw = int.from_bytes(data, "little", signed=False) + return preview_tagged_value(bridge, read_memory, raw, hints) def summarize_property(c_prop, uintptr_max): diff --git a/deps/v8/tools/debug_helper/plugins/v8dbg/shared_bridge.py b/deps/v8/tools/debug_helper/plugins/v8dbg/shared_bridge.py index 0386e9d78c46..fb006813c74b 100644 --- a/deps/v8/tools/debug_helper/plugins/v8dbg/shared_bridge.py +++ b/deps/v8/tools/debug_helper/plugins/v8dbg/shared_bridge.py @@ -15,10 +15,11 @@ from .format import format_frame_location, format_frame_trailer from .inspect import ( + PROPERTY_KIND_ARRAY_OF_KNOWN_SIZE, decode_c_str, decode_tagged_smi, extract_brief_address, - read_frame_trailer, + preview_tagged_slot, summarize_property, ) from .models import HeapHints, InspectResult @@ -31,6 +32,11 @@ # Default per-field string length cap for frame annotations. Use None if unlimited. _MAX_PROP_STRING_CHARS = 256 +# Cap on per-argument previews in backtrace annotations, to limit the +# annotation length and the per-frame debug-helper calls on deep stacks. +# `v8 args` shows the full list. +_MAX_BT_ARG_PREVIEWS = 4 + class StructProperty(ctypes.Structure): _fields_ = [ @@ -353,6 +359,18 @@ def read_char_offset(byte_offset): end_position = self._position_from_offset(script_source, end_offset - 1) return (position, end_position) + def _read_slot_value(self, prop, read_memory): + """Read the raw value stored in a single-slot frame property, or None.""" + if prop is None or not prop.address or not prop.size: + return None + try: + data = read_memory(prop.address, prop.size) + except Exception: + return None + if len(data) != prop.size: + return None + return int.from_bytes(data, "little", signed=False) + def describe_js_frame(self, frame_pointer, read_memory): """Return high-level JS frame metadata, or None if the frame is unusable.""" if not frame_pointer: @@ -395,35 +413,68 @@ def describe_js_frame(self, frame_pointer, read_memory): return None if function_name == "": function_name = "<anonymous>" + + # argc is None when the argument count cannot be recovered. In that case, + # the arguments property uses the array-of-unknown-size kind. + arguments = props.get("arguments") + argc = None + if (arguments is not None and + arguments.kind == PROPERTY_KIND_ARRAY_OF_KNOWN_SIZE): + argc = arguments.num_values return { "function_name": function_name, "script_name": script_name, "position": position, "end_position": end_position, "script_source": script_source, + "receiver": self._read_slot_value(props.get("receiver"), read_memory), + "argc": argc, + "arguments": arguments, } finally: library._v8_debug_helper_Free_StackFrameResult(result_ptr) + def argument_previews(self, annotation, read_memory, cap=None, hints=None): + """Render compact per-argument previews for a describe_js_frame result. + + Returns a list of at most `cap` briefs, or None when the argument slots + cannot be read. + """ + arguments = annotation.get("arguments") + argc = annotation.get("argc") + if arguments is None or argc is None: + return None + count = argc if cap is None else min(argc, cap) + return [ + preview_tagged_slot(self, read_memory, + arguments.address + i * arguments.size, + arguments.size, hints) for i in range(count) + ] + def frame_suffix(self, frame_pointer, read_memory): """Format the JS annotation suffix for a debugger frame: - [<function_name> @ <script_name>:<line>:<column>] (this=0x..., argc=N) + [<function_name> @ <script_name>:<line>:<column>] (this=..., [0]=..., ...) If source text cannot be recovered but the script name still can, the annotation degrades to: [<function_name> @ <script_name>] - Drops the trailing `(this=..., argc=...)` if the frame slots are unreadable. + Argument previews are capped, so a longer frame gets a "... (argc=N)" + tail. When the argument count cannot be recovered, the trailer is + `(this=..., argc=?)`. It is dropped when the receiver slot is unreadable + too. """ annotation = self.describe_js_frame(frame_pointer, read_memory) if not annotation: return "" - receiver, argc = read_frame_trailer(frame_pointer, self._ptr_size, - read_memory) + previews = self.argument_previews( + annotation, read_memory, cap=_MAX_BT_ARG_PREVIEWS) location = format_frame_location(annotation) - return f" [{location}]{format_frame_trailer(receiver, argc)}" + trailer = format_frame_trailer(annotation["receiver"], annotation["argc"], + previews) + return f" [{location}]{trailer}" _bridges = {} diff --git a/deps/v8/tools/dev/gen-checked-in-headers.py b/deps/v8/tools/dev/gen-checked-in-headers.py new file mode 100644 index 000000000000..0e63d0d0c53c --- /dev/null +++ b/deps/v8/tools/dev/gen-checked-in-headers.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 + +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can +# be found in the LICENSE file. +"""Regenerate headers in src/gen/ with `gm.py gen-checked-in-headers`. + +Builds regen_checked_in_generated_headers in out/<arch>.release, creating +that build directory if needed. Requires v8_use_checked_in_generated_headers. +""" + +import argparse +import os +import platform +import subprocess +import sys +from pathlib import Path + +parser = argparse.ArgumentParser( + description='Regenerates the checked-in generated headers in src/gen/.') +parser.add_argument( + '--out', + default=Path('out'), + required=False, + type=Path, + help='directory containing the build directories') +args = parser.parse_args() + +GN_ARG = "v8_use_checked_in_generated_headers" +TARGET = "regen_checked_in_generated_headers" + + +def run(cmd, **kwargs): + print(f"# CMD: {cmd}") + return subprocess.run(cmd, **kwargs, check=True) + + +def machine_target(): + raw = platform.machine().lower() + if raw in ("x86_64", "amd64"): + return "x64" + if raw == "aarch64": + return "arm64" + return raw + + +V8_PATH = Path(__file__).parents[2] +GM = V8_PATH / 'tools' / 'dev' / 'gm.py' + + +def main(): + target = machine_target() + build_dir = args.out / f"{target}.release" + + if not (V8_PATH / build_dir / "args.gn").exists(): + env = os.environ.copy() + env["V8_GM_OUTDIR"] = str((V8_PATH / args.out).resolve()) + run([sys.executable, str(GM), f"{target}.release.gn_args"], + cwd=V8_PATH, + env=env) + run(["gn", "gen", str(build_dir)], cwd=V8_PATH) + + gn_args = subprocess.run( + ["gn", "args", + str(build_dir), f"--list={GN_ARG}", "--short"], + cwd=V8_PATH, + capture_output=True, + text=True, + check=True).stdout + if f"{GN_ARG} = true" not in gn_args: + print( + f"{build_dir} has {GN_ARG} = false: its generated headers are not " + "the ones that are checked in, so regenerating from it would check " + "in the wrong content. Use a build directory with the default " + "configuration. See src/gen/README.md.", + file=sys.stderr) + return 1 + + # The action writes into src/gen/, which is outside the build directory + # and so cannot be declared as an output; its only output is a stamp + # file, and a hand-edited or deleted checked-in copy does not invalidate + # it. Remove it so the action always runs. + (V8_PATH / build_dir / "gen" / f"{TARGET}.stamp").unlink(missing_ok=True) + + run(["autoninja", "-C", str(build_dir), TARGET], cwd=V8_PATH) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deps/v8/tools/dev/gen-static-roots.py b/deps/v8/tools/dev/gen-static-roots.py index e5d5e14eb319..d1eaa7c74842 100755 --- a/deps/v8/tools/dev/gen-static-roots.py +++ b/deps/v8/tools/dev/gen-static-roots.py @@ -126,7 +126,10 @@ def build_and_check(target): e = dict(os.environ) e['V8_GM_OUTDIR'] = f"{args.out}" e['V8_GM_BUILD_DIR_PREFIX'] = build_prefix - run([f"{sys.executable}", f"{GM}", f"{machine_target()}.release.gn_args"], + run([ + f"{sys.executable}", f"{GM}", "quiet", + f"{machine_target()}.release.gn_args" + ], env=e) # Patch the default config according to our needs @@ -158,14 +161,16 @@ def build_and_check(target): f.write(f"{extra} = {val}\n") # Build mksnapshot - run([f"{sys.executable}", f"{GM}", f"{machine_target()}.release.mksnapshot"], + run([ + f"{sys.executable}", f"{GM}", "quiet", + f"{machine_target()}.release.mksnapshot" + ], env=e) # Generate static roots file and check if it changed - filename = f"static-roots-{target}.h" - out_file = Path(tempfile.gettempdir()) / filename + out_file = Path(tempfile.gettempdir()) / f"static-roots-{target}.h" run([f"{build_dir / 'mksnapshot'}", "--static-roots-src", f"{out_file}"]) - target_file = V8_PATH / 'src' / 'roots' / filename + target_file = V8_PATH / 'src' / 'gen' / target / 'static-roots.h' if not filecmp.cmp(out_file, target_file): shutil.move(out_file, target_file) return True @@ -178,18 +183,18 @@ def update_v8_internal_h(): content = internal_h_path.read_text() common_values = {} - hole_values = {} common_names_map = { 'UndefinedValue': 'kUndefinedValue', 'NullValue': 'kNullValue', 'TrueValue': 'kTrueValue', 'FalseValue': 'kFalseValue', - 'EmptyString': 'kempty_string' + 'EmptyString': 'kempty_string', + 'TheHoleValue': 'kTheHoleValue', } for config in STATIC_ROOT_CONFIGURATIONS.keys(): - file_path = V8_PATH / 'src' / 'roots' / f"static-roots-{config}.h" + file_path = V8_PATH / 'src' / 'gen' / config / 'static-roots.h' if not file_path.exists(): print( f"Warning: {file_path} does not exist. Skipping v8-internal.h update." @@ -215,14 +220,6 @@ def update_v8_internal_h(): else: common_values[internal_name] = val - match = re.search( - f"static constexpr Tagged_t kTheHoleValue = (0x[0-9a-f]+);", - file_content) - if not match: - print(f"Error: Could not find kTheHoleValue in {file_path}") - return False - hole_values[config] = match.group(1) - new_content = content for name, val in common_values.items(): @@ -230,28 +227,6 @@ def update_v8_internal_h(): replacement = f"V({name}, {val})" new_content = re.sub(pattern, replacement, new_content) - wasm_hole = hole_values['intl-wasm'] - intl_hole = hole_values['intl-nowasm'] - nointl_hole = hole_values['nointl-nowasm'] - - block_regex = re.compile( - r""" - (\#ifdef\ V8_ENABLE_WEBASSEMBLY\s+ - static\ constexpr\ Tagged_t\ kBuildDependentTheHoleValue\ =\ )0x[0-9a-f]+(;\s+ - \#else\s+ - \#ifdef\ V8_INTL_SUPPORT\s+ - static\ constexpr\ Tagged_t\ kBuildDependentTheHoleValue\ =\ )0x[0-9a-f]+(;\s+ - \#else\s+ - static\ constexpr\ Tagged_t\ kBuildDependentTheHoleValue\ =\ )0x[0-9a-f]+(;\s+ - \#endif\s+ - \#endif) - """, re.VERBOSE | re.MULTILINE) - - def replace_block(m): - return f"{m.group(1)}{wasm_hole}{m.group(2)}{intl_hole}{m.group(3)}{nointl_hole}{m.group(4)}" - - new_content = block_regex.sub(replace_block, new_content) - if content != new_content: print(f"Updating {internal_h_path}") internal_h_path.write_text(new_content) diff --git a/deps/v8/tools/dev/gm.py b/deps/v8/tools/dev/gm.py index 5444d0f29e6e..b7a7837584ea 100755 --- a/deps/v8/tools/dev/gm.py +++ b/deps/v8/tools/dev/gm.py @@ -277,6 +277,14 @@ def detect_reclient(): return Reclient.CUSTOM if "download_remoteexec_cfg" in custom_vars: return Reclient.GOOGLE + # On Linux corp machines (including Cog), Siso's built-in remote execution + # uses .sisoenv and does not require download_remoteexec_cfg in .gclient. + sisoenv_path = ( + (CHROMIUM_DIR or V8_ROOT_DIR) / "build" / "config" / "siso" / ".sisoenv" + ) + if (platform.system() == "Linux" and shutil.which("gcert") is not None and + sisoenv_path.exists()): + return Reclient.GOOGLE return Reclient.NONE @@ -461,6 +469,8 @@ def _write(filename, content, log=True): def _notify(summary, body): + if QUIET: + return if (shutil.which('notify-send') is not None and os.environ.get("DISPLAY") is not None): _call(f"notify-send '{summary}' '{body}'", silent=True) @@ -577,6 +587,10 @@ def build(self): return_code, output = _call_with_output(cmd) if return_code != 0 and "FAILED:" in output: + if "tools/dev/gm.py gen-checked-in-headers" in output: + _notify("V8 build requires your attention", + "Please regenerate the checked-in generated headers.") + return return_code if "snapshot_blob" in output: if "gen-static-roots.py" in output: _notify("V8 build requires your attention", @@ -857,6 +871,14 @@ def parse_arg(self, argstring): arch = "arm64" self.populate_configs([arch], ["release"], ["mkgrokdump"], [], False) return + # Special handling for "gen-checked-in-headers": regenerate the checked-in + # generated headers under src/gen/ (see src/gen/README.md). + if argstring == "gen-checked-in-headers": + sys.exit( + subprocess.call([ + sys.executable, + str(V8_DIR / "tools" / "dev" / "gen-checked-in-headers.py") + ])) if argstring.startswith("--"): # Pass all other flags to test runner. self.testrunner_args.append(argstring) diff --git a/deps/v8/tools/dev/setup_worktree_build.py b/deps/v8/tools/dev/setup_worktree_build.py index 419809f1ac73..264c8785765f 100755 --- a/deps/v8/tools/dev/setup_worktree_build.py +++ b/deps/v8/tools/dev/setup_worktree_build.py @@ -2,15 +2,28 @@ # Copyright 2026 the V8 project authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +"""Sets up shared gclient dependencies for V8 git worktrees. + +When a worktree's DEPS matches the main repository, shared dependency +directories are symlinked directly to the main repository. When DEPS diverges, +a hermetic gclient sync is cached under <main_repo>/worktrees/.deps_cache/<hash> +and symlinked into the worktree. + +Unreferenced cache entries are automatically pruned during sync while keeping +all actively referenced entries and at least MIN_CACHED_DEPS most recently used +entries. Cache management can also be triggered manually via the `prune-cache` +and `clear-cache` subcommands. +""" from contextlib import contextmanager import filecmp import hashlib import os +from pathlib import Path +import pprint import shutil import subprocess import sys -from pathlib import Path try: import fcntl @@ -19,22 +32,33 @@ HAS_FCNTL = False +MIN_CACHED_DEPS = 3 + + @contextmanager -def file_lock(lock_path: Path): +def file_lock(lock_path: Path, blocking: bool = True): if not HAS_FCNTL: - yield + yield True return lock_path.parent.mkdir(parents=True, exist_ok=True) - with open(lock_path, "w") as f: + with open(lock_path, "a") as f: + locked = False try: - fcntl.flock(f, fcntl.LOCK_EX) - yield + flags = fcntl.LOCK_EX | (0 if blocking else fcntl.LOCK_NB) + fcntl.flock(f, flags) + locked = True + except (BlockingIOError, OSError): + if blocking: + raise + try: + yield locked finally: - try: - fcntl.flock(f, fcntl.LOCK_UN) - except OSError: - pass + if locked: + try: + fcntl.flock(f, fcntl.LOCK_UN) + except OSError: + pass def create_relative_symlinks(source_root: Path, target_dir: Path, @@ -92,6 +116,28 @@ def get_shared_dirs(root_entries_file: Path) -> list[str]: return pruned +def write_v8_gclient(src_gclient: Path, dst_gclient: Path): + config = {} + exec(src_gclient.read_text(), config) + solutions = config.get("solutions") + if not isinstance(solutions, list): + print( + f"Error: No 'solutions' list found in {src_gclient}.", file=sys.stderr) + sys.exit(1) + v8_solutions = [ + s for s in solutions if isinstance(s, dict) and s.get("name") == "v8" + ] + if not v8_solutions: + print(f"Error: No 'v8' solution found in {src_gclient}.", file=sys.stderr) + sys.exit(1) + config["solutions"] = v8_solutions + lines = [ + f"{k} = {pprint.pformat(v)}\n" for k, v in config.items() + if not k.startswith("__") + ] + dst_gclient.write_text("".join(lines)) + + def init_deps_cache(main_repo: Path, deps_worktree: Path, shared_dirs: list[str], cache_root: Path, content_hash: str): @@ -146,11 +192,11 @@ def cow_copy(src, dst, *, follow_symlinks=True): except Exception as e: print(f"Warning during caching {d}: {e}", file=sys.stderr) - # Step 5: Preserve custom gclient configurations. + # Step 5: Preserve custom gclient configurations for the v8 solution only. gclient_main = main_repo.parent / ".gclient" gclient_file = tmp_root / ".gclient" if gclient_main.is_file(): - shutil.copy2(gclient_main, gclient_file) + write_v8_gclient(gclient_main, gclient_file) else: print( "Error: .gclient file not found in the parent directory of the main repository.\n" @@ -184,6 +230,11 @@ def cow_copy(src, dst, *, follow_symlinks=True): def should_skip_worktree_deps(worktree_dir: Path) -> bool: + # If {build} is not a symlink, then we're probably in a btrfs CoW snapshot + # rather than a normal git worktree. + build = worktree_dir / "build" + if build.is_dir() and not build.is_symlink(): + return True try: # Check if v8.skip-worktree-deps is set to true in git config res = subprocess.check_output( @@ -223,32 +274,157 @@ def sync_dependencies(main_repo: Path, worktree_dir: Path): create_relative_symlinks(main_repo, worktree_dir, shared_dirs) elif deps_worktree.is_file(): content_hash = hashlib.sha256(deps_worktree.read_bytes()).hexdigest()[:12] - cache_root = main_repo / "worktrees" / ".deps_cache" / content_hash + cache_dir = main_repo / "worktrees" / ".deps_cache" + cache_root = cache_dir / content_hash cache_v8 = cache_root / "v8" - lock_path = cache_root.parent / f"{content_hash}.lock" - with file_lock(lock_path): + with file_lock(cache_dir / ".lock"): if not cache_root.exists(): init_deps_cache(main_repo, deps_worktree, shared_dirs, cache_root, content_hash) cached_shared_dirs = get_shared_dirs(cache_root / ".gclient_entries") create_relative_symlinks(cache_v8, worktree_dir, cached_shared_dirs) + record_worktree_usage(cache_root, worktree_dir) + + prune_cache(main_repo, blocking=False) + + +def record_worktree_usage(cache_root: Path, worktree_dir: Path): + try: + wt_file = cache_root / ".worktrees" + wt_resolved = str(worktree_dir.resolve()) + existing = set() + if wt_file.is_file(): + existing = { + line.strip() + for line in wt_file.read_text().splitlines() + if line.strip() + } + if wt_resolved not in existing: + existing.add(wt_resolved) + wt_file.write_text("\n".join(sorted(existing)) + "\n") + os.utime(cache_root, None) + except OSError: + pass + + +def get_referenced_cache_hashes(main_repo: Path, cache_dir: Path) -> set[str]: + worktrees: set[Path] = set() + try: + out = subprocess.check_output(["git", "worktree", "list", "--porcelain"], + cwd=main_repo, + stderr=subprocess.DEVNULL, + text=True) + for line in out.splitlines(): + if line.startswith("worktree "): + worktrees.add(Path(line[len("worktree "):].strip())) + except Exception: + pass + + worktrees_dir = main_repo / "worktrees" + if worktrees_dir.is_dir(): + for d in worktrees_dir.iterdir(): + if d.name != ".deps_cache" and d.is_dir() and not d.is_symlink(): + worktrees.add(d) + + for item in cache_dir.iterdir(): + wt_file = item / ".worktrees" + if item.is_dir() and wt_file.is_file(): + try: + for line in wt_file.read_text().splitlines(): + if line.strip(): + worktrees.add(Path(line.strip())) + except OSError: + pass + + referenced: set[str] = set() + main_resolved = main_repo.resolve() + cache_resolved = cache_dir.resolve() + deps_main = main_repo / "DEPS" + + for wt in worktrees: + try: + if not wt.is_dir() or not (wt / ".git").exists(): + continue + if wt.resolve() == main_resolved: + continue + except OSError: + continue + + build_link = wt / "build" + if build_link.is_symlink(): + try: + link_target = Path( + os.path.normpath(build_link.parent.resolve() / + os.readlink(build_link))) + rel = link_target.relative_to(cache_resolved) + if rel.parts: + referenced.add(rel.parts[0]) + except (OSError, ValueError): + pass + + deps_wt = wt / "DEPS" + if deps_wt.is_file(): + try: + if not deps_main.is_file() or not filecmp.cmp( + deps_main, deps_wt, shallow=False): + h = hashlib.sha256(deps_wt.read_bytes()).hexdigest()[:12] + referenced.add(h) + except OSError: + pass + + return referenced + + +def prune_cache(main_repo: Path, + min_keep: int = MIN_CACHED_DEPS, + blocking: bool = True): + cache_dir = main_repo / "worktrees" / ".deps_cache" + if not cache_dir.is_dir(): + return + + with file_lock(cache_dir / ".lock", blocking=blocking) as locked: + if not locked: + return + + entries = [] + for item in cache_dir.iterdir(): + if not item.is_dir(): + continue + if item.name.endswith(".tmp"): + shutil.rmtree(item, ignore_errors=True) + else: + try: + entries.append((item.stat().st_mtime, item)) + except OSError: + pass + + if len(entries) <= min_keep: + return + + referenced = get_referenced_cache_hashes(main_repo, cache_dir) + entries.sort(key=lambda x: x[0], reverse=True) + + keep = set(referenced) + for _, item in entries[:min_keep]: + keep.add(item.name) + + for _, item in entries: + if item.name not in keep: + shutil.rmtree(item, ignore_errors=True) def clear_cache(main_repo: Path): cache_dir = main_repo / "worktrees" / ".deps_cache" if cache_dir.exists(): print(f"Clearing worktree dependencies cache at {cache_dir}...") - for item in cache_dir.iterdir(): - if item.is_dir(): - # Strip .tmp suffix to acquire the correct lock during init_deps_cache. - hash_name = item.name[:-4] if item.name.endswith(".tmp") else item.name - lock_path = cache_dir / f"{hash_name}.lock" - with file_lock(lock_path): + with file_lock(cache_dir / ".lock"): + for item in cache_dir.iterdir(): + if item.is_dir(): shutil.rmtree(item, ignore_errors=True) - # We deliberately do not delete .lock files because unlinking them - # while another process might be waiting on them breaks mutual exclusion. + # We deliberately do not delete .lock because unlinking it while another + # process might be waiting on it breaks mutual exclusion. else: print(f"No cache found at {cache_dir}.") @@ -257,9 +433,19 @@ def clear_cache(main_repo: Path): if len(sys.argv) == 3 and sys.argv[1] == "clear-cache": clear_cache(Path(sys.argv[2])) sys.exit(0) - if len(sys.argv) != 3: + if len(sys.argv) == 3 and sys.argv[1] == "prune-cache": + prune_cache(Path(sys.argv[2])) + sys.exit(0) + if len(sys.argv) != 3 or sys.argv[1] in ("-h", "--help"): print("usage:\n" " ./setup_worktree_build.py main_repo worktree_dir\n" - " ./setup_worktree_build.py clear-cache main_repo") - sys.exit(1) + " Set up shared dependency symlinks for worktree_dir and prune\n" + " unreferenced .deps_cache entries.\n" + " ./setup_worktree_build.py prune-cache main_repo\n" + " Remove unreferenced .deps_cache entries, keeping all entries\n" + f" referenced by active worktrees and the {MIN_CACHED_DEPS} most" + " recent entries.\n" + " ./setup_worktree_build.py clear-cache main_repo\n" + " Remove all entries in <main_repo>/worktrees/.deps_cache.") + sys.exit(0 if len(sys.argv) > 1 and sys.argv[1] in ("-h", "--help") else 1) sync_dependencies(Path(sys.argv[1]), Path(sys.argv[2])) diff --git a/deps/v8/tools/dev/update-compile-commands.py b/deps/v8/tools/dev/update-compile-commands.py index ee1b83f5e1a1..7983069f047a 100755 --- a/deps/v8/tools/dev/update-compile-commands.py +++ b/deps/v8/tools/dev/update-compile-commands.py @@ -117,9 +117,9 @@ def GenerateCCFiles(): build_dir = f"out/{DEFAULT_ARCH}.debug" assert os.path.exists(os.path.join(build_dir, "build.ninja")) targets = "v8_generated_cc_files" - # The metagen action only exists when v8_use_metagen_instance_types is on. - if _GetGnArg(build_dir, "v8_use_metagen_instance_types") == "true": - targets += " metagen_instance_types_h" + # The metagen action only exists when v8_use_metagen is on. + if _GetGnArg(build_dir, "v8_use_metagen") == "true": + targets += " run_metagen" _Call(f"autoninja -C {build_dir} {targets}") diff --git a/deps/v8/tools/gcmole/bootstrap.sh b/deps/v8/tools/gcmole/bootstrap.sh index 602f1b2069a7..3dc1c7c6f5dd 100755 --- a/deps/v8/tools/gcmole/bootstrap.sh +++ b/deps/v8/tools/gcmole/bootstrap.sh @@ -38,6 +38,14 @@ BUILD_TYPE="Release" # BUILD_TYPE="Debug" BUILD_DIR="${THIS_DIR}/bootstrap/build" +# Put third_party/ninja on PATH ahead of third_party/depot_tools so cmake and +# ninja invoke the CIPD ninja binary directly instead of depot_tools/ninja, +# which requires an initialized python3_bin_reldir.txt in depot_tools. +THIRD_PARTY_NINJA_DIR="$(readlink -f "${THIS_DIR}/../../third_party/ninja")" +if [ -d "${THIRD_PARTY_NINJA_DIR}" ]; then + export PATH="${THIRD_PARTY_NINJA_DIR}:${PATH}" +fi + # Die if any command dies. set -e diff --git a/deps/v8/tools/gcmole/gcmole-test.cc b/deps/v8/tools/gcmole/gcmole-test.cc index 45d43d583f04..a44c29654620 100644 --- a/deps/v8/tools/gcmole/gcmole-test.cc +++ b/deps/v8/tools/gcmole/gcmole-test.cc @@ -404,6 +404,7 @@ void TestOutParameter(Isolate* isolate) { } class JSDispatchHandleMember; +class CppHeapPointerMember; template <typename T, typename CompressionScheme> class TaggedMember; @@ -412,13 +413,20 @@ JSDispatchHandleMember* ReturnRawJSDispatchHandleMember(Isolate* isolate) { return nullptr; } -JSDispatchHandle* ReturnRawJSDispatchHandle(Isolate* isolate) { +JSDispatchHandle ReturnRawJSDispatchHandle(Isolate* isolate) { CauseGCManaged(42, isolate); - return nullptr; + return kNullJSDispatchHandle; +} + +ExternalPointerHandle ReturnRawExternalPointerHandle(Isolate* isolate) { + CauseGCManaged(42, isolate); + return kNullExternalPointerHandle; } void DummyTakePointers(JSDispatchHandleMember* a, JSDispatchHandleMember* b) {} -void DummyTakePointers2(JSDispatchHandle* a, JSDispatchHandle* b) {} +void DummyTakeHandles(JSDispatchHandle a, JSDispatchHandle b) {} +void DummyTakeExternalPointerHandles(ExternalPointerHandle a, + ExternalPointerHandle b) {} void TestJSDispatchHandleMemberEvalOrder(Isolate* isolate) { // Should cause warning. @@ -428,8 +436,14 @@ void TestJSDispatchHandleMemberEvalOrder(Isolate* isolate) { void TestJSDispatchHandleEvalOrder(Isolate* isolate) { // Should cause warning. - DummyTakePointers2(ReturnRawJSDispatchHandle(isolate), - ReturnRawJSDispatchHandle(isolate)); + DummyTakeHandles(ReturnRawJSDispatchHandle(isolate), + ReturnRawJSDispatchHandle(isolate)); +} + +void TestExternalPointerHandleEvalOrder(Isolate* isolate) { + // Should cause warning. + DummyTakeExternalPointerHandles(ReturnRawExternalPointerHandle(isolate), + ReturnRawExternalPointerHandle(isolate)); } void TestTaggedMemberDeadVar(TaggedMember<Object, void> raw_member, @@ -446,13 +460,88 @@ void TestJSDispatchHandleMemberDeadVar(JSDispatchHandleMember* raw_member, USE(raw_member); } -void TestJSDispatchHandleDeadVar(JSDispatchHandle* raw_handle, +void TestJSDispatchHandleDeadVar(JSDispatchHandle raw_handle, Isolate* isolate) { CauseGCManaged(42, isolate); // Should cause warning. USE(raw_handle); } +void TestExternalPointerHandleDeadVar(ExternalPointerHandle raw_handle, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_handle); +} + +void TestCppHeapPointerHandleDeadVar(CppHeapPointerHandle raw_handle, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_handle); +} + +void TestTrustedPointerHandleDeadVar(TrustedPointerHandle raw_handle, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_handle); +} + +void TestExternalPointerSlotDeadVar(ExternalPointerSlot raw_slot, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_slot); +} + +void TestCppHeapPointerSlotDeadVar(CppHeapPointerSlot raw_slot, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_slot); +} + +void TestExternalPointerMemberDeadVar( + ExternalPointerMember<kAnyExternalPointerTagRange>* raw_member, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_member); +} + +void TestTrustedPointerMemberDeadVar( + TrustedPointerMember<ExposedTrustedObject, kAllTrustedPointerTags>* + raw_member, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_member); +} + +void TestCppHeapPointerMemberDeadVar(CppHeapPointerMember* raw_member, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Should cause warning. + USE(raw_member); +} + +void TestTableHandleSafePatterns(ExternalPointerHandle raw_handle, + ExternalPointerHandle* out_handle, + JSDispatchHandle* out_dispatch_handle, + Isolate* isolate) { + CauseGCManaged(42, isolate); + // Reassigning a table handle after GC should make it live again. + raw_handle = kNullExternalPointerHandle; + USE(raw_handle); + // Global constexpr handle constants and Handle* out-parameters should not + // warn. + USE(kNullExternalPointerHandle); + USE(kNullJSDispatchHandle); + USE(out_handle); + USE(out_dispatch_handle); +} + void TestTaggedMemberPtrDeadVar(TaggedMember<Object, void>* raw_member, Isolate* isolate) { CauseGCManaged(42, isolate); diff --git a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 index e9fcab73887e..3754cd418f5f 100644 --- a/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 +++ b/deps/v8/tools/gcmole/gcmole-tools.tar.gz.sha1 @@ -1 +1 @@ -bc810086fbc612b88056c7a1d61cd61db2f68758 \ No newline at end of file +b2ebe9c7fd0cfa26152fd8d4e787d63b143f4445 \ No newline at end of file diff --git a/deps/v8/tools/gcmole/gcmole.cc b/deps/v8/tools/gcmole/gcmole.cc index 4e1b063ef7f9..3d96a6c39829 100644 --- a/deps/v8/tools/gcmole/gcmole.cc +++ b/deps/v8/tools/gcmole/gcmole.cc @@ -262,6 +262,10 @@ struct Resolver { i++) { clang::NamedDecl* decl = *i; + if (llvm::isa<T>(decl)) { + return llvm::cast<T>(decl); + } + // Try to strip off any type aliases. const clang::TypeAliasDecl* type_alias_decl = llvm::dyn_cast_or_null<clang::TypeAliasDecl>(decl); @@ -290,11 +294,112 @@ struct Resolver { return nullptr; } + template <typename T> + T* ResolveCanonical(const char* n) { + T* decl = Resolve<T>(n); + return decl ? decl->getCanonicalDecl() : nullptr; + } + + clang::CXXRecordDecl* ResolveDefinition(const char* n) { + clang::CXXRecordDecl* decl = Resolve<clang::CXXRecordDecl>(n); + return decl ? decl->getDefinition() : nullptr; + } + private: clang::ASTContext& ctx_; clang::DeclContext* decl_ctx_; }; +struct KnownDecls { + clang::CXXRecordDecl* heap_object = nullptr; + clang::CXXRecordDecl* smi = nullptr; + clang::CXXRecordDecl* tagged_index = nullptr; + clang::CXXRecordDecl* cleared_weak_value = nullptr; + clang::ClassTemplateDecl* tagged = nullptr; + clang::CXXRecordDecl* js_dispatch_handle = nullptr; + clang::TypedefNameDecl* external_pointer_handle = nullptr; + clang::TypedefNameDecl* cpp_heap_pointer_handle = nullptr; + clang::TypedefNameDecl* trusted_pointer_handle = nullptr; + clang::CXXRecordDecl* js_dispatch_handle_member = nullptr; + clang::ClassTemplateDecl* external_pointer_member = nullptr; + clang::ClassTemplateDecl* trusted_pointer_member = nullptr; + clang::CXXRecordDecl* cpp_heap_pointer_member = nullptr; + clang::CXXRecordDecl* external_pointer_slot = nullptr; + clang::CXXRecordDecl* cpp_heap_pointer_slot = nullptr; + clang::CXXRecordDecl* trusted_pointer_slot = nullptr; + clang::ClassTemplateDecl* tagged_member = nullptr; + clang::ClassTemplateDecl* unaligned_value_member = nullptr; + clang::CXXRecordDecl* unaligned_double_member = nullptr; + clang::CXXRecordDecl* no_gc_mole = nullptr; + clang::CXXRecordDecl* conservative_pinning_scope = nullptr; + + static KnownDecls Resolve(clang::ASTContext& ctx) { + Resolver v8_internal = + Resolver(ctx).ResolveNamespace("v8").ResolveNamespace("internal"); + KnownDecls decls; + // It is a valid situation that no_gc_mole == nullptr when DisableGCMole is + // not included and can't be resolved. This is gracefully handled in the + // FunctionAnalyzer later. + decls.no_gc_mole = + v8_internal.Resolve<clang::CXXRecordDecl>("DisableGCMole"); + decls.conservative_pinning_scope = + v8_internal.Resolve<clang::CXXRecordDecl>("ConservativePinningScope"); + decls.heap_object = v8_internal.ResolveDefinition("HeapObject"); + decls.smi = v8_internal.ResolveDefinition("Smi"); + decls.tagged_index = v8_internal.ResolveDefinition("TaggedIndex"); + decls.cleared_weak_value = + v8_internal.Resolve<clang::CXXRecordDecl>("ClearedWeakValue"); + decls.tagged = + v8_internal.ResolveCanonical<clang::ClassTemplateDecl>("Tagged"); + decls.js_dispatch_handle = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>("JSDispatchHandle"); + decls.external_pointer_handle = + v8_internal.ResolveCanonical<clang::TypedefNameDecl>( + "ExternalPointerHandle"); + decls.cpp_heap_pointer_handle = + v8_internal.ResolveCanonical<clang::TypedefNameDecl>( + "CppHeapPointerHandle"); + decls.trusted_pointer_handle = + v8_internal.ResolveCanonical<clang::TypedefNameDecl>( + "TrustedPointerHandle"); + decls.js_dispatch_handle_member = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>( + "JSDispatchHandleMember"); + decls.external_pointer_member = + v8_internal.ResolveCanonical<clang::ClassTemplateDecl>( + "ExternalPointerMember"); + decls.trusted_pointer_member = + v8_internal.ResolveCanonical<clang::ClassTemplateDecl>( + "TrustedPointerMember"); + decls.cpp_heap_pointer_member = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>( + "CppHeapPointerMember"); + decls.external_pointer_slot = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>( + "ExternalPointerSlot"); + decls.cpp_heap_pointer_slot = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>( + "CppHeapPointerSlot"); + decls.trusted_pointer_slot = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>( + "TrustedPointerSlot"); + decls.tagged_member = + v8_internal.ResolveCanonical<clang::ClassTemplateDecl>("TaggedMember"); + decls.unaligned_value_member = + v8_internal.ResolveCanonical<clang::ClassTemplateDecl>( + "UnalignedValueMember"); + decls.unaligned_double_member = + v8_internal.ResolveCanonical<clang::CXXRecordDecl>( + "UnalignedDoubleMember"); + return decls; + } + + bool HasRequiredDecls() const { + return heap_object != nullptr && smi != nullptr && + tagged_index != nullptr && tagged != nullptr; + } +}; + class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> { public: explicit CalleesPrinter(clang::MangleContext* ctx, @@ -799,22 +904,22 @@ static bool IsSuspectedToCauseGC(clang::MangleContext* ctx, } static const int kNoEffect = 0; -static const int kCausesGC = 1; -static const int kRawDef = 2; -static const int kRawUse = 4; +static const int kCausesGC = 1 << 0; +static const int kRawDef = 1 << 1; +static const int kRawUse = 1 << 2; static const int kAllEffects = kCausesGC | kRawDef | kRawUse; class Environment; class ExprEffect { public: - bool hasGC() { return (effect_ & kCausesGC) != 0; } + bool hasGC() const { return (effect_ & kCausesGC) != 0; } void setGC() { effect_ |= kCausesGC; } - bool hasRawDef() { return (effect_ & kRawDef) != 0; } + bool hasRawDef() const { return (effect_ & kRawDef) != 0; } void setRawDef() { effect_ |= kRawDef; } - bool hasRawUse() { return (effect_ & kRawUse) != 0; } + bool hasRawUse() const { return (effect_ & kRawUse) != 0; } void setRawUse() { effect_ |= kRawUse; } static ExprEffect None() { return ExprEffect(kNoEffect, nullptr); } @@ -827,17 +932,16 @@ class ExprEffect { static ExprEffect MergeSeq(ExprEffect a, ExprEffect b); ExprEffect Define(const std::string& name); - Environment* env() { - return reinterpret_cast<Environment*>(effect_ & ~kAllEffects); - } + Environment* env() const { return env_; } static ExprEffect GC() { return ExprEffect(kCausesGC, nullptr); } private: ExprEffect(int effect, Environment* env) - : effect_((effect & kAllEffects) | reinterpret_cast<intptr_t>(env)) {} + : effect_(effect & kAllEffects), env_(env) {} - intptr_t effect_; + int effect_; + Environment* env_; }; const std::string BAD_EXPR_MSG( @@ -854,6 +958,8 @@ class Environment { return env; } + bool IsUnreachable() const { return unreachable_; } + static Environment Merge(const Environment& l, const Environment& r) { Environment out(l); out &= r; @@ -861,7 +967,8 @@ class Environment { } Environment ApplyEffect(ExprEffect effect) const { - Environment out = effect.hasGC() ? Environment() : Environment(*this); + Environment out(*this); + if (effect.hasGC()) out.live_.clear(); if (effect.env()) out |= *effect.env(); return out; } @@ -874,8 +981,9 @@ class Environment { return is_live(code->second); } - bool Equal(const Environment& env) { + bool Equal(const Environment& env) const { if (unreachable_ && env.unreachable_) return true; + if (unreachable_ != env.unreachable_) return false; size_t size = std::max(live_.size(), env.live_.size()); for (size_t i = 0; i < size; ++i) { if (is_live(i) != env.is_live(i)) return false; @@ -884,7 +992,9 @@ class Environment { } Environment Define(const std::string& name) const { - return Environment(*this, SymbolToCode(name)); + Environment out(*this); + out.MDefine(name); + return out; } void MDefine(const std::string& name) { set_live(SymbolToCode(name)); } @@ -926,10 +1036,6 @@ class Environment { } private: - Environment(const Environment& l, int code) : live_(l.live_) { - set_live(code); - } - void set_live(size_t pos) { if (unreachable_) return; if (pos >= live_.size()) live_.resize(pos + 1); @@ -976,6 +1082,7 @@ class Environment { friend class ExprEffect; friend class CallProps; + friend class FunctionAnalyzer; }; class CallProps { @@ -1059,36 +1166,9 @@ static std::string THIS("this"); class FunctionAnalyzer { public: - FunctionAnalyzer(clang::MangleContext* ctx, - clang::CXXRecordDecl* heap_object_decl, - clang::CXXRecordDecl* smi_decl, - clang::CXXRecordDecl* tagged_index_decl, - clang::CXXRecordDecl* cleared_weak_value_decl, - clang::ClassTemplateDecl* tagged_decl, - clang::CXXRecordDecl* js_dispatch_handle_decl, - clang::CXXRecordDecl* js_dispatch_handle_member_decl, - clang::ClassTemplateDecl* tagged_member_decl, - clang::ClassTemplateDecl* unaligned_value_member_decl, - clang::CXXRecordDecl* unaligned_double_member_decl, - clang::CXXRecordDecl* no_gc_mole_decl, - clang::CXXRecordDecl* conservative_pinning_scope_decl, + FunctionAnalyzer(clang::MangleContext* ctx, const KnownDecls& decls, clang::DiagnosticsEngine& d, clang::SourceManager& sm) - : ctx_(ctx), - heap_object_decl_(heap_object_decl), - smi_decl_(smi_decl), - tagged_index_decl_(tagged_index_decl), - cleared_weak_value_decl_(cleared_weak_value_decl), - tagged_decl_(tagged_decl), - js_dispatch_handle_decl_(js_dispatch_handle_decl), - js_dispatch_handle_member_decl_(js_dispatch_handle_member_decl), - tagged_member_decl_(tagged_member_decl), - unaligned_value_member_decl_(unaligned_value_member_decl), - unaligned_double_member_decl_(unaligned_double_member_decl), - no_gc_mole_decl_(no_gc_mole_decl), - conservative_pinning_scope_decl_(conservative_pinning_scope_decl), - d_(d), - sm_(sm), - block_(nullptr) {} + : ctx_(ctx), decls_(decls), d_(d), sm_(sm) {} ~FunctionAnalyzer() { delete ctx_; } @@ -1217,19 +1297,19 @@ class FunctionAnalyzer { DECL_VISIT_EXPR(AbstractConditionalOperator) { Environment after_cond = env.ApplyEffect(VisitExpr(expr->getCond(), env)); - std::vector<GCScope> saved_scopes = scopes_; + std::vector<GCScope> saved_scopes = state_.scopes; ExprEffect true_effect = VisitExpr(expr->getTrueExpr(), after_cond); - std::vector<GCScope> true_scopes = scopes_; + std::vector<GCScope> true_scopes = state_.scopes; - scopes_ = saved_scopes; + state_.scopes = saved_scopes; ExprEffect false_effect = VisitExpr(expr->getFalseExpr(), after_cond); - std::vector<GCScope> false_scopes = scopes_; + std::vector<GCScope> false_scopes = state_.scopes; assert(true_scopes.size() == false_scopes.size()); for (size_t i = 0; i < true_scopes.size(); ++i) { - scopes_[i] = MergeScopes(true_scopes[i], false_scopes[i]); + state_.scopes[i] = MergeScopes(true_scopes[i], false_scopes[i]); } return ExprEffect::Merge(true_effect, false_effect); @@ -1241,9 +1321,8 @@ class FunctionAnalyzer { } bool IsRawPointerVar(clang::Expr* expr, std::string* var_name) { - if (llvm::isa<clang::DeclRefExpr>(expr)) { - *var_name = - llvm::cast<clang::DeclRefExpr>(expr)->getDecl()->getNameAsString(); + if (auto* decl_ref = llvm::dyn_cast<clang::DeclRefExpr>(expr)) { + *var_name = decl_ref->getDecl()->getNameAsString(); return true; } @@ -1263,6 +1342,14 @@ class FunctionAnalyzer { case clang::BO_LOr: return ExprEffect::Merge(VisitExpr(lhs, env), VisitExpr(rhs, env)); + case clang::BO_Assign: { + std::string var_name; + if (IsRawPointerVar(lhs, &var_name)) { + return VisitExpr(rhs, env).Define(var_name); + } + return Parallel(expr, 2, exprs, env); + } + default: return Parallel(expr, 2, exprs, env); } @@ -1389,6 +1476,16 @@ class FunctionAnalyzer { ExprEffect Use(const clang::Expr* parent, const clang::ValueDecl* var, const Environment& env) { if (IsExternalVMState(var)) return ExprEffect::GC(); + if (const auto* var_decl = llvm::dyn_cast<clang::VarDecl>(var)) { + // Environment only tracks liveness for local variables and parameters + // declared inside the analyzed function. Ignore constexpr constants and + // namespace/global-scope variables (such as kNullExternalPointerHandle or + // kNullJSDispatchHandle), which cannot become stale across GCs and are + // never registered in Environment. + if (var_decl->isConstexpr() || !var_decl->isLocalVarDeclOrParm()) { + return ExprEffect::None(); + } + } return Use(parent, var->getType(), var->getNameAsString(), clang::FullSourceLoc(var->getLocation(), sm_), env); } @@ -1410,42 +1507,9 @@ class FunctionAnalyzer { } } - // After visiting the receiver and the arguments of the {call} node, this - // function might report a GC-unsafe usage (due to the undefined evaluation - // order of the receiver and the rest of the arguments). - ExprEffect VisitCallExpr(clang::CallExpr* call, const Environment& env) { - CallProps props; - - clang::CXXMemberCallExpr* memcall = - llvm::dyn_cast_or_null<clang::CXXMemberCallExpr>(call); - if (memcall != nullptr) { - clang::Expr* receiver = memcall->getImplicitObjectArgument(); - props.SetEffect(0, VisitExpr(receiver, env)); - } - - std::string var_name; - clang::CXXOperatorCallExpr* opcall = - llvm::dyn_cast_or_null<clang::CXXOperatorCallExpr>(call); - if (opcall != nullptr && opcall->isAssignmentOp() && - IsRawPointerVar(opcall->getArg(0), &var_name)) { - // TODO(gcmole): We are treating all assignment operator calls with - // the left hand side looking like {raw_pointer_var} as safe independent - // of the concrete assignment operator implementation. This should be - // changed to be more narrow only if the assignment operator of the base - // {Object} or {HeapObject} class was used, which we know to be safe. - props.SetEffect(1, VisitExpr(call->getArg(1), env).Define(var_name)); - } else { - VisitArguments<>(call, &props, env); - } - - if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG); - - ExprEffect out = props.ComputeCumulativeEffect( - RepresentsRawPointerType(call->getType())); - - clang::FunctionDecl* callee = call->getDirectCallee(); - if (callee == nullptr) return out; - + void CheckCallForGCCause(clang::CallExpr* call, + clang::CXXMemberCallExpr* memcall, + clang::FunctionDecl* callee, ExprEffect* out) { const clang::CXXRecordDecl* receiver_record = nullptr; const clang::CXXMethodDecl* method_decl = nullptr; bool is_this_call = false; @@ -1471,33 +1535,33 @@ class FunctionAnalyzer { } if (!is_allowlisted && gc_suspects.find(dummy_mangled) != gc_suspects.end()) { - out.setGC(); - scopes_.back().SetGCCauseLocation( + out->setGC(); + state_.scopes.back().SetGCCauseLocation( clang::FullSourceLoc(call->getExprLoc(), sm_), callee); } } - return out; // Always return out early for virtual calls! + return; // Always return early for virtual calls! } if (IsKnownToCauseGC(ctx_, callee)) { - out.setGC(); - scopes_.back().SetGCCauseLocation( + out->setGC(); + state_.scopes.back().SetGCCauseLocation( clang::FullSourceLoc(call->getExprLoc(), sm_), callee); } // Support for virtual methods that might be GC suspects. - if (memcall == nullptr) return out; + if (memcall == nullptr) return; clang::CXXMethodDecl* method = llvm::dyn_cast_or_null<clang::CXXMethodDecl>(callee); - if (method == nullptr) return out; - if (!method->isVirtual()) return out; + if (method == nullptr) return; + if (!method->isVirtual()) return; clang::CXXMethodDecl* target = method->getDevirtualizedMethod( memcall->getImplicitObjectArgument(), false); if (target != nullptr) { if (IsKnownToCauseGC(ctx_, target)) { - out.setGC(); - scopes_.back().SetGCCauseLocation( + out->setGC(); + state_.scopes.back().SetGCCauseLocation( clang::FullSourceLoc(call->getExprLoc(), sm_), target); } } else { @@ -1506,11 +1570,50 @@ class FunctionAnalyzer { // match of the {method}'s name against the GC suspects in order // to increase coverage. if (IsSuspectedToCauseGC(ctx_, method)) { - out.setGC(); - scopes_.back().SetGCCauseLocation( + out->setGC(); + state_.scopes.back().SetGCCauseLocation( clang::FullSourceLoc(call->getExprLoc(), sm_), method); } } + } + + // After visiting the receiver and the arguments of the {call} node, this + // function might report a GC-unsafe usage (due to the undefined evaluation + // order of the receiver and the rest of the arguments). + ExprEffect VisitCallExpr(clang::CallExpr* call, const Environment& env) { + CallProps props; + + clang::CXXMemberCallExpr* memcall = + llvm::dyn_cast_or_null<clang::CXXMemberCallExpr>(call); + if (memcall != nullptr) { + clang::Expr* receiver = memcall->getImplicitObjectArgument(); + props.SetEffect(0, VisitExpr(receiver, env)); + } + + std::string var_name; + clang::CXXOperatorCallExpr* opcall = + llvm::dyn_cast_or_null<clang::CXXOperatorCallExpr>(call); + if (opcall != nullptr && opcall->isAssignmentOp() && + IsRawPointerVar(opcall->getArg(0), &var_name)) { + // TODO(gcmole): We are treating all assignment operator calls with + // the left hand side looking like {raw_pointer_var} as safe independent + // of the concrete assignment operator implementation. This should be + // changed to be more narrow only if the assignment operator of the base + // {Object} or {HeapObject} class was used, which we know to be safe. + props.SetEffect(1, VisitExpr(call->getArg(1), env).Define(var_name)); + } else { + VisitArguments<>(call, &props, env); + } + + if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG); + + ExprEffect out = props.ComputeCumulativeEffect( + RepresentsRawPointerType(call->getType())); + + clang::FunctionDecl* callee = call->getDirectCallee(); + if (callee == nullptr) return out; + + CheckCallForGCCause(call, memcall, callee, &out); return out; } @@ -1589,7 +1692,7 @@ class FunctionAnalyzer { void MergeIn(const Environment& env) { Environment old_in = in_; - in_ = Environment::Merge(in_, env); + in_ &= env; changed_ = !old_in.Equal(in_); } @@ -1603,9 +1706,7 @@ class FunctionAnalyzer { const Environment& out() { return out_; } - void MergeOut(const Environment& env) { - out_ = Environment::Merge(out_, env); - } + void MergeOut(const Environment& env) { out_ &= env; } void Sequential(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) { Environment a_out = owner_->VisitStmt(a, in()); @@ -1639,17 +1740,17 @@ class FunctionAnalyzer { }; DECL_VISIT_STMT(BreakStmt) { - block_->MergeOut(env); + state_.block->MergeOut(env); return Environment::Unreachable(); } DECL_VISIT_STMT(ContinueStmt) { - block_->MergeIn(env); + state_.block->MergeIn(env); return Environment::Unreachable(); } DECL_VISIT_STMT(CompoundStmt) { - scopes_.push_back(GCScope()); + state_.scopes.push_back(GCScope()); Environment out = env; clang::CompoundStmt::body_iterator end = stmt->body_end(); for (clang::CompoundStmt::body_iterator s = stmt->body_begin(); s != end; @@ -1661,7 +1762,7 @@ class FunctionAnalyzer { } DECL_VISIT_STMT(WhileStmt) { - scopes_.push_back(GCScope()); + state_.scopes.push_back(GCScope()); Block block(env, this); do { block.Loop(stmt->getCond(), stmt->getBody()); @@ -1690,7 +1791,7 @@ class FunctionAnalyzer { } DECL_VISIT_STMT(ForStmt) { - scopes_.push_back(GCScope()); + state_.scopes.push_back(GCScope()); Block block(VisitStmt(stmt->getInit(), env), this); do { block.Loop(stmt->getCond(), stmt->getBody(), stmt->getInc()); @@ -1700,23 +1801,23 @@ class FunctionAnalyzer { } DECL_VISIT_STMT(IfStmt) { - scopes_.push_back(GCScope()); + state_.scopes.push_back(GCScope()); Environment init_out = VisitStmt(stmt->getInit(), env); Environment cond_out = VisitStmt(stmt->getCond(), init_out); - std::vector<GCScope> saved_scopes = scopes_; + std::vector<GCScope> saved_scopes = state_.scopes; Environment then_out = VisitStmt(stmt->getThen(), cond_out); - std::vector<GCScope> then_scopes = scopes_; + std::vector<GCScope> then_scopes = state_.scopes; - scopes_ = saved_scopes; + state_.scopes = saved_scopes; Environment else_out = VisitStmt(stmt->getElse(), cond_out); - std::vector<GCScope> else_scopes = scopes_; + std::vector<GCScope> else_scopes = state_.scopes; assert(then_scopes.size() == else_scopes.size()); for (size_t i = 0; i < then_scopes.size(); ++i) { - scopes_[i] = MergeScopes(then_scopes[i], else_scopes[i]); + state_.scopes[i] = MergeScopes(then_scopes[i], else_scopes[i]); } PopScope(); @@ -1724,7 +1825,7 @@ class FunctionAnalyzer { } DECL_VISIT_STMT(SwitchStmt) { - scopes_.push_back(GCScope()); + state_.scopes.push_back(GCScope()); Block block(env, this); block.Sequential(stmt->getCond(), stmt->getBody()); PopScope(); @@ -1732,13 +1833,13 @@ class FunctionAnalyzer { } DECL_VISIT_STMT(CaseStmt) { - Environment in = Environment::Merge(env, block_->in()); + Environment in = Environment::Merge(env, state_.block->in()); Environment after_lhs = VisitStmt(stmt->getLHS(), in); return VisitStmt(stmt->getSubStmt(), after_lhs); } DECL_VISIT_STMT(DefaultStmt) { - Environment in = Environment::Merge(env, block_->in()); + Environment in = Environment::Merge(env, state_.block->in()); return VisitStmt(stmt->getSubStmt(), in); } @@ -1782,7 +1883,7 @@ class FunctionAnalyzer { if (specialization) { auto* template_decl = specialization->getSpecializedTemplate()->getCanonicalDecl(); - if (template_decl == tagged_decl_) { + if (template_decl == decls_.tagged) { auto& template_args = specialization->getTemplateArgs(); if (template_args.size() != 1) { llvm::errs() << "v8::internal::Tagged<T> should have exactly one " @@ -1799,27 +1900,48 @@ class FunctionAnalyzer { auto* tagged_type_record = template_args[0].getAsType()->getAsCXXRecordDecl(); - return tagged_type_record != smi_decl_ && - tagged_type_record != tagged_index_decl_ && - tagged_type_record != cleared_weak_value_decl_; + return tagged_type_record != decls_.smi && + tagged_type_record != decls_.tagged_index && + tagged_type_record != decls_.cleared_weak_value; } } return false; } - bool IsRawPointerToOnHeapValue(const clang::CXXRecordDecl* record) { - if (record == nullptr) return false; - - if (js_dispatch_handle_decl_ && - record->getCanonicalDecl() == js_dispatch_handle_decl_) { + bool IsTableHandleType(clang::QualType qtype) { + if (qtype.isNull()) return false; + const clang::CXXRecordDecl* record = qtype->getAsCXXRecordDecl(); + if (record && decls_.js_dispatch_handle && + record->getCanonicalDecl() == decls_.js_dispatch_handle) { return true; } - if (js_dispatch_handle_member_decl_ && - record->getCanonicalDecl() == js_dispatch_handle_member_decl_) { - return true; + clang::QualType current = qtype; + while (const auto* td_type = current->getAs<clang::TypedefType>()) { + const clang::TypedefNameDecl* decl = + td_type->getDecl()->getCanonicalDecl(); + if ((decls_.external_pointer_handle && + decl == decls_.external_pointer_handle) || + (decls_.cpp_heap_pointer_handle && + decl == decls_.cpp_heap_pointer_handle) || + (decls_.trusted_pointer_handle && + decl == decls_.trusted_pointer_handle)) { + return true; + } + current = decl->getUnderlyingType(); } - if (unaligned_double_member_decl_ && - record->getCanonicalDecl() == unaligned_double_member_decl_) { + return false; + } + + bool IsOnHeapMemberRecord(const clang::CXXRecordDecl* record) { + if (record == nullptr) return false; + + const clang::CXXRecordDecl* canonical = record->getCanonicalDecl(); + if ((decls_.js_dispatch_handle_member && + canonical == decls_.js_dispatch_handle_member) || + (decls_.cpp_heap_pointer_member && + canonical == decls_.cpp_heap_pointer_member) || + (decls_.unaligned_double_member && + canonical == decls_.unaligned_double_member)) { return true; } @@ -1828,19 +1950,42 @@ class FunctionAnalyzer { if (specialization) { auto* template_decl = specialization->getSpecializedTemplate()->getCanonicalDecl(); - if ((tagged_member_decl_ && template_decl == tagged_member_decl_) || - (unaligned_value_member_decl_ && - template_decl == unaligned_value_member_decl_)) { + if ((decls_.tagged_member && template_decl == decls_.tagged_member) || + (decls_.external_pointer_member && + template_decl == decls_.external_pointer_member) || + (decls_.trusted_pointer_member && + template_decl == decls_.trusted_pointer_member) || + (decls_.unaligned_value_member && + template_decl == decls_.unaligned_value_member)) { return true; } } + return false; + } + bool IsOnHeapClassOrMember(const clang::CXXRecordDecl* record) { + if (record == nullptr) return false; + if (IsOnHeapMemberRecord(record)) return true; if (!InV8Namespace(record)) return false; const clang::CXXRecordDecl* definition = GetDefinitionOrNull(record); if (!definition) return false; - if (IsDerivedFrom(record, heap_object_decl_)) { + return IsDerivedFrom(record, decls_.heap_object); + } + + bool IsRawPointerToOnHeapValue(const clang::CXXRecordDecl* record) { + if (record == nullptr) return false; + if (IsOnHeapClassOrMember(record)) return true; + + const clang::CXXRecordDecl* canonical = record->getCanonicalDecl(); + if ((decls_.external_pointer_slot && + canonical == decls_.external_pointer_slot) || + (decls_.cpp_heap_pointer_slot && + canonical == decls_.cpp_heap_pointer_slot) || + (decls_.trusted_pointer_slot && + canonical == decls_.trusted_pointer_slot)) { return true; } + return false; } @@ -1857,11 +2002,10 @@ class FunctionAnalyzer { } bool IsInternalPointerType(clang::QualType qtype) { - const clang::CXXRecordDecl* record = qtype->getAsCXXRecordDecl(); - if (record && js_dispatch_handle_decl_ && - record->getCanonicalDecl() == js_dispatch_handle_decl_) { - return false; + if (IsTableHandleType(qtype)) { + return true; } + const clang::CXXRecordDecl* record = qtype->getAsCXXRecordDecl(); bool result = IsOnHeapValue(record); TRACE_LLVM_TYPE("is internal " << result, qtype); return result; @@ -1885,32 +2029,33 @@ class FunctionAnalyzer { } bool IsGCGuard(clang::QualType qtype) { - return IsSameType(qtype, no_gc_mole_decl_); + return IsSameType(qtype, decls_.no_gc_mole); } bool IsConservativePinningScope(clang::QualType qtype) { - return IsSameType(qtype, conservative_pinning_scope_decl_); + return IsSameType(qtype, decls_.conservative_pinning_scope); } Environment VisitDecl(clang::Decl* decl, Environment& env) { if (clang::VarDecl* var = llvm::dyn_cast<clang::VarDecl>(decl)) { - Environment out = var->hasInit() ? VisitStmt(var->getInit(), env) : env; + bool is_param = llvm::isa<clang::ParmVarDecl>(decl); + Environment out = + (!is_param && var->hasInit()) ? VisitStmt(var->getInit(), env) : env; clang::QualType var_type = var->getType(); - if (llvm::dyn_cast<clang::ParmVarDecl>(decl) && - var_type->isReferenceType()) { + if (is_param && var_type->isReferenceType()) { var_type = var_type->getAs<clang::ReferenceType>()->getPointeeType(); } if (RepresentsRawPointerType(var_type)) { - out = out.Define(var->getNameAsString()); + out.MDefine(var->getNameAsString()); } if (IsGCGuard(var_type)) { - scopes_.back().guard_location = + state_.scopes.back().guard_location = clang::FullSourceLoc(decl->getLocation(), sm_); } if (IsConservativePinningScope(var_type)) { - scopes_.back().conservative_pinning_scope_location = + state_.scopes.back().conservative_pinning_scope_location = clang::FullSourceLoc(decl->getLocation(), sm_); } @@ -1936,8 +2081,7 @@ class FunctionAnalyzer { clang::FunctionDecl::param_const_iterator end = f->param_end(); for (clang::FunctionDecl::param_const_iterator p = f->param_begin(); p != end; ++p) { - env.MDefine((*p)->getNameAsString()); - VisitDecl(*p, env); + env = VisitDecl(*p, env); } } @@ -1945,7 +2089,7 @@ class FunctionAnalyzer { const clang::FunctionDecl* body = nullptr; if (f->hasBody(body)) { Environment env; - scopes_.push_back(GCScope()); + state_.scopes.push_back(GCScope()); DefineAndVisitParameters(body, env); VisitStmt(body->getBody(), env); PopScope(); @@ -1954,15 +2098,15 @@ class FunctionAnalyzer { } Block* EnterBlock(Block* block) { - Block* parent = block_; - block_ = block; + Block* parent = state_.block; + state_.block = block; return parent; } - void LeaveBlock(Block* block) { block_ = block; } + void LeaveBlock(Block* block) { state_.block = block; } bool HasActiveGuard() { - for (const auto& s : scopes_) { + for (const auto& s : state_.scopes) { if (s.IsBeforeGCCause()) return true; } return false; @@ -1970,7 +2114,7 @@ class FunctionAnalyzer { bool HasActiveConservativePinning( const clang::FullSourceLoc decl_location) const { - for (const auto& s : scopes_) { + for (const auto& s : state_.scopes) { if (s.IsAfterConservativePinningScope(decl_location)) return true; } return false; @@ -2065,7 +2209,7 @@ class FunctionAnalyzer { << msg; // Find the relevant GC scope (see HasActiveGuard). const GCScope* pscope = nullptr; - for (auto ri = scopes_.rbegin(); ri != scopes_.rend(); ++ri) { + for (auto ri = state_.scopes.rbegin(); ri != state_.scopes.rend(); ++ri) { if (!ri->IsBeforeGCCause() && ri->gccause_location.isValid()) { pscope = &(*ri); break; @@ -2095,24 +2239,7 @@ class FunctionAnalyzer { PrintGCCauseTree(name, visited); } - clang::MangleContext* ctx_; - clang::CXXRecordDecl* heap_object_decl_; - clang::CXXRecordDecl* smi_decl_; - clang::CXXRecordDecl* tagged_index_decl_; - clang::CXXRecordDecl* cleared_weak_value_decl_; - clang::ClassTemplateDecl* tagged_decl_; - clang::CXXRecordDecl* js_dispatch_handle_decl_; - clang::CXXRecordDecl* js_dispatch_handle_member_decl_; - clang::ClassTemplateDecl* tagged_member_decl_; - clang::ClassTemplateDecl* unaligned_value_member_decl_; - clang::CXXRecordDecl* unaligned_double_member_decl_; - clang::CXXRecordDecl* no_gc_mole_decl_; - clang::CXXRecordDecl* conservative_pinning_scope_decl_; - - clang::DiagnosticsEngine& d_; - clang::SourceManager& sm_; - Block* block_; struct GCScope { clang::FullSourceLoc guard_location; @@ -2161,18 +2288,28 @@ class FunctionAnalyzer { } void PopScope() { - if (scopes_.size() > 1) { - GCScope& inner = scopes_.back(); - GCScope& outer = scopes_[scopes_.size() - 2]; + if (state_.scopes.size() > 1) { + GCScope& inner = state_.scopes.back(); + GCScope& outer = state_.scopes[state_.scopes.size() - 2]; if (inner.gccause_location.isValid()) { outer.gccause_location = inner.gccause_location; outer.gccause_decl = inner.gccause_decl; } } - scopes_.pop_back(); + state_.scopes.pop_back(); } - std::vector<GCScope> scopes_; + struct AnalysisState { + std::vector<GCScope> scopes; + Block* block = nullptr; + }; + + clang::MangleContext* ctx_; + KnownDecls decls_; + clang::DiagnosticsEngine& d_; + clang::SourceManager& sm_; + + AnalysisState state_; }; class ProblemsFinder : public clang::ASTConsumer, @@ -2231,108 +2368,22 @@ class ProblemsFinder : public clang::ASTConsumer, void HandleTranslationUnit(clang::ASTContext& ctx) override { if (TranslationUnitIgnored()) return; - Resolver r(ctx); - - // It is a valid situation that no_gc_mole_decl == nullptr when - // DisableGCMole is not included and can't be resolved. This is gracefully - // handled in the FunctionAnalyzer later. - auto v8_internal = r.ResolveNamespace("v8").ResolveNamespace("internal"); - clang::CXXRecordDecl* no_gc_mole_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("DisableGCMole"); - - clang::CXXRecordDecl* conservative_pinning_scope_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("ConservativePinningScope"); - - clang::CXXRecordDecl* heap_object_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("HeapObject"); - - clang::CXXRecordDecl* smi_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("Smi"); - - clang::CXXRecordDecl* tagged_index_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("TaggedIndex"); - - clang::CXXRecordDecl* cleared_weak_value_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("ClearedWeakValue"); - - clang::ClassTemplateDecl* tagged_decl = - v8_internal.Resolve<clang::ClassTemplateDecl>("Tagged"); - - clang::CXXRecordDecl* js_dispatch_handle_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("JSDispatchHandle"); - - clang::CXXRecordDecl* js_dispatch_handle_member_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("JSDispatchHandleMember"); - - clang::ClassTemplateDecl* tagged_member_decl = - v8_internal.Resolve<clang::ClassTemplateDecl>("TaggedMember"); - - clang::ClassTemplateDecl* unaligned_value_member_decl = - v8_internal.Resolve<clang::ClassTemplateDecl>("UnalignedValueMember"); - - clang::CXXRecordDecl* unaligned_double_member_decl = - v8_internal.Resolve<clang::CXXRecordDecl>("UnalignedDoubleMember"); - - if (heap_object_decl != nullptr) { - heap_object_decl = heap_object_decl->getDefinition(); - } - - if (smi_decl != nullptr) { - smi_decl = smi_decl->getDefinition(); - } - - if (tagged_index_decl != nullptr) { - tagged_index_decl = tagged_index_decl->getDefinition(); - } - - if (tagged_decl != nullptr) { - tagged_decl = tagged_decl->getCanonicalDecl(); - } - - if (js_dispatch_handle_decl != nullptr) { - js_dispatch_handle_decl = js_dispatch_handle_decl->getCanonicalDecl(); - } - - if (js_dispatch_handle_member_decl != nullptr) { - js_dispatch_handle_member_decl = - js_dispatch_handle_member_decl->getCanonicalDecl(); - } - - if (tagged_member_decl != nullptr) { - tagged_member_decl = tagged_member_decl->getCanonicalDecl(); - } - - if (unaligned_value_member_decl != nullptr) { - unaligned_value_member_decl = - unaligned_value_member_decl->getCanonicalDecl(); - } - - if (unaligned_double_member_decl != nullptr) { - unaligned_double_member_decl = - unaligned_double_member_decl->getCanonicalDecl(); - } - - if (heap_object_decl != nullptr && smi_decl != nullptr && - tagged_index_decl != nullptr && tagged_decl != nullptr) { + KnownDecls decls = KnownDecls::Resolve(ctx); + if (decls.HasRequiredDecls()) { function_analyzer_ = new FunctionAnalyzer( - clang::ItaniumMangleContext::create(ctx, d_), heap_object_decl, - smi_decl, tagged_index_decl, cleared_weak_value_decl, tagged_decl, - js_dispatch_handle_decl, js_dispatch_handle_member_decl, - tagged_member_decl, unaligned_value_member_decl, - unaligned_double_member_decl, no_gc_mole_decl, - conservative_pinning_scope_decl, d_, sm_); + clang::ItaniumMangleContext::create(ctx, d_), decls, d_, sm_); TraverseDecl(ctx.getTranslationUnitDecl()); } else if (g_verbose) { - if (heap_object_decl == nullptr) { + if (decls.heap_object == nullptr) { llvm::errs() << "Failed to resolve v8::internal::HeapObject\n"; } - if (smi_decl == nullptr) { + if (decls.smi == nullptr) { llvm::errs() << "Failed to resolve v8::internal::Smi\n"; } - if (tagged_index_decl == nullptr) { + if (decls.tagged_index == nullptr) { llvm::errs() << "Failed to resolve v8::internal::TaggedIndex\n"; } - if (tagged_decl == nullptr) { + if (decls.tagged == nullptr) { llvm::errs() << "Failed to resolve v8::internal::Tagged<T>\n"; } } diff --git a/deps/v8/tools/gcmole/package.sh b/deps/v8/tools/gcmole/package.sh index 0b9949a4e52e..7dda9b0d3f12 100755 --- a/deps/v8/tools/gcmole/package.sh +++ b/deps/v8/tools/gcmole/package.sh @@ -57,7 +57,7 @@ echo $(readlink -f "${PACKAGE_FILE}") echo echo Upload the update package to the chrome infra: echo -echo 'gsutil.py cp tools/gcmole/gcmole-tools.tar.gz gs://chrome-v8-gcmole/$(cat tools/gcmole/gcmole-tools.tar.gz.sha1)' +echo 'gcloud storage cp tools/gcmole/gcmole-tools.tar.gz gs://chrome-v8-gcmole/$(cat tools/gcmole/gcmole-tools.tar.gz.sha1)' echo echo Run bootstrap.sh in chroot if glibc versions mismatch with bots: echo '# Create chroot' diff --git a/deps/v8/tools/gcmole/test-expectations.txt b/deps/v8/tools/gcmole/test-expectations.txt index d2ccda0094b3..33dae5060888 100644 --- a/deps/v8/tools/gcmole/test-expectations.txt +++ b/deps/v8/tools/gcmole/test-expectations.txt @@ -239,103 +239,184 @@ tools/gcmole/gcmole-test.cc:356:3: note: Call might cause unexpected GC. tools/gcmole/gcmole-test.cc:25:1: note: GC call here. 25 | void Safepoint() { LocalHeap::Current()->Safepoint(); } | ^ -tools/gcmole/gcmole-test.cc:425:3: warning: Possible problem with evaluation order with interleaved GCs. - 425 | DummyTakePointers(ReturnRawJSDispatchHandleMember(isolate), +tools/gcmole/gcmole-test.cc:433:3: warning: Possible problem with evaluation order with interleaved GCs. + 433 | DummyTakePointers(ReturnRawJSDispatchHandleMember(isolate), | ^ -tools/gcmole/gcmole-test.cc:426:21: note: Call might cause unexpected GC. - 426 | ReturnRawJSDispatchHandleMember(isolate)); +tools/gcmole/gcmole-test.cc:434:21: note: Call might cause unexpected GC. + 434 | ReturnRawJSDispatchHandleMember(isolate)); | ^ -tools/gcmole/gcmole-test.cc:410:1: note: GC call here. - 410 | JSDispatchHandleMember* ReturnRawJSDispatchHandleMember(Isolate* isolate) { +tools/gcmole/gcmole-test.cc:411:1: note: GC call here. + 411 | JSDispatchHandleMember* ReturnRawJSDispatchHandleMember(Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:431:3: warning: Possible problem with evaluation order with interleaved GCs. - 431 | DummyTakePointers2(ReturnRawJSDispatchHandle(isolate), +tools/gcmole/gcmole-test.cc:439:3: warning: Possible problem with evaluation order with interleaved GCs. + 439 | DummyTakeHandles(ReturnRawJSDispatchHandle(isolate), | ^ -tools/gcmole/gcmole-test.cc:432:22: note: Call might cause unexpected GC. - 432 | ReturnRawJSDispatchHandle(isolate)); - | ^ -tools/gcmole/gcmole-test.cc:415:1: note: GC call here. - 415 | JSDispatchHandle* ReturnRawJSDispatchHandle(Isolate* isolate) { +tools/gcmole/gcmole-test.cc:440:20: note: Call might cause unexpected GC. + 440 | ReturnRawJSDispatchHandle(isolate)); + | ^ +tools/gcmole/gcmole-test.cc:416:1: note: GC call here. + 416 | JSDispatchHandle ReturnRawJSDispatchHandle(Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:439:7: warning: Possibly stale variable due to GCs. - 439 | USE(raw_member); +tools/gcmole/gcmole-test.cc:445:3: warning: Possible problem with evaluation order with interleaved GCs. + 445 | DummyTakeExternalPointerHandles(ReturnRawExternalPointerHandle(isolate), + | ^ +tools/gcmole/gcmole-test.cc:446:35: note: Call might cause unexpected GC. + 446 | ReturnRawExternalPointerHandle(isolate)); + | ^ +tools/gcmole/gcmole-test.cc:421:1: note: GC call here. + 421 | ExternalPointerHandle ReturnRawExternalPointerHandle(Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:453:7: warning: Possibly stale variable due to GCs. + 453 | USE(raw_member); | ^ -tools/gcmole/gcmole-test.cc:437:3: note: Call might cause unexpected GC. - 437 | CauseGCManaged(42, isolate); +tools/gcmole/gcmole-test.cc:451:3: note: Call might cause unexpected GC. + 451 | CauseGCManaged(42, isolate); | ^ tools/gcmole/gcmole-test.cc:39:1: note: GC call here. 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:446:7: warning: Possibly stale variable due to GCs. - 446 | USE(raw_member); +tools/gcmole/gcmole-test.cc:460:7: warning: Possibly stale variable due to GCs. + 460 | USE(raw_member); | ^ -tools/gcmole/gcmole-test.cc:444:3: note: Call might cause unexpected GC. - 444 | CauseGCManaged(42, isolate); +tools/gcmole/gcmole-test.cc:458:3: note: Call might cause unexpected GC. + 458 | CauseGCManaged(42, isolate); | ^ tools/gcmole/gcmole-test.cc:39:1: note: GC call here. 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:453:7: warning: Possibly stale variable due to GCs. - 453 | USE(raw_handle); +tools/gcmole/gcmole-test.cc:467:7: warning: Possibly stale variable due to GCs. + 467 | USE(raw_handle); | ^ -tools/gcmole/gcmole-test.cc:451:3: note: Call might cause unexpected GC. - 451 | CauseGCManaged(42, isolate); +tools/gcmole/gcmole-test.cc:465:3: note: Call might cause unexpected GC. + 465 | CauseGCManaged(42, isolate); | ^ tools/gcmole/gcmole-test.cc:39:1: note: GC call here. 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:460:7: warning: Possibly stale variable due to GCs. - 460 | USE(raw_member); +tools/gcmole/gcmole-test.cc:474:7: warning: Possibly stale variable due to GCs. + 474 | USE(raw_handle); | ^ -tools/gcmole/gcmole-test.cc:458:3: note: Call might cause unexpected GC. - 458 | CauseGCManaged(42, isolate); +tools/gcmole/gcmole-test.cc:472:3: note: Call might cause unexpected GC. + 472 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:481:7: warning: Possibly stale variable due to GCs. + 481 | USE(raw_handle); + | ^ +tools/gcmole/gcmole-test.cc:479:3: note: Call might cause unexpected GC. + 479 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:488:7: warning: Possibly stale variable due to GCs. + 488 | USE(raw_handle); + | ^ +tools/gcmole/gcmole-test.cc:486:3: note: Call might cause unexpected GC. + 486 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:495:7: warning: Possibly stale variable due to GCs. + 495 | USE(raw_slot); + | ^ +tools/gcmole/gcmole-test.cc:493:3: note: Call might cause unexpected GC. + 493 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:502:7: warning: Possibly stale variable due to GCs. + 502 | USE(raw_slot); + | ^ +tools/gcmole/gcmole-test.cc:500:3: note: Call might cause unexpected GC. + 500 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:510:7: warning: Possibly stale variable due to GCs. + 510 | USE(raw_member); + | ^ +tools/gcmole/gcmole-test.cc:508:3: note: Call might cause unexpected GC. + 508 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:519:7: warning: Possibly stale variable due to GCs. + 519 | USE(raw_member); + | ^ +tools/gcmole/gcmole-test.cc:517:3: note: Call might cause unexpected GC. + 517 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:526:7: warning: Possibly stale variable due to GCs. + 526 | USE(raw_member); + | ^ +tools/gcmole/gcmole-test.cc:524:3: note: Call might cause unexpected GC. + 524 | CauseGCManaged(42, isolate); + | ^ +tools/gcmole/gcmole-test.cc:39:1: note: GC call here. + 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { + | ^ +tools/gcmole/gcmole-test.cc:549:7: warning: Possibly stale variable due to GCs. + 549 | USE(raw_member); + | ^ +tools/gcmole/gcmole-test.cc:547:3: note: Call might cause unexpected GC. + 547 | CauseGCManaged(42, isolate); | ^ tools/gcmole/gcmole-test.cc:39:1: note: GC call here. 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:466:7: warning: Possibly stale variable due to GCs. - 466 | USE(raw_obj); +tools/gcmole/gcmole-test.cc:555:7: warning: Possibly stale variable due to GCs. + 555 | USE(raw_obj); | ^ -tools/gcmole/gcmole-test.cc:464:3: note: Call might cause unexpected GC. - 464 | CauseGCManaged(42, isolate); +tools/gcmole/gcmole-test.cc:553:3: note: Call might cause unexpected GC. + 553 | CauseGCManaged(42, isolate); | ^ tools/gcmole/gcmole-test.cc:39:1: note: GC call here. 39 | Tagged<Managed<int>> CauseGCManaged(int i, Isolate* isolate) { | ^ -tools/gcmole/gcmole-test.cc:510:9: warning: Possibly stale variable due to GCs. - 510 | Print(raw_obj); +tools/gcmole/gcmole-test.cc:599:9: warning: Possibly stale variable due to GCs. + 599 | Print(raw_obj); | ^ -tools/gcmole/gcmole-test.cc:508:11: note: Call might cause unexpected GC. - 508 | visitor.VisitPointer(raw_obj, slot); +tools/gcmole/gcmole-test.cc:597:11: note: Call might cause unexpected GC. + 597 | visitor.VisitPointer(raw_obj, slot); | ^ ./src/objects/visitors.h:<number>:<number>: note: GC call here. | virtual void VisitPointer(Tagged<HeapObject> host, ObjectSlot p) { | ^ -tools/gcmole/gcmole-test.cc:524:9: warning: Possibly stale variable due to GCs. - 524 | Print(raw_obj); +tools/gcmole/gcmole-test.cc:613:9: warning: Possibly stale variable due to GCs. + 613 | Print(raw_obj); | ^ -tools/gcmole/gcmole-test.cc:522:17: note: Call might cause unexpected GC. - 522 | base_visitor->VisitPointer(raw_obj, slot); +tools/gcmole/gcmole-test.cc:611:17: note: Call might cause unexpected GC. + 611 | base_visitor->VisitPointer(raw_obj, slot); | ^ ./src/objects/visitors.h:<number>:<number>: note: GC call here. | virtual void VisitPointer(Tagged<HeapObject> host, ObjectSlot p) { | ^ -tools/gcmole/gcmole-test.cc:558:9: warning: Possibly stale variable due to GCs. - 558 | Print(raw_obj); +tools/gcmole/gcmole-test.cc:647:9: warning: Possibly stale variable due to GCs. + 647 | Print(raw_obj); | ^ -tools/gcmole/gcmole-test.cc:557:17: note: Call might cause unexpected GC. - 557 | base_visitor->VisitPointer(raw_obj, slot); +tools/gcmole/gcmole-test.cc:646:17: note: Call might cause unexpected GC. + 646 | base_visitor->VisitPointer(raw_obj, slot); | ^ ./src/objects/visitors.h:<number>:<number>: note: GC call here. | virtual void VisitPointer(Tagged<HeapObject> host, ObjectSlot p) { | ^ -tools/gcmole/gcmole-test.cc:574:9: warning: Possibly stale variable due to GCs. - 574 | Print(raw_obj); +tools/gcmole/gcmole-test.cc:663:9: warning: Possibly stale variable due to GCs. + 663 | Print(raw_obj); | ^ -tools/gcmole/gcmole-test.cc:573:11: note: Call might cause unexpected GC. - 573 | visitor.VisitPointer(raw_obj, slot); +tools/gcmole/gcmole-test.cc:662:11: note: Call might cause unexpected GC. + 662 | visitor.VisitPointer(raw_obj, slot); | ^ ./src/objects/visitors.h:<number>:<number>: note: GC call here. | virtual void VisitPointer(Tagged<HeapObject> host, ObjectSlot p) { | ^ -37 warnings generated. +46 warnings generated. diff --git a/deps/v8/tools/jj/README.md b/deps/v8/tools/jj/README.md new file mode 100644 index 000000000000..db05e040cf6b --- /dev/null +++ b/deps/v8/tools/jj/README.md @@ -0,0 +1,52 @@ +# Jujutsu (jj) in V8 + +> [!NOTE] +> **WIP Solution**: This is a temporary setup adapted from Chromium (`//tools/jj`) +> until the shared tooling is finalized in `depot_tools/jj`. + +--- + +## 1. Setup + +In your colocated V8 repository root: + +```bash +# Initialize jj if not already done +jj git init --colocate . + +# Link this config to the repo-level jj configuration +ln -sf "$(pwd)/tools/jj/config.toml" "$(jj config path --repo)" +``` + +--- + +## 2. How to use it + +### Working with commits +Most commands for working locally with commits work just fine. Git submodules (DEPS) are not yet supported by `jj`: whenever you see `jj` say "ignoring git submodule" (or switch across commits with dependency changes), run `gclient sync`. + +To start a new change off trunk: +```bash +jj git fetch +jj new trunk() +``` + +### Syncing code +```bash +jj sync +``` +Uses the alias in `tools/jj/config.toml` (fetches `origin` and rebases current stack onto `trunk()`). + +If a sync results in a conflict, resolve it directly in the files or use `jj resolve`. Use `jj evolog -r <revision>` to inspect the pre-conflict state. + +### Uploading code +```bash +jj upload +``` +Uses the alias in `tools/jj/config.toml` (runs `jj fix` on mutable revisions in the stack and uploads to Gerrit). + +### Running formatters +```bash +jj fix +``` +Uses the configuration in `tools/jj/config.toml` (mirrors `git cl format`: `clang_format.py` on changed C++ lines, `gn format` for GN/GNI, JS untouched). diff --git a/deps/v8/tools/jj/config.toml b/deps/v8/tools/jj/config.toml new file mode 100644 index 000000000000..ad6138f304c3 --- /dev/null +++ b/deps/v8/tools/jj/config.toml @@ -0,0 +1,64 @@ +[workspace] +auto-update-stale = true + +[git] +auto-local-bookmark = false +write-change-id-header = true + +[gerrit] +default-remote = "origin" +default-remote-branch = "main" + +[revset-aliases] +"trunk()" = "main@origin" +"immutable_heads()" = "remote_bookmarks() | tags()" + +[aliases] +# Gerrit CL URL preview matching Chromium +# ("6a6a6964" = ASCII "jjid" padding 32-hex jj UUID to 40-hex Gerrit Change-Id) +"gerrit-url" = [ + "log", + "--no-graph", + "-T", + '"https://chromium-review.googlesource.com/q/" ++ if(trailers.contains_key("Change-Id"), trailers.filter(|t| t.key() == "Change-Id").map(|t| t.value()), "I" ++ change_id.normal_hex() ++ "6a6a6964") ++ "\n"' +] + +# Chromium-style porcelain aliases +"v8-sync" = ["util", "exec", "--", "bash", "-c", """ +jj git fetch +jj rebase -b 'mutable() & ::@' -d 'trunk()' --skip-emptied +""", ""] +"sync" = ["v8-sync"] + +# Runs `jj fix` on the stack, then pushes to Gerrit +"v8-upload" = ["util", "exec", "--", "bash", "-c", """ +rev="@" +prev="" +for arg in "$@"; do + if [ "$prev" = "-r" ]; then rev="$arg"; break; fi + prev="$arg" +done +jj fix -s "mutable()::($rev)" +jj gerrit upload "$@" +""", ""] +"upload" = ["v8-upload"] + +[fix.tools.google3format] +enabled = false +# If you're not using the google-internal jj, this will complain that +# google3format is an invalid fix tool because it has no command/patterns +command = ["/dev/null"] +patterns = ["null"] + +# The source of truth for formatters is depot_tools' git_cl.py +# Mirror plain `git cl format`: C++ only on changed lines (clang-format-diff), +# no JS (V8 doesn't set FORMAT_JS). `git cl format --stdin-filename` formats +# whole files, so it's only used where `git cl format` does too (GN). +[fix.tools.clang-format] +command = ["clang_format.py", "--assume-filename=$path"] +line-range-arg = "--lines=$first:$last" +patterns = ["glob:'**/*.cc'", "glob:'**/*.h'"] + +[fix.tools.git-cl-format] +command = ["git", "cl", "format", "--stdin-filename=$path"] +patterns = ["glob:'**/*.gn'", "glob:'**/*.gni'"] diff --git a/deps/v8/tools/metagen/PRESUBMIT.py b/deps/v8/tools/metagen/PRESUBMIT.py new file mode 100644 index 000000000000..42d888eb8be0 --- /dev/null +++ b/deps/v8/tools/metagen/PRESUBMIT.py @@ -0,0 +1,32 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +USE_PYTHON3 = True + + +def _RunTests(input_api, output_api): + return input_api.RunTests( + input_api.canned_checks.GetUnitTestsInDirectory( + input_api, + output_api, + 'test', + files_to_check=[r'.+_test\.py$'], + run_on_python2=False)) + + +def _CommonChecks(input_api, output_api): + """Checks common to both upload and commit.""" + checks = [ + _RunTests, + ] + + return sum([check(input_api, output_api) for check in checks], []) + + +def CheckChangeOnCommit(input_api, output_api): + return _CommonChecks(input_api, output_api) + + +def CheckChangeOnUpload(input_api, output_api): + return _CommonChecks(input_api, output_api) diff --git a/deps/v8/tools/metagen/clang_bootstrap.py b/deps/v8/tools/metagen/clang_bootstrap.py index 4afb046e1130..3c0a305933bb 100644 --- a/deps/v8/tools/metagen/clang_bootstrap.py +++ b/deps/v8/tools/metagen/clang_bootstrap.py @@ -43,7 +43,7 @@ output ships in the V8 build. The clang builtin headers (stddef.h etc.) are a separate input handled -by metagen.py's --clang-resource-dir / --clang-builtin-headers-dir. +by metagen.py's --clang-resource-dir. """ from __future__ import annotations diff --git a/deps/v8/tools/metagen/compile_flags.py b/deps/v8/tools/metagen/compile_flags.py index 30024b7f283a..cc585f458381 100644 --- a/deps/v8/tools/metagen/compile_flags.py +++ b/deps/v8/tools/metagen/compile_flags.py @@ -24,10 +24,9 @@ file, response files). The clang builtin headers (stddef.h etc.) are not handled here: the -build system points metagen.py at the toolchain that holds them, via ---clang-resource-dir or --clang-builtin-headers-dir. Probing for them -would read paths the build never declared, which a sandboxed action -cannot do. +build system passes their toolchain's resource directory to metagen.py +via --clang-resource-dir. Probing for headers would read paths the build +never declared, which a sandboxed action cannot do. """ from __future__ import annotations @@ -37,6 +36,7 @@ import shutil import subprocess import sys +import tempfile # Single-token drops: compile-only and dep-info flags (these only occur # in the Bazel-synthesized command line; gn desc cflags never carry @@ -118,14 +118,6 @@ def _find_gn(source_root: str) -> str | None: return shutil.which("gn") -def _is_clang_cl(arg0: str) -> bool: - """Detect clang-cl driver by argv[0]'s basename.""" - name = os.path.basename(arg0).lower() - if name.endswith(".exe"): - name = name[:-4] - return name == "clang-cl" - - def _filter(args: list[str], input_path: str) -> list[str]: out: list[str] = [] norm_input = os.path.normpath(input_path) if input_path else "" @@ -157,59 +149,107 @@ def _filter(args: list[str], input_path: str) -> list[str]: return out -def get_compile_args_from_gn_desc( - build_dir: str, target_label: str, - source_root: str) -> tuple[list[str], str, bool]: +def get_compile_args_from_gn_desc(build_dir: str, target_label: str, + source_root: str) -> tuple[list[str], str]: """GN path: reconstruct one target's compile flags via `gn desc`. `source_root` is the directory holding the build's `.gn` marker. The caller passes it in because the build dir need not sit under it. - Returns (flags, cwd, cl_mode): + Returns (flags, cwd): flags libclang args. Path-bearing flags (-I, -isystem, ...) are left as-is; the caller must invoke libclang with cwd=`cwd` so build-dir-relative paths resolve. cwd The build dir (cflags' paths are relative to it). - cl_mode True iff the toolchain is clang-cl. The caller injects - `--driver-mode=cl` when this is set. cflags/cflags_cc are passed through verbatim; include_dirs are source-absolute `//...` and rebased against `source_root` here. """ source_root = os.path.abspath(source_root) + build_dir = os.path.abspath(build_dir) gn = _find_gn(source_root) if not gn: raise RuntimeError( "[metagen] gn not found under <source-root>/buildtools or on PATH.") - out_rel = os.path.relpath(os.path.abspath(build_dir), source_root) - try: - # -q ("don't print output on success") keeps stdout to the JSON alone. - # Without it gn prepends any build-file warning to the document -- an - # arm_float_abi that no declare_args() claims on the arm64 bots, say -- - # and the parse below fails. A gn that actually fails still reports. - proc = subprocess.run( - [gn, "desc", "-q", out_rel, target_label, "--format=json"], - cwd=source_root, - capture_output=True, - text=True, - check=True, - ) - except FileNotFoundError: - raise RuntimeError(f"[metagen] gn binary not found: {gn}") - except subprocess.CalledProcessError as e: - raise RuntimeError(f"[metagen] `gn desc {out_rel} {target_label}` failed " - f"(exit {e.returncode}). Has `gn gen` run there?\n" - f"{(e.stderr or '').strip()}") - try: - desc = json.loads(proc.stdout) - except json.JSONDecodeError as e: - raise RuntimeError(f"[metagen] `gn desc` output was not valid JSON: {e}") - if not isinstance(desc, dict) or not desc: - raise RuntimeError( - f"[metagen] `gn desc` returned no target for {target_label}.") - # Single-target query: the sole value maps the (toolchain-qualified) - # label to its resolved fields. - fields = next(iter(desc.values())) + # GN evaluates build files during `desc`. Some Chromium build scripts write + # into the output directory, so querying the active directory during a build + # can race with other actions reading those files. + # See https://chromium.googlesource.com/chromium/src/+/refs/heads/main/tools/licenses/licenses.py#1005 + # TODO(jgruber): Pass the resolved flags through GN substitutions instead. + with tempfile.TemporaryDirectory(dir=os.path.dirname(build_dir)) as tmp_dir: + shutil.copyfile( + os.path.join(build_dir, "args.gn"), os.path.join(tmp_dir, "args.gn")) + if sys.platform == "darwin": + sdk_links = os.path.join(build_dir, "xcode_links") + if os.path.isdir(sdk_links): + shutil.copytree( + sdk_links, os.path.join(tmp_dir, "xcode_links"), symlinks=True) + # Explicit SDK paths supplied by embedder build tools must stay below + # the query's output directory for Chromium's sdk_inputs action. + old_sdk_root = "//" + os.path.relpath(build_dir, source_root) + "/" + new_sdk_root = "//" + os.path.relpath(tmp_dir, source_root) + "/" + with open(os.path.join(tmp_dir, "args.gn"), "a") as f: + f.write("\nif (defined(mac_sdk_path)) {\n") + f.write(" mac_sdk_path = string_replace(mac_sdk_path, " + f"{json.dumps(old_sdk_root)}, {json.dumps(new_sdk_root)})\n") + f.write("}\n") + open(os.path.join(tmp_dir, "build.ninja"), "w").close() + try: + # -q ("don't print output on success") keeps stdout to the JSON alone. + # Without it gn prepends any build-file warning to the document -- an + # arm_float_abi that no declare_args() claims on the arm64 bots, say -- + # and the parse below fails. A gn that actually fails still reports. + proc = subprocess.run( + [ + gn, "desc", "-q", "--root=" + source_root, tmp_dir, target_label, + "--format=json" + ], + cwd=source_root, + capture_output=True, + text=True, + check=True, + ) + except FileNotFoundError: + raise RuntimeError(f"[metagen] gn binary not found: {gn}") + except subprocess.CalledProcessError as e: + raise RuntimeError(f"[metagen] `gn desc {tmp_dir} {target_label}` failed " + f"(exit {e.returncode}). Is the target part of that " + f"toolchain's build?\n" + f"{(e.stdout or '').strip()}\n" + f"{(e.stderr or '').strip()}") + try: + desc = json.loads(proc.stdout) + except json.JSONDecodeError as e: + raise RuntimeError(f"[metagen] `gn desc` output was not valid JSON: {e}") + if not isinstance(desc, dict) or not desc: + raise RuntimeError( + f"[metagen] `gn desc` returned no target for {target_label}.") + fields = next(iter(desc.values())) + + # GN reports paths derived from root_build_dir under the temporary output + # directory. Point them back to the generated files in the active build. + replacements = [(tmp_dir, build_dir), + (tmp_dir.replace(os.sep, + "/"), build_dir.replace(os.sep, "/"))] + try: + tmp_rel = os.path.relpath(tmp_dir, source_root).replace(os.sep, "/") + build_rel = os.path.relpath(build_dir, source_root).replace(os.sep, "/") + except ValueError: + # On Windows, the output directory may be on a different drive. + pass + else: + replacements.extend( + (("//" + tmp_rel, "//" + build_rel), (tmp_rel, build_rel))) + + def restore_build_path(value): + for old, new in replacements: + value = value.replace(old, new) + return value + + fields = { + key: [restore_build_path(value) for value in fields.get(key) or []] + for key in ("defines", "include_dirs", "cflags", "cflags_cc") + } flags: list[str] = [f"-D{d}" for d in fields.get("defines") or []] for inc in fields.get("include_dirs") or []: @@ -223,24 +263,19 @@ def get_compile_args_from_gn_desc( cflags = (fields.get("cflags") or []) + (fields.get("cflags_cc") or []) flags += cflags - # clang-cl spells its options with a leading slash; posix clang never - # does. The caller injects --driver-mode=cl when this is set. - cl_mode = any(f.startswith("/") for f in cflags) - # Drop plugin chains (-Xclang -add-plugin ...), backend-only (-mllvm), # and sanitizer/coverage/crash-dir flags libclang can't honor under # -fsyntax-only. gn desc's cflags never carry -c/-o/@rsp/the input # path, so the input-path arg to _filter is unused. filtered = _filter(flags, "") - return filtered, os.path.abspath(build_dir), cl_mode + return filtered, os.path.abspath(build_dir) -def get_compile_args_from_file(path: str) -> tuple[list[str], str, bool]: +def get_compile_args_from_file(path: str) -> tuple[list[str], str]: """Bazel path: read the single-entry compile_commands.json the rule synthesizes (bazel/defs.bzl). - Returns (flags, cwd, cl_mode) with the same contract as - `get_compile_args_from_gn_desc`. The synthesized entry always carries + Returns (flags, cwd). The synthesized entry always carries an `arguments` array (never a `command` string), so the flags are read directly with no shell tokenization. argv[0] and the bogus source file are dropped; `-c`/`-o` and friends go through the shared _filter. @@ -257,7 +292,5 @@ def get_compile_args_from_file(path: str) -> tuple[list[str], str, bool]: raise RuntimeError( f"[metagen] compile-commands entry has no `arguments` array: " f"{entry}. bazel/defs.bzl must emit `arguments`, not `command`.") - arg0, rest = args[0], args[1:] - cl_mode = _is_clang_cl(arg0) cwd = entry.get("directory") or "." - return _filter(rest, entry.get("file", "")), cwd, cl_mode + return _filter(args[1:], entry.get("file", "")), cwd diff --git a/deps/v8/tools/metagen/compile_flags_test.py b/deps/v8/tools/metagen/compile_flags_test.py deleted file mode 100644 index 928701d435fc..000000000000 --- a/deps/v8/tools/metagen/compile_flags_test.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2026 the V8 project authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import json -import os -from pathlib import Path -import subprocess -import sys -import tempfile -import unittest -from unittest import mock - -# Running this file as a script puts tools/metagen/ on sys.path, not its -# parent, so the `metagen` package is not importable yet. -_PARENT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -if _PARENT not in sys.path: - sys.path.insert(0, _PARENT) - -from metagen import compile_flags # noqa: E402 - - -class GnCompileFlagsTest(unittest.TestCase): - - def test_external_build_directory(self): - with tempfile.TemporaryDirectory() as tmp: - source_root = Path(tmp) / 'src' - build_dir = Path(tmp) / 'cache' / 'Release' - source_root.mkdir() - build_dir.mkdir(parents=True) - (source_root / '.gn').touch() - target = '//v8:probe(//build/toolchain:target)' - desc = { - target: { - 'defines': ['PROBE=1'], - 'include_dirs': ['//v8/include', - str(build_dir / 'gen')], - 'cflags_cc': ['-std=c++20'], - } - } - with mock.patch.object( - compile_flags, '_find_gn', - return_value='gn') as find_gn, mock.patch.object( - compile_flags.subprocess, - 'run', - return_value=subprocess.CompletedProcess( - [], 0, json.dumps(desc))) as run: - flags, cwd, cl_mode = compile_flags.get_compile_args_from_gn_desc( - str(build_dir), target, str(source_root)) - find_gn.assert_called_once_with(str(source_root)) - # gn runs in the source root, and reaches the build dir through a - # relative path that leaves the checkout. - argv, kwargs = run.call_args - self.assertEqual(argv[0], [ - 'gn', 'desc', '-q', - os.path.relpath(build_dir, source_root), target, '--format=json' - ]) - self.assertEqual(kwargs['cwd'], str(source_root)) - self.assertTrue(kwargs['check']) - self.assertEqual(flags, [ - '-DPROBE=1', f'-I{source_root / "v8" / "include"}', - f'-I{build_dir / "gen"}', '-std=c++20' - ]) - self.assertEqual(cwd, str(build_dir)) - self.assertFalse(cl_mode) - - -class FilterTest(unittest.TestCase): - - def test_drops_clang_modules_family(self): - # A use_clang_modules build passes all of these. -fbuiltin-module-map - # is the easy one to miss: it names no path, so it does nothing until - # the resource dir actually has builtin headers in it. - modules_flags = [ - '-fmodules', - '-fmodule-map-file=/x/module.modulemap', - '-fmodule-file=std=/x/std.pcm', - '-fimplicit-modules', - '-fimplicit-module-maps', - '-fno-implicit-modules', - '-fno-implicit-module-maps', - '-fbuiltin-module-map', - ] - self.assertEqual( - compile_flags._filter(modules_flags + ['-DKEEP'], ''), ['-DKEEP']) - - -if __name__ == '__main__': - unittest.main() diff --git a/deps/v8/tools/metagen/cpp_hier.py b/deps/v8/tools/metagen/cpp_hier.py index f81288ddf2d4..0c38fd1467d3 100644 --- a/deps/v8/tools/metagen/cpp_hier.py +++ b/deps/v8/tools/metagen/cpp_hier.py @@ -3,7 +3,7 @@ # found in the LICENSE file. """Harvest the class hierarchy from C++ V8_OBJECT headers via libclang. -Produces `ClassInfo` records (see instance_types.py) for every class +Produces `ClassInfo` objects (see instance_types.py) for every class that transitively inherits HeapObject in the input headers, sourced from the `[[clang::annotate("V8_IT_*")]]` markers carried by aliases in each class body. Feed the list into `instance_types.assign_instance_types` to drive IT @@ -25,6 +25,13 @@ This module references `clang.cindex` at import time, so `clang_bootstrap.bootstrap()` must have run first -- metagen.py does that before importing us. + +TODO(jgruber): Rename to parse.py and scan_cpp to parse_driver; the +module's job is the libclang parse and the ParsedTU built from it. +Rename _harvest_classes to _index_classes and move its ClassInfo +derivation out into it_extract.py, the twin of layout_extract.py, so +that the pipeline reads as one parse, one index, two extractions. +Drop the harvest vocabulary here and in metagen.py at the same time. """ from __future__ import annotations @@ -51,18 +58,54 @@ # Anchored, because the V8_OBJECTS_<NAME>_H_ include guards share a # prefix with V8_OBJECT and would otherwise match. _MARKER_MACRO_RE = re.compile( - r"^(V8_IT_[A-Z_]+|V8_ABSTRACT_OBJECT" + r"^(V8_IT_[A-Z_]+|V8_TQ_[A-Z_]+|V8_ABSTRACT_OBJECT" r"|V8_OBJECT(_END|_PUSH|_POP|_INNER_CLASS(_END)?)?)$") +@dataclasses.dataclass +class ParsedTU: + """The parsed translation unit and its indexes. + + Instance-type and layout extraction share these indexes. `tu` keeps + every cursor alive. Each consumer adds the declarations it reads to + `visited`; visited_files() collects their paths for the depfile. + """ + tu: cindex.TranslationUnit + templates_idx: dict[str, list[cindex.Cursor]] + # Every v8::internal class-like definition that reaches HeapObject, + # keyed by unqualified name (ambiguity is fatal during the scan). + heap_classes: dict[str, cindex.Cursor] + # Namespace-scope type aliases keyed by unqualified name, first one + # wins. Class-scope aliases are left out so that a member such as + # Internals::Tagged_t cannot shadow the namespace alias. + aliases: dict[str, cindex.Cursor] + visited: set[cindex.Cursor] + + @dataclasses.dataclass class ScanResult: classes: list[ClassInfo] - # Absolute paths of the files the harvest read a fact out of -- class - # declarations, the bases and templates it resolved through, and the - # marker definitions. Derived from the walk, not filtered from the - # include list, so it stays correct when a declaration moves. - provenance: list[str] = dataclasses.field(default_factory=list) + parsed: ParsedTU + + +def visited_files(visited: set[cindex.Cursor], v8_root: str) -> list[str]: + """Absolute paths of the checkout files holding a visited declaration: + the classes, the bases and templates resolved through, field types, + and the marker definitions. Derived from the walk, not filtered from + the include list, so it stays correct when a declaration moves.""" + files: set[str] = set() + # Prefix test rather than os.path.commonpath, which raises across + # drives on Windows -- and `visited` reaches the toolchain and sysroot + # declarations, which need not share the checkout's drive. + root = os.path.abspath(v8_root) + os.sep + for cursor in visited: + loc = cursor.location + if loc is None or loc.file is None: + continue + path = os.path.abspath(loc.file.name) + if path.startswith(root): + files.add(path) + return sorted(files) def _annotations(cursor: cindex.Cursor) -> list[str]: @@ -155,81 +198,60 @@ def _class_info_from_cursor( def _dump_parse_failure(v8_root: str, driver_path: str, parse_flags: list[str], - reason: str, parse_cwd: str | None = None) -> None: - """Re-run the parse through the clang binary and forward its stderr. - - Covers both ways the parse fails. On an unrecoverable TU the Python - binding drops the diagnostics: CXTranslationUnit is NULL and - from_source raises, so all we have is "Error parsing translation - unit". On a TU that parsed with errors we have diagnostics but not the - `In file included from ...` stacks, which are what show a header - resolving to a different file than the build's compile uses. clang - prints both. - - Best-effort: if the bundled clang is missing or won't spawn, we log - that and let the caller fail as it would have anyway. - """ - # libclang's argv mirrors the GCC-style clang driver, not clang-cl. - # On Linux/Mac the Chromium toolchain ships clang directly; on - # Windows it ships only clang-cl.exe -- invoke that with - # --driver-mode=g++ to make it parse the same flag set libclang did. - # Probe both <v8_root>/third_party/... and <v8_root>/../third_party/... - # to handle Chromium subproject builds where the toolchain lives at - # the chromium toplevel. - clang_extra_args: list[str] = [] + """Ask clang for diagnostics when libclang returned no translation unit.""" + # libclang takes GCC-style arguments, including on Windows. + clang_extra_args = [] if sys.platform == "win32": clang_rel = "third_party/llvm-build/Release+Asserts/bin/clang-cl.exe" clang_extra_args = ["--driver-mode=g++"] else: clang_rel = "third_party/llvm-build/Release+Asserts/bin/clang" - clang_bin = "" + # Chromium builds keep the toolchain above the V8 checkout. for root in (v8_root, os.path.abspath(os.path.join(v8_root, os.pardir))): - candidate = os.path.join(root, clang_rel) - if os.path.isfile(candidate): - clang_bin = candidate + clang_bin = os.path.join(root, clang_rel) + if os.path.isfile(clang_bin): break - print( - f"[metagen] {reason}; re-running via clang -fsyntax-only to surface " - "diagnostics:", - file=sys.stderr) - print(f"[metagen] clang: {clang_bin}", file=sys.stderr) - print(f"[metagen] driver: {driver_path}", file=sys.stderr) - print( - f"[metagen] flags ({len(parse_flags)}): " - f"{' '.join(parse_flags[:12])}{' ...' if len(parse_flags) > 12 else ''}", - file=sys.stderr) - if not clang_bin or not os.path.isfile(clang_bin): + else: print( - f"[metagen] (clang binary not found; cannot re-run)", file=sys.stderr) + "metagen: note: clang is unavailable for additional diagnostics.", + file=sys.stderr) return + + # Match PARSE_SKIP_FUNCTION_BODIES: bodies can reference declarations + # that have not been generated yet. try: proc = subprocess.run( - [clang_bin] + clang_extra_args + ["-fsyntax-only", driver_path] + - parse_flags, + [clang_bin] + clang_extra_args + [ + "-fsyntax-only", "-Xclang", "-skip-function-bodies", "-w", + driver_path + ] + parse_flags, cwd=parse_cwd or v8_root, - capture_output=True, - text=True, - timeout=60, - ) - except (OSError, subprocess.SubprocessError) as e: - print(f"[metagen] (subprocess failed: {e})", file=sys.stderr) + timeout=60) + except subprocess.TimeoutExpired: + print( + "metagen: note: clang diagnostic rerun timed out after 60 seconds.", + file=sys.stderr) + return + except OSError as e: + print( + f"metagen: note: could not run clang for diagnostics: {e}", + file=sys.stderr) return - if proc.stderr: - print("[metagen] clang stderr (first 80 lines):", file=sys.stderr) - for line in proc.stderr.splitlines()[:80]: - print(f"[metagen] {line}", file=sys.stderr) - print(f"[metagen] clang exited with {proc.returncode}", file=sys.stderr) + if proc.returncode != 1: + print( + f"metagen: note: clang diagnostic rerun exited with {proc.returncode}.", + file=sys.stderr) def scan_cpp(v8_root: str, driver_path: str, flags: list[str], parse_cwd: str | None = None) -> ScanResult: - """Parse `driver_path` via libclang and return ClassInfo records. + """Parse `driver_path` via libclang and return ClassInfo objects. The driver's active direct includes are the headers to harvest. The order of - returned records mirrors AST preorder, which equals (header inclusion order, + returned classes mirrors AST preorder, which equals (header inclusion order, source-position order within each header). That order is stable for a given driver + V8 tree. @@ -261,16 +283,14 @@ def scan_cpp(v8_root: str, try: tu = index.parse(driver_path, args=parse_flags, options=options) except cindex.TranslationUnitLoadError: - # libclang couldn't even start the parse -- typically a sysroot - # / include-path / target-triple mismatch (Windows MSVC paths, - # missing builtin headers, ...). At this point the TU is NULL - # so we have no diagnostics to read via libclang. Re-run the - # parse via the clang binary as a subprocess; its stderr carries - # the actual error. - _dump_parse_failure(v8_root, driver_path, parse_flags, - "libclang refused the TU", parse_cwd) - raise - _reject_recovery_ast(tu, v8_root, driver_path, parse_flags, parse_cwd) + print( + f"{driver_path}: error: libclang could not parse the translation " + "unit.", + file=sys.stderr, + flush=True) + _dump_parse_failure(v8_root, driver_path, parse_flags, parse_cwd) + sys.exit(1) + _reject_recovery_ast(tu) return _harvest_classes(tu, v8_root) finally: if saved_cwd is not None: @@ -278,40 +298,10 @@ def scan_cpp(v8_root: str, def _position(cursor: cindex.Cursor, v8_root: str) -> str: - """`file.h:line:col`, relative to v8_root so the harvest's output and - its diagnostics are reproducible across checkouts.""" - loc = cursor.location - fname = os.path.relpath(loc.file.name, v8_root) if loc.file else "<unknown>" - return f"{fname}:{loc.line}:{loc.column}" - - -_SCOPE_KINDS = (cindex.CursorKind.NAMESPACE, cindex.CursorKind.CLASS_DECL, - cindex.CursorKind.STRUCT_DECL, cindex.CursorKind.CLASS_TEMPLATE, - cindex.CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION) - + return extract.position(cursor, v8_root) or "<unknown>" -def _qualified_name(cursor: cindex.Cursor) -> str: - """Return `cursor`'s name with its namespaces and enclosing classes, - e.g. "v8::internal::FixedArray::Iterator". - The enclosing classes are what separates the four v8::internal classes - named Iterator; the namespaces are what separates v8::Context from the - object. - """ - parts = [cursor.spelling] - parent = cursor.semantic_parent - while parent is not None and parent.kind != cindex.CursorKind.TRANSLATION_UNIT: - if parent.kind in _SCOPE_KINDS: - parts.append(parent.spelling) - parent = parent.semantic_parent - return "::".join(reversed(parts)) - - -def _reject_recovery_ast(tu, - v8_root: str, - driver_path: str, - parse_flags: list[str], - parse_cwd: str | None = None) -> None: +def _reject_recovery_ast(tu) -> None: """Exit unless the TU parsed cleanly. Never consume Clang's recovery AST. A missing declaration can corrupt a @@ -321,16 +311,10 @@ def _reject_recovery_ast(tu, errors = [d for d in tu.diagnostics if d.severity >= cindex.Diagnostic.Error] if not errors: return - for d in errors[:30]: - print( - f"[metagen] diag {d.severity} {d.location}: {d.spelling}", - file=sys.stderr) - if len(errors) > 30: - print(f"[metagen] ... and {len(errors) - 30} more", file=sys.stderr) - _dump_parse_failure(v8_root, driver_path, parse_flags, - f"libclang reported {len(errors)} error diagnostic(s)", - parse_cwd) - print("[metagen] refusing to harvest a recovery AST.", file=sys.stderr) + for diagnostic in errors: + print(diagnostic.format(), file=sys.stderr) + for note in diagnostic.children: + print(note.format(), file=sys.stderr) sys.exit(1) @@ -363,36 +347,33 @@ def _harvest_classes(tu, v8_root: str) -> ScanResult: cindex.CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION) _HARVEST_KINDS = (cindex.CursorKind.CLASS_DECL, cindex.CursorKind.CLASS_TEMPLATE) + _ALIAS_KINDS = (cindex.CursorKind.TYPEDEF_DECL, + cindex.CursorKind.TYPE_ALIAS_DECL) + _NAMESPACE_KINDS = (cindex.CursorKind.TRANSLATION_UNIT, + cindex.CursorKind.NAMESPACE) templates_idx: dict[str, list[cindex.Cursor]] = {} raw_candidates: dict[str, cindex.Cursor] = {} + aliases: dict[str, cindex.Cursor] = {} # Cursors that lost an unqualified-name collision, for the check below. shadowed: dict[str, list[cindex.Cursor]] = {} - def _walk(cur): + def _walk(cur, parent_kind): k = cur.kind + if k in _ALIAS_KINDS and parent_kind in _NAMESPACE_KINDS: + aliases.setdefault(cur.spelling, cur) if k in _TEMPLATE_KINDS and cur.is_definition(): templates_idx.setdefault(cur.spelling, []).append(cur) if k in _HARVEST_KINDS and cur.is_definition(): - # V8_IT_NO_AUTO_CHECKER normally excludes the class from the harvest. - # Combined with V8_IT_OWN_TYPE, it instead keeps the class in the IT - # tree while suppressing only its generated checker buckets. - no_auto_checker = _has_annotation(cur, _V8_IT_NO_AUTO_CHECKER) - own_type = _has_annotation(cur, _V8_IT_OWN_TYPE) - if not no_auto_checker or own_type: - loc = cur.location - # The driver reaches far more than the objects -- the public API - # headers among it -- and `raw_candidates` is keyed by unqualified - # name, so v8::Context would claim the key of the object it shares - # a name with and never be reconsidered. Select on the namespace: - # the harvest wants v8::internal and nothing else. - if _qualified_name(cur).startswith("v8::internal::"): - if raw_candidates.setdefault(cur.spelling, cur) != cur: - shadowed.setdefault(cur.spelling, []).append(cur) + # The driver reaches include/ API headers, and `raw_candidates` is keyed + # by unqualified name. Avoid cross-namespace collisions. + if extract.qualified_name(cur).startswith("v8::internal::"): + if raw_candidates.setdefault(cur.spelling, cur) != cur: + shadowed.setdefault(cur.spelling, []).append(cur) if k in _DESCEND_KINDS or k in _TEMPLATE_KINDS: for child in cur.get_children(): - _walk(child) + _walk(child, k) - _walk(tu.cursor) + _walk(tu.cursor, None) def _reaches_heap_object(cur: cindex.Cursor) -> bool: return cur.spelling == extract.HEAP_OBJECT_ROOT or ( @@ -415,10 +396,10 @@ def _reaches_heap_object(cur: cindex.Cursor) -> bool: claimants = {} for cur in [winner] + losers: if _reaches_heap_object(cur): - claimants.setdefault(_qualified_name(cur), cur) + claimants.setdefault(extract.qualified_name(cur), cur) if not claimants: continue - if len(claimants) > 1 or _qualified_name(winner) not in claimants: + if len(claimants) > 1 or extract.qualified_name(winner) not in claimants: print( f"[metagen] `{name}` is claimed by more than one v8::internal " f"class that reaches {extract.HEAP_OBJECT_ROOT}:", @@ -442,7 +423,7 @@ def _reaches_heap_object(cur: cindex.Cursor) -> bool: # ruled a candidate out: a header that keeps a class out of the # harvest decides the output too. visited: set[cindex.Cursor] = set() - candidates: dict[str, cindex.Cursor] = { + heap_classes: dict[str, cindex.Cursor] = { name: cur for name, cur in raw_candidates.items() if name == extract.HEAP_OBJECT_ROOT or extract.resolve_logical_base( @@ -450,6 +431,15 @@ def _reaches_heap_object(cur: cindex.Cursor) -> bool: is not None } + # Layout extraction includes classes excluded from generated checkers because + # they still define layouts and base classes. + candidates: dict[str, cindex.Cursor] = { + name: cur + for name, cur in heap_classes.items() + if not _has_annotation(cur, _V8_IT_NO_AUTO_CHECKER) or + _has_annotation(cur, _V8_IT_OWN_TYPE) + } + # Compute the leaf set. A candidate is a leaf if no other candidate # names it as the closest logical base. The base resolution here # uses the full candidate set so intermediate candidates count as @@ -500,17 +490,11 @@ def _reaches_heap_object(cur: cindex.Cursor) -> bool: _MARKER_MACRO_RE.match(cursor.spelling)): visited.add(cursor) - provenance: set[str] = set() - # Prefix test rather than os.path.commonpath, which raises across - # drives on Windows -- and `visited` reaches the toolchain and sysroot - # declarations, which need not share the checkout's drive. - root = os.path.abspath(v8_root) + os.sep - for cursor in visited: - loc = cursor.location - if loc is None or loc.file is None: - continue - path = os.path.abspath(loc.file.name) - if path.startswith(root): - provenance.add(path) - - return ScanResult(classes=classes, provenance=sorted(provenance)) + return ScanResult( + classes=classes, + parsed=ParsedTU( + tu=tu, + templates_idx=templates_idx, + heap_classes=heap_classes, + aliases=aliases, + visited=visited)) diff --git a/deps/v8/tools/metagen/extract.py b/deps/v8/tools/metagen/extract.py index 701464169623..561b5201e590 100644 --- a/deps/v8/tools/metagen/extract.py +++ b/deps/v8/tools/metagen/extract.py @@ -5,21 +5,57 @@ Inheritance walking through templates plus V8_IT_* annotation discovery. Shared between IT-mode harvesting (`cpp_hier.py`) and -layout-mode generation (the `metagen-layout` branch); keep -IT-emission concerns out of here. +layout extraction (`layout_extract.py`); keep IT-emission concerns +out of here. This module references `clang.cindex` at import time, so `clang_bootstrap.bootstrap()` must have run first -- metagen.py does that before importing any consumer of this module. + +TODO(jgruber): Rename to cursors.py. Nothing here extracts; these are +stateless cursor helpers, and "extract" belongs to layout_extract.py. """ from __future__ import annotations +import os + import clang.cindex as cindex HEAP_OBJECT_ROOT = "HeapObject" +def qualified_name(cursor: cindex.Cursor) -> str: + """The declaration name, including namespaces and enclosing classes.""" + parts = [cursor.spelling] + parent = cursor.semantic_parent + while parent is not None and parent.kind != cindex.CursorKind.TRANSLATION_UNIT: + if parent.kind in (cindex.CursorKind.NAMESPACE, + cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL, + cindex.CursorKind.CLASS_TEMPLATE, + cindex.CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION): + parts.append(parent.spelling) + parent = parent.semantic_parent + return "::".join(reversed(parts)) + + +def position(cursor: cindex.Cursor, v8_root: str) -> str | None: + """`file.h:line:col` relative to v8_root, forward slashes, so output + and diagnostics are reproducible across checkouts. None when the + cursor has no file.""" + loc = cursor.location + if loc.file is None: + return None + try: + rel = os.path.relpath(loc.file.name, v8_root) + except ValueError: + # Windows: the toolchain and sysroot need not share the checkout's + # drive. + rel = loc.file.name + return f"{rel.replace(os.sep, '/')}:{loc.line}:{loc.column}" + + def class_annotations(cursor: cindex.Cursor) -> list[str]: """Return the `[[clang::annotate]]` payloads on a class's members. @@ -121,11 +157,11 @@ def resolve_logical_base( if args_map is None: args_map = {} - def _visit(c: cindex.Cursor | None) -> None: + def mark_visited(c: cindex.Cursor | None) -> None: if visited is not None and c is not None: visited.add(c) - _visit(cursor) + mark_visited(cursor) name = cursor.spelling sig = (name, frozenset((k, v.spelling) for k, v in args_map.items() if v)) if sig in seen: @@ -137,7 +173,7 @@ def _visit(c: cindex.Cursor | None) -> None: continue bt = child.type base_decl = bt.get_declaration() - _visit(base_decl) + mark_visited(base_decl) base_decl_name = base_decl.spelling if not base_decl_name and bt.kind == cindex.TypeKind.UNEXPOSED: base_decl_name = bt.spelling @@ -153,7 +189,7 @@ def _visit(c: cindex.Cursor | None) -> None: if sub_name in participating: return sub_name sub_def = sub.get_declaration().get_definition() or sub.get_declaration() - _visit(sub_def) + mark_visited(sub_def) if sub_def.kind in _CLASS_LIKE: result = resolve_logical_base(sub_def, participating, templates, {}, seen, visited) @@ -183,9 +219,9 @@ def _visit(c: cindex.Cursor | None) -> None: if nargs > 0: candidates.extend(templates.get(base_decl_name, [])) for _t in candidates: - _visit(_t) + mark_visited(_t) base_def = base_decl.get_definition() or base_decl - _visit(base_def) + mark_visited(base_def) if base_def.kind in _CLASS_LIKE: candidates.append(base_def) for cand in candidates: diff --git a/deps/v8/tools/metagen/layout_extract.py b/deps/v8/tools/metagen/layout_extract.py new file mode 100644 index 000000000000..b97f60d34c63 --- /dev/null +++ b/deps/v8/tools/metagen/layout_extract.py @@ -0,0 +1,826 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Object layout extraction from the parsed translation unit. + +Consumes the ParsedTU produced by cpp_hier.scan_cpp and produces +layout_ir.ClassLayout objects for declarations that represent V8 +heap-object types (see represents_heap_object_type). + +A class's exported fields are all data members at offsets in +[sizeof(base), sizeof(class)), where base is the nearest ancestor with +an exported layout. This includes members of intermediate template +bases such as TaggedArrayBase. V8 heap objects use +single, non-virtual inheritance, so a member's offset within its +declaring class equals its offset within the derived class; the +ClassLayout contiguity validation checks that assumption. + +Every problem is fatal: an unknown member type, a missing offset, a +malformed annotation, or more than one flexible tail raises LayoutError +and metagen exits without output. +""" + +from __future__ import annotations + +import re + +import clang.cindex as cindex + +from metagen import extract +from metagen.layout_ir import (ANNOTATION_PREFIX, Annotation, BitFieldEntry, + ClassLayout, Config, Field, LayoutError, CppType, + StorageType, Tail, named_type, union_type) + +# Class templates allowed as wrapper arguments. The record names the +# template and its payload, so a consumer can map an instantiation to a +# type of its own (for Torque, kClassTemplateNames in +# src/torque/layout-loader.cc). Must be kept in sync with that list. +_CLASS_TEMPLATE_ARGUMENTS = frozenset({"CppGCManaged"}) + +# Annotation arguments are not parsed here; Torque parses them. +_TQ_PAYLOAD_RE = re.compile(r"^(V8_TQ_[A-Za-z0-9_]+)(?:\((.*)\))?$") + +_SIGNED_KINDS = frozenset({ + cindex.TypeKind.CHAR_S, + cindex.TypeKind.SCHAR, + cindex.TypeKind.SHORT, + cindex.TypeKind.INT, + cindex.TypeKind.LONG, + cindex.TypeKind.LONGLONG, +}) +_UNSIGNED_KINDS = frozenset({ + cindex.TypeKind.CHAR_U, + cindex.TypeKind.UCHAR, + cindex.TypeKind.USHORT, + cindex.TypeKind.UINT, + cindex.TypeKind.ULONG, + cindex.TypeKind.ULONGLONG, +}) + +# Preserve pointer-width aliases because their canonical types are ABI-specific. +_POINTER_WIDTH_ALIASES = frozenset( + {"intptr_t", "uintptr_t", "size_t", "ptrdiff_t", "Address"}) + +# C++ classes/structs represented as struct fields by layout consumers. +# Reject others so an unknown storage wrapper cannot fall through to a struct. +_STRUCT_TYPES = frozenset({ + "v8::internal::CoverageInfoSlot", + "v8::internal::DescriptorArray::Entry", + "v8::internal::DoubleStringCache::Entry", + "v8::internal::JSIteratorHelperSimple::IteratorRecord", + "v8::internal::JSValidIteratorWrapper::IteratorRecord", + "v8::internal::ScopeInfo::PositionInfo", + "v8::internal::WasmCodePointer", +}) + +_POINTER_TAG_TYPES = frozenset({ + "v8::internal::ExternalPointerTag", + "v8::internal::TrustedPointerTag", +}) + + +def _parse_annotations(payloads, where: str) -> tuple[Annotation, ...]: + """The V8_TQ_ annotations among `payloads`, name split from argument. + + Anything not of the form V8_TQ_<name> or V8_TQ_<name>(arg) is + malformed and fails here. Torque defines what the names mean. + """ + out = [] + for payload in payloads: + if not payload.startswith(ANNOTATION_PREFIX): + continue + m = _TQ_PAYLOAD_RE.match(payload) + if m is None: + raise LayoutError(f"{where}: malformed annotation payload {payload!r}") + out.append(Annotation(name=m.group(1), arg=m.group(2))) + names = [a.name for a in out] + dupes = sorted({n for n in names if names.count(n) > 1}) + if dupes: + raise LayoutError(f"{where}: repeated annotation(s) {', '.join(dupes)}") + return tuple(sorted(out, key=lambda a: (a.name, a.arg or ""))) + + +def _alias_annotations(cursor: cindex.Cursor) -> list[str]: + """Annotation payloads on the class's alias declarations only. + + extract.class_annotations collects attributes from every member, + which for layout classes also includes the per-field V8_TQ_ + annotations on data members. Class-level annotations (V8_TQ_TAIL_*) + expand to `using ... = void` aliases, so restricting to + TYPE_ALIAS_DECL children separates the two. + """ + out: list[str] = [] + for child in cursor.get_children(): + if child.kind != cindex.CursorKind.TYPE_ALIAS_DECL: + continue + for grandchild in child.get_children(): + if grandchild.kind == cindex.CursorKind.ANNOTATE_ATTR: + out.append(grandchild.spelling) + return out + + +def _where(cursor: cindex.Cursor) -> str: + loc = cursor.location + if loc.file is None: + return "<unknown>" + return f"{loc.file.name}:{loc.line}" + + +def mark_visited(parsed, cursor: cindex.Cursor | None) -> None: + if cursor is not None: + parsed.visited.add(cursor) + + +def _decl_of(t: cindex.Type): + decl = t.get_declaration() + return decl if decl.spelling else None + + +def _bit_field_group_base(decl: cindex.Cursor) -> cindex.Type | None: + """The BitFieldGroup specialization `decl` derives from, if any.""" + for child in decl.get_children(): + if child.kind != cindex.CursorKind.CXX_BASE_SPECIFIER: + continue + base = child.type.get_canonical() + base_decl = _decl_of(base) + if base_decl is not None and base_decl.spelling == "BitFieldGroup": + return base + return None + + +def _cpp_class_scoped_name(decl: cindex.Cursor) -> str: + """The C++ name of `decl`, qualified by its enclosing classes.""" + parts = [] + while decl is not None and decl.kind in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL, + cindex.CursorKind.CLASS_TEMPLATE, + cindex.CursorKind.ENUM_DECL): + parts.append(decl.spelling) + decl = decl.semantic_parent + return "::".join(reversed(parts)) + + +def _template_args(t: cindex.Type) -> list[cindex.Type]: + """Type template arguments of a specialization, preferring the + as-written (sugared) type so aliases like MaybeObject survive, and + falling back to the canonical type.""" + n = t.get_num_template_arguments() + if n <= 0: + t = t.get_canonical() + n = t.get_num_template_arguments() + if n <= 0: + return [] + args = [] + for i in range(n): + arg = t.get_template_argument_type(i) + # Non-type arguments come back as invalid types; skip them (the + # callers that need them read DECL_REF_EXPR children instead). + if arg.kind != cindex.TypeKind.INVALID: + args.append(arg) + return args + + +def _pointer_tag_names(field: cindex.Cursor) -> list[str]: + """Names of the pointer-tag constants referenced in the field's + declared type (e.g. kFooTrustedPointerTag, or a kFoo...TagRange + constant). The reference can sit below an implicit conversion, so + walk the whole subtree; the filter keeps unrelated references (array + extents, defaults) out.""" + out = [] + for child in field.walk_preorder(): + if child.kind != cindex.CursorKind.DECL_REF_EXPR: + continue + ref = child.referenced + if ref is None: + continue + if ref.kind == cindex.CursorKind.ENUM_CONSTANT_DECL: + parent = ref.semantic_parent + if (parent is not None and + extract.qualified_name(parent) in _POINTER_TAG_TYPES): + out.append(ref.spelling) + elif ref.kind == cindex.CursorKind.VAR_DECL: + tag_type = ref.type.get_canonical() + type_decl = tag_type.get_declaration() + if (extract.qualified_name(type_decl) == "v8::internal::TagRange" and + tag_type.get_num_template_arguments() == 1 and extract.qualified_name( + tag_type.get_template_argument_type(0).get_declaration()) + in _POINTER_TAG_TYPES): + out.append(ref.spelling) + # A tag can be referenced more than once through conversions. + return list(dict.fromkeys(out)) + + +class _Extractor: + + def __init__(self, parsed, v8_root: str): + self.parsed = parsed + self.v8_root = v8_root + + def _position(self, cursor: cindex.Cursor) -> str: + pos = extract.position(cursor, self.v8_root) + if pos is None: + raise LayoutError(f"{cursor.spelling}: declaration without a location") + return pos + + def _pointer_width_alias(self, t: cindex.Type) -> str | None: + """The pointer-width C++ alias an integral member is written + through, if any; the outermost one wins, so a member written + Address does not report as uintptr_t. The width alone cannot tell, + since on a 32-bit target it equals that of a plain uint32_t.""" + while True: + decl = _decl_of(t) + if decl is None or decl.kind not in (cindex.CursorKind.TYPEDEF_DECL, + cindex.CursorKind.TYPE_ALIAS_DECL): + return None + mark_visited(self.parsed, decl) + if decl.spelling in _POINTER_WIDTH_ALIASES: + return decl.spelling + t = decl.underlying_typedef_type + + def _cpp_int_type_of(self, t: cindex.Type) -> CppType: + """Preserve known pointer-width aliases; name other integers by size + and signedness using <cstdint> names. + + For example, uintptr_t stays uintptr_t even on a 32-bit target. + An unsigned long becomes uint32_t or uint64_t, depending on its + size in the target ABI. + """ + alias = self._pointer_width_alias(t) + if alias is not None: + return named_type(alias) + canonical = t.get_canonical() + is_signed = canonical.kind in _SIGNED_KINDS + return named_type(f"{'' if is_signed else 'u'}int" + f"{canonical.get_size() * 8}_t") + + def _cpp_type_of(self, t: cindex.Type) -> CppType: + """The structured C++ type of a wrapper's type argument. Aliases + keep their name (MaybeObject stays MaybeObject); Union/UnionOf + flatten, which is what they mean in C++ (union.h forbids a union of + unions); Weak<T> keeps its template shape.""" + decl = _decl_of(t) + if decl is None: + raise LayoutError(f"cannot resolve type {t.spelling!r}") + mark_visited(self.parsed, decl) + name = decl.spelling + + if decl.kind in (cindex.CursorKind.TYPEDEF_DECL, + cindex.CursorKind.TYPE_ALIAS_DECL): + # Keep a namespace-scope alias like MaybeObject rather than + # expanding it to its canonical union. A class-scoped alias + # (SharedFunctionInfo::NameOrScopeInfoT) is not visible outside + # its class, so expand it. + parent = decl.semantic_parent + if parent is not None and parent.kind in ( + cindex.CursorKind.CLASS_DECL, cindex.CursorKind.STRUCT_DECL, + cindex.CursorKind.CLASS_TEMPLATE): + return self._cpp_type_of(t.get_canonical()) + return named_type(name) + + if name in ("Union", "UnionOf"): + # An alias template like MaybeWeak<T> resolves to Union's decl + # but has fewer arguments than the flattened union; the canonical + # type has them all. + args = _template_args(t) + if len(args) < 2: + args = _template_args(t.get_canonical()) + # Sugared members can themselves be unions (UnionOf<Smi, + # MaybeWeak<Map>, ...>); flatten the way UnionOf itself does, + # keeping first occurrences. + members = [] + for a in args: + member = self._cpp_type_of(a) + splice = member.members if member.kind == "union" else (member,) + members.extend(m for m in splice if m not in members) + if len(members) < 2: + raise LayoutError(f"union type {t.spelling!r} with < 2 members") + return union_type(*members) + + if name == "Weak": + args = _template_args(t) + if len(args) != 1: + raise LayoutError(f"Weak type {t.spelling!r} without one argument") + return named_type("Weak", self._cpp_type_of(args[0])) + + if decl.kind in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL, + cindex.CursorKind.CLASS_TEMPLATE): + if t.get_canonical().get_num_template_arguments() > 0: + if name not in _CLASS_TEMPLATE_ARGUMENTS: + raise LayoutError(f"unsupported class template argument " + f"{t.spelling!r}; add {name} to " + f"_CLASS_TEMPLATE_ARGUMENTS and to each consumer") + return named_type(name, self._payload_type(t)) + return named_type(name) + + if decl.kind == cindex.CursorKind.ENUM_DECL: + return named_type(name) + + raise LayoutError(f"unsupported type argument {t.spelling!r} ({decl.kind})") + + def _payload_type(self, t: cindex.Type) -> CppType: + """The sole argument of an allowed class template, named but not + visited: a payload is a plain C++ type, not a heap object, so it has + no layout of its own to harvest.""" + args = _template_args(t.get_canonical()) + if len(args) != 1: + raise LayoutError(f"class template {t.spelling!r} without one argument") + parts = args[0].get_canonical().spelling.split("::") + return named_type(parts[-1], namespaces=tuple(parts[:-1])) + + def _bitfield_storage(self, + field: cindex.Cursor, + name: str, + group: cindex.Cursor, + base: cindex.Type, + smi: bool = False) -> StorageType: + """Read direct base::BitField aliases in declaration order. + + Smi storage uses a tagged slot instead of the group's integer width. + """ + bits = [] + for alias in group.get_children(): + if alias.kind != cindex.CursorKind.TYPE_ALIAS_DECL: + continue + bit = alias.underlying_typedef_type.get_canonical() + decl = _decl_of(bit) + if decl is None or decl.spelling != "BitField": + raise LayoutError(f"{_where(field)}: {group.spelling}::" + f"{alias.spelling} is not a base::BitField " + f"({bit.spelling}); a BitFieldGroup may only " + f"contain base::BitField aliases") + bits.append( + BitFieldEntry( + cpp_name=alias.spelling, + type=self._bit_field_type(decl.get_template_argument_type(0)), + offset=decl.get_template_argument_value(1), + num_bits=decl.get_template_argument_value(2))) + if not bits: + raise LayoutError(f"{_where(field)}: bit field group " + f"{group.spelling!r} declares no bit fields") + if smi: + return StorageType(kind="smi_bitfield", name=name, bits=tuple(bits)) + return StorageType( + kind="bitfield", + name=name, + width=base.get_template_argument_type(1).get_size(), + bits=tuple(bits)) + + def _bit_field_type(self, t: cindex.Type) -> str: + """The C++ name of one bit field's value type. A base::StrongAlias + (SharedFlag, ResizableFlag, ...) is its underlying type; Torque + declares such fields as that type.""" + canonical = t.get_canonical() + if canonical.kind == cindex.TypeKind.BOOL: + return "bool" + if canonical.kind == cindex.TypeKind.ENUM: + decl = canonical.get_declaration() + mark_visited(self.parsed, decl) + return _cpp_class_scoped_name(decl) + if canonical.kind == cindex.TypeKind.RECORD: + decl = _decl_of(canonical) + if decl is not None and decl.spelling == "StrongAlias": + mark_visited(self.parsed, decl) + args = _template_args(canonical) + if len(args) == 2: + return self._bit_field_type(args[1]) + raise LayoutError(f"unsupported bit field type {t.spelling!r}; only " + f"bool, enums, integers and base::StrongAlias of " + f"those are supported") + return self._cpp_int_type_of(t).name + + def _is_trusted_space_scheme(self, field: cindex.Cursor, + scheme: cindex.Type) -> bool: + """Whether a TaggedMember's compression scheme is the trusted-space + one, which makes the slot a protected pointer. + + With the sandbox the scheme is an alias for + V8HeapCompressionSchemeImpl<TrustedCage>; without it, it is a + distinct struct of its own (globals.h keeps it distinct so that + is_same_v dispatch behaves the same either way). An unrecognized + scheme is fatal: falling through to a plain tagged slot would + record the wrong representation. + """ + canonical = scheme.get_canonical() + decl = _decl_of(canonical) + if decl is None: + raise LayoutError(f"{_where(field)}: cannot resolve compression " + f"scheme {scheme.spelling!r}") + mark_visited(self.parsed, decl) + if decl.spelling == "TrustedSpaceCompressionScheme": + return True + if decl.spelling == "V8HeapCompressionSchemeImpl": + cages = _template_args(canonical) + cage = _decl_of(cages[0]) if cages else None + if cage is None: + raise LayoutError(f"{_where(field)}: V8HeapCompressionSchemeImpl " + f"without a cage argument") + mark_visited(self.parsed, cage) + if cage.spelling in ("TrustedCage", "MainCage"): + return cage.spelling == "TrustedCage" + raise LayoutError(f"{_where(field)}: unsupported compression cage " + f"{cage.spelling!r}") + raise LayoutError(f"{_where(field)}: unsupported compression scheme " + f"{decl.spelling!r}") + + def _member_tags(self, field: cindex.Cursor, + elem_type: cindex.Type) -> list[str]: + """Pointer-tag constants for a tagged member wrapper. Normally + referenced from the field's own declared type; when the member is + declared through an alias (CodePointerMember), the reference lives + on the alias declaration instead.""" + tags = _pointer_tag_names(field) + if not tags: + alias = _decl_of(elem_type) + if alias is not None and alias.kind in ( + cindex.CursorKind.TYPEDEF_DECL, cindex.CursorKind.TYPE_ALIAS_DECL): + mark_visited(self.parsed, alias) + tags = _pointer_tag_names(alias) + return tags + + def _unaligned_arg_type(self, field: cindex.Cursor, + arg: cindex.Type) -> CppType: + """The C++ type of an UnalignedValueMember's argument: a float, an + integer, or a named struct.""" + canonical = arg.get_canonical() + if canonical.kind == cindex.TypeKind.DOUBLE: + return named_type("double") + if canonical.kind == cindex.TypeKind.FLOAT: + return named_type("float") + if canonical.kind in _SIGNED_KINDS or canonical.kind in _UNSIGNED_KINDS: + return self._cpp_int_type_of(arg) + decl = _decl_of(canonical) + if decl is not None and decl.kind in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL): + mark_visited(self.parsed, decl) + return named_type(decl.spelling) + raise LayoutError(f"{_where(field)}: unsupported " + f"UnalignedValueMember<{arg.spelling}>") + + def _storage_type_of(self, field: cindex.Cursor, + elem_type: cindex.Type) -> StorageType: + """Storage for one member (with any constant-array extent + already peeled off by the caller).""" + canonical = elem_type.get_canonical() + decl = _decl_of(canonical) + + # A bare TrustedPointerHandle member (always atomic-wrapped in + # practice) is an object's own pointer-table entry -- physically + # the same slot a TrustedPointerMember holds, minus pointee and + # tag. + handle_alias = self.parsed.aliases.get("TrustedPointerHandle") + if handle_alias is None: + raise LayoutError( + f"{_where(field)}: missing TrustedPointerHandle declaration; " + "update trusted-pointer storage classification") + written = _decl_of(elem_type) + if written == handle_alias: + mark_visited(self.parsed, written) + return StorageType(kind="trusted_pointer") + + if decl is not None: + base = _bit_field_group_base(decl) + if base is not None: + mark_visited(self.parsed, decl) + return self._bitfield_storage(field, _cpp_class_scoped_name(decl), decl, + base) + + if decl is not None and decl.kind in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL): + mark_visited(self.parsed, decl) + name = decl.spelling + if name == "atomic": + # std::atomic<T> has T's size and alignment; the atomicity is + # accessor semantics, not layout. Prefer the sugared argument + # so aliases like TrustedPointerHandle stay recognizable. + args = _template_args(elem_type) or _template_args(canonical) + if len(args) != 1: + raise LayoutError(f"{_where(field)}: atomic member without one " + f"type argument ({elem_type.spelling})") + return self._storage_type_of(field, args[0]) + if name == "TaggedMember": + # The written type usually has one argument and defaults the + # compression scheme; the canonical type has both. Prefer the + # sugared first argument so aliases survive. + sugared = _template_args(elem_type) + args = sugared if len(sugared) == 2 else _template_args(canonical) + if len(args) != 2: + raise LayoutError(f"{_where(field)}: TaggedMember with " + f"{len(args)} type arguments") + value_arg = sugared[0] if sugared else args[0] + arg_type = self._cpp_type_of(value_arg) + if self._is_trusted_space_scheme(field, args[1]): + return StorageType(kind="protected_tagged", arg=arg_type) + return StorageType(kind="tagged", arg=arg_type) + if name == "SmiBitFieldMember": + args = _template_args(elem_type) or _template_args(canonical) + group = _decl_of(args[0].get_canonical()) if args else None + base = _bit_field_group_base(group) if group is not None else None + if base is None: + raise LayoutError(f"{_where(field)}: SmiBitFieldMember argument " + f"is not a BitFieldGroup") + mark_visited(self.parsed, group) + return self._bitfield_storage( + field, _cpp_class_scoped_name(group), group, base, smi=True) + if name == "TrustedPointerMember": + args = _template_args(elem_type) or _template_args(canonical) + if not args: + raise LayoutError( + f"{_where(field)}: TrustedPointerMember without arguments") + pointee = self._cpp_type_of(args[0]) + tags = self._member_tags(field, elem_type) + if len(tags) != 1: + raise LayoutError( + f"{_where(field)}: expected exactly one tag reference on " + f"TrustedPointerMember, found {tags}") + return StorageType(kind="trusted_pointer", arg=pointee, tag=tags[0]) + if name == "ExternalPointerMember": + tags = self._member_tags(field, elem_type) + if len(tags) != 1: + raise LayoutError( + f"{_where(field)}: expected exactly one tag reference on " + f"{name}, found {tags}") + return StorageType(kind="external_pointer", tag=tags[0]) + if name == "CppHeapPointerMember": + # Not tagged at the member: cpp_heap_wrappable slots share + # embedder tag ranges, so the tag is a call-site argument. + return StorageType(kind="cpp_heap_pointer") + if name == "JSDispatchHandleMember": + return StorageType(kind="js_dispatch_handle") + if name == "UnalignedDoubleMember": + return StorageType(kind="unaligned", arg=named_type("double")) + if name == "UnalignedValueMember": + args = _template_args(elem_type) or _template_args(canonical) + if not args: + raise LayoutError( + f"{_where(field)}: UnalignedValueMember without arguments") + return StorageType( + kind="unaligned", arg=self._unaligned_arg_type(field, args[0])) + if extract.qualified_name(decl) not in _STRUCT_TYPES: + raise LayoutError(f"{_where(field)}: unsupported member class " + f"{extract.qualified_name(decl)!r} " + f"({elem_type.spelling})") + # A plain nested struct (CoverageInfoSlot, DoubleStringCache's + # Entry). The size is what matters for the layout; `name` is the + # C++ struct name, which a consumer maps to its own struct type. + return StorageType(kind="struct", name=name, width=canonical.get_size()) + + if canonical.kind == cindex.TypeKind.ENUM: + enum_decl = canonical.get_declaration() + mark_visited(self.parsed, enum_decl) + underlying = enum_decl.enum_type.get_canonical() + width = underlying.get_size() + return StorageType( + kind="enum", + name=enum_decl.spelling, + width=width, + is_signed=underlying.kind in _SIGNED_KINDS) + + if canonical.kind == cindex.TypeKind.BOOL: + return StorageType(kind="bool") + + if canonical.kind in _SIGNED_KINDS or canonical.kind in _UNSIGNED_KINDS: + width = canonical.get_size() + is_signed = canonical.kind in _SIGNED_KINDS + return StorageType( + kind="int", + width=width, + is_signed=is_signed, + pointer_width_alias=self._pointer_width_alias(elem_type)) + + raise LayoutError( + f"{_where(field)}: unsupported member type {elem_type.spelling!r}") + + def _member_annotations(self, cursor: cindex.Cursor) -> tuple: + """The V8_TQ_ annotations written on a data member.""" + return _parse_annotations( + (child.spelling + for child in cursor.get_children() + if child.kind == cindex.CursorKind.ANNOTATE_ATTR), _where(cursor)) + + def _make_field(self, field: cindex.Cursor, offset: int) -> Field: + t = field.type + extent = None + if t.kind == cindex.TypeKind.CONSTANTARRAY: + extent = t.get_array_size() + if extent == 0: + raise LayoutError( + f"{_where(field)}: {field.spelling}: zero-length array member " + f"outside a flexible tail") + elem_type = t.get_array_element_type() + else: + elem_type = t + size = t.get_size() + if size <= 0: + raise LayoutError(f"{_where(field)}: {field.spelling}: no size") + return Field( + cpp_name=field.spelling, + cpp_type=elem_type.spelling, + position=self._position(field), + offset=offset, + size=size, + storage=self._storage_type_of(field, elem_type), + array_extent=extent, + annotations=self._member_annotations(field)) + + def _make_zero_field(self, field: cindex.Cursor, offset: int) -> Field: + """A zero-length array member below sizeof, recorded with size 0.""" + return Field( + cpp_name=field.spelling, + cpp_type=field.type.get_array_element_type().spelling, + position=self._position(field), + offset=offset, + size=0, + storage=self._storage_type_of(field, + field.type.get_array_element_type()), + annotations=self._member_annotations(field)) + + def _make_tail(self, field: cindex.Cursor, offset: int) -> Tail: + elem_type = field.type.get_array_element_type() + elem_size = elem_type.get_size() + if elem_size <= 0: + raise LayoutError(f"{_where(field)}: flexible tail element has no size") + return Tail( + cpp_name=field.spelling, + cpp_element_type=elem_type.spelling, + position=self._position(field), + offset=offset, + element_size=elem_size, + element_storage=self._storage_type_of(field, elem_type), + annotations=self._member_annotations(field)) + + def _collect_members(self, class_type: cindex.Type, stop_base: str | None, + out: list) -> None: + """Collect the fields of `class_type` and of every base between it + and the base named `stop_base` (exclusive). + + For `template <typename T> class Base { T value_; }`, the type of + `Base<int>` exposes `value_` as an int field through get_fields(). + Its declaration cursor's get_children() is empty, so walk the + instantiated types with get_bases() and get_fields(). + + `out` receives (offset_bytes, cursor) pairs; a flexible-array + member is included with its zero-length array type. + """ + for base in class_type.get_bases(): + canonical = base.type.get_canonical() + base_decl = canonical.get_declaration() + mark_visited(self.parsed, base_decl) + base_name = base_decl.spelling or base.type.spelling + if base_name.startswith("TorqueGenerated"): + raise LayoutError( + f"{_where(base_decl)}: unexpected Torque-generated base " + f"{base.type.spelling!r}; heap object layouts must be defined in C++" + ) + if stop_base is not None and base_name == stop_base: + continue + if base_decl.kind not in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL): + raise LayoutError( + f"{_where(base_decl)}: cannot resolve base {base.type.spelling!r}") + # Single, non-virtual inheritance: the base subobject is at + # offset 0, so member offsets within the base are valid within + # the derived class too. ClassLayout's contiguity validation + # checks this. + self._collect_members(canonical, stop_base, out) + for child in class_type.get_fields(): + offset_bits = child.get_field_offsetof() + if offset_bits < 0: + raise LayoutError( + f"{_where(child)}: {child.spelling}: libclang reports no " + f"offset (error {offset_bits})") + # libclang reports offsets in bits; the layout stores 8-bit byte offsets. + if offset_bits % 8 != 0: + raise LayoutError(f"{_where(child)}: {child.spelling}: not " + f"byte-aligned") + out.append((offset_bits // 8, child)) + + def _class_annotations(self, cursor: cindex.Cursor) -> tuple: + """Class annotations describing how Torque represents the tail.""" + return _parse_annotations(_alias_annotations(cursor), _where(cursor)) + + def extract_class_layout(self, name: str, cursor: cindex.Cursor, + layout_cursors: dict) -> ClassLayout: + mark_visited(self.parsed, cursor) + size = cursor.type.get_size() + if size <= 0: + raise LayoutError(f"{_where(cursor)}: {name}: sizeof failed ({size})") + align = cursor.type.get_align() + if align <= 0: + raise LayoutError(f"{_where(cursor)}: {name}: alignof failed ({align})") + + if name == extract.HEAP_OBJECT_ROOT: + base_name = None + base_size = 0 + else: + base_name = extract.resolve_logical_base( + cursor, + set(layout_cursors.keys()), + templates=self.parsed.templates_idx, + visited=self.parsed.visited) + if base_name is None or base_name not in layout_cursors: + raise LayoutError( + f"{_where(cursor)}: {name}: no ancestor with an exported layout") + base_cursor = layout_cursors[base_name] + base_size = base_cursor.type.get_size() + if base_size <= 0: + raise LayoutError(f"{name}: sizeof({base_name}) failed ({base_size})") + + members: list = [] + self._collect_members(cursor.type, base_name, members) + # Sort by offset. + members.sort(key=lambda pair: pair[0]) + + ann = self._class_annotations(cursor) + fields = [] + tail = None + for offset, member in members: + is_zero_array = ( + member.type.kind == cindex.TypeKind.CONSTANTARRAY and + member.type.get_array_size() == 0) + # A zero-length array at sizeof(class) is the flexible tail + # (FLEXIBLE_ARRAY_MEMBER); anywhere else it is the zero-size + # padding idiom (`char padding_[0]` under config guards). + if is_zero_array and offset != size: + fields.append(self._make_zero_field(member, offset)) + continue + is_flexible_array_member = is_zero_array + if is_flexible_array_member: + if tail is not None: + raise LayoutError( + f"{_where(member)}: {name}: more than one flexible tail") + tail = self._make_tail(member, offset) + else: + fields.append(self._make_field(member, offset)) + + qualified = f"v8::internal::{name}" + qualified_base = (f"v8::internal::{base_name}" + if base_name is not None else None) + return ClassLayout( + cpp_name=qualified, + position=self._position(cursor), + base_cpp_name=qualified_base, + base_size=base_size, + size=size, + alignment=align, + fields=tuple(fields), + tail=tail, + annotations=ann) + + +# Read configuration sizes from the aliases that define them in the parsed +# translation unit. Flags and similarly sized types are not reliable proxies. +_CONFIG_ALIASES = { + "Tagged_t": "tagged_size", + "Address": "pointer_size", + "ExternalPointer_t": "external_pointer_size", + "CppHeapPointer_t": "cpp_heap_pointer_size", + "TrustedPointer_t": "trusted_pointer_size", +} + + +def extract_config(parsed) -> Config: + """The build configuration of the parsed translation unit.""" + sizes: dict[str, int] = {} + for name, field in _CONFIG_ALIASES.items(): + alias = parsed.aliases.get(name) + if alias is None: + continue + size = alias.underlying_typedef_type.get_size() + if size <= 0: + raise LayoutError(f"{_where(alias)}: sizeof({name}) failed ({size})") + mark_visited(parsed, alias) + sizes[field] = size + missing = sorted(set(_CONFIG_ALIASES.values()) - set(sizes)) + if missing: + raise LayoutError("the translation unit declares no " + ", ".join( + sorted(name for name, f in _CONFIG_ALIASES.items() if f in missing)) + + "; cannot record the build " + "configuration the layouts were extracted under") + return Config(**sizes) + + +def represents_heap_object_type(cursor: cindex.Cursor) -> bool: + """Whether the declaration represents a V8 heap-object type. + + Class templates are inheritance machinery rather than object types of + their own. + """ + return cursor.kind in (cindex.CursorKind.CLASS_DECL, + cindex.CursorKind.STRUCT_DECL) + + +def extract_layouts(parsed, v8_root: str) -> list[ClassLayout]: + """Build layouts for every V8 heap-object type in the parsed TU.""" + layout_cursors = { + name: cur + for name, cur in parsed.heap_classes.items() + if represents_heap_object_type(cur) + } + extractor = _Extractor(parsed, v8_root) + layouts = [] + for name in sorted(layout_cursors): + layouts.append( + extractor.extract_class_layout(name, layout_cursors[name], + layout_cursors)) + return layouts diff --git a/deps/v8/tools/metagen/layout_ir.py b/deps/v8/tools/metagen/layout_ir.py new file mode 100644 index 000000000000..dbffc1c944dd --- /dev/null +++ b/deps/v8/tools/metagen/layout_ir.py @@ -0,0 +1,716 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Typed IR and JSON schema for object layouts defined in C++. + +layout_extract.py produces these layouts from the parsed translation +unit and serializes them to layouts.json. They describe C++ storage, +member types, and the build configuration. Torque maps storage to field +types in layout-loader.cc; V8_TQ_* annotations pass through uninterpreted. + +The dataclasses validate on construction and raise LayoutError on failure. +Serialization is deterministic; parse_document validates the emitted +schema independently of Torque's loader. Source positions are serialized +separately so moving declarations does not change layouts.json. + +SCHEMA_VERSION is bumped on any change to the emitted shape; a consumer +rejects a version it does not know. +""" + +from __future__ import annotations + +import dataclasses +import json + +SCHEMA_VERSION = 1 + +# Keep this set closed so unknown storage wrappers fail during extraction. +STORAGE_KINDS = frozenset({ + # `arg` holds the structured TaggedMember type argument. + "tagged", + "protected_tagged", + # TrustedPointerMember<T, tag>: an indirect pointer handle; `tag` + # names the TrustedPointerTag constant. + "trusted_pointer", + "external_pointer", + "cpp_heap_pointer", + # A BitFieldGroup member: `name` is the C++ struct name and `bits` + # contains the fields in bit order. + "bitfield", + # A SmiBitFieldMember: a tagged slot containing at most 31 bits. + "smi_bitfield", + # Integral storage: `width` bytes, `signed` flag, and + # `pointer_width_alias` when the member was written through one + # (uintptr_t, size_t, ...), which its width alone does not say. + "int", + # An enum with integral storage; `name` is the unqualified C++ enum + # name, `width`/`signed` describe the underlying type. + "enum", + "bool", + "unaligned", + # A plain nested struct member; `name` is the C++ struct type + # name, `width` its size. + "struct", + "js_dispatch_handle", +}) + +ANNOTATION_PREFIX = "V8_TQ_" + + +class LayoutError(Exception): + """Invalid layout data that must not be emitted. Always fatal.""" + + +def _check(cond: bool, what: str) -> None: + if not cond: + raise LayoutError(what) + + +def _check_identifier(s: str, what: str) -> None: + _check( + isinstance(s, str) and s.replace("_", "a").isalnum() and s != "", + f"{what}: not an identifier: {s!r}") + + +def _check_class_scoped_name(s: str, what: str) -> None: + _check(isinstance(s, str), f"{what} must be a string") + for part in s.split("::"): + _check_identifier(part, what) + + +@dataclasses.dataclass(frozen=True) +class Config: + """The build configuration the layouts were extracted under. + + Offsets and sizes are only valid for a matching configuration, and + the JSON is generated per build directory, so a consumer must be + able to check that it got the right one: a 64-bit document read by a + 32-bit consumer would otherwise describe wrong layouts without any + error. Every size is read from the type that defines it in the parsed + translation unit, not from a flag. + """ + + tagged_size: int # sizeof(Tagged_t); < pointer_size iff compressed + pointer_size: int # sizeof(Address) + external_pointer_size: int # sizeof(ExternalPointer_t) + cpp_heap_pointer_size: int # sizeof(CppHeapPointer_t) + trusted_pointer_size: int # sizeof(TrustedPointer_t) + + def __post_init__(self) -> None: + for name in ("tagged_size", "pointer_size", "external_pointer_size", + "cpp_heap_pointer_size", "trusted_pointer_size"): + value = getattr(self, name) + _check( + isinstance(value, int) and not isinstance(value, bool) and + value in (1, 2, 4, 8), f"config: {name} is not a valid size: " + f"{value!r}") + _check(self.tagged_size <= self.pointer_size, + "config: tagged_size exceeds pointer_size") + + def to_json(self): + return { + "tagged_size": self.tagged_size, + "pointer_size": self.pointer_size, + "external_pointer_size": self.external_pointer_size, + "cpp_heap_pointer_size": self.cpp_heap_pointer_size, + "trusted_pointer_size": self.trusted_pointer_size, + } + + @staticmethod + def from_json(d) -> "Config": + _check(isinstance(d, dict), f"config: expected object, got {d!r}") + keys = { + "tagged_size", "pointer_size", "external_pointer_size", + "cpp_heap_pointer_size", "trusted_pointer_size" + } + _check_keys(d, keys, set(), "config") + return Config(**{k: d[k] for k in keys}) + + +@dataclasses.dataclass(frozen=True) +class Annotation: + """One V8_TQ_* annotation as written on a C++ declaration. + + Metagen does not interpret annotations: it splits the name from the + parenthesized argument and passes both through. What an annotation means, + which declarations it may appear on and whether it takes an argument + is defined by the consumer (for Torque, kAnnotations in layout-loader.cc), + so an annotation can be added or changed without touching metagen or this + schema. + """ + + name: str + arg: str | None = None + + def __post_init__(self) -> None: + _check( + isinstance(self.name, str) and self.name.startswith(ANNOTATION_PREFIX), + f"annotation name without the {ANNOTATION_PREFIX} prefix: " + f"{self.name!r}") + _check_identifier(self.name, "annotation name") + if self.arg is not None: + _check( + isinstance(self.arg, str) and self.arg != "", + f"{self.name}: empty argument") + + def to_json(self): + d = {"name": self.name} + if self.arg is not None: + d["arg"] = self.arg + return d + + @staticmethod + def from_json(d) -> "Annotation": + _check(isinstance(d, dict), f"annotation: expected object, got {d!r}") + _check_keys(d, {"name"}, {"arg"}, "annotation") + return Annotation(name=d["name"], arg=d.get("arg")) + + +def annotations_json(annotations: tuple["Annotation", ...]) -> list: + return [a.to_json() for a in annotations] + + +def canonical_annotations(annotations, what: str) -> tuple["Annotation", ...]: + """Sorted by name so the document is stable. A repeated annotation is + rejected here regardless of its meaning.""" + out = tuple(sorted(annotations, key=lambda a: (a.name, a.arg or ""))) + names = [a.name for a in out] + dupes = sorted({n for n in names if names.count(n) > 1}) + _check(not dupes, f"{what}: repeated annotation(s) {', '.join(dupes)}") + return out + + +def annotations_from_json(d, what: str) -> tuple["Annotation", ...]: + raw = d.get("annotations", ()) + _check(isinstance(raw, (list, tuple)), f"{what}: annotations is not a list") + return canonical_annotations((Annotation.from_json(a) for a in raw), what) + + +@dataclasses.dataclass(frozen=True) +class CppType: + """A C++ type argument: a named type with optional template + arguments, or a flattened union of these. + + Names are always C++ names: `double`, `uintptr_t`, `Map`, + `MaybeObject`. A consumer with its own names for primitives maps them + itself. + + Structured rather than a string so a consumer builds its type + representation directly instead of parsing C++ type syntax. The + verbatim string is available too, on Field.cpp_type.""" + + kind: str # "name" | "union" + name: str | None = None # for "name" + args: tuple[CppType, ...] = () # for "name": template arguments + members: tuple[CppType, ...] = () # for "union": UnionOf<...> flattened + # for "name": namespace qualification (iterator::IteratorRecord) + namespaces: tuple[str, ...] = () + + def __post_init__(self) -> None: + if self.kind == "name": + _check_identifier(self.name or "", "cpp type name") + for ns in self.namespaces: + _check_identifier(ns, "cpp type namespace") + _check(not self.members, "cpp name type with union members") + elif self.kind == "union": + _check(self.name is None and not self.args, "cpp union with name/args") + _check(len(self.members) >= 2, "cpp union with fewer than 2 members") + _check( + all(m.kind == "name" for m in self.members), + "cpp union members must be named types") + else: + raise LayoutError(f"unknown cpp type kind: {self.kind!r}") + + def to_json(self): + if self.kind == "name": + d = {"kind": "name", "name": self.name} + if self.namespaces: + d["namespaces"] = list(self.namespaces) + if self.args: + d["args"] = [a.to_json() for a in self.args] + return d + return {"kind": "union", "members": [m.to_json() for m in self.members]} + + @staticmethod + def from_json(d) -> "CppType": + _check(isinstance(d, dict), f"cpp type: expected object, got {d!r}") + kind = d.get("kind") + if kind == "name": + _check_keys(d, {"kind", "name"}, {"args", "namespaces"}, "cpp type") + return CppType( + kind="name", + name=d["name"], + args=tuple(CppType.from_json(a) for a in d.get("args", ())), + namespaces=tuple(d.get("namespaces", ()))) + if kind == "union": + _check_keys(d, {"kind", "members"}, set(), "cpp type") + return CppType( + kind="union", + members=tuple(CppType.from_json(m) for m in d["members"])) + raise LayoutError(f"unknown cpp type kind: {kind!r}") + + +def named_type(name: str, *args: CppType, + namespaces: tuple[str, ...] = ()) -> CppType: + return CppType( + kind="name", name=name, args=tuple(args), namespaces=namespaces) + + +def union_type(*members: CppType) -> CppType: + return CppType(kind="union", members=tuple(members)) + + +@dataclasses.dataclass(frozen=True) +class BitFieldEntry: + """One field of a "bitfield" storage: a base::BitField alias. + + `cpp_name` is the alias name; the consumer derives its own field name + from it (Torque: IsCallableBit -> is_callable).""" + + cpp_name: str + type: str + offset: int + num_bits: int + + def __post_init__(self) -> None: + _check_identifier(self.cpp_name, "bit field name") + _check_class_scoped_name(self.type, "bit field type") + _check(self.num_bits > 0, f"bit field {self.cpp_name}: no bits") + _check(self.offset >= 0, f"bit field {self.cpp_name}: negative offset") + + def to_json(self): + return { + "cpp_name": self.cpp_name, + "type": self.type, + "offset": self.offset, + "num_bits": self.num_bits, + } + + @staticmethod + def from_json(d) -> "BitFieldEntry": + _check(isinstance(d, dict), f"bit field: expected object, got {d!r}") + _check_keys(d, {"cpp_name", "type", "offset", "num_bits"}, set(), + "bit field") + return BitFieldEntry( + cpp_name=d["cpp_name"], + type=d["type"], + offset=d["offset"], + num_bits=d["num_bits"]) + + +@dataclasses.dataclass(frozen=True) +class StorageType: + """A field's storage, one of STORAGE_KINDS.""" + + kind: str + # "tagged" / "protected_tagged" / "unaligned": the structured type + # argument. "trusted_pointer": the pointee as CppType. + arg: CppType | None = None + # "trusted_pointer" / "external_pointer": the C++ tag constant name. + tag: str | None = None + # "int" / "enum": underlying width in bytes and signedness. + width: int | None = None + is_signed: bool | None = None + # Preserve pointer-width aliases; their canonical width is ABI-specific. + pointer_width_alias: str | None = None + # C++ type name without namespaces; includes enclosing classes for bitfields. + name: str | None = None + # "bitfield" / "smi_bitfield": the group's fields, in declaration + # order. Fields may overlap. + bits: tuple[BitFieldEntry, ...] = () + + def __post_init__(self) -> None: + _check(self.kind in STORAGE_KINDS, f"unknown storage kind: {self.kind!r}") + if self.kind in ("tagged", "protected_tagged", "unaligned"): + _check(self.arg is not None, f"{self.kind} storage without type arg") + if self.kind == "trusted_pointer": + # Both absent for an object's own pointer-table entry (the + # atomic TrustedPointerHandle member). + _check((self.arg is None) == (self.tag is None), + "trusted_pointer storage needs pointee and tag together") + if self.kind == "external_pointer": + _check(self.tag is not None, "external_pointer storage needs a tag") + if self.kind in ("int", "enum"): + _check(self.width in (1, 2, 4, 8), f"{self.kind} storage width invalid") + _check(self.is_signed is not None, f"{self.kind} storage needs signness") + if self.kind in ("enum", "struct"): + _check_identifier(self.name or "", f"{self.kind} storage name") + if self.kind == "struct": + _check(self.width is not None and self.width > 0, + "struct storage needs a size") + if self.kind in ("bitfield", "smi_bitfield"): + _check_class_scoped_name(self.name, f"{self.kind} storage name") + if self.kind == "bitfield": + _check(self.width in (1, 2, 4, 8), "bitfield storage width invalid") + capacity = self.width * 8 + else: + _check(self.width is None, "smi_bitfield storage with a width") + capacity = 31 + _check(bool(self.bits), f"{self.kind} storage without fields") + for bit in self.bits: + end = bit.offset + bit.num_bits + _check( + end <= capacity, f"bitfield {self.name}: {bit.cpp_name}: " + f"{end} bits exceed the storage") + else: + _check(not self.bits, f"{self.kind} storage with bit fields") + if self.pointer_width_alias is not None: + _check(self.kind == "int", "pointer_width_alias on non-int storage") + _check_identifier(self.pointer_width_alias, "pointer_width_alias") + + def to_json(self): + d = {"kind": self.kind} + if self.name is not None: + d["name"] = self.name + if self.arg is not None: + d["arg"] = self.arg.to_json() + if self.tag is not None: + d["tag"] = self.tag + if self.width is not None: + d["width"] = self.width + if self.is_signed is not None: + d["signed"] = self.is_signed + if self.pointer_width_alias is not None: + d["pointer_width_alias"] = self.pointer_width_alias + if self.bits: + d["bits"] = [b.to_json() for b in self.bits] + return d + + @staticmethod + def from_json(d) -> "StorageType": + _check(isinstance(d, dict), f"storage type: expected object, got {d!r}") + _check_keys(d, {"kind"}, { + "name", "arg", "tag", "width", "signed", "pointer_width_alias", "bits" + }, "storage type") + arg = d.get("arg") + return StorageType( + kind=d.get("kind", ""), + arg=CppType.from_json(arg) if arg is not None else None, + tag=d.get("tag"), + width=d.get("width"), + is_signed=d.get("signed"), + pointer_width_alias=d.get("pointer_width_alias"), + name=d.get("name"), + bits=tuple(BitFieldEntry.from_json(b) for b in d.get("bits", ()))) + + +@dataclasses.dataclass(frozen=True) +class Field: + """One fixed-offset field.""" + + cpp_name: str # C++ member name, e.g. "maybe_value_" + # The C++ type as written; `storage` does not keep it. + cpp_type: str + offset: int # byte offset from the start of the object + size: int # total byte size (element size * extent for arrays) + storage: StorageType + # Element count of a fixed-extent C++ array member. None for scalars. + array_extent: int | None = None + # The V8_TQ_* annotations written on the member, uninterpreted. + annotations: tuple[Annotation, ...] = () + # Stored only in the positions document and excluded from equality. + position: str | None = dataclasses.field(default=None, compare=False) + + def __post_init__(self) -> None: + _check_identifier(self.cpp_name, "field cpp_name") + _check( + isinstance(self.cpp_type, str) and self.cpp_type != "", + f"{self.cpp_name}: empty cpp_type") + object.__setattr__(self, "annotations", + canonical_annotations(self.annotations, self.cpp_name)) + _check(self.offset >= 0, f"{self.cpp_name}: negative offset") + # Zero only for the zero-length-array padding idiom. + _check(self.size >= 0, f"{self.cpp_name}: negative size") + if self.array_extent is not None: + _check(self.array_extent > 0, f"{self.cpp_name}: invalid array extent") + _check(self.size % self.array_extent == 0, + f"{self.cpp_name}: size not a multiple of array extent") + + def to_json(self): + d = { + "cpp_name": self.cpp_name, + "cpp_type": self.cpp_type, + "offset": self.offset, + "size": self.size, + "storage": self.storage.to_json(), + } + if self.array_extent is not None: + d["array_extent"] = self.array_extent + if self.annotations: + d["annotations"] = annotations_json(self.annotations) + return d + + @staticmethod + def from_json(d) -> "Field": + _check(isinstance(d, dict), f"field: expected object, got {d!r}") + _check_keys(d, {"cpp_name", "cpp_type", "offset", "size", "storage"}, + {"array_extent", "annotations"}, "field") + return Field( + cpp_name=d["cpp_name"], + cpp_type=d["cpp_type"], + offset=d["offset"], + size=d["size"], + storage=StorageType.from_json(d["storage"]), + array_extent=d.get("array_extent"), + annotations=annotations_from_json(d, d["cpp_name"])) + + +@dataclasses.dataclass(frozen=True) +class Tail: + """A trailing variable-length section (one FLEXIBLE_ARRAY_MEMBER). + + ClassLayout.annotations describes how Torque represents the tail. + Member annotations are stored here. The tail is recorded even without + annotations. + """ + + cpp_name: str + cpp_element_type: str # see Field.cpp_type + offset: int # == ClassLayout.size, the fixed-header end + element_size: int + element_storage: StorageType + # The V8_TQ_* annotations written on the flexible array member itself. + annotations: tuple[Annotation, ...] = () + # See Field.position. + position: str | None = dataclasses.field(default=None, compare=False) + + def __post_init__(self) -> None: + _check_identifier(self.cpp_name, "tail cpp_name") + _check( + isinstance(self.cpp_element_type, str) and self.cpp_element_type != "", + f"{self.cpp_name}: empty cpp_element_type") + object.__setattr__(self, "annotations", + canonical_annotations(self.annotations, self.cpp_name)) + _check(self.offset >= 0, "tail: negative offset") + _check(self.element_size > 0, "tail: non-positive element size") + + def to_json(self): + d = { + "cpp_name": self.cpp_name, + "cpp_element_type": self.cpp_element_type, + "offset": self.offset, + "element_size": self.element_size, + "element_storage": self.element_storage.to_json(), + } + if self.annotations: + d["annotations"] = annotations_json(self.annotations) + return d + + @staticmethod + def from_json(d) -> "Tail": + _check(isinstance(d, dict), f"tail: expected object, got {d!r}") + _check_keys(d, { + "cpp_name", "cpp_element_type", "offset", "element_size", + "element_storage" + }, {"annotations"}, "tail") + return Tail( + cpp_name=d["cpp_name"], + cpp_element_type=d["cpp_element_type"], + offset=d["offset"], + element_size=d["element_size"], + element_storage=StorageType.from_json(d["element_storage"]), + annotations=annotations_from_json(d, d["cpp_name"])) + + +@dataclasses.dataclass(frozen=True) +class ClassLayout: + """One exported class layout. + + `fields` holds only the fields this class introduces -- everything at + offsets in [base_size, size), flattened across intermediate + C++ bases without exported layouts. Inherited fields live on the base's own + layout. Contiguity is enforced: V8_OBJECT bodies compile with -Wpadded + as an error, so a gap can only mean an unmodeled member. + """ + + cpp_name: str # fully qualified, e.g. "v8::internal::Cell" + # None only for the hierarchy root, HeapObject. + base_cpp_name: str | None + base_size: int # sizeof(base_cpp_name); 0 for the root + size: int # sizeof(class); for tailed classes the fixed-header size + alignment: int + fields: tuple[Field, ...] + tail: Tail | None = None + # The V8_TQ_* annotations written on the class itself, uninterpreted. + annotations: tuple[Annotation, ...] = () + # See Field.position. + position: str | None = dataclasses.field(default=None, compare=False) + + def __post_init__(self) -> None: + _check("::" in self.cpp_name, f"{self.cpp_name}: cpp_name not qualified") + object.__setattr__(self, "annotations", + canonical_annotations(self.annotations, self.cpp_name)) + if self.base_cpp_name is not None: + _check("::" in self.base_cpp_name, + f"{self.base_cpp_name}: base cpp_name not qualified") + _check(self.base_size > 0, f"{self.cpp_name}: base_size must be > 0") + else: + _check(self.base_size == 0, f"{self.cpp_name}: root with base_size") + _check(self.size >= self.base_size, + f"{self.cpp_name}: smaller than its base") + _check(self.alignment > 0 and (self.alignment & (self.alignment - 1)) == 0, + f"{self.cpp_name}: alignment not a power of two") + + # Fields are ordered, in range, and contiguous from the base to the + # end of the fixed header. + pos = self.base_size + for f in self.fields: + _check( + f.offset == pos, f"{self.cpp_name}.{f.cpp_name}: offset " + f"{f.offset}, expected {pos} (gap or overlap)") + pos += f.size + _check( + pos == self.size, f"{self.cpp_name}: fields end at {pos}, " + f"class size is {self.size}") + if self.tail is not None: + _check( + self.tail.offset == self.size, + f"{self.cpp_name}: tail at {self.tail.offset}, header ends " + f"at {self.size}") + + names = [f.cpp_name for f in self.fields] + _check( + len(names) == len(set(names)), + f"{self.cpp_name}: duplicate field names") + + def to_json(self): + d = { + "cpp_name": self.cpp_name, + "base": self.base_cpp_name, + "base_size": self.base_size, + "size": self.size, + "alignment": self.alignment, + "fields": [f.to_json() for f in self.fields], + } + if self.annotations: + d["annotations"] = annotations_json(self.annotations) + if self.tail is not None: + d["tail"] = self.tail.to_json() + return d + + @staticmethod + def from_json(d) -> "ClassLayout": + _check(isinstance(d, dict), f"class: expected object, got {d!r}") + _check_keys( + d, {"cpp_name", "base", "base_size", "size", "alignment", "fields"}, + {"tail", "annotations"}, "class") + tail = d.get("tail") + return ClassLayout( + cpp_name=d["cpp_name"], + base_cpp_name=d["base"], + base_size=d["base_size"], + size=d["size"], + alignment=d["alignment"], + fields=tuple(Field.from_json(f) for f in d["fields"]), + tail=Tail.from_json(tail) if tail is not None else None, + annotations=annotations_from_json(d, d["cpp_name"])) + + +def _check_keys(d: dict, required: set, optional: set, what: str) -> None: + keys = set(d.keys()) + missing = required - keys + _check(not missing, f"{what}: missing keys {sorted(missing)}") + unknown = keys - required - optional + _check(not unknown, f"{what}: unknown keys {sorted(unknown)}") + + +def canonical_order(classes: list[ClassLayout]) -> list[ClassLayout]: + """The canonical emission order: a pre-order walk of the inheritance + forest, siblings and roots by fully-qualified C++ name. + + A class whose base is absent from the set roots its own tree, so a + partial harvest still orders. The order depends only on the layouts + themselves, which is what lets parse_document check that a document + is in canonical form. + """ + names = [c.cpp_name for c in classes] + if len(names) != len(set(names)): + dupes = sorted({n for n in names if names.count(n) > 1}) + raise LayoutError("duplicate class layouts: " + ", ".join(dupes)) + known = set(names) + children: dict[str, list[ClassLayout]] = {} + roots = [] + for c in sorted(classes, key=lambda x: x.cpp_name): + if c.base_cpp_name is not None and c.base_cpp_name in known: + children.setdefault(c.base_cpp_name, []).append(c) + else: + roots.append(c) + + ordered = [] + stack = list(reversed(roots)) + while stack: + c = stack.pop() + ordered.append(c) + stack.extend(reversed(children.get(c.cpp_name, ()))) + if len(ordered) != len(classes): + unreached = sorted(known - {c.cpp_name for c in ordered}) + raise LayoutError("cycle in the base chain of: " + ", ".join(unreached)) + return ordered + + +def serialize_document(config: Config, classes: list[ClassLayout]) -> str: + """Deterministic JSON for a set of class layouts. + + Classes emit in canonical_order; key order is the fixed to_json order. + """ + _check(isinstance(config, Config), "document: config is not a Config") + doc = { + "schema_version": SCHEMA_VERSION, + "config": config.to_json(), + "classes": [c.to_json() for c in canonical_order(classes)], + } + return json.dumps(doc, indent=1) + "\n" + + +def serialize_positions(classes: list[ClassLayout]) -> str: + """Deterministic positions document: C++ source positions for every + class and member, keyed by cpp_name. Separate from the layout + document so that only consumers that need positions (diagnostics, + cross-references) read it, and the layout document does not change + when declarations merely move.""" + entries = [] + for c in canonical_order(classes): + _check(bool(c.position), f"{c.cpp_name}: no source position") + members = {} + for f in c.fields: + _check(bool(f.position), f"{c.cpp_name}.{f.cpp_name}: no source position") + members[f.cpp_name] = f.position + if c.tail is not None: + _check( + bool(c.tail.position), + f"{c.cpp_name}.{c.tail.cpp_name}: no source position") + _check(c.tail.cpp_name not in members, + f"{c.cpp_name}: tail name collides with a field") + members[c.tail.cpp_name] = c.tail.position + entries.append({ + "cpp_name": c.cpp_name, + "position": c.position, + "members": dict(sorted(members.items())), + }) + doc = {"schema_version": SCHEMA_VERSION, "classes": entries} + return json.dumps(doc, indent=1) + "\n" + + +def parse_document(text: str) -> tuple[Config, list[ClassLayout]]: + """Parse and validate a serialized document. + + Torque's C++ loader reads the document independently; this parser + pins the schema contract in tests and gives tools a validated + reader. + """ + try: + doc = json.loads(text) + except json.JSONDecodeError as e: + raise LayoutError(f"not valid JSON: {e}") from e + _check(isinstance(doc, dict), "document: expected object") + _check_keys(doc, {"schema_version", "config", "classes"}, set(), "document") + version = doc["schema_version"] + _check(version == SCHEMA_VERSION, + f"schema version {version!r} != supported {SCHEMA_VERSION}") + config = Config.from_json(doc["config"]) + classes = [ClassLayout.from_json(c) for c in doc["classes"]] + # Reject documents that are valid but not canonical. + _check( + serialize_document(config, classes) == text, + "document is not in canonical serialized form") + return config, classes diff --git a/deps/v8/tools/metagen/metagen.py b/deps/v8/tools/metagen/metagen.py index bfc590af9184..1698787c3525 100644 --- a/deps/v8/tools/metagen/metagen.py +++ b/deps/v8/tools/metagen/metagen.py @@ -2,15 +2,11 @@ # Copyright 2026 the V8 project authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Entry point for metagen instance-type generation. +"""Entry point for metagen metadata generation. Drives a libclang harvest of V8_OBJECT / V8_IT_-annotated C++ class -declarations and emits `instance-types.h`. One invocation per build -dir; ninja calls us from `tools/metagen/BUILD.gn`. - -Layout-mode generation (`extern class Foo extends ...` Torque emission -from the same C++ headers) is a follow-up; the prototype lives on the -stacked `metagen-layout` branch and is not part of this CL. +declarations and emits `instance-types.h` and `layouts.json` for Torque. +One invocation per build dir; ninja calls us from `BUILD.gn`. """ from __future__ import annotations @@ -28,11 +24,11 @@ if _PARENT not in sys.path: sys.path.insert(0, _PARENT) -# Don't import cpp_hier yet -- it pulls in clang.cindex at module-load -# time, which requires the bindings to be resolvable. We bootstrap that -# in main() once the flags say where they come from. +# cpp_hier and layout_extract import clang.cindex. Import them in main() +# after configuring the bindings path from the command-line flags. from metagen import compile_flags # noqa: E402 from metagen import instance_types as it # noqa: E402 +from metagen import layout_ir # noqa: E402 def _write_depfile(depfile: str, output: str, deps: list[str]) -> None: @@ -102,23 +98,11 @@ def main() -> int: "toolchain whose builtin headers metagen parses against.") p.add_argument( "--clang-resource-dir", - default=None, + required=True, help="Path to the clang toolchain's resource dir (lib/clang/<N>, " "the directory whose include/ holds stddef.h, stdarg.h and the arch " "intrinsics). Passed to the parse as -resource-dir=, which lets the " - "driver order the builtin headers itself. Preferred over " - "--clang-builtin-headers-dir wherever the canonical layout exists. " - "Mutually exclusive with it.") - p.add_argument( - "--clang-builtin-headers-dir", - default=None, - help="Directory holding the clang builtin headers, for build systems " - "that stage them flat, with no lib/clang/<N> hierarchy for " - "-resource-dir= to point at (Bazel). Appended as a system-include dir " - "instead, which takes the path directly. Never probed for: the build " - "system knows where it staged them, and in a sandbox any path we " - "guessed would be an undeclared input. Mutually exclusive with " - "--clang-resource-dir.") + "driver order the builtin headers itself.") p.add_argument( "--driver", required=True, @@ -127,8 +111,14 @@ def main() -> int: p.add_argument( "--out", required=True, - help="Directory to write instance-types.h into. The only " - "directory metagen writes to.") + help="Directory to write instance-types.h and layouts.json into; " + "--enable-layout-positions also adds layout-positions.json.") + p.add_argument( + "--enable-layout-positions", + action="store_true", + help="Also write per-member C++ source positions to " + "layout-positions.json. This is separate so " + "position-only changes need not invalidate layout consumers.") p.add_argument( "--depfile", default=None, @@ -137,7 +127,7 @@ def main() -> int: "of. Only the driver is a declared build input, so without this " "an edit to one of them leaves the output stale.") # TODO(jgruber): Remove --check once metagen is the sole IT source and the - # Torque reference path (v8_use_metagen_instance_types=false) is gone. + # Torque reference path (v8_use_metagen=false) is gone. p.add_argument( "--check", action="store_true", @@ -152,6 +142,11 @@ def main() -> int: "runs `gn desc` against it (see --flags-from-target) to harvest the " "cflags clang uses for that target. Mutually exclusive with " "--compile-commands.") + p.add_argument( + "--driver-mode", + choices=("gcc", "cl"), + required=True, + help="Libclang driver mode selected by the build's C++ toolchain.") p.add_argument( "--source-root", default=None, @@ -226,8 +221,7 @@ def verbose_print(msg: str) -> None: file=sys.stderr) return 1 - # Bootstrap libclang *before* importing cpp_hier -- it references - # clang.cindex at module-load time. + # Configure libclang before importing modules that use clang.cindex. from metagen import clang_bootstrap # noqa: E402 if args.libclang_from_python_env: clang_bootstrap.bootstrap_from_python_env() @@ -243,6 +237,7 @@ def verbose_print(msg: str) -> None: # `os.path.abspath` honors that. clang_bootstrap.bootstrap(libclang_dir=os.path.abspath(args.libclang_dir)) from metagen import cpp_hier # noqa: E402 + from metagen import layout_extract # noqa: E402 if bool(args.build_dir) == bool(args.compile_commands): print( @@ -268,14 +263,18 @@ def verbose_print(msg: str) -> None: flags_target = args.flags_from_target if args.flags_toolchain: flags_target = f"{flags_target}({args.flags_toolchain})" - raw_flags, parse_cwd, cl_mode = compile_flags.get_compile_args_from_gn_desc( - build_dir, flags_target, os.path.abspath(args.source_root)) + try: + raw_flags, parse_cwd = compile_flags.get_compile_args_from_gn_desc( + build_dir, flags_target, os.path.abspath(args.source_root)) + except RuntimeError as e: + print(e, file=sys.stderr) + return 1 flags_source = f"build_dir={build_dir} (gn desc {flags_target})" else: cc_json = os.path.abspath(args.compile_commands) - raw_flags, parse_cwd, cl_mode = compile_flags.get_compile_args_from_file( - cc_json) + raw_flags, parse_cwd = compile_flags.get_compile_args_from_file(cc_json) flags_source = f"compile_commands={cc_json}" + cl_mode = args.driver_mode == "cl" flags_dependency = None if args.flags_dependency: @@ -299,34 +298,14 @@ def verbose_print(msg: str) -> None: # bindings, so its own resource dir has no headers in it. We take them # from the clang toolchain package instead, which rolls from the same # LLVM revision and so always matches the parsing library. - if bool(args.clang_resource_dir) == bool(args.clang_builtin_headers_dir): - print( - "error: exactly one of --clang-resource-dir or " - "--clang-builtin-headers-dir is required.", - file=sys.stderr) - return 1 - resource_dir = None - builtin_headers_dir = None - if args.clang_resource_dir: - resource_dir = os.path.abspath(args.clang_resource_dir) - flag = "--clang-resource-dir" - probe = os.path.join(resource_dir, "include", "stddef.h") - else: - builtin_headers_dir = os.path.abspath(args.clang_builtin_headers_dir) - flag = "--clang-builtin-headers-dir" - probe = os.path.join(builtin_headers_dir, "stddef.h") - if not os.path.isfile(probe): + resource_dir = os.path.abspath(args.clang_resource_dir) + stddef = os.path.join(resource_dir, "include", "stddef.h") + if not os.path.isfile(stddef): print( - f"[metagen] {flag} does not hold clang's builtin headers:\n" - f" {probe} not found", + f"[metagen] --clang-resource-dir does not hold clang's builtin " + f"headers:\n {stddef} not found", file=sys.stderr) return 1 - # -fsyntax-only, -ferror-limit=, -resource-dir= and -D carry `CLOption` - # visibility in clang's Options.td, so one spelling works under both - # drivers. -isystem does NOT: the clang-cl driver drops it with an - # ignorable -Wunknown-argument warning, and the parse then fails on the - # first intrinsics header. Its cl-mode equivalent is -imsvc. - sysinclude = "-imsvc" if cl_mode else "-isystem" prefix = [ "-fsyntax-only", @@ -375,19 +354,9 @@ def verbose_print(msg: str) -> None: # toolchain's command template puts them. flags = prefix + args.extra_flag + raw_flags + no_perfetto - # The builtin headers have to sit after libc++'s include dir and before - # the platform SDK's. - # - # -resource-dir= lets the driver place them, and it gets that right in - # both modes, so prefer it. That relies on libc++ arriving as -I, since - # the driver sorts -imsvc dirs after the resource dir. Only a flat - # staging dir needs the include-dir spelling, which we append: right for - # libc++, and right on Windows only while the SDK dirs arrive as - # /winsysroot. - if resource_dir: - flags.append(f"-resource-dir={resource_dir}") - else: - flags.append(f"{sysinclude}{builtin_headers_dir}") + # The driver places builtin headers after libc++ and before the SDK. + # In cl-mode, libc++ must arrive as -I to precede the resource dir. + flags.append(f"-resource-dir={resource_dir}") verbose_print(f"Harvesting class hierarchy from " f"{os.path.relpath(driver_path, v8_root)} ({flags_source})...") @@ -396,25 +365,29 @@ def verbose_print(msg: str) -> None: path = os.path.join(out_dir, "instance-types.h") cpp_res = cpp_hier.scan_cpp(v8_root, driver_path, flags, parse_cwd=parse_cwd) + + # Layout extraction adds the declarations it reads to the visited set. + # The depfile includes their source files. + try: + layout_config = layout_extract.extract_config(cpp_res.parsed) + layouts = layout_extract.extract_layouts(cpp_res.parsed, v8_root) + layout_json = layout_ir.serialize_document(layout_config, layouts) + if args.enable_layout_positions: + layout_positions_json = layout_ir.serialize_positions(layouts) + except layout_ir.LayoutError as e: + print(f"[metagen] layout extraction failed: {e}", file=sys.stderr) + return 1 + verbose_print(f" extracted {len(layouts)} layouts") + + visited_files = cpp_hier.visited_files(cpp_res.parsed.visited, v8_root) verbose_print(f" {len(cpp_res.classes)} classes, " - f"{len(cpp_res.provenance)} provenance files (from C++)") + f"{len(visited_files)} visited files (from C++)") classes = cpp_res.classes - # The files the harvest read a fact out of, not everything the parse - # opened. The closure is ~17x larger and mostly the inline layer and - # the sysroot, none of which can move a class head; depending on it - # would put the harvest on the critical path of edits that cannot - # change its output. Provenance is derived from the walk rather than - # filtered by hand, so it stays correct when a declaration moves -- - # and once metagen emits object layout, field types become one more - # provenance source rather than a reason to widen the whole set. - # - # Written ahead of the write-if-changed check below: ninja requires - # the depfile to exist after the action runs, including on the run - # that leaves the output untouched. --check writes no output, so a - # depfile naming one would be meaningless. + # Write the depfile with the files containing visited declarations. + # --check writes no output, so no depfile needed there. if args.depfile and not args.check: - deps = cpp_res.provenance + deps = visited_files if flags_dependency: deps = deps + [flags_dependency] _write_depfile(args.depfile, path, deps) @@ -424,11 +397,15 @@ def verbose_print(msg: str) -> None: # InstanceTypeTraits / heap snapshot labels, and the Print/Verify # dispatch list. tree = it.assign_instance_types(classes) - generated = ("#ifndef V8_GEN_TORQUE_GENERATED_INSTANCE_TYPES_H_\n" - "#define V8_GEN_TORQUE_GENERATED_INSTANCE_TYPES_H_\n" - "\n" + it.emit_enum_macros(tree) + it.emit_bucket_macros(tree) + - it.emit_dispatch_macro(tree) + - "#endif // V8_GEN_TORQUE_GENERATED_INSTANCE_TYPES_H_\n") + generated = ( + "// This file is automatically generated by tools/metagen/metagen.py.\n" + "// Do not edit manually.\n" + "\n" + "#ifndef V8_GEN_METAGEN_INSTANCE_TYPES_H_\n" + "#define V8_GEN_METAGEN_INSTANCE_TYPES_H_\n" + "\n" + it.emit_enum_macros(tree) + it.emit_bucket_macros(tree) + + it.emit_dispatch_macro(tree) + + "#endif // V8_GEN_METAGEN_INSTANCE_TYPES_H_\n") if args.check: import difflib @@ -438,15 +415,15 @@ def normalize(text: str) -> list[str]: # Comment-insensitive comparison: /* ... */ position comments # legitimately differ (C++ header links here, .tq links in # Torque's emission), as do // prose comments and the include - # guard / V8_USE_METAGEN_INSTANCE_TYPES scaffolding around the macro + # guard / V8_USE_METAGEN scaffolding around the macro # blocks. The diagnostic-dispatch list is also skipped: it has no # literal counterpart in Torque's emission (the torque path # aliases it to the debug-reader lists, see # src/objects/instance-types-gen.h). Only the remaining macro # definitions must match. - scaffold = re.compile(r"^#(ifndef V8_GEN_TORQUE_GENERATED_" - r"|define V8_GEN_TORQUE_GENERATED_" - r"|endif|if !V8_USE_METAGEN_INSTANCE_TYPES)") + scaffold = re.compile(r"^#(ifndef V8_GEN_(TORQUE_GENERATED|METAGEN)_" + r"|define V8_GEN_(TORQUE_GENERATED|METAGEN)_" + r"|endif|if !V8_USE_METAGEN)") out: list[str] = [] in_dispatch = False for ln in text.splitlines(): @@ -491,19 +468,26 @@ def normalize(text: str) -> list[str]: sys.stdout.write(line) return 1 - # Write-if-changed: the GN action rule carries restat=1, so leaving - # the mtime alone when the content is identical prunes the (near- - # global, via instance-type.h) set of dependents whenever an edit - # to one of the input headers doesn't change the IT assignment. + # Preserve unchanged outputs so their dependents do not rebuild. + _write_if_changed(path, generated, verbose_print) + _write_if_changed( + os.path.join(out_dir, "layouts.json"), layout_json, verbose_print) + if args.enable_layout_positions: + _write_if_changed( + os.path.join(out_dir, "layout-positions.json"), layout_positions_json, + verbose_print) + return 0 + + +def _write_if_changed(path: str, content: str, verbose_print) -> None: if os.path.exists(path): with open(path) as f: - if f.read() == generated: + if f.read() == content: verbose_print(f"Unchanged {path}") - return 0 + return with open(path, "w") as f: - f.write(generated) + f.write(content) verbose_print(f"Wrote {path}") - return 0 if __name__ == "__main__": diff --git a/deps/v8/tools/metagen/test/compile_flags_test.py b/deps/v8/tools/metagen/test/compile_flags_test.py new file mode 100644 index 000000000000..e68be065a0e7 --- /dev/null +++ b/deps/v8/tools/metagen/test/compile_flags_test.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest +from unittest import mock + +# Only this file's directory is on sys.path when it runs as a script, +# so the `metagen` package is not importable yet. Import through it +# anyway, so the patches below land on the module object metagen.py +# holds. +_TOOLS = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +if _TOOLS not in sys.path: + sys.path.insert(0, _TOOLS) + +from metagen import compile_flags # noqa: E402 + + +class GnCompileFlagsTest(unittest.TestCase): + + def test_external_build_directory(self): + with tempfile.TemporaryDirectory() as tmp: + source_root = Path(tmp) / 'src' + build_dir = Path(tmp) / 'cache' / 'Release' + source_root.mkdir() + build_dir.mkdir(parents=True) + (source_root / '.gn').touch() + (build_dir / 'args.gn').write_text('target_cpu = "x64"\n') + target = '//v8:probe(//build/toolchain:target)' + queried_dir = None + + def run_desc(argv, **kwargs): + nonlocal queried_dir + queried_dir = Path(argv[4]) + self.assertNotEqual(queried_dir, build_dir) + self.assertEqual(queried_dir.parent, build_dir.parent) + self.assertEqual((queried_dir / 'args.gn').read_text(), + 'target_cpu = "x64"\n') + self.assertTrue((queried_dir / 'build.ninja').is_file()) + desc = { + target: { + 'defines': ['PROBE=1'], + 'include_dirs': [ + '//v8/include', '//' + + os.path.relpath(queried_dir, source_root) + '/gen/include', + str(queried_dir / 'gen') + ], + 'cflags': [ + '-isysroot', '/SDK', '-isystem', + str(queried_dir / 'system/include') + ], + 'cflags_cc': ['-std=c++20'], + } + } + return subprocess.CompletedProcess(argv, 0, json.dumps(desc)) + + with mock.patch.object(compile_flags.sys, 'platform', 'linux'), \ + mock.patch.object( + compile_flags, '_find_gn', + return_value='gn') as find_gn, mock.patch.object( + compile_flags.subprocess, 'run', side_effect=run_desc) as run: + flags, cwd = compile_flags.get_compile_args_from_gn_desc( + str(build_dir), target, str(source_root)) + find_gn.assert_called_once_with(str(source_root)) + self.assertFalse(queried_dir.exists()) + argv, kwargs = run.call_args + self.assertEqual(argv[0], [ + 'gn', 'desc', '-q', '--root=' + str(source_root), + str(queried_dir), target, '--format=json' + ]) + self.assertEqual(kwargs['cwd'], str(source_root)) + self.assertTrue(kwargs['check']) + self.assertEqual(flags, [ + '-DPROBE=1', f'-I{source_root / "v8" / "include"}', + f'-I{build_dir / "gen" / "include"}', f'-I{build_dir / "gen"}', + '-isysroot', '/SDK', '-isystem', + str(build_dir / 'system/include'), '-std=c++20' + ]) + self.assertEqual(cwd, str(build_dir)) + + def test_macos_sdk_links_and_override_are_isolated(self): + with tempfile.TemporaryDirectory() as tmp: + source_root = Path(tmp) / 'src' + build_dir = source_root / 'out' / 'Release' + sdk = Path(tmp) / 'MacOSX.sdk' + sdk.mkdir() + sdk_links = build_dir / 'xcode_links' / 'embedder' + sdk_links.mkdir(parents=True) + try: + (sdk_links / sdk.name).symlink_to(sdk, target_is_directory=True) + except OSError as e: + if getattr(e, 'winerror', None) != 1314: + raise + self.skipTest('Symlink creation requires Windows privileges') + args = ('mac_sdk_path = ' + '"//out/Release/xcode_links/embedder/MacOSX.sdk"\n') + (build_dir / 'args.gn').write_text(args) + queried_dir = None + + def run_desc(argv, **kwargs): + nonlocal queried_dir + queried_dir = Path(argv[4]) + query_args = (queried_dir / 'args.gn').read_text() + self.assertTrue(query_args.startswith(args)) + self.assertIn('if (defined(mac_sdk_path))', query_args) + query_rel = os.path.relpath(queried_dir, source_root) + self.assertIn( + 'string_replace(mac_sdk_path, "//out/Release/", ' + f'{json.dumps("//" + query_rel + "/")})', query_args) + query_sdk = queried_dir / 'xcode_links' / 'embedder' / sdk.name + self.assertTrue(query_sdk.is_symlink()) + self.assertEqual(query_sdk.resolve(), sdk.resolve()) + # Mutating the query's links must not affect the running build. + query_sdk.unlink() + self.assertTrue((sdk_links / sdk.name).is_symlink()) + desc = {'//:probe': {'cflags': ['-isysroot', str(query_sdk)],}} + return subprocess.CompletedProcess(argv, 0, json.dumps(desc)) + + with mock.patch.object(compile_flags.sys, 'platform', 'darwin'), \ + mock.patch.object(compile_flags, '_find_gn', return_value='gn'), \ + mock.patch.object(compile_flags.subprocess, 'run', + side_effect=run_desc): + flags, cwd = compile_flags.get_compile_args_from_gn_desc( + str(build_dir), '//:probe', str(source_root)) + self.assertEqual(flags, ['-isysroot', str(sdk_links / sdk.name)]) + self.assertEqual(cwd, str(build_dir)) + self.assertEqual((build_dir / 'args.gn').read_text(), args) + self.assertFalse(queried_dir.exists()) + + def test_gn_failure_includes_stdout_and_stderr(self): + with tempfile.TemporaryDirectory() as tmp: + build_dir = Path(tmp) / 'build' + build_dir.mkdir() + (build_dir / 'args.gn').touch() + error = subprocess.CalledProcessError( + 1, + 'gn', + output='File is not inside output directory.', + stderr='SDK diagnostic') + with mock.patch.object(compile_flags.sys, 'platform', 'linux'), \ + mock.patch.object(compile_flags, '_find_gn', return_value='gn'), \ + mock.patch.object(compile_flags.subprocess, 'run', + side_effect=error): + with self.assertRaises(RuntimeError) as raised: + compile_flags.get_compile_args_from_gn_desc( + str(build_dir), '//:probe', tmp) + self.assertIn(error.stdout, str(raised.exception)) + self.assertIn(error.stderr, str(raised.exception)) + + def test_build_directory_on_another_drive(self): + with tempfile.TemporaryDirectory() as tmp: + source_root = Path(tmp) / 'src' + build_dir = Path(tmp) / 'build' + source_root.mkdir() + build_dir.mkdir() + (build_dir / 'args.gn').touch() + + def run_desc(argv, **kwargs): + temp_dir = Path(argv[4]) + desc = {'//:probe': {'include_dirs': [str(temp_dir / 'gen')],}} + return subprocess.CompletedProcess(argv, 0, json.dumps(desc)) + + with mock.patch.object(compile_flags.sys, 'platform', 'win32'), \ + mock.patch.object(compile_flags, '_find_gn', return_value='gn'), \ + mock.patch.object(compile_flags.os.path, 'relpath', + side_effect=ValueError('different drive')), \ + mock.patch.object(compile_flags.subprocess, 'run', + side_effect=run_desc): + flags, cwd = compile_flags.get_compile_args_from_gn_desc( + str(build_dir), '//:probe', str(source_root)) + self.assertEqual(flags, [f'-I{build_dir / "gen"}']) + self.assertEqual(cwd, str(build_dir)) + + +class FilterTest(unittest.TestCase): + + def test_drops_clang_modules_family(self): + # A use_clang_modules build passes all of these. -fbuiltin-module-map + # is the easy one to miss: it names no path, so it does nothing until + # the resource dir actually has builtin headers in it. + modules_flags = [ + '-fmodules', + '-fmodule-map-file=/x/module.modulemap', + '-fmodule-file=std=/x/std.pcm', + '-fimplicit-modules', + '-fimplicit-module-maps', + '-fno-implicit-modules', + '-fno-implicit-module-maps', + '-fbuiltin-module-map', + ] + self.assertEqual( + compile_flags._filter(modules_flags + ['-DKEEP'], ''), ['-DKEEP']) + + +class BazelCompileFlagsTest(unittest.TestCase): + """The compile_commands.json path (bazel/defs.bzl synthesizes it).""" + + def write(self, tmp, entries): + path = Path(tmp) / 'compile_commands.json' + path.write_text(json.dumps(entries)) + return str(path) + + # This entry carries one flag from every category the filter drops. + ARGUMENTS = [ + 'clang++', + '-c', + 'harvest-driver.cc', + '-o', + 'driver.o', + '-MMD', + '-MF', + 'driver.d', + '-DV8_ENABLE_SANDBOX', + '-I../../include', + '-Xclang', + '-add-plugin', + '-mllvm', + '-instcombine-lower-dbg', + '-Werror=unused', + '-fprofile-use=default.profdata', + '-fmodule-file=std.pcm', + '-std=c++20', + ] + + def entry(self, **overrides): + entry = { + 'directory': '/build', + 'file': 'harvest-driver.cc', + 'arguments': list(self.ARGUMENTS), + } + entry.update(overrides) + return entry + + def test_only_the_parseable_flags_survive(self): + with tempfile.TemporaryDirectory() as tmp: + flags, cwd = compile_flags.get_compile_args_from_file( + self.write(tmp, [self.entry()])) + # argv[0], the input file, the compile/dep/output flags, the plugin + # and backend pairs and the instrumentation families all go. + self.assertEqual(flags, + ['-DV8_ENABLE_SANDBOX', '-I../../include', '-std=c++20']) + self.assertEqual(cwd, '/build') + + def test_clang_cl_flags_survive(self): + with tempfile.TemporaryDirectory() as tmp: + entry = self.entry(arguments=['clang-cl.exe', '/std:c++20', '/WX']) + flags, _ = compile_flags.get_compile_args_from_file( + self.write(tmp, [entry])) + # /WX would escalate libclang's own warnings into errors. + self.assertEqual(flags, ['/std:c++20']) + + def test_response_file_is_rejected(self): + with tempfile.TemporaryDirectory() as tmp: + entry = self.entry(arguments=['clang++', '@driver.rsp']) + with self.assertRaises(RuntimeError) as e: + compile_flags.get_compile_args_from_file(self.write(tmp, [entry])) + self.assertIn('response file', str(e.exception)) + + def test_a_command_string_is_rejected(self): + # A `command` string would need the shell tokenization this path + # deliberately lacks. + with tempfile.TemporaryDirectory() as tmp: + entry = self.entry() + del entry['arguments'] + entry['command'] = 'clang++ -c harvest-driver.cc' + with self.assertRaises(RuntimeError) as e: + compile_flags.get_compile_args_from_file(self.write(tmp, [entry])) + self.assertIn('no `arguments` array', str(e.exception)) + + def test_more_than_one_entry_is_rejected(self): + with tempfile.TemporaryDirectory() as tmp: + path = self.write(tmp, [self.entry(), self.entry()]) + with self.assertRaises(RuntimeError) as e: + compile_flags.get_compile_args_from_file(path) + self.assertIn('one-entry list', str(e.exception)) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/v8/tools/metagen/test/instance_types_test.py b/deps/v8/tools/metagen/test/instance_types_test.py new file mode 100644 index 000000000000..7a595251090a --- /dev/null +++ b/deps/v8/tools/metagen/test/instance_types_test.py @@ -0,0 +1,392 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Tests for the instance-type solver and macro emission. + +The expectations are Torque's: the numbering rules from +src/torque/instance-type-generator.cc, the capification cases from +CapifyStringWithUnderscores (src/torque/utils.cc). A divergence in the +port shows up here, not as a --check diff against an emission that goes +away with the Torque path. +""" + +import contextlib +import io +import os +import sys +import unittest + +_TOOLS = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +if _TOOLS not in sys.path: + sys.path.insert(0, _TOOLS) + +from metagen import instance_types as it # noqa: E402 + + +def cls(name, base, **kwargs): + """A ClassInfo with the fields no test cares about filled in.""" + info = it.ClassInfo( + name=name, + base=base, + position=f"{name.lower()}.h:1:1", + is_abstract=kwargs.pop("abstract", False), + has_same_instance_type_as_parent=kwargs.pop("same_type_as_parent", False), + highest_within_parent=kwargs.pop("highest", False), + lowest_within_parent=kwargs.pop("lowest", False), + constraints=it.InstanceTypeConstraints( + value=kwargs.pop("value", -1), + num_flags_bits=kwargs.pop("flags_bits", -1))) + # What is left names a ClassInfo field directly. An unknown one is a + # typo, not a silent no-op. + for field, value in kwargs.items(): + if not hasattr(info, field): + raise TypeError(f"ClassInfo has no field {field}") + setattr(info, field, value) + return info + + +def own_values(root): + """Map each class holding an instance-type value to that value.""" + found = {} + + def walk(node): + if node.num_own_values == 1: + found[node.cls.name] = node.value + for child in node.children: + walk(child) + + walk(root) + return found + + +def ranges(root): + """Map each class in the solved tree to its (start, end) range.""" + found = {} + + def walk(node): + found[node.cls.name] = (node.start, node.end) + for child in node.children: + walk(child) + + walk(root) + return found + + +class MacroText: + """The emitted macros, split into entries per macro name. + + A macro that was not emitted raises on lookup instead of reporting no + entries, which would let an assertNotIn pass for the wrong reason. + """ + + def __init__(self, text): + self.text = text + self.macros = {} + for block in text.split("\n\n"): + lines = block.strip("\n").split("\n") + # Each block is a comment, then the #define, then its entries. + heads = [ + i for i, line in enumerate(lines) + if line.startswith("#define ") and line.endswith("(V) \\") + ] + if not heads: + continue + head = lines[heads[0]] + name = head[len("#define "):-len("(V) \\")] + entries = [] + for line in lines[heads[0] + 1:]: + # Every entry line continues the macro, the last one included. + assert line.endswith(" \\"), f"{name}: unterminated line {line!r}" + entries.append(line[:-2].strip()) + self.macros[name] = entries + + def __getitem__(self, macro): + if macro not in self.macros: + raise AssertionError( + f"{macro} not emitted; got {sorted(self.macros)}\n{self.text}") + return self.macros[macro] + + +class SolverTest(unittest.TestCase): + + def test_numbering_is_dense_from_zero(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Beta", "HeapObject"), + cls("Alpha", "HeapObject"), + ]) + # Equal-sized siblings fall to the name tie-break. + self.assertEqual(own_values(root), {"Alpha": 0, "Beta": 1}) + self.assertEqual((root.start, root.end), (0, 1)) + + def test_bigger_subtrees_are_placed_first(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Zoo", "HeapObject", abstract=True), + cls("ZooA", "Zoo"), + cls("ZooB", "Zoo"), + cls("Ant", "HeapObject"), + ]) + # Zoo spans two values, so it sorts ahead of Ant despite the name. + self.assertEqual(own_values(root), {"ZooA": 0, "ZooB": 1, "Ant": 2}) + + def test_lowest_and_highest_bracket_their_siblings(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Middle", "HeapObject"), + cls("Zebra", "HeapObject", lowest=True), + cls("Aardvark", "HeapObject", highest=True), + ]) + # Both markers win over the name tie-break. + self.assertEqual(own_values(root), {"Zebra": 0, "Middle": 1, "Aardvark": 2}) + + def test_two_lowest_children_are_fatal(self): + stderr = io.StringIO() + with contextlib.redirect_stderr(stderr), self.assertRaises(SystemExit) as e: + it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("First", "HeapObject", lowest=True), + cls("Second", "HeapObject", lowest=True), + ]) + self.assertEqual(e.exception.code, 1) + self.assertIn("two lowest children", stderr.getvalue()) + + def test_abstract_class_spans_its_children(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Trailing", "HeapObject"), + cls("Group", "HeapObject", abstract=True), + cls("GroupA", "Group"), + cls("GroupB", "Group"), + ]) + solved = ranges(root) + self.assertEqual( + own_values(root), { + "GroupA": 0, + "GroupB": 1, + "Trailing": 2 + }) + # An abstract class holds no value of its own, and its range covers + # its children exactly. The emitted FIRST_/LAST_ check reads that + # range. + self.assertNotIn("Group", own_values(root)) + self.assertEqual(solved["Group"], (0, 1)) + self.assertEqual(solved["HeapObject"], (0, 2)) + + def test_explicit_value_is_honored(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Filler", "HeapObject"), + cls("Pinned", "HeapObject", value=17), + ]) + self.assertEqual(own_values(root)["Pinned"], 17) + + def test_explicit_value_survives_unconstrained_siblings(self): + # Constrained children go first, so the fillers flow around the + # pinned value instead of squatting on it. + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("AFiller", "HeapObject"), + cls("BFiller", "HeapObject"), + cls("Pinned", "HeapObject", value=0), + ]) + self.assertEqual( + own_values(root), { + "Pinned": 0, + "AFiller": 1, + "BFiller": 2 + }) + + def test_colliding_explicit_values_are_fatal(self): + stderr = io.StringIO() + with contextlib.redirect_stderr(stderr), self.assertRaises(SystemExit) as e: + it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("PinnedA", "HeapObject", value=5), + cls("PinnedB", "HeapObject", value=5), + ]) + self.assertEqual(e.exception.code, 1) + self.assertIn("PinnedB", stderr.getvalue()) + + def test_type_shared_with_parent_gets_no_value(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Owner", "HeapObject"), + cls("Sharer", "Owner", same_type_as_parent=True), + ]) + self.assertEqual(own_values(root), {"Owner": 0}) + self.assertEqual( + MacroText(it.emit_enum_macros(root))["TORQUE_ASSIGNED_INSTANCE_TYPES"], + [ + "V(FIRST_HEAP_OBJECT_TYPE, 0)", "V(FIRST_OWNER_TYPE, 0)", + "V(OWNER_TYPE, 0)", "V(LAST_OWNER_TYPE, 0)", + "V(LAST_HEAP_OBJECT_TYPE, 0)" + ]) + + def test_flag_class_reserves_a_power_of_two(self): + root = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Flagged", "HeapObject", flags_bits=2), + cls("Shadowed", "Flagged"), + cls("After", "HeapObject"), + ]) + solved = ranges(root) + self.assertEqual(solved["Flagged"], (0, 3)) + # Subclasses share the flag bits, so they leave the tree. + self.assertNotIn("Shadowed", solved) + self.assertEqual(own_values(root)["After"], 4) + + def test_multiple_roots_are_fatal(self): + stderr = io.StringIO() + with contextlib.redirect_stderr(stderr), self.assertRaises(SystemExit) as e: + it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Stray", "NotInTheHarvest"), + ]) + self.assertEqual(e.exception.code, 1) + self.assertIn("multiple roots", stderr.getvalue()) + + def test_no_classes_yields_no_tree(self): + self.assertIsNone(it.assign_instance_types([])) + + +class EmissionTest(unittest.TestCase): + + def setUp(self): + self.tree = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Abstract", "HeapObject", abstract=True), + cls("AbstractA", "Abstract"), + cls("AbstractB", "Abstract"), + cls("Family", "HeapObject", has_printer=True, has_verifier=True), + cls("Child", "Family"), + cls("Loner", "HeapObject", has_printer=True, has_verifier=True), + ]) + # Pin the layout the expectations below are written against. + self.assertEqual( + own_values(self.tree), { + "AbstractA": 0, + "AbstractB": 1, + "Family": 2, + "Child": 3, + "Loner": 4 + }) + + def test_every_type_gets_first_and_last_markers(self): + macros = MacroText(it.emit_enum_macros(self.tree)) + entries = macros["TORQUE_ASSIGNED_INSTANCE_TYPES"] + self.assertIn("V(FIRST_ABSTRACT_TYPE, 0)", entries) + self.assertIn("V(LAST_ABSTRACT_TYPE, 1)", entries) + # The markers alias the value for a single-value class, and + # generated CSA reads them either way. + self.assertIn("V(FIRST_LONER_TYPE, 4)", entries) + self.assertIn("V(LONER_TYPE, 4)", entries) + self.assertIn("V(LAST_LONER_TYPE, 4)", entries) + # The flat list carries the concrete types only. + values_list = macros["TORQUE_ASSIGNED_INSTANCE_TYPE_LIST"] + self.assertIn("V(LONER_TYPE)", values_list) + self.assertNotIn("V(ABSTRACT_TYPE)", values_list) + + def test_flag_class_has_no_last_marker(self): + tree = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Flagged", "HeapObject", flags_bits=2), + ]) + entries = MacroText( + it.emit_enum_macros(tree))["TORQUE_ASSIGNED_INSTANCE_TYPES"] + self.assertIn("V(FIRST_FLAGGED_TYPE, 0)", entries) + self.assertNotIn("V(LAST_FLAGGED_TYPE, 3)", entries) + + def test_buckets_split_single_multiple_and_range(self): + macros = MacroText(it.emit_bucket_macros(self.tree)) + # SINGLE: an own value, and nothing else in the range. + self.assertEqual(macros["INSTANCE_TYPE_LIST_SINGLE"], [ + "V(AbstractA, ABSTRACT_A_TYPE)", "V(AbstractB, ABSTRACT_B_TYPE)", + "V(Child, CHILD_TYPE)", "V(Loner, LONER_TYPE)" + ]) + # MULTIPLE: an own value, and a subtree that spans more. + self.assertEqual(macros["INSTANCE_TYPE_LIST_MULTIPLE"], + ["V(Family, FAMILY_TYPE)"]) + # RANGE: no own value, and a span of several. + self.assertEqual(macros["INSTANCE_TYPE_LIST_RANGE"], [ + "V(Abstract, FIRST_ABSTRACT_TYPE, LAST_ABSTRACT_TYPE)", + "V(Family, FIRST_FAMILY_TYPE, LAST_FAMILY_TYPE)" + ]) + + def test_root_gets_no_range_entry(self): + # The root's check would be a tautology; Torque skips it. + self.assertNotIn( + "V(HeapObject, FIRST_HEAP_OBJECT_TYPE, LAST_HEAP_OBJECT_TYPE)", + MacroText(it.emit_bucket_macros(self.tree))["INSTANCE_TYPE_LIST_RANGE"]) + + def test_no_auto_checker_keeps_the_type_but_drops_the_check(self): + tree = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Hidden", "HeapObject", no_auto_checker=True), + cls("Visible", "HeapObject"), + ]) + self.assertIn( + "V(HIDDEN_TYPE, 0)", + MacroText(it.emit_enum_macros(tree))["TORQUE_ASSIGNED_INSTANCE_TYPES"]) + self.assertEqual( + MacroText(it.emit_bucket_macros(tree))["INSTANCE_TYPE_LIST_SINGLE"], + ["V(Visible, VISIBLE_TYPE)"]) + + def test_dispatch_needs_a_printer_and_a_verifier(self): + tree = it.assign_instance_types([ + cls("HeapObject", None, abstract=True), + cls("Both", "HeapObject", has_printer=True, has_verifier=True), + cls("PrinterOnly", "HeapObject", has_printer=True), + cls("VerifierOnly", "HeapObject", has_verifier=True), + cls("HandWritten", + "HeapObject", + has_printer=True, + has_verifier=True, + no_auto_dispatch=True), + ]) + macros = MacroText(it.emit_dispatch_macro(tree)) + self.assertEqual(macros["HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST"], + ["V(Both, BOTH_TYPE)"]) + + def test_empty_tree_still_defines_every_macro(self): + for emit, macros in ((it.emit_enum_macros, [ + "TORQUE_ASSIGNED_INSTANCE_TYPES", "TORQUE_ASSIGNED_INSTANCE_TYPE_LIST" + ]), (it.emit_bucket_macros, [ + "INSTANCE_TYPE_LIST_SINGLE", "INSTANCE_TYPE_LIST_MULTIPLE", + "INSTANCE_TYPE_LIST_RANGE" + ]), (it.emit_dispatch_macro, ["HEAP_OBJECT_DIAGNOSTIC_DISPATCH_LIST"])): + emitted = MacroText(emit(None)) + for macro in macros: + self.assertEqual(emitted[macro], [], macro) + + +class CapifyTest(unittest.TestCase): + + # Ground truth: CapifyStringWithUnderscores (src/torque/utils.cc). + CASES = { + "Code": "CODE", + "ArrayList": "ARRAY_LIST", + "AsyncGeneratorRequest": "ASYNC_GENERATOR_REQUEST", + "SmallOrderedHashMap": "SMALL_ORDERED_HASH_MAP", + # A digit closes a word. + "Uint8TypedArrayConstructor": "UINT8_TYPED_ARRAY_CONSTRUCTOR", + "Tuple2": "TUPLE2", + # JSAbc yields JS_ABC for any Abc, wherever the JS sits. + "JSObject": "JS_OBJECT", + "JSWeakRef": "JS_WEAK_REF", + "WasmJSFunction": "WASM_JS_FUNCTION", + # A longer capital run after the JS stays one word. + "JSAPIObjectWithEmbedderSlots": "JS_APIOBJECT_WITH_EMBEDDER_SLOTS", + # Dots and dashes separate words: file names reach this too. + "instance-types.h": "INSTANCE_TYPES_H", + } + + def test_matches_torque(self): + for name, expected in self.CASES.items(): + self.assertEqual(it.capify_with_underscores(name), expected, name) + + +if __name__ == "__main__": + unittest.main() diff --git a/deps/v8/tools/metagen/test/metagen_test.py b/deps/v8/tools/metagen/test/metagen_test.py new file mode 100644 index 000000000000..16b243d113cb --- /dev/null +++ b/deps/v8/tools/metagen/test/metagen_test.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import contextlib +import io +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import types +import unittest +from unittest import mock + +# Only this file's directory is on sys.path when it runs as a script. +_TOOLS = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +if _TOOLS not in sys.path: + sys.path.insert(0, _TOOLS) + +from metagen import clang_bootstrap, compile_flags, metagen # noqa: E402 + + +class HarvestReached(Exception): + pass + + +class DriverModeTest(unittest.TestCase): + + def test_invalid_mode_arguments(self): + for options, error in ( + (['--build-dir=out'], 'required: --driver-mode'), + (['--build-dir=out', '--driver-mode=unknown'], 'invalid choice'), + (['--compile-commands=commands.json'], 'required: --driver-mode'), + (['--compile-commands=commands.json', + '--driver-mode=unknown'], 'invalid choice'), + ): + with self.subTest(options=options): + stderr = io.StringIO() + with mock.patch.object(sys, 'argv', + ['metagen', '--driver=driver.cc', '--out=gen', + '--clang-resource-dir=/unused'] + + options), contextlib.redirect_stderr(stderr), \ + mock.patch.object(compile_flags, + 'get_compile_args_from_gn_desc') as gn, \ + mock.patch.object(compile_flags, + 'get_compile_args_from_file') as database: + with self.assertRaises(SystemExit) as raised: + metagen.main() + self.assertEqual(raised.exception.code, 2) + self.assertIn(error, stderr.getvalue()) + gn.assert_not_called() + database.assert_not_called() + + def test_harvest_driver_flags(self): + for source, mode, raw_flags in ( + ('gn', 'gcc', ['-isysroot', '/SDK', '-iframework', '/Frameworks']), + ('gn', 'gcc', ['/absolute/path']), + ('gn', 'cl', []), + ('gn', 'cl', ['/std:c++20', '/winsysroot', '/SDK']), + ('clang++', 'gcc', ['-std=c++20']), + ('clang-cl.exe', 'cl', ['/std:c++20']), + ('compiler-wrapper', 'gcc', ['-isysroot', '/SDK']), + ('compiler-wrapper', 'cl', ['/std:c++20']), + ('x86_64-w64-mingw32-g++', 'gcc', ['-std=c++20']), + ): + with self.subTest(source=source, mode=mode, raw_flags=raw_flags), \ + tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + include = root / 'include' + include.mkdir() + (include / 'stddef.h').touch() + argv = [ + 'metagen', + '--driver=driver.cc', + f'--out={root / "gen"}', + '--libclang-from-python-env', + f'--driver-mode={mode}', + f'--clang-resource-dir={root}', + ] + if source == 'gn': + (root / 'args.gn').touch() + argv += [ + f'--build-dir={root}', + f'--source-root={root}', + '--flags-from-target=//:probe', + '--flags-toolchain=//:target', + ] + else: + database = root / 'compile_commands.json' + database.write_text( + json.dumps([{ + 'directory': str(root), + 'file': 'probe.cc', + 'arguments': [source, '-c', 'probe.cc'] + raw_flags, + }])) + argv.append(f'--compile-commands={database}') + desc = {'//:probe(//:target)': {'cflags': raw_flags}} + scan = mock.Mock(side_effect=HarvestReached) + cpp_hier = types.ModuleType('metagen.cpp_hier') + cpp_hier.scan_cpp = scan + layout_extract = types.ModuleType('metagen.layout_extract') + with mock.patch.object(sys, 'argv', argv), \ + mock.patch.object(clang_bootstrap, 'bootstrap_from_python_env'), \ + mock.patch.object(sys.modules['metagen'], 'cpp_hier', cpp_hier, + create=True), \ + mock.patch.object(sys.modules['metagen'], 'layout_extract', + layout_extract, create=True), \ + mock.patch.object(compile_flags, '_find_gn', return_value='gn'), \ + mock.patch.object(compile_flags.subprocess, 'run', return_value= + subprocess.CompletedProcess( + [], 0, json.dumps(desc))): + with self.assertRaises(HarvestReached): + metagen.main() + scan.assert_called_once() + flags = scan.call_args.args[2] + self.assertEqual(scan.call_args.kwargs['parse_cwd'], str(root)) + self.assertEqual('--driver-mode=cl' in flags, mode == 'cl') + if mode == 'cl': + self.assertEqual(flags[0], '--driver-mode=cl') + self.assertEqual(flags[-1], f'-resource-dir={root}') + for flag in raw_flags: + self.assertIn(flag, flags) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/v8/tools/metagen/tests/layout_extract_test.py b/deps/v8/tools/metagen/tests/layout_extract_test.py new file mode 100644 index 000000000000..4fc1109222c1 --- /dev/null +++ b/deps/v8/tools/metagen/tests/layout_extract_test.py @@ -0,0 +1,1078 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Extractor tests against small synthetic translation units. + +Each test parses a C++ snippet with stand-ins for V8 object macros and +member wrappers using the bundled libclang. The tests use the production +code for class discovery, base resolution, and layout extraction. +""" + +import contextlib +import io +import os +import sys +import unittest + +_TOOLS_DIR = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +_V8_ROOT = os.path.dirname(_TOOLS_DIR) +sys.path.insert(0, _TOOLS_DIR) + +from metagen import clang_bootstrap + +clang_bootstrap.bootstrap( + libclang_dir=os.path.join(_V8_ROOT, "third_party", "llvm-libclang")) + +import clang.cindex as cindex # noqa: E402 + +from metagen import cpp_hier # noqa: E402 +from metagen import layout_extract # noqa: E402 +from metagen import layout_ir # noqa: E402 +from metagen.layout_ir import ( + LayoutError, + named_type, # noqa: E402 + serialize_document, + serialize_positions) + +# A fake of the V8 object macros as V8_METAGEN_GENERATION_PASS expands +# them, member wrappers with layout-compatible stand-in storage (4-byte +# handles, as in compressed-pointer builds), and the alias/union type +# stubs. Every concrete class below that reaches HeapObject participates +# in layout export automatically. +_PRELUDE = r""" +#define V8_TQ_ANNOTATE(P) [[clang::annotate(P)]] +#define V8_TQ_MARK(NAME, PAYLOAD) \ + using V8TQ_##NAME V8_TQ_ANNOTATE(PAYLOAD) = void +#define V8_TQ_TAIL_LENGTH(F) \ + V8_TQ_MARK(TqTailLength, "V8_TQ_TAIL_LENGTH(" #F ")") +#define V8_TQ_CONST V8_TQ_ANNOTATE("V8_TQ_CONST") +#define V8_TQ_RELAXED V8_TQ_ANNOTATE("V8_TQ_RELAXED") +#define V8_TQ_ACQ_REL V8_TQ_ANNOTATE("V8_TQ_ACQ_REL") +#define V8_TQ_CUSTOM_WEAK V8_TQ_ANNOTATE("V8_TQ_CUSTOM_WEAK") +#define V8_TQ_TYPE(T) V8_TQ_ANNOTATE("V8_TQ_TYPE(" #T ")") +#define V8_TQ_NAME(N) V8_TQ_ANNOTATE("V8_TQ_NAME(" #N ")") + +using uint8_t = unsigned char; +using uint16_t = unsigned short; +using uint32_t = unsigned int; +using int32_t = int; +using int16_t = short; + +namespace std { +template <typename T> +class atomic { + T value_; +}; +} // namespace std + +namespace v8 { +namespace internal { + +using TrustedPointerHandle = uint32_t; + +class Map; +class Smi; +class String; +class Undefined; + +// Modelled as in globals.h: the schemes are aliases for an impl +// template parameterised by a cage, which is what the extraction +// matches on. +template <typename Cage> +class V8HeapCompressionSchemeImpl; +class MainCage; +class TrustedCage; +using V8HeapCompressionScheme = V8HeapCompressionSchemeImpl<MainCage>; +using TrustedSpaceCompressionScheme = V8HeapCompressionSchemeImpl<TrustedCage>; + +template <typename T, typename CompressionScheme = V8HeapCompressionScheme> +class TaggedMember { + uint32_t storage_; +}; +template <typename T> +using ProtectedTaggedMember = TaggedMember<T, TrustedSpaceCompressionScheme>; + +enum TrustedPointerTag { kTestBytecodeTag, kTestCodeTag }; +enum ExternalPointerTag { kTestCallbackTag }; +template <typename Tag> +struct TagRange { + constexpr TagRange(Tag tag) : first(tag), last(tag) {} + constexpr TagRange(Tag first, Tag last) : first(first), last(last) {} + Tag first; + Tag last; +}; +using ExternalPointerTagRange = TagRange<ExternalPointerTag>; +using TrustedPointerTagRange = TagRange<TrustedPointerTag>; +template <typename T, TrustedPointerTagRange tag> +class TrustedPointerMember { + uint32_t handle_; +}; +template <ExternalPointerTagRange tag> +class ExternalPointerMember { + uint32_t handle_; +}; + +template <typename... Ts> +class Union {}; +template <typename... Ts> +using UnionOf = Union<Ts...>; +template <typename T> +class Weak {}; +template <typename T> +using MaybeWeak = UnionOf<T, Weak<T>>; + +class HeapObject; +using MaybeObject = Union<Smi, HeapObject, Weak<HeapObject>>; + +class HeapObject { + public: + TaggedMember<Map> map_; +}; + +} // namespace internal +} // namespace v8 +""" + +_PARSE_OPTIONS = ( + cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD + | cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES) + +_INDEX = cindex.Index.create() + +# Absolute so the v8-root-relative paths come out right. +_V8_ROOT = "/nonexistent-v8-root" + + +def parse(body: str, + extra_headers=None, + *, + prelude=_PRELUDE) -> cpp_hier.ParsedTU: + """Parse a snippet. `extra_headers` maps a v8-root-relative path to + its contents and prepends an #include of it, for the checks that read + which header a declaration came from.""" + includes = "".join( + f'#include "{_V8_ROOT}/{path}"\n' for path in (extra_headers or {})) + source = prelude + includes + "namespace v8 { namespace internal {\n" + \ + body + "\n} }\n" + unsaved = [("metagen_layout_test.cc", source)] + for path, contents in (extra_headers or {}).items(): + unsaved.append((f"{_V8_ROOT}/{path}", + "#pragma once\nnamespace v8 { namespace internal {\n" + + contents + "\n} }\n")) + tu = _INDEX.parse( + "metagen_layout_test.cc", + args=["-x", "c++", "-std=c++20", "-fsyntax-only"], + unsaved_files=unsaved, + options=_PARSE_OPTIONS) + errors = [d for d in tu.diagnostics if d.severity >= cindex.Diagnostic.Error] + if errors: + raise AssertionError("test snippet does not compile: " + + "; ".join(str(d) for d in errors)) + return cpp_hier._harvest_classes(tu, _V8_ROOT).parsed + + +def extract_layouts(body: str, extra_headers=None): + h = parse(body, extra_headers) + return { + r.cpp_name.rsplit("::", 1)[-1]: r + for r in layout_extract.extract_layouts(h, _V8_ROOT) + } + + +class SimpleClassTest(unittest.TestCase): + + def test_cell_analog(self): + layouts = extract_layouts(""" + class Cell : public HeapObject { + public: + TaggedMember<MaybeObject> maybe_value_; + }; + """) + self.assertEqual(set(layouts), {"HeapObject", "Cell"}) + cell = layouts["Cell"] + self.assertEqual(cell.cpp_name, "v8::internal::Cell") + self.assertEqual(cell.base_cpp_name, "v8::internal::HeapObject") + self.assertEqual(cell.base_size, 4) + self.assertEqual(cell.size, 8) + (f,) = cell.fields + self.assertEqual(f.cpp_name, "maybe_value_") + self.assertEqual(f.annotations, ()) + self.assertEqual(f.offset, 4) + self.assertEqual(f.size, 4) + self.assertEqual(f.storage.kind, "tagged") + # The alias name is kept; the canonical Union<...> is not used. + self.assertEqual(f.storage.arg, named_type("MaybeObject")) + + def test_heap_object_root(self): + layouts = extract_layouts("") + root = layouts["HeapObject"] + self.assertIsNone(root.base_cpp_name) + self.assertEqual(root.base_size, 0) + self.assertEqual(root.size, 4) + (map_field,) = root.fields + self.assertEqual(map_field.cpp_name, "map_") + self.assertEqual(map_field.storage.arg, named_type("Map")) + + def test_serializes(self): + layouts = extract_layouts(""" + class Cell : public HeapObject { + public: + TaggedMember<MaybeObject> maybe_value_; + }; + """) + text = serialize_document( + layout_ir.Config( + tagged_size=4, + pointer_size=8, + external_pointer_size=4, + cpp_heap_pointer_size=4, + trusted_pointer_size=4), list(layouts.values())) + self.assertIn('"schema_version": 1', text) + self.assertIn('"cpp_type": "TaggedMember<MaybeObject>"', text) + self.assertNotIn('"position"', text) + positions = serialize_positions(list(layouts.values())) + self.assertIn('"maybe_value_"', positions) + + def test_raw_enum_and_atomic_fields(self): + layouts = extract_layouts(""" + enum class FooKind : uint16_t { kA, kB }; + class Foo : public HeapObject { + public: + int32_t frame_size_; + uint16_t parameter_count_; + FooKind kind_; + std::atomic<uint32_t> usage_; + }; + """) + foo = layouts["Foo"] + kinds = [(f.cpp_name, f.storage.kind, f.storage.width) for f in foo.fields] + self.assertEqual(kinds, [ + ("frame_size_", "int", 4), + ("parameter_count_", "int", 2), + ("kind_", "enum", 2), + ("usage_", "int", 4), + ]) + frame_size, parameter_count, kind, usage = foo.fields + self.assertTrue(frame_size.storage.is_signed) + self.assertFalse(parameter_count.storage.is_signed) + self.assertFalse(usage.storage.is_signed) + self.assertEqual(kind.storage.name, "FooKind") + self.assertTrue(foo.fields[0].storage.is_signed) + self.assertFalse(foo.fields[3].storage.is_signed) + self.assertEqual(foo.fields[2].storage.name, "FooKind") + + def _uintptr_layouts(self, uintptr_definition): + # A stand-in with the member-wrapper shape of UnalignedValueMember. + # The Smi slot keeps the layout contiguous when the 8-byte members + # need 8-byte alignment after the 4-byte HeapObject header. + return extract_layouts(f""" + {uintptr_definition} + template <typename T> + class UnalignedValueMember {{ T value_; }}; + class Foo : public HeapObject {{ + public: + TaggedMember<Smi> slot_; + UnalignedValueMember<uintptr_t> wrapped_; + uintptr_t bare_; + }}; + """) + + def test_uintptr_alias_wins_over_msvc_canonical_kind(self): + # MSVC x64: uintptr_t canonicalizes to unsigned long long; the + # alias must still be recognized as pointer-width. + layouts = self._uintptr_layouts("using uintptr_t = unsigned long long;") + _, wrapped, bare = layouts["Foo"].fields + self.assertEqual(wrapped.storage.arg, named_type("uintptr_t")) + self.assertEqual(bare.storage.pointer_width_alias, "uintptr_t") + self.assertEqual(bare.storage.width, 8) + + def test_uintptr_alias_wins_over_ilp32_canonical_kind(self): + # ILP32: uintptr_t canonicalizes to unsigned int. The width alone + # would say uint32, which is why the alias is recorded by name. + layouts = self._uintptr_layouts("using uintptr_t = unsigned int;") + _, wrapped, bare = layouts["Foo"].fields + self.assertEqual(wrapped.storage.arg, named_type("uintptr_t")) + self.assertEqual(bare.storage.pointer_width_alias, "uintptr_t") + self.assertEqual(bare.storage.width, 4) + + def test_no_torque_names_reach_the_layout(self): + # The schema preserves C++ type names for consumers to map. + layouts = extract_layouts(""" + using uintptr_t = unsigned long long; + class UnalignedDoubleMember { double value_; }; + template <typename T> + class UnalignedValueMember { T value_; }; + class Foo : public HeapObject { + public: + TaggedMember<Smi> slot_; + UnalignedDoubleMember d_; + UnalignedValueMember<uintptr_t> p_; + }; + """) + _, d, p = layouts["Foo"].fields + self.assertEqual(d.storage.arg, named_type("double")) + self.assertEqual(p.storage.arg, named_type("uintptr_t")) + + def test_fixed_width_ints_keep_canonical_mapping(self): + layouts = extract_layouts(""" + using uint64_t = unsigned long long; + class Foo : public HeapObject { + public: + TaggedMember<Smi> slot_; + uint64_t u64_; + }; + """) + _, u64 = layouts["Foo"].fields + self.assertEqual((u64.storage.width, u64.storage.is_signed), (8, False)) + self.assertIsNone(u64.storage.pointer_width_alias) + + def test_chained_alias_resolves_to_the_pointer_width_one(self): + # Word reaches uintptr_t only through the desugaring chain. + layouts = extract_layouts(""" + using uintptr_t = unsigned long long; + using Word = uintptr_t; + class Foo : public HeapObject { + public: + TaggedMember<Smi> slot_; + Word bare_; + }; + """) + _, bare = layouts["Foo"].fields + self.assertEqual(bare.storage.pointer_width_alias, "uintptr_t") + + def test_address_wins_over_the_alias_it_desugars_to(self): + layouts = extract_layouts(""" + using uintptr_t = unsigned long long; + using Address = uintptr_t; + class Foo : public HeapObject { + public: + TaggedMember<Smi> slot_; + Address bare_; + }; + """) + _, bare = layouts["Foo"].fields + self.assertEqual(bare.storage.pointer_width_alias, "Address") + + def test_size_t_is_recorded_by_its_own_name(self): + layouts = extract_layouts(""" + using size_t = unsigned long long; + class Foo : public HeapObject { + public: + TaggedMember<Smi> slot_; + size_t size_; + }; + """) + _, size = layouts["Foo"].fields + self.assertEqual(size.storage.pointer_width_alias, "size_t") + + def test_unrecognized_long_has_no_alias(self): + # No alias in the chain is pointer-width, so the member is + # described by its width alone. + layouts = extract_layouts(""" + class Foo : public HeapObject { + public: + TaggedMember<Smi> slot_; + unsigned long raw_; + }; + """) + _, raw = layouts["Foo"].fields + self.assertIsNone(raw.storage.pointer_width_alias) + + def test_union_weak_and_alias_template_flattening(self): + layouts = extract_layouts(""" + class Bar : public HeapObject { + public: + TaggedMember<UnionOf<String, Undefined>> name_; + TaggedMember<Weak<Map>> weak_map_; + TaggedMember<UnionOf<String, MaybeWeak<Map>>> mixed_; + }; + """) + name, weak_map, mixed = layouts["Bar"].fields + self.assertEqual(name.storage.arg.kind, "union") + self.assertEqual([m.name for m in name.storage.arg.members], + ["String", "Undefined"]) + self.assertEqual(weak_map.storage.arg, named_type("Weak", + named_type("Map"))) + # MaybeWeak<Map> is flattened into the enclosing union. + self.assertEqual(mixed.storage.arg.members, + (named_type("String"), named_type("Map"), + named_type("Weak", named_type("Map")))) + + def test_known_class_template_argument_preserves_payload(self): + layouts = extract_layouts(""" + template <typename T> + class CppGCManaged : public HeapObject {}; + class Holder : public HeapObject { + public: + TaggedMember<CppGCManaged<Map>> wrapped_; + }; + """) + wrapped, = layouts["Holder"].fields + # Consumers map the template and payload to their own types. + self.assertEqual( + wrapped.storage.arg, + named_type("CppGCManaged", + named_type("Map", namespaces=("v8", "internal")))) + self.assertEqual(wrapped.cpp_type, "TaggedMember<CppGCManaged<Map>>") + + def test_wasm_code_pointer_member(self): + layouts = extract_layouts(""" + class WasmCodePointer { + uint32_t value_; + }; + class Holder : public HeapObject { + public: + WasmCodePointer call_target_; + }; + """) + target, = layouts["Holder"].fields + self.assertEqual(target.storage.kind, "struct") + self.assertEqual(target.storage.name, "WasmCodePointer") + self.assertEqual(target.storage.width, 4) + + def test_sandbox_pointer_members(self): + layouts = extract_layouts(""" + class BytecodeArray; + class Code; + using CodePointerMember = TrustedPointerMember<Code, kTestCodeTag>; + class Baz : public HeapObject { + public: + TrustedPointerMember<BytecodeArray, kTestBytecodeTag> bytecode_; + ExternalPointerMember<kTestCallbackTag> callback_; + ProtectedTaggedMember<BytecodeArray> protected_; + CodePointerMember code_; + }; + """) + bytecode, callback, protected, code = layouts["Baz"].fields + self.assertEqual(bytecode.storage.kind, "trusted_pointer") + self.assertEqual(bytecode.storage.tag, "kTestBytecodeTag") + self.assertEqual(bytecode.storage.arg, named_type("BytecodeArray")) + self.assertEqual(callback.storage.kind, "external_pointer") + self.assertEqual(callback.storage.tag, "kTestCallbackTag") + self.assertEqual(protected.storage.kind, "protected_tagged") + self.assertEqual(protected.storage.arg, named_type("BytecodeArray")) + # The tag reference lives on the alias declaration. + self.assertEqual(code.storage.tag, "kTestCodeTag") + + def test_fixed_array_and_struct_members(self): + layouts = extract_layouts(""" + struct CoverageInfoSlot { + int32_t start; + int32_t end; + }; + class Qux : public HeapObject { + public: + uint32_t bitset_[2]; + CoverageInfoSlot slot_; + }; + """) + bitset, slot = layouts["Qux"].fields + self.assertEqual(bitset.array_extent, 2) + self.assertEqual(bitset.size, 8) + self.assertEqual(bitset.storage.kind, "int") + self.assertEqual(slot.storage.kind, "struct") + self.assertEqual(slot.storage.name, "CoverageInfoSlot") + self.assertEqual(slot.storage.width, 8) + + def test_pointer_tag_ranges(self): + layouts = extract_layouts(""" + constexpr ExternalPointerTagRange kCallbackRange(kTestCallbackTag); + constexpr TrustedPointerTagRange kCodeRange(kTestBytecodeTag, + kTestCodeTag); + class Callback : public HeapObject { + public: + ExternalPointerMember<kCallbackRange> callback_; + TrustedPointerMember<HeapObject, kCodeRange> code_; + }; + """) + callback, code = layouts["Callback"].fields + self.assertEqual(callback.storage.kind, "external_pointer") + self.assertEqual(callback.storage.tag, "kCallbackRange") + self.assertEqual(code.storage.kind, "trusted_pointer") + self.assertEqual(code.storage.tag, "kCodeRange") + + def test_pointer_tags_ignore_unrelated_references(self): + h = parse(""" + enum OtherPointerTag { kOtherTag }; + namespace other { + enum ExternalPointerTag { kForeignTag }; + template <typename T> struct TagRange { T value; }; + constexpr TagRange<int> kForeignRange{0}; + } + struct TagRangeLookalike { int value; }; + constexpr TagRangeLookalike kLookalike{0}; + constexpr TagRange<OtherPointerTag> kOtherRange(kOtherTag); + template <auto... values> struct Probe {}; + class References { + public: + Probe<kTestCallbackTag, kOtherTag, other::kForeignTag, + other::kForeignRange, kLookalike, kOtherRange> field; + }; + """) + fields = list(_find_class(h, "References").type.get_fields()) + self.assertEqual( + layout_extract._pointer_tag_names(fields[0]), ["kTestCallbackTag"]) + + def test_zero_size_padding_array_is_void_field(self): + layouts = extract_layouts(""" + class Padded : public HeapObject { + public: + char padding_0_[0]; + uint32_t value_; + }; + """) + padding, value = layouts["Padded"].fields + self.assertEqual(padding.cpp_name, "padding_0_") + self.assertEqual(padding.size, 0) + self.assertEqual(value.cpp_name, "value_") + self.assertEqual(value.offset, 4) + + +class ConfigTest(unittest.TestCase): + """extract_config reads each size from the alias V8 itself takes it + from, so Config tracks the build configuration. Reading a type + that merely resembles one is how trusted_pointer_size went wrong: + TrustedPointerHandle is uint32_t in every configuration, while a + trusted pointer slot is tagged when the sandbox is off.""" + + _ALIASES = """ + using Tagged_t = unsigned int; + using Address = unsigned long long; + using ExternalPointer_t = unsigned long long; + using CppHeapPointer_t = unsigned int; + using TrustedPointer_t = unsigned short; + """ + + def test_reads_every_size_from_its_own_alias(self): + h = parse(self._ALIASES) + config = layout_extract.extract_config(h) + self.assertEqual( + (config.tagged_size, config.pointer_size, config.external_pointer_size, + config.cpp_heap_pointer_size, config.trusted_pointer_size), + (4, 8, 8, 4, 2)) + + def test_a_missing_alias_is_fatal(self): + with self.assertRaises(LayoutError) as ctx: + layout_extract.extract_config( + parse(self._ALIASES.replace("using TrustedPointer_t", "using X"))) + self.assertIn("TrustedPointer_t", str(ctx.exception)) + + def test_a_class_member_does_not_shadow_the_namespace_alias(self): + # v8-internal.h declares Internals::Tagged_t ahead of the namespace + # alias; the alias index holds namespace-scope aliases only, so the + # later one still wins. + h = parse(""" + class Internals { public: using Tagged_t = unsigned long long; }; + """ + self._ALIASES) + self.assertEqual(layout_extract.extract_config(h).tagged_size, 4) + + +class AnnotationTest(unittest.TestCase): + + def test_annotations_pass_through_uninterpreted(self): + layouts = extract_layouts(""" + class Info : public HeapObject { + public: + V8_TQ_CONST V8_TQ_RELAXED TaggedMember<Smi> length_; + V8_TQ_TYPE(SmiTagged<VariableProperties>) TaggedMember<Smi> props_; + V8_TQ_NAME(other) uint32_t renamed_; + }; + """) + length, props, renamed = layouts["Info"].fields + self.assertEqual([(a.name, a.arg) for a in length.annotations], + [("V8_TQ_CONST", None), ("V8_TQ_RELAXED", None)]) + self.assertEqual(props.storage.arg, named_type("Smi")) + self.assertEqual([(a.name, a.arg) for a in props.annotations], + [("V8_TQ_TYPE", "SmiTagged<VariableProperties>")]) + self.assertEqual(renamed.cpp_name, "renamed_") + self.assertEqual([(a.name, a.arg) for a in renamed.annotations], + [("V8_TQ_NAME", "other")]) + + def test_annotation_argument_is_not_parsed(self): + layouts = extract_layouts(""" + class Info : public HeapObject { + public: + V8_TQ_TYPE(iterator::IteratorRecord) TaggedMember<Smi> value_; + }; + """) + (value,) = layouts["Info"].fields + self.assertEqual(value.storage.arg, named_type("Smi")) + self.assertEqual([(a.name, a.arg) for a in value.annotations], + [("V8_TQ_TYPE", "iterator::IteratorRecord")]) + + +class BaseChainTest(unittest.TestCase): + + _ARRAY_BASE = """ + class FakeArrayBase : public HeapObject { + public: + V8_TQ_CONST uint32_t length_; + }; + template <typename Derived, typename ElementT, typename Super> + class TaggedArrayBase : public Super { + public: + using ElementMemberT = TaggedMember<ElementT>; + }; + """ + + def test_flatten_through_template_base(self): + layouts = extract_layouts(self._ARRAY_BASE + """ + class FakeArray + : public TaggedArrayBase<FakeArray, Map, FakeArrayBase> { + public: + V8_TQ_TAIL_LENGTH(length); + V8_TQ_NAME(objects) + TaggedMember<Map> objects_[0]; + }; + """) + arr = layouts["FakeArray"] + self.assertEqual(arr.base_cpp_name, "v8::internal::FakeArrayBase") + self.assertEqual(arr.base_size, 8) + self.assertEqual(arr.fields, ()) + self.assertIsNotNone(arr.tail) + + def test_member_in_template_base(self): + layouts = extract_layouts(self._ARRAY_BASE + """ + template <typename Derived, typename Super> + class CapacityBase : public Super { + public: + uint32_t capacity_; + }; + class FakeTable : public CapacityBase<FakeTable, FakeArrayBase> { + public: + uint32_t elements_; + }; + """) + table = layouts["FakeTable"] + self.assertEqual(table.base_cpp_name, "v8::internal::FakeArrayBase") + self.assertEqual([(f.cpp_name, f.offset) for f in table.fields], + [("capacity_", 8), ("elements_", 12)]) + + +class TailTest(unittest.TestCase): + + def test_tail(self): + layouts = extract_layouts(""" + class Blob : public HeapObject { + public: + V8_TQ_CONST TaggedMember<Smi> length_; + V8_TQ_TAIL_LENGTH(length); + V8_TQ_NAME(bytes) + uint8_t flexible_array_member_data_[0]; + }; + """) + blob = layouts["Blob"] + self.assertEqual(blob.size, 8) + self.assertEqual([(a.name, a.arg) for a in blob.annotations], + [("V8_TQ_TAIL_LENGTH", "length")]) + self.assertEqual([(a.name, a.arg) for a in blob.tail.annotations], + [("V8_TQ_NAME", "bytes")]) + tail = blob.tail + self.assertEqual(tail.element_size, 1) + self.assertEqual(tail.element_storage.kind, "int") + self.assertEqual(tail.element_storage.width, 1) + + def test_tail_without_annotations_is_still_recorded(self): + layouts = extract_layouts(""" + class Blob : public HeapObject { + public: + V8_TQ_CONST TaggedMember<Smi> length_; + uint8_t flexible_array_member_data_[0]; + }; + """) + blob = layouts["Blob"] + self.assertIsNotNone(blob.tail) + self.assertEqual(blob.annotations, ()) + self.assertEqual(blob.tail.element_size, 1) + + +class BitFieldGroupTest(unittest.TestCase): + # Test templates with the names and arguments recognized by the extractor: + # "BitField" with (type, shift, size) arguments, and a base + # "BitFieldGroup" whose second argument is the storage type. + _PRELUDE = """ + namespace base { + template <typename T, int shift, int size, typename U = uint32_t> + class BitField { + public: + template <typename T2, int size2> + using Next = BitField<T2, shift + size, size2, U>; + }; + } // namespace base + template <typename Derived, typename U> + class BitFieldGroup { + public: + template <typename T, int size> + using First = base::BitField<T, 0, size, U>; + private: + U value_; + }; + template <typename Group> + class SmiBitFieldMember : TaggedMember<Smi> {}; + enum class Kind : uint8_t { kA, kB, kC }; + """ + + def _layouts(self, body): + return extract_layouts(self._PRELUDE + body) + + def test_bit_fields_are_extracted_in_declaration_order(self): + (field,) = self._layouts(""" + class Foo : public HeapObject { + public: + struct Bits : BitFieldGroup<Bits, uint32_t> { + using IsFooBit = First<bool, 1>; + using KindBits = IsFooBit::Next<Kind, 2>; + using CountBits = KindBits::Next<int32_t, 5>; + using AlternativeBits = IsFooBit::Next<uint32_t, 31>; + }; + Bits bits_; + }; + """)["Foo"].fields + self.assertEqual(field.storage.kind, "bitfield") + self.assertEqual(field.storage.name, "Foo::Bits") + self.assertEqual(field.storage.width, 4) + self.assertEqual([ + (b.cpp_name, b.type, b.offset, b.num_bits) for b in field.storage.bits + ], [ + ("IsFooBit", "bool", 0, 1), + ("KindBits", "Kind", 1, 2), + ("CountBits", "int32_t", 3, 5), + ("AlternativeBits", "uint32_t", 1, 31), + ]) + + def test_enclosing_classes_name_the_group(self): + # Aliases and std::atomic do not affect the declaring C++ type name. + aliased, direct, _ = self._layouts(""" + class Foo : public HeapObject { + public: + struct Bits : BitFieldGroup<Bits, uint8_t> { + using IsFooBit = First<bool, 1>; + }; + using FooBitFields = Bits; + std::atomic<FooBitFields> aliased_; + Bits direct_; + uint16_t padding_; + }; + """)["Foo"].fields + self.assertEqual(aliased.storage.name, "Foo::Bits") + self.assertEqual(aliased.storage.width, 1) + self.assertEqual(direct.storage.name, "Foo::Bits") + + def test_nested_classes_are_preserved_without_namespaces(self): + field, _ = self._layouts(""" + namespace v8::internal { + class Foo : public HeapObject { + public: + struct Holder { + struct Bits : BitFieldGroup<Bits, uint8_t> { + using IsFooBit = base::BitField<bool, 0, 1, uint8_t>; + }; + }; + Holder::Bits bits_; + uint8_t padding_[3]; + }; + } + """)["Foo"].fields + self.assertEqual(field.storage.name, "Foo::Holder::Bits") + + def test_class_scoped_enum_bit_field_type_is_qualified(self): + (field,) = self._layouts(""" + namespace v8::internal { + class Foo : public HeapObject { + public: + enum class Mode : uint8_t { kA, kB }; + struct Bits : BitFieldGroup<Bits, uint32_t> { + using ModeBits = First<Mode, 1>; + using KindBits = ModeBits::Next<Kind, 2>; + }; + Bits bits_; + }; + } + """)["Foo"].fields + self.assertEqual([(b.cpp_name, b.type) for b in field.storage.bits], + [("ModeBits", "Foo::Mode"), ("KindBits", "Kind")]) + + def test_smi_member_records_the_group_as_a_tagged_slot(self): + (field,) = self._layouts(""" + class Foo : public HeapObject { + public: + struct Flags : BitFieldGroup<Flags, uint32_t> { + using IsFooBit = base::BitField<bool, 0, 1, uint32_t>; + using CountBits = IsFooBit::Next<uint32_t, 30>; + }; + SmiBitFieldMember<Flags> flags_; + }; + """)["Foo"].fields + self.assertEqual(field.storage.kind, "smi_bitfield") + self.assertEqual(field.storage.name, "Foo::Flags") + self.assertIsNone(field.storage.width) + self.assertEqual( + [(b.cpp_name, b.offset, b.num_bits) for b in field.storage.bits], + [("IsFooBit", 0, 1), ("CountBits", 1, 30)]) + + def test_smi_member_bits_must_fit_31(self): + with self.assertRaisesRegex(LayoutError, "32 bits exceed the storage"): + self._layouts(""" + class Foo : public HeapObject { + public: + struct Flags : BitFieldGroup<Flags, uint32_t> { + using IsFooBit = base::BitField<bool, 0, 1, uint32_t>; + using CountBits = IsFooBit::Next<uint32_t, 31>; + }; + SmiBitFieldMember<Flags> flags_; + }; + """) + + def test_smi_member_argument_must_be_a_group(self): + with self.assertRaisesRegex(LayoutError, "is not a BitFieldGroup"): + self._layouts(""" + class Foo : public HeapObject { + public: + struct Flags { + using IsFooBit = base::BitField<bool, 0, 1, uint32_t>; + }; + SmiBitFieldMember<Flags> flags_; + }; + """) + + def test_non_bit_field_alias_is_fatal(self): + with self.assertRaisesRegex(LayoutError, "is not a base::BitField"): + self._layouts(""" + class Foo : public HeapObject { + public: + struct Bits : BitFieldGroup<Bits, uint8_t> { + using IsFooBit = base::BitField<bool, 0, 1, uint8_t>; + using Underlying = uint8_t; + }; + Bits bits_; + }; + """) + + _STRONG_ALIAS = """ + namespace base { + template <typename Tag, typename T> + class StrongAlias { T value_; }; + } // namespace base + using SharedFlag = base::StrongAlias<struct SharedFlagTag, bool>; + using Count = base::StrongAlias<struct CountTag, uint16_t>; + """ + + def test_strong_alias_bit_field_has_its_underlying_type(self): + (field,) = self._layouts(self._STRONG_ALIAS + """ + class Foo : public HeapObject { + public: + struct Bits : BitFieldGroup<Bits, uint32_t> { + using IsSharedBit = base::BitField<SharedFlag, 0, 1, uint32_t>; + using CountBits = IsSharedBit::Next<Count, 4>; + }; + Bits bits_; + }; + """)["Foo"].fields + self.assertEqual([(b.cpp_name, b.type) for b in field.storage.bits], + [("IsSharedBit", "bool"), ("CountBits", "uint16_t")]) + + def test_other_class_bit_field_type_is_fatal(self): + with self.assertRaisesRegex(LayoutError, "unsupported bit field type"): + self._layouts(""" + struct Opaque { uint8_t v; }; + class Foo : public HeapObject { + public: + struct Bits : BitFieldGroup<Bits, uint32_t> { + using OpaqueBits = base::BitField<Opaque, 0, 8, uint32_t>; + }; + Bits bits_; + }; + """) + + def test_empty_group_is_fatal(self): + with self.assertRaisesRegex(LayoutError, "declares no bit fields"): + self._layouts(""" + class Foo : public HeapObject { + public: + struct Bits : BitFieldGroup<Bits, uint8_t> {}; + Bits bits_; + }; + """) + + +class ParseDiagnosticsTest(unittest.TestCase): + + def test_error_and_note(self): + tu = _INDEX.parse( + "diagnostics.cc", + args=["-std=c++20"], + unsaved_files=[("diagnostics.cc", "void f(int);\nvoid g() { f(); }\n")]) + stderr = io.StringIO() + with contextlib.redirect_stderr(stderr), self.assertRaises( + SystemExit) as ctx: + cpp_hier._reject_recovery_ast(tu) + self.assertEqual(ctx.exception.code, 1) + output = stderr.getvalue() + self.assertIn("diagnostics.cc:2:12: error:", output) + self.assertIn("diagnostics.cc:1:6: note:", output) + self.assertNotIn("[metagen]", output) + self.assertNotIn("SourceLocation", output) + + def test_valid_translation_unit(self): + tu = _INDEX.parse( + "diagnostics.cc", unsaved_files=[("diagnostics.cc", "int field;\n")]) + stderr = io.StringIO() + with contextlib.redirect_stderr(stderr): + cpp_hier._reject_recovery_ast(tu) + self.assertEqual(stderr.getvalue(), "") + + +class FailureModeTest(unittest.TestCase): + + def test_missing_trusted_pointer_handle_alias_is_fatal(self): + h = parse( + """ + class Holder : public HeapObject { + public: + std::atomic<RenamedTrustedPointerHandle> handle_; + }; + """, + prelude=_PRELUDE.replace("TrustedPointerHandle", + "RenamedTrustedPointerHandle")) + field = next(_find_class(h, "Holder").type.get_fields()) + with self.assertRaisesRegex(LayoutError, + "missing TrustedPointerHandle declaration"): + layout_extract._Extractor(h, _V8_ROOT)._storage_type_of(field, field.type) + + def test_torque_generated_base_is_fatal(self): + for base in ("TorqueGeneratedFoo<Foo, HeapObject>", "Intermediate<Foo>"): + with self.subTest(base=base): + with self.assertRaisesRegex(LayoutError, + "unexpected Torque-generated base"): + extract_layouts(f""" + template <typename D, typename P> + class TorqueGeneratedFoo : public P {{}}; + template <typename D> + class Intermediate : public TorqueGeneratedFoo<D, HeapObject> {{}}; + class Foo : public {base} {{}}; + """) + + def test_unknown_class_template_argument_is_fatal(self): + with self.assertRaisesRegex(LayoutError, "unsupported class template"): + extract_layouts(""" + template <typename T> + class Wrapper : public HeapObject {}; + class Holder : public HeapObject { + public: + TaggedMember<Wrapper<Map>> wrapped_; + }; + """) + + def test_unknown_member_type_is_fatal(self): + with self.assertRaises(LayoutError) as ctx: + extract_layouts(""" + class Bad : public HeapObject { + public: + void* raw_pointer_; + }; + """) + self.assertIn("unsupported member type", str(ctx.exception)) + + def test_unknown_member_wrapper_is_fatal(self): + for header in ("src/objects/tagged-field.h", "src/objects/new-wrapper.h"): + with self.subTest(header=header): + with self.assertRaisesRegex(LayoutError, "unsupported member class"): + extract_layouts( + """ + class Bad : public HeapObject { + public: + MysteryMember mystery_; + }; + """, {header: "class MysteryMember { unsigned int handle_; };"}) + + def test_unknown_struct_is_fatal(self): + for name in ("ScoreMember", "CoverageInfoSlot"): + with self.subTest(name=name): + with self.assertRaisesRegex(LayoutError, "unsupported member class"): + extract_layouts(f""" + namespace other {{ struct {name} {{ int value; }}; }} + class Foo : public HeapObject {{ + public: + other::{name} value_; + }}; + """) + + def test_unknown_compression_scheme_is_fatal(self): + # Falling through to a plain tagged slot would record the wrong + # representation. + with self.assertRaises(LayoutError) as ctx: + extract_layouts(""" + class MysteryScheme; + class Bad : public HeapObject { + public: + TaggedMember<Smi, MysteryScheme> slot_; + }; + """) + self.assertIn("unsupported compression scheme", str(ctx.exception)) + + def test_unknown_compression_cage_is_fatal(self): + with self.assertRaises(LayoutError) as ctx: + extract_layouts(""" + class MysteryCage; + class Bad : public HeapObject { + public: + TaggedMember<Smi, V8HeapCompressionSchemeImpl<MysteryCage>> slot_; + }; + """) + self.assertIn("unsupported compression cage", str(ctx.exception)) + + def test_class_outside_hierarchy_is_fatal(self): + with self.assertRaises(LayoutError) as ctx: + h = parse(""" + class Orphan { + public: + uint32_t x_; + }; + """) + # Orphan does not inherit HeapObject and has no layout to export. + layout_extract._Extractor(h, "/nonexistent-v8-root").extract_class_layout( + "Orphan", _find_class(h, "Orphan"), {}) + self.assertIn("no ancestor with an exported layout", str(ctx.exception)) + + def test_unknown_annotation_passes_through(self): + # Export unknown annotations because Torque defines their meaning. + layouts = extract_layouts(""" + class Bad : public HeapObject { + public: + [[clang::annotate("V8_TQ_BOGUS")]] uint32_t x_; + }; + """) + (x,) = layouts["Bad"].fields + self.assertEqual([(a.name, a.arg) for a in x.annotations], + [("V8_TQ_BOGUS", None)]) + + def test_malformed_annotation_payload_is_fatal(self): + with self.assertRaises(LayoutError): + extract_layouts(""" + class Bad : public HeapObject { + public: + [[clang::annotate("V8_TQ_TYPE(unclosed")]] uint32_t x_; + }; + """) + + def test_repeated_annotation_is_fatal(self): + with self.assertRaises(LayoutError): + extract_layouts(""" + class Bad : public HeapObject { + public: + V8_TQ_NAME(a) V8_TQ_NAME(b) uint32_t x_; + }; + """) + + +def _find_class(h, name): + for cur in h.tu.cursor.walk_preorder(): + if cur.kind == cindex.CursorKind.CLASS_DECL and cur.spelling == name \ + and cur.is_definition(): + return cur + raise AssertionError(f"class {name} not found") + + +if __name__ == "__main__": + unittest.main() diff --git a/deps/v8/tools/metagen/tests/layout_ir_test.py b/deps/v8/tools/metagen/tests/layout_ir_test.py new file mode 100644 index 000000000000..28cb8f99ef0e --- /dev/null +++ b/deps/v8/tools/metagen/tests/layout_ir_test.py @@ -0,0 +1,535 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Schema tests for the layout IR: validation, determinism, round-trip.""" + +import json +import os +import sys +import unittest + +sys.path.insert( + 0, + os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) + +from metagen.layout_ir import (Annotation, BitFieldEntry, ClassLayout, Config, + Field, LayoutError, CppType, StorageType, Tail, + named_type, parse_document, serialize_document, + serialize_positions, union_type) + +# The configuration the fixtures describe: compressed tagged values on a +# 64-bit target with the sandbox on. +CONFIG = Config( + tagged_size=4, + pointer_size=8, + external_pointer_size=4, + cpp_heap_pointer_size=4, + trusted_pointer_size=4) + + +def document(classes): + return serialize_document(CONFIG, classes) + + +def tagged(name, *args): + return StorageType(kind="tagged", arg=named_type(name, *args)) + + +def int_storage(width, signed=True): + return StorageType(kind="int", width=width, is_signed=signed) + + +def bitfield(*bits, width=1): + return StorageType(kind="bitfield", name="Foo::Bits", width=width, bits=bits) + + +def smi_bitfield(*bits, **kwargs): + return StorageType(kind="smi_bitfield", name="FooFlags", bits=bits, **kwargs) + + +def field(cpp_name, offset, size, storage=None, cpp_type=None, **kwargs): + return Field( + cpp_name=cpp_name, + cpp_type=cpp_type or "TaggedMember<Object>", + position="src/objects/test.h:1:1", + offset=offset, + size=size, + storage=storage or tagged("Object"), + **kwargs) + + +def cell_layout(**overrides): + kwargs = dict( + cpp_name="v8::internal::Cell", + position="src/objects/cell.h:16:18", + base_cpp_name="v8::internal::HeapObject", + base_size=4, + size=8, + alignment=4, + fields=(field("maybe_value_", 4, 4, tagged("MaybeObject")),)) + kwargs.update(overrides) + return ClassLayout(**kwargs) + + +class CppTypeTest(unittest.TestCase): + + def test_name_with_args(self): + t = named_type("TrustedPointer", named_type("BytecodeArray")) + self.assertEqual( + t.to_json(), { + "kind": "name", + "name": "TrustedPointer", + "args": [{ + "kind": "name", + "name": "BytecodeArray" + }], + }) + + def test_union_roundtrip(self): + t = union_type(named_type("String"), named_type("Undefined")) + self.assertEqual(CppType.from_json(t.to_json()), t) + + def test_union_needs_two_members(self): + with self.assertRaises(LayoutError): + union_type(named_type("String")) + + def test_rejects_non_identifier_name(self): + with self.assertRaises(LayoutError): + named_type("Foo Bar") + + def test_rejects_unknown_kind(self): + with self.assertRaises(LayoutError): + CppType.from_json({"kind": "tuple", "members": []}) + + def test_rejects_unknown_key(self): + with self.assertRaises(LayoutError): + CppType.from_json({"kind": "name", "name": "A", "extra": 1}) + + +class StorageTypeTest(unittest.TestCase): + + def test_unknown_kind_fatal(self): + with self.assertRaises(LayoutError): + StorageType(kind="mystery") + + def test_tagged_needs_arg(self): + with self.assertRaises(LayoutError): + StorageType(kind="tagged") + + def test_trusted_pointer_needs_tag(self): + with self.assertRaises(LayoutError): + StorageType(kind="trusted_pointer", arg=named_type("BytecodeArray")) + + def test_int_width_validated(self): + with self.assertRaises(LayoutError): + StorageType(kind="int", width=3, is_signed=True) + + def test_enum_roundtrip(self): + s = StorageType(kind="enum", name="InstanceType", width=2, is_signed=False) + self.assertEqual(StorageType.from_json(s.to_json()), s) + + def test_bitfield_roundtrip(self): + s = bitfield( + BitFieldEntry("IsFooBit", "bool", 0, 1), + BitFieldEntry("KindBits", "Kind", 1, 3)) + self.assertEqual(StorageType.from_json(s.to_json()), s) + self.assertEqual(s.to_json()["bits"][1], { + "cpp_name": "KindBits", + "type": "Kind", + "offset": 1, + "num_bits": 3 + }) + + def test_bitfield_rejects_invalid_qualified_names(self): + for name in (None, 42, "::Bits", "Foo::", "Foo::::Bits", "Foo:Bits"): + with self.subTest(name=name), self.assertRaises(LayoutError): + StorageType( + kind="bitfield", + name=name, + width=1, + bits=(BitFieldEntry("IsFooBit", "bool", 0, 1),)) + + def test_bitfield_type_may_be_class_scoped(self): + s = bitfield(BitFieldEntry("ModeBits", "Foo::Mode", 0, 2)) + self.assertEqual(StorageType.from_json(s.to_json()), s) + + def test_bitfield_rejects_invalid_qualified_types(self): + for type_name in (None, 42, "::Mode", "Foo::", "Foo::::Mode", "Foo:Mode"): + with self.subTest(type_name=type_name), self.assertRaises(LayoutError): + BitFieldEntry("ModeBits", type_name, 0, 2) + + def test_bitfield_needs_fields(self): + with self.assertRaisesRegex(LayoutError, "without fields"): + bitfield() + + def test_bitfield_gaps_and_overlaps_roundtrip(self): + s = bitfield( + BitFieldEntry("KindBits", "Kind", 2, 3), + BitFieldEntry("PayloadBits", "uint8_t", 1, 7), + BitFieldEntry("IsFooBit", "bool", 0, 1)) + self.assertEqual(StorageType.from_json(s.to_json()), s) + + def test_bitfield_chain_must_fit_the_storage(self): + with self.assertRaisesRegex(LayoutError, "exceed the storage"): + bitfield( + BitFieldEntry("LowBits", "uint8_t", 0, 5), + BitFieldEntry("HighBits", "uint8_t", 5, 4), + BitFieldEntry("AlternativeBits", "uint8_t", 0, 8)) + + def test_smi_bitfield_roundtrip(self): + s = smi_bitfield( + BitFieldEntry("IsFooBit", "bool", 0, 1), + BitFieldEntry("CountBits", "uint32_t", 1, 30)) + self.assertEqual(StorageType.from_json(s.to_json()), s) + self.assertNotIn("width", s.to_json()) + + def test_smi_bitfield_chain_must_fit_31_bits(self): + with self.assertRaisesRegex(LayoutError, "32 bits exceed the storage"): + smi_bitfield( + BitFieldEntry("IsFooBit", "bool", 0, 1), + BitFieldEntry("CountBits", "uint32_t", 1, 31), + BitFieldEntry("AlternativeBits", "uint32_t", 0, 31)) + + def test_smi_bitfield_has_no_width(self): + with self.assertRaisesRegex(LayoutError, "with a width"): + smi_bitfield(BitFieldEntry("IsFooBit", "bool", 0, 1), width=4) + + def test_bits_only_on_bitfield_storage(self): + with self.assertRaisesRegex(LayoutError, "int storage with bit fields"): + StorageType( + kind="int", + width=1, + is_signed=False, + bits=(BitFieldEntry("IsFooBit", "bool", 0, 1),)) + + def test_bit_field_entry_rejects_unknown_key(self): + with self.assertRaises(LayoutError): + BitFieldEntry.from_json({ + "cpp_name": "IsFooBit", + "type": "bool", + "offset": 0, + "num_bits": 1, + "extra": 1 + }) + + +class FieldTest(unittest.TestCase): + + def test_array_size_must_be_multiple_of_extent(self): + with self.assertRaises(LayoutError): + field("bits_", 4, 10, int_storage(4, signed=False), array_extent=3) + + def test_optional_keys_omitted_from_json(self): + f = field("maybe_value_", 4, 4) + self.assertNotIn("annotations", f.to_json()) + self.assertNotIn("array_extent", f.to_json()) + + def test_annotations_roundtrip(self): + f = field( + "flags_", + 4, + 4, + int_storage(4, signed=False), + annotations=(Annotation("V8_TQ_CONST"), Annotation("V8_TQ_RELAXED"))) + self.assertEqual(Field.from_json(f.to_json()), f) + + def test_annotations_sort_and_reject_repeats(self): + f = field( + "flags_", + 4, + 4, + annotations=(Annotation("V8_TQ_RELAXED"), Annotation("V8_TQ_CONST"))) + self.assertEqual([a["name"] for a in f.to_json()["annotations"]], + ["V8_TQ_CONST", "V8_TQ_RELAXED"]) + with self.assertRaises(LayoutError): + Field.from_json({ + "cpp_name": "f_", + "offset": 4, + "size": 4, + "storage": tagged("Object").to_json(), + "annotations": [{ + "name": "V8_TQ_CONST" + }, { + "name": "V8_TQ_CONST" + }], + }) + + def test_annotation_name_must_be_prefixed(self): + with self.assertRaises(LayoutError): + Annotation("CONST") + + def test_unparsed_annotation_arguments_roundtrip(self): + # Metagen never parses these; a comma inside the argument must + # survive untouched. + f = field( + "values_", + 4, + 8, + int_storage(4, signed=False), + array_extent=2, + annotations=(Annotation("V8_TQ_NAME", "otherValues"), + Annotation("V8_TQ_TYPE", "foo::Bar<Baz, Qux>"), + Annotation("V8_TQ_EXTENT_NAME", "kNamedExtent"))) + self.assertEqual(Field.from_json(f.to_json()), f) + + def test_empty_annotation_argument_is_fatal(self): + with self.assertRaises(LayoutError): + Annotation("V8_TQ_TYPE", "") + + +class ClassLayoutTest(unittest.TestCase): + + def test_valid_layout(self): + c = cell_layout() + self.assertEqual(c.size, 8) + + def test_gap_is_fatal(self): + with self.assertRaises(LayoutError) as ctx: + cell_layout(size=12) + self.assertIn("fields end at 8", str(ctx.exception)) + + def test_overlap_is_fatal(self): + with self.assertRaises(LayoutError): + cell_layout( + size=8, fields=(field("a_", 4, 4), field("b_", 6, 2, int_storage(2)))) + + def test_field_before_base_is_fatal(self): + with self.assertRaises(LayoutError): + cell_layout(fields=(field("early_", 0, 8),)) + + def test_unqualified_cpp_name_fatal(self): + with self.assertRaises(LayoutError): + cell_layout(cpp_name="Cell") + + def test_duplicate_field_names_fatal(self): + with self.assertRaises(LayoutError): + cell_layout( + size=12, fields=(field("value_", 4, 4), field("value_", 8, 4))) + + def test_root_class_has_no_base(self): + c = ClassLayout( + cpp_name="v8::internal::HeapObject", + position="src/objects/heap-object.h:100:1", + base_cpp_name=None, + base_size=0, + size=4, + alignment=4, + fields=(field( + "map_", + 0, + 4, + tagged("Map"), + annotations=(Annotation("V8_TQ_CONST"),)),)) + self.assertIsNone(ClassLayout.from_json(c.to_json()).base_cpp_name) + + def test_non_power_of_two_alignment_fatal(self): + with self.assertRaises(LayoutError): + cell_layout(alignment=6) + + def test_tail_offset_must_match_header(self): + tail = Tail( + cpp_name="flexible_array_member_data_", + cpp_element_type="uint8_t", + position="src/objects/test.h:9:1", + offset=12, + element_size=1, + element_storage=int_storage(1, signed=False)) + with self.assertRaises(LayoutError): + cell_layout( + size=8, fields=(field("length_", 4, 4, tagged("Smi")),), tail=tail) + + def test_tail_roundtrip(self): + tail = Tail( + cpp_name="flexible_array_member_data_", + cpp_element_type="uint8_t", + position="src/objects/test.h:9:1", + offset=8, + element_size=1, + element_storage=int_storage(1, signed=False)) + c = cell_layout(fields=(field("length_", 4, 4, tagged("Smi")),), tail=tail) + self.assertEqual(ClassLayout.from_json(c.to_json()), c) + + +class ConfigTest(unittest.TestCase): + + def test_config_is_part_of_the_document(self): + text = document([cell_layout()]) + self.assertIn('"config"', text) + self.assertIn('"tagged_size": 4', text) + + def test_rejects_an_implausible_size(self): + with self.assertRaises(LayoutError): + Config( + tagged_size=3, + pointer_size=8, + external_pointer_size=4, + cpp_heap_pointer_size=4, + trusted_pointer_size=4) + + def test_rejects_tagged_wider_than_pointer(self): + with self.assertRaises(LayoutError): + Config( + tagged_size=8, + pointer_size=4, + external_pointer_size=4, + cpp_heap_pointer_size=4, + trusted_pointer_size=4) + + def test_missing_config_is_fatal(self): + doc = json.loads(document([cell_layout()])) + del doc["config"] + with self.assertRaises(LayoutError): + parse_document(json.dumps(doc, indent=1) + "\n") + + def test_unknown_config_key_is_fatal(self): + doc = json.loads(document([cell_layout()])) + doc["config"]["smi_shift_size"] = 1 + with self.assertRaises(LayoutError): + parse_document(json.dumps(doc, indent=1) + "\n") + + +class CppTypeSpellingTest(unittest.TestCase): + + def test_cpp_type_is_recorded_verbatim(self): + spelling = "TaggedMember<UnionOf<Smi, JSObject>>" + text = document( + [cell_layout(fields=(field("a_", 4, 4, cpp_type=spelling),))]) + self.assertIn(spelling, text) + _, classes = parse_document(text) + self.assertEqual(classes[0].fields[0].cpp_type, spelling) + + def test_empty_cpp_type_is_fatal(self): + # Constructed directly: the `field` helper defaults cpp_type to empty. + with self.assertRaises(LayoutError): + Field( + cpp_name="a_", + cpp_type="", + offset=4, + size=4, + storage=tagged("Object")) + + def test_cpp_type_is_required(self): + doc = json.loads(document([cell_layout()])) + del doc["classes"][0]["fields"][0]["cpp_type"] + with self.assertRaises(LayoutError): + parse_document(json.dumps(doc, indent=1) + "\n") + + +class DocumentTest(unittest.TestCase): + + def test_serialization_is_input_order_independent(self): + a = cell_layout() + b = cell_layout(cpp_name="v8::internal::AccessorPair") + self.assertEqual(document([a, b]), document([b, a])) + text = document([a, b]) + self.assertLess(text.index("AccessorPair"), text.index("Cell")) + + def test_classes_emit_in_inheritance_preorder(self): + root = cell_layout( + cpp_name="v8::internal::HeapObject", + base_cpp_name=None, + base_size=0, + size=4, + fields=(field("map_", 0, 4),)) + zebra = cell_layout(cpp_name="v8::internal::Zebra") + aardvark = cell_layout(cpp_name="v8::internal::Aardvark") + # Derived off Zebra, so it precedes the alphabetically earlier Aardvark. + stripe = cell_layout( + cpp_name="v8::internal::Stripe", + base_cpp_name="v8::internal::Zebra", + base_size=8, + size=12, + fields=(field("extra_", 8, 4),)) + text = document([aardvark, stripe, root, zebra]) + self.assertEqual([c["cpp_name"] for c in json.loads(text)["classes"]], [ + "v8::internal::HeapObject", "v8::internal::Aardvark", + "v8::internal::Zebra", "v8::internal::Stripe" + ]) + + def test_classes_with_an_absent_base_root_their_own_tree(self): + # No HeapObject layout: both classes name a base outside the set. + text = document( + [cell_layout(cpp_name="v8::internal::Zebra"), + cell_layout()]) + self.assertLess(text.index("Cell"), text.index("Zebra")) + + def test_base_chain_cycle_fatal(self): + a = cell_layout(cpp_name="v8::internal::A", base_cpp_name="v8::internal::B") + b = cell_layout(cpp_name="v8::internal::B", base_cpp_name="v8::internal::A") + with self.assertRaises(LayoutError): + document([a, b]) + + def test_duplicate_class_fatal(self): + with self.assertRaises(LayoutError): + document([cell_layout(), cell_layout()]) + + def test_roundtrip(self): + text = document([cell_layout()]) + config, classes = parse_document(text) + self.assertEqual(config, CONFIG) + self.assertEqual(serialize_document(config, classes), text) + + def test_torque_names_are_not_serialized(self): + text = document([cell_layout()]) + doc = json.loads(text) + self.assertNotIn("torque_name", text) + self.assertEqual(doc["classes"][0]["base"], "v8::internal::HeapObject") + self.assertEqual(doc["classes"][0]["fields"][0]["cpp_name"], "maybe_value_") + + def test_positions_split_from_layouts(self): + self.assertNotIn("position", document([cell_layout()])) + positions = json.loads(serialize_positions([cell_layout()])) + (c,) = positions["classes"] + self.assertEqual(c["cpp_name"], "v8::internal::Cell") + self.assertEqual(c["position"], "src/objects/cell.h:16:18") + self.assertEqual(c["members"], {"maybe_value_": "src/objects/test.h:1:1"}) + + def test_positions_include_the_tail(self): + import json + tail = Tail( + cpp_name="flexible_array_member_data_", + cpp_element_type="uint8_t", + position="src/objects/test.h:9:1", + offset=8, + element_size=1, + element_storage=int_storage(1, signed=False)) + c = cell_layout(fields=(field("length_", 4, 4, tagged("Smi")),), tail=tail) + positions = json.loads(serialize_positions([c])) + self.assertEqual( + positions["classes"][0]["members"], { + "length_": "src/objects/test.h:1:1", + "flexible_array_member_data_": "src/objects/test.h:9:1", + }) + + def test_positions_require_a_position(self): + with self.assertRaises(LayoutError): + serialize_positions([cell_layout(position=None)]) + + def test_trailing_newline(self): + self.assertTrue(document([]).endswith("}\n")) + + def test_version_mismatch_fatal(self): + text = document([]).replace('"schema_version": 1', '"schema_version": 99') + with self.assertRaises(LayoutError) as ctx: + parse_document(text) + self.assertIn("schema version", str(ctx.exception)) + + def test_non_canonical_input_fatal(self): + # Same JSON value, different formatting: not canonical. + import json + text = document([cell_layout()]) + reformatted = json.dumps(json.loads(text), indent=4) + "\n" + with self.assertRaises(LayoutError): + parse_document(reformatted) + + def test_unknown_document_key_fatal(self): + import json + doc = json.loads(document([])) + doc["extras"] = [] + with self.assertRaises(LayoutError): + parse_document(json.dumps(doc, indent=1) + "\n") + + +if __name__ == "__main__": + unittest.main() diff --git a/deps/v8/tools/regexp/correctness_fuzzer/README.md b/deps/v8/tools/regexp/correctness_fuzzer/README.md index 8a00141d6ac0..f2d679939c2e 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/README.md +++ b/deps/v8/tools/regexp/correctness_fuzzer/README.md @@ -20,7 +20,16 @@ emitted in a mode that accepts it and generated patterns are essentially always syntactically valid. Cases span the interesting character-width axes -- ASCII, Latin-1, BMP two-byte, supplementary -- and subjects are drawn from the characters the pattern itself mentions, so roughly half of all cases match -rather than failing at the first character. +rather than failing at the first character. Patterns containing `\Z` or `\z` +request subjects with trailing line terminators to exercise the difference +between these assertions. + +The grammar includes the staged `\A`, `\z`, and `\Z` assertions +([proposal](https://github.com/tc39/proposal-regexp-buffer-boundaries), +`--js-regexp-buffer-boundaries`). Like foozzie, this tool enables +`--js-staging` through `grammar.D8_FLAGS`. These flags precede the `--ref` and +`--test` configuration flags, which can override them. Disabling a staged +feature in the reference causes cases using it to be skipped as syntax errors. Each case runs on two separately constructed `RegExp` objects, and both results are reported. The two differ in what the engine has cached by the time they @@ -92,6 +101,15 @@ tools/regexp/correctness_fuzzer/correctness_fuzzer.py --ref A --test B \ --pattern '(?=|)()x|' --flags '' --subject z ``` +Or replay a whole generated testcase file -- typically one ClusterFuzz attached +to a bug (see below) -- classifying every case in it and minimizing each +finding: + +```sh +tools/regexp/correctness_fuzzer/correctness_fuzzer.py --ref A --test B \ + --testcase fuzz-3.js +``` + ## Options | Flag | Default | Meaning | @@ -103,11 +121,12 @@ tools/regexp/correctness_fuzzer/correctness_fuzzer.py --ref A --test B \ | `--batch-size` | `500` | Cases per batch. | | `--max-findings` | `20` | Stop after this many divergences. | | `--progress-every` | `25` | Print a flushed progress line every N clean batches (`0` disables). | -| `--profile` | `default` | Weight overlay: `anchored`, `classes`, `backtracking`, `loops`, `lookaround`. | +| `--profile` | `default` | Weight overlay: `anchored`, `buffer_boundaries`, `classes`, `backtracking`, `loops`, `lookaround`. | | `--weight` | | Multiply one rule's weight, `Production.rule=N`; repeatable. | | `--max-depth` | `5` | Derivation depth budget. The default is the smallest that reaches every grammar rule. | | `--coverage` | off | Report per-rule expansion counts and unexercised rules. | | `--pattern` | | Reproduce a single case (with `--flags` / `--subject` / `--last-index`). | +| `--testcase` | | Replay a generated testcase file (`run.py` output, e.g. a ClusterFuzz `fuzz-N.js`). | The exit status is non-zero when any divergence is found. @@ -116,6 +135,81 @@ keeps everything printed so far even when redirected to a file: the seed, every finding, and the progress trail. An interrupt during a finding's minimization still prints that finding unminimized before exiting. +## ClusterFuzz + +The same generator runs on ClusterFuzz as a blackbox fuzzer, with foozzie +(`tools/clusterfuzz/foozzie/`) as the application. `run.py` implements the +blackbox contract -- `--input_dir`, `--output_dir`, `--no_of_files` -- and only +generates: each `fuzz-N.js` is a self-contained script of ~500 cases plus the +harness, which foozzie executes under two of its configurations and diffs. +Everything downstream (crash detection, dedup, minimization, bisection, bug +filing) is ClusterFuzz's. Foozzie already ships in the build archive, so no new +application or build target is needed. + +Both entry points emit their batches through `harness.py`, so a ClusterFuzz +testcase is byte-for-byte what the interactive tool runs; `--testcase` takes one +back apart and hands each case to the real minimizer. Relative to the +interactive tool, the ClusterFuzz side gains the cross-architecture comparisons +(x64 against the arm/arm64 simulators). ClusterFuzz only removes complete case +lines during minimization. + +Each case prints `v8-foozzie source: regexp-fuzzer:<tag>`. Foozzie hashes the +last label before a difference into a `regexp-<hash>` key. `harness.js` +derives the tag from pattern metacharacters at run time to group similar +patterns, independent of V8 output. + +Testcase files are kept small: ClusterFuzz generates thousands per fuzz task +onto a ~100 MB partition. Each case is a whitespace-free JSON array of +pattern, flags, subject and lastIndex, with the tag computed by the harness +rather than stored, and the harness embedded without its comments. A +500-case file is ~26 KB; `--cases-per-file` is the lever if the budget +tightens further. + +Simulate a job locally before uploading; this is also how to judge how noisy a +grammar change is under foozzie's rules, which unlike the interactive tool have +no ground-truth side to skip a configuration-dependent exception: + +```sh +tools/regexp/correctness_fuzzer/run_locally_against_foozzie.py \ + --d8 out/x64.release/d8 --files 100 +``` + +Which configurations foozzie compares is chosen by the fuzzer, as for +js_fuzzer: next to each `fuzz-N.js`, `run.py` writes a `flags-N.js` with the +`v8_foozzie.py` flags for it (`--first-config`, `--second-config`, +`--second-d8`, `--second-config-extra-flags`, and a fixed `--random-seed`). +It draws them from +`tools/clusterfuzz/foozzie/v8_fuzz_experiments_regexp.json` and +`v8_fuzz_flags_regexp.json`, read from the build directory the fuzzer runs +against (`$APP_DIR` on ClusterFuzz, where the V8 build copies them next to d8; +the foozzie source directory when run from a checkout). + +Each experiment row is `[probability, baseline, second, second_d8]`. Foozzie +always runs the baseline, an implicit flagless `default` on `second_d8`, and +`second` on `second_d8`, and diffs the latter two against the baseline. The +regexp table uses `jitless` (implies `--regexp-interpret-all`, the bytecode +interpreter) as the baseline, so every file compares the x64 interpreter +against native code on x64 or the arm64/arm/ia32 simulators through the +implicit `default` run. `second` is `slow_path` (`--force-slow-path`, the +runtime `RegExpExec` path) throughout, since a `default` second config would +duplicate the implicit run. x64 gets the largest share as the fastest and +least flaky configuration. The flag table holds regexp codegen toggles that +must be observationally invisible, plus `--regexp-tier-up-ticks=1` to exercise +the interpreter-to-native tier-up mid-run; they are applied to the `default` +and `second` runs. + +A generated case with exponential backtracking occasionally exceeds foozzie's +per-run timeout; foozzie treats that as a pass and the file is lost, which at +the observed rate (about 1 in 100 files) is noise. The dry run counts and +keeps such files. + +Build the bundle with `package.sh` (default output `out/regexp_fuzzer.zip`): +`run.py`, `harness.py`, `harness.js`, `grammar/` and a copy of js_fuzzer's +`foozzie_launcher.py`, all at the top level. It is uploaded through the +ClusterFuzz UI and attached to the existing foozzie correctness jobs and plain +d8 sanitizer jobs; re-run and re-upload whenever the grammar or harness +changes. + ## Tests ```sh @@ -124,8 +218,11 @@ tools/regexp/correctness_fuzzer/grammar_test.py --d8 out/x64.release/d8 Pins the properties that decay silently: every grammar rule stays reachable under every profile, mode-specific syntax stays in its mode, generated patterns -parse, and a meaningful share of cases match. Omit `--d8` to run only the -checks that need no build. +parse, a meaningful share of cases match, and the emitted testcase format +stands alone, survives a line-based minimizer, and round-trips through +`--testcase`. Omit `--d8` for the fast presubmit checks with bounded samples. +Use `--exhaustive` for full Python samples and rule/profile coverage without +a build. `--d8` also enables the exhaustive Python checks. ## Files @@ -135,9 +232,13 @@ checks that need no build. - `rules.py` -- the grammar itself, one `@rule` per spec alternative. - `cases.py` -- flags, subjects, and whole cases. - `profiles.py` -- weight overlays and `--weight` parsing. -- `grammar_test.py` -- tests for the above. -- `correctness_fuzzer.py` -- execution, diff, and minimization. +- `grammar_test.py` -- tests for the above, the harness, and the testcase format. +- `correctness_fuzzer.py` -- interactive entry point: execution, diff, and minimization. - `harness.js` -- the `d8` harness that constructs and runs each regexp. +- `harness.py` -- emits cases plus harness as one self-contained script, and parses it back. +- `run.py` -- ClusterFuzz entry point: generates testcase files and their foozzie flags. +- `run_locally_against_foozzie.py` -- local simulation of a ClusterFuzz foozzie job. +- `package.sh` -- builds the zip uploaded to ClusterFuzz. A rule never makes a weighted choice of its own: anything that would be an `if rng.random() < p` inside a rule body is a separate `@rule` with its own diff --git a/deps/v8/tools/regexp/correctness_fuzzer/correctness_fuzzer.py b/deps/v8/tools/regexp/correctness_fuzzer/correctness_fuzzer.py index 5f87710baca6..bebf44704797 100755 --- a/deps/v8/tools/regexp/correctness_fuzzer/correctness_fuzzer.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/correctness_fuzzer.py @@ -32,9 +32,16 @@ tools/regexp/correctness_fuzzer/correctness_fuzzer.py --ref A --test B \ --pattern '(?=|)()x|' --flags '' --subject z +Replay a generated testcase file, e.g. one ClusterFuzz attached to a bug +(see run.py), classifying every case in it and minimizing each finding: + + tools/regexp/correctness_fuzzer/correctness_fuzzer.py --ref A --test B \ + --testcase fuzz-3.js + The reference is treated as ground truth; only cases the reference executes cleanly are compared, so an unsupported-syntax difference in -the reference is never reported as a test failure. +the reference is never reported as a test failure. Both configurations +use --js-staging by default; see README.md for flag overrides. """ import argparse @@ -49,12 +56,7 @@ import tempfile import grammar - -# The d8 harness that actually constructs and runs each regexp, kept next to -# this script so it ships with the tool instead of being written at runtime. -# realpath so the harness is found even when the script is invoked via symlink. -HARNESS_PATH = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "harness.js") +import harness def parse_config(spec): @@ -85,10 +87,11 @@ def __init__(self, ref_spec, test_spec): @contextlib.contextmanager def _cases_file(self, cases): - fd, path = tempfile.mkstemp(prefix="regexp_fuzz_", suffix=".json") + # Use the same testcase format as the ClusterFuzz generator. + fd, path = tempfile.mkstemp(prefix="regexp_fuzz_", suffix=".js") try: - with os.fdopen(fd, "w") as f: - json.dump(cases, f) + with os.fdopen(fd, "w", encoding="utf-8") as f: + f.write(harness.emit_js(cases)) yield path finally: os.unlink(path) @@ -96,7 +99,7 @@ def _cases_file(self, cases): def _run(self, config, casefile): path, flags = config try: - p = subprocess.run([path, *flags, HARNESS_PATH, "--", casefile], + p = subprocess.run([path, *grammar.D8_FLAGS, *flags, casefile], capture_output=True, text=True, timeout=60) @@ -110,9 +113,12 @@ def _results(out): Selecting by shape keeps the diff robust to any banner or warning lines a d8 configuration might print around the harness output. + + str.splitlines() would also split at U+2028, U+2029 and U+0085, + which JSON.stringify leaves unescaped inside strings. """ results = {} - for line in out.splitlines(): + for line in out.split("\n"): key, tab, value = line.partition("\t") if tab and key.isdigit(): results[int(key)] = value @@ -310,11 +316,55 @@ def size(p): return pattern, flags, subject, last_index +def _regexp_literal(pattern, flags): + """Format a valid constructor pattern as a UTF-8-safe regexp literal.""" + # Combine raw surrogate pairs before escaping lone surrogates. + pattern = pattern.encode("utf-16-le", + "surrogatepass").decode("utf-16-le", "surrogatepass") + escapes = { + "\n": r"\n", + "\r": r"\r", + "\t": r"\t", + "\u2028": r"\u2028", + "\u2029": r"\u2029" + } + unicode = "u" in flags or "v" in flags + out = [] + in_class = False + chars = iter(pattern) + for c in chars: + if c == "\\": + c = next(chars, "") + if not c: + out.append("\\") + break + if c not in escapes and not (ord(c) < 32 or 0xd800 <= ord(c) <= 0xdfff): + out.append("\\" + c) + continue + # Legacy identity escapes of raw controls/surrogates lose their prefix. + if c in escapes: + out.append(escapes[c]) + elif ord(c) < 32 or ord(c) == 127: + out.append(r"\x%02x" % ord(c)) + elif 0xd800 <= ord(c) <= 0xdfff: + # Braces prevent pairing with an adjacent \uXXXX escape in Unicode mode. + out.append((r"\u{%04x}" if unicode else r"\u%04x") % ord(c)) + else: + if c == "/" and not in_class: + out.append("\\") + elif c == "[": + in_class = True + elif c == "]": + in_class = False + out.append(c) + return "/%s/%s" % ("".join(out) or "(?:)", flags) + + def _print_case(runner, pattern, flags, subject, last_index, header): rc_r, res_r = runner.run_one(runner.ref, pattern, flags, subject, last_index) rc_t, res_t = runner.run_one(runner.test, pattern, flags, subject, last_index) print(header) - print(" pattern: /%s/%s" % (pattern, flags)) + print(" pattern: %s" % _regexp_literal(pattern, flags)) print(" subject: %r" % subject) if last_index: print(" lastIndex: %d" % last_index) @@ -405,11 +455,18 @@ def main(): "--coverage", action="store_true", help="report which grammar rules the run exercised, and which it missed") - ap.add_argument( + repro = ap.add_mutually_exclusive_group() + repro.add_argument( "--pattern", help="reproduce a single case instead of fuzzing") ap.add_argument("--flags", default="") ap.add_argument("--subject", default="") ap.add_argument("--last-index", type=int, default=0) + repro.add_argument( + "--testcase", + metavar="FILE", + help="replay a generated testcase file (e.g. a ClusterFuzz fuzz-N.js) " + "instead of fuzzing: every case in it is classified and each finding " + "minimized") args = ap.parse_args() try: @@ -429,6 +486,23 @@ def main(): print("no divergence for the given case") return 0 + if args.testcase is not None: + with open(args.testcase, encoding="utf-8") as f: + try: + cases = harness.parse_testcase(f.read()) + except ValueError as e: + ap.error(str(e)) + # Run cases separately to attribute crashes. + findings = 0 + for i, (pat, fl, sub, li) in enumerate(cases): + kind = runner.finding(pat, fl, sub, li) + if kind: + report(runner, pat, fl, sub, li, "%s case=%d" % (kind, i)) + findings += 1 + print("done: %d case(s) from %s, %d finding(s)" % + (len(cases), args.testcase, findings)) + return 1 if findings else 0 + seed = args.seed if args.seed is not None else random.randrange(2**32) # Print (flushed) up front so the seed survives an early abort; a long run is # typically stopped with Ctrl-C, and the seed is what makes it reproducible. diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/__init__.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/__init__.py index 5bb70aec1335..eb6be2911a43 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/__init__.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/__init__.py @@ -47,8 +47,12 @@ from .profiles import PROFILES, parse_weights from .registry import Context, GrammarError, all_rules, expand +# Match foozzie's staged syntax support. See README.md for flag overrides. +D8_FLAGS = ("--js-staging",) + __all__ = [ "Context", + "D8_FLAGS", "GrammarError", "PROFILES", "all_rules", diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/cases.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/cases.py index a41096c8ac83..37ad49e719b3 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/cases.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/cases.py @@ -4,7 +4,7 @@ """Flags, subjects, and whole cases.""" from .menus import (LAST_INDEX_SHARE, SUBJECT_LITERAL_SHARE, SUBJECT_MAX_LEN, - SUBJECT_NOISE) + SUBJECT_NOISE, SUBJECT_TAIL_SHARE) from .registry import Context from .rules import gen_pattern @@ -37,18 +37,23 @@ def gen_flags(rng): return flags -def gen_subject(rng, literals): +def gen_subject(rng, literals, tails=()): """Build a subject biased toward characters the pattern mentions. Drawing from the pattern's own literal pool is what makes a meaningful share of cases match; a uniformly random subject almost never gets past the first character, leaving the match path untested. + + Append a requested tail with probability SUBJECT_TAIL_SHARE, independently + of the body length. This exercises assertions before trailing terminators. """ pool = [c for c in literals if c] or ["a"] out = [] for _ in range(rng.randint(0, SUBJECT_MAX_LEN)): take_literal = rng.random() < SUBJECT_LITERAL_SHARE out.append(rng.choice(pool if take_literal else SUBJECT_NOISE)) + if tails and rng.random() < SUBJECT_TAIL_SHARE: + out.append(rng.choice(tails)) return "".join(out) @@ -63,7 +68,7 @@ def gen_case(rng, max_depth=5, weights=None, coverage=None): weights=weights, coverage=coverage) pattern = gen_pattern(ctx) - subject = gen_subject(rng, ctx.literals) + subject = gen_subject(rng, ctx.literals, ctx.tails) # lastIndex only has an observable effect for sticky/global patterns, but # setting it regardless costs nothing and keeps the case shape uniform. last_index = 0 diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/menus.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/menus.py index 37ce043757ca..9e407ab1e5ff 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/menus.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/menus.py @@ -16,6 +16,8 @@ # operator alternation has. LITERAL = list("abcxyzABXY019") + list("=:;,~!@%&<>") LITERAL_WIDE = ["é", "Ω", "\U0001f0a1"] +# Halves of U+1F0A1, which is already in the subject noise pool. +SURROGATES = ["\ud83c", "\udca1"] # `\xHH` reaches U+00FF and no further, so its pool is the Latin-1 subset: # LITERAL_WIDE's other members would silently truncate ("x%02x" % 0x3A9 is @@ -36,6 +38,9 @@ # something the pattern can actually match. ESCAPE_LITERALS = {"f": "\f", "n": "\n", "r": "\r", "t": "\t", "v": "\v"} +# Line terminators and CRLF: suffixes that distinguish `\Z` from `\z`. +LINE_TERMINATORS = ["\n", "\r", "\r\n", "\u2028", "\u2029"] + # Property names that exist in every ICU build V8 ships with. UNICODE_PROPERTIES = [ "L", @@ -78,5 +83,8 @@ SUBJECT_LITERAL_SHARE = 0.75 SUBJECT_MAX_LEN = 10 +# Probability of appending a tail requested by the pattern. +SUBJECT_TAIL_SHARE = 0.5 + # Probability that a case sets a nonzero lastIndex. LAST_INDEX_SHARE = 0.3 diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/profiles.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/profiles.py index cca49749a134..6051c6da2a49 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/profiles.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/profiles.py @@ -14,10 +14,24 @@ # prefix filter optimization actually sees. "anchored": { "Assertion.caret": 8.0, + "Assertion.start_of_input": 4.0, "Term.assertion": 2.0, "Disjunction.alternation": 2.0, "Atom.character_class": 2.0, }, + # Exercise assertions in groups and their legacy identity-escape meanings. + # `\Z` uses a forward lookahead even inside lookbehind. + "buffer_boundaries": { + "Assertion.start_of_input": 6.0, + "Assertion.end_of_input": 6.0, + "Assertion.end_of_buffer": 8.0, + "Term.assertion": 2.0, + "Assertion.lookbehind": 2.0, + "Assertion.negative_lookbehind": 2.0, + "Disjunction.alternation": 2.0, + "Atom.capturing_group": 2.0, + "CharacterEscape.identity_escape_boundary_letter": 6.0, + }, # v-mode set algebra: nested classes, intersection, subtraction, strings. "classes": { "Atom.character_class": 4.0, diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/registry.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/registry.py index 0ba3da24c798..139744bd2555 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/registry.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/registry.py @@ -79,6 +79,7 @@ def __init__(self, self.capture_count = 0 self.group_names = [] self.literals = [] + self.tails = [] # Nonzero inside a negated class, where a string-valued operand is a # static-semantics error rather than merely unusual. self.no_strings = 0 @@ -109,6 +110,10 @@ def note_literal(self, s): self.literals.append(s) return s + def note_tails(self, tails): + """Request suffixes for gen_subject to sample independently of literals.""" + self.tails.extend(tails) + def describe(self): """Parameter summary, for error messages.""" return "unicode_mode=%r unicode_sets_mode=%r in_class=%d no_strings=%d" % ( diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py index 0977afa7c15c..395e360dba4b 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar/rules.py @@ -18,9 +18,9 @@ """ from .menus import (ASCII_LETTER, CLASS_SET_SAFE, CONTROL_ESCAPE, - ESCAPE_LITERALS, LATIN1_ONLY, LITERAL, LITERAL_WIDE, - RANGE_ALPHABET, UNICODE_PROPERTIES, - UNICODE_PROPERTIES_OF_STRINGS) + ESCAPE_LITERALS, LATIN1_ONLY, LINE_TERMINATORS, LITERAL, + LITERAL_WIDE, RANGE_ALPHABET, SURROGATES, + UNICODE_PROPERTIES, UNICODE_PROPERTIES_OF_STRINGS) from .registry import (NOT_SETS, NOT_UNICODE, SETS, UNICODE, concat_terms, expand, repeat, rule) @@ -90,6 +90,7 @@ def quantified_atom(ctx): # Assertion :: `^` `$` `\b` `\B` +# [+UnicodeMode] `\A` `\z` `\Z` # `(?=` Disjunction `)` and the three other lookaround forms @@ -113,6 +114,34 @@ def not_word_boundary(ctx): return r"\B" +# Outside Unicode mode these are identity escapes (see +# identity_escape_boundary_letter). Assertion is not derived inside classes. + + +@rule("Assertion", weight=1.0, guard=UNICODE) +def start_of_input(ctx): + # Anchoring can remove the search loop; nonzero lastIndex with g/y must + # still fail rather than restart at the anchor. + return r"\A" + + +@rule("Assertion", weight=0.7, guard=UNICODE) +def end_of_input(ctx): + # Use the same suffixes as `\Z` to exercise their differing semantics. + ctx.note_tails(LINE_TERMINATORS) + return r"\z" + + +@rule("Assertion", weight=0.8, guard=UNICODE) +def end_of_buffer(ctx): + # `\Z` matches at end of input or before a trailing line terminator or CRLF. + # Also put terminators inside subjects, where the assertion must fail unless + # the remaining suffix is itself a single terminator or CRLF. + ctx.note_tails(LINE_TERMINATORS) + ctx.note_literal(ctx.rng.choice(LINE_TERMINATORS)) + return r"\Z" + + @rule("Assertion", weight=1.0, recursive=True) def lookahead(ctx): return "(?=" + expand(ctx, "Disjunction") + ")" @@ -223,7 +252,7 @@ def pattern_character(ctx): def pattern_character_wide(ctx): # A non-Latin-1 literal forces the two-byte subject representation and, for # the supplementary one, the surrogate-pair path. - return ctx.note_literal(ctx.rng.choice(LITERAL_WIDE)) + return ctx.note_literal(ctx.rng.choice(LITERAL_WIDE + SURROGATES)) @rule("Atom", weight=1.5) @@ -384,14 +413,14 @@ def hex_escape(ctx): @rule("CharacterEscape", weight=1.5) def unicode_escape(ctx): - c = ctx.rng.choice(LITERAL + ["é", "Ω"]) + c = ctx.rng.choice(LITERAL + ["é", "Ω"] + SURROGATES) ctx.note_literal(c) return "u%04x" % ord(c) @rule("CharacterEscape", weight=0.8, guard=UNICODE) def unicode_escape_braced(ctx): - c = ctx.rng.choice(LITERAL + LITERAL_WIDE) + c = ctx.rng.choice(LITERAL + LITERAL_WIDE + SURROGATES) ctx.note_literal(c) return "u{%x}" % ord(c) @@ -413,13 +442,21 @@ def unicode_escape_surrogate_pair(ctx): @rule("CharacterEscape", weight=1.0, guard=UNICODE) def identity_escape(ctx): # [+UnicodeMode] restricts IdentityEscape to SyntaxCharacter and `/`. - return ctx.rng.choice(list("^$\\.*+?()[]{}|/")) + return ctx.note_literal(ctx.rng.choice(list("^$\\.*+?()[]{}|/"))) @rule("CharacterEscape", weight=1.0, guard=NOT_UNICODE) def identity_escape_extended(ctx): # Only [~UnicodeMode] admits arbitrary non-ID characters. - return ctx.rng.choice(list("^$\\.*+?()[]{}|/-@~")) + return ctx.note_literal(ctx.rng.choice(list("^$\\.*+?()[]{}|/-@~"))) + + +@rule("CharacterEscape", weight=0.5, guard=NOT_UNICODE) +def identity_escape_boundary_letter(ctx): + # In legacy mode these match letters, both inside and outside classes. + letter = ctx.rng.choice(list("AzZ")) + ctx.note_literal(letter) + return letter # CharacterClassEscape :: `d` `D` `s` `S` `w` `W` @@ -513,7 +550,7 @@ def class_literal(ctx): @rule("ClassAtom", weight=0.8) def class_literal_wide(ctx): - return ctx.note_literal(ctx.rng.choice(LITERAL_WIDE)) + return ctx.note_literal(ctx.rng.choice(LITERAL_WIDE + SURROGATES)) @rule("ClassAtom", weight=2.0) @@ -581,7 +618,7 @@ def set_operand(ctx): @rule("ClassSetOperand", weight=7.0) def set_character(ctx): - return ctx.note_literal(ctx.rng.choice(CLASS_SET_SAFE)) + return expand(ctx, "ClassSetCharacter") @rule("ClassSetOperand", weight=2.0) @@ -607,10 +644,25 @@ def nested_negated_class(ctx): def class_string_disjunction(ctx): # `\q{a|bc|}`: a disjunction of literal strings, the one construct that # lets a class match more than a single character. - words = [] - for _ in range(ctx.rng.randint(1, 3)): - w = "".join( - ctx.rng.choice(CLASS_SET_SAFE) for _ in range(ctx.rng.randint(0, 3))) - ctx.note_literal(w) - words.append(w) + words = [ + "".join( + expand(ctx, "ClassSetCharacter") + for _ in range(ctx.rng.randint(0, 3))) + for _ in range(ctx.rng.randint(1, 3)) + ] return r"\q{%s}" % "|".join(words) + + +# ClassSetCharacter :: SourceCharacter but not ClassSetSyntaxCharacter +# `\` CharacterEscape + + +@rule("ClassSetCharacter", weight=6.0) +def literal(ctx): + return ctx.note_literal( + ctx.rng.choice(CLASS_SET_SAFE + LITERAL_WIDE + SURROGATES)) + + +@rule("ClassSetCharacter", weight=2.0) +def escape(ctx): + return "\\" + expand(ctx, "CharacterEscape") diff --git a/deps/v8/tools/regexp/correctness_fuzzer/grammar_test.py b/deps/v8/tools/regexp/correctness_fuzzer/grammar_test.py index c43aa1ce6a12..d60b6ec2ce3e 100755 --- a/deps/v8/tools/regexp/correctness_fuzzer/grammar_test.py +++ b/deps/v8/tools/regexp/correctness_fuzzer/grammar_test.py @@ -14,12 +14,15 @@ tools/regexp/correctness_fuzzer/grammar_test.py --d8 out/x64.release/d8 -The rest run without a build. +The default run uses small samples for presubmit. --exhaustive enables the +full Python coverage sweeps without a build; --d8 enables those too. """ import argparse import collections +import contextlib import inspect +import io import json import os import random @@ -31,33 +34,32 @@ import correctness_fuzzer import grammar -from grammar import registry - -HARNESS_PATH = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "harness.js") +import harness +import run +from grammar import menus, registry # Set from the command line; None means the d8-dependent tests are skipped. D8 = None +EXHAUSTIVE = False + + +def sample_size(n): + return n if EXHAUSTIVE else min(n, 200) def run_cases(cases): """Run |cases| through the harness, returning index -> result JSON string.""" - fd, path = tempfile.mkstemp(prefix="grammar_test_", suffix=".json") + fd, path = tempfile.mkstemp(prefix="grammar_test_", suffix=".js") try: - with os.fdopen(fd, "w") as f: - json.dump(cases, f) - p = subprocess.run([D8, HARNESS_PATH, "--", path], + with os.fdopen(fd, "w", encoding="utf-8") as f: + f.write(harness.emit_js(cases)) + p = subprocess.run([D8, *grammar.D8_FLAGS, path], capture_output=True, text=True, timeout=300) finally: os.unlink(path) - results = {} - for line in p.stdout.splitlines(): - key, tab, value = line.partition("\t") - if tab and key.isdigit(): - results[int(key)] = value - return results + return correctness_fuzzer.Runner._results(p.stdout) def generate(n, seed=1, **kwargs): @@ -80,10 +82,26 @@ def _in_class(pattern, pos): return depth > 0 +def _escapes(pattern): + r"""Yield (position, escaped character) for each `\x` in |pattern|. + + Consume each escape as a pair, so `\\A` yields only the escaped backslash. + """ + i = 0 + while i < len(pattern) - 1: + if pattern[i] == "\\": + yield i, pattern[i + 1] + i += 2 + else: + i += 1 + + class GrammarStructureTest(unittest.TestCase): """Properties of the grammar itself, checkable without a d8.""" def test_every_rule_is_reachable(self): + if not EXHAUSTIVE: + self.skipTest("needs --exhaustive or --d8") # A rule that never fires tests nothing, and no amount of case volume # reveals that on its own -- this is the check that caught a depth-budget # bug where every generated character class came out empty. @@ -97,6 +115,8 @@ def test_every_rule_is_reachable(self): self.assertEqual([], missing, "unreachable at the default --max-depth") def test_every_profile_reaches_every_rule(self): + if not EXHAUSTIVE: + self.skipTest("needs --exhaustive or --d8") # A profile reweights rules; setting one to a very low weight in effect # removes it, which should be a deliberate choice rather than a side # effect of tuning some other rule up. @@ -112,11 +132,21 @@ def test_every_profile_reaches_every_rule(self): ] self.assertEqual([], missing) + def test_profiles_keep_positive_rule_weights(self): + for profile in grammar.PROFILES: + weights = grammar.parse_weights(profile, None) + ctx = grammar.Context(random.Random(1), False, False, 5, weights=weights) + for rules in registry.GRAMMAR.values(): + for rule in rules: + self.assertGreater( + ctx.weight_of(rule), 0, + "%s: %s.%s" % (profile, rule.prod, rule.name)) + def test_mode_specific_syntax_stays_in_its_mode(self): # The spec's [+UnicodeMode] / [+UnicodeSetsMode] parameters are what make # most syntax errors structurally impossible; a rule that loses its guard # would still generate, just invalidly. - for pattern, flags, _, _ in generate(4000): + for pattern, flags, _, _ in generate(sample_size(4000)): if "v" not in flags: self.assertNotIn(r"\q{", pattern) self.assertNotIn("&&", pattern) @@ -126,11 +156,77 @@ def test_mode_specific_syntax_stays_in_its_mode(self): self.assertNotIn(r"\P{", pattern) self.assertNotIn(r"\u{", pattern) + def test_buffer_boundary_assertions_stay_in_unicode_mode(self): + # Check the production: pattern text cannot distinguish assertions from + # identically spelled legacy identity escapes. + rng = random.Random(1) + without = { + grammar.expand(grammar.Context(rng, False, False, 5), "Assertion") + for _ in range(2000) + } + self.assertFalse(without & {r"\A", r"\z", r"\Z"}, without) + with_mode = { + grammar.expand(grammar.Context(rng, True, False, 5), "Assertion") + for _ in range(2000) + } + self.assertTrue({r"\A", r"\z", r"\Z"} <= with_mode, with_mode) + + def test_boundary_letters_are_identity_escapes_outside_unicode_mode(self): + # Compare whole escapes so `\cA` does not count as the identity escape A. + rng = random.Random(1) + letters = {"A", "z", "Z"} + without = { + grammar.expand( + grammar.Context(rng, False, False, 5), "CharacterEscape") + for _ in range(2000) + } + self.assertEqual(letters, without & letters) + with_mode = { + grammar.expand(grammar.Context(rng, True, False, 5), "CharacterEscape") + for _ in range(2000) + } + self.assertFalse(with_mode & letters, with_mode & letters) + + def test_buffer_boundary_escapes_stay_out_of_unicode_classes(self): + for pattern, flags, _, _ in generate(4000): + if "u" not in flags and "v" not in flags: + continue + for pos, escaped in _escapes(pattern): + if escaped in "AzZ": + self.assertFalse(_in_class(pattern, pos), pattern) + + def test_end_of_buffer_subjects_end_in_a_line_terminator(self): + # Compare with patterns that request no tails to distinguish requested + # suffixes from terminators drawn from SUBJECT_NOISE. + terminators = tuple(menus.LINE_TERMINATORS) + asked, asked_tail, asked_crlf, asked_mid = 0, 0, 0, 0 + other, other_tail = 0, 0 + for pattern, flags, subject, _ in generate(6000): + unicode = "u" in flags or "v" in flags + asks = unicode and any(c in "zZ" for _, c in _escapes(pattern)) + ends = subject.endswith(terminators) + if asks: + asked += 1 + asked_tail += ends + asked_crlf += subject.endswith("\r\n") + asked_mid += any(c in terminators for c in subject[:-1]) and not ends + else: + other += 1 + other_tail += ends + self.assertGreater(asked, 100, "too few cases to measure") + self.assertGreater(asked_tail / asked, 0.3) + self.assertGreater(asked_crlf, 0) + self.assertGreater(asked_mid, 0) + self.assertGreater(asked_tail / asked, 2 * other_tail / other) + def test_digit_terminated_escapes_are_separated(self): # `\1` and `\0` are terminated by lookahead, so a digit right after either # silently reparses it. The `(?:)` separator that prevents this is only a # separator between Terms; inside a class it would be four more members. - for pattern, _, _, _ in generate(4000): + for escape in (r"\0", r"\1", r"\12"): + self.assertEqual(escape + "(?:)3", registry.concat_terms([escape, "3"])) + self.assertEqual(r"\d3", registry.concat_terms([r"\d", "3"])) + for pattern, _, _, _ in generate(sample_size(4000)): self.assertIsNone(re.search(r"\\[0-9]+[0-9]", pattern), pattern) for m in re.finditer(r"\(\?:\)", pattern): self.assertFalse(_in_class(pattern, m.start()), pattern) @@ -141,8 +237,10 @@ def test_generation_is_deterministic(self): self.assertEqual(generate(200, seed=7), generate(200, seed=7)) def test_depth_budget_bounds_pattern_size(self): - small = max(len(p) for p, _, _, _ in generate(500, max_depth=2)) - large = max(len(p) for p, _, _, _ in generate(500, max_depth=6)) + small = max( + len(p) for p, _, _, _ in generate(sample_size(500), max_depth=2)) + large = max( + len(p) for p, _, _, _ in generate(sample_size(500), max_depth=6)) self.assertLess(small, large) def test_unknown_profile_and_rule_are_rejected(self): @@ -222,7 +320,7 @@ def test_quantifier_bounds_reach_past_the_unroll_threshold(self): # which cannot tell a quantifier from a `\q{9}` or a `{` inside a class. counted = looping = 0 rng = random.Random(1) - for _ in range(3000): + for _ in range(sample_size(3000)): ctx = grammar.Context(rng, False, False, 5) m = re.fullmatch(r"\{(\d+),?\d*\}", grammar.expand(ctx, "QuantifierPrefix")) @@ -240,19 +338,19 @@ def test_flags_cover_the_result_shaping_ones(self): # adds match indices, a whole output surface; neither was generated # before. seen = set() - for _, flags, _, _ in generate(2000): + for _, flags, _, _ in generate(sample_size(2000)): seen.update(flags) self.assertEqual(set("dgimsuvy"), seen) def test_u_and_v_are_never_combined(self): - for _, flags, _, _ in generate(3000): + for _, flags, _, _ in generate(sample_size(3000)): self.assertFalse("u" in flags and "v" in flags, flags) def test_weight_override_shifts_the_distribution(self): def caret_share(weights): coverage = collections.Counter() - generate(1500, weights=weights, coverage=coverage) + generate(sample_size(1500), weights=weights, coverage=coverage) return coverage[("Assertion", "caret")] base = caret_share(None) @@ -260,6 +358,68 @@ def caret_share(weights): grammar.parse_weights("default", ["Assertion.caret=20"])) self.assertGreater(boosted, base) + def test_class_string_disjunction_surrogates(self): + # Inside `\q{...}`, lone surrogates only combine into a supplementary code + # point when both halves are literals or `\uXXXX` escapes; any `\u{...}` + # escape keeps them separate. Verify that mixed escape forms and + # literal/escaped combinations are reachable, and that every + # ClassSetCharacter expansion records a single decoded character in + # ctx.literals rather than escape sequences. + weights = grammar.parse_weights("default", [ + "CharacterClass.negated_class=0", + "ClassContents.empty_class=0", + "ClassSetOperandOrRange.set_range=0", + "ClassSetOperand.set_character=0", + "ClassSetOperand.set_class_escape=0", + "CharacterEscape.unicode_escape=10", + "CharacterEscape.unicode_escape_braced=20", + "ClassSetCharacter.literal=1", + "ClassSetCharacter.escape=2", + ]) + targets = { + r"\ud83c\u{dca1}", + r"\u{d83c}\udca1", + r"\u{d83c}\u{dca1}", + "\\ud83c\udca1", + "\\u{d83c}\udca1", + "\ud83c\\udca1", + "\ud83c\\u{dca1}", + } + seen = set() + rng = random.Random(13) + for _ in range(8000): + cov = collections.Counter() + ctx = grammar.Context(rng, True, True, 1, weights=weights, coverage=cov) + pat = grammar.expand(ctx, "CharacterClass") + self.assertTrue(pat.startswith(r"[\q{") and pat.endswith("}]"), pat) + n_chars = ( + cov[("ClassSetCharacter", "literal")] + + cov[("ClassSetCharacter", "escape")]) + self.assertEqual(n_chars, len(ctx.literals)) + self.assertTrue(all(len(lit) == 1 for lit in ctx.literals), ctx.literals) + for t in targets: + if t in pat: + seen.add(t) + self.assertIn("\ud83c", ctx.literals) + self.assertIn("\udca1", ctx.literals) + if seen == targets: + break + self.assertEqual(targets, seen) + + +class ResultParsingTest(unittest.TestCase): + """How harness output is cut into per-case results.""" + + def test_unicode_line_separators_do_not_split_a_result(self): + out = ('banner\n' + '0\t{"cold":{"r":["a\u2028"]},"warm":{"r":["a\u2028"]}}\n' + '1\t{"cold":{"r":["\u2029"]},"warm":{"r":["\u2029"]}}\n' + 'DONE\n') + results = correctness_fuzzer.Runner._results(out) + self.assertEqual([0, 1], sorted(results)) + self.assertEqual(["a\u2028"], json.loads(results[0])["warm"]["r"]) + self.assertEqual(["\u2029"], json.loads(results[1])["warm"]["r"]) + class ClassificationTest(unittest.TestCase): """How a pair of harness results is turned into a finding. @@ -310,6 +470,52 @@ def test_a_missing_result_line_is_a_divergence(self): self.assertEqual("DIVERGENCE", correctness_fuzzer.classify(0, self.OK, 0, None)) + def test_print_case_preserves_pattern_and_flags(self): + + class StubRunner: + ref = test = None + + def run_one(self, config, pattern, flags, subject, last_index=0): + return 0, ClassificationTest.OK + + for pattern, flags, expected in self.LITERAL_CASES: + with self.subTest(pattern=pattern, flags=flags): + raw = io.BytesIO() + stream = io.TextIOWrapper(raw, encoding="utf-8") + with contextlib.redirect_stdout(stream): + correctness_fuzzer._print_case(StubRunner(), pattern, flags, pattern, + 0, "DIVERGENCE") + lines = raw.getvalue().decode("utf-8").splitlines() + self.assertEqual(" pattern: " + expected, lines[1]) + + LITERAL_CASES = ( + (r"\d", "", r"/\d/"), + (r"\\", "u", r"/\\/u"), + ('"', "v", '/"/v'), + ("/", "", r"/\//"), + (r"\/", "u", r"/\//u"), + (r"\\/", "v", r"/\\\//v"), + ("[/]", "u", "/[/]/u"), + (r"\[/", "", r"/\[\//"), + ("", "v", "/(?:)/v"), + ("\n\r\t\u2028\u2029\x00\x01\x7f", "", + r"/\n\r\t\u2028\u2029\x00\x01\x7f/"), + ("\\\n", "", r"/\n/"), + ("\\\\\n", "u", r"/\\\n/u"), + ("[\\\n/]", "", r"/[\n/]/"), + ("\ud83c", "", r"/\ud83c/"), + ("\udca1", "u", r"/\u{dca1}/u"), + ("\ud83c", "v", r"/\u{d83c}/v"), + ("\\\ud83c", "", r"/\ud83c/"), + ("\\\x00", "", r"/\x00/"), + ("\ud83c\udca1", "u", "/\U0001f0a1/u"), + ("\U0001f0a1", "v", "/\U0001f0a1/v"), + ("\ud83c" + r"\udca1", "u", r"/\u{d83c}\udca1/u"), + (r"\ud83c" + "\udca1", "v", r"/\ud83c\u{dca1}/v"), + ("[\ud83c" + r"\udca1]", "v", r"/[\u{d83c}\udca1]/v"), + (r"[\q{" + "\ud83c" + r"\udca1}]", "v", r"/[\q{\u{d83c}\udca1}]/v"), + ) + class MinimizerTest(unittest.TestCase): """Shrinking, which has to keep up with the large quantifier bounds.""" @@ -353,6 +559,106 @@ def finding(self, pattern, flags, subject, last_index=0): self.assertLess(runner.calls, 100) +class TestcaseFormatTest(unittest.TestCase): + """Test emitted testcase files.""" + + CASES = [ + ["a|b", "gi", "ab", 1], + ["[\\p{L}--[a]]", "v", "\u00e9\U0001f600", 0], + ["(?<n>x)\\k<n>", "d", "xx", 0], + ] + + def test_emitted_script_is_standalone_ascii(self): + text = harness.emit_js(self.CASES, header=["seed=1"]) + self.assertTrue(text.isascii()) + self.assertNotIn("arguments[", text) + self.assertNotIn("read(", text) + self.assertTrue(text.startswith("// seed=1\nconst cases = [\n")) + + def test_emitted_script_uses_regexp_foozzie_namespace(self): + text = harness.emit_js(self.CASES) + self.assertIn('v8-foozzie source: regexp-fuzzer:', text) + self.assertNotIn('V8 correctness self-check failure', text) + + def test_one_case_per_line_with_trailing_commas(self): + lines = harness.emit_js(self.CASES).splitlines() + start = lines.index("const cases = [") + end = lines.index("];") + body = lines[start + 1:end] + self.assertEqual(len(self.CASES), len(body)) + self.assertTrue(all(l.endswith(",") for l in body)) + + def test_emitted_cases_are_compact(self): + # ClusterFuzz writes thousands of these files to a small partition, so the + # per-case encoding is pinned: no whitespace and no stored tag. + lines = harness.emit_js(self.CASES).splitlines() + start = lines.index("const cases = [") + self.assertEqual('["a|b","gi","ab",1],', lines[start + 1]) + self.assertEqual('["(?<n>x)\\\\k<n>","d","xx",0],', lines[start + 3]) + + def test_embedded_harness_has_no_comments(self): + text = harness.emit_js(self.CASES) + _, _, tail = text.partition("\n];\n") + self.assertTrue(tail) + for line in tail.splitlines(): + self.assertFalse(line.lstrip().startswith("//"), line) + self.assertTrue(line.strip(), "blank line in embedded harness") + # The stripped copy is still the whole harness. + self.assertIn("function execOnce(", tail) + self.assertIn("function sourceTag(", tail) + + def test_cases_round_trip(self): + text = harness.emit_js(self.CASES) + self.assertEqual(self.CASES, harness.parse_testcase(text)) + + def test_parser_tolerates_a_minimized_file(self): + lines = harness.emit_js(self.CASES).splitlines() + del lines[2] + lines[2] = lines[2].rstrip(",") + lines[2] = '["ab", "y"]' + cases = harness.parse_testcase("\n".join(lines)) + self.assertEqual([["a|b", "gi", "ab", 1], ["ab", "y", "", 0]], cases) + + def test_parser_rejects_a_foreign_file(self): + with self.assertRaises(ValueError): + harness.parse_testcase("print('not a fuzzer testcase');\n") + + +class FlagsFileTest(unittest.TestCase): + """Test the foozzie flags emitted next to each testcase.""" + + EXPERIMENTS = [[30, "jitless", "slow_path", "d8"], + [70, "jitless", "slow_path", "clang_x86/d8"]] + ADDITIONAL = [[0.5, "--foo"], [0.5, "--bar --baz"]] + + def test_choose_flags_draws_from_the_tables(self): + rng = random.Random(7) + for _ in range(50): + flags = run.choose_foozzie_flags(rng, self.EXPERIMENTS, self.ADDITIONAL, + 12345) + self.assertEqual("--random-seed=12345", flags[0]) + self.assertEqual(["--first-config=jitless", "--second-config=slow_path"], + flags[1:3]) + self.assertIn(flags[3], ["--second-d8=d8", "--second-d8=clang_x86/d8"]) + extra = [f.split("=", 1)[1] for f in flags[4:]] + self.assertIn( + extra, + [[], ["--foo"], ["--bar", "--baz"], ["--foo", "--bar", "--baz"]]) + + def test_every_testcase_gets_a_flags_file(self): + with tempfile.TemporaryDirectory() as out: + run.main( + ["--output_dir", out, "--no_of_files", "3", "--cases-per-file", "5"]) + for i in range(3): + with open(os.path.join(out, "flags-%d.js" % i)) as f: + flags = f.read().split() + seeds = [flag for flag in flags if flag.startswith("--random-seed=")] + self.assertEqual(1, len(seeds)) + self.assertIn(int(seeds[0].split("=", 1)[1]), range(1, 2**31)) + self.assertTrue(any(f.startswith("--first-config=") for f in flags)) + self.assertTrue(any(f.startswith("--second-d8=") for f in flags)) + + class GeneratedPatternTest(unittest.TestCase): """Properties that only a real engine can judge.""" @@ -362,6 +668,114 @@ def setUp(self): if D8 is None: self.skipTest("needs --d8") + def test_source_tag_keeps_shape_and_drops_literals(self): + # The foozzie clustering tag is computed by harness.js so that it is not + # stored per case; check it through d8, which is the only place it exists. + cases = [ + ["(ab|cd)+\\d", "gi", "", 0], + ["(xy|zw)+\\d", "ig", "", 0], + ["\\.", "", "", 0], + ["\\w\\1", "", "", 0], + ["(" * 500, "", "", 0], + [r"\d" * 41, "", "", 0], + ["(" * 39 + r"\d+", "", "", 0], + ["\\", "", "", 0], + ] + fd, path = tempfile.mkstemp(prefix="grammar_test_", suffix=".js") + try: + with os.fdopen(fd, "w", encoding="utf-8") as f: + f.write(harness.emit_js(cases)) + p = subprocess.run([D8, path], capture_output=True, text=True, timeout=60) + finally: + os.unlink(path) + self.assertEqual(0, p.returncode, p.stdout + p.stderr) + prefix = "v8-foozzie source: regexp-fuzzer:" + tags = [ + l[len(prefix):] for l in p.stdout.splitlines() if l.startswith(prefix) + ] + self.assertEqual(len(cases), len(tags), p.stdout) + self.assertEqual("gi/(|)+\\d", tags[0]) + self.assertEqual(tags[0], tags[1]) + self.assertEqual("/", tags[2]) + self.assertEqual("/\\w\\1", tags[3]) + self.assertLessEqual(len(tags[4]), 41) + self.assertEqual("/" + r"\d" * 40, tags[5]) + self.assertEqual("/" + "(" * 39 + r"\d", tags[6]) + self.assertEqual("/", tags[7]) + + def test_source_tag_does_not_execute_regexp(self): + script = harness.emit_js([]) + r''' + RegExp.prototype.exec = RegExp.prototype.test = function() { + throw new Error("sourceTag executed a regexp"); + }; + print(sourceTag("\\0\\9\\A\\Z\\a\\z\\/\\:\\@\\[\\`\\{\\é", "ig")); + ''' + p = subprocess.run([D8, "-e", script], + capture_output=True, + text=True, + timeout=60) + self.assertEqual(0, p.returncode, p.stdout + p.stderr) + self.assertEqual(["DONE", r"gi/\0\9\A\Z\a\z"], p.stdout.splitlines()) + + def test_printed_literals_preserve_matches(self): + atoms = ("0", "d", "\\", "/", "[", "]", '"', "\n", "\r", "\t", "\u2028", + "\u2029", "\x00", "\ud83c", "\udca1") + subjects = [""] + list(atoms) + [a + b for a in atoms for b in atoms] + cases = [] + patterns = [(p, f) for p, f, _ in ClassificationTest.LITERAL_CASES] + for n in range(6): + for c in ("/", "\n", "\r", "\u2028", "\u2029", "\x00", "\ud83c", + "\ud83c\udca1"): + for flags in ("", "u", "v", "gy", "du"): + patterns.append(("\\" * n + c, flags)) + for pattern, flags in patterns: + cases.append([ + pattern, flags, + correctness_fuzzer._regexp_literal(pattern, flags), subjects, 0 + ]) + for pattern, flags, subject, last_index in generate(3000, seed=19): + cases.append([ + pattern, flags, + correctness_fuzzer._regexp_literal(pattern, flags), [subject], + last_index + ]) + script = "const cases = " + json.dumps(cases) + ";\n" + r""" + function exec(r, subject, lastIndex) { + r.lastIndex = lastIndex; + const m = r.exec(subject); + return JSON.stringify({r:m, idx:m?.index, g:m?.groups, di:m?.indices, + dg:m?.indices?.groups, li:r.lastIndex}); + } + let checked = 0; + for (const [pattern, flags, literal, subjects, lastIndex] of cases) { + let original; + try { + original = new RegExp(pattern, flags); + } catch { + continue; // Formatting is only defined for valid patterns. + } + const copy = eval(literal); + if (copy.flags !== original.flags) throw new Error(literal); + for (const subject of subjects) { + const a = exec(original, subject, lastIndex); + const b = exec(copy, subject, lastIndex); + if (a !== b) { + throw new Error(JSON.stringify({pattern, flags, literal, subject, + lastIndex, a, b})); + } + } + checked++; + } + print(checked); + """ + with tempfile.TemporaryDirectory() as out: + path = os.path.join(out, "literals.js") + with open(path, "w", encoding="utf-8") as f: + f.write(script) + p = subprocess.run([D8, path], capture_output=True, text=True, timeout=60) + self.assertEqual(0, p.returncode, p.stdout + p.stderr) + self.assertGreaterEqual(int(p.stdout.strip()), 3000) + def test_patterns_are_syntactically_valid(self): # The generator this replaced emitted 44% syntax errors, so nearly half of # every run was discarded before executing anything. Zero is the right bar @@ -420,13 +834,75 @@ def test_harness_reports_indices_and_groups(self): # Absent without the flag or the construct, rather than reported as null. self.assertNotIn("di", json.loads(results[1])["warm"]) + def test_runner_runs_with_staged_syntax_enabled(self): + # Legacy `\A` matches a letter; a trailing CRLF distinguishes `\Z` and `\z`. + runner = correctness_fuzzer.Runner(D8, D8) + cases = [ + (r"\Ax", "u", "x", ["x"]), + (r"\A", "", "A", ["A"]), + (r"x\Z", "u", "x\r\n", ["x"]), + (r"x\z", "u", "x\r\n", None), + ] + for pattern, flags, subject, expected in cases: + with self.subTest(pattern=pattern, flags=flags): + rc, result = runner.run_one(runner.ref, pattern, flags, subject) + self.assertEqual(0, rc) + parsed = json.loads(result) + self.assertIsInstance(parsed, dict, result) + for state in ("cold", "warm"): + match = parsed[state] + self.assertEqual(expected, match["r"] if match else None) + + def test_generated_testcase_runs_standalone(self): + with tempfile.TemporaryDirectory() as out: + path = os.path.join(out, "fuzz-0.js") + with open(path, "w", encoding="utf-8") as f: + f.write(run.generate_file(1, "buffer_boundaries", 5, 50)) + p = subprocess.run([D8, *grammar.D8_FLAGS, path], + capture_output=True, + text=True, + timeout=300) + self.assertEqual(0, p.returncode, p.stderr) + lines = p.stdout.split("\n") + self.assertEqual("", lines.pop()) + self.assertEqual("DONE", lines[-1]) + results = correctness_fuzzer.Runner._results(p.stdout) + self.assertEqual(50, len(results)) + self.assertNotIn('"ERR_CTOR"', results.values()) + self.assertEqual( + 50, + sum(1 for l in lines + if l.startswith("v8-foozzie source: regexp-fuzzer:"))) + + def test_testcase_replay_of_a_clean_file_finds_nothing(self): + with tempfile.TemporaryDirectory() as out: + run.main( + ["--output_dir", out, "--no_of_files", "1", "--cases-per-file", "20"]) + p = subprocess.run([ + sys.executable, + os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "correctness_fuzzer.py"), "--ref", D8, "--test", D8, "--testcase", + os.path.join(out, "fuzz-0.js") + ], + capture_output=True, + text=True, + timeout=600) + self.assertEqual(0, p.returncode, p.stdout + p.stderr) + self.assertIn("20 case(s)", p.stdout) + def main(): ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("--d8", help="d8 binary; enables the execution tests") + ap.add_argument( + "--exhaustive", + action="store_true", + help="run full Python coverage sweeps and sample sizes") args, remaining = ap.parse_known_args() - global D8 + global D8, EXHAUSTIVE D8 = args.d8 + EXHAUSTIVE = args.exhaustive or D8 is not None if D8 is None: print("no --d8 given; skipping the tests that need one", file=sys.stderr) unittest.main(argv=[sys.argv[0]] + remaining) diff --git a/deps/v8/tools/regexp/correctness_fuzzer/harness.js b/deps/v8/tools/regexp/correctness_fuzzer/harness.js index e1f8daf51ce2..427f46629500 100644 --- a/deps/v8/tools/regexp/correctness_fuzzer/harness.js +++ b/deps/v8/tools/regexp/correctness_fuzzer/harness.js @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// d8 harness for the regexp correctness fuzzer. Reads a JSON array of -// [pattern, flags, subject, lastIndex] cases from the file named on the command -// line and prints one result line per case as "<index>\t<json>". The result is -// null, an error marker string ("ERR_CTOR" or "ERR_EXEC:<name>"), or -// {r:[captures], idx, li}. Construction and exec errors are captured rather -// than thrown so a single bad case does not abort the batch; both markers -// share the "ERR_" prefix so the driver can treat either as "no ground -// truth" with a single check. +// Runs [pattern, flags, subject, lastIndex] cases. Each result is +// "<index>\t<json>": null, "ERR_CTOR", "ERR_EXEC:<name>", or +// {r:[captures], idx, li}. Constructor and exec errors do not abort the batch. +// +// harness.py prepends `const cases = [...]` and strips these comments; local +// and ClusterFuzz drivers use the resulting script. // // lastIndex is set before exec and read back after: for a sticky or global // pattern it selects where the attempt starts and is updated by the result, so @@ -22,13 +20,11 @@ // reaches the second object through the compilation cache, so the second runs // warm along paths a single-shot run would never take. // -// Both objects are identical and start from the same lastIndex, so their -// results must agree whatever either configuration computes. A mismatch is a -// bug in that configuration by itself -- the one class a two-config diff -// cannot see, since it survives being wrong on both sides. -const cases = JSON.parse(read(arguments[0])); +// Foozzie uses the source tag as a key for failure clustering. The +// regexp-fuzzer namespace separates it from JavaScript fuzzer source keys. for (let i = 0; i < cases.length; i++) { const [pat, flags, sub, lastIndex] = cases[i]; + print("v8-foozzie source: regexp-fuzzer:" + sourceTag(pat, flags)); let out; try { const cold = execOnce(pat, flags, sub, lastIndex); @@ -61,3 +57,24 @@ function execOnce(pat, flags, sub, lastIndex) { if (m.groups !== undefined) r.g = m.groups; return r; } + +// A bounded tag that groups patterns by structure: the sorted flags, then +// the pattern reduced to its metacharacters and ASCII alphanumeric escapes +// (\d, \1, \p...), with literals dropped. Each escape counts as one token. +// Avoid regexp execution so tags do not depend on the engine being tested. +function sourceTag(pat, flags) { + const structural = "()[]{}|*+?^$.-&!=<>:,"; + const out = []; + for (let i = 0; i < pat.length && out.length < 40; i++) { + const c = pat[i]; + if (c === "\\") { + const nxt = pat[++i]; + // Keep ASCII alphanumeric escapes; other escaped characters are literals. + if ((nxt >= "0" && nxt <= "9") || (nxt >= "A" && nxt <= "Z") || + (nxt >= "a" && nxt <= "z")) out.push(c + nxt); + continue; + } + if (structural.includes(c)) out.push(c); + } + return Array.from(flags).sort().join("") + "/" + out.join(""); +} diff --git a/deps/v8/tools/regexp/correctness_fuzzer/harness.py b/deps/v8/tools/regexp/correctness_fuzzer/harness.py new file mode 100644 index 000000000000..9ba461d872a3 --- /dev/null +++ b/deps/v8/tools/regexp/correctness_fuzzer/harness.py @@ -0,0 +1,82 @@ +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Emit and parse self-contained regexp-fuzzer testcases. + +Local and ClusterFuzz drivers use this format: + + // <header lines, if any> + const cases = [ + ["<pattern>","<flags>","<subject>",<lastIndex>], + ... + ]; + <harness.js, comment-only and blank lines stripped> + +Each case occupies one line and ends with a comma for line-based minimization. +json.dumps escapes non-ASCII characters and lone surrogates. + +ClusterFuzz writes thousands of these files per fuzz task to a small +partition, so a case stores only what the engine needs: no JSON whitespace, +and the foozzie source tag is derived from the pattern by harness.js at run +time rather than stored next to each case. The harness is embedded without +its comments for the same reason. +""" + +import json +from pathlib import Path + +HARNESS_PATH = Path(__file__).resolve().parent / "harness.js" + +_CASES_OPEN = "const cases = [" +_CASES_CLOSE = "];" + + +def _compact_harness(): + """harness.js with comment-only and blank lines removed. + + Only whole lines starting with `//` are dropped, so a `//` inside a string + or regexp literal cannot be touched. harness.js has no block comments. + """ + lines = HARNESS_PATH.read_text(encoding="utf-8").splitlines() + return "\n".join( + l for l in lines if l.strip() and not l.lstrip().startswith("//")) + + +def emit_js(cases, header=()): + """Emit cases as a self-contained d8 script.""" + lines = ["// " + h for h in header] + lines.append(_CASES_OPEN) + for pattern, flags, subject, last_index in cases: + lines.append( + json.dumps([pattern, flags, subject, last_index], separators=(",", + ":")) + + ",") + lines.append(_CASES_CLOSE) + lines.append(_compact_harness()) + return "\n".join(lines) + + +def parse_testcase(text): + """Parse cases, accepting missing trailing commas and optional fields.""" + cases = [] + in_cases = False + for line in text.splitlines(): + stripped = line.strip() + if not in_cases: + in_cases = stripped == _CASES_OPEN + continue + if stripped == _CASES_CLOSE: + break + stripped = stripped.rstrip(",") + if not stripped: + continue + fields = json.loads(stripped) + pattern = fields[0] + flags = fields[1] if len(fields) > 1 else "" + subject = fields[2] if len(fields) > 2 else "" + last_index = fields[3] if len(fields) > 3 else 0 + cases.append([pattern, flags, subject, last_index]) + if not in_cases: + raise ValueError("no '%s' block found; not a file emitted by emit_js()" % + _CASES_OPEN) + return cases diff --git a/deps/v8/tools/regexp/correctness_fuzzer/package.sh b/deps/v8/tools/regexp/correctness_fuzzer/package.sh new file mode 100755 index 000000000000..8a139cff5440 --- /dev/null +++ b/deps/v8/tools/regexp/correctness_fuzzer/package.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Build the ClusterFuzz blackbox-fuzzer archive. +# +# Usage: package.sh [output.zip] (default: <v8>/out/regexp_fuzzer.zip) +# +# Archive root: +# run.py the fuzzer executable (--input_dir/--output_dir/ +# --no_of_files) +# harness.py harness.js grammar/ run.py dependencies +# foozzie_launcher.py js_fuzzer's launcher for existing correctness jobs +# +# Upload through ClusterFuzz's Fuzzers > Create/Edit page. Rebuild after +# changing grammar/ or the harness. + +set -eu + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +V8_ROOT="$(cd "$DIR/../../.." && pwd)" +OUT="${1:-$V8_ROOT/out/regexp_fuzzer.zip}" + +STAGE="$(mktemp -d)" +trap 'rm -rf "$STAGE"' EXIT + +cp "$DIR/run.py" "$DIR/harness.py" "$DIR/harness.js" "$STAGE/" +mkdir "$STAGE/grammar" +cp "$DIR"/grammar/*.py "$STAGE/grammar/" +cp "$V8_ROOT/tools/clusterfuzz/js_fuzzer/foozzie_launcher.py" "$STAGE/" +chmod +x "$STAGE/run.py" "$STAGE/foozzie_launcher.py" + +# Test the staged bundle outside the repository. On ClusterFuzz, APP_DIR is +# the build directory holding the foozzie experiment tables. +CHECK="$(mktemp -d)" +trap 'rm -rf "$STAGE" "$CHECK"' EXIT +(cd / && APP_DIR="$V8_ROOT/tools/clusterfuzz/foozzie" \ + PYTHONDONTWRITEBYTECODE=1 python3 "$STAGE/run.py" \ + --input_dir "$CHECK" --output_dir "$CHECK" --no_of_files 2 >/dev/null) +test -s "$CHECK/fuzz-0.js" && test -s "$CHECK/fuzz-1.js" +test -s "$CHECK/flags-0.js" && test -s "$CHECK/flags-1.js" + +mkdir -p "$(dirname "$OUT")" +rm -f "$OUT" +# Exclude extra file attributes from the archive. +(cd "$STAGE" && zip -q -r -X "$OUT" .) +echo "wrote $OUT" +unzip -l "$OUT" diff --git a/deps/v8/tools/regexp/correctness_fuzzer/run.py b/deps/v8/tools/regexp/correctness_fuzzer/run.py new file mode 100755 index 000000000000..238b3c6b8d6c --- /dev/null +++ b/deps/v8/tools/regexp/correctness_fuzzer/run.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Generate regexp-fuzzer inputs for ClusterFuzz. + +Blackbox-fuzzer contract: + + run.py --input_dir <corpus> --output_dir <dir> --no_of_files <n> + +For each fuzz-N.js, also writes flags-N.js with the v8_foozzie.py flags for +that testcase: random seed, first and second config, second d8 and extra +flags. These are drawn from v8_fuzz_experiments_regexp.json and +v8_fuzz_flags_regexp.json, read +from the V8 build directory ($APP_DIR on ClusterFuzz; the foozzie source +directory otherwise). + +Each output file is self-contained and records its seed and grammar profile. +The input corpus is unused. +""" + +import argparse +import json +import os +import random +import sys + +from pathlib import Path + +import grammar +import harness + +# 500 cases amortize d8 startup while keeping normal simulator runs below +# foozzie's 3s timeout. +DEFAULT_CASES_PER_FILE = 500 + +EXPERIMENTS_FILE = "v8_fuzz_experiments_regexp.json" +ADDITIONAL_FLAGS_FILE = "v8_fuzz_flags_regexp.json" + +# Where the foozzie tables live in a V8 checkout. Resolved from this file's +# location (tools/regexp/correctness_fuzzer/run.py), not the working +# directory, so local runs need no APP_DIR. Absent in the ClusterFuzz bundle. +TOOLS_DIR = Path(__file__).resolve().parent.parent.parent +FOOZZIE_SOURCE_DIR = TOOLS_DIR / "clusterfuzz" / "foozzie" + + +def build_dir(): + """Directory holding the foozzie tables bundled with d8. + + ClusterFuzz sets APP_DIR to the build directory, as js_fuzzer expects. Local + runs from a checkout fall back to the tables' source directory. + """ + if "APP_DIR" in os.environ: + return Path(os.environ["APP_DIR"]) + if (FOOZZIE_SOURCE_DIR / EXPERIMENTS_FILE).is_file(): + return FOOZZIE_SOURCE_DIR + sys.exit("run.py: set APP_DIR to the d8 build directory (not running from " + "a V8 checkout, so there is no fallback)") + + +def load_json_from_build(name): + """Load a foozzie config table bundled with d8.""" + with (build_dir() / name).open(encoding="utf-8") as f: + return json.load(f) + + +def choose_foozzie_flags(rng, experiments, additional_flags, random_seed): + """Randomly choose v8_foozzie.py flags from the experiment tables. + + Same distribution as v8_fuzz_config.Config.choose_foozzie_flags and + js_fuzzer's chooseRandomFlags. + """ + # Pick one experiment row, weighted by its probability column. + weights = [row[0] for row in experiments] + _, first_config, second_config, second_d8 = rng.choices( + experiments, weights=weights)[0] + flags = [ + "--random-seed=" + str(random_seed), + "--first-config=" + first_config, + "--second-config=" + second_config, + "--second-d8=" + second_d8, + ] + + # Add additional flags to second config based on experiment percentages. + for p, extra in additional_flags: + if rng.random() < p: + flags += ["--second-config-extra-flags=" + f for f in extra.split()] + return flags + + +def generate_file(seed, profile, max_depth, cases_per_file): + """Generate a deterministic testcase.""" + rng = random.Random(seed) + weights = grammar.parse_weights(profile, None) + cases = [ + grammar.gen_case(rng, max_depth, weights) for _ in range(cases_per_file) + ] + header = [ + "Generated by tools/regexp/correctness_fuzzer/run.py", + "seed=%d profile=%s max_depth=%d" % (seed, profile, max_depth), + "Replay: correctness_fuzzer.py --ref <d8> --test <d8:--flags> " + "--testcase <this file>", + ] + return harness.emit_js(cases, header) + + +def main(argv=None): + ap = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("--input_dir", help="corpus directory; accepted and unused") + ap.add_argument("--output_dir", required=True) + ap.add_argument("--no_of_files", type=int, required=True) + ap.add_argument( + "--cases-per-file", + type=int, + default=DEFAULT_CASES_PER_FILE, + help="cases per generated file (default %(default)s)") + ap.add_argument( + "--max-depth", + type=int, + default=5, + help="derivation depth budget, as in correctness_fuzzer.py") + args = ap.parse_args(argv) + + experiments = load_json_from_build(EXPERIMENTS_FILE) + additional_flags = load_json_from_build(ADDITIONAL_FLAGS_FILE) + + os.makedirs(args.output_dir, exist_ok=True) + # Draw independent seeds for concurrent generator instances. + sysrand = random.SystemRandom() + # Profiles change rule weights without changing reachability. + profiles = sorted(grammar.PROFILES) + for i in range(args.no_of_files): + seed = sysrand.randrange(2**32) + random_seed = sysrand.randrange(1, 2**31) + profile = profiles[sysrand.randrange(len(profiles))] + text = generate_file(seed, profile, args.max_depth, args.cases_per_file) + path = os.path.join(args.output_dir, "fuzz-%d.js" % i) + with open(path, "w", encoding="utf-8") as f: + f.write(text) + flags = choose_foozzie_flags(sysrand, experiments, additional_flags, + random_seed) + path = os.path.join(args.output_dir, "flags-%d.js" % i) + with open(path, "w", encoding="utf-8") as f: + f.write(" ".join(flags)) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deps/v8/tools/regexp/correctness_fuzzer/run_locally_against_foozzie.py b/deps/v8/tools/regexp/correctness_fuzzer/run_locally_against_foozzie.py new file mode 100755 index 000000000000..20d637f3f4c9 --- /dev/null +++ b/deps/v8/tools/regexp/correctness_fuzzer/run_locally_against_foozzie.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Generate testcases and run them through foozzie locally. + +Configuration-specific stack or backtrack limits are reported as differences. +correctness_fuzzer.py skips them when the reference has no result. + + tools/regexp/correctness_fuzzer/run_locally_against_foozzie.py \\ + --d8 out/x64.release/d8 --files 50 + +Foozzie requires v8_build_config.json next to d8. Correctness-fuzzer builds +also contain cross-architecture d8 binaries for --second-d8. --keep retains +reports and timeouts for correctness_fuzzer.py --testcase. +""" + +import argparse +import json +import os +import shutil +import subprocess +import sys +import tempfile + +DIR = os.path.dirname(os.path.realpath(__file__)) +FOOZZIE_DIR = os.path.join(DIR, "..", "..", "clusterfuzz", "foozzie") +FOOZZIE = os.path.join(FOOZZIE_DIR, "v8_foozzie.py") + +# Exclude default pairs that require a simulator binary. +with open(os.path.join(FOOZZIE_DIR, "v8_fuzz_experiments_regexp.json")) as f: + DEFAULT_PAIRS = sorted( + set("%s:%s" % (first, second) + for _, first, second, second_d8 in json.load(f) + if second_d8 == "d8")) + + +def main(): + ap = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("--d8", required=True, help="d8 for both sides") + ap.add_argument( + "--second-d8", help="d8 for the second side, e.g. a cross-arch build") + ap.add_argument("--files", type=int, default=20, help="files to generate") + ap.add_argument( + "--pair", + action="append", + metavar="FIRST:SECOND", + help="foozzie config pair to compare; repeatable " + "(default: %s)" % " ".join(DEFAULT_PAIRS)) + ap.add_argument("--cases-per-file", type=int) + ap.add_argument( + "--keep", + metavar="DIR", + help="copy files foozzie reported on or timed out on into DIR " + "(default: a temp dir)") + args = ap.parse_args() + # Foozzie resolves relative d8 paths against its own directory. + args.d8 = os.path.abspath(args.d8) + if args.second_d8: + args.second_d8 = os.path.abspath(args.second_d8) + + pairs = [p.split(":", 1) for p in (args.pair or DEFAULT_PAIRS)] + keep = args.keep + + with tempfile.TemporaryDirectory(prefix="regexp_fuzz_") as gen: + cmd = [ + sys.executable, + os.path.join(DIR, "run.py"), "--input_dir", gen, "--output_dir", gen, + "--no_of_files", + str(args.files) + ] + if args.cases_per_file: + cmd += ["--cases-per-file", str(args.cases_per_file)] + subprocess.run(cmd, check=True) + + failures = timeouts = 0 + for i in range(args.files): + testcase = os.path.join(gen, "fuzz-%d.js" % i) + for first, second in pairs: + cmd = [ + sys.executable, FOOZZIE, "--first-config", first, "--second-config", + second, "--first-d8", args.d8, "--second-d8", args.second_d8 or + args.d8, testcase + ] + p = subprocess.run(cmd, capture_output=True, text=True) + # Foozzie returns success on timeout. Retain and count the testcase. + timed_out = "T-I-M-E-O-U-T" in p.stdout + if p.returncode == 0 and not timed_out: + continue + if timed_out: + timeouts += 1 + else: + failures += 1 + if keep is None: + keep = tempfile.mkdtemp(prefix="regexp_foozzie_") + os.makedirs(keep, exist_ok=True) + dest = os.path.join(keep, "fuzz-%d-%s-%s" % (i, first, second)) + shutil.copy(testcase, dest + ".js") + with open(dest + ".txt", "w") as f: + f.write(p.stdout + p.stderr) + head = [l for l in p.stdout.splitlines() if l.startswith("# V8 ")] + print("fuzz-%d %s vs %s: %s" % + (i, first, second, "timeout" if timed_out else "rc=%d %s" % + (p.returncode, " | ".join(head[:3])))) + sys.stdout.flush() + + print("done: %d files x %d pairs, %d foozzie report(s), %d timeout(s)%s" % + (args.files, len(pairs), failures, timeouts, + (", kept under %s" % keep) if keep and (failures or timeouts) else "")) + return 1 if failures else 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deps/v8/tools/release/common_includes.py b/deps/v8/tools/release/common_includes.py index 492a375f22ca..98833bece3a6 100644 --- a/deps/v8/tools/release/common_includes.py +++ b/deps/v8/tools/release/common_includes.py @@ -665,12 +665,7 @@ def RunStep(self): print("Using account %s for review." % self._options.reviewer) reviewer = self._options.reviewer - tbr_reviewer = None - if self._options.tbr_reviewer: - print("Using account %s for TBR review." % self._options.tbr_reviewer) - tbr_reviewer = self._options.tbr_reviewer - - if not reviewer and not tbr_reviewer: + if not reviewer: print( "Please enter the email address of a V8 reviewer for your patch: ", end=' ') @@ -678,8 +673,7 @@ def RunStep(self): reviewer = self.ReadLine() self.GitUpload(reviewer, self._options.force_upload, - bypass_hooks=self._options.bypass_upload_hooks, - tbr_reviewer=tbr_reviewer) + bypass_hooks=self._options.bypass_upload_hooks) def MakeStep(step_class=Step, number=0, state=None, config=None, @@ -736,8 +730,6 @@ def MakeOptions(self, args=None): help="File to write results summary to.") parser.add_argument("-r", "--reviewer", default="", help="The account name to be used for reviews.") - parser.add_argument("--tbr-reviewer", "--tbr", default="", - help="The account name to be used for TBR reviews.") parser.add_argument("-s", "--step", help="Specify the step where to start work. Default: 0.", default=0, type=int) diff --git a/deps/v8/tools/release/git_recipes.py b/deps/v8/tools/release/git_recipes.py index c574bb2475c8..94a54f84ede5 100644 --- a/deps/v8/tools/release/git_recipes.py +++ b/deps/v8/tools/release/git_recipes.py @@ -207,13 +207,10 @@ def GitApplyPatch(self, patch_file, reverse=False, **kwargs): def GitUpload(self, reviewer="", force=False, cq=False, cq_dry_run=False, set_bot_commit=False, bypass_hooks=False, - cc="", tbr_reviewer="", no_autocc=False, message_file=None, - **kwargs): + cc="", no_autocc=False, message_file=None, **kwargs): args = ["cl upload --send-mail"] if reviewer: args += ["-r", Quoted(reviewer)] - if tbr_reviewer: - args += ["--tbrs", Quoted(tbr_reviewer)] if force: args.append("-f") if cq: diff --git a/deps/v8/tools/testrunner/base_runner.py b/deps/v8/tools/testrunner/base_runner.py index fc6f747dc75e..de411b31b61a 100644 --- a/deps/v8/tools/testrunner/base_runner.py +++ b/deps/v8/tools/testrunner/base_runner.py @@ -337,6 +337,11 @@ def _add_parser_default_options(self, parser): parser.add_option("--no-harness", "--noharness", default=False, action="store_true", help="Run without test harness of a given suite") + parser.add_option( + "--no-fork-server", + default=False, + action="store_true", + help="Do not use fork server for running v8_unittests") parser.add_option("--random-seed", default=0, type=int, help="Default seed for initializing random generator") parser.add_option("--run-skipped", help="Also run skipped tests.", @@ -772,6 +777,7 @@ def _create_test_config(self): timeout=timeout, verbose=self.options.verbose, regenerate_expected_files=self.options.regenerate_expected_files, + no_fork_server=self.options.no_fork_server, ) # TODO(majeski): remove options & args parameters diff --git a/deps/v8/tools/testrunner/local/command.py b/deps/v8/tools/testrunner/local/command.py index 9f2c637eb5a1..93803e709486 100644 --- a/deps/v8/tools/testrunner/local/command.py +++ b/deps/v8/tools/testrunner/local/command.py @@ -5,6 +5,7 @@ from contextlib import contextmanager from pathlib import Path +import atexit import logging import os import signal @@ -99,6 +100,7 @@ def __init__(self, shell, args=None, cmd_prefix=None, timeout=60, env=None, self.env = env or {} self.verbose = verbose self.handle_sigterm = handle_sigterm + self.use_fork_server = bool(getattr(test_case, 'use_fork_server', False)) if log_process_stats: self.process_logger = self.get_process_logger() @@ -210,7 +212,199 @@ def get_process_logger(self): return PROCESS_LOGGER +# VariantProc cycles through all active variants per test, so keep capacity +# above the 8 supported unittests variants (standard + ADDITIONAL_VARIANTS in +# test/unittests/testcfg.py) to avoid LRU thrashing. Each cached server is an +# idle, initialized v8_unittests process, i.e. up to 16 per worker. +_FORK_SERVERS = {} +_MAX_FORK_SERVERS = 16 +_FORK_SERVER_DISABLED = False + + +def close_fork_servers(): + for server in list(_FORK_SERVERS.values()): + server.close() + _FORK_SERVERS.clear() + + +# Used by SingleThreadedExecutionPool (in-process execution); multiprocessing +# workers exit via os._exit(0) and rely on stdin EOF for server shutdown. +atexit.register(close_fork_servers) + + +class _ForkServer(object): + """Persistent fork-server process speaking the line-framed pipe protocol: + Request (stdin): "<gtest_filter>\\n" + Response (stdout): "RES <exit_code> <stdout_len> <stderr_len>\\n" + followed by <stdout_len> stdout bytes and + <stderr_len> stderr bytes. + """ + + def __init__(self, shell, base_args, env): + self.ok = False + self.process = subprocess.Popen( + args=[str(shell), '--fork-server'] + list(base_args), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + # Inherit stderr so that server-side diagnostics (flag errors, CHECK + # failures, sanitizer reports) remain visible. + stderr=None, + env=env, + start_new_session=True, + ) + + def read_exact(self, n): + chunks = [] + remaining = n + while remaining > 0: + chunk = self.process.stdout.read(remaining) + if not chunk: + raise EOFError('Unexpected EOF from fork server') + chunks.append(chunk) + remaining -= len(chunk) + return b''.join(chunks) + + def close(self): + if not self.process: + return + proc = self.process + self.process = None + try: + if proc.stdin: + proc.stdin.close() + except OSError: + pass + try: + proc.wait(timeout=1.0) + except subprocess.TimeoutExpired: + terminate_process_group_posix(proc) + try: + proc.wait(timeout=1.0) + except subprocess.TimeoutExpired: + pass + try: + if proc.stdout: + proc.stdout.close() + except OSError: + pass + + class PosixCommand(DesktopCommand): + + def execute(self): + if (self.use_fork_server and not self.cmd_prefix and + not _FORK_SERVER_DISABLED): + # Only a single --gtest_filter is supported. With several (e.g. via + # --extra-flags), gtest's last-one-wins semantics would be hard to + # replicate, so fall back to direct execution. + filter_indices = [ + i for i, arg in enumerate(self.args) + if arg.startswith('--gtest_filter=') + ] + if len(filter_indices) == 1: + i = filter_indices[0] + test_filter = self.args[i][len('--gtest_filter='):] + if test_filter: + base_args = self.args[:i] + self.args[i + 1:] + return self._execute_with_fork_server(test_filter, base_args) + return super().execute() + + def _execute_with_fork_server(self, test_filter, base_args): + if self.verbose: + print('# %s (fork-server)' % self) + + env = self._get_env() + key = (str(self.shell), tuple(base_args), tuple(sorted(env.items()))) + server = _FORK_SERVERS.pop(key, None) + if (server is None or server.process is None or + server.process.poll() is not None): + if server is not None: + server.close() + while len(_FORK_SERVERS) >= _MAX_FORK_SERVERS: + oldest_key = next(iter(_FORK_SERVERS)) + _FORK_SERVERS.pop(oldest_key).close() + try: + server = _ForkServer(self.shell, base_args, env) + except OSError as e: + self._disable_fork_server(e) + return super().execute() + _FORK_SERVERS[key] = server + + proc = server.process + pid = proc.pid + timeout_occured = [False] + completed = False + error = None + with handle_sigterm(proc, self._abort, self.handle_sigterm): + timer = threading.Timer(self.timeout, self._abort, + [proc, timeout_occured]) + timer.start() + start_time = time.time() + try: + proc.stdin.write((test_filter + '\n').encode('utf-8')) + proc.stdin.flush() + res_line = proc.stdout.readline() + if not res_line or not res_line.startswith(b'RES '): + raise EOFError(f'Expected RES from fork server, got {res_line!r}') + parts = res_line.split() + if len(parts) != 4: + raise ValueError(f'Malformed RES header: {res_line!r}') + returncode = int(parts[1]) + stdout = server.read_exact(int(parts[2])) + stderr = server.read_exact(int(parts[3])) + server.ok = True + completed = True + except Exception as e: + error = e + finally: + end_time = time.time() + timer.cancel() + if not completed: + # Also covers BaseException (e.g. KeyboardInterrupt): never leave a + # server with a half-read response in the cache. + _FORK_SERVERS.pop(key, None) + server.close() + + if not completed: + if timeout_occured[0]: + return output.Output( + proc.returncode or -signal.SIGKILL, + True, + '', + '', + pid, + start_time, + end_time, + stats=None, + ) + if not server.ok: + self._disable_fork_server(error) + else: + logging.warning( + 'Fork server failed for %s (%r); falling back to direct execution', + self, error) + return super().execute() + + return output.Output( + returncode, + timeout_occured[0], + stdout.decode('utf-8', 'replace'), + stderr.decode('utf-8', 'replace'), + pid, + start_time, + end_time, + stats=None, + ) + + def _disable_fork_server(self, error): + global _FORK_SERVER_DISABLED + _FORK_SERVER_DISABLED = True + close_fork_servers() + logging.warning( + 'Fork server failed on first request for %s (%r); disabling fork ' + 'server in this worker and falling back to direct execution', self, + error) + # TODO(machenbach): Use base process start without shell once # https://crbug.com/v8/8889 is resolved. def _start_process(self): @@ -220,14 +414,14 @@ def wrapped(arg): return arg try: return subprocess.Popen( - args=' '.join(map(wrapped, self._get_popen_args())), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env=self._get_env(), - shell=True, - # Make the new shell create its own process group. This allows to kill - # all spawned processes reliably (https://crbug.com/v8/8292). - preexec_fn=os.setsid, + args=' '.join(map(wrapped, self._get_popen_args())), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=self._get_env(), + shell=True, + # Make the new shell create its own process group. This allows to kill + # all spawned processes reliably (https://crbug.com/v8/8292). + start_new_session=True, ) except Exception as e: sys.stderr.write('Error executing: %s\n' % self) @@ -279,7 +473,7 @@ def _start_process(self): shell=True, # Make the new shell create its own process group. This allows to kill # all spawned processes reliably (https://crbug.com/v8/8292). - preexec_fn=os.setsid, + start_new_session=True, ) except Exception as e: sys.stderr.write('Error executing: %s\n' % self) diff --git a/deps/v8/tools/testrunner/local/command_test.py b/deps/v8/tools/testrunner/local/command_test.py new file mode 100644 index 000000000000..10c81e3fb5b9 --- /dev/null +++ b/deps/v8/tools/testrunner/local/command_test.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python3 +# Copyright 2026 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import signal +import stat +import sys +import tempfile +import threading +import time +import unittest + +# Needed because the test runner contains relative imports. +TOOLS_PATH = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +sys.path.append(TOOLS_PATH) + +from testrunner.local import command +from testrunner.local.pool import AbortException + +FAKE_SERVER_SCRIPT = """#!{python} +import sys +import time + +if len(sys.argv) < 2 or sys.argv[1] != '--fork-server': + print('DIRECT:' + ' '.join(sys.argv[1:]), end='') + sys.stderr.write('DIRECT_ERR') + sys.exit(0) + +if '--fail-startup' in sys.argv: + sys.exit(1) + +for line in sys.stdin: + filt = line.strip() + if filt == 'hang': + time.sleep(30) + elif filt == 'short_res': + sys.stdout.buffer.write(b'RES 0\\n') + sys.stdout.buffer.flush() + elif filt == 'garbage': + sys.stdout.buffer.write(b'NOT_A_RES\\n') + sys.stdout.buffer.flush() + elif filt == 'segv': + sys.stdout.buffer.write(b'RES -11 0 4\\nSEGV') + sys.stdout.buffer.flush() + elif filt == 'abrt': + sys.stdout.buffer.write(b'RES -6 0 4\\nABRT') + sys.stdout.buffer.flush() + else: + out = ('OUT:' + filt).encode('utf-8') + err = ('ERR:' + filt).encode('utf-8') + header = ('RES 0 %d %d\\n' % (len(out), len(err))).encode('utf-8') + sys.stdout.buffer.write(header + out + err) + sys.stdout.buffer.flush() +""" + + +class _DummyTestCase(object): + + def __init__(self, use_fork_server=True): + self.use_fork_server = use_fork_server + + +@unittest.skipIf(sys.platform == 'win32', 'POSIX fork server only') +class ForkServerCommandTest(unittest.TestCase): + + def setUp(self): + command.close_fork_servers() + command._FORK_SERVER_DISABLED = False + self._tmp = tempfile.NamedTemporaryFile( + mode='w', suffix='.py', delete=False) + self._tmp.write(FAKE_SERVER_SCRIPT.format(python=sys.executable)) + self._tmp.close() + os.chmod(self._tmp.name, stat.S_IRWXU) + self.shell = self._tmp.name + + def tearDown(self): + command.close_fork_servers() + command._FORK_SERVER_DISABLED = False + if os.path.exists(self._tmp.name): + os.unlink(self._tmp.name) + + def _make_cmd(self, + test_filter='Suite.Test', + extra_args=None, + timeout=5, + use_fork_server=True, + cmd_prefix=None, + handle_sigterm=False): + args = list(extra_args or []) + [f'--gtest_filter={test_filter}'] + return command.PosixCommand( + shell=self.shell, + args=args, + cmd_prefix=cmd_prefix, + timeout=timeout, + test_case=_DummyTestCase(use_fork_server=use_fork_server), + handle_sigterm=handle_sigterm, + ) + + def testSuccessAndReuse(self): + out1 = self._make_cmd('Suite.One').execute() + self.assertEqual(0, out1.exit_code) + self.assertFalse(out1.timed_out) + self.assertEqual('OUT:Suite.One', out1.stdout) + self.assertEqual('ERR:Suite.One', out1.stderr) + self.assertEqual(1, len(command._FORK_SERVERS)) + + out2 = self._make_cmd('Suite.Two').execute() + self.assertEqual(0, out2.exit_code) + self.assertEqual('OUT:Suite.Two', out2.stdout) + self.assertEqual('ERR:Suite.Two', out2.stderr) + self.assertEqual(out1.pid, out2.pid) + self.assertEqual(1, len(command._FORK_SERVERS)) + + def testSignalExitCodes(self): + segv = self._make_cmd('segv').execute() + self.assertEqual(-11, segv.exit_code) + self.assertTrue(segv.HasCrashed()) + + abrt = self._make_cmd('abrt').execute() + self.assertEqual(-6, abrt.exit_code) + self.assertFalse(abrt.HasCrashed()) + + def testMalformedHeaderFallsBackWithoutDisabling(self): + # First request succeeds so server.ok becomes True. + out1 = self._make_cmd('Suite.Ok').execute() + self.assertEqual('OUT:Suite.Ok', out1.stdout) + + # Truncated RES header ("RES 0\n") triggers fallback to direct mode, + # evicts the broken server, and leaves fork server enabled for next test. + out2 = self._make_cmd('short_res').execute() + self.assertEqual(0, out2.exit_code) + self.assertIn('DIRECT:', out2.stdout) + self.assertFalse(command._FORK_SERVER_DISABLED) + self.assertEqual(0, len(command._FORK_SERVERS)) + + out3 = self._make_cmd('Suite.Recovered').execute() + self.assertEqual('OUT:Suite.Recovered', out3.stdout) + self.assertNotEqual(out1.pid, out3.pid) + + def testNonResHeaderFallsBackWithoutDisabling(self): + out1 = self._make_cmd('Suite.Ok').execute() + self.assertEqual('OUT:Suite.Ok', out1.stdout) + + # A line that is not a RES header at all takes the same fallback path as + # a truncated one: direct execution, eviction, fork server stays enabled. + out2 = self._make_cmd('garbage').execute() + self.assertEqual(0, out2.exit_code) + self.assertIn('DIRECT:', out2.stdout) + self.assertFalse(command._FORK_SERVER_DISABLED) + self.assertEqual(0, len(command._FORK_SERVERS)) + + def testStartupFailureStickyDisable(self): + out1 = self._make_cmd('Suite.One', extra_args=['--fail-startup']).execute() + self.assertIn('DIRECT:', out1.stdout) + self.assertTrue(command._FORK_SERVER_DISABLED) + self.assertEqual(0, len(command._FORK_SERVERS)) + + # Subsequent commands bypass fork server immediately. + out2 = self._make_cmd('Suite.Two').execute() + self.assertIn('DIRECT:', out2.stdout) + + def testTimeoutEvictsAndRespawns(self): + out1 = self._make_cmd('hang', timeout=0.2).execute() + self.assertTrue(out1.timed_out) + self.assertEqual(0, len(command._FORK_SERVERS)) + + out2 = self._make_cmd('Suite.AfterTimeout').execute() + self.assertFalse(out2.timed_out) + self.assertEqual('OUT:Suite.AfterTimeout', out2.stdout) + + def testLruCacheEviction(self): + procs = [] + for i in range(command._MAX_FORK_SERVERS + 2): + out = self._make_cmd('Suite.Test', extra_args=[f'--flag={i}']).execute() + self.assertEqual('OUT:Suite.Test', out.stdout) + # Capture the Popen object now; _ForkServer.close() drops its reference. + server = command._FORK_SERVERS[next(reversed(command._FORK_SERVERS))] + self.assertEqual(out.pid, server.process.pid) + procs.append(server.process) + self.assertLessEqual( + len(command._FORK_SERVERS), command._MAX_FORK_SERVERS) + + # First two servers should have been closed and reaped, the rest is alive. + for proc in procs[:2]: + self.assertIsNotNone(proc.returncode) + for proc in procs[2:]: + self.assertIsNone(proc.poll()) + + def testDirectModeWhenDisabledOrPrefixed(self): + out1 = self._make_cmd('Suite.One', use_fork_server=False).execute() + self.assertIn('DIRECT:', out1.stdout) + self.assertEqual(0, len(command._FORK_SERVERS)) + + out2 = self._make_cmd('Suite.Two', cmd_prefix=[sys.executable]).execute() + self.assertIn('DIRECT:', out2.stdout) + self.assertEqual(0, len(command._FORK_SERVERS)) + + def testDirectModeWithMultipleFilters(self): + # E.g. an additional --gtest_filter passed via --extra-flags. gtest's + # last-one-wins semantics are left to direct execution. + out = self._make_cmd( + 'Suite.Two', extra_args=['--gtest_filter=Suite.One']).execute() + self.assertIn('DIRECT:', out.stdout) + self.assertIn('--gtest_filter=Suite.One --gtest_filter=Suite.Two', + out.stdout) + self.assertEqual(0, len(command._FORK_SERVERS)) + self.assertFalse(command._FORK_SERVER_DISABLED) + + def testSpawnErrorStickyDisable(self): + # A non-existent shell makes Popen raise OSError when spawning the server. + # This must not propagate but disable the fork server and fall back to + # direct execution (which reports the shell's error as a regular result). + self.shell = os.path.join(os.path.dirname(self.shell), 'does_not_exist') + out1 = self._make_cmd('Suite.One').execute() + self.assertNotEqual(0, out1.exit_code) + self.assertTrue(command._FORK_SERVER_DISABLED) + self.assertEqual(0, len(command._FORK_SERVERS)) + + out2 = self._make_cmd('Suite.Two').execute() + self.assertNotEqual(0, out2.exit_code) + self.assertEqual(0, len(command._FORK_SERVERS)) + + def testSigtermRaisesAbortException(self): + # The real signal.signal lives in the signal (or _signal) module; a no-op + # lambda installed by command.setup_testing() would leave SIGTERM at + # SIG_DFL and kill the test process. + if getattr(signal.signal, '__module__', None) not in ('signal', '_signal'): + self.skipTest('signal.signal is monkey-patched (command.setup_testing)') + + # Safety net: should SIGTERM arrive before handle_sigterm installed its + # handler, it must not hit SIG_DFL and kill the test process. + previous = signal.signal(signal.SIGTERM, lambda *_: None) + self.addCleanup(signal.signal, signal.SIGTERM, previous) + + cmd = self._make_cmd('hang', timeout=10, handle_sigterm=True) + main_thread_id = threading.main_thread().ident + + def send_sigterm(): + # Wait until the server is registered, i.e. the request is in flight. + while not command._FORK_SERVERS: + time.sleep(0.01) + time.sleep(0.05) + # pthread_kill is unaffected by pool.setup_testing() patching os.kill. + signal.pthread_kill(main_thread_id, signal.SIGTERM) + + t = threading.Thread(target=send_sigterm) + t.start() + try: + with self.assertRaises(AbortException): + cmd.execute() + finally: + t.join() + self.assertEqual(0, len(command._FORK_SERVERS)) + + +if __name__ == '__main__': + unittest.main() diff --git a/deps/v8/tools/testrunner/local/variants.py b/deps/v8/tools/testrunner/local/variants.py index 653dcf6eef04..0134cba908d5 100644 --- a/deps/v8/tools/testrunner/local/variants.py +++ b/deps/v8/tools/testrunner/local/variants.py @@ -165,6 +165,7 @@ "--wasm-random-rescheduling" ], "validate_generated_code": ["--validate-generated-code"], + "ecma402_icu4x_plural_rules": ["--ecma402-icu4x-plural-rules"], # Google3 variant. "google3": [], } @@ -378,7 +379,6 @@ def negate_flag(flag): "single_generation": [ "--shared-strings", "--shared-heap", - "--harmony-struct", "--wasm-shared", ], "!slow_dchecks": ["--enable-slow-asserts"], diff --git a/deps/v8/tools/testrunner/objects/testcase.py b/deps/v8/tools/testrunner/objects/testcase.py index 675016eb8e6b..053a603e88d2 100644 --- a/deps/v8/tools/testrunner/objects/testcase.py +++ b/deps/v8/tools/testrunner/objects/testcase.py @@ -94,6 +94,7 @@ def read_file(file): return f.read() class TestCase(object): + use_fork_server = False def __init__(self, suite, path, name): self.suite = suite diff --git a/deps/v8/tools/testrunner/outproc/base.py b/deps/v8/tools/testrunner/outproc/base.py index eb38d883974d..922ecd4587af 100644 --- a/deps/v8/tools/testrunner/outproc/base.py +++ b/deps/v8/tools/testrunner/outproc/base.py @@ -211,16 +211,17 @@ def _ignore_actual_line(self, line): """ if not line: return True - return (line.startswith('==') or - line.startswith('**') or - line.startswith('ANDROID') or - line.startswith('###') or - # Android linker warning. - line.startswith('WARNING: linker:') or - # We don't differentiate release/debug when passing flags. That - # might produce some warnings for debug flags missing in release. - line.startswith('Warning: unknown flag') or - line == 'Try --help for options') + return ( + line.startswith('==') or line.startswith('**') or + line.startswith('ANDROID') or line.startswith('###') or + # Android linker warning. + line.startswith('WARNING: linker:') or + # Testing on Android devices mixes stderr into stdout. + line.startswith('V8 is running with') or + # We don't differentiate release/debug when passing flags. That + # might produce some warnings for debug flags missing in release. + line.startswith('Warning: unknown flag') or + line == 'Try --help for options') def _ignore_expected_line(self, line): return not line diff --git a/deps/v8/tools/testrunner/test_config.py b/deps/v8/tools/testrunner/test_config.py index 497a04ed9bdf..37bb75c7b04b 100644 --- a/deps/v8/tools/testrunner/test_config.py +++ b/deps/v8/tools/testrunner/test_config.py @@ -24,7 +24,8 @@ def __init__(self, target_os, timeout, verbose, - regenerate_expected_files=False): + regenerate_expected_files=False, + no_fork_server=False): self.command_prefix = command_prefix self.extra_flags = extra_flags self.extra_d8_flags = extra_d8_flags @@ -44,3 +45,4 @@ def __init__(self, self.timeout = timeout self.verbose = verbose self.regenerate_expected_files = regenerate_expected_files + self.no_fork_server = no_fork_server diff --git a/deps/v8/tools/testrunner/testproc/fuzzer.py b/deps/v8/tools/testrunner/testproc/fuzzer.py index 5380fbf552b5..eddc2ced9af8 100644 --- a/deps/v8/tools/testrunner/testproc/fuzzer.py +++ b/deps/v8/tools/testrunner/testproc/fuzzer.py @@ -60,7 +60,6 @@ (0.1, '--regexp-tier-up-ticks=100'), (0.1, '--no-regexp-quick-check'), (0.1, '--no-regexp-unroll'), - (0.1, '--shared-string-table'), (0.1, '--shared-heap'), (0.1, '--stress-background-compile'), (0.2, '--stress-flush-code'), diff --git a/deps/v8/tools/turbolizer/README.md b/deps/v8/tools/turbolizer/README.md index c1f42b9ffa7a..8c63d6670d99 100644 --- a/deps/v8/tools/turbolizer/README.md +++ b/deps/v8/tools/turbolizer/README.md @@ -17,7 +17,14 @@ Turbolizer is build using npm: Afterwards, turbolizer can be hosted locally by starting a web server that serve the contents of the turbolizer directory, e.g.: - python3 -m http.server 8000 + npm run dev-server + +For convenience, files can be loaded via the command line: + + ./cli.js path/to/turbo-foo-1.json + # or... + npm install -g # install globally + turbolizer path/to/turbo-foo-1.json To deploy to a directory that can be hosted the script `deploy` can be used. The following command will deploy to the directory /www/turbolizer: diff --git a/deps/v8/tools/turbolizer/cli.js b/deps/v8/tools/turbolizer/cli.js new file mode 100755 index 000000000000..2d181495ab50 --- /dev/null +++ b/deps/v8/tools/turbolizer/cli.js @@ -0,0 +1,128 @@ +#!/usr/bin/env node +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import { spawn } from "node:child_process"; +import { readFile, stat } from "node:fs/promises"; +import { createServer } from "node:http"; +import { basename, resolve } from "node:path"; +import { parseArgs } from "node:util"; + +const TURBOLIZER_URL = "https://v8.github.io/tools/head/turbolizer"; + +function usage() { + console.error( + "Usage: turbolizer [-n|--no-open] [--url URL] [--port PORT] " + + "path/to/turbo.json [path/to/another.json ...]"); +} + +async function parseCommandLineArgs() { + const { values, positionals } = parseArgs({ + options: { + help: { + type: "boolean", + short: "h" + }, + "no-open": { + type: "boolean", + short: "n" + }, + url: { + type: "string" + }, + port: { + type: "string" + } + }, + allowPositionals: true + }); + + if (values.help) { + usage(); + process.exit(0); + } + + if (positionals.length === 0) { + usage(); + process.exit(1); + } + + const jsonFiles = []; + for (const arg of positionals) { + const path = resolve(arg); + if (!(await stat(path)).isFile()) { + throw new Error(`${arg} is not a file`); + } + jsonFiles.push(path); + } + + return { + jsonFiles, + url: new URL(values.url || TURBOLIZER_URL), + openBrowser: !values["no-open"], + // By default, use 0 to listen on any localhost port available. + port: Number(values.port ?? 0) + }; +} + +function open(url) { + let command; + switch (process.platform) { + case "darwin": + command = "open"; + break; + case "linux": + command = "xdg-open"; + break; + default: + throw new Error(`Failed to open browser on ${process.platform}`); + } + const child = spawn(command, [url], { + detached: true, + stdio: "ignore" + }); + child.on("error", err => { + console.error(`Failed to open browser: ${err.message}`); + }); + child.unref(); +} + +async function main() { + const { jsonFiles, url, openBrowser, port } = + await parseCommandLineArgs(); + + for (const path of jsonFiles) { + const data = await readFile(path); + // A "one-shot" server that exits after the file is served. + const server = createServer((request, response) => { + response.writeHead(200, { + "access-control-allow-origin": url.origin, + "content-type": "application/json; charset=utf-8" + }); + response.end(data, () => server.close()); + }); + + server.listen(port, "localhost", () => { + const fileUrl = new URL(url); + const { port } = server.address(); + fileUrl.searchParams.set("url", `http://localhost:${port}`); + + if (openBrowser) { + console.log(`Opening Turbolizer for ${basename(path)}...`); + open(fileUrl); + } else { + console.log(`Turbolizer ready on ${fileUrl.toString()}.`); + } + + console.log(`Serving ${basename(path)}.`); + }); + + server.on("error", err => { throw err; }); + } +} + +main().catch(err => { + console.error(err.message || err); + process.exit(1); +}); diff --git a/deps/v8/tools/turbolizer/package-lock.json b/deps/v8/tools/turbolizer/package-lock.json index 4925de01c3bc..0bc2519ac42d 100644 --- a/deps/v8/tools/turbolizer/package-lock.json +++ b/deps/v8/tools/turbolizer/package-lock.json @@ -14,6 +14,9 @@ "rollup-plugin-node-resolve": "^4.0.0", "rollup-plugin-typescript2": "^0.32.1" }, + "bin": { + "turbolizer": "cli.js" + }, "devDependencies": { "@types/node": "^17.0.41", "chai": "^4.3.6", diff --git a/deps/v8/tools/turbolizer/package.json b/deps/v8/tools/turbolizer/package.json index 17788f23ada7..d714c30cc0f7 100644 --- a/deps/v8/tools/turbolizer/package.json +++ b/deps/v8/tools/turbolizer/package.json @@ -23,6 +23,9 @@ "type": "git", "url": "https://github.com/v8/v8.git" }, + "bin": { + "turbolizer": "cli.js" + }, "devDependencies": { "@types/node": "^17.0.41", "chai": "^4.3.6", diff --git a/deps/v8/tools/turbolizer/src/phases/turboshaft-graph-phase/turboshaft-graph-operation.ts b/deps/v8/tools/turbolizer/src/phases/turboshaft-graph-phase/turboshaft-graph-operation.ts index 5ac406a6c67f..b413c0df4ed3 100644 --- a/deps/v8/tools/turbolizer/src/phases/turboshaft-graph-phase/turboshaft-graph-operation.ts +++ b/deps/v8/tools/turbolizer/src/phases/turboshaft-graph-phase/turboshaft-graph-operation.ts @@ -95,7 +95,7 @@ enum MemoryRepresentation { TaggedSigned = "TaggedSigned", UncompressedTaggedPointer = "UncompressedTaggedPointer", ProtectedPointer = "ProtectedPointer", - IndirectPointer = "IndirectPointer", + TrustedPointer = "TrustedPointer", SandboxedPointer = "SandboxedPointer", Simd128 = "Simd128", Simd256 = "Simd256", @@ -119,7 +119,7 @@ function mrString(rep: MemoryRepresentation): string { case MemoryRepresentation.TaggedSigned: return "ts"; case MemoryRepresentation.UncompressedTaggedPointer: return "utp"; case MemoryRepresentation.ProtectedPointer: return "pp"; - case MemoryRepresentation.IndirectPointer: return "ip"; + case MemoryRepresentation.TrustedPointer: return "trp"; case MemoryRepresentation.SandboxedPointer: return "sp"; case MemoryRepresentation.Simd128: return "s128"; case MemoryRepresentation.Simd256: return "s256"; @@ -568,7 +568,7 @@ enum WriteBarrierKind { AssertNoWriteBarrier = "AssertNoWriteBarrier", MapWriteBarrier = "MapWriteBarrier", PointerWriteBarrier = "PointerWriteBarrier", - IndirectPointerWriteBarrier = "IndirectPointerWriteBarrier", + TrustedPointerWriteBarrier = "TrustedPointerWriteBarrier", EphemeronKeyWriteBarrier = "EphemeronKeyWriteBarrier", FullWriteBarrier = "FullWriteBarrier", } diff --git a/deps/v8/tools/turbolizer/src/turbo-visualizer.ts b/deps/v8/tools/turbolizer/src/turbo-visualizer.ts index b3935eefc9fb..5831794ca0f2 100644 --- a/deps/v8/tools/turbolizer/src/turbo-visualizer.ts +++ b/deps/v8/tools/turbolizer/src/turbo-visualizer.ts @@ -66,6 +66,8 @@ window.onload = function () { const jsonObj = JSON.parse(txtRes); const mainFunction = sourceResolver.getMainFunction(jsonObj); + document.title = `Turbolizer: ${mainFunction.functionName}`; + sourceResolver.setInlinings(jsonObj.inlinings); sourceResolver.setSourceLineToBytecodePosition(jsonObj.sourceLineToBytecodePosition); sourceResolver.setSources(jsonObj.sources, mainFunction); @@ -129,6 +131,22 @@ window.onload = function () { } } + async function maybeLoadFileFromUrlParam() { + const url = new URLSearchParams(window.location.search).get("url"); + if (!url) return; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`${response.status} ${response.statusText}`); + } + loadFile(await response.text()); + } catch (err) { + window.alert("Error: Failed to load TurboFan JSON file from URL:\n" + + `${url}\nerror: ${err}`); + } + } + function initializeUploadHandlers() { // The <input> form #upload-helper with type file can't be a picture. // We hence keep it hidden, and forward the click from the picture @@ -144,7 +162,6 @@ window.onload = function () { if (uploadFile) { const fileReader = new FileReader(); fileReader.onload = () => { - document.title = uploadFile.name.replace(".json", ""); const txtRes = fileReader.result; if (typeof txtRes === "string") { loadFile(txtRes); @@ -165,5 +182,6 @@ window.onload = function () { } initializeUploadHandlers(); + maybeLoadFileFromUrlParam(); resizer.updatePanes(); }; diff --git a/deps/v8/tools/v8_presubmit.py b/deps/v8/tools/v8_presubmit.py index ddf23e880008..f28692df03a2 100755 --- a/deps/v8/tools/v8_presubmit.py +++ b/deps/v8/tools/v8_presubmit.py @@ -36,7 +36,8 @@ import multiprocessing import optparse import os -from os.path import abspath, join, dirname, basename, exists, isfile, isdir +from os.path import (abspath, join, dirname, basename, exists, isfile, isdir, + relpath) import pickle import re import subprocess @@ -249,13 +250,21 @@ class SourceFileProcessor(object): files and invoke a custom check on the files. """ + # Checked-in generated files. The build compares them against the + # generator output, so editing them to satisfy a source check does not + # work. See src/gen/README.md. PRESUBMIT.py skips the same paths. + GENERATED_PATHS = (join('src', 'gen') + os.sep,) + def RunOnPath(self, path): """Runs processor on all files under the given path.""" all_files = [] for file in self.GetPathsToSearch(): all_files += self.FindFilesIn(join(path, file)) - return self.ProcessFiles(all_files) + return self.ProcessFiles([ + f for f in all_files + if not relpath(f, path).startswith(SourceFileProcessor.GENERATED_PATHS) + ]) def RunOnFiles(self, files): """Runs processor only on affected files.""" diff --git a/deps/v8/tools/v8windbg/src/object-inspection.cc b/deps/v8/tools/v8windbg/src/object-inspection.cc index b4fbbc210e56..a2811a42a097 100644 --- a/deps/v8/tools/v8windbg/src/object-inspection.cc +++ b/deps/v8/tools/v8windbg/src/object-inspection.cc @@ -69,7 +69,7 @@ IFACEMETHODIMP V8CachedObject::GetCachedV8HeapObject( std::stringstream message; message << "Unable to read memory"; if (location_.IsVirtualAddress()) { - message << " at 0x" << std::hex << location_.GetOffset(); + message << " at 0x" << std::hex << location_.GetOffset() << std::dec; } heap_object_.friendly_name = ConvertToU16String(message.str()); } else { @@ -271,7 +271,7 @@ HRESULT GetModelForBitField(uint64_t address, const uint8_t num_bits, // need all of the bytes, so check for S_OK. if (hr != S_OK) { std::stringstream message; - message << "Unable to read memory at 0x" << std::hex << address; + message << "Unable to read memory at 0x" << std::hex << address << std::dec; return CreateString(ConvertToU16String(message.str()), result); } diff --git a/deps/v8/tools/wasm/module-inspector.cc b/deps/v8/tools/wasm/module-inspector.cc index eb7bc52172f8..8bf0fb8160bc 100644 --- a/deps/v8/tools/wasm/module-inspector.cc +++ b/deps/v8/tools/wasm/module-inspector.cc @@ -94,6 +94,30 @@ char* PrintHexBytesCore(char* ptr, uint32_t num_bytes, const uint8_t* start) { return ptr; } +void WriteEscaped(StringBuilder& out, const char* text, size_t length) { + for (size_t i = 0; i < length; i++) { + uint8_t c = static_cast<uint8_t>(text[i]); + if (c >= 32 && c != '\\') { + out << static_cast<char>(c); + continue; + } + switch (c) { + // C/C++ also knows '\a', but JS does not, and we want to be language + // agnostic, so play it safe and fall through to the hex escape. + // clang-format off + case '\b': out << "\\b"; break; + case '\t': out << "\\t"; break; + case '\n': out << "\\n"; break; + case '\v': out << "\\v"; break; + case '\f': out << "\\f"; break; + case '\r': out << "\\r"; break; + case '\\': out << "\\\\"; break; + default: out << "\\x" << kHexChars[c >> 4] << kHexChars[c & 0xf]; break; + // clang-format on + } + } +} + class InstructionStatistics { public: void Record(WasmOpcode opcode, uint32_t size) { @@ -434,7 +458,9 @@ class HexDumpModuleDis : public ITracer { void Description(const char* desc) override { description_ << desc; } void Description(const char* desc, size_t length) override { - description_.write(desc, length); + // Arbitrary strings from the wire bytes go through here. We could pass + // them through as they are, but it's nice to escape control characters. + WriteEscaped(description_, desc, length); } void Description(uint32_t number) override { if (description_.length() != 0) description_ << " "; From 0d22f147a92d87b10ee1f88e57ddbc15428e8713 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Tue, 27 Oct 2026 16:53:08 -0400 Subject: [PATCH 2/9] deps: update Rust crates for V8 15.8.62 --- deps/crates/Cargo.lock | 104 +- deps/crates/Cargo.toml | 11 +- .../.cargo_vcs_info.json | 6 - .../src/rust_interop.rs | 79 - .../.cargo-checksum.json | 0 .../.cargo_vcs_info.json | 6 + .../Cargo.lock | 2 +- .../Cargo.toml | 2 +- .../Cargo.toml.orig | 2 +- .../LICENSE-APACHE | 0 .../LICENSE-MIT | 0 .../OWNERS | 0 .../README.md | 4 +- .../src/callback.rs | 0 .../src/lib.rs | 39 +- .../src/result.rs | 19 +- .../src/rust_interop.rs | 228 + .../src/slices.rs | 16 +- .../src/wasm_glue.rs | 0 .../src/write.rs | 258 +- .../icu_calendar-v2/.cargo_vcs_info.json | 2 +- deps/crates/vendor/icu_calendar-v2/Cargo.lock | 436 +- deps/crates/vendor/icu_calendar-v2/Cargo.toml | 50 +- .../vendor/icu_calendar-v2/Cargo.toml.orig | 16 +- deps/crates/vendor/icu_calendar-v2/README.md | 4 +- .../vendor/icu_calendar-v2/benches/convert.rs | 2 +- .../vendor/icu_calendar-v2/benches/date.rs | 5 +- .../icu_calendar-v2/benches/preferred.rs | 28 + .../vendor/icu_calendar-v2/benches/until.rs | 2 +- .../icu_calendar-v2/src/any_calendar.rs | 118 +- .../src/cal/abstract_gregorian.rs | 4 +- .../icu_calendar-v2/src/cal/buddhist.rs | 25 +- .../vendor/icu_calendar-v2/src/cal/coptic.rs | 28 +- .../src/cal/east_asian_traditional.rs | 77 +- .../icu_calendar-v2/src/cal/ethiopian.rs | 34 +- .../icu_calendar-v2/src/cal/gregorian.rs | 24 +- .../vendor/icu_calendar-v2/src/cal/hebrew.rs | 26 +- .../vendor/icu_calendar-v2/src/cal/hijri.rs | 12 +- .../vendor/icu_calendar-v2/src/cal/indian.rs | 40 +- .../vendor/icu_calendar-v2/src/cal/iso.rs | 24 +- .../icu_calendar-v2/src/cal/japanese.rs | 136 +- .../vendor/icu_calendar-v2/src/cal/julian.rs | 63 +- .../vendor/icu_calendar-v2/src/cal/persian.rs | 28 +- .../vendor/icu_calendar-v2/src/cal/roc.rs | 30 +- .../vendor/icu_calendar-v2/src/calendar.rs | 2 +- .../src/calendar_arithmetic.rs | 56 +- .../vendor/icu_calendar-v2/src/chrono.rs | 16 +- .../crates/vendor/icu_calendar-v2/src/date.rs | 16 +- .../vendor/icu_calendar-v2/src/duration.rs | 2 +- .../vendor/icu_calendar-v2/src/error.rs | 48 +- .../vendor/icu_calendar-v2/src/ixdtf.rs | 25 +- .../crates/vendor/icu_calendar-v2/src/jiff.rs | 4 +- deps/crates/vendor/icu_calendar-v2/src/lib.rs | 4 +- .../vendor/icu_calendar-v2/src/options.rs | 20 +- .../vendor/icu_calendar-v2/src/preferences.rs | 4 +- .../vendor/icu_calendar-v2/src/provider.rs | 521 +- .../src/tests/constructor_roundtrip.rs | 221 + .../src/tests/date_arithmetic_snapshot.rs | 2 +- .../src/tests/extended_year.rs | 4 +- .../icu_calendar-v2/src/tests/extrema.rs | 15 +- .../vendor/icu_calendar-v2/src/tests/mod.rs | 63 + .../vendor/icu_calendar-v2/src/tests/month.rs | 2 +- .../src/tests/not_enough_fields.rs | 2 +- .../vendor/icu_calendar-v2/src/third_party.rs | 3 +- .../vendor/icu_calendar-v2/src/time_crate.rs | 4 +- .../vendor/icu_calendar-v2/src/types.rs | 8 +- .../crates/vendor/icu_calendar-v2/src/week.rs | 6 +- .../icu_calendar-v2/tests/arithmetic.rs | 2 +- .../icu_calendar-v2/tests/reference_year.rs | 18 +- .../vendor/icu_calendar-v2/tests/reingold.rs | 4 +- .../icu_calendar_data-v2/.cargo_vcs_info.json | 2 +- .../vendor/icu_calendar_data-v2/Cargo.lock | 2 +- .../vendor/icu_calendar_data-v2/Cargo.toml | 13 +- .../icu_calendar_data-v2/Cargo.toml.orig | 4 +- .../vendor/icu_calendar_data-v2/README.md | 2 +- .../data/calendar_japanese_modern_v1.rs.data | 19 +- .../data/calendar_preferred_v1.rs.data | 70 + .../data/calendar_week_v1.rs.data | 10 +- .../vendor/icu_calendar_data-v2/data/mod.rs | 6 +- .../vendor/icu_calendar_data-v2/src/lib.rs | 23 +- .../icu_collections-v2/.cargo_vcs_info.json | 6 - .../vendor/icu_collections-v2/Cargo.lock | 820 --- .../vendor/icu_collections-v2/Cargo.toml | 215 - .../vendor/icu_collections-v2/Cargo.toml.orig | 74 - deps/crates/vendor/icu_collections-v2/OWNERS | 2 - .../vendor/icu_collections-v2/README.md | 27 - .../benches/codepointtrie.rs | 104 - .../icu_collections-v2/benches/iai_cpt.rs | 77 - .../icu_collections-v2/benches/inv_list.rs | 66 - .../benches/tries/gc_fast.rs | 1128 ---- .../benches/tries/gc_small.rs | 865 --- .../icu_collections-v2/benches/tries/mod.rs | 6 - .../icu_collections-v2/src/char16trie/mod.rs | 44 - .../icu_collections-v2/src/char16trie/trie.rs | 495 -- .../src/codepointinvlist/builder.rs | 986 ---- .../src/codepointinvlist/conversions.rs | 180 - .../src/codepointinvlist/cpinvlist.rs | 1070 ---- .../src/codepointinvlist/mod.rs | 80 - .../src/codepointinvlist/utils.rs | 118 - .../src/codepointinvliststringlist/mod.rs | 400 -- .../src/codepointtrie/cptrie.rs | 1897 ------ .../src/codepointtrie/error.rs | 30 - .../src/codepointtrie/impl_const.rs | 76 - .../src/codepointtrie/mod.rs | 53 - .../src/codepointtrie/planes.rs | 296 - .../src/codepointtrie/serde.rs | 74 - .../src/codepointtrie/toml.rs | 124 - .../icu_collections-v2/src/iterator_utils.rs | 188 - .../vendor/icu_collections-v2/src/lib.rs | 44 - .../icu_collections-v2/tests/char16trie.rs | 304 - .../vendor/icu_collections-v2/tests/cpt.rs | 489 -- .../tests/data/char16trie/empty.toml | 11 - .../tests/data/char16trie/months.toml | 19 - .../tests/data/char16trie/test_a.toml | 11 - .../tests/data/char16trie/test_a_ab.toml | 11 - .../tests/data/char16trie/test_branches.toml | 15 - .../tests/data/char16trie/test_compact.toml | 16 - .../data/char16trie/test_long_branch.toml | 28 - .../data/char16trie/test_long_sequence.toml | 32 - .../data/char16trie/test_shortest_branch.toml | 11 - .../tests/data/cpt/free-blocks.16.toml | 113 - .../tests/data/cpt/free-blocks.32.toml | 113 - .../tests/data/cpt/free-blocks.8.toml | 113 - .../tests/data/cpt/free-blocks.small16.toml | 53 - .../tests/data/cpt/grow-data.16.toml | 117 - .../tests/data/cpt/grow-data.32.toml | 113 - .../tests/data/cpt/grow-data.8.toml | 113 - .../tests/data/cpt/grow-data.small16.toml | 53 - .../tests/data/cpt/planes.toml | 140 - .../tests/data/cpt/set-empty.16.toml | 101 - .../tests/data/cpt/set-empty.32.toml | 101 - .../tests/data/cpt/set-empty.8.toml | 101 - .../tests/data/cpt/set-empty.small16.toml | 41 - .../tests/data/cpt/set-single-value.16.toml | 101 - .../tests/data/cpt/set-single-value.32.toml | 101 - .../tests/data/cpt/set-single-value.8.toml | 101 - .../data/cpt/set-single-value.small16.toml | 41 - .../tests/data/cpt/set1.16.toml | 138 - .../tests/data/cpt/set1.32.toml | 138 - .../tests/data/cpt/set1.8.toml | 138 - .../tests/data/cpt/set1.small16.toml | 81 - .../tests/data/cpt/set2-overlap.16.toml | 128 - .../tests/data/cpt/set2-overlap.32.toml | 128 - .../tests/data/cpt/set2-overlap.small16.toml | 73 - .../tests/data/cpt/set3-initial-9.16.toml | 128 - .../tests/data/cpt/set3-initial-9.32.toml | 128 - .../tests/data/cpt/set3-initial-9.8.toml | 128 - .../data/cpt/set3-initial-9.small16.toml | 72 - .../tests/data/cpt/short-all-same.16.toml | 321 - .../tests/data/cpt/short-all-same.8.toml | 385 -- .../data/cpt/short-all-same.small16.toml | 321 - .../tests/data/cpt/small0-in-fast.16.toml | 116 - .../tests/data/cpt/small0-in-fast.32.toml | 116 - .../tests/data/cpt/small0-in-fast.8.toml | 116 - .../data/cpt/small0-in-fast.small16.toml | 63 - .../vendor/icu_locale-v2/.cargo_vcs_info.json | 6 - deps/crates/vendor/icu_locale-v2/OWNERS | 2 - deps/crates/vendor/icu_locale-v2/README.md | 75 - .../benches/fixtures/locales.json | 41 - .../fixtures/uncanonicalized-locales.json | 88 - .../benches/locale_canonicalizer.rs | 107 - .../vendor/icu_locale-v2/src/canonicalizer.rs | 622 -- .../icu_locale-v2/src/directionality.rs | 255 - .../icu_locale-v2/src/exemplar_chars.rs | 305 - .../vendor/icu_locale-v2/src/expander.rs | 606 -- deps/crates/vendor/icu_locale-v2/src/lib.rs | 109 - .../vendor/icu_locale-v2/src/provider.rs | 488 -- .../tests/fixtures/canonicalize.json | 444 -- .../tests/fixtures/maximize.json | 214 - .../tests/fixtures/minimize.json | 26 - .../icu_locale-v2/tests/fixtures/mod.rs | 12 - .../tests/locale_canonicalizer.rs | 81 - .../icu_locale_core-v2/.cargo_vcs_info.json | 2 +- .../vendor/icu_locale_core-v2/Cargo.lock | 84 +- .../vendor/icu_locale_core-v2/Cargo.toml | 6 +- .../src/extensions/private/other.rs | 3 +- .../src/extensions/unicode/attribute.rs | 2 +- .../src/extensions/unicode/subdivision.rs | 4 +- .../vendor/icu_locale_core-v2/src/langid.rs | 2 +- .../vendor/icu_locale_core-v2/src/locale.rs | 2 +- .../extensions/unicode/keywords/calendar.rs | 3 +- .../unicode/keywords/dictionary_break.rs | 4 +- .../icu_locale_core-v2/src/preferences/mod.rs | 24 +- .../icu_locale_core-v2/src/subtags/mod.rs | 3 +- .../icu_locale_data-v2/.cargo_vcs_info.json | 6 - deps/crates/vendor/icu_locale_data-v2/LICENSE | 46 - deps/crates/vendor/icu_locale_data-v2/OWNERS | 2 - .../vendor/icu_locale_data-v2/README.md | 14 - .../data/locale_aliases_v1.rs.data | 119 - ...e_exemplar_characters_auxiliary_v1.rs.data | 1107 ---- ...ocale_exemplar_characters_index_v1.rs.data | 869 --- ...locale_exemplar_characters_main_v1.rs.data | 1233 ---- ...ale_exemplar_characters_numbers_v1.rs.data | 323 - ...exemplar_characters_punctuation_v1.rs.data | 729 --- .../locale_likely_subtags_extended_v1.rs.data | 105 - ...le_likely_subtags_script_region_v1.rs.data | 93 - .../data/locale_parents_v1.rs.data | 85 - .../data/locale_script_direction_v1.rs.data | 80 - .../.cargo-checksum.json | 0 .../.cargo_vcs_info.json | 6 + .../Cargo.lock | 276 +- .../Cargo.toml | 56 +- .../Cargo.toml.orig | 27 +- .../LICENSE | 0 .../vendor/icu_locale_fallback-v2/README.md | 8 + .../src}/algorithms.rs | 72 +- .../src/lib.rs} | 50 +- .../icu_locale_fallback-v2/src/provider.rs | 135 + .../.cargo-checksum.json | 0 .../.cargo_vcs_info.json | 6 + .../Cargo.lock | 4 +- .../Cargo.toml | 19 +- .../Cargo.toml.orig | 8 +- .../LICENSE | 0 .../icu_locale_fallback_data-v2/README.md | 14 + .../build.rs | 0 .../locale_likely_subtags_language_v1.rs.data | 38 +- .../data/locale_parents_v1.rs.data | 85 + .../data/mod.rs | 21 +- .../src/lib.rs | 25 +- .../icu_provider-v2/.cargo_vcs_info.json | 2 +- deps/crates/vendor/icu_provider-v2/Cargo.lock | 110 +- deps/crates/vendor/icu_provider-v2/Cargo.toml | 8 +- .../vendor/icu_provider-v2/Cargo.toml.orig | 2 +- .../vendor/icu_provider-v2/src/export/mod.rs | 12 +- .../vendor/ixdtf-v0_6/.cargo_vcs_info.json | 2 +- deps/crates/vendor/ixdtf-v0_6/Cargo.lock | 56 +- deps/crates/vendor/ixdtf-v0_6/Cargo.toml | 2 +- deps/crates/vendor/ixdtf-v0_6/Cargo.toml.orig | 2 +- deps/crates/vendor/ixdtf-v0_6/src/core.rs | 16 +- .../ixdtf-v0_6/src/parsers/annotations.rs | 39 +- .../vendor/ixdtf-v0_6/src/parsers/tests.rs | 69 +- .../vendor/ixdtf-v0_6/src/parsers/timezone.rs | 13 +- .../vendor/smallvec-v1/.cargo_vcs_info.json | 2 +- deps/crates/vendor/smallvec-v1/Cargo.lock | 10 +- deps/crates/vendor/smallvec-v1/Cargo.toml | 2 +- .../crates/vendor/smallvec-v1/Cargo.toml.orig | 3 +- deps/crates/vendor/smallvec-v1/src/lib.rs | 140 +- deps/crates/vendor/smallvec-v1/src/tests.rs | 112 + .../crates/vendor/syn-v2/.cargo-checksum.json | 1 - .../crates/vendor/syn-v2/.cargo_vcs_info.json | 6 - deps/crates/vendor/syn-v2/Cargo.lock | 1912 ------ deps/crates/vendor/syn-v2/Cargo.toml | 272 - deps/crates/vendor/syn-v2/Cargo.toml.orig | 95 - deps/crates/vendor/syn-v2/LICENSE-APACHE | 176 - deps/crates/vendor/syn-v2/LICENSE-MIT | 23 - deps/crates/vendor/syn-v2/README.md | 282 - deps/crates/vendor/syn-v2/benches/file.rs | 59 - deps/crates/vendor/syn-v2/benches/rust.rs | 189 - deps/crates/vendor/syn-v2/src/attr.rs | 841 --- deps/crates/vendor/syn-v2/src/bigint.rs | 68 - deps/crates/vendor/syn-v2/src/buffer.rs | 437 -- deps/crates/vendor/syn-v2/src/classify.rs | 311 - .../vendor/syn-v2/src/custom_keyword.rs | 260 - .../vendor/syn-v2/src/custom_punctuation.rs | 305 - deps/crates/vendor/syn-v2/src/data.rs | 410 -- deps/crates/vendor/syn-v2/src/derive.rs | 260 - deps/crates/vendor/syn-v2/src/discouraged.rs | 225 - deps/crates/vendor/syn-v2/src/drops.rs | 58 - deps/crates/vendor/syn-v2/src/error.rs | 473 -- deps/crates/vendor/syn-v2/src/export.rs | 73 - deps/crates/vendor/syn-v2/src/expr.rs | 4031 ------------- deps/crates/vendor/syn-v2/src/ext.rs | 180 - deps/crates/vendor/syn-v2/src/file.rs | 128 - deps/crates/vendor/syn-v2/src/fixup.rs | 773 --- deps/crates/vendor/syn-v2/src/gen/clone.rs | 2267 ------- deps/crates/vendor/syn-v2/src/gen/debug.rs | 3238 ---------- deps/crates/vendor/syn-v2/src/gen/eq.rs | 2308 -------- deps/crates/vendor/syn-v2/src/gen/fold.rs | 3906 ------------ deps/crates/vendor/syn-v2/src/gen/hash.rs | 2878 --------- deps/crates/vendor/syn-v2/src/gen/token.css | 737 --- deps/crates/vendor/syn-v2/src/gen/visit.rs | 3941 ------------- .../crates/vendor/syn-v2/src/gen/visit_mut.rs | 3761 ------------ deps/crates/vendor/syn-v2/src/generics.rs | 1420 ----- deps/crates/vendor/syn-v2/src/group.rs | 294 - deps/crates/vendor/syn-v2/src/ident.rs | 109 - deps/crates/vendor/syn-v2/src/item.rs | 3413 ----------- deps/crates/vendor/syn-v2/src/lib.rs | 1016 ---- deps/crates/vendor/syn-v2/src/lifetime.rs | 155 - deps/crates/vendor/syn-v2/src/lit.rs | 1928 ------ deps/crates/vendor/syn-v2/src/lookahead.rs | 350 -- deps/crates/vendor/syn-v2/src/mac.rs | 225 - deps/crates/vendor/syn-v2/src/macros.rs | 182 - deps/crates/vendor/syn-v2/src/meta.rs | 427 -- deps/crates/vendor/syn-v2/src/op.rs | 219 - deps/crates/vendor/syn-v2/src/parse.rs | 1420 ----- .../vendor/syn-v2/src/parse_macro_input.rs | 128 - deps/crates/vendor/syn-v2/src/parse_quote.rs | 244 - deps/crates/vendor/syn-v2/src/pat.rs | 915 --- deps/crates/vendor/syn-v2/src/path.rs | 945 --- deps/crates/vendor/syn-v2/src/precedence.rs | 210 - deps/crates/vendor/syn-v2/src/print.rs | 16 - deps/crates/vendor/syn-v2/src/punctuated.rs | 1170 ---- deps/crates/vendor/syn-v2/src/restriction.rs | 180 - deps/crates/vendor/syn-v2/src/scan_expr.rs | 258 - deps/crates/vendor/syn-v2/src/sealed.rs | 4 - deps/crates/vendor/syn-v2/src/span.rs | 63 - deps/crates/vendor/syn-v2/src/spanned.rs | 118 - deps/crates/vendor/syn-v2/src/stmt.rs | 477 -- deps/crates/vendor/syn-v2/src/thread.rs | 60 - deps/crates/vendor/syn-v2/src/token.rs | 1104 ---- deps/crates/vendor/syn-v2/src/tt.rs | 97 - deps/crates/vendor/syn-v2/src/ty.rs | 1239 ---- deps/crates/vendor/syn-v2/src/verbatim.rs | 32 - deps/crates/vendor/syn-v2/src/whitespace.rs | 65 - deps/crates/vendor/syn-v2/tests/common/eq.rs | 893 --- deps/crates/vendor/syn-v2/tests/common/mod.rs | 6 - .../vendor/syn-v2/tests/common/parse.rs | 51 - .../vendor/syn-v2/tests/common/visit.rs | 119 - deps/crates/vendor/syn-v2/tests/debug/gen.rs | 5238 ----------------- deps/crates/vendor/syn-v2/tests/debug/mod.rs | 147 - deps/crates/vendor/syn-v2/tests/macros/mod.rs | 7 - deps/crates/vendor/syn-v2/tests/regression.rs | 5 - .../syn-v2/tests/regression/issue1108.rs | 5 - .../syn-v2/tests/regression/issue1235.rs | 32 - deps/crates/vendor/syn-v2/tests/repo/mod.rs | 1017 ---- .../vendor/syn-v2/tests/repo/progress.rs | 33 - .../vendor/syn-v2/tests/snapshot/mod.rs | 68 - .../vendor/syn-v2/tests/test_asyncness.rs | 49 - .../vendor/syn-v2/tests/test_attribute.rs | 231 - .../vendor/syn-v2/tests/test_derive_input.rs | 785 --- deps/crates/vendor/syn-v2/tests/test_expr.rs | 1702 ------ .../vendor/syn-v2/tests/test_generics.rs | 356 -- .../vendor/syn-v2/tests/test_grouping.rs | 59 - deps/crates/vendor/syn-v2/tests/test_ident.rs | 87 - deps/crates/vendor/syn-v2/tests/test_item.rs | 371 -- deps/crates/vendor/syn-v2/tests/test_lit.rs | 335 -- deps/crates/vendor/syn-v2/tests/test_meta.rs | 180 - .../vendor/syn-v2/tests/test_parse_buffer.rs | 104 - .../vendor/syn-v2/tests/test_parse_quote.rs | 172 - .../vendor/syn-v2/tests/test_parse_stream.rs | 187 - deps/crates/vendor/syn-v2/tests/test_pat.rs | 158 - deps/crates/vendor/syn-v2/tests/test_path.rs | 116 - .../vendor/syn-v2/tests/test_precedence.rs | 556 -- .../vendor/syn-v2/tests/test_punctuated.rs | 92 - .../vendor/syn-v2/tests/test_receiver.rs | 327 - .../vendor/syn-v2/tests/test_round_trip.rs | 225 - .../vendor/syn-v2/tests/test_shebang.rs | 73 - deps/crates/vendor/syn-v2/tests/test_size.rs | 54 - deps/crates/vendor/syn-v2/tests/test_stmt.rs | 337 -- .../vendor/syn-v2/tests/test_token_trees.rs | 38 - deps/crates/vendor/syn-v2/tests/test_ty.rs | 471 -- .../syn-v2/tests/test_unparenthesize.rs | 70 - .../vendor/syn-v2/tests/test_visibility.rs | 191 - deps/crates/vendor/syn-v2/tests/zzz_stable.rs | 33 - .../crates/vendor/syn-v3/.cargo_vcs_info.json | 2 +- deps/crates/vendor/syn-v3/Cargo.lock | 208 +- deps/crates/vendor/syn-v3/Cargo.toml | 2 +- deps/crates/vendor/syn-v3/Cargo.toml.orig | 2 +- deps/crates/vendor/syn-v3/src/expr.rs | 18 +- deps/crates/vendor/syn-v3/src/lib.rs | 2 +- deps/crates/vendor/syn-v3/tests/common/eq.rs | 10 +- deps/crates/vendor/syn-v3/tests/test_stmt.rs | 35 +- .../synstructure-v0_13/.cargo-checksum.json | 1 - .../synstructure-v0_13/.cargo_vcs_info.json | 6 - .../.cargo-checksum.json | 0 .../synstructure-v0_14/.cargo_vcs_info.json | 6 + .../Cargo.lock | 20 +- .../Cargo.toml | 21 +- .../Cargo.toml.orig | 6 +- .../LICENSE | 0 .../README.md | 2 +- .../src/lib.rs | 52 +- .../src/macros.rs | 0 .../vendor/tinystr-v0_8/.cargo_vcs_info.json | 2 +- deps/crates/vendor/tinystr-v0_8/Cargo.lock | 72 +- deps/crates/vendor/tinystr-v0_8/Cargo.toml | 4 +- .../vendor/tinystr-v0_8/Cargo.toml.orig | 2 +- deps/crates/vendor/tinystr-v0_8/src/ascii.rs | 10 + .../vendor/tinystr-v0_8/src/unvalidated.rs | 2 +- .../unicode-ident-v1/.cargo_vcs_info.json | 2 +- .../unicode-ident-v1/.github/workflows/ci.yml | 16 +- .../crates/vendor/unicode-ident-v1/Cargo.lock | 398 +- .../crates/vendor/unicode-ident-v1/Cargo.toml | 2 +- .../vendor/unicode-ident-v1/Cargo.toml.orig | 4 +- deps/crates/vendor/unicode-ident-v1/README.md | 32 +- .../crates/vendor/unicode-ident-v1/src/lib.rs | 43 +- .../vendor/unicode-ident-v1/src/tables.rs | 254 +- .../tests/fst/xid_continue.fst | Bin 76143 -> 78779 bytes .../unicode-ident-v1/tests/fst/xid_start.fst | Bin 67370 -> 69927 bytes .../unicode-ident-v1/tests/static_size.rs | 8 +- .../unicode-ident-v1/tests/tables/tables.rs | 558 +- .../unicode-ident-v1/tests/trie/trie.rs | 252 +- .../vendor/utf8_iter-v1/.cargo-checksum.json | 1 - .../vendor/utf8_iter-v1/.cargo_vcs_info.json | 6 - deps/crates/vendor/utf8_iter-v1/.gitignore | 2 - deps/crates/vendor/utf8_iter-v1/COPYRIGHT | 42 - deps/crates/vendor/utf8_iter-v1/Cargo.toml | 33 - .../vendor/utf8_iter-v1/Cargo.toml.orig | 13 - .../crates/vendor/utf8_iter-v1/LICENSE-APACHE | 202 - deps/crates/vendor/utf8_iter-v1/LICENSE-MIT | 25 - deps/crates/vendor/utf8_iter-v1/README.md | 56 - .../crates/vendor/utf8_iter-v1/src/indices.rs | 120 - deps/crates/vendor/utf8_iter-v1/src/lib.rs | 282 - deps/crates/vendor/utf8_iter-v1/src/report.rs | 234 - .../yoke-derive-v0_8/.cargo_vcs_info.json | 2 +- .../crates/vendor/yoke-derive-v0_8/Cargo.lock | 18 +- .../crates/vendor/yoke-derive-v0_8/Cargo.toml | 22 +- .../vendor/yoke-derive-v0_8/Cargo.toml.orig | 9 +- .../crates/vendor/yoke-derive-v0_8/src/lib.rs | 5 +- .../vendor/yoke-v0_8/.cargo_vcs_info.json | 2 +- deps/crates/vendor/yoke-v0_8/Cargo.lock | 50 +- deps/crates/vendor/yoke-v0_8/Cargo.toml | 15 +- deps/crates/vendor/yoke-v0_8/Cargo.toml.orig | 2 +- .../vendor/yoke-v0_8/src/cartable_ptr.rs | 5 +- deps/crates/vendor/yoke-v0_8/src/yoke.rs | 45 +- deps/crates/vendor/yoke-v0_8/src/yokeable.rs | 2 +- .../zerofrom-derive-v0_1/.cargo_vcs_info.json | 2 +- .../vendor/zerofrom-derive-v0_1/Cargo.lock | 18 +- .../vendor/zerofrom-derive-v0_1/Cargo.toml | 21 +- .../zerofrom-derive-v0_1/Cargo.toml.orig | 8 +- .../vendor/zerofrom-derive-v0_1/src/lib.rs | 10 +- .../zerovec-derive-v0_11/.cargo_vcs_info.json | 2 +- .../vendor/zerovec-derive-v0_11/Cargo.lock | 14 +- .../vendor/zerovec-derive-v0_11/Cargo.toml | 3 +- .../zerovec-derive-v0_11/Cargo.toml.orig | 3 +- .../vendor/zerovec-derive-v0_11/src/varule.rs | 13 +- .../vendor/zerovec-v0_11/.cargo_vcs_info.json | 2 +- deps/crates/vendor/zerovec-v0_11/Cargo.lock | 134 +- deps/crates/vendor/zerovec-v0_11/Cargo.toml | 8 +- .../vendor/zerovec-v0_11/Cargo.toml.orig | 2 +- deps/crates/vendor/zerovec-v0_11/src/lib.rs | 2 +- .../vendor/zerovec-v0_11/src/map2d/map.rs | 4 +- .../vendor/zerovec-v0_11/src/ule/custom.rs | 4 +- .../vendor/zerovec-v0_11/src/ule/mod.rs | 33 +- .../vendor/zerovec-v0_11/src/ule/slices.rs | 8 +- .../zerovec-v0_11/src/varzerovec/owned.rs | 117 +- 427 files changed, 4841 insertions(+), 95083 deletions(-) delete mode 100644 deps/crates/vendor/diplomat-runtime-v0_15/.cargo_vcs_info.json delete mode 100644 deps/crates/vendor/diplomat-runtime-v0_15/src/rust_interop.rs rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/.cargo-checksum.json (100%) create mode 100644 deps/crates/vendor/diplomat-runtime-v0_16/.cargo_vcs_info.json rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/Cargo.lock (99%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/Cargo.toml (98%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/Cargo.toml.orig (97%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/LICENSE-APACHE (100%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/LICENSE-MIT (100%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/OWNERS (100%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/README.md (98%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/src/callback.rs (100%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/src/lib.rs (65%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/src/result.rs (86%) create mode 100644 deps/crates/vendor/diplomat-runtime-v0_16/src/rust_interop.rs rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/src/slices.rs (91%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/src/wasm_glue.rs (100%) rename deps/crates/vendor/{diplomat-runtime-v0_15 => diplomat-runtime-v0_16}/src/write.rs (53%) create mode 100644 deps/crates/vendor/icu_calendar-v2/benches/preferred.rs create mode 100644 deps/crates/vendor/icu_calendar-v2/src/tests/constructor_roundtrip.rs create mode 100644 deps/crates/vendor/icu_calendar_data-v2/data/calendar_preferred_v1.rs.data delete mode 100644 deps/crates/vendor/icu_collections-v2/.cargo_vcs_info.json delete mode 100644 deps/crates/vendor/icu_collections-v2/Cargo.lock delete mode 100644 deps/crates/vendor/icu_collections-v2/Cargo.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/Cargo.toml.orig delete mode 100644 deps/crates/vendor/icu_collections-v2/OWNERS delete mode 100644 deps/crates/vendor/icu_collections-v2/README.md delete mode 100644 deps/crates/vendor/icu_collections-v2/benches/codepointtrie.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/benches/iai_cpt.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/benches/inv_list.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/benches/tries/gc_fast.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/benches/tries/gc_small.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/benches/tries/mod.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/char16trie/mod.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/char16trie/trie.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointinvlist/builder.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointinvlist/conversions.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointinvlist/cpinvlist.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointinvlist/mod.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointinvlist/utils.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointinvliststringlist/mod.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/cptrie.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/error.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/impl_const.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/mod.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/planes.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/serde.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/codepointtrie/toml.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/iterator_utils.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/src/lib.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/char16trie.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/cpt.rs delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/empty.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/months.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a_ab.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_branches.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_compact.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_branch.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_sequence.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_shortest_branch.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/planes.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.small16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.16.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.32.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.8.toml delete mode 100644 deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.small16.toml delete mode 100644 deps/crates/vendor/icu_locale-v2/.cargo_vcs_info.json delete mode 100644 deps/crates/vendor/icu_locale-v2/OWNERS delete mode 100644 deps/crates/vendor/icu_locale-v2/README.md delete mode 100644 deps/crates/vendor/icu_locale-v2/benches/fixtures/locales.json delete mode 100644 deps/crates/vendor/icu_locale-v2/benches/fixtures/uncanonicalized-locales.json delete mode 100644 deps/crates/vendor/icu_locale-v2/benches/locale_canonicalizer.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/src/canonicalizer.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/src/directionality.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/src/exemplar_chars.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/src/expander.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/src/lib.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/src/provider.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/tests/fixtures/canonicalize.json delete mode 100644 deps/crates/vendor/icu_locale-v2/tests/fixtures/maximize.json delete mode 100644 deps/crates/vendor/icu_locale-v2/tests/fixtures/minimize.json delete mode 100644 deps/crates/vendor/icu_locale-v2/tests/fixtures/mod.rs delete mode 100644 deps/crates/vendor/icu_locale-v2/tests/locale_canonicalizer.rs delete mode 100644 deps/crates/vendor/icu_locale_data-v2/.cargo_vcs_info.json delete mode 100644 deps/crates/vendor/icu_locale_data-v2/LICENSE delete mode 100644 deps/crates/vendor/icu_locale_data-v2/OWNERS delete mode 100644 deps/crates/vendor/icu_locale_data-v2/README.md delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_aliases_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_auxiliary_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_index_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_main_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_numbers_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_punctuation_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_extended_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_script_region_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_parents_v1.rs.data delete mode 100644 deps/crates/vendor/icu_locale_data-v2/data/locale_script_direction_v1.rs.data rename deps/crates/vendor/{icu_collections-v2 => icu_locale_fallback-v2}/.cargo-checksum.json (100%) create mode 100644 deps/crates/vendor/icu_locale_fallback-v2/.cargo_vcs_info.json rename deps/crates/vendor/{icu_locale-v2 => icu_locale_fallback-v2}/Cargo.lock (73%) rename deps/crates/vendor/{icu_locale-v2 => icu_locale_fallback-v2}/Cargo.toml (83%) rename deps/crates/vendor/{icu_locale-v2 => icu_locale_fallback-v2}/Cargo.toml.orig (70%) rename deps/crates/vendor/{icu_collections-v2 => icu_locale_fallback-v2}/LICENSE (100%) create mode 100644 deps/crates/vendor/icu_locale_fallback-v2/README.md rename deps/crates/vendor/{icu_locale-v2/src/fallback => icu_locale_fallback-v2/src}/algorithms.rs (90%) rename deps/crates/vendor/{icu_locale-v2/src/fallback/mod.rs => icu_locale_fallback-v2/src/lib.rs} (86%) create mode 100644 deps/crates/vendor/icu_locale_fallback-v2/src/provider.rs rename deps/crates/vendor/{icu_locale-v2 => icu_locale_fallback_data-v2}/.cargo-checksum.json (100%) create mode 100644 deps/crates/vendor/icu_locale_fallback_data-v2/.cargo_vcs_info.json rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/Cargo.lock (69%) rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/Cargo.toml (83%) rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/Cargo.toml.orig (81%) rename deps/crates/vendor/{icu_locale-v2 => icu_locale_fallback_data-v2}/LICENSE (100%) create mode 100644 deps/crates/vendor/icu_locale_fallback_data-v2/README.md rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/build.rs (100%) rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/data/locale_likely_subtags_language_v1.rs.data (55%) create mode 100644 deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_parents_v1.rs.data rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/data/mod.rs (50%) rename deps/crates/vendor/{icu_locale_data-v2 => icu_locale_fallback_data-v2}/src/lib.rs (55%) delete mode 100644 deps/crates/vendor/syn-v2/.cargo-checksum.json delete mode 100644 deps/crates/vendor/syn-v2/.cargo_vcs_info.json delete mode 100644 deps/crates/vendor/syn-v2/Cargo.lock delete mode 100644 deps/crates/vendor/syn-v2/Cargo.toml delete mode 100644 deps/crates/vendor/syn-v2/Cargo.toml.orig delete mode 100644 deps/crates/vendor/syn-v2/LICENSE-APACHE delete mode 100644 deps/crates/vendor/syn-v2/LICENSE-MIT delete mode 100644 deps/crates/vendor/syn-v2/README.md delete mode 100644 deps/crates/vendor/syn-v2/benches/file.rs delete mode 100644 deps/crates/vendor/syn-v2/benches/rust.rs delete mode 100644 deps/crates/vendor/syn-v2/src/attr.rs delete mode 100644 deps/crates/vendor/syn-v2/src/bigint.rs delete mode 100644 deps/crates/vendor/syn-v2/src/buffer.rs delete mode 100644 deps/crates/vendor/syn-v2/src/classify.rs delete mode 100644 deps/crates/vendor/syn-v2/src/custom_keyword.rs delete mode 100644 deps/crates/vendor/syn-v2/src/custom_punctuation.rs delete mode 100644 deps/crates/vendor/syn-v2/src/data.rs delete mode 100644 deps/crates/vendor/syn-v2/src/derive.rs delete mode 100644 deps/crates/vendor/syn-v2/src/discouraged.rs delete mode 100644 deps/crates/vendor/syn-v2/src/drops.rs delete mode 100644 deps/crates/vendor/syn-v2/src/error.rs delete mode 100644 deps/crates/vendor/syn-v2/src/export.rs delete mode 100644 deps/crates/vendor/syn-v2/src/expr.rs delete mode 100644 deps/crates/vendor/syn-v2/src/ext.rs delete mode 100644 deps/crates/vendor/syn-v2/src/file.rs delete mode 100644 deps/crates/vendor/syn-v2/src/fixup.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/clone.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/debug.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/eq.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/fold.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/hash.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/token.css delete mode 100644 deps/crates/vendor/syn-v2/src/gen/visit.rs delete mode 100644 deps/crates/vendor/syn-v2/src/gen/visit_mut.rs delete mode 100644 deps/crates/vendor/syn-v2/src/generics.rs delete mode 100644 deps/crates/vendor/syn-v2/src/group.rs delete mode 100644 deps/crates/vendor/syn-v2/src/ident.rs delete mode 100644 deps/crates/vendor/syn-v2/src/item.rs delete mode 100644 deps/crates/vendor/syn-v2/src/lib.rs delete mode 100644 deps/crates/vendor/syn-v2/src/lifetime.rs delete mode 100644 deps/crates/vendor/syn-v2/src/lit.rs delete mode 100644 deps/crates/vendor/syn-v2/src/lookahead.rs delete mode 100644 deps/crates/vendor/syn-v2/src/mac.rs delete mode 100644 deps/crates/vendor/syn-v2/src/macros.rs delete mode 100644 deps/crates/vendor/syn-v2/src/meta.rs delete mode 100644 deps/crates/vendor/syn-v2/src/op.rs delete mode 100644 deps/crates/vendor/syn-v2/src/parse.rs delete mode 100644 deps/crates/vendor/syn-v2/src/parse_macro_input.rs delete mode 100644 deps/crates/vendor/syn-v2/src/parse_quote.rs delete mode 100644 deps/crates/vendor/syn-v2/src/pat.rs delete mode 100644 deps/crates/vendor/syn-v2/src/path.rs delete mode 100644 deps/crates/vendor/syn-v2/src/precedence.rs delete mode 100644 deps/crates/vendor/syn-v2/src/print.rs delete mode 100644 deps/crates/vendor/syn-v2/src/punctuated.rs delete mode 100644 deps/crates/vendor/syn-v2/src/restriction.rs delete mode 100644 deps/crates/vendor/syn-v2/src/scan_expr.rs delete mode 100644 deps/crates/vendor/syn-v2/src/sealed.rs delete mode 100644 deps/crates/vendor/syn-v2/src/span.rs delete mode 100644 deps/crates/vendor/syn-v2/src/spanned.rs delete mode 100644 deps/crates/vendor/syn-v2/src/stmt.rs delete mode 100644 deps/crates/vendor/syn-v2/src/thread.rs delete mode 100644 deps/crates/vendor/syn-v2/src/token.rs delete mode 100644 deps/crates/vendor/syn-v2/src/tt.rs delete mode 100644 deps/crates/vendor/syn-v2/src/ty.rs delete mode 100644 deps/crates/vendor/syn-v2/src/verbatim.rs delete mode 100644 deps/crates/vendor/syn-v2/src/whitespace.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/common/eq.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/common/mod.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/common/parse.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/common/visit.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/debug/gen.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/debug/mod.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/macros/mod.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/regression.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/regression/issue1108.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/regression/issue1235.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/repo/mod.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/repo/progress.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/snapshot/mod.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_asyncness.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_attribute.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_derive_input.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_expr.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_generics.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_grouping.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_ident.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_item.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_lit.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_meta.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_parse_buffer.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_parse_quote.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_parse_stream.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_pat.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_path.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_precedence.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_punctuated.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_receiver.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_round_trip.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_shebang.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_size.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_stmt.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_token_trees.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_ty.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_unparenthesize.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/test_visibility.rs delete mode 100644 deps/crates/vendor/syn-v2/tests/zzz_stable.rs delete mode 100644 deps/crates/vendor/synstructure-v0_13/.cargo-checksum.json delete mode 100644 deps/crates/vendor/synstructure-v0_13/.cargo_vcs_info.json rename deps/crates/vendor/{icu_locale_data-v2 => synstructure-v0_14}/.cargo-checksum.json (100%) create mode 100644 deps/crates/vendor/synstructure-v0_14/.cargo_vcs_info.json rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/Cargo.lock (69%) rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/Cargo.toml (96%) rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/Cargo.toml.orig (95%) rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/LICENSE (100%) rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/README.md (96%) rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/src/lib.rs (98%) rename deps/crates/vendor/{synstructure-v0_13 => synstructure-v0_14}/src/macros.rs (100%) delete mode 100644 deps/crates/vendor/utf8_iter-v1/.cargo-checksum.json delete mode 100644 deps/crates/vendor/utf8_iter-v1/.cargo_vcs_info.json delete mode 100644 deps/crates/vendor/utf8_iter-v1/.gitignore delete mode 100644 deps/crates/vendor/utf8_iter-v1/COPYRIGHT delete mode 100644 deps/crates/vendor/utf8_iter-v1/Cargo.toml delete mode 100644 deps/crates/vendor/utf8_iter-v1/Cargo.toml.orig delete mode 100644 deps/crates/vendor/utf8_iter-v1/LICENSE-APACHE delete mode 100644 deps/crates/vendor/utf8_iter-v1/LICENSE-MIT delete mode 100644 deps/crates/vendor/utf8_iter-v1/README.md delete mode 100644 deps/crates/vendor/utf8_iter-v1/src/indices.rs delete mode 100644 deps/crates/vendor/utf8_iter-v1/src/lib.rs delete mode 100644 deps/crates/vendor/utf8_iter-v1/src/report.rs diff --git a/deps/crates/Cargo.lock b/deps/crates/Cargo.lock index 2dc90a16afb1..b39204c50515 100644 --- a/deps/crates/Cargo.lock +++ b/deps/crates/Cargo.lock @@ -32,12 +32,12 @@ dependencies = [ "diplomat_core", "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] name = "diplomat-runtime" -version = "0.15.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -50,7 +50,7 @@ dependencies = [ "serde", "smallvec", "strck", - "syn 3.0.5", + "syn", ] [[package]] @@ -60,19 +60,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] name = "icu_calendar" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "calendrical_calculations", "displaydoc", "icu_calendar_data", - "icu_locale", "icu_locale_core", + "icu_locale_fallback", "icu_provider", "tinystr", "zerovec", @@ -80,30 +80,29 @@ dependencies = [ [[package]] name = "icu_calendar_data" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "icu_collections" -version = "2.2.0" +name = "icu_locale_core" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", + "litemap", + "serde", + "tinystr", + "writeable", "zerovec", ] [[package]] -name = "icu_locale" -version = "2.2.0" +name = "icu_locale_fallback" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "icu_collections", "icu_locale_core", - "icu_locale_data", + "icu_locale_fallback_data", "icu_provider", "potential_utf", "tinystr", @@ -111,26 +110,13 @@ dependencies = [ ] [[package]] -name = "icu_locale_core" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "displaydoc", - "litemap", - "serde", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locale_data" -version = "2.2.0" +name = "icu_locale_fallback_data" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "icu_provider" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "displaydoc", @@ -146,7 +132,7 @@ dependencies = [ [[package]] name = "ixdtf" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -161,12 +147,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "node_crates" -version = "15.6.75" +version = "15.8.62" dependencies = [ - "icu_locale", "icu_locale_core", "icu_provider", - "syn 3.0.5", + "syn", "temporal_capi", "temporal_rs", ] @@ -238,12 +223,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] name = "smallvec" -version = "1.16.1" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -261,17 +246,7 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", @@ -281,12 +256,12 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn", ] [[package]] @@ -334,7 +309,7 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "displaydoc", @@ -344,12 +319,7 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "utf8_iter" -version = "1.0.4" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -359,7 +329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait", @@ -369,12 +339,12 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn", "synstructure", ] @@ -388,12 +358,12 @@ dependencies = [ [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn", "synstructure", ] @@ -408,7 +378,7 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde", @@ -419,12 +389,12 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] diff --git a/deps/crates/Cargo.toml b/deps/crates/Cargo.toml index 1152cae0839d..74ad1a878934 100644 --- a/deps/crates/Cargo.toml +++ b/deps/crates/Cargo.toml @@ -3,23 +3,18 @@ [package] edition = "2021" name = "node_crates" -version = "15.6.75" +version = "15.8.62" rust-version = "1.88" [lib] crate-type = [ "staticlib" ] -[dependencies.icu_locale] -version = "2.2.0" -default-features = false -features = [ "compiled_data" ] - [dependencies.icu_locale_core] -version = "2.2.0" +version = "2.4.0" default-features = false [dependencies.icu_provider] -version = "2.2.0" +version = "2.4.0" default-features = false [dependencies.syn] diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/.cargo_vcs_info.json b/deps/crates/vendor/diplomat-runtime-v0_15/.cargo_vcs_info.json deleted file mode 100644 index a0c309d129a9..000000000000 --- a/deps/crates/vendor/diplomat-runtime-v0_15/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "702b1b2289f40ae45c01068eabb9c229b70827e7" - }, - "path_in_vcs": "runtime" -} \ No newline at end of file diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/rust_interop.rs b/deps/crates/vendor/diplomat-runtime-v0_15/src/rust_interop.rs deleted file mode 100644 index d1b20122e921..000000000000 --- a/deps/crates/vendor/diplomat-runtime-v0_15/src/rust_interop.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Types for interfacing with Diplomat FFI APIs from Rust. -//! -//! By and large, Diplomat helps you produce a Rust-written library that can be called from other -//! languages. You write the library in Rust, but interact with the Diplomat-wrapped library -//! in a non-Rust language. -//! -//! However, either for debugging purposes, or for extending the library in custom ways, you may find -//! yourself wanting to work with the Diplomat-wrapped library from Rust. This module contains -//! utilities for doing that. - -use crate::diplomat_buffer_write_create; -use crate::diplomat_buffer_write_destroy; -use crate::DiplomatWrite; -use core::borrow::Borrow; - -/// A [`DiplomatWrite`] backed by a `Vec`, for convenient use in Rust. -pub struct RustWriteVec { - /// Safety Invariant: must have been created by diplomat_buffer_write_create() - ptr: *mut DiplomatWrite, -} - -impl RustWriteVec { - /// Creates a new [`RustWriteVec`] with the given initial buffer capacity. - pub fn with_capacity(cap: usize) -> Self { - Self { - ptr: diplomat_buffer_write_create(cap), - } - } - - /// Borrows the underlying [`DiplomatWrite`]. - #[allow(clippy::should_implement_trait)] // the trait is also implemented - pub fn borrow(&self) -> &DiplomatWrite { - // Safety: the pointer is valid because the Drop impl hasn't been called yet. - unsafe { &*self.ptr } - } - - /// Mutably borrows the underlying [`DiplomatWrite`]. - /// - /// # Safety - /// The contents of the returned pointer MUST NOT be swapped with another instance - /// of [`DiplomatWrite`] that may have been created from a different source. This - /// requirement is satisfied if this is the only instance of [`DiplomatWrite`] - /// in scope. - /// - /// For more information, see [`DiplomatWrite`]. - pub unsafe fn borrow_mut(&mut self) -> &mut DiplomatWrite { - // Safety: the pointer is valid because the Drop impl hasn't been called yet. - unsafe { &mut *self.ptr } - } -} - -impl Borrow<DiplomatWrite> for RustWriteVec { - fn borrow(&self) -> &DiplomatWrite { - self.borrow() - } -} - -impl Drop for RustWriteVec { - fn drop(&mut self) { - // Safety: by invariant, ptr was created by diplomat_buffer_write_create() - unsafe { diplomat_buffer_write_destroy(self.ptr) } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::fmt::Write; - - #[test] - fn test_rust_write() { - let mut buffer = RustWriteVec::with_capacity(5); - // Safety: this is the only instance of `DiplomatWrite` in scope. - unsafe { buffer.borrow_mut() } - .write_str("Hello World") - .unwrap(); - assert_eq!(buffer.borrow().as_bytes(), b"Hello World"); - } -} diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/.cargo-checksum.json b/deps/crates/vendor/diplomat-runtime-v0_16/.cargo-checksum.json similarity index 100% rename from deps/crates/vendor/diplomat-runtime-v0_15/.cargo-checksum.json rename to deps/crates/vendor/diplomat-runtime-v0_16/.cargo-checksum.json diff --git a/deps/crates/vendor/diplomat-runtime-v0_16/.cargo_vcs_info.json b/deps/crates/vendor/diplomat-runtime-v0_16/.cargo_vcs_info.json new file mode 100644 index 000000000000..1322e829c0bc --- /dev/null +++ b/deps/crates/vendor/diplomat-runtime-v0_16/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "0cca8412630402302b4bd720842101b144a3e18d" + }, + "path_in_vcs": "runtime" +} \ No newline at end of file diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/Cargo.lock b/deps/crates/vendor/diplomat-runtime-v0_16/Cargo.lock similarity index 99% rename from deps/crates/vendor/diplomat-runtime-v0_15/Cargo.lock rename to deps/crates/vendor/diplomat-runtime-v0_16/Cargo.lock index 7ac421c665e5..e98610440d8a 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/Cargo.lock +++ b/deps/crates/vendor/diplomat-runtime-v0_16/Cargo.lock @@ -26,7 +26,7 @@ dependencies = [ [[package]] name = "diplomat-runtime" -version = "0.15.2" +version = "0.16.1" dependencies = [ "jni", "log", diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/Cargo.toml b/deps/crates/vendor/diplomat-runtime-v0_16/Cargo.toml similarity index 98% rename from deps/crates/vendor/diplomat-runtime-v0_15/Cargo.toml rename to deps/crates/vendor/diplomat-runtime-v0_16/Cargo.toml index bbe1eb243e80..f1dd6070f02c 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/Cargo.toml +++ b/deps/crates/vendor/diplomat-runtime-v0_16/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.88" name = "diplomat-runtime" -version = "0.15.2" +version = "0.16.1" authors = [ "Shadaj Laddad <shadaj@users.noreply.github.com>", "Manish Goregaokar <manishsmail@gmail.com>", diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/Cargo.toml.orig b/deps/crates/vendor/diplomat-runtime-v0_16/Cargo.toml.orig similarity index 97% rename from deps/crates/vendor/diplomat-runtime-v0_15/Cargo.toml.orig rename to deps/crates/vendor/diplomat-runtime-v0_16/Cargo.toml.orig index 917c213c882c..07a1874feece 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/Cargo.toml.orig +++ b/deps/crates/vendor/diplomat-runtime-v0_16/Cargo.toml.orig @@ -3,7 +3,7 @@ name = "diplomat-runtime" description = "Common runtime utilities used by diplomat codegen" # We are working on decoupling diplomat-runtime's version from the rest # https://github.com/rust-diplomat/diplomat/issues/958 -version = "0.15.2" +version = "0.16.1" rust-version.workspace = true authors.workspace = true categories.workspace = true diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/LICENSE-APACHE b/deps/crates/vendor/diplomat-runtime-v0_16/LICENSE-APACHE similarity index 100% rename from deps/crates/vendor/diplomat-runtime-v0_15/LICENSE-APACHE rename to deps/crates/vendor/diplomat-runtime-v0_16/LICENSE-APACHE diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/LICENSE-MIT b/deps/crates/vendor/diplomat-runtime-v0_16/LICENSE-MIT similarity index 100% rename from deps/crates/vendor/diplomat-runtime-v0_15/LICENSE-MIT rename to deps/crates/vendor/diplomat-runtime-v0_16/LICENSE-MIT diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/OWNERS b/deps/crates/vendor/diplomat-runtime-v0_16/OWNERS similarity index 100% rename from deps/crates/vendor/diplomat-runtime-v0_15/OWNERS rename to deps/crates/vendor/diplomat-runtime-v0_16/OWNERS diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/README.md b/deps/crates/vendor/diplomat-runtime-v0_16/README.md similarity index 98% rename from deps/crates/vendor/diplomat-runtime-v0_15/README.md rename to deps/crates/vendor/diplomat-runtime-v0_16/README.md index 1495091108a1..01cc1a2e2faa 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/README.md +++ b/deps/crates/vendor/diplomat-runtime-v0_16/README.md @@ -20,8 +20,8 @@ $ cargo install diplomat-tool Then, add the Diplomat macro and runtime as dependencies to your project: ```toml -diplomat = "0.10.0" -diplomat-runtime = "0.10.0" +diplomat = "0.17.0" +diplomat-runtime = "0.16.1" ``` ## Getting Started diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/callback.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/callback.rs similarity index 100% rename from deps/crates/vendor/diplomat-runtime-v0_15/src/callback.rs rename to deps/crates/vendor/diplomat-runtime-v0_16/src/callback.rs diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/lib.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/lib.rs similarity index 65% rename from deps/crates/vendor/diplomat-runtime-v0_15/src/lib.rs rename to deps/crates/vendor/diplomat-runtime-v0_16/src/lib.rs index ea7ae826a558..32e1777a2c62 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/src/lib.rs +++ b/deps/crates/vendor/diplomat-runtime-v0_16/src/lib.rs @@ -6,11 +6,23 @@ //! Include this in any crate that also depends on `diplomat`, since `#[diplomat::bridge]` //! will generate code that relies on types from here. //! -//! This crate contains a fair number of `DiplomatFoo` types. Some, like -//! [`DiplomatOption`], are FFI-safe versions of Rust types that can be put in -//! a struct and passed safely over FFI. Others, like [`DiplomatChar`], are simple -//! type aliases that signal to the Diplomat tool that particular semantics are desired -//! on the C++ side. +//! # Type Overview +//! +//! - **Option and Result**: [`DiplomatResult<T, E>`] (FFI-safe `Result`) and [`DiplomatOption<T>`] (type alias for [`DiplomatResult<T, ()>`]). +//! - **Slices**: [`DiplomatSlice<'a, T>`] (`&'a [T]`), [`DiplomatSliceMut<'a, T>`] (`&'a mut [T]`), and [`DiplomatOwnedSlice<T>`] (`Box<[T]>`). +//! - **String input**: These all map to appropriate string types across FFI. +//! - Unvalidated UTF-8: [`DiplomatStrSlice<'a>`] (`&'a [u8]`), [`DiplomatOwnedStrSlice`] (`Box<[u8]>`) +//! - Unvalidated UTF-16: [`DiplomatStr16Slice<'a>`] (`&'a [u16]`), [`DiplomatOwnedStr16Slice`] (`Box<[u16]>`) +//! - Validated UTF-8: [`DiplomatUtf8StrSlice<'a>`] (`&'a str`), [`DiplomatOwnedUTF8StrSlice`] (`Box<str>`) +//! - Unvalidated stringy DSTs: [`DiplomatStr`] (`[u8]`), [`DiplomatStr16`] (`[u16]`), for convenient use with `&` and `Box` as function parameters. +//! - **String output**: [`DiplomatWrite`] and [`DiplomatWrite16`] +//! - **Primitive buffer output**: [`DiplomatWriteGeneric<T>`] +//! - **Callbacks**: [`DiplomatCallback<ReturnType>`] (FFI-safe callback handle). +//! - **Scalars**: [`DiplomatChar`] (`u32`) and [`DiplomatByte`] (`u8`). +//! +//! Note that many of these are type aliases; using these types instead of the type alias signals that Diplomat is expected to +//! generate the equivalent type on the other side. For example, using `DiplomatChar` will signal that a language's `char` type is +//! to be used, even if the actual type seen by rust is an unvalidated `u32`. //! //! # Features //! @@ -18,6 +30,7 @@ //! //! The `jvm-callback-support` feature should be enabled if building Diplomat for use in the JVM, for //! a Diplomat-based library that uses callbacks. + extern crate alloc; use alloc::alloc::Layout; @@ -26,8 +39,10 @@ use alloc::alloc::Layout; mod wasm_glue; mod write; -pub use write::DiplomatWrite; -pub use write::{diplomat_buffer_write_create, diplomat_buffer_write_destroy}; +pub use write::{ + diplomat_buffer_write_create, diplomat_buffer_write_destroy, diplomat_simple_write, + DiplomatAbiCompatible, DiplomatWrite, DiplomatWrite16, DiplomatWriteGeneric, +}; mod slices; pub use slices::{ DiplomatOwnedSlice, DiplomatOwnedStr16Slice, DiplomatOwnedStrSlice, DiplomatOwnedUTF8StrSlice, @@ -54,6 +69,11 @@ pub type DiplomatChar = u32; /// /// This type will usually map to some string type in the target language, and /// you will not need to worry about the safety of mismatched string invariants. +/// +/// [`DiplomatStrSlice`] is equivalent to `&DiplomatStr`: both are provided since +/// `&DiplomatStr` is more convenient but not allowed in Diplomat structs (since it +/// is not directly FFI safe). Instead, this type can be conveniently used in function +/// parameter lists. pub type DiplomatStr = [u8]; /// Like `Wstr`, but unvalidated. @@ -62,6 +82,11 @@ pub type DiplomatStr = [u8]; /// /// This type will usually map to some string type in the target language, and /// you will not need to worry about the safety of mismatched string invariants. +/// +/// [`DiplomatStr16Slice`] is equivalent to `&DiplomatStr16`: both are provided since +/// `&DiplomatStr16` is more convenient but not allowed in Diplomat structs (since it +/// is not directly FFI safe). Instead, this type can be conveniently used in function +/// parameter lists. pub type DiplomatStr16 = [u16]; /// Like [`u8`], but interpreted explicitly as a raw byte as opposed to a numerical value. diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/result.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/result.rs similarity index 86% rename from deps/crates/vendor/diplomat-runtime-v0_15/src/result.rs rename to deps/crates/vendor/diplomat-runtime-v0_16/src/result.rs index 5f20930d7904..21a64809e0ae 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/src/result.rs +++ b/deps/crates/vendor/diplomat-runtime-v0_16/src/result.rs @@ -13,16 +13,33 @@ union DiplomatResultValue<T, E> { #[repr(C)] pub struct DiplomatResult<T, E> { value: DiplomatResultValue<T, E>, + /// Whether the result is `Ok`. + /// + /// Note: Mutating this field directly in Rust is unsound, and this field will become + /// private in `diplomat-runtime` 1.0 ([#1239](https://github.com/rust-diplomat/diplomat/issues/1239)). + /// Prefer calling [`DiplomatResult::is_ok()`] or [`DiplomatResult::is_err()`]. pub is_ok: bool, } -/// A type to represent Option<T> over FFI. +/// A type to represent `Option<T>` over FFI. /// /// Used internally to handle `Option<T>` arguments and return types, and needs to be /// used explicitly for optional struct fields. pub type DiplomatOption<T> = DiplomatResult<T, ()>; impl<T, E> DiplomatResult<T, E> { + /// Returns `true` if the result is `Ok`. + #[inline] + pub const fn is_ok(&self) -> bool { + self.is_ok + } + + /// Returns `true` if the result is `Err`. + #[inline] + pub const fn is_err(&self) -> bool { + !self.is_ok + } + pub fn as_ref(&self) -> Result<&T, &E> { // Safety: we're only accessing the union variants when the flag is correct unsafe { diff --git a/deps/crates/vendor/diplomat-runtime-v0_16/src/rust_interop.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/rust_interop.rs new file mode 100644 index 000000000000..5461ee60ee8d --- /dev/null +++ b/deps/crates/vendor/diplomat-runtime-v0_16/src/rust_interop.rs @@ -0,0 +1,228 @@ +//! Types for interfacing with Diplomat FFI APIs from Rust. +//! +//! By and large, Diplomat helps you produce a Rust-written library that can be called from other +//! languages. You write the library in Rust, but interact with the Diplomat-wrapped library +//! in a non-Rust language. +//! +//! However, either for debugging purposes, or for extending the library in custom ways, you may find +//! yourself wanting to work with the Diplomat-wrapped library from Rust. This module contains +//! utilities for doing that. + +use crate::diplomat_buffer_write_create; +use crate::diplomat_buffer_write_destroy; +use crate::DiplomatAbiCompatible; +use crate::DiplomatWrite; +use crate::DiplomatWriteGeneric; +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ptr; + +/// A [`DiplomatWrite`] backed by a `Vec`, for convenient use in Rust. +pub struct RustWriteVec { + /// Safety Invariant: must have been created by diplomat_buffer_write_create() + ptr: *mut DiplomatWrite, +} + +impl RustWriteVec { + /// Creates a new [`RustWriteVec`] with the given initial buffer capacity. + pub fn with_capacity(cap: usize) -> Self { + Self { + ptr: diplomat_buffer_write_create(cap), + } + } + + /// Borrows the underlying [`DiplomatWrite`]. + #[allow(clippy::should_implement_trait)] // the trait is also implemented + pub fn borrow(&self) -> &DiplomatWrite { + // Safety: the pointer is valid because the Drop impl hasn't been called yet. + unsafe { &*self.ptr } + } + + /// Mutably borrows the underlying [`DiplomatWrite`]. + /// + /// # Safety + /// The contents of the returned pointer MUST NOT be swapped with another instance + /// of [`DiplomatWrite`] that may have been created from a different source. This + /// requirement is satisfied if this is the only instance of [`DiplomatWrite`] + /// in scope. + /// + /// For more information, see [`DiplomatWrite`]. + pub unsafe fn borrow_mut(&mut self) -> &mut DiplomatWrite { + // Safety: the pointer is valid because the Drop impl hasn't been called yet. + unsafe { &mut *self.ptr } + } +} + +impl Borrow<DiplomatWrite> for RustWriteVec { + fn borrow(&self) -> &DiplomatWrite { + self.borrow() + } +} + +impl Drop for RustWriteVec { + fn drop(&mut self) { + // Safety: by invariant, ptr was created by diplomat_buffer_write_create() + unsafe { diplomat_buffer_write_destroy(self.ptr) } + } +} + +/// A [`DiplomatWriteGeneric<T>`] backed by a `Vec<T>`, for convenient use in Rust. +pub struct RustWriteVecGeneric<T: DiplomatAbiCompatible> { + // Safety invariant: `inner.raw`'s `buf`, `len`, and `cap` correspond to a valid + // `Vec<T>` allocation with `len = inner.raw.len / size_of::<T>()` and + // `cap = inner.raw.cap / size_of::<T>()`. + inner: DiplomatWriteGeneric<T>, +} + +// Note: `this` must be `*mut DiplomatWrite` rather than `&mut DiplomatWrite` to match +// the `extern "C" fn(*mut DiplomatWrite, usize) -> bool` signature of `DiplomatWrite::grow`. +extern "C" fn grow_vec<T: DiplomatAbiCompatible>( + this: *mut DiplomatWrite, + new_cap_bytes: usize, +) -> bool { + // SAFETY: + // 1. `this` is a valid pointer to a `DiplomatWrite` constructed by `RustWriteVecGeneric::with_capacity`. + // 2. `this.buf` was allocated by `Vec::<T>` with `old_len_elems` initialized elements and `old_cap_elems` capacity. + unsafe { + let this = this.as_mut().unwrap(); + let elem_size = core::mem::size_of::<T>(); + if elem_size == 0 { + return true; + } + let new_cap_elems = new_cap_bytes.div_ceil(elem_size); + let old_len_elems = this.len / elem_size; + let old_cap_elems = this.cap / elem_size; + + let mut vec = Vec::<T>::from_raw_parts(this.buf as *mut T, old_len_elems, old_cap_elems); + vec.reserve(new_cap_elems.saturating_sub(old_len_elems)); + this.cap = vec.capacity() * elem_size; + this.buf = vec.as_mut_ptr() as *mut u8; + core::mem::forget(vec); + } + true +} + +impl<T: DiplomatAbiCompatible> RustWriteVecGeneric<T> { + /// Creates a new [`RustWriteVecGeneric`] with the given initial element capacity. + pub fn with_capacity(cap: usize) -> Self { + extern "C" fn flush(_: *mut DiplomatWrite) {} + let mut vec = Vec::<T>::with_capacity(cap); + let raw = DiplomatWrite { + context: ptr::null_mut(), + buf: vec.as_mut_ptr() as *mut u8, + len: 0, + grow_failed: false, + cap: vec.capacity() * core::mem::size_of::<T>(), + flush, + grow: grow_vec::<T>, + }; + core::mem::forget(vec); + Self { + inner: DiplomatWriteGeneric { + raw, + _marker: PhantomData, + }, + } + } + + /// Borrows the underlying [`DiplomatWriteGeneric<T>`]. + #[allow(clippy::should_implement_trait)] // the trait is also implemented + pub fn borrow(&self) -> &DiplomatWriteGeneric<T> { + &self.inner + } + + /// Mutably borrows the underlying [`DiplomatWriteGeneric<T>`]. + /// + /// # Safety + /// The contents of the returned reference MUST NOT be swapped with another instance + /// of [`DiplomatWriteGeneric<T>`] that may have been created from a different source. + pub unsafe fn borrow_mut(&mut self) -> &mut DiplomatWriteGeneric<T> { + &mut self.inner + } + + /// Returns a slice of the elements written so far. + pub fn as_slice(&self) -> &[T] { + self.inner.as_slice() + } + + /// Consumes the wrapper and returns the filled `Vec<T>`. + pub fn into_vec(self) -> Vec<T> { + let this = ManuallyDrop::new(self); + let elem_size = core::mem::size_of::<T>(); + let len_elems = this.inner.raw.len.checked_div(elem_size).unwrap_or(0); + let cap_elems = this.inner.raw.cap.checked_div(elem_size).unwrap_or(0); + // SAFETY: + // 1. By `self.inner`'s safety invariant, `this.inner.raw.buf` was allocated by `Vec<T>` + // with `len_elems` initialized elements and `cap_elems` capacity. + // 2. Wrapping `self` in `ManuallyDrop` prevents `Drop` from reconstructing and freeing + // the `Vec<T>` a second time. + unsafe { Vec::<T>::from_raw_parts(this.inner.raw.buf as *mut T, len_elems, cap_elems) } + } +} + +impl<T: DiplomatAbiCompatible> Borrow<DiplomatWriteGeneric<T>> for RustWriteVecGeneric<T> { + fn borrow(&self) -> &DiplomatWriteGeneric<T> { + self.borrow() + } +} + +impl<T: DiplomatAbiCompatible> Drop for RustWriteVecGeneric<T> { + fn drop(&mut self) { + let elem_size = core::mem::size_of::<T>(); + let len_elems = self.inner.raw.len.checked_div(elem_size).unwrap_or(0); + let cap_elems = self.inner.raw.cap.checked_div(elem_size).unwrap_or(0); + // SAFETY: By `self.inner`'s safety invariant, `self.inner.raw.buf` was allocated by `Vec<T>` + // with `len_elems` initialized elements and `cap_elems` capacity. + unsafe { + let _ = Vec::<T>::from_raw_parts(self.inner.raw.buf as *mut T, len_elems, cap_elems); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::fmt::Write; + + #[test] + fn test_rust_write() { + let mut buffer = RustWriteVec::with_capacity(5); + // Safety: this is the only instance of `DiplomatWrite` in scope. + unsafe { buffer.borrow_mut() } + .write_str("Hello World") + .unwrap(); + assert_eq!(buffer.borrow().as_bytes(), b"Hello World"); + } + + #[test] + fn test_rust_write_generic() { + let mut buffer = RustWriteVecGeneric::<u32>::with_capacity(2); + // SAFETY: this is the only instance of `DiplomatWriteGeneric<u32>` in scope. + let writer = unsafe { buffer.borrow_mut() }; + writer.push(10); + writer.push(20); + writer.push(30); // triggers grow + writer.write_slice(&[40, 50]); + writer.extend([60, 70]); + assert_eq!(writer.len(), 7); + assert_eq!(buffer.as_slice(), &[10, 20, 30, 40, 50, 60, 70]); + assert_eq!(buffer.into_vec(), alloc::vec![10, 20, 30, 40, 50, 60, 70]); + } + + #[test] + fn test_rust_write_16() { + let mut buffer = RustWriteVecGeneric::<u16>::with_capacity(2); + // SAFETY: this is the only instance of `DiplomatWrite16` in scope. + let writer: &mut crate::DiplomatWrite16 = unsafe { buffer.borrow_mut() }; + writer.write_char_as_utf16('A'); + writer.write_char_as_utf16('𐐷'); // surrogate pair: 0xD801, 0xDC37 + assert_eq!(writer.len(), 3); + assert_eq!(buffer.as_slice(), &[0x0041, 0xD801, 0xDC37]); + assert_eq!( + alloc::string::String::from_utf16(buffer.as_slice()).unwrap(), + "A𐐷" + ); + } +} diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/slices.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/slices.rs similarity index 91% rename from deps/crates/vendor/diplomat-runtime-v0_15/src/slices.rs rename to deps/crates/vendor/diplomat-runtime-v0_16/src/slices.rs index 1c7638aa0d74..a6b60e86527b 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/src/slices.rs +++ b/deps/crates/vendor/diplomat-runtime-v0_16/src/slices.rs @@ -269,23 +269,35 @@ impl Deref for DiplomatOwnedUTF8StrSlice { } } -/// This like `&str`, but unvalidated and safe to use over FFI +/// This is like `&str`, but unvalidated and safe to use over FFI /// /// This type will usually map to some string type in the target language, and /// you will not need to worry about the safety of mismatched string invariants. +/// +/// Using this type on a function signature is equivalent to using `&DiplomatStr`, +/// however this type is FFI-safe and therefore also allowed inside Diplomat structs. pub type DiplomatStrSlice<'a> = DiplomatSlice<'a, u8>; -/// This like `Box<str>`, but unvalidated and safe to use over FFI +/// This is like `Box<str>`, but unvalidated and safe to use over FFI /// /// This type will usually map to some string type in the target language, and /// you will not need to worry about the safety of mismatched string invariants. +/// +/// Using this type on a function signature is equivalent to using `Box<DiplomatStr>`, +/// however this type is FFI-safe and therefore also allowed inside Diplomat structs. pub type DiplomatOwnedStrSlice = DiplomatOwnedSlice<u8>; /// An unvalidated UTF-16 string that is safe to use over FFI /// /// This type will usually map to some string type in the target language, and /// you will not need to worry about the safety of mismatched string invariants. +/// +/// Using this type on a function signature is equivalent to using `&DiplomatStr16`, +/// however this type is FFI-safe and therefore also allowed inside Diplomat structs. pub type DiplomatStr16Slice<'a> = DiplomatSlice<'a, u16>; /// An unvalidated, owned UTF-16 string that is safe to use over FFI /// /// This type will usually map to some string type in the target language, and /// you will not need to worry about the safety of mismatched string invariants. +/// +/// Using this type on a function signature is equivalent to using `Box<DiplomatStr16>`, +/// however this type is FFI-safe and therefore also allowed inside Diplomat structs. pub type DiplomatOwnedStr16Slice<'a> = DiplomatOwnedSlice<u16>; diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/wasm_glue.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/wasm_glue.rs similarity index 100% rename from deps/crates/vendor/diplomat-runtime-v0_15/src/wasm_glue.rs rename to deps/crates/vendor/diplomat-runtime-v0_16/src/wasm_glue.rs diff --git a/deps/crates/vendor/diplomat-runtime-v0_15/src/write.rs b/deps/crates/vendor/diplomat-runtime-v0_16/src/write.rs similarity index 53% rename from deps/crates/vendor/diplomat-runtime-v0_15/src/write.rs rename to deps/crates/vendor/diplomat-runtime-v0_16/src/write.rs index 1d6400680d2e..c4996bc1f9a3 100644 --- a/deps/crates/vendor/diplomat-runtime-v0_15/src/write.rs +++ b/deps/crates/vendor/diplomat-runtime-v0_16/src/write.rs @@ -30,7 +30,7 @@ use core::{fmt, ptr}; /// /// 1. [`diplomat_simple_write()`] to write to a fixed-size buffer. /// 2. [`diplomat_buffer_write_create()`] to write to a Vec allocated by Rust. -/// A wrapper is provided: [`RustWriteVec`](rust_interop::RustWriteVec). +/// A wrapper is provided: [`RustWriteVec`](crate::rust_interop::RustWriteVec). /// /// Backends may have additional constructors for writing to various shapes of buffer. /// @@ -49,10 +49,10 @@ use core::{fmt, ptr}; /// ``` /// /// As a result, any function that returns an owned `DiplomatWrite` or a `&mut DiplomatWrite` -/// must be `unsafe`. For an example, see [`RustWriteVec::borrow_mut`]. +/// must be `unsafe`. For an example, see [`RustWriteVec::borrow_mut`](crate::rust_interop::RustWriteVec::borrow_mut). /// /// Diplomat backends guarantee they will only ever hand the same type of `DiplomatWrite` object to Rust -/// code; this is only something you need to worry about if using [`RustWriteVec`](rust_interop::RustWriteVec), +/// code; this is only something you need to worry about if using [`RustWriteVec`](crate::rust_interop::RustWriteVec), /// or `DiplomatWrite` objects manually created in Rust via APIs like `diplomat_simple_write`. /// /// # Safety invariants: @@ -72,22 +72,22 @@ pub struct DiplomatWrite { /// /// The pointer may reference structured data on the foreign side, /// such as C++ std::string, used to reallocate buf. - context: *mut c_void, + pub(crate) context: *mut c_void, /// The raw string buffer, which will be mutated on the Rust side. - buf: *mut u8, + pub(crate) buf: *mut u8, /// The current filled size of the buffer - len: usize, + pub(crate) len: usize, /// The current capacity of the buffer - cap: usize, + pub(crate) cap: usize, /// Set to true if `grow` ever fails. - grow_failed: bool, + pub(crate) grow_failed: bool, /// Called by Rust to indicate that there is no more data to write. /// /// May be called multiple times. /// /// Arguments: /// - `self` (`*mut DiplomatWrite`): This `DiplomatWrite` - flush: extern "C" fn(*mut DiplomatWrite), + pub(crate) flush: extern "C" fn(*mut DiplomatWrite), /// Called by Rust to request more capacity in the buffer. The implementation should allocate a new /// buffer and copy the contents of the old buffer into the new buffer, updating `self.buf` and `self.cap` /// @@ -96,7 +96,7 @@ pub struct DiplomatWrite { /// - `capacity` (`usize`): The requested capacity. /// /// Returns: `true` if the allocation succeeded. Should not update any state if it failed. - grow: extern "C" fn(*mut DiplomatWrite, usize) -> bool, + pub(crate) grow: extern "C" fn(*mut DiplomatWrite, usize) -> bool, } impl DiplomatWrite { @@ -151,7 +151,7 @@ impl fmt::Write for DiplomatWrite { /// Once done, this will append a null terminator to the written string. /// /// This is largely used internally by Diplomat-generated FFI code, and should not need to be constructed -/// manually outside of that context. See [`RustWriteVec`](rust_interop::RustWriteVec) if you need this in Rust. +/// manually outside of that context. See [`RustWriteVec`](crate::rust_interop::RustWriteVec) if you need this in Rust. /// /// # Safety /// @@ -186,7 +186,7 @@ pub unsafe extern "C" fn diplomat_simple_write(buf: *mut u8, buf_size: usize) -> /// The pointer is valid until that function is called. /// /// This is largely used internally by Diplomat-generated FFI code, and should not need to be constructed -/// manually outside of that context. See [`RustWriteVec`](rust_interop::RustWriteVec) if you need this in Rust. +/// manually outside of that context. See [`RustWriteVec`](crate::rust_interop::RustWriteVec) if you need this in Rust. /// /// The grow impl never sets `grow_failed`, although it is possible for it to panic. #[no_mangle] @@ -268,3 +268,237 @@ pub unsafe extern "C" fn diplomat_buffer_write_destroy(this: *mut DiplomatWrite) drop(vec); drop(this); } + +mod sealed { + pub trait Sealed {} +} + +/// Marker trait for types that have a stable, shared C ABI layout and can be written +/// directly into a [`DiplomatWriteGeneric`]. +/// +/// This trait is currently sealed and implemented only for scalar primitive types. +/// +/// # Safety +/// Implementors must: +/// - Be `Copy` and Plain Old Data (POD). +/// - Have a fixed, shared layout across the FFI boundary. +/// - Contain no pointers, references, or custom `Drop` glue. +pub unsafe trait DiplomatAbiCompatible: Copy + sealed::Sealed {} + +macro_rules! impl_abi_compatible { + ($($ty:ty),* $(,)?) => { + $( + impl sealed::Sealed for $ty {} + // SAFETY: Scalar primitives are Copy, POD, have no pointers or Drop glue, + // and share a fixed C ABI layout across FFI. + unsafe impl DiplomatAbiCompatible for $ty {} + )* + }; +} + +impl_abi_compatible!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize, f32, f64); + +/// An object that can write a sequence of primitive values of type `T` across FFI. +/// +/// This wraps an underlying [`DiplomatWrite`] with a type-safe API for pushing elements, +/// writing slices, and extending from iterators. +/// +/// # Safety invariants +/// - All safety invariants of [`DiplomatWrite`] hold on `self.raw`. +/// - `self.raw.len` and `self.raw.cap` are measured in bytes, and `self.raw.len` is always +/// a multiple of `size_of::<T>()`. +/// - `self.raw.buf` points to `self.raw.len / size_of::<T>()` consecutive properly initialized +/// values of `T`. +#[repr(transparent)] +pub struct DiplomatWriteGeneric<T: DiplomatAbiCompatible> { + pub(crate) raw: DiplomatWrite, + pub(crate) _marker: core::marker::PhantomData<T>, +} + +impl<T: DiplomatAbiCompatible> DiplomatWriteGeneric<T> { + /// Pushes a single element into the buffer. + #[inline] + pub fn push(&mut self, val: T) { + if self.raw.grow_failed { + return; + } + let elem_size = core::mem::size_of::<T>(); + if elem_size == 0 { + return; + } + let Some(needed_bytes) = self.raw.len.checked_add(elem_size) else { + self.raw.grow_failed = true; + return; + }; + if needed_bytes > self.raw.cap { + let success = (self.raw.grow)(&mut self.raw, needed_bytes); + if !success { + self.raw.grow_failed = true; + return; + } + } + debug_assert!(needed_bytes <= self.raw.cap); + // SAFETY: + // 1. `self.raw.buf` is valid for at least `needed_bytes` bytes (`<= self.raw.cap`). + // 2. `write_unaligned` is used so no alignment assumption on `self.raw.buf` is required. + unsafe { + ptr::write_unaligned(self.raw.buf.add(self.raw.len) as *mut T, val); + } + // Maintains safety invariant: `self.raw.len <= self.raw.cap` and `len` is a multiple of `size_of::<T>()`. + self.raw.len = needed_bytes; + } + + /// Appends a contiguous slice of elements into the buffer. + #[inline] + pub fn write_slice(&mut self, slice: &[T]) { + if self.raw.grow_failed || slice.is_empty() { + return; + } + let elem_size = core::mem::size_of::<T>(); + if elem_size == 0 { + return; + } + let Some(byte_len) = slice.len().checked_mul(elem_size) else { + self.raw.grow_failed = true; + return; + }; + let Some(needed_bytes) = self.raw.len.checked_add(byte_len) else { + self.raw.grow_failed = true; + return; + }; + if needed_bytes > self.raw.cap { + let success = (self.raw.grow)(&mut self.raw, needed_bytes); + if !success { + self.raw.grow_failed = true; + return; + } + } + debug_assert!(needed_bytes <= self.raw.cap); + // SAFETY: + // 1. `slice.as_ptr()` is valid for `byte_len` bytes. + // 2. `self.raw.buf.add(self.raw.len)` is valid for `byte_len` bytes (`needed_bytes <= self.raw.cap`). + // 3. The two memory regions do not overlap because `&mut self` exclusively borrows the write buffer. + unsafe { + ptr::copy_nonoverlapping( + slice.as_ptr() as *const u8, + self.raw.buf.add(self.raw.len), + byte_len, + ); + } + // Maintains safety invariant: `self.raw.len <= self.raw.cap` and `len` is a multiple of `size_of::<T>()`. + self.raw.len = needed_bytes; + } + + /// Extends the buffer with elements from an iterator. + pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { + let iter = iter.into_iter(); + let (lower, _) = iter.size_hint(); + if lower > 0 { + self.reserve(lower); + } + for item in iter { + self.push(item); + } + } + + /// Reserves capacity for at least `additional` more elements of type `T`. + /// + /// Returns `true` if the reservation succeeded, or `false` if allocation failed. + pub fn reserve(&mut self, additional: usize) -> bool { + if self.raw.grow_failed { + return false; + } + let elem_size = core::mem::size_of::<T>(); + let Some(additional_bytes) = additional.checked_mul(elem_size) else { + self.raw.grow_failed = true; + return false; + }; + let Some(needed_bytes) = self.raw.len.checked_add(additional_bytes) else { + self.raw.grow_failed = true; + return false; + }; + if needed_bytes > self.raw.cap { + let success = (self.raw.grow)(&mut self.raw, needed_bytes); + if !success { + self.raw.grow_failed = true; + return false; + } + } + true + } + + /// Returns the number of elements of type `T` written so far. + #[inline] + pub fn len(&self) -> usize { + self.raw + .len + .checked_div(core::mem::size_of::<T>()) + .unwrap_or(0) + } + + /// Returns `true` if no elements have been written. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the current capacity in elements of type `T`. + #[inline] + pub fn capacity(&self) -> usize { + self.raw + .cap + .checked_div(core::mem::size_of::<T>()) + .unwrap_or(0) + } + + /// Returns a slice of the elements written so far if the underlying buffer is aligned for `T`. + /// + /// If growth has failed, this returns what has been written so far. + pub fn as_slice(&self) -> &[T] { + if self.raw.buf.is_null() || self.raw.len == 0 { + return &[]; + } + let elem_size = core::mem::size_of::<T>(); + if elem_size == 0 { + return &[]; + } + let count = self.raw.len / elem_size; + if !(self.raw.buf as usize).is_multiple_of(core::mem::align_of::<T>()) { + return &[]; + } + debug_assert!(self.raw.len <= self.raw.cap); + // SAFETY: + // 1. `self.raw.buf` is non-null and aligned to `align_of::<T>()` (checked above). + // 2. By `DiplomatWriteGeneric<T>`'s safety invariants, `self.raw.buf` points to `count` + // consecutive properly initialized values of `T` with total size `<= isize::MAX`. + // 3. The buffer will not be mutated while `&self` is borrowed. + unsafe { core::slice::from_raw_parts(self.raw.buf as *const T, count) } + } + + /// Call this function before releasing the buffer to C. + pub fn flush(&mut self) { + self.raw.flush(); + } +} + +impl<T: DiplomatAbiCompatible> Extend<T> for DiplomatWriteGeneric<T> { + fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { + DiplomatWriteGeneric::extend(self, iter); + } +} + +/// An object that can one-shot write a UTF-16 string. +/// +/// Over FFI, this acts just like [`DiplomatWrite`], except that the underlying +/// buffer contains `u16` code units and is converted into a string by backends +/// that support `utf16_writeables`. +pub type DiplomatWrite16 = DiplomatWriteGeneric<u16>; + +impl DiplomatWriteGeneric<u16> { + /// Encodes `c` as UTF-16 (1 or 2 `u16` code units) and appends it to the buffer. + #[inline] + pub fn write_char_as_utf16(&mut self, c: char) { + let mut buf = [0u16; 2]; + self.write_slice(c.encode_utf16(&mut buf)); + } +} diff --git a/deps/crates/vendor/icu_calendar-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_calendar-v2/.cargo_vcs_info.json index 3b5a9e97d12d..071f26eec28d 100644 --- a/deps/crates/vendor/icu_calendar-v2/.cargo_vcs_info.json +++ b/deps/crates/vendor/icu_calendar-v2/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "6f32890b737485e86b712777edb7001d2f31c9c8" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "components/calendar" } \ No newline at end of file diff --git a/deps/crates/vendor/icu_calendar-v2/Cargo.lock b/deps/crates/vendor/icu_calendar-v2/Cargo.lock index 4f6b937bd7a1..4a861836abef 100644 --- a/deps/crates/vendor/icu_calendar-v2/Cargo.lock +++ b/deps/crates/vendor/icu_calendar-v2/Cargo.lock @@ -10,9 +10,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -31,9 +31,9 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base64" @@ -43,21 +43,21 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "calendrical_calculations" @@ -78,9 +78,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.57" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838" dependencies = [ "find-msvc-tools", "shlex", @@ -88,15 +88,15 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "num-traits", ] @@ -130,18 +130,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cobs" @@ -173,14 +173,13 @@ dependencies = [ [[package]] name = "console" -version = "0.15.11" +version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" dependencies = [ "encode_unicode", "libc", - "once_cell", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -194,9 +193,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" dependencies = [ "cfg-if", ] @@ -239,9 +238,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -249,18 +248,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -281,41 +280,38 @@ dependencies = [ [[package]] name = "databake-derive" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b537745234cbf0e296a3bd836d70a614dff4cb522b14e2680ef006bb1ed5ff" +checksum = "495503291b258422ea2bb9863d9f4e31eadbc5bcbdbe8b721769fa2c98dc4d41" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", "synstructure", ] [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", -] +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "either" -version = "1.15.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "encode_unicode" @@ -346,24 +342,25 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" [[package]] name = "flate2" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -401,15 +398,15 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "http" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -423,7 +420,7 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "icu_calendar" -version = "2.2.1" +version = "2.4.0" dependencies = [ "calendrical_calculations", "chrono", @@ -431,8 +428,8 @@ dependencies = [ "databake", "displaydoc", "icu_calendar_data", - "icu_locale", "icu_locale_core", + "icu_locale_fallback", "icu_provider", "insta", "itertools 0.14.0", @@ -449,33 +446,33 @@ dependencies = [ [[package]] name = "icu_calendar_data" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118577bcf3a0fa7c6ac0a7d6e951814da84ee56b9b1f68fb4d8d10b08cefaf4d" +checksum = "514da54e79efa36b5976232d5b3d1d8ee1b47b19ab658f1b1ebe39221696c2d8" [[package]] -name = "icu_collections" -version = "2.2.0" +name = "icu_locale_core" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ + "databake", "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", + "litemap", + "serde", + "tinystr", + "writeable", "zerovec", ] [[package]] -name = "icu_locale" -version = "2.2.0" +name = "icu_locale_fallback" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +checksum = "406e9ae5b95d8aa37db6293405931b766a6172d1848daee22d70eb44aa78a43c" dependencies = [ - "icu_collections", "icu_locale_core", - "icu_locale_data", + "icu_locale_fallback_data", "icu_provider", "potential_utf", "tinystr", @@ -483,30 +480,16 @@ dependencies = [ ] [[package]] -name = "icu_locale_core" -version = "2.2.0" +name = "icu_locale_fallback_data" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "serde", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locale_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" +checksum = "3632ebbd0c5c3637ba1a40bdf8288f2cb9d2268e73441a69d5fc73d7cfbaa87c" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "databake", "displaydoc", @@ -524,9 +507,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.46.3" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4" +checksum = "b67d3d2e287e4b86c10b3f3b641033d1f89b74bdb39d05f34952e2b9a6fe21cd" dependencies = [ "console", "once_cell", @@ -571,15 +554,15 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "ixdtf" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" +checksum = "4754a1731458af0443709c9667302793d3f63cc90ec4ba4c8259f2b9515478e5" [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "portable-atomic", @@ -588,20 +571,20 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ "once_cell", "wasm-bindgen", @@ -609,9 +592,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.183" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "libm" @@ -627,27 +610,27 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "log" -version = "0.4.29" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "miniz_oxide" -version = "0.8.9" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" dependencies = [ "adler2", "simd-adler32", @@ -655,9 +638,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-traits" @@ -725,15 +708,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" dependencies = [ "portable-atomic", ] @@ -750,9 +733,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "serde_core", "writeable", @@ -767,18 +750,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -811,9 +794,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -823,9 +806,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -834,9 +817,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "ring" @@ -854,9 +837,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ "bitflags", "errno", @@ -867,9 +850,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "log", "once_cell", @@ -882,18 +865,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "ring", "rustls-pki-types", @@ -902,9 +885,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "same-file" @@ -917,9 +900,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -927,29 +910,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -960,15 +943,15 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "similar" @@ -978,9 +961,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_logger" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291bee647ce7310b0ea721bfd7e0525517b4468eb7c7e15eb8bd774343179702" +checksum = "c7038d0e96661bf9ce647e1a6f6ef6d6f3663f66d9bf741abf14ba4876071c17" dependencies = [ "colored", "log", @@ -1002,9 +985,20 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.117" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -1013,13 +1007,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] @@ -1037,32 +1031,31 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "time" -version = "0.3.45" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -1074,15 +1067,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -1090,9 +1083,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "databake", "displaydoc", @@ -1118,9 +1111,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "untrusted" @@ -1163,12 +1156,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "walkdir" version = "2.5.0" @@ -1196,9 +1183,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if", "once_cell", @@ -1209,9 +1196,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1219,31 +1206,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" dependencies = [ "js-sys", "wasm-bindgen", @@ -1251,9 +1238,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "1c1c8e20c8a38fc7d65abfe74eb7280e4aa667e8eec8bc84996d2874810748d9" dependencies = [ "rustls-pki-types", ] @@ -1282,15 +1269,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -1372,15 +1350,15 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -1389,34 +1367,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", "synstructure", ] @@ -1428,9 +1406,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "zerovec", @@ -1438,9 +1416,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "databake", "serde", @@ -1451,17 +1429,23 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/deps/crates/vendor/icu_calendar-v2/Cargo.toml b/deps/crates/vendor/icu_calendar-v2/Cargo.toml index d274f60e292c..99c5e94078cf 100644 --- a/deps/crates/vendor/icu_calendar-v2/Cargo.toml +++ b/deps/crates/vendor/icu_calendar-v2/Cargo.toml @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2021" -rust-version = "1.86" +edition = "2024" +rust-version = "1.88" name = "icu_calendar" -version = "2.2.1" +version = "2.4.0" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -48,6 +48,7 @@ categories = [ ] license = "Unicode-3.0" repository = "https://github.com/unicode-org/icu4x" +resolver = "2" [package.metadata.docs.rs] all-features = true @@ -66,8 +67,8 @@ alloc = [ ] compiled_data = [ "dep:icu_calendar_data", - "dep:icu_locale", - "icu_locale?/compiled_data", + "dep:icu_locale_fallback", + "icu_locale_fallback?/compiled_data", "icu_provider/baked", ] datagen = [ @@ -77,6 +78,7 @@ datagen = [ "tinystr/databake", "alloc", "icu_provider/export", + "icu_locale_core/databake", ] default = [ "compiled_data", @@ -89,6 +91,7 @@ serde = [ "zerovec/serde", "tinystr/serde", "icu_provider/serde", + "icu_locale_core/serde", ] unstable = [] unstable_chrono_0_4 = ["dep:chrono"] @@ -126,6 +129,11 @@ name = "date" path = "benches/date.rs" harness = false +[[bench]] +name = "preferred" +path = "benches/preferred.rs" +harness = false + [[bench]] name = "until" path = "benches/until.rs" @@ -151,25 +159,25 @@ version = "0.2.3" default-features = false [dependencies.icu_calendar_data] -version = "~2.2.0" +version = "~2.4.0" optional = true default-features = false -[dependencies.icu_locale] -version = "~2.2.0" -optional = true +[dependencies.icu_locale_core] +version = "2.4.0" default-features = false -[dependencies.icu_locale_core] -version = "2.2.0" +[dependencies.icu_locale_fallback] +version = "~2.4.0" +optional = true default-features = false [dependencies.icu_provider] -version = "2.2.0" +version = "2.4.0" default-features = false [dependencies.ixdtf] -version = "0.6.5" +version = "0.6.7" optional = true default-features = false @@ -190,17 +198,17 @@ optional = true default-features = false [dependencies.tinystr] -version = "0.8.3" +version = "0.8.5" features = ["zerovec"] default-features = false [dependencies.zerovec] -version = "0.11.6" +version = "0.11.9" features = ["derive"] default-features = false [dev-dependencies.insta] -version = "1.38.0" +version = "1.43.2" [dev-dependencies.itertools] version = "0.14.0" @@ -231,8 +239,9 @@ version = "3.0.0" version = "0.5.0" [lints.clippy] -alloc-instead-of-core = "warn" -branches-sharing-code = "warn" +alloc_instead_of_core = "warn" +bool_assert_comparison = "allow" +branches_sharing_code = "warn" collection_is_never_read = "warn" crosspointer_transmute = "warn" dbg_macro = "warn" @@ -247,7 +256,7 @@ mismatching_type_param_order = "warn" missing_fields_in_debug = "warn" missing_transmute_annotations = "warn" negative_feature_names = "warn" -or-fun-call = "warn" +or_fun_call = "warn" same_functions_in_if_condition = "warn" todo = "warn" transmute_bytes_to_str = "warn" @@ -258,7 +267,7 @@ transmute_ptr_to_ref = "warn" transmute_undefined_repr = "warn" transmutes_expressible_as_ptr_casts = "warn" trivially_copy_pass_by_ref = "deny" -unnecessary-wraps = "warn" +unnecessary_wraps = "warn" useless_transmute = "warn" wildcard_dependencies = "warn" @@ -275,6 +284,7 @@ priority = 0 check-cfg = [ "cfg(icu4c_enable_renaming)", "cfg(needs_alloc_error_handler)", + "cfg(icu4x_nightly_tests)", "cfg(icu4x_run_size_tests)", "cfg(icu4x_unstable_fast_trie_only)", ] diff --git a/deps/crates/vendor/icu_calendar-v2/Cargo.toml.orig b/deps/crates/vendor/icu_calendar-v2/Cargo.toml.orig index 8d7d5e8faf02..721b86a1860e 100644 --- a/deps/crates/vendor/icu_calendar-v2/Cargo.toml.orig +++ b/deps/crates/vendor/icu_calendar-v2/Cargo.toml.orig @@ -5,7 +5,7 @@ [package] name = "icu_calendar" description = "Date APIs for Gregorian and non-Gregorian calendars" -version = "2.2.1" +version.workspace = true categories.workspace = true keywords = ["unicode", "formatting", "date"] @@ -36,7 +36,7 @@ databake = { workspace = true, features = ["derive"], optional = true } serde = { workspace = true, features = ["derive"], optional = true } icu_calendar_data = { workspace = true, optional = true } -icu_locale = { workspace = true, optional = true } +icu_locale_fallback = { workspace = true, optional = true } chrono = { workspace = true, optional = true } jiff = { workspace = true, optional = true } @@ -50,7 +50,7 @@ serde = { workspace = true, features = ["derive", "alloc"] } serde_json = { workspace = true } simple_logger = { workspace = true } ureq = { workspace = true } -insta = "1.38.0" +insta = { workspace = true } time = { workspace = true, features = ["large-dates"]} @@ -62,9 +62,9 @@ criterion = { workspace = true } default = ["compiled_data", "ixdtf"] ixdtf = ["dep:ixdtf"] logging = ["calendrical_calculations/logging"] -serde = ["dep:serde", "zerovec/serde", "tinystr/serde", "icu_provider/serde"] -datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake", "alloc", "icu_provider/export"] -compiled_data = ["dep:icu_calendar_data", "dep:icu_locale", "icu_locale?/compiled_data", "icu_provider/baked"] +serde = ["dep:serde", "zerovec/serde", "tinystr/serde", "icu_provider/serde", "icu_locale_core/serde"] +datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake", "alloc", "icu_provider/export", "icu_locale_core/databake"] +compiled_data = ["dep:icu_calendar_data", "dep:icu_locale_fallback", "icu_locale_fallback?/compiled_data", "icu_provider/baked"] unstable = [] unstable_jiff_0_2 = ["dep:jiff"] unstable_chrono_0_4 = ["dep:chrono"] @@ -84,6 +84,10 @@ harness = false name = "convert" harness = false +[[bench]] +name = "preferred" +harness = false + [[test]] name = "arithmetic" required-features = ["ixdtf"] diff --git a/deps/crates/vendor/icu_calendar-v2/README.md b/deps/crates/vendor/icu_calendar-v2/README.md index 857bddb2a154..c44496462504 100644 --- a/deps/crates/vendor/icu_calendar-v2/README.md +++ b/deps/crates/vendor/icu_calendar-v2/README.md @@ -27,7 +27,7 @@ for working with dates, encompassing information about the day, month, year, as well as the calendar type. ```rust -use icu::calendar::{types::Weekday, Date}; +use icu::calendar::{Date, types::Weekday}; // Creating ISO date: 1992-09-02. let mut date_iso = Date::try_new_iso(1992, 9, 2) @@ -46,8 +46,8 @@ assert_eq!(date_iso.days_in_month(), 30); Example of converting an ISO date across Indian and Buddhist calendars. ```rust -use icu::calendar::cal::{Buddhist, Indian}; use icu::calendar::Date; +use icu::calendar::cal::{Buddhist, Indian}; // Creating ISO date: 1992-09-02. let mut date_iso = Date::try_new_iso(1992, 9, 2) diff --git a/deps/crates/vendor/icu_calendar-v2/benches/convert.rs b/deps/crates/vendor/icu_calendar-v2/benches/convert.rs index d8d07e796972..e1959891b855 100644 --- a/deps/crates/vendor/icu_calendar-v2/benches/convert.rs +++ b/deps/crates/vendor/icu_calendar-v2/benches/convert.rs @@ -3,7 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, + BenchmarkGroup, Criterion, black_box, criterion_group, criterion_main, measurement::WallTime, }; use icu_calendar::{Calendar, Date}; diff --git a/deps/crates/vendor/icu_calendar-v2/benches/date.rs b/deps/crates/vendor/icu_calendar-v2/benches/date.rs index 4cf99b524e1c..6b8eb6b93ca3 100644 --- a/deps/crates/vendor/icu_calendar-v2/benches/date.rs +++ b/deps/crates/vendor/icu_calendar-v2/benches/date.rs @@ -18,11 +18,12 @@ struct Test { } use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, + BenchmarkGroup, Criterion, black_box, criterion_group, criterion_main, measurement::WallTime, }; use icu_calendar::{ + AsCalendar, Calendar, Date, options::{DateAddOptions, Overflow}, - types, AsCalendar, Calendar, Date, + types, }; fn bench_date<A: AsCalendar>(date: &mut Date<A>) { diff --git a/deps/crates/vendor/icu_calendar-v2/benches/preferred.rs b/deps/crates/vendor/icu_calendar-v2/benches/preferred.rs new file mode 100644 index 000000000000..8532901386c6 --- /dev/null +++ b/deps/crates/vendor/icu_calendar-v2/benches/preferred.rs @@ -0,0 +1,28 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use criterion::{Criterion, black_box, criterion_group, criterion_main}; +use icu::calendar::AnyCalendarKind; +use icu::calendar::preferences::CalendarPreferences; +use icu::locale::locale; + +/// Loading the preferred calendar is an operation often in the critical path +/// for datetime formatting. We want to keep it from regressing. See #8375. +fn preferred_benches(c: &mut Criterion) { + let prefs = &[ + CalendarPreferences::from(locale!("en")), + CalendarPreferences::from(locale!("fa")), + CalendarPreferences::from(locale!("ar-EG")), + CalendarPreferences::from(locale!("ar-SA-u-ca-islamic")), + CalendarPreferences::from(locale!("he-u-ca-hebrew")), + ]; + let mut group = c.benchmark_group("preferred"); + group.bench_function("try_new", |b| { + b.iter(|| black_box(&prefs).map(AnyCalendarKind::try_new)) + }); + group.finish(); +} + +criterion_group!(benches, preferred_benches); +criterion_main!(benches); diff --git a/deps/crates/vendor/icu_calendar-v2/benches/until.rs b/deps/crates/vendor/icu_calendar-v2/benches/until.rs index 318285750981..cde609c3e9b8 100644 --- a/deps/crates/vendor/icu_calendar-v2/benches/until.rs +++ b/deps/crates/vendor/icu_calendar-v2/benches/until.rs @@ -3,7 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, + BenchmarkGroup, Criterion, black_box, criterion_group, criterion_main, measurement::WallTime, }; use icu_calendar::options::{DateDifferenceOptions, DateDurationUnit}; use icu_calendar::types::RataDie; diff --git a/deps/crates/vendor/icu_calendar-v2/src/any_calendar.rs b/deps/crates/vendor/icu_calendar-v2/src/any_calendar.rs index 2cb820d6bcc2..16a4b64bc0be 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/any_calendar.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/any_calendar.rs @@ -7,6 +7,7 @@ #![allow(clippy::unit_arg)] use crate::cal::*; +use crate::provider::CalendarPreferredV1; use crate::{AsCalendar, Calendar, Date, Ref}; use crate::preferences::{CalendarAlgorithm, CalendarPreferences, HijriCalendarAlgorithm}; @@ -75,7 +76,7 @@ macro_rules! make_any_calendar { ) -> Result<Self::DateInner, $crate::error::DateNewError> { Ok(match self { $( - &Self::$variant(ref c) => $any_date_ident::$variant(c.new_date(year, month, day)?), + &Self::$variant(c) => $any_date_ident::$variant(c.new_date(year, month, day)?), )+ }) } @@ -87,7 +88,7 @@ macro_rules! make_any_calendar { ) -> Result<Self::DateInner, $crate::error::DateFromFieldsError> { Ok(match self { $( - &Self::$variant(ref c) => $any_date_ident::$variant(c.from_fields(fields, options)?), + &Self::$variant(c) => $any_date_ident::$variant(c.from_fields(fields, options)?), )+ }) } @@ -95,7 +96,7 @@ macro_rules! make_any_calendar { fn has_cheap_iso_conversion(&self) -> bool { match self { $( - Self::$variant(ref c) => c.has_cheap_iso_conversion(), + Self::$variant(c) => c.has_cheap_iso_conversion(), )+ } } @@ -103,7 +104,7 @@ macro_rules! make_any_calendar { fn from_iso(&self, iso: <$crate::Iso as $crate::Calendar>::DateInner) -> Self::DateInner { match self { $( - &Self::$variant(ref c) => $any_date_ident::$variant(c.from_iso(iso)), + &Self::$variant(c) => $any_date_ident::$variant(c.from_iso(iso)), )+ } } @@ -111,7 +112,7 @@ macro_rules! make_any_calendar { fn to_iso(&self, date: &Self::DateInner) -> <$crate::Iso as $crate::Calendar>::DateInner { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.to_iso(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.to_iso(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -121,7 +122,7 @@ macro_rules! make_any_calendar { fn from_rata_die(&self, rd: $crate::types::RataDie) -> Self::DateInner { match self { $( - &Self::$variant(ref c) => $any_date_ident::$variant(c.from_rata_die(rd)), + &Self::$variant(c) => $any_date_ident::$variant(c.from_rata_die(rd)), )+ } } @@ -129,7 +130,7 @@ macro_rules! make_any_calendar { fn to_rata_die(&self, date: &Self::DateInner) -> $crate::types::RataDie { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.to_rata_die(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.to_rata_die(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -139,7 +140,7 @@ macro_rules! make_any_calendar { fn months_in_year(&self, date: &Self::DateInner) -> u8 { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.months_in_year(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.months_in_year(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -149,7 +150,7 @@ macro_rules! make_any_calendar { fn days_in_year(&self, date: &Self::DateInner) -> u16 { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.days_in_year(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.days_in_year(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -159,7 +160,7 @@ macro_rules! make_any_calendar { fn days_in_month(&self, date: &Self::DateInner) -> u8 { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.days_in_month(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.days_in_month(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -169,7 +170,7 @@ macro_rules! make_any_calendar { fn year_info(&self, date: &Self::DateInner) -> $crate::types::YearInfo { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.year_info(&d).into(), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.year_info(&d).into(), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -180,7 +181,7 @@ macro_rules! make_any_calendar { fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.is_in_leap_year(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.is_in_leap_year(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -191,7 +192,7 @@ macro_rules! make_any_calendar { fn month(&self, date: &Self::DateInner) -> $crate::types::MonthInfo { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.month(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.month(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -202,7 +203,7 @@ macro_rules! make_any_calendar { fn day_of_month(&self, date: &Self::DateInner) -> $crate::types::DayOfMonth { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.day_of_month(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.day_of_month(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -213,7 +214,7 @@ macro_rules! make_any_calendar { fn day_of_year(&self, date: &Self::DateInner) -> $crate::types::DayOfYear { match (self, date) { $( - (&Self::$variant(ref c), &$any_date_ident::$variant(d)) => c.day_of_year(&d), + (&Self::$variant(c), &$any_date_ident::$variant(d)) => c.day_of_year(&d), )+ // This is only reached from misuse of from_raw, a semi-internal api _ => panic!(concat!(stringify!($any_calendar_ident), " with mismatched date type")), @@ -229,7 +230,7 @@ macro_rules! make_any_calendar { let mut date = *date; match (self, &mut date) { $( - (&Self::$variant(ref c), $any_date_ident::$variant(ref mut d)) => { + (&Self::$variant(c), $any_date_ident::$variant(d)) => { *d = c.add(d, duration, options)?; }, )+ @@ -247,7 +248,7 @@ macro_rules! make_any_calendar { ) -> $crate::types::DateDuration { match (self, date1, date2) { $( - (Self::$variant(ref c), $any_date_ident::$variant(d1), $any_date_ident::$variant(d2)) => { + (Self::$variant(c), $any_date_ident::$variant(d1), $any_date_ident::$variant(d2)) => { c.until(d1, d2, options) } )+ @@ -259,7 +260,7 @@ macro_rules! make_any_calendar { fn check_date_compatibility(&self, other: &Self) -> Result<(), Self::DateCompatibilityError> { match (self, other) { $( - (Self::$variant(ref c1), Self::$variant(ref c2)) if c1.check_date_compatibility(c2).is_ok() => { + (Self::$variant(c1), Self::$variant(c2)) if c1.check_date_compatibility(c2).is_ok() => { Ok(()) } )+ @@ -278,7 +279,7 @@ macro_rules! make_any_calendar { fn calendar_algorithm(&self) -> Option<CalendarAlgorithm> { match self { $( - Self::$variant(ref c) => c.calendar_algorithm(), + Self::$variant(c) => c.calendar_algorithm(), )+ } } @@ -352,6 +353,8 @@ make_any_calendar!( /// /// There are many ways of constructing an [`AnyCalendar`]'d date: /// ``` + /// # #![allow(clippy::eq_op)] + /// # #![allow(clippy::neg_cmp_op_on_partial_ord)] /// use icu::calendar::{AnyCalendar, AnyCalendarKind, Date, cal::{Japanese, Gregorian}, types::MonthCode}; /// use icu::locale::locale; /// use tinystr::tinystr; @@ -359,7 +362,7 @@ make_any_calendar!( /// /// let locale = locale!("en-u-ca-japanese"); // English with the Japanese calendar /// - /// let calendar = AnyCalendar::new(AnyCalendarKind::new(locale.into())); + /// let calendar = AnyCalendar::new(AnyCalendarKind::try_new(locale.into()).unwrap()); /// /// // This is a Date<AnyCalendar> /// let any_japanese_date = Date::try_new_gregorian(2020, 9, 1) @@ -403,6 +406,7 @@ make_any_calendar!( Japanese(Japanese), #[deprecated(since = "2.2.0", note = "see `Japanese`")] JapaneseExtended(Japanese), + Julian(Julian), Persian(Persian), Roc(Roc), ); @@ -420,6 +424,7 @@ make_any_calendar_impls!( Indian(Indian), Iso(Iso), Japanese(Japanese), + Julian(Julian), Persian(Persian), Roc(Roc), HijriSimulated(Hijri<hijri::AstronomicalSimulation>), @@ -471,6 +476,7 @@ impl AnyCalendar { AnyCalendarKind::Japanese | AnyCalendarKind::JapaneseExtended => { AnyCalendar::Japanese(Japanese::new()) } + AnyCalendarKind::Julian => AnyCalendar::Julian(Julian), AnyCalendarKind::Persian => AnyCalendar::Persian(Persian), AnyCalendarKind::Roc => AnyCalendar::Roc(Roc), } @@ -523,6 +529,7 @@ impl AnyCalendar { AnyCalendarKind::Japanese | AnyCalendarKind::JapaneseExtended => { AnyCalendar::Japanese(Japanese::try_new_with_buffer_provider(provider)?) } + AnyCalendarKind::Julian => AnyCalendar::Julian(Julian), AnyCalendarKind::Persian => AnyCalendar::Persian(Persian), AnyCalendarKind::Roc => AnyCalendar::Roc(Roc), }) @@ -571,6 +578,7 @@ impl AnyCalendar { AnyCalendarKind::Japanese | AnyCalendarKind::JapaneseExtended => { AnyCalendar::Japanese(Japanese::try_new_unstable(provider)?) } + AnyCalendarKind::Julian => AnyCalendar::Julian(Julian), AnyCalendarKind::Persian => AnyCalendar::Persian(Persian), AnyCalendarKind::Roc => AnyCalendar::Roc(Roc), }) @@ -618,6 +626,7 @@ impl AnyCalendar { AnyCalendarKind::Japanese | AnyCalendarKind::JapaneseExtended => { AnyCalendar::Japanese(Japanese::default()) } + AnyCalendarKind::Julian => AnyCalendar::Julian(Julian), AnyCalendarKind::Persian => AnyCalendar::Persian(Persian), AnyCalendarKind::Roc => AnyCalendar::Roc(Roc), } @@ -653,6 +662,7 @@ impl AnyCalendar { Self::Iso(_) => AnyCalendarKind::Iso, #[allow(deprecated)] Self::Japanese(_) | Self::JapaneseExtended(_) => AnyCalendarKind::Japanese, + Self::Julian(_) => AnyCalendarKind::Julian, Self::Persian(_) => AnyCalendarKind::Persian, Self::Roc(_) => AnyCalendarKind::Roc, } @@ -726,6 +736,8 @@ pub enum AnyCalendarKind { /// Deprecated, use `Japanese`. #[deprecated(since = "2.2.0", note = "use `Japanese`")] JapaneseExtended, + /// The kind of a [`Julian`] calendar + Julian, /// The kind of a [`Persian`] calendar /// /// This corresponds to the `"persian"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). @@ -737,13 +749,77 @@ pub enum AnyCalendarKind { } impl AnyCalendarKind { + #[deprecated(since = "2.2.0", note = "use `AnyCalendarKind::try_new`")] /// Selects the [`AnyCalendarKind`] appropriate for the given [`CalendarPreferences`]. pub fn new(prefs: CalendarPreferences) -> Self { + #[allow(deprecated)] prefs .resolved_algorithm() .try_into() .unwrap_or(Self::Gregorian) } + + icu_provider::gen_buffer_data_constructors!( + (prefs: CalendarPreferences) -> error: DataError, + /// Selects the [`AnyCalendarKind`] appropriate for the given [`CalendarPreferences`]. + /// + /// # Example + /// + /// ``` + /// use icu::calendar::{AnyCalendarKind, preferences::{CalendarPreferences, HijriCalendarAlgorithm}}; + /// use icu::locale::locale; + /// + /// assert_eq!(AnyCalendarKind::try_new(locale!("und").into()).unwrap(), AnyCalendarKind::Gregorian); + /// assert_eq!(AnyCalendarKind::try_new(locale!("und-US-u-ca-hebrew").into()).unwrap(), AnyCalendarKind::Hebrew); + /// assert_eq!(AnyCalendarKind::try_new(locale!("und-AF").into()).unwrap(), AnyCalendarKind::Persian); + /// assert_eq!(AnyCalendarKind::try_new(locale!("fa").into()).unwrap(), AnyCalendarKind::Persian); + /// assert_eq!(AnyCalendarKind::try_new(locale!("und-US-u-rg-thxxxx").into()).unwrap(), AnyCalendarKind::Buddhist); + /// assert_eq!( + /// AnyCalendarKind::try_new(locale!("und-US-u-ca-islamic").into()).unwrap(), + /// AnyCalendarKind::HijriTabularTypeIIFriday + /// ); + /// # assert_eq!(AnyCalendarKind::try_new("und-US-u-ca-islamic-rgsa".parse::<icu::locale::Locale>().unwrap().into()).unwrap(), + /// # AnyCalendarKind::HijriTabularTypeIIFriday + /// # ); + /// # assert_eq!(AnyCalendarKind::try_new("und-US-u-ca-islamic-foo".parse::<icu::locale::Locale>().unwrap().into()).unwrap(), + /// # AnyCalendarKind::Gregorian + /// # ); + /// # assert_eq!(AnyCalendarKind::try_new("und-US-u-ca-hebrew-foo".parse::<icu::locale::Locale>().unwrap().into()).unwrap(), + /// # AnyCalendarKind::Gregorian + /// # ); + /// ``` + ); + + #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_new)] + pub fn try_new_unstable<P: DataProvider<CalendarPreferredV1>>( + provider: &P, + mut prefs: CalendarPreferences, + ) -> Result<Self, DataError> { + if prefs.calendar_algorithm + == Some(CalendarAlgorithm::Hijri(Some(HijriCalendarAlgorithm::Rgsa))) + { + // Resolve islamic-rgsa to the region's Hijri default. + prefs.calendar_algorithm = Some(CalendarAlgorithm::Hijri(None)); + } + + let algorithm = match prefs.calendar_algorithm { + Some(algorithm) if !matches!(algorithm, CalendarAlgorithm::Hijri(None)) => algorithm, + unresolved => DataProvider::<CalendarPreferredV1>::load( + &provider, + DataRequest { + id: DataIdentifierBorrowed::for_locale(&CalendarPreferredV1::make_locale( + prefs.locale_preferences, + )), + metadata: Default::default(), + }, + )? + .payload + .get() + .resolve(unresolved), + }; + + Ok(algorithm.try_into().unwrap_or(Self::Gregorian)) + } } impl TryFrom<CalendarAlgorithm> for AnyCalendarKind { @@ -850,9 +926,9 @@ impl<C: IntoAnyCalendar> Date<C> { #[cfg(test)] mod tests { use super::*; + use crate::Ref; use crate::error::DateNewError; use crate::types::{Month, YearInput}; - use crate::Ref; #[track_caller] fn single_test_roundtrip( diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/abstract_gregorian.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/abstract_gregorian.rs index db75cbae8bc1..8d7b4fea5300 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/abstract_gregorian.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/abstract_gregorian.rs @@ -11,7 +11,7 @@ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::preferences::CalendarAlgorithm; use crate::types::EraYear; -use crate::{types, Calendar}; +use crate::{Calendar, types}; use calendrical_calculations::rata_die::RataDie; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -22,7 +22,7 @@ pub(crate) trait GregorianYears: Clone + core::fmt::Debug { const EXTENDED_YEAR_OFFSET: i32 = 0; fn extended_from_era_year(&self, era: Option<&[u8]>, year: i32) - -> Result<i32, UnknownEraError>; + -> Result<i32, UnknownEraError>; fn era_year_from_extended(&self, extended_year: i32, month: u8, day: u8) -> EraYear; diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/buddhist.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/buddhist.rs index cc54c03c3a82..3055511c665a 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/buddhist.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/buddhist.rs @@ -6,9 +6,10 @@ use crate::cal::abstract_gregorian::AbstractGregorian; use crate::error::UnknownEraError; use crate::preferences::CalendarAlgorithm; use crate::{ - cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}, + Date, RangeError, + cal::abstract_gregorian::{GregorianYears, impl_with_abstract_gregorian}, calendar_arithmetic::ArithmeticDate, - types, Date, RangeError, + types, }; use tinystr::tinystr; @@ -272,4 +273,24 @@ mod test { check_test_case(case); } } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Buddhist); + let reconstructed = Date::try_new_buddhist( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Buddhist failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/coptic.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/coptic.rs index 742989e1ec91..1e61d61e8f68 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/coptic.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/coptic.rs @@ -9,7 +9,7 @@ use crate::error::{ }; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; -use crate::{types, Calendar, Date, RangeError}; +use crate::{Calendar, Date, RangeError, types}; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; @@ -228,11 +228,7 @@ impl Calendar for Coptic { } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - if self.is_in_leap_year(date) { - 366 - } else { - 365 - } + if self.is_in_leap_year(date) { 366 } else { 365 } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { @@ -351,4 +347,24 @@ mod tests { let date = Date::try_from_fields(fields, options, Coptic).unwrap(); assert_eq!(date.day_of_month().0, 6, "Day was successfully constrained"); } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Coptic); + let reconstructed = Date::try_new_coptic( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Coptic failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/east_asian_traditional.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/east_asian_traditional.rs index aa6997be238a..03ddadf75c05 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/east_asian_traditional.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/east_asian_traditional.rs @@ -2,6 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::AsCalendar; use crate::calendar_arithmetic::{ArithmeticDate, DateFieldsResolver, PackWithMD}; use crate::error::{ DateAddError, DateError, DateFromFieldsError, DateNewError, EcmaReferenceYearError, @@ -9,8 +10,7 @@ use crate::error::{ }; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::options::{DateFromFieldsOptions, Overflow}; -use crate::AsCalendar; -use crate::{types, Calendar, Date}; +use crate::{Calendar, Date, types}; use calendrical_calculations::chinese_based; use calendrical_calculations::rata_die::RataDie; use core::cmp::Ordering; @@ -360,26 +360,26 @@ impl Rules for China { /// [Yuk Tung Liu]: https://ytliu0.github.io/ChineseCalendar/table.html /// /// ```rust -/// use icu::calendar::cal::{ChineseTraditional, KoreanTraditional}; /// use icu::calendar::Date; +/// use icu::calendar::cal::{ChineseTraditional, KoreanTraditional}; /// /// let iso_a = Date::try_new_iso(2012, 4, 23).unwrap(); /// let korean_a = iso_a.to_calendar(KoreanTraditional::new()); /// let chinese_a = iso_a.to_calendar(ChineseTraditional::new()); /// /// assert_eq!(korean_a.month().number(), 3); -/// assert_eq!(korean_a.month().to_input().is_leap(), true); +/// assert!(korean_a.month().to_input().is_leap()); /// assert_eq!(chinese_a.month().number(), 4); -/// assert_eq!(chinese_a.month().to_input().is_leap(), false); +/// assert!(!chinese_a.month().to_input().is_leap()); /// /// let iso_b = Date::try_new_iso(2012, 5, 23).unwrap(); /// let korean_b = iso_b.to_calendar(KoreanTraditional::new()); /// let chinese_b = iso_b.to_calendar(ChineseTraditional::new()); /// /// assert_eq!(korean_b.month().number(), 4); -/// assert_eq!(korean_b.month().to_input().is_leap(), false); +/// assert!(!korean_b.month().to_input().is_leap()); /// assert_eq!(chinese_b.month().number(), 4); -/// assert_eq!(chinese_b.month().to_input().is_leap(), true); +/// assert!(chinese_b.month().to_input().is_leap()); /// ``` pub type KoreanTraditional = EastAsianTraditional<Korea>; @@ -480,8 +480,8 @@ impl Date<KoreanTraditional> { /// valid range of `-9999..=9999`. /// /// ```rust - /// use icu::calendar::types::Month; /// use icu::calendar::Date; + /// use icu::calendar::types::Month; /// /// let date = Date::try_new_korean_traditional(2025, Month::new(5), 25) /// .expect("Failed to initialize Date instance."); @@ -845,8 +845,8 @@ impl Date<ChineseTraditional> { /// valid range of `-9999..=9999`. /// /// ```rust - /// use icu::calendar::types::Month; /// use icu::calendar::Date; + /// use icu::calendar::types::Month; /// /// let date = Date::try_new_chinese_traditional(2025, Month::new(5), 25) /// .expect("Failed to initialize Date instance."); @@ -1454,7 +1454,10 @@ mod test { } let rd = date.to_rata_die().to_i64_date(); let expected = case.expected; - assert_eq!(rd, expected, "RD from Chinese failed, with expected: {expected} and calculated: {rd}, for test case: {case:?}"); + assert_eq!( + rd, expected, + "RD from Chinese failed, with expected: {expected} and calculated: {rd}, for test case: {case:?}" + ); } } @@ -1469,7 +1472,10 @@ mod test { let chinese = Date::from_rata_die(rata_die, ChineseTraditional::new()); let result = chinese.to_rata_die(); - assert_eq!(result, rata_die, "Failed roundtrip RD -> Chinese -> RD for RD: {rata_die:?}, with calculated: {result:?} from Chinese date:\n{chinese:?}"); + assert_eq!( + result, rata_die, + "Failed roundtrip RD -> Chinese -> RD for RD: {rata_die:?}, with calculated: {result:?} from Chinese date:\n{chinese:?}" + ); rd += 7043; iters += 1; @@ -1744,7 +1750,10 @@ mod test { let iso = Date::try_new_iso(year, month, day).unwrap(); let chinese = iso.to_calendar(ChineseTraditional::new()); let result = chinese.to_calendar(Iso); - assert_eq!(iso, result, "ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}"); + assert_eq!( + iso, result, + "ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}" + ); } } @@ -1863,7 +1872,7 @@ mod test { #[test] #[ignore] // slow, network fn test_against_hong_kong_observatory_data() { - use crate::{cal::Gregorian, Date}; + use crate::{Date, cal::Gregorian}; let mut related_iso = 1900; let mut lunar_month = Month::new(11); @@ -1934,7 +1943,7 @@ mod test { #[test] #[ignore] // network fn test_against_kasi_data() { - use crate::{cal::Gregorian, Date}; + use crate::{Date, cal::Gregorian}; // TODO: query KASI directly let uri = "https://gist.githubusercontent.com/Manishearth/d8c94a7df22a9eacefc4472a5805322e/raw/e1ea3b0aa52428686bb3a9cd0f262878515e16c1/resolved.json"; @@ -2119,4 +2128,44 @@ mod test { packed_roundtrip_single(RANDOM2, Some(5), 18 + 2); packed_roundtrip_single(RANDOM2, Some(12), 18 + 5); } + + #[test] + fn test_chinese_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, ChineseTraditional::new()); + let reconstructed = Date::try_new_chinese_traditional( + date.year().extended_year(), + date.month().to_input(), + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Chinese Traditional failed for RD {:?}", + rd + ); + } + } + + #[test] + fn test_korean_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, KoreanTraditional::new()); + let reconstructed = Date::try_new_korean_traditional( + date.year().extended_year(), + date.month().to_input(), + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Korean Traditional failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/ethiopian.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/ethiopian.rs index 9a19f278f5bd..2424dfbf6732 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/ethiopian.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/ethiopian.rs @@ -2,8 +2,8 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::cal::coptic::{CopticDateInner, CopticYear}; use crate::cal::Coptic; +use crate::cal::coptic::{CopticDateInner, CopticYear}; use crate::calendar_arithmetic::{ArithmeticDate, DateFieldsResolver}; use crate::error::{ DateAddError, DateFromFieldsError, DateNewError, EcmaReferenceYearError, UnknownEraError, @@ -11,7 +11,7 @@ use crate::error::{ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; -use crate::{types, Calendar, Date, RangeError}; +use crate::{Calendar, Date, RangeError, types}; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; @@ -182,7 +182,7 @@ impl Calendar for Ethiopian { } fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - date.0 .0.to_rata_die() + date.0.0.to_rata_die() } fn has_cheap_iso_conversion(&self) -> bool { @@ -227,7 +227,7 @@ impl Calendar for Ethiopian { } fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let coptic_year = date.0 .0.year(); + let coptic_year = date.0.0.year(); let extended_year = coptic_year.to_ethiopian_year(self.0); if self.0 == EthiopianEraStyle::AmeteAlem || extended_year <= 0 { @@ -306,8 +306,8 @@ impl Date<Ethiopian> { /// Years are interpreted according to the provided `era_style`. /// /// ```rust - /// use icu::calendar::cal::EthiopianEraStyle; /// use icu::calendar::Date; + /// use icu::calendar::cal::EthiopianEraStyle; /// /// let date_ethiopian = /// Date::try_new_ethiopian(EthiopianEraStyle::AmeteMihret, 2014, 8, 25) @@ -413,4 +413,28 @@ mod test { 1 ); } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die( + rd, + Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteMihret), + ); + let reconstructed = Date::try_new_ethiopian( + EthiopianEraStyle::AmeteMihret, + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Ethiopian failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/gregorian.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/gregorian.rs index 5e4bb780c1be..4f357e130fa3 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/gregorian.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/gregorian.rs @@ -3,12 +3,12 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::cal::abstract_gregorian::{ - impl_with_abstract_gregorian, AbstractGregorian, GregorianYears, + AbstractGregorian, GregorianYears, impl_with_abstract_gregorian, }; use crate::calendar_arithmetic::ArithmeticDate; use crate::error::UnknownEraError; use crate::preferences::CalendarAlgorithm; -use crate::{types, Date, RangeError}; +use crate::{Date, RangeError, types}; use tinystr::tinystr; impl_with_abstract_gregorian!(Gregorian, GregorianDateInner, CeBce, _x, CeBce); @@ -317,4 +317,24 @@ mod test { } } } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Gregorian); + let reconstructed = Date::try_new_gregorian( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Gregorian failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/hebrew.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/hebrew.rs index 46f1e99ef842..eef0d242434d 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/hebrew.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/hebrew.rs @@ -2,6 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::RangeError; use crate::calendar_arithmetic::{ArithmeticDate, DateFieldsResolver, PackWithMD}; use crate::error::{ DateAddError, DateFromFieldsError, DateNewError, EcmaReferenceYearError, LunisolarDateError, @@ -10,8 +11,7 @@ use crate::error::{ use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::options::{DateFromFieldsOptions, Overflow}; use crate::types::{DateFields, LeapStatus, Month, MonthInfo}; -use crate::RangeError; -use crate::{types, Calendar, Date}; +use crate::{Calendar, Date, types}; use ::tinystr::tinystr; use calendrical_calculations::hebrew_keviyah::{Keviyah, YearInfo}; use calendrical_calculations::rata_die::RataDie; @@ -420,8 +420,8 @@ impl Date<Hebrew> { /// valid range of `-9999..=9999`. /// /// ```rust - /// use icu::calendar::types::Month; /// use icu::calendar::Date; + /// use icu::calendar::types::Month; /// /// let date = Date::try_new_hebrew_v2(5782, Month::leap(5), 7) /// .expect("Failed to initialize Date instance."); @@ -620,4 +620,24 @@ mod tests { // https://www.hebcal.com/converter?hd=1&hm=Tishrei&hy=3760&h2g=1 assert_eq!(dt.weekday(), Weekday::Saturday); } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Hebrew); + let reconstructed = Date::try_new_hebrew_v2( + date.year().extended_year(), + date.month().to_input(), + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Hebrew failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/hijri.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/hijri.rs index f0042886d9f9..391337c99e7c 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/hijri.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/hijri.rs @@ -12,8 +12,8 @@ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; use crate::types::Month; -use crate::{types, Calendar, Date}; use crate::{AsCalendar, RangeError}; +use crate::{Calendar, Date, types}; use calendrical_calculations::rata_die::RataDie; use core::cmp::Ordering; use core::fmt::Debug; @@ -836,10 +836,10 @@ fn computer_reference_years() { .extended_year; let y_30 = compute_hijri_reference_year(month, 30, rules).map(|y| y.extended_year); - if let Some(y_30) = y_30 { - if y_29 != y_30 { - println!("({month}, 30..) => {y_30},") - } + if let Some(y_30) = y_30 + && y_29 != y_30 + { + println!("({month}, 30..) => {y_30},") } if month == 11 { let y_1 = compute_hijri_reference_year(month, 1, rules) @@ -1070,8 +1070,8 @@ impl<A: AsCalendar<Calendar = Hijri<R>>, R: Rules> Date<A> { /// valid range of `-9999..=9999`. /// /// ```rust - /// use icu::calendar::cal::Hijri; /// use icu::calendar::Date; + /// use icu::calendar::cal::Hijri; /// /// let hijri = Hijri::new_umm_al_qura(); /// diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/indian.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/indian.rs index ea3a916def06..bfa1b403fe8f 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/indian.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/indian.rs @@ -10,7 +10,7 @@ use crate::error::{ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; -use crate::{types, Calendar, Date, RangeError}; +use crate::{Calendar, Date, RangeError, types}; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; @@ -210,11 +210,7 @@ impl Calendar for Indian { } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - if self.is_in_leap_year(date) { - 366 - } else { - 365 - } + if self.is_in_leap_year(date) { 366 } else { 365 } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { @@ -533,7 +529,11 @@ mod tests { let indian_i = Date::from_rata_die(rd_i, Indian); let indian_j = Date::from_rata_die(rd_j, Indian); - assert_eq!(i.cmp(&j), indian_i.cmp(&indian_j), "Directionality test failed for i: {i}, j: {j}, indian_i: {indian_i:?}, indian_j: {indian_j:?}"); + assert_eq!( + i.cmp(&j), + indian_i.cmp(&indian_j), + "Directionality test failed for i: {i}, j: {j}, indian_i: {indian_i:?}, indian_j: {indian_j:?}" + ); } } } @@ -546,8 +546,32 @@ mod tests { let indian_i = Date::from_rata_die(RataDie::new(i), Indian); let indian_j = Date::from_rata_die(RataDie::new(j), Indian); - assert_eq!(i.cmp(&j), indian_i.cmp(&indian_j), "Directionality test failed for i: {i}, j: {j}, indian_i: {indian_i:?}, indian_j: {indian_j:?}"); + assert_eq!( + i.cmp(&j), + indian_i.cmp(&indian_j), + "Directionality test failed for i: {i}, j: {j}, indian_i: {indian_i:?}, indian_j: {indian_j:?}" + ); } } } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Indian); + let reconstructed = Date::try_new_indian( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Indian failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/iso.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/iso.rs index e0bdc55dd10c..02826938d3b4 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/iso.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/iso.rs @@ -3,11 +3,11 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::cal::abstract_gregorian::{ - impl_with_abstract_gregorian, AbstractGregorian, GregorianYears, + AbstractGregorian, GregorianYears, impl_with_abstract_gregorian, }; use crate::calendar_arithmetic::ArithmeticDate; use crate::error::UnknownEraError; -use crate::{types, Date, RangeError}; +use crate::{Date, RangeError, types}; use tinystr::tinystr; /// The [ISO-8601 Calendar](https://en.wikipedia.org/wiki/ISO_8601#Dates) @@ -387,4 +387,24 @@ mod test { check(1461, 4, 12, 31); // leap year check(1462, 5, 1, 1); } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Iso); + let reconstructed = Date::try_new_iso( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "ISO failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/japanese.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/japanese.rs index 2296485e6411..712dfde17854 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/japanese.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/japanese.rs @@ -3,15 +3,14 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::cal::abstract_gregorian::{ - impl_with_abstract_gregorian, AbstractGregorian, GregorianYears, + AbstractGregorian, GregorianYears, impl_with_abstract_gregorian, }; use crate::cal::gregorian::CeBce; use crate::calendar_arithmetic::ArithmeticDate; use crate::error::{DateError, UnknownEraError}; -use crate::provider::{CalendarJapaneseModernV1, EraStartDate, PackedEra}; -use crate::{types, AsCalendar, Date}; +use crate::provider::{CalendarJapaneseModernV1, EraStartDate, JapaneseEras}; +use crate::{AsCalendar, Date, types}; use icu_provider::prelude::*; -use tinystr::{tinystr, TinyAsciiStr}; /// The [Japanese Calendar] (with modern eras only) /// @@ -37,9 +36,7 @@ use tinystr::{tinystr, TinyAsciiStr}; /// These eras are loaded from data, requiring a data provider capable of providing [`CalendarJapaneseModernV1`] /// data. #[derive(Clone, Debug, Default, Copy)] -pub struct Japanese { - post_reiwa_era: Option<PackedEra>, -} +pub struct Japanese(JapaneseEras); impl Japanese { /// Creates a new [`Japanese`] using only modern eras (post-meiji) from compiled data. @@ -49,12 +46,7 @@ impl Japanese { /// [📚 Help choosing a constructor](icu_provider::constructors) #[cfg(feature = "compiled_data")] pub const fn new() -> Self { - const { - Self { - post_reiwa_era: crate::provider::Baked::SINGLETON_CALENDAR_JAPANESE_MODERN_V1 - .last_after_reiwa(), - } - } + const { Self(*crate::provider::Baked::SINGLETON_CALENDAR_JAPANESE_MODERN_V1) } } icu_provider::gen_buffer_data_constructors!(() -> error: DataError, @@ -69,65 +61,7 @@ impl Japanese { pub fn try_new_unstable<D: DataProvider<CalendarJapaneseModernV1> + ?Sized>( provider: &D, ) -> Result<Self, DataError> { - Ok(Self { - post_reiwa_era: provider - .load(Default::default())? - .payload - .get() - .last_after_reiwa(), - }) - } -} - -impl Japanese { - fn eras(self) -> impl Iterator<Item = (EraStartDate, TinyAsciiStr<8>, u8)> { - self.post_reiwa_era.map(|p| p.unpack()).into_iter().chain([ - ( - EraStartDate { - year: 2019, - month: 5, - day: 1, - }, - tinystr!(8, "reiwa"), - 6, - ), - ( - EraStartDate { - year: 1989, - month: 1, - day: 8, - }, - tinystr!(8, "heisei"), - 5, - ), - ( - EraStartDate { - year: 1926, - month: 12, - day: 25, - }, - tinystr!(8, "showa"), - 4, - ), - ( - EraStartDate { - year: 1912, - month: 7, - day: 30, - }, - tinystr!(8, "taisho"), - 3, - ), - ( - EraStartDate { - year: 1868, - month: 10, - day: 23, - }, - tinystr!(8, "meiji"), - 2, - ), - ]) + Ok(Self(*provider.load(Default::default())?.payload.get())) } } @@ -142,8 +76,9 @@ impl GregorianYears for Japanese { } let (start, ..) = self + .0 .eras() - .find(|(_, name, _)| era == Some(name.as_bytes())) + .rfind(|(_, name, _)| era == Some(name.as_bytes())) .ok_or(UnknownEraError)?; Ok(year - 1 + start.year) @@ -152,17 +87,18 @@ impl GregorianYears for Japanese { fn era_year_from_extended(&self, year: i32, month: u8, day: u8) -> types::EraYear { let date: EraStartDate = EraStartDate { year, month, day }; - let ret = if let Some((start, code, idx)) = self.eras().find(|&(start, ..)| date >= start) { - types::EraYear { - era: code.resize(), - era_index: Some(idx), - year: year - start.year + 1, - extended_year: year, - ambiguity: types::YearAmbiguity::CenturyRequired, - } - } else { - CeBce.era_year_from_extended(year, month, day) - }; + let ret = + if let Some((start, code, idx)) = self.0.eras().rfind(|&(start, ..)| date >= start) { + types::EraYear { + era: code.resize(), + era_index: Some(idx), + year: year - start.year + 1, + extended_year: year, + ambiguity: types::YearAmbiguity::CenturyRequired, + } + } else { + CeBce.era_year_from_extended(year, month, day) + }; // Special case: Meiji 1 to 5 are treated as CE. // @@ -267,9 +203,10 @@ impl Date<Japanese> { #[cfg(test)] mod tests { use super::*; + use tinystr::tinystr; - const CALENDAR: Japanese = Japanese { - post_reiwa_era: Some(PackedEra::pack( + const CALENDAR: Japanese = Japanese( + JapaneseEras::with_last_era( EraStartDate { year: 2086, month: 11, @@ -277,8 +214,9 @@ mod tests { }, tinystr!(8, "fuzu"), 8, - )), - }; + ) + .unwrap(), + ); fn single_test_roundtrip(era: &str, year: i32, month: u8, day: u8) { let date = Date::try_new_japanese_with_calendar(era, year, month, day, CALENDAR) @@ -380,4 +318,26 @@ mod tests { single_test_era_range_roundtrip("ce", 1873, 5, 1, "meiji", 6); single_test_era_range_roundtrip("ce", 1874, 1, 1, "meiji", 7); } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Japanese::new()); + let reconstructed = Date::try_new_japanese_with_calendar( + date.era_year().era.as_str(), + date.era_year().year, + date.month().ordinal, + date.day_of_month().0, + Japanese::new(), + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Japanese failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/julian.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/julian.rs index aca19f093576..6fb03fcd9590 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/julian.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/julian.rs @@ -10,7 +10,7 @@ use crate::error::{ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; -use crate::{types, Calendar, Date, RangeError}; +use crate::{Calendar, Date, RangeError, types}; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; @@ -71,6 +71,47 @@ use tinystr::tinystr; /// The calendar was used [incorrectly](https://en.wikipedia.org/wiki/Julian_calendar#Leap_year_error) /// for a while after adoption, so the first year where the months align with this proleptic /// implementation is probably 4 CE. +/// +/// # Examples +/// +/// The `Julian` variant of [`AnyCalendar`](crate::AnyCalendar) can be used to implement a date that +/// switches between [`Julian`] and [`Gregorian`](crate::cal::Gregorian). +/// +/// ```rust +/// use icu::calendar::AnyCalendar; +/// use icu::calendar::AnyCalendarKind; +/// use icu::calendar::Date; +/// use icu::calendar::error::RangeError; +/// use icu::calendar::Gregorian; +/// +/// fn historical_french_date(year: i32, month: u8, day: u8) -> Result<Date<AnyCalendar>, RangeError> { +/// if (year, month, day) <= (1582, 10, 4) { +/// // October 4, 1582 was the last day of the Julian calendar in France +/// Ok(Date::try_new_julian(year, month, day)?.to_any()) +/// } else if (year, month, day) >= (1582, 10, 15) { +/// // October 15, 1582 was the first day of the Gregorian calendar in France +/// Ok(Date::try_new_gregorian(year, month, day)?.to_any()) +/// } else { +/// // October 5-14 did not exist in France in 1582 +/// Err(RangeError { +/// field: "day", +/// value: day.into(), +/// min: 15, +/// max: 4 +/// }) +/// } +/// } +/// +/// let julian = historical_french_date(1500, 1, 1).unwrap(); +/// let gregorian = historical_french_date(1600, 1, 1).unwrap(); +/// +/// assert_eq!(julian.calendar().kind(), AnyCalendarKind::Julian); +/// assert_eq!(gregorian.calendar().kind(), AnyCalendarKind::Gregorian); +/// +/// // Check the resolved dates in the proleptic Gregorian calendar: +/// assert_eq!(julian.to_calendar(Gregorian), Date::try_new_gregorian(1500, 1, 10).unwrap()); +/// assert_eq!(gregorian.to_calendar(Gregorian), Date::try_new_gregorian(1600, 1, 1).unwrap()); +/// ``` #[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Julian; @@ -506,4 +547,24 @@ mod test { Date::try_new_julian(-4, 2, 29).unwrap(); Date::try_new_julian(2020, 2, 29).unwrap(); } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Julian); + let reconstructed = Date::try_new_julian( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Julian failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/persian.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/persian.rs index 146f0d8c1909..637f4a81776c 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/persian.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/persian.rs @@ -10,7 +10,7 @@ use crate::error::{ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; -use crate::{types, Calendar, Date, RangeError}; +use crate::{Calendar, Date, RangeError, types}; use ::tinystr::tinystr; use calendrical_calculations::rata_die::RataDie; @@ -155,11 +155,7 @@ impl Calendar for Persian { } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - if self.is_in_leap_year(date) { - 366 - } else { - 365 - } + if self.is_in_leap_year(date) { 366 } else { 365 } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { @@ -751,4 +747,24 @@ mod tests { assert_eq!(iso_date.to_calendar(Persian), persian_date); } } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Persian); + let reconstructed = Date::try_new_persian( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Persian failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/cal/roc.rs b/deps/crates/vendor/icu_calendar-v2/src/cal/roc.rs index d0cf048c10f5..d4af987df3f3 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/cal/roc.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/cal/roc.rs @@ -3,12 +3,12 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::cal::abstract_gregorian::{ - impl_with_abstract_gregorian, AbstractGregorian, GregorianYears, + AbstractGregorian, GregorianYears, impl_with_abstract_gregorian, }; use crate::calendar_arithmetic::ArithmeticDate; use crate::error::UnknownEraError; use crate::preferences::CalendarAlgorithm; -use crate::{types, Date, RangeError}; +use crate::{Date, RangeError, types}; use tinystr::tinystr; /// The [Republic of China Calendar](https://en.wikipedia.org/wiki/Republic_of_China_calendar) @@ -171,8 +171,10 @@ mod test { roc_from_rd.day_of_month().0, ) .unwrap(); - assert_eq!(roc_from_rd, roc_from_case, - "ROC date from RD not equal to ROC generated from manually-input ymd\nCase: {case:?}\nRD: {roc_from_rd:?}\nManual: {roc_from_case:?}"); + assert_eq!( + roc_from_rd, roc_from_case, + "ROC date from RD not equal to ROC generated from manually-input ymd\nCase: {case:?}\nRD: {roc_from_rd:?}\nManual: {roc_from_case:?}" + ); } #[test] @@ -326,4 +328,24 @@ mod test { } } } + + #[test] + fn test_constructor_roundtrip() { + let rds = crate::tests::get_interesting_rds(); + for rd in rds { + let date = Date::from_rata_die(rd, Roc); + let reconstructed = Date::try_new_roc( + date.year().extended_year(), + date.month().ordinal, + date.day_of_month().0, + ) + .unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Roc failed for RD {:?}", + rd + ); + } + } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/calendar.rs b/deps/crates/vendor/icu_calendar-v2/src/calendar.rs index 25bfa4121980..10d824838adf 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/calendar.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/calendar.rs @@ -4,12 +4,12 @@ use calendrical_calculations::rata_die::RataDie; +use crate::Iso; use crate::cal::iso::IsoDateInner; use crate::error::{DateAddError, DateError, DateFromFieldsError, DateNewError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::{self, Month, YearInput}; -use crate::Iso; use core::fmt; #[cfg(doc)] diff --git a/deps/crates/vendor/icu_calendar-v2/src/calendar_arithmetic.rs b/deps/crates/vendor/icu_calendar-v2/src/calendar_arithmetic.rs index f655ea0e68c2..a2cb514c8c15 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/calendar_arithmetic.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/calendar_arithmetic.rs @@ -6,13 +6,13 @@ use calendrical_calculations::rata_die::RataDie; use crate::duration::DateDuration; use crate::error::{ - range_check, DateAddError, DateFromFieldsError, DateNewError, EcmaReferenceYearError, - LunisolarDateError, MonthError, UnknownEraError, + DateAddError, DateFromFieldsError, DateNewError, EcmaReferenceYearError, LunisolarDateError, + MonthError, UnknownEraError, range_check, }; use crate::options::{DateAddOptions, DateDifferenceOptions, DateDurationUnit}; use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; use crate::types::{DateFields, Month}; -use crate::{types, Calendar, DateError, RangeError}; +use crate::{Calendar, DateError, RangeError, types}; use core::cmp::Ordering; use core::fmt::Debug; use core::hash::{Hash, Hasher}; @@ -432,7 +432,7 @@ impl<C: DateFieldsResolver> ArithmeticDate<C> { } None => match missing_fields_strategy { MissingFieldsStrategy::Reject => { - return Err(DateFromFieldsError::NotEnoughFields) + return Err(DateFromFieldsError::NotEnoughFields); } MissingFieldsStrategy::Ecma => { let (m, d) = match (fields.month, fields.month_code, fields.ordinal_month) { @@ -464,10 +464,10 @@ impl<C: DateFieldsResolver> ArithmeticDate<C> { let extended_year = calendar.extended_year_from_era_year_unchecked(era, era_year)?; let year = calendar.year_info_from_extended(extended_year); - if let Some(extended_year) = fields.extended_year { - if calendar.extended_from_year_info(year) != extended_year { - return Err(DateFromFieldsError::InconsistentYear); - } + if let Some(extended_year) = fields.extended_year + && calendar.extended_from_year_info(year) != extended_year + { + return Err(DateFromFieldsError::InconsistentYear); } year } @@ -478,10 +478,10 @@ impl<C: DateFieldsResolver> ArithmeticDate<C> { let month = match (fields.month_code, fields.month) { (_, Some(month)) => { let computed_month = calendar.ordinal_from_month(year, month, overflow)?; - if let Some(ordinal_month) = fields.ordinal_month { - if computed_month != ordinal_month { - return Err(DateFromFieldsError::InconsistentMonth); - } + if let Some(ordinal_month) = fields.ordinal_month + && computed_month != ordinal_month + { + return Err(DateFromFieldsError::InconsistentMonth); } computed_month } @@ -491,10 +491,10 @@ impl<C: DateFieldsResolver> ArithmeticDate<C> { None => Month::try_from_utf8(month_code)?, }; let computed_month = calendar.ordinal_from_month(year, validated, overflow)?; - if let Some(ordinal_month) = fields.ordinal_month { - if computed_month != ordinal_month { - return Err(DateFromFieldsError::InconsistentMonth); - } + if let Some(ordinal_month) = fields.ordinal_month + && computed_month != ordinal_month + { + return Err(DateFromFieldsError::InconsistentMonth); } computed_month } @@ -944,11 +944,7 @@ impl<C: DateFieldsResolver> ArithmeticDate<C> { Ok(d) => d, Err(_) => { debug_assert!(false, "rata die diff out of i32 range"); - if diff > 0 { - i32::MAX - } else { - i32::MIN - } + if diff > 0 { i32::MAX } else { i32::MIN } } }; if matches!(options.largest_unit, Some(DateDurationUnit::Weeks)) { @@ -1284,8 +1280,8 @@ impl<'a, C: DateFieldsResolver> SurpassesChecker<'a, C> { mod tests { use super::*; use crate::{ - cal::{coptic::CopticYear, *}, Date, + cal::{coptic::CopticYear, *}, }; #[test] @@ -1375,12 +1371,16 @@ mod tests { ]; // Valid RDs can represent all valid years - assert!(lowest_years - .iter() - .all(|y| y <= CONSTRUCTOR_YEAR_RANGE.start())); - assert!(highest_years - .iter() - .all(|y| y >= CONSTRUCTOR_YEAR_RANGE.end())); + assert!( + lowest_years + .iter() + .all(|y| y <= CONSTRUCTOR_YEAR_RANGE.start()) + ); + assert!( + highest_years + .iter() + .all(|y| y >= CONSTRUCTOR_YEAR_RANGE.end()) + ); // All years are 21-bits assert!(-lowest_years.iter().copied().min().unwrap() < 1 << 20); diff --git a/deps/crates/vendor/icu_calendar-v2/src/chrono.rs b/deps/crates/vendor/icu_calendar-v2/src/chrono.rs index d7e7d329bf76..f1773b68df7b 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/chrono.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/chrono.rs @@ -2,11 +2,11 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::Date; +use crate::Gregorian; use crate::cal::abstract_gregorian::AbstractGregorianYear; use crate::cal::gregorian::GregorianDateInner; use crate::calendar_arithmetic::ArithmeticDate; -use crate::Date; -use crate::Gregorian; impl From<chrono::NaiveDate> for Date<Gregorian> { fn from(chrono: chrono::NaiveDate) -> Self { @@ -35,10 +35,14 @@ fn assert_range() { use crate::types::RataDie; use chrono::Datelike; - assert!(VALID_RD_RANGE - .contains(&(RataDie::new(0) + chrono::NaiveDate::MIN.num_days_from_ce() as i64))); - assert!(VALID_RD_RANGE - .contains(&(RataDie::new(0) + chrono::NaiveDate::MAX.num_days_from_ce() as i64))); + assert!( + VALID_RD_RANGE + .contains(&(RataDie::new(0) + chrono::NaiveDate::MIN.num_days_from_ce() as i64)) + ); + assert!( + VALID_RD_RANGE + .contains(&(RataDie::new(0) + chrono::NaiveDate::MAX.num_days_from_ce() as i64)) + ); } impl From<chrono::Weekday> for crate::types::Weekday { diff --git a/deps/crates/vendor/icu_calendar-v2/src/date.rs b/deps/crates/vendor/icu_calendar-v2/src/date.rs index d58854e23bff..0195c566abc3 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/date.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/date.rs @@ -8,7 +8,7 @@ use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::{CyclicYear, EraYear, IsoWeekOfYear}; use crate::week::{RelativeUnit, WeekCalculator, WeekOf}; -use crate::{types, Calendar, Iso}; +use crate::{Calendar, Iso, types}; #[cfg(feature = "alloc")] use alloc::rc::Rc; #[cfg(feature = "alloc")] @@ -170,9 +170,9 @@ impl<A: AsCalendar> Date<A> { /// # Examples /// /// ```rust - /// use icu::calendar::types::{Month, YearInput}; /// use icu::calendar::Date; /// use icu::calendar::Iso; + /// use icu::calendar::types::{Month, YearInput}; /// /// // Example: creation of ISO date from integers. /// let date_iso = Date::try_new(1970.into(), Month::new(1), 2, Iso) @@ -211,9 +211,9 @@ impl<A: AsCalendar> Date<A> { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Gregorian; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(2000); @@ -246,7 +246,7 @@ impl<A: AsCalendar> Date<A> { /// described on the [`Date`] type instead clamping the result: /// /// ```rust - /// use icu::calendar::{types::RataDie, Date, Gregorian}; + /// use icu::calendar::{Date, Gregorian, types::RataDie}; /// /// let rd = RataDie::new(1_000_000_000); /// assert_ne!(Date::from_rata_die(rd, Gregorian).to_rata_die(), rd); @@ -415,8 +415,8 @@ impl<A: AsCalendar> Date<A> { /// # Examples /// /// ``` - /// use icu::calendar::types::DateDuration; /// use icu::calendar::Date; + /// use icu::calendar::types::DateDuration; /// /// let d1 = Date::try_new_iso(2020, 1, 1).unwrap(); /// let d2 = Date::try_new_iso(2025, 10, 2).unwrap(); @@ -431,9 +431,9 @@ impl<A: AsCalendar> Date<A> { /// Reversing the order of parameters does not necessarily produce the inverse result: /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::options::{DateDifferenceOptions, DateDurationUnit}; /// use icu::calendar::types::DateDuration; - /// use icu::calendar::Date; /// /// let d1 = Date::try_new_iso(2025, 9, 30).unwrap(); /// let d2 = Date::try_new_iso(2025, 10, 31).unwrap(); @@ -528,8 +528,8 @@ impl Date<Iso> { /// # Examples /// /// ``` - /// use icu::calendar::types::IsoWeekOfYear; /// use icu::calendar::Date; + /// use icu::calendar::types::IsoWeekOfYear; /// /// let date = Date::try_new_iso(2022, 8, 26).unwrap(); /// @@ -685,9 +685,9 @@ impl<A> Copy for Date<A> where A: AsCalendar + Copy {} mod tests { use super::*; use crate::{ + Gregorian, cal::{Buddhist, Hebrew}, types::{Month, Weekday}, - Gregorian, }; #[test] diff --git a/deps/crates/vendor/icu_calendar-v2/src/duration.rs b/deps/crates/vendor/icu_calendar-v2/src/duration.rs index b58f05f2b2a4..aa4961d276d1 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/duration.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/duration.rs @@ -22,11 +22,11 @@ use crate::error::DateDurationParseError; /// # Example /// /// ```rust +/// use icu::calendar::Date; /// use icu::calendar::options::DateDifferenceOptions; /// use icu::calendar::options::DateDurationUnit; /// use icu::calendar::types::DateDuration; /// use icu::calendar::types::Weekday; -/// use icu::calendar::Date; /// /// // Creating ISO date: 1992-09-02. /// let mut date_iso = Date::try_new_iso(1992, 9, 2) diff --git a/deps/crates/vendor/icu_calendar-v2/src/error.rs b/deps/crates/vendor/icu_calendar-v2/src/error.rs index e695cbeb339b..c8f416ebf0ec 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/error.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/error.rs @@ -34,10 +34,10 @@ pub enum DateError { /// /// ``` /// # #![allow(deprecated)] - /// use icu::calendar::cal::Hebrew; - /// use icu::calendar::types::Month; /// use icu::calendar::Date; /// use icu::calendar::DateError; + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::types::Month; /// /// Date::try_new_from_codes(None, 5784, Month::leap(5).code(), 1, Hebrew) /// .expect("5784 is a leap year"); @@ -63,9 +63,9 @@ pub enum LunisolarDateError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::error::LunisolarDateError; /// use icu::calendar::types::Month; - /// use icu::calendar::Date; /// /// let err = Date::try_new_hebrew_v2(5785, Month::new(5), 50) /// .expect_err("no month has 50 days"); @@ -82,9 +82,9 @@ pub enum LunisolarDateError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::error::LunisolarDateError; /// use icu::calendar::types::Month; - /// use icu::calendar::Date; /// /// Date::try_new_hebrew_v2(5784, Month::leap(5), 1) /// .expect("5784 is a leap year"); @@ -101,9 +101,9 @@ pub enum LunisolarDateError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::error::LunisolarDateError; /// use icu::calendar::types::Month; - /// use icu::calendar::Date; /// /// let err = Date::try_new_hebrew_v2(5785, Month::leap(1), 1) /// .expect_err("Tishrei does not have a leap month"); @@ -117,9 +117,9 @@ pub enum LunisolarDateError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::error::LunisolarDateError; /// use icu::calendar::types::Month; - /// use icu::calendar::Date; /// /// let err = Date::try_new_hebrew_v2(56812, Month::leap(5), 1) /// .expect_err("56812 is too big"); @@ -143,11 +143,11 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; + /// use icu::calendar::Iso; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::error::RangeError; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; - /// use icu::calendar::Iso; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(2000); @@ -169,11 +169,11 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; + /// use icu::calendar::Iso; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::error::RangeError; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; - /// use icu::calendar::Iso; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(2000); @@ -198,10 +198,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` - /// use icu::calendar::error::DateFromFieldsError; - /// use icu::calendar::types::DateFields; /// use icu::calendar::Date; /// use icu::calendar::Iso; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(2000); @@ -220,10 +220,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(5783); @@ -241,10 +241,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(5783); @@ -262,10 +262,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; /// /// let mut fields = DateFields::default(); /// fields.era = Some(b"ce"); // valid in Gregorian, but not Hebrew @@ -285,10 +285,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Japanese; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; /// /// let mut fields = DateFields::default(); /// fields.era = Some(b"reiwa"); @@ -314,10 +314,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; /// use tinystr::tinystr; /// /// let mut fields = DateFields::default(); @@ -343,10 +343,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` - /// use icu::calendar::error::DateFromFieldsError; - /// use icu::calendar::types::{DateFields, Month}; /// use icu::calendar::Date; /// use icu::calendar::Iso; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::{DateFields, Month}; /// /// let mut fields = DateFields::default(); /// fields.extended_year = Some(2000); @@ -366,10 +366,10 @@ pub enum DateFromFieldsError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; /// use tinystr::tinystr; /// /// let mut fields = DateFields::default(); @@ -447,10 +447,10 @@ pub enum DateAddError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::error::DateAddError; /// use icu::calendar::options::{DateAddOptions, Overflow}; /// use icu::calendar::types::DateDuration; - /// use icu::calendar::Date; /// /// // There is a day 31 in October but not in November. /// let d = Date::try_new_iso(2025, 10, 31).unwrap(); @@ -477,11 +477,11 @@ pub enum DateAddError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateAddError; /// use icu::calendar::options::{DateAddOptions, Overflow}; /// use icu::calendar::types::{DateDuration, Month}; - /// use icu::calendar::Date; /// /// // Hebrew year 5784 is a leap year, 5785 is not. /// // Adar I (the leap month) is month 5 in a leap year. @@ -505,9 +505,9 @@ pub enum DateAddError { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::error::DateAddError; /// use icu::calendar::types::DateDuration; - /// use icu::calendar::Date; /// /// let d = Date::try_new_iso(2025, 1, 1).unwrap(); /// let duration = DateDuration::for_years(1_000_000); @@ -529,10 +529,10 @@ impl core::error::Error for DateAddError {} /// # Examples /// /// ``` +/// use icu::calendar::Date; /// use icu::calendar::error::MismatchedCalendarError; /// use icu::calendar::options::DateDifferenceOptions; /// use icu::calendar::options::DateDurationUnit; -/// use icu::calendar::Date; /// /// let d1 = Date::try_new_gregorian(2000, 1, 1).unwrap().to_any(); /// let d2 = Date::try_new_persian(1562, 1, 1).unwrap().to_any(); diff --git a/deps/crates/vendor/icu_calendar-v2/src/ixdtf.rs b/deps/crates/vendor/icu_calendar-v2/src/ixdtf.rs index bd89d205a32a..ac90bccc7c5d 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/ixdtf.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/ixdtf.rs @@ -11,10 +11,10 @@ use crate::types::RataDie; use crate::{AsCalendar, Calendar, Date, Iso, RangeError}; use calendrical_calculations::gregorian::fixed_from_gregorian; use icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm; +use ixdtf::ParseError as Rfc9557Error; use ixdtf::encoding::Utf8; use ixdtf::parsers::IxdtfParser; use ixdtf::records::IxdtfParseRecord; -use ixdtf::ParseError as Rfc9557Error; /// An error returned from parsing an RFC 9557 string to an `icu::calendar` type. #[derive(Debug, displaydoc::Display)] @@ -142,18 +142,17 @@ impl<A: AsCalendar> Date<A> { ) -> Result<IsoDateInner, ParseError> { let date_record = ixdtf_record.date.ok_or(ParseError::MissingFields)?; - if let Some(ixdtf_calendar) = ixdtf_record.calendar { - if let Some(expected_calendar) = calendar { - if ixdtf_calendar != expected_calendar.as_str().as_bytes() { - return Err(ParseError::MismatchedCalendar( - expected_calendar, - icu_locale_core::extensions::unicode::Value::try_from_utf8(ixdtf_calendar) - .ok() - .and_then(|v| CalendarAlgorithm::try_from(&v).ok()) - .ok_or(ParseError::UnknownCalendar)?, - )); - } - } + if let Some(ixdtf_calendar) = ixdtf_record.calendar + && let Some(expected_calendar) = calendar + && ixdtf_calendar != expected_calendar.as_str().as_bytes() + { + return Err(ParseError::MismatchedCalendar( + expected_calendar, + icu_locale_core::extensions::unicode::Value::try_from_utf8(ixdtf_calendar) + .ok() + .and_then(|v| CalendarAlgorithm::try_from(&v).ok()) + .ok_or(ParseError::UnknownCalendar)?, + )); } // `date_record` is in `VALID_RD_RANGE` by `ixdtf` invariants diff --git a/deps/crates/vendor/icu_calendar-v2/src/jiff.rs b/deps/crates/vendor/icu_calendar-v2/src/jiff.rs index 5e1daff3e9f3..c06264b9efbf 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/jiff.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/jiff.rs @@ -2,11 +2,11 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::Date; +use crate::Gregorian; use crate::cal::abstract_gregorian::AbstractGregorianYear; use crate::cal::gregorian::GregorianDateInner; use crate::calendar_arithmetic::ArithmeticDate; -use crate::Date; -use crate::Gregorian; impl From<jiff::civil::Date> for Date<Gregorian> { fn from(jiff: jiff::civil::Date) -> Self { diff --git a/deps/crates/vendor/icu_calendar-v2/src/lib.rs b/deps/crates/vendor/icu_calendar-v2/src/lib.rs index f3d31e885fa0..28cb21d0da9d 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/lib.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/lib.rs @@ -40,7 +40,7 @@ //! as well as the calendar type. //! //! ```rust -//! use icu::calendar::{types::Weekday, Date}; +//! use icu::calendar::{Date, types::Weekday}; //! //! // Creating ISO date: 1992-09-02. //! let mut date_iso = Date::try_new_iso(1992, 9, 2) @@ -59,8 +59,8 @@ //! Example of converting an ISO date across Indian and Buddhist calendars. //! //! ```rust -//! use icu::calendar::cal::{Buddhist, Indian}; //! use icu::calendar::Date; +//! use icu::calendar::cal::{Buddhist, Indian}; //! //! // Creating ISO date: 1992-09-02. //! let mut date_iso = Date::try_new_iso(1992, 9, 2) diff --git a/deps/crates/vendor/icu_calendar-v2/src/options.rs b/deps/crates/vendor/icu_calendar-v2/src/options.rs index dc0b515239db..68eb91c4361d 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/options.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/options.rs @@ -15,11 +15,11 @@ pub struct DateFromFieldsOptions { /// # Examples /// /// ``` + /// use icu::calendar::Date; + /// use icu::calendar::Iso; /// use icu::calendar::options::DateFromFieldsOptions; /// use icu::calendar::options::Overflow; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; - /// use icu::calendar::Iso; /// /// // There is no day 31 in September. /// let mut fields = DateFields::default(); @@ -50,11 +50,11 @@ pub struct DateFromFieldsOptions { /// # Examples /// /// ``` + /// use icu::calendar::Date; + /// use icu::calendar::Iso; /// use icu::calendar::options::DateFromFieldsOptions; /// use icu::calendar::options::MissingFieldsStrategy; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; - /// use icu::calendar::Iso; /// /// // These options are missing a year. /// let mut fields = DateFields::default(); @@ -90,10 +90,10 @@ pub struct DateAddOptions { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::options::DateAddOptions; /// use icu::calendar::options::Overflow; /// use icu::calendar::types::DateDuration; - /// use icu::calendar::Date; /// /// // There is a day 31 in October but not in November. /// let d1 = Date::try_new_iso(2025, 10, 31).unwrap(); @@ -139,10 +139,10 @@ pub struct DateDifferenceOptions { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::options::DateDifferenceOptions; /// use icu::calendar::options::DateDurationUnit; /// use icu::calendar::types::DateDuration; - /// use icu::calendar::Date; /// /// let d1 = Date::try_new_iso(2025, 3, 31).unwrap(); /// let d2 = Date::try_new_iso(2026, 5, 15).unwrap(); @@ -221,12 +221,12 @@ pub enum Overflow { /// # Examples /// /// ``` + /// use icu::calendar::Date; + /// use icu::calendar::DateError; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::options::DateFromFieldsOptions; /// use icu::calendar::options::Overflow; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; - /// use icu::calendar::DateError; /// /// let mut options = DateFromFieldsOptions::default(); /// options.overflow = Some(Overflow::Constrain); @@ -260,12 +260,12 @@ pub enum Overflow { /// # Examples /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Hebrew; /// use icu::calendar::error::DateFromFieldsError; /// use icu::calendar::options::DateFromFieldsOptions; /// use icu::calendar::options::Overflow; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; /// use tinystr::tinystr; /// /// let mut options = DateFromFieldsOptions::default(); @@ -371,9 +371,9 @@ pub enum DateDurationUnit { #[cfg(test)] mod tests { use crate::{ + Date, Gregorian, error::DateFromFieldsError, types::{DateFields, Month}, - Date, Gregorian, }; use itertools::Itertools; use std::collections::{BTreeMap, BTreeSet}; diff --git a/deps/crates/vendor/icu_calendar-v2/src/preferences.rs b/deps/crates/vendor/icu_calendar-v2/src/preferences.rs index 598fa2924634..2c39fb1eb4fc 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/preferences.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/preferences.rs @@ -47,6 +47,7 @@ impl CalendarPreferences { /// # Example /// /// ``` + /// # #![allow(deprecated)] /// use icu::calendar::preferences::{CalendarAlgorithm, CalendarPreferences, HijriCalendarAlgorithm}; /// use icu::locale::locale; /// @@ -68,8 +69,9 @@ impl CalendarPreferences { /// # CalendarAlgorithm::Gregory /// # ); /// ``` + #[deprecated(since = "2.3.0")] pub fn resolved_algorithm(self) -> CalendarAlgorithm { - use icu_locale_core::subtags::{region, Region}; + use icu_locale_core::subtags::{Region, region}; const AE: Region = region!("AE"); const BH: Region = region!("BH"); const KW: Region = region!("KW"); diff --git a/deps/crates/vendor/icu_calendar-v2/src/provider.rs b/deps/crates/vendor/icu_calendar-v2/src/provider.rs index 9637cd52dc01..7f4c532f1dbb 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/provider.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/provider.rs @@ -15,13 +15,16 @@ // Provider structs must be stable #![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] +use core::fmt::Debug; use core::num::NonZeroU8; use crate::types::Weekday; +use icu_locale_core::preferences::extensions::unicode::keywords::{ + CalendarAlgorithm, HijriCalendarAlgorithm, +}; use icu_provider::fallback::{LocaleFallbackConfig, LocaleFallbackPriority}; use icu_provider::prelude::*; use tinystr::TinyAsciiStr; -use zerovec::ZeroVec; #[cfg(feature = "compiled_data")] #[derive(Debug)] @@ -40,10 +43,10 @@ const _: () = { use icu_calendar_data::*; pub mod icu { pub use crate as calendar; - pub use icu_locale as locale; } make_provider!(Baked); impl_calendar_japanese_modern_v1!(Baked); + impl_calendar_preferred_v1!(Baked); impl_calendar_week_v1!(Baked); }; @@ -51,7 +54,7 @@ icu_provider::data_marker!( /// Modern Japanese era names CalendarJapaneseModernV1, "calendar/japanese/modern/v1", - JapaneseEras<'static>, + JapaneseEras, is_singleton = true ); @@ -67,9 +70,196 @@ icu_provider::data_marker!( }, ); +/// Default calendar preferences for a region. +#[derive(Debug, Clone, Copy, PartialEq, Eq, yoke::Yokeable, zerofrom::ZeroFrom)] +#[cfg_attr(feature = "datagen", derive(databake::Bake))] +#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))] +pub struct CalendarPreference { + /// The default calendar to use for this region. + pub default_algorithm: CalendarAlgorithm, + /// The default Hijri calendar to use for this region. + pub default_hijri_algorithm: HijriCalendarAlgorithm, +} + +#[cfg(any(feature = "serde", feature = "datagen"))] +#[derive(serde::Serialize, serde::Deserialize)] +struct CalendarPreferenceHuman<'a> { + #[serde(borrow)] + default_algorithm: &'a str, + #[serde(borrow)] + default_hijri_algorithm: &'a str, +} + +#[cfg(feature = "datagen")] +impl serde::Serialize for CalendarPreference { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + let human = CalendarPreferenceHuman { + default_algorithm: self.default_algorithm.as_str(), + default_hijri_algorithm: CalendarAlgorithm::Hijri(Some( + self.default_hijri_algorithm, + )) + .as_str(), + }; + return human.serialize(serializer); + } + + let default = match self.default_algorithm { + CalendarAlgorithm::Buddhist => 1u8, + CalendarAlgorithm::Chinese => 2, + CalendarAlgorithm::Coptic => 3, + CalendarAlgorithm::Dangi => 4, + CalendarAlgorithm::Ethioaa => 5, + CalendarAlgorithm::Ethiopic => 6, + CalendarAlgorithm::Gregory => 7, + CalendarAlgorithm::Hebrew => 8, + CalendarAlgorithm::Indian => 9, + CalendarAlgorithm::Hijri(Some(s)) if s == self.default_hijri_algorithm => 10, + CalendarAlgorithm::Iso8601 => 11, + CalendarAlgorithm::Japanese => 12, + CalendarAlgorithm::Persian => 13, + CalendarAlgorithm::Roc => 14, + _ => { + debug_assert!( + false, + "unknown calendar algorithm: {:?}", + self.default_algorithm + ); + 0 + } + }; + let hijri = match self.default_hijri_algorithm { + HijriCalendarAlgorithm::Umalqura => 1, + HijriCalendarAlgorithm::Tbla => 2, + HijriCalendarAlgorithm::Civil => 3, + HijriCalendarAlgorithm::Rgsa => 4, + _ => { + debug_assert!( + false, + "unknown hijri algorithm: {:?}", + self.default_hijri_algorithm + ); + 0 + } + }; + + (default << 3 | hijri).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for CalendarPreference { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + let human = CalendarPreferenceHuman::deserialize(deserializer)?; + let default_val = + icu_locale_core::extensions::unicode::Value::try_from_str(human.default_algorithm) + .map_err(serde::de::Error::custom)?; + let default_algorithm = + CalendarAlgorithm::try_from(&default_val).map_err(serde::de::Error::custom)?; + let hijri_val = icu_locale_core::extensions::unicode::Value::try_from_str( + human.default_hijri_algorithm, + ) + .map_err(serde::de::Error::custom)?; + let default_hijri_algorithm = match CalendarAlgorithm::try_from(&hijri_val) { + Ok(CalendarAlgorithm::Hijri(Some(h))) => h, + _ => return Err(serde::de::Error::custom("expected islamic-* calendar")), + }; + return Ok(Self { + default_algorithm, + default_hijri_algorithm, + }); + } + + let packed = u8::deserialize(deserializer)?; + let default_algorithm = packed >> 3; + let default_hijri_algorithm = packed & 0x07; + let default_hijri_algorithm = match default_hijri_algorithm { + 1 => HijriCalendarAlgorithm::Umalqura, + 2 => HijriCalendarAlgorithm::Tbla, + 3 => HijriCalendarAlgorithm::Civil, + 4 => HijriCalendarAlgorithm::Rgsa, + _ => { + debug_assert!( + false, + "unknown hijri algorithm discriminant: {default_hijri_algorithm}" + ); + HijriCalendarAlgorithm::Civil + } + }; + let default_algorithm = match default_algorithm { + 1 => CalendarAlgorithm::Buddhist, + 2 => CalendarAlgorithm::Chinese, + 3 => CalendarAlgorithm::Coptic, + 4 => CalendarAlgorithm::Dangi, + 5 => CalendarAlgorithm::Ethioaa, + 6 => CalendarAlgorithm::Ethiopic, + 7 => CalendarAlgorithm::Gregory, + 8 => CalendarAlgorithm::Hebrew, + 9 => CalendarAlgorithm::Indian, + 10 => CalendarAlgorithm::Hijri(Some(default_hijri_algorithm)), + 11 => CalendarAlgorithm::Iso8601, + 12 => CalendarAlgorithm::Japanese, + 13 => CalendarAlgorithm::Persian, + 14 => CalendarAlgorithm::Roc, + _ => { + debug_assert!( + false, + "unknown calendar algorithm discriminant: {default_algorithm}" + ); + CalendarAlgorithm::Gregory + } + }; + Ok(Self { + default_algorithm, + default_hijri_algorithm, + }) + } +} + +impl CalendarPreference { + /// Resolves a [`Option<CalendarAlgorithm>`] to a concrete algorithm against these preferences. + pub fn resolve(&self, unresolved: Option<CalendarAlgorithm>) -> CalendarAlgorithm { + match unresolved { + Some(CalendarAlgorithm::Hijri(None)) => { + CalendarAlgorithm::Hijri(Some(self.default_hijri_algorithm)) + } + Some(a) => a, + None => self.default_algorithm, + } + } +} + +icu_provider::data_marker!( + /// The preferred calendar algorithm for a region. + CalendarPreferredV1, + "calendar/preferred/v1", + CalendarPreference, + fallback_config = { + let mut config = LocaleFallbackConfig::default(); + config.priority = LocaleFallbackPriority::Region; + config + }, +); + +icu_provider::data_struct!( + CalendarPreference, + #[cfg(feature = "datagen")] +); + #[cfg(feature = "datagen")] /// The latest minimum set of markers required by this component. -pub const MARKERS: &[DataMarkerInfo] = &[CalendarJapaneseModernV1::INFO, CalendarWeekV1::INFO]; +pub const MARKERS: &[DataMarkerInfo] = &[ + CalendarJapaneseModernV1::INFO, + CalendarWeekV1::INFO, + CalendarPreferredV1::INFO, +]; /// The date at which an era started /// @@ -105,58 +295,236 @@ pub struct EraStartDate { /// including in SemVer minor releases. While the serde representation of data structs is guaranteed /// to be stable, their Rust representation might not be. Use with caution. /// </div> -#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct JapaneseEras<'data> { - /// A map from era start dates to their era codes - #[cfg_attr(feature = "serde", serde(borrow))] - pub dates_to_eras: ZeroVec<'data, (EraStartDate, TinyAsciiStr<16>)>, -} +#[derive(Debug, PartialEq, Clone, Copy, Default, yoke::Yokeable, zerofrom::ZeroFrom)] +pub struct JapaneseEras(Option<PackedEra>); icu_provider::data_struct!( - JapaneseEras<'_>, + JapaneseEras, #[cfg(feature = "datagen")] ); -impl JapaneseEras<'_> { - pub(crate) const fn last_after_reiwa(&self) -> Option<PackedEra> { - let Some(&zerovec::ule::tuple::Tuple2ULE(start, code)) = - self.dates_to_eras.as_slice().as_ule_slice().last() - else { +impl JapaneseEras { + /// Creates a new [`JapaneseEras`] without a post-Reiwa era. + pub const fn up_to_reiwa() -> Self { + Self(None) + } + + /// Creates a new [`JapaneseEras`] with the last post-Reiwa era's start date, code, and index. + pub const fn with_last_era( + start: EraStartDate, + code: TinyAsciiStr<8>, + index: u8, + ) -> Option<Self> { + if start.year < 2026 { + return Some(Self::up_to_reiwa()); + } + let Some(packed) = PackedEra::pack(start, code, index) else { return None; }; - if start.year.as_signed_int() < 2026 { - return None; + Some(Self(Some(packed))) + } + + /// Returns all post-Meji eras, in chronological order. + pub fn eras(self) -> impl DoubleEndedIterator<Item = (EraStartDate, TinyAsciiStr<8>, u8)> { + use tinystr::tinystr; + [ + ( + EraStartDate { + year: 1868, + month: 10, + day: 23, + }, + tinystr!(8, "meiji"), + 2, + ), + ( + EraStartDate { + year: 1912, + month: 7, + day: 30, + }, + tinystr!(8, "taisho"), + 3, + ), + ( + EraStartDate { + year: 1926, + month: 12, + day: 25, + }, + tinystr!(8, "showa"), + 4, + ), + ( + EraStartDate { + year: 1989, + month: 1, + day: 8, + }, + tinystr!(8, "heisei"), + 5, + ), + ( + EraStartDate { + year: 2019, + month: 5, + day: 1, + }, + tinystr!(8, "reiwa"), + 6, + ), + ] + .into_iter() + .chain(self.0.map(PackedEra::unpack)) + } +} + +#[cfg(feature = "datagen")] +impl databake::Bake for JapaneseEras { + fn bake(&self, ctx: &databake::CrateEnv) -> databake::TokenStream { + ctx.insert("icu_calendar"); + if let Some((era_start_date, code, idx)) = self.eras().last() + && code != "reiwa" + { + let era_start_date = era_start_date.bake(ctx); + let code = code.bake(ctx); + let idx = idx.bake(ctx); + databake::quote! { + icu_calendar::provider::JapaneseEras::with_last_era(#era_start_date, #code, #idx).unwrap() + } + } else { + databake::quote! { + icu_calendar::provider::JapaneseEras::up_to_reiwa() + } } - Some(PackedEra::pack( - EraStartDate { - year: start.year.as_signed_int(), - month: start.month, - day: start.day, - }, + } +} + +#[cfg(feature = "datagen")] +impl databake::BakeSize for JapaneseEras { + fn borrows_size(&self) -> usize { + 0 + } +} + +#[cfg(feature = "datagen")] +impl serde::Serialize for JapaneseEras { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + use zerovec::ZeroVec; + + #[derive(serde::Serialize)] + struct Raw<'data> { + pub dates_to_eras: ZeroVec<'data, (EraStartDate, TinyAsciiStr<16>)>, + } + + let mut dates_to_eras = self + .eras() + .map(|(start, code, _)| (start, code.resize())) + .collect::<ZeroVec<_>>(); + + while let Some((start, code, index)) = self.eras().last() + && dates_to_eras.len() + 2 <= index as usize + { + use zerovec::ule::AsULE; + + dates_to_eras.with_mut(|v| v.push((start, code.resize()).to_unaligned())); + } + + Raw { dates_to_eras }.serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for JapaneseEras { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + use serde::de::Error; + use zerovec::ZeroVec; + + #[derive(serde::Deserialize)] + struct Raw<'data> { + #[serde(borrow)] + pub dates_to_eras: ZeroVec<'data, (EraStartDate, TinyAsciiStr<16>)>, + } + + let Raw { dates_to_eras } = Raw::deserialize(deserializer)?; + + let Some((start, code)) = dates_to_eras.last() else { + return Err(D::Error::custom("At least one era is required")); + }; + + if Self::up_to_reiwa() + .eras() + .map(|(start, code, ..)| (start, code.resize())) + .ne(dates_to_eras + .iter() + .take(Self::up_to_reiwa().eras().count())) + { + return Err(D::Error::custom( + "Invalid era data: Meiji through Reiwa must be present and in order", + )); + } + + Self::with_last_era( + start, code.resize(), - self.dates_to_eras.as_slice().len() as u8 + 1, - )) + dates_to_eras.as_slice().len() as u8 + 1, + ) + .ok_or_else(|| D::Error::custom("Invalid era")) } } /// A type to represent a modern (post 2026, 8-byte code) era. -#[derive(Debug, PartialEq, Copy, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -pub(crate) struct PackedEra(NonZeroU8 /* give a niche */, [u8; 6]); +/// +/// <div class="stab unstable"> +/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. While the serde representation of data structs is guaranteed +/// to be stable, their Rust representation might not be. Use with caution. +/// </div> +#[derive(PartialEq, Copy, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] +struct PackedEra(NonZeroU8 /* give a niche */, [u8; 6]); + +impl Debug for PackedEra { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let (start, code, index) = self.unpack(); + f.debug_struct("PackedEra") + .field("start", &start) + .field("code", &code) + .field("index", &index) + .field("<packed>", &(self.0, self.1)) + .finish() + } +} impl PackedEra { /// Construct a `PackedEra` from a tuple /// This supports start dates until 2086-12-31, indices 7 and 8, and lower ASCII alphabetic codes - pub const fn pack(start: EraStartDate, code: TinyAsciiStr<8>, index: u8) -> Self { - debug_assert!(start.day < 1 << 5); // 5 bits - debug_assert!(start.month < 1 << 4); // 4 bits - debug_assert!(2026 <= start.year && start.year < 2026 + (1 << 6)); // 6 bits - - debug_assert!(7 <= index && index < 7 + (1 << 1)); // 1 bit - - debug_assert!(code.is_ascii_alphabetic_lowercase()); // 40 bits + const fn pack(start: EraStartDate, code: TinyAsciiStr<8>, index: u8) -> Option<Self> { + // 5 bits + if !(0 < start.day && start.day < 1 << 5) { + return None; + } + // 4 bits + if !(0 < start.month && start.month < 1 << 4) { + return None; + } + // 6 bits + if !(2026 <= start.year && start.year < 2026 + (1 << 6)) { + return None; + } + // 1 bit + if !(7 <= index && index < 7 + (1 << 1)) { + return None; + } + // 40 bits + if !code.is_ascii_alphabetic_lowercase() { + return None; + } let mut packed = 0; @@ -177,14 +545,15 @@ impl PackedEra { let [a, b, c, d, e, f, g, z] = packed.to_le_bytes(); debug_assert!(z == 0); - // the lowest byte contains month and day, so it's non-zero - debug_assert!(a > 0); - Self(unsafe { NonZeroU8::new_unchecked(a) }, [b, c, d, e, f, g]) + let Some(a) = NonZeroU8::new(a) else { + return None; + }; + Some(Self(a, [b, c, d, e, f, g])) } /// Convert a `PackedEra` into a tuple of start date, code, and /// [`era_index`](crate::types::EraYear::era_index) - pub const fn unpack(self) -> (EraStartDate, TinyAsciiStr<8>, u8) { + const fn unpack(self) -> (EraStartDate, TinyAsciiStr<8>, u8) { let Self(a, [b, c, d, e, f, g]) = self; let mut packed = u64::from_le_bytes([a.get(), b, c, d, e, f, g, 0]); @@ -226,7 +595,7 @@ impl PackedEra { } #[test] -fn packed_era_size() { +fn japanese_eras_size() { assert_eq!(size_of::<PackedEra>(), 7); assert_eq!(size_of::<Option<PackedEra>>(), 7); assert_eq!(size_of::<crate::cal::Japanese>(), 7); @@ -234,7 +603,7 @@ fn packed_era_size() { } #[test] -fn packed_era_roundtrip() { +fn japanese_eras_packing() { let start = EraStartDate { year: 2086, month: 11, @@ -242,10 +611,70 @@ fn packed_era_roundtrip() { }; let code = tinystr::tinystr!(8, "fuzu"); let index = 8; + assert_eq!( - PackedEra::pack(start, code, index).unpack(), + JapaneseEras::with_last_era(start, code, index) + .unwrap() + .eras() + .last() + .unwrap(), (start, code, index) ); + assert_ne!( + JapaneseEras::up_to_reiwa().eras().last().unwrap(), + (start, code, index) + ); +} + +#[test] +fn japanese_eras_serde_roundtrip() { + let eras = JapaneseEras::with_last_era( + EraStartDate { + year: 2086, + month: 11, + day: 1, + }, + tinystr::tinystr!(8, "fuzu"), + 8, + ) + .unwrap(); + + assert_eq!( + serde_json::from_str::<JapaneseEras>(&serde_json::to_string(&eras).unwrap()).unwrap(), + eras + ); + + let eras = JapaneseEras::up_to_reiwa(); + + assert_eq!( + serde_json::from_str::<JapaneseEras>(&serde_json::to_string(&eras).unwrap()).unwrap(), + eras + ); +} + +#[test] +fn japanese_eras_bake() { + databake::test_bake!( + JapaneseEras, + const, + crate::provider::JapaneseEras::with_last_era( + crate::provider::EraStartDate { + year: 2086i32, + month: 11u8, + day: 1u8, + }, + tinystr::tinystr!(8usize, "fuzu"), + 8u8 + ) + .unwrap(), + icu_calendar + ); + databake::test_bake!( + JapaneseEras, + const, + crate::provider::JapaneseEras::up_to_reiwa(), + icu_calendar + ); } /// An ICU4X mapping to a subset of CLDR weekData. diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/constructor_roundtrip.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/constructor_roundtrip.rs new file mode 100644 index 000000000000..0ec3887fa3cf --- /dev/null +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/constructor_roundtrip.rs @@ -0,0 +1,221 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::Calendar; +use crate::Date; +use crate::error::DateFromFieldsError; +use crate::options::{DateFromFieldsOptions, Overflow}; +use crate::types::DateFields; +use calendrical_calculations::rata_die::RataDie; + +// We could use the `bitflags` crate here, but we are using raw constants +// to avoid pulling in an extra dependency. +type Flags = u32; +const EXTENDED_YEAR: u32 = 1 << 0; +const ERA: u32 = 1 << 1; +const ERA_YEAR: u32 = 1 << 2; +const MONTH: u32 = 1 << 3; +const MONTH_CODE: u32 = 1 << 4; +const ORDINAL_MONTH: u32 = 1 << 5; +const DAY: u32 = 1 << 6; +const MAKE_INCONSISTENT_YEAR: u32 = 1 << 7; +const MAKE_INCONSISTENT_MONTH: u32 = 1 << 8; + +fn try_from_fields_helper<C: Calendar + Copy>( + flags: Flags, + rd: RataDie, + options: DateFromFieldsOptions, + cal: C, +) -> Result<Date<C>, DateFromFieldsError> { + let date = Date::from_rata_die(rd, cal); + let mut fields = DateFields::default(); + + if flags & EXTENDED_YEAR != 0 { + fields.extended_year = Some(date.year().extended_year()); + } + + let era_bytes = date.year().era().map(|ey| ey.era); + if flags & ERA != 0 + && let Some(ref eb) = era_bytes + { + fields.era = Some(eb.as_bytes()); + } + if flags & ERA_YEAR != 0 + && let Some(ey) = date.year().era() + { + fields.era_year = Some(ey.year); + } + + let month_input = date.month().to_input(); + if flags & MONTH != 0 { + fields.month = Some(month_input); + } + + let month_code_holder = month_input.code(); + if flags & MONTH_CODE != 0 { + fields.month_code = Some(month_code_holder.0.as_bytes()); + } + if flags & ORDINAL_MONTH != 0 { + fields.ordinal_month = Some(date.month().ordinal); + } + if flags & DAY != 0 { + fields.day = Some(date.day_of_month().0); + } + + if flags & MAKE_INCONSISTENT_YEAR != 0 + && let Some(ref mut y) = fields.extended_year + { + *y += 1; + } + + if flags & MAKE_INCONSISTENT_MONTH != 0 + && let Some(ref mut m) = fields.ordinal_month + { + *m = if *m == 1 { 2 } else { 1 }; + } + + Date::try_from_fields(fields, options, cal) +} + +super::test_all_cals!( + fn check_constructor_roundtrip<C: Calendar + Copy>(cal: C) { + let rds = crate::tests::get_interesting_rds(); + + for rd in rds { + let date = Date::from_rata_die(rd, cal); + + for overflow in [Overflow::Reject, Overflow::Constrain] { + let options = DateFromFieldsOptions { + overflow: Some(overflow), + ..Default::default() + }; + + // Test 1: extended_year + month + day + let result = try_from_fields_helper(EXTENDED_YEAR | MONTH | DAY, rd, options, cal); + assert_eq!( + result.unwrap().to_rata_die(), + rd, + "Failed roundtrip for extended_year + month + day at RD {:?}", + rd + ); + + // Test 2: extended_year + month_code + day + let result = + try_from_fields_helper(EXTENDED_YEAR | MONTH_CODE | DAY, rd, options, cal); + assert_eq!( + result.unwrap().to_rata_die(), + rd, + "Failed roundtrip for extended_year + month_code + day at RD {:?}", + rd + ); + + // Test 3: extended_year + ordinal_month + day + let result = + try_from_fields_helper(EXTENDED_YEAR | ORDINAL_MONTH | DAY, rd, options, cal); + assert_eq!( + result.unwrap().to_rata_die(), + rd, + "Failed roundtrip for extended_year + ordinal_month + day at RD {:?}", + rd + ); + + // Test 4: era + era_year + month + day (if era exists) + if date.year().era().is_some() { + let result = + try_from_fields_helper(ERA | ERA_YEAR | MONTH | DAY, rd, options, cal); + assert_eq!( + result.unwrap().to_rata_die(), + rd, + "Failed roundtrip for era + era_year + month + day at RD {:?}", + rd + ); + } + + // Test 5: Both extended_year and era+era_year + if date.year().era().is_some() { + let result = try_from_fields_helper( + EXTENDED_YEAR | ERA | ERA_YEAR | MONTH | DAY, + rd, + options, + cal, + ); + assert_eq!( + result.unwrap().to_rata_die(), + rd, + "Failed roundtrip for both year fields at RD {:?}", + rd + ); + } + + // Test 6: Date::try_new + let extended_year = date.year().extended_year(); + let month = date.month().to_input(); + let day = date.day_of_month().0; + let reconstructed = Date::try_new(extended_year.into(), month, day, cal).unwrap(); + assert_eq!( + reconstructed.to_rata_die(), + rd, + "Failed roundtrip for Date::try_new at RD {:?}", + rd + ); + + // Negative Test 1: Inconsistent year + if date.year().era().is_some() { + let result = try_from_fields_helper( + EXTENDED_YEAR | ERA | ERA_YEAR | MONTH | DAY | MAKE_INCONSISTENT_YEAR, + rd, + options, + cal, + ); + assert_eq!( + result.map(|d| d.to_rata_die()), + Err(DateFromFieldsError::InconsistentYear), + "Expected InconsistentYear for RD {:?}", + rd + ); + } + + // Negative Test 2: Inconsistent month + if date.months_in_year() >= 2 { + let result = try_from_fields_helper( + EXTENDED_YEAR | MONTH | ORDINAL_MONTH | DAY | MAKE_INCONSISTENT_MONTH, + rd, + options, + cal, + ); + assert_eq!( + result.map(|d| d.to_rata_die()), + Err(DateFromFieldsError::InconsistentMonth), + "Expected InconsistentMonth for RD {:?}", + rd + ); + } + + // Test insufficient fields: Missing Day + { + let result = try_from_fields_helper(EXTENDED_YEAR | MONTH, rd, options, cal); + assert!( + result.is_err(), + "Expected error for missing day at RD {:?}", + rd + ); + } + + // Test insufficient fields: Missing Year + { + let result = try_from_fields_helper(MONTH | DAY, rd, options, cal); + assert!( + result.is_err(), + "Expected error for missing year at RD {:?}", + rd + ); + } + } + } + } +); + +// Note: Specific calendar constructors (like Date::try_new_iso, Date::try_new_gregorian, etc.) +// are tested individually in their respective files under src/cal/ to ensure correct coverage +// of their diverse signatures. diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/date_arithmetic_snapshot.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/date_arithmetic_snapshot.rs index 5cbbba1acbb8..518f0793b35a 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/tests/date_arithmetic_snapshot.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/date_arithmetic_snapshot.rs @@ -2,9 +2,9 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::Date; use crate::options::{DateAddOptions, DateDifferenceOptions, DateDurationUnit}; use crate::types::{DateDuration, RataDie}; -use crate::Date; use insta::assert_snapshot; use std::fmt::Write; diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/extended_year.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/extended_year.rs index 91e52a232fb1..5dce6ffd061b 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/tests/extended_year.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/extended_year.rs @@ -2,10 +2,10 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::preferences::CalendarAlgorithm; -use crate::types::Month; use crate::Calendar; use crate::Date; +use crate::preferences::CalendarAlgorithm; +use crate::types::Month; /// Reference: <https://tc39.es/proposal-intl-era-monthcode/#sec-temporal-calendardatearithmeticyear> fn extended_epoch<C: Calendar>(c: &C) -> Option<i32> { diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/extrema.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/extrema.rs index 1cf2f9fa9087..0ecd41bd049e 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/tests/extrema.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/extrema.rs @@ -2,6 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::Date; use crate::calendar_arithmetic::{CONSTRUCTOR_YEAR_RANGE, GENEROUS_YEAR_RANGE, VALID_RD_RANGE}; use crate::duration::DateDuration; use crate::error::DateAddError; @@ -10,7 +11,6 @@ use crate::options::{ DateAddOptions, DateDifferenceOptions, DateDurationUnit, DateFromFieldsOptions, Overflow, }; use crate::types::{DateFields, Month, YearInput}; -use crate::Date; use calendrical_calculations::gregorian::fixed_from_gregorian; use calendrical_calculations::rata_die::RataDie; @@ -139,7 +139,11 @@ super::test_all_cals!( for overflow in [CONSTRAIN, REJECT] { let added = start_date.try_added_with_options(duration_bound, overflow); if added.is_err() && overflow == REJECT { - assert_ne!(added, Err(DateAddError::Overflow), "{start_date:?} + {duration_bound:?} should not produce overflow error in Reject mode"); + assert_ne!( + added, + Err(DateAddError::Overflow), + "{start_date:?} + {duration_bound:?} should not produce overflow error in Reject mode" + ); } else { assert_eq!( added, @@ -186,8 +190,11 @@ super::test_all_cals!( for generous_duration in [generous_max_duration, generous_max_neg_duration] { for overflow in [CONSTRAIN, REJECT] { - assert_eq!(start_date.try_added_with_options(generous_duration, overflow), Err(DateAddError::Overflow), - "Adding durations from the generously-large range should always fail (but never panic)"); + assert_eq!( + start_date.try_added_with_options(generous_duration, overflow), + Err(DateAddError::Overflow), + "Adding durations from the generously-large range should always fail (but never panic)" + ); } } } diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/mod.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/mod.rs index a217fc7a2a84..337c754bd456 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/tests/mod.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/mod.rs @@ -3,6 +3,7 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). mod arithmetic; +mod constructor_roundtrip; mod continuity_test; mod date_arithmetic_snapshot; mod exhaustive; @@ -11,6 +12,10 @@ mod extrema; mod month; mod not_enough_fields; +use crate::Date; +use crate::types::Month; +use calendrical_calculations::rata_die::RataDie; + macro_rules! test_all_cals { ($(#[$meta:meta])* fn $name:ident<C: Calendar + Copy>($cal:ident: C) $tt:tt) => { mod $name { @@ -127,3 +132,61 @@ macro_rules! test_all_cals { }; } use test_all_cals; + +pub(crate) fn get_interesting_rds() -> Vec<RataDie> { + let mut rds = Vec::new(); + + // Iso / Gregorian leap day + let date = Date::try_new_iso(2020, 2, 29).expect("2020-02-29 is a valid ISO date"); + rds.push(date.to_rata_die()); + + // Hebrew leap month (Adar I) in leap year 5784 + let date = Date::try_new_hebrew_v2(5784, Month::leap(5), 15).expect("Valid Hebrew date"); + rds.push(date.to_rata_die()); + + // Hebrew Adar II in leap year 5784 + let date = Date::try_new_hebrew_v2(5784, Month::new(6), 15).expect("Valid Hebrew date"); + rds.push(date.to_rata_die()); + + // Hebrew non-Adar month in leap year 5784 + let date = Date::try_new_hebrew_v2(5784, Month::new(1), 15).expect("Valid Hebrew date"); + rds.push(date.to_rata_die()); + + // Chinese leap month date + let date = + Date::try_new_chinese_traditional(2023, Month::leap(2), 1).expect("Valid Chinese date"); + rds.push(date.to_rata_die()); + + // Chinese leap year 2023, non-leap month + let date = + Date::try_new_chinese_traditional(2023, Month::new(1), 1).expect("Valid Chinese date"); + rds.push(date.to_rata_die()); + + // Japanese era transition + let date = Date::try_new_japanese_with_calendar("reiwa", 1, 5, 1, crate::cal::Japanese::new()) + .expect("Valid Japanese date"); + rds.push(date.to_rata_die()); + + // Ethiopic month 13 + let date = Date::try_new_ethiopian(crate::cal::EthiopianEraStyle::AmeteMihret, 2015, 13, 5) + .expect("Valid Ethiopian date"); + rds.push(date.to_rata_die()); + + // Coptic month 13 + let date = Date::try_new_coptic(1686, 13, 5).expect("Valid Coptic date"); + rds.push(date.to_rata_die()); + + // Add some more general dates + rds.push(RataDie::new(0)); + rds.push(RataDie::new(1)); + rds.push(RataDie::new(-1)); + rds.push(RataDie::new(730000)); // ~2000 CE + rds.push(RataDie::new(100)); + rds.push(RataDie::new(-100)); + rds.push(RataDie::new(1000000)); // ~2739 CE + rds.push(RataDie::new(-1000000)); // ~ -2739 CE + rds.push(RataDie::new(123456)); + rds.push(RataDie::new(-123456)); + + rds +} diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/month.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/month.rs index 841e7c2e071c..315d260f7d2e 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/tests/month.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/month.rs @@ -4,11 +4,11 @@ #![allow(clippy::field_reassign_with_default)] // use public API +use crate::Date; use crate::error::{DateFromFieldsError, MonthCodeParseError}; use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; use crate::preferences::CalendarAlgorithm; use crate::types::{DateFields, Month, MonthCode}; -use crate::Date; static INVALID_SYNTAX: &[&str] = &[ "M", "M0", "M1", "01L", "L01", "M001", "M110", "MxxL", "m01", "M02l", diff --git a/deps/crates/vendor/icu_calendar-v2/src/tests/not_enough_fields.rs b/deps/crates/vendor/icu_calendar-v2/src/tests/not_enough_fields.rs index d14a52f77209..f87dc89447d8 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/tests/not_enough_fields.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/tests/not_enough_fields.rs @@ -2,10 +2,10 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::Date; use crate::error::DateFromFieldsError; use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; use crate::types::DateFields; -use crate::Date; #[test] fn test_from_fields_not_enough_fields() { diff --git a/deps/crates/vendor/icu_calendar-v2/src/third_party.rs b/deps/crates/vendor/icu_calendar-v2/src/third_party.rs index 6ef83065d1eb..29b4f10b1e38 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/third_party.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/third_party.rs @@ -67,7 +67,8 @@ //! use icu::calendar::{Date, Gregorian, types::Weekday}; //! //! // Convert a time::Date into an ICU4X Date<Gregorian> -//! let time_date = time::Date::from_calendar_date(2025, time::Month::January, 15).unwrap(); +//! let time_date = +//! time::Date::from_calendar_date(2025, time::Month::January, 15).unwrap(); //! let icu_date = Date::<Gregorian>::from(time_date); //! assert_eq!(icu_date.era_year().year, 2025); //! diff --git a/deps/crates/vendor/icu_calendar-v2/src/time_crate.rs b/deps/crates/vendor/icu_calendar-v2/src/time_crate.rs index 829e45a625bf..b4e9769e8729 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/time_crate.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/time_crate.rs @@ -2,11 +2,11 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::Date; +use crate::Gregorian; use crate::cal::abstract_gregorian::AbstractGregorianYear; use crate::cal::gregorian::GregorianDateInner; use crate::calendar_arithmetic::ArithmeticDate; -use crate::Date; -use crate::Gregorian; impl From<time::Date> for Date<Gregorian> { fn from(other: time::Date) -> Self { diff --git a/deps/crates/vendor/icu_calendar-v2/src/types.rs b/deps/crates/vendor/icu_calendar-v2/src/types.rs index 48a0028df3de..14f7acae3145 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/types.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/types.rs @@ -73,9 +73,9 @@ pub struct DateFields<'a> { /// Either `extended_year` or `era` + `era_year` can be used in `DateFields`: /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::Japanese; /// use icu::calendar::types::DateFields; - /// use icu::calendar::Date; /// /// let mut fields1 = DateFields::default(); /// fields1.era = Some(b"reiwa"); @@ -151,9 +151,9 @@ pub struct DateFields<'a> { /// might not resolve to the same month number: /// /// ``` + /// use icu::calendar::Date; /// use icu::calendar::cal::ChineseTraditional; /// use icu::calendar::types::{DateFields, Month}; - /// use icu::calendar::Date; /// /// // The 2023 Year of the Rabbit had a leap month after the 2nd month. /// let mut fields1 = DateFields::default(); @@ -215,7 +215,7 @@ impl fmt::Debug for DateFields<'_> { day, } = *self; let mut builder = f.debug_struct("DateFields"); - if let Some(s) = era.and_then(|s| core::str::from_utf8(s).ok()) { + if let Some(s) = era.and_then(|s| str::from_utf8(s).ok()) { builder.field("era", &Some(s)); } else { builder.field("era", &era); @@ -223,7 +223,7 @@ impl fmt::Debug for DateFields<'_> { builder.field("era_year", &era_year); builder.field("extended_year", &extended_year); builder.field("month", &month); - if let Some(s) = month_code.and_then(|s| core::str::from_utf8(s).ok()) { + if let Some(s) = month_code.and_then(|s| str::from_utf8(s).ok()) { builder.field("month_code", &Some(s)); } else { builder.field("month_code", &month_code); diff --git a/deps/crates/vendor/icu_calendar-v2/src/week.rs b/deps/crates/vendor/icu_calendar-v2/src/week.rs index fae1913e63cc..ff58200c2dfe 100644 --- a/deps/crates/vendor/icu_calendar-v2/src/week.rs +++ b/deps/crates/vendor/icu_calendar-v2/src/week.rs @@ -20,7 +20,7 @@ const MIN_UNIT_DAYS: u16 = 14; /// ``` /// use icu::calendar::types::Weekday; /// use icu::calendar::week::WeekInformation; -/// use icu::locale::{locale, Locale}; +/// use icu::locale::{Locale, locale}; /// /// // For en-US /// let info = WeekInformation::try_new(locale!("en-US").into()).unwrap(); @@ -316,7 +316,7 @@ impl Iterator for WeekdaySetIterator { #[cfg(test)] mod tests { use super::*; - use crate::{types::DateDuration, types::Weekday, Date, RangeError}; + use crate::{Date, RangeError, types::DateDuration, types::Weekday}; static ISO_CALENDAR: WeekCalculator = WeekCalculator { first_weekday: Weekday::Monday, @@ -657,8 +657,8 @@ fn test_weekdays_iter() { #[test] fn test_iso_weeks() { - use crate::types::IsoWeekOfYear; use crate::Date; + use crate::types::IsoWeekOfYear; #[expect(clippy::zero_prefixed_literal)] for ((y, m, d), (iso_year, week_number)) in [ diff --git a/deps/crates/vendor/icu_calendar-v2/tests/arithmetic.rs b/deps/crates/vendor/icu_calendar-v2/tests/arithmetic.rs index bc275d08a8e1..227e4561e443 100644 --- a/deps/crates/vendor/icu_calendar-v2/tests/arithmetic.rs +++ b/deps/crates/vendor/icu_calendar-v2/tests/arithmetic.rs @@ -5,10 +5,10 @@ use std::convert::Infallible; use icu_calendar::{ + AsCalendar, Calendar, Date, Iso, cal::Hebrew, options::{DateAddOptions, DateDifferenceOptions, DateDurationUnit, Overflow}, types::{DateDuration, Month}, - AsCalendar, Calendar, Date, Iso, }; #[rustfmt::skip] diff --git a/deps/crates/vendor/icu_calendar-v2/tests/reference_year.rs b/deps/crates/vendor/icu_calendar-v2/tests/reference_year.rs index bb1b6b2445b5..60d137e8ff61 100644 --- a/deps/crates/vendor/icu_calendar-v2/tests/reference_year.rs +++ b/deps/crates/vendor/icu_calendar-v2/tests/reference_year.rs @@ -5,11 +5,11 @@ use std::{collections::HashSet, fmt::Debug}; use icu_calendar::{ + Calendar, Date, cal::*, error::DateFromFieldsError, options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}, types::{DateFields, Month}, - Calendar, Date, }; /// Test that a given calendar produces valid monthdays @@ -133,13 +133,13 @@ where if let Ok(reject_result) = reject_result { // We didn't need to constrain here, update the last valid date last_valid_date = Some(reject_result); - } else if let Some(last_valid_date) = last_valid_date { - if md_validity != ValidityState::ChineseConstrain { - assert_eq!( - last_valid_date, reference_date, - "Constrain should constrain to the last valid date in the month" - ); - } + } else if let Some(last_valid_date) = last_valid_date + && md_validity != ValidityState::ChineseConstrain + { + assert_eq!( + last_valid_date, reference_date, + "Constrain should constrain to the last valid date in the month" + ); } // Test that ordinal months cause it to fail (even if the month code is still set) @@ -239,7 +239,7 @@ fn hijri_tabular_md_condition(month_number: u8, is_leap: bool, day_number: u8) - } // Odd months have 30 days, even months have 29, except for M12 in a leap year - ValidityState::from(if month_number % 2 == 0 { + ValidityState::from(if month_number.is_multiple_of(2) { if month_number == 12 { day_number <= 30 } else { diff --git a/deps/crates/vendor/icu_calendar-v2/tests/reingold.rs b/deps/crates/vendor/icu_calendar-v2/tests/reingold.rs index 0a1f2536f65b..960fd661e7c4 100644 --- a/deps/crates/vendor/icu_calendar-v2/tests/reingold.rs +++ b/deps/crates/vendor/icu_calendar-v2/tests/reingold.rs @@ -2,11 +2,11 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use icu_calendar::Date; +use icu_calendar::cal::Hijri; use icu_calendar::cal::hijri::{ HijriYear, Rules, TabularAlgorithm, TabularAlgorithmEpoch, TabularAlgorithmLeapYears, }; -use icu_calendar::cal::Hijri; -use icu_calendar::Date; /// [`Hijri`] [`Rules`] based on an astronomical simulation for Mecca. /// diff --git a/deps/crates/vendor/icu_calendar_data-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_calendar_data-v2/.cargo_vcs_info.json index 050558e7ea49..16f10b9a4fa3 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/.cargo_vcs_info.json +++ b/deps/crates/vendor/icu_calendar_data-v2/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "c9fac4e625ccb2c6a7aa35079fff9709db4385ac" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "provider/data/calendar" } \ No newline at end of file diff --git a/deps/crates/vendor/icu_calendar_data-v2/Cargo.lock b/deps/crates/vendor/icu_calendar_data-v2/Cargo.lock index e0df6897dd08..6b993fa9e7f0 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/Cargo.lock +++ b/deps/crates/vendor/icu_calendar_data-v2/Cargo.lock @@ -4,4 +4,4 @@ version = 3 [[package]] name = "icu_calendar_data" -version = "2.2.0" +version = "2.4.0" diff --git a/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml b/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml index 64c7f7cd370e..93e5563cd7f9 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml +++ b/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2021" -rust-version = "1.86" +edition = "2024" +rust-version = "1.88" name = "icu_calendar_data" -version = "2.2.0" +version = "2.4.0" authors = ["The ICU4X Project Developers"] build = "build.rs" include = [ @@ -47,12 +47,13 @@ categories = [ ] license = "Unicode-3.0" repository = "https://github.com/unicode-org/icu4x" +resolver = "2" [package.metadata.sources.cldr] -tagged = "48.2.0" +tagged = "49.0.0" -[package.metadata.sources.icuexport] -tagged = "release-78.1rc" +[package.metadata.sources.unicode] +tagged = "18.0.0" [package.metadata.sources.segmenter_lstm] tagged = "v0.1.0" diff --git a/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml.orig b/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml.orig index f32d897671a5..6d59ca791359 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml.orig +++ b/deps/crates/vendor/icu_calendar_data-v2/Cargo.toml.orig @@ -18,8 +18,8 @@ repository.workspace = true rust-version.workspace = true [package.metadata.sources] -cldr = { tagged = "48.2.0" } -icuexport = { tagged = "release-78.1rc" } +cldr = { tagged = "49.0.0" } +unicode = { tagged = "18.0.0" } segmenter_lstm = { tagged = "v0.1.0" } [lints.rust] diff --git a/deps/crates/vendor/icu_calendar_data-v2/README.md b/deps/crates/vendor/icu_calendar_data-v2/README.md index 5a8dd8de71d2..f54f584e4a58 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/README.md +++ b/deps/crates/vendor/icu_calendar_data-v2/README.md @@ -4,7 +4,7 @@ Data for the `icu_calendar` crate -This data was generated with CLDR version 48.2.0, ICU version release-78.1rc, and +This data was generated with CLDR version 49.0.0, Unicode version 18.0.0, and LSTM segmenter version v0.1.0. <!-- cargo-rdme end --> diff --git a/deps/crates/vendor/icu_calendar_data-v2/data/calendar_japanese_modern_v1.rs.data b/deps/crates/vendor/icu_calendar_data-v2/data/calendar_japanese_modern_v1.rs.data index ecfc337c398d..8ad9c320ca5f 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/data/calendar_japanese_modern_v1.rs.data +++ b/deps/crates/vendor/icu_calendar_data-v2/data/calendar_japanese_modern_v1.rs.data @@ -4,26 +4,25 @@ /// `icu`'s `_unstable` constructors. /// /// Using this implementation will embed the following data in the binary's data segment: -/// * 134B[^1] for the singleton data struct +/// * 7B[^1] for the singleton data struct /// /// [^1]: these numbers can be smaller in practice due to linker deduplication /// /// This macro requires the following crates: /// * `icu` /// * `icu_provider` -/// * `zerovec` #[doc(hidden)] #[macro_export] macro_rules! __impl_calendar_japanese_modern_v1 { ($ provider : ty) => { - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl $provider { #[doc(hidden)] - pub const SINGLETON_CALENDAR_JAPANESE_MODERN_V1: &'static <icu::calendar::provider::CalendarJapaneseModernV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::calendar::provider::JapaneseEras { dates_to_eras: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"L\x07\0\0\n\x17meiji\0\0\0\0\0\0\0\0\0\0\0x\x07\0\0\x07\x1Etaisho\0\0\0\0\0\0\0\0\0\0\x86\x07\0\0\x0C\x19showa\0\0\0\0\0\0\0\0\0\0\0\xC5\x07\0\0\x01\x08heisei\0\0\0\0\0\0\0\0\0\0\xE3\x07\0\0\x05\x01reiwa\0\0\0\0\0\0\0\0\0\0\0") } }; + pub const SINGLETON_CALENDAR_JAPANESE_MODERN_V1: &'static <icu::calendar::provider::CalendarJapaneseModernV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::calendar::provider::JapaneseEras::up_to_reiwa(); } - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::DataProvider<icu::calendar::provider::CalendarJapaneseModernV1> for $provider { fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::calendar::provider::CalendarJapaneseModernV1>, icu_provider::DataError> { if req.id.locale.is_unknown() { @@ -36,7 +35,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { }; ($ provider : ty , ITER) => { __impl_calendar_japanese_modern_v1!($provider); - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::IterableDataProvider<icu::calendar::provider::CalendarJapaneseModernV1> for $provider { fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) @@ -45,7 +44,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { }; ($ provider : ty , DRY) => { __impl_calendar_japanese_modern_v1!($provider); - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::DryDataProvider<icu::calendar::provider::CalendarJapaneseModernV1> for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { if req.id.locale.is_unknown() { @@ -58,7 +57,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { }; ($ provider : ty , DRY , ITER) => { __impl_calendar_japanese_modern_v1!($provider); - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::DryDataProvider<icu::calendar::provider::CalendarJapaneseModernV1> for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { if req.id.locale.is_unknown() { @@ -68,7 +67,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { } } } - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::IterableDataProvider<icu::calendar::provider::CalendarJapaneseModernV1> for $provider { fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) diff --git a/deps/crates/vendor/icu_calendar_data-v2/data/calendar_preferred_v1.rs.data b/deps/crates/vendor/icu_calendar_data-v2/data/calendar_preferred_v1.rs.data new file mode 100644 index 000000000000..8b249837e73b --- /dev/null +++ b/deps/crates/vendor/icu_calendar_data-v2/data/calendar_preferred_v1.rs.data @@ -0,0 +1,70 @@ +// @generated +/// Implement `DataProvider<CalendarPreferredV1>` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +/// +/// Using this implementation will embed the following data in the binary's data segment: +/// * 69B for the lookup data structure (9 data identifiers) +/// * 8B[^1] for the actual data (4 unique structs) +/// +/// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu` +/// * `icu_locale_core` +/// * `icu_provider` +/// * `icu_provider/baked` +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_calendar_preferred_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.88"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.88"] + impl $provider { + const DATA_CALENDAR_PREFERRED_V1: icu_provider::baked::zerotrie::Data<icu::calendar::provider::CalendarPreferredV1> = { + const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"und\x80-\xC7ABIKQST\x06\x08\n\x0C\x0E\x10\xC2EF\x01\x81\x82H\x81R\x82W\x81A\x81A\x81H\x83" }; + const VALUES: &'static [<icu::calendar::provider::CalendarPreferredV1 as icu_provider::baked::zerotrie::DynamicDataMarker>::DataStruct] = &[icu::calendar::provider::CalendarPreference { default_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm::Gregory, default_hijri_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::HijriCalendarAlgorithm::Civil }, icu::calendar::provider::CalendarPreference { default_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm::Gregory, default_hijri_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::HijriCalendarAlgorithm::Umalqura }, icu::calendar::provider::CalendarPreference { default_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm::Persian, default_hijri_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::HijriCalendarAlgorithm::Civil }, icu::calendar::provider::CalendarPreference { default_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm::Buddhist, default_hijri_algorithm: icu_locale_core::preferences::extensions::unicode::keywords::HijriCalendarAlgorithm::Civil }]; + unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } + }; + } + #[clippy::msrv = "1.88"] + impl icu_provider::DataProvider<icu::calendar::provider::CalendarPreferredV1> for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::calendar::provider::CalendarPreferredV1>, icu_provider::DataError> { + let mut metadata = icu_provider::DataResponseMetadata::default(); + let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_CALENDAR_PREFERRED_V1, req.id, req.metadata.attributes_prefix_match) { + payload + } else { + const FALLBACKER: icu_locale_fallback::LocaleFallbackerWithConfig<'static> = icu_locale_fallback::LocaleFallbacker::new().for_config(<icu::calendar::provider::CalendarPreferredV1 as icu_provider::DataMarker>::INFO.fallback_config); + let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); + loop { + if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_CALENDAR_PREFERRED_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { + metadata.locale = Some(fallback_iterator.take()); + break payload; + } + if fallback_iterator.get().is_unknown() { + return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(<icu::calendar::provider::CalendarPreferredV1 as icu_provider::DataMarker>::INFO, req)); + } + fallback_iterator.step(); + } + }; + Ok(icu_provider::DataResponse { payload, metadata }) + } + } + }; + ($ provider : ty , ITER) => { + __impl_calendar_preferred_v1!($provider); + #[clippy::msrv = "1.88"] + impl icu_provider::IterableDataProvider<icu::calendar::provider::CalendarPreferredV1> for $provider { + fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { + Ok(icu_provider::baked::DataStore::iter(&Self::DATA_CALENDAR_PREFERRED_V1).collect()) + } + } + }; + ($ provider : ty , DRY) => {}; + ($ provider : ty , DRY , ITER) => { + __impl_calendar_preferred_v1!($provider, ITER); + }; +} +#[doc(inline)] +pub use __impl_calendar_preferred_v1 as impl_calendar_preferred_v1; diff --git a/deps/crates/vendor/icu_calendar_data-v2/data/calendar_week_v1.rs.data b/deps/crates/vendor/icu_calendar_data-v2/data/calendar_week_v1.rs.data index dc2bc0feff28..c9bec451d993 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/data/calendar_week_v1.rs.data +++ b/deps/crates/vendor/icu_calendar_data-v2/data/calendar_week_v1.rs.data @@ -17,9 +17,9 @@ #[macro_export] macro_rules! __impl_calendar_week_v1 { ($ provider : ty) => { - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl $provider { const DATA_CALENDAR_WEEK_V1: icu_provider::baked::zerotrie::Data<icu::calendar::provider::CalendarWeekV1> = { const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"und\x80-\xD7ABCDEGHIJKLMNOPQSTUVWYZ\t\x1E$06<BT]io\x84\x8A\x8C\xA1\xA3\xB2\xBB\xC4\xCA\xCC\xCE\xC3FGS\x01\x02\x81\x82\x82\xC7DHRSTWZ\x01\x02\x03\x04\x05\x06\x82\x83\x82\x82\x82\x82\x82\xC2AO\x01\x82\x82\xC4JMOZ\x01\x02\x03\x84\x82\x82\x83\xC2GT\x01\x83\x82\xC2TU\x01\x82\x82\xC2KN\x01\x82\x82\xC6DLNQRS\x01\x02\x03\x04\x05\x82\x85\x86\x83\x87\x82\xC3MOP\x01\x02\x82\x83\x82\xC4EHRW\x01\x02\x03\x82\x82\x82\x83\xC2AY\x01\x82\x83\xC7HMOTVXZ\x01\x02\x03\x04\x05\x06\x82\x82\x82\x82\x88\x82\x82\xC2IP\x01\x82\x82M\x83\xC7AEHKRTY\x01\x02\x03\x04\x05\x06\x82\x82\x82\x82\x82\x82\x82A\x83\xC5ADGVY\x01\x02\x03\x04\x85\x83\x82\x82\x83\xC3HTW\x01\x02\x82\x82\x82\xC3GMS\x01\x02\x89\x82\x82\xC2EI\x01\x82\x82S\x82E\x85\xC2AW\x01\x82\x82" }; @@ -27,14 +27,14 @@ macro_rules! __impl_calendar_week_v1 { unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } }; } - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::DataProvider<icu::calendar::provider::CalendarWeekV1> for $provider { fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::calendar::provider::CalendarWeekV1>, icu_provider::DataError> { let mut metadata = icu_provider::DataResponseMetadata::default(); let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_CALENDAR_WEEK_V1, req.id, req.metadata.attributes_prefix_match) { payload } else { - const FALLBACKER: icu::locale::fallback::LocaleFallbackerWithConfig<'static> = icu::locale::fallback::LocaleFallbacker::new().for_config(<icu::calendar::provider::CalendarWeekV1 as icu_provider::DataMarker>::INFO.fallback_config); + const FALLBACKER: icu_locale_fallback::LocaleFallbackerWithConfig<'static> = icu_locale_fallback::LocaleFallbacker::new().for_config(<icu::calendar::provider::CalendarWeekV1 as icu_provider::DataMarker>::INFO.fallback_config); let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); loop { if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_CALENDAR_WEEK_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { @@ -53,7 +53,7 @@ macro_rules! __impl_calendar_week_v1 { }; ($ provider : ty , ITER) => { __impl_calendar_week_v1!($provider); - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl icu_provider::IterableDataProvider<icu::calendar::provider::CalendarWeekV1> for $provider { fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { Ok(icu_provider::baked::DataStore::iter(&Self::DATA_CALENDAR_WEEK_V1).collect()) diff --git a/deps/crates/vendor/icu_calendar_data-v2/data/mod.rs b/deps/crates/vendor/icu_calendar_data-v2/data/mod.rs index ffa33a336237..26e03ff24746 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/data/mod.rs +++ b/deps/crates/vendor/icu_calendar_data-v2/data/mod.rs @@ -1,4 +1,5 @@ // @generated +include!("calendar_preferred_v1.rs.data"); include!("calendar_japanese_modern_v1.rs.data"); include!("calendar_week_v1.rs.data"); /// Marks a type as a data provider. You can then use macros like @@ -16,7 +17,7 @@ include!("calendar_week_v1.rs.data"); #[macro_export] macro_rules! __make_provider { ($ name : ty) => { - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl $name { #[allow(dead_code)] pub(crate) const MUST_USE_MAKE_PROVIDER_MACRO: () = (); @@ -28,13 +29,14 @@ macro_rules! __make_provider { pub use __make_provider as make_provider; /// This macro requires the following crates: /// * `icu` +/// * `icu_locale_core` /// * `icu_provider` /// * `icu_provider/baked` -/// * `zerovec` #[allow(unused_macros)] macro_rules! impl_data_provider { ($ provider : ty) => { make_provider!($provider); + impl_calendar_preferred_v1!($provider); impl_calendar_japanese_modern_v1!($provider); impl_calendar_week_v1!($provider); }; diff --git a/deps/crates/vendor/icu_calendar_data-v2/src/lib.rs b/deps/crates/vendor/icu_calendar_data-v2/src/lib.rs index 90d2b19b7e3c..647b2e1505e9 100644 --- a/deps/crates/vendor/icu_calendar_data-v2/src/lib.rs +++ b/deps/crates/vendor/icu_calendar_data-v2/src/lib.rs @@ -4,7 +4,7 @@ //! Data for the `icu_calendar` crate //! -//! This data was generated with CLDR version 48.2.0, ICU version release-78.1rc, and +//! This data was generated with CLDR version 49.0.0, Unicode version 18.0.0, and //! LSTM segmenter version v0.1.0. #![no_std] @@ -15,3 +15,24 @@ include!(concat!(core::env!("ICU4X_DATA_DIR"), "/mod.rs")); #[cfg(not(icu4x_custom_data))] include!("../data/mod.rs"); + +#[macro_export] +macro_rules! cldr_tag { + () => { + "49.0.0" + }; +} + +#[macro_export] +macro_rules! unicode_tag { + () => { + "18.0.0" + }; +} + +#[macro_export] +macro_rules! segmenter_lstm_tag { + () => { + "v0.1.0" + }; +} diff --git a/deps/crates/vendor/icu_collections-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_collections-v2/.cargo_vcs_info.json deleted file mode 100644 index 2997b36686a6..000000000000 --- a/deps/crates/vendor/icu_collections-v2/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "c9fac4e625ccb2c6a7aa35079fff9709db4385ac" - }, - "path_in_vcs": "components/collections" -} \ No newline at end of file diff --git a/deps/crates/vendor/icu_collections-v2/Cargo.lock b/deps/crates/vendor/icu_collections-v2/Cargo.lock deleted file mode 100644 index 31aff5335ad5..000000000000 --- a/deps/crates/vendor/icu_collections-v2/Cargo.lock +++ /dev/null @@ -1,820 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clap" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" -dependencies = [ - "anstyle", - "clap_lex", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "criterion" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" -dependencies = [ - "anes", - "cast", - "ciborium", - "clap", - "criterion-plot", - "is-terminal", - "itertools", - "num-traits", - "once_cell", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "databake" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4b1db5ca40636726f1f73daff0d626accbd49bcd8136fcade87d7cf1e6bbb" -dependencies = [ - "databake-derive", - "proc-macro2", - "quote", -] - -[[package]] -name = "databake-derive" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b537745234cbf0e296a3bd836d70a614dff4cb522b14e2680ef006bb1ed5ff" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "iai" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678" - -[[package]] -name = "icu_collections" -version = "2.2.0" -dependencies = [ - "criterion", - "databake", - "displaydoc", - "iai", - "postcard", - "potential_utf", - "serde", - "serde_json", - "toml", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "indexmap" -version = "2.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "is-terminal" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "js-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.183" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "oorandom" -version = "11.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" - -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "serde_core", - "zerovec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "databake", - "serde", - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/deps/crates/vendor/icu_collections-v2/Cargo.toml b/deps/crates/vendor/icu_collections-v2/Cargo.toml deleted file mode 100644 index 7f57b47901a3..000000000000 --- a/deps/crates/vendor/icu_collections-v2/Cargo.toml +++ /dev/null @@ -1,215 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.86" -name = "icu_collections" -version = "2.2.0" -authors = ["The ICU4X Project Developers"] -build = false -include = [ - "data/**/*", - "src/**/*", - "examples/**/*", - "benches/**/*", - "tests/**/*", - "Cargo.toml", - "LICENSE", - "README.md", - "build.rs", -] -autolib = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "Collection of API for use in ICU libraries." -homepage = "https://icu4x.unicode.org" -readme = "README.md" -keywords = [ - "unicode", - "data-structures", -] -categories = [ - "internationalization", - "localization", - "no-std", - "embedded", -] -license = "Unicode-3.0" -repository = "https://github.com/unicode-org/icu4x" - -[package.metadata.docs.rs] -all-features = true - -[package.metadata.cargo-all-features] -max_combination_size = 3 - -[features] -alloc = [ - "serde?/alloc", - "zerovec/alloc", -] -databake = [ - "dep:databake", - "zerovec/databake", -] -serde = [ - "dep:serde", - "zerovec/serde", - "potential_utf/serde", - "alloc", -] - -[lib] -name = "icu_collections" -path = "src/lib.rs" -bench = false - -[[test]] -name = "char16trie" -path = "tests/char16trie.rs" - -[[test]] -name = "cpt" -path = "tests/cpt.rs" - -[[bench]] -name = "codepointtrie" -path = "benches/codepointtrie.rs" -harness = false - -[[bench]] -name = "iai_cpt" -path = "benches/iai_cpt.rs" -harness = false - -[[bench]] -name = "inv_list" -path = "benches/inv_list.rs" -harness = false - -[dependencies.databake] -version = "0.2.0" -features = ["derive"] -optional = true -default-features = false - -[dependencies.displaydoc] -version = "0.2.3" -default-features = false - -[dependencies.potential_utf] -version = "0.1.3" -features = ["zerovec"] -default-features = false - -[dependencies.serde] -version = "1.0.220" -features = ["derive"] -optional = true -default-features = false - -[dependencies.utf8_iter] -version = "1.0.2" -default-features = false - -[dependencies.yoke] -version = "0.8.2" -features = ["derive"] -default-features = false - -[dependencies.zerofrom] -version = "0.1.6" -features = ["derive"] -default-features = false - -[dependencies.zerovec] -version = "0.11.6" -features = [ - "derive", - "yoke", -] -default-features = false - -[dev-dependencies.iai] -version = "0.1.1" - -[dev-dependencies.postcard] -version = "1.0.3" -features = ["alloc"] -default-features = false - -[dev-dependencies.serde] -version = "1.0.220" -features = ["derive"] -default-features = false - -[dev-dependencies.serde_json] -version = "1.0.45" - -[dev-dependencies.toml] -version = "0.8.0" -features = ["parse"] -default-features = false - -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion] -version = "0.5.0" - -[lints.clippy] -alloc-instead-of-core = "warn" -branches-sharing-code = "warn" -collection_is_never_read = "warn" -crosspointer_transmute = "warn" -dbg_macro = "warn" -debug_assert_with_mut_call = "warn" -doc_markdown = "warn" -exhaustive_enums = "deny" -exhaustive_structs = "deny" -fn_to_numeric_cast_any = "warn" -infinite_loop = "warn" -large_stack_arrays = "warn" -mismatching_type_param_order = "warn" -missing_fields_in_debug = "warn" -missing_transmute_annotations = "warn" -negative_feature_names = "warn" -or-fun-call = "warn" -same_functions_in_if_condition = "warn" -todo = "warn" -transmute_bytes_to_str = "warn" -transmute_int_to_bool = "warn" -transmute_int_to_non_zero = "warn" -transmute_ptr_to_ptr = "warn" -transmute_ptr_to_ref = "warn" -transmute_undefined_repr = "warn" -transmutes_expressible_as_ptr_casts = "warn" -trivially_copy_pass_by_ref = "deny" -unnecessary-wraps = "warn" -useless_transmute = "warn" -wildcard_dependencies = "warn" - -[lints.rust] -missing_debug_implementations = "deny" -trivial_numeric_casts = "deny" -unused_lifetimes = "warn" -unused_macro_rules = "warn" -unused_qualifications = "warn" - -[lints.rust.unexpected_cfgs] -level = "warn" -priority = 0 -check-cfg = [ - "cfg(icu4c_enable_renaming)", - "cfg(needs_alloc_error_handler)", - "cfg(icu4x_run_size_tests)", - "cfg(icu4x_unstable_fast_trie_only)", -] diff --git a/deps/crates/vendor/icu_collections-v2/Cargo.toml.orig b/deps/crates/vendor/icu_collections-v2/Cargo.toml.orig deleted file mode 100644 index c15f61500b46..000000000000 --- a/deps/crates/vendor/icu_collections-v2/Cargo.toml.orig +++ /dev/null @@ -1,74 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -[package] -name = "icu_collections" -description = "Collection of API for use in ICU libraries." -categories.workspace = true -keywords = ["unicode", "data-structures"] - -authors.workspace = true -edition.workspace = true -homepage.workspace = true -include.workspace = true -license.workspace = true -repository.workspace = true -rust-version.workspace = true -version.workspace = true - -[package.metadata.docs.rs] -all-features = true - -[package.metadata.cargo-all-features] -max_combination_size = 3 - -[dependencies] -displaydoc = { workspace = true } -yoke = { workspace = true, features = ["derive"] } -zerofrom = { workspace = true, features = ["derive"] } -zerovec = { workspace = true, features = ["derive", "yoke"] } -potential_utf = { workspace = true, features = ["zerovec"] } -utf8_iter = { workspace = true } - -serde = { workspace = true, features = ["derive"], optional = true } -databake = { workspace = true, features = ["derive"], optional = true } - -[dev-dependencies] -iai = { workspace = true } -icu = { path = "../../components/icu", default-features = false } -icu_properties = { path = "../../components/properties" } -postcard = { workspace = true, features = ["alloc"] } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } - -toml = { workspace = true } - -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -criterion = { workspace = true } - -[features] -serde = ["dep:serde", "zerovec/serde", "potential_utf/serde", "alloc"] -databake = ["dep:databake", "zerovec/databake"] -alloc = ["serde?/alloc", "zerovec/alloc"] - -[lib] -bench = false # This option is required for Benchmark CI - -[[bench]] -name = "codepointtrie" -harness = false -path = "benches/codepointtrie.rs" - -[[bench]] -name = "iai_cpt" -harness = false -path = "benches/iai_cpt.rs" - -[[bench]] -name = "inv_list" -harness = false -path = "benches/inv_list.rs" - -[lints] -workspace = true diff --git a/deps/crates/vendor/icu_collections-v2/OWNERS b/deps/crates/vendor/icu_collections-v2/OWNERS deleted file mode 100644 index cbe7d0620c40..000000000000 --- a/deps/crates/vendor/icu_collections-v2/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# This file has been auto-generated by the `gnrt` tool. -file://third_party/rust/icu_collections/OWNERS diff --git a/deps/crates/vendor/icu_collections-v2/README.md b/deps/crates/vendor/icu_collections-v2/README.md deleted file mode 100644 index e90aa210bb69..000000000000 --- a/deps/crates/vendor/icu_collections-v2/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# icu_collections [![crates.io](https://img.shields.io/crates/v/icu_collections)](https://crates.io/crates/icu_collections) - -<!-- cargo-rdme start --> - -Efficient collections for Unicode data. - -This module is published as its own crate ([`icu_collections`](https://docs.rs/icu_collections/latest/icu_collections/)) -and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project. - -ICU4X `CodePointTrie` provides a read-only view of `CodePointTrie` data that is exported -from ICU4C. Detailed information about the design of the data structure can be found in the documentation -for the `CodePointTrie` struct. - -ICU4X `CodePointInversionList` provides necessary functionality for highly efficient querying of sets of Unicode characters. -It is an implementation of the existing [ICU4C UnicodeSet API](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UnicodeSet.html). - -ICU4X `Char16Trie` provides a data structure for a space-efficient and time-efficient lookup of -sequences of 16-bit units (commonly but not necessarily UTF-16 code units) -which map to integer values. -It is an implementation of the existing [ICU4C UCharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UCharsTrie.html) -/ [ICU4J CharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/util/CharsTrie.html) API. - -<!-- cargo-rdme end --> - -## More Information - -For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). diff --git a/deps/crates/vendor/icu_collections-v2/benches/codepointtrie.rs b/deps/crates/vendor/icu_collections-v2/benches/codepointtrie.rs deleted file mode 100644 index e49401634dd5..000000000000 --- a/deps/crates/vendor/icu_collections-v2/benches/codepointtrie.rs +++ /dev/null @@ -1,104 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use criterion::{black_box, criterion_group, criterion_main, Criterion}; - -use icu_collections::codepointtrie::CodePointTrie; - -#[path = "tries/mod.rs"] -mod tries; - -mod sample_str_lng { - // "eng" is all ASCII - pub const ENG: &str = "Universal Declaration of Human Rights"; - // "pcd" has ASCII mixed with low-BMP code points - pub const PCD: &str = "Dèclaråcion dès dreûts d' l'ome po tos lès payîs dè monde"; - // "ukr" uses low-BMP code points (less than U+1000) - pub const UKR: &str = "ЗАГАЛЬНА ДЕКЛАРАЦІЯ ПРАВ ЛЮДИНІ"; - // "yue" uses high-BMP code points (greater than U+1000), so it benefits from fast mode - pub const YUE: &str = "世界人权宣言"; - // "ccp" exercises supplementary code points - pub const CCP: &str = "𑄟𑄚𑄬𑄭𑄃𑄇𑄴𑄇𑄥𑄧𑄁𑄢𑄴 𑄝𑄬𑄇𑄴𑄅𑄚𑄮𑄢𑄴 𑄟𑄧𑄚𑄳𑄢𑄧𑄧𑄇𑄉𑄮𑄌𑄴"; -} - -const SAMPLE_STRING_MIXED: &str = "Dèclaråcion ЗАГАЛЬНА 世界人权宣言 𑄟𑄚𑄬𑄭𑄃𑄇𑄴𑄇𑄥𑄧𑄁𑄢𑄴"; - -/// A function that returns 100 code points in the desired language -fn one_hundred_code_points(sample_str: &str) -> String { - sample_str.chars().cycle().take(100).collect() -} - -fn get_trie_small() -> CodePointTrie<'static, u8> { - CodePointTrie::try_new( - tries::gc_small::HEADER, - tries::gc_small::INDEX, - tries::gc_small::DATA, - ) - .unwrap() -} - -fn get_trie_fast() -> CodePointTrie<'static, u8> { - CodePointTrie::try_new( - tries::gc_fast::HEADER, - tries::gc_fast::INDEX, - tries::gc_fast::DATA, - ) - .unwrap() -} - -fn overview_bench(c: &mut Criterion) { - let s = one_hundred_code_points(SAMPLE_STRING_MIXED); - let cpt_small = get_trie_small(); - - c.bench_function("cpt/overview", |b| { - b.iter(|| { - black_box(&s) - .chars() - .map(|c| black_box(&cpt_small).get32(c as u32)) - .reduce(|a, b| a.wrapping_add(b)) - }); - }); - - c.bench_function("cpt/get_range", |b| { - b.iter(|| { - black_box(&s) - .chars() - .map(|c| black_box(&cpt_small).get_range(c as u32).unwrap()) - .fold(0u32, |acc, ele| { - acc.wrapping_add(ele.range.end() - ele.range.start() + ele.value as u32) - }) - }); - }); - - { - let cpt_fast = get_trie_fast(); - lang_bench(c, &cpt_small, "small/eng", sample_str_lng::ENG); - lang_bench(c, &cpt_small, "small/pcd", sample_str_lng::PCD); - lang_bench(c, &cpt_small, "small/ukr", sample_str_lng::UKR); - lang_bench(c, &cpt_small, "small/yue", sample_str_lng::YUE); - lang_bench(c, &cpt_small, "small/ccp", sample_str_lng::CCP); - lang_bench(c, &cpt_fast, "fast/eng", sample_str_lng::ENG); - lang_bench(c, &cpt_fast, "fast/pcd", sample_str_lng::PCD); - lang_bench(c, &cpt_fast, "fast/ukr", sample_str_lng::UKR); - lang_bench(c, &cpt_fast, "fast/yue", sample_str_lng::YUE); - lang_bench(c, &cpt_fast, "fast/ccp", sample_str_lng::CCP); - } -} - -fn lang_bench(c: &mut Criterion, cpt: &CodePointTrie<u8>, lid: &str, sample_str: &str) { - let bench_name = format!("cpt/get/{lid}"); - let s = one_hundred_code_points(sample_str); - - c.bench_function(&bench_name, |b| { - b.iter(|| { - black_box(&s) - .chars() - .map(|c| black_box(&cpt).get32(c as u32)) - .reduce(|a, b| a.wrapping_add(b)) - }); - }); -} - -criterion_group!(benches, overview_bench,); -criterion_main!(benches); diff --git a/deps/crates/vendor/icu_collections-v2/benches/iai_cpt.rs b/deps/crates/vendor/icu_collections-v2/benches/iai_cpt.rs deleted file mode 100644 index 3d57cbb4a168..000000000000 --- a/deps/crates/vendor/icu_collections-v2/benches/iai_cpt.rs +++ /dev/null @@ -1,77 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use icu_collections::codepointtrie::CodePointTrie; - -#[path = "tries/mod.rs"] -mod tries; - -// The string has 41 chars. -const SAMPLE_STRING_LATIN1: &str = "Declaration loremips umdolo loremipsompi"; -const SAMPLE_STRING_MIXED: &str = "Dèclaråcion ЗАГАЛЬНА 世界人权宣言 𑄟𑄚𑄬𑄭𑄃𑄇𑄴𑄇𑄥𑄧𑄁𑄢𑄴"; - -fn get_trie_small() -> CodePointTrie<'static, u8> { - CodePointTrie::try_new( - tries::gc_small::HEADER, - tries::gc_small::INDEX, - tries::gc_small::DATA, - ) - .unwrap() -} - -fn get_trie_fast() -> CodePointTrie<'static, u8> { - CodePointTrie::try_new( - tries::gc_fast::HEADER, - tries::gc_fast::INDEX, - tries::gc_fast::DATA, - ) - .unwrap() -} - -fn bench_iai_cpt_overview(fast: bool, mixed: bool) { - // Tests the instructions required to get CPT for 100,000 chars. - - let cpt = if fast { - get_trie_fast() - } else { - get_trie_small() - }; - let sample = if mixed { - SAMPLE_STRING_MIXED - } else { - SAMPLE_STRING_LATIN1 - }; - - let mut i: u8 = 0; - for c in sample.chars() { - i = i.wrapping_add(cpt.get32(c as u32)) - //i = i.wrapping_add(1); - } - - // Ensure the loop is not DCEd - assert!(i < 255); -} - -fn bench_iai_cpt_latin_fast() { - bench_iai_cpt_overview(true, false); -} - -fn bench_iai_cpt_latin_small() { - bench_iai_cpt_overview(false, false); -} - -fn bench_iai_cpt_mixed_fast() { - bench_iai_cpt_overview(true, true); -} - -fn bench_iai_cpt_mixed_small() { - bench_iai_cpt_overview(false, true); -} - -iai::main!( - bench_iai_cpt_latin_fast, - bench_iai_cpt_latin_small, - bench_iai_cpt_mixed_fast, - bench_iai_cpt_mixed_small, -); diff --git a/deps/crates/vendor/icu_collections-v2/benches/inv_list.rs b/deps/crates/vendor/icu_collections-v2/benches/inv_list.rs deleted file mode 100644 index 743c855af8c7..000000000000 --- a/deps/crates/vendor/icu_collections-v2/benches/inv_list.rs +++ /dev/null @@ -1,66 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use criterion::{criterion_group, criterion_main, Criterion}; -use icu_collections::codepointinvlist::CodePointInversionList; -use std::char; - -fn uniset_bench(c: &mut Criterion) { - let best_ex = [0x41, 0x46]; - let best_sample = CodePointInversionList::try_from_u32_inversion_list_slice(&best_ex).unwrap(); - let worst_ex: Vec<u32> = (0x0..((char::MAX as u32) + 1)).collect(); - let worst_sample = - CodePointInversionList::try_from_u32_inversion_list_slice(&worst_ex).unwrap(); - - c.bench_function("uniset/overview", |b| { - #[expect(clippy::suspicious_map)] - b.iter(|| { - best_sample - .iter_chars() - .map(|ch| best_sample.contains(ch)) - .count(); - worst_sample - .iter_chars() - .map(|ch| worst_sample.contains(ch)) - .count(); - best_sample - .iter_chars() - .map(|ch| best_sample.contains_range('A'..ch)) - .count(); - worst_sample - .iter_chars() - .take(100) - .map(|ch| worst_sample.contains_range(char::from_u32(0x0).unwrap()..ch)) - .count(); - }) - }); - - { - let mut group = c.benchmark_group("uniset/contains"); - group.bench_with_input("best", &best_sample, |b, sample| { - b.iter(|| sample.iter_chars().map(|ch| sample.contains(ch))) - }); - group.bench_with_input("worst", &worst_sample, |b, sample| { - b.iter(|| sample.iter_chars().take(100).map(|ch| sample.contains(ch))) - }); - group.finish(); - - let mut group = c.benchmark_group("uniset/contains_range"); - group.bench_with_input("best", &best_sample, |b, sample| { - b.iter(|| sample.iter_chars().map(|ch| sample.contains_range('A'..ch))) - }); - group.bench_with_input("worst", &worst_sample, |b, sample| { - b.iter(|| { - sample - .iter_chars() - .take(100) - .map(|ch| sample.contains_range(char::from_u32(0x0).unwrap()..ch)) - }) - }); - group.finish(); - } -} - -criterion_group!(benches, uniset_bench); -criterion_main!(benches); diff --git a/deps/crates/vendor/icu_collections-v2/benches/tries/gc_fast.rs b/deps/crates/vendor/icu_collections-v2/benches/tries/gc_fast.rs deleted file mode 100644 index ba98a40f78e8..000000000000 --- a/deps/crates/vendor/icu_collections-v2/benches/tries/gc_fast.rs +++ /dev/null @@ -1,1128 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use icu_collections::codepointtrie::{CodePointTrieHeader, TrieType}; -use zerovec::ule::AsULE; -use zerovec::{zerovec, ZeroVec}; - -#[rustfmt::skip] -pub const INDEX: ZeroVec<u16> = zerovec!(u16; <u16 as AsULE>::ULE::from_unsigned; - [ - 0,0x40,0x7f,0xbf,0xff,0x12e,0x16d,0x1ad,0x1e5,0x224,0x250,0x28e,0x2ce,0x2de,0x31e,0x34f, - 0x38c,0x3bc,0x3fa,0x43a,0x44a,0x47b,0x4b2,0x4f2,0x532,0x572,0x5a3,0x5cf,0x60f,0x644,0x65e,0x69e, - 0x6de,0x71e,0x756,0x78d,0x7ca,0x809,0x848,0x887,0x8c6,0x905,0x944,0x983,0x9c3,0xa01,0xa3f,0xa7f, - 0xabf,0xafe,0xb3e,0xb7e,0xbbe,0xbfd,0xc3d,0xc7d,0xcbc,0xcfc,0xd3b,0xd7b,0xdbb,0xdfb,0xe3b,0xe79, - 0xeb9,0xef9,0xf37,0xf71,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xfb1,0xfe8,0x1026,0x1055,0x107a,0x10ba,0x10da, - 0x111a,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x112d,0x116d,0x118d,0x11cd,0x120d,0x124d,0x128b, - 0x12cb,0x1308,0x1348,0x1378,0x13b8,0x13f8,0x1438,0x146e,0x14ae,0x14d9,0x1519,0x1558,0x1598,0x15d6,0x1616,0x1650, - 0x1690,0x16d0,0x1710,0x1750,0x1790,0x17bc,0x17a1,0x2ce,0x17fc,0x17fc,0x1826,0x17fc,0x1865,0x18a5,0x18e5,0x1924, - 0x1964,0x19a3,0x19e3,0x1a22,0x1a62,0x1aa2,0x1adf,0x1b11,0x1b45,0x1b45,0x1b45,0x1b45,0x1b85,0x1bb0,0x1bed,0x1c21, - 0x1c43,0x1c83,0x1ca7,0x1cc3,0x1d03,0x1d03,0x1bb5,0x1d42,0x1d03,0x1bbd,0x1d03,0x1d03,0x1d03,0x1d82,0x1cef,0x1dc2, - 0x1d03,0x1d03,0x1d03,0x1d03,0x1b45,0x1b45,0x1dff,0x1e27,0x1b45,0x1b45,0x1b45,0x1b45,0x1e67,0x1ea2,0x1ed8,0x1d03, - 0x38c,0x1f18,0x17fc,0x1f57,0x1f97,0x1fc7,0x2007,0x2027,0x2067,0x20a7,0x20e7,0x2102,0x1d03,0x1d03,0x1d03,0x2120, - 0x2160,0x21a0,0x21c9,0x21ea,0x222a,0x5a3,0x225b,0x229b,0x22db,0x2313,0x2329,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1d03,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x12f6,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x2369,0x23a2,0x5a3,0x5a3,0x5a3,0x5a3,0x23e2,0x2422,0x2462,0x2482,0x24c2,0x24f4,0x2532,0x256e, - 0x25ac,0x25ec,0x262c,0x2668,0x26a8,0x26e1,0x2721,0x2760,0x27a0,0x27e0,0x281e,0x285e,0x289d,0x28cd,0x28fd,0x293d, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x297d,0x29b6, - 0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6, - 0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6,0x29f6, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x2a76,0x5a3,0x2aa6,0x2ae6,0x2b26,0x2b34,0x2b71, - 0x5a3,0x5a3,0x5a3,0x5a3,0x2b84,0x2bc4,0x2bf4,0x2c2c,0x2c6c,0x2ca8,0x5a3,0x2cde,0x2d1e,0x2d5e,0x2d8f,0x2dce, - 0xac0,0xade,0xafb,0xb1a,0xb3a,0xb3a,0xb47,0xb64,0xb84,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e, - 0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e, - 0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e,0xb8e, - 0xb8e,0xb8e,0xb8e,0xb8e,0xbae,0xb8e,0xb8e,0xb8e,0xbce,0xbce,0xbce,0xbcf,0xbce,0xbce,0xbce,0xbcf, - 0x865,0x5a3,0xae1,0x2e0e,0x50f,0x50f,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x73e, - 0x2e1e,0x10a3,0x10a3,0x2e2a,0x1ac2,0x1ac2,0x1ac2,0x2e3a,0x2e43,0x1c5d,0x1c69,0xd18,0xd18,0x1d03,0x1d03,0x2e53, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x510,0x5a3,0x5a3,0x5a3,0x993,0x2e63,0x2e67, - 0x5a3,0x5a3,0x2e6f,0x5a3,0x2e7e,0x5a3,0x5a3,0x2e8e,0x5a3,0x2e9e,0x5a3,0x5a3,0x1460,0x2ead,0xd18,0xd18, - 0x41,0x41,0x342,0x28fd,0x28fd,0x5a3,0x5a3,0x5a3,0x5a3,0x50f,0xb24,0x41,0x41,0x2ebd,0x28fd,0x2ec5, - 0x5a3,0x5a3,0x13a6,0x5a3,0x5a3,0x5a3,0x2ed5,0x335,0x335,0x2ee5,0x2ef3,0x2f01,0xd18,0xd18,0xd18,0xd18, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x13a7,0x5a3,0x13a8,0x13a6,0xd18,0x2f11,0x280,0x280,0x2f16,0xd18,0xd18,0xd18,0xd18, - 0x2f26,0x5a3,0x5a3,0x2f30,0x5a3,0x2f3f,0x5a3,0x2f4f,0x5a3,0x50e,0x1c9c,0xd18,0xd18,0xd18,0x5a3,0x2f5f, - 0x5a3,0x2f6f,0x5a3,0x2f7f,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x2f8f,0x10a3,0x1ca1,0x10a3,0x10a3, - 0x2f9e,0x94e,0x5a3,0x2fae,0x2e6a,0x2fbe,0x5a3,0x2fce,0x5a3,0x2fde,0xd18,0xd18,0x2fee,0x5a3,0x2ff9,0x3009, - 0x5a3,0x5a3,0x5a3,0x3019,0x5a3,0x3029,0x5a3,0x3039,0x5a3,0x3049,0x1c9a,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x5a3,0x5a3,0x5a3,0x5a3,0x1338,0xd18,0xd18,0xd18,0x41,0x41,0x41,0x3059,0x28fd,0x28fd,0x28fd,0x3069, - 0x5a3,0x5a3,0x3079,0xb24,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x10a3,0x10a8,0x5a3,0x5a3,0x3089,0xd99,0xd18,0xd18,0xd18,0xd18,0x5a3,0x2fde,0x3099,0x5a3,0x577,0x30a9, - 0xd18,0x5a3,0x30b9,0xd18,0xd18,0x5a3,0x30c9,0xd18,0x5a3,0x13a7,0x281b,0x5a3,0x5a3,0x575,0x30d9,0x1ca1, - 0x30e9,0x30f9,0x7cb,0x5a3,0x5a3,0x3109,0x3117,0x5a3,0x1338,0xb24,0x773,0x5a3,0x3127,0x3134,0x3144,0x5a3, - 0x5a3,0x3154,0x7cb,0x5a3,0x5a3,0x3164,0x3173,0x3183,0x1ca2,0x3193,0x5a3,0x954,0x31a3,0x31b2,0xd18,0xd18, - 0xd18,0xd18,0x31c2,0x863,0x31d1,0x5a3,0x5a3,0x630,0x31e1,0xb24,0x31f1,0x858,0x868,0x3200,0x3210,0x3220, - 0x322e,0x1562,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x323e,0x324e,0x325e, - 0xd99,0xd18,0x5a3,0x5a3,0x5a3,0x326e,0x327d,0xb24,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x5a3,0x5a3,0xed5,0x328d,0x329c,0x32a4,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x32b4,0x32c3,0xb24, - 0x32d3,0xd18,0x5a3,0x5a3,0x32e3,0x32f3,0xb24,0xd18,0xd18,0xd18,0x5a3,0x108a,0x3303,0x3313,0x13a7,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x31a3,0x3323,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0x41,0x41,0x28fd,0x28fd,0xc23,0x3333,0x3342,0x334e,0x5a3,0x335e,0x336e,0xb24, - 0xd18,0xd18,0xd18,0xd18,0x2a9c,0x5a3,0x5a3,0x337e,0x338e,0xd18,0x339e,0x5a3,0x5a3,0x33ab,0x33ba,0x33ca, - 0x5a3,0x5a3,0x573,0x33da,0x33e8,0x5a3,0x5a3,0x5a3,0x5a3,0x1338,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x868,0x5a3,0xed5,0x33f8,0x3408,0xc23, - 0x10aa,0x550,0x5a3,0xe2a,0x3418,0x3427,0xd18,0xd18,0xd18,0xd18,0x96e,0x5a3,0x5a3,0x3437,0x3446,0xb24, - 0x3456,0x5a3,0x3460,0x3470,0xb24,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0x5a3,0x3480,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x993,0x10a3,0x3490,0x349f,0x34ad,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1337,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x1ac2,0x1ac2,0x1ac2,0x1ac2,0x1ac2,0x1ac2,0x34bd,0x34cd,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd97,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x34dd,0x5a3,0x5a3,0x50e,0x34ed,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x13a7,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0x5a3,0x5a3,0x5a3,0x1338,0x5a3,0x50e,0x2770,0x5a3,0x5a3,0x5a3,0x5a3,0x50e,0xb24,0x5a3,0x50f, - 0x34fd,0x5a3,0x5a3,0x5a3,0x350d,0x351d,0x352d,0x353b,0x741,0x5a3,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0x41,0x41,0x28fd,0x28fd,0x10a3,0x354b,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3, - 0x5a3,0xe1d,0x355b,0x355c,0x355c,0x3564,0x3573,0xd18,0xd18,0xd18,0xd18,0x3581,0x3591,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x13a6,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x13a8,0xd18,0xd18,0x1338,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x35a1,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0xd98,0xd18,0xd18,0xd98,0x2ed1,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x511,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x73e,0x510,0x1338,0x35b1,0x35c1, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x2ce,0x2ce,0x641,0x2ce,0x1560,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1c66,0xd18,0xd18,0xd18,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x1d03,0x1d03,0x1c64,0x1d03,0x1d03,0x1ecf,0x1d03,0x1d03,0x1d03,0x35d1,0x35de,0x35eb,0x1d03,0x35f7, - 0x1d03,0x1d03,0x1d03,0x1c5f,0xd18,0x1d03,0x1d03,0x1d03,0x1d03,0x3605,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0x10a3,0x3615,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1c63,0x10a3,0x2e6a,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x41,0x3b2,0x28fd,0x3625,0x3ae,0x2ef0,0x1865,0x41,0xdc,0x3635,0x3645, - 0x3653,0x2ef1,0x41,0x3b2,0x28fd,0x3660,0x366d,0x28fd,0x367b,0x368b,0x369a,0x369e,0x41,0xd8,0x28fd,0x41, - 0x3b2,0x28fd,0x3625,0x3ae,0x28fd,0x1865,0x41,0xdc,0x369e,0x41,0xd8,0x28fd,0x41,0x3b2,0x28fd,0x36ae, - 0x41,0x36bd,0xeb,0x38a,0x36cd,0x28fd,0x36d9,0x41,0x36b9,0xe7,0x36c7,0xc7,0x28fd,0xed,0x41,0x36e5, - 0x28fd,0x36f2,0x3700,0x3700,0x3700,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x2ce,0x2ce,0x2ce,0x3710,0x2ce,0x2ce,0x371b,0x3728,0x3734,0x1a27,0x4c2, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x25a,0x1fae,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xe4c,0x3744,0x3752,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x510,0x3762,0x3772,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x3782,0xd18,0x5a3,0x5a3,0x633,0x3792,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x37a2,0x50e,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x37b2,0x1560,0xd18,0xd18,0x41,0x41,0xdc,0x28fd, - 0x37c2,0x2770,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x1ca2,0x10a3,0x10a3,0x37d2, - 0x37e2,0xd18,0xd18,0xd18,0xd18,0x1ca2,0x10a3,0x37f2,0x10a9,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xae4,0x5a3,0x3802,0x380f,0x381d,0x382d,0x383b,0x3843,0x867,0x511,0x3852, - 0x511,0xd18,0xd18,0xd18,0x3862,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x1d03,0x1d03,0x1c5e,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1c66,0x1c5b, - 0x148b,0x148b,0x148b,0x1d03,0x1c64,0x1cb6,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1c5c, - 0xd18,0xd18,0xd18,0x1c7d,0x1d03,0x1c67,0x1d03,0x1d03,0x1c5e,0x1c61,0x1c68,0x1c64,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x1d03,0x1d03,0x3872,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x3882,0x1c5d,0x1c5d,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1c66,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x1c61,0x1c5e,0x1c69,0x1c5e,0x1d03,0x1d03,0x1d03,0x1c62,0x10ca,0x1d03,0x1d03,0x1c62,0x1d03,0x1c5c, - 0x1c68,0xd18,0xd18,0xd18,0xd18,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03, - 0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1c66,0x1c5c,0x388f,0x1c63,0x1d03,0x1c5d,0x1c5f,0x1c64,0x10ca,0x1c62,0x1c63, - 0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1d03,0x1eeb,0x1d03,0x1d03,0x1c5f,0xd18,0xd18,0xb24, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd18,0xd18, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x1338,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x50f,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd99, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x993,0xd18, - 0x5a3,0x50f,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x73e,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x389e,0xd18,0x38ae,0x38ae,0x38ae,0x38ae,0x38ae,0x38ae,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0xd18, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36, - 0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x2a36,0x38be, - 0x440,0x460,0x480,0x4a0,0x4c0,0x4e0,0x500,0x51a,0x53a,0x55a,0x57a,0x59a,0x5ba,0x5da,0x5fa,0x615, - 0xd0,0x635,0x655,0x66a,0x66a,0x66a,0x66a,0x671,0xd0,0xd0,0x691,0x66a,0x66a,0x66a,0x66a,0x66a, - 0xd0,0x6b1,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a, - 0x66a,0x66a,0xd0,0x6d1,0x66a,0x6ed,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0x70d,0xd0, - 0xd0,0x72d,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a, - 0x66a,0x66a,0x73e,0x75e,0x775,0x66a,0x66a,0x66a,0x66a,0x795,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a, - 0x66a,0x7a5,0x7c5,0x7e5,0x805,0x825,0x845,0x865,0x66a,0x875,0x895,0x8ac,0x66a,0x8bc,0x8dc,0x66a, - 0x8f5,0x915,0x935,0x955,0x845,0x975,0x995,0x9b0,0x66a,0x66a,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0x9d0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0x9e0,0x9ff,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xa15,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xa20,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a, - 0xd0,0xa40,0x66a,0x66a,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xa60,0x66a,0x66a, - 0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a, - 0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0xa80,0x66a, - 0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a, - 0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x66a,0x380,0x380, - 0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380, - 0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0x380,0xaa0 - ] -); - -#[rustfmt::skip] -pub const DATA: ZeroVec<u8> = zerovec!(u8; core::convert::identity; - [ - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0xc,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17, - 9,9,9,9,9,9,9,9,9,9,0x17,0x17,0x18,0x18,0x18,0x17, - 0x17,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0x14,0x17,0x15,0x1a,0x16, - 0x1a,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,0x14,0x18,0x15,0x18,0xf, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xc, - 0x17,0x19,0x19,0x19,0x19,0x1b,0x17,0x1a,0x1b,5,0x1c,0x18,0x10,0x1b,0x1a,0x1b, - 0x18,0xb,0xb,0x1a,2,0x17,0x17,0x1a,0xb,5,0x1d,0xb,0xb,0xb,0x17,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,0x18,1,1,1,1,1,1,1,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,0x18,2,2,2,2,2,2,2,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,1,2,1,2,1,2,2,1,1, - 2,1,2,1,1,2,1,1,1,2,2,1,1,1,1,2, - 1,1,2,1,1,1,2,2,2,1,1,2,1,1,2,1, - 2,1,2,1,1,2,1,2,2,1,2,1,1,2,1,1, - 1,2,1,2,1,1,2,2,5,1,2,2,2,5,5,5, - 5,1,3,2,1,3,2,1,3,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,2,1,3, - 2,1,2,1,1,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,2,2,2,2,2,2,1, - 1,2,1,1,2,1,2,1,1,1,1,2,1,2,1,2, - 1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,5,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 0x1a,0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,4,4,4, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4, - 4,4,4,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,0x1a,4,0x1a,0x1a,0x1a, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,1,2, - 1,2,4,0x1a,1,2,0,0,4,2,2,2,0x17,1,0,0, - 0,0,0x1a,0x1a,1,0x17,1,1,1,0,1,0,1,1,2,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2, - 2,1,1,1,2,2,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,2, - 2,2,2,1,2,0x18,1,2,1,1,2,2,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,0x1b,6,6,6, - 6,6,7,7,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,0,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,0,0,4,0x17,0x17,0x17,0x17,0x17,0x17,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,0x17,0x13,0,0,0x1b, - 0x1b,0x19,0,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 0x13,6,0x17,6,6,0x17,6,6,0x17,6,0,0,0,0,0,0, - 0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, - 0,5,5,5,5,0x17,0x17,0,0,0,0,0,0,0,0,0, - 0,0,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x18,0x18,0x17,0x17,0x19,0x17,0x17, - 0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,0x17,0x10,0x17, - 0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,4,5,5,5,5,5,5,5,5,5,5,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,9,9,9,9,9,9,9,9,9,9,0x17,0x17,0x17,0x17, - 5,5,6,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,0x17,5,6,6,6,6,6,6,6,0x10,0x1b,6,6, - 6,6,6,6,4,4,6,6,0x1b,6,6,6,6,5,5,9, - 9,9,9,9,9,9,9,9,9,5,5,5,0x1b,0x1b,5,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0x10,5, - 6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,5, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9, - 9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6, - 6,6,4,4,0x1b,0x17,0x17,0x17,4,0,0,6,0x19,0x19,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,6,6,6,4,6,6,6,6,6,6,6, - 6,6,4,6,6,6,4,6,6,6,6,6,0,0,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,6,6,6,0,0,0x17,0,5,5, - 5,5,5,5,5,5,5,5,5,0,0,0,0,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1a,5, - 5,5,5,5,5,0,0x10,0x10,0,0,0,0,0,0,6,6, - 6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,4,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0x10, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,8,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,8,6,5,8,8,6,6,6,6,6,6, - 6,6,8,8,8,8,6,8,8,5,6,6,6,6,6,6, - 6,5,5,5,5,5,5,5,5,5,5,6,6,0x17,0x17,9, - 9,9,9,9,9,9,9,9,9,0x17,4,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,8,8,0,5,5,5, - 5,5,5,5,5,0,0,5,5,0,0,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0,5,5,5,5,5,5,5,0,5,0,0,0,5,5, - 5,5,0,0,6,5,8,8,6,6,6,6,0,0,8,8, - 0,0,8,8,6,5,0,0,0,0,0,0,0,0,8,0, - 0,0,0,5,5,0,5,5,5,6,6,0,0,9,9,9, - 9,9,9,9,9,9,9,5,5,0x19,0x19,0xb,0xb,0xb,0xb,0xb, - 0xb,0x1b,0x19,5,0x17,6,0,6,6,8,0,5,5,5,5,5, - 5,0,0,0,0,5,5,0,0,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 5,5,5,5,5,5,5,0,5,5,0,5,5,0,5,5, - 0,0,6,0,8,8,6,6,0,0,0,0,6,6,0,0, - 6,6,6,0,0,0,6,0,0,0,0,0,0,0,5,5, - 5,5,0,5,0,0,0,0,0,0,0,9,9,9,9,9, - 9,9,9,9,9,6,6,5,5,5,6,0x17,0,0,0,0, - 0,0,0,0,0,6,6,8,0,5,5,5,5,5,5,5, - 5,5,0,5,5,5,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5, - 5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0, - 6,5,8,8,6,6,6,6,6,0,6,6,8,0,8,8, - 6,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,5,5,6,6,0,0,9,9,9,9,9,9,9, - 9,9,9,0x17,0x19,0,0,0,0,0,0,0,5,6,6,6, - 6,6,6,0,6,8,8,0,5,5,5,5,5,5,5,5, - 0,0,5,5,0,0,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5, - 5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,6, - 5,8,6,6,6,6,0,0,8,8,0,0,8,8,6,0, - 0,0,0,0,0,0,6,6,8,0,0,0,0,5,5,0, - 5,5,5,6,6,0,0,9,9,9,9,9,9,9,9,9, - 9,0x1b,5,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0, - 0,6,5,0,5,5,5,5,5,5,0,0,0,5,5,5, - 0,5,5,5,5,0,0,0,5,5,0,5,0,5,5,0, - 0,0,5,5,0,0,0,5,5,5,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,0,0,0,0,8,8,6, - 8,8,0,0,0,8,8,8,0,8,8,8,6,0,0,5, - 0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,0xb, - 0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x1b,0,0,0,0,0,6, - 8,8,8,6,5,5,5,5,5,5,5,5,0,5,5,5, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,0,0,6,5,6,6,8, - 8,8,8,0,6,6,6,0,6,6,6,6,0,0,0,0, - 0,0,0,6,6,0,5,5,5,0,0,5,0,0,5,5, - 6,6,0,0,9,9,9,9,9,9,9,9,9,9,0,0, - 0,0,0,0,0,0x17,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x1b,5,6, - 8,8,0x17,5,5,5,5,5,5,5,5,0,5,5,5,0, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5, - 5,5,0,5,5,5,5,5,0,0,6,5,8,6,8,8, - 8,8,8,0,6,8,8,0,8,8,6,6,0,0,0,0, - 0,0,0,8,8,0,0,0,0,0,0,5,5,0,5,5, - 6,6,0,0,9,9,9,9,9,9,9,9,9,9,0,5, - 5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6, - 8,8,5,5,5,5,5,5,5,5,5,0,5,5,5,0, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,6,5,8,8,6,6, - 6,6,0,8,8,8,0,8,8,8,6,5,0x1b,0,0,0, - 0,5,5,5,8,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,6, - 6,0,0,9,9,9,9,9,9,9,9,9,9,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0x1b,5,5,5,5,5,5,0,6,8, - 8,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,0,0,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 5,5,5,5,5,5,5,5,5,0,5,0,0,5,5,5, - 5,5,5,5,0,0,0,6,0,0,0,0,8,8,8,6, - 6,6,0,6,0,8,8,8,8,8,8,8,8,0,0,0, - 0,0,0,9,9,9,9,9,9,9,9,9,9,0,0,8, - 8,0x17,0,0,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,6,5,5, - 6,6,6,6,6,6,6,0,0,0,0,0x19,5,5,5,5, - 5,5,4,6,6,6,6,6,6,6,6,0x17,9,9,9,9, - 9,9,9,9,9,9,0x17,0x17,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,5, - 0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 5,0,5,5,5,5,5,5,5,5,5,5,6,5,5,6, - 6,6,6,6,6,6,6,6,5,0,0,5,5,5,5,5, - 0,4,0,6,6,6,6,6,6,0,0,9,9,9,9,9, - 9,9,9,9,9,0,0,5,5,5,5,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,5,0x1b,0x1b,0x1b,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,0x17, - 0x1b,0x1b,0x1b,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,9,9,9,9,9, - 9,9,9,9,9,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x1b, - 6,0x1b,6,0x1b,6,0x14,0x15,0x14,0x15,8,8,5,5,5,5,5, - 5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0,0,0,0,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,8,6,6,6,6,6, - 0x17,6,6,5,5,5,5,5,6,6,6,6,6,6,6,6, - 6,6,6,0,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b, - 0x1b,0x1b,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,8,8,6,6,6,6,8,6,6,6,6,6, - 6,8,6,6,8,8,6,6,5,9,9,9,9,9,9,9, - 9,9,9,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,5,5,8, - 8,6,6,5,5,5,5,6,6,6,5,8,8,8,5,5, - 8,8,8,8,8,8,8,5,5,5,6,6,6,6,5,5, - 5,5,5,5,5,5,5,5,5,6,8,8,6,6,8,8, - 8,8,8,8,6,5,8,9,9,9,9,9,9,9,9,9, - 9,8,8,8,6,0x1b,0x1b,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,0, - 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,0x17,4,2,2, - 2,5,5,5,5,5,5,5,5,5,0,5,5,5,5,0, - 0,5,5,5,5,5,5,5,0,5,0,5,5,5,5,0, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0,5,5,5,5,0,0,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,0,5,5,5,5,0,0, - 5,5,5,5,5,5,5,0,5,5,5,5,0,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,0,5,5,5,5,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,0,0,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,2,2,2,2,2,2,0,0,0x13,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0x1b,0x17,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0xc,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0x14,0x15,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0x17,0x17,0x17,0xa,0xa,0xa,5,5, - 5,5,5,5,5,5,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, - 6,6,8,0,0,0,0,0,0,0,0,0,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, - 6,8,0x17,0x17,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, - 6,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0,5,5,5,0,6, - 6,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,6,6,8,6,6,6,6,6,6,6,8,8,8,8,8, - 8,6,8,8,6,6,6,6,6,6,6,6,6,6,6,0x17, - 0x17,0x17,4,0x17,0x17,0x17,0x19,5,6,0,0,9,9,9,9,9, - 9,9,9,9,9,0,0,0,0,0,0,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x17, - 0x17,0x13,0x17,0x17,0x17,0x17,6,6,6,0x10,6,9,9,9,9,9, - 9,9,9,9,9,0,0,0,0,0,0,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0,0,0,0,0,0,0,5,5,5,5,5,6,6,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,6,5,0,0,0,0,0,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, - 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,0,6,6,6,8,8,8,8,6, - 6,8,8,8,0,0,0,0,8,8,6,8,8,8,8,8, - 8,6,6,6,0,0,0,0,0x1b,0,0,0,0x17,0x17,9,9, - 9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,0,0,5,5,5,5,5,0,0,0, - 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,0,0,0,0,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0,0,0,0,0,0,9,9, - 9,9,9,9,9,9,9,9,0xb,0,0,0,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,6,6,8,8,6,0,0,0x17,0x17,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,8,6, - 8,6,6,6,6,6,6,6,0,6,8,6,8,8,6,6, - 6,6,6,6,6,6,8,8,8,8,8,8,6,6,6,6, - 6,6,6,6,6,6,0,0,6,9,9,9,9,9,9,9, - 9,9,9,0,0,0,0,0,0,9,9,9,9,9,9,9, - 9,9,9,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 4,0x17,0x17,0x17,0x17,0x17,0x17,0,0,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,7,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,6,6,6,6,8,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,6,8,6,6, - 6,6,6,8,6,8,8,8,6,8,8,5,5,5,5,5, - 5,5,5,0,0,0,9,9,9,9,9,9,9,9,9,9, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,6,6,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x17,0x17,0,6,6,8,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,8,6,6,6,6,8,8,6,6, - 8,6,6,6,5,5,9,9,9,9,9,9,9,9,9,9, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,6,8,6,6,8,8,8,6,8,6, - 6,6,8,8,0,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,8,8,8,8,8,8,8,8,6,6,6,6, - 6,6,6,6,8,8,6,6,0,0,0,0x17,0x17,0x17,0x17,0x17, - 9,9,9,9,9,9,9,9,9,9,0,0,0,5,5,5, - 9,9,9,9,9,9,9,9,9,9,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,4,4,4,4,4,4,0x17,0x17, - 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0, - 6,6,6,0x17,6,6,6,6,6,6,6,6,6,6,6,6, - 6,8,6,6,6,6,6,6,6,5,5,5,5,6,5,5, - 5,5,5,5,6,5,5,8,6,6,5,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2, - 2,2,2,2,4,2,2,2,2,2,2,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,2,2,2,2, - 2,2,2,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,2,2,2,2,2,2,2,1,1,1, - 1,1,1,1,1,2,2,2,2,2,2,0,0,1,1,1, - 1,1,1,0,0,2,2,2,2,2,2,2,2,1,1,1, - 1,1,1,1,1,2,2,2,2,2,2,2,2,1,1,1, - 1,1,1,1,1,2,2,2,2,2,2,0,0,1,1,1, - 1,1,1,0,0,2,2,2,2,2,2,2,2,0,1,0, - 1,0,1,0,1,2,2,2,2,2,2,2,2,1,1,1, - 1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,0,0,2,2,2,2,2,2,2,2,3,3,3, - 3,3,3,3,3,2,2,2,2,2,2,2,2,3,3,3, - 3,3,3,3,3,2,2,2,2,2,2,2,2,3,3,3, - 3,3,3,3,3,2,2,2,2,2,0,2,2,1,1,1, - 1,3,0x1a,2,0x1a,0x1a,2,2,2,0,2,2,1,1,1,1, - 3,0x1a,0x1a,0x1a,2,2,2,2,0,0,2,2,1,1,1,1, - 0,0x1a,0x1a,0x1a,2,2,2,2,2,2,2,2,1,1,1,1, - 1,0x1a,0x1a,0x1a,0,0,2,2,2,0,2,2,1,1,1,1, - 3,0x1a,0x1a,0,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x10, - 0x10,0x10,0x10,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x1c,0x1d,0x14,0x1c, - 0x1c,0x1d,0x14,0x1c,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xd,0xe,0x10,0x10, - 0x10,0x10,0x10,0xc,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1c,0x1d,0x17, - 0x17,0x17,0x17,0x16,0x17,0x17,0x17,0x18,0x14,0x15,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x18,0x17,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x17,0xc,0x10,0x10,0x10,0x10,0x10,0,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x10,0x10,0x10,0xb,4,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0x18,0x18,0x18, - 0x14,0x15,4,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x18,0x18,0x18, - 0x14,0x15,0,4,4,4,4,4,4,4,4,4,4,4,4,4, - 0,0,0,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, - 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, - 0x19,0x19,0x19,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,7, - 7,7,7,6,7,7,7,6,6,6,6,6,6,6,6,6, - 6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0x1b,0x1b,1,0x1b,0x1b,0x1b,0x1b,1,0x1b,0x1b,2,1,1,1, - 2,2,1,1,1,2,0x1b,1,0x1b,0x1b,0x18,1,1,1,1,1, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1,0x1b,1,0x1b,1,0x1b,1,1,1,1, - 0x1b,2,1,1,1,1,2,5,5,5,5,2,0x1b,0x1b,2,2, - 1,1,0x18,0x18,0x18,0x18,0x18,1,2,2,2,2,0x1b,0x18,0x1b,0x1b, - 2,0x1b,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xa,0xa,1,2,0xa,0xa,0xa,0xa,0xb,0x1b,0x1b,0,0,0,0,0x18, - 0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x18, - 0x1b,0x1b,0x18,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18, - 0x18,0x1b,0x1b,0x18,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14, - 0x15,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18, - 0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15, - 0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15, - 0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15, - 0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14, - 0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x14,0x15,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,1,2,1,1,1,2,2,1, - 2,1,2,1,2,1,1,1,1,2,1,2,2,1,2,2, - 2,2,2,2,4,4,1,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,2,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,1,2,1,2,6,6,6,1,2,0,0,0,0,0, - 0x17,0x17,0x17,0x17,0xb,0x17,0x17,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,0, - 0,0,0,0,2,0,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 0,0,0,0,0,0,4,0x17,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,6,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, - 0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,5, - 5,5,5,5,5,5,0,5,5,5,5,5,5,5,0,5, - 5,5,5,5,5,5,0,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,0x17,0x17,0x1c,0x1d,0x1c,0x1d,0x17,0x17,0x17, - 0x1c,0x1d,0x17,0x1c,0x1d,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x17, - 0x17,0x13,0x17,0x1c,0x1d,0x17,0x17,0x1c,0x1d,0x14,0x15,0x14,0x15,0x14,0x15,0x14, - 0x15,0x17,0x17,0x17,0x17,0x17,4,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x13,0x13,0x17,0x17,0x17,0x17,0x13,0x17,0x14,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x17,0x17,0x17,0x14,0x15,0x14,0x15, - 0x14,0x15,0x14,0x15,0x13,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0, - 0xc,0x17,0x17,0x17,0x1b,4,5,0xa,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15, - 0x14,0x15,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0x14,0x15,0x15, - 0x1b,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,6,6,6,6,8,8, - 0x13,4,4,4,4,4,0x1b,0x1b,0xa,0xa,0xa,4,5,0x17,0x1b,0x1b, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 0,0,6,6,0x1a,0x1a,4,4,5,0x13,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,0x17,4,4,4,5,0,0,0,0,0,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0,0x1b,0x1b,0xb,0xb,0xb, - 0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0, - 0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0x1b,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,5,5,5,5, - 5,5,5,5,5,5,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0, - 0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4, - 0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,4,0x17, - 0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,9,9,9,9,9,9,9,9,9,9,5,5,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 5,6,7,7,7,0x17,6,6,6,6,6,6,6,6,6,6, - 0x17,4,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,4,4, - 6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xa,0xa,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0, - 0,0,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4,4,4,4,4,4, - 4,4,0x1a,0x1a,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,2,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,4,2,2,2,2,2,2,2,2,1,2,1, - 2,1,1,2,1,2,1,2,1,2,4,0x1a,0x1a,1,2,1, - 2,5,1,2,1,2,2,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,1,1,1, - 1,2,1,1,1,1,1,2,1,2,1,2,1,2,1,2, - 1,2,1,1,1,1,2,1,2,0,0,0,0,0,1,2, - 0,2,0,2,1,2,1,2,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 4,4,4,1,2,5,4,4,2,5,5,5,5,5,6,5, - 5,5,6,5,5,5,5,6,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8, - 8,6,6,8,0x1b,0x1b,0x1b,0x1b,6,0,0,0,0xb,0xb,0xb,0xb, - 0xb,0xb,0x1b,0x1b,0x19,0x1b,0,0,0,0,0,0,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,8,8,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 8,8,8,8,8,8,8,8,8,8,8,8,6,6,0,0, - 0,0,0,0,0,0,0x17,0x17,9,9,9,9,9,9,9,9, - 9,9,0,0,0,0,0,0,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5, - 0x17,0x17,0x17,5,0x17,5,5,6,9,9,9,9,9,9,9,9, - 9,9,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6, - 6,6,6,6,6,6,0x17,0x17,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6, - 6,6,6,8,8,0,0,0,0,0,0,0,0,0,0,0, - 0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, - 0,6,6,6,8,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,8,8,6,6,6,6,8,8,6,6,8, - 8,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4, - 9,9,9,9,9,9,9,9,9,9,0,0,0,0,0x17,0x17, - 5,5,5,5,5,6,4,5,5,5,5,5,5,5,5,5, - 9,9,9,9,9,9,9,9,9,9,5,5,5,5,5,0, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,8, - 8,6,6,8,8,6,6,0,0,0,0,0,0,0,0,0, - 5,5,5,6,5,5,5,5,5,5,5,5,6,8,0,0, - 9,9,9,9,9,9,9,9,9,9,0,0,0x17,0x17,0x17,0x17, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 4,5,5,5,5,5,5,0x1b,0x1b,0x1b,5,8,6,8,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,5, - 6,6,6,5,5,6,6,5,5,5,5,5,6,6,5,6, - 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,5,5,4,0x17,0x17,5,5, - 5,5,5,5,5,5,5,5,5,8,6,6,8,8,0x17,0x17, - 5,4,4,8,6,0,0,0,0,0,0,0,0,0,5,5, - 5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5, - 5,5,5,5,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,0,5,5,5,5,5,5,5,0,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,0x1a,4,4,4,4,2,2,2, - 2,2,2,2,2,2,4,0x1a,0x1a,0,0,0,0,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 8,8,6,8,8,6,8,8,0x17,8,6,0,0,9,9,9, - 9,9,9,9,9,9,9,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,0,0,0,0,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0, - 0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0, - 0,0,0,5,6,5,5,5,5,5,5,5,5,5,5,0x18, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5, - 5,5,5,0,5,0,5,5,0,5,5,0,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, - 0x1a,0x1a,0x1a,0x1a,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,0x15,0x14,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,0,0,0,0,0,0,0,0x1b,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, - 5,5,5,5,5,5,5,5,0x19,0x1b,0x1b,0x1b,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0x14,0x15,0x17,0,0,0,0,0,0,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,0x17,0x13,0x13,0x16, - 0x16,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x14, - 0x15,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x17,0x17,0x17,0,0x17,0x17,0x17,0x17, - 0x13,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x18,0x13,0x18,0x18,0x18,0, - 0x17,0x19,0x17,0x17,0,0,0,0,5,5,5,5,5,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0,0,0x10,0,0x17, - 0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17,9,9, - 9,9,9,9,9,9,9,9,0x17,0x17,0x18,0x18,0x18,0x17,0x17,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,0x14,0x17,0x15,0x1a,0x16,0x1a,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,0x14,0x18,0x15,0x18,0x14,0x15,0x17, - 0x14,0x15,0x17,0x17,5,5,5,5,5,5,5,5,5,5,4,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0, - 5,5,5,5,5,5,0,0,5,5,5,5,5,5,0,0, - 5,5,5,5,5,5,0,0,5,5,5,0,0,0,0x19,0x19, - 0x18,0x1a,0x1b,0x19,0x19,0,0x1b,0x18,0x18,0x18,0x18,0x1b,0x1b,0,0,0, - 0,0,0,0,0,0,0,0x10,0x10,0x10,0x1b,0x1b,0,0,5,5, - 5,5,5,5,5,5,5,5,5,0,5,5,0,5,0x17,0x17, - 0x17,0,0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0,0, - 0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xa,0xa,0xa,0xa,0xa,0xb, - 0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0x1b, - 0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 6,0,0,6,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0,0,0,0,0,0,0,0,0,5,5,5,0xa, - 5,5,5,5,5,5,5,5,0xa,0,0,0,0,0,5,5, - 5,5,5,5,6,6,6,6,6,0,0,0,0,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,0,0x17,0xa,0xa, - 0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,1,1,1, - 1,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2, - 2,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0, - 0,0,0,0,0x17,1,1,1,0,1,1,0,2,2,2,2, - 2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2, - 2,2,2,0,2,2,2,2,2,2,2,0,2,2,0,0, - 0,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4, - 4,0,0,0,0,0,5,5,5,5,5,5,0,0,5,0, - 5,5,5,5,5,5,0,5,5,0,0,0,5,0,0,5, - 5,5,5,5,5,0,0x17,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5, - 5,5,5,5,5,5,0x1b,0x1b,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5, - 5,5,0,5,5,0,0,0,0,0,0xb,0xb,0xb,0xb,0xb,5, - 5,5,5,5,5,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0x17,5, - 5,5,5,5,5,5,5,5,5,0,0,0,0,0,0x17,5, - 5,5,5,5,5,5,5,0,0,0,0,0xb,0xb,5,5,6, - 6,6,0,6,6,0,0,0,0,0,6,6,6,6,5,5, - 5,5,5,5,0,0,6,6,6,0,0,0,0,6,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0xb,0xb,0x17,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0xb,0xb,0xb,5,5, - 5,5,5,5,5,5,0x1b,5,5,5,5,5,5,5,6,6, - 0,0,0,0,0xb,0xb,0xb,0xb,0xb,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0, - 0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,5,5,0, - 0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,0,0,0,0, - 0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,0,0,0,0,0, - 0,0,0x17,0x17,0x17,0x17,0,0,0,1,1,1,0,0,0,0, - 0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0, - 0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,5,6,6,6, - 6,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, - 5,5,5,0,6,6,0x13,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 5,0,0,0,0,0,0,0,0,6,0xb,0xb,0xb,0xb,0x17,0x17, - 0x17,0x17,0x17,0,0,0,0,0,0,5,5,6,6,6,6,0x17, - 0x17,0x17,0x17,0,0,0,0,0,0,5,5,5,5,5,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0,0,0,0,6,6,6,6,6,6,6, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0xb,0xb,0xb,0xb,0xb,0xb,9, - 9,9,9,9,9,9,9,9,9,6,5,5,6,6,5,0, - 0,0,0,0,0,0,0,0,6,8,8,8,6,6,6,6, - 8,8,6,6,0x17,0x17,0x10,0x17,0x17,6,0,0,0,0,0,0, - 0,0,0,0,0x10,0,0,5,5,5,5,5,5,5,6,6, - 6,6,6,8,6,6,6,6,6,0,9,9,9,9,9,9, - 9,9,9,9,0x17,0x17,0x17,0x17,5,8,8,5,0,0,0,0, - 0,0,0,0,5,5,5,6,0x17,0x17,5,0,0,0,0,0, - 0,0,0,0,5,5,5,8,8,8,6,6,6,6,6,6, - 6,6,6,8,5,5,5,5,0x17,0x17,0x17,0x17,6,6,6,6, - 0x17,8,6,9,9,9,9,9,9,9,9,9,9,5,0x17,5, - 0x17,0x17,0x17,0xb,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0,0, - 0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,8, - 8,8,6,6,8,8,6,8,6,6,0x17,0x17,0x17,0x17,0x17,0x17, - 6,0,5,5,5,5,5,5,5,0,5,0,5,5,5,5, - 0,5,5,5,5,5,5,5,5,5,0x17,0,0,0,0,0, - 0,8,8,8,6,6,6,6,6,6,6,6,0,0,0,0, - 0,6,6,8,8,0,5,5,5,5,5,5,5,5,0,0, - 5,0,5,5,0,5,5,5,5,5,0,6,6,5,8,8, - 6,8,8,8,8,0,0,8,8,0,0,8,8,8,0,0, - 5,0,0,0,0,0,0,8,0,0,0,0,0,5,5,5, - 8,8,0,0,6,6,6,6,6,6,6,0,0,0,5,5, - 5,5,5,8,8,8,6,6,6,6,6,6,6,6,8,8, - 6,6,6,8,6,5,5,5,5,0x17,0x17,0x17,0x17,0x17,9,9, - 9,9,9,9,9,9,9,9,0x17,0x17,0,0x17,6,5,8,8, - 8,6,6,6,6,6,6,8,6,8,8,8,8,6,8,6, - 6,5,5,0x17,5,0,0,0,0,0,0,0,0,8,8,6, - 6,6,6,0,0,8,8,8,8,6,6,8,6,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5, - 6,6,0,0,8,8,8,6,6,6,6,6,6,6,6,8, - 8,6,8,6,0x17,0x17,0x17,5,0,0,0,0,0,0,0,0, - 0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0,0,0,5,5,5,5,5,5,5,5,5,5,5,6,8, - 6,8,8,6,6,6,6,6,6,8,6,5,0x17,0,0,0, - 0,0,0,8,8,6,6,6,6,8,6,6,6,6,6,0, - 0,0,0,9,9,9,9,9,9,9,9,9,9,0xb,0xb,0x17, - 0x17,0x17,0x1b,6,6,6,6,6,6,6,6,8,6,6,0x17,0, - 0,0,0,0xb,0xb,0xb,0,0,0,0,0,0,0,0,0,0, - 0,0,5,5,5,5,5,5,5,0,0,5,0,0,5,5, - 5,5,0,5,5,0,5,5,5,5,5,5,5,5,8,8, - 8,8,8,8,0,8,8,0,0,6,6,8,6,5,8,5, - 8,6,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,5,8, - 8,8,6,6,6,6,0,0,6,6,8,8,8,8,6,5, - 0x17,5,8,0,0,0,0,0,0,0,0,0,0,0,5,6, - 6,6,6,6,6,6,6,6,6,5,5,5,5,5,6,6, - 6,6,6,6,8,5,6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,6,0,0,0,0,0,0,0,0,5,6,6,6,6,6, - 6,8,8,6,6,6,5,5,5,5,6,6,6,6,6,6, - 6,8,6,6,0x17,0x17,0x17,5,0x17,0x17,0x17,0,0,0,0,0, - 0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,0, - 6,6,6,6,6,6,8,6,5,0x17,0x17,0x17,0x17,0x17,0,0, - 0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6, - 0,8,6,6,6,6,6,6,8,6,6,8,6,6,0,0, - 0,0,0,0,0,0,0,5,6,6,6,6,6,6,0,0, - 0,6,0,6,6,0,6,6,6,6,6,6,5,6,0,0, - 0,0,0,0,0,0,5,5,5,5,5,5,0,5,5,0, - 5,5,5,5,5,5,5,5,5,5,8,8,8,8,8,0, - 6,6,0,8,8,6,8,6,5,0,0,0,0,0,0,0, - 5,5,5,6,6,8,8,0x17,0x17,0,0,0,0,0,0,0, - 0xb,0xb,0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x19,0x19, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0x17,0xa,0xa,0xa, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0x17,0x17,0x17, - 0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,5,0x17,0x17, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0x10,0x10,0x10, - 0x10,0x10,0x10,0x10,0x10,0x10,0,0,0,0,0,0,0,6,6,6, - 6,6,0x17,0,0,0,0,0,0,0,0,0,0,6,6,6, - 6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x1b,0x1b,4,4,4, - 4,0x17,0x1b,0,0,0,0,0,0,0,0,0,0,9,9,9, - 9,9,9,9,9,9,9,0,0xb,0xb,0xb,0xb,0xb,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0x17,0x17,0x17,0x17,0,0,0,0,0,5,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0, - 0,0,0,6,6,6,4,4,4,4,4,4,4,4,4,4, - 4,4,4,0x17,4,6,0,0,0,0,0,0,0,0,0,0, - 0,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,4,4,4,4,0,4,4,4,4,4,4,4,0,4,4, - 0,5,5,5,5,5,5,5,5,5,5,0,0,0x1b,6,6, - 0x17,0x10,0x10,0x10,0x10,0,0,0,0,0,0,0,0,0,0,0, - 0,0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b,0x1b,8,8, - 8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,6,6,6,6,0x1b,0x1b, - 6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,6,6,6,6,0x1b,0x1b,6,6,6,0x1b,0,0,0,0,0, - 0,0,0,0,0,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0, - 0,0,0,0,0,2,2,2,2,1,1,1,1,1,1,1, - 1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2, - 2,1,0,1,1,0,0,1,0,0,1,1,0,0,1,1, - 1,1,0,1,1,1,1,1,1,2,2,2,2,0,2,0, - 2,2,2,2,1,1,0,1,1,1,1,0,0,1,1,1, - 1,1,0,1,1,1,1,1,1,1,0,2,2,2,2,2, - 2,2,2,1,1,0,1,1,1,1,0,1,1,1,1,1, - 0,1,0,0,0,1,1,1,1,1,1,0,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2, - 2,2,2,2,0,0,1,1,1,1,1,1,1,1,0x18,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1, - 1,1,1,1,1,1,1,1,0x18,2,2,2,2,2,0x18,2, - 2,2,2,2,2,1,1,1,1,1,1,1,1,1,0x18,2, - 2,2,2,2,2,0x18,2,2,2,2,2,2,1,2,0,0, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,6,6,6,6,6, - 6,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17, - 0,0,0,0,6,6,6,6,6,6,6,6,6,0,0,6, - 6,6,6,6,0,6,6,0,6,6,6,6,6,0,0,0, - 0,0,6,6,6,6,6,6,6,4,4,4,4,4,4,4, - 0,0,9,9,9,9,9,9,9,9,9,9,0,0,0,0, - 5,0x1b,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,0,9,9,9,9,9,9,9,9,9,9,0,0,0,0, - 0,0x19,5,5,5,5,5,5,5,0,5,5,5,5,0,5, - 5,0,5,5,5,5,5,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,2,2,2,2,6,6,6,6,6,6,6,4,0,0, - 0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x1b,0xb, - 0xb,0xb,0x19,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0,0,0, - 0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0x1b,0xb,0,5,5,0,5,0,0,5,0,5,5,5,5,5, - 5,5,0,5,5,5,5,0,5,0,5,0,0,0,0,5, - 0,0,0,0,5,0,5,0,5,0,5,5,5,0,5,5, - 0,5,0,0,5,0,5,0,5,0,5,0,5,5,0,5, - 0,0,5,5,5,5,0,5,5,5,5,0,5,5,5,5, - 0,5,0,5,5,5,0,5,5,5,5,5,0,5,5,5, - 5,5,0x18,0x18,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a, - 0x1a,0x1a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0x1b, - 0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x10, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x10,0x10, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0,0 - ] -); - -pub static HEADER: CodePointTrieHeader = CodePointTrieHeader { - high_start: 0x110000, - shifted12_high_start: 0x110, - trie_type: TrieType::Fast, - index3_null_offset: 0x66a, - data_null_offset: 0xd18, - null_value: 0x0, -}; diff --git a/deps/crates/vendor/icu_collections-v2/benches/tries/gc_small.rs b/deps/crates/vendor/icu_collections-v2/benches/tries/gc_small.rs deleted file mode 100644 index da297a2d4c60..000000000000 --- a/deps/crates/vendor/icu_collections-v2/benches/tries/gc_small.rs +++ /dev/null @@ -1,865 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use icu_collections::codepointtrie::{CodePointTrieHeader, TrieType}; -use zerovec::ule::AsULE; -use zerovec::{zerovec, ZeroVec}; - -#[rustfmt::skip] -pub const INDEX: ZeroVec<u16> = zerovec!(u16; <u16 as AsULE>::ULE::from_unsigned; - [ - 0,0x40,0x7f,0xbf,0xff,0x12e,0x16d,0x1ad,0x1e5,0x224,0x250,0x28e,0x2ce,0x2de,0x31e,0x34f, - 0x38c,0x3bc,0x3fa,0x43a,0x44a,0x47b,0x4b2,0x4f2,0x532,0x572,0x5a3,0x5cf,0x60f,0x644,0x65e,0x69e, - 0x6de,0x71e,0x756,0x78d,0x7ca,0x809,0x848,0x887,0x8c6,0x905,0x944,0x983,0x9c3,0xa01,0xa3f,0xa7f, - 0xabf,0xafe,0xb3e,0xb7e,0xbbe,0xbfd,0xc3d,0xc7d,0xcbc,0xcfc,0xd3b,0xd7b,0xdbb,0xdfb,0xe3b,0xe79, - 0xbbd,0xbd7,0xbe7,0xbfd,0xc1d,0xc3b,0xc58,0xc77,0xc97,0xc97,0xca4,0xcc1,0xce1,0xceb,0xceb,0xceb, - 0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb, - 0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb, - 0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xceb,0xd0b,0xceb,0xceb,0xceb,0xd2b,0xd2b,0xd2b,0xd2c, - 0xd2b,0xd2b,0xd2b,0xd2c,0,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x7f,0x8f,0x9f,0xaf, - 0xbf,0xcf,0xdf,0xef,0xff,0x10f,0x11f,0x12f,0x12e,0x13e,0x14e,0x15e,0x16d,0x17d,0x18d,0x19d, - 0x1ad,0x1bd,0x1cd,0x1dd,0x1e5,0x1f5,0x205,0x215,0x224,0x234,0x244,0x254,0x250,0x260,0x270,0x280, - 0x28e,0x29e,0x2ae,0x2be,0x2ce,0x2de,0x2ee,0x2fe,0x2de,0x2ee,0x2fe,0x30e,0x31e,0x32e,0x33e,0x34e, - 0x34f,0x35f,0x36f,0x37f,0x38c,0x39c,0x3ac,0x3bc,0x3bc,0x3cc,0x3dc,0x3ec,0x3fa,0x40a,0x41a,0x42a, - 0x43a,0x44a,0x45a,0x46a,0x44a,0x45a,0x46a,0x47a,0x47b,0x48b,0x49b,0x4ab,0x4b2,0x4c2,0x4d2,0x4e2, - 0x4f2,0x502,0x512,0x522,0x532,0x542,0x552,0x562,0x572,0x582,0x592,0x5a2,0x5a3,0x5b3,0x5c3,0x5d3, - 0x5cf,0x5df,0x5ef,0x5ff,0x60f,0x61f,0x62f,0x63f,0x644,0x654,0x664,0x674,0x65e,0x66e,0x67e,0x68e, - 0x69e,0x6ae,0x6be,0x6ce,0x6de,0x6ee,0x6fe,0x70e,0x71e,0x72e,0x73e,0x74e,0x756,0x766,0x776,0x786, - 0x78d,0x79d,0x7ad,0x7bd,0x7ca,0x7da,0x7ea,0x7fa,0x809,0x819,0x829,0x839,0x848,0x858,0x868,0x878, - 0x887,0x897,0x8a7,0x8b7,0x8c6,0x8d6,0x8e6,0x8f6,0x905,0x915,0x925,0x935,0x944,0x954,0x964,0x974, - 0x983,0x993,0x9a3,0x9b3,0x9c3,0x9d3,0x9e3,0x9f3,0xa01,0xa11,0xa21,0xa31,0xa3f,0xa4f,0xa5f,0xa6f, - 0xa7f,0xa8f,0xa9f,0xaaf,0xabf,0xacf,0xadf,0xaef,0xafe,0xb0e,0xb1e,0xb2e,0xb3e,0xb4e,0xb5e,0xb6e, - 0xb7e,0xb8e,0xb9e,0xbae,0xbbe,0xbce,0xbde,0xbee,0xbfd,0xc0d,0xc1d,0xc2d,0xc3d,0xc4d,0xc5d,0xc6d, - 0xc7d,0xc8d,0xc9d,0xcad,0xcbc,0xccc,0xcdc,0xcec,0xcfc,0xd0c,0xd1c,0xd2c,0xd3b,0xd4b,0xd5b,0xd6b, - 0xd7b,0xd8b,0xd9b,0xdab,0xdbb,0xdcb,0xddb,0xdeb,0xdfb,0xe0b,0xe1b,0xe2b,0xe3b,0xe4b,0xe5b,0xe6b, - 0xe79,0xe89,0xe99,0xea9,0x5a3,0x5a3,0xeb9,0xec8,0xed8,0xee8,0xef7,0xf06,0xf14,0xf24,0x41,0x41, - 0xf34,0x61,0x61,0xf44,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0xf54,0xf64,0x5a3,0x5a3,0xf54,0x5a3,0x5a3,0xf5c,0xf6c,0xae1,0x5a3,0x5a3, - 0x5a3,0xf6c,0x5a3,0x5a3,0x5a3,0xf74,0xf84,0xf8d,0x5a3,0xf9d,0x41,0x41,0x41,0x41,0x41,0xfad, - 0xfbd,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0xfc0,0x5a3,0xfd0,0xfd5,0x5a3,0x5a3,0x5a3,0x5a3,0xfe5,0xff4,0x5a3,0x1004,0x5a3,0x1013,0x5a3,0x1023, - 0x864,0x1033,0x5a3,0x5a3,0x5a3,0x1043,0x1051,0x105d,0xb24,0x106d,0x107d,0xb24,0x5a3,0x5a3,0x108d,0x5a3, - 0x5a3,0x1094,0x10a4,0x5a3,0x10ab,0x5a3,0x5a3,0x5a3,0x5a3,0x10bb,0x5a3,0x50e,0x10cb,0x10db,0x10eb,0x5a3, - 0x50f,0x10fb,0x5a3,0x5a3,0x511,0x5a3,0x1093,0x110b,0x1119,0x1119,0x5a3,0x1129,0x5a3,0x5a3,0x5a3,0x1139, - 0x1149,0x1156,0xb24,0xb24,0x1166,0x1176,0x640,0xd18,0xd18,0xd18,0x7c9,0x5a3,0x5a3,0x1186,0x1194,0xed8, - 0x11a4,0x11b0,0x7cb,0x5a3,0x11c0,0x69e,0x5a3,0x5a3,0x11ce,0x11dd,0x5a3,0x5a3,0x11ed,0x11f9,0x1209,0x69e, - 0x5a3,0x1216,0x1226,0x41,0x41,0x1236,0x1246,0x1256,0x1265,0x126e,0x61,0x61,0x274,0x280,0x280,0x280, - 0x127e,0x1289,0x61,0x275,0x280,0x280,0x2ce,0x2ce,0x2ce,0x2ce,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0x1299,0xff,0xff,0xff,0xff,0xff,0xff,0x12a8,0x12b8,0x12a8,0x12a8,0x12b8,0x12c8, - 0x12a8,0x12d8,0x12e8,0x12e8,0x12e8,0x12f8,0x1307,0x1317,0x1327,0x1337,0x1347,0x1357,0x1367,0x1377,0x1386,0x1394, - 0x13a4,0x13b4,0x13c4,0x13d4,0x13e4,0x13e4,0x13f3,0x1403,0x1412,0x1421,0x1431,0x1441,0x144f,0x145f,0x146f,0x147f, - 0x148f,0x148f,0x149c,0x14ac,0x14bc,0x1119,0x14cb,0x14db,0x1119,0x14e7,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, - 0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14fb,0x1119,0x150b,0x1119,0x1119,0x1119, - 0x1119,0x1516,0x1119,0x14e0,0x14eb,0x1526,0x1119,0x152a,0x1538,0x1119,0x1119,0x1541,0xd18,0x153d,0xd18,0x147f, - 0x147f,0x147f,0x1551,0x1119,0x1119,0x1119,0x1119,0x155d,0x147f,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x1119,0x1119,0x14c3,0x14c9,0x1119,0x1119,0x14e3,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x156d, - 0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x157d, - 0x1587,0x147f,0x1569,0x1119,0x1119,0x1597,0x14eb,0x15a1,0x14eb,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, - 0x14eb,0x15a4,0x15ac,0x14eb,0x14eb,0x14eb,0x15b5,0x14eb,0x15c1,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb, - 0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x1119,0x1119,0x1119,0x14eb,0x15cf,0x1119,0x1119, - 0x15dc,0x1119,0x15e6,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x41,0x41,0x41,0x61,0x61,0x61,0x15f6, - 0x1605,0xff,0xff,0xff,0xff,0xff,0xff,0x1614,0x1623,0x61,0x61,0x1633,0x5a3,0x5a3,0x5a3,0x1643, - 0x1653,0x5a3,0x1663,0x86a,0x86a,0x86a,0x86a,0x2ce,0x2ce,0x1673,0x1681,0x1691,0x16a1,0x16b1,0x16c1,0xd18, - 0xd18,0x1119,0x15e2,0x1119,0x1119,0x1119,0x1119,0x1119,0x16d1,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x16e1,0xd18,0x153c,0x16f1,0x16ff,0x170f,0x171f,0x501,0x5a3,0x5a3, - 0x5a3,0x5a3,0x172f,0xfbd,0x5a3,0x5a3,0x5a3,0x5a3,0x173e,0x4fd,0x5a3,0x5a3,0x501,0x5a3,0x5a3,0x5a3, - 0x5a3,0x50e,0x174e,0x5a3,0x5a3,0x1119,0x1119,0x16d1,0x5a3,0x1119,0x1754,0x1553,0x1119,0x1764,0x147e,0x1119, - 0x1119,0x1553,0x1119,0x1119,0x147e,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1119,0x1119,0x1119,0x1119,0x5a3,0x56d,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x510,0x1119,0x1119, - 0x1119,0x1541,0x5a3,0x5a3,0x1216,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1774,0x5a3,0x1784,0xd18,0xff,0xff,0x1794,0x17a4,0xff,0x17b4,0x5a3, - 0x5a3,0x5a3,0x5a3,0x17c4,0x17d4,0x2bd,0x17e4,0x17f4,0xfd,0xff,0xff,0xff,0x1804,0x1812,0x1822,0x1828, - 0x1832,0x183e,0x184e,0xd18,0x185c,0x186a,0x5a3,0x1877,0x1887,0x5a3,0x5a3,0x5a3,0x1897,0x18a7,0x5a3,0x5a3, - 0x18b3,0x18bf,0xb24,0x2ce,0x18cf,0x69e,0x5a3,0x18df,0x5a3,0x576,0x18ef,0x5a3,0x510,0x7ca,0x5a3,0x5a3, - 0x18ff,0x190e,0x191e,0x192e,0x10f1,0x5a3,0x5a3,0x1935,0x1944,0x1954,0x1964,0x5a3,0x1974,0x5a3,0x5a3,0x5a3, - 0x1984,0x1994,0x1999,0x19a9,0x19b9,0x19c8,0x10ba,0x86a,0x61,0x61,0x19d8,0x19e8,0x61,0x61,0x61,0x61, - 0x61,0x5a3,0x5a3,0x19f8,0xb24,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd97, - 0x5a3,0x1a08,0x5a3,0x5a3,0x511,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18, - 0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a18, - 0x1a18,0x1a18,0x1a18,0x1a18,0x1a18,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28, - 0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28, - 0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x50f,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1093,0xd18,0xd18,0x1a38, - 0x1a45,0x1a54,0x1a5e,0x1a6e,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1a7c,0x1a89,0x4ff,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x1a99,0x1119,0x5a3,0x5a3,0x5a3,0x5a3,0x500,0x5a3,0x5a3,0x1aa9,0xd18,0xd18,0x1ab9,0x2ce,0x1ac9,0x2ce, - 0x1ad9,0x1ae5,0x1af5,0x1b04,0xae3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1b14,0x1b24,0x30,0x40, - 0x50,0x60,0x1b34,0x1b44,0x1b54,0x5a3,0x1b56,0x5a3,0x50e,0x19c7,0x1b66,0x1b76,0x1b85,0x865,0x5a3,0xae1, - 0x1b95,0x50f,0x50f,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x73e,0x1ba5,0x147f,0x147f, - 0xf96,0x148f,0x148f,0x148f,0x1bb5,0x1bbe,0x153b,0x1bcc,0xd18,0xd18,0x1119,0x1119,0x1bdc,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x510,0x5a3,0x5a3,0x5a3,0x993,0x1bec,0x1bf0,0x5a3,0x5a3,0x1bf8, - 0x5a3,0x1c07,0x5a3,0x5a3,0x1c17,0x5a3,0x1c27,0x5a3,0x5a3,0x1c37,0x1c47,0xd18,0xd18,0x41,0x41,0x342, - 0x61,0x61,0x5a3,0x5a3,0x5a3,0x5a3,0x50f,0xb24,0x41,0x41,0x1c57,0x61,0x1c5f,0x5a3,0x5a3,0x1c6f, - 0x5a3,0x5a3,0x5a3,0x1c73,0x335,0x335,0x1c83,0x1c91,0x1c9f,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x1663,0x5a3,0x10bb,0x1c6f,0xd18,0x1caf,0x280,0x280,0x1cb4,0xd18,0xd18,0xd18,0xd18,0x1cc4,0x5a3,0x5a3, - 0x1cce,0x5a3,0x1cdd,0x5a3,0x1ced,0x5a3,0x50e,0x154a,0xd18,0xd18,0xd18,0x5a3,0x1cfd,0x5a3,0x1d0d,0x5a3, - 0x1d1d,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x1d2d,0x147f,0x1d3d,0x147f,0x147f,0x1d4d,0x94e,0x5a3, - 0x1d5d,0x1bf3,0x1d6d,0x5a3,0x1d7d,0x5a3,0x1d8d,0xd18,0xd18,0x1d9d,0x5a3,0x1da8,0x1db8,0x5a3,0x5a3,0x5a3, - 0x1dc8,0x5a3,0x1dd8,0x5a3,0x1de8,0x5a3,0x1df8,0x1548,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3, - 0x5a3,0x1094,0xd18,0xd18,0xd18,0x41,0x41,0x41,0x1e08,0x61,0x61,0x61,0x1e18,0x5a3,0x5a3,0x1e28, - 0xb24,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x147f,0x1bed,0x5a3, - 0x5a3,0x1e38,0xd99,0xd18,0xd18,0xd18,0xd18,0x5a3,0x1d8d,0x1e48,0x5a3,0x577,0x1e58,0xd18,0x5a3,0x1e68, - 0xd18,0xd18,0x5a3,0x1e78,0xd18,0x5a3,0x1663,0x1e88,0x5a3,0x5a3,0x575,0x1e98,0x1d3d,0x1ea8,0x1eb8,0x7cb, - 0x5a3,0x5a3,0x1ec8,0x1ed6,0x5a3,0x1094,0xb24,0x773,0x5a3,0x1ee6,0x1ef3,0x1f03,0x5a3,0x5a3,0x1f13,0x7cb, - 0x5a3,0x5a3,0x1f23,0x1f32,0x1f42,0x1f52,0x1f5d,0x5a3,0x954,0x1f6d,0x1f7c,0xd18,0xd18,0xd18,0xd18,0x1f8c, - 0x863,0x1f9b,0x5a3,0x5a3,0x630,0x1fab,0xb24,0x1fbb,0x858,0x868,0x1fca,0x1fda,0x1fea,0x1ff8,0x141d,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x2008,0x2018,0x2028,0xd99,0xd18,0x5a3, - 0x5a3,0x5a3,0x2038,0x2047,0xb24,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3, - 0x5a3,0x2057,0x2066,0x2075,0x207d,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x208d,0x209c,0xb24,0x20ac,0xd18,0x5a3, - 0x5a3,0x20bc,0x20cc,0xb24,0xd18,0xd18,0xd18,0x5a3,0xf74,0x20dc,0x20ec,0x1663,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x1f6d,0x20fc,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0x41,0x41,0x61,0x61,0xc23,0x210c,0x211b,0x2127,0x5a3,0x2137,0x2147,0xb24,0xd18,0xd18,0xd18, - 0xd18,0x2157,0x5a3,0x5a3,0x2166,0x2176,0xd18,0x2186,0x5a3,0x5a3,0x2193,0x21a2,0x21b2,0x5a3,0x5a3,0x573, - 0x21c2,0x21d0,0x5a3,0x5a3,0x5a3,0x5a3,0x1094,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x868,0x5a3,0x2057,0x21e0,0x21f0,0xc23,0xf8d,0x550,0x5a3, - 0xe2a,0x2200,0x220f,0xd18,0xd18,0xd18,0xd18,0x96e,0x5a3,0x5a3,0x221f,0x222e,0xb24,0x223e,0x5a3,0x2248, - 0x2258,0xb24,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x5a3,0x2268,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x993,0x147f,0x2278, - 0x2287,0x2295,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1093,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x148f,0x148f,0x148f,0x148f,0x148f,0x148f,0x22a5,0x22b5,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd97,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x22c5,0x5a3,0x5a3, - 0x50e,0x22d5,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3, - 0x5a3,0x5a3,0x1663,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3, - 0x5a3,0x1094,0x5a3,0x50e,0x191e,0x5a3,0x5a3,0x5a3,0x5a3,0x50e,0xb24,0x5a3,0x50f,0x22e5,0x5a3,0x5a3, - 0x5a3,0x22f5,0x2305,0x2315,0x2323,0x741,0x5a3,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x41,0x41, - 0x61,0x61,0x147f,0x2333,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0xe1d,0x2343, - 0x2344,0x2344,0x234c,0x235b,0xd18,0xd18,0xd18,0xd18,0x2369,0x2379,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x1c6f,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x10bb,0xd18,0xd18,0x1094,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x2389,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd98,0xd18,0xd18, - 0xd98,0x2398,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x511,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x73e,0x510,0x1094,0x23a8,0x23b8,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x2ce,0x2ce,0x641,0x2ce,0x141b,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x16d1,0xd18, - 0xd18,0xd18,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x16e1,0x1119,0x1119,0x23c8,0x1119,0x1119,0x1119,0x23d3,0x23e0,0x23ed,0x1119,0x23f9,0x1119,0x1119,0x1119, - 0x153d,0xd18,0x1119,0x1119,0x1119,0x1119,0x2407,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0x147f,0x2417,0x1119,0x1119,0x1119,0x1119,0x1119,0x1541,0x147f,0x1bf3,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x41,0x3b2,0x61,0x2427,0x3ae,0x1c8e,0x12a8,0x41,0xdc,0x2437,0x2447,0x2455,0x1c8f,0x41, - 0x3b2,0x61,0x2462,0x246f,0x61,0x247d,0x248d,0x249c,0x24a0,0x41,0xd8,0x61,0x41,0x3b2,0x61,0x2427, - 0x3ae,0x61,0x12a8,0x41,0xdc,0x24a0,0x41,0xd8,0x61,0x41,0x3b2,0x61,0x24b0,0x41,0x24bf,0xeb, - 0x38a,0x24cf,0x61,0x24db,0x41,0x24bb,0xe7,0x24c9,0xc7,0x61,0xed,0x41,0x24e7,0x61,0x24f4,0x2502, - 0x2502,0x2502,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x2ce,0x2ce,0x2ce,0x2512,0x2ce,0x2ce,0x251d,0x252a,0x2536,0x13f8,0x4c2,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x25a,0x2546,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xe4c,0x2556,0x2564,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x5a3,0x5a3,0x510,0x2574,0x2584,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x5a3,0x2594,0xd18,0x5a3,0x5a3,0x633,0x25a4,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x25b4,0x50e,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x25c4,0x141b,0xd18,0xd18,0x41,0x41,0xdc,0x61,0x25d4,0x191e,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x1f52,0x147f,0x147f,0x25e4,0x25f4,0xd18,0xd18, - 0xd18,0xd18,0x1f52,0x147f,0x2604,0x1bee,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xae4,0x5a3,0x2614,0x2621,0x262f,0x263f,0x264d,0x2655,0x867,0x511,0x2664,0x511,0xd18,0xd18, - 0xd18,0x2674,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x1119,0x1119,0x153c,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x16d1,0x1754,0x1118,0x1118,0x1118, - 0x1119,0x16e1,0x2684,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x153a,0xd18,0xd18,0xd18, - 0x1bd6,0x1119,0x1bca,0x1119,0x1119,0x153c,0x153f,0x1bcb,0x16e1,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x2691,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x26a1, - 0x153b,0x153b,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x16d1,0x1119,0x1119,0x1119,0x1119,0x1119,0x153f, - 0x153c,0x1bcc,0x153c,0x1119,0x1119,0x1119,0x1540,0xf9d,0x1119,0x1119,0x1540,0x1119,0x153a,0x1bcb,0xd18,0xd18, - 0xd18,0xd18,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x16d1,0x153a,0x26ae,0x1541,0x1119,0x153b,0x153d,0x16e1,0xf9d,0x1540,0x1541,0x1119,0x1119,0x1119, - 0x1119,0x1119,0x1119,0x1119,0x1119,0x1119,0x26be,0x1119,0x1119,0x153d,0xd18,0xd18,0xb24,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd18,0xd18,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x1094,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x50f,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0xd99,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x993,0xd18,0x5a3,0x50f,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18, - 0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x5a3,0x5a3,0x5a3, - 0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3, - 0x5a3,0x73e,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x26ce,0xd18,0x26de, - 0x26de,0x26de,0x26de,0x26de,0x26de,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0xd18,0x2ce,0x2ce,0x2ce, - 0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0x2ce,0xd18,0x1a28,0x1a28,0x1a28, - 0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28, - 0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,0x26ee,0x84,0xa4,0xc4, - 0xe4,0x104,0x124,0x144,0x164,0x184,0x1a0,0x1c0,0x1da,0x1fa,0x21a,0x23a,0x25a,0x27a,0x29a,0x2b9, - 0x2d9,0x2f9,0x319,0x339,0x359,0x379,0x399,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3bd,0x3b9,0x3b9, - 0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9, - 0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3dd,0x3b9,0x3f5,0x415,0x435,0x455,0x3b9,0x3b9,0x3b9, - 0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x475,0x495,0x495,0x495,0x495,0x4b5,0x4b5,0x4b5, - 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4c5,0x4df,0x4fd,0x51d,0x53d,0x55d,0x57d, - 0x59d,0x5bd,0x5dd,0x5fd,0x617,0x637,0x657,0x677,0x697,0x6b7,0x6d7,0x6f7,0x712,0x3b9,0x732,0x752, - 0x767,0x767,0x767,0x767,0x76e,0x3b9,0x3b9,0x78e,0x767,0x767,0x767,0x767,0x767,0x3b9,0x7ae,0x767, - 0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x3b9, - 0x7ce,0x767,0x7ea,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x80a,0x3b9,0x3b9,0x82a,0x767, - 0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x83b, - 0x85b,0x872,0x767,0x767,0x767,0x767,0x892,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x8a2,0x8c2, - 0x8e2,0x902,0x922,0x942,0x962,0x767,0x972,0x992,0x9a9,0x767,0x9b9,0x9d9,0x767,0x9f2,0xa12,0xa32, - 0xa52,0x942,0xa72,0xa92,0xaad,0x767,0x767,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9, - 0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9, - 0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0xacd,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0xadd, - 0xafc,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0xb12,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9, - 0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0xb1d,0x767,0x767,0x767,0x767,0x767,0x767,0x3b9,0xb3d,0x767, - 0x767,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0x3b9,0xb5d,0x767,0x767,0x767,0x767,0x767, - 0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767, - 0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0xb7d,0x767,0x767,0x767,0x767, - 0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767, - 0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x767,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, - 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5, - 0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0xb9d - ] -); - -#[rustfmt::skip] -pub const DATA: ZeroVec<u8> = zerovec!(u8; core::convert::identity; - [ - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0xc,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17, - 9,9,9,9,9,9,9,9,9,9,0x17,0x17,0x18,0x18,0x18,0x17, - 0x17,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0x14,0x17,0x15,0x1a,0x16, - 0x1a,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,0x14,0x18,0x15,0x18,0xf, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xc, - 0x17,0x19,0x19,0x19,0x19,0x1b,0x17,0x1a,0x1b,5,0x1c,0x18,0x10,0x1b,0x1a,0x1b, - 0x18,0xb,0xb,0x1a,2,0x17,0x17,0x1a,0xb,5,0x1d,0xb,0xb,0xb,0x17,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,0x18,1,1,1,1,1,1,1,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,0x18,2,2,2,2,2,2,2,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,1,2,1,2,1,2,2,1,1, - 2,1,2,1,1,2,1,1,1,2,2,1,1,1,1,2, - 1,1,2,1,1,1,2,2,2,1,1,2,1,1,2,1, - 2,1,2,1,1,2,1,2,2,1,2,1,1,2,1,1, - 1,2,1,2,1,1,2,2,5,1,2,2,2,5,5,5, - 5,1,3,2,1,3,2,1,3,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,2,1,3, - 2,1,2,1,1,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,2,2,2,2,2,2,1, - 1,2,1,1,2,1,2,1,1,1,1,2,1,2,1,2, - 1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,5,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 0x1a,0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,4,4,4, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4, - 4,4,4,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,0x1a,4,0x1a,0x1a,0x1a, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,1,2, - 1,2,4,0x1a,1,2,0,0,4,2,2,2,0x17,1,0,0, - 0,0,0x1a,0x1a,1,0x17,1,1,1,0,1,0,1,1,2,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2, - 2,1,1,1,2,2,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,2, - 2,2,2,1,2,0x18,1,2,1,1,2,2,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,0x1b,6,6,6, - 6,6,7,7,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,0,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,0,0,4,0x17,0x17,0x17,0x17,0x17,0x17,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,0x17,0x13,0,0,0x1b, - 0x1b,0x19,0,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 0x13,6,0x17,6,6,0x17,6,6,0x17,6,0,0,0,0,0,0, - 0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, - 0,5,5,5,5,0x17,0x17,0,0,0,0,0,0,0,0,0, - 0,0,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x18,0x18,0x17,0x17,0x19,0x17,0x17, - 0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,0x17,0x10,0x17, - 0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,4,5,5,5,5,5,5,5,5,5,5,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,9,9,9,9,9,9,9,9,9,9,0x17,0x17,0x17,0x17, - 5,5,6,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,0x17,5,6,6,6,6,6,6,6,0x10,0x1b,6,6, - 6,6,6,6,4,4,6,6,0x1b,6,6,6,6,5,5,9, - 9,9,9,9,9,9,9,9,9,5,5,5,0x1b,0x1b,5,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0x10,5, - 6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,5, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9, - 9,9,9,9,9,9,9,9,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6, - 6,6,4,4,0x1b,0x17,0x17,0x17,4,0,0,6,0x19,0x19,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,6,6,6,4,6,6,6,6,6,6,6, - 6,6,4,6,6,6,4,6,6,6,6,6,0,0,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,6,6,6,0,0,0x17,0,5,5, - 5,5,5,5,5,5,5,5,5,0,0,0,0,0,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1a,5, - 5,5,5,5,5,0,0x10,0x10,0,0,0,0,0,0,6,6, - 6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,4,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0x10, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,8,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,6,8,6,5,8,8,6,6,6,6,6,6, - 6,6,8,8,8,8,6,8,8,5,6,6,6,6,6,6, - 6,5,5,5,5,5,5,5,5,5,5,6,6,0x17,0x17,9, - 9,9,9,9,9,9,9,9,9,0x17,4,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,8,8,0,5,5,5, - 5,5,5,5,5,0,0,5,5,0,0,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0,5,5,5,5,5,5,5,0,5,0,0,0,5,5, - 5,5,0,0,6,5,8,8,6,6,6,6,0,0,8,8, - 0,0,8,8,6,5,0,0,0,0,0,0,0,0,8,0, - 0,0,0,5,5,0,5,5,5,6,6,0,0,9,9,9, - 9,9,9,9,9,9,9,5,5,0x19,0x19,0xb,0xb,0xb,0xb,0xb, - 0xb,0x1b,0x19,5,0x17,6,0,6,6,8,0,5,5,5,5,5, - 5,0,0,0,0,5,5,0,0,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 5,5,5,5,5,5,5,0,5,5,0,5,5,0,5,5, - 0,0,6,0,8,8,6,6,0,0,0,0,6,6,0,0, - 6,6,6,0,0,0,6,0,0,0,0,0,0,0,5,5, - 5,5,0,5,0,0,0,0,0,0,0,9,9,9,9,9, - 9,9,9,9,9,6,6,5,5,5,6,0x17,0,0,0,0, - 0,0,0,0,0,6,6,8,0,5,5,5,5,5,5,5, - 5,5,0,5,5,5,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5, - 5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0, - 6,5,8,8,6,6,6,6,6,0,6,6,8,0,8,8, - 6,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,5,5,6,6,0,0,9,9,9,9,9,9,9, - 9,9,9,0x17,0x19,0,0,0,0,0,0,0,5,6,6,6, - 6,6,6,0,6,8,8,0,5,5,5,5,5,5,5,5, - 0,0,5,5,0,0,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5, - 5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,6, - 5,8,6,6,6,6,0,0,8,8,0,0,8,8,6,0, - 0,0,0,0,0,0,6,6,8,0,0,0,0,5,5,0, - 5,5,5,6,6,0,0,9,9,9,9,9,9,9,9,9, - 9,0x1b,5,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0, - 0,6,5,0,5,5,5,5,5,5,0,0,0,5,5,5, - 0,5,5,5,5,0,0,0,5,5,0,5,0,5,5,0, - 0,0,5,5,0,0,0,5,5,5,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,0,0,0,0,8,8,6, - 8,8,0,0,0,8,8,8,0,8,8,8,6,0,0,5, - 0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,0xb, - 0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x1b,0,0,0,0,0,6, - 8,8,8,6,5,5,5,5,5,5,5,5,0,5,5,5, - 0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,0,0,6,5,6,6,8, - 8,8,8,0,6,6,6,0,6,6,6,6,0,0,0,0, - 0,0,0,6,6,0,5,5,5,0,0,5,0,0,5,5, - 6,6,0,0,9,9,9,9,9,9,9,9,9,9,0,0, - 0,0,0,0,0,0x17,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x1b,5,6, - 8,8,0x17,5,5,5,5,5,5,5,5,0,5,5,5,0, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5, - 5,5,0,5,5,5,5,5,0,0,6,5,8,6,8,8, - 8,8,8,0,6,8,8,0,8,8,6,6,0,0,0,0, - 0,0,0,8,8,0,0,0,0,0,0,5,5,0,5,5, - 6,6,0,0,9,9,9,9,9,9,9,9,9,9,0,5, - 5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6, - 8,8,5,5,5,5,5,5,5,5,5,0,5,5,5,0, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,6,6,5,8,8,6,6, - 6,6,0,8,8,8,0,8,8,8,6,5,0x1b,0,0,0, - 0,5,5,5,8,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,6, - 6,0,0,9,9,9,9,9,9,9,9,9,9,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0x1b,5,5,5,5,5,5,0,6,8, - 8,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,0,0,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 5,5,5,5,5,5,5,5,5,0,5,0,0,5,5,5, - 5,5,5,5,0,0,0,6,0,0,0,0,8,8,8,6, - 6,6,0,6,0,8,8,8,8,8,8,8,8,0,0,0, - 0,0,0,9,9,9,9,9,9,9,9,9,9,0,0,8, - 8,0x17,0,0,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,6,5,5, - 6,6,6,6,6,6,6,0,0,0,0,0x19,5,5,5,5, - 5,5,4,6,6,6,6,6,6,6,6,0x17,9,9,9,9, - 9,9,9,9,9,9,0x17,0x17,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,5, - 0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, - 5,0,5,5,5,5,5,5,5,5,5,5,6,5,5,6, - 6,6,6,6,6,6,6,6,5,0,0,5,5,5,5,5, - 0,4,0,6,6,6,6,6,6,0,0,9,9,9,9,9, - 9,9,9,9,9,0,0,5,5,5,5,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,5,0x1b,0x1b,0x1b,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,0x17, - 0x1b,0x1b,0x1b,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,9,9,9,9,9, - 9,9,9,9,9,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x1b, - 6,0x1b,6,0x1b,6,0x14,0x15,0x14,0x15,8,8,5,5,5,5,5, - 5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,0,0,0,0,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,8,6,6,6,6,6, - 0x17,6,6,5,5,5,5,5,6,6,6,6,6,6,6,6, - 6,6,6,0,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b, - 0x1b,0x1b,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, - 5,5,5,5,8,8,6,6,6,8,6,6,6,6,6,6, - 8,6,6,8,8,6,6,5,9,9,9,9,9,9,9,9, - 9,9,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,5,5,8,8, - 6,6,5,5,5,5,6,6,5,8,8,8,5,5,8,8, - 8,8,8,8,8,5,5,6,6,6,6,5,5,5,5,5, - 5,5,5,5,5,5,6,8,8,6,6,8,8,8,8,8, - 8,6,5,8,9,9,9,9,9,9,9,9,9,9,8,8, - 8,6,0x1b,0x1b,1,1,1,1,1,1,0,1,0,0,0,0, - 0,1,0,0,2,2,2,2,2,2,2,2,2,2,2,0x17, - 4,2,2,2,5,5,5,5,5,5,5,5,5,0,5,5, - 5,5,0,0,5,5,5,5,5,5,5,0,5,0,5,5, - 5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,0, - 0,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,1,1,1, - 1,1,1,0,0,2,2,2,2,2,2,0,0,0x13,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,0x1b,0x17,5, - 0xc,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 0x14,0x15,0,0,0,5,5,5,5,5,5,5,5,5,5,5, - 0x17,0x17,0x17,0xa,0xa,5,5,5,5,5,5,5,5,0,0,0, - 0,0,0,0,5,5,6,6,6,8,0,0,0,0,0,0, - 0,0,0,5,5,6,6,8,0x17,0x17,0,0,0,0,0,0, - 0,0,0,5,5,6,6,0,0,0,0,0,0,0,0,0, - 0,0,0,5,0,6,6,0,0,0,0,0,0,0,0,0, - 0,0,0,5,5,5,5,6,6,8,6,6,6,6,6,6, - 6,8,8,8,8,8,8,6,8,8,6,6,6,6,6,6, - 6,0x17,0x17,0x17,4,0x17,0x17,0x17,0x19,5,6,0,0,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0x17,0x17,0x17, - 0x17,0x17,0x17,0x13,0x17,0x17,0x17,0x17,6,6,6,0x10,6,5,5,5, - 4,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, - 0,0,0,0,5,5,5,5,5,6,6,5,5,5,5,5, - 5,5,5,5,6,5,0,0,0,0,0,5,5,5,5,5, - 5,0,0,0,0,0,0,0,0,0,0,6,6,6,8,8, - 8,8,6,6,8,8,8,0,0,0,0,8,8,6,8,8, - 8,8,8,8,6,6,6,0,0,0,0,0x1b,0,0,0,0x17, - 0x17,9,9,9,9,9,9,9,9,9,9,5,5,5,5,5, - 0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,9, - 9,9,9,9,9,0xb,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,5,5,5, - 6,6,8,8,6,0,0,0x17,0x17,5,5,5,5,5,8,6, - 8,6,6,6,6,6,6,6,0,6,8,6,8,8,6,6, - 6,6,6,6,6,6,8,8,8,6,6,6,6,6,6,6, - 6,6,6,0,0,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,4,0x17,0x17, - 0x17,0x17,0x17,0x17,0,0,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,7,6,5,5,5,5,6,8,6,6,6,6, - 6,8,6,8,8,8,6,8,8,5,5,5,5,5,5,5, - 5,0,0,0,0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6, - 6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0, - 5,8,6,6,6,6,8,8,6,6,8,6,6,6,5,5, - 5,5,5,5,6,8,6,6,8,8,8,6,8,6,6,8, - 8,0,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,5,5,5, - 5,8,8,8,8,8,8,8,8,6,6,6,6,8,8,6, - 6,0,0,0,0x17,0x17,0x17,0x17,0x17,9,9,9,9,9,9,9, - 9,9,9,0,0,0,5,5,5,5,5,5,5,5,4,4, - 4,4,4,4,0x17,0x17,2,2,2,2,2,2,2,2,2,0, - 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1, - 1,0,0,1,1,1,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0, - 0,0,0,0,0,0,6,6,6,0x17,6,6,6,6,6,6, - 6,6,6,6,6,6,8,6,6,6,6,6,6,6,5,5, - 5,5,6,5,5,8,6,6,5,0,0,0,0,0,4,4, - 4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2, - 2,4,2,2,2,2,2,2,2,1,2,1,2,1,2,2, - 2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2, - 1,1,1,1,1,1,1,1,2,2,2,2,2,2,0,0, - 1,1,1,1,1,1,0,0,2,2,2,2,2,2,2,2, - 0,1,0,1,0,1,0,1,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,2,2,2,2,2,0,2,2, - 1,1,1,1,3,0x1a,2,0x1a,0x1a,2,2,2,0,2,2,1, - 1,1,1,3,0x1a,0x1a,0x1a,2,2,2,2,0,0,2,2,1, - 1,1,1,0,0x1a,0x1a,0x1a,2,2,2,2,2,2,2,2,1, - 1,1,1,1,0x1a,0x1a,0x1a,0,0,2,2,2,0,2,2,1, - 1,1,1,3,0x1a,0x1a,0,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc, - 0xc,0xc,0x10,0x10,0x10,0x10,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x1c, - 0x1d,0x14,0x1c,0x1c,0x1d,0x14,0x1c,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xd, - 0xe,0x10,0x10,0x10,0x10,0x10,0xc,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x1c,0x1d,0x17,0x17,0x17,0x17,0x16,0x17,0x17,0x17,0x18,0x14,0x15,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x18,0x17,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0xc,0x10,0x10,0x10,0x10,0x10,0,0x10,0x10,0x10,0x10,0x10,0x10, - 0x10,0x10,0x10,0x10,0xb,4,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0x18,0x18, - 0x18,0x14,0x15,4,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x18,0x18, - 0x18,0x14,0x15,0,4,4,4,4,4,4,4,4,4,4,4,4, - 4,0,0,0,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, - 0x19,0x19,0x19,0x19,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,6,7,7,7,6,6,6,6,6,6,6,6,6, - 6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0x1b,0x1b,1,0x1b,0x1b,0x1b,0x1b,1,0x1b,0x1b,2,1,1,1,2, - 2,1,1,1,2,0x1b,1,0x1b,0x1b,0x18,1,1,1,1,1,0x1b, - 0x1b,0x1b,0x1b,1,0x1b,1,0x1b,1,0x1b,1,1,1,1,0x1b,2,1, - 1,1,1,2,5,5,5,5,2,0x1b,0x1b,2,2,1,1,0x18, - 0x18,0x18,0x18,0x18,1,2,2,2,2,0x1b,0x18,0x1b,0x1b,2,0x1b,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xa, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,1, - 2,0xa,0xa,0xa,0xa,0xb,0x1b,0x1b,0,0,0,0,0x18,0x18,0x18,0x18, - 0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x18, - 0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x18,0x1b,0x18, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0, - 0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0xb,0xb,0xb,0xb,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x18,0x18, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14, - 0x15,0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14, - 0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x18, - 0x18,0x18,0x18,0x18,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b, - 0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1,2,1,1,1,2,2,1,2,1, - 2,1,2,1,1,1,2,1,2,2,1,2,2,2,2,2, - 2,4,4,1,1,2,1,2,2,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1, - 2,1,2,6,6,1,2,0,0,0,0,0,0x17,0x17,0x17,0x17, - 0xb,0x17,0x17,2,2,2,2,2,2,0,2,0,0,0,0,0, - 2,0,0,5,5,5,5,5,5,5,5,0,0,0,0,0, - 0,0,4,0x17,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,6,5,5,5,5,5,5,5,0,0,0,0,0,0, - 0,0,0,0x17,0x17,0x1c,0x1d,0x1c,0x1d,0x17,0x17,0x17,0x1c,0x1d,0x17,0x1c, - 0x1d,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x17,0x17,0x13,0x17,0x1c,0x1d,0x17, - 0x17,0x1c,0x1d,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x17,0x17, - 4,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x13,0x17,0x17,0x17, - 0x17,0x13,0x17,0x14,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x1b,0x1b,0x17,0x17,0x17,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0, - 0,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0, - 0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0, - 0,0xc,0x17,0x17,0x17,0x1b,4,5,0xa,0x14,0x15,0x14,0x15,0x14,0x15,0x14, - 0x15,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0x14,0x15,0x15,0x1b, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,6,6,6,6,8,8,0x13, - 4,4,4,4,4,0x1b,0x1b,0xa,0xa,0xa,4,5,0x17,0x1b,0x1b,5, - 5,5,5,5,5,5,0,0,6,6,0x1a,0x1a,4,4,5,5, - 5,5,5,5,5,5,5,5,5,0x17,4,4,4,5,0x1b,0x1b, - 0xb,0xb,0xb,0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,5,5,5,5,5,5,5,5,5,5,5,5, - 4,0x17,0x17,0x17,9,9,9,9,9,9,9,9,9,9,5,5, - 0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,5,6,7,7,7,0x17,6,6,6,6,6,6,6,6, - 6,6,0x17,4,1,2,1,2,1,2,1,2,1,2,1,2, - 4,4,6,6,5,5,5,5,5,5,0xa,0xa,0xa,0xa,0xa,0xa, - 0xa,0xa,0xa,0xa,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0, - 0,0,0,0,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4,4,4,4, - 4,4,4,4,0x1a,0x1a,1,2,1,2,1,2,1,2,1,2, - 1,2,1,2,4,2,2,2,2,2,2,2,2,1,2,1, - 2,1,1,2,1,2,1,2,1,2,4,0x1a,0x1a,1,2,1, - 2,5,1,2,1,2,2,2,1,2,1,2,1,2,1,2, - 1,2,1,1,1,1,1,2,1,2,1,2,1,2,1,2, - 1,2,1,1,1,1,2,1,2,0,0,0,0,0,1,2, - 0,2,0,2,1,2,1,2,0,0,0,0,0,0,4,4, - 4,1,2,5,4,4,2,5,5,5,5,5,6,5,5,5, - 6,5,5,5,5,6,5,5,5,5,8,8,6,6,8,0x1b, - 0x1b,0x1b,0x1b,6,0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0x1b,0x1b,0x19, - 0x1b,0,0,0,0,0,0,5,5,5,5,0x17,0x17,0x17,0x17,0, - 0,0,0,0,0,0,0,8,8,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,8,8,8,8,8,8,8,8,8, - 8,8,8,6,6,0,0,0,0,0,0,0,0,0x17,0x17,6, - 6,5,5,5,5,5,5,0x17,0x17,0x17,5,0x17,5,5,6,5, - 5,5,5,5,5,6,6,6,6,6,6,6,6,0x17,0x17,6, - 6,8,8,0,0,0,0,0,0,0,0,0,0,0,0x17,5, - 5,5,6,8,8,6,6,6,6,8,8,6,6,8,8,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4,9,9, - 9,9,9,9,9,9,9,9,0,0,0,0,0x17,0x17,5,5, - 5,5,5,6,4,5,5,5,5,5,5,5,5,5,6,6, - 6,6,6,6,8,6,6,8,8,6,6,0,0,0,0,0, - 0,0,0,0,5,5,5,6,5,5,5,5,5,5,5,5, - 6,8,0,0,9,9,9,9,9,9,9,9,9,9,0,0, - 0x17,0x17,0x17,0x17,4,5,5,5,5,5,5,0x1b,0x1b,0x1b,5,8, - 6,8,5,5,6,5,6,6,6,5,5,6,6,5,5,5, - 5,5,6,6,5,6,5,0,0,0,0,0,0,0,0,0, - 0,0,0,0,5,5,4,0x17,0x17,5,5,5,5,5,5,5, - 5,5,5,5,8,6,6,8,8,0x17,0x17,5,4,4,8,6, - 0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0, - 0,5,5,5,5,5,5,0,2,2,2,2,2,2,2,2, - 2,2,2,0x1a,4,4,4,4,2,2,2,2,2,2,2,2, - 2,4,0x1a,0x1a,0,0,0,0,5,5,5,8,8,6,8,8, - 6,8,8,0x17,8,6,0,0,5,5,5,5,5,5,5,0, - 0,0,0,5,5,5,5,5,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,2,2,2,2,2,2,2,0, - 0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0, - 0,0,5,6,5,5,5,5,5,5,5,5,5,0x18,5,5, - 5,5,5,5,5,0,5,5,5,5,5,0,5,0,5,5, - 0,5,5,0,5,5,5,5,5,5,5,5,5,5,0x1a,0x1a, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0,0,0,0, - 0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,0x15,0x14,5,5,5,5,5,5,5, - 5,0,0,0,0,0,0,0,0x1b,5,5,5,5,5,5,5, - 5,5,5,5,5,0x19,0x1b,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x14,0x15,0x17,0,0,0,0,0,0,0x17,0x13,0x13,0x16,0x16,0x14,0x15, - 0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x14,0x15,0x17,0x17, - 0x17,0x17,0x16,0x16,0x16,0x17,0x17,0x17,0,0x17,0x17,0x17,0x17,0x13,0x14,0x15, - 0x14,0x15,0x14,0x15,0x17,0x17,0x18,0x13,0x18,0x18,0x18,0,0x17,0x19,0x17,0x17, - 0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0,0,0x10,0,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18, - 0x17,0x13,0x17,0x17,2,2,2,2,2,2,2,2,2,2,2,0x14, - 0x18,0x15,0x18,0x14,0x15,0x17,0x14,0x15,0x17,0x17,5,5,5,5,5,5, - 5,5,5,5,4,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,4,4,0,0,5,5,5,5,5,5,0,0, - 5,5,5,0,0,0,0x19,0x19,0x18,0x1a,0x1b,0x19,0x19,0,0x1b,0x18, - 0x18,0x18,0x18,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0x10,0x10, - 0x10,0x1b,0x1b,0,0,5,5,5,5,5,5,5,5,5,5,5, - 0,5,5,0,5,0x17,0x17,0x17,0,0,0,0,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xa,0xa,0xa,0xa,0xa,0xb,0xb,0xb,0xb,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xb,0xb,0x1b,0x1b,0x1b,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0,0,6,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0, - 0,0,0,0,0,5,5,5,0xa,5,5,5,5,5,5,5, - 5,0xa,0,0,0,0,0,5,5,5,5,5,5,6,6,6, - 6,6,0,0,0,0,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,0,0x17,5,5,5,5,0,0,0,0,5, - 5,5,5,5,5,5,5,0x17,0xa,0xa,0xa,0xa,0xa,0,0,0, - 0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,2, - 2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,5, - 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, - 0,0,0x17,1,1,1,0,1,1,0,2,2,2,2,2,2, - 2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, - 2,0,2,2,2,2,2,2,2,0,2,2,0,0,0,4, - 4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,0, - 0,0,0,0,5,5,5,5,5,5,0,0,5,0,5,5, - 5,5,5,5,0,5,5,0,0,0,5,0,0,5,5,5, - 5,5,5,0,0x17,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5, - 5,5,5,5,0x1b,0x1b,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5, - 0,5,5,0,0,0,0,0,0xb,0xb,0xb,0xb,0xb,5,5,5, - 5,5,5,0xb,0xb,0xb,0xb,0xb,0xb,0,0,0,0x17,5,5,5, - 5,5,5,5,5,5,5,0,0,0,0,0,0x17,5,5,5, - 5,5,5,5,5,0,0,0,0,0xb,0xb,5,5,0,0,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,6,6, - 6,0,6,6,0,0,0,0,0,6,6,6,6,5,5,5, - 5,5,5,0,0,6,6,6,0,0,0,0,6,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0xb,0xb,0x17,5,5,5, - 5,5,5,5,5,5,5,5,5,5,0xb,0xb,0xb,5,5,5, - 5,5,5,5,5,0x1b,5,5,5,5,5,5,5,6,6,0, - 0,0,0,0xb,0xb,0xb,0xb,0xb,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0, - 0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0, - 0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,5,5,0,0, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,0,0,0,0,0, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5,5,0,0,0,0,0,0, - 0,0x17,0x17,0x17,0x17,0,0,0,1,1,1,0,0,0,0,0, - 0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0, - 0,0,0xb,0xb,0xb,0xb,0xb,0xb,5,5,5,5,6,6,6,6, - 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, - 5,5,0,6,6,0x13,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,5, - 0,0,0,0,0,0,0,0,6,0xb,0xb,0xb,0xb,0x17,0x17,0x17, - 0x17,0x17,0,0,0,0,0,0,5,5,6,6,6,6,0x17,0x17, - 0x17,0x17,0,0,0,0,0,0,5,5,5,5,5,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0,0,0,0,8,6,8,5,5,5,5,5, - 5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0,0,0xb,0xb,0xb,0xb,0xb,0xb,9,9, - 9,9,9,9,9,9,9,9,6,5,5,6,6,5,0,0, - 0,0,0,0,0,0,0,6,8,8,8,6,6,6,6,8, - 8,6,6,0x17,0x17,0x10,0x17,0x17,6,0,0,0,0,0,0,0, - 0,0,0,0x10,0,0,5,5,5,5,5,5,5,6,6,6, - 6,6,8,6,6,6,6,6,0,9,9,9,9,9,9,9, - 9,9,9,0x17,0x17,0x17,0x17,5,8,8,5,0,0,0,0,0, - 0,0,0,5,5,5,6,0x17,0x17,5,0,0,0,0,0,0, - 0,0,0,5,5,5,8,8,8,6,6,6,6,6,6,6, - 6,6,8,5,5,5,5,0x17,0x17,0x17,0x17,6,6,6,6,0x17, - 8,6,9,9,9,9,9,9,9,9,9,9,5,0x17,5,0x17, - 0x17,0x17,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0,0,0,0,0,0,0,0,0,0,0,5,5,5, - 5,5,5,5,5,5,5,5,5,8,8,8,6,6,8,8, - 6,8,6,6,0x17,0x17,0x17,0x17,0x17,0x17,6,0,5,5,5,5, - 5,5,5,0,5,0,5,5,5,5,0,5,5,5,5,5, - 5,5,5,5,0x17,0,0,0,0,0,0,8,8,8,6,6, - 6,6,6,6,6,6,0,0,0,0,0,6,6,8,8,0, - 5,5,5,5,5,5,5,5,0,0,5,0,5,5,0,5, - 5,5,5,5,0,6,6,5,8,8,6,8,8,8,8,0, - 0,8,8,0,0,8,8,8,0,0,5,0,0,0,0,0, - 0,8,0,0,0,0,0,5,5,5,8,8,0,0,6,6, - 6,6,6,6,6,0,0,0,5,5,5,5,5,8,8,8, - 6,6,6,6,6,6,6,6,8,8,6,6,6,8,6,5, - 5,5,5,0x17,0x17,0x17,0x17,0x17,9,9,9,9,9,9,9,9, - 9,9,0x17,0x17,0,0x17,6,5,8,8,8,6,6,6,6,6, - 6,8,6,8,8,8,8,6,8,6,6,5,5,0x17,5,0, - 0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,8,8,6,6,6,6,0,0,8,8, - 8,8,6,6,8,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,5,5,5,5,6,6,0,0,8,8,8, - 6,6,6,6,6,6,6,6,8,8,6,8,6,0x17,0x17,0x17, - 5,0,0,0,0,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,5,5,5,5, - 5,5,5,5,5,5,5,6,8,6,8,8,6,6,6,6, - 6,6,8,6,5,0x17,0,0,0,0,0,0,8,8,6,6, - 6,6,8,6,6,6,6,6,0,0,0,0,9,9,9,9, - 9,9,9,9,9,9,0xb,0xb,0x17,0x17,0x17,0x1b,6,6,6,6, - 6,6,6,6,8,6,6,0x17,0,0,0,0,0xb,0xb,0xb,0, - 0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5, - 5,5,0,0,5,0,0,5,5,5,5,0,5,5,0,5, - 5,5,5,5,5,5,5,8,8,8,8,8,8,0,8,8, - 0,0,6,6,8,6,5,8,5,8,6,0x17,0x17,0x17,0,0, - 0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,0, - 0,5,5,5,5,5,5,8,8,8,6,6,6,6,0,0, - 6,6,8,8,8,8,6,5,0x17,5,8,0,0,0,0,0, - 0,0,0,0,0,0,5,6,6,6,6,6,6,6,6,6, - 6,5,5,5,5,5,6,6,6,6,6,6,8,5,6,6, - 6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,6,0,0,0,0,0,0, - 0,0,5,6,6,6,6,6,6,8,8,6,6,6,5,5, - 5,5,6,6,6,6,6,6,6,8,6,6,0x17,0x17,0x17,5, - 0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,0,0, - 6,6,6,6,6,6,6,0,6,6,6,6,6,6,8,6, - 5,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0, - 6,6,6,6,6,6,6,6,0,8,6,6,6,6,6,6, - 8,6,6,8,6,6,0,0,0,0,0,0,0,0,0,5, - 6,6,6,6,6,6,0,0,0,6,0,6,6,0,6,6, - 6,6,6,6,5,6,0,0,0,0,0,0,0,0,5,5, - 5,5,5,5,0,5,5,0,5,5,5,5,5,5,5,5, - 5,5,8,8,8,8,8,0,6,6,0,8,8,6,8,6, - 5,0,0,0,0,0,0,0,5,5,5,6,6,8,8,0x17, - 0x17,0,0,0,0,0,0,0,0xb,0xb,0xb,0xb,0xb,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x19,0x19,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0x17,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xa,0xa,0xa,0xa,0,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0, - 0,0,0,0,0,5,0x17,0x17,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0,0, - 0,0,0,0,0,6,6,6,6,6,0x17,0,0,0,0,0, - 0,0,0,0,0,6,6,6,6,6,6,6,0x17,0x17,0x17,0x17, - 0x17,0x1b,0x1b,0x1b,0x1b,4,4,4,4,0x17,0x1b,0,0,0,0,0, - 0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,0, - 0xb,0xb,0xb,0xb,0xb,0,5,5,5,5,5,5,5,5,5,5, - 5,5,5,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x17,0x17,0x17,0x17,0,0, - 0,0,0,5,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,0,0,0,0,0,0,0,6,6,6,4,4, - 4,4,4,4,4,4,4,4,4,4,4,0x17,4,6,0,0, - 0,0,0,0,0,0,0,0,0,8,8,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,4,4,4,4,0,4,4, - 4,4,4,4,4,0,4,4,0,0,0,0,5,5,5,5, - 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, - 5,5,0,0,0x1b,6,6,0x17,0x10,0x10,0x10,0x10,0,0,0,0, - 0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0, - 0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b,0x1b, - 8,8,8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,6,6,6,6, - 0x1b,0x1b,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1b,0x1b,0x1b,6,6,6,6,0x1b,0x1b,6,6,6,0x1b,0,0,0, - 0,0,0,0,0,0,0,0xb,0xb,0xb,0xb,0,0,0,0,0, - 0,0,0,0,0,0,0,2,2,2,2,1,1,1,1,1, - 1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2, - 2,2,2,1,0,1,1,0,0,1,0,0,1,1,0,0, - 1,1,1,1,0,1,1,1,1,1,1,2,2,2,2,0, - 2,0,2,2,2,2,1,1,0,1,1,1,1,0,0,1, - 1,1,1,1,0,1,1,1,1,1,1,1,0,2,2,2, - 2,2,2,2,2,1,1,0,1,1,1,1,0,1,1,1, - 1,1,0,1,0,0,0,1,1,1,1,1,1,0,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1, - 2,2,2,2,2,2,0,0,1,1,1,1,1,1,1,1, - 0x18,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1, - 1,1,1,1,1,1,1,1,1,1,0x18,2,2,2,2,2, - 0x18,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1, - 0x18,2,2,2,2,2,2,0x18,2,2,2,2,2,2,1,2, - 0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,6,6,6, - 6,6,6,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,6, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x17,0x17,0x17, - 0x17,0x17,0,0,0,0,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,0,6,6,6,6,6,6,6,6,6,0, - 0,6,6,6,6,6,0,6,6,0,6,6,6,6,6,0, - 0,0,0,0,6,6,6,6,6,6,6,4,4,4,4,4, - 4,4,0,0,9,9,9,9,9,9,9,9,9,9,0,0, - 0,0,5,0x1b,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,6,0,9,9,9,9,9,9,9,9,9,9,0,0, - 0,0,0,0x19,5,5,5,5,5,5,5,0,5,5,5,5, - 0,5,5,0,5,5,5,5,5,0,0,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,2,2,2,2,6,6,6,6,6,6,6,4, - 0,0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0x1b,0xb,0xb,0xb,0x19,0xb,0xb,0xb,0xb,0,0,0,0,0,0,0, - 0,0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0x1b,0xb,0,5,5,0,5,0,0,5,0,5,5,5, - 5,5,5,5,0,5,5,5,5,0,5,0,5,0,0,0, - 0,5,0,0,0,0,5,0,5,0,5,0,5,5,5,0, - 5,5,0,5,0,0,5,0,5,0,5,0,5,0,5,5, - 0,5,0,0,5,5,5,5,0,5,5,5,5,0,5,5, - 5,5,0,5,0,5,5,5,0,5,5,5,5,5,0,5, - 5,5,5,5,0x18,0x18,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a, - 0x1a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0x1b,0x1b, - 0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b, - 0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x10, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x10,0x10, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x11,0x11, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0,0,0,0 - ] -); - -pub static HEADER: CodePointTrieHeader = CodePointTrieHeader { - high_start: 0x110000, - shifted12_high_start: 0x110, - trie_type: TrieType::Small, - index3_null_offset: 0x767, - data_null_offset: 0xd18, - null_value: 0x0, -}; diff --git a/deps/crates/vendor/icu_collections-v2/benches/tries/mod.rs b/deps/crates/vendor/icu_collections-v2/benches/tries/mod.rs deleted file mode 100644 index 576516da5e4f..000000000000 --- a/deps/crates/vendor/icu_collections-v2/benches/tries/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -pub mod gc_fast; -pub mod gc_small; diff --git a/deps/crates/vendor/icu_collections-v2/src/char16trie/mod.rs b/deps/crates/vendor/icu_collections-v2/src/char16trie/mod.rs deleted file mode 100644 index 1a4b66b9471c..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/char16trie/mod.rs +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module provides a data structure for a space-efficient and time-efficient lookup of -//! sequences of 16-bit units (commonly but not necessarily UTF-16 code units) -//! which map to integer values. -//! -//! It is an implementation of the existing [ICU4C UCharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UCharsTrie.html) -//! / [ICU4J CharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/util/CharsTrie.html) API. -//! -//! ## Architecture -//! -//! ICU4X [`Char16Trie`] is designed to provide a read-only view of `UCharsTrie` data that is exported from ICU4C. -//! -//! ## Examples -//! -//! ### Querying a `Char16Trie` -//! -//! ```rust -//! use icu::collections::char16trie::{Char16Trie, TrieResult}; -//! use zerovec::ZeroVec; -//! -//! // A Char16Trie containing the ASCII characters mapping 'a' to 1 and 'ab' -//! // to 100. -//! let trie_data = [48, 97, 176, 98, 32868]; -//! let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(&trie_data)); -//! -//! let mut iter = trie.iter(); -//! let res = iter.next('a'); -//! assert_eq!(res, TrieResult::Intermediate(1)); -//! let res = iter.next('b'); -//! assert_eq!(res, TrieResult::FinalValue(100)); -//! let res = iter.next('c'); -//! assert_eq!(res, TrieResult::NoMatch); -//! ``` -//! -//! [`ICU4X`]: ../icu/index.html - -mod trie; - -pub use trie::Char16Trie; -pub use trie::Char16TrieIterator; -pub use trie::TrieResult; diff --git a/deps/crates/vendor/icu_collections-v2/src/char16trie/trie.rs b/deps/crates/vendor/icu_collections-v2/src/char16trie/trie.rs deleted file mode 100644 index 668a0ca84bbd..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/char16trie/trie.rs +++ /dev/null @@ -1,495 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use zerofrom::ZeroFrom; -use zerovec::{ZeroSlice, ZeroVec}; - -// Match-node lead unit values, after masking off intermediate-value bits: - -// 00..0f: Branch node. If node!=0 then the length is node+1, otherwise -// the length is one more than the next byte. - -// For a branch sub-node with at most this many entries, we drop down -// to a linear search. -const MAX_BRANCH_LINEAR_SUB_NODE_LENGTH: usize = 5; - -// 0030..003f: Linear-match node, match 1..16 units and continue reading the next node. -const MIN_LINEAR_MATCH: u16 = 0x30; -const MAX_LINEAR_MATCH_LENGTH: u16 = 0x10; - -// Match-node lead unit bits 14..6 for the optional intermediate value. -// If these bits are 0, then there is no intermediate value. -// Otherwise, see the *NodeValue* constants below. -const MIN_VALUE_LEAD: u16 = MIN_LINEAR_MATCH + MAX_LINEAR_MATCH_LENGTH; // 0x40 -const NODE_TYPE_MASK: u16 = MIN_VALUE_LEAD - 1; // 0x003f - -// A final-value node has bit 15 set. -const VALUE_IS_FINAL: u16 = 0x8000; - -// Compact value: After testing bit 0, shift right by 15 and then use the following thresholds. -const MAX_ONE_UNIT_VALUE: u16 = 0x3fff; - -const MIN_TWO_UNIT_VALUE_LEAD: u16 = MAX_ONE_UNIT_VALUE + 1; // 0x4000 - -const MAX_ONE_UNIT_NODE_VALUE: u16 = 0xff; - -const MIN_TWO_UNIT_NODE_VALUE_LEAD: u16 = MIN_VALUE_LEAD + ((MAX_ONE_UNIT_NODE_VALUE + 1) << 6); // 0x4040 - -const THREE_UNIT_NODE_VALUE_LEAD: u16 = 0x7fc0; - -const THREE_UNIT_VALUE_LEAD: u16 = 0x7fff; - -// Compact delta integers. -const MAX_ONE_UNIT_DELTA: u16 = 0xfbff; -const MIN_TWO_UNIT_DELTA_LEAD: u16 = MAX_ONE_UNIT_DELTA + 1; // 0xfc00 -const THREE_UNIT_DELTA_LEAD: u16 = 0xffff; - -fn skip_value(pos: usize, lead: u16) -> usize { - if lead < MIN_TWO_UNIT_VALUE_LEAD { - pos - } else if lead < THREE_UNIT_VALUE_LEAD { - pos + 1 - } else { - pos + 2 - } -} - -fn skip_node_value(pos: usize, lead: u16) -> usize { - if lead < MIN_TWO_UNIT_NODE_VALUE_LEAD { - pos - } else if lead < THREE_UNIT_NODE_VALUE_LEAD { - pos + 1 - } else { - pos + 2 - } -} - -/// This struct represents a de-serialized `Char16Trie` that was exported from -/// ICU binary data. -/// -/// Light-weight, non-const reader class for a `CharsTrie`. Traverses a -/// char-serialized data structure with minimal state, for mapping 16-bit-unit -/// sequences to non-negative integer values. -/// -/// For more information: -/// - [ICU4C UCharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UCharsTrie.html) -/// - [ICU4J CharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/util/CharsTrie.html) API. -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "databake", derive(databake::Bake))] -#[cfg_attr(feature = "databake", databake(path = icu_collections::char16trie))] -#[derive(Clone, Debug, PartialEq, Eq, ZeroFrom)] -#[allow(clippy::exhaustive_structs)] // effectively exhaustive, struct-constructible for baking -pub struct Char16Trie<'data> { - /// An array of u16 containing the trie data. - #[cfg_attr(feature = "serde", serde(borrow))] - #[doc(hidden)] // #2417 - pub data: ZeroVec<'data, u16>, -} - -impl<'data> Char16Trie<'data> { - /// Returns a new [`Char16Trie`] with ownership of the provided data. - #[inline] - pub fn new(data: ZeroVec<'data, u16>) -> Self { - Self { data } - } - - /// Returns a new [`Char16TrieIterator`] backed by borrowed data from the `trie` data - #[inline] - pub fn iter(&self) -> Char16TrieIterator<'_> { - Char16TrieIterator::new(&self.data) - } -} - -/// This struct represents an iterator over a [`Char16Trie`]. -#[derive(Clone, Debug)] -pub struct Char16TrieIterator<'a> { - /// A reference to the [`Char16Trie`] data to iterate over. - trie: &'a ZeroSlice<u16>, - /// Index of next trie unit to read, or `None` if there are no more matches. - pos: Option<usize>, - /// Remaining length of a linear-match node, minus 1, or `None` if not in - /// such a node. - remaining_match_length: Option<usize>, -} - -/// An enum representing the return value from a lookup in [`Char16Trie`]. -#[derive(Clone, Copy, Debug, PartialEq)] -#[allow(clippy::exhaustive_enums)] -pub enum TrieResult { - /// The input unit(s) did not continue a matching string. - /// Once `next()` returns `TrieResult::NoMatch`, all further calls to `next()` - /// will also return `TrieResult::NoMatch`. - NoMatch, - /// The input unit(s) matched a string but there is no value for the string - /// so far. (It is a prefix of a longer string.) - NoValue, - /// The input unit(s) continued a matching string and there is a value for - /// the string so far. No further input byte/unit can continue a matching - /// string. - FinalValue(i32), - /// The input unit(s) continued a matching string and there is a value for - /// the string so far. Another input byte/unit can continue a matching - /// string. - Intermediate(i32), -} - -// Get the lead surrogate (0xd800..0xdbff) for a -// supplementary code point (0x10000..0x10ffff). -// @param supplementary 32-bit code point (U+10000..U+10ffff) -// @return lead surrogate (U+d800..U+dbff) for supplementary -fn u16_lead(supplementary: i32) -> u16 { - (((supplementary) >> 10) + 0xd7c0) as u16 -} - -// Get the trail surrogate (0xdc00..0xdfff) for a -// supplementary code point (0x10000..0x10ffff). -// @param supplementary 32-bit code point (U+10000..U+10ffff) -// @return trail surrogate (U+dc00..U+dfff) for supplementary -fn u16_tail(supplementary: i32) -> u16 { - (((supplementary) & 0x3ff) | 0xdc00) as u16 -} - -/// A macro that takes an `Option` argument and either unwraps it if it has a value or -/// causes the function to return `TrieResult::NoMatch` if there is no value. -/// This could perhaps be done with `std::ops::Try` once stabilized. -macro_rules! trie_unwrap { - ($option:expr) => { - match $option { - Some(x) => x, - None => { - // Unexpected - debug_assert!(false); - return TrieResult::NoMatch; - } - } - }; -} - -impl<'a> Char16TrieIterator<'a> { - /// Returns a new [`Char16TrieIterator`] backed by borrowed data for the `trie` array - #[inline] - pub fn new(trie: &'a ZeroSlice<u16>) -> Self { - Self { - trie, - pos: Some(0), - remaining_match_length: None, - } - } - - /// Traverses the trie from the current state for this input char. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::char16trie::{Char16Trie, TrieResult}; - /// use zerovec::ZeroVec; - /// - /// // A Char16Trie containing the ASCII characters 'a' and 'b'. - /// let trie_data = [48, 97, 176, 98, 32868]; - /// let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(&trie_data)); - /// - /// let mut iter = trie.iter(); - /// let res = iter.next('a'); - /// assert_eq!(res, TrieResult::Intermediate(1)); - /// let res = iter.next('b'); - /// assert_eq!(res, TrieResult::FinalValue(100)); - /// let res = iter.next('c'); - /// assert_eq!(res, TrieResult::NoMatch); - /// ``` - pub fn next(&mut self, c: char) -> TrieResult { - if (c as u32) <= 0xffff { - self.next16(c as u16) - } else { - match self.next16(u16_lead(c as i32)) { - TrieResult::NoValue | TrieResult::Intermediate(_) => { - self.next16(u16_tail(c as i32)) - } - _ => TrieResult::NoMatch, - } - } - } - - /// Traverses the trie from the current state for this input char. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::char16trie::{Char16Trie, TrieResult}; - /// use zerovec::ZeroVec; - /// - /// // A Char16Trie containing the ASCII characters 'a' and 'b'. - /// let trie_data = [48, 97, 176, 98, 32868]; - /// let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(&trie_data)); - /// - /// let mut iter = trie.iter(); - /// let res = iter.next('a'); - /// assert_eq!(res, TrieResult::Intermediate(1)); - /// let res = iter.next('b'); - /// assert_eq!(res, TrieResult::FinalValue(100)); - /// let res = iter.next('c'); - /// assert_eq!(res, TrieResult::NoMatch); - /// ``` - pub fn next32(&mut self, c: u32) -> TrieResult { - if c <= 0xffff { - self.next16(c as u16) - } else { - match self.next16(u16_lead(c as i32)) { - TrieResult::NoValue | TrieResult::Intermediate(_) => { - self.next16(u16_tail(c as i32)) - } - _ => TrieResult::NoMatch, - } - } - } - - /// Traverses the trie from the current state for this input char. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::char16trie::{Char16Trie, TrieResult}; - /// use zerovec::ZeroVec; - /// - /// // A Char16Trie containing the ASCII characters 'a' and 'b'. - /// let trie_data = [48, 97, 176, 98, 32868]; - /// let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(&trie_data)); - /// - /// let mut iter = trie.iter(); - /// let res = iter.next16('a' as u16); - /// assert_eq!(res, TrieResult::Intermediate(1)); - /// let res = iter.next16('b' as u16); - /// assert_eq!(res, TrieResult::FinalValue(100)); - /// let res = iter.next16('c' as u16); - /// assert_eq!(res, TrieResult::NoMatch); - /// ``` - pub fn next16(&mut self, c: u16) -> TrieResult { - let mut pos = match self.pos { - Some(p) => p, - None => return TrieResult::NoMatch, - }; - if let Some(length) = self.remaining_match_length { - // Remaining part of a linear-match node - if c == trie_unwrap!(self.trie.get(pos)) { - pos += 1; - self.pos = Some(pos); - if length == 0 { - self.remaining_match_length = None; - let node = trie_unwrap!(self.trie.get(pos)); - if node >= MIN_VALUE_LEAD { - return self.value_result(pos); - } - } else { - self.remaining_match_length = Some(length - 1); - } - return TrieResult::NoValue; - } - self.stop(); - TrieResult::NoMatch - } else { - self.next_impl(pos, c) - } - } - - fn branch_next(&mut self, pos: usize, length: usize, in_unit: u16) -> TrieResult { - let mut pos = pos; - let mut length = length; - if length == 0 { - length = trie_unwrap!(self.trie.get(pos)) as usize; - pos += 1; - } - length += 1; - - // The length of the branch is the number of units to select from. - // The data structure encodes a binary search. - while length > MAX_BRANCH_LINEAR_SUB_NODE_LENGTH { - if in_unit < trie_unwrap!(self.trie.get(pos)) { - length >>= 1; - pos = trie_unwrap!(self.jump_by_delta(pos + 1)); - } else { - length = length - (length >> 1); - pos = trie_unwrap!(self.skip_delta(pos + 1)); - } - } - // Drop down to linear search for the last few bytes. - // length>=2 because the loop body above sees length>kMaxBranchLinearSubNodeLength>=3 - // and divides length by 2. - loop { - if in_unit == trie_unwrap!(self.trie.get(pos)) { - pos += 1; - let mut node = trie_unwrap!(self.trie.get(pos)); - if node & VALUE_IS_FINAL != 0 { - self.pos = Some(pos); - return self.value_result(pos); - } - // Use the non-final value as the jump delta. - pos += 1; - - if node < MIN_TWO_UNIT_VALUE_LEAD { - pos += node as usize; - } else if node < THREE_UNIT_VALUE_LEAD { - pos += (((node - MIN_TWO_UNIT_VALUE_LEAD) as u32) << 16) as usize - | trie_unwrap!(self.trie.get(pos)) as usize; - pos += 1; - } else { - pos += ((trie_unwrap!(self.trie.get(pos)) as usize) << 16) - | trie_unwrap!(self.trie.get(pos + 1)) as usize; - pos += 2; - } - node = trie_unwrap!(self.trie.get(pos)); - self.pos = Some(pos); - - if node >= MIN_VALUE_LEAD { - return self.value_result(pos); - } - return TrieResult::NoValue; - } - length -= 1; - pos = trie_unwrap!(self.skip_value(pos + 1)); - if length <= 1 { - break; - } - } - - if in_unit == trie_unwrap!(self.trie.get(pos)) { - pos += 1; - self.pos = Some(pos); - let node = trie_unwrap!(self.trie.get(pos)); - if node >= MIN_VALUE_LEAD { - return self.value_result(pos); - } - TrieResult::NoValue - } else { - self.stop(); - TrieResult::NoMatch - } - } - - fn next_impl(&mut self, pos: usize, in_unit: u16) -> TrieResult { - let mut node = trie_unwrap!(self.trie.get(pos)); - let mut pos = pos + 1; - loop { - if node < MIN_LINEAR_MATCH { - return self.branch_next(pos, node as usize, in_unit); - } else if node < MIN_VALUE_LEAD { - // Match the first of length+1 units. - let length = node - MIN_LINEAR_MATCH; - if in_unit == trie_unwrap!(self.trie.get(pos)) { - pos += 1; - if length == 0 { - self.remaining_match_length = None; - self.pos = Some(pos); - node = trie_unwrap!(self.trie.get(pos)); - if node >= MIN_VALUE_LEAD { - return self.value_result(pos); - } - return TrieResult::NoValue; - } - self.remaining_match_length = Some(length as usize - 1); - self.pos = Some(pos); - return TrieResult::NoValue; - } - // No match - break; - } else if (node & VALUE_IS_FINAL) != 0 { - // No further matching units. - break; - } else { - // Skip intermediate value. - pos = skip_node_value(pos, node); - node &= NODE_TYPE_MASK; - } - } - self.stop(); - TrieResult::NoMatch - } - - fn stop(&mut self) { - self.pos = None; - } - - #[inline(always)] // 1 call site and we want the Option to go away - fn jump_by_delta(&self, pos: usize) -> Option<usize> { - let delta = self.trie.get(pos)?; - let v = if delta < MIN_TWO_UNIT_DELTA_LEAD { - // nothing to do - pos + 1 + delta as usize - } else if delta == THREE_UNIT_DELTA_LEAD { - let delta = - ((self.trie.get(pos + 1)? as usize) << 16) | (self.trie.get(pos + 2)? as usize); - pos + delta + 3 - } else { - let delta = (((delta - MIN_TWO_UNIT_DELTA_LEAD) as usize) << 16) - | (self.trie.get(pos + 1)? as usize); - pos + delta + 2 - }; - Some(v) - } - - #[inline(always)] // 1 call site and we want the Option to go away - fn skip_value(&self, pos: usize) -> Option<usize> { - let lead_unit = self.trie.get(pos)?; - Some(skip_value(pos + 1, lead_unit & 0x7fff)) - } - - #[inline(always)] // 1 call site and we want the Option to go away - fn skip_delta(&self, pos: usize) -> Option<usize> { - let delta = self.trie.get(pos)?; - let v = if delta < MIN_TWO_UNIT_DELTA_LEAD { - pos + 1 - } else if delta == THREE_UNIT_DELTA_LEAD { - pos + 3 - } else { - pos + 2 - }; - Some(v) - } - - fn value_result(&self, pos: usize) -> TrieResult { - match self.get_value(pos) { - Some(result) => result, - None => { - // Unexpected - debug_assert!(false); - TrieResult::NoMatch - } - } - } - - #[inline(always)] // 1 call site and we want the Option to go away - fn get_value(&self, pos: usize) -> Option<TrieResult> { - let lead_unit = self.trie.get(pos)?; - if lead_unit & VALUE_IS_FINAL == VALUE_IS_FINAL { - self.read_value(pos + 1, lead_unit & 0x7fff) - .map(TrieResult::FinalValue) - } else { - self.read_node_value(pos + 1, lead_unit) - .map(TrieResult::Intermediate) - } - } - - #[inline(always)] // 1 call site and we want the Option to go away - fn read_value(&self, pos: usize, lead_unit: u16) -> Option<i32> { - let v = if lead_unit < MIN_TWO_UNIT_VALUE_LEAD { - lead_unit.into() - } else if lead_unit < THREE_UNIT_VALUE_LEAD { - (((lead_unit - MIN_TWO_UNIT_VALUE_LEAD) as i32) << 16) | self.trie.get(pos)? as i32 - } else { - ((self.trie.get(pos)? as i32) << 16) | self.trie.get(pos + 1)? as i32 - }; - Some(v) - } - - #[inline(always)] // 1 call site and we want the Option to go away - fn read_node_value(&self, pos: usize, lead_unit: u16) -> Option<i32> { - let v = if lead_unit < (MIN_TWO_UNIT_NODE_VALUE_LEAD) { - ((lead_unit >> 6) - 1).into() - } else if lead_unit < THREE_UNIT_NODE_VALUE_LEAD { - ((((lead_unit & 0x7fc0) - MIN_TWO_UNIT_NODE_VALUE_LEAD) as i32) << 10) - | self.trie.get(pos)? as i32 - } else { - ((self.trie.get(pos)? as i32) << 16) | self.trie.get(pos + 1)? as i32 - }; - Some(v) - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/builder.rs b/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/builder.rs deleted file mode 100644 index d24f9f66ac83..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/builder.rs +++ /dev/null @@ -1,986 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use alloc::vec; -use alloc::vec::Vec; -use core::{char, cmp::Ordering, ops::RangeBounds}; -use potential_utf::PotentialCodePoint; - -use crate::codepointinvlist::{utils::deconstruct_range, CodePointInversionList}; -use zerovec::{ule::AsULE, ZeroVec}; - -/// A builder for [`CodePointInversionList`]. -/// -/// Provides exposure to builder functions and conversion to [`CodePointInversionList`] -#[derive(Default, Clone, Debug)] -pub struct CodePointInversionListBuilder { - // A sorted list of even length, with values <= char::MAX + 1 - intervals: Vec<u32>, -} - -impl CodePointInversionListBuilder { - /// Returns empty [`CodePointInversionListBuilder`] - pub const fn new() -> Self { - Self { intervals: vec![] } - } - - /// Returns a [`CodePointInversionList`] and consumes the [`CodePointInversionListBuilder`] - pub fn build(self) -> CodePointInversionList<'static> { - let inv_list: ZeroVec<PotentialCodePoint> = self - .intervals - .into_iter() - .map(PotentialCodePoint::from_u24) - .collect(); - #[expect(clippy::unwrap_used)] // by invariant - CodePointInversionList::try_from_inversion_list(inv_list).unwrap() - } - - /// Abstraction for adding/removing a range from start..end - /// - /// If add is true add, else remove - fn add_remove_middle(&mut self, start: u32, end: u32, add: bool) { - if start >= end || end > char::MAX as u32 + 1 { - return; - } - let start_res = self.intervals.binary_search(&start); - let end_res = self.intervals.binary_search(&end); - let mut start_ind = start_res.unwrap_or_else(|x| x); - let mut end_ind = end_res.unwrap_or_else(|x| x); - let start_pos_check = (start_ind % 2 == 0) == add; - let end_pos_check = (end_ind % 2 == 0) == add; - let start_eq_end = start_ind == end_ind; - - #[expect(clippy::indexing_slicing)] // all indices are binary search results - if start_eq_end && start_pos_check && end_res.is_err() { - self.intervals.splice(start_ind..end_ind, [start, end]); - } else { - if start_pos_check { - self.intervals[start_ind] = start; - start_ind += 1; - } - if end_pos_check { - if end_res.is_ok() { - end_ind += 1; - } else { - end_ind -= 1; - self.intervals[end_ind] = end; - } - } - if start_ind < end_ind { - self.intervals.drain(start_ind..end_ind); - } - } - } - - /// Add the range to the [`CodePointInversionListBuilder`] - /// - /// Accomplishes this through binary search for the start and end indices and merges intervals - /// in between with inplace memory. Performs `O(1)` operation if adding to end of list, and `O(N)` otherwise, - /// where `N` is the number of endpoints. - fn add(&mut self, start: u32, end: u32) { - if start >= end { - return; - } - if self.intervals.is_empty() { - self.intervals.extend_from_slice(&[start, end]); - return; - } - self.add_remove_middle(start, end, true); - } - - /// Add the character to the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_char('a'); - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('a')); - /// ``` - pub fn add_char(&mut self, c: char) { - let to_add = c as u32; - self.add(to_add, to_add + 1); - } - - /// Add the code point value to the [`CodePointInversionListBuilder`] - /// - /// Note: Even though [`u32`] and [`prim@char`] in Rust are non-negative 4-byte - /// values, there is an important difference. A [`u32`] can take values up to - /// a very large integer value, while a [`prim@char`] in Rust is defined to be in - /// the range from 0 to the maximum valid Unicode Scalar Value. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add32(0x41); - /// let check = builder.build(); - /// assert!(check.contains32(0x41)); - /// ``` - pub fn add32(&mut self, c: u32) { - if c <= char::MAX as u32 { - // we already know 0 <= c because c: u32 - self.add(c, c + 1); - } - } - - /// Add the range of characters to the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='Z'); - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('A')); - /// ``` - pub fn add_range(&mut self, range: impl RangeBounds<char>) { - let (start, end) = deconstruct_range(range); - self.add(start, end); - } - - /// Add the range of characters, represented as u32, to the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range32(0xd800..=0xdfff); - /// let check = builder.build(); - /// assert!(check.contains32(0xd900)); - /// ``` - pub fn add_range32(&mut self, range: impl RangeBounds<u32>) { - let (start, end) = deconstruct_range(range); - // Sets that include char::MAX need to allow an end value of MAX + 1 - if start <= end && end <= char::MAX as u32 + 1 { - self.add(start, end); - } - } - - /// Add the [`CodePointInversionList`] reference to the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::{ - /// CodePointInversionList, CodePointInversionListBuilder, - /// }; - /// let mut builder = CodePointInversionListBuilder::new(); - /// let set = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - /// 0x41, 0x4C, - /// ]) - /// .unwrap(); - /// builder.add_set(&set); - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('A')); - /// ``` - #[allow(unused_assignments)] - pub fn add_set(&mut self, set: &CodePointInversionList) { - #[expect(clippy::indexing_slicing)] // chunks - set.as_inversion_list() - .as_ule_slice() - .chunks(2) - .for_each(|pair| { - self.add( - u32::from(PotentialCodePoint::from_unaligned(pair[0])), - u32::from(PotentialCodePoint::from_unaligned(pair[1])), - ) - }); - } - - /// Removes the range from the [`CodePointInversionListBuilder`] - /// - /// Performs binary search to find start and end affected intervals, then removes in an `O(N)` fashion - /// where `N` is the number of endpoints, with in-place memory. - fn remove(&mut self, start: u32, end: u32) { - if start >= end || self.intervals.is_empty() { - return; - } - if let Some(&last) = self.intervals.last() { - #[expect(clippy::indexing_slicing)] - // by invariant, if we have a last we have a (different) first - if start <= self.intervals[0] && end >= last { - self.intervals.clear(); - } else { - self.add_remove_middle(start, end, false); - } - } - } - - /// Remove the character from the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='Z'); - /// builder.remove_char('A'); - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('B')); - pub fn remove_char(&mut self, c: char) { - self.remove32(c as u32) - } - - /// See [`Self::remove_char`] - pub fn remove32(&mut self, c: u32) { - self.remove(c, c + 1); - } - - /// Remove the range of characters from the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='Z'); - /// builder.remove_range('A'..='C'); - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('D')); - pub fn remove_range(&mut self, range: impl RangeBounds<char>) { - let (start, end) = deconstruct_range(range); - self.remove(start, end); - } - - /// See [`Self::remove_range`] - pub fn remove_range32(&mut self, range: impl RangeBounds<u32>) { - let (start, end) = deconstruct_range(range); - self.remove(start, end); - } - - /// Remove the [`CodePointInversionList`] from the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::{CodePointInversionList, CodePointInversionListBuilder}; - /// let mut builder = CodePointInversionListBuilder::new(); - /// let set = CodePointInversionList::try_from_u32_inversion_list_slice(&[0x41, 0x46]).unwrap(); - /// builder.add_range('A'..='Z'); - /// builder.remove_set(&set); // removes 'A'..='E' - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('F')); - #[expect(clippy::indexing_slicing)] // chunks - pub fn remove_set(&mut self, set: &CodePointInversionList) { - set.as_inversion_list() - .as_ule_slice() - .chunks(2) - .for_each(|pair| { - self.remove( - u32::from(PotentialCodePoint::from_unaligned(pair[0])), - u32::from(PotentialCodePoint::from_unaligned(pair[1])), - ) - }); - } - - /// Retain the specified character in the [`CodePointInversionListBuilder`] if it exists - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='Z'); - /// builder.retain_char('A'); - /// let set = builder.build(); - /// let mut check = set.iter_chars(); - /// assert_eq!(check.next(), Some('A')); - /// assert_eq!(check.next(), None); - /// ``` - pub fn retain_char(&mut self, c: char) { - self.retain32(c as u32) - } - - /// See [`Self::retain_char`] - pub fn retain32(&mut self, c: u32) { - self.remove(0, c); - self.remove(c + 1, (char::MAX as u32) + 1); - } - - /// Retain the range of characters located within the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='Z'); - /// builder.retain_range('A'..='B'); - /// let set = builder.build(); - /// let mut check = set.iter_chars(); - /// assert_eq!(check.next(), Some('A')); - /// assert_eq!(check.next(), Some('B')); - /// assert_eq!(check.next(), None); - /// ``` - pub fn retain_range(&mut self, range: impl RangeBounds<char>) { - let (start, end) = deconstruct_range(range); - self.remove(0, start); - self.remove(end, (char::MAX as u32) + 1); - } - - /// See [`Self::retain_range`] - pub fn retain_range32(&mut self, range: impl RangeBounds<u32>) { - let (start, end) = deconstruct_range(range); - self.remove(0, start); - self.remove(end, (char::MAX as u32) + 1); - } - - /// Retain the elements in the specified set within the [`CodePointInversionListBuilder`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::{ - /// CodePointInversionList, CodePointInversionListBuilder, - /// }; - /// let mut builder = CodePointInversionListBuilder::new(); - /// let set = - /// CodePointInversionList::try_from_u32_inversion_list_slice(&[65, 70]) - /// .unwrap(); - /// builder.add_range('A'..='Z'); - /// builder.retain_set(&set); // retains 'A'..='E' - /// let check = builder.build(); - /// assert!(check.contains('A')); - /// assert!(!check.contains('G')); - /// ``` - #[expect(clippy::indexing_slicing)] // chunks - pub fn retain_set(&mut self, set: &CodePointInversionList) { - let mut prev = 0; - for pair in set.as_inversion_list().as_ule_slice().chunks(2) { - let range_start = u32::from(PotentialCodePoint::from_unaligned(pair[0])); - let range_limit = u32::from(PotentialCodePoint::from_unaligned(pair[1])); - self.remove(prev, range_start); - prev = range_limit; - } - self.remove(prev, (char::MAX as u32) + 1); - } - - /// Computes the complement of the argument, adding any elements that do not yet exist in the builder, - /// and removing any elements that already exist in the builder. See public functions for examples. - /// - /// Performs in `O(B + S)`, where `B` is the number of endpoints in the Builder, and `S` is the number - /// of endpoints in the argument. - fn complement_list(&mut self, set_iter: impl IntoIterator<Item = u32>) { - let mut res: Vec<u32> = vec![]; // not the biggest fan of having to allocate new memory - let mut ai = self.intervals.iter(); - let mut bi = set_iter.into_iter(); - let mut a = ai.next(); - let mut b = bi.next(); - while let (Some(c), Some(d)) = (a, b) { - match c.cmp(&d) { - Ordering::Less => { - res.push(*c); - a = ai.next(); - } - Ordering::Greater => { - res.push(d); - b = bi.next(); - } - Ordering::Equal => { - a = ai.next(); - b = bi.next(); - } - } - } - if let Some(c) = a { - res.push(*c) - } - if let Some(d) = b { - res.push(d) - } - res.extend(ai); - res.extend(bi); - self.intervals = res; - } - - /// Computes the complement of the builder, inverting the builder (any elements in the builder are removed, - /// while any elements not in the builder are added) - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::{ - /// CodePointInversionList, CodePointInversionListBuilder, - /// }; - /// let mut builder = CodePointInversionListBuilder::new(); - /// let set = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - /// 0x0, - /// 0x41, - /// 0x46, - /// (std::char::MAX as u32) + 1, - /// ]) - /// .unwrap(); - /// builder.add_set(&set); - /// builder.complement(); - /// let check = builder.build(); - /// assert_eq!(check.iter_chars().next(), Some('A')); - /// ``` - pub fn complement(&mut self) { - if !self.intervals.is_empty() { - #[expect(clippy::indexing_slicing)] // by invariant - if self.intervals[0] == 0 { - self.intervals.drain(0..1); - } else { - self.intervals.insert(0, 0); - } - if self.intervals.last() == Some(&(char::MAX as u32 + 1)) { - self.intervals.pop(); - } else { - self.intervals.push(char::MAX as u32 + 1); - } - } else { - self.intervals - .extend_from_slice(&[0, (char::MAX as u32 + 1)]); - } - } - - /// Complements the character in the builder, adding it if not in the builder, and removing it otherwise. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='D'); - /// builder.complement_char('A'); - /// builder.complement_char('E'); - /// let check = builder.build(); - /// assert!(check.contains('E')); - /// assert!(!check.contains('A')); - /// ``` - pub fn complement_char(&mut self, c: char) { - self.complement32(c as u32); - } - - /// See [`Self::complement_char`] - pub fn complement32(&mut self, c: u32) { - self.complement_list([c, c + 1]); - } - - /// Complements the range in the builder, adding any elements in the range if not in the builder, and - /// removing them otherwise. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// builder.add_range('A'..='D'); - /// builder.complement_range('C'..='F'); - /// let check = builder.build(); - /// assert!(check.contains('F')); - /// assert!(!check.contains('C')); - /// ``` - pub fn complement_range(&mut self, range: impl RangeBounds<char>) { - let (start, end) = deconstruct_range(range); - self.complement_list([start, end]); - } - - /// See [`Self::complement_range`] - pub fn complement_range32(&mut self, range: impl RangeBounds<u32>) { - let (start, end) = deconstruct_range(range); - self.complement_list([start, end]); - } - - /// Complements the set in the builder, adding any elements in the set if not in the builder, and - /// removing them otherwise. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::{ - /// CodePointInversionList, CodePointInversionListBuilder, - /// }; - /// let mut builder = CodePointInversionListBuilder::new(); - /// let set = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - /// 0x41, 0x46, 0x4B, 0x5A, - /// ]) - /// .unwrap(); - /// builder.add_range('C'..='N'); // 67 - 78 - /// builder.complement_set(&set); - /// let check = builder.build(); - /// assert!(check.contains('Q')); // 81 - /// assert!(!check.contains('N')); // 78 - /// ``` - pub fn complement_set(&mut self, set: &CodePointInversionList) { - let inv_list_iter_owned = set.as_inversion_list().iter().map(u32::from); - self.complement_list(inv_list_iter_owned); - } - - /// Returns whether the build is empty. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionListBuilder; - /// let mut builder = CodePointInversionListBuilder::new(); - /// let check = builder.build(); - /// assert!(check.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - self.intervals.is_empty() - } -} - -#[cfg(test)] -mod tests { - use super::{CodePointInversionList, CodePointInversionListBuilder}; - use core::char; - - fn generate_tester(ex: &[u32]) -> CodePointInversionListBuilder { - let check = CodePointInversionList::try_from_u32_inversion_list_slice(ex).unwrap(); - let mut builder = CodePointInversionListBuilder::new(); - builder.add_set(&check); - builder - } - - #[test] - fn test_new() { - let ex = CodePointInversionListBuilder::new(); - assert!(ex.intervals.is_empty()); - } - - #[test] - fn test_build() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add(0x41, 0x42); - let check: CodePointInversionList = builder.build(); - assert_eq!(check.iter_chars().next(), Some('A')); - } - - #[test] - fn test_empty_build() { - let builder = CodePointInversionListBuilder::new(); - let check: CodePointInversionList = builder.build(); - assert!(check.is_empty()); - } - - #[test] - fn test_add_to_empty() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add(0x0, 0xA); - assert_eq!(builder.intervals, [0x0, 0xA]); - } - - #[test] - fn test_add_invalid() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add(0x0, 0x0); - builder.add(0x5, 0x0); - assert!(builder.intervals.is_empty()); - } - - #[test] - fn test_add_to_start() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x0, 0x5); - let expected = [0x0, 0x5, 0xA, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_start_overlap() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x0, 0xE); - let expected = [0x0, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_end() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x3C, 0x46); - let expected = [0xA, 0x14, 0x28, 0x32, 60, 70]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_end_overlap() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x2B, 0x46); - let expected = [0xA, 0x14, 0x28, 0x46]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_middle_no_overlap() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x19, 0x1B); - let expected = [0xA, 0x14, 0x19, 0x1B, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_middle_inside() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0xA, 0x14); - let expected = [0xA, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_middle_left_overlap() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0xF, 0x19); - let expected = [0xA, 0x19, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_middle_right_overlap() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x1E, 0x28); - let expected = [0xA, 0x14, 0x1E, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_full_encompass() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x0, 0x3C); - let expected = [0x0, 0x3C]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_to_partial_encompass() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x0, 0x23); - let expected = [0x0, 0x23, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_aligned_front() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(5, 10); - let expected = [5, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_aligned_back() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x32, 0x37); - let expected = [0xA, 0x14, 0x28, 0x37]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_aligned_start_middle() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x14, 0x19); - let expected = [0xA, 0x19, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_aligned_end_middle() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x23, 0x28); - let expected = [0xA, 0x14, 0x23, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_aligned_in_between_end() { - let mut builder = generate_tester(&[0xA, 0x14, 0x1E, 0x28, 0x32, 0x3C]); - builder.add(0xF, 0x1E); - let expected = [0xA, 0x28, 0x32, 0x3C]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_aligned_in_between_start() { - let mut builder = generate_tester(&[0xA, 0x14, 0x1E, 0x28, 0x32, 0x3C]); - builder.add(20, 35); - let expected = [0xA, 0x28, 0x32, 0x3C]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_adjacent_ranges() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.add(0x13, 0x14); - builder.add(0x14, 0x15); - builder.add(0x15, 0x16); - let expected = [0xA, 0x16, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_codepointinversionlist() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - 0x5, 0xA, 0x16, 0x21, 0x2C, 0x33, - ]) - .unwrap(); - builder.add_set(&check); - let expected = [0x5, 0x14, 0x16, 0x21, 0x28, 0x33]; - assert_eq!(builder.intervals, expected); - } - #[test] - fn test_add_char() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add_char('a'); - let expected = [0x61, 0x62]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_range() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add_range('A'..='Z'); - let expected = [0x41, 0x5B]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_range32() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add_range32(0xd800..=0xdfff); - let expected = [0xd800, 0xe000]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_add_invalid_range() { - let mut builder = CodePointInversionListBuilder::new(); - builder.add_range('Z'..='A'); - assert!(builder.intervals.is_empty()); - } - - #[test] - fn test_remove_empty() { - let mut builder = CodePointInversionListBuilder::new(); - builder.remove(0x0, 0xA); - assert!(builder.intervals.is_empty()); - } - - #[test] - fn test_remove_entire_builder() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0xA, 0x32); - assert!(builder.intervals.is_empty()); - } - - #[test] - fn test_remove_entire_range() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0xA, 0x14); - let expected = [0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_partial_range_left() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0xA, 0x2B); - let expected = [0x2B, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_ne_range() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0x14, 0x28); - let expected = [0xA, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_partial_range_right() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0xF, 0x37); - let expected = [0xA, 0xF]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_middle_range() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0xC, 0x12); - let expected = [0xA, 0xC, 0x12, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_ne_middle_range() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0x19, 0x1B); - let expected = [0xA, 0x14, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_encompassed_range() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32, 70, 80]); - builder.remove(0x19, 0x37); - let expected = [0xA, 0x14, 0x46, 0x50]; - assert_eq!(builder.intervals, expected); - } - #[test] - fn test_remove_adjacent_ranges() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.remove(0x27, 0x28); - builder.remove(0x28, 0x29); - builder.remove(0x29, 0x2A); - let expected = [0xA, 0x14, 0x2A, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_char() { - let mut builder = generate_tester(&[0x41, 0x46]); - builder.remove_char('A'); // 65 - let expected = [0x42, 0x46]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_range() { - let mut builder = generate_tester(&[0x41, 0x5A]); - builder.remove_range('A'..'L'); // 65 - 76 - let expected = [0x4C, 0x5A]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_remove_set() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32, 70, 80]); - let remove = - CodePointInversionList::try_from_u32_inversion_list_slice(&[0xA, 0x14, 0x2D, 0x4B]) - .unwrap(); - builder.remove_set(&remove); - let expected = [0x28, 0x2D, 0x4B, 0x50]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_retain_char() { - let mut builder = generate_tester(&[0x41, 0x5A]); - builder.retain_char('A'); // 65 - let expected = [0x41, 0x42]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_retain_range() { - let mut builder = generate_tester(&[0x41, 0x5A]); - builder.retain_range('C'..'F'); // 67 - 70 - let expected = [0x43, 0x46]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_retain_range_empty() { - let mut builder = generate_tester(&[0x41, 0x46]); - builder.retain_range('F'..'Z'); - assert!(builder.intervals.is_empty()); - } - - #[test] - fn test_retain_set() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32, 70, 80]); - let retain = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - 0xE, 0x14, 0x19, 0x37, 0x4D, 0x51, - ]) - .unwrap(); - builder.retain_set(&retain); - let expected = [0xE, 0x14, 0x28, 0x32, 0x4D, 0x50]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.complement(); - let expected = [0x0, 0xA, 0x14, 0x28, 0x32, (char::MAX as u32) + 1]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_empty() { - let mut builder = generate_tester(&[]); - builder.complement(); - let expected = [0x0, (char::MAX as u32) + 1]; - assert_eq!(builder.intervals, expected); - - builder.complement(); - let expected: [u32; 0] = []; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_zero_max() { - let mut builder = generate_tester(&[0x0, 0xA, 0x5A, (char::MAX as u32) + 1]); - builder.complement(); - let expected = [0xA, 0x5A]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_interior() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.complement_list([0xE, 0x14]); - let expected = [0xA, 0xE, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_exterior() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.complement_list([0x19, 0x23]); - let expected = [0xA, 0x14, 0x19, 0x23, 0x28, 0x32]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_larger_list() { - let mut builder = generate_tester(&[0xA, 0x14, 0x28, 0x32]); - builder.complement_list([0x1E, 0x37, 0x3C, 0x46]); - let expected = [0xA, 0x14, 0x1E, 0x28, 0x32, 0x37, 0x3C, 0x46]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_char() { - let mut builder = generate_tester(&[0x41, 0x4C]); // A - K - builder.complement_char('A'); - builder.complement_char('L'); - let expected = [0x42, 0x4D]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_range() { - let mut builder = generate_tester(&[0x46, 0x4C]); // F - K - builder.complement_range('A'..='Z'); - let expected = [0x41, 0x46, 0x4C, 0x5B]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_complement_set() { - let mut builder = generate_tester(&[0x43, 0x4E]); - let set = - CodePointInversionList::try_from_u32_inversion_list_slice(&[0x41, 0x46, 0x4B, 0x5A]) - .unwrap(); - builder.complement_set(&set); - let expected = [0x41, 0x43, 0x46, 0x4B, 0x4E, 0x5A]; - assert_eq!(builder.intervals, expected); - } - - #[test] - fn test_is_empty() { - let builder = CodePointInversionListBuilder::new(); - assert!(builder.is_empty()); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/conversions.rs b/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/conversions.rs deleted file mode 100644 index 7488654a8f32..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/conversions.rs +++ /dev/null @@ -1,180 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use core::iter::FromIterator; -use core::{ - convert::TryFrom, - ops::{Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}, -}; - -use super::RangeError; -use crate::codepointinvlist::utils::deconstruct_range; -use crate::codepointinvlist::CodePointInversionList; -use crate::codepointinvlist::CodePointInversionListBuilder; -use potential_utf::PotentialCodePoint; -use zerovec::ZeroVec; - -fn try_from_range<'data>( - range: impl RangeBounds<char>, -) -> Result<CodePointInversionList<'data>, RangeError> { - let (from, till) = deconstruct_range(range); - if from < till { - let set = [ - PotentialCodePoint::from_u24(from), - PotentialCodePoint::from_u24(till), - ]; - let inv_list: ZeroVec<PotentialCodePoint> = ZeroVec::alloc_from_slice(&set); - #[expect(clippy::unwrap_used)] // valid - Ok(CodePointInversionList::try_from_inversion_list(inv_list).unwrap()) - } else { - Err(RangeError(from, till)) - } -} - -impl TryFrom<Range<char>> for CodePointInversionList<'_> { - type Error = RangeError; - - fn try_from(range: Range<char>) -> Result<Self, Self::Error> { - try_from_range(range) - } -} - -impl TryFrom<RangeFrom<char>> for CodePointInversionList<'_> { - type Error = RangeError; - - fn try_from(range: RangeFrom<char>) -> Result<Self, Self::Error> { - try_from_range(range) - } -} - -impl TryFrom<RangeFull> for CodePointInversionList<'_> { - type Error = RangeError; - - fn try_from(_: RangeFull) -> Result<Self, Self::Error> { - Ok(Self::all()) - } -} - -impl TryFrom<RangeInclusive<char>> for CodePointInversionList<'_> { - type Error = RangeError; - - fn try_from(range: RangeInclusive<char>) -> Result<Self, Self::Error> { - try_from_range(range) - } -} - -impl TryFrom<RangeTo<char>> for CodePointInversionList<'_> { - type Error = RangeError; - - fn try_from(range: RangeTo<char>) -> Result<Self, Self::Error> { - try_from_range(range) - } -} - -impl TryFrom<RangeToInclusive<char>> for CodePointInversionList<'_> { - type Error = RangeError; - - fn try_from(range: RangeToInclusive<char>) -> Result<Self, Self::Error> { - try_from_range(range) - } -} - -impl FromIterator<RangeInclusive<u32>> for CodePointInversionList<'_> { - fn from_iter<I: IntoIterator<Item = RangeInclusive<u32>>>(iter: I) -> Self { - let mut builder = CodePointInversionListBuilder::new(); - for range in iter { - builder.add_range32(range); - } - builder.build() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::codepointinvlist::CodePointInversionList; - use core::{char, convert::TryFrom}; - - #[test] - fn test_try_from_range() { - let check: Vec<char> = CodePointInversionList::try_from('A'..'B') - .unwrap() - .iter_chars() - .collect(); - assert_eq!(vec!['A'], check); - } - - #[test] - fn test_try_from_range_error() { - let check = CodePointInversionList::try_from('A'..'A'); - assert!(matches!(check, Err(RangeError(65, 65)))); - } - - #[test] - fn test_try_from_range_inclusive() { - let check: Vec<char> = CodePointInversionList::try_from('A'..='A') - .unwrap() - .iter_chars() - .collect(); - assert_eq!(vec!['A'], check); - } - - #[test] - fn test_try_from_range_inclusive_err() { - let check = CodePointInversionList::try_from('B'..'A'); - assert!(matches!(check, Err(RangeError(66, 65)))); - } - - #[test] - fn test_try_from_range_from() { - let uset = CodePointInversionList::try_from('A'..).unwrap(); - let check: usize = uset.size(); - let expected: usize = (char::MAX as usize) + 1 - 65; - assert_eq!(expected, check); - } - - #[test] - fn test_try_from_range_to() { - let uset = CodePointInversionList::try_from(..'A').unwrap(); - let check: usize = uset.size(); - let expected: usize = 65; - assert_eq!(expected, check); - } - - #[test] - fn test_try_from_range_to_err() { - let check = CodePointInversionList::try_from(..(0x0 as char)); - assert!(matches!(check, Err(RangeError(0, 0)))); - } - - #[test] - fn test_try_from_range_to_inclusive() { - let uset = CodePointInversionList::try_from(..='A').unwrap(); - let check: usize = uset.size(); - let expected: usize = 66; - assert_eq!(expected, check); - } - - #[test] - fn test_try_from_range_full() { - let uset = CodePointInversionList::try_from(..).unwrap(); - let check: usize = uset.size(); - let expected: usize = (char::MAX as usize) + 1; - assert_eq!(expected, check); - } - - #[test] - fn test_from_range_iterator() { - let ranges = [ - 0..=0x3FFF, - 0x4000..=0x7FFF, - 0x8000..=0xBFFF, - 0xC000..=0xFFFF, - ]; - let expected = - CodePointInversionList::try_from_u32_inversion_list_slice(&[0x0, 0x1_0000]).unwrap(); - let actual = CodePointInversionList::from_iter(ranges); - assert_eq!(expected, actual); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/cpinvlist.rs b/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/cpinvlist.rs deleted file mode 100644 index 74fa5ee57682..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/cpinvlist.rs +++ /dev/null @@ -1,1070 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -#[cfg(feature = "serde")] -use alloc::format; -#[cfg(feature = "serde")] -use alloc::string::String; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -use core::{char, ops::RangeBounds, ops::RangeInclusive}; -use potential_utf::PotentialCodePoint; -use yoke::Yokeable; -use zerofrom::ZeroFrom; -use zerovec::{ule::AsULE, zerovec, ZeroVec}; - -use super::InvalidSetError; -use crate::codepointinvlist::utils::{deconstruct_range, is_valid_zv}; - -/// Represents the end code point of the Basic Multilingual Plane range, starting from code point 0, inclusive -const BMP_MAX: u32 = 0xFFFF; - -/// Represents the inversion list for a set of all code points in the Basic Multilingual Plane. -const BMP_INV_LIST_VEC: ZeroVec<PotentialCodePoint> = zerovec!(PotentialCodePoint; PotentialCodePoint::to_unaligned; [PotentialCodePoint::from_u24(0x0), PotentialCodePoint::from_u24(BMP_MAX + 1)]); - -/// Represents the inversion list for all of the code points in the Unicode range. -const ALL_VEC: ZeroVec<PotentialCodePoint> = zerovec!(PotentialCodePoint; PotentialCodePoint::to_unaligned; [PotentialCodePoint::from_u24(0x0), PotentialCodePoint::from_u24((char::MAX as u32) + 1)]); - -/// A membership wrapper for [`CodePointInversionList`]. -/// -/// Provides exposure to membership functions and constructors from serialized `CodePointSet`s (sets of code points) -/// and predefined ranges. -#[zerovec::make_varule(CodePointInversionListULE)] -#[zerovec::skip_derive(Ord)] -#[zerovec::derive(Debug)] -#[derive(Debug, Eq, PartialEq, Clone, Yokeable, ZeroFrom)] -#[cfg_attr(not(feature = "alloc"), zerovec::skip_derive(ZeroMapKV, ToOwned))] -pub struct CodePointInversionList<'data> { - // If we wanted to use an array to keep the memory on the stack, there is an unsafe nightly feature - // https://doc.rust-lang.org/nightly/core/array/trait.FixedSizeArray.html - // Allows for traits of fixed size arrays - - // Implements an [inversion list.](https://en.wikipedia.org/wiki/Inversion_list) - inv_list: ZeroVec<'data, PotentialCodePoint>, - size: u32, -} - -#[cfg(feature = "serde")] -impl<'de: 'a, 'a> serde::Deserialize<'de> for CodePointInversionList<'a> { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: serde::Deserializer<'de>, - { - use serde::de::Error; - - let parsed_inv_list = if deserializer.is_human_readable() { - let parsed_strings = Vec::<alloc::borrow::Cow<'de, str>>::deserialize(deserializer)?; - let mut inv_list = ZeroVec::new_owned(Vec::with_capacity(parsed_strings.len() * 2)); - for range in parsed_strings { - fn internal(range: &str) -> Option<(u32, u32)> { - let (start, range) = UnicodeCodePoint::parse(range)?; - if range.is_empty() { - return Some((start.0, start.0)); - } - let (hyphen, range) = UnicodeCodePoint::parse(range)?; - if hyphen.0 != '-' as u32 { - return None; - } - let (end, range) = UnicodeCodePoint::parse(range)?; - range.is_empty().then_some((start.0, end.0)) - } - let (start, end) = internal(&range).ok_or_else(|| Error::custom(format!( - "Cannot deserialize invalid inversion list for CodePointInversionList: {range:?}" - )))?; - inv_list.with_mut(|v| { - v.push(PotentialCodePoint::from_u24(start).to_unaligned()); - v.push(PotentialCodePoint::from_u24(end + 1).to_unaligned()); - }); - } - inv_list - } else { - ZeroVec::<PotentialCodePoint>::deserialize(deserializer)? - }; - CodePointInversionList::try_from_inversion_list(parsed_inv_list).map_err(|e| { - Error::custom(format!( - "Cannot deserialize invalid inversion list for CodePointInversionList: {e:?}" - )) - }) - } -} - -#[cfg(feature = "databake")] -impl databake::Bake for CodePointInversionList<'_> { - fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream { - env.insert("icu_collections"); - let inv_list = self.inv_list.bake(env); - let size = self.size.bake(env); - // Safe because our parts are safe. - databake::quote! { unsafe { - #[allow(unused_unsafe)] - icu_collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(#inv_list, #size) - }} - } -} - -#[cfg(feature = "databake")] -impl databake::BakeSize for CodePointInversionList<'_> { - fn borrows_size(&self) -> usize { - self.inv_list.borrows_size() - } -} - -#[cfg(feature = "serde")] -#[derive(Debug, Copy, Clone)] -struct UnicodeCodePoint(u32); - -#[cfg(feature = "serde")] -impl UnicodeCodePoint { - fn from_u32(cp: u32) -> Result<Self, String> { - if cp <= char::MAX as u32 { - Ok(Self(cp)) - } else { - Err(format!("Not a Unicode code point {cp}")) - } - } - - fn parse(value: &str) -> Option<(Self, &str)> { - Some(if let Some(hex) = value.strip_prefix("U+") { - let (escape, remainder) = (hex.get(..4)?, hex.get(4..)?); - (Self(u32::from_str_radix(escape, 16).ok()?), remainder) - } else { - let c = value.chars().next()?; - (Self(c as u32), value.get(c.len_utf8()..)?) - }) - } -} - -#[cfg(feature = "serde")] -impl core::fmt::Display for UnicodeCodePoint { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self.0 { - s @ 0xD800..=0xDFFF => write!(f, "U+{s:X}"), - // char should be in range by construction but this code is not so performance-sensitive - // so we just use the replacement character - c => write!( - f, - "{}", - char::from_u32(c).unwrap_or(char::REPLACEMENT_CHARACTER) - ), - } - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for CodePointInversionList<'_> { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: serde::Serializer, - { - if serializer.is_human_readable() { - use serde::ser::Error; - use serde::ser::SerializeSeq; - let mut seq = serializer.serialize_seq(Some(self.inv_list.len() / 2))?; - for range in self.iter_ranges() { - let start = UnicodeCodePoint::from_u32(*range.start()).map_err(S::Error::custom)?; - if range.start() == range.end() { - seq.serialize_element(&format!("{start}"))?; - } else { - let end = UnicodeCodePoint::from_u32(*range.end()).map_err(S::Error::custom)?; - seq.serialize_element(&format!("{start}-{end}",))?; - } - } - seq.end() - } else { - // Note: serde(flatten) currently does not promote a struct field of type Vec - // to replace the struct when serializing. The error message from the default - // serialization is: "can only flatten structs and maps (got a sequence)". - self.inv_list.serialize(serializer) - } - } -} - -impl<'data> CodePointInversionList<'data> { - /// Returns a new [`CodePointInversionList`] from an [inversion list](https://en.wikipedia.org/wiki/Inversion_list) - /// represented as a [`ZeroVec`]`<`[`PotentialCodePoint`]`>` of code points. - /// - /// The inversion list must be of even length, sorted ascending non-overlapping, - /// and within the bounds of `0x0 -> 0x10FFFF` inclusive, and end points being exclusive. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// use icu::collections::codepointinvlist::InvalidSetError; - /// use potential_utf::PotentialCodePoint; - /// use zerovec::ZeroVec; - /// - /// let valid = [0x0, 0x10000]; - /// let inv_list: ZeroVec<PotentialCodePoint> = valid - /// .into_iter() - /// .map(PotentialCodePoint::from_u24) - /// .collect(); - /// let result = CodePointInversionList::try_from_inversion_list(inv_list); - /// assert!(matches!(result, CodePointInversionList)); - /// - /// let invalid = vec![0x0, 0x80, 0x3]; - /// let inv_list: ZeroVec<PotentialCodePoint> = invalid - /// .iter() - /// .copied() - /// .map(PotentialCodePoint::from_u24) - /// .collect(); - /// let result = CodePointInversionList::try_from_inversion_list(inv_list); - /// assert!(matches!(result, Err(InvalidSetError(_)))); - /// if let Err(InvalidSetError(actual)) = result { - /// assert_eq!( - /// &invalid, - /// &actual.into_iter().map(u32::from).collect::<Vec<_>>() - /// ); - /// } - /// ``` - pub fn try_from_inversion_list( - inv_list: ZeroVec<'data, PotentialCodePoint>, - ) -> Result<Self, InvalidSetError> { - #[expect(clippy::indexing_slicing)] // chunks - if is_valid_zv(&inv_list) { - let size = inv_list - .as_ule_slice() - .chunks(2) - .map(|end_points| { - u32::from(<PotentialCodePoint as AsULE>::from_unaligned(end_points[1])) - - u32::from(<PotentialCodePoint as AsULE>::from_unaligned(end_points[0])) - }) - .sum::<u32>(); - Ok(Self { inv_list, size }) - } else { - Err(InvalidSetError( - #[cfg(feature = "alloc")] - inv_list.to_vec(), - )) - } - } - - /// Safety: no actual safety invariants, however has correctness invariants - #[doc(hidden)] // databake internal - pub const unsafe fn from_parts_unchecked( - inv_list: ZeroVec<'data, PotentialCodePoint>, - size: u32, - ) -> Self { - Self { inv_list, size } - } - - /// Returns a new, fully-owned [`CodePointInversionList`] by cloning an [inversion list](https://en.wikipedia.org/wiki/Inversion_list) - /// represented as a slice of [`PotentialCodePoint`] code points. - /// - /// The inversion list must be of even length, sorted ascending non-overlapping, - /// and within the bounds of `0x0 -> 0x10FFFF` inclusive, and end points being exclusive. - /// - /// ✨ *Enabled with the `alloc` Cargo feature.* - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// - /// let bmp_list = &[0x0, 0x10000]; - /// let smp_list = &[0x10000, 0x20000]; - /// let sip_list = &[0x20000, 0x30000]; - /// - /// let lists: Vec<CodePointInversionList> = - /// [&bmp_list[..], smp_list, sip_list] - /// .into_iter() - /// .map(|l| { - /// CodePointInversionList::try_from_u32_inversion_list_slice(l) - /// .unwrap() - /// }) - /// .collect(); - /// - /// let bmp = &lists[0]; - /// assert!(bmp.contains32(0xFFFF)); - /// assert!(!bmp.contains32(0x10000)); - /// - /// assert!(!lists.iter().any(|set| set.contains32(0x40000))); - /// ``` - #[cfg(feature = "alloc")] - pub fn try_from_u32_inversion_list_slice(inv_list: &[u32]) -> Result<Self, InvalidSetError> { - let inv_list_zv: ZeroVec<PotentialCodePoint> = inv_list - .iter() - .copied() - .map(PotentialCodePoint::from_u24) - .collect(); - CodePointInversionList::try_from_inversion_list(inv_list_zv) - } - - /// Attempts to convert this list into a fully-owned one. No-op if already fully owned - /// - /// ✨ *Enabled with the `alloc` Cargo feature.* - #[cfg(feature = "alloc")] - pub fn into_owned(self) -> CodePointInversionList<'static> { - CodePointInversionList { - inv_list: self.inv_list.into_owned(), - size: self.size, - } - } - - /// Returns an owned inversion list representing the current [`CodePointInversionList`] - /// - /// ✨ *Enabled with the `alloc` Cargo feature.* - #[cfg(feature = "alloc")] - pub fn get_inversion_list_vec(&self) -> Vec<u32> { - self.as_inversion_list().iter().map(u32::from).collect() - } - - /// Returns [`CodePointInversionList`] spanning entire Unicode range - /// - /// The range spans from `0x0 -> 0x10FFFF` inclusive. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// - /// let expected = [0x0, (char::MAX as u32) + 1]; - /// assert_eq!( - /// CodePointInversionList::all().get_inversion_list_vec(), - /// expected - /// ); - /// assert_eq!( - /// CodePointInversionList::all().size(), - /// (expected[1] - expected[0]) as usize - /// ); - /// ``` - pub const fn all() -> Self { - Self { - inv_list: ALL_VEC, - size: (char::MAX as u32) + 1, - } - } - - /// Returns [`CodePointInversionList`] spanning BMP range - /// - /// The range spans from `0x0 -> 0xFFFF` inclusive. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// - /// const BMP_MAX: u32 = 0xFFFF; - /// - /// let expected = [0x0, BMP_MAX + 1]; - /// assert_eq!( - /// CodePointInversionList::bmp().get_inversion_list_vec(), - /// expected - /// ); - /// assert_eq!( - /// CodePointInversionList::bmp().size(), - /// (expected[1] - expected[0]) as usize - /// ); - /// ``` - pub fn bmp() -> Self { - Self { - inv_list: BMP_INV_LIST_VEC, - size: BMP_MAX + 1, - } - } - - /// Returns the inversion list as a slice - /// - /// Public only to the crate, not exposed to public - #[cfg(feature = "alloc")] - pub(crate) fn as_inversion_list(&self) -> &ZeroVec<'_, PotentialCodePoint> { - &self.inv_list - } - - /// Yields an [`Iterator`] going through the character set in the [`CodePointInversionList`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x44, 0x45, 0x46]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// let mut ex_iter_chars = example.iter_chars(); - /// assert_eq!(Some('A'), ex_iter_chars.next()); - /// assert_eq!(Some('B'), ex_iter_chars.next()); - /// assert_eq!(Some('C'), ex_iter_chars.next()); - /// assert_eq!(Some('E'), ex_iter_chars.next()); - /// assert_eq!(None, ex_iter_chars.next()); - /// ``` - pub fn iter_chars(&self) -> impl Iterator<Item = char> + '_ { - #[expect(clippy::indexing_slicing)] // chunks - self.inv_list - .as_ule_slice() - .chunks(2) - .flat_map(|pair| { - u32::from(PotentialCodePoint::from_unaligned(pair[0])) - ..u32::from(PotentialCodePoint::from_unaligned(pair[1])) - }) - .filter_map(char::from_u32) - } - - /// Yields an [`Iterator`] returning the ranges of the code points that are - /// included in the [`CodePointInversionList`] - /// - /// Ranges are returned as [`RangeInclusive`], which is inclusive of its - /// `end` bound value. An end-inclusive behavior matches the ICU4C/J - /// behavior of ranges, ex: `CodePointInversionList::contains(UChar32 start, UChar32 end)`. - /// - /// # Example - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x44, 0x45, 0x46]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// let mut example_iter_ranges = example.iter_ranges(); - /// assert_eq!(Some(0x41..=0x43), example_iter_ranges.next()); - /// assert_eq!(Some(0x45..=0x45), example_iter_ranges.next()); - /// assert_eq!(None, example_iter_ranges.next()); - /// ``` - pub fn iter_ranges(&self) -> impl ExactSizeIterator<Item = RangeInclusive<u32>> + '_ { - #[expect(clippy::indexing_slicing)] // chunks - self.inv_list.as_ule_slice().chunks(2).map(|pair| { - let range_start = u32::from(PotentialCodePoint::from_unaligned(pair[0])); - let range_limit = u32::from(PotentialCodePoint::from_unaligned(pair[1])); - range_start..=(range_limit - 1) - }) - } - - /// Yields an [`Iterator`] returning the ranges of the code points that are - /// *not* included in the [`CodePointInversionList`] - /// - /// Ranges are returned as [`RangeInclusive`], which is inclusive of its - /// `end` bound value. An end-inclusive behavior matches the ICU4C/J - /// behavior of ranges, ex: `CodePointInversionList::contains(UChar32 start, UChar32 end)`. - /// - /// # Example - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x44, 0x45, 0x46]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// let mut example_iter_ranges = example.iter_ranges_complemented(); - /// assert_eq!(Some(0..=0x40), example_iter_ranges.next()); - /// assert_eq!(Some(0x44..=0x44), example_iter_ranges.next()); - /// assert_eq!(Some(0x46..=char::MAX as u32), example_iter_ranges.next()); - /// assert_eq!(None, example_iter_ranges.next()); - /// ``` - pub fn iter_ranges_complemented(&self) -> impl Iterator<Item = RangeInclusive<u32>> + '_ { - let inv_ule = self.inv_list.as_ule_slice(); - let middle = inv_ule.get(1..inv_ule.len() - 1).unwrap_or(&[]); - let beginning = if let Some(first) = self.inv_list.first() { - let first = u32::from(first); - if first == 0 { - None - } else { - Some(0..=first - 1) - } - } else { - None - }; - let end = if let Some(last) = self.inv_list.last() { - let last = u32::from(last); - if last == char::MAX as u32 { - None - } else { - Some(last..=char::MAX as u32) - } - } else { - None - }; - #[expect(clippy::indexing_slicing)] // chunks - let chunks = middle.chunks(2).map(|pair| { - let range_start = u32::from(PotentialCodePoint::from_unaligned(pair[0])); - let range_limit = u32::from(PotentialCodePoint::from_unaligned(pair[1])); - range_start..=(range_limit - 1) - }); - beginning.into_iter().chain(chunks).chain(end) - } - - /// Returns the number of ranges contained in this [`CodePointInversionList`] - pub fn get_range_count(&self) -> usize { - self.inv_list.len() / 2 - } - - /// Returns a specific range contained in this [`CodePointInversionList`] by index. - /// Intended for use in FFI. - pub fn get_nth_range(&self, idx: usize) -> Option<RangeInclusive<u32>> { - let start_idx = idx * 2; - let end_idx = start_idx + 1; - let start = u32::from(self.inv_list.get(start_idx)?); - let end = u32::from(self.inv_list.get(end_idx)?); - Some(start..=(end - 1)) - } - - /// Returns the number of elements of the [`CodePointInversionList`] - pub fn size(&self) -> usize { - if self.is_empty() { - return 0; - } - self.size as usize - } - - /// Returns whether or not the [`CodePointInversionList`] is empty - pub fn is_empty(&self) -> bool { - self.inv_list.is_empty() - } - - /// Wrapper for contains - /// - /// Returns an [`Option`] as to whether or not it is possible for the query to be contained. - /// The value in the [`Option`] is the start index of the range that contains the query. - fn contains_query(&self, query: u32) -> Option<usize> { - let query = PotentialCodePoint::try_from(query).ok()?; - match self.inv_list.binary_search(&query) { - Ok(pos) => { - if pos % 2 == 0 { - Some(pos) - } else { - None - } - } - Err(pos) => { - if pos % 2 != 0 && pos < self.inv_list.len() { - Some(pos - 1) - } else { - None - } - } - } - } - - /// Checks to see the query is in the [`CodePointInversionList`] - /// - /// Runs a binary search in `O(log(n))` where `n` is the number of start and end points - /// in the set using [`core`] implementation - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x43, 0x44, 0x45]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// assert!(example.contains('A')); - /// assert!(!example.contains('C')); - /// ``` - pub fn contains(&self, query: char) -> bool { - self.contains_query(query as u32).is_some() - } - - /// Checks to see the unsigned int is in the [`CodePointInversionList::all()`](CodePointInversionList::all()) - /// - /// Note: Even though [`u32`] and [`prim@char`] in Rust are non-negative 4-byte - /// values, there is an important difference. A [`u32`] can take values up to - /// a very large integer value, while a [`prim@char`] in Rust is defined to be in - /// the range from 0 to the maximum valid Unicode Scalar Value. - /// - /// Runs a binary search in `O(log(n))` where `n` is the number of start and end points - /// in the set using [`core`] implementation - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x43, 0x44, 0x45]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// assert!(example.contains32(0x41)); - /// assert!(!example.contains32(0x43)); - /// ``` - pub fn contains32(&self, query: u32) -> bool { - self.contains_query(query).is_some() - } - - /// Checks to see if the range is in the [`CodePointInversionList`] - /// - /// Runs a binary search in `O(log(n))` where `n` is the number of start and end points - /// in the set using [`Vec`] implementation. Only runs the search once on the `start` - /// parameter, while the `end` parameter is checked in a single `O(1)` step. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x43, 0x44, 0x45]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// assert!(example.contains_range('A'..'C')); - /// assert!(example.contains_range('A'..='B')); - /// assert!(!example.contains_range('A'..='C')); - /// ``` - /// - /// Surrogate points (`0xD800 -> 0xDFFF`) will return [`false`] if the Range contains them but the - /// [`CodePointInversionList`] does not. - /// - /// Note: when comparing to ICU4C/J, keep in mind that `Range`s in Rust are - /// constructed inclusive of start boundary and exclusive of end boundary. - /// The ICU4C/J `CodePointInversionList::contains(UChar32 start, UChar32 end)` method - /// differs by including the end boundary. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// use std::char; - /// let check = - /// char::from_u32(0xD7FE).unwrap()..char::from_u32(0xE001).unwrap(); - /// let example_list = [0xD7FE, 0xD7FF, 0xE000, 0xE001]; - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// assert!(!example.contains_range(check)); - /// ``` - pub fn contains_range(&self, range: impl RangeBounds<char>) -> bool { - let (from, till) = deconstruct_range(range); - if from >= till { - return false; - } - match self.contains_query(from) { - Some(pos) => { - if let Some(x) = self.inv_list.get(pos + 1) { - (till) <= x.into() - } else { - debug_assert!( - false, - "Inversion list query should not return out of bounds index" - ); - false - } - } - None => false, - } - } - - /// Check if the calling [`CodePointInversionList`] contains all the characters of the given [`CodePointInversionList`] - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x46, 0x55, 0x5B]; // A - E, U - Z - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// let a_to_d = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - /// 0x41, 0x45, - /// ]) - /// .unwrap(); - /// let f_to_t = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - /// 0x46, 0x55, - /// ]) - /// .unwrap(); - /// let r_to_x = CodePointInversionList::try_from_u32_inversion_list_slice(&[ - /// 0x52, 0x58, - /// ]) - /// .unwrap(); - /// assert!(example.contains_set(&a_to_d)); // contains all - /// assert!(!example.contains_set(&f_to_t)); // contains none - /// assert!(!example.contains_set(&r_to_x)); // contains some - /// ``` - pub fn contains_set(&self, set: &Self) -> bool { - if set.size() > self.size() { - return false; - } - - let mut set_ranges = set.iter_ranges(); - let mut check_elem = set_ranges.next(); - - let ranges = self.iter_ranges(); - for range in ranges { - match check_elem { - Some(ref check_range) => { - if check_range.start() >= range.start() - && check_range.end() <= &(range.end() + 1) - { - check_elem = set_ranges.next(); - } - } - _ => break, - } - } - check_elem.is_none() - } - - /// Returns the end of the initial substring where the characters are either contained/not contained - /// in the set. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x44]; // {A, B, C} - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// assert_eq!(example.span("CABXYZ", true), 3); - /// assert_eq!(example.span("XYZC", false), 3); - /// assert_eq!(example.span("XYZ", true), 0); - /// assert_eq!(example.span("ABC", false), 0); - /// ``` - pub fn span(&self, span_str: &str, contained: bool) -> usize { - span_str - .chars() - .take_while(|&x| self.contains(x) == contained) - .count() - } - - /// Returns the start of the trailing substring (starting from end of string) where the characters are - /// either contained/not contained in the set. Returns the length of the string if no valid return. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// let example_list = [0x41, 0x44]; // {A, B, C} - /// let example = CodePointInversionList::try_from_u32_inversion_list_slice( - /// &example_list, - /// ) - /// .unwrap(); - /// assert_eq!(example.span_back("XYZCAB", true), 3); - /// assert_eq!(example.span_back("ABCXYZ", true), 6); - /// assert_eq!(example.span_back("CABXYZ", false), 3); - /// ``` - pub fn span_back(&self, span_str: &str, contained: bool) -> usize { - span_str.len() - - span_str - .chars() - .rev() - .take_while(|&x| self.contains(x) == contained) - .count() - } -} - -#[cfg(test)] -mod tests { - use super::{CodePointInversionList, InvalidSetError}; - use std::{char, vec::Vec}; - use zerovec::ZeroVec; - - #[test] - fn test_codepointinversionlist_try_from_vec() { - let ex = vec![0x2, 0x3, 0x4, 0x5]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(ex, check.get_inversion_list_vec()); - assert_eq!(2, check.size()); - } - - #[test] - fn test_codepointinversionlist_try_from_vec_error() { - let check = vec![0x1, 0x1, 0x2, 0x3, 0x4]; - let set = CodePointInversionList::try_from_u32_inversion_list_slice(&check); - assert!(matches!(set, Err(InvalidSetError(_)))); - if let Err(InvalidSetError(actual)) = set { - assert_eq!( - &check, - &actual.into_iter().map(u32::from).collect::<Vec<_>>() - ); - } - } - - // CodePointInversionList membership functions - #[test] - fn test_codepointinversionlist_contains_query() { - let ex = vec![0x41, 0x46, 0x4B, 0x55]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert!(check.contains_query(0x40).is_none()); - assert_eq!(check.contains_query(0x41).unwrap(), 0); - assert_eq!(check.contains_query(0x44).unwrap(), 0); - assert!(check.contains_query(0x46).is_none()); - assert_eq!(check.contains_query(0x4C).unwrap(), 2); - assert!(check.contains_query(0x56).is_none()); - } - - #[test] - fn test_codepointinversionlist_contains() { - let ex = vec![0x2, 0x5, 0xA, 0xF]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert!(check.contains(0x2 as char)); - assert!(check.contains(0x4 as char)); - assert!(check.contains(0xA as char)); - assert!(check.contains(0xE as char)); - } - - #[test] - fn test_codepointinversionlist_contains_false() { - let ex = vec![0x2, 0x5, 0xA, 0xF]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert!(!check.contains(0x1 as char)); - assert!(!check.contains(0x5 as char)); - assert!(!check.contains(0x9 as char)); - assert!(!check.contains(0xF as char)); - assert!(!check.contains(0x10 as char)); - } - - #[test] - fn test_codepointinversionlist_contains_range() { - let ex = vec![0x41, 0x46, 0x4B, 0x55]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert!(check.contains_range('A'..='E')); // 65 - 69 - assert!(check.contains_range('C'..'D')); // 67 - 67 - assert!(check.contains_range('L'..'P')); // 76 - 80 - assert!(!check.contains_range('L'..='U')); // 76 - 85 - } - - #[test] - fn test_codepointinversionlist_contains_range_false() { - let ex = vec![0x41, 0x46, 0x4B, 0x55]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert!(!check.contains_range('!'..'A')); // 33 - 65 - assert!(!check.contains_range('F'..'K')); // 70 - 74 - assert!(!check.contains_range('U'..)); // 85 - .. - } - - #[test] - fn test_codepointinversionlist_contains_range_invalid() { - let check = CodePointInversionList::all(); - assert!(!check.contains_range('A'..'!')); // 65 - 33 - assert!(!check.contains_range('A'..'A')); // 65 - 65 - } - - #[test] - fn test_codepointinversionlist_contains_set_u() { - let ex = vec![0xA, 0x14, 0x28, 0x32, 0x46, 0x50, 0x64, 0x6E]; - let u = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - let inside = vec![0xF, 0x14, 0x2C, 0x31, 0x46, 0x50, 0x64, 0x6D]; - let s = CodePointInversionList::try_from_u32_inversion_list_slice(&inside).unwrap(); - assert!(u.contains_set(&s)); - } - - #[test] - fn test_codepointinversionlist_contains_set_u_false() { - let ex = vec![0xA, 0x14, 0x28, 0x32, 0x46, 0x50, 0x64, 0x78]; - let u = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - let outside = vec![0x0, 0xA, 0x16, 0x2C, 0x32, 0x46, 0x4F, 0x51, 0x6D, 0x6F]; - let s = CodePointInversionList::try_from_u32_inversion_list_slice(&outside).unwrap(); - assert!(!u.contains_set(&s)); - } - - #[test] - fn test_codepointinversionlist_size() { - let ex = vec![0x2, 0x5, 0xA, 0xF]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(8, check.size()); - let check = CodePointInversionList::all(); - let expected = (char::MAX as u32) + 1; - assert_eq!(expected as usize, check.size()); - let inv_list_vec = vec![]; - let check = CodePointInversionList { - inv_list: ZeroVec::from_slice_or_alloc(&inv_list_vec), - size: 0, - }; - assert_eq!(check.size(), 0); - } - - #[test] - fn test_codepointinversionlist_is_empty() { - let inv_list_vec = vec![]; - let check = CodePointInversionList { - inv_list: ZeroVec::from_slice_or_alloc(&inv_list_vec), - size: 0, - }; - assert!(check.is_empty()); - } - - #[test] - fn test_codepointinversionlist_is_not_empty() { - let check = CodePointInversionList::all(); - assert!(!check.is_empty()); - } - - #[test] - fn test_codepointinversionlist_iter_chars() { - let ex = vec![0x41, 0x44, 0x45, 0x46, 0xD800, 0xD801]; - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - let mut iter = check.iter_chars(); - assert_eq!(Some('A'), iter.next()); - assert_eq!(Some('B'), iter.next()); - assert_eq!(Some('C'), iter.next()); - assert_eq!(Some('E'), iter.next()); - assert_eq!(None, iter.next()); - } - - #[test] - fn test_codepointinversionlist_iter_ranges() { - let ex = vec![0x41, 0x44, 0x45, 0x46, 0xD800, 0xD801]; - let set = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - let mut ranges = set.iter_ranges(); - assert_eq!(Some(0x41..=0x43), ranges.next()); - assert_eq!(Some(0x45..=0x45), ranges.next()); - assert_eq!(Some(0xD800..=0xD800), ranges.next()); - assert_eq!(None, ranges.next()); - } - - #[test] - fn test_codepointinversionlist_iter_ranges_exactsizeiter_trait() { - let ex = vec![0x41, 0x44, 0x45, 0x46, 0xD800, 0xD801]; - let set = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - let ranges = set.iter_ranges(); - assert_eq!(3, ranges.len()); - } - - #[test] - fn test_codepointinversionlist_range_count() { - let ex = vec![0x41, 0x44, 0x45, 0x46, 0xD800, 0xD801]; - let set = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(3, set.get_range_count()); - } - - #[test] - fn test_codepointinversionlist_get_nth_range() { - let ex = vec![0x41, 0x44, 0x45, 0x46, 0xD800, 0xD801]; - let set = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(Some(0x41..=0x43), set.get_nth_range(0)); - assert_eq!(Some(0x45..=0x45), set.get_nth_range(1)); - assert_eq!(Some(0xD800..=0xD800), set.get_nth_range(2)); - assert_eq!(None, set.get_nth_range(3)); - } - - // Range<char> cannot represent the upper bound (non-inclusive) for - // char::MAX, whereas Range<u32> can. - #[test] - fn test_codepointinversionlist_iter_ranges_with_max_code_point() { - let ex = vec![0x80, (char::MAX as u32) + 1]; - let set = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - let mut ranges = set.iter_ranges(); - assert_eq!(Some(0x80..=(char::MAX as u32)), ranges.next()); - assert_eq!(None, ranges.next()); - } - - #[test] - fn test_codepointinversionlist_span_contains() { - let ex = vec![0x41, 0x44, 0x46, 0x4B]; // A - D, F - K - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(check.span("ABCDE", true), 3); - assert_eq!(check.span("E", true), 0); - } - - #[test] - fn test_codepointinversionlist_span_does_not_contain() { - let ex = vec![0x41, 0x44, 0x46, 0x4B]; // A - D, F - K - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(check.span("DEF", false), 2); - assert_eq!(check.span("KLMA", false), 3); - } - - #[test] - fn test_codepointinversionlist_span_back_contains() { - let ex = vec![0x41, 0x44, 0x46, 0x4B]; // A - D, F - K - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(check.span_back("XYZABFH", true), 3); - assert_eq!(check.span_back("ABCXYZ", true), 6); - } - - #[test] - fn test_codepointinversionlist_span_back_does_not_contain() { - let ex = vec![0x41, 0x44, 0x46, 0x4B]; // A - D, F - K - let check = CodePointInversionList::try_from_u32_inversion_list_slice(&ex).unwrap(); - assert_eq!(check.span_back("ABCXYZ", false), 3); - assert_eq!(check.span_back("XYZABC", false), 6); - } - - #[test] - fn test_uniset_to_inv_list() { - let inv_list = [ - 0x9, 0xE, 0x20, 0x21, 0x85, 0x86, 0xA0, 0xA1, 0x1626, 0x1627, 0x2000, 0x2003, 0x2028, - 0x202A, 0x202F, 0x2030, 0x205F, 0x2060, 0x3000, 0x3001, - ]; - let s: CodePointInversionList = - CodePointInversionList::try_from_u32_inversion_list_slice(&inv_list).unwrap(); - let round_trip_inv_list = s.get_inversion_list_vec(); - assert_eq!( - round_trip_inv_list.into_iter().collect::<ZeroVec<u32>>(), - inv_list - ); - } - - #[test] - fn test_serde_serialize() { - let inv_list = [0x41, 0x46, 0x4B, 0x55]; - let uniset = CodePointInversionList::try_from_u32_inversion_list_slice(&inv_list).unwrap(); - let json_str = serde_json::to_string(&uniset).unwrap(); - assert_eq!(json_str, r#"["A-E","K-T"]"#); - } - - #[test] - fn test_serde_serialize_surrogates() { - let inv_list = [0xDFAB, 0xDFFF]; - let uniset = CodePointInversionList::try_from_u32_inversion_list_slice(&inv_list).unwrap(); - let json_str = serde_json::to_string(&uniset).unwrap(); - assert_eq!(json_str, r#"["U+DFAB-U+DFFE"]"#); - } - - #[test] - fn test_serde_deserialize() { - let inv_list_str = r#"["A-E","K-T"]"#; - let exp_inv_list = [0x41, 0x46, 0x4B, 0x55]; - let exp_uniset = - CodePointInversionList::try_from_u32_inversion_list_slice(&exp_inv_list).unwrap(); - let act_uniset: CodePointInversionList = serde_json::from_str(inv_list_str).unwrap(); - assert_eq!(act_uniset, exp_uniset); - } - - #[test] - fn test_serde_deserialize_surrogates() { - let inv_list_str = r#"["U+DFAB-U+DFFE"]"#; - let exp_inv_list = [0xDFAB, 0xDFFF]; - let exp_uniset = - CodePointInversionList::try_from_u32_inversion_list_slice(&exp_inv_list).unwrap(); - let act_uniset: CodePointInversionList = serde_json::from_str(inv_list_str).unwrap(); - assert_eq!(act_uniset, exp_uniset); - } - - #[test] - fn test_serde_deserialize_invalid() { - assert!(serde_json::from_str::<CodePointInversionList>("[65,70,98775,85]").is_err()); - assert!(serde_json::from_str::<CodePointInversionList>("[65,70,U+FFFFFFFFFF,85]").is_err()); - } - - #[test] - fn test_serde_with_postcard_roundtrip() -> Result<(), postcard::Error> { - let set = CodePointInversionList::bmp(); - let set_serialized: Vec<u8> = postcard::to_allocvec(&set).unwrap(); - let set_deserialized: CodePointInversionList = - postcard::from_bytes::<CodePointInversionList>(&set_serialized)?; - - assert_eq!(&set, &set_deserialized); - assert!(!set_deserialized.inv_list.is_owned()); - - Ok(()) - } - - #[test] - fn databake() { - databake::test_bake!( - CodePointInversionList<'static>, - const, - unsafe { - #[allow(unused_unsafe)] - crate::codepointinvlist::CodePointInversionList::from_parts_unchecked( - unsafe { - zerovec::ZeroVec::from_bytes_unchecked( - b"0\0\0\0:\0\0\0A\0\0\0G\0\0\0a\0\0\0g\0\0\0", - ) - }, - 22u32, - ) - }, - icu_collections, - [zerovec], - ); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/mod.rs b/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/mod.rs deleted file mode 100644 index be47ec5ca0d2..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/mod.rs +++ /dev/null @@ -1,80 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module provides necessary functionality for highly efficient querying of sets of Unicode characters. -//! -//! It is an implementation of the code point portion of the existing -//! [ICU4C UnicodeSet API](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UnicodeSet.html). -//! -//! # Architecture -//! ICU4X [`CodePointInversionList`] is split up into independent levels, with [`CodePointInversionList`] representing the membership/query API, -//! and [`CodePointInversionListBuilder`] representing the builder API. -//! -//! # Examples: -//! -//! ## Creating a `CodePointInversionList` -//! -//! `CodePointSets` are created from either serialized [`CodePointSets`](CodePointInversionList), -//! represented by [inversion lists](https://unicode-org.github.io/icu/userguide/strings/properties.html), -//! the [`CodePointInversionListBuilder`], or from the Properties API. -//! -//! ``` -//! use icu::collections::codepointinvlist::{ -//! CodePointInversionList, CodePointInversionListBuilder, -//! }; -//! -//! let mut builder = CodePointInversionListBuilder::new(); -//! builder.add_range('A'..='Z'); -//! let set: CodePointInversionList = builder.build(); -//! -//! assert!(set.contains('A')); -//! ``` -//! -//! ## Querying a `CodePointInversionList` -//! -//! Currently, you can check if a character/range of characters exists in the [`CodePointInversionList`], or iterate through the characters. -//! -//! ``` -//! use icu::collections::codepointinvlist::{ -//! CodePointInversionList, CodePointInversionListBuilder, -//! }; -//! -//! let mut builder = CodePointInversionListBuilder::new(); -//! builder.add_range('A'..='Z'); -//! let set: CodePointInversionList = builder.build(); -//! -//! assert!(set.contains('A')); -//! assert!(set.contains_range('A'..='C')); -//! assert_eq!(set.iter_chars().next(), Some('A')); -//! ``` -//! -//! [`ICU4X`]: ../icu/index.html - -#[cfg(feature = "alloc")] -#[macro_use] -mod builder; -#[cfg(feature = "alloc")] -mod conversions; -mod cpinvlist; -mod utils; - -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -#[cfg(feature = "alloc")] -pub use builder::CodePointInversionListBuilder; -pub use cpinvlist::CodePointInversionList; -pub use cpinvlist::CodePointInversionListULE; -use displaydoc::Display; - -#[derive(Display, Debug)] -/// A [`CodePointInversionList`] was constructed with an invalid inversion list -#[cfg_attr(feature = "alloc", displaydoc("Invalid set: {0:?}"))] -#[allow(clippy::exhaustive_structs)] // newtype -pub struct InvalidSetError(#[cfg(feature = "alloc")] pub Vec<potential_utf::PotentialCodePoint>); - -/// A [`CodePointInversionList`] was constructed from an invalid range -#[derive(Display, Debug)] -#[displaydoc("Invalid range: {0}..{1}")] -#[allow(clippy::exhaustive_structs)] // newtype -pub struct RangeError(pub u32, pub u32); diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/utils.rs b/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/utils.rs deleted file mode 100644 index ef04d3b18b9a..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointinvlist/utils.rs +++ /dev/null @@ -1,118 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use core::{ - char, - ops::{Bound::*, RangeBounds}, -}; -use potential_utf::PotentialCodePoint; -use zerovec::ule::AsULE; -use zerovec::ZeroVec; - -/// Returns whether the vector is sorted ascending non inclusive, of even length, -/// and within the bounds of `0x0 -> 0x10FFFF + 1` inclusive. -#[expect(clippy::indexing_slicing)] // windows -#[expect(clippy::unwrap_used)] // by is_empty check -pub fn is_valid_zv(inv_list_zv: &ZeroVec<'_, PotentialCodePoint>) -> bool { - inv_list_zv.is_empty() - || (inv_list_zv.len() % 2 == 0 - && inv_list_zv.as_ule_slice().windows(2).all(|chunk| { - <PotentialCodePoint as AsULE>::from_unaligned(chunk[0]) - < <PotentialCodePoint as AsULE>::from_unaligned(chunk[1]) - }) - && u32::from(inv_list_zv.last().unwrap()) <= char::MAX as u32 + 1) -} - -/// Returns start (inclusive) and end (exclusive) bounds of [`RangeBounds`] -pub fn deconstruct_range<T>(range: impl RangeBounds<T>) -> (u32, u32) -where - T: Into<u32> + Copy, -{ - let from = match range.start_bound() { - Included(b) => (*b).into(), - Excluded(_) => unreachable!(), - Unbounded => 0, - }; - let till = match range.end_bound() { - Included(b) => (*b).into() + 1, - Excluded(b) => (*b).into(), - Unbounded => (char::MAX as u32) + 1, - }; - (from, till) -} - -#[cfg(test)] -mod tests { - use super::{deconstruct_range, is_valid_zv, PotentialCodePoint}; - use core::char; - use zerovec::ZeroVec; - - fn make_zv(slice: &[u32]) -> ZeroVec<'_, PotentialCodePoint> { - slice - .iter() - .copied() - .map(PotentialCodePoint::from_u24) - .collect() - } - #[test] - fn test_is_valid_zv() { - let check = make_zv(&[0x2, 0x3, 0x4, 0x5]); - assert!(is_valid_zv(&check)); - } - - #[test] - fn test_is_valid_zv_empty() { - let check = make_zv(&[]); - assert!(is_valid_zv(&check)); - } - - #[test] - fn test_is_valid_zv_overlapping() { - let check = make_zv(&[0x2, 0x5, 0x4, 0x6]); - assert!(!is_valid_zv(&check)); - } - - #[test] - fn test_is_valid_zv_out_of_order() { - let check = make_zv(&[0x5, 0x4, 0x5, 0x6, 0x7]); - assert!(!is_valid_zv(&check)); - } - - #[test] - fn test_is_valid_zv_duplicate() { - let check = make_zv(&[0x1, 0x2, 0x3, 0x3, 0x5]); - assert!(!is_valid_zv(&check)); - } - - #[test] - fn test_is_valid_zv_odd() { - let check = make_zv(&[0x1, 0x2, 0x3, 0x4, 0x5]); - assert!(!is_valid_zv(&check)); - } - - #[test] - fn test_is_valid_zv_out_of_range() { - let check = make_zv(&[0x1, 0x2, 0x3, 0x4, (char::MAX as u32) + 1]); - assert!(!is_valid_zv(&check)); - } - - // deconstruct_range - - #[test] - fn test_deconstruct_range() { - let expected = (0x41, 0x45); - let check = deconstruct_range('A'..'E'); // Range - assert_eq!(check, expected); - let check = deconstruct_range('A'..='D'); // Range Inclusive - assert_eq!(check, expected); - let check = deconstruct_range('A'..); // Range From - assert_eq!(check, (0x41, (char::MAX as u32) + 1)); - let check = deconstruct_range(..'A'); // Range To - assert_eq!(check, (0x0, 0x41)); - let check = deconstruct_range(..='A'); // Range To Inclusive - assert_eq!(check, (0x0, 0x42)); - let check = deconstruct_range::<char>(..); // Range Full - assert_eq!(check, (0x0, (char::MAX as u32) + 1)); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointinvliststringlist/mod.rs b/deps/crates/vendor/icu_collections-v2/src/codepointinvliststringlist/mod.rs deleted file mode 100644 index 9fb15c64bfe0..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointinvliststringlist/mod.rs +++ /dev/null @@ -1,400 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module provides functionality for querying of sets of Unicode code points and strings. -//! -//! It depends on [`CodePointInversionList`] to efficiently represent Unicode code points, while -//! it also maintains a list of strings in the set. -//! -//! It is an implementation of the existing [ICU4C UnicodeSet API](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UnicodeSet.html). - -#[cfg(feature = "alloc")] -use crate::codepointinvlist::CodePointInversionListBuilder; -use crate::codepointinvlist::{CodePointInversionList, CodePointInversionListULE}; -#[cfg(feature = "alloc")] -use alloc::string::{String, ToString}; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -use displaydoc::Display; -use yoke::Yokeable; -use zerofrom::ZeroFrom; -use zerovec::{VarZeroSlice, VarZeroVec}; - -/// A data structure providing a concrete implementation of a set of code points and strings, -/// using an inversion list for the code points. -/// -/// This is what ICU4C calls a `UnicodeSet`. -#[zerovec::make_varule(CodePointInversionListAndStringListULE)] -#[zerovec::skip_derive(Ord)] -#[zerovec::derive(Debug)] -#[derive(Debug, Eq, PartialEq, Clone, Yokeable, ZeroFrom)] -#[cfg_attr(not(feature = "alloc"), zerovec::skip_derive(ZeroMapKV, ToOwned))] -// Valid to auto-derive Deserialize because the invariants are weakly held -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "serde", zerovec::derive(Serialize, Deserialize, Debug))] -pub struct CodePointInversionListAndStringList<'data> { - #[cfg_attr(feature = "serde", serde(borrow))] - #[zerovec::varule(CodePointInversionListULE)] - cp_inv_list: CodePointInversionList<'data>, - // Invariants (weakly held): - // - no input string is length 1 (a length 1 string should be a single code point) - // - the string list is sorted - // - the elements in the string list are unique - #[cfg_attr(feature = "serde", serde(borrow))] - str_list: VarZeroVec<'data, str>, -} - -#[cfg(feature = "databake")] -impl databake::Bake for CodePointInversionListAndStringList<'_> { - fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream { - env.insert("icu_collections"); - let cp_inv_list = self.cp_inv_list.bake(env); - let str_list = self.str_list.bake(env); - // Safe because our parts are safe. - databake::quote! { - icu_collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked(#cp_inv_list, #str_list) - } - } -} - -#[cfg(feature = "databake")] -impl databake::BakeSize for CodePointInversionListAndStringList<'_> { - fn borrows_size(&self) -> usize { - self.cp_inv_list.borrows_size() + self.str_list.borrows_size() - } -} - -impl<'data> CodePointInversionListAndStringList<'data> { - /// Returns a new [`CodePointInversionListAndStringList`] from both a [`CodePointInversionList`] for the - /// code points and a [`VarZeroVec`]`<`[`str`]`>` of strings. - pub fn try_from( - cp_inv_list: CodePointInversionList<'data>, - str_list: VarZeroVec<'data, str>, - ) -> Result<Self, InvalidStringList> { - // Verify invariants: - // Do so by using the equivalent of str_list.iter().windows(2) to get - // overlapping windows of size 2. The above putative code is not possible - // because `.windows()` exists on a slice, but VarZeroVec cannot return a slice - // because the non-fixed size elements necessitate at least some type - // of allocation. - { - let mut it = str_list.iter(); - if let Some(mut x) = it.next() { - if x.len() == 1 { - return Err(InvalidStringList::InvalidStringLength( - #[cfg(feature = "alloc")] - x.to_string(), - )); - } - for y in it { - if x.len() == 1 { - return Err(InvalidStringList::InvalidStringLength( - #[cfg(feature = "alloc")] - x.to_string(), - )); - } else if x == y { - return Err(InvalidStringList::StringListNotUnique( - #[cfg(feature = "alloc")] - x.to_string(), - )); - } else if x > y { - return Err(InvalidStringList::StringListNotSorted( - #[cfg(feature = "alloc")] - x.to_string(), - #[cfg(feature = "alloc")] - y.to_string(), - )); - } - - // Next window begins. Update `x` here, `y` will be updated in next loop iteration. - x = y; - } - } - } - - Ok(CodePointInversionListAndStringList { - cp_inv_list, - str_list, - }) - } - - #[doc(hidden)] // databake internal - pub const fn from_parts_unchecked( - cp_inv_list: CodePointInversionList<'data>, - str_list: VarZeroVec<'data, str>, - ) -> Self { - CodePointInversionListAndStringList { - cp_inv_list, - str_list, - } - } - - /// Returns the number of elements in this set (its cardinality). - /// Note than the elements of a set may include both individual - /// codepoints and strings. - pub fn size(&self) -> usize { - self.cp_inv_list.size() + self.str_list.len() - } - - /// Return true if this set contains multi-code point strings or the empty string. - pub fn has_strings(&self) -> bool { - !self.str_list.is_empty() - } - - /// - /// # Examples - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// use icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList; - /// use zerovec::VarZeroVec; - /// - /// let cp_slice = &[0, 0x1_0000, 0x10_FFFF, 0x11_0000]; - /// let cp_list = - /// CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - /// let str_slice = &["", "bmp_max", "unicode_max", "zero"]; - /// let str_list = VarZeroVec::<str>::from(str_slice); - /// - /// let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list).unwrap(); - /// - /// assert!(cpilsl.contains_str("bmp_max")); - /// assert!(cpilsl.contains_str("")); - /// assert!(cpilsl.contains_str("A")); - /// assert!(cpilsl.contains_str("ቔ")); // U+1254 ETHIOPIC SYLLABLE QHEE - /// assert!(!cpilsl.contains_str("bazinga!")); - /// ``` - pub fn contains_str(&self, s: &str) -> bool { - let mut chars = s.chars(); - if let Some(first_char) = chars.next() { - if chars.next().is_none() { - return self.contains(first_char); - } - } - self.str_list.binary_search(s).is_ok() - } - - /// See [`Self::contains_str`] - pub fn contains_utf8(&self, s: &[u8]) -> bool { - use utf8_iter::Utf8CharsEx; - let mut chars = s.chars(); - if let Some(first_char) = chars.next() { - if chars.next().is_none() { - return self.contains(first_char); - } - } - self.str_list - .binary_search_by(|t| t.as_bytes().cmp(s)) - .is_ok() - } - - /// - /// # Examples - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// use icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList; - /// use zerovec::VarZeroVec; - /// - /// let cp_slice = &[0, 0x80, 0xFFFF, 0x1_0000, 0x10_FFFF, 0x11_0000]; - /// let cp_list = - /// CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - /// let str_slice = &["", "ascii_max", "bmp_max", "unicode_max", "zero"]; - /// let str_list = VarZeroVec::<str>::from(str_slice); - /// - /// let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list).unwrap(); - /// - /// assert!(cpilsl.contains32(0)); - /// assert!(cpilsl.contains32(0x0042)); - /// assert!(!cpilsl.contains32(0x0080)); - /// ``` - pub fn contains32(&self, cp: u32) -> bool { - self.cp_inv_list.contains32(cp) - } - - /// - /// # Examples - /// ``` - /// use icu::collections::codepointinvlist::CodePointInversionList; - /// use icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList; - /// use zerovec::VarZeroVec; - /// - /// let cp_slice = &[0, 0x1_0000, 0x10_FFFF, 0x11_0000]; - /// let cp_list = - /// CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - /// let str_slice = &["", "bmp_max", "unicode_max", "zero"]; - /// let str_list = VarZeroVec::<str>::from(str_slice); - /// - /// let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list).unwrap(); - /// - /// assert!(cpilsl.contains('A')); - /// assert!(cpilsl.contains('ቔ')); // U+1254 ETHIOPIC SYLLABLE QHEE - /// assert!(!cpilsl.contains('\u{1_0000}')); - /// assert!(!cpilsl.contains('🨫')); // U+1FA2B NEUTRAL CHESS TURNED QUEEN - pub fn contains(&self, ch: char) -> bool { - self.contains32(ch as u32) - } - - /// Access the underlying [`CodePointInversionList`]. - pub fn code_points(&self) -> &CodePointInversionList<'data> { - &self.cp_inv_list - } - - /// Access the contained strings. - pub fn strings(&self) -> &VarZeroSlice<str> { - &self.str_list - } -} - -#[cfg(feature = "alloc")] -/// ✨ *Enabled with the `alloc` Cargo feature.* -impl<'a> FromIterator<&'a str> for CodePointInversionListAndStringList<'_> { - fn from_iter<I>(it: I) -> Self - where - I: IntoIterator<Item = &'a str>, - { - let mut builder = CodePointInversionListBuilder::new(); - let mut strings = Vec::<&str>::new(); - for s in it { - let mut chars = s.chars(); - if let Some(first_char) = chars.next() { - if chars.next().is_none() { - builder.add_char(first_char); - continue; - } - } - strings.push(s); - } - - // Ensure that the string list is sorted. If not, the binary search that - // is used for `.contains(&str)` will return garbage output. - strings.sort_unstable(); - strings.dedup(); - - let cp_inv_list = builder.build(); - let str_list = VarZeroVec::<str>::from(&strings); - - CodePointInversionListAndStringList { - cp_inv_list, - str_list, - } - } -} - -/// Custom Errors for [`CodePointInversionListAndStringList`]. -#[derive(Display, Debug)] -#[allow(clippy::exhaustive_enums)] // todo, missed in 2.0 -pub enum InvalidStringList { - /// A string in the string list had an invalid length - #[cfg_attr(feature = "alloc", displaydoc("Invalid string length for string: {0}"))] - InvalidStringLength(#[cfg(feature = "alloc")] String), - /// A string in the string list appears more than once - #[cfg_attr(feature = "alloc", displaydoc("String list has duplicate: {0}"))] - StringListNotUnique(#[cfg(feature = "alloc")] String), - /// Two strings in the string list compare to each other opposite of sorted order - #[cfg_attr( - feature = "alloc", - displaydoc("Strings in string list not in sorted order: ({0}, {1})") - )] - StringListNotSorted( - #[cfg(feature = "alloc")] String, - #[cfg(feature = "alloc")] String, - ), -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_size_has_strings() { - let cp_slice = &[0, 1, 0x7F, 0x80, 0xFFFF, 0x1_0000, 0x10_FFFF, 0x11_0000]; - let cp_list = CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - let str_slice = &["ascii_max", "bmp_max", "unicode_max", "zero"]; - let str_list = VarZeroVec::<str>::from(str_slice); - - let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list).unwrap(); - - assert!(cpilsl.has_strings()); - assert_eq!(8, cpilsl.size()); - } - - #[test] - fn test_empty_string_allowed() { - let cp_slice = &[0, 1, 0x7F, 0x80, 0xFFFF, 0x1_0000, 0x10_FFFF, 0x11_0000]; - let cp_list = CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - let str_slice = &["", "ascii_max", "bmp_max", "unicode_max", "zero"]; - let str_list = VarZeroVec::<str>::from(str_slice); - - let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list).unwrap(); - - assert!(cpilsl.has_strings()); - assert_eq!(9, cpilsl.size()); - } - - #[test] - fn test_invalid_string() { - let cp_slice = &[0, 1]; - let cp_list = CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - let str_slice = &["a"]; - let str_list = VarZeroVec::<str>::from(str_slice); - - let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list); - - assert!(matches!( - cpilsl, - Err(InvalidStringList::InvalidStringLength(_)) - )); - } - - #[test] - fn test_invalid_string_list_has_duplicate() { - let cp_slice = &[0, 1]; - let cp_list = CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - let str_slice = &["abc", "abc"]; - let str_list = VarZeroVec::<str>::from(str_slice); - - let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list); - - assert!(matches!( - cpilsl, - Err(InvalidStringList::StringListNotUnique(_)) - )); - } - - #[test] - fn test_invalid_string_list_not_sorted() { - let cp_slice = &[0, 1]; - let cp_list = CodePointInversionList::try_from_u32_inversion_list_slice(cp_slice).unwrap(); - let str_slice = &["xyz", "abc"]; - let str_list = VarZeroVec::<str>::from(str_slice); - - let cpilsl = CodePointInversionListAndStringList::try_from(cp_list, str_list); - - assert!(matches!( - cpilsl, - Err(InvalidStringList::StringListNotSorted(_, _)) - )); - } - - #[test] - fn test_from_iter_invariants() { - let in_strs_1 = ["a", "abc", "xyz", "abc"]; - let in_strs_2 = ["xyz", "abc", "a", "abc"]; - - let cpilsl_1 = CodePointInversionListAndStringList::from_iter(in_strs_1); - let cpilsl_2 = CodePointInversionListAndStringList::from_iter(in_strs_2); - - assert_eq!(cpilsl_1, cpilsl_2); - - assert!(cpilsl_1.has_strings()); - assert!(cpilsl_1.contains_str("abc")); - assert!(cpilsl_1.contains_str("xyz")); - assert!(!cpilsl_1.contains_str("def")); - - assert_eq!(1, cpilsl_1.cp_inv_list.size()); - assert!(cpilsl_1.contains('a')); - assert!(!cpilsl_1.contains('0')); - assert!(!cpilsl_1.contains('q')); - - assert_eq!(3, cpilsl_1.size()); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/cptrie.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/cptrie.rs deleted file mode 100644 index 086d936e2b57..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/cptrie.rs +++ /dev/null @@ -1,1897 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use crate::codepointtrie::error::Error; -use crate::codepointtrie::impl_const::*; - -#[cfg(feature = "alloc")] -use crate::codepointinvlist::CodePointInversionList; -use core::char::CharTryFromError; -use core::convert::Infallible; -use core::convert::TryFrom; -use core::fmt::Display; -#[cfg(feature = "alloc")] -use core::iter::FromIterator; -use core::num::TryFromIntError; -use core::ops::RangeInclusive; -use yoke::Yokeable; -use zerofrom::ZeroFrom; -use zerovec::ule::AsULE; -#[cfg(feature = "alloc")] -use zerovec::ule::UleError; -use zerovec::ZeroSlice; -use zerovec::ZeroVec; - -/// The type of trie represents whether the trie has an optimization that -/// would make it smaller or faster. -/// -/// Regarding performance, a trie being a small or fast type affects the number of array lookups -/// needed for code points in the range `[0x1000, 0x10000)`. In this range, `Small` tries use 4 array lookups, -/// while `Fast` tries use 2 array lookups. -/// Code points before the interval (in `[0, 0x1000)`) will always use 2 array lookups. -/// Code points after the interval (in `[0x10000, 0x10FFFF]`) will always use 4 array lookups. -/// -/// Regarding size, `Fast` type tries are larger than `Small` type tries because the minimum size of -/// the index array is larger. The minimum size is the "fast max" limit, which is the limit of the range -/// of code points with 2 array lookups. -/// -/// See the document [Unicode Properties and Code Point Tries in ICU4X](https://github.com/unicode-org/icu4x/blob/main/documents/design/properties_code_point_trie.md). -/// -/// Also see [`UCPTrieType`](https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/ucptrie_8h.html) in ICU4C. -#[derive(Clone, Copy, PartialEq, Debug, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "databake", derive(databake::Bake))] -#[cfg_attr(feature = "databake", databake(path = icu_collections::codepointtrie))] -#[allow(clippy::exhaustive_enums)] // based on a stable serialized form -pub enum TrieType { - /// Represents the "fast" type code point tries for the - /// [`TrieType`] trait. The "fast max" limit is set to `0xffff`. - Fast = 0, - /// Represents the "small" type code point tries for the - /// [`TrieType`] trait. The "fast max" limit is set to `0x0fff`. - Small = 1, -} - -// TrieValue trait - -// AsULE is AsUnalignedLittleEndian, i.e. "allowed in a zerovec" - -/// A trait representing the values stored in the data array of a [`CodePointTrie`]. -/// This trait is used as a type parameter in constructing a `CodePointTrie`. -/// -/// This trait can be implemented on anything that can be represented as a u32s worth of data. -pub trait TrieValue: Copy + Eq + PartialEq + AsULE + 'static { - /// Last-resort fallback value to return if we cannot read data from the trie. - /// - /// In most cases, the error value is read from the last element of the `data` array, - /// this value is used for empty codepointtrie arrays - /// Error type when converting from a u32 to this `TrieValue`. - type TryFromU32Error: Display; - /// A parsing function that is primarily motivated by deserialization contexts. - /// When the serialization type width is smaller than 32 bits, then it is expected - /// that the call site will widen the value to a `u32` first. - fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error>; - - /// A method for converting back to a `u32` that can roundtrip through - /// [`Self::try_from_u32()`]. The default implementation of this trait - /// method panics in debug mode and returns 0 in release mode. - /// - /// This method is allowed to have GIGO behavior when fed a value that has - /// no corresponding `u32` (since such values cannot be stored in the trie) - fn to_u32(self) -> u32; -} - -macro_rules! impl_primitive_trie_value { - ($primitive:ty, $error:ty) => { - impl TrieValue for $primitive { - type TryFromU32Error = $error; - fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> { - Self::try_from(i) - } - - #[allow(trivial_numeric_casts)] - fn to_u32(self) -> u32 { - // bitcast when the same size, zero-extend/sign-extend - // when not the same size - self as u32 - } - } - }; -} - -impl_primitive_trie_value!(u8, TryFromIntError); -impl_primitive_trie_value!(u16, TryFromIntError); -impl_primitive_trie_value!(u32, Infallible); -impl_primitive_trie_value!(i8, TryFromIntError); -impl_primitive_trie_value!(i16, TryFromIntError); -impl_primitive_trie_value!(i32, TryFromIntError); -impl_primitive_trie_value!(char, CharTryFromError); - -/// Helper function used by [`get_range`]. Converts occurrences of trie's null -/// value into the provided `null_value`. -/// -/// Note: the ICU version of this helper function uses a `ValueFilter` function -/// to apply a transform on a non-null value. But currently, this implementation -/// stops short of that functionality, and instead leaves the non-null trie value -/// untouched. This is equivalent to having a `ValueFilter` function that is the -/// identity function. -fn maybe_filter_value<T: TrieValue>(value: T, trie_null_value: T, null_value: T) -> T { - if value == trie_null_value { - null_value - } else { - value - } -} - -/// This struct represents a de-serialized [`CodePointTrie`] that was exported from -/// ICU binary data. -/// -/// For more information: -/// - [ICU Site design doc](https://unicode-org.github.io/icu/design/struct/utrie) -/// - [ICU User Guide section on Properties lookup](https://unicode-org.github.io/icu/userguide/strings/properties.html#lookup) -// serde impls in crate::serde -#[derive(Debug, Eq, PartialEq, Yokeable, ZeroFrom)] -pub struct CodePointTrie<'trie, T: TrieValue> { - /// # Safety Invariant - /// - /// The value of `header.trie_type` must not change after construction. - pub(crate) header: CodePointTrieHeader, - /// # Safety Invariant - /// - /// If `header.trie_type == TrieType::Fast`, `index.len()` must be greater - /// than `FAST_TYPE_FAST_INDEXING_MAX`. Otherwise, `index.len()` - /// must be greater than `SMALL_TYPE_FAST_INDEXING_MAX`. Furthermore, - /// this field must not change after construction. (Strictly: It must - /// not become shorter than the length requirement stated above and the - /// values within the prefix up to the length requirement must not change.) - pub(crate) index: ZeroVec<'trie, u16>, - /// # Safety Invariant - /// - /// If `header.trie_type == TrieType::Fast`, `data.len()` must be greater - /// than `FAST_TYPE_DATA_MASK` plus the largest value in - /// `index[0..FAST_TYPE_FAST_INDEXING_MAX + 1]`. Otherwise, `data.len()` - /// must be greater than `FAST_TYPE_DATA_MASK` plus the largest value in - /// `index[0..SMALL_TYPE_FAST_INDEXING_MAX + 1]`. Furthermore, this field - /// must not change after construction. (Strictly: The stated length - /// requirement must continue to hold.) - pub(crate) data: ZeroVec<'trie, T>, - // serde impl skips this field - #[zerofrom(clone)] // TrieValue is Copy, this allows us to avoid - // a T: ZeroFrom bound - pub(crate) error_value: T, -} - -/// This struct contains the fixed-length header fields of a [`CodePointTrie`]. -/// -/// # Safety Invariant -/// -/// The `trie_type` field must not change after construction. -/// -/// (In practice, all the fields here remain unchanged during the lifetime -/// of the trie.) -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "databake", derive(databake::Bake))] -#[cfg_attr(feature = "databake", databake(path = icu_collections::codepointtrie))] -#[derive(Copy, Clone, Debug, Eq, PartialEq, Yokeable, ZeroFrom)] -#[allow(clippy::exhaustive_structs)] // based on a stable serialized form -pub struct CodePointTrieHeader { - /// The code point of the start of the last range of the trie. A - /// range is defined as a partition of the code point space such that the - /// value in this trie associated with all code points of the same range is - /// the same. - /// - /// For the property value data for many Unicode properties, - /// often times, `high_start` is `U+10000` or lower. In such cases, not - /// reserving space in the `index` array for duplicate values is a large - /// savings. The "highValue" associated with the `high_start` range is - /// stored at the second-to-last position of the `data` array. - /// (See `impl_const::HIGH_VALUE_NEG_DATA_OFFSET`.) - pub high_start: u32, - /// A version of the `high_start` value that is right-shifted 12 spaces, - /// but is rounded up to a multiple `0x1000` for easy testing from UTF-8 - /// lead bytes. - pub shifted12_high_start: u16, - /// Offset for the null block in the "index-3" table of the `index` array. - /// Set to an impossibly high value (e.g., `0xffff`) if there is no - /// dedicated index-3 null block. - pub index3_null_offset: u16, - /// Internal data null block offset, not shifted. - /// Set to an impossibly high value (e.g., `0xfffff`) if there is no - /// dedicated data null block. - pub data_null_offset: u32, - /// The value stored in the trie that represents a null value being - /// associated to a code point. - pub null_value: u32, - /// The enum value representing the type of trie, where trie type is as it - /// is defined in ICU (ex: Fast, Small). - /// - /// # Safety Invariant - /// - /// Must not change after construction. - pub trie_type: TrieType, -} - -impl TryFrom<u8> for TrieType { - type Error = Error; - - fn try_from(trie_type_int: u8) -> Result<TrieType, Error> { - match trie_type_int { - 0 => Ok(TrieType::Fast), - 1 => Ok(TrieType::Small), - _ => Err(Error::FromDeserialized { - reason: "Cannot parse value for trie_type", - }), - } - } -} - -// Helper macro that turns arithmetic into wrapping-in-release, checked-in-debug arithmetic -// -// This is rustc's default behavior anyway, however some projects like Android deliberately -// enable overflow checks. CodePointTrie::get() is intended to be used in Android bionic which -// cares about codesize and we don't want the pile of panicking infrastructure brought in by overflow -// checks, so we force wrapping in release. -// See #6052 -macro_rules! w( - // Note: these matchers are not perfect since you cannot have an operator after an expr matcher - // Use variables if you need complex first operands. - ($a:tt + $b:expr) => { - { - #[allow(unused_parens)] - let a = $a; - let b = $b; - debug_assert!(a.checked_add(b).is_some()); - $a.wrapping_add($b) - } - }; - ($a:tt - $b:expr) => { - - { - #[allow(unused_parens)] - let a = $a; - let b = $b; - debug_assert!(a.checked_sub(b).is_some()); - $a.wrapping_sub($b) - } - }; - ($a:tt * $b:expr) => { - { - #[allow(unused_parens)] - let a = $a; - let b = $b; - debug_assert!(a.checked_mul(b).is_some()); - $a.wrapping_mul($b) - } - }; -); - -impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { - #[doc(hidden)] // databake internal - /// # Safety - /// - /// `header.trie_type`, `index`, and `data` must - /// satisfy the invariants for the fields of the - /// same names on `CodePointTrie`. - pub const unsafe fn from_parts_unstable_unchecked_v1( - header: CodePointTrieHeader, - index: ZeroVec<'trie, u16>, - data: ZeroVec<'trie, T>, - error_value: T, - ) -> Self { - // Field invariants upheld: The caller is responsible. - // In practice, this means that datagen in the databake - // mode upholds these invariants when constructing the - // `CodePointTrie` that is then baked. - Self { - header, - index, - data, - error_value, - } - } - - /// Returns a new [`CodePointTrie`] backed by borrowed data for the `index` - /// array and `data` array, whose data values have width `W`. - pub fn try_new( - header: CodePointTrieHeader, - index: ZeroVec<'trie, u16>, - data: ZeroVec<'trie, T>, - ) -> Result<CodePointTrie<'trie, T>, Error> { - let error_value = Self::validate_fields(&header, &index, &data)?; - // Field invariants upheld: Checked by `validate_fields` above. - let trie: CodePointTrie<'trie, T> = CodePointTrie { - header, - index, - data, - error_value, - }; - Ok(trie) - } - - /// Checks the invariant on the fields that fast-path access relies on for - /// safety in order to omit slice bound checks and upon success returns the - /// `error_value` for the trie. - /// - /// # Safety Usable Invariant - /// - /// Iff this function returns `Ok(T)`, the arguments satisfy the invariants - /// for corresponding fields of `CodePointTrie`. (Other than proving that - /// nothing else changes the fields subsequently.) - pub(crate) fn validate_fields( - header: &CodePointTrieHeader, - index: &ZeroSlice<u16>, - data: &ZeroSlice<T>, - ) -> Result<T, Error> { - let error_value = data.last().ok_or(Error::EmptyDataVector)?; - - // `CodePointTrie` lookup has two stages: fast and small (the trie types - // are also fast and small; they affect where the boundary between fast - // and small lookups is). - // - // The length requirements for `index` and `data` are checked here only - // for the fast lookup case so that the fast lookup can omit bound checks - // at the time of access. In the small lookup case, bounds are checked at - // the time of access. - // - // The fast lookup happens on the prefixes of `index` and `data` with - // more items for the small lookup case afterwards. The check here - // only looks at the prefixes relevant to the fast case. - // - // In the fast lookup case, the bits of the of the code point are - // partitioned into a bit prefix and a bit suffix. First, a value - // is read from `index` by indexing into it using the bit prefix. - // Then `data` is accessed by the value just read from `index` plus - // the bit suffix. - // - // Therefore, the length of `index` needs to accommodate access - // by the maximum possible bit prefix, and the length of `data` - // needs to accommodate access by the largest value stored in the part - // of `data` reachable by the bit prefix plus the maximum possible bit - // suffix. - // - // The maximum possible bit prefix depends on the trie type. - - // The maximum code point that can be used for fast-path access: - let fast_max = match header.trie_type { - TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, - TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, - }; - // Keep only the prefix bits: - let max_bit_prefix = fast_max >> FAST_TYPE_SHIFT; - // Attempt slice the part of `index` that the fast path can index into. - // Since `max_bit_prefix` is the largest possible value used for - // indexing (inclusive bound), we need to add one to get the exclusive - // bound, which is what `get_subslice` wants. - let fast_index = index - .get_subslice(0..(max_bit_prefix as usize) + 1) - .ok_or(Error::IndexTooShortForFastAccess)?; - // Invariant upheld for `index`: If we got this far, the length of `index` - // satisfies its length invariant on the assumption that `header.trie_type` - // will not change subsequently. - - // Now find the largest offset in the part of `index` reachable by the - // bit prefix. `max` can never actually return `None`, since we already - // know the slice isn't empty. Hence, reusing the error kind instead of - // minting a new one for this check. - let max_offset = fast_index - .iter() - .max() - .ok_or(Error::IndexTooShortForFastAccess)?; - // `FAST_TYPE_DATA_MASK` is the maximum possible bit suffix, since the - // maximum is when all the bits in the suffix are set, and the mask - // has that many bits set. - if (max_offset) as usize + (FAST_TYPE_DATA_MASK as usize) >= data.len() { - return Err(Error::DataTooShortForFastAccess); - } - - // Invariant upheld for `data`: If we got this far, the length of `data` - // satisfies `data`'s length invariant on the assumption that the contents - // of `fast_index` subslice of `index` and `header.trie_type` will not - // change subsequently. - - Ok(error_value) - } - - /// Turns this trie into a version whose trie type is encoded in the Rust type. - #[inline] - pub fn to_typed(self) -> Typed<FastCodePointTrie<'trie, T>, SmallCodePointTrie<'trie, T>> { - match self.header.trie_type { - TrieType::Fast => Typed::Fast(FastCodePointTrie { inner: self }), - TrieType::Small => Typed::Small(SmallCodePointTrie { inner: self }), - } - } - - /// Obtains a reference to this trie as a Rust type that encodes the trie type in the Rust type. - #[inline] - pub fn as_typed_ref( - &self, - ) -> Typed<&FastCodePointTrie<'trie, T>, &SmallCodePointTrie<'trie, T>> { - // SAFETY: `FastCodePointTrie` and `SmallCodePointTrie` are `repr(transparent)` - // with `CodePointTrie`, so transmuting between the references is OK when the - // actual trie type agrees with the semantics of the typed wrapper. - match self.header.trie_type { - TrieType::Fast => Typed::Fast(unsafe { - &*(self as *const CodePointTrie<'trie, T> as *const FastCodePointTrie<'trie, T>) - }), - TrieType::Small => Typed::Small(unsafe { - &*(self as *const CodePointTrie<'trie, T> as *const SmallCodePointTrie<'trie, T>) - }), - } - } - - /// Returns the position in the data array containing the trie's stored - /// error value. - #[inline(always)] // `always` was based on previous normalizer benchmarking - fn trie_error_val_index(&self) -> u32 { - // We use wrapping_sub here to avoid panicky overflow checks. - // len should always be > 1, but if it isn't this will just cause GIGO behavior of producing - // None on `.get()` - debug_assert!(self.data.len() as u32 >= ERROR_VALUE_NEG_DATA_OFFSET); - w!((self.data.len() as u32) - ERROR_VALUE_NEG_DATA_OFFSET) - } - - fn internal_small_index(&self, code_point: u32) -> u32 { - // We use wrapping arithmetic here to avoid overflow checks making their way into binaries - // with overflow checks enabled. Ultimately this code ends up as a checked index, so any - // bugs here will cause GIGO - let mut index1_pos: u32 = code_point >> SHIFT_1; - if self.header.trie_type == TrieType::Fast { - debug_assert!( - FAST_TYPE_FAST_INDEXING_MAX < code_point && code_point < self.header.high_start - ); - index1_pos = w!(index1_pos + BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH); - } else { - assert!(code_point < self.header.high_start && self.header.high_start > SMALL_LIMIT); - index1_pos = w!(index1_pos + SMALL_INDEX_LENGTH); - } - let index1_val = if let Some(index1_val) = self.index.get(index1_pos as usize) { - index1_val - } else { - return self.trie_error_val_index(); - }; - let index3_block_idx: u32 = - w!((index1_val as u32) + (code_point >> SHIFT_2) & INDEX_2_MASK); - let mut index3_block: u32 = - if let Some(index3_block) = self.index.get(index3_block_idx as usize) { - index3_block as u32 - } else { - return self.trie_error_val_index(); - }; - let mut index3_pos: u32 = (code_point >> SHIFT_3) & INDEX_3_MASK; - let mut data_block: u32; - if index3_block & 0x8000 == 0 { - // 16-bit indexes - data_block = - if let Some(data_block) = self.index.get(w!(index3_block + index3_pos) as usize) { - data_block as u32 - } else { - return self.trie_error_val_index(); - }; - } else { - // 18-bit indexes stored in groups of 9 entries per 8 indexes. - index3_block = w!((index3_block & 0x7fff) + w!((index3_pos & !7) + index3_pos >> 3)); - index3_pos &= 7; - data_block = if let Some(data_block) = self.index.get(index3_block as usize) { - data_block as u32 - } else { - return self.trie_error_val_index(); - }; - data_block = (data_block << w!(2u32 + w!(2u32 * index3_pos))) & 0x30000; - index3_block += 1; - data_block = - if let Some(index3_val) = self.index.get(w!(index3_block + index3_pos) as usize) { - data_block | (index3_val as u32) - } else { - return self.trie_error_val_index(); - }; - } - // Returns data_pos == data_block (offset) + - // portion of code_point bit field for last (4th) lookup - w!(data_block + code_point & SMALL_DATA_MASK) - } - - /// Returns the position in the `data` array for the given code point, - /// where this code point is at or above the fast limit associated for the - /// `trie_type`. We will refer to that limit as "`fastMax`" here. - /// - /// A lookup of the value in the code point trie for a code point in the - /// code point space range [`fastMax`, `high_start`) will be a 4-step - /// lookup: 3 lookups in the `index` array and one lookup in the `data` - /// array. Lookups for code points in the range [`high_start`, - /// `CODE_POINT_MAX`] are short-circuited to be a single lookup, see - /// [`CodePointTrieHeader::high_start`]. - fn small_index(&self, code_point: u32) -> u32 { - if code_point >= self.header.high_start { - w!((self.data.len() as u32) - HIGH_VALUE_NEG_DATA_OFFSET) - } else { - self.internal_small_index(code_point) // helper fn - } - } - - /// Returns the position in the `data` array for the given code point, - /// where this code point is below the fast limit associated for the - /// `trie type`. We will refer to that limit as "`fastMax`" here. - /// - /// A lookup of the value in the code point trie for a code point in the - /// code point space range [0, `fastMax`) will be a 2-step lookup: 1 - /// lookup in the `index` array and one lookup in the `data` array. By - /// design, for trie type `T`, there is an element allocated in the `index` - /// array for each block of code points in [0, `fastMax`), which in - /// turn guarantees that those code points are represented and only need 1 - /// lookup. - fn fast_index(&self, code_point: u32) -> u32 { - let index_array_pos: u32 = code_point >> FAST_TYPE_SHIFT; - let index_array_val: u16 = - if let Some(index_array_val) = self.index.get(index_array_pos as usize) { - index_array_val - } else { - return self.trie_error_val_index(); - }; - let masked_cp = code_point & FAST_TYPE_DATA_MASK; - let index_array_val = index_array_val as u32; - let fast_index_val: u32 = w!(index_array_val + masked_cp); - fast_index_val - } - - /// Returns the value that is associated with `code_point` in this [`CodePointTrie`] - /// if `code_point` uses fast-path lookup or `None` if `code_point` - /// should use small-path lookup or is above the supported range. - #[inline(always)] // "always" to make the `Option` collapse away - fn get32_by_fast_index(&self, code_point: u32) -> Option<T> { - let fast_max = match self.header.trie_type { - TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, - TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, - }; - if code_point <= fast_max { - // SAFETY: We just checked the invariant of - // `get32_assuming_fast_index`, - // which is - // "If `self.header.trie_type == TrieType::Small`, `code_point` must be at most - // `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == - // TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`." - Some(unsafe { self.get32_assuming_fast_index(code_point) }) - } else { - // The caller needs to call `get32_by_small_index` or determine - // that the argument is above the permitted range. - None - } - } - - /// Performs the actual fast-mode lookup - /// - /// # Safety - /// - /// If `self.header.trie_type == TrieType::Small`, `code_point` must be at most - /// `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == - /// TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`. - #[inline(always)] - unsafe fn get32_assuming_fast_index(&self, code_point: u32) -> T { - // Check the safety invariant of this method. - debug_assert!( - code_point - <= match self.header.trie_type { - TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, - TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, - } - ); - - let bit_prefix = (code_point as usize) >> FAST_TYPE_SHIFT; - debug_assert!(bit_prefix < self.index.len()); - // SAFETY: Relying on the length invariant of `self.index` having - // been checked and on the unchangedness invariant of `self.index` - // and `self.header.trie_type` after construction. - let base_offset_to_data: usize = usize::from(u16::from_unaligned(*unsafe { - self.index.as_ule_slice().get_unchecked(bit_prefix) - })); - let bit_suffix = (code_point & FAST_TYPE_DATA_MASK) as usize; - // SAFETY: Cannot overflow with supported (32-bit and 64-bit) `usize` - // sizes, since `base_offset_to_data` was extended from `u16` and - // `bit_suffix` is at most `FAST_TYPE_DATA_MASK`, which is well - // under what it takes to reach the 32-bit (or 64-bit) max with - // additon from the max of `u16`. - let offset_to_data = w!(base_offset_to_data + bit_suffix); - debug_assert!(offset_to_data < self.data.len()); - // SAFETY: Relying on the length invariant of `self.data` having - // been checked and on the unchangedness invariant of `self.data`, - // `self.index`, and `self.header.trie_type` after construction. - T::from_unaligned(*unsafe { self.data.as_ule_slice().get_unchecked(offset_to_data) }) - } - - /// Coldness wrapper for `get32_by_small_index` to also allow - /// calls without the effects of `#[cold]`. - #[cold] - #[inline(always)] - fn get32_by_small_index_cold(&self, code_point: u32) -> T { - self.get32_by_small_index(code_point) - } - - /// Returns the value that is associated with `code_point` in this [`CodePointTrie`] - /// assuming that the small index path should be used. - /// - /// # Intended Precondition - /// - /// `code_point` must be at most `CODE_POINT_MAX` AND greter than - /// `FAST_TYPE_FAST_INDEXING_MAX` if the trie type is fast or greater - /// than `SMALL_TYPE_FAST_INDEXING_MAX` if the trie type is small. - /// This is checked when debug assertions are enabled. If this - /// precondition is violated, the behavior of this method is - /// memory-safe, but the returned value may be bogus (not - /// necessarily the designated error value). - #[inline(never)] - fn get32_by_small_index(&self, code_point: u32) -> T { - debug_assert!(code_point <= CODE_POINT_MAX); - debug_assert!( - code_point - > match self.header.trie_type { - TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, - TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, - } - ); - self.data - .get(self.small_index(code_point) as usize) - .unwrap_or(self.error_value) - } - - /// Returns the value that is associated with `code_point` in this [`CodePointTrie`]. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// let trie = planes::get_planes_trie(); - /// - /// assert_eq!(0, trie.get32(0x41)); // 'A' as u32 - /// assert_eq!(0, trie.get32(0x13E0)); // 'Ꮰ' as u32 - /// assert_eq!(1, trie.get32(0x10044)); // '𐁄' as u32 - /// ``` - #[inline(always)] // `always` based on normalizer benchmarking - pub fn get32(&self, code_point: u32) -> T { - if let Some(v) = self.get32_by_fast_index(code_point) { - v - } else if code_point <= CODE_POINT_MAX { - self.get32_by_small_index_cold(code_point) - } else { - self.error_value - } - } - - /// Returns the value that is associated with `char` in this [`CodePointTrie`]. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// let trie = planes::get_planes_trie(); - /// - /// assert_eq!(0, trie.get('A')); // 'A' as u32 - /// assert_eq!(0, trie.get('Ꮰ')); // 'Ꮰ' as u32 - /// assert_eq!(1, trie.get('𐁄')); // '𐁄' as u32 - /// ``` - #[inline(always)] - pub fn get(&self, c: char) -> T { - // LLVM's optimizations have been observed not to be 100% - // reliable around collapsing away unnecessary parts of - // `get32`, so not just calling `get32` here. - let code_point = u32::from(c); - if let Some(v) = self.get32_by_fast_index(code_point) { - v - } else { - self.get32_by_small_index_cold(code_point) - } - } - - /// Returns the value that is associated with `bmp` in this [`CodePointTrie`]. - #[inline(always)] - pub fn get16(&self, bmp: u16) -> T { - // LLVM's optimizations have been observed not to be 100% - // reliable around collapsing away unnecessary parts of - // `get32`, so not just calling `get32` here. - let code_point = u32::from(bmp); - if let Some(v) = self.get32_by_fast_index(code_point) { - v - } else { - self.get32_by_small_index_cold(code_point) - } - } - - /// Lookup trie value by non-Basic Multilingual Plane Scalar Value. - /// - /// The return value may be bogus (not necessarily `error_value`) is the argument is actually in - /// the Basic Multilingual Plane or above the Unicode Scalar Value - /// range (panics instead with debug assertions enabled). - #[inline(always)] - pub fn get32_supplementary(&self, supplementary: u32) -> T { - debug_assert!(supplementary > 0xFFFF); - debug_assert!(supplementary <= CODE_POINT_MAX); - self.get32_by_small_index(supplementary) - } - - /// Returns a reference to the ULE of the value that is associated with `code_point` in this [`CodePointTrie`]. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// let trie = planes::get_planes_trie(); - /// - /// assert_eq!(Some(&0), trie.get32_ule(0x41)); // 'A' as u32 - /// assert_eq!(Some(&0), trie.get32_ule(0x13E0)); // 'Ꮰ' as u32 - /// assert_eq!(Some(&1), trie.get32_ule(0x10044)); // '𐁄' as u32 - /// ``` - #[inline(always)] // `always` was based on previous normalizer benchmarking - pub fn get32_ule(&self, code_point: u32) -> Option<&T::ULE> { - // All code points up to the fast max limit are represented - // individually in the `index` array to hold their `data` array position, and - // thus only need 2 lookups for a [CodePointTrie::get()](`crate::codepointtrie::CodePointTrie::get`). - // Code points above the "fast max" limit require 4 lookups. - let fast_max = match self.header.trie_type { - TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, - TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, - }; - let data_pos: u32 = if code_point <= fast_max { - Self::fast_index(self, code_point) - } else if code_point <= CODE_POINT_MAX { - Self::small_index(self, code_point) - } else { - self.trie_error_val_index() - }; - // Returns the trie value (or trie's error value). - self.data.as_ule_slice().get(data_pos as usize) - } - - /// Converts the [`CodePointTrie`] into one that returns another type of the same size. - /// - /// Borrowed data remains borrowed, and owned data remains owned. - /// - /// If the old and new types are not the same size, use - /// [`CodePointTrie::try_alloc_map_value`]. - /// - /// # Panics - /// - /// Panics if `T` and `P` are different sizes. - /// - /// More specifically, panics if [`ZeroVec::try_into_converted()`] panics when converting - /// `ZeroVec<T>` into `ZeroVec<P>`, which happens if `T::ULE` and `P::ULE` differ in size. - /// - /// ✨ *Enabled with the `alloc` Cargo feature.* - /// - /// # Examples - /// - /// ```no_run - /// use icu::collections::codepointtrie::planes; - /// use icu::collections::codepointtrie::CodePointTrie; - /// - /// let planes_trie_u8: CodePointTrie<u8> = planes::get_planes_trie(); - /// let planes_trie_i8: CodePointTrie<i8> = - /// planes_trie_u8.try_into_converted().expect("infallible"); - /// - /// assert_eq!(planes_trie_i8.get32(0x30000), 3); - /// ``` - #[cfg(feature = "alloc")] - pub fn try_into_converted<P>(self) -> Result<CodePointTrie<'trie, P>, UleError> - where - P: TrieValue, - { - let converted_data = self.data.try_into_converted()?; - let error_ule = self.error_value.to_unaligned(); - let slice = &[error_ule]; - let error_vec = ZeroVec::<T>::new_borrowed(slice); - let error_converted = error_vec.try_into_converted::<P>()?; - #[expect(clippy::expect_used)] // we know this cannot fail - Ok(CodePointTrie { - header: self.header, - index: self.index, - data: converted_data, - error_value: error_converted - .get(0) - .expect("vector known to have one element"), - }) - } - - /// Maps the [`CodePointTrie`] into one that returns a different type. - /// - /// This function returns owned data. - /// - /// If the old and new types are the same size, use the more efficient - /// [`CodePointTrie::try_into_converted`]. - /// - /// ✨ *Enabled with the `alloc` Cargo feature.* - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// use icu::collections::codepointtrie::CodePointTrie; - /// - /// let planes_trie_u8: CodePointTrie<u8> = planes::get_planes_trie(); - /// let planes_trie_u16: CodePointTrie<u16> = planes_trie_u8 - /// .try_alloc_map_value(TryFrom::try_from) - /// .expect("infallible"); - /// - /// assert_eq!(planes_trie_u16.get32(0x30000), 3); - /// ``` - #[cfg(feature = "alloc")] - pub fn try_alloc_map_value<P, E>( - &self, - mut f: impl FnMut(T) -> Result<P, E>, - ) -> Result<CodePointTrie<'trie, P>, E> - where - P: TrieValue, - { - let error_converted = f(self.error_value)?; - let converted_data = self.data.iter().map(f).collect::<Result<ZeroVec<P>, E>>()?; - Ok(CodePointTrie { - header: self.header, - index: self.index.clone(), - data: converted_data, - error_value: error_converted, - }) - } - - /// Returns a [`CodePointMapRange`] struct which represents a range of code - /// points associated with the same trie value. The returned range will be - /// the longest stretch of consecutive code points starting at `start` that - /// share this value. - /// - /// This method is designed to use the internal details of - /// the structure of [`CodePointTrie`] to be optimally efficient. This will - /// outperform a naive approach that just uses [`CodePointTrie::get()`]. - /// - /// This method provides lower-level functionality that can be used in the - /// implementation of other methods that are more convenient to the user. - /// To obtain an optimal partition of the code point space for - /// this trie resulting in the fewest number of ranges, see - /// [`CodePointTrie::iter_ranges()`]. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// - /// let trie = planes::get_planes_trie(); - /// - /// const CODE_POINT_MAX: u32 = 0x10ffff; - /// let start = 0x1_0000; - /// let exp_end = 0x1_ffff; - /// - /// let start_val = trie.get32(start); - /// assert_eq!(trie.get32(exp_end), start_val); - /// assert_ne!(trie.get32(exp_end + 1), start_val); - /// - /// use icu::collections::codepointtrie::CodePointMapRange; - /// - /// let cpm_range: CodePointMapRange<u8> = trie.get_range(start).unwrap(); - /// - /// assert_eq!(cpm_range.range.start(), &start); - /// assert_eq!(cpm_range.range.end(), &exp_end); - /// assert_eq!(cpm_range.value, start_val); - /// - /// // `start` can be any code point, whether or not it lies on the boundary - /// // of a maximally large range that still contains `start` - /// - /// let submaximal_1_start = start + 0x1234; - /// let submaximal_1 = trie.get_range(submaximal_1_start).unwrap(); - /// assert_eq!(submaximal_1.range.start(), &0x1_1234); - /// assert_eq!(submaximal_1.range.end(), &0x1_ffff); - /// assert_eq!(submaximal_1.value, start_val); - /// - /// let submaximal_2_start = start + 0xffff; - /// let submaximal_2 = trie.get_range(submaximal_2_start).unwrap(); - /// assert_eq!(submaximal_2.range.start(), &0x1_ffff); - /// assert_eq!(submaximal_2.range.end(), &0x1_ffff); - /// assert_eq!(submaximal_2.value, start_val); - /// ``` - pub fn get_range(&self, start: u32) -> Option<CodePointMapRange<T>> { - // Exit early if the start code point is out of range, or if it is - // in the last range of code points in high_start..=CODE_POINT_MAX - // (start- and end-inclusive) that all share the same trie value. - if CODE_POINT_MAX < start { - return None; - } - if start >= self.header.high_start { - let di: usize = self.data.len() - (HIGH_VALUE_NEG_DATA_OFFSET as usize); - let value: T = self.data.get(di)?; - return Some(CodePointMapRange { - range: start..=CODE_POINT_MAX, - value, - }); - } - - let null_value: T = T::try_from_u32(self.header.null_value).ok()?; - - let mut prev_i3_block: u32 = u32::MAX; // using u32::MAX (instead of -1 as an i32 in ICU) - let mut prev_block: u32 = u32::MAX; // using u32::MAX (instead of -1 as an i32 in ICU) - let mut c: u32 = start; - let mut trie_value: T = self.error_value(); - let mut value: T = self.error_value(); - let mut have_value: bool = false; - - loop { - let i3_block: u32; - let mut i3: u32; - let i3_block_length: u32; - let data_block_length: u32; - - // Initialize values before beginning the iteration in the subsequent - // `loop` block. In particular, use the "i3*" local variables - // (representing the `index` array position's offset + increment - // for a 3rd-level trie lookup) to help initialize the data block - // variable `block` in the loop for the `data` array. - // - // When a lookup code point is <= the trie's *_FAST_INDEXING_MAX that - // corresponds to its `trie_type`, the lookup only takes 2 steps - // (once into the `index`, once into the `data` array); otherwise, - // takes 4 steps (3 iterative lookups into the `index`, once more - // into the `data` array). So for convenience's sake, when we have the - // 2-stage lookup, reuse the "i3*" variable names for the first lookup. - if c <= 0xffff - && (self.header.trie_type == TrieType::Fast || c <= SMALL_TYPE_FAST_INDEXING_MAX) - { - i3_block = 0; - i3 = c >> FAST_TYPE_SHIFT; - i3_block_length = if self.header.trie_type == TrieType::Fast { - BMP_INDEX_LENGTH - } else { - SMALL_INDEX_LENGTH - }; - data_block_length = FAST_TYPE_DATA_BLOCK_LENGTH; - } else { - // Use the multi-stage index. - let mut i1: u32 = c >> SHIFT_1; - if self.header.trie_type == TrieType::Fast { - debug_assert!(0xffff < c && c < self.header.high_start); - i1 = i1 + BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; - } else { - debug_assert!( - c < self.header.high_start && self.header.high_start > SMALL_LIMIT - ); - i1 += SMALL_INDEX_LENGTH; - } - let i2: u16 = self.index.get(i1 as usize)?; - let i3_block_idx: u32 = (i2 as u32) + ((c >> SHIFT_2) & INDEX_2_MASK); - i3_block = if let Some(i3b) = self.index.get(i3_block_idx as usize) { - i3b as u32 - } else { - return None; - }; - if i3_block == prev_i3_block && (c - start) >= CP_PER_INDEX_2_ENTRY { - // The index-3 block is the same as the previous one, and filled with value. - debug_assert!((c & (CP_PER_INDEX_2_ENTRY - 1)) == 0); - c += CP_PER_INDEX_2_ENTRY; - - if c >= self.header.high_start { - break; - } else { - continue; - } - } - prev_i3_block = i3_block; - if i3_block == self.header.index3_null_offset as u32 { - // This is the index-3 null block. - // All of the `data` array blocks pointed to by the values - // in this block of the `index` 3rd-stage subarray will - // contain this trie's null_value. So if we are in the middle - // of a range, end it and return early, otherwise start a new - // range of null values. - if have_value { - if null_value != value { - return Some(CodePointMapRange { - range: start..=(c - 1), - value, - }); - } - } else { - trie_value = T::try_from_u32(self.header.null_value).ok()?; - value = null_value; - have_value = true; - } - prev_block = self.header.data_null_offset; - c = (c + CP_PER_INDEX_2_ENTRY) & !(CP_PER_INDEX_2_ENTRY - 1); - - if c >= self.header.high_start { - break; - } else { - continue; - } - } - i3 = (c >> SHIFT_3) & INDEX_3_MASK; - i3_block_length = INDEX_3_BLOCK_LENGTH; - data_block_length = SMALL_DATA_BLOCK_LENGTH; - } - - // Enumerate data blocks for one index-3 block. - loop { - let mut block: u32; - if (i3_block & 0x8000) == 0 { - block = if let Some(b) = self.index.get((i3_block + i3) as usize) { - b as u32 - } else { - return None; - }; - } else { - // 18-bit indexes stored in groups of 9 entries per 8 indexes. - let mut group: u32 = (i3_block & 0x7fff) + (i3 & !7) + (i3 >> 3); - let gi: u32 = i3 & 7; - let gi_val: u32 = if let Some(giv) = self.index.get(group as usize) { - giv.into() - } else { - return None; - }; - block = (gi_val << (2 + (2 * gi))) & 0x30000; - group += 1; - let ggi_val: u32 = if let Some(ggiv) = self.index.get((group + gi) as usize) { - ggiv as u32 - } else { - return None; - }; - block |= ggi_val; - } - - // If our previous and current return values of the 3rd-stage `index` - // lookup yield the same `data` block offset, and if we already know that - // the entire `data` block / subarray starting at that offset stores - // `value` and nothing else, then we can extend our range by the length - // of a data block and continue. - // Otherwise, we have to iterate over the values stored in the - // new data block to see if they differ from `value`. - if block == prev_block && (c - start) >= data_block_length { - // The block is the same as the previous one, and filled with value. - debug_assert!((c & (data_block_length - 1)) == 0); - c += data_block_length; - } else { - let data_mask: u32 = data_block_length - 1; - prev_block = block; - if block == self.header.data_null_offset { - // This is the data null block. - // If we are in the middle of a range, end it and - // return early, otherwise start a new range of null - // values. - if have_value { - if null_value != value { - return Some(CodePointMapRange { - range: start..=(c - 1), - value, - }); - } - } else { - trie_value = T::try_from_u32(self.header.null_value).ok()?; - value = null_value; - have_value = true; - } - c = (c + data_block_length) & !data_mask; - } else { - let mut di: u32 = block + (c & data_mask); - let mut trie_value_2: T = self.data.get(di as usize)?; - if have_value { - if trie_value_2 != trie_value { - if maybe_filter_value( - trie_value_2, - T::try_from_u32(self.header.null_value).ok()?, - null_value, - ) != value - { - return Some(CodePointMapRange { - range: start..=(c - 1), - value, - }); - } - // `trie_value` stores the previous value that was retrieved - // from the trie. - // `value` stores the value associated for the range (return - // value) that we are currently building, which is computed - // as a transformation by applying maybe_filter_value() - // to the trie value. - // The current trie value `trie_value_2` within this data block - // differs here from the previous value in `trie_value`. - // But both map to `value` after applying `maybe_filter_value`. - // It is not clear whether the previous or the current trie value - // (or neither) is more likely to match potential subsequent trie - // values that would extend the range by mapping to `value`. - // On the assumption of locality -- often times consecutive - // characters map to the same trie values -- remembering the new - // one might make it faster to extend this range further - // (by increasing the chance that the next `trie_value_2 != - // trie_value` test will be false). - trie_value = trie_value_2; // may or may not help - } - } else { - trie_value = trie_value_2; - value = maybe_filter_value( - trie_value_2, - T::try_from_u32(self.header.null_value).ok()?, - null_value, - ); - have_value = true; - } - - c += 1; - while (c & data_mask) != 0 { - di += 1; - trie_value_2 = self.data.get(di as usize)?; - if trie_value_2 != trie_value { - if maybe_filter_value( - trie_value_2, - T::try_from_u32(self.header.null_value).ok()?, - null_value, - ) != value - { - return Some(CodePointMapRange { - range: start..=(c - 1), - value, - }); - } - // `trie_value` stores the previous value that was retrieved - // from the trie. - // `value` stores the value associated for the range (return - // value) that we are currently building, which is computed - // as a transformation by applying maybe_filter_value() - // to the trie value. - // The current trie value `trie_value_2` within this data block - // differs here from the previous value in `trie_value`. - // But both map to `value` after applying `maybe_filter_value`. - // It is not clear whether the previous or the current trie value - // (or neither) is more likely to match potential subsequent trie - // values that would extend the range by mapping to `value`. - // On the assumption of locality -- often times consecutive - // characters map to the same trie values -- remembering the new - // one might make it faster to extend this range further - // (by increasing the chance that the next `trie_value_2 != - // trie_value` test will be false). - trie_value = trie_value_2; // may or may not help - } - - c += 1; - } - } - } - - i3 += 1; - if i3 >= i3_block_length { - break; - } - } - - if c >= self.header.high_start { - break; - } - } - - debug_assert!(have_value); - - // Now that c >= high_start, compare `value` to `high_value` to see - // if we can merge our current range with the high_value range - // high_start..=CODE_POINT_MAX (start- and end-inclusive), otherwise - // stop at high_start - 1. - let di: u32 = self.data.len() as u32 - HIGH_VALUE_NEG_DATA_OFFSET; - let high_value: T = self.data.get(di as usize)?; - if maybe_filter_value( - high_value, - T::try_from_u32(self.header.null_value).ok()?, - null_value, - ) != value - { - c -= 1; - } else { - c = CODE_POINT_MAX; - } - Some(CodePointMapRange { - range: start..=c, - value, - }) - } - - /// Yields an [`Iterator`] returning ranges of consecutive code points that - /// share the same value in the [`CodePointTrie`], as given by - /// [`CodePointTrie::get_range()`]. - /// - /// # Examples - /// - /// ``` - /// use core::ops::RangeInclusive; - /// use icu::collections::codepointtrie::planes; - /// use icu::collections::codepointtrie::CodePointMapRange; - /// - /// let planes_trie = planes::get_planes_trie(); - /// - /// let mut ranges = planes_trie.iter_ranges(); - /// - /// for plane in 0..=16 { - /// let exp_start = plane * 0x1_0000; - /// let exp_end = exp_start + 0xffff; - /// assert_eq!( - /// ranges.next(), - /// Some(CodePointMapRange { - /// range: exp_start..=exp_end, - /// value: plane as u8 - /// }) - /// ); - /// } - /// - /// // Hitting the end of the iterator returns `None`, as will subsequent - /// // calls to .next(). - /// assert_eq!(ranges.next(), None); - /// assert_eq!(ranges.next(), None); - /// ``` - pub fn iter_ranges(&self) -> CodePointMapRangeIterator<'_, T> { - let init_range = Some(CodePointMapRange { - range: u32::MAX..=u32::MAX, - value: self.error_value(), - }); - CodePointMapRangeIterator::<T> { - cpt: self, - cpm_range: init_range, - } - } - - /// Yields an [`Iterator`] returning the ranges of the code points whose values - /// match `value` in the [`CodePointTrie`]. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// - /// let trie = planes::get_planes_trie(); - /// - /// let plane_val = 2; - /// let mut sip_range_iter = trie.iter_ranges_for_value(plane_val as u8); - /// - /// let start = plane_val * 0x1_0000; - /// let end = start + 0xffff; - /// - /// let sip_range = sip_range_iter.next() - /// .expect("Plane 2 (SIP) should exist in planes data"); - /// assert_eq!(start..=end, sip_range); - /// - /// assert!(sip_range_iter.next().is_none()); - pub fn iter_ranges_for_value( - &self, - value: T, - ) -> impl Iterator<Item = RangeInclusive<u32>> + '_ { - self.iter_ranges() - .filter(move |cpm_range| cpm_range.value == value) - .map(|cpm_range| cpm_range.range) - } - - /// Yields an [`Iterator`] returning the ranges of the code points after passing - /// the value through a mapping function. - /// - /// This is preferable to calling `.get_ranges().map()` since it will coalesce - /// adjacent ranges into one. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// - /// let trie = planes::get_planes_trie(); - /// - /// let plane_val = 2; - /// let mut sip_range_iter = trie.iter_ranges_mapped(|value| value != plane_val as u8).filter(|range| range.value); - /// - /// let end = plane_val * 0x1_0000 - 1; - /// - /// let sip_range = sip_range_iter.next() - /// .expect("Complemented planes data should have at least one entry"); - /// assert_eq!(0..=end, sip_range.range); - pub fn iter_ranges_mapped<'a, U: Eq + 'a>( - &'a self, - mut map: impl FnMut(T) -> U + Copy + 'a, - ) -> impl Iterator<Item = CodePointMapRange<U>> + 'a { - crate::iterator_utils::RangeListIteratorCoalescer::new(self.iter_ranges().map( - move |range| CodePointMapRange { - range: range.range, - value: map(range.value), - }, - )) - } - - /// Returns a [`CodePointInversionList`] for the code points that have the given - /// [`TrieValue`] in the trie. - /// - /// ✨ *Enabled with the `alloc` Cargo feature.* - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// - /// let trie = planes::get_planes_trie(); - /// - /// let plane_val = 2; - /// let sip = trie.get_set_for_value(plane_val as u8); - /// - /// let start = plane_val * 0x1_0000; - /// let end = start + 0xffff; - /// - /// assert!(!sip.contains32(start - 1)); - /// assert!(sip.contains32(start)); - /// assert!(sip.contains32(end)); - /// assert!(!sip.contains32(end + 1)); - /// ``` - #[cfg(feature = "alloc")] - pub fn get_set_for_value(&self, value: T) -> CodePointInversionList<'static> { - let value_ranges = self.iter_ranges_for_value(value); - CodePointInversionList::from_iter(value_ranges) - } - - /// Returns the value used as an error value for this trie - #[inline] - pub fn error_value(&self) -> T { - self.error_value - } -} - -#[cfg(feature = "databake")] -impl<T: TrieValue + databake::Bake> databake::Bake for CodePointTrie<'_, T> { - fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream { - let header = self.header.bake(env); - let index = self.index.bake(env); - let data = self.data.bake(env); - let error_value = self.error_value.bake(env); - databake::quote! { unsafe { icu_collections::codepointtrie::CodePointTrie::from_parts_unstable_unchecked_v1(#header, #index, #data, #error_value) } } - } -} - -#[cfg(feature = "databake")] -impl<T: TrieValue + databake::Bake> databake::BakeSize for CodePointTrie<'_, T> { - fn borrows_size(&self) -> usize { - self.header.borrows_size() + self.index.borrows_size() + self.data.borrows_size() - } -} - -impl<T: TrieValue + Into<u32>> CodePointTrie<'_, T> { - /// Returns the value that is associated with `code_point` for this [`CodePointTrie`] - /// as a `u32`. - /// - /// # Examples - /// - /// ``` - /// use icu::collections::codepointtrie::planes; - /// let trie = planes::get_planes_trie(); - /// - /// let cp = '𑖎' as u32; - /// assert_eq!(cp, 0x1158E); - /// - /// let plane_num: u8 = trie.get32(cp); - /// assert_eq!(trie.get32_u32(cp), plane_num as u32); - /// ``` - // Note: This API method maintains consistency with the corresponding - // original ICU APIs. - pub fn get32_u32(&self, code_point: u32) -> u32 { - self.get32(code_point).into() - } -} - -impl<T: TrieValue> Clone for CodePointTrie<'_, T> -where - <T as AsULE>::ULE: Clone, -{ - fn clone(&self) -> Self { - CodePointTrie { - header: self.header, - index: self.index.clone(), - data: self.data.clone(), - error_value: self.error_value, - } - } -} - -/// Represents a range of consecutive code points sharing the same value in a -/// code point map. -/// -/// The start and end of the interval is represented as a -/// `RangeInclusive<u32>`, and the value is represented as `T`. -#[derive(PartialEq, Eq, Debug, Clone)] -#[allow(clippy::exhaustive_structs)] // based on a stable serialized form -pub struct CodePointMapRange<T> { - /// Range of code points from start to end (inclusive). - pub range: RangeInclusive<u32>, - /// Trie value associated with this range. - pub value: T, -} - -/// A custom [`Iterator`] type specifically for a code point trie that returns -/// [`CodePointMapRange`]s. -#[derive(Debug)] -pub struct CodePointMapRangeIterator<'a, T: TrieValue> { - cpt: &'a CodePointTrie<'a, T>, - // Initialize `range` to Some(CodePointMapRange{ start: u32::MAX, end: u32::MAX, value: 0}). - // When `range` is Some(...) and has a start value different from u32::MAX, then we have - // returned at least one code point range due to a call to `next()`. - // When `range` == `None`, it means that we have hit the end of iteration. It would occur - // after a call to `next()` returns a None <=> we attempted to call `get_range()` - // with a start code point that is > CODE_POINT_MAX. - cpm_range: Option<CodePointMapRange<T>>, -} - -impl<T: TrieValue> Iterator for CodePointMapRangeIterator<'_, T> { - type Item = CodePointMapRange<T>; - - fn next(&mut self) -> Option<Self::Item> { - self.cpm_range = match &self.cpm_range { - Some(cpmr) => { - if *cpmr.range.start() == u32::MAX { - self.cpt.get_range(0) - } else { - self.cpt.get_range(cpmr.range.end() + 1) - } - } - None => None, - }; - // Note: Clone is cheap. We can't Copy because RangeInclusive does not impl Copy. - self.cpm_range.clone() - } -} - -/// For sealing `TypedCodePointTrie` -/// -/// # Safety Usable Invariant -/// -/// All implementations of `TypedCodePointTrie` are reviewable in this module. -trait Seal {} - -/// Trait for writing trait bounds for monomorphizing over either -/// `FastCodePointTrie` or `SmallCodePointTrie`. -#[allow(private_bounds)] // Permit sealing -pub trait TypedCodePointTrie<'trie, T: TrieValue>: Seal { - /// The `TrieType` associated with this `TypedCodePointTrie` - /// - /// # Safety Usable Invariant - /// - /// This constant matches `self.as_untyped_ref().header.trie_type`. - const TRIE_TYPE: TrieType; - - /// Lookup trie value as `u32` by Unicode Scalar Value without branching on trie type. - #[inline(always)] - fn get32_u32(&self, code_point: u32) -> u32 { - self.get32(code_point).to_u32() - } - - /// Lookup trie value by Basic Multilingual Plane Code Point without branching on trie type. - #[inline(always)] - fn get16(&self, bmp: u16) -> T { - // LLVM's optimizations have been observed not to be 100% - // reliable around collapsing away unnecessary parts of - // `get32`, so not just calling `get32` here. - let code_point = u32::from(bmp); - if let Some(v) = self.get32_by_fast_index(code_point) { - v - } else { - self.as_untyped_ref().get32_by_small_index_cold(code_point) - } - } - - /// Lookup trie value by non-Basic Multilingual Plane Scalar Value without branching on trie type. - #[inline(always)] - fn get32_supplementary(&self, supplementary: u32) -> T { - self.as_untyped_ref().get32_supplementary(supplementary) - } - - /// Lookup trie value by Unicode Scalar Value without branching on trie type. - #[inline(always)] - fn get(&self, c: char) -> T { - // LLVM's optimizations have been observed not to be 100% - // reliable around collapsing away unnecessary parts of - // `get32`, so not just calling `get32` here. - let code_point = u32::from(c); - if let Some(v) = self.get32_by_fast_index(code_point) { - v - } else { - self.as_untyped_ref().get32_by_small_index_cold(code_point) - } - } - - /// Lookup trie value by Unicode Code Point without branching on trie type. - #[inline(always)] - fn get32(&self, code_point: u32) -> T { - if let Some(v) = self.get32_by_fast_index(code_point) { - v - } else if code_point <= CODE_POINT_MAX { - self.as_untyped_ref().get32_by_small_index_cold(code_point) - } else { - self.as_untyped_ref().error_value - } - } - - /// Returns the value that is associated with `code_point` in this [`CodePointTrie`] - /// if `code_point` uses fast-path lookup or `None` if `code_point` - /// should use small-path lookup or is above the supported range. - #[inline(always)] // "always" to make the `Option` collapse away - fn get32_by_fast_index(&self, code_point: u32) -> Option<T> { - debug_assert_eq!(Self::TRIE_TYPE, self.as_untyped_ref().header.trie_type); - let fast_max = match Self::TRIE_TYPE { - TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, - TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, - }; - if code_point <= fast_max { - // SAFETY: We just checked the invariant of - // `get32_assuming_fast_index`, - // which is - // "If `self.header.trie_type == TrieType::Small`, `code_point` must be at most - // `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == - // TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`." - // ... assuming that `Self::TRIE_TYPE` always matches - // `self.as_untyped_ref().header.trie_type`, i.e. we're relying on - // `CodePointTrie::to_typed` and `CodePointTrie::as_typed_ref` being correct - // and the exclusive ways of obtaining `Self`. - Some(unsafe { self.as_untyped_ref().get32_assuming_fast_index(code_point) }) - } else { - // The caller needs to call `get32_by_small_index` or determine - // that the argument is above the permitted range. - None - } - } - - /// Returns a reference to the wrapped `CodePointTrie`. - fn as_untyped_ref(&self) -> &CodePointTrie<'trie, T>; - - /// Extracts the wrapped `CodePointTrie`. - fn to_untyped(self) -> CodePointTrie<'trie, T>; -} - -/// Type-safe wrapper for a fast trie guaranteeing -/// the the getters don't branch on the trie type -/// and for guarenteeing that `get16` is branchless -/// in release builds. -#[derive(Debug)] -#[repr(transparent)] -pub struct FastCodePointTrie<'trie, T: TrieValue> { - inner: CodePointTrie<'trie, T>, -} - -impl<'trie, T: TrieValue> TypedCodePointTrie<'trie, T> for FastCodePointTrie<'trie, T> { - const TRIE_TYPE: TrieType = TrieType::Fast; - - /// Returns a reference to the wrapped `CodePointTrie`. - #[inline(always)] - fn as_untyped_ref(&self) -> &CodePointTrie<'trie, T> { - &self.inner - } - - /// Extracts the wrapped `CodePointTrie`. - #[inline(always)] - fn to_untyped(self) -> CodePointTrie<'trie, T> { - self.inner - } - - /// Lookup trie value by Basic Multilingual Plane Code Point without branching on trie type. - #[inline(always)] - fn get16(&self, bmp: u16) -> T { - debug_assert!(u32::from(u16::MAX) <= FAST_TYPE_FAST_INDEXING_MAX); - debug_assert_eq!(Self::TRIE_TYPE, TrieType::Fast); - debug_assert_eq!(self.as_untyped_ref().header.trie_type, TrieType::Fast); - let code_point = u32::from(bmp); - // SAFETY: With `TrieType::Fast`, the `u16` range satisfies - // the invariant of `get32_assuming_fast_index`, which is - // "If `self.header.trie_type == TrieType::Small`, `code_point` must be at most - // `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == - // TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`." - // - // We're relying on `CodePointTrie::to_typed` and `CodePointTrie::as_typed_ref` - // being correct and the exclusive ways of obtaining `Self`. - unsafe { self.as_untyped_ref().get32_assuming_fast_index(code_point) } - } -} - -impl<'trie, T: TrieValue> Seal for FastCodePointTrie<'trie, T> {} - -impl<'trie, T: TrieValue> TryFrom<&'trie CodePointTrie<'trie, T>> - for &'trie FastCodePointTrie<'trie, T> -{ - type Error = TypedCodePointTrieError; - - fn try_from( - reference: &'trie CodePointTrie<'trie, T>, - ) -> Result<&'trie FastCodePointTrie<'trie, T>, TypedCodePointTrieError> { - match reference.as_typed_ref() { - Typed::Fast(trie) => Ok(trie), - Typed::Small(_) => Err(TypedCodePointTrieError), - } - } -} - -impl<'trie, T: TrieValue> TryFrom<CodePointTrie<'trie, T>> for FastCodePointTrie<'trie, T> { - type Error = TypedCodePointTrieError; - - fn try_from( - value: CodePointTrie<'trie, T>, - ) -> Result<FastCodePointTrie<'trie, T>, TypedCodePointTrieError> { - match value.to_typed() { - Typed::Fast(trie) => Ok(trie), - Typed::Small(_) => Err(TypedCodePointTrieError), - } - } -} - -/// Type-safe wrapper for a small trie guaranteeing -/// the the getters don't branch on the trie type. -#[derive(Debug)] -#[repr(transparent)] -pub struct SmallCodePointTrie<'trie, T: TrieValue> { - inner: CodePointTrie<'trie, T>, -} - -impl<'trie, T: TrieValue> TypedCodePointTrie<'trie, T> for SmallCodePointTrie<'trie, T> { - const TRIE_TYPE: TrieType = TrieType::Small; - - /// Returns a reference to the wrapped `CodePointTrie`. - #[inline(always)] - fn as_untyped_ref(&self) -> &CodePointTrie<'trie, T> { - &self.inner - } - - /// Extracts the wrapped `CodePointTrie`. - #[inline(always)] - fn to_untyped(self) -> CodePointTrie<'trie, T> { - self.inner - } -} - -impl<'trie, T: TrieValue> Seal for SmallCodePointTrie<'trie, T> {} - -impl<'trie, T: TrieValue> TryFrom<&'trie CodePointTrie<'trie, T>> - for &'trie SmallCodePointTrie<'trie, T> -{ - type Error = TypedCodePointTrieError; - - fn try_from( - reference: &'trie CodePointTrie<'trie, T>, - ) -> Result<&'trie SmallCodePointTrie<'trie, T>, TypedCodePointTrieError> { - match reference.as_typed_ref() { - Typed::Fast(_) => Err(TypedCodePointTrieError), - Typed::Small(trie) => Ok(trie), - } - } -} - -impl<'trie, T: TrieValue> TryFrom<CodePointTrie<'trie, T>> for SmallCodePointTrie<'trie, T> { - type Error = TypedCodePointTrieError; - - fn try_from( - value: CodePointTrie<'trie, T>, - ) -> Result<SmallCodePointTrie<'trie, T>, TypedCodePointTrieError> { - match value.to_typed() { - Typed::Fast(_) => Err(TypedCodePointTrieError), - Typed::Small(trie) => Ok(trie), - } - } -} - -/// Error indicating that the `TrieType` of an untyped trie -/// does not match the requested typed trie type. -#[derive(Debug)] -#[non_exhaustive] -pub struct TypedCodePointTrieError; - -/// Holder for either fast or small trie with the trie -/// type encoded into the Rust type. -#[allow(clippy::exhaustive_enums)] -#[derive(Debug)] -pub enum Typed<F, S> { - /// The trie type is fast. - Fast(F), - /// The trie type is small. - Small(S), -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::codepointtrie::planes; - use alloc::vec::Vec; - - #[test] - #[cfg(feature = "serde")] - fn test_serde_with_postcard_roundtrip() -> Result<(), postcard::Error> { - let trie = planes::get_planes_trie(); - let trie_serialized: Vec<u8> = postcard::to_allocvec(&trie).unwrap(); - - // Assert an expected (golden data) version of the serialized trie. - const EXP_TRIE_SERIALIZED: &[u8] = &[ - 128, 128, 64, 128, 2, 2, 0, 0, 1, 160, 18, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, - 2, 144, 2, 144, 2, 144, 2, 176, 2, 176, 2, 176, 2, 176, 2, 208, 2, 208, 2, 208, 2, 208, - 2, 240, 2, 240, 2, 240, 2, 240, 2, 16, 3, 16, 3, 16, 3, 16, 3, 48, 3, 48, 3, 48, 3, 48, - 3, 80, 3, 80, 3, 80, 3, 80, 3, 112, 3, 112, 3, 112, 3, 112, 3, 144, 3, 144, 3, 144, 3, - 144, 3, 176, 3, 176, 3, 176, 3, 176, 3, 208, 3, 208, 3, 208, 3, 208, 3, 240, 3, 240, 3, - 240, 3, 240, 3, 16, 4, 16, 4, 16, 4, 16, 4, 48, 4, 48, 4, 48, 4, 48, 4, 80, 4, 80, 4, - 80, 4, 80, 4, 112, 4, 112, 4, 112, 4, 112, 4, 0, 0, 16, 0, 32, 0, 48, 0, 64, 0, 80, 0, - 96, 0, 112, 0, 0, 0, 16, 0, 32, 0, 48, 0, 0, 0, 16, 0, 32, 0, 48, 0, 0, 0, 16, 0, 32, - 0, 48, 0, 0, 0, 16, 0, 32, 0, 48, 0, 0, 0, 16, 0, 32, 0, 48, 0, 0, 0, 16, 0, 32, 0, 48, - 0, 0, 0, 16, 0, 32, 0, 48, 0, 0, 0, 16, 0, 32, 0, 48, 0, 128, 0, 128, 0, 128, 0, 128, - 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, - 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, - 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, - 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, - 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, - 0, 144, 0, 144, 0, 144, 0, 144, 0, 144, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, - 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, - 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, 0, 160, - 0, 160, 0, 160, 0, 160, 0, 160, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, - 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, - 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, 0, 176, - 0, 176, 0, 176, 0, 176, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, - 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, - 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, 0, 192, - 0, 192, 0, 192, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, - 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, - 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, - 0, 208, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, - 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, - 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, 0, 224, - 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, - 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, - 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, - 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, - 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 32, 1, 32, 1, 32, 1, - 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, - 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, - 32, 1, 32, 1, 32, 1, 32, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, - 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, - 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 64, 1, 64, - 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, - 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, - 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, - 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, - 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, - 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, - 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, - 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 128, 0, 136, 0, 136, 0, 136, 0, 136, - 0, 136, 0, 136, 0, 136, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, - 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, - 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, - 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, - 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, - 168, 0, 168, 0, 168, 0, 168, 0, 168, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, - 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, - 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, 200, 0, - 200, 0, 200, 0, 200, 0, 200, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, - 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, - 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, 232, 0, - 232, 0, 232, 0, 232, 0, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, - 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, - 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, - 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, - 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, - 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, - 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, - 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 104, 1, 104, 1, 104, 1, 104, 1, - 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, - 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, - 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, - 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, - 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, - 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, - 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, - 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, - 168, 1, 168, 1, 168, 1, 168, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, - 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, - 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, - 200, 1, 200, 1, 200, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, - 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, - 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, - 232, 1, 232, 1, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, - 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, - 2, 8, 2, 8, 2, 8, 2, 8, 2, 8, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, - 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, - 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 40, 2, 72, - 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, - 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, - 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 72, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, - 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, - 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, - 104, 2, 104, 2, 104, 2, 104, 2, 104, 2, 244, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 0, - ]; - assert_eq!(trie_serialized, EXP_TRIE_SERIALIZED); - - let trie_deserialized = postcard::from_bytes::<CodePointTrie<u8>>(&trie_serialized)?; - - assert_eq!(&trie.index, &trie_deserialized.index); - assert_eq!(&trie.data, &trie_deserialized.data); - - assert!(!trie_deserialized.index.is_owned()); - assert!(!trie_deserialized.data.is_owned()); - - Ok(()) - } - - #[test] - fn test_typed() { - let untyped = planes::get_planes_trie(); - assert_eq!(untyped.get('\u{10000}'), 1); - let small_ref = <&SmallCodePointTrie<_>>::try_from(&untyped).unwrap(); - assert_eq!(small_ref.get('\u{10000}'), 1); - let _ = <&FastCodePointTrie<_>>::try_from(&untyped).is_err(); - let small = <SmallCodePointTrie<_>>::try_from(untyped).unwrap(); - assert_eq!(small.get('\u{10000}'), 1); - } - - #[test] - fn test_get_range() { - let planes_trie = planes::get_planes_trie(); - - let first_range: Option<CodePointMapRange<u8>> = planes_trie.get_range(0x0); - assert_eq!( - first_range, - Some(CodePointMapRange { - range: 0x0..=0xffff, - value: 0 - }) - ); - - let second_range: Option<CodePointMapRange<u8>> = planes_trie.get_range(0x1_0000); - assert_eq!( - second_range, - Some(CodePointMapRange { - range: 0x10000..=0x1ffff, - value: 1 - }) - ); - - let penultimate_range: Option<CodePointMapRange<u8>> = planes_trie.get_range(0xf_0000); - assert_eq!( - penultimate_range, - Some(CodePointMapRange { - range: 0xf_0000..=0xf_ffff, - value: 15 - }) - ); - - let last_range: Option<CodePointMapRange<u8>> = planes_trie.get_range(0x10_0000); - assert_eq!( - last_range, - Some(CodePointMapRange { - range: 0x10_0000..=0x10_ffff, - value: 16 - }) - ); - } - - #[test] - #[allow(unused_unsafe)] // `unsafe` below is both necessary and unnecessary - fn databake() { - databake::test_bake!( - CodePointTrie<'static, u32>, - const, - unsafe { - crate::codepointtrie::CodePointTrie::from_parts_unstable_unchecked_v1( - crate::codepointtrie::CodePointTrieHeader { - high_start: 1u32, - shifted12_high_start: 2u16, - index3_null_offset: 3u16, - data_null_offset: 4u32, - null_value: 5u32, - trie_type: crate::codepointtrie::TrieType::Small, - }, - zerovec::ZeroVec::new(), - zerovec::ZeroVec::new(), - 0u32, - ) - }, - icu_collections, - [zerovec], - ); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/error.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/error.rs deleted file mode 100644 index 383949d95611..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/error.rs +++ /dev/null @@ -1,30 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! Custom error type(s) for the parent module. - -use displaydoc::Display; - -/// A custom error type for [`CodePointTrie`](super::CodePointTrie). -#[derive(Copy, Clone, Display, Debug, PartialEq)] -#[non_exhaustive] -pub enum Error { - /// Could not construct [`CodePointTrie`](super::CodePointTrie) from deserialized values - #[displaydoc("Could not construct CodePointTrie from deserialized values: {reason}")] - FromDeserialized { - /// Reason for inability to deserialize values. - reason: &'static str, - }, - /// [`CodePointTrie`](super::CodePointTrie) must be constructed from data vector with at least one element - #[displaydoc("CodePointTrie must be constructed from data vector with at least one element")] - EmptyDataVector, - /// [`CodePointTrie`](super::CodePointTrie) must be constructed from index vector long enough to accommodate fast-path access - #[displaydoc("CodePointTrie must be constructed from index vector long enough to accommodate fast-path access")] - IndexTooShortForFastAccess, - /// [`CodePointTrie`](super::CodePointTrie) must be constructed from data vector long enough to accommodate fast-path access - #[displaydoc("CodePointTrie must be constructed from data vector long enough to accommodate fast-path access")] - DataTooShortForFastAccess, -} - -impl core::error::Error for Error {} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/impl_const.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/impl_const.rs deleted file mode 100644 index 61e4f2746ded..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/impl_const.rs +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -pub const FAST_TYPE_SHIFT: i32 = 6; - -/// Number of entries in a data block for code points below the fast limit. 64=0x40 -pub const FAST_TYPE_DATA_BLOCK_LENGTH: u32 = 1 << FAST_TYPE_SHIFT; - -/// Mask for getting the lower bits for the in-fast-data-block offset. -pub const FAST_TYPE_DATA_MASK: u32 = FAST_TYPE_DATA_BLOCK_LENGTH - 1; - -/// Fast indexing limit for "fast"-type trie -pub const FAST_TYPE_FAST_INDEXING_MAX: u32 = 0xffff; - -/// Fast indexing limit for "small"-type trie -pub const SMALL_TYPE_FAST_INDEXING_MAX: u32 = 0xfff; - -/// Offset from dataLength (to be subtracted) for fetching the -/// value returned for out-of-range code points and ill-formed UTF-8/16. -pub const ERROR_VALUE_NEG_DATA_OFFSET: u32 = 1; - -/// Offset from dataLength (to be subtracted) for fetching the -/// value returned for code points highStart..U+10FFFF. -pub const HIGH_VALUE_NEG_DATA_OFFSET: u32 = 2; - -/// The length of the BMP index table. 1024=0x400 -pub const BMP_INDEX_LENGTH: u32 = 0x10000 >> FAST_TYPE_SHIFT; - -pub const SMALL_LIMIT: u32 = 0x1000; - -pub const SMALL_INDEX_LENGTH: u32 = SMALL_LIMIT >> FAST_TYPE_SHIFT; - -/// Shift size for getting the index-3 table offset. -pub const SHIFT_3: u32 = 4; - -/// Shift size for getting the index-2 table offset. -pub const SHIFT_2: u32 = 5 + SHIFT_3; - -/// Shift size for getting the index-1 table offset. -pub const SHIFT_1: u32 = 5 + SHIFT_2; - -/// Difference between two shift sizes, -/// for getting an index-2 offset from an index-3 offset. 5=9-4 -pub const SHIFT_2_3: u32 = SHIFT_2 - SHIFT_3; - -/// Difference between two shift sizes, -/// for getting an index-1 offset from an index-2 offset. 5=14-9 -pub const SHIFT_1_2: u32 = SHIFT_1 - SHIFT_2; - -/// Number of index-1 entries for the BMP. (4) -/// This part of the index-1 table is omitted from the serialized form. -pub const OMITTED_BMP_INDEX_1_LENGTH: u32 = 0x10000 >> SHIFT_1; - -/// Number of entries in an index-2 block. 32=0x20 -pub const INDEX_2_BLOCK_LENGTH: u32 = 1 << SHIFT_1_2; - -/// Mask for getting the lower bits for the in-index-2-block offset. -pub const INDEX_2_MASK: u32 = INDEX_2_BLOCK_LENGTH - 1; - -/// Number of code points per index-2 table entry. 512=0x200 -pub const CP_PER_INDEX_2_ENTRY: u32 = 1 << SHIFT_2; - -/// Number of entries in an index-3 block. 32=0x20 -pub const INDEX_3_BLOCK_LENGTH: u32 = 1 << SHIFT_2_3; - -/// Mask for getting the lower bits for the in-index-3-block offset. -pub const INDEX_3_MASK: u32 = INDEX_3_BLOCK_LENGTH - 1; - -/// Number of entries in a small data block. 16=0x10 -pub const SMALL_DATA_BLOCK_LENGTH: u32 = 1 << SHIFT_3; - -/// Mask for getting the lower bits for the in-small-data-block offset. -pub const SMALL_DATA_MASK: u32 = SMALL_DATA_BLOCK_LENGTH - 1; - -pub const CODE_POINT_MAX: u32 = 0x10ffff; diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/mod.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/mod.rs deleted file mode 100644 index dfc5a29ffc21..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/mod.rs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module provides a data structure for an time-efficient lookup of values -//! associated to code points. -//! -//! It is an implementation of the existing [ICU4C UCPTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/ucptrie_8h.html) -//! / [ICU4J CodePointTrie](https://unicode-org.github.io/icu-docs/apidoc/dev/icu4j/) API. -//! -//! # Architecture -//! -//! ICU4X [`CodePointTrie`] is designed to provide a read-only view of [`CodePointTrie`] data that is exported -//! from ICU4C. Detailed information about the design of the data structure can be found in the documentation -//! for the [`CodePointTrie`] struct. -//! -//! # Examples -//! -//! ## Querying a `CodePointTrie` -//! -//! ``` -//! use icu::collections::codepointtrie::planes; -//! let trie = planes::get_planes_trie(); -//! -//! assert_eq!(0, trie.get32(0x41)); // 'A' as u32 -//! assert_eq!(0, trie.get32(0x13E0)); // 'Ꮰ' as u32 -//! assert_eq!(1, trie.get32(0x10044)); // '𐁄' as u32 -//! ``` -//! -//! [`ICU4X`]: ../icu/index.html - -mod cptrie; -mod error; -mod impl_const; -pub mod planes; - -#[cfg(feature = "serde")] -pub mod toml; - -#[cfg(feature = "serde")] -mod serde; - -pub use cptrie::CodePointMapRange; -pub use cptrie::CodePointMapRangeIterator; -pub use cptrie::CodePointTrie; -pub use cptrie::CodePointTrieHeader; -pub use cptrie::FastCodePointTrie; -pub use cptrie::SmallCodePointTrie; -pub use cptrie::TrieType; -pub use cptrie::TrieValue; -pub use cptrie::Typed; -pub use cptrie::TypedCodePointTrie; -pub use error::Error as CodePointTrieError; diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/planes.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/planes.rs deleted file mode 100644 index a806632992fe..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/planes.rs +++ /dev/null @@ -1,296 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! Sample data for [`CodePointTrie`] that returns the code point's plane number. - -use crate::codepointtrie::cptrie::*; -use zerovec::ZeroVec; - -const INDEX_ARRAY_AS_BYTES: &[u8] = &[ - 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x2, 0x90, 0x2, - 0x90, 0x2, 0x90, 0x2, 0xb0, 0x2, 0xb0, 0x2, 0xb0, 0x2, 0xb0, 0x2, 0xd0, 0x2, 0xd0, 0x2, 0xd0, - 0x2, 0xd0, 0x2, 0xf0, 0x2, 0xf0, 0x2, 0xf0, 0x2, 0xf0, 0x2, 0x10, 0x3, 0x10, 0x3, 0x10, 0x3, - 0x10, 0x3, 0x30, 0x3, 0x30, 0x3, 0x30, 0x3, 0x30, 0x3, 0x50, 0x3, 0x50, 0x3, 0x50, 0x3, 0x50, - 0x3, 0x70, 0x3, 0x70, 0x3, 0x70, 0x3, 0x70, 0x3, 0x90, 0x3, 0x90, 0x3, 0x90, 0x3, 0x90, 0x3, - 0xb0, 0x3, 0xb0, 0x3, 0xb0, 0x3, 0xb0, 0x3, 0xd0, 0x3, 0xd0, 0x3, 0xd0, 0x3, 0xd0, 0x3, 0xf0, - 0x3, 0xf0, 0x3, 0xf0, 0x3, 0xf0, 0x3, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x10, 0x4, 0x30, 0x4, - 0x30, 0x4, 0x30, 0x4, 0x30, 0x4, 0x50, 0x4, 0x50, 0x4, 0x50, 0x4, 0x50, 0x4, 0x70, 0x4, 0x70, - 0x4, 0x70, 0x4, 0x70, 0x4, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, 0x0, 0x40, 0x0, 0x50, 0x0, - 0x60, 0x0, 0x70, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, - 0x0, 0x30, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, - 0x30, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, - 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, 0x0, 0x0, 0x0, 0x10, 0x0, 0x20, 0x0, 0x30, 0x0, - 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, - 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, - 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, - 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80, 0x0, 0x90, 0x0, 0x90, 0x0, - 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, - 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, - 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, - 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0x90, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, - 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, - 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, - 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xa0, - 0x0, 0xa0, 0x0, 0xa0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, - 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, - 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, - 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, 0x0, 0xb0, - 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, - 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, - 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, - 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xd0, 0x0, 0xd0, - 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, - 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, - 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, - 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xd0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, - 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, - 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, - 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, - 0xe0, 0x0, 0xe0, 0x0, 0xe0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, - 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, - 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, - 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, 0xf0, 0x0, - 0xf0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, - 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, - 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, - 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, - 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, - 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, - 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, 0x10, 0x1, - 0x10, 0x1, 0x10, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, - 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, - 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, - 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, 0x20, 0x1, - 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, - 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, - 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, - 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x30, 0x1, 0x40, 0x1, 0x40, 0x1, - 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, - 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, - 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, - 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x40, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, - 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, - 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, - 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, 0x1, 0x50, - 0x1, 0x50, 0x1, 0x50, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, - 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, - 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, - 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, 0x1, 0x60, - 0x1, 0x80, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, 0x88, 0x0, - 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, - 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, - 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, - 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, - 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, - 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, - 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, 0xa8, 0x0, - 0xa8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, - 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, - 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, - 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xc8, 0x0, 0xe8, 0x0, - 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, - 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, - 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, - 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0xe8, 0x0, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, - 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, - 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, - 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, 0x8, 0x1, - 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, - 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, - 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, - 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x28, 0x1, 0x48, 0x1, 0x48, 0x1, - 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, - 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, - 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, - 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x48, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, - 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, - 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, - 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, 0x1, 0x68, - 0x1, 0x68, 0x1, 0x68, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, - 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, - 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, - 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, 0x1, 0x88, - 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, - 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, - 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, - 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xa8, 0x1, 0xc8, 0x1, 0xc8, - 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, - 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, - 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, - 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xc8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, - 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, - 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, - 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, - 0xe8, 0x1, 0xe8, 0x1, 0xe8, 0x1, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, - 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, - 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, - 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x8, 0x2, 0x28, 0x2, 0x28, 0x2, - 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, - 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, - 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, - 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x28, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, - 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, - 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, - 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, 0x2, 0x48, - 0x2, 0x48, 0x2, 0x48, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, - 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, - 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, - 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, 0x2, 0x68, - 0x2, -]; - -/// Return a [`CodePointTrie`] that returns the Unicode plane number, an -/// integer from 0-16 inclusive, for each code point. -/// -/// This `CodePointTrie` -/// does not actually represent any Unicode property, but it is provided in -/// case it is useful to users of `CodePointTrie` for testing or other -/// purposes. See <https://www.unicode.org/glossary/#plane>. -pub fn get_planes_trie() -> CodePointTrie<'static, u8> { - let index_array_as_bytes: &[u8] = INDEX_ARRAY_AS_BYTES; - let data_8_array: &[u8] = &[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xb, - 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xc, 0xc, 0xc, - 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xd, 0xd, 0xd, 0xd, 0xd, - 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xd, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, - 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, - 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x10, 0x10, 0x10, 0, - ]; - #[expect(clippy::unwrap_used)] // valid bytes - let index: ZeroVec<u16> = ZeroVec::parse_bytes(index_array_as_bytes).unwrap(); - #[expect(clippy::unwrap_used)] // valid bytes - let data: ZeroVec<u8> = ZeroVec::parse_bytes(data_8_array).unwrap(); - let high_start = 0x100000; - let shifted12_high_start = 0x100; - let index3_null_offset = 0x2; - let data_null_offset = 0x0; - let null_value = 0x0; - let trie_type = TrieType::Small; - - let trie_header = CodePointTrieHeader { - high_start, - shifted12_high_start, - index3_null_offset, - data_null_offset, - null_value, - trie_type, - }; - - #[expect(clippy::unwrap_used)] // valid data - CodePointTrie::try_new(trie_header, index, data).unwrap() -} - -#[cfg(test)] -mod tests { - use zerovec::ZeroVec; - - const INDEX_ARRAY: &[u16] = &[ - 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x288, 0x290, 0x290, 0x290, 0x2b0, 0x2b0, 0x2b0, 0x2b0, 0x2d0, 0x2d0, 0x2d0, - 0x2d0, 0x2f0, 0x2f0, 0x2f0, 0x2f0, 0x310, 0x310, 0x310, 0x310, 0x330, 0x330, 0x330, 0x330, - 0x350, 0x350, 0x350, 0x350, 0x370, 0x370, 0x370, 0x370, 0x390, 0x390, 0x390, 0x390, 0x3b0, - 0x3b0, 0x3b0, 0x3b0, 0x3d0, 0x3d0, 0x3d0, 0x3d0, 0x3f0, 0x3f0, 0x3f0, 0x3f0, 0x410, 0x410, - 0x410, 0x410, 0x430, 0x430, 0x430, 0x430, 0x450, 0x450, 0x450, 0x450, 0x470, 0x470, 0x470, - 0x470, 0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0, 0x10, 0x20, 0x30, 0, 0x10, 0x20, - 0x30, 0, 0x10, 0x20, 0x30, 0, 0x10, 0x20, 0x30, 0, 0x10, 0x20, 0x30, 0, 0x10, 0x20, 0x30, - 0, 0x10, 0x20, 0x30, 0, 0x10, 0x20, 0x30, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, - 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, - 0xd0, 0xd0, 0xd0, 0xd0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, - 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, - 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, - 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, - 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, - 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, - 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, - 0x110, 0x110, 0x110, 0x110, 0x110, 0x110, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, - 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, - 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x120, 0x130, - 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, - 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, 0x130, - 0x130, 0x130, 0x130, 0x130, 0x130, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, - 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, - 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x140, 0x150, 0x150, - 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, - 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, 0x150, - 0x150, 0x150, 0x150, 0x150, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, - 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, - 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x160, 0x80, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0x108, 0x108, - 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, - 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, - 0x108, 0x108, 0x108, 0x108, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, - 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, - 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x128, 0x148, 0x148, 0x148, - 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, - 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, 0x148, - 0x148, 0x148, 0x148, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, - 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, - 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x168, 0x188, 0x188, 0x188, 0x188, - 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, - 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, 0x188, - 0x188, 0x188, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, - 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, - 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1a8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, - 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, - 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, 0x1c8, - 0x1c8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, - 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, - 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x1e8, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, - 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, - 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, 0x208, - 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, - 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, - 0x228, 0x228, 0x228, 0x228, 0x228, 0x228, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, - 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, - 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x248, 0x268, - 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, - 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, 0x268, - 0x268, 0x268, 0x268, 0x268, 0x268, - ]; - - #[test] - fn test_index_byte_array_literal() { - let index_array_as_bytes: &[u8] = super::INDEX_ARRAY_AS_BYTES; - let index_zv_bytes: ZeroVec<u16> = - ZeroVec::parse_bytes(index_array_as_bytes).expect("infallible"); - let index_zv_aligned: ZeroVec<u16> = ZeroVec::from_slice_or_alloc(INDEX_ARRAY); - assert_eq!(index_zv_bytes, index_zv_aligned); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/serde.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/serde.rs deleted file mode 100644 index adfb2d8aa08e..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/serde.rs +++ /dev/null @@ -1,74 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use crate::codepointtrie::{CodePointTrie, CodePointTrieHeader, TrieValue}; -use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use zerofrom::ZeroFrom; -use zerovec::ZeroVec; - -#[derive(Serialize, Deserialize)] -pub struct CodePointTrieSerde<'trie, T: TrieValue> { - header: CodePointTrieHeader, - #[serde(borrow)] - index: ZeroVec<'trie, u16>, - #[serde(borrow)] - data: ZeroVec<'trie, T>, -} - -impl<T: TrieValue + Serialize> Serialize for CodePointTrie<'_, T> { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - let ser = CodePointTrieSerde { - header: self.header, - index: ZeroFrom::zero_from(&self.index), - data: ZeroFrom::zero_from(&self.data), - }; - ser.serialize(serializer) - } -} - -impl<'de, 'trie, T: TrieValue + Deserialize<'de>> Deserialize<'de> for CodePointTrie<'trie, T> -where - 'de: 'trie, -{ - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - let de = CodePointTrieSerde::deserialize(deserializer)?; - // SAFETY: - // `validate_fields` upholds the invariants for the fields that - // fast-path access without bound checks relies on. - let error_value = match CodePointTrie::validate_fields(&de.header, &de.index, &de.data) { - Ok(v) => v, - Err(e) => { - match e { - super::CodePointTrieError::FromDeserialized { reason } => { - // Not supposed to be returned by `validate_fields`. - debug_assert!(false); - return Err(D::Error::custom(reason)); - } - super::CodePointTrieError::EmptyDataVector => { - return Err(D::Error::custom("CodePointTrie must be constructed from data vector with at least one element")); - } - super::CodePointTrieError::IndexTooShortForFastAccess => { - return Err(D::Error::custom("CodePointTrie must be constructed from index vector long enough to accommodate fast-path access")); - } - super::CodePointTrieError::DataTooShortForFastAccess => { - return Err(D::Error::custom("CodePointTrie must be constructed from data vector long enough to accommodate fast-path access")); - } - } - } - }; - // Field invariants upheld: Checked by `validate_fields` above. - Ok(CodePointTrie { - header: de.header, - index: de.index, - data: de.data, - error_value, - }) - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/toml.rs b/deps/crates/vendor/icu_collections-v2/src/codepointtrie/toml.rs deleted file mode 100644 index 0e05f16510da..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/codepointtrie/toml.rs +++ /dev/null @@ -1,124 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! Utilities for reading [`CodePointTrie`] data from TOML files. - -use crate::codepointtrie::error::Error; -use crate::codepointtrie::CodePointTrie; -use crate::codepointtrie::CodePointTrieHeader; -use crate::codepointtrie::TrieType; -use crate::codepointtrie::TrieValue; -use alloc::string::String; -use alloc::vec::Vec; -use core::convert::TryFrom; -use zerovec::ZeroVec; - -/// A Serde-compatible struct for reading serialized [`CodePointTrie`] TOML files -/// generated by ICU4C. -/// -/// Use `TryInto` to convert [`CodePointTrieToml`] to a proper [`CodePointTrie`]. -#[derive(serde::Deserialize, Debug)] -pub struct CodePointTrieToml { - #[serde(skip)] - _short_name: String, - #[serde(skip)] - _long_name: String, - #[serde(skip)] - _name: String, - index: Vec<u16>, - data_8: Option<Vec<u8>>, - data_16: Option<Vec<u16>>, - data_32: Option<Vec<u32>>, - #[serde(skip)] - _index_length: u32, - #[serde(skip)] - _data_length: u32, - #[serde(rename = "highStart")] - high_start: u32, - #[serde(rename = "shifted12HighStart")] - shifted12_high_start: u16, - #[serde(rename = "type")] - trie_type_enum_val: u8, - #[serde(rename = "valueWidth")] - _value_width_enum_val: u8, - #[serde(rename = "index3NullOffset")] - index3_null_offset: u16, - #[serde(rename = "dataNullOffset")] - data_null_offset: u32, - #[serde(rename = "nullValue")] - null_value: u32, -} - -/// Data slice from a [`CodePointTrie`] TOML. -/// -/// ICU4C exports data as either `u8`, `u16`, or `u32`, which may be converted -/// to other types as appropriate. -#[allow(clippy::exhaustive_enums)] // based on a stable serialized form -#[derive(Debug)] -pub enum CodePointDataSlice<'a> { - /// A serialized [`CodePointTrie`] data array 8-bit values. - U8(&'a [u8]), - /// A serialized [`CodePointTrie`] data array 16-bit values. - U16(&'a [u16]), - /// A serialized [`CodePointTrie`] data array 32-bit values. - U32(&'a [u32]), -} - -impl CodePointTrieToml { - /// Gets the `index` slice. - pub fn index_slice(&self) -> &[u16] { - self.index.as_slice() - } - - /// Gets the `data` slice. - pub fn data_slice(&self) -> Result<CodePointDataSlice<'_>, Error> { - if let Some(data_8) = &self.data_8 { - Ok(CodePointDataSlice::U8(data_8.as_slice())) - } else if let Some(data_16) = &self.data_16 { - Ok(CodePointDataSlice::U16(data_16.as_slice())) - } else if let Some(data_32) = &self.data_32 { - Ok(CodePointDataSlice::U32(data_32.as_slice())) - } else { - Err(Error::FromDeserialized { - reason: "Did not find data array for CodePointTrie in TOML", - }) - } - } -} - -impl TryFrom<&CodePointTrieToml> for CodePointTrieHeader { - type Error = Error; - - fn try_from(cpt_data: &CodePointTrieToml) -> Result<Self, Self::Error> { - let trie_type_enum: TrieType = TrieType::try_from(cpt_data.trie_type_enum_val)?; - Ok(CodePointTrieHeader { - high_start: cpt_data.high_start, - shifted12_high_start: cpt_data.shifted12_high_start, - index3_null_offset: cpt_data.index3_null_offset, - data_null_offset: cpt_data.data_null_offset, - null_value: cpt_data.null_value, - trie_type: trie_type_enum, - }) - } -} - -impl<T: TrieValue> TryFrom<&CodePointTrieToml> for CodePointTrie<'static, T> { - type Error = Error; - - fn try_from(cpt_data: &CodePointTrieToml) -> Result<CodePointTrie<'static, T>, Self::Error> { - use CodePointDataSlice::*; - let header = CodePointTrieHeader::try_from(cpt_data)?; - let index: ZeroVec<u16> = ZeroVec::alloc_from_slice(&cpt_data.index); - let data: Result<ZeroVec<'static, T>, T::TryFromU32Error> = match cpt_data.data_slice()? { - U8(s) => s.iter().map(|i| T::try_from_u32(*i as u32)).collect(), - U16(s) => s.iter().map(|i| T::try_from_u32(*i as u32)).collect(), - U32(s) => s.iter().map(|i| T::try_from_u32(*i)).collect(), - }; - - let data = data.map_err(|_| Error::FromDeserialized { - reason: "Could not parse data array to typed array", - })?; - CodePointTrie::<T>::try_new(header, index, data) - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/iterator_utils.rs b/deps/crates/vendor/icu_collections-v2/src/iterator_utils.rs deleted file mode 100644 index 913e3535eeb6..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/iterator_utils.rs +++ /dev/null @@ -1,188 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use crate::codepointtrie::CodePointMapRange; - -/// This is an iterator that coalesces adjacent ranges in an iterator over code -/// point ranges -pub(crate) struct RangeListIteratorCoalescer<I, T> { - iter: I, - peek: Option<CodePointMapRange<T>>, -} - -impl<I, T: Eq> RangeListIteratorCoalescer<I, T> -where - I: Iterator<Item = CodePointMapRange<T>>, -{ - pub fn new(iter: I) -> Self { - Self { iter, peek: None } - } -} - -impl<I, T: Eq> Iterator for RangeListIteratorCoalescer<I, T> -where - I: Iterator<Item = CodePointMapRange<T>>, -{ - type Item = CodePointMapRange<T>; - - fn next(&mut self) -> Option<Self::Item> { - // Get the initial range we're working with: either a leftover - // range from last time, or the next range - let mut ret = if let Some(peek) = self.peek.take() { - peek - } else if let Some(next) = self.iter.next() { - next - } else { - // No ranges, exit early - return None; - }; - - // Keep pulling ranges - #[expect(clippy::while_let_on_iterator)] - // can't move the iterator, also we want it to be explicit that we're not draining the iterator - while let Some(next) = self.iter.next() { - if *next.range.start() == ret.range.end() + 1 && next.value == ret.value { - // Range has no gap, coalesce - ret.range = *ret.range.start()..=*next.range.end(); - } else { - // Range has a gap, return what we have so far, update - // peek - self.peek = Some(next); - return Some(ret); - } - } - - // Ran out of elements, exit - Some(ret) - } -} - -#[cfg(test)] -mod tests { - use crate::codepointinvlist::CodePointInversionListBuilder; - use core::fmt::Debug; - use icu_properties::props::{BinaryProperty, EnumeratedProperty}; - use icu_properties::{CodePointMapData, CodePointSetData}; - - fn test_set<P: BinaryProperty>(name: &str) { - let mut builder = CodePointInversionListBuilder::new(); - let mut builder_complement = CodePointInversionListBuilder::new(); - - for range in CodePointSetData::new::<P>().iter_ranges() { - builder.add_range32(range) - } - - for range in CodePointSetData::new::<P>().iter_ranges_complemented() { - builder_complement.add_range32(range) - } - - builder.complement(); - let set1 = builder.build(); - let set2 = builder_complement.build(); - assert_eq!(set1, set2, "Set {name} failed to complement correctly"); - } - - fn test_map<T: EnumeratedProperty + Debug>(value: T, name: &str) { - let mut builder = CodePointInversionListBuilder::new(); - let mut builder_complement = CodePointInversionListBuilder::new(); - - for range in CodePointMapData::<T>::new().iter_ranges_for_value(value) { - builder.add_range32(range) - } - - for range in CodePointMapData::<T>::new().iter_ranges_for_value_complemented(value) { - builder_complement.add_range32(range) - } - - builder.complement(); - let set1 = builder.build(); - let set2 = builder_complement.build(); - assert_eq!( - set1, set2, - "Map {name} failed to complement correctly with value {value:?}" - ); - } - - #[test] - fn test_complement_sets() { - use icu_properties::props::*; - // Stress test the RangeListIteratorComplementer logic by ensuring it works for - // a whole bunch of binary properties - test_set::<AsciiHexDigit>("ASCII_Hex_Digit"); - test_set::<Alnum>("Alnum"); - test_set::<Alphabetic>("Alphabetic"); - test_set::<BidiControl>("Bidi_Control"); - test_set::<BidiMirrored>("Bidi_Mirrored"); - test_set::<Blank>("Blank"); - test_set::<Cased>("Cased"); - test_set::<CaseIgnorable>("Case_Ignorable"); - test_set::<FullCompositionExclusion>("Full_Composition_Exclusion"); - test_set::<ChangesWhenCasefolded>("Changes_When_Casefolded"); - test_set::<ChangesWhenCasemapped>("Changes_When_Casemapped"); - test_set::<ChangesWhenNfkcCasefolded>("Changes_When_NFKC_Casefolded"); - test_set::<ChangesWhenLowercased>("Changes_When_Lowercased"); - test_set::<ChangesWhenTitlecased>("Changes_When_Titlecased"); - test_set::<ChangesWhenUppercased>("Changes_When_Uppercased"); - test_set::<Dash>("Dash"); - test_set::<Deprecated>("Deprecated"); - test_set::<DefaultIgnorableCodePoint>("Default_Ignorable_Code_Point"); - test_set::<Diacritic>("Diacritic"); - test_set::<EmojiModifierBase>("Emoji_Modifier_Base"); - test_set::<EmojiComponent>("Emoji_Component"); - test_set::<EmojiModifier>("Emoji_Modifier"); - test_set::<Emoji>("Emoji"); - test_set::<EmojiPresentation>("Emoji_Presentation"); - test_set::<Extender>("Extender"); - test_set::<ExtendedPictographic>("Extended_Pictographic"); - test_set::<Graph>("Graph"); - test_set::<GraphemeBase>("Grapheme_Base"); - test_set::<GraphemeExtend>("Grapheme_Extend"); - test_set::<GraphemeLink>("Grapheme_Link"); - test_set::<HexDigit>("Hex_Digit"); - test_set::<Hyphen>("Hyphen"); - test_set::<IdContinue>("Id_Continue"); - test_set::<Ideographic>("Ideographic"); - test_set::<IdStart>("Id_Start"); - test_set::<IdsBinaryOperator>("Ids_Binary_Operator"); - test_set::<IdsTrinaryOperator>("Ids_Trinary_Operator"); - test_set::<JoinControl>("Join_Control"); - test_set::<LogicalOrderException>("Logical_Order_Exception"); - test_set::<Lowercase>("Lowercase"); - test_set::<Math>("Math"); - test_set::<NoncharacterCodePoint>("Noncharacter_Code_Point"); - test_set::<NfcInert>("NFC_Inert"); - test_set::<NfdInert>("NFD_Inert"); - test_set::<NfkcInert>("NFKC_Inert"); - test_set::<NfkdInert>("NFKD_Inert"); - test_set::<PatternSyntax>("Pattern_Syntax"); - test_set::<PatternWhiteSpace>("Pattern_White_Space"); - test_set::<PrependedConcatenationMark>("Prepended_Concatenation_Mark"); - test_set::<Print>("Print"); - test_set::<QuotationMark>("Quotation_Mark"); - test_set::<Radical>("Radical"); - test_set::<RegionalIndicator>("Regional_Indicator"); - test_set::<SoftDotted>("Soft_Dotted"); - test_set::<SegmentStarter>("Segment_Starter"); - test_set::<CaseSensitive>("Case_Sensitive"); - test_set::<SentenceTerminal>("Sentence_Terminal"); - test_set::<TerminalPunctuation>("Terminal_Punctuation"); - test_set::<UnifiedIdeograph>("Unified_Ideograph"); - test_set::<Uppercase>("Uppercase"); - test_set::<VariationSelector>("Variation_Selector"); - test_set::<WhiteSpace>("White_Space"); - test_set::<Xdigit>("Xdigit"); - test_set::<XidContinue>("XID_Continue"); - test_set::<XidStart>("XID_Start"); - } - - #[test] - fn test_complement_maps() { - use icu_properties::props::{GeneralCategory, Script}; - test_map(GeneralCategory::UppercaseLetter, "gc"); - test_map(GeneralCategory::OtherPunctuation, "gc"); - test_map(Script::Devanagari, "script"); - test_map(Script::Latin, "script"); - test_map(Script::Common, "script"); - } -} diff --git a/deps/crates/vendor/icu_collections-v2/src/lib.rs b/deps/crates/vendor/icu_collections-v2/src/lib.rs deleted file mode 100644 index f19010e72bf6..000000000000 --- a/deps/crates/vendor/icu_collections-v2/src/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -// https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations -#![cfg_attr(not(any(test, doc)), no_std)] -#![cfg_attr( - not(test), - deny( - clippy::indexing_slicing, - clippy::unwrap_used, - clippy::expect_used, - clippy::panic, - ) -)] -#![warn(missing_docs)] - -//! Efficient collections for Unicode data. -//! -//! This module is published as its own crate ([`icu_collections`](https://docs.rs/icu_collections/latest/icu_collections/)) -//! and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project. -//! -//! ICU4X [`CodePointTrie`](crate::codepointtrie::CodePointTrie) provides a read-only view of `CodePointTrie` data that is exported -//! from ICU4C. Detailed information about the design of the data structure can be found in the documentation -//! for the [`CodePointTrie`](crate::codepointtrie::CodePointTrie) struct. -//! -//! ICU4X [`CodePointInversionList`](`crate::codepointinvlist::CodePointInversionList`) provides necessary functionality for highly efficient querying of sets of Unicode characters. -//! It is an implementation of the existing [ICU4C UnicodeSet API](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UnicodeSet.html). -//! -//! ICU4X [`Char16Trie`](`crate::char16trie::Char16Trie`) provides a data structure for a space-efficient and time-efficient lookup of -//! sequences of 16-bit units (commonly but not necessarily UTF-16 code units) -//! which map to integer values. -//! It is an implementation of the existing [ICU4C UCharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1UCharsTrie.html) -//! / [ICU4J CharsTrie](https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/com/ibm/icu/util/CharsTrie.html) API. - -#[cfg(feature = "alloc")] -extern crate alloc; - -pub mod char16trie; -pub mod codepointinvlist; -pub mod codepointinvliststringlist; -pub mod codepointtrie; - -pub(crate) mod iterator_utils; diff --git a/deps/crates/vendor/icu_collections-v2/tests/char16trie.rs b/deps/crates/vendor/icu_collections-v2/tests/char16trie.rs deleted file mode 100644 index dcb4424c635e..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/char16trie.rs +++ /dev/null @@ -1,304 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use icu_collections::char16trie::{Char16Trie, TrieResult}; -use zerovec::ZeroVec; - -#[test] -fn empty() { - let trie_data = toml::from_str::<TestFile>(include_str!("data/char16trie/empty.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - let res = trie.iter().next('h'); - assert_eq!(res, TrieResult::NoMatch); -} - -#[test] -fn a() { - let trie_data = toml::from_str::<TestFile>(include_str!("data/char16trie/test_a.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - let mut iter = trie.iter(); - let res = iter.next('h'); - assert_eq!(res, TrieResult::NoMatch); - - let mut iter = trie.iter(); - let res = iter.next('a'); - assert_eq!(res, TrieResult::FinalValue(1)); - let res = iter.next('a'); - assert_eq!(res, TrieResult::NoMatch); -} - -#[test] -fn a_b() { - let trie_data = toml::from_str::<TestFile>(include_str!("data/char16trie/test_a_ab.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - let mut iter = trie.iter(); - let res = iter.next('a'); - assert_eq!(res, TrieResult::Intermediate(1)); - let res = iter.next('a'); - assert_eq!(res, TrieResult::NoMatch); - - let mut iter = trie.iter(); - let res = iter.next('a'); - assert_eq!(res, TrieResult::Intermediate(1)); - let res = iter.next('b'); - assert_eq!(res, TrieResult::FinalValue(100)); - let res = iter.next('b'); - assert_eq!(res, TrieResult::NoMatch); -} - -#[test] -fn shortest_branch() { - let trie_data = - toml::from_str::<TestFile>(include_str!("data/char16trie/test_shortest_branch.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - let mut iter = trie.iter(); - let res = iter.next('a'); - assert_eq!(res, TrieResult::FinalValue(1000)); - let res = iter.next('b'); - assert_eq!(res, TrieResult::NoMatch); - - let mut iter = trie.iter(); - let res = iter.next('b'); - assert_eq!(res, TrieResult::FinalValue(2000)); - let res = iter.next('a'); - assert_eq!(res, TrieResult::NoMatch); -} - -#[test] -fn branches() { - let trie_data = toml::from_str::<TestFile>(include_str!("data/char16trie/test_branches.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - for (query, expected) in [ - ("a", TrieResult::FinalValue(0x10)), - ("cc", TrieResult::FinalValue(0x40)), - ("e", TrieResult::FinalValue(0x100)), - ("ggg", TrieResult::FinalValue(0x400)), - ("i", TrieResult::FinalValue(0x1000)), - ("kkkk", TrieResult::FinalValue(0x4000)), - ("n", TrieResult::FinalValue(0x10000)), - ("ppppp", TrieResult::FinalValue(0x40000)), - ("r", TrieResult::FinalValue(0x100000)), - ("sss", TrieResult::FinalValue(0x200000)), - ("t", TrieResult::FinalValue(0x400000)), - ("uu", TrieResult::FinalValue(0x800000)), - ("vv", TrieResult::FinalValue(0x7fffffff)), - ("zz", TrieResult::FinalValue(-2147483648)), - ] { - let mut iter = trie.iter(); - for (i, chr) in query.chars().enumerate() { - let res = iter.next(chr); - if i + 1 == query.len() { - assert_eq!(res, expected); - } else { - assert_eq!(res, TrieResult::NoValue); - } - } - } -} - -#[test] -fn long_sequence() { - let trie_data = - toml::from_str::<TestFile>(include_str!("data/char16trie/test_long_sequence.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - for (query, expected) in [ - ("a", TrieResult::Intermediate(-1)), - // sequence of linear-match nodes - ( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - TrieResult::Intermediate(-2), - ), - // more than 256 units - ( - concat!( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - ), - TrieResult::FinalValue(-3), - ), - ] { - let mut iter = trie.iter(); - for (i, chr) in query.chars().enumerate() { - let res = iter.next(chr); - if i + 1 == query.len() { - assert_eq!(res, expected); - } else if i == 0 { - assert_eq!(res, TrieResult::Intermediate(-1)); - } else if i == 51 { - assert_eq!(res, TrieResult::Intermediate(-2)); - } else { - assert_eq!(res, TrieResult::NoValue); - } - } - } -} - -#[test] -fn long_branch() { - let trie_data = - toml::from_str::<TestFile>(include_str!("data/char16trie/test_long_branch.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - for (query, expected) in [ - ("a", TrieResult::FinalValue(-2)), - ("b", TrieResult::FinalValue(-1)), - ("c", TrieResult::FinalValue(0)), - ("d2", TrieResult::FinalValue(1)), - ("f", TrieResult::FinalValue(0x3f)), - ("g", TrieResult::FinalValue(0x40)), - ("h", TrieResult::FinalValue(0x41)), - ("j23", TrieResult::FinalValue(0x1900)), - ("j24", TrieResult::FinalValue(0x19ff)), - ("j25", TrieResult::FinalValue(0x1a00)), - ("k2", TrieResult::FinalValue(0x1a80)), - ("k3", TrieResult::FinalValue(0x1aff)), - ("l234567890", TrieResult::Intermediate(0x1b00)), - ("l234567890123", TrieResult::FinalValue(0x1b01)), - ( - "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", - TrieResult::FinalValue(0x10ffff), - ), - ( - "oooooooooooooooooooooooooooooooooooooooooooooooooooooo", - TrieResult::FinalValue(0x110000), - ), - ( - "pppppppppppppppppppppppppppppppppppppppppppppppppppppp", - TrieResult::FinalValue(0x120000), - ), - ("r", TrieResult::FinalValue(0x333333)), - ("s2345", TrieResult::FinalValue(0x4444444)), - ("t234567890", TrieResult::FinalValue(0x77777777)), - ("z", TrieResult::FinalValue(-2147483647)), - ] { - let mut iter = trie.iter(); - for (i, chr) in query.chars().enumerate() { - let res = iter.next(chr); - if i + 1 == query.len() { - assert_eq!(res, expected); - } else if query == "l234567890123" && i == 9 { - assert_eq!(res, TrieResult::Intermediate(0x1b00)); - } else { - assert_eq!(res, TrieResult::NoValue); - } - } - } -} - -#[test] -fn compact() { - let trie_data = toml::from_str::<TestFile>(include_str!("data/char16trie/test_compact.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - for (query, expected) in [ - ("+", TrieResult::Intermediate(0)), - ("+august", TrieResult::FinalValue(8)), - ("+december", TrieResult::FinalValue(12)), - ("+july", TrieResult::FinalValue(7)), - ("+june", TrieResult::FinalValue(6)), - ("+november", TrieResult::FinalValue(11)), - ("+october", TrieResult::FinalValue(10)), - ("+september", TrieResult::FinalValue(9)), - ("-", TrieResult::Intermediate(0)), - ("-august", TrieResult::FinalValue(8)), - ("-december", TrieResult::FinalValue(12)), - ("-july", TrieResult::FinalValue(7)), - ("-june", TrieResult::FinalValue(6)), - ("-november", TrieResult::FinalValue(11)), - ("-october", TrieResult::FinalValue(10)), - ("-september", TrieResult::FinalValue(9)), - ("xjuly", TrieResult::FinalValue(7)), - ("xjune", TrieResult::FinalValue(6)), - ] { - let mut iter = trie.iter(); - for (i, chr) in query.chars().enumerate() { - let res = iter.next(chr); - if i + 1 == query.len() { - assert_eq!(res, expected); - } else if chr == '-' || chr == '+' { - assert_eq!(res, TrieResult::Intermediate(0)); - } else { - assert_eq!(res, TrieResult::NoValue); - } - } - } -} - -#[test] -fn months() { - let trie_data = toml::from_str::<TestFile>(include_str!("data/char16trie/months.toml")) - .unwrap() - .ucharstrie - .data; - let trie = Char16Trie::new(ZeroVec::from_slice_or_alloc(trie_data.as_slice())); - - let mut iter = trie.iter(); - for (chr, expected) in [ - ('j', TrieResult::NoValue), - ('u', TrieResult::NoValue), - ('n', TrieResult::Intermediate(6)), - ('e', TrieResult::FinalValue(6)), - ] { - let res = iter.next(chr); - assert_eq!(res, expected); - } - let res = iter.next('h'); - assert_eq!(res, TrieResult::NoMatch); - - let mut iter = trie.iter(); - for (chr, expected) in [ - ('j', TrieResult::NoValue), - ('u', TrieResult::NoValue), - ('l', TrieResult::NoValue), - ('y', TrieResult::FinalValue(7)), - ] { - let res = iter.next(chr); - assert_eq!(res, expected); - } - let res = iter.next('h'); - assert_eq!(res, TrieResult::NoMatch); -} - -#[derive(serde::Deserialize)] -struct TestFile { - ucharstrie: Char16TrieVec, -} - -#[derive(serde::Deserialize)] -struct Char16TrieVec { - data: Vec<u16>, -} diff --git a/deps/crates/vendor/icu_collections-v2/tests/cpt.rs b/deps/crates/vendor/icu_collections-v2/tests/cpt.rs deleted file mode 100644 index 1218ea79558a..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/cpt.rs +++ /dev/null @@ -1,489 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -#![allow(dead_code)] - -use icu_collections::codepointtrie::planes::get_planes_trie; -use icu_collections::codepointtrie::*; -use zerovec::ZeroVec; - -#[test] -fn planes_trie_deserialize_check_test() { - // Get expected planes trie from crate::planes::get_planes_trie() - - let exp_planes_trie = get_planes_trie(); - - // Compute actual planes trie from planes.toml - - let planes_enum_prop = - ::toml::from_str::<UnicodeEnumeratedProperty>(include_str!("data/cpt/planes.toml")) - .unwrap(); - - let code_point_trie_struct = planes_enum_prop.code_point_trie.trie_struct; - - let trie_header = CodePointTrieHeader { - high_start: code_point_trie_struct.high_start, - shifted12_high_start: code_point_trie_struct.shifted12_high_start, - index3_null_offset: code_point_trie_struct.index3_null_offset, - data_null_offset: code_point_trie_struct.data_null_offset, - null_value: code_point_trie_struct.null_value, - trie_type: TrieType::try_from(code_point_trie_struct.trie_type_enum_val).unwrap_or_else( - |_| { - panic!( - "Could not parse trie_type serialized enum value in test data file: {}", - code_point_trie_struct.name - ) - }, - ), - }; - - let data = ZeroVec::from_slice_or_alloc(code_point_trie_struct.data_8.as_ref().unwrap()); - let index = ZeroVec::from_slice_or_alloc(&code_point_trie_struct.index); - let trie_result = CodePointTrie::try_new(trie_header, index, data); - let act_planes_trie = trie_result.unwrap(); - - // Get check ranges (inversion map-style sequence of range+value) and - // apply the trie validation test fn on expected and actual tries - - let serialized_ranges: Vec<(u32, u32, u32)> = planes_enum_prop.code_point_map.data.ranges; - let mut check_ranges: Vec<u32> = vec![]; - for range_tuple in serialized_ranges { - let range_end = range_tuple.1 + 1; - let value = range_tuple.2; - check_ranges.push(range_end); - check_ranges.push(value); - } - - check_trie(&act_planes_trie, &check_ranges); - check_trie(&exp_planes_trie, &check_ranges); -} - -#[test] -fn free_blocks_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/free-blocks.16.toml")); -} - -#[test] -fn free_blocks_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/free-blocks.32.toml")); -} - -#[test] -fn free_blocks_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/free-blocks.8.toml")); -} - -#[test] -fn free_blocks_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/free-blocks.small16.toml")); -} - -#[test] -fn grow_data_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/grow-data.16.toml")); -} - -#[test] -fn grow_data_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/grow-data.32.toml")); -} - -#[test] -fn grow_data_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/grow-data.8.toml")); -} - -#[test] -fn grow_data_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/grow-data.small16.toml")); -} - -#[test] -fn set1_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set1.16.toml")); -} - -#[test] -fn set1_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set1.32.toml")); -} - -#[test] -fn set1_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set1.8.toml")); -} - -#[test] -fn set1_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set1.small16.toml")); -} - -#[test] -fn set2_overlap_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set2-overlap.16.toml")); -} - -#[test] -fn set2_overlap_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set2-overlap.32.toml")); -} - -#[test] -fn set2_overlap_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set2-overlap.small16.toml")); -} - -#[test] -fn set3_initial_9_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set3-initial-9.16.toml")); -} - -#[test] -fn set3_initial_9_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set3-initial-9.32.toml")); -} - -#[test] -fn set3_initial_9_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set3-initial-9.8.toml")); -} - -#[test] -fn set3_initial_9_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set3-initial-9.small16.toml")); -} - -#[test] -fn set_empty_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-empty.16.toml")); -} - -#[test] -fn set_empty_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-empty.32.toml")); -} - -#[test] -fn set_empty_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-empty.8.toml")); -} - -#[test] -fn set_empty_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-empty.small16.toml")); -} - -#[test] -fn set_single_value_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-single-value.16.toml")); -} - -#[test] -fn set_single_value_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-single-value.32.toml")); -} - -#[test] -fn set_single_value_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-single-value.8.toml")); -} - -#[test] -fn set_single_value_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/set-single-value.small16.toml")); -} - -#[test] -fn short_all_same_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/short-all-same.16.toml")); -} - -#[test] -fn short_all_same_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/short-all-same.8.toml")); -} - -#[test] -fn short_all_same_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/short-all-same.small16.toml")); -} - -#[test] -fn small0_in_fast_16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/small0-in-fast.16.toml")); -} - -#[test] -fn small0_in_fast_32() { - run_deserialize_test_from_test_data(include_str!("data/cpt/small0-in-fast.32.toml")); -} - -#[test] -fn small0_in_fast_8() { - run_deserialize_test_from_test_data(include_str!("data/cpt/small0-in-fast.8.toml")); -} - -#[test] -fn small0_in_fast_small16() { - run_deserialize_test_from_test_data(include_str!("data/cpt/small0-in-fast.small16.toml")); -} - -/// The width of the elements in the data array of a [`CodePointTrie`]. -/// See [`UCPTrieValueWidth`](https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/ucptrie_8h.html) in ICU4C. -#[derive(Clone, Copy, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -enum ValueWidthEnum { - Bits16 = 0, - Bits32 = 1, - Bits8 = 2, -} - -/// Test .`get()` on [`CodePointTrie`] by iterating through each range in -/// `check_ranges` and assert that the associated -/// value matches the trie value for each code point in the range. -fn check_trie<T: TrieValue + Into<u32>>(trie: &CodePointTrie<T>, check_ranges: &[u32]) { - assert_eq!( - 0, - check_ranges.len() % 2, - "check_ranges must have an even number of 32-bit values in (limit,value) pairs" - ); - - let mut i: u32 = 0; - let check_range_tuples = check_ranges.chunks(2); - // Iterate over each check range - for range_tuple in check_range_tuples { - let range_limit = range_tuple[0]; - let range_value = range_tuple[1]; - // Check all values in this range, one-by-one - while i < range_limit { - assert_eq!(range_value, trie.get32(i).into(), "trie_get({i})",); - i += 1; - } - } -} - -/// Test `.get_range()` / `.iter_ranges()` on [`CodePointTrie`] by calling -/// `.iter_ranges()` on the trie. -/// -/// `.iter_ranges()` returns an iterator that produces values -/// by calls to .`get_range`, and this checks if it matches the values in `check_ranges`. -fn test_check_ranges_get_ranges<T: TrieValue + Into<u32>>( - trie: &CodePointTrie<T>, - check_ranges: &[u32], -) { - assert_eq!( - 0, - check_ranges.len() % 2, - "check_ranges must have an even number of 32-bit values in (limit,value) pairs" - ); - - let mut trie_ranges = trie.iter_ranges(); - - let mut range_start: u32 = 0; - let check_range_tuples = check_ranges.chunks(2); - // Iterate over each check range - for range_tuple in check_range_tuples { - let range_limit = range_tuple[0]; - let range_value = range_tuple[1]; - - // The check ranges array seems to start with a trivial range whose - // limit is zero. range_start is initialized to 0, so we can skip. - if range_limit == 0 { - continue; - } - - let cpm_range = trie_ranges.next(); - assert!(cpm_range.is_some(), "CodePointTrie iter_ranges() produces fewer ranges than the check_ranges field in testdata has"); - let cpm_range = cpm_range.unwrap(); - let cpmr_start = cpm_range.range.start(); - let cpmr_end = cpm_range.range.end(); - let cpmr_value: u32 = cpm_range.value.into(); - - assert_eq!(range_start, *cpmr_start); - assert_eq!(range_limit, *cpmr_end + 1); - assert_eq!(range_value, cpmr_value); - - range_start = range_limit; - } - - assert!(trie_ranges.next().is_none(), "CodePointTrie iter_ranges() produces more ranges than the check_ranges field in testdata has"); -} - -/// Run above tests that verify the validity of [`CodePointTrie`] methods -fn run_trie_tests<T: TrieValue + Into<u32>>(trie: &CodePointTrie<T>, check_ranges: &[u32]) { - check_trie(trie, check_ranges); - test_check_ranges_get_ranges(trie, check_ranges); -} - -// The following structs might be useful later for de-/serialization of the -// main `CodePointTrie` struct in the corresponding data provider. - -#[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] -struct UnicodeEnumeratedProperty { - code_point_map: EnumPropCodePointMap, - code_point_trie: EnumPropSerializedCPT, -} - -#[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] -struct EnumPropCodePointMap { - data: EnumPropCodePointMapData, -} - -#[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] -struct EnumPropCodePointMapData { - long_name: String, - name: String, - ranges: Vec<(u32, u32, u32)>, -} - -#[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] -struct EnumPropSerializedCPT { - #[cfg_attr(any(feature = "serde", test), serde(rename = "struct"))] - trie_struct: EnumPropSerializedCPTStruct, -} - -// These structs support the test data dumped as TOML files from ICU. -// Because the properties CodePointMap data will also be dumped from ICU -// using similar functions, some of these structs may be useful to refactor -// into main code at a later point. - -#[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] -struct EnumPropSerializedCPTStruct { - #[cfg_attr(any(feature = "serde", test), serde(skip))] - long_name: String, - name: String, - index: Vec<u16>, - data_8: Option<Vec<u8>>, - data_16: Option<Vec<u16>>, - data_32: Option<Vec<u32>>, - #[cfg_attr(any(feature = "serde", test), serde(skip))] - index_length: u32, - #[cfg_attr(any(feature = "serde", test), serde(skip))] - data_length: u32, - #[cfg_attr(any(feature = "serde", test), serde(rename = "highStart"))] - high_start: u32, - #[cfg_attr(any(feature = "serde", test), serde(rename = "shifted12HighStart"))] - shifted12_high_start: u16, - #[cfg_attr(any(feature = "serde", test), serde(rename = "type"))] - trie_type_enum_val: u8, - #[cfg_attr(any(feature = "serde", test), serde(rename = "valueWidth"))] - value_width_enum_val: u8, - #[cfg_attr(any(feature = "serde", test), serde(rename = "index3NullOffset"))] - index3_null_offset: u16, - #[cfg_attr(any(feature = "serde", test), serde(rename = "dataNullOffset"))] - data_null_offset: u32, - #[cfg_attr(any(feature = "serde", test), serde(rename = "nullValue"))] - null_value: u32, -} - -// Given a .toml file dumped from ICU4C test data for UCPTrie, run the test -// data file deserialization into the test file struct, convert and construct -// the `CodePointTrie`, and test the constructed struct against the test file's -// "check ranges" (inversion map ranges) using `check_trie` to verify the -// validity of the `CodePointTrie`'s behavior for all code points. -#[allow(dead_code)] -fn run_deserialize_test_from_test_data(test_file: &str) { - // The following structs are specific to the TOML format files for dumped ICU - // test data. - - #[derive(serde::Deserialize)] - struct TestFile { - code_point_trie: TestCodePointTrie, - } - - #[derive(serde::Deserialize)] - struct TestCodePointTrie { - // The trie_struct field for test data files is dumped from the same source - // (ICU4C) using the same function (usrc_writeUCPTrie) as property data - // for the provider, so we can reuse the same struct here. - #[serde(rename(deserialize = "struct"))] - trie_struct: EnumPropSerializedCPTStruct, - #[serde(rename(deserialize = "testdata"))] - test_data: TestData, - } - - #[derive(serde::Deserialize)] - struct TestData { - #[serde(rename(deserialize = "checkRanges"))] - check_ranges: Vec<u32>, - } - - let test_file = ::toml::from_str::<TestFile>(test_file).unwrap(); - - let test_struct = test_file.code_point_trie.trie_struct; - - println!( - "Running CodePointTrie reader logic test on test data file: {}", - test_struct.name - ); - - let trie_type_enum = match TrieType::try_from(test_struct.trie_type_enum_val) { - Ok(enum_val) => enum_val, - _ => { - panic!( - "Could not parse trie_type serialized enum value in test data file: {}", - test_struct.name - ); - } - }; - - let trie_header = CodePointTrieHeader { - high_start: test_struct.high_start, - shifted12_high_start: test_struct.shifted12_high_start, - index3_null_offset: test_struct.index3_null_offset, - data_null_offset: test_struct.data_null_offset, - null_value: test_struct.null_value, - trie_type: trie_type_enum, - }; - - let index = ZeroVec::from_slice_or_alloc(&test_struct.index); - - match (test_struct.data_8, test_struct.data_16, test_struct.data_32) { - (Some(data_8), _, _) => { - let data = ZeroVec::from_slice_or_alloc(&data_8); - let trie_result = CodePointTrie::try_new(trie_header, index, data); - assert!(trie_result.is_ok(), "Could not construct trie"); - assert_eq!( - test_struct.value_width_enum_val, - ValueWidthEnum::Bits8 as u8 - ); - run_trie_tests( - &trie_result.unwrap(), - &test_file.code_point_trie.test_data.check_ranges, - ); - } - - (_, Some(data_16), _) => { - let data = ZeroVec::from_slice_or_alloc(&data_16); - let trie_result = CodePointTrie::try_new(trie_header, index, data); - assert!(trie_result.is_ok(), "Could not construct trie"); - assert_eq!( - test_struct.value_width_enum_val, - ValueWidthEnum::Bits16 as u8 - ); - run_trie_tests( - &trie_result.unwrap(), - &test_file.code_point_trie.test_data.check_ranges, - ); - } - - (_, _, Some(data_32)) => { - let data = ZeroVec::from_slice_or_alloc(&data_32); - let trie_result = CodePointTrie::try_new(trie_header, index, data); - assert!(trie_result.is_ok(), "Could not construct trie"); - assert_eq!( - test_struct.value_width_enum_val, - ValueWidthEnum::Bits32 as u8 - ); - run_trie_tests( - &trie_result.unwrap(), - &test_file.code_point_trie.test_data.check_ranges, - ); - } - - (_, _, _) => { - panic!("Could not match test trie data to a known value width or trie type"); - } - }; -} diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/empty.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/empty.toml deleted file mode 100644 index 91f04b03ac17..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/empty.toml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: empty.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 32768, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/months.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/months.toml deleted file mode 100644 index 79bfd4c92df3..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/months.toml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: months.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 1,97,134,106,1,97,13,117,1,108,6,110,449,46,32774,101,32774, - 48,121,32775,48,110,147,106,72,111,22,111,32769,112,11,113,12, - 114,32769,117,49,97,114,176,121,32769,48,112,32769,49,113,113,32769, - 106,32769,107,35,108,32769,109,32769,110,58,110,110,110,110,110,110, - 110,110,110,110,110,63,110,110,110,110,110,110,110,110,110,110, - 110,110,110,110,110,110,32769,2,107,32769,108,32769,109,48,109,32769, - 101,22,101,12,102,32769,103,13,104,32769,105,50,105,105,105,32769, - 1,101,32769,102,32769,48,103,32769,46,32769,97,32769,98,7,99,32769, - 100,49,100,100,32769,48,98,32769,52,117,103,117,115,116,32776, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a.toml deleted file mode 100644 index 48f53aaa860b..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a.toml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_a.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 48,97,32769, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a_ab.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a_ab.toml deleted file mode 100644 index c4633ba56059..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_a_ab.toml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_a_ab.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 48,97,176,98,32868, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_branches.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_branches.toml deleted file mode 100644 index 1c7c62619186..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_branches.toml +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_branches.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 13,112,42,116,22,116,49216,0,117,8,118,10,122,48,122,65535,32768, - 0,48,117,49280,0,48,118,65535,32767,65535,112,9,114,49168,0,115, - 49,115,115,49184,0,51,112,112,112,112,49156,0,103,19,103,7, - 105,36864,107,7,110,49153,0,49,103,103,33792,50,107,107,107,49152, - 16384,97,32784,99,2,101,33024,48,99,32832, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_compact.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_compact.toml deleted file mode 100644 index 780ca9491a8f..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_compact.toml +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_compact.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 2,43,13,45,11,120,49,106,117,1,108,53,110,48,101,32774,69, - 110,32,110,13,111,20,115,55,101,112,116,101,109,98,101,114, - 32777,54,111,118,101,109,98,101,114,32779,53,99,116,111,98,101, - 114,32778,97,15,100,20,106,48,117,1,108,4,110,48,101,32774, - 48,121,32775,52,117,103,117,115,116,32776,54,101,99,101,109,98, - 101,114,32780, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_branch.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_branch.toml deleted file mode 100644 index 4c260ce61b38..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_branch.toml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_long_branch.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 16,107,240,112,92,112,11,114,49203,13107,115,65,116,70,122,65535,32768, - 1,52,112,112,112,112,112,63,112,112,112,112,112,112,112,112, - 112,112,112,112,112,112,112,112,63,112,112,112,112,112,112,112, - 112,112,112,112,112,112,112,112,112,63,112,112,112,112,112,112, - 112,112,112,112,112,112,112,112,112,112,49170,0,51,50,51,52, - 53,50244,17476,56,50,51,52,53,54,55,56,57,48,65535,30583,30583, - 107,64,108,67,110,81,111,52,111,111,111,111,111,63,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,63,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,63, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, - 49169,0,1,50,39552,51,39679,56,50,51,52,53,54,55,56,57, - 48,16498,6912,49,50,51,39681,52,110,110,110,110,110,63,110,110, - 110,110,110,110,110,110,110,110,110,110,110,110,110,110,63,110, - 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,63, - 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, - 49168,65535,102,16,102,32831,103,32832,104,32833,106,48,50,2,51,39168, - 52,39423,53,39424,97,65535,65535,65534,98,65535,65535,65535,99,32768,100,48, - 50,32769, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_sequence.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_sequence.toml deleted file mode 100644 index 72722a369cb6..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_long_sequence.toml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_long_sequence.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 48,97,32754,65535,65535,98,99,100,63,101,102,103,104,105,106,107,108, - 109,110,111,112,113,114,115,116,63,117,118,119,120,121,122,65, - 66,67,68,69,70,71,72,73,74,63,75,76,77,78,79,80, - 81,82,83,84,85,86,87,88,89,90,32755,65535,65534,97,98,99, - 100,63,101,102,103,104,105,106,107,108,109,110,111,112,113,114, - 115,116,63,117,118,119,120,121,122,65,66,67,68,69,70,71, - 72,73,74,63,75,76,77,78,79,80,81,82,83,84,85,86, - 87,88,89,90,63,97,98,99,100,101,102,103,104,105,106,107, - 108,109,110,111,112,63,113,114,115,116,117,118,119,120,121,122, - 65,66,67,68,69,70,63,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,63,87,88,89,90,97,98,99,100, - 101,102,103,104,105,106,107,108,63,109,110,111,112,113,114,115, - 116,117,118,119,120,121,122,65,66,63,67,68,69,70,71,72, - 73,74,75,76,77,78,79,80,81,82,63,83,84,85,86,87, - 88,89,90,97,98,99,100,101,102,103,104,63,105,106,107,108, - 109,110,111,112,113,114,115,116,117,118,119,120,63,121,122,65, - 66,67,68,69,70,71,72,73,74,75,76,77,78,63,79,80, - 81,82,83,84,85,86,87,88,89,90,97,98,99,100,63,101, - 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,63, - 117,118,119,120,121,122,65,66,67,68,69,70,71,72,73,74, - 63,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, - 90,65535,65535,65533, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_shortest_branch.toml b/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_shortest_branch.toml deleted file mode 100644 index 639cb0314c33..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/char16trie/test_shortest_branch.toml +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: test_shortest_branch.toml -# -# machine-generated by: ucharstrietest.c - -[ucharstrie] -data = [ - 1,97,33768,98,34768, -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.16.toml deleted file mode 100644 index 7febd4c3b470..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.16.toml +++ /dev/null @@ -1,113 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: free-blocks.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "free-blocks.16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0x80,0xc0,0xc0, - 0xc0,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_16 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 1,0xad -] -indexLength = 1024 -dataLength = 258 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x1 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x740,1,0x780,2,0x880,3,0x110000,1 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.32.toml deleted file mode 100644 index 002b6f260dfa..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.32.toml +++ /dev/null @@ -1,113 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: free-blocks.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "free-blocks.32" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0x80,0xc0,0xc0, - 0xc0,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_32 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 1,0xad -] -indexLength = 1024 -dataLength = 258 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 1 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x1 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x740,1,0x780,2,0x880,3,0x110000,1 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.8.toml deleted file mode 100644 index c8c469cedc4e..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.8.toml +++ /dev/null @@ -1,113 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: free-blocks.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "free-blocks.8" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0x80,0xc0,0xc0, - 0xc0,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_8 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 1,1,1,0xad -] -indexLength = 1024 -dataLength = 260 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 2 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x1 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x740,1,0x780,2,0x880,3,0x110000,1 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.small16.toml deleted file mode 100644 index 8a88bcb03180..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/free-blocks.small16.toml +++ /dev/null @@ -1,53 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: free-blocks.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "free-blocks.small16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0x80,0xc0,0xc0, - 0xc0,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_16 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 1,0xad -] -indexLength = 64 -dataLength = 258 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 1 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x1 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x740,1,0x780,2,0x880,3,0x110000,1 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.16.toml deleted file mode 100644 index 4977ec0d856d..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.16.toml +++ /dev/null @@ -1,117 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: grow-data.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "grow-data.16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x80,0xa0,0xc0, - 0xc0,0xc0,0xe0,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100 -] -data_16 = [ - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0xad -] -indexLength = 1024 -dataLength = 322 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x100 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x720,2,0x7a0,3,0x8a0,4,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.32.toml deleted file mode 100644 index 01ea3c3adffd..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.32.toml +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: grow-data.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "grow-data.32" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x80,0xa0,0xc0, - 0xc0,0xc0,0xe0,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100 -] -data_32 = [ - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 0xad -] -indexLength = 1024 -dataLength = 321 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 1 -index3NullOffset = 0x7fff -dataNullOffset = 0x100 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x720,2,0x7a0,3,0x8a0,4,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.8.toml deleted file mode 100644 index ef2c0956a6e6..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.8.toml +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: grow-data.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "grow-data.8" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x80,0xa0,0xc0, - 0xc0,0xc0,0xe0,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100 -] -data_8 = [ - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,0xad -] -indexLength = 1024 -dataLength = 324 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 2 -index3NullOffset = 0x7fff -dataNullOffset = 0x100 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x720,2,0x7a0,3,0x8a0,4,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.small16.toml deleted file mode 100644 index 1e761f166ca3..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/grow-data.small16.toml +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: grow-data.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "grow-data.small16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x80,0xa0,0xc0, - 0xc0,0xc0,0xe0,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100 -] -data_16 = [ - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0xad -] -indexLength = 64 -dataLength = 322 -highStart = 0xa00 -shifted12HighStart = 0x1 -type = 1 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x100 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,1,0x720,2,0x7a0,3,0x8a0,4,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/planes.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/planes.toml deleted file mode 100644 index d5f5e7d81603..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/planes.toml +++ /dev/null @@ -1,140 +0,0 @@ -# This file is part of ICU4X. For terms of use, please see the file -# called LICENSE at the top level of the ICU4X source tree -# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -[code_point_map.data] -long_name = "planes" -name = "planes" -ranges = [ - [0x0, 0xffff, 0], - [0x10000, 0x1ffff, 1], - [0x20000, 0x2ffff, 2], - [0x30000, 0x3ffff, 3], - [0x40000, 0x4ffff, 4], - [0x50000, 0x5ffff, 5], - [0x60000, 0x6ffff, 6], - [0x70000, 0x7ffff, 7], - [0x80000, 0x8ffff, 8], - [0x90000, 0x9ffff, 9], - [0xa0000, 0xaffff, 10], - [0xb0000, 0xbffff, 11], - [0xc0000, 0xcffff, 12], - [0xd0000, 0xdffff, 13], - [0xe0000, 0xeffff, 14], - [0xf0000, 0xfffff, 15], - [0x100000, 0x10ffff, 16], -] - -[code_point_trie.struct] -long_name = "planes" -name = "planes" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x288,0x290,0x290,0x290,0x2b0,0x2b0,0x2b0,0x2b0,0x2d0,0x2d0,0x2d0,0x2d0,0x2f0,0x2f0,0x2f0,0x2f0, - 0x310,0x310,0x310,0x310,0x330,0x330,0x330,0x330,0x350,0x350,0x350,0x350,0x370,0x370,0x370,0x370, - 0x390,0x390,0x390,0x390,0x3b0,0x3b0,0x3b0,0x3b0,0x3d0,0x3d0,0x3d0,0x3d0,0x3f0,0x3f0,0x3f0,0x3f0, - 0x410,0x410,0x410,0x410,0x430,0x430,0x430,0x430,0x450,0x450,0x450,0x450,0x470,0x470,0x470,0x470, - 0,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0,0x10,0x20,0x30,0,0x10,0x20,0x30, - 0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30, - 0,0x10,0x20,0x30,0,0x10,0x20,0x30,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0, - 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0, - 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0, - 0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0, - 0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, - 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, - 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100, - 0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x100,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110, - 0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110, - 0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120, - 0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120, - 0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x120,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130, - 0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130, - 0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x130,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140, - 0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140, - 0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x140,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150, - 0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150, - 0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x150,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160, - 0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160, - 0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x160,0x80,0x88,0x88,0x88,0x88,0x88,0x88,0x88, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, - 0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, - 0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8, - 0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8, - 0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8, - 0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8, - 0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108, - 0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108, - 0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128, - 0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128,0x128, - 0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148, - 0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148,0x148, - 0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168, - 0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168,0x168, - 0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188, - 0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188, - 0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8, - 0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8,0x1a8, - 0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8, - 0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8, - 0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8, - 0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8,0x1e8, - 0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208, - 0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208,0x208, - 0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228, - 0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228, - 0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248, - 0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248,0x248, - 0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268, - 0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268,0x268 -] -data_8 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc, - 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, - 0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0x10,0x10,0x10,0 -] -indexLength = 1168 -dataLength = 372 -highStart = 0x100000 -shifted12HighStart = 0x100 -type = 1 -valueWidth = 2 -index3NullOffset = 0x2 -dataNullOffset = 0x0 -nullValue = 0x0 diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.16.toml deleted file mode 100644 index b9ec8ed16ec9..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.16.toml +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-empty.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-empty.16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_16 = [ - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,0xad -] -indexLength = 1024 -dataLength = 130 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 0 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x3 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,3 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.32.toml deleted file mode 100644 index cc3e16726431..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.32.toml +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-empty.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-empty.32" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_32 = [ - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 0xad -] -indexLength = 1024 -dataLength = 129 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 0 -valueWidth = 1 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x3 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,3 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.8.toml deleted file mode 100644 index 5ce7bba5b5f5..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.8.toml +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-empty.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-empty.8" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_8 = [ - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,0xad -] -indexLength = 1024 -dataLength = 132 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 0 -valueWidth = 2 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x3 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,3 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.small16.toml deleted file mode 100644 index f61d9fe18ad1..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-empty.small16.toml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-empty.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-empty.small16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_16 = [ - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,0xad -] -indexLength = 64 -dataLength = 130 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 1 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x3 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,3 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.16.toml deleted file mode 100644 index 6eac4b7bdc8a..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.16.toml +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-single-value.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-single-value.16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_16 = [ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0xad -] -indexLength = 1024 -dataLength = 130 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 0 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.32.toml deleted file mode 100644 index 9db848236d6a..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.32.toml +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-single-value.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-single-value.32" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_32 = [ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 0xad -] -indexLength = 1024 -dataLength = 129 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 0 -valueWidth = 1 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.8.toml deleted file mode 100644 index c92b7a8e1e5d..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.8.toml +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-single-value.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-single-value.8" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_8 = [ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,0xad -] -indexLength = 1024 -dataLength = 132 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 0 -valueWidth = 2 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.small16.toml deleted file mode 100644 index 568362f5565a..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set-single-value.small16.toml +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set-single-value.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set-single-value.small16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -] -data_16 = [ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,0xad -] -indexLength = 64 -dataLength = 130 -highStart = 0x0 -shifted12HighStart = 0x0 -type = 1 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x0 -nullValue = 0x5 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,3,0x110000,5 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.16.toml deleted file mode 100644 index e064217ae6f5..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.16.toml +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set1.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set1.16" -index = [ - 0,0x40,0x40,0x59,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0xb3,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xfb,0x121,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x14d,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x495,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x4bc,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4df,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x1ba,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x1c6,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x1d3,0x1da,0x1da,0x1da,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x439,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0x455,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x475 -] -data_16 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0,0,0,0,0,0, - 0,0,0,0,0,0,0xf,0x10,0x10,0x11,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0,0xad -] -indexLength = 1248 -dataLength = 492 -highStart = 0xf0200 -shifted12HighStart = 0xf1 -type = 0 -valueWidth = 0 -index3NullOffset = 0x4 -dataNullOffset = 0x0 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x40,0,0xe7,0x34,0x3400,0,0x9fa6,0x61,0xda9e,0x31,0xdada,0,0xeeee,0xff, - 0x11111,1,0x44444,0x61,0xf0003,0,0xf0004,0xf,0xf0006,0x10,0xf0007,0x11,0xf0040,0x12,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.32.toml deleted file mode 100644 index 9b7299b37ff8..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.32.toml +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set1.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set1.32" -index = [ - 0,0x40,0x40,0x59,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0xb3,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xfb,0x121,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x14d,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x495,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x4bc,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4df,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x1ba,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x1c6,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x1d3,0x1da,0x1da,0x1da,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x439,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0x455,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x475 -] -data_32 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0,0,0,0,0,0, - 0,0,0,0,0,0,0xf,0x10,0x10,0x11,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0,0xad -] -indexLength = 1248 -dataLength = 492 -highStart = 0xf0200 -shifted12HighStart = 0xf1 -type = 0 -valueWidth = 1 -index3NullOffset = 0x4 -dataNullOffset = 0x0 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x40,0,0xe7,0x34,0x3400,0,0x9fa6,0x61,0xda9e,0x31,0xdada,0,0xeeee,0xff, - 0x11111,1,0x44444,0x61,0xf0003,0,0xf0004,0xf,0xf0006,0x10,0xf0007,0x11,0xf0040,0x12,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.8.toml deleted file mode 100644 index 4d06bf9d3bb6..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.8.toml +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set1.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set1.8" -index = [ - 0,0x40,0x40,0x59,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0xb3,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xfb,0x121,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b, - 0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x14d,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x495,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x4bc,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf, - 0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4df,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b, - 0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x17b,0x1ba,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x1c6,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x1d3,0x1da,0x1da,0x1da,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x3bc,0x439,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0x455,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x475 -] -data_8 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0,0,0,0,0,0, - 0,0,0,0,0,0,0xf,0x10,0x10,0x11,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0,0xad -] -indexLength = 1248 -dataLength = 492 -highStart = 0xf0200 -shifted12HighStart = 0xf1 -type = 0 -valueWidth = 2 -index3NullOffset = 0x4 -dataNullOffset = 0x0 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x40,0,0xe7,0x34,0x3400,0,0x9fa6,0x61,0xda9e,0x31,0xdada,0,0xeeee,0xff, - 0x11111,1,0x44444,0x61,0xf0003,0,0xf0004,0xf,0xf0006,0x10,0xf0007,0x11,0xf0040,0x12,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.small16.toml deleted file mode 100644 index 1a7241775911..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set1.small16.toml +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set1.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set1.small16" -index = [ - 0,0x40,0x40,0x59,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x17f,0x199,0x1aa,0x1bd,0x1d5,0x199,0x199,0x199,0x199,0x199,0x199,0x199,0x199,0x199,0x199,0x199, - 0x199,0x1f3,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6, - 0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6, - 0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x1f6,0x216,0,0x10,0x20, - 0x30,0x40,0x50,0x60,0x70,0x40,0x50,0x60,0x70,0x59,0x69,0x79,0x89,0,0x10,0x20, - 0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20, - 0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0xa3,0xa9,0xa9, - 0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9, - 0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xab,0, - 0,0,0xb9,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, - 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, - 0xc3,0xc3,0xc3,0xc5,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3, - 0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3, - 0xd3,0xd3,0xd3,0xd3,0xe2,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x99,0x99,0x99,0xee,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xfb, - 0x102,0x102,0x102,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x7d, - 0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,0xad,0xad,0xad,0xad,0xad,0xad,0xad, - 0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad, - 0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xb3,0xce,0xce,0xce,0xce,0xce,0xce, - 0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xe5,0xf3,0xf3,0xf3,0xf3,0xf3, - 0xf3,0xf3,0xf3,0xf3,0x105,0x114,0x114,0x114,0x114,0x114,0x114,0x114,0x114,0x123,0xad,0xad, - 0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad, - 0xad,0xad,0xad,0xad,0xad,0x13f,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,0x15f -] -data_16 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0,0,0,0,0,0,0, - 0,0,0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x61,0x61,0,0,0,0,0,0,0,0,0,0,0,0,0xf,0x10, - 0x10,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x12,0x12,0xad,0,0xad -] -indexLength = 535 -dataLength = 277 -highStart = 0xf0200 -shifted12HighStart = 0xf1 -type = 1 -valueWidth = 0 -index3NullOffset = 0x4 -dataNullOffset = 0x0 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x40,0,0xe7,0x34,0x3400,0,0x9fa6,0x61,0xda9e,0x31,0xdada,0,0xeeee,0xff, - 0x11111,1,0x44444,0x61,0xf0003,0,0xf0004,0xf,0xf0006,0x10,0xf0007,0x11,0xf0040,0x12,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.16.toml deleted file mode 100644 index 79bed6eae236..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.16.toml +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set2-overlap.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set2-overlap.16" -index = [ - 0,0x40,0x72,0x95,0xb3,0xb3,0xb3,0xb3,0xf2,0xf2,0xf2,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0x45e,0x45e,0x45e,0x45e,0x45e,0x45e,0x45e,0x462,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0x132,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135, - 0x13e,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x14d,0x135,0x135,0x135,0x135,0x135, - 0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135, - 0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x155,0x161,0x161,0x161,0x161, - 0x161,0x161,0x161,0x161,0x161,0x161,0x161,0x161,0x167,0x172,0xb3,0xb3,0xb3,0xb3,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x408,0x421, - 0x42b,0x43e -] -data_16 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,0,0,0,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7a,0x7a,0x7a,0x7a,0x7a,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7a,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,2,0,0,0,0,0,0,0,0,0,0,0,7,7,7, - 7,7,0,0xad -] -indexLength = 1154 -dataLength = 388 -highStart = 0x30000 -shifted12HighStart = 0x30 -type = 0 -valueWidth = 0 -index3NullOffset = 0xb -dataNullOffset = 0xb3 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x21,0,0x72,0x5555,0xdd,3,0xde,4,0x201,0,0x240,6,0x241,0, - 0x280,6,0x281,0,0x2c0,6,0x2f883,0,0x2f987,0x7a,0x2fa98,5,0x2fedc,0x7a,0x2ffaa,1, - 0x2ffab,2,0x2ffbb,0,0x2ffc0,7,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.32.toml deleted file mode 100644 index 7582d9608ee5..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.32.toml +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set2-overlap.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set2-overlap.32" -index = [ - 0,0x40,0x72,0x95,0xb3,0xb3,0xb3,0xb3,0xf2,0xf2,0xf2,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0x45e,0x45e,0x45e,0x45e,0x45e,0x45e,0x45e,0x462,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0x132,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135, - 0x13e,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x14d,0x135,0x135,0x135,0x135,0x135, - 0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135, - 0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x155,0x161,0x161,0x161,0x161, - 0x161,0x161,0x161,0x161,0x161,0x161,0x161,0x161,0x167,0x172,0xb3,0xb3,0xb3,0xb3,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0x408,0x421, - 0x42b,0x43e -] -data_32 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,0,0,0,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7a,0x7a,0x7a,0x7a,0x7a,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7a,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,2,0,0,0,0,0,0,0,0,0,0,0,7,7,7, - 7,7,0,0xad -] -indexLength = 1154 -dataLength = 388 -highStart = 0x30000 -shifted12HighStart = 0x30 -type = 0 -valueWidth = 1 -index3NullOffset = 0xb -dataNullOffset = 0xb3 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x21,0,0x72,0x5555,0xdd,3,0xde,4,0x201,0,0x240,6,0x241,0, - 0x280,6,0x281,0,0x2c0,6,0x2f883,0,0x2f987,0x7a,0x2fa98,5,0x2fedc,0x7a,0x2ffaa,1, - 0x2ffab,2,0x2ffbb,0,0x2ffc0,7,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.small16.toml deleted file mode 100644 index 08741aca228e..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set2-overlap.small16.toml +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set2-overlap.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set2-overlap.small16" -index = [ - 0,0x40,0x72,0x95,0xb3,0xb3,0xb3,0xb3,0xf2,0xf2,0xf2,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xee,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xfa,0,0x10,0x20,0x30, - 0x40,0x50,0x60,0x70,0x72,0x82,0x92,0xa2,0x95,0xa5,0xb5,0xc5,0xb3,0xc3,0xd3,0xe3, - 0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3,0xf2,0x102,0x112,0x122, - 0xf2,0x102,0x112,0x122,0xf2,0x102,0x112,0x122,0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3, - 0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3, - 0xb3,0xc3,0xd3,0xe3,0xb3,0xc3,0xd3,0xe3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0x132,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135, - 0x13e,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x145,0x14d,0x135,0x135,0x135,0x135,0x135, - 0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135, - 0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x135,0x155,0x161,0x161,0x161,0x161, - 0x161,0x161,0x161,0x161,0x161,0x161,0x161,0x161,0x167,0x172,0xb3,0xb3,0xb3,0xb3,0x4c,0x6c, - 0x78,0x78,0x78,0x78,0x78,0x78,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xb,0xb,0xb,0xb,0xb,0xb,0x98,0xb1,0xbb,0xce -] -data_16 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555, - 0x5555,0x5555,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,0,0,0,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7a,0x7a,0x7a,0x7a,0x7a,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7a,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,2,0,0,0,0,0,0,0,0,0,0,0,7,7,7, - 7,7,0,0xad -] -indexLength = 282 -dataLength = 388 -highStart = 0x30000 -shifted12HighStart = 0x30 -type = 1 -valueWidth = 0 -index3NullOffset = 0xb -dataNullOffset = 0xb3 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,0,0x21,0,0x72,0x5555,0xdd,3,0xde,4,0x201,0,0x240,6,0x241,0, - 0x280,6,0x281,0,0x2c0,6,0x2f883,0,0x2f987,0x7a,0x2fa98,5,0x2fedc,0x7a,0x2ffaa,1, - 0x2ffab,2,0x2ffbb,0,0x2ffc0,7,0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.16.toml deleted file mode 100644 index c94365e84cc9..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.16.toml +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set3-initial-9.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set3-initial-9.16" -index = [ - 0,0x40,0x5c,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xf7,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x177, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x1a6,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x1da,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6 -] -data_16 = [ - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,9,9,9,9,9,9,9,9,9, - 9,9,9,9,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,0xad -] -indexLength = 1024 -dataLength = 552 -highStart = 0xce00 -shifted12HighStart = 0xd -type = 0 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0x80 -nullValue = 0x9 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,9,0x31,9,0xa4,1,0x3400,9,0x6789,2,0x9000,9,0xa000,4,0xabcd,9, - 0xbcde,3,0xcccc,9,0x110000,6 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.32.toml deleted file mode 100644 index 1a0c9732c8df..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.32.toml +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set3-initial-9.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set3-initial-9.32" -index = [ - 0,0x40,0x5c,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xf7,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x177, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x1a6,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x1da,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6 -] -data_32 = [ - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,9,9,9,9,9,9,9,9,9, - 9,9,9,9,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,0xad -] -indexLength = 1024 -dataLength = 551 -highStart = 0xce00 -shifted12HighStart = 0xd -type = 0 -valueWidth = 1 -index3NullOffset = 0x7fff -dataNullOffset = 0x80 -nullValue = 0x9 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,9,0x31,9,0xa4,1,0x3400,9,0x6789,2,0x9000,9,0xa000,4,0xabcd,9, - 0xbcde,3,0xcccc,9,0x110000,6 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.8.toml deleted file mode 100644 index 5008268b71ac..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.8.toml +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set3-initial-9.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set3-initial-9.8" -index = [ - 0,0x40,0x5c,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xf7,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137,0x137, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x177, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184,0x184, - 0x184,0x184,0x184,0x1a6,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x1da,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6, - 0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6 -] -data_8 = [ - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,9,9,9,9,9,9,9,9,9, - 9,9,9,9,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,0xad -] -indexLength = 1024 -dataLength = 552 -highStart = 0xce00 -shifted12HighStart = 0xd -type = 0 -valueWidth = 2 -index3NullOffset = 0x7fff -dataNullOffset = 0x80 -nullValue = 0x9 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,9,0x31,9,0xa4,1,0x3400,9,0x6789,2,0x9000,9,0xa000,4,0xabcd,9, - 0xbcde,3,0xcccc,9,0x110000,6 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.small16.toml deleted file mode 100644 index aee1538455db..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/set3-initial-9.small16.toml +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: set3-initial-9.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "set3-initial-9.small16" -index = [ - 0,0x40,0x5c,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x11c,0x136,0x14e,0x16d,0,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x5c,0x6c,0x7c,0x8c, - 0x80,0x90,0xa0,0xb0,0x80,0x90,0xa0,0xb0,0x80,0x90,0xa0,0xb0,0x80,0x90,0xa0,0xb0, - 0x80,0x90,0xa0,0xb0,0x80,0x90,0xa0,0xb0,0x80,0x90,0xa0,0xb0,0x80,0x90,0xa0,0xb0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc7,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7, - 0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7, - 0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0xe7,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4, - 0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4, - 0xf4,0xf4,0xf4,0xf4,0xf4,0xf6,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x104,0x110,0x110,0x110,0x110,0x110,0x110,0x110, - 0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x110,0x44,0x50,0x50,0x50, - 0x50,0x50,0x50,0x50,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70, - 0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x78,3,3,3,3,3,3, - 3,3,3,3,3,3,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,3,3, - 3,3,3,0xb8,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xe8,3,3,3, - 3,3,3,0xfc -] -data_16 = [ - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 9,9,9,9,9,9,9,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,9,9,9,9,9,9,9,9,9, - 9,9,9,9,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,9,9,9,9,9,9,9,9,9,9,9,9, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,0xad -] -indexLength = 372 -dataLength = 290 -highStart = 0xce00 -shifted12HighStart = 0xd -type = 1 -valueWidth = 0 -index3NullOffset = 0x3 -dataNullOffset = 0x80 -nullValue = 0x9 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0,9,0x31,9,0xa4,1,0x3400,9,0x6789,2,0x9000,9,0xa000,4,0xabcd,9, - 0xbcde,3,0xcccc,9,0x110000,6 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.16.toml deleted file mode 100644 index c8156e69b005..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.16.toml +++ /dev/null @@ -1,321 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: short-all-same.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "short-all-same.small16" -index = [ - 0,0x40,0x80,0xc0,0x100,0x140,0x180,0x1c0,0x200,0x240,0x280,0x2c0,0x300,0x340,0x380,0x3c0, - 0x400,0x440,0x480,0x4c0,0x500,0x540,0x580,0x5c0,0x600,0x640,0x680,0x6c0,0x700,0x740,0x780,0x7c0, - 0x800,0x840,0x880,0x8c0,0x900,0x940,0x980,0x9c0,0xa00,0xa40,0xa80,0xac0,0xb00,0xb40,0xb80,0xbc0, - 0xc00,0xc40,0xc80,0xcc0,0xd00,0xd40,0xd80,0xdc0,0xe00,0xe40,0xe80,0xec0,0xf00,0xf40,0xf80,0xfc0 -] -data_16 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc, - 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, - 0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, - 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, - 0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d, - 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, - 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21, - 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, - 0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23, - 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, - 0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25, - 0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26, - 0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27, - 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28, - 0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29, - 0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a, - 0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b, - 0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c, - 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, - 0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e, - 0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f, - 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, - 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, - 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, - 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, - 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, - 0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39, - 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, - 0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b, - 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, - 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, - 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, - 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, - 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43, - 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, - 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45, - 0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, - 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47, - 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, - 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, - 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, - 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, - 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, - 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, - 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, - 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, - 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50, - 0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51, - 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52, - 0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53, - 0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54, - 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, - 0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56, - 0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57, - 0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, - 0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a, - 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, - 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, - 0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, - 0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e, - 0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f, - 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, - 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, - 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, - 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, - 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, - 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, - 0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68, - 0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69, - 0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a, - 0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b, - 0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c, - 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d, - 0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e, - 0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f, - 0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70, - 0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71, - 0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72, - 0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73, - 0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74, - 0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75, - 0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76, - 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77, - 0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78, - 0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79, - 0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b, - 0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c, - 0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d, - 0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e, - 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81, - 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, - 0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85, - 0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86, - 0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87, - 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88, - 0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89, - 0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a, - 0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b, - 0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c, - 0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d, - 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, - 0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91, - 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92, - 0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, - 0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94, - 0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95, - 0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96, - 0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97, - 0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a, - 0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b, - 0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c, - 0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d, - 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e, - 0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f, - 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0, - 0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1, - 0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2, - 0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3, - 0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4, - 0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5, - 0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6, - 0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7, - 0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, - 0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9, - 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, - 0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab, - 0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac, - 0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad, - 0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae, - 0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf, - 0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0, - 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, - 0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4, - 0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5, - 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6, - 0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7, - 0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8, - 0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9, - 0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba, - 0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb, - 0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc, - 0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd, - 0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe, - 0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, - 0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2, - 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, - 0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4, - 0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5, - 0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6, - 0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7, - 0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8, - 0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9, - 0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca, - 0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb, - 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, - 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd, - 0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce, - 0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2, - 0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3, - 0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4, - 0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5, - 0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6, - 0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7, - 0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda, - 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb, - 0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc, - 0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd, - 0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde, - 0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2, - 0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3, - 0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4, - 0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5, - 0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6, - 0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7, - 0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8, - 0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9, - 0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea, - 0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb, - 0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec, - 0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed, - 0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee, - 0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef, - 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, - 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1, - 0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2, - 0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3, - 0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4, - 0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5, - 0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, - 0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, - 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, - 0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb, - 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, - 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, - 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0,0xad -] -indexLength = 64 -dataLength = 4098 -highStart = 0x1000 -shifted12HighStart = 0x1 -type = 1 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0xfffff -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x10,0,0x20,1,0x30,2,0x40,3,0x50,4,0x60,5,0x70,6,0x80,7, - 0x90,8,0xa0,9,0xb0,0xa,0xc0,0xb,0xd0,0xc,0xe0,0xd,0xf0,0xe,0x100,0xf, - 0x110,0x10,0x120,0x11,0x130,0x12,0x140,0x13,0x150,0x14,0x160,0x15,0x170,0x16,0x180,0x17, - 0x190,0x18,0x1a0,0x19,0x1b0,0x1a,0x1c0,0x1b,0x1d0,0x1c,0x1e0,0x1d,0x1f0,0x1e,0x200,0x1f, - 0x210,0x20,0x220,0x21,0x230,0x22,0x240,0x23,0x250,0x24,0x260,0x25,0x270,0x26,0x280,0x27, - 0x290,0x28,0x2a0,0x29,0x2b0,0x2a,0x2c0,0x2b,0x2d0,0x2c,0x2e0,0x2d,0x2f0,0x2e,0x300,0x2f, - 0x310,0x30,0x320,0x31,0x330,0x32,0x340,0x33,0x350,0x34,0x360,0x35,0x370,0x36,0x380,0x37, - 0x390,0x38,0x3a0,0x39,0x3b0,0x3a,0x3c0,0x3b,0x3d0,0x3c,0x3e0,0x3d,0x3f0,0x3e,0x400,0x3f, - 0x410,0x40,0x420,0x41,0x430,0x42,0x440,0x43,0x450,0x44,0x460,0x45,0x470,0x46,0x480,0x47, - 0x490,0x48,0x4a0,0x49,0x4b0,0x4a,0x4c0,0x4b,0x4d0,0x4c,0x4e0,0x4d,0x4f0,0x4e,0x500,0x4f, - 0x510,0x50,0x520,0x51,0x530,0x52,0x540,0x53,0x550,0x54,0x560,0x55,0x570,0x56,0x580,0x57, - 0x590,0x58,0x5a0,0x59,0x5b0,0x5a,0x5c0,0x5b,0x5d0,0x5c,0x5e0,0x5d,0x5f0,0x5e,0x600,0x5f, - 0x610,0x60,0x620,0x61,0x630,0x62,0x640,0x63,0x650,0x64,0x660,0x65,0x670,0x66,0x680,0x67, - 0x690,0x68,0x6a0,0x69,0x6b0,0x6a,0x6c0,0x6b,0x6d0,0x6c,0x6e0,0x6d,0x6f0,0x6e,0x700,0x6f, - 0x710,0x70,0x720,0x71,0x730,0x72,0x740,0x73,0x750,0x74,0x760,0x75,0x770,0x76,0x780,0x77, - 0x790,0x78,0x7a0,0x79,0x7b0,0x7a,0x7c0,0x7b,0x7d0,0x7c,0x7e0,0x7d,0x7f0,0x7e,0x800,0x7f, - 0x810,0x80,0x820,0x81,0x830,0x82,0x840,0x83,0x850,0x84,0x860,0x85,0x870,0x86,0x880,0x87, - 0x890,0x88,0x8a0,0x89,0x8b0,0x8a,0x8c0,0x8b,0x8d0,0x8c,0x8e0,0x8d,0x8f0,0x8e,0x900,0x8f, - 0x910,0x90,0x920,0x91,0x930,0x92,0x940,0x93,0x950,0x94,0x960,0x95,0x970,0x96,0x980,0x97, - 0x990,0x98,0x9a0,0x99,0x9b0,0x9a,0x9c0,0x9b,0x9d0,0x9c,0x9e0,0x9d,0x9f0,0x9e,0xa00,0x9f, - 0xa10,0xa0,0xa20,0xa1,0xa30,0xa2,0xa40,0xa3,0xa50,0xa4,0xa60,0xa5,0xa70,0xa6,0xa80,0xa7, - 0xa90,0xa8,0xaa0,0xa9,0xab0,0xaa,0xac0,0xab,0xad0,0xac,0xae0,0xad,0xaf0,0xae,0xb00,0xaf, - 0xb10,0xb0,0xb20,0xb1,0xb30,0xb2,0xb40,0xb3,0xb50,0xb4,0xb60,0xb5,0xb70,0xb6,0xb80,0xb7, - 0xb90,0xb8,0xba0,0xb9,0xbb0,0xba,0xbc0,0xbb,0xbd0,0xbc,0xbe0,0xbd,0xbf0,0xbe,0xc00,0xbf, - 0xc10,0xc0,0xc20,0xc1,0xc30,0xc2,0xc40,0xc3,0xc50,0xc4,0xc60,0xc5,0xc70,0xc6,0xc80,0xc7, - 0xc90,0xc8,0xca0,0xc9,0xcb0,0xca,0xcc0,0xcb,0xcd0,0xcc,0xce0,0xcd,0xcf0,0xce,0xd00,0xcf, - 0xd10,0xd0,0xd20,0xd1,0xd30,0xd2,0xd40,0xd3,0xd50,0xd4,0xd60,0xd5,0xd70,0xd6,0xd80,0xd7, - 0xd90,0xd8,0xda0,0xd9,0xdb0,0xda,0xdc0,0xdb,0xdd0,0xdc,0xde0,0xdd,0xdf0,0xde,0xe00,0xdf, - 0xe10,0xe0,0xe20,0xe1,0xe30,0xe2,0xe40,0xe3,0xe50,0xe4,0xe60,0xe5,0xe70,0xe6,0xe80,0xe7, - 0xe90,0xe8,0xea0,0xe9,0xeb0,0xea,0xec0,0xeb,0xed0,0xec,0xee0,0xed,0xef0,0xee,0xf00,0xef, - 0xf10,0xf0,0xf20,0xf1,0xf30,0xf2,0xf40,0xf3,0xf50,0xf4,0xf60,0xf5,0xf70,0xf6,0xf80,0xf7, - 0xf90,0xf8,0xfa0,0xf9,0xfb0,0xfa,0xfc0,0xfb,0xfd0,0xfc,0xfe0,0xfd,0xff0,0xfe,0x1000,0xff, - 0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.8.toml deleted file mode 100644 index e1b264884780..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.8.toml +++ /dev/null @@ -1,385 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: short-all-same.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "short-all-same.8" -index = [ - 0,0x40,0x80,0xc0,0x100,0x140,0x180,0x1c0,0x200,0x240,0x280,0x2c0,0x300,0x340,0x380,0x3c0, - 0x400,0x440,0x480,0x4c0,0x500,0x540,0x580,0x5c0,0x600,0x640,0x680,0x6c0,0x700,0x740,0x780,0x7c0, - 0x800,0x840,0x880,0x8c0,0x900,0x940,0x980,0x9c0,0xa00,0xa40,0xa80,0xac0,0xb00,0xb40,0xb80,0xbc0, - 0xc00,0xc40,0xc80,0xcc0,0xd00,0xd40,0xd80,0xdc0,0xe00,0xe40,0xe80,0xec0,0xf00,0xf40,0xf80,0xfc0, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, - 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000 -] -data_8 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc, - 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, - 0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, - 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, - 0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d, - 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, - 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21, - 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, - 0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23, - 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, - 0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25, - 0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26, - 0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27, - 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28, - 0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29, - 0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a, - 0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b, - 0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c, - 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, - 0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e, - 0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f, - 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, - 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, - 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, - 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, - 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, - 0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39, - 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, - 0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b, - 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, - 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, - 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, - 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, - 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43, - 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, - 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45, - 0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, - 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47, - 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, - 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, - 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, - 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, - 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, - 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, - 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, - 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, - 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50, - 0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51, - 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52, - 0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53, - 0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54, - 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, - 0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56, - 0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57, - 0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, - 0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a, - 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, - 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, - 0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, - 0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e, - 0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f, - 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, - 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, - 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, - 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, - 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, - 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, - 0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68, - 0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69, - 0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a, - 0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b, - 0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c, - 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d, - 0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e, - 0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f, - 0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70, - 0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71, - 0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72, - 0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73, - 0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74, - 0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75, - 0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76, - 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77, - 0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78, - 0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79, - 0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b, - 0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c, - 0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d, - 0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e, - 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81, - 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, - 0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85, - 0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86, - 0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87, - 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88, - 0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89, - 0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a, - 0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b, - 0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c, - 0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d, - 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, - 0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91, - 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92, - 0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, - 0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94, - 0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95, - 0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96, - 0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97, - 0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a, - 0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b, - 0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c, - 0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d, - 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e, - 0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f, - 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0, - 0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1, - 0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2, - 0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3, - 0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4, - 0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5, - 0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6, - 0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7, - 0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, - 0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9, - 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, - 0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab, - 0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac, - 0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad, - 0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae, - 0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf, - 0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0, - 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, - 0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4, - 0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5, - 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6, - 0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7, - 0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8, - 0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9, - 0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba, - 0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb, - 0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc, - 0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd, - 0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe, - 0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, - 0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2, - 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, - 0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4, - 0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5, - 0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6, - 0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7, - 0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8, - 0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9, - 0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca, - 0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb, - 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, - 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd, - 0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce, - 0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2, - 0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3, - 0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4, - 0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5, - 0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6, - 0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7, - 0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda, - 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb, - 0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc, - 0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd, - 0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde, - 0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2, - 0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3, - 0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4, - 0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5, - 0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6, - 0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7, - 0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8, - 0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9, - 0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea, - 0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb, - 0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec, - 0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed, - 0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee, - 0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef, - 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, - 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1, - 0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2, - 0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3, - 0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4, - 0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5, - 0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, - 0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, - 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, - 0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb, - 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, - 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, - 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0xad -] -indexLength = 1024 -dataLength = 4164 -highStart = 0x1000 -shifted12HighStart = 0x1 -type = 0 -valueWidth = 2 -index3NullOffset = 0x7fff -dataNullOffset = 0x1000 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x10,0,0x20,1,0x30,2,0x40,3,0x50,4,0x60,5,0x70,6,0x80,7, - 0x90,8,0xa0,9,0xb0,0xa,0xc0,0xb,0xd0,0xc,0xe0,0xd,0xf0,0xe,0x100,0xf, - 0x110,0x10,0x120,0x11,0x130,0x12,0x140,0x13,0x150,0x14,0x160,0x15,0x170,0x16,0x180,0x17, - 0x190,0x18,0x1a0,0x19,0x1b0,0x1a,0x1c0,0x1b,0x1d0,0x1c,0x1e0,0x1d,0x1f0,0x1e,0x200,0x1f, - 0x210,0x20,0x220,0x21,0x230,0x22,0x240,0x23,0x250,0x24,0x260,0x25,0x270,0x26,0x280,0x27, - 0x290,0x28,0x2a0,0x29,0x2b0,0x2a,0x2c0,0x2b,0x2d0,0x2c,0x2e0,0x2d,0x2f0,0x2e,0x300,0x2f, - 0x310,0x30,0x320,0x31,0x330,0x32,0x340,0x33,0x350,0x34,0x360,0x35,0x370,0x36,0x380,0x37, - 0x390,0x38,0x3a0,0x39,0x3b0,0x3a,0x3c0,0x3b,0x3d0,0x3c,0x3e0,0x3d,0x3f0,0x3e,0x400,0x3f, - 0x410,0x40,0x420,0x41,0x430,0x42,0x440,0x43,0x450,0x44,0x460,0x45,0x470,0x46,0x480,0x47, - 0x490,0x48,0x4a0,0x49,0x4b0,0x4a,0x4c0,0x4b,0x4d0,0x4c,0x4e0,0x4d,0x4f0,0x4e,0x500,0x4f, - 0x510,0x50,0x520,0x51,0x530,0x52,0x540,0x53,0x550,0x54,0x560,0x55,0x570,0x56,0x580,0x57, - 0x590,0x58,0x5a0,0x59,0x5b0,0x5a,0x5c0,0x5b,0x5d0,0x5c,0x5e0,0x5d,0x5f0,0x5e,0x600,0x5f, - 0x610,0x60,0x620,0x61,0x630,0x62,0x640,0x63,0x650,0x64,0x660,0x65,0x670,0x66,0x680,0x67, - 0x690,0x68,0x6a0,0x69,0x6b0,0x6a,0x6c0,0x6b,0x6d0,0x6c,0x6e0,0x6d,0x6f0,0x6e,0x700,0x6f, - 0x710,0x70,0x720,0x71,0x730,0x72,0x740,0x73,0x750,0x74,0x760,0x75,0x770,0x76,0x780,0x77, - 0x790,0x78,0x7a0,0x79,0x7b0,0x7a,0x7c0,0x7b,0x7d0,0x7c,0x7e0,0x7d,0x7f0,0x7e,0x800,0x7f, - 0x810,0x80,0x820,0x81,0x830,0x82,0x840,0x83,0x850,0x84,0x860,0x85,0x870,0x86,0x880,0x87, - 0x890,0x88,0x8a0,0x89,0x8b0,0x8a,0x8c0,0x8b,0x8d0,0x8c,0x8e0,0x8d,0x8f0,0x8e,0x900,0x8f, - 0x910,0x90,0x920,0x91,0x930,0x92,0x940,0x93,0x950,0x94,0x960,0x95,0x970,0x96,0x980,0x97, - 0x990,0x98,0x9a0,0x99,0x9b0,0x9a,0x9c0,0x9b,0x9d0,0x9c,0x9e0,0x9d,0x9f0,0x9e,0xa00,0x9f, - 0xa10,0xa0,0xa20,0xa1,0xa30,0xa2,0xa40,0xa3,0xa50,0xa4,0xa60,0xa5,0xa70,0xa6,0xa80,0xa7, - 0xa90,0xa8,0xaa0,0xa9,0xab0,0xaa,0xac0,0xab,0xad0,0xac,0xae0,0xad,0xaf0,0xae,0xb00,0xaf, - 0xb10,0xb0,0xb20,0xb1,0xb30,0xb2,0xb40,0xb3,0xb50,0xb4,0xb60,0xb5,0xb70,0xb6,0xb80,0xb7, - 0xb90,0xb8,0xba0,0xb9,0xbb0,0xba,0xbc0,0xbb,0xbd0,0xbc,0xbe0,0xbd,0xbf0,0xbe,0xc00,0xbf, - 0xc10,0xc0,0xc20,0xc1,0xc30,0xc2,0xc40,0xc3,0xc50,0xc4,0xc60,0xc5,0xc70,0xc6,0xc80,0xc7, - 0xc90,0xc8,0xca0,0xc9,0xcb0,0xca,0xcc0,0xcb,0xcd0,0xcc,0xce0,0xcd,0xcf0,0xce,0xd00,0xcf, - 0xd10,0xd0,0xd20,0xd1,0xd30,0xd2,0xd40,0xd3,0xd50,0xd4,0xd60,0xd5,0xd70,0xd6,0xd80,0xd7, - 0xd90,0xd8,0xda0,0xd9,0xdb0,0xda,0xdc0,0xdb,0xdd0,0xdc,0xde0,0xdd,0xdf0,0xde,0xe00,0xdf, - 0xe10,0xe0,0xe20,0xe1,0xe30,0xe2,0xe40,0xe3,0xe50,0xe4,0xe60,0xe5,0xe70,0xe6,0xe80,0xe7, - 0xe90,0xe8,0xea0,0xe9,0xeb0,0xea,0xec0,0xeb,0xed0,0xec,0xee0,0xed,0xef0,0xee,0xf00,0xef, - 0xf10,0xf0,0xf20,0xf1,0xf30,0xf2,0xf40,0xf3,0xf50,0xf4,0xf60,0xf5,0xf70,0xf6,0xf80,0xf7, - 0xf90,0xf8,0xfa0,0xf9,0xfb0,0xfa,0xfc0,0xfb,0xfd0,0xfc,0xfe0,0xfd,0xff0,0xfe,0x1000,0xff, - 0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.small16.toml deleted file mode 100644 index c8156e69b005..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/short-all-same.small16.toml +++ /dev/null @@ -1,321 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: short-all-same.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "short-all-same.small16" -index = [ - 0,0x40,0x80,0xc0,0x100,0x140,0x180,0x1c0,0x200,0x240,0x280,0x2c0,0x300,0x340,0x380,0x3c0, - 0x400,0x440,0x480,0x4c0,0x500,0x540,0x580,0x5c0,0x600,0x640,0x680,0x6c0,0x700,0x740,0x780,0x7c0, - 0x800,0x840,0x880,0x8c0,0x900,0x940,0x980,0x9c0,0xa00,0xa40,0xa80,0xac0,0xb00,0xb40,0xb80,0xbc0, - 0xc00,0xc40,0xc80,0xcc0,0xd00,0xd40,0xd80,0xdc0,0xe00,0xe40,0xe80,0xec0,0xf00,0xf40,0xf80,0xfc0 -] -data_16 = [ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa, - 0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb,0xb, - 0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc, - 0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd, - 0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe,0xe, - 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, - 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, - 0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, - 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, - 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, - 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, - 0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a, - 0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b, - 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, - 0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d, - 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e, - 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21, - 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, - 0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23, - 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, - 0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25,0x25, - 0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26,0x26, - 0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x27, - 0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28, - 0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29,0x29, - 0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a, - 0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b,0x2b, - 0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c,0x2c, - 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, - 0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e,0x2e, - 0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f, - 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32, - 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35, - 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, - 0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37, - 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, - 0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39, - 0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a,0x3a, - 0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b,0x3b, - 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, - 0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, - 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e, - 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, - 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43, - 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, - 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45, - 0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, - 0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47, - 0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48, - 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49, - 0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, - 0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b, - 0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c,0x4c, - 0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d, - 0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e, - 0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f,0x4f, - 0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50, - 0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51,0x51, - 0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52,0x52, - 0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53,0x53, - 0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54,0x54, - 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, - 0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56, - 0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57,0x57, - 0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58, - 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, - 0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a, - 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, - 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, - 0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d, - 0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e,0x5e, - 0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f, - 0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60, - 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, - 0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62,0x62, - 0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63, - 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, - 0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65,0x65, - 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, - 0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67,0x67, - 0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68, - 0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69, - 0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a,0x6a, - 0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b, - 0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c, - 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d, - 0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e,0x6e, - 0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f,0x6f, - 0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70, - 0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71, - 0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72,0x72, - 0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73,0x73, - 0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74,0x74, - 0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75,0x75, - 0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76,0x76, - 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77, - 0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78, - 0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79,0x79, - 0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a,0x7a, - 0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b,0x7b, - 0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c, - 0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d, - 0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e, - 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81, - 0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, - 0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85,0x85, - 0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86, - 0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x87, - 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88, - 0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89,0x89, - 0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a, - 0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b,0x8b, - 0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c,0x8c, - 0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d,0x8d, - 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, - 0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f,0x8f, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91,0x91, - 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92, - 0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93, - 0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94,0x94, - 0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95, - 0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96,0x96, - 0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x97, - 0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98, - 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99, - 0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a, - 0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b,0x9b, - 0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c,0x9c, - 0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d, - 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e, - 0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f, - 0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0, - 0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1, - 0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2, - 0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3, - 0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4, - 0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5,0xa5, - 0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6,0xa6, - 0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7, - 0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8, - 0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9,0xa9, - 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, - 0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab, - 0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xac, - 0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad,0xad, - 0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae, - 0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf,0xaf, - 0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0, - 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1, - 0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2, - 0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3,0xb3, - 0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4, - 0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5,0xb5, - 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6, - 0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7, - 0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8,0xb8, - 0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9, - 0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba, - 0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb, - 0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc,0xbc, - 0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd,0xbd, - 0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe, - 0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf, - 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, - 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, - 0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2,0xc2, - 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3, - 0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4, - 0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5,0xc5, - 0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6, - 0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7,0xc7, - 0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8,0xc8, - 0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9,0xc9, - 0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca,0xca, - 0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb, - 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, - 0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd, - 0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce,0xce, - 0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2, - 0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3,0xd3, - 0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4,0xd4, - 0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5, - 0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6, - 0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7,0xd7, - 0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8,0xd8, - 0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9,0xd9, - 0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda,0xda, - 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb, - 0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc, - 0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd, - 0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde, - 0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2, - 0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3,0xe3, - 0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4, - 0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5, - 0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6, - 0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7, - 0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8, - 0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9, - 0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea, - 0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb, - 0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec, - 0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed,0xed, - 0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee, - 0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef, - 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, - 0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1, - 0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2, - 0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3, - 0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4,0xf4, - 0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf5, - 0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, - 0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, - 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, - 0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, - 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, - 0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb, - 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, - 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, - 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0,0xad -] -indexLength = 64 -dataLength = 4098 -highStart = 0x1000 -shifted12HighStart = 0x1 -type = 1 -valueWidth = 0 -index3NullOffset = 0x7fff -dataNullOffset = 0xfffff -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x10,0,0x20,1,0x30,2,0x40,3,0x50,4,0x60,5,0x70,6,0x80,7, - 0x90,8,0xa0,9,0xb0,0xa,0xc0,0xb,0xd0,0xc,0xe0,0xd,0xf0,0xe,0x100,0xf, - 0x110,0x10,0x120,0x11,0x130,0x12,0x140,0x13,0x150,0x14,0x160,0x15,0x170,0x16,0x180,0x17, - 0x190,0x18,0x1a0,0x19,0x1b0,0x1a,0x1c0,0x1b,0x1d0,0x1c,0x1e0,0x1d,0x1f0,0x1e,0x200,0x1f, - 0x210,0x20,0x220,0x21,0x230,0x22,0x240,0x23,0x250,0x24,0x260,0x25,0x270,0x26,0x280,0x27, - 0x290,0x28,0x2a0,0x29,0x2b0,0x2a,0x2c0,0x2b,0x2d0,0x2c,0x2e0,0x2d,0x2f0,0x2e,0x300,0x2f, - 0x310,0x30,0x320,0x31,0x330,0x32,0x340,0x33,0x350,0x34,0x360,0x35,0x370,0x36,0x380,0x37, - 0x390,0x38,0x3a0,0x39,0x3b0,0x3a,0x3c0,0x3b,0x3d0,0x3c,0x3e0,0x3d,0x3f0,0x3e,0x400,0x3f, - 0x410,0x40,0x420,0x41,0x430,0x42,0x440,0x43,0x450,0x44,0x460,0x45,0x470,0x46,0x480,0x47, - 0x490,0x48,0x4a0,0x49,0x4b0,0x4a,0x4c0,0x4b,0x4d0,0x4c,0x4e0,0x4d,0x4f0,0x4e,0x500,0x4f, - 0x510,0x50,0x520,0x51,0x530,0x52,0x540,0x53,0x550,0x54,0x560,0x55,0x570,0x56,0x580,0x57, - 0x590,0x58,0x5a0,0x59,0x5b0,0x5a,0x5c0,0x5b,0x5d0,0x5c,0x5e0,0x5d,0x5f0,0x5e,0x600,0x5f, - 0x610,0x60,0x620,0x61,0x630,0x62,0x640,0x63,0x650,0x64,0x660,0x65,0x670,0x66,0x680,0x67, - 0x690,0x68,0x6a0,0x69,0x6b0,0x6a,0x6c0,0x6b,0x6d0,0x6c,0x6e0,0x6d,0x6f0,0x6e,0x700,0x6f, - 0x710,0x70,0x720,0x71,0x730,0x72,0x740,0x73,0x750,0x74,0x760,0x75,0x770,0x76,0x780,0x77, - 0x790,0x78,0x7a0,0x79,0x7b0,0x7a,0x7c0,0x7b,0x7d0,0x7c,0x7e0,0x7d,0x7f0,0x7e,0x800,0x7f, - 0x810,0x80,0x820,0x81,0x830,0x82,0x840,0x83,0x850,0x84,0x860,0x85,0x870,0x86,0x880,0x87, - 0x890,0x88,0x8a0,0x89,0x8b0,0x8a,0x8c0,0x8b,0x8d0,0x8c,0x8e0,0x8d,0x8f0,0x8e,0x900,0x8f, - 0x910,0x90,0x920,0x91,0x930,0x92,0x940,0x93,0x950,0x94,0x960,0x95,0x970,0x96,0x980,0x97, - 0x990,0x98,0x9a0,0x99,0x9b0,0x9a,0x9c0,0x9b,0x9d0,0x9c,0x9e0,0x9d,0x9f0,0x9e,0xa00,0x9f, - 0xa10,0xa0,0xa20,0xa1,0xa30,0xa2,0xa40,0xa3,0xa50,0xa4,0xa60,0xa5,0xa70,0xa6,0xa80,0xa7, - 0xa90,0xa8,0xaa0,0xa9,0xab0,0xaa,0xac0,0xab,0xad0,0xac,0xae0,0xad,0xaf0,0xae,0xb00,0xaf, - 0xb10,0xb0,0xb20,0xb1,0xb30,0xb2,0xb40,0xb3,0xb50,0xb4,0xb60,0xb5,0xb70,0xb6,0xb80,0xb7, - 0xb90,0xb8,0xba0,0xb9,0xbb0,0xba,0xbc0,0xbb,0xbd0,0xbc,0xbe0,0xbd,0xbf0,0xbe,0xc00,0xbf, - 0xc10,0xc0,0xc20,0xc1,0xc30,0xc2,0xc40,0xc3,0xc50,0xc4,0xc60,0xc5,0xc70,0xc6,0xc80,0xc7, - 0xc90,0xc8,0xca0,0xc9,0xcb0,0xca,0xcc0,0xcb,0xcd0,0xcc,0xce0,0xcd,0xcf0,0xce,0xd00,0xcf, - 0xd10,0xd0,0xd20,0xd1,0xd30,0xd2,0xd40,0xd3,0xd50,0xd4,0xd60,0xd5,0xd70,0xd6,0xd80,0xd7, - 0xd90,0xd8,0xda0,0xd9,0xdb0,0xda,0xdc0,0xdb,0xdd0,0xdc,0xde0,0xdd,0xdf0,0xde,0xe00,0xdf, - 0xe10,0xe0,0xe20,0xe1,0xe30,0xe2,0xe40,0xe3,0xe50,0xe4,0xe60,0xe5,0xe70,0xe6,0xe80,0xe7, - 0xe90,0xe8,0xea0,0xe9,0xeb0,0xea,0xec0,0xeb,0xed0,0xec,0xee0,0xed,0xef0,0xee,0xf00,0xef, - 0xf10,0xf0,0xf20,0xf1,0xf30,0xf2,0xf40,0xf3,0xf50,0xf4,0xf60,0xf5,0xf70,0xf6,0xf80,0xf7, - 0xf90,0xf8,0xfa0,0xf9,0xfb0,0xfa,0xfc0,0xfb,0xfd0,0xfc,0xfe0,0xfd,0xff0,0xfe,0x1000,0xff, - 0x110000,0 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.16.toml deleted file mode 100644 index 56163ddaad97..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.16.toml +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: small0-in-fast.16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "small0-in-fast.16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0x80,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0xd0,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0x424,0x424,0x424,0x424,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd1,0xd1,0xd1,0xd1,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404, - 0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404, - 0x404,0x404,0x404,0x404 -] -data_16 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,0xad,9,0xad -] -indexLength = 1092 -dataLength = 292 -highStart = 0x20000 -shifted12HighStart = 0x20 -type = 0 -valueWidth = 0 -index3NullOffset = 0x404 -dataNullOffset = 0xd1 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x880,1,0x890,0,0x1040,2,0x1051,0,0x10000,3,0x20000,0,0x110000,9 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.32.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.32.toml deleted file mode 100644 index 9d4685ba2f86..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.32.toml +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: small0-in-fast.32 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "small0-in-fast.32" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0x80,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0xd0,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0x424,0x424,0x424,0x424,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd1,0xd1,0xd1,0xd1,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404, - 0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404, - 0x404,0x404,0x404,0x404 -] -data_32 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,9,0xad -] -indexLength = 1092 -dataLength = 291 -highStart = 0x20000 -shifted12HighStart = 0x20 -type = 0 -valueWidth = 1 -index3NullOffset = 0x404 -dataNullOffset = 0xd1 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x880,1,0x890,0,0x1040,2,0x1051,0,0x10000,3,0x20000,0,0x110000,9 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.8.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.8.toml deleted file mode 100644 index 8f42007065c9..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.8.toml +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: small0-in-fast.8 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "small0-in-fast.8" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0x80,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0xd0,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1, - 0x424,0x424,0x424,0x424,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1,0xd1, - 0xd1,0xd1,0xd1,0xd1,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404, - 0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404,0x404, - 0x404,0x404,0x404,0x404 -] -data_8 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,9,9,0xad -] -indexLength = 1092 -dataLength = 292 -highStart = 0x20000 -shifted12HighStart = 0x20 -type = 0 -valueWidth = 2 -index3NullOffset = 0x404 -dataNullOffset = 0xd1 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x880,1,0x890,0,0x1040,2,0x1051,0,0x10000,3,0x20000,0,0x110000,9 -] diff --git a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.small16.toml b/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.small16.toml deleted file mode 100644 index dd203a39de69..000000000000 --- a/deps/crates/vendor/icu_collections-v2/tests/data/cpt/small0-in-fast.small16.toml +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2021 and later: Unicode, Inc. and others. -# License & terms of use: http://www.unicode.org/copyright.html -# -# file name: small0-in-fast.small16 -# -# machine-generated by: ucptrietest.c - -[code_point_trie.struct] -name = "small0-in-fast.small16" -index = [ - 0,0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0x80,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, - 0xda,0xe3,0xe3,0xe3,0x103,0x103,0x103,0x103,0,0x10,0x20,0x30,0x40,0x50,0x60,0x70, - 0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30, - 0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30,0,0x10,0x20,0x30, - 0x80,0x90,0xa0,0xb0,0x90,0xa0,0xb0,0xc0,0x90,0xa0,0xb0,0xc0,0x90,0xa0,0xb0,0xc0, - 0x90,0xa0,0xb0,0xc0,0x90,0xa0,0xb0,0xc0,0x90,0xa0,0xb0,0xc0,0x90,0xa0,0xb0,0xc0, - 0x90,0xa0,0xb0,0xc0,0x90,0x90,0x90,0x90,0xd0,0xdf,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, - 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0, - 0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0x48,0x50,0x50,0x50,0x68,0x74, - 0x74,0x74,0x94,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a, - 0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a,0x9a, - 0x9a,0x9a,0x9a,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba, - 0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba, - 0xba,0xba,0xba -] -data_16 = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 0xad,9,0xad -] -indexLength = 291 -dataLength = 243 -highStart = 0x20000 -shifted12HighStart = 0x20 -type = 1 -valueWidth = 0 -index3NullOffset = 0xba -dataNullOffset = 0xd0 -nullValue = 0x0 - -[code_point_trie.testdata] -# Array of (limit, value) pairs -checkRanges = [ - 0x880,1,0x890,0,0x1040,2,0x1051,0,0x10000,3,0x20000,0,0x110000,9 -] diff --git a/deps/crates/vendor/icu_locale-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale-v2/.cargo_vcs_info.json deleted file mode 100644 index 0064f117e0b1..000000000000 --- a/deps/crates/vendor/icu_locale-v2/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "c9fac4e625ccb2c6a7aa35079fff9709db4385ac" - }, - "path_in_vcs": "components/locale" -} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale-v2/OWNERS b/deps/crates/vendor/icu_locale-v2/OWNERS deleted file mode 100644 index 07a258f68f0b..000000000000 --- a/deps/crates/vendor/icu_locale-v2/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# This file has been auto-generated by the `gnrt` tool. -file://third_party/rust/icu_locale/OWNERS diff --git a/deps/crates/vendor/icu_locale-v2/README.md b/deps/crates/vendor/icu_locale-v2/README.md deleted file mode 100644 index 418237748bcb..000000000000 --- a/deps/crates/vendor/icu_locale-v2/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# icu_locale [![crates.io](https://img.shields.io/crates/v/icu_locale)](https://crates.io/crates/icu_locale) - -<!-- cargo-rdme start --> - -Canonicalization of locale identifiers based on [`CLDR`] data. - -This module is published as its own crate ([`icu_locale`](https://docs.rs/icu_locale/latest/icu_locale/)) -and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project. - -It currently supports locale canonicalization based upon the canonicalization -algorithm from [`UTS #35: Unicode LDML 3. LocaleId Canonicalization`], -as well as the minimize and maximize likely subtags algorithms -as described in [`UTS #35: Unicode LDML 3. Likely Subtags`]. - -The maximize method potentially updates a passed in locale in place -depending up the results of running the 'Add Likely Subtags' algorithm -from [`UTS #35: Unicode LDML 3. Likely Subtags`]. - -This minimize method returns a new Locale that is the result of running the -'Remove Likely Subtags' algorithm from [`UTS #35: Unicode LDML 3. Likely Subtags`]. - -## Examples - -```rust -use icu::locale::Locale; -use icu::locale::{LocaleCanonicalizer, TransformResult}; - -let lc = LocaleCanonicalizer::new_extended(); - -let mut locale: Locale = "ja-Latn-fonipa-hepburn-heploc" - .parse() - .expect("parse failed"); -assert_eq!(lc.canonicalize(&mut locale), TransformResult::Modified); -assert_eq!(locale, "ja-Latn-alalc97-fonipa".parse::<Locale>().unwrap()); -``` - -```rust -use icu::locale::{locale, LocaleExpander, TransformResult}; - -let lc = LocaleExpander::new_common(); - -let mut locale = locale!("zh-CN"); -assert_eq!(lc.maximize(&mut locale.id), TransformResult::Modified); -assert_eq!(locale, locale!("zh-Hans-CN")); - -let mut locale = locale!("zh-Hant-TW"); -assert_eq!(lc.maximize(&mut locale.id), TransformResult::Unmodified); -assert_eq!(locale, locale!("zh-Hant-TW")); -``` - -```rust -use icu::locale::{locale, LocaleExpander, TransformResult}; -use writeable::assert_writeable_eq; - -let lc = LocaleExpander::new_common(); - -let mut locale = locale!("zh-Hans-CN"); -assert_eq!(lc.minimize(&mut locale.id), TransformResult::Modified); -assert_eq!(locale, locale!("zh")); - -let mut locale = locale!("zh"); -assert_eq!(lc.minimize(&mut locale.id), TransformResult::Unmodified); -assert_eq!(locale, locale!("zh")); -``` - -[`ICU4X`]: ../icu/index.html -[`CLDR`]: https://cldr.unicode.org/ -[`UTS #35: Unicode LDML 3. Likely Subtags`]: https://www.unicode.org/reports/tr35/#Likely_Subtags. -[`UTS #35: Unicode LDML 3. LocaleId Canonicalization`]: https://unicode.org/reports/tr35/#LocaleId_Canonicalization, - -<!-- cargo-rdme end --> - -## More Information - -For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). diff --git a/deps/crates/vendor/icu_locale-v2/benches/fixtures/locales.json b/deps/crates/vendor/icu_locale-v2/benches/fixtures/locales.json deleted file mode 100644 index 0e8ba8b798eb..000000000000 --- a/deps/crates/vendor/icu_locale-v2/benches/fixtures/locales.json +++ /dev/null @@ -1,41 +0,0 @@ -[ - "en-US", - "en-GB", - "es-AR", - "it", - "zh-Hans-CN", - "de-AT", - "pl", - "fr-FR", - "de-AT", - "sr-Cyrl-SR", - "nb-NO", - "fr-FR", - "mk", - "uk", - "und-PL", - "und-Latn-AM", - "ug-Cyrl", - "sr-ME", - "mn-Mong", - "lif-Limb", - "gan", - "zh-Hant", - "yue-Hans", - "unr", - "unr-Deva", - "und-Thai-CN", - "ug-Cyrl", - "en-Latn-DE", - "pl-FR", - "de-CH", - "tuq", - "sr-ME", - "ng", - "klx", - "kk-Arab", - "en-Cyrl", - "und-Cyrl-UK", - "und-Arab", - "und-Arab-FO" -] diff --git a/deps/crates/vendor/icu_locale-v2/benches/fixtures/uncanonicalized-locales.json b/deps/crates/vendor/icu_locale-v2/benches/fixtures/uncanonicalized-locales.json deleted file mode 100644 index 18eadbce68e2..000000000000 --- a/deps/crates/vendor/icu_locale-v2/benches/fixtures/uncanonicalized-locales.json +++ /dev/null @@ -1,88 +0,0 @@ -[ - "cka", - "cze", - "gfx", - "sgn-BR", - "sgn-DD", - "tam", - "und-aaland", - "nob-bokmal", - "no-nynorsk", - "und-Qaai", - "en-554", - "en-084", - "art-lojban", - "zh-guoyu", - "zh-hakka", - "zh-xiang", - "aar-x-private", - "heb-x-private", - "ces", - "hy-arevela", - "hy-arevmda", - "cel-gaulish", - "ja-latn-hepburn-heploc", - "ja-Latn-fonipa-hepburn-heploc", - "und-Armn-SU", - "sh", - "sh-Cyrl", - "cnr", - "cnr-BA", - "ru-SU", - "ru-810", - "en-SU", - "en-810", - "und-SU", - "und-810", - "und-Latn-SU", - "und-Latn-810", - "hy-SU", - "hy-810", - "und-Armn-SU", - "und-Armn-810", - "sr-CS", - "sr-Latn-CS", - "sr-Cyrl-CS", - "az-NT", - "sl-t-sl-rozaj-biske-1994", - "DE-T-M0-DIN-K0-QWERTZ", - "en-t-m0-true", - "en-t-iw", - "und-u-rg-no23", - "und-u-rg-cn11", - "und-u-rg-cz10a", - "und-u-rg-fra", - "und-u-rg-frg", - "und-u-rg-lud", - "und-NO-u-rg-no23", - "und-CN-u-rg-cn11", - "und-CZ-u-rg-cz10a", - "und-FR-u-rg-fra", - "und-FR-u-rg-frg", - "und-u-rg-lud", - "und-u-sd-no23", - "und-u-sd-cn11", - "und-u-sd-cz10a", - "und-u-sd-fra", - "hy-arevela", - "hy-Armn-arevela", - "hy-AM-arevela", - "hy-arevela-fonipa", - "hy-fonipa-arevela", - "hy-arevmda", - "hy-Armn-arevmda", - "hy-AM-arevmda", - "hy-arevmda-fonipa", - "hy-fonipa-arevmda", - "ja-Latn-hepburn-heploc", - "ja-Latn-JP-hepburn-heploc", - "sv-aaland", - "el-polytoni", - "ja-Latn-alalc97-hepburn-heploc", - "ja-Latn-hepburn-alalc97-heploc", - "ja-Latn-hepburn-heploc-alalc97", - "ja-Latn-heploc-hepburn", - "ja-Latn-heploc", - "ja-Latn-aaland-heploc", - "ja-Latn-heploc-polytoni" -] diff --git a/deps/crates/vendor/icu_locale-v2/benches/locale_canonicalizer.rs b/deps/crates/vendor/icu_locale-v2/benches/locale_canonicalizer.rs deleted file mode 100644 index 11d8668196ac..000000000000 --- a/deps/crates/vendor/icu_locale-v2/benches/locale_canonicalizer.rs +++ /dev/null @@ -1,107 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use icu_locale::LocaleCanonicalizer; -use icu_locale::LocaleExpander; -use icu_locale_core::Locale; - -fn canonicalize_bench(c: &mut Criterion) { - let lc = LocaleCanonicalizer::new_common(); - - let mut group = c.benchmark_group("uncanonicalized"); - - let data: Vec<String> = - serde_json::from_str(include_str!("fixtures/uncanonicalized-locales.json")) - .expect("Failed to read a fixture"); - let locales: Vec<Locale> = data.iter().map(|s| s.parse().unwrap()).collect(); - - group.bench_function("clone", |b| { - b.iter(|| { - for locale in &locales { - let _ = black_box(locale).clone(); - } - }) - }); - - group.bench_function("canonicalize", |b| { - b.iter(|| { - for locale in &locales { - let mut locale = black_box(locale).clone(); - lc.canonicalize(&mut locale); - } - }) - }); - - group.finish(); -} - -fn canonicalize_noop_bench(c: &mut Criterion) { - let lc = LocaleCanonicalizer::new_common(); - - let mut group = c.benchmark_group("canonicalized"); - - // None of these locales require canonicalization, so this measures the cost of calling - // the canonicalizer on locales that will not be modified. - let data: Vec<String> = serde_json::from_str(include_str!("fixtures/locales.json")) - .expect("Failed to read a fixture"); - let locales: Vec<Locale> = data.iter().map(|s| s.parse().unwrap()).collect(); - - group.bench_function("clone", |b| { - b.iter(|| { - for locale in &locales { - let _ = black_box(locale).clone(); - } - }) - }); - - group.bench_function("canonicalize", |b| { - b.iter(|| { - for locale in &locales { - let mut locale = black_box(locale).clone(); - lc.canonicalize(&mut locale); - } - }) - }); - - group.finish(); -} - -fn maximize_bench(c: &mut Criterion) { - let lc = LocaleExpander::new_common(); - - let mut group = c.benchmark_group("likelysubtags"); - - let data: Vec<String> = serde_json::from_str(include_str!("fixtures/locales.json")) - .expect("Failed to read a fixture"); - let locales: Vec<Locale> = data.iter().map(|s| s.parse().unwrap()).collect(); - - group.bench_function("maximize", |b| { - b.iter(|| { - for locale in &locales { - let mut locale = locale.clone(); - lc.maximize(black_box(&mut locale.id)); - } - }) - }); - - group.bench_function("minimize", |b| { - b.iter(|| { - for locale in &locales { - let mut locale = locale.clone(); - lc.minimize(black_box(&mut locale.id)); - } - }) - }); - - group.finish(); -} - -criterion_group!( - benches, - canonicalize_bench, - canonicalize_noop_bench, - maximize_bench -); -criterion_main!(benches); diff --git a/deps/crates/vendor/icu_locale-v2/src/canonicalizer.rs b/deps/crates/vendor/icu_locale-v2/src/canonicalizer.rs deleted file mode 100644 index 880a7fdc9b76..000000000000 --- a/deps/crates/vendor/icu_locale-v2/src/canonicalizer.rs +++ /dev/null @@ -1,622 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! The collection of code for locale canonicalization. - -use crate::provider::*; -use alloc::vec::Vec; -use core::cmp::Ordering; - -use crate::LocaleExpander; -use crate::TransformResult; -use icu_locale_core::extensions::Extensions; -use icu_locale_core::subtags::{Language, Region, Script}; -use icu_locale_core::{ - extensions::unicode::key, - subtags::{language, Variant, Variants}, - LanguageIdentifier, Locale, -}; -use icu_provider::prelude::*; -use tinystr::TinyAsciiStr; - -/// Implements the algorithm defined in *[UTS #35: Annex C, LocaleId Canonicalization]*. -/// -/// # Examples -/// -/// ``` -/// use icu::locale::Locale; -/// use icu::locale::{LocaleCanonicalizer, TransformResult}; -/// -/// let lc = LocaleCanonicalizer::new_extended(); -/// -/// let mut locale: Locale = "ja-Latn-fonipa-hepburn-heploc".parse().unwrap(); -/// assert_eq!(lc.canonicalize(&mut locale), TransformResult::Modified); -/// assert_eq!(locale, "ja-Latn-alalc97-fonipa".parse().unwrap()); -/// ``` -/// -/// [UTS #35: Annex C, LocaleId Canonicalization]: https://unicode.org/reports/tr35/#LocaleId_Canonicalization -#[derive(Debug)] -pub struct LocaleCanonicalizer<Expander = LocaleExpander> { - /// Data to support canonicalization. - aliases: DataPayload<LocaleAliasesV1>, - /// Likely subtags implementation for delegation. - expander: Expander, -} - -fn uts35_rule_matches<'a, I>( - source: &LanguageIdentifier, - language: Language, - script: Option<Script>, - region: Option<Region>, - raw_variants: I, -) -> bool -where - I: Iterator<Item = &'a str>, -{ - (language.is_unknown() || language == source.language) - && (script.is_none() || script == source.script) - && (region.is_none() || region == source.region) - && { - // Checks if variants are a subset of source variants. - // As both iterators are sorted, this can be done linearly. - let mut source_variants = source.variants.iter(); - 'outer: for raw_variant in raw_variants { - for source_variant in source_variants.by_ref() { - match source_variant.as_str().cmp(raw_variant) { - Ordering::Equal => { - // The source_variant is equal, move to next raw_variant - continue 'outer; - } - Ordering::Less => { - // The source_variant is smaller, take the next source_variant - } - Ordering::Greater => { - // The source_variant is greater, - // raw_variants is not a subset of source_variants - return false; - } - } - } - // There are raw_variants left after we exhausted source_variants - return false; - } - true - } -} - -fn uts35_replacement<'a, I>( - source: &mut LanguageIdentifier, - ruletype_has_language: bool, - ruletype_has_script: bool, - ruletype_has_region: bool, - ruletype_variants: Option<I>, - replacement: &LanguageIdentifier, -) where - I: Iterator<Item = &'a str>, -{ - if ruletype_has_language || (source.language.is_unknown() && !replacement.language.is_unknown()) - { - source.language = replacement.language; - } - if ruletype_has_script || (source.script.is_none() && replacement.script.is_some()) { - source.script = replacement.script; - } - if ruletype_has_region || (source.region.is_none() && replacement.region.is_some()) { - source.region = replacement.region; - } - if let Some(skips) = ruletype_variants { - // The rule matches if the ruletype variants are a subset of the source variants. - // This means ja-Latn-fonipa-hepburn-heploc matches against the rule for - // hepburn-heploc and is canonicalized to ja-Latn-alalc97-fonipa - - // We're merging three sorted deduped iterators into a new sequence: - // sources - skips + replacements - - let mut sources = source.variants.iter().peekable(); - let mut replacements = replacement.variants.iter().peekable(); - let mut skips = skips.peekable(); - - let mut variants: Vec<Variant> = Vec::new(); - - loop { - match (sources.peek(), skips.peek(), replacements.peek()) { - (Some(&source), Some(skip), _) - if source.as_str().cmp(skip) == Ordering::Greater => - { - skips.next(); - } - (Some(&source), Some(skip), _) if source.as_str().cmp(skip) == Ordering::Equal => { - skips.next(); - sources.next(); - } - (Some(&source), _, Some(&replacement)) - if replacement.cmp(source) == Ordering::Less => - { - variants.push(*replacement); - replacements.next(); - } - (Some(&source), _, Some(&replacement)) - if replacement.cmp(source) == Ordering::Equal => - { - variants.push(*source); - sources.next(); - replacements.next(); - } - (Some(&source), _, _) => { - variants.push(*source); - sources.next(); - } - (None, _, Some(&replacement)) => { - variants.push(*replacement); - replacements.next(); - } - (None, _, None) => { - break; - } - } - } - source.variants = Variants::from_vec_unchecked(variants); - } -} - -#[inline] -fn uts35_check_language_rules( - langid: &mut LanguageIdentifier, - alias_data: &DataPayload<LocaleAliasesV1>, -) -> TransformResult { - if !langid.language.is_unknown() { - let lang: TinyAsciiStr<3> = langid.language.into(); - let replacement = if lang.len() == 2 { - alias_data - .get() - .language_len2 - .get(&lang.resize().to_unvalidated()) - } else { - alias_data.get().language_len3.get(&lang.to_unvalidated()) - }; - - if let Some(replacement) = replacement { - if let Ok(new_langid) = replacement.parse() { - uts35_replacement::<core::iter::Empty<&str>>( - langid, - true, - false, - false, - None, - &new_langid, - ); - return TransformResult::Modified; - } - } - } - - TransformResult::Unmodified -} - -impl LocaleCanonicalizer<LocaleExpander> { - /// A constructor which creates a [`LocaleCanonicalizer`] from compiled data, - /// using a [`LocaleExpander`] for common locales. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new_common() -> Self { - Self::new_with_expander(LocaleExpander::new_common()) - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new_common: skip, - try_new_common_with_buffer_provider, - try_new_common_unstable, - Self, - ] - ); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_common)] - pub fn try_new_common_unstable<P>(provider: &P) -> Result<Self, DataError> - where - P: DataProvider<LocaleAliasesV1> - + DataProvider<LocaleLikelySubtagsLanguageV1> - + DataProvider<LocaleLikelySubtagsScriptRegionV1> - + ?Sized, - { - let expander = LocaleExpander::try_new_common_unstable(provider)?; - Self::try_new_with_expander_unstable(provider, expander) - } - - /// A constructor which creates a [`LocaleCanonicalizer`] from compiled data, - /// using a [`LocaleExpander`] for all locales. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new_extended() -> Self { - Self::new_with_expander(LocaleExpander::new_extended()) - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new_extended: skip, - try_new_extended_with_buffer_provider, - try_new_extended_unstable, - Self, - ] - ); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_extended)] - pub fn try_new_extended_unstable<P>(provider: &P) -> Result<Self, DataError> - where - P: DataProvider<LocaleAliasesV1> - + DataProvider<LocaleLikelySubtagsLanguageV1> - + DataProvider<LocaleLikelySubtagsScriptRegionV1> - + DataProvider<LocaleLikelySubtagsExtendedV1> - + ?Sized, - { - let expander = LocaleExpander::try_new_extended_unstable(provider)?; - Self::try_new_with_expander_unstable(provider, expander) - } -} - -impl<Expander: AsRef<LocaleExpander>> LocaleCanonicalizer<Expander> { - /// Creates a [`LocaleCanonicalizer`] with a custom [`LocaleExpander`] and compiled data. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new_with_expander(expander: Expander) -> Self { - Self { - aliases: DataPayload::from_static_ref(Baked::SINGLETON_LOCALE_ALIASES_V1), - expander, - } - } - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_with_expander)] - pub fn try_new_with_expander_unstable<P>( - provider: &P, - expander: Expander, - ) -> Result<Self, DataError> - where - P: DataProvider<LocaleAliasesV1> + ?Sized, - { - let aliases: DataPayload<LocaleAliasesV1> = provider.load(Default::default())?.payload; - - Ok(Self { aliases, expander }) - } - - icu_provider::gen_buffer_data_constructors!((options: Expander) -> error: DataError, - functions: [ - new_with_expander: skip, - try_new_with_expander_with_buffer_provider, - try_new_with_expander_unstable, - Self, - ] - ); - - /// The canonicalize method potentially updates a passed in locale in place - /// depending up the results of running the canonicalization algorithm - /// from <https://unicode.org/reports/tr35/#LocaleId_Canonicalization>. - /// - /// Some BCP47 canonicalization data is not part of the CLDR json package. Because - /// of this, some canonicalizations are not performed, e.g. the canonicalization of - /// `und-u-ca-islamicc` to `und-u-ca-islamic-civil`. This will be fixed in a future - /// release once the missing data has been added to the CLDR json data. See: - /// <https://github.com/unicode-org/icu4x/issues/746> - /// - /// # Examples - /// - /// ``` - /// use icu::locale::{Locale, LocaleCanonicalizer, TransformResult}; - /// - /// let lc = LocaleCanonicalizer::new_extended(); - /// - /// let mut locale: Locale = "ja-Latn-fonipa-hepburn-heploc".parse().unwrap(); - /// assert_eq!(lc.canonicalize(&mut locale), TransformResult::Modified); - /// assert_eq!(locale, "ja-Latn-alalc97-fonipa".parse().unwrap()); - /// ``` - pub fn canonicalize(&self, locale: &mut Locale) -> TransformResult { - let mut result = TransformResult::Unmodified; - - // This loops until we get a 'fixed point', where applying the rules do not - // result in any more changes. - loop { - // These are linear searches due to the ordering imposed by the canonicalization - // rules, where rules with more variants should be considered first. With the - // current data in CLDR, we will only do this for locales which have variants, - // or new rules which we haven't special-cased yet (of which there are fewer - // than 20). - let modified = if locale.id.variants.is_empty() { - self.canonicalize_absolute_language_fallbacks(&mut locale.id) - } else { - self.canonicalize_language_variant_fallbacks(&mut locale.id) - }; - if modified { - result = TransformResult::Modified; - continue; - } - - if !locale.id.language.is_unknown() { - // If the region is specified, check sgn-region rules first - if let Some(region) = locale.id.region { - if locale.id.language == language!("sgn") { - if let Some(&sgn_lang) = self - .aliases - .get() - .sgn_region - .get(®ion.to_tinystr().to_unvalidated()) - { - uts35_replacement::<core::iter::Empty<&str>>( - &mut locale.id, - true, - false, - true, - None, - &sgn_lang.into(), - ); - result = TransformResult::Modified; - continue; - } - } - } - - if uts35_check_language_rules(&mut locale.id, &self.aliases) - == TransformResult::Modified - { - result = TransformResult::Modified; - continue; - } - } - - if let Some(script) = locale.id.script { - if let Some(&replacement) = self - .aliases - .get() - .script - .get(&script.to_tinystr().to_unvalidated()) - { - locale.id.script = Some(replacement); - result = TransformResult::Modified; - continue; - } - } - - if let Some(region) = locale.id.region { - let replacement = if region.is_alphabetic() { - self.aliases - .get() - .region_alpha - .get(®ion.to_tinystr().resize().to_unvalidated()) - } else { - self.aliases - .get() - .region_num - .get(®ion.to_tinystr().to_unvalidated()) - }; - if let Some(&replacement) = replacement { - locale.id.region = Some(replacement); - result = TransformResult::Modified; - continue; - } - - if let Some(regions) = self - .aliases - .get() - .complex_region - .get(®ion.to_tinystr().to_unvalidated()) - { - // Skip if regions are empty - if let Some(default_region) = regions.get(0) { - let mut maximized = LanguageIdentifier { - language: locale.id.language, - script: locale.id.script, - region: None, - variants: Variants::default(), - }; - - locale.id.region = Some( - match ( - self.expander.as_ref().maximize(&mut maximized), - maximized.region, - ) { - (TransformResult::Modified, Some(candidate)) - if regions.iter().any(|x| x == candidate) => - { - candidate - } - _ => default_region, - }, - ); - result = TransformResult::Modified; - continue; - } - } - } - - if !locale.id.variants.is_empty() { - let mut modified = Vec::with_capacity(0); - for (idx, &variant) in locale.id.variants.iter().enumerate() { - if let Some(&updated) = self - .aliases - .get() - .variant - .get(&variant.to_tinystr().to_unvalidated()) - { - if modified.is_empty() { - modified = locale.id.variants.to_vec(); - } - #[expect(clippy::indexing_slicing)] - let _ = core::mem::replace(&mut modified[idx], updated); - } - } - - if !modified.is_empty() { - modified.sort(); - modified.dedup(); - locale.id.variants = Variants::from_vec_unchecked(modified); - result = TransformResult::Modified; - continue; - } - } - - // Nothing matched in this iteration, we're done. - break; - } - - if !locale.extensions.transform.is_empty() || !locale.extensions.unicode.is_empty() { - self.canonicalize_extensions(&mut locale.extensions, &mut result); - } - result - } - - fn canonicalize_extensions(&self, extensions: &mut Extensions, result: &mut TransformResult) { - // Handle Locale extensions in their own loops, because these rules do not interact - // with each other. - if let Some(ref mut lang) = extensions.transform.lang { - while uts35_check_language_rules(lang, &self.aliases) == TransformResult::Modified { - *result = TransformResult::Modified; - } - } - - if !extensions.unicode.keywords.is_empty() { - for key in [key!("rg"), key!("sd")] { - if let Some(value) = extensions.unicode.keywords.get_mut(&key) { - if let Some(only_value) = value.as_single_subtag() { - if let Some(modified_value) = self - .aliases - .get() - .subdivision - .get(&only_value.to_tinystr().resize().to_unvalidated()) - { - if let Ok(modified_value) = modified_value.parse() { - *value = modified_value; - *result = TransformResult::Modified; - } - } - } - } - } - } - } - - fn canonicalize_language_variant_fallbacks(&self, lid: &mut LanguageIdentifier) -> bool { - // These language/variant comibnations have around 20 rules - for LanguageStrStrPair(lang, raw_variants, raw_to) in self - .aliases - .get() - .language_variants - .iter() - .map(zerofrom::ZeroFrom::zero_from) - { - let raw_variants = raw_variants.split('-'); - // if is_iter_sorted(raw_variants.clone()) { // can we sort at construction? - if uts35_rule_matches(lid, lang, None, None, raw_variants.clone()) { - if let Ok(to) = raw_to.parse() { - uts35_replacement( - lid, - !lang.is_unknown(), - false, - false, - Some(raw_variants), - &to, - ); - return true; - } - } - } - false - } - - fn canonicalize_absolute_language_fallbacks(&self, lid: &mut LanguageIdentifier) -> bool { - for StrStrPair(raw_from, raw_to) in self - .aliases - .get() - .language - .iter() - .map(zerofrom::ZeroFrom::zero_from) - { - if let Ok(from) = raw_from.parse::<LanguageIdentifier>() { - if uts35_rule_matches( - lid, - from.language, - from.script, - from.region, - from.variants.iter().map(Variant::as_str), - ) { - if let Ok(to) = raw_to.parse() { - uts35_replacement( - lid, - !from.language.is_unknown(), - from.script.is_some(), - from.region.is_some(), - Some(from.variants.iter().map(Variant::as_str)), - &to, - ); - return true; - } - } - } - } - false - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_uts35_rule_matches() { - for (source, rule, result) in [ - ("ja", "und", true), - ("und-heploc-hepburn", "und-hepburn", true), - ("ja-heploc-hepburn", "und-hepburn", true), - ("ja-hepburn", "und-hepburn-heploc", false), - ] { - let source = source.parse().unwrap(); - let rule = rule.parse::<LanguageIdentifier>().unwrap(); - assert_eq!( - uts35_rule_matches( - &source, - rule.language, - rule.script, - rule.region, - rule.variants.iter().map(Variant::as_str), - ), - result, - "{source}" - ); - } - } - - #[test] - fn test_uts35_replacement() { - for (locale, rule_0, rule_1, result) in [ - ( - "ja-Latn-fonipa-hepburn-heploc", - "und-hepburn-heploc", - "und-alalc97", - "ja-Latn-alalc97-fonipa", - ), - ("sgn-DD", "und-DD", "und-DE", "sgn-DE"), - ("sgn-DE", "sgn-DE", "gsg", "gsg"), - ] { - let mut locale: Locale = locale.parse().unwrap(); - let rule_0 = rule_0.parse::<LanguageIdentifier>().unwrap(); - let rule_1 = rule_1.parse().unwrap(); - let result = result.parse::<Locale>().unwrap(); - uts35_replacement( - &mut locale.id, - !rule_0.language.is_unknown(), - rule_0.script.is_some(), - rule_0.region.is_some(), - Some(rule_0.variants.iter().map(Variant::as_str)), - &rule_1, - ); - assert_eq!(result, locale); - } - } -} diff --git a/deps/crates/vendor/icu_locale-v2/src/directionality.rs b/deps/crates/vendor/icu_locale-v2/src/directionality.rs deleted file mode 100644 index 6a2464645d3e..000000000000 --- a/deps/crates/vendor/icu_locale-v2/src/directionality.rs +++ /dev/null @@ -1,255 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use crate::provider::*; -use crate::LocaleExpander; -use icu_locale_core::subtags::Script; -use icu_locale_core::LanguageIdentifier; -use icu_provider::prelude::*; - -/// Represents the direction of a script. -/// -/// [`LocaleDirectionality`] can be used to get this information. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[non_exhaustive] -pub enum Direction { - /// The script is left-to-right. - LeftToRight, - /// The script is right-to-left. - RightToLeft, -} - -/// Provides methods to determine the direction of a locale. -/// -/// The `Expander` generic parameter wraps a [`LocaleExpander`]. -/// -/// # Examples -/// -/// ``` -/// use icu::locale::{langid, Direction, LocaleDirectionality}; -/// -/// let ld = LocaleDirectionality::new_common(); -/// -/// assert_eq!(ld.get(&langid!("en")), Some(Direction::LeftToRight)); -/// ``` -#[derive(Debug)] -pub struct LocaleDirectionality<Expander = LocaleExpander> { - script_direction: DataPayload<LocaleScriptDirectionV1>, - expander: Expander, -} - -impl LocaleDirectionality<LocaleExpander> { - /// Creates a [`LocaleDirectionality`] from compiled data, using [`LocaleExpander`] - /// data for common locales. - /// - /// This includes limited likely subtags data, see [`LocaleExpander::new_common()`]. - #[cfg(feature = "compiled_data")] - pub const fn new_common() -> Self { - Self::new_with_expander(LocaleExpander::new_common()) - } - - // Note: This is a custom impl because the bounds on `try_new_unstable` don't suffice - #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::new_common)] - #[cfg(feature = "serde")] - pub fn try_new_common_with_buffer_provider( - provider: &(impl BufferProvider + ?Sized), - ) -> Result<Self, DataError> { - let expander = LocaleExpander::try_new_common_with_buffer_provider(provider)?; - Self::try_new_with_expander_unstable(&provider.as_deserializing(), expander) - } - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_common)] - pub fn try_new_common_unstable<P>(provider: &P) -> Result<LocaleDirectionality, DataError> - where - P: DataProvider<LocaleScriptDirectionV1> - + DataProvider<LocaleLikelySubtagsLanguageV1> - + DataProvider<LocaleLikelySubtagsScriptRegionV1> - + ?Sized, - { - let expander = LocaleExpander::try_new_common_unstable(provider)?; - Self::try_new_with_expander_unstable(provider, expander) - } - - /// Creates a [`LocaleDirectionality`] from compiled data, using [`LocaleExpander`] - /// data for all locales. - /// - /// This includes all likely subtags data, see [`LocaleExpander::new_extended()`]. - #[cfg(feature = "compiled_data")] - pub const fn new_extended() -> Self { - Self::new_with_expander(LocaleExpander::new_extended()) - } - - // Note: This is a custom impl because the bounds on `try_new_unstable` don't suffice - #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::new_extended)] - #[cfg(feature = "serde")] - pub fn try_new_extended_with_buffer_provider( - provider: &(impl BufferProvider + ?Sized), - ) -> Result<Self, DataError> { - let expander = LocaleExpander::try_new_extended_with_buffer_provider(provider)?; - Self::try_new_with_expander_unstable(&provider.as_deserializing(), expander) - } - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_extended)] - pub fn try_new_extended_unstable<P>(provider: &P) -> Result<LocaleDirectionality, DataError> - where - P: DataProvider<LocaleScriptDirectionV1> - + DataProvider<LocaleLikelySubtagsLanguageV1> - + DataProvider<LocaleLikelySubtagsScriptRegionV1> - + DataProvider<LocaleLikelySubtagsExtendedV1> - + ?Sized, - { - let expander = LocaleExpander::try_new_extended_unstable(provider)?; - Self::try_new_with_expander_unstable(provider, expander) - } -} - -impl<Expander: AsRef<LocaleExpander>> LocaleDirectionality<Expander> { - /// Creates a [`LocaleDirectionality`] with a custom [`LocaleExpander`] and compiled data. - /// - /// This allows using [`LocaleExpander::new_extended()`] with data for all locales. - /// - /// # Examples - /// - /// ``` - /// use icu::locale::{ - /// langid, Direction, LocaleDirectionality, LocaleExpander, - /// }; - /// - /// let ld_default = LocaleDirectionality::new_common(); - /// - /// assert_eq!(ld_default.get(&langid!("jbn")), None); - /// - /// let expander = LocaleExpander::new_extended(); - /// let ld_extended = LocaleDirectionality::new_with_expander(expander); - /// - /// assert_eq!( - /// ld_extended.get(&langid!("jbn")), - /// Some(Direction::RightToLeft) - /// ); - /// ``` - #[cfg(feature = "compiled_data")] - pub const fn new_with_expander(expander: Expander) -> Self { - LocaleDirectionality { - script_direction: DataPayload::from_static_ref( - Baked::SINGLETON_LOCALE_SCRIPT_DIRECTION_V1, - ), - expander, - } - } - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_with_expander)] - pub fn try_new_with_expander_unstable<P>( - provider: &P, - expander: Expander, - ) -> Result<Self, DataError> - where - P: DataProvider<LocaleScriptDirectionV1> + ?Sized, - { - let script_direction = provider.load(Default::default())?.payload; - - Ok(LocaleDirectionality { - script_direction, - expander, - }) - } - - /// Returns the script direction of the given locale. - /// - /// Note that the direction is a property of the script of a locale, not of the language. As such, - /// when given a locale without an associated script tag (i.e., `locale!("en")` vs. `locale!("en-Latn")`), - /// this method first tries to infer the script using the language and region before returning its direction. - /// - /// If you already have a script struct and want to get its direction, you should use - /// `Locale::from(Some(my_script))` and call this method. - /// - /// This method will return `None` if either a locale's script cannot be determined, or there is no information - /// for the script. - /// - /// # Examples - /// - /// Using an existing locale: - /// - /// ``` - /// use icu::locale::{langid, Direction, LocaleDirectionality}; - /// - /// let ld = LocaleDirectionality::new_common(); - /// - /// assert_eq!(ld.get(&langid!("en-US")), Some(Direction::LeftToRight)); - /// - /// assert_eq!(ld.get(&langid!("ar")), Some(Direction::RightToLeft)); - /// - /// assert_eq!(ld.get(&langid!("en-Arab")), Some(Direction::RightToLeft)); - /// - /// assert_eq!(ld.get(&langid!("foo")), None); - /// ``` - /// - /// Using a script directly: - /// - /// ``` - /// use icu::locale::subtags::script; - /// use icu::locale::{Direction, LanguageIdentifier, LocaleDirectionality}; - /// - /// let ld = LocaleDirectionality::new_common(); - /// - /// assert_eq!( - /// ld.get(&LanguageIdentifier::from(Some(script!("Latn")))), - /// Some(Direction::LeftToRight) - /// ); - /// ``` - pub fn get(&self, langid: &LanguageIdentifier) -> Option<Direction> { - let script = self.expander.as_ref().get_likely_script(langid)?; - - if self.script_in_ltr(script) { - Some(Direction::LeftToRight) - } else if self.script_in_rtl(script) { - Some(Direction::RightToLeft) - } else { - None - } - } - - /// Returns whether the given locale is right-to-left. - /// - /// Note that if this method returns `false`, the locale is either left-to-right or - /// the [`LocaleDirectionality`] does not include data for the locale. - /// You should use [`LocaleDirectionality::get`] if you need to differentiate between these cases. - /// - /// See [`LocaleDirectionality::get`] for more information. - pub fn is_right_to_left(&self, langid: &LanguageIdentifier) -> bool { - self.expander - .as_ref() - .get_likely_script(langid) - .map(|s| self.script_in_rtl(s)) - .unwrap_or(false) - } - - /// Returns whether the given locale is left-to-right. - /// - /// Note that if this method returns `false`, the locale is either right-to-left or - /// the [`LocaleDirectionality`] does not include data for the locale. - /// You should use [`LocaleDirectionality::get`] if you need to differentiate between these cases. - /// - /// See [`LocaleDirectionality::get`] for more information. - pub fn is_left_to_right(&self, langid: &LanguageIdentifier) -> bool { - self.expander - .as_ref() - .get_likely_script(langid) - .map(|s| self.script_in_ltr(s)) - .unwrap_or(false) - } - - fn script_in_rtl(&self, script: Script) -> bool { - self.script_direction - .get() - .rtl - .binary_search(&script.to_tinystr().to_unvalidated()) - .is_ok() - } - - fn script_in_ltr(&self, script: Script) -> bool { - self.script_direction - .get() - .ltr - .binary_search(&script.to_tinystr().to_unvalidated()) - .is_ok() - } -} diff --git a/deps/crates/vendor/icu_locale-v2/src/exemplar_chars.rs b/deps/crates/vendor/icu_locale-v2/src/exemplar_chars.rs deleted file mode 100644 index 98385e1a95bd..000000000000 --- a/deps/crates/vendor/icu_locale-v2/src/exemplar_chars.rs +++ /dev/null @@ -1,305 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module provides APIs for getting exemplar characters for a locale. -//! -//! Exemplars are characters used by a language, separated into different sets. -//! The sets are: main, auxiliary, punctuation, numbers, and index. -//! -//! The sets define, according to typical usage in the language, -//! which characters occur in which contexts with which frequency. -//! For more information, see the documentation in the -//! [Exemplars section in Unicode Technical Standard #35](https://unicode.org/reports/tr35/tr35-general.html#Exemplars) -//! of the LDML specification. -//! -//! # Examples -//! -//! ``` -//! use icu::locale::exemplar_chars::ExemplarCharacters; -//! use icu::locale::locale; -//! -//! let locale = locale!("en-001").into(); -//! let exemplars_main = ExemplarCharacters::try_new_main(&locale) -//! .expect("locale should be present"); -//! -//! assert!(exemplars_main.contains('a')); -//! assert!(exemplars_main.contains('z')); -//! assert!(exemplars_main.contains_str("a")); -//! assert!(!exemplars_main.contains_str("ä")); -//! assert!(!exemplars_main.contains_str("ng")); -//! ``` - -use crate::provider::*; -use core::ops::Deref; -use icu_collections::codepointinvliststringlist::CodePointInversionListAndStringList; -use icu_provider::{marker::ErasedMarker, prelude::*}; - -/// A wrapper around `UnicodeSet` data (characters and strings) -#[derive(Debug)] -pub struct ExemplarCharacters { - data: DataPayload<ErasedMarker<ExemplarCharactersData<'static>>>, -} - -impl ExemplarCharacters { - /// Construct a borrowed version of this type that can be queried. - /// - /// This avoids a potential small underlying cost per API call (ex: `contains()`) by consolidating it - /// up front. - #[inline] - pub fn as_borrowed(&self) -> ExemplarCharactersBorrowed<'_> { - ExemplarCharactersBorrowed { - data: self.data.get(), - } - } -} - -/// A borrowed wrapper around code point set data, returned by -/// [`ExemplarCharacters::as_borrowed()`]. More efficient to query. -#[derive(Clone, Copy, Debug)] -pub struct ExemplarCharactersBorrowed<'a> { - data: &'a ExemplarCharactersData<'a>, -} - -impl<'a> Deref for ExemplarCharactersBorrowed<'a> { - type Target = CodePointInversionListAndStringList<'a>; - - fn deref(&self) -> &Self::Target { - &self.data.0 - } -} - -impl ExemplarCharactersBorrowed<'static> { - /// Cheaply converts a [`ExemplarCharactersBorrowed<'static>`] into a [`ExemplarCharacters`]. - /// - /// Note: Due to branching and indirection, using [`ExemplarCharacters`] might inhibit some - /// compile-time optimizations that are possible with [`ExemplarCharactersBorrowed`]. - pub const fn static_to_owned(self) -> ExemplarCharacters { - ExemplarCharacters { - data: DataPayload::from_static_ref(self.data), - } - } -} - -macro_rules! make_exemplar_chars_unicode_set_property { - ( - // currently unused - dyn_data_marker: $d:ident; - data_marker: $data_marker:ty; - func: - pub fn $unstable:ident(); - $(#[$attr:meta])* - pub fn $compiled:ident(); - ) => { - impl ExemplarCharactersBorrowed<'static> { - $(#[$attr])* - #[cfg(feature = "compiled_data")] - #[inline] - pub fn $compiled( - locale: &DataLocale, - ) -> Result<Self, DataError> { - Ok(ExemplarCharactersBorrowed { - data: DataProvider::<$data_marker>::load( - &crate::provider::Baked, - DataRequest { - id: DataIdentifierBorrowed::for_locale(locale), - ..Default::default() - })? - .payload - .get_static() - .ok_or_else(|| DataError::custom("Baked provider didn't return static payload"))? - }) - } - - } - impl ExemplarCharacters { - $(#[$attr])* - #[cfg(feature = "compiled_data")] - pub fn $compiled( - locale: &DataLocale, - ) -> Result<ExemplarCharactersBorrowed<'static>, DataError> { - ExemplarCharactersBorrowed::$compiled(locale) - } - - #[doc = concat!("A version of [`Self::", stringify!($compiled), "()`] that uses custom data provided by a [`DataProvider`].")] - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - pub fn $unstable( - provider: &(impl DataProvider<$data_marker> + ?Sized), - locale: &DataLocale, - ) -> Result<Self, DataError> { - Ok(Self { - data: - provider.load( - DataRequest { - id: DataIdentifierBorrowed::for_locale(locale), - ..Default::default() - })? - .payload - .cast() - }) - } - } - } -} - -make_exemplar_chars_unicode_set_property!( - dyn_data_marker: ExemplarCharactersMain; - data_marker: LocaleExemplarCharactersMainV1; - func: - pub fn try_new_main_unstable(); - - /// Get the "main" set of exemplar characters. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// # Examples - /// - /// ``` - /// use icu::locale::locale; - /// use icu::locale::exemplar_chars::ExemplarCharacters; - /// - /// let exemplars_main = ExemplarCharacters::try_new_main(&locale!("en").into()) - /// .expect("locale should be present"); - /// - /// assert!(exemplars_main.contains('a')); - /// assert!(exemplars_main.contains('z')); - /// assert!(exemplars_main.contains_str("a")); - /// assert!(!exemplars_main.contains_str("ä")); - /// assert!(!exemplars_main.contains_str("ng")); - /// assert!(!exemplars_main.contains_str("A")); - /// ``` - pub fn try_new_main(); -); - -make_exemplar_chars_unicode_set_property!( - dyn_data_marker: ExemplarCharactersAuxiliary; - data_marker: LocaleExemplarCharactersAuxiliaryV1; - func: - pub fn try_new_auxiliary_unstable(); - - /// Get the "auxiliary" set of exemplar characters. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// # Examples - /// - /// ``` - /// use icu::locale::locale; - /// use icu::locale::exemplar_chars::ExemplarCharacters; - /// - /// let exemplars_auxiliary = - /// ExemplarCharacters::try_new_auxiliary(&locale!("en").into()) - /// .expect("locale should be present"); - /// - /// assert!(!exemplars_auxiliary.contains('a')); - /// assert!(!exemplars_auxiliary.contains('z')); - /// assert!(!exemplars_auxiliary.contains_str("a")); - /// assert!(exemplars_auxiliary.contains_str("ä")); - /// assert!(!exemplars_auxiliary.contains_str("ng")); - /// assert!(!exemplars_auxiliary.contains_str("A")); - /// ``` - pub fn try_new_auxiliary(); -); - -make_exemplar_chars_unicode_set_property!( - dyn_data_marker: ExemplarCharactersPunctuation; - data_marker: LocaleExemplarCharactersPunctuationV1; - func: - pub fn try_new_punctuation_unstable(); - - /// Get the "punctuation" set of exemplar characters. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// # Examples - /// - /// ``` - /// use icu::locale::locale; - /// use icu::locale::exemplar_chars::ExemplarCharacters; - /// - /// let exemplars_punctuation = - /// ExemplarCharacters::try_new_punctuation(&locale!("en").into()) - /// .expect("locale should be present"); - /// - /// assert!(!exemplars_punctuation.contains('0')); - /// assert!(!exemplars_punctuation.contains('9')); - /// assert!(!exemplars_punctuation.contains('%')); - /// assert!(exemplars_punctuation.contains(',')); - /// assert!(exemplars_punctuation.contains('.')); - /// assert!(exemplars_punctuation.contains('!')); - /// assert!(exemplars_punctuation.contains('?')); - /// ``` - pub fn try_new_punctuation(); -); - -make_exemplar_chars_unicode_set_property!( - dyn_data_marker: ExemplarCharactersNumbers; - data_marker: LocaleExemplarCharactersNumbersV1; - func: - pub fn try_new_numbers_unstable(); - - /// Get the "numbers" set of exemplar characters. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// # Examples - /// - /// ``` - /// use icu::locale::locale; - /// use icu::locale::exemplar_chars::ExemplarCharacters; - /// - /// let exemplars_numbers = - /// ExemplarCharacters::try_new_numbers(&locale!("en").into()) - /// .expect("locale should be present"); - /// - /// assert!(exemplars_numbers.contains('0')); - /// assert!(exemplars_numbers.contains('9')); - /// assert!(exemplars_numbers.contains('%')); - /// assert!(exemplars_numbers.contains(',')); - /// assert!(exemplars_numbers.contains('.')); - /// assert!(!exemplars_numbers.contains('!')); - /// assert!(!exemplars_numbers.contains('?')); - /// ``` - pub fn try_new_numbers(); -); - -make_exemplar_chars_unicode_set_property!( - dyn_data_marker: ExemplarCharactersIndex; - data_marker: LocaleExemplarCharactersIndexV1; - func: - pub fn try_new_index_unstable(); - - /// Get the "index" set of exemplar characters. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// # Examples - /// - /// ``` - /// use icu::locale::locale; - /// use icu::locale::exemplar_chars::ExemplarCharacters; - /// - /// let exemplars_index = - /// ExemplarCharacters::try_new_index(&locale!("en").into()) - /// .expect("locale should be present"); - /// - /// assert!(!exemplars_index.contains('a')); - /// assert!(!exemplars_index.contains('z')); - /// assert!(!exemplars_index.contains_str("a")); - /// assert!(!exemplars_index.contains_str("ä")); - /// assert!(!exemplars_index.contains_str("ng")); - /// assert!(exemplars_index.contains_str("A")); - /// ``` - pub fn try_new_index(); -); diff --git a/deps/crates/vendor/icu_locale-v2/src/expander.rs b/deps/crates/vendor/icu_locale-v2/src/expander.rs deleted file mode 100644 index 6b921b44fecb..000000000000 --- a/deps/crates/vendor/icu_locale-v2/src/expander.rs +++ /dev/null @@ -1,606 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use crate::provider::*; - -use icu_locale_core::subtags::{Language, Region, Script}; -use icu_locale_core::LanguageIdentifier; -use icu_provider::prelude::*; - -use crate::TransformResult; - -/// Implements the *Add Likely Subtags* and *Remove Likely Subtags* -/// algorithms as defined in *[UTS #35: Likely Subtags]*. -/// -/// # Examples -/// -/// Add likely subtags: -/// -/// ``` -/// use icu::locale::locale; -/// use icu::locale::{LocaleExpander, TransformResult}; -/// -/// let lc = LocaleExpander::new_common(); -/// -/// let mut locale = locale!("zh-CN"); -/// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Modified); -/// assert_eq!(locale, locale!("zh-Hans-CN")); -/// -/// let mut locale = locale!("zh-Hant-TW"); -/// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Unmodified); -/// assert_eq!(locale, locale!("zh-Hant-TW")); -/// ``` -/// -/// Remove likely subtags: -/// -/// ``` -/// use icu::locale::{locale, LocaleExpander, TransformResult}; -/// -/// let lc = LocaleExpander::new_common(); -/// -/// let mut locale = locale!("zh-Hans-CN"); -/// assert_eq!(lc.minimize(&mut locale.id), TransformResult::Modified); -/// assert_eq!(locale, locale!("zh")); -/// -/// let mut locale = locale!("zh"); -/// assert_eq!(lc.minimize(&mut locale.id), TransformResult::Unmodified); -/// assert_eq!(locale, locale!("zh")); -/// ``` -/// -/// Normally, only CLDR locales with Basic or higher coverage are included. To include more -/// locales for maximization, use [`try_new_extended`](Self::try_new_extended_unstable): -/// -/// ``` -/// use icu::locale::{locale, LocaleExpander, TransformResult}; -/// -/// let lc = LocaleExpander::new_extended(); -/// -/// let mut locale = locale!("atj"); -/// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Modified); -/// assert_eq!(locale, locale!("atj-Latn-CA")); -/// ``` -/// -/// [UTS #35: Likely Subtags]: https://www.unicode.org/reports/tr35/#Likely_Subtags -#[derive(Debug, Clone)] -pub struct LocaleExpander { - likely_subtags_l: DataPayload<LocaleLikelySubtagsLanguageV1>, - likely_subtags_sr: DataPayload<LocaleLikelySubtagsScriptRegionV1>, - likely_subtags_ext: Option<DataPayload<LocaleLikelySubtagsExtendedV1>>, -} - -struct LocaleExpanderBorrowed<'a> { - likely_subtags_l: &'a LikelySubtagsForLanguage<'a>, - likely_subtags_sr: &'a LikelySubtagsForScriptRegion<'a>, - likely_subtags_ext: Option<&'a LikelySubtagsExtended<'a>>, -} - -impl LocaleExpanderBorrowed<'_> { - fn get_l(&self, l: Language) -> Option<(Script, Region)> { - let key = &l.to_tinystr().to_unvalidated(); - self.likely_subtags_l.language.get_copied(key).or_else(|| { - self.likely_subtags_ext - .and_then(|ext| ext.language.get_copied(key)) - }) - } - - fn get_ls(&self, l: Language, s: Script) -> Option<Region> { - let key = &( - l.to_tinystr().to_unvalidated(), - s.to_tinystr().to_unvalidated(), - ); - self.likely_subtags_l - .language_script - .get_copied(key) - .or_else(|| { - self.likely_subtags_ext - .and_then(|ext| ext.language_script.get_copied(key)) - }) - } - - fn get_lr(&self, l: Language, r: Region) -> Option<Script> { - let key = &( - l.to_tinystr().to_unvalidated(), - r.to_tinystr().to_unvalidated(), - ); - self.likely_subtags_l - .language_region - .get_copied(key) - .or_else(|| { - self.likely_subtags_ext - .and_then(|ext| ext.language_region.get_copied(key)) - }) - } - - fn get_s(&self, s: Script) -> Option<(Language, Region)> { - let key = &s.to_tinystr().to_unvalidated(); - self.likely_subtags_sr.script.get_copied(key).or_else(|| { - self.likely_subtags_ext - .and_then(|ext| ext.script.get_copied(key)) - }) - } - - fn get_sr(&self, s: Script, r: Region) -> Option<Language> { - let key = &( - s.to_tinystr().to_unvalidated(), - r.to_tinystr().to_unvalidated(), - ); - self.likely_subtags_sr - .script_region - .get_copied(key) - .or_else(|| { - self.likely_subtags_ext - .and_then(|ext| ext.script_region.get_copied(key)) - }) - } - - fn get_r(&self, r: Region) -> Option<(Language, Script)> { - let key = &r.to_tinystr().to_unvalidated(); - self.likely_subtags_sr.region.get_copied(key).or_else(|| { - self.likely_subtags_ext - .and_then(|ext| ext.region.get_copied(key)) - }) - } - - fn get_und(&self) -> (Language, Script, Region) { - self.likely_subtags_l.und - } -} - -#[inline] -fn update_langid( - language: Language, - script: Option<Script>, - region: Option<Region>, - langid: &mut LanguageIdentifier, -) -> TransformResult { - let mut modified = false; - - if langid.language.is_unknown() && !language.is_unknown() { - langid.language = language; - modified = true; - } - - if langid.script.is_none() && script.is_some() { - langid.script = script; - modified = true; - } - - if langid.region.is_none() && region.is_some() { - langid.region = region; - modified = true; - } - - if modified { - TransformResult::Modified - } else { - TransformResult::Unmodified - } -} - -#[inline] -fn update_langid_minimize( - language: Language, - script: Option<Script>, - region: Option<Region>, - langid: &mut LanguageIdentifier, -) -> TransformResult { - let mut modified = false; - - if langid.language != language { - langid.language = language; - modified = true; - } - - if langid.script != script { - langid.script = script; - modified = true; - } - - if langid.region != region { - langid.region = region; - modified = true; - } - - if modified { - TransformResult::Modified - } else { - TransformResult::Unmodified - } -} - -impl LocaleExpander { - /// Creates a [`LocaleExpander`] with compiled data for commonly-used locales - /// (locales with *Basic* or higher [CLDR coverage]). - /// - /// Use this constructor if you want limited likely subtags for data-oriented use cases. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// [CLDR coverage]: https://www.unicode.org/reports/tr35/tr35-info.html#Coverage_Levels - #[cfg(feature = "compiled_data")] - pub const fn new_common() -> Self { - LocaleExpander { - likely_subtags_l: DataPayload::from_static_ref( - Baked::SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1, - ), - likely_subtags_sr: DataPayload::from_static_ref( - Baked::SINGLETON_LOCALE_LIKELY_SUBTAGS_SCRIPT_REGION_V1, - ), - likely_subtags_ext: None, - } - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new_common: skip, - try_new_common_with_buffer_provider, - try_new_common_unstable, - Self - ]); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_common)] - pub fn try_new_common_unstable<P>(provider: &P) -> Result<LocaleExpander, DataError> - where - P: DataProvider<LocaleLikelySubtagsLanguageV1> - + DataProvider<LocaleLikelySubtagsScriptRegionV1> - + ?Sized, - { - let likely_subtags_l = provider.load(Default::default())?.payload; - let likely_subtags_sr = provider.load(Default::default())?.payload; - - Ok(LocaleExpander { - likely_subtags_l, - likely_subtags_sr, - likely_subtags_ext: None, - }) - } - - /// Creates a [`LocaleExpander`] with compiled data for all locales. - /// - /// Use this constructor if you want to include data for all locales, including ones - /// that may not have data for other services (i.e. [CLDR coverage] below *Basic*). - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - /// - /// [CLDR coverage]: https://www.unicode.org/reports/tr35/tr35-info.html#Coverage_Levels - #[cfg(feature = "compiled_data")] - pub const fn new_extended() -> Self { - LocaleExpander { - likely_subtags_l: DataPayload::from_static_ref( - Baked::SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1, - ), - likely_subtags_sr: DataPayload::from_static_ref( - Baked::SINGLETON_LOCALE_LIKELY_SUBTAGS_SCRIPT_REGION_V1, - ), - likely_subtags_ext: Some(DataPayload::from_static_ref( - Baked::SINGLETON_LOCALE_LIKELY_SUBTAGS_EXTENDED_V1, - )), - } - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new_extended: skip, - try_new_extended_with_buffer_provider, - try_new_extended_unstable, - Self - ]); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_extended)] - pub fn try_new_extended_unstable<P>(provider: &P) -> Result<LocaleExpander, DataError> - where - P: DataProvider<LocaleLikelySubtagsLanguageV1> - + DataProvider<LocaleLikelySubtagsScriptRegionV1> - + DataProvider<LocaleLikelySubtagsExtendedV1> - + ?Sized, - { - let likely_subtags_l = provider.load(Default::default())?.payload; - let likely_subtags_sr = provider.load(Default::default())?.payload; - let likely_subtags_ext = Some(provider.load(Default::default())?.payload); - - Ok(LocaleExpander { - likely_subtags_l, - likely_subtags_sr, - likely_subtags_ext, - }) - } - - fn as_borrowed(&self) -> LocaleExpanderBorrowed<'_> { - LocaleExpanderBorrowed { - likely_subtags_l: self.likely_subtags_l.get(), - likely_subtags_sr: self.likely_subtags_sr.get(), - likely_subtags_ext: self.likely_subtags_ext.as_ref().map(|p| p.get()), - } - } - - /// The maximize method potentially updates a passed in locale in place - /// depending up the results of running the 'Add Likely Subtags' algorithm - /// from <https://www.unicode.org/reports/tr35/#Likely_Subtags>. - /// - /// If the result of running the algorithm would result in a new locale, the - /// locale argument is updated in place to match the result, and the method - /// returns [`TransformResult::Modified`]. Otherwise, the method - /// returns [`TransformResult::Unmodified`] and the locale argument is - /// unchanged. - /// - /// This function does not guarantee that any particular set of subtags - /// will be present in the resulting locale. - /// - /// # Examples - /// - /// ``` - /// use icu::locale::{locale, LocaleExpander, TransformResult}; - /// - /// let lc = LocaleExpander::new_common(); - /// - /// let mut locale = locale!("zh-CN"); - /// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Modified); - /// assert_eq!(locale, locale!("zh-Hans-CN")); - /// - /// let mut locale = locale!("zh-Hant-TW"); - /// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Unmodified); - /// assert_eq!(locale, locale!("zh-Hant-TW")); - /// ``` - /// - /// If there is no data for a particular language, the result is not - /// modified. Note that [`LocaleExpander::new_extended`] supports - /// more languages. - /// - /// ``` - /// use icu::locale::{locale, LocaleExpander, TransformResult}; - /// - /// let lc = LocaleExpander::new_common(); - /// - /// // No subtags data for ccp in the default set: - /// let mut locale = locale!("ccp"); - /// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Unmodified); - /// assert_eq!(locale, locale!("ccp")); - /// - /// // The extended set supports it: - /// let lc = LocaleExpander::new_extended(); - /// let mut locale = locale!("ccp"); - /// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Modified); - /// assert_eq!(locale, locale!("ccp-Cakm-BD")); - /// - /// // But even the extended set does not support all language subtags: - /// let mut locale = locale!("mul"); - /// assert_eq!(lc.maximize(&mut locale.id), TransformResult::Unmodified); - /// assert_eq!(locale, locale!("mul")); - /// ``` - pub fn maximize(&self, langid: &mut LanguageIdentifier) -> TransformResult { - let data = self.as_borrowed(); - - if !langid.language.is_unknown() && langid.script.is_some() && langid.region.is_some() { - return TransformResult::Unmodified; - } - - if !langid.language.is_unknown() { - if let Some(region) = langid.region { - if let Some(script) = data.get_lr(langid.language, region) { - return update_langid(Language::UNKNOWN, Some(script), None, langid); - } - } - if let Some(script) = langid.script { - if let Some(region) = data.get_ls(langid.language, script) { - return update_langid(Language::UNKNOWN, None, Some(region), langid); - } - } - if let Some((script, region)) = data.get_l(langid.language) { - return update_langid(Language::UNKNOWN, Some(script), Some(region), langid); - } - // Language not found: return unmodified. - return TransformResult::Unmodified; - } - if let Some(script) = langid.script { - if let Some(region) = langid.region { - if let Some(language) = data.get_sr(script, region) { - return update_langid(language, None, None, langid); - } - } - if let Some((language, region)) = data.get_s(script) { - return update_langid(language, None, Some(region), langid); - } - } - if let Some(region) = langid.region { - if let Some((language, script)) = data.get_r(region) { - return update_langid(language, Some(script), None, langid); - } - } - - // We failed to find anything in the und-SR, und-S, or und-R tables, - // to fall back to bare "und" - debug_assert!(langid.language.is_unknown()); - update_langid( - data.get_und().0, - Some(data.get_und().1), - Some(data.get_und().2), - langid, - ) - } - - /// This returns a new Locale that is the result of running the - /// 'Remove Likely Subtags' algorithm from - /// <https://www.unicode.org/reports/tr35/#Likely_Subtags>. - /// - /// If the result of running the algorithm would result in a new locale, the - /// locale argument is updated in place to match the result, and the method - /// returns [`TransformResult::Modified`]. Otherwise, the method - /// returns [`TransformResult::Unmodified`] and the locale argument is - /// unchanged. - /// - /// # Examples - /// - /// ``` - /// use icu::locale::{locale, LocaleExpander, TransformResult}; - /// - /// let lc = LocaleExpander::new_common(); - /// - /// let mut locale = locale!("zh-Hans-CN"); - /// assert_eq!(lc.minimize(&mut locale.id), TransformResult::Modified); - /// assert_eq!(locale, locale!("zh")); - /// - /// let mut locale = locale!("zh"); - /// assert_eq!(lc.minimize(&mut locale.id), TransformResult::Unmodified); - /// assert_eq!(locale, locale!("zh")); - /// ``` - pub fn minimize(&self, langid: &mut LanguageIdentifier) -> TransformResult { - self.minimize_impl(langid, true) - } - - /// This returns a new Locale that is the result of running the - /// 'Remove Likely Subtags, favoring script' algorithm from - /// <https://www.unicode.org/reports/tr35/#Likely_Subtags>. - /// - /// If the result of running the algorithm would result in a new locale, the - /// locale argument is updated in place to match the result, and the method - /// returns [`TransformResult::Modified`]. Otherwise, the method - /// returns [`TransformResult::Unmodified`] and the locale argument is - /// unchanged. - /// - /// # Examples - /// - /// ``` - /// use icu::locale::{locale, LocaleExpander, TransformResult}; - /// - /// let lc = LocaleExpander::new_common(); - /// - /// let mut locale = locale!("zh-TW"); - /// assert_eq!( - /// lc.minimize_favor_script(&mut locale.id), - /// TransformResult::Modified - /// ); - /// assert_eq!(locale, locale!("zh-Hant")); - /// ``` - pub fn minimize_favor_script(&self, langid: &mut LanguageIdentifier) -> TransformResult { - self.minimize_impl(langid, false) - } - - fn minimize_impl( - &self, - langid: &mut LanguageIdentifier, - favor_region: bool, - ) -> TransformResult { - let mut max = langid.clone(); - self.maximize(&mut max); - - let mut trial = max.clone(); - - trial.script = None; - trial.region = None; - self.maximize(&mut trial); - if trial == max { - return update_langid_minimize(max.language, None, None, langid); - } - - if favor_region { - trial.script = None; - trial.region = max.region; - self.maximize(&mut trial); - - if trial == max { - return update_langid_minimize(max.language, None, max.region, langid); - } - - trial.script = max.script; - trial.region = None; - self.maximize(&mut trial); - if trial == max { - return update_langid_minimize(max.language, max.script, None, langid); - } - } else { - trial.script = max.script; - trial.region = None; - self.maximize(&mut trial); - if trial == max { - return update_langid_minimize(max.language, max.script, None, langid); - } - - trial.script = None; - trial.region = max.region; - self.maximize(&mut trial); - - if trial == max { - return update_langid_minimize(max.language, None, max.region, langid); - } - } - - update_langid_minimize(max.language, max.script, max.region, langid) - } - - // TODO(3492): consider turning this and a future get_likely_region/get_likely_language public - #[inline] - pub(crate) fn get_likely_script(&self, langid: &LanguageIdentifier) -> Option<Script> { - langid - .script - .or_else(|| self.infer_likely_script(langid.language, langid.region)) - } - - fn infer_likely_script(&self, language: Language, region: Option<Region>) -> Option<Script> { - let data = self.as_borrowed(); - - // proceed through _all possible cases_ in order of specificity - // (borrowed from LocaleExpander::maximize): - // 1. language + region - // 2. language - // 3. region - // we need to check all cases, because e.g. for "en-US" the default script is associated - // with "en" but not "en-US" - if !language.is_unknown() { - if let Some(region) = region { - // 1. we know both language and region - if let Some(script) = data.get_lr(language, region) { - return Some(script); - } - } - // 2. we know language, but we either do not know region or knowing region did not help - if let Some((script, _)) = data.get_l(language) { - return Some(script); - } - } - if let Some(region) = region { - // 3. we know region, but we either do not know language or knowing language did not help - if let Some((_, script)) = data.get_r(region) { - return Some(script); - } - } - // we could not figure out the script from the given locale - None - } -} - -impl AsRef<LocaleExpander> for LocaleExpander { - fn as_ref(&self) -> &LocaleExpander { - self - } -} - -#[cfg(feature = "serde")] -#[cfg(test)] -mod tests { - use super::*; - use icu_locale_core::locale; - - #[test] - fn test_minimize_favor_script() { - let lc = LocaleExpander::new_common(); - let mut locale = locale!("yue-Hans"); - assert_eq!( - lc.minimize_favor_script(&mut locale.id), - TransformResult::Unmodified - ); - assert_eq!(locale, locale!("yue-Hans")); - } - - #[test] - fn test_minimize_favor_region() { - let lc = LocaleExpander::new_common(); - let mut locale = locale!("yue-Hans"); - assert_eq!(lc.minimize(&mut locale.id), TransformResult::Modified); - assert_eq!(locale, locale!("yue-CN")); - } -} diff --git a/deps/crates/vendor/icu_locale-v2/src/lib.rs b/deps/crates/vendor/icu_locale-v2/src/lib.rs deleted file mode 100644 index 2c9200102337..000000000000 --- a/deps/crates/vendor/icu_locale-v2/src/lib.rs +++ /dev/null @@ -1,109 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -// https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations -#![cfg_attr(not(any(test, doc)), no_std)] -#![cfg_attr( - not(test), - deny( - clippy::indexing_slicing, - clippy::unwrap_used, - clippy::expect_used, - clippy::panic, - ) -)] -#![warn(missing_docs)] - -//! Canonicalization of locale identifiers based on [`CLDR`] data. -//! -//! This module is published as its own crate ([`icu_locale`](https://docs.rs/icu_locale/latest/icu_locale/)) -//! and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project. -//! -//! It currently supports locale canonicalization based upon the canonicalization -//! algorithm from [`UTS #35: Unicode LDML 3. LocaleId Canonicalization`], -//! as well as the minimize and maximize likely subtags algorithms -//! as described in [`UTS #35: Unicode LDML 3. Likely Subtags`]. -//! -//! The maximize method potentially updates a passed in locale in place -//! depending up the results of running the 'Add Likely Subtags' algorithm -//! from [`UTS #35: Unicode LDML 3. Likely Subtags`]. -//! -//! This minimize method returns a new Locale that is the result of running the -//! 'Remove Likely Subtags' algorithm from [`UTS #35: Unicode LDML 3. Likely Subtags`]. -//! -//! # Examples -//! -//! ``` -//! use icu::locale::Locale; -//! use icu::locale::{LocaleCanonicalizer, TransformResult}; -//! -//! let lc = LocaleCanonicalizer::new_extended(); -//! -//! let mut locale: Locale = "ja-Latn-fonipa-hepburn-heploc" -//! .parse() -//! .expect("parse failed"); -//! assert_eq!(lc.canonicalize(&mut locale), TransformResult::Modified); -//! assert_eq!(locale, "ja-Latn-alalc97-fonipa".parse::<Locale>().unwrap()); -//! ``` -//! -//! ``` -//! use icu::locale::{locale, LocaleExpander, TransformResult}; -//! -//! let lc = LocaleExpander::new_common(); -//! -//! let mut locale = locale!("zh-CN"); -//! assert_eq!(lc.maximize(&mut locale.id), TransformResult::Modified); -//! assert_eq!(locale, locale!("zh-Hans-CN")); -//! -//! let mut locale = locale!("zh-Hant-TW"); -//! assert_eq!(lc.maximize(&mut locale.id), TransformResult::Unmodified); -//! assert_eq!(locale, locale!("zh-Hant-TW")); -//! ``` -//! -//! ``` -//! use icu::locale::{locale, LocaleExpander, TransformResult}; -//! use writeable::assert_writeable_eq; -//! -//! let lc = LocaleExpander::new_common(); -//! -//! let mut locale = locale!("zh-Hans-CN"); -//! assert_eq!(lc.minimize(&mut locale.id), TransformResult::Modified); -//! assert_eq!(locale, locale!("zh")); -//! -//! let mut locale = locale!("zh"); -//! assert_eq!(lc.minimize(&mut locale.id), TransformResult::Unmodified); -//! assert_eq!(locale, locale!("zh")); -//! ``` -//! -//! [`ICU4X`]: ../icu/index.html -//! [`CLDR`]: https://cldr.unicode.org/ -//! [`UTS #35: Unicode LDML 3. Likely Subtags`]: https://www.unicode.org/reports/tr35/#Likely_Subtags. -//! [`UTS #35: Unicode LDML 3. LocaleId Canonicalization`]: https://unicode.org/reports/tr35/#LocaleId_Canonicalization, - -extern crate alloc; - -mod canonicalizer; -mod directionality; -pub mod exemplar_chars; -mod expander; -pub mod fallback; -pub mod provider; - -pub use icu_locale_core::*; - -pub use canonicalizer::LocaleCanonicalizer; -pub use directionality::{Direction, LocaleDirectionality}; -pub use expander::LocaleExpander; -#[doc(inline)] -pub use fallback::LocaleFallbacker; - -/// Used to track the result of a transformation operation that potentially modifies its argument in place. -#[derive(Debug, PartialEq)] -#[allow(clippy::exhaustive_enums)] // this enum is stable -pub enum TransformResult { - /// The canonicalization operation modified the locale. - Modified, - /// The canonicalization operation did not modify the locale. - Unmodified, -} diff --git a/deps/crates/vendor/icu_locale-v2/src/provider.rs b/deps/crates/vendor/icu_locale-v2/src/provider.rs deleted file mode 100644 index 6999fde25a54..000000000000 --- a/deps/crates/vendor/icu_locale-v2/src/provider.rs +++ /dev/null @@ -1,488 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -// Provider structs must be stable -#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] - -//! 🚧 \[Unstable\] Data provider struct definitions for this ICU4X component. -//! -//! <div class="stab unstable"> -//! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -//! including in SemVer minor releases. While the serde representation of data structs is guaranteed -//! to be stable, their Rust representation might not be. Use with caution. -//! </div> -//! -//! Read more about data providers: [`icu_provider`] - -#[cfg(feature = "compiled_data")] -#[derive(Debug)] -/// Baked data -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. In particular, the `DataProvider` implementations are only -/// guaranteed to match with this version's `*_unstable` providers. Use with caution. -/// </div> -pub struct Baked; - -#[cfg(feature = "compiled_data")] -#[allow(unused_imports)] -const _: () = { - use icu_locale_data::*; - pub mod icu { - pub use crate as locale; - pub use icu_collections as collections; - } - make_provider!(Baked); - impl_locale_aliases_v1!(Baked); - impl_locale_likely_subtags_extended_v1!(Baked); - impl_locale_likely_subtags_language_v1!(Baked); - impl_locale_likely_subtags_script_region_v1!(Baked); - impl_locale_parents_v1!(Baked); - impl_locale_script_direction_v1!(Baked); - - impl_locale_exemplar_characters_auxiliary_v1!(Baked); - impl_locale_exemplar_characters_index_v1!(Baked); - impl_locale_exemplar_characters_main_v1!(Baked); - impl_locale_exemplar_characters_numbers_v1!(Baked); - impl_locale_exemplar_characters_punctuation_v1!(Baked); -}; - -icu_provider::data_marker!( - /// Marker for locale alias data. - LocaleAliasesV1, - "locale/aliases/v1", - Aliases<'static>, - is_singleton = true -); -icu_provider::data_marker!( - /// Marker for data for likely subtags for languages. - LocaleLikelySubtagsLanguageV1, - "locale/likely/subtags/language/v1", - LikelySubtagsForLanguage<'static>, - is_singleton = true -); -icu_provider::data_marker!( - /// Marker for data for likely subtags for scripts and regions. - LocaleLikelySubtagsScriptRegionV1, - "locale/likely/subtags/script/region/v1", - LikelySubtagsForScriptRegion<'static>, - is_singleton = true -); -icu_provider::data_marker!( - /// Marker for extended data for likely subtags. - LocaleLikelySubtagsExtendedV1, - "locale/likely/subtags/extended/v1", - LikelySubtagsExtended<'static>, - is_singleton = true -); -icu_provider::data_marker!( - /// Marker for locale fallback parents data. - LocaleParentsV1, - "locale/parents/v1", - Parents<'static>, - is_singleton = true -); - -icu_provider::data_marker!( - /// Marker for script direction data. - LocaleScriptDirectionV1, - "locale/script/direction/v1", - ScriptDirection<'static>, - is_singleton = true -); - -icu_provider::data_marker!( - /// Marker for auxiliary exemplar characters data. - LocaleExemplarCharactersAuxiliaryV1, - "locale/exemplar/characters/auxiliary/v1", - ExemplarCharactersData<'static>, -); -icu_provider::data_marker!( - /// Marker for index exemplar characters data. - LocaleExemplarCharactersIndexV1, - "locale/exemplar/characters/index/v1", - ExemplarCharactersData<'static>, -); -icu_provider::data_marker!( - /// Marker for main exemplar characters data. - LocaleExemplarCharactersMainV1, - "locale/exemplar/characters/main/v1", - ExemplarCharactersData<'static>, -); -icu_provider::data_marker!( - /// Marker for numbers exemplar characters data. - LocaleExemplarCharactersNumbersV1, - "locale/exemplar/characters/numbers/v1", - ExemplarCharactersData<'static>, -); -icu_provider::data_marker!( - /// Marker for punctuation exemplar characters data. - LocaleExemplarCharactersPunctuationV1, - "locale/exemplar/characters/punctuation/v1", - ExemplarCharactersData<'static>, -); - -#[cfg(feature = "datagen")] -/// The latest minimum set of markers required by this component. -pub const MARKERS: &[DataMarkerInfo] = &[ - LocaleAliasesV1::INFO, - LocaleExemplarCharactersAuxiliaryV1::INFO, - LocaleExemplarCharactersIndexV1::INFO, - LocaleExemplarCharactersMainV1::INFO, - LocaleExemplarCharactersNumbersV1::INFO, - LocaleExemplarCharactersPunctuationV1::INFO, - LocaleLikelySubtagsExtendedV1::INFO, - LocaleLikelySubtagsLanguageV1::INFO, - LocaleLikelySubtagsScriptRegionV1::INFO, - LocaleParentsV1::INFO, - LocaleScriptDirectionV1::INFO, -]; - -#[cfg(doc)] -use crate::LanguageIdentifier; -use alloc::borrow::Cow; -use icu_collections::codepointinvliststringlist::CodePointInversionListAndStringList; -use icu_locale_core::subtags::{Language, Region, Script, Variant}; -use icu_provider::prelude::*; -use potential_utf::PotentialUtf8; -use tinystr::{TinyAsciiStr, UnvalidatedTinyAsciiStr}; -use zerovec::{VarZeroVec, ZeroMap, ZeroSlice, ZeroVec}; - -// We use raw TinyAsciiStrs for map keys, as we then don't have to -// validate them as subtags on deserialization. Map lookup can be -// done even if they are not valid tags (an invalid key will just -// become inaccessible). -type UnvalidatedLanguage = UnvalidatedTinyAsciiStr<3>; -type UnvalidatedScript = UnvalidatedTinyAsciiStr<4>; -type UnvalidatedRegion = UnvalidatedTinyAsciiStr<3>; -type UnvalidatedVariant = UnvalidatedTinyAsciiStr<8>; -type UnvalidatedSubdivision = UnvalidatedTinyAsciiStr<7>; -type SemivalidatedSubdivision = TinyAsciiStr<7>; - -// LanguageIdentifier doesn't have an AsULE implementation, so we have -// to store strs and parse when needed. -type UnvalidatedLanguageIdentifier = str; -type UnvalidatedLanguageIdentifierPair = StrStrPairVarULE; -type UnvalidatedLanguageVariantsPair = LanguageStrStrPairVarULE; - -#[zerovec::make_varule(StrStrPairVarULE)] -#[zerovec::derive(Debug)] -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize), - zerovec::derive(Deserialize) -)] -#[cfg_attr( - feature = "datagen", - derive(serde::Serialize, databake::Bake), - zerovec::derive(Serialize), - databake(path = icu_locale::provider), -)] -/// A pair of strings with a [`EncodeAsVarULE`](zerovec::ule::EncodeAsVarULE) implementation. -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -pub struct StrStrPair<'a>( - #[cfg_attr(feature = "serde", serde(borrow))] pub Cow<'a, str>, - #[cfg_attr(feature = "serde", serde(borrow))] pub Cow<'a, str>, -); - -#[zerovec::make_varule(LanguageStrStrPairVarULE)] -#[zerovec::derive(Debug)] -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize), - zerovec::derive(Deserialize) -)] -#[cfg_attr( - feature = "datagen", - derive(serde::Serialize, databake::Bake), - zerovec::derive(Serialize), - databake(path = icu_locale::provider), -)] -/// A triplet of strings with a [`EncodeAsVarULE`](zerovec::ule::EncodeAsVarULE) implementation. -pub struct LanguageStrStrPair<'a>( - pub Language, - #[cfg_attr(feature = "serde", serde(borrow))] pub Cow<'a, str>, - #[cfg_attr(feature = "serde", serde(borrow))] pub Cow<'a, str>, -); - -#[derive(PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_locale::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -#[yoke(prove_covariance_manually)] -/// This alias data is used for locale canonicalization. -/// -/// Each field defines a -/// mapping from an old identifier to a new identifier, based upon the rules in -/// from <https://unicode.org/reports/tr35/#LocaleId_Canonicalization>. The data -/// is stored in sorted order, allowing for binary search to identify rules to -/// apply. It is broken down into smaller vectors based upon some characteristic -/// of the data, to help avoid unnecessary searches. For example, the `sgn_region` -/// field contains aliases for sign language and region, so that it is not -/// necessary to search the data unless the input is a sign language. -/// -/// The algorithm in tr35 is not guaranteed to terminate on data other than what -/// is currently in CLDR. For this reason, it is not a good idea to attempt to add -/// or modify aliases for use in this structure. -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -// TODO: Use validated types as value types -// Notice: improves the alignment of `language_variants` speeding up canonicalization by upon -// to 40%. See https://github.com/unicode-org/icu4x/pull/2935 for details. -#[derive(Debug)] -pub struct Aliases<'data> { - /// `[language, variant(-variant)*] -> [langid]` - /// This is not a map as it's searched linearly according to the canonicalization rules. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_variants: VarZeroVec<'data, UnvalidatedLanguageVariantsPair>, - /// `sgn-[region] -> [language]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub sgn_region: ZeroMap<'data, UnvalidatedRegion, Language>, - /// `[language{2}] -> [langid]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_len2: ZeroMap<'data, UnvalidatedTinyAsciiStr<2>, UnvalidatedLanguageIdentifier>, - /// `[language{3}] -> [langid]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_len3: ZeroMap<'data, UnvalidatedLanguage, UnvalidatedLanguageIdentifier>, - /// `[langid] -> [langid]` - /// This is not a map as it's searched linearly according to the canonicalization rules. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language: VarZeroVec<'data, UnvalidatedLanguageIdentifierPair>, - - /// `[script] -> [script]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub script: ZeroMap<'data, UnvalidatedScript, Script>, - - /// `[region{2}] -> [region]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub region_alpha: ZeroMap<'data, UnvalidatedTinyAsciiStr<2>, Region>, - /// `[region{3}] -> [region]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub region_num: ZeroMap<'data, UnvalidatedRegion, Region>, - - /// `[region] -> [region]+` - #[cfg_attr(feature = "serde", serde(borrow))] - pub complex_region: ZeroMap<'data, UnvalidatedRegion, ZeroSlice<Region>>, - - /// `[variant] -> [variant]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub variant: ZeroMap<'data, UnvalidatedVariant, Variant>, - - /// `[value{7}] -> [value{7}]` - #[cfg_attr(feature = "serde", serde(borrow))] - pub subdivision: ZeroMap<'data, UnvalidatedSubdivision, SemivalidatedSubdivision>, -} - -icu_provider::data_struct!( - Aliases<'_>, - #[cfg(feature = "datagen")] -); - -#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_locale::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -/// This likely subtags data is used for the minimize and maximize operations. -/// -/// Each field defines a mapping from an old identifier to a new identifier, -/// based upon the rules in -/// <https://www.unicode.org/reports/tr35/#Likely_Subtags>. -/// -/// The data is stored is broken down into smaller vectors based upon the rules -/// defined for the likely subtags maximize algorithm. -/// -/// For efficiency, only the relevant part of the [`LanguageIdentifier`] is stored -/// for searching and replacing. E.g., the `language_script` field is used to store -/// rules for [`LanguageIdentifier`]s that contain a language and a script, but not a -/// region. -/// -/// This struct contains mappings when the input contains a language subtag. -/// Also see [`LikelySubtagsForScriptRegion`]. -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -#[yoke(prove_covariance_manually)] -pub struct LikelySubtagsForLanguage<'data> { - /// Language and script. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_script: ZeroMap<'data, (UnvalidatedLanguage, UnvalidatedScript), Region>, - /// Language and region. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_region: ZeroMap<'data, (UnvalidatedLanguage, UnvalidatedRegion), Script>, - /// Just language. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language: ZeroMap<'data, UnvalidatedLanguage, (Script, Region)>, - /// Undefined. - pub und: (Language, Script, Region), -} - -icu_provider::data_struct!( - LikelySubtagsForLanguage<'_>, - #[cfg(feature = "datagen")] -); - -#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_locale::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -/// This likely subtags data is used for the minimize and maximize operations. -/// -/// Each field defines a mapping from an old identifier to a new identifier, -/// based upon the rules in -/// <https://www.unicode.org/reports/tr35/#Likely_Subtags>. -/// -/// The data is stored is broken down into smaller vectors based upon the rules -/// defined for the likely subtags maximize algorithm. -/// -/// For efficiency, only the relevant part of the [`LanguageIdentifier`] is stored -/// for searching and replacing. E.g., the `script_region` field is used to store -/// rules for [`LanguageIdentifier`]s that contain a script and a region, but not a -/// language. -/// -/// This struct contains mappings when the input does not contain a language subtag. -/// Also see [`LikelySubtagsForLanguage`]. -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -#[yoke(prove_covariance_manually)] -pub struct LikelySubtagsForScriptRegion<'data> { - /// Script and region. - #[cfg_attr(feature = "serde", serde(borrow))] - pub script_region: ZeroMap<'data, (UnvalidatedScript, UnvalidatedRegion), Language>, - /// Just script. - #[cfg_attr(feature = "serde", serde(borrow))] - pub script: ZeroMap<'data, UnvalidatedScript, (Language, Region)>, - /// Just region. - #[cfg_attr(feature = "serde", serde(borrow))] - pub region: ZeroMap<'data, UnvalidatedRegion, (Language, Script)>, -} - -icu_provider::data_struct!( - LikelySubtagsForScriptRegion<'_>, - #[cfg(feature = "datagen")] -); - -#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_locale::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -/// This likely subtags data is used for full coverage of locales, including ones that -/// don't otherwise have data in the Common Locale Data Repository (CLDR). -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -#[yoke(prove_covariance_manually)] -pub struct LikelySubtagsExtended<'data> { - /// Language and script. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_script: ZeroMap<'data, (UnvalidatedLanguage, UnvalidatedScript), Region>, - /// Language and region. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language_region: ZeroMap<'data, (UnvalidatedLanguage, UnvalidatedRegion), Script>, - /// Just language. - #[cfg_attr(feature = "serde", serde(borrow))] - pub language: ZeroMap<'data, UnvalidatedLanguage, (Script, Region)>, - /// Script and region. - #[cfg_attr(feature = "serde", serde(borrow))] - pub script_region: ZeroMap<'data, (UnvalidatedScript, UnvalidatedRegion), Language>, - /// Just script. - #[cfg_attr(feature = "serde", serde(borrow))] - pub script: ZeroMap<'data, UnvalidatedScript, (Language, Region)>, - /// Just region. - #[cfg_attr(feature = "serde", serde(borrow))] - pub region: ZeroMap<'data, UnvalidatedRegion, (Language, Script)>, -} - -icu_provider::data_struct!( - LikelySubtagsExtended<'_>, - #[cfg(feature = "datagen")] -); - -/// Locale fallback rules derived from CLDR parent locales data. -#[derive(Default, Clone, PartialEq, Debug, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_locale::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -#[yoke(prove_covariance_manually)] -pub struct Parents<'data> { - /// Map from language identifier to language identifier, indicating that the language on the - /// left should inherit from the language on the right. - #[cfg_attr(feature = "serde", serde(borrow))] - pub parents: ZeroMap<'data, PotentialUtf8, (Language, Option<Script>, Option<Region>)>, -} - -icu_provider::data_struct!( - Parents<'_>, - #[cfg(feature = "datagen")] -); - -#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_locale::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -/// This directionality data is used to determine the script directionality of a locale. -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -#[yoke(prove_covariance_manually)] -pub struct ScriptDirection<'data> { - /// Scripts in right-to-left direction. - #[cfg_attr(feature = "serde", serde(borrow))] - pub rtl: ZeroVec<'data, UnvalidatedScript>, - /// Scripts in left-to-right direction. - #[cfg_attr(feature = "serde", serde(borrow))] - pub ltr: ZeroVec<'data, UnvalidatedScript>, -} - -icu_provider::data_struct!( - ScriptDirection<'_>, - #[cfg(feature = "datagen")] -); - -/// A set of characters and strings which share a particular property value. -/// -/// <div class="stab unstable"> -/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -/// </div> -#[derive(Debug, Eq, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr( - feature = "datagen", - derive(serde::Serialize, databake::Bake), - databake(path = icu_locale::provider), -)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct ExemplarCharactersData<'data>( - #[cfg_attr(feature = "serde", serde(borrow))] pub CodePointInversionListAndStringList<'data>, -); - -icu_provider::data_struct!( - ExemplarCharactersData<'_>, - #[cfg(feature = "datagen")] -); diff --git a/deps/crates/vendor/icu_locale-v2/tests/fixtures/canonicalize.json b/deps/crates/vendor/icu_locale-v2/tests/fixtures/canonicalize.json deleted file mode 100644 index 89e6cec052a6..000000000000 --- a/deps/crates/vendor/icu_locale-v2/tests/fixtures/canonicalize.json +++ /dev/null @@ -1,444 +0,0 @@ -[ - { - "input": "es", - "output": "es" - }, - { - "input": "en-CA", - "output": "en-CA" - }, - { - "input": "cka", - "output": "cmr" - }, - { - "input": "cze", - "output": "cs" - }, - { - "input": "gfx", - "output": "vaj" - }, - { - "input": "sgn-BR", - "output": "bzs" - }, - { - "input": "sgn-DD", - "output": "gsg" - }, - { - "input": "tam", - "output": "ta" - }, - { - "input": "und-aaland", - "output": "und-AX" - }, - { - "input": "nob-bokmal", - "output": "nb" - }, - { - "input": "no-nynorsk", - "output": "nn" - }, - { - "input": "und-Qaai", - "output": "und-Zinh" - }, - { - "input": "en-554", - "output": "en-NZ" - }, - { - "input": "en-084", - "output": "en-BZ" - }, - { - "input": "art-lojban", - "output": "jbo" - }, - { - "input": "zh-guoyu", - "output": "zh" - }, - { - "input": "zh-hakka", - "output": "hak" - }, - { - "input": "zh-xiang", - "output": "hsn" - }, - { - "input": "aar-x-private", - "output": "aa-x-private" - }, - { - "input": "heb-x-private", - "output": "he-x-private" - }, - { - "input": "ces", - "output": "cs" - }, - { - "input": "hy-arevela", - "output": "hy" - }, - { - "input": "hy-arevmda", - "output": "hyw" - }, - { - "input": "cel-gaulish", - "output": "xtg" - }, - { - "input": "ja-latn-hepburn-heploc", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-fonipa-hepburn-heploc", - "output": "ja-Latn-alalc97-fonipa" - }, - { - "input": "und-Armn-SU", - "output": "und-Armn-AM" - }, - { - "input": "sh", - "output": "sr-Latn" - }, - { - "input": "sh-Cyrl", - "output": "sr-Cyrl" - }, - { - "input": "cnr", - "output": "sr-ME" - }, - { - "input": "cnr-BA", - "output": "sr-BA" - }, - { - "input": "ru-SU", - "output": "ru-RU" - }, - { - "input": "ru-810", - "output": "ru-RU" - }, - { - "input": "en-SU", - "output": "en-RU" - }, - { - "input": "en-810", - "output": "en-RU" - }, - { - "input": "und-SU", - "output": "und-RU" - }, - { - "input": "und-810", - "output": "und-RU" - }, - { - "input": "und-Latn-SU", - "output": "und-Latn-RU" - }, - { - "input": "und-Latn-810", - "output": "und-Latn-RU" - }, - { - "input": "hy-SU", - "output": "hy-AM" - }, - { - "input": "hy-810", - "output": "hy-AM" - }, - { - "input": "und-Armn-SU", - "output": "und-Armn-AM" - }, - { - "input": "und-Armn-810", - "output": "und-Armn-AM" - }, - { - "input": "sr-CS", - "output": "sr-RS" - }, - { - "input": "sr-Latn-CS", - "output": "sr-Latn-RS" - }, - { - "input": "sr-Cyrl-CS", - "output": "sr-Cyrl-RS" - }, - { - "input": "az-NT", - "output": "az-SA" - }, - { - "input": "sl-t-sl-rozaj-biske-1994", - "output": "sl-t-sl-1994-biske-rozaj" - }, - { - "input": "DE-T-M0-DIN-K0-QWERTZ", - "output": "de-t-k0-qwertz-m0-din" - }, - { - "input": "en-t-m0-true", - "output": "en-t-m0-true" - }, - { - "input": "en-t-iw", - "output": "en-t-he" - }, - { - "input": "und-u-rg-no23", - "output": "und-u-rg-no50" - }, - { - "input": "und-u-rg-cn11", - "output": "und-u-rg-cnbj" - }, - { - "input": "und-u-rg-cz10a", - "output": "und-u-rg-cz110" - }, - { - "input": "und-u-rg-fra", - "output": "und-u-rg-frges" - }, - { - "input": "und-u-rg-frg", - "output": "und-u-rg-frges" - }, - { - "input": "und-u-rg-lud", - "output": "und-u-rg-lucl" - }, - { - "input": "und-NO-u-rg-no23", - "output": "und-NO-u-rg-no50" - }, - { - "input": "und-CN-u-rg-cn11", - "output": "und-CN-u-rg-cnbj" - }, - { - "input": "und-CZ-u-rg-cz10a", - "output": "und-CZ-u-rg-cz110" - }, - { - "input": "und-FR-u-rg-fra", - "output": "und-FR-u-rg-frges" - }, - { - "input": "und-FR-u-rg-frg", - "output": "und-FR-u-rg-frges" - }, - { - "input": "und-u-rg-lud", - "output": "und-u-rg-lucl" - }, - { - "input": "und-u-sd-no23", - "output": "und-u-sd-no50" - }, - { - "input": "und-u-sd-cn11", - "output": "und-u-sd-cnbj" - }, - { - "input": "und-u-sd-cz10a", - "output": "und-u-sd-cz110" - }, - { - "input": "und-u-sd-fra", - "output": "und-u-sd-frges" - }, - { - "input": "hy-arevela", - "output": "hy" - }, - { - "input": "hy-Armn-arevela", - "output": "hy-Armn" - }, - { - "input": "hy-AM-arevela", - "output": "hy-AM" - }, - { - "input": "hy-arevela-fonipa", - "output": "hy-fonipa" - }, - { - "input": "hy-fonipa-arevela", - "output": "hy-fonipa" - }, - { - "input": "hy-arevmda", - "output": "hyw" - }, - { - "input": "hy-Armn-arevmda", - "output": "hyw-Armn" - }, - { - "input": "hy-AM-arevmda", - "output": "hyw-AM" - }, - { - "input": "hy-arevmda-fonipa", - "output": "hyw-fonipa" - }, - { - "input": "hy-fonipa-arevmda", - "output": "hyw-fonipa" - }, - { - "input": "ja-Latn-hepburn-heploc", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-JP-hepburn-heploc", - "output": "ja-Latn-JP-alalc97" - }, - { - "input": "sv-aaland", - "output": "sv-AX" - }, - { - "input": "el-polytoni", - "output": "el-polyton" - }, - { - "input": "ja-Latn-alalc97-hepburn-heploc", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-hepburn-alalc97-heploc", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-hepburn-heploc-alalc97", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-heploc-hepburn", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-heploc", - "output": "ja-Latn-alalc97" - }, - { - "input": "ja-Latn-aaland-heploc", - "output": "ja-Latn-AX-alalc97" - }, - { - "input": "ja-Latn-heploc-polytoni", - "output": "ja-Latn-alalc97-polyton" - }, - { - "input": "und-Latn-t-und-hani-m0-names", - "output": "und-Latn-t-und-hani-m0-prprname", - "disabled": true - }, - { - "input": "und-u-ca-ethiopian-amete-alem", - "output": "und-u-ca-ethioaa", - "disabled": true - }, - { - "input": "und-u-ca-islamicc", - "output": "und-u-ca-islamic-civil", - "disabled": true - }, - { - "input": "und-u-ks-primary", - "output": "und-u-ks-level1", - "disabled": true - }, - { - "input": "und-u-ks-tertiary", - "output": "und-u-ks-level3", - "disabled": true - }, - { - "input": "und-u-ms-imperial", - "output": "und-u-ms-uksystem", - "disabled": true - }, - { - "input": "und-u-kb-yes", - "output": "und-u-kb", - "disabled": true - }, - { - "input": "und-u-kc-yes", - "output": "und-u-k", - "disabled": true - }, - { - "input": "und-u-kh-yes", - "output": "und-u-kh", - "disabled": true - }, - { - "input": "und-u-kk-yes", - "output": "und-u-kk", - "disabled": true - }, - { - "input": "und-u-kn-yes", - "output": "und-u-kn", - "disabled": true - }, - { - "input": "und-u-ka-yes", - "output": "und-u-ka-yes", - "disabled": true - }, - { - "input": "und-u-tz-cnckg", - "output": "und-u-tz-cnsha", - "disabled": true - }, - { - "input": "und-u-tz-eire", - "output": "und-u-tz-iedub", - "disabled": true - }, - { - "input": "und-u-tz-est", - "output": "und-u-tz-utcw05", - "disabled": true - }, - { - "input": "und-u-tz-gmt0", - "output": "und-u-tz-gmt", - "disabled": true - }, - { - "input": "und-u-tz-uct", - "output": "und-u-tz-utc", - "disabled": true - }, - { - "input": "und-u-tz-zulu", - "output": "und-u-tz-utc", - "disabled": true - } -] \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale-v2/tests/fixtures/maximize.json b/deps/crates/vendor/icu_locale-v2/tests/fixtures/maximize.json deleted file mode 100644 index 85f551735a56..000000000000 --- a/deps/crates/vendor/icu_locale-v2/tests/fixtures/maximize.json +++ /dev/null @@ -1,214 +0,0 @@ -[ - { - "input": "en-US", - "output": "en-Latn-US" - }, - { - "input": "en-GB", - "output": "en-Latn-GB" - }, - { - "input": "es-AR", - "output": "es-Latn-AR" - }, - { - "input": "it", - "output": "it-Latn-IT" - }, - { - "input": "zh-Hans-CN", - "output": "zh-Hans-CN" - }, - { - "input": "de-AT", - "output": "de-Latn-AT" - }, - { - "input": "pl", - "output": "pl-Latn-PL" - }, - { - "input": "fr-FR", - "output": "fr-Latn-FR" - }, - { - "input": "de-AT", - "output": "de-Latn-AT" - }, - { - "input": "sr-Cyrl-SR", - "output": "sr-Cyrl-SR" - }, - { - "input": "nb-NO", - "output": "nb-Latn-NO" - }, - { - "input": "fr-FR", - "output": "fr-Latn-FR" - }, - { - "input": "mk", - "output": "mk-Cyrl-MK" - }, - { - "input": "uk", - "output": "uk-Cyrl-UA" - }, - { - "input": "und-PL", - "output": "pl-Latn-PL" - }, - { - "input": "und-Latn-AM", - "output": "ku-Latn-AM" - }, - { - "input": "ug-Cyrl", - "output": "ug-Cyrl-KZ" - }, - { - "input": "sr-ME", - "output": "sr-Latn-ME" - }, - { - "input": "mn-Mong", - "output": "mn-Mong-CN" - }, - { - "input": "lif-Limb", - "output": "lif-Limb-IN" - }, - { - "input": "gan", - "output": "gan-Hans-CN" - }, - { - "input": "zh-Hant", - "output": "zh-Hant-TW" - }, - { - "input": "yue-Hans", - "output": "yue-Hans-CN" - }, - { - "input": "unr", - "output": "unr-Beng-IN" - }, - { - "input": "unr-Deva", - "output": "unr-Deva-NP" - }, - { - "input": "und-Thai-CN", - "output": "lcp-Thai-CN" - }, - { - "input": "ug-Cyrl", - "output": "ug-Cyrl-KZ" - }, - { - "input": "en-Latn-DE", - "output": "en-Latn-DE" - }, - { - "input": "pl-FR", - "output": "pl-Latn-FR" - }, - { - "input": "de-CH", - "output": "de-Latn-CH" - }, - { - "input": "tuq", - "output": "tuq-Latn-TD" - }, - { - "input": "sr-ME", - "output": "sr-Latn-ME" - }, - { - "input": "ng", - "output": "ng-Latn-NA" - }, - { - "input": "klx", - "output": "klx-Latn-PG" - }, - { - "input": "kk-Arab", - "output": "kk-Arab-CN" - }, - { - "input": "en-Cyrl", - "output": "en-Cyrl-US" - }, - { - "input": "und-Cyrl-UK", - "output": "ru-Cyrl-UK" - }, - { - "input": "und-Arab", - "output": "ar-Arab-EG" - }, - { - "input": "und-Arab-FO", - "output": "ar-Arab-FO" - }, - { - "input": "zh-TW", - "output": "zh-Hant-TW" - }, - { - "input": "und", - "output": "en-Latn-US" - }, - { - "input": "zh-SG", - "output": "zh-Hans-SG" - }, - { - "input": "und-TW", - "output": "zh-Hant-TW" - }, - { - "input": "zh-hant-u-nu-Chinese-hc-h23", - "output": "zh-Hant-TW-u-hc-h23-nu-chinese" - }, - { - "input": "und-001", - "output": "en-Latn-001" - }, - { - "input": "und-150", - "output": "en-Latn-150" - }, - { - "input": "und-419", - "output": "es-Latn-419" - }, - { - "input": "und-latn-AQ", - "output": "en-Latn-AQ" - }, - { - "input": "und-Arab-AF", - "output": "fa-Arab-AF" - }, - { - "input": "qaa", - "output": "qaa" - }, - { - "input": "qaa-CH", - "output": "qaa-CH" - }, - { - "input": "qaa-Cyrl", - "output": "qaa-Cyrl" - }, - { - "input": "qaa-Cyrl-CH", - "output": "qaa-Cyrl-CH" - } -] diff --git a/deps/crates/vendor/icu_locale-v2/tests/fixtures/minimize.json b/deps/crates/vendor/icu_locale-v2/tests/fixtures/minimize.json deleted file mode 100644 index 8da4d0779347..000000000000 --- a/deps/crates/vendor/icu_locale-v2/tests/fixtures/minimize.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "input": "zh-Hant", - "output": "zh-TW" - }, - { - "input": "en-Latn-US", - "output": "en" - }, - { - "input": "en", - "output": "en" - }, - { - "input": "und", - "output": "en" - }, - { - "input": "es-ES-preeuro", - "output": "es-preeuro" - }, - { - "input": "zh-Hant-TW-u-hc-h23-nu-chinese", - "output": "zh-TW-u-hc-h23-nu-chinese" - } -] diff --git a/deps/crates/vendor/icu_locale-v2/tests/fixtures/mod.rs b/deps/crates/vendor/icu_locale-v2/tests/fixtures/mod.rs deleted file mode 100644 index 071a039f7d3b..000000000000 --- a/deps/crates/vendor/icu_locale-v2/tests/fixtures/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use serde::Deserialize; - -#[derive(Deserialize, Debug)] -pub struct CanonicalizationTest { - pub input: String, - pub output: String, - pub disabled: Option<bool>, -} diff --git a/deps/crates/vendor/icu_locale-v2/tests/locale_canonicalizer.rs b/deps/crates/vendor/icu_locale-v2/tests/locale_canonicalizer.rs deleted file mode 100644 index b5dceed85568..000000000000 --- a/deps/crates/vendor/icu_locale-v2/tests/locale_canonicalizer.rs +++ /dev/null @@ -1,81 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -mod fixtures; - -use icu_locale::{LocaleCanonicalizer, LocaleExpander, TransformResult}; -use icu_locale_core::Locale; -use writeable::assert_writeable_eq; - -#[test] -fn test_maximize() { - let lc = LocaleExpander::new_extended(); - - let testcases: Vec<fixtures::CanonicalizationTest> = - serde_json::from_str(include_str!("fixtures/maximize.json")) - .expect("Failed to read a fixture"); - - for case in testcases { - if let Some(true) = case.disabled { - continue; - } - let mut locale: Locale = case.input.parse().unwrap(); - let unmodified = locale.clone(); - let result = lc.maximize(&mut locale.id); - assert_writeable_eq!(locale, case.output, "{:?}", case); - if result == TransformResult::Modified { - assert_ne!(locale, unmodified, "{case:?}"); - } else { - assert_eq!(locale, unmodified, "{case:?}"); - } - } -} - -#[test] -fn test_minimize() { - let lc = LocaleExpander::new_extended(); - - let testcases: Vec<fixtures::CanonicalizationTest> = - serde_json::from_str(include_str!("fixtures/minimize.json")) - .expect("Failed to read a fixture"); - - for case in testcases { - if let Some(true) = case.disabled { - continue; - } - let mut locale: Locale = case.input.parse().unwrap(); - let unmodified = locale.clone(); - let result = lc.minimize(&mut locale.id); - assert_writeable_eq!(locale, case.output, "{:?}", case); - if result == TransformResult::Modified { - assert_ne!(locale, unmodified, "{case:?}"); - } else { - assert_eq!(locale, unmodified, "{case:?}"); - } - } -} - -#[test] -fn test_canonicalize() { - let lc = LocaleCanonicalizer::new_extended(); - - let testcases: Vec<fixtures::CanonicalizationTest> = - serde_json::from_str(include_str!("fixtures/canonicalize.json")) - .expect("Failed to read a fixture"); - - for case in testcases { - if let Some(true) = case.disabled { - continue; - } - let mut locale: Locale = case.input.parse().expect("Unable to parse input"); - let unmodified = locale.clone(); - let result = lc.canonicalize(&mut locale); - assert_writeable_eq!(locale, case.output, "{:?}", case); - if result == TransformResult::Modified { - assert_ne!(locale, unmodified, "{case:?}"); - } else { - assert_eq!(locale, unmodified, "{case:?}"); - } - } -} diff --git a/deps/crates/vendor/icu_locale_core-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale_core-v2/.cargo_vcs_info.json index 1cd82148c314..8ca0e7bb3caa 100644 --- a/deps/crates/vendor/icu_locale_core-v2/.cargo_vcs_info.json +++ b/deps/crates/vendor/icu_locale_core-v2/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "a14f2dad852be26bad277ae704abf27a15cbfed1" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "components/locale_core" } \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale_core-v2/Cargo.lock b/deps/crates/vendor/icu_locale_core-v2/Cargo.lock index 5b6dc353986e..aecd4e2ebf97 100644 --- a/deps/crates/vendor/icu_locale_core-v2/Cargo.lock +++ b/deps/crates/vendor/icu_locale_core-v2/Cargo.lock @@ -43,9 +43,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "ciborium" @@ -76,18 +76,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cobs" @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -156,18 +156,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -188,13 +188,13 @@ dependencies = [ [[package]] name = "databake-derive" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b537745234cbf0e296a3bd836d70a614dff4cb522b14e2680ef006bb1ed5ff" +checksum = "495503291b258422ea2bb9863d9f4e31eadbc5bcbdbe8b721769fa2c98dc4d41" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -206,14 +206,14 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "either" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "embedded-io" @@ -239,9 +239,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "iai" @@ -251,7 +251,7 @@ checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678" [[package]] name = "icu_locale_core" -version = "2.3.0" +version = "2.4.0" dependencies = [ "criterion", "databake", @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "litemap" @@ -384,9 +384,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" [[package]] name = "proc-macro2" @@ -497,14 +497,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -526,9 +526,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -537,13 +537,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] [[package]] @@ -563,14 +563,14 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "tinystr" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", "serde_core", @@ -589,9 +589,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "walkdir" @@ -696,9 +696,9 @@ checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" [[package]] name = "zerovec" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "serde", "zerofrom", diff --git a/deps/crates/vendor/icu_locale_core-v2/Cargo.toml b/deps/crates/vendor/icu_locale_core-v2/Cargo.toml index 9a6383ffd516..68bba1b4986e 100644 --- a/deps/crates/vendor/icu_locale_core-v2/Cargo.toml +++ b/deps/crates/vendor/icu_locale_core-v2/Cargo.toml @@ -13,7 +13,7 @@ edition = "2024" rust-version = "1.88" name = "icu_locale_core" -version = "2.3.0" +version = "2.4.0" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -131,7 +131,7 @@ optional = true default-features = false [dependencies.tinystr] -version = "0.8.4" +version = "0.8.5" default-features = false [dependencies.writeable] @@ -139,7 +139,7 @@ version = "0.6.4" default-features = false [dependencies.zerovec] -version = "0.11.7" +version = "0.11.9" optional = true default-features = false diff --git a/deps/crates/vendor/icu_locale_core-v2/src/extensions/private/other.rs b/deps/crates/vendor/icu_locale_core-v2/src/extensions/private/other.rs index b3d8e074f15e..0c039c773e5d 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/extensions/private/other.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/extensions/private/other.rs @@ -13,8 +13,7 @@ impl_tinystr_subtag!( /// ``` /// use icu::locale::extensions::private::Subtag; /// - /// let subtag1: Subtag = "Foo".parse() - /// .expect("Failed to parse a Subtag."); + /// let subtag1: Subtag = "Foo".parse().expect("Failed to parse a Subtag."); /// /// assert_eq!(subtag1.as_str(), "foo"); /// ``` diff --git a/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/attribute.rs b/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/attribute.rs index 8430fbbeeae1..0ab8151f75c3 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/attribute.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/attribute.rs @@ -12,7 +12,7 @@ impl_tinystr_subtag!( /// # Examples /// /// ``` - /// use icu::locale::extensions::unicode::{attribute, Attribute}; + /// use icu::locale::extensions::unicode::{Attribute, attribute}; /// /// let attr: Attribute = /// "buddhist".parse().expect("Failed to parse an Attribute."); diff --git a/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/subdivision.rs b/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/subdivision.rs index b8f98eea480e..8d149b662a92 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/subdivision.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/extensions/unicode/subdivision.rs @@ -25,7 +25,9 @@ impl_tinystr_subtag!( /// # Examples /// /// ``` - /// use icu::locale::extensions::unicode::{subdivision_suffix, SubdivisionSuffix}; + /// use icu::locale::extensions::unicode::{ + /// SubdivisionSuffix, subdivision_suffix, + /// }; /// /// let ss: SubdivisionSuffix = /// "sct".parse().expect("Failed to parse a SubdivisionSuffix."); diff --git a/deps/crates/vendor/icu_locale_core-v2/src/langid.rs b/deps/crates/vendor/icu_locale_core-v2/src/langid.rs index e0cf28ea7921..fbbe5b21dc21 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/langid.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/langid.rs @@ -362,7 +362,7 @@ impl LanguageIdentifier { /// } /// } /// - /// let _: BTreeSet<LanguageIdentifierTotalOrd> = unimplemented!(); + /// BTreeSet::<LanguageIdentifierTotalOrd>::new(); /// ``` /// /// [`BTreeSet`]: alloc::collections::BTreeSet diff --git a/deps/crates/vendor/icu_locale_core-v2/src/locale.rs b/deps/crates/vendor/icu_locale_core-v2/src/locale.rs index edfee9e17151..1d6a27b174d4 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/locale.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/locale.rs @@ -367,7 +367,7 @@ impl Locale { /// } /// } /// - /// let _: BTreeSet<LocaleTotalOrd> = unimplemented!(); + /// BTreeSet::<LocaleTotalOrd>::new(); /// ``` /// /// [`BTreeSet`]: alloc::collections::BTreeSet diff --git a/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/calendar.rs b/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/calendar.rs index 2f1bacdc82be..aeea6daf7a04 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/calendar.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/calendar.rs @@ -22,7 +22,8 @@ enum_keyword!( Civil, /// Hijri calendar, Saudi Arabia sighting Rgsa -}); + } +); /// Handles aliases present in `v`. If found, returns a [`CalendarAlgorithm`], else returns None fn handle_aliases(v: &Value) -> Option<CalendarAlgorithm> { diff --git a/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/dictionary_break.rs b/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/dictionary_break.rs index 91556b8e106c..c327292aff4a 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/dictionary_break.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/preferences/extensions/unicode/keywords/dictionary_break.rs @@ -29,7 +29,5 @@ struct_keyword!( .collect::<Result<_, _>>() .map(Self) }, - |input: &DictionaryBreakScriptExclusions| { - input.0.iter().copied().map(Into::into).collect() - } + |input: &DictionaryBreakScriptExclusions| { input.0.iter().copied().map(Into::into).collect() } ); diff --git a/deps/crates/vendor/icu_locale_core-v2/src/preferences/mod.rs b/deps/crates/vendor/icu_locale_core-v2/src/preferences/mod.rs index 2791f37e4e93..59848f199198 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/preferences/mod.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/preferences/mod.rs @@ -91,8 +91,8 @@ //! }; //! use icu::locale::locale; //! -//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> () { () } -//! # fn load_data(locale: ()) -> MyData { MyData {} } +//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> icu::locale::DataLocale { icu::locale::DataLocale::default() } +//! # fn load_data(locale: icu::locale::DataLocale) -> MyData { MyData {} } //! # struct MyData {} //! define_preferences!( //! /// Name of the preferences struct @@ -127,8 +127,9 @@ //! # extensions::unicode::keywords::HourCycle, //! # }; //! # use icu::locale::locale; -//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> () { () } -//! # fn load_data(locale: ()) -> MyData { MyData {} } +//! # struct DataLocale; +//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> DataLocale { DataLocale } +//! # fn load_data(locale: DataLocale) -> MyData { MyData {} } //! # struct MyData {} //! # define_preferences!( //! # /// Name of the preferences struct @@ -162,8 +163,9 @@ //! # extensions::unicode::keywords::HourCycle, //! # }; //! # use icu::locale::locale; -//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> () { () } -//! # fn load_data(locale: ()) -> MyData { MyData {} } +//! # struct DataLocale; +//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> DataLocale { DataLocale } +//! # fn load_data(locale: DataLocale) -> MyData { MyData {} } //! # struct MyData {} //! # define_preferences!( //! # /// Name of the preferences struct @@ -208,8 +210,9 @@ //! # extensions::unicode::keywords::HourCycle, //! # }; //! # use icu::locale::locale; -//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> () { () } -//! # fn load_data(locale: ()) -> MyData { MyData {} } +//! # struct DataLocale; +//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> DataLocale { DataLocale } +//! # fn load_data(locale: DataLocale) -> MyData { MyData {} } //! # struct MyData {} //! # define_preferences!( //! # /// Name of the preferences struct @@ -263,8 +266,9 @@ //! # extensions::unicode::keywords::HourCycle, //! # }; //! # use icu::locale::locale; -//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> () { () } -//! # fn load_data(locale: ()) -> MyData { MyData {} } +//! # struct DataLocale; +//! # fn get_data_locale_from_prefs(input: ExampleComponentPreferences) -> DataLocale { DataLocale } +//! # fn load_data(locale: DataLocale) -> MyData { MyData {} } //! # struct MyData {} //! # define_preferences!( //! # /// Name of the preferences struct diff --git a/deps/crates/vendor/icu_locale_core-v2/src/subtags/mod.rs b/deps/crates/vendor/icu_locale_core-v2/src/subtags/mod.rs index 31c72f687ab2..c4d5a503c0e5 100644 --- a/deps/crates/vendor/icu_locale_core-v2/src/subtags/mod.rs +++ b/deps/crates/vendor/icu_locale_core-v2/src/subtags/mod.rs @@ -72,8 +72,7 @@ impl_tinystr_subtag!( /// ``` /// use icu::locale::subtags::Subtag; /// - /// let subtag1: Subtag = "Foo".parse() - /// .expect("Failed to parse a Subtag."); + /// let subtag1: Subtag = "Foo".parse().expect("Failed to parse a Subtag."); /// /// assert_eq!(subtag1.as_str(), "foo"); /// ``` diff --git a/deps/crates/vendor/icu_locale_data-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale_data-v2/.cargo_vcs_info.json deleted file mode 100644 index 80a70c273063..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "c9fac4e625ccb2c6a7aa35079fff9709db4385ac" - }, - "path_in_vcs": "provider/data/locale" -} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale_data-v2/LICENSE b/deps/crates/vendor/icu_locale_data-v2/LICENSE deleted file mode 100644 index c9be6012c537..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/LICENSE +++ /dev/null @@ -1,46 +0,0 @@ -UNICODE LICENSE V3 - -COPYRIGHT AND PERMISSION NOTICE - -Copyright © 2020-2024 Unicode, Inc. - -NOTICE TO USER: Carefully read the following legal agreement. BY -DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR -SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE -TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT -DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of data files and any associated documentation (the "Data Files") or -software and any associated documentation (the "Software") to deal in the -Data Files or Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, and/or sell -copies of the Data Files or Software, and to permit persons to whom the -Data Files or Software are furnished to do so, provided that either (a) -this copyright and permission notice appear with all copies of the Data -Files or Software, or (b) this copyright and permission notice appear in -associated Documentation. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF -THIRD PARTY RIGHTS. - -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE -BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, -OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA -FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder shall -not be used in advertising or otherwise to promote the sale, use or other -dealings in these Data Files or Software without prior written -authorization of the copyright holder. - -SPDX-License-Identifier: Unicode-3.0 - -— - -Portions of ICU4X may have been adapted from ICU4C and/or ICU4J. -ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation and others. diff --git a/deps/crates/vendor/icu_locale_data-v2/OWNERS b/deps/crates/vendor/icu_locale_data-v2/OWNERS deleted file mode 100644 index b09cd849229c..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# This file has been auto-generated by the `gnrt` tool. -file://third_party/rust/icu_locale_data/OWNERS diff --git a/deps/crates/vendor/icu_locale_data-v2/README.md b/deps/crates/vendor/icu_locale_data-v2/README.md deleted file mode 100644 index eb237e9ab1cd..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# icu_locale_data [![crates.io](https://img.shields.io/crates/v/icu_locale_data)](https://crates.io/crates/icu_locale_data) - -<!-- cargo-rdme start --> - -Data for the `icu_locale` crate - -This data was generated with CLDR version 48.2.0, ICU version release-78.1rc, and -LSTM segmenter version v0.1.0. - -<!-- cargo-rdme end --> - -## More Information - -For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_aliases_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_aliases_v1.rs.data deleted file mode 100644 index f8633043022d..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_aliases_v1.rs.data +++ /dev/null @@ -1,119 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleAliasesV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 8474B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_aliases_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_ALIASES_V1: &'static <icu::locale::provider::LocaleAliasesV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::locale::provider::Aliases { - language_variants: unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x13\0\r\0\x1B\0*\09\0F\0T\0r\0~\0\x8B\0\x98\0\xA9\0\xB8\0\xC7\0\xD5\0\xE2\0\xF0\0\xFF\0\x0C\x01aa\0\x05\0saahossyart\x06\0lojbanjbocel\x07\0gaulishxtghy\0\x07\0arevmdahywno\0\x06\0bokmalnbno\0\x07\0nynorsknnund\x0E\0hepburn-heplocund-alalc97zh\0\x05\0guoyuzhzh\0\x05\0hakkahakzh\0\x05\0xianghsnund\x06\0aalandund-AXund\x07\0arevelaundund\x07\0arevmdaundund\x06\0bokmalundund\x05\0hakkaundund\x06\0lojbanundund\x07\0nynorskundund\x05\0saahoundund\x05\0xiangund") }, - sgn_region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"BR\0CO\0DE\0DK\0ES\0FR\0GB\0GR\0IE\0IT\0JP\0MX\0NI\0NL\0NO\0PT\0SE\0US\0ZA\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"bzscsngsgdslsspfslbfigssisgisejslmfsncsdsensipsrswlasesfs") }) - }, - language_len2: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"bhiniwjijwmoshtltw") }, unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x03\0\x05\0\x07\0\t\0\x0B\0\r\0\x14\0\x17\0bhoidheyijvrosr-Latnfilak") }) - }, - language_len3: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"aamaarabkadpafragpaisajpajtajuakaalbalsamharaarbargarmasdasmaueavaaveaymayrayxazeazjbakbambaqbazbccbclbelbenbgmbhkbicbihbisbjdbjqbkbblgbodbosbrebtbbulburbxkbxrcatccqceschachechichuchvcjrckacldclscmkcmncnrcorcoscoycqucrecwdcymczedafdandapdekdeudgodhddikdiqditdivdjldkldrhdrrdrwduddujdutdwldzoekkellelpemkengepoeskesteusewefaofasfatfijfinfrafrefryfucfulgavgazgbcgbogeogergfxggnggoggrgioglagleglggliglvgnogomgregrngtiguggujguvgyahathauhbshdnheahebherhimhinhmohrrhrvhunhyeibiiboiceidoiiiikeikuileillilwinaindipkislitaizijarjavjegjpnkalkankaskatkaukazkdvkgckgdkghkgmkhkkhmkikkinkirkmrknckngkojkomkonkorkppkpvkrmktrkuakurkvskwqkxekxlkzhkzjkztlaklaolatlavlbklegliilimlinlitllolmmltzlubluglvsmacmahmalmaomarmaymegmgxmhrmkdmlgmltmntmofmolmonmrimsamstmupmwdmwjmyamydmytnadnaunavnbfnblnbxncpndendonepnldnlnnlrnnonnsnnxnobnomnoonornpintentsnxunyaociojgojioriormoryossounpanpatpbupcrperpesplipltpmcpmkpmupnbpolporppapprprpprsprypuspuzquequzrmrrmyrohronrumrunrussagsansapscasccscrsglsinskkslksloslvsmdsmesmosnasnbsndsomsotspaspysqisrcsrdsrpsswsulsumsunswaswcsweswhszdtahtamtattduteltggtgktglthathcthwthxtibtidtietirtkktlwtmktmptnetnftontpwtsftsntsottqtukturtwiuigukrumuunpuokurduzbuznvenvievolwelwgwwitwiwwlnwolxbaxhoxiaxkhxpexrqxsjxslxssybdyddyenyidyiyymaymtyoryosyuuzaizhazhozirzkbzsmzulzyb") }, unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\xAA\x01\x03\0\x05\0\x07\0\t\0\x0B\0\x0E\0\x11\0\x14\0\x17\0\x1A\0\x1C\0\x1E\0 \0\"\0$\0&\0(\0*\0-\0/\x002\x004\x006\08\0:\0=\0?\0A\0C\0E\0G\0J\0M\0P\0R\0T\0W\0Z\0]\0`\0b\0e\0h\0k\0n\0p\0r\0t\0w\0y\0{\0~\0\x81\0\x83\0\x86\0\x88\0\x8A\0\x8C\0\x8E\0\x90\0\x92\0\x95\0\x98\0\x9B\0\x9D\0\xA0\0\xA2\0\xA7\0\xA9\0\xAB\0\xAE\0\xB1\0\xB3\0\xB5\0\xB7\0\xB9\0\xBC\0\xBE\0\xC1\0\xC4\0\xC6\0\xC9\0\xCC\0\xCF\0\xD2\0\xD5\0\xD7\0\xDA\0\xDD\0\xDF\0\xE2\0\xE7\0\xEA\0\xED\0\xEF\0\xF2\0\xF4\0\xF6\0\xF8\0\xFB\0\xFE\0\0\x01\x02\x01\x04\x01\x06\x01\x08\x01\n\x01\x0C\x01\x0E\x01\x10\x01\x12\x01\x14\x01\x16\x01\x18\x01\x1A\x01\x1C\x01\x1E\x01!\x01#\x01&\x01)\x01+\x01-\x010\x013\x016\x019\x01<\x01>\x01@\x01B\x01E\x01G\x01J\x01M\x01O\x01Q\x01T\x01V\x01X\x01[\x01^\x01`\x01b\x01i\x01l\x01o\x01q\x01s\x01v\x01x\x01z\x01}\x01\x7F\x01\x81\x01\x83\x01\x86\x01\x88\x01\x8A\x01\x8C\x01\x8E\x01\x90\x01\x92\x01\x94\x01\x97\x01\x9A\x01\x9C\x01\x9E\x01\xA0\x01\xA2\x01\xA4\x01\xA7\x01\xAA\x01\xAC\x01\xAF\x01\xB1\x01\xB3\x01\xB5\x01\xB7\x01\xB9\x01\xBB\x01\xBD\x01\xC0\x01\xC3\x01\xC6\x01\xC9\x01\xCC\x01\xCE\x01\xD0\x01\xD2\x01\xD4\x01\xD6\x01\xD8\x01\xDA\x01\xDC\x01\xDF\x01\xE1\x01\xE3\x01\xE5\x01\xE8\x01\xEA\x01\xED\x01\xF0\x01\xF2\x01\xF4\x01\xF7\x01\xFA\x01\xFD\x01\0\x02\x03\x02\x06\x02\t\x02\x0C\x02\x0E\x02\x10\x02\x12\x02\x15\x02\x18\x02\x1B\x02\x1D\x02\x1F\x02!\x02$\x02'\x02)\x02+\x02-\x02/\x021\x023\x025\x027\x029\x02;\x02>\x02A\x02D\x02F\x02H\x02J\x02M\x02P\x02R\x02T\x02V\x02X\x02[\x02^\x02a\x02d\x02f\x02i\x02l\x02o\x02q\x02s\x02v\x02x\x02{\x02~\x02\x80\x02\x82\x02\x84\x02\x86\x02\x89\x02\x8C\x02\x8E\x02\x91\x02\x94\x02\x96\x02\x99\x02\x9C\x02\x9E\x02\xA0\x02\xA3\x02\xA6\x02\xA9\x02\xAB\x02\xAD\x02\xAF\x02\xB1\x02\xB3\x02\xB5\x02\xB7\x02\xB9\x02\xBC\x02\xBE\x02\xC1\x02\xC3\x02\xC6\x02\xC8\x02\xCA\x02\xCC\x02\xCE\x02\xD1\x02\xD4\x02\xD7\x02\xDA\x02\xDC\x02\xDE\x02\xE1\x02\xE4\x02\xE6\x02\xEB\x02\xEE\x02\xF0\x02\xF3\x02\xF5\x02\xF7\x02\xFA\x02\xFD\x02\xFF\x02\x01\x03\x03\x03\x05\x03\x07\x03\t\x03\x0B\x03\x0E\x03\x11\x03\x13\x03\x15\x03\x18\x03\x1A\x03\x1D\x03\x1F\x03!\x03#\x03&\x03(\x03*\x03,\x03/\x031\x033\x035\x037\x03:\x03<\x03>\x03@\x03B\x03D\x03G\x03J\x03L\x03N\x03S\x03U\x03W\x03Z\x03\\\x03^\x03`\x03c\x03e\x03h\x03j\x03m\x03o\x03r\x03u\x03x\x03z\x03}\x03\x80\x03\x82\x03\x85\x03\x88\x03\x8B\x03\x8E\x03\x91\x03\x96\x03\x98\x03\x9B\x03\x9E\x03\xA0\x03\xA2\x03\xA5\x03\xA7\x03\xA9\x03\xAB\x03\xAD\x03\xAF\x03\xB2\x03\xB5\x03\xB8\x03\xBA\x03\xBC\x03\xBE\x03\xC0\x03\xC2\x03\xC4\x03\xC6\x03\xC9\x03\xCC\x03\xCF\x03\xD1\x03\xD3\x03\xD6\x03\xD8\x03\xDB\x03\xDE\x03\xE1\x03\xE4\x03\xE7\x03\xEA\x03\xED\x03\xF0\x03\xF2\x03\xF5\x03\xF7\x03\xFA\x03\xFD\x03\0\x04\x02\x04\x05\x04\x08\x04\x0B\x04\r\x04\x0F\x04\x12\x04\x15\x04\x17\x04\x19\x04aasaaabdzafapfamiapcaebjrbaksqsqamararanhysnzasktzavaeayaynunazazbabmeunvobalbikbebnbcgfblbirbhobidrlbzcebkibabobsbrbebbgmyluybuacarkicschcezhcucvmomcmrsyrsaxchzhsr-MEkwcopijquhcrcrcycsdnjdanjzsqmdedoimwrdinzzadifdvdzeaqdmnkzkfa-AFuthdwunldbtdzetelamqmaneneoiketeueefofaakfjfifrfrfyffffdevomwnygrbkadevajgvresggtuaougdgaglkzkgvgonkokelgnnycgnguduzgbahthasr-Latnhaihmnhehzsrxhihojalhrhuhyopaigisioiiiuiuieilmgaliaidikisitezajgkjvoybjaklknkskakrkkzkdtdfncqkmlplumnkmkirwkykukrkgkwvkvkgkojkmkvbmfdtpkjkugdjyamtvdkrudgldtpdtpksplolalvbncenlraqlilnltngtrmxlblulglvmkmhmlmimrmscirjbkchmmkmgmtwnnxntromnmimsmryrajdmwvajmyaogmryxnynanvnrunrgllkdzndngnenlazdnrknnnbrngvnbcbrdtdnoneekopijbppnyocojojoromorosvajpakxrpsadxfafapimghuwcrrphrlahplptbfylcqgufa-AFprtpspubququemxromrmrorornrusgsaaqthlesrhrisksioybskskslkmbsesmsnibasdsostesklnsqscscsrsssgdulwsuswsw-CDsvswumitytattdtptebjptgfilthtpoolaoybboitdrastitwmweotdgtyjkakfa-AFtotpntajtntstmhtktrakugukdelwroemauruzuzvevivocywgbnolnwowawocaxxhacnwawkpedmwsujdenzkorkiyiynqyiyrmlrrmtmyozomyugzapzazhscvkjhmszuza") }) - }, - language: zerovec::vecs::VarZeroVec16::new(), - script: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"Qaai") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"Zinh") }) - }, - region_alpha: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"BUCTDDDYFXHVJTMINHNQPUPZQURHTPUKVDWKYDZR") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"MM\0KI\0DE\0BJ\0FR\0BF\0UM\0UM\0VU\0AQ\0UM\0PA\0EU\0ZW\0TL\0GB\0VN\0UM\0YE\0CD\0") }) - }, - region_num: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"004008010012016020024028031032036040044048050051052056060064068070072074076084086090092096100104108112116120124132136140144148152156158162166170174175178180184188191192196203204208212214218222226230231232233234238239242246248249250254258260262266268270275276278280288292296300304308312316320324328332334336340344348352356360364368372376380384388392398400404408410414417418422426428430434438440442446450454458462466470474478480484492496498499500504508512516520524528531533534535540548554558562566570574578580581583584585586591598600604608612616620624626630634638642643646652654659660662663666670674678682686688690694702703704705706710716720724728729732736740744748752756760762764768772776780784788792795796798800804807818826831832833834840850854858860862876882886887894958959960962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"AF\0AL\0AQ\0DZ\0AS\0AD\0AO\0AG\0AZ\0AR\0AU\0AT\0BS\0BH\0BD\0AM\0BB\0BE\0BM\0BT\0BO\0BA\0BW\0BV\0BR\0BZ\0IO\0SB\0VG\0BN\0BG\0MM\0BI\0BY\0KH\0CM\0CA\0CV\0KY\0CF\0LK\0TD\0CL\0CN\0TW\0CX\0CC\0CO\0KM\0YT\0CG\0CD\0CK\0CR\0HR\0CU\0CY\0CZ\0BJ\0DK\0DM\0DO\0EC\0SV\0GQ\0ET\0ET\0ER\0EE\0FO\0FK\0GS\0FJ\0FI\0AX\0FR\0FR\0GF\0PF\0TF\0DJ\0GA\0GE\0GM\0PS\0DE\0DE\0DE\0GH\0GI\0KI\0GR\0GL\0GD\0GP\0GU\0GT\0GN\0GY\0HT\0HM\0VA\0HN\0HK\0HU\0IS\0IN\0ID\0IR\0IQ\0IE\0IL\0IT\0CI\0JM\0JP\0KZ\0JO\0KE\0KP\0KR\0KW\0KG\0LA\0LB\0LS\0LV\0LR\0LY\0LI\0LT\0LU\0MO\0MG\0MW\0MY\0MV\0ML\0MT\0MQ\0MR\0MU\0MX\0MC\0MN\0MD\0ME\0MS\0MA\0MZ\0OM\0NA\0NR\0NP\0NL\0CW\0AW\0SX\0BQ\0NC\0VU\0NZ\0NI\0NE\0NG\0NU\0NF\0NO\0MP\0UM\0FM\0MH\0PW\0PK\0PA\0PG\0PY\0PE\0PH\0PN\0PL\0PT\0GW\0TL\0PR\0QA\0RE\0RO\0RU\0RW\0BL\0SH\0KN\0AI\0LC\0MF\0PM\0VC\0SM\0ST\0SA\0SN\0RS\0SC\0SL\0SG\0SK\0VN\0SI\0SO\0ZA\0ZW\0YE\0ES\0SS\0SD\0EH\0SD\0SR\0SJ\0SZ\0SE\0CH\0SY\0TJ\0TH\0TG\0TK\0TO\0TT\0AE\0TN\0TR\0TM\0TC\0TV\0UG\0UA\0MK\0EG\0GB\0GG\0JE\0IM\0TZ\0US\0VI\0BF\0UY\0UZ\0VE\0WF\0WS\0YE\0YE\0ZM\0AA\0QM\0QN\0QP\0QQ\0QR\0QS\0QT\0EU\0QV\0QW\0QX\0QY\0QZ\0XA\0XB\0XC\0XD\0XE\0XF\0XG\0XH\0XI\0XJ\0XK\0XL\0XM\0XN\0XO\0XP\0XQ\0XR\0XS\0XT\0XU\0XV\0XW\0XX\0XY\0XZ\0ZZ\0") }) - }, - complex_region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"062172200530532536582810830890891AN\0CS\0FQ\0NT\0PC\0SU\0YU\0") }, unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x12\0\x06\0*\x000\09\0B\0H\0T\0\x81\0\x87\0\x99\0\x9F\0\xA8\0\xAE\0\xB4\0\xBA\0\xC6\0\xF3\x00034143RU\0AM\0AZ\0BY\0GE\0KG\0KZ\0MD\0TJ\0TM\0UA\0UZ\0CZ\0SK\0CW\0SX\0BQ\0CW\0SX\0BQ\0SA\0IQ\0FM\0MH\0MP\0PW\0RU\0AM\0AZ\0BY\0EE\0GE\0KZ\0KG\0LV\0LT\0MD\0TJ\0TM\0UA\0UZ\0JE\0GG\0RS\0ME\0SI\0HR\0MK\0BA\0RS\0ME\0CW\0SX\0BQ\0RS\0ME\0AQ\0TF\0SA\0IQ\0FM\0MH\0MP\0PW\0RU\0AM\0AZ\0BY\0EE\0GE\0KZ\0KG\0LV\0LT\0MD\0TJ\0TM\0UA\0UZ\0RS\0ME\0") }) - }, - variant: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"heploc\0\0polytoni") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"alalc97\0polyton\0") }) - }, - subdivision: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"cn11\0\0\0cn12\0\0\0cn13\0\0\0cn14\0\0\0cn15\0\0\0cn21\0\0\0cn22\0\0\0cn23\0\0\0cn31\0\0\0cn32\0\0\0cn33\0\0\0cn34\0\0\0cn35\0\0\0cn36\0\0\0cn37\0\0\0cn41\0\0\0cn42\0\0\0cn43\0\0\0cn44\0\0\0cn45\0\0\0cn46\0\0\0cn50\0\0\0cn51\0\0\0cn52\0\0\0cn53\0\0\0cn54\0\0\0cn61\0\0\0cn62\0\0\0cn63\0\0\0cn64\0\0\0cn65\0\0\0cn71\0\0\0cn91\0\0\0cn92\0\0\0cz10a\0\0cz10b\0\0cz10c\0\0cz10d\0\0cz10e\0\0cz10f\0\0cz611\0\0cz612\0\0cz613\0\0cz614\0\0cz615\0\0cz621\0\0cz622\0\0cz623\0\0cz624\0\0cz626\0\0cz627\0\0czjc\0\0\0czjm\0\0\0czka\0\0\0czkr\0\0\0czli\0\0\0czmo\0\0\0czol\0\0\0czpa\0\0\0czpl\0\0\0czpr\0\0\0czst\0\0\0czus\0\0\0czvy\0\0\0czzl\0\0\0fi01\0\0\0fra\0\0\0\0frb\0\0\0\0frbl\0\0\0frc\0\0\0\0frcp\0\0\0frd\0\0\0\0fre\0\0\0\0frf\0\0\0\0frg\0\0\0\0frgf\0\0\0frgp\0\0\0frgua\0\0frh\0\0\0\0fri\0\0\0\0frj\0\0\0\0frk\0\0\0\0frl\0\0\0\0frlre\0\0frm\0\0\0\0frmay\0\0frmf\0\0\0frmq\0\0\0frn\0\0\0\0frnc\0\0\0fro\0\0\0\0frp\0\0\0\0frpf\0\0\0frpm\0\0\0frq\0\0\0\0frr\0\0\0\0frre\0\0\0frs\0\0\0\0frt\0\0\0\0frtf\0\0\0fru\0\0\0\0frv\0\0\0\0frwf\0\0\0fryt\0\0\0laxn\0\0\0lud\0\0\0\0lug\0\0\0\0lul\0\0\0\0mrnkc\0\0nlaw\0\0\0nlcw\0\0\0nlsx\0\0\0no23\0\0\0nzn\0\0\0\0nzs\0\0\0\0omba\0\0\0omsh\0\0\0plds\0\0\0plkp\0\0\0pllb\0\0\0plld\0\0\0pllu\0\0\0plma\0\0\0plmz\0\0\0plop\0\0\0plpd\0\0\0plpk\0\0\0plpm\0\0\0plsk\0\0\0plsl\0\0\0plwn\0\0\0plwp\0\0\0plzp\0\0\0shta\0\0\0tteto\0\0ttrcm\0\0ttwto\0\0twkhq\0\0twtnq\0\0twtpq\0\0twtxq\0\0usas\0\0\0usgu\0\0\0usmp\0\0\0uspr\0\0\0usum\0\0\0usvi\0\0\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"cnbj\0\0\0cntj\0\0\0cnhe\0\0\0cnsx\0\0\0cnmn\0\0\0cnln\0\0\0cnjl\0\0\0cnhl\0\0\0cnsh\0\0\0cnjs\0\0\0cnzj\0\0\0cnah\0\0\0cnfj\0\0\0cnjx\0\0\0cnsd\0\0\0cnha\0\0\0cnhb\0\0\0cnhn\0\0\0cngd\0\0\0cngx\0\0\0cnhi\0\0\0cncq\0\0\0cnsc\0\0\0cngz\0\0\0cnyn\0\0\0cnxz\0\0\0cnsn\0\0\0cngs\0\0\0cnqh\0\0\0cnnx\0\0\0cnxj\0\0\0twzzzz\0hkzzzz\0mozzzz\0cz110\0\0cz111\0\0cz112\0\0cz113\0\0cz114\0\0cz115\0\0cz663\0\0cz632\0\0cz633\0\0cz634\0\0cz635\0\0cz641\0\0cz642\0\0cz643\0\0cz644\0\0cz646\0\0cz647\0\0cz31\0\0\0cz64\0\0\0cz41\0\0\0cz52\0\0\0cz51\0\0\0cz80\0\0\0cz71\0\0\0cz53\0\0\0cz32\0\0\0cz10\0\0\0cz20\0\0\0cz42\0\0\0cz63\0\0\0cz72\0\0\0axzzzz\0frges\0\0frnaq\0\0blzzzz\0frara\0\0cpzzzz\0frbfc\0\0frbre\0\0frcvl\0\0frges\0\0gfzzzz\0gpzzzz\0gpzzzz\0frcor\0\0frbfc\0\0fridf\0\0frocc\0\0frnaq\0\0rezzzz\0frges\0\0ytzzzz\0mfzzzz\0mqzzzz\0frocc\0\0nczzzz\0frhdf\0\0frnor\0\0pfzzzz\0pmzzzz\0frnor\0\0frpdl\0\0rezzzz\0frhdf\0\0frnaq\0\0tfzzzz\0frpac\0\0frara\0\0wfzzzz\0ytzzzz\0laxs\0\0\0lucl\0\0\0luec\0\0\0luca\0\0\0mr13\0\0\0awzzzz\0cwzzzz\0sxzzzz\0no50\0\0\0nzauk\0\0nzcan\0\0ombj\0\0\0omsj\0\0\0pl02\0\0\0pl04\0\0\0pl08\0\0\0pl10\0\0\0pl06\0\0\0pl12\0\0\0pl14\0\0\0pl16\0\0\0pl20\0\0\0pl18\0\0\0pl22\0\0\0pl26\0\0\0pl24\0\0\0pl28\0\0\0pl30\0\0\0pl32\0\0\0tazzzz\0tttob\0\0ttmrc\0\0tttob\0\0twkhh\0\0twtnn\0\0twnwt\0\0twtxg\0\0aszzzz\0guzzzz\0mpzzzz\0przzzz\0umzzzz\0vizzzz\0") }) - }, - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleAliasesV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleAliasesV1>, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_ALIASES_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleAliasesV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_aliases_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleAliasesV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_aliases_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleAliasesV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleAliasesV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_aliases_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleAliasesV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleAliasesV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleAliasesV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_aliases_v1 as impl_locale_aliases_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_auxiliary_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_auxiliary_v1.rs.data deleted file mode 100644 index 812ff6123ea4..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_auxiliary_v1.rs.data +++ /dev/null @@ -1,1107 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleExemplarCharactersAuxiliaryV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 824B for the lookup data structure (168 data identifiers) -/// * 34390B[^1] for the actual data (148 unique structs) -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `icu_provider/baked` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_exemplar_characters_auxiliary_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - const DATA_LOCALE_EXEMPLAR_CHARACTERS_AUXILIARY_V1: icu_provider::baked::zerotrie::Data<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1> = { - const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xE1zabcdefghijklmnopqrstuvwxyz\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x02\x02\x02\x02\x02\x02\x15?Wi\x94\xBE\xD1\xFE\x1A\"Xr\x95\xB5\xBC\xDB\xDE\xEFIp\x8C\x9A\x9D\xA6\xBB\xC5fkrsz\x01\x02\x07\n\x80\x81\x82-MA\x83\x84t\x85\x86\xC9aeghlnrsu\x07\x08\x0B\r\x0F\x10\x13\x15l-Latn\x87\x88\x89c\x8Ao\x8Bo\x8C\x8D\x8Ex\x8F\x90\0a\x90\x01\xC5aesvy\x02\x05\n\x0C\x90\x02b\x90\x03\x90\x04w\x90\x05\x90\x01\x90\x06\xC4aeos\x02\x04\x07\x90\x07\x90\x08i\x90\tb\x90\n\xC7elnostu\x02\x0E\x15\x17\x19\x1B\x90\x0B\x90\x0C-polyton\x90\r\x90\x0E-ZA\x90\x0F\x90\0\x90\x10\x90\x11\x90\x12\xC6afiory\x07\x0E\x13\x15\x1C\x90\x13-AF\x90\x14-Adlm\x90\x15\x90\x16l\x90\x17\x90\x18\x90\x19-CA\x90\x1A\x90\x1B\xC4adlu\x05\x07\t\x90\x1Ca\x90\x1D\x90\x1E\x90\x1F\x90 \xC8aeirstuy\x07\t\x12\x14\x17\x19\x1B\x90!-NE\x90\"\x90#\x90$-Latn\x90%\x90\0b\x90&\x90'\x90(\x90)\xC7adegist\x02\x04\x06\x08\n\x0C\x90\x0E\x90\x0E\x90*\x90+\x90,\x90-\x90.\xC2av\x02\x90/\x900\xC9aegmnosuy\x02\x05\x08\n\x0C\x18 \"\x901a\x902p\x903\x904\x905\x906k\x90$-Latn\x907\x908-Deva\x8F\x909\x90:\xC6bimotv\x02\x05\x08\n\x0C\x90;j\x90<o\x90\x0E\x90=\x90>\x90?\xC8aiklnrty\x03\x05\x07\t\r\x0F\x11i\x90@\x90A\x90B\x90C\x90Di\x8F\x90E\x90F\x90G\xC6deloqs\x08\n\x0C\x0E\x11s\x90H-NL\x90I\x90$\x90J\x90Ko\x90Lo\x90M\xC2cr\x02\x90N\x8F\xC6aclmst\x02\x05\x07\n\x11\x90Om\x90P\x90Qs\x90R\x90S-PK\x90T\x90Uu\x90V\xC4amou\x03\x05\x07j\x90W\x90X\x90Y\x90\x01\xD0acdhikloqrtuvwyz\x05\n\x12\x15\x17\x19\x1B\x1D\x1E')+-47\x90Zh\x90[\x90\\n\x90]\x90^-Deva\x8Fn\x90_\x90`\x90a\x90b\x90c\x86\x90d-Latn\x90e\x90f\x90g\x90h\x90i-CD\x90jr\x90kl\x90l\xCAaeghiknort\x01\x03\x05\x07\t\x0B\r\x0F\x11\x8F\x90m\x90n\x90o\x90p\x90q\x90r\x90s\x90t\x90u\xC5gknrz\x02\x04\x07\t\x90v\x90wd\x90\r\x90x\x90y-Cyrl\x90n\xC3eim\x03\x05c\x90z\x90{w\x90|o\x90}\xC2hn\x02\x90\x0Er\x90~\xC3oru\x02\x05\x90rl\x90\x7Fe\x91\0-Hans\x91\x01\xC2hu\t\x91\x02-Hant\x91\x03\x90\x0E" }; - const VALUES: &'static [<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1 as icu_provider::baked::zerotrie::DynamicDataMarker>::DataStruct] = &[ - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE1\0\0\xE3\0\0\xE8\0\0\xEC\0\0\xEE\0\0\xF2\0\0\xF4\0\0\xF9\0\0\xFB\0\0\xFC\0\0\xFE\0\0") }, 14u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0j\0\0k\0\0q\0\0r\0\0v\0\0w\0\0z\0\0{\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0") }, 14u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"@\x06\0A\x06\0o\x06\0p\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x98\x06\0\x99\x06\0\x9C\x06\0\x9D\x06\0\xA2\x06\0\xA3\x06\0\xA4\x06\0\xA6\x06\0\xA7\x06\0\xAA\x06\0\xAF\x06\0\xB0\x06\0\xCC\x06\0\xCD\x06\0\x0C \0\x10 \0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"o\x06\0p\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x98\x06\0\x99\x06\0\x9C\x06\0\x9D\x06\0\xA2\x06\0\xA3\x06\0\xA4\x06\0\xA6\x06\0\xA7\x06\0\xAA\x06\0\xAD\x06\0\xAE\x06\0\xAF\x06\0\xB0\x06\0\xCC\x06\0\xCD\x06\0c\x07\0d\x07\0\x0C \0\x10 \0") }, 19u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xB0\t\0\xB1\t\0\xCE\t\0\xCF\t\0\xF2\t\0\xF3\t\0\x0C \0\x0E \0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"j\0\0l\0\0w\0\0x\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"w\0\0x\0\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"D\x01\0E\x01\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(zerovec::ZeroVec::new(), 0u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\n\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0 \0$\0\xD0\xB0\xCC\x81\xD0\xB5\xCC\x81\xD0\xBE\xCC\x81\xD1\x83\xCC\x81\xD1\x8B\xCC\x81\xD1\x8D\xCC\x81\xD1\x8E\xCC\x81\xD1\x8F\xCC\x81\xD1\x91\xCC\x81\xD1\x96\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"K\x04\0L\x04\0M\x04\0N\x04\0P\x04\0R\x04\0]\x04\0^\x04\0c\x04\0d\x04\0k\x04\0l\x04\0") }, 7u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x06\0\x04\0\x08\0\x0C\0\x10\0\x14\0\xD0\xB0\xCC\x80\xD0\xBE\xCC\x80\xD1\x83\xCC\x80\xD1\x8A\xCC\x80\xD1\x8E\xCC\x80\xD1\x8F\xCC\x80") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\t\0\x03\t\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\x0C\t\0\x0F\t\0\x11\t\0\x13\t\0\x15\t\0") }, 11u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"d\0\0e\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0\xDF\0\0\xE0\0\0\xE3\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xEF\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF5\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFC\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x07\x01\0\x08\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x1B\x01\0\x1C\x01\0)\x01\0*\x01\0+\x01\0,\x01\0-\x01\0.\x01\x003\x01\x004\x01\0H\x01\0I\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0Y\x01\0Z\x01\0a\x01\0b\x01\0k\x01\0l\x01\0m\x01\0n\x01\0\x7F\x01\0\x80\x01\0\x92\x01\0\x93\x01\0\xB4\x01\0\xB5\x01\0\xCE\x01\0\xCF\x01\0\xD0\x01\0\xD1\x01\0\xD2\x01\0\xD3\x01\0\xD4\x01\0\xD5\x01\0S\x02\0T\x02\0W\x02\0X\x02\0c\x02\0d\x02\0\x8B\x02\0\x8C\x02\0\x92\x02\0\x93\x02\0\x1B\x1E\0\x1C\x1E\0-\x1E\0.\x1E\0u\x1E\0v\x1E\0\xBD\x1E\0\xBE\x1E\0") }, 53u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x1D\0\x03\0\x05\0\x08\0\x0B\0\x0E\0\x11\0\x13\0\x16\0\x1A\0\x1E\0\"\0&\0*\0.\x002\x006\0:\0>\0B\0F\0J\0N\0R\0V\0Z\0^\0b\0f\0a\xCC\xB0hwm\xCC\x84m\xCC\x8Cn\xCC\x84o\xCC\xB0xw\xC5\x8Bw\xC7\x9D\xCC\x83\xC7\x9D\xCC\x84\xC7\x9D\xCC\xB0\xC9\x94\xCC\x83\xC9\x94\xCC\x84\xC9\x94\xCC\x8C\xC9\x94\xCC\xB0\xC9\x99\xCC\x8C\xC9\x9B\xCC\x83\xC9\x9B\xCC\x84\xC9\x9B\xCC\x8C\xC9\x9B\xCC\xB0\xC9\xA9\xCC\x83\xC9\xA9\xCC\x84\xC9\xA9\xCC\xB0\xCA\x8A\xCC\x83\xCA\x8A\xCC\x84\xCA\x8A\xCC\x8C\xCA\x8A\xCC\xB0\xCC\x83\xC5\xA9\xCC\x83\xCA\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF0\t\0\xFA\t\0\x0C \0\x0E \0") }, 12u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0\xE0\0\0\xEA\0\0\xEB\0\0\xF0\0\0\xF2\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x0C \0\x0E \0") }, 2u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0z\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(zerovec::ZeroVec::new(), 0u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0 \0\xD0\xB0\xCC\x81\xD0\xB5\xCC\x81\xD0\xB8\xCC\x81\xD0\xBE\xCC\x81\xD1\x83\xCC\x81\xD1\x8B\xCC\x81\xD1\x8D\xCC\x81\xD1\x8E\xCC\x81\xD1\x8F\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xBA\0\0\xBB\0\0\xE1\0\0\xE7\0\0\xEA\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF1\0\0\xF2\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0@\x01\0A\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0f\0\0g\0\0j\0\0k\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0\xF1\0\0\xF2\0\0") }, 8u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0>\x01\0?\x01\0B\x01\0C\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0U\x01\0V\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x10\x15\0\x17\x15\0") }, 7u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"k\0\0l\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0\xE3\0\0\xE4\0\0\xE5\0\0\xE8\0\0\xF1\0\0\xF2\0\0\xF8\0\0\xF9\0\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE3\0\0\xE4\0\0\xE5\0\0\xE7\0\0\xEC\0\0\xED\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF9\0\0\xFD\0\0\xFF\0\0\0\x01\0S\x01\0T\x01\0\xFF\x01\0\0\x02\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE4\0\0\xE5\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF8\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x1F\x01\0 \x01\0+\x01\0,\x01\0-\x01\0.\x01\x000\x01\x002\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0_\x01\0`\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 39u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\r\t\0\x0E\t\0\x11\t\0\x12\t\0E\t\0F\t\0\x0C \0\x0E \0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDF\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFE\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x05\x01\0\x06\x01\0\x0F\x01\0\x10\x01\0\x11\x01\0\x12\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x17\x01\0\x18\x01\0\x19\x01\0\x1A\x01\0\x1F\x01\0 \x01\0+\x01\0,\x01\0-\x01\0.\x01\x000\x01\x002\x01\0:\x01\0;\x01\0>\x01\0?\x01\0H\x01\0I\x01\0M\x01\0N\x01\0O\x01\0P\x01\0Q\x01\0R\x01\0S\x01\0T\x01\0Y\x01\0Z\x01\0_\x01\0`\x01\0e\x01\0f\x01\0k\x01\0l\x01\0m\x01\0n\x01\0o\x01\0p\x01\0q\x01\0r\x01\0|\x01\0}\x01\0") }, 57u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0j\0\0k\0\0q\0\0r\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x15\x01\0\x16\x01\0-\x01\0.\x01\0O\x01\0P\x01\0S\x01\0T\x01\0m\x01\0n\x01\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x1F\0\x08\x1F\0\x10\x1F\0\x16\x1F\0 \x1F\0(\x1F\x000\x1F\08\x1F\0B\x1F\0E\x1F\0P\x1F\0X\x1F\0b\x1F\0h\x1F\0p\x1F\0q\x1F\0r\x1F\0s\x1F\0t\x1F\0u\x1F\0v\x1F\0w\x1F\0x\x1F\0y\x1F\0z\x1F\0{\x1F\0|\x1F\0}\x1F\0\xB6\x1F\0\xB7\x1F\0\xC6\x1F\0\xC7\x1F\0\xD2\x1F\0\xD3\x1F\0\xD6\x1F\0\xD8\x1F\0\xE2\x1F\0\xE3\x1F\0\xE6\x1F\0\xE8\x1F\0\xF6\x1F\0\xF7\x1F\0") }, 63u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(zerovec::ZeroVec::new(), 0u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE3\0\0\xE4\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0a\x01\0b\x01\0k\x01\0l\x01\0m\x01\0n\x01\0\x13\x1E\0\x14\x1E\0=\x1E\0>\x1E\0E\x1E\0F\x1E\0K\x1E\0L\x1E\0q\x1E\0r\x1E\0") }, 43u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0\xFE\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE4\0\0\xE5\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF8\0\0\xFC\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE7\0\0\xE8\0\0\xF0\0\0\xF2\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\x06\0&\x06\0@\x06\0A\x06\0C\x06\0D\x06\0I\x06\0K\x06\0N\x06\0Q\x06\0R\x06\0S\x06\0V\x06\0W\x06\0p\x06\0q\x06\0\x0C \0\x10 \0") }, 15u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\x06\0&\x06\0C\x06\0D\x06\0I\x06\0K\x06\0N\x06\0Q\x06\0R\x06\0S\x06\0V\x06\0W\x06\0p\x06\0q\x06\0|\x06\0}\x06\0\x81\x06\0\x82\x06\0\x85\x06\0\x86\x06\0\x89\x06\0\x8A\x06\0\x93\x06\0\x94\x06\0\x96\x06\0\x97\x06\0\x9A\x06\0\x9B\x06\0\xAB\x06\0\xAC\x06\0\xBC\x06\0\xBD\x06\0\x0C \0\x10 \0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b">\xE9\x01D\xE9\x01") }, 6u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDF\0\0\xE4\0\0\xE6\0\0\xEC\0\0\xED\0\0\xF6\0\0\xF8\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x05\x01\0\x06\x01\0\x07\x01\0\x08\x01\0\x0B\x01\0\x0C\x01\0\r\x01\0\x0E\x01\0\x0F\x01\0\x10\x01\0\x11\x01\0\x12\x01\0\x13\x01\0\x14\x01\0\x17\x01\0\x18\x01\0\x19\x01\0\x1A\x01\0\x1B\x01\0\x1C\x01\0\x1F\x01\0 \x01\0#\x01\0$\x01\0'\x01\0(\x01\0+\x01\0,\x01\0/\x01\x002\x01\x007\x01\08\x01\0:\x01\0;\x01\0<\x01\0=\x01\0>\x01\0?\x01\0B\x01\0C\x01\0D\x01\0E\x01\0F\x01\0G\x01\0H\x01\0I\x01\0K\x01\0L\x01\0Q\x01\0R\x01\0S\x01\0T\x01\0U\x01\0V\x01\0Y\x01\0Z\x01\0[\x01\0\\\x01\0]\x01\0^\x01\0_\x01\0`\x01\0c\x01\0d\x01\0e\x01\0f\x01\0g\x01\0h\x01\0k\x01\0l\x01\0o\x01\0p\x01\0q\x01\0r\x01\0s\x01\0t\x01\0z\x01\0{\x01\0|\x01\0}\x01\0\xE5\x01\0\xE6\x01\0\xE7\x01\0\xE8\x01\0\xE9\x01\0\xEA\x01\0\xEF\x01\0\xF0\x01\0\x19\x02\0\x1A\x02\0\x1B\x02\0\x1C\x02\0\x1F\x02\0 \x02\0\x92\x02\0\x93\x02\0") }, 80u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE3\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xEF\0\0\xF2\0\0\xF5\0\0\xF9\0\0\xFC\0\0") }, 15u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0w\0\0y\0\0z\0\0{\0\0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDF\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE6\0\0\xEC\0\0\xEE\0\0\xF1\0\0\xF4\0\0\xF5\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFB\0\0\x01\x01\0\x02\x01\0\x07\x01\0\x08\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\x003\x01\x004\x01\0Y\x01\0Z\x01\0a\x01\0b\x01\0\x7F\x01\0\x80\x01\0\xD4\x01\0\xD5\x01\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE1\0\0\xE2\0\0\xE3\0\0\xE6\0\0\xEC\0\0\xEE\0\0\xF1\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFB\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\0\xD4\x01\0\xD5\x01\0") }, 16u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE6\0\0\xE7\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"j\0\0l\0\0q\0\0r\0\0v\0\0{\0\0\xE5\0\0\xE6\0\0\x0B\x01\0\x0C\x01\0!\x01\0\"\x01\0\x03\x1E\0\x04\x1E\0\x0B\x1E\0\x0C\x1E\0\x1F\x1E\0 \x1E\0A\x1E\0B\x1E\0W\x1E\0X\x1E\0a\x1E\0b\x1E\0k\x1E\0l\x1E\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0)\x01\0*\x01\0i\x01\0j\x01\0") }, 7u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"j\0\0l\0\0q\0\0r\0\0v\0\0{\0\0\xE1\0\0\xE8\0\0\xE9\0\0\xEC\0\0\xED\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x0B\x01\0\x0C\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0!\x01\0\"\x01\0+\x01\0,\x01\0-\x01\0.\x01\x001\x01\x002\x01\0B\x01\0C\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0_\x01\0`\x01\0k\x01\0l\x01\0m\x01\0n\x01\0\x19\x02\0\x1A\x02\0\x0B\x1E\0\x0C\x1E\0\x1F\x1E\0 \x1E\0A\x1E\0B\x1E\0W\x1E\0X\x1E\0a\x1E\0b\x1E\0k\x1E\0l\x1E\0") }, 53u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0Q\x02\0R\x02\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF0\n\0\xF1\n\0\x0C \0\x0E \0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"p\0\0r\0\0v\0\0w\0\0x\0\0y\0\0\xE0\0\0\xE3\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xEF\0\0\xF2\0\0\xF5\0\0\xF9\0\0\xFC\0\0") }, 19u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0r\xCC\x83") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"p\0\0r\0\0v\0\0w\0\0x\0\0y\0\0\xE0\0\0\xE3\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xEF\0\0\xF2\0\0\xF5\0\0\xF9\0\0\xFC\0\0") }, 19u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x03\0r\xCC\x83\xCA\xBCy") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xB0\x05\0\xBA\x05\0\xBB\x05\0\xBE\x05\0\xBF\x05\0\xC0\x05\0\xC1\x05\0\xC3\x05\0\xC4\x05\0\xC5\x05\0\xF4\x05\0\xF5\x05\0\x0E \0\x10 \0") }, 20u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"D\t\0E\t\0\x0C \0\x0E \0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF1\0\0\xF2\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0M\x01\0N\x01\0O\x01\0P\x01\0[\x01\0\\\x01\0k\x01\0l\x01\0\r\x1E\0\x0E\x1E\0%\x1E\0&\x1E\x007\x1E\08\x1E\0A\x1E\0B\x1E\0E\x1E\0F\x1E\0G\x1E\0H\x1E\0[\x1E\0\\\x1E\0c\x1E\0d\x1E\0m\x1E\0n\x1E\0") }, 18u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x04\0\x03\0\x06\0\t\0l\xCC\xA5m\xCC\x90r\xCC\xA5r\xCC\xA5\xCC\x84") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDF\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFE\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x05\x01\0\x06\x01\0\x0F\x01\0\x10\x01\0\x11\x01\0\x12\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x17\x01\0\x18\x01\0\x19\x01\0\x1A\x01\0\x1F\x01\0 \x01\0+\x01\0,\x01\0-\x01\0.\x01\x000\x01\x002\x01\0:\x01\0;\x01\0>\x01\0?\x01\0H\x01\0I\x01\0M\x01\0N\x01\0O\x01\0P\x01\0Q\x01\0R\x01\0S\x01\0T\x01\0U\x01\0V\x01\0[\x01\0\\\x01\0_\x01\0`\x01\0e\x01\0f\x01\0k\x01\0l\x01\0m\x01\0n\x01\0o\x01\0p\x01\0q\x01\0r\x01\0z\x01\0{\x01\0|\x01\0}\x01\0") }, 59u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"x\0\0y\0\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0z\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x87\x05\0\x88\x05\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFE\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 34u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x03\0l\xCA\xBCn\xCA\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0\xE0\0\0\xE2\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xEE\0\0\xF2\0\0\xF4\0\0\xF9\0\0\xFB\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\0D\x01\0E\x01\0M\x01\0N\x01\0k\x01\0l\x01\0\xF9\x01\0\xFA\x01\0?\x1E\0@\x1E\0") }, 21u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x07\0\x03\0\x08\0\r\0\x12\0\x17\0\x1C\0m\xCC\x80\xE1\xBB\x8B\xCC\x80\xE1\xBB\x8B\xCC\x81\xE1\xBB\x8D\xCC\x80\xE1\xBB\x8D\xCC\x81\xE1\xBB\xA5\xCC\x80\xE1\xBB\xA5\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x90\xA4\0\xC7\xA4\0") }, 55u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0w\0\0x\0\0z\0\0{\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xDF\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xED\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFD\0\0\xFF\0\0\0\x01\0S\x01\0T\x01\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x11N\0\x12N\0\xA5N\0\xA6N\0\xA8N\0\xA9N\0LQ\0MQ\0NQ\0OQ\0\xE7Q\0\xE8Q\0CR\0DR\0oS\0pS\0\tV\0\nV\0\x14V\0\x15V\0\x18V\0\x19V\0\xECX\0\xEDX\0\xFAX\0\xFBX\0\t[\0\n[\0\xC5[\0\xC6[\0\xF3]\0\xF4]\0\x9A^\0\x9B^\0\xB5^\0\xB6^\0\x18_\0\x19_\0W_\0X_\0\xB6`\0\xB7`\0\x15a\0\x16a\0\nb\0\x0Bb\0\x0Cb\0\rb\0\xFCb\0\xFDb\0\xC3c\0\xC4c\0\xA7e\0\xA8e\0\x0Cf\0\rf\0Vg\0Wg\0vh\0wh\0\xB5h\0\xB6h\0Ti\0Ui\0Xn\0Yn\0\x1Aq\0\x1Bq\0\xEDq\0\xEEq\0,r\0-r\0Lr\0Mr\0]r\0^r\0ar\0br\0\xD0r\0\xD1r\0\xD7r\0\xD8r\0\xFCr\0\xFDr\0*s\0+s\0Es\0Fs\0xv\0yv\0\x91w\0\x92w\0\x87x\0\x88x\0Zy\0[y\0\x84y\0\x85y\0\x8Ey\0\x8Fy\0\xE4y\0\xE5y\0\xFFz\0\0{\0F}\0G}\0M~\0N~\0k\x7F\0l\x7F\0\x8F\x81\0\x90\x81\0\x92\x82\0\x93\x82\0\xC4\x87\0\xC5\x87\0\xF9\x87\0\xFA\x87\0\r\x88\0\x0E\x88\0#\x88\0$\x88\0\x1B\x8D\0\x1C\x8D\0D\x8E\0E\x8E\0\xB0\x8F\0\xB1\x8F\0I\x91\0J\x91\0\xF2\x92\0\xF3\x92\0\x04\x93\0\x05\x93\0(\x93\0)\x93\0\x8F\x95\0\x90\x95\0\xA9\x95\0\xAA\x95\0\xC0\x96\0\xC1\x96\0\xC9\x96\0\xCA\x96\0\xF3\x9C\0\xF4\x9C\0 \x9F\0!\x9F\0\x8D\x9F\0\x8E\x9F\0") }, 75u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"f\0\0g\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF1\x10\0\xFB\x10\0\0-\0&-\0") }, 48u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0w\0\0x\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE0\0\0\xF0\0\0\xF2\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0)\x01\0*\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0i\x01\0j\x01\0k\x01\0l\x01\0m\x01\0n\x01\0X\x1D\0Y\x1D\0\xBD\x1E\0\xBE\x1E\0") }, 47u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x03\0n\xCC\x88rr") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"b\0\0e\0\0l\0\0m\0\0q\0\0r\0\0w\0\0y\0\0z\0\0{\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE9\0\0\xEA\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0\xB0\x02\0\xB1\x02\0I\x1D\0J\x1D\0M\x1D\0N\x1D\0\x7F \0\x80 \0") }, 49u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x9D\x17\0\x9F\x17\0\xB4\x17\0\xB6\x17\0\xCC\x17\0\xCD\x17\0\xCE\x17\0\xD0\x17\0\xD1\x17\0\xD2\x17\0\x0B \0\x0C \0") }, 9u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDE\x0C\0\xDF\x0C\0\x0C \0\x0E \0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x11\0\x13\x11\0a\x11\0v\x11\0\xA8\x11\0\xC3\x11\0\x18N\0\x19N\x002N\x003N\0CN\0DN\0EN\0FN\0VN\0WN\0]N\0_N\0kN\0lN\0~N\0\x7FN\0\x82N\0\x83N\0\x98N\0\x99N\0\xA4N\0\xA5N\0\xACN\0\xADN\0\xC7N\0\xC8N\0\xCAN\0\xCCN\0\xF6N\0\xF8N\0\x01O\0\x02O\0\x0BO\0\x0CO\0\x0EO\0\x0FO\0=O\0>O\0sO\0tO\0vO\0wO\0\x83O\0\x84O\0\x86O\0\x87O\0\x8AO\0\x8BO\0\x9BO\0\x9CO\0\xC2O\0\xC3O\0\xD3O\0\xD4O\0\xF1O\0\xF2O\0\x0BP\0\x0CP\0\x1EP\0\x1FP\0&P\0'P\0(P\0)P\0GP\0IP\0eP\0fP\0\x80P\0\x81P\0\x91P\0\x92P\0\xBEP\0\xBFP\0\xC5P\0\xC6P\0\xD1P\0\xD2P\0\xF9P\0\xFAP\0\x06Q\0\x07Q\0\tQ\0\nQ\0:Q\0;Q\0IQ\0JQ\0KQ\0LQ\0bQ\0cQ\0gQ\0hQ\0lQ\0mQ\0qQ\0rQ\0vQ\0xQ\0|Q\0}Q\0\x80Q\0\x81Q\0\xA0Q\0\xA1Q\0\xF1Q\0\xF2Q\0\nR\0\x0BR\0.R\0/R\08R\09R\0;R\0<R\0KR\0LR\0[R\0\\R\0\x87R\0\x88R\0\x8DR\0\x8ER\0\x92R\0\x93R\0\x9FR\0\xA1R\0\xA4R\0\xA5R\0\xABR\0\xACR\0\xC1R\0\xC2R\0\xCDR\0\xCER\0\xD8R\0\xD9R\0\xE4R\0\xE5R\0\xF8R\0\xF9R\0\xFBR\0\xFCR\0\xFER\0\xFFR\0!S\0\"S\0#S\0$S\0@S\0AS\0WS\0XS\0fS\0gS\0tS\0vS\0wS\0xS\0\x7FS\0\x80S\0\xA5S\0\xA6S\0\xBBS\0\xBCS\0\xCAS\0\xCBS\0\xE3S\0\xE4S\0\xE5S\0\xE6S\0\xE9S\0\xEAS\0\xEBS\0\xECS\0\xEFS\0\xF0S\0\x04T\0\x05T\0\tT\0\nT\0\x1BT\0\x1CT\0JT\0KT\0qT\0rT\0uT\0vT\0\x8ET\0\x8FT\0\xACT\0\xADT\0\xE5T\0\xE6T\0\xEDT\0\xEET\0SU\0TU\0\x80U\0\x81U\0\x87U\0\x88U\0\x9DU\0\x9EU\0\xABU\0\xADU\0\xDCU\0\xDDU\0\tV\0\nV\0\x14V\0\x15V\0hV\0iV\0\xCAV\0\xCBV\0\xF0V\0\xF1V\0\xFAV\0\xFBV\0\x08W\0\tW\0\x0BW\0\x0CW\0-W\0.W\0;W\0<W\0GW\0HW\0NW\0OW\0QW\0RW\0dW\0eW\0pW\0qW\0uW\0vW\0\xA2W\0\xA3W\0\xFAW\0\xFBW\0\xFCW\0\xFDW\0\0X\0\x01X\0\x05X\0\x06X\0\x08X\0\tX\0*X\0+X\0:X\0;X\0JX\0KX\0OX\0PX\0\x83X\0\x84X\0\xBEX\0\xBFX\0\xD9X\0\xDAX\0\xDEX\0\xDFX\0\x14Y\0\x15Y\0GY\0IY\0NY\0OY\0QY\0RY\0xY\0yY\0\x93Y\0\x94Y\0\x97Y\0\x98Y\0\xD1Y\0\xD2Y\0\xDCY\0\xDDY\0\xE6Y\0\xE7Y\0\x18Z\0\x19Z\0\x1CZ\0\x1DZ\0\xC1Z\0\xC2Z\0\x0C[\0\r[\0T[\0U[\0c[\0e[\0\x8F[\0\x90[\0\x98[\0\x99[\0\xA2[\0\xA3[\0\xAE[\0\xAF[\0\xB6[\0\xB7[\0\xC4[\0\xC5[\0\xC7[\0\xC8[\0\xE1[\0\xE2[\0\xEC[\0\xED[\0;\\\0<\\\0@\\\0A\\\0E\\\0G\\\0H\\\0I\\\0\x90\\\0\x91\\\0\xA1\\\0\xA2\\\0\xAC\\\0\xAD\\\0\x0E]\0\x0F]\0\x11]\0\x12]\0\x17]\0\x18]\0L]\0M]\0P]\0Q]\0\x87]\0\x88]\0\xA0]\0\xA1]\0\xE5]\0\xE6]\0\xE7]\0\xE9]\0\xF1]\0\xF2]\0\xFE]\0\xFF]\0r^\0s^\0y^\0z^\0~^\0\x7F^\0\x9A^\0\x9B^\0\xAB^\0\xAC^\0\xB7^\0\xB8^\0\xCA^\0\xCB^\0\xD0^\0\xD1^\0\xD3^\0\xD4^\0\xE3^\0\xE4^\0\xFA^\0\xFB^\0\x13_\0\x14_\0:_\0;_\0J_\0K_\0\x91_\0\x92_\0\xCC_\0\xCD_\0%`\0&`\0*`\0+`\0/`\x000`\0P`\0Q`\0]`\0^`\0j`\0k`\0m`\0n`\0\xB8`\0\xB9`\0\x06a\0\x07a\0\x1Fa\0 a\0'a\0(a\x007a\08a\0>a\0?a\0Ja\0Ka\0ca\0ea\0ha\0ia\0va\0xa\0\xA9a\0\xAAa\0\xACa\0\xADa\0\xBEa\0\xBFa\0\xC3a\0\xC4a\0\xC7a\0\xC8a\0\xE6a\0\xE7a\0\xF6a\0\xF7a\0\xFCa\0\xFDa\0\x08b\0\tb\0\x12b\0\x13b\0\x1Fb\0 b\0!b\0\"b\0qb\0rb\0\x80b\0\x81b\0\x89b\0\x8Ab\0\xC9b\0\xCAb\0\xCFb\0\xD1b\0\xD2b\0\xD3b\0\xD8b\0\xD9b\0\xECb\0\xEDb\0\xEEb\0\xEFb\0\xF1b\0\xF2b\0\xF3b\0\xF4b\0\xF7b\0\xF8b\0\xFFb\0\0c\0Oc\0Pc\0nc\0oc\0rc\0sc\0zc\0{c\0\x98c\0\x99c\0\x9Bc\0\x9Cc\0\xA7c\0\xA8c\0\xC0c\0\xC1c\0\xC6c\0\xC7c\0\xEDc\0\xEEc\0\xCAd\0\xCBd\0\xCEd\0\xCFd\0\xD2d\0\xD3d\0\xDAd\0\xDBd\0\xE7d\0\xE8d\0*e\0+e\x007e\08e\09e\0:e\0;e\0<e\0Ee\0Fe\0Ne\0Oe\0Qe\0Re\0be\0ce\0le\0me\0re\0se\0\x9Be\0\x9Ce\0\xA4e\0\xA5e\0\xD7e\0\xD8e\0\xE3e\0\xE4e\0\x06f\0\x07f\0\x11f\0\x12f\0of\0pf\0wf\0xf\0\x87f\0\x88f\0\x96f\0\x97f\0\xA0f\0\xA1f\0\xBBf\0\xBCf\0\xE0f\0\xE1f\0\xF2f\0\xF3f\0\xF4f\0\xF5f\0\xF7f\0\xF8f\0\x17g\0\x18g\0\x1Eg\0 g\0:g\0;g\0Fg\0Gg\0^g\0_g\0pg\0qg\0\x8Fg\0\x90g\0\x9Cg\0\x9Dg\0\xAFg\0\xB0g\0\xB6g\0\xB7g\0\xB8g\0\xB9g\0\xD1g\0\xD2g\0\xE9g\0\xEAg\0\xECg\0\xEDg\0\xEFg\0\xF0g\0!h\0\"h\09h\0:h\0<h\0=h\0@h\0Ah\0Bh\0Ch\0Th\0Uh\0\x7Fh\0\x80h\0\x8Fh\0\x90h\0\x97h\0\x98h\0\xB0h\0\xB2h\0\xC4h\0\xC5h\0\xCBh\0\xCCh\0\xCDh\0\xCEh\0\xD8h\0\xD9h\0\xE8h\0\xE9h\0\xFAh\0\xFBh\0Wi\0Xi\0`i\0ai\0ui\0vi\0\xC1i\0\xC2i\0\xCBi\0\xCCi\0\xD0i\0\xD1i\0\xE8i\0\xE9i\0\xEAi\0\xEBi\0\xFBi\0\xFCi\0\xFFi\0\0j\0\x02j\0\x03j\0Dj\0Ej\0Kj\0Lj\0Xj\0Yj\0_j\0`j\0\x84j\0\x85j\0\x8Ej\0\x8Fj\0\xA2j\0\xA3j\0\xC3j\0\xC4j\0\x04k\0\x05k\0\nk\0\x0Bk\0:k\0;k\0>k\0?k\0Lk\0Mk\0Pk\0Qk\0xk\0yk\0\xBCk\0\xBDk\0\xC6k\0\xC7k\0\xECk\0\xEDk\0#l\0$l\0Bl\0Cl\0_l\0`l\0hl\0il\0rl\0sl\0zl\0{l\0}l\0~l\0\x82l\0\x83l\0\xBDl\0\xBEl\0\x1Bm\0\x1Cm\08m\09m\0jm\0km\0\x87m\0\x88m\0\xC3m\0\xC4m\0\xC7m\0\xC8m\0\x1Bn\0\x1Cn\0 n\0!n\x004n\x005n\0sn\0tn\0\x9Dn\0\x9En\0\xAAn\0\xABn\0\xD1n\0\xD2n\0\xFEn\0\xFFn\0\x11o\0\x12o\0To\0Uo\0po\0qo\0\x97o\0\x98o\0\xC0o\0\xC1o\0\xEBo\0\xECo\0Lp\0Mp\0xp\0yp\0\x85p\0\x86p\0\x9Ap\0\x9Bp\0\xACp\0\xADp\0\xD9p\0\xDAp\0\xF1p\0\xF2p\0Vq\0Wq\0\x1Br\0\x1Cr\0}r\0~r\0\xACr\0\xADr\0\xC2r\0\xC3r\0\xD7r\0\xD8r\0\xE1r\0\xE2r\0\xFCr\0\xFDr\0Ws\0Xs\0\x96s\0\x97s\0\x98s\0\x99s\0\xC2s\0\xC3s\0\xCFs\0\xD0s\0\xD6s\0\xD7s\0\xD9s\0\xDAs\0\xDEs\0\xDFs\0\xEAs\0\xEBs\0\x03t\0\x04t\0&t\0't\0(t\0)t\0*t\0+t\0/t\x000t\x004t\x005t\0~t\0\x7Ft\0\x82t\0\x83t\0\x9Ft\0\xA0t\0\xA3t\0\xA4t\0\xA5t\0\xA6t\0\xCAt\0\xCBt\0\xD8t\0\xD9t\0\xDCt\0\xDDt\0\x04u\0\x05u\0\x18u\0\x19u\x002u\x003u\x007u\08u\0Gu\0Hu\0Lu\0Mu\0xu\0yu\0zu\0{u\0\x7Fu\0\x80u\0\x86u\0\x87u\0\xA5u\0\xA6u\0\xB3u\0\xB4u\0\xC2u\0\xC3u\0\xD9u\0\xDAu\0\xFCu\0\xFDu\0Nv\0Ov\0iv\0jv\0xv\0yv\0\x86v\0\x87v\0\x8Ev\0\x8Fv\0\x90v\0\x91v\0\xD6v\0\xD7v\0\xE3v\0\xE4v\0\x0Bw\0\x0Cw\x007w\08w\0~w\0\x7Fw\0\xB0w\0\xB1w\0\xBCw\0\xBDw\0\xBFw\0\xC0w\0\xDCw\0\xDDw\0\xE9w\0\xEAw\0\xEFw\0\xF0w\0Ex\0Fx\0lx\0mx\0\x81x\0\x82x\0\xA3x\0\xA4x\0\xCEx\0\xCFx\0\xECx\0\xEDx\0\xEFx\0\xF0x\0\xF5x\0\xF6x\0Ay\0By\0Gy\0Iy\0[y\0\\y\0zy\0{y\0\x81y\0\x82y\0\xBDy\0\xBEy\0\xD1y\0\xD2y\0\x08z\0\tz\0<z\0>z\0?z\0Az\0vz\0wz\0yz\0{z\0\x98z\0\x99z\0\x9Fz\0\xA0z\0\xAEz\0\xAFz\0\xBAz\0\xBBz\0\xC5z\0\xC6z\0\xDFz\0\xE0z\0\xEDz\0\xEEz\0\xF6z\0\xF7z\0\xFFz\0\0{\0K{\0L{\0P{\0Q{\0`{\0a{\0\x87{\0\x88{\0\x95{\0\x96{\0\x9D{\0\x9E{\0\xA1{\0\xA2{\0!|\0\"|\0\xB3|\0\xB4|\0\xE0|\0\xE1|\0\xFB|\0\xFC|\0\xFE|\0\xFF|\0\0}\0\x01}\0\r}\0\x0E}\0\x18}\0\x19}\0\x1A}\0\x1B}\0:}\0;}\0E}\0F}\0P}\0Q}\0^}\0_}\0f}\0g}\0s}\0t}\0y}\0z}\0\x7F}\0\x80}\0\x93}\0\x94}\0\xB1}\0\xB2}\0\xBA}\0\xBB}\0\xCA}\0\xCB}\0k~\0l~\0m~\0n~\0|~\0}~\0:\x7F\0;\x7F\0P\x7F\0Q\x7F\0k\x7F\0l\x7F\0\x85\x7F\0\x86\x7F\0\x88\x7F\0\x89\x7F\0\x8C\x7F\0\x8D\x7F\0\x94\x7F\0\x95\x7F\0\xA4\x7F\0\xA5\x7F\0\xB9\x7F\0\xBA\x7F\0\xF9\x7F\0\xFA\x7F\0\x03\x80\0\x04\x80\0\x06\x80\0\x07\x80\0\t\x80\0\n\x80\0\x15\x80\0\x16\x80\0-\x80\0.\x80\0?\x80\0@\x80\0\x8C\x80\0\x8D\x80\0\x9D\x80\0\x9E\x80\0\xA1\x80\0\xA2\x80\0\xA9\x80\0\xAA\x80\0\xAF\x80\0\xB0\x80\0\xB1\x80\0\xB2\x80\0\xDB\x80\0\xDC\x80\0\xF1\x80\0\xF2\x80\0\x1A\x81\0\x1C\x81\0T\x81\0U\x81\0q\x81\0r\x81\0\x88\x81\0\x89\x81\0\x8F\x81\0\x90\x81\0\xA0\x81\0\xA1\x81\0\xD8\x81\0\xD9\x81\0\xFC\x81\0\xFD\x81\0\x05\x82\0\x06\x82\0\n\x82\0\x0B\x82\0!\x82\0\"\x82\0n\x82\0o\x82\0q\x82\0r\x82\0\x8E\x82\0\x8F\x82\0\xA5\x82\0\xA6\x82\0\xA9\x82\0\xAA\x82\0\xB9\x82\0\xBA\x82\0\xDB\x82\0\xDC\x82\0\xDF\x82\0\xE0\x82\0\xE6\x82\0\xE7\x82\0\xFD\x82\0\xFE\x82\0\x04\x83\0\x05\x83\0\x96\x83\0\x97\x83\0\xC5\x83\0\xC6\x83\0\xCA\x83\0\xCB\x83\0\xCC\x83\0\xCD\x83\0\xD3\x83\0\xD4\x83\0\xEB\x83\0\xEC\x83\0\xF0\x83\0\xF1\x83\0=\x84\0>\x84\0[\x84\0\\\x84\0u\x84\0v\x84\0\xCB\x84\0\xCC\x84\0N\x85\0O\x85\0h\x85\0i\x85\0\x91\x85\0\x92\x85\0\xC1\x85\0\xC2\x85\0\xCD\x85\0\xCE\x85\0\xFF\x85\0\0\x86\0-\x86\0.\x86\0?\x86\0@\x86\0T\x86\0U\x86\0\xA3\x86\0\xA4\x86\0\xDF\x86\0\xE0\x86\0N\x87\0O\x87\0\xBA\x87\0\xBB\x87\0\x1F\x88\0 \x88\x001\x88\x002\x88\0W\x88\0X\x88\0b\x88\0c\x88\0r\x88\0s\x88\0~\x88\0\x80\x88\0\x88\x88\0\x89\x88\0\x9E\x88\0\x9F\x88\0\xB4\x88\0\xB5\x88\0\xD9\x88\0\xDA\x88\0\xF8\x88\0\xF9\x88\0\x10\x89\0\x11\x89\0A\x89\0B\x89\0_\x89\0`\x89\0d\x89\0e\x89\0\x8B\x89\0\x8C\x89\0\x8F\x89\0\x90\x89\0\xA1\x89\0\xA2\x89\0\xB2\x89\0\xB3\x89\0\xBA\x89\0\xBB\x89\0\xC0\x89\0\xC1\x89\0\xD2\x89\0\xD3\x89\0\x08\x8A\0\t\x8A\0\x18\x8A\0\x19\x8A\0#\x8A\0$\x8A\x006\x8A\x007\x8A\0m\x8A\0n\x8A\0\x87\x8A\0\x88\x8A\0\xA1\x8A\0\xA2\x8A\0\xA5\x8A\0\xA6\x8A\0\xB2\x8A\0\xB3\x8A\0\xEB\x8A\0\xEC\x8A\0\xFE\x8A\0\xFF\x8A\0\x19\x8B\0\x1A\x8B\0\x1B\x8B\0\x1C\x8B\x003\x8B\x004\x8B\09\x8B\0:\x8B\0O\x8B\0P\x8B\0f\x8B\0g\x8B\0t\x8B\0u\x8B\x007\x8C\08\x8C\0?\x8C\0@\x8C\0H\x8C\0I\x8C\0\xA2\x8C\0\xA3\x8C\0\xAB\x8C\0\xAC\x8C\0\xB4\x8C\0\xB5\x8C\0\xC8\x8C\0\xC9\x8C\0\xFC\x8C\0\xFD\x8C\0s\x8D\0t\x8D\0w\x8D\0x\x8D\0\xCF\x8D\0\xD0\x8D\0\xDD\x8D\0\xDE\x8D\0\xE8\x8D\0\xE9\x8D\0\x1E\x8E\0\x1F\x8E\0G\x8E\0H\x8E\0v\x8E\0w\x8E\0\xAC\x8E\0\xAD\x8E\0\xC0\x8E\0\xC1\x8E\0\xCA\x8E\0\xCB\x8E\0\xCC\x8E\0\xCE\x8E\0\xFB\x8E\0\xFC\x8E\0\x03\x8F\0\x04\x8F\0\x15\x8F\0\x16\x8F\0N\x8F\0O\x8F\0_\x8F\0`\x8F\0\x9C\x8F\0\x9D\x8F\0\xD1\x8F\0\xD2\x8F\0\xE6\x8F\0\xE7\x8F\0\xF2\x8F\0\xF3\x8F\0\x02\x90\0\x03\x90\0\x11\x90\0\x12\x90\0\x15\x90\0\x16\x90\x005\x90\x006\x90\0N\x90\0O\x90\0c\x90\0d\x90\0}\x90\0~\x90\0\x8F\x90\0\x90\x90\0\xA3\x90\0\xA4\x90\0\xAF\x90\0\xB0\x90\0\xB1\x90\0\xB2\x90\0\xCA\x90\0\xCB\x90\0\xCE\x90\0\xCF\x90\0\xE1\x90\0\xE2\x90\0\xED\x90\0\xEE\x90\0j\x91\0k\x91\0\xB5\x91\0\xB6\x91\0\xD1\x91\0\xD2\x91\0\x10\x92\0\x11\x92\0\x1E\x92\0\x1F\x92\0@\x92\0A\x92\0E\x92\0F\x92\0W\x92\0X\x92\0d\x92\0e\x92\0\xB6\x92\0\xB7\x92\0\xF8\x92\0\xF9\x92\0\xFC\x92\0\xFD\x92\0!\x93\0\"\x93\0$\x93\0%\x93\0&\x93\0'\x93\0.\x93\0/\x93\0K\x93\0L\x93\0u\x93\0v\x93\0\x8C\x93\0\x8D\x93\0\xA7\x93\0\xA8\x93\0\xE1\x93\0\xE2\x93\0Q\x94\0S\x94\0[\x94\0\\\x94\0\x8B\x95\0\x8C\x95\0\x93\x95\0\x94\x95\0\x98\x95\0\x99\x95\0\xA3\x95\0\xA4\x95\0\xA8\x95\0\xA9\x95\0\xD5\x95\0\xD6\x95\0\xDC\x95\0\xDD\x95\0M\x96\0N\x96\0\x8E\x96\0\x8F\x96\0\x94\x96\0\x95\x96\0\x99\x96\0\x9A\x96\0\xC7\x96\0\xC8\x96\0\xE3\x96\0\xE4\x96\0\x8F\x97\0\x90\x97\0\xA0\x97\0\xA1\x97\0\xA8\x97\0\xA9\x97\0\xAB\x97\0\xAC\x97\0\x03\x98\0\x04\x98\08\x98\09\x98\0F\x98\0G\x98\0g\x98\0h\x98\0\xE2\x98\0\xE3\x98\0\x03\x99\0\x04\x99\0(\x99\0)\x99\0I\x99\0J\x99\0K\x99\0L\x99\0Q\x99\0R\x99\0\xD2\x99\0\xD3\x99\0\xD5\x99\0\xD6\x99\0\xF1\x99\0\xF2\x99\0\x0E\x9A\0\x10\x9A\0+\x9A\0,\x9A\0E\x9A\0F\x9A\0U\x9A\0V\x9A\0Z\x9A\0[\x9A\0e\x9A\0f\x9A\0\xA8\x9A\0\xA9\x9A\0\xD8\x9A\0\xD9\x9A\0<\x9B\0=\x9B\0A\x9B\0B\x9B\0\xAB\x9B\0\xAC\x9B\0\xE4\x9B\0\xE5\x9B\0\xE8\x9B\0\xE9\x9B\0G\x9C\0H\x9C\0\xE9\x9C\0\xEA\x9C\0Q\x9D\0R\x9D\0`\x9D\0a\x9D\0\xC4\x9D\0\xC5\x9D\0\xD7\x9D\0\xD8\x9D\0\x1E\x9E\0\x1F\x9E\0\x92\x9E\0\x93\x9E\0\xB4\x9E\0\xB5\x9E\0\xD4\x9E\0\xD5\x9E\0\x13\x9F\0\x14\x9F\0\x95\x9F\0\x96\x9F\0\x9C\x9F\0\x9D\x9F\0") }, 822u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE3\0\0\xE4\0\0\xE7\0\0\xE8\0\0\xEA\0\0\xEB\0\0\xF0\0\0\xF2\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xF9\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"&\x06\0'\x06\0N\x06\0Q\x06\0T\x06\0X\x06\0_\x06\0`\x06\0\x0E \0\x10 \0") }, 11u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDF\0\0\xE7\0\0\xE8\0\0\xEA\0\0\xEB\0\0\xEE\0\0\xEF\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF8\0\0\xFB\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"2\x04\x003\x04\0D\x04\0E\x04\0F\x04\0G\x04\0I\x04\0J\x04\0L\x04\0M\x04\0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xDF\0\0\xE4\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x1F\x01\0 \x01\0+\x01\0,\x01\0-\x01\0.\x01\x000\x01\x002\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0_\x01\0`\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 40u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF5\0\0\xF6\0\0M\x01\0N\x01\0S\x01\0T\x01\0Y\x01\0Z\x01\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD0\x0E\0\xDA\x0E\0\x0B \0\x0C \0") }, 11u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0y\0\0\xE0\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xEE\0\0\xF1\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF9\0\0\xFB\0\0)\x01\0*\x01\0i\x01\0j\x01\0\xBD\x1E\0\xBE\x1E\0") }, 19u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x19\0\x02\0\x04\0\x07\0\x0C\0\x11\0\x16\0\x19\0\x1E\0!\0$\0'\0+\0/\x003\x007\0;\0?\0C\0G\0M\0S\0W\0[\0_\0chdzd\xC5\xBEi\xCC\x87\xCC\x80i\xCC\x87\xCC\x81i\xCC\x87\xCC\x83j\xCC\x83j\xCC\x87\xCC\x83l\xCC\x83m\xCC\x83r\xCC\x83\xC4\x85\xCC\x81\xC4\x85\xCC\x83\xC4\x97\xCC\x81\xC4\x97\xCC\x83\xC4\x99\xCC\x81\xC4\x99\xCC\x83\xC4\xAF\xCC\x81\xC4\xAF\xCC\x83\xC4\xAF\xCC\x87\xCC\x81\xC4\xAF\xCC\x87\xCC\x83\xC5\xAB\xCC\x81\xC5\xAB\xCC\x83\xC5\xB3\xCC\x81\xC5\xB3\xCC\x83") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0z\0\0M\x01\0N\x01\0W\x01\0X\x01\0") }, 6u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\r\t\0\x0F\t\0\x11\t\0\x13\t\0\x15\t\0a\t\0b\t\0") }, 13u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x06\0\xE0\xA4\x85\xE0\xA4\x82\xE0\xA4\x85\xE0\xA4\x83") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"b\0\0e\0\0f\0\0h\0\0j\0\0k\0\0l\0\0m\0\0q\0\0r\0\0s\0\0t\0\0v\0\0w\0\0x\0\0{\0\0") }, 13u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"P\x04\0Q\x04\0]\x04\0^\x04\0") }, 2u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\r\0\x04\r\0\x0C\r\0\r\r\0>\r\0D\r\0F\r\0I\r\0J\r\0L\r\0M\r\0N\r\0W\r\0X\r\0`\r\0b\r\0z\r\0\x80\r\0\x0C \0\x0E \0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x97\x04\0\x98\x04\0\xBB\x04\0\xBC\x04\0\xCA\x04\0\xCB\x04\0\xD9\x04\0\xDA\x04\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x02\t\0\r\t\0\x0E\t\x001\t\x002\t\0<\t\0=\t\0D\t\0E\t\0\x0C \0\x0E \0") }, 7u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0y\0\0z\0\0") }, 2u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\"\x10\0#\x10\0(\x10\0)\x10\x003\x10\x005\x10\0@\x10\0J\x10\0P\x10\0[\x10\0b\x10\0c\x10\0d\x10\0f\x10\0u\x10\0v\x10\0}\x10\0\x7F\x10\0\x86\x10\0\x87\x10\0\x88\x10\0\x89\x10\0\x8A\x10\0\x8B\x10\0\x8F\x10\0\x9A\x10\0") }, 45u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE3\0\0\xE6\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF8\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x19\x01\0\x1A\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE3\0\0\xE4\0\0\xE5\0\0\xE8\0\0\xF0\0\0\xF2\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF9\0\0\xFD\0\0") }, 20u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE1\0\0\xE2\0\0\xE4\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEE\0\0\xEF\0\0\xF1\0\0\xF2\0\0\xF4\0\0\xF5\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0\xFE\0\0\xFF\0\0\0\x01\0S\x01\0T\x01\0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE1\0\0\xE2\0\0\xE3\0\0\xE5\0\0\xE7\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xED\0\0\xEE\0\0\xF1\0\0\xF2\0\0\xF6\0\0\xF7\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0\r\x01\0\x0E\x01\0\x11\x01\0\x12\x01\0D\x01\0E\x01\0K\x01\0L\x01\0a\x01\0b\x01\0g\x01\0h\x01\0~\x01\0\x7F\x01\0\xCE\x01\0\xCF\x01\0") }, 19u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE8\x07\0\xEB\x07\0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0z\0\0{\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE2\0\0\xE7\0\0\xEA\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF1\0\0\xF2\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x03\n\0\x04\n\0\x0C \0\x0E \0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xE9\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 8u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x05\0\xE1\xBA\xB9\xCC\x80\xE1\xBB\x8D\xCC\x80") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0\xDF\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xEC\0\0\xEE\0\0\xF0\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF9\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0S\x01\0T\x01\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"h\0\0i\0\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD2\x06\0\xD3\x06\0\x0C \0\x10 \0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x0C \0\x10 \0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE4\0\0\xE7\0\0\xE8\0\0\xE9\0\0\xEB\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"b\0\0h\0\0j\0\0k\0\0o\0\0p\0\0r\0\0s\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0\xE0\0\0\xF0\0\0\xF2\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 49u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x03\0\x05\0chhphqh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x06\t\0\x0C\t\0\x0F\t\0\x11\t\0\x13\t\0\x15\t\0") }, 10u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE1\0\0\xE3\0\0\xE4\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xED\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE2\0\0\xE4\0\0\xE6\0\0\xE7\0\0\xEC\0\0\xF1\0\0\xF2\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0_\x01\0`\x01\0c\x01\0d\x01\0") }, 14u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\r\t\0\x0E\t\0\x11\t\0\x12\t\0E\t\0F\t\0I\t\0J\t\0\x0C \0\x0E \0") }, 6u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"2\x04\x003\x04\x005\x04\08\x04\0D\x04\0E\x04\0F\x04\0G\x04\0H\x04\0K\x04\0L\x04\0M\x04\0N\x04\0P\x04\0Q\x04\0R\x04\0") }, 13u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"k\0\0l\0\0q\0\0r\0\0w\0\0z\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xDF\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xE9\0\0\xEC\0\0\xED\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF7\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFD\0\0\xFF\0\0\0\x01\0S\x01\0T\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"k\0\0l\0\0w\0\0z\0\0\xE7\0\0\xE8\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0\x11\x01\0\x12\x01\0a\x01\0b\x01\0Y\x02\0Z\x02\0%\x1E\0&\x1E\0") }, 11u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"&\x06\0'\x06\0N\x06\0Q\x06\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"(\x10\0)\x10\x003\x10\x005\x10\0@\x10\0J\x10\0P\x10\0[\x10\0e\x10\0f\x10\0\x90\x10\0\x9A\x10\0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x8E\r\0\x91\r\0\xA6\r\0\xA7\r\0\xF3\r\0\xF4\r\0\x0B \0\x0E \0") }, 8u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0Q\x01\0R\x01\0S\x01\0T\x01\0Y\x01\0Z\x01\0k\x01\0l\x01\0m\x01\0n\x01\0q\x01\0r\x01\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0z\0\0\xE0\0\0\xE3\0\0\xE4\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x07\x01\0\x08\x01\0\x11\x01\0\x12\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 43u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0b\0\0e\0\0f\0\0i\0\0j\0\0o\0\0q\0\0u\0\0w\0\0z\0\0{\0\0") }, 8u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(zerovec::ZeroVec::new(), 0u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x05\0\x04\0\x08\0\x0C\0\x10\0\xD0\xB0\xCC\x82\xD0\xB5\xCC\x82\xD0\xB8\xCC\x82\xD0\xBE\xCC\x82\xD1\x83\xCC\x82") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0z\0\0\xE5\0\0\xE6\0\0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE0\0\0\xE9\0\0\xEA\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xE1\0\0\xE4\0\0\xE6\0\0\xE9\0\0\xEB\0\0\xEC\0\0\xED\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0+\x01\0,\x01\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0x\0\0y\0\0") }, 2u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x0F\x07\0\x10\x07\0-\x07\x000\x07\0M\x07\0P\x07\0\x0C \0\x0E \0") }, 9u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0\xDF\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xF0\0\0\xF1\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFE\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x05\x01\0\x06\x01\0\r\x01\0\x0E\x01\0\x0F\x01\0\x10\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0\x19\x01\0\x1A\x01\0\x1B\x01\0\x1C\x01\0+\x01\0,\x01\0-\x01\0.\x01\0>\x01\0?\x01\0H\x01\0I\x01\0S\x01\0T\x01\0U\x01\0V\x01\0Y\x01\0Z\x01\0a\x01\0b\x01\0e\x01\0f\x01\0k\x01\0l\x01\0m\x01\0n\x01\0o\x01\0p\x01\0~\x01\0\x7F\x01\0") }, 51u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"f\x0C\0p\x0C\0\x0C \0\x0E \0") }, 12u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"F\x04\0G\x04\0I\x04\0J\x04\0K\x04\0M\x04\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x0B \0\x0C \0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x07\x12\0\x08\x12\0G\x12\0H\x12\0\x87\x12\0\x88\x12\0\xAF\x12\0\xB0\x12\0\xCF\x12\0\xD0\x12\0\xEF\x12\0\xF0\x12\0\xF8\x12\0\0\x13\0\x0F\x13\0\x10\x13\0\x18\x13\0 \x13\0X\x13\0[\x13\0\x80\x13\0\x9A\x13\0\x80-\0\x97-\0\xA0-\0\xA7-\0\xA8-\0\xAF-\0\xB0-\0\xB7-\0\xB8-\0\xBF-\0\xC0-\0\xC7-\0\xC8-\0\xCF-\0\xD0-\0\xD7-\0\xD8-\0\xDF-\0") }, 131u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0{\0\0") }, 5u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"b\0\0e\0\0g\0\0h\0\0j\0\0k\0\0q\0\0s\0\0w\0\0{\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0\x03\x01\0\x04\x01\0\x15\x01\0\x16\x01\0-\x01\0.\x01\0O\x01\0P\x01\0S\x01\0T\x01\0m\x01\0n\x01\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"q\0\0r\0\0w\0\0y\0\0\xDF\0\0\xE7\0\0\xE8\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF8\0\0\xFC\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 39u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x93\x04\0\x94\x04\0\x9B\x04\0\x9C\x04\0") }, 2u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"&\x06\0'\x06\0\x0E \0\x10 \0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"J\x04\0L\x04\0M\x04\0N\x04\0Q\x04\0R\x04\0") }, 4u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\n\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0 \0$\0\xD0\xB0\xCC\x81\xD0\xB5\xCC\x81\xD0\xB8\xCC\x81\xD0\xBE\xCC\x81\xD1\x83\xCC\x81\xD1\x8E\xCC\x81\xD1\x8F\xCC\x81\xD1\x94\xCC\x81\xD1\x96\xCC\x81\xD1\x97\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x06\0\x04\x06\0\"\x06\0%\x06\0&\x06\0'\x06\0)\x06\0*\x06\0G\x06\0H\x06\0J\x06\0S\x06\0T\x06\0U\x06\0V\x06\0Y\x06\0p\x06\0q\x06\0z\x06\0~\x06\0\xBA\x06\0\xBB\x06\0\xC2\x06\0\xC4\x06\0\x0C \0\x10 \0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0w\0\0x\0\0\xE0\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0") }, 40u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"k\0\0l\0\0q\0\0r\0\0w\0\0x\0\0y\0\0z\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE1\0\0\xE2\0\0\xE7\0\0\xE8\0\0\xED\0\0\xEE\0\0\xFA\0\0\xFB\0\0\x07\x01\0\x08\x01\0B\x01\0C\x01\0_\x01\0`\x01\0c\x01\0d\x01\0\xF5\x01\0\xF6\x01\0\xA3\x02\0\xA4\x02\0\xA6\x02\0\xA7\x02\0\x11\x1E\0\x12\x1E\0") }, 18u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0z\xCC\xA7") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"f\0\0g\0\0j\0\0k\0\0w\0\0x\0\0z\0\0{\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"b\0\0c\0\0d\0\0e\0\0g\0\0h\0\0q\0\0r\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"h\0\0i\0\0v\0\0w\0\0z\0\0{\0\0\xE3\0\0\xE4\0\0") }, 4u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"D\t\0E\t\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"c\0\0d\0\0f\0\0g\0\0h\0\0i\0\0j\0\0k\0\0l\0\0m\0\0o\0\0p\0\0q\0\0r\0\0v\0\0w\0\0z\0\0{\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\xE0\0\0\xE3\0\0\xE4\0\0\xF0\0\0\xF1\0\0\xF7\0\0\xF8\0\0\xFD\0\0\xFF\0\0\0\x01\0\x01\x01\0\x02\x01\0\x03\x01\0\x04\x01\0\x13\x01\0\x14\x01\0\x15\x01\0\x16\x01\0+\x01\0,\x01\0-\x01\0.\x01\0M\x01\0N\x01\0O\x01\0P\x01\0S\x01\0T\x01\0k\x01\0l\x01\0m\x01\0n\x01\0\xF9\x1E\0\xFA\x1E\0") }, 50u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"MN\0NN\0\xC2N\0\xC3N\0\x0FO\0\x10O\0PO\0QO\0\xB6O\0\xB7O\0\xF3P\0\xF4P\0FQ\0GQ\0LQ\0MQ\0yQ\0zQ\0\xF8Q\0\xF9Q\0+R\0,R\08R\09R\0\xF3R\0\xF4R\0QS\0RS\0^S\0_S\0`S\0aS\0\xF6S\0\xF7S\0\x05V\0\x06V\0$X\0%X\0\x8EX\0\x8FX\0\xE4X\0\xE5X\0eY\0fY\0\\[\0][\0\xC7\\\0\xC8\\\0\xBC]\0\xBD]\0\xFD]\0\xFE]\0\x17h\0\x18h\0Ti\0Ui\0\x85m\0\x86m\0>n\0?n\0\x8Eo\0\x8Fo\0Xp\0Yp\0\xE6q\0\xE7q\0\xC4r\0\xC5r\x003t\x004t\0Zt\0[t\0+u\0,u\0\x91x\0\x92x\0\x01y\0\x02y\0\x9C~\0\x9D~\0G\x82\0H\x82\0\x92\x82\0\x93\x82\0\xD7\x82\0\xD8\x82\0(\x83\0)\x83\0\xEC\x84\0\xED\x84\0\xA9\x86\0\xAA\x86\0\0\x87\0\x01\x87\0\xD8\x88\0\xD9\x88\0,\x8B\0-\x8B\0K\x91\0L\x91\0\xB4\x96\0\xB5\x96\0\xC0\x96\0\xC1\x96\0\xEA\x9A\0\xEB\x9A\0") }, 53u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"MN\0NN\0\xC2N\0\xC3N\0\x0FO\0\x10O\0PO\0QO\0\xA3O\0\xA4O\0\xF3P\0\xF4P\0FQ\0GQ\0QQ\0RQ\08R\09R\0\xCBR\0\xCCR\0QS\0RS\0^S\0_S\0\x80T\0\x81T\0\x05V\0\x06V\0$X\0%X\0\x8EX\0\x8FX\0\xE4X\0\xE5X\0\\[\0][\0\x7F\\\0\x80\\\0\xC7\\\0\xC8\\\0\xFD]\0\xFE]\0\x9Ce\0\x9De\0\x19f\0\x1Af\0<f\0=f\0\x17h\0\x18h\0Ti\0Ui\0Qm\0Rm\0\x85m\0\x86m\0Xn\0Yn\0\x8Eo\0\x8Fo\0\x7Fp\0\x80p\0\xC4r\0\xC5r\x003t\x004t\0Zt\0[t\0+u\0,u\0\x91x\0\x92x\0\x01y\0\x02y\0\xF0~\0\xF1~\0\x92\x82\0\x93\x82\0\xD7\x82\0\xD8\x82\0(\x83\0)\x83\x005\x83\x006\x83\0\xEC\x84\0\xED\x84\0\xA9\x86\0\xAA\x86\0\xF0\x86\0\xF1\x86\0\0\x87\0\x01\x87\0\xD8\x88\0\xD9\x88\0,\x8C\0-\x8C\0c\x8D\0d\x8D\0K\x91\0L\x91\0\xFD\x95\0\xFE\x95\0G\x96\0H\x96\0\x1C\x97\0\x1D\x97\0") }, 53u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x10N\0\x11N\0\x1BN\0\x1CN\0+N\0,N\0RN\0TN\0^N\0_N\0sN\0tN\0\xA2N\0\xA3N\0\xA9N\0\xAAN\0\xADN\0\xAEN\0\xC2N\0\xC3N\0\xC6N\0\xC7N\0\xD1N\0\xD2N\0\xD3N\0\xD4N\0\xD7N\0\xD8N\0\x1EO\0\x1FO\0*O\0+O\x006O\x007O\0:O\0;O\0CO\0DO\0cO\0dO\0\x84O\0\x85O\0\x88O\0\x89O\0\x8DO\0\x8EO\0\xA3O\0\xA4O\0\xA5O\0\xA6O\0\xAEO\0\xAFO\0\xCFO\0\xD1O\0\xD8O\0\xD9O\0\xEDO\0\xEEO\0\xEFO\0\xF0O\0\xFAO\0\xFBO\0\x14P\0\x15P\0\x18P\0\x19P\0!P\0\"P\0:P\0;P\0NP\0OP\0\x7FP\0\x80P\0\x85P\0\x86P\0\x88P\0\x89P\0\x8DP\0\x8EP\0\xA3P\0\xA4P\0\xDAP\0\xDBP\0\xF3P\0\xF4P\0\xF5P\0\xF6P\0\xFBP\0\xFCP\0\\Q\0]Q\0bQ\0cQ\0\x80Q\0\x81Q\0\x89Q\0\x8AQ\0\x97Q\0\x98Q\0\xA4Q\0\xA6Q\0\xAFQ\0\xB0Q\0\xB6Q\0\xB7Q\0\xBBQ\0\xBCQ\0\xC0Q\0\xC1Q\0\xC4Q\0\xC5Q\0\xC9Q\0\xCAQ\0\xD1Q\0\xD2Q\0\xDBQ\0\xDCQ\0\xF3Q\0\xF4Q\0\xF6Q\0\xF7Q\0\xF8Q\0\xFAQ\0\xFFQ\0\0R\0\x01R\0\x02R\0\x03R\0\x04R\0 R\0!R\0(R\0)R\0.R\0/R\09R\0:R\0CR\0DR\0JR\0KR\0TR\0UR\0VR\0WR\0eR\0fR\0}R\0~R\0\x7FR\0\x80R\0\x88R\0\x89R\0\xC3R\0\xC4R\0\xD8R\0\xD9R\0\xDFR\0\xE0R\0\xFAR\0\xFBR\0\0S\0\x01S\0\x15S\0\x16S\0 S\0!S\0#S\0$S\0*S\0+S\0.S\0/S\0>S\0@S\0IS\0JS\0QS\0RS\0\\S\0]S\0^S\0_S\0dS\0eS\0fS\0hS\0uS\0vS\0xS\0yS\0\x7FS\0\x80S\0\x95S\0\x96S\0\x98S\0\x99S\0\xA2S\0\xA3S\0\xA6S\0\xA7S\0\xA8S\0\xA9S\0\xC1S\0\xC2S\0\xDBS\0\xDCS\0\xE0S\0\xE1S\0\xE8S\0\xEAS\0\xEES\0\xEFS\0\xFCS\0\xFES\0\x01T\0\x02T\0\x06T\0\x07T\0\x0FT\0\x10T\0\x15T\0\x16T\0\x1ET\0\x1FT\0 T\0!T\0(T\0*T\0-T\0/T\x001T\x002T\x004T\x005T\0<T\0=T\0UT\0VT\0[T\0\\T\0cT\0dT\0{T\0|T\0\x84T\0\x85T\0\x8BT\0\x8CT\0\x8FT\0\x91T\0\x92T\0\x93T\0\x95T\0\x96T\0\x99T\0\x9AT\0\xB3T\0\xB4T\0\xB8T\0\xB9T\0\xBDT\0\xBET\0\xC4T\0\xC5T\0\xC6T\0\xC7T\0\xD1T\0\xD2T\0\xD7T\0\xD8T\0\xE8T\0\xE9T\0\xEET\0\xEFT\0\xFAT\0\xFBT\0\xFCT\0\xFDT\0\x01U\0\x02U\0\x06U\0\x08U\0 U\0!U\0'U\0(U\0>U\0?U\0CU\0EU\0dU\0eU\0nU\0oU\0pU\0qU\0xU\0yU\0|U\0}U\0\x89U\0\x8AU\0\x98U\0\x99U\0\xA7U\0\xA8U\0\xB1U\0\xB2U\0\xB3U\0\xB4U\0\xC5U\0\xC6U\0\xD3U\0\xD4U\0\xDCU\0\xDDU\0\xE1U\0\xE2U\0\xE6U\0\xE7U\0\xFDU\0\xFEU\0\0V\0\x01V\0\x18V\0\x19V\0\x1FV\0 V\x001V\x003V\x006V\x007V\09V\0:V\0XV\0YV\0\\V\0]V\0bV\0cV\0iV\0kV\0\x8EV\0\x90V\0\xA3V\0\xA4V\0\xB7V\0\xB8V\0\xBCV\0\xBDV\0\xCAV\0\xCBV\0\xDAV\0\xDBV\0\xE4V\0\xE5V\0\xF1V\0\xF2V\0\x03W\0\x04W\0JW\0KW\0OW\0PW\0]W\0^W\0_W\0aW\0oW\0pW\0wW\0xW\0\x84W\0\x85W\0\x9BW\0\x9CW\0\xA2W\0\xA3W\0\xA6W\0\xA7W\0\xABW\0\xACW\0\xAEW\0\xAFW\0\xC2W\0\xC3W\0\xE0W\0\xE1W\0$X\0%X\x000X\x001X\x005X\x006X\0LX\0MX\0XX\0YX\0\x85X\0\x86X\0\x93X\0\x94X\0\x99X\0\x9AX\0\x9FX\0\xA0X\0\xA9X\0\xAAX\0\xF3X\0\xF4X\0\xF6X\0\xF7X\0\xF9X\0\xFAX\0-Y\0.Y\0/Y\x000Y\0NY\0OY\0`Y\0aY\0bY\0cY\0xY\0yY\0\x83Y\0\x85Y\0\x86Y\0\x87Y\0\x92Y\0\x94Y\0\xDAY\0\xDBY\0\xDCY\0\xDDY\0\xE5Y\0\xE6Y\0\xE8Y\0\xE9Y\0\xFBY\0\xFCY\0\x07Z\0\x08Z\0%Z\0&Z\x006Z\x007Z\0IZ\0JZ\0jZ\0kZ\0tZ\0uZ\0vZ\0wZ\0\x7FZ\0\x80Z\0\x9AZ\0\x9BZ\0\xB3Z\0\xB4Z\0\xC2Z\0\xC3Z\0\xC9Z\0\xCAZ\0j[\0k[\0u[\0v[\0}[\0~[\0\x85[\0\x86[\0\xA0[\0\xA1[\0\xA6[\0\xA7[\0\xAB[\0\xAC[\0\xB0[\0\xB1[\0\xB5[\0\xB6[\0\xD3[\0\xD4[\0\xE5[\0\xE6[\0\xFA[\0\xFB[\0\t\\\0\n\\\0'\\\0(\\\0,\\\0-\\\x004\\\x005\\\08\\\09\\\0?\\\0@\\\0H\\\0K\\\0N\\\0O\\\0Q\\\0R\\\0a\\\0b\\\0e\\\0f\\\0o\\\0p\\\0y\\\0z\\\0\x7F\\\0\x80\\\0\x94\\\0\x95\\\0\x96\\\0\x97\\\0\xA9\\\0\xAA\\\0\xAD\\\0\xAE\\\0\xE6\\\0\xE7\\\0\xE8\\\0\xE9\\\0\xED\\\0\xEE\\\0\xFB\\\0\xFC\\\0\x0E]\0\x0F]\0\x14]\0\x15]\0\x16]\0\x17]\0\x1B]\0\x1C]\0-]\0.]\0L]\0M]\0\xC5]\0\xC6]\0\xCD]\0\xCE]\0\xE2]\0\xE3]\0\xE9]\0\xEA]\0\xFD]\0\xFF]\0\x06^\0\x07^\0\x18^\0\x19^\0\x1A^\0\x1B^\0\x1C^\0\x1D^\0'^\0(^\x007^\08^\0L^\0M^\0b^\0c^\0\x84^\0\x85^\0\x87^\0\x88^\0\x90^\0\x91^\0\xB5^\0\xB7^\0\xCA^\0\xCB^\0\xD3^\0\xD4^\0\x13_\0\x14_\0\x1B_\0\x1C_\0'_\0(_\0W_\0X_\0d_\0e_\0j_\0k_\0\x8A_\0\x8B_\0\x98_\0\x9A_\0\xA1_\0\xA2_\0\xBD_\0\xBE_\0\xF1_\0\xF2_\0\xFF_\0\0`\0\x14`\0\x15`\0\x1C`\0\x1D`\0 `\0!`\0/`\x000`\0C`\0D`\0M`\0N`\0R`\0S`\0U`\0V`\0d`\0e`\0l`\0m`\0s`\0t`\0\x8D`\0\x8E`\0\x96`\0\x97`\0\xA6`\0\xA7`\0\xAC`\0\xAD`\0\xAF`\0\xB0`\0\xB4`\0\xB5`\0\xBC`\0\xBD`\0\xCA`\0\xCC`\0\xD5`\0\xD6`\0\xDF`\0\xE0`\0\xE6`\0\xE7`\0\xE9`\0\xEA`\0\xEB`\0\xEC`\0\xED`\0\xEE`\0\xF0`\0\xF1`\0\xF6`\0\xF7`\0\x15a\0\x16a\0#a\0%a\0?a\0@a\0La\0Ma\0ha\0ia\0wa\0xa\0\x8Ba\0\x8Ca\0\x8Ea\0\x8Fa\0\x94a\0\x95a\0\xA8a\0\xA9a\0\xC8a\0\xC9a\0\xCAa\0\xCBa\0\xE6a\0\xE7a\0\x0Eb\0\x0Fb\0\x1Ab\0\x1Bb\0\x1Fb\0 b\x003b\x004b\0Rb\0Sb\0Tb\0Ub\0[b\0\\b\0pb\0qb\0sb\0tb\0vb\0wb\0|b\0}b\0\x92b\0\x93b\0\x96b\0\x97b\0\x9Ab\0\x9Cb\0\xA0b\0\xA2b\0\xBCb\0\xBDb\0\xC2b\0\xC3b\0\xC4b\0\xC5b\0\xC7b\0\xC8b\0\xCCb\0\xCDb\0\xCEb\0\xCFb\0\xD0b\0\xD1b\0\xD3b\0\xD4b\0\xD7b\0\xD8b\0\xD9b\0\xDAb\0\xE2b\0\xE4b\0\xE7b\0\xE8b\0\xEDb\0\xEEb\0\xEFb\0\xF0b\0\xF1b\0\xF2b\0\xF4b\0\xF5b\0\xFDb\0\xFEb\0\x02c\0\x03c\0\x0Ec\0\x0Fc\0\x1Ac\0\x1Bc\0\x1Fc\0!c\0#c\0$c\0(c\0)c\0+c\0,c\0=c\0>c\0Bc\0Cc\0Ec\0Gc\0Lc\0Pc\0^c\0_c\0cc\0dc\0gc\0hc\0vc\0wc\0zc\0|c\0\x80c\0\x81c\0\x82c\0\x83c\0\x8Fc\0\x91c\0\x98c\0\x99c\0\xA0c\0\xA1c\0\xB0c\0\xB1c\0\xB7c\0\xB8c\0\xBAc\0\xBBc\0\xC9c\0\xCAc\0\xCDc\0\xCEc\0\xE3c\0\xE4c\0\xE9c\0\xEBc\0\xEDc\0\xEEc\0\xFDc\0\xFEc\0\0d\0\x03d\0\x05d\0\x06d\0\x0Fd\0\x10d\0\x13d\0\x15d\0:d\0;d\0Gd\0Hd\0gd\0hd\0yd\0zd\0\x85d\0\x86d\0\x87d\0\x88d\0\x91d\0\x92d\0\x95d\0\x96d\0\xA4d\0\xA5d\0\xA9d\0\xAAd\0\xACd\0\xADd\0\xAEd\0\xAFd\0\xB0d\0\xB1d\0\xB5d\0\xB6d\0\xBCd\0\xBDd\0\xC2d\0\xC3d\0\xC5d\0\xC6d\0\xD2d\0\xD3d\0\0e\0\x01e\0[e\0\\e\0^e\0_e\0we\0xe\0\x8Ce\0\x8De\0\x91e\0\x92e\0\x9Fe\0\xA0e\0\xA4e\0\xA5e\0\xA7e\0\xA8e\0\xA9e\0\xAAe\0\xECe\0\xEDe\0\xF1e\0\xF2e\0\xF7e\0\xF8e\0\x14f\0\x15f\0\x19f\0\x1Af\0'f\0(f\0<f\0=f\0Lf\0Mf\0Uf\0Vf\0ff\0gf\0pf\0qf\0~f\0\x7Ff\0\x87f\0\x88f\0\xD9f\0\xDAf\0\xDDf\0\xDEf\0\x14g\0\x15g\0&g\0'g\x004g\x005g\0=g\0>g\0Fg\0Gg\0Og\0Pg\0Vg\0Wg\0`g\0ag\0mg\0ng\0\x89g\0\x8Ag\0\x95g\0\x96g\0\x9Ag\0\x9Bg\0\xA3g\0\xA4g\0\xAFg\0\xB0g\0\xC4g\0\xC5g\0\xD1g\0\xD3g\0\xDCg\0\xDDg\0\xE0g\0\xE1g\0\xE9g\0\xEAg\0\xF1g\0\xF2g\0\xFFg\0\0h\0\x05h\0\x06h\0\x08h\0\th\0\x13h\0\x14h\0\x16h\0\x18h\0*h\0+h\0=h\0>h\0Bh\0Ch\0Ph\0Qh\0Th\0Uh\0fh\0gh\0hh\0jh\0vh\0wh\0\x86h\0\x87h\0\x97h\0\x98h\0\xA2h\0\xA3h\0\xA7h\0\xA9h\0\xADh\0\xAEh\0\xB3h\0\xB4h\0\xCDh\0\xCEh\0\xD5h\0\xD6h\0\xD8h\0\xD9h\0\xE0h\0\xE1h\0\xF1h\0\xF2h\0\xF5h\0\xF6h\0\xFAh\0\xFBh\0\x0Ei\0\x0Fi\0\x12i\0\x13i\0-i\0.i\0?i\0@i\0Ti\0Ui\0`i\0ai\0wi\0xi\0\x84i\0\x85i\0\x86i\0\x87i\0\x88i\0\x89i\0\x94i\0\x96i\0\xA8i\0\xA9i\0\xB4i\0\xB5i\0\xCCi\0\xCDi\0\xD0i\0\xD1i\0\xDBi\0\xDCi\0\xDFi\0\xE0i\0\xFDi\0\xFEi\0\xFFi\0\0j\0\x1Fj\0 j\0*j\0+j\0Dj\0Ej\0Gj\0Hj\0Xj\0Zj\0aj\0bj\0qj\0rj\0\x90j\0\x91j\0\xACj\0\xADj\0Gk\0Hk\0gk\0hk\0yk\0zk\0|k\0}k\0\x83k\0\x84k\0\x89k\0\x8Ak\0\x96k\0\x97k\0\xB4k\0\xB5k\0\xB7k\0\xB8k\0\xBFk\0\xC0k\0\xC1k\0\xC2k\0\xD9k\0\xDAk\0\xE1k\0\xE2k\0\xEFk\0\xF0k\0\x13l\0\x14l\0\"l\0#l\0'l\0)l\0.l\x000l\0Al\0Bl\0[l\0\\l\0^l\0_l\0pl\0ql\0yl\0zl\0\x81l\0\x82l\0\x90l\0\x91l\0\x9Bl\0\x9Cl\0\xA5l\0\xA7l\0\xAAl\0\xACl\0\xAEl\0\xAFl\0\xB8l\0\xB9l\0\xBCl\0\xBFl\0\xC4l\0\xC5l\0\xCCl\0\xCDl\0\xDEl\0\xDFl\0\xEAl\0\xEBl\0\xF5l\0\xF6l\0\xFBl\0\xFDl\0\x01m\0\x02m\0\x12m\0\x13m\0<m\0=m\0Fm\0Hm\0Jm\0Km\0cm\0dm\0xm\0ym\0\x82m\0\x83m\0\x8Cm\0\x8Dm\0\x8Em\0\x8Fm\0\x95m\0\x96m\0\x9Dm\0\x9Em\0\xA1m\0\xA2m\0\xA3m\0\xA5m\0\xA6m\0\xA8m\0\xA9m\0\xAAm\0\xAEm\0\xAFm\0\xC0m\0\xC1m\0\xC6m\0\xC8m\0\xCCm\0\xCDm\0\xE4m\0\xE5m\0\xEBm\0\xECm\0\xEEm\0\xEFm\0\xF3m\0\xF4m\0\xF9m\0\xFAm\0\nn\0\x0Bn\0\x14n\0\x15n\0\x17n\0\x18n\0\x1Dn\0\x1En\0 n\0!n\0$n\0%n\x002n\x003n\0:n\0;n\0Cn\0Dn\0Xn\0Yn\0\x7Fn\0\x80n\0\x83n\0\x84n\0\x85n\0\x86n\0\x89n\0\x8An\0\xA2n\0\xA3n\0\xAFn\0\xB0n\0\xB6n\0\xB7n\0\xBAn\0\xBBn\0\xC7n\0\xC8n\0\xD4n\0\xD6n\0\xDAn\0\xDBn\0\xDEn\0\xDFn\0\xE4n\0\xE5n\0\xE9n\0\xEAn\0\x06o\0\x07o\0\x13o\0\x14o\x001o\x002o\0>o\0?o\0Go\0Ho\0mo\0no\0\x84o\0\x85o\0\x88o\0\x89o\0\x9Co\0\x9Do\0\xA1o\0\xA2o\0\xD2o\0\xD3o\0\x11p\0\x12p\0vp\0wp\0xp\0yp\0|p\0}p\0~p\0\x7Fp\0\x8Ap\0\x8Bp\0\x92p\0\x93p\0\x95p\0\x96p\0\xABp\0\xAEp\0\xBCp\0\xBEp\0\xC1p\0\xC2p\0\xD8p\0\xDAp\0\xDBp\0\xDCp\0\xDFp\0\xE0p\0\xEBp\0\xECp\0\xF9p\0\xFAp\0\tq\0\x0Bq\0\x15q\0\x16q\0\x19q\0\x1Bq\x000q\x001q\0Nq\0Oq\0dq\0eq\0}q\0~q\0\x84q\0\x85q\0\x8Fq\0\x90q\0\x94q\0\x95q\0\x99q\0\x9Aq\0\xACq\0\xADq\0\xE5q\0\xE6q\09r\0:r\0\x80r\0\x82r\0\x84r\0\x85r\0\xACr\0\xADr\0\xB8r\0\xB9r\0\xC8r\0\xC9r\0\xDEr\0\xDFr\0\xE1r\0\xE2r\0\xEDr\0\xEEr\0\xF0r\0\xF1r\0\xF8r\0\xF9r\0\x0Es\0\x0Fs\0\x15s\0\x17s\0)s\0*s\0+s\0-s\0>s\0@s\0ms\0ns\0~s\0\x7Fs\0\x96s\0\x97s\0\xB7s\0\xB8s\0\x05t\0\x06t\0\tt\0\nt\0\x10t\0\x11t\0\"t\0#t\0Zt\0[t\0\xA7t\0\xA8t\0\xE2t\0\xE5t\0\xEEt\0\xEFt\0\xF7t\0\xF8t\0%u\0&u\0)u\0*u\0+u\0,u\0Ou\0Pu\0Tu\0Uu\0\\u\0]u\0tu\0uu\0xu\0yu\0\x99u\0\x9Bu\0\x9Fu\0\xA0u\0\xA4u\0\xA5u\0\xABu\0\xACu\0\xAEu\0\xAFu\0\xB9u\0\xBAu\0\xC7u\0\xC8u\0\xCAu\0\xCBu\0\xD2u\0\xD3u\0\xD8u\0\xD9u\0\xE2u\0\xE3u\0\xEAu\0\xEBu\0\xF0u\0\xF1u\0\xF9u\0\xFAu\0\x1Fv\0 v\0$v\0%v\0&v\0'v\0)v\0,v\08v\09v\0>v\0?v\0Lv\0Mv\0cv\0dv\0\x82v\0\x83v\0\x93v\0\x94v\0\x96v\0\x97v\0\xB1v\0\xB2v\0\xBFv\0\xC0v\0\xC6v\0\xC7v\0\xCFv\0\xD1v\0\xD4v\0\xD5v\0\xD7v\0\xD8v\0\xE5v\0\xE6v\0\xEFv\0\xF0v\0\xF2v\0\xF3v\0\xF9v\0\xFAv\0(w\0*w\0/w\x000w\x006w\08w\0Aw\0Bw\0Pw\0Qw\0fw\0gw\0kw\0mw\0yw\0zw\0\x7Fw\0\x80w\0\x84w\0\x86w\0\x8Cw\0\x8Dw\0\x8Ew\0\x8Fw\0\x92w\0\x93w\0\xA9w\0\xABw\0\xACw\0\xAEw\0\xB3w\0\xB4w\0\xBBw\0\xBCw\0\xD7w\0\xD8w\0\xE2w\0\xE3w\0\xE9w\0\xEAw\0\xEBw\0\xECw\0\xEEw\0\xEFw\0\xFEw\0\0x\0\x0Cx\0\rx\0\x16x\0\x17x\0\x1Ax\0\x1Bx\x000x\x001x\08x\09x\0>x\0?x\0Ex\0Fx\0]x\0^x\0kx\0lx\0\x8Cx\0\x8Dx\0\x91x\0\x92x\0\x98x\0\x99x\0\xB1x\0\xB2x\0\xB3x\0\xB4x\0\xBEx\0\xBFx\0\xCAx\0\xCBx\0\xD5x\0\xD6x\0\xF7x\0\xF8x\0\x01y\0\x02y\0@y\0Ay\0Hy\0Iy\0_y\0ay\0my\0ny\0wy\0xy\0\x80y\0\x81y\0\x84y\0\x85y\0\xB9y\0\xBAy\0\xBDy\0\xBFy\0\xC3y\0\xC4y\0\xC6y\0\xC7y\0\xC9y\0\xCAy\0\xE7y\0\xE8y\0\xF8y\0\xF9y\0\xFDy\0\xFEy\0\x1Az\0\x1Bz\0 z\0!z\0;z\0>z\0Wz\0Xz\0tz\0uz\0\x83z\0\x85z\0\x8Dz\0\x8Ez\0\x91z\0\x93z\0\x96z\0\x97z\0\x98z\0\x99z\0\x9Cz\0\x9Dz\0\x9Fz\0\xA0z\0\xA5z\0\xA6z\0\xBFz\0\xC0z\0\xD6z\0\xD7z\0\xE3z\0\xE4z\0\xEDz\0\xEEz\0\xFFz\0\0{\0\x06{\0\x07{\0\x0B{\0\x0C{\0\x19{\0\x1A{\0:{\0;{\0<{\0={\0O{\0Q{\0R{\0S{\0[{\0\\{\0]{\0^{\0w{\0x{\0\x95{\0\x96{\0\xA9{\0\xAA{\0\xAB{\0\xAC{\0\xB8{\0\xB9{\0\xD3{\0\xD4{\0\xE1{\0\xE2{\0\xF1{\0\xF2{\0\xF7{\0\xF8{\0\x07|\0\x08|\0'|\0(|\08|\09|\0}|\0~|\0\x91|\0\x92|\0\x98|\0\x99|\0\x9F|\0\xA0|\0\xA5|\0\xA6|\0\xAA|\0\xAB|\0\xAE|\0\xAF|\0\xB1|\0\xB2|\0\xBD|\0\xBE|\0\xD9|\0\xDA|\0\xE0|\0\xE1|\0\xEF|\0\xF0|\0\n}\0\x0B}\0n}\0o}\0\xA0~\0\xA1~\0\xA4~\0\xA5~\0\xAB~\0\xAD~\0\xB1~\0\xB2~\0\xB9~\0\xBB~\0\xC5~\0\xC6~\0\xCA~\0\xCB~\0\xCE~\0\xCF~\0\xD1~\0\xD3~\0\xDA~\0\xDB~\0\xDE~\0\xDF~\0\xE2~\0\xE4~\0\xF0~\0\xF1~\0\xF3~\0\xF4~\0\xF7~\0\xF9~\0\xFD~\0\xFE~\0\0\x7F\0\x01\x7F\0\x04\x7F\0\x05\x7F\0\x06\x7F\0\x07\x7F\0\t\x7F\0\n\x7F\0\x0E\x7F\0\x0F\x7F\0\x14\x7F\0\x16\x7F\0\x1A\x7F\0\x1B\x7F\0\x1D\x7F\0\x1E\x7F\0$\x7F\0%\x7F\0-\x7F\0.\x7F\x000\x7F\x001\x7F\0i\x7F\0j\x7F\0\x94\x7F\0\x95\x7F\0\x9A\x7F\0\x9B\x7F\0\xA1\x7F\0\xA2\x7F\0\xB9\x7F\0\xBA\x7F\0\xE9\x7F\0\xEA\x7F\0\xF1\x7F\0\xF2\x7F\0\x15\x80\0\x16\x80\0\x18\x80\0\x1A\x80\08\x80\09\x80\0;\x80\0<\x80\0=\x80\0>\x80\0?\x80\0@\x80\0B\x80\0C\x80\0F\x80\0G\x80\0K\x80\0L\x80\0\x83\x80\0\x84\x80\0\x86\x80\0\x88\x80\0\x8B\x80\0\x8D\x80\0\x98\x80\0\x99\x80\0\x9B\x80\0\x9C\x80\0\x9D\x80\0\x9E\x80\0\xA0\x80\0\xA1\x80\0\xA2\x80\0\xA3\x80\0\xAA\x80\0\xAB\x80\0\xAE\x80\0\xAF\x80\0\xB4\x80\0\xB5\x80\0\xBA\x80\0\xBB\x80\0\xBE\x80\0\xC1\x80\0\xC3\x80\0\xC4\x80\0\xDA\x80\0\xDB\x80\0\xE7\x80\0\xE8\x80\0\xF0\x80\0\xF1\x80\0\xF3\x80\0\xF4\x80\0\x02\x81\0\x03\x81\0\t\x81\0\x0B\x81\0\x0F\x81\0\x11\x81\0\x13\x81\0\x14\x81\0\x16\x81\0\x17\x81\0\x1A\x81\0\x1B\x81\0/\x81\x000\x81\0>\x81\0?\x81\0K\x81\0L\x81\0T\x81\0V\x81\0e\x81\0f\x81\0n\x81\0o\x81\0z\x81\0|\x81\0\x80\x81\0\x81\x81\0\x8A\x81\0\x8B\x81\0\x8F\x81\0\x90\x81\0\x9B\x81\0\x9E\x81\0\xA8\x81\0\xA9\x81\0\xC0\x81\0\xC1\x81\0\xCA\x81\0\xCB\x81\0\xFC\x81\0\xFD\x81\0\0\x82\0\x01\x82\0\x05\x82\0\x07\x82\0\x14\x82\0\x15\x82\x001\x82\x002\x82\x005\x82\x007\x82\0G\x82\0H\x82\0X\x82\0Y\x82\0n\x82\0o\x82\0p\x82\0q\x82\0s\x82\0t\x82\0\x8B\x82\0\x8C\x82\0\x99\x82\0\x9A\x82\0\x9C\x82\0\x9D\x82\0\xA5\x82\0\xA6\x82\0\xAF\x82\0\xB0\x82\0\xB9\x82\0\xBA\x82\0\xBD\x82\0\xBE\x82\0\xC7\x82\0\xC8\x82\0\xD1\x82\0\xD2\x82\0\xD4\x82\0\xD5\x82\0\xDB\x82\0\xDD\x82\0\xDE\x82\0\xE0\x82\0\xE3\x82\0\xE4\x82\0\xF9\x82\0\xFA\x82\0\x01\x83\0\x02\x83\0\x04\x83\0\x06\x83\0\t\x83\0\n\x83\0\x0E\x83\0\x0F\x83\0'\x83\0(\x83\0,\x83\0-\x83\x005\x83\x006\x83\08\x83\09\x83\0F\x83\0G\x83\0T\x83\0U\x83\0a\x83\0b\x83\0d\x83\0e\x83\0g\x83\0h\x83\0k\x83\0l\x83\0\x93\x83\0\x94\x83\0\xB4\x83\0\xB5\x83\0\xB9\x83\0\xBB\x83\0\xBD\x83\0\xBE\x83\0\xC7\x83\0\xC8\x83\0\xCA\x83\0\xCB\x83\0\xCC\x83\0\xCD\x83\0\xE0\x83\0\xE1\x83\0\xF1\x83\0\xF2\x83\0\x0C\x84\0\r\x84\0\x0E\x84\0\x0F\x84\0\x1D\x84\0\x1E\x84\0c\x84\0d\x84\0i\x84\0j\x84\0k\x84\0m\x84\0q\x84\0r\x84\0u\x84\0v\x84\0\x9C\x84\0\x9D\x84\0\xB2\x84\0\xB3\x84\0\xB8\x84\0\xB9\x84\0\xC4\x84\0\xC5\x84\0\xFF\x84\0\0\x85\0\x13\x85\0\x14\x85\0\x17\x85\0\x18\x85\0\x1A\x85\0\x1B\x85\0,\x85\0-\x85\0<\x85\0>\x85\0I\x85\0K\x85\0t\x85\0u\x85\0~\x85\0\x7F\x85\0\x87\x85\0\x88\x85\0\x9B\x85\0\x9C\x85\0\xAF\x85\0\xB0\x85\0\xD0\x85\0\xD1\x85\0\xD5\x85\0\xD6\x85\0\xFB\x85\0\xFC\x85\0\x11\x86\0\x12\x86\0O\x86\0Q\x86\0Z\x86\0[\x86\0\x80\x86\0\x81\x86\0\x82\x86\0\x83\x86\0\x8A\x86\0\x8B\x86\0\x8C\x86\0\x8D\x86\0\x93\x86\0\x94\x86\0\x95\x86\0\x96\x86\0\x9D\x86\0\x9E\x86\0\xA3\x86\0\xA5\x86\0\xAA\x86\0\xAB\x86\0\xAF\x86\0\xB0\x86\0\xC0\x86\0\xC1\x86\0\xC6\x86\0\xC7\x86\0\xCE\x86\0\xCF\x86\0\xD0\x86\0\xD1\x86\0\xDB\x86\0\xDC\x86\0\xE4\x86\0\xE5\x86\0\xF0\x86\0\xF1\x86\0\xFE\x86\0\xFF\x86\0\0\x87\0\x01\x87\0\x08\x87\0\t\x87\0\x12\x87\0\x14\x87\0\x15\x87\0\x16\x87\0\x17\x87\0\x19\x87\0!\x87\0\"\x87\0%\x87\0&\x87\x004\x87\x005\x87\0;\x87\0<\x87\0G\x87\0H\x87\0I\x87\0J\x87\0L\x87\0M\x87\0N\x87\0O\x87\0W\x87\0X\x87\0Y\x87\0Z\x87\0`\x87\0a\x87\0t\x87\0u\x87\0\x82\x87\0\x84\x87\0\xBA\x87\0\xBB\x87\0\xC0\x87\0\xC1\x87\0\xC6\x87\0\xC7\x87\0\xCB\x87\0\xCC\x87\0\xD1\x87\0\xD2\x87\0\x15\x88\0\x16\x88\0E\x88\0F\x88\0M\x88\0N\x88\0T\x88\0U\x88\0Y\x88\0Z\x88\0k\x88\0m\x88\0p\x88\0q\x88\0w\x88\0x\x88\0\x81\x88\0\x82\x88\0\x84\x88\0\x85\x88\0\x8D\x88\0\x8E\x88\0\x96\x88\0\x97\x88\0\x9C\x88\0\x9D\x88\0\xB1\x88\0\xB2\x88\0\xD9\x88\0\xDA\x88\0\xF3\x88\0\xF4\x88\0\xF8\x88\0\xFA\x88\0\x02\x89\0\x03\x89\0\x10\x89\0\x11\x89\0\x12\x89\0\x13\x89\0%\x89\0&\x89\0*\x89\0+\x89\0_\x89\0`\x89\0\xC5\x89\0\xC6\x89\0\xE6\x89\0\xE7\x89\0\x8A\x8A\0\x8B\x8A\0l\x8B\0m\x8B\0\xA5\x8B\0\xA6\x8B\0\xB3\x8B\0\xB4\x8B\0\xB6\x8B\0\xB7\x8B\0\xB9\x8B\0\xBA\x8B\0\xBC\x8B\0\xBE\x8B\0\xC0\x8B\0\xC1\x8B\0\xC8\x8B\0\xC9\x8B\0\xCA\x8B\0\xCB\x8B\0\xE1\x8B\0\xE2\x8B\0\xEB\x8B\0\xED\x8B\0\xF1\x8B\0\xF3\x8B\0\xF5\x8B\0\xF6\x8B\0\xFD\x8B\0\xFE\x8B\0\x06\x8C\0\x07\x8C\0\r\x8C\0\x0F\x8C\0\x10\x8C\0\x11\x8C\0\x1A\x8C\0\x1B\x8C\0#\x8C\0%\x8C\0&\x8C\0'\x8C\0,\x8C\0.\x8C\x004\x8C\x005\x8C\0A\x8C\0B\x8C\0L\x8C\0M\x8C\0Z\x8C\0[\x8C\0k\x8C\0l\x8C\0y\x8C\0{\x8C\0&\x8D\0'\x8D\0+\x8D\0-\x8D\0.\x8D\0/\x8D\x000\x8D\x001\x8D\x007\x8D\08\x8D\0;\x8D\0<\x8D\0?\x8D\0@\x8D\0A\x8D\0D\x8D\0N\x8D\0O\x8D\0X\x8D\0Y\x8D\0a\x8D\0b\x8D\0c\x8D\0d\x8D\0f\x8D\0g\x8D\0t\x8D\0u\x8D\0v\x8D\0w\x8D\0\x9F\x8D\0\xA0\x8D\0\xB4\x8D\0\xB5\x8D\0\xBE\x8D\0\xBF\x8D\0\xC6\x8D\0\xC7\x8D\0\xCB\x8D\0\xCC\x8D\0\xDB\x8D\0\xDC\x8D\0\xE4\x8D\0\xE5\x8D\0\xE8\x8D\0\xE9\x8D\0\xEA\x8D\0\xEB\x8D\0\xF5\x8D\0\xF6\x8D\0\xF7\x8D\0\xF8\x8D\0\xFA\x8D\0\xFB\x8D\0\n\x8E\0\x0B\x8E\0*\x8E\0+\x8E\x001\x8E\x002\x8E\0B\x8E\0C\x8E\0D\x8E\0E\x8E\0H\x8E\0I\x8E\0K\x8E\0L\x8E\0f\x8E\0g\x8E\0l\x8E\0n\x8E\0r\x8E\0s\x8E\0\x81\x8E\0\x82\x8E\0\x8F\x8E\0\x90\x8E\0\xAC\x8E\0\xAD\x8E\0\xAF\x8E\0\xB0\x8E\0\xBA\x8E\0\xBB\x8E\0g\x8F\0h\x8F\0t\x8F\0u\x8F\0\x7F\x8F\0\x80\x8F\0\x90\x8F\0\x91\x8F\0\x96\x8F\0\x98\x8F\0\x99\x8F\0\x9A\x8F\0\x9C\x8F\0\x9D\x8F\0\x9F\x8F\0\xA0\x8F\0\xA3\x8F\0\xA4\x8F\0\xAB\x8F\0\xAC\x8F\0\xBD\x8F\0\xBE\x8F\0\xC2\x8F\0\xC3\x8F\0\xC4\x8F\0\xC5\x8F\0\xE2\x8F\0\xE3\x8F\0\xED\x8F\0\xEE\x8F\0\xF9\x8F\0\xFA\x8F\0\x17\x90\0\x18\x90\0\x1E\x90\0\x1F\x90\0.\x90\0/\x90\0>\x90\0?\x90\0B\x90\0C\x90\0O\x90\0P\x90\0c\x90\0d\x90\0e\x90\0f\x90\0\x91\x90\0\x92\x90\0\xC1\x90\0\xC2\x90\0\xCA\x90\0\xCB\x90\0\x19\x91\0\x1A\x91\0L\x91\0M\x91\0W\x91\0X\x91\0]\x91\0^\x91\0b\x91\0d\x91\0e\x91\0f\x91\0j\x91\0k\x91\0l\x91\0m\x91\0q\x91\0r\x91\0u\x91\0v\x91\0\x7F\x91\0\x80\x91\0\x87\x91\0\x88\x91\0\x8B\x91\0\x8C\x91\0\xBA\x91\0\xBB\x91\0t\x92\0u\x92\0\x89\x94\0\x8A\x94\0\x99\x94\0\x9A\x94\0\x9D\x94\0\x9F\x94\0\xA0\x94\0\xA1\x94\0\xA5\x94\0\xA6\x94\0\xA7\x94\0\xA8\x94\0\xA9\x94\0\xAA\x94\0\xAE\x94\0\xB0\x94\0\xB3\x94\0\xB4\x94\0\xBE\x94\0\xBF\x94\0\xC2\x94\0\xC3\x94\0\xC5\x94\0\xC6\x94\0\xD0\x94\0\xD1\x94\0\xDB\x94\0\xDC\x94\0\xDD\x94\0\xDE\x94\0\xF0\x94\0\xF1\x94\0\xF2\x94\0\xF3\x94\0\xF8\x94\0\xF9\x94\0\x04\x95\0\x05\x95\0\x08\x95\0\t\x95\0\x0C\x95\0\r\x95\0\x10\x95\0\x12\x95\0\x1A\x95\0\x1B\x95\0#\x95\0&\x95\0/\x95\x001\x95\09\x95\0:\x95\0;\x95\0<\x95\0@\x95\0A\x95\0P\x95\0R\x95\0V\x95\0W\x95\0p\x95\0q\x95\0v\x95\0w\x95\0\xEF\x95\0\xF0\x95\0\xF8\x95\0\xF9\x95\0\xFA\x95\0\xFB\x95\0\xFD\x95\0\xFE\x95\0\0\x96\0\x01\x96\0\x0E\x96\0\x0F\x96\x001\x96\x002\x96\0K\x96\0M\x96\0U\x96\0V\x96\0a\x96\0b\x96\0h\x96\0i\x96\0\x85\x96\0\x86\x96\0\x8B\x96\0\x8C\x96\0\x98\x96\0\x9A\x96\0\xA7\x96\0\xA8\x96\0\xB6\x96\0\xB7\x96\0\xC0\x96\0\xC2\x96\0\xC7\x96\0\xC8\x96\0\xCC\x96\0\xCD\x96\0\xCF\x96\0\xD0\x96\0\xD5\x96\0\xD6\x96\0\xF9\x96\0\xFA\x96\0\x04\x97\0\x05\x97\0\t\x97\0\n\x97\0\x0E\x97\0\x0F\x97\0\x1C\x97\0\x1D\x97\0\x1E\x97\0\x1F\x97\0>\x97\0?\x97\0a\x97\0b\x97\0t\x97\0u\x97\0v\x97\0w\x97\0\x8D\x97\0\x8E\x97\0\xA0\x97\0\xA1\x97\0\xAD\x97\0\xAE\x97\0\xE7\x97\0\xE8\x97\0\xED\x97\0\xEE\x97\0\xF5\x97\0\xF6\x97\0w\x98\0x\x98\0\x81\x98\0\x83\x98\0\x85\x98\0\x86\x98\0\x88\x98\0\x89\x98\0\x8A\x98\0\x8B\x98\0\x93\x98\0\x94\x98\0\x96\x98\0\x97\x98\0\x9C\x98\0\x9D\x98\0\xA0\x98\0\xA1\x98\0\xA4\x98\0\xA5\x98\0\xD3\x98\0\xD4\x98\0e\x99\0f\x99\0j\x99\0k\x99\0r\x99\0s\x99\0u\x99\0w\x99\0z\x99\0{\x99\0\x7F\x99\0\x80\x99\0\x81\x99\0\x82\x99\0\x85\x99\0\x86\x99\0\x88\x99\0\x89\x99\0\x8B\x99\0\x8C\x99\0\x8D\x99\0\x8E\x99\0\x8F\x99\0\x90\x99\0\x92\x99\0\x93\x99\0n\x9A\0q\x9A\0s\x9A\0u\x9A\0y\x9A\0z\x9A\0|\x9A\0}\x9A\0\x82\x9A\0\x83\x9A\0\x84\x9A\0\x85\x9A\0\x86\x9A\0\x88\x9A\0\x8F\x9A\0\x90\x9A\0\xA1\x9A\0\xA2\x9A\0\xB0\x9A\0\xB1\x9A\0\xB7\x9A\0\xB8\x9A\0\xBC\x9A\0\xBD\x9A\0\xC5\x9A\0\xC6\x9A\0\xD3\x9A\0\xD4\x9A\0\xE6\x9A\0\xE7\x9A\0\x08\x9B\0\t\x9B\0\x13\x9B\0\x14\x9B\0A\x9B\0B\x9B\0D\x9B\0E\x9B\0O\x9B\0P\x9B\0\x7F\x9C\0\x80\x9C\0\x8D\x9C\0\x8E\x9C\0\xA4\x9C\0\xA5\x9C\0\xA8\x9C\0\xA9\x9C\0\xAB\x9C\0\xAC\x9C\0\xB8\x9C\0\xB9\x9C\0\xC4\x9C\0\xC5\x9C\0\xCD\x9C\0\xCE\x9C\0\xD6\x9C\0\xD7\x9C\0\xDE\x9C\0\xDF\x9C\0\"\x9E\0#\x9E\0%\x9E\0'\x9E\0/\x9E\x000\x9E\x003\x9E\x004\x9E\x005\x9E\x006\x9E\0=\x9E\0>\x9E\0C\x9E\0D\x9E\0I\x9E\0K\x9E\0O\x9E\0P\x9E\0f\x9E\0g\x9E\0\xCF\x9E\0\xD0\x9E\0\xD4\x9E\0\xD5\x9E\0\xDB\x9E\0\xDC\x9E\0\xEF\x9E\0\xF0\x9E\0\x0E\x9F\0\x0F\x9F\0,\x9F\0-\x9F\0\x87\x9F\0\x88\x9F\0") }, 1465u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"(N\0)N\x006N\x007N\0?N\0@N\0MN\0NN\0sN\0tN\0\x85N\0\x86N\0\xA0N\0\xA1N\0\xC2N\0\xC3N\0\x0FO\0\x10O\0PO\0QO\0\xB6O\0\xB7O\0\xCFO\0\xD0O\0\tP\0\nP\0}P\0~P\0\x85P\0\x86P\0\x98P\0\x99P\0\xF3P\0\xF4P\0?Q\0@Q\0FQ\0GQ\0LQ\0MQ\0yQ\0zQ\0\x82Q\0\x83Q\0\x96Q\0\x97Q\0\xABQ\0\xACQ\0\xCBQ\0\xCCQ\0\xCDQ\0\xCEQ\0\xE0Q\0\xE1Q\0\xF5Q\0\xF6Q\0\xF8Q\0\xF9Q\0\x12R\0\x13R\0(R\0)R\0+R\0,R\0.R\0/R\08R\09R\0CR\0DR\0\xF3R\0\xF4R\0\xF9R\0\xFAR\0\xFER\0\xFFR\0\x15S\0\x16S\0\x19S\0\x1BS\0#S\0$S\0/S\x000S\08S\09S\0QS\0RS\0^S\0_S\0`S\0aS\0iS\0jS\0yS\0zS\0\x82S\0\x83S\0\xB6S\0\xB7S\0\xC9S\0\xCAS\0\xF6S\0\xF7S\0;T\0<T\0\xFAT\0\xFBT\0\x07U\0\x08U\x005U\x006U\0dU\0eU\0\xAAU\0\xABU\0\xB2U\0\xB3U\0\x1FV\0 V\0AV\0BV\0SV\0TV\0XV\0YV\0\x8FV\0\x90V\0\xD7V\0\xD8V\0QW\0RW\0$X\0%X\0\x85X\0\x86X\0\x8EX\0\x8FX\0\x93X\0\x94X\0\x9FX\0\xA0X\0\xB3X\0\xB4X\0\xE4X\0\xE5X\0\xE9X\0\xEAX\0\xFAX\0\xFBX\0\x02Y\0\x03Y\0\nY\0\x0BY\0eY\0fY\0\x96Y\0\x97Y\x000[\x001[\0U[\0V[\0\\[\0][\0u[\0v[\0\x80[\0\x81[\0\xF8[\0\xF9[\0\xFA[\0\xFB[\0\"\\\0#\\\08\\\09\\\0?\\\0@\\\0M\\\0N\\\0Q\\\0R\\\0n\\\0o\\\0\xC7\\\0\xC8\\\0\xBC]\0\xBD]\0\xDB]\0\xDC]\0\xFD]\0\xFF]\0\x06^\0\x07^\0\x1A^\0\x1B^\0_^\0`^\0z^\0{^\0\x7F^\0\x80^\0\xC1^\0\xC2^\0\xC8^\0\xC9^\0\xDA^\0\xDB^\0\xDF^\0\xE0^\0\xF4^\0\xF5^\0\xFE^\0\xFF^\0\x0B_\0\x0C_\0\x13_\0\x14_\0P_\0Q_\0a_\0b_\0s_\0t_\0\xE1_\0\xE2_\0\x8Aa\0\x8Ba\0\xE8a\0\xE9a\0\xF8a\0\xF9a\0\x1Fb\0 b\0nb\0ob\0sb\0tb\0Bc\0Cc\0Oc\0Pc\0gc\0hc\0\xA0c\0\xA1c\0\xB0c\0\xB1c\0\xF9c\0\xFAc\0\x0Fd\0\x10d\0@d\0Ad\0Td\0Ud\0\x95d\0\x96d\0\xB2d\0\xB3d\0\0e\0\x01e\0$e\0%e\x004e\x005e\0^e\0_e\0\x91e\0\x92e\0\x9Ce\0\x9De\0\xA4e\0\xA5e\0\xA7e\0\xA8e\0\xE0e\0\xE1e\0\x88f\0\x89f\0\xAEf\0\xAFf\0\xC7f\0\xC8f\0\xECf\0\xEDf\0\xF3f\0\xF4f\0\x14g\0\x15g\0Vg\0Wg\0\xAFg\0\xB0g\0\x13h\0\x14h\0\x17h\0\x18h\0=h\0>h\0Fh\0Gh\0vh\0wh\0\x7Fh\0\x80h\0\xCDh\0\xCEh\0\xD5h\0\xD6h\0\xFAh\0\xFBh\0\x12i\0\x13i\0Ti\0Ui\0\xCCi\0\xCDi\0Dj\0Ej\0Gj\0Hj\0Xj\0Zj\0\xACj\0\xADj\0\xB8j\0\xB9j\0\xC3j\0\xC4j\0\xDAj\0\xDBj\0\xFBj\0\xFCj\0\x16k\0\x17k\0 k\0!k\0yk\0zk\0\x8Bk\0\x8Ck\0\xADk\0\xAEk\0\xB3k\0\xB4k\0\xCBk\0\xCCk\0\x14l\0\x15l\0Al\0Bl\0\xABl\0\xACl\0\xAEl\0\xAFl\0\xE3l\0\xE4l\0cm\0dm\0tm\0um\0\x85m\0\x86m\0\x8Em\0\x8Fm\0\xAEm\0\xAFm\0\xC7m\0\xC8m\0\xCBm\0\xCCm\0>n\0?n\0Xn\0Yn\0\x9Cn\0\x9Dn\0?o\0@o\0\x8Eo\0\x8Fo\0\xA1o\0\xA2o\0\xD5o\0\xD6o\0Xp\0Yp\0\xD8p\0\xD9p\0\xF9p\0\xFAp\0\nq\0\x0Bq\0\x19q\0\x1Aq\x000q\x001q\0Nq\0Oq\0nq\0oq\0\xD5q\0\xD6q\0\xD9q\0\xDAq\0\xE6q\0\xE7q\0\xEDq\0\xEEq\0\rr\0\x0Er\0;r\0<r\0?r\0@r\0ar\0br\0\x80r\0\x81r\0\xACr\0\xADr\0\xC4r\0\xC5r\0\xE1r\0\xE2r\0\xF8r\0\xF9r\0)s\0*s\0>s\0@s\0zs\0{s\0~s\0\x7Fs\x003t\x004t\0Zt\0[t\0\xE2t\0\xE3t\0\x15u\0\x16u\0+u\0,u\0\x8Au\0\x8Cu\0\x92u\0\x93u\0\xB2u\0\xB3u\0\xBEu\0\xBFu\0&v\0(v\0vv\0wv\0\x82v\0\x83v\0\xBAv\0\xBBv\0\xBFv\0\xC0v\0\xC6v\0\xC7v\0\xC8v\0\xC9v\0\xD2v\0\xD3v\0\xD4v\0\xD5v\0\xE5v\0\xE6v\0(w\0*w\0Ow\0Pw\0\x87w\0\x88w\0\x8Cw\0\x8Dw\0\xAAw\0\xABw\0\xE2w\0\xE3w\0\x91x\0\x92x\0\xDAx\0\xDBx\0\x01y\0\x02y\0+y\0,y\0Hy\0Iy\0\xB1y\0\xB2y\0\xB8y\0\xB9y\0\xBEy\0\xC0y\0;z\0<z\0@z\0Az\0tz\0uz\0\x84z\0\x85z\0\xFFz\0\0{\0R{\0S{\0w{\0x{\0\x8F{\0\x90{\0\x94{\0\x95{\0\xF7{\0\xF8{\0\r|\0\x0E|\0`|\0a|\0\xD6|\0\xD7|\0\xF0|\0\xF1|\0\xF8|\0\xF9|\0\t}\0\n}\0\x0B}\0\x0C}\0\x17}\0\x18}\0.}\0/}\x003}\x004}\0\xBD}\0\xBE}\0\xBF}\0\xC0}\0+~\0,~\0C~\0D~\0a~\0b~\0i~\0j~\0\x8F~\0\x90~\0\x96~\0\x97~\0\x9C~\0\x9D~\x006\x7F\x007\x7F\0H\x7F\0I\x7F\0P\x7F\0R\x7F\0i\x7F\0j\x7F\0\xAF\x7F\0\xB0\x7F\0\x12\x80\0\x13\x80\0s\x80\0t\x80\0~\x80\0\x80\x80\0\x8C\x80\0\x8D\x80\0\x96\x80\0\x97\x80\0\xBA\x80\0\xBB\x80\0\x08\x81\0\t\x81\0\x16\x81\0\x17\x81\0P\x81\0Q\x81\0y\x81\0z\x81\0\x9A\x81\0\x9B\x81\0\xA0\x81\0\xA1\x81\0\xC2\x81\0\xC3\x81\0\xDF\x81\0\xE0\x81\0\xFC\x81\0\xFD\x81\0\x1B\x82\0\x1C\x82\0G\x82\0H\x82\0n\x82\0o\x82\0x\x82\0y\x82\0\x92\x82\0\x93\x82\0\x99\x82\0\x9A\x82\0\xAD\x82\0\xAE\x82\0\xBD\x82\0\xBE\x82\0\xD7\x82\0\xD8\x82\0\xE3\x82\0\xE4\x82\0\x04\x83\0\x05\x83\0(\x83\0)\x83\x005\x83\x006\x83\08\x83\09\x83\0\x93\x83\0\x94\x83\0\x96\x83\0\x97\x83\0\xC7\x83\0\xC8\x83\0\xCC\x83\0\xCD\x83\0\xF1\x83\0\xF2\x83\0\x0E\x84\0\x0F\x84\x005\x84\x006\x84\0u\x84\0v\x84\0\x9C\x84\0\x9D\x84\0\xB8\x84\0\xB9\x84\0\xC4\x84\0\xC5\x84\0\xC9\x84\0\xCA\x84\0\xEC\x84\0\xED\x84\0\x14\x85\0\x15\x85\0%\x85\0&\x85\0,\x85\0-\x85\0I\x85\0J\x85\0~\x85\0\x7F\x85\0\x91\x85\0\x92\x85\0\xAF\x85\0\xB0\x85\0\x0B\x86\0\x0C\x86\0\x11\x86\0\x12\x86\0?\x86\0@\x86\0M\x86\0N\x86\0k\x86\0l\x86\0y\x86\0z\x86\0\x8A\x86\0\x8B\x86\0\x93\x86\0\x94\x86\0\xA9\x86\0\xAA\x86\0\xAF\x86\0\xB0\x86\0\xDB\x86\0\xDC\x86\0\0\x87\0\x01\x87\0\x18\x87\0\x19\x87\0%\x87\0&\x87\x004\x87\x005\x87\0Y\x87\0Z\x87\0_\x87\0a\x87\0f\x87\0g\x87\0t\x87\0u\x87\0x\x87\0y\x87\0\x82\x87\0\x84\x87\0\x9E\x87\0\x9F\x87\0\xBA\x87\0\xBB\x87\0\xC0\x87\0\xC1\x87\0\xC4\x87\0\xC5\x87\0\xCB\x87\0\xCC\x87\0\xD1\x87\0\xD2\x87\0\xF3\x87\0\xF4\x87\0\xFB\x87\0\xFC\x87\0\x05\x88\0\x06\x88\0\x15\x88\0\x16\x88\0\x1F\x88\0 \x88\0#\x88\0$\x88\0k\x88\0l\x88\0\x8D\x88\0\x8E\x88\0\xCF\x88\0\xD0\x88\0\xD8\x88\0\xDA\x88\0\xF1\x88\0\xF2\x88\0\xF9\x88\0\xFA\x88\0\x10\x89\0\x11\x89\0j\x89\0k\x89\0o\x89\0p\x89\0~\x89\0\x7F\x89\0\x1D\x8A\0\x1E\x8A\0:\x8A\0;\x8A\0\x0E\x8B\0\x0F\x8B\0,\x8B\0-\x8B\0N\x8C\0O\x8C\0T\x8C\0V\x8C\0Z\x8C\0[\x8C\0x\x8C\0z\x8C\0\x1B\x8D\0\x1C\x8D\0\xC6\x8D\0\xC7\x8D\0\xE8\x8D\0\xE9\x8D\0\xEA\x8D\0\xEB\x8D\0)\x8E\0*\x8E\0\xAC\x8E\0\xAD\x8E\0\xF8\x8E\0\xF9\x8E\0N\x8F\0O\x8F\0\x9C\x8F\0\x9D\x8F\0\xA3\x8F\0\xA4\x8F\0\xB5\x8F\0\xB6\x8F\0^\x90\0_\x90\0\x91\x90\0\x92\x90\0\x19\x91\0\x1A\x91\0K\x91\0L\x91\0j\x91\0k\x91\0\xAC\x91\0\xAD\x91\0\xC6\x91\0\xC7\x91\0\xD8\x91\0\xD9\x91\0\x14\x92\0\x16\x92\0E\x92\0F\x92\0[\x92\0\\\x92\0d\x92\0e\x92\0\xC1\x92\0\xC2\x92\0(\x93\0)\x93\x006\x93\x007\x93\0J\x93\0K\x93\0\x9A\x93\0\x9B\x93\0\xAC\x93\0\xAD\x93\0\xC8\x93\0\xC9\x93\0\xE2\x93\0\xE3\x93\0:\x94\0;\x94\0p\x94\0q\x94\0}\x94\0~\x94\0\x7F\x94\0\x80\x94\0\xA9\x95\0\xAA\x95\0\x1C\x96\0\x1D\x96\x001\x96\x002\x96\0\xB4\x96\0\xB5\x96\0\xB6\x96\0\xB7\x96\0\xB9\x96\0\xBA\x96\0\xC0\x96\0\xC1\x96\0\xCC\x96\0\xCD\x96\0\x04\x97\0\x05\x97\0\x1C\x97\0\x1D\x97\0Q\x97\0R\x97\0Y\x97\0Z\x97\0t\x97\0u\x97\0\xA0\x97\0\xA1\x97\0\xAD\x97\0\xAE\x97\0\xED\x97\0\xEE\x97\0\x0C\x98\0\r\x98\08\x98\09\x98\0[\x98\0\\\x98\0\xB1\x98\0\xB2\x98\0\xC6\x98\0\xC7\x98\0\xEA\x98\0\xEB\x98\0\x03\x99\0\x04\x99\0\x0C\x99\0\r\x99\0\x1A\x99\0\x1B\x99\x005\x99\x006\x99\0>\x99\0?\x99\0\xDD\x99\0\xDE\x99\0\xF1\x99\0\xF2\x99\0U\x9A\0V\x9A\0\xB0\x9A\0\xB1\x9A\0\xB7\x9A\0\xB8\x9A\0\xCF\x9A\0\xD0\x9A\0\xDF\x9A\0\xE0\x9A\0\r\x9B\0\x0E\x9B\0/\x9B\x000\x9B\x002\x9B\x003\x9B\0w\x9B\0x\x9B\0\x91\x9B\0\x92\x9B\0\xC9\x9B\0\xCB\x9B\0\xE8\x9B\0\xE9\x9B\0w\x9C\0x\x9C\0\xE9\x9C\0\xEA\x9C\0\xF6\x9C\0\xF7\x9C\0(\x9D\0)\x9D\0a\x9D\0b\x9D\0\xB4\x9D\0\xB5\x9D\0\x1A\x9E\0\x1B\x9E\0u\x9E\0v\x9E\0}\x9E\0~\x9E\0\xCD\x9E\0\xCE\x9E\0\xDB\x9E\0\xDC\x9E\0\xF9\x9E\0\xFA\x9E\0\xFD\x9E\0\xFE\x9E\0\x0E\x9F\0\x0F\x9F\0,\x9F\0-\x9F\0\x90\x9F\0\x91\x9F\0\xA0\x9F\0\xA1\x9F\0") }, 495u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - ]; - unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1>, icu_provider::DataError> { - let mut metadata = icu_provider::DataResponseMetadata::default(); - let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_AUXILIARY_V1, req.id, req.metadata.attributes_prefix_match) { - payload - } else { - const FALLBACKER: icu::locale::fallback::LocaleFallbackerWithConfig<'static> = icu::locale::fallback::LocaleFallbacker::new().for_config(<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1 as icu_provider::DataMarker>::INFO.fallback_config); - let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); - loop { - if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_AUXILIARY_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { - metadata.locale = Some(fallback_iterator.take()); - break payload; - } - if fallback_iterator.get().is_unknown() { - return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1 as icu_provider::DataMarker>::INFO, req)); - } - fallback_iterator.step(); - } - }; - Ok(icu_provider::DataResponse { payload, metadata }) - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_exemplar_characters_auxiliary_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleExemplarCharactersAuxiliaryV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok(icu_provider::baked::DataStore::iter(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_AUXILIARY_V1).collect()) - } - } - }; - ($ provider : ty , DRY) => {}; - ($ provider : ty , DRY , ITER) => { - __impl_locale_exemplar_characters_auxiliary_v1!($provider, ITER); - }; -} -#[doc(inline)] -pub use __impl_locale_exemplar_characters_auxiliary_v1 as impl_locale_exemplar_characters_auxiliary_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_index_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_index_v1.rs.data deleted file mode 100644 index 4125fa21fa5c..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_index_v1.rs.data +++ /dev/null @@ -1,869 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleExemplarCharactersIndexV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 690B for the lookup data structure (146 data identifiers) -/// * 13345B[^1] for the actual data (114 unique structs) -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `icu_provider/baked` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_exemplar_characters_index_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - const DATA_LOCALE_EXEMPLAR_CHARACTERS_INDEX_V1: icu_provider::baked::zerotrie::Data<icu::locale::provider::LocaleExemplarCharactersIndexV1> = { - const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xE1zabcdefghijklmnopqrstuvwxyz\0\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x02\x02\x02\x02\x02\x145Mc}\x9C\xAB\xCD\xE2\xEA\x1A-Qcj~\x81\x90\xDA\x03\x18\x1B\x1E 4\xC6fkmrsz\x01\x02\x03\x04\x07\x80\x81\x82\x83\x84t\x85\x86\xC6aegnrs\x08\t\n\x0B\x0E\x87l-Latn\x88\x89\x8A\x8B\x8Cx\x8D\x8E-Cyrl\x8F\xC6aehsvy\x01\x03\x06\x08\n\x80b\x80r\x90\0\x90\x01\x90\x02\x90\x03\xC4aeos\x02\x08\x0B\x90\x04\x80-AT\x90\x05i\x90\x06b\x90\x07\xC7elnostu\x02\x04\x05\x07\t\x0B\x90\x08\x90\t\x80\x90\n\x90\x0B\x90\x0C\x80\xC6afiory\x02\t\x0E\x10\x11\x90\r-Adlm\x90\x0E\x90\x0Fl\x90\x10\x90\x11\x80\x90\x12\xC4adlu\x01\x03\x05\x80\x90\x13\x90\x0B\x90\x14\xC7aeirsuy\x07\t\x0B\r\x10\x12\x90\x15-NE\x90\x16\x90\x17\x90\x18\x90\x19b\x90\x1A\x90\x1B\x90\x1C\xC6adgist\x01\x02\x04\x06\x08\x80\x80\x90\x1D\x90\x1E\x90\x1F\x80\xC2av\x02\x90 \x90!\xC9aegkmnouy\x02\x05\x08\x11\x13\x15\x1A\x1C\x90\"a\x90#p\x90$\x90%-Arab\x90&\x90'\x90(\x90)k\x90*\x90+\x90,\xC5biotv\x01\x03\x05\x07\x80j\x80\x90-\x90.\x90/\xC9aiklnrsty\x03\x05\x07\t\x0B\r\x0E\x10i\x900\x901\x902\x903\x904\x905\x80\x906\x907\xC4delo\x05\x07\x08s-NL\x80\x90\x18\x80\x90\x04\xC2mr\x01\x80\x908\xC5aclst\x02\x05\x07\t\x909m\x90:\x90;\x90<\x80u\x90=\xC4mouw\x02\x04\x06\x90>\x90?\x90@\x80\xCFacdhikloqruvwyz\x05\n\x0C\x0F\x11\x13\x15\x17\x19 \"$&)\x90\x06h\x90A\x90Bn\x90C\x90Dn\x90E\x90F\x90G\x90H\x90I\x90J\x8F-Latn\x8E\x90K\x90\x0F\x90:r\x90Ll\x90M\xCAaeghikorty\x02\x04\x06\x08\n\x0C\x0E\x10\x12\x90N\x90O\x90P\x90Q\x90R\x90S\x90T\x90U\x90Vv\x90,\xC5gknrz\x02\x04\x07\t\x90W\x90Xd\x90Y\x90Z\x90[i\x90\\o\x90]h\x80\xC3oru\x02\x05\x90^l\x90_e\x90`-Hans\x80\xC3ahu\x01\t\x80\x80-Hant\x90a\x80" }; - const VALUES: &'static [<icu::locale::provider::LocaleExemplarCharactersIndexV1 as icu_provider::baked::zerotrie::DynamicDataMarker>::DataStruct] = &[ - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x86\x01\0\x87\x01\0\x90\x01\0\x91\x01\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x12\0\x01\x12\0\x08\x12\0\t\x12\0\x10\x12\0\x11\x12\0\x18\x12\0\x19\x12\0 \x12\0!\x12\0(\x12\0)\x12\x000\x12\x001\x12\08\x12\09\x12\0@\x12\0A\x12\0H\x12\0I\x12\0`\x12\0a\x12\0h\x12\0i\x12\0p\x12\0q\x12\0x\x12\0y\x12\0\x80\x12\0\x81\x12\0\x88\x12\0\x89\x12\0\x90\x12\0\x91\x12\0\x98\x12\0\x99\x12\0\xA0\x12\0\xA1\x12\0\xA8\x12\0\xA9\x12\0\xB0\x12\0\xB1\x12\0\xB8\x12\0\xB9\x12\0\xC8\x12\0\xC9\x12\0\xD0\x12\0\xD1\x12\0\xD8\x12\0\xD9\x12\0\xE0\x12\0\xE1\x12\0\xE8\x12\0\xE9\x12\0\xF0\x12\0\xF1\x12\0\0\x13\0\x01\x13\0\x08\x13\0\t\x13\0\x10\x13\0\x11\x13\0 \x13\0!\x13\0(\x13\0)\x13\x000\x13\x001\x13\08\x13\09\x13\0@\x13\0A\x13\0H\x13\0I\x13\0P\x13\0Q\x13\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0I\x06\0J\x06\0K\x06\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x82\t\0\x84\t\0\x85\t\0\x8C\t\0\x8F\t\0\x91\t\0\x93\t\0\xA9\t\0\xAA\t\0\xB0\t\0\xB2\t\0\xB3\t\0\xB6\t\0\xBA\t\0\xBC\t\0\xBD\t\0\xCD\t\0\xCF\t\0\xF0\t\0\xF2\t\0") }, 49u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0J\0\0L\0\0W\0\0X\0\0[\0\0\xD1\0\0\xD2\0\0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC7\0\0\xC8\0\0\xD6\0\0\xD7\0\0\xDC\0\0\xDD\0\0\x1E\x01\0\x1F\x01\x000\x01\x001\x01\0^\x01\0_\x01\0\x8F\x01\0\x90\x01\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x10\x04\x000\x04\0\x92\x04\0\x93\x04\0\x98\x04\0\x99\x04\0\xA0\x04\0\xA1\x04\0\xA2\x04\0\xA3\x04\0\xAA\x04\0\xAB\x04\0\xAE\x04\0\xAF\x04\0\xBA\x04\0\xBB\x04\0\xD8\x04\0\xD9\x04\0\xE8\x04\0\xE9\x04\0") }, 42u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0Q\0\0R\0\0V\0\0W\0\0X\0\0Y\0\0[\0\0\xC1\0\0\xC2\0\0\xC9\0\0\xCA\0\0\xD3\0\0\xD4\0\0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0ChDhGhKhRhShThZh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x06\x04\0\x07\x04\0\x10\x04\0\x18\x04\0\x19\x04\0)\x04\0+\x04\x000\x04\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x10\x04\0*\x04\0.\x04\x000\x04\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x85\t\0\x8C\t\0\x8F\t\0\x91\t\0\x93\t\0\x99\t\0\x9A\t\0\x9E\t\0\x9F\t\0\xA9\t\0\xAA\t\0\xB1\t\0\xB2\t\0\xB3\t\0\xB6\t\0\xBA\t\0") }, 41u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE0\xA6\x95\xE0\xA7\x8D\xE0\xA6\xB7") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0Q\0\0R\0\0[\0\0") }, 25u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\x0B\t\0\r\t\0\x0E\t\0\x0F\t\0\x12\t\0\x13\t\0\x19\t\0\x1A\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0") }, 45u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE0\xA4\xA1\xE0\xA4\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x06\x01\0\x07\x01\0\x0C\x01\0\r\x01\0`\x01\0a\x01\0}\x01\0~\x01\0") }, 30u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x03\0\x05\0D\xC5\xBDLJNJ") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\x04\0\x03\x04\0\x08\x04\0\x0C\x04\0\x0F\x04\0\x19\x04\0\x1A\x04\0)\x04\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xA0\x13\0\xA1\x13\0\xA6\x13\0\xA7\x13\0\xAD\x13\0\xAE\x13\0\xB3\x13\0\xB4\x13\0\xB9\x13\0\xBA\x13\0\xBE\x13\0\xBF\x13\0\xC6\x13\0\xC7\x13\0\xCC\x13\0\xCD\x13\0\xD3\x13\0\xD4\x13\0\xDC\x13\0\xDD\x13\0\xE3\x13\0\xE4\x13\0\xE9\x13\0\xEA\x13\0\xEF\x13\0\xF0\x13\0") }, 13u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x0C\x01\0\r\x01\0X\x01\0Y\x01\0`\x01\0a\x01\0}\x01\0~\x01\0") }, 30u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0CH") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x10\x04\x000\x04\0\xAA\x04\0\xAB\x04\0\xD0\x04\0\xD1\x04\0\xD6\x04\0\xD7\x04\0\xF2\x04\0\xF3\x04\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0") }, 26u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0CHDDFFLLNGPHRHTH") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC5\0\0\xC7\0\0\xD8\0\0\xD9\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC4\0\0\xC5\0\0\xD6\0\0\xD7\0\0\xDC\0\0\xDD\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\r\t\0\x0F\t\0\x11\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0`\t\0b\t\0") }, 48u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x06\x01\0\x07\x01\0\x0C\x01\0\r\x01\0A\x01\0B\x01\0Z\x01\0[\x01\0`\x01\0a\x01\0y\x01\0z\x01\0}\x01\0~\x01\0") }, 33u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0Ch") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0J\0\0K\0\0Q\0\0R\0\0[\0\0J\x01\0K\x01\0\x86\x01\0\x87\x01\0\x89\x01\0\x8A\x01\0\x90\x01\0\x92\x01\0\x94\x01\0\x95\x01\0\xB2\x01\0\xB3\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x91\x03\0\xA2\x03\0\xA3\x03\0\xAA\x03\0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0Q\0\0R\0\0W\0\0Z\0\0[\0\0\x08\x01\0\t\x01\0\x1C\x01\0\x1D\x01\0$\x01\0%\x01\x004\x01\x005\x01\0\\\x01\0]\x01\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xD1\0\0\xD2\0\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC4\0\0\xC5\0\0\xD5\0\0\xD7\0\0\xDC\0\0\xDD\0\0`\x01\0a\x01\0}\x01\0~\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\"\x06\0#\x06\0'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x98\x06\0\x99\x06\0\xA9\x06\0\xAA\x06\0\xAF\x06\0\xB0\x06\0\xCC\x06\0\xCD\x06\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\xE9\x01\x01\xE9\x01\x1B\xE9\x01\x1C\xE9\x01") }, 2u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC4\0\0\xC6\0\0\xD6\0\0\xD7\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xD1\0\0\xD2\0\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0Ng") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC1\0\0\xC2\0\0\xC6\0\0\xC7\0\0\xCD\0\0\xCE\0\0\xD0\0\0\xD1\0\0\xD3\0\0\xD4\0\0\xD8\0\0\xD9\0\0\xDA\0\0\xDB\0\0\xDD\0\0\xDE\0\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0Q\0\0R\0\0Y\0\0Z\0\0[\0\0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0J\0\0L\0\0Q\0\0R\0\0V\0\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x85\n\0\x8C\n\0\x8D\n\0\x8E\n\0\x8F\n\0\x92\n\0\x93\n\0\xA9\n\0\xAA\n\0\xB1\n\0\xB2\n\0\xB4\n\0\xB5\n\0\xBA\n\0") }, 47u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x05\0\x06\0\x0C\0\x15\0\x1E\0\xE0\xAA\x85\xE0\xAA\x82\xE0\xAA\x85\xE0\xAA\x83\xE0\xAA\x95\xE0\xAB\x8D\xE0\xAA\xB7\xE0\xAA\x9C\xE0\xAB\x8D\xE0\xAA\x9E\xE0\xAA\xA4\xE0\xAB\x8D\xE0\xAA\xB0") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0P\0\0R\0\0V\0\0W\0\0X\0\0Y\0\0[\0\0\x81\x01\0\x82\x01\0\x8A\x01\0\x8B\x01\0\x98\x01\0\x99\x01\0\xB3\x01\0\xB4\x01\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x81\x01\0\x82\x01\0\x8A\x01\0\x8B\x01\0\x98\x01\0\x99\x01\0\xB3\x01\0\xB4\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD0\x05\0\xDA\x05\0\xDB\x05\0\xDD\x05\0\xDE\x05\0\xDF\x05\0\xE0\x05\0\xE3\x05\0\xE4\x05\0\xE5\x05\0\xE6\x05\0\xEB\x05\0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\x0C\t\0\x0F\t\0\x11\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0") }, 44u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x06\x01\0\x07\x01\0\x0C\x01\0\r\x01\0\x10\x01\0\x11\x01\0`\x01\0a\x01\0}\x01\0~\x01\0") }, 31u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x03\0\x05\0D\xC5\xBDLJNJ") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x06\x01\0\x07\x01\0\x0C\x01\0\r\x01\0A\x01\0B\x01\0`\x01\0a\x01\0}\x01\0~\x01\0") }, 31u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0CHD\xC5\xB9") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC1\0\0\xC2\0\0\xC9\0\0\xCA\0\0\xCD\0\0\xCE\0\0\xD3\0\0\xD4\0\0\xD6\0\0\xD7\0\0\xDA\0\0\xDB\0\0\xDC\0\0\xDD\0\0P\x01\0Q\x01\0p\x01\0q\x01\0") }, 35u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x02\0\x04\0\x07\0\t\0\x0B\0\r\0\x0F\0\x11\0CSDZDZSGYLYNYSZTYZS") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"1\x05\0W\x05\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0D\x1E\0E\x1E\0\xCA\x1E\0\xCB\x1E\0\xCC\x1E\0\xCD\x1E\0\xE4\x1E\0\xE5\x1E\0") }, 30u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0CHGBGHGWKPKWNWNYSH") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0U\0\0V\0\0[\0\0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x18\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0\x12\0\x14\0\x16\0\x18\0\x1A\0\x1C\0\x1E\0 \0\"\0$\0&\0(\0*\0,\0.\0BBCHDDGGHLHMHNHXIEJJMGNBNDNGNJNRNYNZRRSHSSUOZHZZ") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC1\0\0\xC2\0\0\xC6\0\0\xC7\0\0\xC9\0\0\xCA\0\0\xCD\0\0\xCE\0\0\xD0\0\0\xD1\0\0\xD3\0\0\xD4\0\0\xD6\0\0\xD7\0\0\xDA\0\0\xDB\0\0\xDD\0\0\xDF\0\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"B0\0C0\0K0\0L0\0U0\0V0\0_0\0`0\0j0\0k0\0o0\0p0\0~0\0\x7F0\0\x840\0\x850\0\x890\0\x8A0\0\x8F0\0\x900\0") }, 10u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0F\0\0G\0\0Q\0\0R\0\0V\0\0W\0\0X\0\0Y\0\0Z\0\0\xC2\0\0\xC3\0\0\xC5\0\0\xC6\0\0\xC8\0\0\xCB\0\0\xCC\0\0\xCD\0\0\xD2\0\0\xD3\0\0\xD9\0\0\xDA\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD0\x10\0\xF1\x10\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0Q\0\0R\0\0W\0\0X\0\0Y\0\0Z\0\0[\0\0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0B\0\0E\0\0L\0\0M\0\0Q\0\0R\0\0W\0\0Y\0\0Z\0\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x06\x04\0\x07\x04\0\x10\x04\x000\x04\0\x92\x04\0\x93\x04\0\x9A\x04\0\x9B\x04\0\xA2\x04\0\xA3\x04\0\xAE\x04\0\xAF\x04\0\xB0\x04\0\xB1\x04\0\xBA\x04\0\xBB\x04\0\xD8\x04\0\xD9\x04\0\xE8\x04\0\xE9\x04\0") }, 42u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0\"\x06\0'\x06\0)\x06\0*\x06\0+\x06\0,\x06\0.\x06\0/\x06\x000\x06\x001\x06\x005\x06\09\x06\0:\x06\0A\x06\0G\x06\0H\x06\0K\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\xAD\x06\0\xAE\x06\0\xAF\x06\0\xB0\x06\0\xBE\x06\0\xBF\x06\0\xC6\x06\0\xC8\x06\0\xCB\x06\0\xCC\x06\0\xD5\x06\0\xD6\x06\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x80\x17\0\x9D\x17\0\x9F\x17\0\xA3\x17\0\xA5\x17\0\xA8\x17\0\xA9\x17\0\xB2\x17\0\xB3\x17\0\xB4\x17\0") }, 46u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x85\x0C\0\x8D\x0C\0\x8E\x0C\0\x91\x0C\0\x92\x0C\0\xA9\x0C\0\xAA\x0C\0\xB4\x0C\0\xB5\x0C\0\xBA\x0C\0\xDE\x0C\0\xDF\x0C\0\xE0\x0C\0\xE2\x0C\0") }, 52u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"11\x0021\x0041\x0051\x0071\081\091\0:1\0A1\0C1\0E1\0F1\0G1\0I1\0J1\0O1\0") }, 14u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\x0E\t\0\x0F\t\0\x12\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0") }, 48u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC7\0\0\xC8\0\0\xCA\0\0\xCB\0\0\xCE\0\0\xCF\0\0\xDB\0\0\xDC\0\0^\x01\0_\x01\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x10\x04\x000\x04\0\xA2\x04\0\xA3\x04\0\xAE\x04\0\xAF\x04\0\xE8\x04\0\xE9\x04\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x81\x0E\0\x83\x0E\0\x84\x0E\0\x85\x0E\0\x87\x0E\0\x89\x0E\0\x8A\x0E\0\x8B\x0E\0\x8D\x0E\0\x8E\x0E\0\x94\x0E\0\x98\x0E\0\x99\x0E\0\xA0\x0E\0\xA1\x0E\0\xA4\x0E\0\xA5\x0E\0\xA6\x0E\0\xA7\x0E\0\xA8\x0E\0\xAA\x0E\0\xAC\x0E\0\xAD\x0E\0\xAF\x0E\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x06\0\x06\0\x0C\0\x12\0\x18\0\x1E\0\xE0\xBA\xAB\xE0\xBA\x87\xE0\xBA\xAB\xE0\xBA\x8D\xE0\xBA\xAB\xE0\xBA\x99\xE0\xBA\xAB\xE0\xBA\xA1\xE0\xBA\xAB\xE0\xBA\xA5\xE0\xBA\xAB\xE0\xBA\xA7") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0Q\0\0R\0\0W\0\0Y\0\0[\0\0\x04\x01\0\x05\x01\0\x0C\x01\0\r\x01\0\x16\x01\0\x17\x01\0\x18\x01\0\x19\x01\0.\x01\0/\x01\0`\x01\0a\x01\0j\x01\0k\x01\0r\x01\0s\x01\0}\x01\0~\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\0\x01\0\x01\x01\0\x0C\x01\0\r\x01\0\x12\x01\0\x13\x01\0\"\x01\0#\x01\0*\x01\0+\x01\x006\x01\x007\x01\0;\x01\0<\x01\0E\x01\0F\x01\0`\x01\0a\x01\0j\x01\0k\x01\0}\x01\0~\x01\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\t\0\r\t\0\x0F\t\0\x11\t\0\x13\t\0\x19\t\0\x1A\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0<\t\0=\t\0a\t\0b\t\0") }, 46u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x07\0\x06\0\x0C\0\x15\0\x1E\0$\0-\0\xE0\xA4\x85\xE0\xA4\x82\xE0\xA4\x85\xE0\xA4\x83\xE0\xA4\x95\xE0\xA5\x8D\xE0\xA4\xB7\xE0\xA4\x9C\xE0\xA5\x8D\xE0\xA4\x9E\xE0\xA4\xA1\xE0\xA4\x82\xE0\xA4\xA4\xE0\xA5\x8D\xE0\xA4\xB0\xE0\xA4\xB6\xE0\xA5\x8D\xE0\xA4\xB0") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0B\0\0E\0\0F\0\0H\0\0J\0\0K\0\0L\0\0M\0\0Q\0\0R\0\0S\0\0T\0\0V\0\0W\0\0X\0\0") }, 13u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x03\x04\0\x04\x04\0\x05\x04\0\x06\x04\0\x08\x04\0\x0B\x04\0\x0C\x04\0\r\x04\0\x0F\x04\0\x19\x04\0\x1A\x04\0)\x04\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\r\0\x0C\r\0\x0E\r\0\x11\r\0\x12\r\0)\r\0*\r\0:\r\0") }, 49u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x10\x04\x000\x04\0\xAE\x04\0\xAF\x04\0\xE8\x04\0\xE9\x04\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\t\0\x04\t\0\x05\t\0\r\t\0\x0F\t\0\x12\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0=\t\0>\t\0E\t\0F\t\0M\t\0N\t\0P\t\0Q\t\0\r \0\x0E \0") }, 54u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\n\x01\0\x0B\x01\0 \x01\0!\x01\0&\x01\0'\x01\0{\x01\0|\x01\0") }, 30u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x03\0G\xC4\xA6IE*") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x10\0\"\x10\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\x0B\0\x0C\x0B\0\x0F\x0B\0\x11\x0B\0\x13\x0B\0)\x0B\0*\x0B\x001\x0B\x002\x0B\x004\x0B\x006\x0B\0:\x0B\0_\x0B\0`\x0B\0q\x0B\0r\x0B\0") }, 46u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE0\xAC\x95\xE0\xAD\x8D\xE0\xAC\xB7") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\n\0\x06\n\0\x15\n\0)\n\0*\n\x001\n\x002\n\x003\n\x005\n\x006\n\08\n\0:\n\0\\\n\0]\n\0r\n\0t\n\0") }, 35u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE0\xA8\xB8\xE0\xA8\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0Q\0\0R\0\0X\0\0Y\0\0[\0\0") }, 23u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0CH") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xD3\0\0\xD4\0\0\x06\x01\0\x07\x01\0A\x01\0B\x01\0Z\x01\0[\x01\0y\x01\0z\x01\0{\x01\0|\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0#\x06\0'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0|\x06\0}\x06\0~\x06\0\x7F\x06\0\x81\x06\0\x82\x06\0\x85\x06\0\x87\x06\0\x89\x06\0\x8A\x06\0\x93\x06\0\x94\x06\0\x96\x06\0\x97\x06\0\x98\x06\0\x99\x06\0\x9A\x06\0\x9B\x06\0\xA9\x06\0\xAA\x06\0\xAB\x06\0\xAC\x06\0\xBC\x06\0\xBD\x06\0\xCC\x06\0\xCD\x06\0") }, 42u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0B\0\0H\0\0J\0\0K\0\0O\0\0P\0\0V\0\0W\0\0X\0\0Y\0\0Z\0\0\xD1\0\0\xD2\0\0") }, 16u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0CHLl") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC0\0\0\xC1\0\0\xC8\0\0\xCA\0\0\xCC\0\0\xCD\0\0\xD2\0\0\xD3\0\0\xD9\0\0\xDA\0\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC2\0\0\xC3\0\0\xCE\0\0\xCF\0\0\x02\x01\0\x03\x01\0\x18\x02\0\x19\x02\0\x1A\x02\0\x1B\x02\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x10\x04\0*\x04\0+\x04\0,\x04\0-\x04\x000\x04\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x10\x04\0\x12\x04\0\x13\x04\0\x15\x04\0\x18\x04\0$\x04\0%\x04\0&\x04\0'\x04\0(\x04\0+\x04\0,\x04\0-\x04\0.\x04\0\x94\x04\0\x95\x04\0\xA4\x04\0\xA5\x04\0\xAE\x04\0\xAF\x04\0\xBA\x04\0\xBB\x04\0\xE8\x04\0\xE9\x04\0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x04\0\xD0\x94\xD1\x8C\xD0\x9D\xD1\x8C") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0") }, 26u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0TZ") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0K\0\0L\0\0W\0\0Z\0\0[\0\0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0J\x06\0K\x06\0z\x06\0|\x06\0}\x06\0\x81\x06\0\x83\x06\0\x85\x06\0\x86\x06\0\x88\x06\0\x8A\x06\0\x8B\x06\0\x8C\x06\0\x8E\x06\0\x8F\x06\0\x90\x06\0\x99\x06\0\x9A\x06\0\xA6\x06\0\xA7\x06\0\xA9\x06\0\xAB\x06\0\xAF\x06\0\xB0\x06\0\xB1\x06\0\xB2\x06\0\xB3\x06\0\xB4\x06\0\xBB\x06\0\xBC\x06\0\xBE\x06\0\xBF\x06\0") }, 50u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x04\0\xD8\xAC\xDA\xBE\xDA\xAF\xDA\xBE") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x04\x10\0\x05\x10\0\x10\x10\0\x12\x10\0\x15\x10\0\x16\x10\0\x19\x10\0\x1F\x10\0\"\x10\0#\x10\0u\x10\0y\x10\0z\x10\0\x82\x10\0\x9E\x10\0\xA0\x10\0\xE0\xA9\0\xE1\xA9\0\xE3\xA9\0\xE4\xA9\0a\xAA\0b\xAA\0j\xAA\0k\xAA\0n\xAA\0o\xAA\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x85\r\0\x8E\r\0\x91\r\0\x97\r\0\x9A\r\0\xA6\r\0\xA7\r\0\xB2\r\0\xB3\r\0\xBC\r\0\xBD\r\0\xBE\r\0\xC0\r\0\xC7\r\0") }, 55u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC4\0\0\xC5\0\0\xD4\0\0\xD5\0\0\x0C\x01\0\r\x01\0\x0E\x01\0\x0F\x01\0=\x01\0>\x01\0`\x01\0a\x01\0d\x01\0e\x01\0}\x01\0~\x01\0") }, 34u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0CH") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\x06\x01\0\x07\x01\0\x0C\x01\0\r\x01\0\x10\x01\0\x11\x01\0`\x01\0a\x01\0}\x01\0~\x01\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"B\0\0E\0\0F\0\0I\0\0J\0\0O\0\0Q\0\0U\0\0W\0\0Z\0\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0W\0\0X\0\0[\0\0\xC7\0\0\xC8\0\0\xCB\0\0\xCC\0\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0DHGJLLNJRRSHTHXHZH") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC9\0\0\xCA\0\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x10\x07\0\x11\x07\0\x12\x07\0\x14\x07\0\x15\x07\0\x1C\x07\0\x1D\x07\0\x1E\x07\0\x1F\x07\0$\x07\0%\x07\0'\x07\0(\x07\0-\x07\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xD4\0\0\xD5\0\0\x06\x01\0\x07\x01\0A\x01\0B\x01\0C\x01\0D\x01\0L\x01\0M\x01\0Z\x01\0[\x01\0y\x01\0z\x01\0{\x01\0|\x01\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x85\x0B\0\x8B\x0B\0\x8E\x0B\0\x91\x0B\0\x92\x0B\0\x96\x0B\0\x99\x0B\0\x9B\x0B\0\x9E\x0B\0\xA0\x0B\0\xA3\x0B\0\xA5\x0B\0\xA8\x0B\0\xAB\x0B\0\xAE\x0B\0\xB6\x0B\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\x0C\0\x0C\x0C\0\x0E\x0C\0\x11\x0C\0\x12\x0C\0)\x0C\0*\x0C\x004\x0C\x005\x0C\0:\x0C\0`\x0C\0a\x0C\0") }, 49u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x10\x04\0&\x04\0'\x04\0)\x04\0*\x04\0+\x04\0-\x04\x000\x04\0\x92\x04\0\x93\x04\0\x9A\x04\0\x9B\x04\0\xB2\x04\0\xB3\x04\0\xB6\x04\0\xB7\x04\0\xE2\x04\0\xE3\x04\0\xEE\x04\0\xEF\x04\0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x0E\0/\x0E\0") }, 46u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x12\0\x01\x12\0\x08\x12\0\t\x12\0\x10\x12\0\x11\x12\0\x18\x12\0\x19\x12\0 \x12\0!\x12\0(\x12\0)\x12\x000\x12\x001\x12\08\x12\09\x12\0@\x12\0A\x12\0H\x12\0I\x12\0P\x12\0Q\x12\0X\x12\0Y\x12\0`\x12\0a\x12\0h\x12\0i\x12\0p\x12\0q\x12\0x\x12\0y\x12\0\x80\x12\0\x81\x12\0\x88\x12\0\x89\x12\0\x90\x12\0\x91\x12\0\x98\x12\0\x99\x12\0\xA0\x12\0\xA1\x12\0\xA8\x12\0\xA9\x12\0\xB0\x12\0\xB1\x12\0\xB8\x12\0\xB9\x12\0\xC0\x12\0\xC1\x12\0\xC8\x12\0\xC9\x12\0\xD0\x12\0\xD1\x12\0\xD8\x12\0\xD9\x12\0\xE0\x12\0\xE1\x12\0\xE8\x12\0\xE9\x12\0\xF0\x12\0\xF1\x12\0\0\x13\0\x01\x13\0\x08\x13\0\t\x13\0\x10\x13\0\x11\x13\0 \x13\0!\x13\0(\x13\0)\x13\x000\x13\x001\x13\08\x13\09\x13\0@\x13\0A\x13\0H\x13\0I\x13\0P\x13\0Q\x13\0") }, 41u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0Q\0\0R\0\0V\0\0W\0\0X\0\0Y\0\0[\0\0\xC4\0\0\xC5\0\0\xC7\0\0\xC8\0\0\xD6\0\0\xD7\0\0\xDC\0\0\xDE\0\0G\x01\0H\x01\0^\x01\0_\x01\0}\x01\0~\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0B\0\0E\0\0G\0\0H\0\0J\0\0K\0\0Q\0\0S\0\0W\0\0\xBB\x02\0\xBC\x02\0") }, 16u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0NG") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC7\0\0\xC8\0\0\xD6\0\0\xD7\0\0\xDC\0\0\xDD\0\x000\x01\x001\x01\0^\x01\0_\x01\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x04\0\x02\x04\0\x10\x04\x000\x04\0\x96\x04\0\x97\x04\0\xA2\x04\0\xA3\x04\0\xAE\x04\0\xAF\x04\0\xBA\x04\0\xBB\x04\0\xD8\x04\0\xD9\x04\0\xE8\x04\0\xE9\x04\0") }, 39u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"'\x06\0)\x06\0*\x06\0+\x06\0,\x06\0-\x06\0.\x06\x000\x06\x001\x06\x005\x06\0:\x06\0;\x06\0A\x06\0G\x06\0H\x06\0K\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x98\x06\0\x99\x06\0\xAD\x06\0\xAE\x06\0\xAF\x06\0\xB0\x06\0\xBE\x06\0\xBF\x06\0\xC6\x06\0\xC9\x06\0\xCB\x06\0\xCC\x06\0\xD0\x06\0\xD1\x06\0\xD5\x06\0\xD6\x06\0") }, 32u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0\xD8\xA6\xD8\xA7\xD8\xA6\xD9\x87\xD8\xA6\xD9\x88\xD8\xA6\xD9\x89\xD8\xA6\xDB\x86\xD8\xA6\xDB\x87\xD8\xA6\xDB\x88\xD8\xA6\xDB\x90") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x04\x04\0\x05\x04\0\x06\x04\0\x08\x04\0\x10\x04\0*\x04\0.\x04\x000\x04\0\x90\x04\0\x91\x04\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(zerovec::ZeroVec::new(), 0u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0\"\x06\0'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0G\x06\0H\x06\0I\x06\0y\x06\0z\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x88\x06\0\x89\x06\0\x91\x06\0\x92\x06\0\x98\x06\0\x99\x06\0\xA9\x06\0\xAA\x06\0\xAF\x06\0\xB0\x06\0\xBE\x06\0\xBF\x06\0\xC1\x06\0\xC2\x06\0\xCC\x06\0\xCD\x06\0\xD2\x06\0\xD3\x06\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0W\0\0X\0\0[\0\0") }, 24u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x04\0\x02\0\x05\0\x08\0ChG\xCA\xBBO\xCA\xBBSh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0\xC2\0\0\xC3\0\0\xCA\0\0\xCB\0\0\xD4\0\0\xD5\0\0\x02\x01\0\x03\x01\0\x10\x01\0\x11\x01\0\xA0\x01\0\xA1\x01\0\xAF\x01\0\xB0\x01\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0[\0\0J\x01\0K\x01\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0Q\0\0R\0\0V\0\0W\0\0X\0\0Y\0\0Z\0\0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"A\0\0C\0\0D\0\0F\0\0G\0\0H\0\0I\0\0J\0\0K\0\0L\0\0M\0\0O\0\0P\0\0Q\0\0R\0\0V\0\0W\0\0Z\0\0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0N\0\x02N\0\x08N\0\tN\0\rN\0\x0EN\0\x14N\0\x15N\0\x1EN\0\x1FN\0&N\0'N\x002N\x003N\0XN\0YN\0~N\0\x7FN\0\x82N\0\x83N\0\xADN\0\xAEN\0\x80P\0\x81P\0\xCEP\0\xCFP\0\xF5P\0\xF6P\0\x10Q\0\x11Q\0\x1FQ\0 Q\x003Q\x004Q\x007Q\08Q\0;Q\0<Q\0\xE2S\0\xE3S\0\xB4V\0\xB5V\0\xCCV\0\xCDV\0\xD1V\0\xD2V\0\xF3^\0\xF4^\0") }, 25u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0N\0\x01N\0(N\0)N\x006N\x007N\0?N\0@N\0YN\0ZN\0\x85N\0\x86N\0\x8CN\0\x8DN\0\xA0N\0\xA1N\0\xBAN\0\xBBN\0?Q\0@Q\0eQ\0fQ\0kQ\0lQ\0\x82Q\0\x83Q\0\x96Q\0\x97Q\0\xABQ\0\xACQ\0\xE0Q\0\xE1Q\0\xF5Q\0\xF6Q\0\0R\0\x01R\0\x9BR\0\x9CR\0\xF9R\0\xFAR\0\x15S\0\x16S\0\x1AS\0\x1BS\08S\09S\0AS\0BS\0\\S\0]S\0iS\0jS\0\x82S\0\x83S\0\xB6S\0\xB7S\0\xC8S\0\xC9S\0\xE3S\0\xE4S\0\xD7V\0\xD8V\0\x1FW\0 W\0\xEBX\0\xECX\0\x02Y\0\x03Y\0\nY\0\x0BY\0\x15Y\0\x16Y\0'Y\0(Y\0sY\0tY\0P[\0Q[\0\x80[\0\x81[\0\xF8[\0\xF9[\0\x0F\\\0\x10\\\0\"\\\0#\\\08\\\09\\\0n\\\0o\\\0q\\\0r\\\0\xDB]\0\xDC]\0\xE5]\0\xE6]\0\xF1]\0\xF2]\0\xFE]\0\xFF]\0r^\0s^\0z^\0{^\0\x7F^\0\x80^\0\xF4^\0\xF5^\0\xFE^\0\xFF^\0\x0B_\0\x0C_\0\x13_\0\x14_\0P_\0Q_\0a_\0b_\0s_\0t_\0\xC3_\0\xC4_\0\x08b\0\tb\x006b\x007b\0Kb\0Lb\0/e\x000e\x004e\x005e\0\x87e\0\x88e\0\x97e\0\x98e\0\xA4e\0\xA5e\0\xB9e\0\xBAe\0\xE0e\0\xE1e\0\xE5e\0\xE6e\0\xF0f\0\xF1f\0\x08g\0\tg\0(g\0)g\0 k\0!k\0bk\0ck\0yk\0zk\0\xB3k\0\xB4k\0\xCBk\0\xCCk\0\xD4k\0\xD5k\0\xDBk\0\xDCk\0\x0Fl\0\x10l\0\x14l\0\x15l\x004l\x005l\0kp\0lp\0*r\0+r\x006r\x007r\0;r\0<r\0?r\0@r\0Gr\0Hr\0Yr\0Zr\0[r\0\\r\0\xACr\0\xADr\0\x84s\0\x85s\0\x89s\0\x8As\0\xDCt\0\xDDt\0\xE6t\0\xE7t\0\x18u\0\x19u\0\x1Fu\0 u\0(u\0)u\x000u\x001u\0\x8Bu\0\x8Cu\0\x92u\0\x93u\0vv\0wv\0}v\0~v\0\xAEv\0\xAFv\0\xBFv\0\xC0v\0\xEEv\0\xEFv\0\xDBw\0\xDCw\0\xE2w\0\xE3w\0\xF3w\0\xF4w\0:y\0;y\0\xB8y\0\xB9y\0\xBEy\0\xBFy\0tz\0uz\0\xCBz\0\xCCz\0\xF9z\0\xFAz\0s|\0t|\0\xF8|\0\xF9|\x006\x7F\x007\x7F\0Q\x7F\0R\x7F\0\x8A\x7F\0\x8B\x7F\0\xBD\x7F\0\xBE\x7F\0\x01\x80\0\x02\x80\0\x0C\x80\0\r\x80\0\x12\x80\0\x13\x80\x003\x80\x004\x80\0\x7F\x80\0\x80\x80\0\x89\x80\0\x8A\x80\0\xE3\x81\0\xE4\x81\0\xEA\x81\0\xEB\x81\0\xF3\x81\0\xF4\x81\0\xFC\x81\0\xFD\x81\0\x0C\x82\0\r\x82\0\x1B\x82\0\x1C\x82\0\x1F\x82\0 \x82\0n\x82\0o\x82\0r\x82\0s\x82\0x\x82\0y\x82\0M\x86\0N\x86\0k\x86\0l\x86\0@\x88\0A\x88\0L\x88\0M\x88\0c\x88\0d\x88\0~\x89\0\x7F\x89\0\x8B\x89\0\x8C\x89\0\xD2\x89\0\xD3\x89\0\0\x8A\0\x01\x8A\x007\x8C\08\x8C\0F\x8C\0G\x8C\0U\x8C\0V\x8C\0x\x8C\0y\x8C\0\x9D\x8C\0\x9E\x8C\0d\x8D\0e\x8D\0p\x8D\0q\x8D\0\xB3\x8D\0\xB4\x8D\0\xAB\x8E\0\xAC\x8E\0\xCA\x8E\0\xCB\x8E\0\x9B\x8F\0\x9C\x8F\0\xB0\x8F\0\xB1\x8F\0\xB5\x8F\0\xB6\x8F\0\x91\x90\0\x92\x90\0I\x91\0J\x91\0\xC6\x91\0\xC7\x91\0\xCC\x91\0\xCD\x91\0\xD1\x91\0\xD2\x91\0w\x95\0x\x95\0\x80\x95\0\x81\x95\0\x1C\x96\0\x1D\x96\0\xB6\x96\0\xB7\x96\0\xB9\x96\0\xBA\x96\0\xE8\x96\0\xE9\x96\0Q\x97\0R\x97\0^\x97\0_\x97\0b\x97\0c\x97\0i\x97\0j\x97\0\xCB\x97\0\xCC\x97\0\xED\x97\0\xEE\x97\0\xF3\x97\0\xF4\x97\0\x01\x98\0\x02\x98\0\xA8\x98\0\xA9\x98\0\xDB\x98\0\xDC\x98\0\xDF\x98\0\xE0\x98\0\x96\x99\0\x97\x99\0\x99\x99\0\x9A\x99\0\xAC\x99\0\xAD\x99\0\xA8\x9A\0\xA9\x9A\0\xD8\x9A\0\xD9\x9A\0\xDF\x9A\0\xE0\x9A\0%\x9B\0&\x9B\0/\x9B\x000\x9B\x002\x9B\x003\x9B\0<\x9B\0=\x9B\0Z\x9B\0[\x9B\0\xE5\x9C\0\xE6\x9C\0u\x9E\0v\x9E\0\x7F\x9E\0\x80\x9E\0\xA5\x9E\0\xA6\x9E\0\xBB\x9E\0\xBC\x9E\0\xC3\x9E\0\xC4\x9E\0\xCD\x9E\0\xCE\x9E\0\xD1\x9E\0\xD2\x9E\0\xF9\x9E\0\xFA\x9E\0\xFD\x9E\0\xFE\x9E\0\x0E\x9F\0\x0F\x9F\0\x13\x9F\0\x14\x9F\0 \x9F\0!\x9F\0;\x9F\0<\x9F\0J\x9F\0K\x9F\0R\x9F\0S\x9F\0\x8D\x9F\0\x8E\x9F\0\x9C\x9F\0\x9D\x9F\0\xA0\x9F\0\xA1\x9F\0") }, 214u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - ]; - unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleExemplarCharactersIndexV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleExemplarCharactersIndexV1>, icu_provider::DataError> { - let mut metadata = icu_provider::DataResponseMetadata::default(); - let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_INDEX_V1, req.id, req.metadata.attributes_prefix_match) { - payload - } else { - const FALLBACKER: icu::locale::fallback::LocaleFallbackerWithConfig<'static> = icu::locale::fallback::LocaleFallbacker::new().for_config(<icu::locale::provider::LocaleExemplarCharactersIndexV1 as icu_provider::DataMarker>::INFO.fallback_config); - let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); - loop { - if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_INDEX_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { - metadata.locale = Some(fallback_iterator.take()); - break payload; - } - if fallback_iterator.get().is_unknown() { - return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(<icu::locale::provider::LocaleExemplarCharactersIndexV1 as icu_provider::DataMarker>::INFO, req)); - } - fallback_iterator.step(); - } - }; - Ok(icu_provider::DataResponse { payload, metadata }) - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_exemplar_characters_index_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleExemplarCharactersIndexV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok(icu_provider::baked::DataStore::iter(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_INDEX_V1).collect()) - } - } - }; - ($ provider : ty , DRY) => {}; - ($ provider : ty , DRY , ITER) => { - __impl_locale_exemplar_characters_index_v1!($provider, ITER); - }; -} -#[doc(inline)] -pub use __impl_locale_exemplar_characters_index_v1 as impl_locale_exemplar_characters_index_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_main_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_main_v1.rs.data deleted file mode 100644 index a3e80162ef54..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_main_v1.rs.data +++ /dev/null @@ -1,1233 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleExemplarCharactersMainV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 896B for the lookup data structure (181 data identifiers) -/// * 74297B[^1] for the actual data (166 unique structs) -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `icu_provider/baked` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_exemplar_characters_main_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - const DATA_LOCALE_EXEMPLAR_CHARACTERS_MAIN_V1: icu_provider::baked::zerotrie::Data<icu::locale::provider::LocaleExemplarCharactersMainV1> = { - const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xE1zabcdefghijklmnopqrstuvwxyz\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x14Gd{\xA1\xC1\xD4\xF5\x11\x19v\x90\xB8\xD8\xE4\x03\x06\x1B\x82\xAF\xCB\xD9\xDC\xE5\xFF\xC6fkmrsz\x01\x02\x03\x04\x07\x80\x81\x82\x83\x84t\x85\x86\xC9aeghlnrsu\x08\t\x0C\x0E\x10\x11\x15\x1E\x87l-Latn\x88\x89\x8Ac\x8Bo\x8Co\x8D\x8E\x8Fx\x90\0\x90\x01-Cyrl\x90\x02a\x90\x03\xC6aehsvy\x02\x05\x08\r\x0F\x90\x04b\x90\x05r\x90\x06\x90\x07w\x90\x08\x90\t\x90\n\xC4aeos\x02\t\x0C\x90\x0B\x90\x0C-CH\x90\ri\x90\x0Eb\x90\x0F\xC7elnostu\x02\x0E\x10\x12\x14\x16\x90\x10\x90\x11-polyton\x90\x12\x90\x13\x90\x14\x90\x15\x90\x16\x90\x17\xC6afiory\x02\t\x0E\x10\x12\x90\x18-Adlm\x90\x19\x90\x1Al\x90\x1B\x90\x1C\x90\x1D\x90\x1E\xC4adlu\x05\x07\t\x90\x1Fa\x90 \x90!\x90\"\x90#\xC8aeirstuy\x02\x04\x06\x08\x0B\r\x0F\x90$\x90%\x90&\x90\x01b\x90'\x90(\x90)\x90*\xC7adegist\x02\x04\x06\x08\n\x0C\x90\x13\x90\x13\x90+\x90,\x90-\x90.\x90/\xC2av\x02\x900\x901\xCBaegkmnosuxy\x02\x05\x08\x11\x13\x15!*,E\x902a\x903p\x904\x905-Arab\x906\x907\x908\x909k\x90:-Latn\x90;\x90<-Deva\x90=\x90>v\x90?-\xC3DOT\x05\neva\x90@rya\x90Aelu\x90B\x90C\xC6bimotv\x02\x05\x08\n\x0C\x90Dj\x90Eo\x90\x13\x90F\x90G\x90H\xC9aiklnrsty\x03\x05\x07\t\x0E\x10\x12\x14i\x90I\x90J\x90K\x90L\x90Mi\x90N\x90O\x90\x13\x90P\x90Q\xC6deloqs\x08\n\x0C\x0E\x11s\x90R-NL\x90\x13\x90&\x90S\x90To\x90Uo\x90V\xC3cmr\x02\x04\x90W\x90\x13\x90X\xC6aclmst\x02\x05\x07\n\x11\x90Ym\x90Z\x90[s\x90\\\x90]-PK\x90^\x90_u\x90`\xC5amouw\x03\x05\x07\tj\x90a\x90/\x90b\x90c\x90\x13\xD0acdhikloqrtuvwyz\n\x0F\x18\x1B\x1D\x1F!#%.024AD\x90d\xC2ht\x02\x90e\x90f\x90gn\x90h\x90i-Deva\x90jn\x90k\x90l\x90m\x90n\x90o\x90p\x90\x02-Latn\x90\x01\x90q\x90r\x90s\x90t-\xC2CK\x03D\x90uE\x90\x13r\x90vl\x90w\xCBaeghiknorty\x02\x04\x06\x08\n\x0C\x0E\x10\x12\x14\x90x\x90y\x90z\x90{\x90|\x90}\x90~\x90\x7F\x91\0\x91\x01v\x91\x02\xC5gknrz\x02\x04\x07\t\x91\x03\x91\x04d\x91\x05\x91\x06\x91\x07-Cyrl\x91\x08\xC3eim\x03\x05c\x91\t\x91\nw\x91\x0Bo\x91\x0C\xC2hn\x02\x90\x13r\x91\r\xC3oru\x07\n\x91\x0E-BJ\x91\x0Fl\x91\x10e\x91\x11-Hans\x91\x12\xC3ahu\x02\x0B\x90\x13\x91\x13-Hant\x91\x14\x91\x15" }; - const VALUES: &'static [<icu::locale::provider::LocaleExemplarCharactersMainV1 as icu_provider::baked::zerotrie::DynamicDataMarker>::DataStruct] = &[ - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE3\0\0\xE8\0\0\xEC\0\0\xEE\0\0\xF0\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xFB\0\0\xFC\0\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0j\0\0k\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0T\x02\0U\x02\0[\x02\0\\\x02\0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x12\0\x07\x12\0\x08\x12\0G\x12\0H\x12\0I\x12\0J\x12\0N\x12\0`\x12\0\x87\x12\0\x88\x12\0\x89\x12\0\x8A\x12\0\x8E\x12\0\x90\x12\0\xAF\x12\0\xB0\x12\0\xB1\x12\0\xB2\x12\0\xB6\x12\0\xB8\x12\0\xBF\x12\0\xC8\x12\0\xCF\x12\0\xD0\x12\0\xD7\x12\0\xD8\x12\0\xEF\x12\0\xF0\x12\0\xF8\x12\0\0\x13\0\x0F\x13\0\x10\x13\0\x11\x13\0\x12\x13\0\x16\x13\0 \x13\0G\x13\0H\x13\0X\x13\0") }, 282u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0;\x06\0A\x06\0S\x06\0p\x06\0q\x06\0") }, 45u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x81\t\0\x84\t\0\x85\t\0\x8C\t\0\x8F\t\0\x91\t\0\x93\t\0\xA9\t\0\xAA\t\0\xB0\t\0\xB2\t\0\xB3\t\0\xB6\t\0\xBA\t\0\xBC\t\0\xBD\t\0\xBE\t\0\xC4\t\0\xC7\t\0\xC9\t\0\xCB\t\0\xCE\t\0\xF0\t\0\xF2\t\0") }, 59u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x04\0\t\0\x0F\0\x15\0\xE0\xA6\x95\xE0\xA7\x8D\xE0\xA6\xB7\xE0\xA6\xA1\xE0\xA6\xBC\xE0\xA6\xA2\xE0\xA6\xBC\xE0\xA6\xAF\xE0\xA6\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0j\0\0l\0\0w\0\0x\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0%\x1E\0&\x1E\x007\x1E\08\x1E\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0w\0\0x\0\0{\0\0\xE7\0\0\xE8\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0\x1F\x01\0 \x01\x000\x01\x002\x01\0_\x01\0`\x01\0Y\x02\0Z\x02\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0\x93\x04\0\x94\x04\0\x99\x04\0\x9A\x04\0\xA1\x04\0\xA2\x04\0\xA3\x04\0\xA4\x04\0\xAB\x04\0\xAC\x04\0\xAF\x04\0\xB0\x04\0\xBB\x04\0\xBC\x04\0\xD9\x04\0\xDA\x04\0\xE9\x04\0\xEA\x04\0") }, 42u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xF3\0\0\xF4\0\0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0chdhghkhrhshthzh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\08\x04\09\x04\0I\x04\0K\x04\0P\x04\0Q\x04\0R\x04\0V\x04\0W\x04\0^\x04\0_\x04\0") }, 32u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x04\0\xD0\xB4\xD0\xB6\xD0\xB4\xD0\xB7") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0K\x04\0L\x04\0M\x04\0N\x04\0P\x04\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x02\t\0\x03\t\0\x04\t\0\x05\t\0\x0C\t\0\x0F\t\0\x11\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0>\t\0D\t\0E\t\0F\t\0G\t\0I\t\0K\t\0N\t\0") }, 58u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x15\t\0\x19\t\0\x1A\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0<\t\0=\t\0>\t\0D\t\0E\t\0F\t\0G\t\0I\t\0K\t\0N\t\0") }, 48u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0d\0\0e\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xE0\0\0\xE3\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xEF\0\0\xF2\0\0\xF5\0\0\xF9\0\0\xFC\0\0D\x01\0E\x01\0K\x01\0L\x01\0\xDD\x01\0\xDE\x01\0\xF9\x01\0\xFA\x01\0T\x02\0U\x02\0V\x02\0W\x02\0[\x02\0\\\x02\0i\x02\0j\x02\0\x8A\x02\0\x8B\x02\0?\x1E\0@\x1E\0") }, 46u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x17\0\x02\0\x04\0\x07\0\t\0\x0B\0\x0E\0\x12\0\x16\0\x1A\0\x1E\0\"\0&\0*\0.\x002\x006\0:\0>\0B\0F\0J\0N\0gbkpm\xCC\x80nysh\xC5\x8Bm\xC5\x8B\xCC\x80\xC5\x8B\xCC\x81\xC7\x9D\xCC\x80\xC7\x9D\xCC\x81\xC7\x9D\xCC\x82\xC9\x94\xCC\x80\xC9\x94\xCC\x81\xC9\x94\xCC\x82\xC9\x9B\xCC\x80\xC9\x9B\xCC\x81\xC9\x9B\xCC\x82\xC9\xA9\xCC\x80\xC9\xA9\xCC\x81\xC9\xA9\xCC\x82\xCA\x8A\xCC\x80\xCA\x8A\xCC\x81\xCA\x8A\xCC\x82") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x81\t\0\x84\t\0\x85\t\0\x8D\t\0\x8F\t\0\x91\t\0\x93\t\0\xA9\t\0\xAA\t\0\xB1\t\0\xB2\t\0\xB3\t\0\xB6\t\0\xBA\t\0\xBC\t\0\xC5\t\0\xC7\t\0\xC9\t\0\xCB\t\0\xCF\t\0\xD7\t\0\xD8\t\0\xE0\t\0\xE4\t\0\xFA\t\0\xFB\t\0") }, 68u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x04\0\t\0\x0F\0\x15\0\xE0\xA6\x95\xE0\xA7\x8D\xE0\xA6\xB7\xE0\xA6\xA1\xE0\xA6\xBC\xE0\xA6\xA2\xE0\xA6\xBC\xE0\xA6\xAF\xE0\xA6\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0{\0\0\xEA\0\0\xEB\0\0\xF1\0\0\xF2\0\0\xF9\0\0\xFA\0\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0chc\xCA\xBCh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x03\t\0\x05\t\0\x0B\t\0\r\t\0\x0E\t\0\x0F\t\0\x12\t\0\x13\t\0\x19\t\0\x1A\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0<\t\0=\t\0>\t\0D\t\0E\t\0F\t\0G\t\0J\t\0K\t\0N\t\0") }, 61u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE0\xA4\xA1\xE0\xA4\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0z\0\0{\0\0\x07\x01\0\x08\x01\0\r\x01\0\x0E\x01\0\x11\x01\0\x12\x01\0a\x01\0b\x01\0~\x01\0\x7F\x01\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x03\0\x05\0d\xC5\xBEljnj") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\09\x04\0:\x04\0I\x04\0R\x04\0S\x04\0X\x04\0\\\x04\0_\x04\0`\x04\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0\xAF\x04\0\xB0\x04\0\xBB\x04\0\xBC\x04\0\xE9\x04\0\xEA\x04\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xB7\0\0\xB8\0\0\xE0\0\0\xE1\0\0\xE7\0\0\xEA\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF0\0\0\xF2\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0f\0\0g\0\0j\0\0k\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0") }, 19u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF8\x13\0\xFD\x13\0p\xAB\0\xC0\xAB\0") }, 85u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFE\0\0\r\x01\0\x0E\x01\0\x0F\x01\0\x10\x01\0\x1B\x01\0\x1C\x01\0H\x01\0I\x01\0Y\x01\0Z\x01\0a\x01\0b\x01\0e\x01\0f\x01\0o\x01\0p\x01\0~\x01\0\x7F\x01\0") }, 41u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0ch") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x14\0\x02\x14\0\x03\x14\0\x07\x14\0\n\x14\0\x0C\x14\0\r\x14\0\x0E\x14\0\x0F\x14\0\x10\x14\0\x11\x14\0\x12\x14\0\x13\x14\0\x14\x14\0\x15\x14\0\x16\x14\0\x18\x14\0\x19\x14\0\x1A\x14\0\x1B\x14\0\x1F\x14\0!\x14\0\"\x14\0%\x14\0&\x14\0'\x14\0(\x14\0)\x14\0/\x14\x000\x14\x001\x14\x005\x14\08\x14\0:\x14\0J\x14\0K\x14\0L\x14\0M\x14\0N\x14\0R\x14\0U\x14\0W\x14\0k\x14\0l\x14\0m\x14\0q\x14\0r\x14\0t\x14\0\x89\x14\0\x8A\x14\0\x8B\x14\0\x8F\x14\0\x90\x14\0\x92\x14\0\xA3\x14\0\xA4\x14\0\xA5\x14\0\xA9\x14\0\xAA\x14\0\xAC\x14\0\xBC\x14\0\xBD\x14\0\xC0\x14\0\xC1\x14\0\xC2\x14\0\xC6\x14\0\xC7\x14\0\xC9\x14\0\xD3\x14\0\xD4\x14\0\xD5\x14\0\xD9\x14\0\xDA\x14\0\xDC\x14\0\xEB\x14\0\xEC\x14\0\xED\x14\0\xEE\x14\0\xEF\x14\0\xF3\x14\0\xF4\x14\0\xF6\x14\0&\x15\0'\x15\0(\x15\0,\x15\0-\x15\0/\x15\0@\x15\0A\x15\0C\x15\0D\x15\0F\x15\0J\x15\0K\x15\0M\x15\0Q\x15\0R\x15\0}\x15\0~\x15\0") }, 97u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0\xAB\x04\0\xAC\x04\0\xD1\x04\0\xD2\x04\0\xD7\x04\0\xD8\x04\0\xF3\x04\0\xF4\x04\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0k\0\0l\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xE0\0\0\xE3\0\0\xE4\0\0\xE5\0\0\xE8\0\0\xF0\0\0\xF2\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF9\0\0\xFE\0\0\xFF\0\0\0\x01\0u\x01\0v\x01\0w\x01\0x\x01\0\x81\x1E\0\x82\x1E\0\x83\x1E\0\x84\x1E\0\x85\x1E\0\x86\x1E\0\xF3\x1E\0\xF4\x1E\0") }, 49u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0chddffllngphrhth") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE5\0\0\xE7\0\0\xF8\0\0\xF9\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xDF\0\0\xE0\0\0\xE4\0\0\xE5\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE4\0\0\xE5\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\r\t\0\x0F\t\0\x11\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0<\t\0E\t\0G\t\0I\t\0K\t\0N\t\0P\t\0S\t\0`\t\0d\t\0") }, 70u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\t\0\x0F\0\xE0\xA4\x95\xE0\xA5\x8D\xE0\xA4\xB7\xE0\xA4\xA1\xE0\xA4\xBC\xE0\xA4\xA2\xE0\xA4\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xF3\0\0\xF4\0\0\x07\x01\0\x08\x01\0\r\x01\0\x0E\x01\0\x1B\x01\0\x1C\x01\0B\x01\0C\x01\0D\x01\0E\x01\0U\x01\0V\x01\0[\x01\0\\\x01\0a\x01\0b\x01\0z\x01\0{\x01\0~\x01\0\x7F\x01\0") }, 37u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0ch") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0j\0\0k\0\0q\0\0r\0\0{\0\0\xE0\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xEE\0\0\xF2\0\0\xF4\0\0\xF5\0\0\xF6\0\0\xF9\0\0\xFB\0\0)\x01\0*\x01\0K\x01\0L\x01\0i\x01\0j\x01\0\x92\x01\0\x93\x01\0T\x02\0U\x02\0V\x02\0W\x02\0[\x02\0\\\x02\0c\x02\0d\x02\0\x8B\x02\0\x8C\x02\0\xBD\x1E\0\xBE\x1E\0") }, 45u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x06\0\x04\0\x08\0\x0C\0\x10\0\x14\0\xC9\x94\xCC\x80\xC9\x94\xCC\x81\xC9\x94\xCC\x83\xC9\x9B\xCC\x80\xC9\x9B\xCC\x81\xC9\x9B\xCC\x83") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x90\x03\0\x91\x03\0\xAC\x03\0\xCF\x03\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x90\x03\0\x91\x03\0\xAC\x03\0\xCF\x03\0\0\x1F\0\x08\x1F\0\x10\x1F\0\x16\x1F\0 \x1F\0(\x1F\x000\x1F\08\x1F\0B\x1F\0E\x1F\0P\x1F\0X\x1F\0b\x1F\0h\x1F\0p\x1F\0q\x1F\0r\x1F\0s\x1F\0t\x1F\0u\x1F\0v\x1F\0w\x1F\0x\x1F\0y\x1F\0z\x1F\0{\x1F\0|\x1F\0}\x1F\0\xB6\x1F\0\xB7\x1F\0\xC6\x1F\0\xC7\x1F\0\xD2\x1F\0\xD3\x1F\0\xD6\x1F\0\xD8\x1F\0\xE2\x1F\0\xE3\x1F\0\xE6\x1F\0\xE8\x1F\0\xF6\x1F\0\xF7\x1F\0") }, 99u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0z\0\0{\0\0\t\x01\0\n\x01\0\x1D\x01\0\x1E\x01\0%\x01\0&\x01\x005\x01\x006\x01\0]\x01\0^\x01\0m\x01\0n\x01\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE4\0\0\xE5\0\0\xF5\0\0\xF7\0\0\xFC\0\0\xFD\0\0a\x01\0b\x01\0~\x01\0\x7F\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE7\0\0\xE8\0\0\xF1\0\0\xF2\0\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0%\x06\0&\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0K\x06\0N\x06\0Q\x06\0R\x06\0T\x06\0U\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x98\x06\0\x99\x06\0\xA9\x06\0\xAA\x06\0\xAF\x06\0\xB0\x06\0\xCC\x06\0\xCD\x06\0") }, 43u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\"\xE9\x01>\xE9\x01D\xE9\x01G\xE9\x01K\xE9\x01L\xE9\x01") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE4\0\0\xE6\0\0\xF6\0\0\xF7\0\0a\x01\0b\x01\0~\x01\0\x7F\x01\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xF1\0\0\xF2\0\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0ng") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0w\0\0y\0\0z\0\0\xE1\0\0\xE2\0\0\xE6\0\0\xE7\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF8\0\0\xF9\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFE\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE6\0\0\xEC\0\0\xEE\0\0\xF0\0\0\xF4\0\0\xF5\0\0\xF9\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0\0\x01\0S\x01\0T\x01\0") }, 42u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0x\0\0y\0\0{\0\0\xE0\0\0\xE3\0\0\xE4\0\0\xE5\0\0\xE8\0\0\xEC\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF0\0\0\xF3\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xFA\0\0\xFE\0\0") }, 41u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0ij\xC3\xADj\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0j\0\0l\0\0q\0\0r\0\0v\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0{\0\0K\x01\0L\x01\0T\x02\0U\x02\0[\x02\0\\\x02\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0j\0\0l\0\0q\0\0r\0\0v\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xE9\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF0\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x81\n\0\x84\n\0\x85\n\0\x8C\n\0\x8D\n\0\x8E\n\0\x8F\n\0\x92\n\0\x93\n\0\xA9\n\0\xAA\n\0\xB1\n\0\xB2\n\0\xB4\n\0\xB5\n\0\xBA\n\0\xBC\n\0\xC6\n\0\xC7\n\0\xCA\n\0\xCB\n\0\xCE\n\0\xD0\n\0\xD1\n\0\xE0\n\0\xE1\n\0") }, 68u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0p\0\0r\0\0v\0\0w\0\0x\0\0y\0\0{\0\0\x99\x01\0\x9A\x01\0\xB4\x01\0\xB5\x01\0S\x02\0T\x02\0W\x02\0X\x02\0\xBC\x02\0\xBD\x02\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0shts") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD0\x05\0\xEB\x05\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\x0E\t\0\x0F\t\0\x12\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0<\t\0D\t\0E\t\0F\t\0G\t\0J\t\0K\t\0N\t\0P\t\0Q\t\0") }, 67u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xF3\0\0\xF4\0\0\x07\x01\0\x08\x01\0\r\x01\0\x0E\x01\0\x1B\x01\0\x1C\x01\0B\x01\0C\x01\0D\x01\0E\x01\0Y\x01\0Z\x01\0a\x01\0b\x01\0~\x01\0\x7F\x01\0") }, 35u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0chd\xC5\xBA") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0u\0\0v\0\0x\0\0y\0\0{\0\0\xE8\0\0\xE9\0\0\xF2\0\0\xF3\0\0") }, 24u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0F\0anchenngonouounui") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0z\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0Q\x01\0R\x01\0q\x01\0r\x01\0") }, 31u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x12\0\x03\0\x05\0\x08\0\x0C\0\x0E\0\x11\0\x14\0\x16\0\x19\0\x1B\0\x1E\0 \0#\0%\0(\0*\0,\0ccscsddzddzsdzdzsggygyllylynnynysszszttytyzszzs") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\x05\0\x87\x05\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0{\0\0E\x1E\0F\x1E\0\xCB\x1E\0\xCC\x1E\0\xCD\x1E\0\xCE\x1E\0\xE5\x1E\0\xE6\x1E\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0chgbghgwkpkwnwnysh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\xA0\0\x8D\xA4\0") }, 1165u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0w\0\0x\0\0z\0\0\xE1\0\0\xE2\0\0\xE6\0\0\xE7\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF3\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFF\0\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x050\0\x060\0A0\0\x940\0\x9D0\0\x9F0\0\xA10\0\xF70\0\xFC0\0\xFF0\0\0N\0\x02N\0\x03N\0\x04N\0\x07N\0\x0CN\0\rN\0\x0FN\0\x14N\0\x15N\0\x16N\0\x17N\0\x18N\0\x1AN\0!N\0\"N\0&N\0'N\0-N\0.N\x002N\x003N\08N\0:N\0;N\0=N\0EN\0FN\0ON\0PN\0WN\0XN\0YN\0ZN\0]N\0_N\0qN\0rN\0sN\0tN\0~N\0\x7FN\0\x80N\0\x81N\0\x86N\0\x87N\0\x88N\0\x8AN\0\x8BN\0\x8DN\0\x92N\0\x93N\0\x94N\0\x96N\0\x9CN\0\x9DN\0\xA1N\0\xA2N\0\xA4N\0\xA5N\0\xABN\0\xAEN\0\xBAN\0\xBBN\0\xC1N\0\xC2N\0\xCAN\0\xCCN\0\xCFN\0\xD0N\0\xD5N\0\xD7N\0\xD8N\0\xDAN\0\xE3N\0\xE6N\0\xEEN\0\xEFN\0\xF0N\0\xF1N\0\xF2N\0\xF3N\0\xF6N\0\xF7N\0\xFBN\0\xFCN\0\x01O\0\x02O\0\x0EO\0\x12O\0\x1AO\0\x1BO\0\x1DO\0\x1EO\0/O\x000O\x004O\x005O\08O\09O\0:O\0;O\0<O\0=O\0FO\0GO\0MO\0QO\0SO\0TO\0UO\0VO\0YO\0ZO\0\\O\0]O\0sO\0tO\0uO\0vO\0\x7FO\0\x80O\0\x8BO\0\x8CO\0\x8DO\0\x8EO\0\x9BO\0\x9CO\0\x9DO\0\x9EO\0\xA1O\0\xA2O\0\xAEO\0\xB0O\0\xB5O\0\xB7O\0\xBFO\0\xC0O\0\xC2O\0\xC4O\0\xCAO\0\xCBO\0\xD7O\0\xD8O\0\xDDO\0\xDEO\0\xE1O\0\xE2O\0\xEEO\0\xEFO\0\xF3O\0\xF4O\0\xF5O\0\xF6O\0\xF8O\0\xF9O\0\xFAO\0\xFBO\0\tP\0\nP\0\x0BP\0\x0CP\0\rP\0\x0EP\0\x12P\0\x13P\0\x19P\0\x1AP\0\x1FP\0 P\0#P\0%P\0+P\0,P\09P\0:P\0IP\0JP\0OP\0PP\0\\P\0]P\0eP\0fP\0tP\0wP\0}P\0~P\0\x8DP\0\x8EP\0\x91P\0\x92P\0\x98P\0\x9AP\0\xACP\0\xADP\0\xB2P\0\xB3P\0\xB5P\0\xB6P\0\xB7P\0\xB8P\0\xBEP\0\xBFP\0\xC5P\0\xC6P\0\xCDP\0\xCEP\0\xCFP\0\xD0P\0\xD5P\0\xD6P\0\xDAP\0\xDBP\0\xE7P\0\xE8P\0\0Q\0\x01Q\0\x04Q\0\x05Q\0\x12Q\0\x13Q\0\x1FQ\0 Q\0*Q\0+Q\0CQ\0GQ\0HQ\0JQ\0KQ\0LQ\0MQ\0NQ\0PQ\0QQ\0ZQ\0[Q\0eQ\0fQ\0hQ\0iQ\0kQ\0nQ\0qQ\0rQ\0uQ\0vQ\0wQ\0yQ\0|Q\0}Q\0\x85Q\0\x87Q\0\x8AQ\0\x8BQ\0\x8DQ\0\x8EQ\0\x92Q\0\x93Q\0\x97Q\0\x98Q\0\x99Q\0\x9AQ\0\xA0Q\0\xA1Q\0\xA5Q\0\xA6Q\0\xACQ\0\xADQ\0\xB6Q\0\xB8Q\0\xC4Q\0\xC5Q\0\xC6Q\0\xC7Q\0\xCDQ\0\xCEQ\0\xDDQ\0\xDEQ\0\xE1Q\0\xE2Q\0\xE6Q\0\xE7Q\0\xF6Q\0\xF7Q\0\xF8Q\0\xFBQ\0\0R\0\x01R\0\x03R\0\x04R\0\x06R\0\tR\0\nR\0\x0BR\0\x11R\0\x12R\0\x17R\0\x18R\0\x1DR\0\x1ER\0$R\0&R\0)R\0*R\x000R\x001R\x006R\0<R\0GR\0HR\0JR\0KR\0MR\0NR\0VR\0WR\0[R\0\\R\0cR\0fR\0oR\0qR\0rR\0sR\0uR\0vR\0\x87R\0\x88R\0\x9BR\0\x9CR\0\x9FR\0\xA1R\0\xA3R\0\xA4R\0\xA9R\0\xABR\0\xB1R\0\xB2R\0\xB4R\0\xB5R\0\xB9R\0\xBAR\0\xBER\0\xBFR\0\xC3R\0\xC4R\0\xC5R\0\xC6R\0\xC7R\0\xC8R\0\xC9R\0\xCAR\0\xD5R\0\xD6R\0\xD8R\0\xDAR\0\xDDR\0\xDER\0\xDFR\0\xE0R\0\xE2R\0\xE3R\0\xE4R\0\xE5R\0\xE7R\0\xE8R\0\xF2R\0\xF3R\0\xFER\0\xFFR\0\x02S\0\x03S\0\x05S\0\x06S\0\x16S\0\x18S\0 S\0!S\09S\0<S\0?S\0@S\0AS\0BS\0CS\0DS\0GS\0IS\0JS\0KS\0QS\0US\0WS\0YS\0ZS\0[S\0`S\0aS\0pS\0rS\0sS\0vS\0xS\0yS\0\x84S\0\x85S\0\x98S\0\x99S\0\x9AS\0\x9BS\0\x9FS\0\xA0S\0\xB3S\0\xB4S\0\xBBS\0\xBCS\0\xC2S\0\xC3S\0\xC8S\0\xC9S\0\xCAS\0\xCFS\0\xD4S\0\xD5S\0\xD6S\0\xD8S\0\xD9S\0\xDAS\0\xE3S\0\xE6S\0\xEBS\0\xEDS\0\xEFS\0\xF4S\0\xF7S\0\xF9S\0\x04T\0\x05T\0\x08T\0\nT\0\x0CT\0\x12T\0\x1BT\0\x1CT\0\x1FT\0 T\0&T\0'T\0+T\0,T\08T\0:T\0BT\0CT\0HT\0KT\0hT\0iT\0jT\0kT\0sT\0tT\0|T\0~T\0\x8CT\0\x8DT\0\xB2T\0\xB3T\0\xBDT\0\xBET\0\xC0T\0\xC2T\0\xE1T\0\xE2T\0\xF2T\0\xF3T\0\xFAT\0\xFBT\0\x04U\0\x05U\0\x06U\0\x08U\0\x10U\0\x11U\0/U\x000U\x001U\x002U\0>U\0?U\0FU\0GU\0OU\0PU\0SU\0TU\0\x84U\0\x85U\0\x89U\0\x8AU\0\x9AU\0\x9BU\0\x9CU\0\x9EU\0\xA9U\0\xACU\0\xB6U\0\xB7U\0\xC5U\0\xC6U\0\xE3U\0\xE4U\0\x06V\0\x07V\x001V\x003V\0hV\0iV\0tV\0uV\0\x87V\0\x88V\0\xDAV\0\xDCV\0\xDEV\0\xDFV\0\xE0V\0\xE1V\0\xE3V\0\xE4V\0\xF0V\0\xF1V\0\xF2V\0\xF4V\0\xFAV\0\xFBV\0\xFDV\0\xFEV\0\x0FW\0\x10W\0\x12W\0\x13W\0\x1FW\0 W\0'W\0)W\x000W\x001W\0BW\0CW\0GW\0HW\0JW\0KW\0QW\0RW\0jW\0kW\0\x82W\0\x83W\0\x8BW\0\x8CW\0\xA3W\0\xA4W\0\xCBW\0\xCCW\0\xCEW\0\xCFW\0\xDFW\0\xE0W\0\xF7W\0\xF8W\0\xF9W\0\xFBW\0\xFCW\0\xFDW\0\0X\0\x01X\0\x02X\0\x03X\0\x05X\0\x07X\0\x15X\0\x16X\0$X\0%X\0*X\0+X\x001X\x002X\x004X\x005X\0@X\0BX\0JX\0KX\0QX\0RX\0TX\0UX\0WX\0XX\0ZX\0[X\0^X\0_X\0iX\0jX\0kX\0lX\0~X\0\x7FX\0\x83X\0\x84X\0\x93X\0\x94X\0\x97X\0\x98X\0\x9CX\0\x9DX\0\xA8X\0\xA9X\0\xB3X\0\xB4X\0\xBEX\0\xBFX\0\xC1X\0\xC2X\0\xC7X\0\xC8X\0\xCAX\0\xCBX\0\xCCX\0\xCDX\0\xEBX\0\xECX\0\xEEX\0\xEFX\0\xF0X\0\xF3X\0\tY\0\nY\0\x0FY\0\x10Y\0\x15Y\0\x17Y\0\x1AY\0\x1BY\0\x1CY\0\x1DY\0\"Y\0#Y\0'Y\0(Y\0)Y\0,Y\0.Y\0/Y\x001Y\x002Y\0GY\0JY\0OY\0PY\0QY\0RY\0TY\0UY\0eY\0fY\0hY\0iY\0jY\0kY\0nY\0oY\0sY\0uY\0}Y\0~Y\0\x82Y\0\x85Y\0\x8AY\0\x8BY\0\x96Y\0\x97Y\0\x99Y\0\x9AY\0\xA5Y\0\xA6Y\0\xA8Y\0\xA9Y\0\xACY\0\xADY\0\xB9Y\0\xBAY\0\xBBY\0\xBCY\0\xC9Y\0\xCAY\0\xCBY\0\xCCY\0\xD3Y\0\xD5Y\0\xEBY\0\xECY\0\xFBY\0\xFCY\0\xFFY\0\0Z\0\x01Z\0\x02Z\0\x18Z\0\x19Z\0 Z\0!Z\0/Z\x000Z\0FZ\0GZ\0ZZ\0[Z\0fZ\0gZ\0\x7FZ\0\x80Z\0\x92Z\0\x93Z\0\x9BZ\0\x9CZ\0\xC1Z\0\xC2Z\0\xC9Z\0\xCAZ\0\xCCZ\0\xCDZ\0\xE1Z\0\xE2Z\0\"[\0#[\0P[\0Q[\0T[\0U[\0W[\0Y[\0][\0^[\0c[\0e[\0f[\0g[\0k[\0l[\0\x85[\0\x86[\0\x87[\0\x8A[\0\x8C[\0\x8D[\0\x97[\0\x9E[\0\x9F[\0\xA0[\0\xA2[\0\xA5[\0\xAE[\0\xAF[\0\xB0[\0\xB1[\0\xB3[\0\xB7[\0\xB9[\0\xBA[\0\xBF[\0\xC0[\0\xC2[\0\xC3[\0\xC4[\0\xC5[\0\xC6[\0\xC7[\0\xCC[\0\xCD[\0\xD2[\0\xD3[\0\xDB[\0\xDC[\0\xDD[\0\xDE[\0\xDF[\0\xE0[\0\xE1[\0\xE2[\0\xE7[\0\xE8[\0\xE9[\0\xEA[\0\xEE[\0\xEF[\0\xF8[\0\xF9[\0\xFA[\0\xFB[\0\xFE[\0\0\\\0\x01\\\0\x03\\\0\x04\\\0\x05\\\0\x06\\\0\x07\\\0\t\\\0\x0C\\\0\x0E\\\0\x10\\\0\x11\\\0\x12\\\0\x1A\\\0\x1B\\\x001\\\x002\\\0:\\\0A\\\0E\\\0F\\\0H\\\0I\\\0J\\\0L\\\0U\\\0V\\\0^\\\0_\\\0d\\\0f\\\0o\\\0p\\\0q\\\0r\\\0\x90\\\0\x91\\\0\xA1\\\0\xA2\\\0\xA9\\\0\xAA\\\0\xAC\\\0\xAD\\\0\xB3\\\0\xB4\\\0\xB8\\\0\xB9\\\0\xE0\\\0\xE2\\\0\xF0\\\0\xF1\\\0\xF6\\\0\xF7\\\0\x07]\0\x08]\0\x0E]\0\x0F]\0\x16]\0\x17]\0)]\0*]\0P]\0Q]\0\xDD]\0\xDF]\0\xE1]\0\xE2]\0\xE3]\0\xE4]\0\xE5]\0\xE9]\0\xEE]\0\xEF]\0\xF1]\0\xF2]\0\xFB]\0\xFC]\0\xFE]\0\xFF]\0\x02^\0\x04^\0\x06^\0\x07^\0\x0C^\0\r^\0\x1D^\0\x1E^\0%^\0&^\0+^\0,^\0-^\0.^\0/^\x001^\x003^\x004^\08^\09^\0=^\0>^\0E^\0F^\0U^\0V^\0c^\0d^\0r^\0u^\0x^\0z^\0{^\0\x7F^\0\x81^\0\x82^\0\x83^\0\x84^\0\x8A^\0\x8B^\0\x8F^\0\x90^\0\x95^\0\x96^\0\x97^\0\x98^\0\x9C^\0\x9D^\0\xA6^\0\xA8^\0\xAB^\0\xAC^\0\xAD^\0\xAE^\0\xB6^\0\xB9^\0\xC3^\0\xC4^\0\xC9^\0\xCB^\0\xF6^\0\xF8^\0\xFA^\0\xFB^\0\x01_\0\x02_\0\x04_\0\x05_\0\n_\0\x0B_\0\x0F_\0\x11_\0\x13_\0\x16_\0\x1F_\0 _\0%_\0(_\x001_\x002_\x005_\x006_\x007_\08_\0>_\0?_\0S_\0T_\0Y_\0Z_\0b_\0c_\0i_\0j_\0k_\0l_\0p_\0r_\0y_\0z_\0|_\0}_\0\x80_\0\x82_\0\x84_\0\x86_\0\x8B_\0\x8D_\0\x90_\0\x91_\0\x92_\0\x94_\0\x97_\0\x98_\0\xA1_\0\xA2_\0\xA9_\0\xAB_\0\xAE_\0\xAF_\0\xB3_\0\xB5_\0\xB9_\0\xBA_\0\xC3_\0\xC4_\0\xC5_\0\xC6_\0\xCC_\0\xCE_\0\xD7_\0\xDA_\0\xDC_\0\xDD_\0\xE0_\0\xE1_\0\xEB_\0\xEC_\0\xF5_\0\xF6_\0\x12`\0\x13`\0\x16`\0\x17`\0\x1D`\0\x1E`\0 `\0!`\0%`\0&`\0'`\0)`\0*`\0+`\0K`\0L`\0P`\0Q`\0R`\0S`\0c`\0d`\0e`\0f`\0h`\0j`\0m`\0n`\0o`\0p`\0u`\0v`\0\x94`\0\x95`\0\x9F`\0\xA1`\0\xA3`\0\xA4`\0\xA6`\0\xA7`\0\xA9`\0\xAB`\0\xB2`\0\xB3`\0\xBC`\0\xBD`\0\xC5`\0\xC6`\0\xD1`\0\xD2`\0\xDC`\0\xDD`\0\xE7`\0\xE9`\0\xF0`\0\xF1`\0\xF3`\0\xF4`\0\x01a\0\x02a\0\ta\0\na\0\x0Fa\0\x10a\0\x1Aa\0\x1Ca\0\x1Fa\0 a\0Da\0Ea\0Ha\0Ia\0Ka\0Ma\0Na\0Oa\0Ua\0Va\0ba\0da\0ha\0ia\0na\0oa\0pa\0qa\0va\0wa\0\x82a\0\x83a\0\x8Ea\0\x8Fa\0\xA4a\0\xA5a\0\xA7a\0\xA8a\0\xA9a\0\xAAa\0\xACa\0\xADa\0\xB2a\0\xB3a\0\xB6a\0\xB7a\0\xBEa\0\xBFa\0\xC7a\0\xC8a\0\xD0a\0\xD1a\0\xF2a\0\xF3a\0\xF8a\0\xF9a\0\x10b\0\x13b\0\x1Ab\0\x1Bb\0&b\0'b\0/b\x000b\x004b\x005b\08b\09b\0;b\0<b\0?b\0Ab\0Gb\0Hb\0Ib\0Jb\0Kb\0Lb\0Mb\0Nb\0Sb\0Tb\0Ub\0Vb\0qb\0rb\0vb\0wb\0yb\0zb\0\x7Fb\0\x81b\0\x84b\0\x85b\0\x8Ab\0\x8Bb\0\x91b\0\x92b\0\x95b\0\x96b\0\x97b\0\x99b\0\x9Cb\0\x9Db\0\x9Eb\0\x9Fb\0\xABb\0\xACb\0\xB1b\0\xB2b\0\xB5b\0\xB6b\0\xB9b\0\xBAb\0\xBCb\0\xBEb\0\xC5b\0\xC6b\0\xC9b\0\xCAb\0\xCDb\0\xCEb\0\xD0b\0\xD1b\0\xD2b\0\xD4b\0\xD8b\0\xDAb\0\xDBb\0\xDCb\0\xDDb\0\xDEb\0\xE0b\0\xE2b\0\xECb\0\xEEb\0\xF3b\0\xF4b\0\xF6b\0\xF8b\0\xFEb\0\xFFb\0\x01c\0\x02c\0\x07c\0\x08c\0\x11c\0\x12c\0\x19c\0\x1Ac\0\x1Fc\0 c\0(c\0)c\0+c\0,c\0/c\x000c\0?c\0@c\0Ic\0Jc\0Uc\0Vc\0Wc\0Xc\0\\c\0]c\0hc\0ic\0nc\0oc\0{c\0|c\0\x83c\0\x84c\0\x88c\0\x89c\0\x8Cc\0\x8Dc\0\x92c\0\x93c\0\x98c\0\x99c\0\x9Bc\0\x9Cc\0\xA1c\0\xA3c\0\xA5c\0\xA6c\0\xA7c\0\xA9c\0\xAAc\0\xABc\0\xB2c\0\xB3c\0\xCFc\0\xD1c\0\xDAc\0\xDCc\0\xE1c\0\xE2c\0\xEEc\0\xEFc\0\xF4c\0\xF5c\0\xFAc\0\xFBc\0\rd\0\x0Ed\0,d\0.d\0:d\0;d\0>d\0?d\0Bd\0Cd\0Xd\0Yd\0id\0jd\0od\0pd\0\x83d\0\x84d\0\xA4d\0\xA5d\0\xAEd\0\xAFd\0\xB2d\0\xB3d\0\xC1d\0\xC2d\0\xCDd\0\xCEd\0\xE6d\0\xE7d\0\xECd\0\xEDd\0/e\x000e\09e\0:e\0;e\0<e\0>e\0@e\0Ee\0Fe\0Oe\0Pe\0Qe\0Re\0We\0Xe\0Ye\0Ze\0be\0de\0le\0me\0pe\0qe\0te\0ve\0we\0xe\0\x87e\0\x88e\0\x89e\0\x8Ae\0\x8Ee\0\x8Fe\0\x91e\0\x92e\0\x97e\0\x98e\0\x99e\0\x9Ae\0\x9Ce\0\x9De\0\xA4e\0\xA6e\0\xACe\0\xAEe\0\xB0e\0\xB1e\0\xB9e\0\xBAe\0\xBDe\0\xBEe\0\xC5e\0\xC6e\0\xCBe\0\xCCe\0\xCFe\0\xD0e\0\xD7e\0\xD8e\0\xE2e\0\xE3e\0\xE5e\0\xEAe\0\xECe\0\xEDe\0\xFAe\0\xFBe\0\x06f\0\x08f\0\x0Ef\0\x0Ff\0\x13f\0\x15f\0\x1Ff\0!f\0%f\0&f\0'f\0)f\0-f\0.f\0/f\x000f\0<f\0=f\0Bf\0Cf\0if\0jf\0nf\0pf\0tf\0uf\0vf\0wf\0\x81f\0\x82f\0\x87f\0\x88f\0\x91f\0\x92f\0\x96f\0\x98f\0\xA6f\0\xA7f\0\xABf\0\xACf\0\xAEf\0\xAFf\0\xB4f\0\xB5f\0\xC7f\0\xC8f\0\xD6f\0\xD7f\0\xDCf\0\xDDf\0\xF2f\0\xF3f\0\xF4f\0\xF5f\0\xF8f\0\xFAf\0\xFDf\0\xFEf\0\xFFf\0\x01g\0\x08g\0\ng\0\rg\0\x0Eg\0\x15g\0\x16g\0\x17g\0\x18g\0\x1Bg\0\x1Cg\0\x1Dg\0\x1Eg\0\x1Fg\0 g\0(g\0)g\0*g\0.g\x001g\x002g\x004g\x005g\0:g\0;g\0=g\0>g\0Ig\0Jg\0Pg\0Rg\0_g\0`g\0ag\0bg\0eg\0fg\0og\0pg\0qg\0rg\0~g\0\x80g\0\x90g\0\x91g\0\x95g\0\x96g\0\x97g\0\x98g\0\x9Ag\0\x9Bg\0\x9Cg\0\x9Eg\0\xA0g\0\xA1g\0\xA2g\0\xA3g\0\xAFg\0\xB0g\0\xB6g\0\xB7g\0\xC4g\0\xC5g\0\xD0g\0\xD1g\0\xD3g\0\xD5g\0\xF1g\0\xF2g\0\xF3g\0\xF4g\0\xF5g\0\xF6g\0\xFBg\0\xFCg\0\xFFg\0\0h\0\x03h\0\x05h\0\x13h\0\x14h\0!h\0\"h\0*h\0+h\08h\0:h\0<h\0>h\0Ah\0Bh\0Ch\0Dh\0Hh\0Ih\0Qh\0Rh\0\\h\0]h\0_h\0`h\0\x85h\0\x86h\0\x97h\0\x98h\0\xA8h\0\xA9h\0\xB0h\0\xB1h\0\xC4h\0\xC5h\0\xCBh\0\xCCh\0\xD2h\0\xD3h\0\xDAh\0\xDBh\0\xDFh\0\xE0h\0\xEEh\0\xEFh\0\xFAh\0\xFBh\0\x05i\0\x06i\0\ri\0\x0Fi\0\x1Ci\0\x1Di\0mi\0ni\0ui\0vi\0wi\0xi\0|i\0~i\0\x82i\0\x83i\0\xCBi\0\xCCi\0\xD8i\0\xD9i\0\xFDi\0\xFEi\0\x19j\0\x1Aj\0!j\0\"j\0)j\0+j\09j\0:j\0Kj\0Lj\0_j\0`j\0\x04k\0\x05k\0 k\0\"k\0'k\0(k\x002k\x003k\0:k\0;k\0>k\0?k\0Lk\0Mk\0Sk\0Tk\0bk\0dk\0fk\0gk\0ik\0jk\0ok\0pk\0sk\0uk\0{k\0|k\0\x89k\0\x8Ck\0\x96k\0\x97k\0\xB4k\0\xB6k\0\xBAk\0\xBCk\0\xBFk\0\xC1k\0\xCDk\0\xCFk\0\xD2k\0\xD3k\0\xD4k\0\xD5k\0\xDBk\0\xDCk\0\x0Fl\0\x10l\0\x11l\0\x12l\0\x17l\0\x18l\x004l\x005l\x007l\09l\0>l\0?l\0Al\0Cl\0Nl\0Ol\0Wl\0Xl\0Zl\0[l\0_l\0al\0pl\0ql\0zl\0{l\0}l\0~l\0\x83l\0\x84l\0\x88l\0\x89l\0\x96l\0\x97l\0\x99l\0\x9Al\0\xA1l\0\xA3l\0\xB3l\0\xB4l\0\xB8l\0\xBAl\0\xBBl\0\xBDl\0\xBFl\0\xC0l\0\xC1l\0\xC2l\0\xC9l\0\xCBl\0\xCCl\0\xCDl\0\xD5l\0\xD6l\0\xE1l\0\xE4l\0\xE5l\0\xE6l\0\xE8l\0\xE9l\0\xF0l\0\xF1l\0\xF3l\0\xF4l\0\x0Bm\0\x0Cm\0\x17m\0\x18m\0\x1Em\0\x1Fm\0%m\0&m\0*m\0+m\0;m\0<m\0>m\0?m\0Am\0Bm\0Dm\0Fm\0\\m\0]m\0fm\0gm\0jm\0km\0nm\0om\0tm\0um\0wm\0ym\0\x88m\0\x89m\0\x99m\0\x9Am\0\xAFm\0\xB0m\0\xB2m\0\xB3m\0\xBCm\0\xBDm\0\xD1m\0\xD2m\0\xE1m\0\xE2m\0\xEBm\0\xECm\0\xF1m\0\xF2m\0\xF7m\0\xF8m\0\xFBm\0\xFCm\0\x05n\0\x06n\0\x07n\0\nn\0\x0Bn\0\x0Cn\0\x13n\0\x14n\0\x1Bn\0\x1Cn\0!n\0\"n\0&n\0'n\0)n\0*n\0,n\0-n\0/n\x000n\0Vn\0Wn\0gn\0hn\0on\0pn\0~n\0\x81n\0\x90n\0\x91n\0\x96n\0\x97n\0\x9Dn\0\x9En\0\xB6n\0\xB7n\0\xBAn\0\xBBn\0\xC5n\0\xC6n\0\xCBn\0\xCCn\0\xD1n\0\xD2n\0\xDDn\0\xDFn\0\xF4n\0\xF5n\0\x01o\0\x03o\0\x06o\0\x07o\0\x0Fo\0\x10o\0\x14o\0\x15o\0 o\0!o\0\"o\0#o\0+o\0-o\08o\09o\0To\0Uo\0\\o\0]o\0_o\0`o\0do\0eo\0no\0oo\0po\0qo\0\x84o\0\x85o\0\xC0o\0\xC2o\0\xC3o\0\xC4o\0\xEBo\0\xECo\0\xEFo\0\xF0o\0,p\0-p\0kp\0lp\0op\0qp\0}p\0~p\0\x89p\0\x8Bp\0\x8Ep\0\x8Fp\0\xADp\0\xAEp\0\xB9p\0\xBBp\0\xC8p\0\xC9p\0!q\0\"q\0&q\0'q\x006q\x007q\0<q\0=q\0Nq\0Oq\0Yq\0Zq\0gq\0hq\0iq\0jq\0nq\0oq\0\x8Aq\0\x8Bq\0\x9Fq\0\xA0q\0\xB1q\0\xB2q\0\xC3q\0\xC4q\0\xE5q\0\xE6q\0\x06r\0\x07r\0*r\0+r\x005r\x007r\0=r\0>r\0Gr\0Ir\0Yr\0Zr\0[r\0\\r\0gr\0hr\0ir\0jr\0rr\0sr\0yr\0zr\0\xA0r\0\xA1r\0\xACr\0\xADr\0\xAFr\0\xB0r\0\xB6r\0\xB7r\0\xC2r\0\xC3r\0\xD9r\0\xDAr\0\xE9r\0\xEAr\0\xECr\0\xEEr\0\x1Bs\0\x1Cs\0\x1Fs\0 s\0+s\0,s\0.s\0/s\x006s\x007s\0?s\0@s\0Ds\0Es\0cs\0ds\0rs\0ss\0\x84s\0\x85s\0\x87s\0\x88s\0\x89s\0\x8As\0\x8Bs\0\x8Cs\0\xA9s\0\xAAs\0\xCDs\0\xCEs\0\xE0s\0\xE1s\0\xEDs\0\xEEs\0\xFEs\0\xFFs\0\x03t\0\x04t\0\x06t\0\x07t\x004t\x005t\0`t\0at\0\x83t\0\x84t\0\xA7t\0\xA8t\0\xB0t\0\xB1t\0\xBDt\0\xBEt\0\xE6t\0\xE7t\0\xF6t\0\xF7t\0\x18u\0\x19u\0\x1Au\0\x1Bu\0\x1Fu\0 u\0#u\0$u\0(u\0)u\x000u\x004u\x007u\08u\0:u\0<u\0Lu\0Mu\0Ou\0Pu\0Qu\0Ru\0Tu\0Uu\0Yu\0Zu\0\\u\0^u\0eu\0fu\0ju\0ku\0pu\0qu\0su\0tu\0\x7Fu\0\x80u\0\x8Eu\0\x8Fu\0\x91u\0\x92u\0\xABu\0\xACu\0\xB2u\0\xB3u\0\xBEu\0\xBFu\0\xC5u\0\xC6u\0\xC7u\0\xC8u\0\xD5u\0\xD6u\0\xD8u\0\xD9u\0\xDBu\0\xDCu\0\xE2u\0\xE3u\0\xE9u\0\xEAu\0\xF4u\0\xF5u\0\rv\0\x0Ev\0Bv\0Cv\0Rv\0Sv\0Vv\0Wv\0zv\0|v\0}v\0\x7Fv\0\x84v\0\x85v\0\x86v\0\x88v\0\xAEv\0\xAFv\0\xBFv\0\xC0v\0\xC6v\0\xC7v\0\xCAv\0\xCBv\0\xD7v\0\xD8v\0\xDBv\0\xDCv\0\xDFv\0\xE0v\0\xE3v\0\xE5v\0\xEEv\0\xEFv\0\xF2v\0\xF3v\0\xF4v\0\xF5v\0\xF8v\0\xF9v\0\xFEv\0\xFFv\0\x01w\0\x02w\0\tw\0\nw\0\x0Bw\0\rw\0\x1Fw\0!w\0:w\0;w\0<w\0=w\0@w\0Aw\0aw\0bw\0cw\0dw\0fw\0gw\0\xACw\0\xAEw\0\xB3w\0\xB4w\0\xDBw\0\xDCw\0\xE2w\0\xE3w\0\xE5w\0\xE6w\0\xEDw\0\xEEw\0\xEFw\0\xF0w\0\xF3w\0\xF4w\0\x02x\0\x03x\0\x14x\0\x16x\x002x\x003x\x004x\x005x\0]x\0^x\0kx\0mx\0\x81x\0\x82x\0\x91x\0\x92x\0\xBAx\0\xBBx\0\xC1x\0\xC2x\0\xE8x\0\xE9x\0\x01y\0\x02y\0\x0Ey\0\x0Fy\0:y\0;y\0<y\0=y\0>y\0?y\0Hy\0Jy\0Vy\0Wy\0]y\0_y\0ey\0fy\0hy\0iy\0my\0ny\0\x81y\0\x82y\0\x85y\0\x86y\0\x8Dy\0\x8Ey\0\x8Fy\0\x90y\0\xC0y\0\xC2y\0\xCBy\0\xCCy\0\xD1y\0\xD3y\0\xD8y\0\xD9y\0\xDFy\0\xE0y\0\xE9y\0\xEAy\0\xF0y\0\xF1y\0\xFBy\0\xFCy\0\x0Bz\0\x0Cz\0\x0Ez\0\x0Fz\0\x1Az\0\x1Bz\0.z\0/z\x002z\x003z\0<z\0>z\0?z\0Az\0Bz\0Cz\0Mz\0Nz\0Oz\0Pz\0kz\0lz\0tz\0uz\0vz\0wz\0zz\0{z\0\x81z\0\x82z\0\x83z\0\x84z\0\x92z\0\x94z\0\x9Fz\0\xA0z\0\xAEz\0\xB0z\0\xCBz\0\xCCz\0\xDCz\0\xDDz\0\xE0z\0\xE1z\0\xE5z\0\xE6z\0\xEFz\0\xF0z\0\xF6z\0\xF7z\0\xF9z\0\xFAz\0\x11{\0\x12{\0\x1B{\0\x1C{\0&{\0'{\0,{\0-{\0F{\0G{\0I{\0J{\0K{\0L{\0R{\0S{\0T{\0U{\0V{\0W{\0\x87{\0\x88{\0\x8B{\0\x8C{\0\x97{\0\x98{\0\xA1{\0\xA2{\0\xB1{\0\xB2{\0\xB8{\0\xB9{\0\xC0{\0\xC1{\0\xC4{\0\xC5{\0\xC9{\0\xCA{\0\xE4{\0\xE5{\0!|\0\"|\0?|\0@|\0M|\0N|\0`|\0a|\0s|\0t|\0\x89|\0\x8A|\0\x8B|\0\x8C|\0\x92|\0\x93|\0\x97|\0\x99|\0\x9B|\0\x9C|\0\xA7|\0\xA8|\0\xBE|\0\xBF|\0\xD6|\0\xD7|\0\xE7|\0\xE8|\0\xF8|\0\xF9|\0\xFB|\0\xFC|\0\xFE|\0\xFF|\0\0}\0\x01}\0\x04}\0\x06}\0\x0B}\0\x0C}\0\r}\0\x0E}\0\x14}\0\x15}\0\x19}\0\x1C}\0 }\0#}\0+}\0,}\0/}\x001}\x003}\x004}\09}\0;}\0B}\0C}\0D}\0E}\0L}\0M}\0P}\0Q}\0^}\0_}\0a}\0b}\0f}\0g}\0q}\0r}\0u}\0w}\0y}\0z}\0\x99}\0\x9B}\0\xAD}\0\xAE}\0\xB1}\0\xB3}\0\xBB}\0\xBC}\0\xBF}\0\xC0}\0\xCA}\0\xCB}\0\xCF}\0\xD0}\0\xD1}\0\xD3}\0\xDA}\0\xDB}\0\xE0}\0\xE1}\0\xE8}\0\xEA}\0\xEF}\0\xF0}\0\xF4}\0\xF5}\0\xFB}\0\xFC}\0\x01~\0\x02~\0\x04~\0\x05~\0\x1B~\0\x1C~\0&~\0'~\0+~\0,~\0.~\0/~\0>~\0?~\0A~\0B~\0J~\0K~\0T~\0V~\0m~\0n~\0p~\0q~\x006\x7F\x007\x7F\0j\x7F\0k\x7F\0n\x7F\0o\x7F\0p\x7F\0q\x7F\0r\x7F\0s\x7F\0u\x7F\0v\x7F\0w\x7F\0x\x7F\0\x85\x7F\0\x86\x7F\0\x8A\x7F\0\x8B\x7F\0\x8E\x7F\0\x8F\x7F\0\x9E\x7F\0\x9F\x7F\0\xA4\x7F\0\xA5\x7F\0\xA8\x7F\0\xAA\x7F\0\xBD\x7F\0\xBE\x7F\0\xC1\x7F\0\xC2\x7F\0\xCC\x7F\0\xCD\x7F\0\xD2\x7F\0\xD3\x7F\0\xFB\x7F\0\xFD\x7F\0\x01\x80\0\x02\x80\0\x03\x80\0\x04\x80\0\x05\x80\0\x06\x80\0\x10\x80\0\x11\x80\0\x15\x80\0\x16\x80\0\x17\x80\0\x18\x80\x003\x80\x004\x80\0V\x80\0W\x80\0^\x80\0_\x80\0t\x80\0u\x80\0w\x80\0x\x80\0\x89\x80\0\x8A\x80\0\x8C\x80\0\x8D\x80\0\x96\x80\0\x97\x80\0\x98\x80\0\x99\x80\0\x9D\x80\0\x9E\x80\0\xA1\x80\0\xA3\x80\0\xA5\x80\0\xA6\x80\0\xA9\x80\0\xAB\x80\0\xAF\x80\0\xB0\x80\0\xB2\x80\0\xB3\x80\0\xBA\x80\0\xBB\x80\0\xC3\x80\0\xC4\x80\0\xC6\x80\0\xC7\x80\0\xCC\x80\0\xCD\x80\0\xCE\x80\0\xCF\x80\0\xDE\x80\0\xDF\x80\0\xF4\x80\0\xF5\x80\0\xF8\x80\0\xF9\x80\0\xFD\x80\0\xFE\x80\0\x02\x81\0\x03\x81\0\x05\x81\0\x06\x81\0\x07\x81\0\t\x81\0\n\x81\0\x0B\x81\0\x1A\x81\0\x1B\x81\x001\x81\x002\x81\x003\x81\x004\x81\0N\x81\0O\x81\0P\x81\0Q\x81\0U\x81\0V\x81\0k\x81\0l\x81\0p\x81\0q\x81\0x\x81\0{\x81\0\x9A\x81\0\x9B\x81\0\x9C\x81\0\x9E\x81\0\xA8\x81\0\xA9\x81\0\xB3\x81\0\xB4\x81\0\xC6\x81\0\xC7\x81\0\xD3\x81\0\xD4\x81\0\xE3\x81\0\xE4\x81\0\xE8\x81\0\xE9\x81\0\xEA\x81\0\xEB\x81\0\xED\x81\0\xEE\x81\0\xF3\x81\0\xF5\x81\0\xFC\x81\0\xFD\x81\0\x08\x82\0\t\x82\0\x0C\x82\0\r\x82\0\x0E\x82\0\x0F\x82\0\x17\x82\0\x18\x82\0\x1E\x82\0 \x82\0*\x82\0+\x82\0,\x82\0-\x82\x006\x82\08\x82\09\x82\0:\x82\0G\x82\0H\x82\0f\x82\0g\x82\0o\x82\0p\x82\0r\x82\0s\x82\0v\x82\0w\x82\0\x8B\x82\0\x8C\x82\0\x9D\x82\0\x9E\x82\0\xAF\x82\0\xB0\x82\0\xB1\x82\0\xB2\x82\0\xB3\x82\0\xB4\x82\0\xB8\x82\0\xB9\x82\0\xBD\x82\0\xBE\x82\0\xD7\x82\0\xD8\x82\0\xDB\x82\0\xDC\x82\0\xE5\x82\0\xE7\x82\0\xF1\x82\0\xF2\x82\0\x02\x83\0\x03\x83\0\x0E\x83\0\x0F\x83\0(\x83\0)\x83\x006\x83\x007\x83\0I\x83\0J\x83\0R\x83\0S\x83\0X\x83\0Y\x83\0w\x83\0x\x83\0\xCA\x83\0\xCB\x83\0\xCC\x83\0\xCD\x83\0\xD3\x83\0\xD4\x83\0\xDC\x83\0\xDD\x83\0\xEF\x83\0\xF0\x83\0\x0E\x84\0\x0F\x84\0=\x84\0>\x84\0I\x84\0J\x84\0W\x84\0X\x84\0[\x84\0\\\x84\0l\x84\0m\x84\0\xB8\x84\0\xB9\x84\0\xC4\x84\0\xC5\x84\0\xCB\x84\0\xCC\x84\0\x11\x85\0\x12\x85\x005\x85\x006\x85\0=\x85\0>\x85\0\x84\x85\0\x85\x85\0\xA6\x85\0\xA7\x85\0\xAA\x85\0\xAD\x85\0\xCD\x85\0\xCE\x85\0\xE4\x85\0\xE5\x85\0\xE9\x85\0\xEA\x85\0\xFB\x85\0\xFC\x85\0N\x86\0O\x86\0P\x86\0Q\x86\0Z\x86\0[\x86\0\\\x86\0]\x86\0^\x86\0_\x86\0k\x86\0l\x86\0y\x86\0z\x86\0\x8A\x86\0\x8B\x86\0\x95\x86\0\x96\x86\0\xC7\x86\0\xC8\x86\0\xCD\x86\0\xCE\x86\0\xEE\x86\0\xEF\x86\0\x02\x87\0\x03\x87\0\x1C\x87\0\x1D\x87\0\x8D\x87\0\x8E\x87\0@\x88\0A\x88\0F\x88\0G\x88\0L\x88\0M\x88\0S\x88\0T\x88\0W\x88\0X\x88\0[\x88\0\\\x88\0]\x88\0^\x88\0a\x88\0b\x88\0c\x88\0d\x88\0h\x88\0i\x88\0p\x88\0q\x88\0w\x88\0x\x88\0\x8B\x88\0\x8C\x88\0\x96\x88\0\x97\x88\0\xAB\x88\0\xAC\x88\0\xC1\x88\0\xC3\x88\0\xC5\x88\0\xC6\x88\0\xCF\x88\0\xD0\x88\0\xD5\x88\0\xD6\x88\0\xDC\x88\0\xDD\x88\0\xF8\x88\0\xF9\x88\0\xFD\x88\0\xFF\x88\0\x07\x89\0\x08\x89\0\x10\x89\0\x11\x89\0\x12\x89\0\x13\x89\0_\x89\0`\x89\0r\x89\0s\x89\0\x7F\x89\0\x80\x89\0\x81\x89\0\x82\x89\0\x86\x89\0\x88\x89\0\x8B\x89\0\x8C\x89\0\x8F\x89\0\x90\x89\0\x96\x89\0\x97\x89\0\x9A\x89\0\x9B\x89\0\xA7\x89\0\xA8\x89\0\xAA\x89\0\xAB\x89\0\xB3\x89\0\xB4\x89\0\xD2\x89\0\xD3\x89\0\xE3\x89\0\xE4\x89\0\xE6\x89\0\xE7\x89\0\0\x8A\0\x01\x8A\0\x02\x8A\0\x04\x8A\0\x08\x8A\0\t\x8A\0\x0E\x8A\0\x0F\x8A\0\x13\x8A\0\x14\x8A\0\x17\x8A\0\x19\x8A\0\x1F\x8A\0 \x8A\0*\x8A\0+\x8A\0-\x8A\0.\x8A\x001\x8A\x002\x8A\x003\x8A\x005\x8A\0:\x8A\0;\x8A\0<\x8A\0=\x8A\0P\x8A\0Q\x8A\0T\x8A\0V\x8A\0^\x8A\0_\x8A\0`\x8A\0a\x8A\0c\x8A\0d\x8A\0f\x8A\0g\x8A\0i\x8A\0j\x8A\0n\x8A\0o\x8A\0p\x8A\0t\x8A\0\x87\x8A\0\x88\x8A\0\x89\x8A\0\x8A\x8A\0\x8C\x8A\0\x8E\x8A\0\x93\x8A\0\x94\x8A\0\x95\x8A\0\x96\x8A\0\x98\x8A\0\x99\x8A\0\x9E\x8A\0\x9F\x8A\0\xA0\x8A\0\xA1\x8A\0\xA4\x8A\0\xA5\x8A\0\xAC\x8A\0\xAE\x8A\0\xB0\x8A\0\xB1\x8A\0\xB2\x8A\0\xB3\x8A\0\xBF\x8A\0\xC0\x8A\0\xC7\x8A\0\xC8\x8A\0\xCB\x8A\0\xCC\x8A\0\xD6\x8A\0\xD7\x8A\0\xE6\x8A\0\xE8\x8A\0\xED\x8A\0\xEF\x8A\0\xF8\x8A\0\xF9\x8A\0\xFE\x8A\0\xFF\x8A\0\0\x8B\0\x02\x8B\0\x04\x8B\0\x05\x8B\0\x0E\x8B\0\x0F\x8B\0\x19\x8B\0\x1A\x8B\0\x1B\x8B\0\x1C\x8B\0\x1D\x8B\0\x1E\x8B\0!\x8B\0\"\x8B\09\x8B\0:\x8B\0X\x8B\0Y\x8B\0\\\x8B\0]\x8B\0f\x8B\0g\x8B\0p\x8B\0q\x8B\0r\x8B\0s\x8B\0w\x8B\0x\x8B\x007\x8C\08\x8C\0F\x8C\0G\x8C\0J\x8C\0K\x8C\0Z\x8C\0[\x8C\0a\x8C\0b\x8C\0j\x8C\0k\x8C\0\x8C\x8C\0\x8D\x8C\0\x9D\x8C\0\x9F\x8C\0\xA0\x8C\0\xA3\x8C\0\xA7\x8C\0\xAD\x8C\0\xAF\x8C\0\xB0\x8C\0\xB4\x8C\0\xB5\x8C\0\xB7\x8C\0\xB9\x8C\0\xBB\x8C\0\xBD\x8C\0\xBF\x8C\0\xC1\x8C\0\xC2\x8C\0\xC5\x8C\0\xC7\x8C\0\xC8\x8C\0\xCA\x8C\0\xCB\x8C\0\xD3\x8C\0\xD4\x8C\0\xDB\x8C\0\xDD\x8C\0\xDE\x8C\0\xDF\x8C\0\xE0\x8C\0\xE1\x8C\0\xE2\x8C\0\xE3\x8C\0\xE6\x8C\0\xE7\x8C\0\xEA\x8C\0\xEB\x8C\0\xED\x8C\0\xEE\x8C\0\xFC\x8C\0\xFD\x8C\0\x08\x8D\0\t\x8D\0d\x8D\0e\x8D\0f\x8D\0g\x8D\0p\x8D\0q\x8D\0t\x8D\0u\x8D\0w\x8D\0x\x8D\0\x85\x8D\0\x86\x8D\0\x8A\x8D\0\x8B\x8D\0\xA3\x8D\0\xA4\x8D\0\xB3\x8D\0\xB4\x8D\0\xDD\x8D\0\xDE\x8D\0\xE1\x8D\0\xE2\x8D\0\xEF\x8D\0\xF0\x8D\0\xF3\x8D\0\xF4\x8D\0\xF5\x8D\0\xF6\x8D\0\n\x8E\0\x0B\x8E\0\x0F\x8E\0\x10\x8E\0*\x8E\0+\x8E\0t\x8E\0u\x8E\0\x8D\x8E\0\x8E\x8E\0\xAB\x8E\0\xAC\x8E\0\xCA\x8E\0\xCB\x8E\0\xCC\x8E\0\xCE\x8E\0\xD2\x8E\0\xD3\x8E\0\xDF\x8E\0\xE0\x8E\0\xE2\x8E\0\xE3\x8E\0\xF8\x8E\0\xF9\x8E\0\xFD\x8E\0\xFE\x8E\0\x03\x8F\0\x04\x8F\0\t\x8F\0\n\x8F\0\x1D\x8F\0\x1E\x8F\0)\x8F\0+\x8F\08\x8F\09\x8F\0D\x8F\0E\x8F\0\x9B\x8F\0\x9C\x8F\0\x9E\x8F\0\x9F\x8F\0\xA3\x8F\0\xA4\x8F\0\xB1\x8F\0\xB3\x8F\0\xBA\x8F\0\xBB\x8F\0\xBC\x8F\0\xBD\x8F\0\xC5\x8F\0\xC6\x8F\0\xCE\x8F\0\xCF\x8F\0\xD1\x8F\0\xD2\x8F\0\xD4\x8F\0\xD5\x8F\0\xEB\x8F\0\xEC\x8F\0\xED\x8F\0\xEE\x8F\0\xF0\x8F\0\xF1\x8F\0\xF7\x8F\0\xF8\x8F\0\xFD\x8F\0\xFE\x8F\0\0\x90\0\x02\x90\0\x03\x90\0\x04\x90\0\x06\x90\0\x07\x90\0\x0F\x90\0\x11\x90\0\x13\x90\0\x15\x90\0\x1A\x90\0\x1B\x90\0\x1D\x90\0\x1E\x90\0\x1F\x90\0!\x90\0#\x90\0$\x90\0.\x90\0/\x90\x001\x90\x003\x90\08\x90\09\x90\0B\x90\0C\x90\0E\x90\0F\x90\0G\x90\0H\x90\0J\x90\0L\x90\0M\x90\0O\x90\0S\x90\0V\x90\0\\\x90\0]\x90\0`\x90\0b\x90\0c\x90\0d\x90\0i\x90\0j\x90\0m\x90\0o\x90\0u\x90\0v\x90\0w\x90\0y\x90\0z\x90\0{\x90\0\x7F\x90\0\x80\x90\0\x84\x90\0\x85\x90\0\xA3\x90\0\xA4\x90\0\xA6\x90\0\xA7\x90\0\xAA\x90\0\xAB\x90\0\xB8\x90\0\xB9\x90\0\xCA\x90\0\xCB\x90\0\xCE\x90\0\xCF\x90\0\xE1\x90\0\xE2\x90\0\xE8\x90\0\xE9\x90\0\xED\x90\0\xEE\x90\0\xF5\x90\0\xF6\x90\0\xF7\x90\0\xF8\x90\0\xFD\x90\0\xFE\x90\0L\x91\0O\x91\0R\x91\0S\x91\0T\x91\0U\x91\0b\x91\0c\x91\0j\x91\0k\x91\0l\x91\0m\x91\0u\x91\0v\x91\0w\x91\0y\x91\0\x92\x91\0\x93\x91\0\x9C\x91\0\x9D\x91\0\xB8\x91\0\xB9\x91\0\xC7\x91\0\xC9\x91\0\xCC\x91\0\xD0\x91\0\xD1\x91\0\xD2\x91\0\xDC\x91\0\xDE\x91\0\xE3\x91\0\xE4\x91\0\r\x92\0\x0E\x92\x004\x92\x005\x92\0D\x92\0E\x92\0[\x92\0\\\x92\0b\x92\0c\x92\0q\x92\0r\x92\0\x80\x92\0\x81\x92\0\x83\x92\0\x84\x92\0\x85\x92\0\x86\x92\0\x98\x92\0\x99\x92\0\xAD\x92\0\xAE\x92\0\xED\x92\0\xEE\x92\0\xF3\x92\0\xF4\x92\0\xFC\x92\0\xFD\x92\0 \x93\0!\x93\0&\x93\0'\x93\0,\x93\0-\x93\0.\x93\x000\x93\x002\x93\x003\x93\0K\x93\0L\x93\0[\x93\0\\\x93\0u\x93\0v\x93\0\x8C\x93\0\x8D\x93\0\x96\x93\0\x97\x93\0\xAE\x93\0\xAF\x93\0\xE1\x93\0\xE2\x93\0\x18\x94\0\x19\x94\0Q\x94\0R\x94\0w\x95\0x\x95\0\x80\x95\0\x81\x95\0\x89\x95\0\x8A\x95\0\x8B\x95\0\x8C\x95\0\x91\x95\0\x92\x95\0\x93\x95\0\x94\x95\0\xA2\x95\0\xA4\x95\0\xA5\x95\0\xA6\x95\0\xB2\x95\0\xB3\x95\0\xC7\x95\0\xC8\x95\0\xD8\x95\0\xD9\x95\0\x1C\x96\0\x1D\x96\0*\x96\0+\x96\x002\x96\x003\x96\0;\x96\0<\x96\0D\x96\0E\x96\0M\x96\0N\x96\0P\x96\0Q\x96\0[\x96\0\\\x96\0b\x96\0f\x96\0j\x96\0k\x96\0p\x96\0q\x96\0s\x96\0t\x96\0u\x96\0w\x96\0x\x96\0y\x96\0z\x96\0{\x96\0}\x96\0~\x96\0\x85\x96\0\x87\x96\0\x8A\x96\0\x8B\x96\0\x8E\x96\0\x90\x96\0\x94\x96\0\x95\x96\0\x99\x96\0\x9A\x96\0\x9B\x96\0\x9D\x96\0\xA0\x96\0\xA1\x96\0\xA3\x96\0\xA4\x96\0\xB7\x96\0\xB8\x96\0\xBB\x96\0\xBC\x96\0\xC4\x96\0\xC8\x96\0\xCC\x96\0\xCD\x96\0\xD1\x96\0\xD2\x96\0\xE2\x96\0\xE4\x96\0\xE8\x96\0\xE9\x96\0\xEA\x96\0\xEB\x96\0\xF0\x96\0\xF1\x96\0\xF2\x96\0\xF3\x96\0\xF6\x96\0\xF8\x96\0\xFB\x96\0\xFC\x96\0\0\x97\0\x01\x97\0\x07\x97\0\x08\x97\0\n\x97\0\x0B\x97\0\x1C\x97\0\x1D\x97\0'\x97\0(\x97\x002\x97\x003\x97\0R\x97\0S\x97\0Y\x97\0Z\x97\0^\x97\0_\x97\0b\x97\0c\x97\0i\x97\0j\x97\0t\x97\0u\x97\0\xD3\x97\0\xD4\x97\0\xF3\x97\0\xF4\x97\0\xFB\x97\0\xFC\x97\0\xFF\x97\0\0\x98\0\x02\x98\0\x04\x98\0\x05\x98\0\x07\x98\0\x08\x98\0\t\x98\0\x10\x98\0\x14\x98\0\x18\x98\0\x19\x98\0,\x98\0.\x98\0;\x98\0=\x98\0L\x98\0O\x98\0T\x98\0V\x98\0X\x98\0Y\x98\0^\x98\0_\x98\0g\x98\0h\x98\0\xA8\x98\0\xA9\x98\0\xDB\x98\0\xDC\x98\0\xDF\x98\0\xE0\x98\0\xE2\x98\0\xE3\x98\0\xEF\x98\0\xF0\x98\0\xF2\x98\0\xF3\x98\0\xFC\x98\0\xFF\x98\0\x05\x99\0\x06\x99\0\n\x99\0\x0B\x99\0\x0C\x99\0\r\x99\0\x13\x99\0\x14\x99\0(\x99\0)\x99\0\x96\x99\0\x97\x99\0\x99\x99\0\x9A\x99\0\xAC\x99\0\xAD\x99\0\xC4\x99\0\xC7\x99\0\xD0\x99\0\xD1\x99\0\xD2\x99\0\xD3\x99\0\x0E\x9A\0\x0F\x9A\0\x12\x9A\0\x14\x9A\x000\x9A\x001\x9A\0Z\x9A\0[\x9A\0\xA8\x9A\0\xA9\x9A\0\xB8\x9A\0\xB9\x9A\0\xC4\x9A\0\xC5\x9A\0\xD8\x9A\0\xD9\x9A\0\xEA\x9A\0\xEB\x9A\x001\x9B\x002\x9B\0<\x9B\0=\x9B\0B\x9B\0C\x9B\0E\x9B\0F\x9B\0T\x9B\0U\x9B\0Z\x9B\0[\x9B\0\xAE\x9B\0\xAF\x9B\0\xE8\x9B\0\xE9\x9B\0\xE5\x9C\0\xE6\x9C\0\xF4\x9C\0\xF5\x9C\0\x8F\x9D\0\x90\x9D\0\xB4\x9D\0\xB5\x9D\0\x7F\x9E\0\x80\x9E\0\x93\x9E\0\x94\x9E\0\x97\x9E\0\x98\x9E\0\xA6\x9E\0\xA7\x9E\0\xBA\x9E\0\xBC\x9E\0\xC4\x9E\0\xC5\x9E\0\xD2\x9E\0\xD3\x9E\0\xD9\x9E\0\xDA\x9E\0\x13\x9F\0\x14\x9F\0;\x9F\0<\x9F\0b\x9F\0c\x9F\0") }, 2311u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0f\0\0g\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xE2\0\0\xE3\0\0\xE5\0\0\xE6\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD0\x10\0\xF1\x10\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0w\0\0x\0\0{\0\0\xF1\0\0\xF2\0\0") }, 24u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x04\0\x02\0\x04\0\x06\0djlhnhtx") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0b\0\0e\0\0l\0\0m\0\0q\0\0r\0\0w\0\0y\0\0z\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE9\0\0\xEA\0\0\xF3\0\0\xF4\0\0)\x01\0*\x01\0i\x01\0j\x01\0\xBD\x1E\0\xBE\x1E\0\xF9\x1E\0\xFA\x1E\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0V\x04\0W\x04\0\x93\x04\0\x94\x04\0\x9B\x04\0\x9C\x04\0\xA3\x04\0\xA4\x04\0\xAF\x04\0\xB0\x04\0\xB1\x04\0\xB2\x04\0\xBB\x04\0\xBC\x04\0\xD9\x04\0\xDA\x04\0\xE9\x04\0\xEA\x04\0") }, 42u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0\"\x06\0'\x06\0)\x06\0*\x06\0+\x06\0,\x06\0.\x06\0/\x06\x000\x06\x001\x06\x005\x06\09\x06\0:\x06\0A\x06\0G\x06\0H\x06\0K\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\xAD\x06\0\xAE\x06\0\xAF\x06\0\xB0\x06\0\xBE\x06\0\xBF\x06\0\xC6\x06\0\xC8\x06\0\xCB\x06\0\xCC\x06\0\xD5\x06\0\xD6\x06\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x80\x17\0\x9D\x17\0\x9F\x17\0\xA3\x17\0\xA5\x17\0\xA8\x17\0\xA9\x17\0\xB4\x17\0\xB6\x17\0\xCC\x17\0\xCD\x17\0\xCE\x17\0\xD0\x17\0\xD1\x17\0\xD2\x17\0\xD3\x17\0") }, 72u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x06\0\xE1\x9E\xA2\xE1\x9E\xB6\xE1\x9E\xA7\xE1\x9E\x80") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x82\x0C\0\x84\x0C\0\x85\x0C\0\x8D\x0C\0\x8E\x0C\0\x91\x0C\0\x92\x0C\0\xA9\x0C\0\xAA\x0C\0\xB4\x0C\0\xB5\x0C\0\xBA\x0C\0\xBC\x0C\0\xC5\x0C\0\xC6\x0C\0\xC9\x0C\0\xCA\x0C\0\xCE\x0C\0\xD5\x0C\0\xD7\x0C\0\xE0\x0C\0\xE2\x0C\0") }, 71u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\xAC\0\xA4\xD7\0") }, 11172u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\x0E\t\0\x0F\t\0\x12\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0<\t\0D\t\0E\t\0F\t\0G\t\0J\t\0K\t\0N\t\0P\t\0Q\t\0f\t\0p\t\0") }, 77u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x06\0\x0C\0\x12\0\x18\0\x1E\0$\0*\0\xE0\xA4\x95\xE0\xA4\xBC\xE0\xA4\x96\xE0\xA4\xBC\xE0\xA4\x97\xE0\xA4\xBC\xE0\xA4\x9C\xE0\xA4\xBC\xE0\xA4\xA1\xE0\xA4\xBC\xE0\xA4\xA2\xE0\xA4\xBC\xE0\xA4\xAB\xE0\xA4\xBC\xE0\xA4\xAF\xE0\xA4\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE3\0\0\xE4\0\0\xE7\0\0\xE8\0\0\xEA\0\0\xEB\0\0\xF1\0\0\xF2\0\0\xF4\0\0\xF6\0\0\xF8\0\0\xF9\0\0)\x01\0*\x01\0\xBD\x1E\0\xBE\x1E\0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b" \x06\0%\x06\0'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0G\x06\0H\x06\0I\x06\0r\x06\0s\x06\0y\x06\0z\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x88\x06\0\x89\x06\0\x91\x06\0\x92\x06\0\x98\x06\0\x99\x06\0\xA9\x06\0\xAA\x06\0\xAF\x06\0\xB0\x06\0\xBA\x06\0\xBB\x06\0\xBE\x06\0\xBF\x06\0\xC1\x06\0\xC2\x06\0\xC4\x06\0\xC5\x06\0\xC6\x06\0\xC7\x06\0\xCC\x06\0\xCD\x06\0\xD2\x06\0\xD3\x06\0") }, 46u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x03\t\0\x05\t\0\x0B\t\0\x0F\t\0\x10\t\0\x11\t\0\x12\t\0\x13\t\0\x14\t\0\x15\t\0\x18\t\0\x1A\t\0\x1D\t\0\x1F\t\0\"\t\0$\t\0'\t\0(\t\0)\t\0*\t\0-\t\0.\t\x001\t\x002\t\x003\t\x005\t\x007\t\08\t\0:\t\0<\t\0=\t\0>\t\0F\t\0G\t\0J\t\0K\t\0N\t\0") }, 50u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x06\0\xE0\xA4\x9A\xE0\xA4\xBC\xE0\xA4\x9B\xE0\xA4\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE7\0\0\xE8\0\0\xEA\0\0\xEB\0\0\xEE\0\0\xEF\0\0\xFB\0\0\xFC\0\0_\x01\0`\x01\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0f\0\0g\0\0q\0\0r\0\0w\0\0y\0\0z\0\0\xF1\0\0\xF2\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\0M\x01\0N\x01\0k\x01\0l\x01\0\r\x1E\0\x0E\x1E\x007\x1E\08\x1E\0E\x1E\0F\x1E\0G\x1E\0H\x1E\0[\x1E\0\\\x1E\0m\x1E\0n\x1E\0") }, 33u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0aa\xC4\x81\xC4\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\x0B\t\0\x0F\t\0\x10\t\0\x13\t\0\x14\t\0\x15\t\0\x16\t\0\x17\t\0\x18\t\0\x19\t\0\x1B\t\0\x1C\t\0\x1D\t\0\x1E\t\0 \t\0!\t\0\"\t\0#\t\0%\t\0&\t\0'\t\0(\t\0)\t\0*\t\0+\t\0,\t\0-\t\0.\t\x001\t\x002\t\x004\t\x005\t\x006\t\08\t\0:\t\0=\t\0C\t\0G\t\0H\t\0K\t\0L\t\0M\t\0N\t\0") }, 42u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x05\0\x06\0\x0C\0\x12\0\x18\0\xE0\xA4\x85\xE0\xA4\xBD\xE0\xA4\x86\xE0\xA4\xBD\xE0\xA4\x8F\xE0\xA4\xBD\xE0\xA4\x93\xE0\xA4\xBD\xE0\xA4\xA1\xE0\xA4\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x0B\0\x04\x0B\0\x05\x0B\0\x0B\x0B\0\x0F\x0B\0\x10\x0B\0\x15\x0B\0\x16\x0B\0\x17\x0B\0\x18\x0B\0\x19\x0B\0\x1B\x0B\0\x1C\x0B\0\x1D\x0B\0\x1E\x0B\0 \x0B\0!\x0B\0\"\x0B\0#\x0B\0%\x0B\0&\x0B\0'\x0B\0(\x0B\0)\x0B\0*\x0B\0+\x0B\0,\x0B\0-\x0B\0.\x0B\0/\x0B\x000\x0B\x001\x0B\x002\x0B\x004\x0B\08\x0B\0:\x0B\0<\x0B\0=\x0B\0>\x0B\0C\x0B\0G\x0B\0H\x0B\0M\x0B\0N\x0B\0_\x0B\0`\x0B\0q\x0B\0r\x0B\0") }, 40u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x04\0\x08\0\xE0\xAC\x85:\xE0\xAC\x86:\xE0\xAC\x8F:") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x0C\0\x04\x0C\0\x05\x0C\0\x0B\x0C\0\x0E\x0C\0\x10\x0C\0\x12\x0C\0\x14\x0C\0\x15\x0C\0\x16\x0C\0\x17\x0C\0\x18\x0C\0\x1A\x0C\0\x1B\x0C\0\x1C\x0C\0\x1D\x0C\0\x1E\x0C\0 \x0C\0!\x0C\0\"\x0C\0#\x0C\0%\x0C\0&\x0C\0'\x0C\0(\x0C\0)\x0C\0*\x0C\0+\x0C\0,\x0C\0-\x0C\0.\x0C\x001\x0C\x002\x0C\x003\x0C\x005\x0C\x006\x0C\08\x0C\0:\x0C\0>\x0C\0C\x0C\0F\x0C\0H\x0C\0J\x0C\0L\x0C\0M\x0C\0N\x0C\0") }, 43u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE0\xB0\xA1\xE0\xB0\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\x002\x04\x003\x04\0D\x04\0E\x04\0F\x04\0G\x04\0I\x04\0J\x04\0L\x04\0M\x04\0P\x04\0Q\x04\0R\x04\0\xA3\x04\0\xA4\x04\0\xAF\x04\0\xB0\x04\0\xE9\x04\0\xEA\x04\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE4\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE4\0\0\xE5\0\0\xE6\0\0\xED\0\0\xEE\0\0\xF0\0\0\xF1\0\0\xF5\0\0\xF6\0\0\xF7\0\0\xF9\0\0\xFA\0\0\xFB\0\0\xFD\0\0") }, 46u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x81\x0E\0\x83\x0E\0\x84\x0E\0\x85\x0E\0\x87\x0E\0\x89\x0E\0\x8A\x0E\0\x8B\x0E\0\x8D\x0E\0\x8E\x0E\0\x94\x0E\0\x98\x0E\0\x99\x0E\0\xA0\x0E\0\xA1\x0E\0\xA4\x0E\0\xA5\x0E\0\xA6\x0E\0\xA7\x0E\0\xA8\x0E\0\xAA\x0E\0\xAC\x0E\0\xAD\x0E\0\xBA\x0E\0\xBB\x0E\0\xBE\x0E\0\xC0\x0E\0\xC5\x0E\0\xC6\x0E\0\xC7\x0E\0\xC8\x0E\0\xCE\x0E\0\xDC\x0E\0\xDE\x0E\0") }, 55u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0y\0\0{\0\0\x05\x01\0\x06\x01\0\r\x01\0\x0E\x01\0\x17\x01\0\x18\x01\0\x19\x01\0\x1A\x01\0/\x01\x000\x01\0a\x01\0b\x01\0k\x01\0l\x01\0s\x01\0t\x01\0~\x01\0\x7F\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0z\0\0{\0\0\x01\x01\0\x02\x01\0\r\x01\0\x0E\x01\0\x13\x01\0\x14\x01\0#\x01\0$\x01\0+\x01\0,\x01\x007\x01\08\x01\0<\x01\0=\x01\0F\x01\0G\x01\0a\x01\0b\x01\0k\x01\0l\x01\0~\x01\0\x7F\x01\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\t\0\x04\t\0\x15\t\0\x19\t\0\x1A\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0<\t\0=\t\0>\t\0C\t\0G\t\0I\t\0K\t\0M\t\0") }, 44u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x05\0\t\0\x12\0\x18\0!\0\xE0\xA4\x95\xE0\xA5\x8D\xE0\xA4\xB7\xE0\xA4\x9C\xE0\xA5\x8D\xE0\xA4\x9E\xE0\xA4\xA1\xE0\xA4\x82\xE0\xA4\xA4\xE0\xA5\x8D\xE0\xA4\xB0\xE0\xA4\xB6\xE0\xA5\x8D\xE0\xA4\xB0") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0b\0\0e\0\0f\0\0h\0\0j\0\0k\0\0l\0\0m\0\0q\0\0r\0\0s\0\0t\0\0v\0\0w\0\0x\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\0M\x01\0N\x01\0k\x01\0l\x01\0") }, 18u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0ngwh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\09\x04\0:\x04\0I\x04\0S\x04\0T\x04\0U\x04\0V\x04\0X\x04\0[\x04\0\\\x04\0]\x04\0_\x04\0`\x04\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x05\r\0\x0C\r\0\x0E\r\0\x11\r\0\x12\r\0)\r\0*\r\0:\r\0") }, 49u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x06\0\xE0\xB4\x85\xE0\xB4\x82\xE0\xB4\x85\xE0\xB4\x83") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0\xAF\x04\0\xB0\x04\0\xE9\x04\0\xEA\x04\0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x81\t\0\x84\t\0\x85\t\0\x8C\t\0\x8F\t\0\x91\t\0\x93\t\0\xA9\t\0\xAA\t\0\xB1\t\0\xB2\t\0\xB3\t\0\xB6\t\0\xBA\t\0\xBC\t\0\xBD\t\0\xBE\t\0\xC4\t\0\xC7\t\0\xC9\t\0\xCB\t\0\xCE\t\0\xF1\t\0\xF2\t\0") }, 59u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x06\0\x0C\0\xE0\xA6\xA1\xE0\xA6\xBC\xE0\xA6\xA2\xE0\xA6\xBC\xE0\xA6\xAF\xE0\xA6\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\t\0\x04\t\0\x05\t\0\r\t\0\x0F\t\0\x12\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0=\t\0D\t\0E\t\0F\t\0G\t\0J\t\0K\t\0N\t\0P\t\0Q\t\0") }, 64u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\t\0\xE0\xA4\x95\xE0\xA5\x8D\xE0\xA4\xB7\xE0\xA4\x9C\xE0\xA5\x8D\xE0\xA4\x9E") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0y\0\0z\0\0{\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xE9\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0\x0B\x01\0\x0C\x01\0!\x01\0\"\x01\0'\x01\0(\x01\0|\x01\0}\x01\0") }, 33u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0g\xC4\xA7") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x10\0\"\x10\0#\x10\0(\x10\0)\x10\x003\x10\x006\x10\0@\x10\0O\x10\0P\x10\0") }, 60u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE4\0\0\xE6\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE2\0\0\xE4\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF0\0\0\xF3\0\0\xF4\0\0\xF6\0\0\xF7\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0") }, 36u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x02\0ij\xC3\xADj\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE1\0\0\xE5\0\0\xE7\0\0\xE9\0\0\xEA\0\0\xF2\0\0\xF5\0\0\xF8\0\0\xF9\0\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xCA\x07\0\xE8\x07\0\xEB\x07\0\xF6\x07\0") }, 41u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0z\0\0\xEA\0\0\xEB\0\0\xF4\0\0\xF5\0\0a\x01\0b\x01\0") }, 25u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE2\0\0\xE7\0\0\xEA\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF0\0\0\xF2\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xFC\0\0\xFD\0\0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x0B\0\x04\x0B\0\x05\x0B\0\x0C\x0B\0\x0F\x0B\0\x11\x0B\0\x13\x0B\0)\x0B\0*\x0B\x001\x0B\x002\x0B\x004\x0B\x005\x0B\0:\x0B\0<\x0B\0=\x0B\0>\x0B\0D\x0B\0G\x0B\0I\x0B\0K\x0B\0N\x0B\0_\x0B\0`\x0B\0q\x0B\0r\x0B\0") }, 62u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\t\0\x0F\0\xE0\xAC\x95\xE0\xAD\x8D\xE0\xAC\xB7\xE0\xAC\xA1\xE0\xAC\xBC\xE0\xAC\xA2\xE0\xAC\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\n\0\x03\n\0\x05\n\0\x0B\n\0\x0F\n\0\x11\n\0\x13\n\0)\n\0*\n\x001\n\x002\n\x003\n\x005\n\x006\n\08\n\0:\n\0<\n\0=\n\0>\n\0C\n\0G\n\0I\n\0K\n\0N\n\0\\\n\0]\n\0f\n\0u\n\0") }, 69u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x06\0\x06\0\x0C\0\x12\0\x18\0\x1E\0\xE0\xA8\x96\xE0\xA8\xBC\xE0\xA8\x97\xE0\xA8\xBC\xE0\xA8\x9C\xE0\xA8\xBC\xE0\xA8\xAB\xE0\xA8\xBC\xE0\xA8\xB2\xE0\xA8\xBC\xE0\xA8\xB8\xE0\xA8\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0{\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0\xB9\x1E\0\xBA\x1E\0\xCD\x1E\0\xCE\x1E\0") }, 30u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x07\0\x02\0\x04\0\x06\0\x08\0\n\0\x0F\0chgbkpshzh\xE1\xBA\xB9\xCC\x81\xE1\xBB\x8D\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0{\0\0\xF3\0\0\xF4\0\0\x05\x01\0\x06\x01\0\x07\x01\0\x08\x01\0\x19\x01\0\x1A\x01\0B\x01\0C\x01\0D\x01\0E\x01\0[\x01\0\\\x01\0z\x01\0{\x01\0|\x01\0}\x01\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0h\0\0i\0\0k\0\0l\0\0w\0\0z\0\0{\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xEA\0\0\xEB\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 28u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0F\0cccheuggghn-s-css") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0%\x06\0&\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0J\x06\0S\x06\0T\x06\0U\x06\0p\x06\0q\x06\0|\x06\0}\x06\0~\x06\0\x7F\x06\0\x81\x06\0\x82\x06\0\x85\x06\0\x87\x06\0\x89\x06\0\x8A\x06\0\x93\x06\0\x94\x06\0\x96\x06\0\x97\x06\0\x98\x06\0\x99\x06\0\x9A\x06\0\x9B\x06\0\xA9\x06\0\xAA\x06\0\xAB\x06\0\xAC\x06\0\xAF\x06\0\xB0\x06\0\xBC\x06\0\xBD\x06\0\xCC\x06\0\xCE\x06\0\xD0\x06\0\xD1\x06\0") }, 60u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0%\x06\0&\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0J\x06\0S\x06\0T\x06\0U\x06\0p\x06\0q\x06\0|\x06\0}\x06\0~\x06\0\x7F\x06\0\x81\x06\0\x82\x06\0\x85\x06\0\x87\x06\0\x89\x06\0\x8A\x06\0\x93\x06\0\x94\x06\0\x96\x06\0\x97\x06\0\x98\x06\0\x99\x06\0\x9A\x06\0\x9B\x06\0\xA9\x06\0\xAA\x06\0\xAB\x06\0\xAC\x06\0\xAF\x06\0\xB0\x06\0\xBC\x06\0\xBD\x06\0\xCC\x06\0\xCE\x06\0\xD0\x06\0\xD1\x06\0\xD2\x06\0\xD3\x06\0") }, 61u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE4\0\0\xE7\0\0\xE8\0\0\xE9\0\0\xEB\0\0\xED\0\0\xEE\0\0\xF2\0\0\xF6\0\0\xFA\0\0\xFB\0\0") }, 39u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0b\0\0h\0\0j\0\0k\0\0o\0\0p\0\0r\0\0s\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xF1\0\0\xF2\0\0") }, 15u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x07\0\x02\0\x06\0\t\0\x0B\0\x0E\0\x11\0chch\xCA\xBCk\xCA\xBCllp\xCA\xBCq\xCA\xBCt\xCA\xBC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\x06\t\0\x15\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0>\t\0D\t\0E\t\0F\t\0G\t\0I\t\0K\t\0N\t\0") }, 49u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE2\0\0\xE3\0\0\xEE\0\0\xEF\0\0\x03\x01\0\x04\x01\0\x19\x02\0\x1A\x02\0\x1B\x02\0\x1C\x02\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\r\t\0\x0F\t\0\x11\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\0:\t\0<\t\0E\t\0G\t\0I\t\0K\t\0N\t\0P\t\0S\t\0`\t\0d\t\0") }, 70u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\x002\x04\x003\x04\x005\x04\08\x04\0D\x04\0E\x04\0F\x04\0G\x04\0H\x04\0K\x04\0L\x04\0M\x04\0N\x04\0\x95\x04\0\x96\x04\0\xA5\x04\0\xA6\x04\0\xAF\x04\0\xB0\x04\0\xBB\x04\0\xBC\x04\0\xE9\x04\0\xEA\x04\0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x04\0\xD0\xB4\xD1\x8C\xD0\xBD\xD1\x8C") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"Z\x1C\0~\x1C\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0k\0\0l\0\0q\0\0r\0\0w\0\0z\0\0{\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xE9\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF3\0\0\xF9\0\0\xFA\0\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0k\0\0l\0\0w\0\0z\0\0{\0\0\xE0\0\0\xE1\0\0\xE2\0\0\xE3\0\0\xE8\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0\xED\0\0\xEE\0\0\xEF\0\0\xF2\0\0\xF3\0\0\xF4\0\0\xF5\0\0\xF9\0\0\xFA\0\0\xFB\0\0\xFC\0\0\r\x1E\0\x0E\x1E\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0#\x06\0'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0I\x06\0J\x06\0K\x06\0z\x06\0|\x06\0}\x06\0\x81\x06\0\x83\x06\0\x85\x06\0\x86\x06\0\x88\x06\0\x8A\x06\0\x8B\x06\0\x8C\x06\0\x8E\x06\0\x8F\x06\0\x90\x06\0\x99\x06\0\x9A\x06\0\xA6\x06\0\xA7\x06\0\xA9\x06\0\xAB\x06\0\xAF\x06\0\xB0\x06\0\xB1\x06\0\xB2\x06\0\xB3\x06\0\xB4\x06\0\xBB\x06\0\xBC\x06\0\xBE\x06\0\xBF\x06\0") }, 52u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x04\0\xD8\xAC\xDA\xBE\xDA\xAF\xDA\xBE") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x02\t\0\x03\t\0\x05\t\0\x0B\t\0\x0F\t\0\x11\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x003\t\x005\t\0:\t\0<\t\0=\t\0>\t\0F\t\0G\t\0J\t\0K\t\0N\t\0{\t\0}\t\0~\t\0\x80\t\0") }, 63u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x04\x10\0\x05\x10\0\x10\x10\0\x12\x10\0\x15\x10\0\x16\x10\0\x19\x10\0\x1F\x10\0\"\x10\0#\x10\0-\x10\x002\x10\x005\x10\x007\x10\08\x10\09\x10\0:\x10\0>\x10\0b\x10\0c\x10\0u\x10\0y\x10\0z\x10\0\x8B\x10\0\x9E\x10\0\xA0\x10\0\xE0\xA9\0\xE1\xA9\0\xE3\xA9\0\xE6\xA9\0a\xAA\0b\xAA\0f\xAA\0k\xAA\0n\xAA\0o\xAA\0") }, 58u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x82\r\0\x84\r\0\x85\r\0\x8E\r\0\x91\r\0\x97\r\0\x9A\r\0\xA6\r\0\xA7\r\0\xB2\r\0\xB3\r\0\xBC\r\0\xBD\r\0\xBE\r\0\xC0\r\0\xC7\r\0\xCA\r\0\xCB\r\0\xCF\r\0\xD5\r\0\xD6\r\0\xD7\r\0\xD8\r\0\xE0\r\0\xF2\r\0\xF3\r\0") }, 74u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE1\0\0\xE2\0\0\xE4\0\0\xE5\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF5\0\0\xFA\0\0\xFB\0\0\xFD\0\0\xFE\0\0\r\x01\0\x0E\x01\0\x0F\x01\0\x10\x01\0:\x01\0;\x01\0>\x01\0?\x01\0H\x01\0I\x01\0U\x01\0V\x01\0a\x01\0b\x01\0e\x01\0f\x01\0~\x01\0\x7F\x01\0") }, 43u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x03\0\x02\0\x04\0chdzd\xC5\xBE") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0z\0\0{\0\0\r\x01\0\x0E\x01\0a\x01\0b\x01\0~\x01\0\x7F\x01\0") }, 25u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"b\0\0e\0\0f\0\0i\0\0j\0\0o\0\0q\0\0u\0\0w\0\0z\0\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0w\0\0x\0\0{\0\0\xE7\0\0\xE8\0\0\xEB\0\0\xEC\0\0") }, 27u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\t\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0dhgjllnjrrshthxhzh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0v\0\0w\0\0x\0\0y\0\0z\0\0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE9\0\0\xEA\0\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0\xE0\0\0\xE1\0\0\xE4\0\0\xE6\0\0\xE9\0\0\xEA\0\0\xF6\0\0\xF7\0\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0x\0\0y\0\0{\0\0") }, 23u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0ch") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0x\0\0y\0\0{\0\0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x07\0\x0E\x07\0\x10\x07\0-\x07\x000\x07\0K\x07\0") }, 70u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0{\0\0\xE3\0\0\xE4\0\0\xF4\0\0\xF6\0\0\x07\x01\0\x08\x01\0B\x01\0C\x01\0D\x01\0E\x01\0M\x01\0N\x01\0O\x01\0P\x01\0[\x01\0\\\x01\0z\x01\0{\x01\0|\x01\0}\x01\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x83\x0B\0\x84\x0B\0\x85\x0B\0\x8B\x0B\0\x8E\x0B\0\x91\x0B\0\x92\x0B\0\x96\x0B\0\x99\x0B\0\x9B\x0B\0\x9C\x0B\0\x9D\x0B\0\x9E\x0B\0\xA0\x0B\0\xA3\x0B\0\xA5\x0B\0\xA8\x0B\0\xAB\x0B\0\xAE\x0B\0\xB6\x0B\0\xB7\x0B\0\xBA\x0B\0\xBE\x0B\0\xC3\x0B\0\xC6\x0B\0\xC9\x0B\0\xCA\x0B\0\xCE\x0B\0") }, 47u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x0C\0\x04\x0C\0\x05\x0C\0\r\x0C\0\x0E\x0C\0\x11\x0C\0\x12\x0C\0)\x0C\0*\x0C\x004\x0C\x005\x0C\0:\x0C\0>\x0C\0E\x0C\0F\x0C\0I\x0C\0J\x0C\0N\x0C\0U\x0C\0W\x0C\0`\x0C\0b\x0C\0") }, 70u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0F\x04\0G\x04\0I\x04\0J\x04\0K\x04\0M\x04\0P\x04\0Q\x04\0R\x04\0\x93\x04\0\x94\x04\0\x9B\x04\0\x9C\x04\0\xB3\x04\0\xB4\x04\0\xB7\x04\0\xB8\x04\0\xE3\x04\0\xE4\x04\0\xEF\x04\0\xF0\x04\0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\x0E\0;\x0E\0@\x0E\0O\x0E\0") }, 73u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0\x12\0\x07\x12\0\x08\x12\0G\x12\0H\x12\0I\x12\0J\x12\0N\x12\0P\x12\0W\x12\0X\x12\0Y\x12\0Z\x12\0^\x12\0`\x12\0\x87\x12\0\x88\x12\0\x89\x12\0\x8A\x12\0\x8E\x12\0\x90\x12\0\xAF\x12\0\xB0\x12\0\xB1\x12\0\xB2\x12\0\xB6\x12\0\xB8\x12\0\xBF\x12\0\xC0\x12\0\xC1\x12\0\xC2\x12\0\xC6\x12\0\xC8\x12\0\xCF\x12\0\xD0\x12\0\xD7\x12\0\xD8\x12\0\xEF\x12\0\xF0\x12\0\xF8\x12\0\0\x13\0\x0F\x13\0\x10\x13\0\x11\x13\0\x12\x13\0\x16\x13\0 \x13\0X\x13\0_\x13\0`\x13\0") }, 301u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0{\0\0\xE4\0\0\xE5\0\0\xE7\0\0\xE8\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFE\0\0H\x01\0I\x01\0_\x01\0`\x01\0~\x01\0\x7F\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xEA\0\0\xEB\0\0\xF4\0\0\xF5\0\0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0b\0\0e\0\0g\0\0h\0\0j\0\0k\0\0q\0\0s\0\0w\0\0\xE1\0\0\xE2\0\0\xE9\0\0\xEA\0\0\xED\0\0\xEE\0\0\xF3\0\0\xF4\0\0\xFA\0\0\xFB\0\0\x01\x01\0\x02\x01\0\x13\x01\0\x14\x01\0+\x01\0,\x01\0M\x01\0N\x01\0k\x01\0l\x01\0\xBB\x02\0\xBC\x02\0") }, 26u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0ng") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0q\0\0r\0\0w\0\0y\0\0{\0\0\xE7\0\0\xE8\0\0\xF6\0\0\xF7\0\0\xFC\0\0\xFD\0\0\x1F\x01\0 \x01\x000\x01\x002\x01\0_\x01\0`\x01\0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0\x97\x04\0\x98\x04\0\xA3\x04\0\xA4\x04\0\xAF\x04\0\xB0\x04\0\xBB\x04\0\xBC\x04\0\xD9\x04\0\xDA\x04\0\xE9\x04\0\xEA\x04\0") }, 39u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0P\x04\0Q\x04\0R\x04\0\xA3\x04\0\xA4\x04\0\xAF\x04\0\xB0\x04\0\xE9\x04\0\xEA\x04\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"'\x06\0)\x06\0*\x06\0+\x06\0,\x06\0-\x06\0.\x06\x000\x06\x001\x06\x005\x06\0:\x06\0;\x06\0A\x06\0G\x06\0H\x06\0K\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x98\x06\0\x99\x06\0\xAD\x06\0\xAE\x06\0\xAF\x06\0\xB0\x06\0\xBE\x06\0\xBF\x06\0\xC6\x06\0\xC9\x06\0\xCB\x06\0\xCC\x06\0\xD0\x06\0\xD1\x06\0\xD5\x06\0\xD6\x06\0") }, 32u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x04\0\x08\0\x0C\0\x10\0\x14\0\x18\0\x1C\0\xD8\xA6\xD8\xA7\xD8\xA6\xD9\x87\xD8\xA6\xD9\x88\xD8\xA6\xD9\x89\xD8\xA6\xDB\x86\xD8\xA6\xDB\x87\xD8\xA6\xDB\x88\xD8\xA6\xDB\x90") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xBC\x02\0\xBD\x02\x000\x04\0J\x04\0L\x04\0M\x04\0N\x04\0P\x04\0T\x04\0U\x04\0V\x04\0X\x04\0\x91\x04\0\x92\x04\0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(zerovec::ZeroVec::new(), 0u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\x06\0\"\x06\0'\x06\0)\x06\0*\x06\0;\x06\0A\x06\0C\x06\0D\x06\0G\x06\0H\x06\0I\x06\0y\x06\0z\x06\0~\x06\0\x7F\x06\0\x86\x06\0\x87\x06\0\x88\x06\0\x89\x06\0\x91\x06\0\x92\x06\0\x98\x06\0\x99\x06\0\xA9\x06\0\xAA\x06\0\xAF\x06\0\xB0\x06\0\xBE\x06\0\xBF\x06\0\xC1\x06\0\xC2\x06\0\xCC\x06\0\xCD\x06\0\xD2\x06\0\xD3\x06\0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0w\0\0x\0\0{\0\0\xBC\x02\0\xBD\x02\0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x04\0\x02\0\x05\0\x08\0chg\xCA\xBBo\xCA\xBBsh") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"0\x04\0F\x04\0G\x04\0I\x04\0J\x04\0K\x04\0M\x04\0P\x04\0Q\x04\0R\x04\0^\x04\0_\x04\0\x93\x04\0\x94\x04\0\x9B\x04\0\x9C\x04\0\xB3\x04\0\xB4\x04\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0k\0\0l\0\0q\0\0r\0\0w\0\0x\0\0y\0\0z\0\0{\0\0\xE0\0\0\xE1\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xED\0\0\xF2\0\0\xF4\0\0\xF9\0\0\xFA\0\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0f\0\0g\0\0j\0\0k\0\0w\0\0x\0\0z\0\0\xE0\0\0\xE4\0\0\xE8\0\0\xEB\0\0\xEC\0\0\xEE\0\0\xF2\0\0\xF6\0\0\xF9\0\0\xFB\0\0\xFD\0\0\xFE\0\0\x03\x01\0\x04\x01\0\x11\x01\0\x12\x01\0)\x01\0*\x01\0i\x01\0j\x01\0\xA1\x01\0\xA2\x01\0\xB0\x01\0\xB1\x01\0\xA1\x1E\0\xA2\x1E\0\xA3\x1E\0\xA4\x1E\0\xA5\x1E\0\xA6\x1E\0\xA7\x1E\0\xA8\x1E\0\xA9\x1E\0\xAA\x1E\0\xAB\x1E\0\xAC\x1E\0\xAD\x1E\0\xAE\x1E\0\xAF\x1E\0\xB0\x1E\0\xB1\x1E\0\xB2\x1E\0\xB3\x1E\0\xB4\x1E\0\xB5\x1E\0\xB6\x1E\0\xB7\x1E\0\xB8\x1E\0\xB9\x1E\0\xBA\x1E\0\xBB\x1E\0\xBC\x1E\0\xBD\x1E\0\xBE\x1E\0\xBF\x1E\0\xC0\x1E\0\xC1\x1E\0\xC2\x1E\0\xC3\x1E\0\xC4\x1E\0\xC5\x1E\0\xC6\x1E\0\xC7\x1E\0\xC8\x1E\0\xC9\x1E\0\xCA\x1E\0\xCB\x1E\0\xCC\x1E\0\xCD\x1E\0\xCE\x1E\0\xCF\x1E\0\xD0\x1E\0\xD1\x1E\0\xD2\x1E\0\xD3\x1E\0\xD4\x1E\0\xD5\x1E\0\xD6\x1E\0\xD7\x1E\0\xD8\x1E\0\xD9\x1E\0\xDA\x1E\0\xDB\x1E\0\xDC\x1E\0\xDD\x1E\0\xDE\x1E\0\xDF\x1E\0\xE0\x1E\0\xE1\x1E\0\xE2\x1E\0\xE3\x1E\0\xE4\x1E\0\xE5\x1E\0\xE6\x1E\0\xE7\x1E\0\xE8\x1E\0\xE9\x1E\0\xEA\x1E\0\xEB\x1E\0\xEC\x1E\0\xED\x1E\0\xEE\x1E\0\xEF\x1E\0\xF0\x1E\0\xF1\x1E\0\xF2\x1E\0\xF3\x1E\0\xF4\x1E\0\xF5\x1E\0\xF6\x1E\0\xF7\x1E\0\xF8\x1E\0\xF9\x1E\0\xFA\x1E\0") }, 89u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0b\0\0c\0\0d\0\0e\0\0g\0\0h\0\0q\0\0r\0\0{\0\0") }, 22u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x05\0\x02\0\x04\0\x06\0\x08\0khphthtttth") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0h\0\0i\0\0v\0\0w\0\0z\0\0\xE0\0\0\xE1\0\0\xE9\0\0\xEA\0\0\xEB\0\0\xEC\0\0\xF1\0\0\xF2\0\0\xF3\0\0\xF4\0\0K\x01\0L\x01\0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x01\t\0\x04\t\0\x05\t\0\x0B\t\0\r\t\0\x0E\t\0\x0F\t\0\x12\t\0\x13\t\0)\t\0*\t\x001\t\x002\t\x004\t\x005\t\x007\t\08\t\0:\t\0<\t\0D\t\0E\t\0F\t\0G\t\0J\t\0K\t\0N\t\0P\t\0Q\t\0\x0C \0\x0E \0") }, 66u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xE0\0\0\xE2\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xEE\0\0\xF2\0\0\xF4\0\0\xF9\0\0\xFB\0\0D\x01\0E\x01\0\xF9\x01\0\xFA\x01\0?\x1E\0@\x1E\0c\x1E\0d\x1E\0\xB9\x1E\0\xBA\x1E\0\xCD\x1E\0\xCE\x1E\0") }, 37u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x08\0\x02\0\x05\0\x08\0\x0B\0\x10\0\x15\0\x1A\0gbm\xCC\x80m\xCC\x84n\xCC\x84\xE1\xBA\xB9\xCC\x80\xE1\xBA\xB9\xCC\x81\xE1\xBB\x8D\xCC\x80\xE1\xBB\x8D\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0q\0\0r\0\0v\0\0w\0\0x\0\0y\0\0z\0\0\xE0\0\0\xE2\0\0\xE8\0\0\xEA\0\0\xEC\0\0\xEE\0\0\xF2\0\0\xF4\0\0\xF9\0\0\xFB\0\0T\x02\0U\x02\0[\x02\0\\\x02\0") }, 33u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x06\0\x02\0\x04\0\x08\0\x0C\0\x10\0gbsh\xC9\x94\xCC\x80\xC9\x94\xCC\x81\xC9\x9B\xCC\x80\xC9\x9B\xCC\x81") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0c\0\0d\0\0f\0\0g\0\0h\0\0i\0\0j\0\0k\0\0l\0\0m\0\0o\0\0p\0\0q\0\0r\0\0v\0\0w\0\0z\0\0\xE3\0\0\xE4\0\0)\x01\0*\x01\0i\x01\0j\x01\0\xBD\x1E\0\xBE\x1E\0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0N\0\x02N\0\x03N\0\x04N\0\x08N\0\x0EN\0\x11N\0\x12N\0\x14N\0\x15N\0\x16N\0\x17N\0\x18N\0\x1AN\0\x1FN\0 N\0&N\0'N\0-N\0.N\x002N\x003N\08N\0:N\0;N\0<N\0CN\0DN\0EN\0FN\0HN\0IN\0KN\0LN\0NN\0PN\0VN\0WN\0XN\0ZN\0]N\0^N\0_N\0`N\0~N\0\x7FN\0\x82N\0\x83N\0\x86N\0\x87N\0\x88N\0\x89N\0\x8BN\0\x8DN\0\x8EN\0\x8FN\0\x91N\0\x93N\0\x94N\0\x96N\0\x9BN\0\x9CN\0\x9EN\0\x9FN\0\xA1N\0\xA2N\0\xA4N\0\xA7N\0\xA8N\0\xA9N\0\xABN\0\xADN\0\xAEN\0\xAFN\0\xBAN\0\xBBN\0\xC0N\0\xC2N\0\xC7N\0\xC8N\0\xCAN\0\xCCN\0\xCDN\0\xCEN\0\xD4N\0\xD5N\0\xD6N\0\xD7N\0\xD8N\0\xDAN\0\xE3N\0\xE6N\0\xF0N\0\xF1N\0\xF2N\0\xF3N\0\xF6N\0\xF7N\0\xFBN\0\xFCN\0\xFDN\0\xFEN\0\x01O\0\x02O\0\nO\0\x0BO\0\rO\0\x0EO\0\x10O\0\x12O\0\x19O\0\x1AO\0/O\x001O\x004O\x005O\08O\09O\0<O\0>O\0FO\0GO\0HO\0JO\0MO\0PO\0TO\0VO\0YO\0ZO\0[O\0]O\0`O\0aO\0iO\0jO\0sO\0tO\0\x7FO\0\x80O\0\x86O\0\x87O\0\x8BO\0\x8CO\0\x9BO\0\x9CO\0\x9DO\0\x9EO\0\xAFO\0\xB0O\0\xB5O\0\xB6O\0\xBFO\0\xC0O\0\xC2O\0\xC5O\0\xCAO\0\xCBO\0\xCFO\0\xD0O\0\xD7O\0\xD8O\0\xDDO\0\xDEO\0\xE0O\0\xE2O\0\xEEO\0\xEFO\0\xF1O\0\xF2O\0\xFEO\0\xFFO\0\tP\0\nP\0\x0BP\0\x0CP\0\rP\0\x0EP\0\x11P\0\x13P\0\x19P\0\x1BP\0\x1FP\0 P\0+P\0,P\0<P\0=P\0GP\0HP\0IP\0JP\0OP\0PP\0ZP\0[P\0\\P\0]P\0eP\0fP\0tP\0xP\0}P\0~P\0\x85P\0\x86P\0\x91P\0\x92P\0\x98P\0\x9AP\0\xA2P\0\xA4P\0\xB2P\0\xB4P\0\xB7P\0\xB8P\0\xBBP\0\xBCP\0\xBEP\0\xBFP\0\xC5P\0\xC6P\0\xCFP\0\xD0P\0\xD1P\0\xD2P\0\xE7P\0\xE8P\0\xF9P\0\xFAP\0\0Q\0\x01Q\0\x04Q\0\x05Q\0\x12Q\0\x13Q\0\x18Q\0\x19Q\0*Q\0+Q\0AQ\0BQ\0CQ\0FQ\0GQ\0JQ\0KQ\0LQ\0MQ\0NQ\0RQ\0SQ\0TQ\0UQ\0eQ\0fQ\0gQ\0jQ\0kQ\0oQ\0qQ\0rQ\0uQ\0yQ\0|Q\0}Q\0\x8AQ\0\x8BQ\0\x8DQ\0\x8EQ\0\x92Q\0\x93Q\0\xA0Q\0\xA1Q\0\xACQ\0\xADQ\0\xB0Q\0\xB1Q\0\xB7Q\0\xB8Q\0\xC6Q\0\xC7Q\0\xCBQ\0\xCEQ\0\xDDQ\0\xDEQ\0\xE1Q\0\xE2Q\0\xF0Q\0\xF2Q\0\xFAQ\0\xFBQ\0\xFDQ\0\xFEQ\0\0R\0\x01R\0\x06R\0\x08R\0\nR\0\x0BR\0\x17R\0\x18R\0\x1DR\0\x1ER\0$R\0&R\0(R\0+R\0.R\0/R\x000R\x001R\x006R\08R\0:R\0<R\0CR\0DR\0GR\0HR\0LR\0NR\0[R\0\\R\0iR\0kR\0oR\0pR\0rR\0sR\0uR\0vR\0\x83R\0\x84R\0\x87R\0\x88R\0\x89R\0\x8AR\0\x8DR\0\x8ER\0\x9BR\0\x9CR\0\x9FR\0\xA1R\0\xA9R\0\xACR\0\xC1R\0\xC2R\0\xC7R\0\xC8R\0\xC9R\0\xCAR\0\xD2R\0\xD3R\0\xD5R\0\xD6R\0\xD9R\0\xDAR\0\xDDR\0\xDFR\0\xE2R\0\xE3R\0\xE4R\0\xE5R\0\xF5R\0\xF6R\0\xF8R\0\xF9R\0\xFER\0\0S\0\x05S\0\x06S\0\x08S\0\tS\0\x16S\0\x18S\0/S\x000S\09S\0:S\0@S\0BS\0CS\0DS\0GS\0IS\0JS\0KS\0RS\0US\0WS\0XS\0ZS\0[S\0\\S\0]S\0aS\0bS\0oS\0rS\0sS\0tS\0wS\0xS\0yS\0zS\0{S\0|S\0\x84S\0\x85S\0\x98S\0\x99S\0\x9AS\0\x9BS\0\x9FS\0\xA0S\0\xADS\0\xAES\0\xB2S\0\xB3S\0\xBBS\0\xBCS\0\xC3S\0\xC4S\0\xC8S\0\xC9S\0\xCAS\0\xCCS\0\xCDS\0\xCES\0\xD4S\0\xD5S\0\xD6S\0\xD8S\0\xE3S\0\xE7S\0\xEAS\0\xEES\0\xEFS\0\xF1S\0\xF2S\0\xF4S\0\xF8S\0\xF9S\0\x03T\0\x05T\0\x08T\0\x0BT\0\x0CT\0\x0FT\0\x10T\0\x13T\0\x1BT\0\x1CT\0\x1DT\0!T\0&T\0(T\0+T\0,T\x003T\x004T\x005T\x006T\08T\0:T\0>T\0?T\0@T\0AT\0BT\0CT\0FT\0GT\0JT\0KT\0bT\0cT\0hT\0iT\0sT\0tT\0uT\0vT\0|T\0~T\0\x8CT\0\x8DT\0\x96T\0\x97T\0\xA6T\0\xA8T\0\xAAT\0\xABT\0\xACT\0\xADT\0\xB1T\0\xB2T\0\xC0T\0\xC2T\0\xC7T\0\xCAT\0\xCET\0\xCFT\0\xE1T\0\xE2T\0\xE5T\0\xE7T\0\xE9T\0\xEBT\0\xEDT\0\xEET\0\xF2T\0\xF3T\0\x07U\0\x08U\0\tU\0\nU\0\x10U\0\x11U\0\x14U\0\x15U\0,U\0-U\0.U\x000U\x001U\x002U\x005U\x006U\x007U\09U\0FU\0GU\0JU\0KU\0OU\0PU\0_U\0`U\0aU\0bU\0dU\0gU\0jU\0kU\0\x80U\0\x81U\0\x82U\0\x83U\0\x84U\0\x85U\0\x87U\0\x88U\0\x8AU\0\x8BU\0\x94U\0\x95U\0\x9CU\0\x9EU\0\xAAU\0\xABU\0\xACU\0\xADU\0\xAEU\0\xAFU\0\xB2U\0\xB3U\0\xB5U\0\xB6U\0\xCEU\0\xCFU\0\xDAU\0\xDBU\0\xE8U\0\xE9U\0\xEFU\0\xF0U\0\x06V\0\x07V\0\tV\0\nV\0\x17V\0\x18V\0\x1BV\0\x1CV\x004V\x005V\0;V\0<V\0?V\0@V\0AV\0BV\0SV\0TV\0hV\0iV\0tV\0uV\0\x87V\0\x88V\0\x8FV\0\x90V\0\xB4V\0\xB5V\0\xC9V\0\xCAV\0\xDBV\0\xDCV\0\xDEV\0\xDFV\0\xE0V\0\xE1V\0\xF0V\0\xF1V\0\xFAV\0\xFBV\0\x08W\0\tW\0\x0BW\0\x0CW\0\rW\0\x0EW\0\x12W\0\x14W\0\x16W\0\x17W\0\x18W\0\x19W\0\x1CW\0\x1DW\0\x1FW\0 W\0(W\0)W\0-W\0.W\x000W\x001W\0>W\0?W\0@W\0AW\0GW\0HW\0NW\0OW\0PW\0RW\0aW\0bW\0dW\0eW\0fW\0gW\0jW\0kW\0\x82W\0\x84W\0\x8BW\0\x8CW\0\xC3W\0\xC4W\0\xCEW\0\xCFW\0\xD4W\0\xD5W\0\xDFW\0\xE0W\0\xF7W\0\xF8W\0\xF9W\0\xFBW\0\x02X\0\x03X\0\x05X\0\x07X\0!X\0\"X\0*X\0+X\x001X\x002X\x004X\x005X\0JX\0KX\0TX\0UX\0WX\0XX\0^X\0_X\0kX\0lX\0uX\0vX\0\x83X\0\x84X\0\x85X\0\x86X\0\x93X\0\x94X\0\x9EX\0\xA0X\0\xA8X\0\xA9X\0\xAEX\0\xAFX\0\xB3X\0\xB4X\0\xC1X\0\xC2X\0\xC7X\0\xC8X\0\xD3X\0\xD4X\0\xD8X\0\xD9X\0\xDEX\0\xDFX\0\xE2X\0\xE3X\0\xE9X\0\xEAX\0\xEBX\0\xEDX\0\xEFX\0\xF0X\0\xFAX\0\xFBX\0\xFDX\0\xFEX\0\x0FY\0\x10Y\0\x15Y\0\x17Y\0\x1AY\0\x1BY\0\x1CY\0\x1DY\0 Y\0!Y\0\"Y\0#Y\0%Y\0&Y\0'Y\0(Y\0)Y\0,Y\0.Y\0/Y\x001Y\x002Y\x007Y\09Y\0>Y\0?Y\0GY\0JY\0NY\0PY\0QY\0RY\0TY\0UY\0WY\0XY\0gY\0hY\0jY\0kY\0nY\0oY\0sY\0uY\0vY\0wY\0yY\0zY\0}Y\0~Y\0\x82Y\0\x83Y\0\x99Y\0\x9AY\0\x9DY\0\x9EY\0\xA5Y\0\xA6Y\0\xA8Y\0\xA9Y\0\xAEY\0\xAFY\0\xB3Y\0\xB4Y\0\xB9Y\0\xBAY\0\xBBY\0\xBCY\0\xC6Y\0\xC7Y\0\xCAY\0\xCCY\0\xD0Y\0\xD2Y\0\xD3Y\0\xD5Y\0\xFFY\0\0Z\0\x01Z\0\x02Z\0\x03Z\0\x04Z\0\x18Z\0\x19Z\0\x1BZ\0\x1CZ\0AZ\0BZ\0FZ\0GZ\0ZZ\0[Z\0fZ\0gZ\0\x92Z\0\x93Z\0\xBDZ\0\xBEZ\0\xCCZ\0\xCDZ\0\xE9Z\0\xEAZ\0P[\0Q[\0T[\0V[\0W[\0Y[\0][\0^[\0_[\0`[\0c[\0e[\0i[\0j[\0k[\0l[\0u[\0v[\0x[\0y[\0\x83[\0\x84[\0\x85[\0\x86[\0\x87[\0\x8A[\0\x8B[\0\x8D[\0\x8F[\0\x90[\0\x97[\0\x9D[\0\xA2[\0\xA5[\0\xAE[\0\xAF[\0\xB3[\0\xB4[\0\xB6[\0\xB7[\0\xB9[\0\xBA[\0\xBF[\0\xC0[\0\xC2[\0\xC3[\0\xC4[\0\xC7[\0\xCC[\0\xCD[\0\xD2[\0\xD3[\0\xDE[\0\xE0[\0\xE2[\0\xE3[\0\xE6[\0\xEA[\0\xEB[\0\xED[\0\xEE[\0\xEF[\0\xF5[\0\xF7[\0\xFA[\0\xFB[\0\x01\\\0\x02\\\0\x04\\\0\x05\\\0\x07\\\0\t\\\0\n\\\0\x0C\\\0\r\\\0\x10\\\0\x11\\\0\x12\\\0\x16\\\0\x17\\\0\x1A\\\0\x1B\\\0$\\\0%\\\x001\\\x002\\\0:\\\0;\\\0<\\\0=\\\0>\\\0B\\\0E\\\0G\\\0K\\\0L\\\0M\\\0N\\\0O\\\0P\\\0Q\\\0R\\\0U\\\0V\\\0`\\\0a\\\0d\\\0e\\\0l\\\0m\\\0q\\\0r\\\0\xA1\\\0\xA2\\\0\xA9\\\0\xAA\\\0\xB8\\\0\xB9\\\0\xF0\\\0\xF1\\\0\xF6\\\0\xF7\\\0\xFD\\\0\xFE\\\0\x07]\0\x08]\0\x19]\0\x1A]\x004]\x005]\0P]\0Q]\0\xBA]\0\xBB]\0\xDD]\0\xDF]\0\xE1]\0\xE2]\0\xE5]\0\xE9]\0\xEB]\0\xEC]\0\xEE]\0\xEF]\0\xF1]\0\xF5]\0\xF7]\0\xF8]\0\x02^\0\x04^\0\x0C^\0\r^\0\x15^\0\x17^\0\x1A^\0\x1C^\0\x1D^\0\x1E^\0%^\0&^\0+^\0,^\0-^\0.^\x003^\x004^\x006^\x007^\08^\09^\0=^\0>^\0E^\0F^\0U^\0V^\0_^\0`^\0c^\0d^\0k^\0l^\0r^\0u^\0x^\0z^\0{^\0\x7F^\0\x87^\0\x88^\0\x8A^\0\x8B^\0\x8F^\0\x90^\0\x95^\0\x96^\0\x97^\0\x98^\0\x9A^\0\x9B^\0\x9C^\0\x9D^\0\xA6^\0\xA8^\0\xAB^\0\xAC^\0\xAD^\0\xAE^\0\xB7^\0\xB9^\0\xC8^\0\xCA^\0\xD6^\0\xD7^\0\xDF^\0\xE1^\0\xE2^\0\xE4^\0\xF3^\0\xF4^\0\xF6^\0\xF8^\0\xFA^\0\xFB^\0\x04_\0\x05_\0\x0F_\0\x10_\0\x15_\0\x16_\0\x17_\0\x19_\0\x1F_\0 _\0&_\0'_\x001_\x002_\x005_\x006_\x007_\08_\0H_\0I_\0J_\0K_\0L_\0M_\0N_\0O_\0]_\0__\0b_\0c_\0e_\0f_\0i_\0j_\0l_\0n_\0p_\0r_\0y_\0z_\0|_\0}_\0\x80_\0\x82_\0\x85_\0\x86_\0\x88_\0\x89_\0\x8B_\0\x8D_\0\x90_\0\x93_\0\x97_\0\x98_\0\x9E_\0\x9F_\0\xA9_\0\xAA_\0\xAE_\0\xAF_\0\xB5_\0\xB6_\0\xB7_\0\xB8_\0\xB9_\0\xBA_\0\xC3_\0\xC4_\0\xC5_\0\xC6_\0\xCC_\0\xCE_\0\xD7_\0\xDA_\0\xE0_\0\xE2_\0\xEB_\0\xEC_\0\xF5_\0\xF6_\0\xFD_\0\xFE_\0\x0E`\0\x0F`\0\x12`\0\x13`\0\x15`\0\x17`\0\x1D`\0\x1E`\0!`\0\"`\0%`\0&`\0'`\0)`\0*`\0+`\0F`\0G`\0P`\0Q`\0b`\0c`\0e`\0f`\0h`\0j`\0m`\0n`\0o`\0q`\0\x85`\0\x86`\0\x89`\0\x8A`\0\x94`\0\x95`\0\x9F`\0\xA1`\0\xA8`\0\xA9`\0\xB2`\0\xB3`\0\xB6`\0\xB7`\0\xC5`\0\xC6`\0\xD1`\0\xD2`\0\xDC`\0\xDD`\0\xE0`\0\xE2`\0\xF1`\0\xF2`\0\xF3`\0\xF4`\0\xF9`\0\xFA`\0\x01a\0\x02a\0\x08a\0\na\0\x0Fa\0\x10a\0\x1Aa\0\x1Ca\0\x1Fa\0 a\0Ha\0Ia\0Ka\0La\0Ua\0Va\0Xa\0Ya\0ba\0da\0ga\0ha\0na\0oa\0pa\0qa\0va\0wa\0~a\0\x7Fa\0\x82a\0\x83a\0\x8Aa\0\x8Ba\0\x90a\0\x92a\0\xB2a\0\xB3a\0\xB6a\0\xB7a\0\xBEa\0\xBFa\0\xC2a\0\xC3a\0\xC9a\0\xCAa\0\xE8a\0\xE9a\0\xF6a\0\xF8a\0\xFCa\0\xFDa\0\0b\0\x01b\0\x08b\0\tb\0\nb\0\x0Bb\0\x0Cb\0\rb\0\x10b\0\x13b\0\x16b\0\x17b\0*b\0+b\x000b\x001b\x002b\x003b\x004b\x005b\x006b\x007b\0?b\0Bb\0Gb\0Hb\0Kb\0Lb\0Mb\0Ob\0Sb\0Tb\0Xb\0Yb\0cb\0db\0eb\0fb\0mb\0pb\0yb\0zb\0~b\0\x81b\0\x84b\0\x85b\0\x8Ab\0\x8Bb\0\x93b\0\x94b\0\x95b\0\x96b\0\x97b\0\x99b\0\xABb\0\xADb\0\xB1b\0\xB2b\0\xB5b\0\xB6b\0\xB9b\0\xBAb\0\xBDb\0\xBEb\0\xC6b\0\xC7b\0\xC9b\0\xCAb\0\xCBb\0\xCCb\0\xCDb\0\xCEb\0\xCFb\0\xD0b\0\xD2b\0\xD3b\0\xD4b\0\xD5b\0\xD6b\0\xD7b\0\xDBb\0\xDDb\0\xECb\0\xEDb\0\xF3b\0\xF4b\0\xFCb\0\xFDb\0\xFEb\0\0c\0\x01c\0\x02c\0\x07c\0\x08c\0\tc\0\nc\0\x11c\0\x12c\0\x16c\0\x17c\0*c\0+c\0/c\x000c\0:c\0;c\0Oc\0Qc\0Uc\0Vc\0gc\0ic\0rc\0sc\0wc\0xc\0\x83c\0\x84c\0\x88c\0\x8Ac\0\x8Cc\0\x8Dc\0\x92c\0\x93c\0\x9Bc\0\x9Cc\0\xA0c\0\xA3c\0\xA5c\0\xA6c\0\xA7c\0\xA9c\0\xAAc\0\xABc\0\xB0c\0\xB1c\0\xCFc\0\xD1c\0\xD2c\0\xD3c\0\xDAc\0\xDCc\0\xE1c\0\xE2c\0\xEEc\0\xEFc\0\xF4c\0\xF5c\0\xF9c\0\xFAc\0\rd\0\x0Ed\0\x0Fd\0\x10d\0\x16d\0\x17d\0\x1Cd\0\x1Dd\0\x1Ed\0\x1Fd\0,d\0.d\x006d\x007d\0@d\0Ad\0Xd\0Yd\0id\0jd\0xd\0yd\0\x90d\0\x91d\0\x92d\0\x93d\0\x95d\0\x96d\0\x9Ed\0\x9Fd\0\xA3d\0\xA4d\0\xA5d\0\xA6d\0\xADd\0\xAEd\0\xB2d\0\xB3d\0\xBEd\0\xC0d\0\xC1d\0\xC2d\0\xC7d\0\xC8d\0\xCAd\0\xCCd\0\xCDd\0\xCFd\0\xD4d\0\xD5d\0\xDAd\0\xDBd\0\xE0d\0\xE1d\0\xE6d\0\xE7d\0\xECd\0\xEDd\0\xF4d\0\xF5d\0\xFAd\0\xFBd\0\xFEd\0\xFFd\0\0e\0\x01e\0\x1De\0\x1Ee\0$e\0%e\0/e\x000e\x006e\x007e\09e\0:e\0;e\0<e\0>e\0@e\0Ee\0Fe\0He\0Ie\0Me\0Ne\0Oe\0Pe\0Qe\0Re\0We\0Ze\0]e\0_e\0be\0de\0fe\0ge\0le\0me\0te\0ve\0xe\0ye\0\x87e\0\x88e\0\x90e\0\x92e\0\x97e\0\x98e\0\x99e\0\x9Ae\0\x9Ce\0\x9De\0\xA7e\0\xA8e\0\xAFe\0\xB1e\0\xB7e\0\xB8e\0\xB9e\0\xBAe\0\xBCe\0\xBEe\0\xC1e\0\xC2e\0\xC5e\0\xC6e\0\xCBe\0\xCCe\0\xCFe\0\xD0e\0\xD7e\0\xD8e\0\xE2e\0\xE3e\0\xE5e\0\xE7e\0\xE9e\0\xEAe\0\xEDe\0\xEEe\0\xFAe\0\xFBe\0\x02f\0\x03f\0\x06f\0\x08f\0\x0Cf\0\rf\0\x0Ef\0\x10f\0\x13f\0\x14f\0\x1Ff\0!f\0%f\0&f\0(f\0)f\0-f\0.f\0/f\x000f\0Bf\0Cf\0If\0Jf\0Rf\0Sf\0Zf\0[f\0hf\0if\0nf\0pf\0tf\0uf\0vf\0wf\0zf\0{f\0\x91f\0\x92f\0\x96f\0\x98f\0\xABf\0\xACf\0\xAEf\0\xAFf\0\xB4f\0\xB5f\0\xC6f\0\xC8f\0\xC9f\0\xCAf\0\xECf\0\xEDf\0\xF0f\0\xF1f\0\xF2f\0\xF5f\0\xF8f\0\xF9f\0\xFCf\0\xFDf\0\xFEf\0\x01g\0\x03g\0\x04g\0\x08g\0\ng\0\x0Bg\0\x0Cg\0\rg\0\x0Eg\0\x14g\0\x15g\0\x17g\0\x18g\0\x1Bg\0\x1Cg\0\x1Dg\0\x1Eg\0\x1Fg\0 g\0(g\0)g\0*g\0.g\x001g\x002g\x005g\x006g\0Ig\0Jg\0Ng\0Og\0Pg\0Rg\0Vg\0Wg\0\\g\0]g\0_g\0`g\0og\0rg\0~g\0\x80g\0\x90g\0\x91g\0\x97g\0\x98g\0\x9Cg\0\x9Eg\0\xAFg\0\xB0g\0\xB6g\0\xB7g\0\xCFg\0\xD1g\0\xD3g\0\xD5g\0\xE5g\0\xE6g\0\xECg\0\xEDg\0\xEFg\0\xF0g\0\xF3g\0\xF5g\0\x13h\0\x14h\0!h\0\"h\08h\0:h\0<h\0>h\0Ch\0Dh\0Hh\0Ih\0Lh\0Mh\0Qh\0Rh\0\x81h\0\x82h\0\x85h\0\x86h\0\x9Dh\0\x9Eh\0\xA8h\0\xA9h\0\xAFh\0\xB1h\0\xB5h\0\xB6h\0\xC4h\0\xC5h\0\xC9h\0\xCAh\0\xCBh\0\xCCh\0\xCDh\0\xCEh\0\xD2h\0\xD3h\0\xD5h\0\xD6h\0\xDAh\0\xDBh\0\xEEh\0\xEFh\0\xFAh\0\xFBh\0\x05i\0\x06i\0\ri\0\x0Ei\0\x12i\0\x13i\x000i\x001i\0Ji\0Ki\0Si\0Ti\0Zi\0[i\0mi\0ni\0ui\0vi\0\x82i\0\x83i\0\x9Ci\0\x9Di\0\xAEi\0\xAFi\0\xCBi\0\xCEi\0\x02j\0\x03j\0\x13j\0\x14j\0\x19j\0\x1Aj\0\x1Ej\0\x1Fj\0!j\0\"j\0#j\0$j\09j\0:j\0Dj\0Ej\0Gj\0Hj\0Kj\0Lj\0Xj\0Zj\0_j\0`j\0kj\0lj\0\x80j\0\x81j\0\x94j\0\x95j\0\xA2j\0\xA3j\0\xACj\0\xADj\0\xB8j\0\xB9j\0\xDAj\0\xDBj\0\xFBj\0\xFCj\0\x04k\0\x05k\0\nk\0\x0Bk\0\x16k\0\x17k\0 k\0\"k\0#k\0$k\x002k\x003k\0:k\0;k\0=k\0?k\0Ik\0Jk\0Lk\0Mk\0Pk\0Qk\0ak\0gk\0rk\0sk\0wk\0yk\0{k\0|k\0\x8Ak\0\x8Ck\0\x98k\0\x99k\0\xADk\0\xAEk\0\xB5k\0\xB6k\0\xBAk\0\xBBk\0\xBCk\0\xBDk\0\xC0k\0\xC1k\0\xC5k\0\xC6k\0\xCDk\0\xCEk\0\xCFk\0\xD0k\0\xD2k\0\xD3k\0\xD4k\0\xD5k\0\xDBk\0\xDCk\0\xEBk\0\xECk\0\x0Fl\0\x10l\0\x11l\0\x12l\0#l\0$l\x004l\x005l\08l\09l\0Al\0Cl\0Wl\0Xl\0]l\0^l\0_l\0bl\0jl\0kl\0vl\0wl\0zl\0{l\0}l\0~l\0\x83l\0\x84l\0\x88l\0\x8Al\0\x92l\0\x93l\0\x96l\0\x97l\0\x99l\0\x9Al\0\xABl\0\xACl\0\xAEl\0\xAFl\0\xB3l\0\xB4l\0\xB9l\0\xBAl\0\xBBl\0\xBCl\0\xBFl\0\xC0l\0\xC1l\0\xC2l\0\xC9l\0\xCBl\0\xD5l\0\xD6l\0\xE1l\0\xE4l\0\xE5l\0\xE6l\0\xE8l\0\xE9l\0\xF0l\0\xF1l\0\xF3l\0\xF4l\0\x0Bm\0\x0Cm\0\x17m\0\x18m\0\x1Bm\0\x1Cm\0\x1Em\0\x1Fm\0)m\0+m\x002m\x003m\0;m\0<m\0=m\0?m\0Am\0Bm\0cm\0dm\0fm\0gm\0im\0km\0nm\0om\0tm\0um\0wm\0xm\0\x87m\0\x8Am\0\x8Em\0\x8Fm\0\xAEm\0\xB0m\0\xB2m\0\xB3m\0\xB5m\0\xB6m\0\xBCm\0\xBDm\0\xC7m\0\xC8m\0\xCBm\0\xCCm\0\xD1m\0\xD2m\0\xDAm\0\xDBm\0\xE1m\0\xE2m\0\xE8m\0\xE9m\0\xF1m\0\xF2m\0\xF7m\0\xF8m\0\xFAm\0\xFBm\0\x05n\0\x06n\0\x1Bn\0\x1Cn\0!n\0\"n\0,n\0-n\0/n\x000n\08n\09n\0Vn\0Wn\0Xn\0Yn\0on\0pn\0\x90n\0\x91n\0\x96n\0\x97n\0\x9Cn\0\x9En\0\xAAn\0\xACn\0\xC4n\0\xC6n\0\xCBn\0\xCCn\0\xD1n\0\xD2n\0\xF4n\0\xF5n\0\xFEn\0\0o\0\x02o\0\x03o\0\x0Fo\0\x10o\0\x14o\0\x15o\0 o\0!o\0\"o\0#o\0+o\0,o\x002o\x003o\08o\09o\0?o\0@o\0To\0Uo\0Xo\0Yo\0[o\0\\o\0no\0oo\0\xA1o\0\xA2o\0\xA4o\0\xA5o\0\xB3o\0\xB4o\0\xC0o\0\xC1o\0\xC3o\0\xC4o\0\xD5o\0\xD6o\0\xDFo\0\xE0o\0\xE4o\0\xE5o\0\xEBo\0\xECo\0\xF1o\0\xF2o\0\x0Fp\0\x10p\0Lp\0Mp\0cp\0dp\0kp\0lp\0pp\0qp\0}p\0~p\0\x8Ep\0\x8Fp\0\xAEp\0\xAFp\0\xB8p\0\xB9p\0\xBAp\0\xBBp\0\xC8p\0\xC9p\0\xCFp\0\xD0p\0\xD8p\0\xD9p\0\xE4p\0\xE5p\0\xF9p\0\xFAp\0\nq\0\x0Bq\0\x19q\0\x1Aq\0!q\0\"q\0&q\0'q\x000q\x001q\x006q\x007q\0Yq\0Zq\0^q\0_q\0gq\0hq\0iq\0jq\0nq\0oq\0\x8Aq\0\x8Bq\0\x9Fq\0\xA0q\0\xB1q\0\xB2q\0\xC3q\0\xC4q\0\xC8q\0\xC9q\0\xD2q\0\xD3q\0\xD9q\0\xDAq\0\xDFq\0\xE0q\0\x06r\0\x07r\0\rr\0\x0Er\0\x10r\0\x11r\0\x1Br\0\x1Cr\0*r\0+r\0,r\0.r\x005r\x007r\08r\09r\0:r\0;r\0=r\0?r\0Fr\0Ir\0Lr\0Mr\0Yr\0Zr\0[r\0\\r\0`r\0ar\0gr\0hr\0ir\0jr\0rr\0sr\0yr\0zr\0}r\0~r\0\x80r\0\x81r\0\xA7r\0\xA8r\0\xACr\0\xADr\0\xAFr\0\xB0r\0\xC0r\0\xC1r\0\xC2r\0\xC3r\0\xD0r\0\xD1r\0\xD7r\0\xD8r\0\xE0r\0\xE2r\0\xF8r\0\xF9r\0\xFCr\0\xFDr\0\x1Bs\0\x1Ds\0)s\0*s\x004s\x005s\x006s\x007s\0>s\0@s\0Ds\0Fs\0Ns\0Os\0hs\0is\0rs\0ss\0xs\0ys\0zs\0|s\0~s\0\x7Fs\0\x84s\0\x85s\0\x87s\0\x88s\0\x89s\0\x8As\0\x8Bs\0\x8Cs\0\xA9s\0\xAAs\0\xABs\0\xACs\0\xB2s\0\xB3s\0\xBBs\0\xBCs\0\xCAs\0\xCBs\0\xCDs\0\xCEs\0\xE0s\0\xE1s\0\xE5s\0\xE6s\0\xEDs\0\xEEs\0\xFEs\0\xFFs\0\x03t\0\x04t\0\x06t\0\x07t\0\tt\0\nt\0*t\0+t\x004t\x005t\0Yt\0Zt\0\\t\0]t\0^t\0`t\0dt\0et\0jt\0kt\0pt\0qt\0\xB0t\0\xB1t\0\xDCt\0\xDDt\0\xE2t\0\xE3t\0\xE6t\0\xE7t\0\xF6t\0\xF7t\0\x15u\0\x16u\0\x18u\0\x19u\0\x1Au\0\x1Bu\0\x1Cu\0\x1Du\0\x1Fu\0 u\0\"u\0#u\0(u\0)u\x000u\x004u\x007u\09u\0Lu\0Mu\0Yu\0Zu\0bu\0cu\0eu\0fu\0ju\0lu\0pu\0qu\0vu\0wu\0\x86u\0\x87u\0\x8Fu\0\x90u\0\x91u\0\x92u\0\xB2u\0\xB3u\0\xBCu\0\xBDu\0\xBEu\0\xBFu\0\xC5u\0\xC6u\0\xD5u\0\xD6u\0\xDBu\0\xDCu\0\xF4u\0\xF5u\0\x0Bv\0\x0Cv\0&v\0(v\0Bv\0Cv\0av\0bv\0xv\0yv\0{v\0\x7Fv\0\x82v\0\x83v\0\x84v\0\x85v\0\x86v\0\x88v\0\xAEv\0\xAFv\0\xBFv\0\xC0v\0\xC3v\0\xC4v\0\xC6v\0\xC7v\0\xC8v\0\xC9v\0\xCAv\0\xCBv\0\xD4v\0\xD5v\0\xDBv\0\xDDv\0\xDFv\0\xE0v\0\xE1v\0\xE2v\0\xE3v\0\xE6v\0\xE7v\0\xE8v\0\xEEv\0\xEFv\0\xF2v\0\xF3v\0\xF4v\0\xF5v\0\xF8v\0\xF9v\0\xFCv\0\xFDv\0\xFEv\0\xFFv\0\x01w\0\x02w\0\tw\0\nw\0\x0Bw\0\x0Cw\0\x1Fw\0!w\0<w\0=w\0>w\0?w\0Ow\0Pw\0[w\0\\w\0aw\0bw\0cw\0dw\0\x87w\0\x88w\0\x8Cw\0\x8Dw\0\xA7w\0\xA8w\0\xAAw\0\xABw\0\xADw\0\xAEw\0\xDBw\0\xDCw\0\xE3w\0\xE4w\0\xE5w\0\xE6w\0\xEDw\0\xEEw\0\xF3w\0\xF4w\0\x02x\0\x03x\0\rx\0\x0Ex\0\x14x\0\x15x\x002x\x003x\x004x\x005x\0lx\0mx\0\x8Ex\0\x8Fx\0\x97x\0\x98x\0\x9Fx\0\xA0x\0\xA7x\0\xA8x\0\xA9x\0\xAAx\0\xB0x\0\xB1x\0\xBAx\0\xBBx\0\xBCx\0\xBDx\0\xC1x\0\xC2x\0\xDAx\0\xDBx\0\xE8x\0\xE9x\0\xEFx\0\xF0x\0\x0Ey\0\x0Fy\0\x19y\0\x1Ay\0+y\0,y\0:y\0;y\0>y\0?y\0Hy\0Iy\0Uy\0Wy\0Zy\0\\y\0]y\0_y\0ey\0fy\0hy\0iy\0\x7Fy\0\x80y\0\x81y\0\x82y\0\x8Dy\0\x90y\0\xAAy\0\xABy\0\xAEy\0\xAFy\0\xB1y\0\xB2y\0\xBFy\0\xC2y\0\xCBy\0\xCCy\0\xD1y\0\xD3y\0\xD8y\0\xD9y\0\xDFy\0\xE0y\0\xE4y\0\xE5y\0\xE6y\0\xE7y\0\xFBy\0\xFCy\0\x05z\0\x06z\0\x0Bz\0\x0Cz\0\rz\0\x0Ez\0.z\0/z\x001z\x002z\0;z\0<z\0?z\0Az\0Fz\0Gz\0Lz\0Nz\0iz\0jz\0vz\0wz\0yz\0{z\0\x7Fz\0\x80z\0\x81z\0\x82z\0\x84z\0\x85z\0\x97z\0\x98z\0\xA9z\0\xAAz\0\xAEz\0\xAFz\0\xB6z\0\xB7z\0\xCBz\0\xCCz\0\xD9z\0\xDAz\0\xDFz\0\xE1z\0\xE5z\0\xE6z\0\xEFz\0\xF0z\0\xF6z\0\xF7z\0\xF9z\0\xFAz\0\xFFz\0\0{\0\x11{\0\x12{\0\x1B{\0\x1C{\0&{\0'{\0({\0){\0,{\0-{\0F{\0G{\0I{\0J{\0K{\0L{\0T{\0U{\0V{\0W{\0w{\0x{\0\x8F{\0\x90{\0\x94{\0\x95{\0\x97{\0\x98{\0\xA1{\0\xA2{\0\xAD{\0\xAE{\0\xB1{\0\xB2{\0\xC0{\0\xC1{\0\xC4{\0\xC5{\0\xC7{\0\xC8{\0\xC9{\0\xCA{\0\xF7{\0\xF8{\0!|\0\"|\0+|\0,|\0=|\0>|\0?|\0@|\0C|\0D|\0L|\0N|\0`|\0a|\0d|\0e|\0s|\0t|\0\x89|\0\x8A|\0\x97|\0\x98|\0\xB5|\0\xB6|\0\xBE|\0\xBF|\0\xCA|\0\xCB|\0\xD5|\0\xD7|\0\xDF|\0\xE0|\0\xE5|\0\xE6|\0\xFB|\0\xFC|\0\xFE|\0\xFF|\0\0}\0\x01}\0\x04}\0\x06}\0\t}\0\n}\0\r}\0\x0E}\0\x10}\0\x11}\0\x14}\0\x15}\0\x19}\0\x1C}\0 }\0!}\0\"}\0#}\0+}\0,}\0.}\x001}\x003}\x004}\09}\0:}\0B}\0C}\0D}\0E}\0P}\0Q}\0U}\0V}\0a}\0b}\0f}\0g}\0q}\0s}\0\x93}\0\x94}\0\x9C}\0\x9D}\0\xA0}\0\xA1}\0\xAD}\0\xAE}\0\xB1}\0\xB3}\0\xBD}\0\xBE}\0\xBF}\0\xC0}\0\xCA}\0\xCB}\0\xD2}\0\xD3}\0\xDA}\0\xDB}\0\xE3}\0\xE4}\0\xE8}\0\xEA}\0\xEC}\0\xED}\0\xEF}\0\xF0}\0\xF4}\0\xF5}\0\x1B~\0\x1C~\0#~\0$~\0+~\0,~\0.~\0/~\x001~\x002~\0=~\0?~\0A~\0B~\0C~\0D~\0F~\0G~\0T~\0U~\0^~\0_~\0a~\0b~\0i~\0k~\0s~\0t~\0|~\0}~\0\x8C~\0\x8D~\0\x96~\0\x97~\08\x7F\09\x7F\0:\x7F\0;\x7F\0H\x7F\0I\x7F\0P\x7F\0Q\x7F\0U\x7F\0V\x7F\0i\x7F\0k\x7F\0n\x7F\0o\x7F\0p\x7F\0q\x7F\0r\x7F\0s\x7F\0u\x7F\0v\x7F\0w\x7F\0x\x7F\0\x85\x7F\0\x86\x7F\0\x8A\x7F\0\x8B\x7F\0\x8E\x7F\0\x8F\x7F\0\x9E\x7F\0\x9F\x7F\0\xA4\x7F\0\xA5\x7F\0\xA9\x7F\0\xAA\x7F\0\xBD\x7F\0\xBE\x7F\0\xC1\x7F\0\xC2\x7F\0\xD2\x7F\0\xD3\x7F\0\xD4\x7F\0\xD5\x7F\0\xF0\x7F\0\xF1\x7F\0\xF9\x7F\0\xFA\x7F\0\xFB\x7F\0\xFD\x7F\0\0\x80\0\x02\x80\0\x03\x80\0\x04\x80\0\x05\x80\0\x06\x80\0\x0C\x80\0\x0E\x80\0\x10\x80\0\x11\x80\0\x17\x80\0\x18\x80\x003\x80\x004\x80\x006\x80\x007\x80\0J\x80\0K\x80\0V\x80\0W\x80\0Z\x80\0[\x80\0^\x80\0_\x80\0o\x80\0q\x80\0r\x80\0s\x80\0w\x80\0x\x80\0}\x80\0\x7F\x80\0\x89\x80\0\x8A\x80\0\x8C\x80\0\x8D\x80\0\x9A\x80\0\x9B\x80\0\xA1\x80\0\xA2\x80\0\xA5\x80\0\xA6\x80\0\xA9\x80\0\xAA\x80\0\xAF\x80\0\xB0\x80\0\xB2\x80\0\xB3\x80\0\xBA\x80\0\xBB\x80\0\xCC\x80\0\xCD\x80\0\xCE\x80\0\xCF\x80\0\xD6\x80\0\xD7\x80\0\xDE\x80\0\xDF\x80\0\xE1\x80\0\xE2\x80\0\xF8\x80\0\xF9\x80\0\xFD\x80\0\xFE\x80\0\x06\x81\0\x07\x81\0\x08\x81\0\t\x81\0\x16\x81\0\x17\x81\0+\x81\0,\x81\0P\x81\0Q\x81\0S\x81\0U\x81\0f\x81\0g\x81\0p\x81\0q\x81\0s\x81\0t\x81\0y\x81\0z\x81\0\x7F\x81\0\x80\x81\0\x9A\x81\0\x9B\x81\0\xA0\x81\0\xA1\x81\0\xBD\x81\0\xBE\x81\0\xC2\x81\0\xC3\x81\0\xC9\x81\0\xCA\x81\0\xD8\x81\0\xD9\x81\0\xDF\x81\0\xE0\x81\0\xE3\x81\0\xE4\x81\0\xE5\x81\0\xE6\x81\0\xE8\x81\0\xE9\x81\0\xEA\x81\0\xEB\x81\0\xED\x81\0\xEE\x81\0\xF3\x81\0\xF5\x81\0\xFA\x81\0\xFB\x81\0\x07\x82\0\x0B\x82\0\x0C\x82\0\x0E\x82\0\x12\x82\0\x13\x82\0\x1E\x82\0 \x82\0*\x82\0+\x82\0,\x82\0-\x82\09\x82\0:\x82\0f\x82\0g\x82\0o\x82\0p\x82\0r\x82\0s\x82\0~\x82\0\x7F\x82\0\x99\x82\0\x9A\x82\0\x9D\x82\0\x9E\x82\0\xAC\x82\0\xAE\x82\0\xB1\x82\0\xB2\x82\0\xB3\x82\0\xB4\x82\0\xBD\x82\0\xBE\x82\0\xE3\x82\0\xE4\x82\0\xE5\x82\0\xE7\x82\0\xF1\x82\0\xF2\x82\0\x04\x83\0\x06\x83\0+\x83\0,\x83\x002\x83\x003\x83\x005\x83\x007\x83\08\x83\09\x83\0I\x83\0J\x83\0R\x83\0S\x83\0w\x83\0x\x83\0|\x83\0}\x83\0\x89\x83\0\x8B\x83\0\x8E\x83\0\x8F\x83\0\x93\x83\0\x94\x83\0\x96\x83\0\x97\x83\0\xAB\x83\0\xAC\x83\0\xC7\x83\0\xC8\x83\0\xCC\x83\0\xCD\x83\0\xDC\x83\0\xDD\x83\0\xE9\x83\0\xEA\x83\0\xEF\x83\0\xF0\x83\0\xF2\x83\0\xF3\x83\0\x04\x84\0\x05\x84\0\n\x84\0\x0B\x84\0\x0E\x84\0\x0F\x84\0,\x84\0-\x84\x005\x84\x006\x84\0=\x84\0>\x84\0I\x84\0J\x84\0W\x84\0X\x84\0[\x84\0\\\x84\0a\x84\0b\x84\0u\x84\0v\x84\0\x82\x84\0\x83\x84\0\x99\x84\0\x9A\x84\0\x9C\x84\0\x9D\x84\0\xB2\x84\0\xB3\x84\0\xB8\x84\0\xB9\x84\0\xBC\x84\0\xBD\x84\0\xC4\x84\0\xC5\x84\0\xC9\x84\0\xCA\x84\0\xCB\x84\0\xCC\x84\0\xEE\x84\0\xEF\x84\0\x14\x85\0\x16\x85\0!\x85\0\"\x85\0#\x85\0$\x85\0%\x85\0&\x85\0,\x85\0-\x85\0I\x85\0J\x85\0m\x85\0n\x85\0~\x85\0\x7F\x85\0\x84\x85\0\x85\x85\0\x91\x85\0\x92\x85\0\xA6\x85\0\xA7\x85\0\xA9\x85\0\xAB\x85\0\xAF\x85\0\xB0\x85\0\xC9\x85\0\xCA\x85\0\xCD\x85\0\xCE\x85\0\xCF\x85\0\xD0\x85\0\xDD\x85\0\xDE\x85\0\xE4\x85\0\xE6\x85\0\x06\x86\0\x08\x86\0\x0B\x86\0\x0C\x86\0\x11\x86\0\x12\x86\0-\x86\0.\x86\0?\x86\0@\x86\0N\x86\0O\x86\0U\x86\0V\x86\0[\x86\0\\\x86\0_\x86\0`\x86\0g\x86\0h\x86\0\x8A\x86\0\x8B\x86\0\x93\x86\0\x94\x86\0\xAF\x86\0\xB0\x86\0\xC7\x86\0\xC8\x86\0\xCB\x86\0\xCC\x86\0\xD9\x86\0\xDA\x86\0\x02\x87\0\x03\x87\0\x1C\x87\0\x1D\x87\0%\x87\0&\x87\x004\x87\x005\x87\0Y\x87\0Z\x87\0_\x87\0a\x87\0f\x87\0g\x87\0v\x87\0w\x87\0\x82\x87\0\x84\x87\0\x8D\x87\0\x8E\x87\0\x9E\x87\0\x9F\x87\0\xA2\x87\0\xA3\x87\0\xBA\x87\0\xBB\x87\0\xC0\x87\0\xC1\x87\0\xC4\x87\0\xC5\x87\0\xCB\x87\0\xCC\x87\0\xD1\x87\0\xD2\x87\0\xF2\x87\0\xF4\x87\0\xF9\x87\0\xFA\x87\0\xFB\x87\0\xFC\x87\0\x05\x88\0\x06\x88\0\r\x88\0\x0E\x88\0\x15\x88\0\x16\x88\0#\x88\0$\x88\0;\x88\0<\x88\0@\x88\0A\x88\0L\x88\0M\x88\0S\x88\0T\x88\0W\x88\0X\x88\0[\x88\0\\\x88\0]\x88\0^\x88\0a\x88\0b\x88\0c\x88\0d\x88\0h\x88\0i\x88\0k\x88\0l\x88\0\x8B\x88\0\x8C\x88\0\x8D\x88\0\x8E\x88\0\xAB\x88\0\xAC\x88\0\xC1\x88\0\xC3\x88\0\xCF\x88\0\xD0\x88\0\xD5\x88\0\xD6\x88\0\xDC\x88\0\xDE\x88\0\xE1\x88\0\xE2\x88\0\xF1\x88\0\xF2\x88\0\xF9\x88\0\xFA\x88\0\xFD\x88\0\xFE\x88\0\x07\x89\0\x08\x89\0\x10\x89\0\x11\x89\x002\x89\x003\x89\0j\x89\0k\x89\0o\x89\0p\x89\0\x7F\x89\0\x80\x89\0\x81\x89\0\x82\x89\0\x86\x89\0\x87\x89\0\x8B\x89\0\x8C\x89\0\x8F\x89\0\x90\x89\0\x96\x89\0\x97\x89\0\xAA\x89\0\xAB\x89\0\xBA\x89\0\xBB\x89\0\xBD\x89\0\xBE\x89\0\xC0\x89\0\xC1\x89\0\xD2\x89\0\xD3\x89\0\xE3\x89\0\xE4\x89\0\xF8\x89\0\xF9\x89\0\0\x8A\0\x01\x8A\0\x02\x8A\0\x03\x8A\0\x08\x8A\0\t\x8A\0\n\x8A\0\x0B\x8A\0\x0E\x8A\0\x0F\x8A\0\x13\x8A\0\x14\x8A\0\x17\x8A\0\x19\x8A\0\x1D\x8A\0\x1E\x8A\0%\x8A\0&\x8A\0*\x8A\0+\x8A\0-\x8A\0.\x8A\x001\x8A\x002\x8A\x004\x8A\x005\x8A\0:\x8A\0=\x8A\0U\x8A\0V\x8A\0^\x8A\0_\x8A\0b\x8A\0c\x8A\0f\x8A\0g\x8A\0i\x8A\0j\x8A\0q\x8A\0t\x8A\0\x87\x8A\0\x88\x8A\0\x8C\x8A\0\x8E\x8A\0\x93\x8A\0\x94\x8A\0\x95\x8A\0\x96\x8A\0\x9E\x8A\0\x9F\x8A\0\xA0\x8A\0\xA1\x8A\0\xA4\x8A\0\xA5\x8A\0\xAA\x8A\0\xAB\x8A\0\xB0\x8A\0\xB1\x8A\0\xB2\x8A\0\xB3\x8A\0\xBC\x8A\0\xBD\x8A\0\xBF\x8A\0\xC0\x8A\0\xC7\x8A\0\xC8\x8A\0\xCB\x8A\0\xCC\x8A\0\xD2\x8A\0\xD3\x8A\0\xD6\x8A\0\xD7\x8A\0\xF8\x8A\0\xF9\x8A\0\xFA\x8A\0\xFB\x8A\0\xFE\x8A\0\xFF\x8A\0\0\x8B\0\x01\x8B\0\x02\x8B\0\x03\x8B\0\x0E\x8B\0\x0F\x8B\0\x1B\x8B\0\x1C\x8B\0\x1D\x8B\0\x1E\x8B\0I\x8B\0J\x8B\0X\x8B\0Y\x8B\0\\\x8B\0]\x8B\0f\x8B\0g\x8B\0o\x8B\0q\x8B\0w\x8B\0x\x8B\0}\x8B\0~\x8B\0\x80\x8B\0\x81\x8B\0\x8A\x8B\0\x8B\x8B\0\x93\x8B\0\x94\x8B\0\x9A\x8B\0\x9B\x8B\x007\x8C\08\x8C\0F\x8C\0G\x8C\0H\x8C\0I\x8C\0N\x8C\0O\x8C\0P\x8C\0Q\x8C\0T\x8C\0U\x8C\0a\x8C\0b\x8C\0j\x8C\0k\x8C\0l\x8C\0m\x8C\0y\x8C\0z\x8C\0\x8C\x8C\0\x8D\x8C\0\x93\x8C\0\x94\x8C\0\x9D\x8C\0\x9F\x8C\0\xA0\x8C\0\xA3\x8C\0\xA8\x8C\0\xA9\x8C\0\xAA\x8C\0\xAD\x8C\0\xB4\x8C\0\xB5\x8C\0\xB7\x8C\0\xB8\x8C\0\xBB\x8C\0\xBD\x8C\0\xC0\x8C\0\xC1\x8C\0\xC7\x8C\0\xC9\x8C\0\xD3\x8C\0\xD4\x8C\0\xDC\x8C\0\xDD\x8C\0\xDE\x8C\0\xDF\x8C\0\xE2\x8C\0\xE5\x8C\0\xE6\x8C\0\xE7\x8C\0\xEA\x8C\0\xEB\x8C\0\xED\x8C\0\xEE\x8C\0\xF4\x8C\0\xF5\x8C\0\xFA\x8C\0\xFB\x8C\0\xFC\x8C\0\xFE\x8C\0\x08\x8D\0\t\x8D\0\n\x8D\0\x0B\x8D\0\x0F\x8D\0\x10\x8D\0\x1B\x8D\0\x1C\x8D\0d\x8D\0e\x8D\0k\x8D\0l\x8D\0p\x8D\0q\x8D\0w\x8D\0x\x8D\0\x85\x8D\0\x86\x8D\0\x8A\x8D\0\x8B\x8D\0\x95\x8D\0\x96\x8D\0\x99\x8D\0\x9A\x8D\0\xA3\x8D\0\xA4\x8D\0\xA8\x8D\0\xA9\x8D\0\xB3\x8D\0\xB4\x8D\0\xC6\x8D\0\xC7\x8D\0\xCC\x8D\0\xCD\x8D\0\xCE\x8D\0\xCF\x8D\0\xD1\x8D\0\xD2\x8D\0\xDD\x8D\0\xDE\x8D\0\xDF\x8D\0\xE0\x8D\0\xE1\x8D\0\xE2\x8D\0\xEA\x8D\0\xEB\x8D\0\xEF\x8D\0\xF0\x8D\0\xF3\x8D\0\xF4\x8D\0\x0F\x8E\0\x10\x8E\0\"\x8E\0#\x8E\0)\x8E\0*\x8E\0_\x8E\0`\x8E\0d\x8E\0e\x8E\0\x8D\x8E\0\x8E\x8E\0\xAB\x8E\0\xAC\x8E\0\xB2\x8E\0\xB3\x8E\0\xCA\x8E\0\xCB\x8E\0\xCC\x8E\0\xCE\x8E\0\xD2\x8E\0\xD3\x8E\0\xDF\x8E\0\xE0\x8E\0\xF8\x8E\0\xF9\x8E\0\x03\x8F\0\x04\x8F\0\t\x8F\0\n\x8F\0\x14\x8F\0\x16\x8F\0\x1B\x8F\0\x1C\x8F\0\x1D\x8F\0\x1E\x8F\0)\x8F\0+\x8F\0/\x8F\x000\x8F\08\x8F\09\x8F\0I\x8F\0J\x8F\0N\x8F\0O\x8F\0_\x8F\0`\x8F\0\x9B\x8F\0\x9D\x8F\0\xA3\x8F\0\xA4\x8F\0\xA6\x8F\0\xA7\x8F\0\xA8\x8F\0\xA9\x8F\0\xAD\x8F\0\xAE\x8F\0\xAF\x8F\0\xB3\x8F\0\xC5\x8F\0\xC6\x8F\0\xCE\x8F\0\xCF\x8F\0\xD1\x8F\0\xD2\x8F\0\xD4\x8F\0\xD5\x8F\0\xE6\x8F\0\xE7\x8F\0\xEA\x8F\0\xEC\x8F\0\xF0\x8F\0\xF1\x8F\0\xF4\x8F\0\xF5\x8F\0\xF7\x8F\0\xF8\x8F\0\xFD\x8F\0\xFE\x8F\0\0\x90\0\x02\x90\0\x03\x90\0\x04\x90\0\x06\x90\0\x07\x90\0\x0F\x90\0\x11\x90\0\x14\x90\0\x15\x90\0\x19\x90\0\x1C\x90\0\x1D\x90\0\x1E\x90\0\x1F\x90\0!\x90\0\"\x90\0$\x90\x001\x90\x003\x90\08\x90\09\x90\0<\x90\0=\x90\0G\x90\0H\x90\0J\x90\0L\x90\0M\x90\0O\x90\0S\x90\0V\x90\0Y\x90\0Z\x90\0\\\x90\0]\x90\0`\x90\0a\x90\0i\x90\0j\x90\0m\x90\0o\x90\0r\x90\0s\x90\0w\x90\0y\x90\0z\x90\0{\x90\0\x7F\x90\0\x82\x90\0\x84\x90\0\x85\x90\0\x8A\x90\0\x8B\x90\0\x8F\x90\0\x90\x90\0\xA3\x90\0\xA4\x90\0\xA6\x90\0\xA7\x90\0\xAA\x90\0\xAB\x90\0\xB1\x90\0\xB2\x90\0\xCE\x90\0\xCF\x90\0\xE8\x90\0\xE9\x90\0\xED\x90\0\xEE\x90\0\xF5\x90\0\xF6\x90\0\xFD\x90\0\xFE\x90\0\x02\x91\0\x03\x91\0\t\x91\0\n\x91\0\x19\x91\0\x1A\x91\0-\x91\0.\x91\x000\x91\x001\x91\0I\x91\0J\x91\0M\x91\0N\x91\0R\x91\0S\x91\0j\x91\0k\x91\0w\x91\0y\x91\0\x89\x91\0\x8A\x91\0\x92\x91\0\x93\x91\0\x9C\x91\0\x9D\x91\0\xAB\x91\0\xAD\x91\0\xC7\x91\0\xC8\x91\0\xCB\x91\0\xD0\x91\0\xD1\x91\0\xD2\x91\0\xDD\x91\0\xDE\x91\0\xE3\x91\0\xE4\x91\x004\x92\x005\x92\0E\x92\0F\x92\0b\x92\0c\x92\0d\x92\0e\x92\0\x80\x92\0\x81\x92\0\x85\x92\0\x86\x92\0\x96\x92\0\x97\x92\0\x98\x92\0\x99\x92\0\xB3\x92\0\xB4\x92\0\xB7\x92\0\xB8\x92\0\xC1\x92\0\xC2\x92\0\xD2\x92\0\xD3\x92\0\xFC\x92\0\xFD\x92\0\x04\x93\0\x05\x93\0\"\x93\0#\x93\0&\x93\0'\x93\0(\x93\0)\x93\0+\x93\0,\x93\0/\x93\x000\x93\x006\x93\x007\x93\0J\x93\0L\x93\0u\x93\0v\x93\0~\x93\0\x7F\x93\0\x8A\x93\0\x8B\x93\0\x96\x93\0\x97\x93\0\xAE\x93\0\xAF\x93\0\xC8\x93\0\xC9\x93\0\xE1\x93\0\xE3\x93\0\x18\x94\0\x19\x94\0!\x94\0\"\x94\x005\x94\x006\x94\0Q\x94\0R\x94\0\x7F\x94\0\x80\x94\0w\x95\0x\x95\0\x80\x95\0\x81\x95\0\x83\x95\0\x84\x95\0\x89\x95\0\x8A\x95\0\x8B\x95\0\x8C\x95\0\x8F\x95\0\x90\x95\0\x92\x95\0\x94\x95\0\xA3\x95\0\xA4\x95\0\xA9\x95\0\xAA\x95\0\xB1\x95\0\xB2\x95\0\xC6\x95\0\xC7\x95\0\xCA\x95\0\xCB\x95\0\xCD\x95\0\xCE\x95\0\xD0\x95\0\xD1\x95\0\xDC\x95\0\xDD\x95\0\xE1\x95\0\xE2\x95\x001\x96\x003\x96\0;\x96\0<\x96\0?\x96\0A\x96\0D\x96\0E\x96\0M\x96\0N\x96\0P\x96\0Q\x96\0b\x96\0e\x96\0j\x96\0k\x96\0p\x96\0q\x96\0s\x96\0t\x96\0u\x96\0y\x96\0}\x96\0~\x96\0\x86\x96\0\x87\x96\0\x8A\x96\0\x8B\x96\0\x8E\x96\0\x8F\x96\0\x94\x96\0\x95\x96\0\x9B\x96\0\x9D\x96\0\xA8\x96\0\xA9\x96\0\xAA\x96\0\xAB\x96\0\xB1\x96\0\xB2\x96\0\xBB\x96\0\xBC\x96\0\xC4\x96\0\xC7\x96\0\xC9\x96\0\xCA\x96\0\xCC\x96\0\xCD\x96\0\xD6\x96\0\xD7\x96\0\xD9\x96\0\xDA\x96\0\xDC\x96\0\xDD\x96\0\xDE\x96\0\xDF\x96\0\xE2\x96\0\xE4\x96\0\xE8\x96\0\xE9\x96\0\xEA\x96\0\xEB\x96\0\xF2\x96\0\xF3\x96\0\xF6\x96\0\xF8\x96\0\xFB\x96\0\xFC\x96\0\0\x97\0\x01\x97\0\x07\x97\0\x08\x97\0\r\x97\0\x0E\x97\0\x1C\x97\0\x1D\x97\0'\x97\0(\x97\x002\x97\x003\x97\08\x97\0:\x97\0B\x97\0C\x97\0H\x97\0I\x97\0R\x97\0S\x97\0V\x97\0W\x97\0Y\x97\0Z\x97\0\\\x97\0]\x97\0^\x97\0_\x97\0`\x97\0a\x97\0b\x97\0c\x97\0i\x97\0j\x97\0t\x97\0u\x97\0|\x97\0}\x97\0\x8B\x97\0\x8C\x97\0\xAD\x97\0\xAE\x97\0\xC3\x97\0\xC4\x97\0\xCB\x97\0\xCC\x97\0\xD3\x97\0\xD4\x97\0\xF3\x97\0\xF4\x97\0\xFB\x97\0\xFC\x97\0\xFF\x97\0\0\x98\0\x01\x98\0\x03\x98\0\x05\x98\0\x07\x98\0\x08\x98\0\t\x98\0\x0C\x98\0\r\x98\0\x10\x98\0\x12\x98\0\x13\x98\0\x14\x98\0\x17\x98\0\x19\x98\0\x1E\x98\0\x1F\x98\0-\x98\0.\x98\08\x98\09\x98\0;\x98\0<\x98\0F\x98\0G\x98\0L\x98\0N\x98\0O\x98\0P\x98\0X\x98\0Y\x98\0[\x98\0\\\x98\0^\x98\0_\x98\0g\x98\0h\x98\0o\x98\0p\x98\0\xA8\x98\0\xA9\x98\0\xB1\x98\0\xB2\x98\0\xC4\x98\0\xC5\x98\0\xC6\x98\0\xC7\x98\0\xDB\x98\0\xDC\x98\0\xDF\x98\0\xE0\x98\0\xEA\x98\0\xEB\x98\0\xEF\x98\0\xF0\x98\0\xF2\x98\0\xF3\x98\0\xFD\x98\0\xFF\x98\0\x03\x99\0\x04\x99\0\x05\x99\0\x06\x99\0\n\x99\0\x0B\x99\0\x0C\x99\0\r\x99\0\x10\x99\0\x11\x99\0\x18\x99\0\x19\x99\0\x1A\x99\0\x1B\x99\0(\x99\0)\x99\0>\x99\0?\x99\0\x96\x99\0\x97\x99\0\x99\x99\0\x9A\x99\0\xAC\x99\0\xAD\x99\0\xD0\x99\0\xD1\x99\0\xD5\x99\0\xD6\x99\0\xDB\x99\0\xDC\x99\0\xDD\x99\0\xDE\x99\0\xF1\x99\0\xF2\x99\0\x0E\x9A\0\x0F\x9A\0\x19\x9A\0\x1A\x9A\x007\x9A\08\x9A\0E\x9A\0F\x9A\0U\x9A\0V\x9A\0W\x9A\0X\x9A\0Z\x9A\0[\x9A\0\xA8\x9A\0\xA9\x9A\0\xD4\x9A\0\xD5\x9A\0\xD8\x9A\0\xD9\x9A\0\xEE\x9A\0\xEF\x9A\0\x06\x9B\0\x07\x9B\0\r\x9B\0\x0E\x9B\0%\x9B\0&\x9B\0'\x9B\0(\x9B\x001\x9B\x002\x9B\0<\x9B\0=\x9B\0A\x9B\0C\x9B\0E\x9B\0F\x9B\0T\x9B\0U\x9B\0Z\x9B\0[\x9B\0o\x9B\0p\x9B\0w\x9B\0x\x9B\0\x91\x9B\0\x92\x9B\0\xAE\x9B\0\xAF\x9B\0\xCA\x9B\0\xCB\x9B\0\xE8\x9B\0\xE9\x9B\0w\x9C\0x\x9C\0\xE5\x9C\0\xE6\x9C\0\xE9\x9C\0\xEA\x9C\0\xF3\x9C\0\xF5\x9C\0(\x9D\0)\x9D\0;\x9D\0<\x9D\0]\x9D\0^\x9D\0a\x9D\0b\x9D\0\xB4\x9D\0\xB5\x9D\0\xF9\x9D\0\xFA\x9D\0\x1A\x9E\0\x1B\x9E\0}\x9E\0~\x9E\0\x7F\x9E\0\x80\x9E\0\x97\x9E\0\x98\x9E\0\xA5\x9E\0\xA6\x9E\0\xB5\x9E\0\xB6\x9E\0\xBB\x9E\0\xBD\x9E\0\xC3\x9E\0\xC4\x9E\0\xCE\x9E\0\xCF\x9E\0\xD1\x9E\0\xD2\x9E\0\xD8\x9E\0\xD9\x9E\0\xDB\x9E\0\xDC\x9E\0\xDE\x9E\0\xDF\x9E\0\xE8\x9E\0\xE9\x9E\0\x13\x9F\0\x14\x9F\0 \x9F\0!\x9F\0,\x9F\0-\x9F\0;\x9F\0<\x9F\0J\x9F\0L\x9F\0R\x9F\0S\x9F\0a\x9F\0b\x9F\0\x8D\x9F\0\x8E\x9F\0\x90\x9F\0\x91\x9F\0\x9C\x9F\0\x9D\x9F\0") }, 2470u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0N\0\x02N\0\x03N\0\x04N\0\x07N\0\x0FN\0\x11N\0\x12N\0\x13N\0\x15N\0\x16N\0\x17N\0\x18N\0\x1BN\0\x1CN\0\x1EN\0\"N\0#N\0$N\0&N\0*N\0+N\0-N\0.N\x000N\x001N\x002N\x003N\x004N\x005N\08N\0<N\0=N\0?N\0CN\0DN\0EN\0FN\0HN\0JN\0KN\0MN\0NN\0QN\0TN\0UN\0VN\0WN\0XN\0ZN\0]N\0^N\0_N\0bN\0fN\0gN\0pN\0rN\0\x86N\0\x87N\0\x88N\0\x8AN\0\x8BN\0\x8DN\0\x8EN\0\x90N\0\x91N\0\x93N\0\x94N\0\x96N\0\x9AN\0\x9CN\0\xA1N\0\xA2N\0\xA4N\0\xA9N\0\xABN\0\xADN\0\xAEN\0\xAFN\0\xB2N\0\xB3N\0\xBAN\0\xBBN\0\xBFN\0\xC2N\0\xC5N\0\xC6N\0\xC7N\0\xC8N\0\xCAN\0\xCCN\0\xCDN\0\xCFN\0\xD1N\0\xD2N\0\xD4N\0\xD5N\0\xD6N\0\xD7N\0\xD8N\0\xDAN\0\xE3N\0\xE6N\0\xEAN\0\xEBN\0\xECN\0\xEDN\0\xF0N\0\xF1N\0\xF2N\0\xF3N\0\xF6N\0\xF8N\0\xFBN\0\xFCN\0\xFDN\0\xFEN\0\x01O\0\x02O\0\nO\0\x0BO\0\rO\0\x0EO\0\x10O\0\x12O\0\x17O\0\x1BO\0\x1FO\0!O\0$O\0%O\0&O\0'O\0/O\x001O\x004O\x005O\08O\09O\0<O\0>O\0FO\0GO\0IO\0JO\0MO\0PO\0SO\0TO\0UO\0VO\0YO\0ZO\0[O\0]O\0`O\0aO\0iO\0jO\0sO\0tO\0\x7FO\0\x80O\0\x8BO\0\x8CO\0\x9BO\0\x9CO\0\x9DO\0\x9EO\0\xA0O\0\xA1O\0\xA6O\0\xA9O\0\xAFO\0\xB0O\0\xB5O\0\xB6O\0\xBFO\0\xC0O\0\xC3O\0\xC5O\0\xCAO\0\xCBO\0\xD7O\0\xD8O\0\xDDO\0\xDEO\0\xE1O\0\xE2O\0\xEEO\0\xEFO\0\xFEO\0\xFFO\0\rP\0\x0EP\0\x12P\0\x13P\0\x19P\0\x1BP\0\x1FP\0 P\0<P\0=P\0>P\0?P\0GP\0HP\0OP\0PP\0ZP\0[P\0\\P\0]P\0eP\0fP\0vP\0xP\0\xA3P\0\xA4P\0\xB2P\0\xB3P\0\xBBP\0\xBCP\0\xCFP\0\xD0P\0\xE7P\0\xE8P\0\x12Q\0\x13Q\0?Q\0@Q\0AQ\0BQ\0CQ\0FQ\0HQ\0JQ\0KQ\0LQ\0MQ\0NQ\0TQ\0UQ\0ZQ\0[Q\0eQ\0fQ\0hQ\0iQ\0kQ\0oQ\0pQ\0rQ\0sQ\0zQ\0{Q\0~Q\0\x85Q\0\x86Q\0\x88Q\0\x89Q\0\x8CQ\0\x8EQ\0\x92Q\0\x93Q\0\x99Q\0\x9AQ\0\x9BQ\0\x9DQ\0\xA0Q\0\xA1Q\0\xACQ\0\xADQ\0\xB0Q\0\xB1Q\0\xB2Q\0\xB4Q\0\xB5Q\0\xB6Q\0\xB7Q\0\xB8Q\0\xC0Q\0\xC1Q\0\xC6Q\0\xC7Q\0\xC9Q\0\xCAQ\0\xCCQ\0\xCDQ\0\xCFQ\0\xD0Q\0\xDDQ\0\xDEQ\0\xE0Q\0\xE2Q\0\xE4Q\0\xE5Q\0\xEDQ\0\xEEQ\0\xEFQ\0\xF1Q\0\xF6Q\0\xF7Q\0\xFAQ\0\xFCQ\0\xFDQ\0\xFEQ\0\0R\0\x01R\0\x06R\0\x08R\0\nR\0\x0BR\0\x12R\0\x13R\0\x17R\0\x1CR\0\x1DR\0\x1ER\0 R\0!R\0$R\0%R\0)R\0*R\0+R\0,R\x000R\x001R\x006R\08R\0:R\0<R\0LR\0NR\0QR\0RR\0gR\0hR\0iR\0kR\0oR\0pR\0rR\0sR\0\x9BR\0\x9CR\0\x9DR\0\xA2R\0\xA8R\0\xACR\0\xB1R\0\xB4R\0\xBFR\0\xC0R\0\xC7R\0\xC8R\0\xC9R\0\xCAR\0\xD2R\0\xD3R\0\xE4R\0\xE5R\0\xFFR\0\0S\0\x05S\0\x06S\0\x08S\0\tS\0\x16S\0\x18S\09S\0<S\0AS\0BS\0CS\0DS\0GS\0IS\0JS\0KS\0NS\0PS\0RS\0TS\0US\0XS\0ZS\0[S\0\\S\0]S\0`S\0cS\0gS\0hS\0kS\0lS\0oS\0rS\0sS\0uS\0wS\0xS\0\x82S\0\x83S\0\x84S\0\x87S\0\x89S\0\x8AS\0\x8BS\0\x8DS\0\x98S\0\x99S\0\x9AS\0\x9BS\0\x9FS\0\xA0S\0\xBBS\0\xBCS\0\xBFS\0\xC0S\0\xC2S\0\xC3S\0\xC8S\0\xC9S\0\xCAS\0\xCES\0\xD1S\0\xD2S\0\xD4S\0\xD5S\0\xD6S\0\xDAS\0\xE3S\0\xE7S\0\xEAS\0\xEES\0\xEFS\0\xF1S\0\xF2S\0\xF4S\0\xF6S\0\xFAS\0\x03T\0\x05T\0\x08T\0\x0BT\0\x0CT\0\x0FT\0\x10T\0\x12T\0\x13T\0\x14T\0\x15T\0\x16T\0\x17T\0\x18T\0\x1BT\0\x1CT\0\x1DT\0!T\0&T\0(T\0+T\0-T\0/T\x000T\x004T\x006T\08T\0:T\0>T\0?T\0@T\0AT\0FT\0GT\0JT\0KT\0XT\0YT\0\\T\0]T\0bT\0cT\0hT\0iT\0sT\0tT\0uT\0vT\0|T\0~T\0\x8CT\0\x8DT\0\x96T\0\x97T\0\xA4T\0\xA5T\0\xA6T\0\xA8T\0\xAAT\0\xABT\0\xACT\0\xADT\0\xB1T\0\xB2T\0\xC0T\0\xC2T\0\xC7T\0\xCAT\0\xCDT\0\xCFT\0\xE5T\0\xE7T\0\xE9T\0\xEBT\0\xEDT\0\xEET\0\xF2T\0\xF3T\0\tU\0\nU\0\x10U\0\x11U\0\x14U\0\x15U\0,U\0-U\0.U\x000U\x001U\x002U\x007U\08U\0FU\0GU\0JU\0KU\0aU\0bU\0eU\0gU\0jU\0kU\0pU\0qU\0\x80U\0\x81U\0\x82U\0\x83U\0\x84U\0\x85U\0\x87U\0\x88U\0\x8AU\0\x8BU\0\x94U\0\x95U\0\x9CU\0\x9EU\0\xB5U\0\xB6U\0\xB7U\0\xB8U\0\xE8U\0\xE9U\0\xEFU\0\xF0U\0\tV\0\nV\0\x1BV\0\x1CV\x004V\x005V\0;V\0<V\0?V\0@V\0hV\0iV\0\xDBV\0\xDCV\0\xDEV\0\xDFV\0\xE0V\0\xE1V\0\xE2V\0\xE3V\0\xEDV\0\xEEV\0\xF0V\0\xF1V\0\xF4V\0\xF5V\0\xFAV\0\xFBV\0\xFDV\0\xFFV\0\x06W\0\x07W\0\x08W\0\tW\0\x1CW\0\x1DW\0\x1FW\0 W\0#W\0$W\0(W\0)W\0-W\0.W\x000W\x001W\0:W\0;W\0>W\0?W\0@W\0AW\0GW\0HW\0NW\0QW\0WW\0XW\0ZW\0]W\0aW\0bW\0dW\0eW\0fW\0gW\0jW\0kW\0\x82W\0\x84W\0\x8BW\0\x8CW\0\x92W\0\x93W\0\xC3W\0\xC4W\0\xCEW\0\xCFW\0\xD4W\0\xD5W\0\xDFW\0\xE0W\0\xF9W\0\xFBW\0\x02X\0\x03X\0\x06X\0\x07X\0\x15X\0\x16X\0!X\0\"X\0*X\0+X\0TX\0UX\0^X\0_X\0kX\0lX\0\x83X\0\x84X\0\x99X\0\x9AX\0\x9EX\0\x9FX\0\xA8X\0\xA9X\0\xC1X\0\xC2X\0\xEBX\0\xEDX\0\xEEX\0\xEFX\0\xF0X\0\xF1X\0\xF3X\0\xF4X\0\x04Y\0\x05Y\0\x07Y\0\x08Y\0\rY\0\x0EY\0\x0FY\0\x10Y\0\x15Y\0\x17Y\0\x1AY\0\x1BY\0\x1CY\0\x1DY\0\x1FY\0 Y\0'Y\0(Y\0)Y\0,Y\0.Y\0/Y\x001Y\x002Y\x004Y\x005Y\x007Y\0;Y\0GY\0JY\0KY\0LY\0NY\0PY\0QY\0RY\0TY\0UY\0VY\0XY\0eY\0fY\0sY\0uY\0vY\0wY\0yY\0zY\0}Y\0~Y\0\x82Y\0\x83Y\0\x86Y\0\x89Y\0\x99Y\0\x9AY\0\xA5Y\0\xA6Y\0\xA8Y\0\xA9Y\0\xAEY\0\xAFY\0\xB3Y\0\xB4Y\0\xB9Y\0\xBAY\0\xBBY\0\xBCY\0\xC6Y\0\xC7Y\0\xCBY\0\xCCY\0\xD0Y\0\xD2Y\0\xD3Y\0\xD5Y\0\xFFY\0\0Z\0\x01Z\0\x02Z\0\x03Z\0\x05Z\0\x18Z\0\x19Z\x001Z\x002Z\0FZ\0GZ\0ZZ\0[Z\0\x92Z\0\x93Z\0\xCCZ\0\xCDZ\0\xE9Z\0\xEAZ\0P[\0Q[\0T[\0U[\0W[\0Z[\0][\0^[\0_[\0`[\0c[\0e[\0f[\0g[\0i[\0j[\0\x81[\0\x82[\0\x83[\0\x84[\0\x85[\0\x86[\0\x87[\0\x8A[\0\x8B[\0\x8D[\0\x8F[\0\x90[\0\x97[\0\x9F[\0\xA0[\0\xA5[\0\xAA[\0\xAC[\0\xB3[\0\xB4[\0\xB6[\0\xB7[\0\xB9[\0\xBA[\0\xBD[\0\xC0[\0\xC2[\0\xC3[\0\xC4[\0\xC7[\0\xCC[\0\xCD[\0\xD2[\0\xD3[\0\xDD[\0\xE0[\0\xE8[\0\xE9[\0\xEE[\0\xEF[\0\xF9[\0\xFA[\0\xFB[\0\xFD[\0\xFF[\0\0\\\0\x01\\\0\x02\\\0\x04\\\0\x05\\\0\x06\\\0\x07\\\0\n\\\0\x0B\\\0\x0F\\\0\x10\\\0\x11\\\0\x12\\\0\x14\\\0\x15\\\0\x16\\\0\x17\\\0\x18\\\0\x19\\\0\x1A\\\0\x1B\\\0\x1D\\\0\x1E\\\0$\\\0%\\\x001\\\x002\\\0:\\\0;\\\0<\\\0?\\\0@\\\0C\\\0E\\\0F\\\0J\\\0L\\\0O\\\0P\\\0U\\\0V\\\0^\\\0_\\\0`\\\0a\\\0q\\\0r\\\0\x81\\\0\x83\\\0\x9A\\\0\x9C\\\0\xA9\\\0\xAA\\\0\xAD\\\0\xAE\\\0\xB8\\\0\xB9\\\0\xE1\\\0\xE2\\\0\xF0\\\0\xF1\\\0\x07]\0\x08]\x004]\x005]\0\xDD]\0\xDF]\0\xE1]\0\xE2]\0\xE5]\0\xE9]\0\xEB]\0\xEC]\0\xEE]\0\xEF]\0\xF1]\0\xF5]\0\xF7]\0\xF8]\0\x01^\0\x04^\0\x05^\0\x06^\0\x08^\0\t^\0\x0C^\0\r^\0\x10^\0\x11^\0\x15^\0\x17^\0\x1B^\0\x1C^\0\x1D^\0\x1E^\0&^\0'^\0-^\0/^\08^\09^\0=^\0>^\0E^\0F^\0U^\0V^\0r^\0u^\0v^\0w^\0x^\0y^\0{^\0~^\0\x7F^\0\x80^\0\x84^\0\x85^\0\x86^\0\x88^\0\x8A^\0\x8B^\0\x8F^\0\x90^\0\x93^\0\x96^\0\x97^\0\x98^\0\x9A^\0\x9B^\0\x9C^\0\x9D^\0\x9F^\0\xA0^\0\xA6^\0\xA8^\0\xAD^\0\xAE^\0\xB7^\0\xB9^\0\xC9^\0\xCA^\0\xD6^\0\xD7^\0\xF6^\0\xF8^\0\xFA^\0\xFB^\0\0_\0\x01_\0\x02_\0\x05_\0\x0F_\0\x10_\0\x15_\0\x16_\0\x17_\0\x19_\0\x1F_\0!_\0%_\0'_\0/_\x000_\x001_\x002_\09_\0;_\0J_\0K_\0R_\0T_\0U_\0V_\0]_\0^_\0b_\0c_\0f_\0g_\0i_\0j_\0l_\0n_\0p_\0r_\0y_\0z_\0{_\0}_\0\x80_\0\x82_\0\x84_\0\x86_\0\x88_\0\x89_\0\x8B_\0\x8C_\0\x90_\0\x91_\0\x92_\0\x93_\0\x97_\0\x98_\0\xAE_\0\xAF_\0\xB7_\0\xB8_\0\xC3_\0\xC4_\0\xC5_\0\xC7_\0\xCC_\0\xCE_\0\xD7_\0\xDA_\0\xE0_\0\xE1_\0\xE7_\0\xE8_\0\xEB_\0\xEC_\0\xF5_\0\xF6_\0\xFD_\0\xFE_\0\0`\0\x02`\0\x0E`\0\x0F`\0\x12`\0\x13`\0\x15`\0\x17`\0\x1C`\0\x1E`\0!`\0\"`\0%`\0&`\0'`\0)`\0*`\0+`\0;`\0<`\0K`\0L`\0P`\0Q`\0R`\0S`\0b`\0c`\0h`\0j`\0m`\0n`\0o`\0q`\0v`\0w`\0|`\0}`\0\x89`\0\x8A`\0\x94`\0\x95`\0\x9F`\0\xA1`\0\xA6`\0\xA7`\0\xA8`\0\xA9`\0\xB2`\0\xB3`\0\xC5`\0\xC6`\0\xCA`\0\xCB`\0\xD1`\0\xD2`\0\xDC`\0\xDD`\0\xE0`\0\xE1`\0\xE7`\0\xE9`\0\xEF`\0\xF0`\0\xF3`\0\xF4`\0\xF9`\0\xFA`\0\x01a\0\x02a\0\x08a\0\na\0\x0Fa\0\x10a\0\x1Aa\0\x1Ba\0\x1Fa\0 a\0?a\0@a\0Ha\0Ia\0Ua\0Va\0ba\0ca\0ga\0ha\0pa\0qa\0\xBEa\0\xBFa\0\xC2a\0\xC3a\0\xD2a\0\xD3a\0\x08b\0\tb\0\nb\0\x0Bb\0\x0Cb\0\rb\0\x0Fb\0\x13b\0\x16b\0\x17b\0\x18b\0\x19b\0*b\0+b\x004b\x005b\x007b\08b\0?b\0Bb\0Gb\0Hb\0Kb\0Lb\0Mb\0Ob\0Sb\0Tb\0Xb\0Yb\0cb\0db\0eb\0fb\0gb\0hb\0ib\0jb\0kb\0nb\0ob\0qb\0yb\0zb\0~b\0\x81b\0\x84b\0\x85b\0\x8Ab\0\x8Bb\0\x93b\0\x94b\0\x95b\0\x96b\0\x97b\0\x99b\0\x9Bb\0\x9Cb\0\xA2b\0\xA3b\0\xA4b\0\xA6b\0\xABb\0\xADb\0\xB1b\0\xB2b\0\xB5b\0\xB6b\0\xB9b\0\xBAb\0\xBDb\0\xBEb\0\xC5b\0\xC7b\0\xC9b\0\xCAb\0\xCDb\0\xCEb\0\xCFb\0\xD0b\0\xD2b\0\xD3b\0\xD4b\0\xD5b\0\xD6b\0\xD7b\0\xDBb\0\xDDb\0\xDFb\0\xE0b\0\xE5b\0\xE6b\0\xE8b\0\xEAb\0\xECb\0\xEDb\0\xF3b\0\xF4b\0\xFCb\0\xFDb\0\xFEb\0\0c\0\x01c\0\x03c\0\x07c\0\x08c\0\tc\0\nc\0\x11c\0\x12c\0\x16c\0\x17c\0\x1Dc\0\x1Ec\0!c\0\"c\0$c\0&c\0*c\0+c\0/c\x000c\0:c\0;c\0Pc\0Qc\0Uc\0Vc\0_c\0`c\0ac\0cc\0nc\0oc\0wc\0xc\0\x88c\0\x8Ac\0\x8Cc\0\x8Dc\0\x92c\0\x93c\0\xA2c\0\xA3c\0\xA5c\0\xA6c\0\xA7c\0\xA9c\0\xAAc\0\xABc\0\xB8c\0\xB9c\0\xCFc\0\xD1c\0\xD2c\0\xD3c\0\xE1c\0\xE2c\0\xF4c\0\xF5c\0\x1Cd\0\x1Dd\0\x1Ed\0\x1Fd\0,d\0.d\0Dd\0Ed\0Fd\0Hd\0Xd\0Yd\0id\0jd\0xd\0yd\0\x91d\0\x93d\0\x9Ed\0\x9Fd\0\xADd\0\xAEd\0\xCDd\0\xCFd\0\xE6d\0\xE7d\0/e\x000e\x006e\x007e\09e\0:e\0;e\0<e\0>e\0@e\0Ee\0Fe\0He\0Ie\0Le\0Ne\0Oe\0Pe\0Qe\0Re\0Ye\0Ze\0]e\0^e\0be\0de\0fe\0ge\0le\0me\0pe\0qe\0te\0ue\0\x87e\0\x88e\0\x8Be\0\x8Ce\0\x90e\0\x91e\0\x97e\0\x98e\0\x99e\0\x9Ae\0\xADe\0\xAEe\0\xAFe\0\xB1e\0\xB9e\0\xBAe\0\xBDe\0\xBEe\0\xC1e\0\xC2e\0\xC5e\0\xC6e\0\xCBe\0\xCCe\0\xCFe\0\xD0e\0\xD7e\0\xD8e\0\xE0e\0\xE1e\0\xE2e\0\xE3e\0\xE5e\0\xE8e\0\xE9e\0\xEAe\0\xEDe\0\xEEe\0\xF6e\0\xF7e\0\xFAe\0\xFBe\0\x02f\0\x03f\0\x06f\0\x07f\0\x0Cf\0\rf\0\x0Ef\0\x10f\0\x13f\0\x14f\0\x1Ff\0!f\0%f\0&f\0(f\0)f\0-f\0.f\0/f\x000f\0>f\0?f\0Kf\0Lf\0Rf\0Tf\0Zf\0[f\0hf\0if\0nf\0pf\0tf\0uf\0vf\0wf\0zf\0{f\0\x82f\0\x83f\0\x91f\0\x92f\0\x96f\0\x98f\0\xB4f\0\xB5f\0\xF0f\0\xF1f\0\xF2f\0\xF3f\0\xF4f\0\xF5f\0\xFCf\0\xFDf\0\xFEf\0\x01g\0\x08g\0\ng\0\x0Bg\0\x0Cg\0\rg\0\x0Eg\0\x17g\0\x18g\0\x1Bg\0\x1Cg\0\x1Dg\0\x1Eg\0\x1Fg\0 g\0(g\0)g\0*g\0.g\0/g\x000g\x001g\x002g\x005g\x006g\0:g\0;g\0@g\0Ag\0Bg\0Dg\0Ig\0Jg\0Ng\0Og\0Pg\0Rg\0\\g\0]g\0_g\0`g\0ag\0bg\0eg\0fg\0hg\0ig\0og\0qg\0~g\0\x80g\0\x81g\0\x82g\0\x84g\0\x85g\0\x90g\0\x91g\0\x97g\0\x98g\0\x9Cg\0\x9Eg\0\xA2g\0\xA3g\0\xAAg\0\xACg\0\xB6g\0\xB7g\0\xCFg\0\xD1g\0\xD3g\0\xD5g\0\xE5g\0\xE6g\0\xECg\0\xEDg\0\xEFg\0\xF0g\0\xF3g\0\xF5g\0\x07h\0\x08h\0\x0Fh\0\x10h\0\x11h\0\x12h\0!h\0\"h\x007h\0:h\0<h\0=h\0Ch\0Dh\0Hh\0Ih\0Lh\0Mh\0Qh\0Rh\0ch\0dh\0eh\0fh\0\x81h\0\x82h\0\x85h\0\x86h\0\xA6h\0\xA7h\0\xA8h\0\xA9h\0\xAFh\0\xB1h\0\xB5h\0\xB6h\0\xC0h\0\xC1h\0\xC9h\0\xCAh\0\xCBh\0\xCCh\0\xD2h\0\xD3h\0\xDAh\0\xDBh\0\xEEh\0\xEFh\0\x05i\0\x06i\0\ri\0\x0Ei\x000i\x001i\0Zi\0[i\0|i\0}i\0\x82i\0\x83i\0\x9Ci\0\x9Di\0!j\0\"j\0*j\0+j\0\x80j\0\x81j\0!k\0$k\0'k\0(k\x002k\x003k\0:k\0;k\0>k\0?k\0Ik\0Jk\0Lk\0Mk\0bk\0gk\0{k\0|k\0\x8Ak\0\x8Ck\0\xB5k\0\xB6k\0\xC1k\0\xC2k\0\xC5k\0\xC6k\0\xCDk\0\xCEk\0\xCFk\0\xD0k\0\xD2k\0\xD3k\0\xD4k\0\xD6k\0\xDBk\0\xDCk\0\xEBk\0\xECk\0\x0Fl\0\x10l\0\x11l\0\x12l\0\x14l\0\x15l\x004l\x005l\08l\09l\0Bl\0Cl\0Il\0Jl\0Wl\0Xl\0]l\0^l\0_l\0bl\0dl\0el\0jl\0kl\0vl\0wl\0}l\0~l\0\x83l\0\x84l\0\x88l\0\x8Al\0\x99l\0\x9Al\0\x9Fl\0\xA0l\0\xA1l\0\xA2l\0\xA7l\0\xA8l\0\xB3l\0\xB4l\0\xB9l\0\xBAl\0\xBBl\0\xBCl\0\xBFl\0\xC0l\0\xC4l\0\xC5l\0\xC9l\0\xCBl\0\xD5l\0\xD6l\0\xE1l\0\xE3l\0\xE5l\0\xE6l\0\xE8l\0\xE9l\0\xEAl\0\xEBl\0\xF0l\0\xF1l\0\xF3l\0\xF4l\0\xFDl\0\xFFl\0\x01m\0\x02m\0\x0Bm\0\x0Cm\0\x17m\0\x18m\0\x1Bm\0\x1Cm\0\x1Em\0\x1Fm\0*m\0+m\x002m\x003m\0;m\0<m\0=m\0?m\0Am\0Bm\0Em\0Fm\0Km\0Lm\0Nm\0Pm\0Sm\0Tm\0fm\0gm\0im\0km\0nm\0om\0wm\0xm\0\x82m\0\x83m\0\x88m\0\x8Am\0\x9Bm\0\x9Cm\0\xA8m\0\xA9m\0\xAFm\0\xB0m\0\xB2m\0\xB3m\0\xB5m\0\xB6m\0\xD1m\0\xD2m\0\xE1m\0\xE2m\0\xF1m\0\xF2m\0\xF7m\0\xF8m\0\x05n\0\x06n\0\x10n\0\x11n\0!n\0\"n\0)n\0*n\0/n\x000n\08n\09n\0Vn\0Wn\0~n\0\x7Fn\0\x90n\0\x91n\0\xAAn\0\xABn\0\xCBn\0\xCCn\0\xD1n\0\xD2n\0\xDAn\0\xDBn\0\xE1n\0\xE2n\0\xE5n\0\xE6n\0\xE8n\0\xE9n\0\xF4n\0\xF5n\0\x02o\0\x03o\0\x0Fo\0\x10o\0\x14o\0\x15o\0 o\0!o\0+o\0,o\0Xo\0Yo\0\\o\0]o\0no\0oo\0\xB3o\0\xB4o\0\xC0o\0\xC1o\0Lp\0Mp\0kp\0lp\0mp\0np\0op\0qp\0up\0vp\0~p\0\x7Fp\0\x89p\0\x8Ap\0\x8Ep\0\x8Fp\0\xAEp\0\xAFp\0\xB8p\0\xBAp\0\xC2p\0\xC3p\0\xC8p\0\xC9p\0\xDFp\0\xE0p\0\xE4p\0\xE5p\0\xE6p\0\xE8p\0\xEDp\0\xEEp\0&q\0'q\x006q\x007q\0^q\0_q\0gq\0hq\0\x8Aq\0\x8Bq\0\x9Fq\0\xA0q\0\xC3q\0\xC4q\0\x06r\0\x07r\0*r\0+r\0,r\0-r\x001r\x002r\x005r\09r\0=r\0>r\0Gr\0Ir\0Lr\0Mr\0Yr\0Zr\0[r\0\\r\0`r\0ar\0gr\0hr\0ir\0jr\0rr\0sr\0ur\0vr\0yr\0{r\0\xAFr\0\xB0r\0\xB6r\0\xB7r\0\xB9r\0\xBAr\0\xC2r\0\xC3r\0\xD0r\0\xD1r\0\xD7r\0\xD8r\0\xE0r\0\xE1r\0\xECr\0\xEDr\0\xEEr\0\xEFr\0\xF1r\0\xF2r\0\xFCr\0\xFDr\0\x1Bs\0\x1Ds\0*s\0,s\0.s\0/s\x004s\x005s\0\x84s\0\x85s\0\x87s\0\x88s\0\x89s\0\x8As\0\x8Bs\0\x8Cs\0\x9Bs\0\x9Cs\0\xA9s\0\xAAs\0\xABs\0\xACs\0\xAFs\0\xB1s\0\xB2s\0\xB3s\0\xBBs\0\xBCs\0\xCAs\0\xCBs\0\xCDs\0\xCEs\0\xE0s\0\xE1s\0\xE5s\0\xE6s\0\xEDs\0\xEEs\0\x03t\0\x04t\0\x06t\0\x07t\0\tt\0\nt\0*t\0+t\x004t\x005t\0Yt\0Zt\0\\t\0]t\0^t\0`t\0pt\0qt\0vt\0wt\0\xDCt\0\xDDt\0\xE6t\0\xE7t\0\xF6t\0\xF7t\0\x18u\0\x19u\0\x1Au\0\x1Bu\0\x1Cu\0\x1Du\0\x1Fu\0 u\0(u\0)u\x000u\x004u\x005u\x006u\x007u\09u\0;u\0<u\0Lu\0Mu\0Yu\0Zu\0eu\0fu\0ju\0ku\0\x86u\0\x87u\0\x8Fu\0\x90u\0\x91u\0\x92u\0\x97u\0\x98u\0\xAFu\0\xB0u\0\xBCu\0\xBDu\0\xC5u\0\xC6u\0\xD5u\0\xD6u\0\xDBu\0\xDCu\0\xF4u\0\xF5u\0xv\0yv\0{v\0|v\0}v\0\x7Fv\0\x84v\0\x85v\0\x86v\0\x88v\0\xAEv\0\xAFv\0\xCAv\0\xCBv\0\xD1v\0\xD2v\0\xD6v\0\xD9v\0\xDBv\0\xDCv\0\xDFv\0\xE0v\0\xEEv\0\xEFv\0\xF2v\0\xF3v\0\xF4v\0\xF5v\0\xF8v\0\xF9v\0\xFCv\0\xFDv\0\xFEv\0\xFFv\0\x01w\0\x02w\0\tw\0\nw\0\x0Bw\0\x0Cw\0\x1Fw\0!w\0<w\0=w\0@w\0Aw\0[w\0\\w\0aw\0bw\0cw\0dw\0\xA7w\0\xA8w\0\xDBw\0\xDCw\0\xE3w\0\xE4w\0\xE5w\0\xE6w\0\xEDw\0\xEEw\0\xF3w\0\xF4w\0\xF6w\0\xF7w\0\x01x\0\x03x\0\rx\0\x0Ex\0\x14x\0\x15x\x004x\x005x\0@x\0Ax\0Ux\0Vx\0lx\0mx\0nx\0ox\0\x8Dx\0\x8Fx\0\x97x\0\x98x\0\x9Fx\0\xA0x\0\xA7x\0\xA8x\0\xB0x\0\xB1x\0\xC1x\0\xC2x\0\xE8x\0\xE9x\0:y\0;y\0<y\0=y\0>y\0?y\0Vy\0Wy\0Zy\0\\y\0]y\0_y\0ey\0fy\0hy\0iy\0oy\0py\0xy\0yy\0\x81y\0\x82y\0\x84y\0\x86y\0\x8Fy\0\x90y\0\xBBy\0\xBCy\0\xC0y\0\xC2y\0\xCBy\0\xCCy\0\xCDy\0\xCEy\0\xD1y\0\xD3y\0\xD8y\0\xD9y\0\xDFy\0\xE0y\0\xE4y\0\xE5y\0\xE6y\0\xE7y\0\xEFy\0\xF1y\0\xFBy\0\xFCy\0\x0Bz\0\x0Cz\0\rz\0\x0Fz\0#z\0$z\x003z\x004z\0?z\0@z\0Fz\0Gz\0vz\0xz\0yz\0{z\0\x7Fz\0\x80z\0\x81z\0\x82z\0\x97z\0\x98z\0\x9Dz\0\x9Ez\0\xADz\0\xAEz\0\xCBz\0\xCCz\0\xD9z\0\xDAz\0\xDEz\0\xE1z\0\xE5z\0\xE6z\0\xEFz\0\xF0z\0\xF9z\0\xFAz\0\x11{\0\x12{\0\x14{\0\x15{\0\x1B{\0\x1C{\0&{\0'{\0({\0){\0,{\0-{\0I{\0J{\0K{\0L{\0Q{\0R{\0T{\0U{\0V{\0W{\0y{\0z{\0~{\0\x7F{\0\x80{\0\x81{\0\x97{\0\x98{\0\xA1{\0\xA2{\0\xAB{\0\xAC{\0\xAD{\0\xAE{\0\xB1{\0\xB2{\0\xC7{\0\xC8{\0\xEE{\0\xEF{\0?|\0@|\0M|\0N|\0s|\0t|\0{|\0||\0\x89|\0\x8A|\0\x97|\0\x98|\0\xA4|\0\xA5|\0\xBE|\0\xBF|\0\xCA|\0\xCB|\0\xD5|\0\xD6|\0\xDF|\0\xE0|\0\xFB|\0\xFC|\0 }\0!}\0\"}\0#}\0'}\0(}\0+}\0,}\0/}\x000}\0A~\0B~\0\xA0~\0\xA1~\0\xA2~\0\xA3~\0\xA6~\0\xA8~\0\xAA~\0\xAB~\0\xAC~\0\xAD~\0\xAF~\0\xB0~\0\xB2~\0\xB4~\0\xB5~\0\xB6~\0\xB7~\0\xB9~\0\xBD~\0\xBE~\0\xBF~\0\xC0~\0\xC3~\0\xC5~\0\xC6~\0\xC9~\0\xCD~\0\xCE~\0\xCF~\0\xD0~\0\xD3~\0\xD4~\0\xD5~\0\xD6~\0\xD8~\0\xDA~\0\xDC~\0\xDE~\0\xDF~\0\xE0~\0\xE7~\0\xE8~\0\xE9~\0\xEB~\0\xED~\0\xEE~\0\xF4~\0\xF5~\0\xFC~\0\xFD~\0\xFF~\0\0\x7F\0\x05\x7F\0\x06\x7F\0\x13\x7F\0\x14\x7F\0\x16\x7F\0\x17\x7F\0\x18\x7F\0\x19\x7F\0\x1A\x7F\0\x1B\x7F\0)\x7F\0+\x7F\x004\x7F\x005\x7F\08\x7F\09\x7F\0:\x7F\0;\x7F\0Q\x7F\0R\x7F\0U\x7F\0V\x7F\0W\x7F\0X\x7F\0Z\x7F\0[\x7F\0b\x7F\0c\x7F\0j\x7F\0k\x7F\0n\x7F\0o\x7F\0r\x7F\0s\x7F\0\x8A\x7F\0\x8B\x7F\0\x8E\x7F\0\x8F\x7F\0\x9E\x7F\0\x9F\x7F\0\xA4\x7F\0\xA5\x7F\0\xBD\x7F\0\xBE\x7F\0\xC1\x7F\0\xC2\x7F\0\xD4\x7F\0\xD5\x7F\0\xD8\x7F\0\xD9\x7F\0\xF0\x7F\0\xF1\x7F\0\xFB\x7F\0\xFD\x7F\0\0\x80\0\x02\x80\0\x03\x80\0\x04\x80\0\x05\x80\0\x06\x80\0\x0C\x80\0\x0E\x80\0\x10\x80\0\x11\x80\0\x17\x80\0\x18\x80\x003\x80\x004\x80\x006\x80\x007\x80\0;\x80\0<\x80\0J\x80\0K\x80\0L\x80\0M\x80\0T\x80\0U\x80\0Z\x80\0[\x80\0j\x80\0k\x80\0\x89\x80\0\x8A\x80\0\x9A\x80\0\x9B\x80\0\xA1\x80\0\xA2\x80\0\xA5\x80\0\xA6\x80\0\xA9\x80\0\xAA\x80\0\xAF\x80\0\xB0\x80\0\xB2\x80\0\xB3\x80\0\xC6\x80\0\xC7\x80\0\xCC\x80\0\xCD\x80\0\xCE\x80\0\xCF\x80\0\xD6\x80\0\xD7\x80\0\xDC\x80\0\xDD\x80\0\xDE\x80\0\xDF\x80\0\xE1\x80\0\xE2\x80\0\xF8\x80\0\xF9\x80\0\xFD\x80\0\xFE\x80\0\x06\x81\0\x07\x81\0\x11\x81\0\x12\x81\0\x1A\x81\0\x1B\x81\x001\x81\x002\x81\08\x81\09\x81\0J\x81\0K\x81\0S\x81\0U\x81\0p\x81\0q\x81\0\x7F\x81\0\x80\x81\0\xE3\x81\0\xE4\x81\0\xEA\x81\0\xEB\x81\0\xED\x81\0\xEE\x81\0\xF3\x81\0\xF5\x81\0\x0C\x82\0\x0E\x82\0\x12\x82\0\x13\x82\0\x1E\x82\0 \x82\0*\x82\0+\x82\0,\x82\0-\x82\x000\x82\x001\x82\09\x82\0:\x82\0o\x82\0p\x82\0r\x82\0s\x82\0z\x82\0{\x82\0~\x82\0\x7F\x82\0\x82\x82\0\x83\x82\0\x9D\x82\0\x9E\x82\0\xA6\x82\0\xA7\x82\0\xAC\x82\0\xAD\x82\0\xB1\x82\0\xB2\x82\0\xB3\x82\0\xB4\x82\0\xCD\x82\0\xCE\x82\0\xCF\x82\0\xD0\x82\0\xE5\x82\0\xE7\x82\0\xF1\x82\0\xF2\x82\0\x03\x83\0\x04\x83\0\x05\x83\0\x06\x83\0+\x83\0,\x83\x006\x83\x007\x83\0I\x83\0J\x83\0P\x83\0Q\x83\0R\x83\0S\x83\0c\x83\0d\x83\0o\x83\0p\x83\0w\x83\0x\x83\0|\x83\0}\x83\0\x89\x83\0\x8A\x83\0\x8E\x83\0\x8F\x83\0\xAB\x83\0\xAC\x83\0\xB1\x83\0\xB3\x83\0\xB7\x83\0\xB8\x83\0\xDC\x83\0\xDD\x83\0\xE9\x83\0\xEA\x83\0\xF2\x83\0\xF3\x83\0\x04\x84\0\x05\x84\0$\x84\0&\x84\0'\x84\0)\x84\0=\x84\0>\x84\0[\x84\0\\\x84\0a\x84\0b\x84\0\x82\x84\0\x83\x84\0\x8B\x84\0\x8C\x84\0\x99\x84\0\x9A\x84\0\xB2\x84\0\xB3\x84\0\xDD\x84\0\xDE\x84\0\x15\x85\0\x16\x85\0!\x85\0\"\x85\0\x84\x85\0\x85\x85\0\xAA\x85\0\xAB\x85\0\xCF\x85\0\xD0\x85\0\xE4\x85\0\xE5\x85\0N\x86\0O\x86\0Q\x86\0R\x86\0Z\x86\0[\x86\0k\x86\0l\x86\0}\x86\0~\x86\0\xC7\x86\0\xC8\x86\0\xCB\x86\0\xCC\x86\0\xD9\x86\0\xDA\x86\0\xEE\x86\0\xEF\x86\0\x02\x87\0\x03\x87\0\x1C\x87\0\x1D\x87\0N\x87\0O\x87\0v\x87\0w\x87\0\x8D\x87\0\x8E\x87\0\xF9\x87\0\xFA\x87\0@\x88\0A\x88\0L\x88\0M\x88\0W\x88\0X\x88\0a\x88\0b\x88\0c\x88\0d\x88\0e\x88\0f\x88\0h\x88\0i\x88\0\x8B\x88\0\x8C\x88\0\xAB\x88\0\xAC\x88\0\xC1\x88\0\xC3\x88\0\xC5\x88\0\xC6\x88\0\xD5\x88\0\xD6\x88\0\xE4\x88\0\xE5\x88\0\x7F\x89\0\x80\x89\0\x81\x89\0\x82\x89\0\x86\x89\0\x87\x89\0\xC1\x89\0\xC3\x89\0\xC4\x89\0\xC5\x89\0\xC6\x89\0\xC7\x89\0\xC8\x89\0\xCA\x89\0\xD2\x89\0\xD3\x89\0\xE3\x89\0\xE4\x89\0\xE6\x89\0\xE7\x89\0\0\x8A\0\x01\x8A\0\x89\x8A\0\x8A\x8A\0\x93\x8A\0\x94\x8A\0f\x8B\0g\x8B\0\xA1\x8B\0\xA3\x8B\0\xA4\x8B\0\xA5\x8B\0\xA8\x8B\0\xAA\x8B\0\xAD\x8B\0\xB1\x8B\0\xB2\x8B\0\xB3\x8B\0\xB7\x8B\0\xB9\x8B\0\xBA\x8B\0\xBB\x8B\0\xBE\x8B\0\xC0\x8B\0\xC1\x8B\0\xC2\x8B\0\xC4\x8B\0\xC5\x8B\0\xC6\x8B\0\xC7\x8B\0\xC9\x8B\0\xCA\x8B\0\xCD\x8B\0\xCE\x8B\0\xD1\x8B\0\xD2\x8B\0\xD5\x8B\0\xD6\x8B\0\xD7\x8B\0\xD8\x8B\0\xDA\x8B\0\xDB\x8B\0\xDD\x8B\0\xDF\x8B\0\xE2\x8B\0\xE3\x8B\0\xE5\x8B\0\xE7\x8B\0\xED\x8B\0\xEE\x8B\0\xEF\x8B\0\xF0\x8B\0\xF4\x8B\0\xF5\x8B\0\xF7\x8B\0\xF9\x8B\0\xFA\x8B\0\xFC\x8B\0\xFE\x8B\0\xFF\x8B\0\x01\x8C\0\x02\x8C\0\x03\x8C\0\x04\x8C\0\x05\x8C\0\x06\x8C\0\x08\x8C\0\t\x8C\0\n\x8C\0\x0C\x8C\0\x13\x8C\0\x14\x8C\0\x1A\x8C\0\x1B\x8C\0\"\x8C\0#\x8C\x001\x8C\x002\x8C\x007\x8C\08\x8C\0F\x8C\0G\x8C\0a\x8C\0b\x8C\0j\x8C\0k\x8C\0\x8C\x8C\0\x8D\x8C\0\x1D\x8D\0 \x8D\0!\x8D\0&\x8D\0'\x8D\0)\x8D\0*\x8D\0+\x8D\0-\x8D\0.\x8D\0/\x8D\x000\x8D\x001\x8D\x002\x8D\x004\x8D\x006\x8D\09\x8D\0;\x8D\0>\x8D\0?\x8D\0D\x8D\0E\x8D\0K\x8D\0M\x8D\0O\x8D\0Q\x8D\0V\x8D\0W\x8D\0Z\x8D\0\\\x8D\0^\x8D\0_\x8D\0`\x8D\0a\x8D\0b\x8D\0c\x8D\0d\x8D\0e\x8D\0k\x8D\0l\x8D\0p\x8D\0q\x8D\0u\x8D\0x\x8D\0\x85\x8D\0\x86\x8D\0\x8A\x8D\0\x8C\x8D\0\xA3\x8D\0\xA4\x8D\0\xB3\x8D\0\xB4\x8D\0\xC3\x8D\0\xC4\x8D\0\xCC\x8D\0\xCD\x8D\0\xCE\x8D\0\xCF\x8D\0\xD1\x8D\0\xD2\x8D\0\xDD\x8D\0\xDE\x8D\0\xDF\x8D\0\xE0\x8D\0\xEF\x8D\0\xF0\x8D\0\xF3\x8D\0\xF4\x8D\0\x0F\x8E\0\x10\x8E\0\"\x8E\0#\x8E\0*\x8E\0+\x8E\0\xAB\x8E\0\xAC\x8E\0\xB2\x8E\0\xB3\x8E\0f\x8F\0g\x8F\0h\x8F\0j\x8F\0l\x8F\0m\x8F\0n\x8F\0q\x8F\0{\x8F\0|\x8F\0}\x8F\0~\x8F\0\x83\x8F\0\x84\x8F\0\x85\x8F\0\x87\x8F\0\x88\x8F\0\x8A\x8F\0\x91\x8F\0\x92\x8F\0\x93\x8F\0\x94\x8F\0\x9B\x8F\0\x9C\x8F\0\x9E\x8F\0\x9F\x8F\0\xA8\x8F\0\xAA\x8F\0\xB0\x8F\0\xB2\x8F\0\xB9\x8F\0\xBA\x8F\0\xBE\x8F\0\xBF\x8F\0\xC1\x8F\0\xC2\x8F\0\xC5\x8F\0\xC6\x8F\0\xC7\x8F\0\xC9\x8F\0\xCE\x8F\0\xCF\x8F\0\xD0\x8F\0\xD2\x8F\0\xD4\x8F\0\xD5\x8F\0\xD8\x8F\0\xDA\x8F\0\xDB\x8F\0\xE0\x8F\0\xE6\x8F\0\xE7\x8F\0\xEA\x8F\0\xEC\x8F\0\xF0\x8F\0\xF1\x8F\0\xF7\x8F\0\xF8\x8F\0\xF9\x8F\0\xFA\x8F\0\xFD\x8F\0\xFE\x8F\0\0\x90\0\x04\x90\0\x06\x90\0\x07\x90\0\t\x90\0\x0B\x90\0\x0F\x90\0\x11\x90\0\x14\x90\0\x15\x90\0\x1A\x90\0\x1C\x90\0\x1D\x90\0\x1E\x90\0\x1F\x90\0!\x90\0\"\x90\0#\x90\08\x90\09\x90\0;\x90\0=\x90\0G\x90\0H\x90\0M\x90\0N\x90\0S\x90\0T\x90\0W\x90\0X\x90\0e\x90\0f\x90\0m\x90\0o\x90\0\x7F\x90\0\x81\x90\0\xA3\x90\0\xA4\x90\0\xA6\x90\0\xA7\x90\0\xAA\x90\0\xAB\x90\0\xAE\x90\0\xAF\x90\0\xB1\x90\0\xB2\x90\0\xBB\x90\0\xBC\x90\0\xC1\x90\0\xC2\x90\0\xCE\x90\0\xCF\x90\0\xD1\x90\0\xD2\x90\0\xE8\x90\0\xE9\x90\0\xED\x90\0\xEE\x90\0\xFD\x90\0\xFE\x90\0\x02\x91\0\x03\x91\0I\x91\0J\x91\0M\x91\0N\x91\0R\x91\0S\x91\0w\x91\0y\x91\0\x89\x91\0\x8A\x91\0\x92\x91\0\x93\x91\0\xC7\x91\0\xC8\x91\0\xCA\x91\0\xCB\x91\0\xCC\x91\0\xD0\x91\0\xD1\x91\0\xD2\x91\0t\x92\0u\x92\0\x88\x94\0\x89\x94\0\x93\x94\0\x94\x94\0\x9F\x94\0\xA0\x94\0\xA2\x94\0\xA3\x94\0\xA6\x94\0\xA7\x94\0\xB1\x94\0\xB2\x94\0\xB5\x94\0\xB6\x94\0\xC1\x94\0\xC2\x94\0\xC3\x94\0\xC4\x94\0\xDC\x94\0\xDD\x94\0\xE2\x94\0\xE3\x94\0\xED\x94\0\xEE\x94\0\xF6\x94\0\xF7\x94\0\0\x95\0\x02\x95\0\x05\x95\0\x06\x95\0\x0B\x95\0\x0C\x95\0\x10\x95\0\x11\x95\0\x19\x95\0\x1A\x95\0!\x95\0\"\x95\0&\x95\0'\x95\0.\x95\0/\x95\0G\x95\0H\x95\0Q\x95\0R\x95\0\\\x95\0]\x95\0\x7F\x95\0\x80\x95\0\xE8\x95\0\xE9\x95\0\xEA\x95\0\xEB\x95\0\xED\x95\0\xEF\x95\0\xF0\x95\0\xF1\x95\0\xF2\x95\0\xF3\x95\0\xF4\x95\0\xF5\x95\0\xF7\x95\0\xF8\x95\0\xF9\x95\0\xFA\x95\0\xFB\x95\0\xFC\x95\0\x01\x96\0\x02\x96\0\x05\x96\0\x06\x96\0\x07\x96\0\x08\x96\0\x10\x96\0\x11\x96\0\x14\x96\0\x15\x96\0\x17\x96\0\x18\x96\0\x1F\x96\0 \x96\x002\x96\x007\x96\0;\x96\0<\x96\0?\x96\0A\x96\0D\x96\0G\x96\0H\x96\0I\x96\0M\x96\0N\x96\0P\x96\0Q\x96\0b\x96\0c\x96\0d\x96\0e\x96\0i\x96\0k\x96\0u\x96\0x\x96\0\x86\x96\0\x87\x96\0\x8F\x96\0\x91\x96\0\x94\x96\0\x95\x96\0\x9C\x96\0\x9D\x96\0\xBE\x96\0\xBF\x96\0\xC4\x96\0\xC7\x96\0\xC9\x96\0\xCA\x96\0\xE8\x96\0\xE9\x96\0\xEA\x96\0\xEB\x96\0\xF3\x96\0\xF4\x96\0\xF6\x96\0\xF8\x96\0\xFE\x96\0\xFF\x96\0\0\x97\0\x01\x97\0\x07\x97\0\x08\x97\0\r\x97\0\x0E\x97\x002\x97\x003\x97\08\x97\0:\x97\0R\x97\0S\x97\0V\x97\0W\x97\0Y\x97\0Z\x97\0^\x97\0_\x97\0`\x97\0a\x97\0b\x97\0c\x97\0i\x97\0j\x97\0|\x97\0}\x97\0\x8B\x97\0\x8C\x97\0\x91\x97\0\x92\x97\0\xE6\x97\0\xE7\x97\0\xE9\x97\0\xEA\x97\0\xF3\x97\0\xF4\x97\0\xF5\x97\0\xF6\x97\0\x1E\x98\0\x1F\x98\0u\x98\0w\x98\0y\x98\0|\x98\0}\x98\0\x80\x98\0\x84\x98\0\x85\x98\0\x86\x98\0\x88\x98\0\x91\x98\0\x92\x98\0\x97\x98\0\x99\x98\0\x9C\x98\0\x9E\x98\0\xCE\x98\0\xCF\x98\0\xD8\x98\0\xD9\x98\0\xDE\x98\0\xE0\x98\0\x10\x99\0\x11\x99\0m\x99\0o\x99\0p\x99\0r\x99\0|\x99\0}\x99\0\x86\x99\0\x87\x99\0\x96\x99\0\x97\x99\0\x99\x99\0\x9A\x99\0l\x9A\0m\x9A\0q\x9A\0r\x9A\0v\x9A\0w\x9A\0{\x9A\0|\x9A\0~\x9A\0\x7F\x9A\0\x82\x9A\0\x83\x9A\0\x8C\x9A\0\x8D\x9A\0\x91\x9A\0\x92\x9A\0\x97\x9A\0\x98\x9A\0\x9A\x9A\0\x9B\x9A\0\xA8\x9A\0\xA9\x9A\0\xD8\x9A\0\xD9\x9A\0<\x9B\0=\x9B\0A\x9B\0C\x9B\0E\x9B\0F\x9B\0T\x9B\0U\x9B\0|\x9C\0}\x9C\0\x81\x9C\0\x82\x9C\0\x9C\x9C\0\x9D\x9C\0\x1F\x9E\0 \x9E\0!\x9E\0\"\x9E\0#\x9E\0$\x9E\0?\x9E\0@\x9E\0E\x9E\0F\x9E\0p\x9E\0q\x9E\0\x7F\x9E\0\x80\x9E\0\xA6\x9E\0\xA7\x9E\0\xBB\x9E\0\xBC\x9E\0\xC4\x9E\0\xC5\x9E\0\xCE\x9E\0\xCF\x9E\0\xD1\x9E\0\xD2\x9E\0\xD8\x9E\0\xD9\x9E\0\x13\x9F\0\x14\x9F\0 \x9F\0!\x9F\0;\x9F\0<\x9F\0P\x9F\0Q\x9F\0\x7F\x9F\0\x80\x9F\0\x84\x9F\0\x85\x9F\0\x99\x9F\0\x9A\x9F\0\x9F\x9F\0\xA0\x9F\0") }, 2124u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0N\0\x02N\0\x03N\0\x04N\0\x07N\0\x0FN\0\x11N\0\x12N\0\x13N\0\x15N\0\x16N\0\x17N\0\x18N\0\x1BN\0\x1CN\0\x1EN\0\"N\0#N\0$N\0&N\0'N\0(N\0*N\0+N\0-N\0.N\x000N\x001N\x002N\x003N\x004N\x005N\08N\0<N\0=N\0?N\0CN\0DN\0EN\0FN\0HN\0JN\0KN\0QN\0TN\0UN\0VN\0WN\0XN\0ZN\0]N\0^N\0_N\0bN\0fN\0gN\0pN\0rN\0~N\0\x7FN\0\x86N\0\x87N\0\x88N\0\x8AN\0\x8BN\0\x8DN\0\x8EN\0\x90N\0\x91N\0\x93N\0\x94N\0\x96N\0\x9AN\0\x9CN\0\xA1N\0\xA2N\0\xA4N\0\xA9N\0\xABN\0\xADN\0\xAEN\0\xAFN\0\xB2N\0\xB3N\0\xBAN\0\xBBN\0\xBFN\0\xC2N\0\xC5N\0\xC6N\0\xC7N\0\xC8N\0\xCAN\0\xCCN\0\xCDN\0\xCFN\0\xD4N\0\xD5N\0\xD6N\0\xD7N\0\xD8N\0\xDAN\0\xE3N\0\xE6N\0\xEAN\0\xEBN\0\xECN\0\xEDN\0\xF0N\0\xF1N\0\xF2N\0\xF3N\0\xF6N\0\xF8N\0\xFBN\0\xFCN\0\xFDN\0\xFEN\0\xFFN\0\0O\0\x01O\0\x02O\0\nO\0\x0BO\0\rO\0\x0EO\0\x0FO\0\x12O\0\x17O\0\x1BO\0\x1FO\0!O\0$O\0%O\0&O\0'O\0/O\x001O\x004O\x005O\08O\09O\0<O\0>O\0FO\0GO\0MO\0RO\0SO\0TO\0UO\0VO\0YO\0ZO\0[O\0]O\0`O\0aO\0dO\0eO\0iO\0jO\0sO\0tO\0\x7FO\0\x80O\0\x8BO\0\x8CO\0\x9BO\0\x9CO\0\x9DO\0\x9EO\0\xA0O\0\xA1O\0\xA6O\0\xA9O\0\xACO\0\xADO\0\xAFO\0\xB0O\0\xB5O\0\xB6O\0\xBFO\0\xC0O\0\xC3O\0\xC5O\0\xCAO\0\xCBO\0\xD7O\0\xD8O\0\xDDO\0\xDEO\0\xE1O\0\xE2O\0\xE9O\0\xEAO\0\xEEO\0\xEFO\0\xF1O\0\xF2O\0\xFEO\0\xFFO\0\rP\0\x0EP\0\x12P\0\x13P\0\x19P\0\x1BP\0\x1FP\0 P\0&P\0'P\0<P\0=P\0>P\0?P\0GP\0HP\0LP\0MP\0OP\0PP\0ZP\0[P\0\\P\0]P\0eP\0fP\0vP\0xP\0\xA8P\0\xA9P\0\xACP\0\xADP\0\xB2P\0\xB3P\0\xBBP\0\xBCP\0\xCFP\0\xD0P\0\xE7P\0\xE8P\0\x12Q\0\x13Q\0?Q\0@Q\0AQ\0BQ\0CQ\0GQ\0HQ\0JQ\0KQ\0LQ\0MQ\0NQ\0QQ\0RQ\0TQ\0UQ\0ZQ\0[Q\0eQ\0fQ\0hQ\0iQ\0kQ\0oQ\0pQ\0rQ\0sQ\0zQ\0{Q\0~Q\0\x85Q\0\x86Q\0\x88Q\0\x89Q\0\x8CQ\0\x8EQ\0\x92Q\0\x93Q\0\x99Q\0\x9AQ\0\x9BQ\0\x9DQ\0\xA0Q\0\xA1Q\0\xACQ\0\xADQ\0\xB0Q\0\xB1Q\0\xB2Q\0\xB4Q\0\xB5Q\0\xB6Q\0\xB7Q\0\xB8Q\0\xC6Q\0\xC7Q\0\xCCQ\0\xCDQ\0\xCFQ\0\xD0Q\0\xDDQ\0\xDEQ\0\xE0Q\0\xE2Q\0\xE4Q\0\xE5Q\0\xEDQ\0\xEEQ\0\xEFQ\0\xF1Q\0\xFAQ\0\xFCQ\0\xFDQ\0\xFEQ\0\0R\0\x01R\0\x06R\0\x08R\0\nR\0\x0BR\0\x11R\0\x13R\0\x17R\0\x1CR\0\x1DR\0\x1ER\0$R\0%R\0)R\0*R\0+R\0,R\x000R\x001R\x006R\09R\0:R\0<R\0BR\0CR\0MR\0NR\0QR\0RR\0gR\0hR\0iR\0kR\0oR\0pR\0rR\0sR\0\x9BR\0\x9CR\0\x9DR\0\xA2R\0\xA3R\0\xA4R\0\xA8R\0\xACR\0\xB1R\0\xB4R\0\xBFR\0\xC0R\0\xC7R\0\xC8R\0\xC9R\0\xCAR\0\xCBR\0\xCCR\0\xD2R\0\xD3R\0\xE4R\0\xE5R\0\xFER\0\0S\0\x05S\0\x07S\0\x08S\0\tS\0\x16S\0\x18S\0\x19S\0\x1AS\09S\0<S\0AS\0BS\0CS\0DS\0GS\0IS\0JS\0KS\0NS\0PS\0RS\0TS\0US\0XS\0ZS\0[S\0`S\0cS\0kS\0lS\0oS\0rS\0sS\0uS\0wS\0xS\0\x82S\0\x83S\0\x84S\0\x87S\0\x89S\0\x8AS\0\x8BS\0\x8ES\0\x9AS\0\x9BS\0\x9FS\0\xA0S\0\xBBS\0\xBCS\0\xBFS\0\xC0S\0\xC2S\0\xC3S\0\xC8S\0\xCES\0\xD1S\0\xD2S\0\xD4S\0\xD5S\0\xD6S\0\xDAS\0\xE3S\0\xE7S\0\xEAS\0\xEES\0\xEFS\0\xF1S\0\xF2S\0\xF4S\0\xF6S\0\xFAS\0\x03T\0\x05T\0\x08T\0\x0BT\0\x0CT\0\x0FT\0\x10T\0\x12T\0\x13T\0\x14T\0\x17T\0\x18T\0\x1BT\0\x1CT\0\x1DT\0\x1ET\0\x1FT\0 T\0&T\0(T\0+T\0-T\0/T\x000T\x005T\x006T\08T\0:T\0;T\0<T\0>T\0?T\0@T\0AT\0FT\0GT\0HT\0IT\0JT\0KT\0PT\0QT\0XT\0YT\0\\T\0]T\0bT\0cT\0fT\0gT\0hT\0iT\0sT\0tT\0uT\0vT\0|T\0~T\0\x8CT\0\x8DT\0\x96T\0\x97T\0\xA6T\0\xA9T\0\xAAT\0\xABT\0\xACT\0\xADT\0\xAFT\0\xB0T\0\xB1T\0\xB2T\0\xC0T\0\xC2T\0\xC7T\0\xCAT\0\xCDT\0\xCFT\0\xDFT\0\xE0T\0\xE5T\0\xE7T\0\xE9T\0\xEBT\0\xEDT\0\xEET\0\xF2T\0\xF3T\0\tU\0\nU\0\x10U\0\x11U\0$U\0%U\0,U\0-U\0.U\x000U\x001U\x002U\x007U\08U\0FU\0GU\0JU\0KU\0aU\0bU\0eU\0gU\0jU\0kU\0\x80U\0\x81U\0\x82U\0\x83U\0\x84U\0\x85U\0\x87U\0\x88U\0\x8AU\0\x8BU\0\x8FU\0\x90U\0\x94U\0\x95U\0\x9CU\0\x9EU\0\xB5U\0\xB6U\0\xB7U\0\xB8U\0\xBBU\0\xBCU\0\xD2U\0\xD3U\0\xE8U\0\xE9U\0\xEFU\0\xF0U\0\tV\0\nV\0\x1BV\0\x1CV\x004V\x005V\0;V\0<V\0?V\0@V\0hV\0iV\0\xDBV\0\xDCV\0\xDEV\0\xDFV\0\xE0V\0\xE1V\0\xE2V\0\xE3V\0\xEDV\0\xEEV\0\xF0V\0\xF1V\0\xF4V\0\xF5V\0\xFAV\0\xFBV\0\xFDV\0\xFFV\0\x06W\0\x07W\0\x08W\0\tW\0\x1FW\0 W\0#W\0$W\0(W\0)W\0-W\0.W\x000W\x001W\x003W\x004W\0:W\0;W\0>W\0?W\0@W\0AW\0GW\0HW\0NW\0OW\0PW\0RW\0WW\0XW\0ZW\0]W\0aW\0bW\0dW\0eW\0fW\0gW\0jW\0kW\0\x82W\0\x84W\0\x8BW\0\x8CW\0\x92W\0\x93W\0\xC3W\0\xC4W\0\xCBW\0\xCCW\0\xCEW\0\xCFW\0\xD4W\0\xD5W\0\xDFW\0\xE0W\0\xF9W\0\xFBW\0\x02X\0\x03X\0\x06X\0\x07X\0\x15X\0\x16X\0!X\0\"X\0*X\0+X\0QX\0RX\0TX\0UX\0^X\0_X\0kX\0lX\0\x83X\0\x84X\0\x9EX\0\x9FX\0\xA8X\0\xA9X\0\xC1X\0\xC2X\0\xE4X\0\xE5X\0\xEBX\0\xEDX\0\xEEX\0\xEFX\0\xF0X\0\xF1X\0\x04Y\0\x05Y\0\x07Y\0\x08Y\0\rY\0\x0EY\0\x0FY\0\x10Y\0\x15Y\0\x17Y\0\x1AY\0\x1BY\0\x1CY\0\x1DY\0\x1FY\0 Y\0%Y\0&Y\0'Y\0(Y\0)Y\0,Y\0.Y\0/Y\x001Y\x002Y\x004Y\x005Y\x007Y\0;Y\0GY\0JY\0KY\0LY\0OY\0PY\0QY\0RY\0TY\0UY\0VY\0XY\0eY\0fY\0sY\0uY\0vY\0wY\0yY\0zY\0}Y\0~Y\0\x82Y\0\x83Y\0\x87Y\0\x89Y\0\x96Y\0\x97Y\0\x99Y\0\x9AY\0\xA5Y\0\xA6Y\0\xA8Y\0\xA9Y\0\xAEY\0\xAFY\0\xB9Y\0\xBAY\0\xBBY\0\xBCY\0\xC6Y\0\xC7Y\0\xCAY\0\xCCY\0\xD0Y\0\xD2Y\0\xD3Y\0\xD5Y\0\xFFY\0\0Z\0\x01Z\0\x02Z\0\x03Z\0\x05Z\0\x18Z\0\x19Z\0\x1CZ\0\x1DZ\0\x1FZ\0 Z\x001Z\x002Z\0FZ\0GZ\0ZZ\0[Z\0\x92Z\0\x93Z\0\xC1Z\0\xC2Z\0\xCCZ\0\xCDZ\0\xE9Z\0\xEAZ\0P[\0Q[\0T[\0V[\0W[\0Z[\0\\[\0^[\0_[\0`[\0c[\0e[\0f[\0g[\0i[\0j[\0\x81[\0\x82[\0\x83[\0\x84[\0\x87[\0\x8A[\0\x8B[\0\x8D[\0\x8F[\0\x90[\0\x97[\0\x9F[\0\xA1[\0\xA5[\0\xAA[\0\xAB[\0\xB3[\0\xB5[\0\xB6[\0\xB7[\0\xB9[\0\xBA[\0\xBD[\0\xC0[\0\xC2[\0\xC3[\0\xC4[\0\xC8[\0\xCC[\0\xCD[\0\xD2[\0\xD3[\0\xDD[\0\xE0[\0\xE1[\0\xE2[\0\xE8[\0\xE9[\0\xF8[\0\xFA[\0\xFB[\0\xFD[\0\xFF[\0\0\\\0\x01\\\0\x02\\\0\x04\\\0\x05\\\0\x06\\\0\x07\\\0\n\\\0\x0B\\\0\x0F\\\0\x10\\\0\x11\\\0\x12\\\0\x14\\\0\x15\\\0\x16\\\0\x17\\\0\x18\\\0\x19\\\0\x1A\\\0\x1B\\\0\x1D\\\0\x1E\\\0$\\\0%\\\x001\\\x002\\\0:\\\0;\\\0<\\\0?\\\0@\\\0C\\\0E\\\0F\\\0K\\\0L\\\0O\\\0P\\\0U\\\0V\\\0^\\\0_\\\0`\\\0a\\\0q\\\0r\\\0\x81\\\0\x83\\\0\x97\\\0\x99\\\0\x9A\\\0\x9C\\\0\xB3\\\0\xB4\\\0\xB8\\\0\xB9\\\0\xE1\\\0\xE2\\\0\xF0\\\0\xF1\\\0\x07]\0\x08]\0)]\0*]\x004]\x005]\0\xDD]\0\xDF]\0\xE1]\0\xE2]\0\xE5]\0\xE9]\0\xEB]\0\xEC]\0\xEE]\0\xEF]\0\xF1]\0\xF5]\0\xF7]\0\xF8]\0\x01^\0\x04^\0\x05^\0\x06^\0\x08^\0\t^\0\x0C^\0\r^\0\x10^\0\x11^\0\x15^\0\x17^\0\x1D^\0\x1E^\0&^\0'^\0-^\0/^\08^\09^\0=^\0>^\0E^\0F^\0U^\0V^\0r^\0u^\0v^\0w^\0x^\0y^\0{^\0~^\0\x7F^\0\x80^\0\x86^\0\x87^\0\x8A^\0\x8B^\0\x8F^\0\x90^\0\x93^\0\x96^\0\x97^\0\x98^\0\x99^\0\x9B^\0\x9C^\0\x9D^\0\x9E^\0\xA0^\0\xA6^\0\xA8^\0\xAD^\0\xAE^\0\xB7^\0\xB9^\0\xC9^\0\xCA^\0\xD6^\0\xD7^\0\xF6^\0\xF8^\0\xFA^\0\xFB^\0\0_\0\x01_\0\x02_\0\x05_\0\n_\0\x0B_\0\x0F_\0\x10_\0\x15_\0\x16_\0\x17_\0\x19_\0\x1F_\0!_\0%_\0'_\0/_\x000_\x001_\x002_\09_\0;_\0R_\0T_\0U_\0V_\0]_\0^_\0b_\0c_\0i_\0j_\0l_\0n_\0p_\0r_\0w_\0x_\0y_\0z_\0{_\0}_\0\x80_\0\x82_\0\x84_\0\x86_\0\x88_\0\x89_\0\x8B_\0\x8D_\0\x90_\0\x91_\0\x92_\0\x93_\0\x97_\0\x98_\0\xAA_\0\xAB_\0\xAE_\0\xAF_\0\xB5_\0\xB6_\0\xB7_\0\xB8_\0\xC3_\0\xC4_\0\xC5_\0\xC7_\0\xCC_\0\xCE_\0\xD7_\0\xDA_\0\xE0_\0\xE1_\0\xE7_\0\xE8_\0\xEB_\0\xEC_\0\xF5_\0\xF6_\0\xFD_\0\xFE_\0\0`\0\x02`\0\x0E`\0\x0F`\0\x12`\0\x13`\0\x15`\0\x17`\0\x1D`\0\x1E`\0!`\0\"`\0%`\0&`\0'`\0)`\0*`\0+`\0;`\0<`\0K`\0L`\0P`\0Q`\0b`\0c`\0h`\0j`\0m`\0n`\0o`\0q`\0v`\0w`\0|`\0}`\0\x84`\0\x85`\0\x89`\0\x8A`\0\x94`\0\x95`\0\x9F`\0\xA1`\0\xA3`\0\xA4`\0\xA8`\0\xA9`\0\xB2`\0\xB3`\0\xC5`\0\xC6`\0\xD1`\0\xD2`\0\xDC`\0\xDD`\0\xE0`\0\xE1`\0\xE7`\0\xE9`\0\xEF`\0\xF0`\0\xF3`\0\xF4`\0\xF9`\0\xFA`\0\x01a\0\x02a\0\x08a\0\na\0\x0Fa\0\x10a\0\x1Aa\0\x1Ba\0\x1Fa\0 a\0'a\0(a\0Ha\0Ia\0Na\0Oa\0Ua\0Va\0ba\0ca\0ga\0ha\0pa\0qa\0\xBEa\0\xBFa\0\xC2a\0\xC3a\0\xD2a\0\xD3a\0\x08b\0\tb\0\nb\0\x0Bb\0\x0Cb\0\rb\0\x0Fb\0\x13b\0\x16b\0\x17b\0\x18b\0\x19b\0*b\0+b\x004b\x005b\x007b\08b\0?b\0Bb\0Gb\0Hb\0Kb\0Lb\0Mb\0Ob\0Qb\0Rb\0Sb\0Tb\0Xb\0Yb\0cb\0db\0gb\0hb\0ib\0jb\0kb\0pb\0yb\0zb\0~b\0\x81b\0\x84b\0\x85b\0\x8Ab\0\x8Bb\0\x91b\0\x92b\0\x93b\0\x94b\0\x95b\0\x96b\0\x97b\0\x99b\0\xA2b\0\xA3b\0\xA4b\0\xA6b\0\xABb\0\xADb\0\xB1b\0\xB2b\0\xB5b\0\xB6b\0\xB9b\0\xBAb\0\xBDb\0\xBEb\0\xC5b\0\xC7b\0\xC9b\0\xCAb\0\xCDb\0\xCEb\0\xD2b\0\xD3b\0\xD4b\0\xD5b\0\xD6b\0\xD7b\0\xD8b\0\xD9b\0\xDBb\0\xDDb\0\xDFb\0\xE0b\0\xE5b\0\xE7b\0\xE8b\0\xEAb\0\xECb\0\xEDb\0\xF3b\0\xF4b\0\xF7b\0\xF8b\0\xFCb\0\xFDb\0\xFEb\0\0c\0\x01c\0\x02c\0\x07c\0\x08c\0\tc\0\nc\0\x11c\0\x12c\0\x16c\0\x17c\0\x1Dc\0\x1Ec\0!c\0\"c\0$c\0&c\0*c\0+c\0/c\x000c\0:c\0;c\0Ic\0Jc\0Pc\0Qc\0Uc\0Vc\0_c\0`c\0ac\0cc\0nc\0oc\0wc\0xc\0\x88c\0\x8Ac\0\x8Cc\0\x8Dc\0\x92c\0\x93c\0\xA2c\0\xA3c\0\xA5c\0\xA6c\0\xA7c\0\xABc\0\xB8c\0\xB9c\0\xCFc\0\xD1c\0\xD2c\0\xD3c\0\xE1c\0\xE2c\0\xF4c\0\xF5c\0\x1Cd\0\x1Dd\0\x1Ed\0\x1Fd\0,d\0.d\0Dd\0Ed\0Fd\0Gd\0Jd\0Kd\0Td\0Ud\0Xd\0Yd\0id\0jd\0xd\0yd\0\x92d\0\x93d\0\x9Ed\0\x9Fd\0\xADd\0\xAEd\0\xCDd\0\xCFd\0\xE6d\0\xE7d\0/e\x000e\x006e\x007e\09e\0:e\0;e\0<e\0>e\0@e\0Ee\0Fe\0He\0Ie\0Le\0Me\0Oe\0Pe\0Qe\0Re\0Ye\0Ze\0]e\0^e\0be\0de\0fe\0ge\0le\0me\0pe\0qe\0re\0se\0te\0ue\0\x87e\0\x88e\0\x8Be\0\x8Ce\0\x90e\0\x91e\0\x97e\0\x98e\0\x99e\0\x9Ae\0\x9Ce\0\x9De\0\xA5e\0\xA6e\0\xADe\0\xAEe\0\xAFe\0\xB1e\0\xB9e\0\xBAe\0\xBCe\0\xBEe\0\xC1e\0\xC2e\0\xC5e\0\xC6e\0\xCBe\0\xCCe\0\xCFe\0\xD0e\0\xD7e\0\xD8e\0\xE0e\0\xE1e\0\xE2e\0\xE3e\0\xE5e\0\xEAe\0\xEDe\0\xEEe\0\xF6e\0\xF7e\0\xFAe\0\xFBe\0\x02f\0\x03f\0\x06f\0\x07f\0\x0Cf\0\rf\0\x0Ef\0\x10f\0\x13f\0\x14f\0\x1Ff\0!f\0%f\0&f\0(f\0)f\0-f\0.f\0/f\x000f\0>f\0?f\0Cf\0Df\0Kf\0Lf\0Rf\0Tf\0Zf\0[f\0hf\0if\0nf\0pf\0tf\0uf\0vf\0wf\0zf\0{f\0\x82f\0\x83f\0\x91f\0\x92f\0\x96f\0\x98f\0\xAEf\0\xAFf\0\xB4f\0\xB5f\0\xF0f\0\xF1f\0\xF2f\0\xF3f\0\xF4f\0\xF5f\0\xF9f\0\xFAf\0\xFCf\0\xFDf\0\xFEf\0\x01g\0\x08g\0\ng\0\x0Bg\0\x0Cg\0\rg\0\x0Eg\0\x17g\0\x18g\0\x1Bg\0\x1Cg\0\x1Dg\0\x1Eg\0\x1Fg\0 g\0(g\0)g\0*g\0.g\0/g\x000g\x001g\x002g\x005g\x006g\0:g\0;g\0@g\0Ag\0Bg\0Dg\0Ig\0Jg\0Ng\0Og\0Pg\0Rg\0\\g\0]g\0_g\0`g\0ag\0bg\0eg\0fg\0hg\0ig\0og\0qg\0~g\0\x80g\0\x81g\0\x82g\0\x84g\0\x85g\0\x90g\0\x91g\0\x97g\0\x98g\0\x9Cg\0\x9Eg\0\xA2g\0\xA3g\0\xAAg\0\xACg\0\xB6g\0\xB7g\0\xCFg\0\xD1g\0\xD3g\0\xD5g\0\xE5g\0\xE6g\0\xECg\0\xEDg\0\xEFg\0\xF0g\0\xF3g\0\xF5g\0\x07h\0\x08h\0\x0Bh\0\x0Ch\0\x0Fh\0\x10h\0\x11h\0\x12h\0!h\0\"h\x007h\0:h\0<h\0=h\0Ch\0Dh\0Fh\0Gh\0Hh\0Ih\0Lh\0Mh\0Qh\0Rh\0ch\0dh\0eh\0fh\0\x81h\0\x82h\0\x85h\0\x86h\0\xA6h\0\xA7h\0\xAFh\0\xB1h\0\xB5h\0\xB6h\0\xC0h\0\xC1h\0\xC9h\0\xCAh\0\xCBh\0\xCCh\0\xD2h\0\xD3h\0\xDAh\0\xDBh\0\xEEh\0\xEFh\0\x05i\0\x06i\0\ri\0\x0Ei\x000i\x001i\0Zi\0[i\0|i\0}i\0\x82i\0\x83i\0\x9Ci\0\x9Di\0!j\0\"j\x001j\x002j\0\x80j\0\x81j\0 k\0$k\0'k\0(k\x002k\x003k\0:k\0;k\0>k\0?k\0Ik\0Jk\0Lk\0Mk\0bk\0gk\0jk\0kk\0{k\0|k\0\x8Ak\0\x8Ck\0\xB5k\0\xB6k\0\xC5k\0\xC6k\0\xCDk\0\xCEk\0\xCFk\0\xD0k\0\xD2k\0\xD3k\0\xD4k\0\xD6k\0\xDBk\0\xDCk\0\xEBk\0\xECk\0\x0Fl\0\x10l\0\x11l\0\x12l\0\x14l\0\x15l\0\x1Bl\0\x1Cl\x004l\x005l\08l\09l\0Bl\0Cl\0Gl\0Hl\0Il\0Jl\0Wl\0Xl\0]l\0^l\0_l\0bl\0dl\0el\0jl\0kl\0vl\0wl\0}l\0~l\0\x83l\0\x84l\0\x88l\0\x8Al\0\x99l\0\x9Al\0\x9Fl\0\xA0l\0\xA1l\0\xA2l\0\xA7l\0\xA8l\0\xB3l\0\xB4l\0\xB9l\0\xBAl\0\xBBl\0\xBCl\0\xBFl\0\xC0l\0\xC9l\0\xCBl\0\xD5l\0\xD6l\0\xDBl\0\xDCl\0\xE1l\0\xE4l\0\xE5l\0\xE6l\0\xE8l\0\xE9l\0\xF0l\0\xF1l\0\xF3l\0\xF4l\0\xFDl\0\xFEl\0\x0Bm\0\x0Cm\0\x17m\0\x18m\0\x1Bm\0\x1Cm\0\x1Em\0\x1Fm\0%m\0&m\0*m\0+m\x002m\x003m\0;m\0<m\0=m\0?m\0Am\0Bm\0Em\0Fm\0Km\0Lm\0Nm\0Pm\0Qm\0Rm\0Sm\0Tm\0Ym\0Zm\0fm\0gm\0im\0km\0nm\0om\0tm\0um\0wm\0xm\0\x85m\0\x86m\0\x88m\0\x8Am\0\x9Bm\0\x9Cm\0\xA8m\0\xA9m\0\xAFm\0\xB0m\0\xB2m\0\xB3m\0\xB5m\0\xB6m\0\xCBm\0\xCCm\0\xD1m\0\xD2m\0\xD8m\0\xD9m\0\xE1m\0\xE2m\0\xF1m\0\xF2m\0\xF7m\0\xF8m\0\xFBm\0\xFCm\0\x05n\0\x06n\0\x10n\0\x11n\0!n\0\"n\0#n\0$n\0)n\0*n\0/n\x000n\x004n\x005n\08n\09n\0Vn\0Wn\0~n\0\x7Fn\0\x90n\0\x91n\0\x9Cn\0\x9Dn\0\xAAn\0\xABn\0\xCBn\0\xCCn\0\xD1n\0\xD2n\0\xE1n\0\xE2n\0\xE5n\0\xE6n\0\xE8n\0\xE9n\0\xF4n\0\xF5n\0\x02o\0\x03o\0\x0Fo\0\x10o\0\x14o\0\x15o\0 o\0!o\0+o\0,o\0Xo\0Yo\0\\o\0]o\0no\0oo\0\x8Eo\0\x8Fo\0\xB3o\0\xB4o\0\xC0o\0\xC1o\0Lp\0Mp\0kp\0lp\0mp\0np\0op\0qp\0up\0vp\0\x7Fp\0\x80p\0\x89p\0\x8Ap\0\x8Ep\0\x8Fp\0\xAEp\0\xAFp\0\xB8p\0\xBAp\0\xC2p\0\xC3p\0\xC8p\0\xC9p\0\xE4p\0\xE5p\0\xE6p\0\xE8p\0\xEDp\0\xEEp\0&q\0'q\x006q\x007q\0Lq\0Mq\0^q\0_q\0gq\0hq\0nq\0oq\0\x8Aq\0\x8Bq\0\x9Fq\0\xA0q\0\xC3q\0\xC4q\0\xD5q\0\xD6q\0\x06r\0\x07r\0*r\0+r\0,r\0-r\x001r\x002r\x005r\09r\0=r\0>r\0Gr\0Ir\0Lr\0Mr\0Yr\0Zr\0[r\0\\r\0ar\0cr\0gr\0hr\0ir\0jr\0rr\0sr\0ur\0vr\0yr\0{r\0\xAFr\0\xB0r\0\xB6r\0\xB7r\0\xB9r\0\xBAr\0\xC2r\0\xC3r\0\xD0r\0\xD1r\0\xD7r\0\xD8r\0\xE0r\0\xE1r\0\xECr\0\xEDr\0\xEEr\0\xEFr\0\xF1r\0\xF2r\0\xFCr\0\xFDr\0\x1Bs\0\x1Ds\0*s\0+s\0.s\0/s\x004s\x005s\0\x84s\0\x85s\0\x87s\0\x88s\0\x89s\0\x8As\0\x8Bs\0\x8Cs\0\x9Bs\0\x9Cs\0\xA9s\0\xAAs\0\xABs\0\xACs\0\xAFs\0\xB1s\0\xB2s\0\xB3s\0\xBBs\0\xBCs\0\xC0s\0\xC1s\0\xCAs\0\xCBs\0\xCDs\0\xCEs\0\xE0s\0\xE1s\0\xEDs\0\xEEs\0\x03t\0\x04t\0\x06t\0\x07t\0\nt\0\x0Bt\0*t\0+t\x003t\x005t\0<t\0=t\0Yt\0Zt\0\\t\0]t\0^t\0`t\0pt\0qt\0vt\0wt\0\x83t\0\x84t\0\xDCt\0\xDDt\0\xE6t\0\xE7t\0\xF6t\0\xF7t\0\x18u\0\x19u\0\x1Au\0\x1Bu\0\x1Cu\0\x1Du\0\x1Fu\0 u\0(u\0)u\x000u\x004u\x005u\x006u\x007u\09u\0;u\0<u\0Eu\0Fu\0Lu\0Mu\0Yu\0Zu\0eu\0fu\0ju\0ku\0\x86u\0\x87u\0\x8Fu\0\x90u\0\x91u\0\x92u\0\x97u\0\x98u\0\xAFu\0\xB0u\0\xB2u\0\xB3u\0\xBCu\0\xBDu\0\xBEu\0\xBFu\0\xC5u\0\xC6u\0\xD5u\0\xD6u\0\xDBu\0\xDCu\0\xF4u\0\xF5u\0xv\0yv\0{v\0|v\0}v\0\x7Fv\0\x84v\0\x85v\0\x86v\0\x88v\0\xAEv\0\xAFv\0\xC8v\0\xC9v\0\xCAv\0\xCBv\0\xD1v\0\xD3v\0\xD6v\0\xD7v\0\xD8v\0\xD9v\0\xDBv\0\xDCv\0\xDFv\0\xE0v\0\xEEv\0\xEFv\0\xF4v\0\xF5v\0\xF8v\0\xF9v\0\xFCv\0\xFDv\0\xFEv\0\xFFv\0\x01w\0\x02w\0\tw\0\nw\0\x0Bw\0\x0Cw\0\x1Fw\0!w\0<w\0=w\0@w\0Aw\0[w\0\\w\0aw\0bw\0cw\0dw\0\xA7w\0\xA8w\0\xDBw\0\xDCw\0\xE3w\0\xE4w\0\xE5w\0\xE6w\0\xEDw\0\xEEw\0\xF3w\0\xF4w\0\xF6w\0\xF7w\0\x01x\0\x03x\0\rx\0\x0Ex\0\x14x\0\x15x\x004x\x005x\0@x\0Ax\0Ux\0Vx\0lx\0mx\0nx\0ox\0\x8Dx\0\x8Fx\0\x97x\0\x98x\0\x9Fx\0\xA0x\0\xA7x\0\xA8x\0\xB0x\0\xB1x\0\xC1x\0\xC2x\0\xC5x\0\xC6x\0\xE8x\0\xE9x\0:y\0;y\0<y\0=y\0>y\0?y\0Vy\0Wy\0Zy\0[y\0]y\0_y\0ey\0fy\0hy\0iy\0oy\0py\0xy\0yy\0\x81y\0\x82y\0\x85y\0\x86y\0\x8Fy\0\x90y\0\xBBy\0\xBCy\0\xC0y\0\xC2y\0\xCBy\0\xCCy\0\xCDy\0\xCEy\0\xD1y\0\xD3y\0\xD8y\0\xD9y\0\xDFy\0\xE0y\0\xE4y\0\xE5y\0\xE6y\0\xE7y\0\xE9y\0\xEAy\0\xEFy\0\xF1y\0\xFBy\0\xFCy\0\0z\0\x01z\0\x0Bz\0\x0Cz\0\rz\0\x0Fz\0#z\0$z\x003z\x004z\0?z\0@z\0Fz\0Gz\0vz\0xz\0yz\0{z\0\x7Fz\0\x80z\0\x81z\0\x82z\0\x97z\0\x98z\0\x9Dz\0\x9Ez\0\xCBz\0\xCCz\0\xD9z\0\xDAz\0\xDEz\0\xE1z\0\xE5z\0\xE6z\0\xEFz\0\xF0z\0\xF9z\0\xFAz\0\x11{\0\x12{\0\x14{\0\x15{\0\x1B{\0\x1C{\0&{\0'{\0({\0){\0,{\0-{\0I{\0J{\0K{\0L{\0Q{\0R{\0T{\0U{\0V{\0W{\0y{\0z{\0~{\0\x7F{\0\x80{\0\x81{\0\x97{\0\x98{\0\xA1{\0\xA2{\0\xAD{\0\xAE{\0\xB1{\0\xB2{\0\xC7{\0\xC8{\0\xEE{\0\xEF{\0?|\0@|\0M|\0N|\0s|\0t|\0{|\0||\0\x89|\0\x8A|\0\x92|\0\x93|\0\x97|\0\x98|\0\xA4|\0\xA5|\0\xB9|\0\xBA|\0\xBE|\0\xBF|\0\xCA|\0\xCB|\0\xD5|\0\xD7|\0\xDF|\0\xE0|\0\xFB|\0\xFC|\0 }\0!}\0\"}\0#}\0'}\0(}\0+}\0,}\0/}\x000}\0A~\0B~\0\xA2~\0\xA3~\0\xA6~\0\xA8~\0\xAA~\0\xAB~\0\xAF~\0\xB0~\0\xB2~\0\xB4~\0\xB5~\0\xB6~\0\xB7~\0\xB9~\0\xBD~\0\xBE~\0\xBF~\0\xC0~\0\xC3~\0\xC5~\0\xC6~\0\xC9~\0\xCD~\0\xCE~\0\xCF~\0\xD0~\0\xD3~\0\xD4~\0\xD5~\0\xD6~\0\xD8~\0\xDA~\0\xDC~\0\xDE~\0\xDF~\0\xE0~\0\xE7~\0\xE8~\0\xE9~\0\xEB~\0\xED~\0\xEE~\0\xF4~\0\xF6~\0\xFC~\0\xFD~\0\xFF~\0\0\x7F\0\x05\x7F\0\x06\x7F\0\x13\x7F\0\x14\x7F\0\x16\x7F\0\x17\x7F\0\x18\x7F\0\x19\x7F\0 \x7F\0!\x7F\0)\x7F\0*\x7F\x004\x7F\x005\x7F\x006\x7F\x007\x7F\08\x7F\09\x7F\0:\x7F\0;\x7F\0P\x7F\0R\x7F\0U\x7F\0V\x7F\0W\x7F\0X\x7F\0Z\x7F\0[\x7F\0b\x7F\0c\x7F\0j\x7F\0k\x7F\0n\x7F\0o\x7F\0r\x7F\0s\x7F\0\x8A\x7F\0\x8B\x7F\0\x8E\x7F\0\x8F\x7F\0\x9E\x7F\0\x9F\x7F\0\xA4\x7F\0\xA5\x7F\0\xAF\x7F\0\xB0\x7F\0\xBD\x7F\0\xBE\x7F\0\xC1\x7F\0\xC2\x7F\0\xC5\x7F\0\xC6\x7F\0\xD4\x7F\0\xD5\x7F\0\xD8\x7F\0\xD9\x7F\0\xE0\x7F\0\xE1\x7F\0\xF0\x7F\0\xF1\x7F\0\xFB\x7F\0\xFD\x7F\0\0\x80\0\x02\x80\0\x03\x80\0\x04\x80\0\x05\x80\0\x06\x80\0\x0C\x80\0\x0E\x80\0\x10\x80\0\x11\x80\0\x17\x80\0\x18\x80\x003\x80\x004\x80\x006\x80\x007\x80\0J\x80\0K\x80\0L\x80\0M\x80\0T\x80\0U\x80\0X\x80\0Y\x80\0Z\x80\0[\x80\0j\x80\0k\x80\0\x89\x80\0\x8A\x80\0\x96\x80\0\x97\x80\0\x9A\x80\0\x9B\x80\0\xA1\x80\0\xA2\x80\0\xA4\x80\0\xA6\x80\0\xA9\x80\0\xAA\x80\0\xAF\x80\0\xB0\x80\0\xB2\x80\0\xB3\x80\0\xC1\x80\0\xC2\x80\0\xC6\x80\0\xC7\x80\0\xCC\x80\0\xCD\x80\0\xCE\x80\0\xCF\x80\0\xD6\x80\0\xD7\x80\0\xDC\x80\0\xDD\x80\0\xDE\x80\0\xDF\x80\0\xE1\x80\0\xE2\x80\0\xF6\x80\0\xF7\x80\0\xF8\x80\0\xF9\x80\0\xFD\x80\0\xFE\x80\0\x06\x81\0\x07\x81\0\x11\x81\0\x12\x81\x001\x81\x002\x81\08\x81\09\x81\0J\x81\0K\x81\0P\x81\0Q\x81\0S\x81\0T\x81\0p\x81\0q\x81\0y\x81\0z\x81\0~\x81\0\x80\x81\0\xC2\x81\0\xC3\x81\0\xE3\x81\0\xE4\x81\0\xEA\x81\0\xEB\x81\0\xED\x81\0\xEE\x81\0\xF3\x81\0\xF5\x81\0\x0C\x82\0\x0E\x82\0\x12\x82\0\x13\x82\0\x1E\x82\0 \x82\0*\x82\0+\x82\0,\x82\0-\x82\x000\x82\x001\x82\09\x82\0:\x82\0o\x82\0p\x82\0r\x82\0s\x82\0z\x82\0{\x82\0~\x82\0\x7F\x82\0\x82\x82\0\x83\x82\0\x92\x82\0\x93\x82\0\x9D\x82\0\x9E\x82\0\xA6\x82\0\xA7\x82\0\xAC\x82\0\xAE\x82\0\xB1\x82\0\xB2\x82\0\xB3\x82\0\xB4\x82\0\xCD\x82\0\xCE\x82\0\xCF\x82\0\xD0\x82\0\xD7\x82\0\xD8\x82\0\xE5\x82\0\xE7\x82\0\xF1\x82\0\xF2\x82\0\x02\x83\0\x04\x83\0(\x83\0)\x83\0+\x83\0,\x83\x006\x83\x007\x83\0I\x83\0J\x83\0P\x83\0Q\x83\0R\x83\0S\x83\0c\x83\0d\x83\0o\x83\0p\x83\0w\x83\0x\x83\0\x89\x83\0\x8A\x83\0\x8E\x83\0\x8F\x83\0\xAA\x83\0\xAC\x83\0\xB1\x83\0\xB3\x83\0\xB7\x83\0\xB8\x83\0\xDC\x83\0\xDD\x83\0\xE9\x83\0\xEA\x83\0\xF2\x83\0\xF3\x83\0\x04\x84\0\x05\x84\0\r\x84\0\x0E\x84\0$\x84\0&\x84\0'\x84\0)\x84\0=\x84\0>\x84\0W\x84\0X\x84\0[\x84\0\\\x84\0a\x84\0b\x84\0\x82\x84\0\x83\x84\0\x8B\x84\0\x8C\x84\0\x99\x84\0\x9A\x84\0\xC9\x84\0\xCA\x84\0\xDD\x84\0\xDE\x84\0\xEC\x84\0\xED\x84\0\x11\x85\0\x12\x85\0!\x85\0\"\x85\0\x84\x85\0\x85\x85\0\xAA\x85\0\xAB\x85\0\xC9\x85\0\xCA\x85\0\xCF\x85\0\xD0\x85\0\xE4\x85\0\xE5\x85\0N\x86\0O\x86\0Q\x86\0R\x86\0k\x86\0l\x86\0y\x86\0z\x86\0}\x86\0\x7F\x86\0\x81\x86\0\x82\x86\0\xC7\x86\0\xC8\x86\0\xCB\x86\0\xCC\x86\0\xD9\x86\0\xDA\x86\0\xEE\x86\0\xEF\x86\0\x02\x87\0\x03\x87\0\x1C\x87\0\x1D\x87\0v\x87\0w\x87\0\x8D\x87\0\x8E\x87\0\xF9\x87\0\xFA\x87\0\"\x88\0#\x88\0@\x88\0A\x88\0L\x88\0M\x88\0W\x88\0X\x88\0a\x88\0b\x88\0c\x88\0d\x88\0e\x88\0f\x88\0h\x88\0i\x88\0\x8B\x88\0\x8C\x88\0\xAB\x88\0\xAC\x88\0\xAD\x88\0\xAE\x88\0\xC1\x88\0\xC3\x88\0\xC5\x88\0\xC6\x88\0\xD5\x88\0\xD6\x88\0\xE4\x88\0\xE5\x88\0\x7F\x89\0\x80\x89\0\x81\x89\0\x82\x89\0\x86\x89\0\x87\x89\0\xC1\x89\0\xC3\x89\0\xC4\x89\0\xC5\x89\0\xC6\x89\0\xC7\x89\0\xC8\x89\0\xCA\x89\0\xD2\x89\0\xD3\x89\0\xE3\x89\0\xE4\x89\0\0\x8A\0\x01\x8A\0\x89\x8A\0\x8A\x8A\0\x93\x8A\0\x94\x8A\0f\x8B\0g\x8B\0\xA1\x8B\0\xA3\x8B\0\xA4\x8B\0\xA5\x8B\0\xA8\x8B\0\xAA\x8B\0\xAD\x8B\0\xB1\x8B\0\xB2\x8B\0\xB3\x8B\0\xB7\x8B\0\xB9\x8B\0\xBA\x8B\0\xBB\x8B\0\xBE\x8B\0\xC0\x8B\0\xC1\x8B\0\xC2\x8B\0\xC4\x8B\0\xC5\x8B\0\xC6\x8B\0\xC7\x8B\0\xC9\x8B\0\xCA\x8B\0\xCD\x8B\0\xCE\x8B\0\xD1\x8B\0\xD2\x8B\0\xD5\x8B\0\xD6\x8B\0\xD7\x8B\0\xD8\x8B\0\xDA\x8B\0\xDB\x8B\0\xDD\x8B\0\xDF\x8B\0\xE2\x8B\0\xE3\x8B\0\xE5\x8B\0\xE7\x8B\0\xED\x8B\0\xEE\x8B\0\xEF\x8B\0\xF0\x8B\0\xF4\x8B\0\xF5\x8B\0\xF7\x8B\0\xF9\x8B\0\xFA\x8B\0\xFC\x8B\0\xFE\x8B\0\xFF\x8B\0\x01\x8C\0\x02\x8C\0\x03\x8C\0\x04\x8C\0\x05\x8C\0\x06\x8C\0\x08\x8C\0\t\x8C\0\n\x8C\0\x0C\x8C\0\x13\x8C\0\x14\x8C\0\x1C\x8C\0\x1D\x8C\0\"\x8C\0#\x8C\0(\x8C\0)\x8C\x001\x8C\x002\x8C\x007\x8C\08\x8C\0F\x8C\0G\x8C\0a\x8C\0b\x8C\0j\x8C\0k\x8C\0\x8C\x8C\0\x8D\x8C\0\x1D\x8D\0 \x8D\0!\x8D\0&\x8D\0'\x8D\0+\x8D\0-\x8D\0.\x8D\0/\x8D\x000\x8D\x001\x8D\x002\x8D\x004\x8D\x006\x8D\08\x8D\0;\x8D\0<\x8D\0=\x8D\0>\x8D\0?\x8D\0D\x8D\0E\x8D\0K\x8D\0M\x8D\0O\x8D\0Q\x8D\0T\x8D\0U\x8D\0V\x8D\0W\x8D\0Z\x8D\0\\\x8D\0^\x8D\0_\x8D\0`\x8D\0a\x8D\0b\x8D\0c\x8D\0d\x8D\0e\x8D\0k\x8D\0l\x8D\0p\x8D\0q\x8D\0u\x8D\0v\x8D\0w\x8D\0x\x8D\0\x81\x8D\0\x82\x8D\0\x85\x8D\0\x86\x8D\0\x8A\x8D\0\x8C\x8D\0\xA3\x8D\0\xA4\x8D\0\xB3\x8D\0\xB4\x8D\0\xC3\x8D\0\xC4\x8D\0\xCC\x8D\0\xCD\x8D\0\xD1\x8D\0\xD2\x8D\0\xDD\x8D\0\xDE\x8D\0\xDF\x8D\0\xE0\x8D\0\xEF\x8D\0\xF0\x8D\0\xF3\x8D\0\xF4\x8D\0\x0F\x8E\0\x10\x8E\0\"\x8E\0#\x8E\0)\x8E\0*\x8E\0\xAB\x8E\0\xAC\x8E\0\xB2\x8E\0\xB3\x8E\0f\x8F\0g\x8F\0h\x8F\0j\x8F\0l\x8F\0m\x8F\0n\x8F\0q\x8F\0{\x8F\0|\x8F\0}\x8F\0~\x8F\0\x83\x8F\0\x84\x8F\0\x85\x8F\0\x87\x8F\0\x88\x8F\0\x8A\x8F\0\x91\x8F\0\x92\x8F\0\x93\x8F\0\x94\x8F\0\x9B\x8F\0\x9C\x8F\0\x9E\x8F\0\x9F\x8F\0\xA8\x8F\0\xAA\x8F\0\xB0\x8F\0\xB2\x8F\0\xB9\x8F\0\xBA\x8F\0\xBE\x8F\0\xBF\x8F\0\xC1\x8F\0\xC2\x8F\0\xC5\x8F\0\xC6\x8F\0\xC7\x8F\0\xC9\x8F\0\xCE\x8F\0\xCF\x8F\0\xD0\x8F\0\xD2\x8F\0\xD4\x8F\0\xD5\x8F\0\xD8\x8F\0\xDA\x8F\0\xDB\x8F\0\xE0\x8F\0\xE6\x8F\0\xE7\x8F\0\xEA\x8F\0\xEC\x8F\0\xF0\x8F\0\xF1\x8F\0\xF7\x8F\0\xF8\x8F\0\xFD\x8F\0\xFE\x8F\0\0\x90\0\x04\x90\0\x06\x90\0\x07\x90\0\t\x90\0\x0B\x90\0\x0F\x90\0\x11\x90\0\x12\x90\0\x13\x90\0\x14\x90\0\x15\x90\0\x1A\x90\0\x1C\x90\0\x1D\x90\0\x1E\x90\0\x1F\x90\0!\x90\0\"\x90\0#\x90\08\x90\09\x90\0;\x90\0=\x90\0G\x90\0H\x90\0M\x90\0N\x90\0S\x90\0T\x90\0W\x90\0X\x90\0m\x90\0o\x90\0u\x90\0v\x90\0\x7F\x90\0\x81\x90\0\x93\x90\0\x94\x90\0\xA3\x90\0\xA4\x90\0\xA6\x90\0\xA7\x90\0\xAA\x90\0\xAB\x90\0\xAE\x90\0\xAF\x90\0\xB1\x90\0\xB2\x90\0\xBB\x90\0\xBC\x90\0\xCE\x90\0\xCF\x90\0\xD1\x90\0\xD2\x90\0\xE8\x90\0\xE9\x90\0\xED\x90\0\xEE\x90\0\xFD\x90\0\xFE\x90\0\x02\x91\0\x03\x91\0I\x91\0J\x91\0K\x91\0L\x91\0M\x91\0N\x91\0R\x91\0S\x91\0w\x91\0y\x91\0\x89\x91\0\x8A\x91\0\x92\x91\0\x93\x91\0\xC7\x91\0\xC8\x91\0\xCA\x91\0\xCB\x91\0\xCC\x91\0\xD0\x91\0\xD1\x91\0\xD2\x91\0\x88\x94\0\x89\x94\0\x93\x94\0\x94\x94\0\x9F\x94\0\xA0\x94\0\xA2\x94\0\xA3\x94\0\xA6\x94\0\xA7\x94\0\xB1\x94\0\xB2\x94\0\xBB\x94\0\xBC\x94\0\xC1\x94\0\xC2\x94\0\xC3\x94\0\xC4\x94\0\xDC\x94\0\xDD\x94\0\xE2\x94\0\xE3\x94\0\xED\x94\0\xEE\x94\0\xF6\x94\0\xF7\x94\0\xFA\x94\0\xFB\x94\0\xFE\x94\0\xFF\x94\0\0\x95\0\x02\x95\0\x05\x95\0\x06\x95\0\x0B\x95\0\x0C\x95\0\x19\x95\0\x1A\x95\0!\x95\0\"\x95\0&\x95\0'\x95\0.\x95\0/\x95\0:\x95\0;\x95\0G\x95\0H\x95\0\\\x95\0]\x95\0m\x95\0n\x95\0\x7F\x95\0\x80\x95\0\xE8\x95\0\xE9\x95\0\xEA\x95\0\xEB\x95\0\xED\x95\0\xEF\x95\0\xF0\x95\0\xF1\x95\0\xF2\x95\0\xF3\x95\0\xF4\x95\0\xF5\x95\0\xF7\x95\0\xF8\x95\0\xF9\x95\0\xFA\x95\0\xFB\x95\0\xFC\x95\0\x01\x96\0\x02\x96\0\x05\x96\0\x06\x96\0\x10\x96\0\x11\x96\0\x14\x96\0\x15\x96\0\x1F\x96\0 \x96\0.\x96\0/\x96\x002\x96\x007\x96\0;\x96\0<\x96\0?\x96\0A\x96\0D\x96\0G\x96\0H\x96\0I\x96\0M\x96\0N\x96\0P\x96\0Q\x96\0b\x96\0c\x96\0d\x96\0e\x96\0i\x96\0k\x96\0u\x96\0x\x96\0\x86\x96\0\x87\x96\0\x8F\x96\0\x91\x96\0\x94\x96\0\x95\x96\0\x9C\x96\0\x9D\x96\0\xBE\x96\0\xBF\x96\0\xC4\x96\0\xC7\x96\0\xC9\x96\0\xCA\x96\0\xE8\x96\0\xE9\x96\0\xEA\x96\0\xEB\x96\0\xEF\x96\0\xF0\x96\0\xF3\x96\0\xF4\x96\0\xF6\x96\0\xF8\x96\0\xFE\x96\0\xFF\x96\0\0\x97\0\x01\x97\0\x07\x97\0\x08\x97\0\r\x97\0\x0E\x97\0\x16\x97\0\x17\x97\x002\x97\x003\x97\08\x97\0:\x97\0R\x97\0S\x97\0V\x97\0W\x97\0Y\x97\0Z\x97\0^\x97\0_\x97\0`\x97\0a\x97\0b\x97\0c\x97\0i\x97\0j\x97\0|\x97\0}\x97\0\x8B\x97\0\x8C\x97\0\x91\x97\0\x92\x97\0\xE6\x97\0\xE7\x97\0\xE9\x97\0\xEA\x97\0\xF3\x97\0\xF4\x97\0u\x98\0w\x98\0y\x98\0|\x98\0}\x98\0\x80\x98\0\x84\x98\0\x85\x98\0\x86\x98\0\x88\x98\0\x91\x98\0\x92\x98\0\x97\x98\0\x99\x98\0\x9D\x98\0\x9E\x98\0\xCE\x98\0\xCF\x98\0\xD8\x98\0\xDA\x98\0\xDE\x98\0\xE0\x98\0\x10\x99\0\x11\x99\0m\x99\0o\x99\0p\x99\0r\x99\0|\x99\0}\x99\0\x86\x99\0\x87\x99\0\x96\x99\0\x97\x99\0\x99\x99\0\x9A\x99\0\xA8\x99\0\xA9\x99\0l\x9A\0m\x9A\0q\x9A\0r\x9A\0v\x9A\0w\x9A\0{\x9A\0|\x9A\0~\x9A\0\x7F\x9A\0\x8C\x9A\0\x8D\x9A\0\x91\x9A\0\x92\x9A\0\x97\x9A\0\x98\x9A\0\x9A\x9A\0\x9B\x9A\0\xA4\x9A\0\xA5\x9A\0\xA8\x9A\0\xA9\x9A\0\xD8\x9A\0\xD9\x9A\0<\x9B\0=\x9B\0B\x9B\0C\x9B\0E\x9B\0F\x9B\0T\x9B\0U\x9B\0|\x9C\0}\x9C\0\x81\x9C\0\x82\x9C\0\x9C\x9C\0\x9D\x9C\0\x1F\x9E\0 \x9E\0!\x9E\0\"\x9E\0#\x9E\0$\x9E\0-\x9E\0.\x9E\0?\x9E\0@\x9E\0E\x9E\0F\x9E\0d\x9E\0e\x9E\0p\x9E\0q\x9E\0\x7F\x9E\0\x80\x9E\0\xA6\x9E\0\xA7\x9E\0\xBB\x9E\0\xBC\x9E\0\xC4\x9E\0\xC5\x9E\0\xCE\x9E\0\xCF\x9E\0\xD1\x9E\0\xD2\x9E\0\xD8\x9E\0\xD9\x9E\0\x13\x9F\0\x14\x9F\0 \x9F\0!\x9F\0;\x9F\0<\x9F\0P\x9F\0Q\x9F\0\x7F\x9F\0\x80\x9F\0\x84\x9F\0\x85\x9F\0\x99\x9F\0\x9A\x9F\0\x9F\x9F\0\xA0\x9F\0") }, 2210u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\0N\0\x02N\0\x03N\0\x04N\0\x08N\0\x0EN\0\x11N\0\x12N\0\x14N\0\x15N\0\x16N\0\x17N\0\x18N\0\x1AN\0\x1FN\0 N\0&N\0'N\0-N\0.N\x002N\x003N\08N\0:N\0;N\0<N\0CN\0DN\0EN\0FN\0HN\0IN\0KN\0LN\0NN\0PN\0VN\0WN\0XN\0ZN\0]N\0^N\0_N\0`N\0~N\0\x7FN\0\x82N\0\x83N\0\x86N\0\x87N\0\x88N\0\x89N\0\x8BN\0\x8DN\0\x8EN\0\x8FN\0\x91N\0\x93N\0\x94N\0\x96N\0\x9BN\0\x9CN\0\x9EN\0\x9FN\0\xA1N\0\xA2N\0\xA4N\0\xA7N\0\xA8N\0\xA9N\0\xABN\0\xADN\0\xAEN\0\xAFN\0\xBAN\0\xBBN\0\xC0N\0\xC2N\0\xC7N\0\xC8N\0\xCAN\0\xCCN\0\xCDN\0\xCEN\0\xD4N\0\xD5N\0\xD6N\0\xD7N\0\xD8N\0\xDAN\0\xE3N\0\xE6N\0\xF0N\0\xF1N\0\xF2N\0\xF3N\0\xF6N\0\xF7N\0\xFBN\0\xFCN\0\xFDN\0\xFEN\0\x01O\0\x02O\0\nO\0\x0BO\0\rO\0\x0EO\0\x10O\0\x12O\0\x19O\0\x1AO\0/O\x001O\x004O\x005O\08O\09O\0<O\0>O\0FO\0GO\0HO\0JO\0MO\0PO\0TO\0VO\0YO\0ZO\0[O\0]O\0`O\0aO\0iO\0jO\0sO\0tO\0\x7FO\0\x80O\0\x86O\0\x87O\0\x8BO\0\x8CO\0\x9BO\0\x9CO\0\x9DO\0\x9EO\0\xAFO\0\xB0O\0\xB5O\0\xB6O\0\xBFO\0\xC0O\0\xC2O\0\xC5O\0\xCAO\0\xCBO\0\xD7O\0\xD8O\0\xDDO\0\xDEO\0\xE0O\0\xE2O\0\xEEO\0\xEFO\0\xF1O\0\xF2O\0\xFEO\0\xFFO\0\x0BP\0\x0CP\0\rP\0\x0EP\0\x11P\0\x13P\0\x19P\0\x1BP\0\x1FP\0 P\0+P\0,P\0<P\0=P\0GP\0HP\0IP\0JP\0OP\0PP\0ZP\0[P\0\\P\0]P\0eP\0fP\0tP\0xP\0\x91P\0\x92P\0\x99P\0\x9AP\0\xA2P\0\xA4P\0\xB2P\0\xB4P\0\xB7P\0\xB8P\0\xBBP\0\xBCP\0\xBEP\0\xBFP\0\xC5P\0\xC6P\0\xCFP\0\xD0P\0\xD1P\0\xD2P\0\xE7P\0\xE8P\0\xF9P\0\xFAP\0\0Q\0\x01Q\0\x04Q\0\x05Q\0\x12Q\0\x13Q\0\x18Q\0\x19Q\0*Q\0+Q\0AQ\0BQ\0CQ\0FQ\0GQ\0JQ\0KQ\0LQ\0MQ\0NQ\0RQ\0SQ\0TQ\0UQ\0eQ\0fQ\0gQ\0jQ\0kQ\0oQ\0qQ\0rQ\0uQ\0yQ\0|Q\0}Q\0\x8AQ\0\x8BQ\0\x8DQ\0\x8EQ\0\x92Q\0\x93Q\0\xA0Q\0\xA1Q\0\xACQ\0\xADQ\0\xB0Q\0\xB1Q\0\xB7Q\0\xB8Q\0\xC6Q\0\xC7Q\0\xCCQ\0\xCDQ\0\xDDQ\0\xDEQ\0\xE1Q\0\xE2Q\0\xF0Q\0\xF2Q\0\xFAQ\0\xFBQ\0\xFDQ\0\xFEQ\0\0R\0\x01R\0\x06R\0\x08R\0\nR\0\x0BR\0\x17R\0\x18R\0\x1DR\0\x1ER\0$R\0&R\0)R\0+R\x000R\x001R\x006R\08R\0:R\0<R\0GR\0HR\0LR\0NR\0[R\0\\R\0iR\0kR\0oR\0pR\0rR\0sR\0uR\0vR\0\x83R\0\x84R\0\x87R\0\x88R\0\x89R\0\x8AR\0\x8DR\0\x8ER\0\x9BR\0\x9CR\0\x9FR\0\xA1R\0\xA9R\0\xACR\0\xC1R\0\xC2R\0\xC7R\0\xC8R\0\xC9R\0\xCAR\0\xD2R\0\xD3R\0\xD5R\0\xD6R\0\xD9R\0\xDAR\0\xDDR\0\xDFR\0\xE2R\0\xE3R\0\xE4R\0\xE5R\0\xF5R\0\xF6R\0\xF8R\0\xF9R\0\xFFR\0\0S\0\x05S\0\x06S\0\x08S\0\tS\0\x16S\0\x18S\09S\0:S\0@S\0BS\0CS\0DS\0GS\0IS\0JS\0KS\0RS\0US\0WS\0XS\0ZS\0[S\0\\S\0]S\0aS\0bS\0oS\0rS\0sS\0tS\0wS\0xS\0{S\0|S\0\x84S\0\x85S\0\x98S\0\x99S\0\x9AS\0\x9BS\0\x9FS\0\xA0S\0\xADS\0\xAES\0\xB2S\0\xB3S\0\xBBS\0\xBCS\0\xC3S\0\xC4S\0\xC8S\0\xC9S\0\xCAS\0\xCCS\0\xCDS\0\xCES\0\xD4S\0\xD5S\0\xD6S\0\xD8S\0\xE3S\0\xE7S\0\xEAS\0\xEES\0\xEFS\0\xF1S\0\xF2S\0\xF4S\0\xF8S\0\xF9S\0\x03T\0\x05T\0\x08T\0\x0BT\0\x0CT\0\x0FT\0\x10T\0\x13T\0\x1BT\0\x1CT\0\x1DT\0!T\0&T\0(T\0+T\0,T\x003T\x004T\x005T\x006T\08T\0:T\0>T\0?T\0@T\0AT\0BT\0CT\0FT\0GT\0JT\0KT\0bT\0cT\0hT\0iT\0sT\0tT\0uT\0vT\0|T\0~T\0\x8CT\0\x8DT\0\x96T\0\x97T\0\xA6T\0\xA8T\0\xAAT\0\xABT\0\xACT\0\xADT\0\xB1T\0\xB2T\0\xC0T\0\xC2T\0\xC7T\0\xCAT\0\xCET\0\xCFT\0\xE1T\0\xE2T\0\xE5T\0\xE7T\0\xE9T\0\xEBT\0\xEDT\0\xEET\0\xF2T\0\xF3T\0\tU\0\nU\0\x10U\0\x11U\0\x14U\0\x15U\0,U\0-U\0.U\x000U\x001U\x002U\x007U\09U\0FU\0GU\0JU\0KU\0OU\0PU\0_U\0`U\0aU\0bU\0eU\0gU\0jU\0kU\0\x80U\0\x81U\0\x82U\0\x83U\0\x84U\0\x85U\0\x87U\0\x88U\0\x8AU\0\x8BU\0\x94U\0\x95U\0\x9CU\0\x9EU\0\xACU\0\xADU\0\xAEU\0\xAFU\0\xB5U\0\xB6U\0\xCEU\0\xCFU\0\xDAU\0\xDBU\0\xE8U\0\xE9U\0\xEFU\0\xF0U\0\x06V\0\x07V\0\tV\0\nV\0\x17V\0\x18V\0\x1BV\0\x1CV\x004V\x005V\0;V\0<V\0?V\0@V\0hV\0iV\0tV\0uV\0\x87V\0\x88V\0\xB4V\0\xB5V\0\xC9V\0\xCAV\0\xDBV\0\xDCV\0\xDEV\0\xDFV\0\xE0V\0\xE1V\0\xF0V\0\xF1V\0\xFAV\0\xFBV\0\x08W\0\tW\0\x0BW\0\x0CW\0\rW\0\x0EW\0\x12W\0\x14W\0\x16W\0\x17W\0\x18W\0\x19W\0\x1CW\0\x1DW\0\x1FW\0 W\0(W\0)W\0-W\0.W\x000W\x001W\0>W\0?W\0@W\0AW\0GW\0HW\0NW\0OW\0PW\0QW\0aW\0bW\0dW\0eW\0fW\0gW\0jW\0kW\0\x82W\0\x84W\0\x8BW\0\x8CW\0\xC3W\0\xC4W\0\xCEW\0\xCFW\0\xD4W\0\xD5W\0\xDFW\0\xE0W\0\xF7W\0\xF8W\0\xF9W\0\xFBW\0\x02X\0\x03X\0\x05X\0\x07X\0!X\0\"X\0*X\0+X\x001X\x002X\x004X\x005X\0JX\0KX\0TX\0UX\0WX\0XX\0^X\0_X\0kX\0lX\0uX\0vX\0\x83X\0\x84X\0\x9EX\0\x9FX\0\xA8X\0\xA9X\0\xAEX\0\xAFX\0\xC1X\0\xC2X\0\xC7X\0\xC8X\0\xD3X\0\xD4X\0\xD8X\0\xD9X\0\xDEX\0\xDFX\0\xE2X\0\xE3X\0\xEBX\0\xEDX\0\xEFX\0\xF0X\0\xFDX\0\xFEX\0\x0FY\0\x10Y\0\x15Y\0\x17Y\0\x1AY\0\x1BY\0\x1CY\0\x1DY\0 Y\0!Y\0\"Y\0#Y\0%Y\0&Y\0'Y\0(Y\0)Y\0,Y\0.Y\0/Y\x001Y\x002Y\x007Y\09Y\0>Y\0?Y\0GY\0JY\0NY\0PY\0QY\0RY\0TY\0UY\0WY\0XY\0gY\0hY\0jY\0kY\0nY\0oY\0sY\0uY\0vY\0wY\0yY\0zY\0}Y\0~Y\0\x82Y\0\x83Y\0\x99Y\0\x9AY\0\x9DY\0\x9EY\0\xA5Y\0\xA6Y\0\xA8Y\0\xA9Y\0\xAEY\0\xAFY\0\xB3Y\0\xB4Y\0\xB9Y\0\xBAY\0\xBBY\0\xBCY\0\xC6Y\0\xC7Y\0\xCAY\0\xCCY\0\xD0Y\0\xD2Y\0\xD3Y\0\xD5Y\0\xFFY\0\0Z\0\x01Z\0\x02Z\0\x03Z\0\x04Z\0\x18Z\0\x19Z\0\x1BZ\0\x1CZ\0AZ\0BZ\0FZ\0GZ\0ZZ\0[Z\0fZ\0gZ\0\x92Z\0\x93Z\0\xBDZ\0\xBEZ\0\xCCZ\0\xCDZ\0\xE9Z\0\xEAZ\0P[\0Q[\0T[\0U[\0W[\0Y[\0][\0^[\0_[\0`[\0c[\0e[\0i[\0j[\0k[\0l[\0x[\0y[\0\x83[\0\x84[\0\x85[\0\x86[\0\x87[\0\x8A[\0\x8B[\0\x8D[\0\x8F[\0\x90[\0\x97[\0\x9D[\0\xA2[\0\xA5[\0\xAE[\0\xAF[\0\xB3[\0\xB4[\0\xB6[\0\xB7[\0\xB9[\0\xBA[\0\xBF[\0\xC0[\0\xC2[\0\xC3[\0\xC4[\0\xC7[\0\xCC[\0\xCD[\0\xD2[\0\xD3[\0\xDE[\0\xE0[\0\xE2[\0\xE3[\0\xE6[\0\xEA[\0\xEB[\0\xED[\0\xEE[\0\xEF[\0\xF5[\0\xF7[\0\x01\\\0\x02\\\0\x04\\\0\x05\\\0\x07\\\0\t\\\0\n\\\0\x0C\\\0\r\\\0\x10\\\0\x11\\\0\x12\\\0\x16\\\0\x17\\\0\x1A\\\0\x1B\\\0$\\\0%\\\x001\\\x002\\\0:\\\0;\\\0<\\\0=\\\0>\\\0?\\\0@\\\0B\\\0E\\\0G\\\0K\\\0L\\\0O\\\0P\\\0U\\\0V\\\0`\\\0a\\\0d\\\0e\\\0l\\\0m\\\0q\\\0r\\\0\xA1\\\0\xA2\\\0\xA9\\\0\xAA\\\0\xB8\\\0\xB9\\\0\xF0\\\0\xF1\\\0\xF6\\\0\xF7\\\0\xFD\\\0\xFE\\\0\x07]\0\x08]\0\x19]\0\x1A]\x004]\x005]\0P]\0Q]\0\xBA]\0\xBB]\0\xDD]\0\xDF]\0\xE1]\0\xE2]\0\xE5]\0\xE9]\0\xEB]\0\xEC]\0\xEE]\0\xEF]\0\xF1]\0\xF5]\0\xF7]\0\xF8]\0\x02^\0\x04^\0\x0C^\0\r^\0\x15^\0\x17^\0\x1B^\0\x1C^\0\x1D^\0\x1E^\0%^\0&^\0+^\0,^\0-^\0.^\x003^\x004^\x006^\x007^\08^\09^\0=^\0>^\0E^\0F^\0U^\0V^\0c^\0d^\0k^\0l^\0r^\0u^\0x^\0z^\0{^\0\x7F^\0\x87^\0\x88^\0\x8A^\0\x8B^\0\x8F^\0\x90^\0\x95^\0\x96^\0\x97^\0\x98^\0\x9A^\0\x9B^\0\x9C^\0\x9D^\0\xA6^\0\xA8^\0\xAB^\0\xAC^\0\xAD^\0\xAE^\0\xB7^\0\xB9^\0\xC9^\0\xCA^\0\xD6^\0\xD7^\0\xE0^\0\xE1^\0\xE2^\0\xE4^\0\xF3^\0\xF4^\0\xF6^\0\xF8^\0\xFA^\0\xFB^\0\x04_\0\x05_\0\x0F_\0\x10_\0\x15_\0\x16_\0\x17_\0\x19_\0\x1F_\0 _\0&_\0'_\x001_\x002_\x005_\x006_\x007_\08_\0H_\0I_\0J_\0K_\0L_\0M_\0N_\0O_\0]_\0__\0b_\0c_\0e_\0f_\0i_\0j_\0l_\0n_\0p_\0r_\0y_\0z_\0|_\0}_\0\x80_\0\x82_\0\x85_\0\x86_\0\x88_\0\x89_\0\x8B_\0\x8D_\0\x90_\0\x93_\0\x97_\0\x98_\0\x9E_\0\x9F_\0\xA9_\0\xAA_\0\xAE_\0\xAF_\0\xB5_\0\xB6_\0\xB7_\0\xB8_\0\xB9_\0\xBA_\0\xC3_\0\xC4_\0\xC5_\0\xC6_\0\xCC_\0\xCE_\0\xD7_\0\xDA_\0\xE0_\0\xE1_\0\xEB_\0\xEC_\0\xF5_\0\xF6_\0\xFD_\0\xFE_\0\x0E`\0\x0F`\0\x12`\0\x13`\0\x15`\0\x17`\0\x1D`\0\x1E`\0!`\0\"`\0%`\0&`\0'`\0)`\0*`\0+`\0F`\0G`\0P`\0Q`\0b`\0c`\0e`\0f`\0h`\0j`\0m`\0n`\0o`\0q`\0\x85`\0\x86`\0\x89`\0\x8A`\0\x94`\0\x95`\0\x9F`\0\xA1`\0\xA8`\0\xA9`\0\xB2`\0\xB3`\0\xB6`\0\xB7`\0\xC5`\0\xC6`\0\xD1`\0\xD2`\0\xDC`\0\xDD`\0\xE0`\0\xE2`\0\xF1`\0\xF2`\0\xF3`\0\xF4`\0\xF9`\0\xFA`\0\x01a\0\x02a\0\x08a\0\na\0\x0Fa\0\x10a\0\x1Aa\0\x1Ca\0\x1Fa\0 a\0Ha\0Ia\0Ka\0La\0Ua\0Va\0Xa\0Ya\0ba\0da\0ga\0ha\0na\0oa\0pa\0qa\0va\0wa\0~a\0\x7Fa\0\x82a\0\x83a\0\x90a\0\x92a\0\xB2a\0\xB3a\0\xB6a\0\xB7a\0\xBEa\0\xBFa\0\xC2a\0\xC3a\0\xC9a\0\xCAa\0\xF6a\0\xF8a\0\xFCa\0\xFDa\0\0b\0\x01b\0\x08b\0\tb\0\nb\0\x0Bb\0\x0Cb\0\rb\0\x10b\0\x13b\0\x16b\0\x17b\0*b\0+b\x000b\x001b\x002b\x003b\x004b\x005b\x006b\x007b\0?b\0Bb\0Gb\0Hb\0Kb\0Lb\0Mb\0Ob\0Sb\0Tb\0Xb\0Yb\0cb\0db\0eb\0fb\0mb\0nb\0ob\0pb\0yb\0zb\0~b\0\x81b\0\x84b\0\x85b\0\x8Ab\0\x8Bb\0\x93b\0\x94b\0\x95b\0\x96b\0\x97b\0\x99b\0\xABb\0\xADb\0\xB1b\0\xB2b\0\xB5b\0\xB6b\0\xB9b\0\xBAb\0\xBDb\0\xBEb\0\xC6b\0\xC7b\0\xC9b\0\xCAb\0\xCBb\0\xCCb\0\xCDb\0\xCEb\0\xCFb\0\xD0b\0\xD2b\0\xD3b\0\xD4b\0\xD5b\0\xD6b\0\xD7b\0\xDBb\0\xDDb\0\xECb\0\xEDb\0\xF3b\0\xF4b\0\xFCb\0\xFDb\0\xFEb\0\0c\0\x01c\0\x02c\0\x07c\0\x08c\0\tc\0\nc\0\x11c\0\x12c\0\x16c\0\x17c\0*c\0+c\0/c\x000c\0:c\0;c\0Pc\0Qc\0Uc\0Vc\0hc\0ic\0rc\0sc\0wc\0xc\0\x83c\0\x84c\0\x88c\0\x8Ac\0\x8Cc\0\x8Dc\0\x92c\0\x93c\0\x9Bc\0\x9Cc\0\xA1c\0\xA3c\0\xA5c\0\xA6c\0\xA7c\0\xA9c\0\xAAc\0\xABc\0\xCFc\0\xD1c\0\xD2c\0\xD3c\0\xDAc\0\xDCc\0\xE1c\0\xE2c\0\xEEc\0\xEFc\0\xF4c\0\xF5c\0\rd\0\x0Ed\0\x16d\0\x17d\0\x1Cd\0\x1Dd\0\x1Ed\0\x1Fd\0,d\0.d\x006d\x007d\0Xd\0Yd\0id\0jd\0xd\0yd\0\x90d\0\x91d\0\x92d\0\x93d\0\x9Ed\0\x9Fd\0\xA3d\0\xA4d\0\xA5d\0\xA6d\0\xADd\0\xAEd\0\xBEd\0\xC0d\0\xC1d\0\xC2d\0\xC7d\0\xC8d\0\xCAd\0\xCCd\0\xCDd\0\xCFd\0\xD4d\0\xD5d\0\xDAd\0\xDBd\0\xE0d\0\xE1d\0\xE6d\0\xE7d\0\xECd\0\xEDd\0\xF4d\0\xF5d\0\xFAd\0\xFBd\0\xFEd\0\xFFd\0\x1De\0\x1Ee\0/e\x000e\x006e\x007e\09e\0:e\0;e\0<e\0>e\0@e\0Ee\0Fe\0He\0Ie\0Me\0Ne\0Oe\0Pe\0Qe\0Re\0We\0Ze\0]e\0^e\0be\0de\0fe\0ge\0le\0me\0te\0ve\0xe\0ye\0\x87e\0\x88e\0\x90e\0\x91e\0\x97e\0\x98e\0\x99e\0\x9Ae\0\xAFe\0\xB1e\0\xB7e\0\xB8e\0\xB9e\0\xBAe\0\xBCe\0\xBEe\0\xC1e\0\xC2e\0\xC5e\0\xC6e\0\xCBe\0\xCCe\0\xCFe\0\xD0e\0\xD7e\0\xD8e\0\xE2e\0\xE3e\0\xE5e\0\xE7e\0\xE9e\0\xEAe\0\xEDe\0\xEEe\0\xFAe\0\xFBe\0\x02f\0\x03f\0\x06f\0\x08f\0\x0Cf\0\rf\0\x0Ef\0\x10f\0\x13f\0\x14f\0\x1Ff\0!f\0%f\0&f\0(f\0)f\0-f\0.f\0/f\x000f\0Bf\0Cf\0If\0Jf\0Rf\0Sf\0Zf\0[f\0hf\0if\0nf\0pf\0tf\0uf\0vf\0wf\0zf\0{f\0\x91f\0\x92f\0\x96f\0\x98f\0\xABf\0\xACf\0\xB4f\0\xB5f\0\xC6f\0\xC7f\0\xC9f\0\xCAf\0\xF0f\0\xF1f\0\xF2f\0\xF3f\0\xF4f\0\xF5f\0\xF8f\0\xF9f\0\xFCf\0\xFDf\0\xFEf\0\x01g\0\x03g\0\x04g\0\x08g\0\ng\0\x0Bg\0\x0Cg\0\rg\0\x0Eg\0\x17g\0\x18g\0\x1Bg\0\x1Cg\0\x1Dg\0\x1Eg\0\x1Fg\0 g\0(g\0)g\0*g\0.g\x001g\x002g\x005g\x006g\0Ig\0Jg\0Ng\0Og\0Pg\0Rg\0\\g\0]g\0_g\0`g\0og\0rg\0~g\0\x80g\0\x90g\0\x91g\0\x97g\0\x98g\0\x9Cg\0\x9Eg\0\xB6g\0\xB7g\0\xCFg\0\xD1g\0\xD3g\0\xD5g\0\xE5g\0\xE6g\0\xECg\0\xEDg\0\xEFg\0\xF0g\0\xF3g\0\xF5g\0!h\0\"h\08h\0:h\0<h\0=h\0Ch\0Dh\0Hh\0Ih\0Lh\0Mh\0Qh\0Rh\0\x81h\0\x82h\0\x85h\0\x86h\0\x9Dh\0\x9Eh\0\xA8h\0\xA9h\0\xAFh\0\xB1h\0\xB5h\0\xB6h\0\xC4h\0\xC5h\0\xC9h\0\xCAh\0\xCBh\0\xCCh\0\xD2h\0\xD3h\0\xDAh\0\xDBh\0\xEEh\0\xEFh\0\x05i\0\x06i\0\ri\0\x0Ei\x000i\x001i\0Ji\0Ki\0Si\0Ti\0Zi\0[i\0mi\0ni\0ui\0vi\0\x82i\0\x83i\0\x9Ci\0\x9Di\0\xAEi\0\xAFi\0\xCBi\0\xCCi\0\xCDi\0\xCEi\0\x02j\0\x03j\0\x13j\0\x14j\0\x19j\0\x1Aj\0\x1Ej\0\x1Fj\0!j\0\"j\0#j\0$j\09j\0:j\0Kj\0Lj\0_j\0`j\0kj\0lj\0\x80j\0\x81j\0\x94j\0\x95j\0\xA2j\0\xA3j\0\x04k\0\x05k\0\nk\0\x0Bk\0!k\0\"k\0#k\0$k\x002k\x003k\0:k\0;k\0=k\0?k\0Ik\0Jk\0Lk\0Mk\0Pk\0Qk\0ak\0gk\0rk\0sk\0wk\0yk\0{k\0|k\0\x8Ak\0\x8Bk\0\x98k\0\x99k\0\xB5k\0\xB6k\0\xBAk\0\xBBk\0\xBCk\0\xBDk\0\xC0k\0\xC1k\0\xC5k\0\xC6k\0\xCDk\0\xCEk\0\xCFk\0\xD0k\0\xD2k\0\xD3k\0\xD4k\0\xD5k\0\xDBk\0\xDCk\0\xEBk\0\xECk\0\x0Fl\0\x10l\0\x11l\0\x12l\0#l\0$l\x004l\x005l\08l\09l\0Bl\0Cl\0Wl\0Xl\0]l\0^l\0_l\0bl\0jl\0kl\0vl\0wl\0zl\0{l\0}l\0~l\0\x83l\0\x84l\0\x88l\0\x8Al\0\x92l\0\x93l\0\x96l\0\x97l\0\x99l\0\x9Al\0\xB3l\0\xB4l\0\xB9l\0\xBAl\0\xBBl\0\xBCl\0\xBFl\0\xC0l\0\xC1l\0\xC2l\0\xC9l\0\xCBl\0\xD5l\0\xD6l\0\xE1l\0\xE3l\0\xE5l\0\xE6l\0\xE8l\0\xE9l\0\xF0l\0\xF1l\0\xF3l\0\xF4l\0\x0Bm\0\x0Cm\0\x17m\0\x18m\0\x1Bm\0\x1Cm\0\x1Em\0\x1Fm\0)m\0+m\x002m\x003m\0;m\0<m\0=m\0?m\0Am\0Bm\0fm\0gm\0im\0km\0nm\0om\0wm\0xm\0\x87m\0\x8Am\0\xAFm\0\xB0m\0\xB2m\0\xB3m\0\xB5m\0\xB6m\0\xBCm\0\xBDm\0\xD1m\0\xD2m\0\xDAm\0\xDBm\0\xE1m\0\xE2m\0\xE8m\0\xE9m\0\xF1m\0\xF2m\0\xF7m\0\xF8m\0\xFAm\0\xFBm\0\x05n\0\x06n\0\x1Bn\0\x1Cn\0!n\0\"n\0,n\0-n\0/n\x000n\08n\09n\0Vn\0Wn\0on\0pn\0\x90n\0\x91n\0\x96n\0\x97n\0\x9Dn\0\x9En\0\xAAn\0\xACn\0\xC4n\0\xC6n\0\xCBn\0\xCCn\0\xD1n\0\xD2n\0\xF4n\0\xF5n\0\xFEn\0\0o\0\x02o\0\x03o\0\x0Fo\0\x10o\0\x14o\0\x15o\0 o\0!o\0\"o\0#o\0+o\0,o\x002o\x003o\08o\09o\0To\0Uo\0Xo\0Yo\0[o\0\\o\0no\0oo\0\xA4o\0\xA5o\0\xB3o\0\xB4o\0\xC0o\0\xC1o\0\xC3o\0\xC4o\0\xDFo\0\xE0o\0\xE4o\0\xE5o\0\xEBo\0\xECo\0\xF1o\0\xF2o\0\x0Fp\0\x10p\0Lp\0Mp\0cp\0dp\0kp\0lp\0pp\0qp\0}p\0~p\0\x8Ep\0\x8Fp\0\xAEp\0\xAFp\0\xB8p\0\xB9p\0\xBAp\0\xBBp\0\xC8p\0\xC9p\0\xCFp\0\xD0p\0\xE4p\0\xE5p\0!q\0\"q\0&q\0'q\x006q\x007q\0Yq\0Zq\0^q\0_q\0gq\0hq\0iq\0jq\0\x8Aq\0\x8Bq\0\x9Fq\0\xA0q\0\xB1q\0\xB2q\0\xC3q\0\xC4q\0\xC8q\0\xC9q\0\xD2q\0\xD3q\0\xDFq\0\xE0q\0\x06r\0\x07r\0\x10r\0\x11r\0\x1Br\0\x1Cr\0*r\0+r\0,r\0.r\x005r\x007r\08r\09r\0:r\0;r\0=r\0?r\0Fr\0Ir\0Lr\0Mr\0Yr\0Zr\0[r\0\\r\0`r\0ar\0gr\0hr\0ir\0jr\0rr\0sr\0yr\0zr\0}r\0~r\0\xA7r\0\xA8r\0\xAFr\0\xB0r\0\xC0r\0\xC1r\0\xC2r\0\xC3r\0\xD0r\0\xD1r\0\xD7r\0\xD8r\0\xE0r\0\xE1r\0\xFCr\0\xFDr\0\x1Bs\0\x1Ds\x004s\x005s\x006s\x007s\0Ds\0Fs\0Ns\0Os\0hs\0is\0rs\0ss\0xs\0ys\0{s\0|s\0\x84s\0\x85s\0\x87s\0\x88s\0\x89s\0\x8As\0\x8Bs\0\x8Cs\0\xA9s\0\xAAs\0\xABs\0\xACs\0\xB2s\0\xB3s\0\xBBs\0\xBCs\0\xCAs\0\xCBs\0\xCDs\0\xCEs\0\xE0s\0\xE1s\0\xE5s\0\xE6s\0\xEDs\0\xEEs\0\xFEs\0\xFFs\0\x03t\0\x04t\0\x06t\0\x07t\0\tt\0\nt\0*t\0+t\x004t\x005t\0Yt\0Zt\0\\t\0]t\0^t\0`t\0dt\0et\0jt\0kt\0pt\0qt\0\xB0t\0\xB1t\0\xDCt\0\xDDt\0\xE6t\0\xE7t\0\xF6t\0\xF7t\0\x18u\0\x19u\0\x1Au\0\x1Bu\0\x1Cu\0\x1Du\0\x1Fu\0 u\0\"u\0#u\0(u\0)u\x000u\x004u\x007u\09u\0Lu\0Mu\0Yu\0Zu\0bu\0cu\0eu\0fu\0ju\0lu\0pu\0qu\0vu\0wu\0\x86u\0\x87u\0\x8Fu\0\x90u\0\x91u\0\x92u\0\xBCu\0\xBDu\0\xC5u\0\xC6u\0\xD5u\0\xD6u\0\xDBu\0\xDCu\0\xF4u\0\xF5u\0\x0Bv\0\x0Cv\0Bv\0Cv\0av\0bv\0xv\0yv\0{v\0\x7Fv\0\x84v\0\x85v\0\x86v\0\x88v\0\xAEv\0\xAFv\0\xC3v\0\xC4v\0\xCAv\0\xCBv\0\xDBv\0\xDDv\0\xDFv\0\xE0v\0\xE1v\0\xE2v\0\xE3v\0\xE5v\0\xE7v\0\xE8v\0\xEEv\0\xEFv\0\xF2v\0\xF3v\0\xF4v\0\xF5v\0\xF8v\0\xF9v\0\xFCv\0\xFDv\0\xFEv\0\xFFv\0\x01w\0\x02w\0\tw\0\nw\0\x0Bw\0\x0Cw\0\x1Fw\0!w\0<w\0=w\0>w\0?w\0[w\0\\w\0aw\0bw\0cw\0dw\0\xA7w\0\xA8w\0\xADw\0\xAEw\0\xDBw\0\xDCw\0\xE3w\0\xE4w\0\xE5w\0\xE6w\0\xEDw\0\xEEw\0\xF3w\0\xF4w\0\x02x\0\x03x\0\rx\0\x0Ex\0\x14x\0\x15x\x002x\x003x\x004x\x005x\0lx\0mx\0\x8Ex\0\x8Fx\0\x97x\0\x98x\0\x9Fx\0\xA0x\0\xA7x\0\xA8x\0\xA9x\0\xAAx\0\xB0x\0\xB1x\0\xBAx\0\xBBx\0\xBCx\0\xBDx\0\xC1x\0\xC2x\0\xE8x\0\xE9x\0\xEFx\0\xF0x\0\x0Ey\0\x0Fy\0\x19y\0\x1Ay\0:y\0;y\0>y\0?y\0Uy\0Wy\0Zy\0\\y\0]y\0_y\0ey\0fy\0hy\0iy\0\x7Fy\0\x80y\0\x81y\0\x82y\0\x8Dy\0\x90y\0\xAAy\0\xABy\0\xAEy\0\xAFy\0\xC0y\0\xC2y\0\xCBy\0\xCCy\0\xD1y\0\xD3y\0\xD8y\0\xD9y\0\xDFy\0\xE0y\0\xE4y\0\xE5y\0\xE6y\0\xE7y\0\xFBy\0\xFCy\0\x05z\0\x06z\0\x0Bz\0\x0Cz\0\rz\0\x0Ez\0.z\0/z\x001z\x002z\0?z\0@z\0Fz\0Gz\0Lz\0Nz\0iz\0jz\0vz\0wz\0yz\0{z\0\x7Fz\0\x80z\0\x81z\0\x82z\0\x97z\0\x98z\0\xA9z\0\xAAz\0\xAEz\0\xAFz\0\xB6z\0\xB7z\0\xCBz\0\xCCz\0\xD9z\0\xDAz\0\xDFz\0\xE1z\0\xE5z\0\xE6z\0\xEFz\0\xF0z\0\xF6z\0\xF7z\0\xF9z\0\xFAz\0\x11{\0\x12{\0\x1B{\0\x1C{\0&{\0'{\0({\0){\0,{\0-{\0F{\0G{\0I{\0J{\0K{\0L{\0T{\0U{\0V{\0W{\0\x97{\0\x98{\0\xA1{\0\xA2{\0\xAD{\0\xAE{\0\xB1{\0\xB2{\0\xC0{\0\xC1{\0\xC4{\0\xC5{\0\xC7{\0\xC8{\0\xC9{\0\xCA{\0!|\0\"|\0+|\0,|\0=|\0>|\0?|\0@|\0C|\0D|\0L|\0N|\0d|\0e|\0s|\0t|\0\x89|\0\x8A|\0\x97|\0\x98|\0\xB5|\0\xB6|\0\xBE|\0\xBF|\0\xCA|\0\xCB|\0\xD5|\0\xD6|\0\xDF|\0\xE0|\0\xFB|\0\xFC|\0\xFE|\0\xFF|\0\0}\0\x01}\0\x04}\0\x06}\0\r}\0\x0E}\0\x10}\0\x11}\0\x14}\0\x15}\0\x19}\0\x1C}\0 }\0!}\0\"}\0#}\0+}\0,}\0/}\x001}\09}\0:}\0B}\0C}\0D}\0E}\0P}\0Q}\0U}\0V}\0a}\0b}\0f}\0g}\0q}\0s}\0\x93}\0\x94}\0\x9C}\0\x9D}\0\xA0}\0\xA1}\0\xAD}\0\xAE}\0\xB1}\0\xB3}\0\xCA}\0\xCB}\0\xD2}\0\xD3}\0\xDA}\0\xDB}\0\xE3}\0\xE4}\0\xE8}\0\xEA}\0\xEC}\0\xED}\0\xEF}\0\xF0}\0\xF4}\0\xF5}\0\x1B~\0\x1C~\0#~\0$~\0.~\0/~\x001~\x002~\0=~\0?~\0A~\0B~\0F~\0G~\0T~\0U~\0^~\0_~\0j~\0k~\0s~\0t~\0|~\0}~\0\x8C~\0\x8D~\08\x7F\09\x7F\0:\x7F\0;\x7F\0U\x7F\0V\x7F\0j\x7F\0k\x7F\0n\x7F\0o\x7F\0p\x7F\0q\x7F\0r\x7F\0s\x7F\0u\x7F\0v\x7F\0w\x7F\0x\x7F\0\x85\x7F\0\x86\x7F\0\x8A\x7F\0\x8B\x7F\0\x8E\x7F\0\x8F\x7F\0\x9E\x7F\0\x9F\x7F\0\xA4\x7F\0\xA5\x7F\0\xA9\x7F\0\xAA\x7F\0\xBD\x7F\0\xBE\x7F\0\xC1\x7F\0\xC2\x7F\0\xD2\x7F\0\xD3\x7F\0\xD4\x7F\0\xD5\x7F\0\xF0\x7F\0\xF1\x7F\0\xF9\x7F\0\xFA\x7F\0\xFB\x7F\0\xFD\x7F\0\0\x80\0\x02\x80\0\x03\x80\0\x04\x80\0\x05\x80\0\x06\x80\0\x0C\x80\0\x0E\x80\0\x10\x80\0\x11\x80\0\x17\x80\0\x18\x80\x003\x80\x004\x80\x006\x80\x007\x80\0J\x80\0K\x80\0V\x80\0W\x80\0Z\x80\0[\x80\0^\x80\0_\x80\0o\x80\0q\x80\0r\x80\0s\x80\0w\x80\0x\x80\0}\x80\0~\x80\0\x89\x80\0\x8A\x80\0\x9A\x80\0\x9B\x80\0\xA1\x80\0\xA2\x80\0\xA5\x80\0\xA6\x80\0\xA9\x80\0\xAA\x80\0\xAF\x80\0\xB0\x80\0\xB2\x80\0\xB3\x80\0\xCC\x80\0\xCD\x80\0\xCE\x80\0\xCF\x80\0\xD6\x80\0\xD7\x80\0\xDE\x80\0\xDF\x80\0\xE1\x80\0\xE2\x80\0\xF8\x80\0\xF9\x80\0\xFD\x80\0\xFE\x80\0\x06\x81\0\x07\x81\0+\x81\0,\x81\0S\x81\0U\x81\0f\x81\0g\x81\0p\x81\0q\x81\0s\x81\0t\x81\0\x7F\x81\0\x80\x81\0\xBD\x81\0\xBE\x81\0\xC9\x81\0\xCA\x81\0\xD8\x81\0\xD9\x81\0\xE3\x81\0\xE4\x81\0\xE5\x81\0\xE6\x81\0\xE8\x81\0\xE9\x81\0\xEA\x81\0\xEB\x81\0\xED\x81\0\xEE\x81\0\xF3\x81\0\xF5\x81\0\xFA\x81\0\xFB\x81\0\x07\x82\0\x0B\x82\0\x0C\x82\0\x0E\x82\0\x12\x82\0\x13\x82\0\x1E\x82\0 \x82\0*\x82\0+\x82\0,\x82\0-\x82\09\x82\0:\x82\0f\x82\0g\x82\0o\x82\0p\x82\0r\x82\0s\x82\0~\x82\0\x7F\x82\0\x9D\x82\0\x9E\x82\0\xAC\x82\0\xAD\x82\0\xB1\x82\0\xB2\x82\0\xB3\x82\0\xB4\x82\0\xE5\x82\0\xE7\x82\0\xF1\x82\0\xF2\x82\0\x05\x83\0\x06\x83\0+\x83\0,\x83\x002\x83\x003\x83\x006\x83\x007\x83\0I\x83\0J\x83\0R\x83\0S\x83\0w\x83\0x\x83\0|\x83\0}\x83\0\x89\x83\0\x8B\x83\0\x8E\x83\0\x8F\x83\0\xAB\x83\0\xAC\x83\0\xDC\x83\0\xDD\x83\0\xE9\x83\0\xEA\x83\0\xEF\x83\0\xF0\x83\0\xF2\x83\0\xF3\x83\0\x04\x84\0\x05\x84\0\n\x84\0\x0B\x84\0,\x84\0-\x84\0=\x84\0>\x84\0I\x84\0J\x84\0W\x84\0X\x84\0[\x84\0\\\x84\0a\x84\0b\x84\0\x82\x84\0\x83\x84\0\x99\x84\0\x9A\x84\0\xB2\x84\0\xB3\x84\0\xBC\x84\0\xBD\x84\0\xCB\x84\0\xCC\x84\0\xEE\x84\0\xEF\x84\0\x15\x85\0\x16\x85\0!\x85\0\"\x85\0#\x85\0$\x85\0m\x85\0n\x85\0\x84\x85\0\x85\x85\0\xA6\x85\0\xA7\x85\0\xA9\x85\0\xAB\x85\0\xC9\x85\0\xCA\x85\0\xCD\x85\0\xCE\x85\0\xCF\x85\0\xD0\x85\0\xDD\x85\0\xDE\x85\0\xE4\x85\0\xE6\x85\0\x06\x86\0\x08\x86\0-\x86\0.\x86\0N\x86\0O\x86\0U\x86\0V\x86\0[\x86\0\\\x86\0_\x86\0`\x86\0g\x86\0h\x86\0\xC7\x86\0\xC8\x86\0\xCB\x86\0\xCC\x86\0\xD9\x86\0\xDA\x86\0\x02\x87\0\x03\x87\0\x1C\x87\0\x1D\x87\0v\x87\0w\x87\0\x8D\x87\0\x8E\x87\0\xA2\x87\0\xA3\x87\0\xF2\x87\0\xF3\x87\0\xF9\x87\0\xFA\x87\0\r\x88\0\x0E\x88\0;\x88\0<\x88\0@\x88\0A\x88\0L\x88\0M\x88\0S\x88\0T\x88\0W\x88\0X\x88\0[\x88\0\\\x88\0]\x88\0^\x88\0a\x88\0b\x88\0c\x88\0d\x88\0h\x88\0i\x88\0\x8B\x88\0\x8C\x88\0\xAB\x88\0\xAC\x88\0\xC1\x88\0\xC3\x88\0\xD5\x88\0\xD6\x88\0\xDC\x88\0\xDE\x88\0\xE1\x88\0\xE2\x88\0\xFD\x88\0\xFE\x88\0\x07\x89\0\x08\x89\x002\x89\x003\x89\0\x7F\x89\0\x80\x89\0\x81\x89\0\x82\x89\0\x86\x89\0\x87\x89\0\x8B\x89\0\x8C\x89\0\x8F\x89\0\x90\x89\0\x96\x89\0\x97\x89\0\xAA\x89\0\xAB\x89\0\xBA\x89\0\xBB\x89\0\xBD\x89\0\xBE\x89\0\xC0\x89\0\xC1\x89\0\xD2\x89\0\xD3\x89\0\xE3\x89\0\xE4\x89\0\xF8\x89\0\xF9\x89\0\0\x8A\0\x01\x8A\0\x02\x8A\0\x03\x8A\0\x08\x8A\0\t\x8A\0\n\x8A\0\x0B\x8A\0\x0E\x8A\0\x0F\x8A\0\x13\x8A\0\x14\x8A\0\x17\x8A\0\x19\x8A\0%\x8A\0&\x8A\0*\x8A\0+\x8A\0-\x8A\0.\x8A\x001\x8A\x002\x8A\x004\x8A\x005\x8A\0;\x8A\0=\x8A\0U\x8A\0V\x8A\0^\x8A\0_\x8A\0b\x8A\0c\x8A\0f\x8A\0g\x8A\0i\x8A\0j\x8A\0q\x8A\0t\x8A\0\x87\x8A\0\x88\x8A\0\x8C\x8A\0\x8E\x8A\0\x93\x8A\0\x94\x8A\0\x95\x8A\0\x96\x8A\0\x9E\x8A\0\x9F\x8A\0\xA0\x8A\0\xA1\x8A\0\xA4\x8A\0\xA5\x8A\0\xAA\x8A\0\xAB\x8A\0\xB0\x8A\0\xB1\x8A\0\xB2\x8A\0\xB3\x8A\0\xBC\x8A\0\xBD\x8A\0\xBF\x8A\0\xC0\x8A\0\xC7\x8A\0\xC8\x8A\0\xCB\x8A\0\xCC\x8A\0\xD2\x8A\0\xD3\x8A\0\xD6\x8A\0\xD7\x8A\0\xF8\x8A\0\xF9\x8A\0\xFA\x8A\0\xFB\x8A\0\xFE\x8A\0\xFF\x8A\0\0\x8B\0\x01\x8B\0\x02\x8B\0\x03\x8B\0\x1B\x8B\0\x1C\x8B\0\x1D\x8B\0\x1E\x8B\0I\x8B\0J\x8B\0X\x8B\0Y\x8B\0\\\x8B\0]\x8B\0f\x8B\0g\x8B\0o\x8B\0q\x8B\0w\x8B\0x\x8B\0}\x8B\0~\x8B\0\x80\x8B\0\x81\x8B\0\x8A\x8B\0\x8B\x8B\0\x93\x8B\0\x94\x8B\0\x9A\x8B\0\x9B\x8B\x007\x8C\08\x8C\0F\x8C\0G\x8C\0H\x8C\0I\x8C\0P\x8C\0Q\x8C\0a\x8C\0b\x8C\0j\x8C\0k\x8C\0l\x8C\0m\x8C\0\x8C\x8C\0\x8D\x8C\0\x93\x8C\0\x94\x8C\0\x9D\x8C\0\x9F\x8C\0\xA0\x8C\0\xA3\x8C\0\xA8\x8C\0\xA9\x8C\0\xAA\x8C\0\xAD\x8C\0\xB4\x8C\0\xB5\x8C\0\xB7\x8C\0\xB8\x8C\0\xBB\x8C\0\xBD\x8C\0\xC0\x8C\0\xC1\x8C\0\xC7\x8C\0\xC9\x8C\0\xD3\x8C\0\xD4\x8C\0\xDC\x8C\0\xDD\x8C\0\xDE\x8C\0\xDF\x8C\0\xE2\x8C\0\xE5\x8C\0\xE6\x8C\0\xE7\x8C\0\xEA\x8C\0\xEB\x8C\0\xED\x8C\0\xEE\x8C\0\xF4\x8C\0\xF5\x8C\0\xFA\x8C\0\xFB\x8C\0\xFC\x8C\0\xFE\x8C\0\x08\x8D\0\t\x8D\0\n\x8D\0\x0B\x8D\0\x0F\x8D\0\x10\x8D\0d\x8D\0e\x8D\0k\x8D\0l\x8D\0p\x8D\0q\x8D\0w\x8D\0x\x8D\0\x85\x8D\0\x86\x8D\0\x8A\x8D\0\x8B\x8D\0\x95\x8D\0\x96\x8D\0\x99\x8D\0\x9A\x8D\0\xA3\x8D\0\xA4\x8D\0\xA8\x8D\0\xA9\x8D\0\xB3\x8D\0\xB4\x8D\0\xCC\x8D\0\xCD\x8D\0\xCE\x8D\0\xCF\x8D\0\xD1\x8D\0\xD2\x8D\0\xDD\x8D\0\xDE\x8D\0\xDF\x8D\0\xE0\x8D\0\xE1\x8D\0\xE2\x8D\0\xEF\x8D\0\xF0\x8D\0\xF3\x8D\0\xF4\x8D\0\x0F\x8E\0\x10\x8E\0\"\x8E\0#\x8E\0_\x8E\0`\x8E\0d\x8E\0e\x8E\0\x8D\x8E\0\x8E\x8E\0\xAB\x8E\0\xAC\x8E\0\xB2\x8E\0\xB3\x8E\0\xCA\x8E\0\xCB\x8E\0\xCC\x8E\0\xCE\x8E\0\xD2\x8E\0\xD3\x8E\0\xDF\x8E\0\xE0\x8E\0\x03\x8F\0\x04\x8F\0\t\x8F\0\n\x8F\0\x14\x8F\0\x16\x8F\0\x1B\x8F\0\x1C\x8F\0\x1D\x8F\0\x1E\x8F\0)\x8F\0+\x8F\0/\x8F\x000\x8F\08\x8F\09\x8F\0I\x8F\0J\x8F\0_\x8F\0`\x8F\0\x9B\x8F\0\x9C\x8F\0\xA6\x8F\0\xA7\x8F\0\xA8\x8F\0\xA9\x8F\0\xAD\x8F\0\xAE\x8F\0\xAF\x8F\0\xB3\x8F\0\xC5\x8F\0\xC6\x8F\0\xCE\x8F\0\xCF\x8F\0\xD1\x8F\0\xD2\x8F\0\xD4\x8F\0\xD5\x8F\0\xE6\x8F\0\xE7\x8F\0\xEA\x8F\0\xEC\x8F\0\xF0\x8F\0\xF1\x8F\0\xF4\x8F\0\xF5\x8F\0\xF7\x8F\0\xF8\x8F\0\xFD\x8F\0\xFE\x8F\0\0\x90\0\x02\x90\0\x03\x90\0\x04\x90\0\x06\x90\0\x07\x90\0\x0F\x90\0\x11\x90\0\x14\x90\0\x15\x90\0\x19\x90\0\x1C\x90\0\x1D\x90\0\x1E\x90\0\x1F\x90\0!\x90\0\"\x90\0$\x90\x001\x90\x003\x90\08\x90\09\x90\0<\x90\0=\x90\0G\x90\0H\x90\0J\x90\0L\x90\0M\x90\0O\x90\0S\x90\0V\x90\0Y\x90\0Z\x90\0\\\x90\0]\x90\0`\x90\0a\x90\0i\x90\0j\x90\0m\x90\0o\x90\0r\x90\0s\x90\0w\x90\0y\x90\0z\x90\0{\x90\0\x7F\x90\0\x82\x90\0\x84\x90\0\x85\x90\0\x8A\x90\0\x8B\x90\0\x8F\x90\0\x90\x90\0\xA3\x90\0\xA4\x90\0\xA6\x90\0\xA7\x90\0\xAA\x90\0\xAB\x90\0\xB1\x90\0\xB2\x90\0\xCE\x90\0\xCF\x90\0\xE8\x90\0\xE9\x90\0\xED\x90\0\xEE\x90\0\xF5\x90\0\xF6\x90\0\xFD\x90\0\xFE\x90\0\x02\x91\0\x03\x91\0\t\x91\0\n\x91\0-\x91\0.\x91\x000\x91\x001\x91\0I\x91\0J\x91\0M\x91\0N\x91\0R\x91\0S\x91\0w\x91\0y\x91\0\x89\x91\0\x8A\x91\0\x92\x91\0\x93\x91\0\x9C\x91\0\x9D\x91\0\xAB\x91\0\xAC\x91\0\xC7\x91\0\xC8\x91\0\xCB\x91\0\xD0\x91\0\xD1\x91\0\xD2\x91\0\xDD\x91\0\xDE\x91\0\xE3\x91\0\xE4\x91\x004\x92\x005\x92\0b\x92\0c\x92\0\x80\x92\0\x81\x92\0\x85\x92\0\x86\x92\0\x96\x92\0\x97\x92\0\x98\x92\0\x99\x92\0\xB3\x92\0\xB4\x92\0\xB7\x92\0\xB8\x92\0\xD2\x92\0\xD3\x92\0\xFC\x92\0\xFD\x92\0\x04\x93\0\x05\x93\0\"\x93\0#\x93\0&\x93\0'\x93\0+\x93\0,\x93\0/\x93\x000\x93\0K\x93\0L\x93\0u\x93\0v\x93\0~\x93\0\x7F\x93\0\x8A\x93\0\x8B\x93\0\x96\x93\0\x97\x93\0\xAE\x93\0\xAF\x93\0\xE1\x93\0\xE2\x93\0\x18\x94\0\x19\x94\x005\x94\x006\x94\0Q\x94\0R\x94\0w\x95\0x\x95\0\x80\x95\0\x81\x95\0\x83\x95\0\x84\x95\0\x89\x95\0\x8A\x95\0\x8B\x95\0\x8C\x95\0\x8F\x95\0\x90\x95\0\x92\x95\0\x94\x95\0\xA3\x95\0\xA4\x95\0\xB1\x95\0\xB2\x95\0\xC6\x95\0\xC7\x95\0\xCA\x95\0\xCB\x95\0\xCD\x95\0\xCE\x95\0\xD0\x95\0\xD1\x95\0\xDC\x95\0\xDD\x95\0\xE1\x95\0\xE2\x95\x002\x96\x003\x96\0;\x96\0<\x96\0?\x96\0A\x96\0D\x96\0E\x96\0M\x96\0N\x96\0P\x96\0Q\x96\0b\x96\0e\x96\0j\x96\0k\x96\0p\x96\0q\x96\0s\x96\0t\x96\0u\x96\0y\x96\0}\x96\0~\x96\0\x86\x96\0\x87\x96\0\x8A\x96\0\x8B\x96\0\x8E\x96\0\x8F\x96\0\x94\x96\0\x95\x96\0\x9B\x96\0\x9D\x96\0\xA8\x96\0\xA9\x96\0\xAA\x96\0\xAB\x96\0\xB1\x96\0\xB2\x96\0\xBB\x96\0\xBC\x96\0\xC4\x96\0\xC7\x96\0\xC9\x96\0\xCA\x96\0\xD6\x96\0\xD7\x96\0\xD9\x96\0\xDA\x96\0\xDC\x96\0\xDD\x96\0\xDE\x96\0\xDF\x96\0\xE2\x96\0\xE4\x96\0\xE8\x96\0\xE9\x96\0\xEA\x96\0\xEB\x96\0\xF2\x96\0\xF3\x96\0\xF6\x96\0\xF8\x96\0\xFB\x96\0\xFC\x96\0\0\x97\0\x01\x97\0\x07\x97\0\x08\x97\0\r\x97\0\x0E\x97\0'\x97\0(\x97\x002\x97\x003\x97\08\x97\0:\x97\0B\x97\0C\x97\0H\x97\0I\x97\0R\x97\0S\x97\0V\x97\0W\x97\0\\\x97\0]\x97\0^\x97\0_\x97\0`\x97\0a\x97\0b\x97\0c\x97\0i\x97\0j\x97\0|\x97\0}\x97\0\x8B\x97\0\x8C\x97\0\xC3\x97\0\xC4\x97\0\xCB\x97\0\xCC\x97\0\xD3\x97\0\xD4\x97\0\xF3\x97\0\xF4\x97\0\xFB\x97\0\xFC\x97\0\xFF\x97\0\0\x98\0\x01\x98\0\x03\x98\0\x05\x98\0\x07\x98\0\x08\x98\0\t\x98\0\x10\x98\0\x12\x98\0\x13\x98\0\x14\x98\0\x17\x98\0\x19\x98\0\x1E\x98\0\x1F\x98\0-\x98\0.\x98\0;\x98\0<\x98\0F\x98\0G\x98\0L\x98\0N\x98\0O\x98\0P\x98\0X\x98\0Y\x98\0^\x98\0_\x98\0g\x98\0h\x98\0o\x98\0p\x98\0\xA8\x98\0\xA9\x98\0\xC4\x98\0\xC5\x98\0\xDB\x98\0\xDC\x98\0\xDF\x98\0\xE0\x98\0\xEF\x98\0\xF0\x98\0\xF2\x98\0\xF3\x98\0\xFD\x98\0\xFF\x98\0\x05\x99\0\x06\x99\0\n\x99\0\x0B\x99\0\x10\x99\0\x11\x99\0\x18\x99\0\x19\x99\0(\x99\0)\x99\0\x96\x99\0\x97\x99\0\x99\x99\0\x9A\x99\0\xAC\x99\0\xAD\x99\0\xD0\x99\0\xD1\x99\0\xD5\x99\0\xD6\x99\0\xDB\x99\0\xDC\x99\0\x0E\x9A\0\x0F\x9A\0\x19\x9A\0\x1A\x9A\x007\x9A\08\x9A\0E\x9A\0F\x9A\0W\x9A\0X\x9A\0Z\x9A\0[\x9A\0\xA8\x9A\0\xA9\x9A\0\xD4\x9A\0\xD5\x9A\0\xD8\x9A\0\xD9\x9A\0\xEE\x9A\0\xEF\x9A\0\x06\x9B\0\x07\x9B\0%\x9B\0&\x9B\0'\x9B\0(\x9B\x001\x9B\x002\x9B\0<\x9B\0=\x9B\0A\x9B\0C\x9B\0E\x9B\0F\x9B\0T\x9B\0U\x9B\0Z\x9B\0[\x9B\0o\x9B\0p\x9B\0\xAE\x9B\0\xAF\x9B\0\xE5\x9C\0\xE6\x9C\0\xF3\x9C\0\xF5\x9C\0;\x9D\0<\x9D\0]\x9D\0^\x9D\0\xF9\x9D\0\xFA\x9D\0\x7F\x9E\0\x80\x9E\0\x97\x9E\0\x98\x9E\0\xA5\x9E\0\xA6\x9E\0\xB5\x9E\0\xB6\x9E\0\xBB\x9E\0\xBD\x9E\0\xC3\x9E\0\xC4\x9E\0\xCE\x9E\0\xCF\x9E\0\xD1\x9E\0\xD2\x9E\0\xD8\x9E\0\xD9\x9E\0\xDE\x9E\0\xDF\x9E\0\xE8\x9E\0\xE9\x9E\0\x13\x9F\0\x14\x9F\0 \x9F\0!\x9F\0;\x9F\0<\x9F\0J\x9F\0L\x9F\0R\x9F\0S\x9F\0a\x9F\0b\x9F\0\x8D\x9F\0\x8E\x9F\0\x9C\x9F\0\x9D\x9F\0") }, 2179u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"a\0\0{\0\0") }, 26u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\"\0\x02\0\x04\0\x06\0\x08\0\n\0\x0C\0\x0E\0\x10\0\x12\0\x14\0\x16\0\x18\0\x1A\0\x1D\0 \0#\0&\0(\0+\0.\x001\x003\x007\09\0;\0=\0?\0A\0C\0E\0G\0I\0L\0bhchdldygcgqgxhhhlkhklkpncngcngqngxnhlnknkcnkqnkxnqntshnxnyphqhrhshthtltstshxh") }, - )), - ]; - unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleExemplarCharactersMainV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleExemplarCharactersMainV1>, icu_provider::DataError> { - let mut metadata = icu_provider::DataResponseMetadata::default(); - let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_MAIN_V1, req.id, req.metadata.attributes_prefix_match) { - payload - } else { - const FALLBACKER: icu::locale::fallback::LocaleFallbackerWithConfig<'static> = icu::locale::fallback::LocaleFallbacker::new().for_config(<icu::locale::provider::LocaleExemplarCharactersMainV1 as icu_provider::DataMarker>::INFO.fallback_config); - let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); - loop { - if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_MAIN_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { - metadata.locale = Some(fallback_iterator.take()); - break payload; - } - if fallback_iterator.get().is_unknown() { - return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(<icu::locale::provider::LocaleExemplarCharactersMainV1 as icu_provider::DataMarker>::INFO, req)); - } - fallback_iterator.step(); - } - }; - Ok(icu_provider::DataResponse { payload, metadata }) - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_exemplar_characters_main_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleExemplarCharactersMainV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok(icu_provider::baked::DataStore::iter(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_MAIN_V1).collect()) - } - } - }; - ($ provider : ty , DRY) => {}; - ($ provider : ty , DRY , ITER) => { - __impl_locale_exemplar_characters_main_v1!($provider, ITER); - }; -} -#[doc(inline)] -pub use __impl_locale_exemplar_characters_main_v1 as impl_locale_exemplar_characters_main_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_numbers_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_numbers_v1.rs.data deleted file mode 100644 index 36978f6dbb4d..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_numbers_v1.rs.data +++ /dev/null @@ -1,323 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleExemplarCharactersNumbersV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 484B for the lookup data structure (97 data identifiers) -/// * 3566B[^1] for the actual data (36 unique structs) -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `icu_provider/baked` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_exemplar_characters_numbers_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - const DATA_LOCALE_EXEMPLAR_CHARACTERS_NUMBERS_V1: icu_provider::baked::zerotrie::Data<icu::locale::provider::LocaleExemplarCharactersNumbersV1> = { - const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xE1uabcdefhiklmnoprstuxyz\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01'=CQs\x90\x9C\xA8\xDA\xE5\xF0\xFB\xFE\x0F\x1AJXmp{\xC2rs\"\x80-\xC5DLMST\x02\x08\x0E\x14Z\x81\xC2BY\x01\x81\x81\xC2AR\x01\x81\x81\xC2AO\x01\x82\x82N\x81\x83\xC6eghlnr\x01\x04\x06\x08\t\x84\x84c\x85o\x85o\x86\x83\x84\xC2sv\x01\x84\x84e-\xC3ACL\x02\x04T\x84H\x87I\x87\xC5nostu\x11\x12\x16\x17-\xC4FNSZ\x02\x04\x06I\x84O\x84E\x84A\x84\x88-CR\x84\x88\x89\xC5afior\x01\x07\x08\t\x8A-Adlm\x8B\x88\x89\x8C-\xC2LM\x02U\x8DA\x8D\xC4eiuy\x01\x02\x03\x81\x85\x84\x84\xC3eit\x01\x02\x8E\x8F-CH\x87\xC8aeknosxy\x01\x03\x04\x06\x08\n!\x84a\x84\x84\x90\0k\x85\x90\x01v-\xC3DOT\x05\neva\x90\x02rya\x90\x03elu\x90\x04\x84\xC3itv\x03\x04j\x90\x05\x88\x84\xC3nry\x02\x03i\x83\x85\x90\x06\xC3eoq\x01\x02\x85\x88o\x90\x07r\x90\x08\xC4alst\x02\x03\x05\x90\t\x84\x90\n-PT\x84\xC3amu\x02\x04j\x85\x90\x0B\x84\xCAachklqrvyz\x08\x0B\x0E\x0F\x10\x11\x17\x18\x1A\x85\xC2ht\x01\x84\x90\x0Cn\x90\rn\x90\x0E\x84\x89\x84-Latn\x8D\x88r\x80l\x84\xC4aehk\x02\x04\x05\x90\x0F\x90\x10\x8D\x84\xC4knrz\x01\x04\x06\x84d\x90\x11\x90\x01\x84-Cyrl\x84nr\x85ue\x90\x12-Hans\x90\x12h\x90\x13-Hant\x90\x12" }; - const VALUES: &'static [<icu::locale::provider::LocaleExemplarCharactersNumbersV1 as icu_provider::baked::zerotrie::DynamicDataMarker>::DataStruct] = &[ - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\t\x06\0\n\x06\0\x1C\x06\0\x1D\x06\0`\x06\0m\x06\0\x0E \0\x0F \0\x11 \0\x12 \x000 \x001 \0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\x0E \0\x0F \0\x11 \0\x12 \x000 \x001 \0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"+\0\0/\0\x000\0\0:\0\0j\x06\0k\x06\0\x0E \0\x0F \0\x11 \0\x12 \x000 \x001 \0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\xE6\t\0\xF0\t\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0.\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0") }, 16u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0f\t\0p\t\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\xB2\0\0\xB4\0\0\x11 \0\x12 \x000 \x002 \0") }, 20u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x02\0\x05\0\xCA\xB2\xE1\xB5\x83\xE1\xB5\x8F\xE1\xB5\x83") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0,\0\0-\0\0/\0\x000\0\0:\0\0\x11 \0\x12 \0\x19 \0\x1A \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0-\0\x000\0\0:\0\x000 \x001 \0\x12\"\0\x13\"\0") }, 15u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0-\0\0.\0\0/\0\x000\0\0:\0\x000 \x001 \0\x12\"\0\x13\"\0") }, 16u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0-\0\0.\0\0/\0\x000\0\0:\0\0\t\x06\0\n\x06\0j\x06\0m\x06\0\xF0\x06\0\xFA\x06\0\x0E \0\x0F \x000 \x001 \0\x12\"\0\x13\"\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"P\xE9\x01Z\xE9\x01") }, 10u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\xB2\0\0\xB4\0\0\xB3\x02\0\xB4\x02\0\xE2\x02\0\xE3\x02\0H\x1D\0J\x1D\0\x11 \0\x12 \x000 \x001 \0\x12\"\0\x13\"\0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0'\0\0(\0\0+\0\0.\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xEA\x8B\x8D\xEA\x91\x8D\xEA\x8C\x95\xEA\x87\x96\xEA\x89\xAC\xEA\x83\x98\xEA\x8F\x83\xEA\x89\x86\xEA\x88\xAC") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\xE6\x0C\0\xF0\x0C\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0k\x06\0m\x06\0\xF0\x06\0\xFA\x06\0\x0E \0\x0F \0\x11 \0\x12 \x000 \x001 \0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\x001\0\0g\t\0p\t\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\x001\0\0g\x0B\0p\x0B\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\x001\0\0g\x0C\0p\x0C\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0'\0\0(\0\0+\0\0/\0\x000\0\0:\0\0\xAA\0\0\xAB\0\0\xBA\0\0\xBB\0\0\x11 \0\x12 \x000 \x001 \0\x12\"\0\x13\"\0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0@\x10\0J\x10\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0,\0\0-\0\0/\0\0\x0C\x06\0\r\x06\0\xC0\x07\0\xCA\x07\0\x11 \0\x12 \x000 \x001 \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0f\x0B\0p\x0B\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0f\n\0p\n\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\t\x06\0\n\x06\0j\x06\0m\x06\0\xF0\x06\0\xFA\x06\0\x0E \0\x0F \0\x11 \0\x12 \x000 \x001 \0\x12\"\0\x13\"\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0,\0\0.\0\0/\0\x000\0\0:\0\0\x19 \0\x1A \x000 \x001 \0\x12\"\0\x13\"\0") }, 16u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0P\x1C\0Z\x1C\0\x11 \0\x12 \0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\xAA\0\0\xAB\0\0X\x1D\0Y\x1D\0\x11 \0\x12 \x000 \x001 \0\x12\"\0\x13\"\0") }, 20u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0@\x10\0J\x10\0\x90\x10\0\x9A\x10\0\x11 \0\x12 \x000 \x001 \0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\xE6\x0B\0\xF0\x0B\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0f\x0C\0p\x0C\0\x11 \0\x12 \x000 \x001 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0\x12\"\0\x13\"\0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0\x070\0\x080\0\0N\0\x01N\0\x03N\0\x04N\0\tN\0\nN\0]N\0^N\0\x8CN\0\x8DN\0\x94N\0\x95N\0kQ\0lQ\0mQ\0nQ\0\xDBV\0\xDCV\0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0+\0\0/\0\x000\0\0:\0\0\x11 \0\x12 \x000 \x001 \0\x070\0\x080\0\0N\0\x01N\0\x03N\0\x04N\0\tN\0\nN\0]N\0^N\0\x8CN\0\x8DN\0\x94N\0\x95N\0kQ\0lQ\0mQ\0nQ\0AS\0BS\0\xDBV\0\xDCV\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - ]; - unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleExemplarCharactersNumbersV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleExemplarCharactersNumbersV1>, icu_provider::DataError> { - let mut metadata = icu_provider::DataResponseMetadata::default(); - let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_NUMBERS_V1, req.id, req.metadata.attributes_prefix_match) { - payload - } else { - const FALLBACKER: icu::locale::fallback::LocaleFallbackerWithConfig<'static> = icu::locale::fallback::LocaleFallbacker::new().for_config(<icu::locale::provider::LocaleExemplarCharactersNumbersV1 as icu_provider::DataMarker>::INFO.fallback_config); - let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); - loop { - if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_NUMBERS_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { - metadata.locale = Some(fallback_iterator.take()); - break payload; - } - if fallback_iterator.get().is_unknown() { - return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(<icu::locale::provider::LocaleExemplarCharactersNumbersV1 as icu_provider::DataMarker>::INFO, req)); - } - fallback_iterator.step(); - } - }; - Ok(icu_provider::DataResponse { payload, metadata }) - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_exemplar_characters_numbers_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleExemplarCharactersNumbersV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok(icu_provider::baked::DataStore::iter(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_NUMBERS_V1).collect()) - } - } - }; - ($ provider : ty , DRY) => {}; - ($ provider : ty , DRY , ITER) => { - __impl_locale_exemplar_characters_numbers_v1!($provider, ITER); - }; -} -#[doc(inline)] -pub use __impl_locale_exemplar_characters_numbers_v1 as impl_locale_exemplar_characters_numbers_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_punctuation_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_punctuation_v1.rs.data deleted file mode 100644 index 6e67eb38be88..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_exemplar_characters_punctuation_v1.rs.data +++ /dev/null @@ -1,729 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleExemplarCharactersPunctuationV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 749B for the lookup data structure (164 data identifiers) -/// * 13615B[^1] for the actual data (94 unique structs) -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `icu_provider/baked` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_exemplar_characters_punctuation_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - const DATA_LOCALE_EXEMPLAR_CHARACTERS_PUNCTUATION_V1: icu_provider::baked::zerotrie::Data<icu::locale::provider::LocaleExemplarCharactersPunctuationV1> = { - const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"\xE1yabcdefghijklmnopqrstuvxyz\0\0\0\0\0\0\0\0\0\0\x01\x01\x01\x01\x01\x01\x01\x01\x02\x02\x02\x02\x02\x02\x119Paz\x99\xA8\xC9\xE3\xE68Pp\x88\x98\xB5\xB7\xC3\x127KX`t\xC5fmrsz\x01\x02\x03\x06\x80\x81\x82\x83t\x84\x80\xC9aeghlnrsu\x08\t\x0C\x0E\x10\x11\x13\x14\x85l-Latn\x86\x87\x88c\x89o\x80o\x8A\x8Bx\x80\x8Ca\x85\xC6aehsvy\x01\x03\x05\x08\n\x84b\x8Dr\x80\x8Ew\x8F\x90\0\x80\xC4aeos\x02\x03\x06\x90\x01\x85i\x90\x02b\x90\x03\xC7elnostu\x02\x04\x05\x07\x08\n\x90\x04\x90\x05\x80\x90\x06\x84\x90\x07\x80\xC6afiory\x02\t\x0E\x10\x12\x90\x08-Adlm\x90\t\x90\nl\x90\x0B\x90\x01\x90\x0C\x80\xC4adlu\x03\x05\x06\x80a\x80\x90\r\x84\x80\xC8aeirstuy\x02\x04\x06\x08\x0B\r\x0F\x90\x0E\x90\x0F\x90\x10\x90\x11b\x90\x03\x90\x12\x90\x13\x90\x14\xC7adegist\x01\x02\x04\x06\x08\n\x80\x80\x90\x15\x90\x16\x90\x17\x90\x18\x90\x19a\x90\x1A\xCBaegkmnosuxy\x02\x05\x07\x10\x12\x13\x1E%&;\x90\x1Ba\x90\x1Cp\x80\x90\0-Arab\x90\x1D\x90\x1E\x80\x90\x1Fk\x80-Latn\x90 \x80-Deva\x80\x80v\x80-\xC3DOT\x04\x08eva\x80rya\x80elu\x80\x85\xC6bimotv\x01\x04\x07\x08\n\x85j\x90\x0Co\x90!\x80\x90\"\x90#\xC8aklnrsty\x03\x05\x06\t\x0B\x0C\x0Ei\x90$\x90%\x80\x80i\x80\x90&\x80\x90'\x90(\xC5deloq\x06\x08\t\x0Bs\x85-NL\x80\x90)\x80\x90*o\x90+\xC3cmr\x07\t\x90,-ES\x90-\x90.\x83\xC6aclmst\x02\x04\x06\t\x0B\x90/m\x80\x900s\x90!\x901\x80-PT\x902u\x80\xC3aou\x03\x05j\x903\x904\x85\xD0acdhikloqrtuvwyz\x05\t\x11\x14\x15\x16\x18\x19\x1B$%&'),\x90$h\x905\x906n\x80\x907-Deva\x80n\x90(\x80\x8E\x908\x80\x909\x90:-Latn\x90;\x80\x80\x80\x90<r\x90=l\x900\xCAaeghknorty\x01\x03\x05\x07\t\n\x0B\x0C\x0E\x80\x90>\x90?\x90@\x90A\x80\x80\x80\x90Bv\x90 \xC5gknrz\x02\x04\x07\t\x90C\x90Dd\x90E\x90F\x80\xC3eim\x03\x04c\x90G\x80w\x90H\xC2hn\x01\x80r\x90I\xC3oru\x02\x04\x90Jl\x84e\x90K-Hans\x90L\xC2ah\x01\x80\x90M-Hant\x90K" }; - const VALUES: &'static [<icu::locale::provider::LocaleExemplarCharactersPunctuationV1 as icu_provider::baked::zerotrie::DynamicDataMarker>::DataStruct] = &[ - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0-\0\0.\0\0/\0\0?\0\0@\0\0[\0\0\\\0\0]\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0a\x13\0g\x13\0\x10 \0\x11 \0\x13 \0\x14 \09 \0; \0") }, 20u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0-\0\0/\0\0:\0\0;\0\0[\0\0\\\0\0]\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x0C\x06\0\r\x06\0\x1B\x06\0\x1C\x06\0\x1F\x06\0 \x06\0\x10 \0\x12 \0\x13 \0\x15 \0& \0' \0") }, 20u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0d\t\0e\t\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA1\0\0\xA2\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\xBF\0\0\xC0\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 37u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 12u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \0") }, 15u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \x003 \x004 \0\x16!\0\x17!\0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0-\0\x000\0\0:\0\0;\0\0?\0\0A\0\0[\0\0^\0\0`\0\0a\0\0|\0\0}\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0+\0\0,\0\x000\0\0:\0\0A\0\0[\0\0^\0\0_\0\0`\0\0|\0\0}\0\0~\0\0\x7F\0\0\xA6\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xB0\0\0\xB1\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x16 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0$ \0& \0( \x000 \x004 \09 \0; \0") }, 52u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0d\t\0f\t\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0+\0\0,\0\0-\0\0.\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x11 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1F \0& \0' \x002 \x004 \0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0&\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x14 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0n\x16\0o\x16\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x14 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0! \0& \0' \x002 \x004 \0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\0-\0\0.\0\x000\0\0:\0\0<\0\0?\0\0A\0\0_\0\0`\0\0\xA7\0\0\xA8\0\0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0&\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0@\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0& \0' \0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\x000\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\x11 \0\x12 \0\x13 \0\x14 \0\x1C \0\x1D \0\x1E \0\x1F \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0+\0\0-\0\x000\0\0:\0\0;\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x0C\x06\0\r\x06\0\x1B\x06\0\x1C\x06\0\x1F\x06\0 \x06\0k\x06\0m\x06\0\x10 \0\x12 \0& \0' \09 \0; \0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"%\0\0&\0\0-\0\0/\0\0\x11 \0\x12 \x000 \x001 \0^\xE9\x01`\xE9\x01") }, 7u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0#\0\0$\0\0&\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x14 \0\x19 \0\x1A \0\x1D \0\x1E \0& \0' \0") }, 25u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0@\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x19 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA1\0\0\xA2\0\0\xA7\0\0\xA8\0\0\xA9\0\0\xAA\0\0\xAE\0\0\xAF\0\0\xB0\0\0\xB1\0\0\xB6\0\0\xB8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0( \0J \0K \0\"!\0#!\0") }, 41u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \x002 \x004 \0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\x000\0\0:\0\0<\0\0?\0\0@\0\0[\0\0\\\0\0]\0\0^\0\0\xBE\x05\0\xBF\x05\0\xF3\x05\0\xF5\x05\0\x10 \0\x12 \0\x13 \0\x15 \0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0d\t\0f\t\0p\t\0q\t\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0+\0\0,\0\0-\0\0.\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x11 \0\x13 \0\x15 \0\x18 \0\x1B \0\x1C \0\x1F \0& \0' \x002 \x004 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0*\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0~\0\0\x7F\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \0\x13 \0\x14 \0\x19 \0\x1A \0\x1D \0\x1F \0& \0' \0R \0S \0\xE8'\0\xEA'\0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b",\0\0-\0\0.\0\0/\0\0:\0\0;\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0Z\x05\0`\x05\0\x8A\x05\0\x8B\x05\0") }, 12u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1F \0 \0\" \0& \0' \0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0#\0\0$\0\0%\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0_\0\0`\0\0\xA7\0\0\xA8\0\0\xB7\0\0\xB8\0\0\x10 \0\x12 \0\x13 \0\x17 \0\x18 \0\x1A \0\x1C \0\x1E \0% \0' \x000 \x001 \x002 \x004 \x005 \x006 \0; \0< \0\x010\0\x040\0\x080\0\x120\0\x140\0\x180\0\x1D0\0\x1F0\x000\xFE\x002\xFE\x003\xFE\0E\xFE\0I\xFE\0S\xFE\0T\xFE\0X\xFE\0Y\xFE\0b\xFE\0c\xFE\0d\xFE\0h\xFE\0i\xFE\0j\xFE\0l\xFE\0\x01\xFF\0\x04\xFF\0\x05\xFF\0\x0B\xFF\0\x0C\xFF\0\x10\xFF\0\x1A\xFF\0\x1C\xFF\0\x1F\xFF\0!\xFF\0;\xFF\0>\xFF\0?\xFF\0@\xFF\0[\xFF\0\\\xFF\0]\xFF\0^\xFF\0") }, 127u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0 \0\" \0& \0' \x002 \x004 \0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \0\x14 \0\x15 \0\x19 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0_\0\0`\0\0\xA7\0\0\xA8\0\0\xB6\0\0\xB7\0\0\x10 \0\x12 \0\x14 \0\x17 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0% \0' \x000 \x001 \x002 \x004 \0; \0< \0> \0? \0\x010\0\x040\0\x080\0\x120\0\x140\0\x160\0\x1C0\0\x1D0\0\xFB0\0\xFC0\0\x01\xFF\0\x04\xFF\0\x05\xFF\0\x0B\xFF\0\x0C\xFF\0\x10\xFF\0\x1A\xFF\0\x1C\xFF\0\x1F\xFF\0!\xFF\0;\xFF\0>\xFF\0?\xFF\0@\xFF\0[\xFF\0\\\xFF\0]\xFF\0^\xFF\0a\xFF\0f\xFF\0") }, 85u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0#\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\xFB\x10\0\xFC\x10\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0 \0\" \0& \0' \x002 \x004 \0\x16!\0\x17!\0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0-\0\x000\0\0:\0\0;\0\0@\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x0C\x06\0\r\x06\0\x1B\x06\0\x1C\x06\0\x1F\x06\0 \x06\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0(\0\0*\0\0,\0\0/\0\0?\0\0@\0\0[\0\0^\0\0\xD4\x17\0\xD7\x17\0\xD9\x17\0\xDB\x17\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0_\0\0`\0\0\xA1\0\0\xA2\0\0\xA7\0\0\xA8\0\0\xB6\0\0\xB8\0\0\xBF\0\0\xC0\0\0\x10 \0\x12 \0\x14 \0\x16 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0% \0' \x000 \x001 \x002 \x004 \0; \0< \0> \0? \0\x010\0\x040\0\x080\0\x120\0\x140\0\x160\0\x1C0\0\x1D0\0\xFB0\0\xFC0\0\x01\xFF\0\x04\xFF\0\x05\xFF\0\x0B\xFF\0\x0C\xFF\0\x10\xFF\0\x1A\xFF\0\x1C\xFF\0\x1F\xFF\0!\xFF\0;\xFF\0>\xFF\0?\xFF\0@\xFF\0[\xFF\0\\\xFF\0]\xFF\0^\xFF\0") }, 82u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \0\x14 \0\x15 \0\x19 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 24u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \0") }, 19u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1B \0\x1C \0\x1F \0 \0\" \0& \0' \x002 \x004 \0") }, 34u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0_\0\0a\0\0|\0\0}\0\0~\0\0\x7F\0\0\xA7\0\0\xA8\0\0\x11 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 35u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0'\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 19u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"#\0\0$\0\0(\0\0+\0\0-\0\0.\0\0/\0\x000\0\0@\0\0A\0\0[\0\0^\0\0J\x10\0L\x10\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\0.\0\0;\0\0<\0\0?\0\0@\0\0[\0\0^\0\0d\t\0e\t\0\x11 \0\x12 \0\x14 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 19u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0#\0\0$\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\xBF\0\0\xC0\0\0\x11 \0\x12 \0\x13 \0\x14 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xF7\x07\0\xFA\x07\0") }, 3u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x19 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \0\xC5\"\0\xC6\"\0") }, 31u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \0\xC5\"\0\xC6\"\0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0&\0\0*\0\0,\0\x000\0\0:\0\0<\0\0?\0\0@\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \x002 \x004 \0") }, 25u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0~\0\0\x7F\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xB0\0\0\xB1\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x1D \0\x1F \0 \0\" \0& \0' \x002 \x004 \0") }, 36u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0'\0\0*\0\0/\0\x000\0\0:\0\0<\0\0[\0\0^\0\0\x0C\x06\0\r\x06\0\xD4\x06\0\xD5\x06\0\x18 \0\x19 \0") }, 13u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 32u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0;\0\0?\0\0A\0\0[\0\0^\0\0`\0\0a\0\0|\0\0}\0\0\xA7\0\0\xA8\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x19 \0\x1C \0\x1F \0& \0' \0") }, 27u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b":\0\0;\0\0") }, 1u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\0-\0\0.\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xAB\0\0\xAC\0\0\xB7\0\0\xB8\0\0\xBB\0\0\xBC\0\0\x10 \0\x11 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0(\0\0*\0\0-\0\0.\0\0/\0\x000\0\0:\0\0;\0\0[\0\0\\\0\0]\0\0^\0\0\x0C\x06\0\r\x06\0\x1B\x06\0\x1C\x06\0\x1F\x06\0 \x06\0m\x06\0n\x06\0\x11 \0\x12 \0\x18 \0\x1A \0\x1D \0\x1E \0& \0' \0") }, 18u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0+\0\0,\0\0/\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \0\x13 \0\x14 \0\x1E \0 \0& \0' \0") }, 23u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0~\0\0\x7F\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 33u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0#\0\0$\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x10 \0\x12 \0\x13 \0\x14 \0\x19 \0\x1A \0\x1D \0\x1F \0& \0' \0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0#\0\0$\0\0(\0\0+\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x10 \0\x12 \0\x13 \0\x14 \0\x18 \0\x19 \0\x1A \0\x1B \0\x1C \0\x1D \0\x1E \0\x1F \0& \0' \0") }, 22u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x11 \0\x12 \0") }, 15u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0-\0\0/\0\0:\0\0;\0\0[\0\0\\\0\0]\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x0C\x06\0\r\x06\0\x1B\x06\0\x1C\x06\0\x1F\x06\0 \x06\0\0\x07\0\x0E\x07\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0") }, 38u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 21u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\xBB\0\0\xBC\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x003 \0") }, 32u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0\xE2\x80\xB3\xC2\xAB") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0'\0\0+\0\0,\0\x000\0\0:\0\0;\0\0@\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\x11 \0\x12 \0\x13 \0\x15 \0\x1C \0\x1E \0& \0' \0") }, 25u32) - }, - unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x01\0&,") }, - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\xA7\0\0\xA8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 30u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \09 \0; \0") }, 17u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0\xA7\0\0\xA8\0\0\xAB\0\0\xAC\0\0\xBB\0\0\xBC\0\0\x11 \0\x12 \0\x13 \0\x14 \0\x19 \0\x1A \0\x1C \0\x1D \0\x1E \0\x1F \0\x16!\0\x17!\0") }, 26u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0\"\0\0(\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0\x10 \0\x12 \0") }, 14u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"(\0\0*\0\0.\0\0/\0\0:\0\0;\0\0[\0\0\\\0\0]\0\0^\0\0\x0C\x06\0\x0E\x06\0\x1B\x06\0\x1C\x06\0\x1F\x06\0 \x06\0k\x06\0m\x06\0\xD4\x06\0\xD5\x06\0") }, 13u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\x000\0\0:\0\0<\0\0=\0\0>\0\0?\0\0A\0\0[\0\0^\0\0\xAB\0\0\xAC\0\0\xB7\0\0\xB8\0\0\xBB\0\0\xBC\0\0\x10 \0\x16 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0D \0E \0S \0T \0\x080\0\n0\0") }, 39u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0*\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0\\\0\0]\0\0^\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \x002 \x004 \0") }, 28u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0#\0\0'\0\0*\0\0,\0\0/\0\0:\0\0<\0\0?\0\0@\0\0[\0\0^\0\0p\t\0q\t\0\x11 \0\x12 \0\x18 \0\x1A \0\x1C \0\x1E \0") }, 20u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0&\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0& \0' \x002 \x004 \0") }, 29u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0_\0\0`\0\0\xA7\0\0\xA8\0\0\xB7\0\0\xB8\0\0\x10 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0 \0\" \0% \0( \x000 \x001 \x002 \x004 \x005 \x006 \0; \0< \0> \0? \0\x010\0\x040\0\x080\0\x120\0\x140\0\x160\0\x1D0\0\x1F0\x000\xFE\0E\xFE\0I\xFE\0S\xFE\0T\xFE\0b\xFE\0c\xFE\0d\xFE\0h\xFE\0i\xFE\0j\xFE\0l\xFE\0\x01\xFF\0\x04\xFF\0\x05\xFF\0\x0B\xFF\0\x0C\xFF\0\x10\xFF\0\x1A\xFF\0\x1C\xFF\0\x1F\xFF\0!\xFF\0;\xFF\0>\xFF\0?\xFF\0@\xFF\0[\xFF\0\\\xFF\0]\xFF\0^\xFF\0") }, 130u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0'\0\0(\0\0+\0\0,\0\x000\0\0:\0\0<\0\0?\0\0A\0\0[\0\0^\0\0_\0\0`\0\0\xA7\0\0\xA8\0\0\xB7\0\0\xB8\0\0\x10 \0\x12 \0\x13 \0\x17 \0\x18 \0\x1A \0\x1C \0\x1E \0% \0' \x000 \x001 \x002 \x004 \x005 \x006 \0; \0< \0\x010\0\x040\0\x080\0\x120\0\x140\0\x180\0\x1D0\0\x1F0\x000\xFE\x002\xFE\x003\xFE\0E\xFE\0I\xFE\0S\xFE\0T\xFE\0X\xFE\0Y\xFE\0b\xFE\0c\xFE\0d\xFE\0h\xFE\0i\xFE\0j\xFE\0l\xFE\0\x01\xFF\0\x04\xFF\0\x05\xFF\0\x0B\xFF\0\x0C\xFF\0\x10\xFF\0\x1A\xFF\0\x1C\xFF\0\x1F\xFF\0!\xFF\0;\xFF\0>\xFF\0?\xFF\0@\xFF\0[\xFF\0\\\xFF\0]\xFF\0^\xFF\0") }, 128u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - icu::locale::provider::ExemplarCharactersData(icu::collections::codepointinvliststringlist::CodePointInversionListAndStringList::from_parts_unchecked( - unsafe { - #[allow(unused_unsafe)] - icu::collections::codepointinvlist::CodePointInversionList::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"!\0\0$\0\0%\0\0/\0\0:\0\0A\0\0[\0\0_\0\0`\0\0a\0\0|\0\0}\0\0~\0\0\x7F\0\0\xB7\0\0\xB8\0\0\x11 \0\x12 \0\x13 \0\x15 \0\x18 \0\x1A \0\x1C \0\x1E \0& \0' \0\x010\0\x030\0\n0\0\x0E0\0\x100\0\x120\0\x01\xFF\0\x02\xFF\0\x08\xFF\0\n\xFF\0\x0C\xFF\0\r\xFF\0\x1A\xFF\0\x1C\xFF\0\x1F\xFF\0 \xFF\0\\\xFF\0]\xFF\0^\xFF\0_\xFF\0") }, 53u32) - }, - zerovec::vecs::VarZeroVec16::new(), - )), - ]; - unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleExemplarCharactersPunctuationV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleExemplarCharactersPunctuationV1>, icu_provider::DataError> { - let mut metadata = icu_provider::DataResponseMetadata::default(); - let payload = if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_PUNCTUATION_V1, req.id, req.metadata.attributes_prefix_match) { - payload - } else { - const FALLBACKER: icu::locale::fallback::LocaleFallbackerWithConfig<'static> = icu::locale::fallback::LocaleFallbacker::new().for_config(<icu::locale::provider::LocaleExemplarCharactersPunctuationV1 as icu_provider::DataMarker>::INFO.fallback_config); - let mut fallback_iterator = FALLBACKER.fallback_for(req.id.locale.clone()); - loop { - if let Some(payload) = icu_provider::baked::DataStore::get(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_PUNCTUATION_V1, icu_provider::DataIdentifierBorrowed::for_marker_attributes_and_locale(req.id.marker_attributes, fallback_iterator.get()), req.metadata.attributes_prefix_match) { - metadata.locale = Some(fallback_iterator.take()); - break payload; - } - if fallback_iterator.get().is_unknown() { - return Err(icu_provider::DataErrorKind::IdentifierNotFound.with_req(<icu::locale::provider::LocaleExemplarCharactersPunctuationV1 as icu_provider::DataMarker>::INFO, req)); - } - fallback_iterator.step(); - } - }; - Ok(icu_provider::DataResponse { payload, metadata }) - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_exemplar_characters_punctuation_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleExemplarCharactersPunctuationV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BTreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok(icu_provider::baked::DataStore::iter(&Self::DATA_LOCALE_EXEMPLAR_CHARACTERS_PUNCTUATION_V1).collect()) - } - } - }; - ($ provider : ty , DRY) => {}; - ($ provider : ty , DRY , ITER) => { - __impl_locale_exemplar_characters_punctuation_v1!($provider, ITER); - }; -} -#[doc(inline)] -pub use __impl_locale_exemplar_characters_punctuation_v1 as impl_locale_exemplar_characters_punctuation_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_extended_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_extended_v1.rs.data deleted file mode 100644 index b4a83a18a7e7..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_extended_v1.rs.data +++ /dev/null @@ -1,105 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleLikelySubtagsExtendedV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 72738B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_likely_subtags_extended_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_LIKELY_SUBTAGS_EXTENDED_V1: &'static <icu::locale::provider::LocaleLikelySubtagsExtendedV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::locale::provider::LikelySubtagsExtended { - language_script: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"abqLatnarcHatrarcNbatarcPalmbapKraicu\0GlaghakHanthnjHmnglifLimblzzGeormanNkoomeyLatnnanHantpalPhlppi\0Devapi\0Mymrpi\0Sinhpi\0ThaipntCyrlpntLatnstuTaleunrDeva") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"TR\0IQ\0JO\0SY\0IN\0BG\0TW\0LA\0IN\0GE\0GN\0SN\0TW\0CN\0IN\0MM\0LK\0TH\0RU\0TR\0CN\0NP\0") }) - }, - language_region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"abqTR\0hakTW\0lzzGE\0meySN\0nanMO\0nanTW\0pi\0IN\0pi\0LK\0pi\0MM\0pi\0TH\0pntRU\0pntTR\0stuCN\0unrNP\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"LatnHantGeorLatnHantHantDevaSinhMymrThaiCyrlLatnTaleDeva") }) - }, - language: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"aa\0aaaaabaacaadaaeaafaagaahaaiaakaalaanaaoaapaaqaasaataauaawaaxaazab\0abaabbabcabdabeabfabgabhabiablabmabnaboabpabqabrabsabtabuabvabwabxabyabzacaacbacdaceacfachacmacnacpacqacracsactacuacvacwacxacyaczadaadbaddadeadfadgadhadiadjadladnadoadqadradtaduadwadxadyadzae\0aeaaebaecaeeaekaelaemaeqaeraesaeuaewaeyaezafbafdafeafhafiafkafnafoafpafsafuafzagaagbagcagdageagfaggaghagiagjagkaglagmagnagoagqagragsagtaguagvagwagxagyagzahaahbahgahhahiahkahlahmahnahoahpahrahsahtaiaaibaicaidaieaifaigaiiaijaikailaimainaioaipaiqairaitaiwaixaiyajaajgajiajnajwajzakbakcakdakeakfakgakhakiakkaklakoakpakqakraksaktakuakvakwakzalaalcaldalealfalhalialjalkallalmalnaloalpalqalraltalualwalxalyalzamaambamcameamfamgamiamjamkammamnamoampamqamramsamtamuamvamwamxamyamzan\0anaanbancandaneanfanganhanianjankanlanmannanoanpanqanransantanuanvanwanxanyanzaoaaobaocaodaoeaofaogaoiaojaokaolaomaonaoraosaotaoxaozapbapcapdapeapfapgaphapiapjapkaplapmapnapoappaprapsaptapuapvapwapxapyapzaqcaqdaqgaqkaqmaqnaqraqtaqzarcardarearhariarjarkarlarnaroarparqarrarsaruarvarwarxaryarzasaasbascaseasgashasiasjaskaslasnasoasrassasuasvasxasyaszataatbatcatdateatgatiatjatkatlatmatnatoatpatqatratsattatuatvatwatxatyatzauaaucaudaugauhauiaujaukaulaumaunauoaupauqaurautauuauwauyauzav\0avbavdaviavkavlavmavnavoavsavtavuavvawaawbawcaweawgawhawiawkawmawnawoawrawsawtawuawvawwawxawyaxbaxeaxgaxkaxlaxmaxxay\0ayaaybaycaydayeaygayhayiaykaylaynayoaypayqaysaytayuayzazbazdazgazmaznazoaztazzbaababbacbaebafbagbahbajbanbaobapbarbasbaubavbawbaxbaybbabbbbbcbbdbbebbfbbgbbibbjbbkbblbbmbbnbbobbpbbqbbrbbsbbtbbubbvbbwbbxbbybcabcbbcdbcebcfbcgbchbcibcjbckbcmbcnbcobcpbcqbcrbcsbctbcubcvbcwbcybczbdabdbbdcbddbdebdfbdgbdhbdibdjbdkbdlbdmbdnbdobdpbdqbdrbdsbdtbdubdvbdwbdxbdybdzbeabebbecbedbeebefbehbeibejbekbembeobepbeqbesbetbeubevbewbexbeybezbfabfbbfcbfdbfebffbfgbfhbfjbflbfmbfnbfobfpbfqbfsbftbfubfwbfxbfybfzbgabgbbgdbgfbggbgibgjbgnbgobgpbgqbgrbgsbgtbgubgvbgwbgxbgybgzbhabhbbhcbhdbhebhfbhgbhhbhibhjbhlbhmbhnbhpbhqbhrbhsbhtbhubhvbhwbhybhzbi\0biabibbidbiebifbigbikbilbimbinbiobipbiqbirbitbiubivbiwbixbiybizbjabjbbjcbjfbjgbjhbjibjjbjkbjlbjmbjnbjobjpbjrbjsbjtbjubjvbjwbjxbjybjzbkabkcbkdbkfbkgbkhbkibkjbkkbklbkmbknbkobkpbkqbkrbksbktbkubkvbkwbkxbkybkzblablbblcbldbleblfblhblibljblkblmblnblpblqblrblsbltblvblwblxblyblzbm\0bmabmbbmcbmdbmebmfbmgbmhbmibmjbmkbmlbmmbmnbmobmpbmqbmrbmsbmubmvbmwbmxbmzbnabnbbncbndbnebnfbngbnibnjbnkbnmbnnbnobnpbnqbnrbnsbnubnvbnwbnxbnybnzbo\0boabobboebofbohbojbokbolbombonboobopboqborbotboubovbowboxboybozbpabpcbpdbpebpgbphbpibpjbpkbplbpmbpobppbpqbprbpsbptbpubpvbpwbpxbpybpzbqabqbbqcbqdbqfbqgbqibqjbqkbqlbqmbqobqpbqqbqrbqsbqtbqubqvbqwbqxbqzbrabrbbrcbrdbrfbrgbrhbribrjbrkbrlbrmbrnbrobrpbrqbrrbrsbrtbrubrvbrwbrybrzbsabsbbscbsebsfbshbsibsjbskbslbsmbsnbsobspbsqbsrbssbstbsubsvbswbsxbsybtabtcbtdbtebtfbtgbthbtibtjbtmbtnbtobtpbtqbtrbtsbttbtubtvbtwbtxbtybtzbubbucbudbuebufbugbuhbuibujbukbumbunbuobupbuqbusbutbuubuvbuwbuxbuybuzbvabvbbvcbvdbvebvfbvgbvhbvibvjbvkbvmbvnbvobvqbvrbvtbvubvvbvwbvxbvybvzbwabwbbwcbwdbwebwfbwgbwhbwibwjbwkbwlbwmbwobwpbwqbwrbwsbwtbwubwwbwxbwybwzbxabxbbxcbxfbxgbxhbxibxjbxlbxmbxnbxobxpbxqbxsbxubxvbxwbxzbyabybbycbydbyebyfbyhbyibyjbykbylbymbynbypbyrbysbyvbywbyxbyzbzabzbbzcbzdbzebzfbzhbzibzjbzkbzlbzmbznbzobzpbzqbzrbztbzubzvbzwbzxbzybzzcaacabcaccadcaecafcagcahcajcakcalcamcancaocapcaqcarcascavcawcaxcaycazcbbcbccbdcbgcbicbjcbkcblcbncbocbqcbrcbscbtcbucbvcbwcbycccccdcceccgcchccjcclccmccoccpccrcdecdfcdhcdicdjcdmcdncdocdrcdzce\0ceacegcekcencetceycfacfdcfgcfmcgacgccggcgkch\0chbchdchfchgchhchjchkchlchmchnchochpchqchtchwchxchychzciacibcicciecihcimcincipcirciwciycjacjecjhcjicjkcjmcjncjocjpcjscjvcjyckbcklckmcknckockqckrckscktckuckvckxckyckzclaclccleclhclicljclkcllclmclocltcluclwclycmacmecmgcmicmlcmocmrcmscmtcnacnbcnccngcnhcnicnkcnlcnpcnqcnscntcnwcnxco\0coacobcoccodcoecofcogcohcojcokcolcomcoocopcoqcotcoucoxcozcpacpbcpccpgcpicpncpocpscpucpxcpycqdcr\0cracrbcrccrdcrfcrgcrhcricrjcrkcrlcrmcrncrocrqcrscrtcrvcrwcrxcrycrzcsacsbcshcsjcskcsmcsocspcsscstcsvcsycszctactcctdctectgcthctlctmctnctoctpctscttctuctyctzcu\0cuacubcuccuhcuicujcukculcuocupcutcuucuvcuxcuycvgcvncwacwbcwecwgcwtcxhcyacybcyoczhczkczncztdaadacdaddaedagdahdaidajdakdaldamdaodaqdardasdaudavdawdaxdazdbadbbdbddbedbfdbgdbidbjdbldbmdbndbodbpdbqdbtdbudbvdbwdbydccdcrddadddddeddgddiddjddnddoddrddsddwdecdeddeedefdegdehdeideldemdendeqderdesdevdezdgadgbdgcdgddgedggdghdgidgkdgldgndgrdgsdgtdgwdgxdgzdhgdhidhldhmdhndhodhrdhsdhudhvdhwdhxdiadibdicdiddifdigdihdiidijdildindiodipdirdisdiudiwdixdiydizdjadjbdjcdjddjedjfdjidjjdjkdjmdjndjodjrdjudjwdkadkgdkkdkrdksdkxdlgdlmdlndmadmbdmcdmddmedmfdmgdmkdmldmmdmodmrdmsdmudmvdmwdmxdmydnadnddnedngdnidnjdnkdnndnodnrdntdnudnvdnwdnydoadobdocdoedofdohdokdoldondoodopdordosdotdovdowdoxdoydppdrcdredrgdridrldrndrodrqdrsdrtdrudrydshdsidskdsndsodsqdtadtbdtddthdtidtkdtmdtodtpdtrdtsdttdtudtyduadubducduedufdugduhduidukduldumdunduodupduqdurdusduuduvduwduxduyduzdv\0dvadwadwkdwrdwsdwudwwdwydwzdyadybdyddygdyidymdyndyodyrdyudyydz\0dzadzddzedzgdzldzneaaebcebgebkeboebrebuecrecyefaefeefiegaeglegmegoegyehueipeiteivejaekaekeekgekieklekmekoekpekrekyeleelkelmeloeluemaembemeemgemiemmemnempemsemuemwemxemzenaenbencendenfenhenlenmennenoenqenrenvenwenxeotepieraergerherierkerrerserterweseesgeshesiesmessesuesyetbetnetoetretsettetuetxetzeudeveevhevnewoexteyaeyoezaezefaafabfadfaffagfahfaifajfakfalfamfanfapfarfaufaxfayfazfblferffiffmfgrfiafiefiffipfirfitfiwfj\0fkkfkvflaflhflifllflnflrflyfmpfmufnbfngfnifodfoifomfonforfosfpefqsfrcfrdfrkfrmfrofrpfrqfrrfrsfrtfubfudfuefuffuhfuifumfunfuqfurfutfuufuvfuyfvrfwafwegabgacgadgaegafgaggahgaigajgakgalgamgangaogapgaqgargasgatgaugawgaxgaygbagbbgbdgbegbfgbggbhgbigbjgbkgblgbmgbngbpgbqgbrgbsgbugbvgbwgbxgbygbzgccgcdgcfgclgcngcrgctgdbgdcgddgdegdfgdggdhgdigdjgdkgdlgdmgdngdogdqgdrgdtgdugdxgeagebgecgedgefgeggehgeigejgekgelgeqgesgevgewgexgeygezgfkggaggbggdggegggggkgglggtgguggwghaghcgheghkghnghoghrghsghtgiagibgicgidgiegiggihgilgimgingipgiqgirgisgitgixgiygizgjkgjmgjngjrgjugkagkdgkegkngkogkpgkuglbglcgldglhgljglkgllgloglrgluglwgmagmbgmdgmggmhgmlgmmgmngmrgmugmvgmxgmygmzgn\0gnagnbgncgndgnegnggnhgnignjgnkgnlgnmgnngnqgnrgntgnugnwgnzgoagobgocgodgoegofgoggohgoigojgokgolgongoogopgoqgorgosgotgougovgowgoxgoygpagpegpngqagqngqrgragrbgrcgrdgrggrhgrigrjgrmgrqgrrgrsgrtgrugrvgrwgrxgrygrzgslgsngsogspgswgtagtuguagubgucgudguegufguhguigukgulgumgunguogupguqgurgutguuguwguxguzgv\0gvagvcgvegvfgvjgvlgvmgvngvogvpgvrgvsgvygwagwbgwcgwdgwegwfgwggwigwjgwmgwngwrgwtgwugwwgwxgxxgybgydgyegyfgyggyigylgymgyngyogyrgyygyzgzagzigznhaahachadhaehaghahhaihajhakhalhamhanhaohaphaqharhashavhawhaxhayhazhbahbbhbnhbohbuhchhdyhedheghehheihemhgmhgwhhihhrhhyhiahibhidhifhighihhiihijhikhilhiohirhithiwhixhjihkahkehkhhkkhlahlbhldhlthluhmahmbhmdhmfhmjhmmhmnhmphmqhmrhmshmthmuhmvhmwhmyhmzhnahndhnehnghnhhnihnjhnmhnnhnohnsho\0hoahobhochodhoehohhoihojholhomhoohophorhothovhowhoyhpohrahrchrehrkhrmhrohrphrthruhrwhrxhrzhsnhssht\0htihtohtshtuhtxhubhuchudhuehufhughuhhuihukhulhumhuphurhushuthuuhuvhuwhuxhuyhuzhvchvehvkhvnhvvhwahwchwohyahywhz\0iaiianiaribaibbibdibeibgibhiblibmibnibribuibyicaichicridaidbidciddideidiidridsidtiduifaifbifeiffifkifmifuifyigbigeiggigligmignigoigsigwihbihiihpihwiinijcijeijjijnijsik\0ikhikiikkiklikoikpikriktikvikwikxikzilailbilgiliilkilmiloilpiluilvimiimlimnimoimrimsimtimyin\0inbinginhinjinninoinpintio\0ioriouiowipiipoiquiqwireirhiriirkirniruirxiryisaiscisdishisiiskismisnisoistisuitbitditeitiitkitlitmitoitritsittitvitwitxityitziu\0iumivbivviw\0iwkiwmiwoiwsixcixliyaiyoiyxizhizmizrizzjaajabjacjadjaejafjahjajjakjaljamjanjaojaqjasjatjaujaxjayjazjbejbijbjjbkjbmjbnjbojbrjbtjbujbwjctjdajdgjdtjebjeejehjeijekjeljenjerjetjeujgbjgejgkjgojhiji\0jiajibjicjidjiejigjiljimjitjiujivjiyjjejjrjkajkmjkojkujlejmajmbjmcjmdjmijmljmnjmrjmsjmwjmxjnajndjngjnijnjjnljnsjobjodjogjorjowjpajprjqrjrajrbjrrjrtjrujuajubjudjuhjuijukjuljumjunjuojupjurjutjuujuwjuyjvdjvnjw\0jwijyajyejyykaakabkackadkagkahkaikajkakkamkaokapkaqkavkawkaxkaykbakbbkbckbdkbekbgkbhkbikbjkbkkblkbmkbnkbokbpkbqkbrkbskbtkbukbvkbwkbxkbykbzkcakcbkcckcdkcekcfkcgkchkcikcjkckkclkcmkcnkcokcpkcqkcskctkcukcvkcwkcykczkdakdckddkdekdfkdgkdhkdikdjkdkkdlkdmkdnkdpkdqkdrkdtkdwkdxkdykdzkebkeckedkeekefkegkehkeikekkelkemkenkeokerkesketkeukevkewkexkeykezkfakfbkfckfdkfekffkfgkfhkfikfkkflkfmkfnkfokfpkfqkfrkfskfukfvkfwkfxkfykfzkg\0kgakgbkgekgfkgjkgkkglkgokgqkgrkgskgtkgukgvkgwkgxkgykhakhbkhckhdkhekhfkhgkhhkhjkhlkhnkhokhpkhqkhrkhskhtkhukhvkhwkhxkhykhzki\0kiakibkickidkiekifkigkihkijkilkimkiokipkiqkiskitkiukivkiwkixkiykizkj\0kjakjbkjckjdkjekjgkjhkjikjjkjkkjlkjmkjnkjokjpkjqkjrkjskjtkjukjxkjykjzkkakkbkkckkdkkekkfkkgkkhkkikkjkkkkklkkmkkokkpkkqkkrkkskktkkukkvkkwkkxkkykkzkl\0klaklbklckldkleklfklgklhklikljklkkllklmklnkloklpklqklrklskltkluklvklwklxklyklzkmakmbkmckmdkmekmfkmgkmhkmikmjkmkkmlkmmkmnkmokmpkmqkmskmtkmukmvkmwkmxkmykmzknaknbkndkneknfkniknjknkknlknmknnknoknpknqknrknskntknuknvknwknxknyknzkoakockodkoekofkogkohkoikolkookopkoqkoskotkoukovkowkoykozkpakpckpdkpekpfkpgkphkpikpjkpkkplkpmkpnkpokpqkprkpskptkpukpwkpxkpykpzkqakqbkqckqdkqekqfkqgkqhkqikqjkqkkqlkqmkqnkqokqpkqqkqrkqskqtkqukqvkqwkqxkqykqzkr\0krakrbkrckrdkrekrfkrhkrikrjkrkkrlkrnkrokrpkrrkrskrtkrukrvkrwkrxkrykrzksbkscksdkseksfksgkshksiksjkskkslksmksnksokspksqksrksskstksuksvkswksxkszktaktbktcktdktektfktgkthktiktjktkktlktmktnktoktpktqktskttktuktvktwktxktyktzkubkuckudkuekufkugkuhkuikujkukkulkumkunkuokupkuqkuskutkuukuvkuwkuxkuykuzkv\0kvakvbkvckvdkvekvfkvgkvhkvikvjkvlkvmkvnkvokvpkvqkvrkvtkvvkvwkvxkvykvzkw\0kwakwbkwckwdkwekwfkwgkwhkwikwjkwkkwlkwmkwnkwokwpkwrkwskwtkwukwvkwwkwxkwykwzkxakxbkxckxdkxfkxikxjkxkkxmkxnkxokxpkxqkxrkxtkxwkxxkxykxzkyakybkyckydkyekyfkygkyhkyikyjkykkylkymkynkyokyqkyrkyskytkyukyvkywkyxkyykyzkzakzbkzckzdkzekzfkzikzkkzlkzmkznkzokzpkzrkzskzukzvkzwkzxkzykzzla\0laalablacladlaelaglahlailajlallamlanlaplaqlarlaslaulawlaxlazlbblbelbflbilbjlbllbmlbnlbolbqlbrlbtlbulbvlbwlbxlbylbzlcclcdlcelcflchlcllcmlcplcqlcsldaldblddldgldhldildjldkldlldmldnldoldpldqlealeblecledleeleflehleilejleklellemlenleolepleqlerlesletleulevlewlexleylezlfalfnlg\0lgalgblgglghlgilgklgllgmlgnlgolgqlgrlgtlgulgzlhalhhlhilhmlhnlhslhtlhuli\0lialibliclidlielifliglihliklilliolipliqlirlisliulivliwlixliylizljaljeljiljlljpljwljxlkalkblkclkdlkelkhlkilkjlkllkmlknlkolkrlkslktlkulkyllallbllclldllellfllgllilljllklllllmllnllpllqllullxlmalmblmclmdlmelmflmglmhlmilmjlmklmllmnlmplmqlmrlmulmvlmwlmxlmyln\0lnalnblndlnglnhlnilnjlnllnmlnnlnslnulnwlnzloaloblocloeloglohloilojloklollomlonlooloploqlorloslotloulowloxloylozlpalpelpnlpolpxlqrlralrclrglrilrklrllrmlrnlrolrtlrvlrzlsalsdlselsilsmlsrlssltcltglthltiltnltoltsltulu\0lualucludluelufluhluilujluklullumlunluolupluqlurluslutluuluvluwluyluzlvalvilvklvllvulwalwelwglwhlwllwmlwolwtlwwlxmlyalynlzhlzllznlzzmaamabmadmaemafmagmajmakmammanmaqmasmatmaumavmawmaxmazmbambbmbcmbdmbfmbhmbimbjmbkmblmbmmbnmbombpmbqmbrmbsmbtmbumbvmbwmbxmbymbzmcamcbmccmcdmcemcfmcgmchmcimcjmckmclmcmmcnmcomcpmcqmcrmcsmctmcumcvmcwmcxmcymczmdamdbmdcmddmdemdfmdgmdhmdimdjmdkmdmmdnmdpmdqmdrmdsmdtmdumdvmdwmdxmdymdzmeamebmecmedmeemehmejmekmelmemmenmeomepmeqmermesmetmeumevmewmeymezmfamfbmfcmfdmfemffmfgmfhmfimfjmfkmflmfmmfnmfomfpmfqmfrmftmfumfvmfwmfxmfymfzmg\0mgamgbmgcmgdmgemgfmggmghmgimgjmgkmglmgmmgnmgomgpmgqmgrmgsmgtmgumgvmgwmgymgzmh\0mhbmhcmhdmhemhfmhgmhimhjmhkmhlmhmmhnmhomhpmhqmhsmhtmhumhwmhxmhymhzmiamibmicmidmiemifmigmihmiimijmikmilmimminmiomipmiqmirmitmiumiwmixmiymizmjbmjcmjdmjemjgmjhmjimjjmjkmjlmjmmjnmjqmjrmjsmjtmjumjvmjwmjxmjymjzmkamkbmkcmkemkfmkimkjmkkmklmkmmknmkomkpmkrmksmktmkvmkwmkxmkymkzmlamlbmlcmlemlfmlhmlimljmlkmllmlnmlomlpmlrmlsmlumlvmlwmlxmlzmmammbmmcmmdmmemmfmmgmmhmmimmmmmnmmommpmmqmmrmmtmmummvmmwmmxmmymmzmnamnbmncmndmnemnfmngmnhmnjmnkmnlmnmmnnmnpmnqmnrmnsmnumnvmnwmnxmnymnzmo\0moamocmodmoemogmohmoimojmokmommoomopmoqmormosmotmoumovmowmoxmoymozmpampbmpcmpdmpempgmphmpimpjmpkmplmpmmpnmpomppmpqmprmpsmptmpumpvmpwmpxmpympzmqamqbmqcmqemqfmqgmqhmqimqjmqkmqlmqmmqnmqomqpmqqmqrmqsmqtmqumqvmqwmqxmqymqzmramrbmrcmrdmrfmrgmrhmrjmrkmrlmrmmrnmromrpmrqmrrmrsmrtmrumrvmrwmrxmrymrzmsbmsemsfmsgmshmsimsjmskmslmsmmsnmsomspmsqmssmsumsvmswmsxmsymszmtamtbmtcmtdmtemtfmtgmthmtimtjmtkmtlmtmmtnmtomtpmtqmtrmtsmttmtumtvmtwmtxmtymuamubmucmudmuemugmuhmuimujmukmummuomuqmurmusmutmuumuvmuxmuymuzmvamvdmvemvfmvgmvhmvkmvlmvnmvomvpmvqmvrmvsmvtmvumvvmvwmvxmvymvzmwamwbmwcmwemwfmwgmwhmwimwkmwlmwmmwnmwomwpmwqmwrmwsmwtmwumwvmwwmwzmxamxbmxcmxdmxemxfmxgmxhmximxjmxkmxlmxmmxnmxomxpmxqmxrmxsmxtmxumxvmxwmxxmxymxzmybmycmyemyfmygmyhmyjmykmylmymmypmyrmyumyvmywmyxmyymyzmzamzbmzdmzemzhmzimzjmzkmzlmzmmznmzomzpmzqmzrmztmzumzvmzwmzxmzzna\0naanabnacnaenafnagnajnaknalnamnannaonapnaqnarnasnatnawnaxnaynaznb\0nbanbbnbcnbdnbenbhnbinbjnbknbmnbnnbonbpnbqnbrnbtnbunbvnbwnbyncancbnccncdncencfncgnchncincjncknclncmncnnconcqncrnctncuncxncznd\0ndandbndcnddndfndgndhndindjndkndlndmndnndpndqndrndtndundvndwndxndyndzneanebnecnedneenegnehneinejneknemnenneoneqnernetneunewnexneyneznfanfdnflnfrnfung\0ngangbngcngdngenggnghngingjngknglngmngnngpngqngrngsngtngungvngwngxngyngznhanhbnhcnhdnhenhfnhgnhinhknhmnhnnhonhpnhqnhrnhtnhunhvnhwnhxnhynhznianibnidnienifnignihniinijnilnimninnioniqnirnisnitniunivniwnixniyniznjanjbnjdnjhnjinjjnjlnjmnjnnjonjrnjsnjtnjunjxnjynjznkankbnkcnkdnkenkfnkgnkhnkinkjnkknkmnknnkonkqnkrnksnktnkunkvnkwnkxnkznlanlcnlenlgnlinljnlknlmnlonlqnlunlvnlwnlxnlynlznmanmbnmcnmdnmenmfnmgnmhnminmjnmknmlnmmnmnnmonmpnmqnmrnmsnmtnmunmvnmwnmxnmznnannbnncnndnnennfnngnnhnninnjnnknnlnnmnnnnnpnnqnnrnntnnunnvnnwnnynnznoanocnodnoenofnognohnoinojnoknonnopnoqnosnotnounovnownoynpbnpgnphnplnpnnponpsnpunpxnpynqgnqknqlnqmnqnnqqnqtnqynr\0nranrbnrenrfnrgnrinrknrlnrmnrnnrpnrunrxnrznsansbnscnsdnsensfnsgnshnsknsmnsnnsqnssnstnsunsvnswnsxnsynszntdntgntintjntkntmntontpntrntuntxntyntznuanucnudnuenufnugnuhnuinujnuknumnunnuonupnuqnurnusnutnuunuvnuwnuxnuynuznv\0nvhnvmnvonwbnwcnwenwgnwinwmnwonwrnwwnwxnxanxdnxenxgnxinxknxlnxnnxonxqnxrnxxny\0nybnycnydnyenyfnygnyhnyinyjnyknylnymnynnyonypnyqnyrnysnytnyunyvnywnyxnyynzanzbnzdnzinzknzmnzrnzunzynzzoaaoacoaroavobiobkoblobmoboobrobtobuocaocoocuodaodkodtoduofsofuogbogcoggogooguohtohuoiaoieoinoj\0ojbojcojsojvojwokaokbokcokdokeokgokiokkokmokookroksokuokvokxokzolaoldoleolkolmoloolroltoluomaombomcomgomiomkomlomoompomromtomuomwomxonaoneongonionjonkonnonoonponronsontonuonxoodoonooropaopkopmopooptopyoraorcoreorgornoroorrorsortoruorvorworxorzos\0osaoscosiosoospostosuosxotaotbotdoteotiotkotlotmotnotqotrotsottotuotwotxotyotzouboueouioumovdowiowloyboydoymoyyozmpabpacpadpaepafpagpahpaipakpalpampaopappaqparpaspaupavpawpaxpaypazpbbpbcpbepbfpbgpbhpbipblpbmpbnpbopbppbrpbspbtpbvpbypcapcbpccpcdpcepcfpcgpchpcipcjpckpcnpcppcwpdapdcpdnpdopdtpdupeapebpedpeepegpeipekpelpempeopeppeqpevpexpeypezpfapfepflpgapgdpggpgipgkpglpgnpgspguphdphgphhphkphlphmphnphophrphtphuphvphwpi\0piapibpicpidpifpigpihpijpilpimpinpiopippirpispitpiupivpiwpixpiypizpjtpkapkbpkgpkhpknpkopkppkrpkuplaplbplcpldpleplgplhplkpllplnploplrplspluplvplwplzpmapmbpmdpmepmfpmhpmipmjpmlpmmpmnpmopmqpmrpmtpmwpmxpmypmzpnapncpndpnepngpnhpnipnjpnkpnlpnmpnnpnopnppnqpnrpnspntpnvpnwpnypnzpocpoepofpogpohpoipokpomponpoopoppoqpospotpovpowpoyppeppippkpplppmppnppopppppqppspptpqapqmprcprdpreprfprgprhpriprkprmproprqprrprtpruprwprxpsapsepshpsipsmpsnpsqpsspstpsupswptapthptiptnptoptpptrpttptuptvpuapubpucpudpuepufpugpuipujpumpuopuppuqpurputpuupuwpuxpuypwapwbpwgpwmpwnpwopwrpwwpxmpyepympynpyupyxpyypzepzhpznquaqubqucqudqufqugquiqukqulqumqunqupquqqurqusquvquwquxquyqvaqvcqveqvhqviqvjqvlqvmqvnqvoqvpqvsqvwqvzqwaqwcqwhqwmqwsqwtqxaqxcqxhqxlqxnqxoqxpqxqqxrqxtqxuqxwqyaqypraarabracradrafragrahrairakramranraoraprarravrawraxrayrazrbbrbkrblrbprcfrdbrearebreeregreirejrelremrenresretreyrgargnrgrrgsrgurhgrhpriarifrilrimrinrirritriurjgrjirjsrkarkbrkhrkirkmrktrkwrmarmbrmcrmdrmermfrmgrmhrmirmkrmlrmmrmnrmormprmqrmtrmurmwrmxrmzrn\0rndrngrnlrnnrnrrnwrobrocrodroerofrogrolromrooroprorrourowrpnrptrrirrmrrorrtrskrswrtcrthrtmrtwrubrucruerufrugruirukruorupruqrutruuruyruzrwarwkrwlrwmrworwrrxdrxwryusaasabsacsadsaesafsajsaksamsaosaqsarsassausavsawsaxsaysazsbasbbsbcsbdsbesbgsbhsbisbjsbksblsbmsbnsbosbpsbqsbrsbssbtsbusbvsbwsbxsbysbzscbscescfscgschsciscksclscoscpscssctscuscvscwscxsdasdbsdcsdesdfsdgsdhsdjsdksdnsdosdqsdrsdssdusdxse\0seasebsecsedseesefsegsehseisejsekselsenseosepseqsersessetseusevsewseysezsfesfmsfwsg\0sgasgbsgcsgdsgesghsgisgjsgmsgpsgrsgssgtsgusgwsgysgzshashbshcshdsheshgshhshishjshkshmshoshpshqshrshsshtshushvshwshyshzsiasibsidsiesifsigsihsiisijsiksilsimsipsiqsirsissiusivsiwsixsiysizsjasjbsjcsjdsjesjgsjlsjmsjpsjrsjtsjusjwskaskbskcskdskeskfskgskhskiskjskmsknskoskpskqskrskssktskuskvskwskxskyskzslcsldslgslhslisljsllslmslnslpslrsluslwslxslyslzsm\0smasmbsmcsmfsmgsmhsmjsmksmlsmnsmpsmqsmrsmssmtsmusmwsmxsmysmzsn\0sncsnesnfsngsnisnjsnksnlsnmsnnsnosnpsnqsnrsnssnusnvsnwsnxsnysnzsoasobsocsodsoesogsoisoksolsoosopsoqsorsossousovsowsoxsoysozspbspcspdspespgspispksplspmspnsposppspqsprspssptspvsqasqhsqmsqosqqsqtsqusrasrbsresrfsrgsrhsrisrksrlsrmsrnsrosrqsrrsrssrtsrusrvsrwsrxsrysrzss\0ssbsscssdssessfssgsshssjsslssmssnssossqssssstssussvssxssysszstastbstestfstgsthstistjstkstlstmstnstostpstqstrstssttstustvstwstysuasubsucsuesugsuisujsuksuosuqsursussutsuvsuwsuysuzsvasvbsvcsvesvmsvsswbswfswgswiswjswkswmswoswpswqswrswsswtswuswvswwswxswysxbsxesxnsxrsxssxusxwsyasybsycsyisyksylsymsynsyosyssywsyxszaszbszcszgsznszpszvszwszytaatabtactadtaetaftagtajtaktaltantaotaptaqtartastautavtawtaxtaytaztbatbctbdtbetbftbgtbhtbitbjtbktbltbmtbntbotbptbstbttbutbvtbwtbxtbytbztcatcbtcctcdtcetcftcgtchtcitcktcmtcntcotcptcqtcstcutcwtcxtcytcztdatdbtdctddtdetdgtdhtditdjtdktdltdmtdntdotdqtdrtdstdttdvtdxtdyteatebtectedteetegtehteitektemtenteotepteqtertestetteutevtewtexteyteztfitfntfotfrtfttgatgbtgctgdtgetgftghtgitgjtgntgotgptgqtgstgttgutgvtgwtgxtgytgzthdthethfthhthithkthlthmthpthqthrthsthtthuthvthythztictiftigtihtiitijtiktiltimtintiotiptiqtistittiutivtiwtixtiytjatjgtjitjjtjltjntjotjptjstjutjwtkatkbtkdtketkftkgtkltkptkqtkrtkstkttkutkvtkwtkxtkztl\0tlatlbtlctldtlftlgtlitljtlktlltlmtlntlptlqtlrtlstlttlutlvtlxtlytmatmbtmctmdtmetmftmgtmhtmitmjtmltmmtmntmotmqtmrtmttmutmvtmwtmytmztnatnbtnctndtngtnhtnitnktnltnmtnntnotnptnqtnrtnstnttnvtnwtnxtnytobtoctodtoftogtohtoitojtoktoltomtootoptoqtortostoutovtowtoxtoytoztpatpctpetpftpgtpitpjtpktpltpmtpntpptprtpttputpvtpxtpytpztqbtqltqmtqntqotqptqttqutqwtratrbtrctretrftrgtrhtritrjtrltrmtrntrotrptrqtrrtrstrttrutrvtrwtrxtrytrzts\0tsatsbtsctsdtsgtshtsitsjtsltsptsrtsttsutsvtswtsxtszttbttcttdttettftthttittjttkttlttmttnttottpttrttstttttuttvttwttyttztuatubtuctudtuetuftugtuhtuitujtultumtuntuotuqtustuutuvtuxtuytuztvatvdtvetvitvktvltvmtvntvotvstvttvutvwtvxtwatwbtwdtwetwftwgtwhtwltwmtwntwotwptwqtwrtwttwutwwtwxtwytxatxetxgtxitxjtxmtxntxotxqtxstxttxutxxtxyty\0tyatyetyhtyityjtyltyntyptyrtystyttyutyxtyytyztzhtzjtzltzmtzntzotzxuamuarubaubiublubrubuubyudaudeudgudiudjudludmuduuesufiugaugbugeughugouhauhnuisuivujiukaukgukhukiukkukpukqukuukvukwukyulaulbulculeulfuliulkulmulnuluulwulyumaumbumdumgumiummumnumoumpumrumsunauneunguniunkunmunnunrunuunxunzuonupiupvuraurburcureurfurgurhuriurkurmurnurourpurrurturuurvurwurxuryurzusaushusiuskuspussusuutauteuthutputrutuuumuuruveuvhuvluwauyauzsvaavaevafvagvahvaivajvalvamvanvaovapvarvasvauvavvayvbbvbkve\0vemveovepvervgrvicvidvifvigvilvinvitvivvjkvkavkjvkkvklvkmvknvkovkpvktvkuvkzvlpvlsvmavmbvmcvmdvmevmfvmgvmhvmivmjvmkvmlvmmvmpvmqvmrvmsvmuvmxvmyvmzvnkvnmvnpvo\0vorvotvravrovrsvrtvtovumvunvutvwawa\0waawabwacwadwaewafwagwahwaiwajwalwamwanwapwaqwarwaswatwauwavwawwaxwaywazwbawbbwbewbfwbhwbiwbjwbkwblwbmwbpwbqwbrwbtwbvwbwwcawciwddwdgwdjwdkwdtwduwdywecwedwegwehweiwemweowepwerweswetweuwewwfgwgawgbwggwgiwgowguwgywhawhgwhkwhuwibwicwiewifwigwihwiiwijwikwilwimwinwirwiuwivwiywjawjiwkawkdwkrwkwwkywlawlewlgwlhwliwlmwlowlrwlswluwlvwlwwlxwmawmbwmcwmdwmewmhwmiwmmwmnwmowmswmtwmwwmxwnbwncwndwnewngwniwnkwnmwnnwnownpwnuwnwwnywoawobwocwodwoewofwogwoiwokwomwonwooworwoswowwpcwrbwrgwrhwriwrkwrlwrmwrowrpwrrwrswruwrvwrwwrxwrzwsawsgwsiwskwsrwsswsuwsvwtbwtfwthwtiwtkwtmwtwwuawubwudwulwumwunwurwutwuuwuvwuxwuywwawwbwwowwrwwwwxwwybwyiwymwynwyrwyyxaaxabxagxaixajxakxalxamxanxaoxarxasxatxauxavxawxayxbbxbdxbexbgxbixbjxbmxbnxbpxbrxbwxbyxchxcoxcrxdaxdkxdoxdqxdyxedxegxemxerxesxetxeuxgbxgdxggxgixgmxguxgwxhexhmxhvxiixinxirxisxiyxjbxjtxkaxkbxkcxkdxkexkfxkgxkjxklxknxkpxkqxkrxksxktxkuxkvxkwxkxxkyxkzxlaxlcxldxlyxmaxmbxmcxmdxmfxmgxmhxmjxmmxmnxmoxmpxmqxmrxmtxmuxmvxmwxmxxmyxmzxnaxnbxnixnjxnkxnmxnnxnqxntxnuxnyxnzxocxodxogxoixokxomxonxooxopxorxowxpaxpbxpdxpfxpgxphxpixpjxpkxplxpmxpnxpoxpqxprxptxpvxpwxpxxpzxraxrbxrdxrexrgxrixrmxrnxrrxruxrwxsaxsbxsdxsexshxsixsmxsnxspxsqxsrxsuxsyxtaxtbxtcxtdxtexthxtixtjxtlxtmxtnxtpxtqxtsxttxtuxtvxtwxtyxubxudxujxulxumxunxuoxutxuuxvexvixvnxvoxvsxwaxwdxwexwjxwkxwlxwoxwrxwtxwwxxbxxkxxmxxrxxtxyaxybxyjxykxylxytxyyxzhxzpyaayabyacyadyaeyafyagyahyaiyajyakyalyamyanyaoyapyaqyaryasyatyauyavyawyaxyayyazybaybbybeybhybiybjyblybmybnyboybxybyyclycnycrydaydeydgydkyeayecyeeyeiyejyelyeryesyetyeuyevyeyygaygiyglygmygpygryguygwyhdyi\0yiayigyihyiiyijyilyimyiryisyivykaykgykhykiykkykmykoykrykyylaylbyleylgyliyllylryluylyymbymeymgymkymlymmymnymoympynaynbyndyngynkynlynqynsynuyobyogyoiyokyolyomyonyotyoyyrayrbyreyrkyrmyroyrsyrwyryysdysnyspysryssysyytwytyyuayubyucyudyufyugyuiyujyulyumyunyupyuqyuryutyuwyuxyuzyvayvtywaywgywnywqywrywuywwyxayxgyxlyxmyxuyxyyyryyuzaazabzaczadzaezafzagzahzajzakzamzaozapzaqzarzaszatzauzavzawzaxzayzazzbazbczbezbtzbuzbwzcazchzdjzeazegzehzemzenzgazgbzghzgmzgnzgrzhdzhizhnzhwziazikzilzimzinziwzizzkazkdzkozkpzktzkuzkzzlazljzlmzlnzlqzluzmazmbzmczmdzmezmfzmgzmhzmizmjzmkzmlzmmzmnzmozmpzmqzmrzmszmtzmuzmvzmwzmxzmyzmzznaznezngznkznszoczohzomzoozoqzorzoszpazpbzpczpdzpezpfzpgzphzpizpjzpkzplzpmzpnzpozppzpqzprzpszptzpuzpvzpwzpxzpyzpzzqezrgzrnzrozrpzrszsazsrzsuzteztgztlztmztnztpztqztszttztuztxztyzuhzumzunzuyzwazygzyjzynzypzzazzj") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"LatnET\0LatnNG\0LatnNG\0LatnPG\0LatnPG\0LatnIT\0MlymIN\0LatnPG\0LatnPG\0LatnPG\0LatnPG\0LatnCM\0LatnBR\0ArabDZ\0LatnBR\0LatnUS\0LatnTZ\0GrekGR\0LatnPG\0LatnPG\0LatnID\0LatnID\0CyrlGE\0LatnCI\0LatnCM\0LatnPH\0LatnPH\0LatnCA\0LatnMY\0LatnPG\0ArabTJ\0LatnCI\0RjngID\0LatnNG\0LatnNG\0LatnNG\0LatnPH\0CyrlRU\0LatnGH\0LatnID\0LatnPG\0LatnCI\0ArabBH\0LatnPG\0LatnPH\0LatnPG\0LatnID\0LatnCO\0LatnNG\0LatnGH\0LatnID\0LatnLC\0LatnUG\0ArabIQ\0LatnCN\0LatnNG\0ArabYE\0LatnGT\0LatnBR\0LatnNL\0LatnEC\0LatnUS\0ArabSA\0ArabOM\0LatnCY\0LatnSD\0LatnGH\0LatnTL\0LatnCM\0LatnTG\0ArabOM\0LatnAU\0LatnUG\0LatnIN\0LatnCI\0LatnIN\0LatnID\0LatnPG\0LatnGH\0LatnID\0LatnAU\0LatnNG\0LatnBR\0TibtCN\0CyrlRU\0LatnPG\0AvstIR\0LatnAU\0ArabTN\0ArabEG\0ArabAF\0LatnNC\0LatnCM\0LatnVN\0ArabPK\0LatnAU\0LatnUS\0LatnCN\0LatnPG\0LatnPG\0LatnPG\0ArabKW\0LatnPG\0LatnNG\0LatnGH\0LatnPG\0LatnPG\0LatnNG\0LatnNG\0LatnPG\0LatnMX\0LatnGH\0LatnID\0LatnPE\0LatnNG\0LatnNG\0LatnPG\0LatnPG\0LatnID\0LatnPG\0LatnCD\0DevaIN\0EthiET\0LatnPH\0LatnPG\0LatnPG\0LatnPH\0LatnPG\0LatnCM\0LatnPE\0LatnCM\0LatnPH\0LatnGT\0LatnPH\0LatnSB\0CyrlRU\0LatnPH\0LatnPH\0LatnGH\0LatnVU\0EthiET\0LatnID\0LatnCI\0LatnMM\0LatnTG\0LatnCI\0LatnNG\0AhomIN\0LatnCI\0DevaIN\0LatnNG\0LatnUS\0LatnSB\0ArabCN\0LatnPG\0LatnAU\0LatnPG\0LatnPG\0LatnAG\0SyrcIQ\0HebrIL\0LatnNG\0LatnPG\0LatnIN\0KanaJP\0MymrIN\0LatnID\0ArabAF\0LatnID\0LatnBR\0LatnET\0LatnPG\0LatnCF\0LatnSS\0LatnBJ\0LatnNC\0LatnAU\0LatnNG\0LatnIN\0LatnID\0LatnID\0LatnNG\0LatnGY\0LatnNG\0LatnID\0LatnPG\0LatnPG\0XsuxIQ\0LatnPH\0LatnSR\0LatnGH\0LatnPG\0LatnVU\0LatnTG\0LatnPG\0LatnCM\0CyrlRU\0LatnCG\0LatnUS\0LatnNG\0LatnCL\0LatnCI\0LatnUS\0LatnNG\0LatnAU\0LatnPG\0LatnPH\0LaooLA\0MlymIN\0LatnVU\0LatnXK\0LatnID\0LatnID\0LatnCA\0CyrlRU\0CyrlRU\0LatnSB\0EthiET\0LatnPG\0LatnAU\0LatnCD\0LatnBR\0LatnNG\0LatnPE\0LatnPE\0LatnET\0LatnAU\0LatnTW\0LatnTD\0LatnID\0LatnPG\0LatnPG\0LatnNG\0LatnPG\0LatnID\0LatnPE\0JpanJP\0LatnPG\0LatnMX\0LatnID\0SyrcSY\0LatnAU\0LatnAU\0LatnAU\0LatnES\0LatnCO\0LatnPE\0LatnNG\0LatnID\0LatnNC\0LatnGH\0LatnGB\0LatnPG\0CyrlRU\0LatnPG\0LatnNG\0LatnMM\0LatnIN\0LatnNG\0LatnCO\0DevaIN\0DevaIN\0DevaIN\0LatnCO\0LatnAU\0EthiET\0LatnCM\0LatnNG\0LatnPG\0LatnCI\0LatnPG\0LatnST\0LatnPG\0LatnVE\0LatnPG\0LatnPG\0LatnPG\0LatnPG\0LatnAU\0LatnPG\0LatnNC\0LatnID\0LatnPG\0LatnPG\0LatnVU\0LatnID\0BengBD\0LatnGY\0LatnID\0LatnSB\0ArabSY\0ArabSD\0LatnPG\0LatnPH\0LatnID\0DevaNP\0LatnBR\0LatnUS\0LatnUS\0LatnUS\0LatnUS\0LatnBR\0LatnPG\0LatnVU\0LatnPG\0LatnPG\0LatnIN\0LatnBR\0LatnBR\0LatnUS\0LatnID\0LatnBR\0LatnPG\0CyrlRU\0LatnML\0LatnNG\0LatnNG\0LatnID\0LatnPH\0LatnNC\0LatnPY\0LatnBR\0ArmiIR\0LatnAU\0LatnAU\0LatnCO\0LatnUS\0LatnBR\0LatnBR\0LatnPE\0LatnCL\0LatnBO\0LatnUS\0ArabDZ\0LatnBR\0ArabSA\0LatnBR\0LatnET\0LatnSR\0LatnBR\0ArabMA\0ArabEG\0LatnTZ\0LatnCA\0LatnID\0SgnwUS\0LatnNG\0LatnPE\0LatnID\0LatnCM\0ArabAF\0LatnID\0LatnBR\0LatnPG\0DevaIN\0LatnCM\0LatnBR\0LatnCD\0LatnPG\0LatnID\0LatnID\0LatnPG\0LatnCN\0LatnPE\0LatnPH\0LatnPG\0LatnNG\0LatnCI\0LatnCA\0LatnPH\0LatnPH\0LatnPH\0ArabIR\0LatnCM\0LatnPH\0LatnID\0LatnBR\0LatnUS\0LatnPH\0LatnSS\0CyrlRU\0LatnUS\0LatnBR\0LatnVU\0LatnPH\0LatnSB\0LatnEC\0LatnSB\0LatnBJ\0LatnZM\0LatnPG\0ArabLY\0LatnPG\0LatnVU\0LatnNG\0LatnPG\0LatnNG\0LatnPG\0LatnID\0LatnPG\0LatnPF\0LatnID\0LatnID\0LatnPG\0ArabUZ\0CyrlRU\0LatnPG\0ArabIR\0LatnCI\0Latn001ArabEG\0LatnAU\0LatnGH\0LatnBR\0LatnPE\0LatnPG\0LatnSS\0LatnBR\0DevaIN\0LatnPG\0LatnNG\0LatnBR\0LatnAU\0LatnID\0LatnPG\0LatnAU\0LatnPG\0EthiET\0LatnNG\0LatnID\0LatnID\0LatnBR\0LatnID\0LatnID\0LatnPG\0LatnPG\0LatnID\0LatnAR\0LatnAU\0LatnBR\0LatnCF\0LatnAU\0ArmnAM\0LatnNC\0LatnBO\0LatnPG\0LatnBJ\0LatnPE\0LatnAU\0LatnNG\0LatnTG\0ArabYE\0LatnNG\0LatnNG\0ArabLY\0ArabYE\0LatnPY\0ArabIQ\0LatnPG\0LatnPH\0LatnPH\0LatnNG\0LatnID\0ArabIR\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnCM\0LatnPH\0LatnMX\0LatnSB\0LatnGW\0LatnID\0LatnVE\0LatnCM\0LatnCM\0LatnBS\0LatnID\0LatnID\0LatnCO\0DevaNP\0LatnAT\0LatnCM\0LatnNG\0LatnCM\0LatnCM\0BamuCM\0LatnID\0LatnBJ\0LatnPG\0LatnID\0LatnPG\0LatnCD\0LatnPG\0LatnGA\0LatnCM\0LatnCM\0LatnCM\0GeorGE\0LatnCD\0LatnPG\0LatnBF\0LatnCF\0LatnCM\0LatnPG\0LatnNG\0LatnNG\0LatnNG\0LatnPG\0LatnCM\0LatnCM\0LatnCM\0LatnCN\0LatnSN\0LatnID\0LatnCM\0LatnPG\0LatnGN\0LatnPG\0LatnCI\0LatnAU\0LatnAU\0LatnPG\0LatnNG\0LatnPG\0LatnCD\0EthiET\0LatnCA\0LatnNG\0LatnCD\0LatnPG\0LatnNG\0LatnCM\0LatnNG\0LatnSN\0LatnSN\0LatnID\0LatnCO\0LatnPG\0LatnNG\0LatnPG\0LatnMY\0LatnSS\0LatnSD\0LatnSS\0LatnAZ\0LatnID\0LatnTD\0LatnCM\0LatnTD\0LatnTZ\0LatnVN\0LatnMY\0LatnTZ\0LatnCF\0LatnCM\0OryaIN\0LatnID\0LatnID\0LatnAU\0ArabPK\0LatnCA\0LatnCM\0LatnCM\0LatnID\0DevaIN\0LatnPG\0LatnBJ\0LatnID\0ArabSD\0LatnPG\0LatnZM\0LatnPG\0LatnID\0LatnCG\0LatnTD\0LatnCI\0LatnID\0LatnCI\0LatnID\0LatnSS\0LatnPG\0LatnTZ\0LatnSS\0DevaIN\0LatnCN\0LatnCM\0LatnID\0LatnCF\0LatnID\0LatnPG\0LatnCM\0LatnCF\0LatnCM\0LatnTL\0LatnBF\0LatnCM\0TamlIN\0LatnCN\0ArabPK\0TibtIN\0OryaIN\0LatnPH\0DevaIN\0DevaIN\0LatnNG\0LatnID\0DevaIN\0LatnCM\0LatnIN\0LatnPH\0LatnCM\0ArabPK\0LatnGN\0ArabPK\0DevaIN\0LatnIN\0LatnPH\0LatnSB\0LatnNG\0LatnID\0DevaIN\0GrekTR\0LatnID\0LatnID\0DevaIN\0DevaIN\0LatnID\0DevaIN\0ArabPK\0LatnPG\0LatnPG\0CyrlIL\0DevaIN\0DevaNP\0LatnPG\0ArabOM\0SyrcGE\0LatnID\0LatnID\0LatnMG\0LatnCM\0DevaIN\0DevaIN\0LatnID\0LatnID\0LatnCD\0LatnID\0LatnVU\0LatnAU\0LatnBF\0LatnTD\0LatnPG\0LatnGW\0LatnPG\0LatnPH\0LatnNG\0LatnGH\0LatnNG\0LatnPG\0LatnCD\0LatnPG\0LatnPG\0LatnPG\0LatnIN\0LatnGH\0LatnCM\0DevaIN\0DevaIN\0LatnCD\0LatnCD\0LatnAU\0LatnPG\0SyrcIL\0LatnGW\0LatnPG\0LatnET\0DevaIN\0LatnPG\0LatnPG\0ArabIQ\0LatnID\0LatnCF\0LatnPG\0LatnPG\0LatnBB\0LatnSN\0LatnCM\0LatnTD\0LatnCI\0LatnPH\0LatnAU\0LatnPG\0LatnNG\0LatnCM\0LatnPH\0LatnCD\0LatnCF\0LatnCM\0LatnVU\0LatnCF\0TibtIN\0LatnID\0LatnCM\0LatnID\0LatnCM\0LatnCD\0LatnBR\0LatnID\0LatnPH\0LatnCD\0LatnPH\0LatnNG\0LatnCG\0LatnTL\0LatnNG\0LatnID\0LatnCA\0LatnSB\0LatnCA\0LatnID\0LatnGW\0LatnID\0LatnLR\0LatnCD\0LatnID\0MymrMM\0LatnSS\0LatnPH\0LatnSB\0LatnPG\0LatnCN\0LatnID\0TavtVN\0LatnAO\0LatnPH\0LatnPH\0LatnBJ\0LatnID\0LatnML\0LatnNG\0LatnCD\0LatnPG\0LatnGN\0LatnCF\0LatnSL\0LatnCD\0LatnPG\0LatnTD\0DevaNP\0LatnPG\0LatnCD\0LatnMG\0LatnPG\0LatnCM\0LatnPG\0LatnML\0LatnCO\0LatnNE\0LatnPG\0LatnCM\0LatnCG\0LatnPG\0LatnPG\0LatnID\0LatnMY\0LatnPH\0LatnID\0LatnID\0LatnID\0LatnGQ\0LatnCD\0LatnPH\0LatnVU\0LatnGQ\0LatnTW\0LatnPH\0LatnPG\0LatnID\0LatnVU\0DevaIN\0LatnID\0LatnID\0LatnPG\0LatnCD\0LatnMY\0LatnCM\0TibtCN\0LatnPE\0LatnKE\0LatnCM\0LatnBF\0LatnCD\0LatnPG\0LatnCG\0LatnNG\0LatnNG\0LatnPG\0LatnML\0LatnPG\0LatnPG\0LatnBR\0LatnSS\0LatnTZ\0LatnGH\0LatnPG\0LatnBF\0LatnCF\0LatnML\0LatnVU\0LatnCM\0LatnCF\0LatnPG\0LatnID\0CyrlRU\0LatnPG\0LatnCD\0LatnNC\0LatnAU\0LatnPG\0LatnID\0LatnID\0LatnID\0LatnPH\0LatnPH\0LatnAU\0LatnPG\0LatnID\0LatnPG\0DevaIN\0BengIN\0LatnID\0LatnBJ\0LatnID\0LatnBJ\0LatnCM\0LatnGN\0LatnTG\0ArabIR\0LatnSN\0LatnCF\0LatnPG\0LatnCM\0LatnCM\0LatnNG\0LatnID\0LatnID\0LatnPG\0LatnCM\0LatnCD\0LatnCI\0LatnNG\0LatnNG\0LatnCM\0DevaIN\0KhmrKH\0LatnGY\0DevaNP\0LatnCD\0LatnBO\0ArabPK\0LatnCM\0LatnVU\0ArabSD\0LatnBW\0LatnCD\0LatnCR\0TibtBT\0LatnID\0LatnPG\0LatnSB\0LatnID\0LatnNG\0LatnVN\0LaooLA\0KndaIN\0LatnPG\0LatnPG\0LatnID\0LatnBN\0LatnSN\0LatnCM\0LatnNG\0ArabAF\0LatnCM\0LatnNG\0ArabPK\0LatnNG\0LatnID\0LatnCO\0LatnTD\0LatnGN\0LatnLR\0LatnNG\0LatnCM\0EthiET\0LatnID\0LatnGN\0LatnET\0LatnNG\0LatnMY\0LatnNG\0LatnCM\0BatkID\0LatnNG\0LatnTD\0LatnCI\0LatnMY\0LatnID\0LatnID\0BatkID\0LatnPH\0LatnPH\0LatnPG\0LatnMY\0LatnVU\0LatnID\0LatnNG\0LatnNG\0DevaPK\0LatnPH\0LatnID\0LatnID\0LatnID\0LatnTD\0LatnYT\0LatnTG\0LatnCA\0LatnCD\0LatnID\0LatnCN\0LatnCG\0LatnNG\0LatnPG\0LatnCM\0LatnSL\0LatnPG\0LatnID\0LatnPG\0LatnNG\0LatnPG\0LatnCD\0LatnPG\0LatnGA\0LatnNG\0LatnSL\0LatnNG\0LatnTD\0LatnGQ\0LatnSB\0LatnSB\0LatnID\0LatnTD\0LatnCM\0LatnNG\0LatnSS\0LatnNG\0LatnID\0LatnCM\0LatnPG\0LatnTD\0LatnCF\0LatnAU\0LatnID\0LatnID\0LatnVE\0LatnNG\0LatnCG\0LatnPH\0LatnID\0LatnNC\0LatnFJ\0LatnZM\0LatnPG\0MymrMM\0LatnPG\0LatnMZ\0LatnCM\0LatnVE\0LatnBF\0LatnPG\0LatnCD\0LatnPG\0LatnET\0LatnID\0LatnBF\0LatnNG\0LatnCD\0LatnCM\0LatnGH\0LatnCD\0LatnCN\0LatnBF\0LatnCG\0LatnSB\0LatnSS\0LatnGQ\0LatnPG\0LatnCD\0LatnPG\0LatnAU\0LatnAU\0LatnBF\0CyrlMN\0LatnAU\0LatnNG\0LatnCM\0LatnNG\0LatnCM\0MongCN\0LatnTD\0LatnML\0LatnPG\0LatnPH\0LatnCM\0LatnNG\0LatnID\0LatnPG\0LatnNG\0DevaNP\0LatnCD\0LatnNG\0LatnCN\0LatnID\0LatnAU\0EthiER\0LatnNG\0LatnPG\0LatnNG\0LatnCM\0DevaNP\0LatnPG\0LatnPG\0LatnLR\0LatnID\0LatnMG\0LatnCR\0LatnML\0LatnPG\0LatnPG\0ThaiTH\0LatnBZ\0LatnNI\0LatnID\0LatnCD\0LatnID\0LatnCD\0LatnID\0LatnID\0LatnAU\0Latn001LatnID\0LatnCM\0LatnNG\0LatnML\0LatnNG\0LatnNG\0LatnGT\0LatnHN\0LatnGT\0LatnUS\0LatnSN\0LatnCA\0LatnPY\0LatnPE\0LatnBO\0LatnGT\0LatnMP\0LatnNC\0LatnPG\0LatnBO\0LatnBO\0LatnIN\0LatnVE\0LatnBO\0LatnBO\0LatnBO\0LatnBO\0LatnCA\0LatnBO\0LatnCO\0LatnCO\0LatnCO\0LatnCO\0LatnEC\0LatnBJ\0LatnPH\0LatnMM\0ThaiTH\0LatnNG\0LatnNG\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnCO\0LatnPH\0LatnCO\0LatnPE\0LatnBR\0LatnMZ\0LatnNG\0LatnNG\0LatnGW\0LatnTZ\0LatnMY\0LatnMX\0CakmBD\0LatnSV\0TeluIN\0LatnIN\0DevaIN\0GujrIN\0DevaIN\0DevaNP\0DevaIN\0HansCN\0LatnNG\0BengIN\0CyrlRU\0LatnUS\0LatnPY\0LatnMM\0LatnNG\0LatnNG\0LatnMM\0LatnNG\0LatnNG\0LatnNG\0LatnMM\0LatnPG\0LatnPH\0LatnUG\0TibtBT\0LatnGU\0LatnCO\0LatnMX\0LatnMX\0ArabTM\0LatnUS\0LatnMX\0LatnFM\0LatnUS\0CyrlRU\0LatnUS\0LatnUS\0LatnCA\0LatnMX\0LatnPE\0LatnMZ\0DevaNP\0LatnUS\0LatnMX\0LatnID\0LatnBJ\0LatnUS\0LatnNG\0DevaIN\0LatnIT\0LatnBR\0LatnMX\0LatnNC\0LatnUS\0LatnVE\0ArabKH\0LatnVN\0LatnUS\0CyrlRU\0LatnAO\0ChamVN\0LatnPG\0LatnPE\0LatnCR\0LatnRU\0LatnPG\0HansCN\0ArabIQ\0LatnNG\0LatnHR\0LatnMM\0LatnGH\0LatnTD\0LatnPG\0LatnNC\0CyrlRU\0LatnUS\0LatnTW\0LatnCM\0LatnNG\0LatnGT\0LatnNG\0LatnCA\0LatnMX\0ArabPK\0LatnGH\0LatnMM\0LatnIN\0LatnGH\0LatnUS\0LatnMX\0LatnMM\0LatnPH\0CyrlRU\0LatnMX\0LatnVN\0LatnBF\0SoyoMN\0LatnCO\0LatnID\0LatnVN\0LatnMM\0LatnIT\0LatnZA\0TibtIN\0LatnMM\0LatnVN\0LatnCN\0LatnMM\0LatnPE\0LatnMM\0LatnMX\0HansCN\0LatnCM\0LatnID\0LatnMX\0LatnMM\0LatnGB\0LatnFR\0LatnAU\0LatnMX\0LatnMX\0LatnPE\0LatnCO\0LatnEC\0ThaiTH\0LatnKE\0LatnMX\0LatnMX\0LatnUS\0LatnUS\0LatnCA\0CoptEG\0LatnUS\0LatnPE\0LatnSN\0LatnPE\0LatnMX\0LatnMX\0LatnPE\0LatnPE\0GrekGR\0LatnNR\0LatnGH\0LatnBF\0LatnPH\0LatnPE\0LatnCN\0LatnPE\0LatnCN\0CansCA\0LatnET\0LatnVC\0LatnVU\0LatnUS\0LatnCO\0LatnCA\0CyrlUA\0LatnST\0CansCA\0CansCA\0CansCA\0CansCA\0LatnMX\0LatnUS\0LatnAR\0LatnSC\0LatnAR\0LatnIN\0LatnVN\0LatnCA\0LatnNG\0LatnUS\0LatnMX\0LatnPL\0MymrMM\0LatnMM\0LatnSN\0LatnUS\0LatnMX\0HansCN\0LatnUS\0LatnUS\0LatnMM\0LatnMM\0LatnUS\0LatnMX\0LatnUS\0PaucMM\0LatnMX\0BengBD\0LatnMM\0LatnMX\0LatnUS\0DevaNP\0LatnCO\0LatnMX\0LatnPH\0TamlIN\0LatnMX\0TamlIN\0LatnMX\0CyrlRU\0LatnVN\0LatnCO\0LatnMX\0LatnKE\0LatnCO\0LatnPE\0LatnPA\0LatnBR\0LatnVE\0LatnUS\0LatnMX\0LanaCN\0LatnCM\0LatnMX\0LatnMX\0LatnIN\0LatnMX\0LatnTZ\0LatnMZ\0LatnTZ\0LatnMY\0LatnSN\0LatnNG\0LatnMX\0LatnBO\0LatnPH\0HansCN\0HebrCZ\0LatnMX\0LatnMM\0LatnTD\0LatnPG\0LatnPG\0LatnCM\0LatnGH\0LatnPG\0LatnTD\0LatnSD\0LatnUS\0LatnKE\0LatnNG\0LatnMM\0DevaIN\0CyrlRU\0LatnCI\0LatnTD\0LatnKE\0LatnPH\0LatnAU\0LatnID\0LatnML\0LatnNG\0LatnNG\0LatnID\0LatnID\0LatnML\0LatnNG\0LatnMY\0LatnAU\0LatnNG\0LatnID\0LatnNG\0LatnNG\0LatnCM\0LatnML\0LatnML\0LatnNG\0LatnML\0LatnPG\0ArabIN\0LatnVI\0LatnAU\0LatnSS\0LatnCG\0LatnTL\0LatnPG\0LatnAU\0LatnBJ\0CyrlRU\0LatnAU\0LatnML\0LatnID\0LatnSD\0LatnPG\0LatnLR\0ArabIR\0LatnNG\0ArabPK\0LatnID\0LatnUS\0LatnID\0LatnCA\0LatnCF\0BengIN\0LatnBR\0LatnPG\0LatnCD\0LatnGH\0LatnML\0LatnPH\0LatnBF\0LatnPG\0LatnPG\0LatnNG\0LatnBF\0LatnCF\0ArabSD\0LatnAU\0LatnCA\0LatnBF\0LatnAU\0LatnAU\0LatnPG\0LatnPG\0LatnAU\0DevaNP\0LatnAU\0LatnAO\0GujrIN\0GujrIN\0LatnAU\0LatnTZ\0LatnAU\0LatnNC\0DevaNP\0LatnAU\0LatnPG\0LatnSS\0LatnCI\0LatnSS\0LatnAU\0LatnKE\0LatnMX\0LatnCM\0LatnID\0LatnSD\0LatnSS\0LatnNG\0LatnSS\0LatnNG\0LatnIN\0LatnNA\0LatnSS\0LatnVU\0LatnID\0LatnCD\0LatnAU\0LatnAU\0LatnTD\0LatnAU\0LatnNE\0LatnAU\0LatnAU\0LatnAU\0LatnSR\0LatnML\0LatnAU\0LatnID\0LatnAU\0LatnPG\0LatnAU\0TibtBT\0LatnNG\0LatnID\0LatnMY\0LatnSS\0LatnCM\0CyrlRU\0LatnHR\0LatnIN\0LatnGA\0LatnML\0LatnPG\0LatnAU\0LatnCM\0MedfNG\0LatnMY\0ArabPK\0ArabPK\0LatnCM\0LatnCM\0LatnID\0LatnID\0LatnID\0LatnMY\0LatnAU\0LatnMZ\0LatnID\0LatnID\0LatnPG\0LatnTZ\0CyrlKG\0LatnID\0LatnCI\0LatnID\0LatnBF\0LatnCD\0LatnPG\0LatnID\0MymrMM\0MymrMM\0LatnID\0LatnBR\0LatnPG\0LatnPG\0LatnCN\0LatnTZ\0LatnPG\0LatnNG\0LatnID\0LatnPG\0LatnPG\0LatnCD\0LatnBJ\0LatnSB\0LatnBF\0LatnNG\0LatnZW\0LatnCM\0EthiET\0LatnGH\0LatnMY\0LatnPT\0TibtNP\0LatnMY\0LatnNG\0LatnAU\0LatnID\0LatnMY\0DevaNP\0EthiET\0LatnNL\0LatnTW\0DevaNP\0LatnKE\0LatnTD\0LatnNG\0LatnID\0OryaIN\0LatnML\0LatnCN\0LatnMY\0LatnCA\0LatnAU\0LatnML\0LatnML\0LatnML\0LatnML\0LatnMY\0LatnMY\0LatnML\0LatnML\0LatnML\0DevaNP\0LatnCM\0GujrIN\0LatnPG\0LatnPH\0LatnNC\0LatnKE\0DevaIN\0LatnPG\0LatnPG\0LatnPH\0LatnNL\0LatnID\0LatnPH\0LatnID\0LatnID\0LatnCM\0DevaNP\0LatnCN\0LatnID\0LatnID\0LatnML\0LatnPH\0LatnCM\0ThaaMV\0LatnPG\0LatnNG\0OryaIN\0LatnET\0Latn001LatnAU\0LatnPG\0LatnAU\0DevaNP\0LatnBF\0LatnAU\0LatnAU\0LatnPH\0LatnCI\0LatnML\0LatnAU\0LatnSN\0LatnNG\0LatnBF\0LatnAU\0TibtBT\0LatnNG\0LatnNG\0LatnAU\0LatnTD\0TibtBT\0LatnCD\0LatnAU\0LatnID\0LatnNG\0LatnPH\0LatnCG\0LatnCI\0LatnKE\0GrekGR\0CprtCY\0LatnNG\0LatnCD\0LatnNG\0LatnCI\0LatnIT\0LatnTZ\0LatnNG\0EgypEG\0LatnNG\0LatnID\0LatnPG\0LatnPG\0LatnGW\0LatnNG\0LatnNG\0LatnID\0LatnNG\0LatnBD\0LatnCM\0LatnMZ\0LatnNG\0LatnNG\0KaliMM\0LatnPG\0LatnPG\0LatnNG\0LatnKE\0LatnPG\0LatnNG\0LatnID\0LatnGF\0DevaNP\0LatnPG\0LatnMX\0LatnCM\0LatnPA\0LatnUS\0DevaIN\0LatnID\0LatnFR\0LatnCM\0LatnPG\0LatnKE\0LatnVN\0LatnID\0CyrlRU\0CyrlRU\0LatnPY\0LatnGB\0LatnNG\0LatnID\0LatnPG\0LatnID\0LatnNG\0LatnNG\0LatnPY\0LatnCI\0LatnNG\0TamlIN\0LatnVU\0LatnNG\0LatnPG\0LatnVU\0LatnAU\0LatnCN\0LatnID\0LatnID\0LatnBO\0GonmIN\0ArabIR\0LatnUS\0LatnCI\0LatnUS\0LatnUS\0LatnPH\0LatnNG\0LatnVU\0LatnCM\0LatnPG\0LatnNG\0ItalIT\0LatnNG\0LatnNG\0LatnID\0LatnMX\0CyrlRU\0LatnNG\0CyrlRU\0LatnCM\0LatnES\0LatnUS\0LatnKE\0LatnNG\0LatnNG\0LatnPG\0LatnGQ\0LatnPG\0LatnSB\0LatnPG\0LatnNG\0LatnPG\0LatnPG\0LatnCM\0LatnCM\0LatnNG\0LatnGQ\0LatnSN\0LatnSB\0LatnID\0LatnES\0ArabIR\0ArabIR\0LatnPH\0LatnSS\0LatnPG\0LatnML\0LatnTD\0ArabSD\0LatnNG\0LatnSA\0LatnTZ\0LatnNG\0LatnSE\0LatnPG\0LatnFJ\0LatnNG\0LatnNO\0LatnUS\0LatnID\0LatnNG\0LatnCM\0LatnAU\0LatnCD\0LatnZA\0LatnCM\0DevaIN\0LatnVU\0LatnZA\0LatnTD\0LatnBJ\0LatnPG\0LatnCD\0LatnBJ\0LatnPG\0LatnTW\0LatnGQ\0LatnPG\0LatnUS\0LatnID\0LatnDE\0LatnFR\0LatnFR\0LatnFR\0LatnPG\0LatnDE\0LatnDE\0LatnVU\0ArabCM\0LatnWF\0LatnBJ\0LatnGN\0LatnNE\0LatnTD\0LatnNG\0LatnBR\0LatnNE\0LatnIT\0LatnVU\0LatnCD\0LatnNG\0LatnPG\0LatnSD\0LatnNC\0LatnNA\0LatnTD\0LatnIN\0LatnPH\0LatnVE\0LatnPG\0LatnMD\0LatnPG\0LatnPG\0LatnPG\0LatnID\0LatnTL\0LatnPG\0HansCN\0LatnPG\0LatnPG\0OryaIN\0LatnPG\0GujrIN\0LatnPG\0TeluIN\0LatnPG\0LatnET\0LatnID\0LatnCF\0LatnAU\0LatnAU\0LatnPG\0LatnPG\0LatnCF\0LatnBJ\0LatnID\0OryaIN\0DevaIN\0GujrIN\0DevaIN\0LatnSS\0LatnCF\0LatnCF\0LatnNG\0LatnBJ\0LatnAU\0LatnCF\0LatnAU\0LatnBJ\0LatnNG\0ArabIR\0LatnPG\0LatnAU\0LatnGP\0LatnGD\0LatnPG\0LatnGF\0LatnVE\0OryaIN\0LatnAU\0LatnPG\0LatnNG\0LatnNG\0LatnPH\0LatnAU\0LatnCF\0LatnAU\0LatnTD\0LatnET\0LatnTD\0LatnPG\0CyrlRU\0LatnYE\0LatnPG\0LatnAU\0LatnNG\0DevaIN\0LatnNG\0LatnPG\0LatnLR\0LatnNG\0LatnID\0LatnNG\0LatnCA\0LatnID\0LatnTG\0LatnNG\0LatnNG\0LatnCF\0LatnID\0LatnGA\0LatnNG\0LatnSO\0LatnCD\0EthiET\0LatnPG\0LatnSB\0LatnLR\0LatnAU\0LatnAU\0ArabPK\0LatnAU\0LatnPG\0LatnPG\0LatnCI\0LatnPG\0ArabLY\0LatnGB\0DevaNP\0LatnMM\0LatnSB\0TfngMA\0ArabPK\0LatnPG\0TibtNP\0LatnAU\0LatnNG\0LatnZA\0LatnCM\0LatnCI\0ArabPK\0LatnAU\0LatnKI\0LatnPG\0CyrlRU\0LatnPG\0LatnVN\0LatnVN\0LatnCM\0LatnCA\0LatnCD\0LatnAU\0LatnCM\0ArabPK\0LatnAU\0LatnGH\0LatnAU\0ArabPK\0LatnPG\0LatnPG\0LatnCM\0LatnNG\0LatnAU\0LatnGN\0LatnZA\0LatnNG\0LatnTD\0CyrlRU\0ArabAF\0LatnTD\0ArabIR\0LatnAU\0LatnNG\0LatnLR\0LatnTD\0LatnNG\0LatnAU\0LatnSB\0LatnNG\0LatnPG\0LatnDE\0LatfDE\0LatnCM\0LatnCM\0LatnAU\0LatnPG\0EthiET\0LatnTZ\0LinbGR\0LatnNG\0LatnPY\0LatnBF\0LatnIN\0LatnES\0LatnCM\0LatnNG\0LatnTG\0LatnNG\0LatnAU\0LatnCI\0LatnBW\0LatnAU\0LatnPG\0LatnAU\0LatnMY\0LatnAU\0LatnPG\0LatnPG\0LatnBO\0LatnCF\0LatnCI\0LatnCO\0LatnPG\0LatnCI\0TibtBT\0EthiET\0LatnTZ\0LatnDE\0LatnPG\0DevaIN\0DevaIN\0LatnLR\0DevaIN\0LatnFJ\0LatnID\0LatnID\0LatnID\0LatnNL\0GothUA\0LatnCM\0LatnCI\0LatnTZ\0LatnCD\0LatnTD\0LatnNG\0LatnGH\0LatnPG\0LatnNG\0LatnBR\0LatnTD\0DevaIN\0LatnLR\0GrekGR\0LatnNG\0LatnPG\0LatnNG\0LatnSB\0LatnLR\0LatnMY\0LatnPG\0ArabDZ\0LatnID\0BengIN\0EthiET\0LatnLR\0LatnPG\0LatnPG\0LatnLR\0LatnPG\0LatnSN\0LatnPG\0LatnCF\0LatnPG\0LatnCH\0LatnBR\0LatnAU\0LatnNG\0LatnBR\0LatnCO\0LatnCI\0LatnAU\0LatnAU\0LatnCO\0LatnBO\0LatnET\0LatnUS\0LatnCO\0LatnBR\0LatnCO\0LatnAU\0LatnPY\0LatnGH\0LatnCR\0LatnVE\0LatnBJ\0LatnBF\0LatnKE\0LatnIM\0LatnPY\0LatnBR\0LatnPG\0LatnPG\0LatnBR\0LatnTD\0LatnNG\0LatnAU\0LatnBR\0LatnBR\0DevaNP\0LatnPG\0LatnAU\0LatnCI\0LatnNG\0ArabPK\0LatnET\0LatnTZ\0ArabPK\0LatnNG\0LatnCA\0LatnBW\0LatnAU\0LatnNG\0LatnUG\0ArabAF\0LatnAU\0LatnAU\0LatnGH\0LatnCI\0LatnPG\0LatnAU\0LatnNG\0LatnAU\0LatnCF\0LatnCM\0LatnET\0LatnPA\0LatnGY\0DevaNP\0LatnBO\0LatnAU\0LatnNG\0LatnSD\0ArabIR\0LatnID\0LatnUS\0ArabIR\0LatnID\0LatnET\0LatnGH\0LatnPG\0LatnCA\0LatnIN\0HansCN\0LatnVN\0LatnPG\0LatnTZ\0LatnPG\0LatnID\0LatnTZ\0EthiET\0LatnCA\0LatnCD\0LatnUS\0LatnCA\0LatnTZ\0ArabAF\0LatnCD\0LatnNG\0LatnSD\0HebrIL\0LatnTL\0LatnMX\0EthiET\0LatnTD\0LatnID\0LatnTZ\0LatnCA\0LatnCD\0LatnNA\0LatnPG\0LatnPG\0LatnSN\0LatnPG\0LatnNG\0LatnPE\0LatnUS\0DevaFJ\0LatnNG\0LatnPG\0TakrIN\0LatnCM\0LatnID\0LatnPH\0LatnBW\0LatnBR\0XsuxTR\0LatnVU\0LatnBR\0LatnID\0LatnTZ\0LatnCD\0ArabIN\0LatnPG\0LatnPG\0DevaIN\0LatnVN\0LatnMM\0HluwTR\0LatnCN\0LatnML\0PlrdCN\0LatnVN\0BopoCN\0LatnCN\0LatnCN\0LatnCN\0BopoCN\0LatnIN\0LatnCN\0LatnPG\0LatnID\0LatnVN\0LatnCN\0LatnCN\0LatnCN\0LatnCM\0ArabPK\0DevaIN\0LatnAO\0LatnBW\0LatnCN\0HmnpUS\0HansCN\0LatnPH\0ArabPK\0LatnSR\0LatnPG\0LatnSB\0LatnPG\0DevaIN\0LatnNG\0LatnNG\0ArabOM\0LatnUS\0DevaIN\0LatnAO\0LatnSS\0LatnCD\0LatnUS\0LatnTD\0LatnPG\0LatnID\0HaniCN\0DevaIN\0MymrMM\0LatnIN\0LatnPG\0LatnVN\0LatnID\0LatnCN\0LatnVN\0LatnAU\0SyrcTR\0LatnIN\0LatnPG\0LatnBR\0ArabIR\0HansCN\0ArabOM\0LatnHT\0LatnID\0LatnCO\0LatnTZ\0LatnID\0XsuxTR\0LatnPE\0LatnBW\0LatnID\0LatnMX\0LatnPG\0LatnPE\0LatnCL\0LatnPG\0LatnID\0LatnPG\0LatnCD\0LatnUS\0LatnCA\0LatnMX\0DevaNP\0LatnPE\0LatnMX\0LatnID\0LatnPE\0HebrIL\0CyrlRU\0LatnHT\0LatnMX\0LatnNC\0LatnID\0LatnMX\0LatnCI\0LatnUS\0LatnNG\0LatnCM\0ArmnAM\0LatnNA\0LatnNC\0LatnPG\0LatnPG\0LatnMY\0LatnNG\0LatnAU\0LatnNG\0LatnPH\0LatnVN\0LatnPH\0LatnNG\0LatnNG\0LatnNG\0LatnID\0LatnNG\0LatnBJ\0LatnNG\0LatnCO\0LatnKE\0LatnIN\0LatnNG\0LatnBJ\0LatnNG\0LatnPG\0LatnSS\0LatnNG\0LatnTL\0LatnNG\0LatnPH\0LatnPH\0LatnTG\0LatnVU\0LatnPH\0LatnCG\0LatnPH\0LatnPH\0LatnNG\0LatnNG\0LatnPG\0LatnNG\0LatnPG\0LatnBO\0LatnPG\0Latn001LatnNG\0LatnID\0LatnNG\0LatnID\0LatnAU\0LatnAU\0LatnNG\0LatnNG\0LatnBJ\0LatnNG\0LatnNG\0LatnUS\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnAU\0LatnCA\0LatnNG\0LatnNG\0LatnUG\0LatnTZ\0LatnID\0LatnZM\0LatnAU\0LatnCN\0LatnPH\0LatnMY\0LatnPH\0LatnPH\0LatnID\0LatnNG\0LatnPG\0LatnUS\0LatnPG\0LatnPG\0LatnID\0LatnIT\0LatnSS\0LyciTR\0LatnID\0LatnCO\0LatnUS\0CyrlRU\0LatnCO\0LatnPH\0LatnPG\0LatnPE\0MymrMM\0Latn001EthiET\0LatnPG\0LatnUS\0LatnPG\0LatnPG\0LatnPE\0LatnNG\0LatnID\0LatnID\0LatnNG\0LatnTZ\0LatnBR\0TamlIN\0LatnID\0LatnPH\0LatnPG\0LatnPE\0LatnPH\0LatnNG\0LatnNG\0ArabAF\0LatnID\0LatnTZ\0LatnNG\0LatnHR\0LatnCM\0LatnPH\0LatnID\0LatnBO\0LatnPH\0HebrIT\0CyrlRU\0LatnNG\0LatnBO\0LatnPG\0LatnNG\0LatnPH\0LatnPH\0LatnNG\0LatnID\0LatnPH\0LatnGT\0CansCA\0LatnCN\0LatnPH\0LatnPH\0HebrIL\0LatnPH\0LatnPG\0LatnID\0LatnPG\0LatnMX\0LatnGT\0LatnNG\0LatnCM\0LatnCG\0LatnRU\0LatnNG\0LatnNG\0LatnNG\0LatnBR\0LatnNG\0LatnGT\0ArabGN\0LatnPG\0LatnNG\0LatnMY\0LatnSB\0LatnMY\0LatnID\0LatnJM\0LatnAU\0LatnAU\0LatnID\0LatnNC\0ArabAF\0LatnID\0LatnID\0LatnAU\0LatnNC\0HebrIL\0LatnAU\0LatnID\0LatnPG\0LatnNG\0ArabLY\0Latn001LatnID\0LatnBR\0LatnCM\0LatnAU\0CyrlUA\0TibtIN\0ArabPK\0CyrlRU\0LatnPE\0DevaNP\0LatnVN\0LatnID\0LatnCI\0LatnID\0LatnNG\0LatnNG\0LatnPG\0LatnTD\0LatnCD\0GeorGE\0LatnNG\0LatnCM\0LatnMY\0HebrUA\0LatnCM\0LatnNG\0LatnHN\0LatnNG\0LatnNG\0LatnAU\0LatnPG\0LatnCM\0LatnTZ\0LatnCN\0LatnEC\0LatnCN\0HangKR\0LatnNG\0LatnID\0MymrMM\0LatnPG\0LatnNG\0LatnSD\0LatnPG\0LatnNG\0LatnTZ\0LatnID\0LatnNG\0DevaNP\0LatnMM\0LatnGH\0LatnNG\0LatnPG\0LatnMX\0TakrIN\0ArabPK\0LatnAU\0LatnNG\0LatnET\0DevaIN\0DevaIN\0LatnCD\0LatnCI\0ArabPK\0LatnBO\0LatnML\0HebrPS\0HebrIL\0LatnPE\0LatnVN\0HebrIL\0LatnNG\0LatnNG\0LatnVE\0LatnBR\0LatnNG\0LatnCI\0LatnNG\0LatnAU\0LatnNG\0DevaNP\0LatnSD\0OryaIN\0LatnNG\0LatnBR\0LatnBR\0LatnDK\0LatnNG\0LatnNG\0OryaIN\0LatnID\0LatnSR\0LatnID\0LatnGH\0TibtCN\0HebrIL\0LatnTD\0CyrlUZ\0LatnDZ\0LatnMM\0LatnNG\0LatnMY\0LatnCF\0LatnNG\0LatnNG\0LatnPH\0LatnKE\0LatnML\0CyrlRU\0LatnPE\0LatnBR\0BaliID\0LatnID\0LatnBR\0LatnAU\0LatnBR\0LatnBR\0CyrlRU\0LatnAU\0TibtIN\0LatnCO\0LatnID\0LatnCD\0LatnPG\0LatnTD\0LatnPG\0LatnCF\0LatnSS\0LatnTG\0LatnPG\0LatnET\0LatnGA\0LatnPG\0ArabPK\0LatnID\0LatnPG\0LatnPG\0ArabNE\0LatnNG\0CyrlRU\0LatnPG\0LatnNG\0LatnID\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnGW\0LatnZW\0LatnPG\0LatnCF\0LatnUG\0LatnPG\0LatnSD\0LatnNG\0LatnNG\0LatnPG\0LatnTZ\0LatnCD\0LatnCD\0ArabDZ\0LatnTZ\0LatnAU\0LatnTZ\0LatnAU\0LatnTZ\0LatnPG\0LatnCD\0LatnTG\0LatnUG\0LatnUG\0LatnNC\0LatnNG\0LatnNG\0LatnZW\0LatnNG\0BengIN\0LatnLT\0ThaiTH\0LatnID\0LatnNG\0LatnID\0LatnCM\0LatnGA\0LatnSD\0LatnTZ\0LatnUS\0LatnTG\0LatnSD\0LatnPG\0LatnID\0LatnGT\0LatnCD\0LatnTL\0LatnCM\0LatnUG\0LatnTD\0LatnNG\0CyrlRU\0LatnTG\0MlymIN\0LatnPG\0DevaIN\0TeluIN\0LatnNG\0KndaIN\0DevaIN\0TeluIN\0KndaIN\0TamlIN\0LatnIN\0KndaIN\0MlymIN\0TamlIN\0DevaIN\0LatnCM\0ArabIR\0LatnCM\0LatnCI\0DevaIN\0DevaIN\0DevaIN\0DevaIN\0DevaIN\0LatnIN\0LatnIN\0DevaIN\0DevaIN\0LatnBF\0LatnCD\0LatnCI\0LatnID\0LatnID\0LatnPG\0DevaNP\0LatnBR\0LatnAU\0LatnSD\0LatnID\0LatnID\0LatnAU\0LatnNG\0LatnPG\0LatnID\0LatnID\0LatnID\0TibtNP\0LatnIN\0TaluCN\0LatnID\0LatnID\0LatnID\0ThaiLA\0TibtCN\0LatnID\0LatnNG\0LatnPG\0DevaIN\0BrahIR\0LatnID\0LatnML\0LatnIN\0LatnPG\0MymrIN\0LatnAO\0CyrlRU\0ArabPK\0LatnCD\0LatnCD\0LatnPG\0LatnKE\0LatnTD\0LatnSD\0LatnUS\0LatnCM\0LatnTD\0DevaNP\0LatnID\0LatnPG\0LatnPG\0LatnNG\0CyrlRU\0LatnUS\0DevaNP\0LatnID\0LatnPG\0LatnPG\0LatnTR\0LatnTZ\0LatnPG\0LatnIN\0LatnID\0LatnTZ\0LatnNA\0LatnID\0LatnGT\0LatnID\0LatnPG\0LatnID\0LaooLA\0CyrlRU\0LatnSB\0LatnAZ\0LatnID\0DevaNP\0LatnVN\0LatnAU\0DevaIN\0MymrMM\0LatnUS\0LatnID\0LatnPG\0ThaiTH\0LatnUS\0LatnPG\0LatnPG\0TibtBT\0LatnNG\0LatnID\0LatnPG\0LatnNG\0LatnGN\0TibtIN\0LatnPH\0LanaMM\0LatnTZ\0LatnCM\0LatnSB\0LatnID\0LatnNG\0LatnSD\0LatnAU\0LatnCD\0LatnNG\0LatnNG\0DevaNP\0LatnNG\0LatnID\0LatnCG\0LatnID\0LatnAU\0LatnCA\0LatnGL\0LatnUS\0LatnMX\0LatnCM\0LatnAU\0DevaNP\0LatnTD\0LatnPH\0LatnPG\0LatnID\0ArabIR\0LatnNG\0LatnPH\0LatnPG\0LatnKE\0LatnNG\0LatnPG\0LatnPG\0DevaNP\0LatnPK\0LatnPG\0LatnLR\0LatnVU\0LatnID\0LatnPG\0LatnID\0LatnID\0LatnGH\0LatnAO\0LatnCN\0LatnPH\0LatnCM\0LatnPG\0LatnPG\0LatnPG\0LatnNG\0DevaIN\0LatnPH\0LatnPH\0LatnIN\0LatnPG\0LatnPG\0LatnCM\0LatnET\0LatnPG\0LatnID\0LatnPG\0LatnBR\0LatnCD\0LatnPG\0LatnNG\0ArabIR\0LatnNG\0LatnPH\0LatnID\0LatnPH\0LatnGW\0LatnNG\0LatnGT\0LatnSL\0LatnID\0LatnBR\0DevaIN\0LatnSL\0LatnCM\0LatnMY\0LatnPG\0LatnMY\0LatnBR\0LatnGN\0LatnPG\0LatnNA\0LatnID\0LatnCD\0LatnBF\0LatnPG\0LatnNG\0LatnID\0LatnSS\0LatnNG\0LatnCO\0LatnCG\0CyrlRU\0LatnPG\0LatnUG\0LatnPG\0LatnGA\0LatnFM\0LatnCM\0LatnTD\0LatnNG\0LatnNG\0LatnUS\0LatnPG\0LatnNG\0LatnCO\0LatnID\0LatnLR\0LatnPG\0LatnFM\0LatnGH\0LatnID\0LatnBR\0LatnNG\0LatnCD\0LatnVN\0LatnBR\0LatnTG\0LatnID\0LatnPG\0LatnID\0CyrlRU\0LatnID\0LatnPG\0LatnPG\0CyrlRU\0LatnUG\0LatnPG\0LatnPG\0LatnPG\0SyrcIQ\0LatnPH\0LatnPG\0LatnBF\0LatnTZ\0LatnPG\0LatnPG\0LatnBJ\0LatnPG\0LatnCI\0LatnZM\0LatnLR\0LatnTD\0LatnBR\0LatnMY\0LatnGN\0LatnMY\0LatnZA\0LatnID\0LatnPG\0LatnCM\0EthiET\0LatnZA\0LatnNG\0DevaNP\0LatnUS\0CyrlRU\0LatnTL\0LatnBR\0LatnVU\0LatnNG\0LatnSL\0LatnPH\0CyrlRU\0LatnRU\0LatnLR\0LatnLR\0LatnNG\0KhmrKH\0LatnSS\0LatnNE\0DevaIN\0KhmrKH\0LatnLR\0LatnSN\0LatnAZ\0LatnID\0LatnTZ\0LatnPH\0LatnPG\0LatnPG\0LatnCM\0LatnSB\0LatnDE\0LatnPG\0LatnPG\0LatnUS\0LatnPG\0LatnNG\0LatnPH\0LatnNG\0LatnCF\0LatnNG\0LatnPG\0LatnLR\0LatnBF\0MymrIN\0LatnCD\0MymrMM\0LatnID\0DevaIN\0LatnVN\0EthiET\0LatnNG\0LatnAU\0DevaNP\0LatnCD\0LatnAU\0LatnTD\0LatnID\0LatnCI\0LatnPG\0ArabIR\0LatnPG\0LatnBR\0LatnPG\0PlrdCN\0LatnPH\0LatnID\0LatnID\0LatnCD\0LatnVN\0LatnUS\0LatnBR\0LatnCD\0LatnNA\0LatnNG\0LatnID\0LatnPG\0LatnPG\0LaooLA\0LatnNG\0LatnNG\0LatnBR\0LatnTZ\0LatnID\0LatnNG\0CyrlRU\0LatnER\0LatnPG\0LatnPG\0LatnBR\0LatnGH\0LatnCA\0LatnUS\0LatnID\0LatnCF\0LatnAU\0LatnAU\0LatnCL\0CyrlRU\0CyrlRU\0LatnID\0LatnPG\0LatnID\0LatnMY\0LatnTD\0LatnPG\0LatnID\0LatnTD\0LatnCM\0LatnMM\0LatnCM\0LatnCO\0LatnID\0LatnID\0MymrMM\0LatnID\0MymrMM\0LatnID\0LatnID\0ArabPK\0KaliMM\0LatnID\0LatnGB\0LatnBR\0LatnNG\0LatnCG\0LatnSB\0LatnID\0LatnSB\0LatnTD\0LatnID\0LatnCO\0LatnPG\0LatnCA\0LatnNG\0LatnNA\0LatnNA\0LatnPG\0LatnCI\0LatnID\0LatnCD\0LatnID\0LatnCM\0LatnTD\0LatnSR\0DevaIN\0LatnAO\0LatnAO\0LatnPG\0LatnCI\0LatnET\0LatnBN\0MymrMM\0LatnMY\0LatnTD\0MymrMM\0ThaiTH\0LatnMY\0LatnBR\0ArabPK\0LatnID\0LatnPG\0LatnPG\0LatnPG\0LatnCG\0LatnVN\0LatnPG\0LatnTZ\0LatnPH\0LatnPG\0LatnID\0LatnGH\0LatnCI\0LatnPG\0LatnUS\0LatnMY\0LatnPH\0LatnPH\0LatnUS\0LatnCF\0LatnPH\0LatnID\0LatnTD\0LatnBR\0LatnMY\0LatnID\0KaliMM\0DevaNP\0DevaIN\0LatnPG\0LatnPG\0LatnBR\0LatnBF\0LatnID\0LatnCI\0LatnID\0LatnPG\0LatnID\0LatnMY\0LatnSB\0LatnID\0LatnID\0LatnMW\0LatnGA\0LatnID\0LatnCM\0LatnMY\0LatnID\0LatnID\0LatnBR\0LatnID\0LatnCD\0LatnID\0LatnVA\0LatnPH\0LinaGR\0LatnMX\0HebrIL\0DevaIN\0LatnTZ\0ArabPK\0LatnMW\0LatnUG\0LatnCD\0LatnZM\0LatnNG\0LatnTD\0LatnVN\0LatnGH\0LatnTG\0LatnID\0LatnID\0LatnIN\0LatnPG\0LatnPG\0CyrlRU\0DevaIN\0LatnCM\0TibtIN\0LatnPH\0DevaIN\0LatnLA\0LaooLA\0LatnPG\0DevaNP\0LatnVN\0LatnPG\0LatnPG\0LatnID\0LatnID\0LatnAU\0LatnAU\0LatnID\0LatnID\0LatnID\0LatnID\0LatnAO\0LatnID\0LatnPG\0ThaiCN\0LatnID\0LatnID\0LatnCI\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnCG\0LatnNG\0LatnNG\0LatnNG\0LatnGN\0Latn001LatnNG\0LatnNG\0LatnNG\0LatnCD\0LatnZM\0LatnBO\0LatnCD\0LatnBF\0LatnGH\0LatnZM\0LatnPG\0LatnCD\0LatnPG\0LatnCD\0LatnCM\0LatnSV\0LatnCM\0LepcIN\0LatnPG\0LatnPG\0LatnCD\0LatnPG\0LatnPG\0LatnID\0LatnID\0LatnID\0LatnID\0CyrlRU\0LatnCM\0Latn001LatnUG\0LatnSB\0LatnSB\0LatnUG\0LatnVN\0LatnID\0LatnVU\0LatnSB\0LatnCD\0LatnET\0LatnSS\0LatnGH\0LatnSB\0LatnPG\0LatnSB\0LatnCD\0LatnVN\0LatnID\0LatnCN\0DevaNP\0LatnMY\0SyrcSY\0LatnVU\0LatnCN\0LatnNL\0LatnSL\0LatnPG\0LatnCN\0LatnPG\0LatnCD\0DevaNP\0LatnGH\0LatnPG\0LatnCD\0LatnCA\0LatnID\0LatnGH\0LatnET\0LatnLR\0LisuCN\0LatnSD\0LatnLV\0LatnID\0LatnID\0LatnCF\0LatnCD\0LatnAU\0LatnID\0LatnID\0LatnID\0LatnID\0LatnAU\0LatnAU\0LatnTL\0LatnKE\0LatnVN\0LatnBR\0LatnUG\0TibtBT\0ArabIR\0LatnMY\0LatnPG\0LatnAU\0LatnVU\0LatnKE\0LatnSS\0LatnKE\0LatnUS\0LatnAU\0LatnSS\0LatnNG\0LatnMZ\0LatnGN\0LatnIT\0LatnPG\0LatnPG\0LatnID\0LatnCG\0LatnAU\0LatnMY\0LatnPG\0LatnID\0LatnTD\0LatnVU\0LatnID\0LatnSB\0LatnFJ\0LatnGN\0LatnVU\0LatnAU\0LatnSD\0LatnTD\0LatnID\0LatnPG\0DevaNP\0LatnCD\0LatnID\0LatnIN\0LatnVU\0TeluIN\0LatnCM\0LatnID\0LatnID\0LatnVU\0LatnFJ\0LatnUS\0LatnCM\0LatnID\0LatnCD\0LatnCF\0LatnNA\0LatnID\0LatnHU\0LatnMY\0LatnPG\0LatnAU\0LatnCF\0LatnPG\0LatnVU\0LatnCM\0LatnNG\0LatnAU\0LatnCD\0LatnID\0LatnBF\0LatnPH\0LatnID\0LatnCD\0LatnSS\0LatnCI\0LatnPG\0LatnSL\0LatnCD\0LatnLR\0LatnMW\0LatnCD\0LatnNG\0LatnCD\0LatnCI\0LatnPG\0LatnSS\0LatnUS\0LatnMY\0LatnID\0DevaNP\0LatnZM\0LatnVU\0LatnID\0LatnMM\0PlrdCN\0LatnSS\0LatnSS\0LatnMY\0ArabIR\0LatnAU\0LatnKE\0ArabPK\0ArabIR\0LatnKE\0LatnID\0LatnSD\0LatnID\0LatnVU\0LatnVU\0ArabIR\0HebrIL\0LatnCD\0LatnMM\0LatnUG\0LatnPG\0ArabPK\0HantCN\0LatnLV\0LatnUG\0LatnID\0LatnBR\0LatnKE\0LatnKE\0LatnID\0LatnCD\0LatnCD\0LatnUG\0LatnRU\0LatnZM\0LatnPG\0HansCN\0LatnUS\0LatnCD\0TibtBT\0LatnSS\0LatnAO\0LatnZM\0LatnKE\0LatnGA\0LatnCU\0LatnID\0LatnIN\0LatnUS\0DevaNP\0ArabOM\0LatnCM\0LatnKE\0ArabIR\0LatnTL\0LatnLA\0LatnSB\0LatnCD\0LatnID\0LatnCD\0LatnID\0LatnKE\0LatnVN\0ThaiTH\0ThaiCN\0LatnSS\0LatnID\0LatnVU\0LatnPG\0TibtBT\0LatnZM\0HantCN\0LatnVU\0LatnMM\0LatnTR\0LatnMX\0LatnMX\0LatnID\0LatnNG\0LatnCM\0DevaIN\0LatnMX\0LatnID\0LatnGT\0LatnGM\0LatnMX\0LatnKE\0LatnMX\0LatnMX\0LatnBR\0LatnGH\0LatnID\0LatnMX\0LatnPH\0LatnPH\0LatnBR\0LatnPH\0LatnSG\0LatnPG\0LatnPH\0LatnBR\0LatnPG\0LatnBR\0LatnCG\0LatnCO\0LatnCM\0LatnCO\0LatnPG\0LatnCO\0LatnPH\0LatnPH\0LatnNG\0LatnGN\0LatnPG\0LatnPG\0ArabPK\0LatnMX\0LatnPY\0LatnPE\0LatnPG\0LatnPE\0LatnMX\0LatnPE\0LatnVE\0LatnVE\0LatnPG\0LatnNG\0LatnAO\0LatnCO\0LatnMY\0LatnTD\0LatnMX\0LatnCM\0LatnPG\0LatnPG\0LatnCM\0LatnCM\0LatnCM\0LatnPG\0LatnTD\0LatnCF\0LatnPG\0LatnPG\0LatnNG\0LatnPG\0LatnPG\0LatnCM\0ArabTD\0CyrlRU\0LatnTD\0LatnPH\0LatnCD\0LatnCD\0LatnCD\0LatnCD\0LatnCF\0LatnCD\0LatnCD\0LatnID\0LatnPG\0LatnCG\0LatnCG\0LatnMX\0LatnCG\0EthiET\0EthiET\0LatnBR\0LatnCM\0LatnPG\0LatnAU\0LatnPG\0LatnPG\0LatnMX\0LatnID\0LatnPG\0LatnMY\0LatnAU\0LatnSL\0LatnMY\0LatnAU\0LatnCM\0LatnKE\0LatnTD\0LatnPG\0LatnPG\0LatnLR\0LatnNG\0ArabDZ\0LatnUS\0ArabTH\0LatnID\0LatnCD\0LatnCM\0LatnMU\0LatnCM\0LatnGN\0LatnCM\0ArabCM\0LatnCM\0LatnCM\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnID\0LatnTG\0LatnAU\0LatnPG\0LatnAO\0LatnSN\0LatnPG\0LatnET\0LatnMX\0LatnSS\0LatnMG\0LatgIE\0LatnTD\0LatnSS\0LatnSS\0LatnTD\0LatnID\0LatnCM\0LatnMZ\0LatnNG\0LatnNG\0LatnID\0LatnPG\0LatnTL\0LatnCF\0LatnCM\0DevaNP\0LatnTZ\0LatnZM\0LatnTZ\0LatnPG\0LatnPG\0LatnTZ\0LatnTZ\0LatnTZ\0LatnTZ\0LatnMH\0LatnGA\0LatnMX\0LatnTZ\0LatnMY\0LatnPG\0LatnAU\0LatnUG\0ArabAF\0LatnCM\0LatnPG\0LatnMZ\0LatnIT\0LatnZM\0LatnID\0LatnUS\0LatnID\0LatnVE\0LatnIN\0LatnBW\0LatnMM\0LatnID\0LatnID\0LatnUS\0LatnMX\0LatnCA\0MandIQ\0LatnMX\0LatnCM\0LatnMX\0LatnMX\0LatnMX\0LatnCM\0LatnUS\0LatnMX\0LatnMX\0LatnID\0LatnMX\0LatnMX\0LatnNI\0LatnMX\0LatnMX\0LatnMX\0LatnPG\0LatnMX\0LatnMX\0LatnMX\0LatnTL\0LatnMX\0LatnUS\0LatnTD\0LatnCN\0LatnTZ\0LatnCN\0LatnPG\0LatnPG\0DevaIN\0LatnPG\0LatnPG\0MlymIN\0MlymIN\0LatnNG\0DevaIN\0TeluIN\0MlymIN\0LatnIN\0LatnBD\0LatnUS\0DevaNP\0LatnCI\0DevaIN\0LatnPG\0DevaIN\0LatnNG\0ArabPK\0LatnFM\0LatnCM\0LatnBJ\0ThaiTH\0LatnID\0LatnNG\0LatnPG\0LatnPG\0LatnMX\0LatnNC\0LatnVU\0LatnCG\0LatnPH\0LatnID\0LatnTL\0LatnVU\0LatnCM\0LatnVN\0LatnPG\0ThaiLA\0LatnPG\0LatnID\0LatnTD\0LatnKE\0LatnVU\0LatnSB\0LatnSN\0LatnPG\0LatnCM\0LatnSD\0LatnSB\0LatnVU\0LatnCM\0LatnVU\0LatnPH\0LatnNG\0LatnID\0LatnMX\0LatnCN\0LatnVU\0LatnNG\0LatnVU\0LatnBR\0LatnPG\0LatnVU\0LatnPH\0LatnPG\0LatnPG\0LatnPG\0LatnCN\0LatnPG\0LatnCM\0LatnBR\0LatnVU\0LatnPG\0LatnTD\0LatnCD\0LatnPG\0LatnID\0MongCN\0LatnBR\0LatnTD\0LatnCM\0LatnVN\0LatnCD\0ArabAF\0LatnGM\0LatnVU\0LatnPG\0LatnVN\0LatnCN\0LatnMY\0LatnUS\0CyrlRU\0LatnID\0LatnSB\0MymrMM\0LatnID\0LatnMZ\0LatnID\0LatnRO\0LatnCI\0LatnAR\0LatnUS\0LatnCA\0LatnID\0LatnCA\0LatnNG\0LatnCG\0LatnID\0LatnNI\0LatnVN\0LatnBZ\0LatnID\0LatnSD\0LatnBF\0LatnCO\0LatnTD\0LatnUS\0LatnCG\0LatnPG\0LatnET\0LatnTD\0LatnTZ\0LatnAU\0LatnAU\0LatnBR\0LatnET\0LatnTD\0LatnAU\0LatnCM\0LatnAU\0LatnTD\0LatnPG\0LatnMX\0LatnPG\0LatnPG\0LatnPG\0LatnBR\0LatnSB\0LatnPG\0LatnPG\0LatnBR\0LatnPG\0LatnBR\0LatnPG\0LatnID\0ThaiTH\0LatnID\0LatnCM\0LatnID\0LatnPG\0LatnID\0LatnID\0LatnMX\0LatnID\0LatnID\0LatnPH\0LatnBJ\0LatnPF\0LatnID\0LatnID\0LatnID\0LatnMY\0LatnID\0LatnID\0LatnTH\0LatnSS\0LatnPG\0LatnPG\0LatnID\0LatnID\0LatnPG\0ThaiTH\0LatnVU\0LatnUS\0DevaNP\0LatnID\0LatnIN\0LatnIN\0CyrlRU\0LatnNC\0LatnFM\0LatnVU\0LatnSB\0MrooBD\0LatnVU\0LatnPF\0DevaIN\0LatnVU\0LatnNG\0LatnCM\0LatnPF\0LatnPH\0LatnID\0LatnPH\0LatnID\0LatnPH\0LatnTD\0LatnID\0LatnID\0LatnMG\0LatnMY\0LatnCD\0LatnPH\0LatnID\0LatnPH\0LatnVU\0LatnID\0LatnBR\0LatnNC\0LatnID\0LatnPG\0LatnCM\0LatnGW\0LatnPG\0LatnPG\0LatnPG\0LatnPH\0LatnCI\0LatnPG\0LatnID\0LatnSB\0LatnPG\0LatnID\0LatnID\0LatnPG\0LatnID\0LatnCM\0LatnNG\0CyrlRU\0LatnNI\0LatnMX\0LatnBO\0LatnVN\0DevaIN\0LatnPE\0LatnVU\0LatnMX\0LatnPG\0LatnPH\0LatnMX\0LatnPG\0LatnCM\0LatnTD\0LatnCM\0CyrlRU\0LatnEC\0LatnCM\0LatnSS\0LatnID\0LatnTD\0TibtNP\0LatnPG\0LatnCM\0LatnCN\0LatnSS\0LatnUS\0DevaIN\0LatnKE\0TamlIN\0LatnPG\0LatnCM\0EthiET\0LatnPG\0LatnID\0ArabPK\0MongCN\0LatnMX\0LatnTD\0LatnPG\0LatnAU\0LatnPG\0LatnSB\0LatnID\0LatnPG\0LatnID\0LatnID\0LatnVU\0LatnTD\0LatnMY\0LatnTZ\0LatnID\0ArabPK\0EthiET\0LatnPG\0LatnPG\0LatnPG\0LatnTZ\0LatnAU\0LatnPG\0LatnPG\0LatnVU\0LatnML\0LatnPT\0LatnTD\0LatnZM\0LatnVU\0LatnAU\0LatnMM\0DevaIN\0LatnKE\0MymrMM\0LatnSS\0LatnID\0HmnpUS\0LatnCD\0LatnMX\0LatnMX\0LatnZW\0LatnID\0LatnVU\0LatnCM\0LatnAO\0LatnCD\0LatnES\0LatnIN\0LatnPG\0LatnBJ\0LatnPG\0LatnID\0LatnZM\0LatnMX\0LatnMX\0LatnMY\0LatnMX\0LatnMX\0LatnCM\0LatnMX\0LatnPG\0LatnCI\0LatnMX\0LatnID\0LatnTD\0LatnCD\0LatnGA\0LatnET\0LatnCM\0LatnUS\0LatnSS\0LatnML\0LatnID\0EthiET\0LatnBR\0LatnPE\0LatnBR\0CyrlRU\0LatnPG\0LatnUG\0LatnCO\0MandIR\0LatnMX\0ArabDZ\0LatnCM\0LatnPG\0LatnAR\0LatnMX\0LatnLR\0LatnNG\0LatnMX\0LatnNG\0ArabIR\0LatnBR\0LatnBO\0LatnID\0LatnBR\0LatnMY\0LatnPG\0LatnCF\0LatnGH\0LatnGY\0LatnPG\0LatnNR\0LatnID\0LatnBR\0LatnPG\0LatnID\0LatnPG\0LatnIN\0LatnGN\0LatnPG\0LatnPG\0LatnAU\0HansCN\0DevaNP\0LatnIT\0LatnNA\0LatnNG\0LatnPG\0LatnNG\0LatnGH\0LatnPG\0LatnAU\0LatnMX\0LatnNO\0LatnAO\0LatnNG\0LatnIN\0LatnCD\0LatnIN\0LatnNG\0LatnIN\0LatnAU\0LatnPG\0LatnCF\0LatnID\0LatnNG\0LatnNG\0LatnID\0LatnNG\0LatnIN\0LatnIN\0LatnCM\0LatnCD\0LatnPG\0LatnPG\0LatnIN\0LatnPG\0DevaNP\0LatnPG\0LatnPG\0LatnCA\0LatnMX\0LatnMX\0LatnMX\0LatnAU\0LatnMX\0LatnPG\0LatnPG\0LatnPG\0LaooLA\0LatnCM\0LatnIN\0LatnGH\0LatnMX\0LatnUS\0LatnZW\0LatnCG\0LatnCM\0LatnMZ\0LatnNG\0CyrlRU\0LatnTZ\0LatnTZ\0LatnNG\0LatnTZ\0LatnCD\0LatnCD\0LatnTD\0LatnCG\0LatnUG\0LatnAO\0LatnNG\0LatnCD\0LatnCM\0LatnSN\0LatnCD\0LatnID\0LatnCF\0LatnSS\0LatnID\0LatnCI\0LatnID\0LatnNG\0LatnNC\0CyrlRU\0TibtBT\0XsuxTR\0LatnPG\0LatnNC\0LatnNC\0LatnNC\0LatnVN\0LatnMX\0LatnID\0LatnPG\0Latn001DevaNP\0LatnPG\0LatnCI\0LatnUS\0LatnID\0LatnNG\0LatnSB\0LatnGH\0LatnCM\0LatnNA\0LatnCD\0LatnCD\0LatnCD\0LatnCF\0LatnCM\0LatnCF\0LatnZA\0LatnNG\0LatnCM\0LatnAU\0LatnMZ\0LatnFM\0LatnCM\0LatnTZ\0LatnTZ\0LatnSB\0LatnNG\0LaooLA\0LatnMX\0LatnCM\0LatnNG\0LatnNG\0LatnCM\0LatnCG\0LatnAU\0LatnCI\0LatnMX\0LatnPY\0LatnMX\0LatnAU\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnPG\0LatnMX\0LatnMX\0LatnBW\0LatnMX\0LatnCM\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnID\0LatnPG\0LatnAU\0LatnTD\0LatnPG\0LatnAU\0LatnTZ\0LatnPG\0LatnID\0LatnID\0LatnTZ\0LatnNG\0CyrlRU\0LatnKE\0LatnID\0LatnPG\0TeluIN\0LatnNU\0CyrlRU\0LatnPG\0LatnCD\0LatnCD\0LatnPG\0LatnNG\0LatnIN\0LatnTZ\0LatnIN\0LatnAU\0LatnCM\0LatnSS\0LatnIN\0LatnIN\0LatnIN\0LatnNG\0LatnID\0LatnSR\0LatnAU\0LatnCG\0LatnCM\0LatnIN\0LatnZM\0LatnIN\0LatnCM\0LatnIN\0LatnSB\0LatnIN\0LatnPG\0LatnIN\0LatnIN\0LatnID\0LatnVU\0LatnPG\0LatnAO\0LatnGH\0LatnGH\0LatnFM\0LatnID\0LatnTZ\0LatnCI\0LatnMW\0LatnCD\0LatnNG\0LatnNG\0LatnCM\0LatnID\0LatnKE\0LatnSB\0ArabAF\0LatnCD\0LatnID\0ArabPK\0LatnCD\0LatnMM\0LatnGH\0LatnMX\0LatnAU\0DevaIN\0LatnAU\0LatnSB\0LatnIN\0LatnVU\0LatnTD\0LatnGA\0LatnIN\0LatnIN\0LatnCM\0LatnIN\0LatnNG\0LatnCF\0LatnVU\0LatnCM\0DevaNP\0LatnBW\0LatnIN\0LatnAU\0LatnZW\0LatnCM\0LatnVU\0LatnFM\0LatnUS\0LatnAU\0LatnPG\0LatnPG\0LatnTG\0LatnAU\0LatnCD\0LatnTD\0LatnVU\0LatnAO\0LatnPG\0LatnIN\0LatnCM\0LatnID\0LatnET\0LatnPG\0LatnIN\0LatnPG\0LatnTD\0WchoIN\0LatnTZ\0LatnAU\0LatnUS\0LatnGH\0LatnAU\0LatnBF\0LatnAU\0LatnCM\0LatnCO\0LatnPG\0LanaTH\0DevaIN\0LatnPG\0CyrlRU\0LatnPG\0DevaIN\0LatnCO\0LatnUS\0RunrSE\0LatnPG\0LatnCD\0YiiiCN\0LatnPE\0LatnPG\0Latn001LatnTZ\0LatnTD\0TibtBT\0LatnMM\0LatnIN\0LatnMX\0LatnPG\0LatnIN\0LatnID\0LatnIN\0LatnSB\0LatnID\0LatnBJ\0LatnBJ\0LatnAO\0LatnID\0LatnPG\0LatnMM\0LatnNG\0LatnMM\0LatnZA\0LatnGA\0LatnER\0LatnIN\0LatnJE\0LatnVU\0LatnIN\0LatnAU\0LatnAU\0LatnMY\0RunrGB\0LatnIT\0LatnCN\0LatnAU\0LatnPG\0LatnIN\0LatnZA\0LatnNG\0YiiiCN\0LatnZM\0YiiiCN\0LatnTZ\0LatnCM\0CansCA\0LatnIN\0LatnPG\0LatnUS\0LatnPG\0TnsaIN\0LatnMX\0YiiiCN\0LatnVU\0LatnAO\0LatnID\0LatnUS\0LatnMY\0LatnAU\0LatnBF\0LatnAU\0LatnTZ\0LatnBJ\0LatnCD\0LatnMX\0LatnGH\0LatnSB\0LatnMM\0YiiiVN\0ArabIR\0LatnNC\0LatnBR\0LatnPG\0LatnCF\0LatnCN\0LatnAU\0LatnNG\0LatnGQ\0LatnUG\0LatnCA\0LatnTO\0LatnMM\0LatnVN\0LatnNG\0LatnPG\0LatnPG\0LatnSS\0LatnVN\0LatnCD\0LatnBF\0LatnFM\0LatnPG\0LatnAU\0LatnMX\0LatnUS\0LatnVU\0LatnPG\0LatnCM\0LatnCI\0NewaNP\0LatnCM\0LatnAU\0LatnVU\0LatnSS\0LatnAU\0LatnPG\0LatnTZ\0DevaNP\0LatnTL\0LatnCD\0LatnID\0LatnID\0LatnTZ\0LatnMM\0LatnID\0LatnAU\0LatnGA\0LatnCN\0LatnPG\0LatnID\0LatnMW\0LatnGH\0LatnCD\0LatnKE\0LatnAO\0LatnKE\0LatnCD\0LatnAU\0LatnSD\0LatnCD\0LatnAO\0ThaiTH\0LatnTZ\0LatnUG\0LatnUG\0LatnUG\0ArabIR\0LatnMW\0LatnAU\0LatnAU\0LatnMZ\0LatnAU\0ThaiTH\0LatnAU\0LatnTZ\0LatnCM\0LatnGA\0LatnCD\0LatnGH\0LatnCF\0LatnIN\0LatnNG\0LatnCG\0LatnTD\0LatnML\0CyrlRU\0CyrlRU\0SyrcSY\0GeorGE\0LatnUS\0LatnPH\0LatnCM\0PhnxJO\0LatnPH\0MymrMM\0LatnFR\0LatnNG\0LatnPE\0LatnGB\0LatnMX\0LatnNG\0ArabPK\0LatnNL\0LatnNG\0LatnNL\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0LatnNG\0XsuxTR\0LatnHU\0LatnID\0LatnSS\0LatnPG\0CansCA\0LatnCA\0LatnCA\0CansCA\0LatnSB\0LatnCA\0LatnCA\0LatnNG\0LatnCD\0LatnNG\0LatnNG\0LatnAU\0LatnKE\0LatnPG\0HangKR\0HaniKR\0LatnNG\0LatnNG\0LatnCM\0LatnPG\0LatnNG\0KhmrKH\0DevaNP\0LatnTZ\0TibtBT\0LatnAU\0LatnNG\0LatnRU\0LatnVU\0LatnLT\0LatnAO\0LatnUS\0LatnVU\0LatnPE\0LatnPE\0LatnCD\0CyrlRU\0LatnCD\0LatnPG\0MteiIN\0ModiIN\0LatnKE\0LatnPE\0LatnPG\0MymrMM\0LatnAR\0LatnCA\0LatnPG\0LatnID\0LatnPG\0LatnPG\0LatnPG\0LatnCA\0LatnIN\0LatnPG\0LatnPG\0LatnPG\0LatnVU\0LatnID\0LatnUS\0DevaIN\0LatnZA\0LatnNG\0LatnID\0LatnPG\0LatnPG\0LatnMX\0LatnBR\0LatnSB\0LatnKE\0LatnPE\0LatnNG\0LatnMY\0LatnPG\0LatnNG\0LatnMY\0TeluIN\0ArabPK\0CyrlRU\0LatnBR\0LatnNG\0LatnID\0CyrlGE\0OsgeUS\0ItalIT\0JavaID\0LatnNG\0LatnES\0LatnCM\0LatnPG\0LatnDE\0ArabTR\0TibtCN\0LatnID\0LatnMX\0LatnBR\0OrkhMN\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnSD\0LatnMX\0LatnMX\0LatnBR\0LatnCA\0LatnMX\0GranIN\0LatnMX\0LatnLR\0LatnPG\0OugrCN\0LatnPG\0LatnSE\0LatnPG\0LatnGB\0LaooLA\0LatnET\0LatnBR\0LatnPG\0LatnCM\0LatnBR\0LatnVN\0LatnBR\0LatnCD\0LatnBR\0LatnPH\0LatnBR\0LatnNG\0LatnBR\0PhliIR\0LatnPH\0LatnUS\0LatnCW\0CyrlTJ\0LatnUS\0LatnID\0LatnPW\0LatnBR\0LatnUS\0LatnBR\0LatnHN\0LatnBR\0LatnCO\0LatnGY\0LatnMX\0LatnMX\0LatnVE\0LatnVE\0LatnCM\0LatnNG\0LatnMX\0LatnNG\0LatnGW\0LatnGN\0LatnTZ\0LatnMX\0ArabAF\0LatnIN\0LatnPG\0LatnMX\0KhmrKH\0LatnCN\0LatnFR\0MymrMM\0MlymIN\0MlymIN\0DevaIN\0DevaIN\0TeluIN\0LatnIN\0LatnNG\0LatnBO\0LatnNG\0LatnPG\0LatnUS\0LatnID\0LatnID\0LatnCA\0LatnMM\0LatnID\0LatnUS\0LatnPG\0LatnID\0OryaIN\0LatnMX\0LatnPG\0LatnID\0LatnCD\0XpeoIR\0LatnPG\0LatnUS\0LatnVE\0LatnPG\0LatnID\0LatnMY\0LatnFM\0LatnCM\0LatnDE\0LatnSS\0KharPK\0DevaIN\0LatnPG\0LatnVU\0OgamIE\0ItalIT\0LatnNG\0LatnID\0DevaIN\0LatnVN\0LatnVN\0MymrIN\0ArabPK\0LatnMZ\0PhnxLB\0LaooLA\0ArabPK\0ThaiTH\0ThaiTH\0ArabAF\0DevaNP\0LatnGB\0LatnMX\0LatnPE\0LatnGA\0LatnVE\0LatnFM\0LatnPE\0LatnNF\0LatnCO\0LatnBJ\0LatnUS\0LatnPG\0LatnCO\0LatnNG\0LatnBR\0LatnSB\0LatnAU\0LatnAU\0LatnSB\0LatnTZ\0LatnPG\0LatnNG\0LatnNC\0LatnAU\0BrahIN\0LatnKE\0LatnPG\0LatnBD\0LatnAU\0LatnKE\0LatnCK\0MlymIN\0LatnID\0LatnPG\0LatnVU\0LatnPH\0LatnGB\0LatnID\0LatnAR\0LatnID\0ArabPK\0MymrMM\0LatnCO\0LatnMX\0LatnCI\0LatnMX\0LatnBR\0LatnPH\0LatnPH\0LatnMY\0LatnVU\0LatnCD\0LatnAU\0LatnNC\0LatnID\0BrahIN\0LatnCN\0LatnCN\0LatnTN\0LatnCM\0LatnCM\0LatnID\0LatnMX\0LatnPG\0LatnPF\0LatnUS\0LatnIN\0LatnID\0LatnMX\0LatnMY\0LatnID\0LatnAO\0LatnMY\0LatnNG\0LatnCK\0LatnID\0LatnAU\0LatnBO\0LatnBF\0LatnMY\0LatnPG\0LatnPE\0LatnID\0LatnBF\0LatnPG\0LatnID\0GrekGR\0LatnAU\0LatnAU\0LatnCM\0LatnCF\0LatnGT\0LatnMX\0LatnCD\0LatnBR\0LatnGT\0LatnMX\0LatnBR\0LatnUS\0LatnFM\0LatnUS\0LatnNC\0LatnMX\0LatnMX\0LatnUS\0LatnGW\0LatnMX\0LatnTZ\0LatnPG\0LatnMX\0LatnID\0LatnSV\0LatnID\0LatnPG\0LatnPG\0LatnCD\0LatnPG\0LatnMX\0LatnPG\0LatnNG\0LatnCA\0ArabAF\0ArabIR\0LatnST\0LatnPH\0LatnPL\0LatnPH\0LatnNC\0LatnMM\0LatnPG\0LatnFR\0LatnPE\0LatnBR\0ThaiTH\0LatnID\0LatnPG\0ArabIN\0LatnID\0LatnID\0ArabAF\0ArabAF\0LatnBO\0LatnID\0LatnPG\0LatnPG\0ArabPK\0BrahIN\0LatnVU\0LatnPY\0LatnBR\0LatnAU\0LatnID\0LatnBR\0LatnPG\0LatnVU\0LatnID\0LatnID\0LatnVU\0LatnMX\0LatnIN\0LatnID\0LatnID\0LatnAR\0LatnID\0LatnBF\0LatnCO\0LatnID\0DevaNP\0LatnVN\0LatnPG\0LatnBO\0LatnBR\0LatnID\0LatnGA\0LatnFM\0LatnPG\0LatnUS\0LatnPG\0LatnNG\0LatnPG\0LatnPH\0LatnTW\0MymrMM\0DevaIN\0ThaiTH\0LatnMX\0LatnCI\0LatnNG\0LatnBR\0LatnTW\0MymrMM\0LatnMM\0LatnNG\0LatnTW\0LatnMM\0LatnUS\0LatnPE\0LatnGT\0LatnEC\0LatnPE\0LatnEC\0LatnUS\0LatnPE\0LatnBO\0LatnGT\0LatnUS\0LatnPE\0LatnES\0LatnPE\0LatnAR\0LatnGT\0LatnEC\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnEC\0LatnEC\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnPE\0LatnEC\0LatnPE\0LatnPE\0LatnPE\0LatnHU\0LatnPE\0LatnUS\0LatnPE\0LatnPE\0LatnPE\0LatnEC\0LatnPE\0LatnPE\0LatnPE\0ArabIR\0LatnEC\0LatnPE\0LatnPE\0LatnPE\0Latn001LatnUS\0DevaNP\0DevaNP\0LatnID\0LatnVN\0DevaNP\0LatnKE\0BengIN\0LatnPG\0LatnPG\0LatnBR\0LatnID\0LatnPG\0LatnCL\0LatnCK\0DevaNP\0LatnMM\0LatnNG\0LatnPF\0LatnID\0MymrMM\0LatnPH\0LatnPH\0LatnAU\0LatnRE\0ArabIR\0LatnPG\0LatnID\0LatnMY\0LatnTZ\0OryaIN\0LatnID\0LatnKE\0LatnPE\0LatnVN\0LatnNG\0LatnID\0LatnBO\0LatnVU\0LatnIT\0LatnPE\0LatnVN\0LatnID\0RohgMM\0LatnPG\0LatnIN\0LatnMA\0LatnMM\0LatnTZ\0LatnNG\0LatnID\0LatnAU\0LatnID\0LatnID\0DevaNP\0DevaNP\0KhmrKH\0LatnBR\0LatnCK\0MymrMM\0LatnBF\0BengBD\0LatnAU\0LatnNI\0LatnAU\0LatnSK\0LatnDK\0LatnGB\0LatnFI\0LatnNO\0LatnID\0ArmnAM\0LatnPG\0LatnPL\0LatnID\0LatnRS\0LatnCH\0LatnPG\0LatnES\0ArabIR\0LatnSE\0LatnGB\0LatnVN\0MymrIN\0LatnBI\0LatnCD\0LatnMZ\0LatnIN\0LatnID\0LatnAU\0LatnTZ\0LatnID\0LatnVN\0LatnNG\0LatnPG\0LatnTZ\0LatnVN\0LatnPH\0LatnRO\0LatnPG\0LatnAU\0LatnID\0LatnTD\0LatnID\0LatnVU\0LatnPG\0LatnSB\0LatnNZ\0LatnPG\0LatnAU\0CyrlRS\0LatnNG\0LatnMM\0LatnID\0LatnFJ\0DevaIN\0LatnUG\0LatnUG\0CyrlUA\0LatnTZ\0LatnSB\0LatnTZ\0LatnNG\0LatnHR\0LatnRO\0LatnGR\0CyrlRU\0LatnMY\0LatnNG\0LatnNG\0LatnPG\0LatnTZ\0LatnTZ\0LatnUG\0LatnPG\0DevaIN\0LatnAU\0LatnAU\0KanaJP\0LatnTD\0LatnPA\0LatnUS\0LatnTZ\0LatnBR\0LatnGH\0LatnID\0LatnGA\0SamrPS\0LatnID\0LatnKE\0LatnBO\0LatnID\0LatnID\0LatnSN\0LatnID\0LatnVU\0LatnNG\0SaurIN\0LatnTD\0LatnSB\0LatnPG\0LatnBF\0LatnPG\0LatnID\0LatnPG\0LatnPG\0LatnTD\0LatnTZ\0LatnPH\0LatnTZ\0ArabPK\0LatnMY\0LatnTZ\0LatnPG\0LatnID\0LatnNA\0LatnID\0TibtIN\0LatnIT\0LatnGA\0LatnID\0LatnZM\0LatnCF\0LatnVN\0LatnCN\0LatnPA\0LatnID\0LatnIN\0LatnLK\0DevaIN\0ArabPK\0LatnGB\0DevaNP\0LatnCA\0LaooLA\0TakrIN\0LatnNG\0LatnNG\0GrekIT\0LatnID\0ArabIQ\0LatnIT\0LatnNG\0ArabIQ\0ArabAF\0ArabIR\0LatnCG\0LatnPG\0LatnIT\0LatnMY\0LatnID\0BengBD\0ArabTN\0LatnID\0LatnMY\0LatnNO\0LatnMY\0LatnCI\0LatnCA\0LatnVN\0LatnUS\0LatnCI\0LatnTZ\0LatnMZ\0LatnMX\0LatnPG\0LatnCA\0CyrlRU\0LatnBF\0LatnPG\0LatnBF\0LatnBF\0LatnUS\0LatnML\0LatnID\0LatnID\0LatnCI\0LatnPG\0LatnEC\0LatnMM\0LatnPH\0PlrdCN\0LatnGH\0LatnCF\0LatnIE\0LatnPH\0LatnKE\0LatnPH\0LatnID\0CyrlTJ\0LatnCM\0DevaIN\0LatnKE\0LatnIN\0ArabIR\0LatnLT\0TibtBT\0LatnID\0EthiET\0ArabAF\0LatnPG\0LatnNG\0LatnBR\0LatnCD\0ArabPK\0LatnET\0LatnBW\0LatnUS\0TfngMA\0LatnSD\0LatnSS\0ArabIR\0LatnNG\0LatnPE\0LatnZM\0LatnCD\0LatnCA\0LatnUS\0ArabTD\0ArabOM\0LatnSD\0LatnDZ\0LatnML\0CyrlRU\0LatnMY\0LatnET\0LatnZM\0LatnBF\0LatnGH\0LatnNC\0LatnIN\0LatnPG\0LatnBR\0LatnGH\0LatnPG\0TibtIN\0LatnPG\0LatnNG\0LatnUS\0LatnPG\0LatnPG\0LatnPG\0LatnPG\0ArabIR\0ArabEG\0LatnCO\0LatnID\0HansCN\0CyrlRU\0LatnSE\0LatnTD\0LatnIN\0LatnPH\0DevaIN\0LatnPG\0CyrlRU\0LatnSE\0LatnUS\0LatnUS\0ThaiTH\0LatnPG\0LatnUS\0LatnVU\0LatnBR\0LatnMG\0LatnID\0LatnID\0DevaNP\0LatnPG\0LatnPH\0LatnID\0LatnMY\0LatnBF\0ArabPK\0LatnPG\0LatnCD\0LatnVU\0LatnID\0LatnGY\0LatnID\0LatnSB\0LatnID\0LatnCO\0LatnBF\0LatnID\0LatnUS\0LatnPL\0LatnBR\0LatnPG\0LatnPH\0LatnUS\0LatnID\0LatnCN\0LatnID\0LatnPG\0LatnCD\0LatnID\0LatnID\0LatnWS\0LatnSE\0LatnPG\0LatnPG\0LatnPG\0LatnPG\0YiiiCN\0LatnSE\0LatnPH\0LatnPH\0LatnFI\0SamrIL\0LatnPG\0LatnID\0LatnFI\0LatnIN\0KhmrKH\0LatnID\0LatnCD\0ArabIR\0LatnPG\0LatnZW\0LatnPG\0LatnMY\0LatnSN\0LatnCD\0LatnPE\0LatnCF\0LatnML\0LatnPH\0LatnUG\0LatnCO\0LatnUS\0LatnPG\0LatnGA\0LatnPG\0LatnVU\0LatnID\0LatnMY\0LatnGH\0LatnPG\0LatnPG\0LatnPG\0TavtTH\0LatnID\0LatnCD\0LatnCD\0LatnCD\0SogdUZ\0DevaNP\0LatnTD\0LatnPG\0LatnCD\0LatnCD\0LatnPG\0LatnTD\0LatnBF\0ThaiTH\0LatnPW\0LatnPG\0LatnCM\0LatnBJ\0LatnTZ\0LatnID\0LatnVE\0LatnPG\0LatnPG\0LatnMY\0LatnID\0LatnPG\0LatnPG\0LatnPG\0LatnPY\0LatnUS\0LatnML\0LatnPE\0LatnID\0LatnPG\0TibtIN\0OryaIN\0LatnNG\0LatnNG\0LatnCF\0ArabIR\0LaooLA\0ArabYE\0LatnCA\0LatnPG\0SoraIN\0LatnID\0LatnPG\0LatnPH\0ArabCN\0LatnCO\0LatnMY\0LatnID\0LatnSR\0LatnSR\0LatnIT\0LatnBO\0LatnSN\0LatnCA\0LatnID\0LatnBR\0LatnPH\0LatnID\0DevaIN\0LatnPG\0ArabIR\0LatnZA\0LatnPH\0LatnTZ\0LatnPG\0LatnPH\0LatnTW\0LatnPG\0ArabAE\0LatnPG\0LatnGH\0LatnMY\0LatnKE\0LatnPG\0LatnID\0LaooLA\0LatnPG\0LatnPG\0LatnVU\0LatnPG\0LatnER\0LatnPG\0LatnZM\0LatnPH\0LatnID\0LatnPG\0LatnVN\0LatnIE\0LatnVN\0LatnBF\0LatnPG\0LatnNL\0LatnPG\0LatnSB\0LatnCA\0LatnMX\0LatnDE\0LatnCA\0ArabAF\0LatnVN\0LanaMM\0EthiET\0LatnFM\0CyrlRU\0LatnPG\0LatnCD\0LatnPH\0LatnPG\0LatnPG\0LatnPG\0LatnTZ\0LatnTZ\0LatnPG\0LatnET\0LatnNG\0LatnGN\0LatnNI\0LatnIN\0LatnTZ\0LatnBR\0DevaNP\0GeorGE\0LatnPG\0LatnVC\0LatnID\0LatnIT\0LatnSB\0ArabYT\0LatnCD\0LatnDE\0HaniCN\0LatnGA\0LatnMW\0LatnPG\0LatnBR\0LatnPG\0LatnCM\0LatnID\0LatnID\0LatnID\0LatnID\0DevaIN\0LatnVU\0LatnBR\0LatnTD\0LatnKE\0LatnGA\0LatnID\0LatnTW\0LatnNG\0RunrDE\0LatnBJ\0LatnID\0LatnPH\0SyrcTR\0LatnGA\0LatnNG\0BengBD\0LatnBF\0SyrcIR\0LatnKH\0LatnTD\0DevaNP\0LatnGA\0LatnMY\0LatnID\0LatnMY\0LatnCD\0LatnID\0LatnID\0LatnCM\0LatnID\0LatnTW\0LatnUS\0CyrlRU\0LatnMX\0LatnID\0LatnBR\0LatnBR\0LatnSD\0DevaNP\0LatnNG\0LatnNG\0LatnNG\0LatnTW\0LatnCD\0LatnML\0LatnMX\0LatnVN\0LatnUS\0LatnCO\0LatnPG\0LatnTD\0LatnTW\0LatnSD\0LatnBR\0LatnPG\0LatnPG\0LatnSB\0LatnPG\0LatnPG\0LatnAU\0LatnSD\0LatnPG\0TagbPH\0LatnPH\0LatnCD\0LatnCO\0LatnPG\0LatnID\0LatnPG\0LatnCD\0LatnMX\0LatnPG\0LatnPH\0LatnPG\0LatnID\0LatnBJ\0LatnBR\0LatnUS\0LatnTZ\0LatnGH\0LatnCA\0LatnMX\0LatnID\0LatnTC\0LatnPG\0LatnGA\0LatnID\0DevaNP\0MymrMM\0LatnMM\0LatnID\0LatnAU\0LatnMX\0LatnMX\0TamlIN\0KndaIN\0LatnIN\0TfngNE\0DevaIN\0LatnCO\0TaleCN\0LatnML\0DevaNP\0DevaNP\0LatnID\0LatnID\0LatnNG\0LatnNG\0LatnGY\0LatnID\0LatnNG\0LatnNG\0LatnVN\0LatnID\0LatnTL\0LatnNG\0LatnMG\0LatnPH\0LatnMY\0LatnEC\0LatnKE\0LatnCI\0LatnMX\0LatnGA\0LatnAR\0LatnPG\0LatnCD\0LatnSL\0LatnCO\0LatnUG\0LatnMX\0LatnSD\0LatnBR\0JavaID\0LatnTL\0LatnUG\0LatnID\0LatnUS\0LatnSS\0LatnSD\0LatnNE\0LatnBJ\0LatnUS\0LatnID\0LatnPA\0LatnID\0LatnKE\0LatnMY\0LatnPG\0LatnNG\0DevaNP\0TibtBT\0LatnTT\0LatnPG\0LatnIN\0LatnPH\0LatnPG\0LatnVU\0LatnMY\0LatnVU\0LatnPH\0LatnPG\0LatnBR\0LatnCI\0LatnCA\0LatnSS\0LatnAU\0LatnAU\0DevaNP\0DevaNP\0LatnMX\0TaleLA\0LatnKE\0DevaNP\0ThaiTH\0LatnCA\0DevaNP\0DevaNP\0DevaNP\0LatnCA\0LatnSS\0LatnDZ\0LatnNG\0LatnNE\0LatnSD\0LatnPG\0EthiER\0LatnMY\0LatnCD\0DevaNP\0LatnCM\0LatnUS\0LatnPG\0CyrlRU\0LatnPG\0LatnID\0LatnBF\0LatnPH\0LatnCO\0LatnPH\0LatnNG\0LatnAU\0LatnUS\0LatnPH\0LatnLR\0LatnID\0LatnCN\0LatnAU\0MymrMM\0LatnCI\0ArabDZ\0LatnAU\0LatnCN\0LatnAU\0LatnAU\0LatnBR\0DevaIN\0LatnTL\0LatnMZ\0LatnBR\0LatnMG\0LatnTK\0LatnSB\0LatnNG\0LatnAZ\0ArabIR\0DevaNP\0LatnMX\0LatnPG\0LatnSB\0LatnID\0LatnVN\0LatnPH\0LatnMX\0LatnID\0LatnMX\0LatnID\0LatnPG\0LatnID\0LatnUS\0LatnUG\0LatnID\0LatnCD\0LatnVU\0LatnID\0LatnMX\0LatnMM\0LatnSB\0LatnVU\0LatnID\0LatnID\0LatnID\0LatnPG\0LatnAZ\0LatnTD\0LatnVU\0LatnTD\0LatnPG\0LatnBR\0LatnPY\0LatnID\0LatnNE\0LatnVU\0LatnID\0LatnID\0LatnVN\0LatnID\0LatnMY\0LatnPG\0SyrcIL\0LatnVU\0LatnID\0LatnCD\0LatnMY\0LatnPG\0LatnVE\0LatnBO\0LatnCO\0LatnCO\0LatnCO\0LatnTD\0LatnPG\0LatnID\0LatnVU\0LatnVU\0LatnID\0LatnVU\0LatnBO\0LatnVU\0LatnPR\0LatnSN\0LatnPG\0LatnID\0CakmBD\0LatnID\0LatnSB\0LatnTZ\0LatnAR\0LatnMX\0LatnGN\0LatnPG\0LatnMW\0LatnMZ\0LatnZM\0LatnMX\0Latn001LatnUS\0LatnID\0LatnMX\0LatnMX\0LatnSS\0LatnCD\0LatnMX\0LatnVN\0ArabIR\0LatnUS\0LatnPW\0LatnID\0LatnCM\0LatnPG\0LatnMX\0LatnBD\0LatnID\0LatnID\0LatnPG\0LatnPY\0LatnBR\0LatnMX\0LatnGH\0LatnBR\0LatnMX\0LatnBR\0LatnMX\0KhmrKH\0LatnMP\0LatnMX\0LatnBR\0LatnPG\0LatnBR\0LatnVU\0LatnPG\0LatnUS\0LatnPG\0LatnPG\0LatnMX\0LatnSB\0LatnUS\0ArabAF\0LatnPG\0LatnMX\0LatnID\0LatnTT\0HebrIL\0LatnPG\0LatnSR\0LatnTD\0LatnGB\0ArabAF\0LatnBO\0LatnIN\0LatnIN\0LatnMX\0LatnPE\0LatnMX\0LatnID\0LatnTR\0LatnTW\0ArabPK\0LatnMY\0LatnIN\0LatnBR\0LatnZA\0LatnCG\0LatnET\0LatnMZ\0GrekGR\0LatnPH\0LatnCM\0LatnCA\0TibtBT\0LatnVN\0LatnBF\0LatnVU\0LatnML\0LatnTW\0LatnGA\0LatnNG\0LatnPG\0LatnMX\0LatnNG\0LatnGT\0LatnPG\0LatnPG\0LatnCM\0LaooLA\0LatnID\0LatnUG\0LatnCO\0LatnZM\0LatnCA\0LatnID\0LaooLA\0LatnID\0LatnNG\0ThaiTH\0LatnAZ\0LatnPG\0LatnPG\0LatnMY\0LatnID\0DevaNP\0LatnPG\0LatnUS\0LatnPG\0LatnBR\0LatnCO\0LatnCO\0LatnTD\0LatnPG\0LatnCM\0LatnID\0LatnNG\0LatnMW\0LatnUS\0LatnBR\0LatnTD\0LatnCA\0LatnUS\0LatnKE\0LatnBR\0LatnKE\0LatnBF\0LatnSB\0LatnNG\0LatnID\0LatnNG\0LatnVU\0LatnTV\0LatnID\0MymrMM\0LatnID\0LatnKE\0LatnIN\0LatnCM\0LatnID\0LatnTW\0LatnUS\0LatnPH\0LatnNL\0LatnID\0LatnUS\0LatnID\0LatnVN\0LatnMZ\0TibtIN\0LatnCM\0LatnBW\0LatnPG\0LatnNE\0LatnMX\0LatnBR\0LatnID\0LatnPG\0LatnMZ\0LatnID\0LatnMY\0LatnID\0TangCN\0LatnBR\0LatnNG\0LatnID\0LatnID\0TotoIN\0LatnID\0LatnID\0LatnID\0LatnBR\0LatnMY\0LatnMG\0LatnPF\0LatnPG\0LatnNG\0LatnVN\0LatnCG\0LatnVN\0LatnVN\0LatnID\0LatnAU\0TavtVN\0LatnVN\0LatnVN\0LatnBW\0LatnCG\0LatnNG\0LatnVN\0LatnMX\0LatnGT\0Latn001LatnMA\0LatnID\0LatnMX\0LatnPG\0LatnBR\0LatnPG\0LatnNG\0LatnTD\0LatnPH\0LatnPG\0LatnPG\0LatnTR\0LatnNG\0CyrlRU\0MlymIN\0CyrlRU\0LatnID\0LatnCM\0CyrlRU\0LatnSD\0LatnID\0LatnPG\0UgarSY\0LatnAU\0LatnSB\0CyrlRU\0ThaiTH\0LatnNG\0LatnID\0LatnPG\0LatnCM\0LatnNG\0LatnID\0LatnPG\0LatnCF\0OryaIN\0LatnMM\0LatnNG\0LatnNG\0LatnNG\0LatnSS\0LatnNG\0LatnAU\0LatnNG\0LatnNG\0CyrlRU\0LatnAR\0LatnID\0LatnFM\0LatnAU\0LatnID\0LatnPG\0LatnID\0LatnNI\0LatnNG\0LatnUS\0LatnAO\0LatnAU\0LatnAU\0LatnMY\0LatnNG\0LatnMM\0LatnBR\0LatnAU\0LatnAU\0LatnID\0LatnPG\0LatnNG\0LatnAU\0LatnPG\0LatnBR\0LatnUS\0LatnAU\0BengIN\0LatnPG\0BengIN\0LatnID\0LatnTW\0LatnPG\0LatnVU\0LatnPE\0LatnBR\0LatnAU\0LatnBO\0LatnAU\0LatnPG\0LatnNG\0LatnPG\0ThaiTH\0LatnPG\0LatnID\0LatnPG\0LatnBR\0LatnVU\0LatnPG\0LatnBR\0LatnPG\0LatnPG\0LatnPG\0LatnID\0LatnBR\0LatnPG\0ArabPK\0LatnBD\0LatnCM\0LatnGT\0LatnNG\0LatnPG\0LatnNG\0LatnUS\0LatnNG\0LatnSB\0LatnNG\0LatnPG\0GrekGE\0LatnVU\0LatnNC\0LatnPG\0LatnPG\0LatnAU\0LatnNG\0ArabAF\0TamlIN\0LatnCF\0ArabIR\0LatnGH\0DevaIN\0VaiiLR\0LatnNA\0LatnPG\0LatnPG\0LatnPG\0LatnVU\0LatnIN\0LatnMX\0DevaIN\0LatnCD\0DevaIN\0DevaNP\0LatnID\0LatnPH\0LatnZA\0LatnNG\0LatnUS\0LatnRU\0LatnNG\0ArabPK\0LatnSX\0LatnTZ\0LatnCG\0LatnBF\0LatnAR\0LatnTZ\0LatnNG\0LatnPG\0DevaIN\0LatnAU\0LatnTD\0LatnID\0LatnID\0LatnBR\0LatnNG\0LatnID\0LatnIN\0LatnID\0LatnAU\0LatnNG\0LatnVU\0LatnBE\0LatnAU\0LatnAU\0LatnMX\0KndaIN\0LatnID\0LatnDE\0LatnPG\0ArabIR\0LatnAU\0LatnMX\0LatnMZ\0LatnAU\0LatnMX\0LatnMX\0LatnMX\0LatnMZ\0LatnID\0LatnAU\0LatnMX\0LatnMX\0LatnMX\0LatnSB\0LatnVU\0LatnVU\0Latn001LatnNG\0LatnRU\0LatnVU\0LatnEE\0LatnSB\0LatnVU\0LatnID\0LatnGA\0LatnTZ\0LatnCM\0LatnCN\0LatnBE\0LatnUS\0LatnPG\0LatnUS\0LatnID\0LatnCH\0LatnBR\0LatnPG\0LatnID\0LatnID\0LatnPG\0EthiET\0LatnUS\0LatnCI\0LatnGY\0LatnAU\0LatnPH\0LatnUS\0LatnPG\0LatnBR\0LatnNG\0LatnBR\0LatnPG\0LatnSR\0LatnPG\0LatnVE\0LatnID\0LatnID\0LatnBF\0LatnTZ\0LatnTZ\0LatnTZ\0ArabAF\0LatnPK\0LatnCN\0LatnAU\0TeluIN\0DevaIN\0LatnAU\0LatnAU\0LatnID\0LatnBR\0LatnTG\0LatnGA\0LatnPG\0LatnAU\0LatnAU\0LatnCA\0LatnAU\0LatnAU\0LatnCI\0LatnPG\0LatnAU\0LatnCM\0LatnPG\0LatnBJ\0LatnID\0LatnDE\0LatnPG\0LatnCM\0LatnID\0LatnMM\0LatnID\0LatnID\0LatnAU\0LatnPG\0LatnAU\0LatnPG\0LatnID\0LatnAU\0LatnAU\0LatnID\0LatnPG\0LatnID\0LatnID\0LatnBF\0LatnUS\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnPG\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnUS\0LatnBR\0LatnPG\0LatnPG\0LatnUS\0LatnNG\0LatnNG\0LatnTZ\0LatnID\0LatnAU\0LatnAU\0LatnAU\0LatnPG\0EthiET\0LatnAU\0LatnTL\0LatnID\0LatnGB\0ArabID\0LatnVU\0LatnWF\0LatnAU\0LatnAR\0LatnID\0LatnGH\0LatnNG\0LatnAU\0LatnPG\0LatnBR\0DevaNP\0LatnTL\0LatnAU\0LatnID\0LatnNC\0LatnPG\0LatnID\0LatnAU\0LatnMZ\0LatnPG\0LatnPG\0LatnPG\0LatnAU\0ArabPK\0LatnID\0ArabKM\0LatnID\0LatnAU\0LatnAU\0LatnID\0LatnPG\0LatnPG\0LatnUS\0LatnAU\0LatnAU\0LatnCI\0LatnPG\0LatnID\0LatnFM\0LatnGM\0LatnPG\0LatnID\0LatnCM\0LatnNG\0LatnCD\0LatnID\0LatnID\0LatnPG\0LatnID\0LatnVE\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnID\0LatnAU\0LatnPG\0LatnID\0LatnPG\0LatnAU\0LatnID\0LatnAU\0LatnID\0GongIN\0LatnVU\0LatnPG\0LatnPG\0LatnGH\0LatnBR\0ArabAF\0LatnTZ\0LatnPG\0LatnAU\0LatnET\0LatnPG\0DevaIN\0LatnID\0LatnAU\0LatnAU\0LatnTG\0LatnID\0LatnGA\0LatnTZ\0LatnAU\0LatnPG\0HansCN\0LatnPG\0LatnAU\0LatnID\0LatnBJ\0LatnAU\0LatnVU\0LatnAU\0LatnCM\0LatnAU\0LatnAU\0LatnAU\0LatnPL\0LatnUS\0LatnBR\0LatnFJ\0LatnES\0LatnNG\0AghbAZ\0LatnBR\0LatnBR\0LatnVE\0CyrlRU\0LatnZA\0EthiET\0LatnVN\0LatnPG\0CyrlRU\0LatnBR\0LatnID\0LatnBR\0LatnUS\0LatnID\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnPG\0LatnAU\0LatnFR\0LatnMY\0LatnAU\0LatnID\0LatnBR\0LatnAU\0LatnUS\0ChrsUZ\0CariTR\0LatnAU\0LatnAU\0LatnAO\0CyrlRU\0LatnID\0LatnCM\0LatnZA\0LatnID\0LatnBR\0LatnPG\0LatnBR\0LatnPG\0LatnCI\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0ArabPK\0KhmrKH\0LatnVN\0LatnZA\0LatnGT\0LatnBR\0OryaIN\0LatnBR\0LatnAU\0LatnAU\0ArabPK\0LatnBJ\0ArabIR\0LatnID\0LatnID\0TibtBT\0LatnML\0ArabIR\0LatnID\0LatnID\0ArabIR\0LatnID\0LatnBR\0LatnID\0LatnGH\0LatnCG\0LatnBW\0LatnID\0LatnPG\0LatnMY\0LatnBT\0LatnPG\0LyciTR\0LydiTR\0ElymIR\0LatnSO\0LatnCM\0LatnMZ\0LatnCM\0GeorGE\0LatnCM\0LatnAU\0LatnCM\0LatnID\0ManiCN\0LatnBR\0LatnAU\0LatnAU\0MercSD\0LatnID\0LatnAU\0LatnMG\0LatnMG\0LatnID\0LatnAU\0LatnID\0NarbSA\0LatnTW\0LatnAU\0LatnTZ\0LatnAU\0LatnAU\0LatnPH\0LatnMZ\0LatnUS\0LatnAU\0LatnAU\0LatnEG\0LatnNG\0LatnID\0LatnUG\0LatnPG\0LatnBR\0LatnSD\0LatnGH\0LatnBR\0LatnPG\0LatnBR\0LatnPG\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0GrekTR\0LatnAU\0OgamGB\0LatnAU\0LatnBR\0LatnAU\0CyrlRU\0LatnBR\0LatnMX\0LatnUS\0PrtiIR\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnBR\0LatnBF\0LatnAU\0LatnBR\0LatnAU\0LatnBR\0CyrlRU\0CyrlRU\0LatnIT\0LatnAU\0LatnPG\0SarbYE\0LatnPH\0SidtTR\0LatnID\0LatnNG\0LatnPG\0LatnGH\0LatnNG\0LatnPG\0LatnMZ\0DevaNP\0LatnVE\0LatnTW\0LatnMX\0LatnMX\0LatnSD\0LatnMX\0LatnID\0LatnAU\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0BrahIR\0LatnMX\0LatnMX\0LatnMX\0LatnAU\0LatnBR\0LatnMX\0TamlIN\0LatnAU\0TamlIN\0LatnAU\0LatnIT\0LatnAU\0LatnTD\0LatnAU\0LatnNA\0ItalIT\0ArabAF\0LatnES\0LatnIT\0LatnIT\0LatnBR\0LatnAU\0LatnBJ\0LatnAU\0LatnAU\0LatnBJ\0CyrlRU\0LatnID\0LatnAU\0LatnAU\0LatnGH\0LatnID\0LatnAU\0LatnBR\0LatnID\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnBR\0LatnAU\0LatnAU\0MarcCN\0LatnMX\0LatnPE\0LatnBR\0LatnID\0LatnPE\0LatnVE\0LatnCD\0LatnCL\0LatnTJ\0CyrlTJ\0LatnCF\0LatnUS\0LatnGN\0LatnCM\0LatnNI\0LatnMZ\0LatnFM\0LatnMX\0LatnVE\0LatnCM\0LatnCM\0LatnVE\0LatnCM\0LatnBR\0LatnAO\0LatnNG\0LatnNG\0LatnNG\0LatnCM\0LatnCN\0DevaNP\0DevaNP\0LatnNG\0LatnNG\0LatnPG\0LatnBR\0LatnPG\0LatnPG\0LatnPG\0LatnCN\0LatnCO\0LatnTW\0LatnAU\0LatnPG\0ArabPK\0LatnPG\0MlymIN\0LatnDE\0LatnPG\0LatnCM\0GrekGR\0LatnCD\0LatnNG\0LatnNG\0LatnID\0TeluIN\0LatnPG\0LatnBW\0LatnAU\0LatnAU\0LatnPG\0LatnPG\0PlrdCN\0LatnPG\0LatnAU\0LatnPG\0HebrIL\0HebrUA\0LatnAU\0YiiiCN\0HebrDE\0LatnAU\0LatnAU\0LatnAU\0LatnIN\0LatnID\0LatnPG\0YiiiCN\0LatnPH\0CyrlRU\0CyrlMN\0LatnID\0LatnPG\0LatnPG\0LatnCM\0LatnPG\0LatnCF\0LatnPG\0LatnPG\0LatnPG\0LatnPG\0LatnID\0LatnPG\0LatnAU\0LatnPG\0LatnNC\0LatnPG\0LatnPE\0LatnCD\0LatnMZ\0LatnPG\0LatnSO\0LatnID\0LatnPG\0LatnPG\0PlrdCN\0LatnPG\0LatnAU\0LatnCD\0CyrlRU\0LatnPG\0LatnNG\0LatnCD\0LatnCO\0LatnPG\0LatnPH\0JpanJP\0LatnUS\0LatnIE\0LatnCD\0LatnPG\0LatnNG\0ThaiTH\0LatnPG\0LatnPG\0LatnCI\0CyrlRU\0LatnAU\0LatnBR\0LatnID\0LatnPG\0LatnAU\0YiiiCN\0YiiiCN\0YiiiCN\0CyrlRU\0LatnPG\0PlrdCN\0LatnPG\0LatnAU\0LatnMX\0LatnAU\0LatnUS\0HebrIL\0LatnUS\0CyrlRU\0LatnCO\0LatnPG\0LatnCF\0LatnUS\0LatnNG\0LatnCO\0LatnBO\0LatnUS\0LatnPG\0LatnPG\0CyrlRU\0LatnBO\0LatnID\0LatnVE\0LatnPG\0LatnAU\0LatnBR\0PlrdCN\0LatnAU\0PlrdCN\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnPG\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnSD\0LatnNG\0LatnTZ\0LatnTZ\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0TibtIN\0LatnMX\0LatnMX\0LatnMX\0LatnET\0LatnNG\0Arab001LatnMY\0LatnMY\0LatnID\0LatnNG\0LatnMY\0LatnMX\0HaniCN\0ArabKM\0LatnNL\0LatnPG\0HaniCN\0LatnNG\0TfngMR\0LatnTZ\0HaniCN\0TfngMA\0HaniCN\0HaniCN\0LatnPG\0HaniCN\0LatnNG\0LatnCN\0LatnCM\0LatnPG\0LatnPG\0LatnGN\0LatnTD\0LatnTZ\0LatnTZ\0LatnNG\0LatnID\0LatnMM\0CyrlRU\0LatnBR\0KitsCN\0LatnAU\0CyrlRU\0LatnCD\0HaniCN\0LatnMY\0HaniCN\0HaniCN\0LatnNG\0LatnAU\0LatnCD\0LatnAU\0LatnAU\0LatnAU\0LatnCD\0LatnAU\0LatnPG\0LatnMY\0LatnAU\0LatnAU\0LatnAU\0LatnAU\0LatnGA\0LatnSD\0LatnCD\0LatnCD\0LatnAU\0LatnCD\0LatnAU\0LatnAU\0LatnAU\0LatnCD\0LatnCG\0LatnAU\0LatnCD\0LatnTD\0LatnCD\0LatnVN\0LatnAU\0LatnNG\0LatnMX\0LatnMX\0LatnIN\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0HaniCN\0OryaIN\0LatnTD\0LatnEC\0HebrFR\0LatnID\0LatnPG\0LatnMX\0LatnPG\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnMX\0LatnPG\0ArabOM\0LatnUS\0LatnCM\0EthiET\0HaniCN\0LatnCN\0HaniCN\0LatnMM\0LatnTR\0HaniCN\0") }) - }, - script_region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabKH\0ArabMM\0ArabTH\0ArabTR\0ArabYT\0CyrlAF\0CyrlGE\0CyrlIR\0CyrlTR\0DevaFJ\0DevaPK\0GrekTR\0HebrSE\0HebrUA\0HebrUS\0HmnpAU\0HmnpFR\0HmnpGF\0HmnpLA\0HmnpMM\0HmnpSR\0HmnpTH\0LanaMM\0LatnMM\0LatnRU\0LatnTW\0MymrIN\0MymrTH\0NkooML\0ThaiCN\0ThaiKH\0ThaiLA\0TibtBT\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"cjarhgmfaapcswbkaaab\0kaakbdhifbtvbgxyi\0yi\0yi\0hnjhnjhnjhnjhnjhnjhnjstukackrltrvkhtmnwbm\0lcpkdtkdtdz\0") }) - }, - script: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"AghbAhomArmiAvstBaliBamuBassBatkBerfBrahBugiBuhdCakmCansCariChamChrsCoptCpmnCprtDiakEgypElymGlagGongGonmGothGukhHanoHatrHluwHmngHmnpItalKaliKawiKharKitsKraiLanaLepcLimbLinaLinbLisuLyciLydiMakaMandManiMarcMedfMendMercMeroMrooMultNagmNarbNbatNewaNkooOgamOnaoOrkhOsgeOugrPalmPaucPermPhagPhliPhlpPhnxPlrdPrtiRjngRohgRunrSamrSarbSaurSgnwSidtSogdSogoSoraSoyoSunuSyloTagbTaleTaluTangTavtTayoTfngThaaTibtTnsaTolsTotoUgarVaiiWaraWchoXpeoXsuxZanb") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"xagAZ\0ahoIN\0arcIR\0ae\0IR\0banID\0baxCM\0bsqLR\0bbcID\0zagSD\0pkaIN\0bugID\0bkuPH\0ccpBD\0iu\0CA\0xcrTR\0cjmVN\0xcoUZ\0copEG\0undCY\0ecyCY\0dv\0MV\0egyEG\0arcIR\0cu\0BG\0wsgIN\0esgIN\0gotUA\0gvrNP\0hnnPH\0arcIQ\0hluTR\0hnjLA\0mwwUS\0ettIT\0ekyMM\0kawID\0pgdPK\0zktCN\0bapIN\0nodTH\0lepIN\0lifIN\0labGR\0gmyGR\0lisCN\0xlcTR\0xldTR\0makID\0myzIR\0xmnCN\0bo\0CN\0dmfNG\0menSL\0xmrSD\0xmrSD\0mroBD\0skrPK\0unrIN\0xnaSA\0arcJO\0newNP\0manGN\0sgaIE\0unrIN\0otkMN\0osaUS\0ouiCN\0arcSY\0ctdMM\0kv\0RU\0lzhCN\0palIR\0palCN\0phnLB\0hmdCN\0xprIR\0rejID\0rhgMM\0nonSE\0smpIL\0xsaYE\0sazIN\0aseUS\0xsdTR\0sogUZ\0sogUZ\0srbIN\0cmgMN\0suzNP\0sylBD\0tbwPH\0tddCN\0khbCN\0txgCN\0bltVN\0tyjVN\0zghMA\0dv\0MV\0bo\0CN\0nstIN\0kruIN\0txoIN\0ugaSY\0vaiLR\0hocIN\0nnpIN\0peoIR\0akkIQ\0cmgMN\0") }) - }, - region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"AS\0BI\0BQ\0BT\0CF\0CW\0GL\0HT\0MG\0ML\0MV\0NO\0PG\0PW\0PY\0SJ\0TK\0TV\0VU\0WS\0ZW\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"sm\0Latnrn\0LatnpapLatndz\0Tibtsg\0LatnpapLatnkl\0Latnht\0Latnmg\0Latnbm\0Latndv\0Thaanb\0LatntpiLatnpauLatngn\0Latnnb\0LatntklLatntvlLatnbi\0Latnsm\0Latnsn\0Latn") }) - }, - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleLikelySubtagsExtendedV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleLikelySubtagsExtendedV1>, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_LIKELY_SUBTAGS_EXTENDED_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsExtendedV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_likely_subtags_extended_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleLikelySubtagsExtendedV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_likely_subtags_extended_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleLikelySubtagsExtendedV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsExtendedV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_likely_subtags_extended_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleLikelySubtagsExtendedV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsExtendedV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleLikelySubtagsExtendedV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_likely_subtags_extended_v1 as impl_locale_likely_subtags_extended_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_script_region_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_script_region_v1.rs.data deleted file mode 100644 index d05930f2b87f..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_script_region_v1.rs.data +++ /dev/null @@ -1,93 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleLikelySubtagsScriptRegionV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 3284B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_likely_subtags_script_region_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_LIKELY_SUBTAGS_SCRIPT_REGION_V1: &'static <icu::locale::provider::LocaleLikelySubtagsScriptRegionV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::locale::provider::LikelySubtagsForScriptRegion { - script_region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ArabAF\0ArabAZ\0ArabBN\0ArabCC\0ArabCN\0ArabGB\0ArabID\0ArabIN\0ArabIR\0ArabMN\0ArabMU\0ArabNG\0ArabPK\0ArabTJ\0CyrlAL\0CyrlAZ\0CyrlBA\0CyrlBG\0CyrlGR\0CyrlKG\0CyrlMD\0CyrlME\0CyrlMK\0CyrlMN\0CyrlRO\0CyrlRS\0CyrlSK\0CyrlTJ\0CyrlUA\0CyrlUZ\0CyrlXK\0DevaBT\0DevaMU\0DevaNP\0EthiER\0HantCA\0HantCN\0LatnAE\0LatnAF\0LatnAM\0LatnBD\0LatnBG\0LatnBT\0LatnCC\0LatnCN\0LatnCY\0LatnDZ\0LatnEG\0LatnER\0LatnET\0LatnGR\0LatnHK\0LatnIL\0LatnIN\0LatnIQ\0LatnIR\0LatnJO\0LatnKM\0LatnKZ\0LatnLB\0LatnLK\0LatnMA\0LatnMK\0LatnMO\0LatnMR\0LatnMV\0LatnNP\0LatnPK\0LatnSD\0LatnSS\0LatnSY\0LatnTD\0LatnTH\0LatnTN\0LatnUA\0LatnYE\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"fa\0az\0ms\0ms\0ug\0ur\0ms\0ur\0fa\0kk\0ur\0ha\0ur\0fa\0mk\0az\0sr\0bg\0mk\0ky\0uk\0sr\0mk\0mn\0bg\0sr\0uk\0tg\0uk\0uz\0sr\0ne\0bhone\0ti\0yueyueen\0tk\0ku\0en\0en\0en\0en\0za\0tr\0fr\0en\0en\0en\0en\0en\0en\0en\0en\0tk\0en\0fr\0en\0en\0en\0fr\0sq\0en\0fr\0en\0en\0en\0en\0en\0ku\0fr\0en\0fr\0pl\0en\0") }) - }, - script: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"AdlmArabArmnBengBhksBopoBraiCherCyrlDevaDogrDuplElbaEthiGaraGeorGranGrekGujrGuruHanbHangHaniHansHantHebrHiraHungJamoJavaJpanKanaKhmrKhojKndaKoreKthiLaooMahjMlymModiMongMteiMymrNandOlckOryaOsmaShawShrdSiddSindSinhSundSyrcTakrTamlTeluTglgThaiTirhTodrTutgVithYeziYiii") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"ff\0GN\0ar\0EG\0hy\0AM\0bn\0BD\0sa\0IN\0zh\0TW\0fr\0FR\0chrUS\0ru\0RU\0hi\0IN\0doiIN\0fr\0FR\0sq\0AL\0am\0ET\0wo\0SN\0ka\0GE\0sa\0IN\0el\0GR\0gu\0IN\0pa\0IN\0zh\0TW\0ko\0KR\0zh\0CN\0zh\0CN\0zh\0TW\0he\0IL\0ja\0JP\0hu\0HU\0ko\0KR\0jv\0ID\0ja\0JP\0ja\0JP\0km\0KH\0sd\0IN\0kn\0IN\0ko\0KR\0bhoIN\0lo\0LA\0hi\0IN\0ml\0IN\0mr\0IN\0mn\0CN\0mniIN\0my\0MM\0sa\0IN\0satIN\0or\0IN\0so\0SO\0en\0GB\0sa\0IN\0sa\0IN\0sd\0IN\0si\0LK\0su\0ID\0syrIQ\0doiIN\0ta\0IN\0te\0IN\0filPH\0th\0TH\0maiIN\0sq\0AL\0sa\0IN\0sq\0AL\0ku\0GE\0ii\0CN\0") }) - }, - region: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"419AD\0AE\0AF\0AL\0AM\0AO\0AR\0AT\0AW\0AX\0AZ\0BA\0BD\0BE\0BF\0BG\0BH\0BJ\0BL\0BN\0BO\0BR\0BV\0BY\0CC\0CD\0CG\0CH\0CI\0CL\0CM\0CN\0CO\0CR\0CU\0CV\0CY\0CZ\0DE\0DJ\0DK\0DO\0DZ\0EA\0EC\0EE\0EG\0EH\0ER\0ES\0ET\0FI\0FO\0FR\0GA\0GE\0GF\0GH\0GN\0GP\0GQ\0GR\0GT\0GW\0HK\0HN\0HR\0HU\0IC\0ID\0IL\0IN\0IQ\0IR\0IS\0IT\0JO\0JP\0KE\0KG\0KH\0KM\0KP\0KR\0KW\0KZ\0LA\0LB\0LI\0LK\0LS\0LT\0LU\0LV\0LY\0MA\0MC\0MD\0ME\0MF\0MK\0MM\0MN\0MO\0MQ\0MR\0MT\0MU\0MX\0MY\0MZ\0NA\0NC\0NE\0NI\0NL\0NP\0OM\0PA\0PE\0PF\0PH\0PK\0PL\0PM\0PR\0PS\0PT\0QA\0RE\0RO\0RS\0RU\0RW\0SA\0SC\0SD\0SE\0SI\0SK\0SM\0SN\0SO\0SR\0SS\0ST\0SV\0SY\0TD\0TF\0TG\0TH\0TJ\0TL\0TM\0TN\0TO\0TR\0TW\0TZ\0UA\0UG\0UY\0UZ\0VA\0VE\0VN\0WF\0XK\0YE\0YT\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"es\0Latnca\0Latnar\0Arabfa\0Arabsq\0Latnhy\0Armnpt\0Latnes\0Latnde\0Latnnl\0Latnsv\0Latnaz\0Latnbs\0Latnbn\0Bengnl\0Latnfr\0Latnbg\0Cyrlar\0Arabfr\0Latnfr\0Latnms\0Latnes\0Latnpt\0Latnno\0Latnru\0Cyrlms\0Arabfr\0Latnfr\0Latnde\0Latnfr\0Latnes\0Latnfr\0Latnzh\0Hanses\0Latnes\0Latnes\0Latnpt\0Latnel\0Grekcs\0Latnde\0Latnfr\0Latnda\0Latnes\0Latnar\0Arabes\0Latnes\0Latnet\0Latnar\0Arabar\0Arabti\0Ethies\0Latnam\0Ethifi\0Latnfo\0Latnfr\0Latnfr\0Latnka\0Georfr\0Latnak\0Latnfr\0Latnfr\0Latnes\0Latnel\0Grekes\0Latnpt\0Latnzh\0Hantes\0Latnhr\0Latnhu\0Latnes\0Latnid\0Latnhe\0Hebrhi\0Devaar\0Arabfa\0Arabis\0Latnit\0Latnar\0Arabja\0Jpansw\0Latnky\0Cyrlkm\0Khmrar\0Arabko\0Koreko\0Korear\0Arabru\0Cyrllo\0Laooar\0Arabde\0Latnsi\0Sinhst\0Latnlt\0Latnfr\0Latnlv\0Latnar\0Arabar\0Arabfr\0Latnro\0Latnsr\0Latnfr\0Latnmk\0Cyrlmy\0Mymrmn\0Cyrlzh\0Hantfr\0Latnar\0Arabmt\0Latnfr\0Latnes\0Latnms\0Latnpt\0Latnaf\0Latnfr\0Latnha\0Latnes\0Latnnl\0Latnne\0Devaar\0Arabes\0Latnes\0Latnfr\0LatnfilLatnur\0Arabpl\0Latnfr\0Latnes\0Latnar\0Arabpt\0Latnar\0Arabfr\0Latnro\0Latnsr\0Cyrlru\0Cyrlrw\0Latnar\0Arabfr\0Latnar\0Arabsv\0Latnsl\0Latnsk\0Latnit\0Latnwo\0Latnso\0Latnnl\0Latnar\0Arabpt\0Latnes\0Latnar\0Arabar\0Arabfr\0Latnfr\0Latnth\0Thaitg\0Cyrlpt\0Latntk\0Latnar\0Arabto\0Latntr\0Latnzh\0Hantsw\0Latnuk\0Cyrlsw\0Latnes\0Latnuz\0Latnit\0Latnes\0Latnvi\0Latnfr\0Latnsq\0Latnar\0Arabfr\0Latn") }) - }, - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1>, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_LIKELY_SUBTAGS_SCRIPT_REGION_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_likely_subtags_script_region_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_likely_subtags_script_region_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_likely_subtags_script_region_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleLikelySubtagsScriptRegionV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_likely_subtags_script_region_v1 as impl_locale_likely_subtags_script_region_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_parents_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_parents_v1.rs.data deleted file mode 100644 index 56d0bdd708f3..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_parents_v1.rs.data +++ /dev/null @@ -1,85 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleParentsV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 2941B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_parents_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_PARENTS_V1: &'static <icu::locale::provider::LocaleParentsV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::locale::provider::Parents { - parents: unsafe { - #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x98\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02E\x02J\x02O\x02T\x02Y\x02^\x02c\x02h\x02m\x02r\x02w\x02|\x02\x81\x02\x86\x02\x8B\x02\x90\x02\x95\x02\x9A\x02\xA1\x02\xA3\x02\xA5\x02\xA7\x02\xAC\x02\xB1\x02\xB6\x02\xBB\x02\xC0\x02\xC5\x02\xCA\x02\xCF\x02\xD4\x02\xD9\x02\xDE\x02\xE3\x02\xEB\x02\xF3\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-CZen-DEen-DGen-DKen-DMen-EEen-ERen-ESen-FIen-FJen-FKen-FMen-FRen-GBen-GDen-GEen-GGen-GHen-GIen-GMen-GSen-GYen-HKen-HUen-IDen-IEen-ILen-IMen-INen-IOen-ITen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-LTen-LVen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NOen-NRen-NUen-NZen-PGen-PKen-PLen-PNen-PTen-PWen-ROen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SKen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UAen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-JPes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLund-Hansund-Hantzh-Hant-MO") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0und\x01Hani\0\0\0\0und\x01Hani\0\0\0\0zh\0\x01Hant\x01HK\0") }) - }, - }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleParentsV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleParentsV1>, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_PARENTS_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleParentsV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_parents_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleParentsV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_parents_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleParentsV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleParentsV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_parents_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleParentsV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleParentsV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleParentsV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_parents_v1 as impl_locale_parents_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_script_direction_v1.rs.data b/deps/crates/vendor/icu_locale_data-v2/data/locale_script_direction_v1.rs.data deleted file mode 100644 index 63487afc84fd..000000000000 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_script_direction_v1.rs.data +++ /dev/null @@ -1,80 +0,0 @@ -// @generated -/// Implement `DataProvider<LocaleScriptDirectionV1>` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 756B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -/// -/// This macro requires the following crates: -/// * `icu` -/// * `icu_provider` -/// * `zerovec` -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_locale_script_direction_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.86"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_LOCALE_SCRIPT_DIRECTION_V1: &'static <icu::locale::provider::LocaleScriptDirectionV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::locale::provider::ScriptDirection { rtl: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"AdlmArabArmiAvstChrsCprtElymGaraHatrHebrHungKharLydiMandManiMendMercMeroNarbNbatNkooOrkhOugrPalmPhliPhlpPhnxPrtiRohgSamrSarbSidtSogdSogoSyrcThaaYezi") }, ltr: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"AghbAhomArmnBaliBamuBassBatkBengBerfBhksBopoBrahBugiBuhdCakmCansCariChamCherCoptCpmnCyrlDevaDiakDogrDsrtDuplEgypElbaEthiGeorGlagGongGonmGothGranGrekGujrGukhGuruHanbHangHaniHanoHansHantHiraHluwHmngHmnpItalJamoJavaJpanKaliKanaKawiKhmrKhojKitsKndaKoreKraiKthiLanaLaooLatnLepcLimbLinaLinbLisuLyciMahjMakaMarcMedfMlymModiMongMrooMteiMultMymrNagmNandNewaNshuOgamOlckOnaoOryaOsgeOsmaPaucPermPhagPlrdRjngRunrSaurSgnwShawShrdSiddSindSinhSoraSoyoSundSunuSyloTagbTakrTaleTaluTamlTangTavtTayoTeluTfngTglgThaiTibtTirhTnsaTodrTolsTotoTutgUgarVaiiVithWaraWchoXpeoXsuxYiiiZanb") } }; - } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleScriptDirectionV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleScriptDirectionV1>, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_SCRIPT_DIRECTION_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleScriptDirectionV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_locale_script_direction_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleScriptDirectionV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_locale_script_direction_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleScriptDirectionV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleScriptDirectionV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_locale_script_direction_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleScriptDirectionV1> for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleScriptDirectionV1 as icu_provider::DataMarker>::INFO, req)) - } - } - } - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleScriptDirectionV1> for $provider { - fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_locale_script_direction_v1 as impl_locale_script_direction_v1; diff --git a/deps/crates/vendor/icu_collections-v2/.cargo-checksum.json b/deps/crates/vendor/icu_locale_fallback-v2/.cargo-checksum.json similarity index 100% rename from deps/crates/vendor/icu_collections-v2/.cargo-checksum.json rename to deps/crates/vendor/icu_locale_fallback-v2/.cargo-checksum.json diff --git a/deps/crates/vendor/icu_locale_fallback-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale_fallback-v2/.cargo_vcs_info.json new file mode 100644 index 000000000000..b7ce2123ca95 --- /dev/null +++ b/deps/crates/vendor/icu_locale_fallback-v2/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" + }, + "path_in_vcs": "components/locale_fallback" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale-v2/Cargo.lock b/deps/crates/vendor/icu_locale_fallback-v2/Cargo.lock similarity index 73% rename from deps/crates/vendor/icu_locale-v2/Cargo.lock rename to deps/crates/vendor/icu_locale_fallback-v2/Cargo.lock index 245cb515af5f..c24164a6a43b 100644 --- a/deps/crates/vendor/icu_locale-v2/Cargo.lock +++ b/deps/crates/vendor/icu_locale_fallback-v2/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -25,15 +25,15 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "cast" @@ -43,9 +43,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "ciborium" @@ -76,18 +76,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cobs" @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -156,18 +156,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -188,32 +188,32 @@ dependencies = [ [[package]] name = "databake-derive" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b537745234cbf0e296a3bd836d70a614dff4cb522b14e2680ef006bb1ed5ff" +checksum = "495503291b258422ea2bb9863d9f4e31eadbc5bcbdbe8b721769fa2c98dc4d41" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", "synstructure", ] [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "either" -version = "1.15.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "erased-serde" @@ -238,35 +238,33 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] -name = "icu_collections" -version = "2.2.0" +name = "icu_locale_core" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "databake", "displaydoc", - "potential_utf", + "litemap", "serde", - "utf8_iter", - "yoke", - "zerofrom", + "tinystr", + "writeable", "zerovec", ] [[package]] -name = "icu_locale" -version = "2.2.0" +name = "icu_locale_fallback" +version = "2.4.0" dependencies = [ "criterion", "databake", - "icu_collections", "icu_locale_core", - "icu_locale_data", + "icu_locale_fallback_data", "icu_provider", "potential_utf", "serde", @@ -276,31 +274,16 @@ dependencies = [ ] [[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "databake", - "displaydoc", - "litemap", - "serde", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locale_data" -version = "2.2.0" +name = "icu_locale_fallback_data" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" +checksum = "3632ebbd0c5c3637ba1a40bdf8288f2cb9d2268e73441a69d5fc73d7cfbaa87c" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "databake", "displaydoc", @@ -344,9 +327,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ "once_cell", "wasm-bindgen", @@ -354,21 +337,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.183" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "num-traits" @@ -431,9 +414,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "serde_core", "writeable", @@ -442,18 +425,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -480,9 +463,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -492,9 +475,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -503,15 +486,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "same-file" @@ -524,9 +507,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -534,29 +517,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -573,9 +556,20 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.117" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -584,40 +578,40 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "databake", "displaydoc", @@ -643,15 +637,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "walkdir" @@ -665,9 +653,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if", "once_cell", @@ -678,9 +666,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -688,31 +676,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" dependencies = [ "js-sys", "wasm-bindgen", @@ -744,15 +732,15 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -761,42 +749,42 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "zerovec", @@ -804,9 +792,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "databake", "serde", @@ -817,17 +805,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.9", ] [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/deps/crates/vendor/icu_locale-v2/Cargo.toml b/deps/crates/vendor/icu_locale_fallback-v2/Cargo.toml similarity index 83% rename from deps/crates/vendor/icu_locale-v2/Cargo.toml rename to deps/crates/vendor/icu_locale_fallback-v2/Cargo.toml index ea69b0cb6a28..4d1745c1d10f 100644 --- a/deps/crates/vendor/icu_locale-v2/Cargo.toml +++ b/deps/crates/vendor/icu_locale_fallback-v2/Cargo.toml @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2021" -rust-version = "1.86" -name = "icu_locale" -version = "2.2.0" +edition = "2024" +rust-version = "1.88" +name = "icu_locale_fallback" +version = "2.4.0" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -32,13 +32,15 @@ autobins = false autoexamples = false autotests = false autobenches = false -description = "API for Unicode Language and Locale Identifiers canonicalization" +description = "API for Locale Fallback algorithms" homepage = "https://icu4x.unicode.org" readme = "README.md" keywords = [ "unicode", "language-tags", "bcp47", + "locale", + "fallback", ] categories = [ "internationalization", @@ -48,6 +50,7 @@ categories = [ ] license = "Unicode-3.0" repository = "https://github.com/unicode-org/icu4x" +resolver = "2" [package.metadata.cargo-all-features] skip_optional_dependencies = true @@ -57,7 +60,7 @@ all-features = true [features] compiled_data = [ - "dep:icu_locale_data", + "dep:icu_locale_fallback_data", "icu_provider/baked", ] datagen = [ @@ -66,7 +69,6 @@ datagen = [ "zerovec/databake", "icu_locale_core/databake", "tinystr/databake", - "icu_collections/databake", "icu_provider/export", ] default = ["compiled_data"] @@ -77,49 +79,35 @@ serde = [ "zerovec/serde", "icu_provider/serde", "potential_utf/serde", - "icu_collections/serde", ] +std = ["icu_provider/std"] [lib] -name = "icu_locale" +name = "icu_locale_fallback" path = "src/lib.rs" bench = false -[[test]] -name = "locale_canonicalizer" -path = "tests/locale_canonicalizer.rs" -required-features = ["serde"] - -[[bench]] -name = "locale_canonicalizer" -path = "benches/locale_canonicalizer.rs" -harness = false - [dependencies.databake] version = "0.2.0" features = ["derive"] optional = true default-features = false -[dependencies.icu_collections] -version = "~2.2.0" -default-features = false - [dependencies.icu_locale_core] -version = "2.2.0" +version = "2.4.0" features = [ "alloc", "zerovec", ] default-features = false -[dependencies.icu_locale_data] -version = "~2.2.0" +[dependencies.icu_locale_fallback_data] +version = "~2.4.0" optional = true default-features = false [dependencies.icu_provider] -version = "2.2.0" +version = "2.4.0" features = ["alloc"] default-features = false @@ -141,7 +129,7 @@ optional = true default-features = false [dependencies.tinystr] -version = "0.8.3" +version = "0.8.5" features = [ "alloc", "zerovec", @@ -149,7 +137,7 @@ features = [ default-features = false [dependencies.zerovec] -version = "0.11.6" +version = "0.11.9" features = [ "alloc", "yoke", @@ -168,8 +156,9 @@ version = "1.0.45" version = "0.5.0" [lints.clippy] -alloc-instead-of-core = "warn" -branches-sharing-code = "warn" +alloc_instead_of_core = "warn" +bool_assert_comparison = "allow" +branches_sharing_code = "warn" collection_is_never_read = "warn" crosspointer_transmute = "warn" dbg_macro = "warn" @@ -184,7 +173,7 @@ mismatching_type_param_order = "warn" missing_fields_in_debug = "warn" missing_transmute_annotations = "warn" negative_feature_names = "warn" -or-fun-call = "warn" +or_fun_call = "warn" same_functions_in_if_condition = "warn" todo = "warn" transmute_bytes_to_str = "warn" @@ -195,7 +184,7 @@ transmute_ptr_to_ref = "warn" transmute_undefined_repr = "warn" transmutes_expressible_as_ptr_casts = "warn" trivially_copy_pass_by_ref = "deny" -unnecessary-wraps = "warn" +unnecessary_wraps = "warn" useless_transmute = "warn" wildcard_dependencies = "warn" @@ -212,6 +201,7 @@ priority = 0 check-cfg = [ "cfg(icu4c_enable_renaming)", "cfg(needs_alloc_error_handler)", + "cfg(icu4x_nightly_tests)", "cfg(icu4x_run_size_tests)", "cfg(icu4x_unstable_fast_trie_only)", ] diff --git a/deps/crates/vendor/icu_locale-v2/Cargo.toml.orig b/deps/crates/vendor/icu_locale_fallback-v2/Cargo.toml.orig similarity index 70% rename from deps/crates/vendor/icu_locale-v2/Cargo.toml.orig rename to deps/crates/vendor/icu_locale_fallback-v2/Cargo.toml.orig index 41e83c924d50..be58e4cdb992 100644 --- a/deps/crates/vendor/icu_locale-v2/Cargo.toml.orig +++ b/deps/crates/vendor/icu_locale_fallback-v2/Cargo.toml.orig @@ -3,10 +3,10 @@ # (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). [package] -name = "icu_locale" -description = "API for Unicode Language and Locale Identifiers canonicalization" +name = "icu_locale_fallback" +description = "API for Locale Fallback algorithms" categories.workspace = true -keywords = ["unicode", "language-tags", "bcp47"] +keywords = ["unicode", "language-tags", "bcp47", "locale", "fallback"] authors.workspace = true edition.workspace = true @@ -30,11 +30,9 @@ icu_provider = { workspace = true, features = ["alloc"] } serde = { workspace = true, features = ["derive", "alloc"], optional = true } tinystr = { workspace = true, features = ["alloc", "zerovec"] } potential_utf = { workspace = true, features = ["alloc", "zerovec"] } -zerovec = { workspace = true, features = ["alloc", "yoke"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } -icu_collections = { workspace = true } - -icu_locale_data = { workspace = true, optional = true } +icu_locale_fallback_data = { workspace = true, optional = true } [dev-dependencies] serde = { workspace = true, features = ["derive"] } @@ -50,17 +48,10 @@ bench = false # This option is required for Benchmark CI [features] default = ["compiled_data"] -serde = ["dep:serde", "icu_locale_core/serde", "tinystr/serde", "zerovec/serde", "icu_provider/serde", "potential_utf/serde", "icu_collections/serde"] -datagen = ["serde", "dep:databake", "zerovec/databake", "icu_locale_core/databake", "tinystr/databake", "icu_collections/databake", "icu_provider/export"] -compiled_data = ["dep:icu_locale_data", "icu_provider/baked"] - -[[bench]] -name = "locale_canonicalizer" -harness = false - -[[test]] -name = "locale_canonicalizer" -required-features = ["serde"] +std = ["icu_provider/std"] +serde = ["dep:serde", "icu_locale_core/serde", "tinystr/serde", "zerovec/serde", "icu_provider/serde", "potential_utf/serde"] +datagen = ["serde", "dep:databake", "zerovec/databake", "icu_locale_core/databake", "tinystr/databake", "icu_provider/export"] +compiled_data = ["dep:icu_locale_fallback_data", "icu_provider/baked"] [lints] workspace = true diff --git a/deps/crates/vendor/icu_collections-v2/LICENSE b/deps/crates/vendor/icu_locale_fallback-v2/LICENSE similarity index 100% rename from deps/crates/vendor/icu_collections-v2/LICENSE rename to deps/crates/vendor/icu_locale_fallback-v2/LICENSE diff --git a/deps/crates/vendor/icu_locale_fallback-v2/README.md b/deps/crates/vendor/icu_locale_fallback-v2/README.md new file mode 100644 index 000000000000..0c4a94695ebb --- /dev/null +++ b/deps/crates/vendor/icu_locale_fallback-v2/README.md @@ -0,0 +1,8 @@ +# icu_locale_fallback [![crates.io](https://img.shields.io/crates/v/icu_locale_fallback)](https://crates.io/crates/icu_locale_fallback) + +<!-- cargo-rdme start --> + +Tools for locale fallback, enabling arbitrary input locales to be mapped into the nearest +locale with data. + +<!-- cargo-rdme end --> diff --git a/deps/crates/vendor/icu_locale-v2/src/fallback/algorithms.rs b/deps/crates/vendor/icu_locale_fallback-v2/src/algorithms.rs similarity index 90% rename from deps/crates/vendor/icu_locale-v2/src/fallback/algorithms.rs rename to deps/crates/vendor/icu_locale_fallback-v2/src/algorithms.rs index 7b7ab742b059..e15d0afc530f 100644 --- a/deps/crates/vendor/icu_locale-v2/src/fallback/algorithms.rs +++ b/deps/crates/vendor/icu_locale_fallback-v2/src/algorithms.rs @@ -3,23 +3,21 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use super::LocaleFallbackPriority; -use icu_locale_core::subtags::{Language, Region, Script}; +use ::icu_locale_core::subtags::{Language, Region, Script}; use super::*; impl LocaleFallbackerWithConfig<'_> { pub(crate) fn normalize(&self, locale: &mut DataLocale, default_script: &mut Option<Script>) { // 0. If there is an invalid or trivial "sd" subtag, drop it - if let Some(subdivision) = locale.subdivision.take() { - if let Some(region) = locale.region { - if subdivision - .as_str() - .starts_with(region.to_tinystr().to_ascii_lowercase().as_str()) - && !subdivision.as_str().ends_with("zzzz") - { - locale.subdivision = Some(subdivision); - } - } + if let Some(subdivision) = locale.subdivision.take() + && let Some(region) = locale.region + && subdivision + .as_str() + .starts_with(region.to_tinystr().to_ascii_lowercase().as_str()) + && !subdivision.as_str().ends_with("zzzz") + { + locale.subdivision = Some(subdivision); } let language = locale.language; // 1. Populate the region (required for region fallback only) @@ -45,7 +43,10 @@ impl LocaleFallbackerWithConfig<'_> { } } // 2. Remove the script if it is implied by the other subtags - if locale.script.is_some() || self.config.priority == LocaleFallbackPriority::Script { + if locale.script.is_some() + || locale.region.is_some() + || self.config.priority == LocaleFallbackPriority::Script + { *default_script = locale .region .and_then(|region| { @@ -106,16 +107,18 @@ impl LocaleFallbackIteratorInner<'_> { return; } // 7. Remove region - if let Some(region) = locale.region { - // 6. Add the script subtag if necessary - if locale.script.is_none() { - let language = locale.language; - if let Some(script) = self.likely_subtags.language_region.get_copied(&( - language.to_tinystr().to_unvalidated(), - region.to_tinystr().to_unvalidated(), - )) { - locale.script = Some(script); - } + if let Some(_region) = locale.region { + // note: self.backup_region is not used right now + // 6. Add or remove the script subtag if necessary + let language_implied_script = self + .likely_subtags + .language + .get_copied(&locale.language.to_tinystr().to_unvalidated()) + .map(|(s, _r)| s); + if language_implied_script != self.max_script { + locale.script = self.max_script; + } else { + locale.script = None; } locale.region = None; locale.variant = self.backup_variant.take(); @@ -183,6 +186,8 @@ impl LocaleFallbackIteratorInner<'_> { .map(|(s, _r)| s); if language_implied_script != self.max_script { locale.script = self.max_script; + } else { + locale.script = None; } locale.region = None; locale.variant = self.backup_variant.take(); @@ -237,8 +242,8 @@ impl LocaleFallbackIteratorInner<'_> { #[cfg(test)] mod tests { use super::*; - use icu_locale_core::preferences::LocalePreferences; use icu_locale_core::Locale; + use icu_locale_core::preferences::LocalePreferences; use writeable::Writeable; struct TestCase { @@ -327,6 +332,13 @@ mod tests { expected_script_chain: &["sr-ME", "sr-Latn", "und-Latn"], expected_region_chain: &["sr-ME", "und-ME"], }, + TestCase { + input: "sr-Cyrl-ME", + requires_data: true, + expected_language_chain: &["sr-Cyrl-ME", "sr"], + expected_script_chain: &["sr-Cyrl-ME", "sr", "und-Cyrl"], + expected_region_chain: &["sr-Cyrl-ME", "und-ME"], + }, TestCase { input: "sr-ME-fonipa", requires_data: true, @@ -414,6 +426,13 @@ mod tests { expected_script_chain: &["zh-CN", "zh", "und-Hans", "und-Hani"], expected_region_chain: &["zh-CN", "und-CN"], }, + TestCase { + input: "zh-Hant-CN", + requires_data: true, + expected_language_chain: &["zh-Hant-CN", "zh-Hant"], + expected_script_chain: &["zh-Hant-CN", "zh-Hant", "und-Hant", "und-Hani"], + expected_region_chain: &["zh-Hant-CN", "und-CN"], + }, TestCase { input: "zh-TW", requires_data: true, @@ -421,6 +440,13 @@ mod tests { expected_script_chain: &["zh-TW", "zh-Hant", "und-Hant", "und-Hani"], expected_region_chain: &["zh-TW", "und-TW"], }, + TestCase { + input: "zh-Hans-TW", + requires_data: true, + expected_language_chain: &["zh-Hans-TW", "zh"], + expected_script_chain: &["zh-Hans-TW", "zh", "und-Hans", "und-Hani"], + expected_region_chain: &["zh-Hans-TW", "und-TW"], + }, TestCase { input: "yue-HK", requires_data: true, diff --git a/deps/crates/vendor/icu_locale-v2/src/fallback/mod.rs b/deps/crates/vendor/icu_locale_fallback-v2/src/lib.rs similarity index 86% rename from deps/crates/vendor/icu_locale-v2/src/fallback/mod.rs rename to deps/crates/vendor/icu_locale_fallback-v2/src/lib.rs index de46418de49a..919b57275a01 100644 --- a/deps/crates/vendor/icu_locale-v2/src/fallback/mod.rs +++ b/deps/crates/vendor/icu_locale_fallback-v2/src/lib.rs @@ -5,14 +5,28 @@ //! Tools for locale fallback, enabling arbitrary input locales to be mapped into the nearest //! locale with data. +// https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations +#![cfg_attr(not(any(test, doc)), no_std)] +#![cfg_attr( + not(test), + deny( + clippy::indexing_slicing, + clippy::unwrap_used, + clippy::expect_used, + clippy::panic, + ) +)] +#![warn(missing_docs)] + use crate::provider::*; -use icu_locale_core::subtags::*; +use icu_locale_core::subtags::{Language, Region, Script, Subtag, Variant, region, script}; use icu_provider::prelude::*; #[doc(inline)] pub use icu_provider::fallback::{LocaleFallbackConfig, LocaleFallbackPriority}; mod algorithms; +pub mod provider; /// Implements the algorithm defined in *[UTS #35: Locale Inheritance and Matching]*. /// @@ -20,6 +34,9 @@ mod algorithms; /// algorithm. See *[the design doc]* for a detailed description and [#2243]( /// https://github.com/unicode-org/icu4x/issues/2243) to track alignment with *UTS #35*. /// +/// While the first element produced here is *usually* the input locale, +/// the fallback iterator normalizes the input locale first, which may strip implied subtags. +/// /// If running fallback in a loop, use [`DataLocale::is_unknown()`] to break from the loop. /// /// # Examples @@ -51,9 +68,27 @@ mod algorithms; /// assert_eq!(fallback_iterator.get(), &locale!("und").into()); /// ``` /// +/// `zh-Hans` normalizes to `zh` because `Hans` is the default script for `zh`: +/// +/// ``` +/// use icu::locale::fallback::LocaleFallbacker; +/// use icu::locale::locale; +/// +/// // Set up a LocaleFallbacker with data. +/// let fallbacker = LocaleFallbacker::new(); +/// +/// let mut fallback_iterator = fallbacker +/// .for_config(Default::default()) +/// .fallback_for(locale!("zh-Hans").into()); +/// +/// // The origin "zh-Hans" is normalized to "zh" because Hans is the default script. +/// assert_eq!(fallback_iterator.get(), &locale!("zh").into()); +/// fallback_iterator.step(); +/// assert_eq!(fallback_iterator.get(), &locale!("und").into()); +/// ``` +/// /// [UTS #35: Locale Inheritance and Matching]: https://www.unicode.org/reports/tr35/#Locale_Inheritance /// [the design doc]: https://docs.google.com/document/d/1Mp7EUyl-sFh_HZYgyeVwj88vJGpCBIWxzlCwGgLCDwM/edit -#[doc(hidden)] // canonical location in super #[derive(Debug, Clone, PartialEq)] pub struct LocaleFallbacker { likely_subtags: DataPayload<LocaleLikelySubtagsLanguageV1>, @@ -148,11 +183,7 @@ impl LocaleFallbacker { language_region: Default::default(), language_script: Default::default(), // Unused - und: ( - Language::UNKNOWN, - crate::subtags::script!("Zzzz"), - crate::subtags::region!("ZZ"), - ), + und: (Language::UNKNOWN, script!("Zzzz"), region!("ZZ")), }), parents: DataPayload::from_owned(Default::default()), } @@ -238,6 +269,11 @@ impl<'a> LocaleFallbackerWithConfig<'a> { }, } } + + /// Returns this fallbacker's configuration. + pub fn config(&self) -> LocaleFallbackConfig { + self.config + } } impl LocaleFallbackIterator<'_> { diff --git a/deps/crates/vendor/icu_locale_fallback-v2/src/provider.rs b/deps/crates/vendor/icu_locale_fallback-v2/src/provider.rs new file mode 100644 index 000000000000..fa0ce34be749 --- /dev/null +++ b/deps/crates/vendor/icu_locale_fallback-v2/src/provider.rs @@ -0,0 +1,135 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +// Provider structs must be stable +#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] + +//! 🚧 \[Unstable\] Data provider struct definitions for this ICU4X component. +//! +//! <div class="stab unstable"> +//! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +//! including in SemVer minor releases. While the serde representation of data structs is guaranteed +//! to be stable, their Rust representation might not be. Use with caution. +//! </div> +//! +//! Read more about data providers: [`icu_provider`] + +#[cfg(feature = "compiled_data")] +#[derive(Debug)] +/// Baked data +/// +/// <div class="stab unstable"> +/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. In particular, the `DataProvider` implementations are only +/// guaranteed to match with this version's `*_unstable` providers. Use with caution. +/// </div> +pub struct Baked; + +#[cfg(feature = "compiled_data")] +#[allow(unused_imports)] +const _: () = { + use icu_locale_fallback_data::*; + pub mod icu { + pub mod locale { + pub use crate as fallback; + } + } + pub use crate as icu_locale_fallback; + make_provider!(Baked); + impl_locale_likely_subtags_language_v1!(Baked); + impl_locale_parents_v1!(Baked); +}; + +icu_provider::data_marker!( + /// Marker for data for likely subtags for languages. + LocaleLikelySubtagsLanguageV1, + "locale/likely/subtags/language/v1", + LikelySubtagsForLanguage<'static>, + is_singleton = true +); +icu_provider::data_marker!( + /// Marker for locale fallback parents data. + LocaleParentsV1, + "locale/parents/v1", + Parents<'static>, + is_singleton = true +); + +#[cfg(feature = "datagen")] +/// The latest minimum set of markers required by this component. +pub const MARKERS: &[DataMarkerInfo] = + &[LocaleLikelySubtagsLanguageV1::INFO, LocaleParentsV1::INFO]; + +use icu_locale_core::subtags::{Language, Region, Script}; +use icu_provider::prelude::*; +use potential_utf::PotentialUtf8; +use tinystr::UnvalidatedTinyAsciiStr; +use zerovec::ZeroMap; + +type UnvalidatedLanguage = UnvalidatedTinyAsciiStr<3>; +type UnvalidatedScript = UnvalidatedTinyAsciiStr<4>; +type UnvalidatedRegion = UnvalidatedTinyAsciiStr<3>; + +#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)] +#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] +#[cfg_attr(feature = "datagen", databake(path = icu_locale_fallback::provider))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] +/// This likely subtags data is used for the minimize and maximize operations. +/// +/// Each field defines a mapping from an old identifier to a new identifier, +/// based upon the rules in +/// <https://www.unicode.org/reports/tr35/#Likely_Subtags>. +/// +/// The data is stored is broken down into smaller vectors based upon the rules +/// defined for the likely subtags maximize algorithm. +/// +/// For efficiency, only the relevant part of the [`icu_locale_core::LanguageIdentifier`] is stored +/// for searching and replacing. E.g., the `language_script` field is used to store +/// rules for [`icu_locale_core::LanguageIdentifier`]s that contain a language and a script, but not a +/// region. +/// +/// This struct contains mappings when the input contains a language subtag. +/// +/// <div class="stab unstable"> +/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. While the serde representation of data structs is guaranteed +/// to be stable, their Rust representation might not be. Use with caution. +/// </div> +#[yoke(prove_covariance_manually)] +pub struct LikelySubtagsForLanguage<'data> { + /// Language and script. + #[cfg_attr(feature = "serde", serde(borrow))] + pub language_script: ZeroMap<'data, (UnvalidatedLanguage, UnvalidatedScript), Region>, + /// Language and region. + #[cfg_attr(feature = "serde", serde(borrow))] + pub language_region: ZeroMap<'data, (UnvalidatedLanguage, UnvalidatedRegion), Script>, + /// Just language. + #[cfg_attr(feature = "serde", serde(borrow))] + pub language: ZeroMap<'data, UnvalidatedLanguage, (Script, Region)>, + /// Undefined. + pub und: (Language, Script, Region), +} + +icu_provider::data_struct!( + LikelySubtagsForLanguage<'_>, + #[cfg(feature = "datagen")] +); + +/// Locale fallback rules derived from CLDR parent locales data. +#[derive(Default, Clone, PartialEq, Debug, yoke::Yokeable, zerofrom::ZeroFrom)] +#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] +#[cfg_attr(feature = "datagen", databake(path = icu_locale_fallback::provider))] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] +#[yoke(prove_covariance_manually)] +pub struct Parents<'data> { + /// Map from language identifier to language identifier, indicating that the language on the + /// left should inherit from the language on the right. + #[cfg_attr(feature = "serde", serde(borrow))] + pub parents: ZeroMap<'data, PotentialUtf8, (Language, Option<Script>, Option<Region>)>, +} + +icu_provider::data_struct!( + Parents<'_>, + #[cfg(feature = "datagen")] +); diff --git a/deps/crates/vendor/icu_locale-v2/.cargo-checksum.json b/deps/crates/vendor/icu_locale_fallback_data-v2/.cargo-checksum.json similarity index 100% rename from deps/crates/vendor/icu_locale-v2/.cargo-checksum.json rename to deps/crates/vendor/icu_locale_fallback_data-v2/.cargo-checksum.json diff --git a/deps/crates/vendor/icu_locale_fallback_data-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale_fallback_data-v2/.cargo_vcs_info.json new file mode 100644 index 000000000000..e35ce0d78756 --- /dev/null +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" + }, + "path_in_vcs": "provider/data/locale_fallback" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale_data-v2/Cargo.lock b/deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.lock similarity index 69% rename from deps/crates/vendor/icu_locale_data-v2/Cargo.lock rename to deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.lock index 607c357b95b6..01688a8e6403 100644 --- a/deps/crates/vendor/icu_locale_data-v2/Cargo.lock +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.lock @@ -3,5 +3,5 @@ version = 3 [[package]] -name = "icu_locale_data" -version = "2.2.0" +name = "icu_locale_fallback_data" +version = "2.4.0" diff --git a/deps/crates/vendor/icu_locale_data-v2/Cargo.toml b/deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.toml similarity index 83% rename from deps/crates/vendor/icu_locale_data-v2/Cargo.toml rename to deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.toml index bbb57e0684ad..bf6e4bfce105 100644 --- a/deps/crates/vendor/icu_locale_data-v2/Cargo.toml +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.toml @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2021" -rust-version = "1.86" -name = "icu_locale_data" -version = "2.2.0" +edition = "2024" +rust-version = "1.88" +name = "icu_locale_fallback_data" +version = "2.4.0" authors = ["The ICU4X Project Developers"] build = "build.rs" include = [ @@ -32,7 +32,7 @@ autobins = false autoexamples = false autotests = false autobenches = false -description = "Data for the icu_locale crate" +description = "Data for the icu_locale_fallback crate" homepage = "https://icu4x.unicode.org" readme = "README.md" keywords = [ @@ -47,18 +47,19 @@ categories = [ ] license = "Unicode-3.0" repository = "https://github.com/unicode-org/icu4x" +resolver = "2" [package.metadata.sources.cldr] -tagged = "48.2.0" +tagged = "49.0.0" -[package.metadata.sources.icuexport] -tagged = "release-78.1rc" +[package.metadata.sources.unicode] +tagged = "18.0.0" [package.metadata.sources.segmenter_lstm] tagged = "v0.1.0" [lib] -name = "icu_locale_data" +name = "icu_locale_fallback_data" path = "src/lib.rs" [dependencies] diff --git a/deps/crates/vendor/icu_locale_data-v2/Cargo.toml.orig b/deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.toml.orig similarity index 81% rename from deps/crates/vendor/icu_locale_data-v2/Cargo.toml.orig rename to deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.toml.orig index 525404653ee1..da9a7d6c47ed 100644 --- a/deps/crates/vendor/icu_locale_data-v2/Cargo.toml.orig +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/Cargo.toml.orig @@ -3,8 +3,8 @@ # (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). [package] -name = "icu_locale_data" -description = "Data for the icu_locale crate" +name = "icu_locale_fallback_data" +description = "Data for the icu_locale_fallback crate" categories.workspace = true keywords = ["data", "unicode"] license = "Unicode-3.0" @@ -18,8 +18,8 @@ repository.workspace = true rust-version.workspace = true [package.metadata.sources] -cldr = { tagged = "48.2.0" } -icuexport = { tagged = "release-78.1rc" } +cldr = { tagged = "49.0.0" } +unicode = { tagged = "18.0.0" } segmenter_lstm = { tagged = "v0.1.0" } [lints.rust] diff --git a/deps/crates/vendor/icu_locale-v2/LICENSE b/deps/crates/vendor/icu_locale_fallback_data-v2/LICENSE similarity index 100% rename from deps/crates/vendor/icu_locale-v2/LICENSE rename to deps/crates/vendor/icu_locale_fallback_data-v2/LICENSE diff --git a/deps/crates/vendor/icu_locale_fallback_data-v2/README.md b/deps/crates/vendor/icu_locale_fallback_data-v2/README.md new file mode 100644 index 000000000000..3ec079be8f6c --- /dev/null +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/README.md @@ -0,0 +1,14 @@ +# icu_locale_fallback_data [![crates.io](https://img.shields.io/crates/v/icu_locale_fallback_data)](https://crates.io/crates/icu_locale_fallback_data) + +<!-- cargo-rdme start --> + +Data for the `icu_locale_fallback` crate + +This data was generated with CLDR version 49.0.0, Unicode version 18.0.0, and +LSTM segmenter version v0.1.0. + +<!-- cargo-rdme end --> + +## More Information + +For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). diff --git a/deps/crates/vendor/icu_locale_data-v2/build.rs b/deps/crates/vendor/icu_locale_fallback_data-v2/build.rs similarity index 100% rename from deps/crates/vendor/icu_locale_data-v2/build.rs rename to deps/crates/vendor/icu_locale_fallback_data-v2/build.rs diff --git a/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_language_v1.rs.data b/deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_likely_subtags_language_v1.rs.data similarity index 55% rename from deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_language_v1.rs.data rename to deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_likely_subtags_language_v1.rs.data index 110343f582fb..d04dd379aa4c 100644 --- a/deps/crates/vendor/icu_locale_data-v2/data/locale_likely_subtags_language_v1.rs.data +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_likely_subtags_language_v1.rs.data @@ -4,7 +4,7 @@ /// `icu`'s `_unstable` constructors. /// /// Using this implementation will embed the following data in the binary's data segment: -/// * 2440B[^1] for the singleton data struct +/// * 2550B[^1] for the singleton data struct /// /// [^1]: these numbers can be smaller in practice due to linker deduplication /// @@ -17,12 +17,12 @@ #[macro_export] macro_rules! __impl_locale_likely_subtags_language_v1 { ($ provider : ty) => { - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl $provider { #[doc(hidden)] - pub const SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1: &'static <icu::locale::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu::locale::provider::LikelySubtagsForLanguage { + pub const SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1: &'static <icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu_locale_fallback::provider::LikelySubtagsForLanguage { language_script: unsafe { #[allow(unused_unsafe)] zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"az\0Araben\0Shawff\0Adlmkk\0Arabku\0Arabku\0Cyrlku\0Yeziky\0Arabky\0Latnmn\0Mongpa\0Arabsd\0Devasd\0Khojsd\0Sindtg\0Arabug\0Cyrluz\0ArabyueHanszh\0Bopozh\0Hanbzh\0Hant") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"IR\0GB\0GN\0CN\0IQ\0AM\0GE\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0KZ\0AF\0CN\0TW\0TW\0TW\0") }) @@ -33,26 +33,26 @@ macro_rules! __impl_locale_likely_subtags_language_v1 { }, language: unsafe { #[allow(unused_unsafe)] - zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"af\0ak\0am\0ar\0as\0astaz\0ba\0balbe\0bg\0bgcbhoblobn\0br\0brxbs\0buaca\0cebchrcs\0cswcv\0cy\0da\0de\0doidsbee\0el\0en\0eo\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0fy\0ga\0gaagd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ie\0ig\0ii\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ku\0kxvky\0lb\0lijlmolo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0mt\0my\0ndsne\0nl\0nn\0no\0nqonsooc\0om\0or\0pa\0pcmpl\0pmsps\0pt\0qu\0rajrm\0ro\0ru\0rw\0sa\0sahsatsc\0scnsd\0shnsi\0sk\0sl\0so\0sq\0sr\0st\0su\0sv\0sw\0syrszlta\0te\0tg\0th\0ti\0tk\0tn\0to\0tr\0tt\0tyvug\0uk\0ur\0uz\0vecvi\0vmwwo\0xh\0xnryo\0yrlyueza\0zh\0zu\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"LatnZA\0LatnGH\0EthiET\0ArabEG\0BengIN\0LatnES\0LatnAZ\0CyrlRU\0ArabPK\0CyrlBY\0CyrlBG\0DevaIN\0DevaIN\0LatnBJ\0BengBD\0LatnFR\0DevaIN\0LatnBA\0CyrlRU\0LatnES\0LatnPH\0CherUS\0LatnCZ\0CansCA\0CyrlRU\0LatnGB\0LatnDK\0LatnDE\0DevaIN\0LatnDE\0LatnGH\0GrekGR\0LatnUS\0Latn001LatnES\0LatnEE\0LatnES\0ArabIR\0LatnSN\0LatnFI\0LatnPH\0LatnFO\0LatnFR\0LatnNL\0LatnIE\0LatnGH\0LatnGB\0LatnES\0GujrIN\0LatnNG\0HebrIL\0DevaIN\0LatnHR\0LatnDE\0LatnHU\0ArmnAM\0Latn001LatnID\0LatnEE\0LatnNG\0YiiiCN\0LatnIS\0LatnIT\0JpanJP\0LatnID\0GeorGE\0LatnCV\0LatnBR\0CyrlKZ\0KhmrKH\0KndaIN\0KoreKR\0DevaIN\0ArabIN\0LatnTR\0LatnIN\0CyrlKG\0LatnLU\0LatnIT\0LatnIT\0LaooLA\0LatnLT\0LatnLV\0DevaIN\0LatnNZ\0CyrlMK\0MlymIN\0CyrlMN\0BengIN\0DevaIN\0LatnMY\0LatnMT\0MymrMM\0LatnDE\0DevaNP\0LatnNL\0LatnNO\0LatnNO\0NkooGN\0LatnZA\0LatnFR\0LatnET\0OryaIN\0GuruIN\0LatnNG\0LatnPL\0LatnIT\0ArabAF\0LatnBR\0LatnPE\0DevaIN\0LatnCH\0LatnRO\0CyrlRU\0LatnRW\0DevaIN\0CyrlRU\0OlckIN\0LatnIT\0LatnIT\0ArabPK\0MymrMM\0SinhLK\0LatnSK\0LatnSI\0LatnSO\0LatnAL\0CyrlRS\0LatnZA\0LatnID\0LatnSE\0LatnTZ\0SyrcIQ\0LatnPL\0TamlIN\0TeluIN\0CyrlTJ\0ThaiTH\0EthiET\0LatnTM\0LatnZA\0LatnTO\0LatnTR\0CyrlRU\0CyrlRU\0ArabCN\0CyrlUA\0ArabPK\0LatnUZ\0LatnIT\0LatnVN\0LatnMZ\0LatnSN\0LatnZA\0DevaIN\0LatnNG\0LatnBR\0HantHK\0LatnCN\0HansCN\0LatnZA\0") }) + zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"adyaf\0ak\0am\0ar\0as\0astaz\0ba\0balbe\0bg\0bgcbhoblobn\0br\0brxbs\0buaca\0cebchrckbcopcs\0cswcv\0cy\0da\0de\0doidsbee\0el\0en\0eo\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0fy\0ga\0gaagd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ie\0ig\0ii\0is\0it\0ja\0jv\0ka\0kbdkeakekkgpki\0kk\0km\0kn\0ko\0kokks\0kshku\0kxvky\0lb\0lijlldlmolo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0mt\0my\0ndsne\0nl\0nn\0no\0nqonsooc\0om\0or\0pa\0pcmpl\0pmsprgps\0pt\0qu\0qucrajrm\0ro\0ru\0rw\0sa\0sahsatsc\0scnsd\0shnsi\0sk\0sl\0so\0sq\0sr\0st\0su\0suzsv\0sw\0syrszlta\0te\0tg\0th\0ti\0tk\0tn\0to\0tr\0tt\0tyvug\0uk\0ur\0uz\0vecvi\0vmwwo\0xh\0xnryo\0yrlyueza\0zh\0zu\0") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"CyrlRU\0LatnZA\0LatnGH\0EthiET\0ArabEG\0BengIN\0LatnES\0LatnAZ\0CyrlRU\0ArabPK\0CyrlBY\0CyrlBG\0DevaIN\0DevaIN\0LatnBJ\0BengBD\0LatnFR\0DevaIN\0LatnBA\0CyrlRU\0LatnES\0LatnPH\0CherUS\0ArabIQ\0CoptEG\0LatnCZ\0CansCA\0CyrlRU\0LatnGB\0LatnDK\0LatnDE\0DevaIN\0LatnDE\0LatnGH\0GrekGR\0LatnUS\0Latn001LatnES\0LatnEE\0LatnES\0ArabIR\0LatnSN\0LatnFI\0LatnPH\0LatnFO\0LatnFR\0LatnNL\0LatnIE\0LatnGH\0LatnGB\0LatnES\0GujrIN\0LatnNG\0HebrIL\0DevaIN\0LatnHR\0LatnDE\0LatnHU\0ArmnAM\0Latn001LatnID\0LatnEE\0LatnNG\0YiiiCN\0LatnIS\0LatnIT\0JpanJP\0LatnID\0GeorGE\0CyrlRU\0LatnCV\0LatnGT\0LatnBR\0LatnKE\0CyrlKZ\0KhmrKH\0KndaIN\0KoreKR\0DevaIN\0ArabIN\0LatnDE\0LatnTR\0LatnIN\0CyrlKG\0LatnLU\0LatnIT\0LatnIT\0LatnIT\0LaooLA\0LatnLT\0LatnLV\0DevaIN\0LatnNZ\0CyrlMK\0MlymIN\0CyrlMN\0BengIN\0DevaIN\0LatnMY\0LatnMT\0MymrMM\0LatnDE\0DevaNP\0LatnNL\0LatnNO\0LatnNO\0NkooGN\0LatnZA\0LatnFR\0LatnET\0OryaIN\0GuruIN\0LatnNG\0LatnPL\0LatnIT\0LatnPL\0ArabAF\0LatnBR\0LatnPE\0LatnGT\0DevaIN\0LatnCH\0LatnRO\0CyrlRU\0LatnRW\0DevaIN\0CyrlRU\0OlckIN\0LatnIT\0LatnIT\0ArabPK\0MymrMM\0SinhLK\0LatnSK\0LatnSI\0LatnSO\0LatnAL\0CyrlRS\0LatnZA\0LatnID\0DevaNP\0LatnSE\0LatnTZ\0SyrcIQ\0LatnPL\0TamlIN\0TeluIN\0CyrlTJ\0ThaiTH\0EthiET\0LatnTM\0LatnZA\0LatnTO\0LatnTR\0CyrlRU\0CyrlRU\0ArabCN\0CyrlUA\0ArabPK\0LatnUZ\0LatnIT\0LatnVN\0LatnMZ\0LatnSN\0LatnZA\0DevaIN\0LatnNG\0LatnBR\0HantHK\0LatnCN\0HansCN\0LatnZA\0") }) }, und: (icu_locale_core::subtags::language!("en"), icu_locale_core::subtags::script!("Latn"), icu_locale_core::subtags::region!("US")), }; } - #[clippy::msrv = "1.86"] - impl icu_provider::DataProvider<icu::locale::provider::LocaleLikelySubtagsLanguageV1> for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::provider::LocaleLikelySubtagsLanguageV1>, icu_provider::DataError> { + #[clippy::msrv = "1.88"] + impl icu_provider::DataProvider<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1> for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1>, icu_provider::DataError> { if req.id.locale.is_unknown() { Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1), metadata: icu_provider::DataResponseMetadata::default() }) } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DataMarker>::INFO, req)) + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DataMarker>::INFO, req)) } } } }; ($ provider : ty , ITER) => { __impl_locale_likely_subtags_language_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleLikelySubtagsLanguageV1> for $provider { + #[clippy::msrv = "1.88"] + impl icu_provider::IterableDataProvider<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1> for $provider { fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) } @@ -60,31 +60,31 @@ macro_rules! __impl_locale_likely_subtags_language_v1 { }; ($ provider : ty , DRY) => { __impl_locale_likely_subtags_language_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleLikelySubtagsLanguageV1> for $provider { + #[clippy::msrv = "1.88"] + impl icu_provider::DryDataProvider<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1> for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { if req.id.locale.is_unknown() { Ok(icu_provider::DataResponseMetadata::default()) } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DataMarker>::INFO, req)) + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DataMarker>::INFO, req)) } } } }; ($ provider : ty , DRY , ITER) => { __impl_locale_likely_subtags_language_v1!($provider); - #[clippy::msrv = "1.86"] - impl icu_provider::DryDataProvider<icu::locale::provider::LocaleLikelySubtagsLanguageV1> for $provider { + #[clippy::msrv = "1.88"] + impl icu_provider::DryDataProvider<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1> for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { if req.id.locale.is_unknown() { Ok(icu_provider::DataResponseMetadata::default()) } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DataMarker>::INFO, req)) + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1 as icu_provider::DataMarker>::INFO, req)) } } } - #[clippy::msrv = "1.86"] - impl icu_provider::IterableDataProvider<icu::locale::provider::LocaleLikelySubtagsLanguageV1> for $provider { + #[clippy::msrv = "1.88"] + impl icu_provider::IterableDataProvider<icu::locale::fallback::provider::LocaleLikelySubtagsLanguageV1> for $provider { fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) } diff --git a/deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_parents_v1.rs.data b/deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_parents_v1.rs.data new file mode 100644 index 000000000000..7b5a03061a74 --- /dev/null +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/data/locale_parents_v1.rs.data @@ -0,0 +1,85 @@ +// @generated +/// Implement `DataProvider<LocaleParentsV1>` on the given struct using the data +/// hardcoded in this file. This allows the struct to be used with +/// `icu`'s `_unstable` constructors. +/// +/// Using this implementation will embed the following data in the binary's data segment: +/// * 2925B[^1] for the singleton data struct +/// +/// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu` +/// * `icu_provider` +/// * `zerovec` +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_locale_parents_v1 { + ($ provider : ty) => { + #[clippy::msrv = "1.88"] + const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; + #[clippy::msrv = "1.88"] + impl $provider { + #[doc(hidden)] + pub const SINGLETON_LOCALE_PARENTS_V1: &'static <icu::locale::fallback::provider::LocaleParentsV1 as icu_provider::DynamicDataMarker>::DataStruct = &icu_locale_fallback::provider::Parents { + parents: unsafe { + #[allow(unused_unsafe)] + zerovec::ZeroMap::from_parts_unchecked(unsafe { zerovec::vecs::VarZeroVec16::from_bytes_unchecked(b"\x97\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02E\x02J\x02O\x02T\x02Y\x02^\x02c\x02h\x02m\x02r\x02w\x02|\x02\x81\x02\x86\x02\x8B\x02\x90\x02\x95\x02\x9A\x02\xA1\x02\xA3\x02\xA5\x02\xAA\x02\xAF\x02\xB4\x02\xB9\x02\xBE\x02\xC3\x02\xC8\x02\xCD\x02\xD2\x02\xD7\x02\xDC\x02\xE1\x02\xE9\x02\xF1\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-CZen-DEen-DGen-DKen-DMen-EEen-ERen-ESen-FIen-FJen-FKen-FMen-FRen-GBen-GDen-GEen-GGen-GHen-GIen-GMen-GSen-GYen-HKen-HUen-IDen-IEen-ILen-IMen-INen-IOen-ITen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-LTen-LVen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NOen-NRen-NUen-NZen-PGen-PKen-PLen-PNen-PTen-PWen-ROen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SKen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UAen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-JPes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLund-Hansund-Hantzh-Hant-MO") }, unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0und\x01Hani\0\0\0\0und\x01Hani\0\0\0\0zh\0\x01Hant\x01HK\0") }) + }, + }; + } + #[clippy::msrv = "1.88"] + impl icu_provider::DataProvider<icu::locale::fallback::provider::LocaleParentsV1> for $provider { + fn load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponse<icu::locale::fallback::provider::LocaleParentsV1>, icu_provider::DataError> { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_LOCALE_PARENTS_V1), metadata: icu_provider::DataResponseMetadata::default() }) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::fallback::provider::LocaleParentsV1 as icu_provider::DataMarker>::INFO, req)) + } + } + } + }; + ($ provider : ty , ITER) => { + __impl_locale_parents_v1!($provider); + #[clippy::msrv = "1.88"] + impl icu_provider::IterableDataProvider<icu::locale::fallback::provider::LocaleParentsV1> for $provider { + fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { + Ok([Default::default()].into_iter().collect()) + } + } + }; + ($ provider : ty , DRY) => { + __impl_locale_parents_v1!($provider); + #[clippy::msrv = "1.88"] + impl icu_provider::DryDataProvider<icu::locale::fallback::provider::LocaleParentsV1> for $provider { + fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponseMetadata::default()) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::fallback::provider::LocaleParentsV1 as icu_provider::DataMarker>::INFO, req)) + } + } + } + }; + ($ provider : ty , DRY , ITER) => { + __impl_locale_parents_v1!($provider); + #[clippy::msrv = "1.88"] + impl icu_provider::DryDataProvider<icu::locale::fallback::provider::LocaleParentsV1> for $provider { + fn dry_load(&self, req: icu_provider::DataRequest) -> Result<icu_provider::DataResponseMetadata, icu_provider::DataError> { + if req.id.locale.is_unknown() { + Ok(icu_provider::DataResponseMetadata::default()) + } else { + Err(icu_provider::DataErrorKind::InvalidRequest.with_req(<icu::locale::fallback::provider::LocaleParentsV1 as icu_provider::DataMarker>::INFO, req)) + } + } + } + #[clippy::msrv = "1.88"] + impl icu_provider::IterableDataProvider<icu::locale::fallback::provider::LocaleParentsV1> for $provider { + fn iter_ids(&self) -> Result<std::collections::BtreeSet<icu_provider::DataIdentifierCow<'static>>, icu_provider::DataError> { + Ok([Default::default()].into_iter().collect()) + } + } + }; +} +#[doc(inline)] +pub use __impl_locale_parents_v1 as impl_locale_parents_v1; diff --git a/deps/crates/vendor/icu_locale_data-v2/data/mod.rs b/deps/crates/vendor/icu_locale_fallback_data-v2/data/mod.rs similarity index 50% rename from deps/crates/vendor/icu_locale_data-v2/data/mod.rs rename to deps/crates/vendor/icu_locale_fallback_data-v2/data/mod.rs index 7c7d6e9205a8..64a609084f4c 100644 --- a/deps/crates/vendor/icu_locale_data-v2/data/mod.rs +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/data/mod.rs @@ -1,15 +1,6 @@ // @generated include!("locale_likely_subtags_language_v1.rs.data"); include!("locale_parents_v1.rs.data"); -include!("locale_exemplar_characters_main_v1.rs.data"); -include!("locale_exemplar_characters_numbers_v1.rs.data"); -include!("locale_aliases_v1.rs.data"); -include!("locale_exemplar_characters_index_v1.rs.data"); -include!("locale_exemplar_characters_auxiliary_v1.rs.data"); -include!("locale_likely_subtags_extended_v1.rs.data"); -include!("locale_script_direction_v1.rs.data"); -include!("locale_likely_subtags_script_region_v1.rs.data"); -include!("locale_exemplar_characters_punctuation_v1.rs.data"); /// Marks a type as a data provider. You can then use macros like /// `impl_core_helloworld_v1` to add implementations. /// @@ -25,7 +16,7 @@ include!("locale_exemplar_characters_punctuation_v1.rs.data"); #[macro_export] macro_rules! __make_provider { ($ name : ty) => { - #[clippy::msrv = "1.86"] + #[clippy::msrv = "1.88"] impl $name { #[allow(dead_code)] pub(crate) const MUST_USE_MAKE_PROVIDER_MACRO: () = (); @@ -39,7 +30,6 @@ pub use __make_provider as make_provider; /// * `icu` /// * `icu_locale_core` /// * `icu_provider` -/// * `icu_provider/baked` /// * `zerovec` #[allow(unused_macros)] macro_rules! impl_data_provider { @@ -47,14 +37,5 @@ macro_rules! impl_data_provider { make_provider!($provider); impl_locale_likely_subtags_language_v1!($provider); impl_locale_parents_v1!($provider); - impl_locale_exemplar_characters_main_v1!($provider); - impl_locale_exemplar_characters_numbers_v1!($provider); - impl_locale_aliases_v1!($provider); - impl_locale_exemplar_characters_index_v1!($provider); - impl_locale_exemplar_characters_auxiliary_v1!($provider); - impl_locale_likely_subtags_extended_v1!($provider); - impl_locale_script_direction_v1!($provider); - impl_locale_likely_subtags_script_region_v1!($provider); - impl_locale_exemplar_characters_punctuation_v1!($provider); }; } diff --git a/deps/crates/vendor/icu_locale_data-v2/src/lib.rs b/deps/crates/vendor/icu_locale_fallback_data-v2/src/lib.rs similarity index 55% rename from deps/crates/vendor/icu_locale_data-v2/src/lib.rs rename to deps/crates/vendor/icu_locale_fallback_data-v2/src/lib.rs index c48d43734e1a..b9549928abf2 100644 --- a/deps/crates/vendor/icu_locale_data-v2/src/lib.rs +++ b/deps/crates/vendor/icu_locale_fallback_data-v2/src/lib.rs @@ -2,9 +2,9 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! Data for the `icu_locale` crate +//! Data for the `icu_locale_fallback` crate //! -//! This data was generated with CLDR version 48.2.0, ICU version release-78.1rc, and +//! This data was generated with CLDR version 49.0.0, Unicode version 18.0.0, and //! LSTM segmenter version v0.1.0. #![no_std] @@ -15,3 +15,24 @@ include!(concat!(core::env!("ICU4X_DATA_DIR"), "/mod.rs")); #[cfg(not(icu4x_custom_data))] include!("../data/mod.rs"); + +#[macro_export] +macro_rules! cldr_tag { + () => { + "49.0.0" + }; +} + +#[macro_export] +macro_rules! unicode_tag { + () => { + "18.0.0" + }; +} + +#[macro_export] +macro_rules! segmenter_lstm_tag { + () => { + "v0.1.0" + }; +} diff --git a/deps/crates/vendor/icu_provider-v2/.cargo_vcs_info.json b/deps/crates/vendor/icu_provider-v2/.cargo_vcs_info.json index d680756d7ab1..a4894345b782 100644 --- a/deps/crates/vendor/icu_provider-v2/.cargo_vcs_info.json +++ b/deps/crates/vendor/icu_provider-v2/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "898d79c69f37da7b45a15a5714663c9b59b3d928" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "provider/core" } \ No newline at end of file diff --git a/deps/crates/vendor/icu_provider-v2/Cargo.lock b/deps/crates/vendor/icu_provider-v2/Cargo.lock index 01d0545d4c94..aa74d37bff73 100644 --- a/deps/crates/vendor/icu_provider-v2/Cargo.lock +++ b/deps/crates/vendor/icu_provider-v2/Cargo.lock @@ -52,9 +52,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "ciborium" @@ -85,18 +85,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cobs" @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -165,18 +165,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -197,13 +197,13 @@ dependencies = [ [[package]] name = "databake-derive" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b537745234cbf0e296a3bd836d70a614dff4cb522b14e2680ef006bb1ed5ff" +checksum = "495503291b258422ea2bb9863d9f4e31eadbc5bcbdbe8b721769fa2c98dc4d41" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -215,14 +215,14 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "either" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "erased-serde" @@ -247,15 +247,15 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "icu_locale_core" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", @@ -266,7 +266,7 @@ dependencies = [ [[package]] name = "icu_provider" -version = "2.3.1" +version = "2.4.0" dependencies = [ "bincode", "criterion", @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "litemap" @@ -336,9 +336,9 @@ checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "log" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "memchr" @@ -514,14 +514,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -549,9 +549,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -560,13 +560,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] [[package]] @@ -586,14 +586,14 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "tinystr" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", "serde_core", @@ -618,9 +618,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "walkdir" @@ -719,9 +719,9 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -730,13 +730,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -751,13 +751,13 @@ dependencies = [ [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -773,9 +773,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "databake", "serde", @@ -785,13 +785,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] diff --git a/deps/crates/vendor/icu_provider-v2/Cargo.toml b/deps/crates/vendor/icu_provider-v2/Cargo.toml index 5961ca1a83e9..f5470dc9689d 100644 --- a/deps/crates/vendor/icu_provider-v2/Cargo.toml +++ b/deps/crates/vendor/icu_provider-v2/Cargo.toml @@ -13,7 +13,7 @@ edition = "2024" rust-version = "1.88" name = "icu_provider" -version = "2.3.1" +version = "2.4.0" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -131,7 +131,7 @@ version = "0.4.0" optional = true [dependencies.icu_locale_core] -version = "2.3.0" +version = "2.4.0" default-features = false [dependencies.log] @@ -165,7 +165,7 @@ optional = true default-features = false [dependencies.yoke] -version = "0.8.3" +version = "0.8.4" features = ["derive"] default-features = false @@ -180,7 +180,7 @@ optional = true default-features = false [dependencies.zerovec] -version = "0.11.8" +version = "0.11.9" features = ["derive"] default-features = false diff --git a/deps/crates/vendor/icu_provider-v2/Cargo.toml.orig b/deps/crates/vendor/icu_provider-v2/Cargo.toml.orig index d66a7b99c938..23b5dd4cfd6a 100644 --- a/deps/crates/vendor/icu_provider-v2/Cargo.toml.orig +++ b/deps/crates/vendor/icu_provider-v2/Cargo.toml.orig @@ -15,7 +15,7 @@ include.workspace = true license.workspace = true repository.workspace = true rust-version.workspace = true -version = "2.3.1" +version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/deps/crates/vendor/icu_provider-v2/src/export/mod.rs b/deps/crates/vendor/icu_provider-v2/src/export/mod.rs index c6aea2ebced6..1a95239952e0 100644 --- a/deps/crates/vendor/icu_provider-v2/src/export/mod.rs +++ b/deps/crates/vendor/icu_provider-v2/src/export/mod.rs @@ -129,12 +129,12 @@ macro_rules! __make_exportable_provider { ($provider:ty, [ $($(#[$cfg:meta])? $struct_m:ty),+, ]) => { impl $crate::export::ExportableProvider for $provider { fn supported_markers(&self) -> alloc::collections::BTreeSet<$crate::DataMarkerInfo> { - alloc::collections::BTreeSet::from_iter([ - $( - $(#[$cfg])? - <$struct_m>::INFO, - )+ - ]) + let mut r = alloc::collections::BTreeSet::new(); + $( + $(#[$cfg])? + r.insert(<$struct_m>::INFO); + )+ + r } } diff --git a/deps/crates/vendor/ixdtf-v0_6/.cargo_vcs_info.json b/deps/crates/vendor/ixdtf-v0_6/.cargo_vcs_info.json index ebe60890da79..e54e86910361 100644 --- a/deps/crates/vendor/ixdtf-v0_6/.cargo_vcs_info.json +++ b/deps/crates/vendor/ixdtf-v0_6/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "a14f2dad852be26bad277ae704abf27a15cbfed1" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "utils/ixdtf" } \ No newline at end of file diff --git a/deps/crates/vendor/ixdtf-v0_6/Cargo.lock b/deps/crates/vendor/ixdtf-v0_6/Cargo.lock index bc497c3c61a6..b9999d9ea2eb 100644 --- a/deps/crates/vendor/ixdtf-v0_6/Cargo.lock +++ b/deps/crates/vendor/ixdtf-v0_6/Cargo.lock @@ -43,9 +43,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "ciborium" @@ -76,18 +76,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -95,9 +95,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "criterion" @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -147,18 +147,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -168,9 +168,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "either" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "half" @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "is-terminal" @@ -216,7 +216,7 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "ixdtf" -version = "0.6.6" +version = "0.6.7" dependencies = [ "criterion", "serde-json-core", @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "memchr" @@ -418,14 +418,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -447,9 +447,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -468,9 +468,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "walkdir" diff --git a/deps/crates/vendor/ixdtf-v0_6/Cargo.toml b/deps/crates/vendor/ixdtf-v0_6/Cargo.toml index bc0533fbdabe..2368cd894725 100644 --- a/deps/crates/vendor/ixdtf-v0_6/Cargo.toml +++ b/deps/crates/vendor/ixdtf-v0_6/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.82" name = "ixdtf" -version = "0.6.6" +version = "0.6.7" authors = ["The ICU4X Project Developers"] build = false include = [ diff --git a/deps/crates/vendor/ixdtf-v0_6/Cargo.toml.orig b/deps/crates/vendor/ixdtf-v0_6/Cargo.toml.orig index 369b77dd8f2d..6f0225cc61a4 100644 --- a/deps/crates/vendor/ixdtf-v0_6/Cargo.toml.orig +++ b/deps/crates/vendor/ixdtf-v0_6/Cargo.toml.orig @@ -5,7 +5,7 @@ [package] name = "ixdtf" description = "Parser for Internet eXtended DateTime Format" -version = "0.6.6" +version = "0.6.7" categories.workspace = true keywords = ["iso8601", "date-time"] diff --git a/deps/crates/vendor/ixdtf-v0_6/src/core.rs b/deps/crates/vendor/ixdtf-v0_6/src/core.rs index a24a04cb347b..5668ac7d2c75 100644 --- a/deps/crates/vendor/ixdtf-v0_6/src/core.rs +++ b/deps/crates/vendor/ixdtf-v0_6/src/core.rs @@ -38,11 +38,6 @@ impl<'a, T: EncodingType> Cursor<'a, T> { self.pos = pos; } - /// Peek the value at next position (current + 1). - pub(crate) fn peek(&self) -> ParserResult<Option<u8>> { - self.peek_n(1) - } - /// Returns current position in source as `char`. pub(crate) fn current(&self) -> ParserResult<Option<u8>> { self.peek_n(0) @@ -76,6 +71,17 @@ impl<'a, T: EncodingType> Cursor<'a, T> { result } + /// Advances the cursor and returns the current char if it satisfies `f`. + pub(crate) fn next_if(&mut self, f: impl FnOnce(u8) -> bool) -> ParserResult<Option<u8>> { + if let Some(ch) = self.current()? { + if f(ch) { + self.advance(); + return Ok(Some(ch)); + } + } + Ok(None) + } + /// Returns the next value as a digit /// /// # Errors diff --git a/deps/crates/vendor/ixdtf-v0_6/src/parsers/annotations.rs b/deps/crates/vendor/ixdtf-v0_6/src/parsers/annotations.rs index 6ddb55b5152c..9b43b310a82c 100644 --- a/deps/crates/vendor/ixdtf-v0_6/src/parsers/annotations.rs +++ b/deps/crates/vendor/ixdtf-v0_6/src/parsers/annotations.rs @@ -128,23 +128,19 @@ fn parse_annotation_key<'a, T: EncodingType>( ) -> ParserResult<&'a [T::CodeUnit]> { let key_start = cursor.pos(); assert_syntax!( - is_a_key_leading_char(cursor.next_or(ParseError::AnnotationKeyLeadingChar)?), + cursor.next_if(is_a_key_leading_char)?.is_some(), AnnotationKeyLeadingChar, ); - while let Some(potential_key_char) = cursor.next()? { - // End of key. - if cursor.check_or(false, is_annotation_key_value_separator)? { - // Return found key - return cursor - .slice(key_start, cursor.pos()) - .ok_or(ParseError::ImplAssert); - } - + while let Some(potential_key_char) = + cursor.next_if(|ch| !is_annotation_key_value_separator(ch))? + { assert_syntax!(is_a_key_char(potential_key_char), AnnotationKeyChar); } - Err(ParseError::AnnotationChar) + cursor + .slice(key_start, cursor.pos()) + .ok_or(ParseError::ImplAssert) } /// Parse an `AnnotationValue`. @@ -152,21 +148,16 @@ fn parse_annotation_value<'a, T: EncodingType>( cursor: &mut Cursor<'a, T>, ) -> ParserResult<&'a [T::CodeUnit]> { let value_start = cursor.pos(); - cursor.advance(); - while let Some(potential_value_char) = cursor.next()? { - if cursor.check_or(false, is_annotation_close)? { - // Return the determined AnnotationValue. - return cursor - .slice(value_start, cursor.pos()) - .ok_or(ParseError::ImplAssert); - } - + assert_syntax!( + cursor.next_if(is_annotation_value_component)?.is_some(), + AnnotationValueChar, + ); + while let Some(potential_value_char) = cursor.next_if(|ch| !is_annotation_close(ch))? { if is_hyphen(potential_value_char) { assert_syntax!( - cursor.peek()?.is_some_and(is_annotation_value_component), + cursor.next_if(is_annotation_value_component)?.is_some(), AnnotationValueCharPostHyphen, ); - cursor.advance(); continue; } @@ -176,5 +167,7 @@ fn parse_annotation_value<'a, T: EncodingType>( ); } - Err(ParseError::AnnotationValueChar) + cursor + .slice(value_start, cursor.pos()) + .ok_or(ParseError::ImplAssert) } diff --git a/deps/crates/vendor/ixdtf-v0_6/src/parsers/tests.rs b/deps/crates/vendor/ixdtf-v0_6/src/parsers/tests.rs index f51081ca3c37..ce77bec894c1 100644 --- a/deps/crates/vendor/ixdtf-v0_6/src/parsers/tests.rs +++ b/deps/crates/vendor/ixdtf-v0_6/src/parsers/tests.rs @@ -93,7 +93,7 @@ fn bad_zoned_date_time() { let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, - Err(ParseError::AnnotationClose), + Err(ParseError::IanaChar), "Invalid ZonedDateTime parsing: \"{bad_value}\" should fail to parse." ); @@ -1528,3 +1528,70 @@ fn utf16_basic_test() { }; assert_eq!(String::from_utf16_lossy(id), "America/Chicago"); } + +#[test] +fn annotation_and_timezone_validation_regression_8620() { + use super::TimeZoneParser; + + let valid_annotations = [ + ("2020-01-01[a=b]", None), + ("2020-01-01[_a=b]", None), + ("2020-01-01[u-ca=g]", Some("g")), + ("2020-01-01[u-ca=a-b]", Some("a-b")), + ("2020-01-01[u-ca=a-bc-d]", Some("a-bc-d")), + ]; + for (input, expected_cal) in valid_annotations { + let parsed = IxdtfParser::from_str(input).parse().expect(input); + assert_eq!(parsed.calendar, expected_cal.map(str::as_bytes), "{input}"); + } + + let invalid_annotations = [ + ("2020-01-01[u-cA=iso8601]", ParseError::AnnotationKeyChar), + ("2020-01-01[aB=iso8601]", ParseError::AnnotationKeyChar), + ("2020-01-01[u-ca=iso8601!]", ParseError::AnnotationValueChar), + ("2020-01-01[u-ca=!iso8601]", ParseError::AnnotationValueChar), + ("2020-01-01[u-ca=!!]", ParseError::AnnotationValueChar), + ("2020-01-01[u-ca=-iso]", ParseError::AnnotationValueChar), + ( + "2020-01-01[u-ca=iso-]", + ParseError::AnnotationValueCharPostHyphen, + ), + ( + "2020-01-01[u-ca=iso--8601]", + ParseError::AnnotationValueCharPostHyphen, + ), + ]; + for (input, expected_err) in invalid_annotations { + let err = IxdtfParser::from_str(input).parse().unwrap_err(); + assert_eq!(err, expected_err, "{input}"); + } + + let invalid_tz_annotations = [ + ("2020-01-01[America/Chicago!]", ParseError::IanaChar), + ("2020-01-01[UTC!]", ParseError::IanaChar), + ("2020-01-01[cet!]", ParseError::IanaChar), + ("2020-01-01[America/]", ParseError::IanaCharPostSeparator), + ( + "2020-01-01[America//Chicago]", + ParseError::IanaCharPostSeparator, + ), + ]; + for (input, expected_err) in invalid_tz_annotations { + let err = IxdtfParser::from_str(input).parse().unwrap_err(); + assert_eq!(err, expected_err, "{input}"); + } + + let invalid_bare_iana = [ + ("America/Chicago!", ParseError::IanaChar), + ("UTC!", ParseError::IanaChar), + ("America/", ParseError::IanaCharPostSeparator), + ("America//Chicago", ParseError::IanaCharPostSeparator), + ("1America/Chicago", ParseError::TzLeadingChar), + ]; + for (input, expected_err) in invalid_bare_iana { + let err = TimeZoneParser::from_str(input) + .parse_iana_identifier() + .unwrap_err(); + assert_eq!(err, expected_err, "{input}"); + } +} diff --git a/deps/crates/vendor/ixdtf-v0_6/src/parsers/timezone.rs b/deps/crates/vendor/ixdtf-v0_6/src/parsers/timezone.rs index 9b51cbc7338c..abf0520e9ddd 100644 --- a/deps/crates/vendor/ixdtf-v0_6/src/parsers/timezone.rs +++ b/deps/crates/vendor/ixdtf-v0_6/src/parsers/timezone.rs @@ -130,20 +130,15 @@ pub(crate) fn parse_time_zone<'a, T: EncodingType>( pub(crate) fn parse_tz_iana_name<'a, T: EncodingType>( cursor: &mut Cursor<'a, T>, ) -> ParserResult<&'a [T::CodeUnit]> { - assert_syntax!(cursor.check_or(false, is_tz_leading_char)?, TzLeadingChar); let tz_name_start = cursor.pos(); - while let Some(potential_value_char) = cursor.next()? { - if cursor.check_or(true, is_annotation_close)? { - // Return the valid TimeZoneIANAName - break; - } - + assert_syntax!(cursor.next_if(is_tz_leading_char)?.is_some(), TzLeadingChar,); + while let Some(potential_value_char) = cursor.next_if(|ch| !is_annotation_close(ch))? { if is_tz_name_separator(potential_value_char) { - assert_syntax!(cursor.check_or(false, is_tz_char)?, IanaCharPostSeparator,); + assert_syntax!(cursor.next_if(is_tz_char)?.is_some(), IanaCharPostSeparator,); continue; } - assert_syntax!(is_tz_char(potential_value_char), IanaChar,); + assert_syntax!(is_tz_char(potential_value_char), IanaChar); } cursor diff --git a/deps/crates/vendor/smallvec-v1/.cargo_vcs_info.json b/deps/crates/vendor/smallvec-v1/.cargo_vcs_info.json index ff8f1a264e7f..130e6c6c48c3 100644 --- a/deps/crates/vendor/smallvec-v1/.cargo_vcs_info.json +++ b/deps/crates/vendor/smallvec-v1/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "700e1c3ff899cda7799b18e0804889105fc8beea" + "sha1": "ccf5fc71044d491c46a3d79e7ed53948e6da1590" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/deps/crates/vendor/smallvec-v1/Cargo.lock b/deps/crates/vendor/smallvec-v1/Cargo.lock index 9f66f69caf8a..c0d3765cb6b6 100644 --- a/deps/crates/vendor/smallvec-v1/Cargo.lock +++ b/deps/crates/vendor/smallvec-v1/Cargo.lock @@ -81,7 +81,7 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.16.1" +version = "1.16.2" dependencies = [ "arbitrary", "bincode 1.3.3", @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" dependencies = [ "proc-macro2", "quote", @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" [[package]] name = "unty" diff --git a/deps/crates/vendor/smallvec-v1/Cargo.toml b/deps/crates/vendor/smallvec-v1/Cargo.toml index 32ea355150ea..2875e120cbe5 100644 --- a/deps/crates/vendor/smallvec-v1/Cargo.toml +++ b/deps/crates/vendor/smallvec-v1/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "smallvec" -version = "1.16.1" +version = "1.16.2" authors = ["The Servo Project Developers"] build = false include = [ diff --git a/deps/crates/vendor/smallvec-v1/Cargo.toml.orig b/deps/crates/vendor/smallvec-v1/Cargo.toml.orig index 0d64acc35564..a833c63e2e3d 100644 --- a/deps/crates/vendor/smallvec-v1/Cargo.toml.orig +++ b/deps/crates/vendor/smallvec-v1/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "smallvec" -version = "1.16.1" +version = "1.16.2" edition = "2018" authors = ["The Servo Project Developers"] license = "MIT OR Apache-2.0" @@ -8,7 +8,6 @@ repository = "https://github.com/servo/rust-smallvec" description = "'Small vector' optimization: store up to a small number of items on the stack" keywords = ["small", "vec", "vector", "stack", "no_std"] categories = ["data-structures"] -readme = "README.md" documentation = "https://docs.rs/smallvec/" include = ["Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"] diff --git a/deps/crates/vendor/smallvec-v1/src/lib.rs b/deps/crates/vendor/smallvec-v1/src/lib.rs index 74080244f54b..8b25dc04b35a 100644 --- a/deps/crates/vendor/smallvec-v1/src/lib.rs +++ b/deps/crates/vendor/smallvec-v1/src/lib.rs @@ -113,8 +113,6 @@ extern crate std; #[cfg(test)] mod tests; -#[cfg(feature = "serde")] -use core::marker::PhantomData; #[cfg(feature = "drain_keep_rest")] use core::mem::ManuallyDrop; #[cfg(feature = "malloc_size_of")] @@ -140,6 +138,7 @@ use { hash::{Hash, Hasher}, hint::unreachable_unchecked, iter::{repeat, FromIterator, FusedIterator, IntoIterator}, + marker::PhantomData, mem::{self, MaybeUninit}, ops::{self, Range, RangeBounds}, ptr::{self, NonNull}, @@ -812,6 +811,25 @@ unsafe impl<A: Array + Sync> Sync for SmallVecData<A> {} /// assert_eq!(v.len(), 5); /// assert!(v.spilled()); /// ``` +/// +/// References used by an element's destructor must outlive the vector, even +/// with the `may_dangle` feature and no inline storage: +/// +/// ```compile_fail,E0597 +/// use smallvec::SmallVec; +/// +/// struct PrintOnDrop<'a>(&'a str); +/// impl Drop for PrintOnDrop<'_> { +/// fn drop(&mut self) { +/// println!("{}", self.0); +/// } +/// } +/// +/// let mut v = SmallVec::<[PrintOnDrop<'_>; 0]>::new(); +/// let text = String::from("borrowed"); +/// v.push(PrintOnDrop(&text)); +/// // `text` is dropped before `v`, whose elements still need it. +/// ``` pub struct SmallVec<A: Array> { // The capacity field is used to determine which of the storage variants is active: // If capacity <= Self::inline_capacity() then the inline variant is used and capacity holds @@ -820,6 +838,9 @@ pub struct SmallVec<A: Array> { // memory allocation. capacity: usize, data: SmallVecData<A>, + // Own A::Item, including when A has length zero and all items are on the heap. + // This is required for sound drop checking with #[may_dangle]. + _marker: PhantomData<A::Item>, } impl<A: Array> SmallVec<A> { @@ -835,6 +856,7 @@ impl<A: Array> SmallVec<A> { SmallVec { capacity: 0, data: SmallVecData::empty(), + _marker: PhantomData, } } @@ -886,6 +908,7 @@ impl<A: Array> SmallVec<A> { SmallVec { capacity: len, data, + _marker: PhantomData, } } } else { @@ -898,6 +921,7 @@ impl<A: Array> SmallVec<A> { SmallVec { capacity: cap, data: SmallVecData::from_heap(ptr, len), + _marker: PhantomData, } } } @@ -918,6 +942,7 @@ impl<A: Array> SmallVec<A> { SmallVec { capacity: A::size(), data: SmallVecData::from_inline(MaybeUninit::new(buf)), + _marker: PhantomData, } } @@ -957,6 +982,7 @@ impl<A: Array> SmallVec<A> { SmallVec { capacity: len, data: SmallVecData::from_inline(buf), + _marker: PhantomData, } } @@ -1623,16 +1649,104 @@ impl<A: Array> SmallVec<A> { /// `false`. This method operates in place and preserves the order of /// the retained elements. pub fn retain<F: FnMut(&mut A::Item) -> bool>(&mut self, mut f: F) { - let mut del = 0; - let len = self.len(); - for i in 0..len { - if !f(&mut self[i]) { - del += 1; - } else if del > 0 { - self.swap(i - del, i); + let original_len = self.len(); + + if original_len == 0 { + // Empty case: explicit return allows better optimization, vs + // letting compiler infer it + return; + } + + // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] + // | ^- write ^- read | + // |<- original_len ->| + // Kept: Elements which predicate returns true on. + // Hole: Moved or dropped element slot. + // Unchecked: Unchecked valid elements. + // + // This drop guard will be invoked when predicate or `drop` of element + // panicked. It shifts unchecked elements to cover holes and + // `set_len` to the correct length. In cases when predicate and + // `drop` never panic, it will be optimized out. + struct PanicGuard<'a, A: Array> { + v: &'a mut SmallVec<A>, + read: usize, + write: usize, + original_len: usize, + } + + impl<A: Array> Drop for PanicGuard<'_, A> { + #[cold] + fn drop(&mut self) { + let remaining = self.original_len - self.read; + // SAFETY: Trailing unchecked items must be valid since we never + // touch them. + unsafe { + let ptr = self.v.as_mut_ptr(); + ptr::copy(ptr.add(self.read), ptr.add(self.write), remaining); + } + // SAFETY: After filling holes, all items are in contiguous + // memory. + unsafe { + self.v.set_len(self.write + remaining); + } + } + } + + let mut read = 0; + loop { + // SAFETY: read < original_len + let cur = unsafe { self.get_unchecked_mut(read) }; + if !f(cur) { + break; + } + read += 1; + if read == original_len { + // All elements are kept, return early. + return; } } - self.truncate(len - del); + + // Critical section starts here and at least one element is going to be + // removed. Advance `g.read` early to avoid double drop if + // `drop_in_place` panicked. + let mut g = PanicGuard { + v: self, + read: read + 1, + write: read, + original_len, + }; + // SAFETY: previous `read` is always less than original_len. + unsafe { ptr::drop_in_place(g.v.as_mut_ptr().add(read)) } + + let ptr = g.v.as_mut_ptr(); + while g.read < g.original_len { + // SAFETY: `read` is always less than original_len. + let cur = unsafe { &mut *ptr.add(g.read) }; + if !f(cur) { + // Advance `read` early to avoid double drop if `drop_in_place` + // panicked. + g.read += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + } else { + // SAFETY: `read` > `write`, so the slots don't overlap. + // We use copy for move, and never touch the source element + // again. + unsafe { + let hole = ptr.add(g.write); + ptr::copy_nonoverlapping(cur, hole, 1); + } + g.write += 1; + g.read += 1; + } + } + + // We are leaving the critical section and no panic happened, + // Commit the length change and forget the guard. + // SAFETY: `write` is always less than or equal to original_len. + unsafe { g.v.set_len(g.write) }; + core::mem::forget(g); } /// Retains only the elements specified by the predicate. @@ -1820,6 +1934,7 @@ impl<A: Array> SmallVec<A> { SmallVec { capacity, data: SmallVecData::from_heap(ptr, length), + _marker: PhantomData, } } @@ -1862,6 +1977,7 @@ where ); data }), + _marker: PhantomData, } } else { let mut b = slice.to_vec(); @@ -1871,6 +1987,7 @@ where SmallVec { capacity: cap, data: SmallVecData::from_heap(ptr, len), + _marker: PhantomData, } } } @@ -2511,6 +2628,7 @@ impl<T, const N: usize> SmallVec<[T; N]> { SmallVec { capacity: 0, data: SmallVecData::from_const(MaybeUninit::uninit()), + _marker: PhantomData, } } @@ -2526,6 +2644,7 @@ impl<T, const N: usize> SmallVec<[T; N]> { SmallVec { capacity: N, data: SmallVecData::from_const(MaybeUninit::new(items)), + _marker: PhantomData, } } @@ -2542,6 +2661,7 @@ impl<T, const N: usize> SmallVec<[T; N]> { SmallVec { capacity: len, data: SmallVecData::from_const(MaybeUninit::new(items)), + _marker: PhantomData, } } } diff --git a/deps/crates/vendor/smallvec-v1/src/tests.rs b/deps/crates/vendor/smallvec-v1/src/tests.rs index e0118ccbfeff..99d992ec9e8d 100644 --- a/deps/crates/vendor/smallvec-v1/src/tests.rs +++ b/deps/crates/vendor/smallvec-v1/src/tests.rs @@ -13,6 +13,20 @@ pub fn test_zero() { assert_eq!(&*v, &[0]); } +#[cfg(feature = "may_dangle")] +#[test] +fn may_dangle_without_element_drop() { + let mut inline = SmallVec::<[&str; 1]>::new(); + let mut spilled = SmallVec::<[&str; 0]>::new(); + let text = "borrowed".to_owned(); + inline.push(&text); + spilled.push(&text); + assert!(!inline.spilled()); + assert!(spilled.spilled()); + // `text` is dropped first, but dropping the vectors never reads these + // references. +} + // We heap allocate all these strings so that double frees will show up under // valgrind. @@ -786,6 +800,104 @@ fn test_retain() { assert_eq!(Rc::strong_count(&one), 1); } +#[test] +fn test_retain_panic_preserves_unprocessed_tail() { + use std::{ + cell::Cell, + panic::{catch_unwind, AssertUnwindSafe}, + }; + + struct Tracked { + id: usize, + drops: Rc<Vec<Cell<usize>>>, + panic_at: Option<usize>, + } + impl Drop for Tracked { + fn drop(&mut self) { + self.drops[self.id].set(self.drops[self.id].get() + 1); + assert_ne!(self.panic_at, Some(self.id), "drop panic"); + } + } + fn tracked(len: usize, panic_at: Option<usize>) -> (Vec<Tracked>, Rc<Vec<Cell<usize>>>) { + let drops = Rc::new((0..len).map(|_| Cell::new(0)).collect::<Vec<_>>()); + let values = (0..len) + .map(|id| Tracked { + id, + drops: drops.clone(), + panic_at, + }) + .collect(); + (values, drops) + } + fn ids(values: &[Tracked]) -> Vec<usize> { + values.iter().map(|v| v.id).collect() + } + + for len in [8, 32].iter().copied() { + for panic_at in 0..len { + for drop_panics in [false, true].iter().copied() { + if drop_panics && panic_at % 2 == 0 { + continue; + } + let destructor = if drop_panics { Some(panic_at) } else { None }; + let (input, drops) = tracked(len, destructor); + let mut actual: SmallVec<[_; 16]> = input.into_iter().collect(); + assert!(catch_unwind(AssertUnwindSafe(|| actual.retain(|x| { + if !drop_panics { + assert_ne!(x.id, panic_at); + } + x.id % 2 == 0 + }))) + .is_err()); + let read = panic_at + if drop_panics { 1 } else { 0 }; + let expected: Vec<_> = (0..panic_at).step_by(2).chain(read..len).collect(); + assert_eq!(ids(&actual), expected); + drop(actual); + assert!(drops.iter().all(|x| x.get() == 1)); + } + } + } +} + +#[test] +fn test_retain_patterns_and_zst() { + use std::{cell::Cell, thread_local}; + + thread_local! { static ZST_DROPS: Cell<usize> = Cell::new(0); } + struct Zst; + impl Drop for Zst { + fn drop(&mut self) { + ZST_DROPS.with(|x| x.set(x.get() + 1)); + } + } + + for len in [0, 1, 15, 16, 17, 64].iter().copied() { + for keep in 0..3 { + let mut actual: SmallVec<[_; 16]> = (0..len).collect(); + let mut expected: Vec<_> = (0..len).collect(); + actual.retain(|x| { + *x += 1; + *x % 2 < keep + }); + for x in &mut expected { + *x += 1; + } + expected.retain(|x| *x % 2 < keep); + assert_eq!(actual.as_slice(), expected.as_slice()); + } + } + ZST_DROPS.with(|x| x.set(0)); + let mut values: SmallVec<[_; 16]> = (0..32).map(|_| Zst).collect(); + let mut seen = 0; + values.retain(|_| { + seen += 1; + seen % 2 == 0 + }); + assert_eq!(values.len(), 16); + drop(values); + ZST_DROPS.with(|x| assert_eq!(x.get(), 32)); +} + #[test] fn test_dedup() { let mut dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 2, 3, 3]); diff --git a/deps/crates/vendor/syn-v2/.cargo-checksum.json b/deps/crates/vendor/syn-v2/.cargo-checksum.json deleted file mode 100644 index 697c9ce2fbb4..000000000000 --- a/deps/crates/vendor/syn-v2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{}} diff --git a/deps/crates/vendor/syn-v2/.cargo_vcs_info.json b/deps/crates/vendor/syn-v2/.cargo_vcs_info.json deleted file mode 100644 index 4baa697e4888..000000000000 --- a/deps/crates/vendor/syn-v2/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "3295f9e9841785ac88a5e558c884854d5fb7d67f" - }, - "path_in_vcs": "" -} \ No newline at end of file diff --git a/deps/crates/vendor/syn-v2/Cargo.lock b/deps/crates/vendor/syn-v2/Cargo.lock deleted file mode 100644 index 56da3b12d1e5..000000000000 --- a/deps/crates/vendor/syn-v2/Cargo.lock +++ /dev/null @@ -1,1912 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "anyhow" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "automod" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a273e731a7fb8c2268fd2932c9e9a3469f4fd171d85d070d2687190229653bd3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "aws-lc-rs" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", - "pkg-config", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" - -[[package]] -name = "bumpalo" -version = "3.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" - -[[package]] -name = "bytes" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" - -[[package]] -name = "cc" -version = "1.2.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chacha20" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" -dependencies = [ - "cfg-if", - "cpufeatures", - "rand_core", -] - -[[package]] -name = "cmake" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" -dependencies = [ - "cc", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "console" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" -dependencies = [ - "encode_unicode", - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" - -[[package]] -name = "displaydoc" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "either" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" - -[[package]] -name = "encode_unicode" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - -[[package]] -name = "filetime" -version = "0.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" -dependencies = [ - "cfg-if", - "libc", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "rand_core", - "wasm-bindgen", -] - -[[package]] -name = "h2" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - -[[package]] -name = "http" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "hyper" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "insta" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" -dependencies = [ - "console", - "once_cell", - "similar", - "tempfile", -] - -[[package]] -name = "ipnet" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "jni" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" -dependencies = [ - "cfg-if", - "combine", - "jni-macros", - "jni-sys", - "log", - "simd_cesu8", - "thiserror", - "walkdir", - "windows-link", -] - -[[package]] -name = "jni-macros" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "simd_cesu8", - "syn 2.0.118", -] - -[[package]] -name = "jni-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" -dependencies = [ - "jni-sys-macros", -] - -[[package]] -name = "jni-sys-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" -dependencies = [ - "quote", - "syn 2.0.118", -] - -[[package]] -name = "jobserver" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" -dependencies = [ - "getrandom 0.4.3", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" -dependencies = [ - "cfg-if", - "futures-util", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[package]] -name = "log" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "memchr" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "pkg-config" -version = "0.3.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quinn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" -dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.4.3", - "lru-slab", - "rand", - "rand_pcg", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.61.2", -] - -[[package]] -name = "quote" -version = "1.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "rand" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" -dependencies = [ - "chacha20", - "getrandom 0.4.3", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - -[[package]] -name = "rand_pcg" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rayon" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "reqwest" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "mime", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-hash" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.23.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" -dependencies = [ - "aws-lc-rs", - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pki-types" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - -[[package]] -name = "simd-adler32" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" - -[[package]] -name = "simd_cesu8" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" -dependencies = [ - "rustc_version", - "simdutf8", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "similar" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" - -[[package]] -name = "socket2" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.119" -dependencies = [ - "anyhow", - "automod", - "flate2", - "insta", - "proc-macro2", - "quote", - "rayon", - "ref-cast", - "reqwest", - "rustversion", - "syn-test-suite", - "tar", - "termcolor", - "unicode-ident", - "walkdir", -] - -[[package]] -name = "syn-test-suite" -version = "0.0.0+test" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d661992f60e67c8bdd9a7d6360d30d1301f5783abf7d59933844f656762eb5" - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tar" -version = "0.4.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.3", - "once_cell", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" -dependencies = [ - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", - "url", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.118", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-root-certs" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "xattr" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" -dependencies = [ - "libc", - "rustix", -] - -[[package]] -name = "yoke" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] diff --git a/deps/crates/vendor/syn-v2/Cargo.toml b/deps/crates/vendor/syn-v2/Cargo.toml deleted file mode 100644 index 02741c0177b9..000000000000 --- a/deps/crates/vendor/syn-v2/Cargo.toml +++ /dev/null @@ -1,272 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.71" -name = "syn" -version = "2.0.119" -authors = ["David Tolnay <dtolnay@gmail.com>"] -build = false -include = [ - "/benches/**", - "/Cargo.toml", - "/LICENSE-APACHE", - "/LICENSE-MIT", - "/README.md", - "/src/**", - "/tests/**", -] -autolib = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "Parser for Rust source code" -documentation = "https://docs.rs/syn" -readme = "README.md" -keywords = [ - "macros", - "syn", -] -categories = [ - "development-tools::procedural-macro-helpers", - "parser-implementations", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/dtolnay/syn" - -[package.metadata.docs.rs] -all-features = true -targets = ["x86_64-unknown-linux-gnu"] -rustdoc-args = [ - "--generate-link-to-definition", - "--generate-macro-expansion", - "--extend-css=src/gen/token.css", - "--extern-html-root-url=core=https://doc.rust-lang.org", - "--extern-html-root-url=alloc=https://doc.rust-lang.org", - "--extern-html-root-url=std=https://doc.rust-lang.org", - "--extern-html-root-url=proc_macro=https://doc.rust-lang.org", -] - -[package.metadata.playground] -features = [ - "full", - "visit", - "visit-mut", - "fold", - "extra-traits", -] - -[features] -clone-impls = [] -default = [ - "derive", - "parsing", - "printing", - "clone-impls", - "proc-macro", -] -derive = [] -extra-traits = [] -fold = [] -full = [] -parsing = [] -printing = ["dep:quote"] -proc-macro = [ - "proc-macro2/proc-macro", - "quote?/proc-macro", -] -test = ["syn-test-suite/all-features"] -visit = [] -visit-mut = [] - -[lib] -name = "syn" -path = "src/lib.rs" - -[[test]] -name = "regression" -path = "tests/regression.rs" - -[[test]] -name = "test_asyncness" -path = "tests/test_asyncness.rs" - -[[test]] -name = "test_attribute" -path = "tests/test_attribute.rs" - -[[test]] -name = "test_derive_input" -path = "tests/test_derive_input.rs" - -[[test]] -name = "test_expr" -path = "tests/test_expr.rs" - -[[test]] -name = "test_generics" -path = "tests/test_generics.rs" - -[[test]] -name = "test_grouping" -path = "tests/test_grouping.rs" - -[[test]] -name = "test_ident" -path = "tests/test_ident.rs" - -[[test]] -name = "test_item" -path = "tests/test_item.rs" - -[[test]] -name = "test_lit" -path = "tests/test_lit.rs" - -[[test]] -name = "test_meta" -path = "tests/test_meta.rs" - -[[test]] -name = "test_parse_buffer" -path = "tests/test_parse_buffer.rs" - -[[test]] -name = "test_parse_quote" -path = "tests/test_parse_quote.rs" - -[[test]] -name = "test_parse_stream" -path = "tests/test_parse_stream.rs" - -[[test]] -name = "test_pat" -path = "tests/test_pat.rs" - -[[test]] -name = "test_path" -path = "tests/test_path.rs" - -[[test]] -name = "test_precedence" -path = "tests/test_precedence.rs" - -[[test]] -name = "test_punctuated" -path = "tests/test_punctuated.rs" - -[[test]] -name = "test_receiver" -path = "tests/test_receiver.rs" - -[[test]] -name = "test_round_trip" -path = "tests/test_round_trip.rs" - -[[test]] -name = "test_shebang" -path = "tests/test_shebang.rs" - -[[test]] -name = "test_size" -path = "tests/test_size.rs" - -[[test]] -name = "test_stmt" -path = "tests/test_stmt.rs" - -[[test]] -name = "test_token_trees" -path = "tests/test_token_trees.rs" - -[[test]] -name = "test_ty" -path = "tests/test_ty.rs" - -[[test]] -name = "test_unparenthesize" -path = "tests/test_unparenthesize.rs" - -[[test]] -name = "test_visibility" -path = "tests/test_visibility.rs" - -[[test]] -name = "zzz_stable" -path = "tests/zzz_stable.rs" - -[[bench]] -name = "file" -path = "benches/file.rs" -required-features = [ - "full", - "parsing", -] - -[[bench]] -name = "rust" -path = "benches/rust.rs" -harness = false -required-features = [ - "full", - "parsing", -] - -[dependencies.proc-macro2] -version = "1.0.91" -default-features = false - -[dependencies.quote] -version = "1.0.35" -optional = true -default-features = false - -[dependencies.unicode-ident] -version = "1" - -[dev-dependencies.anyhow] -version = "1" - -[dev-dependencies.automod] -version = "1" - -[dev-dependencies.insta] -version = "1" - -[dev-dependencies.ref-cast] -version = "1" - -[dev-dependencies.rustversion] -version = "1" - -[dev-dependencies.syn-test-suite] -version = "0" - -[dev-dependencies.termcolor] -version = "1" - -[target."cfg(not(miri))".dev-dependencies.flate2] -version = "1" - -[target."cfg(not(miri))".dev-dependencies.rayon] -version = "1" - -[target."cfg(not(miri))".dev-dependencies.reqwest] -version = "0.13" -features = ["blocking"] - -[target."cfg(not(miri))".dev-dependencies.tar] -version = "0.4.16" - -[target."cfg(not(miri))".dev-dependencies.walkdir] -version = "2.3.2" diff --git a/deps/crates/vendor/syn-v2/Cargo.toml.orig b/deps/crates/vendor/syn-v2/Cargo.toml.orig deleted file mode 100644 index a2a8d2987893..000000000000 --- a/deps/crates/vendor/syn-v2/Cargo.toml.orig +++ /dev/null @@ -1,95 +0,0 @@ -[package] -name = "syn" -version = "2.0.119" -authors = ["David Tolnay <dtolnay@gmail.com>"] -categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] -description = "Parser for Rust source code" -documentation = "https://docs.rs/syn" -edition = "2021" -include = [ - "/benches/**", - "/Cargo.toml", - "/LICENSE-APACHE", - "/LICENSE-MIT", - "/README.md", - "/src/**", - "/tests/**", -] -keywords = ["macros", "syn"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/dtolnay/syn" -rust-version = "1.71" - -[features] -default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"] -derive = [] -full = [] -parsing = [] -printing = ["dep:quote"] -visit = [] -visit-mut = [] -fold = [] -clone-impls = [] -extra-traits = [] -proc-macro = ["proc-macro2/proc-macro", "quote?/proc-macro"] -test = ["syn-test-suite/all-features"] - -[dependencies] -proc-macro2 = { version = "1.0.91", default-features = false } -quote = { version = "1.0.35", optional = true, default-features = false } -unicode-ident = "1" - -[dev-dependencies] -anyhow = "1" -automod = "1" -insta = "1" -ref-cast = "1" -rustversion = "1" -syn-test-suite = { version = "0", path = "tests/features" } -termcolor = "1" - -[target.'cfg(not(miri))'.dev-dependencies] -flate2 = "1" -rayon = "1" -reqwest = { version = "0.13", features = ["blocking"] } -tar = "0.4.16" -walkdir = "2.3.2" - -[[bench]] -name = "rust" -harness = false -required-features = ["full", "parsing"] - -[[bench]] -name = "file" -required-features = ["full", "parsing"] - -[package.metadata.docs.rs] -all-features = true -targets = ["x86_64-unknown-linux-gnu"] -rustdoc-args = [ - "--generate-link-to-definition", - "--generate-macro-expansion", - "--extend-css=src/gen/token.css", - "--extern-html-root-url=core=https://doc.rust-lang.org", - "--extern-html-root-url=alloc=https://doc.rust-lang.org", - "--extern-html-root-url=std=https://doc.rust-lang.org", - "--extern-html-root-url=proc_macro=https://doc.rust-lang.org", -] - -[package.metadata.playground] -features = ["full", "visit", "visit-mut", "fold", "extra-traits"] - -[workspace] -members = [ - "dev", - "examples/dump-syntax", - "examples/heapsize/example", - "examples/heapsize/heapsize", - "examples/heapsize/heapsize_derive", - "examples/lazy-static/example", - "examples/lazy-static/lazy-static", - "examples/trace-var/example", - "examples/trace-var/trace-var", - "tests/features", -] diff --git a/deps/crates/vendor/syn-v2/LICENSE-APACHE b/deps/crates/vendor/syn-v2/LICENSE-APACHE deleted file mode 100644 index 1b5ec8b78e23..000000000000 --- a/deps/crates/vendor/syn-v2/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/deps/crates/vendor/syn-v2/LICENSE-MIT b/deps/crates/vendor/syn-v2/LICENSE-MIT deleted file mode 100644 index 31aa79387f27..000000000000 --- a/deps/crates/vendor/syn-v2/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/syn-v2/README.md b/deps/crates/vendor/syn-v2/README.md deleted file mode 100644 index 7ac4b2dc3d82..000000000000 --- a/deps/crates/vendor/syn-v2/README.md +++ /dev/null @@ -1,282 +0,0 @@ -Parser for Rust source code -=========================== - -[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/syn-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/syn) -[<img alt="crates.io" src="https://img.shields.io/crates/v/syn.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/syn) -[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-syn-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/syn) -[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/syn/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/syn/actions?query=branch%3Amaster) - -Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree -of Rust source code. - -Currently this library is geared toward use in Rust procedural macros, but -contains some APIs that may be useful more generally. - -- **Data structures** — Syn provides a complete syntax tree that can represent - any valid Rust source code. The syntax tree is rooted at [`syn::File`] which - represents a full source file, but there are other entry points that may be - useful to procedural macros including [`syn::Item`], [`syn::Expr`] and - [`syn::Type`]. - -- **Derives** — Of particular interest to derive macros is [`syn::DeriveInput`] - which is any of the three legal input items to a derive macro. An example - below shows using this type in a library that can derive implementations of a - user-defined trait. - -- **Parsing** — Parsing in Syn is built around [parser functions] with the - signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined by - Syn is individually parsable and may be used as a building block for custom - syntaxes, or you may dream up your own brand new syntax without involving any - of our syntax tree types. - -- **Location information** — Every token parsed by Syn is associated with a - `Span` that tracks line and column information back to the source of that - token. These spans allow a procedural macro to display detailed error messages - pointing to all the right places in the user's code. There is an example of - this below. - -- **Feature flags** — Functionality is aggressively feature gated so your - procedural macros enable only what they need, and do not pay in compile time - for all the rest. - -[`syn::File`]: https://docs.rs/syn/2.0/syn/struct.File.html -[`syn::Item`]: https://docs.rs/syn/2.0/syn/enum.Item.html -[`syn::Expr`]: https://docs.rs/syn/2.0/syn/enum.Expr.html -[`syn::Type`]: https://docs.rs/syn/2.0/syn/enum.Type.html -[`syn::DeriveInput`]: https://docs.rs/syn/2.0/syn/struct.DeriveInput.html -[parser functions]: https://docs.rs/syn/2.0/syn/parse/index.html - -[*Release notes*](https://github.com/dtolnay/syn/releases) - -<br> - -## Resources - -The best way to learn about procedural macros is by writing some. Consider -working through [this procedural macro workshop][workshop] to get familiar with -the different types of procedural macros. The workshop contains relevant links -into the Syn documentation as you work through each project. - -[workshop]: https://github.com/dtolnay/proc-macro-workshop - -<br> - -## Example of a derive macro - -The canonical derive macro using Syn looks like this. We write an ordinary Rust -function tagged with a `proc_macro_derive` attribute and the name of the trait -we are deriving. Any time that derive appears in the user's code, the Rust -compiler passes their data structure as tokens into our macro. We get to execute -arbitrary Rust code to figure out what to do with those tokens, then hand some -tokens back to the compiler to compile into the user's crate. - -[`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html - -```toml -[dependencies] -syn = "2.0" -quote = "1.0" - -[lib] -proc-macro = true -``` - -```rust -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput}; - -#[proc_macro_derive(MyMacro)] -pub fn my_macro(input: TokenStream) -> TokenStream { - // Parse the input tokens into a syntax tree - let input = parse_macro_input!(input as DeriveInput); - - // Build the output, possibly using quasi-quotation - let expanded = quote! { - // ... - }; - - // Hand the output tokens back to the compiler - TokenStream::from(expanded) -} -``` - -The [`heapsize`] example directory shows a complete working implementation of a -derive macro. The example derives a `HeapSize` trait which computes an estimate -of the amount of heap memory owned by a value. - -[`heapsize`]: examples/heapsize - -```rust -pub trait HeapSize { - /// Total number of bytes of heap memory owned by `self`. - fn heap_size_of_children(&self) -> usize; -} -``` - -The derive macro allows users to write `#[derive(HeapSize)]` on data structures -in their program. - -```rust -#[derive(HeapSize)] -struct Demo<'a, T: ?Sized> { - a: Box<T>, - b: u8, - c: &'a str, - d: String, -} -``` - -<br> - -## Spans and error reporting - -The token-based procedural macro API provides great control over where the -compiler's error messages are displayed in user code. Consider the error the -user sees if one of their field types does not implement `HeapSize`. - -```rust -#[derive(HeapSize)] -struct Broken { - ok: String, - bad: std::thread::Thread, -} -``` - -By tracking span information all the way through the expansion of a procedural -macro as shown in the `heapsize` example, token-based macros in Syn are able to -trigger errors that directly pinpoint the source of the problem. - -```console -error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied - --> src/main.rs:7:5 - | -7 | bad: std::thread::Thread, - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread` -``` - -<br> - -## Parsing a custom syntax - -The [`lazy-static`] example directory shows the implementation of a -`functionlike!(...)` procedural macro in which the input tokens are parsed using -Syn's parsing API. - -[`lazy-static`]: examples/lazy-static - -The example reimplements the popular `lazy_static` crate from crates.io as a -procedural macro. - -```rust -lazy_static! { - static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); -} -``` - -The implementation shows how to trigger custom warnings and error messages on -the macro input. - -```console -warning: come on, pick a more creative name - --> src/main.rs:10:16 - | -10 | static ref FOO: String = "lazy_static".to_owned(); - | ^^^ -``` - -<br> - -## Testing - -When testing macros, we often care not just that the macro can be used -successfully but also that when the macro is provided with invalid input it -produces maximally helpful error messages. Consider using the [`trybuild`] crate -to write tests for errors that are emitted by your macro or errors detected by -the Rust compiler in the expanded code following misuse of the macro. Such tests -help avoid regressions from later refactors that mistakenly make an error no -longer trigger or be less helpful than it used to be. - -[`trybuild`]: https://github.com/dtolnay/trybuild - -<br> - -## Debugging - -When developing a procedural macro it can be helpful to look at what the -generated code looks like. Use `cargo rustc -- -Zunstable-options --Zunpretty=expanded` or the [`cargo expand`] subcommand. - -[`cargo expand`]: https://github.com/dtolnay/cargo-expand - -To show the expanded code for some crate that uses your procedural macro, run -`cargo expand` from that crate. To show the expanded code for one of your own -test cases, run `cargo expand --test the_test_case` where the last argument is -the name of the test file without the `.rs` extension. - -This write-up by Brandon W Maister discusses debugging in more detail: -[Debugging Rust's new Custom Derive system][debugging]. - -[debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ - -<br> - -## Optional features - -Syn puts a lot of functionality behind optional features in order to optimize -compile time for the most common use cases. The following features are -available. - -- **`derive`** *(enabled by default)* — Data structures for representing the - possible input to a derive macro, including structs and enums and types. -- **`full`** — Data structures for representing the syntax tree of all valid - Rust source code, including items and expressions. -- **`parsing`** *(enabled by default)* — Ability to parse input tokens into a - syntax tree node of a chosen type. -- **`printing`** *(enabled by default)* — Ability to print a syntax tree node as - tokens of Rust source code. -- **`visit`** — Trait for traversing a syntax tree. -- **`visit-mut`** — Trait for traversing and mutating in place a syntax tree. -- **`fold`** — Trait for transforming an owned syntax tree. -- **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree - types. -- **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree - types. -- **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic - library libproc_macro from rustc toolchain. - -<br> - -## Proc macro shim - -Syn operates on the token representation provided by the [proc-macro2] crate -from crates.io rather than using the compiler's built in proc-macro crate -directly. This enables code using Syn to execute outside of the context of a -procedural macro, such as in unit tests or build.rs, and we avoid needing -incompatible ecosystems for proc macros vs non-macro use cases. - -In general all of your code should be written against proc-macro2 rather than -proc-macro. The one exception is in the signatures of procedural macro entry -points, which are required by the language to use `proc_macro::TokenStream`. - -The proc-macro2 crate will automatically detect and use the compiler's data -structures when a procedural macro is active. - -[proc-macro2]: https://docs.rs/proc-macro2/1.0/proc_macro2/ - -<br> - -#### License - -<sup> -Licensed under either of <a href="LICENSE-APACHE">Apache License, Version -2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. -</sup> - -<br> - -<sub> -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this crate by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. -</sub> diff --git a/deps/crates/vendor/syn-v2/benches/file.rs b/deps/crates/vendor/syn-v2/benches/file.rs deleted file mode 100644 index 6167488c9c55..000000000000 --- a/deps/crates/vendor/syn-v2/benches/file.rs +++ /dev/null @@ -1,59 +0,0 @@ -// $ cargo bench --features full,test --bench file - -#![feature(rustc_private, test)] -#![recursion_limit = "1024"] -#![allow( - clippy::elidable_lifetime_names, - clippy::items_after_statements, - clippy::manual_let_else, - clippy::match_like_matches_macro, - clippy::missing_panics_doc, - clippy::must_use_candidate, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -extern crate test; - -#[macro_use] -#[path = "../tests/macros/mod.rs"] -mod macros; - -#[allow(dead_code)] -#[path = "../tests/repo/mod.rs"] -mod repo; - -use proc_macro2::{Span, TokenStream}; -use std::fs; -use std::str::FromStr; -use syn::parse::{ParseStream, Parser}; -use test::Bencher; - -const FILE: &str = "tests/rust/library/core/src/str/mod.rs"; - -fn get_tokens() -> TokenStream { - repo::clone_rust(); - let content = fs::read_to_string(FILE).unwrap(); - TokenStream::from_str(&content).unwrap() -} - -#[bench] -fn baseline(b: &mut Bencher) { - let tokens = get_tokens(); - b.iter(|| drop(tokens.clone())); -} - -#[bench] -fn create_token_buffer(b: &mut Bencher) { - let tokens = get_tokens(); - fn immediate_fail(_input: ParseStream) -> syn::Result<()> { - Err(syn::Error::new(Span::call_site(), "")) - } - b.iter(|| immediate_fail.parse2(tokens.clone())); -} - -#[bench] -fn parse_file(b: &mut Bencher) { - let tokens = get_tokens(); - b.iter(|| syn::parse2::<syn::File>(tokens.clone())); -} diff --git a/deps/crates/vendor/syn-v2/benches/rust.rs b/deps/crates/vendor/syn-v2/benches/rust.rs deleted file mode 100644 index c0e82c65c00f..000000000000 --- a/deps/crates/vendor/syn-v2/benches/rust.rs +++ /dev/null @@ -1,189 +0,0 @@ -// $ cargo bench --features full,test --bench rust -// -// Syn only, useful for profiling: -// $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full,test --bench rust - -#![cfg_attr(not(syn_only), feature(rustc_private))] -#![recursion_limit = "1024"] -#![allow( - clippy::arc_with_non_send_sync, - clippy::cast_lossless, - clippy::elidable_lifetime_names, - clippy::let_underscore_untyped, - clippy::manual_let_else, - clippy::match_like_matches_macro, - clippy::needless_lifetimes, - clippy::uninlined_format_args, - clippy::unnecessary_wraps -)] - -#[macro_use] -#[path = "../tests/macros/mod.rs"] -mod macros; - -#[allow(dead_code)] -#[path = "../tests/repo/mod.rs"] -mod repo; - -use std::fs; -use std::path::Path; -use std::time::{Duration, Instant}; - -#[cfg(not(syn_only))] -mod tokenstream_parse { - use proc_macro2::TokenStream; - use std::path::Path; - use std::str::FromStr; - - pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { - TokenStream::from_str(content).map(drop).map_err(drop) - } -} - -mod syn_parse { - use std::path::Path; - - pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { - syn::parse_file(content).map(drop).map_err(drop) - } -} - -#[cfg(not(syn_only))] -mod librustc_parse { - extern crate rustc_data_structures; - extern crate rustc_driver; - extern crate rustc_error_messages; - extern crate rustc_errors; - extern crate rustc_parse; - extern crate rustc_session; - extern crate rustc_span; - - use crate::repo; - use rustc_errors::emitter::Emitter; - use rustc_errors::{DiagCtxt, DiagInner}; - use rustc_parse::lexer::StripTokens; - use rustc_session::parse::ParseSess; - use rustc_span::source_map::{FilePathMapping, SourceMap}; - use rustc_span::FileName; - use std::path::Path; - use std::sync::Arc; - - pub fn bench(path: &Path, content: &str) -> Result<(), ()> { - struct SilentEmitter; - - impl Emitter for SilentEmitter { - fn emit_diagnostic(&mut self, _diag: DiagInner) {} - fn source_map(&self) -> Option<&SourceMap> { - None - } - } - - let edition = repo::edition(path).parse().unwrap(); - rustc_span::create_session_if_not_set_then(edition, |_| { - let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = Box::new(SilentEmitter); - let handler = DiagCtxt::new(emitter); - let sess = ParseSess::with_dcx(handler, source_map); - let name = FileName::Custom("bench".to_owned()); - let mut parser = rustc_parse::new_parser_from_source_str( - &sess, - name, - content.to_owned(), - StripTokens::ShebangAndFrontmatter, - ) - .unwrap(); - if let Err(diagnostic) = parser.parse_crate_mod() { - diagnostic.cancel(); - return Err(()); - } - Ok(()) - }) - } -} - -#[cfg(not(syn_only))] -mod read_from_disk { - use std::path::Path; - - pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { - let _ = content; - Ok(()) - } -} - -fn exec(mut codepath: impl FnMut(&Path, &str) -> Result<(), ()>) -> Duration { - let begin = Instant::now(); - let mut success = 0; - let mut total = 0; - - ["tests/rust/compiler", "tests/rust/library"] - .iter() - .flat_map(|dir| { - walkdir::WalkDir::new(dir) - .into_iter() - .filter_entry(repo::base_dir_filter) - }) - .for_each(|entry| { - let entry = entry.unwrap(); - let path = entry.path(); - if path.is_dir() { - return; - } - let content = fs::read_to_string(path).unwrap(); - let ok = codepath(path, &content).is_ok(); - success += ok as usize; - total += 1; - if !ok { - eprintln!("FAIL {}", path.display()); - } - }); - - assert_eq!(success, total); - begin.elapsed() -} - -fn main() { - repo::clone_rust(); - - macro_rules! testcases { - ($($(#[$cfg:meta])* $name:ident,)*) => { - [ - $( - $(#[$cfg])* - (stringify!($name), $name::bench as fn(&Path, &str) -> Result<(), ()>), - )* - ] - }; - } - - #[cfg(not(syn_only))] - { - let mut lines = 0; - let mut files = 0; - exec(|_path, content| { - lines += content.lines().count(); - files += 1; - Ok(()) - }); - eprintln!("\n{} lines in {} files", lines, files); - } - - for (name, f) in testcases!( - #[cfg(not(syn_only))] - read_from_disk, - #[cfg(not(syn_only))] - tokenstream_parse, - syn_parse, - #[cfg(not(syn_only))] - librustc_parse, - ) { - eprint!("{:20}", format!("{}:", name)); - let elapsed = exec(f); - eprintln!( - "elapsed={}.{:03}s", - elapsed.as_secs(), - elapsed.subsec_millis(), - ); - } - eprintln!(); -} diff --git a/deps/crates/vendor/syn-v2/src/attr.rs b/deps/crates/vendor/syn-v2/src/attr.rs deleted file mode 100644 index 5e2d7a71f25d..000000000000 --- a/deps/crates/vendor/syn-v2/src/attr.rs +++ /dev/null @@ -1,841 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::error::Error; -#[cfg(feature = "parsing")] -use crate::error::Result; -use crate::expr::Expr; -use crate::mac::MacroDelimiter; -#[cfg(feature = "parsing")] -use crate::meta::{self, ParseNestedMeta}; -#[cfg(feature = "parsing")] -use crate::parse::{Parse, ParseStream, Parser}; -use crate::path::Path; -use crate::token; -#[cfg(feature = "parsing")] -use alloc::format; -#[cfg(feature = "parsing")] -use alloc::vec::Vec; -#[cfg(feature = "printing")] -use core::iter; -#[cfg(feature = "printing")] -use core::slice; -use proc_macro2::TokenStream; - -ast_struct! { - /// An attribute, like `#[repr(transparent)]`. - /// - /// <br> - /// - /// # Syntax - /// - /// Rust has six types of attributes. - /// - /// - Outer attributes like `#[repr(transparent)]`. These appear outside or - /// in front of the item they describe. - /// - /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside - /// of the item they describe, usually a module. - /// - /// - Outer one-line doc comments like `/// Example`. - /// - /// - Inner one-line doc comments like `//! Please file an issue`. - /// - /// - Outer documentation blocks `/** Example */`. - /// - /// - Inner documentation blocks `/*! Please file an issue */`. - /// - /// The `style` field of type `AttrStyle` distinguishes whether an attribute - /// is outer or inner. - /// - /// Every attribute has a `path` that indicates the intended interpretation - /// of the rest of the attribute's contents. The path and the optional - /// additional contents are represented together in the `meta` field of the - /// attribute in three possible varieties: - /// - /// - Meta::Path — attributes whose information content conveys just a - /// path, for example the `#[test]` attribute. - /// - /// - Meta::List — attributes that carry arbitrary tokens after the - /// path, surrounded by a delimiter (parenthesis, bracket, or brace). For - /// example `#[derive(Copy)]` or `#[precondition(x < 5)]`. - /// - /// - Meta::NameValue — attributes with an `=` sign after the path, - /// followed by a Rust expression. For example `#[path = - /// "sys/windows.rs"]`. - /// - /// All doc comments are represented in the NameValue style with a path of - /// "doc", as this is how they are processed by the compiler and by - /// `macro_rules!` macros. - /// - /// ```text - /// #[derive(Copy, Clone)] - /// ~~~~~~Path - /// ^^^^^^^^^^^^^^^^^^^Meta::List - /// - /// #[path = "sys/windows.rs"] - /// ~~~~Path - /// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue - /// - /// #[test] - /// ^^^^Meta::Path - /// ``` - /// - /// <br> - /// - /// # Parsing from tokens to Attribute - /// - /// This type does not implement the [`Parse`] trait and thus cannot be - /// parsed directly by [`ParseStream::parse`]. Instead use - /// [`ParseStream::call`] with one of the two parser functions - /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on - /// which you intend to parse. - /// - /// [`Parse`]: crate::parse::Parse - /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse - /// [`ParseStream::call`]: crate::parse::ParseBuffer::call - /// - /// ``` - /// use syn::{Attribute, Ident, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // Parses a unit struct with attributes. - /// // - /// // #[path = "s.tmpl"] - /// // struct S; - /// struct UnitStruct { - /// attrs: Vec<Attribute>, - /// struct_token: Token![struct], - /// name: Ident, - /// semi_token: Token![;], - /// } - /// - /// impl Parse for UnitStruct { - /// fn parse(input: ParseStream) -> Result<Self> { - /// Ok(UnitStruct { - /// attrs: input.call(Attribute::parse_outer)?, - /// struct_token: input.parse()?, - /// name: input.parse()?, - /// semi_token: input.parse()?, - /// }) - /// } - /// } - /// ``` - /// - /// <p><br></p> - /// - /// # Parsing from Attribute to structured arguments - /// - /// The grammar of attributes in Rust is very flexible, which makes the - /// syntax tree not that useful on its own. In particular, arguments of the - /// `Meta::List` variety of attribute are held in an arbitrary `tokens: - /// TokenStream`. Macros are expected to check the `path` of the attribute, - /// decide whether they recognize it, and then parse the remaining tokens - /// according to whatever grammar they wish to require for that kind of - /// attribute. Use [`parse_args()`] to parse those tokens into the expected - /// data structure. - /// - /// [`parse_args()`]: Attribute::parse_args - /// - /// <p><br></p> - /// - /// # Doc comments - /// - /// The compiler transforms doc comments, such as `/// comment` and `/*! - /// comment */`, into attributes before macros are expanded. Each comment is - /// expanded into an attribute of the form `#[doc = r"comment"]`. - /// - /// As an example, the following `mod` items are expanded identically: - /// - /// ``` - /// # use syn::{ItemMod, parse_quote}; - /// let doc: ItemMod = parse_quote! { - /// /// Single line doc comments - /// /// We write so many! - /// /** - /// * Multi-line comments... - /// * May span many lines - /// */ - /// mod example { - /// //! Of course, they can be inner too - /// /*! And fit in a single line */ - /// } - /// }; - /// let attr: ItemMod = parse_quote! { - /// #[doc = r" Single line doc comments"] - /// #[doc = r" We write so many!"] - /// #[doc = r" - /// * Multi-line comments... - /// * May span many lines - /// "] - /// mod example { - /// #![doc = r" Of course, they can be inner too"] - /// #![doc = r" And fit in a single line "] - /// } - /// }; - /// assert_eq!(doc, attr); - /// ``` - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Attribute { - pub pound_token: Token![#], - pub style: AttrStyle, - pub bracket_token: token::Bracket, - pub meta: Meta, - } -} - -impl Attribute { - /// Returns the path that identifies the interpretation of this attribute. - /// - /// For example this would return the `test` in `#[test]`, the `derive` in - /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. - pub fn path(&self) -> &Path { - self.meta.path() - } - - /// Parse the arguments to the attribute as a syntax tree. - /// - /// This is similar to pulling out the `TokenStream` from `Meta::List` and - /// doing `syn::parse2::<T>(meta_list.tokens)`, except that using - /// `parse_args` the error message has a more useful span when `tokens` is - /// empty. - /// - /// The surrounding delimiters are *not* included in the input to the - /// parser. - /// - /// ```text - /// #[my_attr(value < 5)] - /// ^^^^^^^^^ what gets parsed - /// ``` - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Attribute, Expr}; - /// - /// let attr: Attribute = parse_quote! { - /// #[precondition(value < 5)] - /// }; - /// - /// if attr.path().is_ident("precondition") { - /// let precondition: Expr = attr.parse_args()?; - /// // ... - /// } - /// # anyhow::Ok(()) - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_args<T: Parse>(&self) -> Result<T> { - self.parse_args_with(T::parse) - } - - /// Parse the arguments to the attribute using the given parser. - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Attribute}; - /// - /// let attr: Attribute = parse_quote! { - /// #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }] - /// }; - /// - /// let bwom = attr.parse_args_with(Attribute::parse_outer)?; - /// - /// // Attribute does not have a Parse impl, so we couldn't directly do: - /// // let bwom: Attribute = attr.parse_args()?; - /// # anyhow::Ok(()) - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { - match &self.meta { - Meta::Path(path) => Err(crate::error::new2( - path.segments.first().unwrap().ident.span(), - path.segments.last().unwrap().ident.span(), - format!( - "expected attribute arguments in parentheses: {}[{}(...)]", - parsing::DisplayAttrStyle(&self.style), - parsing::DisplayPath(path), - ), - )), - Meta::NameValue(meta) => Err(Error::new( - meta.eq_token.span, - format_args!( - "expected parentheses: {}[{}(...)]", - parsing::DisplayAttrStyle(&self.style), - parsing::DisplayPath(&meta.path), - ), - )), - Meta::List(meta) => meta.parse_args_with(parser), - } - } - - /// Parse the arguments to the attribute, expecting it to follow the - /// conventional structure used by most of Rust's built-in attributes. - /// - /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference - /// explains the convention in more detail. Not all attributes follow this - /// convention, so [`parse_args()`][Self::parse_args] is available if you - /// need to parse arbitrarily goofy attribute syntax. - /// - /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax - /// - /// # Example - /// - /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute - /// syntax. - /// - /// ``` - /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt}; - /// - /// let input: ItemStruct = parse_quote! { - /// #[repr(C, align(4))] - /// pub struct MyStruct(u16, u32); - /// }; - /// - /// let mut repr_c = false; - /// let mut repr_transparent = false; - /// let mut repr_align = None::<usize>; - /// let mut repr_packed = None::<usize>; - /// for attr in &input.attrs { - /// if attr.path().is_ident("repr") { - /// attr.parse_nested_meta(|meta| { - /// // #[repr(C)] - /// if meta.path.is_ident("C") { - /// repr_c = true; - /// return Ok(()); - /// } - /// - /// // #[repr(transparent)] - /// if meta.path.is_ident("transparent") { - /// repr_transparent = true; - /// return Ok(()); - /// } - /// - /// // #[repr(align(N))] - /// if meta.path.is_ident("align") { - /// let content; - /// parenthesized!(content in meta.input); - /// let lit: LitInt = content.parse()?; - /// let n: usize = lit.base10_parse()?; - /// repr_align = Some(n); - /// return Ok(()); - /// } - /// - /// // #[repr(packed)] or #[repr(packed(N))], omitted N means 1 - /// if meta.path.is_ident("packed") { - /// if meta.input.peek(token::Paren) { - /// let content; - /// parenthesized!(content in meta.input); - /// let lit: LitInt = content.parse()?; - /// let n: usize = lit.base10_parse()?; - /// repr_packed = Some(n); - /// } else { - /// repr_packed = Some(1); - /// } - /// return Ok(()); - /// } - /// - /// Err(meta.error("unrecognized repr")) - /// })?; - /// } - /// } - /// # anyhow::Ok(()) - /// ``` - /// - /// # Alternatives - /// - /// In some cases, for attributes which have nested layers of structured - /// content, the following less flexible approach might be more convenient: - /// - /// ``` - /// # use syn::{parse_quote, ItemStruct}; - /// # - /// # let input: ItemStruct = parse_quote! { - /// # #[repr(C, align(4))] - /// # pub struct MyStruct(u16, u32); - /// # }; - /// # - /// use syn::punctuated::Punctuated; - /// use syn::{parenthesized, token, Error, LitInt, Meta, Token}; - /// - /// let mut repr_c = false; - /// let mut repr_transparent = false; - /// let mut repr_align = None::<usize>; - /// let mut repr_packed = None::<usize>; - /// for attr in &input.attrs { - /// if attr.path().is_ident("repr") { - /// let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?; - /// for meta in nested { - /// match meta { - /// // #[repr(C)] - /// Meta::Path(path) if path.is_ident("C") => { - /// repr_c = true; - /// } - /// - /// // #[repr(align(N))] - /// Meta::List(meta) if meta.path.is_ident("align") => { - /// let lit: LitInt = meta.parse_args()?; - /// let n: usize = lit.base10_parse()?; - /// repr_align = Some(n); - /// } - /// - /// /* ... */ - /// - /// _ => { - /// return Err(Error::new_spanned(meta, "unrecognized repr")); - /// } - /// } - /// } - /// } - /// } - /// # Ok(()) - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_nested_meta( - &self, - logic: impl FnMut(ParseNestedMeta) -> Result<()>, - ) -> Result<()> { - self.parse_args_with(meta::parser(logic)) - } - - /// Parses zero or more outer attributes from the stream. - /// - /// # Example - /// - /// See - /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> { - let mut attrs = Vec::new(); - while input.peek(Token![#]) { - attrs.push(input.call(parsing::single_parse_outer)?); - } - Ok(attrs) - } - - /// Parses zero or more inner attributes from the stream. - /// - /// # Example - /// - /// See - /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> { - let mut attrs = Vec::new(); - parsing::parse_inner(input, &mut attrs)?; - Ok(attrs) - } -} - -ast_enum! { - /// Distinguishes between attributes that decorate an item and attributes - /// that are contained within an item. - /// - /// # Outer attributes - /// - /// - `#[repr(transparent)]` - /// - `/// # Example` - /// - `/** Please file an issue */` - /// - /// # Inner attributes - /// - /// - `#![feature(proc_macro)]` - /// - `//! # Example` - /// - `/*! Please file an issue */` - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum AttrStyle { - Outer, - Inner(Token![!]), - } -} - -ast_enum! { - /// Content of a compile-time structured attribute. - /// - /// ## Path - /// - /// A meta path is like the `test` in `#[test]`. - /// - /// ## List - /// - /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`. - /// - /// ## NameValue - /// - /// A name-value meta is like the `path = "..."` in `#[path = - /// "sys/windows.rs"]`. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum Meta { - Path(Path), - - /// A structured list within an attribute, like `derive(Copy, Clone)`. - List(MetaList), - - /// A name-value pair within an attribute, like `feature = "nightly"`. - NameValue(MetaNameValue), - } -} - -ast_struct! { - /// A structured list within an attribute, like `derive(Copy, Clone)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct MetaList { - pub path: Path, - pub delimiter: MacroDelimiter, - pub tokens: TokenStream, - } -} - -ast_struct! { - /// A name-value pair within an attribute, like `feature = "nightly"`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct MetaNameValue { - pub path: Path, - pub eq_token: Token![=], - pub value: Expr, - } -} - -impl Meta { - /// Returns the path that begins this structured meta item. - /// - /// For example this would return the `test` in `#[test]`, the `derive` in - /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. - pub fn path(&self) -> &Path { - match self { - Meta::Path(path) => path, - Meta::List(meta) => &meta.path, - Meta::NameValue(meta) => &meta.path, - } - } - - /// Error if this is a `Meta::List` or `Meta::NameValue`. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn require_path_only(&self) -> Result<&Path> { - let error_span = match self { - Meta::Path(path) => return Ok(path), - Meta::List(meta) => meta.delimiter.span().open(), - Meta::NameValue(meta) => meta.eq_token.span, - }; - Err(Error::new(error_span, "unexpected token in attribute")) - } - - /// Error if this is a `Meta::Path` or `Meta::NameValue`. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn require_list(&self) -> Result<&MetaList> { - match self { - Meta::List(meta) => Ok(meta), - Meta::Path(path) => Err(crate::error::new2( - path.segments.first().unwrap().ident.span(), - path.segments.last().unwrap().ident.span(), - format!( - "expected attribute arguments in parentheses: `{}(...)`", - parsing::DisplayPath(path), - ), - )), - Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")), - } - } - - /// Error if this is a `Meta::Path` or `Meta::List`. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn require_name_value(&self) -> Result<&MetaNameValue> { - match self { - Meta::NameValue(meta) => Ok(meta), - Meta::Path(path) => Err(crate::error::new2( - path.segments.first().unwrap().ident.span(), - path.segments.last().unwrap().ident.span(), - format!( - "expected a value for this attribute: `{} = ...`", - parsing::DisplayPath(path), - ), - )), - Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")), - } - } -} - -impl MetaList { - /// See [`Attribute::parse_args`]. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_args<T: Parse>(&self) -> Result<T> { - self.parse_args_with(T::parse) - } - - /// See [`Attribute::parse_args_with`]. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { - let scope = self.delimiter.span().close(); - crate::parse::parse_scoped(parser, scope, self.tokens.clone()) - } - - /// See [`Attribute::parse_nested_meta`]. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_nested_meta( - &self, - logic: impl FnMut(ParseNestedMeta) -> Result<()>, - ) -> Result<()> { - self.parse_args_with(meta::parser(logic)) - } -} - -#[cfg(feature = "printing")] -pub(crate) trait FilterAttrs<'a> { - type Ret: Iterator<Item = &'a Attribute>; - - fn outer(self) -> Self::Ret; - #[cfg(feature = "full")] - fn inner(self) -> Self::Ret; -} - -#[cfg(feature = "printing")] -impl<'a> FilterAttrs<'a> for &'a [Attribute] { - type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>; - - fn outer(self) -> Self::Ret { - fn is_outer(attr: &&Attribute) -> bool { - match attr.style { - AttrStyle::Outer => true, - AttrStyle::Inner(_) => false, - } - } - self.iter().filter(is_outer) - } - - #[cfg(feature = "full")] - fn inner(self) -> Self::Ret { - fn is_inner(attr: &&Attribute) -> bool { - match attr.style { - AttrStyle::Inner(_) => true, - AttrStyle::Outer => false, - } - } - self.iter().filter(is_inner) - } -} - -impl From<Path> for Meta { - fn from(meta: Path) -> Meta { - Meta::Path(meta) - } -} - -impl From<MetaList> for Meta { - fn from(meta: MetaList) -> Meta { - Meta::List(meta) - } -} - -impl From<MetaNameValue> for Meta { - fn from(meta: MetaNameValue) -> Meta { - Meta::NameValue(meta) - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; - use crate::error::Result; - use crate::expr::{Expr, ExprLit}; - use crate::lit::Lit; - use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; - use crate::path::Path; - use crate::{mac, token}; - use alloc::vec::Vec; - use core::fmt::{self, Display}; - use proc_macro2::Ident; - - pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> { - while input.peek(Token![#]) && input.peek2(Token![!]) { - attrs.push(input.call(single_parse_inner)?); - } - Ok(()) - } - - pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> { - let content; - Ok(Attribute { - pound_token: input.parse()?, - style: AttrStyle::Inner(input.parse()?), - bracket_token: bracketed!(content in input), - meta: content.parse()?, - }) - } - - pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> { - let content; - Ok(Attribute { - pound_token: input.parse()?, - style: AttrStyle::Outer, - bracket_token: bracketed!(content in input), - meta: content.parse()?, - }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Meta { - fn parse(input: ParseStream) -> Result<Self> { - let path = parse_outermost_meta_path(input)?; - parse_meta_after_path(path, input) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for MetaList { - fn parse(input: ParseStream) -> Result<Self> { - let path = parse_outermost_meta_path(input)?; - parse_meta_list_after_path(path, input) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for MetaNameValue { - fn parse(input: ParseStream) -> Result<Self> { - let path = parse_outermost_meta_path(input)?; - parse_meta_name_value_after_path(path, input) - } - } - - // Unlike meta::parse_meta_path which accepts arbitrary keywords in the path, - // only the `unsafe` keyword is accepted as an attribute's outermost path. - fn parse_outermost_meta_path(input: ParseStream) -> Result<Path> { - if input.peek(Token![unsafe]) { - let unsafe_token: Token![unsafe] = input.parse()?; - Ok(Path::from(Ident::new("unsafe", unsafe_token.span))) - } else { - Path::parse_mod_style(input) - } - } - - pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> { - if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) { - parse_meta_list_after_path(path, input).map(Meta::List) - } else if input.peek(Token![=]) && !input.peek(Token![==]) && !input.peek(Token![=>]) { - parse_meta_name_value_after_path(path, input).map(Meta::NameValue) - } else { - Ok(Meta::Path(path)) - } - } - - fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> { - let (delimiter, tokens) = mac::parse_delimiter(input)?; - Ok(MetaList { - path, - delimiter, - tokens, - }) - } - - fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> { - let eq_token: Token![=] = input.parse()?; - let ahead = input.fork(); - let lit: Option<Lit> = ahead.parse()?; - let value = if let (Some(lit), true) = (lit, ahead.is_empty()) { - input.advance_to(&ahead); - Expr::Lit(ExprLit { - attrs: Vec::new(), - lit, - }) - } else if input.peek(Token![#]) && input.peek2(token::Bracket) { - return Err(input.error("unexpected attribute inside of attribute")); - } else { - input.parse()? - }; - Ok(MetaNameValue { - path, - eq_token, - value, - }) - } - - pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle); - - impl<'a> Display for DisplayAttrStyle<'a> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(match self.0 { - AttrStyle::Outer => "#", - AttrStyle::Inner(_) => "#!", - }) - } - } - - pub(super) struct DisplayPath<'a>(pub &'a Path); - - impl<'a> Display for DisplayPath<'a> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - for (i, segment) in self.0.segments.iter().enumerate() { - if i > 0 || self.0.leading_colon.is_some() { - formatter.write_str("::")?; - } - write!(formatter, "{}", segment.ident)?; - } - Ok(()) - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; - use crate::path; - use crate::path::printing::PathStyle; - use proc_macro2::TokenStream; - use quote::ToTokens; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Attribute { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.pound_token.to_tokens(tokens); - if let AttrStyle::Inner(b) = &self.style { - b.to_tokens(tokens); - } - self.bracket_token.surround(tokens, |tokens| { - self.meta.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Meta { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Meta::Path(path) => path::printing::print_path(tokens, path, PathStyle::Mod), - Meta::List(meta_list) => meta_list.to_tokens(tokens), - Meta::NameValue(meta_name_value) => meta_name_value.to_tokens(tokens), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for MetaList { - fn to_tokens(&self, tokens: &mut TokenStream) { - path::printing::print_path(tokens, &self.path, PathStyle::Mod); - self.delimiter.surround(tokens, self.tokens.clone()); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for MetaNameValue { - fn to_tokens(&self, tokens: &mut TokenStream) { - path::printing::print_path(tokens, &self.path, PathStyle::Mod); - self.eq_token.to_tokens(tokens); - self.value.to_tokens(tokens); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/bigint.rs b/deps/crates/vendor/syn-v2/src/bigint.rs deleted file mode 100644 index d32298b79321..000000000000 --- a/deps/crates/vendor/syn-v2/src/bigint.rs +++ /dev/null @@ -1,68 +0,0 @@ -use alloc::string::String; -use alloc::vec::Vec; -use core::ops::{AddAssign, MulAssign}; - -// For implementing base10_digits() accessor on LitInt. -pub(crate) struct BigInt { - digits: Vec<u8>, -} - -impl BigInt { - pub(crate) fn new() -> Self { - BigInt { digits: Vec::new() } - } - - pub(crate) fn to_string(&self) -> String { - let mut repr = String::with_capacity(self.digits.len()); - - let mut has_nonzero = false; - for digit in self.digits.iter().rev() { - has_nonzero |= *digit != 0; - if has_nonzero { - repr.push((*digit + b'0') as char); - } - } - - if repr.is_empty() { - repr.push('0'); - } - - repr - } - - fn reserve_two_digits(&mut self) { - let len = self.digits.len(); - let desired = - len + !self.digits.ends_with(&[0, 0]) as usize + !self.digits.ends_with(&[0]) as usize; - self.digits.resize(desired, 0); - } -} - -impl AddAssign<u8> for BigInt { - // Assumes increment <16. - fn add_assign(&mut self, mut increment: u8) { - self.reserve_two_digits(); - - let mut i = 0; - while increment > 0 { - let sum = self.digits[i] + increment; - self.digits[i] = sum % 10; - increment = sum / 10; - i += 1; - } - } -} - -impl MulAssign<u8> for BigInt { - // Assumes base <=16. - fn mul_assign(&mut self, base: u8) { - self.reserve_two_digits(); - - let mut carry = 0; - for digit in &mut self.digits { - let prod = *digit * base + carry; - *digit = prod % 10; - carry = prod / 10; - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/buffer.rs b/deps/crates/vendor/syn-v2/src/buffer.rs deleted file mode 100644 index 277093dc9386..000000000000 --- a/deps/crates/vendor/syn-v2/src/buffer.rs +++ /dev/null @@ -1,437 +0,0 @@ -//! A stably addressed token buffer supporting efficient traversal based on a -//! cheaply copyable cursor. - -// This module is heavily commented as it contains most of the unsafe code in -// Syn, and caution should be used when editing it. The public-facing interface -// is 100% safe but the implementation is fragile internally. - -use crate::ext::TokenStreamExt as _; -use crate::Lifetime; -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::cmp::Ordering; -use core::marker::PhantomData; -use core::ptr; -use proc_macro2::extra::DelimSpan; -use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; - -/// Internal type which is used instead of `TokenTree` to represent a token tree -/// within a `TokenBuffer`. -enum Entry { - // Mimicking types from proc-macro. - // Group entries contain the offset to the matching End entry. - Group(Group, usize), - Ident(Ident), - Punct(Punct), - Literal(Literal), - // End entries contain the offset (negative) to the start of the buffer, and - // offset (negative) to the matching Group entry. - End(isize, isize), -} - -/// A buffer that can be efficiently traversed multiple times, unlike -/// `TokenStream` which requires a deep copy in order to traverse more than -/// once. -pub struct TokenBuffer { - // NOTE: Do not implement clone on this - while the current design could be - // cloned, other designs which could be desirable may not be cloneable. - entries: Box<[Entry]>, -} - -impl TokenBuffer { - fn recursive_new(entries: &mut Vec<Entry>, stream: TokenStream) { - for tt in stream { - match tt { - TokenTree::Ident(ident) => entries.push(Entry::Ident(ident)), - TokenTree::Punct(punct) => entries.push(Entry::Punct(punct)), - TokenTree::Literal(literal) => entries.push(Entry::Literal(literal)), - TokenTree::Group(group) => { - let group_start_index = entries.len(); - entries.push(Entry::End(0, 0)); // we replace this below - Self::recursive_new(entries, group.stream()); - let group_end_index = entries.len(); - let group_offset = group_end_index - group_start_index; - entries.push(Entry::End( - -(group_end_index as isize), - -(group_offset as isize), - )); - entries[group_start_index] = Entry::Group(group, group_offset); - } - } - } - } - - /// Creates a `TokenBuffer` containing all the tokens from the input - /// `proc_macro::TokenStream`. - #[cfg(feature = "proc-macro")] - #[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))] - pub fn new(stream: proc_macro::TokenStream) -> Self { - Self::new2(stream.into()) - } - - /// Creates a `TokenBuffer` containing all the tokens from the input - /// `proc_macro2::TokenStream`. - pub fn new2(stream: TokenStream) -> Self { - let mut entries = Vec::new(); - Self::recursive_new(&mut entries, stream); - entries.push(Entry::End(-(entries.len() as isize), 0)); - Self { - entries: entries.into_boxed_slice(), - } - } - - /// Creates a cursor referencing the first token in the buffer and able to - /// traverse until the end of the buffer. - pub fn begin(&self) -> Cursor { - let ptr = self.entries.as_ptr(); - unsafe { Cursor::create(ptr, ptr.add(self.entries.len() - 1)) } - } -} - -/// A cheaply copyable cursor into a `TokenBuffer`. -/// -/// This cursor holds a shared reference into the immutable data which is used -/// internally to represent a `TokenStream`, and can be efficiently manipulated -/// and copied around. -/// -/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer` -/// object and get a cursor to its first token with `begin()`. -pub struct Cursor<'a> { - // The current entry which the `Cursor` is pointing at. - ptr: *const Entry, - // This is the only `Entry::End` object which this cursor is allowed to - // point at. All other `End` objects are skipped over in `Cursor::create`. - scope: *const Entry, - // Cursor is covariant in 'a. This field ensures that our pointers are still - // valid. - marker: PhantomData<&'a Entry>, -} - -impl<'a> Cursor<'a> { - /// Creates a cursor referencing a static empty TokenStream. - pub fn empty() -> Self { - // It's safe in this situation for us to put an `Entry` object in global - // storage, despite it not actually being safe to send across threads - // (`Ident` is a reference into a thread-local table). This is because - // this entry never includes a `Ident` object. - // - // This wrapper struct allows us to break the rules and put a `Sync` - // object in global storage. - struct UnsafeSyncEntry(Entry); - unsafe impl Sync for UnsafeSyncEntry {} - static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0, 0)); - - Cursor { - ptr: &EMPTY_ENTRY.0, - scope: &EMPTY_ENTRY.0, - marker: PhantomData, - } - } - - /// This create method intelligently exits non-explicitly-entered - /// `None`-delimited scopes when the cursor reaches the end of them, - /// allowing for them to be treated transparently. - unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self { - // NOTE: If we're looking at a `End`, we want to advance the cursor - // past it, unless `ptr == scope`, which means that we're at the edge of - // our cursor's scope. We should only have `ptr != scope` at the exit - // from None-delimited groups entered with `ignore_none`. - while let Entry::End(..) = unsafe { &*ptr } { - if ptr::eq(ptr, scope) { - break; - } - ptr = unsafe { ptr.add(1) }; - } - - Cursor { - ptr, - scope, - marker: PhantomData, - } - } - - /// Get the current entry. - fn entry(self) -> &'a Entry { - unsafe { &*self.ptr } - } - - /// Bump the cursor to point at the next token after the current one. This - /// is undefined behavior if the cursor is currently looking at an - /// `Entry::End`. - /// - /// If the cursor is looking at an `Entry::Group`, the bumped cursor will - /// point at the first token in the group (with the same scope end). - unsafe fn bump_ignore_group(self) -> Cursor<'a> { - unsafe { Cursor::create(self.ptr.add(1), self.scope) } - } - - /// While the cursor is looking at a `None`-delimited group, move it to look - /// at the first token inside instead. If the group is empty, this will move - /// the cursor past the `None`-delimited group. - /// - /// WARNING: This mutates its argument. - fn ignore_none(&mut self) { - while let Entry::Group(group, _) = self.entry() { - if group.delimiter() == Delimiter::None { - unsafe { *self = self.bump_ignore_group() }; - } else { - break; - } - } - } - - /// Checks whether the cursor is currently pointing at the end of its valid - /// scope. - pub fn eof(self) -> bool { - // We're at eof if we're at the end of our scope. - ptr::eq(self.ptr, self.scope) - } - - /// If the cursor is pointing at a `Ident`, returns it along with a cursor - /// pointing at the next `TokenTree`. - pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> { - self.ignore_none(); - match self.entry() { - Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump_ignore_group() })), - _ => None, - } - } - - /// If the cursor is pointing at a `Punct`, returns it along with a cursor - /// pointing at the next `TokenTree`. - pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> { - self.ignore_none(); - match self.entry() { - Entry::Punct(punct) if punct.as_char() != '\'' => { - Some((punct.clone(), unsafe { self.bump_ignore_group() })) - } - _ => None, - } - } - - /// If the cursor is pointing at a `Literal`, return it along with a cursor - /// pointing at the next `TokenTree`. - pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> { - self.ignore_none(); - match self.entry() { - Entry::Literal(literal) => Some((literal.clone(), unsafe { self.bump_ignore_group() })), - _ => None, - } - } - - /// If the cursor is pointing at a `Lifetime`, returns it along with a - /// cursor pointing at the next `TokenTree`. - pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> { - self.ignore_none(); - match self.entry() { - Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => { - let next = unsafe { self.bump_ignore_group() }; - let (ident, rest) = next.ident()?; - let lifetime = Lifetime { - apostrophe: punct.span(), - ident, - }; - Some((lifetime, rest)) - } - _ => None, - } - } - - /// If the cursor is pointing at a `Group` with the given delimiter, returns - /// a cursor into that group and one pointing to the next `TokenTree`. - pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, DelimSpan, Cursor<'a>)> { - // If we're not trying to enter a none-delimited group, we want to - // ignore them. We have to make sure to _not_ ignore them when we want - // to enter them, of course. For obvious reasons. - if delim != Delimiter::None { - self.ignore_none(); - } - - if let Entry::Group(group, end_offset) = self.entry() { - if group.delimiter() == delim { - let span = group.delim_span(); - let end_of_group = unsafe { self.ptr.add(*end_offset) }; - let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) }; - let after_group = unsafe { Cursor::create(end_of_group, self.scope) }; - return Some((inside_of_group, span, after_group)); - } - } - - None - } - - /// If the cursor is pointing at a `Group`, returns a cursor into the group - /// and one pointing to the next `TokenTree`. - pub fn any_group(self) -> Option<(Cursor<'a>, Delimiter, DelimSpan, Cursor<'a>)> { - if let Entry::Group(group, end_offset) = self.entry() { - let delimiter = group.delimiter(); - let span = group.delim_span(); - let end_of_group = unsafe { self.ptr.add(*end_offset) }; - let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) }; - let after_group = unsafe { Cursor::create(end_of_group, self.scope) }; - return Some((inside_of_group, delimiter, span, after_group)); - } - - None - } - - pub(crate) fn any_group_token(self) -> Option<(Group, Cursor<'a>)> { - if let Entry::Group(group, end_offset) = self.entry() { - let end_of_group = unsafe { self.ptr.add(*end_offset) }; - let after_group = unsafe { Cursor::create(end_of_group, self.scope) }; - return Some((group.clone(), after_group)); - } - - None - } - - /// Copies all remaining tokens visible from this cursor into a - /// `TokenStream`. - pub fn token_stream(self) -> TokenStream { - let mut tokens = TokenStream::new(); - let mut cursor = self; - while let Some((tt, rest)) = cursor.token_tree() { - tokens.append(tt); - cursor = rest; - } - tokens - } - - /// If the cursor is pointing at a `TokenTree`, returns it along with a - /// cursor pointing at the next `TokenTree`. - /// - /// Returns `None` if the cursor has reached the end of its stream. - /// - /// This method does not treat `None`-delimited groups as transparent, and - /// will return a `Group(None, ..)` if the cursor is looking at one. - pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> { - let (tree, len) = match self.entry() { - Entry::Group(group, end_offset) => (group.clone().into(), *end_offset), - Entry::Literal(literal) => (literal.clone().into(), 1), - Entry::Ident(ident) => (ident.clone().into(), 1), - Entry::Punct(punct) => (punct.clone().into(), 1), - Entry::End(..) => return None, - }; - - let rest = unsafe { Cursor::create(self.ptr.add(len), self.scope) }; - Some((tree, rest)) - } - - /// Returns the `Span` of the current token, or `Span::call_site()` if this - /// cursor points to eof. - pub fn span(mut self) -> Span { - match self.entry() { - Entry::Group(group, _) => group.span(), - Entry::Literal(literal) => literal.span(), - Entry::Ident(ident) => ident.span(), - Entry::Punct(punct) => punct.span(), - Entry::End(_, offset) => { - self.ptr = unsafe { self.ptr.offset(*offset) }; - if let Entry::Group(group, _) = self.entry() { - group.span_close() - } else { - Span::call_site() - } - } - } - } - - /// Returns the `Span` of the token immediately prior to the position of - /// this cursor, or of the current token if there is no previous one. - #[cfg(any(feature = "full", feature = "derive"))] - pub(crate) fn prev_span(mut self) -> Span { - if start_of_buffer(self) < self.ptr { - self.ptr = unsafe { self.ptr.sub(1) }; - } - self.span() - } - - /// Skip over the next token that is not a None-delimited group, without - /// cloning it. Returns `None` if this cursor points to eof. - /// - /// This method treats `'lifetimes` as a single token. - pub(crate) fn skip(mut self) -> Option<Cursor<'a>> { - self.ignore_none(); - - let len = match self.entry() { - Entry::End(..) => return None, - - // Treat lifetimes as a single tt for the purposes of 'skip'. - Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => { - match unsafe { &*self.ptr.add(1) } { - Entry::Ident(_) => 2, - _ => 1, - } - } - - Entry::Group(_, end_offset) => *end_offset, - _ => 1, - }; - - Some(unsafe { Cursor::create(self.ptr.add(len), self.scope) }) - } - - pub(crate) fn scope_delimiter(self) -> Delimiter { - match unsafe { &*self.scope } { - Entry::End(_, offset) => match unsafe { &*self.scope.offset(*offset) } { - Entry::Group(group, _) => group.delimiter(), - _ => Delimiter::None, - }, - _ => unreachable!(), - } - } -} - -impl<'a> Copy for Cursor<'a> {} - -impl<'a> Clone for Cursor<'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a> Eq for Cursor<'a> {} - -impl<'a> PartialEq for Cursor<'a> { - fn eq(&self, other: &Self) -> bool { - ptr::eq(self.ptr, other.ptr) - } -} - -impl<'a> PartialOrd for Cursor<'a> { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - if same_buffer(*self, *other) { - Some(cmp_assuming_same_buffer(*self, *other)) - } else { - None - } - } -} - -pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool { - ptr::eq(a.scope, b.scope) -} - -pub(crate) fn same_buffer(a: Cursor, b: Cursor) -> bool { - ptr::eq(start_of_buffer(a), start_of_buffer(b)) -} - -fn start_of_buffer(cursor: Cursor) -> *const Entry { - unsafe { - match &*cursor.scope { - Entry::End(offset, _) => cursor.scope.offset(*offset), - _ => unreachable!(), - } - } -} - -pub(crate) fn cmp_assuming_same_buffer(a: Cursor, b: Cursor) -> Ordering { - a.ptr.cmp(&b.ptr) -} - -pub(crate) fn open_span_of_group(cursor: Cursor) -> Span { - match cursor.entry() { - Entry::Group(group, _) => group.span_open(), - _ => cursor.span(), - } -} diff --git a/deps/crates/vendor/syn-v2/src/classify.rs b/deps/crates/vendor/syn-v2/src/classify.rs deleted file mode 100644 index 6d5edbd559ab..000000000000 --- a/deps/crates/vendor/syn-v2/src/classify.rs +++ /dev/null @@ -1,311 +0,0 @@ -#[cfg(feature = "full")] -use crate::expr::Expr; -#[cfg(any(feature = "printing", feature = "full"))] -use crate::generics::TypeParamBound; -#[cfg(any(feature = "printing", feature = "full"))] -use crate::path::{Path, PathArguments}; -#[cfg(any(feature = "printing", feature = "full"))] -use crate::punctuated::Punctuated; -#[cfg(any(feature = "printing", feature = "full"))] -use crate::ty::{ReturnType, Type}; -#[cfg(any(feature = "printing", feature = "full"))] -use core::ops::ControlFlow; -#[cfg(feature = "full")] -use proc_macro2::{Delimiter, TokenStream, TokenTree}; - -#[cfg(feature = "full")] -pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { - match expr { - Expr::Macro(expr) => !expr.mac.delimiter.is_brace(), - _ => requires_comma_to_be_match_arm(expr), - } -} - -#[cfg(feature = "full")] -pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool { - match expr { - Expr::If(_) - | Expr::Match(_) - | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc - | Expr::While(_) - | Expr::Loop(_) - | Expr::ForLoop(_) - | Expr::TryBlock(_) - | Expr::Const(_) => false, - - Expr::Array(_) - | Expr::Assign(_) - | Expr::Async(_) - | Expr::Await(_) - | Expr::Binary(_) - | Expr::Break(_) - | Expr::Call(_) - | Expr::Cast(_) - | Expr::Closure(_) - | Expr::Continue(_) - | Expr::Field(_) - | Expr::Group(_) - | Expr::Index(_) - | Expr::Infer(_) - | Expr::Let(_) - | Expr::Lit(_) - | Expr::Macro(_) - | Expr::MethodCall(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::Range(_) - | Expr::RawAddr(_) - | Expr::Reference(_) - | Expr::Repeat(_) - | Expr::Return(_) - | Expr::Struct(_) - | Expr::Try(_) - | Expr::Tuple(_) - | Expr::Unary(_) - | Expr::Yield(_) - | Expr::Verbatim(_) => true, - } -} - -#[cfg(feature = "printing")] -pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool { - loop { - match ty { - Type::BareFn(t) => match &t.output { - ReturnType::Default => return false, - ReturnType::Type(_, ret) => ty = ret, - }, - Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { - ControlFlow::Break(trailing_path) => return trailing_path, - ControlFlow::Continue(t) => ty = t, - }, - Type::Path(t) => match last_type_in_path(&t.path) { - ControlFlow::Break(trailing_path) => return trailing_path, - ControlFlow::Continue(t) => ty = t, - }, - Type::Ptr(t) => ty = &t.elem, - Type::Reference(t) => ty = &t.elem, - Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { - ControlFlow::Break(trailing_path) => return trailing_path, - ControlFlow::Continue(t) => ty = t, - }, - - Type::Array(_) - | Type::Group(_) - | Type::Infer(_) - | Type::Macro(_) - | Type::Never(_) - | Type::Paren(_) - | Type::Slice(_) - | Type::Tuple(_) - | Type::Verbatim(_) => return false, - } - } - - fn last_type_in_path(path: &Path) -> ControlFlow<bool, &Type> { - match &path.segments.last().unwrap().arguments { - PathArguments::None => ControlFlow::Break(true), - PathArguments::AngleBracketed(_) => ControlFlow::Break(false), - PathArguments::Parenthesized(arg) => match &arg.output { - ReturnType::Default => ControlFlow::Break(false), - ReturnType::Type(_, ret) => ControlFlow::Continue(ret), - }, - } - } - - fn last_type_in_bounds( - bounds: &Punctuated<TypeParamBound, Token![+]>, - ) -> ControlFlow<bool, &Type> { - match bounds.last().unwrap() { - TypeParamBound::Trait(t) => last_type_in_path(&t.path), - TypeParamBound::Lifetime(_) - | TypeParamBound::PreciseCapture(_) - | TypeParamBound::Verbatim(_) => ControlFlow::Break(false), - } - } -} - -/// Whether the expression's first token is the label of a loop/block. -#[cfg(all(feature = "printing", feature = "full"))] -pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { - loop { - match expr { - Expr::Block(e) => return e.label.is_some(), - Expr::ForLoop(e) => return e.label.is_some(), - Expr::Loop(e) => return e.label.is_some(), - Expr::While(e) => return e.label.is_some(), - - Expr::Assign(e) => expr = &e.left, - Expr::Await(e) => expr = &e.base, - Expr::Binary(e) => expr = &e.left, - Expr::Call(e) => expr = &e.func, - Expr::Cast(e) => expr = &e.expr, - Expr::Field(e) => expr = &e.base, - Expr::Index(e) => expr = &e.expr, - Expr::MethodCall(e) => expr = &e.receiver, - Expr::Range(e) => match &e.start { - Some(start) => expr = start, - None => return false, - }, - Expr::Try(e) => expr = &e.expr, - - Expr::Array(_) - | Expr::Async(_) - | Expr::Break(_) - | Expr::Closure(_) - | Expr::Const(_) - | Expr::Continue(_) - | Expr::Group(_) - | Expr::If(_) - | Expr::Infer(_) - | Expr::Let(_) - | Expr::Lit(_) - | Expr::Macro(_) - | Expr::Match(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::RawAddr(_) - | Expr::Reference(_) - | Expr::Repeat(_) - | Expr::Return(_) - | Expr::Struct(_) - | Expr::TryBlock(_) - | Expr::Tuple(_) - | Expr::Unary(_) - | Expr::Unsafe(_) - | Expr::Verbatim(_) - | Expr::Yield(_) => return false, - } - } -} - -/// Whether the expression's last token is `}`. -#[cfg(feature = "full")] -pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool { - loop { - match expr { - Expr::Async(_) - | Expr::Block(_) - | Expr::Const(_) - | Expr::ForLoop(_) - | Expr::If(_) - | Expr::Loop(_) - | Expr::Match(_) - | Expr::Struct(_) - | Expr::TryBlock(_) - | Expr::Unsafe(_) - | Expr::While(_) => return true, - - Expr::Assign(e) => expr = &e.right, - Expr::Binary(e) => expr = &e.right, - Expr::Break(e) => match &e.expr { - Some(e) => expr = e, - None => return false, - }, - Expr::Cast(e) => return type_trailing_brace(&e.ty), - Expr::Closure(e) => expr = &e.body, - Expr::Let(e) => expr = &e.expr, - Expr::Macro(e) => return e.mac.delimiter.is_brace(), - Expr::Range(e) => match &e.end { - Some(end) => expr = end, - None => return false, - }, - Expr::RawAddr(e) => expr = &e.expr, - Expr::Reference(e) => expr = &e.expr, - Expr::Return(e) => match &e.expr { - Some(e) => expr = e, - None => return false, - }, - Expr::Unary(e) => expr = &e.expr, - Expr::Verbatim(e) => return tokens_trailing_brace(e), - Expr::Yield(e) => match &e.expr { - Some(e) => expr = e, - None => return false, - }, - - Expr::Array(_) - | Expr::Await(_) - | Expr::Call(_) - | Expr::Continue(_) - | Expr::Field(_) - | Expr::Group(_) - | Expr::Index(_) - | Expr::Infer(_) - | Expr::Lit(_) - | Expr::MethodCall(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::Repeat(_) - | Expr::Try(_) - | Expr::Tuple(_) => return false, - } - } - - fn type_trailing_brace(mut ty: &Type) -> bool { - loop { - match ty { - Type::BareFn(t) => match &t.output { - ReturnType::Default => return false, - ReturnType::Type(_, ret) => ty = ret, - }, - Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { - ControlFlow::Break(trailing_brace) => return trailing_brace, - ControlFlow::Continue(t) => ty = t, - }, - Type::Macro(t) => return t.mac.delimiter.is_brace(), - Type::Path(t) => match last_type_in_path(&t.path) { - Some(t) => ty = t, - None => return false, - }, - Type::Ptr(t) => ty = &t.elem, - Type::Reference(t) => ty = &t.elem, - Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { - ControlFlow::Break(trailing_brace) => return trailing_brace, - ControlFlow::Continue(t) => ty = t, - }, - Type::Verbatim(t) => return tokens_trailing_brace(t), - - Type::Array(_) - | Type::Group(_) - | Type::Infer(_) - | Type::Never(_) - | Type::Paren(_) - | Type::Slice(_) - | Type::Tuple(_) => return false, - } - } - } - - fn last_type_in_path(path: &Path) -> Option<&Type> { - match &path.segments.last().unwrap().arguments { - PathArguments::None | PathArguments::AngleBracketed(_) => None, - PathArguments::Parenthesized(arg) => match &arg.output { - ReturnType::Default => None, - ReturnType::Type(_, ret) => Some(ret), - }, - } - } - - fn last_type_in_bounds( - bounds: &Punctuated<TypeParamBound, Token![+]>, - ) -> ControlFlow<bool, &Type> { - match bounds.last().unwrap() { - TypeParamBound::Trait(t) => match last_type_in_path(&t.path) { - Some(t) => ControlFlow::Continue(t), - None => ControlFlow::Break(false), - }, - TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => { - ControlFlow::Break(false) - } - TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)), - } - } - - fn tokens_trailing_brace(tokens: &TokenStream) -> bool { - if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() { - last.delimiter() == Delimiter::Brace - } else { - false - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/custom_keyword.rs b/deps/crates/vendor/syn-v2/src/custom_keyword.rs deleted file mode 100644 index cc4f632c981a..000000000000 --- a/deps/crates/vendor/syn-v2/src/custom_keyword.rs +++ /dev/null @@ -1,260 +0,0 @@ -/// Define a type that supports parsing and printing a given identifier as if it -/// were a keyword. -/// -/// # Usage -/// -/// As a convention, it is recommended that this macro be invoked within a -/// module called `kw` or `keyword` and that the resulting parser be invoked -/// with a `kw::` or `keyword::` prefix. -/// -/// ``` -/// mod kw { -/// syn::custom_keyword!(whatever); -/// } -/// ``` -/// -/// The generated syntax tree node supports the following operations just like -/// any built-in keyword token. -/// -/// - [Peeking] — `input.peek(kw::whatever)` -/// -/// - [Parsing] — `input.parse::<kw::whatever>()?` -/// -/// - [Printing] — `quote!( ... #whatever_token ... )` -/// -/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)` -/// -/// - Field access to its span — `let sp = whatever_token.span` -/// -/// [Peeking]: crate::parse::ParseBuffer::peek -/// [Parsing]: crate::parse::ParseBuffer::parse -/// [Printing]: quote::ToTokens -/// [`Span`]: proc_macro2::Span -/// -/// # Example -/// -/// This example parses input that looks like `bool = true` or `str = "value"`. -/// The key must be either the identifier `bool` or the identifier `str`. If -/// `bool`, the value may be either `true` or `false`. If `str`, the value may -/// be any string literal. -/// -/// The symbols `bool` and `str` are not reserved keywords in Rust so these are -/// not considered keywords in the `syn::token` module. Like any other -/// identifier that is not a keyword, these can be declared as custom keywords -/// by crates that need to use them as such. -/// -/// ``` -/// use syn::{LitBool, LitStr, Result, Token}; -/// use syn::parse::{Parse, ParseStream}; -/// -/// mod kw { -/// syn::custom_keyword!(bool); -/// syn::custom_keyword!(str); -/// } -/// -/// enum Argument { -/// Bool { -/// bool_token: kw::bool, -/// eq_token: Token![=], -/// value: LitBool, -/// }, -/// Str { -/// str_token: kw::str, -/// eq_token: Token![=], -/// value: LitStr, -/// }, -/// } -/// -/// impl Parse for Argument { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let lookahead = input.lookahead1(); -/// if lookahead.peek(kw::bool) { -/// Ok(Argument::Bool { -/// bool_token: input.parse::<kw::bool>()?, -/// eq_token: input.parse()?, -/// value: input.parse()?, -/// }) -/// } else if lookahead.peek(kw::str) { -/// Ok(Argument::Str { -/// str_token: input.parse::<kw::str>()?, -/// eq_token: input.parse()?, -/// value: input.parse()?, -/// }) -/// } else { -/// Err(lookahead.error()) -/// } -/// } -/// } -/// ``` -#[macro_export] -macro_rules! custom_keyword { - ($ident:ident) => { - #[allow(non_camel_case_types)] - pub struct $ident { - #[allow(dead_code)] - pub span: $crate::__private::Span, - } - - #[doc(hidden)] - #[allow(dead_code, non_snake_case)] - pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>( - span: __S, - ) -> $ident { - $ident { - span: $crate::__private::IntoSpans::into_spans(span), - } - } - - const _: () = { - impl $crate::__private::Default for $ident { - fn default() -> Self { - $ident { - span: $crate::__private::Span::call_site(), - } - } - } - - $crate::impl_parse_for_custom_keyword!($ident); - $crate::impl_to_tokens_for_custom_keyword!($ident); - $crate::impl_clone_for_custom_keyword!($ident); - $crate::impl_extra_traits_for_custom_keyword!($ident); - }; - }; -} - -// Not public API. -#[cfg(feature = "parsing")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_parse_for_custom_keyword { - ($ident:ident) => { - // For peek. - impl $crate::__private::CustomToken for $ident { - fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool { - if let $crate::__private::Some((ident, _rest)) = cursor.ident() { - ident == $crate::__private::stringify!($ident) - } else { - false - } - } - - fn display() -> &'static $crate::__private::str { - $crate::__private::concat!("`", $crate::__private::stringify!($ident), "`") - } - } - - impl $crate::parse::Parse for $ident { - fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { - input.step(|cursor| { - if let $crate::__private::Some((ident, rest)) = cursor.ident() { - if ident == $crate::__private::stringify!($ident) { - return $crate::__private::Ok(($ident { span: ident.span() }, rest)); - } - } - $crate::__private::Err(cursor.error($crate::__private::concat!( - "expected `", - $crate::__private::stringify!($ident), - "`", - ))) - }) - } - } - }; -} - -// Not public API. -#[cfg(not(feature = "parsing"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_parse_for_custom_keyword { - ($ident:ident) => {}; -} - -// Not public API. -#[cfg(feature = "printing")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_to_tokens_for_custom_keyword { - ($ident:ident) => { - impl $crate::__private::ToTokens for $ident { - fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { - let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span); - $crate::__private::TokenStreamExt::append(tokens, ident); - } - } - }; -} - -// Not public API. -#[cfg(not(feature = "printing"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_to_tokens_for_custom_keyword { - ($ident:ident) => {}; -} - -// Not public API. -#[cfg(feature = "clone-impls")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_clone_for_custom_keyword { - ($ident:ident) => { - impl $crate::__private::Copy for $ident {} - - #[allow(clippy::expl_impl_clone_on_copy)] - impl $crate::__private::Clone for $ident { - fn clone(&self) -> Self { - *self - } - } - }; -} - -// Not public API. -#[cfg(not(feature = "clone-impls"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_clone_for_custom_keyword { - ($ident:ident) => {}; -} - -// Not public API. -#[cfg(feature = "extra-traits")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_extra_traits_for_custom_keyword { - ($ident:ident) => { - impl $crate::__private::Debug for $ident { - fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult { - $crate::__private::Formatter::write_str( - f, - $crate::__private::concat!( - "Keyword [", - $crate::__private::stringify!($ident), - "]", - ), - ) - } - } - - impl $crate::__private::Eq for $ident {} - - impl $crate::__private::PartialEq for $ident { - fn eq(&self, _other: &Self) -> $crate::__private::bool { - true - } - } - - impl $crate::__private::Hash for $ident { - fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} - } - }; -} - -// Not public API. -#[cfg(not(feature = "extra-traits"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_extra_traits_for_custom_keyword { - ($ident:ident) => {}; -} diff --git a/deps/crates/vendor/syn-v2/src/custom_punctuation.rs b/deps/crates/vendor/syn-v2/src/custom_punctuation.rs deleted file mode 100644 index 58955c7ff196..000000000000 --- a/deps/crates/vendor/syn-v2/src/custom_punctuation.rs +++ /dev/null @@ -1,305 +0,0 @@ -/// Define a type that supports parsing and printing a multi-character symbol -/// as if it were a punctuation token. -/// -/// # Usage -/// -/// ``` -/// syn::custom_punctuation!(LeftRightArrow, <=>); -/// ``` -/// -/// The generated syntax tree node supports the following operations just like -/// any built-in punctuation token. -/// -/// - [Peeking] — `input.peek(LeftRightArrow)` -/// -/// - [Parsing] — `input.parse::<LeftRightArrow>()?` -/// -/// - [Printing] — `quote!( ... #lrarrow ... )` -/// -/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)` -/// -/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])` -/// -/// - Field access to its spans — `let spans = lrarrow.spans` -/// -/// [Peeking]: crate::parse::ParseBuffer::peek -/// [Parsing]: crate::parse::ParseBuffer::parse -/// [Printing]: quote::ToTokens -/// [`Span`]: proc_macro2::Span -/// -/// # Example -/// -/// ``` -/// use core::iter; -/// use proc_macro2::{TokenStream, TokenTree}; -/// use syn::parse::{Parse, ParseStream, Peek, Result}; -/// use syn::punctuated::Punctuated; -/// use syn::Expr; -/// -/// syn::custom_punctuation!(PathSeparator, </>); -/// -/// // expr </> expr </> expr ... -/// struct PathSegments { -/// segments: Punctuated<Expr, PathSeparator>, -/// } -/// -/// impl Parse for PathSegments { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let mut segments = Punctuated::new(); -/// -/// let first = parse_until(input, PathSeparator)?; -/// segments.push_value(syn::parse2(first)?); -/// -/// while input.peek(PathSeparator) { -/// segments.push_punct(input.parse()?); -/// -/// let next = parse_until(input, PathSeparator)?; -/// segments.push_value(syn::parse2(next)?); -/// } -/// -/// Ok(PathSegments { segments }) -/// } -/// } -/// -/// fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> { -/// let mut tokens = TokenStream::new(); -/// while !input.is_empty() && !input.peek(end) { -/// let next: TokenTree = input.parse()?; -/// tokens.extend(iter::once(next)); -/// } -/// Ok(tokens) -/// } -/// -/// fn main() { -/// let input = r#" a::b </> c::d::e "#; -/// let _: PathSegments = syn::parse_str(input).unwrap(); -/// } -/// ``` -#[macro_export] -macro_rules! custom_punctuation { - ($ident:ident, $($tt:tt)+) => { - pub struct $ident { - #[allow(dead_code)] - pub spans: $crate::custom_punctuation_repr!($($tt)+), - } - - #[doc(hidden)] - #[allow(dead_code, non_snake_case)] - pub fn $ident<__S: $crate::__private::IntoSpans<$crate::custom_punctuation_repr!($($tt)+)>>( - spans: __S, - ) -> $ident { - let _validate_len = 0 $(+ $crate::custom_punctuation_len!(strict, $tt))*; - $ident { - spans: $crate::__private::IntoSpans::into_spans(spans) - } - } - - const _: () = { - impl $crate::__private::Default for $ident { - fn default() -> Self { - $ident($crate::__private::Span::call_site()) - } - } - - $crate::impl_parse_for_custom_punctuation!($ident, $($tt)+); - $crate::impl_to_tokens_for_custom_punctuation!($ident, $($tt)+); - $crate::impl_clone_for_custom_punctuation!($ident, $($tt)+); - $crate::impl_extra_traits_for_custom_punctuation!($ident, $($tt)+); - }; - }; -} - -// Not public API. -#[cfg(feature = "parsing")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_parse_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => { - impl $crate::__private::CustomToken for $ident { - fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool { - $crate::__private::peek_punct(cursor, $crate::stringify_punct!($($tt)+)) - } - - fn display() -> &'static $crate::__private::str { - $crate::__private::concat!("`", $crate::stringify_punct!($($tt)+), "`") - } - } - - impl $crate::parse::Parse for $ident { - fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { - let spans: $crate::custom_punctuation_repr!($($tt)+) = - $crate::__private::parse_punct(input, $crate::stringify_punct!($($tt)+))?; - Ok($ident(spans)) - } - } - }; -} - -// Not public API. -#[cfg(not(feature = "parsing"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_parse_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => {}; -} - -// Not public API. -#[cfg(feature = "printing")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_to_tokens_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => { - impl $crate::__private::ToTokens for $ident { - fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { - $crate::__private::print_punct($crate::stringify_punct!($($tt)+), &self.spans, tokens) - } - } - }; -} - -// Not public API. -#[cfg(not(feature = "printing"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_to_tokens_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => {}; -} - -// Not public API. -#[cfg(feature = "clone-impls")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_clone_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => { - impl $crate::__private::Copy for $ident {} - - #[allow(clippy::expl_impl_clone_on_copy)] - impl $crate::__private::Clone for $ident { - fn clone(&self) -> Self { - *self - } - } - }; -} - -// Not public API. -#[cfg(not(feature = "clone-impls"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_clone_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => {}; -} - -// Not public API. -#[cfg(feature = "extra-traits")] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_extra_traits_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => { - impl $crate::__private::Debug for $ident { - fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult { - $crate::__private::Formatter::write_str(f, $crate::__private::stringify!($ident)) - } - } - - impl $crate::__private::Eq for $ident {} - - impl $crate::__private::PartialEq for $ident { - fn eq(&self, _other: &Self) -> $crate::__private::bool { - true - } - } - - impl $crate::__private::Hash for $ident { - fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} - } - }; -} - -// Not public API. -#[cfg(not(feature = "extra-traits"))] -#[doc(hidden)] -#[macro_export] -macro_rules! impl_extra_traits_for_custom_punctuation { - ($ident:ident, $($tt:tt)+) => {}; -} - -// Not public API. -#[doc(hidden)] -#[macro_export] -macro_rules! custom_punctuation_repr { - ($($tt:tt)+) => { - [$crate::__private::Span; 0 $(+ $crate::custom_punctuation_len!(lenient, $tt))+] - }; -} - -// Not public API. -#[doc(hidden)] -#[macro_export] -#[rustfmt::skip] -macro_rules! custom_punctuation_len { - ($mode:ident, &) => { 1 }; - ($mode:ident, &&) => { 2 }; - ($mode:ident, &=) => { 2 }; - ($mode:ident, @) => { 1 }; - ($mode:ident, ^) => { 1 }; - ($mode:ident, ^=) => { 2 }; - ($mode:ident, :) => { 1 }; - ($mode:ident, ,) => { 1 }; - ($mode:ident, $) => { 1 }; - ($mode:ident, .) => { 1 }; - ($mode:ident, ..) => { 2 }; - ($mode:ident, ...) => { 3 }; - ($mode:ident, ..=) => { 3 }; - ($mode:ident, =) => { 1 }; - ($mode:ident, ==) => { 2 }; - ($mode:ident, =>) => { 2 }; - ($mode:ident, >=) => { 2 }; - ($mode:ident, >) => { 1 }; - ($mode:ident, <-) => { 2 }; - ($mode:ident, <=) => { 2 }; - ($mode:ident, <) => { 1 }; - ($mode:ident, -) => { 1 }; - ($mode:ident, -=) => { 2 }; - ($mode:ident, !=) => { 2 }; - ($mode:ident, !) => { 1 }; - ($mode:ident, |) => { 1 }; - ($mode:ident, |=) => { 2 }; - ($mode:ident, ||) => { 2 }; - ($mode:ident, ::) => { 2 }; - ($mode:ident, %) => { 1 }; - ($mode:ident, %=) => { 2 }; - ($mode:ident, +) => { 1 }; - ($mode:ident, +=) => { 2 }; - ($mode:ident, #) => { 1 }; - ($mode:ident, ?) => { 1 }; - ($mode:ident, ->) => { 2 }; - ($mode:ident, ;) => { 1 }; - ($mode:ident, <<) => { 2 }; - ($mode:ident, <<=) => { 3 }; - ($mode:ident, >>) => { 2 }; - ($mode:ident, >>=) => { 3 }; - ($mode:ident, /) => { 1 }; - ($mode:ident, /=) => { 2 }; - ($mode:ident, *) => { 1 }; - ($mode:ident, *=) => { 2 }; - ($mode:ident, ~) => { 1 }; - (lenient, $tt:tt) => { 0 }; - (strict, $tt:tt) => {{ $crate::custom_punctuation_unexpected!($tt); 0 }}; -} - -// Not public API. -#[doc(hidden)] -#[macro_export] -macro_rules! custom_punctuation_unexpected { - () => {}; -} - -// Not public API. -#[doc(hidden)] -#[macro_export] -macro_rules! stringify_punct { - ($($tt:tt)+) => { - $crate::__private::concat!($($crate::__private::stringify!($tt)),+) - }; -} diff --git a/deps/crates/vendor/syn-v2/src/data.rs b/deps/crates/vendor/syn-v2/src/data.rs deleted file mode 100644 index 0fdbe7139ff0..000000000000 --- a/deps/crates/vendor/syn-v2/src/data.rs +++ /dev/null @@ -1,410 +0,0 @@ -use crate::attr::Attribute; -use crate::expr::{Expr, Index, Member}; -use crate::ident::Ident; -use crate::punctuated::{self, Punctuated}; -use crate::restriction::{FieldMutability, Visibility}; -use crate::token; -use crate::ty::Type; -use alloc::vec::Vec; - -ast_struct! { - /// An enum variant. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Variant { - pub attrs: Vec<Attribute>, - - /// Name of the variant. - pub ident: Ident, - - /// Content stored in the variant. - pub fields: Fields, - - /// Explicit discriminant: `Variant = 1` - pub discriminant: Option<(Token![=], Expr)>, - } -} - -ast_enum_of_structs! { - /// Data stored within an enum variant or struct. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum Fields { - /// Named fields of a struct or struct variant such as `Point { x: f64, - /// y: f64 }`. - Named(FieldsNamed), - - /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. - Unnamed(FieldsUnnamed), - - /// Unit struct or unit variant such as `None`. - Unit, - } -} - -ast_struct! { - /// Named fields of a struct or struct variant such as `Point { x: f64, - /// y: f64 }`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct FieldsNamed { - pub brace_token: token::Brace, - pub named: Punctuated<Field, Token![,]>, - } -} - -ast_struct! { - /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct FieldsUnnamed { - pub paren_token: token::Paren, - pub unnamed: Punctuated<Field, Token![,]>, - } -} - -impl Fields { - /// Get an iterator over the borrowed [`Field`] items in this object. This - /// iterator can be used to iterate over a named or unnamed struct or - /// variant's fields uniformly. - pub fn iter(&self) -> punctuated::Iter<Field> { - match self { - Fields::Unit => crate::punctuated::empty_punctuated_iter(), - Fields::Named(f) => f.named.iter(), - Fields::Unnamed(f) => f.unnamed.iter(), - } - } - - /// Get an iterator over the mutably borrowed [`Field`] items in this - /// object. This iterator can be used to iterate over a named or unnamed - /// struct or variant's fields uniformly. - pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { - match self { - Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), - Fields::Named(f) => f.named.iter_mut(), - Fields::Unnamed(f) => f.unnamed.iter_mut(), - } - } - - /// Returns the number of fields. - pub fn len(&self) -> usize { - match self { - Fields::Unit => 0, - Fields::Named(f) => f.named.len(), - Fields::Unnamed(f) => f.unnamed.len(), - } - } - - /// Returns `true` if there are zero fields. - pub fn is_empty(&self) -> bool { - match self { - Fields::Unit => true, - Fields::Named(f) => f.named.is_empty(), - Fields::Unnamed(f) => f.unnamed.is_empty(), - } - } - - return_impl_trait! { - /// Get an iterator over the fields of a struct or variant as [`Member`]s. - /// This iterator can be used to iterate over a named or unnamed struct or - /// variant's fields uniformly. - /// - /// # Example - /// - /// The following is a simplistic [`Clone`] derive for structs. (A more - /// complete implementation would additionally want to infer trait bounds on - /// the generic type parameters.) - /// - /// ``` - /// # use quote::quote; - /// # - /// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream { - /// let ident = &input.ident; - /// let members = input.fields.members(); - /// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - /// quote! { - /// impl #impl_generics Clone for #ident #ty_generics #where_clause { - /// fn clone(&self) -> Self { - /// Self { - /// #(#members: self.#members.clone()),* - /// } - /// } - /// } - /// } - /// } - /// ``` - /// - /// For structs with named fields, it produces an expression like `Self { a: - /// self.a.clone() }`. For structs with unnamed fields, `Self { 0: - /// self.0.clone() }`. And for unit structs, `Self {}`. - pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] { - Members { - fields: self.iter(), - index: 0, - } - } - } -} - -impl IntoIterator for Fields { - type Item = Field; - type IntoIter = punctuated::IntoIter<Field>; - - fn into_iter(self) -> Self::IntoIter { - match self { - Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), - Fields::Named(f) => f.named.into_iter(), - Fields::Unnamed(f) => f.unnamed.into_iter(), - } - } -} - -impl<'a> IntoIterator for &'a Fields { - type Item = &'a Field; - type IntoIter = punctuated::Iter<'a, Field>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a> IntoIterator for &'a mut Fields { - type Item = &'a mut Field; - type IntoIter = punctuated::IterMut<'a, Field>; - - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -ast_struct! { - /// A field of a struct or enum variant. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Field { - pub attrs: Vec<Attribute>, - - pub vis: Visibility, - - pub mutability: FieldMutability, - - /// Name of the field, if any. - /// - /// Fields of tuple structs have no names. - pub ident: Option<Ident>, - - pub colon_token: Option<Token![:]>, - - pub ty: Type, - } -} - -pub struct Members<'a> { - fields: punctuated::Iter<'a, Field>, - index: u32, -} - -impl<'a> Iterator for Members<'a> { - type Item = Member; - - fn next(&mut self) -> Option<Self::Item> { - let field = self.fields.next()?; - let member = match &field.ident { - Some(ident) => Member::Named(ident.clone()), - None => { - #[cfg(all(feature = "parsing", feature = "printing"))] - let span = crate::spanned::Spanned::span(&field.ty); - #[cfg(not(all(feature = "parsing", feature = "printing")))] - let span = proc_macro2::Span::call_site(); - Member::Unnamed(Index { index: self.index, span }) - } - }; - self.index += 1; - Some(member) - } -} - -impl<'a> Clone for Members<'a> { - fn clone(&self) -> Self { - Members { fields: self.fields.clone(), index: self.index } - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant}; - use crate::error::Result; - use crate::expr::Expr; - use crate::ext::IdentExt as _; - use crate::ident::Ident; - #[cfg(not(feature = "full"))] - use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; - use crate::restriction::{FieldMutability, Visibility}; - #[cfg(not(feature = "full"))] - use crate::scan_expr::scan_expr; - use crate::token; - use crate::ty::Type; - use crate::verbatim; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Variant { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let _visibility: Visibility = input.parse()?; - let ident: Ident = input.parse()?; - let fields = if input.peek(token::Brace) { - Fields::Named(input.parse()?) - } else if input.peek(token::Paren) { - Fields::Unnamed(input.parse()?) - } else { - Fields::Unit - }; - let discriminant = if input.peek(Token![=]) { - let eq_token: Token![=] = input.parse()?; - #[cfg(feature = "full")] - let discriminant: Expr = input.parse()?; - #[cfg(not(feature = "full"))] - let discriminant = { - let begin = input.cursor(); - let ahead = input.fork(); - let mut discriminant: Result<Expr> = ahead.parse(); - if discriminant.is_ok() { - input.advance_to(&ahead); - } else if scan_expr(input).is_ok() { - discriminant = Ok(Expr::Verbatim(verbatim::between(begin, input.cursor()))); - } - discriminant? - }; - Some((eq_token, discriminant)) - } else { - None - }; - Ok(Variant { attrs, ident, fields, discriminant }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for FieldsNamed { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(FieldsNamed { - brace_token: braced!(content in input), - named: content.parse_terminated(Field::parse_named, Token![,])?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for FieldsUnnamed { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(FieldsUnnamed { - paren_token: parenthesized!(content in input), - unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?, - }) - } - } - - impl Field { - /// Parses a named (braced struct) field. - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_named(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - - let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]); - let ident = if unnamed_field { input.call(Ident::parse_any) } else { input.parse() }?; - - let colon_token: Token![:] = input.parse()?; - - let ty: Type = if unnamed_field - && (input.peek(Token![struct]) - || input.peek(Token![union]) && input.peek2(token::Brace)) - { - let begin = input.cursor(); - input.call(Ident::parse_any)?; - input.parse::<FieldsNamed>()?; - Type::Verbatim(verbatim::between(begin, input.cursor())) - } else { - input.parse()? - }; - - Ok(Field { - attrs, - vis, - mutability: FieldMutability::None, - ident: Some(ident), - colon_token: Some(colon_token), - ty, - }) - } - - /// Parses an unnamed (tuple struct) field. - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_unnamed(input: ParseStream) -> Result<Self> { - Ok(Field { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - mutability: FieldMutability::None, - ident: None, - colon_token: None, - ty: input.parse()?, - }) - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant}; - use crate::print::TokensOrDefault; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Variant { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(&self.attrs); - self.ident.to_tokens(tokens); - self.fields.to_tokens(tokens); - if let Some((eq_token, disc)) = &self.discriminant { - eq_token.to_tokens(tokens); - disc.to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for FieldsNamed { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.brace_token.surround(tokens, |tokens| { - self.named.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for FieldsUnnamed { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.paren_token.surround(tokens, |tokens| { - self.unnamed.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Field { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(&self.attrs); - self.vis.to_tokens(tokens); - if let Some(ident) = &self.ident { - ident.to_tokens(tokens); - TokensOrDefault(&self.colon_token).to_tokens(tokens); - } - self.ty.to_tokens(tokens); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/derive.rs b/deps/crates/vendor/syn-v2/src/derive.rs deleted file mode 100644 index 573b88fb1667..000000000000 --- a/deps/crates/vendor/syn-v2/src/derive.rs +++ /dev/null @@ -1,260 +0,0 @@ -use crate::attr::Attribute; -use crate::data::{Fields, FieldsNamed, Variant}; -use crate::generics::Generics; -use crate::ident::Ident; -use crate::punctuated::Punctuated; -use crate::restriction::Visibility; -use crate::token; -use alloc::vec::Vec; - -ast_struct! { - /// Data structure sent to a `proc_macro_derive` macro. - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - pub struct DeriveInput { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub ident: Ident, - pub generics: Generics, - pub data: Data, - } -} - -ast_enum! { - /// The storage of a struct, enum or union data structure. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - pub enum Data { - Struct(DataStruct), - Enum(DataEnum), - Union(DataUnion), - } -} - -ast_struct! { - /// A struct input to a `proc_macro_derive` macro. - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - pub struct DataStruct { - pub struct_token: Token![struct], - pub fields: Fields, - pub semi_token: Option<Token![;]>, - } -} - -ast_struct! { - /// An enum input to a `proc_macro_derive` macro. - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - pub struct DataEnum { - pub enum_token: Token![enum], - pub brace_token: token::Brace, - pub variants: Punctuated<Variant, Token![,]>, - } -} - -ast_struct! { - /// An untagged union input to a `proc_macro_derive` macro. - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - pub struct DataUnion { - pub union_token: Token![union], - pub fields: FieldsNamed, - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - use crate::data::{Fields, FieldsNamed, Variant}; - use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; - use crate::error::Result; - use crate::generics::{Generics, WhereClause}; - use crate::ident::Ident; - use crate::parse::{Parse, ParseStream}; - use crate::punctuated::Punctuated; - use crate::restriction::Visibility; - use crate::token; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for DeriveInput { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse::<Visibility>()?; - - let lookahead = input.lookahead1(); - if lookahead.peek(Token![struct]) { - let struct_token = input.parse::<Token![struct]>()?; - let ident = input.parse::<Ident>()?; - let generics = input.parse::<Generics>()?; - let (where_clause, fields, semi) = data_struct(input)?; - Ok(DeriveInput { - attrs, - vis, - ident, - generics: Generics { - where_clause, - ..generics - }, - data: Data::Struct(DataStruct { - struct_token, - fields, - semi_token: semi, - }), - }) - } else if lookahead.peek(Token![enum]) { - let enum_token = input.parse::<Token![enum]>()?; - let ident = input.parse::<Ident>()?; - let generics = input.parse::<Generics>()?; - let (where_clause, brace, variants) = data_enum(input)?; - Ok(DeriveInput { - attrs, - vis, - ident, - generics: Generics { - where_clause, - ..generics - }, - data: Data::Enum(DataEnum { - enum_token, - brace_token: brace, - variants, - }), - }) - } else if lookahead.peek(Token![union]) { - let union_token = input.parse::<Token![union]>()?; - let ident = input.parse::<Ident>()?; - let generics = input.parse::<Generics>()?; - let (where_clause, fields) = data_union(input)?; - Ok(DeriveInput { - attrs, - vis, - ident, - generics: Generics { - where_clause, - ..generics - }, - data: Data::Union(DataUnion { - union_token, - fields, - }), - }) - } else { - Err(lookahead.error()) - } - } - } - - pub(crate) fn data_struct( - input: ParseStream, - ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> { - let mut lookahead = input.lookahead1(); - let mut where_clause = None; - if lookahead.peek(Token![where]) { - where_clause = Some(input.parse()?); - lookahead = input.lookahead1(); - } - - if where_clause.is_none() && lookahead.peek(token::Paren) { - let fields = input.parse()?; - - lookahead = input.lookahead1(); - if lookahead.peek(Token![where]) { - where_clause = Some(input.parse()?); - lookahead = input.lookahead1(); - } - - if lookahead.peek(Token![;]) { - let semi = input.parse()?; - Ok((where_clause, Fields::Unnamed(fields), Some(semi))) - } else { - Err(lookahead.error()) - } - } else if lookahead.peek(token::Brace) { - let fields = input.parse()?; - Ok((where_clause, Fields::Named(fields), None)) - } else if lookahead.peek(Token![;]) { - let semi = input.parse()?; - Ok((where_clause, Fields::Unit, Some(semi))) - } else { - Err(lookahead.error()) - } - } - - pub(crate) fn data_enum( - input: ParseStream, - ) -> Result<( - Option<WhereClause>, - token::Brace, - Punctuated<Variant, Token![,]>, - )> { - let where_clause = input.parse()?; - - let content; - let brace = braced!(content in input); - let variants = content.parse_terminated(Variant::parse, Token![,])?; - - Ok((where_clause, brace, variants)) - } - - pub(crate) fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> { - let where_clause = input.parse()?; - let fields = input.parse()?; - Ok((where_clause, fields)) - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::attr::FilterAttrs; - use crate::data::Fields; - use crate::derive::{Data, DeriveInput}; - use crate::print::TokensOrDefault; - use proc_macro2::TokenStream; - use quote::ToTokens; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for DeriveInput { - fn to_tokens(&self, tokens: &mut TokenStream) { - for attr in self.attrs.outer() { - attr.to_tokens(tokens); - } - self.vis.to_tokens(tokens); - match &self.data { - Data::Struct(d) => d.struct_token.to_tokens(tokens), - Data::Enum(d) => d.enum_token.to_tokens(tokens), - Data::Union(d) => d.union_token.to_tokens(tokens), - } - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - match &self.data { - Data::Struct(data) => match &data.fields { - Fields::Named(fields) => { - self.generics.where_clause.to_tokens(tokens); - fields.to_tokens(tokens); - } - Fields::Unnamed(fields) => { - fields.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - TokensOrDefault(&data.semi_token).to_tokens(tokens); - } - Fields::Unit => { - self.generics.where_clause.to_tokens(tokens); - TokensOrDefault(&data.semi_token).to_tokens(tokens); - } - }, - Data::Enum(data) => { - self.generics.where_clause.to_tokens(tokens); - data.brace_token.surround(tokens, |tokens| { - data.variants.to_tokens(tokens); - }); - } - Data::Union(data) => { - self.generics.where_clause.to_tokens(tokens); - data.fields.to_tokens(tokens); - } - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/discouraged.rs b/deps/crates/vendor/syn-v2/src/discouraged.rs deleted file mode 100644 index 9e26bd9ac04b..000000000000 --- a/deps/crates/vendor/syn-v2/src/discouraged.rs +++ /dev/null @@ -1,225 +0,0 @@ -//! Extensions to the parsing API with niche applicability. - -use crate::buffer::Cursor; -use crate::error::Result; -use crate::parse::{inner_unexpected, ParseBuffer, Unexpected}; -use alloc::rc::Rc; -use core::cell::Cell; -use core::mem; -use proc_macro2::extra::DelimSpan; -use proc_macro2::Delimiter; - -/// Extensions to the `ParseStream` API to support speculative parsing. -pub trait Speculative { - /// Advance this parse stream to the position of a forked parse stream. - /// - /// This is the opposite operation to [`ParseStream::fork`]. You can fork a - /// parse stream, perform some speculative parsing, then join the original - /// stream to the fork to "commit" the parsing from the fork to the main - /// stream. - /// - /// If you can avoid doing this, you should, as it limits the ability to - /// generate useful errors. That said, it is often the only way to parse - /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem - /// is that when the fork fails to parse an `A`, it's impossible to tell - /// whether that was because of a syntax error and the user meant to provide - /// an `A`, or that the `A`s are finished and it's time to start parsing - /// `B`s. Use with care. - /// - /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by - /// parsing `B*` and removing the leading members of `A` from the - /// repetition, bypassing the need to involve the downsides associated with - /// speculative parsing. - /// - /// [`ParseStream::fork`]: ParseBuffer::fork - /// - /// # Example - /// - /// There has been chatter about the possibility of making the colons in the - /// turbofish syntax like `path::to::<T>` no longer required by accepting - /// `path::to<T>` in expression position. Specifically, according to [RFC - /// 2544], [`PathSegment`] parsing should always try to consume a following - /// `<` token as the start of generic arguments, and reset to the `<` if - /// that fails (e.g. the token is acting as a less-than operator). - /// - /// This is the exact kind of parsing behavior which requires the "fork, - /// try, commit" behavior that [`ParseStream::fork`] discourages. With - /// `advance_to`, we can avoid having to parse the speculatively parsed - /// content a second time. - /// - /// This change in behavior can be implemented in syn by replacing just the - /// `Parse` implementation for `PathSegment`: - /// - /// ``` - /// # use syn::ext::IdentExt; - /// use syn::parse::discouraged::Speculative; - /// # use syn::parse::{Parse, ParseStream}; - /// # use syn::{Ident, PathArguments, Result, Token}; - /// - /// pub struct PathSegment { - /// pub ident: Ident, - /// pub arguments: PathArguments, - /// } - /// # - /// # impl<T> From<T> for PathSegment - /// # where - /// # T: Into<Ident>, - /// # { - /// # fn from(ident: T) -> Self { - /// # PathSegment { - /// # ident: ident.into(), - /// # arguments: PathArguments::None, - /// # } - /// # } - /// # } - /// - /// impl Parse for PathSegment { - /// fn parse(input: ParseStream) -> Result<Self> { - /// if input.peek(Token![super]) - /// || input.peek(Token![self]) - /// || input.peek(Token![Self]) - /// || input.peek(Token![crate]) - /// { - /// let ident = input.call(Ident::parse_any)?; - /// return Ok(PathSegment::from(ident)); - /// } - /// - /// let ident = input.parse()?; - /// if input.peek(Token![::]) && input.peek3(Token![<]) { - /// return Ok(PathSegment { - /// ident, - /// arguments: PathArguments::AngleBracketed(input.parse()?), - /// }); - /// } - /// if input.peek(Token![<]) && !input.peek(Token![<=]) { - /// let fork = input.fork(); - /// if let Ok(arguments) = fork.parse() { - /// input.advance_to(&fork); - /// return Ok(PathSegment { - /// ident, - /// arguments: PathArguments::AngleBracketed(arguments), - /// }); - /// } - /// } - /// Ok(PathSegment::from(ident)) - /// } - /// } - /// - /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap(); - /// ``` - /// - /// # Drawbacks - /// - /// The main drawback of this style of speculative parsing is in error - /// presentation. Even if the lookahead is the "correct" parse, the error - /// that is shown is that of the "fallback" parse. To use the same example - /// as the turbofish above, take the following unfinished "turbofish": - /// - /// ```text - /// let _ = f<&'a fn(), for<'a> serde::>(); - /// ``` - /// - /// If this is parsed as generic arguments, we can provide the error message - /// - /// ```text - /// error: expected identifier - /// --> src.rs:L:C - /// | - /// L | let _ = f<&'a fn(), for<'a> serde::>(); - /// | ^ - /// ``` - /// - /// but if parsed using the above speculative parsing, it falls back to - /// assuming that the `<` is a less-than when it fails to parse the generic - /// arguments, and tries to interpret the `&'a` as the start of a labelled - /// loop, resulting in the much less helpful error - /// - /// ```text - /// error: expected `:` - /// --> src.rs:L:C - /// | - /// L | let _ = f<&'a fn(), for<'a> serde::>(); - /// | ^^ - /// ``` - /// - /// This can be mitigated with various heuristics (two examples: show both - /// forks' parse errors, or show the one that consumed more tokens), but - /// when you can control the grammar, sticking to something that can be - /// parsed LL(3) and without the LL(*) speculative parsing this makes - /// possible, displaying reasonable errors becomes much more simple. - /// - /// [RFC 2544]: https://github.com/rust-lang/rfcs/pull/2544 - /// [`PathSegment`]: crate::PathSegment - /// - /// # Performance - /// - /// This method performs a cheap fixed amount of work that does not depend - /// on how far apart the two streams are positioned. - /// - /// # Panics - /// - /// The forked stream in the argument of `advance_to` must have been - /// obtained by forking `self`. Attempting to advance to any other stream - /// will cause a panic. - fn advance_to(&self, fork: &Self); -} - -impl<'a> Speculative for ParseBuffer<'a> { - fn advance_to(&self, fork: &Self) { - if !crate::buffer::same_scope(self.cursor(), fork.cursor()) { - panic!("fork was not derived from the advancing parse stream"); - } - - let (self_unexp, self_sp) = inner_unexpected(self); - let (fork_unexp, fork_sp) = inner_unexpected(fork); - if !Rc::ptr_eq(&self_unexp, &fork_unexp) { - match (fork_sp, self_sp) { - // Unexpected set on the fork, but not on `self`, copy it over. - (Some((span, delimiter)), None) => { - self_unexp.set(Unexpected::Some(span, delimiter)); - } - // Unexpected unset. Use chain to propagate errors from fork. - (None, None) => { - fork_unexp.set(Unexpected::Chain(self_unexp)); - - // Ensure toplevel 'unexpected' tokens from the fork don't - // propagate up the chain by replacing the root `unexpected` - // pointer, only 'unexpected' tokens from existing group - // parsers should propagate. - fork.unexpected - .set(Some(Rc::new(Cell::new(Unexpected::None)))); - } - // Unexpected has been set on `self`. No changes needed. - (_, Some(_)) => {} - } - } - - // See comment on `cell` in the struct definition. - self.cell - .set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) }); - } -} - -/// Extensions to the `ParseStream` API to support manipulating invisible -/// delimiters the same as if they were visible. -pub trait AnyDelimiter { - /// Returns the delimiter, the span of the delimiter token, and the nested - /// contents for further parsing. - fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)>; -} - -impl<'a> AnyDelimiter for ParseBuffer<'a> { - fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)> { - self.step(|cursor| { - if let Some((content, delimiter, span, rest)) = cursor.any_group() { - let scope = span.close(); - let nested = crate::parse::advance_step_cursor(cursor, content); - let unexpected = crate::parse::get_unexpected(self); - let content = crate::parse::new_parse_buffer(scope, nested, unexpected); - Ok(((delimiter, span, content), rest)) - } else { - Err(cursor.error("expected any delimiter")) - } - }) - } -} diff --git a/deps/crates/vendor/syn-v2/src/drops.rs b/deps/crates/vendor/syn-v2/src/drops.rs deleted file mode 100644 index 20ab75e4215c..000000000000 --- a/deps/crates/vendor/syn-v2/src/drops.rs +++ /dev/null @@ -1,58 +0,0 @@ -use core::iter; -use core::mem::ManuallyDrop; -use core::ops::{Deref, DerefMut}; -use core::option; -use core::slice; - -#[repr(transparent)] -pub(crate) struct NoDrop<T: ?Sized>(ManuallyDrop<T>); - -impl<T> NoDrop<T> { - pub(crate) fn new(value: T) -> Self - where - T: TrivialDrop, - { - NoDrop(ManuallyDrop::new(value)) - } -} - -impl<T: ?Sized> Deref for NoDrop<T> { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<T: ?Sized> DerefMut for NoDrop<T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -pub(crate) trait TrivialDrop {} - -impl<T> TrivialDrop for iter::Empty<T> {} -impl<T> TrivialDrop for slice::Iter<'_, T> {} -impl<T> TrivialDrop for slice::IterMut<'_, T> {} -impl<T> TrivialDrop for option::IntoIter<&T> {} -impl<T> TrivialDrop for option::IntoIter<&mut T> {} - -#[test] -fn test_needs_drop() { - use core::mem::needs_drop; - - struct NeedsDrop; - - impl Drop for NeedsDrop { - fn drop(&mut self) {} - } - - assert!(needs_drop::<NeedsDrop>()); - - // Test each of the types with a handwritten TrivialDrop impl above. - assert!(!needs_drop::<iter::Empty<NeedsDrop>>()); - assert!(!needs_drop::<slice::Iter<NeedsDrop>>()); - assert!(!needs_drop::<slice::IterMut<NeedsDrop>>()); - assert!(!needs_drop::<option::IntoIter<&NeedsDrop>>()); - assert!(!needs_drop::<option::IntoIter<&mut NeedsDrop>>()); -} diff --git a/deps/crates/vendor/syn-v2/src/error.rs b/deps/crates/vendor/syn-v2/src/error.rs deleted file mode 100644 index 2b753ea60102..000000000000 --- a/deps/crates/vendor/syn-v2/src/error.rs +++ /dev/null @@ -1,473 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::buffer::Cursor; -use crate::ext::{PunctExt as _, TokenStreamExt as _}; -use crate::thread::ThreadBound; -#[cfg(feature = "parsing")] -use alloc::format; -use alloc::string::{String, ToString}; -use alloc::vec; -use alloc::vec::Vec; -use core::fmt::{self, Debug, Display}; -use core::slice; -use proc_macro2::{ - Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, -}; -#[cfg(feature = "printing")] -use quote::ToTokens; - -/// The result of a Syn parser. -pub type Result<T> = core::result::Result<T, Error>; - -/// Error returned when a Syn parser cannot parse the input tokens. -/// -/// # Error reporting in proc macros -/// -/// The correct way to report errors back to the compiler from a procedural -/// macro is by emitting an appropriately spanned invocation of -/// [`compile_error!`] in the generated code. This produces a better diagnostic -/// message than simply panicking the macro. -/// -/// [`compile_error!`]: core::compile_error! -/// -/// When parsing macro input, the [`parse_macro_input!`] macro handles the -/// conversion to `compile_error!` automatically. -/// -/// [`parse_macro_input!`]: crate::parse_macro_input! -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::parse::{Parse, ParseStream, Result}; -/// use syn::{parse_macro_input, ItemFn}; -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_attribute] -/// # }; -/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { -/// let args = parse_macro_input!(args as MyAttrArgs); -/// let input = parse_macro_input!(input as ItemFn); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// -/// struct MyAttrArgs { -/// # _k: [(); { stringify! { -/// ... -/// # }; 0 }] -/// } -/// -/// impl Parse for MyAttrArgs { -/// fn parse(input: ParseStream) -> Result<Self> { -/// # stringify! { -/// ... -/// # }; -/// # unimplemented!() -/// } -/// } -/// ``` -/// -/// For errors that arise later than the initial parsing stage, the -/// [`.to_compile_error()`] or [`.into_compile_error()`] methods can be used to -/// perform an explicit conversion to `compile_error!`. -/// -/// [`.to_compile_error()`]: Error::to_compile_error -/// [`.into_compile_error()`]: Error::into_compile_error -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// # use proc_macro::TokenStream; -/// # use syn::{parse_macro_input, DeriveInput}; -/// # -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_derive(MyDerive)] -/// # }; -/// pub fn my_derive(input: TokenStream) -> TokenStream { -/// let input = parse_macro_input!(input as DeriveInput); -/// -/// // fn(DeriveInput) -> syn::Result<proc_macro2::TokenStream> -/// expand::my_derive(input) -/// .unwrap_or_else(syn::Error::into_compile_error) -/// .into() -/// } -/// # -/// # mod expand { -/// # use proc_macro2::TokenStream; -/// # use syn::{DeriveInput, Result}; -/// # -/// # pub fn my_derive(input: DeriveInput) -> Result<TokenStream> { -/// # unimplemented!() -/// # } -/// # } -/// ``` -pub struct Error { - messages: Vec<ErrorMessage>, -} - -struct ErrorMessage { - // Span is implemented as an index into a thread-local interner to keep the - // size small. It is not safe to access from a different thread. We want - // errors to be Send and Sync to play nicely with ecosystem crates for error - // handling, so pin the span we're given to its original thread and assume - // it is Span::call_site if accessed from any other thread. - span: ThreadBound<SpanRange>, - message: String, -} - -// Cannot use core::ops::Range<Span> because that does not implement Copy, -// whereas ThreadBound<T> requires a Copy impl as a way to ensure no Drop impls -// are involved. -struct SpanRange { - start: Span, - end: Span, -} - -#[cfg(test)] -struct _Test -where - Error: Send + Sync; - -impl Error { - /// Usually the [`ParseStream::error`] method will be used instead, which - /// automatically uses the correct span from the current position of the - /// parse stream. - /// - /// Use `Error::new` when the error needs to be triggered on some span other - /// than where the parse stream is currently positioned. - /// - /// [`ParseStream::error`]: crate::parse::ParseBuffer::error - /// - /// # Example - /// - /// ``` - /// use syn::{Error, Ident, LitStr, Result, Token}; - /// use syn::parse::ParseStream; - /// - /// // Parses input that looks like `name = "string"` where the key must be - /// // the identifier `name` and the value may be any string literal. - /// // Returns the string literal. - /// fn parse_name(input: ParseStream) -> Result<LitStr> { - /// let name_token: Ident = input.parse()?; - /// if name_token != "name" { - /// // Trigger an error not on the current position of the stream, - /// // but on the position of the unexpected identifier. - /// return Err(Error::new(name_token.span(), "expected `name`")); - /// } - /// input.parse::<Token![=]>()?; - /// let s: LitStr = input.parse()?; - /// Ok(s) - /// } - /// ``` - pub fn new<T: Display>(span: Span, message: T) -> Self { - return new(span, message.to_string()); - - fn new(span: Span, message: String) -> Error { - Error { - messages: vec![ErrorMessage { - span: ThreadBound::new(SpanRange { - start: span, - end: span, - }), - message, - }], - } - } - } - - /// Creates an error with the specified message spanning the given syntax - /// tree node. - /// - /// Unlike the `Error::new` constructor, this constructor takes an argument - /// `tokens` which is a syntax tree node. This allows the resulting `Error` - /// to attempt to span all tokens inside of `tokens`. While you would - /// typically be able to use the `Spanned` trait with the above `Error::new` - /// constructor, implementation limitations today mean that - /// `Error::new_spanned` may provide a higher-quality error message on - /// stable Rust. - /// - /// When in doubt it's recommended to stick to `Error::new` (or - /// `ParseStream::error`)! - #[cfg(feature = "printing")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self { - return new_spanned(tokens.into_token_stream(), message.to_string()); - - fn new_spanned(tokens: TokenStream, message: String) -> Error { - let mut iter = tokens.into_iter(); - let start = iter.next().map_or_else(Span::call_site, |t| t.span()); - let end = iter.last().map_or(start, |t| t.span()); - Error { - messages: vec![ErrorMessage { - span: ThreadBound::new(SpanRange { start, end }), - message, - }], - } - } - } - - /// The source location of the error. - /// - /// Spans are not thread-safe so this function returns `Span::call_site()` - /// if called from a different thread than the one on which the `Error` was - /// originally created. - pub fn span(&self) -> Span { - let SpanRange { start, end } = match self.messages[0].span.get() { - Some(span) => *span, - None => return Span::call_site(), - }; - start.join(end).unwrap_or(start) - } - - /// Render the error as an invocation of [`compile_error!`]. - /// - /// The [`parse_macro_input!`] macro provides a convenient way to invoke - /// this method correctly in a procedural macro. - /// - /// [`compile_error!`]: core::compile_error! - /// [`parse_macro_input!`]: crate::parse_macro_input! - pub fn to_compile_error(&self) -> TokenStream { - let mut tokens = TokenStream::new(); - for msg in &self.messages { - ErrorMessage::to_compile_error(msg, &mut tokens); - } - tokens - } - - /// Render the error as an invocation of [`compile_error!`]. - /// - /// [`compile_error!`]: core::compile_error! - /// - /// # Example - /// - /// ``` - /// # extern crate proc_macro; - /// # - /// use proc_macro::TokenStream; - /// use syn::{parse_macro_input, DeriveInput, Error}; - /// - /// # const _: &str = stringify! { - /// #[proc_macro_derive(MyTrait)] - /// # }; - /// pub fn derive_my_trait(input: TokenStream) -> TokenStream { - /// let input = parse_macro_input!(input as DeriveInput); - /// my_trait::expand(input) - /// .unwrap_or_else(Error::into_compile_error) - /// .into() - /// } - /// - /// mod my_trait { - /// use proc_macro2::TokenStream; - /// use syn::{DeriveInput, Result}; - /// - /// pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> { - /// /* ... */ - /// # unimplemented!() - /// } - /// } - /// ``` - pub fn into_compile_error(self) -> TokenStream { - self.to_compile_error() - } - - /// Add another error message to self such that when `to_compile_error()` is - /// called, both errors will be emitted together. - pub fn combine(&mut self, another: Error) { - self.messages.extend(another.messages); - } -} - -impl ErrorMessage { - fn to_compile_error(&self, tokens: &mut TokenStream) { - let (start, end) = match self.span.get() { - Some(range) => (range.start, range.end), - None => (Span::call_site(), Span::call_site()), - }; - - // ::core::compile_error!($message) - tokens.append(TokenTree::Punct(Punct::new_spanned( - ':', - Spacing::Joint, - start, - ))); - tokens.append(TokenTree::Punct(Punct::new_spanned( - ':', - Spacing::Alone, - start, - ))); - tokens.append(TokenTree::Ident(Ident::new("core", start))); - tokens.append(TokenTree::Punct(Punct::new_spanned( - ':', - Spacing::Joint, - start, - ))); - tokens.append(TokenTree::Punct(Punct::new_spanned( - ':', - Spacing::Alone, - start, - ))); - tokens.append(TokenTree::Ident(Ident::new("compile_error", start))); - tokens.append(TokenTree::Punct(Punct::new_spanned( - '!', - Spacing::Alone, - start, - ))); - tokens.append(TokenTree::Group({ - let mut group = Group::new( - Delimiter::Brace, - TokenStream::from({ - let mut string = Literal::string(&self.message); - string.set_span(end); - TokenTree::Literal(string) - }), - ); - group.set_span(end); - group - })); - } -} - -#[cfg(feature = "parsing")] -pub(crate) fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error { - if cursor.eof() { - Error::new(scope, format!("unexpected end of input, {}", message)) - } else { - let span = crate::buffer::open_span_of_group(cursor); - Error::new(span, message) - } -} - -#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))] -pub(crate) fn new2<T: Display>(start: Span, end: Span, message: T) -> Error { - return new2(start, end, message.to_string()); - - fn new2(start: Span, end: Span, message: String) -> Error { - Error { - messages: vec![ErrorMessage { - span: ThreadBound::new(SpanRange { start, end }), - message, - }], - } - } -} - -impl Debug for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - if self.messages.len() == 1 { - formatter - .debug_tuple("Error") - .field(&self.messages[0]) - .finish() - } else { - formatter - .debug_tuple("Error") - .field(&self.messages) - .finish() - } - } -} - -impl Debug for ErrorMessage { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - Debug::fmt(&self.message, formatter) - } -} - -impl Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(&self.messages[0].message) - } -} - -impl Clone for Error { - fn clone(&self) -> Self { - Error { - messages: self.messages.clone(), - } - } -} - -impl Clone for ErrorMessage { - fn clone(&self) -> Self { - ErrorMessage { - span: self.span, - message: self.message.clone(), - } - } -} - -impl Clone for SpanRange { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for SpanRange {} - -// TODO: impl core::error::Error (requires Rust 1.81+) -impl std::error::Error for Error {} - -impl From<LexError> for Error { - fn from(err: LexError) -> Self { - Error::new(err.span(), err) - } -} - -impl IntoIterator for Error { - type Item = Error; - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { - messages: self.messages.into_iter(), - } - } -} - -pub struct IntoIter { - messages: vec::IntoIter<ErrorMessage>, -} - -impl Iterator for IntoIter { - type Item = Error; - - fn next(&mut self) -> Option<Self::Item> { - Some(Error { - messages: vec![self.messages.next()?], - }) - } -} - -impl<'a> IntoIterator for &'a Error { - type Item = Error; - type IntoIter = Iter<'a>; - - fn into_iter(self) -> Self::IntoIter { - Iter { - messages: self.messages.iter(), - } - } -} - -pub struct Iter<'a> { - messages: slice::Iter<'a, ErrorMessage>, -} - -impl<'a> Iterator for Iter<'a> { - type Item = Error; - - fn next(&mut self) -> Option<Self::Item> { - Some(Error { - messages: vec![self.messages.next()?.clone()], - }) - } -} - -impl Extend<Error> for Error { - fn extend<T: IntoIterator<Item = Error>>(&mut self, iter: T) { - for err in iter { - self.combine(err); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/export.rs b/deps/crates/vendor/syn-v2/src/export.rs deleted file mode 100644 index eca67f6adaa6..000000000000 --- a/deps/crates/vendor/syn-v2/src/export.rs +++ /dev/null @@ -1,73 +0,0 @@ -#[doc(hidden)] -pub use core::clone::Clone; -#[doc(hidden)] -pub use core::cmp::{Eq, PartialEq}; -#[doc(hidden)] -pub use core::concat; -#[doc(hidden)] -pub use core::default::Default; -#[doc(hidden)] -pub use core::fmt::Debug; -#[doc(hidden)] -pub use core::hash::{Hash, Hasher}; -#[doc(hidden)] -pub use core::marker::Copy; -#[doc(hidden)] -pub use core::option::Option::{None, Some}; -#[doc(hidden)] -pub use core::result::Result::{Err, Ok}; -#[doc(hidden)] -pub use core::stringify; - -#[doc(hidden)] -pub type Formatter<'a> = core::fmt::Formatter<'a>; -#[doc(hidden)] -pub type FmtResult = core::fmt::Result; - -#[doc(hidden)] -pub type bool = core::primitive::bool; -#[doc(hidden)] -pub type str = core::primitive::str; - -#[cfg(feature = "printing")] -#[doc(hidden)] -pub use quote; - -#[doc(hidden)] -pub type Span = proc_macro2::Span; -#[doc(hidden)] -pub type TokenStream2 = proc_macro2::TokenStream; - -#[cfg(feature = "parsing")] -#[doc(hidden)] -pub use crate::group::{parse_braces, parse_brackets, parse_parens}; - -#[doc(hidden)] -pub use crate::span::IntoSpans; - -#[cfg(all(feature = "parsing", feature = "printing"))] -#[doc(hidden)] -pub use crate::parse_quote::parse as parse_quote; - -#[cfg(feature = "parsing")] -#[doc(hidden)] -pub use crate::token::parsing::{peek_punct, punct as parse_punct}; - -#[cfg(feature = "printing")] -#[doc(hidden)] -pub use crate::token::printing::punct as print_punct; - -#[cfg(feature = "parsing")] -#[doc(hidden)] -pub use crate::token::private::CustomToken; - -#[cfg(feature = "proc-macro")] -#[doc(hidden)] -pub type TokenStream = proc_macro::TokenStream; - -#[cfg(feature = "printing")] -#[doc(hidden)] -pub use quote::{ToTokens, TokenStreamExt}; - -#[doc(hidden)] -pub struct private(pub(crate) ()); diff --git a/deps/crates/vendor/syn-v2/src/expr.rs b/deps/crates/vendor/syn-v2/src/expr.rs deleted file mode 100644 index 70fc37c25506..000000000000 --- a/deps/crates/vendor/syn-v2/src/expr.rs +++ /dev/null @@ -1,4031 +0,0 @@ -use crate::attr::Attribute; -#[cfg(all(feature = "parsing", feature = "full"))] -use crate::error::Result; -#[cfg(feature = "parsing")] -use crate::ext::IdentExt as _; -#[cfg(feature = "full")] -use crate::generics::BoundLifetimes; -use crate::ident::Ident; -#[cfg(any(feature = "parsing", feature = "full"))] -use crate::lifetime::Lifetime; -use crate::lit::Lit; -use crate::mac::Macro; -use crate::op::{BinOp, UnOp}; -#[cfg(feature = "parsing")] -use crate::parse::ParseStream; -#[cfg(feature = "full")] -use crate::pat::Pat; -use crate::path::{AngleBracketedGenericArguments, Path, QSelf}; -use crate::punctuated::Punctuated; -#[cfg(feature = "full")] -use crate::stmt::Block; -use crate::token; -#[cfg(feature = "full")] -use crate::ty::ReturnType; -use crate::ty::Type; -use alloc::boxed::Box; -use alloc::vec::Vec; -#[cfg(feature = "printing")] -use core::fmt::{self, Display}; -use core::hash::{Hash, Hasher}; -#[cfg(all(feature = "parsing", feature = "full"))] -use core::mem; -use proc_macro2::{Span, TokenStream}; -#[cfg(feature = "printing")] -use quote::IdentFragment; - -ast_enum_of_structs! { - /// A Rust expression. - /// - /// *This type is available only if Syn is built with the `"derive"` or `"full"` - /// feature, but most of the variants are not available unless "full" is enabled.* - /// - /// # Syntax tree enums - /// - /// This type is a syntax tree enum. In Syn this and other syntax tree enums - /// are designed to be traversed using the following rebinding idiom. - /// - /// ``` - /// # use syn::Expr; - /// # - /// # fn example(expr: Expr) { - /// # const IGNORE: &str = stringify! { - /// let expr: Expr = /* ... */; - /// # }; - /// match expr { - /// Expr::MethodCall(expr) => { - /// /* ... */ - /// } - /// Expr::Cast(expr) => { - /// /* ... */ - /// } - /// Expr::If(expr) => { - /// /* ... */ - /// } - /// - /// /* ... */ - /// # _ => {} - /// # } - /// # } - /// ``` - /// - /// We begin with a variable `expr` of type `Expr` that has no fields - /// (because it is an enum), and by matching on it and rebinding a variable - /// with the same name `expr` we effectively imbue our variable with all of - /// the data fields provided by the variant that it turned out to be. So for - /// example above if we ended up in the `MethodCall` case then we get to use - /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get - /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`. - /// - /// This approach avoids repeating the variant names twice on every line. - /// - /// ``` - /// # use syn::{Expr, ExprMethodCall}; - /// # - /// # fn example(expr: Expr) { - /// // Repetitive; recommend not doing this. - /// match expr { - /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { - /// # } - /// # _ => {} - /// # } - /// # } - /// ``` - /// - /// In general, the name to which a syntax tree enum variant is bound should - /// be a suitable name for the complete syntax tree enum type. - /// - /// ``` - /// # use syn::{Expr, ExprField}; - /// # - /// # fn example(discriminant: ExprField) { - /// // Binding is called `base` which is the name I would use if I were - /// // assigning `*discriminant.base` without an `if let`. - /// if let Expr::Tuple(base) = *discriminant.base { - /// # } - /// # } - /// ``` - /// - /// A sign that you may not be choosing the right variable names is if you - /// see names getting repeated in your code, like accessing - /// `receiver.receiver` or `pat.pat` or `cond.cond`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum Expr { - /// A slice literal expression: `[a, b, c, d]`. - Array(ExprArray), - - /// An assignment expression: `a = compute()`. - Assign(ExprAssign), - - /// An async block: `async { ... }`. - Async(ExprAsync), - - /// An await expression: `fut.await`. - Await(ExprAwait), - - /// A binary operation: `a + b`, `a += b`. - Binary(ExprBinary), - - /// A blocked scope: `{ ... }`. - Block(ExprBlock), - - /// A `break`, with an optional label to break and an optional - /// expression. - Break(ExprBreak), - - /// A function call expression: `invoke(a, b)`. - Call(ExprCall), - - /// A cast expression: `foo as f64`. - Cast(ExprCast), - - /// A closure expression: `|a, b| a + b`. - Closure(ExprClosure), - - /// A const block: `const { ... }`. - Const(ExprConst), - - /// A `continue`, with an optional label. - Continue(ExprContinue), - - /// Access of a named struct field (`obj.k`) or unnamed tuple struct - /// field (`obj.0`). - Field(ExprField), - - /// A for loop: `for pat in expr { ... }`. - ForLoop(ExprForLoop), - - /// An expression contained within invisible delimiters. - /// - /// This variant is important for faithfully representing the precedence - /// of expressions and is related to `None`-delimited spans in a - /// `TokenStream`. - Group(ExprGroup), - - /// An `if` expression with an optional `else` block: `if expr { ... } - /// else { ... }`. - /// - /// The `else` branch expression may only be an `If` or `Block` - /// expression, not any of the other types of expression. - If(ExprIf), - - /// A square bracketed indexing expression: `vector[2]`. - Index(ExprIndex), - - /// The inferred value of a const generic argument, denoted `_`. - Infer(ExprInfer), - - /// A `let` guard: `let Some(x) = opt`. - Let(ExprLet), - - /// A literal in place of an expression: `1`, `"foo"`. - Lit(ExprLit), - - /// Conditionless loop: `loop { ... }`. - Loop(ExprLoop), - - /// A macro invocation expression: `format!("{}", q)`. - Macro(ExprMacro), - - /// A `match` expression: `match n { Some(n) => {}, None => {} }`. - Match(ExprMatch), - - /// A method call expression: `x.foo::<T>(a, b)`. - MethodCall(ExprMethodCall), - - /// A parenthesized expression: `(a + b)`. - Paren(ExprParen), - - /// A path like `core::mem::replace` possibly containing generic - /// parameters and a qualified self-type. - /// - /// A plain identifier like `x` is a path of length 1. - Path(ExprPath), - - /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`. - Range(ExprRange), - - /// Address-of operation: `&raw const place` or `&raw mut place`. - RawAddr(ExprRawAddr), - - /// A referencing operation: `&a` or `&mut a`. - Reference(ExprReference), - - /// An array literal constructed from one repeated element: `[0u8; N]`. - Repeat(ExprRepeat), - - /// A `return`, with an optional value to be returned. - Return(ExprReturn), - - /// A struct literal expression: `Point { x: 1, y: 1 }`. - /// - /// The `rest` provides the value of the remaining fields as in `S { a: - /// 1, b: 1, ..rest }`. - Struct(ExprStruct), - - /// A try-expression: `expr?`. - Try(ExprTry), - - /// A try block: `try { ... }`. - TryBlock(ExprTryBlock), - - /// A tuple expression: `(a, b, c, d)`. - Tuple(ExprTuple), - - /// A unary operation: `!x`, `*x`, `-x`. - Unary(ExprUnary), - - /// An unsafe block: `unsafe { ... }`. - Unsafe(ExprUnsafe), - - /// Tokens in expression position not interpreted by Syn. - Verbatim(TokenStream), - - /// A while loop: `while expr { ... }`. - While(ExprWhile), - - /// A yield expression: `yield expr`. - Yield(ExprYield), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match expr { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // Expr::Array(expr) => {...} - // Expr::Assign(expr) => {...} - // ... - // Expr::Yield(expr) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// A slice literal expression: `[a, b, c, d]`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprArray #full { - pub attrs: Vec<Attribute>, - pub bracket_token: token::Bracket, - pub elems: Punctuated<Expr, Token![,]>, - } -} - -ast_struct! { - /// An assignment expression: `a = compute()`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprAssign #full { - pub attrs: Vec<Attribute>, - pub left: Box<Expr>, - pub eq_token: Token![=], - pub right: Box<Expr>, - } -} - -ast_struct! { - /// An async block: `async { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprAsync #full { - pub attrs: Vec<Attribute>, - pub async_token: Token![async], - pub capture: Option<Token![move]>, - pub block: Block, - } -} - -ast_struct! { - /// An await expression: `fut.await`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprAwait #full { - pub attrs: Vec<Attribute>, - pub base: Box<Expr>, - pub dot_token: Token![.], - pub await_token: Token![await], - } -} - -ast_struct! { - /// A binary operation: `a + b`, `a += b`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprBinary { - pub attrs: Vec<Attribute>, - pub left: Box<Expr>, - pub op: BinOp, - pub right: Box<Expr>, - } -} - -ast_struct! { - /// A blocked scope: `{ ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprBlock #full { - pub attrs: Vec<Attribute>, - pub label: Option<Label>, - pub block: Block, - } -} - -ast_struct! { - /// A `break`, with an optional label to break and an optional - /// expression. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprBreak #full { - pub attrs: Vec<Attribute>, - pub break_token: Token![break], - pub label: Option<Lifetime>, - pub expr: Option<Box<Expr>>, - } -} - -ast_struct! { - /// A function call expression: `invoke(a, b)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprCall { - pub attrs: Vec<Attribute>, - pub func: Box<Expr>, - pub paren_token: token::Paren, - pub args: Punctuated<Expr, Token![,]>, - } -} - -ast_struct! { - /// A cast expression: `foo as f64`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprCast { - pub attrs: Vec<Attribute>, - pub expr: Box<Expr>, - pub as_token: Token![as], - pub ty: Box<Type>, - } -} - -ast_struct! { - /// A closure expression: `|a, b| a + b`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprClosure #full { - pub attrs: Vec<Attribute>, - pub lifetimes: Option<BoundLifetimes>, - pub constness: Option<Token![const]>, - pub movability: Option<Token![static]>, - pub asyncness: Option<Token![async]>, - pub capture: Option<Token![move]>, - pub or1_token: Token![|], - pub inputs: Punctuated<Pat, Token![,]>, - pub or2_token: Token![|], - pub output: ReturnType, - pub body: Box<Expr>, - } -} - -ast_struct! { - /// A const block: `const { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprConst #full { - pub attrs: Vec<Attribute>, - pub const_token: Token![const], - pub block: Block, - } -} - -ast_struct! { - /// A `continue`, with an optional label. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprContinue #full { - pub attrs: Vec<Attribute>, - pub continue_token: Token![continue], - pub label: Option<Lifetime>, - } -} - -ast_struct! { - /// Access of a named struct field (`obj.k`) or unnamed tuple struct - /// field (`obj.0`). - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprField { - pub attrs: Vec<Attribute>, - pub base: Box<Expr>, - pub dot_token: Token![.], - pub member: Member, - } -} - -ast_struct! { - /// A for loop: `for pat in expr { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprForLoop #full { - pub attrs: Vec<Attribute>, - pub label: Option<Label>, - pub for_token: Token![for], - pub pat: Box<Pat>, - pub in_token: Token![in], - pub expr: Box<Expr>, - pub body: Block, - } -} - -ast_struct! { - /// An expression contained within invisible delimiters. - /// - /// This variant is important for faithfully representing the precedence - /// of expressions and is related to `None`-delimited spans in a - /// `TokenStream`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprGroup { - pub attrs: Vec<Attribute>, - pub group_token: token::Group, - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// An `if` expression with an optional `else` block: `if expr { ... } - /// else { ... }`. - /// - /// The `else` branch expression may only be an `If` or `Block` - /// expression, not any of the other types of expression. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprIf #full { - pub attrs: Vec<Attribute>, - pub if_token: Token![if], - pub cond: Box<Expr>, - pub then_branch: Block, - pub else_branch: Option<(Token![else], Box<Expr>)>, - } -} - -ast_struct! { - /// A square bracketed indexing expression: `vector[2]`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprIndex { - pub attrs: Vec<Attribute>, - pub expr: Box<Expr>, - pub bracket_token: token::Bracket, - pub index: Box<Expr>, - } -} - -ast_struct! { - /// The inferred value of a const generic argument, denoted `_`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprInfer #full { - pub attrs: Vec<Attribute>, - pub underscore_token: Token![_], - } -} - -ast_struct! { - /// A `let` guard: `let Some(x) = opt`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprLet #full { - pub attrs: Vec<Attribute>, - pub let_token: Token![let], - pub pat: Box<Pat>, - pub eq_token: Token![=], - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// A literal in place of an expression: `1`, `"foo"`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprLit { - pub attrs: Vec<Attribute>, - pub lit: Lit, - } -} - -ast_struct! { - /// Conditionless loop: `loop { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprLoop #full { - pub attrs: Vec<Attribute>, - pub label: Option<Label>, - pub loop_token: Token![loop], - pub body: Block, - } -} - -ast_struct! { - /// A macro invocation expression: `format!("{}", q)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprMacro { - pub attrs: Vec<Attribute>, - pub mac: Macro, - } -} - -ast_struct! { - /// A `match` expression: `match n { Some(n) => {}, None => {} }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprMatch #full { - pub attrs: Vec<Attribute>, - pub match_token: Token![match], - pub expr: Box<Expr>, - pub brace_token: token::Brace, - pub arms: Vec<Arm>, - } -} - -ast_struct! { - /// A method call expression: `x.foo::<T>(a, b)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprMethodCall { - pub attrs: Vec<Attribute>, - pub receiver: Box<Expr>, - pub dot_token: Token![.], - pub method: Ident, - pub turbofish: Option<AngleBracketedGenericArguments>, - pub paren_token: token::Paren, - pub args: Punctuated<Expr, Token![,]>, - } -} - -ast_struct! { - /// A parenthesized expression: `(a + b)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprParen { - pub attrs: Vec<Attribute>, - pub paren_token: token::Paren, - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// A path like `core::mem::replace` possibly containing generic - /// parameters and a qualified self-type. - /// - /// A plain identifier like `x` is a path of length 1. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprPath { - pub attrs: Vec<Attribute>, - pub qself: Option<QSelf>, - pub path: Path, - } -} - -ast_struct! { - /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprRange #full { - pub attrs: Vec<Attribute>, - pub start: Option<Box<Expr>>, - pub limits: RangeLimits, - pub end: Option<Box<Expr>>, - } -} - -ast_struct! { - /// Address-of operation: `&raw const place` or `&raw mut place`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprRawAddr #full { - pub attrs: Vec<Attribute>, - pub and_token: Token![&], - pub raw: Token![raw], - pub mutability: PointerMutability, - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// A referencing operation: `&a` or `&mut a`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprReference { - pub attrs: Vec<Attribute>, - pub and_token: Token![&], - pub mutability: Option<Token![mut]>, - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// An array literal constructed from one repeated element: `[0u8; N]`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprRepeat #full { - pub attrs: Vec<Attribute>, - pub bracket_token: token::Bracket, - pub expr: Box<Expr>, - pub semi_token: Token![;], - pub len: Box<Expr>, - } -} - -ast_struct! { - /// A `return`, with an optional value to be returned. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprReturn #full { - pub attrs: Vec<Attribute>, - pub return_token: Token![return], - pub expr: Option<Box<Expr>>, - } -} - -ast_struct! { - /// A struct literal expression: `Point { x: 1, y: 1 }`. - /// - /// The `rest` provides the value of the remaining fields as in `S { a: - /// 1, b: 1, ..rest }`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprStruct { - pub attrs: Vec<Attribute>, - pub qself: Option<QSelf>, - pub path: Path, - pub brace_token: token::Brace, - pub fields: Punctuated<FieldValue, Token![,]>, - pub dot2_token: Option<Token![..]>, - pub rest: Option<Box<Expr>>, - } -} - -ast_struct! { - /// A try-expression: `expr?`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprTry #full { - pub attrs: Vec<Attribute>, - pub expr: Box<Expr>, - pub question_token: Token![?], - } -} - -ast_struct! { - /// A try block: `try { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprTryBlock #full { - pub attrs: Vec<Attribute>, - pub try_token: Token![try], - pub block: Block, - } -} - -ast_struct! { - /// A tuple expression: `(a, b, c, d)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprTuple { - pub attrs: Vec<Attribute>, - pub paren_token: token::Paren, - pub elems: Punctuated<Expr, Token![,]>, - } -} - -ast_struct! { - /// A unary operation: `!x`, `*x`, `-x`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ExprUnary { - pub attrs: Vec<Attribute>, - pub op: UnOp, - pub expr: Box<Expr>, - } -} - -ast_struct! { - /// An unsafe block: `unsafe { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprUnsafe #full { - pub attrs: Vec<Attribute>, - pub unsafe_token: Token![unsafe], - pub block: Block, - } -} - -ast_struct! { - /// A while loop: `while expr { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprWhile #full { - pub attrs: Vec<Attribute>, - pub label: Option<Label>, - pub while_token: Token![while], - pub cond: Box<Expr>, - pub body: Block, - } -} - -ast_struct! { - /// A yield expression: `yield expr`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ExprYield #full { - pub attrs: Vec<Attribute>, - pub yield_token: Token![yield], - pub expr: Option<Box<Expr>>, - } -} - -impl Expr { - /// An unspecified invalid expression. - /// - /// ``` - /// use core::mem; - /// use quote::ToTokens; - /// use syn::{parse_quote, Expr}; - /// - /// fn unparenthesize(e: &mut Expr) { - /// while let Expr::Paren(paren) = e { - /// *e = mem::replace(&mut *paren.expr, Expr::PLACEHOLDER); - /// } - /// } - /// - /// fn main() { - /// let mut e: Expr = parse_quote! { ((1 + 1)) }; - /// unparenthesize(&mut e); - /// assert_eq!("1 + 1", e.to_token_stream().to_string()); - /// } - /// ``` - pub const PLACEHOLDER: Self = Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path { leading_colon: None, segments: Punctuated::new() }, - }); - - /// An alternative to the primary `Expr::parse` parser (from the [`Parse`] - /// trait) for ambiguous syntactic positions in which a trailing brace - /// should not be taken as part of the expression. - /// - /// [`Parse`]: crate::parse::Parse - /// - /// Rust grammar has an ambiguity where braces sometimes turn a path - /// expression into a struct initialization and sometimes do not. In the - /// following code, the expression `S {}` is one expression. Presumably - /// there is an empty struct `struct S {}` defined somewhere which it is - /// instantiating. - /// - /// ``` - /// # struct S; - /// # impl core::ops::Deref for S { - /// # type Target = bool; - /// # fn deref(&self) -> &Self::Target { - /// # &true - /// # } - /// # } - /// let _ = *S {}; - /// - /// // parsed by rustc as: `*(S {})` - /// ``` - /// - /// We would want to parse the above using `Expr::parse` after the `=` - /// token. - /// - /// But in the following, `S {}` is *not* a struct init expression. - /// - /// ``` - /// # const S: &bool = &true; - /// if *S {} {} - /// - /// // parsed by rustc as: - /// // - /// // if (*S) { - /// // /* empty block */ - /// // } - /// // { - /// // /* another empty block */ - /// // } - /// ``` - /// - /// For that reason we would want to parse if-conditions using - /// `Expr::parse_without_eager_brace` after the `if` token. Same for similar - /// syntactic positions such as the condition expr after a `while` token or - /// the expr at the top of a `match`. - /// - /// The Rust grammar's choices around which way this ambiguity is resolved - /// at various syntactic positions is fairly arbitrary. Really either parse - /// behavior could work in most positions, and language designers just - /// decide each case based on which is more likely to be what the programmer - /// had in mind most of the time. - /// - /// ``` - /// # struct S; - /// # fn doc() -> S { - /// if return S {} {} - /// # unreachable!() - /// # } - /// - /// // parsed by rustc as: - /// // - /// // if (return (S {})) { - /// // } - /// // - /// // but could equally well have been this other arbitrary choice: - /// // - /// // if (return S) { - /// // } - /// // {} - /// ``` - /// - /// Note the grammar ambiguity on trailing braces is distinct from - /// precedence and is not captured by assigning a precedence level to the - /// braced struct init expr in relation to other operators. This can be - /// illustrated by `return 0..S {}` vs `match 0..S {}`. The former parses as - /// `return (0..(S {}))` implying tighter precedence for struct init than - /// `..`, while the latter parses as `match (0..S) {}` implying tighter - /// precedence for `..` than struct init, a contradiction. - #[cfg(all(feature = "full", feature = "parsing"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "full", feature = "parsing"))))] - pub fn parse_without_eager_brace(input: ParseStream) -> Result<Expr> { - parsing::ambiguous_expr(input, parsing::AllowStruct(false)) - } - - /// An alternative to the primary `Expr::parse` parser (from the [`Parse`] - /// trait) for syntactic positions in which expression boundaries are placed - /// more eagerly than done by the typical expression grammar. This includes - /// expressions at the head of a statement or in the right-hand side of a - /// `match` arm. - /// - /// [`Parse`]: crate::parse::Parse - /// - /// Compare the following cases: - /// - /// 1. - /// ``` - /// # let result = (); - /// # let guard = false; - /// # let cond = true; - /// # let f = true; - /// # let g = f; - /// # - /// let _ = match result { - /// () if guard => if cond { f } else { g } - /// () => false, - /// }; - /// ``` - /// - /// 2. - /// ``` - /// # let cond = true; - /// # let f = (); - /// # let g = f; - /// # - /// let _ = || { - /// if cond { f } else { g } - /// () - /// }; - /// ``` - /// - /// 3. - /// ``` - /// # let cond = true; - /// # let f = || (); - /// # let g = f; - /// # - /// let _ = [if cond { f } else { g } ()]; - /// ``` - /// - /// The same sequence of tokens `if cond { f } else { g } ()` appears in - /// expression position 3 times. The first two syntactic positions use eager - /// placement of expression boundaries, and parse as `Expr::If`, with the - /// adjacent `()` becoming `Pat::Tuple` or `Expr::Tuple`. In contrast, the - /// third case uses standard expression boundaries and parses as - /// `Expr::Call`. - /// - /// As with [`parse_without_eager_brace`], this ambiguity in the Rust - /// grammar is independent of precedence. - /// - /// [`parse_without_eager_brace`]: Self::parse_without_eager_brace - #[cfg(all(feature = "full", feature = "parsing"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "full", feature = "parsing"))))] - pub fn parse_with_earlier_boundary_rule(input: ParseStream) -> Result<Expr> { - parsing::parse_with_earlier_boundary_rule(input) - } - - /// Returns whether the next token in the parse stream is one that might - /// possibly form the beginning of an expr. - /// - /// This classification is a load-bearing part of the grammar of some Rust - /// expressions, notably `return` and `break`. For example `return < …` will - /// never parse `<` as a binary operator regardless of what comes after, - /// because `<` is a legal starting token for an expression and so it's - /// required to be continued as a return value, such as `return <Struct as - /// Trait>::CONST`. Meanwhile `return > …` treats the `>` as a binary - /// operator because it cannot be a starting token for any Rust expression. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn peek(input: ParseStream) -> bool { - input.peek(Ident::peek_any) && !input.peek(Token![as]) // value name or keyword - || input.peek(token::Paren) // tuple - || input.peek(token::Bracket) // array - || input.peek(token::Brace) // block - || input.peek(Lit) // literal - || input.peek(Token![!]) && !input.peek(Token![!=]) // operator not - || input.peek(Token![-]) && !input.peek(Token![-=]) && !input.peek(Token![->]) // unary minus - || input.peek(Token![*]) && !input.peek(Token![*=]) // dereference - || input.peek(Token![|]) && !input.peek(Token![|=]) // closure - || input.peek(Token![&]) && !input.peek(Token![&=]) // reference - || input.peek(Token![..]) // range - || input.peek(Token![<]) && !input.peek(Token![<=]) && !input.peek(Token![<<=]) // associated path - || input.peek(Token![::]) // absolute path - || input.peek(Lifetime) // labeled loop - || input.peek(Token![#]) // expression attributes - } - - #[cfg(all(feature = "parsing", feature = "full"))] - pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> { - match self { - Expr::Array(ExprArray { attrs, .. }) - | Expr::Assign(ExprAssign { attrs, .. }) - | Expr::Async(ExprAsync { attrs, .. }) - | Expr::Await(ExprAwait { attrs, .. }) - | Expr::Binary(ExprBinary { attrs, .. }) - | Expr::Block(ExprBlock { attrs, .. }) - | Expr::Break(ExprBreak { attrs, .. }) - | Expr::Call(ExprCall { attrs, .. }) - | Expr::Cast(ExprCast { attrs, .. }) - | Expr::Closure(ExprClosure { attrs, .. }) - | Expr::Const(ExprConst { attrs, .. }) - | Expr::Continue(ExprContinue { attrs, .. }) - | Expr::Field(ExprField { attrs, .. }) - | Expr::ForLoop(ExprForLoop { attrs, .. }) - | Expr::Group(ExprGroup { attrs, .. }) - | Expr::If(ExprIf { attrs, .. }) - | Expr::Index(ExprIndex { attrs, .. }) - | Expr::Infer(ExprInfer { attrs, .. }) - | Expr::Let(ExprLet { attrs, .. }) - | Expr::Lit(ExprLit { attrs, .. }) - | Expr::Loop(ExprLoop { attrs, .. }) - | Expr::Macro(ExprMacro { attrs, .. }) - | Expr::Match(ExprMatch { attrs, .. }) - | Expr::MethodCall(ExprMethodCall { attrs, .. }) - | Expr::Paren(ExprParen { attrs, .. }) - | Expr::Path(ExprPath { attrs, .. }) - | Expr::Range(ExprRange { attrs, .. }) - | Expr::RawAddr(ExprRawAddr { attrs, .. }) - | Expr::Reference(ExprReference { attrs, .. }) - | Expr::Repeat(ExprRepeat { attrs, .. }) - | Expr::Return(ExprReturn { attrs, .. }) - | Expr::Struct(ExprStruct { attrs, .. }) - | Expr::Try(ExprTry { attrs, .. }) - | Expr::TryBlock(ExprTryBlock { attrs, .. }) - | Expr::Tuple(ExprTuple { attrs, .. }) - | Expr::Unary(ExprUnary { attrs, .. }) - | Expr::Unsafe(ExprUnsafe { attrs, .. }) - | Expr::While(ExprWhile { attrs, .. }) - | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), - Expr::Verbatim(_) => Vec::new(), - } - } -} - -ast_enum! { - /// A struct or tuple struct field accessed in a struct literal or field - /// expression. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum Member { - /// A named field like `self.x`. - Named(Ident), - /// An unnamed field like `self.0`. - Unnamed(Index), - } -} - -impl From<Ident> for Member { - fn from(ident: Ident) -> Member { - Member::Named(ident) - } -} - -impl From<Index> for Member { - fn from(index: Index) -> Member { - Member::Unnamed(index) - } -} - -impl From<usize> for Member { - fn from(index: usize) -> Member { - Member::Unnamed(Index::from(index)) - } -} - -impl Eq for Member {} - -impl PartialEq for Member { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Member::Named(this), Member::Named(other)) => this == other, - (Member::Unnamed(this), Member::Unnamed(other)) => this == other, - _ => false, - } - } -} - -impl Hash for Member { - fn hash<H: Hasher>(&self, state: &mut H) { - match self { - Member::Named(m) => m.hash(state), - Member::Unnamed(m) => m.hash(state), - } - } -} - -#[cfg(feature = "printing")] -impl IdentFragment for Member { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self { - Member::Named(m) => Display::fmt(m, formatter), - Member::Unnamed(m) => Display::fmt(&m.index, formatter), - } - } - - fn span(&self) -> Option<Span> { - match self { - Member::Named(m) => Some(m.span()), - Member::Unnamed(m) => Some(m.span), - } - } -} - -#[cfg(any(feature = "parsing", feature = "printing"))] -impl Member { - pub(crate) fn is_named(&self) -> bool { - match self { - Member::Named(_) => true, - Member::Unnamed(_) => false, - } - } -} - -ast_struct! { - /// The index of an unnamed tuple struct field. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Index { - pub index: u32, - pub span: Span, - } -} - -impl From<usize> for Index { - fn from(index: usize) -> Index { - assert!(index < u32::MAX as usize); - Index { index: index as u32, span: Span::call_site() } - } -} - -impl Eq for Index {} - -impl PartialEq for Index { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } -} - -impl Hash for Index { - fn hash<H: Hasher>(&self, state: &mut H) { - self.index.hash(state); - } -} - -#[cfg(feature = "printing")] -impl IdentFragment for Index { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.index, formatter) - } - - fn span(&self) -> Option<Span> { - Some(self.span) - } -} - -ast_struct! { - /// A field-value pair in a struct literal. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct FieldValue { - pub attrs: Vec<Attribute>, - pub member: Member, - - /// The colon in `Struct { x: x }`. If written in shorthand like - /// `Struct { x }`, there is no colon. - pub colon_token: Option<Token![:]>, - - pub expr: Expr, - } -} - -#[cfg(feature = "full")] -ast_struct! { - /// A lifetime labeling a `for`, `while`, or `loop`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Label { - pub name: Lifetime, - pub colon_token: Token![:], - } -} - -#[cfg(feature = "full")] -ast_struct! { - /// One arm of a `match` expression: `0..=10 => { return true; }`. - /// - /// As in: - /// - /// ``` - /// # fn f() -> bool { - /// # let n = 0; - /// match n { - /// 0..=10 => { - /// return true; - /// } - /// // ... - /// # _ => {} - /// } - /// # false - /// # } - /// ``` - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Arm { - pub attrs: Vec<Attribute>, - pub pat: Pat, - pub guard: Option<(Token![if], Box<Expr>)>, - pub fat_arrow_token: Token![=>], - pub body: Box<Expr>, - pub comma: Option<Token![,]>, - } -} - -#[cfg(feature = "full")] -ast_enum! { - /// Limit types of a range, inclusive or exclusive. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub enum RangeLimits { - /// Inclusive at the beginning, exclusive at the end. - HalfOpen(Token![..]), - /// Inclusive at the beginning and end. - Closed(Token![..=]), - } -} - -#[cfg(feature = "full")] -ast_enum! { - /// Mutability of a raw pointer (`*const T`, `*mut T`), in which non-mutable - /// isn't the implicit default. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub enum PointerMutability { - Const(Token![const]), - Mut(Token![mut]), - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - #[cfg(feature = "full")] - use crate::attr; - use crate::attr::Attribute; - #[cfg(feature = "full")] - use crate::buffer::Cursor; - #[cfg(feature = "full")] - use crate::classify; - use crate::error::{Error, Result}; - #[cfg(feature = "full")] - use crate::expr::{ - Arm, ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, - ExprConst, ExprContinue, ExprForLoop, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch, - ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprUnsafe, - ExprWhile, ExprYield, Label, PointerMutability, RangeLimits, - }; - use crate::expr::{ - Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprGroup, ExprIndex, ExprLit, ExprMacro, - ExprMethodCall, ExprParen, ExprPath, ExprReference, ExprStruct, ExprTuple, ExprUnary, - FieldValue, Index, Member, - }; - #[cfg(feature = "full")] - use crate::generics::{self, BoundLifetimes}; - use crate::ident::Ident; - #[cfg(feature = "full")] - use crate::lifetime::Lifetime; - use crate::lit::{Lit, LitFloat, LitInt}; - use crate::mac::{self, Macro}; - use crate::op::BinOp; - use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; - #[cfg(feature = "full")] - use crate::pat::{Pat, PatType}; - use crate::path::{self, AngleBracketedGenericArguments, Path, QSelf}; - use crate::precedence::Precedence; - use crate::punctuated::Punctuated; - #[cfg(feature = "full")] - use crate::stmt::Block; - use crate::token; - use crate::ty; - #[cfg(feature = "full")] - use crate::ty::{ReturnType, Type}; - use crate::verbatim; - use alloc::boxed::Box; - use alloc::format; - use alloc::string::ToString; - use alloc::vec::Vec; - use core::mem; - #[cfg(feature = "full")] - use proc_macro2::{Span, TokenStream}; - - // When we're parsing expressions which occur before blocks, like in an if - // statement's condition, we cannot parse a struct literal. - // - // Struct literals are ambiguous in certain positions - // https://github.com/rust-lang/rfcs/pull/92 - #[cfg(feature = "full")] - pub(super) struct AllowStruct(pub bool); - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Expr { - fn parse(input: ParseStream) -> Result<Self> { - ambiguous_expr( - input, - #[cfg(feature = "full")] - AllowStruct(true), - ) - } - } - - #[cfg(feature = "full")] - pub(super) fn parse_with_earlier_boundary_rule(input: ParseStream) -> Result<Expr> { - let mut attrs = input.call(expr_attrs)?; - let mut expr = if input.peek(token::Group) { - let allow_struct = AllowStruct(true); - let atom = expr_group(input, allow_struct)?; - if continue_parsing_early(&atom) { - trailer_helper(input, atom)? - } else { - atom - } - } else if input.peek(Token![if]) { - Expr::If(input.parse()?) - } else if input.peek(Token![while]) { - Expr::While(input.parse()?) - } else if input.peek(Token![for]) - && !generics::parsing::choose_generics_over_qpath_after_keyword(input) - { - Expr::ForLoop(input.parse()?) - } else if input.peek(Token![loop]) { - Expr::Loop(input.parse()?) - } else if input.peek(Token![match]) { - Expr::Match(input.parse()?) - } else if input.peek(Token![try]) && input.peek2(token::Brace) { - Expr::TryBlock(input.parse()?) - } else if input.peek(Token![unsafe]) { - Expr::Unsafe(input.parse()?) - } else if input.peek(Token![const]) && input.peek2(token::Brace) { - Expr::Const(input.parse()?) - } else if input.peek(token::Brace) { - Expr::Block(input.parse()?) - } else if input.peek(Lifetime) { - atom_labeled(input)? - } else { - let allow_struct = AllowStruct(true); - unary_expr(input, allow_struct)? - }; - - if continue_parsing_early(&expr) { - attrs.extend(expr.replace_attrs(Vec::new())); - expr.replace_attrs(attrs); - - let allow_struct = AllowStruct(true); - return parse_expr(input, expr, allow_struct, Precedence::MIN); - } - - if input.peek(Token![.]) && !input.peek(Token![..]) || input.peek(Token![?]) { - expr = trailer_helper(input, expr)?; - - attrs.extend(expr.replace_attrs(Vec::new())); - expr.replace_attrs(attrs); - - let allow_struct = AllowStruct(true); - return parse_expr(input, expr, allow_struct, Precedence::MIN); - } - - attrs.extend(expr.replace_attrs(Vec::new())); - expr.replace_attrs(attrs); - Ok(expr) - } - - #[cfg(feature = "full")] - impl Copy for AllowStruct {} - - #[cfg(feature = "full")] - impl Clone for AllowStruct { - fn clone(&self) -> Self { - *self - } - } - - #[cfg(feature = "full")] - fn parse_expr( - input: ParseStream, - mut lhs: Expr, - allow_struct: AllowStruct, - base: Precedence, - ) -> Result<Expr> { - loop { - let ahead = input.fork(); - if let Expr::Range(_) = lhs { - // A range cannot be the left-hand side of another binary operator. - break; - } else if let Ok(op) = ahead.parse::<BinOp>() { - let precedence = Precedence::of_binop(&op); - if precedence < base { - break; - } - if precedence == Precedence::Assign { - if let Expr::Range(_) = lhs { - break; - } - } - if precedence == Precedence::Compare { - if let Expr::Binary(lhs) = &lhs { - if Precedence::of_binop(&lhs.op) == Precedence::Compare { - return Err(input.error("comparison operators cannot be chained")); - } - } - } - input.advance_to(&ahead); - let right = parse_binop_rhs(input, allow_struct, precedence)?; - lhs = - Expr::Binary(ExprBinary { attrs: Vec::new(), left: Box::new(lhs), op, right }); - } else if Precedence::Assign >= base - && input.peek(Token![=]) - && !input.peek(Token![=>]) - && match lhs { - Expr::Range(_) => false, - _ => true, - } - { - let eq_token: Token![=] = input.parse()?; - let right = parse_binop_rhs(input, allow_struct, Precedence::Assign)?; - lhs = Expr::Assign(ExprAssign { - attrs: Vec::new(), - left: Box::new(lhs), - eq_token, - right, - }); - } else if Precedence::Range >= base && input.peek(Token![..]) { - let limits: RangeLimits = input.parse()?; - let end = parse_range_end(input, &limits, allow_struct)?; - lhs = Expr::Range(ExprRange { - attrs: Vec::new(), - start: Some(Box::new(lhs)), - limits, - end, - }); - } else if Precedence::Cast >= base && input.peek(Token![as]) { - let as_token: Token![as] = input.parse()?; - let allow_plus = false; - let allow_group_generic = false; - let ty = ty::parsing::ambig_ty(input, allow_plus, allow_group_generic)?; - check_cast(input)?; - lhs = Expr::Cast(ExprCast { - attrs: Vec::new(), - expr: Box::new(lhs), - as_token, - ty: Box::new(ty), - }); - } else { - break; - } - } - Ok(lhs) - } - - #[cfg(not(feature = "full"))] - fn parse_expr(input: ParseStream, mut lhs: Expr, base: Precedence) -> Result<Expr> { - loop { - let ahead = input.fork(); - if let Ok(op) = ahead.parse::<BinOp>() { - let precedence = Precedence::of_binop(&op); - if precedence < base { - break; - } - if precedence == Precedence::Compare { - if let Expr::Binary(lhs) = &lhs { - if Precedence::of_binop(&lhs.op) == Precedence::Compare { - return Err(input.error("comparison operators cannot be chained")); - } - } - } - input.advance_to(&ahead); - let right = parse_binop_rhs(input, precedence)?; - lhs = - Expr::Binary(ExprBinary { attrs: Vec::new(), left: Box::new(lhs), op, right }); - } else if Precedence::Cast >= base && input.peek(Token![as]) { - let as_token: Token![as] = input.parse()?; - let allow_plus = false; - let allow_group_generic = false; - let ty = ty::parsing::ambig_ty(input, allow_plus, allow_group_generic)?; - check_cast(input)?; - lhs = Expr::Cast(ExprCast { - attrs: Vec::new(), - expr: Box::new(lhs), - as_token, - ty: Box::new(ty), - }); - } else { - break; - } - } - Ok(lhs) - } - - fn parse_binop_rhs( - input: ParseStream, - #[cfg(feature = "full")] allow_struct: AllowStruct, - precedence: Precedence, - ) -> Result<Box<Expr>> { - let mut rhs = unary_expr( - input, - #[cfg(feature = "full")] - allow_struct, - )?; - loop { - let next = peek_precedence(input); - if next > precedence || next == precedence && precedence == Precedence::Assign { - let cursor = input.cursor(); - rhs = parse_expr( - input, - rhs, - #[cfg(feature = "full")] - allow_struct, - next, - )?; - if cursor == input.cursor() { - // Bespoke grammar restrictions separate from precedence can - // cause parsing to not advance, such as `..a` being - // disallowed in the left-hand side of binary operators, - // even ones that have lower precedence than `..`. - break; - } - } else { - break; - } - } - Ok(Box::new(rhs)) - } - - fn peek_precedence(input: ParseStream) -> Precedence { - if let Ok(op) = input.fork().parse() { - Precedence::of_binop(&op) - } else if input.peek(Token![=]) && !input.peek(Token![=>]) { - Precedence::Assign - } else if input.peek(Token![..]) { - Precedence::Range - } else if input.peek(Token![as]) { - Precedence::Cast - } else { - Precedence::MIN - } - } - - // Parse an arbitrary expression. - pub(super) fn ambiguous_expr( - input: ParseStream, - #[cfg(feature = "full")] allow_struct: AllowStruct, - ) -> Result<Expr> { - let lhs = unary_expr( - input, - #[cfg(feature = "full")] - allow_struct, - )?; - parse_expr( - input, - lhs, - #[cfg(feature = "full")] - allow_struct, - Precedence::MIN, - ) - } - - #[cfg(feature = "full")] - fn expr_attrs(input: ParseStream) -> Result<Vec<Attribute>> { - let mut attrs = Vec::new(); - while !input.peek(token::Group) && input.peek(Token![#]) { - attrs.push(input.call(attr::parsing::single_parse_outer)?); - } - Ok(attrs) - } - - // <UnOp> <trailer> - // & <trailer> - // &mut <trailer> - // box <trailer> - #[cfg(feature = "full")] - fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { - let begin = input.cursor(); - let attrs = input.call(expr_attrs)?; - if input.peek(token::Group) { - return trailer_expr(begin, attrs, input, allow_struct); - } - - if input.peek(Token![&]) { - let and_token: Token![&] = input.parse()?; - let raw: Option<Token![raw]> = if input.peek(Token![raw]) - && (input.peek2(Token![mut]) || input.peek2(Token![const])) - { - Some(input.parse()?) - } else { - None - }; - let mutability: Option<Token![mut]> = input.parse()?; - let const_token: Option<Token![const]> = - if raw.is_some() && mutability.is_none() { Some(input.parse()?) } else { None }; - let expr = Box::new(unary_expr(input, allow_struct)?); - if let Some(raw) = raw { - Ok(Expr::RawAddr(ExprRawAddr { - attrs, - and_token, - raw, - mutability: match mutability { - Some(mut_token) => PointerMutability::Mut(mut_token), - None => PointerMutability::Const(const_token.unwrap()), - }, - expr, - })) - } else { - Ok(Expr::Reference(ExprReference { attrs, and_token, mutability, expr })) - } - } else if input.peek(Token![*]) || input.peek(Token![!]) || input.peek(Token![-]) { - expr_unary(input, attrs, allow_struct).map(Expr::Unary) - } else { - trailer_expr(begin, attrs, input, allow_struct) - } - } - - #[cfg(not(feature = "full"))] - fn unary_expr(input: ParseStream) -> Result<Expr> { - if input.peek(Token![&]) { - Ok(Expr::Reference(ExprReference { - attrs: Vec::new(), - and_token: input.parse()?, - mutability: input.parse()?, - expr: Box::new(unary_expr(input)?), - })) - } else if input.peek(Token![*]) || input.peek(Token![!]) || input.peek(Token![-]) { - Ok(Expr::Unary(ExprUnary { - attrs: Vec::new(), - op: input.parse()?, - expr: Box::new(unary_expr(input)?), - })) - } else { - trailer_expr(input) - } - } - - // <atom> (..<args>) ... - // <atom> . <ident> (..<args>) ... - // <atom> . <ident> ... - // <atom> . <lit> ... - // <atom> [ <expr> ] ... - // <atom> ? ... - #[cfg(feature = "full")] - fn trailer_expr( - begin: Cursor, - mut attrs: Vec<Attribute>, - input: ParseStream, - allow_struct: AllowStruct, - ) -> Result<Expr> { - let atom = atom_expr(input, allow_struct)?; - let mut e = trailer_helper(input, atom)?; - - if let Expr::Verbatim(tokens) = &mut e { - *tokens = verbatim::between(begin, input.cursor()); - } else if !attrs.is_empty() { - if let Expr::Range(range) = e { - let spans: &[Span] = match &range.limits { - RangeLimits::HalfOpen(limits) => &limits.spans, - RangeLimits::Closed(limits) => &limits.spans, - }; - return Err(crate::error::new2( - spans[0], - *spans.last().unwrap(), - "attributes are not allowed on range expressions starting with `..`", - )); - } - let inner_attrs = e.replace_attrs(Vec::new()); - attrs.extend(inner_attrs); - e.replace_attrs(attrs); - } - - Ok(e) - } - - #[cfg(feature = "full")] - fn trailer_helper(input: ParseStream, mut e: Expr) -> Result<Expr> { - loop { - if input.peek(token::Paren) { - let content; - e = Expr::Call(ExprCall { - attrs: Vec::new(), - func: Box::new(e), - paren_token: parenthesized!(content in input), - args: content.parse_terminated(Expr::parse, Token![,])?, - }); - } else if input.peek(Token![.]) - && !input.peek(Token![..]) - && match e { - Expr::Range(_) => false, - _ => true, - } - { - let mut dot_token: Token![.] = input.parse()?; - - let float_token: Option<LitFloat> = input.parse()?; - if let Some(float_token) = float_token { - if multi_index(&mut e, &mut dot_token, float_token)? { - continue; - } - } - - let await_token: Option<Token![await]> = input.parse()?; - if let Some(await_token) = await_token { - e = Expr::Await(ExprAwait { - attrs: Vec::new(), - base: Box::new(e), - dot_token, - await_token, - }); - continue; - } - - let member: Member = input.parse()?; - let turbofish = if member.is_named() && input.peek(Token![::]) { - Some(AngleBracketedGenericArguments::parse_turbofish(input)?) - } else { - None - }; - - if turbofish.is_some() || input.peek(token::Paren) { - if let Member::Named(method) = member { - let content; - e = Expr::MethodCall(ExprMethodCall { - attrs: Vec::new(), - receiver: Box::new(e), - dot_token, - method, - turbofish, - paren_token: parenthesized!(content in input), - args: content.parse_terminated(Expr::parse, Token![,])?, - }); - continue; - } - } - - e = Expr::Field(ExprField { - attrs: Vec::new(), - base: Box::new(e), - dot_token, - member, - }); - } else if input.peek(token::Bracket) { - let content; - e = Expr::Index(ExprIndex { - attrs: Vec::new(), - expr: Box::new(e), - bracket_token: bracketed!(content in input), - index: content.parse()?, - }); - } else if input.peek(Token![?]) - && match e { - Expr::Range(_) => false, - _ => true, - } - { - e = Expr::Try(ExprTry { - attrs: Vec::new(), - expr: Box::new(e), - question_token: input.parse()?, - }); - } else { - break; - } - } - Ok(e) - } - - #[cfg(not(feature = "full"))] - fn trailer_expr(input: ParseStream) -> Result<Expr> { - let mut e = atom_expr(input)?; - - loop { - if input.peek(token::Paren) { - let content; - e = Expr::Call(ExprCall { - attrs: Vec::new(), - func: Box::new(e), - paren_token: parenthesized!(content in input), - args: content.parse_terminated(Expr::parse, Token![,])?, - }); - } else if input.peek(Token![.]) - && !input.peek(Token![..]) - && !input.peek2(Token![await]) - { - let mut dot_token: Token![.] = input.parse()?; - - let float_token: Option<LitFloat> = input.parse()?; - if let Some(float_token) = float_token { - if multi_index(&mut e, &mut dot_token, float_token)? { - continue; - } - } - - let member: Member = input.parse()?; - let turbofish = if member.is_named() && input.peek(Token![::]) { - let colon2_token: Token![::] = input.parse()?; - let turbofish = - AngleBracketedGenericArguments::do_parse(Some(colon2_token), input)?; - Some(turbofish) - } else { - None - }; - - if turbofish.is_some() || input.peek(token::Paren) { - if let Member::Named(method) = member { - let content; - e = Expr::MethodCall(ExprMethodCall { - attrs: Vec::new(), - receiver: Box::new(e), - dot_token, - method, - turbofish, - paren_token: parenthesized!(content in input), - args: content.parse_terminated(Expr::parse, Token![,])?, - }); - continue; - } - } - - e = Expr::Field(ExprField { - attrs: Vec::new(), - base: Box::new(e), - dot_token, - member, - }); - } else if input.peek(token::Bracket) { - let content; - e = Expr::Index(ExprIndex { - attrs: Vec::new(), - expr: Box::new(e), - bracket_token: bracketed!(content in input), - index: content.parse()?, - }); - } else { - break; - } - } - - Ok(e) - } - - // Parse all atomic expressions which don't have to worry about precedence - // interactions, as they are fully contained. - #[cfg(feature = "full")] - fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { - if input.peek(token::Group) { - expr_group(input, allow_struct) - } else if input.peek(Lit) { - input.parse().map(Expr::Lit) - } else if input.peek(Token![async]) - && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace)) - { - input.parse().map(Expr::Async) - } else if input.peek(Token![try]) && input.peek2(token::Brace) { - input.parse().map(Expr::TryBlock) - } else if input.peek(Token![|]) - || input.peek(Token![move]) - || input.peek(Token![for]) - && generics::parsing::choose_generics_over_qpath_after_keyword(input) - || input.peek(Token![const]) && !input.peek2(token::Brace) - || input.peek(Token![static]) - || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move])) - { - expr_closure(input, allow_struct).map(Expr::Closure) - } else if token::parsing::peek_keyword(input.cursor(), "builtin") && input.peek2(Token![#]) - { - expr_builtin(input) - } else if input.peek(Ident) - || input.peek(Token![::]) - || input.peek(Token![<]) - || input.peek(Token![self]) - || input.peek(Token![Self]) - || input.peek(Token![super]) - || input.peek(Token![crate]) - || input.peek(Token![try]) && (input.peek2(Token![!]) || input.peek2(Token![::])) - { - path_or_macro_or_struct(input, allow_struct) - } else if input.peek(token::Paren) { - paren_or_tuple(input) - } else if input.peek(Token![break]) { - expr_break(input, allow_struct).map(Expr::Break) - } else if input.peek(Token![continue]) { - input.parse().map(Expr::Continue) - } else if input.peek(Token![return]) { - input.parse().map(Expr::Return) - } else if input.peek(Token![become]) { - expr_become(input) - } else if input.peek(token::Bracket) { - array_or_repeat(input) - } else if input.peek(Token![let]) { - expr_let(input, allow_struct).map(Expr::Let) - } else if input.peek(Token![if]) { - input.parse().map(Expr::If) - } else if input.peek(Token![while]) { - input.parse().map(Expr::While) - } else if input.peek(Token![for]) { - input.parse().map(Expr::ForLoop) - } else if input.peek(Token![loop]) { - input.parse().map(Expr::Loop) - } else if input.peek(Token![match]) { - input.parse().map(Expr::Match) - } else if input.peek(Token![yield]) { - input.parse().map(Expr::Yield) - } else if input.peek(Token![unsafe]) { - input.parse().map(Expr::Unsafe) - } else if input.peek(Token![const]) { - input.parse().map(Expr::Const) - } else if input.peek(token::Brace) { - input.parse().map(Expr::Block) - } else if input.peek(Token![..]) { - expr_range(input, allow_struct).map(Expr::Range) - } else if input.peek(Token![_]) { - input.parse().map(Expr::Infer) - } else if input.peek(Lifetime) { - atom_labeled(input) - } else { - Err(input.error("expected an expression")) - } - } - - #[cfg(feature = "full")] - fn atom_labeled(input: ParseStream) -> Result<Expr> { - let the_label: Label = input.parse()?; - let mut expr = if input.peek(Token![while]) { - Expr::While(input.parse()?) - } else if input.peek(Token![for]) { - Expr::ForLoop(input.parse()?) - } else if input.peek(Token![loop]) { - Expr::Loop(input.parse()?) - } else if input.peek(token::Brace) { - Expr::Block(input.parse()?) - } else { - return Err(input.error("expected loop or block expression")); - }; - match &mut expr { - Expr::While(ExprWhile { label, .. }) - | Expr::ForLoop(ExprForLoop { label, .. }) - | Expr::Loop(ExprLoop { label, .. }) - | Expr::Block(ExprBlock { label, .. }) => *label = Some(the_label), - _ => unreachable!(), - } - Ok(expr) - } - - #[cfg(not(feature = "full"))] - fn atom_expr(input: ParseStream) -> Result<Expr> { - if input.peek(token::Group) { - expr_group(input) - } else if input.peek(Lit) { - input.parse().map(Expr::Lit) - } else if input.peek(token::Paren) { - paren_or_tuple(input) - } else if input.peek(Ident) - || input.peek(Token![::]) - || input.peek(Token![<]) - || input.peek(Token![self]) - || input.peek(Token![Self]) - || input.peek(Token![super]) - || input.peek(Token![crate]) - { - path_or_macro_or_struct(input) - } else if input.is_empty() { - Err(input.error("expected an expression")) - } else { - if input.peek(token::Brace) { - let scan = input.fork(); - let content; - braced!(content in scan); - if content.parse::<Expr>().is_ok() && content.is_empty() { - let expr_block = verbatim::between(input.cursor(), scan.cursor()); - input.advance_to(&scan); - return Ok(Expr::Verbatim(expr_block)); - } - } - Err(input.error("unsupported expression; enable syn's features=[\"full\"]")) - } - } - - #[cfg(feature = "full")] - fn expr_builtin(input: ParseStream) -> Result<Expr> { - let begin = input.cursor(); - - token::parsing::keyword(input, "builtin")?; - input.parse::<Token![#]>()?; - input.parse::<Ident>()?; - - let args; - parenthesized!(args in input); - args.parse::<TokenStream>()?; - - Ok(Expr::Verbatim(verbatim::between(begin, input.cursor()))) - } - - fn path_or_macro_or_struct( - input: ParseStream, - #[cfg(feature = "full")] allow_struct: AllowStruct, - ) -> Result<Expr> { - let expr_style = true; - let (qself, path) = path::parsing::qpath(input, expr_style)?; - rest_of_path_or_macro_or_struct( - qself, - path, - input, - #[cfg(feature = "full")] - allow_struct, - ) - } - - fn rest_of_path_or_macro_or_struct( - qself: Option<QSelf>, - path: Path, - input: ParseStream, - #[cfg(feature = "full")] allow_struct: AllowStruct, - ) -> Result<Expr> { - if qself.is_none() - && input.peek(Token![!]) - && !input.peek(Token![!=]) - && path.is_mod_style() - { - let bang_token: Token![!] = input.parse()?; - let (delimiter, tokens) = mac::parse_delimiter(input)?; - return Ok(Expr::Macro(ExprMacro { - attrs: Vec::new(), - mac: Macro { path, bang_token, delimiter, tokens }, - })); - } - - #[cfg(not(feature = "full"))] - let allow_struct = (true,); - if allow_struct.0 && input.peek(token::Brace) { - return expr_struct_helper(input, qself, path).map(Expr::Struct); - } - - Ok(Expr::Path(ExprPath { attrs: Vec::new(), qself, path })) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprMacro { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprMacro { attrs: Vec::new(), mac: input.parse()? }) - } - } - - fn paren_or_tuple(input: ParseStream) -> Result<Expr> { - let content; - let paren_token = parenthesized!(content in input); - if content.is_empty() { - return Ok(Expr::Tuple(ExprTuple { - attrs: Vec::new(), - paren_token, - elems: Punctuated::new(), - })); - } - - let first: Expr = content.parse()?; - if content.is_empty() { - return Ok(Expr::Paren(ExprParen { - attrs: Vec::new(), - paren_token, - expr: Box::new(first), - })); - } - - let mut elems = Punctuated::new(); - elems.push_value(first); - while !content.is_empty() { - let punct = content.parse()?; - elems.push_punct(punct); - if content.is_empty() { - break; - } - let value = content.parse()?; - elems.push_value(value); - } - Ok(Expr::Tuple(ExprTuple { attrs: Vec::new(), paren_token, elems })) - } - - #[cfg(feature = "full")] - fn array_or_repeat(input: ParseStream) -> Result<Expr> { - let content; - let bracket_token = bracketed!(content in input); - if content.is_empty() { - return Ok(Expr::Array(ExprArray { - attrs: Vec::new(), - bracket_token, - elems: Punctuated::new(), - })); - } - - let first: Expr = content.parse()?; - if content.is_empty() || content.peek(Token![,]) { - let mut elems = Punctuated::new(); - elems.push_value(first); - while !content.is_empty() { - let punct = content.parse()?; - elems.push_punct(punct); - if content.is_empty() { - break; - } - let value = content.parse()?; - elems.push_value(value); - } - Ok(Expr::Array(ExprArray { attrs: Vec::new(), bracket_token, elems })) - } else if content.peek(Token![;]) { - let semi_token: Token![;] = content.parse()?; - let len: Expr = content.parse()?; - Ok(Expr::Repeat(ExprRepeat { - attrs: Vec::new(), - bracket_token, - expr: Box::new(first), - semi_token, - len: Box::new(len), - })) - } else { - Err(content.error("expected `,` or `;`")) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprArray { - fn parse(input: ParseStream) -> Result<Self> { - let content; - let bracket_token = bracketed!(content in input); - let mut elems = Punctuated::new(); - - while !content.is_empty() { - let first: Expr = content.parse()?; - elems.push_value(first); - if content.is_empty() { - break; - } - let punct = content.parse()?; - elems.push_punct(punct); - } - - Ok(ExprArray { attrs: Vec::new(), bracket_token, elems }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprRepeat { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(ExprRepeat { - bracket_token: bracketed!(content in input), - attrs: Vec::new(), - expr: content.parse()?, - semi_token: content.parse()?, - len: content.parse()?, - }) - } - } - - #[cfg(feature = "full")] - fn continue_parsing_early(mut expr: &Expr) -> bool { - while let Expr::Group(group) = expr { - expr = &group.expr; - } - match expr { - Expr::If(_) - | Expr::While(_) - | Expr::ForLoop(_) - | Expr::Loop(_) - | Expr::Match(_) - | Expr::TryBlock(_) - | Expr::Unsafe(_) - | Expr::Const(_) - | Expr::Block(_) => false, - _ => true, - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprLit { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprLit { attrs: Vec::new(), lit: input.parse()? }) - } - } - - fn expr_group( - input: ParseStream, - #[cfg(feature = "full")] allow_struct: AllowStruct, - ) -> Result<Expr> { - let group = crate::group::parse_group(input)?; - let mut inner: Expr = group.content.parse()?; - - match inner { - Expr::Path(mut expr) if expr.attrs.is_empty() => { - let grouped_len = expr.path.segments.len(); - Path::parse_rest(input, &mut expr.path, true)?; - match rest_of_path_or_macro_or_struct( - expr.qself, - expr.path, - input, - #[cfg(feature = "full")] - allow_struct, - )? { - Expr::Path(expr) if expr.path.segments.len() == grouped_len => { - inner = Expr::Path(expr); - } - extended => return Ok(extended), - } - } - _ => {} - } - - Ok(Expr::Group(ExprGroup { - attrs: Vec::new(), - group_token: group.token, - expr: Box::new(inner), - })) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprParen { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(ExprParen { - attrs: Vec::new(), - paren_token: parenthesized!(content in input), - expr: content.parse()?, - }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprLet { - fn parse(input: ParseStream) -> Result<Self> { - let allow_struct = AllowStruct(true); - expr_let(input, allow_struct) - } - } - - #[cfg(feature = "full")] - fn expr_let(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprLet> { - Ok(ExprLet { - attrs: Vec::new(), - let_token: input.parse()?, - pat: Box::new(Pat::parse_multi_with_leading_vert(input)?), - eq_token: input.parse()?, - expr: Box::new({ - let lhs = unary_expr(input, allow_struct)?; - parse_expr(input, lhs, allow_struct, Precedence::Compare)? - }), - }) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprIf { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - - let mut clauses = Vec::new(); - let mut expr; - loop { - let if_token: Token![if] = input.parse()?; - let cond = input.call(Expr::parse_without_eager_brace)?; - let then_branch: Block = input.parse()?; - - expr = ExprIf { - attrs: Vec::new(), - if_token, - cond: Box::new(cond), - then_branch, - else_branch: None, - }; - - if !input.peek(Token![else]) { - break; - } - - let else_token: Token![else] = input.parse()?; - let lookahead = input.lookahead1(); - if lookahead.peek(Token![if]) { - expr.else_branch = Some((else_token, Box::new(Expr::PLACEHOLDER))); - clauses.push(expr); - } else if lookahead.peek(token::Brace) { - expr.else_branch = Some(( - else_token, - Box::new(Expr::Block(ExprBlock { - attrs: Vec::new(), - label: None, - block: input.parse()?, - })), - )); - break; - } else { - return Err(lookahead.error()); - } - } - - while let Some(mut prev) = clauses.pop() { - *prev.else_branch.as_mut().unwrap().1 = Expr::If(expr); - expr = prev; - } - expr.attrs = attrs; - Ok(expr) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprInfer { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprInfer { - attrs: input.call(Attribute::parse_outer)?, - underscore_token: input.parse()?, - }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprForLoop { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let label: Option<Label> = input.parse()?; - let for_token: Token![for] = input.parse()?; - - let pat = Pat::parse_multi_with_leading_vert(input)?; - - let in_token: Token![in] = input.parse()?; - let expr: Expr = input.call(Expr::parse_without_eager_brace)?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ExprForLoop { - attrs, - label, - for_token, - pat: Box::new(pat), - in_token, - expr: Box::new(expr), - body: Block { brace_token, stmts }, - }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprLoop { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let label: Option<Label> = input.parse()?; - let loop_token: Token![loop] = input.parse()?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ExprLoop { attrs, label, loop_token, body: Block { brace_token, stmts } }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprMatch { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let match_token: Token![match] = input.parse()?; - let expr = Expr::parse_without_eager_brace(input)?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - - let arms = Arm::parse_multiple(&content)?; - - Ok(ExprMatch { attrs, match_token, expr: Box::new(expr), brace_token, arms }) - } - } - - macro_rules! impl_by_parsing_expr { - ( - $( - $expr_type:ty, $variant:ident, $msg:expr, - )* - ) => { - $( - #[cfg(all(feature = "full", feature = "printing"))] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for $expr_type { - fn parse(input: ParseStream) -> Result<Self> { - let mut expr: Expr = input.parse()?; - loop { - match expr { - Expr::$variant(inner) => return Ok(inner), - Expr::Group(next) => expr = *next.expr, - _ => return Err(Error::new_spanned(expr, $msg)), - } - } - } - } - )* - }; - } - - impl_by_parsing_expr! { - ExprAssign, Assign, "expected assignment expression", - ExprAwait, Await, "expected await expression", - ExprBinary, Binary, "expected binary operation", - ExprCall, Call, "expected function call expression", - ExprCast, Cast, "expected cast expression", - ExprField, Field, "expected struct field access", - ExprIndex, Index, "expected indexing expression", - ExprMethodCall, MethodCall, "expected method call expression", - ExprRange, Range, "expected range expression", - ExprTry, Try, "expected try expression", - ExprTuple, Tuple, "expected tuple expression", - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprUnary { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = Vec::new(); - let allow_struct = AllowStruct(true); - expr_unary(input, attrs, allow_struct) - } - } - - #[cfg(feature = "full")] - fn expr_unary( - input: ParseStream, - attrs: Vec<Attribute>, - allow_struct: AllowStruct, - ) -> Result<ExprUnary> { - Ok(ExprUnary { - attrs, - op: input.parse()?, - expr: Box::new(unary_expr(input, allow_struct)?), - }) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprClosure { - fn parse(input: ParseStream) -> Result<Self> { - let allow_struct = AllowStruct(true); - expr_closure(input, allow_struct) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprRawAddr { - fn parse(input: ParseStream) -> Result<Self> { - let allow_struct = AllowStruct(true); - Ok(ExprRawAddr { - attrs: Vec::new(), - and_token: input.parse()?, - raw: input.parse()?, - mutability: input.parse()?, - expr: Box::new(unary_expr(input, allow_struct)?), - }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprReference { - fn parse(input: ParseStream) -> Result<Self> { - let allow_struct = AllowStruct(true); - Ok(ExprReference { - attrs: Vec::new(), - and_token: input.parse()?, - mutability: input.parse()?, - expr: Box::new(unary_expr(input, allow_struct)?), - }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprBreak { - fn parse(input: ParseStream) -> Result<Self> { - let allow_struct = AllowStruct(true); - expr_break(input, allow_struct) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprReturn { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprReturn { - attrs: Vec::new(), - return_token: input.parse()?, - expr: { - if Expr::peek(input) { - Some(input.parse()?) - } else { - None - } - }, - }) - } - } - - #[cfg(feature = "full")] - fn expr_become(input: ParseStream) -> Result<Expr> { - let begin = input.cursor(); - input.parse::<Token![become]>()?; - input.parse::<Expr>()?; - Ok(Expr::Verbatim(verbatim::between(begin, input.cursor()))) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprTryBlock { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprTryBlock { attrs: Vec::new(), try_token: input.parse()?, block: input.parse()? }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprYield { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprYield { - attrs: Vec::new(), - yield_token: input.parse()?, - expr: { - if Expr::peek(input) { - Some(input.parse()?) - } else { - None - } - }, - }) - } - } - - #[cfg(feature = "full")] - fn expr_closure(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprClosure> { - let lifetimes: Option<BoundLifetimes> = input.parse()?; - let constness: Option<Token![const]> = input.parse()?; - let movability: Option<Token![static]> = input.parse()?; - let asyncness: Option<Token![async]> = input.parse()?; - let capture: Option<Token![move]> = input.parse()?; - let or1_token: Token![|] = input.parse()?; - - let mut inputs = Punctuated::new(); - loop { - if input.peek(Token![|]) { - break; - } - let value = closure_arg(input)?; - inputs.push_value(value); - if input.peek(Token![|]) { - break; - } - let punct: Token![,] = input.parse()?; - inputs.push_punct(punct); - } - - let or2_token: Token![|] = input.parse()?; - - let (output, body) = if input.peek(Token![->]) { - let arrow_token: Token![->] = input.parse()?; - let ty: Type = input.parse()?; - let body: Block = input.parse()?; - let output = ReturnType::Type(arrow_token, Box::new(ty)); - let block = Expr::Block(ExprBlock { attrs: Vec::new(), label: None, block: body }); - (output, block) - } else { - let body = ambiguous_expr(input, allow_struct)?; - (ReturnType::Default, body) - }; - - Ok(ExprClosure { - attrs: Vec::new(), - lifetimes, - constness, - movability, - asyncness, - capture, - or1_token, - inputs, - or2_token, - output, - body: Box::new(body), - }) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprAsync { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprAsync { - attrs: Vec::new(), - async_token: input.parse()?, - capture: input.parse()?, - block: input.parse()?, - }) - } - } - - #[cfg(feature = "full")] - fn closure_arg(input: ParseStream) -> Result<Pat> { - let attrs = input.call(Attribute::parse_outer)?; - let mut pat = Pat::parse_single(input)?; - - if input.peek(Token![:]) { - Ok(Pat::Type(PatType { - attrs, - pat: Box::new(pat), - colon_token: input.parse()?, - ty: input.parse()?, - })) - } else { - match &mut pat { - Pat::Const(pat) => pat.attrs = attrs, - Pat::Ident(pat) => pat.attrs = attrs, - Pat::Lit(pat) => pat.attrs = attrs, - Pat::Macro(pat) => pat.attrs = attrs, - Pat::Or(pat) => pat.attrs = attrs, - Pat::Paren(pat) => pat.attrs = attrs, - Pat::Path(pat) => pat.attrs = attrs, - Pat::Range(pat) => pat.attrs = attrs, - Pat::Reference(pat) => pat.attrs = attrs, - Pat::Rest(pat) => pat.attrs = attrs, - Pat::Slice(pat) => pat.attrs = attrs, - Pat::Struct(pat) => pat.attrs = attrs, - Pat::Tuple(pat) => pat.attrs = attrs, - Pat::TupleStruct(pat) => pat.attrs = attrs, - Pat::Type(_) => unreachable!(), - Pat::Verbatim(_) => {} - Pat::Wild(pat) => pat.attrs = attrs, - } - Ok(pat) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprWhile { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let label: Option<Label> = input.parse()?; - let while_token: Token![while] = input.parse()?; - let cond = Expr::parse_without_eager_brace(input)?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ExprWhile { - attrs, - label, - while_token, - cond: Box::new(cond), - body: Block { brace_token, stmts }, - }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprConst { - fn parse(input: ParseStream) -> Result<Self> { - let const_token: Token![const] = input.parse()?; - - let content; - let brace_token = braced!(content in input); - let inner_attrs = content.call(Attribute::parse_inner)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ExprConst { attrs: inner_attrs, const_token, block: Block { brace_token, stmts } }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Label { - fn parse(input: ParseStream) -> Result<Self> { - Ok(Label { name: input.parse()?, colon_token: input.parse()? }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Option<Label> { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Lifetime) { - input.parse().map(Some) - } else { - Ok(None) - } - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprContinue { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ExprContinue { - attrs: Vec::new(), - continue_token: input.parse()?, - label: input.parse()?, - }) - } - } - - #[cfg(feature = "full")] - fn expr_break(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprBreak> { - let break_token: Token![break] = input.parse()?; - - let ahead = input.fork(); - let label: Option<Lifetime> = ahead.parse()?; - if label.is_some() && ahead.peek(Token![:]) { - // Not allowed: `break 'label: loop {...}` - // Parentheses are required. `break ('label: loop {...})` - let _: Expr = input.parse()?; - let start_span = label.unwrap().apostrophe; - let end_span = input.cursor().prev_span(); - return Err(crate::error::new2(start_span, end_span, "parentheses required")); - } - - input.advance_to(&ahead); - let expr = if Expr::peek(input) && (allow_struct.0 || !input.peek(token::Brace)) { - Some(input.parse()?) - } else { - None - }; - - Ok(ExprBreak { attrs: Vec::new(), break_token, label, expr }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for FieldValue { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let member: Member = input.parse()?; - let (colon_token, value) = if input.peek(Token![:]) || !member.is_named() { - let colon_token: Token![:] = input.parse()?; - let value: Expr = input.parse()?; - (Some(colon_token), value) - } else if let Member::Named(ident) = &member { - let value = Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path::from(ident.clone()), - }); - (None, value) - } else { - unreachable!() - }; - - Ok(FieldValue { attrs, member, colon_token, expr: value }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprStruct { - fn parse(input: ParseStream) -> Result<Self> { - let expr_style = true; - let (qself, path) = path::parsing::qpath(input, expr_style)?; - expr_struct_helper(input, qself, path) - } - } - - fn expr_struct_helper( - input: ParseStream, - qself: Option<QSelf>, - path: Path, - ) -> Result<ExprStruct> { - let content; - let brace_token = braced!(content in input); - - let mut fields = Punctuated::new(); - while !content.is_empty() { - if content.peek(Token![..]) { - return Ok(ExprStruct { - attrs: Vec::new(), - qself, - path, - brace_token, - fields, - dot2_token: Some(content.parse()?), - rest: if content.is_empty() { None } else { Some(Box::new(content.parse()?)) }, - }); - } - - fields.push(content.parse()?); - if content.is_empty() { - break; - } - let punct: Token![,] = content.parse()?; - fields.push_punct(punct); - } - - Ok(ExprStruct { - attrs: Vec::new(), - qself, - path, - brace_token, - fields, - dot2_token: None, - rest: None, - }) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprUnsafe { - fn parse(input: ParseStream) -> Result<Self> { - let unsafe_token: Token![unsafe] = input.parse()?; - - let content; - let brace_token = braced!(content in input); - let inner_attrs = content.call(Attribute::parse_inner)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ExprUnsafe { attrs: inner_attrs, unsafe_token, block: Block { brace_token, stmts } }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprBlock { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let label: Option<Label> = input.parse()?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ExprBlock { attrs, label, block: Block { brace_token, stmts } }) - } - } - - #[cfg(feature = "full")] - fn expr_range(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprRange> { - let limits: RangeLimits = input.parse()?; - let end = parse_range_end(input, &limits, allow_struct)?; - Ok(ExprRange { attrs: Vec::new(), start: None, limits, end }) - } - - #[cfg(feature = "full")] - fn parse_range_end( - input: ParseStream, - limits: &RangeLimits, - allow_struct: AllowStruct, - ) -> Result<Option<Box<Expr>>> { - if matches!(limits, RangeLimits::HalfOpen(_)) - && (input.is_empty() - || input.peek(Token![,]) - || input.peek(Token![;]) - || input.peek(Token![.]) && !input.peek(Token![..]) - || input.peek(Token![?]) - || input.peek(Token![=>]) - || !allow_struct.0 && input.peek(token::Brace) - || input.peek(Token![=]) - || input.peek(Token![+]) - || input.peek(Token![/]) - || input.peek(Token![%]) - || input.peek(Token![^]) - || input.peek(Token![>]) - || input.peek(Token![<=]) - || input.peek(Token![!=]) - || input.peek(Token![-=]) - || input.peek(Token![*=]) - || input.peek(Token![&=]) - || input.peek(Token![|=]) - || input.peek(Token![<<=]) - || input.peek(Token![as])) - { - Ok(None) - } else { - let end = parse_binop_rhs(input, allow_struct, Precedence::Range)?; - Ok(Some(end)) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for RangeLimits { - fn parse(input: ParseStream) -> Result<Self> { - let lookahead = input.lookahead1(); - let dot_dot = lookahead.peek(Token![..]); - let dot_dot_eq = dot_dot && lookahead.peek(Token![..=]); - let dot_dot_dot = dot_dot && input.peek(Token![...]); - if dot_dot_eq { - input.parse().map(RangeLimits::Closed) - } else if dot_dot && !dot_dot_dot { - input.parse().map(RangeLimits::HalfOpen) - } else { - Err(lookahead.error()) - } - } - } - - #[cfg(feature = "full")] - impl RangeLimits { - pub(crate) fn parse_obsolete(input: ParseStream) -> Result<Self> { - let lookahead = input.lookahead1(); - let dot_dot = lookahead.peek(Token![..]); - let dot_dot_eq = dot_dot && lookahead.peek(Token![..=]); - let dot_dot_dot = dot_dot && input.peek(Token![...]); - if dot_dot_eq { - input.parse().map(RangeLimits::Closed) - } else if dot_dot_dot { - let dot3: Token![...] = input.parse()?; - Ok(RangeLimits::Closed(Token![..=](dot3.spans))) - } else if dot_dot { - input.parse().map(RangeLimits::HalfOpen) - } else { - Err(lookahead.error()) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ExprPath { - fn parse(input: ParseStream) -> Result<Self> { - #[cfg(not(feature = "full"))] - let attrs = Vec::new(); - #[cfg(feature = "full")] - let attrs = input.call(Attribute::parse_outer)?; - - let expr_style = true; - let (qself, path) = path::parsing::qpath(input, expr_style)?; - - Ok(ExprPath { attrs, qself, path }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Member { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Ident) { - input.parse().map(Member::Named) - } else if input.peek(LitInt) { - input.parse().map(Member::Unnamed) - } else { - Err(input.error("expected identifier or integer")) - } - } - } - - #[cfg(feature = "full")] - impl Arm { - pub(crate) fn parse_multiple(input: ParseStream) -> Result<Vec<Self>> { - let mut arms = Vec::new(); - while !input.is_empty() { - arms.push(input.call(Arm::parse)?); - } - Ok(arms) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Arm { - fn parse(input: ParseStream) -> Result<Arm> { - let requires_comma; - Ok(Arm { - attrs: input.call(Attribute::parse_outer)?, - pat: Pat::parse_multi_with_leading_vert(input)?, - guard: { - if input.peek(Token![if]) { - let if_token: Token![if] = input.parse()?; - let guard: Expr = input.parse()?; - Some((if_token, Box::new(guard))) - } else { - None - } - }, - fat_arrow_token: input.parse()?, - body: { - let body = Expr::parse_with_earlier_boundary_rule(input)?; - requires_comma = classify::requires_comma_to_be_match_arm(&body); - Box::new(body) - }, - comma: { - if requires_comma && !input.is_empty() { - Some(input.parse()?) - } else { - input.parse()? - } - }, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Index { - fn parse(input: ParseStream) -> Result<Self> { - let lit: LitInt = input.parse()?; - if lit.suffix().is_empty() { - Ok(Index { - index: lit - .base10_digits() - .parse() - .map_err(|err| Error::new(lit.span(), err))?, - span: lit.span(), - }) - } else { - Err(Error::new(lit.span(), "expected unsuffixed integer")) - } - } - } - - fn multi_index(e: &mut Expr, dot_token: &mut Token![.], float: LitFloat) -> Result<bool> { - let float_token = float.token(); - let float_span = float_token.span(); - let mut float_repr = float_token.to_string(); - let trailing_dot = float_repr.ends_with('.'); - if trailing_dot { - float_repr.truncate(float_repr.len() - 1); - } - - let mut offset = 0; - for part in float_repr.split('.') { - let mut index: Index = - crate::parse_str(part).map_err(|err| Error::new(float_span, err))?; - let part_end = offset + part.len(); - index.span = float_token.subspan(offset..part_end).unwrap_or(float_span); - - let base = mem::replace(e, Expr::PLACEHOLDER); - *e = Expr::Field(ExprField { - attrs: Vec::new(), - base: Box::new(base), - dot_token: Token![.](dot_token.span), - member: Member::Unnamed(index), - }); - - let dot_span = float_token.subspan(part_end..part_end + 1).unwrap_or(float_span); - *dot_token = Token![.](dot_span); - offset = part_end + 1; - } - - Ok(!trailing_dot) - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for PointerMutability { - fn parse(input: ParseStream) -> Result<Self> { - let lookahead = input.lookahead1(); - if lookahead.peek(Token![const]) { - Ok(PointerMutability::Const(input.parse()?)) - } else if lookahead.peek(Token![mut]) { - Ok(PointerMutability::Mut(input.parse()?)) - } else { - Err(lookahead.error()) - } - } - } - - fn check_cast(input: ParseStream) -> Result<()> { - let kind = if input.peek(Token![.]) && !input.peek(Token![..]) { - if input.peek2(Token![await]) { - "`.await`" - } else if input.peek2(Ident) && (input.peek3(token::Paren) || input.peek3(Token![::])) { - "a method call" - } else { - "a field access" - } - } else if input.peek(Token![?]) { - "`?`" - } else if input.peek(token::Bracket) { - "indexing" - } else if input.peek(token::Paren) { - "a function call" - } else { - return Ok(()); - }; - let msg = format!("casts cannot be followed by {}", kind); - Err(input.error(msg)) - } -} - -#[cfg(feature = "printing")] -pub(crate) mod printing { - use crate::attr::Attribute; - #[cfg(feature = "full")] - use crate::attr::FilterAttrs; - #[cfg(feature = "full")] - use crate::classify; - #[cfg(feature = "full")] - use crate::expr::{ - Arm, ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, - ExprConst, ExprContinue, ExprForLoop, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch, - ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprUnsafe, - ExprWhile, ExprYield, Label, PointerMutability, RangeLimits, - }; - use crate::expr::{ - Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprGroup, ExprIndex, ExprLit, ExprMacro, - ExprMethodCall, ExprParen, ExprPath, ExprReference, ExprStruct, ExprTuple, ExprUnary, - FieldValue, Index, Member, - }; - use crate::fixup::FixupContext; - use crate::op::BinOp; - use crate::path; - use crate::path::printing::PathStyle; - use crate::precedence::Precedence; - use crate::token; - #[cfg(feature = "full")] - use crate::ty::ReturnType; - use proc_macro2::{Literal, Span, TokenStream}; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg(feature = "full")] - pub(crate) fn outer_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) { - tokens.append_all(attrs.outer()); - } - - #[cfg(feature = "full")] - fn inner_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) { - tokens.append_all(attrs.inner()); - } - - #[cfg(not(feature = "full"))] - pub(crate) fn outer_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {} - - pub(crate) fn print_subexpression( - expr: &Expr, - needs_group: bool, - tokens: &mut TokenStream, - mut fixup: FixupContext, - ) { - if needs_group { - // If we are surrounding the whole cond in parentheses, such as: - // - // if (return Struct {}) {} - // - // then there is no need for parenthesizing the individual struct - // expressions within. On the other hand if the whole cond is not - // parenthesized, then print_expr must parenthesize exterior struct - // literals. - // - // if x == (Struct {}) {} - // - fixup = FixupContext::NONE; - } - - let do_print_expr = |tokens: &mut TokenStream| print_expr(expr, tokens, fixup); - - if needs_group { - token::Paren::default().surround(tokens, do_print_expr); - } else { - do_print_expr(tokens); - } - } - - pub(crate) fn print_expr(expr: &Expr, tokens: &mut TokenStream, mut fixup: FixupContext) { - #[cfg(feature = "full")] - let needs_group = fixup.parenthesize(expr); - #[cfg(not(feature = "full"))] - let needs_group = false; - - if needs_group { - fixup = FixupContext::NONE; - } - - let do_print_expr = |tokens: &mut TokenStream| match expr { - #[cfg(feature = "full")] - Expr::Array(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Assign(e) => print_expr_assign(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Async(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Await(e) => print_expr_await(e, tokens, fixup), - Expr::Binary(e) => print_expr_binary(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Block(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Break(e) => print_expr_break(e, tokens, fixup), - Expr::Call(e) => print_expr_call(e, tokens, fixup), - Expr::Cast(e) => print_expr_cast(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Closure(e) => print_expr_closure(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Const(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Continue(e) => e.to_tokens(tokens), - Expr::Field(e) => print_expr_field(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::ForLoop(e) => e.to_tokens(tokens), - Expr::Group(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::If(e) => e.to_tokens(tokens), - Expr::Index(e) => print_expr_index(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Infer(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Let(e) => print_expr_let(e, tokens, fixup), - Expr::Lit(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Loop(e) => e.to_tokens(tokens), - Expr::Macro(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Match(e) => e.to_tokens(tokens), - Expr::MethodCall(e) => print_expr_method_call(e, tokens, fixup), - Expr::Paren(e) => e.to_tokens(tokens), - Expr::Path(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Range(e) => print_expr_range(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::RawAddr(e) => print_expr_raw_addr(e, tokens, fixup), - Expr::Reference(e) => print_expr_reference(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Repeat(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Return(e) => print_expr_return(e, tokens, fixup), - Expr::Struct(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Try(e) => print_expr_try(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::TryBlock(e) => e.to_tokens(tokens), - Expr::Tuple(e) => e.to_tokens(tokens), - Expr::Unary(e) => print_expr_unary(e, tokens, fixup), - #[cfg(feature = "full")] - Expr::Unsafe(e) => e.to_tokens(tokens), - Expr::Verbatim(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::While(e) => e.to_tokens(tokens), - #[cfg(feature = "full")] - Expr::Yield(e) => print_expr_yield(e, tokens, fixup), - - #[cfg(not(feature = "full"))] - _ => unreachable!(), - }; - - if needs_group { - token::Paren::default().surround(tokens, do_print_expr); - } else { - do_print_expr(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprArray { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.bracket_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprAssign { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_assign(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_assign(e: &ExprAssign, tokens: &mut TokenStream, mut fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - - let needs_group = !e.attrs.is_empty(); - if needs_group { - fixup = FixupContext::NONE; - } - - let do_print_expr = |tokens: &mut TokenStream| { - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( - &e.left, - false, - false, - Precedence::Assign, - ); - print_subexpression(&e.left, left_prec <= Precedence::Range, tokens, left_fixup); - e.eq_token.to_tokens(tokens); - print_expr( - &e.right, - tokens, - fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign), - ); - }; - - if needs_group { - token::Paren::default().surround(tokens, do_print_expr); - } else { - do_print_expr(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprAsync { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.async_token.to_tokens(tokens); - self.capture.to_tokens(tokens); - self.block.to_tokens(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprAwait { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_await(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_await(e: &ExprAwait, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&e.base); - print_subexpression(&e.base, left_prec < Precedence::Unambiguous, tokens, left_fixup); - e.dot_token.to_tokens(tokens); - e.await_token.to_tokens(tokens); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprBinary { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_binary(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_binary(e: &ExprBinary, tokens: &mut TokenStream, mut fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - - let needs_group = !e.attrs.is_empty(); - if needs_group { - fixup = FixupContext::NONE; - } - - let do_print_expr = |tokens: &mut TokenStream| { - let binop_prec = Precedence::of_binop(&e.op); - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( - &e.left, - #[cfg(feature = "full")] - match &e.op { - BinOp::Sub(_) - | BinOp::Mul(_) - | BinOp::And(_) - | BinOp::Or(_) - | BinOp::BitAnd(_) - | BinOp::BitOr(_) - | BinOp::Shl(_) - | BinOp::Lt(_) => true, - _ => false, - }, - match &e.op { - BinOp::Shl(_) | BinOp::Lt(_) => true, - _ => false, - }, - #[cfg(feature = "full")] - binop_prec, - ); - let left_needs_group = match binop_prec { - Precedence::Assign => left_prec <= Precedence::Range, - Precedence::Compare => left_prec <= binop_prec, - _ => left_prec < binop_prec, - }; - - let right_fixup = fixup.rightmost_subexpression_fixup( - #[cfg(feature = "full")] - false, - #[cfg(feature = "full")] - false, - #[cfg(feature = "full")] - binop_prec, - ); - let right_needs_group = binop_prec != Precedence::Assign - && right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec; - - print_subexpression(&e.left, left_needs_group, tokens, left_fixup); - e.op.to_tokens(tokens); - print_subexpression(&e.right, right_needs_group, tokens, right_fixup); - }; - - if needs_group { - token::Paren::default().surround(tokens, do_print_expr); - } else { - do_print_expr(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprBlock { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.label.to_tokens(tokens); - self.block.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - tokens.append_all(&self.block.stmts); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprBreak { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_break(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_break(e: &ExprBreak, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.break_token.to_tokens(tokens); - e.label.to_tokens(tokens); - if let Some(value) = &e.expr { - print_subexpression( - value, - // Parenthesize `break 'inner: loop { break 'inner 1 } + 1` - // ^---------------------------------^ - e.label.is_none() && classify::expr_leading_label(value), - tokens, - fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump), - ); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprCall { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_call(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_call(e: &ExprCall, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( - &e.func, - #[cfg(feature = "full")] - true, - false, - #[cfg(feature = "full")] - Precedence::Unambiguous, - ); - let needs_group = if let Expr::Field(func) = &*e.func { - func.member.is_named() - } else { - left_prec < Precedence::Unambiguous - }; - print_subexpression(&e.func, needs_group, tokens, left_fixup); - - e.paren_token.surround(tokens, |tokens| { - e.args.to_tokens(tokens); - }); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprCast { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_cast(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_cast(e: &ExprCast, tokens: &mut TokenStream, mut fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - - let needs_group = !e.attrs.is_empty(); - if needs_group { - fixup = FixupContext::NONE; - } - - let do_print_expr = |tokens: &mut TokenStream| { - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( - &e.expr, - #[cfg(feature = "full")] - false, - false, - #[cfg(feature = "full")] - Precedence::Cast, - ); - print_subexpression(&e.expr, left_prec < Precedence::Cast, tokens, left_fixup); - e.as_token.to_tokens(tokens); - e.ty.to_tokens(tokens); - }; - - if needs_group { - token::Paren::default().surround(tokens, do_print_expr); - } else { - do_print_expr(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprClosure { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_closure(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_closure(e: &ExprClosure, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.lifetimes.to_tokens(tokens); - e.constness.to_tokens(tokens); - e.movability.to_tokens(tokens); - e.asyncness.to_tokens(tokens); - e.capture.to_tokens(tokens); - e.or1_token.to_tokens(tokens); - e.inputs.to_tokens(tokens); - e.or2_token.to_tokens(tokens); - e.output.to_tokens(tokens); - if matches!(e.output, ReturnType::Default) - || matches!(&*e.body, Expr::Block(body) if body.attrs.is_empty() && body.label.is_none()) - { - print_expr( - &e.body, - tokens, - fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump), - ); - } else { - token::Brace::default().surround(tokens, |tokens| { - print_expr(&e.body, tokens, FixupContext::new_stmt()); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprConst { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.const_token.to_tokens(tokens); - self.block.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - tokens.append_all(&self.block.stmts); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprContinue { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.continue_token.to_tokens(tokens); - self.label.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprField { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_field(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_field(e: &ExprField, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&e.base); - print_subexpression(&e.base, left_prec < Precedence::Unambiguous, tokens, left_fixup); - e.dot_token.to_tokens(tokens); - e.member.to_tokens(tokens); - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprForLoop { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.label.to_tokens(tokens); - self.for_token.to_tokens(tokens); - self.pat.to_tokens(tokens); - self.in_token.to_tokens(tokens); - print_expr(&self.expr, tokens, FixupContext::new_condition()); - self.body.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - tokens.append_all(&self.body.stmts); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprGroup { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.group_token.surround(tokens, |tokens| { - self.expr.to_tokens(tokens); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprIf { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - - let mut expr = self; - loop { - expr.if_token.to_tokens(tokens); - print_expr(&expr.cond, tokens, FixupContext::new_condition()); - expr.then_branch.to_tokens(tokens); - - let (else_token, else_) = match &expr.else_branch { - Some(else_branch) => else_branch, - None => break, - }; - - else_token.to_tokens(tokens); - match &**else_ { - Expr::If(next) => { - expr = next; - } - Expr::Block(last) => { - last.to_tokens(tokens); - break; - } - // If this is not one of the valid expressions to exist in - // an else clause, wrap it in a block. - other => { - token::Brace::default().surround(tokens, |tokens| { - print_expr(other, tokens, FixupContext::new_stmt()); - }); - break; - } - } - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprIndex { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_index(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_index(e: &ExprIndex, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( - &e.expr, - #[cfg(feature = "full")] - true, - false, - #[cfg(feature = "full")] - Precedence::Unambiguous, - ); - print_subexpression(&e.expr, left_prec < Precedence::Unambiguous, tokens, left_fixup); - e.bracket_token.surround(tokens, |tokens| { - e.index.to_tokens(tokens); - }); - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprInfer { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.underscore_token.to_tokens(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprLet { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_let(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_let(e: &ExprLet, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.let_token.to_tokens(tokens); - e.pat.to_tokens(tokens); - e.eq_token.to_tokens(tokens); - let (right_prec, right_fixup) = fixup.rightmost_subexpression(&e.expr, Precedence::Let); - print_subexpression(&e.expr, right_prec < Precedence::Let, tokens, right_fixup); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprLit { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.lit.to_tokens(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprLoop { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.label.to_tokens(tokens); - self.loop_token.to_tokens(tokens); - self.body.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - tokens.append_all(&self.body.stmts); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.mac.to_tokens(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprMatch { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.match_token.to_tokens(tokens); - print_expr(&self.expr, tokens, FixupContext::new_condition()); - self.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - for (i, arm) in self.arms.iter().enumerate() { - arm.to_tokens(tokens); - // Ensure that we have a comma after a non-block arm, except - // for the last one. - let is_last = i == self.arms.len() - 1; - if !is_last - && classify::requires_comma_to_be_match_arm(&arm.body) - && arm.comma.is_none() - { - <Token![,]>::default().to_tokens(tokens); - } - } - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprMethodCall { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_method_call(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_method_call(e: &ExprMethodCall, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&e.receiver); - print_subexpression(&e.receiver, left_prec < Precedence::Unambiguous, tokens, left_fixup); - e.dot_token.to_tokens(tokens); - e.method.to_tokens(tokens); - if let Some(turbofish) = &e.turbofish { - path::printing::print_angle_bracketed_generic_arguments( - tokens, - turbofish, - PathStyle::Expr, - ); - } - e.paren_token.surround(tokens, |tokens| { - e.args.to_tokens(tokens); - }); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprParen { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.paren_token.surround(tokens, |tokens| { - self.expr.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprPath { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprRange { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_range(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_range(e: &ExprRange, tokens: &mut TokenStream, mut fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - - let needs_group = !e.attrs.is_empty(); - if needs_group { - fixup = FixupContext::NONE; - } - - let do_print_expr = |tokens: &mut TokenStream| { - if let Some(start) = &e.start { - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( - start, - true, - false, - Precedence::Range, - ); - print_subexpression(start, left_prec <= Precedence::Range, tokens, left_fixup); - } - e.limits.to_tokens(tokens); - if let Some(end) = &e.end { - let right_fixup = - fixup.rightmost_subexpression_fixup(false, true, Precedence::Range); - let right_prec = right_fixup.rightmost_subexpression_precedence(end); - print_subexpression(end, right_prec <= Precedence::Range, tokens, right_fixup); - } - }; - - if needs_group { - token::Paren::default().surround(tokens, do_print_expr); - } else { - do_print_expr(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprRawAddr { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_raw_addr(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_raw_addr(e: &ExprRawAddr, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.and_token.to_tokens(tokens); - e.raw.to_tokens(tokens); - e.mutability.to_tokens(tokens); - let (right_prec, right_fixup) = fixup.rightmost_subexpression(&e.expr, Precedence::Prefix); - print_subexpression(&e.expr, right_prec < Precedence::Prefix, tokens, right_fixup); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprReference { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_reference(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_reference(e: &ExprReference, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.and_token.to_tokens(tokens); - e.mutability.to_tokens(tokens); - let (right_prec, right_fixup) = fixup.rightmost_subexpression( - &e.expr, - #[cfg(feature = "full")] - Precedence::Prefix, - ); - print_subexpression(&e.expr, right_prec < Precedence::Prefix, tokens, right_fixup); - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprRepeat { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.bracket_token.surround(tokens, |tokens| { - self.expr.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - self.len.to_tokens(tokens); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprReturn { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_return(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_return(e: &ExprReturn, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.return_token.to_tokens(tokens); - if let Some(expr) = &e.expr { - print_expr( - expr, - tokens, - fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump), - ); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprStruct { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr); - self.brace_token.surround(tokens, |tokens| { - self.fields.to_tokens(tokens); - if let Some(dot2_token) = &self.dot2_token { - dot2_token.to_tokens(tokens); - } else if self.rest.is_some() { - Token![..](Span::call_site()).to_tokens(tokens); - } - self.rest.to_tokens(tokens); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprTry { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_try(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_try(e: &ExprTry, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&e.expr); - print_subexpression(&e.expr, left_prec < Precedence::Unambiguous, tokens, left_fixup); - e.question_token.to_tokens(tokens); - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprTryBlock { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.try_token.to_tokens(tokens); - self.block.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprTuple { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.paren_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); - // If we only have one argument, we need a trailing comma to - // distinguish ExprTuple from ExprParen. - if self.elems.len() == 1 && !self.elems.trailing_punct() { - <Token![,]>::default().to_tokens(tokens); - } - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprUnary { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_unary(self, tokens, FixupContext::NONE); - } - } - - fn print_expr_unary(e: &ExprUnary, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.op.to_tokens(tokens); - let (right_prec, right_fixup) = fixup.rightmost_subexpression( - &e.expr, - #[cfg(feature = "full")] - Precedence::Prefix, - ); - print_subexpression(&e.expr, right_prec < Precedence::Prefix, tokens, right_fixup); - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprUnsafe { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.unsafe_token.to_tokens(tokens); - self.block.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - tokens.append_all(&self.block.stmts); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprWhile { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.label.to_tokens(tokens); - self.while_token.to_tokens(tokens); - print_expr(&self.cond, tokens, FixupContext::new_condition()); - self.body.brace_token.surround(tokens, |tokens| { - inner_attrs_to_tokens(&self.attrs, tokens); - tokens.append_all(&self.body.stmts); - }); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ExprYield { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_yield(self, tokens, FixupContext::NONE); - } - } - - #[cfg(feature = "full")] - fn print_expr_yield(e: &ExprYield, tokens: &mut TokenStream, fixup: FixupContext) { - outer_attrs_to_tokens(&e.attrs, tokens); - e.yield_token.to_tokens(tokens); - if let Some(expr) = &e.expr { - print_expr( - expr, - tokens, - fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump), - ); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Arm { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(&self.attrs); - self.pat.to_tokens(tokens); - if let Some((if_token, guard)) = &self.guard { - if_token.to_tokens(tokens); - guard.to_tokens(tokens); - } - self.fat_arrow_token.to_tokens(tokens); - print_expr(&self.body, tokens, FixupContext::new_match_arm()); - self.comma.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for FieldValue { - fn to_tokens(&self, tokens: &mut TokenStream) { - outer_attrs_to_tokens(&self.attrs, tokens); - self.member.to_tokens(tokens); - if let Some(colon_token) = &self.colon_token { - colon_token.to_tokens(tokens); - self.expr.to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Index { - fn to_tokens(&self, tokens: &mut TokenStream) { - let mut lit = Literal::i64_unsuffixed(i64::from(self.index)); - lit.set_span(self.span); - tokens.append(lit); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Label { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.name.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Member { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Member::Named(ident) => ident.to_tokens(tokens), - Member::Unnamed(index) => index.to_tokens(tokens), - } - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for RangeLimits { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - RangeLimits::HalfOpen(t) => t.to_tokens(tokens), - RangeLimits::Closed(t) => t.to_tokens(tokens), - } - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PointerMutability { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - PointerMutability::Const(const_token) => const_token.to_tokens(tokens), - PointerMutability::Mut(mut_token) => mut_token.to_tokens(tokens), - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/ext.rs b/deps/crates/vendor/syn-v2/src/ext.rs deleted file mode 100644 index 212e22398d5a..000000000000 --- a/deps/crates/vendor/syn-v2/src/ext.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Extension traits to provide parsing methods on foreign types. - -#[cfg(feature = "parsing")] -use crate::buffer::Cursor; -#[cfg(feature = "parsing")] -use crate::error::Result; -#[cfg(feature = "parsing")] -use crate::parse::ParseStream; -#[cfg(feature = "parsing")] -use crate::parse::Peek; -#[cfg(feature = "parsing")] -use crate::sealed::lookahead; -#[cfg(feature = "parsing")] -use crate::token::CustomToken; -use alloc::string::ToString; -use core::iter; -use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream, TokenTree}; - -/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro. -/// -/// This trait is sealed and cannot be implemented for types outside of Syn. It -/// is implemented only for `proc_macro2::Ident`. -pub trait IdentExt: Sized + private::Sealed { - /// Parses any identifier including keywords. - /// - /// This is useful when parsing macro input which allows Rust keywords as - /// identifiers. - /// - /// # Example - /// - /// ``` - /// use syn::{Error, Ident, Result, Token}; - /// use syn::ext::IdentExt; - /// use syn::parse::ParseStream; - /// - /// mod kw { - /// syn::custom_keyword!(name); - /// } - /// - /// // Parses input that looks like `name = NAME` where `NAME` can be - /// // any identifier. - /// // - /// // Examples: - /// // - /// // name = anything - /// // name = impl - /// fn parse_dsl(input: ParseStream) -> Result<Ident> { - /// input.parse::<kw::name>()?; - /// input.parse::<Token![=]>()?; - /// let name = input.call(Ident::parse_any)?; - /// Ok(name) - /// } - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - fn parse_any(input: ParseStream) -> Result<Self>; - - /// Peeks any identifier including keywords. Usage: - /// `input.peek(Ident::peek_any)` - /// - /// This is different from `input.peek(Ident)` which only returns true in - /// the case of an ident which is not a Rust keyword. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - #[allow(non_upper_case_globals)] - const peek_any: private::PeekFn = private::PeekFn; - - /// Strips the raw marker `r#`, if any, from the beginning of an ident. - /// - /// - unraw(`x`) = `x` - /// - unraw(`move`) = `move` - /// - unraw(`r#move`) = `move` - /// - /// # Example - /// - /// In the case of interop with other languages like Python that have a - /// different set of keywords than Rust, we might come across macro input - /// that involves raw identifiers to refer to ordinary variables in the - /// other language with a name that happens to be a Rust keyword. - /// - /// The function below appends an identifier from the caller's input onto a - /// fixed prefix. Without using `unraw()`, this would tend to produce - /// invalid identifiers like `__pyo3_get_r#move`. - /// - /// ``` - /// use proc_macro2::Span; - /// use syn::Ident; - /// use syn::ext::IdentExt; - /// - /// fn ident_for_getter(variable: &Ident) -> Ident { - /// let getter = format!("__pyo3_get_{}", variable.unraw()); - /// Ident::new(&getter, Span::call_site()) - /// } - /// ``` - fn unraw(&self) -> Ident; -} - -impl IdentExt for Ident { - #[cfg(feature = "parsing")] - fn parse_any(input: ParseStream) -> Result<Self> { - input.step(|cursor| match cursor.ident() { - Some((ident, rest)) => Ok((ident, rest)), - None => Err(cursor.error("expected ident")), - }) - } - - fn unraw(&self) -> Ident { - let string = self.to_string(); - if let Some(string) = string.strip_prefix("r#") { - Ident::new(string, self.span()) - } else { - self.clone() - } - } -} - -#[cfg(feature = "parsing")] -impl Peek for private::PeekFn { - type Token = private::IdentAny; -} - -#[cfg(feature = "parsing")] -impl CustomToken for private::IdentAny { - fn peek(cursor: Cursor) -> bool { - cursor.ident().is_some() - } - - fn display() -> &'static str { - "identifier" - } -} - -#[cfg(feature = "parsing")] -impl lookahead::Sealed for private::PeekFn {} - -pub(crate) trait TokenStreamExt { - fn append(&mut self, token: TokenTree); -} - -impl TokenStreamExt for TokenStream { - fn append(&mut self, token: TokenTree) { - self.extend(iter::once(token)); - } -} - -pub(crate) trait PunctExt { - fn new_spanned(ch: char, spacing: Spacing, span: Span) -> Self; -} - -impl PunctExt for Punct { - fn new_spanned(ch: char, spacing: Spacing, span: Span) -> Self { - let mut punct = Punct::new(ch, spacing); - punct.set_span(span); - punct - } -} - -mod private { - use proc_macro2::Ident; - - pub trait Sealed {} - - impl Sealed for Ident {} - - #[cfg(feature = "parsing")] - pub struct PeekFn; - - #[cfg(feature = "parsing")] - pub struct IdentAny; - - #[cfg(feature = "parsing")] - impl Copy for PeekFn {} - - #[cfg(feature = "parsing")] - impl Clone for PeekFn { - fn clone(&self) -> Self { - *self - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/file.rs b/deps/crates/vendor/syn-v2/src/file.rs deleted file mode 100644 index dbb1bcb4fff9..000000000000 --- a/deps/crates/vendor/syn-v2/src/file.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::attr::Attribute; -use crate::item::Item; -use alloc::string::String; -use alloc::vec::Vec; - -ast_struct! { - /// A complete file of Rust source code. - /// - /// Typically `File` objects are created with [`parse_file`]. - /// - /// [`parse_file`]: crate::parse_file - /// - /// # Example - /// - /// Parse a Rust source file into a `syn::File` and print out a debug - /// representation of the syntax tree. - /// - /// ``` - /// use std::env; - /// use std::fs; - /// use std::process; - /// - /// fn main() { - /// # } - /// # - /// # fn fake_main() { - /// let mut args = env::args(); - /// let _ = args.next(); // executable name - /// - /// let filename = match (args.next(), args.next()) { - /// (Some(filename), None) => filename, - /// _ => { - /// eprintln!("Usage: dump-syntax path/to/filename.rs"); - /// process::exit(1); - /// } - /// }; - /// - /// let src = fs::read_to_string(&filename).expect("unable to read file"); - /// let syntax = syn::parse_file(&src).expect("unable to parse file"); - /// - /// // Debug impl is available if Syn is built with "extra-traits" feature. - /// println!("{:#?}", syntax); - /// } - /// ``` - /// - /// Running with its own source code as input, this program prints output - /// that begins with: - /// - /// ```text - /// File { - /// shebang: None, - /// attrs: [], - /// items: [ - /// Use( - /// ItemUse { - /// attrs: [], - /// vis: Inherited, - /// use_token: Use, - /// leading_colon: None, - /// tree: Path( - /// UsePath { - /// ident: Ident( - /// std, - /// ), - /// colon2_token: Colon2, - /// tree: Name( - /// UseName { - /// ident: Ident( - /// env, - /// ), - /// }, - /// ), - /// }, - /// ), - /// semi_token: Semi, - /// }, - /// ), - /// ... - /// ``` - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct File { - pub shebang: Option<String>, - pub attrs: Vec<Attribute>, - pub items: Vec<Item>, - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - use crate::error::Result; - use crate::file::File; - use crate::parse::{Parse, ParseStream}; - use alloc::vec::Vec; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for File { - fn parse(input: ParseStream) -> Result<Self> { - Ok(File { - shebang: None, - attrs: input.call(Attribute::parse_inner)?, - items: { - let mut items = Vec::new(); - while !input.is_empty() { - items.push(input.parse()?); - } - items - }, - }) - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::attr::FilterAttrs; - use crate::file::File; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for File { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&self.items); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/fixup.rs b/deps/crates/vendor/syn-v2/src/fixup.rs deleted file mode 100644 index 6d2c3092d548..000000000000 --- a/deps/crates/vendor/syn-v2/src/fixup.rs +++ /dev/null @@ -1,773 +0,0 @@ -use crate::classify; -use crate::expr::Expr; -#[cfg(feature = "full")] -use crate::expr::{ - ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield, -}; -use crate::precedence::Precedence; -#[cfg(feature = "full")] -use crate::ty::ReturnType; - -pub(crate) struct FixupContext { - #[cfg(feature = "full")] - previous_operator: Precedence, - #[cfg(feature = "full")] - next_operator: Precedence, - - // Print expression such that it can be parsed back as a statement - // consisting of the original expression. - // - // The effect of this is for binary operators in statement position to set - // `leftmost_subexpression_in_stmt` when printing their left-hand operand. - // - // (match x {}) - 1; // match needs parens when LHS of binary operator - // - // match x {}; // not when its own statement - // - #[cfg(feature = "full")] - stmt: bool, - - // This is the difference between: - // - // (match x {}) - 1; // subexpression needs parens - // - // let _ = match x {} - 1; // no parens - // - // There are 3 distinguishable contexts in which `print_expr` might be - // called with the expression `$match` as its argument, where `$match` - // represents an expression of kind `ExprKind::Match`: - // - // - stmt=false leftmost_subexpression_in_stmt=false - // - // Example: `let _ = $match - 1;` - // - // No parentheses required. - // - // - stmt=false leftmost_subexpression_in_stmt=true - // - // Example: `$match - 1;` - // - // Must parenthesize `($match)`, otherwise parsing back the output as a - // statement would terminate the statement after the closing brace of - // the match, parsing `-1;` as a separate statement. - // - // - stmt=true leftmost_subexpression_in_stmt=false - // - // Example: `$match;` - // - // No parentheses required. - #[cfg(feature = "full")] - leftmost_subexpression_in_stmt: bool, - - // Print expression such that it can be parsed as a match arm. - // - // This is almost equivalent to `stmt`, but the grammar diverges a tiny bit - // between statements and match arms when it comes to braced macro calls. - // Macro calls with brace delimiter terminate a statement without a - // semicolon, but do not terminate a match-arm without comma. - // - // m! {} - 1; // two statements: a macro call followed by -1 literal - // - // match () { - // _ => m! {} - 1, // binary subtraction operator - // } - // - #[cfg(feature = "full")] - match_arm: bool, - - // This is almost equivalent to `leftmost_subexpression_in_stmt`, other than - // for braced macro calls. - // - // If we have `m! {} - 1` as an expression, the leftmost subexpression - // `m! {}` will need to be parenthesized in the statement case but not the - // match-arm case. - // - // (m! {}) - 1; // subexpression needs parens - // - // match () { - // _ => m! {} - 1, // no parens - // } - // - #[cfg(feature = "full")] - leftmost_subexpression_in_match_arm: bool, - - // This is the difference between: - // - // if let _ = (Struct {}) {} // needs parens - // - // match () { - // () if let _ = Struct {} => {} // no parens - // } - // - #[cfg(feature = "full")] - condition: bool, - - // This is the difference between: - // - // if break Struct {} == (break) {} // needs parens - // - // if break break == Struct {} {} // no parens - // - #[cfg(feature = "full")] - rightmost_subexpression_in_condition: bool, - - // This is the difference between: - // - // if break ({ x }).field + 1 {} needs parens - // - // if break 1 + { x }.field {} // no parens - // - #[cfg(feature = "full")] - leftmost_subexpression_in_optional_operand: bool, - - // This is the difference between: - // - // let _ = (return) - 1; // without paren, this would return -1 - // - // let _ = return + 1; // no paren because '+' cannot begin expr - // - #[cfg(feature = "full")] - next_operator_can_begin_expr: bool, - - // This is the difference between: - // - // let _ = 1 + return 1; // no parens if rightmost subexpression - // - // let _ = 1 + (return 1) + 1; // needs parens - // - #[cfg(feature = "full")] - next_operator_can_continue_expr: bool, - - // This is the difference between: - // - // let _ = x as u8 + T; - // - // let _ = (x as u8) < T; - // - // Without parens, the latter would want to parse `u8<T...` as a type. - next_operator_can_begin_generics: bool, -} - -impl FixupContext { - /// The default amount of fixing is minimal fixing. Fixups should be turned - /// on in a targeted fashion where needed. - pub const NONE: Self = FixupContext { - #[cfg(feature = "full")] - previous_operator: Precedence::MIN, - #[cfg(feature = "full")] - next_operator: Precedence::MIN, - #[cfg(feature = "full")] - stmt: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_stmt: false, - #[cfg(feature = "full")] - match_arm: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_match_arm: false, - #[cfg(feature = "full")] - condition: false, - #[cfg(feature = "full")] - rightmost_subexpression_in_condition: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_optional_operand: false, - #[cfg(feature = "full")] - next_operator_can_begin_expr: false, - #[cfg(feature = "full")] - next_operator_can_continue_expr: false, - next_operator_can_begin_generics: false, - }; - - /// Create the initial fixup for printing an expression in statement - /// position. - #[cfg(feature = "full")] - pub fn new_stmt() -> Self { - FixupContext { - stmt: true, - ..FixupContext::NONE - } - } - - /// Create the initial fixup for printing an expression as the right-hand - /// side of a match arm. - #[cfg(feature = "full")] - pub fn new_match_arm() -> Self { - FixupContext { - match_arm: true, - ..FixupContext::NONE - } - } - - /// Create the initial fixup for printing an expression as the "condition" - /// of an `if` or `while`. There are a few other positions which are - /// grammatically equivalent and also use this, such as the iterator - /// expression in `for` and the scrutinee in `match`. - #[cfg(feature = "full")] - pub fn new_condition() -> Self { - FixupContext { - condition: true, - rightmost_subexpression_in_condition: true, - ..FixupContext::NONE - } - } - - /// Transform this fixup into the one that should apply when printing the - /// leftmost subexpression of the current expression. - /// - /// The leftmost subexpression is any subexpression that has the same first - /// token as the current expression, but has a different last token. - /// - /// For example in `$a + $b` and `$a.method()`, the subexpression `$a` is a - /// leftmost subexpression. - /// - /// Not every expression has a leftmost subexpression. For example neither - /// `-$a` nor `[$a]` have one. - pub fn leftmost_subexpression_with_operator( - self, - expr: &Expr, - #[cfg(feature = "full")] next_operator_can_begin_expr: bool, - next_operator_can_begin_generics: bool, - #[cfg(feature = "full")] precedence: Precedence, - ) -> (Precedence, Self) { - let fixup = FixupContext { - #[cfg(feature = "full")] - next_operator: precedence, - #[cfg(feature = "full")] - stmt: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt, - #[cfg(feature = "full")] - match_arm: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_match_arm: self.match_arm - || self.leftmost_subexpression_in_match_arm, - #[cfg(feature = "full")] - rightmost_subexpression_in_condition: false, - #[cfg(feature = "full")] - next_operator_can_begin_expr, - #[cfg(feature = "full")] - next_operator_can_continue_expr: true, - next_operator_can_begin_generics, - ..self - }; - - (fixup.leftmost_subexpression_precedence(expr), fixup) - } - - /// Transform this fixup into the one that should apply when printing a - /// leftmost subexpression followed by a `.` or `?` token, which confer - /// different statement boundary rules compared to other leftmost - /// subexpressions. - pub fn leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self) { - let fixup = FixupContext { - #[cfg(feature = "full")] - next_operator: Precedence::Unambiguous, - #[cfg(feature = "full")] - stmt: self.stmt || self.leftmost_subexpression_in_stmt, - #[cfg(feature = "full")] - leftmost_subexpression_in_stmt: false, - #[cfg(feature = "full")] - match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, - #[cfg(feature = "full")] - leftmost_subexpression_in_match_arm: false, - #[cfg(feature = "full")] - rightmost_subexpression_in_condition: false, - #[cfg(feature = "full")] - next_operator_can_begin_expr: false, - #[cfg(feature = "full")] - next_operator_can_continue_expr: true, - next_operator_can_begin_generics: false, - ..self - }; - - (fixup.leftmost_subexpression_precedence(expr), fixup) - } - - fn leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence { - #[cfg(feature = "full")] - if !self.next_operator_can_begin_expr || self.next_operator == Precedence::Range { - if let Scan::Bailout = scan_right(expr, self, Precedence::MIN, 0, 0) { - if scan_left(expr, self) { - return Precedence::Unambiguous; - } - } - } - - self.precedence(expr) - } - - /// Transform this fixup into the one that should apply when printing the - /// rightmost subexpression of the current expression. - /// - /// The rightmost subexpression is any subexpression that has a different - /// first token than the current expression, but has the same last token. - /// - /// For example in `$a + $b` and `-$b`, the subexpression `$b` is a - /// rightmost subexpression. - /// - /// Not every expression has a rightmost subexpression. For example neither - /// `[$b]` nor `$a.f($b)` have one. - pub fn rightmost_subexpression( - self, - expr: &Expr, - #[cfg(feature = "full")] precedence: Precedence, - ) -> (Precedence, Self) { - let fixup = self.rightmost_subexpression_fixup( - #[cfg(feature = "full")] - false, - #[cfg(feature = "full")] - false, - #[cfg(feature = "full")] - precedence, - ); - (fixup.rightmost_subexpression_precedence(expr), fixup) - } - - pub fn rightmost_subexpression_fixup( - self, - #[cfg(feature = "full")] reset_allow_struct: bool, - #[cfg(feature = "full")] optional_operand: bool, - #[cfg(feature = "full")] precedence: Precedence, - ) -> Self { - FixupContext { - #[cfg(feature = "full")] - previous_operator: precedence, - #[cfg(feature = "full")] - stmt: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_stmt: false, - #[cfg(feature = "full")] - match_arm: false, - #[cfg(feature = "full")] - leftmost_subexpression_in_match_arm: false, - #[cfg(feature = "full")] - condition: self.condition && !reset_allow_struct, - #[cfg(feature = "full")] - leftmost_subexpression_in_optional_operand: self.condition && optional_operand, - ..self - } - } - - pub fn rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence { - let default_prec = self.precedence(expr); - - #[cfg(feature = "full")] - if match self.previous_operator { - Precedence::Assign | Precedence::Let | Precedence::Prefix => { - default_prec < self.previous_operator - } - _ => default_prec <= self.previous_operator, - } && match self.next_operator { - Precedence::Range | Precedence::Or | Precedence::And => true, - _ => !self.next_operator_can_begin_expr, - } { - if let Scan::Bailout | Scan::Fail = scan_right(expr, self, self.previous_operator, 1, 0) - { - if scan_left(expr, self) { - return Precedence::Prefix; - } - } - } - - default_prec - } - - /// Determine whether parentheses are needed around the given expression to - /// head off the early termination of a statement or condition. - #[cfg(feature = "full")] - pub fn parenthesize(self, expr: &Expr) -> bool { - (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr)) - || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_))) - || (self.leftmost_subexpression_in_match_arm - && !classify::requires_comma_to_be_match_arm(expr)) - || (self.condition && matches!(expr, Expr::Struct(_))) - || (self.rightmost_subexpression_in_condition - && matches!( - expr, - Expr::Return(ExprReturn { expr: None, .. }) - | Expr::Yield(ExprYield { expr: None, .. }) - )) - || (self.rightmost_subexpression_in_condition - && !self.condition - && matches!( - expr, - Expr::Break(ExprBreak { expr: None, .. }) - | Expr::Path(_) - | Expr::Range(ExprRange { end: None, .. }) - )) - || (self.leftmost_subexpression_in_optional_operand - && matches!(expr, Expr::Block(expr) if expr.attrs.is_empty() && expr.label.is_none())) - } - - /// Determines the effective precedence of a subexpression. Some expressions - /// have higher or lower precedence when adjacent to particular operators. - fn precedence(self, expr: &Expr) -> Precedence { - #[cfg(feature = "full")] - if self.next_operator_can_begin_expr { - // Decrease precedence of value-less jumps when followed by an - // operator that would otherwise get interpreted as beginning a - // value for the jump. - if let Expr::Break(ExprBreak { expr: None, .. }) - | Expr::Return(ExprReturn { expr: None, .. }) - | Expr::Yield(ExprYield { expr: None, .. }) = expr - { - return Precedence::Jump; - } - } - - #[cfg(feature = "full")] - if !self.next_operator_can_continue_expr { - match expr { - // Increase precedence of expressions that extend to the end of - // current statement or group. - Expr::Break(_) - | Expr::Closure(_) - | Expr::Let(_) - | Expr::Return(_) - | Expr::Yield(_) => { - return Precedence::Prefix; - } - Expr::Range(e) if e.start.is_none() => return Precedence::Prefix, - _ => {} - } - } - - if self.next_operator_can_begin_generics { - if let Expr::Cast(cast) = expr { - if classify::trailing_unparameterized_path(&cast.ty) { - return Precedence::MIN; - } - } - } - - Precedence::of(expr) - } -} - -impl Copy for FixupContext {} - -impl Clone for FixupContext { - fn clone(&self) -> Self { - *self - } -} - -#[cfg(feature = "full")] -enum Scan { - Fail, - Bailout, - Consume, -} - -#[cfg(feature = "full")] -impl Copy for Scan {} - -#[cfg(feature = "full")] -impl Clone for Scan { - fn clone(&self) -> Self { - *self - } -} - -#[cfg(feature = "full")] -impl PartialEq for Scan { - fn eq(&self, other: &Self) -> bool { - *self as u8 == *other as u8 - } -} - -#[cfg(feature = "full")] -fn scan_left(expr: &Expr, fixup: FixupContext) -> bool { - match expr { - Expr::Assign(_) => fixup.previous_operator <= Precedence::Assign, - Expr::Binary(e) => match Precedence::of_binop(&e.op) { - Precedence::Assign => fixup.previous_operator <= Precedence::Assign, - binop_prec => fixup.previous_operator < binop_prec, - }, - Expr::Cast(_) => fixup.previous_operator < Precedence::Cast, - Expr::Range(e) => e.start.is_none() || fixup.previous_operator < Precedence::Assign, - _ => true, - } -} - -#[cfg(feature = "full")] -fn scan_right( - expr: &Expr, - fixup: FixupContext, - precedence: Precedence, - fail_offset: u8, - bailout_offset: u8, -) -> Scan { - let consume_by_precedence = if match precedence { - Precedence::Assign | Precedence::Compare => precedence <= fixup.next_operator, - _ => precedence < fixup.next_operator, - } || fixup.next_operator == Precedence::MIN - { - Scan::Consume - } else { - Scan::Bailout - }; - if fixup.parenthesize(expr) { - return consume_by_precedence; - } - match expr { - Expr::Assign(e) if e.attrs.is_empty() => { - if match fixup.next_operator { - Precedence::Unambiguous => fail_offset >= 2, - _ => bailout_offset >= 1, - } { - return Scan::Consume; - } - let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign); - let scan = scan_right( - &e.right, - right_fixup, - Precedence::Assign, - match fixup.next_operator { - Precedence::Unambiguous => fail_offset, - _ => 1, - }, - 1, - ); - if let Scan::Bailout | Scan::Consume = scan { - Scan::Consume - } else if let Precedence::Unambiguous = fixup.next_operator { - Scan::Fail - } else { - Scan::Bailout - } - } - Expr::Binary(e) if e.attrs.is_empty() => { - if match fixup.next_operator { - Precedence::Unambiguous => { - fail_offset >= 2 - && (consume_by_precedence == Scan::Consume || bailout_offset >= 1) - } - _ => bailout_offset >= 1, - } { - return Scan::Consume; - } - let binop_prec = Precedence::of_binop(&e.op); - if binop_prec == Precedence::Compare && fixup.next_operator == Precedence::Compare { - return Scan::Consume; - } - let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec); - let scan = scan_right( - &e.right, - right_fixup, - binop_prec, - match fixup.next_operator { - Precedence::Unambiguous => fail_offset, - _ => 1, - }, - consume_by_precedence as u8 - Scan::Bailout as u8, - ); - match scan { - Scan::Fail => {} - Scan::Bailout => return consume_by_precedence, - Scan::Consume => return Scan::Consume, - } - let right_needs_group = binop_prec != Precedence::Assign - && right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec; - if right_needs_group { - consume_by_precedence - } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) { - Scan::Fail - } else { - Scan::Bailout - } - } - Expr::RawAddr(ExprRawAddr { expr, .. }) - | Expr::Reference(ExprReference { expr, .. }) - | Expr::Unary(ExprUnary { expr, .. }) => { - if match fixup.next_operator { - Precedence::Unambiguous => { - fail_offset >= 2 - && (consume_by_precedence == Scan::Consume || bailout_offset >= 1) - } - _ => bailout_offset >= 1, - } { - return Scan::Consume; - } - let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Prefix); - let scan = scan_right( - expr, - right_fixup, - precedence, - match fixup.next_operator { - Precedence::Unambiguous => fail_offset, - _ => 1, - }, - consume_by_precedence as u8 - Scan::Bailout as u8, - ); - match scan { - Scan::Fail => {} - Scan::Bailout => return consume_by_precedence, - Scan::Consume => return Scan::Consume, - } - if right_fixup.rightmost_subexpression_precedence(expr) < Precedence::Prefix { - consume_by_precedence - } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) { - Scan::Fail - } else { - Scan::Bailout - } - } - Expr::Range(e) if e.attrs.is_empty() => match &e.end { - Some(end) => { - if fail_offset >= 2 { - return Scan::Consume; - } - let right_fixup = - fixup.rightmost_subexpression_fixup(false, true, Precedence::Range); - let scan = scan_right( - end, - right_fixup, - Precedence::Range, - fail_offset, - match fixup.next_operator { - Precedence::Assign | Precedence::Range => 0, - _ => 1, - }, - ); - if match (scan, fixup.next_operator) { - (Scan::Fail, _) => false, - (Scan::Bailout, Precedence::Assign | Precedence::Range) => false, - (Scan::Bailout | Scan::Consume, _) => true, - } { - return Scan::Consume; - } - if right_fixup.rightmost_subexpression_precedence(end) <= Precedence::Range { - Scan::Consume - } else { - Scan::Fail - } - } - None => { - if fixup.next_operator_can_begin_expr { - Scan::Consume - } else { - Scan::Fail - } - } - }, - Expr::Break(e) => match &e.expr { - Some(value) => { - if bailout_offset >= 1 || e.label.is_none() && classify::expr_leading_label(value) { - return Scan::Consume; - } - let right_fixup = fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump); - match scan_right(value, right_fixup, Precedence::Jump, 1, 1) { - Scan::Fail => Scan::Bailout, - Scan::Bailout | Scan::Consume => Scan::Consume, - } - } - None => match fixup.next_operator { - Precedence::Assign if precedence > Precedence::Assign => Scan::Fail, - _ => Scan::Consume, - }, - }, - Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr { - Some(e) => { - if bailout_offset >= 1 { - return Scan::Consume; - } - let right_fixup = - fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump); - match scan_right(e, right_fixup, Precedence::Jump, 1, 1) { - Scan::Fail => Scan::Bailout, - Scan::Bailout | Scan::Consume => Scan::Consume, - } - } - None => match fixup.next_operator { - Precedence::Assign if precedence > Precedence::Assign => Scan::Fail, - _ => Scan::Consume, - }, - }, - Expr::Closure(e) => { - if matches!(e.output, ReturnType::Default) - || matches!(&*e.body, Expr::Block(body) if body.attrs.is_empty() && body.label.is_none()) - { - if bailout_offset >= 1 { - return Scan::Consume; - } - let right_fixup = - fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump); - match scan_right(&e.body, right_fixup, Precedence::Jump, 1, 1) { - Scan::Fail => Scan::Bailout, - Scan::Bailout | Scan::Consume => Scan::Consume, - } - } else { - Scan::Consume - } - } - Expr::Let(e) => { - if bailout_offset >= 1 { - return Scan::Consume; - } - let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Let); - let scan = scan_right( - &e.expr, - right_fixup, - Precedence::Let, - 1, - if fixup.next_operator < Precedence::Let { - 0 - } else { - 1 - }, - ); - match scan { - Scan::Fail | Scan::Bailout if fixup.next_operator < Precedence::Let => { - return Scan::Bailout; - } - Scan::Consume => return Scan::Consume, - _ => {} - } - if right_fixup.rightmost_subexpression_precedence(&e.expr) < Precedence::Let { - Scan::Consume - } else if let Scan::Fail = scan { - Scan::Bailout - } else { - Scan::Consume - } - } - Expr::Array(_) - | Expr::Assign(_) - | Expr::Async(_) - | Expr::Await(_) - | Expr::Binary(_) - | Expr::Block(_) - | Expr::Call(_) - | Expr::Cast(_) - | Expr::Const(_) - | Expr::Continue(_) - | Expr::Field(_) - | Expr::ForLoop(_) - | Expr::Group(_) - | Expr::If(_) - | Expr::Index(_) - | Expr::Infer(_) - | Expr::Lit(_) - | Expr::Loop(_) - | Expr::Macro(_) - | Expr::Match(_) - | Expr::MethodCall(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::Range(_) - | Expr::Repeat(_) - | Expr::Struct(_) - | Expr::Try(_) - | Expr::TryBlock(_) - | Expr::Tuple(_) - | Expr::Unsafe(_) - | Expr::Verbatim(_) - | Expr::While(_) => match fixup.next_operator { - Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail, - _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => { - Scan::Fail - } - _ => consume_by_precedence, - }, - } -} diff --git a/deps/crates/vendor/syn-v2/src/gen/clone.rs b/deps/crates/vendor/syn-v2/src/gen/clone.rs deleted file mode 100644 index be2b698422da..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/clone.rs +++ /dev/null @@ -1,2267 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#![allow(clippy::clone_on_copy, clippy::expl_impl_clone_on_copy)] -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Abi { - fn clone(&self) -> Self { - crate::Abi { - extern_token: self.extern_token.clone(), - name: self.name.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::AngleBracketedGenericArguments { - fn clone(&self) -> Self { - crate::AngleBracketedGenericArguments { - colon2_token: self.colon2_token.clone(), - lt_token: self.lt_token.clone(), - args: self.args.clone(), - gt_token: self.gt_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Arm { - fn clone(&self) -> Self { - crate::Arm { - attrs: self.attrs.clone(), - pat: self.pat.clone(), - guard: self.guard.clone(), - fat_arrow_token: self.fat_arrow_token.clone(), - body: self.body.clone(), - comma: self.comma.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::AssocConst { - fn clone(&self) -> Self { - crate::AssocConst { - ident: self.ident.clone(), - generics: self.generics.clone(), - eq_token: self.eq_token.clone(), - value: self.value.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::AssocType { - fn clone(&self) -> Self { - crate::AssocType { - ident: self.ident.clone(), - generics: self.generics.clone(), - eq_token: self.eq_token.clone(), - ty: self.ty.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for crate::AttrStyle {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::AttrStyle { - fn clone(&self) -> Self { - *self - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Attribute { - fn clone(&self) -> Self { - crate::Attribute { - pound_token: self.pound_token.clone(), - style: self.style.clone(), - bracket_token: self.bracket_token.clone(), - meta: self.meta.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::BareFnArg { - fn clone(&self) -> Self { - crate::BareFnArg { - attrs: self.attrs.clone(), - name: self.name.clone(), - ty: self.ty.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::BareVariadic { - fn clone(&self) -> Self { - crate::BareVariadic { - attrs: self.attrs.clone(), - name: self.name.clone(), - dots: self.dots.clone(), - comma: self.comma.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for crate::BinOp {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::BinOp { - fn clone(&self) -> Self { - *self - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Block { - fn clone(&self) -> Self { - crate::Block { - brace_token: self.brace_token.clone(), - stmts: self.stmts.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::BoundLifetimes { - fn clone(&self) -> Self { - crate::BoundLifetimes { - for_token: self.for_token.clone(), - lt_token: self.lt_token.clone(), - lifetimes: self.lifetimes.clone(), - gt_token: self.gt_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::CapturedParam { - fn clone(&self) -> Self { - match self { - crate::CapturedParam::Lifetime(v0) => { - crate::CapturedParam::Lifetime(v0.clone()) - } - crate::CapturedParam::Ident(v0) => crate::CapturedParam::Ident(v0.clone()), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ConstParam { - fn clone(&self) -> Self { - crate::ConstParam { - attrs: self.attrs.clone(), - const_token: self.const_token.clone(), - ident: self.ident.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - eq_token: self.eq_token.clone(), - default: self.default.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Constraint { - fn clone(&self) -> Self { - crate::Constraint { - ident: self.ident.clone(), - generics: self.generics.clone(), - colon_token: self.colon_token.clone(), - bounds: self.bounds.clone(), - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Data { - fn clone(&self) -> Self { - match self { - crate::Data::Struct(v0) => crate::Data::Struct(v0.clone()), - crate::Data::Enum(v0) => crate::Data::Enum(v0.clone()), - crate::Data::Union(v0) => crate::Data::Union(v0.clone()), - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::DataEnum { - fn clone(&self) -> Self { - crate::DataEnum { - enum_token: self.enum_token.clone(), - brace_token: self.brace_token.clone(), - variants: self.variants.clone(), - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::DataStruct { - fn clone(&self) -> Self { - crate::DataStruct { - struct_token: self.struct_token.clone(), - fields: self.fields.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::DataUnion { - fn clone(&self) -> Self { - crate::DataUnion { - union_token: self.union_token.clone(), - fields: self.fields.clone(), - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::DeriveInput { - fn clone(&self) -> Self { - crate::DeriveInput { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - data: self.data.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Expr { - fn clone(&self) -> Self { - match self { - #[cfg(feature = "full")] - crate::Expr::Array(v0) => crate::Expr::Array(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Assign(v0) => crate::Expr::Assign(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Async(v0) => crate::Expr::Async(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Await(v0) => crate::Expr::Await(v0.clone()), - crate::Expr::Binary(v0) => crate::Expr::Binary(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Block(v0) => crate::Expr::Block(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Break(v0) => crate::Expr::Break(v0.clone()), - crate::Expr::Call(v0) => crate::Expr::Call(v0.clone()), - crate::Expr::Cast(v0) => crate::Expr::Cast(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Closure(v0) => crate::Expr::Closure(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Const(v0) => crate::Expr::Const(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Continue(v0) => crate::Expr::Continue(v0.clone()), - crate::Expr::Field(v0) => crate::Expr::Field(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::ForLoop(v0) => crate::Expr::ForLoop(v0.clone()), - crate::Expr::Group(v0) => crate::Expr::Group(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::If(v0) => crate::Expr::If(v0.clone()), - crate::Expr::Index(v0) => crate::Expr::Index(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Infer(v0) => crate::Expr::Infer(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Let(v0) => crate::Expr::Let(v0.clone()), - crate::Expr::Lit(v0) => crate::Expr::Lit(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Loop(v0) => crate::Expr::Loop(v0.clone()), - crate::Expr::Macro(v0) => crate::Expr::Macro(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Match(v0) => crate::Expr::Match(v0.clone()), - crate::Expr::MethodCall(v0) => crate::Expr::MethodCall(v0.clone()), - crate::Expr::Paren(v0) => crate::Expr::Paren(v0.clone()), - crate::Expr::Path(v0) => crate::Expr::Path(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Range(v0) => crate::Expr::Range(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::RawAddr(v0) => crate::Expr::RawAddr(v0.clone()), - crate::Expr::Reference(v0) => crate::Expr::Reference(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Repeat(v0) => crate::Expr::Repeat(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Return(v0) => crate::Expr::Return(v0.clone()), - crate::Expr::Struct(v0) => crate::Expr::Struct(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Try(v0) => crate::Expr::Try(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::TryBlock(v0) => crate::Expr::TryBlock(v0.clone()), - crate::Expr::Tuple(v0) => crate::Expr::Tuple(v0.clone()), - crate::Expr::Unary(v0) => crate::Expr::Unary(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Unsafe(v0) => crate::Expr::Unsafe(v0.clone()), - crate::Expr::Verbatim(v0) => crate::Expr::Verbatim(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::While(v0) => crate::Expr::While(v0.clone()), - #[cfg(feature = "full")] - crate::Expr::Yield(v0) => crate::Expr::Yield(v0.clone()), - #[cfg(not(feature = "full"))] - _ => unreachable!(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprArray { - fn clone(&self) -> Self { - crate::ExprArray { - attrs: self.attrs.clone(), - bracket_token: self.bracket_token.clone(), - elems: self.elems.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprAssign { - fn clone(&self) -> Self { - crate::ExprAssign { - attrs: self.attrs.clone(), - left: self.left.clone(), - eq_token: self.eq_token.clone(), - right: self.right.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprAsync { - fn clone(&self) -> Self { - crate::ExprAsync { - attrs: self.attrs.clone(), - async_token: self.async_token.clone(), - capture: self.capture.clone(), - block: self.block.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprAwait { - fn clone(&self) -> Self { - crate::ExprAwait { - attrs: self.attrs.clone(), - base: self.base.clone(), - dot_token: self.dot_token.clone(), - await_token: self.await_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprBinary { - fn clone(&self) -> Self { - crate::ExprBinary { - attrs: self.attrs.clone(), - left: self.left.clone(), - op: self.op.clone(), - right: self.right.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprBlock { - fn clone(&self) -> Self { - crate::ExprBlock { - attrs: self.attrs.clone(), - label: self.label.clone(), - block: self.block.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprBreak { - fn clone(&self) -> Self { - crate::ExprBreak { - attrs: self.attrs.clone(), - break_token: self.break_token.clone(), - label: self.label.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprCall { - fn clone(&self) -> Self { - crate::ExprCall { - attrs: self.attrs.clone(), - func: self.func.clone(), - paren_token: self.paren_token.clone(), - args: self.args.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprCast { - fn clone(&self) -> Self { - crate::ExprCast { - attrs: self.attrs.clone(), - expr: self.expr.clone(), - as_token: self.as_token.clone(), - ty: self.ty.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprClosure { - fn clone(&self) -> Self { - crate::ExprClosure { - attrs: self.attrs.clone(), - lifetimes: self.lifetimes.clone(), - constness: self.constness.clone(), - movability: self.movability.clone(), - asyncness: self.asyncness.clone(), - capture: self.capture.clone(), - or1_token: self.or1_token.clone(), - inputs: self.inputs.clone(), - or2_token: self.or2_token.clone(), - output: self.output.clone(), - body: self.body.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprConst { - fn clone(&self) -> Self { - crate::ExprConst { - attrs: self.attrs.clone(), - const_token: self.const_token.clone(), - block: self.block.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprContinue { - fn clone(&self) -> Self { - crate::ExprContinue { - attrs: self.attrs.clone(), - continue_token: self.continue_token.clone(), - label: self.label.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprField { - fn clone(&self) -> Self { - crate::ExprField { - attrs: self.attrs.clone(), - base: self.base.clone(), - dot_token: self.dot_token.clone(), - member: self.member.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprForLoop { - fn clone(&self) -> Self { - crate::ExprForLoop { - attrs: self.attrs.clone(), - label: self.label.clone(), - for_token: self.for_token.clone(), - pat: self.pat.clone(), - in_token: self.in_token.clone(), - expr: self.expr.clone(), - body: self.body.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprGroup { - fn clone(&self) -> Self { - crate::ExprGroup { - attrs: self.attrs.clone(), - group_token: self.group_token.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprIf { - fn clone(&self) -> Self { - crate::ExprIf { - attrs: self.attrs.clone(), - if_token: self.if_token.clone(), - cond: self.cond.clone(), - then_branch: self.then_branch.clone(), - else_branch: self.else_branch.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprIndex { - fn clone(&self) -> Self { - crate::ExprIndex { - attrs: self.attrs.clone(), - expr: self.expr.clone(), - bracket_token: self.bracket_token.clone(), - index: self.index.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprInfer { - fn clone(&self) -> Self { - crate::ExprInfer { - attrs: self.attrs.clone(), - underscore_token: self.underscore_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprLet { - fn clone(&self) -> Self { - crate::ExprLet { - attrs: self.attrs.clone(), - let_token: self.let_token.clone(), - pat: self.pat.clone(), - eq_token: self.eq_token.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprLit { - fn clone(&self) -> Self { - crate::ExprLit { - attrs: self.attrs.clone(), - lit: self.lit.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprLoop { - fn clone(&self) -> Self { - crate::ExprLoop { - attrs: self.attrs.clone(), - label: self.label.clone(), - loop_token: self.loop_token.clone(), - body: self.body.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprMacro { - fn clone(&self) -> Self { - crate::ExprMacro { - attrs: self.attrs.clone(), - mac: self.mac.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprMatch { - fn clone(&self) -> Self { - crate::ExprMatch { - attrs: self.attrs.clone(), - match_token: self.match_token.clone(), - expr: self.expr.clone(), - brace_token: self.brace_token.clone(), - arms: self.arms.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprMethodCall { - fn clone(&self) -> Self { - crate::ExprMethodCall { - attrs: self.attrs.clone(), - receiver: self.receiver.clone(), - dot_token: self.dot_token.clone(), - method: self.method.clone(), - turbofish: self.turbofish.clone(), - paren_token: self.paren_token.clone(), - args: self.args.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprParen { - fn clone(&self) -> Self { - crate::ExprParen { - attrs: self.attrs.clone(), - paren_token: self.paren_token.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprPath { - fn clone(&self) -> Self { - crate::ExprPath { - attrs: self.attrs.clone(), - qself: self.qself.clone(), - path: self.path.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprRange { - fn clone(&self) -> Self { - crate::ExprRange { - attrs: self.attrs.clone(), - start: self.start.clone(), - limits: self.limits.clone(), - end: self.end.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprRawAddr { - fn clone(&self) -> Self { - crate::ExprRawAddr { - attrs: self.attrs.clone(), - and_token: self.and_token.clone(), - raw: self.raw.clone(), - mutability: self.mutability.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprReference { - fn clone(&self) -> Self { - crate::ExprReference { - attrs: self.attrs.clone(), - and_token: self.and_token.clone(), - mutability: self.mutability.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprRepeat { - fn clone(&self) -> Self { - crate::ExprRepeat { - attrs: self.attrs.clone(), - bracket_token: self.bracket_token.clone(), - expr: self.expr.clone(), - semi_token: self.semi_token.clone(), - len: self.len.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprReturn { - fn clone(&self) -> Self { - crate::ExprReturn { - attrs: self.attrs.clone(), - return_token: self.return_token.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprStruct { - fn clone(&self) -> Self { - crate::ExprStruct { - attrs: self.attrs.clone(), - qself: self.qself.clone(), - path: self.path.clone(), - brace_token: self.brace_token.clone(), - fields: self.fields.clone(), - dot2_token: self.dot2_token.clone(), - rest: self.rest.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprTry { - fn clone(&self) -> Self { - crate::ExprTry { - attrs: self.attrs.clone(), - expr: self.expr.clone(), - question_token: self.question_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprTryBlock { - fn clone(&self) -> Self { - crate::ExprTryBlock { - attrs: self.attrs.clone(), - try_token: self.try_token.clone(), - block: self.block.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprTuple { - fn clone(&self) -> Self { - crate::ExprTuple { - attrs: self.attrs.clone(), - paren_token: self.paren_token.clone(), - elems: self.elems.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprUnary { - fn clone(&self) -> Self { - crate::ExprUnary { - attrs: self.attrs.clone(), - op: self.op.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprUnsafe { - fn clone(&self) -> Self { - crate::ExprUnsafe { - attrs: self.attrs.clone(), - unsafe_token: self.unsafe_token.clone(), - block: self.block.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprWhile { - fn clone(&self) -> Self { - crate::ExprWhile { - attrs: self.attrs.clone(), - label: self.label.clone(), - while_token: self.while_token.clone(), - cond: self.cond.clone(), - body: self.body.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ExprYield { - fn clone(&self) -> Self { - crate::ExprYield { - attrs: self.attrs.clone(), - yield_token: self.yield_token.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Field { - fn clone(&self) -> Self { - crate::Field { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - mutability: self.mutability.clone(), - ident: self.ident.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::FieldMutability { - fn clone(&self) -> Self { - match self { - crate::FieldMutability::None => crate::FieldMutability::None, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::FieldPat { - fn clone(&self) -> Self { - crate::FieldPat { - attrs: self.attrs.clone(), - member: self.member.clone(), - colon_token: self.colon_token.clone(), - pat: self.pat.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::FieldValue { - fn clone(&self) -> Self { - crate::FieldValue { - attrs: self.attrs.clone(), - member: self.member.clone(), - colon_token: self.colon_token.clone(), - expr: self.expr.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Fields { - fn clone(&self) -> Self { - match self { - crate::Fields::Named(v0) => crate::Fields::Named(v0.clone()), - crate::Fields::Unnamed(v0) => crate::Fields::Unnamed(v0.clone()), - crate::Fields::Unit => crate::Fields::Unit, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::FieldsNamed { - fn clone(&self) -> Self { - crate::FieldsNamed { - brace_token: self.brace_token.clone(), - named: self.named.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::FieldsUnnamed { - fn clone(&self) -> Self { - crate::FieldsUnnamed { - paren_token: self.paren_token.clone(), - unnamed: self.unnamed.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::File { - fn clone(&self) -> Self { - crate::File { - shebang: self.shebang.clone(), - attrs: self.attrs.clone(), - items: self.items.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::FnArg { - fn clone(&self) -> Self { - match self { - crate::FnArg::Receiver(v0) => crate::FnArg::Receiver(v0.clone()), - crate::FnArg::Typed(v0) => crate::FnArg::Typed(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ForeignItem { - fn clone(&self) -> Self { - match self { - crate::ForeignItem::Fn(v0) => crate::ForeignItem::Fn(v0.clone()), - crate::ForeignItem::Static(v0) => crate::ForeignItem::Static(v0.clone()), - crate::ForeignItem::Type(v0) => crate::ForeignItem::Type(v0.clone()), - crate::ForeignItem::Macro(v0) => crate::ForeignItem::Macro(v0.clone()), - crate::ForeignItem::Verbatim(v0) => crate::ForeignItem::Verbatim(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ForeignItemFn { - fn clone(&self) -> Self { - crate::ForeignItemFn { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - sig: self.sig.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ForeignItemMacro { - fn clone(&self) -> Self { - crate::ForeignItemMacro { - attrs: self.attrs.clone(), - mac: self.mac.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ForeignItemStatic { - fn clone(&self) -> Self { - crate::ForeignItemStatic { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - static_token: self.static_token.clone(), - mutability: self.mutability.clone(), - ident: self.ident.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ForeignItemType { - fn clone(&self) -> Self { - crate::ForeignItemType { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - type_token: self.type_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::GenericArgument { - fn clone(&self) -> Self { - match self { - crate::GenericArgument::Lifetime(v0) => { - crate::GenericArgument::Lifetime(v0.clone()) - } - crate::GenericArgument::Type(v0) => crate::GenericArgument::Type(v0.clone()), - crate::GenericArgument::Const(v0) => { - crate::GenericArgument::Const(v0.clone()) - } - crate::GenericArgument::AssocType(v0) => { - crate::GenericArgument::AssocType(v0.clone()) - } - crate::GenericArgument::AssocConst(v0) => { - crate::GenericArgument::AssocConst(v0.clone()) - } - crate::GenericArgument::Constraint(v0) => { - crate::GenericArgument::Constraint(v0.clone()) - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::GenericParam { - fn clone(&self) -> Self { - match self { - crate::GenericParam::Lifetime(v0) => { - crate::GenericParam::Lifetime(v0.clone()) - } - crate::GenericParam::Type(v0) => crate::GenericParam::Type(v0.clone()), - crate::GenericParam::Const(v0) => crate::GenericParam::Const(v0.clone()), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Generics { - fn clone(&self) -> Self { - crate::Generics { - lt_token: self.lt_token.clone(), - params: self.params.clone(), - gt_token: self.gt_token.clone(), - where_clause: self.where_clause.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ImplItem { - fn clone(&self) -> Self { - match self { - crate::ImplItem::Const(v0) => crate::ImplItem::Const(v0.clone()), - crate::ImplItem::Fn(v0) => crate::ImplItem::Fn(v0.clone()), - crate::ImplItem::Type(v0) => crate::ImplItem::Type(v0.clone()), - crate::ImplItem::Macro(v0) => crate::ImplItem::Macro(v0.clone()), - crate::ImplItem::Verbatim(v0) => crate::ImplItem::Verbatim(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ImplItemConst { - fn clone(&self) -> Self { - crate::ImplItemConst { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - defaultness: self.defaultness.clone(), - const_token: self.const_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - eq_token: self.eq_token.clone(), - expr: self.expr.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ImplItemFn { - fn clone(&self) -> Self { - crate::ImplItemFn { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - defaultness: self.defaultness.clone(), - sig: self.sig.clone(), - block: self.block.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ImplItemMacro { - fn clone(&self) -> Self { - crate::ImplItemMacro { - attrs: self.attrs.clone(), - mac: self.mac.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ImplItemType { - fn clone(&self) -> Self { - crate::ImplItemType { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - defaultness: self.defaultness.clone(), - type_token: self.type_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - eq_token: self.eq_token.clone(), - ty: self.ty.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ImplRestriction { - fn clone(&self) -> Self { - match *self {} - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Index { - fn clone(&self) -> Self { - crate::Index { - index: self.index.clone(), - span: self.span.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Item { - fn clone(&self) -> Self { - match self { - crate::Item::Const(v0) => crate::Item::Const(v0.clone()), - crate::Item::Enum(v0) => crate::Item::Enum(v0.clone()), - crate::Item::ExternCrate(v0) => crate::Item::ExternCrate(v0.clone()), - crate::Item::Fn(v0) => crate::Item::Fn(v0.clone()), - crate::Item::ForeignMod(v0) => crate::Item::ForeignMod(v0.clone()), - crate::Item::Impl(v0) => crate::Item::Impl(v0.clone()), - crate::Item::Macro(v0) => crate::Item::Macro(v0.clone()), - crate::Item::Mod(v0) => crate::Item::Mod(v0.clone()), - crate::Item::Static(v0) => crate::Item::Static(v0.clone()), - crate::Item::Struct(v0) => crate::Item::Struct(v0.clone()), - crate::Item::Trait(v0) => crate::Item::Trait(v0.clone()), - crate::Item::TraitAlias(v0) => crate::Item::TraitAlias(v0.clone()), - crate::Item::Type(v0) => crate::Item::Type(v0.clone()), - crate::Item::Union(v0) => crate::Item::Union(v0.clone()), - crate::Item::Use(v0) => crate::Item::Use(v0.clone()), - crate::Item::Verbatim(v0) => crate::Item::Verbatim(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemConst { - fn clone(&self) -> Self { - crate::ItemConst { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - const_token: self.const_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - eq_token: self.eq_token.clone(), - expr: self.expr.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemEnum { - fn clone(&self) -> Self { - crate::ItemEnum { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - enum_token: self.enum_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - brace_token: self.brace_token.clone(), - variants: self.variants.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemExternCrate { - fn clone(&self) -> Self { - crate::ItemExternCrate { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - extern_token: self.extern_token.clone(), - crate_token: self.crate_token.clone(), - ident: self.ident.clone(), - rename: self.rename.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemFn { - fn clone(&self) -> Self { - crate::ItemFn { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - sig: self.sig.clone(), - block: self.block.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemForeignMod { - fn clone(&self) -> Self { - crate::ItemForeignMod { - attrs: self.attrs.clone(), - unsafety: self.unsafety.clone(), - abi: self.abi.clone(), - brace_token: self.brace_token.clone(), - items: self.items.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemImpl { - fn clone(&self) -> Self { - crate::ItemImpl { - attrs: self.attrs.clone(), - defaultness: self.defaultness.clone(), - unsafety: self.unsafety.clone(), - impl_token: self.impl_token.clone(), - generics: self.generics.clone(), - trait_: self.trait_.clone(), - self_ty: self.self_ty.clone(), - brace_token: self.brace_token.clone(), - items: self.items.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemMacro { - fn clone(&self) -> Self { - crate::ItemMacro { - attrs: self.attrs.clone(), - ident: self.ident.clone(), - mac: self.mac.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemMod { - fn clone(&self) -> Self { - crate::ItemMod { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - unsafety: self.unsafety.clone(), - mod_token: self.mod_token.clone(), - ident: self.ident.clone(), - content: self.content.clone(), - semi: self.semi.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemStatic { - fn clone(&self) -> Self { - crate::ItemStatic { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - static_token: self.static_token.clone(), - mutability: self.mutability.clone(), - ident: self.ident.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - eq_token: self.eq_token.clone(), - expr: self.expr.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemStruct { - fn clone(&self) -> Self { - crate::ItemStruct { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - struct_token: self.struct_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - fields: self.fields.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemTrait { - fn clone(&self) -> Self { - crate::ItemTrait { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - unsafety: self.unsafety.clone(), - auto_token: self.auto_token.clone(), - restriction: self.restriction.clone(), - trait_token: self.trait_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - colon_token: self.colon_token.clone(), - supertraits: self.supertraits.clone(), - brace_token: self.brace_token.clone(), - items: self.items.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemTraitAlias { - fn clone(&self) -> Self { - crate::ItemTraitAlias { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - trait_token: self.trait_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - eq_token: self.eq_token.clone(), - bounds: self.bounds.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemType { - fn clone(&self) -> Self { - crate::ItemType { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - type_token: self.type_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - eq_token: self.eq_token.clone(), - ty: self.ty.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemUnion { - fn clone(&self) -> Self { - crate::ItemUnion { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - union_token: self.union_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - fields: self.fields.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ItemUse { - fn clone(&self) -> Self { - crate::ItemUse { - attrs: self.attrs.clone(), - vis: self.vis.clone(), - use_token: self.use_token.clone(), - leading_colon: self.leading_colon.clone(), - tree: self.tree.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Label { - fn clone(&self) -> Self { - crate::Label { - name: self.name.clone(), - colon_token: self.colon_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::LifetimeParam { - fn clone(&self) -> Self { - crate::LifetimeParam { - attrs: self.attrs.clone(), - lifetime: self.lifetime.clone(), - colon_token: self.colon_token.clone(), - bounds: self.bounds.clone(), - } - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Lit { - fn clone(&self) -> Self { - match self { - crate::Lit::Str(v0) => crate::Lit::Str(v0.clone()), - crate::Lit::ByteStr(v0) => crate::Lit::ByteStr(v0.clone()), - crate::Lit::CStr(v0) => crate::Lit::CStr(v0.clone()), - crate::Lit::Byte(v0) => crate::Lit::Byte(v0.clone()), - crate::Lit::Char(v0) => crate::Lit::Char(v0.clone()), - crate::Lit::Int(v0) => crate::Lit::Int(v0.clone()), - crate::Lit::Float(v0) => crate::Lit::Float(v0.clone()), - crate::Lit::Bool(v0) => crate::Lit::Bool(v0.clone()), - crate::Lit::Verbatim(v0) => crate::Lit::Verbatim(v0.clone()), - } - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::LitBool { - fn clone(&self) -> Self { - crate::LitBool { - value: self.value.clone(), - span: self.span.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Local { - fn clone(&self) -> Self { - crate::Local { - attrs: self.attrs.clone(), - let_token: self.let_token.clone(), - pat: self.pat.clone(), - init: self.init.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::LocalInit { - fn clone(&self) -> Self { - crate::LocalInit { - eq_token: self.eq_token.clone(), - expr: self.expr.clone(), - diverge: self.diverge.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Macro { - fn clone(&self) -> Self { - crate::Macro { - path: self.path.clone(), - bang_token: self.bang_token.clone(), - delimiter: self.delimiter.clone(), - tokens: self.tokens.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::MacroDelimiter { - fn clone(&self) -> Self { - match self { - crate::MacroDelimiter::Paren(v0) => crate::MacroDelimiter::Paren(v0.clone()), - crate::MacroDelimiter::Brace(v0) => crate::MacroDelimiter::Brace(v0.clone()), - crate::MacroDelimiter::Bracket(v0) => { - crate::MacroDelimiter::Bracket(v0.clone()) - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Member { - fn clone(&self) -> Self { - match self { - crate::Member::Named(v0) => crate::Member::Named(v0.clone()), - crate::Member::Unnamed(v0) => crate::Member::Unnamed(v0.clone()), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Meta { - fn clone(&self) -> Self { - match self { - crate::Meta::Path(v0) => crate::Meta::Path(v0.clone()), - crate::Meta::List(v0) => crate::Meta::List(v0.clone()), - crate::Meta::NameValue(v0) => crate::Meta::NameValue(v0.clone()), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::MetaList { - fn clone(&self) -> Self { - crate::MetaList { - path: self.path.clone(), - delimiter: self.delimiter.clone(), - tokens: self.tokens.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::MetaNameValue { - fn clone(&self) -> Self { - crate::MetaNameValue { - path: self.path.clone(), - eq_token: self.eq_token.clone(), - value: self.value.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ParenthesizedGenericArguments { - fn clone(&self) -> Self { - crate::ParenthesizedGenericArguments { - paren_token: self.paren_token.clone(), - inputs: self.inputs.clone(), - output: self.output.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Pat { - fn clone(&self) -> Self { - match self { - crate::Pat::Const(v0) => crate::Pat::Const(v0.clone()), - crate::Pat::Ident(v0) => crate::Pat::Ident(v0.clone()), - crate::Pat::Lit(v0) => crate::Pat::Lit(v0.clone()), - crate::Pat::Macro(v0) => crate::Pat::Macro(v0.clone()), - crate::Pat::Or(v0) => crate::Pat::Or(v0.clone()), - crate::Pat::Paren(v0) => crate::Pat::Paren(v0.clone()), - crate::Pat::Path(v0) => crate::Pat::Path(v0.clone()), - crate::Pat::Range(v0) => crate::Pat::Range(v0.clone()), - crate::Pat::Reference(v0) => crate::Pat::Reference(v0.clone()), - crate::Pat::Rest(v0) => crate::Pat::Rest(v0.clone()), - crate::Pat::Slice(v0) => crate::Pat::Slice(v0.clone()), - crate::Pat::Struct(v0) => crate::Pat::Struct(v0.clone()), - crate::Pat::Tuple(v0) => crate::Pat::Tuple(v0.clone()), - crate::Pat::TupleStruct(v0) => crate::Pat::TupleStruct(v0.clone()), - crate::Pat::Type(v0) => crate::Pat::Type(v0.clone()), - crate::Pat::Verbatim(v0) => crate::Pat::Verbatim(v0.clone()), - crate::Pat::Wild(v0) => crate::Pat::Wild(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatIdent { - fn clone(&self) -> Self { - crate::PatIdent { - attrs: self.attrs.clone(), - by_ref: self.by_ref.clone(), - mutability: self.mutability.clone(), - ident: self.ident.clone(), - subpat: self.subpat.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatOr { - fn clone(&self) -> Self { - crate::PatOr { - attrs: self.attrs.clone(), - leading_vert: self.leading_vert.clone(), - cases: self.cases.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatParen { - fn clone(&self) -> Self { - crate::PatParen { - attrs: self.attrs.clone(), - paren_token: self.paren_token.clone(), - pat: self.pat.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatReference { - fn clone(&self) -> Self { - crate::PatReference { - attrs: self.attrs.clone(), - and_token: self.and_token.clone(), - mutability: self.mutability.clone(), - pat: self.pat.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatRest { - fn clone(&self) -> Self { - crate::PatRest { - attrs: self.attrs.clone(), - dot2_token: self.dot2_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatSlice { - fn clone(&self) -> Self { - crate::PatSlice { - attrs: self.attrs.clone(), - bracket_token: self.bracket_token.clone(), - elems: self.elems.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatStruct { - fn clone(&self) -> Self { - crate::PatStruct { - attrs: self.attrs.clone(), - qself: self.qself.clone(), - path: self.path.clone(), - brace_token: self.brace_token.clone(), - fields: self.fields.clone(), - rest: self.rest.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatTuple { - fn clone(&self) -> Self { - crate::PatTuple { - attrs: self.attrs.clone(), - paren_token: self.paren_token.clone(), - elems: self.elems.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatTupleStruct { - fn clone(&self) -> Self { - crate::PatTupleStruct { - attrs: self.attrs.clone(), - qself: self.qself.clone(), - path: self.path.clone(), - paren_token: self.paren_token.clone(), - elems: self.elems.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatType { - fn clone(&self) -> Self { - crate::PatType { - attrs: self.attrs.clone(), - pat: self.pat.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PatWild { - fn clone(&self) -> Self { - crate::PatWild { - attrs: self.attrs.clone(), - underscore_token: self.underscore_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Path { - fn clone(&self) -> Self { - crate::Path { - leading_colon: self.leading_colon.clone(), - segments: self.segments.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PathArguments { - fn clone(&self) -> Self { - match self { - crate::PathArguments::None => crate::PathArguments::None, - crate::PathArguments::AngleBracketed(v0) => { - crate::PathArguments::AngleBracketed(v0.clone()) - } - crate::PathArguments::Parenthesized(v0) => { - crate::PathArguments::Parenthesized(v0.clone()) - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PathSegment { - fn clone(&self) -> Self { - crate::PathSegment { - ident: self.ident.clone(), - arguments: self.arguments.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PointerMutability { - fn clone(&self) -> Self { - match self { - crate::PointerMutability::Const(v0) => { - crate::PointerMutability::Const(v0.clone()) - } - crate::PointerMutability::Mut(v0) => { - crate::PointerMutability::Mut(v0.clone()) - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PreciseCapture { - fn clone(&self) -> Self { - crate::PreciseCapture { - use_token: self.use_token.clone(), - lt_token: self.lt_token.clone(), - params: self.params.clone(), - gt_token: self.gt_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PredicateLifetime { - fn clone(&self) -> Self { - crate::PredicateLifetime { - lifetime: self.lifetime.clone(), - colon_token: self.colon_token.clone(), - bounds: self.bounds.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::PredicateType { - fn clone(&self) -> Self { - crate::PredicateType { - lifetimes: self.lifetimes.clone(), - bounded_ty: self.bounded_ty.clone(), - colon_token: self.colon_token.clone(), - bounds: self.bounds.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::QSelf { - fn clone(&self) -> Self { - crate::QSelf { - lt_token: self.lt_token.clone(), - ty: self.ty.clone(), - position: self.position.clone(), - as_token: self.as_token.clone(), - gt_token: self.gt_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for crate::RangeLimits {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::RangeLimits { - fn clone(&self) -> Self { - *self - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Receiver { - fn clone(&self) -> Self { - crate::Receiver { - attrs: self.attrs.clone(), - reference: self.reference.clone(), - mutability: self.mutability.clone(), - self_token: self.self_token.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::ReturnType { - fn clone(&self) -> Self { - match self { - crate::ReturnType::Default => crate::ReturnType::Default, - crate::ReturnType::Type(v0, v1) => { - crate::ReturnType::Type(v0.clone(), v1.clone()) - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Signature { - fn clone(&self) -> Self { - crate::Signature { - constness: self.constness.clone(), - asyncness: self.asyncness.clone(), - unsafety: self.unsafety.clone(), - abi: self.abi.clone(), - fn_token: self.fn_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - paren_token: self.paren_token.clone(), - inputs: self.inputs.clone(), - variadic: self.variadic.clone(), - output: self.output.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::StaticMutability { - fn clone(&self) -> Self { - match self { - crate::StaticMutability::Mut(v0) => crate::StaticMutability::Mut(v0.clone()), - crate::StaticMutability::None => crate::StaticMutability::None, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Stmt { - fn clone(&self) -> Self { - match self { - crate::Stmt::Local(v0) => crate::Stmt::Local(v0.clone()), - crate::Stmt::Item(v0) => crate::Stmt::Item(v0.clone()), - crate::Stmt::Expr(v0, v1) => crate::Stmt::Expr(v0.clone(), v1.clone()), - crate::Stmt::Macro(v0) => crate::Stmt::Macro(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::StmtMacro { - fn clone(&self) -> Self { - crate::StmtMacro { - attrs: self.attrs.clone(), - mac: self.mac.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitBound { - fn clone(&self) -> Self { - crate::TraitBound { - paren_token: self.paren_token.clone(), - modifier: self.modifier.clone(), - lifetimes: self.lifetimes.clone(), - path: self.path.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for crate::TraitBoundModifier {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitBoundModifier { - fn clone(&self) -> Self { - *self - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitItem { - fn clone(&self) -> Self { - match self { - crate::TraitItem::Const(v0) => crate::TraitItem::Const(v0.clone()), - crate::TraitItem::Fn(v0) => crate::TraitItem::Fn(v0.clone()), - crate::TraitItem::Type(v0) => crate::TraitItem::Type(v0.clone()), - crate::TraitItem::Macro(v0) => crate::TraitItem::Macro(v0.clone()), - crate::TraitItem::Verbatim(v0) => crate::TraitItem::Verbatim(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitItemConst { - fn clone(&self) -> Self { - crate::TraitItemConst { - attrs: self.attrs.clone(), - const_token: self.const_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - colon_token: self.colon_token.clone(), - ty: self.ty.clone(), - default: self.default.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitItemFn { - fn clone(&self) -> Self { - crate::TraitItemFn { - attrs: self.attrs.clone(), - sig: self.sig.clone(), - default: self.default.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitItemMacro { - fn clone(&self) -> Self { - crate::TraitItemMacro { - attrs: self.attrs.clone(), - mac: self.mac.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TraitItemType { - fn clone(&self) -> Self { - crate::TraitItemType { - attrs: self.attrs.clone(), - type_token: self.type_token.clone(), - ident: self.ident.clone(), - generics: self.generics.clone(), - colon_token: self.colon_token.clone(), - bounds: self.bounds.clone(), - default: self.default.clone(), - semi_token: self.semi_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Type { - fn clone(&self) -> Self { - match self { - crate::Type::Array(v0) => crate::Type::Array(v0.clone()), - crate::Type::BareFn(v0) => crate::Type::BareFn(v0.clone()), - crate::Type::Group(v0) => crate::Type::Group(v0.clone()), - crate::Type::ImplTrait(v0) => crate::Type::ImplTrait(v0.clone()), - crate::Type::Infer(v0) => crate::Type::Infer(v0.clone()), - crate::Type::Macro(v0) => crate::Type::Macro(v0.clone()), - crate::Type::Never(v0) => crate::Type::Never(v0.clone()), - crate::Type::Paren(v0) => crate::Type::Paren(v0.clone()), - crate::Type::Path(v0) => crate::Type::Path(v0.clone()), - crate::Type::Ptr(v0) => crate::Type::Ptr(v0.clone()), - crate::Type::Reference(v0) => crate::Type::Reference(v0.clone()), - crate::Type::Slice(v0) => crate::Type::Slice(v0.clone()), - crate::Type::TraitObject(v0) => crate::Type::TraitObject(v0.clone()), - crate::Type::Tuple(v0) => crate::Type::Tuple(v0.clone()), - crate::Type::Verbatim(v0) => crate::Type::Verbatim(v0.clone()), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeArray { - fn clone(&self) -> Self { - crate::TypeArray { - bracket_token: self.bracket_token.clone(), - elem: self.elem.clone(), - semi_token: self.semi_token.clone(), - len: self.len.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeBareFn { - fn clone(&self) -> Self { - crate::TypeBareFn { - lifetimes: self.lifetimes.clone(), - unsafety: self.unsafety.clone(), - abi: self.abi.clone(), - fn_token: self.fn_token.clone(), - paren_token: self.paren_token.clone(), - inputs: self.inputs.clone(), - variadic: self.variadic.clone(), - output: self.output.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeGroup { - fn clone(&self) -> Self { - crate::TypeGroup { - group_token: self.group_token.clone(), - elem: self.elem.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeImplTrait { - fn clone(&self) -> Self { - crate::TypeImplTrait { - impl_token: self.impl_token.clone(), - bounds: self.bounds.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeInfer { - fn clone(&self) -> Self { - crate::TypeInfer { - underscore_token: self.underscore_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeMacro { - fn clone(&self) -> Self { - crate::TypeMacro { - mac: self.mac.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeNever { - fn clone(&self) -> Self { - crate::TypeNever { - bang_token: self.bang_token.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeParam { - fn clone(&self) -> Self { - crate::TypeParam { - attrs: self.attrs.clone(), - ident: self.ident.clone(), - colon_token: self.colon_token.clone(), - bounds: self.bounds.clone(), - eq_token: self.eq_token.clone(), - default: self.default.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeParamBound { - fn clone(&self) -> Self { - match self { - crate::TypeParamBound::Trait(v0) => crate::TypeParamBound::Trait(v0.clone()), - crate::TypeParamBound::Lifetime(v0) => { - crate::TypeParamBound::Lifetime(v0.clone()) - } - #[cfg(feature = "full")] - crate::TypeParamBound::PreciseCapture(v0) => { - crate::TypeParamBound::PreciseCapture(v0.clone()) - } - crate::TypeParamBound::Verbatim(v0) => { - crate::TypeParamBound::Verbatim(v0.clone()) - } - #[cfg(not(feature = "full"))] - _ => unreachable!(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeParen { - fn clone(&self) -> Self { - crate::TypeParen { - paren_token: self.paren_token.clone(), - elem: self.elem.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypePath { - fn clone(&self) -> Self { - crate::TypePath { - qself: self.qself.clone(), - path: self.path.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypePtr { - fn clone(&self) -> Self { - crate::TypePtr { - star_token: self.star_token.clone(), - const_token: self.const_token.clone(), - mutability: self.mutability.clone(), - elem: self.elem.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeReference { - fn clone(&self) -> Self { - crate::TypeReference { - and_token: self.and_token.clone(), - lifetime: self.lifetime.clone(), - mutability: self.mutability.clone(), - elem: self.elem.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeSlice { - fn clone(&self) -> Self { - crate::TypeSlice { - bracket_token: self.bracket_token.clone(), - elem: self.elem.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeTraitObject { - fn clone(&self) -> Self { - crate::TypeTraitObject { - dyn_token: self.dyn_token.clone(), - bounds: self.bounds.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::TypeTuple { - fn clone(&self) -> Self { - crate::TypeTuple { - paren_token: self.paren_token.clone(), - elems: self.elems.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for crate::UnOp {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UnOp { - fn clone(&self) -> Self { - *self - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UseGlob { - fn clone(&self) -> Self { - crate::UseGlob { - star_token: self.star_token.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UseGroup { - fn clone(&self) -> Self { - crate::UseGroup { - brace_token: self.brace_token.clone(), - items: self.items.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UseName { - fn clone(&self) -> Self { - crate::UseName { - ident: self.ident.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UsePath { - fn clone(&self) -> Self { - crate::UsePath { - ident: self.ident.clone(), - colon2_token: self.colon2_token.clone(), - tree: self.tree.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UseRename { - fn clone(&self) -> Self { - crate::UseRename { - ident: self.ident.clone(), - as_token: self.as_token.clone(), - rename: self.rename.clone(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::UseTree { - fn clone(&self) -> Self { - match self { - crate::UseTree::Path(v0) => crate::UseTree::Path(v0.clone()), - crate::UseTree::Name(v0) => crate::UseTree::Name(v0.clone()), - crate::UseTree::Rename(v0) => crate::UseTree::Rename(v0.clone()), - crate::UseTree::Glob(v0) => crate::UseTree::Glob(v0.clone()), - crate::UseTree::Group(v0) => crate::UseTree::Group(v0.clone()), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Variadic { - fn clone(&self) -> Self { - crate::Variadic { - attrs: self.attrs.clone(), - pat: self.pat.clone(), - dots: self.dots.clone(), - comma: self.comma.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Variant { - fn clone(&self) -> Self { - crate::Variant { - attrs: self.attrs.clone(), - ident: self.ident.clone(), - fields: self.fields.clone(), - discriminant: self.discriminant.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::VisRestricted { - fn clone(&self) -> Self { - crate::VisRestricted { - pub_token: self.pub_token.clone(), - paren_token: self.paren_token.clone(), - in_token: self.in_token.clone(), - path: self.path.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::Visibility { - fn clone(&self) -> Self { - match self { - crate::Visibility::Public(v0) => crate::Visibility::Public(v0.clone()), - crate::Visibility::Restricted(v0) => { - crate::Visibility::Restricted(v0.clone()) - } - crate::Visibility::Inherited => crate::Visibility::Inherited, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::WhereClause { - fn clone(&self) -> Self { - crate::WhereClause { - where_token: self.where_token.clone(), - predicates: self.predicates.clone(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for crate::WherePredicate { - fn clone(&self) -> Self { - match self { - crate::WherePredicate::Lifetime(v0) => { - crate::WherePredicate::Lifetime(v0.clone()) - } - crate::WherePredicate::Type(v0) => crate::WherePredicate::Type(v0.clone()), - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/gen/debug.rs b/deps/crates/vendor/syn-v2/src/gen/debug.rs deleted file mode 100644 index bf0784d1c463..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/debug.rs +++ /dev/null @@ -1,3238 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#![allow(unknown_lints, non_local_definitions)] -use core::fmt::{self, Debug}; -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Abi { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Abi"); - formatter.field("extern_token", &self.extern_token); - formatter.field("name", &self.name); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::AngleBracketedGenericArguments { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "AngleBracketedGenericArguments") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::AngleBracketedGenericArguments { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("colon2_token", &self.colon2_token); - formatter.field("lt_token", &self.lt_token); - formatter.field("args", &self.args); - formatter.field("gt_token", &self.gt_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Arm { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Arm"); - formatter.field("attrs", &self.attrs); - formatter.field("pat", &self.pat); - formatter.field("guard", &self.guard); - formatter.field("fat_arrow_token", &self.fat_arrow_token); - formatter.field("body", &self.body); - formatter.field("comma", &self.comma); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::AssocConst { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("AssocConst"); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("eq_token", &self.eq_token); - formatter.field("value", &self.value); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::AssocType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("AssocType"); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("eq_token", &self.eq_token); - formatter.field("ty", &self.ty); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::AttrStyle { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("AttrStyle::")?; - match self { - crate::AttrStyle::Outer => formatter.write_str("Outer"), - crate::AttrStyle::Inner(v0) => { - let mut formatter = formatter.debug_tuple("Inner"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Attribute { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Attribute"); - formatter.field("pound_token", &self.pound_token); - formatter.field("style", &self.style); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("meta", &self.meta); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::BareFnArg { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("BareFnArg"); - formatter.field("attrs", &self.attrs); - formatter.field("name", &self.name); - formatter.field("ty", &self.ty); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::BareVariadic { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("BareVariadic"); - formatter.field("attrs", &self.attrs); - formatter.field("name", &self.name); - formatter.field("dots", &self.dots); - formatter.field("comma", &self.comma); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::BinOp { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("BinOp::")?; - match self { - crate::BinOp::Add(v0) => { - let mut formatter = formatter.debug_tuple("Add"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Sub(v0) => { - let mut formatter = formatter.debug_tuple("Sub"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Mul(v0) => { - let mut formatter = formatter.debug_tuple("Mul"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Div(v0) => { - let mut formatter = formatter.debug_tuple("Div"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Rem(v0) => { - let mut formatter = formatter.debug_tuple("Rem"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::And(v0) => { - let mut formatter = formatter.debug_tuple("And"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Or(v0) => { - let mut formatter = formatter.debug_tuple("Or"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::BitXor(v0) => { - let mut formatter = formatter.debug_tuple("BitXor"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::BitAnd(v0) => { - let mut formatter = formatter.debug_tuple("BitAnd"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::BitOr(v0) => { - let mut formatter = formatter.debug_tuple("BitOr"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Shl(v0) => { - let mut formatter = formatter.debug_tuple("Shl"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Shr(v0) => { - let mut formatter = formatter.debug_tuple("Shr"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Eq(v0) => { - let mut formatter = formatter.debug_tuple("Eq"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Lt(v0) => { - let mut formatter = formatter.debug_tuple("Lt"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Le(v0) => { - let mut formatter = formatter.debug_tuple("Le"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Ne(v0) => { - let mut formatter = formatter.debug_tuple("Ne"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Ge(v0) => { - let mut formatter = formatter.debug_tuple("Ge"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::Gt(v0) => { - let mut formatter = formatter.debug_tuple("Gt"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::AddAssign(v0) => { - let mut formatter = formatter.debug_tuple("AddAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::SubAssign(v0) => { - let mut formatter = formatter.debug_tuple("SubAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::MulAssign(v0) => { - let mut formatter = formatter.debug_tuple("MulAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::DivAssign(v0) => { - let mut formatter = formatter.debug_tuple("DivAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::RemAssign(v0) => { - let mut formatter = formatter.debug_tuple("RemAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::BitXorAssign(v0) => { - let mut formatter = formatter.debug_tuple("BitXorAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::BitAndAssign(v0) => { - let mut formatter = formatter.debug_tuple("BitAndAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::BitOrAssign(v0) => { - let mut formatter = formatter.debug_tuple("BitOrAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::ShlAssign(v0) => { - let mut formatter = formatter.debug_tuple("ShlAssign"); - formatter.field(v0); - formatter.finish() - } - crate::BinOp::ShrAssign(v0) => { - let mut formatter = formatter.debug_tuple("ShrAssign"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Block { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Block"); - formatter.field("brace_token", &self.brace_token); - formatter.field("stmts", &self.stmts); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::BoundLifetimes { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("BoundLifetimes"); - formatter.field("for_token", &self.for_token); - formatter.field("lt_token", &self.lt_token); - formatter.field("lifetimes", &self.lifetimes); - formatter.field("gt_token", &self.gt_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::CapturedParam { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("CapturedParam::")?; - match self { - crate::CapturedParam::Lifetime(v0) => { - let mut formatter = formatter.debug_tuple("Lifetime"); - formatter.field(v0); - formatter.finish() - } - crate::CapturedParam::Ident(v0) => { - let mut formatter = formatter.debug_tuple("Ident"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ConstParam { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ConstParam"); - formatter.field("attrs", &self.attrs); - formatter.field("const_token", &self.const_token); - formatter.field("ident", &self.ident); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.field("eq_token", &self.eq_token); - formatter.field("default", &self.default); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Constraint { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Constraint"); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("colon_token", &self.colon_token); - formatter.field("bounds", &self.bounds); - formatter.finish() - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Data { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Data::")?; - match self { - crate::Data::Struct(v0) => v0.debug(formatter, "Struct"), - crate::Data::Enum(v0) => v0.debug(formatter, "Enum"), - crate::Data::Union(v0) => v0.debug(formatter, "Union"), - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::DataEnum { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "DataEnum") - } -} -#[cfg(feature = "derive")] -impl crate::DataEnum { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("enum_token", &self.enum_token); - formatter.field("brace_token", &self.brace_token); - formatter.field("variants", &self.variants); - formatter.finish() - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::DataStruct { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "DataStruct") - } -} -#[cfg(feature = "derive")] -impl crate::DataStruct { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("struct_token", &self.struct_token); - formatter.field("fields", &self.fields); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::DataUnion { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "DataUnion") - } -} -#[cfg(feature = "derive")] -impl crate::DataUnion { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("union_token", &self.union_token); - formatter.field("fields", &self.fields); - formatter.finish() - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::DeriveInput { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("DeriveInput"); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("data", &self.data); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Expr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Expr::")?; - match self { - #[cfg(feature = "full")] - crate::Expr::Array(v0) => v0.debug(formatter, "Array"), - #[cfg(feature = "full")] - crate::Expr::Assign(v0) => v0.debug(formatter, "Assign"), - #[cfg(feature = "full")] - crate::Expr::Async(v0) => v0.debug(formatter, "Async"), - #[cfg(feature = "full")] - crate::Expr::Await(v0) => v0.debug(formatter, "Await"), - crate::Expr::Binary(v0) => v0.debug(formatter, "Binary"), - #[cfg(feature = "full")] - crate::Expr::Block(v0) => v0.debug(formatter, "Block"), - #[cfg(feature = "full")] - crate::Expr::Break(v0) => v0.debug(formatter, "Break"), - crate::Expr::Call(v0) => v0.debug(formatter, "Call"), - crate::Expr::Cast(v0) => v0.debug(formatter, "Cast"), - #[cfg(feature = "full")] - crate::Expr::Closure(v0) => v0.debug(formatter, "Closure"), - #[cfg(feature = "full")] - crate::Expr::Const(v0) => v0.debug(formatter, "Const"), - #[cfg(feature = "full")] - crate::Expr::Continue(v0) => v0.debug(formatter, "Continue"), - crate::Expr::Field(v0) => v0.debug(formatter, "Field"), - #[cfg(feature = "full")] - crate::Expr::ForLoop(v0) => v0.debug(formatter, "ForLoop"), - crate::Expr::Group(v0) => v0.debug(formatter, "Group"), - #[cfg(feature = "full")] - crate::Expr::If(v0) => v0.debug(formatter, "If"), - crate::Expr::Index(v0) => v0.debug(formatter, "Index"), - #[cfg(feature = "full")] - crate::Expr::Infer(v0) => v0.debug(formatter, "Infer"), - #[cfg(feature = "full")] - crate::Expr::Let(v0) => v0.debug(formatter, "Let"), - crate::Expr::Lit(v0) => v0.debug(formatter, "Lit"), - #[cfg(feature = "full")] - crate::Expr::Loop(v0) => v0.debug(formatter, "Loop"), - crate::Expr::Macro(v0) => v0.debug(formatter, "Macro"), - #[cfg(feature = "full")] - crate::Expr::Match(v0) => v0.debug(formatter, "Match"), - crate::Expr::MethodCall(v0) => v0.debug(formatter, "MethodCall"), - crate::Expr::Paren(v0) => v0.debug(formatter, "Paren"), - crate::Expr::Path(v0) => v0.debug(formatter, "Path"), - #[cfg(feature = "full")] - crate::Expr::Range(v0) => v0.debug(formatter, "Range"), - #[cfg(feature = "full")] - crate::Expr::RawAddr(v0) => v0.debug(formatter, "RawAddr"), - crate::Expr::Reference(v0) => v0.debug(formatter, "Reference"), - #[cfg(feature = "full")] - crate::Expr::Repeat(v0) => v0.debug(formatter, "Repeat"), - #[cfg(feature = "full")] - crate::Expr::Return(v0) => v0.debug(formatter, "Return"), - crate::Expr::Struct(v0) => v0.debug(formatter, "Struct"), - #[cfg(feature = "full")] - crate::Expr::Try(v0) => v0.debug(formatter, "Try"), - #[cfg(feature = "full")] - crate::Expr::TryBlock(v0) => v0.debug(formatter, "TryBlock"), - crate::Expr::Tuple(v0) => v0.debug(formatter, "Tuple"), - crate::Expr::Unary(v0) => v0.debug(formatter, "Unary"), - #[cfg(feature = "full")] - crate::Expr::Unsafe(v0) => v0.debug(formatter, "Unsafe"), - crate::Expr::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - #[cfg(feature = "full")] - crate::Expr::While(v0) => v0.debug(formatter, "While"), - #[cfg(feature = "full")] - crate::Expr::Yield(v0) => v0.debug(formatter, "Yield"), - #[cfg(not(feature = "full"))] - _ => unreachable!(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprArray { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprArray") - } -} -#[cfg(feature = "full")] -impl crate::ExprArray { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("elems", &self.elems); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprAssign { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprAssign") - } -} -#[cfg(feature = "full")] -impl crate::ExprAssign { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("left", &self.left); - formatter.field("eq_token", &self.eq_token); - formatter.field("right", &self.right); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprAsync { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprAsync") - } -} -#[cfg(feature = "full")] -impl crate::ExprAsync { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("async_token", &self.async_token); - formatter.field("capture", &self.capture); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprAwait { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprAwait") - } -} -#[cfg(feature = "full")] -impl crate::ExprAwait { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("base", &self.base); - formatter.field("dot_token", &self.dot_token); - formatter.field("await_token", &self.await_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprBinary { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprBinary") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprBinary { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("left", &self.left); - formatter.field("op", &self.op); - formatter.field("right", &self.right); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprBlock { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprBlock") - } -} -#[cfg(feature = "full")] -impl crate::ExprBlock { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("label", &self.label); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprBreak { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprBreak") - } -} -#[cfg(feature = "full")] -impl crate::ExprBreak { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("break_token", &self.break_token); - formatter.field("label", &self.label); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprCall { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprCall") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprCall { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("func", &self.func); - formatter.field("paren_token", &self.paren_token); - formatter.field("args", &self.args); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprCast { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprCast") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprCast { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("expr", &self.expr); - formatter.field("as_token", &self.as_token); - formatter.field("ty", &self.ty); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprClosure { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprClosure") - } -} -#[cfg(feature = "full")] -impl crate::ExprClosure { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("lifetimes", &self.lifetimes); - formatter.field("constness", &self.constness); - formatter.field("movability", &self.movability); - formatter.field("asyncness", &self.asyncness); - formatter.field("capture", &self.capture); - formatter.field("or1_token", &self.or1_token); - formatter.field("inputs", &self.inputs); - formatter.field("or2_token", &self.or2_token); - formatter.field("output", &self.output); - formatter.field("body", &self.body); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprConst { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprConst") - } -} -#[cfg(feature = "full")] -impl crate::ExprConst { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("const_token", &self.const_token); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprContinue { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprContinue") - } -} -#[cfg(feature = "full")] -impl crate::ExprContinue { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("continue_token", &self.continue_token); - formatter.field("label", &self.label); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprField { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprField") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprField { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("base", &self.base); - formatter.field("dot_token", &self.dot_token); - formatter.field("member", &self.member); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprForLoop { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprForLoop") - } -} -#[cfg(feature = "full")] -impl crate::ExprForLoop { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("label", &self.label); - formatter.field("for_token", &self.for_token); - formatter.field("pat", &self.pat); - formatter.field("in_token", &self.in_token); - formatter.field("expr", &self.expr); - formatter.field("body", &self.body); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprGroup { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprGroup") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprGroup { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("group_token", &self.group_token); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprIf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprIf") - } -} -#[cfg(feature = "full")] -impl crate::ExprIf { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("if_token", &self.if_token); - formatter.field("cond", &self.cond); - formatter.field("then_branch", &self.then_branch); - formatter.field("else_branch", &self.else_branch); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprIndex { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprIndex") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprIndex { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("expr", &self.expr); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("index", &self.index); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprInfer { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprInfer") - } -} -#[cfg(feature = "full")] -impl crate::ExprInfer { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("underscore_token", &self.underscore_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprLet { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprLet") - } -} -#[cfg(feature = "full")] -impl crate::ExprLet { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("let_token", &self.let_token); - formatter.field("pat", &self.pat); - formatter.field("eq_token", &self.eq_token); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprLit { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprLit") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprLit { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("lit", &self.lit); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprLoop { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprLoop") - } -} -#[cfg(feature = "full")] -impl crate::ExprLoop { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("label", &self.label); - formatter.field("loop_token", &self.loop_token); - formatter.field("body", &self.body); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprMacro") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("mac", &self.mac); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprMatch { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprMatch") - } -} -#[cfg(feature = "full")] -impl crate::ExprMatch { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("match_token", &self.match_token); - formatter.field("expr", &self.expr); - formatter.field("brace_token", &self.brace_token); - formatter.field("arms", &self.arms); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprMethodCall { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprMethodCall") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprMethodCall { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("receiver", &self.receiver); - formatter.field("dot_token", &self.dot_token); - formatter.field("method", &self.method); - formatter.field("turbofish", &self.turbofish); - formatter.field("paren_token", &self.paren_token); - formatter.field("args", &self.args); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprParen { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprParen") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprParen { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("paren_token", &self.paren_token); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprPath { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprPath") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprPath { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("qself", &self.qself); - formatter.field("path", &self.path); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprRange { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprRange") - } -} -#[cfg(feature = "full")] -impl crate::ExprRange { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("start", &self.start); - formatter.field("limits", &self.limits); - formatter.field("end", &self.end); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprRawAddr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprRawAddr") - } -} -#[cfg(feature = "full")] -impl crate::ExprRawAddr { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("and_token", &self.and_token); - formatter.field("raw", &self.raw); - formatter.field("mutability", &self.mutability); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprReference { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprReference") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprReference { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("and_token", &self.and_token); - formatter.field("mutability", &self.mutability); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprRepeat { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprRepeat") - } -} -#[cfg(feature = "full")] -impl crate::ExprRepeat { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("expr", &self.expr); - formatter.field("semi_token", &self.semi_token); - formatter.field("len", &self.len); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprReturn { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprReturn") - } -} -#[cfg(feature = "full")] -impl crate::ExprReturn { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("return_token", &self.return_token); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprStruct { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprStruct") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprStruct { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("qself", &self.qself); - formatter.field("path", &self.path); - formatter.field("brace_token", &self.brace_token); - formatter.field("fields", &self.fields); - formatter.field("dot2_token", &self.dot2_token); - formatter.field("rest", &self.rest); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprTry { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprTry") - } -} -#[cfg(feature = "full")] -impl crate::ExprTry { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("expr", &self.expr); - formatter.field("question_token", &self.question_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprTryBlock { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprTryBlock") - } -} -#[cfg(feature = "full")] -impl crate::ExprTryBlock { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("try_token", &self.try_token); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprTuple { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprTuple") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprTuple { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("paren_token", &self.paren_token); - formatter.field("elems", &self.elems); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprUnary { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprUnary") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ExprUnary { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("op", &self.op); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprUnsafe { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprUnsafe") - } -} -#[cfg(feature = "full")] -impl crate::ExprUnsafe { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("unsafe_token", &self.unsafe_token); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprWhile { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprWhile") - } -} -#[cfg(feature = "full")] -impl crate::ExprWhile { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("label", &self.label); - formatter.field("while_token", &self.while_token); - formatter.field("cond", &self.cond); - formatter.field("body", &self.body); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ExprYield { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ExprYield") - } -} -#[cfg(feature = "full")] -impl crate::ExprYield { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("yield_token", &self.yield_token); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Field { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Field"); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("mutability", &self.mutability); - formatter.field("ident", &self.ident); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::FieldMutability { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("FieldMutability::")?; - match self { - crate::FieldMutability::None => formatter.write_str("None"), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::FieldPat { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("FieldPat"); - formatter.field("attrs", &self.attrs); - formatter.field("member", &self.member); - formatter.field("colon_token", &self.colon_token); - formatter.field("pat", &self.pat); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::FieldValue { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("FieldValue"); - formatter.field("attrs", &self.attrs); - formatter.field("member", &self.member); - formatter.field("colon_token", &self.colon_token); - formatter.field("expr", &self.expr); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Fields { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Fields::")?; - match self { - crate::Fields::Named(v0) => v0.debug(formatter, "Named"), - crate::Fields::Unnamed(v0) => v0.debug(formatter, "Unnamed"), - crate::Fields::Unit => formatter.write_str("Unit"), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::FieldsNamed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "FieldsNamed") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::FieldsNamed { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("brace_token", &self.brace_token); - formatter.field("named", &self.named); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::FieldsUnnamed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "FieldsUnnamed") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::FieldsUnnamed { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("paren_token", &self.paren_token); - formatter.field("unnamed", &self.unnamed); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::File { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("File"); - formatter.field("shebang", &self.shebang); - formatter.field("attrs", &self.attrs); - formatter.field("items", &self.items); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::FnArg { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("FnArg::")?; - match self { - crate::FnArg::Receiver(v0) => { - let mut formatter = formatter.debug_tuple("Receiver"); - formatter.field(v0); - formatter.finish() - } - crate::FnArg::Typed(v0) => { - let mut formatter = formatter.debug_tuple("Typed"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ForeignItem { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("ForeignItem::")?; - match self { - crate::ForeignItem::Fn(v0) => v0.debug(formatter, "Fn"), - crate::ForeignItem::Static(v0) => v0.debug(formatter, "Static"), - crate::ForeignItem::Type(v0) => v0.debug(formatter, "Type"), - crate::ForeignItem::Macro(v0) => v0.debug(formatter, "Macro"), - crate::ForeignItem::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ForeignItemFn { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ForeignItemFn") - } -} -#[cfg(feature = "full")] -impl crate::ForeignItemFn { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("sig", &self.sig); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ForeignItemMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ForeignItemMacro") - } -} -#[cfg(feature = "full")] -impl crate::ForeignItemMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("mac", &self.mac); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ForeignItemStatic { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ForeignItemStatic") - } -} -#[cfg(feature = "full")] -impl crate::ForeignItemStatic { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("static_token", &self.static_token); - formatter.field("mutability", &self.mutability); - formatter.field("ident", &self.ident); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ForeignItemType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ForeignItemType") - } -} -#[cfg(feature = "full")] -impl crate::ForeignItemType { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("type_token", &self.type_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::GenericArgument { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("GenericArgument::")?; - match self { - crate::GenericArgument::Lifetime(v0) => { - let mut formatter = formatter.debug_tuple("Lifetime"); - formatter.field(v0); - formatter.finish() - } - crate::GenericArgument::Type(v0) => { - let mut formatter = formatter.debug_tuple("Type"); - formatter.field(v0); - formatter.finish() - } - crate::GenericArgument::Const(v0) => { - let mut formatter = formatter.debug_tuple("Const"); - formatter.field(v0); - formatter.finish() - } - crate::GenericArgument::AssocType(v0) => { - let mut formatter = formatter.debug_tuple("AssocType"); - formatter.field(v0); - formatter.finish() - } - crate::GenericArgument::AssocConst(v0) => { - let mut formatter = formatter.debug_tuple("AssocConst"); - formatter.field(v0); - formatter.finish() - } - crate::GenericArgument::Constraint(v0) => { - let mut formatter = formatter.debug_tuple("Constraint"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::GenericParam { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("GenericParam::")?; - match self { - crate::GenericParam::Lifetime(v0) => { - let mut formatter = formatter.debug_tuple("Lifetime"); - formatter.field(v0); - formatter.finish() - } - crate::GenericParam::Type(v0) => { - let mut formatter = formatter.debug_tuple("Type"); - formatter.field(v0); - formatter.finish() - } - crate::GenericParam::Const(v0) => { - let mut formatter = formatter.debug_tuple("Const"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Generics { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Generics"); - formatter.field("lt_token", &self.lt_token); - formatter.field("params", &self.params); - formatter.field("gt_token", &self.gt_token); - formatter.field("where_clause", &self.where_clause); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ImplItem { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("ImplItem::")?; - match self { - crate::ImplItem::Const(v0) => v0.debug(formatter, "Const"), - crate::ImplItem::Fn(v0) => v0.debug(formatter, "Fn"), - crate::ImplItem::Type(v0) => v0.debug(formatter, "Type"), - crate::ImplItem::Macro(v0) => v0.debug(formatter, "Macro"), - crate::ImplItem::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ImplItemConst { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ImplItemConst") - } -} -#[cfg(feature = "full")] -impl crate::ImplItemConst { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("defaultness", &self.defaultness); - formatter.field("const_token", &self.const_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.field("eq_token", &self.eq_token); - formatter.field("expr", &self.expr); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ImplItemFn { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ImplItemFn") - } -} -#[cfg(feature = "full")] -impl crate::ImplItemFn { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("defaultness", &self.defaultness); - formatter.field("sig", &self.sig); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ImplItemMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ImplItemMacro") - } -} -#[cfg(feature = "full")] -impl crate::ImplItemMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("mac", &self.mac); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ImplItemType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ImplItemType") - } -} -#[cfg(feature = "full")] -impl crate::ImplItemType { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("defaultness", &self.defaultness); - formatter.field("type_token", &self.type_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("eq_token", &self.eq_token); - formatter.field("ty", &self.ty); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ImplRestriction { - fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { - match *self {} - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Index { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Index"); - formatter.field("index", &self.index); - formatter.field("span", &self.span); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Item { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Item::")?; - match self { - crate::Item::Const(v0) => v0.debug(formatter, "Const"), - crate::Item::Enum(v0) => v0.debug(formatter, "Enum"), - crate::Item::ExternCrate(v0) => v0.debug(formatter, "ExternCrate"), - crate::Item::Fn(v0) => v0.debug(formatter, "Fn"), - crate::Item::ForeignMod(v0) => v0.debug(formatter, "ForeignMod"), - crate::Item::Impl(v0) => v0.debug(formatter, "Impl"), - crate::Item::Macro(v0) => v0.debug(formatter, "Macro"), - crate::Item::Mod(v0) => v0.debug(formatter, "Mod"), - crate::Item::Static(v0) => v0.debug(formatter, "Static"), - crate::Item::Struct(v0) => v0.debug(formatter, "Struct"), - crate::Item::Trait(v0) => v0.debug(formatter, "Trait"), - crate::Item::TraitAlias(v0) => v0.debug(formatter, "TraitAlias"), - crate::Item::Type(v0) => v0.debug(formatter, "Type"), - crate::Item::Union(v0) => v0.debug(formatter, "Union"), - crate::Item::Use(v0) => v0.debug(formatter, "Use"), - crate::Item::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemConst { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemConst") - } -} -#[cfg(feature = "full")] -impl crate::ItemConst { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("const_token", &self.const_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.field("eq_token", &self.eq_token); - formatter.field("expr", &self.expr); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemEnum { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemEnum") - } -} -#[cfg(feature = "full")] -impl crate::ItemEnum { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("enum_token", &self.enum_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("brace_token", &self.brace_token); - formatter.field("variants", &self.variants); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemExternCrate { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemExternCrate") - } -} -#[cfg(feature = "full")] -impl crate::ItemExternCrate { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("extern_token", &self.extern_token); - formatter.field("crate_token", &self.crate_token); - formatter.field("ident", &self.ident); - formatter.field("rename", &self.rename); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemFn { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemFn") - } -} -#[cfg(feature = "full")] -impl crate::ItemFn { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("sig", &self.sig); - formatter.field("block", &self.block); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemForeignMod { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemForeignMod") - } -} -#[cfg(feature = "full")] -impl crate::ItemForeignMod { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("unsafety", &self.unsafety); - formatter.field("abi", &self.abi); - formatter.field("brace_token", &self.brace_token); - formatter.field("items", &self.items); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemImpl { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemImpl") - } -} -#[cfg(feature = "full")] -impl crate::ItemImpl { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("defaultness", &self.defaultness); - formatter.field("unsafety", &self.unsafety); - formatter.field("impl_token", &self.impl_token); - formatter.field("generics", &self.generics); - formatter.field("trait_", &self.trait_); - formatter.field("self_ty", &self.self_ty); - formatter.field("brace_token", &self.brace_token); - formatter.field("items", &self.items); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemMacro") - } -} -#[cfg(feature = "full")] -impl crate::ItemMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("ident", &self.ident); - formatter.field("mac", &self.mac); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemMod { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemMod") - } -} -#[cfg(feature = "full")] -impl crate::ItemMod { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("unsafety", &self.unsafety); - formatter.field("mod_token", &self.mod_token); - formatter.field("ident", &self.ident); - formatter.field("content", &self.content); - formatter.field("semi", &self.semi); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemStatic { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemStatic") - } -} -#[cfg(feature = "full")] -impl crate::ItemStatic { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("static_token", &self.static_token); - formatter.field("mutability", &self.mutability); - formatter.field("ident", &self.ident); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.field("eq_token", &self.eq_token); - formatter.field("expr", &self.expr); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemStruct { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemStruct") - } -} -#[cfg(feature = "full")] -impl crate::ItemStruct { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("struct_token", &self.struct_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("fields", &self.fields); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemTrait { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemTrait") - } -} -#[cfg(feature = "full")] -impl crate::ItemTrait { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("unsafety", &self.unsafety); - formatter.field("auto_token", &self.auto_token); - formatter.field("restriction", &self.restriction); - formatter.field("trait_token", &self.trait_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("colon_token", &self.colon_token); - formatter.field("supertraits", &self.supertraits); - formatter.field("brace_token", &self.brace_token); - formatter.field("items", &self.items); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemTraitAlias { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemTraitAlias") - } -} -#[cfg(feature = "full")] -impl crate::ItemTraitAlias { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("trait_token", &self.trait_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("eq_token", &self.eq_token); - formatter.field("bounds", &self.bounds); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemType") - } -} -#[cfg(feature = "full")] -impl crate::ItemType { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("type_token", &self.type_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("eq_token", &self.eq_token); - formatter.field("ty", &self.ty); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemUnion { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemUnion") - } -} -#[cfg(feature = "full")] -impl crate::ItemUnion { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("union_token", &self.union_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("fields", &self.fields); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ItemUse { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ItemUse") - } -} -#[cfg(feature = "full")] -impl crate::ItemUse { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("vis", &self.vis); - formatter.field("use_token", &self.use_token); - formatter.field("leading_colon", &self.leading_colon); - formatter.field("tree", &self.tree); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Label { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Label"); - formatter.field("name", &self.name); - formatter.field("colon_token", &self.colon_token); - formatter.finish() - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Lifetime { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "Lifetime") - } -} -impl crate::Lifetime { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("apostrophe", &self.apostrophe); - formatter.field("ident", &self.ident); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::LifetimeParam { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("LifetimeParam"); - formatter.field("attrs", &self.attrs); - formatter.field("lifetime", &self.lifetime); - formatter.field("colon_token", &self.colon_token); - formatter.field("bounds", &self.bounds); - formatter.finish() - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Lit { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Lit::")?; - match self { - crate::Lit::Str(v0) => v0.debug(formatter, "Str"), - crate::Lit::ByteStr(v0) => v0.debug(formatter, "ByteStr"), - crate::Lit::CStr(v0) => v0.debug(formatter, "CStr"), - crate::Lit::Byte(v0) => v0.debug(formatter, "Byte"), - crate::Lit::Char(v0) => v0.debug(formatter, "Char"), - crate::Lit::Int(v0) => v0.debug(formatter, "Int"), - crate::Lit::Float(v0) => v0.debug(formatter, "Float"), - crate::Lit::Bool(v0) => v0.debug(formatter, "Bool"), - crate::Lit::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Local { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "Local") - } -} -#[cfg(feature = "full")] -impl crate::Local { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("let_token", &self.let_token); - formatter.field("pat", &self.pat); - formatter.field("init", &self.init); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::LocalInit { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("LocalInit"); - formatter.field("eq_token", &self.eq_token); - formatter.field("expr", &self.expr); - formatter.field("diverge", &self.diverge); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Macro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Macro"); - formatter.field("path", &self.path); - formatter.field("bang_token", &self.bang_token); - formatter.field("delimiter", &self.delimiter); - formatter.field("tokens", &self.tokens); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::MacroDelimiter { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("MacroDelimiter::")?; - match self { - crate::MacroDelimiter::Paren(v0) => { - let mut formatter = formatter.debug_tuple("Paren"); - formatter.field(v0); - formatter.finish() - } - crate::MacroDelimiter::Brace(v0) => { - let mut formatter = formatter.debug_tuple("Brace"); - formatter.field(v0); - formatter.finish() - } - crate::MacroDelimiter::Bracket(v0) => { - let mut formatter = formatter.debug_tuple("Bracket"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Member { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Member::")?; - match self { - crate::Member::Named(v0) => { - let mut formatter = formatter.debug_tuple("Named"); - formatter.field(v0); - formatter.finish() - } - crate::Member::Unnamed(v0) => { - let mut formatter = formatter.debug_tuple("Unnamed"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Meta { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Meta::")?; - match self { - crate::Meta::Path(v0) => v0.debug(formatter, "Path"), - crate::Meta::List(v0) => v0.debug(formatter, "List"), - crate::Meta::NameValue(v0) => v0.debug(formatter, "NameValue"), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::MetaList { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "MetaList") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::MetaList { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("path", &self.path); - formatter.field("delimiter", &self.delimiter); - formatter.field("tokens", &self.tokens); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::MetaNameValue { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "MetaNameValue") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::MetaNameValue { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("path", &self.path); - formatter.field("eq_token", &self.eq_token); - formatter.field("value", &self.value); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ParenthesizedGenericArguments { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "ParenthesizedGenericArguments") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::ParenthesizedGenericArguments { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("paren_token", &self.paren_token); - formatter.field("inputs", &self.inputs); - formatter.field("output", &self.output); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Pat { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Pat::")?; - match self { - crate::Pat::Const(v0) => v0.debug(formatter, "Const"), - crate::Pat::Ident(v0) => v0.debug(formatter, "Ident"), - crate::Pat::Lit(v0) => v0.debug(formatter, "Lit"), - crate::Pat::Macro(v0) => v0.debug(formatter, "Macro"), - crate::Pat::Or(v0) => v0.debug(formatter, "Or"), - crate::Pat::Paren(v0) => v0.debug(formatter, "Paren"), - crate::Pat::Path(v0) => v0.debug(formatter, "Path"), - crate::Pat::Range(v0) => v0.debug(formatter, "Range"), - crate::Pat::Reference(v0) => v0.debug(formatter, "Reference"), - crate::Pat::Rest(v0) => v0.debug(formatter, "Rest"), - crate::Pat::Slice(v0) => v0.debug(formatter, "Slice"), - crate::Pat::Struct(v0) => v0.debug(formatter, "Struct"), - crate::Pat::Tuple(v0) => v0.debug(formatter, "Tuple"), - crate::Pat::TupleStruct(v0) => v0.debug(formatter, "TupleStruct"), - crate::Pat::Type(v0) => v0.debug(formatter, "Type"), - crate::Pat::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - crate::Pat::Wild(v0) => v0.debug(formatter, "Wild"), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatIdent { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatIdent") - } -} -#[cfg(feature = "full")] -impl crate::PatIdent { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("by_ref", &self.by_ref); - formatter.field("mutability", &self.mutability); - formatter.field("ident", &self.ident); - formatter.field("subpat", &self.subpat); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatOr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatOr") - } -} -#[cfg(feature = "full")] -impl crate::PatOr { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("leading_vert", &self.leading_vert); - formatter.field("cases", &self.cases); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatParen { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatParen") - } -} -#[cfg(feature = "full")] -impl crate::PatParen { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("paren_token", &self.paren_token); - formatter.field("pat", &self.pat); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatReference { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatReference") - } -} -#[cfg(feature = "full")] -impl crate::PatReference { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("and_token", &self.and_token); - formatter.field("mutability", &self.mutability); - formatter.field("pat", &self.pat); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatRest { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatRest") - } -} -#[cfg(feature = "full")] -impl crate::PatRest { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("dot2_token", &self.dot2_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatSlice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatSlice") - } -} -#[cfg(feature = "full")] -impl crate::PatSlice { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("elems", &self.elems); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatStruct { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatStruct") - } -} -#[cfg(feature = "full")] -impl crate::PatStruct { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("qself", &self.qself); - formatter.field("path", &self.path); - formatter.field("brace_token", &self.brace_token); - formatter.field("fields", &self.fields); - formatter.field("rest", &self.rest); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatTuple { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatTuple") - } -} -#[cfg(feature = "full")] -impl crate::PatTuple { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("paren_token", &self.paren_token); - formatter.field("elems", &self.elems); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatTupleStruct { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatTupleStruct") - } -} -#[cfg(feature = "full")] -impl crate::PatTupleStruct { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("qself", &self.qself); - formatter.field("path", &self.path); - formatter.field("paren_token", &self.paren_token); - formatter.field("elems", &self.elems); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatType") - } -} -#[cfg(feature = "full")] -impl crate::PatType { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("pat", &self.pat); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PatWild { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "PatWild") - } -} -#[cfg(feature = "full")] -impl crate::PatWild { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("underscore_token", &self.underscore_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Path { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "Path") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::Path { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("leading_colon", &self.leading_colon); - formatter.field("segments", &self.segments); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PathArguments { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("PathArguments::")?; - match self { - crate::PathArguments::None => formatter.write_str("None"), - crate::PathArguments::AngleBracketed(v0) => { - v0.debug(formatter, "AngleBracketed") - } - crate::PathArguments::Parenthesized(v0) => { - v0.debug(formatter, "Parenthesized") - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PathSegment { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PathSegment"); - formatter.field("ident", &self.ident); - formatter.field("arguments", &self.arguments); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PointerMutability { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("PointerMutability::")?; - match self { - crate::PointerMutability::Const(v0) => { - let mut formatter = formatter.debug_tuple("Const"); - formatter.field(v0); - formatter.finish() - } - crate::PointerMutability::Mut(v0) => { - let mut formatter = formatter.debug_tuple("Mut"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PreciseCapture { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PreciseCapture"); - formatter.field("use_token", &self.use_token); - formatter.field("lt_token", &self.lt_token); - formatter.field("params", &self.params); - formatter.field("gt_token", &self.gt_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PredicateLifetime { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PredicateLifetime"); - formatter.field("lifetime", &self.lifetime); - formatter.field("colon_token", &self.colon_token); - formatter.field("bounds", &self.bounds); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::PredicateType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PredicateType"); - formatter.field("lifetimes", &self.lifetimes); - formatter.field("bounded_ty", &self.bounded_ty); - formatter.field("colon_token", &self.colon_token); - formatter.field("bounds", &self.bounds); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::QSelf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("QSelf"); - formatter.field("lt_token", &self.lt_token); - formatter.field("ty", &self.ty); - formatter.field("position", &self.position); - formatter.field("as_token", &self.as_token); - formatter.field("gt_token", &self.gt_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::RangeLimits { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("RangeLimits::")?; - match self { - crate::RangeLimits::HalfOpen(v0) => { - let mut formatter = formatter.debug_tuple("HalfOpen"); - formatter.field(v0); - formatter.finish() - } - crate::RangeLimits::Closed(v0) => { - let mut formatter = formatter.debug_tuple("Closed"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Receiver { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Receiver"); - formatter.field("attrs", &self.attrs); - formatter.field("reference", &self.reference); - formatter.field("mutability", &self.mutability); - formatter.field("self_token", &self.self_token); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::ReturnType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("ReturnType::")?; - match self { - crate::ReturnType::Default => formatter.write_str("Default"), - crate::ReturnType::Type(v0, v1) => { - let mut formatter = formatter.debug_tuple("Type"); - formatter.field(v0); - formatter.field(v1); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Signature { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Signature"); - formatter.field("constness", &self.constness); - formatter.field("asyncness", &self.asyncness); - formatter.field("unsafety", &self.unsafety); - formatter.field("abi", &self.abi); - formatter.field("fn_token", &self.fn_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("paren_token", &self.paren_token); - formatter.field("inputs", &self.inputs); - formatter.field("variadic", &self.variadic); - formatter.field("output", &self.output); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::StaticMutability { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("StaticMutability::")?; - match self { - crate::StaticMutability::Mut(v0) => { - let mut formatter = formatter.debug_tuple("Mut"); - formatter.field(v0); - formatter.finish() - } - crate::StaticMutability::None => formatter.write_str("None"), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Stmt { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Stmt::")?; - match self { - crate::Stmt::Local(v0) => v0.debug(formatter, "Local"), - crate::Stmt::Item(v0) => { - let mut formatter = formatter.debug_tuple("Item"); - formatter.field(v0); - formatter.finish() - } - crate::Stmt::Expr(v0, v1) => { - let mut formatter = formatter.debug_tuple("Expr"); - formatter.field(v0); - formatter.field(v1); - formatter.finish() - } - crate::Stmt::Macro(v0) => v0.debug(formatter, "Macro"), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::StmtMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "StmtMacro") - } -} -#[cfg(feature = "full")] -impl crate::StmtMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("mac", &self.mac); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitBound { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TraitBound"); - formatter.field("paren_token", &self.paren_token); - formatter.field("modifier", &self.modifier); - formatter.field("lifetimes", &self.lifetimes); - formatter.field("path", &self.path); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitBoundModifier { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("TraitBoundModifier::")?; - match self { - crate::TraitBoundModifier::None => formatter.write_str("None"), - crate::TraitBoundModifier::Maybe(v0) => { - let mut formatter = formatter.debug_tuple("Maybe"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitItem { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("TraitItem::")?; - match self { - crate::TraitItem::Const(v0) => v0.debug(formatter, "Const"), - crate::TraitItem::Fn(v0) => v0.debug(formatter, "Fn"), - crate::TraitItem::Type(v0) => v0.debug(formatter, "Type"), - crate::TraitItem::Macro(v0) => v0.debug(formatter, "Macro"), - crate::TraitItem::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitItemConst { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TraitItemConst") - } -} -#[cfg(feature = "full")] -impl crate::TraitItemConst { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("const_token", &self.const_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("colon_token", &self.colon_token); - formatter.field("ty", &self.ty); - formatter.field("default", &self.default); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitItemFn { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TraitItemFn") - } -} -#[cfg(feature = "full")] -impl crate::TraitItemFn { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("sig", &self.sig); - formatter.field("default", &self.default); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitItemMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TraitItemMacro") - } -} -#[cfg(feature = "full")] -impl crate::TraitItemMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("mac", &self.mac); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TraitItemType { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TraitItemType") - } -} -#[cfg(feature = "full")] -impl crate::TraitItemType { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("attrs", &self.attrs); - formatter.field("type_token", &self.type_token); - formatter.field("ident", &self.ident); - formatter.field("generics", &self.generics); - formatter.field("colon_token", &self.colon_token); - formatter.field("bounds", &self.bounds); - formatter.field("default", &self.default); - formatter.field("semi_token", &self.semi_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Type { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Type::")?; - match self { - crate::Type::Array(v0) => v0.debug(formatter, "Array"), - crate::Type::BareFn(v0) => v0.debug(formatter, "BareFn"), - crate::Type::Group(v0) => v0.debug(formatter, "Group"), - crate::Type::ImplTrait(v0) => v0.debug(formatter, "ImplTrait"), - crate::Type::Infer(v0) => v0.debug(formatter, "Infer"), - crate::Type::Macro(v0) => v0.debug(formatter, "Macro"), - crate::Type::Never(v0) => v0.debug(formatter, "Never"), - crate::Type::Paren(v0) => v0.debug(formatter, "Paren"), - crate::Type::Path(v0) => v0.debug(formatter, "Path"), - crate::Type::Ptr(v0) => v0.debug(formatter, "Ptr"), - crate::Type::Reference(v0) => v0.debug(formatter, "Reference"), - crate::Type::Slice(v0) => v0.debug(formatter, "Slice"), - crate::Type::TraitObject(v0) => v0.debug(formatter, "TraitObject"), - crate::Type::Tuple(v0) => v0.debug(formatter, "Tuple"), - crate::Type::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeArray { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeArray") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeArray { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("elem", &self.elem); - formatter.field("semi_token", &self.semi_token); - formatter.field("len", &self.len); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeBareFn { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeBareFn") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeBareFn { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("lifetimes", &self.lifetimes); - formatter.field("unsafety", &self.unsafety); - formatter.field("abi", &self.abi); - formatter.field("fn_token", &self.fn_token); - formatter.field("paren_token", &self.paren_token); - formatter.field("inputs", &self.inputs); - formatter.field("variadic", &self.variadic); - formatter.field("output", &self.output); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeGroup { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeGroup") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeGroup { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("group_token", &self.group_token); - formatter.field("elem", &self.elem); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeImplTrait { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeImplTrait") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeImplTrait { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("impl_token", &self.impl_token); - formatter.field("bounds", &self.bounds); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeInfer { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeInfer") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeInfer { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("underscore_token", &self.underscore_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeMacro { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeMacro") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeMacro { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("mac", &self.mac); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeNever { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeNever") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeNever { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("bang_token", &self.bang_token); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeParam { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeParam"); - formatter.field("attrs", &self.attrs); - formatter.field("ident", &self.ident); - formatter.field("colon_token", &self.colon_token); - formatter.field("bounds", &self.bounds); - formatter.field("eq_token", &self.eq_token); - formatter.field("default", &self.default); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeParamBound { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("TypeParamBound::")?; - match self { - crate::TypeParamBound::Trait(v0) => { - let mut formatter = formatter.debug_tuple("Trait"); - formatter.field(v0); - formatter.finish() - } - crate::TypeParamBound::Lifetime(v0) => v0.debug(formatter, "Lifetime"), - #[cfg(feature = "full")] - crate::TypeParamBound::PreciseCapture(v0) => { - let mut formatter = formatter.debug_tuple("PreciseCapture"); - formatter.field(v0); - formatter.finish() - } - crate::TypeParamBound::Verbatim(v0) => { - let mut formatter = formatter.debug_tuple("Verbatim"); - formatter.field(v0); - formatter.finish() - } - #[cfg(not(feature = "full"))] - _ => unreachable!(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeParen { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeParen") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeParen { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("paren_token", &self.paren_token); - formatter.field("elem", &self.elem); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypePath { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypePath") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypePath { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("qself", &self.qself); - formatter.field("path", &self.path); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypePtr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypePtr") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypePtr { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("star_token", &self.star_token); - formatter.field("const_token", &self.const_token); - formatter.field("mutability", &self.mutability); - formatter.field("elem", &self.elem); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeReference { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeReference") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeReference { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("and_token", &self.and_token); - formatter.field("lifetime", &self.lifetime); - formatter.field("mutability", &self.mutability); - formatter.field("elem", &self.elem); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeSlice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeSlice") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeSlice { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("bracket_token", &self.bracket_token); - formatter.field("elem", &self.elem); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeTraitObject { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeTraitObject") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeTraitObject { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("dyn_token", &self.dyn_token); - formatter.field("bounds", &self.bounds); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::TypeTuple { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "TypeTuple") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::TypeTuple { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("paren_token", &self.paren_token); - formatter.field("elems", &self.elems); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UnOp { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("UnOp::")?; - match self { - crate::UnOp::Deref(v0) => { - let mut formatter = formatter.debug_tuple("Deref"); - formatter.field(v0); - formatter.finish() - } - crate::UnOp::Not(v0) => { - let mut formatter = formatter.debug_tuple("Not"); - formatter.field(v0); - formatter.finish() - } - crate::UnOp::Neg(v0) => { - let mut formatter = formatter.debug_tuple("Neg"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UseGlob { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseGlob"); - formatter.field("star_token", &self.star_token); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UseGroup { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseGroup"); - formatter.field("brace_token", &self.brace_token); - formatter.field("items", &self.items); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UseName { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseName"); - formatter.field("ident", &self.ident); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UsePath { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UsePath"); - formatter.field("ident", &self.ident); - formatter.field("colon2_token", &self.colon2_token); - formatter.field("tree", &self.tree); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UseRename { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseRename"); - formatter.field("ident", &self.ident); - formatter.field("as_token", &self.as_token); - formatter.field("rename", &self.rename); - formatter.finish() - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::UseTree { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("UseTree::")?; - match self { - crate::UseTree::Path(v0) => { - let mut formatter = formatter.debug_tuple("Path"); - formatter.field(v0); - formatter.finish() - } - crate::UseTree::Name(v0) => { - let mut formatter = formatter.debug_tuple("Name"); - formatter.field(v0); - formatter.finish() - } - crate::UseTree::Rename(v0) => { - let mut formatter = formatter.debug_tuple("Rename"); - formatter.field(v0); - formatter.finish() - } - crate::UseTree::Glob(v0) => { - let mut formatter = formatter.debug_tuple("Glob"); - formatter.field(v0); - formatter.finish() - } - crate::UseTree::Group(v0) => { - let mut formatter = formatter.debug_tuple("Group"); - formatter.field(v0); - formatter.finish() - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Variadic { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Variadic"); - formatter.field("attrs", &self.attrs); - formatter.field("pat", &self.pat); - formatter.field("dots", &self.dots); - formatter.field("comma", &self.comma); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Variant { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Variant"); - formatter.field("attrs", &self.attrs); - formatter.field("ident", &self.ident); - formatter.field("fields", &self.fields); - formatter.field("discriminant", &self.discriminant); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::VisRestricted { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "VisRestricted") - } -} -#[cfg(any(feature = "derive", feature = "full"))] -impl crate::VisRestricted { - fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - let mut formatter = formatter.debug_struct(name); - formatter.field("pub_token", &self.pub_token); - formatter.field("paren_token", &self.paren_token); - formatter.field("in_token", &self.in_token); - formatter.field("path", &self.path); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::Visibility { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Visibility::")?; - match self { - crate::Visibility::Public(v0) => { - let mut formatter = formatter.debug_tuple("Public"); - formatter.field(v0); - formatter.finish() - } - crate::Visibility::Restricted(v0) => v0.debug(formatter, "Restricted"), - crate::Visibility::Inherited => formatter.write_str("Inherited"), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::WhereClause { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("WhereClause"); - formatter.field("where_token", &self.where_token); - formatter.field("predicates", &self.predicates); - formatter.finish() - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for crate::WherePredicate { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("WherePredicate::")?; - match self { - crate::WherePredicate::Lifetime(v0) => { - let mut formatter = formatter.debug_tuple("Lifetime"); - formatter.field(v0); - formatter.finish() - } - crate::WherePredicate::Type(v0) => { - let mut formatter = formatter.debug_tuple("Type"); - formatter.field(v0); - formatter.finish() - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/gen/eq.rs b/deps/crates/vendor/syn-v2/src/gen/eq.rs deleted file mode 100644 index 5ba15722b7bc..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/eq.rs +++ /dev/null @@ -1,2308 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#[cfg(any(feature = "derive", feature = "full"))] -use crate::tt::TokenStreamHelper; -#[cfg(feature = "extra-traits")] -use alloc::string::ToString; -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Abi {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Abi { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::AngleBracketedGenericArguments {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::AngleBracketedGenericArguments { - fn eq(&self, other: &Self) -> bool { - self.colon2_token == other.colon2_token && self.args == other.args - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Arm {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Arm { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.pat == other.pat && self.guard == other.guard - && self.body == other.body && self.comma == other.comma - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::AssocConst {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::AssocConst { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident && self.generics == other.generics - && self.value == other.value - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::AssocType {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::AssocType { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident && self.generics == other.generics - && self.ty == other.ty - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::AttrStyle {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::AttrStyle { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::AttrStyle::Outer, crate::AttrStyle::Outer) => true, - (crate::AttrStyle::Inner(_), crate::AttrStyle::Inner(_)) => true, - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Attribute {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Attribute { - fn eq(&self, other: &Self) -> bool { - self.style == other.style && self.meta == other.meta - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::BareFnArg {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::BareFnArg { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.name == other.name && self.ty == other.ty - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::BareVariadic {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::BareVariadic { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.name == other.name && self.comma == other.comma - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::BinOp {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::BinOp { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::BinOp::Add(_), crate::BinOp::Add(_)) => true, - (crate::BinOp::Sub(_), crate::BinOp::Sub(_)) => true, - (crate::BinOp::Mul(_), crate::BinOp::Mul(_)) => true, - (crate::BinOp::Div(_), crate::BinOp::Div(_)) => true, - (crate::BinOp::Rem(_), crate::BinOp::Rem(_)) => true, - (crate::BinOp::And(_), crate::BinOp::And(_)) => true, - (crate::BinOp::Or(_), crate::BinOp::Or(_)) => true, - (crate::BinOp::BitXor(_), crate::BinOp::BitXor(_)) => true, - (crate::BinOp::BitAnd(_), crate::BinOp::BitAnd(_)) => true, - (crate::BinOp::BitOr(_), crate::BinOp::BitOr(_)) => true, - (crate::BinOp::Shl(_), crate::BinOp::Shl(_)) => true, - (crate::BinOp::Shr(_), crate::BinOp::Shr(_)) => true, - (crate::BinOp::Eq(_), crate::BinOp::Eq(_)) => true, - (crate::BinOp::Lt(_), crate::BinOp::Lt(_)) => true, - (crate::BinOp::Le(_), crate::BinOp::Le(_)) => true, - (crate::BinOp::Ne(_), crate::BinOp::Ne(_)) => true, - (crate::BinOp::Ge(_), crate::BinOp::Ge(_)) => true, - (crate::BinOp::Gt(_), crate::BinOp::Gt(_)) => true, - (crate::BinOp::AddAssign(_), crate::BinOp::AddAssign(_)) => true, - (crate::BinOp::SubAssign(_), crate::BinOp::SubAssign(_)) => true, - (crate::BinOp::MulAssign(_), crate::BinOp::MulAssign(_)) => true, - (crate::BinOp::DivAssign(_), crate::BinOp::DivAssign(_)) => true, - (crate::BinOp::RemAssign(_), crate::BinOp::RemAssign(_)) => true, - (crate::BinOp::BitXorAssign(_), crate::BinOp::BitXorAssign(_)) => true, - (crate::BinOp::BitAndAssign(_), crate::BinOp::BitAndAssign(_)) => true, - (crate::BinOp::BitOrAssign(_), crate::BinOp::BitOrAssign(_)) => true, - (crate::BinOp::ShlAssign(_), crate::BinOp::ShlAssign(_)) => true, - (crate::BinOp::ShrAssign(_), crate::BinOp::ShrAssign(_)) => true, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Block {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Block { - fn eq(&self, other: &Self) -> bool { - self.stmts == other.stmts - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::BoundLifetimes {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::BoundLifetimes { - fn eq(&self, other: &Self) -> bool { - self.lifetimes == other.lifetimes - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::CapturedParam {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::CapturedParam { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - crate::CapturedParam::Lifetime(self0), - crate::CapturedParam::Lifetime(other0), - ) => self0 == other0, - (crate::CapturedParam::Ident(self0), crate::CapturedParam::Ident(other0)) => { - self0 == other0 - } - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ConstParam {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ConstParam { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.ident == other.ident && self.ty == other.ty - && self.eq_token == other.eq_token && self.default == other.default - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Constraint {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Constraint { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident && self.generics == other.generics - && self.bounds == other.bounds - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Data {} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Data { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Data::Struct(self0), crate::Data::Struct(other0)) => self0 == other0, - (crate::Data::Enum(self0), crate::Data::Enum(other0)) => self0 == other0, - (crate::Data::Union(self0), crate::Data::Union(other0)) => self0 == other0, - _ => false, - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::DataEnum {} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::DataEnum { - fn eq(&self, other: &Self) -> bool { - self.variants == other.variants - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::DataStruct {} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::DataStruct { - fn eq(&self, other: &Self) -> bool { - self.fields == other.fields && self.semi_token == other.semi_token - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::DataUnion {} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::DataUnion { - fn eq(&self, other: &Self) -> bool { - self.fields == other.fields - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::DeriveInput {} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::DeriveInput { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.data == other.data - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Expr {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Expr { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - #[cfg(feature = "full")] - (crate::Expr::Array(self0), crate::Expr::Array(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Assign(self0), crate::Expr::Assign(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Async(self0), crate::Expr::Async(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Await(self0), crate::Expr::Await(other0)) => self0 == other0, - (crate::Expr::Binary(self0), crate::Expr::Binary(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Block(self0), crate::Expr::Block(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Break(self0), crate::Expr::Break(other0)) => self0 == other0, - (crate::Expr::Call(self0), crate::Expr::Call(other0)) => self0 == other0, - (crate::Expr::Cast(self0), crate::Expr::Cast(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Closure(self0), crate::Expr::Closure(other0)) => { - self0 == other0 - } - #[cfg(feature = "full")] - (crate::Expr::Const(self0), crate::Expr::Const(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Continue(self0), crate::Expr::Continue(other0)) => { - self0 == other0 - } - (crate::Expr::Field(self0), crate::Expr::Field(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::ForLoop(self0), crate::Expr::ForLoop(other0)) => { - self0 == other0 - } - (crate::Expr::Group(self0), crate::Expr::Group(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::If(self0), crate::Expr::If(other0)) => self0 == other0, - (crate::Expr::Index(self0), crate::Expr::Index(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Infer(self0), crate::Expr::Infer(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Let(self0), crate::Expr::Let(other0)) => self0 == other0, - (crate::Expr::Lit(self0), crate::Expr::Lit(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Loop(self0), crate::Expr::Loop(other0)) => self0 == other0, - (crate::Expr::Macro(self0), crate::Expr::Macro(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Match(self0), crate::Expr::Match(other0)) => self0 == other0, - (crate::Expr::MethodCall(self0), crate::Expr::MethodCall(other0)) => { - self0 == other0 - } - (crate::Expr::Paren(self0), crate::Expr::Paren(other0)) => self0 == other0, - (crate::Expr::Path(self0), crate::Expr::Path(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Range(self0), crate::Expr::Range(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::RawAddr(self0), crate::Expr::RawAddr(other0)) => { - self0 == other0 - } - (crate::Expr::Reference(self0), crate::Expr::Reference(other0)) => { - self0 == other0 - } - #[cfg(feature = "full")] - (crate::Expr::Repeat(self0), crate::Expr::Repeat(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Return(self0), crate::Expr::Return(other0)) => self0 == other0, - (crate::Expr::Struct(self0), crate::Expr::Struct(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Try(self0), crate::Expr::Try(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::TryBlock(self0), crate::Expr::TryBlock(other0)) => { - self0 == other0 - } - (crate::Expr::Tuple(self0), crate::Expr::Tuple(other0)) => self0 == other0, - (crate::Expr::Unary(self0), crate::Expr::Unary(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Unsafe(self0), crate::Expr::Unsafe(other0)) => self0 == other0, - (crate::Expr::Verbatim(self0), crate::Expr::Verbatim(other0)) => { - TokenStreamHelper(self0) == TokenStreamHelper(other0) - } - #[cfg(feature = "full")] - (crate::Expr::While(self0), crate::Expr::While(other0)) => self0 == other0, - #[cfg(feature = "full")] - (crate::Expr::Yield(self0), crate::Expr::Yield(other0)) => self0 == other0, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprArray {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprArray { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.elems == other.elems - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprAssign {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprAssign { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.left == other.left && self.right == other.right - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprAsync {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprAsync { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.capture == other.capture - && self.block == other.block - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprAwait {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprAwait { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.base == other.base - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprBinary {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprBinary { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.left == other.left && self.op == other.op - && self.right == other.right - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprBlock {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprBlock { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.label == other.label - && self.block == other.block - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprBreak {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprBreak { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.label == other.label && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprCall {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprCall { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.func == other.func && self.args == other.args - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprCast {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprCast { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr && self.ty == other.ty - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprClosure {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprClosure { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.lifetimes == other.lifetimes - && self.constness == other.constness && self.movability == other.movability - && self.asyncness == other.asyncness && self.capture == other.capture - && self.inputs == other.inputs && self.output == other.output - && self.body == other.body - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprConst {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprConst { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.block == other.block - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprContinue {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprContinue { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.label == other.label - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprField {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprField { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.base == other.base - && self.member == other.member - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprForLoop {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprForLoop { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.label == other.label && self.pat == other.pat - && self.expr == other.expr && self.body == other.body - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprGroup {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprGroup { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprIf {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprIf { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.cond == other.cond - && self.then_branch == other.then_branch - && self.else_branch == other.else_branch - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprIndex {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprIndex { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr && self.index == other.index - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprInfer {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprInfer { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprLet {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprLet { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.pat == other.pat && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprLit {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprLit { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.lit == other.lit - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprLoop {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprLoop { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.label == other.label && self.body == other.body - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprMacro {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprMacro { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mac == other.mac - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprMatch {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprMatch { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr && self.arms == other.arms - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprMethodCall {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprMethodCall { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.receiver == other.receiver - && self.method == other.method && self.turbofish == other.turbofish - && self.args == other.args - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprParen {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprParen { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprPath {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprPath { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.qself == other.qself && self.path == other.path - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprRange {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprRange { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.start == other.start - && self.limits == other.limits && self.end == other.end - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprRawAddr {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprRawAddr { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mutability == other.mutability - && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprReference {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprReference { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mutability == other.mutability - && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprRepeat {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprRepeat { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr && self.len == other.len - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprReturn {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprReturn { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprStruct {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprStruct { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.qself == other.qself && self.path == other.path - && self.fields == other.fields && self.dot2_token == other.dot2_token - && self.rest == other.rest - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprTry {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprTry { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprTryBlock {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprTryBlock { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.block == other.block - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprTuple {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprTuple { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.elems == other.elems - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprUnary {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprUnary { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.op == other.op && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprUnsafe {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprUnsafe { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.block == other.block - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprWhile {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprWhile { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.label == other.label && self.cond == other.cond - && self.body == other.body - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ExprYield {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ExprYield { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Field {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Field { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.mutability == other.mutability && self.ident == other.ident - && self.colon_token == other.colon_token && self.ty == other.ty - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::FieldMutability {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::FieldMutability { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::FieldMutability::None, crate::FieldMutability::None) => true, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::FieldPat {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::FieldPat { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.member == other.member - && self.colon_token == other.colon_token && self.pat == other.pat - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::FieldValue {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::FieldValue { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.member == other.member - && self.colon_token == other.colon_token && self.expr == other.expr - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Fields {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Fields { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Fields::Named(self0), crate::Fields::Named(other0)) => { - self0 == other0 - } - (crate::Fields::Unnamed(self0), crate::Fields::Unnamed(other0)) => { - self0 == other0 - } - (crate::Fields::Unit, crate::Fields::Unit) => true, - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::FieldsNamed {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::FieldsNamed { - fn eq(&self, other: &Self) -> bool { - self.named == other.named - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::FieldsUnnamed {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::FieldsUnnamed { - fn eq(&self, other: &Self) -> bool { - self.unnamed == other.unnamed - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::File {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::File { - fn eq(&self, other: &Self) -> bool { - self.shebang == other.shebang && self.attrs == other.attrs - && self.items == other.items - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::FnArg {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::FnArg { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::FnArg::Receiver(self0), crate::FnArg::Receiver(other0)) => { - self0 == other0 - } - (crate::FnArg::Typed(self0), crate::FnArg::Typed(other0)) => self0 == other0, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ForeignItem {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ForeignItem { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::ForeignItem::Fn(self0), crate::ForeignItem::Fn(other0)) => { - self0 == other0 - } - (crate::ForeignItem::Static(self0), crate::ForeignItem::Static(other0)) => { - self0 == other0 - } - (crate::ForeignItem::Type(self0), crate::ForeignItem::Type(other0)) => { - self0 == other0 - } - (crate::ForeignItem::Macro(self0), crate::ForeignItem::Macro(other0)) => { - self0 == other0 - } - ( - crate::ForeignItem::Verbatim(self0), - crate::ForeignItem::Verbatim(other0), - ) => TokenStreamHelper(self0) == TokenStreamHelper(other0), - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ForeignItemFn {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ForeignItemFn { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.sig == other.sig - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ForeignItemMacro {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ForeignItemMacro { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mac == other.mac - && self.semi_token == other.semi_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ForeignItemStatic {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ForeignItemStatic { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.mutability == other.mutability && self.ident == other.ident - && self.ty == other.ty - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ForeignItemType {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ForeignItemType { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::GenericArgument {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::GenericArgument { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - crate::GenericArgument::Lifetime(self0), - crate::GenericArgument::Lifetime(other0), - ) => self0 == other0, - ( - crate::GenericArgument::Type(self0), - crate::GenericArgument::Type(other0), - ) => self0 == other0, - ( - crate::GenericArgument::Const(self0), - crate::GenericArgument::Const(other0), - ) => self0 == other0, - ( - crate::GenericArgument::AssocType(self0), - crate::GenericArgument::AssocType(other0), - ) => self0 == other0, - ( - crate::GenericArgument::AssocConst(self0), - crate::GenericArgument::AssocConst(other0), - ) => self0 == other0, - ( - crate::GenericArgument::Constraint(self0), - crate::GenericArgument::Constraint(other0), - ) => self0 == other0, - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::GenericParam {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::GenericParam { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - crate::GenericParam::Lifetime(self0), - crate::GenericParam::Lifetime(other0), - ) => self0 == other0, - (crate::GenericParam::Type(self0), crate::GenericParam::Type(other0)) => { - self0 == other0 - } - (crate::GenericParam::Const(self0), crate::GenericParam::Const(other0)) => { - self0 == other0 - } - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Generics {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Generics { - fn eq(&self, other: &Self) -> bool { - self.lt_token == other.lt_token && self.params == other.params - && self.gt_token == other.gt_token && self.where_clause == other.where_clause - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ImplItem {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ImplItem { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::ImplItem::Const(self0), crate::ImplItem::Const(other0)) => { - self0 == other0 - } - (crate::ImplItem::Fn(self0), crate::ImplItem::Fn(other0)) => self0 == other0, - (crate::ImplItem::Type(self0), crate::ImplItem::Type(other0)) => { - self0 == other0 - } - (crate::ImplItem::Macro(self0), crate::ImplItem::Macro(other0)) => { - self0 == other0 - } - (crate::ImplItem::Verbatim(self0), crate::ImplItem::Verbatim(other0)) => { - TokenStreamHelper(self0) == TokenStreamHelper(other0) - } - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ImplItemConst {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ImplItemConst { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.defaultness == other.defaultness && self.ident == other.ident - && self.generics == other.generics && self.ty == other.ty - && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ImplItemFn {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ImplItemFn { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.defaultness == other.defaultness && self.sig == other.sig - && self.block == other.block - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ImplItemMacro {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ImplItemMacro { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mac == other.mac - && self.semi_token == other.semi_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ImplItemType {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ImplItemType { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.defaultness == other.defaultness && self.ident == other.ident - && self.generics == other.generics && self.ty == other.ty - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ImplRestriction {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ImplRestriction { - fn eq(&self, _other: &Self) -> bool { - match *self {} - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Item {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Item { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Item::Const(self0), crate::Item::Const(other0)) => self0 == other0, - (crate::Item::Enum(self0), crate::Item::Enum(other0)) => self0 == other0, - (crate::Item::ExternCrate(self0), crate::Item::ExternCrate(other0)) => { - self0 == other0 - } - (crate::Item::Fn(self0), crate::Item::Fn(other0)) => self0 == other0, - (crate::Item::ForeignMod(self0), crate::Item::ForeignMod(other0)) => { - self0 == other0 - } - (crate::Item::Impl(self0), crate::Item::Impl(other0)) => self0 == other0, - (crate::Item::Macro(self0), crate::Item::Macro(other0)) => self0 == other0, - (crate::Item::Mod(self0), crate::Item::Mod(other0)) => self0 == other0, - (crate::Item::Static(self0), crate::Item::Static(other0)) => self0 == other0, - (crate::Item::Struct(self0), crate::Item::Struct(other0)) => self0 == other0, - (crate::Item::Trait(self0), crate::Item::Trait(other0)) => self0 == other0, - (crate::Item::TraitAlias(self0), crate::Item::TraitAlias(other0)) => { - self0 == other0 - } - (crate::Item::Type(self0), crate::Item::Type(other0)) => self0 == other0, - (crate::Item::Union(self0), crate::Item::Union(other0)) => self0 == other0, - (crate::Item::Use(self0), crate::Item::Use(other0)) => self0 == other0, - (crate::Item::Verbatim(self0), crate::Item::Verbatim(other0)) => { - TokenStreamHelper(self0) == TokenStreamHelper(other0) - } - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemConst {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemConst { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.ty == other.ty - && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemEnum {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemEnum { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.variants == other.variants - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemExternCrate {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemExternCrate { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.rename == other.rename - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemFn {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemFn { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.sig == other.sig - && self.block == other.block - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemForeignMod {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemForeignMod { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.unsafety == other.unsafety - && self.abi == other.abi && self.items == other.items - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemImpl {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemImpl { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.defaultness == other.defaultness - && self.unsafety == other.unsafety && self.generics == other.generics - && self.trait_ == other.trait_ && self.self_ty == other.self_ty - && self.items == other.items - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemMacro {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemMacro { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.ident == other.ident && self.mac == other.mac - && self.semi_token == other.semi_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemMod {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemMod { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.unsafety == other.unsafety && self.ident == other.ident - && self.content == other.content && self.semi == other.semi - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemStatic {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemStatic { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.mutability == other.mutability && self.ident == other.ident - && self.ty == other.ty && self.expr == other.expr - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemStruct {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemStruct { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.fields == other.fields - && self.semi_token == other.semi_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemTrait {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemTrait { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.unsafety == other.unsafety && self.auto_token == other.auto_token - && self.restriction == other.restriction && self.ident == other.ident - && self.generics == other.generics && self.colon_token == other.colon_token - && self.supertraits == other.supertraits && self.items == other.items - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemTraitAlias {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemTraitAlias { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.bounds == other.bounds - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemType {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemType { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.ty == other.ty - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemUnion {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemUnion { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident - && self.generics == other.generics && self.fields == other.fields - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ItemUse {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ItemUse { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.vis == other.vis - && self.leading_colon == other.leading_colon && self.tree == other.tree - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Label {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Label { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LifetimeParam {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::LifetimeParam { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.lifetime == other.lifetime - && self.colon_token == other.colon_token && self.bounds == other.bounds - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Lit {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Lit { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Lit::Str(self0), crate::Lit::Str(other0)) => self0 == other0, - (crate::Lit::ByteStr(self0), crate::Lit::ByteStr(other0)) => self0 == other0, - (crate::Lit::CStr(self0), crate::Lit::CStr(other0)) => self0 == other0, - (crate::Lit::Byte(self0), crate::Lit::Byte(other0)) => self0 == other0, - (crate::Lit::Char(self0), crate::Lit::Char(other0)) => self0 == other0, - (crate::Lit::Int(self0), crate::Lit::Int(other0)) => self0 == other0, - (crate::Lit::Float(self0), crate::Lit::Float(other0)) => self0 == other0, - (crate::Lit::Bool(self0), crate::Lit::Bool(other0)) => self0 == other0, - (crate::Lit::Verbatim(self0), crate::Lit::Verbatim(other0)) => { - self0.to_string() == other0.to_string() - } - _ => false, - } - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitBool {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::LitBool { - fn eq(&self, other: &Self) -> bool { - self.value == other.value - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitByte {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitByteStr {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitCStr {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitChar {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitFloat {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitInt {} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LitStr {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Local {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Local { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.pat == other.pat && self.init == other.init - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::LocalInit {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::LocalInit { - fn eq(&self, other: &Self) -> bool { - self.expr == other.expr && self.diverge == other.diverge - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Macro {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Macro { - fn eq(&self, other: &Self) -> bool { - self.path == other.path && self.delimiter == other.delimiter - && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens) - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::MacroDelimiter {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::MacroDelimiter { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::MacroDelimiter::Paren(_), crate::MacroDelimiter::Paren(_)) => true, - (crate::MacroDelimiter::Brace(_), crate::MacroDelimiter::Brace(_)) => true, - (crate::MacroDelimiter::Bracket(_), crate::MacroDelimiter::Bracket(_)) => { - true - } - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Meta {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Meta { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Meta::Path(self0), crate::Meta::Path(other0)) => self0 == other0, - (crate::Meta::List(self0), crate::Meta::List(other0)) => self0 == other0, - (crate::Meta::NameValue(self0), crate::Meta::NameValue(other0)) => { - self0 == other0 - } - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::MetaList {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::MetaList { - fn eq(&self, other: &Self) -> bool { - self.path == other.path && self.delimiter == other.delimiter - && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens) - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::MetaNameValue {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::MetaNameValue { - fn eq(&self, other: &Self) -> bool { - self.path == other.path && self.value == other.value - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ParenthesizedGenericArguments {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ParenthesizedGenericArguments { - fn eq(&self, other: &Self) -> bool { - self.inputs == other.inputs && self.output == other.output - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Pat {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Pat { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Pat::Const(self0), crate::Pat::Const(other0)) => self0 == other0, - (crate::Pat::Ident(self0), crate::Pat::Ident(other0)) => self0 == other0, - (crate::Pat::Lit(self0), crate::Pat::Lit(other0)) => self0 == other0, - (crate::Pat::Macro(self0), crate::Pat::Macro(other0)) => self0 == other0, - (crate::Pat::Or(self0), crate::Pat::Or(other0)) => self0 == other0, - (crate::Pat::Paren(self0), crate::Pat::Paren(other0)) => self0 == other0, - (crate::Pat::Path(self0), crate::Pat::Path(other0)) => self0 == other0, - (crate::Pat::Range(self0), crate::Pat::Range(other0)) => self0 == other0, - (crate::Pat::Reference(self0), crate::Pat::Reference(other0)) => { - self0 == other0 - } - (crate::Pat::Rest(self0), crate::Pat::Rest(other0)) => self0 == other0, - (crate::Pat::Slice(self0), crate::Pat::Slice(other0)) => self0 == other0, - (crate::Pat::Struct(self0), crate::Pat::Struct(other0)) => self0 == other0, - (crate::Pat::Tuple(self0), crate::Pat::Tuple(other0)) => self0 == other0, - (crate::Pat::TupleStruct(self0), crate::Pat::TupleStruct(other0)) => { - self0 == other0 - } - (crate::Pat::Type(self0), crate::Pat::Type(other0)) => self0 == other0, - (crate::Pat::Verbatim(self0), crate::Pat::Verbatim(other0)) => { - TokenStreamHelper(self0) == TokenStreamHelper(other0) - } - (crate::Pat::Wild(self0), crate::Pat::Wild(other0)) => self0 == other0, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatIdent {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatIdent { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.by_ref == other.by_ref - && self.mutability == other.mutability && self.ident == other.ident - && self.subpat == other.subpat - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatOr {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatOr { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.leading_vert == other.leading_vert - && self.cases == other.cases - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatParen {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatParen { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.pat == other.pat - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatReference {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatReference { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mutability == other.mutability - && self.pat == other.pat - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatRest {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatRest { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatSlice {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatSlice { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.elems == other.elems - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatStruct {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatStruct { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.qself == other.qself && self.path == other.path - && self.fields == other.fields && self.rest == other.rest - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatTuple {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatTuple { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.elems == other.elems - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatTupleStruct {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatTupleStruct { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.qself == other.qself && self.path == other.path - && self.elems == other.elems - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatType {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatType { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.pat == other.pat && self.ty == other.ty - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PatWild {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PatWild { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Path {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Path { - fn eq(&self, other: &Self) -> bool { - self.leading_colon == other.leading_colon && self.segments == other.segments - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PathArguments {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PathArguments { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::PathArguments::None, crate::PathArguments::None) => true, - ( - crate::PathArguments::AngleBracketed(self0), - crate::PathArguments::AngleBracketed(other0), - ) => self0 == other0, - ( - crate::PathArguments::Parenthesized(self0), - crate::PathArguments::Parenthesized(other0), - ) => self0 == other0, - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PathSegment {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PathSegment { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident && self.arguments == other.arguments - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PointerMutability {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PointerMutability { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::PointerMutability::Const(_), crate::PointerMutability::Const(_)) => { - true - } - (crate::PointerMutability::Mut(_), crate::PointerMutability::Mut(_)) => true, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PreciseCapture {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PreciseCapture { - fn eq(&self, other: &Self) -> bool { - self.params == other.params - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PredicateLifetime {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PredicateLifetime { - fn eq(&self, other: &Self) -> bool { - self.lifetime == other.lifetime && self.bounds == other.bounds - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::PredicateType {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::PredicateType { - fn eq(&self, other: &Self) -> bool { - self.lifetimes == other.lifetimes && self.bounded_ty == other.bounded_ty - && self.bounds == other.bounds - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::QSelf {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::QSelf { - fn eq(&self, other: &Self) -> bool { - self.ty == other.ty && self.position == other.position - && self.as_token == other.as_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::RangeLimits {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::RangeLimits { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::RangeLimits::HalfOpen(_), crate::RangeLimits::HalfOpen(_)) => true, - (crate::RangeLimits::Closed(_), crate::RangeLimits::Closed(_)) => true, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Receiver {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Receiver { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.reference == other.reference - && self.mutability == other.mutability - && self.colon_token == other.colon_token && self.ty == other.ty - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::ReturnType {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::ReturnType { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::ReturnType::Default, crate::ReturnType::Default) => true, - (crate::ReturnType::Type(_, self1), crate::ReturnType::Type(_, other1)) => { - self1 == other1 - } - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Signature {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Signature { - fn eq(&self, other: &Self) -> bool { - self.constness == other.constness && self.asyncness == other.asyncness - && self.unsafety == other.unsafety && self.abi == other.abi - && self.ident == other.ident && self.generics == other.generics - && self.inputs == other.inputs && self.variadic == other.variadic - && self.output == other.output - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::StaticMutability {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::StaticMutability { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::StaticMutability::Mut(_), crate::StaticMutability::Mut(_)) => true, - (crate::StaticMutability::None, crate::StaticMutability::None) => true, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Stmt {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Stmt { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Stmt::Local(self0), crate::Stmt::Local(other0)) => self0 == other0, - (crate::Stmt::Item(self0), crate::Stmt::Item(other0)) => self0 == other0, - (crate::Stmt::Expr(self0, self1), crate::Stmt::Expr(other0, other1)) => { - self0 == other0 && self1 == other1 - } - (crate::Stmt::Macro(self0), crate::Stmt::Macro(other0)) => self0 == other0, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::StmtMacro {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::StmtMacro { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mac == other.mac - && self.semi_token == other.semi_token - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitBound {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitBound { - fn eq(&self, other: &Self) -> bool { - self.paren_token == other.paren_token && self.modifier == other.modifier - && self.lifetimes == other.lifetimes && self.path == other.path - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitBoundModifier {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitBoundModifier { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::TraitBoundModifier::None, crate::TraitBoundModifier::None) => true, - ( - crate::TraitBoundModifier::Maybe(_), - crate::TraitBoundModifier::Maybe(_), - ) => true, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitItem {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitItem { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::TraitItem::Const(self0), crate::TraitItem::Const(other0)) => { - self0 == other0 - } - (crate::TraitItem::Fn(self0), crate::TraitItem::Fn(other0)) => { - self0 == other0 - } - (crate::TraitItem::Type(self0), crate::TraitItem::Type(other0)) => { - self0 == other0 - } - (crate::TraitItem::Macro(self0), crate::TraitItem::Macro(other0)) => { - self0 == other0 - } - (crate::TraitItem::Verbatim(self0), crate::TraitItem::Verbatim(other0)) => { - TokenStreamHelper(self0) == TokenStreamHelper(other0) - } - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitItemConst {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitItemConst { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.ident == other.ident - && self.generics == other.generics && self.ty == other.ty - && self.default == other.default - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitItemFn {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitItemFn { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.sig == other.sig - && self.default == other.default && self.semi_token == other.semi_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitItemMacro {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitItemMacro { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.mac == other.mac - && self.semi_token == other.semi_token - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TraitItemType {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TraitItemType { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.ident == other.ident - && self.generics == other.generics && self.colon_token == other.colon_token - && self.bounds == other.bounds && self.default == other.default - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Type {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Type::Array(self0), crate::Type::Array(other0)) => self0 == other0, - (crate::Type::BareFn(self0), crate::Type::BareFn(other0)) => self0 == other0, - (crate::Type::Group(self0), crate::Type::Group(other0)) => self0 == other0, - (crate::Type::ImplTrait(self0), crate::Type::ImplTrait(other0)) => { - self0 == other0 - } - (crate::Type::Infer(self0), crate::Type::Infer(other0)) => self0 == other0, - (crate::Type::Macro(self0), crate::Type::Macro(other0)) => self0 == other0, - (crate::Type::Never(self0), crate::Type::Never(other0)) => self0 == other0, - (crate::Type::Paren(self0), crate::Type::Paren(other0)) => self0 == other0, - (crate::Type::Path(self0), crate::Type::Path(other0)) => self0 == other0, - (crate::Type::Ptr(self0), crate::Type::Ptr(other0)) => self0 == other0, - (crate::Type::Reference(self0), crate::Type::Reference(other0)) => { - self0 == other0 - } - (crate::Type::Slice(self0), crate::Type::Slice(other0)) => self0 == other0, - (crate::Type::TraitObject(self0), crate::Type::TraitObject(other0)) => { - self0 == other0 - } - (crate::Type::Tuple(self0), crate::Type::Tuple(other0)) => self0 == other0, - (crate::Type::Verbatim(self0), crate::Type::Verbatim(other0)) => { - TokenStreamHelper(self0) == TokenStreamHelper(other0) - } - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeArray {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeArray { - fn eq(&self, other: &Self) -> bool { - self.elem == other.elem && self.len == other.len - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeBareFn {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeBareFn { - fn eq(&self, other: &Self) -> bool { - self.lifetimes == other.lifetimes && self.unsafety == other.unsafety - && self.abi == other.abi && self.inputs == other.inputs - && self.variadic == other.variadic && self.output == other.output - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeGroup {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeGroup { - fn eq(&self, other: &Self) -> bool { - self.elem == other.elem - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeImplTrait {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeImplTrait { - fn eq(&self, other: &Self) -> bool { - self.bounds == other.bounds - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeInfer {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeInfer { - fn eq(&self, _other: &Self) -> bool { - true - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeMacro {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeMacro { - fn eq(&self, other: &Self) -> bool { - self.mac == other.mac - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeNever {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeNever { - fn eq(&self, _other: &Self) -> bool { - true - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeParam {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeParam { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.ident == other.ident - && self.colon_token == other.colon_token && self.bounds == other.bounds - && self.eq_token == other.eq_token && self.default == other.default - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeParamBound {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeParamBound { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - crate::TypeParamBound::Trait(self0), - crate::TypeParamBound::Trait(other0), - ) => self0 == other0, - ( - crate::TypeParamBound::Lifetime(self0), - crate::TypeParamBound::Lifetime(other0), - ) => self0 == other0, - #[cfg(feature = "full")] - ( - crate::TypeParamBound::PreciseCapture(self0), - crate::TypeParamBound::PreciseCapture(other0), - ) => self0 == other0, - ( - crate::TypeParamBound::Verbatim(self0), - crate::TypeParamBound::Verbatim(other0), - ) => TokenStreamHelper(self0) == TokenStreamHelper(other0), - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeParen {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeParen { - fn eq(&self, other: &Self) -> bool { - self.elem == other.elem - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypePath {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypePath { - fn eq(&self, other: &Self) -> bool { - self.qself == other.qself && self.path == other.path - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypePtr {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypePtr { - fn eq(&self, other: &Self) -> bool { - self.const_token == other.const_token && self.mutability == other.mutability - && self.elem == other.elem - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeReference {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeReference { - fn eq(&self, other: &Self) -> bool { - self.lifetime == other.lifetime && self.mutability == other.mutability - && self.elem == other.elem - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeSlice {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeSlice { - fn eq(&self, other: &Self) -> bool { - self.elem == other.elem - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeTraitObject {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeTraitObject { - fn eq(&self, other: &Self) -> bool { - self.dyn_token == other.dyn_token && self.bounds == other.bounds - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::TypeTuple {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::TypeTuple { - fn eq(&self, other: &Self) -> bool { - self.elems == other.elems - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UnOp {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UnOp { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::UnOp::Deref(_), crate::UnOp::Deref(_)) => true, - (crate::UnOp::Not(_), crate::UnOp::Not(_)) => true, - (crate::UnOp::Neg(_), crate::UnOp::Neg(_)) => true, - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UseGlob {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UseGlob { - fn eq(&self, _other: &Self) -> bool { - true - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UseGroup {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UseGroup { - fn eq(&self, other: &Self) -> bool { - self.items == other.items - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UseName {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UseName { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UsePath {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UsePath { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident && self.tree == other.tree - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UseRename {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UseRename { - fn eq(&self, other: &Self) -> bool { - self.ident == other.ident && self.rename == other.rename - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::UseTree {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::UseTree { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::UseTree::Path(self0), crate::UseTree::Path(other0)) => { - self0 == other0 - } - (crate::UseTree::Name(self0), crate::UseTree::Name(other0)) => { - self0 == other0 - } - (crate::UseTree::Rename(self0), crate::UseTree::Rename(other0)) => { - self0 == other0 - } - (crate::UseTree::Glob(self0), crate::UseTree::Glob(other0)) => { - self0 == other0 - } - (crate::UseTree::Group(self0), crate::UseTree::Group(other0)) => { - self0 == other0 - } - _ => false, - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Variadic {} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Variadic { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.pat == other.pat && self.comma == other.comma - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Variant {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Variant { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.ident == other.ident - && self.fields == other.fields && self.discriminant == other.discriminant - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::VisRestricted {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::VisRestricted { - fn eq(&self, other: &Self) -> bool { - self.in_token == other.in_token && self.path == other.path - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::Visibility {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::Visibility { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (crate::Visibility::Public(_), crate::Visibility::Public(_)) => true, - ( - crate::Visibility::Restricted(self0), - crate::Visibility::Restricted(other0), - ) => self0 == other0, - (crate::Visibility::Inherited, crate::Visibility::Inherited) => true, - _ => false, - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::WhereClause {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::WhereClause { - fn eq(&self, other: &Self) -> bool { - self.predicates == other.predicates - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for crate::WherePredicate {} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for crate::WherePredicate { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - crate::WherePredicate::Lifetime(self0), - crate::WherePredicate::Lifetime(other0), - ) => self0 == other0, - (crate::WherePredicate::Type(self0), crate::WherePredicate::Type(other0)) => { - self0 == other0 - } - _ => false, - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/gen/fold.rs b/deps/crates/vendor/syn-v2/src/gen/fold.rs deleted file mode 100644 index b71421f47a35..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/fold.rs +++ /dev/null @@ -1,3906 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#![allow(unreachable_code, unused_variables)] -#![allow( - clippy::match_wildcard_for_single_variants, - clippy::needless_match, - clippy::needless_pass_by_ref_mut, -)] -#[cfg(any(feature = "derive", feature = "full"))] -use alloc::boxed::Box; -#[cfg(any(feature = "derive", feature = "full"))] -use alloc::vec::Vec; -#[cfg(feature = "full")] -macro_rules! full { - ($e:expr) => { - $e - }; -} -#[cfg(all(feature = "derive", not(feature = "full")))] -macro_rules! full { - ($e:expr) => { - unreachable!() - }; -} -/// Syntax tree traversal to transform the nodes of an owned syntax tree. -/// -/// See the [module documentation] for details. -/// -/// [module documentation]: self -pub trait Fold { - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_abi(&mut self, i: crate::Abi) -> crate::Abi { - fold_abi(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_angle_bracketed_generic_arguments( - &mut self, - i: crate::AngleBracketedGenericArguments, - ) -> crate::AngleBracketedGenericArguments { - fold_angle_bracketed_generic_arguments(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_arm(&mut self, i: crate::Arm) -> crate::Arm { - fold_arm(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_assoc_const(&mut self, i: crate::AssocConst) -> crate::AssocConst { - fold_assoc_const(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_assoc_type(&mut self, i: crate::AssocType) -> crate::AssocType { - fold_assoc_type(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_attr_style(&mut self, i: crate::AttrStyle) -> crate::AttrStyle { - fold_attr_style(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_attribute(&mut self, i: crate::Attribute) -> crate::Attribute { - fold_attribute(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_attributes(&mut self, i: Vec<crate::Attribute>) -> Vec<crate::Attribute> { - fold_vec(i, self, Self::fold_attribute) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_bare_fn_arg(&mut self, i: crate::BareFnArg) -> crate::BareFnArg { - fold_bare_fn_arg(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_bare_variadic(&mut self, i: crate::BareVariadic) -> crate::BareVariadic { - fold_bare_variadic(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_bin_op(&mut self, i: crate::BinOp) -> crate::BinOp { - fold_bin_op(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_block(&mut self, i: crate::Block) -> crate::Block { - fold_block(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_bound_lifetimes( - &mut self, - i: crate::BoundLifetimes, - ) -> crate::BoundLifetimes { - fold_bound_lifetimes(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_captured_param(&mut self, i: crate::CapturedParam) -> crate::CapturedParam { - fold_captured_param(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_const_param(&mut self, i: crate::ConstParam) -> crate::ConstParam { - fold_const_param(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_constraint(&mut self, i: crate::Constraint) -> crate::Constraint { - fold_constraint(self, i) - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn fold_data(&mut self, i: crate::Data) -> crate::Data { - fold_data(self, i) - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn fold_data_enum(&mut self, i: crate::DataEnum) -> crate::DataEnum { - fold_data_enum(self, i) - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn fold_data_struct(&mut self, i: crate::DataStruct) -> crate::DataStruct { - fold_data_struct(self, i) - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn fold_data_union(&mut self, i: crate::DataUnion) -> crate::DataUnion { - fold_data_union(self, i) - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn fold_derive_input(&mut self, i: crate::DeriveInput) -> crate::DeriveInput { - fold_derive_input(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr(&mut self, i: crate::Expr) -> crate::Expr { - fold_expr(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_array(&mut self, i: crate::ExprArray) -> crate::ExprArray { - fold_expr_array(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_assign(&mut self, i: crate::ExprAssign) -> crate::ExprAssign { - fold_expr_assign(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_async(&mut self, i: crate::ExprAsync) -> crate::ExprAsync { - fold_expr_async(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_await(&mut self, i: crate::ExprAwait) -> crate::ExprAwait { - fold_expr_await(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_binary(&mut self, i: crate::ExprBinary) -> crate::ExprBinary { - fold_expr_binary(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_block(&mut self, i: crate::ExprBlock) -> crate::ExprBlock { - fold_expr_block(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_break(&mut self, i: crate::ExprBreak) -> crate::ExprBreak { - fold_expr_break(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_call(&mut self, i: crate::ExprCall) -> crate::ExprCall { - fold_expr_call(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_cast(&mut self, i: crate::ExprCast) -> crate::ExprCast { - fold_expr_cast(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_closure(&mut self, i: crate::ExprClosure) -> crate::ExprClosure { - fold_expr_closure(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_const(&mut self, i: crate::ExprConst) -> crate::ExprConst { - fold_expr_const(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_continue(&mut self, i: crate::ExprContinue) -> crate::ExprContinue { - fold_expr_continue(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_field(&mut self, i: crate::ExprField) -> crate::ExprField { - fold_expr_field(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_for_loop(&mut self, i: crate::ExprForLoop) -> crate::ExprForLoop { - fold_expr_for_loop(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_group(&mut self, i: crate::ExprGroup) -> crate::ExprGroup { - fold_expr_group(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_if(&mut self, i: crate::ExprIf) -> crate::ExprIf { - fold_expr_if(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_index(&mut self, i: crate::ExprIndex) -> crate::ExprIndex { - fold_expr_index(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_infer(&mut self, i: crate::ExprInfer) -> crate::ExprInfer { - fold_expr_infer(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_let(&mut self, i: crate::ExprLet) -> crate::ExprLet { - fold_expr_let(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_lit(&mut self, i: crate::ExprLit) -> crate::ExprLit { - fold_expr_lit(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_loop(&mut self, i: crate::ExprLoop) -> crate::ExprLoop { - fold_expr_loop(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_macro(&mut self, i: crate::ExprMacro) -> crate::ExprMacro { - fold_expr_macro(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_match(&mut self, i: crate::ExprMatch) -> crate::ExprMatch { - fold_expr_match(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_method_call( - &mut self, - i: crate::ExprMethodCall, - ) -> crate::ExprMethodCall { - fold_expr_method_call(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_paren(&mut self, i: crate::ExprParen) -> crate::ExprParen { - fold_expr_paren(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_path(&mut self, i: crate::ExprPath) -> crate::ExprPath { - fold_expr_path(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_range(&mut self, i: crate::ExprRange) -> crate::ExprRange { - fold_expr_range(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_raw_addr(&mut self, i: crate::ExprRawAddr) -> crate::ExprRawAddr { - fold_expr_raw_addr(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_reference(&mut self, i: crate::ExprReference) -> crate::ExprReference { - fold_expr_reference(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_repeat(&mut self, i: crate::ExprRepeat) -> crate::ExprRepeat { - fold_expr_repeat(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_return(&mut self, i: crate::ExprReturn) -> crate::ExprReturn { - fold_expr_return(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_struct(&mut self, i: crate::ExprStruct) -> crate::ExprStruct { - fold_expr_struct(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_try(&mut self, i: crate::ExprTry) -> crate::ExprTry { - fold_expr_try(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_try_block(&mut self, i: crate::ExprTryBlock) -> crate::ExprTryBlock { - fold_expr_try_block(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_tuple(&mut self, i: crate::ExprTuple) -> crate::ExprTuple { - fold_expr_tuple(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_expr_unary(&mut self, i: crate::ExprUnary) -> crate::ExprUnary { - fold_expr_unary(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_unsafe(&mut self, i: crate::ExprUnsafe) -> crate::ExprUnsafe { - fold_expr_unsafe(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_while(&mut self, i: crate::ExprWhile) -> crate::ExprWhile { - fold_expr_while(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_expr_yield(&mut self, i: crate::ExprYield) -> crate::ExprYield { - fold_expr_yield(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_field(&mut self, i: crate::Field) -> crate::Field { - fold_field(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_field_mutability( - &mut self, - i: crate::FieldMutability, - ) -> crate::FieldMutability { - fold_field_mutability(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_field_pat(&mut self, i: crate::FieldPat) -> crate::FieldPat { - fold_field_pat(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_field_value(&mut self, i: crate::FieldValue) -> crate::FieldValue { - fold_field_value(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_fields(&mut self, i: crate::Fields) -> crate::Fields { - fold_fields(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_fields_named(&mut self, i: crate::FieldsNamed) -> crate::FieldsNamed { - fold_fields_named(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_fields_unnamed(&mut self, i: crate::FieldsUnnamed) -> crate::FieldsUnnamed { - fold_fields_unnamed(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_file(&mut self, i: crate::File) -> crate::File { - fold_file(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_fn_arg(&mut self, i: crate::FnArg) -> crate::FnArg { - fold_fn_arg(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_foreign_item(&mut self, i: crate::ForeignItem) -> crate::ForeignItem { - fold_foreign_item(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_foreign_item_fn(&mut self, i: crate::ForeignItemFn) -> crate::ForeignItemFn { - fold_foreign_item_fn(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_foreign_item_macro( - &mut self, - i: crate::ForeignItemMacro, - ) -> crate::ForeignItemMacro { - fold_foreign_item_macro(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_foreign_item_static( - &mut self, - i: crate::ForeignItemStatic, - ) -> crate::ForeignItemStatic { - fold_foreign_item_static(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_foreign_item_type( - &mut self, - i: crate::ForeignItemType, - ) -> crate::ForeignItemType { - fold_foreign_item_type(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_generic_argument( - &mut self, - i: crate::GenericArgument, - ) -> crate::GenericArgument { - fold_generic_argument(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_generic_param(&mut self, i: crate::GenericParam) -> crate::GenericParam { - fold_generic_param(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_generics(&mut self, i: crate::Generics) -> crate::Generics { - fold_generics(self, i) - } - fn fold_ident(&mut self, i: proc_macro2::Ident) -> proc_macro2::Ident { - fold_ident(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_impl_item(&mut self, i: crate::ImplItem) -> crate::ImplItem { - fold_impl_item(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_impl_item_const(&mut self, i: crate::ImplItemConst) -> crate::ImplItemConst { - fold_impl_item_const(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_impl_item_fn(&mut self, i: crate::ImplItemFn) -> crate::ImplItemFn { - fold_impl_item_fn(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_impl_item_macro(&mut self, i: crate::ImplItemMacro) -> crate::ImplItemMacro { - fold_impl_item_macro(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_impl_item_type(&mut self, i: crate::ImplItemType) -> crate::ImplItemType { - fold_impl_item_type(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_impl_restriction( - &mut self, - i: crate::ImplRestriction, - ) -> crate::ImplRestriction { - fold_impl_restriction(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_index(&mut self, i: crate::Index) -> crate::Index { - fold_index(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item(&mut self, i: crate::Item) -> crate::Item { - fold_item(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_const(&mut self, i: crate::ItemConst) -> crate::ItemConst { - fold_item_const(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_enum(&mut self, i: crate::ItemEnum) -> crate::ItemEnum { - fold_item_enum(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_extern_crate( - &mut self, - i: crate::ItemExternCrate, - ) -> crate::ItemExternCrate { - fold_item_extern_crate(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_fn(&mut self, i: crate::ItemFn) -> crate::ItemFn { - fold_item_fn(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_foreign_mod( - &mut self, - i: crate::ItemForeignMod, - ) -> crate::ItemForeignMod { - fold_item_foreign_mod(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_impl(&mut self, i: crate::ItemImpl) -> crate::ItemImpl { - fold_item_impl(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_macro(&mut self, i: crate::ItemMacro) -> crate::ItemMacro { - fold_item_macro(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_mod(&mut self, i: crate::ItemMod) -> crate::ItemMod { - fold_item_mod(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_static(&mut self, i: crate::ItemStatic) -> crate::ItemStatic { - fold_item_static(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_struct(&mut self, i: crate::ItemStruct) -> crate::ItemStruct { - fold_item_struct(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_trait(&mut self, i: crate::ItemTrait) -> crate::ItemTrait { - fold_item_trait(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_trait_alias( - &mut self, - i: crate::ItemTraitAlias, - ) -> crate::ItemTraitAlias { - fold_item_trait_alias(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_type(&mut self, i: crate::ItemType) -> crate::ItemType { - fold_item_type(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_union(&mut self, i: crate::ItemUnion) -> crate::ItemUnion { - fold_item_union(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_item_use(&mut self, i: crate::ItemUse) -> crate::ItemUse { - fold_item_use(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_label(&mut self, i: crate::Label) -> crate::Label { - fold_label(self, i) - } - fn fold_lifetime(&mut self, i: crate::Lifetime) -> crate::Lifetime { - fold_lifetime(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_lifetime_param(&mut self, i: crate::LifetimeParam) -> crate::LifetimeParam { - fold_lifetime_param(self, i) - } - fn fold_lit(&mut self, i: crate::Lit) -> crate::Lit { - fold_lit(self, i) - } - fn fold_lit_bool(&mut self, i: crate::LitBool) -> crate::LitBool { - fold_lit_bool(self, i) - } - fn fold_lit_byte(&mut self, i: crate::LitByte) -> crate::LitByte { - fold_lit_byte(self, i) - } - fn fold_lit_byte_str(&mut self, i: crate::LitByteStr) -> crate::LitByteStr { - fold_lit_byte_str(self, i) - } - fn fold_lit_cstr(&mut self, i: crate::LitCStr) -> crate::LitCStr { - fold_lit_cstr(self, i) - } - fn fold_lit_char(&mut self, i: crate::LitChar) -> crate::LitChar { - fold_lit_char(self, i) - } - fn fold_lit_float(&mut self, i: crate::LitFloat) -> crate::LitFloat { - fold_lit_float(self, i) - } - fn fold_lit_int(&mut self, i: crate::LitInt) -> crate::LitInt { - fold_lit_int(self, i) - } - fn fold_lit_str(&mut self, i: crate::LitStr) -> crate::LitStr { - fold_lit_str(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_local(&mut self, i: crate::Local) -> crate::Local { - fold_local(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_local_init(&mut self, i: crate::LocalInit) -> crate::LocalInit { - fold_local_init(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_macro(&mut self, i: crate::Macro) -> crate::Macro { - fold_macro(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_macro_delimiter( - &mut self, - i: crate::MacroDelimiter, - ) -> crate::MacroDelimiter { - fold_macro_delimiter(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_member(&mut self, i: crate::Member) -> crate::Member { - fold_member(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_meta(&mut self, i: crate::Meta) -> crate::Meta { - fold_meta(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_meta_list(&mut self, i: crate::MetaList) -> crate::MetaList { - fold_meta_list(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_meta_name_value(&mut self, i: crate::MetaNameValue) -> crate::MetaNameValue { - fold_meta_name_value(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_parenthesized_generic_arguments( - &mut self, - i: crate::ParenthesizedGenericArguments, - ) -> crate::ParenthesizedGenericArguments { - fold_parenthesized_generic_arguments(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat(&mut self, i: crate::Pat) -> crate::Pat { - fold_pat(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_ident(&mut self, i: crate::PatIdent) -> crate::PatIdent { - fold_pat_ident(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_or(&mut self, i: crate::PatOr) -> crate::PatOr { - fold_pat_or(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_paren(&mut self, i: crate::PatParen) -> crate::PatParen { - fold_pat_paren(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_reference(&mut self, i: crate::PatReference) -> crate::PatReference { - fold_pat_reference(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_rest(&mut self, i: crate::PatRest) -> crate::PatRest { - fold_pat_rest(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_slice(&mut self, i: crate::PatSlice) -> crate::PatSlice { - fold_pat_slice(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_struct(&mut self, i: crate::PatStruct) -> crate::PatStruct { - fold_pat_struct(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_tuple(&mut self, i: crate::PatTuple) -> crate::PatTuple { - fold_pat_tuple(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_tuple_struct( - &mut self, - i: crate::PatTupleStruct, - ) -> crate::PatTupleStruct { - fold_pat_tuple_struct(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_type(&mut self, i: crate::PatType) -> crate::PatType { - fold_pat_type(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pat_wild(&mut self, i: crate::PatWild) -> crate::PatWild { - fold_pat_wild(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_path(&mut self, i: crate::Path) -> crate::Path { - fold_path(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_path_arguments(&mut self, i: crate::PathArguments) -> crate::PathArguments { - fold_path_arguments(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_path_segment(&mut self, i: crate::PathSegment) -> crate::PathSegment { - fold_path_segment(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_pointer_mutability( - &mut self, - i: crate::PointerMutability, - ) -> crate::PointerMutability { - fold_pointer_mutability(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_precise_capture( - &mut self, - i: crate::PreciseCapture, - ) -> crate::PreciseCapture { - fold_precise_capture(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_predicate_lifetime( - &mut self, - i: crate::PredicateLifetime, - ) -> crate::PredicateLifetime { - fold_predicate_lifetime(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_predicate_type(&mut self, i: crate::PredicateType) -> crate::PredicateType { - fold_predicate_type(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_qself(&mut self, i: crate::QSelf) -> crate::QSelf { - fold_qself(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_range_limits(&mut self, i: crate::RangeLimits) -> crate::RangeLimits { - fold_range_limits(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_receiver(&mut self, i: crate::Receiver) -> crate::Receiver { - fold_receiver(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_return_type(&mut self, i: crate::ReturnType) -> crate::ReturnType { - fold_return_type(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_signature(&mut self, i: crate::Signature) -> crate::Signature { - fold_signature(self, i) - } - fn fold_span(&mut self, i: proc_macro2::Span) -> proc_macro2::Span { - i - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_static_mutability( - &mut self, - i: crate::StaticMutability, - ) -> crate::StaticMutability { - fold_static_mutability(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_stmt(&mut self, i: crate::Stmt) -> crate::Stmt { - fold_stmt(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_stmt_macro(&mut self, i: crate::StmtMacro) -> crate::StmtMacro { - fold_stmt_macro(self, i) - } - fn fold_token_stream( - &mut self, - i: proc_macro2::TokenStream, - ) -> proc_macro2::TokenStream { - i - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_trait_bound(&mut self, i: crate::TraitBound) -> crate::TraitBound { - fold_trait_bound(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_trait_bound_modifier( - &mut self, - i: crate::TraitBoundModifier, - ) -> crate::TraitBoundModifier { - fold_trait_bound_modifier(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_trait_item(&mut self, i: crate::TraitItem) -> crate::TraitItem { - fold_trait_item(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_trait_item_const( - &mut self, - i: crate::TraitItemConst, - ) -> crate::TraitItemConst { - fold_trait_item_const(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_trait_item_fn(&mut self, i: crate::TraitItemFn) -> crate::TraitItemFn { - fold_trait_item_fn(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_trait_item_macro( - &mut self, - i: crate::TraitItemMacro, - ) -> crate::TraitItemMacro { - fold_trait_item_macro(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_trait_item_type(&mut self, i: crate::TraitItemType) -> crate::TraitItemType { - fold_trait_item_type(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type(&mut self, i: crate::Type) -> crate::Type { - fold_type(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_array(&mut self, i: crate::TypeArray) -> crate::TypeArray { - fold_type_array(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_bare_fn(&mut self, i: crate::TypeBareFn) -> crate::TypeBareFn { - fold_type_bare_fn(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_group(&mut self, i: crate::TypeGroup) -> crate::TypeGroup { - fold_type_group(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_impl_trait(&mut self, i: crate::TypeImplTrait) -> crate::TypeImplTrait { - fold_type_impl_trait(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_infer(&mut self, i: crate::TypeInfer) -> crate::TypeInfer { - fold_type_infer(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_macro(&mut self, i: crate::TypeMacro) -> crate::TypeMacro { - fold_type_macro(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_never(&mut self, i: crate::TypeNever) -> crate::TypeNever { - fold_type_never(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_param(&mut self, i: crate::TypeParam) -> crate::TypeParam { - fold_type_param(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_param_bound( - &mut self, - i: crate::TypeParamBound, - ) -> crate::TypeParamBound { - fold_type_param_bound(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_paren(&mut self, i: crate::TypeParen) -> crate::TypeParen { - fold_type_paren(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_path(&mut self, i: crate::TypePath) -> crate::TypePath { - fold_type_path(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_ptr(&mut self, i: crate::TypePtr) -> crate::TypePtr { - fold_type_ptr(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_reference(&mut self, i: crate::TypeReference) -> crate::TypeReference { - fold_type_reference(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_slice(&mut self, i: crate::TypeSlice) -> crate::TypeSlice { - fold_type_slice(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_trait_object( - &mut self, - i: crate::TypeTraitObject, - ) -> crate::TypeTraitObject { - fold_type_trait_object(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_type_tuple(&mut self, i: crate::TypeTuple) -> crate::TypeTuple { - fold_type_tuple(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_un_op(&mut self, i: crate::UnOp) -> crate::UnOp { - fold_un_op(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_use_glob(&mut self, i: crate::UseGlob) -> crate::UseGlob { - fold_use_glob(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_use_group(&mut self, i: crate::UseGroup) -> crate::UseGroup { - fold_use_group(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_use_name(&mut self, i: crate::UseName) -> crate::UseName { - fold_use_name(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_use_path(&mut self, i: crate::UsePath) -> crate::UsePath { - fold_use_path(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_use_rename(&mut self, i: crate::UseRename) -> crate::UseRename { - fold_use_rename(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_use_tree(&mut self, i: crate::UseTree) -> crate::UseTree { - fold_use_tree(self, i) - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn fold_variadic(&mut self, i: crate::Variadic) -> crate::Variadic { - fold_variadic(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_variant(&mut self, i: crate::Variant) -> crate::Variant { - fold_variant(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_vis_restricted(&mut self, i: crate::VisRestricted) -> crate::VisRestricted { - fold_vis_restricted(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_visibility(&mut self, i: crate::Visibility) -> crate::Visibility { - fold_visibility(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_where_clause(&mut self, i: crate::WhereClause) -> crate::WhereClause { - fold_where_clause(self, i) - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn fold_where_predicate( - &mut self, - i: crate::WherePredicate, - ) -> crate::WherePredicate { - fold_where_predicate(self, i) - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_abi<F>(f: &mut F, node: crate::Abi) -> crate::Abi -where - F: Fold + ?Sized, -{ - crate::Abi { - extern_token: node.extern_token, - name: (node.name).map(|it| f.fold_lit_str(it)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_angle_bracketed_generic_arguments<F>( - f: &mut F, - node: crate::AngleBracketedGenericArguments, -) -> crate::AngleBracketedGenericArguments -where - F: Fold + ?Sized, -{ - crate::AngleBracketedGenericArguments { - colon2_token: node.colon2_token, - lt_token: node.lt_token, - args: crate::punctuated::fold(node.args, f, F::fold_generic_argument), - gt_token: node.gt_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_arm<F>(f: &mut F, node: crate::Arm) -> crate::Arm -where - F: Fold + ?Sized, -{ - crate::Arm { - attrs: f.fold_attributes(node.attrs), - pat: f.fold_pat(node.pat), - guard: (node.guard).map(|it| ((it).0, Box::new(f.fold_expr(*(it).1)))), - fat_arrow_token: node.fat_arrow_token, - body: Box::new(f.fold_expr(*node.body)), - comma: node.comma, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_assoc_const<F>(f: &mut F, node: crate::AssocConst) -> crate::AssocConst -where - F: Fold + ?Sized, -{ - crate::AssocConst { - ident: f.fold_ident(node.ident), - generics: (node.generics).map(|it| f.fold_angle_bracketed_generic_arguments(it)), - eq_token: node.eq_token, - value: f.fold_expr(node.value), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_assoc_type<F>(f: &mut F, node: crate::AssocType) -> crate::AssocType -where - F: Fold + ?Sized, -{ - crate::AssocType { - ident: f.fold_ident(node.ident), - generics: (node.generics).map(|it| f.fold_angle_bracketed_generic_arguments(it)), - eq_token: node.eq_token, - ty: f.fold_type(node.ty), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_attr_style<F>(f: &mut F, node: crate::AttrStyle) -> crate::AttrStyle -where - F: Fold + ?Sized, -{ - match node { - crate::AttrStyle::Outer => crate::AttrStyle::Outer, - crate::AttrStyle::Inner(_binding_0) => crate::AttrStyle::Inner(_binding_0), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_attribute<F>(f: &mut F, node: crate::Attribute) -> crate::Attribute -where - F: Fold + ?Sized, -{ - crate::Attribute { - pound_token: node.pound_token, - style: f.fold_attr_style(node.style), - bracket_token: node.bracket_token, - meta: f.fold_meta(node.meta), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_bare_fn_arg<F>(f: &mut F, node: crate::BareFnArg) -> crate::BareFnArg -where - F: Fold + ?Sized, -{ - crate::BareFnArg { - attrs: f.fold_attributes(node.attrs), - name: (node.name).map(|it| (f.fold_ident((it).0), (it).1)), - ty: f.fold_type(node.ty), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_bare_variadic<F>(f: &mut F, node: crate::BareVariadic) -> crate::BareVariadic -where - F: Fold + ?Sized, -{ - crate::BareVariadic { - attrs: f.fold_attributes(node.attrs), - name: (node.name).map(|it| (f.fold_ident((it).0), (it).1)), - dots: node.dots, - comma: node.comma, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_bin_op<F>(f: &mut F, node: crate::BinOp) -> crate::BinOp -where - F: Fold + ?Sized, -{ - match node { - crate::BinOp::Add(_binding_0) => crate::BinOp::Add(_binding_0), - crate::BinOp::Sub(_binding_0) => crate::BinOp::Sub(_binding_0), - crate::BinOp::Mul(_binding_0) => crate::BinOp::Mul(_binding_0), - crate::BinOp::Div(_binding_0) => crate::BinOp::Div(_binding_0), - crate::BinOp::Rem(_binding_0) => crate::BinOp::Rem(_binding_0), - crate::BinOp::And(_binding_0) => crate::BinOp::And(_binding_0), - crate::BinOp::Or(_binding_0) => crate::BinOp::Or(_binding_0), - crate::BinOp::BitXor(_binding_0) => crate::BinOp::BitXor(_binding_0), - crate::BinOp::BitAnd(_binding_0) => crate::BinOp::BitAnd(_binding_0), - crate::BinOp::BitOr(_binding_0) => crate::BinOp::BitOr(_binding_0), - crate::BinOp::Shl(_binding_0) => crate::BinOp::Shl(_binding_0), - crate::BinOp::Shr(_binding_0) => crate::BinOp::Shr(_binding_0), - crate::BinOp::Eq(_binding_0) => crate::BinOp::Eq(_binding_0), - crate::BinOp::Lt(_binding_0) => crate::BinOp::Lt(_binding_0), - crate::BinOp::Le(_binding_0) => crate::BinOp::Le(_binding_0), - crate::BinOp::Ne(_binding_0) => crate::BinOp::Ne(_binding_0), - crate::BinOp::Ge(_binding_0) => crate::BinOp::Ge(_binding_0), - crate::BinOp::Gt(_binding_0) => crate::BinOp::Gt(_binding_0), - crate::BinOp::AddAssign(_binding_0) => crate::BinOp::AddAssign(_binding_0), - crate::BinOp::SubAssign(_binding_0) => crate::BinOp::SubAssign(_binding_0), - crate::BinOp::MulAssign(_binding_0) => crate::BinOp::MulAssign(_binding_0), - crate::BinOp::DivAssign(_binding_0) => crate::BinOp::DivAssign(_binding_0), - crate::BinOp::RemAssign(_binding_0) => crate::BinOp::RemAssign(_binding_0), - crate::BinOp::BitXorAssign(_binding_0) => crate::BinOp::BitXorAssign(_binding_0), - crate::BinOp::BitAndAssign(_binding_0) => crate::BinOp::BitAndAssign(_binding_0), - crate::BinOp::BitOrAssign(_binding_0) => crate::BinOp::BitOrAssign(_binding_0), - crate::BinOp::ShlAssign(_binding_0) => crate::BinOp::ShlAssign(_binding_0), - crate::BinOp::ShrAssign(_binding_0) => crate::BinOp::ShrAssign(_binding_0), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_block<F>(f: &mut F, node: crate::Block) -> crate::Block -where - F: Fold + ?Sized, -{ - crate::Block { - brace_token: node.brace_token, - stmts: fold_vec(node.stmts, f, F::fold_stmt), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_bound_lifetimes<F>( - f: &mut F, - node: crate::BoundLifetimes, -) -> crate::BoundLifetimes -where - F: Fold + ?Sized, -{ - crate::BoundLifetimes { - for_token: node.for_token, - lt_token: node.lt_token, - lifetimes: crate::punctuated::fold(node.lifetimes, f, F::fold_generic_param), - gt_token: node.gt_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_captured_param<F>( - f: &mut F, - node: crate::CapturedParam, -) -> crate::CapturedParam -where - F: Fold + ?Sized, -{ - match node { - crate::CapturedParam::Lifetime(_binding_0) => { - crate::CapturedParam::Lifetime(f.fold_lifetime(_binding_0)) - } - crate::CapturedParam::Ident(_binding_0) => { - crate::CapturedParam::Ident(f.fold_ident(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_const_param<F>(f: &mut F, node: crate::ConstParam) -> crate::ConstParam -where - F: Fold + ?Sized, -{ - crate::ConstParam { - attrs: f.fold_attributes(node.attrs), - const_token: node.const_token, - ident: f.fold_ident(node.ident), - colon_token: node.colon_token, - ty: f.fold_type(node.ty), - eq_token: node.eq_token, - default: (node.default).map(|it| f.fold_expr(it)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_constraint<F>(f: &mut F, node: crate::Constraint) -> crate::Constraint -where - F: Fold + ?Sized, -{ - crate::Constraint { - ident: f.fold_ident(node.ident), - generics: (node.generics).map(|it| f.fold_angle_bracketed_generic_arguments(it)), - colon_token: node.colon_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn fold_data<F>(f: &mut F, node: crate::Data) -> crate::Data -where - F: Fold + ?Sized, -{ - match node { - crate::Data::Struct(_binding_0) => { - crate::Data::Struct(f.fold_data_struct(_binding_0)) - } - crate::Data::Enum(_binding_0) => crate::Data::Enum(f.fold_data_enum(_binding_0)), - crate::Data::Union(_binding_0) => { - crate::Data::Union(f.fold_data_union(_binding_0)) - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn fold_data_enum<F>(f: &mut F, node: crate::DataEnum) -> crate::DataEnum -where - F: Fold + ?Sized, -{ - crate::DataEnum { - enum_token: node.enum_token, - brace_token: node.brace_token, - variants: crate::punctuated::fold(node.variants, f, F::fold_variant), - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn fold_data_struct<F>(f: &mut F, node: crate::DataStruct) -> crate::DataStruct -where - F: Fold + ?Sized, -{ - crate::DataStruct { - struct_token: node.struct_token, - fields: f.fold_fields(node.fields), - semi_token: node.semi_token, - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn fold_data_union<F>(f: &mut F, node: crate::DataUnion) -> crate::DataUnion -where - F: Fold + ?Sized, -{ - crate::DataUnion { - union_token: node.union_token, - fields: f.fold_fields_named(node.fields), - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn fold_derive_input<F>(f: &mut F, node: crate::DeriveInput) -> crate::DeriveInput -where - F: Fold + ?Sized, -{ - crate::DeriveInput { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - data: f.fold_data(node.data), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr<F>(f: &mut F, node: crate::Expr) -> crate::Expr -where - F: Fold + ?Sized, -{ - match node { - crate::Expr::Array(_binding_0) => { - crate::Expr::Array(full!(f.fold_expr_array(_binding_0))) - } - crate::Expr::Assign(_binding_0) => { - crate::Expr::Assign(full!(f.fold_expr_assign(_binding_0))) - } - crate::Expr::Async(_binding_0) => { - crate::Expr::Async(full!(f.fold_expr_async(_binding_0))) - } - crate::Expr::Await(_binding_0) => { - crate::Expr::Await(full!(f.fold_expr_await(_binding_0))) - } - crate::Expr::Binary(_binding_0) => { - crate::Expr::Binary(f.fold_expr_binary(_binding_0)) - } - crate::Expr::Block(_binding_0) => { - crate::Expr::Block(full!(f.fold_expr_block(_binding_0))) - } - crate::Expr::Break(_binding_0) => { - crate::Expr::Break(full!(f.fold_expr_break(_binding_0))) - } - crate::Expr::Call(_binding_0) => crate::Expr::Call(f.fold_expr_call(_binding_0)), - crate::Expr::Cast(_binding_0) => crate::Expr::Cast(f.fold_expr_cast(_binding_0)), - crate::Expr::Closure(_binding_0) => { - crate::Expr::Closure(full!(f.fold_expr_closure(_binding_0))) - } - crate::Expr::Const(_binding_0) => { - crate::Expr::Const(full!(f.fold_expr_const(_binding_0))) - } - crate::Expr::Continue(_binding_0) => { - crate::Expr::Continue(full!(f.fold_expr_continue(_binding_0))) - } - crate::Expr::Field(_binding_0) => { - crate::Expr::Field(f.fold_expr_field(_binding_0)) - } - crate::Expr::ForLoop(_binding_0) => { - crate::Expr::ForLoop(full!(f.fold_expr_for_loop(_binding_0))) - } - crate::Expr::Group(_binding_0) => { - crate::Expr::Group(f.fold_expr_group(_binding_0)) - } - crate::Expr::If(_binding_0) => crate::Expr::If(full!(f.fold_expr_if(_binding_0))), - crate::Expr::Index(_binding_0) => { - crate::Expr::Index(f.fold_expr_index(_binding_0)) - } - crate::Expr::Infer(_binding_0) => { - crate::Expr::Infer(full!(f.fold_expr_infer(_binding_0))) - } - crate::Expr::Let(_binding_0) => { - crate::Expr::Let(full!(f.fold_expr_let(_binding_0))) - } - crate::Expr::Lit(_binding_0) => crate::Expr::Lit(f.fold_expr_lit(_binding_0)), - crate::Expr::Loop(_binding_0) => { - crate::Expr::Loop(full!(f.fold_expr_loop(_binding_0))) - } - crate::Expr::Macro(_binding_0) => { - crate::Expr::Macro(f.fold_expr_macro(_binding_0)) - } - crate::Expr::Match(_binding_0) => { - crate::Expr::Match(full!(f.fold_expr_match(_binding_0))) - } - crate::Expr::MethodCall(_binding_0) => { - crate::Expr::MethodCall(f.fold_expr_method_call(_binding_0)) - } - crate::Expr::Paren(_binding_0) => { - crate::Expr::Paren(f.fold_expr_paren(_binding_0)) - } - crate::Expr::Path(_binding_0) => crate::Expr::Path(f.fold_expr_path(_binding_0)), - crate::Expr::Range(_binding_0) => { - crate::Expr::Range(full!(f.fold_expr_range(_binding_0))) - } - crate::Expr::RawAddr(_binding_0) => { - crate::Expr::RawAddr(full!(f.fold_expr_raw_addr(_binding_0))) - } - crate::Expr::Reference(_binding_0) => { - crate::Expr::Reference(f.fold_expr_reference(_binding_0)) - } - crate::Expr::Repeat(_binding_0) => { - crate::Expr::Repeat(full!(f.fold_expr_repeat(_binding_0))) - } - crate::Expr::Return(_binding_0) => { - crate::Expr::Return(full!(f.fold_expr_return(_binding_0))) - } - crate::Expr::Struct(_binding_0) => { - crate::Expr::Struct(f.fold_expr_struct(_binding_0)) - } - crate::Expr::Try(_binding_0) => { - crate::Expr::Try(full!(f.fold_expr_try(_binding_0))) - } - crate::Expr::TryBlock(_binding_0) => { - crate::Expr::TryBlock(full!(f.fold_expr_try_block(_binding_0))) - } - crate::Expr::Tuple(_binding_0) => { - crate::Expr::Tuple(f.fold_expr_tuple(_binding_0)) - } - crate::Expr::Unary(_binding_0) => { - crate::Expr::Unary(f.fold_expr_unary(_binding_0)) - } - crate::Expr::Unsafe(_binding_0) => { - crate::Expr::Unsafe(full!(f.fold_expr_unsafe(_binding_0))) - } - crate::Expr::Verbatim(_binding_0) => { - crate::Expr::Verbatim(f.fold_token_stream(_binding_0)) - } - crate::Expr::While(_binding_0) => { - crate::Expr::While(full!(f.fold_expr_while(_binding_0))) - } - crate::Expr::Yield(_binding_0) => { - crate::Expr::Yield(full!(f.fold_expr_yield(_binding_0))) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_array<F>(f: &mut F, node: crate::ExprArray) -> crate::ExprArray -where - F: Fold + ?Sized, -{ - crate::ExprArray { - attrs: f.fold_attributes(node.attrs), - bracket_token: node.bracket_token, - elems: crate::punctuated::fold(node.elems, f, F::fold_expr), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_assign<F>(f: &mut F, node: crate::ExprAssign) -> crate::ExprAssign -where - F: Fold + ?Sized, -{ - crate::ExprAssign { - attrs: f.fold_attributes(node.attrs), - left: Box::new(f.fold_expr(*node.left)), - eq_token: node.eq_token, - right: Box::new(f.fold_expr(*node.right)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_async<F>(f: &mut F, node: crate::ExprAsync) -> crate::ExprAsync -where - F: Fold + ?Sized, -{ - crate::ExprAsync { - attrs: f.fold_attributes(node.attrs), - async_token: node.async_token, - capture: node.capture, - block: f.fold_block(node.block), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_await<F>(f: &mut F, node: crate::ExprAwait) -> crate::ExprAwait -where - F: Fold + ?Sized, -{ - crate::ExprAwait { - attrs: f.fold_attributes(node.attrs), - base: Box::new(f.fold_expr(*node.base)), - dot_token: node.dot_token, - await_token: node.await_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_binary<F>(f: &mut F, node: crate::ExprBinary) -> crate::ExprBinary -where - F: Fold + ?Sized, -{ - crate::ExprBinary { - attrs: f.fold_attributes(node.attrs), - left: Box::new(f.fold_expr(*node.left)), - op: f.fold_bin_op(node.op), - right: Box::new(f.fold_expr(*node.right)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_block<F>(f: &mut F, node: crate::ExprBlock) -> crate::ExprBlock -where - F: Fold + ?Sized, -{ - crate::ExprBlock { - attrs: f.fold_attributes(node.attrs), - label: (node.label).map(|it| f.fold_label(it)), - block: f.fold_block(node.block), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_break<F>(f: &mut F, node: crate::ExprBreak) -> crate::ExprBreak -where - F: Fold + ?Sized, -{ - crate::ExprBreak { - attrs: f.fold_attributes(node.attrs), - break_token: node.break_token, - label: (node.label).map(|it| f.fold_lifetime(it)), - expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_call<F>(f: &mut F, node: crate::ExprCall) -> crate::ExprCall -where - F: Fold + ?Sized, -{ - crate::ExprCall { - attrs: f.fold_attributes(node.attrs), - func: Box::new(f.fold_expr(*node.func)), - paren_token: node.paren_token, - args: crate::punctuated::fold(node.args, f, F::fold_expr), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_cast<F>(f: &mut F, node: crate::ExprCast) -> crate::ExprCast -where - F: Fold + ?Sized, -{ - crate::ExprCast { - attrs: f.fold_attributes(node.attrs), - expr: Box::new(f.fold_expr(*node.expr)), - as_token: node.as_token, - ty: Box::new(f.fold_type(*node.ty)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_closure<F>(f: &mut F, node: crate::ExprClosure) -> crate::ExprClosure -where - F: Fold + ?Sized, -{ - crate::ExprClosure { - attrs: f.fold_attributes(node.attrs), - lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), - constness: node.constness, - movability: node.movability, - asyncness: node.asyncness, - capture: node.capture, - or1_token: node.or1_token, - inputs: crate::punctuated::fold(node.inputs, f, F::fold_pat), - or2_token: node.or2_token, - output: f.fold_return_type(node.output), - body: Box::new(f.fold_expr(*node.body)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_const<F>(f: &mut F, node: crate::ExprConst) -> crate::ExprConst -where - F: Fold + ?Sized, -{ - crate::ExprConst { - attrs: f.fold_attributes(node.attrs), - const_token: node.const_token, - block: f.fold_block(node.block), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_continue<F>(f: &mut F, node: crate::ExprContinue) -> crate::ExprContinue -where - F: Fold + ?Sized, -{ - crate::ExprContinue { - attrs: f.fold_attributes(node.attrs), - continue_token: node.continue_token, - label: (node.label).map(|it| f.fold_lifetime(it)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_field<F>(f: &mut F, node: crate::ExprField) -> crate::ExprField -where - F: Fold + ?Sized, -{ - crate::ExprField { - attrs: f.fold_attributes(node.attrs), - base: Box::new(f.fold_expr(*node.base)), - dot_token: node.dot_token, - member: f.fold_member(node.member), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_for_loop<F>(f: &mut F, node: crate::ExprForLoop) -> crate::ExprForLoop -where - F: Fold + ?Sized, -{ - crate::ExprForLoop { - attrs: f.fold_attributes(node.attrs), - label: (node.label).map(|it| f.fold_label(it)), - for_token: node.for_token, - pat: Box::new(f.fold_pat(*node.pat)), - in_token: node.in_token, - expr: Box::new(f.fold_expr(*node.expr)), - body: f.fold_block(node.body), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_group<F>(f: &mut F, node: crate::ExprGroup) -> crate::ExprGroup -where - F: Fold + ?Sized, -{ - crate::ExprGroup { - attrs: f.fold_attributes(node.attrs), - group_token: node.group_token, - expr: Box::new(f.fold_expr(*node.expr)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_if<F>(f: &mut F, node: crate::ExprIf) -> crate::ExprIf -where - F: Fold + ?Sized, -{ - crate::ExprIf { - attrs: f.fold_attributes(node.attrs), - if_token: node.if_token, - cond: Box::new(f.fold_expr(*node.cond)), - then_branch: f.fold_block(node.then_branch), - else_branch: (node.else_branch) - .map(|it| ((it).0, Box::new(f.fold_expr(*(it).1)))), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_index<F>(f: &mut F, node: crate::ExprIndex) -> crate::ExprIndex -where - F: Fold + ?Sized, -{ - crate::ExprIndex { - attrs: f.fold_attributes(node.attrs), - expr: Box::new(f.fold_expr(*node.expr)), - bracket_token: node.bracket_token, - index: Box::new(f.fold_expr(*node.index)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_infer<F>(f: &mut F, node: crate::ExprInfer) -> crate::ExprInfer -where - F: Fold + ?Sized, -{ - crate::ExprInfer { - attrs: f.fold_attributes(node.attrs), - underscore_token: node.underscore_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_let<F>(f: &mut F, node: crate::ExprLet) -> crate::ExprLet -where - F: Fold + ?Sized, -{ - crate::ExprLet { - attrs: f.fold_attributes(node.attrs), - let_token: node.let_token, - pat: Box::new(f.fold_pat(*node.pat)), - eq_token: node.eq_token, - expr: Box::new(f.fold_expr(*node.expr)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_lit<F>(f: &mut F, node: crate::ExprLit) -> crate::ExprLit -where - F: Fold + ?Sized, -{ - crate::ExprLit { - attrs: f.fold_attributes(node.attrs), - lit: f.fold_lit(node.lit), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_loop<F>(f: &mut F, node: crate::ExprLoop) -> crate::ExprLoop -where - F: Fold + ?Sized, -{ - crate::ExprLoop { - attrs: f.fold_attributes(node.attrs), - label: (node.label).map(|it| f.fold_label(it)), - loop_token: node.loop_token, - body: f.fold_block(node.body), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_macro<F>(f: &mut F, node: crate::ExprMacro) -> crate::ExprMacro -where - F: Fold + ?Sized, -{ - crate::ExprMacro { - attrs: f.fold_attributes(node.attrs), - mac: f.fold_macro(node.mac), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_match<F>(f: &mut F, node: crate::ExprMatch) -> crate::ExprMatch -where - F: Fold + ?Sized, -{ - crate::ExprMatch { - attrs: f.fold_attributes(node.attrs), - match_token: node.match_token, - expr: Box::new(f.fold_expr(*node.expr)), - brace_token: node.brace_token, - arms: fold_vec(node.arms, f, F::fold_arm), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_method_call<F>( - f: &mut F, - node: crate::ExprMethodCall, -) -> crate::ExprMethodCall -where - F: Fold + ?Sized, -{ - crate::ExprMethodCall { - attrs: f.fold_attributes(node.attrs), - receiver: Box::new(f.fold_expr(*node.receiver)), - dot_token: node.dot_token, - method: f.fold_ident(node.method), - turbofish: (node.turbofish) - .map(|it| f.fold_angle_bracketed_generic_arguments(it)), - paren_token: node.paren_token, - args: crate::punctuated::fold(node.args, f, F::fold_expr), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_paren<F>(f: &mut F, node: crate::ExprParen) -> crate::ExprParen -where - F: Fold + ?Sized, -{ - crate::ExprParen { - attrs: f.fold_attributes(node.attrs), - paren_token: node.paren_token, - expr: Box::new(f.fold_expr(*node.expr)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_path<F>(f: &mut F, node: crate::ExprPath) -> crate::ExprPath -where - F: Fold + ?Sized, -{ - crate::ExprPath { - attrs: f.fold_attributes(node.attrs), - qself: (node.qself).map(|it| f.fold_qself(it)), - path: f.fold_path(node.path), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_range<F>(f: &mut F, node: crate::ExprRange) -> crate::ExprRange -where - F: Fold + ?Sized, -{ - crate::ExprRange { - attrs: f.fold_attributes(node.attrs), - start: (node.start).map(|it| Box::new(f.fold_expr(*it))), - limits: f.fold_range_limits(node.limits), - end: (node.end).map(|it| Box::new(f.fold_expr(*it))), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_raw_addr<F>(f: &mut F, node: crate::ExprRawAddr) -> crate::ExprRawAddr -where - F: Fold + ?Sized, -{ - crate::ExprRawAddr { - attrs: f.fold_attributes(node.attrs), - and_token: node.and_token, - raw: node.raw, - mutability: f.fold_pointer_mutability(node.mutability), - expr: Box::new(f.fold_expr(*node.expr)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_reference<F>( - f: &mut F, - node: crate::ExprReference, -) -> crate::ExprReference -where - F: Fold + ?Sized, -{ - crate::ExprReference { - attrs: f.fold_attributes(node.attrs), - and_token: node.and_token, - mutability: node.mutability, - expr: Box::new(f.fold_expr(*node.expr)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_repeat<F>(f: &mut F, node: crate::ExprRepeat) -> crate::ExprRepeat -where - F: Fold + ?Sized, -{ - crate::ExprRepeat { - attrs: f.fold_attributes(node.attrs), - bracket_token: node.bracket_token, - expr: Box::new(f.fold_expr(*node.expr)), - semi_token: node.semi_token, - len: Box::new(f.fold_expr(*node.len)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_return<F>(f: &mut F, node: crate::ExprReturn) -> crate::ExprReturn -where - F: Fold + ?Sized, -{ - crate::ExprReturn { - attrs: f.fold_attributes(node.attrs), - return_token: node.return_token, - expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_struct<F>(f: &mut F, node: crate::ExprStruct) -> crate::ExprStruct -where - F: Fold + ?Sized, -{ - crate::ExprStruct { - attrs: f.fold_attributes(node.attrs), - qself: (node.qself).map(|it| f.fold_qself(it)), - path: f.fold_path(node.path), - brace_token: node.brace_token, - fields: crate::punctuated::fold(node.fields, f, F::fold_field_value), - dot2_token: node.dot2_token, - rest: (node.rest).map(|it| Box::new(f.fold_expr(*it))), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_try<F>(f: &mut F, node: crate::ExprTry) -> crate::ExprTry -where - F: Fold + ?Sized, -{ - crate::ExprTry { - attrs: f.fold_attributes(node.attrs), - expr: Box::new(f.fold_expr(*node.expr)), - question_token: node.question_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_try_block<F>( - f: &mut F, - node: crate::ExprTryBlock, -) -> crate::ExprTryBlock -where - F: Fold + ?Sized, -{ - crate::ExprTryBlock { - attrs: f.fold_attributes(node.attrs), - try_token: node.try_token, - block: f.fold_block(node.block), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_tuple<F>(f: &mut F, node: crate::ExprTuple) -> crate::ExprTuple -where - F: Fold + ?Sized, -{ - crate::ExprTuple { - attrs: f.fold_attributes(node.attrs), - paren_token: node.paren_token, - elems: crate::punctuated::fold(node.elems, f, F::fold_expr), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_expr_unary<F>(f: &mut F, node: crate::ExprUnary) -> crate::ExprUnary -where - F: Fold + ?Sized, -{ - crate::ExprUnary { - attrs: f.fold_attributes(node.attrs), - op: f.fold_un_op(node.op), - expr: Box::new(f.fold_expr(*node.expr)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_unsafe<F>(f: &mut F, node: crate::ExprUnsafe) -> crate::ExprUnsafe -where - F: Fold + ?Sized, -{ - crate::ExprUnsafe { - attrs: f.fold_attributes(node.attrs), - unsafe_token: node.unsafe_token, - block: f.fold_block(node.block), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_while<F>(f: &mut F, node: crate::ExprWhile) -> crate::ExprWhile -where - F: Fold + ?Sized, -{ - crate::ExprWhile { - attrs: f.fold_attributes(node.attrs), - label: (node.label).map(|it| f.fold_label(it)), - while_token: node.while_token, - cond: Box::new(f.fold_expr(*node.cond)), - body: f.fold_block(node.body), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_expr_yield<F>(f: &mut F, node: crate::ExprYield) -> crate::ExprYield -where - F: Fold + ?Sized, -{ - crate::ExprYield { - attrs: f.fold_attributes(node.attrs), - yield_token: node.yield_token, - expr: (node.expr).map(|it| Box::new(f.fold_expr(*it))), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_field<F>(f: &mut F, node: crate::Field) -> crate::Field -where - F: Fold + ?Sized, -{ - crate::Field { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - mutability: f.fold_field_mutability(node.mutability), - ident: (node.ident).map(|it| f.fold_ident(it)), - colon_token: node.colon_token, - ty: f.fold_type(node.ty), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_field_mutability<F>( - f: &mut F, - node: crate::FieldMutability, -) -> crate::FieldMutability -where - F: Fold + ?Sized, -{ - match node { - crate::FieldMutability::None => crate::FieldMutability::None, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_field_pat<F>(f: &mut F, node: crate::FieldPat) -> crate::FieldPat -where - F: Fold + ?Sized, -{ - crate::FieldPat { - attrs: f.fold_attributes(node.attrs), - member: f.fold_member(node.member), - colon_token: node.colon_token, - pat: Box::new(f.fold_pat(*node.pat)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_field_value<F>(f: &mut F, node: crate::FieldValue) -> crate::FieldValue -where - F: Fold + ?Sized, -{ - crate::FieldValue { - attrs: f.fold_attributes(node.attrs), - member: f.fold_member(node.member), - colon_token: node.colon_token, - expr: f.fold_expr(node.expr), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_fields<F>(f: &mut F, node: crate::Fields) -> crate::Fields -where - F: Fold + ?Sized, -{ - match node { - crate::Fields::Named(_binding_0) => { - crate::Fields::Named(f.fold_fields_named(_binding_0)) - } - crate::Fields::Unnamed(_binding_0) => { - crate::Fields::Unnamed(f.fold_fields_unnamed(_binding_0)) - } - crate::Fields::Unit => crate::Fields::Unit, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_fields_named<F>(f: &mut F, node: crate::FieldsNamed) -> crate::FieldsNamed -where - F: Fold + ?Sized, -{ - crate::FieldsNamed { - brace_token: node.brace_token, - named: crate::punctuated::fold(node.named, f, F::fold_field), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_fields_unnamed<F>( - f: &mut F, - node: crate::FieldsUnnamed, -) -> crate::FieldsUnnamed -where - F: Fold + ?Sized, -{ - crate::FieldsUnnamed { - paren_token: node.paren_token, - unnamed: crate::punctuated::fold(node.unnamed, f, F::fold_field), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_file<F>(f: &mut F, node: crate::File) -> crate::File -where - F: Fold + ?Sized, -{ - crate::File { - shebang: node.shebang, - attrs: f.fold_attributes(node.attrs), - items: fold_vec(node.items, f, F::fold_item), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_fn_arg<F>(f: &mut F, node: crate::FnArg) -> crate::FnArg -where - F: Fold + ?Sized, -{ - match node { - crate::FnArg::Receiver(_binding_0) => { - crate::FnArg::Receiver(f.fold_receiver(_binding_0)) - } - crate::FnArg::Typed(_binding_0) => { - crate::FnArg::Typed(f.fold_pat_type(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_foreign_item<F>(f: &mut F, node: crate::ForeignItem) -> crate::ForeignItem -where - F: Fold + ?Sized, -{ - match node { - crate::ForeignItem::Fn(_binding_0) => { - crate::ForeignItem::Fn(f.fold_foreign_item_fn(_binding_0)) - } - crate::ForeignItem::Static(_binding_0) => { - crate::ForeignItem::Static(f.fold_foreign_item_static(_binding_0)) - } - crate::ForeignItem::Type(_binding_0) => { - crate::ForeignItem::Type(f.fold_foreign_item_type(_binding_0)) - } - crate::ForeignItem::Macro(_binding_0) => { - crate::ForeignItem::Macro(f.fold_foreign_item_macro(_binding_0)) - } - crate::ForeignItem::Verbatim(_binding_0) => { - crate::ForeignItem::Verbatim(f.fold_token_stream(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_foreign_item_fn<F>( - f: &mut F, - node: crate::ForeignItemFn, -) -> crate::ForeignItemFn -where - F: Fold + ?Sized, -{ - crate::ForeignItemFn { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - sig: f.fold_signature(node.sig), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_foreign_item_macro<F>( - f: &mut F, - node: crate::ForeignItemMacro, -) -> crate::ForeignItemMacro -where - F: Fold + ?Sized, -{ - crate::ForeignItemMacro { - attrs: f.fold_attributes(node.attrs), - mac: f.fold_macro(node.mac), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_foreign_item_static<F>( - f: &mut F, - node: crate::ForeignItemStatic, -) -> crate::ForeignItemStatic -where - F: Fold + ?Sized, -{ - crate::ForeignItemStatic { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - static_token: node.static_token, - mutability: f.fold_static_mutability(node.mutability), - ident: f.fold_ident(node.ident), - colon_token: node.colon_token, - ty: Box::new(f.fold_type(*node.ty)), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_foreign_item_type<F>( - f: &mut F, - node: crate::ForeignItemType, -) -> crate::ForeignItemType -where - F: Fold + ?Sized, -{ - crate::ForeignItemType { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - type_token: node.type_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - semi_token: node.semi_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_generic_argument<F>( - f: &mut F, - node: crate::GenericArgument, -) -> crate::GenericArgument -where - F: Fold + ?Sized, -{ - match node { - crate::GenericArgument::Lifetime(_binding_0) => { - crate::GenericArgument::Lifetime(f.fold_lifetime(_binding_0)) - } - crate::GenericArgument::Type(_binding_0) => { - crate::GenericArgument::Type(f.fold_type(_binding_0)) - } - crate::GenericArgument::Const(_binding_0) => { - crate::GenericArgument::Const(f.fold_expr(_binding_0)) - } - crate::GenericArgument::AssocType(_binding_0) => { - crate::GenericArgument::AssocType(f.fold_assoc_type(_binding_0)) - } - crate::GenericArgument::AssocConst(_binding_0) => { - crate::GenericArgument::AssocConst(f.fold_assoc_const(_binding_0)) - } - crate::GenericArgument::Constraint(_binding_0) => { - crate::GenericArgument::Constraint(f.fold_constraint(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_generic_param<F>(f: &mut F, node: crate::GenericParam) -> crate::GenericParam -where - F: Fold + ?Sized, -{ - match node { - crate::GenericParam::Lifetime(_binding_0) => { - crate::GenericParam::Lifetime(f.fold_lifetime_param(_binding_0)) - } - crate::GenericParam::Type(_binding_0) => { - crate::GenericParam::Type(f.fold_type_param(_binding_0)) - } - crate::GenericParam::Const(_binding_0) => { - crate::GenericParam::Const(f.fold_const_param(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_generics<F>(f: &mut F, node: crate::Generics) -> crate::Generics -where - F: Fold + ?Sized, -{ - crate::Generics { - lt_token: node.lt_token, - params: crate::punctuated::fold(node.params, f, F::fold_generic_param), - gt_token: node.gt_token, - where_clause: (node.where_clause).map(|it| f.fold_where_clause(it)), - } -} -pub fn fold_ident<F>(f: &mut F, node: proc_macro2::Ident) -> proc_macro2::Ident -where - F: Fold + ?Sized, -{ - let mut node = node; - let span = f.fold_span(node.span()); - node.set_span(span); - node -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_impl_item<F>(f: &mut F, node: crate::ImplItem) -> crate::ImplItem -where - F: Fold + ?Sized, -{ - match node { - crate::ImplItem::Const(_binding_0) => { - crate::ImplItem::Const(f.fold_impl_item_const(_binding_0)) - } - crate::ImplItem::Fn(_binding_0) => { - crate::ImplItem::Fn(f.fold_impl_item_fn(_binding_0)) - } - crate::ImplItem::Type(_binding_0) => { - crate::ImplItem::Type(f.fold_impl_item_type(_binding_0)) - } - crate::ImplItem::Macro(_binding_0) => { - crate::ImplItem::Macro(f.fold_impl_item_macro(_binding_0)) - } - crate::ImplItem::Verbatim(_binding_0) => { - crate::ImplItem::Verbatim(f.fold_token_stream(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_impl_item_const<F>( - f: &mut F, - node: crate::ImplItemConst, -) -> crate::ImplItemConst -where - F: Fold + ?Sized, -{ - crate::ImplItemConst { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - defaultness: node.defaultness, - const_token: node.const_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - colon_token: node.colon_token, - ty: f.fold_type(node.ty), - eq_token: node.eq_token, - expr: f.fold_expr(node.expr), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_impl_item_fn<F>(f: &mut F, node: crate::ImplItemFn) -> crate::ImplItemFn -where - F: Fold + ?Sized, -{ - crate::ImplItemFn { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - defaultness: node.defaultness, - sig: f.fold_signature(node.sig), - block: f.fold_block(node.block), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_impl_item_macro<F>( - f: &mut F, - node: crate::ImplItemMacro, -) -> crate::ImplItemMacro -where - F: Fold + ?Sized, -{ - crate::ImplItemMacro { - attrs: f.fold_attributes(node.attrs), - mac: f.fold_macro(node.mac), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_impl_item_type<F>( - f: &mut F, - node: crate::ImplItemType, -) -> crate::ImplItemType -where - F: Fold + ?Sized, -{ - crate::ImplItemType { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - defaultness: node.defaultness, - type_token: node.type_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - eq_token: node.eq_token, - ty: f.fold_type(node.ty), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_impl_restriction<F>( - f: &mut F, - node: crate::ImplRestriction, -) -> crate::ImplRestriction -where - F: Fold + ?Sized, -{ - match node {} -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_index<F>(f: &mut F, node: crate::Index) -> crate::Index -where - F: Fold + ?Sized, -{ - crate::Index { - index: node.index, - span: f.fold_span(node.span), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item<F>(f: &mut F, node: crate::Item) -> crate::Item -where - F: Fold + ?Sized, -{ - match node { - crate::Item::Const(_binding_0) => { - crate::Item::Const(f.fold_item_const(_binding_0)) - } - crate::Item::Enum(_binding_0) => crate::Item::Enum(f.fold_item_enum(_binding_0)), - crate::Item::ExternCrate(_binding_0) => { - crate::Item::ExternCrate(f.fold_item_extern_crate(_binding_0)) - } - crate::Item::Fn(_binding_0) => crate::Item::Fn(f.fold_item_fn(_binding_0)), - crate::Item::ForeignMod(_binding_0) => { - crate::Item::ForeignMod(f.fold_item_foreign_mod(_binding_0)) - } - crate::Item::Impl(_binding_0) => crate::Item::Impl(f.fold_item_impl(_binding_0)), - crate::Item::Macro(_binding_0) => { - crate::Item::Macro(f.fold_item_macro(_binding_0)) - } - crate::Item::Mod(_binding_0) => crate::Item::Mod(f.fold_item_mod(_binding_0)), - crate::Item::Static(_binding_0) => { - crate::Item::Static(f.fold_item_static(_binding_0)) - } - crate::Item::Struct(_binding_0) => { - crate::Item::Struct(f.fold_item_struct(_binding_0)) - } - crate::Item::Trait(_binding_0) => { - crate::Item::Trait(f.fold_item_trait(_binding_0)) - } - crate::Item::TraitAlias(_binding_0) => { - crate::Item::TraitAlias(f.fold_item_trait_alias(_binding_0)) - } - crate::Item::Type(_binding_0) => crate::Item::Type(f.fold_item_type(_binding_0)), - crate::Item::Union(_binding_0) => { - crate::Item::Union(f.fold_item_union(_binding_0)) - } - crate::Item::Use(_binding_0) => crate::Item::Use(f.fold_item_use(_binding_0)), - crate::Item::Verbatim(_binding_0) => { - crate::Item::Verbatim(f.fold_token_stream(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_const<F>(f: &mut F, node: crate::ItemConst) -> crate::ItemConst -where - F: Fold + ?Sized, -{ - crate::ItemConst { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - const_token: node.const_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - colon_token: node.colon_token, - ty: Box::new(f.fold_type(*node.ty)), - eq_token: node.eq_token, - expr: Box::new(f.fold_expr(*node.expr)), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_enum<F>(f: &mut F, node: crate::ItemEnum) -> crate::ItemEnum -where - F: Fold + ?Sized, -{ - crate::ItemEnum { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - enum_token: node.enum_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - brace_token: node.brace_token, - variants: crate::punctuated::fold(node.variants, f, F::fold_variant), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_extern_crate<F>( - f: &mut F, - node: crate::ItemExternCrate, -) -> crate::ItemExternCrate -where - F: Fold + ?Sized, -{ - crate::ItemExternCrate { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - extern_token: node.extern_token, - crate_token: node.crate_token, - ident: f.fold_ident(node.ident), - rename: (node.rename).map(|it| ((it).0, f.fold_ident((it).1))), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_fn<F>(f: &mut F, node: crate::ItemFn) -> crate::ItemFn -where - F: Fold + ?Sized, -{ - crate::ItemFn { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - sig: f.fold_signature(node.sig), - block: Box::new(f.fold_block(*node.block)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_foreign_mod<F>( - f: &mut F, - node: crate::ItemForeignMod, -) -> crate::ItemForeignMod -where - F: Fold + ?Sized, -{ - crate::ItemForeignMod { - attrs: f.fold_attributes(node.attrs), - unsafety: node.unsafety, - abi: f.fold_abi(node.abi), - brace_token: node.brace_token, - items: fold_vec(node.items, f, F::fold_foreign_item), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_impl<F>(f: &mut F, node: crate::ItemImpl) -> crate::ItemImpl -where - F: Fold + ?Sized, -{ - crate::ItemImpl { - attrs: f.fold_attributes(node.attrs), - defaultness: node.defaultness, - unsafety: node.unsafety, - impl_token: node.impl_token, - generics: f.fold_generics(node.generics), - trait_: (node.trait_).map(|it| ((it).0, f.fold_path((it).1), (it).2)), - self_ty: Box::new(f.fold_type(*node.self_ty)), - brace_token: node.brace_token, - items: fold_vec(node.items, f, F::fold_impl_item), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_macro<F>(f: &mut F, node: crate::ItemMacro) -> crate::ItemMacro -where - F: Fold + ?Sized, -{ - crate::ItemMacro { - attrs: f.fold_attributes(node.attrs), - ident: (node.ident).map(|it| f.fold_ident(it)), - mac: f.fold_macro(node.mac), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_mod<F>(f: &mut F, node: crate::ItemMod) -> crate::ItemMod -where - F: Fold + ?Sized, -{ - crate::ItemMod { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - unsafety: node.unsafety, - mod_token: node.mod_token, - ident: f.fold_ident(node.ident), - content: (node.content).map(|it| ((it).0, fold_vec((it).1, f, F::fold_item))), - semi: node.semi, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_static<F>(f: &mut F, node: crate::ItemStatic) -> crate::ItemStatic -where - F: Fold + ?Sized, -{ - crate::ItemStatic { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - static_token: node.static_token, - mutability: f.fold_static_mutability(node.mutability), - ident: f.fold_ident(node.ident), - colon_token: node.colon_token, - ty: Box::new(f.fold_type(*node.ty)), - eq_token: node.eq_token, - expr: Box::new(f.fold_expr(*node.expr)), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_struct<F>(f: &mut F, node: crate::ItemStruct) -> crate::ItemStruct -where - F: Fold + ?Sized, -{ - crate::ItemStruct { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - struct_token: node.struct_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - fields: f.fold_fields(node.fields), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_trait<F>(f: &mut F, node: crate::ItemTrait) -> crate::ItemTrait -where - F: Fold + ?Sized, -{ - crate::ItemTrait { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - unsafety: node.unsafety, - auto_token: node.auto_token, - restriction: (node.restriction).map(|it| f.fold_impl_restriction(it)), - trait_token: node.trait_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - colon_token: node.colon_token, - supertraits: crate::punctuated::fold( - node.supertraits, - f, - F::fold_type_param_bound, - ), - brace_token: node.brace_token, - items: fold_vec(node.items, f, F::fold_trait_item), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_trait_alias<F>( - f: &mut F, - node: crate::ItemTraitAlias, -) -> crate::ItemTraitAlias -where - F: Fold + ?Sized, -{ - crate::ItemTraitAlias { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - trait_token: node.trait_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - eq_token: node.eq_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_type<F>(f: &mut F, node: crate::ItemType) -> crate::ItemType -where - F: Fold + ?Sized, -{ - crate::ItemType { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - type_token: node.type_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - eq_token: node.eq_token, - ty: Box::new(f.fold_type(*node.ty)), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_union<F>(f: &mut F, node: crate::ItemUnion) -> crate::ItemUnion -where - F: Fold + ?Sized, -{ - crate::ItemUnion { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - union_token: node.union_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - fields: f.fold_fields_named(node.fields), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_item_use<F>(f: &mut F, node: crate::ItemUse) -> crate::ItemUse -where - F: Fold + ?Sized, -{ - crate::ItemUse { - attrs: f.fold_attributes(node.attrs), - vis: f.fold_visibility(node.vis), - use_token: node.use_token, - leading_colon: node.leading_colon, - tree: f.fold_use_tree(node.tree), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_label<F>(f: &mut F, node: crate::Label) -> crate::Label -where - F: Fold + ?Sized, -{ - crate::Label { - name: f.fold_lifetime(node.name), - colon_token: node.colon_token, - } -} -pub fn fold_lifetime<F>(f: &mut F, node: crate::Lifetime) -> crate::Lifetime -where - F: Fold + ?Sized, -{ - crate::Lifetime { - apostrophe: f.fold_span(node.apostrophe), - ident: f.fold_ident(node.ident), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_lifetime_param<F>( - f: &mut F, - node: crate::LifetimeParam, -) -> crate::LifetimeParam -where - F: Fold + ?Sized, -{ - crate::LifetimeParam { - attrs: f.fold_attributes(node.attrs), - lifetime: f.fold_lifetime(node.lifetime), - colon_token: node.colon_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_lifetime), - } -} -pub fn fold_lit<F>(f: &mut F, node: crate::Lit) -> crate::Lit -where - F: Fold + ?Sized, -{ - match node { - crate::Lit::Str(_binding_0) => crate::Lit::Str(f.fold_lit_str(_binding_0)), - crate::Lit::ByteStr(_binding_0) => { - crate::Lit::ByteStr(f.fold_lit_byte_str(_binding_0)) - } - crate::Lit::CStr(_binding_0) => crate::Lit::CStr(f.fold_lit_cstr(_binding_0)), - crate::Lit::Byte(_binding_0) => crate::Lit::Byte(f.fold_lit_byte(_binding_0)), - crate::Lit::Char(_binding_0) => crate::Lit::Char(f.fold_lit_char(_binding_0)), - crate::Lit::Int(_binding_0) => crate::Lit::Int(f.fold_lit_int(_binding_0)), - crate::Lit::Float(_binding_0) => crate::Lit::Float(f.fold_lit_float(_binding_0)), - crate::Lit::Bool(_binding_0) => crate::Lit::Bool(f.fold_lit_bool(_binding_0)), - crate::Lit::Verbatim(_binding_0) => crate::Lit::Verbatim(_binding_0), - } -} -pub fn fold_lit_bool<F>(f: &mut F, node: crate::LitBool) -> crate::LitBool -where - F: Fold + ?Sized, -{ - crate::LitBool { - value: node.value, - span: f.fold_span(node.span), - } -} -pub fn fold_lit_byte<F>(f: &mut F, node: crate::LitByte) -> crate::LitByte -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -pub fn fold_lit_byte_str<F>(f: &mut F, node: crate::LitByteStr) -> crate::LitByteStr -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -pub fn fold_lit_cstr<F>(f: &mut F, node: crate::LitCStr) -> crate::LitCStr -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -pub fn fold_lit_char<F>(f: &mut F, node: crate::LitChar) -> crate::LitChar -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -pub fn fold_lit_float<F>(f: &mut F, node: crate::LitFloat) -> crate::LitFloat -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -pub fn fold_lit_int<F>(f: &mut F, node: crate::LitInt) -> crate::LitInt -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -pub fn fold_lit_str<F>(f: &mut F, node: crate::LitStr) -> crate::LitStr -where - F: Fold + ?Sized, -{ - let span = f.fold_span(node.span()); - let mut node = node; - node.set_span(span); - node -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_local<F>(f: &mut F, node: crate::Local) -> crate::Local -where - F: Fold + ?Sized, -{ - crate::Local { - attrs: f.fold_attributes(node.attrs), - let_token: node.let_token, - pat: f.fold_pat(node.pat), - init: (node.init).map(|it| f.fold_local_init(it)), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_local_init<F>(f: &mut F, node: crate::LocalInit) -> crate::LocalInit -where - F: Fold + ?Sized, -{ - crate::LocalInit { - eq_token: node.eq_token, - expr: Box::new(f.fold_expr(*node.expr)), - diverge: (node.diverge).map(|it| ((it).0, Box::new(f.fold_expr(*(it).1)))), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_macro<F>(f: &mut F, node: crate::Macro) -> crate::Macro -where - F: Fold + ?Sized, -{ - crate::Macro { - path: f.fold_path(node.path), - bang_token: node.bang_token, - delimiter: f.fold_macro_delimiter(node.delimiter), - tokens: f.fold_token_stream(node.tokens), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_macro_delimiter<F>( - f: &mut F, - node: crate::MacroDelimiter, -) -> crate::MacroDelimiter -where - F: Fold + ?Sized, -{ - match node { - crate::MacroDelimiter::Paren(_binding_0) => { - crate::MacroDelimiter::Paren(_binding_0) - } - crate::MacroDelimiter::Brace(_binding_0) => { - crate::MacroDelimiter::Brace(_binding_0) - } - crate::MacroDelimiter::Bracket(_binding_0) => { - crate::MacroDelimiter::Bracket(_binding_0) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_member<F>(f: &mut F, node: crate::Member) -> crate::Member -where - F: Fold + ?Sized, -{ - match node { - crate::Member::Named(_binding_0) => { - crate::Member::Named(f.fold_ident(_binding_0)) - } - crate::Member::Unnamed(_binding_0) => { - crate::Member::Unnamed(f.fold_index(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_meta<F>(f: &mut F, node: crate::Meta) -> crate::Meta -where - F: Fold + ?Sized, -{ - match node { - crate::Meta::Path(_binding_0) => crate::Meta::Path(f.fold_path(_binding_0)), - crate::Meta::List(_binding_0) => crate::Meta::List(f.fold_meta_list(_binding_0)), - crate::Meta::NameValue(_binding_0) => { - crate::Meta::NameValue(f.fold_meta_name_value(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_meta_list<F>(f: &mut F, node: crate::MetaList) -> crate::MetaList -where - F: Fold + ?Sized, -{ - crate::MetaList { - path: f.fold_path(node.path), - delimiter: f.fold_macro_delimiter(node.delimiter), - tokens: f.fold_token_stream(node.tokens), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_meta_name_value<F>( - f: &mut F, - node: crate::MetaNameValue, -) -> crate::MetaNameValue -where - F: Fold + ?Sized, -{ - crate::MetaNameValue { - path: f.fold_path(node.path), - eq_token: node.eq_token, - value: f.fold_expr(node.value), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_parenthesized_generic_arguments<F>( - f: &mut F, - node: crate::ParenthesizedGenericArguments, -) -> crate::ParenthesizedGenericArguments -where - F: Fold + ?Sized, -{ - crate::ParenthesizedGenericArguments { - paren_token: node.paren_token, - inputs: crate::punctuated::fold(node.inputs, f, F::fold_type), - output: f.fold_return_type(node.output), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat<F>(f: &mut F, node: crate::Pat) -> crate::Pat -where - F: Fold + ?Sized, -{ - match node { - crate::Pat::Const(_binding_0) => crate::Pat::Const(f.fold_expr_const(_binding_0)), - crate::Pat::Ident(_binding_0) => crate::Pat::Ident(f.fold_pat_ident(_binding_0)), - crate::Pat::Lit(_binding_0) => crate::Pat::Lit(f.fold_expr_lit(_binding_0)), - crate::Pat::Macro(_binding_0) => crate::Pat::Macro(f.fold_expr_macro(_binding_0)), - crate::Pat::Or(_binding_0) => crate::Pat::Or(f.fold_pat_or(_binding_0)), - crate::Pat::Paren(_binding_0) => crate::Pat::Paren(f.fold_pat_paren(_binding_0)), - crate::Pat::Path(_binding_0) => crate::Pat::Path(f.fold_expr_path(_binding_0)), - crate::Pat::Range(_binding_0) => crate::Pat::Range(f.fold_expr_range(_binding_0)), - crate::Pat::Reference(_binding_0) => { - crate::Pat::Reference(f.fold_pat_reference(_binding_0)) - } - crate::Pat::Rest(_binding_0) => crate::Pat::Rest(f.fold_pat_rest(_binding_0)), - crate::Pat::Slice(_binding_0) => crate::Pat::Slice(f.fold_pat_slice(_binding_0)), - crate::Pat::Struct(_binding_0) => { - crate::Pat::Struct(f.fold_pat_struct(_binding_0)) - } - crate::Pat::Tuple(_binding_0) => crate::Pat::Tuple(f.fold_pat_tuple(_binding_0)), - crate::Pat::TupleStruct(_binding_0) => { - crate::Pat::TupleStruct(f.fold_pat_tuple_struct(_binding_0)) - } - crate::Pat::Type(_binding_0) => crate::Pat::Type(f.fold_pat_type(_binding_0)), - crate::Pat::Verbatim(_binding_0) => { - crate::Pat::Verbatim(f.fold_token_stream(_binding_0)) - } - crate::Pat::Wild(_binding_0) => crate::Pat::Wild(f.fold_pat_wild(_binding_0)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_ident<F>(f: &mut F, node: crate::PatIdent) -> crate::PatIdent -where - F: Fold + ?Sized, -{ - crate::PatIdent { - attrs: f.fold_attributes(node.attrs), - by_ref: node.by_ref, - mutability: node.mutability, - ident: f.fold_ident(node.ident), - subpat: (node.subpat).map(|it| ((it).0, Box::new(f.fold_pat(*(it).1)))), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_or<F>(f: &mut F, node: crate::PatOr) -> crate::PatOr -where - F: Fold + ?Sized, -{ - crate::PatOr { - attrs: f.fold_attributes(node.attrs), - leading_vert: node.leading_vert, - cases: crate::punctuated::fold(node.cases, f, F::fold_pat), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_paren<F>(f: &mut F, node: crate::PatParen) -> crate::PatParen -where - F: Fold + ?Sized, -{ - crate::PatParen { - attrs: f.fold_attributes(node.attrs), - paren_token: node.paren_token, - pat: Box::new(f.fold_pat(*node.pat)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_reference<F>(f: &mut F, node: crate::PatReference) -> crate::PatReference -where - F: Fold + ?Sized, -{ - crate::PatReference { - attrs: f.fold_attributes(node.attrs), - and_token: node.and_token, - mutability: node.mutability, - pat: Box::new(f.fold_pat(*node.pat)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_rest<F>(f: &mut F, node: crate::PatRest) -> crate::PatRest -where - F: Fold + ?Sized, -{ - crate::PatRest { - attrs: f.fold_attributes(node.attrs), - dot2_token: node.dot2_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_slice<F>(f: &mut F, node: crate::PatSlice) -> crate::PatSlice -where - F: Fold + ?Sized, -{ - crate::PatSlice { - attrs: f.fold_attributes(node.attrs), - bracket_token: node.bracket_token, - elems: crate::punctuated::fold(node.elems, f, F::fold_pat), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_struct<F>(f: &mut F, node: crate::PatStruct) -> crate::PatStruct -where - F: Fold + ?Sized, -{ - crate::PatStruct { - attrs: f.fold_attributes(node.attrs), - qself: (node.qself).map(|it| f.fold_qself(it)), - path: f.fold_path(node.path), - brace_token: node.brace_token, - fields: crate::punctuated::fold(node.fields, f, F::fold_field_pat), - rest: (node.rest).map(|it| f.fold_pat_rest(it)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_tuple<F>(f: &mut F, node: crate::PatTuple) -> crate::PatTuple -where - F: Fold + ?Sized, -{ - crate::PatTuple { - attrs: f.fold_attributes(node.attrs), - paren_token: node.paren_token, - elems: crate::punctuated::fold(node.elems, f, F::fold_pat), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_tuple_struct<F>( - f: &mut F, - node: crate::PatTupleStruct, -) -> crate::PatTupleStruct -where - F: Fold + ?Sized, -{ - crate::PatTupleStruct { - attrs: f.fold_attributes(node.attrs), - qself: (node.qself).map(|it| f.fold_qself(it)), - path: f.fold_path(node.path), - paren_token: node.paren_token, - elems: crate::punctuated::fold(node.elems, f, F::fold_pat), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_type<F>(f: &mut F, node: crate::PatType) -> crate::PatType -where - F: Fold + ?Sized, -{ - crate::PatType { - attrs: f.fold_attributes(node.attrs), - pat: Box::new(f.fold_pat(*node.pat)), - colon_token: node.colon_token, - ty: Box::new(f.fold_type(*node.ty)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pat_wild<F>(f: &mut F, node: crate::PatWild) -> crate::PatWild -where - F: Fold + ?Sized, -{ - crate::PatWild { - attrs: f.fold_attributes(node.attrs), - underscore_token: node.underscore_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_path<F>(f: &mut F, node: crate::Path) -> crate::Path -where - F: Fold + ?Sized, -{ - crate::Path { - leading_colon: node.leading_colon, - segments: crate::punctuated::fold(node.segments, f, F::fold_path_segment), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_path_arguments<F>( - f: &mut F, - node: crate::PathArguments, -) -> crate::PathArguments -where - F: Fold + ?Sized, -{ - match node { - crate::PathArguments::None => crate::PathArguments::None, - crate::PathArguments::AngleBracketed(_binding_0) => { - crate::PathArguments::AngleBracketed( - f.fold_angle_bracketed_generic_arguments(_binding_0), - ) - } - crate::PathArguments::Parenthesized(_binding_0) => { - crate::PathArguments::Parenthesized( - f.fold_parenthesized_generic_arguments(_binding_0), - ) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_path_segment<F>(f: &mut F, node: crate::PathSegment) -> crate::PathSegment -where - F: Fold + ?Sized, -{ - crate::PathSegment { - ident: f.fold_ident(node.ident), - arguments: f.fold_path_arguments(node.arguments), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_pointer_mutability<F>( - f: &mut F, - node: crate::PointerMutability, -) -> crate::PointerMutability -where - F: Fold + ?Sized, -{ - match node { - crate::PointerMutability::Const(_binding_0) => { - crate::PointerMutability::Const(_binding_0) - } - crate::PointerMutability::Mut(_binding_0) => { - crate::PointerMutability::Mut(_binding_0) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_precise_capture<F>( - f: &mut F, - node: crate::PreciseCapture, -) -> crate::PreciseCapture -where - F: Fold + ?Sized, -{ - crate::PreciseCapture { - use_token: node.use_token, - lt_token: node.lt_token, - params: crate::punctuated::fold(node.params, f, F::fold_captured_param), - gt_token: node.gt_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_predicate_lifetime<F>( - f: &mut F, - node: crate::PredicateLifetime, -) -> crate::PredicateLifetime -where - F: Fold + ?Sized, -{ - crate::PredicateLifetime { - lifetime: f.fold_lifetime(node.lifetime), - colon_token: node.colon_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_lifetime), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_predicate_type<F>( - f: &mut F, - node: crate::PredicateType, -) -> crate::PredicateType -where - F: Fold + ?Sized, -{ - crate::PredicateType { - lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), - bounded_ty: f.fold_type(node.bounded_ty), - colon_token: node.colon_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_qself<F>(f: &mut F, node: crate::QSelf) -> crate::QSelf -where - F: Fold + ?Sized, -{ - crate::QSelf { - lt_token: node.lt_token, - ty: Box::new(f.fold_type(*node.ty)), - position: node.position, - as_token: node.as_token, - gt_token: node.gt_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_range_limits<F>(f: &mut F, node: crate::RangeLimits) -> crate::RangeLimits -where - F: Fold + ?Sized, -{ - match node { - crate::RangeLimits::HalfOpen(_binding_0) => { - crate::RangeLimits::HalfOpen(_binding_0) - } - crate::RangeLimits::Closed(_binding_0) => crate::RangeLimits::Closed(_binding_0), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_receiver<F>(f: &mut F, node: crate::Receiver) -> crate::Receiver -where - F: Fold + ?Sized, -{ - crate::Receiver { - attrs: f.fold_attributes(node.attrs), - reference: (node.reference) - .map(|it| ((it).0, ((it).1).map(|it| f.fold_lifetime(it)))), - mutability: node.mutability, - self_token: node.self_token, - colon_token: node.colon_token, - ty: Box::new(f.fold_type(*node.ty)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_return_type<F>(f: &mut F, node: crate::ReturnType) -> crate::ReturnType -where - F: Fold + ?Sized, -{ - match node { - crate::ReturnType::Default => crate::ReturnType::Default, - crate::ReturnType::Type(_binding_0, _binding_1) => { - crate::ReturnType::Type(_binding_0, Box::new(f.fold_type(*_binding_1))) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_signature<F>(f: &mut F, node: crate::Signature) -> crate::Signature -where - F: Fold + ?Sized, -{ - crate::Signature { - constness: node.constness, - asyncness: node.asyncness, - unsafety: node.unsafety, - abi: (node.abi).map(|it| f.fold_abi(it)), - fn_token: node.fn_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - paren_token: node.paren_token, - inputs: crate::punctuated::fold(node.inputs, f, F::fold_fn_arg), - variadic: (node.variadic).map(|it| f.fold_variadic(it)), - output: f.fold_return_type(node.output), - } -} -pub fn fold_span<F>(f: &mut F, node: proc_macro2::Span) -> proc_macro2::Span -where - F: Fold + ?Sized, -{ - node -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_static_mutability<F>( - f: &mut F, - node: crate::StaticMutability, -) -> crate::StaticMutability -where - F: Fold + ?Sized, -{ - match node { - crate::StaticMutability::Mut(_binding_0) => { - crate::StaticMutability::Mut(_binding_0) - } - crate::StaticMutability::None => crate::StaticMutability::None, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_stmt<F>(f: &mut F, node: crate::Stmt) -> crate::Stmt -where - F: Fold + ?Sized, -{ - match node { - crate::Stmt::Local(_binding_0) => crate::Stmt::Local(f.fold_local(_binding_0)), - crate::Stmt::Item(_binding_0) => crate::Stmt::Item(f.fold_item(_binding_0)), - crate::Stmt::Expr(_binding_0, _binding_1) => { - crate::Stmt::Expr(f.fold_expr(_binding_0), _binding_1) - } - crate::Stmt::Macro(_binding_0) => { - crate::Stmt::Macro(f.fold_stmt_macro(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_stmt_macro<F>(f: &mut F, node: crate::StmtMacro) -> crate::StmtMacro -where - F: Fold + ?Sized, -{ - crate::StmtMacro { - attrs: f.fold_attributes(node.attrs), - mac: f.fold_macro(node.mac), - semi_token: node.semi_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_trait_bound<F>(f: &mut F, node: crate::TraitBound) -> crate::TraitBound -where - F: Fold + ?Sized, -{ - crate::TraitBound { - paren_token: node.paren_token, - modifier: f.fold_trait_bound_modifier(node.modifier), - lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), - path: f.fold_path(node.path), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_trait_bound_modifier<F>( - f: &mut F, - node: crate::TraitBoundModifier, -) -> crate::TraitBoundModifier -where - F: Fold + ?Sized, -{ - match node { - crate::TraitBoundModifier::None => crate::TraitBoundModifier::None, - crate::TraitBoundModifier::Maybe(_binding_0) => { - crate::TraitBoundModifier::Maybe(_binding_0) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_trait_item<F>(f: &mut F, node: crate::TraitItem) -> crate::TraitItem -where - F: Fold + ?Sized, -{ - match node { - crate::TraitItem::Const(_binding_0) => { - crate::TraitItem::Const(f.fold_trait_item_const(_binding_0)) - } - crate::TraitItem::Fn(_binding_0) => { - crate::TraitItem::Fn(f.fold_trait_item_fn(_binding_0)) - } - crate::TraitItem::Type(_binding_0) => { - crate::TraitItem::Type(f.fold_trait_item_type(_binding_0)) - } - crate::TraitItem::Macro(_binding_0) => { - crate::TraitItem::Macro(f.fold_trait_item_macro(_binding_0)) - } - crate::TraitItem::Verbatim(_binding_0) => { - crate::TraitItem::Verbatim(f.fold_token_stream(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_trait_item_const<F>( - f: &mut F, - node: crate::TraitItemConst, -) -> crate::TraitItemConst -where - F: Fold + ?Sized, -{ - crate::TraitItemConst { - attrs: f.fold_attributes(node.attrs), - const_token: node.const_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - colon_token: node.colon_token, - ty: f.fold_type(node.ty), - default: (node.default).map(|it| ((it).0, f.fold_expr((it).1))), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_trait_item_fn<F>(f: &mut F, node: crate::TraitItemFn) -> crate::TraitItemFn -where - F: Fold + ?Sized, -{ - crate::TraitItemFn { - attrs: f.fold_attributes(node.attrs), - sig: f.fold_signature(node.sig), - default: (node.default).map(|it| f.fold_block(it)), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_trait_item_macro<F>( - f: &mut F, - node: crate::TraitItemMacro, -) -> crate::TraitItemMacro -where - F: Fold + ?Sized, -{ - crate::TraitItemMacro { - attrs: f.fold_attributes(node.attrs), - mac: f.fold_macro(node.mac), - semi_token: node.semi_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_trait_item_type<F>( - f: &mut F, - node: crate::TraitItemType, -) -> crate::TraitItemType -where - F: Fold + ?Sized, -{ - crate::TraitItemType { - attrs: f.fold_attributes(node.attrs), - type_token: node.type_token, - ident: f.fold_ident(node.ident), - generics: f.fold_generics(node.generics), - colon_token: node.colon_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - default: (node.default).map(|it| ((it).0, f.fold_type((it).1))), - semi_token: node.semi_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type<F>(f: &mut F, node: crate::Type) -> crate::Type -where - F: Fold + ?Sized, -{ - match node { - crate::Type::Array(_binding_0) => { - crate::Type::Array(f.fold_type_array(_binding_0)) - } - crate::Type::BareFn(_binding_0) => { - crate::Type::BareFn(f.fold_type_bare_fn(_binding_0)) - } - crate::Type::Group(_binding_0) => { - crate::Type::Group(f.fold_type_group(_binding_0)) - } - crate::Type::ImplTrait(_binding_0) => { - crate::Type::ImplTrait(f.fold_type_impl_trait(_binding_0)) - } - crate::Type::Infer(_binding_0) => { - crate::Type::Infer(f.fold_type_infer(_binding_0)) - } - crate::Type::Macro(_binding_0) => { - crate::Type::Macro(f.fold_type_macro(_binding_0)) - } - crate::Type::Never(_binding_0) => { - crate::Type::Never(f.fold_type_never(_binding_0)) - } - crate::Type::Paren(_binding_0) => { - crate::Type::Paren(f.fold_type_paren(_binding_0)) - } - crate::Type::Path(_binding_0) => crate::Type::Path(f.fold_type_path(_binding_0)), - crate::Type::Ptr(_binding_0) => crate::Type::Ptr(f.fold_type_ptr(_binding_0)), - crate::Type::Reference(_binding_0) => { - crate::Type::Reference(f.fold_type_reference(_binding_0)) - } - crate::Type::Slice(_binding_0) => { - crate::Type::Slice(f.fold_type_slice(_binding_0)) - } - crate::Type::TraitObject(_binding_0) => { - crate::Type::TraitObject(f.fold_type_trait_object(_binding_0)) - } - crate::Type::Tuple(_binding_0) => { - crate::Type::Tuple(f.fold_type_tuple(_binding_0)) - } - crate::Type::Verbatim(_binding_0) => { - crate::Type::Verbatim(f.fold_token_stream(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_array<F>(f: &mut F, node: crate::TypeArray) -> crate::TypeArray -where - F: Fold + ?Sized, -{ - crate::TypeArray { - bracket_token: node.bracket_token, - elem: Box::new(f.fold_type(*node.elem)), - semi_token: node.semi_token, - len: f.fold_expr(node.len), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_bare_fn<F>(f: &mut F, node: crate::TypeBareFn) -> crate::TypeBareFn -where - F: Fold + ?Sized, -{ - crate::TypeBareFn { - lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), - unsafety: node.unsafety, - abi: (node.abi).map(|it| f.fold_abi(it)), - fn_token: node.fn_token, - paren_token: node.paren_token, - inputs: crate::punctuated::fold(node.inputs, f, F::fold_bare_fn_arg), - variadic: (node.variadic).map(|it| f.fold_bare_variadic(it)), - output: f.fold_return_type(node.output), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_group<F>(f: &mut F, node: crate::TypeGroup) -> crate::TypeGroup -where - F: Fold + ?Sized, -{ - crate::TypeGroup { - group_token: node.group_token, - elem: Box::new(f.fold_type(*node.elem)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_impl_trait<F>( - f: &mut F, - node: crate::TypeImplTrait, -) -> crate::TypeImplTrait -where - F: Fold + ?Sized, -{ - crate::TypeImplTrait { - impl_token: node.impl_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_infer<F>(f: &mut F, node: crate::TypeInfer) -> crate::TypeInfer -where - F: Fold + ?Sized, -{ - crate::TypeInfer { - underscore_token: node.underscore_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_macro<F>(f: &mut F, node: crate::TypeMacro) -> crate::TypeMacro -where - F: Fold + ?Sized, -{ - crate::TypeMacro { - mac: f.fold_macro(node.mac), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_never<F>(f: &mut F, node: crate::TypeNever) -> crate::TypeNever -where - F: Fold + ?Sized, -{ - crate::TypeNever { - bang_token: node.bang_token, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_param<F>(f: &mut F, node: crate::TypeParam) -> crate::TypeParam -where - F: Fold + ?Sized, -{ - crate::TypeParam { - attrs: f.fold_attributes(node.attrs), - ident: f.fold_ident(node.ident), - colon_token: node.colon_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - eq_token: node.eq_token, - default: (node.default).map(|it| f.fold_type(it)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_param_bound<F>( - f: &mut F, - node: crate::TypeParamBound, -) -> crate::TypeParamBound -where - F: Fold + ?Sized, -{ - match node { - crate::TypeParamBound::Trait(_binding_0) => { - crate::TypeParamBound::Trait(f.fold_trait_bound(_binding_0)) - } - crate::TypeParamBound::Lifetime(_binding_0) => { - crate::TypeParamBound::Lifetime(f.fold_lifetime(_binding_0)) - } - crate::TypeParamBound::PreciseCapture(_binding_0) => { - crate::TypeParamBound::PreciseCapture( - full!(f.fold_precise_capture(_binding_0)), - ) - } - crate::TypeParamBound::Verbatim(_binding_0) => { - crate::TypeParamBound::Verbatim(f.fold_token_stream(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_paren<F>(f: &mut F, node: crate::TypeParen) -> crate::TypeParen -where - F: Fold + ?Sized, -{ - crate::TypeParen { - paren_token: node.paren_token, - elem: Box::new(f.fold_type(*node.elem)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_path<F>(f: &mut F, node: crate::TypePath) -> crate::TypePath -where - F: Fold + ?Sized, -{ - crate::TypePath { - qself: (node.qself).map(|it| f.fold_qself(it)), - path: f.fold_path(node.path), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_ptr<F>(f: &mut F, node: crate::TypePtr) -> crate::TypePtr -where - F: Fold + ?Sized, -{ - crate::TypePtr { - star_token: node.star_token, - const_token: node.const_token, - mutability: node.mutability, - elem: Box::new(f.fold_type(*node.elem)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_reference<F>( - f: &mut F, - node: crate::TypeReference, -) -> crate::TypeReference -where - F: Fold + ?Sized, -{ - crate::TypeReference { - and_token: node.and_token, - lifetime: (node.lifetime).map(|it| f.fold_lifetime(it)), - mutability: node.mutability, - elem: Box::new(f.fold_type(*node.elem)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_slice<F>(f: &mut F, node: crate::TypeSlice) -> crate::TypeSlice -where - F: Fold + ?Sized, -{ - crate::TypeSlice { - bracket_token: node.bracket_token, - elem: Box::new(f.fold_type(*node.elem)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_trait_object<F>( - f: &mut F, - node: crate::TypeTraitObject, -) -> crate::TypeTraitObject -where - F: Fold + ?Sized, -{ - crate::TypeTraitObject { - dyn_token: node.dyn_token, - bounds: crate::punctuated::fold(node.bounds, f, F::fold_type_param_bound), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_type_tuple<F>(f: &mut F, node: crate::TypeTuple) -> crate::TypeTuple -where - F: Fold + ?Sized, -{ - crate::TypeTuple { - paren_token: node.paren_token, - elems: crate::punctuated::fold(node.elems, f, F::fold_type), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_un_op<F>(f: &mut F, node: crate::UnOp) -> crate::UnOp -where - F: Fold + ?Sized, -{ - match node { - crate::UnOp::Deref(_binding_0) => crate::UnOp::Deref(_binding_0), - crate::UnOp::Not(_binding_0) => crate::UnOp::Not(_binding_0), - crate::UnOp::Neg(_binding_0) => crate::UnOp::Neg(_binding_0), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_use_glob<F>(f: &mut F, node: crate::UseGlob) -> crate::UseGlob -where - F: Fold + ?Sized, -{ - crate::UseGlob { - star_token: node.star_token, - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_use_group<F>(f: &mut F, node: crate::UseGroup) -> crate::UseGroup -where - F: Fold + ?Sized, -{ - crate::UseGroup { - brace_token: node.brace_token, - items: crate::punctuated::fold(node.items, f, F::fold_use_tree), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_use_name<F>(f: &mut F, node: crate::UseName) -> crate::UseName -where - F: Fold + ?Sized, -{ - crate::UseName { - ident: f.fold_ident(node.ident), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_use_path<F>(f: &mut F, node: crate::UsePath) -> crate::UsePath -where - F: Fold + ?Sized, -{ - crate::UsePath { - ident: f.fold_ident(node.ident), - colon2_token: node.colon2_token, - tree: Box::new(f.fold_use_tree(*node.tree)), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_use_rename<F>(f: &mut F, node: crate::UseRename) -> crate::UseRename -where - F: Fold + ?Sized, -{ - crate::UseRename { - ident: f.fold_ident(node.ident), - as_token: node.as_token, - rename: f.fold_ident(node.rename), - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_use_tree<F>(f: &mut F, node: crate::UseTree) -> crate::UseTree -where - F: Fold + ?Sized, -{ - match node { - crate::UseTree::Path(_binding_0) => { - crate::UseTree::Path(f.fold_use_path(_binding_0)) - } - crate::UseTree::Name(_binding_0) => { - crate::UseTree::Name(f.fold_use_name(_binding_0)) - } - crate::UseTree::Rename(_binding_0) => { - crate::UseTree::Rename(f.fold_use_rename(_binding_0)) - } - crate::UseTree::Glob(_binding_0) => { - crate::UseTree::Glob(f.fold_use_glob(_binding_0)) - } - crate::UseTree::Group(_binding_0) => { - crate::UseTree::Group(f.fold_use_group(_binding_0)) - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn fold_variadic<F>(f: &mut F, node: crate::Variadic) -> crate::Variadic -where - F: Fold + ?Sized, -{ - crate::Variadic { - attrs: f.fold_attributes(node.attrs), - pat: (node.pat).map(|it| (Box::new(f.fold_pat(*(it).0)), (it).1)), - dots: node.dots, - comma: node.comma, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_variant<F>(f: &mut F, node: crate::Variant) -> crate::Variant -where - F: Fold + ?Sized, -{ - crate::Variant { - attrs: f.fold_attributes(node.attrs), - ident: f.fold_ident(node.ident), - fields: f.fold_fields(node.fields), - discriminant: (node.discriminant).map(|it| ((it).0, f.fold_expr((it).1))), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_vis_restricted<F>( - f: &mut F, - node: crate::VisRestricted, -) -> crate::VisRestricted -where - F: Fold + ?Sized, -{ - crate::VisRestricted { - pub_token: node.pub_token, - paren_token: node.paren_token, - in_token: node.in_token, - path: Box::new(f.fold_path(*node.path)), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_visibility<F>(f: &mut F, node: crate::Visibility) -> crate::Visibility -where - F: Fold + ?Sized, -{ - match node { - crate::Visibility::Public(_binding_0) => crate::Visibility::Public(_binding_0), - crate::Visibility::Restricted(_binding_0) => { - crate::Visibility::Restricted(f.fold_vis_restricted(_binding_0)) - } - crate::Visibility::Inherited => crate::Visibility::Inherited, - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_where_clause<F>(f: &mut F, node: crate::WhereClause) -> crate::WhereClause -where - F: Fold + ?Sized, -{ - crate::WhereClause { - where_token: node.where_token, - predicates: crate::punctuated::fold(node.predicates, f, F::fold_where_predicate), - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn fold_where_predicate<F>( - f: &mut F, - node: crate::WherePredicate, -) -> crate::WherePredicate -where - F: Fold + ?Sized, -{ - match node { - crate::WherePredicate::Lifetime(_binding_0) => { - crate::WherePredicate::Lifetime(f.fold_predicate_lifetime(_binding_0)) - } - crate::WherePredicate::Type(_binding_0) => { - crate::WherePredicate::Type(f.fold_predicate_type(_binding_0)) - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -fn fold_vec<T, V, F>(vec: Vec<T>, fold: &mut V, mut f: F) -> Vec<T> -where - V: ?Sized, - F: FnMut(&mut V, T) -> T, -{ - vec.into_iter().map(|it| f(fold, it)).collect() -} diff --git a/deps/crates/vendor/syn-v2/src/gen/hash.rs b/deps/crates/vendor/syn-v2/src/gen/hash.rs deleted file mode 100644 index 508af526c1ec..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/hash.rs +++ /dev/null @@ -1,2878 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#[cfg(any(feature = "derive", feature = "full"))] -use crate::tt::TokenStreamHelper; -#[cfg(feature = "extra-traits")] -use alloc::string::ToString; -use core::hash::{Hash, Hasher}; -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Abi { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.name.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::AngleBracketedGenericArguments { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.colon2_token.hash(state); - self.args.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Arm { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.pat.hash(state); - self.guard.hash(state); - self.body.hash(state); - self.comma.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::AssocConst { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - self.generics.hash(state); - self.value.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::AssocType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - self.generics.hash(state); - self.ty.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::AttrStyle { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::AttrStyle::Outer => { - state.write_u8(0u8); - } - crate::AttrStyle::Inner(_) => { - state.write_u8(1u8); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Attribute { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.style.hash(state); - self.meta.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::BareFnArg { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.name.hash(state); - self.ty.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::BareVariadic { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.name.hash(state); - self.comma.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::BinOp { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::BinOp::Add(_) => { - state.write_u8(0u8); - } - crate::BinOp::Sub(_) => { - state.write_u8(1u8); - } - crate::BinOp::Mul(_) => { - state.write_u8(2u8); - } - crate::BinOp::Div(_) => { - state.write_u8(3u8); - } - crate::BinOp::Rem(_) => { - state.write_u8(4u8); - } - crate::BinOp::And(_) => { - state.write_u8(5u8); - } - crate::BinOp::Or(_) => { - state.write_u8(6u8); - } - crate::BinOp::BitXor(_) => { - state.write_u8(7u8); - } - crate::BinOp::BitAnd(_) => { - state.write_u8(8u8); - } - crate::BinOp::BitOr(_) => { - state.write_u8(9u8); - } - crate::BinOp::Shl(_) => { - state.write_u8(10u8); - } - crate::BinOp::Shr(_) => { - state.write_u8(11u8); - } - crate::BinOp::Eq(_) => { - state.write_u8(12u8); - } - crate::BinOp::Lt(_) => { - state.write_u8(13u8); - } - crate::BinOp::Le(_) => { - state.write_u8(14u8); - } - crate::BinOp::Ne(_) => { - state.write_u8(15u8); - } - crate::BinOp::Ge(_) => { - state.write_u8(16u8); - } - crate::BinOp::Gt(_) => { - state.write_u8(17u8); - } - crate::BinOp::AddAssign(_) => { - state.write_u8(18u8); - } - crate::BinOp::SubAssign(_) => { - state.write_u8(19u8); - } - crate::BinOp::MulAssign(_) => { - state.write_u8(20u8); - } - crate::BinOp::DivAssign(_) => { - state.write_u8(21u8); - } - crate::BinOp::RemAssign(_) => { - state.write_u8(22u8); - } - crate::BinOp::BitXorAssign(_) => { - state.write_u8(23u8); - } - crate::BinOp::BitAndAssign(_) => { - state.write_u8(24u8); - } - crate::BinOp::BitOrAssign(_) => { - state.write_u8(25u8); - } - crate::BinOp::ShlAssign(_) => { - state.write_u8(26u8); - } - crate::BinOp::ShrAssign(_) => { - state.write_u8(27u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Block { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.stmts.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::BoundLifetimes { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.lifetimes.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::CapturedParam { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::CapturedParam::Lifetime(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::CapturedParam::Ident(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ConstParam { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.ident.hash(state); - self.ty.hash(state); - self.eq_token.hash(state); - self.default.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Constraint { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - self.generics.hash(state); - self.bounds.hash(state); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Data { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Data::Struct(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Data::Enum(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Data::Union(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::DataEnum { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.variants.hash(state); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::DataStruct { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.fields.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::DataUnion { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.fields.hash(state); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::DeriveInput { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.data.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Expr { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - #[cfg(feature = "full")] - crate::Expr::Array(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Assign(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Async(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Await(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::Expr::Binary(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Block(v0) => { - state.write_u8(5u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Break(v0) => { - state.write_u8(6u8); - v0.hash(state); - } - crate::Expr::Call(v0) => { - state.write_u8(7u8); - v0.hash(state); - } - crate::Expr::Cast(v0) => { - state.write_u8(8u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Closure(v0) => { - state.write_u8(9u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Const(v0) => { - state.write_u8(10u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Continue(v0) => { - state.write_u8(11u8); - v0.hash(state); - } - crate::Expr::Field(v0) => { - state.write_u8(12u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::ForLoop(v0) => { - state.write_u8(13u8); - v0.hash(state); - } - crate::Expr::Group(v0) => { - state.write_u8(14u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::If(v0) => { - state.write_u8(15u8); - v0.hash(state); - } - crate::Expr::Index(v0) => { - state.write_u8(16u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Infer(v0) => { - state.write_u8(17u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Let(v0) => { - state.write_u8(18u8); - v0.hash(state); - } - crate::Expr::Lit(v0) => { - state.write_u8(19u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Loop(v0) => { - state.write_u8(20u8); - v0.hash(state); - } - crate::Expr::Macro(v0) => { - state.write_u8(21u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Match(v0) => { - state.write_u8(22u8); - v0.hash(state); - } - crate::Expr::MethodCall(v0) => { - state.write_u8(23u8); - v0.hash(state); - } - crate::Expr::Paren(v0) => { - state.write_u8(24u8); - v0.hash(state); - } - crate::Expr::Path(v0) => { - state.write_u8(25u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Range(v0) => { - state.write_u8(26u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::RawAddr(v0) => { - state.write_u8(27u8); - v0.hash(state); - } - crate::Expr::Reference(v0) => { - state.write_u8(28u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Repeat(v0) => { - state.write_u8(29u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Return(v0) => { - state.write_u8(30u8); - v0.hash(state); - } - crate::Expr::Struct(v0) => { - state.write_u8(31u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Try(v0) => { - state.write_u8(32u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::TryBlock(v0) => { - state.write_u8(33u8); - v0.hash(state); - } - crate::Expr::Tuple(v0) => { - state.write_u8(34u8); - v0.hash(state); - } - crate::Expr::Unary(v0) => { - state.write_u8(35u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Unsafe(v0) => { - state.write_u8(36u8); - v0.hash(state); - } - crate::Expr::Verbatim(v0) => { - state.write_u8(37u8); - TokenStreamHelper(v0).hash(state); - } - #[cfg(feature = "full")] - crate::Expr::While(v0) => { - state.write_u8(38u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::Expr::Yield(v0) => { - state.write_u8(39u8); - v0.hash(state); - } - #[cfg(not(feature = "full"))] - _ => unreachable!(), - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprArray { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.elems.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprAssign { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.left.hash(state); - self.right.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprAsync { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.capture.hash(state); - self.block.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprAwait { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.base.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprBinary { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.left.hash(state); - self.op.hash(state); - self.right.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprBlock { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.label.hash(state); - self.block.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprBreak { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.label.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprCall { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.func.hash(state); - self.args.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprCast { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - self.ty.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprClosure { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.lifetimes.hash(state); - self.constness.hash(state); - self.movability.hash(state); - self.asyncness.hash(state); - self.capture.hash(state); - self.inputs.hash(state); - self.output.hash(state); - self.body.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprConst { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.block.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprContinue { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.label.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprField { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.base.hash(state); - self.member.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprForLoop { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.label.hash(state); - self.pat.hash(state); - self.expr.hash(state); - self.body.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprGroup { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprIf { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.cond.hash(state); - self.then_branch.hash(state); - self.else_branch.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprIndex { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - self.index.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprInfer { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprLet { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.pat.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprLit { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.lit.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprLoop { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.label.hash(state); - self.body.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mac.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprMatch { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - self.arms.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprMethodCall { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.receiver.hash(state); - self.method.hash(state); - self.turbofish.hash(state); - self.args.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprParen { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprPath { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.qself.hash(state); - self.path.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprRange { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.start.hash(state); - self.limits.hash(state); - self.end.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprRawAddr { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mutability.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprReference { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mutability.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprRepeat { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - self.len.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprReturn { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprStruct { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.qself.hash(state); - self.path.hash(state); - self.fields.hash(state); - self.dot2_token.hash(state); - self.rest.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprTry { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprTryBlock { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.block.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprTuple { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.elems.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprUnary { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.op.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprUnsafe { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.block.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprWhile { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.label.hash(state); - self.cond.hash(state); - self.body.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ExprYield { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Field { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.mutability.hash(state); - self.ident.hash(state); - self.colon_token.hash(state); - self.ty.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::FieldMutability { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::FieldMutability::None => { - state.write_u8(0u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::FieldPat { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.member.hash(state); - self.colon_token.hash(state); - self.pat.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::FieldValue { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.member.hash(state); - self.colon_token.hash(state); - self.expr.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Fields { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Fields::Named(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Fields::Unnamed(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Fields::Unit => { - state.write_u8(2u8); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::FieldsNamed { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.named.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::FieldsUnnamed { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.unnamed.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::File { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.shebang.hash(state); - self.attrs.hash(state); - self.items.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::FnArg { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::FnArg::Receiver(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::FnArg::Typed(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ForeignItem { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::ForeignItem::Fn(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::ForeignItem::Static(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::ForeignItem::Type(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::ForeignItem::Macro(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::ForeignItem::Verbatim(v0) => { - state.write_u8(4u8); - TokenStreamHelper(v0).hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ForeignItemFn { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.sig.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ForeignItemMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mac.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ForeignItemStatic { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.mutability.hash(state); - self.ident.hash(state); - self.ty.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ForeignItemType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::GenericArgument { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::GenericArgument::Lifetime(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::GenericArgument::Type(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::GenericArgument::Const(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::GenericArgument::AssocType(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::GenericArgument::AssocConst(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - crate::GenericArgument::Constraint(v0) => { - state.write_u8(5u8); - v0.hash(state); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::GenericParam { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::GenericParam::Lifetime(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::GenericParam::Type(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::GenericParam::Const(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Generics { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.lt_token.hash(state); - self.params.hash(state); - self.gt_token.hash(state); - self.where_clause.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ImplItem { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::ImplItem::Const(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::ImplItem::Fn(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::ImplItem::Type(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::ImplItem::Macro(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::ImplItem::Verbatim(v0) => { - state.write_u8(4u8); - TokenStreamHelper(v0).hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ImplItemConst { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.defaultness.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.ty.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ImplItemFn { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.defaultness.hash(state); - self.sig.hash(state); - self.block.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ImplItemMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mac.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ImplItemType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.defaultness.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.ty.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ImplRestriction { - fn hash<H>(&self, _state: &mut H) - where - H: Hasher, - { - match *self {} - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Item { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Item::Const(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Item::Enum(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Item::ExternCrate(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::Item::Fn(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::Item::ForeignMod(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - crate::Item::Impl(v0) => { - state.write_u8(5u8); - v0.hash(state); - } - crate::Item::Macro(v0) => { - state.write_u8(6u8); - v0.hash(state); - } - crate::Item::Mod(v0) => { - state.write_u8(7u8); - v0.hash(state); - } - crate::Item::Static(v0) => { - state.write_u8(8u8); - v0.hash(state); - } - crate::Item::Struct(v0) => { - state.write_u8(9u8); - v0.hash(state); - } - crate::Item::Trait(v0) => { - state.write_u8(10u8); - v0.hash(state); - } - crate::Item::TraitAlias(v0) => { - state.write_u8(11u8); - v0.hash(state); - } - crate::Item::Type(v0) => { - state.write_u8(12u8); - v0.hash(state); - } - crate::Item::Union(v0) => { - state.write_u8(13u8); - v0.hash(state); - } - crate::Item::Use(v0) => { - state.write_u8(14u8); - v0.hash(state); - } - crate::Item::Verbatim(v0) => { - state.write_u8(15u8); - TokenStreamHelper(v0).hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemConst { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.ty.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemEnum { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.variants.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemExternCrate { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.rename.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemFn { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.sig.hash(state); - self.block.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemForeignMod { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.unsafety.hash(state); - self.abi.hash(state); - self.items.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemImpl { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.defaultness.hash(state); - self.unsafety.hash(state); - self.generics.hash(state); - self.trait_.hash(state); - self.self_ty.hash(state); - self.items.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.ident.hash(state); - self.mac.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemMod { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.unsafety.hash(state); - self.ident.hash(state); - self.content.hash(state); - self.semi.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemStatic { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.mutability.hash(state); - self.ident.hash(state); - self.ty.hash(state); - self.expr.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemStruct { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.fields.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemTrait { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.unsafety.hash(state); - self.auto_token.hash(state); - self.restriction.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.colon_token.hash(state); - self.supertraits.hash(state); - self.items.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemTraitAlias { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.bounds.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.ty.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemUnion { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.fields.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ItemUse { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.leading_colon.hash(state); - self.tree.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Label { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.name.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::LifetimeParam { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.lifetime.hash(state); - self.colon_token.hash(state); - self.bounds.hash(state); - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Lit { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Lit::Str(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Lit::ByteStr(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Lit::CStr(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::Lit::Byte(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::Lit::Char(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - crate::Lit::Int(v0) => { - state.write_u8(5u8); - v0.hash(state); - } - crate::Lit::Float(v0) => { - state.write_u8(6u8); - v0.hash(state); - } - crate::Lit::Bool(v0) => { - state.write_u8(7u8); - v0.hash(state); - } - crate::Lit::Verbatim(v0) => { - state.write_u8(8u8); - v0.to_string().hash(state); - } - } - } -} -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::LitBool { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.value.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Local { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.pat.hash(state); - self.init.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::LocalInit { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.expr.hash(state); - self.diverge.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Macro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.path.hash(state); - self.delimiter.hash(state); - TokenStreamHelper(&self.tokens).hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::MacroDelimiter { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::MacroDelimiter::Paren(_) => { - state.write_u8(0u8); - } - crate::MacroDelimiter::Brace(_) => { - state.write_u8(1u8); - } - crate::MacroDelimiter::Bracket(_) => { - state.write_u8(2u8); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Meta { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Meta::Path(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Meta::List(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Meta::NameValue(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::MetaList { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.path.hash(state); - self.delimiter.hash(state); - TokenStreamHelper(&self.tokens).hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::MetaNameValue { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.path.hash(state); - self.value.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ParenthesizedGenericArguments { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.inputs.hash(state); - self.output.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Pat { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Pat::Const(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Pat::Ident(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Pat::Lit(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::Pat::Macro(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::Pat::Or(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - crate::Pat::Paren(v0) => { - state.write_u8(5u8); - v0.hash(state); - } - crate::Pat::Path(v0) => { - state.write_u8(6u8); - v0.hash(state); - } - crate::Pat::Range(v0) => { - state.write_u8(7u8); - v0.hash(state); - } - crate::Pat::Reference(v0) => { - state.write_u8(8u8); - v0.hash(state); - } - crate::Pat::Rest(v0) => { - state.write_u8(9u8); - v0.hash(state); - } - crate::Pat::Slice(v0) => { - state.write_u8(10u8); - v0.hash(state); - } - crate::Pat::Struct(v0) => { - state.write_u8(11u8); - v0.hash(state); - } - crate::Pat::Tuple(v0) => { - state.write_u8(12u8); - v0.hash(state); - } - crate::Pat::TupleStruct(v0) => { - state.write_u8(13u8); - v0.hash(state); - } - crate::Pat::Type(v0) => { - state.write_u8(14u8); - v0.hash(state); - } - crate::Pat::Verbatim(v0) => { - state.write_u8(15u8); - TokenStreamHelper(v0).hash(state); - } - crate::Pat::Wild(v0) => { - state.write_u8(16u8); - v0.hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatIdent { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.by_ref.hash(state); - self.mutability.hash(state); - self.ident.hash(state); - self.subpat.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatOr { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.leading_vert.hash(state); - self.cases.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatParen { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.pat.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatReference { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mutability.hash(state); - self.pat.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatRest { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatSlice { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.elems.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatStruct { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.qself.hash(state); - self.path.hash(state); - self.fields.hash(state); - self.rest.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatTuple { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.elems.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatTupleStruct { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.qself.hash(state); - self.path.hash(state); - self.elems.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.pat.hash(state); - self.ty.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PatWild { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Path { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.leading_colon.hash(state); - self.segments.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PathArguments { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::PathArguments::None => { - state.write_u8(0u8); - } - crate::PathArguments::AngleBracketed(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::PathArguments::Parenthesized(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PathSegment { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - self.arguments.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PointerMutability { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::PointerMutability::Const(_) => { - state.write_u8(0u8); - } - crate::PointerMutability::Mut(_) => { - state.write_u8(1u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PreciseCapture { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.params.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PredicateLifetime { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.lifetime.hash(state); - self.bounds.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::PredicateType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.lifetimes.hash(state); - self.bounded_ty.hash(state); - self.bounds.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::QSelf { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ty.hash(state); - self.position.hash(state); - self.as_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::RangeLimits { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::RangeLimits::HalfOpen(_) => { - state.write_u8(0u8); - } - crate::RangeLimits::Closed(_) => { - state.write_u8(1u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Receiver { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.reference.hash(state); - self.mutability.hash(state); - self.colon_token.hash(state); - self.ty.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::ReturnType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::ReturnType::Default => { - state.write_u8(0u8); - } - crate::ReturnType::Type(_, v1) => { - state.write_u8(1u8); - v1.hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Signature { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.constness.hash(state); - self.asyncness.hash(state); - self.unsafety.hash(state); - self.abi.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.inputs.hash(state); - self.variadic.hash(state); - self.output.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::StaticMutability { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::StaticMutability::Mut(_) => { - state.write_u8(0u8); - } - crate::StaticMutability::None => { - state.write_u8(1u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Stmt { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Stmt::Local(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Stmt::Item(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Stmt::Expr(v0, v1) => { - state.write_u8(2u8); - v0.hash(state); - v1.hash(state); - } - crate::Stmt::Macro(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::StmtMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mac.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitBound { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.paren_token.hash(state); - self.modifier.hash(state); - self.lifetimes.hash(state); - self.path.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitBoundModifier { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::TraitBoundModifier::None => { - state.write_u8(0u8); - } - crate::TraitBoundModifier::Maybe(_) => { - state.write_u8(1u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitItem { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::TraitItem::Const(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::TraitItem::Fn(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::TraitItem::Type(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::TraitItem::Macro(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::TraitItem::Verbatim(v0) => { - state.write_u8(4u8); - TokenStreamHelper(v0).hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitItemConst { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.ty.hash(state); - self.default.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitItemFn { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.sig.hash(state); - self.default.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitItemMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.mac.hash(state); - self.semi_token.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TraitItemType { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.ident.hash(state); - self.generics.hash(state); - self.colon_token.hash(state); - self.bounds.hash(state); - self.default.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Type { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Type::Array(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::Type::BareFn(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Type::Group(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::Type::ImplTrait(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::Type::Infer(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - crate::Type::Macro(v0) => { - state.write_u8(5u8); - v0.hash(state); - } - crate::Type::Never(v0) => { - state.write_u8(6u8); - v0.hash(state); - } - crate::Type::Paren(v0) => { - state.write_u8(7u8); - v0.hash(state); - } - crate::Type::Path(v0) => { - state.write_u8(8u8); - v0.hash(state); - } - crate::Type::Ptr(v0) => { - state.write_u8(9u8); - v0.hash(state); - } - crate::Type::Reference(v0) => { - state.write_u8(10u8); - v0.hash(state); - } - crate::Type::Slice(v0) => { - state.write_u8(11u8); - v0.hash(state); - } - crate::Type::TraitObject(v0) => { - state.write_u8(12u8); - v0.hash(state); - } - crate::Type::Tuple(v0) => { - state.write_u8(13u8); - v0.hash(state); - } - crate::Type::Verbatim(v0) => { - state.write_u8(14u8); - TokenStreamHelper(v0).hash(state); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeArray { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.elem.hash(state); - self.len.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeBareFn { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.lifetimes.hash(state); - self.unsafety.hash(state); - self.abi.hash(state); - self.inputs.hash(state); - self.variadic.hash(state); - self.output.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeGroup { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.elem.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeImplTrait { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.bounds.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeInfer { - fn hash<H>(&self, _state: &mut H) - where - H: Hasher, - {} -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeMacro { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.mac.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeNever { - fn hash<H>(&self, _state: &mut H) - where - H: Hasher, - {} -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeParam { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.ident.hash(state); - self.colon_token.hash(state); - self.bounds.hash(state); - self.eq_token.hash(state); - self.default.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeParamBound { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::TypeParamBound::Trait(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::TypeParamBound::Lifetime(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - #[cfg(feature = "full")] - crate::TypeParamBound::PreciseCapture(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::TypeParamBound::Verbatim(v0) => { - state.write_u8(3u8); - TokenStreamHelper(v0).hash(state); - } - #[cfg(not(feature = "full"))] - _ => unreachable!(), - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeParen { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.elem.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypePath { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.qself.hash(state); - self.path.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypePtr { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.const_token.hash(state); - self.mutability.hash(state); - self.elem.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeReference { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.lifetime.hash(state); - self.mutability.hash(state); - self.elem.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeSlice { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.elem.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeTraitObject { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.dyn_token.hash(state); - self.bounds.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::TypeTuple { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.elems.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UnOp { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::UnOp::Deref(_) => { - state.write_u8(0u8); - } - crate::UnOp::Not(_) => { - state.write_u8(1u8); - } - crate::UnOp::Neg(_) => { - state.write_u8(2u8); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UseGlob { - fn hash<H>(&self, _state: &mut H) - where - H: Hasher, - {} -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UseGroup { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.items.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UseName { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UsePath { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - self.tree.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UseRename { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.ident.hash(state); - self.rename.hash(state); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::UseTree { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::UseTree::Path(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::UseTree::Name(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::UseTree::Rename(v0) => { - state.write_u8(2u8); - v0.hash(state); - } - crate::UseTree::Glob(v0) => { - state.write_u8(3u8); - v0.hash(state); - } - crate::UseTree::Group(v0) => { - state.write_u8(4u8); - v0.hash(state); - } - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Variadic { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.pat.hash(state); - self.comma.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Variant { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.ident.hash(state); - self.fields.hash(state); - self.discriminant.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::VisRestricted { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.in_token.hash(state); - self.path.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::Visibility { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::Visibility::Public(_) => { - state.write_u8(0u8); - } - crate::Visibility::Restricted(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - crate::Visibility::Inherited => { - state.write_u8(2u8); - } - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::WhereClause { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.predicates.hash(state); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for crate::WherePredicate { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - match self { - crate::WherePredicate::Lifetime(v0) => { - state.write_u8(0u8); - v0.hash(state); - } - crate::WherePredicate::Type(v0) => { - state.write_u8(1u8); - v0.hash(state); - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/gen/token.css b/deps/crates/vendor/syn-v2/src/gen/token.css deleted file mode 100644 index ed82ae1502b4..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/token.css +++ /dev/null @@ -1,737 +0,0 @@ -a.struct[title="struct syn::token::Abstract"], -a.struct[title="struct syn::token::And"], -a.struct[title="struct syn::token::AndAnd"], -a.struct[title="struct syn::token::AndEq"], -a.struct[title="struct syn::token::As"], -a.struct[title="struct syn::token::Async"], -a.struct[title="struct syn::token::At"], -a.struct[title="struct syn::token::Auto"], -a.struct[title="struct syn::token::Await"], -a.struct[title="struct syn::token::Become"], -a.struct[title="struct syn::token::Box"], -a.struct[title="struct syn::token::Break"], -a.struct[title="struct syn::token::Caret"], -a.struct[title="struct syn::token::CaretEq"], -a.struct[title="struct syn::token::Colon"], -a.struct[title="struct syn::token::Comma"], -a.struct[title="struct syn::token::Const"], -a.struct[title="struct syn::token::Continue"], -a.struct[title="struct syn::token::Crate"], -a.struct[title="struct syn::token::Default"], -a.struct[title="struct syn::token::Do"], -a.struct[title="struct syn::token::Dollar"], -a.struct[title="struct syn::token::Dot"], -a.struct[title="struct syn::token::DotDot"], -a.struct[title="struct syn::token::DotDotDot"], -a.struct[title="struct syn::token::DotDotEq"], -a.struct[title="struct syn::token::Dyn"], -a.struct[title="struct syn::token::Else"], -a.struct[title="struct syn::token::Enum"], -a.struct[title="struct syn::token::Eq"], -a.struct[title="struct syn::token::EqEq"], -a.struct[title="struct syn::token::Extern"], -a.struct[title="struct syn::token::FatArrow"], -a.struct[title="struct syn::token::Final"], -a.struct[title="struct syn::token::Fn"], -a.struct[title="struct syn::token::For"], -a.struct[title="struct syn::token::Ge"], -a.struct[title="struct syn::token::Gt"], -a.struct[title="struct syn::token::If"], -a.struct[title="struct syn::token::Impl"], -a.struct[title="struct syn::token::In"], -a.struct[title="struct syn::token::LArrow"], -a.struct[title="struct syn::token::Le"], -a.struct[title="struct syn::token::Let"], -a.struct[title="struct syn::token::Loop"], -a.struct[title="struct syn::token::Lt"], -a.struct[title="struct syn::token::Macro"], -a.struct[title="struct syn::token::Match"], -a.struct[title="struct syn::token::Minus"], -a.struct[title="struct syn::token::MinusEq"], -a.struct[title="struct syn::token::Mod"], -a.struct[title="struct syn::token::Move"], -a.struct[title="struct syn::token::Mut"], -a.struct[title="struct syn::token::Ne"], -a.struct[title="struct syn::token::Not"], -a.struct[title="struct syn::token::Or"], -a.struct[title="struct syn::token::OrEq"], -a.struct[title="struct syn::token::OrOr"], -a.struct[title="struct syn::token::Override"], -a.struct[title="struct syn::token::PathSep"], -a.struct[title="struct syn::token::Percent"], -a.struct[title="struct syn::token::PercentEq"], -a.struct[title="struct syn::token::Plus"], -a.struct[title="struct syn::token::PlusEq"], -a.struct[title="struct syn::token::Pound"], -a.struct[title="struct syn::token::Priv"], -a.struct[title="struct syn::token::Pub"], -a.struct[title="struct syn::token::Question"], -a.struct[title="struct syn::token::RArrow"], -a.struct[title="struct syn::token::Raw"], -a.struct[title="struct syn::token::Ref"], -a.struct[title="struct syn::token::Return"], -a.struct[title="struct syn::token::SelfType"], -a.struct[title="struct syn::token::SelfValue"], -a.struct[title="struct syn::token::Semi"], -a.struct[title="struct syn::token::Shl"], -a.struct[title="struct syn::token::ShlEq"], -a.struct[title="struct syn::token::Shr"], -a.struct[title="struct syn::token::ShrEq"], -a.struct[title="struct syn::token::Slash"], -a.struct[title="struct syn::token::SlashEq"], -a.struct[title="struct syn::token::Star"], -a.struct[title="struct syn::token::StarEq"], -a.struct[title="struct syn::token::Static"], -a.struct[title="struct syn::token::Struct"], -a.struct[title="struct syn::token::Super"], -a.struct[title="struct syn::token::Tilde"], -a.struct[title="struct syn::token::Trait"], -a.struct[title="struct syn::token::Try"], -a.struct[title="struct syn::token::Type"], -a.struct[title="struct syn::token::Typeof"], -a.struct[title="struct syn::token::Underscore"], -a.struct[title="struct syn::token::Union"], -a.struct[title="struct syn::token::Unsafe"], -a.struct[title="struct syn::token::Unsized"], -a.struct[title="struct syn::token::Use"], -a.struct[title="struct syn::token::Virtual"], -a.struct[title="struct syn::token::Where"], -a.struct[title="struct syn::token::While"], -a.struct[title="struct syn::token::Yield"] { - display: inline-block; - color: transparent; - white-space: nowrap; -} - -a.struct[title="struct syn::token::Abstract"]::before, -a.struct[title="struct syn::token::And"]::before, -a.struct[title="struct syn::token::AndAnd"]::before, -a.struct[title="struct syn::token::AndEq"]::before, -a.struct[title="struct syn::token::As"]::before, -a.struct[title="struct syn::token::Async"]::before, -a.struct[title="struct syn::token::At"]::before, -a.struct[title="struct syn::token::Auto"]::before, -a.struct[title="struct syn::token::Await"]::before, -a.struct[title="struct syn::token::Become"]::before, -a.struct[title="struct syn::token::Box"]::before, -a.struct[title="struct syn::token::Break"]::before, -a.struct[title="struct syn::token::Caret"]::before, -a.struct[title="struct syn::token::CaretEq"]::before, -a.struct[title="struct syn::token::Colon"]::before, -a.struct[title="struct syn::token::Comma"]::before, -a.struct[title="struct syn::token::Const"]::before, -a.struct[title="struct syn::token::Continue"]::before, -a.struct[title="struct syn::token::Crate"]::before, -a.struct[title="struct syn::token::Default"]::before, -a.struct[title="struct syn::token::Do"]::before, -a.struct[title="struct syn::token::Dollar"]::before, -a.struct[title="struct syn::token::Dot"]::before, -a.struct[title="struct syn::token::DotDot"]::before, -a.struct[title="struct syn::token::DotDotDot"]::before, -a.struct[title="struct syn::token::DotDotEq"]::before, -a.struct[title="struct syn::token::Dyn"]::before, -a.struct[title="struct syn::token::Else"]::before, -a.struct[title="struct syn::token::Enum"]::before, -a.struct[title="struct syn::token::Eq"]::before, -a.struct[title="struct syn::token::EqEq"]::before, -a.struct[title="struct syn::token::Extern"]::before, -a.struct[title="struct syn::token::FatArrow"]::before, -a.struct[title="struct syn::token::Final"]::before, -a.struct[title="struct syn::token::Fn"]::before, -a.struct[title="struct syn::token::For"]::before, -a.struct[title="struct syn::token::Ge"]::before, -a.struct[title="struct syn::token::Gt"]::before, -a.struct[title="struct syn::token::If"]::before, -a.struct[title="struct syn::token::Impl"]::before, -a.struct[title="struct syn::token::In"]::before, -a.struct[title="struct syn::token::LArrow"]::before, -a.struct[title="struct syn::token::Le"]::before, -a.struct[title="struct syn::token::Let"]::before, -a.struct[title="struct syn::token::Loop"]::before, -a.struct[title="struct syn::token::Lt"]::before, -a.struct[title="struct syn::token::Macro"]::before, -a.struct[title="struct syn::token::Match"]::before, -a.struct[title="struct syn::token::Minus"]::before, -a.struct[title="struct syn::token::MinusEq"]::before, -a.struct[title="struct syn::token::Mod"]::before, -a.struct[title="struct syn::token::Move"]::before, -a.struct[title="struct syn::token::Mut"]::before, -a.struct[title="struct syn::token::Ne"]::before, -a.struct[title="struct syn::token::Not"]::before, -a.struct[title="struct syn::token::Or"]::before, -a.struct[title="struct syn::token::OrEq"]::before, -a.struct[title="struct syn::token::OrOr"]::before, -a.struct[title="struct syn::token::Override"]::before, -a.struct[title="struct syn::token::PathSep"]::before, -a.struct[title="struct syn::token::Percent"]::before, -a.struct[title="struct syn::token::PercentEq"]::before, -a.struct[title="struct syn::token::Plus"]::before, -a.struct[title="struct syn::token::PlusEq"]::before, -a.struct[title="struct syn::token::Pound"]::before, -a.struct[title="struct syn::token::Priv"]::before, -a.struct[title="struct syn::token::Pub"]::before, -a.struct[title="struct syn::token::Question"]::before, -a.struct[title="struct syn::token::RArrow"]::before, -a.struct[title="struct syn::token::Raw"]::before, -a.struct[title="struct syn::token::Ref"]::before, -a.struct[title="struct syn::token::Return"]::before, -a.struct[title="struct syn::token::SelfType"]::before, -a.struct[title="struct syn::token::SelfValue"]::before, -a.struct[title="struct syn::token::Semi"]::before, -a.struct[title="struct syn::token::Shl"]::before, -a.struct[title="struct syn::token::ShlEq"]::before, -a.struct[title="struct syn::token::Shr"]::before, -a.struct[title="struct syn::token::ShrEq"]::before, -a.struct[title="struct syn::token::Slash"]::before, -a.struct[title="struct syn::token::SlashEq"]::before, -a.struct[title="struct syn::token::Star"]::before, -a.struct[title="struct syn::token::StarEq"]::before, -a.struct[title="struct syn::token::Static"]::before, -a.struct[title="struct syn::token::Struct"]::before, -a.struct[title="struct syn::token::Super"]::before, -a.struct[title="struct syn::token::Tilde"]::before, -a.struct[title="struct syn::token::Trait"]::before, -a.struct[title="struct syn::token::Try"]::before, -a.struct[title="struct syn::token::Type"]::before, -a.struct[title="struct syn::token::Typeof"]::before, -a.struct[title="struct syn::token::Underscore"]::before, -a.struct[title="struct syn::token::Union"]::before, -a.struct[title="struct syn::token::Unsafe"]::before, -a.struct[title="struct syn::token::Unsized"]::before, -a.struct[title="struct syn::token::Use"]::before, -a.struct[title="struct syn::token::Virtual"]::before, -a.struct[title="struct syn::token::Where"]::before, -a.struct[title="struct syn::token::While"]::before, -a.struct[title="struct syn::token::Yield"]::before { - display: inline-block; - color: var(--type-link-color); - width: 0; -} - -a.struct[title="struct syn::token::Abstract"]::before { - content: "Token![abstract]"; -} - -a.struct[title="struct syn::token::And"]::before { - content: "Token![&]"; -} - -a.struct[title="struct syn::token::AndAnd"]::before { - content: "Token![&&]"; -} - -a.struct[title="struct syn::token::AndEq"]::before { - content: "Token![&=]"; -} - -a.struct[title="struct syn::token::As"]::before { - content: "Token![as]"; -} - -a.struct[title="struct syn::token::Async"]::before { - content: "Token![async]"; -} - -a.struct[title="struct syn::token::At"]::before { - content: "Token![@]"; -} - -a.struct[title="struct syn::token::Auto"]::before { - content: "Token![auto]"; -} - -a.struct[title="struct syn::token::Await"]::before { - content: "Token![await]"; -} - -a.struct[title="struct syn::token::Become"]::before { - content: "Token![become]"; -} - -a.struct[title="struct syn::token::Box"]::before { - content: "Token![box]"; -} - -a.struct[title="struct syn::token::Break"]::before { - content: "Token![break]"; -} - -a.struct[title="struct syn::token::Caret"]::before { - content: "Token![^]"; -} - -a.struct[title="struct syn::token::CaretEq"]::before { - content: "Token![^=]"; -} - -a.struct[title="struct syn::token::Colon"]::before { - content: "Token![:]"; -} - -a.struct[title="struct syn::token::Comma"]::before { - content: "Token![,]"; -} - -a.struct[title="struct syn::token::Const"]::before { - content: "Token![const]"; -} - -a.struct[title="struct syn::token::Continue"]::before { - content: "Token![continue]"; -} - -a.struct[title="struct syn::token::Crate"]::before { - content: "Token![crate]"; -} - -a.struct[title="struct syn::token::Default"]::before { - content: "Token![default]"; -} - -a.struct[title="struct syn::token::Do"]::before { - content: "Token![do]"; -} - -a.struct[title="struct syn::token::Dollar"]::before { - content: "Token![$]"; -} - -a.struct[title="struct syn::token::Dot"]::before { - content: "Token![.]"; -} - -a.struct[title="struct syn::token::DotDot"]::before { - content: "Token![..]"; -} - -a.struct[title="struct syn::token::DotDotDot"]::before { - content: "Token![...]"; -} - -a.struct[title="struct syn::token::DotDotEq"]::before { - content: "Token![..=]"; -} - -a.struct[title="struct syn::token::Dyn"]::before { - content: "Token![dyn]"; -} - -a.struct[title="struct syn::token::Else"]::before { - content: "Token![else]"; -} - -a.struct[title="struct syn::token::Enum"]::before { - content: "Token![enum]"; -} - -a.struct[title="struct syn::token::Eq"]::before { - content: "Token![=]"; -} - -a.struct[title="struct syn::token::EqEq"]::before { - content: "Token![==]"; -} - -a.struct[title="struct syn::token::Extern"]::before { - content: "Token![extern]"; -} - -a.struct[title="struct syn::token::FatArrow"]::before { - content: "Token![=>]"; -} - -a.struct[title="struct syn::token::Final"]::before { - content: "Token![final]"; -} - -a.struct[title="struct syn::token::Fn"]::before { - content: "Token![fn]"; -} - -a.struct[title="struct syn::token::For"]::before { - content: "Token![for]"; -} - -a.struct[title="struct syn::token::Ge"]::before { - content: "Token![>=]"; -} - -a.struct[title="struct syn::token::Gt"]::before { - content: "Token![>]"; -} - -a.struct[title="struct syn::token::If"]::before { - content: "Token![if]"; -} - -a.struct[title="struct syn::token::Impl"]::before { - content: "Token![impl]"; -} - -a.struct[title="struct syn::token::In"]::before { - content: "Token![in]"; -} - -a.struct[title="struct syn::token::LArrow"]::before { - content: "Token![<-]"; -} - -a.struct[title="struct syn::token::Le"]::before { - content: "Token![<=]"; -} - -a.struct[title="struct syn::token::Let"]::before { - content: "Token![let]"; -} - -a.struct[title="struct syn::token::Loop"]::before { - content: "Token![loop]"; -} - -a.struct[title="struct syn::token::Lt"]::before { - content: "Token![<]"; -} - -a.struct[title="struct syn::token::Macro"]::before { - content: "Token![macro]"; -} - -a.struct[title="struct syn::token::Match"]::before { - content: "Token![match]"; -} - -a.struct[title="struct syn::token::Minus"]::before { - content: "Token![-]"; -} - -a.struct[title="struct syn::token::MinusEq"]::before { - content: "Token![-=]"; -} - -a.struct[title="struct syn::token::Mod"]::before { - content: "Token![mod]"; -} - -a.struct[title="struct syn::token::Move"]::before { - content: "Token![move]"; -} - -a.struct[title="struct syn::token::Mut"]::before { - content: "Token![mut]"; -} - -a.struct[title="struct syn::token::Ne"]::before { - content: "Token![!=]"; -} - -a.struct[title="struct syn::token::Not"]::before { - content: "Token![!]"; -} - -a.struct[title="struct syn::token::Or"]::before { - content: "Token![|]"; -} - -a.struct[title="struct syn::token::OrEq"]::before { - content: "Token![|=]"; -} - -a.struct[title="struct syn::token::OrOr"]::before { - content: "Token![||]"; -} - -a.struct[title="struct syn::token::Override"]::before { - content: "Token![override]"; -} - -a.struct[title="struct syn::token::PathSep"]::before { - content: "Token![::]"; -} - -a.struct[title="struct syn::token::Percent"]::before { - content: "Token![%]"; -} - -a.struct[title="struct syn::token::PercentEq"]::before { - content: "Token![%=]"; -} - -a.struct[title="struct syn::token::Plus"]::before { - content: "Token![+]"; -} - -a.struct[title="struct syn::token::PlusEq"]::before { - content: "Token![+=]"; -} - -a.struct[title="struct syn::token::Pound"]::before { - content: "Token![#]"; -} - -a.struct[title="struct syn::token::Priv"]::before { - content: "Token![priv]"; -} - -a.struct[title="struct syn::token::Pub"]::before { - content: "Token![pub]"; -} - -a.struct[title="struct syn::token::Question"]::before { - content: "Token![?]"; -} - -a.struct[title="struct syn::token::RArrow"]::before { - content: "Token![->]"; -} - -a.struct[title="struct syn::token::Raw"]::before { - content: "Token![raw]"; -} - -a.struct[title="struct syn::token::Ref"]::before { - content: "Token![ref]"; -} - -a.struct[title="struct syn::token::Return"]::before { - content: "Token![return]"; -} - -a.struct[title="struct syn::token::SelfType"]::before { - content: "Token![Self]"; -} - -a.struct[title="struct syn::token::SelfValue"]::before { - content: "Token![self]"; -} - -a.struct[title="struct syn::token::Semi"]::before { - content: "Token![;]"; -} - -a.struct[title="struct syn::token::Shl"]::before { - content: "Token![<<]"; -} - -a.struct[title="struct syn::token::ShlEq"]::before { - content: "Token![<<=]"; -} - -a.struct[title="struct syn::token::Shr"]::before { - content: "Token![>>]"; -} - -a.struct[title="struct syn::token::ShrEq"]::before { - content: "Token![>>=]"; -} - -a.struct[title="struct syn::token::Slash"]::before { - content: "Token![/]"; -} - -a.struct[title="struct syn::token::SlashEq"]::before { - content: "Token![/=]"; -} - -a.struct[title="struct syn::token::Star"]::before { - content: "Token![*]"; -} - -a.struct[title="struct syn::token::StarEq"]::before { - content: "Token![*=]"; -} - -a.struct[title="struct syn::token::Static"]::before { - content: "Token![static]"; -} - -a.struct[title="struct syn::token::Struct"]::before { - content: "Token![struct]"; -} - -a.struct[title="struct syn::token::Super"]::before { - content: "Token![super]"; -} - -a.struct[title="struct syn::token::Tilde"]::before { - content: "Token![~]"; -} - -a.struct[title="struct syn::token::Trait"]::before { - content: "Token![trait]"; -} - -a.struct[title="struct syn::token::Try"]::before { - content: "Token![try]"; -} - -a.struct[title="struct syn::token::Type"]::before { - content: "Token![type]"; -} - -a.struct[title="struct syn::token::Typeof"]::before { - content: "Token![typeof]"; -} - -a.struct[title="struct syn::token::Underscore"]::before { - content: "Token![_]"; - font-size: calc(100% * 10 / 9); -} - -a.struct[title="struct syn::token::Union"]::before { - content: "Token![union]"; -} - -a.struct[title="struct syn::token::Unsafe"]::before { - content: "Token![unsafe]"; -} - -a.struct[title="struct syn::token::Unsized"]::before { - content: "Token![unsized]"; -} - -a.struct[title="struct syn::token::Use"]::before { - content: "Token![use]"; -} - -a.struct[title="struct syn::token::Virtual"]::before { - content: "Token![virtual]"; -} - -a.struct[title="struct syn::token::Where"]::before { - content: "Token![where]"; -} - -a.struct[title="struct syn::token::While"]::before { - content: "Token![while]"; -} - -a.struct[title="struct syn::token::Yield"]::before { - content: "Token![yield]"; -} - -a.struct[title="struct syn::token::Underscore"] { - font-size: calc(100% * 9 / 10); -} - -a.struct[title="struct syn::token::PercentEq"]::after, -a.struct[title="struct syn::token::Question"]::after { - content: "."; -} - -a.struct[title="struct syn::token::DotDotDot"]::after, -a.struct[title="struct syn::token::FatArrow"]::after, -a.struct[title="struct syn::token::Percent"]::after { - content: ".."; -} - -a.struct[title="struct syn::token::CaretEq"]::after, -a.struct[title="struct syn::token::Dollar"]::after, -a.struct[title="struct syn::token::DotDotEq"]::after, -a.struct[title="struct syn::token::MinusEq"]::after, -a.struct[title="struct syn::token::PathSep"]::after, -a.struct[title="struct syn::token::SelfValue"]::after, -a.struct[title="struct syn::token::SlashEq"]::after { - content: "..."; -} - -a.struct[title="struct syn::token::AndAnd"]::after, -a.struct[title="struct syn::token::Caret"]::after, -a.struct[title="struct syn::token::Colon"]::after, -a.struct[title="struct syn::token::Comma"]::after, -a.struct[title="struct syn::token::DotDot"]::after, -a.struct[title="struct syn::token::LArrow"]::after, -a.struct[title="struct syn::token::Minus"]::after, -a.struct[title="struct syn::token::PlusEq"]::after, -a.struct[title="struct syn::token::Pound"]::after, -a.struct[title="struct syn::token::RArrow"]::after, -a.struct[title="struct syn::token::SelfType"]::after, -a.struct[title="struct syn::token::Slash"]::after, -a.struct[title="struct syn::token::StarEq"]::after, -a.struct[title="struct syn::token::Tilde"]::after { - content: "...."; -} - -a.struct[title="struct syn::token::AndEq"]::after, -a.struct[title="struct syn::token::Plus"]::after, -a.struct[title="struct syn::token::Semi"]::after, -a.struct[title="struct syn::token::Star"]::after { - content: "....."; -} - -a.struct[title="struct syn::token::And"]::after, -a.struct[title="struct syn::token::Dot"]::after, -a.struct[title="struct syn::token::EqEq"]::after, -a.struct[title="struct syn::token::Not"]::after, -a.struct[title="struct syn::token::OrEq"]::after, -a.struct[title="struct syn::token::OrOr"]::after, -a.struct[title="struct syn::token::ShlEq"]::after, -a.struct[title="struct syn::token::ShrEq"]::after { - content: "......"; -} - -a.struct[title="struct syn::token::At"]::after, -a.struct[title="struct syn::token::Eq"]::after, -a.struct[title="struct syn::token::Gt"]::after, -a.struct[title="struct syn::token::Lt"]::after, -a.struct[title="struct syn::token::Or"]::after, -a.struct[title="struct syn::token::Shl"]::after, -a.struct[title="struct syn::token::Shr"]::after { - content: "......."; -} - -a.struct[title="struct syn::token::Abstract"]::after, -a.struct[title="struct syn::token::As"]::after, -a.struct[title="struct syn::token::Async"]::after, -a.struct[title="struct syn::token::Auto"]::after, -a.struct[title="struct syn::token::Await"]::after, -a.struct[title="struct syn::token::Become"]::after, -a.struct[title="struct syn::token::Box"]::after, -a.struct[title="struct syn::token::Break"]::after, -a.struct[title="struct syn::token::Const"]::after, -a.struct[title="struct syn::token::Continue"]::after, -a.struct[title="struct syn::token::Crate"]::after, -a.struct[title="struct syn::token::Default"]::after, -a.struct[title="struct syn::token::Do"]::after, -a.struct[title="struct syn::token::Dyn"]::after, -a.struct[title="struct syn::token::Else"]::after, -a.struct[title="struct syn::token::Enum"]::after, -a.struct[title="struct syn::token::Extern"]::after, -a.struct[title="struct syn::token::Final"]::after, -a.struct[title="struct syn::token::Fn"]::after, -a.struct[title="struct syn::token::For"]::after, -a.struct[title="struct syn::token::Ge"]::after, -a.struct[title="struct syn::token::If"]::after, -a.struct[title="struct syn::token::Impl"]::after, -a.struct[title="struct syn::token::In"]::after, -a.struct[title="struct syn::token::Le"]::after, -a.struct[title="struct syn::token::Let"]::after, -a.struct[title="struct syn::token::Loop"]::after, -a.struct[title="struct syn::token::Macro"]::after, -a.struct[title="struct syn::token::Match"]::after, -a.struct[title="struct syn::token::Mod"]::after, -a.struct[title="struct syn::token::Move"]::after, -a.struct[title="struct syn::token::Mut"]::after, -a.struct[title="struct syn::token::Ne"]::after, -a.struct[title="struct syn::token::Override"]::after, -a.struct[title="struct syn::token::Priv"]::after, -a.struct[title="struct syn::token::Pub"]::after, -a.struct[title="struct syn::token::Raw"]::after, -a.struct[title="struct syn::token::Ref"]::after, -a.struct[title="struct syn::token::Return"]::after, -a.struct[title="struct syn::token::Static"]::after, -a.struct[title="struct syn::token::Struct"]::after, -a.struct[title="struct syn::token::Super"]::after, -a.struct[title="struct syn::token::Trait"]::after, -a.struct[title="struct syn::token::Try"]::after, -a.struct[title="struct syn::token::Type"]::after, -a.struct[title="struct syn::token::Typeof"]::after, -a.struct[title="struct syn::token::Union"]::after, -a.struct[title="struct syn::token::Unsafe"]::after, -a.struct[title="struct syn::token::Unsized"]::after, -a.struct[title="struct syn::token::Use"]::after, -a.struct[title="struct syn::token::Virtual"]::after, -a.struct[title="struct syn::token::Where"]::after, -a.struct[title="struct syn::token::While"]::after, -a.struct[title="struct syn::token::Yield"]::after { - content: "........"; -} diff --git a/deps/crates/vendor/syn-v2/src/gen/visit.rs b/deps/crates/vendor/syn-v2/src/gen/visit.rs deleted file mode 100644 index cd258fcde120..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/visit.rs +++ /dev/null @@ -1,3941 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#![allow(unused_variables)] -#![allow(clippy::needless_pass_by_ref_mut)] -#[cfg(any(feature = "full", feature = "derive"))] -use crate::punctuated::Punctuated; -#[cfg(feature = "full")] -macro_rules! full { - ($e:expr) => { - $e - }; -} -#[cfg(all(feature = "derive", not(feature = "full")))] -macro_rules! full { - ($e:expr) => { - unreachable!() - }; -} -macro_rules! skip { - ($($tt:tt)*) => {}; -} -/// Syntax tree traversal to walk a shared borrow of a syntax tree. -/// -/// See the [module documentation] for details. -/// -/// [module documentation]: self -pub trait Visit<'ast> { - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_abi(&mut self, i: &'ast crate::Abi) { - visit_abi(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_angle_bracketed_generic_arguments( - &mut self, - i: &'ast crate::AngleBracketedGenericArguments, - ) { - visit_angle_bracketed_generic_arguments(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_arm(&mut self, i: &'ast crate::Arm) { - visit_arm(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_assoc_const(&mut self, i: &'ast crate::AssocConst) { - visit_assoc_const(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_assoc_type(&mut self, i: &'ast crate::AssocType) { - visit_assoc_type(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_attr_style(&mut self, i: &'ast crate::AttrStyle) { - visit_attr_style(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_attribute(&mut self, i: &'ast crate::Attribute) { - visit_attribute(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bare_fn_arg(&mut self, i: &'ast crate::BareFnArg) { - visit_bare_fn_arg(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bare_variadic(&mut self, i: &'ast crate::BareVariadic) { - visit_bare_variadic(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bin_op(&mut self, i: &'ast crate::BinOp) { - visit_bin_op(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_block(&mut self, i: &'ast crate::Block) { - visit_block(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bound_lifetimes(&mut self, i: &'ast crate::BoundLifetimes) { - visit_bound_lifetimes(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_captured_param(&mut self, i: &'ast crate::CapturedParam) { - visit_captured_param(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_const_param(&mut self, i: &'ast crate::ConstParam) { - visit_const_param(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_constraint(&mut self, i: &'ast crate::Constraint) { - visit_constraint(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data(&mut self, i: &'ast crate::Data) { - visit_data(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_enum(&mut self, i: &'ast crate::DataEnum) { - visit_data_enum(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_struct(&mut self, i: &'ast crate::DataStruct) { - visit_data_struct(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_union(&mut self, i: &'ast crate::DataUnion) { - visit_data_union(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_derive_input(&mut self, i: &'ast crate::DeriveInput) { - visit_derive_input(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr(&mut self, i: &'ast crate::Expr) { - visit_expr(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_array(&mut self, i: &'ast crate::ExprArray) { - visit_expr_array(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_assign(&mut self, i: &'ast crate::ExprAssign) { - visit_expr_assign(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_async(&mut self, i: &'ast crate::ExprAsync) { - visit_expr_async(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_await(&mut self, i: &'ast crate::ExprAwait) { - visit_expr_await(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_binary(&mut self, i: &'ast crate::ExprBinary) { - visit_expr_binary(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_block(&mut self, i: &'ast crate::ExprBlock) { - visit_expr_block(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_break(&mut self, i: &'ast crate::ExprBreak) { - visit_expr_break(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_call(&mut self, i: &'ast crate::ExprCall) { - visit_expr_call(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_cast(&mut self, i: &'ast crate::ExprCast) { - visit_expr_cast(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_closure(&mut self, i: &'ast crate::ExprClosure) { - visit_expr_closure(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_const(&mut self, i: &'ast crate::ExprConst) { - visit_expr_const(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_continue(&mut self, i: &'ast crate::ExprContinue) { - visit_expr_continue(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_field(&mut self, i: &'ast crate::ExprField) { - visit_expr_field(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_for_loop(&mut self, i: &'ast crate::ExprForLoop) { - visit_expr_for_loop(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_group(&mut self, i: &'ast crate::ExprGroup) { - visit_expr_group(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_if(&mut self, i: &'ast crate::ExprIf) { - visit_expr_if(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_index(&mut self, i: &'ast crate::ExprIndex) { - visit_expr_index(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_infer(&mut self, i: &'ast crate::ExprInfer) { - visit_expr_infer(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_let(&mut self, i: &'ast crate::ExprLet) { - visit_expr_let(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_lit(&mut self, i: &'ast crate::ExprLit) { - visit_expr_lit(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_loop(&mut self, i: &'ast crate::ExprLoop) { - visit_expr_loop(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_macro(&mut self, i: &'ast crate::ExprMacro) { - visit_expr_macro(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_match(&mut self, i: &'ast crate::ExprMatch) { - visit_expr_match(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_method_call(&mut self, i: &'ast crate::ExprMethodCall) { - visit_expr_method_call(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_paren(&mut self, i: &'ast crate::ExprParen) { - visit_expr_paren(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_path(&mut self, i: &'ast crate::ExprPath) { - visit_expr_path(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_range(&mut self, i: &'ast crate::ExprRange) { - visit_expr_range(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_raw_addr(&mut self, i: &'ast crate::ExprRawAddr) { - visit_expr_raw_addr(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_reference(&mut self, i: &'ast crate::ExprReference) { - visit_expr_reference(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_repeat(&mut self, i: &'ast crate::ExprRepeat) { - visit_expr_repeat(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_return(&mut self, i: &'ast crate::ExprReturn) { - visit_expr_return(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_struct(&mut self, i: &'ast crate::ExprStruct) { - visit_expr_struct(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_try(&mut self, i: &'ast crate::ExprTry) { - visit_expr_try(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_try_block(&mut self, i: &'ast crate::ExprTryBlock) { - visit_expr_try_block(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_tuple(&mut self, i: &'ast crate::ExprTuple) { - visit_expr_tuple(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_unary(&mut self, i: &'ast crate::ExprUnary) { - visit_expr_unary(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_unsafe(&mut self, i: &'ast crate::ExprUnsafe) { - visit_expr_unsafe(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_while(&mut self, i: &'ast crate::ExprWhile) { - visit_expr_while(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_yield(&mut self, i: &'ast crate::ExprYield) { - visit_expr_yield(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_field(&mut self, i: &'ast crate::Field) { - visit_field(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_field_mutability(&mut self, i: &'ast crate::FieldMutability) { - visit_field_mutability(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_field_pat(&mut self, i: &'ast crate::FieldPat) { - visit_field_pat(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_field_value(&mut self, i: &'ast crate::FieldValue) { - visit_field_value(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_fields(&mut self, i: &'ast crate::Fields) { - visit_fields(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_fields_named(&mut self, i: &'ast crate::FieldsNamed) { - visit_fields_named(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_fields_unnamed(&mut self, i: &'ast crate::FieldsUnnamed) { - visit_fields_unnamed(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_file(&mut self, i: &'ast crate::File) { - visit_file(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_fn_arg(&mut self, i: &'ast crate::FnArg) { - visit_fn_arg(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item(&mut self, i: &'ast crate::ForeignItem) { - visit_foreign_item(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_fn(&mut self, i: &'ast crate::ForeignItemFn) { - visit_foreign_item_fn(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_macro(&mut self, i: &'ast crate::ForeignItemMacro) { - visit_foreign_item_macro(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_static(&mut self, i: &'ast crate::ForeignItemStatic) { - visit_foreign_item_static(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_type(&mut self, i: &'ast crate::ForeignItemType) { - visit_foreign_item_type(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_generic_argument(&mut self, i: &'ast crate::GenericArgument) { - visit_generic_argument(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_generic_param(&mut self, i: &'ast crate::GenericParam) { - visit_generic_param(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_generics(&mut self, i: &'ast crate::Generics) { - visit_generics(self, i); - } - fn visit_ident(&mut self, i: &'ast proc_macro2::Ident) { - visit_ident(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item(&mut self, i: &'ast crate::ImplItem) { - visit_impl_item(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_const(&mut self, i: &'ast crate::ImplItemConst) { - visit_impl_item_const(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_fn(&mut self, i: &'ast crate::ImplItemFn) { - visit_impl_item_fn(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_macro(&mut self, i: &'ast crate::ImplItemMacro) { - visit_impl_item_macro(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_type(&mut self, i: &'ast crate::ImplItemType) { - visit_impl_item_type(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_restriction(&mut self, i: &'ast crate::ImplRestriction) { - visit_impl_restriction(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_index(&mut self, i: &'ast crate::Index) { - visit_index(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item(&mut self, i: &'ast crate::Item) { - visit_item(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_const(&mut self, i: &'ast crate::ItemConst) { - visit_item_const(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_enum(&mut self, i: &'ast crate::ItemEnum) { - visit_item_enum(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_extern_crate(&mut self, i: &'ast crate::ItemExternCrate) { - visit_item_extern_crate(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_fn(&mut self, i: &'ast crate::ItemFn) { - visit_item_fn(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_foreign_mod(&mut self, i: &'ast crate::ItemForeignMod) { - visit_item_foreign_mod(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_impl(&mut self, i: &'ast crate::ItemImpl) { - visit_item_impl(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_macro(&mut self, i: &'ast crate::ItemMacro) { - visit_item_macro(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_mod(&mut self, i: &'ast crate::ItemMod) { - visit_item_mod(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_static(&mut self, i: &'ast crate::ItemStatic) { - visit_item_static(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_struct(&mut self, i: &'ast crate::ItemStruct) { - visit_item_struct(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_trait(&mut self, i: &'ast crate::ItemTrait) { - visit_item_trait(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_trait_alias(&mut self, i: &'ast crate::ItemTraitAlias) { - visit_item_trait_alias(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_type(&mut self, i: &'ast crate::ItemType) { - visit_item_type(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_union(&mut self, i: &'ast crate::ItemUnion) { - visit_item_union(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_use(&mut self, i: &'ast crate::ItemUse) { - visit_item_use(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_label(&mut self, i: &'ast crate::Label) { - visit_label(self, i); - } - fn visit_lifetime(&mut self, i: &'ast crate::Lifetime) { - visit_lifetime(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_lifetime_param(&mut self, i: &'ast crate::LifetimeParam) { - visit_lifetime_param(self, i); - } - fn visit_lit(&mut self, i: &'ast crate::Lit) { - visit_lit(self, i); - } - fn visit_lit_bool(&mut self, i: &'ast crate::LitBool) { - visit_lit_bool(self, i); - } - fn visit_lit_byte(&mut self, i: &'ast crate::LitByte) { - visit_lit_byte(self, i); - } - fn visit_lit_byte_str(&mut self, i: &'ast crate::LitByteStr) { - visit_lit_byte_str(self, i); - } - fn visit_lit_cstr(&mut self, i: &'ast crate::LitCStr) { - visit_lit_cstr(self, i); - } - fn visit_lit_char(&mut self, i: &'ast crate::LitChar) { - visit_lit_char(self, i); - } - fn visit_lit_float(&mut self, i: &'ast crate::LitFloat) { - visit_lit_float(self, i); - } - fn visit_lit_int(&mut self, i: &'ast crate::LitInt) { - visit_lit_int(self, i); - } - fn visit_lit_str(&mut self, i: &'ast crate::LitStr) { - visit_lit_str(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_local(&mut self, i: &'ast crate::Local) { - visit_local(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_local_init(&mut self, i: &'ast crate::LocalInit) { - visit_local_init(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_macro(&mut self, i: &'ast crate::Macro) { - visit_macro(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_macro_delimiter(&mut self, i: &'ast crate::MacroDelimiter) { - visit_macro_delimiter(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_member(&mut self, i: &'ast crate::Member) { - visit_member(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_meta(&mut self, i: &'ast crate::Meta) { - visit_meta(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_meta_list(&mut self, i: &'ast crate::MetaList) { - visit_meta_list(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_meta_name_value(&mut self, i: &'ast crate::MetaNameValue) { - visit_meta_name_value(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_parenthesized_generic_arguments( - &mut self, - i: &'ast crate::ParenthesizedGenericArguments, - ) { - visit_parenthesized_generic_arguments(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat(&mut self, i: &'ast crate::Pat) { - visit_pat(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_ident(&mut self, i: &'ast crate::PatIdent) { - visit_pat_ident(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_or(&mut self, i: &'ast crate::PatOr) { - visit_pat_or(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_paren(&mut self, i: &'ast crate::PatParen) { - visit_pat_paren(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_reference(&mut self, i: &'ast crate::PatReference) { - visit_pat_reference(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_rest(&mut self, i: &'ast crate::PatRest) { - visit_pat_rest(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_slice(&mut self, i: &'ast crate::PatSlice) { - visit_pat_slice(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_struct(&mut self, i: &'ast crate::PatStruct) { - visit_pat_struct(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_tuple(&mut self, i: &'ast crate::PatTuple) { - visit_pat_tuple(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_tuple_struct(&mut self, i: &'ast crate::PatTupleStruct) { - visit_pat_tuple_struct(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_type(&mut self, i: &'ast crate::PatType) { - visit_pat_type(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_wild(&mut self, i: &'ast crate::PatWild) { - visit_pat_wild(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_path(&mut self, i: &'ast crate::Path) { - visit_path(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_path_arguments(&mut self, i: &'ast crate::PathArguments) { - visit_path_arguments(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_path_segment(&mut self, i: &'ast crate::PathSegment) { - visit_path_segment(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pointer_mutability(&mut self, i: &'ast crate::PointerMutability) { - visit_pointer_mutability(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_precise_capture(&mut self, i: &'ast crate::PreciseCapture) { - visit_precise_capture(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_predicate_lifetime(&mut self, i: &'ast crate::PredicateLifetime) { - visit_predicate_lifetime(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_predicate_type(&mut self, i: &'ast crate::PredicateType) { - visit_predicate_type(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_qself(&mut self, i: &'ast crate::QSelf) { - visit_qself(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_range_limits(&mut self, i: &'ast crate::RangeLimits) { - visit_range_limits(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_receiver(&mut self, i: &'ast crate::Receiver) { - visit_receiver(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_return_type(&mut self, i: &'ast crate::ReturnType) { - visit_return_type(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_signature(&mut self, i: &'ast crate::Signature) { - visit_signature(self, i); - } - fn visit_span(&mut self, i: &proc_macro2::Span) {} - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_static_mutability(&mut self, i: &'ast crate::StaticMutability) { - visit_static_mutability(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_stmt(&mut self, i: &'ast crate::Stmt) { - visit_stmt(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_stmt_macro(&mut self, i: &'ast crate::StmtMacro) { - visit_stmt_macro(self, i); - } - fn visit_token_stream(&mut self, i: &'ast proc_macro2::TokenStream) {} - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_trait_bound(&mut self, i: &'ast crate::TraitBound) { - visit_trait_bound(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_trait_bound_modifier(&mut self, i: &'ast crate::TraitBoundModifier) { - visit_trait_bound_modifier(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item(&mut self, i: &'ast crate::TraitItem) { - visit_trait_item(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_const(&mut self, i: &'ast crate::TraitItemConst) { - visit_trait_item_const(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_fn(&mut self, i: &'ast crate::TraitItemFn) { - visit_trait_item_fn(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_macro(&mut self, i: &'ast crate::TraitItemMacro) { - visit_trait_item_macro(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_type(&mut self, i: &'ast crate::TraitItemType) { - visit_trait_item_type(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type(&mut self, i: &'ast crate::Type) { - visit_type(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_array(&mut self, i: &'ast crate::TypeArray) { - visit_type_array(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_bare_fn(&mut self, i: &'ast crate::TypeBareFn) { - visit_type_bare_fn(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_group(&mut self, i: &'ast crate::TypeGroup) { - visit_type_group(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_impl_trait(&mut self, i: &'ast crate::TypeImplTrait) { - visit_type_impl_trait(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_infer(&mut self, i: &'ast crate::TypeInfer) { - visit_type_infer(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_macro(&mut self, i: &'ast crate::TypeMacro) { - visit_type_macro(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_never(&mut self, i: &'ast crate::TypeNever) { - visit_type_never(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_param(&mut self, i: &'ast crate::TypeParam) { - visit_type_param(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_param_bound(&mut self, i: &'ast crate::TypeParamBound) { - visit_type_param_bound(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_paren(&mut self, i: &'ast crate::TypeParen) { - visit_type_paren(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_path(&mut self, i: &'ast crate::TypePath) { - visit_type_path(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_ptr(&mut self, i: &'ast crate::TypePtr) { - visit_type_ptr(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_reference(&mut self, i: &'ast crate::TypeReference) { - visit_type_reference(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_slice(&mut self, i: &'ast crate::TypeSlice) { - visit_type_slice(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_trait_object(&mut self, i: &'ast crate::TypeTraitObject) { - visit_type_trait_object(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_tuple(&mut self, i: &'ast crate::TypeTuple) { - visit_type_tuple(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_un_op(&mut self, i: &'ast crate::UnOp) { - visit_un_op(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_glob(&mut self, i: &'ast crate::UseGlob) { - visit_use_glob(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_group(&mut self, i: &'ast crate::UseGroup) { - visit_use_group(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_name(&mut self, i: &'ast crate::UseName) { - visit_use_name(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_path(&mut self, i: &'ast crate::UsePath) { - visit_use_path(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_rename(&mut self, i: &'ast crate::UseRename) { - visit_use_rename(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_tree(&mut self, i: &'ast crate::UseTree) { - visit_use_tree(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_variadic(&mut self, i: &'ast crate::Variadic) { - visit_variadic(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_variant(&mut self, i: &'ast crate::Variant) { - visit_variant(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_vis_restricted(&mut self, i: &'ast crate::VisRestricted) { - visit_vis_restricted(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_visibility(&mut self, i: &'ast crate::Visibility) { - visit_visibility(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_where_clause(&mut self, i: &'ast crate::WhereClause) { - visit_where_clause(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_where_predicate(&mut self, i: &'ast crate::WherePredicate) { - visit_where_predicate(self, i); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_abi<'ast, V>(v: &mut V, node: &'ast crate::Abi) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.extern_token); - if let Some(it) = &node.name { - v.visit_lit_str(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_angle_bracketed_generic_arguments<'ast, V>( - v: &mut V, - node: &'ast crate::AngleBracketedGenericArguments, -) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.colon2_token); - skip!(node.lt_token); - for el in Punctuated::pairs(&node.args) { - let it = el.value(); - v.visit_generic_argument(it); - } - skip!(node.gt_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_arm<'ast, V>(v: &mut V, node: &'ast crate::Arm) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_pat(&node.pat); - if let Some(it) = &node.guard { - skip!((it).0); - v.visit_expr(&*(it).1); - } - skip!(node.fat_arrow_token); - v.visit_expr(&*node.body); - skip!(node.comma); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_assoc_const<'ast, V>(v: &mut V, node: &'ast crate::AssocConst) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); - if let Some(it) = &node.generics { - v.visit_angle_bracketed_generic_arguments(it); - } - skip!(node.eq_token); - v.visit_expr(&node.value); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_assoc_type<'ast, V>(v: &mut V, node: &'ast crate::AssocType) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); - if let Some(it) = &node.generics { - v.visit_angle_bracketed_generic_arguments(it); - } - skip!(node.eq_token); - v.visit_type(&node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_attr_style<'ast, V>(v: &mut V, node: &'ast crate::AttrStyle) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::AttrStyle::Outer => {} - crate::AttrStyle::Inner(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_attribute<'ast, V>(v: &mut V, node: &'ast crate::Attribute) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.pound_token); - v.visit_attr_style(&node.style); - skip!(node.bracket_token); - v.visit_meta(&node.meta); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bare_fn_arg<'ast, V>(v: &mut V, node: &'ast crate::BareFnArg) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.name { - v.visit_ident(&(it).0); - skip!((it).1); - } - v.visit_type(&node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bare_variadic<'ast, V>(v: &mut V, node: &'ast crate::BareVariadic) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.name { - v.visit_ident(&(it).0); - skip!((it).1); - } - skip!(node.dots); - skip!(node.comma); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bin_op<'ast, V>(v: &mut V, node: &'ast crate::BinOp) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::BinOp::Add(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Sub(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Mul(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Div(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Rem(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::And(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Or(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitXor(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitAnd(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitOr(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Shl(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Shr(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Eq(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Lt(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Le(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Ne(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Ge(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Gt(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::AddAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::SubAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::MulAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::DivAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::RemAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitXorAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitAndAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitOrAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::ShlAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::ShrAssign(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_block<'ast, V>(v: &mut V, node: &'ast crate::Block) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.brace_token); - for it in &node.stmts { - v.visit_stmt(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bound_lifetimes<'ast, V>(v: &mut V, node: &'ast crate::BoundLifetimes) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.for_token); - skip!(node.lt_token); - for el in Punctuated::pairs(&node.lifetimes) { - let it = el.value(); - v.visit_generic_param(it); - } - skip!(node.gt_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_captured_param<'ast, V>(v: &mut V, node: &'ast crate::CapturedParam) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::CapturedParam::Lifetime(_binding_0) => { - v.visit_lifetime(_binding_0); - } - crate::CapturedParam::Ident(_binding_0) => { - v.visit_ident(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_const_param<'ast, V>(v: &mut V, node: &'ast crate::ConstParam) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.const_token); - v.visit_ident(&node.ident); - skip!(node.colon_token); - v.visit_type(&node.ty); - skip!(node.eq_token); - if let Some(it) = &node.default { - v.visit_expr(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_constraint<'ast, V>(v: &mut V, node: &'ast crate::Constraint) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); - if let Some(it) = &node.generics { - v.visit_angle_bracketed_generic_arguments(it); - } - skip!(node.colon_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data<'ast, V>(v: &mut V, node: &'ast crate::Data) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Data::Struct(_binding_0) => { - v.visit_data_struct(_binding_0); - } - crate::Data::Enum(_binding_0) => { - v.visit_data_enum(_binding_0); - } - crate::Data::Union(_binding_0) => { - v.visit_data_union(_binding_0); - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_enum<'ast, V>(v: &mut V, node: &'ast crate::DataEnum) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.enum_token); - skip!(node.brace_token); - for el in Punctuated::pairs(&node.variants) { - let it = el.value(); - v.visit_variant(it); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_struct<'ast, V>(v: &mut V, node: &'ast crate::DataStruct) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.struct_token); - v.visit_fields(&node.fields); - skip!(node.semi_token); -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_union<'ast, V>(v: &mut V, node: &'ast crate::DataUnion) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.union_token); - v.visit_fields_named(&node.fields); -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_derive_input<'ast, V>(v: &mut V, node: &'ast crate::DeriveInput) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - v.visit_data(&node.data); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr<'ast, V>(v: &mut V, node: &'ast crate::Expr) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Expr::Array(_binding_0) => { - full!(v.visit_expr_array(_binding_0)); - } - crate::Expr::Assign(_binding_0) => { - full!(v.visit_expr_assign(_binding_0)); - } - crate::Expr::Async(_binding_0) => { - full!(v.visit_expr_async(_binding_0)); - } - crate::Expr::Await(_binding_0) => { - full!(v.visit_expr_await(_binding_0)); - } - crate::Expr::Binary(_binding_0) => { - v.visit_expr_binary(_binding_0); - } - crate::Expr::Block(_binding_0) => { - full!(v.visit_expr_block(_binding_0)); - } - crate::Expr::Break(_binding_0) => { - full!(v.visit_expr_break(_binding_0)); - } - crate::Expr::Call(_binding_0) => { - v.visit_expr_call(_binding_0); - } - crate::Expr::Cast(_binding_0) => { - v.visit_expr_cast(_binding_0); - } - crate::Expr::Closure(_binding_0) => { - full!(v.visit_expr_closure(_binding_0)); - } - crate::Expr::Const(_binding_0) => { - full!(v.visit_expr_const(_binding_0)); - } - crate::Expr::Continue(_binding_0) => { - full!(v.visit_expr_continue(_binding_0)); - } - crate::Expr::Field(_binding_0) => { - v.visit_expr_field(_binding_0); - } - crate::Expr::ForLoop(_binding_0) => { - full!(v.visit_expr_for_loop(_binding_0)); - } - crate::Expr::Group(_binding_0) => { - v.visit_expr_group(_binding_0); - } - crate::Expr::If(_binding_0) => { - full!(v.visit_expr_if(_binding_0)); - } - crate::Expr::Index(_binding_0) => { - v.visit_expr_index(_binding_0); - } - crate::Expr::Infer(_binding_0) => { - full!(v.visit_expr_infer(_binding_0)); - } - crate::Expr::Let(_binding_0) => { - full!(v.visit_expr_let(_binding_0)); - } - crate::Expr::Lit(_binding_0) => { - v.visit_expr_lit(_binding_0); - } - crate::Expr::Loop(_binding_0) => { - full!(v.visit_expr_loop(_binding_0)); - } - crate::Expr::Macro(_binding_0) => { - v.visit_expr_macro(_binding_0); - } - crate::Expr::Match(_binding_0) => { - full!(v.visit_expr_match(_binding_0)); - } - crate::Expr::MethodCall(_binding_0) => { - v.visit_expr_method_call(_binding_0); - } - crate::Expr::Paren(_binding_0) => { - v.visit_expr_paren(_binding_0); - } - crate::Expr::Path(_binding_0) => { - v.visit_expr_path(_binding_0); - } - crate::Expr::Range(_binding_0) => { - full!(v.visit_expr_range(_binding_0)); - } - crate::Expr::RawAddr(_binding_0) => { - full!(v.visit_expr_raw_addr(_binding_0)); - } - crate::Expr::Reference(_binding_0) => { - v.visit_expr_reference(_binding_0); - } - crate::Expr::Repeat(_binding_0) => { - full!(v.visit_expr_repeat(_binding_0)); - } - crate::Expr::Return(_binding_0) => { - full!(v.visit_expr_return(_binding_0)); - } - crate::Expr::Struct(_binding_0) => { - v.visit_expr_struct(_binding_0); - } - crate::Expr::Try(_binding_0) => { - full!(v.visit_expr_try(_binding_0)); - } - crate::Expr::TryBlock(_binding_0) => { - full!(v.visit_expr_try_block(_binding_0)); - } - crate::Expr::Tuple(_binding_0) => { - v.visit_expr_tuple(_binding_0); - } - crate::Expr::Unary(_binding_0) => { - v.visit_expr_unary(_binding_0); - } - crate::Expr::Unsafe(_binding_0) => { - full!(v.visit_expr_unsafe(_binding_0)); - } - crate::Expr::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - crate::Expr::While(_binding_0) => { - full!(v.visit_expr_while(_binding_0)); - } - crate::Expr::Yield(_binding_0) => { - full!(v.visit_expr_yield(_binding_0)); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_array<'ast, V>(v: &mut V, node: &'ast crate::ExprArray) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.bracket_token); - for el in Punctuated::pairs(&node.elems) { - let it = el.value(); - v.visit_expr(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_assign<'ast, V>(v: &mut V, node: &'ast crate::ExprAssign) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.left); - skip!(node.eq_token); - v.visit_expr(&*node.right); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_async<'ast, V>(v: &mut V, node: &'ast crate::ExprAsync) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.async_token); - skip!(node.capture); - v.visit_block(&node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_await<'ast, V>(v: &mut V, node: &'ast crate::ExprAwait) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.base); - skip!(node.dot_token); - skip!(node.await_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast crate::ExprBinary) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.left); - v.visit_bin_op(&node.op); - v.visit_expr(&*node.right); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_block<'ast, V>(v: &mut V, node: &'ast crate::ExprBlock) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.label { - v.visit_label(it); - } - v.visit_block(&node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_break<'ast, V>(v: &mut V, node: &'ast crate::ExprBreak) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.break_token); - if let Some(it) = &node.label { - v.visit_lifetime(it); - } - if let Some(it) = &node.expr { - v.visit_expr(&**it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_call<'ast, V>(v: &mut V, node: &'ast crate::ExprCall) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.func); - skip!(node.paren_token); - for el in Punctuated::pairs(&node.args) { - let it = el.value(); - v.visit_expr(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_cast<'ast, V>(v: &mut V, node: &'ast crate::ExprCast) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.expr); - skip!(node.as_token); - v.visit_type(&*node.ty); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_closure<'ast, V>(v: &mut V, node: &'ast crate::ExprClosure) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.lifetimes { - v.visit_bound_lifetimes(it); - } - skip!(node.constness); - skip!(node.movability); - skip!(node.asyncness); - skip!(node.capture); - skip!(node.or1_token); - for el in Punctuated::pairs(&node.inputs) { - let it = el.value(); - v.visit_pat(it); - } - skip!(node.or2_token); - v.visit_return_type(&node.output); - v.visit_expr(&*node.body); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_const<'ast, V>(v: &mut V, node: &'ast crate::ExprConst) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.const_token); - v.visit_block(&node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_continue<'ast, V>(v: &mut V, node: &'ast crate::ExprContinue) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.continue_token); - if let Some(it) = &node.label { - v.visit_lifetime(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_field<'ast, V>(v: &mut V, node: &'ast crate::ExprField) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.base); - skip!(node.dot_token); - v.visit_member(&node.member); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_for_loop<'ast, V>(v: &mut V, node: &'ast crate::ExprForLoop) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.label { - v.visit_label(it); - } - skip!(node.for_token); - v.visit_pat(&*node.pat); - skip!(node.in_token); - v.visit_expr(&*node.expr); - v.visit_block(&node.body); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_group<'ast, V>(v: &mut V, node: &'ast crate::ExprGroup) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.group_token); - v.visit_expr(&*node.expr); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_if<'ast, V>(v: &mut V, node: &'ast crate::ExprIf) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.if_token); - v.visit_expr(&*node.cond); - v.visit_block(&node.then_branch); - if let Some(it) = &node.else_branch { - skip!((it).0); - v.visit_expr(&*(it).1); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_index<'ast, V>(v: &mut V, node: &'ast crate::ExprIndex) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.expr); - skip!(node.bracket_token); - v.visit_expr(&*node.index); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_infer<'ast, V>(v: &mut V, node: &'ast crate::ExprInfer) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.underscore_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_let<'ast, V>(v: &mut V, node: &'ast crate::ExprLet) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.let_token); - v.visit_pat(&*node.pat); - skip!(node.eq_token); - v.visit_expr(&*node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_lit<'ast, V>(v: &mut V, node: &'ast crate::ExprLit) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_lit(&node.lit); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_loop<'ast, V>(v: &mut V, node: &'ast crate::ExprLoop) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.label { - v.visit_label(it); - } - skip!(node.loop_token); - v.visit_block(&node.body); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_macro<'ast, V>(v: &mut V, node: &'ast crate::ExprMacro) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_macro(&node.mac); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_match<'ast, V>(v: &mut V, node: &'ast crate::ExprMatch) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.match_token); - v.visit_expr(&*node.expr); - skip!(node.brace_token); - for it in &node.arms { - v.visit_arm(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_method_call<'ast, V>(v: &mut V, node: &'ast crate::ExprMethodCall) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.receiver); - skip!(node.dot_token); - v.visit_ident(&node.method); - if let Some(it) = &node.turbofish { - v.visit_angle_bracketed_generic_arguments(it); - } - skip!(node.paren_token); - for el in Punctuated::pairs(&node.args) { - let it = el.value(); - v.visit_expr(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_paren<'ast, V>(v: &mut V, node: &'ast crate::ExprParen) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.paren_token); - v.visit_expr(&*node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_path<'ast, V>(v: &mut V, node: &'ast crate::ExprPath) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.qself { - v.visit_qself(it); - } - v.visit_path(&node.path); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_range<'ast, V>(v: &mut V, node: &'ast crate::ExprRange) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.start { - v.visit_expr(&**it); - } - v.visit_range_limits(&node.limits); - if let Some(it) = &node.end { - v.visit_expr(&**it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_raw_addr<'ast, V>(v: &mut V, node: &'ast crate::ExprRawAddr) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.and_token); - skip!(node.raw); - v.visit_pointer_mutability(&node.mutability); - v.visit_expr(&*node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_reference<'ast, V>(v: &mut V, node: &'ast crate::ExprReference) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.and_token); - skip!(node.mutability); - v.visit_expr(&*node.expr); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_repeat<'ast, V>(v: &mut V, node: &'ast crate::ExprRepeat) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.bracket_token); - v.visit_expr(&*node.expr); - skip!(node.semi_token); - v.visit_expr(&*node.len); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_return<'ast, V>(v: &mut V, node: &'ast crate::ExprReturn) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.return_token); - if let Some(it) = &node.expr { - v.visit_expr(&**it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_struct<'ast, V>(v: &mut V, node: &'ast crate::ExprStruct) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.qself { - v.visit_qself(it); - } - v.visit_path(&node.path); - skip!(node.brace_token); - for el in Punctuated::pairs(&node.fields) { - let it = el.value(); - v.visit_field_value(it); - } - skip!(node.dot2_token); - if let Some(it) = &node.rest { - v.visit_expr(&**it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_try<'ast, V>(v: &mut V, node: &'ast crate::ExprTry) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_expr(&*node.expr); - skip!(node.question_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_try_block<'ast, V>(v: &mut V, node: &'ast crate::ExprTryBlock) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.try_token); - v.visit_block(&node.block); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_tuple<'ast, V>(v: &mut V, node: &'ast crate::ExprTuple) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.paren_token); - for el in Punctuated::pairs(&node.elems) { - let it = el.value(); - v.visit_expr(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_unary<'ast, V>(v: &mut V, node: &'ast crate::ExprUnary) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_un_op(&node.op); - v.visit_expr(&*node.expr); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_unsafe<'ast, V>(v: &mut V, node: &'ast crate::ExprUnsafe) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.unsafe_token); - v.visit_block(&node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_while<'ast, V>(v: &mut V, node: &'ast crate::ExprWhile) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.label { - v.visit_label(it); - } - skip!(node.while_token); - v.visit_expr(&*node.cond); - v.visit_block(&node.body); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_yield<'ast, V>(v: &mut V, node: &'ast crate::ExprYield) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.yield_token); - if let Some(it) = &node.expr { - v.visit_expr(&**it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_field<'ast, V>(v: &mut V, node: &'ast crate::Field) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - v.visit_field_mutability(&node.mutability); - if let Some(it) = &node.ident { - v.visit_ident(it); - } - skip!(node.colon_token); - v.visit_type(&node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_field_mutability<'ast, V>(v: &mut V, node: &'ast crate::FieldMutability) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::FieldMutability::None => {} - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_field_pat<'ast, V>(v: &mut V, node: &'ast crate::FieldPat) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_member(&node.member); - skip!(node.colon_token); - v.visit_pat(&*node.pat); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_field_value<'ast, V>(v: &mut V, node: &'ast crate::FieldValue) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_member(&node.member); - skip!(node.colon_token); - v.visit_expr(&node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_fields<'ast, V>(v: &mut V, node: &'ast crate::Fields) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Fields::Named(_binding_0) => { - v.visit_fields_named(_binding_0); - } - crate::Fields::Unnamed(_binding_0) => { - v.visit_fields_unnamed(_binding_0); - } - crate::Fields::Unit => {} - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_fields_named<'ast, V>(v: &mut V, node: &'ast crate::FieldsNamed) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.brace_token); - for el in Punctuated::pairs(&node.named) { - let it = el.value(); - v.visit_field(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_fields_unnamed<'ast, V>(v: &mut V, node: &'ast crate::FieldsUnnamed) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.paren_token); - for el in Punctuated::pairs(&node.unnamed) { - let it = el.value(); - v.visit_field(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_file<'ast, V>(v: &mut V, node: &'ast crate::File) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.shebang); - for it in &node.attrs { - v.visit_attribute(it); - } - for it in &node.items { - v.visit_item(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_fn_arg<'ast, V>(v: &mut V, node: &'ast crate::FnArg) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::FnArg::Receiver(_binding_0) => { - v.visit_receiver(_binding_0); - } - crate::FnArg::Typed(_binding_0) => { - v.visit_pat_type(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item<'ast, V>(v: &mut V, node: &'ast crate::ForeignItem) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::ForeignItem::Fn(_binding_0) => { - v.visit_foreign_item_fn(_binding_0); - } - crate::ForeignItem::Static(_binding_0) => { - v.visit_foreign_item_static(_binding_0); - } - crate::ForeignItem::Type(_binding_0) => { - v.visit_foreign_item_type(_binding_0); - } - crate::ForeignItem::Macro(_binding_0) => { - v.visit_foreign_item_macro(_binding_0); - } - crate::ForeignItem::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_fn<'ast, V>(v: &mut V, node: &'ast crate::ForeignItemFn) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - v.visit_signature(&node.sig); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_macro<'ast, V>(v: &mut V, node: &'ast crate::ForeignItemMacro) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_macro(&node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_static<'ast, V>( - v: &mut V, - node: &'ast crate::ForeignItemStatic, -) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.static_token); - v.visit_static_mutability(&node.mutability); - v.visit_ident(&node.ident); - skip!(node.colon_token); - v.visit_type(&*node.ty); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_type<'ast, V>(v: &mut V, node: &'ast crate::ForeignItemType) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.type_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.semi_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_generic_argument<'ast, V>(v: &mut V, node: &'ast crate::GenericArgument) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::GenericArgument::Lifetime(_binding_0) => { - v.visit_lifetime(_binding_0); - } - crate::GenericArgument::Type(_binding_0) => { - v.visit_type(_binding_0); - } - crate::GenericArgument::Const(_binding_0) => { - v.visit_expr(_binding_0); - } - crate::GenericArgument::AssocType(_binding_0) => { - v.visit_assoc_type(_binding_0); - } - crate::GenericArgument::AssocConst(_binding_0) => { - v.visit_assoc_const(_binding_0); - } - crate::GenericArgument::Constraint(_binding_0) => { - v.visit_constraint(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_generic_param<'ast, V>(v: &mut V, node: &'ast crate::GenericParam) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::GenericParam::Lifetime(_binding_0) => { - v.visit_lifetime_param(_binding_0); - } - crate::GenericParam::Type(_binding_0) => { - v.visit_type_param(_binding_0); - } - crate::GenericParam::Const(_binding_0) => { - v.visit_const_param(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_generics<'ast, V>(v: &mut V, node: &'ast crate::Generics) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.lt_token); - for el in Punctuated::pairs(&node.params) { - let it = el.value(); - v.visit_generic_param(it); - } - skip!(node.gt_token); - if let Some(it) = &node.where_clause { - v.visit_where_clause(it); - } -} -pub fn visit_ident<'ast, V>(v: &mut V, node: &'ast proc_macro2::Ident) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_span(&node.span()); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item<'ast, V>(v: &mut V, node: &'ast crate::ImplItem) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::ImplItem::Const(_binding_0) => { - v.visit_impl_item_const(_binding_0); - } - crate::ImplItem::Fn(_binding_0) => { - v.visit_impl_item_fn(_binding_0); - } - crate::ImplItem::Type(_binding_0) => { - v.visit_impl_item_type(_binding_0); - } - crate::ImplItem::Macro(_binding_0) => { - v.visit_impl_item_macro(_binding_0); - } - crate::ImplItem::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_const<'ast, V>(v: &mut V, node: &'ast crate::ImplItemConst) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.defaultness); - skip!(node.const_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.colon_token); - v.visit_type(&node.ty); - skip!(node.eq_token); - v.visit_expr(&node.expr); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_fn<'ast, V>(v: &mut V, node: &'ast crate::ImplItemFn) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.defaultness); - v.visit_signature(&node.sig); - v.visit_block(&node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_macro<'ast, V>(v: &mut V, node: &'ast crate::ImplItemMacro) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_macro(&node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_type<'ast, V>(v: &mut V, node: &'ast crate::ImplItemType) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.defaultness); - skip!(node.type_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.eq_token); - v.visit_type(&node.ty); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_restriction<'ast, V>(v: &mut V, node: &'ast crate::ImplRestriction) -where - V: Visit<'ast> + ?Sized, -{ - match *node {} -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_index<'ast, V>(v: &mut V, node: &'ast crate::Index) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.index); - v.visit_span(&node.span); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item<'ast, V>(v: &mut V, node: &'ast crate::Item) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Item::Const(_binding_0) => { - v.visit_item_const(_binding_0); - } - crate::Item::Enum(_binding_0) => { - v.visit_item_enum(_binding_0); - } - crate::Item::ExternCrate(_binding_0) => { - v.visit_item_extern_crate(_binding_0); - } - crate::Item::Fn(_binding_0) => { - v.visit_item_fn(_binding_0); - } - crate::Item::ForeignMod(_binding_0) => { - v.visit_item_foreign_mod(_binding_0); - } - crate::Item::Impl(_binding_0) => { - v.visit_item_impl(_binding_0); - } - crate::Item::Macro(_binding_0) => { - v.visit_item_macro(_binding_0); - } - crate::Item::Mod(_binding_0) => { - v.visit_item_mod(_binding_0); - } - crate::Item::Static(_binding_0) => { - v.visit_item_static(_binding_0); - } - crate::Item::Struct(_binding_0) => { - v.visit_item_struct(_binding_0); - } - crate::Item::Trait(_binding_0) => { - v.visit_item_trait(_binding_0); - } - crate::Item::TraitAlias(_binding_0) => { - v.visit_item_trait_alias(_binding_0); - } - crate::Item::Type(_binding_0) => { - v.visit_item_type(_binding_0); - } - crate::Item::Union(_binding_0) => { - v.visit_item_union(_binding_0); - } - crate::Item::Use(_binding_0) => { - v.visit_item_use(_binding_0); - } - crate::Item::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_const<'ast, V>(v: &mut V, node: &'ast crate::ItemConst) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.const_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.colon_token); - v.visit_type(&*node.ty); - skip!(node.eq_token); - v.visit_expr(&*node.expr); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_enum<'ast, V>(v: &mut V, node: &'ast crate::ItemEnum) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.enum_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.brace_token); - for el in Punctuated::pairs(&node.variants) { - let it = el.value(); - v.visit_variant(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_extern_crate<'ast, V>(v: &mut V, node: &'ast crate::ItemExternCrate) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.extern_token); - skip!(node.crate_token); - v.visit_ident(&node.ident); - if let Some(it) = &node.rename { - skip!((it).0); - v.visit_ident(&(it).1); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_fn<'ast, V>(v: &mut V, node: &'ast crate::ItemFn) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - v.visit_signature(&node.sig); - v.visit_block(&*node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_foreign_mod<'ast, V>(v: &mut V, node: &'ast crate::ItemForeignMod) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.unsafety); - v.visit_abi(&node.abi); - skip!(node.brace_token); - for it in &node.items { - v.visit_foreign_item(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_impl<'ast, V>(v: &mut V, node: &'ast crate::ItemImpl) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.defaultness); - skip!(node.unsafety); - skip!(node.impl_token); - v.visit_generics(&node.generics); - if let Some(it) = &node.trait_ { - skip!((it).0); - v.visit_path(&(it).1); - skip!((it).2); - } - v.visit_type(&*node.self_ty); - skip!(node.brace_token); - for it in &node.items { - v.visit_impl_item(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_macro<'ast, V>(v: &mut V, node: &'ast crate::ItemMacro) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.ident { - v.visit_ident(it); - } - v.visit_macro(&node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_mod<'ast, V>(v: &mut V, node: &'ast crate::ItemMod) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.unsafety); - skip!(node.mod_token); - v.visit_ident(&node.ident); - if let Some(it) = &node.content { - skip!((it).0); - for it in &(it).1 { - v.visit_item(it); - } - } - skip!(node.semi); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_static<'ast, V>(v: &mut V, node: &'ast crate::ItemStatic) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.static_token); - v.visit_static_mutability(&node.mutability); - v.visit_ident(&node.ident); - skip!(node.colon_token); - v.visit_type(&*node.ty); - skip!(node.eq_token); - v.visit_expr(&*node.expr); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_struct<'ast, V>(v: &mut V, node: &'ast crate::ItemStruct) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.struct_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - v.visit_fields(&node.fields); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_trait<'ast, V>(v: &mut V, node: &'ast crate::ItemTrait) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.unsafety); - skip!(node.auto_token); - if let Some(it) = &node.restriction { - v.visit_impl_restriction(it); - } - skip!(node.trait_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.colon_token); - for el in Punctuated::pairs(&node.supertraits) { - let it = el.value(); - v.visit_type_param_bound(it); - } - skip!(node.brace_token); - for it in &node.items { - v.visit_trait_item(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_trait_alias<'ast, V>(v: &mut V, node: &'ast crate::ItemTraitAlias) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.trait_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.eq_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_type<'ast, V>(v: &mut V, node: &'ast crate::ItemType) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.type_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.eq_token); - v.visit_type(&*node.ty); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_union<'ast, V>(v: &mut V, node: &'ast crate::ItemUnion) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.union_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - v.visit_fields_named(&node.fields); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_use<'ast, V>(v: &mut V, node: &'ast crate::ItemUse) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_visibility(&node.vis); - skip!(node.use_token); - skip!(node.leading_colon); - v.visit_use_tree(&node.tree); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_label<'ast, V>(v: &mut V, node: &'ast crate::Label) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_lifetime(&node.name); - skip!(node.colon_token); -} -pub fn visit_lifetime<'ast, V>(v: &mut V, node: &'ast crate::Lifetime) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_span(&node.apostrophe); - v.visit_ident(&node.ident); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_lifetime_param<'ast, V>(v: &mut V, node: &'ast crate::LifetimeParam) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_lifetime(&node.lifetime); - skip!(node.colon_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_lifetime(it); - } -} -pub fn visit_lit<'ast, V>(v: &mut V, node: &'ast crate::Lit) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Lit::Str(_binding_0) => { - v.visit_lit_str(_binding_0); - } - crate::Lit::ByteStr(_binding_0) => { - v.visit_lit_byte_str(_binding_0); - } - crate::Lit::CStr(_binding_0) => { - v.visit_lit_cstr(_binding_0); - } - crate::Lit::Byte(_binding_0) => { - v.visit_lit_byte(_binding_0); - } - crate::Lit::Char(_binding_0) => { - v.visit_lit_char(_binding_0); - } - crate::Lit::Int(_binding_0) => { - v.visit_lit_int(_binding_0); - } - crate::Lit::Float(_binding_0) => { - v.visit_lit_float(_binding_0); - } - crate::Lit::Bool(_binding_0) => { - v.visit_lit_bool(_binding_0); - } - crate::Lit::Verbatim(_binding_0) => { - skip!(_binding_0); - } - } -} -pub fn visit_lit_bool<'ast, V>(v: &mut V, node: &'ast crate::LitBool) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.value); - v.visit_span(&node.span); -} -pub fn visit_lit_byte<'ast, V>(v: &mut V, node: &'ast crate::LitByte) -where - V: Visit<'ast> + ?Sized, -{} -pub fn visit_lit_byte_str<'ast, V>(v: &mut V, node: &'ast crate::LitByteStr) -where - V: Visit<'ast> + ?Sized, -{} -pub fn visit_lit_cstr<'ast, V>(v: &mut V, node: &'ast crate::LitCStr) -where - V: Visit<'ast> + ?Sized, -{} -pub fn visit_lit_char<'ast, V>(v: &mut V, node: &'ast crate::LitChar) -where - V: Visit<'ast> + ?Sized, -{} -pub fn visit_lit_float<'ast, V>(v: &mut V, node: &'ast crate::LitFloat) -where - V: Visit<'ast> + ?Sized, -{} -pub fn visit_lit_int<'ast, V>(v: &mut V, node: &'ast crate::LitInt) -where - V: Visit<'ast> + ?Sized, -{} -pub fn visit_lit_str<'ast, V>(v: &mut V, node: &'ast crate::LitStr) -where - V: Visit<'ast> + ?Sized, -{} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_local<'ast, V>(v: &mut V, node: &'ast crate::Local) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.let_token); - v.visit_pat(&node.pat); - if let Some(it) = &node.init { - v.visit_local_init(it); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_local_init<'ast, V>(v: &mut V, node: &'ast crate::LocalInit) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.eq_token); - v.visit_expr(&*node.expr); - if let Some(it) = &node.diverge { - skip!((it).0); - v.visit_expr(&*(it).1); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_macro<'ast, V>(v: &mut V, node: &'ast crate::Macro) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_path(&node.path); - skip!(node.bang_token); - v.visit_macro_delimiter(&node.delimiter); - v.visit_token_stream(&node.tokens); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_macro_delimiter<'ast, V>(v: &mut V, node: &'ast crate::MacroDelimiter) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::MacroDelimiter::Paren(_binding_0) => { - skip!(_binding_0); - } - crate::MacroDelimiter::Brace(_binding_0) => { - skip!(_binding_0); - } - crate::MacroDelimiter::Bracket(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_member<'ast, V>(v: &mut V, node: &'ast crate::Member) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Member::Named(_binding_0) => { - v.visit_ident(_binding_0); - } - crate::Member::Unnamed(_binding_0) => { - v.visit_index(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_meta<'ast, V>(v: &mut V, node: &'ast crate::Meta) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Meta::Path(_binding_0) => { - v.visit_path(_binding_0); - } - crate::Meta::List(_binding_0) => { - v.visit_meta_list(_binding_0); - } - crate::Meta::NameValue(_binding_0) => { - v.visit_meta_name_value(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_meta_list<'ast, V>(v: &mut V, node: &'ast crate::MetaList) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_path(&node.path); - v.visit_macro_delimiter(&node.delimiter); - v.visit_token_stream(&node.tokens); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_meta_name_value<'ast, V>(v: &mut V, node: &'ast crate::MetaNameValue) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_path(&node.path); - skip!(node.eq_token); - v.visit_expr(&node.value); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_parenthesized_generic_arguments<'ast, V>( - v: &mut V, - node: &'ast crate::ParenthesizedGenericArguments, -) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.paren_token); - for el in Punctuated::pairs(&node.inputs) { - let it = el.value(); - v.visit_type(it); - } - v.visit_return_type(&node.output); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat<'ast, V>(v: &mut V, node: &'ast crate::Pat) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Pat::Const(_binding_0) => { - v.visit_expr_const(_binding_0); - } - crate::Pat::Ident(_binding_0) => { - v.visit_pat_ident(_binding_0); - } - crate::Pat::Lit(_binding_0) => { - v.visit_expr_lit(_binding_0); - } - crate::Pat::Macro(_binding_0) => { - v.visit_expr_macro(_binding_0); - } - crate::Pat::Or(_binding_0) => { - v.visit_pat_or(_binding_0); - } - crate::Pat::Paren(_binding_0) => { - v.visit_pat_paren(_binding_0); - } - crate::Pat::Path(_binding_0) => { - v.visit_expr_path(_binding_0); - } - crate::Pat::Range(_binding_0) => { - v.visit_expr_range(_binding_0); - } - crate::Pat::Reference(_binding_0) => { - v.visit_pat_reference(_binding_0); - } - crate::Pat::Rest(_binding_0) => { - v.visit_pat_rest(_binding_0); - } - crate::Pat::Slice(_binding_0) => { - v.visit_pat_slice(_binding_0); - } - crate::Pat::Struct(_binding_0) => { - v.visit_pat_struct(_binding_0); - } - crate::Pat::Tuple(_binding_0) => { - v.visit_pat_tuple(_binding_0); - } - crate::Pat::TupleStruct(_binding_0) => { - v.visit_pat_tuple_struct(_binding_0); - } - crate::Pat::Type(_binding_0) => { - v.visit_pat_type(_binding_0); - } - crate::Pat::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - crate::Pat::Wild(_binding_0) => { - v.visit_pat_wild(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_ident<'ast, V>(v: &mut V, node: &'ast crate::PatIdent) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.by_ref); - skip!(node.mutability); - v.visit_ident(&node.ident); - if let Some(it) = &node.subpat { - skip!((it).0); - v.visit_pat(&*(it).1); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_or<'ast, V>(v: &mut V, node: &'ast crate::PatOr) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.leading_vert); - for el in Punctuated::pairs(&node.cases) { - let it = el.value(); - v.visit_pat(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_paren<'ast, V>(v: &mut V, node: &'ast crate::PatParen) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.paren_token); - v.visit_pat(&*node.pat); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_reference<'ast, V>(v: &mut V, node: &'ast crate::PatReference) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.and_token); - skip!(node.mutability); - v.visit_pat(&*node.pat); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_rest<'ast, V>(v: &mut V, node: &'ast crate::PatRest) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.dot2_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_slice<'ast, V>(v: &mut V, node: &'ast crate::PatSlice) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.bracket_token); - for el in Punctuated::pairs(&node.elems) { - let it = el.value(); - v.visit_pat(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_struct<'ast, V>(v: &mut V, node: &'ast crate::PatStruct) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.qself { - v.visit_qself(it); - } - v.visit_path(&node.path); - skip!(node.brace_token); - for el in Punctuated::pairs(&node.fields) { - let it = el.value(); - v.visit_field_pat(it); - } - if let Some(it) = &node.rest { - v.visit_pat_rest(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_tuple<'ast, V>(v: &mut V, node: &'ast crate::PatTuple) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.paren_token); - for el in Punctuated::pairs(&node.elems) { - let it = el.value(); - v.visit_pat(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_tuple_struct<'ast, V>(v: &mut V, node: &'ast crate::PatTupleStruct) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.qself { - v.visit_qself(it); - } - v.visit_path(&node.path); - skip!(node.paren_token); - for el in Punctuated::pairs(&node.elems) { - let it = el.value(); - v.visit_pat(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_type<'ast, V>(v: &mut V, node: &'ast crate::PatType) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_pat(&*node.pat); - skip!(node.colon_token); - v.visit_type(&*node.ty); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_wild<'ast, V>(v: &mut V, node: &'ast crate::PatWild) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.underscore_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_path<'ast, V>(v: &mut V, node: &'ast crate::Path) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.leading_colon); - for el in Punctuated::pairs(&node.segments) { - let it = el.value(); - v.visit_path_segment(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_path_arguments<'ast, V>(v: &mut V, node: &'ast crate::PathArguments) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::PathArguments::None => {} - crate::PathArguments::AngleBracketed(_binding_0) => { - v.visit_angle_bracketed_generic_arguments(_binding_0); - } - crate::PathArguments::Parenthesized(_binding_0) => { - v.visit_parenthesized_generic_arguments(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_path_segment<'ast, V>(v: &mut V, node: &'ast crate::PathSegment) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); - v.visit_path_arguments(&node.arguments); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pointer_mutability<'ast, V>(v: &mut V, node: &'ast crate::PointerMutability) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::PointerMutability::Const(_binding_0) => { - skip!(_binding_0); - } - crate::PointerMutability::Mut(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_precise_capture<'ast, V>(v: &mut V, node: &'ast crate::PreciseCapture) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.use_token); - skip!(node.lt_token); - for el in Punctuated::pairs(&node.params) { - let it = el.value(); - v.visit_captured_param(it); - } - skip!(node.gt_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_predicate_lifetime<'ast, V>(v: &mut V, node: &'ast crate::PredicateLifetime) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_lifetime(&node.lifetime); - skip!(node.colon_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_lifetime(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_predicate_type<'ast, V>(v: &mut V, node: &'ast crate::PredicateType) -where - V: Visit<'ast> + ?Sized, -{ - if let Some(it) = &node.lifetimes { - v.visit_bound_lifetimes(it); - } - v.visit_type(&node.bounded_ty); - skip!(node.colon_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_qself<'ast, V>(v: &mut V, node: &'ast crate::QSelf) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.lt_token); - v.visit_type(&*node.ty); - skip!(node.position); - skip!(node.as_token); - skip!(node.gt_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_range_limits<'ast, V>(v: &mut V, node: &'ast crate::RangeLimits) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::RangeLimits::HalfOpen(_binding_0) => { - skip!(_binding_0); - } - crate::RangeLimits::Closed(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_receiver<'ast, V>(v: &mut V, node: &'ast crate::Receiver) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.reference { - skip!((it).0); - if let Some(it) = &(it).1 { - v.visit_lifetime(it); - } - } - skip!(node.mutability); - skip!(node.self_token); - skip!(node.colon_token); - v.visit_type(&*node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_return_type<'ast, V>(v: &mut V, node: &'ast crate::ReturnType) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::ReturnType::Default => {} - crate::ReturnType::Type(_binding_0, _binding_1) => { - skip!(_binding_0); - v.visit_type(&**_binding_1); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_signature<'ast, V>(v: &mut V, node: &'ast crate::Signature) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.constness); - skip!(node.asyncness); - skip!(node.unsafety); - if let Some(it) = &node.abi { - v.visit_abi(it); - } - skip!(node.fn_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.paren_token); - for el in Punctuated::pairs(&node.inputs) { - let it = el.value(); - v.visit_fn_arg(it); - } - if let Some(it) = &node.variadic { - v.visit_variadic(it); - } - v.visit_return_type(&node.output); -} -pub fn visit_span<'ast, V>(v: &mut V, node: &proc_macro2::Span) -where - V: Visit<'ast> + ?Sized, -{} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_static_mutability<'ast, V>(v: &mut V, node: &'ast crate::StaticMutability) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::StaticMutability::Mut(_binding_0) => { - skip!(_binding_0); - } - crate::StaticMutability::None => {} - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_stmt<'ast, V>(v: &mut V, node: &'ast crate::Stmt) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Stmt::Local(_binding_0) => { - v.visit_local(_binding_0); - } - crate::Stmt::Item(_binding_0) => { - v.visit_item(_binding_0); - } - crate::Stmt::Expr(_binding_0, _binding_1) => { - v.visit_expr(_binding_0); - skip!(_binding_1); - } - crate::Stmt::Macro(_binding_0) => { - v.visit_stmt_macro(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_stmt_macro<'ast, V>(v: &mut V, node: &'ast crate::StmtMacro) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_macro(&node.mac); - skip!(node.semi_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_trait_bound<'ast, V>(v: &mut V, node: &'ast crate::TraitBound) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.paren_token); - v.visit_trait_bound_modifier(&node.modifier); - if let Some(it) = &node.lifetimes { - v.visit_bound_lifetimes(it); - } - v.visit_path(&node.path); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_trait_bound_modifier<'ast, V>( - v: &mut V, - node: &'ast crate::TraitBoundModifier, -) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::TraitBoundModifier::None => {} - crate::TraitBoundModifier::Maybe(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item<'ast, V>(v: &mut V, node: &'ast crate::TraitItem) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::TraitItem::Const(_binding_0) => { - v.visit_trait_item_const(_binding_0); - } - crate::TraitItem::Fn(_binding_0) => { - v.visit_trait_item_fn(_binding_0); - } - crate::TraitItem::Type(_binding_0) => { - v.visit_trait_item_type(_binding_0); - } - crate::TraitItem::Macro(_binding_0) => { - v.visit_trait_item_macro(_binding_0); - } - crate::TraitItem::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_const<'ast, V>(v: &mut V, node: &'ast crate::TraitItemConst) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.const_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.colon_token); - v.visit_type(&node.ty); - if let Some(it) = &node.default { - skip!((it).0); - v.visit_expr(&(it).1); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_fn<'ast, V>(v: &mut V, node: &'ast crate::TraitItemFn) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_signature(&node.sig); - if let Some(it) = &node.default { - v.visit_block(it); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_macro<'ast, V>(v: &mut V, node: &'ast crate::TraitItemMacro) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_macro(&node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_type<'ast, V>(v: &mut V, node: &'ast crate::TraitItemType) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - skip!(node.type_token); - v.visit_ident(&node.ident); - v.visit_generics(&node.generics); - skip!(node.colon_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } - if let Some(it) = &node.default { - skip!((it).0); - v.visit_type(&(it).1); - } - skip!(node.semi_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type<'ast, V>(v: &mut V, node: &'ast crate::Type) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Type::Array(_binding_0) => { - v.visit_type_array(_binding_0); - } - crate::Type::BareFn(_binding_0) => { - v.visit_type_bare_fn(_binding_0); - } - crate::Type::Group(_binding_0) => { - v.visit_type_group(_binding_0); - } - crate::Type::ImplTrait(_binding_0) => { - v.visit_type_impl_trait(_binding_0); - } - crate::Type::Infer(_binding_0) => { - v.visit_type_infer(_binding_0); - } - crate::Type::Macro(_binding_0) => { - v.visit_type_macro(_binding_0); - } - crate::Type::Never(_binding_0) => { - v.visit_type_never(_binding_0); - } - crate::Type::Paren(_binding_0) => { - v.visit_type_paren(_binding_0); - } - crate::Type::Path(_binding_0) => { - v.visit_type_path(_binding_0); - } - crate::Type::Ptr(_binding_0) => { - v.visit_type_ptr(_binding_0); - } - crate::Type::Reference(_binding_0) => { - v.visit_type_reference(_binding_0); - } - crate::Type::Slice(_binding_0) => { - v.visit_type_slice(_binding_0); - } - crate::Type::TraitObject(_binding_0) => { - v.visit_type_trait_object(_binding_0); - } - crate::Type::Tuple(_binding_0) => { - v.visit_type_tuple(_binding_0); - } - crate::Type::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_array<'ast, V>(v: &mut V, node: &'ast crate::TypeArray) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.bracket_token); - v.visit_type(&*node.elem); - skip!(node.semi_token); - v.visit_expr(&node.len); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_bare_fn<'ast, V>(v: &mut V, node: &'ast crate::TypeBareFn) -where - V: Visit<'ast> + ?Sized, -{ - if let Some(it) = &node.lifetimes { - v.visit_bound_lifetimes(it); - } - skip!(node.unsafety); - if let Some(it) = &node.abi { - v.visit_abi(it); - } - skip!(node.fn_token); - skip!(node.paren_token); - for el in Punctuated::pairs(&node.inputs) { - let it = el.value(); - v.visit_bare_fn_arg(it); - } - if let Some(it) = &node.variadic { - v.visit_bare_variadic(it); - } - v.visit_return_type(&node.output); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_group<'ast, V>(v: &mut V, node: &'ast crate::TypeGroup) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.group_token); - v.visit_type(&*node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_impl_trait<'ast, V>(v: &mut V, node: &'ast crate::TypeImplTrait) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.impl_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_infer<'ast, V>(v: &mut V, node: &'ast crate::TypeInfer) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.underscore_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_macro<'ast, V>(v: &mut V, node: &'ast crate::TypeMacro) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_macro(&node.mac); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_never<'ast, V>(v: &mut V, node: &'ast crate::TypeNever) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.bang_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_param<'ast, V>(v: &mut V, node: &'ast crate::TypeParam) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_ident(&node.ident); - skip!(node.colon_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } - skip!(node.eq_token); - if let Some(it) = &node.default { - v.visit_type(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_param_bound<'ast, V>(v: &mut V, node: &'ast crate::TypeParamBound) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::TypeParamBound::Trait(_binding_0) => { - v.visit_trait_bound(_binding_0); - } - crate::TypeParamBound::Lifetime(_binding_0) => { - v.visit_lifetime(_binding_0); - } - crate::TypeParamBound::PreciseCapture(_binding_0) => { - full!(v.visit_precise_capture(_binding_0)); - } - crate::TypeParamBound::Verbatim(_binding_0) => { - v.visit_token_stream(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_paren<'ast, V>(v: &mut V, node: &'ast crate::TypeParen) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.paren_token); - v.visit_type(&*node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_path<'ast, V>(v: &mut V, node: &'ast crate::TypePath) -where - V: Visit<'ast> + ?Sized, -{ - if let Some(it) = &node.qself { - v.visit_qself(it); - } - v.visit_path(&node.path); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_ptr<'ast, V>(v: &mut V, node: &'ast crate::TypePtr) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.star_token); - skip!(node.const_token); - skip!(node.mutability); - v.visit_type(&*node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_reference<'ast, V>(v: &mut V, node: &'ast crate::TypeReference) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.and_token); - if let Some(it) = &node.lifetime { - v.visit_lifetime(it); - } - skip!(node.mutability); - v.visit_type(&*node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_slice<'ast, V>(v: &mut V, node: &'ast crate::TypeSlice) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.bracket_token); - v.visit_type(&*node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_trait_object<'ast, V>(v: &mut V, node: &'ast crate::TypeTraitObject) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.dyn_token); - for el in Punctuated::pairs(&node.bounds) { - let it = el.value(); - v.visit_type_param_bound(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_tuple<'ast, V>(v: &mut V, node: &'ast crate::TypeTuple) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.paren_token); - for el in Punctuated::pairs(&node.elems) { - let it = el.value(); - v.visit_type(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_un_op<'ast, V>(v: &mut V, node: &'ast crate::UnOp) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::UnOp::Deref(_binding_0) => { - skip!(_binding_0); - } - crate::UnOp::Not(_binding_0) => { - skip!(_binding_0); - } - crate::UnOp::Neg(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_glob<'ast, V>(v: &mut V, node: &'ast crate::UseGlob) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.star_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_group<'ast, V>(v: &mut V, node: &'ast crate::UseGroup) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.brace_token); - for el in Punctuated::pairs(&node.items) { - let it = el.value(); - v.visit_use_tree(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_name<'ast, V>(v: &mut V, node: &'ast crate::UseName) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_path<'ast, V>(v: &mut V, node: &'ast crate::UsePath) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); - skip!(node.colon2_token); - v.visit_use_tree(&*node.tree); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_rename<'ast, V>(v: &mut V, node: &'ast crate::UseRename) -where - V: Visit<'ast> + ?Sized, -{ - v.visit_ident(&node.ident); - skip!(node.as_token); - v.visit_ident(&node.rename); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_tree<'ast, V>(v: &mut V, node: &'ast crate::UseTree) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::UseTree::Path(_binding_0) => { - v.visit_use_path(_binding_0); - } - crate::UseTree::Name(_binding_0) => { - v.visit_use_name(_binding_0); - } - crate::UseTree::Rename(_binding_0) => { - v.visit_use_rename(_binding_0); - } - crate::UseTree::Glob(_binding_0) => { - v.visit_use_glob(_binding_0); - } - crate::UseTree::Group(_binding_0) => { - v.visit_use_group(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_variadic<'ast, V>(v: &mut V, node: &'ast crate::Variadic) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - if let Some(it) = &node.pat { - v.visit_pat(&*(it).0); - skip!((it).1); - } - skip!(node.dots); - skip!(node.comma); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_variant<'ast, V>(v: &mut V, node: &'ast crate::Variant) -where - V: Visit<'ast> + ?Sized, -{ - for it in &node.attrs { - v.visit_attribute(it); - } - v.visit_ident(&node.ident); - v.visit_fields(&node.fields); - if let Some(it) = &node.discriminant { - skip!((it).0); - v.visit_expr(&(it).1); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_vis_restricted<'ast, V>(v: &mut V, node: &'ast crate::VisRestricted) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.pub_token); - skip!(node.paren_token); - skip!(node.in_token); - v.visit_path(&*node.path); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_visibility<'ast, V>(v: &mut V, node: &'ast crate::Visibility) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::Visibility::Public(_binding_0) => { - skip!(_binding_0); - } - crate::Visibility::Restricted(_binding_0) => { - v.visit_vis_restricted(_binding_0); - } - crate::Visibility::Inherited => {} - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_where_clause<'ast, V>(v: &mut V, node: &'ast crate::WhereClause) -where - V: Visit<'ast> + ?Sized, -{ - skip!(node.where_token); - for el in Punctuated::pairs(&node.predicates) { - let it = el.value(); - v.visit_where_predicate(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_where_predicate<'ast, V>(v: &mut V, node: &'ast crate::WherePredicate) -where - V: Visit<'ast> + ?Sized, -{ - match node { - crate::WherePredicate::Lifetime(_binding_0) => { - v.visit_predicate_lifetime(_binding_0); - } - crate::WherePredicate::Type(_binding_0) => { - v.visit_predicate_type(_binding_0); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/gen/visit_mut.rs b/deps/crates/vendor/syn-v2/src/gen/visit_mut.rs deleted file mode 100644 index 6588182c4fd6..000000000000 --- a/deps/crates/vendor/syn-v2/src/gen/visit_mut.rs +++ /dev/null @@ -1,3761 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#![allow(unused_variables)] -#![allow(clippy::needless_pass_by_ref_mut)] -#[cfg(any(feature = "full", feature = "derive"))] -use crate::punctuated::Punctuated; -#[cfg(any(feature = "derive", feature = "full"))] -use alloc::vec::Vec; -#[cfg(feature = "full")] -macro_rules! full { - ($e:expr) => { - $e - }; -} -#[cfg(all(feature = "derive", not(feature = "full")))] -macro_rules! full { - ($e:expr) => { - unreachable!() - }; -} -macro_rules! skip { - ($($tt:tt)*) => {}; -} -/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in -/// place. -/// -/// See the [module documentation] for details. -/// -/// [module documentation]: self -pub trait VisitMut { - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_abi_mut(&mut self, i: &mut crate::Abi) { - visit_abi_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_angle_bracketed_generic_arguments_mut( - &mut self, - i: &mut crate::AngleBracketedGenericArguments, - ) { - visit_angle_bracketed_generic_arguments_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_arm_mut(&mut self, i: &mut crate::Arm) { - visit_arm_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_assoc_const_mut(&mut self, i: &mut crate::AssocConst) { - visit_assoc_const_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_assoc_type_mut(&mut self, i: &mut crate::AssocType) { - visit_assoc_type_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_attr_style_mut(&mut self, i: &mut crate::AttrStyle) { - visit_attr_style_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_attribute_mut(&mut self, i: &mut crate::Attribute) { - visit_attribute_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_attributes_mut(&mut self, i: &mut Vec<crate::Attribute>) { - for attr in i { - self.visit_attribute_mut(attr); - } - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bare_fn_arg_mut(&mut self, i: &mut crate::BareFnArg) { - visit_bare_fn_arg_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bare_variadic_mut(&mut self, i: &mut crate::BareVariadic) { - visit_bare_variadic_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bin_op_mut(&mut self, i: &mut crate::BinOp) { - visit_bin_op_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_block_mut(&mut self, i: &mut crate::Block) { - visit_block_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_bound_lifetimes_mut(&mut self, i: &mut crate::BoundLifetimes) { - visit_bound_lifetimes_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_captured_param_mut(&mut self, i: &mut crate::CapturedParam) { - visit_captured_param_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_const_param_mut(&mut self, i: &mut crate::ConstParam) { - visit_const_param_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_constraint_mut(&mut self, i: &mut crate::Constraint) { - visit_constraint_mut(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_mut(&mut self, i: &mut crate::Data) { - visit_data_mut(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_enum_mut(&mut self, i: &mut crate::DataEnum) { - visit_data_enum_mut(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_struct_mut(&mut self, i: &mut crate::DataStruct) { - visit_data_struct_mut(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_data_union_mut(&mut self, i: &mut crate::DataUnion) { - visit_data_union_mut(self, i); - } - #[cfg(feature = "derive")] - #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] - fn visit_derive_input_mut(&mut self, i: &mut crate::DeriveInput) { - visit_derive_input_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_mut(&mut self, i: &mut crate::Expr) { - visit_expr_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_array_mut(&mut self, i: &mut crate::ExprArray) { - visit_expr_array_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_assign_mut(&mut self, i: &mut crate::ExprAssign) { - visit_expr_assign_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_async_mut(&mut self, i: &mut crate::ExprAsync) { - visit_expr_async_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_await_mut(&mut self, i: &mut crate::ExprAwait) { - visit_expr_await_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_binary_mut(&mut self, i: &mut crate::ExprBinary) { - visit_expr_binary_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_block_mut(&mut self, i: &mut crate::ExprBlock) { - visit_expr_block_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_break_mut(&mut self, i: &mut crate::ExprBreak) { - visit_expr_break_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_call_mut(&mut self, i: &mut crate::ExprCall) { - visit_expr_call_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_cast_mut(&mut self, i: &mut crate::ExprCast) { - visit_expr_cast_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_closure_mut(&mut self, i: &mut crate::ExprClosure) { - visit_expr_closure_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_const_mut(&mut self, i: &mut crate::ExprConst) { - visit_expr_const_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_continue_mut(&mut self, i: &mut crate::ExprContinue) { - visit_expr_continue_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_field_mut(&mut self, i: &mut crate::ExprField) { - visit_expr_field_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_for_loop_mut(&mut self, i: &mut crate::ExprForLoop) { - visit_expr_for_loop_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_group_mut(&mut self, i: &mut crate::ExprGroup) { - visit_expr_group_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_if_mut(&mut self, i: &mut crate::ExprIf) { - visit_expr_if_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_index_mut(&mut self, i: &mut crate::ExprIndex) { - visit_expr_index_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_infer_mut(&mut self, i: &mut crate::ExprInfer) { - visit_expr_infer_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_let_mut(&mut self, i: &mut crate::ExprLet) { - visit_expr_let_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_lit_mut(&mut self, i: &mut crate::ExprLit) { - visit_expr_lit_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_loop_mut(&mut self, i: &mut crate::ExprLoop) { - visit_expr_loop_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_macro_mut(&mut self, i: &mut crate::ExprMacro) { - visit_expr_macro_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_match_mut(&mut self, i: &mut crate::ExprMatch) { - visit_expr_match_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_method_call_mut(&mut self, i: &mut crate::ExprMethodCall) { - visit_expr_method_call_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_paren_mut(&mut self, i: &mut crate::ExprParen) { - visit_expr_paren_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_path_mut(&mut self, i: &mut crate::ExprPath) { - visit_expr_path_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_range_mut(&mut self, i: &mut crate::ExprRange) { - visit_expr_range_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_raw_addr_mut(&mut self, i: &mut crate::ExprRawAddr) { - visit_expr_raw_addr_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_reference_mut(&mut self, i: &mut crate::ExprReference) { - visit_expr_reference_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_repeat_mut(&mut self, i: &mut crate::ExprRepeat) { - visit_expr_repeat_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_return_mut(&mut self, i: &mut crate::ExprReturn) { - visit_expr_return_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_struct_mut(&mut self, i: &mut crate::ExprStruct) { - visit_expr_struct_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_try_mut(&mut self, i: &mut crate::ExprTry) { - visit_expr_try_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_try_block_mut(&mut self, i: &mut crate::ExprTryBlock) { - visit_expr_try_block_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_tuple_mut(&mut self, i: &mut crate::ExprTuple) { - visit_expr_tuple_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_expr_unary_mut(&mut self, i: &mut crate::ExprUnary) { - visit_expr_unary_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_unsafe_mut(&mut self, i: &mut crate::ExprUnsafe) { - visit_expr_unsafe_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_while_mut(&mut self, i: &mut crate::ExprWhile) { - visit_expr_while_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_expr_yield_mut(&mut self, i: &mut crate::ExprYield) { - visit_expr_yield_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_field_mut(&mut self, i: &mut crate::Field) { - visit_field_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_field_mutability_mut(&mut self, i: &mut crate::FieldMutability) { - visit_field_mutability_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_field_pat_mut(&mut self, i: &mut crate::FieldPat) { - visit_field_pat_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_field_value_mut(&mut self, i: &mut crate::FieldValue) { - visit_field_value_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_fields_mut(&mut self, i: &mut crate::Fields) { - visit_fields_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_fields_named_mut(&mut self, i: &mut crate::FieldsNamed) { - visit_fields_named_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_fields_unnamed_mut(&mut self, i: &mut crate::FieldsUnnamed) { - visit_fields_unnamed_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_file_mut(&mut self, i: &mut crate::File) { - visit_file_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_fn_arg_mut(&mut self, i: &mut crate::FnArg) { - visit_fn_arg_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_mut(&mut self, i: &mut crate::ForeignItem) { - visit_foreign_item_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_fn_mut(&mut self, i: &mut crate::ForeignItemFn) { - visit_foreign_item_fn_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_macro_mut(&mut self, i: &mut crate::ForeignItemMacro) { - visit_foreign_item_macro_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_static_mut(&mut self, i: &mut crate::ForeignItemStatic) { - visit_foreign_item_static_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_foreign_item_type_mut(&mut self, i: &mut crate::ForeignItemType) { - visit_foreign_item_type_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_generic_argument_mut(&mut self, i: &mut crate::GenericArgument) { - visit_generic_argument_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_generic_param_mut(&mut self, i: &mut crate::GenericParam) { - visit_generic_param_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_generics_mut(&mut self, i: &mut crate::Generics) { - visit_generics_mut(self, i); - } - fn visit_ident_mut(&mut self, i: &mut proc_macro2::Ident) { - visit_ident_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_mut(&mut self, i: &mut crate::ImplItem) { - visit_impl_item_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_const_mut(&mut self, i: &mut crate::ImplItemConst) { - visit_impl_item_const_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_fn_mut(&mut self, i: &mut crate::ImplItemFn) { - visit_impl_item_fn_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_macro_mut(&mut self, i: &mut crate::ImplItemMacro) { - visit_impl_item_macro_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_item_type_mut(&mut self, i: &mut crate::ImplItemType) { - visit_impl_item_type_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_impl_restriction_mut(&mut self, i: &mut crate::ImplRestriction) { - visit_impl_restriction_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_index_mut(&mut self, i: &mut crate::Index) { - visit_index_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_mut(&mut self, i: &mut crate::Item) { - visit_item_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_const_mut(&mut self, i: &mut crate::ItemConst) { - visit_item_const_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_enum_mut(&mut self, i: &mut crate::ItemEnum) { - visit_item_enum_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_extern_crate_mut(&mut self, i: &mut crate::ItemExternCrate) { - visit_item_extern_crate_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_fn_mut(&mut self, i: &mut crate::ItemFn) { - visit_item_fn_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_foreign_mod_mut(&mut self, i: &mut crate::ItemForeignMod) { - visit_item_foreign_mod_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_impl_mut(&mut self, i: &mut crate::ItemImpl) { - visit_item_impl_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_macro_mut(&mut self, i: &mut crate::ItemMacro) { - visit_item_macro_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_mod_mut(&mut self, i: &mut crate::ItemMod) { - visit_item_mod_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_static_mut(&mut self, i: &mut crate::ItemStatic) { - visit_item_static_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_struct_mut(&mut self, i: &mut crate::ItemStruct) { - visit_item_struct_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_trait_mut(&mut self, i: &mut crate::ItemTrait) { - visit_item_trait_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_trait_alias_mut(&mut self, i: &mut crate::ItemTraitAlias) { - visit_item_trait_alias_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_type_mut(&mut self, i: &mut crate::ItemType) { - visit_item_type_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_union_mut(&mut self, i: &mut crate::ItemUnion) { - visit_item_union_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_item_use_mut(&mut self, i: &mut crate::ItemUse) { - visit_item_use_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_label_mut(&mut self, i: &mut crate::Label) { - visit_label_mut(self, i); - } - fn visit_lifetime_mut(&mut self, i: &mut crate::Lifetime) { - visit_lifetime_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_lifetime_param_mut(&mut self, i: &mut crate::LifetimeParam) { - visit_lifetime_param_mut(self, i); - } - fn visit_lit_mut(&mut self, i: &mut crate::Lit) { - visit_lit_mut(self, i); - } - fn visit_lit_bool_mut(&mut self, i: &mut crate::LitBool) { - visit_lit_bool_mut(self, i); - } - fn visit_lit_byte_mut(&mut self, i: &mut crate::LitByte) { - visit_lit_byte_mut(self, i); - } - fn visit_lit_byte_str_mut(&mut self, i: &mut crate::LitByteStr) { - visit_lit_byte_str_mut(self, i); - } - fn visit_lit_cstr_mut(&mut self, i: &mut crate::LitCStr) { - visit_lit_cstr_mut(self, i); - } - fn visit_lit_char_mut(&mut self, i: &mut crate::LitChar) { - visit_lit_char_mut(self, i); - } - fn visit_lit_float_mut(&mut self, i: &mut crate::LitFloat) { - visit_lit_float_mut(self, i); - } - fn visit_lit_int_mut(&mut self, i: &mut crate::LitInt) { - visit_lit_int_mut(self, i); - } - fn visit_lit_str_mut(&mut self, i: &mut crate::LitStr) { - visit_lit_str_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_local_mut(&mut self, i: &mut crate::Local) { - visit_local_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_local_init_mut(&mut self, i: &mut crate::LocalInit) { - visit_local_init_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_macro_mut(&mut self, i: &mut crate::Macro) { - visit_macro_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_macro_delimiter_mut(&mut self, i: &mut crate::MacroDelimiter) { - visit_macro_delimiter_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_member_mut(&mut self, i: &mut crate::Member) { - visit_member_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_meta_mut(&mut self, i: &mut crate::Meta) { - visit_meta_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_meta_list_mut(&mut self, i: &mut crate::MetaList) { - visit_meta_list_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_meta_name_value_mut(&mut self, i: &mut crate::MetaNameValue) { - visit_meta_name_value_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_parenthesized_generic_arguments_mut( - &mut self, - i: &mut crate::ParenthesizedGenericArguments, - ) { - visit_parenthesized_generic_arguments_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_mut(&mut self, i: &mut crate::Pat) { - visit_pat_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_ident_mut(&mut self, i: &mut crate::PatIdent) { - visit_pat_ident_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_or_mut(&mut self, i: &mut crate::PatOr) { - visit_pat_or_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_paren_mut(&mut self, i: &mut crate::PatParen) { - visit_pat_paren_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_reference_mut(&mut self, i: &mut crate::PatReference) { - visit_pat_reference_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_rest_mut(&mut self, i: &mut crate::PatRest) { - visit_pat_rest_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_slice_mut(&mut self, i: &mut crate::PatSlice) { - visit_pat_slice_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_struct_mut(&mut self, i: &mut crate::PatStruct) { - visit_pat_struct_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_tuple_mut(&mut self, i: &mut crate::PatTuple) { - visit_pat_tuple_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_tuple_struct_mut(&mut self, i: &mut crate::PatTupleStruct) { - visit_pat_tuple_struct_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_type_mut(&mut self, i: &mut crate::PatType) { - visit_pat_type_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pat_wild_mut(&mut self, i: &mut crate::PatWild) { - visit_pat_wild_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_path_mut(&mut self, i: &mut crate::Path) { - visit_path_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_path_arguments_mut(&mut self, i: &mut crate::PathArguments) { - visit_path_arguments_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_path_segment_mut(&mut self, i: &mut crate::PathSegment) { - visit_path_segment_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_pointer_mutability_mut(&mut self, i: &mut crate::PointerMutability) { - visit_pointer_mutability_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_precise_capture_mut(&mut self, i: &mut crate::PreciseCapture) { - visit_precise_capture_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_predicate_lifetime_mut(&mut self, i: &mut crate::PredicateLifetime) { - visit_predicate_lifetime_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_predicate_type_mut(&mut self, i: &mut crate::PredicateType) { - visit_predicate_type_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_qself_mut(&mut self, i: &mut crate::QSelf) { - visit_qself_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_range_limits_mut(&mut self, i: &mut crate::RangeLimits) { - visit_range_limits_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_receiver_mut(&mut self, i: &mut crate::Receiver) { - visit_receiver_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_return_type_mut(&mut self, i: &mut crate::ReturnType) { - visit_return_type_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_signature_mut(&mut self, i: &mut crate::Signature) { - visit_signature_mut(self, i); - } - fn visit_span_mut(&mut self, i: &mut proc_macro2::Span) {} - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_static_mutability_mut(&mut self, i: &mut crate::StaticMutability) { - visit_static_mutability_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_stmt_mut(&mut self, i: &mut crate::Stmt) { - visit_stmt_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_stmt_macro_mut(&mut self, i: &mut crate::StmtMacro) { - visit_stmt_macro_mut(self, i); - } - fn visit_token_stream_mut(&mut self, i: &mut proc_macro2::TokenStream) {} - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_trait_bound_mut(&mut self, i: &mut crate::TraitBound) { - visit_trait_bound_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_trait_bound_modifier_mut(&mut self, i: &mut crate::TraitBoundModifier) { - visit_trait_bound_modifier_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_mut(&mut self, i: &mut crate::TraitItem) { - visit_trait_item_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_const_mut(&mut self, i: &mut crate::TraitItemConst) { - visit_trait_item_const_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_fn_mut(&mut self, i: &mut crate::TraitItemFn) { - visit_trait_item_fn_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_macro_mut(&mut self, i: &mut crate::TraitItemMacro) { - visit_trait_item_macro_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_trait_item_type_mut(&mut self, i: &mut crate::TraitItemType) { - visit_trait_item_type_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_mut(&mut self, i: &mut crate::Type) { - visit_type_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_array_mut(&mut self, i: &mut crate::TypeArray) { - visit_type_array_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_bare_fn_mut(&mut self, i: &mut crate::TypeBareFn) { - visit_type_bare_fn_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_group_mut(&mut self, i: &mut crate::TypeGroup) { - visit_type_group_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_impl_trait_mut(&mut self, i: &mut crate::TypeImplTrait) { - visit_type_impl_trait_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_infer_mut(&mut self, i: &mut crate::TypeInfer) { - visit_type_infer_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_macro_mut(&mut self, i: &mut crate::TypeMacro) { - visit_type_macro_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_never_mut(&mut self, i: &mut crate::TypeNever) { - visit_type_never_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_param_mut(&mut self, i: &mut crate::TypeParam) { - visit_type_param_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_param_bound_mut(&mut self, i: &mut crate::TypeParamBound) { - visit_type_param_bound_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_paren_mut(&mut self, i: &mut crate::TypeParen) { - visit_type_paren_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_path_mut(&mut self, i: &mut crate::TypePath) { - visit_type_path_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_ptr_mut(&mut self, i: &mut crate::TypePtr) { - visit_type_ptr_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_reference_mut(&mut self, i: &mut crate::TypeReference) { - visit_type_reference_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_slice_mut(&mut self, i: &mut crate::TypeSlice) { - visit_type_slice_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_trait_object_mut(&mut self, i: &mut crate::TypeTraitObject) { - visit_type_trait_object_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_type_tuple_mut(&mut self, i: &mut crate::TypeTuple) { - visit_type_tuple_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_un_op_mut(&mut self, i: &mut crate::UnOp) { - visit_un_op_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_glob_mut(&mut self, i: &mut crate::UseGlob) { - visit_use_glob_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_group_mut(&mut self, i: &mut crate::UseGroup) { - visit_use_group_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_name_mut(&mut self, i: &mut crate::UseName) { - visit_use_name_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_path_mut(&mut self, i: &mut crate::UsePath) { - visit_use_path_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_rename_mut(&mut self, i: &mut crate::UseRename) { - visit_use_rename_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_use_tree_mut(&mut self, i: &mut crate::UseTree) { - visit_use_tree_mut(self, i); - } - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - fn visit_variadic_mut(&mut self, i: &mut crate::Variadic) { - visit_variadic_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_variant_mut(&mut self, i: &mut crate::Variant) { - visit_variant_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_vis_restricted_mut(&mut self, i: &mut crate::VisRestricted) { - visit_vis_restricted_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_visibility_mut(&mut self, i: &mut crate::Visibility) { - visit_visibility_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_where_clause_mut(&mut self, i: &mut crate::WhereClause) { - visit_where_clause_mut(self, i); - } - #[cfg(any(feature = "derive", feature = "full"))] - #[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] - fn visit_where_predicate_mut(&mut self, i: &mut crate::WherePredicate) { - visit_where_predicate_mut(self, i); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_abi_mut<V>(v: &mut V, node: &mut crate::Abi) -where - V: VisitMut + ?Sized, -{ - skip!(node.extern_token); - if let Some(it) = &mut node.name { - v.visit_lit_str_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_angle_bracketed_generic_arguments_mut<V>( - v: &mut V, - node: &mut crate::AngleBracketedGenericArguments, -) -where - V: VisitMut + ?Sized, -{ - skip!(node.colon2_token); - skip!(node.lt_token); - for mut el in Punctuated::pairs_mut(&mut node.args) { - let it = el.value_mut(); - v.visit_generic_argument_mut(it); - } - skip!(node.gt_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_arm_mut<V>(v: &mut V, node: &mut crate::Arm) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_pat_mut(&mut node.pat); - if let Some(it) = &mut node.guard { - skip!((it).0); - v.visit_expr_mut(&mut *(it).1); - } - skip!(node.fat_arrow_token); - v.visit_expr_mut(&mut *node.body); - skip!(node.comma); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_assoc_const_mut<V>(v: &mut V, node: &mut crate::AssocConst) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); - if let Some(it) = &mut node.generics { - v.visit_angle_bracketed_generic_arguments_mut(it); - } - skip!(node.eq_token); - v.visit_expr_mut(&mut node.value); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_assoc_type_mut<V>(v: &mut V, node: &mut crate::AssocType) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); - if let Some(it) = &mut node.generics { - v.visit_angle_bracketed_generic_arguments_mut(it); - } - skip!(node.eq_token); - v.visit_type_mut(&mut node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_attr_style_mut<V>(v: &mut V, node: &mut crate::AttrStyle) -where - V: VisitMut + ?Sized, -{ - match node { - crate::AttrStyle::Outer => {} - crate::AttrStyle::Inner(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_attribute_mut<V>(v: &mut V, node: &mut crate::Attribute) -where - V: VisitMut + ?Sized, -{ - skip!(node.pound_token); - v.visit_attr_style_mut(&mut node.style); - skip!(node.bracket_token); - v.visit_meta_mut(&mut node.meta); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bare_fn_arg_mut<V>(v: &mut V, node: &mut crate::BareFnArg) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.name { - v.visit_ident_mut(&mut (it).0); - skip!((it).1); - } - v.visit_type_mut(&mut node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bare_variadic_mut<V>(v: &mut V, node: &mut crate::BareVariadic) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.name { - v.visit_ident_mut(&mut (it).0); - skip!((it).1); - } - skip!(node.dots); - skip!(node.comma); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bin_op_mut<V>(v: &mut V, node: &mut crate::BinOp) -where - V: VisitMut + ?Sized, -{ - match node { - crate::BinOp::Add(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Sub(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Mul(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Div(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Rem(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::And(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Or(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitXor(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitAnd(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitOr(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Shl(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Shr(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Eq(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Lt(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Le(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Ne(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Ge(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::Gt(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::AddAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::SubAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::MulAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::DivAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::RemAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitXorAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitAndAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::BitOrAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::ShlAssign(_binding_0) => { - skip!(_binding_0); - } - crate::BinOp::ShrAssign(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_block_mut<V>(v: &mut V, node: &mut crate::Block) -where - V: VisitMut + ?Sized, -{ - skip!(node.brace_token); - for it in &mut node.stmts { - v.visit_stmt_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_bound_lifetimes_mut<V>(v: &mut V, node: &mut crate::BoundLifetimes) -where - V: VisitMut + ?Sized, -{ - skip!(node.for_token); - skip!(node.lt_token); - for mut el in Punctuated::pairs_mut(&mut node.lifetimes) { - let it = el.value_mut(); - v.visit_generic_param_mut(it); - } - skip!(node.gt_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_captured_param_mut<V>(v: &mut V, node: &mut crate::CapturedParam) -where - V: VisitMut + ?Sized, -{ - match node { - crate::CapturedParam::Lifetime(_binding_0) => { - v.visit_lifetime_mut(_binding_0); - } - crate::CapturedParam::Ident(_binding_0) => { - v.visit_ident_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_const_param_mut<V>(v: &mut V, node: &mut crate::ConstParam) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.const_token); - v.visit_ident_mut(&mut node.ident); - skip!(node.colon_token); - v.visit_type_mut(&mut node.ty); - skip!(node.eq_token); - if let Some(it) = &mut node.default { - v.visit_expr_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_constraint_mut<V>(v: &mut V, node: &mut crate::Constraint) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); - if let Some(it) = &mut node.generics { - v.visit_angle_bracketed_generic_arguments_mut(it); - } - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_mut<V>(v: &mut V, node: &mut crate::Data) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Data::Struct(_binding_0) => { - v.visit_data_struct_mut(_binding_0); - } - crate::Data::Enum(_binding_0) => { - v.visit_data_enum_mut(_binding_0); - } - crate::Data::Union(_binding_0) => { - v.visit_data_union_mut(_binding_0); - } - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_enum_mut<V>(v: &mut V, node: &mut crate::DataEnum) -where - V: VisitMut + ?Sized, -{ - skip!(node.enum_token); - skip!(node.brace_token); - for mut el in Punctuated::pairs_mut(&mut node.variants) { - let it = el.value_mut(); - v.visit_variant_mut(it); - } -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_struct_mut<V>(v: &mut V, node: &mut crate::DataStruct) -where - V: VisitMut + ?Sized, -{ - skip!(node.struct_token); - v.visit_fields_mut(&mut node.fields); - skip!(node.semi_token); -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_data_union_mut<V>(v: &mut V, node: &mut crate::DataUnion) -where - V: VisitMut + ?Sized, -{ - skip!(node.union_token); - v.visit_fields_named_mut(&mut node.fields); -} -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub fn visit_derive_input_mut<V>(v: &mut V, node: &mut crate::DeriveInput) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - v.visit_data_mut(&mut node.data); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_mut<V>(v: &mut V, node: &mut crate::Expr) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Expr::Array(_binding_0) => { - full!(v.visit_expr_array_mut(_binding_0)); - } - crate::Expr::Assign(_binding_0) => { - full!(v.visit_expr_assign_mut(_binding_0)); - } - crate::Expr::Async(_binding_0) => { - full!(v.visit_expr_async_mut(_binding_0)); - } - crate::Expr::Await(_binding_0) => { - full!(v.visit_expr_await_mut(_binding_0)); - } - crate::Expr::Binary(_binding_0) => { - v.visit_expr_binary_mut(_binding_0); - } - crate::Expr::Block(_binding_0) => { - full!(v.visit_expr_block_mut(_binding_0)); - } - crate::Expr::Break(_binding_0) => { - full!(v.visit_expr_break_mut(_binding_0)); - } - crate::Expr::Call(_binding_0) => { - v.visit_expr_call_mut(_binding_0); - } - crate::Expr::Cast(_binding_0) => { - v.visit_expr_cast_mut(_binding_0); - } - crate::Expr::Closure(_binding_0) => { - full!(v.visit_expr_closure_mut(_binding_0)); - } - crate::Expr::Const(_binding_0) => { - full!(v.visit_expr_const_mut(_binding_0)); - } - crate::Expr::Continue(_binding_0) => { - full!(v.visit_expr_continue_mut(_binding_0)); - } - crate::Expr::Field(_binding_0) => { - v.visit_expr_field_mut(_binding_0); - } - crate::Expr::ForLoop(_binding_0) => { - full!(v.visit_expr_for_loop_mut(_binding_0)); - } - crate::Expr::Group(_binding_0) => { - v.visit_expr_group_mut(_binding_0); - } - crate::Expr::If(_binding_0) => { - full!(v.visit_expr_if_mut(_binding_0)); - } - crate::Expr::Index(_binding_0) => { - v.visit_expr_index_mut(_binding_0); - } - crate::Expr::Infer(_binding_0) => { - full!(v.visit_expr_infer_mut(_binding_0)); - } - crate::Expr::Let(_binding_0) => { - full!(v.visit_expr_let_mut(_binding_0)); - } - crate::Expr::Lit(_binding_0) => { - v.visit_expr_lit_mut(_binding_0); - } - crate::Expr::Loop(_binding_0) => { - full!(v.visit_expr_loop_mut(_binding_0)); - } - crate::Expr::Macro(_binding_0) => { - v.visit_expr_macro_mut(_binding_0); - } - crate::Expr::Match(_binding_0) => { - full!(v.visit_expr_match_mut(_binding_0)); - } - crate::Expr::MethodCall(_binding_0) => { - v.visit_expr_method_call_mut(_binding_0); - } - crate::Expr::Paren(_binding_0) => { - v.visit_expr_paren_mut(_binding_0); - } - crate::Expr::Path(_binding_0) => { - v.visit_expr_path_mut(_binding_0); - } - crate::Expr::Range(_binding_0) => { - full!(v.visit_expr_range_mut(_binding_0)); - } - crate::Expr::RawAddr(_binding_0) => { - full!(v.visit_expr_raw_addr_mut(_binding_0)); - } - crate::Expr::Reference(_binding_0) => { - v.visit_expr_reference_mut(_binding_0); - } - crate::Expr::Repeat(_binding_0) => { - full!(v.visit_expr_repeat_mut(_binding_0)); - } - crate::Expr::Return(_binding_0) => { - full!(v.visit_expr_return_mut(_binding_0)); - } - crate::Expr::Struct(_binding_0) => { - v.visit_expr_struct_mut(_binding_0); - } - crate::Expr::Try(_binding_0) => { - full!(v.visit_expr_try_mut(_binding_0)); - } - crate::Expr::TryBlock(_binding_0) => { - full!(v.visit_expr_try_block_mut(_binding_0)); - } - crate::Expr::Tuple(_binding_0) => { - v.visit_expr_tuple_mut(_binding_0); - } - crate::Expr::Unary(_binding_0) => { - v.visit_expr_unary_mut(_binding_0); - } - crate::Expr::Unsafe(_binding_0) => { - full!(v.visit_expr_unsafe_mut(_binding_0)); - } - crate::Expr::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - crate::Expr::While(_binding_0) => { - full!(v.visit_expr_while_mut(_binding_0)); - } - crate::Expr::Yield(_binding_0) => { - full!(v.visit_expr_yield_mut(_binding_0)); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_array_mut<V>(v: &mut V, node: &mut crate::ExprArray) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.bracket_token); - for mut el in Punctuated::pairs_mut(&mut node.elems) { - let it = el.value_mut(); - v.visit_expr_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_assign_mut<V>(v: &mut V, node: &mut crate::ExprAssign) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.left); - skip!(node.eq_token); - v.visit_expr_mut(&mut *node.right); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_async_mut<V>(v: &mut V, node: &mut crate::ExprAsync) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.async_token); - skip!(node.capture); - v.visit_block_mut(&mut node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_await_mut<V>(v: &mut V, node: &mut crate::ExprAwait) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.base); - skip!(node.dot_token); - skip!(node.await_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut crate::ExprBinary) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.left); - v.visit_bin_op_mut(&mut node.op); - v.visit_expr_mut(&mut *node.right); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_block_mut<V>(v: &mut V, node: &mut crate::ExprBlock) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.label { - v.visit_label_mut(it); - } - v.visit_block_mut(&mut node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_break_mut<V>(v: &mut V, node: &mut crate::ExprBreak) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.break_token); - if let Some(it) = &mut node.label { - v.visit_lifetime_mut(it); - } - if let Some(it) = &mut node.expr { - v.visit_expr_mut(&mut **it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_call_mut<V>(v: &mut V, node: &mut crate::ExprCall) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.func); - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.args) { - let it = el.value_mut(); - v.visit_expr_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_cast_mut<V>(v: &mut V, node: &mut crate::ExprCast) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.expr); - skip!(node.as_token); - v.visit_type_mut(&mut *node.ty); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_closure_mut<V>(v: &mut V, node: &mut crate::ExprClosure) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.lifetimes { - v.visit_bound_lifetimes_mut(it); - } - skip!(node.constness); - skip!(node.movability); - skip!(node.asyncness); - skip!(node.capture); - skip!(node.or1_token); - for mut el in Punctuated::pairs_mut(&mut node.inputs) { - let it = el.value_mut(); - v.visit_pat_mut(it); - } - skip!(node.or2_token); - v.visit_return_type_mut(&mut node.output); - v.visit_expr_mut(&mut *node.body); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_const_mut<V>(v: &mut V, node: &mut crate::ExprConst) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.const_token); - v.visit_block_mut(&mut node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_continue_mut<V>(v: &mut V, node: &mut crate::ExprContinue) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.continue_token); - if let Some(it) = &mut node.label { - v.visit_lifetime_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_field_mut<V>(v: &mut V, node: &mut crate::ExprField) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.base); - skip!(node.dot_token); - v.visit_member_mut(&mut node.member); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_for_loop_mut<V>(v: &mut V, node: &mut crate::ExprForLoop) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.label { - v.visit_label_mut(it); - } - skip!(node.for_token); - v.visit_pat_mut(&mut *node.pat); - skip!(node.in_token); - v.visit_expr_mut(&mut *node.expr); - v.visit_block_mut(&mut node.body); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_group_mut<V>(v: &mut V, node: &mut crate::ExprGroup) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.group_token); - v.visit_expr_mut(&mut *node.expr); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_if_mut<V>(v: &mut V, node: &mut crate::ExprIf) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.if_token); - v.visit_expr_mut(&mut *node.cond); - v.visit_block_mut(&mut node.then_branch); - if let Some(it) = &mut node.else_branch { - skip!((it).0); - v.visit_expr_mut(&mut *(it).1); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_index_mut<V>(v: &mut V, node: &mut crate::ExprIndex) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.expr); - skip!(node.bracket_token); - v.visit_expr_mut(&mut *node.index); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_infer_mut<V>(v: &mut V, node: &mut crate::ExprInfer) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.underscore_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_let_mut<V>(v: &mut V, node: &mut crate::ExprLet) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.let_token); - v.visit_pat_mut(&mut *node.pat); - skip!(node.eq_token); - v.visit_expr_mut(&mut *node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_lit_mut<V>(v: &mut V, node: &mut crate::ExprLit) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_lit_mut(&mut node.lit); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_loop_mut<V>(v: &mut V, node: &mut crate::ExprLoop) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.label { - v.visit_label_mut(it); - } - skip!(node.loop_token); - v.visit_block_mut(&mut node.body); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_macro_mut<V>(v: &mut V, node: &mut crate::ExprMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_macro_mut(&mut node.mac); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_match_mut<V>(v: &mut V, node: &mut crate::ExprMatch) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.match_token); - v.visit_expr_mut(&mut *node.expr); - skip!(node.brace_token); - for it in &mut node.arms { - v.visit_arm_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_method_call_mut<V>(v: &mut V, node: &mut crate::ExprMethodCall) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.receiver); - skip!(node.dot_token); - v.visit_ident_mut(&mut node.method); - if let Some(it) = &mut node.turbofish { - v.visit_angle_bracketed_generic_arguments_mut(it); - } - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.args) { - let it = el.value_mut(); - v.visit_expr_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_paren_mut<V>(v: &mut V, node: &mut crate::ExprParen) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.paren_token); - v.visit_expr_mut(&mut *node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_path_mut<V>(v: &mut V, node: &mut crate::ExprPath) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.qself { - v.visit_qself_mut(it); - } - v.visit_path_mut(&mut node.path); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_range_mut<V>(v: &mut V, node: &mut crate::ExprRange) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.start { - v.visit_expr_mut(&mut **it); - } - v.visit_range_limits_mut(&mut node.limits); - if let Some(it) = &mut node.end { - v.visit_expr_mut(&mut **it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_raw_addr_mut<V>(v: &mut V, node: &mut crate::ExprRawAddr) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.and_token); - skip!(node.raw); - v.visit_pointer_mutability_mut(&mut node.mutability); - v.visit_expr_mut(&mut *node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_reference_mut<V>(v: &mut V, node: &mut crate::ExprReference) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.and_token); - skip!(node.mutability); - v.visit_expr_mut(&mut *node.expr); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_repeat_mut<V>(v: &mut V, node: &mut crate::ExprRepeat) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.bracket_token); - v.visit_expr_mut(&mut *node.expr); - skip!(node.semi_token); - v.visit_expr_mut(&mut *node.len); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_return_mut<V>(v: &mut V, node: &mut crate::ExprReturn) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.return_token); - if let Some(it) = &mut node.expr { - v.visit_expr_mut(&mut **it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_struct_mut<V>(v: &mut V, node: &mut crate::ExprStruct) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.qself { - v.visit_qself_mut(it); - } - v.visit_path_mut(&mut node.path); - skip!(node.brace_token); - for mut el in Punctuated::pairs_mut(&mut node.fields) { - let it = el.value_mut(); - v.visit_field_value_mut(it); - } - skip!(node.dot2_token); - if let Some(it) = &mut node.rest { - v.visit_expr_mut(&mut **it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_try_mut<V>(v: &mut V, node: &mut crate::ExprTry) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_expr_mut(&mut *node.expr); - skip!(node.question_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_try_block_mut<V>(v: &mut V, node: &mut crate::ExprTryBlock) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.try_token); - v.visit_block_mut(&mut node.block); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_tuple_mut<V>(v: &mut V, node: &mut crate::ExprTuple) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.elems) { - let it = el.value_mut(); - v.visit_expr_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_expr_unary_mut<V>(v: &mut V, node: &mut crate::ExprUnary) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_un_op_mut(&mut node.op); - v.visit_expr_mut(&mut *node.expr); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_unsafe_mut<V>(v: &mut V, node: &mut crate::ExprUnsafe) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.unsafe_token); - v.visit_block_mut(&mut node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_while_mut<V>(v: &mut V, node: &mut crate::ExprWhile) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.label { - v.visit_label_mut(it); - } - skip!(node.while_token); - v.visit_expr_mut(&mut *node.cond); - v.visit_block_mut(&mut node.body); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_expr_yield_mut<V>(v: &mut V, node: &mut crate::ExprYield) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.yield_token); - if let Some(it) = &mut node.expr { - v.visit_expr_mut(&mut **it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_field_mut<V>(v: &mut V, node: &mut crate::Field) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - v.visit_field_mutability_mut(&mut node.mutability); - if let Some(it) = &mut node.ident { - v.visit_ident_mut(it); - } - skip!(node.colon_token); - v.visit_type_mut(&mut node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_field_mutability_mut<V>(v: &mut V, node: &mut crate::FieldMutability) -where - V: VisitMut + ?Sized, -{ - match node { - crate::FieldMutability::None => {} - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_field_pat_mut<V>(v: &mut V, node: &mut crate::FieldPat) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_member_mut(&mut node.member); - skip!(node.colon_token); - v.visit_pat_mut(&mut *node.pat); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_field_value_mut<V>(v: &mut V, node: &mut crate::FieldValue) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_member_mut(&mut node.member); - skip!(node.colon_token); - v.visit_expr_mut(&mut node.expr); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_fields_mut<V>(v: &mut V, node: &mut crate::Fields) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Fields::Named(_binding_0) => { - v.visit_fields_named_mut(_binding_0); - } - crate::Fields::Unnamed(_binding_0) => { - v.visit_fields_unnamed_mut(_binding_0); - } - crate::Fields::Unit => {} - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_fields_named_mut<V>(v: &mut V, node: &mut crate::FieldsNamed) -where - V: VisitMut + ?Sized, -{ - skip!(node.brace_token); - for mut el in Punctuated::pairs_mut(&mut node.named) { - let it = el.value_mut(); - v.visit_field_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_fields_unnamed_mut<V>(v: &mut V, node: &mut crate::FieldsUnnamed) -where - V: VisitMut + ?Sized, -{ - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.unnamed) { - let it = el.value_mut(); - v.visit_field_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_file_mut<V>(v: &mut V, node: &mut crate::File) -where - V: VisitMut + ?Sized, -{ - skip!(node.shebang); - v.visit_attributes_mut(&mut node.attrs); - for it in &mut node.items { - v.visit_item_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_fn_arg_mut<V>(v: &mut V, node: &mut crate::FnArg) -where - V: VisitMut + ?Sized, -{ - match node { - crate::FnArg::Receiver(_binding_0) => { - v.visit_receiver_mut(_binding_0); - } - crate::FnArg::Typed(_binding_0) => { - v.visit_pat_type_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_mut<V>(v: &mut V, node: &mut crate::ForeignItem) -where - V: VisitMut + ?Sized, -{ - match node { - crate::ForeignItem::Fn(_binding_0) => { - v.visit_foreign_item_fn_mut(_binding_0); - } - crate::ForeignItem::Static(_binding_0) => { - v.visit_foreign_item_static_mut(_binding_0); - } - crate::ForeignItem::Type(_binding_0) => { - v.visit_foreign_item_type_mut(_binding_0); - } - crate::ForeignItem::Macro(_binding_0) => { - v.visit_foreign_item_macro_mut(_binding_0); - } - crate::ForeignItem::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_fn_mut<V>(v: &mut V, node: &mut crate::ForeignItemFn) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - v.visit_signature_mut(&mut node.sig); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_macro_mut<V>(v: &mut V, node: &mut crate::ForeignItemMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_macro_mut(&mut node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_static_mut<V>(v: &mut V, node: &mut crate::ForeignItemStatic) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.static_token); - v.visit_static_mutability_mut(&mut node.mutability); - v.visit_ident_mut(&mut node.ident); - skip!(node.colon_token); - v.visit_type_mut(&mut *node.ty); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_foreign_item_type_mut<V>(v: &mut V, node: &mut crate::ForeignItemType) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.type_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.semi_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_generic_argument_mut<V>(v: &mut V, node: &mut crate::GenericArgument) -where - V: VisitMut + ?Sized, -{ - match node { - crate::GenericArgument::Lifetime(_binding_0) => { - v.visit_lifetime_mut(_binding_0); - } - crate::GenericArgument::Type(_binding_0) => { - v.visit_type_mut(_binding_0); - } - crate::GenericArgument::Const(_binding_0) => { - v.visit_expr_mut(_binding_0); - } - crate::GenericArgument::AssocType(_binding_0) => { - v.visit_assoc_type_mut(_binding_0); - } - crate::GenericArgument::AssocConst(_binding_0) => { - v.visit_assoc_const_mut(_binding_0); - } - crate::GenericArgument::Constraint(_binding_0) => { - v.visit_constraint_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_generic_param_mut<V>(v: &mut V, node: &mut crate::GenericParam) -where - V: VisitMut + ?Sized, -{ - match node { - crate::GenericParam::Lifetime(_binding_0) => { - v.visit_lifetime_param_mut(_binding_0); - } - crate::GenericParam::Type(_binding_0) => { - v.visit_type_param_mut(_binding_0); - } - crate::GenericParam::Const(_binding_0) => { - v.visit_const_param_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_generics_mut<V>(v: &mut V, node: &mut crate::Generics) -where - V: VisitMut + ?Sized, -{ - skip!(node.lt_token); - for mut el in Punctuated::pairs_mut(&mut node.params) { - let it = el.value_mut(); - v.visit_generic_param_mut(it); - } - skip!(node.gt_token); - if let Some(it) = &mut node.where_clause { - v.visit_where_clause_mut(it); - } -} -pub fn visit_ident_mut<V>(v: &mut V, node: &mut proc_macro2::Ident) -where - V: VisitMut + ?Sized, -{ - let mut span = node.span(); - v.visit_span_mut(&mut span); - node.set_span(span); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_mut<V>(v: &mut V, node: &mut crate::ImplItem) -where - V: VisitMut + ?Sized, -{ - match node { - crate::ImplItem::Const(_binding_0) => { - v.visit_impl_item_const_mut(_binding_0); - } - crate::ImplItem::Fn(_binding_0) => { - v.visit_impl_item_fn_mut(_binding_0); - } - crate::ImplItem::Type(_binding_0) => { - v.visit_impl_item_type_mut(_binding_0); - } - crate::ImplItem::Macro(_binding_0) => { - v.visit_impl_item_macro_mut(_binding_0); - } - crate::ImplItem::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_const_mut<V>(v: &mut V, node: &mut crate::ImplItemConst) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.defaultness); - skip!(node.const_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.colon_token); - v.visit_type_mut(&mut node.ty); - skip!(node.eq_token); - v.visit_expr_mut(&mut node.expr); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_fn_mut<V>(v: &mut V, node: &mut crate::ImplItemFn) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.defaultness); - v.visit_signature_mut(&mut node.sig); - v.visit_block_mut(&mut node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_macro_mut<V>(v: &mut V, node: &mut crate::ImplItemMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_macro_mut(&mut node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_item_type_mut<V>(v: &mut V, node: &mut crate::ImplItemType) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.defaultness); - skip!(node.type_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.eq_token); - v.visit_type_mut(&mut node.ty); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_impl_restriction_mut<V>(v: &mut V, node: &mut crate::ImplRestriction) -where - V: VisitMut + ?Sized, -{ - match *node {} -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_index_mut<V>(v: &mut V, node: &mut crate::Index) -where - V: VisitMut + ?Sized, -{ - skip!(node.index); - v.visit_span_mut(&mut node.span); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_mut<V>(v: &mut V, node: &mut crate::Item) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Item::Const(_binding_0) => { - v.visit_item_const_mut(_binding_0); - } - crate::Item::Enum(_binding_0) => { - v.visit_item_enum_mut(_binding_0); - } - crate::Item::ExternCrate(_binding_0) => { - v.visit_item_extern_crate_mut(_binding_0); - } - crate::Item::Fn(_binding_0) => { - v.visit_item_fn_mut(_binding_0); - } - crate::Item::ForeignMod(_binding_0) => { - v.visit_item_foreign_mod_mut(_binding_0); - } - crate::Item::Impl(_binding_0) => { - v.visit_item_impl_mut(_binding_0); - } - crate::Item::Macro(_binding_0) => { - v.visit_item_macro_mut(_binding_0); - } - crate::Item::Mod(_binding_0) => { - v.visit_item_mod_mut(_binding_0); - } - crate::Item::Static(_binding_0) => { - v.visit_item_static_mut(_binding_0); - } - crate::Item::Struct(_binding_0) => { - v.visit_item_struct_mut(_binding_0); - } - crate::Item::Trait(_binding_0) => { - v.visit_item_trait_mut(_binding_0); - } - crate::Item::TraitAlias(_binding_0) => { - v.visit_item_trait_alias_mut(_binding_0); - } - crate::Item::Type(_binding_0) => { - v.visit_item_type_mut(_binding_0); - } - crate::Item::Union(_binding_0) => { - v.visit_item_union_mut(_binding_0); - } - crate::Item::Use(_binding_0) => { - v.visit_item_use_mut(_binding_0); - } - crate::Item::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_const_mut<V>(v: &mut V, node: &mut crate::ItemConst) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.const_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.colon_token); - v.visit_type_mut(&mut *node.ty); - skip!(node.eq_token); - v.visit_expr_mut(&mut *node.expr); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_enum_mut<V>(v: &mut V, node: &mut crate::ItemEnum) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.enum_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.brace_token); - for mut el in Punctuated::pairs_mut(&mut node.variants) { - let it = el.value_mut(); - v.visit_variant_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_extern_crate_mut<V>(v: &mut V, node: &mut crate::ItemExternCrate) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.extern_token); - skip!(node.crate_token); - v.visit_ident_mut(&mut node.ident); - if let Some(it) = &mut node.rename { - skip!((it).0); - v.visit_ident_mut(&mut (it).1); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_fn_mut<V>(v: &mut V, node: &mut crate::ItemFn) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - v.visit_signature_mut(&mut node.sig); - v.visit_block_mut(&mut *node.block); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_foreign_mod_mut<V>(v: &mut V, node: &mut crate::ItemForeignMod) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.unsafety); - v.visit_abi_mut(&mut node.abi); - skip!(node.brace_token); - for it in &mut node.items { - v.visit_foreign_item_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_impl_mut<V>(v: &mut V, node: &mut crate::ItemImpl) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.defaultness); - skip!(node.unsafety); - skip!(node.impl_token); - v.visit_generics_mut(&mut node.generics); - if let Some(it) = &mut node.trait_ { - skip!((it).0); - v.visit_path_mut(&mut (it).1); - skip!((it).2); - } - v.visit_type_mut(&mut *node.self_ty); - skip!(node.brace_token); - for it in &mut node.items { - v.visit_impl_item_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_macro_mut<V>(v: &mut V, node: &mut crate::ItemMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.ident { - v.visit_ident_mut(it); - } - v.visit_macro_mut(&mut node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_mod_mut<V>(v: &mut V, node: &mut crate::ItemMod) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.unsafety); - skip!(node.mod_token); - v.visit_ident_mut(&mut node.ident); - if let Some(it) = &mut node.content { - skip!((it).0); - for it in &mut (it).1 { - v.visit_item_mut(it); - } - } - skip!(node.semi); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_static_mut<V>(v: &mut V, node: &mut crate::ItemStatic) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.static_token); - v.visit_static_mutability_mut(&mut node.mutability); - v.visit_ident_mut(&mut node.ident); - skip!(node.colon_token); - v.visit_type_mut(&mut *node.ty); - skip!(node.eq_token); - v.visit_expr_mut(&mut *node.expr); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_struct_mut<V>(v: &mut V, node: &mut crate::ItemStruct) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.struct_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - v.visit_fields_mut(&mut node.fields); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_trait_mut<V>(v: &mut V, node: &mut crate::ItemTrait) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.unsafety); - skip!(node.auto_token); - if let Some(it) = &mut node.restriction { - v.visit_impl_restriction_mut(it); - } - skip!(node.trait_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.supertraits) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } - skip!(node.brace_token); - for it in &mut node.items { - v.visit_trait_item_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_trait_alias_mut<V>(v: &mut V, node: &mut crate::ItemTraitAlias) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.trait_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.eq_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_type_mut<V>(v: &mut V, node: &mut crate::ItemType) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.type_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.eq_token); - v.visit_type_mut(&mut *node.ty); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_union_mut<V>(v: &mut V, node: &mut crate::ItemUnion) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.union_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - v.visit_fields_named_mut(&mut node.fields); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_item_use_mut<V>(v: &mut V, node: &mut crate::ItemUse) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_visibility_mut(&mut node.vis); - skip!(node.use_token); - skip!(node.leading_colon); - v.visit_use_tree_mut(&mut node.tree); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_label_mut<V>(v: &mut V, node: &mut crate::Label) -where - V: VisitMut + ?Sized, -{ - v.visit_lifetime_mut(&mut node.name); - skip!(node.colon_token); -} -pub fn visit_lifetime_mut<V>(v: &mut V, node: &mut crate::Lifetime) -where - V: VisitMut + ?Sized, -{ - v.visit_span_mut(&mut node.apostrophe); - v.visit_ident_mut(&mut node.ident); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_lifetime_param_mut<V>(v: &mut V, node: &mut crate::LifetimeParam) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_lifetime_mut(&mut node.lifetime); - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_lifetime_mut(it); - } -} -pub fn visit_lit_mut<V>(v: &mut V, node: &mut crate::Lit) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Lit::Str(_binding_0) => { - v.visit_lit_str_mut(_binding_0); - } - crate::Lit::ByteStr(_binding_0) => { - v.visit_lit_byte_str_mut(_binding_0); - } - crate::Lit::CStr(_binding_0) => { - v.visit_lit_cstr_mut(_binding_0); - } - crate::Lit::Byte(_binding_0) => { - v.visit_lit_byte_mut(_binding_0); - } - crate::Lit::Char(_binding_0) => { - v.visit_lit_char_mut(_binding_0); - } - crate::Lit::Int(_binding_0) => { - v.visit_lit_int_mut(_binding_0); - } - crate::Lit::Float(_binding_0) => { - v.visit_lit_float_mut(_binding_0); - } - crate::Lit::Bool(_binding_0) => { - v.visit_lit_bool_mut(_binding_0); - } - crate::Lit::Verbatim(_binding_0) => { - skip!(_binding_0); - } - } -} -pub fn visit_lit_bool_mut<V>(v: &mut V, node: &mut crate::LitBool) -where - V: VisitMut + ?Sized, -{ - skip!(node.value); - v.visit_span_mut(&mut node.span); -} -pub fn visit_lit_byte_mut<V>(v: &mut V, node: &mut crate::LitByte) -where - V: VisitMut + ?Sized, -{} -pub fn visit_lit_byte_str_mut<V>(v: &mut V, node: &mut crate::LitByteStr) -where - V: VisitMut + ?Sized, -{} -pub fn visit_lit_cstr_mut<V>(v: &mut V, node: &mut crate::LitCStr) -where - V: VisitMut + ?Sized, -{} -pub fn visit_lit_char_mut<V>(v: &mut V, node: &mut crate::LitChar) -where - V: VisitMut + ?Sized, -{} -pub fn visit_lit_float_mut<V>(v: &mut V, node: &mut crate::LitFloat) -where - V: VisitMut + ?Sized, -{} -pub fn visit_lit_int_mut<V>(v: &mut V, node: &mut crate::LitInt) -where - V: VisitMut + ?Sized, -{} -pub fn visit_lit_str_mut<V>(v: &mut V, node: &mut crate::LitStr) -where - V: VisitMut + ?Sized, -{} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_local_mut<V>(v: &mut V, node: &mut crate::Local) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.let_token); - v.visit_pat_mut(&mut node.pat); - if let Some(it) = &mut node.init { - v.visit_local_init_mut(it); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_local_init_mut<V>(v: &mut V, node: &mut crate::LocalInit) -where - V: VisitMut + ?Sized, -{ - skip!(node.eq_token); - v.visit_expr_mut(&mut *node.expr); - if let Some(it) = &mut node.diverge { - skip!((it).0); - v.visit_expr_mut(&mut *(it).1); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_macro_mut<V>(v: &mut V, node: &mut crate::Macro) -where - V: VisitMut + ?Sized, -{ - v.visit_path_mut(&mut node.path); - skip!(node.bang_token); - v.visit_macro_delimiter_mut(&mut node.delimiter); - v.visit_token_stream_mut(&mut node.tokens); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_macro_delimiter_mut<V>(v: &mut V, node: &mut crate::MacroDelimiter) -where - V: VisitMut + ?Sized, -{ - match node { - crate::MacroDelimiter::Paren(_binding_0) => { - skip!(_binding_0); - } - crate::MacroDelimiter::Brace(_binding_0) => { - skip!(_binding_0); - } - crate::MacroDelimiter::Bracket(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_member_mut<V>(v: &mut V, node: &mut crate::Member) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Member::Named(_binding_0) => { - v.visit_ident_mut(_binding_0); - } - crate::Member::Unnamed(_binding_0) => { - v.visit_index_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_meta_mut<V>(v: &mut V, node: &mut crate::Meta) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Meta::Path(_binding_0) => { - v.visit_path_mut(_binding_0); - } - crate::Meta::List(_binding_0) => { - v.visit_meta_list_mut(_binding_0); - } - crate::Meta::NameValue(_binding_0) => { - v.visit_meta_name_value_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_meta_list_mut<V>(v: &mut V, node: &mut crate::MetaList) -where - V: VisitMut + ?Sized, -{ - v.visit_path_mut(&mut node.path); - v.visit_macro_delimiter_mut(&mut node.delimiter); - v.visit_token_stream_mut(&mut node.tokens); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_meta_name_value_mut<V>(v: &mut V, node: &mut crate::MetaNameValue) -where - V: VisitMut + ?Sized, -{ - v.visit_path_mut(&mut node.path); - skip!(node.eq_token); - v.visit_expr_mut(&mut node.value); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_parenthesized_generic_arguments_mut<V>( - v: &mut V, - node: &mut crate::ParenthesizedGenericArguments, -) -where - V: VisitMut + ?Sized, -{ - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.inputs) { - let it = el.value_mut(); - v.visit_type_mut(it); - } - v.visit_return_type_mut(&mut node.output); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_mut<V>(v: &mut V, node: &mut crate::Pat) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Pat::Const(_binding_0) => { - v.visit_expr_const_mut(_binding_0); - } - crate::Pat::Ident(_binding_0) => { - v.visit_pat_ident_mut(_binding_0); - } - crate::Pat::Lit(_binding_0) => { - v.visit_expr_lit_mut(_binding_0); - } - crate::Pat::Macro(_binding_0) => { - v.visit_expr_macro_mut(_binding_0); - } - crate::Pat::Or(_binding_0) => { - v.visit_pat_or_mut(_binding_0); - } - crate::Pat::Paren(_binding_0) => { - v.visit_pat_paren_mut(_binding_0); - } - crate::Pat::Path(_binding_0) => { - v.visit_expr_path_mut(_binding_0); - } - crate::Pat::Range(_binding_0) => { - v.visit_expr_range_mut(_binding_0); - } - crate::Pat::Reference(_binding_0) => { - v.visit_pat_reference_mut(_binding_0); - } - crate::Pat::Rest(_binding_0) => { - v.visit_pat_rest_mut(_binding_0); - } - crate::Pat::Slice(_binding_0) => { - v.visit_pat_slice_mut(_binding_0); - } - crate::Pat::Struct(_binding_0) => { - v.visit_pat_struct_mut(_binding_0); - } - crate::Pat::Tuple(_binding_0) => { - v.visit_pat_tuple_mut(_binding_0); - } - crate::Pat::TupleStruct(_binding_0) => { - v.visit_pat_tuple_struct_mut(_binding_0); - } - crate::Pat::Type(_binding_0) => { - v.visit_pat_type_mut(_binding_0); - } - crate::Pat::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - crate::Pat::Wild(_binding_0) => { - v.visit_pat_wild_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_ident_mut<V>(v: &mut V, node: &mut crate::PatIdent) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.by_ref); - skip!(node.mutability); - v.visit_ident_mut(&mut node.ident); - if let Some(it) = &mut node.subpat { - skip!((it).0); - v.visit_pat_mut(&mut *(it).1); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_or_mut<V>(v: &mut V, node: &mut crate::PatOr) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.leading_vert); - for mut el in Punctuated::pairs_mut(&mut node.cases) { - let it = el.value_mut(); - v.visit_pat_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_paren_mut<V>(v: &mut V, node: &mut crate::PatParen) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.paren_token); - v.visit_pat_mut(&mut *node.pat); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_reference_mut<V>(v: &mut V, node: &mut crate::PatReference) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.and_token); - skip!(node.mutability); - v.visit_pat_mut(&mut *node.pat); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_rest_mut<V>(v: &mut V, node: &mut crate::PatRest) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.dot2_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_slice_mut<V>(v: &mut V, node: &mut crate::PatSlice) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.bracket_token); - for mut el in Punctuated::pairs_mut(&mut node.elems) { - let it = el.value_mut(); - v.visit_pat_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_struct_mut<V>(v: &mut V, node: &mut crate::PatStruct) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.qself { - v.visit_qself_mut(it); - } - v.visit_path_mut(&mut node.path); - skip!(node.brace_token); - for mut el in Punctuated::pairs_mut(&mut node.fields) { - let it = el.value_mut(); - v.visit_field_pat_mut(it); - } - if let Some(it) = &mut node.rest { - v.visit_pat_rest_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_tuple_mut<V>(v: &mut V, node: &mut crate::PatTuple) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.elems) { - let it = el.value_mut(); - v.visit_pat_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_tuple_struct_mut<V>(v: &mut V, node: &mut crate::PatTupleStruct) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.qself { - v.visit_qself_mut(it); - } - v.visit_path_mut(&mut node.path); - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.elems) { - let it = el.value_mut(); - v.visit_pat_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_type_mut<V>(v: &mut V, node: &mut crate::PatType) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_pat_mut(&mut *node.pat); - skip!(node.colon_token); - v.visit_type_mut(&mut *node.ty); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pat_wild_mut<V>(v: &mut V, node: &mut crate::PatWild) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.underscore_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_path_mut<V>(v: &mut V, node: &mut crate::Path) -where - V: VisitMut + ?Sized, -{ - skip!(node.leading_colon); - for mut el in Punctuated::pairs_mut(&mut node.segments) { - let it = el.value_mut(); - v.visit_path_segment_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_path_arguments_mut<V>(v: &mut V, node: &mut crate::PathArguments) -where - V: VisitMut + ?Sized, -{ - match node { - crate::PathArguments::None => {} - crate::PathArguments::AngleBracketed(_binding_0) => { - v.visit_angle_bracketed_generic_arguments_mut(_binding_0); - } - crate::PathArguments::Parenthesized(_binding_0) => { - v.visit_parenthesized_generic_arguments_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_path_segment_mut<V>(v: &mut V, node: &mut crate::PathSegment) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); - v.visit_path_arguments_mut(&mut node.arguments); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_pointer_mutability_mut<V>(v: &mut V, node: &mut crate::PointerMutability) -where - V: VisitMut + ?Sized, -{ - match node { - crate::PointerMutability::Const(_binding_0) => { - skip!(_binding_0); - } - crate::PointerMutability::Mut(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_precise_capture_mut<V>(v: &mut V, node: &mut crate::PreciseCapture) -where - V: VisitMut + ?Sized, -{ - skip!(node.use_token); - skip!(node.lt_token); - for mut el in Punctuated::pairs_mut(&mut node.params) { - let it = el.value_mut(); - v.visit_captured_param_mut(it); - } - skip!(node.gt_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_predicate_lifetime_mut<V>(v: &mut V, node: &mut crate::PredicateLifetime) -where - V: VisitMut + ?Sized, -{ - v.visit_lifetime_mut(&mut node.lifetime); - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_lifetime_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_predicate_type_mut<V>(v: &mut V, node: &mut crate::PredicateType) -where - V: VisitMut + ?Sized, -{ - if let Some(it) = &mut node.lifetimes { - v.visit_bound_lifetimes_mut(it); - } - v.visit_type_mut(&mut node.bounded_ty); - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_qself_mut<V>(v: &mut V, node: &mut crate::QSelf) -where - V: VisitMut + ?Sized, -{ - skip!(node.lt_token); - v.visit_type_mut(&mut *node.ty); - skip!(node.position); - skip!(node.as_token); - skip!(node.gt_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_range_limits_mut<V>(v: &mut V, node: &mut crate::RangeLimits) -where - V: VisitMut + ?Sized, -{ - match node { - crate::RangeLimits::HalfOpen(_binding_0) => { - skip!(_binding_0); - } - crate::RangeLimits::Closed(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_receiver_mut<V>(v: &mut V, node: &mut crate::Receiver) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.reference { - skip!((it).0); - if let Some(it) = &mut (it).1 { - v.visit_lifetime_mut(it); - } - } - skip!(node.mutability); - skip!(node.self_token); - skip!(node.colon_token); - v.visit_type_mut(&mut *node.ty); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_return_type_mut<V>(v: &mut V, node: &mut crate::ReturnType) -where - V: VisitMut + ?Sized, -{ - match node { - crate::ReturnType::Default => {} - crate::ReturnType::Type(_binding_0, _binding_1) => { - skip!(_binding_0); - v.visit_type_mut(&mut **_binding_1); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_signature_mut<V>(v: &mut V, node: &mut crate::Signature) -where - V: VisitMut + ?Sized, -{ - skip!(node.constness); - skip!(node.asyncness); - skip!(node.unsafety); - if let Some(it) = &mut node.abi { - v.visit_abi_mut(it); - } - skip!(node.fn_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.inputs) { - let it = el.value_mut(); - v.visit_fn_arg_mut(it); - } - if let Some(it) = &mut node.variadic { - v.visit_variadic_mut(it); - } - v.visit_return_type_mut(&mut node.output); -} -pub fn visit_span_mut<V>(v: &mut V, node: &mut proc_macro2::Span) -where - V: VisitMut + ?Sized, -{} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_static_mutability_mut<V>(v: &mut V, node: &mut crate::StaticMutability) -where - V: VisitMut + ?Sized, -{ - match node { - crate::StaticMutability::Mut(_binding_0) => { - skip!(_binding_0); - } - crate::StaticMutability::None => {} - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_stmt_mut<V>(v: &mut V, node: &mut crate::Stmt) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Stmt::Local(_binding_0) => { - v.visit_local_mut(_binding_0); - } - crate::Stmt::Item(_binding_0) => { - v.visit_item_mut(_binding_0); - } - crate::Stmt::Expr(_binding_0, _binding_1) => { - v.visit_expr_mut(_binding_0); - skip!(_binding_1); - } - crate::Stmt::Macro(_binding_0) => { - v.visit_stmt_macro_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_stmt_macro_mut<V>(v: &mut V, node: &mut crate::StmtMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_macro_mut(&mut node.mac); - skip!(node.semi_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_trait_bound_mut<V>(v: &mut V, node: &mut crate::TraitBound) -where - V: VisitMut + ?Sized, -{ - skip!(node.paren_token); - v.visit_trait_bound_modifier_mut(&mut node.modifier); - if let Some(it) = &mut node.lifetimes { - v.visit_bound_lifetimes_mut(it); - } - v.visit_path_mut(&mut node.path); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_trait_bound_modifier_mut<V>(v: &mut V, node: &mut crate::TraitBoundModifier) -where - V: VisitMut + ?Sized, -{ - match node { - crate::TraitBoundModifier::None => {} - crate::TraitBoundModifier::Maybe(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_mut<V>(v: &mut V, node: &mut crate::TraitItem) -where - V: VisitMut + ?Sized, -{ - match node { - crate::TraitItem::Const(_binding_0) => { - v.visit_trait_item_const_mut(_binding_0); - } - crate::TraitItem::Fn(_binding_0) => { - v.visit_trait_item_fn_mut(_binding_0); - } - crate::TraitItem::Type(_binding_0) => { - v.visit_trait_item_type_mut(_binding_0); - } - crate::TraitItem::Macro(_binding_0) => { - v.visit_trait_item_macro_mut(_binding_0); - } - crate::TraitItem::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_const_mut<V>(v: &mut V, node: &mut crate::TraitItemConst) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.const_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.colon_token); - v.visit_type_mut(&mut node.ty); - if let Some(it) = &mut node.default { - skip!((it).0); - v.visit_expr_mut(&mut (it).1); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_fn_mut<V>(v: &mut V, node: &mut crate::TraitItemFn) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_signature_mut(&mut node.sig); - if let Some(it) = &mut node.default { - v.visit_block_mut(it); - } - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_macro_mut<V>(v: &mut V, node: &mut crate::TraitItemMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_macro_mut(&mut node.mac); - skip!(node.semi_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_trait_item_type_mut<V>(v: &mut V, node: &mut crate::TraitItemType) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - skip!(node.type_token); - v.visit_ident_mut(&mut node.ident); - v.visit_generics_mut(&mut node.generics); - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } - if let Some(it) = &mut node.default { - skip!((it).0); - v.visit_type_mut(&mut (it).1); - } - skip!(node.semi_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_mut<V>(v: &mut V, node: &mut crate::Type) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Type::Array(_binding_0) => { - v.visit_type_array_mut(_binding_0); - } - crate::Type::BareFn(_binding_0) => { - v.visit_type_bare_fn_mut(_binding_0); - } - crate::Type::Group(_binding_0) => { - v.visit_type_group_mut(_binding_0); - } - crate::Type::ImplTrait(_binding_0) => { - v.visit_type_impl_trait_mut(_binding_0); - } - crate::Type::Infer(_binding_0) => { - v.visit_type_infer_mut(_binding_0); - } - crate::Type::Macro(_binding_0) => { - v.visit_type_macro_mut(_binding_0); - } - crate::Type::Never(_binding_0) => { - v.visit_type_never_mut(_binding_0); - } - crate::Type::Paren(_binding_0) => { - v.visit_type_paren_mut(_binding_0); - } - crate::Type::Path(_binding_0) => { - v.visit_type_path_mut(_binding_0); - } - crate::Type::Ptr(_binding_0) => { - v.visit_type_ptr_mut(_binding_0); - } - crate::Type::Reference(_binding_0) => { - v.visit_type_reference_mut(_binding_0); - } - crate::Type::Slice(_binding_0) => { - v.visit_type_slice_mut(_binding_0); - } - crate::Type::TraitObject(_binding_0) => { - v.visit_type_trait_object_mut(_binding_0); - } - crate::Type::Tuple(_binding_0) => { - v.visit_type_tuple_mut(_binding_0); - } - crate::Type::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_array_mut<V>(v: &mut V, node: &mut crate::TypeArray) -where - V: VisitMut + ?Sized, -{ - skip!(node.bracket_token); - v.visit_type_mut(&mut *node.elem); - skip!(node.semi_token); - v.visit_expr_mut(&mut node.len); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_bare_fn_mut<V>(v: &mut V, node: &mut crate::TypeBareFn) -where - V: VisitMut + ?Sized, -{ - if let Some(it) = &mut node.lifetimes { - v.visit_bound_lifetimes_mut(it); - } - skip!(node.unsafety); - if let Some(it) = &mut node.abi { - v.visit_abi_mut(it); - } - skip!(node.fn_token); - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.inputs) { - let it = el.value_mut(); - v.visit_bare_fn_arg_mut(it); - } - if let Some(it) = &mut node.variadic { - v.visit_bare_variadic_mut(it); - } - v.visit_return_type_mut(&mut node.output); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_group_mut<V>(v: &mut V, node: &mut crate::TypeGroup) -where - V: VisitMut + ?Sized, -{ - skip!(node.group_token); - v.visit_type_mut(&mut *node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_impl_trait_mut<V>(v: &mut V, node: &mut crate::TypeImplTrait) -where - V: VisitMut + ?Sized, -{ - skip!(node.impl_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_infer_mut<V>(v: &mut V, node: &mut crate::TypeInfer) -where - V: VisitMut + ?Sized, -{ - skip!(node.underscore_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_macro_mut<V>(v: &mut V, node: &mut crate::TypeMacro) -where - V: VisitMut + ?Sized, -{ - v.visit_macro_mut(&mut node.mac); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_never_mut<V>(v: &mut V, node: &mut crate::TypeNever) -where - V: VisitMut + ?Sized, -{ - skip!(node.bang_token); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_param_mut<V>(v: &mut V, node: &mut crate::TypeParam) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_ident_mut(&mut node.ident); - skip!(node.colon_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } - skip!(node.eq_token); - if let Some(it) = &mut node.default { - v.visit_type_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_param_bound_mut<V>(v: &mut V, node: &mut crate::TypeParamBound) -where - V: VisitMut + ?Sized, -{ - match node { - crate::TypeParamBound::Trait(_binding_0) => { - v.visit_trait_bound_mut(_binding_0); - } - crate::TypeParamBound::Lifetime(_binding_0) => { - v.visit_lifetime_mut(_binding_0); - } - crate::TypeParamBound::PreciseCapture(_binding_0) => { - full!(v.visit_precise_capture_mut(_binding_0)); - } - crate::TypeParamBound::Verbatim(_binding_0) => { - v.visit_token_stream_mut(_binding_0); - } - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_paren_mut<V>(v: &mut V, node: &mut crate::TypeParen) -where - V: VisitMut + ?Sized, -{ - skip!(node.paren_token); - v.visit_type_mut(&mut *node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_path_mut<V>(v: &mut V, node: &mut crate::TypePath) -where - V: VisitMut + ?Sized, -{ - if let Some(it) = &mut node.qself { - v.visit_qself_mut(it); - } - v.visit_path_mut(&mut node.path); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_ptr_mut<V>(v: &mut V, node: &mut crate::TypePtr) -where - V: VisitMut + ?Sized, -{ - skip!(node.star_token); - skip!(node.const_token); - skip!(node.mutability); - v.visit_type_mut(&mut *node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_reference_mut<V>(v: &mut V, node: &mut crate::TypeReference) -where - V: VisitMut + ?Sized, -{ - skip!(node.and_token); - if let Some(it) = &mut node.lifetime { - v.visit_lifetime_mut(it); - } - skip!(node.mutability); - v.visit_type_mut(&mut *node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_slice_mut<V>(v: &mut V, node: &mut crate::TypeSlice) -where - V: VisitMut + ?Sized, -{ - skip!(node.bracket_token); - v.visit_type_mut(&mut *node.elem); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_trait_object_mut<V>(v: &mut V, node: &mut crate::TypeTraitObject) -where - V: VisitMut + ?Sized, -{ - skip!(node.dyn_token); - for mut el in Punctuated::pairs_mut(&mut node.bounds) { - let it = el.value_mut(); - v.visit_type_param_bound_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_type_tuple_mut<V>(v: &mut V, node: &mut crate::TypeTuple) -where - V: VisitMut + ?Sized, -{ - skip!(node.paren_token); - for mut el in Punctuated::pairs_mut(&mut node.elems) { - let it = el.value_mut(); - v.visit_type_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_un_op_mut<V>(v: &mut V, node: &mut crate::UnOp) -where - V: VisitMut + ?Sized, -{ - match node { - crate::UnOp::Deref(_binding_0) => { - skip!(_binding_0); - } - crate::UnOp::Not(_binding_0) => { - skip!(_binding_0); - } - crate::UnOp::Neg(_binding_0) => { - skip!(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_glob_mut<V>(v: &mut V, node: &mut crate::UseGlob) -where - V: VisitMut + ?Sized, -{ - skip!(node.star_token); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_group_mut<V>(v: &mut V, node: &mut crate::UseGroup) -where - V: VisitMut + ?Sized, -{ - skip!(node.brace_token); - for mut el in Punctuated::pairs_mut(&mut node.items) { - let it = el.value_mut(); - v.visit_use_tree_mut(it); - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_name_mut<V>(v: &mut V, node: &mut crate::UseName) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_path_mut<V>(v: &mut V, node: &mut crate::UsePath) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); - skip!(node.colon2_token); - v.visit_use_tree_mut(&mut *node.tree); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_rename_mut<V>(v: &mut V, node: &mut crate::UseRename) -where - V: VisitMut + ?Sized, -{ - v.visit_ident_mut(&mut node.ident); - skip!(node.as_token); - v.visit_ident_mut(&mut node.rename); -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_use_tree_mut<V>(v: &mut V, node: &mut crate::UseTree) -where - V: VisitMut + ?Sized, -{ - match node { - crate::UseTree::Path(_binding_0) => { - v.visit_use_path_mut(_binding_0); - } - crate::UseTree::Name(_binding_0) => { - v.visit_use_name_mut(_binding_0); - } - crate::UseTree::Rename(_binding_0) => { - v.visit_use_rename_mut(_binding_0); - } - crate::UseTree::Glob(_binding_0) => { - v.visit_use_glob_mut(_binding_0); - } - crate::UseTree::Group(_binding_0) => { - v.visit_use_group_mut(_binding_0); - } - } -} -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub fn visit_variadic_mut<V>(v: &mut V, node: &mut crate::Variadic) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - if let Some(it) = &mut node.pat { - v.visit_pat_mut(&mut *(it).0); - skip!((it).1); - } - skip!(node.dots); - skip!(node.comma); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_variant_mut<V>(v: &mut V, node: &mut crate::Variant) -where - V: VisitMut + ?Sized, -{ - v.visit_attributes_mut(&mut node.attrs); - v.visit_ident_mut(&mut node.ident); - v.visit_fields_mut(&mut node.fields); - if let Some(it) = &mut node.discriminant { - skip!((it).0); - v.visit_expr_mut(&mut (it).1); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_vis_restricted_mut<V>(v: &mut V, node: &mut crate::VisRestricted) -where - V: VisitMut + ?Sized, -{ - skip!(node.pub_token); - skip!(node.paren_token); - skip!(node.in_token); - v.visit_path_mut(&mut *node.path); -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_visibility_mut<V>(v: &mut V, node: &mut crate::Visibility) -where - V: VisitMut + ?Sized, -{ - match node { - crate::Visibility::Public(_binding_0) => { - skip!(_binding_0); - } - crate::Visibility::Restricted(_binding_0) => { - v.visit_vis_restricted_mut(_binding_0); - } - crate::Visibility::Inherited => {} - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_where_clause_mut<V>(v: &mut V, node: &mut crate::WhereClause) -where - V: VisitMut + ?Sized, -{ - skip!(node.where_token); - for mut el in Punctuated::pairs_mut(&mut node.predicates) { - let it = el.value_mut(); - v.visit_where_predicate_mut(it); - } -} -#[cfg(any(feature = "derive", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "derive", feature = "full"))))] -pub fn visit_where_predicate_mut<V>(v: &mut V, node: &mut crate::WherePredicate) -where - V: VisitMut + ?Sized, -{ - match node { - crate::WherePredicate::Lifetime(_binding_0) => { - v.visit_predicate_lifetime_mut(_binding_0); - } - crate::WherePredicate::Type(_binding_0) => { - v.visit_predicate_type_mut(_binding_0); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/generics.rs b/deps/crates/vendor/syn-v2/src/generics.rs deleted file mode 100644 index 627437940f62..000000000000 --- a/deps/crates/vendor/syn-v2/src/generics.rs +++ /dev/null @@ -1,1420 +0,0 @@ -use crate::attr::Attribute; -use crate::expr::Expr; -use crate::ident::Ident; -use crate::lifetime::Lifetime; -use crate::path::Path; -use crate::punctuated::{Iter, IterMut, Punctuated}; -use crate::token; -use crate::ty::Type; -use alloc::vec::Vec; -#[cfg(all(feature = "printing", feature = "extra-traits"))] -use core::fmt::{self, Debug}; -#[cfg(all(feature = "printing", feature = "extra-traits"))] -use core::hash::{Hash, Hasher}; -use proc_macro2::TokenStream; - -ast_struct! { - /// Lifetimes and type parameters attached to a declaration of a function, - /// enum, trait, etc. - /// - /// This struct represents two distinct optional syntactic elements, - /// [generic parameters] and [where clause]. In some locations of the - /// grammar, there may be other tokens in between these two things. - /// - /// [generic parameters]: https://doc.rust-lang.org/stable/reference/items/generics.html#generic-parameters - /// [where clause]: https://doc.rust-lang.org/stable/reference/items/generics.html#where-clauses - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Generics { - pub lt_token: Option<Token![<]>, - pub params: Punctuated<GenericParam, Token![,]>, - pub gt_token: Option<Token![>]>, - pub where_clause: Option<WhereClause>, - } -} - -ast_enum_of_structs! { - /// A generic type parameter, lifetime, or const generic: `T: Into<String>`, - /// `'a: 'b`, `const LEN: usize`. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum GenericParam { - /// A lifetime parameter: `'a: 'b + 'c + 'd`. - Lifetime(LifetimeParam), - - /// A generic type parameter: `T: Into<String>`. - Type(TypeParam), - - /// A const generic parameter: `const LENGTH: usize`. - Const(ConstParam), - } -} - -ast_struct! { - /// A lifetime definition: `'a: 'b + 'c + 'd`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct LifetimeParam { - pub attrs: Vec<Attribute>, - pub lifetime: Lifetime, - pub colon_token: Option<Token![:]>, - pub bounds: Punctuated<Lifetime, Token![+]>, - } -} - -ast_struct! { - /// A generic type parameter: `T: Into<String>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeParam { - pub attrs: Vec<Attribute>, - pub ident: Ident, - pub colon_token: Option<Token![:]>, - pub bounds: Punctuated<TypeParamBound, Token![+]>, - pub eq_token: Option<Token![=]>, - pub default: Option<Type>, - } -} - -ast_struct! { - /// A const generic parameter: `const LENGTH: usize`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ConstParam { - pub attrs: Vec<Attribute>, - pub const_token: Token![const], - pub ident: Ident, - pub colon_token: Token![:], - pub ty: Type, - pub eq_token: Option<Token![=]>, - pub default: Option<Expr>, - } -} - -impl Default for Generics { - fn default() -> Self { - Generics { lt_token: None, params: Punctuated::new(), gt_token: None, where_clause: None } - } -} - -impl Generics { - return_impl_trait! { - /// Iterator over the lifetime parameters in `self.params`. - pub fn lifetimes(&self) -> impl Iterator<Item = &LifetimeParam> [Lifetimes] { - Lifetimes(self.params.iter()) - } - } - - return_impl_trait! { - /// Iterator over the lifetime parameters in `self.params`. - pub fn lifetimes_mut(&mut self) -> impl Iterator<Item = &mut LifetimeParam> [LifetimesMut] { - LifetimesMut(self.params.iter_mut()) - } - } - - return_impl_trait! { - /// Iterator over the type parameters in `self.params`. - pub fn type_params(&self) -> impl Iterator<Item = &TypeParam> [TypeParams] { - TypeParams(self.params.iter()) - } - } - - return_impl_trait! { - /// Iterator over the type parameters in `self.params`. - pub fn type_params_mut(&mut self) -> impl Iterator<Item = &mut TypeParam> [TypeParamsMut] { - TypeParamsMut(self.params.iter_mut()) - } - } - - return_impl_trait! { - /// Iterator over the constant parameters in `self.params`. - pub fn const_params(&self) -> impl Iterator<Item = &ConstParam> [ConstParams] { - ConstParams(self.params.iter()) - } - } - - return_impl_trait! { - /// Iterator over the constant parameters in `self.params`. - pub fn const_params_mut(&mut self) -> impl Iterator<Item = &mut ConstParam> [ConstParamsMut] { - ConstParamsMut(self.params.iter_mut()) - } - } - - /// Initializes an empty `where`-clause if there is not one present already. - pub fn make_where_clause(&mut self) -> &mut WhereClause { - self.where_clause.get_or_insert_with(|| WhereClause { - where_token: <Token![where]>::default(), - predicates: Punctuated::new(), - }) - } - - /// Split a type's generics into the pieces required for impl'ing a trait - /// for that type. - /// - /// ``` - /// # use proc_macro2::{Span, Ident}; - /// # use quote::quote; - /// # - /// # let generics: syn::Generics = Default::default(); - /// # let name = Ident::new("MyType", Span::call_site()); - /// # - /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - /// quote! { - /// impl #impl_generics MyTrait for #name #ty_generics #where_clause { - /// // ... - /// } - /// } - /// # ; - /// ``` - #[cfg(feature = "printing")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) { - (ImplGenerics(self), TypeGenerics(self), self.where_clause.as_ref()) - } -} - -pub struct Lifetimes<'a>(Iter<'a, GenericParam>); - -impl<'a> Iterator for Lifetimes<'a> { - type Item = &'a LifetimeParam; - - fn next(&mut self) -> Option<Self::Item> { - if let GenericParam::Lifetime(lifetime) = self.0.next()? { - Some(lifetime) - } else { - self.next() - } - } -} - -pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>); - -impl<'a> Iterator for LifetimesMut<'a> { - type Item = &'a mut LifetimeParam; - - fn next(&mut self) -> Option<Self::Item> { - if let GenericParam::Lifetime(lifetime) = self.0.next()? { - Some(lifetime) - } else { - self.next() - } - } -} - -pub struct TypeParams<'a>(Iter<'a, GenericParam>); - -impl<'a> Iterator for TypeParams<'a> { - type Item = &'a TypeParam; - - fn next(&mut self) -> Option<Self::Item> { - if let GenericParam::Type(type_param) = self.0.next()? { - Some(type_param) - } else { - self.next() - } - } -} - -pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>); - -impl<'a> Iterator for TypeParamsMut<'a> { - type Item = &'a mut TypeParam; - - fn next(&mut self) -> Option<Self::Item> { - if let GenericParam::Type(type_param) = self.0.next()? { - Some(type_param) - } else { - self.next() - } - } -} - -pub struct ConstParams<'a>(Iter<'a, GenericParam>); - -impl<'a> Iterator for ConstParams<'a> { - type Item = &'a ConstParam; - - fn next(&mut self) -> Option<Self::Item> { - if let GenericParam::Const(const_param) = self.0.next()? { - Some(const_param) - } else { - self.next() - } - } -} - -pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>); - -impl<'a> Iterator for ConstParamsMut<'a> { - type Item = &'a mut ConstParam; - - fn next(&mut self) -> Option<Self::Item> { - if let GenericParam::Const(const_param) = self.0.next()? { - Some(const_param) - } else { - self.next() - } - } -} - -/// Returned by `Generics::split_for_impl`. -#[cfg(feature = "printing")] -#[cfg_attr(docsrs, doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))))] -pub struct ImplGenerics<'a>(&'a Generics); - -/// Returned by `Generics::split_for_impl`. -#[cfg(feature = "printing")] -#[cfg_attr(docsrs, doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))))] -pub struct TypeGenerics<'a>(&'a Generics); - -/// Returned by `TypeGenerics::as_turbofish`. -#[cfg(feature = "printing")] -#[cfg_attr(docsrs, doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))))] -pub struct Turbofish<'a>(&'a Generics); - -#[cfg(feature = "printing")] -macro_rules! generics_wrapper_impls { - ($ty:ident) => { - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl<'a> Clone for $ty<'a> { - fn clone(&self) -> Self { - $ty(self.0) - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl<'a> Debug for $ty<'a> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.debug_tuple(stringify!($ty)).field(self.0).finish() - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl<'a> Eq for $ty<'a> {} - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl<'a> PartialEq for $ty<'a> { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl<'a> Hash for $ty<'a> { - fn hash<H: Hasher>(&self, state: &mut H) { - self.0.hash(state); - } - } - }; -} - -#[cfg(feature = "printing")] -generics_wrapper_impls!(ImplGenerics); -#[cfg(feature = "printing")] -generics_wrapper_impls!(TypeGenerics); -#[cfg(feature = "printing")] -generics_wrapper_impls!(Turbofish); - -#[cfg(feature = "printing")] -impl<'a> TypeGenerics<'a> { - /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`. - pub fn as_turbofish(&self) -> Turbofish<'a> { - Turbofish(self.0) - } -} - -ast_struct! { - /// A set of bound lifetimes: `for<'a, 'b, 'c>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct BoundLifetimes { - pub for_token: Token![for], - pub lt_token: Token![<], - pub lifetimes: Punctuated<GenericParam, Token![,]>, - pub gt_token: Token![>], - } -} - -impl Default for BoundLifetimes { - fn default() -> Self { - BoundLifetimes { - for_token: Default::default(), - lt_token: Default::default(), - lifetimes: Punctuated::new(), - gt_token: Default::default(), - } - } -} - -impl LifetimeParam { - pub fn new(lifetime: Lifetime) -> Self { - LifetimeParam { attrs: Vec::new(), lifetime, colon_token: None, bounds: Punctuated::new() } - } -} - -impl From<Ident> for TypeParam { - fn from(ident: Ident) -> Self { - TypeParam { - attrs: Vec::new(), - ident, - colon_token: None, - bounds: Punctuated::new(), - eq_token: None, - default: None, - } - } -} - -ast_enum_of_structs! { - /// A trait or lifetime used as a bound on a type parameter. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum TypeParamBound { - Trait(TraitBound), - Lifetime(Lifetime), - PreciseCapture(PreciseCapture), - Verbatim(TokenStream), - } -} - -ast_struct! { - /// A trait used as a bound on a type parameter. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TraitBound { - pub paren_token: Option<token::Paren>, - pub modifier: TraitBoundModifier, - /// The `for<'a>` in `for<'a> Foo<&'a T>` - pub lifetimes: Option<BoundLifetimes>, - /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>` - pub path: Path, - } -} - -ast_enum! { - /// A modifier on a trait bound, currently only used for the `?` in - /// `?Sized`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum TraitBoundModifier { - None, - Maybe(Token![?]), - } -} - -ast_struct! { - /// Precise capturing bound: the 'use<…>' in `impl Trait + - /// use<'a, T>`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PreciseCapture #full { - pub use_token: Token![use], - pub lt_token: Token![<], - pub params: Punctuated<CapturedParam, Token![,]>, - pub gt_token: Token![>], - } -} - -#[cfg(feature = "full")] -ast_enum! { - /// Single parameter in a precise capturing bound. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum CapturedParam { - /// A lifetime parameter in precise capturing bound: `fn f<'a>() -> impl - /// Trait + use<'a>`. - Lifetime(Lifetime), - /// A type parameter or const generic parameter in precise capturing - /// bound: `fn f<T>() -> impl Trait + use<T>` or `fn f<const K: T>() -> - /// impl Trait + use<K>`. - Ident(Ident), - } -} - -ast_struct! { - /// A `where` clause in a definition: `where T: Deserialize<'de>, D: - /// 'static`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct WhereClause { - pub where_token: Token![where], - pub predicates: Punctuated<WherePredicate, Token![,]>, - } -} - -ast_enum_of_structs! { - /// A single predicate in a `where` clause: `T: Deserialize<'de>`. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum WherePredicate { - /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. - Lifetime(PredicateLifetime), - - /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. - Type(PredicateType), - } -} - -ast_struct! { - /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct PredicateLifetime { - pub lifetime: Lifetime, - pub colon_token: Token![:], - pub bounds: Punctuated<Lifetime, Token![+]>, - } -} - -ast_struct! { - /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct PredicateType { - /// Any lifetimes from a `for` binding - pub lifetimes: Option<BoundLifetimes>, - /// The type being bounded - pub bounded_ty: Type, - pub colon_token: Token![:], - /// Trait and lifetime bounds (`Clone+Send+'static`) - pub bounds: Punctuated<TypeParamBound, Token![+]>, - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - #[cfg(feature = "full")] - use crate::error; - use crate::error::{Error, Result}; - use crate::ext::IdentExt as _; - use crate::generics::{ - BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime, - PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause, - WherePredicate, - }; - #[cfg(feature = "full")] - use crate::generics::{CapturedParam, PreciseCapture}; - use crate::ident::Ident; - use crate::lifetime::Lifetime; - use crate::parse::{Parse, ParseStream}; - use crate::path::{self, ParenthesizedGenericArguments, Path, PathArguments}; - use crate::punctuated::Punctuated; - use crate::token; - use crate::ty::Type; - use crate::verbatim; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Generics { - fn parse(input: ParseStream) -> Result<Self> { - if !input.peek(Token![<]) { - return Ok(Generics::default()); - } - - let lt_token: Token![<] = input.parse()?; - - let mut params = Punctuated::new(); - loop { - if input.peek(Token![>]) { - break; - } - - let attrs = input.call(Attribute::parse_outer)?; - let lookahead = input.lookahead1(); - if lookahead.peek(Lifetime) { - params.push_value(GenericParam::Lifetime(LifetimeParam { - attrs, - ..input.parse()? - })); - } else if lookahead.peek(Ident) { - params.push_value(GenericParam::Type(TypeParam { attrs, ..input.parse()? })); - } else if lookahead.peek(Token![const]) { - params.push_value(GenericParam::Const(ConstParam { attrs, ..input.parse()? })); - } else if input.peek(Token![_]) { - params.push_value(GenericParam::Type(TypeParam { - attrs, - ident: input.call(Ident::parse_any)?, - colon_token: None, - bounds: Punctuated::new(), - eq_token: None, - default: None, - })); - } else { - return Err(lookahead.error()); - } - - if input.peek(Token![>]) { - break; - } - let punct = input.parse()?; - params.push_punct(punct); - } - - let gt_token: Token![>] = input.parse()?; - - Ok(Generics { - lt_token: Some(lt_token), - params, - gt_token: Some(gt_token), - where_clause: None, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for GenericParam { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - - let lookahead = input.lookahead1(); - if lookahead.peek(Ident) { - Ok(GenericParam::Type(TypeParam { attrs, ..input.parse()? })) - } else if lookahead.peek(Lifetime) { - Ok(GenericParam::Lifetime(LifetimeParam { attrs, ..input.parse()? })) - } else if lookahead.peek(Token![const]) { - Ok(GenericParam::Const(ConstParam { attrs, ..input.parse()? })) - } else { - Err(lookahead.error()) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LifetimeParam { - fn parse(input: ParseStream) -> Result<Self> { - let has_colon; - Ok(LifetimeParam { - attrs: input.call(Attribute::parse_outer)?, - lifetime: input.parse()?, - colon_token: { - if input.peek(Token![:]) { - has_colon = true; - Some(input.parse()?) - } else { - has_colon = false; - None - } - }, - bounds: { - let mut bounds = Punctuated::new(); - if has_colon { - loop { - if input.is_empty() || input.peek(Token![,]) || input.peek(Token![>]) { - break; - } - let value = input.parse()?; - bounds.push_value(value); - if !input.peek(Token![+]) { - break; - } - let punct = input.parse()?; - bounds.push_punct(punct); - } - } - bounds - }, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for BoundLifetimes { - fn parse(input: ParseStream) -> Result<Self> { - Ok(BoundLifetimes { - for_token: input.parse()?, - lt_token: input.parse()?, - lifetimes: { - let mut lifetimes = Punctuated::new(); - while !input.peek(Token![>]) { - lifetimes.push_value(input.parse()?); - if input.peek(Token![>]) { - break; - } - lifetimes.push_punct(input.parse()?); - } - lifetimes - }, - gt_token: input.parse()?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Option<BoundLifetimes> { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Token![for]) { - input.parse().map(Some) - } else { - Ok(None) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeParam { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let ident: Ident = input.parse()?; - let colon_token: Option<Token![:]> = input.parse()?; - - let mut bounds = Punctuated::new(); - if colon_token.is_some() { - loop { - if input.is_empty() - || input.peek(Token![,]) - || input.peek(Token![>]) - || input.peek(Token![=]) - { - break; - } - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = true; - TypeParamBound::parse_single(input, allow_precise_capture, allow_const)? - }); - if !input.peek(Token![+]) { - break; - } - let punct: Token![+] = input.parse()?; - bounds.push_punct(punct); - } - } - - let eq_token: Option<Token![=]> = input.parse()?; - let default = if eq_token.is_some() { Some(input.parse::<Type>()?) } else { None }; - - Ok(TypeParam { attrs, ident, colon_token, bounds, eq_token, default }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeParamBound { - fn parse(input: ParseStream) -> Result<Self> { - let allow_precise_capture = true; - let allow_const = true; - Self::parse_single(input, allow_precise_capture, allow_const) - } - } - - impl TypeParamBound { - pub(crate) fn parse_single( - input: ParseStream, - #[cfg_attr(not(feature = "full"), allow(unused_variables))] allow_precise_capture: bool, - allow_const: bool, - ) -> Result<Self> { - if input.peek(Lifetime) { - return input.parse().map(TypeParamBound::Lifetime); - } - - #[cfg(feature = "full")] - { - if input.peek(Token![use]) { - let precise_capture: PreciseCapture = input.parse()?; - return if allow_precise_capture { - Ok(TypeParamBound::PreciseCapture(precise_capture)) - } else { - let msg = "`use<...>` precise capturing syntax is not allowed here"; - Err(error::new2( - precise_capture.use_token.span, - precise_capture.gt_token.span, - msg, - )) - }; - } - } - - let begin = input.cursor(); - - let content; - let (paren_token, content) = if input.peek(token::Paren) { - (Some(parenthesized!(content in input)), &content) - } else { - (None, input) - }; - - if let Some(mut bound) = TraitBound::do_parse(content, allow_const)? { - bound.paren_token = paren_token; - Ok(TypeParamBound::Trait(bound)) - } else { - Ok(TypeParamBound::Verbatim(verbatim::between(begin, input.cursor()))) - } - } - - pub(crate) fn parse_multiple( - input: ParseStream, - allow_plus: bool, - allow_precise_capture: bool, - allow_const: bool, - ) -> Result<Punctuated<Self, Token![+]>> { - let mut bounds = Punctuated::new(); - loop { - let bound = Self::parse_single(input, allow_precise_capture, allow_const)?; - bounds.push_value(bound); - if !(allow_plus && input.peek(Token![+])) { - break; - } - bounds.push_punct(input.parse()?); - if !(input.peek(Ident::peek_any) - || input.peek(Token![::]) - || input.peek(Token![?]) - || input.peek(Lifetime) - || input.peek(token::Paren) - || (allow_const && (input.peek(token::Bracket) || input.peek(Token![const])))) - { - break; - } - } - Ok(bounds) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitBound { - fn parse(input: ParseStream) -> Result<Self> { - let allow_const = false; - Self::do_parse(input, allow_const).map(Option::unwrap) - } - } - - impl TraitBound { - fn do_parse(input: ParseStream, allow_const: bool) -> Result<Option<Self>> { - let mut lifetimes: Option<BoundLifetimes> = input.parse()?; - - let is_conditionally_const = cfg!(feature = "full") && input.peek(token::Bracket); - let is_unconditionally_const = cfg!(feature = "full") && input.peek(Token![const]); - if is_conditionally_const { - let conditionally_const; - let bracket_token = bracketed!(conditionally_const in input); - conditionally_const.parse::<Token![const]>()?; - if !allow_const { - let msg = "`[const]` is not allowed here"; - return Err(Error::new(bracket_token.span.join(), msg)); - } - } else if is_unconditionally_const { - let const_token: Token![const] = input.parse()?; - if !allow_const { - let msg = "`const` is not allowed here"; - return Err(Error::new(const_token.span, msg)); - } - } - - let modifier: TraitBoundModifier = input.parse()?; - if lifetimes.is_none() && matches!(modifier, TraitBoundModifier::Maybe(_)) { - lifetimes = input.parse()?; - } - - let mut path: Path = input.parse()?; - if path.segments.last().unwrap().arguments.is_empty() - && (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren)) - { - input.parse::<Option<Token![::]>>()?; - let args: ParenthesizedGenericArguments = input.parse()?; - let parenthesized = PathArguments::Parenthesized(args); - path.segments.last_mut().unwrap().arguments = parenthesized; - } - - if lifetimes.is_some() { - match modifier { - TraitBoundModifier::None => {} - TraitBoundModifier::Maybe(maybe) => { - let msg = "`for<...>` binder not allowed with `?` trait polarity modifier"; - return Err(Error::new(maybe.span, msg)); - } - } - } - - if is_conditionally_const || is_unconditionally_const { - Ok(None) - } else { - Ok(Some(TraitBound { paren_token: None, modifier, lifetimes, path })) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitBoundModifier { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Token![?]) { - input.parse().map(TraitBoundModifier::Maybe) - } else { - Ok(TraitBoundModifier::None) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ConstParam { - fn parse(input: ParseStream) -> Result<Self> { - let mut default = None; - Ok(ConstParam { - attrs: input.call(Attribute::parse_outer)?, - const_token: input.parse()?, - ident: input.parse()?, - colon_token: input.parse()?, - ty: input.parse()?, - eq_token: { - if input.peek(Token![=]) { - let eq_token = input.parse()?; - default = Some(path::parsing::const_argument(input)?); - Some(eq_token) - } else { - None - } - }, - default, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for WhereClause { - fn parse(input: ParseStream) -> Result<Self> { - let where_token: Token![where] = input.parse()?; - - if choose_generics_over_qpath(input) { - return Err(input - .error("generic parameters on `where` clauses are reserved for future use")); - } - - Ok(WhereClause { - where_token, - predicates: { - let mut predicates = Punctuated::new(); - loop { - if input.is_empty() - || input.peek(token::Brace) - || input.peek(Token![,]) - || input.peek(Token![;]) - || input.peek(Token![:]) && !input.peek(Token![::]) - || input.peek(Token![=]) - { - break; - } - let value = input.parse()?; - predicates.push_value(value); - if !input.peek(Token![,]) { - break; - } - let punct = input.parse()?; - predicates.push_punct(punct); - } - predicates - }, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Option<WhereClause> { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Token![where]) { - input.parse().map(Some) - } else { - Ok(None) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for WherePredicate { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Lifetime) && input.peek2(Token![:]) { - Ok(WherePredicate::Lifetime(PredicateLifetime { - lifetime: input.parse()?, - colon_token: input.parse()?, - bounds: { - let mut bounds = Punctuated::new(); - loop { - if input.is_empty() - || input.peek(token::Brace) - || input.peek(Token![,]) - || input.peek(Token![;]) - || input.peek(Token![:]) - || input.peek(Token![=]) - { - break; - } - let value = input.parse()?; - bounds.push_value(value); - if !input.peek(Token![+]) { - break; - } - let punct = input.parse()?; - bounds.push_punct(punct); - } - bounds - }, - })) - } else { - Ok(WherePredicate::Type(PredicateType { - lifetimes: input.parse()?, - bounded_ty: input.parse()?, - colon_token: input.parse()?, - bounds: { - let mut bounds = Punctuated::new(); - loop { - if input.is_empty() - || input.peek(token::Brace) - || input.peek(Token![,]) - || input.peek(Token![;]) - || input.peek(Token![:]) && !input.peek(Token![::]) - || input.peek(Token![=]) - { - break; - } - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = true; - TypeParamBound::parse_single( - input, - allow_precise_capture, - allow_const, - )? - }); - if !input.peek(Token![+]) { - break; - } - let punct = input.parse()?; - bounds.push_punct(punct); - } - bounds - }, - })) - } - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for PreciseCapture { - fn parse(input: ParseStream) -> Result<Self> { - let use_token: Token![use] = input.parse()?; - let lt_token: Token![<] = input.parse()?; - let mut params = Punctuated::new(); - loop { - let lookahead = input.lookahead1(); - params.push_value( - if lookahead.peek(Lifetime) || lookahead.peek(Ident) || input.peek(Token![Self]) - { - input.parse::<CapturedParam>()? - } else if lookahead.peek(Token![>]) { - break; - } else { - return Err(lookahead.error()); - }, - ); - let lookahead = input.lookahead1(); - params.push_punct(if lookahead.peek(Token![,]) { - input.parse::<Token![,]>()? - } else if lookahead.peek(Token![>]) { - break; - } else { - return Err(lookahead.error()); - }); - } - let gt_token: Token![>] = input.parse()?; - Ok(PreciseCapture { use_token, lt_token, params, gt_token }) - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for CapturedParam { - fn parse(input: ParseStream) -> Result<Self> { - let lookahead = input.lookahead1(); - if lookahead.peek(Lifetime) { - input.parse().map(CapturedParam::Lifetime) - } else if lookahead.peek(Ident) || input.peek(Token![Self]) { - input.call(Ident::parse_any).map(CapturedParam::Ident) - } else { - Err(lookahead.error()) - } - } - } - - pub(crate) fn choose_generics_over_qpath(input: ParseStream) -> bool { - // Rust syntax has an ambiguity between generic parameters and qualified - // paths. In `impl <T> :: Thing<T, U> {}` this may either be a generic - // inherent impl `impl<T> ::Thing<T, U>` or a non-generic inherent impl - // for an associated type `impl <T>::Thing<T, U>`. - // - // After `<` the following continuations can only begin generics, not a - // qualified path: - // - // `<` `>` - empty generic parameters - // `<` `#` - generic parameters with attribute - // `<` LIFETIME `>` - single lifetime parameter - // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list - // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds - // `<` (LIFETIME|IDENT) `=` - generic parameter with a default - // `<` const - generic const parameter - // - // The only truly ambiguous case is: - // - // `<` IDENT `>` `::` IDENT ... - // - // which we disambiguate in favor of generics because this is almost - // always the expected one in the context of real-world code. - input.peek(Token![<]) - && (input.peek2(Token![>]) - || input.peek2(Token![#]) - || (input.peek2(Lifetime) || input.peek2(Ident)) - && (input.peek3(Token![>]) - || input.peek3(Token![,]) - || input.peek3(Token![:]) && !input.peek3(Token![::]) - || input.peek3(Token![=])) - || input.peek2(Token![const])) - } - - #[cfg(feature = "full")] - pub(crate) fn choose_generics_over_qpath_after_keyword(input: ParseStream) -> bool { - let input = input.fork(); - input.call(Ident::parse_any).unwrap(); // `impl` or `for` or `where` - choose_generics_over_qpath(&input) - } -} - -#[cfg(feature = "printing")] -pub(crate) mod printing { - use crate::attr::FilterAttrs; - #[cfg(feature = "full")] - use crate::expr; - use crate::expr::Expr; - #[cfg(feature = "full")] - use crate::fixup::FixupContext; - use crate::generics::{ - BoundLifetimes, ConstParam, GenericParam, Generics, ImplGenerics, LifetimeParam, - PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, Turbofish, TypeGenerics, - TypeParam, WhereClause, - }; - #[cfg(feature = "full")] - use crate::generics::{CapturedParam, PreciseCapture}; - use crate::print::TokensOrDefault; - use crate::token; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Generics { - fn to_tokens(&self, tokens: &mut TokenStream) { - if self.params.is_empty() { - return; - } - - TokensOrDefault(&self.lt_token).to_tokens(tokens); - - // Print lifetimes before types and consts, regardless of their - // order in self.params. - let mut trailing_or_empty = true; - for param in self.params.pairs() { - if let GenericParam::Lifetime(_) = **param.value() { - param.to_tokens(tokens); - trailing_or_empty = param.punct().is_some(); - } - } - for param in self.params.pairs() { - match param.value() { - GenericParam::Type(_) | GenericParam::Const(_) => { - if !trailing_or_empty { - <Token![,]>::default().to_tokens(tokens); - trailing_or_empty = true; - } - param.to_tokens(tokens); - } - GenericParam::Lifetime(_) => {} - } - } - - TokensOrDefault(&self.gt_token).to_tokens(tokens); - } - } - - impl<'a> ToTokens for ImplGenerics<'a> { - fn to_tokens(&self, tokens: &mut TokenStream) { - if self.0.params.is_empty() { - return; - } - - TokensOrDefault(&self.0.lt_token).to_tokens(tokens); - - // Print lifetimes before types and consts, regardless of their - // order in self.params. - let mut trailing_or_empty = true; - for param in self.0.params.pairs() { - if let GenericParam::Lifetime(_) = **param.value() { - param.to_tokens(tokens); - trailing_or_empty = param.punct().is_some(); - } - } - for param in self.0.params.pairs() { - if let GenericParam::Lifetime(_) = **param.value() { - continue; - } - if !trailing_or_empty { - <Token![,]>::default().to_tokens(tokens); - trailing_or_empty = true; - } - match param.value() { - GenericParam::Lifetime(_) => unreachable!(), - GenericParam::Type(param) => { - // Leave off the type parameter defaults - tokens.append_all(param.attrs.outer()); - param.ident.to_tokens(tokens); - if !param.bounds.is_empty() { - TokensOrDefault(¶m.colon_token).to_tokens(tokens); - param.bounds.to_tokens(tokens); - } - } - GenericParam::Const(param) => { - // Leave off the const parameter defaults - tokens.append_all(param.attrs.outer()); - param.const_token.to_tokens(tokens); - param.ident.to_tokens(tokens); - param.colon_token.to_tokens(tokens); - param.ty.to_tokens(tokens); - } - } - param.punct().to_tokens(tokens); - } - - TokensOrDefault(&self.0.gt_token).to_tokens(tokens); - } - } - - impl<'a> ToTokens for TypeGenerics<'a> { - fn to_tokens(&self, tokens: &mut TokenStream) { - if self.0.params.is_empty() { - return; - } - - TokensOrDefault(&self.0.lt_token).to_tokens(tokens); - - // Print lifetimes before types and consts, regardless of their - // order in self.params. - let mut trailing_or_empty = true; - for param in self.0.params.pairs() { - if let GenericParam::Lifetime(def) = *param.value() { - // Leave off the lifetime bounds and attributes - def.lifetime.to_tokens(tokens); - param.punct().to_tokens(tokens); - trailing_or_empty = param.punct().is_some(); - } - } - for param in self.0.params.pairs() { - if let GenericParam::Lifetime(_) = **param.value() { - continue; - } - if !trailing_or_empty { - <Token![,]>::default().to_tokens(tokens); - trailing_or_empty = true; - } - match param.value() { - GenericParam::Lifetime(_) => unreachable!(), - GenericParam::Type(param) => { - // Leave off the type parameter defaults - param.ident.to_tokens(tokens); - } - GenericParam::Const(param) => { - // Leave off the const parameter defaults - param.ident.to_tokens(tokens); - } - } - param.punct().to_tokens(tokens); - } - - TokensOrDefault(&self.0.gt_token).to_tokens(tokens); - } - } - - impl<'a> ToTokens for Turbofish<'a> { - fn to_tokens(&self, tokens: &mut TokenStream) { - if !self.0.params.is_empty() { - <Token![::]>::default().to_tokens(tokens); - TypeGenerics(self.0).to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for BoundLifetimes { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.for_token.to_tokens(tokens); - self.lt_token.to_tokens(tokens); - self.lifetimes.to_tokens(tokens); - self.gt_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LifetimeParam { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.lifetime.to_tokens(tokens); - if !self.bounds.is_empty() { - TokensOrDefault(&self.colon_token).to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeParam { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.ident.to_tokens(tokens); - if !self.bounds.is_empty() { - TokensOrDefault(&self.colon_token).to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - if let Some(default) = &self.default { - TokensOrDefault(&self.eq_token).to_tokens(tokens); - default.to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TraitBound { - fn to_tokens(&self, tokens: &mut TokenStream) { - let to_tokens = |tokens: &mut TokenStream| { - self.modifier.to_tokens(tokens); - self.lifetimes.to_tokens(tokens); - self.path.to_tokens(tokens); - }; - match &self.paren_token { - Some(paren) => paren.surround(tokens, to_tokens), - None => to_tokens(tokens), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TraitBoundModifier { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - TraitBoundModifier::None => {} - TraitBoundModifier::Maybe(t) => t.to_tokens(tokens), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ConstParam { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.const_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - if let Some(default) = &self.default { - TokensOrDefault(&self.eq_token).to_tokens(tokens); - print_const_argument(default, tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for WhereClause { - fn to_tokens(&self, tokens: &mut TokenStream) { - if !self.predicates.is_empty() { - self.where_token.to_tokens(tokens); - self.predicates.to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PredicateLifetime { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.lifetime.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PredicateType { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.lifetimes.to_tokens(tokens); - self.bounded_ty.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PreciseCapture { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.use_token.to_tokens(tokens); - self.lt_token.to_tokens(tokens); - - // Print lifetimes before types and consts, regardless of their - // order in self.params. - let mut trailing_or_empty = true; - for param in self.params.pairs() { - if let CapturedParam::Lifetime(_) = **param.value() { - param.to_tokens(tokens); - trailing_or_empty = param.punct().is_some(); - } - } - for param in self.params.pairs() { - if let CapturedParam::Ident(_) = **param.value() { - if !trailing_or_empty { - <Token![,]>::default().to_tokens(tokens); - trailing_or_empty = true; - } - param.to_tokens(tokens); - } - } - - self.gt_token.to_tokens(tokens); - } - } - - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for CapturedParam { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - CapturedParam::Lifetime(lifetime) => lifetime.to_tokens(tokens), - CapturedParam::Ident(ident) => ident.to_tokens(tokens), - } - } - } - - pub(crate) fn print_const_argument(expr: &Expr, tokens: &mut TokenStream) { - match expr { - Expr::Lit(expr) => expr.to_tokens(tokens), - - Expr::Path(expr) - if expr.attrs.is_empty() - && expr.qself.is_none() - && expr.path.get_ident().is_some() => - { - expr.to_tokens(tokens); - } - - #[cfg(feature = "full")] - Expr::Block(expr) => expr.to_tokens(tokens), - - #[cfg(not(feature = "full"))] - Expr::Verbatim(expr) => expr.to_tokens(tokens), - - // ERROR CORRECTION: Add braces to make sure that the - // generated code is valid. - _ => token::Brace::default().surround(tokens, |tokens| { - #[cfg(feature = "full")] - expr::printing::print_expr(expr, tokens, FixupContext::new_stmt()); - - #[cfg(not(feature = "full"))] - expr.to_tokens(tokens); - }), - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/group.rs b/deps/crates/vendor/syn-v2/src/group.rs deleted file mode 100644 index 56667b6a241c..000000000000 --- a/deps/crates/vendor/syn-v2/src/group.rs +++ /dev/null @@ -1,294 +0,0 @@ -use crate::error::Result; -use crate::parse::ParseBuffer; -use crate::token; -use proc_macro2::extra::DelimSpan; -use proc_macro2::Delimiter; - -// Not public API. -#[doc(hidden)] -pub struct Parens<'a> { - #[doc(hidden)] - pub token: token::Paren, - #[doc(hidden)] - pub content: ParseBuffer<'a>, -} - -// Not public API. -#[doc(hidden)] -pub struct Braces<'a> { - #[doc(hidden)] - pub token: token::Brace, - #[doc(hidden)] - pub content: ParseBuffer<'a>, -} - -// Not public API. -#[doc(hidden)] -pub struct Brackets<'a> { - #[doc(hidden)] - pub token: token::Bracket, - #[doc(hidden)] - pub content: ParseBuffer<'a>, -} - -// Not public API. -#[cfg(any(feature = "full", feature = "derive"))] -#[doc(hidden)] -pub struct Group<'a> { - #[doc(hidden)] - pub token: token::Group, - #[doc(hidden)] - pub content: ParseBuffer<'a>, -} - -// Not public API. -#[doc(hidden)] -pub fn parse_parens<'a>(input: &ParseBuffer<'a>) -> Result<Parens<'a>> { - parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens { - token: token::Paren(span), - content, - }) -} - -// Not public API. -#[doc(hidden)] -pub fn parse_braces<'a>(input: &ParseBuffer<'a>) -> Result<Braces<'a>> { - parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces { - token: token::Brace(span), - content, - }) -} - -// Not public API. -#[doc(hidden)] -pub fn parse_brackets<'a>(input: &ParseBuffer<'a>) -> Result<Brackets<'a>> { - parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets { - token: token::Bracket(span), - content, - }) -} - -#[cfg(any(feature = "full", feature = "derive"))] -pub(crate) fn parse_group<'a>(input: &ParseBuffer<'a>) -> Result<Group<'a>> { - parse_delimited(input, Delimiter::None).map(|(span, content)| Group { - token: token::Group(span.join()), - content, - }) -} - -fn parse_delimited<'a>( - input: &ParseBuffer<'a>, - delimiter: Delimiter, -) -> Result<(DelimSpan, ParseBuffer<'a>)> { - input.step(|cursor| { - if let Some((content, span, rest)) = cursor.group(delimiter) { - let scope = span.close(); - let nested = crate::parse::advance_step_cursor(cursor, content); - let unexpected = crate::parse::get_unexpected(input); - let content = crate::parse::new_parse_buffer(scope, nested, unexpected); - Ok(((span, content), rest)) - } else { - let message = match delimiter { - Delimiter::Parenthesis => "expected parentheses", - Delimiter::Brace => "expected curly braces", - Delimiter::Bracket => "expected square brackets", - Delimiter::None => "expected invisible group", - }; - Err(cursor.error(message)) - } - }) -} - -/// Parse a set of parentheses and expose their content to subsequent parsers. -/// -/// # Example -/// -/// ``` -/// # use quote::quote; -/// # -/// use syn::{parenthesized, token, Ident, Result, Token, Type}; -/// use syn::parse::{Parse, ParseStream}; -/// use syn::punctuated::Punctuated; -/// -/// // Parse a simplified tuple struct syntax like: -/// // -/// // struct S(A, B); -/// struct TupleStruct { -/// struct_token: Token![struct], -/// ident: Ident, -/// paren_token: token::Paren, -/// fields: Punctuated<Type, Token![,]>, -/// semi_token: Token![;], -/// } -/// -/// impl Parse for TupleStruct { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let content; -/// Ok(TupleStruct { -/// struct_token: input.parse()?, -/// ident: input.parse()?, -/// paren_token: parenthesized!(content in input), -/// fields: content.parse_terminated(Type::parse, Token![,])?, -/// semi_token: input.parse()?, -/// }) -/// } -/// } -/// # -/// # fn main() { -/// # let input = quote! { -/// # struct S(A, B); -/// # }; -/// # syn::parse2::<TupleStruct>(input).unwrap(); -/// # } -/// ``` -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -macro_rules! parenthesized { - ($content:ident in $cursor:expr) => { - match $crate::__private::parse_parens(&$cursor) { - $crate::__private::Ok(parens) => { - $content = parens.content; - _ = $content; - parens.token - } - $crate::__private::Err(error) => { - return $crate::__private::Err(error); - } - } - }; -} - -/// Parse a set of curly braces and expose their content to subsequent parsers. -/// -/// # Example -/// -/// ``` -/// # use quote::quote; -/// # -/// use syn::{braced, token, Ident, Result, Token, Type}; -/// use syn::parse::{Parse, ParseStream}; -/// use syn::punctuated::Punctuated; -/// -/// // Parse a simplified struct syntax like: -/// // -/// // struct S { -/// // a: A, -/// // b: B, -/// // } -/// struct Struct { -/// struct_token: Token![struct], -/// ident: Ident, -/// brace_token: token::Brace, -/// fields: Punctuated<Field, Token![,]>, -/// } -/// -/// struct Field { -/// name: Ident, -/// colon_token: Token![:], -/// ty: Type, -/// } -/// -/// impl Parse for Struct { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let content; -/// Ok(Struct { -/// struct_token: input.parse()?, -/// ident: input.parse()?, -/// brace_token: braced!(content in input), -/// fields: content.parse_terminated(Field::parse, Token![,])?, -/// }) -/// } -/// } -/// -/// impl Parse for Field { -/// fn parse(input: ParseStream) -> Result<Self> { -/// Ok(Field { -/// name: input.parse()?, -/// colon_token: input.parse()?, -/// ty: input.parse()?, -/// }) -/// } -/// } -/// # -/// # fn main() { -/// # let input = quote! { -/// # struct S { -/// # a: A, -/// # b: B, -/// # } -/// # }; -/// # syn::parse2::<Struct>(input).unwrap(); -/// # } -/// ``` -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -macro_rules! braced { - ($content:ident in $cursor:expr) => { - match $crate::__private::parse_braces(&$cursor) { - $crate::__private::Ok(braces) => { - $content = braces.content; - _ = $content; - braces.token - } - $crate::__private::Err(error) => { - return $crate::__private::Err(error); - } - } - }; -} - -/// Parse a set of square brackets and expose their content to subsequent -/// parsers. -/// -/// # Example -/// -/// ``` -/// # use quote::quote; -/// # -/// use proc_macro2::TokenStream; -/// use syn::{bracketed, token, Result, Token}; -/// use syn::parse::{Parse, ParseStream}; -/// -/// // Parse an outer attribute like: -/// // -/// // #[repr(C, packed)] -/// struct OuterAttribute { -/// pound_token: Token![#], -/// bracket_token: token::Bracket, -/// content: TokenStream, -/// } -/// -/// impl Parse for OuterAttribute { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let content; -/// Ok(OuterAttribute { -/// pound_token: input.parse()?, -/// bracket_token: bracketed!(content in input), -/// content: content.parse()?, -/// }) -/// } -/// } -/// # -/// # fn main() { -/// # let input = quote! { -/// # #[repr(C, packed)] -/// # }; -/// # syn::parse2::<OuterAttribute>(input).unwrap(); -/// # } -/// ``` -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -macro_rules! bracketed { - ($content:ident in $cursor:expr) => { - match $crate::__private::parse_brackets(&$cursor) { - $crate::__private::Ok(brackets) => { - $content = brackets.content; - _ = $content; - brackets.token - } - $crate::__private::Err(error) => { - return $crate::__private::Err(error); - } - } - }; -} diff --git a/deps/crates/vendor/syn-v2/src/ident.rs b/deps/crates/vendor/syn-v2/src/ident.rs deleted file mode 100644 index 923fe19d1962..000000000000 --- a/deps/crates/vendor/syn-v2/src/ident.rs +++ /dev/null @@ -1,109 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::lookahead; - -pub use proc_macro2::Ident; - -#[cfg(feature = "parsing")] -pub_if_not_doc! { - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn Ident(marker: lookahead::TokenMarker) -> Ident { - match marker {} - } -} - -macro_rules! ident_from_token { - ($token:ident) => { - impl From<Token![$token]> for Ident { - fn from(token: Token![$token]) -> Ident { - Ident::new(stringify!($token), token.span) - } - } - }; -} - -ident_from_token!(self); -ident_from_token!(Self); -ident_from_token!(super); -ident_from_token!(crate); -ident_from_token!(extern); - -impl From<Token![_]> for Ident { - fn from(token: Token![_]) -> Ident { - Ident::new("_", token.span) - } -} - -pub(crate) fn xid_ok(symbol: &str) -> bool { - let mut chars = symbol.chars(); - let first = chars.next().unwrap(); - if !(first == '_' || unicode_ident::is_xid_start(first)) { - return false; - } - for ch in chars { - if !unicode_ident::is_xid_continue(ch) { - return false; - } - } - true -} - -#[cfg(feature = "parsing")] -mod parsing { - use crate::buffer::Cursor; - use crate::error::Result; - use crate::parse::{Parse, ParseStream}; - use crate::token::Token; - use alloc::string::ToString; - use proc_macro2::Ident; - - fn accept_as_ident(ident: &Ident) -> bool { - match ident.to_string().as_str() { - "_" | - // Based on https://doc.rust-lang.org/1.65.0/reference/keywords.html - "abstract" | "as" | "async" | "await" | "become" | "box" | "break" | - "const" | "continue" | "crate" | "do" | "dyn" | "else" | "enum" | - "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in" | - "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | - "override" | "priv" | "pub" | "ref" | "return" | "Self" | "self" | - "static" | "struct" | "super" | "trait" | "true" | "try" | "type" | - "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | - "while" | "yield" => false, - _ => true, - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Ident { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| { - if let Some((ident, rest)) = cursor.ident() { - if accept_as_ident(&ident) { - Ok((ident, rest)) - } else { - Err(cursor.error(format_args!( - "expected identifier, found keyword `{}`", - ident, - ))) - } - } else { - Err(cursor.error("expected identifier")) - } - }) - } - } - - impl Token for Ident { - fn peek(cursor: Cursor) -> bool { - if let Some((ident, _rest)) = cursor.ident() { - accept_as_ident(&ident) - } else { - false - } - } - - fn display() -> &'static str { - "identifier" - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/item.rs b/deps/crates/vendor/syn-v2/src/item.rs deleted file mode 100644 index bdb229a1cdd2..000000000000 --- a/deps/crates/vendor/syn-v2/src/item.rs +++ /dev/null @@ -1,3413 +0,0 @@ -use crate::attr::Attribute; -use crate::data::{Fields, FieldsNamed, Variant}; -use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; -use crate::expr::Expr; -use crate::generics::{Generics, TypeParamBound}; -use crate::ident::Ident; -use crate::lifetime::Lifetime; -use crate::mac::Macro; -use crate::pat::{Pat, PatType}; -use crate::path::Path; -use crate::punctuated::Punctuated; -use crate::restriction::Visibility; -use crate::stmt::Block; -use crate::token; -use crate::ty::{Abi, ReturnType, Type}; -use alloc::boxed::Box; -use alloc::vec::Vec; -#[cfg(feature = "parsing")] -use core::mem; -use proc_macro2::TokenStream; - -ast_enum_of_structs! { - /// Things that can appear directly inside of a module or scope. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum Item { - /// A constant item: `const MAX: u16 = 65535`. - Const(ItemConst), - - /// An enum definition: `enum Foo<A, B> { A(A), B(B) }`. - Enum(ItemEnum), - - /// An `extern crate` item: `extern crate serde`. - ExternCrate(ItemExternCrate), - - /// A free-standing function: `fn process(n: usize) -> Result<()> { ... - /// }`. - Fn(ItemFn), - - /// A block of foreign items: `extern "C" { ... }`. - ForeignMod(ItemForeignMod), - - /// An impl block providing trait or associated items: `impl<A> Trait - /// for Data<A> { ... }`. - Impl(ItemImpl), - - /// A macro invocation, which includes `macro_rules!` definitions. - Macro(ItemMacro), - - /// A module or module declaration: `mod m` or `mod m { ... }`. - Mod(ItemMod), - - /// A static item: `static BIKE: Shed = Shed(42)`. - Static(ItemStatic), - - /// A struct definition: `struct Foo<A> { x: A }`. - Struct(ItemStruct), - - /// A trait definition: `pub trait Iterator { ... }`. - Trait(ItemTrait), - - /// A trait alias: `pub trait SharableIterator = Iterator + Sync`. - TraitAlias(ItemTraitAlias), - - /// A type alias: `type Result<T> = core::result::Result<T, MyError>`. - Type(ItemType), - - /// A union definition: `union Foo<A, B> { x: A, y: B }`. - Union(ItemUnion), - - /// A use declaration: `use alloc::collections::HashMap`. - Use(ItemUse), - - /// Tokens forming an item not interpreted by Syn. - Verbatim(TokenStream), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match item { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // Item::Const(item) => {...} - // Item::Enum(item) => {...} - // ... - // Item::Verbatim(item) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// A constant item: `const MAX: u16 = 65535`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemConst { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub const_token: Token![const], - pub ident: Ident, - pub generics: Generics, - pub colon_token: Token![:], - pub ty: Box<Type>, - pub eq_token: Token![=], - pub expr: Box<Expr>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// An enum definition: `enum Foo<A, B> { A(A), B(B) }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemEnum { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub enum_token: Token![enum], - pub ident: Ident, - pub generics: Generics, - pub brace_token: token::Brace, - pub variants: Punctuated<Variant, Token![,]>, - } -} - -ast_struct! { - /// An `extern crate` item: `extern crate serde`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemExternCrate { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub extern_token: Token![extern], - pub crate_token: Token![crate], - pub ident: Ident, - pub rename: Option<(Token![as], Ident)>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A free-standing function: `fn process(n: usize) -> Result<()> { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemFn { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub sig: Signature, - pub block: Box<Block>, - } -} - -ast_struct! { - /// A block of foreign items: `extern "C" { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemForeignMod { - pub attrs: Vec<Attribute>, - pub unsafety: Option<Token![unsafe]>, - pub abi: Abi, - pub brace_token: token::Brace, - pub items: Vec<ForeignItem>, - } -} - -ast_struct! { - /// An impl block providing trait or associated items: `impl<A> Trait - /// for Data<A> { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemImpl { - pub attrs: Vec<Attribute>, - pub defaultness: Option<Token![default]>, - pub unsafety: Option<Token![unsafe]>, - pub impl_token: Token![impl], - pub generics: Generics, - /// Trait this impl implements. - pub trait_: Option<(Option<Token![!]>, Path, Token![for])>, - /// The Self type of the impl. - pub self_ty: Box<Type>, - pub brace_token: token::Brace, - pub items: Vec<ImplItem>, - } -} - -ast_struct! { - /// A macro invocation, which includes `macro_rules!` definitions. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemMacro { - pub attrs: Vec<Attribute>, - /// The `example` in `macro_rules! example { ... }`. - pub ident: Option<Ident>, - pub mac: Macro, - pub semi_token: Option<Token![;]>, - } -} - -ast_struct! { - /// A module or module declaration: `mod m` or `mod m { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemMod { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub unsafety: Option<Token![unsafe]>, - pub mod_token: Token![mod], - pub ident: Ident, - pub content: Option<(token::Brace, Vec<Item>)>, - pub semi: Option<Token![;]>, - } -} - -ast_struct! { - /// A static item: `static BIKE: Shed = Shed(42)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemStatic { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub static_token: Token![static], - pub mutability: StaticMutability, - pub ident: Ident, - pub colon_token: Token![:], - pub ty: Box<Type>, - pub eq_token: Token![=], - pub expr: Box<Expr>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A struct definition: `struct Foo<A> { x: A }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemStruct { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub struct_token: Token![struct], - pub ident: Ident, - pub generics: Generics, - pub fields: Fields, - pub semi_token: Option<Token![;]>, - } -} - -ast_struct! { - /// A trait definition: `pub trait Iterator { ... }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemTrait { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub unsafety: Option<Token![unsafe]>, - pub auto_token: Option<Token![auto]>, - pub restriction: Option<ImplRestriction>, - pub trait_token: Token![trait], - pub ident: Ident, - pub generics: Generics, - pub colon_token: Option<Token![:]>, - pub supertraits: Punctuated<TypeParamBound, Token![+]>, - pub brace_token: token::Brace, - pub items: Vec<TraitItem>, - } -} - -ast_struct! { - /// A trait alias: `pub trait SharableIterator = Iterator + Sync`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemTraitAlias { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub trait_token: Token![trait], - pub ident: Ident, - pub generics: Generics, - pub eq_token: Token![=], - pub bounds: Punctuated<TypeParamBound, Token![+]>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A type alias: `type Result<T> = core::result::Result<T, MyError>`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemType { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub type_token: Token![type], - pub ident: Ident, - pub generics: Generics, - pub eq_token: Token![=], - pub ty: Box<Type>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A union definition: `union Foo<A, B> { x: A, y: B }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemUnion { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub union_token: Token![union], - pub ident: Ident, - pub generics: Generics, - pub fields: FieldsNamed, - } -} - -ast_struct! { - /// A use declaration: `use alloc::collections::HashMap`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ItemUse { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub use_token: Token![use], - pub leading_colon: Option<Token![::]>, - pub tree: UseTree, - pub semi_token: Token![;], - } -} - -impl Item { - #[cfg(feature = "parsing")] - pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> { - match self { - Item::Const(ItemConst { attrs, .. }) - | Item::Enum(ItemEnum { attrs, .. }) - | Item::ExternCrate(ItemExternCrate { attrs, .. }) - | Item::Fn(ItemFn { attrs, .. }) - | Item::ForeignMod(ItemForeignMod { attrs, .. }) - | Item::Impl(ItemImpl { attrs, .. }) - | Item::Macro(ItemMacro { attrs, .. }) - | Item::Mod(ItemMod { attrs, .. }) - | Item::Static(ItemStatic { attrs, .. }) - | Item::Struct(ItemStruct { attrs, .. }) - | Item::Trait(ItemTrait { attrs, .. }) - | Item::TraitAlias(ItemTraitAlias { attrs, .. }) - | Item::Type(ItemType { attrs, .. }) - | Item::Union(ItemUnion { attrs, .. }) - | Item::Use(ItemUse { attrs, .. }) => mem::replace(attrs, new), - Item::Verbatim(_) => Vec::new(), - } - } -} - -impl From<DeriveInput> for Item { - fn from(input: DeriveInput) -> Item { - match input.data { - Data::Struct(data) => Item::Struct(ItemStruct { - attrs: input.attrs, - vis: input.vis, - struct_token: data.struct_token, - ident: input.ident, - generics: input.generics, - fields: data.fields, - semi_token: data.semi_token, - }), - Data::Enum(data) => Item::Enum(ItemEnum { - attrs: input.attrs, - vis: input.vis, - enum_token: data.enum_token, - ident: input.ident, - generics: input.generics, - brace_token: data.brace_token, - variants: data.variants, - }), - Data::Union(data) => Item::Union(ItemUnion { - attrs: input.attrs, - vis: input.vis, - union_token: data.union_token, - ident: input.ident, - generics: input.generics, - fields: data.fields, - }), - } - } -} - -impl From<ItemStruct> for DeriveInput { - fn from(input: ItemStruct) -> DeriveInput { - DeriveInput { - attrs: input.attrs, - vis: input.vis, - ident: input.ident, - generics: input.generics, - data: Data::Struct(DataStruct { - struct_token: input.struct_token, - fields: input.fields, - semi_token: input.semi_token, - }), - } - } -} - -impl From<ItemEnum> for DeriveInput { - fn from(input: ItemEnum) -> DeriveInput { - DeriveInput { - attrs: input.attrs, - vis: input.vis, - ident: input.ident, - generics: input.generics, - data: Data::Enum(DataEnum { - enum_token: input.enum_token, - brace_token: input.brace_token, - variants: input.variants, - }), - } - } -} - -impl From<ItemUnion> for DeriveInput { - fn from(input: ItemUnion) -> DeriveInput { - DeriveInput { - attrs: input.attrs, - vis: input.vis, - ident: input.ident, - generics: input.generics, - data: Data::Union(DataUnion { union_token: input.union_token, fields: input.fields }), - } - } -} - -ast_enum_of_structs! { - /// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub enum UseTree { - /// A path prefix of imports in a `use` item: `core::...`. - Path(UsePath), - - /// An identifier imported by a `use` item: `HashMap`. - Name(UseName), - - /// An renamed identifier imported by a `use` item: `HashMap as Map`. - Rename(UseRename), - - /// A glob import in a `use` item: `*`. - Glob(UseGlob), - - /// A braced group of imports in a `use` item: `{A, B, C}`. - Group(UseGroup), - } -} - -ast_struct! { - /// A path prefix of imports in a `use` item: `core::...`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct UsePath { - pub ident: Ident, - pub colon2_token: Token![::], - pub tree: Box<UseTree>, - } -} - -ast_struct! { - /// An identifier imported by a `use` item: `HashMap`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct UseName { - pub ident: Ident, - } -} - -ast_struct! { - /// An renamed identifier imported by a `use` item: `HashMap as Map`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct UseRename { - pub ident: Ident, - pub as_token: Token![as], - pub rename: Ident, - } -} - -ast_struct! { - /// A glob import in a `use` item: `*`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct UseGlob { - pub star_token: Token![*], - } -} - -ast_struct! { - /// A braced group of imports in a `use` item: `{A, B, C}`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct UseGroup { - pub brace_token: token::Brace, - pub items: Punctuated<UseTree, Token![,]>, - } -} - -ast_enum_of_structs! { - /// An item within an `extern` block. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum ForeignItem { - /// A foreign function in an `extern` block. - Fn(ForeignItemFn), - - /// A foreign static item in an `extern` block: `static ext: u8`. - Static(ForeignItemStatic), - - /// A foreign type in an `extern` block: `type void`. - Type(ForeignItemType), - - /// A macro invocation within an extern block. - Macro(ForeignItemMacro), - - /// Tokens in an `extern` block not interpreted by Syn. - Verbatim(TokenStream), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match item { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // ForeignItem::Fn(item) => {...} - // ForeignItem::Static(item) => {...} - // ... - // ForeignItem::Verbatim(item) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// A foreign function in an `extern` block. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ForeignItemFn { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub sig: Signature, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A foreign static item in an `extern` block: `static ext: u8`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ForeignItemStatic { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub static_token: Token![static], - pub mutability: StaticMutability, - pub ident: Ident, - pub colon_token: Token![:], - pub ty: Box<Type>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A foreign type in an `extern` block: `type void`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ForeignItemType { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub type_token: Token![type], - pub ident: Ident, - pub generics: Generics, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A macro invocation within an extern block. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ForeignItemMacro { - pub attrs: Vec<Attribute>, - pub mac: Macro, - pub semi_token: Option<Token![;]>, - } -} - -ast_enum_of_structs! { - /// An item declaration within the definition of a trait. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum TraitItem { - /// An associated constant within the definition of a trait. - Const(TraitItemConst), - - /// An associated function within the definition of a trait. - Fn(TraitItemFn), - - /// An associated type within the definition of a trait. - Type(TraitItemType), - - /// A macro invocation within the definition of a trait. - Macro(TraitItemMacro), - - /// Tokens within the definition of a trait not interpreted by Syn. - Verbatim(TokenStream), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match item { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // TraitItem::Const(item) => {...} - // TraitItem::Fn(item) => {...} - // ... - // TraitItem::Verbatim(item) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// An associated constant within the definition of a trait. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct TraitItemConst { - pub attrs: Vec<Attribute>, - pub const_token: Token![const], - pub ident: Ident, - pub generics: Generics, - pub colon_token: Token![:], - pub ty: Type, - pub default: Option<(Token![=], Expr)>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// An associated function within the definition of a trait. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct TraitItemFn { - pub attrs: Vec<Attribute>, - pub sig: Signature, - pub default: Option<Block>, - pub semi_token: Option<Token![;]>, - } -} - -ast_struct! { - /// An associated type within the definition of a trait. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct TraitItemType { - pub attrs: Vec<Attribute>, - pub type_token: Token![type], - pub ident: Ident, - pub generics: Generics, - pub colon_token: Option<Token![:]>, - pub bounds: Punctuated<TypeParamBound, Token![+]>, - pub default: Option<(Token![=], Type)>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A macro invocation within the definition of a trait. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct TraitItemMacro { - pub attrs: Vec<Attribute>, - pub mac: Macro, - pub semi_token: Option<Token![;]>, - } -} - -ast_enum_of_structs! { - /// An item within an impl block. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum ImplItem { - /// An associated constant within an impl block. - Const(ImplItemConst), - - /// An associated function within an impl block. - Fn(ImplItemFn), - - /// An associated type within an impl block. - Type(ImplItemType), - - /// A macro invocation within an impl block. - Macro(ImplItemMacro), - - /// Tokens within an impl block not interpreted by Syn. - Verbatim(TokenStream), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match item { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // ImplItem::Const(item) => {...} - // ImplItem::Fn(item) => {...} - // ... - // ImplItem::Verbatim(item) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// An associated constant within an impl block. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ImplItemConst { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub defaultness: Option<Token![default]>, - pub const_token: Token![const], - pub ident: Ident, - pub generics: Generics, - pub colon_token: Token![:], - pub ty: Type, - pub eq_token: Token![=], - pub expr: Expr, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// An associated function within an impl block. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ImplItemFn { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub defaultness: Option<Token![default]>, - pub sig: Signature, - pub block: Block, - } -} - -ast_struct! { - /// An associated type within an impl block. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ImplItemType { - pub attrs: Vec<Attribute>, - pub vis: Visibility, - pub defaultness: Option<Token![default]>, - pub type_token: Token![type], - pub ident: Ident, - pub generics: Generics, - pub eq_token: Token![=], - pub ty: Type, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// A macro invocation within an impl block. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct ImplItemMacro { - pub attrs: Vec<Attribute>, - pub mac: Macro, - pub semi_token: Option<Token![;]>, - } -} - -ast_struct! { - /// A function signature in a trait or implementation: `unsafe fn - /// initialize(&self)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Signature { - pub constness: Option<Token![const]>, - pub asyncness: Option<Token![async]>, - pub unsafety: Option<Token![unsafe]>, - pub abi: Option<Abi>, - pub fn_token: Token![fn], - pub ident: Ident, - pub generics: Generics, - pub paren_token: token::Paren, - pub inputs: Punctuated<FnArg, Token![,]>, - pub variadic: Option<Variadic>, - pub output: ReturnType, - } -} - -impl Signature { - /// A method's `self` receiver, such as `&self` or `self: Box<Self>`. - pub fn receiver(&self) -> Option<&Receiver> { - let arg = self.inputs.first()?; - match arg { - FnArg::Receiver(receiver) => Some(receiver), - FnArg::Typed(_) => None, - } - } -} - -ast_enum_of_structs! { - /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub enum FnArg { - /// The `self` argument of an associated method. - Receiver(Receiver), - - /// A function argument accepted by pattern and type. - Typed(PatType), - } -} - -ast_struct! { - /// The `self` argument of an associated method. - /// - /// If `colon_token` is present, the receiver is written with an explicit - /// type such as `self: Box<Self>`. If `colon_token` is absent, the receiver - /// is written in shorthand such as `self` or `&self` or `&mut self`. In the - /// shorthand case, the type in `ty` is reconstructed as one of `Self`, - /// `&Self`, or `&mut Self`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Receiver { - pub attrs: Vec<Attribute>, - pub reference: Option<(Token![&], Option<Lifetime>)>, - pub mutability: Option<Token![mut]>, - pub self_token: Token![self], - pub colon_token: Option<Token![:]>, - pub ty: Box<Type>, - } -} - -impl Receiver { - pub fn lifetime(&self) -> Option<&Lifetime> { - self.reference.as_ref()?.1.as_ref() - } -} - -ast_struct! { - /// The variadic argument of a foreign function. - /// - /// ```rust - /// # struct c_char; - /// # struct c_int; - /// # - /// extern "C" { - /// fn printf(format: *const c_char, ...) -> c_int; - /// // ^^^ - /// } - /// ``` - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Variadic { - pub attrs: Vec<Attribute>, - pub pat: Option<(Box<Pat>, Token![:])>, - pub dots: Token![...], - pub comma: Option<Token![,]>, - } -} - -ast_enum! { - /// The mutability of an `Item::Static` or `ForeignItem::Static`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum StaticMutability { - Mut(Token![mut]), - None, - } -} - -ast_enum! { - /// Unused, but reserved for RFC 3323 restrictions. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum ImplRestriction {} - - - // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html - // - // pub struct ImplRestriction { - // pub impl_token: Token![impl], - // pub paren_token: token::Paren, - // pub in_token: Option<Token![in]>, - // pub path: Box<Path>, - // } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::{self, Attribute}; - use crate::buffer::Cursor; - use crate::derive; - use crate::error::{Error, Result}; - use crate::expr::Expr; - use crate::ext::IdentExt as _; - use crate::generics::{self, Generics, TypeParamBound}; - use crate::ident::Ident; - use crate::item::{ - FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType, - ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, Item, ItemConst, - ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, - ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, - Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, - TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic, - }; - use crate::lifetime::Lifetime; - use crate::lit::LitStr; - use crate::mac::{self, Macro}; - use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; - use crate::pat::{Pat, PatType, PatWild}; - use crate::path::Path; - use crate::punctuated::Punctuated; - use crate::restriction::Visibility; - use crate::stmt::Block; - use crate::token; - use crate::ty::{Abi, ReturnType, Type, TypePath, TypeReference}; - use crate::verbatim; - use alloc::boxed::Box; - use alloc::vec::Vec; - use proc_macro2::TokenStream; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Item { - fn parse(input: ParseStream) -> Result<Self> { - let begin = input.cursor(); - let attrs = input.call(Attribute::parse_outer)?; - parse_rest_of_item(begin, attrs, input) - } - } - - pub(crate) fn parse_rest_of_item( - begin: Cursor, - mut attrs: Vec<Attribute>, - input: ParseStream, - ) -> Result<Item> { - let ahead = input.fork(); - let vis: Visibility = ahead.parse()?; - - let lookahead = ahead.lookahead1(); - let allow_safe = false; - let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead, allow_safe) { - let vis: Visibility = input.parse()?; - let sig: Signature = input.parse()?; - if input.peek(Token![;]) { - input.parse::<Token![;]>()?; - Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - parse_rest_of_fn(input, Vec::new(), vis, sig).map(Item::Fn) - } - } else if lookahead.peek(Token![extern]) { - ahead.parse::<Token![extern]>()?; - let lookahead = ahead.lookahead1(); - if lookahead.peek(Token![crate]) { - input.parse().map(Item::ExternCrate) - } else if lookahead.peek(token::Brace) { - input.parse().map(Item::ForeignMod) - } else if lookahead.peek(LitStr) { - ahead.parse::<LitStr>()?; - let lookahead = ahead.lookahead1(); - if lookahead.peek(token::Brace) { - input.parse().map(Item::ForeignMod) - } else { - Err(lookahead.error()) - } - } else { - Err(lookahead.error()) - } - } else if lookahead.peek(Token![use]) { - let allow_crate_root_in_path = true; - match parse_item_use(input, allow_crate_root_in_path)? { - Some(item_use) => Ok(Item::Use(item_use)), - None => Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))), - } - } else if lookahead.peek(Token![static]) { - let vis = input.parse()?; - let static_token = input.parse()?; - let mutability = input.parse()?; - let ident = input.parse()?; - if input.peek(Token![=]) { - input.parse::<Token![=]>()?; - input.parse::<Expr>()?; - input.parse::<Token![;]>()?; - Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - let colon_token = input.parse()?; - let ty = input.parse()?; - if input.peek(Token![;]) { - input.parse::<Token![;]>()?; - Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - Ok(Item::Static(ItemStatic { - attrs: Vec::new(), - vis, - static_token, - mutability, - ident, - colon_token, - ty, - eq_token: input.parse()?, - expr: input.parse()?, - semi_token: input.parse()?, - })) - } - } - } else if lookahead.peek(Token![const]) { - let vis = input.parse()?; - let const_token: Token![const] = input.parse()?; - let lookahead = input.lookahead1(); - let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.call(Ident::parse_any)? - } else { - return Err(lookahead.error()); - }; - let mut generics: Generics = input.parse()?; - let colon_token = input.parse()?; - let ty = input.parse()?; - let value = if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { - let expr: Expr = input.parse()?; - Some((eq_token, expr)) - } else { - None - }; - generics.where_clause = input.parse()?; - let semi_token: Token![;] = input.parse()?; - match value { - Some((eq_token, expr)) - if generics.lt_token.is_none() && generics.where_clause.is_none() => - { - Ok(Item::Const(ItemConst { - attrs: Vec::new(), - vis, - const_token, - ident, - generics, - colon_token, - ty, - eq_token, - expr: Box::new(expr), - semi_token, - })) - } - _ => Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))), - } - } else if lookahead.peek(Token![unsafe]) { - ahead.parse::<Token![unsafe]>()?; - let lookahead = ahead.lookahead1(); - if lookahead.peek(Token![trait]) - || lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) - { - input.parse().map(Item::Trait) - } else if lookahead.peek(Token![impl]) { - let allow_verbatim_impl = true; - if let Some(item) = parse_impl(input, allow_verbatim_impl)? { - Ok(Item::Impl(item)) - } else { - Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))) - } - } else if lookahead.peek(Token![extern]) { - input.parse().map(Item::ForeignMod) - } else if lookahead.peek(Token![mod]) { - input.parse().map(Item::Mod) - } else { - Err(lookahead.error()) - } - } else if lookahead.peek(Token![mod]) { - input.parse().map(Item::Mod) - } else if lookahead.peek(Token![type]) { - parse_item_type(begin, input) - } else if lookahead.peek(Token![struct]) { - input.parse().map(Item::Struct) - } else if lookahead.peek(Token![enum]) { - input.parse().map(Item::Enum) - } else if lookahead.peek(Token![union]) && ahead.peek2(Ident) { - input.parse().map(Item::Union) - } else if lookahead.peek(Token![trait]) { - input.call(parse_trait_or_trait_alias) - } else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) { - input.parse().map(Item::Trait) - } else if lookahead.peek(Token![impl]) - || lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) - { - let allow_verbatim_impl = true; - if let Some(item) = parse_impl(input, allow_verbatim_impl)? { - Ok(Item::Impl(item)) - } else { - Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))) - } - } else if lookahead.peek(Token![macro]) { - input.advance_to(&ahead); - parse_macro2(begin, vis, input) - } else if vis.is_inherited() - && (lookahead.peek(Ident) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - || lookahead.peek(Token![::])) - { - input.parse().map(Item::Macro) - } else { - Err(lookahead.error()) - }?; - - attrs.extend(item.replace_attrs(Vec::new())); - item.replace_attrs(attrs); - Ok(item) - } - - struct FlexibleItemType { - vis: Visibility, - defaultness: Option<Token![default]>, - type_token: Token![type], - ident: Ident, - generics: Generics, - colon_token: Option<Token![:]>, - bounds: Punctuated<TypeParamBound, Token![+]>, - ty: Option<(Token![=], Type)>, - semi_token: Token![;], - } - - enum TypeDefaultness { - Optional, - Disallowed, - } - - enum WhereClauseLocation { - // type Ty<T> where T: 'static = T; - BeforeEq, - // type Ty<T> = T where T: 'static; - AfterEq, - // TODO: goes away once the migration period on rust-lang/rust#89122 is over - Both, - } - - impl FlexibleItemType { - fn parse( - input: ParseStream, - allow_defaultness: TypeDefaultness, - where_clause_location: WhereClauseLocation, - ) -> Result<Self> { - let vis: Visibility = input.parse()?; - let defaultness: Option<Token![default]> = match allow_defaultness { - TypeDefaultness::Optional => input.parse()?, - TypeDefaultness::Disallowed => None, - }; - let type_token: Token![type] = input.parse()?; - let ident: Ident = input.parse()?; - let mut generics: Generics = input.parse()?; - let (colon_token, bounds) = Self::parse_optional_bounds(input)?; - - match where_clause_location { - WhereClauseLocation::BeforeEq | WhereClauseLocation::Both => { - generics.where_clause = input.parse()?; - } - WhereClauseLocation::AfterEq => {} - } - - let ty = Self::parse_optional_definition(input)?; - - match where_clause_location { - WhereClauseLocation::AfterEq | WhereClauseLocation::Both - if generics.where_clause.is_none() => - { - generics.where_clause = input.parse()?; - } - _ => {} - } - - let semi_token: Token![;] = input.parse()?; - - Ok(FlexibleItemType { - vis, - defaultness, - type_token, - ident, - generics, - colon_token, - bounds, - ty, - semi_token, - }) - } - - fn parse_optional_bounds( - input: ParseStream, - ) -> Result<(Option<Token![:]>, Punctuated<TypeParamBound, Token![+]>)> { - let colon_token: Option<Token![:]> = input.parse()?; - - let mut bounds = Punctuated::new(); - if colon_token.is_some() { - loop { - if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) { - break; - } - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = true; - TypeParamBound::parse_single(input, allow_precise_capture, allow_const)? - }); - if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) { - break; - } - bounds.push_punct(input.parse::<Token![+]>()?); - } - } - - Ok((colon_token, bounds)) - } - - fn parse_optional_definition(input: ParseStream) -> Result<Option<(Token![=], Type)>> { - let eq_token: Option<Token![=]> = input.parse()?; - if let Some(eq_token) = eq_token { - let definition: Type = input.parse()?; - Ok(Some((eq_token, definition))) - } else { - Ok(None) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemMacro { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let path = input.call(Path::parse_mod_style)?; - let bang_token: Token![!] = input.parse()?; - let ident: Option<Ident> = if input.peek(Token![try]) { - input.call(Ident::parse_any).map(Some) - } else { - input.parse() - }?; - let (delimiter, tokens) = input.call(mac::parse_delimiter)?; - let semi_token: Option<Token![;]> = - if !delimiter.is_brace() { Some(input.parse()?) } else { None }; - Ok(ItemMacro { - attrs, - ident, - mac: Macro { path, bang_token, delimiter, tokens }, - semi_token, - }) - } - } - - fn parse_macro2(begin: Cursor, _vis: Visibility, input: ParseStream) -> Result<Item> { - input.parse::<Token![macro]>()?; - input.parse::<Ident>()?; - - let mut lookahead = input.lookahead1(); - if lookahead.peek(token::Paren) { - let paren_content; - parenthesized!(paren_content in input); - paren_content.parse::<TokenStream>()?; - lookahead = input.lookahead1(); - } - - if lookahead.peek(token::Brace) { - let brace_content; - braced!(brace_content in input); - brace_content.parse::<TokenStream>()?; - } else { - return Err(lookahead.error()); - } - - Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemExternCrate { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ItemExternCrate { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - extern_token: input.parse()?, - crate_token: input.parse()?, - ident: { - if input.peek(Token![self]) { - input.call(Ident::parse_any)? - } else { - input.parse()? - } - }, - rename: { - if input.peek(Token![as]) { - let as_token: Token![as] = input.parse()?; - let rename: Ident = if input.peek(Token![_]) { - Ident::from(input.parse::<Token![_]>()?) - } else { - input.parse()? - }; - Some((as_token, rename)) - } else { - None - } - }, - semi_token: input.parse()?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemUse { - fn parse(input: ParseStream) -> Result<Self> { - let allow_crate_root_in_path = false; - parse_item_use(input, allow_crate_root_in_path).map(Option::unwrap) - } - } - - fn parse_item_use( - input: ParseStream, - allow_crate_root_in_path: bool, - ) -> Result<Option<ItemUse>> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let use_token: Token![use] = input.parse()?; - let leading_colon: Option<Token![::]> = input.parse()?; - let tree = parse_use_tree(input, allow_crate_root_in_path && leading_colon.is_none())?; - let semi_token: Token![;] = input.parse()?; - - let tree = match tree { - Some(tree) => tree, - None => return Ok(None), - }; - - Ok(Some(ItemUse { attrs, vis, use_token, leading_colon, tree, semi_token })) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for UseTree { - fn parse(input: ParseStream) -> Result<UseTree> { - let allow_crate_root_in_path = false; - parse_use_tree(input, allow_crate_root_in_path).map(Option::unwrap) - } - } - - fn parse_use_tree( - input: ParseStream, - allow_crate_root_in_path: bool, - ) -> Result<Option<UseTree>> { - let lookahead = input.lookahead1(); - if lookahead.peek(Ident) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - || lookahead.peek(Token![try]) - { - let ident = input.call(Ident::parse_any)?; - if input.peek(Token![::]) { - Ok(Some(UseTree::Path(UsePath { - ident, - colon2_token: input.parse()?, - tree: Box::new(input.parse()?), - }))) - } else if input.peek(Token![as]) { - Ok(Some(UseTree::Rename(UseRename { - ident, - as_token: input.parse()?, - rename: { - if input.peek(Ident) { - input.parse()? - } else if input.peek(Token![_]) { - Ident::from(input.parse::<Token![_]>()?) - } else { - return Err(input.error("expected identifier or underscore")); - } - }, - }))) - } else { - Ok(Some(UseTree::Name(UseName { ident }))) - } - } else if lookahead.peek(Token![*]) { - Ok(Some(UseTree::Glob(UseGlob { star_token: input.parse()? }))) - } else if lookahead.peek(token::Brace) { - let content; - let brace_token = braced!(content in input); - let mut items = Punctuated::new(); - let mut has_any_crate_root_in_path = false; - loop { - if content.is_empty() { - break; - } - let this_tree_starts_with_crate_root = - allow_crate_root_in_path && content.parse::<Option<Token![::]>>()?.is_some(); - has_any_crate_root_in_path |= this_tree_starts_with_crate_root; - match parse_use_tree( - &content, - allow_crate_root_in_path && !this_tree_starts_with_crate_root, - )? { - Some(tree) if !has_any_crate_root_in_path => items.push_value(tree), - _ => has_any_crate_root_in_path = true, - } - if content.is_empty() { - break; - } - let comma: Token![,] = content.parse()?; - if !has_any_crate_root_in_path { - items.push_punct(comma); - } - } - if has_any_crate_root_in_path { - Ok(None) - } else { - Ok(Some(UseTree::Group(UseGroup { brace_token, items }))) - } - } else { - Err(lookahead.error()) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemStatic { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ItemStatic { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - static_token: input.parse()?, - mutability: input.parse()?, - ident: input.parse()?, - colon_token: input.parse()?, - ty: input.parse()?, - eq_token: input.parse()?, - expr: input.parse()?, - semi_token: input.parse()?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemConst { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let const_token: Token![const] = input.parse()?; - - let lookahead = input.lookahead1(); - let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.call(Ident::parse_any)? - } else { - return Err(lookahead.error()); - }; - - let colon_token: Token![:] = input.parse()?; - let ty: Type = input.parse()?; - let eq_token: Token![=] = input.parse()?; - let expr: Expr = input.parse()?; - let semi_token: Token![;] = input.parse()?; - - Ok(ItemConst { - attrs, - vis, - const_token, - ident, - generics: Generics::default(), - colon_token, - ty: Box::new(ty), - eq_token, - expr: Box::new(expr), - semi_token, - }) - } - } - - fn peek_signature(input: ParseStream, allow_safe: bool) -> bool { - let fork = input.fork(); - fork.parse::<Option<Token![const]>>().is_ok() - && fork.parse::<Option<Token![async]>>().is_ok() - && ((allow_safe - && token::parsing::peek_keyword(fork.cursor(), "safe") - && token::parsing::keyword(&fork, "safe").is_ok()) - || fork.parse::<Option<Token![unsafe]>>().is_ok()) - && fork.parse::<Option<Abi>>().is_ok() - && fork.peek(Token![fn]) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Signature { - fn parse(input: ParseStream) -> Result<Self> { - let allow_safe = false; - parse_signature(input, allow_safe).map(Option::unwrap) - } - } - - fn parse_signature(input: ParseStream, allow_safe: bool) -> Result<Option<Signature>> { - let constness: Option<Token![const]> = input.parse()?; - let asyncness: Option<Token![async]> = input.parse()?; - let unsafety: Option<Token![unsafe]> = input.parse()?; - let safe = allow_safe - && unsafety.is_none() - && token::parsing::peek_keyword(input.cursor(), "safe"); - if safe { - token::parsing::keyword(input, "safe")?; - } - let abi: Option<Abi> = input.parse()?; - let fn_token: Token![fn] = input.parse()?; - let ident: Ident = input.parse()?; - let mut generics: Generics = input.parse()?; - - let content; - let paren_token = parenthesized!(content in input); - let (inputs, variadic) = parse_fn_args(&content)?; - - let output: ReturnType = input.parse()?; - generics.where_clause = input.parse()?; - - Ok(if safe { - None - } else { - Some(Signature { - constness, - asyncness, - unsafety, - abi, - fn_token, - ident, - generics, - paren_token, - inputs, - variadic, - output, - }) - }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemFn { - fn parse(input: ParseStream) -> Result<Self> { - let outer_attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let sig: Signature = input.parse()?; - parse_rest_of_fn(input, outer_attrs, vis, sig) - } - } - - fn parse_rest_of_fn( - input: ParseStream, - mut attrs: Vec<Attribute>, - vis: Visibility, - sig: Signature, - ) -> Result<ItemFn> { - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let stmts = content.call(Block::parse_within)?; - - Ok(ItemFn { attrs, vis, sig, block: Box::new(Block { brace_token, stmts }) }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for FnArg { - fn parse(input: ParseStream) -> Result<Self> { - let allow_variadic = false; - let attrs = input.call(Attribute::parse_outer)?; - match parse_fn_arg_or_variadic(input, attrs, allow_variadic)? { - FnArgOrVariadic::FnArg(arg) => Ok(arg), - FnArgOrVariadic::Variadic(_) => unreachable!(), - } - } - } - - enum FnArgOrVariadic { - FnArg(FnArg), - Variadic(Variadic), - } - - fn parse_fn_arg_or_variadic( - input: ParseStream, - attrs: Vec<Attribute>, - allow_variadic: bool, - ) -> Result<FnArgOrVariadic> { - let ahead = input.fork(); - if let Ok((reference, mutability, self_token)) = parse_receiver_begin(&ahead) { - input.advance_to(&ahead); - let mut receiver = parse_rest_of_receiver(reference, mutability, self_token, input)?; - receiver.attrs = attrs; - return Ok(FnArgOrVariadic::FnArg(FnArg::Receiver(receiver))); - } - - // Hack to parse pre-2018 syntax in - // test/ui/rfc-2565-param-attrs/param-attrs-pretty.rs - // because the rest of the test case is valuable. - if input.peek(Ident) && input.peek2(Token![<]) { - let span = input.span(); - return Ok(FnArgOrVariadic::FnArg(FnArg::Typed(PatType { - attrs, - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token![_](span), - })), - colon_token: Token![:](span), - ty: input.parse()?, - }))); - } - - let pat = Box::new(Pat::parse_single(input)?); - let colon_token: Token![:] = input.parse()?; - - if allow_variadic { - if let Some(dots) = input.parse::<Option<Token![...]>>()? { - return Ok(FnArgOrVariadic::Variadic(Variadic { - attrs, - pat: Some((pat, colon_token)), - dots, - comma: None, - })); - } - } - - Ok(FnArgOrVariadic::FnArg(FnArg::Typed(PatType { - attrs, - pat, - colon_token, - ty: input.parse()?, - }))) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Receiver { - fn parse(input: ParseStream) -> Result<Self> { - let (reference, mutability, self_token) = parse_receiver_begin(input)?; - parse_rest_of_receiver(reference, mutability, self_token, input) - } - } - - fn parse_receiver_begin( - input: ParseStream, - ) -> Result<(Option<(Token![&], Option<Lifetime>)>, Option<Token![mut]>, Token![self])> { - let reference = if input.peek(Token![&]) { - let ampersand: Token![&] = input.parse()?; - let lifetime: Option<Lifetime> = input.parse()?; - Some((ampersand, lifetime)) - } else { - None - }; - let mutability: Option<Token![mut]> = input.parse()?; - let self_token: Token![self] = input.parse()?; - if input.peek(Token![::]) { - return Err(input.error("expected `:`")); - } - Ok((reference, mutability, self_token)) - } - - fn parse_rest_of_receiver( - reference: Option<(Token![&], Option<Lifetime>)>, - mutability: Option<Token![mut]>, - self_token: Token![self], - input: ParseStream, - ) -> Result<Receiver> { - let colon_token: Option<Token![:]> = - if reference.is_some() { None } else { input.parse()? }; - let ty: Type = if colon_token.is_some() { - input.parse()? - } else { - let mut ty = Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("Self", self_token.span)), - }); - if let Some((ampersand, lifetime)) = reference.as_ref() { - ty = Type::Reference(TypeReference { - and_token: Token![&](ampersand.span), - lifetime: lifetime.clone(), - mutability: mutability.as_ref().map(|m| Token![mut](m.span)), - elem: Box::new(ty), - }); - } - ty - }; - Ok(Receiver { - attrs: Vec::new(), - reference, - mutability, - self_token, - colon_token, - ty: Box::new(ty), - }) - } - - fn parse_fn_args( - input: ParseStream, - ) -> Result<(Punctuated<FnArg, Token![,]>, Option<Variadic>)> { - let mut args = Punctuated::new(); - let mut variadic = None; - let mut has_receiver = false; - - while !input.is_empty() { - let attrs = input.call(Attribute::parse_outer)?; - - if let Some(dots) = input.parse::<Option<Token![...]>>()? { - variadic = Some(Variadic { - attrs, - pat: None, - dots, - comma: if input.is_empty() { None } else { Some(input.parse()?) }, - }); - break; - } - - let allow_variadic = true; - let arg = match parse_fn_arg_or_variadic(input, attrs, allow_variadic)? { - FnArgOrVariadic::FnArg(arg) => arg, - FnArgOrVariadic::Variadic(arg) => { - variadic = Some(Variadic { - comma: if input.is_empty() { None } else { Some(input.parse()?) }, - ..arg - }); - break; - } - }; - - match &arg { - FnArg::Receiver(receiver) if has_receiver => { - return Err(Error::new( - receiver.self_token.span, - "unexpected second method receiver", - )); - } - FnArg::Receiver(receiver) if !args.is_empty() => { - return Err(Error::new(receiver.self_token.span, "unexpected method receiver")); - } - FnArg::Receiver(_) => has_receiver = true, - FnArg::Typed(_) => {} - } - args.push_value(arg); - - if input.is_empty() { - break; - } - - let comma: Token![,] = input.parse()?; - args.push_punct(comma); - } - - Ok((args, variadic)) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemMod { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let unsafety: Option<Token![unsafe]> = input.parse()?; - let mod_token: Token![mod] = input.parse()?; - let ident: Ident = - if input.peek(Token![try]) { input.call(Ident::parse_any) } else { input.parse() }?; - - let lookahead = input.lookahead1(); - if lookahead.peek(Token![;]) { - Ok(ItemMod { - attrs, - vis, - unsafety, - mod_token, - ident, - content: None, - semi: Some(input.parse()?), - }) - } else if lookahead.peek(token::Brace) { - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - - let mut items = Vec::new(); - while !content.is_empty() { - items.push(content.parse()?); - } - - Ok(ItemMod { - attrs, - vis, - unsafety, - mod_token, - ident, - content: Some((brace_token, items)), - semi: None, - }) - } else { - Err(lookahead.error()) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemForeignMod { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let unsafety: Option<Token![unsafe]> = input.parse()?; - let abi: Abi = input.parse()?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let mut items = Vec::new(); - while !content.is_empty() { - items.push(content.parse()?); - } - - Ok(ItemForeignMod { attrs, unsafety, abi, brace_token, items }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ForeignItem { - fn parse(input: ParseStream) -> Result<Self> { - let begin = input.cursor(); - let mut attrs = input.call(Attribute::parse_outer)?; - let ahead = input.fork(); - let vis: Visibility = ahead.parse()?; - - let lookahead = ahead.lookahead1(); - let allow_safe = true; - let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead, allow_safe) { - let vis: Visibility = input.parse()?; - let sig = parse_signature(input, allow_safe)?; - let has_safe = sig.is_none(); - let has_body = input.peek(token::Brace); - let semi_token: Option<Token![;]> = if has_body { - let content; - braced!(content in input); - content.call(Attribute::parse_inner)?; - content.call(Block::parse_within)?; - None - } else { - Some(input.parse()?) - }; - if has_safe || has_body { - Ok(ForeignItem::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - Ok(ForeignItem::Fn(ForeignItemFn { - attrs: Vec::new(), - vis, - sig: sig.unwrap(), - semi_token: semi_token.unwrap(), - })) - } - } else if lookahead.peek(Token![static]) - || ((ahead.peek(Token![unsafe]) - || token::parsing::peek_keyword(ahead.cursor(), "safe")) - && ahead.peek2(Token![static])) - { - let vis = input.parse()?; - let unsafety: Option<Token![unsafe]> = input.parse()?; - let safe = - unsafety.is_none() && token::parsing::peek_keyword(input.cursor(), "safe"); - if safe { - token::parsing::keyword(input, "safe")?; - } - let static_token = input.parse()?; - let mutability = input.parse()?; - let ident = input.parse()?; - let colon_token = input.parse()?; - let ty = input.parse()?; - let has_value = input.peek(Token![=]); - if has_value { - input.parse::<Token![=]>()?; - input.parse::<Expr>()?; - } - let semi_token: Token![;] = input.parse()?; - if unsafety.is_some() || safe || has_value { - Ok(ForeignItem::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - Ok(ForeignItem::Static(ForeignItemStatic { - attrs: Vec::new(), - vis, - static_token, - mutability, - ident, - colon_token, - ty, - semi_token, - })) - } - } else if lookahead.peek(Token![type]) { - parse_foreign_item_type(begin, input) - } else if vis.is_inherited() - && (lookahead.peek(Ident) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - || lookahead.peek(Token![::])) - { - input.parse().map(ForeignItem::Macro) - } else { - Err(lookahead.error()) - }?; - - let item_attrs = match &mut item { - ForeignItem::Fn(item) => &mut item.attrs, - ForeignItem::Static(item) => &mut item.attrs, - ForeignItem::Type(item) => &mut item.attrs, - ForeignItem::Macro(item) => &mut item.attrs, - ForeignItem::Verbatim(_) => return Ok(item), - }; - attrs.append(item_attrs); - *item_attrs = attrs; - - Ok(item) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ForeignItemFn { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let sig: Signature = input.parse()?; - let semi_token: Token![;] = input.parse()?; - Ok(ForeignItemFn { attrs, vis, sig, semi_token }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ForeignItemStatic { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ForeignItemStatic { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - static_token: input.parse()?, - mutability: input.parse()?, - ident: input.parse()?, - colon_token: input.parse()?, - ty: input.parse()?, - semi_token: input.parse()?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ForeignItemType { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ForeignItemType { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - type_token: input.parse()?, - ident: input.parse()?, - generics: { - let mut generics: Generics = input.parse()?; - generics.where_clause = input.parse()?; - generics - }, - semi_token: input.parse()?, - }) - } - } - - fn parse_foreign_item_type(begin: Cursor, input: ParseStream) -> Result<ForeignItem> { - let FlexibleItemType { - vis, - defaultness: _, - type_token, - ident, - generics, - colon_token, - bounds: _, - ty, - semi_token, - } = FlexibleItemType::parse(input, TypeDefaultness::Disallowed, WhereClauseLocation::Both)?; - - if colon_token.is_some() || ty.is_some() { - Ok(ForeignItem::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - Ok(ForeignItem::Type(ForeignItemType { - attrs: Vec::new(), - vis, - type_token, - ident, - generics, - semi_token, - })) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ForeignItemMacro { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let mac: Macro = input.parse()?; - let semi_token: Option<Token![;]> = - if mac.delimiter.is_brace() { None } else { Some(input.parse()?) }; - Ok(ForeignItemMacro { attrs, mac, semi_token }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemType { - fn parse(input: ParseStream) -> Result<Self> { - Ok(ItemType { - attrs: input.call(Attribute::parse_outer)?, - vis: input.parse()?, - type_token: input.parse()?, - ident: input.parse()?, - generics: { - let mut generics: Generics = input.parse()?; - generics.where_clause = input.parse()?; - generics - }, - eq_token: input.parse()?, - ty: input.parse()?, - semi_token: input.parse()?, - }) - } - } - - fn parse_item_type(begin: Cursor, input: ParseStream) -> Result<Item> { - let FlexibleItemType { - vis, - defaultness: _, - type_token, - ident, - generics, - colon_token, - bounds: _, - ty, - semi_token, - } = FlexibleItemType::parse( - input, - TypeDefaultness::Disallowed, - WhereClauseLocation::BeforeEq, - )?; - - let (eq_token, ty) = match ty { - Some(ty) if colon_token.is_none() => ty, - _ => return Ok(Item::Verbatim(verbatim::between(begin, input.cursor()))), - }; - - Ok(Item::Type(ItemType { - attrs: Vec::new(), - vis, - type_token, - ident, - generics, - eq_token, - ty: Box::new(ty), - semi_token, - })) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemStruct { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse::<Visibility>()?; - let struct_token = input.parse::<Token![struct]>()?; - let ident = input.parse::<Ident>()?; - let generics = input.parse::<Generics>()?; - let (where_clause, fields, semi_token) = derive::parsing::data_struct(input)?; - Ok(ItemStruct { - attrs, - vis, - struct_token, - ident, - generics: Generics { where_clause, ..generics }, - fields, - semi_token, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemEnum { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse::<Visibility>()?; - let enum_token = input.parse::<Token![enum]>()?; - let ident = input.parse::<Ident>()?; - let generics = input.parse::<Generics>()?; - let (where_clause, brace_token, variants) = derive::parsing::data_enum(input)?; - Ok(ItemEnum { - attrs, - vis, - enum_token, - ident, - generics: Generics { where_clause, ..generics }, - brace_token, - variants, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemUnion { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis = input.parse::<Visibility>()?; - let union_token = input.parse::<Token![union]>()?; - let ident = input.parse::<Ident>()?; - let generics = input.parse::<Generics>()?; - let (where_clause, fields) = derive::parsing::data_union(input)?; - Ok(ItemUnion { - attrs, - vis, - union_token, - ident, - generics: Generics { where_clause, ..generics }, - fields, - }) - } - } - - fn parse_trait_or_trait_alias(input: ParseStream) -> Result<Item> { - let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?; - let lookahead = input.lookahead1(); - if lookahead.peek(token::Brace) - || lookahead.peek(Token![:]) - || lookahead.peek(Token![where]) - { - let unsafety = None; - let auto_token = None; - parse_rest_of_trait( - input, - attrs, - vis, - unsafety, - auto_token, - trait_token, - ident, - generics, - ) - .map(Item::Trait) - } else if lookahead.peek(Token![=]) { - parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics) - .map(Item::TraitAlias) - } else { - Err(lookahead.error()) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemTrait { - fn parse(input: ParseStream) -> Result<Self> { - let outer_attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let unsafety: Option<Token![unsafe]> = input.parse()?; - let auto_token: Option<Token![auto]> = input.parse()?; - let trait_token: Token![trait] = input.parse()?; - let ident: Ident = input.parse()?; - let generics: Generics = input.parse()?; - parse_rest_of_trait( - input, - outer_attrs, - vis, - unsafety, - auto_token, - trait_token, - ident, - generics, - ) - } - } - - fn parse_rest_of_trait( - input: ParseStream, - mut attrs: Vec<Attribute>, - vis: Visibility, - unsafety: Option<Token![unsafe]>, - auto_token: Option<Token![auto]>, - trait_token: Token![trait], - ident: Ident, - mut generics: Generics, - ) -> Result<ItemTrait> { - let colon_token: Option<Token![:]> = input.parse()?; - - let mut supertraits = Punctuated::new(); - if colon_token.is_some() { - loop { - if input.peek(Token![where]) || input.peek(token::Brace) { - break; - } - supertraits.push_value({ - let allow_precise_capture = false; - let allow_const = true; - TypeParamBound::parse_single(input, allow_precise_capture, allow_const)? - }); - if input.peek(Token![where]) || input.peek(token::Brace) { - break; - } - supertraits.push_punct(input.parse()?); - } - } - - generics.where_clause = input.parse()?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let mut items = Vec::new(); - while !content.is_empty() { - items.push(content.parse()?); - } - - Ok(ItemTrait { - attrs, - vis, - unsafety, - auto_token, - restriction: None, - trait_token, - ident, - generics, - colon_token, - supertraits, - brace_token, - items, - }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemTraitAlias { - fn parse(input: ParseStream) -> Result<Self> { - let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?; - parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics) - } - } - - fn parse_start_of_trait_alias( - input: ParseStream, - ) -> Result<(Vec<Attribute>, Visibility, Token![trait], Ident, Generics)> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let trait_token: Token![trait] = input.parse()?; - let ident: Ident = input.parse()?; - let generics: Generics = input.parse()?; - Ok((attrs, vis, trait_token, ident, generics)) - } - - fn parse_rest_of_trait_alias( - input: ParseStream, - attrs: Vec<Attribute>, - vis: Visibility, - trait_token: Token![trait], - ident: Ident, - mut generics: Generics, - ) -> Result<ItemTraitAlias> { - let eq_token: Token![=] = input.parse()?; - - let mut bounds = Punctuated::new(); - loop { - if input.peek(Token![where]) || input.peek(Token![;]) { - break; - } - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = false; - TypeParamBound::parse_single(input, allow_precise_capture, allow_const)? - }); - if input.peek(Token![where]) || input.peek(Token![;]) { - break; - } - bounds.push_punct(input.parse()?); - } - - generics.where_clause = input.parse()?; - let semi_token: Token![;] = input.parse()?; - - Ok(ItemTraitAlias { - attrs, - vis, - trait_token, - ident, - generics, - eq_token, - bounds, - semi_token, - }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitItem { - fn parse(input: ParseStream) -> Result<Self> { - let begin = input.cursor(); - let mut attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let defaultness: Option<Token![default]> = input.parse()?; - let ahead = input.fork(); - - let lookahead = ahead.lookahead1(); - let allow_safe = false; - let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead, allow_safe) { - input.parse().map(TraitItem::Fn) - } else if lookahead.peek(Token![const]) { - let const_token: Token![const] = ahead.parse()?; - let lookahead = ahead.lookahead1(); - if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.advance_to(&ahead); - let ident = input.call(Ident::parse_any)?; - let mut generics: Generics = input.parse()?; - let colon_token: Token![:] = input.parse()?; - let ty: Type = input.parse()?; - let default = if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { - let expr: Expr = input.parse()?; - Some((eq_token, expr)) - } else { - None - }; - generics.where_clause = input.parse()?; - let semi_token: Token![;] = input.parse()?; - if generics.lt_token.is_none() && generics.where_clause.is_none() { - Ok(TraitItem::Const(TraitItemConst { - attrs: Vec::new(), - const_token, - ident, - generics, - colon_token, - ty, - default, - semi_token, - })) - } else { - return Ok(TraitItem::Verbatim(verbatim::between(begin, input.cursor()))); - } - } else if lookahead.peek(Token![async]) - || lookahead.peek(Token![unsafe]) - || lookahead.peek(Token![extern]) - || lookahead.peek(Token![fn]) - { - input.parse().map(TraitItem::Fn) - } else { - Err(lookahead.error()) - } - } else if lookahead.peek(Token![type]) { - parse_trait_item_type(begin, input) - } else if vis.is_inherited() - && defaultness.is_none() - && (lookahead.peek(Ident) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - || lookahead.peek(Token![::])) - { - input.parse().map(TraitItem::Macro) - } else { - Err(lookahead.error()) - }?; - - match (vis, defaultness) { - (Visibility::Inherited, None) => {} - _ => return Ok(TraitItem::Verbatim(verbatim::between(begin, input.cursor()))), - } - - let item_attrs = match &mut item { - TraitItem::Const(item) => &mut item.attrs, - TraitItem::Fn(item) => &mut item.attrs, - TraitItem::Type(item) => &mut item.attrs, - TraitItem::Macro(item) => &mut item.attrs, - TraitItem::Verbatim(_) => unreachable!(), - }; - attrs.append(item_attrs); - *item_attrs = attrs; - Ok(item) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitItemConst { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let const_token: Token![const] = input.parse()?; - - let lookahead = input.lookahead1(); - let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.call(Ident::parse_any)? - } else { - return Err(lookahead.error()); - }; - - let colon_token: Token![:] = input.parse()?; - let ty: Type = input.parse()?; - let default = if input.peek(Token![=]) { - let eq_token: Token![=] = input.parse()?; - let default: Expr = input.parse()?; - Some((eq_token, default)) - } else { - None - }; - let semi_token: Token![;] = input.parse()?; - - Ok(TraitItemConst { - attrs, - const_token, - ident, - generics: Generics::default(), - colon_token, - ty, - default, - semi_token, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitItemFn { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = input.call(Attribute::parse_outer)?; - let sig: Signature = input.parse()?; - - let lookahead = input.lookahead1(); - let (brace_token, stmts, semi_token) = if lookahead.peek(token::Brace) { - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - let stmts = content.call(Block::parse_within)?; - (Some(brace_token), stmts, None) - } else if lookahead.peek(Token![;]) { - let semi_token: Token![;] = input.parse()?; - (None, Vec::new(), Some(semi_token)) - } else { - return Err(lookahead.error()); - }; - - Ok(TraitItemFn { - attrs, - sig, - default: brace_token.map(|brace_token| Block { brace_token, stmts }), - semi_token, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitItemType { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let type_token: Token![type] = input.parse()?; - let ident: Ident = input.parse()?; - let mut generics: Generics = input.parse()?; - let (colon_token, bounds) = FlexibleItemType::parse_optional_bounds(input)?; - let default = FlexibleItemType::parse_optional_definition(input)?; - generics.where_clause = input.parse()?; - let semi_token: Token![;] = input.parse()?; - Ok(TraitItemType { - attrs, - type_token, - ident, - generics, - colon_token, - bounds, - default, - semi_token, - }) - } - } - - fn parse_trait_item_type(begin: Cursor, input: ParseStream) -> Result<TraitItem> { - let FlexibleItemType { - vis, - defaultness: _, - type_token, - ident, - generics, - colon_token, - bounds, - ty, - semi_token, - } = FlexibleItemType::parse( - input, - TypeDefaultness::Disallowed, - WhereClauseLocation::AfterEq, - )?; - - if vis.is_some() { - Ok(TraitItem::Verbatim(verbatim::between(begin, input.cursor()))) - } else { - Ok(TraitItem::Type(TraitItemType { - attrs: Vec::new(), - type_token, - ident, - generics, - colon_token, - bounds, - default: ty, - semi_token, - })) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TraitItemMacro { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let mac: Macro = input.parse()?; - let semi_token: Option<Token![;]> = - if mac.delimiter.is_brace() { None } else { Some(input.parse()?) }; - Ok(TraitItemMacro { attrs, mac, semi_token }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ItemImpl { - fn parse(input: ParseStream) -> Result<Self> { - let allow_verbatim_impl = false; - parse_impl(input, allow_verbatim_impl).map(Option::unwrap) - } - } - - fn parse_impl(input: ParseStream, allow_verbatim_impl: bool) -> Result<Option<ItemImpl>> { - let mut attrs = input.call(Attribute::parse_outer)?; - let has_visibility = allow_verbatim_impl && input.parse::<Visibility>()?.is_some(); - let defaultness: Option<Token![default]> = input.parse()?; - let unsafety: Option<Token![unsafe]> = input.parse()?; - let impl_token: Token![impl] = input.parse()?; - - let has_generics = generics::parsing::choose_generics_over_qpath(input); - let mut generics: Generics = - if has_generics { input.parse()? } else { Generics::default() }; - - let is_const_impl = allow_verbatim_impl - && (input.peek(Token![const]) || input.peek(Token![?]) && input.peek2(Token![const])); - if is_const_impl { - input.parse::<Option<Token![?]>>()?; - input.parse::<Token![const]>()?; - } - - let polarity = if input.peek(Token![!]) && !input.peek2(token::Brace) { - Some(input.parse::<Token![!]>()?) - } else { - None - }; - - #[cfg(not(feature = "printing"))] - let first_ty_span = input.span(); - let mut first_ty: Type = input.parse()?; - let self_ty: Type; - let trait_; - - let is_impl_for = input.peek(Token![for]); - if is_impl_for { - let for_token: Token![for] = input.parse()?; - let mut first_ty_ref = &first_ty; - while let Type::Group(ty) = first_ty_ref { - first_ty_ref = &ty.elem; - } - if let Type::Path(TypePath { qself: None, .. }) = first_ty_ref { - while let Type::Group(ty) = first_ty { - first_ty = *ty.elem; - } - if let Type::Path(TypePath { qself: None, path }) = first_ty { - trait_ = Some((polarity, path, for_token)); - } else { - unreachable!(); - } - } else if !allow_verbatim_impl { - #[cfg(feature = "printing")] - return Err(Error::new_spanned(first_ty_ref, "expected trait path")); - #[cfg(not(feature = "printing"))] - return Err(Error::new(first_ty_span, "expected trait path")); - } else { - trait_ = None; - } - self_ty = input.parse()?; - } else if let Some(polarity) = polarity { - return Err(Error::new(polarity.span, "inherent impls cannot be negative")); - } else { - trait_ = None; - self_ty = first_ty; - } - - generics.where_clause = input.parse()?; - - let content; - let brace_token = braced!(content in input); - attr::parsing::parse_inner(&content, &mut attrs)?; - - let mut items = Vec::new(); - while !content.is_empty() { - items.push(content.parse()?); - } - - if has_visibility || is_const_impl || is_impl_for && trait_.is_none() { - Ok(None) - } else { - Ok(Some(ItemImpl { - attrs, - defaultness, - unsafety, - impl_token, - generics, - trait_, - self_ty: Box::new(self_ty), - brace_token, - items, - })) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ImplItem { - fn parse(input: ParseStream) -> Result<Self> { - let begin = input.cursor(); - let mut attrs = input.call(Attribute::parse_outer)?; - let ahead = input.fork(); - let vis: Visibility = ahead.parse()?; - - let mut lookahead = ahead.lookahead1(); - let defaultness = if lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) { - let defaultness: Token![default] = ahead.parse()?; - lookahead = ahead.lookahead1(); - Some(defaultness) - } else { - None - }; - - let allow_safe = false; - let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead, allow_safe) { - let allow_omitted_body = true; - if let Some(item) = parse_impl_item_fn(input, allow_omitted_body)? { - Ok(ImplItem::Fn(item)) - } else { - Ok(ImplItem::Verbatim(verbatim::between(begin, input.cursor()))) - } - } else if lookahead.peek(Token![const]) { - input.advance_to(&ahead); - let const_token: Token![const] = input.parse()?; - let lookahead = input.lookahead1(); - let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.call(Ident::parse_any)? - } else { - return Err(lookahead.error()); - }; - let mut generics: Generics = input.parse()?; - let colon_token: Token![:] = input.parse()?; - let ty: Type = input.parse()?; - let value = if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { - let expr: Expr = input.parse()?; - Some((eq_token, expr)) - } else { - None - }; - generics.where_clause = input.parse()?; - let semi_token: Token![;] = input.parse()?; - return match value { - Some((eq_token, expr)) - if generics.lt_token.is_none() && generics.where_clause.is_none() => - { - Ok(ImplItem::Const(ImplItemConst { - attrs, - vis, - defaultness, - const_token, - ident, - generics, - colon_token, - ty, - eq_token, - expr, - semi_token, - })) - } - _ => Ok(ImplItem::Verbatim(verbatim::between(begin, input.cursor()))), - }; - } else if lookahead.peek(Token![type]) { - parse_impl_item_type(begin, input) - } else if vis.is_inherited() - && defaultness.is_none() - && (lookahead.peek(Ident) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - || lookahead.peek(Token![::])) - { - input.parse().map(ImplItem::Macro) - } else { - Err(lookahead.error()) - }?; - - { - let item_attrs = match &mut item { - ImplItem::Const(item) => &mut item.attrs, - ImplItem::Fn(item) => &mut item.attrs, - ImplItem::Type(item) => &mut item.attrs, - ImplItem::Macro(item) => &mut item.attrs, - ImplItem::Verbatim(_) => return Ok(item), - }; - attrs.append(item_attrs); - *item_attrs = attrs; - } - - Ok(item) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ImplItemConst { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let defaultness: Option<Token![default]> = input.parse()?; - let const_token: Token![const] = input.parse()?; - - let lookahead = input.lookahead1(); - let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.call(Ident::parse_any)? - } else { - return Err(lookahead.error()); - }; - - let colon_token: Token![:] = input.parse()?; - let ty: Type = input.parse()?; - let eq_token: Token![=] = input.parse()?; - let expr: Expr = input.parse()?; - let semi_token: Token![;] = input.parse()?; - - Ok(ImplItemConst { - attrs, - vis, - defaultness, - const_token, - ident, - generics: Generics::default(), - colon_token, - ty, - eq_token, - expr, - semi_token, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ImplItemFn { - fn parse(input: ParseStream) -> Result<Self> { - let allow_omitted_body = false; - parse_impl_item_fn(input, allow_omitted_body).map(Option::unwrap) - } - } - - fn parse_impl_item_fn( - input: ParseStream, - allow_omitted_body: bool, - ) -> Result<Option<ImplItemFn>> { - let mut attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let defaultness: Option<Token![default]> = input.parse()?; - let sig: Signature = input.parse()?; - - // Accept functions without a body in an impl block because rustc's - // *parser* does not reject them (the compilation error is emitted later - // than parsing) and it can be useful for macro DSLs. - if allow_omitted_body && input.parse::<Option<Token![;]>>()?.is_some() { - return Ok(None); - } - - let content; - let brace_token = braced!(content in input); - attrs.extend(content.call(Attribute::parse_inner)?); - let block = Block { brace_token, stmts: content.call(Block::parse_within)? }; - - Ok(Some(ImplItemFn { attrs, vis, defaultness, sig, block })) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ImplItemType { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - let defaultness: Option<Token![default]> = input.parse()?; - let type_token: Token![type] = input.parse()?; - let ident: Ident = input.parse()?; - let mut generics: Generics = input.parse()?; - let eq_token: Token![=] = input.parse()?; - let ty: Type = input.parse()?; - generics.where_clause = input.parse()?; - let semi_token: Token![;] = input.parse()?; - Ok(ImplItemType { - attrs, - vis, - defaultness, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - }) - } - } - - fn parse_impl_item_type(begin: Cursor, input: ParseStream) -> Result<ImplItem> { - let FlexibleItemType { - vis, - defaultness, - type_token, - ident, - generics, - colon_token, - bounds: _, - ty, - semi_token, - } = FlexibleItemType::parse( - input, - TypeDefaultness::Optional, - WhereClauseLocation::AfterEq, - )?; - - let (eq_token, ty) = match ty { - Some(ty) if colon_token.is_none() => ty, - _ => return Ok(ImplItem::Verbatim(verbatim::between(begin, input.cursor()))), - }; - - Ok(ImplItem::Type(ImplItemType { - attrs: Vec::new(), - vis, - defaultness, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - })) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ImplItemMacro { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let mac: Macro = input.parse()?; - let semi_token: Option<Token![;]> = - if mac.delimiter.is_brace() { None } else { Some(input.parse()?) }; - Ok(ImplItemMacro { attrs, mac, semi_token }) - } - } - - impl Visibility { - fn is_inherited(&self) -> bool { - match self { - Visibility::Inherited => true, - _ => false, - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for StaticMutability { - fn parse(input: ParseStream) -> Result<Self> { - let mut_token: Option<Token![mut]> = input.parse()?; - Ok(mut_token.map_or(StaticMutability::None, StaticMutability::Mut)) - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::attr::FilterAttrs; - use crate::data::Fields; - use crate::item::{ - ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType, ImplItemConst, - ImplItemFn, ImplItemMacro, ImplItemType, ItemConst, ItemEnum, ItemExternCrate, ItemFn, - ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, ItemTrait, - ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, Signature, StaticMutability, - TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, UseGlob, UseGroup, UseName, - UsePath, UseRename, Variadic, - }; - use crate::mac::MacroDelimiter; - use crate::path; - use crate::path::printing::PathStyle; - use crate::print::TokensOrDefault; - use crate::ty::Type; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemExternCrate { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.extern_token.to_tokens(tokens); - self.crate_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - if let Some((as_token, rename)) = &self.rename { - as_token.to_tokens(tokens); - rename.to_tokens(tokens); - } - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemUse { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.use_token.to_tokens(tokens); - self.leading_colon.to_tokens(tokens); - self.tree.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemStatic { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.static_token.to_tokens(tokens); - self.mutability.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.expr.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemConst { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.const_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.expr.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemFn { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.sig.to_tokens(tokens); - self.block.brace_token.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&self.block.stmts); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemMod { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.unsafety.to_tokens(tokens); - self.mod_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - if let Some((brace, items)) = &self.content { - brace.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(items); - }); - } else { - TokensOrDefault(&self.semi).to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemForeignMod { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.unsafety.to_tokens(tokens); - self.abi.to_tokens(tokens); - self.brace_token.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&self.items); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemType { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.type_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemEnum { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.enum_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.brace_token.surround(tokens, |tokens| { - self.variants.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemStruct { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.struct_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - match &self.fields { - Fields::Named(fields) => { - self.generics.where_clause.to_tokens(tokens); - fields.to_tokens(tokens); - } - Fields::Unnamed(fields) => { - fields.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - TokensOrDefault(&self.semi_token).to_tokens(tokens); - } - Fields::Unit => { - self.generics.where_clause.to_tokens(tokens); - TokensOrDefault(&self.semi_token).to_tokens(tokens); - } - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemUnion { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.union_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.fields.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemTrait { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.unsafety.to_tokens(tokens); - self.auto_token.to_tokens(tokens); - self.trait_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - if !self.supertraits.is_empty() { - TokensOrDefault(&self.colon_token).to_tokens(tokens); - self.supertraits.to_tokens(tokens); - } - self.generics.where_clause.to_tokens(tokens); - self.brace_token.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&self.items); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemTraitAlias { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.trait_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.bounds.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemImpl { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.defaultness.to_tokens(tokens); - self.unsafety.to_tokens(tokens); - self.impl_token.to_tokens(tokens); - self.generics.to_tokens(tokens); - if let Some((polarity, path, for_token)) = &self.trait_ { - polarity.to_tokens(tokens); - path.to_tokens(tokens); - for_token.to_tokens(tokens); - } - self.self_ty.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.brace_token.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&self.items); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ItemMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - path::printing::print_path(tokens, &self.mac.path, PathStyle::Mod); - self.mac.bang_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - match &self.mac.delimiter { - MacroDelimiter::Paren(paren) => { - paren.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens)); - } - MacroDelimiter::Brace(brace) => { - brace.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens)); - } - MacroDelimiter::Bracket(bracket) => { - bracket.surround(tokens, |tokens| self.mac.tokens.to_tokens(tokens)); - } - } - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for UsePath { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.ident.to_tokens(tokens); - self.colon2_token.to_tokens(tokens); - self.tree.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for UseName { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.ident.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for UseRename { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.ident.to_tokens(tokens); - self.as_token.to_tokens(tokens); - self.rename.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for UseGlob { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.star_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for UseGroup { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.brace_token.surround(tokens, |tokens| { - self.items.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TraitItemConst { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.const_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - if let Some((eq_token, default)) = &self.default { - eq_token.to_tokens(tokens); - default.to_tokens(tokens); - } - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TraitItemFn { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.sig.to_tokens(tokens); - match &self.default { - Some(block) => { - block.brace_token.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&block.stmts); - }); - } - None => { - TokensOrDefault(&self.semi_token).to_tokens(tokens); - } - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TraitItemType { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.type_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - if !self.bounds.is_empty() { - TokensOrDefault(&self.colon_token).to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - if let Some((eq_token, default)) = &self.default { - eq_token.to_tokens(tokens); - default.to_tokens(tokens); - } - self.generics.where_clause.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TraitItemMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.mac.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ImplItemConst { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.defaultness.to_tokens(tokens); - self.const_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.expr.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ImplItemFn { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.defaultness.to_tokens(tokens); - self.sig.to_tokens(tokens); - self.block.brace_token.surround(tokens, |tokens| { - tokens.append_all(self.attrs.inner()); - tokens.append_all(&self.block.stmts); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ImplItemType { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.defaultness.to_tokens(tokens); - self.type_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ImplItemMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.mac.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ForeignItemFn { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.sig.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ForeignItemStatic { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.static_token.to_tokens(tokens); - self.mutability.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ForeignItemType { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.vis.to_tokens(tokens); - self.type_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ForeignItemMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.mac.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Signature { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.constness.to_tokens(tokens); - self.asyncness.to_tokens(tokens); - self.unsafety.to_tokens(tokens); - self.abi.to_tokens(tokens); - self.fn_token.to_tokens(tokens); - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.paren_token.surround(tokens, |tokens| { - self.inputs.to_tokens(tokens); - if let Some(variadic) = &self.variadic { - if !self.inputs.empty_or_trailing() { - <Token![,]>::default().to_tokens(tokens); - } - variadic.to_tokens(tokens); - } - }); - self.output.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Receiver { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - if let Some((ampersand, lifetime)) = &self.reference { - ampersand.to_tokens(tokens); - lifetime.to_tokens(tokens); - } - self.mutability.to_tokens(tokens); - self.self_token.to_tokens(tokens); - if let Some(colon_token) = &self.colon_token { - colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - } else { - let consistent = match (&self.reference, &self.mutability, &*self.ty) { - (Some(_), mutability, Type::Reference(ty)) => { - mutability.is_some() == ty.mutability.is_some() - && match &*ty.elem { - Type::Path(ty) => ty.qself.is_none() && ty.path.is_ident("Self"), - _ => false, - } - } - (None, _, Type::Path(ty)) => ty.qself.is_none() && ty.path.is_ident("Self"), - _ => false, - }; - if !consistent { - <Token![:]>::default().to_tokens(tokens); - self.ty.to_tokens(tokens); - } - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Variadic { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - if let Some((pat, colon)) = &self.pat { - pat.to_tokens(tokens); - colon.to_tokens(tokens); - } - self.dots.to_tokens(tokens); - self.comma.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for StaticMutability { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - StaticMutability::None => {} - StaticMutability::Mut(mut_token) => mut_token.to_tokens(tokens), - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/lib.rs b/deps/crates/vendor/syn-v2/src/lib.rs deleted file mode 100644 index aeb74a20120c..000000000000 --- a/deps/crates/vendor/syn-v2/src/lib.rs +++ /dev/null @@ -1,1016 +0,0 @@ -//! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate) -//! -//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github -//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust -//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs -//! -//! <br> -//! -//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax -//! tree of Rust source code. -//! -//! Currently this library is geared toward use in Rust procedural macros, but -//! contains some APIs that may be useful more generally. -//! -//! - **Data structures** — Syn provides a complete syntax tree that can -//! represent any valid Rust source code. The syntax tree is rooted at -//! [`syn::File`] which represents a full source file, but there are other -//! entry points that may be useful to procedural macros including -//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`]. -//! -//! - **Derives** — Of particular interest to derive macros is -//! [`syn::DeriveInput`] which is any of the three legal input items to a -//! derive macro. An example below shows using this type in a library that can -//! derive implementations of a user-defined trait. -//! -//! - **Parsing** — Parsing in Syn is built around [parser functions] with the -//! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined -//! by Syn is individually parsable and may be used as a building block for -//! custom syntaxes, or you may dream up your own brand new syntax without -//! involving any of our syntax tree types. -//! -//! - **Location information** — Every token parsed by Syn is associated with a -//! `Span` that tracks line and column information back to the source of that -//! token. These spans allow a procedural macro to display detailed error -//! messages pointing to all the right places in the user's code. There is an -//! example of this below. -//! -//! - **Feature flags** — Functionality is aggressively feature gated so your -//! procedural macros enable only what they need, and do not pay in compile -//! time for all the rest. -//! -//! [`syn::File`]: File -//! [`syn::Item`]: Item -//! [`syn::Expr`]: Expr -//! [`syn::Type`]: Type -//! [`syn::DeriveInput`]: DeriveInput -//! [parser functions]: mod@parse -//! -//! <br> -//! -//! # Example of a derive macro -//! -//! The canonical derive macro using Syn looks like this. We write an ordinary -//! Rust function tagged with a `proc_macro_derive` attribute and the name of -//! the trait we are deriving. Any time that derive appears in the user's code, -//! the Rust compiler passes their data structure as tokens into our macro. We -//! get to execute arbitrary Rust code to figure out what to do with those -//! tokens, then hand some tokens back to the compiler to compile into the -//! user's crate. -//! -//! [`TokenStream`]: proc_macro::TokenStream -//! -//! ```toml -//! [dependencies] -//! syn = "2.0" -//! quote = "1.0" -//! -//! [lib] -//! proc-macro = true -//! ``` -//! -//! ``` -//! # extern crate proc_macro; -//! # -//! use proc_macro::TokenStream; -//! use quote::quote; -//! use syn::{parse_macro_input, DeriveInput}; -//! -//! # const IGNORE_TOKENS: &str = stringify! { -//! #[proc_macro_derive(MyMacro)] -//! # }; -//! pub fn my_macro(input: TokenStream) -> TokenStream { -//! // Parse the input tokens into a syntax tree -//! let input = parse_macro_input!(input as DeriveInput); -//! -//! // Build the output, possibly using quasi-quotation -//! let expanded = quote! { -//! // ... -//! }; -//! -//! // Hand the output tokens back to the compiler -//! TokenStream::from(expanded) -//! } -//! ``` -//! -//! The [`heapsize`] example directory shows a complete working implementation -//! of a derive macro. The example derives a `HeapSize` trait which computes an -//! estimate of the amount of heap memory owned by a value. -//! -//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize -//! -//! ``` -//! pub trait HeapSize { -//! /// Total number of bytes of heap memory owned by `self`. -//! fn heap_size_of_children(&self) -> usize; -//! } -//! ``` -//! -//! The derive macro allows users to write `#[derive(HeapSize)]` on data -//! structures in their program. -//! -//! ``` -//! # const IGNORE_TOKENS: &str = stringify! { -//! #[derive(HeapSize)] -//! # }; -//! struct Demo<'a, T: ?Sized> { -//! a: Box<T>, -//! b: u8, -//! c: &'a str, -//! d: String, -//! } -//! ``` -//! -//! <p><br></p> -//! -//! # Spans and error reporting -//! -//! The token-based procedural macro API provides great control over where the -//! compiler's error messages are displayed in user code. Consider the error the -//! user sees if one of their field types does not implement `HeapSize`. -//! -//! ``` -//! # const IGNORE_TOKENS: &str = stringify! { -//! #[derive(HeapSize)] -//! # }; -//! struct Broken { -//! ok: String, -//! bad: std::thread::Thread, -//! } -//! ``` -//! -//! By tracking span information all the way through the expansion of a -//! procedural macro as shown in the `heapsize` example, token-based macros in -//! Syn are able to trigger errors that directly pinpoint the source of the -//! problem. -//! -//! ```text -//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied -//! --> src/main.rs:7:5 -//! | -//! 7 | bad: std::thread::Thread, -//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread` -//! ``` -//! -//! <br> -//! -//! # Parsing a custom syntax -//! -//! The [`lazy-static`] example directory shows the implementation of a -//! `functionlike!(...)` procedural macro in which the input tokens are parsed -//! using Syn's parsing API. -//! -//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static -//! -//! The example reimplements the popular `lazy_static` crate from crates.io as a -//! procedural macro. -//! -//! ``` -//! # macro_rules! lazy_static { -//! # ($($tt:tt)*) => {} -//! # } -//! # -//! lazy_static! { -//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); -//! } -//! ``` -//! -//! The implementation shows how to trigger custom warnings and error messages -//! on the macro input. -//! -//! ```text -//! warning: come on, pick a more creative name -//! --> src/main.rs:10:16 -//! | -//! 10 | static ref FOO: String = "lazy_static".to_owned(); -//! | ^^^ -//! ``` -//! -//! <br> -//! -//! # Testing -//! -//! When testing macros, we often care not just that the macro can be used -//! successfully but also that when the macro is provided with invalid input it -//! produces maximally helpful error messages. Consider using the [`trybuild`] -//! crate to write tests for errors that are emitted by your macro or errors -//! detected by the Rust compiler in the expanded code following misuse of the -//! macro. Such tests help avoid regressions from later refactors that -//! mistakenly make an error no longer trigger or be less helpful than it used -//! to be. -//! -//! [`trybuild`]: https://github.com/dtolnay/trybuild -//! -//! <br> -//! -//! # Debugging -//! -//! When developing a procedural macro it can be helpful to look at what the -//! generated code looks like. Use `cargo rustc -- -Zunstable-options -//! -Zunpretty=expanded` or the [`cargo expand`] subcommand. -//! -//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand -//! -//! To show the expanded code for some crate that uses your procedural macro, -//! run `cargo expand` from that crate. To show the expanded code for one of -//! your own test cases, run `cargo expand --test the_test_case` where the last -//! argument is the name of the test file without the `.rs` extension. -//! -//! This write-up by Brandon W Maister discusses debugging in more detail: -//! [Debugging Rust's new Custom Derive system][debugging]. -//! -//! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ -//! -//! <br> -//! -//! # Optional features -//! -//! Syn puts a lot of functionality behind optional features in order to -//! optimize compile time for the most common use cases. The following features -//! are available. -//! -//! - **`derive`** *(enabled by default)* — Data structures for representing the -//! possible input to a derive macro, including structs and enums and types. -//! - **`full`** — Data structures for representing the syntax tree of all valid -//! Rust source code, including items and expressions. -//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into -//! a syntax tree node of a chosen type. -//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree -//! node as tokens of Rust source code. -//! - **`visit`** — Trait for traversing a syntax tree. -//! - **`visit-mut`** — Trait for traversing and mutating in place a syntax -//! tree. -//! - **`fold`** — Trait for transforming an owned syntax tree. -//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree -//! types. -//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree -//! types. -//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the -//! dynamic library libproc_macro from rustc toolchain. - -#![no_std] -#![doc(html_root_url = "https://docs.rs/syn/2.0.119")] -#![cfg_attr(docsrs, feature(doc_cfg), doc(auto_cfg = false))] -#![deny(unsafe_op_in_unsafe_fn)] -#![allow(non_camel_case_types)] -#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))] -#![allow( - clippy::bool_to_int_with_if, - clippy::cast_lossless, - clippy::cast_possible_truncation, - clippy::cast_possible_wrap, - clippy::cast_ptr_alignment, - clippy::default_trait_access, - clippy::derivable_impls, - clippy::diverging_sub_expression, - clippy::doc_markdown, - clippy::elidable_lifetime_names, - clippy::enum_glob_use, - clippy::expl_impl_clone_on_copy, - clippy::explicit_auto_deref, - clippy::fn_params_excessive_bools, - clippy::if_not_else, - clippy::inherent_to_string, - clippy::into_iter_without_iter, - clippy::items_after_statements, - clippy::large_enum_variant, - clippy::let_underscore_untyped, // https://github.com/rust-lang/rust-clippy/issues/10410 - clippy::manual_assert, - clippy::manual_let_else, - clippy::manual_map, - clippy::match_like_matches_macro, - clippy::match_same_arms, - clippy::match_wildcard_for_single_variants, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 - clippy::missing_errors_doc, - clippy::missing_panics_doc, - clippy::module_name_repetitions, - clippy::must_use_candidate, - clippy::needless_doctest_main, - clippy::needless_lifetimes, - clippy::needless_pass_by_value, - clippy::needless_update, - clippy::never_loop, - clippy::range_plus_one, - clippy::redundant_else, - clippy::ref_option, - clippy::return_self_not_must_use, - clippy::similar_names, - clippy::single_match_else, - clippy::struct_excessive_bools, - clippy::too_many_arguments, - clippy::too_many_lines, - clippy::trivially_copy_pass_by_ref, - clippy::type_complexity, - clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133 - clippy::uninhabited_references, - clippy::uninlined_format_args, - clippy::unnecessary_box_returns, - clippy::unnecessary_unwrap, - clippy::used_underscore_binding, - clippy::wildcard_imports, -)] -#![allow(unknown_lints, mismatched_lifetime_syntaxes)] - -extern crate alloc; -extern crate std; - -extern crate self as syn; - -#[cfg(feature = "proc-macro")] -extern crate proc_macro; - -#[macro_use] -mod macros; - -#[cfg(feature = "parsing")] -#[macro_use] -mod group; - -#[macro_use] -pub mod token; - -#[cfg(any(feature = "full", feature = "derive"))] -mod attr; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; - -mod bigint; - -#[cfg(feature = "parsing")] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -pub mod buffer; - -#[cfg(any( - all(feature = "parsing", feature = "full"), - all(feature = "printing", any(feature = "full", feature = "derive")), -))] -mod classify; - -mod custom_keyword; - -mod custom_punctuation; - -#[cfg(any(feature = "full", feature = "derive"))] -mod data; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant}; - -#[cfg(any(feature = "full", feature = "derive"))] -mod derive; -#[cfg(feature = "derive")] -#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] -pub use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; - -mod drops; - -mod error; -pub use crate::error::{Error, Result}; - -#[cfg(any(feature = "full", feature = "derive"))] -mod expr; -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::expr::{Arm, Label, PointerMutability, RangeLimits}; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::expr::{ - Expr, ExprBinary, ExprCall, ExprCast, ExprField, ExprIndex, ExprLit, ExprMacro, ExprMethodCall, - ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member, -}; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::expr::{ - ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprClosure, ExprConst, - ExprContinue, ExprForLoop, ExprGroup, ExprIf, ExprInfer, ExprLet, ExprLoop, ExprMatch, - ExprRange, ExprRawAddr, ExprRepeat, ExprReturn, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe, - ExprWhile, ExprYield, -}; - -pub mod ext; - -#[cfg(feature = "full")] -mod file; -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::file::File; - -#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] -mod fixup; - -#[cfg(any(feature = "full", feature = "derive"))] -mod generics; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::generics::{ - BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime, - PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause, - WherePredicate, -}; -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::generics::{CapturedParam, PreciseCapture}; -#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] -#[cfg_attr( - docsrs, - doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))) -)] -pub use crate::generics::{ImplGenerics, Turbofish, TypeGenerics}; - -mod ident; -#[doc(inline)] -pub use crate::ident::Ident; - -#[cfg(feature = "full")] -mod item; -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::item::{ - FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, ForeignItemType, - ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, ImplRestriction, Item, - ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, - ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, - Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, - TraitItemType, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic, -}; - -mod lifetime; -#[doc(inline)] -pub use crate::lifetime::Lifetime; - -mod lit; -#[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566 -pub use crate::lit::StrStyle; -#[doc(inline)] -pub use crate::lit::{ - Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr, -}; - -#[cfg(feature = "parsing")] -mod lookahead; - -#[cfg(any(feature = "full", feature = "derive"))] -mod mac; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::mac::{Macro, MacroDelimiter}; - -#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))] -#[cfg_attr( - docsrs, - doc(cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))) -)] -pub mod meta; - -#[cfg(any(feature = "full", feature = "derive"))] -mod op; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::op::{BinOp, UnOp}; - -#[cfg(feature = "parsing")] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -pub mod parse; - -#[cfg(all(feature = "parsing", feature = "proc-macro"))] -mod parse_macro_input; - -#[cfg(all(feature = "parsing", feature = "printing"))] -mod parse_quote; - -#[cfg(feature = "full")] -mod pat; -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::pat::{ - FieldPat, Pat, PatConst, PatIdent, PatLit, PatMacro, PatOr, PatParen, PatPath, PatRange, - PatReference, PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild, -}; - -#[cfg(any(feature = "full", feature = "derive"))] -mod path; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::path::{ - AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, - ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, -}; - -#[cfg(all( - any(feature = "full", feature = "derive"), - any(feature = "parsing", feature = "printing") -))] -mod precedence; - -#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] -mod print; - -pub mod punctuated; - -#[cfg(any(feature = "full", feature = "derive"))] -mod restriction; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::restriction::{FieldMutability, VisRestricted, Visibility}; - -mod sealed; - -#[cfg(all(feature = "parsing", feature = "derive", not(feature = "full")))] -mod scan_expr; - -mod span; - -#[cfg(all(feature = "parsing", feature = "printing"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] -pub mod spanned; - -#[cfg(feature = "full")] -mod stmt; -#[cfg(feature = "full")] -#[cfg_attr(docsrs, doc(cfg(feature = "full")))] -pub use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro}; - -mod thread; - -#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))] -mod tt; - -#[cfg(any(feature = "full", feature = "derive"))] -mod ty; -#[cfg(any(feature = "full", feature = "derive"))] -#[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] -pub use crate::ty::{ - Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, - TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, - TypeSlice, TypeTraitObject, TypeTuple, -}; - -#[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))] -mod verbatim; - -#[cfg(all(feature = "parsing", feature = "full"))] -mod whitespace; - -#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176 -mod gen { - /// Syntax tree traversal to transform the nodes of an owned syntax tree. - /// - /// Each method of the [`Fold`] trait is a hook that can be overridden to - /// customize the behavior when transforming the corresponding type of node. - /// By default, every method recursively visits the substructure of the - /// input by invoking the right visitor method of each of its fields. - /// - /// [`Fold`]: fold::Fold - /// - /// ``` - /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; - /// # - /// pub trait Fold { - /// /* ... */ - /// - /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary { - /// fold_expr_binary(self, node) - /// } - /// - /// /* ... */ - /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute; - /// # fn fold_expr(&mut self, node: Expr) -> Expr; - /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp; - /// } - /// - /// pub fn fold_expr_binary<V>(v: &mut V, node: ExprBinary) -> ExprBinary - /// where - /// V: Fold + ?Sized, - /// { - /// ExprBinary { - /// attrs: node - /// .attrs - /// .into_iter() - /// .map(|attr| v.fold_attribute(attr)) - /// .collect(), - /// left: Box::new(v.fold_expr(*node.left)), - /// op: v.fold_bin_op(node.op), - /// right: Box::new(v.fold_expr(*node.right)), - /// } - /// } - /// - /// /* ... */ - /// ``` - /// - /// <br> - /// - /// # Example - /// - /// This fold inserts parentheses to fully parenthesizes any expression. - /// - /// ``` - /// // [dependencies] - /// // quote = "1.0" - /// // syn = { version = "2.0", features = ["fold", "full"] } - /// - /// use quote::quote; - /// use syn::fold::{fold_expr, Fold}; - /// use syn::{token, Expr, ExprParen}; - /// - /// struct ParenthesizeEveryExpr; - /// - /// impl Fold for ParenthesizeEveryExpr { - /// fn fold_expr(&mut self, expr: Expr) -> Expr { - /// Expr::Paren(ExprParen { - /// attrs: Vec::new(), - /// expr: Box::new(fold_expr(self, expr)), - /// paren_token: token::Paren::default(), - /// }) - /// } - /// } - /// - /// fn main() { - /// let code = quote! { a() + b(1) * c.d }; - /// let expr: Expr = syn::parse2(code).unwrap(); - /// let parenthesized = ParenthesizeEveryExpr.fold_expr(expr); - /// println!("{}", quote!(#parenthesized)); - /// - /// // Output: (((a)()) + (((b)((1))) * ((c).d))) - /// } - /// ``` - #[cfg(feature = "fold")] - #[cfg_attr(docsrs, doc(cfg(feature = "fold")))] - #[rustfmt::skip] - pub mod fold; - - /// Syntax tree traversal to walk a shared borrow of a syntax tree. - /// - /// Each method of the [`Visit`] trait is a hook that can be overridden to - /// customize the behavior when visiting the corresponding type of node. By - /// default, every method recursively visits the substructure of the input - /// by invoking the right visitor method of each of its fields. - /// - /// [`Visit`]: visit::Visit - /// - /// ``` - /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; - /// # - /// pub trait Visit<'ast> { - /// /* ... */ - /// - /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) { - /// visit_expr_binary(self, node); - /// } - /// - /// /* ... */ - /// # fn visit_attribute(&mut self, node: &'ast Attribute); - /// # fn visit_expr(&mut self, node: &'ast Expr); - /// # fn visit_bin_op(&mut self, node: &'ast BinOp); - /// } - /// - /// pub fn visit_expr_binary<'ast, V>(v: &mut V, node: &'ast ExprBinary) - /// where - /// V: Visit<'ast> + ?Sized, - /// { - /// for attr in &node.attrs { - /// v.visit_attribute(attr); - /// } - /// v.visit_expr(&*node.left); - /// v.visit_bin_op(&node.op); - /// v.visit_expr(&*node.right); - /// } - /// - /// /* ... */ - /// ``` - /// - /// <br> - /// - /// # Example - /// - /// This visitor will print the name of every freestanding function in the - /// syntax tree, including nested functions. - /// - /// ``` - /// // [dependencies] - /// // quote = "1.0" - /// // syn = { version = "2.0", features = ["full", "visit"] } - /// - /// use quote::quote; - /// use syn::visit::{self, Visit}; - /// use syn::{File, ItemFn}; - /// - /// struct FnVisitor; - /// - /// impl<'ast> Visit<'ast> for FnVisitor { - /// fn visit_item_fn(&mut self, node: &'ast ItemFn) { - /// println!("Function with name={}", node.sig.ident); - /// - /// // Delegate to the default impl to visit any nested functions. - /// visit::visit_item_fn(self, node); - /// } - /// } - /// - /// fn main() { - /// let code = quote! { - /// pub fn f() { - /// fn g() {} - /// } - /// }; - /// - /// let syntax_tree: File = syn::parse2(code).unwrap(); - /// FnVisitor.visit_file(&syntax_tree); - /// } - /// ``` - /// - /// The `'ast` lifetime on the input references means that the syntax tree - /// outlives the complete recursive visit call, so the visitor is allowed to - /// hold on to references into the syntax tree. - /// - /// ``` - /// use quote::quote; - /// use syn::visit::{self, Visit}; - /// use syn::{File, ItemFn}; - /// - /// struct FnVisitor<'ast> { - /// functions: Vec<&'ast ItemFn>, - /// } - /// - /// impl<'ast> Visit<'ast> for FnVisitor<'ast> { - /// fn visit_item_fn(&mut self, node: &'ast ItemFn) { - /// self.functions.push(node); - /// visit::visit_item_fn(self, node); - /// } - /// } - /// - /// fn main() { - /// let code = quote! { - /// pub fn f() { - /// fn g() {} - /// } - /// }; - /// - /// let syntax_tree: File = syn::parse2(code).unwrap(); - /// let mut visitor = FnVisitor { functions: Vec::new() }; - /// visitor.visit_file(&syntax_tree); - /// for f in visitor.functions { - /// println!("Function with name={}", f.sig.ident); - /// } - /// } - /// ``` - #[cfg(feature = "visit")] - #[cfg_attr(docsrs, doc(cfg(feature = "visit")))] - #[rustfmt::skip] - pub mod visit; - - /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in - /// place. - /// - /// Each method of the [`VisitMut`] trait is a hook that can be overridden - /// to customize the behavior when mutating the corresponding type of node. - /// By default, every method recursively visits the substructure of the - /// input by invoking the right visitor method of each of its fields. - /// - /// [`VisitMut`]: visit_mut::VisitMut - /// - /// ``` - /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; - /// # - /// pub trait VisitMut { - /// /* ... */ - /// - /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) { - /// visit_expr_binary_mut(self, node); - /// } - /// - /// /* ... */ - /// # fn visit_attribute_mut(&mut self, node: &mut Attribute); - /// # fn visit_expr_mut(&mut self, node: &mut Expr); - /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp); - /// } - /// - /// pub fn visit_expr_binary_mut<V>(v: &mut V, node: &mut ExprBinary) - /// where - /// V: VisitMut + ?Sized, - /// { - /// for attr in &mut node.attrs { - /// v.visit_attribute_mut(attr); - /// } - /// v.visit_expr_mut(&mut *node.left); - /// v.visit_bin_op_mut(&mut node.op); - /// v.visit_expr_mut(&mut *node.right); - /// } - /// - /// /* ... */ - /// ``` - /// - /// <br> - /// - /// # Example - /// - /// This mut visitor replace occurrences of u256 suffixed integer literals - /// like `999u256` with a macro invocation `bigint::u256!(999)`. - /// - /// ``` - /// // [dependencies] - /// // quote = "1.0" - /// // syn = { version = "2.0", features = ["full", "visit-mut"] } - /// - /// use quote::quote; - /// use syn::visit_mut::{self, VisitMut}; - /// use syn::{parse_quote, Expr, File, Lit, LitInt}; - /// - /// struct BigintReplace; - /// - /// impl VisitMut for BigintReplace { - /// fn visit_expr_mut(&mut self, node: &mut Expr) { - /// if let Expr::Lit(expr) = &node { - /// if let Lit::Int(int) = &expr.lit { - /// if int.suffix() == "u256" { - /// let digits = int.base10_digits(); - /// let unsuffixed: LitInt = syn::parse_str(digits).unwrap(); - /// *node = parse_quote!(bigint::u256!(#unsuffixed)); - /// return; - /// } - /// } - /// } - /// - /// // Delegate to the default impl to visit nested expressions. - /// visit_mut::visit_expr_mut(self, node); - /// } - /// } - /// - /// fn main() { - /// let code = quote! { - /// fn main() { - /// let _ = 999u256; - /// } - /// }; - /// - /// let mut syntax_tree: File = syn::parse2(code).unwrap(); - /// BigintReplace.visit_file_mut(&mut syntax_tree); - /// println!("{}", quote!(#syntax_tree)); - /// } - /// ``` - #[cfg(feature = "visit-mut")] - #[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))] - #[rustfmt::skip] - pub mod visit_mut; - - #[cfg(feature = "clone-impls")] - #[rustfmt::skip] - mod clone; - - #[cfg(feature = "extra-traits")] - #[rustfmt::skip] - mod debug; - - #[cfg(feature = "extra-traits")] - #[rustfmt::skip] - mod eq; - - #[cfg(feature = "extra-traits")] - #[rustfmt::skip] - mod hash; -} - -#[cfg(feature = "fold")] -#[cfg_attr(docsrs, doc(cfg(feature = "fold")))] -pub use crate::gen::fold; - -#[cfg(feature = "visit")] -#[cfg_attr(docsrs, doc(cfg(feature = "visit")))] -pub use crate::gen::visit; - -#[cfg(feature = "visit-mut")] -#[cfg_attr(docsrs, doc(cfg(feature = "visit-mut")))] -pub use crate::gen::visit_mut; - -// Not public API. -#[doc(hidden)] -#[path = "export.rs"] -pub mod __private; - -#[cfg(all(feature = "parsing", feature = "full"))] -use alloc::string::ToString; - -/// Parse tokens of source code into the chosen syntax tree node. -/// -/// This is preferred over parsing a string because tokens are able to preserve -/// information about where in the user's code they were originally written (the -/// "span" of the token), possibly allowing the compiler to produce better error -/// messages. -/// -/// This function parses a `proc_macro::TokenStream` which is the type used for -/// interop with the compiler in a procedural macro. To parse a -/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead. -/// -/// [`syn::parse2`]: parse2 -/// -/// This function enforces that the input is fully parsed. If there are any -/// unparsed tokens at the end of the stream, an error is returned. -#[cfg(all(feature = "parsing", feature = "proc-macro"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))] -pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> { - parse::Parser::parse(T::parse, tokens) -} - -/// Parse a proc-macro2 token stream into the chosen syntax tree node. -/// -/// This function parses a `proc_macro2::TokenStream` which is commonly useful -/// when the input comes from a node of the Syn syntax tree, for example the -/// body tokens of a [`Macro`] node. When in a procedural macro parsing the -/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`] -/// instead. -/// -/// [`syn::parse`]: parse() -/// -/// This function enforces that the input is fully parsed. If there are any -/// unparsed tokens at the end of the stream, an error is returned. -#[cfg(feature = "parsing")] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> { - parse::Parser::parse2(T::parse, tokens) -} - -/// Parse a string of Rust code into the chosen syntax tree node. -/// -/// This function enforces that the input is fully parsed. If there are any -/// unparsed tokens at the end of the stream, an error is returned. -/// -/// # Hygiene -/// -/// Every span in the resulting syntax tree will be set to resolve at the macro -/// call site. -/// -/// # Examples -/// -/// ``` -/// use syn::{Expr, Result}; -/// -/// fn run() -> Result<()> { -/// let code = "assert_eq!(u8::max_value(), 255)"; -/// let expr = syn::parse_str::<Expr>(code)?; -/// println!("{:#?}", expr); -/// Ok(()) -/// } -/// # -/// # run().unwrap(); -/// ``` -#[cfg(feature = "parsing")] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> { - parse::Parser::parse_str(T::parse, s) -} - -/// Parse the content of a file of Rust code. -/// -/// This is different from `syn::parse_str::<File>(content)` in two ways: -/// -/// - It discards a leading byte order mark `\u{FEFF}` if the file has one. -/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`. -/// -/// If present, either of these would be an error using `from_str`. -/// -/// # Examples -/// -/// ```no_run -/// use std::error::Error; -/// use std::fs; -/// use std::io::Read; -/// -/// fn run() -> Result<(), Box<dyn Error>> { -/// let content = fs::read_to_string("path/to/code.rs")?; -/// let ast = syn::parse_file(&content)?; -/// if let Some(shebang) = ast.shebang { -/// println!("{}", shebang); -/// } -/// println!("{} items", ast.items.len()); -/// -/// Ok(()) -/// } -/// # -/// # run().unwrap(); -/// ``` -#[cfg(all(feature = "parsing", feature = "full"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))] -pub fn parse_file(mut content: &str) -> Result<File> { - // Strip the BOM if it is present - const BOM: &str = "\u{feff}"; - if content.starts_with(BOM) { - content = &content[BOM.len()..]; - } - - let mut shebang = None; - if content.starts_with("#!") { - let rest = whitespace::skip(&content[2..]); - if !rest.starts_with('[') { - if let Some(idx) = content.find('\n') { - shebang = Some(content[..idx].to_string()); - content = &content[idx..]; - } else { - shebang = Some(content.to_string()); - content = ""; - } - } - } - - let mut file: File = parse_str(content)?; - file.shebang = shebang; - Ok(file) -} diff --git a/deps/crates/vendor/syn-v2/src/lifetime.rs b/deps/crates/vendor/syn-v2/src/lifetime.rs deleted file mode 100644 index eeaa39835409..000000000000 --- a/deps/crates/vendor/syn-v2/src/lifetime.rs +++ /dev/null @@ -1,155 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::lookahead; -use core::cmp::Ordering; -use core::fmt::{self, Display}; -use core::hash::{Hash, Hasher}; -use proc_macro2::{Ident, Span}; - -/// A Rust lifetime: `'a`. -/// -/// Lifetime names must conform to the following rules: -/// -/// - Must start with an apostrophe. -/// - Must not consist of just an apostrophe: `'`. -/// - Character after the apostrophe must be `_` or a Unicode code point with -/// the XID_Start property. -/// - All following characters must be Unicode code points with the XID_Continue -/// property. -pub struct Lifetime { - pub apostrophe: Span, - pub ident: Ident, -} - -impl Lifetime { - /// # Panics - /// - /// Panics if the lifetime does not conform to the bulleted rules above. - /// - /// # Invocation - /// - /// ``` - /// # use proc_macro2::Span; - /// # use syn::Lifetime; - /// # - /// # fn f() -> Lifetime { - /// Lifetime::new("'a", Span::call_site()) - /// # } - /// ``` - pub fn new(symbol: &str, span: Span) -> Self { - if !symbol.starts_with('\'') { - panic!( - "lifetime name must start with apostrophe as in \"'a\", got {:?}", - symbol - ); - } - - if symbol == "'" { - panic!("lifetime name must not be empty"); - } - - if !crate::ident::xid_ok(&symbol[1..]) { - panic!("{:?} is not a valid lifetime name", symbol); - } - - Lifetime { - apostrophe: span, - ident: Ident::new(&symbol[1..], span), - } - } - - pub fn span(&self) -> Span { - self.apostrophe - .join(self.ident.span()) - .unwrap_or(self.apostrophe) - } - - pub fn set_span(&mut self, span: Span) { - self.apostrophe = span; - self.ident.set_span(span); - } -} - -impl Display for Lifetime { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - "'".fmt(formatter)?; - self.ident.fmt(formatter) - } -} - -impl Clone for Lifetime { - fn clone(&self) -> Self { - Lifetime { - apostrophe: self.apostrophe, - ident: self.ident.clone(), - } - } -} - -impl PartialEq for Lifetime { - fn eq(&self, other: &Lifetime) -> bool { - self.ident.eq(&other.ident) - } -} - -impl Eq for Lifetime {} - -impl PartialOrd for Lifetime { - fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Lifetime { - fn cmp(&self, other: &Lifetime) -> Ordering { - self.ident.cmp(&other.ident) - } -} - -impl Hash for Lifetime { - fn hash<H: Hasher>(&self, h: &mut H) { - self.ident.hash(h); - } -} - -#[cfg(feature = "parsing")] -pub_if_not_doc! { - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime { - match marker {} - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::error::Result; - use crate::lifetime::Lifetime; - use crate::parse::{Parse, ParseStream}; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Lifetime { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| { - cursor - .lifetime() - .ok_or_else(|| cursor.error("expected lifetime")) - }) - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::ext::PunctExt as _; - use crate::lifetime::Lifetime; - use proc_macro2::{Punct, Spacing, TokenStream}; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Lifetime { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append(Punct::new_spanned('\'', Spacing::Joint, self.apostrophe)); - self.ident.to_tokens(tokens); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/lit.rs b/deps/crates/vendor/syn-v2/src/lit.rs deleted file mode 100644 index 403d8bac3e62..000000000000 --- a/deps/crates/vendor/syn-v2/src/lit.rs +++ /dev/null @@ -1,1928 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::ext::TokenStreamExt as _; -#[cfg(feature = "parsing")] -use crate::lookahead; -#[cfg(feature = "parsing")] -use crate::parse::{Parse, Parser}; -use crate::{Error, Result}; -use alloc::boxed::Box; -use alloc::ffi::CString; -#[cfg(feature = "parsing")] -use alloc::format; -use alloc::string::{String, ToString}; -use alloc::vec::Vec; -use core::ffi::CStr; -use core::fmt::{self, Display}; -#[cfg(feature = "extra-traits")] -use core::hash::{Hash, Hasher}; -use core::str::{self, FromStr}; -use proc_macro2::{Ident, Literal, Span}; -#[cfg(feature = "parsing")] -use proc_macro2::{TokenStream, TokenTree}; - -ast_enum_of_structs! { - /// A Rust literal such as a string or integer or boolean. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[non_exhaustive] - pub enum Lit { - /// A UTF-8 string literal: `"foo"`. - Str(LitStr), - - /// A byte string literal: `b"foo"`. - ByteStr(LitByteStr), - - /// A nul-terminated C-string literal: `c"foo"`. - CStr(LitCStr), - - /// A byte literal: `b'f'`. - Byte(LitByte), - - /// A character literal: `'a'`. - Char(LitChar), - - /// An integer literal: `1` or `1u16`. - Int(LitInt), - - /// A floating point literal: `1f64` or `1.0e10f64`. - /// - /// Must be finite. May not be infinite or NaN. - Float(LitFloat), - - /// A boolean literal: `true` or `false`. - Bool(LitBool), - - /// A raw token literal not interpreted by Syn. - Verbatim(Literal), - } -} - -ast_struct! { - /// A UTF-8 string literal: `"foo"`. - pub struct LitStr { - repr: Box<LitRepr>, - } -} - -ast_struct! { - /// A byte string literal: `b"foo"`. - pub struct LitByteStr { - repr: Box<LitRepr>, - } -} - -ast_struct! { - /// A nul-terminated C-string literal: `c"foo"`. - pub struct LitCStr { - repr: Box<LitRepr>, - } -} - -ast_struct! { - /// A byte literal: `b'f'`. - pub struct LitByte { - repr: Box<LitRepr>, - } -} - -ast_struct! { - /// A character literal: `'a'`. - pub struct LitChar { - repr: Box<LitRepr>, - } -} - -struct LitRepr { - token: Literal, - suffix: Box<str>, -} - -ast_struct! { - /// An integer literal: `1` or `1u16`. - pub struct LitInt { - repr: Box<LitIntRepr>, - } -} - -struct LitIntRepr { - token: Literal, - digits: Box<str>, - suffix: Box<str>, -} - -ast_struct! { - /// A floating point literal: `1f64` or `1.0e10f64`. - /// - /// Must be finite. May not be infinite or NaN. - pub struct LitFloat { - repr: Box<LitFloatRepr>, - } -} - -struct LitFloatRepr { - token: Literal, - digits: Box<str>, - suffix: Box<str>, -} - -ast_struct! { - /// A boolean literal: `true` or `false`. - pub struct LitBool { - pub value: bool, - pub span: Span, - } -} - -impl LitStr { - pub fn new(value: &str, span: Span) -> Self { - let mut token = Literal::string(value); - token.set_span(span); - LitStr { - repr: Box::new(LitRepr { - token, - suffix: Box::<str>::default(), - }), - } - } - - pub fn value(&self) -> String { - let repr = self.repr.token.to_string(); - let (value, _suffix) = value::parse_lit_str(&repr).unwrap(); - String::from(value) - } - - /// Parse a syntax tree node from the content of this string literal. - /// - /// All spans in the syntax tree will point to the span of this `LitStr`. - /// - /// # Example - /// - /// ``` - /// use syn::{Attribute, Error, Expr, Lit, Meta, Path, Result}; - /// - /// // Parses the path from an attribute that looks like: - /// // - /// // #[path = "a::b::c"] - /// // - /// // or returns `None` if the input is some other attribute. - /// fn get_path(attr: &Attribute) -> Result<Option<Path>> { - /// if !attr.path().is_ident("path") { - /// return Ok(None); - /// } - /// - /// if let Meta::NameValue(meta) = &attr.meta { - /// if let Expr::Lit(expr) = &meta.value { - /// if let Lit::Str(lit_str) = &expr.lit { - /// return lit_str.parse().map(Some); - /// } - /// } - /// } - /// - /// let message = "expected #[path = \"...\"]"; - /// Err(Error::new_spanned(attr, message)) - /// } - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse<T: Parse>(&self) -> Result<T> { - self.parse_with(T::parse) - } - - /// Invoke parser on the content of this string literal. - /// - /// All spans in the syntax tree will point to the span of this `LitStr`. - /// - /// # Example - /// - /// ``` - /// # use proc_macro2::Span; - /// # use syn::{LitStr, Result}; - /// # - /// # fn main() -> Result<()> { - /// # let lit_str = LitStr::new("a::b::c", Span::call_site()); - /// # - /// # const IGNORE: &str = stringify! { - /// let lit_str: LitStr = /* ... */; - /// # }; - /// - /// // Parse a string literal like "a::b::c" into a Path, not allowing - /// // generic arguments on any of the path segments. - /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?; - /// # - /// # Ok(()) - /// # } - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> { - use proc_macro2::Group; - - // Token stream with every span replaced by the given one. - fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream { - let mut tokens = TokenStream::new(); - for token in stream { - tokens.append(respan_token_tree(token, span)); - } - tokens - } - - // Token tree with every span replaced by the given one. - fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { - match &mut token { - TokenTree::Group(g) => { - let stream = respan_token_stream(g.stream(), span); - *g = Group::new(g.delimiter(), stream); - g.set_span(span); - } - other => other.set_span(span), - } - token - } - - // Parse string literal into a token stream with every span equal to the - // original literal's span. - let span = self.span(); - let mut tokens = TokenStream::from_str(&self.value())?; - tokens = respan_token_stream(tokens, span); - - let result = crate::parse::parse_scoped(parser, span, tokens)?; - - let suffix = self.suffix(); - if !suffix.is_empty() { - return Err(Error::new( - self.span(), - format!("unexpected suffix `{}` on string literal", suffix), - )); - } - - Ok(result) - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl LitByteStr { - pub fn new(value: &[u8], span: Span) -> Self { - let mut token = Literal::byte_string(value); - token.set_span(span); - LitByteStr { - repr: Box::new(LitRepr { - token, - suffix: Box::<str>::default(), - }), - } - } - - pub fn value(&self) -> Vec<u8> { - let repr = self.repr.token.to_string(); - let (value, _suffix) = value::parse_lit_byte_str(&repr).unwrap(); - value - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl LitCStr { - pub fn new(value: &CStr, span: Span) -> Self { - let mut token = Literal::c_string(value); - token.set_span(span); - LitCStr { - repr: Box::new(LitRepr { - token, - suffix: Box::<str>::default(), - }), - } - } - - pub fn value(&self) -> CString { - let repr = self.repr.token.to_string(); - let (value, _suffix) = value::parse_lit_c_str(&repr).unwrap(); - value - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl LitByte { - pub fn new(value: u8, span: Span) -> Self { - let mut token = Literal::byte_character(value); - token.set_span(span); - LitByte { - repr: Box::new(LitRepr { - token, - suffix: Box::<str>::default(), - }), - } - } - - pub fn value(&self) -> u8 { - let repr = self.repr.token.to_string(); - let (value, _suffix) = value::parse_lit_byte(&repr).unwrap(); - value - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl LitChar { - pub fn new(value: char, span: Span) -> Self { - let mut token = Literal::character(value); - token.set_span(span); - LitChar { - repr: Box::new(LitRepr { - token, - suffix: Box::<str>::default(), - }), - } - } - - pub fn value(&self) -> char { - let repr = self.repr.token.to_string(); - let (value, _suffix) = value::parse_lit_char(&repr).unwrap(); - value - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl LitInt { - #[track_caller] - pub fn new(repr: &str, span: Span) -> Self { - let (digits, suffix) = match value::parse_lit_int(repr) { - Some(parse) => parse, - None => panic!("not an integer literal: `{}`", repr), - }; - - let mut token: Literal = repr.parse().unwrap(); - token.set_span(span); - LitInt { - repr: Box::new(LitIntRepr { - token, - digits, - suffix, - }), - } - } - - pub fn base10_digits(&self) -> &str { - &self.repr.digits - } - - /// Parses the literal into a selected number type. - /// - /// This is equivalent to `lit.base10_digits().parse()` except that the - /// resulting errors will be correctly spanned to point to the literal token - /// in the macro input. - /// - /// ``` - /// use syn::LitInt; - /// use syn::parse::{Parse, ParseStream, Result}; - /// - /// struct Port { - /// value: u16, - /// } - /// - /// impl Parse for Port { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let lit: LitInt = input.parse()?; - /// let value = lit.base10_parse::<u16>()?; - /// Ok(Port { value }) - /// } - /// } - /// ``` - pub fn base10_parse<N>(&self) -> Result<N> - where - N: FromStr, - N::Err: Display, - { - self.base10_digits() - .parse() - .map_err(|err| Error::new(self.span(), err)) - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl From<Literal> for LitInt { - #[track_caller] - fn from(token: Literal) -> Self { - let repr = token.to_string(); - if let Some((digits, suffix)) = value::parse_lit_int(&repr) { - LitInt { - repr: Box::new(LitIntRepr { - token, - digits, - suffix, - }), - } - } else { - panic!("not an integer literal: `{}`", repr); - } - } -} - -impl Display for LitInt { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.repr.token.fmt(formatter) - } -} - -impl LitFloat { - #[track_caller] - pub fn new(repr: &str, span: Span) -> Self { - let (digits, suffix) = match value::parse_lit_float(repr) { - Some(parse) => parse, - None => panic!("not a float literal: `{}`", repr), - }; - - let mut token: Literal = repr.parse().unwrap(); - token.set_span(span); - LitFloat { - repr: Box::new(LitFloatRepr { - token, - digits, - suffix, - }), - } - } - - pub fn base10_digits(&self) -> &str { - &self.repr.digits - } - - pub fn base10_parse<N>(&self) -> Result<N> - where - N: FromStr, - N::Err: Display, - { - self.base10_digits() - .parse() - .map_err(|err| Error::new(self.span(), err)) - } - - pub fn suffix(&self) -> &str { - &self.repr.suffix - } - - pub fn span(&self) -> Span { - self.repr.token.span() - } - - pub fn set_span(&mut self, span: Span) { - self.repr.token.set_span(span); - } - - pub fn token(&self) -> Literal { - self.repr.token.clone() - } -} - -impl From<Literal> for LitFloat { - #[track_caller] - fn from(token: Literal) -> Self { - let repr = token.to_string(); - if let Some((digits, suffix)) = value::parse_lit_float(&repr) { - LitFloat { - repr: Box::new(LitFloatRepr { - token, - digits, - suffix, - }), - } - } else { - panic!("not a float literal: `{}`", repr); - } - } -} - -impl Display for LitFloat { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.repr.token.fmt(formatter) - } -} - -impl LitBool { - pub fn new(value: bool, span: Span) -> Self { - LitBool { value, span } - } - - pub fn value(&self) -> bool { - self.value - } - - pub fn span(&self) -> Span { - self.span - } - - pub fn set_span(&mut self, span: Span) { - self.span = span; - } - - pub fn token(&self) -> Ident { - let s = if self.value { "true" } else { "false" }; - Ident::new(s, self.span) - } -} - -#[cfg(feature = "extra-traits")] -mod debug_impls { - use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr}; - use core::fmt::{self, Debug}; - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitStr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitStr") - } - } - - impl LitStr { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitByteStr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitByteStr") - } - } - - impl LitByteStr { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitCStr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitCStr") - } - } - - impl LitCStr { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitByte { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitByte") - } - } - - impl LitByte { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitChar { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitChar") - } - } - - impl LitChar { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitInt { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitInt") - } - } - - impl LitInt { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitFloat { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitFloat") - } - } - - impl LitFloat { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("token", &format_args!("{}", self.repr.token)) - .finish() - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for LitBool { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - self.debug(formatter, "LitBool") - } - } - - impl LitBool { - pub(crate) fn debug(&self, formatter: &mut fmt::Formatter, name: &str) -> fmt::Result { - formatter - .debug_struct(name) - .field("value", &self.value) - .finish() - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for LitRepr { - fn clone(&self) -> Self { - LitRepr { - token: self.token.clone(), - suffix: self.suffix.clone(), - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for LitIntRepr { - fn clone(&self) -> Self { - LitIntRepr { - token: self.token.clone(), - digits: self.digits.clone(), - suffix: self.suffix.clone(), - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for LitFloatRepr { - fn clone(&self) -> Self { - LitFloatRepr { - token: self.token.clone(), - digits: self.digits.clone(), - suffix: self.suffix.clone(), - } - } -} - -macro_rules! lit_extra_traits { - ($ty:ident) => { - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Clone for $ty { - fn clone(&self) -> Self { - $ty { - repr: self.repr.clone(), - } - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl PartialEq for $ty { - fn eq(&self, other: &Self) -> bool { - self.repr.token.to_string() == other.repr.token.to_string() - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Hash for $ty { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - self.repr.token.to_string().hash(state); - } - } - - #[cfg(feature = "parsing")] - pub_if_not_doc! { - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn $ty(marker: lookahead::TokenMarker) -> $ty { - match marker {} - } - } - }; -} - -lit_extra_traits!(LitStr); -lit_extra_traits!(LitByteStr); -lit_extra_traits!(LitCStr); -lit_extra_traits!(LitByte); -lit_extra_traits!(LitChar); -lit_extra_traits!(LitInt); -lit_extra_traits!(LitFloat); - -#[cfg(feature = "parsing")] -pub_if_not_doc! { - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool { - match marker {} - } -} - -/// The style of a string literal, either plain quoted or a raw string like -/// `r##"data"##`. -#[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566 -pub enum StrStyle { - /// An ordinary string like `"data"`. - Cooked, - /// A raw string like `r##"data"##`. - /// - /// The unsigned integer is the number of `#` symbols used. - Raw(usize), -} - -#[cfg(feature = "parsing")] -pub_if_not_doc! { - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn Lit(marker: lookahead::TokenMarker) -> Lit { - match marker {} - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::buffer::Cursor; - use crate::error::Result; - use crate::lit::{ - value, Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt, - LitIntRepr, LitStr, - }; - use crate::parse::{Parse, ParseStream, Unexpected}; - use crate::token::{self, Token}; - use alloc::boxed::Box; - use alloc::rc::Rc; - use alloc::string::ToString; - use core::cell::Cell; - use proc_macro2::{Literal, Punct, Span}; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Lit { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| { - if let Some((lit, rest)) = cursor.literal() { - return Ok((Lit::new(lit), rest)); - } - - if let Some((ident, rest)) = cursor.ident() { - let value = ident == "true"; - if value || ident == "false" { - let lit_bool = LitBool { - value, - span: ident.span(), - }; - return Ok((Lit::Bool(lit_bool), rest)); - } - } - - if let Some((punct, rest)) = cursor.punct() { - if punct.as_char() == '-' { - if let Some((lit, rest)) = parse_negative_lit(punct, rest) { - return Ok((lit, rest)); - } - } - } - - Err(cursor.error("expected literal")) - }) - } - } - - fn parse_negative_lit(neg: Punct, cursor: Cursor) -> Option<(Lit, Cursor)> { - let (lit, rest) = cursor.literal()?; - - let mut span = neg.span(); - span = span.join(lit.span()).unwrap_or(span); - - let mut repr = lit.to_string(); - repr.insert(0, '-'); - - if let Some((digits, suffix)) = value::parse_lit_int(&repr) { - let mut token: Literal = repr.parse().unwrap(); - token.set_span(span); - return Some(( - Lit::Int(LitInt { - repr: Box::new(LitIntRepr { - token, - digits, - suffix, - }), - }), - rest, - )); - } - - let (digits, suffix) = value::parse_lit_float(&repr)?; - let mut token: Literal = repr.parse().unwrap(); - token.set_span(span); - Some(( - Lit::Float(LitFloat { - repr: Box::new(LitFloatRepr { - token, - digits, - suffix, - }), - }), - rest, - )) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitStr { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::Str(lit)) => Ok(lit), - _ => Err(head.error("expected string literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitByteStr { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::ByteStr(lit)) => Ok(lit), - _ => Err(head.error("expected byte string literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitCStr { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::CStr(lit)) => Ok(lit), - _ => Err(head.error("expected C string literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitByte { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::Byte(lit)) => Ok(lit), - _ => Err(head.error("expected byte literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitChar { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::Char(lit)) => Ok(lit), - _ => Err(head.error("expected character literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitInt { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::Int(lit)) => Ok(lit), - _ => Err(head.error("expected integer literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitFloat { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::Float(lit)) => Ok(lit), - _ => Err(head.error("expected floating point literal")), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for LitBool { - fn parse(input: ParseStream) -> Result<Self> { - let head = input.fork(); - match input.parse() { - Ok(Lit::Bool(lit)) => Ok(lit), - _ => Err(head.error("expected boolean literal")), - } - } - } - - fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool { - let scope = Span::call_site(); - let unexpected = Rc::new(Cell::new(Unexpected::None)); - let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected); - peek(&buffer) - } - - macro_rules! impl_token { - ($display:literal $name:ty) => { - impl Token for $name { - fn peek(cursor: Cursor) -> bool { - fn peek(input: ParseStream) -> bool { - <$name as Parse>::parse(input).is_ok() - } - peek_impl(cursor, peek) - } - - fn display() -> &'static str { - $display - } - } - - impl token::private::Sealed for $name {} - }; - } - - impl_token!("literal" Lit); - impl_token!("string literal" LitStr); - impl_token!("byte string literal" LitByteStr); - impl_token!("C-string literal" LitCStr); - impl_token!("byte literal" LitByte); - impl_token!("character literal" LitChar); - impl_token!("integer literal" LitInt); - impl_token!("floating point literal" LitFloat); - impl_token!("boolean literal" LitBool); -} - -#[cfg(feature = "printing")] -mod printing { - use crate::lit::{LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr}; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitStr { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitByteStr { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitCStr { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitByte { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitChar { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitInt { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitFloat { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.repr.token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for LitBool { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append(self.token()); - } - } -} - -mod value { - use crate::bigint::BigInt; - use crate::lit::{ - Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt, - LitIntRepr, LitRepr, LitStr, - }; - use alloc::borrow::ToOwned; - use alloc::boxed::Box; - use alloc::ffi::CString; - use alloc::string::{String, ToString}; - use alloc::vec::Vec; - use core::char; - use core::ops::{Index, RangeFrom}; - use proc_macro2::{Literal, Span}; - - impl Lit { - /// Interpret a Syn literal from a proc-macro2 literal. - pub fn new(token: Literal) -> Self { - let repr = token.to_string(); - Lit::from_str(token, &repr) - } - - #[cfg(fuzzing)] - #[doc(hidden)] - pub fn from_str_for_fuzzing(repr: &str) -> Self { - let token = Literal::u8_unsuffixed(0); - Lit::from_str(token, repr) - } - - fn from_str(token: Literal, repr: &str) -> Self { - match byte(repr, 0) { - // "...", r"...", r#"..."# - b'"' | b'r' => { - if let Some((_, suffix)) = parse_lit_str(repr) { - return Lit::Str(LitStr { - repr: Box::new(LitRepr { token, suffix }), - }); - } - } - b'b' => match byte(repr, 1) { - // b"...", br"...", br#"...#" - b'"' | b'r' => { - if let Some((_, suffix)) = parse_lit_byte_str(repr) { - return Lit::ByteStr(LitByteStr { - repr: Box::new(LitRepr { token, suffix }), - }); - } - } - // b'...' - b'\'' => { - if let Some((_, suffix)) = parse_lit_byte(repr) { - return Lit::Byte(LitByte { - repr: Box::new(LitRepr { token, suffix }), - }); - } - } - _ => {} - }, - b'c' => match byte(repr, 1) { - // c"...", cr"...", cr#"..."# - b'"' | b'r' => { - if let Some((_, suffix)) = parse_lit_c_str(repr) { - return Lit::CStr(LitCStr { - repr: Box::new(LitRepr { token, suffix }), - }); - } - } - _ => {} - }, - // '...' - b'\'' => { - if let Some((_, suffix)) = parse_lit_char(repr) { - return Lit::Char(LitChar { - repr: Box::new(LitRepr { token, suffix }), - }); - } - } - b'0'..=b'9' | b'-' => { - // 0, 123, 0xFF, 0o77, 0b11 - if let Some((digits, suffix)) = parse_lit_int(repr) { - return Lit::Int(LitInt { - repr: Box::new(LitIntRepr { - token, - digits, - suffix, - }), - }); - } - // 1.0, 1e-1, 1e+1 - if let Some((digits, suffix)) = parse_lit_float(repr) { - return Lit::Float(LitFloat { - repr: Box::new(LitFloatRepr { - token, - digits, - suffix, - }), - }); - } - } - // true, false - b't' | b'f' if repr == "true" || repr == "false" => { - return Lit::Bool(LitBool { - value: repr == "true", - span: token.span(), - }); - } - b'(' if repr == "(/*ERROR*/)" => return Lit::Verbatim(token), - _ => {} - } - - Lit::Verbatim(token) - } - - pub fn suffix(&self) -> &str { - match self { - Lit::Str(lit) => lit.suffix(), - Lit::ByteStr(lit) => lit.suffix(), - Lit::CStr(lit) => lit.suffix(), - Lit::Byte(lit) => lit.suffix(), - Lit::Char(lit) => lit.suffix(), - Lit::Int(lit) => lit.suffix(), - Lit::Float(lit) => lit.suffix(), - Lit::Bool(_) | Lit::Verbatim(_) => "", - } - } - - pub fn span(&self) -> Span { - match self { - Lit::Str(lit) => lit.span(), - Lit::ByteStr(lit) => lit.span(), - Lit::CStr(lit) => lit.span(), - Lit::Byte(lit) => lit.span(), - Lit::Char(lit) => lit.span(), - Lit::Int(lit) => lit.span(), - Lit::Float(lit) => lit.span(), - Lit::Bool(lit) => lit.span, - Lit::Verbatim(lit) => lit.span(), - } - } - - pub fn set_span(&mut self, span: Span) { - match self { - Lit::Str(lit) => lit.set_span(span), - Lit::ByteStr(lit) => lit.set_span(span), - Lit::CStr(lit) => lit.set_span(span), - Lit::Byte(lit) => lit.set_span(span), - Lit::Char(lit) => lit.set_span(span), - Lit::Int(lit) => lit.set_span(span), - Lit::Float(lit) => lit.set_span(span), - Lit::Bool(lit) => lit.span = span, - Lit::Verbatim(lit) => lit.set_span(span), - } - } - } - - /// Get the byte at offset idx, or a default of `b'\0'` if we're looking - /// past the end of the input buffer. - pub(crate) fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 { - let s = s.as_ref(); - if idx < s.len() { - s[idx] - } else { - 0 - } - } - - fn next_chr(s: &str) -> char { - s.chars().next().unwrap_or('\0') - } - - // Returns (content, suffix). - pub(crate) fn parse_lit_str(s: &str) -> Option<(Box<str>, Box<str>)> { - match byte(s, 0) { - b'"' => parse_lit_str_cooked(s), - b'r' => parse_lit_str_raw(s), - _ => unreachable!(), - } - } - - fn parse_lit_str_cooked(mut s: &str) -> Option<(Box<str>, Box<str>)> { - assert_eq!(byte(s, 0), b'"'); - s = &s[1..]; - - let mut content = String::new(); - 'outer: loop { - let ch = match byte(s, 0) { - b'"' => break, - b'\\' => { - let b = byte(s, 1); - s = s.get(2..)?; - match b { - b'x' => { - let (byte, rest) = backslash_x(s)?; - s = rest; - if byte > 0x7F { - // invalid \x byte in string literal - return None; - } - char::from(byte) - } - b'u' => { - let (ch, rest) = backslash_u(s)?; - s = rest; - ch - } - b'n' => '\n', - b'r' => '\r', - b't' => '\t', - b'\\' => '\\', - b'0' => '\0', - b'\'' => '\'', - b'"' => '"', - b'\r' | b'\n' => loop { - let b = byte(s, 0); - match b { - b' ' | b'\t' | b'\n' | b'\r' => s = &s[1..], - _ => continue 'outer, - } - }, - _ => { - // unexpected byte after backslash - return None; - } - } - } - b'\r' => { - if byte(s, 1) != b'\n' { - // bare carriage return not allowed in string - return None; - } - s = &s[2..]; - '\n' - } - _ => { - let ch = next_chr(s); - s = s.get(ch.len_utf8()..)?; - ch - } - }; - content.push(ch); - } - - assert!(s.starts_with('"')); - let content = content.into_boxed_str(); - let suffix = s[1..].to_owned().into_boxed_str(); - Some((content, suffix)) - } - - fn parse_lit_str_raw(mut s: &str) -> Option<(Box<str>, Box<str>)> { - assert_eq!(byte(s, 0), b'r'); - s = &s[1..]; - - let mut pounds = 0; - loop { - match byte(s, pounds) { - b'#' => pounds += 1, - b'"' => break, - _ => return None, - } - } - let close = s.rfind('"').unwrap(); - for end in s.get(close + 1..close + 1 + pounds)?.bytes() { - if end != b'#' { - return None; - } - } - - let content = s.get(pounds + 1..close)?.to_owned().into_boxed_str(); - let suffix = s[close + 1 + pounds..].to_owned().into_boxed_str(); - Some((content, suffix)) - } - - // Returns (content, suffix). - pub(crate) fn parse_lit_byte_str(s: &str) -> Option<(Vec<u8>, Box<str>)> { - assert_eq!(byte(s, 0), b'b'); - match byte(s, 1) { - b'"' => parse_lit_byte_str_cooked(s), - b'r' => parse_lit_byte_str_raw(s), - _ => unreachable!(), - } - } - - fn parse_lit_byte_str_cooked(mut s: &str) -> Option<(Vec<u8>, Box<str>)> { - assert_eq!(byte(s, 0), b'b'); - assert_eq!(byte(s, 1), b'"'); - s = &s[2..]; - - // We're going to want to have slices which don't respect codepoint boundaries. - let mut v = s.as_bytes(); - - let mut out = Vec::new(); - 'outer: loop { - let byte = match byte(v, 0) { - b'"' => break, - b'\\' => { - let b = byte(v, 1); - v = v.get(2..)?; - match b { - b'x' => { - let (b, rest) = backslash_x(v)?; - v = rest; - b - } - b'n' => b'\n', - b'r' => b'\r', - b't' => b'\t', - b'\\' => b'\\', - b'0' => b'\0', - b'\'' => b'\'', - b'"' => b'"', - b'\r' | b'\n' => loop { - let byte = byte(v, 0); - if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') { - v = &v[1..]; - } else { - continue 'outer; - } - }, - _ => { - // unexpected byte after backslash - return None; - } - } - } - b'\r' => { - if byte(v, 1) != b'\n' { - // bare carriage return not allowed in string - return None; - } - v = &v[2..]; - b'\n' - } - b => { - v = v.get(1..)?; - b - } - }; - out.push(byte); - } - - assert_eq!(byte(v, 0), b'"'); - let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str(); - Some((out, suffix)) - } - - fn parse_lit_byte_str_raw(s: &str) -> Option<(Vec<u8>, Box<str>)> { - assert_eq!(byte(s, 0), b'b'); - let (value, suffix) = parse_lit_str_raw(&s[1..])?; - Some((String::from(value).into_bytes(), suffix)) - } - - // Returns (content, suffix). - pub(crate) fn parse_lit_c_str(s: &str) -> Option<(CString, Box<str>)> { - assert_eq!(byte(s, 0), b'c'); - match byte(s, 1) { - b'"' => parse_lit_c_str_cooked(s), - b'r' => parse_lit_c_str_raw(s), - _ => unreachable!(), - } - } - - fn parse_lit_c_str_cooked(mut s: &str) -> Option<(CString, Box<str>)> { - assert_eq!(byte(s, 0), b'c'); - assert_eq!(byte(s, 1), b'"'); - s = &s[2..]; - - // We're going to want to have slices which don't respect codepoint boundaries. - let mut v = s.as_bytes(); - - let mut out = Vec::new(); - 'outer: loop { - let byte = match byte(v, 0) { - b'"' => break, - b'\\' => { - let b = byte(v, 1); - v = v.get(2..)?; - match b { - b'x' => { - let (b, rest) = backslash_x(v)?; - if b == 0 { - // \x00 is not allowed in C-string literal - return None; - } - v = rest; - b - } - b'u' => { - let (ch, rest) = backslash_u(v)?; - if ch == '\0' { - // \u{0} is not allowed in C-string literal - return None; - } - v = rest; - out.extend_from_slice(ch.encode_utf8(&mut [0u8; 4]).as_bytes()); - continue 'outer; - } - b'n' => b'\n', - b'r' => b'\r', - b't' => b'\t', - b'\\' => b'\\', - b'\'' => b'\'', - b'"' => b'"', - b'\r' | b'\n' => loop { - let byte = byte(v, 0); - if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') { - v = &v[1..]; - } else { - continue 'outer; - } - }, - _ => { - // unexpected byte after backslash - return None; - } - } - } - b'\r' => { - if byte(v, 1) != b'\n' { - // bare carriage return not allowed in string - return None; - } - v = &v[2..]; - b'\n' - } - b => { - v = v.get(1..)?; - b - } - }; - out.push(byte); - } - - assert_eq!(byte(v, 0), b'"'); - let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str(); - let cstring = CString::new(out).ok()?; - Some((cstring, suffix)) - } - - fn parse_lit_c_str_raw(s: &str) -> Option<(CString, Box<str>)> { - assert_eq!(byte(s, 0), b'c'); - let (value, suffix) = parse_lit_str_raw(&s[1..])?; - let cstring = CString::new(String::from(value)).ok()?; - Some((cstring, suffix)) - } - - // Returns (value, suffix). - pub(crate) fn parse_lit_byte(s: &str) -> Option<(u8, Box<str>)> { - assert_eq!(byte(s, 0), b'b'); - assert_eq!(byte(s, 1), b'\''); - - // We're going to want to have slices which don't respect codepoint boundaries. - let mut v = &s.as_bytes()[2..]; - - let b = match byte(v, 0) { - b'\\' => { - let b = byte(v, 1); - v = v.get(2..)?; - match b { - b'x' => { - let (b, rest) = backslash_x(v)?; - v = rest; - b - } - b'n' => b'\n', - b'r' => b'\r', - b't' => b'\t', - b'\\' => b'\\', - b'0' => b'\0', - b'\'' => b'\'', - b'"' => b'"', - _ => { - // unexpected byte after backslash - return None; - } - } - } - b => { - v = v.get(1..)?; - b - } - }; - - if byte(v, 0) != b'\'' { - return None; - } - - let suffix = s[s.len() - v.len() + 1..].to_owned().into_boxed_str(); - Some((b, suffix)) - } - - // Returns (value, suffix). - pub(crate) fn parse_lit_char(mut s: &str) -> Option<(char, Box<str>)> { - assert_eq!(byte(s, 0), b'\''); - s = &s[1..]; - - let ch = match byte(s, 0) { - b'\\' => { - let b = byte(s, 1); - s = s.get(2..)?; - match b { - b'x' => { - let (byte, rest) = backslash_x(s)?; - s = rest; - if byte > 0x7F { - // invalid \x byte in character literal - return None; - } - char::from(byte) - } - b'u' => { - let (ch, rest) = backslash_u(s)?; - s = rest; - ch - } - b'n' => '\n', - b'r' => '\r', - b't' => '\t', - b'\\' => '\\', - b'0' => '\0', - b'\'' => '\'', - b'"' => '"', - _ => { - // unexpected byte after backslash - return None; - } - } - } - _ => { - let ch = next_chr(s); - s = s.get(ch.len_utf8()..)?; - ch - } - }; - - if byte(s, 0) != b'\'' { - return None; - } - - let suffix = s[1..].to_owned().into_boxed_str(); - Some((ch, suffix)) - } - - fn backslash_x<S>(s: &S) -> Option<(u8, &S)> - where - S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized, - { - let mut ch = 0; - let b0 = byte(s, 0); - let b1 = byte(s, 1); - ch += 0x10 - * match b0 { - b'0'..=b'9' => b0 - b'0', - b'a'..=b'f' => 10 + (b0 - b'a'), - b'A'..=b'F' => 10 + (b0 - b'A'), - _ => return None, - }; - ch += match b1 { - b'0'..=b'9' => b1 - b'0', - b'a'..=b'f' => 10 + (b1 - b'a'), - b'A'..=b'F' => 10 + (b1 - b'A'), - _ => return None, - }; - Some((ch, &s[2..])) - } - - fn backslash_u<S>(mut s: &S) -> Option<(char, &S)> - where - S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized, - { - if byte(s, 0) != b'{' { - return None; - } - s = &s[1..]; - - let mut ch = 0; - let mut digits = 0; - loop { - let b = byte(s, 0); - let digit = match b { - b'0'..=b'9' => b - b'0', - b'a'..=b'f' => 10 + b - b'a', - b'A'..=b'F' => 10 + b - b'A', - b'_' if digits > 0 => { - s = &s[1..]; - continue; - } - b'}' if digits == 0 => return None, - b'}' => break, - _ => return None, - }; - if digits == 6 { - return None; - } - ch *= 0x10; - ch += u32::from(digit); - digits += 1; - s = &s[1..]; - } - if byte(s, 0) != b'}' { - return None; - } - s = &s[1..]; - - let ch = char::from_u32(ch)?; - Some((ch, s)) - } - - // Returns base 10 digits and suffix. - pub(crate) fn parse_lit_int(mut s: &str) -> Option<(Box<str>, Box<str>)> { - let negative = byte(s, 0) == b'-'; - if negative { - s = &s[1..]; - } - - let base = match (byte(s, 0), byte(s, 1)) { - (b'0', b'x') => { - s = &s[2..]; - 16 - } - (b'0', b'o') => { - s = &s[2..]; - 8 - } - (b'0', b'b') => { - s = &s[2..]; - 2 - } - (b'0'..=b'9', _) => 10, - _ => return None, - }; - - let mut value = BigInt::new(); - let mut has_digit = false; - 'outer: loop { - let b = byte(s, 0); - let digit = match b { - b'0'..=b'9' => b - b'0', - b'a'..=b'f' if base > 10 => b - b'a' + 10, - b'A'..=b'F' if base > 10 => b - b'A' + 10, - b'_' => { - s = &s[1..]; - continue; - } - // If looking at a floating point literal, we don't want to - // consider it an integer. - b'.' if base == 10 => return None, - b'e' | b'E' if base == 10 => { - let mut has_exp = false; - for (i, b) in s[1..].bytes().enumerate() { - match b { - b'_' => {} - b'-' | b'+' => return None, - b'0'..=b'9' => has_exp = true, - _ => { - let suffix = &s[1 + i..]; - if has_exp && crate::ident::xid_ok(suffix) { - return None; - } else { - break 'outer; - } - } - } - } - if has_exp { - return None; - } else { - break; - } - } - _ => break, - }; - - if digit >= base { - return None; - } - - has_digit = true; - value *= base; - value += digit; - s = &s[1..]; - } - - if !has_digit { - return None; - } - - let suffix = s; - if suffix.is_empty() || crate::ident::xid_ok(suffix) { - let mut repr = value.to_string(); - if negative { - repr.insert(0, '-'); - } - Some((repr.into_boxed_str(), suffix.to_owned().into_boxed_str())) - } else { - None - } - } - - // Returns base 10 digits and suffix. - pub(crate) fn parse_lit_float(input: &str) -> Option<(Box<str>, Box<str>)> { - // Rust's floating point literals are very similar to the ones parsed by - // the standard library, except that rust's literals can contain - // ignorable underscores. Let's remove those underscores. - - let mut bytes = input.to_owned().into_bytes(); - - let start = (*bytes.first()? == b'-') as usize; - match bytes.get(start)? { - b'0'..=b'9' => {} - _ => return None, - } - - let mut read = start; - let mut write = start; - let mut has_dot = false; - let mut has_e = false; - let mut has_sign = false; - let mut has_exponent = false; - while read < bytes.len() { - match bytes[read] { - b'_' => { - // Don't increase write - read += 1; - continue; - } - b'0'..=b'9' => { - if has_e { - has_exponent = true; - } - bytes[write] = bytes[read]; - } - b'.' => { - if has_e || has_dot { - return None; - } - has_dot = true; - bytes[write] = b'.'; - } - b'e' | b'E' => { - match bytes[read + 1..] - .iter() - .find(|b| **b != b'_') - .unwrap_or(&b'\0') - { - b'-' | b'+' | b'0'..=b'9' => {} - _ => break, - } - if has_e { - if has_exponent { - break; - } else { - return None; - } - } - has_e = true; - bytes[write] = b'e'; - } - b'-' | b'+' => { - if has_sign || has_exponent || !has_e { - return None; - } - has_sign = true; - if bytes[read] == b'-' { - bytes[write] = bytes[read]; - } else { - // Omit '+' - read += 1; - continue; - } - } - _ => break, - } - read += 1; - write += 1; - } - - if has_e && !has_exponent { - return None; - } - - let mut digits = String::from_utf8(bytes).unwrap(); - let suffix = digits.split_off(read); - digits.truncate(write); - if suffix.is_empty() || crate::ident::xid_ok(&suffix) { - Some((digits.into_boxed_str(), suffix.into_boxed_str())) - } else { - None - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/lookahead.rs b/deps/crates/vendor/syn-v2/src/lookahead.rs deleted file mode 100644 index 7e7e0315ad52..000000000000 --- a/deps/crates/vendor/syn-v2/src/lookahead.rs +++ /dev/null @@ -1,350 +0,0 @@ -use crate::buffer::Cursor; -use crate::error::{self, Error}; -use crate::sealed::lookahead::Sealed; -use crate::span::IntoSpans; -use crate::token::{CustomToken, Token}; -use alloc::format; -use alloc::vec::Vec; -use core::cell::RefCell; -use core::fmt::{self, Display}; -use proc_macro2::{Delimiter, Span}; - -/// Support for checking the next token in a stream to decide how to parse. -/// -/// An important advantage over [`ParseStream::peek`] is that here we -/// automatically construct an appropriate error message based on the token -/// alternatives that get peeked. If you are producing your own error message, -/// go ahead and use `ParseStream::peek` instead. -/// -/// Use [`ParseStream::lookahead1`] to construct this object. -/// -/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek -/// [`ParseStream::lookahead1`]: crate::parse::ParseBuffer::lookahead1 -/// -/// Consuming tokens from the source stream after constructing a lookahead -/// object does not also advance the lookahead object. -/// -/// # Example -/// -/// ``` -/// use syn::{ConstParam, Ident, Lifetime, LifetimeParam, Result, Token, TypeParam}; -/// use syn::parse::{Parse, ParseStream}; -/// -/// // A generic parameter, a single one of the comma-separated elements inside -/// // angle brackets in: -/// // -/// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } -/// // -/// // On invalid input, lookahead gives us a reasonable error message. -/// // -/// // error: expected one of: identifier, lifetime, `const` -/// // | -/// // 5 | fn f<!Sized>() {} -/// // | ^ -/// enum GenericParam { -/// Type(TypeParam), -/// Lifetime(LifetimeParam), -/// Const(ConstParam), -/// } -/// -/// impl Parse for GenericParam { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let lookahead = input.lookahead1(); -/// if lookahead.peek(Ident) { -/// input.parse().map(GenericParam::Type) -/// } else if lookahead.peek(Lifetime) { -/// input.parse().map(GenericParam::Lifetime) -/// } else if lookahead.peek(Token![const]) { -/// input.parse().map(GenericParam::Const) -/// } else { -/// Err(lookahead.error()) -/// } -/// } -/// } -/// ``` -pub struct Lookahead1<'a> { - scope: Span, - cursor: Cursor<'a>, - comparisons: RefCell<Vec<&'static str>>, -} - -pub(crate) fn new(scope: Span, cursor: Cursor) -> Lookahead1 { - Lookahead1 { - scope, - cursor, - comparisons: RefCell::new(Vec::new()), - } -} - -fn peek_impl( - lookahead: &Lookahead1, - peek: fn(Cursor) -> bool, - display: fn() -> &'static str, -) -> bool { - if peek(lookahead.cursor) { - return true; - } - lookahead.comparisons.borrow_mut().push(display()); - false -} - -impl<'a> Lookahead1<'a> { - /// Looks at the next token in the parse stream to determine whether it - /// matches the requested type of token. - /// - /// # Syntax - /// - /// Note that this method does not use turbofish syntax. Pass the peek type - /// inside of parentheses. - /// - /// - `input.peek(Token![struct])` - /// - `input.peek(Token![==])` - /// - `input.peek(Ident)` *(does not accept keywords)* - /// - `input.peek(Ident::peek_any)` - /// - `input.peek(Lifetime)` - /// - `input.peek(token::Brace)` - pub fn peek<T: Peek>(&self, token: T) -> bool { - let _ = token; - peek_impl(self, T::Token::peek, T::Token::display) - } - - /// Triggers an error at the current position of the parse stream. - /// - /// The error message will identify all of the expected token types that - /// have been peeked against this lookahead instance. - pub fn error(self) -> Error { - let mut comparisons = self.comparisons.into_inner(); - comparisons.retain_mut(|display| { - if *display == "`)`" { - *display = match self.cursor.scope_delimiter() { - Delimiter::Parenthesis => "`)`", - Delimiter::Brace => "`}`", - Delimiter::Bracket => "`]`", - Delimiter::None => return false, - } - } - true - }); - match comparisons.len() { - 0 => { - if self.cursor.eof() { - Error::new(self.scope, "unexpected end of input") - } else { - Error::new(self.cursor.span(), "unexpected token") - } - } - 1 => { - let message = format!("expected {}", comparisons[0]); - error::new_at(self.scope, self.cursor, message) - } - 2 => { - let message = format!("expected {} or {}", comparisons[0], comparisons[1]); - error::new_at(self.scope, self.cursor, message) - } - _ => { - let message = format!("expected one of: {}", CommaSeparated(&comparisons)); - error::new_at(self.scope, self.cursor, message) - } - } - } -} - -struct CommaSeparated<'a>(&'a [&'a str]); - -impl<'a> Display for CommaSeparated<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut first = true; - for &s in self.0 { - if !first { - f.write_str(", ")?; - } - f.write_str(s)?; - first = false; - } - Ok(()) - } -} - -/// Types that can be parsed by looking at just one token. -/// -/// Use [`ParseStream::peek`] to peek one of these types in a parse stream -/// without consuming it from the stream. -/// -/// This trait is sealed and cannot be implemented for types outside of Syn. -/// -/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek -pub trait Peek: Sealed { - // Not public API. - #[doc(hidden)] - type Token: Token; -} - -/// Pseudo-token used for peeking the end of a parse stream. -/// -/// This type is only useful as an argument to one of the following functions: -/// -/// - [`ParseStream::peek`][crate::parse::ParseBuffer::peek] -/// - [`ParseStream::peek2`][crate::parse::ParseBuffer::peek2] -/// - [`ParseStream::peek3`][crate::parse::ParseBuffer::peek3] -/// - [`Lookahead1::peek`] -/// -/// The peek will return `true` if there are no remaining tokens after that -/// point in the parse stream. -/// -/// # Example -/// -/// Suppose we are parsing attributes containing core::fmt inspired formatting -/// arguments: -/// -/// - `#[fmt("simple example")]` -/// - `#[fmt("interpolation e{}ample", self.x)]` -/// - `#[fmt("interpolation e{x}ample")]` -/// -/// and we want to recognize the cases where no interpolation occurs so that -/// more efficient code can be generated. -/// -/// The following implementation uses `input.peek(Token![,]) && -/// input.peek2(End)` to recognize the case of a trailing comma without -/// consuming the comma from the parse stream, because if it isn't a trailing -/// comma, that same comma needs to be parsed as part of `args`. -/// -/// ``` -/// use proc_macro2::TokenStream; -/// use quote::quote; -/// use syn::parse::{End, Parse, ParseStream, Result}; -/// use syn::{parse_quote, Attribute, LitStr, Token}; -/// -/// struct FormatArgs { -/// template: LitStr, // "...{}..." -/// args: TokenStream, // , self.x -/// } -/// -/// impl Parse for FormatArgs { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let template: LitStr = input.parse()?; -/// -/// let args = if input.is_empty() -/// || input.peek(Token![,]) && input.peek2(End) -/// { -/// input.parse::<Option<Token![,]>>()?; -/// TokenStream::new() -/// } else { -/// input.parse()? -/// }; -/// -/// Ok(FormatArgs { -/// template, -/// args, -/// }) -/// } -/// } -/// -/// fn main() -> Result<()> { -/// let attrs: Vec<Attribute> = parse_quote! { -/// #[fmt("simple example")] -/// #[fmt("interpolation e{}ample", self.x)] -/// #[fmt("interpolation e{x}ample")] -/// }; -/// -/// for attr in &attrs { -/// let FormatArgs { template, args } = attr.parse_args()?; -/// let requires_fmt_machinery = -/// !args.is_empty() || template.value().contains(['{', '}']); -/// let out = if requires_fmt_machinery { -/// quote! { -/// ::core::write!(__formatter, #template #args) -/// } -/// } else { -/// quote! { -/// __formatter.write_str(#template) -/// } -/// }; -/// println!("{}", out); -/// } -/// Ok(()) -/// } -/// ``` -/// -/// Implementing this parsing logic without `peek2(End)` is more clumsy because -/// we'd need a parse stream actually advanced past the comma before being able -/// to find out whether there is anything after it. It would look something -/// like: -/// -/// ``` -/// # use proc_macro2::TokenStream; -/// # use syn::parse::{ParseStream, Result}; -/// # use syn::Token; -/// # -/// # fn parse(input: ParseStream) -> Result<()> { -/// use syn::parse::discouraged::Speculative as _; -/// -/// let ahead = input.fork(); -/// ahead.parse::<Option<Token![,]>>()?; -/// let args = if ahead.is_empty() { -/// input.advance_to(&ahead); -/// TokenStream::new() -/// } else { -/// input.parse()? -/// }; -/// # Ok(()) -/// # } -/// ``` -/// -/// or: -/// -/// ``` -/// # use proc_macro2::TokenStream; -/// # use syn::parse::{ParseStream, Result}; -/// # use syn::Token; -/// # -/// # fn parse(input: ParseStream) -> Result<()> { -/// use quote::ToTokens as _; -/// -/// let comma: Option<Token![,]> = input.parse()?; -/// let mut args = TokenStream::new(); -/// if !input.is_empty() { -/// comma.to_tokens(&mut args); -/// input.parse::<TokenStream>()?.to_tokens(&mut args); -/// } -/// # Ok(()) -/// # } -/// ``` -pub struct End; - -impl Copy for End {} - -impl Clone for End { - fn clone(&self) -> Self { - *self - } -} - -impl Peek for End { - type Token = Self; -} - -impl CustomToken for End { - fn peek(cursor: Cursor) -> bool { - cursor.eof() - } - - fn display() -> &'static str { - "`)`" // Lookahead1 error message will fill in the expected close delimiter - } -} - -impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Peek for F { - type Token = T; -} - -pub enum TokenMarker {} - -impl<S> IntoSpans<S> for TokenMarker { - fn into_spans(self) -> S { - match self {} - } -} - -impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {} - -impl Sealed for End {} diff --git a/deps/crates/vendor/syn-v2/src/mac.rs b/deps/crates/vendor/syn-v2/src/mac.rs deleted file mode 100644 index 15107801cfee..000000000000 --- a/deps/crates/vendor/syn-v2/src/mac.rs +++ /dev/null @@ -1,225 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::error::Result; -#[cfg(feature = "parsing")] -use crate::parse::{Parse, ParseStream, Parser}; -use crate::path::Path; -use crate::token::{Brace, Bracket, Paren}; -use proc_macro2::extra::DelimSpan; -#[cfg(feature = "parsing")] -use proc_macro2::Delimiter; -use proc_macro2::TokenStream; -#[cfg(feature = "parsing")] -use proc_macro2::TokenTree; - -ast_struct! { - /// A macro invocation: `println!("{}", mac)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Macro { - pub path: Path, - pub bang_token: Token![!], - pub delimiter: MacroDelimiter, - pub tokens: TokenStream, - } -} - -ast_enum! { - /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum MacroDelimiter { - Paren(Paren), - Brace(Brace), - Bracket(Bracket), - } -} - -impl MacroDelimiter { - pub fn span(&self) -> &DelimSpan { - match self { - MacroDelimiter::Paren(token) => &token.span, - MacroDelimiter::Brace(token) => &token.span, - MacroDelimiter::Bracket(token) => &token.span, - } - } - - #[cfg(all(feature = "full", any(feature = "parsing", feature = "printing")))] - pub(crate) fn is_brace(&self) -> bool { - match self { - MacroDelimiter::Brace(_) => true, - MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false, - } - } -} - -impl Macro { - /// Parse the tokens within the macro invocation's delimiters into a syntax - /// tree. - /// - /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it - /// produces a more useful span when `tokens` is empty. - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token}; - /// use syn::ext::IdentExt; - /// use syn::parse::{Error, Parse, ParseStream, Result}; - /// use syn::punctuated::Punctuated; - /// - /// // The arguments expected by libcore's format_args macro, and as a - /// // result most other formatting and printing macros like println. - /// // - /// // println!("{} is {number:.prec$}", "x", prec=5, number=0.01) - /// struct FormatArgs { - /// format_string: Expr, - /// positional_args: Vec<Expr>, - /// named_args: Vec<(Ident, Expr)>, - /// } - /// - /// impl Parse for FormatArgs { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let format_string: Expr; - /// let mut positional_args = Vec::new(); - /// let mut named_args = Vec::new(); - /// - /// format_string = input.parse()?; - /// while !input.is_empty() { - /// input.parse::<Token![,]>()?; - /// if input.is_empty() { - /// break; - /// } - /// if input.peek(Ident::peek_any) && input.peek2(Token![=]) { - /// while !input.is_empty() { - /// let name: Ident = input.call(Ident::parse_any)?; - /// input.parse::<Token![=]>()?; - /// let value: Expr = input.parse()?; - /// named_args.push((name, value)); - /// if input.is_empty() { - /// break; - /// } - /// input.parse::<Token![,]>()?; - /// } - /// break; - /// } - /// positional_args.push(input.parse()?); - /// } - /// - /// Ok(FormatArgs { - /// format_string, - /// positional_args, - /// named_args, - /// }) - /// } - /// } - /// - /// // Extract the first argument, the format string literal, from an - /// // invocation of a formatting or printing macro. - /// fn get_format_string(m: &Macro) -> Result<LitStr> { - /// let args: FormatArgs = m.parse_body()?; - /// match args.format_string { - /// Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit), - /// other => { - /// // First argument was not a string literal expression. - /// // Maybe something like: println!(concat!(...), ...) - /// Err(Error::new_spanned(other, "format string must be a string literal")) - /// } - /// } - /// } - /// - /// fn main() { - /// let invocation = parse_quote! { - /// println!("{:?}", Instant::now()) - /// }; - /// let lit = get_format_string(&invocation).unwrap(); - /// assert_eq!(lit.value(), "{:?}"); - /// } - /// ``` - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_body<T: Parse>(&self) -> Result<T> { - self.parse_body_with(T::parse) - } - - /// Parse the tokens within the macro invocation's delimiters using the - /// given parser. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> { - let scope = self.delimiter.span().close(); - crate::parse::parse_scoped(parser, scope, self.tokens.clone()) - } -} - -#[cfg(feature = "parsing")] -pub(crate) fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> { - input.step(|cursor| { - if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() { - let span = g.delim_span(); - let delimiter = match g.delimiter() { - Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)), - Delimiter::Brace => MacroDelimiter::Brace(Brace(span)), - Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)), - Delimiter::None => { - return Err(cursor.error("expected delimiter")); - } - }; - Ok(((delimiter, g.stream()), rest)) - } else { - Err(cursor.error("expected delimiter")) - } - }) -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::error::Result; - use crate::mac::{parse_delimiter, Macro}; - use crate::parse::{Parse, ParseStream}; - use crate::path::Path; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Macro { - fn parse(input: ParseStream) -> Result<Self> { - let tokens; - Ok(Macro { - path: input.call(Path::parse_mod_style)?, - bang_token: input.parse()?, - delimiter: { - let (delimiter, content) = parse_delimiter(input)?; - tokens = content; - delimiter - }, - tokens, - }) - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::mac::{Macro, MacroDelimiter}; - use crate::path; - use crate::path::printing::PathStyle; - use crate::token; - use proc_macro2::{Delimiter, TokenStream}; - use quote::ToTokens; - - impl MacroDelimiter { - pub(crate) fn surround(&self, tokens: &mut TokenStream, inner: TokenStream) { - let (delim, span) = match self { - MacroDelimiter::Paren(paren) => (Delimiter::Parenthesis, paren.span), - MacroDelimiter::Brace(brace) => (Delimiter::Brace, brace.span), - MacroDelimiter::Bracket(bracket) => (Delimiter::Bracket, bracket.span), - }; - token::printing::delim(delim, span.join(), tokens, inner); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Macro { - fn to_tokens(&self, tokens: &mut TokenStream) { - path::printing::print_path(tokens, &self.path, PathStyle::Mod); - self.bang_token.to_tokens(tokens); - self.delimiter.surround(tokens, self.tokens.clone()); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/macros.rs b/deps/crates/vendor/syn-v2/src/macros.rs deleted file mode 100644 index c404ae1ab194..000000000000 --- a/deps/crates/vendor/syn-v2/src/macros.rs +++ /dev/null @@ -1,182 +0,0 @@ -#[cfg_attr( - not(any(feature = "full", feature = "derive")), - allow(unknown_lints, unused_macro_rules) -)] -macro_rules! ast_struct { - ( - $(#[$attr:meta])* - $pub:ident $struct:ident $name:ident #full $body:tt - ) => { - check_keyword_matches!(pub $pub); - check_keyword_matches!(struct $struct); - - #[cfg(feature = "full")] - $(#[$attr])* $pub $struct $name $body - - #[cfg(not(feature = "full"))] - $(#[$attr])* $pub $struct $name { - _noconstruct: ::core::marker::PhantomData<::proc_macro2::Span>, - } - - #[cfg(all(not(feature = "full"), feature = "printing"))] - impl ::quote::ToTokens for $name { - fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) { - unreachable!() - } - } - }; - - ( - $(#[$attr:meta])* - $pub:ident $struct:ident $name:ident $body:tt - ) => { - check_keyword_matches!(pub $pub); - check_keyword_matches!(struct $struct); - - $(#[$attr])* $pub $struct $name $body - }; -} - -#[cfg(any(feature = "full", feature = "derive"))] -macro_rules! ast_enum { - ( - $(#[$enum_attr:meta])* - $pub:ident $enum:ident $name:ident $body:tt - ) => { - check_keyword_matches!(pub $pub); - check_keyword_matches!(enum $enum); - - $(#[$enum_attr])* $pub $enum $name $body - }; -} - -macro_rules! ast_enum_of_structs { - ( - $(#[$enum_attr:meta])* - $pub:ident $enum:ident $name:ident $body:tt - ) => { - check_keyword_matches!(pub $pub); - check_keyword_matches!(enum $enum); - - $(#[$enum_attr])* $pub $enum $name $body - - ast_enum_of_structs_impl!($name $body); - - #[cfg(feature = "printing")] - generate_to_tokens!(() tokens $name $body); - }; -} - -macro_rules! ast_enum_of_structs_impl { - ( - $name:ident { - $( - $(#[cfg $cfg_attr:tt])* - $(#[doc $($doc_attr:tt)*])* - $variant:ident $( ($member:ident) )*, - )* - } - ) => { - $($( - ast_enum_from_struct!($name::$variant, $member); - )*)* - }; -} - -macro_rules! ast_enum_from_struct { - // No From<TokenStream> for verbatim variants. - ($name:ident::Verbatim, $member:ident) => {}; - - ($name:ident::$variant:ident, $member:ident) => { - impl From<$member> for $name { - fn from(e: $member) -> $name { - $name::$variant(e) - } - } - }; -} - -#[cfg(feature = "printing")] -macro_rules! generate_to_tokens { - ( - ($($arms:tt)*) $tokens:ident $name:ident { - $(#[cfg $cfg_attr:tt])* - $(#[doc $($doc_attr:tt)*])* - $variant:ident, - $($next:tt)* - } - ) => { - generate_to_tokens!( - ($($arms)* $(#[cfg $cfg_attr])* $name::$variant => {}) - $tokens $name { $($next)* } - ); - }; - - ( - ($($arms:tt)*) $tokens:ident $name:ident { - $(#[cfg $cfg_attr:tt])* - $(#[doc $($doc_attr:tt)*])* - $variant:ident($member:ident), - $($next:tt)* - } - ) => { - generate_to_tokens!( - ($($arms)* $(#[cfg $cfg_attr])* $name::$variant(_e) => _e.to_tokens($tokens),) - $tokens $name { $($next)* } - ); - }; - - (($($arms:tt)*) $tokens:ident $name:ident {}) => { - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ::quote::ToTokens for $name { - fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) { - match self { - $($arms)* - } - } - } - }; -} - -// Rustdoc bug: does not respect the doc(hidden) on some items. -#[cfg(all(doc, feature = "parsing"))] -macro_rules! pub_if_not_doc { - ($(#[$m:meta])* $pub:ident $($item:tt)*) => { - check_keyword_matches!(pub $pub); - - $(#[$m])* - $pub(crate) $($item)* - }; -} - -#[cfg(all(not(doc), feature = "parsing"))] -macro_rules! pub_if_not_doc { - ($(#[$m:meta])* $pub:ident $($item:tt)*) => { - check_keyword_matches!(pub $pub); - - $(#[$m])* - $pub $($item)* - }; -} - -macro_rules! check_keyword_matches { - (enum enum) => {}; - (pub pub) => {}; - (struct struct) => {}; -} - -#[cfg(any(feature = "full", feature = "derive"))] -macro_rules! return_impl_trait { - ( - $(#[$attr:meta])* - $vis:vis fn $name:ident $args:tt -> $impl_trait:ty [$concrete:ty] $body:block - ) => { - #[cfg(not(docsrs))] - $(#[$attr])* - $vis fn $name $args -> $concrete $body - - #[cfg(docsrs)] - $(#[$attr])* - $vis fn $name $args -> $impl_trait $body - }; -} diff --git a/deps/crates/vendor/syn-v2/src/meta.rs b/deps/crates/vendor/syn-v2/src/meta.rs deleted file mode 100644 index 3112db7566a3..000000000000 --- a/deps/crates/vendor/syn-v2/src/meta.rs +++ /dev/null @@ -1,427 +0,0 @@ -//! Facility for interpreting structured content inside of an `Attribute`. - -use crate::error::{Error, Result}; -use crate::ext::IdentExt as _; -use crate::lit::Lit; -use crate::parse::{ParseStream, Parser}; -use crate::path::{Path, PathSegment}; -use crate::punctuated::Punctuated; -use core::fmt::Display; -use proc_macro2::Ident; - -/// Make a parser that is usable with `parse_macro_input!` in a -/// `#[proc_macro_attribute]` macro. -/// -/// *Warning:* When parsing attribute args **other than** the -/// `proc_macro::TokenStream` input of a `proc_macro_attribute`, you do **not** -/// need this function. In several cases your callers will get worse error -/// messages if you use this function, because the surrounding delimiter's span -/// is concealed from attribute macros by rustc. Use -/// [`Attribute::parse_nested_meta`] instead. -/// -/// [`Attribute::parse_nested_meta`]: crate::Attribute::parse_nested_meta -/// -/// # Example -/// -/// This example implements an attribute macro whose invocations look like this: -/// -/// ``` -/// # const IGNORE: &str = stringify! { -/// #[tea(kind = "EarlGrey", hot)] -/// struct Picard {...} -/// # }; -/// ``` -/// -/// The "parameters" supported by the attribute are: -/// -/// - `kind = "..."` -/// - `hot` -/// - `with(sugar, milk, ...)`, a comma-separated list of ingredients -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::{parse_macro_input, LitStr, Path}; -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_attribute] -/// # }; -/// pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream { -/// let mut kind: Option<LitStr> = None; -/// let mut hot: bool = false; -/// let mut with: Vec<Path> = Vec::new(); -/// let tea_parser = syn::meta::parser(|meta| { -/// if meta.path.is_ident("kind") { -/// kind = Some(meta.value()?.parse()?); -/// Ok(()) -/// } else if meta.path.is_ident("hot") { -/// hot = true; -/// Ok(()) -/// } else if meta.path.is_ident("with") { -/// meta.parse_nested_meta(|meta| { -/// with.push(meta.path); -/// Ok(()) -/// }) -/// } else { -/// Err(meta.error("unsupported tea property")) -/// } -/// }); -/// -/// parse_macro_input!(args with tea_parser); -/// eprintln!("kind={kind:?} hot={hot} with={with:?}"); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// ``` -/// -/// The `syn::meta` library will take care of dealing with the commas including -/// trailing commas, and producing sensible error messages on unexpected input. -/// -/// ```console -/// error: expected `,` -/// --> src/main.rs:3:37 -/// | -/// 3 | #[tea(kind = "EarlGrey", with(sugar = "lol", milk))] -/// | ^ -/// ``` -/// -/// # Example -/// -/// Same as above but we factor out most of the logic into a separate function. -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::meta::ParseNestedMeta; -/// use syn::parse::{Parser, Result}; -/// use syn::{parse_macro_input, LitStr, Path}; -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_attribute] -/// # }; -/// pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream { -/// let mut attrs = TeaAttributes::default(); -/// let tea_parser = syn::meta::parser(|meta| attrs.parse(meta)); -/// parse_macro_input!(args with tea_parser); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// -/// #[derive(Default)] -/// struct TeaAttributes { -/// kind: Option<LitStr>, -/// hot: bool, -/// with: Vec<Path>, -/// } -/// -/// impl TeaAttributes { -/// fn parse(&mut self, meta: ParseNestedMeta) -> Result<()> { -/// if meta.path.is_ident("kind") { -/// self.kind = Some(meta.value()?.parse()?); -/// Ok(()) -/// } else /* just like in last example */ -/// # { unimplemented!() } -/// -/// } -/// } -/// ``` -pub fn parser(logic: impl FnMut(ParseNestedMeta) -> Result<()>) -> impl Parser<Output = ()> { - |input: ParseStream| { - if input.is_empty() { - Ok(()) - } else { - parse_nested_meta(input, logic) - } - } -} - -/// Context for parsing a single property in the conventional syntax for -/// structured attributes. -/// -/// # Examples -/// -/// Refer to usage examples on the following two entry-points: -/// -/// - [`Attribute::parse_nested_meta`] if you have an entire `Attribute` to -/// parse. Always use this if possible. Generally this is able to produce -/// better error messages because `Attribute` holds span information for all -/// of the delimiters therein. -/// -/// - [`syn::meta::parser`] if you are implementing a `proc_macro_attribute` -/// macro and parsing the arguments to the attribute macro, i.e. the ones -/// written in the same attribute that dispatched the macro invocation. Rustc -/// does not pass span information for the surrounding delimiters into the -/// attribute macro invocation in this situation, so error messages might be -/// less precise. -/// -/// [`Attribute::parse_nested_meta`]: crate::Attribute::parse_nested_meta -/// [`syn::meta::parser`]: crate::meta::parser -#[non_exhaustive] -pub struct ParseNestedMeta<'a> { - pub path: Path, - pub input: ParseStream<'a>, -} - -impl<'a> ParseNestedMeta<'a> { - /// Used when parsing `key = "value"` syntax. - /// - /// All it does is advance `meta.input` past the `=` sign in the input. You - /// could accomplish the same effect by writing - /// `meta.parse::<Token![=]>()?`, so at most it is a minor convenience to - /// use `meta.value()?`. - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Attribute, LitStr}; - /// - /// let attr: Attribute = parse_quote! { - /// #[tea(kind = "EarlGrey")] - /// }; - /// // conceptually: - /// if attr.path().is_ident("tea") { // this parses the `tea` - /// attr.parse_nested_meta(|meta| { // this parses the `(` - /// if meta.path.is_ident("kind") { // this parses the `kind` - /// let value = meta.value()?; // this parses the `=` - /// let s: LitStr = value.parse()?; // this parses `"EarlGrey"` - /// if s.value() == "EarlGrey" { - /// // ... - /// } - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported attribute")) - /// } - /// })?; - /// } - /// # anyhow::Ok(()) - /// ``` - pub fn value(&self) -> Result<ParseStream<'a>> { - self.input.parse::<Token![=]>()?; - Ok(self.input) - } - - /// Used when parsing `list(...)` syntax **if** the content inside the - /// nested parentheses is also expected to conform to Rust's structured - /// attribute convention. - /// - /// # Example - /// - /// ``` - /// use syn::{parse_quote, Attribute}; - /// - /// let attr: Attribute = parse_quote! { - /// #[tea(with(sugar, milk))] - /// }; - /// - /// if attr.path().is_ident("tea") { - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("with") { - /// meta.parse_nested_meta(|meta| { // <--- - /// if meta.path.is_ident("sugar") { - /// // Here we can go even deeper if needed. - /// Ok(()) - /// } else if meta.path.is_ident("milk") { - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported ingredient")) - /// } - /// }) - /// } else { - /// Err(meta.error("unsupported tea property")) - /// } - /// })?; - /// } - /// # anyhow::Ok(()) - /// ``` - /// - /// # Counterexample - /// - /// If you don't need `parse_nested_meta`'s help in parsing the content - /// written within the nested parentheses, keep in mind that you can always - /// just parse it yourself from the exposed ParseStream. Rust syntax permits - /// arbitrary tokens within those parentheses so for the crazier stuff, - /// `parse_nested_meta` is not what you want. - /// - /// ``` - /// use syn::{parenthesized, parse_quote, Attribute, LitInt}; - /// - /// let attr: Attribute = parse_quote! { - /// #[repr(align(32))] - /// }; - /// - /// let mut align: Option<LitInt> = None; - /// if attr.path().is_ident("repr") { - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("align") { - /// let content; - /// parenthesized!(content in meta.input); - /// align = Some(content.parse()?); - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported repr")) - /// } - /// })?; - /// } - /// # anyhow::Ok(()) - /// ``` - pub fn parse_nested_meta( - &self, - logic: impl FnMut(ParseNestedMeta) -> Result<()>, - ) -> Result<()> { - let content; - parenthesized!(content in self.input); - parse_nested_meta(&content, logic) - } - - /// Report that the attribute's content did not conform to expectations. - /// - /// The span of the resulting error will cover `meta.path` *and* everything - /// that has been parsed so far since it. - /// - /// There are 2 ways you might call this. First, if `meta.path` is not - /// something you recognize: - /// - /// ``` - /// # use syn::Attribute; - /// # - /// # fn example(attr: &Attribute) -> syn::Result<()> { - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("kind") { - /// // ... - /// Ok(()) - /// } else { - /// Err(meta.error("unsupported tea property")) - /// } - /// })?; - /// # Ok(()) - /// # } - /// ``` - /// - /// In this case, it behaves exactly like - /// `syn::Error::new_spanned(&meta.path, "message...")`. - /// - /// ```console - /// error: unsupported tea property - /// --> src/main.rs:3:26 - /// | - /// 3 | #[tea(kind = "EarlGrey", wat = "foo")] - /// | ^^^ - /// ``` - /// - /// More usefully, the second place is if you've already parsed a value but - /// have decided not to accept the value: - /// - /// ``` - /// # use syn::Attribute; - /// # - /// # fn example(attr: &Attribute) -> syn::Result<()> { - /// use syn::Expr; - /// - /// attr.parse_nested_meta(|meta| { - /// if meta.path.is_ident("kind") { - /// let expr: Expr = meta.value()?.parse()?; - /// match expr { - /// Expr::Lit(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Path(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Macro(expr) => /* ... */ - /// # unimplemented!(), - /// _ => Err(meta.error("tea kind must be a string literal, path, or macro")), - /// } - /// } else /* as above */ - /// # { unimplemented!() } - /// - /// })?; - /// # Ok(()) - /// # } - /// ``` - /// - /// ```console - /// error: tea kind must be a string literal, path, or macro - /// --> src/main.rs:3:7 - /// | - /// 3 | #[tea(kind = async { replicator.await })] - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// ``` - /// - /// Often you may want to use `syn::Error::new_spanned` even in this - /// situation. In the above code, that would be: - /// - /// ``` - /// # use syn::{Error, Expr}; - /// # - /// # fn example(expr: Expr) -> syn::Result<()> { - /// match expr { - /// Expr::Lit(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Path(expr) => /* ... */ - /// # unimplemented!(), - /// Expr::Macro(expr) => /* ... */ - /// # unimplemented!(), - /// _ => Err(Error::new_spanned(expr, "unsupported expression type for `kind`")), - /// } - /// # } - /// ``` - /// - /// ```console - /// error: unsupported expression type for `kind` - /// --> src/main.rs:3:14 - /// | - /// 3 | #[tea(kind = async { replicator.await })] - /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - /// ``` - pub fn error(&self, msg: impl Display) -> Error { - let start_span = self.path.segments[0].ident.span(); - let end_span = self.input.cursor().prev_span(); - crate::error::new2(start_span, end_span, msg) - } -} - -pub(crate) fn parse_nested_meta( - input: ParseStream, - mut logic: impl FnMut(ParseNestedMeta) -> Result<()>, -) -> Result<()> { - loop { - let path = input.call(parse_meta_path)?; - logic(ParseNestedMeta { path, input })?; - if input.is_empty() { - return Ok(()); - } - input.parse::<Token![,]>()?; - if input.is_empty() { - return Ok(()); - } - } -} - -// Like Path::parse_mod_style, but accepts keywords in the path. -fn parse_meta_path(input: ParseStream) -> Result<Path> { - Ok(Path { - leading_colon: input.parse()?, - segments: { - let mut segments = Punctuated::new(); - if input.peek(Ident::peek_any) { - let ident = Ident::parse_any(input)?; - segments.push_value(PathSegment::from(ident)); - } else if input.is_empty() { - return Err(input.error("expected nested attribute")); - } else if input.peek(Lit) { - return Err(input.error("unexpected literal in nested attribute, expected ident")); - } else { - return Err(input.error("unexpected token in nested attribute, expected ident")); - } - while input.peek(Token![::]) { - let punct = input.parse()?; - segments.push_punct(punct); - let ident = Ident::parse_any(input)?; - segments.push_value(PathSegment::from(ident)); - } - segments - }, - }) -} diff --git a/deps/crates/vendor/syn-v2/src/op.rs b/deps/crates/vendor/syn-v2/src/op.rs deleted file mode 100644 index 575d9faa1273..000000000000 --- a/deps/crates/vendor/syn-v2/src/op.rs +++ /dev/null @@ -1,219 +0,0 @@ -ast_enum! { - /// A binary operator: `+`, `+=`, `&`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum BinOp { - /// The `+` operator (addition) - Add(Token![+]), - /// The `-` operator (subtraction) - Sub(Token![-]), - /// The `*` operator (multiplication) - Mul(Token![*]), - /// The `/` operator (division) - Div(Token![/]), - /// The `%` operator (modulus) - Rem(Token![%]), - /// The `&&` operator (logical and) - And(Token![&&]), - /// The `||` operator (logical or) - Or(Token![||]), - /// The `^` operator (bitwise xor) - BitXor(Token![^]), - /// The `&` operator (bitwise and) - BitAnd(Token![&]), - /// The `|` operator (bitwise or) - BitOr(Token![|]), - /// The `<<` operator (shift left) - Shl(Token![<<]), - /// The `>>` operator (shift right) - Shr(Token![>>]), - /// The `==` operator (equality) - Eq(Token![==]), - /// The `<` operator (less than) - Lt(Token![<]), - /// The `<=` operator (less than or equal to) - Le(Token![<=]), - /// The `!=` operator (not equal to) - Ne(Token![!=]), - /// The `>=` operator (greater than or equal to) - Ge(Token![>=]), - /// The `>` operator (greater than) - Gt(Token![>]), - /// The `+=` operator - AddAssign(Token![+=]), - /// The `-=` operator - SubAssign(Token![-=]), - /// The `*=` operator - MulAssign(Token![*=]), - /// The `/=` operator - DivAssign(Token![/=]), - /// The `%=` operator - RemAssign(Token![%=]), - /// The `^=` operator - BitXorAssign(Token![^=]), - /// The `&=` operator - BitAndAssign(Token![&=]), - /// The `|=` operator - BitOrAssign(Token![|=]), - /// The `<<=` operator - ShlAssign(Token![<<=]), - /// The `>>=` operator - ShrAssign(Token![>>=]), - } -} - -ast_enum! { - /// A unary operator: `*`, `!`, `-`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum UnOp { - /// The `*` operator for dereferencing - Deref(Token![*]), - /// The `!` operator for logical inversion - Not(Token![!]), - /// The `-` operator for negation - Neg(Token![-]), - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::error::Result; - use crate::op::{BinOp, UnOp}; - use crate::parse::{Parse, ParseStream}; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for BinOp { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Token![+=]) { - input.parse().map(BinOp::AddAssign) - } else if input.peek(Token![-=]) { - input.parse().map(BinOp::SubAssign) - } else if input.peek(Token![*=]) { - input.parse().map(BinOp::MulAssign) - } else if input.peek(Token![/=]) { - input.parse().map(BinOp::DivAssign) - } else if input.peek(Token![%=]) { - input.parse().map(BinOp::RemAssign) - } else if input.peek(Token![^=]) { - input.parse().map(BinOp::BitXorAssign) - } else if input.peek(Token![&=]) { - input.parse().map(BinOp::BitAndAssign) - } else if input.peek(Token![|=]) { - input.parse().map(BinOp::BitOrAssign) - } else if input.peek(Token![<<=]) { - input.parse().map(BinOp::ShlAssign) - } else if input.peek(Token![>>=]) { - input.parse().map(BinOp::ShrAssign) - } else if input.peek(Token![&&]) { - input.parse().map(BinOp::And) - } else if input.peek(Token![||]) { - input.parse().map(BinOp::Or) - } else if input.peek(Token![<<]) { - input.parse().map(BinOp::Shl) - } else if input.peek(Token![>>]) { - input.parse().map(BinOp::Shr) - } else if input.peek(Token![==]) { - input.parse().map(BinOp::Eq) - } else if input.peek(Token![<=]) { - input.parse().map(BinOp::Le) - } else if input.peek(Token![!=]) { - input.parse().map(BinOp::Ne) - } else if input.peek(Token![>=]) { - input.parse().map(BinOp::Ge) - } else if input.peek(Token![+]) { - input.parse().map(BinOp::Add) - } else if input.peek(Token![-]) { - input.parse().map(BinOp::Sub) - } else if input.peek(Token![*]) { - input.parse().map(BinOp::Mul) - } else if input.peek(Token![/]) { - input.parse().map(BinOp::Div) - } else if input.peek(Token![%]) { - input.parse().map(BinOp::Rem) - } else if input.peek(Token![^]) { - input.parse().map(BinOp::BitXor) - } else if input.peek(Token![&]) { - input.parse().map(BinOp::BitAnd) - } else if input.peek(Token![|]) { - input.parse().map(BinOp::BitOr) - } else if input.peek(Token![<]) { - input.parse().map(BinOp::Lt) - } else if input.peek(Token![>]) { - input.parse().map(BinOp::Gt) - } else { - Err(input.error("expected binary operator")) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for UnOp { - fn parse(input: ParseStream) -> Result<Self> { - let lookahead = input.lookahead1(); - if lookahead.peek(Token![*]) { - input.parse().map(UnOp::Deref) - } else if lookahead.peek(Token![!]) { - input.parse().map(UnOp::Not) - } else if lookahead.peek(Token![-]) { - input.parse().map(UnOp::Neg) - } else { - Err(lookahead.error()) - } - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::op::{BinOp, UnOp}; - use proc_macro2::TokenStream; - use quote::ToTokens; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for BinOp { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - BinOp::Add(t) => t.to_tokens(tokens), - BinOp::Sub(t) => t.to_tokens(tokens), - BinOp::Mul(t) => t.to_tokens(tokens), - BinOp::Div(t) => t.to_tokens(tokens), - BinOp::Rem(t) => t.to_tokens(tokens), - BinOp::And(t) => t.to_tokens(tokens), - BinOp::Or(t) => t.to_tokens(tokens), - BinOp::BitXor(t) => t.to_tokens(tokens), - BinOp::BitAnd(t) => t.to_tokens(tokens), - BinOp::BitOr(t) => t.to_tokens(tokens), - BinOp::Shl(t) => t.to_tokens(tokens), - BinOp::Shr(t) => t.to_tokens(tokens), - BinOp::Eq(t) => t.to_tokens(tokens), - BinOp::Lt(t) => t.to_tokens(tokens), - BinOp::Le(t) => t.to_tokens(tokens), - BinOp::Ne(t) => t.to_tokens(tokens), - BinOp::Ge(t) => t.to_tokens(tokens), - BinOp::Gt(t) => t.to_tokens(tokens), - BinOp::AddAssign(t) => t.to_tokens(tokens), - BinOp::SubAssign(t) => t.to_tokens(tokens), - BinOp::MulAssign(t) => t.to_tokens(tokens), - BinOp::DivAssign(t) => t.to_tokens(tokens), - BinOp::RemAssign(t) => t.to_tokens(tokens), - BinOp::BitXorAssign(t) => t.to_tokens(tokens), - BinOp::BitAndAssign(t) => t.to_tokens(tokens), - BinOp::BitOrAssign(t) => t.to_tokens(tokens), - BinOp::ShlAssign(t) => t.to_tokens(tokens), - BinOp::ShrAssign(t) => t.to_tokens(tokens), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for UnOp { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - UnOp::Deref(t) => t.to_tokens(tokens), - UnOp::Not(t) => t.to_tokens(tokens), - UnOp::Neg(t) => t.to_tokens(tokens), - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/parse.rs b/deps/crates/vendor/syn-v2/src/parse.rs deleted file mode 100644 index 9e10b4c9bbd5..000000000000 --- a/deps/crates/vendor/syn-v2/src/parse.rs +++ /dev/null @@ -1,1420 +0,0 @@ -//! Parsing interface for parsing a token stream into a syntax tree node. -//! -//! Parsing in Syn is built on parser functions that take in a [`ParseStream`] -//! and produce a [`Result<T>`] where `T` is some syntax tree node. Underlying -//! these parser functions is a lower level mechanism built around the -//! [`Cursor`] type. `Cursor` is a cheaply copyable cursor over a range of -//! tokens in a token stream. -//! -//! [`Result<T>`]: Result -//! [`Cursor`]: crate::buffer::Cursor -//! -//! # Example -//! -//! Here is a snippet of parsing code to get a feel for the style of the -//! library. We define data structures for a subset of Rust syntax including -//! enums (not shown) and structs, then provide implementations of the [`Parse`] -//! trait to parse these syntax tree data structures from a token stream. -//! -//! Once `Parse` impls have been defined, they can be called conveniently from a -//! procedural macro through [`parse_macro_input!`] as shown at the bottom of -//! the snippet. If the caller provides syntactically invalid input to the -//! procedural macro, they will receive a helpful compiler error message -//! pointing out the exact token that triggered the failure to parse. -//! -//! [`parse_macro_input!`]: crate::parse_macro_input! -//! -//! ``` -//! # extern crate proc_macro; -//! # -//! use proc_macro::TokenStream; -//! use syn::{braced, parse_macro_input, token, Field, Ident, Result, Token}; -//! use syn::parse::{Parse, ParseStream}; -//! use syn::punctuated::Punctuated; -//! -//! enum Item { -//! Struct(ItemStruct), -//! Enum(ItemEnum), -//! } -//! -//! struct ItemStruct { -//! struct_token: Token![struct], -//! ident: Ident, -//! brace_token: token::Brace, -//! fields: Punctuated<Field, Token![,]>, -//! } -//! # -//! # enum ItemEnum {} -//! -//! impl Parse for Item { -//! fn parse(input: ParseStream) -> Result<Self> { -//! let lookahead = input.lookahead1(); -//! if lookahead.peek(Token![struct]) { -//! input.parse().map(Item::Struct) -//! } else if lookahead.peek(Token![enum]) { -//! input.parse().map(Item::Enum) -//! } else { -//! Err(lookahead.error()) -//! } -//! } -//! } -//! -//! impl Parse for ItemStruct { -//! fn parse(input: ParseStream) -> Result<Self> { -//! let content; -//! Ok(ItemStruct { -//! struct_token: input.parse()?, -//! ident: input.parse()?, -//! brace_token: braced!(content in input), -//! fields: content.parse_terminated(Field::parse_named, Token![,])?, -//! }) -//! } -//! } -//! # -//! # impl Parse for ItemEnum { -//! # fn parse(input: ParseStream) -> Result<Self> { -//! # unimplemented!() -//! # } -//! # } -//! -//! # const IGNORE: &str = stringify! { -//! #[proc_macro] -//! # }; -//! pub fn my_macro(tokens: TokenStream) -> TokenStream { -//! let input = parse_macro_input!(tokens as Item); -//! -//! /* ... */ -//! # TokenStream::new() -//! } -//! ``` -//! -//! # The `syn::parse*` functions -//! -//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve -//! as an entry point for parsing syntax tree nodes that can be parsed in an -//! obvious default way. These functions can return any syntax tree node that -//! implements the [`Parse`] trait, which includes most types in Syn. -//! -//! [`syn::parse`]: crate::parse() -//! [`syn::parse2`]: crate::parse2() -//! [`syn::parse_str`]: crate::parse_str() -//! -//! ``` -//! use syn::Type; -//! -//! # fn run_parser() -> syn::Result<()> { -//! let t: Type = syn::parse_str("alloc::collections::HashMap<String, Value>")?; -//! # Ok(()) -//! # } -//! # -//! # run_parser().unwrap(); -//! ``` -//! -//! The [`parse_quote!`] macro also uses this approach. -//! -//! [`parse_quote!`]: crate::parse_quote! -//! -//! # The `Parser` trait -//! -//! Some types can be parsed in several ways depending on context. For example -//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like -//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`] -//! may or may not allow trailing punctuation, and parsing it the wrong way -//! would either reject valid input or accept invalid input. -//! -//! [`Attribute`]: crate::Attribute -//! [`Punctuated`]: crate::punctuated -//! -//! The `Parse` trait is not implemented in these cases because there is no good -//! behavior to consider the default. -//! -//! ```compile_fail -//! # extern crate proc_macro; -//! # -//! # use syn::punctuated::Punctuated; -//! # use syn::{PathSegment, Result, Token}; -//! # -//! # fn f(tokens: proc_macro::TokenStream) -> Result<()> { -//! # -//! // Can't parse `Punctuated` without knowing whether trailing punctuation -//! // should be allowed in this context. -//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?; -//! # -//! # Ok(()) -//! # } -//! ``` -//! -//! In these cases the types provide a choice of parser functions rather than a -//! single `Parse` implementation, and those parser functions can be invoked -//! through the [`Parser`] trait. -//! -//! -//! ``` -//! # extern crate proc_macro; -//! # -//! use proc_macro::TokenStream; -//! use syn::parse::Parser; -//! use syn::punctuated::Punctuated; -//! use syn::{Attribute, Expr, PathSegment, Result, Token}; -//! -//! fn call_some_parser_methods(input: TokenStream) -> Result<()> { -//! // Parse a nonempty sequence of path segments separated by `::` punctuation -//! // with no trailing punctuation. -//! let tokens = input.clone(); -//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty; -//! let _path = parser.parse(tokens)?; -//! -//! // Parse a possibly empty sequence of expressions terminated by commas with -//! // an optional trailing punctuation. -//! let tokens = input.clone(); -//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated; -//! let _args = parser.parse(tokens)?; -//! -//! // Parse zero or more outer attributes but not inner attributes. -//! let tokens = input.clone(); -//! let parser = Attribute::parse_outer; -//! let _attrs = parser.parse(tokens)?; -//! -//! Ok(()) -//! } -//! ``` - -#[path = "discouraged.rs"] -pub mod discouraged; - -use crate::buffer::{Cursor, TokenBuffer}; -use crate::error; -use crate::lookahead; -use crate::punctuated::Punctuated; -use crate::token::Token; -use alloc::boxed::Box; -use alloc::rc::Rc; -use core::cell::Cell; -use core::fmt::{self, Debug, Display}; -#[cfg(feature = "extra-traits")] -use core::hash::{Hash, Hasher}; -use core::marker::PhantomData; -use core::mem; -use core::ops::Deref; -use core::panic::{RefUnwindSafe, UnwindSafe}; -use core::str::FromStr; -use proc_macro2::{Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree}; -#[cfg(feature = "printing")] -use quote::ToTokens; - -pub use crate::error::{Error, Result}; -pub use crate::lookahead::{End, Lookahead1, Peek}; - -/// Parsing interface implemented by all types that can be parsed in a default -/// way from a token stream. -/// -/// Refer to the [module documentation] for details about implementing and using -/// the `Parse` trait. -/// -/// [module documentation]: self -pub trait Parse: Sized { - fn parse(input: ParseStream) -> Result<Self>; -} - -/// Input to a Syn parser function. -/// -/// See the methods of this type under the documentation of [`ParseBuffer`]. For -/// an overview of parsing in Syn, refer to the [module documentation]. -/// -/// [module documentation]: self -pub type ParseStream<'a> = &'a ParseBuffer<'a>; - -/// Cursor position within a buffered token stream. -/// -/// This type is more commonly used through the type alias [`ParseStream`] which -/// is an alias for `&ParseBuffer`. -/// -/// `ParseStream` is the input type for all parser functions in Syn. They have -/// the signature `fn(ParseStream) -> Result<T>`. -/// -/// ## Calling a parser function -/// -/// There is no public way to construct a `ParseBuffer`. Instead, if you are -/// looking to invoke a parser function that requires `ParseStream` as input, -/// you will need to go through one of the public parsing entry points. -/// -/// - The [`parse_macro_input!`] macro if parsing input of a procedural macro; -/// - One of [the `syn::parse*` functions][syn-parse]; or -/// - A method of the [`Parser`] trait. -/// -/// [`parse_macro_input!`]: crate::parse_macro_input! -/// [syn-parse]: self#the-synparse-functions -pub struct ParseBuffer<'a> { - scope: Span, - // Instead of Cell<Cursor<'a>> so that ParseBuffer<'a> is covariant in 'a. - // The rest of the code in this module needs to be careful that only a - // cursor derived from this `cell` is ever assigned to this `cell`. - // - // Cell<Cursor<'a>> cannot be covariant in 'a because then we could take a - // ParseBuffer<'a>, upcast to ParseBuffer<'short> for some lifetime shorter - // than 'a, and then assign a Cursor<'short> into the Cell. - // - // By extension, it would not be safe to expose an API that accepts a - // Cursor<'a> and trusts that it lives as long as the cursor currently in - // the cell. - cell: Cell<Cursor<'static>>, - marker: PhantomData<Cursor<'a>>, - unexpected: Cell<Option<Rc<Cell<Unexpected>>>>, -} - -impl<'a> Drop for ParseBuffer<'a> { - fn drop(&mut self) { - if let Some((unexpected_span, delimiter)) = span_of_unexpected_ignoring_nones(self.cursor()) - { - let (inner, old_span) = inner_unexpected(self); - if old_span.is_none() { - inner.set(Unexpected::Some(unexpected_span, delimiter)); - } - } - } -} - -impl<'a> Display for ParseBuffer<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.cursor().token_stream(), f) - } -} - -impl<'a> Debug for ParseBuffer<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Debug::fmt(&self.cursor().token_stream(), f) - } -} - -impl<'a> UnwindSafe for ParseBuffer<'a> {} -impl<'a> RefUnwindSafe for ParseBuffer<'a> {} - -/// Cursor state associated with speculative parsing. -/// -/// This type is the input of the closure provided to [`ParseStream::step`]. -/// -/// [`ParseStream::step`]: ParseBuffer::step -/// -/// # Example -/// -/// ``` -/// use proc_macro2::TokenTree; -/// use syn::Result; -/// use syn::parse::ParseStream; -/// -/// // This function advances the stream past the next occurrence of `@`. If -/// // no `@` is present in the stream, the stream position is unchanged and -/// // an error is returned. -/// fn skip_past_next_at(input: ParseStream) -> Result<()> { -/// input.step(|cursor| { -/// let mut rest = *cursor; -/// while let Some((tt, next)) = rest.token_tree() { -/// match &tt { -/// TokenTree::Punct(punct) if punct.as_char() == '@' => { -/// return Ok(((), next)); -/// } -/// _ => rest = next, -/// } -/// } -/// Err(cursor.error("no `@` was found after this point")) -/// }) -/// } -/// # -/// # fn remainder_after_skipping_past_next_at( -/// # input: ParseStream, -/// # ) -> Result<proc_macro2::TokenStream> { -/// # skip_past_next_at(input)?; -/// # input.parse() -/// # } -/// # -/// # use syn::parse::Parser; -/// # let remainder = remainder_after_skipping_past_next_at -/// # .parse_str("a @ b c") -/// # .unwrap(); -/// # assert_eq!(remainder.to_string(), "b c"); -/// ``` -pub struct StepCursor<'c, 'a> { - scope: Span, - // This field is covariant in 'c. - cursor: Cursor<'c>, - // This field is contravariant in 'c. Together these make StepCursor - // invariant in 'c. Also covariant in 'a. The user cannot cast 'c to a - // different lifetime but can upcast into a StepCursor with a shorter - // lifetime 'a. - // - // As long as we only ever construct a StepCursor for which 'c outlives 'a, - // this means if ever a StepCursor<'c, 'a> exists we are guaranteed that 'c - // outlives 'a. - marker: PhantomData<fn(Cursor<'c>) -> Cursor<'a>>, -} - -impl<'c, 'a> Deref for StepCursor<'c, 'a> { - type Target = Cursor<'c>; - - fn deref(&self) -> &Self::Target { - &self.cursor - } -} - -impl<'c, 'a> Copy for StepCursor<'c, 'a> {} - -impl<'c, 'a> Clone for StepCursor<'c, 'a> { - fn clone(&self) -> Self { - *self - } -} - -impl<'c, 'a> StepCursor<'c, 'a> { - /// Triggers an error at the current position of the parse stream. - /// - /// The `ParseStream::step` invocation will return this same error without - /// advancing the stream state. - pub fn error<T: Display>(self, message: T) -> Error { - error::new_at(self.scope, self.cursor, message) - } -} - -pub(crate) fn advance_step_cursor<'c, 'a>(proof: StepCursor<'c, 'a>, to: Cursor<'c>) -> Cursor<'a> { - // Refer to the comments within the StepCursor definition. We use the - // fact that a StepCursor<'c, 'a> exists as proof that 'c outlives 'a. - // Cursor is covariant in its lifetime parameter so we can cast a - // Cursor<'c> to one with the shorter lifetime Cursor<'a>. - let _ = proof; - unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(to) } -} - -pub(crate) fn new_parse_buffer( - scope: Span, - cursor: Cursor, - unexpected: Rc<Cell<Unexpected>>, -) -> ParseBuffer { - ParseBuffer { - scope, - // See comment on `cell` in the struct definition. - cell: Cell::new(unsafe { mem::transmute::<Cursor, Cursor<'static>>(cursor) }), - marker: PhantomData, - unexpected: Cell::new(Some(unexpected)), - } -} - -pub(crate) enum Unexpected { - None, - Some(Span, Delimiter), - Chain(Rc<Cell<Unexpected>>), -} - -impl Default for Unexpected { - fn default() -> Self { - Unexpected::None - } -} - -impl Clone for Unexpected { - fn clone(&self) -> Self { - match self { - Unexpected::None => Unexpected::None, - Unexpected::Some(span, delimiter) => Unexpected::Some(*span, *delimiter), - Unexpected::Chain(next) => Unexpected::Chain(next.clone()), - } - } -} - -// We call this on Cell<Unexpected> and Cell<Option<T>> where temporarily -// swapping in a None is cheap. -fn cell_clone<T: Default + Clone>(cell: &Cell<T>) -> T { - let prev = cell.take(); - let ret = prev.clone(); - cell.set(prev); - ret -} - -fn inner_unexpected(buffer: &ParseBuffer) -> (Rc<Cell<Unexpected>>, Option<(Span, Delimiter)>) { - let mut unexpected = get_unexpected(buffer); - loop { - match cell_clone(&unexpected) { - Unexpected::None => return (unexpected, None), - Unexpected::Some(span, delimiter) => return (unexpected, Some((span, delimiter))), - Unexpected::Chain(next) => unexpected = next, - } - } -} - -pub(crate) fn get_unexpected(buffer: &ParseBuffer) -> Rc<Cell<Unexpected>> { - cell_clone(&buffer.unexpected).unwrap() -} - -fn span_of_unexpected_ignoring_nones(mut cursor: Cursor) -> Option<(Span, Delimiter)> { - if cursor.eof() { - return None; - } - while let Some((inner, _span, rest)) = cursor.group(Delimiter::None) { - if let Some(unexpected) = span_of_unexpected_ignoring_nones(inner) { - return Some(unexpected); - } - cursor = rest; - } - if cursor.eof() { - None - } else { - Some((cursor.span(), cursor.scope_delimiter())) - } -} - -impl<'a> ParseBuffer<'a> { - /// Parses a syntax tree node of type `T`, advancing the position of our - /// parse stream past it. - pub fn parse<T: Parse>(&self) -> Result<T> { - T::parse(self) - } - - /// Calls the given parser function to parse a syntax tree node of type `T` - /// from this stream. - /// - /// # Example - /// - /// The parser below invokes [`Attribute::parse_outer`] to parse a vector of - /// zero or more outer attributes. - /// - /// [`Attribute::parse_outer`]: crate::Attribute::parse_outer - /// - /// ``` - /// use syn::{Attribute, Ident, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // Parses a unit struct with attributes. - /// // - /// // #[path = "s.tmpl"] - /// // struct S; - /// struct UnitStruct { - /// attrs: Vec<Attribute>, - /// struct_token: Token![struct], - /// name: Ident, - /// semi_token: Token![;], - /// } - /// - /// impl Parse for UnitStruct { - /// fn parse(input: ParseStream) -> Result<Self> { - /// Ok(UnitStruct { - /// attrs: input.call(Attribute::parse_outer)?, - /// struct_token: input.parse()?, - /// name: input.parse()?, - /// semi_token: input.parse()?, - /// }) - /// } - /// } - /// ``` - pub fn call<T>(&'a self, function: fn(ParseStream<'a>) -> Result<T>) -> Result<T> { - function(self) - } - - /// Looks at the next token in the parse stream to determine whether it - /// matches the requested type of token. - /// - /// Does not advance the position of the parse stream. - /// - /// # Syntax - /// - /// Note that this method does not use turbofish syntax. Pass the peek type - /// inside of parentheses. - /// - /// - `input.peek(Token![struct])` - /// - `input.peek(Token![==])` - /// - `input.peek(syn::Ident)` *(does not accept keywords)* - /// - `input.peek(syn::Ident::peek_any)` - /// - `input.peek(Lifetime)` - /// - `input.peek(token::Brace)` - /// - /// # Example - /// - /// In this example we finish parsing the list of supertraits when the next - /// token in the input is either `where` or an opening curly brace. - /// - /// ``` - /// use syn::{braced, token, Generics, Ident, Result, Token, TypeParamBound}; - /// use syn::parse::{Parse, ParseStream}; - /// use syn::punctuated::Punctuated; - /// - /// // Parses a trait definition containing no associated items. - /// // - /// // trait Marker<'de, T>: A + B<'de> where Box<T>: Clone {} - /// struct MarkerTrait { - /// trait_token: Token![trait], - /// ident: Ident, - /// generics: Generics, - /// colon_token: Option<Token![:]>, - /// supertraits: Punctuated<TypeParamBound, Token![+]>, - /// brace_token: token::Brace, - /// } - /// - /// impl Parse for MarkerTrait { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let trait_token: Token![trait] = input.parse()?; - /// let ident: Ident = input.parse()?; - /// let mut generics: Generics = input.parse()?; - /// let colon_token: Option<Token![:]> = input.parse()?; - /// - /// let mut supertraits = Punctuated::new(); - /// if colon_token.is_some() { - /// loop { - /// supertraits.push_value(input.parse()?); - /// if input.peek(Token![where]) || input.peek(token::Brace) { - /// break; - /// } - /// supertraits.push_punct(input.parse()?); - /// } - /// } - /// - /// generics.where_clause = input.parse()?; - /// let content; - /// let empty_brace_token = braced!(content in input); - /// - /// Ok(MarkerTrait { - /// trait_token, - /// ident, - /// generics, - /// colon_token, - /// supertraits, - /// brace_token: empty_brace_token, - /// }) - /// } - /// } - /// ``` - pub fn peek<T: Peek>(&self, token: T) -> bool { - let _ = token; - T::Token::peek(self.cursor()) - } - - /// Looks at the second-next token in the parse stream. - /// - /// This is commonly useful as a way to implement contextual keywords. - /// - /// # Example - /// - /// This example needs to use `peek2` because the symbol `union` is not a - /// keyword in Rust. We can't use just `peek` and decide to parse a union if - /// the very next token is `union`, because someone is free to write a `mod - /// union` and a macro invocation that looks like `union::some_macro! { ... - /// }`. In other words `union` is a contextual keyword. - /// - /// ``` - /// use syn::{Ident, ItemUnion, Macro, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // Parses either a union or a macro invocation. - /// enum UnionOrMacro { - /// // union MaybeUninit<T> { uninit: (), value: T } - /// Union(ItemUnion), - /// // lazy_static! { ... } - /// Macro(Macro), - /// } - /// - /// impl Parse for UnionOrMacro { - /// fn parse(input: ParseStream) -> Result<Self> { - /// if input.peek(Token![union]) && input.peek2(Ident) { - /// input.parse().map(UnionOrMacro::Union) - /// } else { - /// input.parse().map(UnionOrMacro::Macro) - /// } - /// } - /// } - /// ``` - pub fn peek2<T: Peek>(&self, token: T) -> bool { - fn peek2(buffer: &ParseBuffer, peek: fn(Cursor) -> bool) -> bool { - buffer.cursor().skip().is_some_and(peek) - } - - let _ = token; - peek2(self, T::Token::peek) - } - - /// Looks at the third-next token in the parse stream. - pub fn peek3<T: Peek>(&self, token: T) -> bool { - fn peek3(buffer: &ParseBuffer, peek: fn(Cursor) -> bool) -> bool { - buffer - .cursor() - .skip() - .and_then(Cursor::skip) - .is_some_and(peek) - } - - let _ = token; - peek3(self, T::Token::peek) - } - - /// Parses zero or more occurrences of `T` separated by punctuation of type - /// `P`, with optional trailing punctuation. - /// - /// Parsing continues until the end of this parse stream. The entire content - /// of this parse stream must consist of `T` and `P`. - /// - /// # Example - /// - /// ``` - /// # use quote::quote; - /// # - /// use syn::{parenthesized, token, Ident, Result, Token, Type}; - /// use syn::parse::{Parse, ParseStream}; - /// use syn::punctuated::Punctuated; - /// - /// // Parse a simplified tuple struct syntax like: - /// // - /// // struct S(A, B); - /// struct TupleStruct { - /// struct_token: Token![struct], - /// ident: Ident, - /// paren_token: token::Paren, - /// fields: Punctuated<Type, Token![,]>, - /// semi_token: Token![;], - /// } - /// - /// impl Parse for TupleStruct { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let content; - /// Ok(TupleStruct { - /// struct_token: input.parse()?, - /// ident: input.parse()?, - /// paren_token: parenthesized!(content in input), - /// fields: content.parse_terminated(Type::parse, Token![,])?, - /// semi_token: input.parse()?, - /// }) - /// } - /// } - /// # - /// # let input = quote! { - /// # struct S(A, B); - /// # }; - /// # syn::parse2::<TupleStruct>(input).unwrap(); - /// ``` - /// - /// # See also - /// - /// If your separator is anything more complicated than an invocation of the - /// `Token!` macro, this method won't be applicable and you can instead - /// directly use `Punctuated`'s parser functions: [`parse_terminated`], - /// [`parse_separated_nonempty`] etc. - /// - /// [`parse_terminated`]: Punctuated::parse_terminated - /// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty - /// - /// ``` - /// use syn::{custom_keyword, Expr, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// use syn::punctuated::Punctuated; - /// - /// mod kw { - /// syn::custom_keyword!(fin); - /// } - /// - /// struct Fin(kw::fin, Token![;]); - /// - /// impl Parse for Fin { - /// fn parse(input: ParseStream) -> Result<Self> { - /// Ok(Self(input.parse()?, input.parse()?)) - /// } - /// } - /// - /// struct Thing { - /// steps: Punctuated<Expr, Fin>, - /// } - /// - /// impl Parse for Thing { - /// fn parse(input: ParseStream) -> Result<Self> { - /// # if true { - /// Ok(Thing { - /// steps: Punctuated::parse_terminated(input)?, - /// }) - /// # } else { - /// // or equivalently, this means the same thing: - /// # Ok(Thing { - /// steps: input.call(Punctuated::parse_terminated)?, - /// # }) - /// # } - /// } - /// } - /// ``` - pub fn parse_terminated<T, P>( - &'a self, - parser: fn(ParseStream<'a>) -> Result<T>, - separator: P, - ) -> Result<Punctuated<T, P::Token>> - where - P: Peek, - P::Token: Parse, - { - let _ = separator; - Punctuated::parse_terminated_with(self, parser) - } - - /// Returns whether there are no more tokens remaining to be parsed from - /// this stream. - /// - /// This method returns true upon reaching the end of the content within a - /// set of delimiters, as well as at the end of the tokens provided to the - /// outermost parsing entry point. - /// - /// This is equivalent to - /// <code>.<a href="#method.peek">peek</a>(<a href="struct.End.html">syn::parse::End</a>)</code>. - /// Use `.peek2(End)` or `.peek3(End)` to look for the end of a parse stream - /// further ahead than the current position. - /// - /// # Example - /// - /// ``` - /// use syn::{braced, token, Ident, Item, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // Parses a Rust `mod m { ... }` containing zero or more items. - /// struct Mod { - /// mod_token: Token![mod], - /// name: Ident, - /// brace_token: token::Brace, - /// items: Vec<Item>, - /// } - /// - /// impl Parse for Mod { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let content; - /// Ok(Mod { - /// mod_token: input.parse()?, - /// name: input.parse()?, - /// brace_token: braced!(content in input), - /// items: { - /// let mut items = Vec::new(); - /// while !content.is_empty() { - /// items.push(content.parse()?); - /// } - /// items - /// }, - /// }) - /// } - /// } - /// ``` - pub fn is_empty(&self) -> bool { - self.cursor().eof() - } - - /// Constructs a helper for peeking at the next token in this stream and - /// building an error message if it is not one of a set of expected tokens. - /// - /// # Example - /// - /// ``` - /// use syn::{ConstParam, Ident, Lifetime, LifetimeParam, Result, Token, TypeParam}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // A generic parameter, a single one of the comma-separated elements inside - /// // angle brackets in: - /// // - /// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } - /// // - /// // On invalid input, lookahead gives us a reasonable error message. - /// // - /// // error: expected one of: identifier, lifetime, `const` - /// // | - /// // 5 | fn f<!Sized>() {} - /// // | ^ - /// enum GenericParam { - /// Type(TypeParam), - /// Lifetime(LifetimeParam), - /// Const(ConstParam), - /// } - /// - /// impl Parse for GenericParam { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let lookahead = input.lookahead1(); - /// if lookahead.peek(Ident) { - /// input.parse().map(GenericParam::Type) - /// } else if lookahead.peek(Lifetime) { - /// input.parse().map(GenericParam::Lifetime) - /// } else if lookahead.peek(Token![const]) { - /// input.parse().map(GenericParam::Const) - /// } else { - /// Err(lookahead.error()) - /// } - /// } - /// } - /// ``` - pub fn lookahead1(&self) -> Lookahead1<'a> { - lookahead::new(self.scope, self.cursor()) - } - - /// Forks a parse stream so that parsing tokens out of either the original - /// or the fork does not advance the position of the other. - /// - /// # Performance - /// - /// Forking a parse stream is a cheap fixed amount of work and does not - /// involve copying token buffers. Where you might hit performance problems - /// is if your macro ends up parsing a large amount of content more than - /// once. - /// - /// ``` - /// # use syn::{Expr, Result}; - /// # use syn::parse::ParseStream; - /// # - /// # fn bad(input: ParseStream) -> Result<Expr> { - /// // Do not do this. - /// if input.fork().parse::<Expr>().is_ok() { - /// return input.parse::<Expr>(); - /// } - /// # unimplemented!() - /// # } - /// ``` - /// - /// As a rule, avoid parsing an unbounded amount of tokens out of a forked - /// parse stream. Only use a fork when the amount of work performed against - /// the fork is small and bounded. - /// - /// When complex speculative parsing against the forked stream is - /// unavoidable, use [`parse::discouraged::Speculative`] to advance the - /// original stream once the fork's parse is determined to have been - /// successful. - /// - /// For a lower level way to perform speculative parsing at the token level, - /// consider using [`ParseStream::step`] instead. - /// - /// [`parse::discouraged::Speculative`]: discouraged::Speculative - /// [`ParseStream::step`]: ParseBuffer::step - /// - /// # Example - /// - /// The parse implementation shown here parses possibly restricted `pub` - /// visibilities. - /// - /// - `pub` - /// - `pub(crate)` - /// - `pub(self)` - /// - `pub(super)` - /// - `pub(in some::path)` - /// - /// To handle the case of visibilities inside of tuple structs, the parser - /// needs to distinguish parentheses that specify visibility restrictions - /// from parentheses that form part of a tuple type. - /// - /// ``` - /// # struct A; - /// # struct B; - /// # struct C; - /// # - /// struct S(pub(crate) A, pub (B, C)); - /// ``` - /// - /// In this example input the first tuple struct element of `S` has - /// `pub(crate)` visibility while the second tuple struct element has `pub` - /// visibility; the parentheses around `(B, C)` are part of the type rather - /// than part of a visibility restriction. - /// - /// The parser uses a forked parse stream to check the first token inside of - /// parentheses after the `pub` keyword. This is a small bounded amount of - /// work performed against the forked parse stream. - /// - /// ``` - /// use syn::{parenthesized, token, Ident, Path, Result, Token}; - /// use syn::ext::IdentExt; - /// use syn::parse::{Parse, ParseStream}; - /// - /// struct PubVisibility { - /// pub_token: Token![pub], - /// restricted: Option<Restricted>, - /// } - /// - /// struct Restricted { - /// paren_token: token::Paren, - /// in_token: Option<Token![in]>, - /// path: Path, - /// } - /// - /// impl Parse for PubVisibility { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let pub_token: Token![pub] = input.parse()?; - /// - /// if input.peek(token::Paren) { - /// let ahead = input.fork(); - /// let mut content; - /// parenthesized!(content in ahead); - /// - /// if content.peek(Token![crate]) - /// || content.peek(Token![self]) - /// || content.peek(Token![super]) - /// { - /// return Ok(PubVisibility { - /// pub_token, - /// restricted: Some(Restricted { - /// paren_token: parenthesized!(content in input), - /// in_token: None, - /// path: Path::from(content.call(Ident::parse_any)?), - /// }), - /// }); - /// } else if content.peek(Token![in]) { - /// return Ok(PubVisibility { - /// pub_token, - /// restricted: Some(Restricted { - /// paren_token: parenthesized!(content in input), - /// in_token: Some(content.parse()?), - /// path: content.call(Path::parse_mod_style)?, - /// }), - /// }); - /// } - /// } - /// - /// Ok(PubVisibility { - /// pub_token, - /// restricted: None, - /// }) - /// } - /// } - /// ``` - pub fn fork(&self) -> Self { - ParseBuffer { - scope: self.scope, - cell: self.cell.clone(), - marker: PhantomData, - // Not the parent's unexpected. Nothing cares whether the clone - // parses all the way unless we `advance_to`. - unexpected: Cell::new(Some(Rc::new(Cell::new(Unexpected::None)))), - } - } - - /// Triggers an error at the current position of the parse stream. - /// - /// # Example - /// - /// ``` - /// use syn::{Expr, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // Some kind of loop: `while` or `for` or `loop`. - /// struct Loop { - /// expr: Expr, - /// } - /// - /// impl Parse for Loop { - /// fn parse(input: ParseStream) -> Result<Self> { - /// if input.peek(Token![while]) - /// || input.peek(Token![for]) - /// || input.peek(Token![loop]) - /// { - /// Ok(Loop { - /// expr: input.parse()?, - /// }) - /// } else { - /// Err(input.error("expected some kind of loop")) - /// } - /// } - /// } - /// ``` - pub fn error<T: Display>(&self, message: T) -> Error { - error::new_at(self.scope, self.cursor(), message) - } - - /// Speculatively parses tokens from this parse stream, advancing the - /// position of this stream only if parsing succeeds. - /// - /// This is a powerful low-level API used for defining the `Parse` impls of - /// the basic built-in token types. It is not something that will be used - /// widely outside of the Syn codebase. - /// - /// # Example - /// - /// ``` - /// use proc_macro2::TokenTree; - /// use syn::Result; - /// use syn::parse::ParseStream; - /// - /// // This function advances the stream past the next occurrence of `@`. If - /// // no `@` is present in the stream, the stream position is unchanged and - /// // an error is returned. - /// fn skip_past_next_at(input: ParseStream) -> Result<()> { - /// input.step(|cursor| { - /// let mut rest = *cursor; - /// while let Some((tt, next)) = rest.token_tree() { - /// match &tt { - /// TokenTree::Punct(punct) if punct.as_char() == '@' => { - /// return Ok(((), next)); - /// } - /// _ => rest = next, - /// } - /// } - /// Err(cursor.error("no `@` was found after this point")) - /// }) - /// } - /// # - /// # fn remainder_after_skipping_past_next_at( - /// # input: ParseStream, - /// # ) -> Result<proc_macro2::TokenStream> { - /// # skip_past_next_at(input)?; - /// # input.parse() - /// # } - /// # - /// # use syn::parse::Parser; - /// # let remainder = remainder_after_skipping_past_next_at - /// # .parse_str("a @ b c") - /// # .unwrap(); - /// # assert_eq!(remainder.to_string(), "b c"); - /// ``` - pub fn step<F, R>(&self, function: F) -> Result<R> - where - F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>, - { - // Since the user's function is required to work for any 'c, we know - // that the Cursor<'c> they return is either derived from the input - // StepCursor<'c, 'a> or from a Cursor<'static>. - // - // It would not be legal to write this function without the invariant - // lifetime 'c in StepCursor<'c, 'a>. If this function were written only - // in terms of 'a, the user could take our ParseBuffer<'a>, upcast it to - // a ParseBuffer<'short> which some shorter lifetime than 'a, invoke - // `step` on their ParseBuffer<'short> with a closure that returns - // Cursor<'short>, and we would wrongly write that Cursor<'short> into - // the Cell intended to hold Cursor<'a>. - // - // In some cases it may be necessary for R to contain a Cursor<'a>. - // Within Syn we solve this using `advance_step_cursor` which uses the - // existence of a StepCursor<'c, 'a> as proof that it is safe to cast - // from Cursor<'c> to Cursor<'a>. If needed outside of Syn, it would be - // safe to expose that API as a method on StepCursor. - let (node, rest) = function(StepCursor { - scope: self.scope, - cursor: self.cell.get(), - marker: PhantomData, - })?; - self.cell.set(rest); - Ok(node) - } - - /// Returns the `Span` of the next token in the parse stream, or - /// `Span::call_site()` if this parse stream has completely exhausted its - /// input `TokenStream`. - pub fn span(&self) -> Span { - let cursor = self.cursor(); - if cursor.eof() { - self.scope - } else { - crate::buffer::open_span_of_group(cursor) - } - } - - /// Provides low-level access to the token representation underlying this - /// parse stream. - /// - /// Cursors are immutable so no operations you perform against the cursor - /// will affect the state of this parse stream. - /// - /// # Example - /// - /// ``` - /// use proc_macro2::TokenStream; - /// use syn::buffer::Cursor; - /// use syn::parse::{ParseStream, Result}; - /// - /// // Run a parser that returns T, but get its output as TokenStream instead of T. - /// // This works without T needing to implement ToTokens. - /// fn recognize_token_stream<T>( - /// recognizer: fn(ParseStream) -> Result<T>, - /// ) -> impl Fn(ParseStream) -> Result<TokenStream> { - /// move |input| { - /// let begin = input.cursor(); - /// recognizer(input)?; - /// let end = input.cursor(); - /// Ok(tokens_between(begin, end)) - /// } - /// } - /// - /// // Collect tokens between two cursors as a TokenStream. - /// fn tokens_between(begin: Cursor, end: Cursor) -> TokenStream { - /// assert!(begin <= end); - /// - /// let mut cursor = begin; - /// let mut tokens = TokenStream::new(); - /// while cursor < end { - /// let (token, next) = cursor.token_tree().unwrap(); - /// tokens.extend(core::iter::once(token)); - /// cursor = next; - /// } - /// tokens - /// } - /// - /// fn main() { - /// use quote::quote; - /// use syn::parse::{Parse, Parser}; - /// use syn::Token; - /// - /// // Parse syn::Type as a TokenStream, surrounded by angle brackets. - /// fn example(input: ParseStream) -> Result<TokenStream> { - /// let _langle: Token![<] = input.parse()?; - /// let ty = recognize_token_stream(syn::Type::parse)(input)?; - /// let _rangle: Token![>] = input.parse()?; - /// Ok(ty) - /// } - /// - /// let tokens = quote! { <fn() -> u8> }; - /// println!("{}", example.parse2(tokens).unwrap()); - /// } - /// ``` - pub fn cursor(&self) -> Cursor<'a> { - self.cell.get() - } - - fn check_unexpected(&self) -> Result<()> { - match inner_unexpected(self).1 { - Some((span, delimiter)) => Err(err_unexpected_token(span, delimiter)), - None => Ok(()), - } - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl<T: Parse> Parse for Box<T> { - fn parse(input: ParseStream) -> Result<Self> { - input.parse().map(Box::new) - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl<T: Parse + Token> Parse for Option<T> { - fn parse(input: ParseStream) -> Result<Self> { - if T::peek(input.cursor()) { - Ok(Some(input.parse()?)) - } else { - Ok(None) - } - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl Parse for TokenStream { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| Ok((cursor.token_stream(), Cursor::empty()))) - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl Parse for TokenTree { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| match cursor.token_tree() { - Some((tt, rest)) => Ok((tt, rest)), - None => Err(cursor.error("expected token tree")), - }) - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl Parse for Group { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| { - if let Some((group, rest)) = cursor.any_group_token() { - if group.delimiter() != Delimiter::None { - return Ok((group, rest)); - } - } - Err(cursor.error("expected group token")) - }) - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl Parse for Punct { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| match cursor.punct() { - Some((punct, rest)) => Ok((punct, rest)), - None => Err(cursor.error("expected punctuation token")), - }) - } -} - -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl Parse for Literal { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| match cursor.literal() { - Some((literal, rest)) => Ok((literal, rest)), - None => Err(cursor.error("expected literal token")), - }) - } -} - -/// Parser that can parse Rust tokens into a particular syntax tree node. -/// -/// Refer to the [module documentation] for details about parsing in Syn. -/// -/// [module documentation]: self -pub trait Parser: Sized { - type Output; - - /// Parse a proc-macro2 token stream into the chosen syntax tree node. - /// - /// This function enforces that the input is fully parsed. If there are any - /// unparsed tokens at the end of the stream, an error is returned. - fn parse2(self, tokens: TokenStream) -> Result<Self::Output>; - - /// Parse tokens of source code into the chosen syntax tree node. - /// - /// This function enforces that the input is fully parsed. If there are any - /// unparsed tokens at the end of the stream, an error is returned. - #[cfg(feature = "proc-macro")] - #[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))] - fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output> { - self.parse2(proc_macro2::TokenStream::from(tokens)) - } - - /// Parse a string of Rust code into the chosen syntax tree node. - /// - /// This function enforces that the input is fully parsed. If there are any - /// unparsed tokens at the end of the string, an error is returned. - /// - /// # Hygiene - /// - /// Every span in the resulting syntax tree will be set to resolve at the - /// macro call site. - fn parse_str(self, s: &str) -> Result<Self::Output> { - self.parse2(proc_macro2::TokenStream::from_str(s)?) - } - - // Not public API. - #[doc(hidden)] - fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> { - let _ = scope; - self.parse2(tokens) - } -} - -fn tokens_to_parse_buffer(tokens: &TokenBuffer) -> ParseBuffer { - let scope = Span::call_site(); - let cursor = tokens.begin(); - let unexpected = Rc::new(Cell::new(Unexpected::None)); - new_parse_buffer(scope, cursor, unexpected) -} - -impl<F, T> Parser for F -where - F: FnOnce(ParseStream) -> Result<T>, -{ - type Output = T; - - fn parse2(self, tokens: TokenStream) -> Result<T> { - let buf = TokenBuffer::new2(tokens); - let state = tokens_to_parse_buffer(&buf); - let node = self(&state)?; - state.check_unexpected()?; - if let Some((unexpected_span, delimiter)) = - span_of_unexpected_ignoring_nones(state.cursor()) - { - Err(err_unexpected_token(unexpected_span, delimiter)) - } else { - Ok(node) - } - } - - fn __parse_scoped(self, scope: Span, tokens: TokenStream) -> Result<Self::Output> { - let buf = TokenBuffer::new2(tokens); - let cursor = buf.begin(); - let unexpected = Rc::new(Cell::new(Unexpected::None)); - let state = new_parse_buffer(scope, cursor, unexpected); - let node = self(&state)?; - state.check_unexpected()?; - if let Some((unexpected_span, delimiter)) = - span_of_unexpected_ignoring_nones(state.cursor()) - { - Err(err_unexpected_token(unexpected_span, delimiter)) - } else { - Ok(node) - } - } -} - -pub(crate) fn parse_scoped<F: Parser>(f: F, scope: Span, tokens: TokenStream) -> Result<F::Output> { - f.__parse_scoped(scope, tokens) -} - -fn err_unexpected_token(span: Span, delimiter: Delimiter) -> Error { - let msg = match delimiter { - Delimiter::Parenthesis => "unexpected token, expected `)`", - Delimiter::Brace => "unexpected token, expected `}`", - Delimiter::Bracket => "unexpected token, expected `]`", - Delimiter::None => "unexpected token", - }; - Error::new(span, msg) -} - -/// An empty syntax tree node that consumes no tokens when parsed. -/// -/// This is useful for attribute macros that want to ensure they are not -/// provided any attribute args. -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::parse_macro_input; -/// use syn::parse::Nothing; -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro_attribute] -/// # }; -/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { -/// parse_macro_input!(args as Nothing); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// ``` -/// -/// ```text -/// error: unexpected token -/// --> src/main.rs:3:19 -/// | -/// 3 | #[my_attr(asdf)] -/// | ^^^^ -/// ``` -pub struct Nothing; - -impl Parse for Nothing { - fn parse(_input: ParseStream) -> Result<Self> { - Ok(Nothing) - } -} - -#[cfg(feature = "printing")] -#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] -impl ToTokens for Nothing { - fn to_tokens(&self, tokens: &mut TokenStream) { - let _ = tokens; - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for Nothing { - fn clone(&self) -> Self { - *self - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for Nothing {} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for Nothing { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("Nothing") - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Eq for Nothing {} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for Nothing { - fn eq(&self, _other: &Self) -> bool { - true - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for Nothing { - fn hash<H: Hasher>(&self, _state: &mut H) {} -} diff --git a/deps/crates/vendor/syn-v2/src/parse_macro_input.rs b/deps/crates/vendor/syn-v2/src/parse_macro_input.rs deleted file mode 100644 index f0660aedd7df..000000000000 --- a/deps/crates/vendor/syn-v2/src/parse_macro_input.rs +++ /dev/null @@ -1,128 +0,0 @@ -/// Parse the input TokenStream of a macro, triggering a compile error if the -/// tokens fail to parse. -/// -/// Refer to the [`parse` module] documentation for more details about parsing -/// in Syn. -/// -/// [`parse` module]: mod@crate::parse -/// -/// <br> -/// -/// # Intended usage -/// -/// This macro must be called from a function that returns -/// `proc_macro::TokenStream`. Usually this will be your proc macro entry point, -/// the function that has the #\[proc_macro\] / #\[proc_macro_derive\] / -/// #\[proc_macro_attribute\] attribute. -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// use proc_macro::TokenStream; -/// use syn::{parse_macro_input, Result}; -/// use syn::parse::{Parse, ParseStream}; -/// -/// struct MyMacroInput { -/// /* ... */ -/// } -/// -/// impl Parse for MyMacroInput { -/// fn parse(input: ParseStream) -> Result<Self> { -/// /* ... */ -/// # Ok(MyMacroInput {}) -/// } -/// } -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro] -/// # }; -/// pub fn my_macro(tokens: TokenStream) -> TokenStream { -/// let input = parse_macro_input!(tokens as MyMacroInput); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// ``` -/// -/// <br> -/// -/// # Usage with Parser -/// -/// This macro can also be used with the [`Parser` trait] for types that have -/// multiple ways that they can be parsed. -/// -/// [`Parser` trait]: crate::parse::Parser -/// -/// ``` -/// # extern crate proc_macro; -/// # -/// # use proc_macro::TokenStream; -/// # use syn::{parse_macro_input, Result}; -/// # use syn::parse::ParseStream; -/// # -/// # struct MyMacroInput {} -/// # -/// impl MyMacroInput { -/// fn parse_alternate(input: ParseStream) -> Result<Self> { -/// /* ... */ -/// # Ok(MyMacroInput {}) -/// } -/// } -/// -/// # const IGNORE: &str = stringify! { -/// #[proc_macro] -/// # }; -/// pub fn my_macro(tokens: TokenStream) -> TokenStream { -/// let input = parse_macro_input!(tokens with MyMacroInput::parse_alternate); -/// -/// /* ... */ -/// # TokenStream::new() -/// } -/// ``` -/// -/// <br> -/// -/// # Expansion -/// -/// `parse_macro_input!($variable as $Type)` expands to something like: -/// -/// ```no_run -/// # extern crate proc_macro; -/// # -/// # macro_rules! doc_test { -/// # ($variable:ident as $Type:ty) => { -/// match syn::parse::<$Type>($variable) { -/// Ok(syntax_tree) => syntax_tree, -/// Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()), -/// } -/// # }; -/// # } -/// # -/// # fn test(input: proc_macro::TokenStream) -> proc_macro::TokenStream { -/// # let _ = doc_test!(input as syn::Ident); -/// # proc_macro::TokenStream::new() -/// # } -/// ``` -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "proc-macro"))))] -macro_rules! parse_macro_input { - ($tokenstream:ident as $ty:ty) => { - match $crate::parse::<$ty>($tokenstream) { - $crate::__private::Ok(data) => data, - $crate::__private::Err(err) => { - return $crate::__private::TokenStream::from(err.to_compile_error()); - } - } - }; - ($tokenstream:ident with $parser:path) => { - match $crate::parse::Parser::parse($parser, $tokenstream) { - $crate::__private::Ok(data) => data, - $crate::__private::Err(err) => { - return $crate::__private::TokenStream::from(err.to_compile_error()); - } - } - }; - ($tokenstream:ident) => { - $crate::parse_macro_input!($tokenstream as _) - }; -} diff --git a/deps/crates/vendor/syn-v2/src/parse_quote.rs b/deps/crates/vendor/syn-v2/src/parse_quote.rs deleted file mode 100644 index 3e96b2ed944f..000000000000 --- a/deps/crates/vendor/syn-v2/src/parse_quote.rs +++ /dev/null @@ -1,244 +0,0 @@ -/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses -/// type inference to figure out a return type for those tokens. -/// -/// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html -/// -/// The return type can be any syntax tree node that implements the [`Parse`] -/// trait. -/// -/// [`Parse`]: crate::parse::Parse -/// -/// ``` -/// use quote::quote; -/// use syn::{parse_quote, Stmt}; -/// -/// fn main() { -/// let name = quote!(v); -/// let ty = quote!(u8); -/// -/// let stmt: Stmt = parse_quote! { -/// let #name: #ty = Default::default(); -/// }; -/// -/// println!("{:#?}", stmt); -/// } -/// ``` -/// -/// *This macro is available only if Syn is built with both the `"parsing"` and -/// `"printing"` features.* -/// -/// # Example -/// -/// The following helper function adds a bound `T: HeapSize` to every type -/// parameter `T` in the input generics. -/// -/// ``` -/// use syn::{parse_quote, Generics, GenericParam}; -/// -/// // Add a bound `T: HeapSize` to every type parameter T. -/// fn add_trait_bounds(mut generics: Generics) -> Generics { -/// for param in &mut generics.params { -/// if let GenericParam::Type(type_param) = param { -/// type_param.bounds.push(parse_quote!(HeapSize)); -/// } -/// } -/// generics -/// } -/// ``` -/// -/// # Special cases -/// -/// This macro can parse the following additional types as a special case even -/// though they do not implement the `Parse` trait. -/// -/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]` -/// or inner like `#![...]` -/// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in -/// any order -/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation -/// `P` with optional trailing punctuation -/// - [`Vec<Arm>`] — parses arms separated by optional commas according to the -/// same grammar as the inside of a `match` expression -/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within` -/// - [`Pat`], [`Box<Pat>`] — parses the same as -/// `Pat::parse_multi_with_leading_vert` -/// - [`Field`] — parses a named or unnamed struct field -/// -/// [`Vec<Attribute>`]: Attribute -/// [`Vec<Arm>`]: Arm -/// [`Vec<Stmt>`]: Block::parse_within -/// [`Pat`]: Pat::parse_multi_with_leading_vert -/// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert -/// -/// # Panics -/// -/// Panics if the tokens fail to parse as the expected syntax tree type. The -/// caller is responsible for ensuring that the input tokens are syntactically -/// valid. -#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] -#[macro_export] -macro_rules! parse_quote { - ($($tt:tt)*) => { - $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*)) - }; -} - -/// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned]. -/// -/// Please refer to each of their documentation. -/// -/// # Example -/// -/// ``` -/// use quote::{quote, quote_spanned}; -/// use syn::spanned::Spanned; -/// use syn::{parse_quote_spanned, ReturnType, Signature}; -/// -/// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`, -/// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`, -/// // without introducing any call_site() spans. -/// fn make_ret_pinned_future(sig: &mut Signature) { -/// let ret = match &sig.output { -/// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()), -/// ReturnType::Type(_, ret) => quote!(#ret), -/// }; -/// sig.output = parse_quote_spanned! {ret.span()=> -/// -> ::core::pin::Pin<::alloc::boxed::Box<dyn ::core::future::Future<Output = #ret>>> -/// }; -/// } -/// ``` -#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] -#[macro_export] -macro_rules! parse_quote_spanned { - ($span:expr=> $($tt:tt)*) => { - $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*)) - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// Can parse any type that implements Parse. - -use crate::error::Result; -use crate::parse::{Parse, ParseStream, Parser}; -#[cfg(feature = "full")] -use alloc::boxed::Box; -#[cfg(any(feature = "full", feature = "derive"))] -use alloc::vec::Vec; -use proc_macro2::TokenStream; - -// Not public API. -#[doc(hidden)] -#[track_caller] -pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T { - let parser = T::parse; - match parser.parse2(token_stream) { - Ok(t) => t, - Err(err) => panic!("{}", err), - } -} - -#[doc(hidden)] -pub trait ParseQuote: Sized { - fn parse(input: ParseStream) -> Result<Self>; -} - -impl<T: Parse> ParseQuote for T { - fn parse(input: ParseStream) -> Result<Self> { - <T as Parse>::parse(input) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Any other types that we want `parse_quote!` to be able to parse. - -use crate::punctuated::Punctuated; -#[cfg(any(feature = "full", feature = "derive"))] -use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility}; -#[cfg(feature = "full")] -use crate::{Arm, Block, Pat, Stmt}; - -#[cfg(any(feature = "full", feature = "derive"))] -impl ParseQuote for Attribute { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Token![#]) && input.peek2(Token![!]) { - attr::parsing::single_parse_inner(input) - } else { - attr::parsing::single_parse_outer(input) - } - } -} - -#[cfg(any(feature = "full", feature = "derive"))] -impl ParseQuote for Vec<Attribute> { - fn parse(input: ParseStream) -> Result<Self> { - let mut attrs = Vec::new(); - while !input.is_empty() { - attrs.push(ParseQuote::parse(input)?); - } - Ok(attrs) - } -} - -#[cfg(any(feature = "full", feature = "derive"))] -impl ParseQuote for Field { - fn parse(input: ParseStream) -> Result<Self> { - let attrs = input.call(Attribute::parse_outer)?; - let vis: Visibility = input.parse()?; - - let ident: Option<Ident>; - let colon_token: Option<Token![:]>; - let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]); - if is_named { - ident = Some(input.parse()?); - colon_token = Some(input.parse()?); - } else { - ident = None; - colon_token = None; - } - - let ty: Type = input.parse()?; - - Ok(Field { - attrs, - vis, - mutability: FieldMutability::None, - ident, - colon_token, - ty, - }) - } -} - -#[cfg(feature = "full")] -impl ParseQuote for Pat { - fn parse(input: ParseStream) -> Result<Self> { - Pat::parse_multi_with_leading_vert(input) - } -} - -#[cfg(feature = "full")] -impl ParseQuote for Box<Pat> { - fn parse(input: ParseStream) -> Result<Self> { - <Pat as ParseQuote>::parse(input).map(Box::new) - } -} - -impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { - fn parse(input: ParseStream) -> Result<Self> { - Self::parse_terminated(input) - } -} - -#[cfg(feature = "full")] -impl ParseQuote for Vec<Stmt> { - fn parse(input: ParseStream) -> Result<Self> { - Block::parse_within(input) - } -} - -#[cfg(feature = "full")] -impl ParseQuote for Vec<Arm> { - fn parse(input: ParseStream) -> Result<Self> { - Arm::parse_multiple(input) - } -} diff --git a/deps/crates/vendor/syn-v2/src/pat.rs b/deps/crates/vendor/syn-v2/src/pat.rs deleted file mode 100644 index e0a130913ad1..000000000000 --- a/deps/crates/vendor/syn-v2/src/pat.rs +++ /dev/null @@ -1,915 +0,0 @@ -use crate::attr::Attribute; -use crate::expr::Member; -use crate::ident::Ident; -use crate::path::{Path, QSelf}; -use crate::punctuated::Punctuated; -use crate::token; -use crate::ty::Type; -use alloc::boxed::Box; -use alloc::vec::Vec; -use proc_macro2::TokenStream; - -pub use crate::expr::{ - ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath, - ExprRange as PatRange, -}; - -ast_enum_of_structs! { - /// A pattern in a local binding, function signature, match expression, or - /// various other places. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - #[non_exhaustive] - pub enum Pat { - /// A const block: `const { ... }`. - Const(PatConst), - - /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. - Ident(PatIdent), - - /// A literal pattern: `0`. - Lit(PatLit), - - /// A macro in pattern position. - Macro(PatMacro), - - /// A pattern that matches any one of a set of cases. - Or(PatOr), - - /// A parenthesized pattern: `(A | B)`. - Paren(PatParen), - - /// A path pattern like `Color::Red`, optionally qualified with a - /// self-type. - /// - /// Unqualified path patterns can legally refer to variants, structs, - /// constants or associated constants. Qualified path patterns like - /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to - /// associated constants. - Path(PatPath), - - /// A range pattern: `1..=2`. - Range(PatRange), - - /// A reference pattern: `&mut var`. - Reference(PatReference), - - /// The dots in a tuple or slice pattern: `[0, 1, ..]`. - Rest(PatRest), - - /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. - Slice(PatSlice), - - /// A struct or struct variant pattern: `Variant { x, y, .. }`. - Struct(PatStruct), - - /// A tuple pattern: `(a, b)`. - Tuple(PatTuple), - - /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. - TupleStruct(PatTupleStruct), - - /// A type ascription pattern: `foo: f64`. - Type(PatType), - - /// Tokens in pattern position not interpreted by Syn. - Verbatim(TokenStream), - - /// A pattern that matches any value: `_`. - Wild(PatWild), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match pat { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // Pat::Box(pat) => {...} - // Pat::Ident(pat) => {...} - // ... - // Pat::Wild(pat) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. - /// - /// It may also be a unit struct or struct variant (e.g. `None`), or a - /// constant; these cannot be distinguished syntactically. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatIdent { - pub attrs: Vec<Attribute>, - pub by_ref: Option<Token![ref]>, - pub mutability: Option<Token![mut]>, - pub ident: Ident, - pub subpat: Option<(Token![@], Box<Pat>)>, - } -} - -ast_struct! { - /// A pattern that matches any one of a set of cases. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatOr { - pub attrs: Vec<Attribute>, - pub leading_vert: Option<Token![|]>, - pub cases: Punctuated<Pat, Token![|]>, - } -} - -ast_struct! { - /// A parenthesized pattern: `(A | B)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatParen { - pub attrs: Vec<Attribute>, - pub paren_token: token::Paren, - pub pat: Box<Pat>, - } -} - -ast_struct! { - /// A reference pattern: `&mut var`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatReference { - pub attrs: Vec<Attribute>, - pub and_token: Token![&], - pub mutability: Option<Token![mut]>, - pub pat: Box<Pat>, - } -} - -ast_struct! { - /// The dots in a tuple or slice pattern: `[0, 1, ..]`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatRest { - pub attrs: Vec<Attribute>, - pub dot2_token: Token![..], - } -} - -ast_struct! { - /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatSlice { - pub attrs: Vec<Attribute>, - pub bracket_token: token::Bracket, - pub elems: Punctuated<Pat, Token![,]>, - } -} - -ast_struct! { - /// A struct or struct variant pattern: `Variant { x, y, .. }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatStruct { - pub attrs: Vec<Attribute>, - pub qself: Option<QSelf>, - pub path: Path, - pub brace_token: token::Brace, - pub fields: Punctuated<FieldPat, Token![,]>, - pub rest: Option<PatRest>, - } -} - -ast_struct! { - /// A tuple pattern: `(a, b)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatTuple { - pub attrs: Vec<Attribute>, - pub paren_token: token::Paren, - pub elems: Punctuated<Pat, Token![,]>, - } -} - -ast_struct! { - /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatTupleStruct { - pub attrs: Vec<Attribute>, - pub qself: Option<QSelf>, - pub path: Path, - pub paren_token: token::Paren, - pub elems: Punctuated<Pat, Token![,]>, - } -} - -ast_struct! { - /// A type ascription pattern: `foo: f64`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatType { - pub attrs: Vec<Attribute>, - pub pat: Box<Pat>, - pub colon_token: Token![:], - pub ty: Box<Type>, - } -} - -ast_struct! { - /// A pattern that matches any value: `_`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct PatWild { - pub attrs: Vec<Attribute>, - pub underscore_token: Token![_], - } -} - -ast_struct! { - /// A single field in a struct pattern. - /// - /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated - /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct FieldPat { - pub attrs: Vec<Attribute>, - pub member: Member, - pub colon_token: Option<Token![:]>, - pub pat: Box<Pat>, - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - use crate::buffer::Cursor; - use crate::error::{self, Result}; - use crate::expr::{ - Expr, ExprConst, ExprLit, ExprMacro, ExprPath, ExprRange, Member, RangeLimits, - }; - use crate::ext::IdentExt as _; - use crate::ident::Ident; - use crate::lit::Lit; - use crate::mac::{self, Macro}; - use crate::parse::{Parse, ParseStream}; - use crate::pat::{ - FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, - PatTuple, PatTupleStruct, PatType, PatWild, - }; - use crate::path::{self, Path, QSelf}; - use crate::punctuated::Punctuated; - use crate::stmt::Block; - use crate::token; - use crate::verbatim; - use alloc::boxed::Box; - use alloc::vec::Vec; - use proc_macro2::TokenStream; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Pat { - /// Parse a pattern that does _not_ involve `|` at the top level. - /// - /// This parser matches the behavior of the `$:pat_param` macro_rules - /// matcher, and on editions prior to Rust 2021, the behavior of - /// `$:pat`. - /// - /// In Rust syntax, some examples of where this syntax would occur are - /// in the argument pattern of functions and closures. Patterns using - /// `|` are not allowed to occur in these positions. - /// - /// ```compile_fail - /// fn f(Some(_) | None: Option<T>) { - /// let _ = |Some(_) | None: Option<T>| {}; - /// // ^^^^^^^^^^^^^^^^^^^^^^^^^??? :( - /// } - /// ``` - /// - /// ```console - /// error: top-level or-patterns are not allowed in function parameters - /// --> src/main.rs:1:6 - /// | - /// 1 | fn f(Some(_) | None: Option<T>) { - /// | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)` - /// ``` - pub fn parse_single(input: ParseStream) -> Result<Self> { - let begin = input.cursor(); - let lookahead = input.lookahead1(); - if lookahead.peek(Ident) - && (input.peek2(Token![::]) - || input.peek2(Token![!]) - || input.peek2(token::Brace) - || input.peek2(token::Paren) - || input.peek2(Token![..])) - || input.peek(Token![self]) && input.peek2(Token![::]) - || lookahead.peek(Token![::]) - || lookahead.peek(Token![<]) - || input.peek(Token![Self]) - || input.peek(Token![super]) - || input.peek(Token![crate]) - { - pat_path_or_macro_or_struct_or_range(input) - } else if lookahead.peek(Token![_]) { - input.call(pat_wild).map(Pat::Wild) - } else if input.peek(Token![box]) { - pat_box(begin, input) - } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const]) - { - pat_lit_or_range(input) - } else if lookahead.peek(Token![ref]) - || lookahead.peek(Token![mut]) - || input.peek(Token![self]) - || input.peek(Ident) - { - input.call(pat_ident).map(Pat::Ident) - } else if lookahead.peek(Token![&]) { - input.call(pat_reference).map(Pat::Reference) - } else if lookahead.peek(token::Paren) { - input.call(pat_paren_or_tuple) - } else if lookahead.peek(token::Bracket) { - input.call(pat_slice).map(Pat::Slice) - } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) { - pat_range_half_open(input) - } else if lookahead.peek(Token![const]) { - input.call(pat_const).map(Pat::Verbatim) - } else { - Err(lookahead.error()) - } - } - - /// Parse a pattern, possibly involving `|`, but not a leading `|`. - pub fn parse_multi(input: ParseStream) -> Result<Self> { - multi_pat_impl(input, None) - } - - /// Parse a pattern, possibly involving `|`, possibly including a - /// leading `|`. - /// - /// This parser matches the behavior of the Rust 2021 edition's `$:pat` - /// macro_rules matcher. - /// - /// In Rust syntax, an example of where this syntax would occur is in - /// the pattern of a `match` arm, where the language permits an optional - /// leading `|`, although it is not idiomatic to write one there in - /// handwritten code. - /// - /// ``` - /// # let wat = None; - /// match wat { - /// | None | Some(false) => {} - /// | Some(true) => {} - /// } - /// ``` - /// - /// The compiler accepts it only to facilitate some situations in - /// macro-generated code where a macro author might need to write: - /// - /// ``` - /// # macro_rules! doc { - /// # ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => { - /// match $value { - /// $(| $conditions1)* $(| $conditions2)* => $then - /// } - /// # }; - /// # } - /// # - /// # doc!(true, (true), (false), {}); - /// # doc!(true, (), (true, false), {}); - /// # doc!(true, (true, false), (), {}); - /// ``` - /// - /// Expressing the same thing correctly in the case that either one (but - /// not both) of `$conditions1` and `$conditions2` might be empty, - /// without leading `|`, is complex. - /// - /// Use [`Pat::parse_multi`] instead if you are not intending to support - /// macro-generated macro input. - pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> { - let leading_vert: Option<Token![|]> = input.parse()?; - multi_pat_impl(input, leading_vert) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for PatType { - fn parse(input: ParseStream) -> Result<Self> { - Ok(PatType { - attrs: Vec::new(), - pat: Box::new(Pat::parse_single(input)?), - colon_token: input.parse()?, - ty: input.parse()?, - }) - } - } - - fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> { - let mut pat = Pat::parse_single(input)?; - if leading_vert.is_some() - || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) - { - let mut cases = Punctuated::new(); - cases.push_value(pat); - while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { - let punct = input.parse()?; - cases.push_punct(punct); - let pat = Pat::parse_single(input)?; - cases.push_value(pat); - } - pat = Pat::Or(PatOr { attrs: Vec::new(), leading_vert, cases }); - } - Ok(pat) - } - - fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { - let expr_style = true; - let (qself, path) = path::parsing::qpath(input, expr_style)?; - - if qself.is_none() - && input.peek(Token![!]) - && !input.peek(Token![!=]) - && path.is_mod_style() - { - let bang_token: Token![!] = input.parse()?; - let (delimiter, tokens) = mac::parse_delimiter(input)?; - return Ok(Pat::Macro(ExprMacro { - attrs: Vec::new(), - mac: Macro { path, bang_token, delimiter, tokens }, - })); - } - - if input.peek(token::Brace) { - pat_struct(input, qself, path).map(Pat::Struct) - } else if input.peek(token::Paren) { - pat_tuple_struct(input, qself, path).map(Pat::TupleStruct) - } else if input.peek(Token![..]) { - pat_range(input, qself, path) - } else { - Ok(Pat::Path(ExprPath { attrs: Vec::new(), qself, path })) - } - } - - fn pat_wild(input: ParseStream) -> Result<PatWild> { - Ok(PatWild { attrs: Vec::new(), underscore_token: input.parse()? }) - } - - fn pat_box(begin: Cursor, input: ParseStream) -> Result<Pat> { - input.parse::<Token![box]>()?; - Pat::parse_single(input)?; - Ok(Pat::Verbatim(verbatim::between(begin, input.cursor()))) - } - - fn pat_ident(input: ParseStream) -> Result<PatIdent> { - Ok(PatIdent { - attrs: Vec::new(), - by_ref: input.parse()?, - mutability: input.parse()?, - ident: { - if input.peek(Token![self]) { - input.call(Ident::parse_any)? - } else { - input.parse()? - } - }, - subpat: { - if input.peek(Token![@]) { - let at_token: Token![@] = input.parse()?; - let subpat = Pat::parse_single(input)?; - Some((at_token, Box::new(subpat))) - } else { - None - } - }, - }) - } - - fn pat_tuple_struct( - input: ParseStream, - qself: Option<QSelf>, - path: Path, - ) -> Result<PatTupleStruct> { - let content; - let paren_token = parenthesized!(content in input); - - let mut elems = Punctuated::new(); - while !content.is_empty() { - let value = Pat::parse_multi_with_leading_vert(&content)?; - elems.push_value(value); - if content.is_empty() { - break; - } - let punct = content.parse()?; - elems.push_punct(punct); - } - - Ok(PatTupleStruct { attrs: Vec::new(), qself, path, paren_token, elems }) - } - - fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> { - let content; - let brace_token = braced!(content in input); - - let mut fields = Punctuated::new(); - let mut rest = None; - while !content.is_empty() { - let attrs = content.call(Attribute::parse_outer)?; - if content.peek(Token![..]) { - rest = Some(PatRest { attrs, dot2_token: content.parse()? }); - break; - } - let mut value = content.call(field_pat)?; - value.attrs = attrs; - fields.push_value(value); - if content.is_empty() { - break; - } - let punct: Token![,] = content.parse()?; - fields.push_punct(punct); - } - - Ok(PatStruct { attrs: Vec::new(), qself, path, brace_token, fields, rest }) - } - - fn field_pat(input: ParseStream) -> Result<FieldPat> { - let begin = input.cursor(); - let boxed: Option<Token![box]> = input.parse()?; - let by_ref: Option<Token![ref]> = input.parse()?; - let mutability: Option<Token![mut]> = input.parse()?; - - let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() { - input.parse().map(Member::Named) - } else { - input.parse() - }?; - - if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) - || !member.is_named() - { - return Ok(FieldPat { - attrs: Vec::new(), - member, - colon_token: Some(input.parse()?), - pat: Box::new(Pat::parse_multi_with_leading_vert(input)?), - }); - } - - let ident = match member { - Member::Named(ident) => ident, - Member::Unnamed(_) => unreachable!(), - }; - - let pat = if boxed.is_some() { - Pat::Verbatim(verbatim::between(begin, input.cursor())) - } else { - Pat::Ident(PatIdent { - attrs: Vec::new(), - by_ref, - mutability, - ident: ident.clone(), - subpat: None, - }) - }; - - Ok(FieldPat { - attrs: Vec::new(), - member: Member::Named(ident), - colon_token: None, - pat: Box::new(pat), - }) - } - - fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> { - let limits = RangeLimits::parse_obsolete(input)?; - let end = input.call(pat_range_bound)?; - if let (RangeLimits::Closed(_), None) = (&limits, &end) { - return Err(input.error("expected range upper bound")); - } - Ok(Pat::Range(ExprRange { - attrs: Vec::new(), - start: Some(Box::new(Expr::Path(ExprPath { attrs: Vec::new(), qself, path }))), - limits, - end: end.map(PatRangeBound::into_expr), - })) - } - - fn pat_range_half_open(input: ParseStream) -> Result<Pat> { - let limits: RangeLimits = input.parse()?; - let end = input.call(pat_range_bound)?; - if end.is_some() { - Ok(Pat::Range(ExprRange { - attrs: Vec::new(), - start: None, - limits, - end: end.map(PatRangeBound::into_expr), - })) - } else { - match limits { - RangeLimits::HalfOpen(dot2_token) => { - Ok(Pat::Rest(PatRest { attrs: Vec::new(), dot2_token })) - } - RangeLimits::Closed(_) => Err(input.error("expected range upper bound")), - } - } - } - - fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> { - let content; - let paren_token = parenthesized!(content in input); - - let mut elems = Punctuated::new(); - while !content.is_empty() { - let value = Pat::parse_multi_with_leading_vert(&content)?; - if content.is_empty() { - if elems.is_empty() && !matches!(value, Pat::Rest(_)) { - return Ok(Pat::Paren(PatParen { - attrs: Vec::new(), - paren_token, - pat: Box::new(value), - })); - } - elems.push_value(value); - break; - } - elems.push_value(value); - let punct = content.parse()?; - elems.push_punct(punct); - } - - Ok(Pat::Tuple(PatTuple { attrs: Vec::new(), paren_token, elems })) - } - - fn pat_reference(input: ParseStream) -> Result<PatReference> { - Ok(PatReference { - attrs: Vec::new(), - and_token: input.parse()?, - mutability: input.parse()?, - pat: Box::new(Pat::parse_single(input)?), - }) - } - - fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { - let start = input.call(pat_range_bound)?.unwrap(); - if input.peek(Token![..]) { - let limits = RangeLimits::parse_obsolete(input)?; - let end = input.call(pat_range_bound)?; - if let (RangeLimits::Closed(_), None) = (&limits, &end) { - return Err(input.error("expected range upper bound")); - } - Ok(Pat::Range(ExprRange { - attrs: Vec::new(), - start: Some(start.into_expr()), - limits, - end: end.map(PatRangeBound::into_expr), - })) - } else { - Ok(start.into_pat()) - } - } - - // Patterns that can appear on either side of a range pattern. - enum PatRangeBound { - Const(ExprConst), - Lit(ExprLit), - Path(ExprPath), - } - - impl PatRangeBound { - fn into_expr(self) -> Box<Expr> { - Box::new(match self { - PatRangeBound::Const(pat) => Expr::Const(pat), - PatRangeBound::Lit(pat) => Expr::Lit(pat), - PatRangeBound::Path(pat) => Expr::Path(pat), - }) - } - - fn into_pat(self) -> Pat { - match self { - PatRangeBound::Const(pat) => Pat::Const(pat), - PatRangeBound::Lit(pat) => Pat::Lit(pat), - PatRangeBound::Path(pat) => Pat::Path(pat), - } - } - } - - fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> { - if input.is_empty() - || input.peek(Token![|]) - || input.peek(Token![=]) - || input.peek(Token![:]) && !input.peek(Token![::]) - || input.peek(Token![,]) - || input.peek(Token![;]) - || input.peek(Token![if]) - { - return Ok(None); - } - - let lookahead = input.lookahead1(); - let expr = if lookahead.peek(Lit) { - PatRangeBound::Lit(input.parse()?) - } else if lookahead.peek(Ident) - || lookahead.peek(Token![::]) - || lookahead.peek(Token![<]) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![Self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - { - PatRangeBound::Path(input.parse()?) - } else if lookahead.peek(Token![const]) { - PatRangeBound::Const(input.parse()?) - } else { - return Err(lookahead.error()); - }; - - Ok(Some(expr)) - } - - fn pat_slice(input: ParseStream) -> Result<PatSlice> { - let content; - let bracket_token = bracketed!(content in input); - - let mut elems = Punctuated::new(); - while !content.is_empty() { - let value = Pat::parse_multi_with_leading_vert(&content)?; - match value { - Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => { - let (start, end) = match pat.limits { - RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]), - RangeLimits::Closed(dot_dot_eq) => { - (dot_dot_eq.spans[0], dot_dot_eq.spans[2]) - } - }; - let msg = "range pattern is not allowed unparenthesized inside slice pattern"; - return Err(error::new2(start, end, msg)); - } - _ => {} - } - elems.push_value(value); - if content.is_empty() { - break; - } - let punct = content.parse()?; - elems.push_punct(punct); - } - - Ok(PatSlice { attrs: Vec::new(), bracket_token, elems }) - } - - fn pat_const(input: ParseStream) -> Result<TokenStream> { - let begin = input.cursor(); - input.parse::<Token![const]>()?; - - let content; - braced!(content in input); - content.call(Attribute::parse_inner)?; - content.call(Block::parse_within)?; - - Ok(verbatim::between(begin, input.cursor())) - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::attr::FilterAttrs; - use crate::pat::{ - FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, - PatTuple, PatTupleStruct, PatType, PatWild, - }; - use crate::path; - use crate::path::printing::PathStyle; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatIdent { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.by_ref.to_tokens(tokens); - self.mutability.to_tokens(tokens); - self.ident.to_tokens(tokens); - if let Some((at_token, subpat)) = &self.subpat { - at_token.to_tokens(tokens); - subpat.to_tokens(tokens); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatOr { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.leading_vert.to_tokens(tokens); - self.cases.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatParen { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.paren_token.surround(tokens, |tokens| { - self.pat.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatReference { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.and_token.to_tokens(tokens); - self.mutability.to_tokens(tokens); - self.pat.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatRest { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.dot2_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatSlice { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.bracket_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatStruct { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr); - self.brace_token.surround(tokens, |tokens| { - self.fields.to_tokens(tokens); - // NOTE: We need a comma before the dot2 token if it is present. - if !self.fields.empty_or_trailing() && self.rest.is_some() { - <Token![,]>::default().to_tokens(tokens); - } - self.rest.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatTuple { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.paren_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); - // If there is only one element, a trailing comma is needed to - // distinguish PatTuple from PatParen, unless this is `(..)` - // which is a tuple pattern even without comma. - if self.elems.len() == 1 - && !self.elems.trailing_punct() - && !matches!(self.elems[0], Pat::Rest { .. }) - { - <Token![,]>::default().to_tokens(tokens); - } - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatTupleStruct { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::Expr); - self.paren_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatType { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.pat.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PatWild { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - self.underscore_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for FieldPat { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - if let Some(colon_token) = &self.colon_token { - self.member.to_tokens(tokens); - colon_token.to_tokens(tokens); - } - self.pat.to_tokens(tokens); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/path.rs b/deps/crates/vendor/syn-v2/src/path.rs deleted file mode 100644 index 20fc484b242b..000000000000 --- a/deps/crates/vendor/syn-v2/src/path.rs +++ /dev/null @@ -1,945 +0,0 @@ -#[cfg(feature = "parsing")] -use crate::error::Result; -use crate::expr::Expr; -use crate::generics::TypeParamBound; -use crate::ident::Ident; -use crate::lifetime::Lifetime; -use crate::punctuated::Punctuated; -use crate::token; -use crate::ty::{ReturnType, Type}; -use alloc::boxed::Box; - -ast_struct! { - /// A path at which a named item is exported (e.g. `alloc::collections::HashMap`). - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Path { - pub leading_colon: Option<Token![::]>, - pub segments: Punctuated<PathSegment, Token![::]>, - } -} - -impl<T> From<T> for Path -where - T: Into<PathSegment>, -{ - fn from(segment: T) -> Self { - let mut path = Path { leading_colon: None, segments: Punctuated::new() }; - path.segments.push_value(segment.into()); - path - } -} - -impl Path { - /// Determines whether this is a path of length 1 equal to the given - /// ident. - /// - /// For them to compare equal, it must be the case that: - /// - /// - the path has no leading colon, - /// - the number of path segments is 1, - /// - the first path segment has no angle bracketed or parenthesized path - /// arguments, and - /// - the ident of the first path segment is equal to the given one. - /// - /// # Example - /// - /// ``` - /// use proc_macro2::TokenStream; - /// use syn::{Attribute, Error, Meta, Result}; - /// - /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> { - /// if attr.path().is_ident("serde") { - /// match &attr.meta { - /// Meta::List(meta) => Ok(Some(&meta.tokens)), - /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")), - /// } - /// } else { - /// Ok(None) - /// } - /// } - /// ``` - pub fn is_ident<I>(&self, ident: &I) -> bool - where - I: ?Sized, - Ident: PartialEq<I>, - { - match self.get_ident() { - Some(id) => id == ident, - None => false, - } - } - - /// If this path consists of a single ident, returns the ident. - /// - /// A path is considered an ident if: - /// - /// - the path has no leading colon, - /// - the number of path segments is 1, and - /// - the first path segment has no angle bracketed or parenthesized path - /// arguments. - pub fn get_ident(&self) -> Option<&Ident> { - if self.leading_colon.is_none() - && self.segments.len() == 1 - && self.segments[0].arguments.is_none() - { - Some(&self.segments[0].ident) - } else { - None - } - } - - /// An error if this path is not a single ident, as defined in `get_ident`. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn require_ident(&self) -> Result<&Ident> { - self.get_ident().ok_or_else(|| { - crate::error::new2( - self.segments.first().unwrap().ident.span(), - self.segments.last().unwrap().ident.span(), - "expected this path to be an identifier", - ) - }) - } -} - -ast_struct! { - /// A segment of a path together with any path arguments on that segment. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct PathSegment { - pub ident: Ident, - pub arguments: PathArguments, - } -} - -impl<T> From<T> for PathSegment -where - T: Into<Ident>, -{ - fn from(ident: T) -> Self { - PathSegment { ident: ident.into(), arguments: PathArguments::None } - } -} - -ast_enum! { - /// Angle bracketed or parenthesized arguments of a path segment. - /// - /// ## Angle bracketed - /// - /// The `<'a, T>` in `core::slice::iter<'a, T>`. - /// - /// ## Parenthesized - /// - /// The `(A, B) -> C` in `Fn(A, B) -> C`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum PathArguments { - None, - /// The `<'a, T>` in `core::slice::iter<'a, T>`. - AngleBracketed(AngleBracketedGenericArguments), - /// The `(A, B) -> C` in `Fn(A, B) -> C`. - Parenthesized(ParenthesizedGenericArguments), - } -} - -impl Default for PathArguments { - fn default() -> Self { - PathArguments::None - } -} - -impl PathArguments { - pub fn is_empty(&self) -> bool { - match self { - PathArguments::None => true, - PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(), - PathArguments::Parenthesized(_) => false, - } - } - - pub fn is_none(&self) -> bool { - match self { - PathArguments::None => true, - PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, - } - } -} - -ast_enum! { - /// An individual generic argument, like `'a`, `T`, or `Item = T`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum GenericArgument { - /// A lifetime argument. - Lifetime(Lifetime), - /// A type argument. - Type(Type), - /// A const expression. Must be inside of a block. - /// - /// NOTE: Identity expressions are represented as Type arguments, as - /// they are indistinguishable syntactically. - Const(Expr), - /// A binding (equality constraint) on an associated type: the `Item = - /// u8` in `Iterator<Item = u8>`. - AssocType(AssocType), - /// An equality constraint on an associated constant: the `PANIC = - /// false` in `Trait<PANIC = false>`. - AssocConst(AssocConst), - /// An associated type bound: `Iterator<Item: Display>`. - Constraint(Constraint), - } -} - -ast_struct! { - /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, - /// V>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct AngleBracketedGenericArguments { - pub colon2_token: Option<Token![::]>, - pub lt_token: Token![<], - pub args: Punctuated<GenericArgument, Token![,]>, - pub gt_token: Token![>], - } -} - -ast_struct! { - /// A binding (equality constraint) on an associated type: the `Item = u8` - /// in `Iterator<Item = u8>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct AssocType { - pub ident: Ident, - pub generics: Option<AngleBracketedGenericArguments>, - pub eq_token: Token![=], - pub ty: Type, - } -} - -ast_struct! { - /// An equality constraint on an associated constant: the `PANIC = false` in - /// `Trait<PANIC = false>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct AssocConst { - pub ident: Ident, - pub generics: Option<AngleBracketedGenericArguments>, - pub eq_token: Token![=], - pub value: Expr, - } -} - -ast_struct! { - /// An associated type bound: `Iterator<Item: Display>`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Constraint { - pub ident: Ident, - pub generics: Option<AngleBracketedGenericArguments>, - pub colon_token: Token![:], - pub bounds: Punctuated<TypeParamBound, Token![+]>, - } -} - -ast_struct! { - /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> - /// C`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct ParenthesizedGenericArguments { - pub paren_token: token::Paren, - /// `(A, B)` - pub inputs: Punctuated<Type, Token![,]>, - /// `C` - pub output: ReturnType, - } -} - -ast_struct! { - /// The explicit Self type in a qualified path: the `T` in `<T as - /// Display>::fmt`. - /// - /// The actual path, including the trait and the associated item, is stored - /// separately. The `position` field represents the index of the associated - /// item qualified with this Self type. - /// - /// ```text - /// <Vec<T> as a::b::Trait>::AssociatedItem - /// ^~~~~~ ~~~~~~~~~~~~~~^ - /// ty position = 3 - /// - /// <Vec<T>>::AssociatedItem - /// ^~~~~~ ^ - /// ty position = 0 - /// ``` - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct QSelf { - pub lt_token: Token![<], - pub ty: Box<Type>, - pub position: usize, - pub as_token: Option<Token![as]>, - pub gt_token: Token![>], - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::error::Result; - #[cfg(feature = "full")] - use crate::expr::ExprBlock; - use crate::expr::{Expr, ExprPath}; - use crate::ext::IdentExt as _; - use crate::generics::TypeParamBound; - use crate::ident::Ident; - use crate::lifetime::Lifetime; - use crate::lit::Lit; - use crate::parse::{Parse, ParseStream}; - use crate::path::{ - AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, - ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, - }; - use crate::punctuated::Punctuated; - use crate::token; - use crate::ty::{ReturnType, Type}; - #[cfg(not(feature = "full"))] - use crate::verbatim; - use alloc::boxed::Box; - use alloc::vec::Vec; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Path { - fn parse(input: ParseStream) -> Result<Self> { - Self::parse_helper(input, false) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for GenericArgument { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Lifetime) && !input.peek2(Token![+]) { - return Ok(GenericArgument::Lifetime(input.parse()?)); - } - - if input.peek(Lit) || input.peek(token::Brace) { - return const_argument(input).map(GenericArgument::Const); - } - - let mut argument: Type = input.parse()?; - - match argument { - Type::Path(mut ty) - if ty.qself.is_none() - && ty.path.leading_colon.is_none() - && ty.path.segments.len() == 1 - && match &ty.path.segments[0].arguments { - PathArguments::None | PathArguments::AngleBracketed(_) => true, - PathArguments::Parenthesized(_) => false, - } => - { - if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { - let segment = ty.path.segments.pop().unwrap().into_value(); - let ident = segment.ident; - let generics = match segment.arguments { - PathArguments::None => None, - PathArguments::AngleBracketed(arguments) => Some(arguments), - PathArguments::Parenthesized(_) => unreachable!(), - }; - return if input.peek(Lit) || input.peek(token::Brace) { - Ok(GenericArgument::AssocConst(AssocConst { - ident, - generics, - eq_token, - value: const_argument(input)?, - })) - } else { - Ok(GenericArgument::AssocType(AssocType { - ident, - generics, - eq_token, - ty: input.parse()?, - })) - }; - } - - if let Some(colon_token) = input.parse::<Option<Token![:]>>()? { - let segment = ty.path.segments.pop().unwrap().into_value(); - return Ok(GenericArgument::Constraint(Constraint { - ident: segment.ident, - generics: match segment.arguments { - PathArguments::None => None, - PathArguments::AngleBracketed(arguments) => Some(arguments), - PathArguments::Parenthesized(_) => unreachable!(), - }, - colon_token, - bounds: { - let mut bounds = Punctuated::new(); - loop { - if input.peek(Token![,]) || input.peek(Token![>]) { - break; - } - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = true; - TypeParamBound::parse_single( - input, - allow_precise_capture, - allow_const, - )? - }); - if !input.peek(Token![+]) { - break; - } - let punct: Token![+] = input.parse()?; - bounds.push_punct(punct); - } - bounds - }, - })); - } - - argument = Type::Path(ty); - } - _ => {} - } - - Ok(GenericArgument::Type(argument)) - } - } - - pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> { - let lookahead = input.lookahead1(); - - if input.peek(Lit) { - let lit = input.parse()?; - return Ok(Expr::Lit(lit)); - } - - if input.peek(Ident) { - let ident: Ident = input.parse()?; - return Ok(Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path::from(ident), - })); - } - - if input.peek(token::Brace) { - #[cfg(feature = "full")] - { - let block: ExprBlock = input.parse()?; - return Ok(Expr::Block(block)); - } - - #[cfg(not(feature = "full"))] - { - let begin = input.cursor(); - let content; - braced!(content in input); - content.parse::<Expr>()?; - let verbatim = verbatim::between(begin, input.cursor()); - return Ok(Expr::Verbatim(verbatim)); - } - } - - Err(lookahead.error()) - } - - impl AngleBracketedGenericArguments { - /// Parse `::<…>` with mandatory leading `::`. - /// - /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments` - /// parses optional leading `::`. - #[cfg(feature = "full")] - #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))] - pub fn parse_turbofish(input: ParseStream) -> Result<Self> { - let colon2_token: Token![::] = input.parse()?; - Self::do_parse(Some(colon2_token), input) - } - - pub(crate) fn do_parse( - colon2_token: Option<Token![::]>, - input: ParseStream, - ) -> Result<Self> { - Ok(AngleBracketedGenericArguments { - colon2_token, - lt_token: input.parse()?, - args: { - let mut args = Punctuated::new(); - loop { - if input.peek(Token![>]) { - break; - } - let value: GenericArgument = input.parse()?; - args.push_value(value); - if input.peek(Token![>]) { - break; - } - let punct: Token![,] = input.parse()?; - args.push_punct(punct); - } - args - }, - gt_token: input.parse()?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for AngleBracketedGenericArguments { - fn parse(input: ParseStream) -> Result<Self> { - let colon2_token: Option<Token![::]> = input.parse()?; - Self::do_parse(colon2_token, input) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ParenthesizedGenericArguments { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(ParenthesizedGenericArguments { - paren_token: parenthesized!(content in input), - inputs: content.parse_terminated(Type::parse, Token![,])?, - output: input.call(ReturnType::without_plus)?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for PathSegment { - fn parse(input: ParseStream) -> Result<Self> { - Self::parse_helper(input, false) - } - } - - impl PathSegment { - fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { - if input.peek(Token![super]) - || input.peek(Token![self]) - || input.peek(Token![crate]) - || cfg!(feature = "full") && input.peek(Token![try]) - { - let ident = input.call(Ident::parse_any)?; - return Ok(PathSegment::from(ident)); - } - - let ident = if input.peek(Token![Self]) { - input.call(Ident::parse_any)? - } else { - input.parse()? - }; - - if !expr_style - && input.peek(Token![<]) - && !input.peek(Token![<=]) - && !input.peek(Token![<<=]) - || input.peek(Token![::]) && input.peek3(Token![<]) - { - Ok(PathSegment { ident, arguments: PathArguments::AngleBracketed(input.parse()?) }) - } else { - Ok(PathSegment::from(ident)) - } - } - } - - impl Path { - /// Parse a `Path` containing no path arguments on any of its segments. - /// - /// # Example - /// - /// ``` - /// use syn::{Path, Result, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // A simplified single `use` statement like: - /// // - /// // use alloc::collections::HashMap; - /// // - /// // Note that generic parameters are not allowed in a `use` statement - /// // so the following must not be accepted. - /// // - /// // use a::<b>::c; - /// struct SingleUse { - /// use_token: Token![use], - /// path: Path, - /// } - /// - /// impl Parse for SingleUse { - /// fn parse(input: ParseStream) -> Result<Self> { - /// Ok(SingleUse { - /// use_token: input.parse()?, - /// path: input.call(Path::parse_mod_style)?, - /// }) - /// } - /// } - /// ``` - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_mod_style(input: ParseStream) -> Result<Self> { - Ok(Path { - leading_colon: input.parse()?, - segments: { - let mut segments = Punctuated::new(); - loop { - if !input.peek(Ident) - && !input.peek(Token![super]) - && !input.peek(Token![self]) - && !input.peek(Token![Self]) - && !input.peek(Token![crate]) - { - break; - } - let ident = Ident::parse_any(input)?; - segments.push_value(PathSegment::from(ident)); - if !input.peek(Token![::]) { - break; - } - let punct = input.parse()?; - segments.push_punct(punct); - } - if segments.is_empty() { - return Err(input.parse::<Ident>().unwrap_err()); - } else if segments.trailing_punct() { - return Err(input.error("expected path segment after `::`")); - } - segments - }, - }) - } - - pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { - let mut path = Path { - leading_colon: input.parse()?, - segments: { - let mut segments = Punctuated::new(); - let value = PathSegment::parse_helper(input, expr_style)?; - segments.push_value(value); - segments - }, - }; - Path::parse_rest(input, &mut path, expr_style)?; - Ok(path) - } - - pub(crate) fn parse_rest( - input: ParseStream, - path: &mut Self, - expr_style: bool, - ) -> Result<()> { - while input.peek(Token![::]) && !input.peek3(token::Paren) { - let punct: Token![::] = input.parse()?; - path.segments.push_punct(punct); - let value = PathSegment::parse_helper(input, expr_style)?; - path.segments.push_value(value); - } - Ok(()) - } - - pub(crate) fn is_mod_style(&self) -> bool { - self.segments.iter().all(|segment| segment.arguments.is_none()) - } - } - - pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { - if input.peek(Token![<]) { - let lt_token: Token![<] = input.parse()?; - let this: Type = input.parse()?; - let path = if input.peek(Token![as]) { - let as_token: Token![as] = input.parse()?; - let path: Path = input.parse()?; - Some((as_token, path)) - } else { - None - }; - let gt_token: Token![>] = input.parse()?; - let colon2_token: Token![::] = input.parse()?; - let mut rest = Punctuated::new(); - loop { - let path = PathSegment::parse_helper(input, expr_style)?; - rest.push_value(path); - if !input.peek(Token![::]) { - break; - } - let punct: Token![::] = input.parse()?; - rest.push_punct(punct); - } - let (position, as_token, path) = match path { - Some((as_token, mut path)) => { - let pos = path.segments.len(); - path.segments.push_punct(colon2_token); - path.segments.extend(rest.into_pairs()); - (pos, Some(as_token), path) - } - None => { - let path = Path { leading_colon: Some(colon2_token), segments: rest }; - (0, None, path) - } - }; - let qself = QSelf { lt_token, ty: Box::new(this), position, as_token, gt_token }; - Ok((Some(qself), path)) - } else { - let path = Path::parse_helper(input, expr_style)?; - Ok((None, path)) - } - } -} - -#[cfg(feature = "printing")] -pub(crate) mod printing { - use crate::generics; - use crate::path::{ - AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, - ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, - }; - use crate::print::TokensOrDefault; - #[cfg(feature = "parsing")] - use crate::spanned::Spanned; - use core::cmp; - #[cfg(feature = "parsing")] - use proc_macro2::Span; - use proc_macro2::TokenStream; - use quote::ToTokens; - - pub(crate) enum PathStyle { - Expr, - Mod, - AsWritten, - } - - impl Copy for PathStyle {} - - impl Clone for PathStyle { - fn clone(&self) -> Self { - *self - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Path { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_path(tokens, self, PathStyle::AsWritten); - } - } - - pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) { - path.leading_colon.to_tokens(tokens); - for segment in path.segments.pairs() { - print_path_segment(tokens, segment.value(), style); - segment.punct().to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PathSegment { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_path_segment(tokens, self, PathStyle::AsWritten); - } - } - - fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) { - segment.ident.to_tokens(tokens); - print_path_arguments(tokens, &segment.arguments, style); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for PathArguments { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_path_arguments(tokens, self, PathStyle::AsWritten); - } - } - - fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) { - match arguments { - PathArguments::None => {} - PathArguments::AngleBracketed(arguments) => { - print_angle_bracketed_generic_arguments(tokens, arguments, style); - } - PathArguments::Parenthesized(arguments) => { - print_parenthesized_generic_arguments(tokens, arguments, style); - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for GenericArgument { - #[allow(clippy::match_same_arms)] - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - GenericArgument::Lifetime(lt) => lt.to_tokens(tokens), - GenericArgument::Type(ty) => ty.to_tokens(tokens), - GenericArgument::Const(expr) => { - generics::printing::print_const_argument(expr, tokens); - } - GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens), - GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens), - GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for AngleBracketedGenericArguments { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten); - } - } - - pub(crate) fn print_angle_bracketed_generic_arguments( - tokens: &mut TokenStream, - arguments: &AngleBracketedGenericArguments, - style: PathStyle, - ) { - if let PathStyle::Mod = style { - return; - } - - conditionally_print_turbofish(tokens, &arguments.colon2_token, style); - arguments.lt_token.to_tokens(tokens); - - // Print lifetimes before types/consts/bindings, regardless of their - // order in args. - let mut trailing_or_empty = true; - for param in arguments.args.pairs() { - match param.value() { - GenericArgument::Lifetime(_) => { - param.to_tokens(tokens); - trailing_or_empty = param.punct().is_some(); - } - GenericArgument::Type(_) - | GenericArgument::Const(_) - | GenericArgument::AssocType(_) - | GenericArgument::AssocConst(_) - | GenericArgument::Constraint(_) => {} - } - } - for param in arguments.args.pairs() { - match param.value() { - GenericArgument::Type(_) - | GenericArgument::Const(_) - | GenericArgument::AssocType(_) - | GenericArgument::AssocConst(_) - | GenericArgument::Constraint(_) => { - if !trailing_or_empty { - <Token![,]>::default().to_tokens(tokens); - } - param.to_tokens(tokens); - trailing_or_empty = param.punct().is_some(); - } - GenericArgument::Lifetime(_) => {} - } - } - - arguments.gt_token.to_tokens(tokens); - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for AssocType { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - self.ty.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for AssocConst { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.eq_token.to_tokens(tokens); - generics::printing::print_const_argument(&self.value, tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Constraint { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); - self.colon_token.to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ParenthesizedGenericArguments { - fn to_tokens(&self, tokens: &mut TokenStream) { - print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten); - } - } - - fn print_parenthesized_generic_arguments( - tokens: &mut TokenStream, - arguments: &ParenthesizedGenericArguments, - style: PathStyle, - ) { - if let PathStyle::Mod = style { - return; - } - - conditionally_print_turbofish(tokens, &None, style); - arguments.paren_token.surround(tokens, |tokens| { - arguments.inputs.to_tokens(tokens); - }); - arguments.output.to_tokens(tokens); - } - - pub(crate) fn print_qpath( - tokens: &mut TokenStream, - qself: &Option<QSelf>, - path: &Path, - style: PathStyle, - ) { - let qself = match qself { - Some(qself) => qself, - None => { - print_path(tokens, path, style); - return; - } - }; - qself.lt_token.to_tokens(tokens); - qself.ty.to_tokens(tokens); - - let pos = cmp::min(qself.position, path.segments.len()); - let mut segments = path.segments.pairs(); - if pos > 0 { - TokensOrDefault(&qself.as_token).to_tokens(tokens); - path.leading_colon.to_tokens(tokens); - for (i, segment) in segments.by_ref().take(pos).enumerate() { - print_path_segment(tokens, segment.value(), PathStyle::AsWritten); - if i + 1 == pos { - qself.gt_token.to_tokens(tokens); - } - segment.punct().to_tokens(tokens); - } - } else { - qself.gt_token.to_tokens(tokens); - path.leading_colon.to_tokens(tokens); - } - for segment in segments { - print_path_segment(tokens, segment.value(), style); - segment.punct().to_tokens(tokens); - } - } - - fn conditionally_print_turbofish( - tokens: &mut TokenStream, - colon2_token: &Option<Token![::]>, - style: PathStyle, - ) { - match style { - PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens), - PathStyle::Mod => unreachable!(), - PathStyle::AsWritten => colon2_token.to_tokens(tokens), - } - } - - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] - impl Spanned for QSelf { - fn span(&self) -> Span { - struct QSelfDelimiters<'a>(&'a QSelf); - - impl<'a> ToTokens for QSelfDelimiters<'a> { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.0.lt_token.to_tokens(tokens); - self.0.gt_token.to_tokens(tokens); - } - } - - QSelfDelimiters(self).span() - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/precedence.rs b/deps/crates/vendor/syn-v2/src/precedence.rs deleted file mode 100644 index d225f7f41568..000000000000 --- a/deps/crates/vendor/syn-v2/src/precedence.rs +++ /dev/null @@ -1,210 +0,0 @@ -#[cfg(all(feature = "printing", feature = "full"))] -use crate::attr::{AttrStyle, Attribute}; -#[cfg(feature = "printing")] -use crate::expr::Expr; -#[cfg(all(feature = "printing", feature = "full"))] -use crate::expr::{ - ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, ExprCall, ExprConst, ExprContinue, - ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLit, ExprLoop, ExprMacro, - ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, ExprReturn, ExprStruct, ExprTry, - ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield, -}; -use crate::op::BinOp; -#[cfg(all(feature = "printing", feature = "full"))] -use crate::ty::ReturnType; -use core::cmp::Ordering; - -// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence -pub(crate) enum Precedence { - // return, break, closures - Jump, - // = += -= *= /= %= &= |= ^= <<= >>= - Assign, - // .. ..= - Range, - // || - Or, - // && - And, - // let - #[cfg(feature = "printing")] - Let, - // == != < > <= >= - Compare, - // | - BitOr, - // ^ - BitXor, - // & - BitAnd, - // << >> - Shift, - // + - - Sum, - // * / % - Product, - // as - Cast, - // unary - * ! & &mut - #[cfg(feature = "printing")] - Prefix, - // paths, loops, function calls, array indexing, field expressions, method calls - #[cfg(feature = "printing")] - Unambiguous, -} - -impl Precedence { - pub(crate) const MIN: Self = Precedence::Jump; - - pub(crate) fn of_binop(op: &BinOp) -> Self { - match op { - BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum, - BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product, - BinOp::And(_) => Precedence::And, - BinOp::Or(_) => Precedence::Or, - BinOp::BitXor(_) => Precedence::BitXor, - BinOp::BitAnd(_) => Precedence::BitAnd, - BinOp::BitOr(_) => Precedence::BitOr, - BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift, - - BinOp::Eq(_) - | BinOp::Lt(_) - | BinOp::Le(_) - | BinOp::Ne(_) - | BinOp::Ge(_) - | BinOp::Gt(_) => Precedence::Compare, - - BinOp::AddAssign(_) - | BinOp::SubAssign(_) - | BinOp::MulAssign(_) - | BinOp::DivAssign(_) - | BinOp::RemAssign(_) - | BinOp::BitXorAssign(_) - | BinOp::BitAndAssign(_) - | BinOp::BitOrAssign(_) - | BinOp::ShlAssign(_) - | BinOp::ShrAssign(_) => Precedence::Assign, - } - } - - #[cfg(feature = "printing")] - pub(crate) fn of(e: &Expr) -> Self { - #[cfg(feature = "full")] - fn prefix_attrs(attrs: &[Attribute]) -> Precedence { - for attr in attrs { - if let AttrStyle::Outer = attr.style { - return Precedence::Prefix; - } - } - Precedence::Unambiguous - } - - match e { - #[cfg(feature = "full")] - Expr::Closure(e) => match e.output { - ReturnType::Default => Precedence::Jump, - ReturnType::Type(..) => prefix_attrs(&e.attrs), - }, - - #[cfg(feature = "full")] - Expr::Break(ExprBreak { expr, .. }) - | Expr::Return(ExprReturn { expr, .. }) - | Expr::Yield(ExprYield { expr, .. }) => match expr { - Some(_) => Precedence::Jump, - None => Precedence::Unambiguous, - }, - - Expr::Assign(_) => Precedence::Assign, - Expr::Range(_) => Precedence::Range, - Expr::Binary(e) => Precedence::of_binop(&e.op), - Expr::Let(_) => Precedence::Let, - Expr::Cast(_) => Precedence::Cast, - Expr::RawAddr(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix, - - #[cfg(feature = "full")] - Expr::Array(ExprArray { attrs, .. }) - | Expr::Async(ExprAsync { attrs, .. }) - | Expr::Await(ExprAwait { attrs, .. }) - | Expr::Block(ExprBlock { attrs, .. }) - | Expr::Call(ExprCall { attrs, .. }) - | Expr::Const(ExprConst { attrs, .. }) - | Expr::Continue(ExprContinue { attrs, .. }) - | Expr::Field(ExprField { attrs, .. }) - | Expr::ForLoop(ExprForLoop { attrs, .. }) - | Expr::Group(ExprGroup { attrs, .. }) - | Expr::If(ExprIf { attrs, .. }) - | Expr::Index(ExprIndex { attrs, .. }) - | Expr::Infer(ExprInfer { attrs, .. }) - | Expr::Lit(ExprLit { attrs, .. }) - | Expr::Loop(ExprLoop { attrs, .. }) - | Expr::Macro(ExprMacro { attrs, .. }) - | Expr::Match(ExprMatch { attrs, .. }) - | Expr::MethodCall(ExprMethodCall { attrs, .. }) - | Expr::Paren(ExprParen { attrs, .. }) - | Expr::Path(ExprPath { attrs, .. }) - | Expr::Repeat(ExprRepeat { attrs, .. }) - | Expr::Struct(ExprStruct { attrs, .. }) - | Expr::Try(ExprTry { attrs, .. }) - | Expr::TryBlock(ExprTryBlock { attrs, .. }) - | Expr::Tuple(ExprTuple { attrs, .. }) - | Expr::Unsafe(ExprUnsafe { attrs, .. }) - | Expr::While(ExprWhile { attrs, .. }) => prefix_attrs(attrs), - - #[cfg(not(feature = "full"))] - Expr::Array(_) - | Expr::Async(_) - | Expr::Await(_) - | Expr::Block(_) - | Expr::Call(_) - | Expr::Const(_) - | Expr::Continue(_) - | Expr::Field(_) - | Expr::ForLoop(_) - | Expr::Group(_) - | Expr::If(_) - | Expr::Index(_) - | Expr::Infer(_) - | Expr::Lit(_) - | Expr::Loop(_) - | Expr::Macro(_) - | Expr::Match(_) - | Expr::MethodCall(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::Repeat(_) - | Expr::Struct(_) - | Expr::Try(_) - | Expr::TryBlock(_) - | Expr::Tuple(_) - | Expr::Unsafe(_) - | Expr::While(_) => Precedence::Unambiguous, - - Expr::Verbatim(_) => Precedence::Unambiguous, - - #[cfg(not(feature = "full"))] - Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => unreachable!(), - } - } -} - -impl Copy for Precedence {} - -impl Clone for Precedence { - fn clone(&self) -> Self { - *self - } -} - -impl PartialEq for Precedence { - fn eq(&self, other: &Self) -> bool { - *self as u8 == *other as u8 - } -} - -impl PartialOrd for Precedence { - fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - let this = *self as u8; - let other = *other as u8; - Some(this.cmp(&other)) - } -} diff --git a/deps/crates/vendor/syn-v2/src/print.rs b/deps/crates/vendor/syn-v2/src/print.rs deleted file mode 100644 index 07409932677b..000000000000 --- a/deps/crates/vendor/syn-v2/src/print.rs +++ /dev/null @@ -1,16 +0,0 @@ -use proc_macro2::TokenStream; -use quote::ToTokens; - -pub(crate) struct TokensOrDefault<'a, T: 'a>(pub &'a Option<T>); - -impl<'a, T> ToTokens for TokensOrDefault<'a, T> -where - T: ToTokens + Default, -{ - fn to_tokens(&self, tokens: &mut TokenStream) { - match self.0 { - Some(t) => t.to_tokens(tokens), - None => T::default().to_tokens(tokens), - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/punctuated.rs b/deps/crates/vendor/syn-v2/src/punctuated.rs deleted file mode 100644 index 7545c6692612..000000000000 --- a/deps/crates/vendor/syn-v2/src/punctuated.rs +++ /dev/null @@ -1,1170 +0,0 @@ -//! A punctuated sequence of syntax tree nodes separated by punctuation. -//! -//! Lots of things in Rust are punctuated sequences. -//! -//! - The fields of a struct are `Punctuated<Field, Token![,]>`. -//! - The segments of a path are `Punctuated<PathSegment, Token![::]>`. -//! - The bounds on a generic parameter are `Punctuated<TypeParamBound, -//! Token![+]>`. -//! - The arguments to a function call are `Punctuated<Expr, Token![,]>`. -//! -//! This module provides a common representation for these punctuated sequences -//! in the form of the [`Punctuated<T, P>`] type. We store a vector of pairs of -//! syntax tree node + punctuation, where every node in the sequence is followed -//! by punctuation except for possibly the final one. -//! -//! [`Punctuated<T, P>`]: Punctuated -//! -//! ```text -//! a_function_call(arg1, arg2, arg3); -//! ~~~~^ ~~~~^ ~~~~ -//! ``` - -use crate::drops::{NoDrop, TrivialDrop}; -#[cfg(feature = "parsing")] -use crate::error::Result; -#[cfg(feature = "parsing")] -use crate::parse::{Parse, ParseStream}; -#[cfg(feature = "parsing")] -use crate::token::Token; -use alloc::boxed::Box; -#[cfg(all(feature = "fold", any(feature = "full", feature = "derive")))] -use alloc::collections::VecDeque; -use alloc::vec::{self, Vec}; -#[cfg(feature = "extra-traits")] -use core::fmt::{self, Debug}; -#[cfg(feature = "extra-traits")] -use core::hash::{Hash, Hasher}; -#[cfg(any(feature = "full", feature = "derive"))] -use core::iter; -use core::ops::{Index, IndexMut}; -use core::option; -use core::slice; - -/// **A punctuated sequence of syntax tree nodes of type `T` separated by -/// punctuation of type `P`.** -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct Punctuated<T, P> { - inner: Vec<(T, P)>, - last: Option<Box<T>>, -} - -impl<T, P> Punctuated<T, P> { - /// Creates an empty punctuated sequence. - pub const fn new() -> Self { - Punctuated { - inner: Vec::new(), - last: None, - } - } - - /// Determines whether this punctuated sequence is empty, meaning it - /// contains no syntax tree nodes or punctuation. - pub fn is_empty(&self) -> bool { - self.inner.len() == 0 && self.last.is_none() - } - - /// Returns the number of syntax tree nodes in this punctuated sequence. - /// - /// This is the number of nodes of type `T`, not counting the punctuation of - /// type `P`. - pub fn len(&self) -> usize { - self.inner.len() + if self.last.is_some() { 1 } else { 0 } - } - - /// Borrows the first element in this sequence. - pub fn first(&self) -> Option<&T> { - self.iter().next() - } - - /// Mutably borrows the first element in this sequence. - pub fn first_mut(&mut self) -> Option<&mut T> { - self.iter_mut().next() - } - - /// Borrows the last element in this sequence. - pub fn last(&self) -> Option<&T> { - self.iter().next_back() - } - - /// Mutably borrows the last element in this sequence. - pub fn last_mut(&mut self) -> Option<&mut T> { - self.iter_mut().next_back() - } - - /// Borrows the element at the given index. - pub fn get(&self, index: usize) -> Option<&T> { - if let Some((value, _punct)) = self.inner.get(index) { - Some(value) - } else if index == self.inner.len() { - self.last.as_deref() - } else { - None - } - } - - /// Mutably borrows the element at the given index. - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - let inner_len = self.inner.len(); - if let Some((value, _punct)) = self.inner.get_mut(index) { - Some(value) - } else if index == inner_len { - self.last.as_deref_mut() - } else { - None - } - } - - /// Returns an iterator over borrowed syntax tree nodes of type `&T`. - pub fn iter(&self) -> Iter<T> { - Iter { - inner: Box::new(NoDrop::new(PrivateIter { - inner: self.inner.iter(), - last: self.last.as_ref().map(Box::as_ref).into_iter(), - })), - } - } - - /// Returns an iterator over mutably borrowed syntax tree nodes of type - /// `&mut T`. - pub fn iter_mut(&mut self) -> IterMut<T> { - IterMut { - inner: Box::new(NoDrop::new(PrivateIterMut { - inner: self.inner.iter_mut(), - last: self.last.as_mut().map(Box::as_mut).into_iter(), - })), - } - } - - /// Returns an iterator over the contents of this sequence as borrowed - /// punctuated pairs. - pub fn pairs(&self) -> Pairs<T, P> { - Pairs { - inner: self.inner.iter(), - last: self.last.as_ref().map(Box::as_ref).into_iter(), - } - } - - /// Returns an iterator over the contents of this sequence as mutably - /// borrowed punctuated pairs. - pub fn pairs_mut(&mut self) -> PairsMut<T, P> { - PairsMut { - inner: self.inner.iter_mut(), - last: self.last.as_mut().map(Box::as_mut).into_iter(), - } - } - - /// Returns an iterator over the contents of this sequence as owned - /// punctuated pairs. - pub fn into_pairs(self) -> IntoPairs<T, P> { - IntoPairs { - inner: self.inner.into_iter(), - last: self.last.map(|t| *t).into_iter(), - } - } - - /// Appends a syntax tree node onto the end of this punctuated sequence. The - /// sequence must already have a trailing punctuation, or be empty. - /// - /// Use [`push`] instead if the punctuated sequence may or may not already - /// have trailing punctuation. - /// - /// [`push`]: Punctuated::push - /// - /// # Panics - /// - /// Panics if the sequence is nonempty and does not already have a trailing - /// punctuation. - pub fn push_value(&mut self, value: T) { - assert!( - self.empty_or_trailing(), - "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation", - ); - - self.last = Some(Box::new(value)); - } - - /// Appends a trailing punctuation onto the end of this punctuated sequence. - /// The sequence must be non-empty and must not already have trailing - /// punctuation. - /// - /// # Panics - /// - /// Panics if the sequence is empty or already has a trailing punctuation. - pub fn push_punct(&mut self, punctuation: P) { - assert!( - self.last.is_some(), - "Punctuated::push_punct: cannot push punctuation if Punctuated is empty or already has trailing punctuation", - ); - - let last = self.last.take().unwrap(); - self.inner.push((*last, punctuation)); - } - - /// Removes the last punctuated pair from this sequence, or `None` if the - /// sequence is empty. - pub fn pop(&mut self) -> Option<Pair<T, P>> { - if self.last.is_some() { - self.last.take().map(|t| Pair::End(*t)) - } else { - self.inner.pop().map(|(t, p)| Pair::Punctuated(t, p)) - } - } - - /// Removes the trailing punctuation from this punctuated sequence, or - /// `None` if there isn't any. - pub fn pop_punct(&mut self) -> Option<P> { - if self.last.is_some() { - None - } else { - let (t, p) = self.inner.pop()?; - self.last = Some(Box::new(t)); - Some(p) - } - } - - /// Determines whether this punctuated sequence ends with a trailing - /// punctuation. - pub fn trailing_punct(&self) -> bool { - self.last.is_none() && !self.is_empty() - } - - /// Returns true if either this `Punctuated` is empty, or it has a trailing - /// punctuation. - /// - /// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`. - pub fn empty_or_trailing(&self) -> bool { - self.last.is_none() - } - - /// Appends a syntax tree node onto the end of this punctuated sequence. - /// - /// If there is not a trailing punctuation in this sequence when this method - /// is called, the default value of punctuation type `P` is inserted before - /// the given value of type `T`. - pub fn push(&mut self, value: T) - where - P: Default, - { - if !self.empty_or_trailing() { - self.push_punct(Default::default()); - } - self.push_value(value); - } - - /// Inserts an element at position `index`. - /// - /// # Panics - /// - /// Panics if `index` is greater than the number of elements previously in - /// this punctuated sequence. - pub fn insert(&mut self, index: usize, value: T) - where - P: Default, - { - assert!( - index <= self.len(), - "Punctuated::insert: index out of range", - ); - - if index == self.len() { - self.push(value); - } else { - self.inner.insert(index, (value, Default::default())); - } - } - - /// Clears the sequence of all values and punctuation, making it empty. - pub fn clear(&mut self) { - self.inner.clear(); - self.last = None; - } - - /// Parses zero or more occurrences of `T` separated by punctuation of type - /// `P`, with optional trailing punctuation. - /// - /// Parsing continues until the end of this parse stream. The entire content - /// of this parse stream must consist of `T` and `P`. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_terminated(input: ParseStream) -> Result<Self> - where - T: Parse, - P: Parse, - { - Self::parse_terminated_with(input, T::parse) - } - - /// Parses zero or more occurrences of `T` using the given parse function, - /// separated by punctuation of type `P`, with optional trailing - /// punctuation. - /// - /// Like [`parse_terminated`], the entire content of this stream is expected - /// to be parsed. - /// - /// [`parse_terminated`]: Punctuated::parse_terminated - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_terminated_with<'a>( - input: ParseStream<'a>, - parser: fn(ParseStream<'a>) -> Result<T>, - ) -> Result<Self> - where - P: Parse, - { - let mut punctuated = Punctuated::new(); - - loop { - if input.is_empty() { - break; - } - let value = parser(input)?; - punctuated.push_value(value); - if input.is_empty() { - break; - } - let punct = input.parse()?; - punctuated.push_punct(punct); - } - - Ok(punctuated) - } - - /// Parses one or more occurrences of `T` separated by punctuation of type - /// `P`, not accepting trailing punctuation. - /// - /// Parsing continues as long as punctuation `P` is present at the head of - /// the stream. This method returns upon parsing a `T` and observing that it - /// is not followed by a `P`, even if there are remaining tokens in the - /// stream. - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_separated_nonempty(input: ParseStream) -> Result<Self> - where - T: Parse, - P: Token + Parse, - { - Self::parse_separated_nonempty_with(input, T::parse) - } - - /// Parses one or more occurrences of `T` using the given parse function, - /// separated by punctuation of type `P`, not accepting trailing - /// punctuation. - /// - /// Like [`parse_separated_nonempty`], may complete early without parsing - /// the entire content of this stream. - /// - /// [`parse_separated_nonempty`]: Punctuated::parse_separated_nonempty - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_separated_nonempty_with<'a>( - input: ParseStream<'a>, - parser: fn(ParseStream<'a>) -> Result<T>, - ) -> Result<Self> - where - P: Token + Parse, - { - let mut punctuated = Punctuated::new(); - - loop { - let value = parser(input)?; - punctuated.push_value(value); - if !P::peek(input.cursor()) { - break; - } - let punct = input.parse()?; - punctuated.push_punct(punct); - } - - Ok(punctuated) - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl<T, P> Clone for Punctuated<T, P> -where - T: Clone, - P: Clone, -{ - fn clone(&self) -> Self { - Punctuated { - inner: self.inner.clone(), - last: self.last.clone(), - } - } - - fn clone_from(&mut self, other: &Self) { - self.inner.clone_from(&other.inner); - self.last.clone_from(&other.last); - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl<T, P> Eq for Punctuated<T, P> -where - T: Eq, - P: Eq, -{ -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl<T, P> PartialEq for Punctuated<T, P> -where - T: PartialEq, - P: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - let Punctuated { inner, last } = self; - *inner == other.inner && *last == other.last - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl<T, P> Hash for Punctuated<T, P> -where - T: Hash, - P: Hash, -{ - fn hash<H: Hasher>(&self, state: &mut H) { - let Punctuated { inner, last } = self; - inner.hash(state); - last.hash(state); - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl<T: Debug, P: Debug> Debug for Punctuated<T, P> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut list = f.debug_list(); - for (t, p) in &self.inner { - list.entry(t); - list.entry(p); - } - if let Some(last) = &self.last { - list.entry(last); - } - list.finish() - } -} - -impl<T, P> FromIterator<T> for Punctuated<T, P> -where - P: Default, -{ - fn from_iter<I: IntoIterator<Item = T>>(i: I) -> Self { - let mut ret = Punctuated::new(); - ret.extend(i); - ret - } -} - -impl<T, P> Extend<T> for Punctuated<T, P> -where - P: Default, -{ - fn extend<I: IntoIterator<Item = T>>(&mut self, i: I) { - for value in i { - self.push(value); - } - } -} - -impl<T, P> FromIterator<Pair<T, P>> for Punctuated<T, P> { - fn from_iter<I: IntoIterator<Item = Pair<T, P>>>(i: I) -> Self { - let mut ret = Punctuated::new(); - do_extend(&mut ret, i.into_iter()); - ret - } -} - -impl<T, P> Extend<Pair<T, P>> for Punctuated<T, P> -where - P: Default, -{ - fn extend<I: IntoIterator<Item = Pair<T, P>>>(&mut self, i: I) { - if !self.empty_or_trailing() { - self.push_punct(P::default()); - } - do_extend(self, i.into_iter()); - } -} - -fn do_extend<T, P, I>(punctuated: &mut Punctuated<T, P>, i: I) -where - I: Iterator<Item = Pair<T, P>>, -{ - let mut nomore = false; - for pair in i { - if nomore { - panic!("punctuated extended with items after a Pair::End"); - } - match pair { - Pair::Punctuated(a, b) => punctuated.inner.push((a, b)), - Pair::End(a) => { - punctuated.last = Some(Box::new(a)); - nomore = true; - } - } - } -} - -impl<T, P> IntoIterator for Punctuated<T, P> { - type Item = T; - type IntoIter = IntoIter<T>; - - fn into_iter(self) -> Self::IntoIter { - let mut elements = Vec::with_capacity(self.len()); - - for (t, _) in self.inner { - elements.push(t); - } - if let Some(t) = self.last { - elements.push(*t); - } - - IntoIter { - inner: elements.into_iter(), - } - } -} - -impl<'a, T, P> IntoIterator for &'a Punctuated<T, P> { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - Punctuated::iter(self) - } -} - -impl<'a, T, P> IntoIterator for &'a mut Punctuated<T, P> { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - Punctuated::iter_mut(self) - } -} - -impl<T, P> Default for Punctuated<T, P> { - fn default() -> Self { - Punctuated::new() - } -} - -/// An iterator over borrowed pairs of type `Pair<&T, &P>`. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct Pairs<'a, T: 'a, P: 'a> { - inner: slice::Iter<'a, (T, P)>, - last: option::IntoIter<&'a T>, -} - -impl<'a, T, P> Iterator for Pairs<'a, T, P> { - type Item = Pair<&'a T, &'a P>; - - fn next(&mut self) -> Option<Self::Item> { - self.inner - .next() - .map(|(t, p)| Pair::Punctuated(t, p)) - .or_else(|| self.last.next().map(Pair::End)) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len(), Some(self.len())) - } -} - -impl<'a, T, P> DoubleEndedIterator for Pairs<'a, T, P> { - fn next_back(&mut self) -> Option<Self::Item> { - self.last - .next() - .map(Pair::End) - .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p))) - } -} - -impl<'a, T, P> ExactSizeIterator for Pairs<'a, T, P> { - fn len(&self) -> usize { - self.inner.len() + self.last.len() - } -} - -// No Clone bound on T or P. -impl<'a, T, P> Clone for Pairs<'a, T, P> { - fn clone(&self) -> Self { - Pairs { - inner: self.inner.clone(), - last: self.last.clone(), - } - } -} - -/// An iterator over mutably borrowed pairs of type `Pair<&mut T, &mut P>`. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct PairsMut<'a, T: 'a, P: 'a> { - inner: slice::IterMut<'a, (T, P)>, - last: option::IntoIter<&'a mut T>, -} - -impl<'a, T, P> Iterator for PairsMut<'a, T, P> { - type Item = Pair<&'a mut T, &'a mut P>; - - fn next(&mut self) -> Option<Self::Item> { - self.inner - .next() - .map(|(t, p)| Pair::Punctuated(t, p)) - .or_else(|| self.last.next().map(Pair::End)) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len(), Some(self.len())) - } -} - -impl<'a, T, P> DoubleEndedIterator for PairsMut<'a, T, P> { - fn next_back(&mut self) -> Option<Self::Item> { - self.last - .next() - .map(Pair::End) - .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p))) - } -} - -impl<'a, T, P> ExactSizeIterator for PairsMut<'a, T, P> { - fn len(&self) -> usize { - self.inner.len() + self.last.len() - } -} - -/// An iterator over owned pairs of type `Pair<T, P>`. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct IntoPairs<T, P> { - inner: vec::IntoIter<(T, P)>, - last: option::IntoIter<T>, -} - -impl<T, P> Iterator for IntoPairs<T, P> { - type Item = Pair<T, P>; - - fn next(&mut self) -> Option<Self::Item> { - self.inner - .next() - .map(|(t, p)| Pair::Punctuated(t, p)) - .or_else(|| self.last.next().map(Pair::End)) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len(), Some(self.len())) - } -} - -impl<T, P> DoubleEndedIterator for IntoPairs<T, P> { - fn next_back(&mut self) -> Option<Self::Item> { - self.last - .next() - .map(Pair::End) - .or_else(|| self.inner.next_back().map(|(t, p)| Pair::Punctuated(t, p))) - } -} - -impl<T, P> ExactSizeIterator for IntoPairs<T, P> { - fn len(&self) -> usize { - self.inner.len() + self.last.len() - } -} - -impl<T, P> Clone for IntoPairs<T, P> -where - T: Clone, - P: Clone, -{ - fn clone(&self) -> Self { - IntoPairs { - inner: self.inner.clone(), - last: self.last.clone(), - } - } -} - -/// An iterator over owned values of type `T`. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct IntoIter<T> { - inner: vec::IntoIter<T>, -} - -impl<T> Iterator for IntoIter<T> { - type Item = T; - - fn next(&mut self) -> Option<Self::Item> { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len(), Some(self.len())) - } -} - -impl<T> DoubleEndedIterator for IntoIter<T> { - fn next_back(&mut self) -> Option<Self::Item> { - self.inner.next_back() - } -} - -impl<T> ExactSizeIterator for IntoIter<T> { - fn len(&self) -> usize { - self.inner.len() - } -} - -impl<T> Clone for IntoIter<T> -where - T: Clone, -{ - fn clone(&self) -> Self { - IntoIter { - inner: self.inner.clone(), - } - } -} - -/// An iterator over borrowed values of type `&T`. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct Iter<'a, T: 'a> { - inner: Box<NoDrop<dyn IterTrait<'a, T> + 'a>>, -} - -trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> + DoubleEndedIterator + ExactSizeIterator { - fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T> + 'a>>; -} - -struct PrivateIter<'a, T: 'a, P: 'a> { - inner: slice::Iter<'a, (T, P)>, - last: option::IntoIter<&'a T>, -} - -impl<'a, T, P> TrivialDrop for PrivateIter<'a, T, P> -where - slice::Iter<'a, (T, P)>: TrivialDrop, - option::IntoIter<&'a T>: TrivialDrop, -{ -} - -#[cfg(any(feature = "full", feature = "derive"))] -pub(crate) fn empty_punctuated_iter<'a, T>() -> Iter<'a, T> { - Iter { - inner: Box::new(NoDrop::new(iter::empty())), - } -} - -// No Clone bound on T. -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Self { - Iter { - inner: self.inner.clone_box(), - } - } -} - -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<Self::Item> { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len(), Some(self.len())) - } -} - -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - fn next_back(&mut self) -> Option<Self::Item> { - self.inner.next_back() - } -} - -impl<'a, T> ExactSizeIterator for Iter<'a, T> { - fn len(&self) -> usize { - self.inner.len() - } -} - -impl<'a, T, P> Iterator for PrivateIter<'a, T, P> { - type Item = &'a T; - - fn next(&mut self) -> Option<Self::Item> { - self.inner - .next() - .map(|pair| &pair.0) - .or_else(|| self.last.next()) - } -} - -impl<'a, T, P> DoubleEndedIterator for PrivateIter<'a, T, P> { - fn next_back(&mut self) -> Option<Self::Item> { - self.last - .next() - .or_else(|| self.inner.next_back().map(|pair| &pair.0)) - } -} - -impl<'a, T, P> ExactSizeIterator for PrivateIter<'a, T, P> { - fn len(&self) -> usize { - self.inner.len() + self.last.len() - } -} - -// No Clone bound on T or P. -impl<'a, T, P> Clone for PrivateIter<'a, T, P> { - fn clone(&self) -> Self { - PrivateIter { - inner: self.inner.clone(), - last: self.last.clone(), - } - } -} - -impl<'a, T, I> IterTrait<'a, T> for I -where - T: 'a, - I: DoubleEndedIterator<Item = &'a T> - + ExactSizeIterator<Item = &'a T> - + Clone - + TrivialDrop - + 'a, -{ - fn clone_box(&self) -> Box<NoDrop<dyn IterTrait<'a, T> + 'a>> { - Box::new(NoDrop::new(self.clone())) - } -} - -/// An iterator over mutably borrowed values of type `&mut T`. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub struct IterMut<'a, T: 'a> { - inner: Box<NoDrop<dyn IterMutTrait<'a, T, Item = &'a mut T> + 'a>>, -} - -trait IterMutTrait<'a, T: 'a>: - DoubleEndedIterator<Item = &'a mut T> + ExactSizeIterator<Item = &'a mut T> -{ -} - -struct PrivateIterMut<'a, T: 'a, P: 'a> { - inner: slice::IterMut<'a, (T, P)>, - last: option::IntoIter<&'a mut T>, -} - -impl<'a, T, P> TrivialDrop for PrivateIterMut<'a, T, P> -where - slice::IterMut<'a, (T, P)>: TrivialDrop, - option::IntoIter<&'a mut T>: TrivialDrop, -{ -} - -#[cfg(any(feature = "full", feature = "derive"))] -pub(crate) fn empty_punctuated_iter_mut<'a, T>() -> IterMut<'a, T> { - IterMut { - inner: Box::new(NoDrop::new(iter::empty())), - } -} - -impl<'a, T> Iterator for IterMut<'a, T> { - type Item = &'a mut T; - - fn next(&mut self) -> Option<Self::Item> { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.len(), Some(self.len())) - } -} - -impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { - fn next_back(&mut self) -> Option<Self::Item> { - self.inner.next_back() - } -} - -impl<'a, T> ExactSizeIterator for IterMut<'a, T> { - fn len(&self) -> usize { - self.inner.len() - } -} - -impl<'a, T, P> Iterator for PrivateIterMut<'a, T, P> { - type Item = &'a mut T; - - fn next(&mut self) -> Option<Self::Item> { - self.inner - .next() - .map(|pair| &mut pair.0) - .or_else(|| self.last.next()) - } -} - -impl<'a, T, P> DoubleEndedIterator for PrivateIterMut<'a, T, P> { - fn next_back(&mut self) -> Option<Self::Item> { - self.last - .next() - .or_else(|| self.inner.next_back().map(|pair| &mut pair.0)) - } -} - -impl<'a, T, P> ExactSizeIterator for PrivateIterMut<'a, T, P> { - fn len(&self) -> usize { - self.inner.len() + self.last.len() - } -} - -impl<'a, T, I> IterMutTrait<'a, T> for I -where - T: 'a, - I: DoubleEndedIterator<Item = &'a mut T> + ExactSizeIterator<Item = &'a mut T> + 'a, -{ -} - -/// A single syntax tree node of type `T` followed by its trailing punctuation -/// of type `P` if any. -/// -/// Refer to the [module documentation] for details about punctuated sequences. -/// -/// [module documentation]: self -pub enum Pair<T, P> { - Punctuated(T, P), - End(T), -} - -impl<T, P> Pair<T, P> { - /// Extracts the syntax tree node from this punctuated pair, discarding the - /// following punctuation. - pub fn into_value(self) -> T { - match self { - Pair::Punctuated(t, _) | Pair::End(t) => t, - } - } - - /// Borrows the syntax tree node from this punctuated pair. - pub fn value(&self) -> &T { - match self { - Pair::Punctuated(t, _) | Pair::End(t) => t, - } - } - - /// Mutably borrows the syntax tree node from this punctuated pair. - pub fn value_mut(&mut self) -> &mut T { - match self { - Pair::Punctuated(t, _) | Pair::End(t) => t, - } - } - - /// Borrows the punctuation from this punctuated pair, unless this pair is - /// the final one and there is no trailing punctuation. - pub fn punct(&self) -> Option<&P> { - match self { - Pair::Punctuated(_, p) => Some(p), - Pair::End(_) => None, - } - } - - /// Mutably borrows the punctuation from this punctuated pair, unless the - /// pair is the final one and there is no trailing punctuation. - /// - /// # Example - /// - /// ``` - /// # use proc_macro2::Span; - /// # use syn::punctuated::Punctuated; - /// # use syn::{parse_quote, Token, TypeParamBound}; - /// # - /// # let mut punctuated = Punctuated::<TypeParamBound, Token![+]>::new(); - /// # let span = Span::call_site(); - /// # - /// punctuated.insert(0, parse_quote!('lifetime)); - /// if let Some(punct) = punctuated.pairs_mut().next().unwrap().punct_mut() { - /// punct.span = span; - /// } - /// ``` - pub fn punct_mut(&mut self) -> Option<&mut P> { - match self { - Pair::Punctuated(_, p) => Some(p), - Pair::End(_) => None, - } - } - - /// Creates a punctuated pair out of a syntax tree node and an optional - /// following punctuation. - pub fn new(t: T, p: Option<P>) -> Self { - match p { - Some(p) => Pair::Punctuated(t, p), - None => Pair::End(t), - } - } - - /// Produces this punctuated pair as a tuple of syntax tree node and - /// optional following punctuation. - pub fn into_tuple(self) -> (T, Option<P>) { - match self { - Pair::Punctuated(t, p) => (t, Some(p)), - Pair::End(t) => (t, None), - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl<T, P> Pair<&T, &P> { - pub fn cloned(self) -> Pair<T, P> - where - T: Clone, - P: Clone, - { - match self { - Pair::Punctuated(t, p) => Pair::Punctuated(t.clone(), p.clone()), - Pair::End(t) => Pair::End(t.clone()), - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl<T, P> Clone for Pair<T, P> -where - T: Clone, - P: Clone, -{ - fn clone(&self) -> Self { - match self { - Pair::Punctuated(t, p) => Pair::Punctuated(t.clone(), p.clone()), - Pair::End(t) => Pair::End(t.clone()), - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl<T, P> Copy for Pair<T, P> -where - T: Copy, - P: Copy, -{ -} - -impl<T, P> Index<usize> for Punctuated<T, P> { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - if index.checked_add(1) == Some(self.len()) { - match &self.last { - Some(t) => t, - None => &self.inner[index].0, - } - } else { - &self.inner[index].0 - } - } -} - -impl<T, P> IndexMut<usize> for Punctuated<T, P> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - if index.checked_add(1) == Some(self.len()) { - match &mut self.last { - Some(t) => t, - None => &mut self.inner[index].0, - } - } else { - &mut self.inner[index].0 - } - } -} - -#[cfg(all(feature = "fold", any(feature = "full", feature = "derive")))] -pub(crate) fn fold<T, P, V, F>( - punctuated: Punctuated<T, P>, - fold: &mut V, - mut f: F, -) -> Punctuated<T, P> -where - V: ?Sized, - F: FnMut(&mut V, T) -> T, -{ - let Punctuated { inner, last } = punctuated; - - // Convert into VecDeque to prevent needing to allocate a new Vec<(T, P)> - // for the folded elements. - let mut inner = VecDeque::from(inner); - for _ in 0..inner.len() { - if let Some((t, p)) = inner.pop_front() { - inner.push_back((f(fold, t), p)); - } - } - - Punctuated { - inner: Vec::from(inner), - last: match last { - Some(t) => Some(Box::new(f(fold, *t))), - None => None, - }, - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::punctuated::{Pair, Punctuated}; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl<T, P> ToTokens for Punctuated<T, P> - where - T: ToTokens, - P: ToTokens, - { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.pairs()); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl<T, P> ToTokens for Pair<T, P> - where - T: ToTokens, - P: ToTokens, - { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Pair::Punctuated(a, b) => { - a.to_tokens(tokens); - b.to_tokens(tokens); - } - Pair::End(a) => a.to_tokens(tokens), - } - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/restriction.rs b/deps/crates/vendor/syn-v2/src/restriction.rs deleted file mode 100644 index d0cdf8eda600..000000000000 --- a/deps/crates/vendor/syn-v2/src/restriction.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::path::Path; -use crate::token; -use alloc::boxed::Box; - -ast_enum! { - /// The visibility level of an item: inherited or `pub` or - /// `pub(restricted)`. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum Visibility { - /// A public visibility level: `pub`. - Public(Token![pub]), - - /// A visibility level restricted to some path: `pub(self)` or - /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. - Restricted(VisRestricted), - - /// An inherited visibility, which usually means private. - Inherited, - } -} - -ast_struct! { - /// A visibility level restricted to some path: `pub(self)` or - /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct VisRestricted { - pub pub_token: Token![pub], - pub paren_token: token::Paren, - pub in_token: Option<Token![in]>, - pub path: Box<Path>, - } -} - -ast_enum! { - /// Unused, but reserved for RFC 3323 restrictions. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum FieldMutability { - None, - - // TODO: https://rust-lang.github.io/rfcs/3323-restrictions.html - // - // FieldMutability::Restricted(MutRestricted) - // - // pub struct MutRestricted { - // pub mut_token: Token![mut], - // pub paren_token: token::Paren, - // pub in_token: Option<Token![in]>, - // pub path: Box<Path>, - // } - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::error::Result; - use crate::ext::IdentExt as _; - use crate::ident::Ident; - use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; - use crate::path::Path; - use crate::restriction::{VisRestricted, Visibility}; - use crate::token; - use alloc::boxed::Box; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Visibility { - fn parse(input: ParseStream) -> Result<Self> { - // Recognize an empty None-delimited group, as produced by a $:vis - // matcher that matched no tokens. - if input.peek(token::Group) { - let ahead = input.fork(); - let group = crate::group::parse_group(&ahead)?; - if group.content.is_empty() { - input.advance_to(&ahead); - return Ok(Visibility::Inherited); - } - } - - if input.peek(Token![pub]) { - Self::parse_pub(input) - } else { - Ok(Visibility::Inherited) - } - } - } - - impl Visibility { - fn parse_pub(input: ParseStream) -> Result<Self> { - let pub_token = input.parse::<Token![pub]>()?; - - if input.peek(token::Paren) { - let ahead = input.fork(); - - let content; - let paren_token = parenthesized!(content in ahead); - if content.peek(Token![crate]) - || content.peek(Token![self]) - || content.peek(Token![super]) - { - let path = content.call(Ident::parse_any)?; - - // Ensure there are no additional tokens within `content`. - // Without explicitly checking, we may misinterpret a tuple - // field as a restricted visibility, causing a parse error. - // e.g. `pub (crate::A, crate::B)` (Issue #720). - if content.is_empty() { - input.advance_to(&ahead); - return Ok(Visibility::Restricted(VisRestricted { - pub_token, - paren_token, - in_token: None, - path: Box::new(Path::from(path)), - })); - } - } else if content.peek(Token![in]) { - let in_token: Token![in] = content.parse()?; - let path = content.call(Path::parse_mod_style)?; - - input.advance_to(&ahead); - return Ok(Visibility::Restricted(VisRestricted { - pub_token, - paren_token, - in_token: Some(in_token), - path: Box::new(path), - })); - } - } - - Ok(Visibility::Public(pub_token)) - } - - #[cfg(feature = "full")] - pub(crate) fn is_some(&self) -> bool { - match self { - Visibility::Inherited => false, - _ => true, - } - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::path; - use crate::path::printing::PathStyle; - use crate::restriction::{VisRestricted, Visibility}; - use proc_macro2::TokenStream; - use quote::ToTokens; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Visibility { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Visibility::Public(pub_token) => pub_token.to_tokens(tokens), - Visibility::Restricted(vis_restricted) => vis_restricted.to_tokens(tokens), - Visibility::Inherited => {} - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for VisRestricted { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.pub_token.to_tokens(tokens); - self.paren_token.surround(tokens, |tokens| { - // TODO: If we have a path which is not "self" or "super" or - // "crate", automatically add the "in" token. - self.in_token.to_tokens(tokens); - path::printing::print_path(tokens, &self.path, PathStyle::Mod); - }); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/scan_expr.rs b/deps/crates/vendor/syn-v2/src/scan_expr.rs deleted file mode 100644 index 424e44264564..000000000000 --- a/deps/crates/vendor/syn-v2/src/scan_expr.rs +++ /dev/null @@ -1,258 +0,0 @@ -use self::{Action::*, Input::*}; -use proc_macro2::{Delimiter, Ident, Spacing, TokenTree}; -use syn::parse::{ParseStream, Result}; -#[allow(unused_imports)] -//#[cfg_attr(not(test), expect(unused_imports))] // Rust 1.81+ -use syn::Token; -use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Type}; - -enum Input { - Keyword(&'static str), - Punct(&'static str), - ConsumeAny, - ConsumeBinOp, - ConsumeBrace, - ConsumeDelimiter, - ConsumeIdent, - ConsumeLifetime, - ConsumeLiteral, - ConsumeNestedBrace, - ExpectPath, - ExpectTurbofish, - ExpectType, - CanBeginExpr, - Otherwise, - Empty, -} - -enum Action { - SetState(&'static [(Input, Action)]), - IncDepth, - DecDepth, - Finish, -} - -static INIT: [(Input, Action); 29] = [ - (ConsumeDelimiter, SetState(&POSTFIX)), - (Keyword("async"), SetState(&ASYNC)), - (Keyword("break"), SetState(&BREAK_LABEL)), - (Keyword("const"), SetState(&CONST)), - (Keyword("continue"), SetState(&CONTINUE)), - (Keyword("for"), SetState(&FOR)), - (Keyword("if"), IncDepth), - (Keyword("let"), SetState(&PATTERN)), - (Keyword("loop"), SetState(&BLOCK)), - (Keyword("match"), IncDepth), - (Keyword("move"), SetState(&CLOSURE)), - (Keyword("return"), SetState(&RETURN)), - (Keyword("static"), SetState(&CLOSURE)), - (Keyword("try"), SetState(&BLOCK)), - (Keyword("unsafe"), SetState(&BLOCK)), - (Keyword("while"), IncDepth), - (Keyword("yield"), SetState(&RETURN)), - (Keyword("_"), SetState(&POSTFIX)), - (Punct("!"), SetState(&INIT)), - (Punct("#"), SetState(&[(ConsumeDelimiter, SetState(&INIT))])), - (Punct("&"), SetState(&REFERENCE)), - (Punct("*"), SetState(&INIT)), - (Punct("-"), SetState(&INIT)), - (Punct("..="), SetState(&INIT)), - (Punct(".."), SetState(&RANGE)), - (Punct("|"), SetState(&CLOSURE_ARGS)), - (ConsumeLifetime, SetState(&[(Punct(":"), SetState(&INIT))])), - (ConsumeLiteral, SetState(&POSTFIX)), - (ExpectPath, SetState(&PATH)), -]; - -static POSTFIX: [(Input, Action); 10] = [ - (Keyword("as"), SetState(&[(ExpectType, SetState(&POSTFIX))])), - (Punct("..="), SetState(&INIT)), - (Punct(".."), SetState(&RANGE)), - (Punct("."), SetState(&DOT)), - (Punct("?"), SetState(&POSTFIX)), - (ConsumeBinOp, SetState(&INIT)), - (Punct("="), SetState(&INIT)), - (ConsumeNestedBrace, SetState(&IF_THEN)), - (ConsumeDelimiter, SetState(&POSTFIX)), - (Empty, Finish), -]; - -static ASYNC: [(Input, Action); 3] = [ - (Keyword("move"), SetState(&ASYNC)), - (Punct("|"), SetState(&CLOSURE_ARGS)), - (ConsumeBrace, SetState(&POSTFIX)), -]; - -static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))]; - -static BREAK_LABEL: [(Input, Action); 2] = - [(ConsumeLifetime, SetState(&BREAK_VALUE)), (Otherwise, SetState(&BREAK_VALUE))]; - -static BREAK_VALUE: [(Input, Action); 3] = [ - (ConsumeNestedBrace, SetState(&IF_THEN)), - (CanBeginExpr, SetState(&INIT)), - (Otherwise, SetState(&POSTFIX)), -]; - -static CLOSURE: [(Input, Action); 7] = [ - (Keyword("async"), SetState(&CLOSURE)), - (Keyword("move"), SetState(&CLOSURE)), - (Punct(","), SetState(&CLOSURE)), - (Punct(">"), SetState(&CLOSURE)), - (Punct("|"), SetState(&CLOSURE_ARGS)), - (ConsumeLifetime, SetState(&CLOSURE)), - (ConsumeIdent, SetState(&CLOSURE)), -]; - -static CLOSURE_ARGS: [(Input, Action); 2] = - [(Punct("|"), SetState(&CLOSURE_RET)), (ConsumeAny, SetState(&CLOSURE_ARGS))]; - -static CLOSURE_RET: [(Input, Action); 2] = - [(Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])), (Otherwise, SetState(&INIT))]; - -static CONST: [(Input, Action); 3] = [ - (Keyword("move"), SetState(&CLOSURE)), - (Punct("|"), SetState(&CLOSURE_ARGS)), - (ConsumeBrace, SetState(&POSTFIX)), -]; - -static CONTINUE: [(Input, Action); 2] = - [(ConsumeLifetime, SetState(&POSTFIX)), (Otherwise, SetState(&POSTFIX))]; - -static DOT: [(Input, Action); 3] = [ - (Keyword("await"), SetState(&POSTFIX)), - (ConsumeIdent, SetState(&METHOD)), - (ConsumeLiteral, SetState(&POSTFIX)), -]; - -static FOR: [(Input, Action); 2] = - [(Punct("<"), SetState(&CLOSURE)), (Otherwise, SetState(&PATTERN))]; - -static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)]; -static IF_THEN: [(Input, Action); 2] = - [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)]; - -static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))]; - -static PATH: [(Input, Action); 4] = [ - (Punct("!="), SetState(&INIT)), - (Punct("!"), SetState(&INIT)), - (ConsumeNestedBrace, SetState(&IF_THEN)), - (Otherwise, SetState(&POSTFIX)), -]; - -static PATTERN: [(Input, Action); 15] = [ - (ConsumeDelimiter, SetState(&PATTERN)), - (Keyword("box"), SetState(&PATTERN)), - (Keyword("in"), IncDepth), - (Keyword("mut"), SetState(&PATTERN)), - (Keyword("ref"), SetState(&PATTERN)), - (Keyword("_"), SetState(&PATTERN)), - (Punct("!"), SetState(&PATTERN)), - (Punct("&"), SetState(&PATTERN)), - (Punct("..="), SetState(&PATTERN)), - (Punct(".."), SetState(&PATTERN)), - (Punct("="), SetState(&INIT)), - (Punct("@"), SetState(&PATTERN)), - (Punct("|"), SetState(&PATTERN)), - (ConsumeLiteral, SetState(&PATTERN)), - (ExpectPath, SetState(&PATTERN)), -]; - -static RANGE: [(Input, Action); 6] = [ - (Punct("..="), SetState(&INIT)), - (Punct(".."), SetState(&RANGE)), - (Punct("."), SetState(&DOT)), - (ConsumeNestedBrace, SetState(&IF_THEN)), - (Empty, Finish), - (Otherwise, SetState(&INIT)), -]; - -static RAW: [(Input, Action); 3] = [ - (Keyword("const"), SetState(&INIT)), - (Keyword("mut"), SetState(&INIT)), - (Otherwise, SetState(&POSTFIX)), -]; - -static REFERENCE: [(Input, Action); 3] = [ - (Keyword("mut"), SetState(&INIT)), - (Keyword("raw"), SetState(&RAW)), - (Otherwise, SetState(&INIT)), -]; - -static RETURN: [(Input, Action); 2] = - [(CanBeginExpr, SetState(&INIT)), (Otherwise, SetState(&POSTFIX))]; - -pub(crate) fn scan_expr(input: ParseStream) -> Result<()> { - let mut state = INIT.as_slice(); - let mut depth = 0usize; - 'table: loop { - for rule in state { - if match rule.0 { - Input::Keyword(expected) => input.step(|cursor| match cursor.ident() { - Some((ident, rest)) if ident == expected => Ok((true, rest)), - _ => Ok((false, *cursor)), - })?, - Input::Punct(expected) => input.step(|cursor| { - let begin = *cursor; - let mut cursor = begin; - for (i, ch) in expected.chars().enumerate() { - match cursor.punct() { - Some((punct, _)) if punct.as_char() != ch => break, - Some((_, rest)) if i == expected.len() - 1 => { - return Ok((true, rest)); - } - Some((punct, rest)) if punct.spacing() == Spacing::Joint => { - cursor = rest; - } - _ => break, - } - } - Ok((false, begin)) - })?, - Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(), - Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(), - Input::ConsumeBrace | Input::ConsumeNestedBrace => { - (matches!(rule.0, Input::ConsumeBrace) || depth > 0) - && input.step(|cursor| match cursor.group(Delimiter::Brace) { - Some((_inside, _span, rest)) => Ok((true, rest)), - None => Ok((false, *cursor)), - })? - } - Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() { - Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)), - None => Ok((false, *cursor)), - })?, - Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(), - Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(), - Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(), - Input::ExpectPath => { - input.parse::<ExprPath>()?; - true - } - Input::ExpectTurbofish => { - if input.peek(Token![::]) { - input.parse::<AngleBracketedGenericArguments>()?; - } - true - } - Input::ExpectType => { - Type::without_plus(input)?; - true - } - Input::CanBeginExpr => Expr::peek(input), - Input::Otherwise => true, - Input::Empty => input.is_empty() || input.peek(Token![,]), - } { - state = match rule.1 { - Action::SetState(next) => next, - Action::IncDepth => (depth += 1, &INIT).1, - Action::DecDepth => (depth -= 1, &POSTFIX).1, - Action::Finish => return if depth == 0 { Ok(()) } else { break }, - }; - continue 'table; - } - } - return Err(input.error("unsupported expression")); - } -} diff --git a/deps/crates/vendor/syn-v2/src/sealed.rs b/deps/crates/vendor/syn-v2/src/sealed.rs deleted file mode 100644 index dc804742d12d..000000000000 --- a/deps/crates/vendor/syn-v2/src/sealed.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(feature = "parsing")] -pub(crate) mod lookahead { - pub trait Sealed: Copy {} -} diff --git a/deps/crates/vendor/syn-v2/src/span.rs b/deps/crates/vendor/syn-v2/src/span.rs deleted file mode 100644 index eb2779479aaa..000000000000 --- a/deps/crates/vendor/syn-v2/src/span.rs +++ /dev/null @@ -1,63 +0,0 @@ -use proc_macro2::extra::DelimSpan; -use proc_macro2::{Delimiter, Group, Span, TokenStream}; - -#[doc(hidden)] -pub trait IntoSpans<S> { - fn into_spans(self) -> S; -} - -impl IntoSpans<Span> for Span { - fn into_spans(self) -> Span { - self - } -} - -impl IntoSpans<[Span; 1]> for Span { - fn into_spans(self) -> [Span; 1] { - [self] - } -} - -impl IntoSpans<[Span; 2]> for Span { - fn into_spans(self) -> [Span; 2] { - [self, self] - } -} - -impl IntoSpans<[Span; 3]> for Span { - fn into_spans(self) -> [Span; 3] { - [self, self, self] - } -} - -impl IntoSpans<[Span; 1]> for [Span; 1] { - fn into_spans(self) -> [Span; 1] { - self - } -} - -impl IntoSpans<[Span; 2]> for [Span; 2] { - fn into_spans(self) -> [Span; 2] { - self - } -} - -impl IntoSpans<[Span; 3]> for [Span; 3] { - fn into_spans(self) -> [Span; 3] { - self - } -} - -impl IntoSpans<DelimSpan> for Span { - fn into_spans(self) -> DelimSpan { - let mut group = Group::new(Delimiter::None, TokenStream::new()); - group.set_span(self); - group.delim_span() - } -} - -impl IntoSpans<DelimSpan> for DelimSpan { - fn into_spans(self) -> DelimSpan { - self - } -} diff --git a/deps/crates/vendor/syn-v2/src/spanned.rs b/deps/crates/vendor/syn-v2/src/spanned.rs deleted file mode 100644 index 38551445b26d..000000000000 --- a/deps/crates/vendor/syn-v2/src/spanned.rs +++ /dev/null @@ -1,118 +0,0 @@ -//! A trait that can provide the `Span` of the complete contents of a syntax -//! tree node. -//! -//! <br> -//! -//! # Example -//! -//! Suppose in a procedural macro we have a [`Type`] that we want to assert -//! implements the [`Sync`] trait. Maybe this is the type of one of the fields -//! of a struct for which we are deriving a trait implementation, and we need to -//! be able to pass a reference to one of those fields across threads. -//! -//! [`Type`]: crate::Type -//! [`Sync`]: core::marker::Sync -//! -//! If the field type does *not* implement `Sync` as required, we want the -//! compiler to report an error pointing out exactly which type it was. -//! -//! The following macro code takes a variable `ty` of type `Type` and produces a -//! static assertion that `Sync` is implemented for that type. -//! -//! ``` -//! # extern crate proc_macro; -//! # -//! use proc_macro::TokenStream; -//! use proc_macro2::Span; -//! use quote::quote_spanned; -//! use syn::Type; -//! use syn::spanned::Spanned; -//! -//! # const IGNORE_TOKENS: &str = stringify! { -//! #[proc_macro_derive(MyMacro)] -//! # }; -//! pub fn my_macro(input: TokenStream) -> TokenStream { -//! # let ty = get_a_type(); -//! /* ... */ -//! -//! let assert_sync = quote_spanned! {ty.span()=> -//! struct _AssertSync where #ty: Sync; -//! }; -//! -//! /* ... */ -//! # input -//! } -//! # -//! # fn get_a_type() -> Type { -//! # unimplemented!() -//! # } -//! ``` -//! -//! By inserting this `assert_sync` fragment into the output code generated by -//! our macro, the user's code will fail to compile if `ty` does not implement -//! `Sync`. The errors they would see look like the following. -//! -//! ```text -//! error[E0277]: the trait bound `*const i32: core::marker::Sync` is not satisfied -//! --> src/main.rs:10:21 -//! | -//! 10 | bad_field: *const i32, -//! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely -//! ``` -//! -//! In this technique, using the `Type`'s span for the error message makes the -//! error appear in the correct place underlining the right type. -//! -//! <br> -//! -//! # Limitations -//! -//! The underlying [`proc_macro::Span::join`] method is nightly-only. When -//! called from within a procedural macro in a nightly compiler, `Spanned` will -//! use `join` to produce the intended span. When not using a nightly compiler, -//! only the span of the *first token* of the syntax tree node is returned. -//! -//! In the common case of wanting to use the joined span as the span of a -//! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is -//! able to span the error correctly under the complete syntax tree node without -//! needing the unstable `join`. -//! -//! [`syn::Error::new_spanned`]: crate::Error::new_spanned - -use proc_macro2::Span; -use quote::spanned::Spanned as ToTokens; - -/// A trait that can provide the `Span` of the complete contents of a syntax -/// tree node. -/// -/// This trait is automatically implemented for all types that implement -/// [`ToTokens`] from the `quote` crate, as well as for `Span` itself. -/// -/// [`ToTokens`]: quote::ToTokens -/// -/// See the [module documentation] for an example. -/// -/// [module documentation]: self -pub trait Spanned: private::Sealed { - /// Returns a `Span` covering the complete contents of this syntax tree - /// node, or [`Span::call_site()`] if this node is empty. - /// - /// [`Span::call_site()`]: proc_macro2::Span::call_site - fn span(&self) -> Span; -} - -impl<T: ?Sized + ToTokens> Spanned for T { - fn span(&self) -> Span { - self.__span() - } -} - -mod private { - use crate::spanned::ToTokens; - - pub trait Sealed {} - impl<T: ?Sized + ToTokens> Sealed for T {} - - #[cfg(any(feature = "full", feature = "derive"))] - impl Sealed for crate::QSelf {} -} diff --git a/deps/crates/vendor/syn-v2/src/stmt.rs b/deps/crates/vendor/syn-v2/src/stmt.rs deleted file mode 100644 index 4fcd9304cb99..000000000000 --- a/deps/crates/vendor/syn-v2/src/stmt.rs +++ /dev/null @@ -1,477 +0,0 @@ -use crate::attr::Attribute; -use crate::expr::Expr; -use crate::item::Item; -use crate::mac::Macro; -use crate::pat::Pat; -use crate::token; -use alloc::boxed::Box; -use alloc::vec::Vec; - -ast_struct! { - /// A braced block containing Rust statements. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Block { - pub brace_token: token::Brace, - /// Statements in a block - pub stmts: Vec<Stmt>, - } -} - -ast_enum! { - /// A statement, usually ending in a semicolon. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub enum Stmt { - /// A local (let) binding. - Local(Local), - - /// An item definition. - Item(Item), - - /// Expression, with or without trailing semicolon. - Expr(Expr, Option<Token![;]>), - - /// A macro invocation in statement position. - /// - /// Syntactically it's ambiguous which other kind of statement this - /// macro would expand to. It can be any of local variable (`let`), - /// item, or expression. - Macro(StmtMacro), - } -} - -ast_struct! { - /// A local `let` binding: `let x: u64 = s.parse()?;`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct Local { - pub attrs: Vec<Attribute>, - pub let_token: Token![let], - pub pat: Pat, - pub init: Option<LocalInit>, - pub semi_token: Token![;], - } -} - -ast_struct! { - /// The expression assigned in a local `let` binding, including optional - /// diverging `else` block. - /// - /// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and - /// `= r else { return }` in `let Ok(x) = r else { return }`. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct LocalInit { - pub eq_token: Token![=], - pub expr: Box<Expr>, - pub diverge: Option<(Token![else], Box<Expr>)>, - } -} - -ast_struct! { - /// A macro invocation in statement position. - /// - /// Syntactically it's ambiguous which other kind of statement this macro - /// would expand to. It can be any of local variable (`let`), item, or - /// expression. - #[cfg_attr(docsrs, doc(cfg(feature = "full")))] - pub struct StmtMacro { - pub attrs: Vec<Attribute>, - pub mac: Macro, - pub semi_token: Option<Token![;]>, - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - use crate::buffer::Cursor; - use crate::classify; - use crate::error::Result; - use crate::expr::{Expr, ExprBlock, ExprMacro}; - use crate::ident::Ident; - use crate::item; - use crate::mac::{self, Macro}; - use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; - use crate::pat::{Pat, PatType}; - use crate::path::Path; - use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro}; - use crate::token; - use crate::ty::Type; - use crate::verbatim; - use alloc::boxed::Box; - use alloc::vec::Vec; - use core::mem; - use proc_macro2::TokenStream; - - struct AllowNoSemi(bool); - - impl Block { - /// Parse the body of a block as zero or more statements, possibly - /// including one trailing expression. - /// - /// # Example - /// - /// ``` - /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token}; - /// use syn::parse::{Parse, ParseStream}; - /// - /// // Parse a function with no generics or parameter list. - /// // - /// // fn playground { - /// // let mut x = 1; - /// // x += 1; - /// // println!("{}", x); - /// // } - /// struct MiniFunction { - /// attrs: Vec<Attribute>, - /// fn_token: Token![fn], - /// name: Ident, - /// brace_token: token::Brace, - /// stmts: Vec<Stmt>, - /// } - /// - /// impl Parse for MiniFunction { - /// fn parse(input: ParseStream) -> Result<Self> { - /// let outer_attrs = input.call(Attribute::parse_outer)?; - /// let fn_token: Token![fn] = input.parse()?; - /// let name: Ident = input.parse()?; - /// - /// let content; - /// let brace_token = braced!(content in input); - /// let inner_attrs = content.call(Attribute::parse_inner)?; - /// let stmts = content.call(Block::parse_within)?; - /// - /// Ok(MiniFunction { - /// attrs: { - /// let mut attrs = outer_attrs; - /// attrs.extend(inner_attrs); - /// attrs - /// }, - /// fn_token, - /// name, - /// brace_token, - /// stmts, - /// }) - /// } - /// } - /// ``` - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> { - let mut stmts = Vec::new(); - loop { - while let semi @ Some(_) = input.parse()? { - stmts.push(Stmt::Expr(Expr::Verbatim(TokenStream::new()), semi)); - } - if input.is_empty() { - break; - } - let stmt = parse_stmt(input, AllowNoSemi(true))?; - let requires_semicolon = match &stmt { - Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt), - Stmt::Macro(stmt) => { - stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace() - } - Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false, - }; - stmts.push(stmt); - if input.is_empty() { - break; - } else if requires_semicolon { - return Err(input.error("unexpected token, expected `;`")); - } - } - Ok(stmts) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Block { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(Block { - brace_token: braced!(content in input), - stmts: content.call(Block::parse_within)?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Stmt { - fn parse(input: ParseStream) -> Result<Self> { - let allow_nosemi = AllowNoSemi(false); - parse_stmt(input, allow_nosemi) - } - } - - fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> { - let begin = input.cursor(); - let attrs = input.call(Attribute::parse_outer)?; - let attrs_end = input.cursor(); - - // brace-style macros; paren and bracket macros get parsed as - // expression statements. - let ahead = input.fork(); - let mut is_item_macro = false; - if let Ok(path) = ahead.call(Path::parse_mod_style) { - if ahead.peek(Token![!]) { - if ahead.peek2(Ident) || ahead.peek2(Token![try]) { - is_item_macro = true; - } else if ahead.peek2(token::Brace) - && !(ahead.peek3(Token![.]) && !ahead.peek3(Token![..]) - || ahead.peek3(Token![?])) - { - input.advance_to(&ahead); - return stmt_mac(input, attrs, path).map(Stmt::Macro); - } - } - } - - if input.peek(Token![let]) && !input.peek(token::Group) { - stmt_local(input, attrs).map(Stmt::Local) - } else if input.peek(Token![pub]) - || input.peek(Token![crate]) && !input.peek2(Token![::]) - || input.peek(Token![extern]) - || input.peek(Token![use]) - || input.peek(Token![static]) - && (input.peek2(Token![mut]) - || input.peek2(Ident) - && !(input.peek2(Token![async]) - && (input.peek3(Token![move]) || input.peek3(Token![|])))) - || input.peek(Token![const]) - && !(input.peek2(token::Brace) - || input.peek2(Token![static]) - || input.peek2(Token![async]) - && !(input.peek3(Token![unsafe]) - || input.peek3(Token![extern]) - || input.peek3(Token![fn])) - || input.peek2(Token![move]) - || input.peek2(Token![|])) - || input.peek(Token![unsafe]) && !input.peek2(token::Brace) - || input.peek(Token![async]) - && (input.peek2(Token![unsafe]) - || input.peek2(Token![extern]) - || input.peek2(Token![fn])) - || input.peek(Token![fn]) - || input.peek(Token![mod]) - || input.peek(Token![type]) - || input.peek(Token![struct]) - || input.peek(Token![enum]) - || input.peek(Token![union]) && input.peek2(Ident) - || input.peek(Token![auto]) && input.peek2(Token![trait]) - || input.peek(Token![trait]) - || input.peek(Token![default]) - && (input.peek2(Token![unsafe]) || input.peek2(Token![impl])) - || input.peek(Token![impl]) - || input.peek(Token![macro]) - || is_item_macro - { - let item = item::parsing::parse_rest_of_item(begin, attrs, input)?; - Ok(Stmt::Item(item)) - } else { - stmt_expr(begin, input, allow_nosemi, attrs, attrs_end) - } - } - - fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> { - let bang_token: Token![!] = input.parse()?; - let (delimiter, tokens) = mac::parse_delimiter(input)?; - let semi_token: Option<Token![;]> = input.parse()?; - - Ok(StmtMacro { attrs, mac: Macro { path, bang_token, delimiter, tokens }, semi_token }) - } - - fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> { - let let_token: Token![let] = input.parse()?; - - let mut pat = Pat::parse_single(input)?; - if input.peek(Token![:]) { - let colon_token: Token![:] = input.parse()?; - let ty: Type = input.parse()?; - pat = Pat::Type(PatType { - attrs: Vec::new(), - pat: Box::new(pat), - colon_token, - ty: Box::new(ty), - }); - } - - let init = if let Some(eq_token) = input.parse()? { - let eq_token: Token![=] = eq_token; - let expr: Expr = input.parse()?; - - let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) { - let else_token: Token![else] = input.parse()?; - let diverge = ExprBlock { attrs: Vec::new(), label: None, block: input.parse()? }; - Some((else_token, Box::new(Expr::Block(diverge)))) - } else { - None - }; - - Some(LocalInit { eq_token, expr: Box::new(expr), diverge }) - } else { - None - }; - - let semi_token: Token![;] = input.parse()?; - - Ok(Local { attrs, let_token, pat, init, semi_token }) - } - - fn stmt_expr( - begin: Cursor, - input: ParseStream, - allow_nosemi: AllowNoSemi, - mut attrs: Vec<Attribute>, - attrs_end: Cursor, - ) -> Result<Stmt> { - let mut e = Expr::parse_with_earlier_boundary_rule(input)?; - - let mut attr_target = &mut e; - loop { - attr_target = match attr_target { - Expr::Assign(e) => &mut e.left, - Expr::Binary(e) => &mut e.left, - Expr::Cast(e) => &mut e.expr, - Expr::Array(_) - | Expr::Async(_) - | Expr::Await(_) - | Expr::Block(_) - | Expr::Break(_) - | Expr::Call(_) - | Expr::Closure(_) - | Expr::Const(_) - | Expr::Continue(_) - | Expr::Field(_) - | Expr::ForLoop(_) - | Expr::Group(_) - | Expr::If(_) - | Expr::Index(_) - | Expr::Infer(_) - | Expr::Let(_) - | Expr::Lit(_) - | Expr::Loop(_) - | Expr::Macro(_) - | Expr::Match(_) - | Expr::MethodCall(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::Range(_) - | Expr::RawAddr(_) - | Expr::Reference(_) - | Expr::Repeat(_) - | Expr::Return(_) - | Expr::Struct(_) - | Expr::Try(_) - | Expr::TryBlock(_) - | Expr::Tuple(_) - | Expr::Unary(_) - | Expr::Unsafe(_) - | Expr::While(_) - | Expr::Yield(_) - | Expr::Verbatim(_) => break, - }; - } - - if !attrs.is_empty() { - if let Expr::Verbatim(expr_tokens) = attr_target { - let mut attr_tokens = verbatim::between(begin, attrs_end); - attr_tokens.extend(mem::replace(expr_tokens, TokenStream::new())); - *expr_tokens = attr_tokens; - } else { - let inner_attrs = attr_target.replace_attrs(Vec::new()); - attrs.extend(inner_attrs); - attr_target.replace_attrs(attrs); - } - } - - let semi_token: Option<Token![;]> = input.parse()?; - - match e { - Expr::Macro(ExprMacro { attrs, mac }) - if semi_token.is_some() || mac.delimiter.is_brace() => - { - return Ok(Stmt::Macro(StmtMacro { attrs, mac, semi_token })); - } - _ => {} - } - - if semi_token.is_some() { - Ok(Stmt::Expr(e, semi_token)) - } else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) { - Ok(Stmt::Expr(e, None)) - } else { - Err(input.error("expected semicolon")) - } - } -} - -#[cfg(feature = "printing")] -pub(crate) mod printing { - use crate::classify; - use crate::expr::{self, Expr}; - use crate::fixup::FixupContext; - use crate::stmt::{Block, Local, Stmt, StmtMacro}; - use crate::token; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Block { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.brace_token.surround(tokens, |tokens| { - tokens.append_all(&self.stmts); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Stmt { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Stmt::Local(local) => local.to_tokens(tokens), - Stmt::Item(item) => item.to_tokens(tokens), - Stmt::Expr(expr, semi) => { - expr::printing::print_expr(expr, tokens, FixupContext::new_stmt()); - semi.to_tokens(tokens); - } - Stmt::Macro(mac) => mac.to_tokens(tokens), - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Local { - fn to_tokens(&self, tokens: &mut TokenStream) { - expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); - self.let_token.to_tokens(tokens); - self.pat.to_tokens(tokens); - if let Some(init) = &self.init { - init.eq_token.to_tokens(tokens); - expr::printing::print_subexpression( - &init.expr, - init.diverge.is_some() && classify::expr_trailing_brace(&init.expr), - tokens, - FixupContext::NONE, - ); - if let Some((else_token, diverge)) = &init.diverge { - else_token.to_tokens(tokens); - match &**diverge { - Expr::Block(diverge) => diverge.to_tokens(tokens), - _ => token::Brace::default().surround(tokens, |tokens| { - expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt()); - }), - } - } - } - self.semi_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for StmtMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - expr::printing::outer_attrs_to_tokens(&self.attrs, tokens); - self.mac.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/thread.rs b/deps/crates/vendor/syn-v2/src/thread.rs deleted file mode 100644 index 82accac78ece..000000000000 --- a/deps/crates/vendor/syn-v2/src/thread.rs +++ /dev/null @@ -1,60 +0,0 @@ -use core::fmt::{self, Debug}; -use std::thread::{self, ThreadId}; - -/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value -/// of type T only from the original thread on which the ThreadBound was -/// constructed. -pub(crate) struct ThreadBound<T> { - value: T, - thread_id: ThreadId, -} - -unsafe impl<T> Sync for ThreadBound<T> {} - -// Send bound requires Copy, as otherwise Drop could run in the wrong place. -// -// Today Copy and Drop are mutually exclusive so `T: Copy` implies `T: !Drop`. -// This impl needs to be revisited if that restriction is relaxed in the future. -unsafe impl<T: Copy> Send for ThreadBound<T> {} - -impl<T> ThreadBound<T> { - pub(crate) fn new(value: T) -> Self { - ThreadBound { - value, - thread_id: thread::current().id(), - } - } - - pub(crate) fn get(&self) -> Option<&T> { - if thread::current().id() == self.thread_id { - Some(&self.value) - } else { - None - } - } -} - -impl<T: Debug> Debug for ThreadBound<T> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self.get() { - Some(value) => Debug::fmt(value, formatter), - None => formatter.write_str("unknown"), - } - } -} - -// Copy the bytes of T, even if the currently running thread is the "wrong" -// thread. This is fine as long as the original thread is not simultaneously -// mutating this value via interior mutability, which would be a data race. -// -// Currently `T: Copy` is sufficient to guarantee that T contains no interior -// mutability, because _all_ interior mutability in Rust is built on -// core::cell::UnsafeCell, which has no Copy impl. This impl needs to be -// revisited if that restriction is relaxed in the future. -impl<T: Copy> Copy for ThreadBound<T> {} - -impl<T: Copy> Clone for ThreadBound<T> { - fn clone(&self) -> Self { - *self - } -} diff --git a/deps/crates/vendor/syn-v2/src/token.rs b/deps/crates/vendor/syn-v2/src/token.rs deleted file mode 100644 index 32c5a013e74a..000000000000 --- a/deps/crates/vendor/syn-v2/src/token.rs +++ /dev/null @@ -1,1104 +0,0 @@ -//! Tokens representing Rust punctuation, keywords, and delimiters. -//! -//! The type names in this module can be difficult to keep straight, so we -//! prefer to use the [`Token!`] macro instead. This is a type-macro that -//! expands to the token type of the given token. -//! -//! [`Token!`]: crate::Token -//! -//! # Example -//! -//! The [`ItemStatic`] syntax tree node is defined like this. -//! -//! [`ItemStatic`]: crate::ItemStatic -//! -//! ``` -//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility}; -//! # -//! pub struct ItemStatic { -//! pub attrs: Vec<Attribute>, -//! pub vis: Visibility, -//! pub static_token: Token![static], -//! pub mutability: Option<Token![mut]>, -//! pub ident: Ident, -//! pub colon_token: Token![:], -//! pub ty: Box<Type>, -//! pub eq_token: Token![=], -//! pub expr: Box<Expr>, -//! pub semi_token: Token![;], -//! } -//! ``` -//! -//! # Parsing -//! -//! Keywords and punctuation can be parsed through the [`ParseStream::parse`] -//! method. Delimiter tokens are parsed using the [`parenthesized!`], -//! [`bracketed!`] and [`braced!`] macros. -//! -//! [`ParseStream::parse`]: crate::parse::ParseBuffer::parse() -//! [`parenthesized!`]: crate::parenthesized! -//! [`bracketed!`]: crate::bracketed! -//! [`braced!`]: crate::braced! -//! -//! ``` -//! use syn::{Attribute, Result}; -//! use syn::parse::{Parse, ParseStream}; -//! # -//! # enum ItemStatic {} -//! -//! // Parse the ItemStatic struct shown above. -//! impl Parse for ItemStatic { -//! fn parse(input: ParseStream) -> Result<Self> { -//! # use syn::ItemStatic; -//! # fn parse(input: ParseStream) -> Result<ItemStatic> { -//! Ok(ItemStatic { -//! attrs: input.call(Attribute::parse_outer)?, -//! vis: input.parse()?, -//! static_token: input.parse()?, -//! mutability: input.parse()?, -//! ident: input.parse()?, -//! colon_token: input.parse()?, -//! ty: input.parse()?, -//! eq_token: input.parse()?, -//! expr: input.parse()?, -//! semi_token: input.parse()?, -//! }) -//! # } -//! # unimplemented!() -//! } -//! } -//! ``` -//! -//! # Other operations -//! -//! Every keyword and punctuation token supports the following operations. -//! -//! - [Peeking] — `input.peek(Token![...])` -//! -//! - [Parsing] — `input.parse::<Token![...]>()?` -//! -//! - [Printing] — `quote!( ... #the_token ... )` -//! -//! - Construction from a [`Span`] — `let the_token = Token![...](sp)` -//! -//! - Field access to its span — `let sp = the_token.span` -//! -//! [Peeking]: crate::parse::ParseBuffer::peek() -//! [Parsing]: crate::parse::ParseBuffer::parse() -//! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html -//! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html - -#[cfg(feature = "parsing")] -pub(crate) use self::private::CustomToken; -use self::private::WithSpan; -#[cfg(feature = "parsing")] -use crate::buffer::Cursor; -#[cfg(feature = "parsing")] -use crate::error::Result; -#[cfg(feature = "parsing")] -use crate::lifetime::Lifetime; -#[cfg(feature = "parsing")] -use crate::parse::{Parse, ParseStream}; -use crate::span::IntoSpans; -#[cfg(feature = "extra-traits")] -use core::cmp; -#[cfg(feature = "extra-traits")] -use core::fmt::{self, Debug}; -#[cfg(feature = "extra-traits")] -use core::hash::{Hash, Hasher}; -use core::ops::{Deref, DerefMut}; -use proc_macro2::extra::DelimSpan; -use proc_macro2::Span; -#[cfg(feature = "printing")] -use proc_macro2::TokenStream; -#[cfg(any(feature = "parsing", feature = "printing"))] -use proc_macro2::{Delimiter, Ident}; -#[cfg(feature = "parsing")] -use proc_macro2::{Literal, Punct, TokenTree}; -#[cfg(feature = "printing")] -use quote::{ToTokens, TokenStreamExt as _}; - -/// Marker trait for types that represent single tokens. -/// -/// This trait is sealed and cannot be implemented for types outside of Syn. -#[cfg(feature = "parsing")] -pub trait Token: private::Sealed { - // Not public API. - #[doc(hidden)] - fn peek(cursor: Cursor) -> bool; - - // Not public API. - #[doc(hidden)] - fn display() -> &'static str; -} - -pub(crate) mod private { - #[cfg(feature = "parsing")] - use crate::buffer::Cursor; - use proc_macro2::Span; - - #[cfg(feature = "parsing")] - pub trait Sealed {} - - /// Support writing `token.span` rather than `token.spans[0]` on tokens that - /// hold a single span. - #[repr(transparent)] - #[allow( - unknown_lints, - renamed_and_removed_lints, - // False positive: https://github.com/rust-lang/rust/issues/115922 - repr_transparent_non_zst_fields, - )] - pub struct WithSpan { - pub span: Span, - } - - // Not public API. - #[doc(hidden)] - #[cfg(feature = "parsing")] - pub trait CustomToken { - fn peek(cursor: Cursor) -> bool; - fn display() -> &'static str; - } -} - -#[cfg(feature = "parsing")] -impl private::Sealed for Ident {} - -macro_rules! impl_low_level_token { - ($display:literal $($path:ident)::+ $get:ident) => { - #[cfg(feature = "parsing")] - impl Token for $($path)::+ { - fn peek(cursor: Cursor) -> bool { - cursor.$get().is_some() - } - - fn display() -> &'static str { - $display - } - } - - #[cfg(feature = "parsing")] - impl private::Sealed for $($path)::+ {} - }; -} - -impl_low_level_token!("punctuation token" Punct punct); -impl_low_level_token!("literal" Literal literal); -impl_low_level_token!("token" TokenTree token_tree); -impl_low_level_token!("group token" proc_macro2::Group any_group); -impl_low_level_token!("lifetime" Lifetime lifetime); - -#[cfg(feature = "parsing")] -impl<T: CustomToken> private::Sealed for T {} - -#[cfg(feature = "parsing")] -impl<T: CustomToken> Token for T { - fn peek(cursor: Cursor) -> bool { - <Self as CustomToken>::peek(cursor) - } - - fn display() -> &'static str { - <Self as CustomToken>::display() - } -} - -macro_rules! define_keywords { - ($($token:literal pub struct $name:ident)*) => { - $( - #[doc = concat!('`', $token, '`')] - /// - /// Don't try to remember the name of this type — use the - /// [`Token!`] macro instead. - /// - /// [`Token!`]: crate::token - pub struct $name { - pub span: Span, - } - - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn $name<S: IntoSpans<Span>>(span: S) -> $name { - $name { - span: span.into_spans(), - } - } - - impl core::default::Default for $name { - fn default() -> Self { - $name { - span: Span::call_site(), - } - } - } - - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Copy for $name {} - - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Clone for $name { - fn clone(&self) -> Self { - *self - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(stringify!($name)) - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl cmp::Eq for $name {} - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl PartialEq for $name { - fn eq(&self, _other: &$name) -> bool { - true - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Hash for $name { - fn hash<H: Hasher>(&self, _state: &mut H) {} - } - - #[cfg(feature = "printing")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for $name { - fn to_tokens(&self, tokens: &mut TokenStream) { - printing::keyword($token, self.span, tokens); - } - } - - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for $name { - fn parse(input: ParseStream) -> Result<Self> { - Ok($name { - span: parsing::keyword(input, $token)?, - }) - } - } - - #[cfg(feature = "parsing")] - impl Token for $name { - fn peek(cursor: Cursor) -> bool { - parsing::peek_keyword(cursor, $token) - } - - fn display() -> &'static str { - concat!("`", $token, "`") - } - } - - #[cfg(feature = "parsing")] - impl private::Sealed for $name {} - )* - }; -} - -macro_rules! impl_deref_if_len_is_1 { - ($name:ident/1) => { - impl Deref for $name { - type Target = WithSpan; - - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const Self).cast::<WithSpan>() } - } - } - - impl DerefMut for $name { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *(self as *mut Self).cast::<WithSpan>() } - } - } - }; - - ($name:ident/$len:literal) => {}; -} - -macro_rules! define_punctuation_structs { - ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => { - $( - #[cfg_attr(not(doc), repr(transparent))] - #[allow( - unknown_lints, - renamed_and_removed_lints, - // False positive: https://github.com/rust-lang/rust/issues/115922 - repr_transparent_non_zst_fields, - )] - #[doc = concat!('`', $token, '`')] - /// - /// Usage: - #[doc = concat!($usage, '.')] - /// - /// Don't try to remember the name of this type — use the - /// [`Token!`] macro instead. - /// - /// [`Token!`]: crate::token - pub struct $name { - pub spans: [Span; $len], - } - - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name { - $name { - spans: spans.into_spans(), - } - } - - impl core::default::Default for $name { - fn default() -> Self { - $name { - spans: [Span::call_site(); $len], - } - } - } - - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Copy for $name {} - - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Clone for $name { - fn clone(&self) -> Self { - *self - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(stringify!($name)) - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl cmp::Eq for $name {} - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl PartialEq for $name { - fn eq(&self, _other: &$name) -> bool { - true - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Hash for $name { - fn hash<H: Hasher>(&self, _state: &mut H) {} - } - - impl_deref_if_len_is_1!($name/$len); - )* - }; -} - -macro_rules! define_punctuation { - ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => { - $( - define_punctuation_structs! { - $token pub struct $name/$len #[doc = $usage] - } - - #[cfg(feature = "printing")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for $name { - fn to_tokens(&self, tokens: &mut TokenStream) { - printing::punct($token, &self.spans, tokens); - } - } - - #[cfg(feature = "parsing")] - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for $name { - fn parse(input: ParseStream) -> Result<Self> { - Ok($name { - spans: parsing::punct(input, $token)?, - }) - } - } - - #[cfg(feature = "parsing")] - impl Token for $name { - fn peek(cursor: Cursor) -> bool { - parsing::peek_punct(cursor, $token) - } - - fn display() -> &'static str { - concat!("`", $token, "`") - } - } - - #[cfg(feature = "parsing")] - impl private::Sealed for $name {} - )* - }; -} - -macro_rules! define_delimiters { - ($($delim:ident pub struct $name:ident #[$doc:meta])*) => { - $( - #[$doc] - pub struct $name { - pub span: DelimSpan, - } - - #[doc(hidden)] - #[allow(non_snake_case)] - pub fn $name<S: IntoSpans<DelimSpan>>(span: S) -> $name { - $name { - span: span.into_spans(), - } - } - - impl core::default::Default for $name { - fn default() -> Self { - $name(Span::call_site()) - } - } - - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Copy for $name {} - - #[cfg(feature = "clone-impls")] - #[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] - impl Clone for $name { - fn clone(&self) -> Self { - *self - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Debug for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(stringify!($name)) - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl cmp::Eq for $name {} - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl PartialEq for $name { - fn eq(&self, _other: &$name) -> bool { - true - } - } - - #[cfg(feature = "extra-traits")] - #[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] - impl Hash for $name { - fn hash<H: Hasher>(&self, _state: &mut H) {} - } - - impl $name { - #[cfg(feature = "printing")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - pub fn surround<F>(&self, tokens: &mut TokenStream, f: F) - where - F: FnOnce(&mut TokenStream), - { - let mut inner = TokenStream::new(); - f(&mut inner); - printing::delim(Delimiter::$delim, self.span.join(), tokens, inner); - } - } - - #[cfg(feature = "parsing")] - impl private::Sealed for $name {} - )* - }; -} - -define_punctuation_structs! { - "_" pub struct Underscore/1 /// wildcard patterns, inferred types, unnamed items in constants, extern crates, use declarations, and destructuring assignment -} - -#[cfg(feature = "printing")] -#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] -impl ToTokens for Underscore { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append(Ident::new("_", self.span)); - } -} - -#[cfg(feature = "parsing")] -#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] -impl Parse for Underscore { - fn parse(input: ParseStream) -> Result<Self> { - input.step(|cursor| { - if let Some((ident, rest)) = cursor.ident() { - if ident == "_" { - return Ok((Underscore(ident.span()), rest)); - } - } - if let Some((punct, rest)) = cursor.punct() { - if punct.as_char() == '_' { - return Ok((Underscore(punct.span()), rest)); - } - } - Err(cursor.error("expected `_`")) - }) - } -} - -#[cfg(feature = "parsing")] -impl Token for Underscore { - fn peek(cursor: Cursor) -> bool { - if let Some((ident, _rest)) = cursor.ident() { - return ident == "_"; - } - if let Some((punct, _rest)) = cursor.punct() { - return punct.as_char() == '_'; - } - false - } - - fn display() -> &'static str { - "`_`" - } -} - -#[cfg(feature = "parsing")] -impl private::Sealed for Underscore {} - -/// None-delimited group -pub struct Group { - pub span: Span, -} - -#[doc(hidden)] -#[allow(non_snake_case)] -pub fn Group<S: IntoSpans<Span>>(span: S) -> Group { - Group { - span: span.into_spans(), - } -} - -impl core::default::Default for Group { - fn default() -> Self { - Group { - span: Span::call_site(), - } - } -} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Copy for Group {} - -#[cfg(feature = "clone-impls")] -#[cfg_attr(docsrs, doc(cfg(feature = "clone-impls")))] -impl Clone for Group { - fn clone(&self) -> Self { - *self - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("Group") - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl cmp::Eq for Group {} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl PartialEq for Group { - fn eq(&self, _other: &Group) -> bool { - true - } -} - -#[cfg(feature = "extra-traits")] -#[cfg_attr(docsrs, doc(cfg(feature = "extra-traits")))] -impl Hash for Group { - fn hash<H: Hasher>(&self, _state: &mut H) {} -} - -impl Group { - #[cfg(feature = "printing")] - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - pub fn surround<F>(&self, tokens: &mut TokenStream, f: F) - where - F: FnOnce(&mut TokenStream), - { - let mut inner = TokenStream::new(); - f(&mut inner); - printing::delim(Delimiter::None, self.span, tokens, inner); - } -} - -#[cfg(feature = "parsing")] -impl private::Sealed for Group {} - -#[cfg(feature = "parsing")] -impl Token for Paren { - fn peek(cursor: Cursor) -> bool { - cursor.group(Delimiter::Parenthesis).is_some() - } - - fn display() -> &'static str { - "parentheses" - } -} - -#[cfg(feature = "parsing")] -impl Token for Brace { - fn peek(cursor: Cursor) -> bool { - cursor.group(Delimiter::Brace).is_some() - } - - fn display() -> &'static str { - "curly braces" - } -} - -#[cfg(feature = "parsing")] -impl Token for Bracket { - fn peek(cursor: Cursor) -> bool { - cursor.group(Delimiter::Bracket).is_some() - } - - fn display() -> &'static str { - "square brackets" - } -} - -#[cfg(feature = "parsing")] -impl Token for Group { - fn peek(cursor: Cursor) -> bool { - cursor.group(Delimiter::None).is_some() - } - - fn display() -> &'static str { - "invisible group" - } -} - -define_keywords! { - "abstract" pub struct Abstract - "as" pub struct As - "async" pub struct Async - "auto" pub struct Auto - "await" pub struct Await - "become" pub struct Become - "box" pub struct Box - "break" pub struct Break - "const" pub struct Const - "continue" pub struct Continue - "crate" pub struct Crate - "default" pub struct Default - "do" pub struct Do - "dyn" pub struct Dyn - "else" pub struct Else - "enum" pub struct Enum - "extern" pub struct Extern - "final" pub struct Final - "fn" pub struct Fn - "for" pub struct For - "if" pub struct If - "impl" pub struct Impl - "in" pub struct In - "let" pub struct Let - "loop" pub struct Loop - "macro" pub struct Macro - "match" pub struct Match - "mod" pub struct Mod - "move" pub struct Move - "mut" pub struct Mut - "override" pub struct Override - "priv" pub struct Priv - "pub" pub struct Pub - "raw" pub struct Raw - "ref" pub struct Ref - "return" pub struct Return - "Self" pub struct SelfType - "self" pub struct SelfValue - "static" pub struct Static - "struct" pub struct Struct - "super" pub struct Super - "trait" pub struct Trait - "try" pub struct Try - "type" pub struct Type - "typeof" pub struct Typeof - "union" pub struct Union - "unsafe" pub struct Unsafe - "unsized" pub struct Unsized - "use" pub struct Use - "virtual" pub struct Virtual - "where" pub struct Where - "while" pub struct While - "yield" pub struct Yield -} - -define_punctuation! { - "&" pub struct And/1 /// bitwise and logical AND, borrow, references, reference patterns - "&&" pub struct AndAnd/2 /// lazy AND, borrow, references, reference patterns - "&=" pub struct AndEq/2 /// bitwise AND assignment - "@" pub struct At/1 /// subpattern binding - "^" pub struct Caret/1 /// bitwise and logical XOR - "^=" pub struct CaretEq/2 /// bitwise XOR assignment - ":" pub struct Colon/1 /// various separators - "," pub struct Comma/1 /// various separators - "$" pub struct Dollar/1 /// macros - "." pub struct Dot/1 /// field access, tuple index - ".." pub struct DotDot/2 /// range, struct expressions, patterns, range patterns - "..." pub struct DotDotDot/3 /// variadic functions, range patterns - "..=" pub struct DotDotEq/3 /// inclusive range, range patterns - "=" pub struct Eq/1 /// assignment, attributes, various type definitions - "==" pub struct EqEq/2 /// equal - "=>" pub struct FatArrow/2 /// match arms, macros - ">=" pub struct Ge/2 /// greater than or equal to, generics - ">" pub struct Gt/1 /// greater than, generics, paths - "<-" pub struct LArrow/2 /// unused - "<=" pub struct Le/2 /// less than or equal to - "<" pub struct Lt/1 /// less than, generics, paths - "-" pub struct Minus/1 /// subtraction, negation - "-=" pub struct MinusEq/2 /// subtraction assignment - "!=" pub struct Ne/2 /// not equal - "!" pub struct Not/1 /// bitwise and logical NOT, macro calls, inner attributes, never type, negative impls - "|" pub struct Or/1 /// bitwise and logical OR, closures, patterns in match, if let, and while let - "|=" pub struct OrEq/2 /// bitwise OR assignment - "||" pub struct OrOr/2 /// lazy OR, closures - "::" pub struct PathSep/2 /// path separator - "%" pub struct Percent/1 /// remainder - "%=" pub struct PercentEq/2 /// remainder assignment - "+" pub struct Plus/1 /// addition, trait bounds, macro Kleene matcher - "+=" pub struct PlusEq/2 /// addition assignment - "#" pub struct Pound/1 /// attributes - "?" pub struct Question/1 /// question mark operator, questionably sized, macro Kleene matcher - "->" pub struct RArrow/2 /// function return type, closure return type, function pointer type - ";" pub struct Semi/1 /// terminator for various items and statements, array types - "<<" pub struct Shl/2 /// shift left, nested generics - "<<=" pub struct ShlEq/3 /// shift left assignment - ">>" pub struct Shr/2 /// shift right, nested generics - ">>=" pub struct ShrEq/3 /// shift right assignment, nested generics - "/" pub struct Slash/1 /// division - "/=" pub struct SlashEq/2 /// division assignment - "*" pub struct Star/1 /// multiplication, dereference, raw pointers, macro Kleene matcher, use wildcards - "*=" pub struct StarEq/2 /// multiplication assignment - "~" pub struct Tilde/1 /// unused since before Rust 1.0 -} - -define_delimiters! { - Brace pub struct Brace /// `{`…`}` - Bracket pub struct Bracket /// `[`…`]` - Parenthesis pub struct Paren /// `(`…`)` -} - -/// A type-macro that expands to the name of the Rust type representation of a -/// given token. -/// -/// As a type, `Token!` is commonly used in the type of struct fields, the type -/// of a `let` statement, or in turbofish for a `parse` function. -/// -/// ``` -/// use syn::{Ident, Token}; -/// use syn::parse::{Parse, ParseStream, Result}; -/// -/// // `struct Foo;` -/// pub struct UnitStruct { -/// struct_token: Token![struct], -/// ident: Ident, -/// semi_token: Token![;], -/// } -/// -/// impl Parse for UnitStruct { -/// fn parse(input: ParseStream) -> Result<Self> { -/// let struct_token: Token![struct] = input.parse()?; -/// let ident: Ident = input.parse()?; -/// let semi_token = input.parse::<Token![;]>()?; -/// Ok(UnitStruct { struct_token, ident, semi_token }) -/// } -/// } -/// ``` -/// -/// As an expression, `Token!` is used for peeking tokens or instantiating -/// tokens from a span. -/// -/// ``` -/// # use syn::{Ident, Token}; -/// # use syn::parse::{Parse, ParseStream, Result}; -/// # -/// # struct UnitStruct { -/// # struct_token: Token![struct], -/// # ident: Ident, -/// # semi_token: Token![;], -/// # } -/// # -/// # impl Parse for UnitStruct { -/// # fn parse(input: ParseStream) -> Result<Self> { -/// # unimplemented!() -/// # } -/// # } -/// # -/// fn make_unit_struct(name: Ident) -> UnitStruct { -/// let span = name.span(); -/// UnitStruct { -/// struct_token: Token![struct](span), -/// ident: name, -/// semi_token: Token![;](span), -/// } -/// } -/// -/// # fn parse(input: ParseStream) -> Result<()> { -/// if input.peek(Token![struct]) { -/// let unit_struct: UnitStruct = input.parse()?; -/// /* ... */ -/// } -/// # Ok(()) -/// # } -/// ``` -/// -/// See the [token module] documentation for details and examples. -/// -/// [token module]: crate::token -#[macro_export] -macro_rules! Token { - [abstract] => { $crate::token::Abstract }; - [as] => { $crate::token::As }; - [async] => { $crate::token::Async }; - [auto] => { $crate::token::Auto }; - [await] => { $crate::token::Await }; - [become] => { $crate::token::Become }; - [box] => { $crate::token::Box }; - [break] => { $crate::token::Break }; - [const] => { $crate::token::Const }; - [continue] => { $crate::token::Continue }; - [crate] => { $crate::token::Crate }; - [default] => { $crate::token::Default }; - [do] => { $crate::token::Do }; - [dyn] => { $crate::token::Dyn }; - [else] => { $crate::token::Else }; - [enum] => { $crate::token::Enum }; - [extern] => { $crate::token::Extern }; - [final] => { $crate::token::Final }; - [fn] => { $crate::token::Fn }; - [for] => { $crate::token::For }; - [if] => { $crate::token::If }; - [impl] => { $crate::token::Impl }; - [in] => { $crate::token::In }; - [let] => { $crate::token::Let }; - [loop] => { $crate::token::Loop }; - [macro] => { $crate::token::Macro }; - [match] => { $crate::token::Match }; - [mod] => { $crate::token::Mod }; - [move] => { $crate::token::Move }; - [mut] => { $crate::token::Mut }; - [override] => { $crate::token::Override }; - [priv] => { $crate::token::Priv }; - [pub] => { $crate::token::Pub }; - [raw] => { $crate::token::Raw }; - [ref] => { $crate::token::Ref }; - [return] => { $crate::token::Return }; - [Self] => { $crate::token::SelfType }; - [self] => { $crate::token::SelfValue }; - [static] => { $crate::token::Static }; - [struct] => { $crate::token::Struct }; - [super] => { $crate::token::Super }; - [trait] => { $crate::token::Trait }; - [try] => { $crate::token::Try }; - [type] => { $crate::token::Type }; - [typeof] => { $crate::token::Typeof }; - [union] => { $crate::token::Union }; - [unsafe] => { $crate::token::Unsafe }; - [unsized] => { $crate::token::Unsized }; - [use] => { $crate::token::Use }; - [virtual] => { $crate::token::Virtual }; - [where] => { $crate::token::Where }; - [while] => { $crate::token::While }; - [yield] => { $crate::token::Yield }; - [&] => { $crate::token::And }; - [&&] => { $crate::token::AndAnd }; - [&=] => { $crate::token::AndEq }; - [@] => { $crate::token::At }; - [^] => { $crate::token::Caret }; - [^=] => { $crate::token::CaretEq }; - [:] => { $crate::token::Colon }; - [,] => { $crate::token::Comma }; - [$] => { $crate::token::Dollar }; - [.] => { $crate::token::Dot }; - [..] => { $crate::token::DotDot }; - [...] => { $crate::token::DotDotDot }; - [..=] => { $crate::token::DotDotEq }; - [=] => { $crate::token::Eq }; - [==] => { $crate::token::EqEq }; - [=>] => { $crate::token::FatArrow }; - [>=] => { $crate::token::Ge }; - [>] => { $crate::token::Gt }; - [<-] => { $crate::token::LArrow }; - [<=] => { $crate::token::Le }; - [<] => { $crate::token::Lt }; - [-] => { $crate::token::Minus }; - [-=] => { $crate::token::MinusEq }; - [!=] => { $crate::token::Ne }; - [!] => { $crate::token::Not }; - [|] => { $crate::token::Or }; - [|=] => { $crate::token::OrEq }; - [||] => { $crate::token::OrOr }; - [::] => { $crate::token::PathSep }; - [%] => { $crate::token::Percent }; - [%=] => { $crate::token::PercentEq }; - [+] => { $crate::token::Plus }; - [+=] => { $crate::token::PlusEq }; - [#] => { $crate::token::Pound }; - [?] => { $crate::token::Question }; - [->] => { $crate::token::RArrow }; - [;] => { $crate::token::Semi }; - [<<] => { $crate::token::Shl }; - [<<=] => { $crate::token::ShlEq }; - [>>] => { $crate::token::Shr }; - [>>=] => { $crate::token::ShrEq }; - [/] => { $crate::token::Slash }; - [/=] => { $crate::token::SlashEq }; - [*] => { $crate::token::Star }; - [*=] => { $crate::token::StarEq }; - [~] => { $crate::token::Tilde }; - [_] => { $crate::token::Underscore }; -} - -// Not public API. -#[doc(hidden)] -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::buffer::Cursor; - use crate::error::{Error, Result}; - use crate::parse::ParseStream; - use alloc::format; - use proc_macro2::{Spacing, Span}; - - pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> { - input.step(|cursor| { - if let Some((ident, rest)) = cursor.ident() { - if ident == token { - return Ok((ident.span(), rest)); - } - } - Err(cursor.error(format!("expected `{}`", token))) - }) - } - - pub(crate) fn peek_keyword(cursor: Cursor, token: &str) -> bool { - if let Some((ident, _rest)) = cursor.ident() { - ident == token - } else { - false - } - } - - #[doc(hidden)] - pub fn punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]> { - let mut spans = [input.span(); N]; - punct_helper(input, token, &mut spans)?; - Ok(spans) - } - - fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()> { - input.step(|cursor| { - let mut cursor = *cursor; - assert_eq!(token.len(), spans.len()); - - for (i, ch) in token.chars().enumerate() { - match cursor.punct() { - Some((punct, rest)) => { - spans[i] = punct.span(); - if punct.as_char() != ch { - break; - } else if i == token.len() - 1 { - return Ok(((), rest)); - } else if punct.spacing() != Spacing::Joint { - break; - } - cursor = rest; - } - None => break, - } - } - - Err(Error::new(spans[0], format!("expected `{}`", token))) - }) - } - - #[doc(hidden)] - pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool { - for (i, ch) in token.chars().enumerate() { - match cursor.punct() { - Some((punct, rest)) => { - if punct.as_char() != ch { - break; - } else if i == token.len() - 1 { - return true; - } else if punct.spacing() != Spacing::Joint { - break; - } - cursor = rest; - } - None => break, - } - } - false - } -} - -// Not public API. -#[doc(hidden)] -#[cfg(feature = "printing")] -pub(crate) mod printing { - use crate::ext::PunctExt as _; - use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream}; - use quote::TokenStreamExt as _; - - #[doc(hidden)] - pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) { - assert_eq!(s.len(), spans.len()); - - let mut chars = s.chars(); - let mut spans = spans.iter(); - let ch = chars.next_back().unwrap(); - let span = spans.next_back().unwrap(); - for (ch, span) in chars.zip(spans) { - tokens.append(Punct::new_spanned(ch, Spacing::Joint, *span)); - } - - tokens.append(Punct::new_spanned(ch, Spacing::Alone, *span)); - } - - pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) { - tokens.append(Ident::new(s, span)); - } - - pub(crate) fn delim( - delim: Delimiter, - span: Span, - tokens: &mut TokenStream, - inner: TokenStream, - ) { - let mut g = Group::new(delim, inner); - g.set_span(span); - tokens.append(g); - } -} diff --git a/deps/crates/vendor/syn-v2/src/tt.rs b/deps/crates/vendor/syn-v2/src/tt.rs deleted file mode 100644 index 63a89acc3170..000000000000 --- a/deps/crates/vendor/syn-v2/src/tt.rs +++ /dev/null @@ -1,97 +0,0 @@ -use alloc::string::ToString; -use core::hash::{Hash, Hasher}; -use proc_macro2::{Delimiter, Spacing, TokenStream, TokenTree}; - -pub(crate) struct TokenTreeHelper<'a>(pub &'a TokenTree); - -impl<'a> PartialEq for TokenTreeHelper<'a> { - fn eq(&self, other: &Self) -> bool { - match (self.0, other.0) { - (TokenTree::Group(g1), TokenTree::Group(g2)) => { - match (g1.delimiter(), g2.delimiter()) { - (Delimiter::Parenthesis, Delimiter::Parenthesis) - | (Delimiter::Brace, Delimiter::Brace) - | (Delimiter::Bracket, Delimiter::Bracket) - | (Delimiter::None, Delimiter::None) => {} - _ => return false, - } - - TokenStreamHelper(&g1.stream()) == TokenStreamHelper(&g2.stream()) - } - (TokenTree::Punct(o1), TokenTree::Punct(o2)) => { - o1.as_char() == o2.as_char() - && match (o1.spacing(), o2.spacing()) { - (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true, - _ => false, - } - } - (TokenTree::Literal(l1), TokenTree::Literal(l2)) => l1.to_string() == l2.to_string(), - (TokenTree::Ident(s1), TokenTree::Ident(s2)) => s1 == s2, - _ => false, - } - } -} - -impl<'a> Hash for TokenTreeHelper<'a> { - fn hash<H: Hasher>(&self, h: &mut H) { - match self.0 { - TokenTree::Group(g) => { - 0u8.hash(h); - match g.delimiter() { - Delimiter::Parenthesis => 0u8.hash(h), - Delimiter::Brace => 1u8.hash(h), - Delimiter::Bracket => 2u8.hash(h), - Delimiter::None => 3u8.hash(h), - } - - for item in g.stream() { - TokenTreeHelper(&item).hash(h); - } - 0xFFu8.hash(h); // terminator w/ a variant we don't normally hash - } - TokenTree::Punct(op) => { - 1u8.hash(h); - op.as_char().hash(h); - match op.spacing() { - Spacing::Alone => 0u8.hash(h), - Spacing::Joint => 1u8.hash(h), - } - } - TokenTree::Literal(lit) => (2u8, lit.to_string()).hash(h), - TokenTree::Ident(word) => (3u8, word).hash(h), - } - } -} - -pub(crate) struct TokenStreamHelper<'a>(pub &'a TokenStream); - -impl<'a> PartialEq for TokenStreamHelper<'a> { - fn eq(&self, other: &Self) -> bool { - let left = self.0.clone().into_iter(); - let mut right = other.0.clone().into_iter(); - - for item1 in left { - let item2 = match right.next() { - Some(item) => item, - None => return false, - }; - if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) { - return false; - } - } - - right.next().is_none() - } -} - -impl<'a> Hash for TokenStreamHelper<'a> { - fn hash<H: Hasher>(&self, state: &mut H) { - let tokens = self.0.clone().into_iter(); - - tokens.clone().count().hash(state); - - for tt in tokens { - TokenTreeHelper(&tt).hash(state); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/ty.rs b/deps/crates/vendor/syn-v2/src/ty.rs deleted file mode 100644 index ef2f2716270c..000000000000 --- a/deps/crates/vendor/syn-v2/src/ty.rs +++ /dev/null @@ -1,1239 +0,0 @@ -use crate::attr::Attribute; -use crate::expr::Expr; -use crate::generics::{BoundLifetimes, TypeParamBound}; -use crate::ident::Ident; -use crate::lifetime::Lifetime; -use crate::lit::LitStr; -use crate::mac::Macro; -use crate::path::{Path, QSelf}; -use crate::punctuated::Punctuated; -use crate::token; -use alloc::boxed::Box; -use alloc::vec::Vec; -use proc_macro2::TokenStream; - -ast_enum_of_structs! { - /// The possible types that a Rust value could have. - /// - /// # Syntax tree enum - /// - /// This type is a [syntax tree enum]. - /// - /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - #[non_exhaustive] - pub enum Type { - /// A fixed size array type: `[T; n]`. - Array(TypeArray), - - /// A bare function type: `fn(usize) -> bool`. - BareFn(TypeBareFn), - - /// A type contained within invisible delimiters. - Group(TypeGroup), - - /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or - /// a lifetime. - ImplTrait(TypeImplTrait), - - /// Indication that a type should be inferred by the compiler: `_`. - Infer(TypeInfer), - - /// A macro in the type position. - Macro(TypeMacro), - - /// The never type: `!`. - Never(TypeNever), - - /// A parenthesized type equivalent to the inner type. - Paren(TypeParen), - - /// A path like `core::slice::Iter`, optionally qualified with a - /// self-type as in `<Vec<T> as SomeTrait>::Associated`. - Path(TypePath), - - /// A raw pointer type: `*const T` or `*mut T`. - Ptr(TypePtr), - - /// A reference type: `&'a T` or `&'a mut T`. - Reference(TypeReference), - - /// A dynamically sized slice type: `[T]`. - Slice(TypeSlice), - - /// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a - /// trait or a lifetime. - TraitObject(TypeTraitObject), - - /// A tuple type: `(A, B, C, String)`. - Tuple(TypeTuple), - - /// Tokens in type position not interpreted by Syn. - Verbatim(TokenStream), - - // For testing exhaustiveness in downstream code, use the following idiom: - // - // match ty { - // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] - // - // Type::Array(ty) => {...} - // Type::BareFn(ty) => {...} - // ... - // Type::Verbatim(ty) => {...} - // - // _ => { /* some sane fallback */ } - // } - // - // This way we fail your tests but don't break your library when adding - // a variant. You will be notified by a test failure when a variant is - // added, so that you can add code to handle it, but your library will - // continue to compile and work for downstream users in the interim. - } -} - -ast_struct! { - /// A fixed size array type: `[T; n]`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeArray { - pub bracket_token: token::Bracket, - pub elem: Box<Type>, - pub semi_token: Token![;], - pub len: Expr, - } -} - -ast_struct! { - /// A bare function type: `fn(usize) -> bool`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeBareFn { - pub lifetimes: Option<BoundLifetimes>, - pub unsafety: Option<Token![unsafe]>, - pub abi: Option<Abi>, - pub fn_token: Token![fn], - pub paren_token: token::Paren, - pub inputs: Punctuated<BareFnArg, Token![,]>, - pub variadic: Option<BareVariadic>, - pub output: ReturnType, - } -} - -ast_struct! { - /// A type contained within invisible delimiters. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeGroup { - pub group_token: token::Group, - pub elem: Box<Type>, - } -} - -ast_struct! { - /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or - /// a lifetime. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeImplTrait { - pub impl_token: Token![impl], - pub bounds: Punctuated<TypeParamBound, Token![+]>, - } -} - -ast_struct! { - /// Indication that a type should be inferred by the compiler: `_`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeInfer { - pub underscore_token: Token![_], - } -} - -ast_struct! { - /// A macro in the type position. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeMacro { - pub mac: Macro, - } -} - -ast_struct! { - /// The never type: `!`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeNever { - pub bang_token: Token![!], - } -} - -ast_struct! { - /// A parenthesized type equivalent to the inner type. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeParen { - pub paren_token: token::Paren, - pub elem: Box<Type>, - } -} - -ast_struct! { - /// A path like `core::slice::Iter`, optionally qualified with a - /// self-type as in `<Vec<T> as SomeTrait>::Associated`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypePath { - pub qself: Option<QSelf>, - pub path: Path, - } -} - -ast_struct! { - /// A raw pointer type: `*const T` or `*mut T`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypePtr { - pub star_token: Token![*], - pub const_token: Option<Token![const]>, - pub mutability: Option<Token![mut]>, - pub elem: Box<Type>, - } -} - -ast_struct! { - /// A reference type: `&'a T` or `&'a mut T`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeReference { - pub and_token: Token![&], - pub lifetime: Option<Lifetime>, - pub mutability: Option<Token![mut]>, - pub elem: Box<Type>, - } -} - -ast_struct! { - /// A dynamically sized slice type: `[T]`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeSlice { - pub bracket_token: token::Bracket, - pub elem: Box<Type>, - } -} - -ast_struct! { - /// A trait object type `dyn Bound1 + Bound2 + Bound3` where `Bound` is a - /// trait or a lifetime. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeTraitObject { - pub dyn_token: Option<Token![dyn]>, - pub bounds: Punctuated<TypeParamBound, Token![+]>, - } -} - -ast_struct! { - /// A tuple type: `(A, B, C, String)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct TypeTuple { - pub paren_token: token::Paren, - pub elems: Punctuated<Type, Token![,]>, - } -} - -ast_struct! { - /// The binary interface of a function: `extern "C"`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct Abi { - pub extern_token: Token![extern], - pub name: Option<LitStr>, - } -} - -ast_struct! { - /// An argument in a function type: the `usize` in `fn(usize) -> bool`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct BareFnArg { - pub attrs: Vec<Attribute>, - pub name: Option<(Ident, Token![:])>, - pub ty: Type, - } -} - -ast_struct! { - /// The variadic argument of a function pointer like `fn(usize, ...)`. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub struct BareVariadic { - pub attrs: Vec<Attribute>, - pub name: Option<(Ident, Token![:])>, - pub dots: Token![...], - pub comma: Option<Token![,]>, - } -} - -ast_enum! { - /// Return type of a function signature. - #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] - pub enum ReturnType { - /// Return type is not specified. - /// - /// Functions default to `()` and closures default to type inference. - Default, - /// A particular type is returned. - Type(Token![->], Box<Type>), - } -} - -#[cfg(feature = "parsing")] -pub(crate) mod parsing { - use crate::attr::Attribute; - use crate::error::{self, Result}; - use crate::ext::IdentExt as _; - use crate::generics::{BoundLifetimes, TraitBound, TraitBoundModifier, TypeParamBound}; - use crate::ident::Ident; - use crate::lifetime::Lifetime; - use crate::mac::{self, Macro}; - use crate::parse::{Parse, ParseStream}; - use crate::path; - use crate::path::{Path, PathArguments, QSelf}; - use crate::punctuated::Punctuated; - use crate::token; - use crate::ty::{ - Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, - TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, - TypeReference, TypeSlice, TypeTraitObject, TypeTuple, - }; - use crate::verbatim; - use alloc::boxed::Box; - use alloc::vec::Vec; - use proc_macro2::{Span, TokenStream}; - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Type { - fn parse(input: ParseStream) -> Result<Self> { - let allow_plus = true; - let allow_group_generic = true; - ambig_ty(input, allow_plus, allow_group_generic) - } - } - - impl Type { - /// In some positions, types may not contain the `+` character, to - /// disambiguate them. For example in the expression `1 as T`, T may not - /// contain a `+` character. - /// - /// This parser does not allow a `+`, while the default parser does. - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn without_plus(input: ParseStream) -> Result<Self> { - let allow_plus = false; - let allow_group_generic = true; - ambig_ty(input, allow_plus, allow_group_generic) - } - } - - pub(crate) fn ambig_ty( - input: ParseStream, - allow_plus: bool, - allow_group_generic: bool, - ) -> Result<Type> { - let begin = input.cursor(); - - if input.peek(token::Group) { - let mut group: TypeGroup = input.parse()?; - if input.peek(Token![::]) && input.peek3(Ident::peek_any) { - if let Type::Path(mut ty) = *group.elem { - Path::parse_rest(input, &mut ty.path, false)?; - return Ok(Type::Path(ty)); - } else { - return Ok(Type::Path(TypePath { - qself: Some(QSelf { - lt_token: Token![<](group.group_token.span), - position: 0, - as_token: None, - gt_token: Token![>](group.group_token.span), - ty: group.elem, - }), - path: Path::parse_helper(input, false)?, - })); - } - } else if input.peek(Token![<]) && allow_group_generic - || input.peek(Token![::]) && input.peek3(Token![<]) - { - if let Type::Path(mut ty) = *group.elem { - let arguments = &mut ty.path.segments.last_mut().unwrap().arguments; - if arguments.is_none() { - *arguments = PathArguments::AngleBracketed(input.parse()?); - Path::parse_rest(input, &mut ty.path, false)?; - return Ok(Type::Path(ty)); - } else { - *group.elem = Type::Path(ty); - } - } - } - return Ok(Type::Group(group)); - } - - let mut lifetimes = None::<BoundLifetimes>; - let mut lookahead = input.lookahead1(); - if lookahead.peek(Token![for]) { - lifetimes = input.parse()?; - lookahead = input.lookahead1(); - if !lookahead.peek(Ident) - && !lookahead.peek(Token![fn]) - && !lookahead.peek(Token![unsafe]) - && !lookahead.peek(Token![extern]) - && !lookahead.peek(Token![super]) - && !lookahead.peek(Token![self]) - && !lookahead.peek(Token![Self]) - && !lookahead.peek(Token![crate]) - || input.peek(Token![dyn]) - { - return Err(lookahead.error()); - } - } - - if lookahead.peek(token::Paren) { - let content; - let paren_token = parenthesized!(content in input); - if content.is_empty() { - return Ok(Type::Tuple(TypeTuple { paren_token, elems: Punctuated::new() })); - } - if content.peek(Lifetime) { - return Ok(Type::Paren(TypeParen { - paren_token, - elem: Box::new(Type::TraitObject(content.parse()?)), - })); - } - if content.peek(Token![?]) { - return Ok(Type::TraitObject(TypeTraitObject { - dyn_token: None, - bounds: { - let mut bounds = Punctuated::new(); - bounds.push_value(TypeParamBound::Trait(TraitBound { - paren_token: Some(paren_token), - ..content.parse()? - })); - while let Some(plus) = input.parse()? { - bounds.push_punct(plus); - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = false; - TypeParamBound::parse_single( - input, - allow_precise_capture, - allow_const, - )? - }); - } - bounds - }, - })); - } - let mut first: Type = content.parse()?; - if content.peek(Token![,]) { - return Ok(Type::Tuple(TypeTuple { - paren_token, - elems: { - let mut elems = Punctuated::new(); - elems.push_value(first); - elems.push_punct(content.parse()?); - while !content.is_empty() { - elems.push_value(content.parse()?); - if content.is_empty() { - break; - } - elems.push_punct(content.parse()?); - } - elems - }, - })); - } - if allow_plus && input.peek(Token![+]) { - loop { - let first = match first { - Type::Path(TypePath { qself: None, path }) => { - TypeParamBound::Trait(TraitBound { - paren_token: Some(paren_token), - modifier: TraitBoundModifier::None, - lifetimes: None, - path, - }) - } - Type::TraitObject(TypeTraitObject { dyn_token: None, bounds }) => { - if bounds.len() > 1 || bounds.trailing_punct() { - first = - Type::TraitObject(TypeTraitObject { dyn_token: None, bounds }); - break; - } - match bounds.into_iter().next().unwrap() { - TypeParamBound::Trait(trait_bound) => { - TypeParamBound::Trait(TraitBound { - paren_token: Some(paren_token), - ..trait_bound - }) - } - other @ (TypeParamBound::Lifetime(_) - | TypeParamBound::PreciseCapture(_) - | TypeParamBound::Verbatim(_)) => other, - } - } - _ => break, - }; - return Ok(Type::TraitObject(TypeTraitObject { - dyn_token: None, - bounds: { - let mut bounds = Punctuated::new(); - bounds.push_value(first); - while let Some(plus) = input.parse()? { - bounds.push_punct(plus); - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = false; - TypeParamBound::parse_single( - input, - allow_precise_capture, - allow_const, - )? - }); - } - bounds - }, - })); - } - } - Ok(Type::Paren(TypeParen { paren_token, elem: Box::new(first) })) - } else if lookahead.peek(Token![fn]) - || lookahead.peek(Token![unsafe]) - || lookahead.peek(Token![extern]) - { - let mut bare_fn: TypeBareFn = input.parse()?; - bare_fn.lifetimes = lifetimes; - Ok(Type::BareFn(bare_fn)) - } else if cfg!(feature = "full") - && token::parsing::peek_keyword(input.cursor(), "builtin") - && input.peek2(Token![#]) - { - token::parsing::keyword(input, "builtin")?; - input.parse::<Token![#]>()?; - input.parse::<Ident>()?; - let args; - parenthesized!(args in input); - args.parse::<TokenStream>()?; - Ok(Type::Verbatim(verbatim::between(begin, input.cursor()))) - } else if lookahead.peek(Ident) - || input.peek(Token![super]) - || input.peek(Token![self]) - || input.peek(Token![Self]) - || input.peek(Token![crate]) - || lookahead.peek(Token![::]) - || lookahead.peek(Token![<]) - { - let ty: TypePath = input.parse()?; - if ty.qself.is_some() { - return Ok(Type::Path(ty)); - } - - if input.peek(Token![!]) && !input.peek(Token![!=]) && ty.path.is_mod_style() { - let bang_token: Token![!] = input.parse()?; - let (delimiter, tokens) = mac::parse_delimiter(input)?; - return Ok(Type::Macro(TypeMacro { - mac: Macro { path: ty.path, bang_token, delimiter, tokens }, - })); - } - - if lifetimes.is_some() || allow_plus && input.peek(Token![+]) { - let mut bounds = Punctuated::new(); - bounds.push_value(TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes, - path: ty.path, - })); - if allow_plus { - while input.peek(Token![+]) { - bounds.push_punct(input.parse()?); - if !(input.peek(Ident::peek_any) - || input.peek(Token![::]) - || input.peek(Token![?]) - || input.peek(Lifetime) - || input.peek(token::Paren)) - { - break; - } - bounds.push_value({ - let allow_precise_capture = false; - let allow_const = false; - TypeParamBound::parse_single(input, allow_precise_capture, allow_const)? - }); - } - } - return Ok(Type::TraitObject(TypeTraitObject { dyn_token: None, bounds })); - } - - Ok(Type::Path(ty)) - } else if lookahead.peek(Token![dyn]) { - let dyn_token: Token![dyn] = input.parse()?; - let dyn_span = dyn_token.span; - let star_token: Option<Token![*]> = input.parse()?; - let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?; - Ok(if star_token.is_some() { - Type::Verbatim(verbatim::between(begin, input.cursor())) - } else { - Type::TraitObject(TypeTraitObject { dyn_token: Some(dyn_token), bounds }) - }) - } else if lookahead.peek(token::Bracket) { - let content; - let bracket_token = bracketed!(content in input); - let elem: Type = content.parse()?; - if content.peek(Token![;]) { - Ok(Type::Array(TypeArray { - bracket_token, - elem: Box::new(elem), - semi_token: content.parse()?, - len: content.parse()?, - })) - } else { - Ok(Type::Slice(TypeSlice { bracket_token, elem: Box::new(elem) })) - } - } else if lookahead.peek(Token![*]) { - input.parse().map(Type::Ptr) - } else if lookahead.peek(Token![&]) { - input.parse().map(Type::Reference) - } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) { - input.parse().map(Type::Never) - } else if lookahead.peek(Token![impl]) { - TypeImplTrait::parse(input, allow_plus).map(Type::ImplTrait) - } else if lookahead.peek(Token![_]) { - input.parse().map(Type::Infer) - } else if lookahead.peek(Lifetime) { - input.parse().map(Type::TraitObject) - } else { - Err(lookahead.error()) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeSlice { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(TypeSlice { bracket_token: bracketed!(content in input), elem: content.parse()? }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeArray { - fn parse(input: ParseStream) -> Result<Self> { - let content; - Ok(TypeArray { - bracket_token: bracketed!(content in input), - elem: content.parse()?, - semi_token: content.parse()?, - len: content.parse()?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypePtr { - fn parse(input: ParseStream) -> Result<Self> { - let star_token: Token![*] = input.parse()?; - - let lookahead = input.lookahead1(); - let (const_token, mutability) = if lookahead.peek(Token![const]) { - (Some(input.parse()?), None) - } else if lookahead.peek(Token![mut]) { - (None, Some(input.parse()?)) - } else { - return Err(lookahead.error()); - }; - - Ok(TypePtr { - star_token, - const_token, - mutability, - elem: Box::new(input.call(Type::without_plus)?), - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeReference { - fn parse(input: ParseStream) -> Result<Self> { - Ok(TypeReference { - and_token: input.parse()?, - lifetime: input.parse()?, - mutability: input.parse()?, - // & binds tighter than +, so we don't allow + here. - elem: Box::new(input.call(Type::without_plus)?), - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeBareFn { - fn parse(input: ParseStream) -> Result<Self> { - let args; - let mut variadic = None; - - Ok(TypeBareFn { - lifetimes: input.parse()?, - unsafety: input.parse()?, - abi: input.parse()?, - fn_token: input.parse()?, - paren_token: parenthesized!(args in input), - inputs: { - let mut inputs = Punctuated::new(); - - while !args.is_empty() { - let attrs = args.call(Attribute::parse_outer)?; - - if inputs.empty_or_trailing() - && (args.peek(Token![...]) - || (args.peek(Ident) || args.peek(Token![_])) - && args.peek2(Token![:]) - && args.peek3(Token![...])) - { - variadic = Some(parse_bare_variadic(&args, attrs)?); - break; - } - - let allow_self = inputs.is_empty(); - let arg = parse_bare_fn_arg(&args, allow_self)?; - inputs.push_value(BareFnArg { attrs, ..arg }); - if args.is_empty() { - break; - } - - let comma = args.parse()?; - inputs.push_punct(comma); - } - - inputs - }, - variadic, - output: input.call(ReturnType::without_plus)?, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeNever { - fn parse(input: ParseStream) -> Result<Self> { - Ok(TypeNever { bang_token: input.parse()? }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeInfer { - fn parse(input: ParseStream) -> Result<Self> { - Ok(TypeInfer { underscore_token: input.parse()? }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeTuple { - fn parse(input: ParseStream) -> Result<Self> { - let content; - let paren_token = parenthesized!(content in input); - - if content.is_empty() { - return Ok(TypeTuple { paren_token, elems: Punctuated::new() }); - } - - let first: Type = content.parse()?; - Ok(TypeTuple { - paren_token, - elems: { - let mut elems = Punctuated::new(); - elems.push_value(first); - elems.push_punct(content.parse()?); - while !content.is_empty() { - elems.push_value(content.parse()?); - if content.is_empty() { - break; - } - elems.push_punct(content.parse()?); - } - elems - }, - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeMacro { - fn parse(input: ParseStream) -> Result<Self> { - Ok(TypeMacro { mac: input.parse()? }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypePath { - fn parse(input: ParseStream) -> Result<Self> { - let expr_style = false; - let (qself, path) = path::parsing::qpath(input, expr_style)?; - Ok(TypePath { qself, path }) - } - } - - impl ReturnType { - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn without_plus(input: ParseStream) -> Result<Self> { - let allow_plus = false; - Self::parse(input, allow_plus) - } - - pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { - if input.peek(Token![->]) { - let arrow = input.parse()?; - let allow_group_generic = true; - let ty = ambig_ty(input, allow_plus, allow_group_generic)?; - Ok(ReturnType::Type(arrow, Box::new(ty))) - } else { - Ok(ReturnType::Default) - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for ReturnType { - fn parse(input: ParseStream) -> Result<Self> { - let allow_plus = true; - Self::parse(input, allow_plus) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeTraitObject { - fn parse(input: ParseStream) -> Result<Self> { - let allow_plus = true; - Self::parse(input, allow_plus) - } - } - - impl TypeTraitObject { - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn without_plus(input: ParseStream) -> Result<Self> { - let allow_plus = false; - Self::parse(input, allow_plus) - } - - // Only allow multiple trait references if allow_plus is true. - pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { - let dyn_token: Option<Token![dyn]> = input.parse()?; - let dyn_span = match &dyn_token { - Some(token) => token.span, - None => input.span(), - }; - let bounds = Self::parse_bounds(dyn_span, input, allow_plus)?; - Ok(TypeTraitObject { dyn_token, bounds }) - } - - fn parse_bounds( - dyn_span: Span, - input: ParseStream, - allow_plus: bool, - ) -> Result<Punctuated<TypeParamBound, Token![+]>> { - let allow_precise_capture = false; - let allow_const = false; - let bounds = TypeParamBound::parse_multiple( - input, - allow_plus, - allow_precise_capture, - allow_const, - )?; - let mut last_lifetime_span = None; - let mut at_least_one_trait = false; - for bound in &bounds { - match bound { - TypeParamBound::Trait(_) => { - at_least_one_trait = true; - break; - } - TypeParamBound::Lifetime(lifetime) => { - last_lifetime_span = Some(lifetime.ident.span()); - } - TypeParamBound::PreciseCapture(_) | TypeParamBound::Verbatim(_) => { - unreachable!() - } - } - } - // Just lifetimes like `'a + 'b` is not a TraitObject. - if !at_least_one_trait { - let msg = "at least one trait is required for an object type"; - return Err(error::new2(dyn_span, last_lifetime_span.unwrap(), msg)); - } - Ok(bounds) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeImplTrait { - fn parse(input: ParseStream) -> Result<Self> { - let allow_plus = true; - Self::parse(input, allow_plus) - } - } - - impl TypeImplTrait { - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - pub fn without_plus(input: ParseStream) -> Result<Self> { - let allow_plus = false; - Self::parse(input, allow_plus) - } - - pub(crate) fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { - let impl_token: Token![impl] = input.parse()?; - let allow_precise_capture = true; - let allow_const = true; - let bounds = TypeParamBound::parse_multiple( - input, - allow_plus, - allow_precise_capture, - allow_const, - )?; - let mut last_nontrait_span = None; - let mut at_least_one_trait = false; - for bound in &bounds { - match bound { - TypeParamBound::Trait(_) => { - at_least_one_trait = true; - break; - } - TypeParamBound::Lifetime(lifetime) => { - last_nontrait_span = Some(lifetime.ident.span()); - } - TypeParamBound::PreciseCapture(precise_capture) => { - #[cfg(feature = "full")] - { - last_nontrait_span = Some(precise_capture.gt_token.span); - } - #[cfg(not(feature = "full"))] - { - _ = precise_capture; - unreachable!(); - } - } - TypeParamBound::Verbatim(_) => { - // `[const] Trait` - at_least_one_trait = true; - break; - } - } - } - if !at_least_one_trait { - let msg = "at least one trait must be specified"; - return Err(error::new2(impl_token.span, last_nontrait_span.unwrap(), msg)); - } - Ok(TypeImplTrait { impl_token, bounds }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeGroup { - fn parse(input: ParseStream) -> Result<Self> { - let group = crate::group::parse_group(input)?; - Ok(TypeGroup { group_token: group.token, elem: group.content.parse()? }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for TypeParen { - fn parse(input: ParseStream) -> Result<Self> { - let allow_plus = false; - Self::parse(input, allow_plus) - } - } - - impl TypeParen { - fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { - let content; - Ok(TypeParen { - paren_token: parenthesized!(content in input), - elem: Box::new({ - let allow_group_generic = true; - ambig_ty(&content, allow_plus, allow_group_generic)? - }), - }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for BareFnArg { - fn parse(input: ParseStream) -> Result<Self> { - let allow_self = false; - parse_bare_fn_arg(input, allow_self) - } - } - - fn parse_bare_fn_arg(input: ParseStream, allow_self: bool) -> Result<BareFnArg> { - let attrs = input.call(Attribute::parse_outer)?; - - let begin = input.cursor(); - - let has_mut_self = allow_self && input.peek(Token![mut]) && input.peek2(Token![self]); - if has_mut_self { - input.parse::<Token![mut]>()?; - } - - let mut has_self = false; - let mut name = if (input.peek(Ident) || input.peek(Token![_]) || { - has_self = allow_self && input.peek(Token![self]); - has_self - }) && input.peek2(Token![:]) - && !input.peek2(Token![::]) - { - let name = input.call(Ident::parse_any)?; - let colon: Token![:] = input.parse()?; - Some((name, colon)) - } else { - has_self = false; - None - }; - - let ty = if allow_self && !has_self && input.peek(Token![mut]) && input.peek2(Token![self]) - { - input.parse::<Token![mut]>()?; - input.parse::<Token![self]>()?; - None - } else if has_mut_self && name.is_none() { - input.parse::<Token![self]>()?; - None - } else { - Some(input.parse()?) - }; - - let ty = match ty { - Some(ty) if !has_mut_self => ty, - _ => { - name = None; - Type::Verbatim(verbatim::between(begin, input.cursor())) - } - }; - - Ok(BareFnArg { attrs, name, ty }) - } - - fn parse_bare_variadic(input: ParseStream, attrs: Vec<Attribute>) -> Result<BareVariadic> { - Ok(BareVariadic { - attrs, - name: if input.peek(Ident) || input.peek(Token![_]) { - let name = input.call(Ident::parse_any)?; - let colon: Token![:] = input.parse()?; - Some((name, colon)) - } else { - None - }, - dots: input.parse()?, - comma: input.parse()?, - }) - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Abi { - fn parse(input: ParseStream) -> Result<Self> { - Ok(Abi { extern_token: input.parse()?, name: input.parse()? }) - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] - impl Parse for Option<Abi> { - fn parse(input: ParseStream) -> Result<Self> { - if input.peek(Token![extern]) { - input.parse().map(Some) - } else { - Ok(None) - } - } - } -} - -#[cfg(feature = "printing")] -mod printing { - use crate::attr::FilterAttrs; - use crate::path; - use crate::path::printing::PathStyle; - use crate::print::TokensOrDefault; - use crate::ty::{ - Abi, BareFnArg, BareVariadic, ReturnType, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, - TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, - TypeTraitObject, TypeTuple, - }; - use proc_macro2::TokenStream; - use quote::{ToTokens, TokenStreamExt as _}; - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeSlice { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.bracket_token.surround(tokens, |tokens| { - self.elem.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeArray { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.bracket_token.surround(tokens, |tokens| { - self.elem.to_tokens(tokens); - self.semi_token.to_tokens(tokens); - self.len.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypePtr { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.star_token.to_tokens(tokens); - match &self.mutability { - Some(tok) => tok.to_tokens(tokens), - None => { - TokensOrDefault(&self.const_token).to_tokens(tokens); - } - } - self.elem.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeReference { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.and_token.to_tokens(tokens); - self.lifetime.to_tokens(tokens); - self.mutability.to_tokens(tokens); - self.elem.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeBareFn { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.lifetimes.to_tokens(tokens); - self.unsafety.to_tokens(tokens); - self.abi.to_tokens(tokens); - self.fn_token.to_tokens(tokens); - self.paren_token.surround(tokens, |tokens| { - self.inputs.to_tokens(tokens); - if let Some(variadic) = &self.variadic { - if !self.inputs.empty_or_trailing() { - let span = variadic.dots.spans[0]; - Token![,](span).to_tokens(tokens); - } - variadic.to_tokens(tokens); - } - }); - self.output.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeNever { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.bang_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeTuple { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.paren_token.surround(tokens, |tokens| { - self.elems.to_tokens(tokens); - // If we only have one argument, we need a trailing comma to - // distinguish TypeTuple from TypeParen. - if self.elems.len() == 1 && !self.elems.trailing_punct() { - <Token![,]>::default().to_tokens(tokens); - } - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypePath { - fn to_tokens(&self, tokens: &mut TokenStream) { - path::printing::print_qpath(tokens, &self.qself, &self.path, PathStyle::AsWritten); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeTraitObject { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.dyn_token.to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeImplTrait { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.impl_token.to_tokens(tokens); - self.bounds.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeGroup { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.group_token.surround(tokens, |tokens| { - self.elem.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeParen { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.paren_token.surround(tokens, |tokens| { - self.elem.to_tokens(tokens); - }); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeInfer { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.underscore_token.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for TypeMacro { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.mac.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for ReturnType { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - ReturnType::Default => {} - ReturnType::Type(arrow, ty) => { - arrow.to_tokens(tokens); - ty.to_tokens(tokens); - } - } - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for BareFnArg { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - if let Some((name, colon)) = &self.name { - name.to_tokens(tokens); - colon.to_tokens(tokens); - } - self.ty.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for BareVariadic { - fn to_tokens(&self, tokens: &mut TokenStream) { - tokens.append_all(self.attrs.outer()); - if let Some((name, colon)) = &self.name { - name.to_tokens(tokens); - colon.to_tokens(tokens); - } - self.dots.to_tokens(tokens); - self.comma.to_tokens(tokens); - } - } - - #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] - impl ToTokens for Abi { - fn to_tokens(&self, tokens: &mut TokenStream) { - self.extern_token.to_tokens(tokens); - self.name.to_tokens(tokens); - } - } -} diff --git a/deps/crates/vendor/syn-v2/src/verbatim.rs b/deps/crates/vendor/syn-v2/src/verbatim.rs deleted file mode 100644 index 7e16db396136..000000000000 --- a/deps/crates/vendor/syn-v2/src/verbatim.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::buffer::Cursor; -use crate::ext::TokenStreamExt as _; -use core::cmp::Ordering; -use proc_macro2::{Delimiter, TokenStream}; - -pub(crate) fn between(begin: Cursor, end: Cursor) -> TokenStream { - let mut cursor = begin; - assert!(crate::buffer::same_buffer(end, cursor)); - - let mut tokens = TokenStream::new(); - while cursor != end { - let (tt, next) = cursor.token_tree().unwrap(); - - if crate::buffer::cmp_assuming_same_buffer(end, next) == Ordering::Less { - // A syntax node can cross the boundary of a None-delimited group - // due to such groups being transparent to the parser in most cases. - // Any time this occurs the group is known to be semantically - // irrelevant. https://github.com/dtolnay/syn/issues/1235 - if let Some((inside, _span, after)) = cursor.group(Delimiter::None) { - assert!(next == after); - cursor = inside; - continue; - } else { - panic!("verbatim end must not be inside a delimited group"); - } - } - - tokens.append(tt); - cursor = next; - } - tokens -} diff --git a/deps/crates/vendor/syn-v2/src/whitespace.rs b/deps/crates/vendor/syn-v2/src/whitespace.rs deleted file mode 100644 index a50b5069a68b..000000000000 --- a/deps/crates/vendor/syn-v2/src/whitespace.rs +++ /dev/null @@ -1,65 +0,0 @@ -pub(crate) fn skip(mut s: &str) -> &str { - 'skip: while !s.is_empty() { - let byte = s.as_bytes()[0]; - if byte == b'/' { - if s.starts_with("//") - && (!s.starts_with("///") || s.starts_with("////")) - && !s.starts_with("//!") - { - if let Some(i) = s.find('\n') { - s = &s[i + 1..]; - continue; - } else { - return ""; - } - } else if s.starts_with("/**/") { - s = &s[4..]; - continue; - } else if s.starts_with("/*") - && (!s.starts_with("/**") || s.starts_with("/***")) - && !s.starts_with("/*!") - { - let mut depth = 0; - let bytes = s.as_bytes(); - let mut i = 0; - let upper = bytes.len() - 1; - while i < upper { - if bytes[i] == b'/' && bytes[i + 1] == b'*' { - depth += 1; - i += 1; // eat '*' - } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { - depth -= 1; - if depth == 0 { - s = &s[i + 2..]; - continue 'skip; - } - i += 1; // eat '/' - } - i += 1; - } - return s; - } - } - match byte { - b' ' | 0x09..=0x0D => { - s = &s[1..]; - continue; - } - b if b <= 0x7F => {} - _ => { - let ch = s.chars().next().unwrap(); - if is_whitespace(ch) { - s = &s[ch.len_utf8()..]; - continue; - } - } - } - return s; - } - s -} - -fn is_whitespace(ch: char) -> bool { - // Rust treats left-to-right mark and right-to-left mark as whitespace - ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}' -} diff --git a/deps/crates/vendor/syn-v2/tests/common/eq.rs b/deps/crates/vendor/syn-v2/tests/common/eq.rs deleted file mode 100644 index cd4b951beae6..000000000000 --- a/deps/crates/vendor/syn-v2/tests/common/eq.rs +++ /dev/null @@ -1,893 +0,0 @@ -#![allow(unused_macro_rules)] - -extern crate rustc_ast; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_span; -extern crate thin_vec; - -use rustc_ast::ast::AngleBracketedArg; -use rustc_ast::ast::AngleBracketedArgs; -use rustc_ast::ast::AnonConst; -use rustc_ast::ast::Arm; -use rustc_ast::ast::AsmMacro; -use rustc_ast::ast::AssignOpKind; -use rustc_ast::ast::AssocItemConstraint; -use rustc_ast::ast::AssocItemConstraintKind; -use rustc_ast::ast::AssocItemKind; -use rustc_ast::ast::AttrArgs; -use rustc_ast::ast::AttrId; -use rustc_ast::ast::AttrItem; -use rustc_ast::ast::AttrItemKind; -use rustc_ast::ast::AttrKind; -use rustc_ast::ast::AttrStyle; -use rustc_ast::ast::Attribute; -use rustc_ast::ast::BinOpKind; -use rustc_ast::ast::BindingMode; -use rustc_ast::ast::Block; -use rustc_ast::ast::BlockCheckMode; -use rustc_ast::ast::BorrowKind; -use rustc_ast::ast::BoundAsyncness; -use rustc_ast::ast::BoundConstness; -use rustc_ast::ast::BoundPolarity; -use rustc_ast::ast::ByRef; -use rustc_ast::ast::CaptureBy; -use rustc_ast::ast::Closure; -use rustc_ast::ast::ClosureBinder; -use rustc_ast::ast::Const; -use rustc_ast::ast::ConstBlockItem; -use rustc_ast::ast::ConstItem; -use rustc_ast::ast::ConstItemRhsKind; -use rustc_ast::ast::CoroutineKind; -use rustc_ast::ast::Crate; -use rustc_ast::ast::Defaultness; -use rustc_ast::ast::Delegation; -use rustc_ast::ast::DelegationMac; -use rustc_ast::ast::DelegationSource; -use rustc_ast::ast::DelegationSuffixes; -use rustc_ast::ast::DelimArgs; -use rustc_ast::ast::EarlyParsedAttribute; -use rustc_ast::ast::EiiDecl; -use rustc_ast::ast::EiiImpl; -use rustc_ast::ast::EnumDef; -use rustc_ast::ast::Expr; -use rustc_ast::ast::ExprField; -use rustc_ast::ast::ExprKind; -use rustc_ast::ast::Extern; -use rustc_ast::ast::FieldDef; -use rustc_ast::ast::FloatTy; -use rustc_ast::ast::Fn; -use rustc_ast::ast::FnContract; -use rustc_ast::ast::FnDecl; -use rustc_ast::ast::FnHeader; -use rustc_ast::ast::FnPtrTy; -use rustc_ast::ast::FnRetTy; -use rustc_ast::ast::FnSig; -use rustc_ast::ast::ForLoopKind; -use rustc_ast::ast::ForeignItemKind; -use rustc_ast::ast::ForeignMod; -use rustc_ast::ast::FormatAlignment; -use rustc_ast::ast::FormatArgPosition; -use rustc_ast::ast::FormatArgPositionKind; -use rustc_ast::ast::FormatArgs; -use rustc_ast::ast::FormatArgsPiece; -use rustc_ast::ast::FormatArgument; -use rustc_ast::ast::FormatArgumentKind; -use rustc_ast::ast::FormatArguments; -use rustc_ast::ast::FormatCount; -use rustc_ast::ast::FormatDebugHex; -use rustc_ast::ast::FormatOptions; -use rustc_ast::ast::FormatPlaceholder; -use rustc_ast::ast::FormatSign; -use rustc_ast::ast::FormatTrait; -use rustc_ast::ast::GenBlockKind; -use rustc_ast::ast::GenericArg; -use rustc_ast::ast::GenericArgs; -use rustc_ast::ast::GenericBound; -use rustc_ast::ast::GenericParam; -use rustc_ast::ast::GenericParamKind; -use rustc_ast::ast::Generics; -use rustc_ast::ast::Guard; -use rustc_ast::ast::Impl; -use rustc_ast::ast::ImplPolarity; -use rustc_ast::ast::ImplRestriction; -use rustc_ast::ast::Inline; -use rustc_ast::ast::InlineAsm; -use rustc_ast::ast::InlineAsmOperand; -use rustc_ast::ast::InlineAsmOptions; -use rustc_ast::ast::InlineAsmRegOrRegClass; -use rustc_ast::ast::InlineAsmSym; -use rustc_ast::ast::InlineAsmTemplatePiece; -use rustc_ast::ast::IntTy; -use rustc_ast::ast::IsAuto; -use rustc_ast::ast::Item; -use rustc_ast::ast::ItemKind; -use rustc_ast::ast::Label; -use rustc_ast::ast::Lifetime; -use rustc_ast::ast::LitFloatType; -use rustc_ast::ast::LitIntType; -use rustc_ast::ast::LitKind; -use rustc_ast::ast::Local; -use rustc_ast::ast::LocalKind; -use rustc_ast::ast::MacCall; -use rustc_ast::ast::MacCallStmt; -use rustc_ast::ast::MacStmtStyle; -use rustc_ast::ast::MacroDef; -use rustc_ast::ast::MatchKind; -use rustc_ast::ast::MetaItem; -use rustc_ast::ast::MetaItemInner; -use rustc_ast::ast::MetaItemKind; -use rustc_ast::ast::MetaItemLit; -use rustc_ast::ast::MethodCall; -use rustc_ast::ast::ModKind; -use rustc_ast::ast::ModSpans; -use rustc_ast::ast::Movability; -use rustc_ast::ast::MutRestriction; -use rustc_ast::ast::MutTy; -use rustc_ast::ast::Mutability; -use rustc_ast::ast::NodeId; -use rustc_ast::ast::NormalAttr; -use rustc_ast::ast::Param; -use rustc_ast::ast::Parens; -use rustc_ast::ast::ParenthesizedArgs; -use rustc_ast::ast::Pat; -use rustc_ast::ast::PatField; -use rustc_ast::ast::PatFieldsRest; -use rustc_ast::ast::PatKind; -use rustc_ast::ast::Path; -use rustc_ast::ast::PathSegment; -use rustc_ast::ast::Pinnedness; -use rustc_ast::ast::PolyTraitRef; -use rustc_ast::ast::PreciseCapturingArg; -use rustc_ast::ast::QSelf; -use rustc_ast::ast::RangeEnd; -use rustc_ast::ast::RangeLimits; -use rustc_ast::ast::RangeSyntax; -use rustc_ast::ast::Recovered; -use rustc_ast::ast::RestrictionKind; -use rustc_ast::ast::Safety; -use rustc_ast::ast::StaticItem; -use rustc_ast::ast::Stmt; -use rustc_ast::ast::StmtKind; -use rustc_ast::ast::StrLit; -use rustc_ast::ast::StrStyle; -use rustc_ast::ast::StructExpr; -use rustc_ast::ast::StructRest; -use rustc_ast::ast::Term; -use rustc_ast::ast::Trait; -use rustc_ast::ast::TraitAlias; -use rustc_ast::ast::TraitBoundModifiers; -use rustc_ast::ast::TraitImplHeader; -use rustc_ast::ast::TraitObjectSyntax; -use rustc_ast::ast::TraitRef; -use rustc_ast::ast::Ty; -use rustc_ast::ast::TyAlias; -use rustc_ast::ast::TyKind; -use rustc_ast::ast::TyPat; -use rustc_ast::ast::TyPatKind; -use rustc_ast::ast::UintTy; -use rustc_ast::ast::UnOp; -use rustc_ast::ast::UnsafeBinderCastKind; -use rustc_ast::ast::UnsafeBinderTy; -use rustc_ast::ast::UnsafeSource; -use rustc_ast::ast::UseTree; -use rustc_ast::ast::UseTreeKind; -use rustc_ast::ast::Variant; -use rustc_ast::ast::VariantData; -use rustc_ast::ast::Visibility; -use rustc_ast::ast::VisibilityKind; -use rustc_ast::ast::WhereBoundPredicate; -use rustc_ast::ast::WhereClause; -use rustc_ast::ast::WhereEqPredicate; -use rustc_ast::ast::WherePredicate; -use rustc_ast::ast::WherePredicateKind; -use rustc_ast::ast::WhereRegionPredicate; -use rustc_ast::ast::YieldKind; -use rustc_ast::attr::data_structures::CfgEntry; -use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Lit, Token, TokenKind}; -use rustc_ast::tokenstream::{ - AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream, - Spacing, TokenStream, TokenTree, -}; -use rustc_data_structures::packed::Pu128; -use rustc_span::symbol::{sym, ByteSymbol, Ident, Symbol}; -use rustc_span::{ErrorGuaranteed, LocalExpnId, Span, Spanned, SyntaxContext, DUMMY_SP}; -use std::borrow::Cow; -use std::collections::HashMap; -use std::hash::{BuildHasher, Hash}; -use std::sync::Arc; -use thin_vec::ThinVec; - -pub trait SpanlessEq { - fn eq(&self, other: &Self) -> bool; -} - -impl<T: ?Sized + SpanlessEq> SpanlessEq for Box<T> { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&**self, &**other) - } -} - -impl<T: ?Sized + SpanlessEq> SpanlessEq for Arc<T> { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&**self, &**other) - } -} - -impl<T: SpanlessEq> SpanlessEq for Option<T> { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (None, None) => true, - (Some(this), Some(other)) => SpanlessEq::eq(this, other), - _ => false, - } - } -} - -impl<T: SpanlessEq, E: SpanlessEq> SpanlessEq for Result<T, E> { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Ok(this), Ok(other)) => SpanlessEq::eq(this, other), - (Err(this), Err(other)) => SpanlessEq::eq(this, other), - _ => false, - } - } -} - -impl<T: SpanlessEq> SpanlessEq for [T] { - fn eq(&self, other: &Self) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| SpanlessEq::eq(a, b)) - } -} - -impl<T: SpanlessEq> SpanlessEq for Vec<T> { - fn eq(&self, other: &Self) -> bool { - <[T] as SpanlessEq>::eq(self, other) - } -} - -impl<T: SpanlessEq> SpanlessEq for ThinVec<T> { - fn eq(&self, other: &Self) -> bool { - self.len() == other.len() - && self.iter().zip(other.iter()).all(|(a, b)| SpanlessEq::eq(a, b)) - } -} - -impl<K: Eq + Hash, V: SpanlessEq, S: BuildHasher> SpanlessEq for HashMap<K, V, S> { - fn eq(&self, other: &Self) -> bool { - self.len() == other.len() - && self.iter().all(|(key, this_v)| { - other.get(key).is_some_and(|other_v| SpanlessEq::eq(this_v, other_v)) - }) - } -} - -impl<'a, T: ?Sized + ToOwned + SpanlessEq> SpanlessEq for Cow<'a, T> { - fn eq(&self, other: &Self) -> bool { - <T as SpanlessEq>::eq(self, other) - } -} - -impl<T: SpanlessEq> SpanlessEq for Spanned<T> { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&self.node, &other.node) - } -} - -impl<A: SpanlessEq, B: SpanlessEq> SpanlessEq for (A, B) { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&self.0, &other.0) && SpanlessEq::eq(&self.1, &other.1) - } -} - -impl<A: SpanlessEq, B: SpanlessEq, C: SpanlessEq> SpanlessEq for (A, B, C) { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&self.0, &other.0) - && SpanlessEq::eq(&self.1, &other.1) - && SpanlessEq::eq(&self.2, &other.2) - } -} - -macro_rules! spanless_eq_true { - ($name:ty) => { - impl SpanlessEq for $name { - fn eq(&self, _other: &Self) -> bool { - true - } - } - }; -} - -spanless_eq_true!(Span); -spanless_eq_true!(DelimSpan); -spanless_eq_true!(AttrId); -spanless_eq_true!(NodeId); -spanless_eq_true!(SyntaxContext); -spanless_eq_true!(Spacing); -spanless_eq_true!(LocalExpnId); - -macro_rules! spanless_eq_partial_eq { - ($name:ty) => { - impl SpanlessEq for $name { - fn eq(&self, other: &Self) -> bool { - PartialEq::eq(self, other) - } - } - }; -} - -spanless_eq_partial_eq!(()); -spanless_eq_partial_eq!(bool); -spanless_eq_partial_eq!(u8); -spanless_eq_partial_eq!(u16); -spanless_eq_partial_eq!(u32); -spanless_eq_partial_eq!(u128); -spanless_eq_partial_eq!(usize); -spanless_eq_partial_eq!(char); -spanless_eq_partial_eq!(str); -spanless_eq_partial_eq!(String); -spanless_eq_partial_eq!(Pu128); -spanless_eq_partial_eq!(Symbol); -spanless_eq_partial_eq!(ByteSymbol); -spanless_eq_partial_eq!(CommentKind); -spanless_eq_partial_eq!(Delimiter); -spanless_eq_partial_eq!(InlineAsmOptions); -spanless_eq_partial_eq!(token::LitKind); -spanless_eq_partial_eq!(ErrorGuaranteed); -spanless_eq_partial_eq!(CfgEntry); - -macro_rules! spanless_eq_struct { - { - $($name:ident)::+ $(<$param:ident>)? - $([$field:tt $this:ident $other:ident])* - $(![$ignore:tt])*; - } => { - impl $(<$param: SpanlessEq>)* SpanlessEq for $($name)::+ $(<$param>)* { - fn eq(&self, other: &Self) -> bool { - let $($name)::+ { $($field: $this,)* $($ignore: _,)* } = self; - let $($name)::+ { $($field: $other,)* $($ignore: _,)* } = other; - true $(&& SpanlessEq::eq($this, $other))* - } - } - }; - - { - $($name:ident)::+ $(<$param:ident>)? - $([$field:tt $this:ident $other:ident])* - $(![$ignore:tt])*; - !$next:tt - $($rest:tt)* - } => { - spanless_eq_struct! { - $($name)::+ $(<$param>)* - $([$field $this $other])* - $(![$ignore])* - ![$next]; - $($rest)* - } - }; - - { - $($name:ident)::+ $(<$param:ident>)? - $([$field:tt $this:ident $other:ident])* - $(![$ignore:tt])*; - $next:tt - $($rest:tt)* - } => { - spanless_eq_struct! { - $($name)::+ $(<$param>)* - $([$field $this $other])* - [$next this other] - $(![$ignore])*; - $($rest)* - } - }; -} - -macro_rules! spanless_eq_enum { - { - $($name:ident)::+; - $([$($variant:ident)::+; $([$field:tt $this:ident $other:ident])* $(![$ignore:tt])*])* - } => { - impl SpanlessEq for $($name)::+ { - fn eq(&self, other: &Self) -> bool { - match self { - $( - $($variant)::+ { .. } => {} - )* - } - #[allow(unreachable_patterns)] - match (self, other) { - $( - ( - $($variant)::+ { $($field: $this,)* $($ignore: _,)* }, - $($variant)::+ { $($field: $other,)* $($ignore: _,)* }, - ) => { - true $(&& SpanlessEq::eq($this, $other))* - } - )* - _ => false, - } - } - } - }; - - { - $($name:ident)::+; - $([$($variant:ident)::+; $($fields:tt)*])* - $next:ident [$([$($named:tt)*])* $(![$ignore:tt])*] (!$i:tt $($field:tt)*) - $($rest:tt)* - } => { - spanless_eq_enum! { - $($name)::+; - $([$($variant)::+; $($fields)*])* - $next [$([$($named)*])* $(![$ignore])* ![$i]] ($($field)*) - $($rest)* - } - }; - - { - $($name:ident)::+; - $([$($variant:ident)::+; $($fields:tt)*])* - $next:ident [$([$($named:tt)*])* $(![$ignore:tt])*] ($i:tt $($field:tt)*) - $($rest:tt)* - } => { - spanless_eq_enum! { - $($name)::+; - $([$($variant)::+; $($fields)*])* - $next [$([$($named)*])* [$i this other] $(![$ignore])*] ($($field)*) - $($rest)* - } - }; - - { - $($name:ident)::+; - $([$($variant:ident)::+; $($fields:tt)*])* - $next:ident [$($named:tt)*] () - $($rest:tt)* - } => { - spanless_eq_enum! { - $($name)::+; - $([$($variant)::+; $($fields)*])* - [$($name)::+::$next; $($named)*] - $($rest)* - } - }; - - { - $($name:ident)::+; - $([$($variant:ident)::+; $($fields:tt)*])* - $next:ident ($($field:tt)*) - $($rest:tt)* - } => { - spanless_eq_enum! { - $($name)::+; - $([$($variant)::+; $($fields)*])* - $next [] ($($field)*) - $($rest)* - } - }; - - { - $($name:ident)::+; - $([$($variant:ident)::+; $($fields:tt)*])* - $next:ident - $($rest:tt)* - } => { - spanless_eq_enum! { - $($name)::+; - $([$($variant)::+; $($fields)*])* - [$($name)::+::$next;] - $($rest)* - } - }; -} - -spanless_eq_struct!(AngleBracketedArgs; span args); -spanless_eq_struct!(AnonConst; id value); -spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder); -spanless_eq_struct!(AssocItemConstraint; id ident gen_args kind span); -spanless_eq_struct!(AttrItem; unsafety path args); -spanless_eq_struct!(AttrTokenStream; 0); -spanless_eq_struct!(Attribute; kind id style span); -spanless_eq_struct!(AttrsTarget; attrs tokens); -spanless_eq_struct!(BindingMode; 0 1); -spanless_eq_struct!(Block; stmts id rules span); -spanless_eq_struct!(Closure; binder capture_clause constness coroutine_kind movability fn_decl body !fn_decl_span !fn_arg_span); -spanless_eq_struct!(ConstBlockItem; id span block); -spanless_eq_struct!(ConstItem; defaultness ident generics ty rhs_kind define_opaque); -spanless_eq_struct!(Crate; attrs items spans id is_placeholder); -spanless_eq_struct!(Delegation; id qself path ident rename body source); -spanless_eq_struct!(DelegationMac; qself prefix suffixes body); -spanless_eq_struct!(DelimArgs; dspan delim tokens); -spanless_eq_struct!(DelimSpacing; open close); -spanless_eq_struct!(EiiDecl; foreign_item impl_unsafe); -spanless_eq_struct!(EiiImpl; node_id eii_macro_path known_eii_macro_resolution impl_safety span inner_span is_default); -spanless_eq_struct!(EnumDef; variants); -spanless_eq_struct!(Expr; id kind span attrs !tokens); -spanless_eq_struct!(ExprField; attrs id span ident expr is_shorthand is_placeholder); -spanless_eq_struct!(FieldDef; attrs id span vis mut_restriction safety ident ty default is_placeholder); -spanless_eq_struct!(Fn; defaultness ident generics sig contract define_opaque body eii_impls); -spanless_eq_struct!(FnContract; declarations requires ensures); -spanless_eq_struct!(FnDecl; inputs output); -spanless_eq_struct!(FnHeader; constness coroutine_kind safety ext); -spanless_eq_struct!(FnPtrTy; safety ext generic_params decl decl_span); -spanless_eq_struct!(FnSig; header decl span); -spanless_eq_struct!(ForeignMod; extern_span safety abi items); -spanless_eq_struct!(FormatArgPosition; index kind span); -spanless_eq_struct!(FormatArgs; span template arguments uncooked_fmt_str is_source_literal); -spanless_eq_struct!(FormatArgument; kind expr); -spanless_eq_struct!(FormatOptions; width precision alignment fill sign alternate zero_pad debug_hex); -spanless_eq_struct!(FormatPlaceholder; argument span format_trait format_options); -spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind !colon_span); -spanless_eq_struct!(Generics; params where_clause span); -spanless_eq_struct!(Guard; cond span_with_leading_if); -spanless_eq_struct!(Impl; generics constness of_trait self_ty items); -spanless_eq_struct!(ImplRestriction; kind span); -spanless_eq_struct!(InlineAsm; asm_macro template template_strs operands clobber_abis options line_spans); -spanless_eq_struct!(InlineAsmSym; id qself path); -spanless_eq_struct!(Item<K>; attrs id span vis kind !tokens); -spanless_eq_struct!(Label; ident); -spanless_eq_struct!(Lifetime; id ident); -spanless_eq_struct!(Lit; kind symbol suffix); -spanless_eq_struct!(Local; id super_ pat ty kind span colon_sp attrs !tokens); -spanless_eq_struct!(MacCall; path args); -spanless_eq_struct!(MacCallStmt; mac style attrs tokens); -spanless_eq_struct!(MacroDef; body macro_rules eii_declaration); -spanless_eq_struct!(MetaItem; unsafety path kind span); -spanless_eq_struct!(MetaItemLit; symbol suffix kind span); -spanless_eq_struct!(MethodCall; seg receiver args !span); -spanless_eq_struct!(ModSpans; !inner_span !inject_use_span); -spanless_eq_struct!(MutRestriction; kind span); -spanless_eq_struct!(MutTy; ty mutbl); -spanless_eq_struct!(NormalAttr; item tokens); -spanless_eq_struct!(ParenthesizedArgs; span inputs inputs_span output); -spanless_eq_struct!(Pat; id kind span); -spanless_eq_struct!(PatField; ident pat is_shorthand attrs id span is_placeholder); -spanless_eq_struct!(Path; span segments); -spanless_eq_struct!(PathSegment; ident id args); -spanless_eq_struct!(PolyTraitRef; bound_generic_params modifiers trait_ref span parens); -spanless_eq_struct!(QSelf; ty path_span position); -spanless_eq_struct!(StaticItem; ident ty safety mutability expr define_opaque eii_impls); -spanless_eq_struct!(Stmt; id kind span); -spanless_eq_struct!(StrLit; symbol suffix symbol_unescaped style span); -spanless_eq_struct!(StructExpr; qself path fields rest); -spanless_eq_struct!(Token; kind span); -spanless_eq_struct!(Trait; constness safety is_auto impl_restriction ident generics bounds items); -spanless_eq_struct!(TraitAlias; constness ident generics bounds); -spanless_eq_struct!(TraitBoundModifiers; constness asyncness polarity); -spanless_eq_struct!(TraitImplHeader; defaultness safety polarity trait_ref); -spanless_eq_struct!(TraitRef; path ref_id); -spanless_eq_struct!(Ty; id kind span); -spanless_eq_struct!(TyAlias; defaultness ident generics after_where_clause bounds ty); -spanless_eq_struct!(TyPat; id kind span); -spanless_eq_struct!(UnsafeBinderTy; generic_params inner_ty); -spanless_eq_struct!(UseTree; prefix kind); -spanless_eq_struct!(Variant; attrs id span !vis ident data disr_expr is_placeholder); -spanless_eq_struct!(Visibility; kind span); -spanless_eq_struct!(WhereBoundPredicate; bound_generic_params bounded_ty bounds); -spanless_eq_struct!(WhereClause; has_where_token predicates span); -spanless_eq_struct!(WhereEqPredicate; lhs_ty rhs_ty); -spanless_eq_struct!(WherePredicate; attrs kind id span is_placeholder); -spanless_eq_struct!(WhereRegionPredicate; lifetime bounds); -spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0)); -spanless_eq_enum!(AsmMacro; Asm GlobalAsm NakedAsm); -spanless_eq_enum!(AssocItemConstraintKind; Equality(term) Bound(bounds)); -spanless_eq_enum!(AssocItemKind; Const(0) Fn(0) Type(0) MacCall(0) Delegation(0) DelegationMac(0)); -spanless_eq_enum!(AttrArgs; Empty Delimited(0) Eq(eq_span expr)); -spanless_eq_enum!(AttrItemKind; Parsed(0) Unparsed(0)); -spanless_eq_enum!(AttrStyle; Outer Inner); -spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2 3) AttrsTarget(0)); -spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt); -spanless_eq_enum!(BlockCheckMode; Default Unsafe(0)); -spanless_eq_enum!(BorrowKind; Ref Raw Pin); -spanless_eq_enum!(BoundAsyncness; Normal Async(0)); -spanless_eq_enum!(BoundConstness; Never Always(0) Maybe(0)); -spanless_eq_enum!(BoundPolarity; Positive Negative(0) Maybe(0)); -spanless_eq_enum!(ByRef; Yes(0 1) No); -spanless_eq_enum!(CaptureBy; Value(move_kw) Ref Use(use_kw)); -spanless_eq_enum!(ClosureBinder; NotPresent For(span generic_params)); -spanless_eq_enum!(Const; Yes(0) No); -spanless_eq_enum!(ConstItemRhsKind; Body(rhs) TypeConst(rhs)); -spanless_eq_enum!(Defaultness; Implicit Default(0) Final(0)); -spanless_eq_enum!(DelegationSource; Single List(0) Glob); -spanless_eq_enum!(DelegationSuffixes; List(0) Glob(0)); -spanless_eq_enum!(EarlyParsedAttribute; CfgTrace(0) CfgAttrTrace); -spanless_eq_enum!(Extern; None Implicit(0) Explicit(0 1)); -spanless_eq_enum!(FloatTy; F16 F32 F64 F128); -spanless_eq_enum!(FnRetTy; Default(0) Ty(0)); -spanless_eq_enum!(ForLoopKind; For ForAwait); -spanless_eq_enum!(ForeignItemKind; Static(0) Fn(0) TyAlias(0) MacCall(0)); -spanless_eq_enum!(FormatAlignment; Left Right Center); -spanless_eq_enum!(FormatArgPositionKind; Implicit Number Named); -spanless_eq_enum!(FormatArgsPiece; Literal(0) Placeholder(0)); -spanless_eq_enum!(FormatArgumentKind; Normal Named(0) Captured(0)); -spanless_eq_enum!(FormatCount; Literal(0) Argument(0)); -spanless_eq_enum!(FormatDebugHex; Lower Upper); -spanless_eq_enum!(FormatSign; Plus Minus); -spanless_eq_enum!(FormatTrait; Display Debug LowerExp UpperExp Octal Pointer Binary LowerHex UpperHex); -spanless_eq_enum!(GenBlockKind; Async Gen AsyncGen); -spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0)); -spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0) ParenthesizedElided(0)); -spanless_eq_enum!(GenericBound; Trait(0) Outlives(0) Use(0 1)); -spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty span default)); -spanless_eq_enum!(ImplPolarity; Positive Negative(0)); -spanless_eq_enum!(Inline; Yes No(had_parse_error)); -spanless_eq_enum!(InlineAsmRegOrRegClass; Reg(0) RegClass(0)); -spanless_eq_enum!(InlineAsmTemplatePiece; String(0) Placeholder(operand_idx modifier span)); -spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128); -spanless_eq_enum!(IsAuto; Yes No); -spanless_eq_enum!(LitFloatType; Suffixed(0) Unsuffixed); -spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed); -spanless_eq_enum!(LocalKind; Decl Init(0) InitElse(0 1)); -spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces); -spanless_eq_enum!(MatchKind; Prefix Postfix); -spanless_eq_enum!(MetaItemInner; MetaItem(0) Lit(0)); -spanless_eq_enum!(MetaItemKind; Word List(0) NameValue(0)); -spanless_eq_enum!(ModKind; Loaded(0 1 2) Unloaded); -spanless_eq_enum!(Movability; Static Movable); -spanless_eq_enum!(Mutability; Mut Not); -spanless_eq_enum!(Parens; Yes No); -spanless_eq_enum!(PatFieldsRest; Rest(0) Recovered(0) None); -spanless_eq_enum!(Pinnedness; Not Pinned); -spanless_eq_enum!(PreciseCapturingArg; Lifetime(0) Arg(0 1)); -spanless_eq_enum!(RangeEnd; Included(0) Excluded); -spanless_eq_enum!(RangeLimits; HalfOpen Closed); -spanless_eq_enum!(Recovered; No Yes(0)); -spanless_eq_enum!(RestrictionKind; Unrestricted Restricted(path id shorthand)); -spanless_eq_enum!(Safety; Unsafe(0) Safe(0) Default); -spanless_eq_enum!(StmtKind; Let(0) Item(0) Expr(0) Semi(0) Empty MacCall(0)); -spanless_eq_enum!(StrStyle; Cooked Raw(0)); -spanless_eq_enum!(StructRest; Base(0) Rest(0) None NoneWithError(0)); -spanless_eq_enum!(Term; Ty(0) Const(0)); -spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1 2 3)); -spanless_eq_enum!(TraitObjectSyntax; Dyn None); -spanless_eq_enum!(TyPatKind; Range(0 1 2) NotNull Or(0) Err(0)); -spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128); -spanless_eq_enum!(UnOp; Deref Not Neg); -spanless_eq_enum!(UnsafeBinderCastKind; Wrap Unwrap); -spanless_eq_enum!(UnsafeSource; CompilerGenerated UserProvided); -spanless_eq_enum!(UseTreeKind; Simple(0) Nested(items span) Glob(0)); -spanless_eq_enum!(VariantData; Struct(fields recovered) Tuple(0 1) Unit(0)); -spanless_eq_enum!(VisibilityKind; Public Restricted(path id shorthand) Inherited); -spanless_eq_enum!(WherePredicateKind; BoundPredicate(0) RegionPredicate(0)); -spanless_eq_enum!(YieldKind; Prefix(0) Postfix(0)); -spanless_eq_enum!(AssignOpKind; AddAssign SubAssign MulAssign DivAssign - RemAssign BitXorAssign BitAndAssign BitOrAssign ShlAssign ShrAssign); -spanless_eq_enum!(CoroutineKind; Async(span closure_id return_impl_trait_id) - Gen(span closure_id return_impl_trait_id) - AsyncGen(span closure_id return_impl_trait_id)); -spanless_eq_enum!(ExprKind; Array(0) ConstBlock(0) Call(0 1) MethodCall(0) - Tup(0) Binary(0 1 2) Unary(0 1) Move(0 1) Lit(0) Cast(0 1) Type(0 1) - Let(0 1 2 3) If(0 1 2) While(0 1 2) ForLoop(pat iter body label kind) - Loop(0 1 2) Match(0 1 2) Closure(0) Block(0 1) Gen(0 1 2 3) Await(0 1) - Use(0 1) TryBlock(0 1) Assign(0 1 2) AssignOp(0 1 2) Field(0 1) Index(0 1 2) - Underscore Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1) Continue(0) - Ret(0) InlineAsm(0) OffsetOf(0 1) MacCall(0) Struct(0) Repeat(0 1) Paren(0) - Try(0) Yield(0) Yeet(0) Become(0) IncludedBytes(0) FormatArgs(0) - UnsafeBinderCast(0 1 2) DirectConstArg(0) Err(0) Dummy); -spanless_eq_enum!(InlineAsmOperand; In(reg expr) Out(reg late expr) - InOut(reg late expr) SplitInOut(reg late in_expr out_expr) Const(anon_const) - Sym(sym) Label(block)); -spanless_eq_enum!(ItemKind; ExternCrate(0 1) Use(0) Static(0) Const(0) - ConstBlock(0) Fn(0) Mod(0 1 2) ForeignMod(0) GlobalAsm(0) TyAlias(0) - Enum(0 1 2) Struct(0 1 2) Union(0 1 2) Trait(0) TraitAlias(0) Impl(0) - MacCall(0) MacroDef(0 1) Delegation(0) DelegationMac(0)); -spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0 1) CStr(0 1) Byte(0) Char(0) - Int(0 1) Float(0 1) Bool(0) Err(0)); -spanless_eq_enum!(PatKind; Missing Wild Ident(0 1 2) Struct(0 1 2 3) - TupleStruct(0 1 2) Or(0) Path(0 1) Tuple(0) Box(0) Deref(0) Ref(0 1 2) - Expr(0) Range(0 1 2) Slice(0) Rest Never Guard(0 1) Paren(0) MacCall(0) - Err(0)); -spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Ref(0 1) PinnedRef(0 1) - FnPtr(0) UnsafeBinder(0) Never Tup(0) Path(0 1) TraitObject(0 1) - ImplTrait(0 1) Paren(0) Infer ImplicitSelf MacCall(0) CVarArgs Pat(0 1) - FieldOf(0 1 2) View(0 1) DirectConstArg(0) Dummy Err(0)); - -impl SpanlessEq for Ident { - fn eq(&self, other: &Self) -> bool { - self.as_str() == other.as_str() - } -} - -impl SpanlessEq for RangeSyntax { - fn eq(&self, _other: &Self) -> bool { - match self { - RangeSyntax::DotDotDot | RangeSyntax::DotDotEq => true, - } - } -} - -impl SpanlessEq for Param { - fn eq(&self, other: &Self) -> bool { - let Param { attrs, ty, pat, id, span: _, is_placeholder } = self; - let Param { - attrs: attrs2, - ty: ty2, - pat: pat2, - id: id2, - span: _, - is_placeholder: is_placeholder2, - } = other; - SpanlessEq::eq(id, id2) - && SpanlessEq::eq(is_placeholder, is_placeholder2) - && (matches!(ty.kind, TyKind::Err(_)) - || matches!(ty2.kind, TyKind::Err(_)) - || SpanlessEq::eq(attrs, attrs2) - && SpanlessEq::eq(ty, ty2) - && SpanlessEq::eq(pat, pat2)) - } -} - -impl SpanlessEq for TokenKind { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (TokenKind::Literal(this), TokenKind::Literal(other)) => SpanlessEq::eq(this, other), - (TokenKind::DotDotEq | TokenKind::DotDotDot, _) => match other { - TokenKind::DotDotEq | TokenKind::DotDotDot => true, - _ => false, - }, - _ => self == other, - } - } -} - -impl SpanlessEq for TokenStream { - fn eq(&self, other: &Self) -> bool { - let mut this_trees = self.iter(); - let mut other_trees = other.iter(); - loop { - let Some(this) = this_trees.next() else { - return other_trees.next().is_none(); - }; - let Some(other) = other_trees.next() else { - return false; - }; - if SpanlessEq::eq(this, other) { - continue; - } - if let (TokenTree::Token(this, _), TokenTree::Token(other, _)) = (this, other) { - if match (&this.kind, &other.kind) { - (TokenKind::Literal(this), TokenKind::Literal(other)) => { - SpanlessEq::eq(this, other) - } - (TokenKind::DocComment(_kind, style, symbol), TokenKind::Pound) => { - doc_comment(*style, *symbol, &mut other_trees) - } - (TokenKind::Pound, TokenKind::DocComment(_kind, style, symbol)) => { - doc_comment(*style, *symbol, &mut this_trees) - } - _ => false, - } { - continue; - } - } - return false; - } - } -} - -fn doc_comment<'a>( - style: AttrStyle, - unescaped: Symbol, - trees: &mut impl Iterator<Item = &'a TokenTree>, -) -> bool { - if match style { - AttrStyle::Outer => false, - AttrStyle::Inner => true, - } { - match trees.next() { - Some(TokenTree::Token(Token { kind: TokenKind::Bang, span: _ }, _spacing)) => {} - _ => return false, - } - } - let Some(TokenTree::Delimited(_span, _spacing, Delimiter::Bracket, stream)) = trees.next() - else { - return false; - }; - let mut trees = stream.iter(); - match trees.next() { - Some(TokenTree::Token( - Token { kind: TokenKind::Ident(symbol, IdentIsRaw::No), span: _ }, - _spacing, - )) if *symbol == sym::doc => {} - _ => return false, - } - match trees.next() { - Some(TokenTree::Token(Token { kind: TokenKind::Eq, span: _ }, _spacing)) => {} - _ => return false, - } - match trees.next() { - Some(TokenTree::Token(token, _spacing)) => { - is_escaped_literal_token(token, unescaped) && trees.next().is_none() - } - _ => false, - } -} - -fn is_escaped_literal_token(token: &Token, unescaped: Symbol) -> bool { - match token { - Token { kind: TokenKind::Literal(lit), span: _ } => { - match MetaItemLit::from_token_lit(*lit, DUMMY_SP) { - Ok(lit) => is_escaped_literal_meta_item_lit(&lit, unescaped), - Err(_) => false, - } - } - _ => false, - } -} - -fn is_escaped_literal_meta_item_lit(lit: &MetaItemLit, unescaped: Symbol) -> bool { - match lit { - MetaItemLit { symbol: _, suffix: None, kind, span: _ } => { - is_escaped_lit_kind(kind, unescaped) - } - _ => false, - } -} - -fn is_escaped_lit(lit: &Lit, unescaped: Symbol) -> bool { - match lit { - Lit { kind: token::LitKind::Str, symbol: _, suffix: None } => { - match LitKind::from_token_lit(*lit) { - Ok(lit_kind) => is_escaped_lit_kind(&lit_kind, unescaped), - _ => false, - } - } - _ => false, - } -} - -fn is_escaped_lit_kind(kind: &LitKind, unescaped: Symbol) -> bool { - match kind { - LitKind::Str(symbol, StrStyle::Cooked) => { - symbol.as_str().replace('\r', "") == unescaped.as_str().replace('\r', "") - } - _ => false, - } -} - -impl SpanlessEq for LazyAttrTokenStream { - fn eq(&self, other: &Self) -> bool { - let this = self.to_attr_token_stream(); - let other = other.to_attr_token_stream(); - SpanlessEq::eq(&this, &other) - } -} - -impl SpanlessEq for AttrKind { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (AttrKind::Normal(normal), AttrKind::Normal(normal2)) => { - SpanlessEq::eq(normal, normal2) - } - (AttrKind::DocComment(kind, symbol), AttrKind::DocComment(kind2, symbol2)) => { - SpanlessEq::eq(kind, kind2) && SpanlessEq::eq(symbol, symbol2) - } - (AttrKind::DocComment(kind, unescaped), AttrKind::Normal(normal2)) => { - match kind { - CommentKind::Line | CommentKind::Block => {} - } - let path = Path::from_ident(Ident::with_dummy_span(sym::doc)); - SpanlessEq::eq(&path, &normal2.item.path) - && match &normal2.item.args { - AttrItemKind::Parsed(_) - | AttrItemKind::Unparsed(AttrArgs::Empty | AttrArgs::Delimited(_)) => false, - AttrItemKind::Unparsed(AttrArgs::Eq { eq_span: _, expr }) => { - match &expr.kind { - ExprKind::Lit(lit) => is_escaped_lit(lit, *unescaped), - _ => false, - } - } - } - } - (AttrKind::Normal(_), AttrKind::DocComment(..)) => SpanlessEq::eq(other, self), - } - } -} - -impl SpanlessEq for FormatArguments { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(self.all_args(), other.all_args()) - } -} diff --git a/deps/crates/vendor/syn-v2/tests/common/mod.rs b/deps/crates/vendor/syn-v2/tests/common/mod.rs deleted file mode 100644 index ead830f81165..000000000000 --- a/deps/crates/vendor/syn-v2/tests/common/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![allow(dead_code)] -#![allow(clippy::module_name_repetitions, clippy::shadow_unrelated)] - -pub mod eq; -pub mod parse; -pub mod visit; diff --git a/deps/crates/vendor/syn-v2/tests/common/parse.rs b/deps/crates/vendor/syn-v2/tests/common/parse.rs deleted file mode 100644 index 75217e1b5735..000000000000 --- a/deps/crates/vendor/syn-v2/tests/common/parse.rs +++ /dev/null @@ -1,51 +0,0 @@ -extern crate rustc_ast; -extern crate rustc_driver; -extern crate rustc_expand; -extern crate rustc_parse; -extern crate rustc_session; -extern crate rustc_span; - -use rustc_ast::ast; -use rustc_parse::lexer::StripTokens; -use rustc_session::parse::ParseSess; -use rustc_span::FileName; -use std::panic; - -pub fn librustc_expr(input: &str) -> Option<Box<ast::Expr>> { - match panic::catch_unwind(|| { - let sess = ParseSess::new(); - let name = FileName::Custom("test_precedence".to_string()); - let mut parser = rustc_parse::new_parser_from_source_str( - &sess, - name, - input.to_string(), - StripTokens::ShebangAndFrontmatter, - ) - .unwrap(); - let presult = parser.parse_expr(); - match presult { - Ok(expr) => Some(expr), - Err(diagnostic) => { - diagnostic.emit(); - None - } - } - }) { - Ok(Some(e)) => Some(e), - Ok(None) => None, - Err(_) => { - errorf!("librustc panicked\n"); - None - } - } -} - -pub fn syn_expr(input: &str) -> Option<syn::Expr> { - match syn::parse_str(input) { - Ok(e) => Some(e), - Err(msg) => { - errorf!("syn failed to parse\n{:?}\n", msg); - None - } - } -} diff --git a/deps/crates/vendor/syn-v2/tests/common/visit.rs b/deps/crates/vendor/syn-v2/tests/common/visit.rs deleted file mode 100644 index 2d2a6c5382d5..000000000000 --- a/deps/crates/vendor/syn-v2/tests/common/visit.rs +++ /dev/null @@ -1,119 +0,0 @@ -use proc_macro2::{Delimiter, Group, TokenStream, TokenTree}; -use std::mem; -use syn::visit_mut::{self, VisitMut}; -use syn::{Expr, File, Generics, LifetimeParam, MacroDelimiter, Stmt, StmtMacro, TypeParam}; - -pub struct FlattenParens { - discard_paren_attrs: bool, -} - -impl FlattenParens { - pub fn discard_attrs() -> Self { - FlattenParens { - discard_paren_attrs: true, - } - } - - pub fn combine_attrs() -> Self { - FlattenParens { - discard_paren_attrs: false, - } - } - - pub fn visit_token_stream_mut(tokens: &mut TokenStream) { - *tokens = mem::take(tokens) - .into_iter() - .flat_map(|tt| { - if let TokenTree::Group(group) = tt { - let delimiter = group.delimiter(); - let mut content = group.stream(); - Self::visit_token_stream_mut(&mut content); - if let Delimiter::Parenthesis = delimiter { - content - } else { - TokenStream::from(TokenTree::Group(Group::new(delimiter, content))) - } - } else { - TokenStream::from(tt) - } - }) - .collect(); - } -} - -impl VisitMut for FlattenParens { - fn visit_expr_mut(&mut self, e: &mut Expr) { - while let Expr::Paren(paren) = e { - let paren_attrs = mem::take(&mut paren.attrs); - *e = mem::replace(&mut *paren.expr, Expr::PLACEHOLDER); - if !paren_attrs.is_empty() && !self.discard_paren_attrs { - let nested_attrs = match e { - Expr::Assign(e) => &mut e.attrs, - Expr::Binary(e) => &mut e.attrs, - Expr::Cast(e) => &mut e.attrs, - _ => unimplemented!(), - }; - assert!(nested_attrs.is_empty()); - *nested_attrs = paren_attrs; - } - } - visit_mut::visit_expr_mut(self, e); - } -} - -pub struct AsIfPrinted; - -impl VisitMut for AsIfPrinted { - fn visit_file_mut(&mut self, file: &mut File) { - file.shebang = None; - visit_mut::visit_file_mut(self, file); - } - - fn visit_generics_mut(&mut self, generics: &mut Generics) { - if generics.params.is_empty() { - generics.lt_token = None; - generics.gt_token = None; - } - if let Some(where_clause) = &generics.where_clause { - if where_clause.predicates.is_empty() { - generics.where_clause = None; - } - } - visit_mut::visit_generics_mut(self, generics); - } - - fn visit_lifetime_param_mut(&mut self, param: &mut LifetimeParam) { - if param.bounds.is_empty() { - param.colon_token = None; - } - visit_mut::visit_lifetime_param_mut(self, param); - } - - fn visit_stmt_mut(&mut self, stmt: &mut Stmt) { - if let Stmt::Expr(expr, semi) = stmt { - if let Expr::Macro(e) = expr { - if match e.mac.delimiter { - MacroDelimiter::Brace(_) => true, - MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => semi.is_some(), - } { - let Expr::Macro(expr) = mem::replace(expr, Expr::PLACEHOLDER) else { - unreachable!(); - }; - *stmt = Stmt::Macro(StmtMacro { - attrs: expr.attrs, - mac: expr.mac, - semi_token: *semi, - }); - } - } - } - visit_mut::visit_stmt_mut(self, stmt); - } - - fn visit_type_param_mut(&mut self, param: &mut TypeParam) { - if param.bounds.is_empty() { - param.colon_token = None; - } - visit_mut::visit_type_param_mut(self, param); - } -} diff --git a/deps/crates/vendor/syn-v2/tests/debug/gen.rs b/deps/crates/vendor/syn-v2/tests/debug/gen.rs deleted file mode 100644 index b74d3a6d86f9..000000000000 --- a/deps/crates/vendor/syn-v2/tests/debug/gen.rs +++ /dev/null @@ -1,5238 +0,0 @@ -// This file is @generated by syn-internal-codegen. -// It is not intended for manual editing. - -#![allow(clippy::match_wildcard_for_single_variants)] -use super::{Lite, Present}; -use core::fmt::{self, Debug, Display}; -use ref_cast::RefCast; -impl Debug for Lite<syn::Abi> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Abi"); - if let Some(val) = &self.value.name { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::LitStr); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("name", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::AngleBracketedGenericArguments> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("AngleBracketedGenericArguments"); - if self.value.colon2_token.is_some() { - formatter.field("colon2_token", &Present); - } - if !self.value.args.is_empty() { - formatter.field("args", Lite(&self.value.args)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Arm> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Arm"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("pat", Lite(&self.value.pat)); - if let Some(val) = &self.value.guard { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::If, Box<syn::Expr>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("guard", Print::ref_cast(val)); - } - formatter.field("body", Lite(&self.value.body)); - if self.value.comma.is_some() { - formatter.field("comma", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::AssocConst> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("AssocConst"); - formatter.field("ident", Lite(&self.value.ident)); - if let Some(val) = &self.value.generics { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::AngleBracketedGenericArguments); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("generics", Print::ref_cast(val)); - } - formatter.field("value", Lite(&self.value.value)); - formatter.finish() - } -} -impl Debug for Lite<syn::AssocType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("AssocType"); - formatter.field("ident", Lite(&self.value.ident)); - if let Some(val) = &self.value.generics { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::AngleBracketedGenericArguments); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("generics", Print::ref_cast(val)); - } - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::AttrStyle> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::AttrStyle::Outer => formatter.write_str("AttrStyle::Outer"), - syn::AttrStyle::Inner(_val) => { - formatter.write_str("AttrStyle::Inner")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::Attribute> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Attribute"); - formatter.field("style", Lite(&self.value.style)); - formatter.field("meta", Lite(&self.value.meta)); - formatter.finish() - } -} -impl Debug for Lite<syn::BareFnArg> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("BareFnArg"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.name { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((proc_macro2::Ident, syn::token::Colon)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("name", Print::ref_cast(val)); - } - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::BareVariadic> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("BareVariadic"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.name { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((proc_macro2::Ident, syn::token::Colon)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("name", Print::ref_cast(val)); - } - if self.value.comma.is_some() { - formatter.field("comma", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::BinOp> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::BinOp::Add(_val) => { - formatter.write_str("BinOp::Add")?; - Ok(()) - } - syn::BinOp::Sub(_val) => { - formatter.write_str("BinOp::Sub")?; - Ok(()) - } - syn::BinOp::Mul(_val) => { - formatter.write_str("BinOp::Mul")?; - Ok(()) - } - syn::BinOp::Div(_val) => { - formatter.write_str("BinOp::Div")?; - Ok(()) - } - syn::BinOp::Rem(_val) => { - formatter.write_str("BinOp::Rem")?; - Ok(()) - } - syn::BinOp::And(_val) => { - formatter.write_str("BinOp::And")?; - Ok(()) - } - syn::BinOp::Or(_val) => { - formatter.write_str("BinOp::Or")?; - Ok(()) - } - syn::BinOp::BitXor(_val) => { - formatter.write_str("BinOp::BitXor")?; - Ok(()) - } - syn::BinOp::BitAnd(_val) => { - formatter.write_str("BinOp::BitAnd")?; - Ok(()) - } - syn::BinOp::BitOr(_val) => { - formatter.write_str("BinOp::BitOr")?; - Ok(()) - } - syn::BinOp::Shl(_val) => { - formatter.write_str("BinOp::Shl")?; - Ok(()) - } - syn::BinOp::Shr(_val) => { - formatter.write_str("BinOp::Shr")?; - Ok(()) - } - syn::BinOp::Eq(_val) => { - formatter.write_str("BinOp::Eq")?; - Ok(()) - } - syn::BinOp::Lt(_val) => { - formatter.write_str("BinOp::Lt")?; - Ok(()) - } - syn::BinOp::Le(_val) => { - formatter.write_str("BinOp::Le")?; - Ok(()) - } - syn::BinOp::Ne(_val) => { - formatter.write_str("BinOp::Ne")?; - Ok(()) - } - syn::BinOp::Ge(_val) => { - formatter.write_str("BinOp::Ge")?; - Ok(()) - } - syn::BinOp::Gt(_val) => { - formatter.write_str("BinOp::Gt")?; - Ok(()) - } - syn::BinOp::AddAssign(_val) => { - formatter.write_str("BinOp::AddAssign")?; - Ok(()) - } - syn::BinOp::SubAssign(_val) => { - formatter.write_str("BinOp::SubAssign")?; - Ok(()) - } - syn::BinOp::MulAssign(_val) => { - formatter.write_str("BinOp::MulAssign")?; - Ok(()) - } - syn::BinOp::DivAssign(_val) => { - formatter.write_str("BinOp::DivAssign")?; - Ok(()) - } - syn::BinOp::RemAssign(_val) => { - formatter.write_str("BinOp::RemAssign")?; - Ok(()) - } - syn::BinOp::BitXorAssign(_val) => { - formatter.write_str("BinOp::BitXorAssign")?; - Ok(()) - } - syn::BinOp::BitAndAssign(_val) => { - formatter.write_str("BinOp::BitAndAssign")?; - Ok(()) - } - syn::BinOp::BitOrAssign(_val) => { - formatter.write_str("BinOp::BitOrAssign")?; - Ok(()) - } - syn::BinOp::ShlAssign(_val) => { - formatter.write_str("BinOp::ShlAssign")?; - Ok(()) - } - syn::BinOp::ShrAssign(_val) => { - formatter.write_str("BinOp::ShrAssign")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::Block> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Block"); - formatter.field("stmts", Lite(&self.value.stmts)); - formatter.finish() - } -} -impl Debug for Lite<syn::BoundLifetimes> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("BoundLifetimes"); - if !self.value.lifetimes.is_empty() { - formatter.field("lifetimes", Lite(&self.value.lifetimes)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::CapturedParam> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::CapturedParam::Lifetime(_val) => { - formatter.write_str("CapturedParam::Lifetime")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::CapturedParam::Ident(_val) => { - formatter.write_str("CapturedParam::Ident")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::ConstParam> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ConstParam"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("ty", Lite(&self.value.ty)); - if self.value.eq_token.is_some() { - formatter.field("eq_token", &Present); - } - if let Some(val) = &self.value.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Expr); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Constraint> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Constraint"); - formatter.field("ident", Lite(&self.value.ident)); - if let Some(val) = &self.value.generics { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::AngleBracketedGenericArguments); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("generics", Print::ref_cast(val)); - } - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Data> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Data::Struct(_val) => { - let mut formatter = formatter.debug_struct("Data::Struct"); - formatter.field("fields", Lite(&_val.fields)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::Data::Enum(_val) => { - let mut formatter = formatter.debug_struct("Data::Enum"); - if !_val.variants.is_empty() { - formatter.field("variants", Lite(&_val.variants)); - } - formatter.finish() - } - syn::Data::Union(_val) => { - let mut formatter = formatter.debug_struct("Data::Union"); - formatter.field("fields", Lite(&_val.fields)); - formatter.finish() - } - } - } -} -impl Debug for Lite<syn::DataEnum> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("DataEnum"); - if !self.value.variants.is_empty() { - formatter.field("variants", Lite(&self.value.variants)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::DataStruct> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("DataStruct"); - formatter.field("fields", Lite(&self.value.fields)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::DataUnion> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("DataUnion"); - formatter.field("fields", Lite(&self.value.fields)); - formatter.finish() - } -} -impl Debug for Lite<syn::DeriveInput> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("DeriveInput"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("data", Lite(&self.value.data)); - formatter.finish() - } -} -impl Debug for Lite<syn::Expr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Expr::Array(_val) => { - let mut formatter = formatter.debug_struct("Expr::Array"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if !_val.elems.is_empty() { - formatter.field("elems", Lite(&_val.elems)); - } - formatter.finish() - } - syn::Expr::Assign(_val) => { - let mut formatter = formatter.debug_struct("Expr::Assign"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("left", Lite(&_val.left)); - formatter.field("right", Lite(&_val.right)); - formatter.finish() - } - syn::Expr::Async(_val) => { - let mut formatter = formatter.debug_struct("Expr::Async"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.capture.is_some() { - formatter.field("capture", &Present); - } - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::Expr::Await(_val) => { - let mut formatter = formatter.debug_struct("Expr::Await"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("base", Lite(&_val.base)); - formatter.finish() - } - syn::Expr::Binary(_val) => { - let mut formatter = formatter.debug_struct("Expr::Binary"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("left", Lite(&_val.left)); - formatter.field("op", Lite(&_val.op)); - formatter.field("right", Lite(&_val.right)); - formatter.finish() - } - syn::Expr::Block(_val) => { - let mut formatter = formatter.debug_struct("Expr::Block"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::Expr::Break(_val) => { - let mut formatter = formatter.debug_struct("Expr::Break"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Lifetime); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - if let Some(val) = &_val.expr { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("expr", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Expr::Call(_val) => { - let mut formatter = formatter.debug_struct("Expr::Call"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("func", Lite(&_val.func)); - if !_val.args.is_empty() { - formatter.field("args", Lite(&_val.args)); - } - formatter.finish() - } - syn::Expr::Cast(_val) => { - let mut formatter = formatter.debug_struct("Expr::Cast"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.field("ty", Lite(&_val.ty)); - formatter.finish() - } - syn::Expr::Closure(_val) => { - let mut formatter = formatter.debug_struct("Expr::Closure"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.lifetimes { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BoundLifetimes); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetimes", Print::ref_cast(val)); - } - if _val.constness.is_some() { - formatter.field("constness", &Present); - } - if _val.movability.is_some() { - formatter.field("movability", &Present); - } - if _val.asyncness.is_some() { - formatter.field("asyncness", &Present); - } - if _val.capture.is_some() { - formatter.field("capture", &Present); - } - if !_val.inputs.is_empty() { - formatter.field("inputs", Lite(&_val.inputs)); - } - formatter.field("output", Lite(&_val.output)); - formatter.field("body", Lite(&_val.body)); - formatter.finish() - } - syn::Expr::Const(_val) => { - let mut formatter = formatter.debug_struct("Expr::Const"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::Expr::Continue(_val) => { - let mut formatter = formatter.debug_struct("Expr::Continue"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Lifetime); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Expr::Field(_val) => { - let mut formatter = formatter.debug_struct("Expr::Field"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("base", Lite(&_val.base)); - formatter.field("member", Lite(&_val.member)); - formatter.finish() - } - syn::Expr::ForLoop(_val) => { - let mut formatter = formatter.debug_struct("Expr::ForLoop"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("pat", Lite(&_val.pat)); - formatter.field("expr", Lite(&_val.expr)); - formatter.field("body", Lite(&_val.body)); - formatter.finish() - } - syn::Expr::Group(_val) => { - let mut formatter = formatter.debug_struct("Expr::Group"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::If(_val) => { - let mut formatter = formatter.debug_struct("Expr::If"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("cond", Lite(&_val.cond)); - formatter.field("then_branch", Lite(&_val.then_branch)); - if let Some(val) = &_val.else_branch { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Else, Box<syn::Expr>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("else_branch", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Expr::Index(_val) => { - let mut formatter = formatter.debug_struct("Expr::Index"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.field("index", Lite(&_val.index)); - formatter.finish() - } - syn::Expr::Infer(_val) => { - let mut formatter = formatter.debug_struct("Expr::Infer"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.finish() - } - syn::Expr::Let(_val) => { - let mut formatter = formatter.debug_struct("Expr::Let"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("pat", Lite(&_val.pat)); - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::Lit(_val) => { - let mut formatter = formatter.debug_struct("Expr::Lit"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("lit", Lite(&_val.lit)); - formatter.finish() - } - syn::Expr::Loop(_val) => { - let mut formatter = formatter.debug_struct("Expr::Loop"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("body", Lite(&_val.body)); - formatter.finish() - } - syn::Expr::Macro(_val) => { - let mut formatter = formatter.debug_struct("Expr::Macro"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("mac", Lite(&_val.mac)); - formatter.finish() - } - syn::Expr::Match(_val) => { - let mut formatter = formatter.debug_struct("Expr::Match"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - if !_val.arms.is_empty() { - formatter.field("arms", Lite(&_val.arms)); - } - formatter.finish() - } - syn::Expr::MethodCall(_val) => { - let mut formatter = formatter.debug_struct("Expr::MethodCall"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("receiver", Lite(&_val.receiver)); - formatter.field("method", Lite(&_val.method)); - if let Some(val) = &_val.turbofish { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::AngleBracketedGenericArguments); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("turbofish", Print::ref_cast(val)); - } - if !_val.args.is_empty() { - formatter.field("args", Lite(&_val.args)); - } - formatter.finish() - } - syn::Expr::Paren(_val) => { - let mut formatter = formatter.debug_struct("Expr::Paren"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::Path(_val) => { - let mut formatter = formatter.debug_struct("Expr::Path"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&_val.path)); - formatter.finish() - } - syn::Expr::Range(_val) => { - let mut formatter = formatter.debug_struct("Expr::Range"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.start { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("start", Print::ref_cast(val)); - } - formatter.field("limits", Lite(&_val.limits)); - if let Some(val) = &_val.end { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("end", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Expr::RawAddr(_val) => { - let mut formatter = formatter.debug_struct("Expr::RawAddr"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("mutability", Lite(&_val.mutability)); - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::Reference(_val) => { - let mut formatter = formatter.debug_struct("Expr::Reference"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::Repeat(_val) => { - let mut formatter = formatter.debug_struct("Expr::Repeat"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.field("len", Lite(&_val.len)); - formatter.finish() - } - syn::Expr::Return(_val) => { - let mut formatter = formatter.debug_struct("Expr::Return"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.expr { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("expr", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Expr::Struct(_val) => { - let mut formatter = formatter.debug_struct("Expr::Struct"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&_val.path)); - if !_val.fields.is_empty() { - formatter.field("fields", Lite(&_val.fields)); - } - if _val.dot2_token.is_some() { - formatter.field("dot2_token", &Present); - } - if let Some(val) = &_val.rest { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("rest", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Expr::Try(_val) => { - let mut formatter = formatter.debug_struct("Expr::Try"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::TryBlock(_val) => { - let mut formatter = formatter.debug_struct("Expr::TryBlock"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::Expr::Tuple(_val) => { - let mut formatter = formatter.debug_struct("Expr::Tuple"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if !_val.elems.is_empty() { - formatter.field("elems", Lite(&_val.elems)); - } - formatter.finish() - } - syn::Expr::Unary(_val) => { - let mut formatter = formatter.debug_struct("Expr::Unary"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("op", Lite(&_val.op)); - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Expr::Unsafe(_val) => { - let mut formatter = formatter.debug_struct("Expr::Unsafe"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::Expr::Verbatim(_val) => { - formatter.write_str("Expr::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - syn::Expr::While(_val) => { - let mut formatter = formatter.debug_struct("Expr::While"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("cond", Lite(&_val.cond)); - formatter.field("body", Lite(&_val.body)); - formatter.finish() - } - syn::Expr::Yield(_val) => { - let mut formatter = formatter.debug_struct("Expr::Yield"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.expr { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("expr", Print::ref_cast(val)); - } - formatter.finish() - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::ExprArray> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprArray"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if !self.value.elems.is_empty() { - formatter.field("elems", Lite(&self.value.elems)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprAssign> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprAssign"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("left", Lite(&self.value.left)); - formatter.field("right", Lite(&self.value.right)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprAsync> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprAsync"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.capture.is_some() { - formatter.field("capture", &Present); - } - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprAwait> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprAwait"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("base", Lite(&self.value.base)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprBinary> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprBinary"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("left", Lite(&self.value.left)); - formatter.field("op", Lite(&self.value.op)); - formatter.field("right", Lite(&self.value.right)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprBlock> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprBlock"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprBreak> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprBreak"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Lifetime); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - if let Some(val) = &self.value.expr { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("expr", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprCall> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprCall"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("func", Lite(&self.value.func)); - if !self.value.args.is_empty() { - formatter.field("args", Lite(&self.value.args)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprCast> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprCast"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprClosure> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprClosure"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.lifetimes { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BoundLifetimes); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetimes", Print::ref_cast(val)); - } - if self.value.constness.is_some() { - formatter.field("constness", &Present); - } - if self.value.movability.is_some() { - formatter.field("movability", &Present); - } - if self.value.asyncness.is_some() { - formatter.field("asyncness", &Present); - } - if self.value.capture.is_some() { - formatter.field("capture", &Present); - } - if !self.value.inputs.is_empty() { - formatter.field("inputs", Lite(&self.value.inputs)); - } - formatter.field("output", Lite(&self.value.output)); - formatter.field("body", Lite(&self.value.body)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprConst> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprConst"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprContinue> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprContinue"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Lifetime); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprField> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprField"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("base", Lite(&self.value.base)); - formatter.field("member", Lite(&self.value.member)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprForLoop> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprForLoop"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("pat", Lite(&self.value.pat)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.field("body", Lite(&self.value.body)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprGroup> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprGroup"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprIf> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprIf"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("cond", Lite(&self.value.cond)); - formatter.field("then_branch", Lite(&self.value.then_branch)); - if let Some(val) = &self.value.else_branch { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Else, Box<syn::Expr>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("else_branch", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprIndex> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprIndex"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.field("index", Lite(&self.value.index)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprInfer> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprInfer"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprLet> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprLet"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("pat", Lite(&self.value.pat)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprLit> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprLit"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("lit", Lite(&self.value.lit)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprLoop> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprLoop"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("body", Lite(&self.value.body)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprMacro"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("mac", Lite(&self.value.mac)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprMatch> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprMatch"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - if !self.value.arms.is_empty() { - formatter.field("arms", Lite(&self.value.arms)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprMethodCall> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprMethodCall"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("receiver", Lite(&self.value.receiver)); - formatter.field("method", Lite(&self.value.method)); - if let Some(val) = &self.value.turbofish { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::AngleBracketedGenericArguments); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("turbofish", Print::ref_cast(val)); - } - if !self.value.args.is_empty() { - formatter.field("args", Lite(&self.value.args)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprParen> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprParen"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprPath> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprPath"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&self.value.path)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprRange> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprRange"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.start { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("start", Print::ref_cast(val)); - } - formatter.field("limits", Lite(&self.value.limits)); - if let Some(val) = &self.value.end { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("end", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprRawAddr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprRawAddr"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("mutability", Lite(&self.value.mutability)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprReference> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprReference"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprRepeat> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprRepeat"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.field("len", Lite(&self.value.len)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprReturn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprReturn"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.expr { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("expr", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprStruct> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprStruct"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&self.value.path)); - if !self.value.fields.is_empty() { - formatter.field("fields", Lite(&self.value.fields)); - } - if self.value.dot2_token.is_some() { - formatter.field("dot2_token", &Present); - } - if let Some(val) = &self.value.rest { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("rest", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprTry> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprTry"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprTryBlock> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprTryBlock"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprTuple> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprTuple"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if !self.value.elems.is_empty() { - formatter.field("elems", Lite(&self.value.elems)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ExprUnary> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprUnary"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("op", Lite(&self.value.op)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprUnsafe> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprUnsafe"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprWhile> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprWhile"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.label { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Label); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("label", Print::ref_cast(val)); - } - formatter.field("cond", Lite(&self.value.cond)); - formatter.field("body", Lite(&self.value.body)); - formatter.finish() - } -} -impl Debug for Lite<syn::ExprYield> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ExprYield"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.expr { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Box<syn::Expr>); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("expr", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Field> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Field"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - match self.value.mutability { - syn::FieldMutability::None => {} - _ => { - formatter.field("mutability", Lite(&self.value.mutability)); - } - } - if let Some(val) = &self.value.ident { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(proc_macro2::Ident); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("ident", Print::ref_cast(val)); - } - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::FieldMutability> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::FieldMutability::None => formatter.write_str("FieldMutability::None"), - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::FieldPat> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("FieldPat"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("member", Lite(&self.value.member)); - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - formatter.field("pat", Lite(&self.value.pat)); - formatter.finish() - } -} -impl Debug for Lite<syn::FieldValue> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("FieldValue"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("member", Lite(&self.value.member)); - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::Fields> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Fields::Named(_val) => { - let mut formatter = formatter.debug_struct("Fields::Named"); - if !_val.named.is_empty() { - formatter.field("named", Lite(&_val.named)); - } - formatter.finish() - } - syn::Fields::Unnamed(_val) => { - let mut formatter = formatter.debug_struct("Fields::Unnamed"); - if !_val.unnamed.is_empty() { - formatter.field("unnamed", Lite(&_val.unnamed)); - } - formatter.finish() - } - syn::Fields::Unit => formatter.write_str("Fields::Unit"), - } - } -} -impl Debug for Lite<syn::FieldsNamed> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("FieldsNamed"); - if !self.value.named.is_empty() { - formatter.field("named", Lite(&self.value.named)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::FieldsUnnamed> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("FieldsUnnamed"); - if !self.value.unnamed.is_empty() { - formatter.field("unnamed", Lite(&self.value.unnamed)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::File> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("File"); - if let Some(val) = &self.value.shebang { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(String); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("shebang", Print::ref_cast(val)); - } - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if !self.value.items.is_empty() { - formatter.field("items", Lite(&self.value.items)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::FnArg> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::FnArg::Receiver(_val) => { - formatter.write_str("FnArg::Receiver")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::FnArg::Typed(_val) => { - formatter.write_str("FnArg::Typed")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::ForeignItem> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::ForeignItem::Fn(_val) => { - let mut formatter = formatter.debug_struct("ForeignItem::Fn"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("sig", Lite(&_val.sig)); - formatter.finish() - } - syn::ForeignItem::Static(_val) => { - let mut formatter = formatter.debug_struct("ForeignItem::Static"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - match _val.mutability { - syn::StaticMutability::None => {} - _ => { - formatter.field("mutability", Lite(&_val.mutability)); - } - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("ty", Lite(&_val.ty)); - formatter.finish() - } - syn::ForeignItem::Type(_val) => { - let mut formatter = formatter.debug_struct("ForeignItem::Type"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.finish() - } - syn::ForeignItem::Macro(_val) => { - let mut formatter = formatter.debug_struct("ForeignItem::Macro"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("mac", Lite(&_val.mac)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::ForeignItem::Verbatim(_val) => { - formatter.write_str("ForeignItem::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::ForeignItemFn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ForeignItemFn"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("sig", Lite(&self.value.sig)); - formatter.finish() - } -} -impl Debug for Lite<syn::ForeignItemMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ForeignItemMacro"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("mac", Lite(&self.value.mac)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ForeignItemStatic> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ForeignItemStatic"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - match self.value.mutability { - syn::StaticMutability::None => {} - _ => { - formatter.field("mutability", Lite(&self.value.mutability)); - } - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::ForeignItemType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ForeignItemType"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.finish() - } -} -impl Debug for Lite<syn::GenericArgument> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::GenericArgument::Lifetime(_val) => { - formatter.write_str("GenericArgument::Lifetime")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericArgument::Type(_val) => { - formatter.write_str("GenericArgument::Type")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericArgument::Const(_val) => { - formatter.write_str("GenericArgument::Const")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericArgument::AssocType(_val) => { - formatter.write_str("GenericArgument::AssocType")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericArgument::AssocConst(_val) => { - formatter.write_str("GenericArgument::AssocConst")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericArgument::Constraint(_val) => { - formatter.write_str("GenericArgument::Constraint")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::GenericParam> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::GenericParam::Lifetime(_val) => { - formatter.write_str("GenericParam::Lifetime")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericParam::Type(_val) => { - formatter.write_str("GenericParam::Type")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::GenericParam::Const(_val) => { - formatter.write_str("GenericParam::Const")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::Generics> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Generics"); - if self.value.lt_token.is_some() { - formatter.field("lt_token", &Present); - } - if !self.value.params.is_empty() { - formatter.field("params", Lite(&self.value.params)); - } - if self.value.gt_token.is_some() { - formatter.field("gt_token", &Present); - } - if let Some(val) = &self.value.where_clause { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::WhereClause); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("where_clause", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ImplItem> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::ImplItem::Const(_val) => { - let mut formatter = formatter.debug_struct("ImplItem::Const"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - if _val.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("ty", Lite(&_val.ty)); - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::ImplItem::Fn(_val) => { - let mut formatter = formatter.debug_struct("ImplItem::Fn"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - if _val.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - formatter.field("sig", Lite(&_val.sig)); - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::ImplItem::Type(_val) => { - let mut formatter = formatter.debug_struct("ImplItem::Type"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - if _val.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("ty", Lite(&_val.ty)); - formatter.finish() - } - syn::ImplItem::Macro(_val) => { - let mut formatter = formatter.debug_struct("ImplItem::Macro"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("mac", Lite(&_val.mac)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::ImplItem::Verbatim(_val) => { - formatter.write_str("ImplItem::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::ImplItemConst> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ImplItemConst"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - if self.value.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ImplItemFn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ImplItemFn"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - if self.value.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - formatter.field("sig", Lite(&self.value.sig)); - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ImplItemMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ImplItemMacro"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("mac", Lite(&self.value.mac)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ImplItemType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ImplItemType"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - if self.value.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::ImplRestriction> { - fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { - unreachable!() - } -} -impl Debug for Lite<syn::Index> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Index"); - formatter.field("index", Lite(&self.value.index)); - formatter.finish() - } -} -impl Debug for Lite<syn::Item> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Item::Const(_val) => { - let mut formatter = formatter.debug_struct("Item::Const"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("ty", Lite(&_val.ty)); - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Item::Enum(_val) => { - let mut formatter = formatter.debug_struct("Item::Enum"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - if !_val.variants.is_empty() { - formatter.field("variants", Lite(&_val.variants)); - } - formatter.finish() - } - syn::Item::ExternCrate(_val) => { - let mut formatter = formatter.debug_struct("Item::ExternCrate"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - if let Some(val) = &_val.rename { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::As, proc_macro2::Ident)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("rename", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Item::Fn(_val) => { - let mut formatter = formatter.debug_struct("Item::Fn"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("sig", Lite(&_val.sig)); - formatter.field("block", Lite(&_val.block)); - formatter.finish() - } - syn::Item::ForeignMod(_val) => { - let mut formatter = formatter.debug_struct("Item::ForeignMod"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - formatter.field("abi", Lite(&_val.abi)); - if !_val.items.is_empty() { - formatter.field("items", Lite(&_val.items)); - } - formatter.finish() - } - syn::Item::Impl(_val) => { - let mut formatter = formatter.debug_struct("Item::Impl"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - if _val.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - formatter.field("generics", Lite(&_val.generics)); - if let Some(val) = &_val.trait_ { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((Option<syn::token::Not>, syn::Path, syn::token::For)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt( - &( - &super::Option { - present: self.0.0.is_some(), - }, - Lite(&self.0.1), - ), - formatter, - )?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("trait_", Print::ref_cast(val)); - } - formatter.field("self_ty", Lite(&_val.self_ty)); - if !_val.items.is_empty() { - formatter.field("items", Lite(&_val.items)); - } - formatter.finish() - } - syn::Item::Macro(_val) => { - let mut formatter = formatter.debug_struct("Item::Macro"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.ident { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(proc_macro2::Ident); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("ident", Print::ref_cast(val)); - } - formatter.field("mac", Lite(&_val.mac)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::Item::Mod(_val) => { - let mut formatter = formatter.debug_struct("Item::Mod"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - if _val.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - formatter.field("ident", Lite(&_val.ident)); - if let Some(val) = &_val.content { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Brace, Vec<syn::Item>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("content", Print::ref_cast(val)); - } - if _val.semi.is_some() { - formatter.field("semi", &Present); - } - formatter.finish() - } - syn::Item::Static(_val) => { - let mut formatter = formatter.debug_struct("Item::Static"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - match _val.mutability { - syn::StaticMutability::None => {} - _ => { - formatter.field("mutability", Lite(&_val.mutability)); - } - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("ty", Lite(&_val.ty)); - formatter.field("expr", Lite(&_val.expr)); - formatter.finish() - } - syn::Item::Struct(_val) => { - let mut formatter = formatter.debug_struct("Item::Struct"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("fields", Lite(&_val.fields)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::Item::Trait(_val) => { - let mut formatter = formatter.debug_struct("Item::Trait"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - if _val.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - if _val.auto_token.is_some() { - formatter.field("auto_token", &Present); - } - if let Some(val) = &_val.restriction { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::ImplRestriction); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("restriction", Print::ref_cast(val)); - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - if _val.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - if !_val.supertraits.is_empty() { - formatter.field("supertraits", Lite(&_val.supertraits)); - } - if !_val.items.is_empty() { - formatter.field("items", Lite(&_val.items)); - } - formatter.finish() - } - syn::Item::TraitAlias(_val) => { - let mut formatter = formatter.debug_struct("Item::TraitAlias"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - if !_val.bounds.is_empty() { - formatter.field("bounds", Lite(&_val.bounds)); - } - formatter.finish() - } - syn::Item::Type(_val) => { - let mut formatter = formatter.debug_struct("Item::Type"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("ty", Lite(&_val.ty)); - formatter.finish() - } - syn::Item::Union(_val) => { - let mut formatter = formatter.debug_struct("Item::Union"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("fields", Lite(&_val.fields)); - formatter.finish() - } - syn::Item::Use(_val) => { - let mut formatter = formatter.debug_struct("Item::Use"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("vis", Lite(&_val.vis)); - if _val.leading_colon.is_some() { - formatter.field("leading_colon", &Present); - } - formatter.field("tree", Lite(&_val.tree)); - formatter.finish() - } - syn::Item::Verbatim(_val) => { - formatter.write_str("Item::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::ItemConst> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemConst"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ItemEnum> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemEnum"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - if !self.value.variants.is_empty() { - formatter.field("variants", Lite(&self.value.variants)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemExternCrate> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemExternCrate"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - if let Some(val) = &self.value.rename { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::As, proc_macro2::Ident)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("rename", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemFn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemFn"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("sig", Lite(&self.value.sig)); - formatter.field("block", Lite(&self.value.block)); - formatter.finish() - } -} -impl Debug for Lite<syn::ItemForeignMod> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemForeignMod"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - formatter.field("abi", Lite(&self.value.abi)); - if !self.value.items.is_empty() { - formatter.field("items", Lite(&self.value.items)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemImpl> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemImpl"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.defaultness.is_some() { - formatter.field("defaultness", &Present); - } - if self.value.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - formatter.field("generics", Lite(&self.value.generics)); - if let Some(val) = &self.value.trait_ { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((Option<syn::token::Not>, syn::Path, syn::token::For)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt( - &( - &super::Option { - present: self.0.0.is_some(), - }, - Lite(&self.0.1), - ), - formatter, - )?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("trait_", Print::ref_cast(val)); - } - formatter.field("self_ty", Lite(&self.value.self_ty)); - if !self.value.items.is_empty() { - formatter.field("items", Lite(&self.value.items)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemMacro"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.ident { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(proc_macro2::Ident); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("ident", Print::ref_cast(val)); - } - formatter.field("mac", Lite(&self.value.mac)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemMod> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemMod"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - if self.value.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - formatter.field("ident", Lite(&self.value.ident)); - if let Some(val) = &self.value.content { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Brace, Vec<syn::Item>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("content", Print::ref_cast(val)); - } - if self.value.semi.is_some() { - formatter.field("semi", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemStatic> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemStatic"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - match self.value.mutability { - syn::StaticMutability::None => {} - _ => { - formatter.field("mutability", Lite(&self.value.mutability)); - } - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.field("expr", Lite(&self.value.expr)); - formatter.finish() - } -} -impl Debug for Lite<syn::ItemStruct> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemStruct"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("fields", Lite(&self.value.fields)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemTrait> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemTrait"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - if self.value.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - if self.value.auto_token.is_some() { - formatter.field("auto_token", &Present); - } - if let Some(val) = &self.value.restriction { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::ImplRestriction); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("restriction", Print::ref_cast(val)); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - if !self.value.supertraits.is_empty() { - formatter.field("supertraits", Lite(&self.value.supertraits)); - } - if !self.value.items.is_empty() { - formatter.field("items", Lite(&self.value.items)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemTraitAlias> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemTraitAlias"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::ItemType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemType"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::ItemUnion> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemUnion"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("fields", Lite(&self.value.fields)); - formatter.finish() - } -} -impl Debug for Lite<syn::ItemUse> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ItemUse"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("vis", Lite(&self.value.vis)); - if self.value.leading_colon.is_some() { - formatter.field("leading_colon", &Present); - } - formatter.field("tree", Lite(&self.value.tree)); - formatter.finish() - } -} -impl Debug for Lite<syn::Label> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Label"); - formatter.field("name", Lite(&self.value.name)); - formatter.finish() - } -} -impl Debug for Lite<syn::Lifetime> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Lifetime"); - formatter.field("ident", Lite(&self.value.ident)); - formatter.finish() - } -} -impl Debug for Lite<syn::LifetimeParam> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("LifetimeParam"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("lifetime", Lite(&self.value.lifetime)); - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Lit> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Lit::Str(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::ByteStr(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::CStr(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::Byte(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::Char(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::Int(_val) => write!(formatter, "{}", _val), - syn::Lit::Float(_val) => write!(formatter, "{}", _val), - syn::Lit::Bool(_val) => { - let mut formatter = formatter.debug_struct("Lit::Bool"); - formatter.field("value", Lite(&_val.value)); - formatter.finish() - } - syn::Lit::Verbatim(_val) => { - formatter.write_str("Lit::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::LitBool> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("LitBool"); - formatter.field("value", Lite(&self.value.value)); - formatter.finish() - } -} -impl Debug for Lite<syn::LitByte> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value.value()) - } -} -impl Debug for Lite<syn::LitByteStr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value.value()) - } -} -impl Debug for Lite<syn::LitCStr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value.value()) - } -} -impl Debug for Lite<syn::LitChar> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value.value()) - } -} -impl Debug for Lite<syn::LitFloat> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", self.value) - } -} -impl Debug for Lite<syn::LitInt> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", self.value) - } -} -impl Debug for Lite<syn::LitStr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value.value()) - } -} -impl Debug for Lite<syn::Local> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Local"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("pat", Lite(&self.value.pat)); - if let Some(val) = &self.value.init { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::LocalInit); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("init", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::LocalInit> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("LocalInit"); - formatter.field("expr", Lite(&self.value.expr)); - if let Some(val) = &self.value.diverge { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Else, Box<syn::Expr>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("diverge", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Macro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Macro"); - formatter.field("path", Lite(&self.value.path)); - formatter.field("delimiter", Lite(&self.value.delimiter)); - formatter.field("tokens", Lite(&self.value.tokens)); - formatter.finish() - } -} -impl Debug for Lite<syn::MacroDelimiter> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::MacroDelimiter::Paren(_val) => { - formatter.write_str("MacroDelimiter::Paren")?; - Ok(()) - } - syn::MacroDelimiter::Brace(_val) => { - formatter.write_str("MacroDelimiter::Brace")?; - Ok(()) - } - syn::MacroDelimiter::Bracket(_val) => { - formatter.write_str("MacroDelimiter::Bracket")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::Member> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Member::Named(_val) => { - formatter.write_str("Member::Named")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Member::Unnamed(_val) => { - formatter.write_str("Member::Unnamed")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::Meta> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Meta::Path(_val) => { - let mut formatter = formatter.debug_struct("Meta::Path"); - if _val.leading_colon.is_some() { - formatter.field("leading_colon", &Present); - } - if !_val.segments.is_empty() { - formatter.field("segments", Lite(&_val.segments)); - } - formatter.finish() - } - syn::Meta::List(_val) => { - let mut formatter = formatter.debug_struct("Meta::List"); - formatter.field("path", Lite(&_val.path)); - formatter.field("delimiter", Lite(&_val.delimiter)); - formatter.field("tokens", Lite(&_val.tokens)); - formatter.finish() - } - syn::Meta::NameValue(_val) => { - let mut formatter = formatter.debug_struct("Meta::NameValue"); - formatter.field("path", Lite(&_val.path)); - formatter.field("value", Lite(&_val.value)); - formatter.finish() - } - } - } -} -impl Debug for Lite<syn::MetaList> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("MetaList"); - formatter.field("path", Lite(&self.value.path)); - formatter.field("delimiter", Lite(&self.value.delimiter)); - formatter.field("tokens", Lite(&self.value.tokens)); - formatter.finish() - } -} -impl Debug for Lite<syn::MetaNameValue> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("MetaNameValue"); - formatter.field("path", Lite(&self.value.path)); - formatter.field("value", Lite(&self.value.value)); - formatter.finish() - } -} -impl Debug for Lite<syn::ParenthesizedGenericArguments> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("ParenthesizedGenericArguments"); - if !self.value.inputs.is_empty() { - formatter.field("inputs", Lite(&self.value.inputs)); - } - formatter.field("output", Lite(&self.value.output)); - formatter.finish() - } -} -impl Debug for Lite<syn::Pat> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Pat::Const(_val) => { - formatter.write_str("Pat::Const")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Pat::Ident(_val) => { - let mut formatter = formatter.debug_struct("Pat::Ident"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.by_ref.is_some() { - formatter.field("by_ref", &Present); - } - if _val.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("ident", Lite(&_val.ident)); - if let Some(val) = &_val.subpat { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::At, Box<syn::Pat>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("subpat", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Pat::Lit(_val) => { - formatter.write_str("Pat::Lit")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Pat::Macro(_val) => { - formatter.write_str("Pat::Macro")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Pat::Or(_val) => { - let mut formatter = formatter.debug_struct("Pat::Or"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.leading_vert.is_some() { - formatter.field("leading_vert", &Present); - } - if !_val.cases.is_empty() { - formatter.field("cases", Lite(&_val.cases)); - } - formatter.finish() - } - syn::Pat::Paren(_val) => { - let mut formatter = formatter.debug_struct("Pat::Paren"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("pat", Lite(&_val.pat)); - formatter.finish() - } - syn::Pat::Path(_val) => { - formatter.write_str("Pat::Path")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Pat::Range(_val) => { - formatter.write_str("Pat::Range")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Pat::Reference(_val) => { - let mut formatter = formatter.debug_struct("Pat::Reference"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if _val.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("pat", Lite(&_val.pat)); - formatter.finish() - } - syn::Pat::Rest(_val) => { - let mut formatter = formatter.debug_struct("Pat::Rest"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.finish() - } - syn::Pat::Slice(_val) => { - let mut formatter = formatter.debug_struct("Pat::Slice"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if !_val.elems.is_empty() { - formatter.field("elems", Lite(&_val.elems)); - } - formatter.finish() - } - syn::Pat::Struct(_val) => { - let mut formatter = formatter.debug_struct("Pat::Struct"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&_val.path)); - if !_val.fields.is_empty() { - formatter.field("fields", Lite(&_val.fields)); - } - if let Some(val) = &_val.rest { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::PatRest); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("rest", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Pat::Tuple(_val) => { - let mut formatter = formatter.debug_struct("Pat::Tuple"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if !_val.elems.is_empty() { - formatter.field("elems", Lite(&_val.elems)); - } - formatter.finish() - } - syn::Pat::TupleStruct(_val) => { - let mut formatter = formatter.debug_struct("Pat::TupleStruct"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - if let Some(val) = &_val.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&_val.path)); - if !_val.elems.is_empty() { - formatter.field("elems", Lite(&_val.elems)); - } - formatter.finish() - } - syn::Pat::Type(_val) => { - let mut formatter = formatter.debug_struct("Pat::Type"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("pat", Lite(&_val.pat)); - formatter.field("ty", Lite(&_val.ty)); - formatter.finish() - } - syn::Pat::Verbatim(_val) => { - formatter.write_str("Pat::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - syn::Pat::Wild(_val) => { - let mut formatter = formatter.debug_struct("Pat::Wild"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.finish() - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::PatIdent> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatIdent"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.by_ref.is_some() { - formatter.field("by_ref", &Present); - } - if self.value.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("ident", Lite(&self.value.ident)); - if let Some(val) = &self.value.subpat { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::At, Box<syn::Pat>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("subpat", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatOr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatOr"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.leading_vert.is_some() { - formatter.field("leading_vert", &Present); - } - if !self.value.cases.is_empty() { - formatter.field("cases", Lite(&self.value.cases)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatParen> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatParen"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("pat", Lite(&self.value.pat)); - formatter.finish() - } -} -impl Debug for Lite<syn::PatReference> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatReference"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if self.value.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("pat", Lite(&self.value.pat)); - formatter.finish() - } -} -impl Debug for Lite<syn::PatRest> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatRest"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatSlice> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatSlice"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if !self.value.elems.is_empty() { - formatter.field("elems", Lite(&self.value.elems)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatStruct> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatStruct"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&self.value.path)); - if !self.value.fields.is_empty() { - formatter.field("fields", Lite(&self.value.fields)); - } - if let Some(val) = &self.value.rest { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::PatRest); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("rest", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatTuple> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatTuple"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if !self.value.elems.is_empty() { - formatter.field("elems", Lite(&self.value.elems)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatTupleStruct> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatTupleStruct"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&self.value.path)); - if !self.value.elems.is_empty() { - formatter.field("elems", Lite(&self.value.elems)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PatType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatType"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("pat", Lite(&self.value.pat)); - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::PatWild> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PatWild"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Path> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Path"); - if self.value.leading_colon.is_some() { - formatter.field("leading_colon", &Present); - } - if !self.value.segments.is_empty() { - formatter.field("segments", Lite(&self.value.segments)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PathArguments> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::PathArguments::None => formatter.write_str("PathArguments::None"), - syn::PathArguments::AngleBracketed(_val) => { - let mut formatter = formatter - .debug_struct("PathArguments::AngleBracketed"); - if _val.colon2_token.is_some() { - formatter.field("colon2_token", &Present); - } - if !_val.args.is_empty() { - formatter.field("args", Lite(&_val.args)); - } - formatter.finish() - } - syn::PathArguments::Parenthesized(_val) => { - let mut formatter = formatter - .debug_struct("PathArguments::Parenthesized"); - if !_val.inputs.is_empty() { - formatter.field("inputs", Lite(&_val.inputs)); - } - formatter.field("output", Lite(&_val.output)); - formatter.finish() - } - } - } -} -impl Debug for Lite<syn::PathSegment> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PathSegment"); - formatter.field("ident", Lite(&self.value.ident)); - match self.value.arguments { - syn::PathArguments::None => {} - _ => { - formatter.field("arguments", Lite(&self.value.arguments)); - } - } - formatter.finish() - } -} -impl Debug for Lite<syn::PointerMutability> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::PointerMutability::Const(_val) => { - formatter.write_str("PointerMutability::Const")?; - Ok(()) - } - syn::PointerMutability::Mut(_val) => { - formatter.write_str("PointerMutability::Mut")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::PreciseCapture> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PreciseCapture"); - if !self.value.params.is_empty() { - formatter.field("params", Lite(&self.value.params)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PredicateLifetime> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PredicateLifetime"); - formatter.field("lifetime", Lite(&self.value.lifetime)); - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::PredicateType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("PredicateType"); - if let Some(val) = &self.value.lifetimes { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BoundLifetimes); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetimes", Print::ref_cast(val)); - } - formatter.field("bounded_ty", Lite(&self.value.bounded_ty)); - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::QSelf> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("QSelf"); - formatter.field("ty", Lite(&self.value.ty)); - formatter.field("position", Lite(&self.value.position)); - if self.value.as_token.is_some() { - formatter.field("as_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::RangeLimits> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::RangeLimits::HalfOpen(_val) => { - formatter.write_str("RangeLimits::HalfOpen")?; - Ok(()) - } - syn::RangeLimits::Closed(_val) => { - formatter.write_str("RangeLimits::Closed")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::Receiver> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Receiver"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.reference { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::And, Option<syn::Lifetime>)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt( - { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(Option<syn::Lifetime>); - impl Debug for Print { - fn fmt( - &self, - formatter: &mut fmt::Formatter, - ) -> fmt::Result { - match &self.0 { - Some(_val) => { - formatter.write_str("Some(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - None => formatter.write_str("None"), - } - } - } - Print::ref_cast(&self.0.1) - }, - formatter, - )?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("reference", Print::ref_cast(val)); - } - if self.value.mutability.is_some() { - formatter.field("mutability", &Present); - } - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - formatter.field("ty", Lite(&self.value.ty)); - formatter.finish() - } -} -impl Debug for Lite<syn::ReturnType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::ReturnType::Default => formatter.write_str("ReturnType::Default"), - syn::ReturnType::Type(_v0, _v1) => { - let mut formatter = formatter.debug_tuple("ReturnType::Type"); - formatter.field(Lite(_v1)); - formatter.finish() - } - } - } -} -impl Debug for Lite<syn::Signature> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Signature"); - if self.value.constness.is_some() { - formatter.field("constness", &Present); - } - if self.value.asyncness.is_some() { - formatter.field("asyncness", &Present); - } - if self.value.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - if let Some(val) = &self.value.abi { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Abi); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("abi", Print::ref_cast(val)); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - if !self.value.inputs.is_empty() { - formatter.field("inputs", Lite(&self.value.inputs)); - } - if let Some(val) = &self.value.variadic { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Variadic); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("variadic", Print::ref_cast(val)); - } - formatter.field("output", Lite(&self.value.output)); - formatter.finish() - } -} -impl Debug for Lite<syn::StaticMutability> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::StaticMutability::Mut(_val) => { - formatter.write_str("StaticMutability::Mut")?; - Ok(()) - } - syn::StaticMutability::None => formatter.write_str("StaticMutability::None"), - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::Stmt> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Stmt::Local(_val) => { - let mut formatter = formatter.debug_struct("Stmt::Local"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("pat", Lite(&_val.pat)); - if let Some(val) = &_val.init { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::LocalInit); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("init", Print::ref_cast(val)); - } - formatter.finish() - } - syn::Stmt::Item(_val) => { - formatter.write_str("Stmt::Item")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::Stmt::Expr(_v0, _v1) => { - let mut formatter = formatter.debug_tuple("Stmt::Expr"); - formatter.field(Lite(_v0)); - formatter - .field( - &super::Option { - present: _v1.is_some(), - }, - ); - formatter.finish() - } - syn::Stmt::Macro(_val) => { - let mut formatter = formatter.debug_struct("Stmt::Macro"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("mac", Lite(&_val.mac)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - } - } -} -impl Debug for Lite<syn::StmtMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("StmtMacro"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("mac", Lite(&self.value.mac)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TraitBound> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TraitBound"); - if self.value.paren_token.is_some() { - formatter.field("paren_token", &Present); - } - match self.value.modifier { - syn::TraitBoundModifier::None => {} - _ => { - formatter.field("modifier", Lite(&self.value.modifier)); - } - } - if let Some(val) = &self.value.lifetimes { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BoundLifetimes); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetimes", Print::ref_cast(val)); - } - formatter.field("path", Lite(&self.value.path)); - formatter.finish() - } -} -impl Debug for Lite<syn::TraitBoundModifier> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::TraitBoundModifier::None => { - formatter.write_str("TraitBoundModifier::None") - } - syn::TraitBoundModifier::Maybe(_val) => { - formatter.write_str("TraitBoundModifier::Maybe")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::TraitItem> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::TraitItem::Const(_val) => { - let mut formatter = formatter.debug_struct("TraitItem::Const"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - formatter.field("ty", Lite(&_val.ty)); - if let Some(val) = &_val.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Eq, syn::Expr)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - formatter.finish() - } - syn::TraitItem::Fn(_val) => { - let mut formatter = formatter.debug_struct("TraitItem::Fn"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("sig", Lite(&_val.sig)); - if let Some(val) = &_val.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Block); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::TraitItem::Type(_val) => { - let mut formatter = formatter.debug_struct("TraitItem::Type"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("ident", Lite(&_val.ident)); - formatter.field("generics", Lite(&_val.generics)); - if _val.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - if !_val.bounds.is_empty() { - formatter.field("bounds", Lite(&_val.bounds)); - } - if let Some(val) = &_val.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Eq, syn::Type)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - formatter.finish() - } - syn::TraitItem::Macro(_val) => { - let mut formatter = formatter.debug_struct("TraitItem::Macro"); - if !_val.attrs.is_empty() { - formatter.field("attrs", Lite(&_val.attrs)); - } - formatter.field("mac", Lite(&_val.mac)); - if _val.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } - syn::TraitItem::Verbatim(_val) => { - formatter.write_str("TraitItem::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::TraitItemConst> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TraitItemConst"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - formatter.field("ty", Lite(&self.value.ty)); - if let Some(val) = &self.value.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Eq, syn::Expr)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TraitItemFn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TraitItemFn"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("sig", Lite(&self.value.sig)); - if let Some(val) = &self.value.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Block); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TraitItemMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TraitItemMacro"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("mac", Lite(&self.value.mac)); - if self.value.semi_token.is_some() { - formatter.field("semi_token", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TraitItemType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TraitItemType"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("generics", Lite(&self.value.generics)); - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - if let Some(val) = &self.value.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Eq, syn::Type)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Type> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Type::Array(_val) => { - let mut formatter = formatter.debug_struct("Type::Array"); - formatter.field("elem", Lite(&_val.elem)); - formatter.field("len", Lite(&_val.len)); - formatter.finish() - } - syn::Type::BareFn(_val) => { - let mut formatter = formatter.debug_struct("Type::BareFn"); - if let Some(val) = &_val.lifetimes { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BoundLifetimes); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetimes", Print::ref_cast(val)); - } - if _val.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - if let Some(val) = &_val.abi { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Abi); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("abi", Print::ref_cast(val)); - } - if !_val.inputs.is_empty() { - formatter.field("inputs", Lite(&_val.inputs)); - } - if let Some(val) = &_val.variadic { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BareVariadic); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("variadic", Print::ref_cast(val)); - } - formatter.field("output", Lite(&_val.output)); - formatter.finish() - } - syn::Type::Group(_val) => { - let mut formatter = formatter.debug_struct("Type::Group"); - formatter.field("elem", Lite(&_val.elem)); - formatter.finish() - } - syn::Type::ImplTrait(_val) => { - let mut formatter = formatter.debug_struct("Type::ImplTrait"); - if !_val.bounds.is_empty() { - formatter.field("bounds", Lite(&_val.bounds)); - } - formatter.finish() - } - syn::Type::Infer(_val) => { - let mut formatter = formatter.debug_struct("Type::Infer"); - formatter.finish() - } - syn::Type::Macro(_val) => { - let mut formatter = formatter.debug_struct("Type::Macro"); - formatter.field("mac", Lite(&_val.mac)); - formatter.finish() - } - syn::Type::Never(_val) => { - let mut formatter = formatter.debug_struct("Type::Never"); - formatter.finish() - } - syn::Type::Paren(_val) => { - let mut formatter = formatter.debug_struct("Type::Paren"); - formatter.field("elem", Lite(&_val.elem)); - formatter.finish() - } - syn::Type::Path(_val) => { - let mut formatter = formatter.debug_struct("Type::Path"); - if let Some(val) = &_val.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&_val.path)); - formatter.finish() - } - syn::Type::Ptr(_val) => { - let mut formatter = formatter.debug_struct("Type::Ptr"); - if _val.const_token.is_some() { - formatter.field("const_token", &Present); - } - if _val.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("elem", Lite(&_val.elem)); - formatter.finish() - } - syn::Type::Reference(_val) => { - let mut formatter = formatter.debug_struct("Type::Reference"); - if let Some(val) = &_val.lifetime { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Lifetime); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetime", Print::ref_cast(val)); - } - if _val.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("elem", Lite(&_val.elem)); - formatter.finish() - } - syn::Type::Slice(_val) => { - let mut formatter = formatter.debug_struct("Type::Slice"); - formatter.field("elem", Lite(&_val.elem)); - formatter.finish() - } - syn::Type::TraitObject(_val) => { - let mut formatter = formatter.debug_struct("Type::TraitObject"); - if _val.dyn_token.is_some() { - formatter.field("dyn_token", &Present); - } - if !_val.bounds.is_empty() { - formatter.field("bounds", Lite(&_val.bounds)); - } - formatter.finish() - } - syn::Type::Tuple(_val) => { - let mut formatter = formatter.debug_struct("Type::Tuple"); - if !_val.elems.is_empty() { - formatter.field("elems", Lite(&_val.elems)); - } - formatter.finish() - } - syn::Type::Verbatim(_val) => { - formatter.write_str("Type::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::TypeArray> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeArray"); - formatter.field("elem", Lite(&self.value.elem)); - formatter.field("len", Lite(&self.value.len)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeBareFn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeBareFn"); - if let Some(val) = &self.value.lifetimes { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BoundLifetimes); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetimes", Print::ref_cast(val)); - } - if self.value.unsafety.is_some() { - formatter.field("unsafety", &Present); - } - if let Some(val) = &self.value.abi { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Abi); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("abi", Print::ref_cast(val)); - } - if !self.value.inputs.is_empty() { - formatter.field("inputs", Lite(&self.value.inputs)); - } - if let Some(val) = &self.value.variadic { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::BareVariadic); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("variadic", Print::ref_cast(val)); - } - formatter.field("output", Lite(&self.value.output)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeGroup> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeGroup"); - formatter.field("elem", Lite(&self.value.elem)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeImplTrait> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeImplTrait"); - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TypeInfer> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeInfer"); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeMacro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeMacro"); - formatter.field("mac", Lite(&self.value.mac)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeNever> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeNever"); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeParam> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeParam"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("ident", Lite(&self.value.ident)); - if self.value.colon_token.is_some() { - formatter.field("colon_token", &Present); - } - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - if self.value.eq_token.is_some() { - formatter.field("eq_token", &Present); - } - if let Some(val) = &self.value.default { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Type); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("default", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TypeParamBound> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::TypeParamBound::Trait(_val) => { - formatter.write_str("TypeParamBound::Trait")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::TypeParamBound::Lifetime(_val) => { - let mut formatter = formatter.debug_struct("TypeParamBound::Lifetime"); - formatter.field("ident", Lite(&_val.ident)); - formatter.finish() - } - syn::TypeParamBound::PreciseCapture(_val) => { - formatter.write_str("TypeParamBound::PreciseCapture")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::TypeParamBound::Verbatim(_val) => { - formatter.write_str("TypeParamBound::Verbatim")?; - formatter.write_str("(`")?; - Display::fmt(_val, formatter)?; - formatter.write_str("`)")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::TypeParen> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeParen"); - formatter.field("elem", Lite(&self.value.elem)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypePath> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypePath"); - if let Some(val) = &self.value.qself { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::QSelf); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("qself", Print::ref_cast(val)); - } - formatter.field("path", Lite(&self.value.path)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypePtr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypePtr"); - if self.value.const_token.is_some() { - formatter.field("const_token", &Present); - } - if self.value.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("elem", Lite(&self.value.elem)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeReference> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeReference"); - if let Some(val) = &self.value.lifetime { - #[derive(RefCast)] - #[repr(transparent)] - struct Print(syn::Lifetime); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("lifetime", Print::ref_cast(val)); - } - if self.value.mutability.is_some() { - formatter.field("mutability", &Present); - } - formatter.field("elem", Lite(&self.value.elem)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeSlice> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeSlice"); - formatter.field("elem", Lite(&self.value.elem)); - formatter.finish() - } -} -impl Debug for Lite<syn::TypeTraitObject> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeTraitObject"); - if self.value.dyn_token.is_some() { - formatter.field("dyn_token", &Present); - } - if !self.value.bounds.is_empty() { - formatter.field("bounds", Lite(&self.value.bounds)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::TypeTuple> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("TypeTuple"); - if !self.value.elems.is_empty() { - formatter.field("elems", Lite(&self.value.elems)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::UnOp> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::UnOp::Deref(_val) => { - formatter.write_str("UnOp::Deref")?; - Ok(()) - } - syn::UnOp::Not(_val) => { - formatter.write_str("UnOp::Not")?; - Ok(()) - } - syn::UnOp::Neg(_val) => { - formatter.write_str("UnOp::Neg")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::UseGlob> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseGlob"); - formatter.finish() - } -} -impl Debug for Lite<syn::UseGroup> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseGroup"); - if !self.value.items.is_empty() { - formatter.field("items", Lite(&self.value.items)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::UseName> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseName"); - formatter.field("ident", Lite(&self.value.ident)); - formatter.finish() - } -} -impl Debug for Lite<syn::UsePath> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UsePath"); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("tree", Lite(&self.value.tree)); - formatter.finish() - } -} -impl Debug for Lite<syn::UseRename> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("UseRename"); - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("rename", Lite(&self.value.rename)); - formatter.finish() - } -} -impl Debug for Lite<syn::UseTree> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::UseTree::Path(_val) => { - formatter.write_str("UseTree::Path")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::UseTree::Name(_val) => { - formatter.write_str("UseTree::Name")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::UseTree::Rename(_val) => { - formatter.write_str("UseTree::Rename")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::UseTree::Glob(_val) => { - formatter.write_str("UseTree::Glob")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::UseTree::Group(_val) => { - formatter.write_str("UseTree::Group")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - } -} -impl Debug for Lite<syn::Variadic> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Variadic"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - if let Some(val) = &self.value.pat { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((Box<syn::Pat>, syn::token::Colon)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.0), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("pat", Print::ref_cast(val)); - } - if self.value.comma.is_some() { - formatter.field("comma", &Present); - } - formatter.finish() - } -} -impl Debug for Lite<syn::Variant> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("Variant"); - if !self.value.attrs.is_empty() { - formatter.field("attrs", Lite(&self.value.attrs)); - } - formatter.field("ident", Lite(&self.value.ident)); - formatter.field("fields", Lite(&self.value.fields)); - if let Some(val) = &self.value.discriminant { - #[derive(RefCast)] - #[repr(transparent)] - struct Print((syn::token::Eq, syn::Expr)); - impl Debug for Print { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some(")?; - Debug::fmt(Lite(&self.0.1), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - } - formatter.field("discriminant", Print::ref_cast(val)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::VisRestricted> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("VisRestricted"); - if self.value.in_token.is_some() { - formatter.field("in_token", &Present); - } - formatter.field("path", Lite(&self.value.path)); - formatter.finish() - } -} -impl Debug for Lite<syn::Visibility> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::Visibility::Public(_val) => { - formatter.write_str("Visibility::Public")?; - Ok(()) - } - syn::Visibility::Restricted(_val) => { - let mut formatter = formatter.debug_struct("Visibility::Restricted"); - if _val.in_token.is_some() { - formatter.field("in_token", &Present); - } - formatter.field("path", Lite(&_val.path)); - formatter.finish() - } - syn::Visibility::Inherited => formatter.write_str("Visibility::Inherited"), - } - } -} -impl Debug for Lite<syn::WhereClause> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut formatter = formatter.debug_struct("WhereClause"); - if !self.value.predicates.is_empty() { - formatter.field("predicates", Lite(&self.value.predicates)); - } - formatter.finish() - } -} -impl Debug for Lite<syn::WherePredicate> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match &self.value { - syn::WherePredicate::Lifetime(_val) => { - formatter.write_str("WherePredicate::Lifetime")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - syn::WherePredicate::Type(_val) => { - formatter.write_str("WherePredicate::Type")?; - formatter.write_str("(")?; - Debug::fmt(Lite(_val), formatter)?; - formatter.write_str(")")?; - Ok(()) - } - _ => unreachable!(), - } - } -} -impl Debug for Lite<syn::token::Abstract> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![abstract]") - } -} -impl Debug for Lite<syn::token::And> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![&]") - } -} -impl Debug for Lite<syn::token::AndAnd> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![&&]") - } -} -impl Debug for Lite<syn::token::AndEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![&=]") - } -} -impl Debug for Lite<syn::token::As> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![as]") - } -} -impl Debug for Lite<syn::token::Async> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![async]") - } -} -impl Debug for Lite<syn::token::At> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![@]") - } -} -impl Debug for Lite<syn::token::Auto> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![auto]") - } -} -impl Debug for Lite<syn::token::Await> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![await]") - } -} -impl Debug for Lite<syn::token::Become> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![become]") - } -} -impl Debug for Lite<syn::token::Box> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![box]") - } -} -impl Debug for Lite<syn::token::Break> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![break]") - } -} -impl Debug for Lite<syn::token::Caret> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![^]") - } -} -impl Debug for Lite<syn::token::CaretEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![^=]") - } -} -impl Debug for Lite<syn::token::Colon> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![:]") - } -} -impl Debug for Lite<syn::token::Comma> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![,]") - } -} -impl Debug for Lite<syn::token::Const> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![const]") - } -} -impl Debug for Lite<syn::token::Continue> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![continue]") - } -} -impl Debug for Lite<syn::token::Crate> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![crate]") - } -} -impl Debug for Lite<syn::token::Default> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![default]") - } -} -impl Debug for Lite<syn::token::Do> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![do]") - } -} -impl Debug for Lite<syn::token::Dollar> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![$]") - } -} -impl Debug for Lite<syn::token::Dot> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![.]") - } -} -impl Debug for Lite<syn::token::DotDot> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![..]") - } -} -impl Debug for Lite<syn::token::DotDotDot> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![...]") - } -} -impl Debug for Lite<syn::token::DotDotEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![..=]") - } -} -impl Debug for Lite<syn::token::Dyn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![dyn]") - } -} -impl Debug for Lite<syn::token::Else> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![else]") - } -} -impl Debug for Lite<syn::token::Enum> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![enum]") - } -} -impl Debug for Lite<syn::token::Eq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![=]") - } -} -impl Debug for Lite<syn::token::EqEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![==]") - } -} -impl Debug for Lite<syn::token::Extern> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![extern]") - } -} -impl Debug for Lite<syn::token::FatArrow> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![=>]") - } -} -impl Debug for Lite<syn::token::Final> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![final]") - } -} -impl Debug for Lite<syn::token::Fn> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![fn]") - } -} -impl Debug for Lite<syn::token::For> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![for]") - } -} -impl Debug for Lite<syn::token::Ge> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![>=]") - } -} -impl Debug for Lite<syn::token::Gt> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![>]") - } -} -impl Debug for Lite<syn::token::If> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![if]") - } -} -impl Debug for Lite<syn::token::Impl> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![impl]") - } -} -impl Debug for Lite<syn::token::In> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![in]") - } -} -impl Debug for Lite<syn::token::LArrow> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![<-]") - } -} -impl Debug for Lite<syn::token::Le> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![<=]") - } -} -impl Debug for Lite<syn::token::Let> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![let]") - } -} -impl Debug for Lite<syn::token::Loop> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![loop]") - } -} -impl Debug for Lite<syn::token::Lt> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![<]") - } -} -impl Debug for Lite<syn::token::Macro> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![macro]") - } -} -impl Debug for Lite<syn::token::Match> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![match]") - } -} -impl Debug for Lite<syn::token::Minus> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![-]") - } -} -impl Debug for Lite<syn::token::MinusEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![-=]") - } -} -impl Debug for Lite<syn::token::Mod> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![mod]") - } -} -impl Debug for Lite<syn::token::Move> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![move]") - } -} -impl Debug for Lite<syn::token::Mut> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![mut]") - } -} -impl Debug for Lite<syn::token::Ne> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![!=]") - } -} -impl Debug for Lite<syn::token::Not> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![!]") - } -} -impl Debug for Lite<syn::token::Or> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![|]") - } -} -impl Debug for Lite<syn::token::OrEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![|=]") - } -} -impl Debug for Lite<syn::token::OrOr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![||]") - } -} -impl Debug for Lite<syn::token::Override> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![override]") - } -} -impl Debug for Lite<syn::token::PathSep> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![::]") - } -} -impl Debug for Lite<syn::token::Percent> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![%]") - } -} -impl Debug for Lite<syn::token::PercentEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![%=]") - } -} -impl Debug for Lite<syn::token::Plus> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![+]") - } -} -impl Debug for Lite<syn::token::PlusEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![+=]") - } -} -impl Debug for Lite<syn::token::Pound> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![#]") - } -} -impl Debug for Lite<syn::token::Priv> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![priv]") - } -} -impl Debug for Lite<syn::token::Pub> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![pub]") - } -} -impl Debug for Lite<syn::token::Question> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![?]") - } -} -impl Debug for Lite<syn::token::RArrow> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![->]") - } -} -impl Debug for Lite<syn::token::Raw> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![raw]") - } -} -impl Debug for Lite<syn::token::Ref> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![ref]") - } -} -impl Debug for Lite<syn::token::Return> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![return]") - } -} -impl Debug for Lite<syn::token::SelfType> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![Self]") - } -} -impl Debug for Lite<syn::token::SelfValue> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![self]") - } -} -impl Debug for Lite<syn::token::Semi> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![;]") - } -} -impl Debug for Lite<syn::token::Shl> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![<<]") - } -} -impl Debug for Lite<syn::token::ShlEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![<<=]") - } -} -impl Debug for Lite<syn::token::Shr> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![>>]") - } -} -impl Debug for Lite<syn::token::ShrEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![>>=]") - } -} -impl Debug for Lite<syn::token::Slash> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![/]") - } -} -impl Debug for Lite<syn::token::SlashEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![/=]") - } -} -impl Debug for Lite<syn::token::Star> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![*]") - } -} -impl Debug for Lite<syn::token::StarEq> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![*=]") - } -} -impl Debug for Lite<syn::token::Static> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![static]") - } -} -impl Debug for Lite<syn::token::Struct> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![struct]") - } -} -impl Debug for Lite<syn::token::Super> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![super]") - } -} -impl Debug for Lite<syn::token::Tilde> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![~]") - } -} -impl Debug for Lite<syn::token::Trait> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![trait]") - } -} -impl Debug for Lite<syn::token::Try> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![try]") - } -} -impl Debug for Lite<syn::token::Type> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![type]") - } -} -impl Debug for Lite<syn::token::Typeof> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![typeof]") - } -} -impl Debug for Lite<syn::token::Underscore> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![_]") - } -} -impl Debug for Lite<syn::token::Union> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![union]") - } -} -impl Debug for Lite<syn::token::Unsafe> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![unsafe]") - } -} -impl Debug for Lite<syn::token::Unsized> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![unsized]") - } -} -impl Debug for Lite<syn::token::Use> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![use]") - } -} -impl Debug for Lite<syn::token::Virtual> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![virtual]") - } -} -impl Debug for Lite<syn::token::Where> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![where]") - } -} -impl Debug for Lite<syn::token::While> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![while]") - } -} -impl Debug for Lite<syn::token::Yield> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Token![yield]") - } -} diff --git a/deps/crates/vendor/syn-v2/tests/debug/mod.rs b/deps/crates/vendor/syn-v2/tests/debug/mod.rs deleted file mode 100644 index 7ab2b795d5d3..000000000000 --- a/deps/crates/vendor/syn-v2/tests/debug/mod.rs +++ /dev/null @@ -1,147 +0,0 @@ -#![allow( - clippy::no_effect_underscore_binding, - clippy::too_many_lines, - clippy::used_underscore_binding -)] - -#[rustfmt::skip] -mod gen; - -use proc_macro2::{Ident, Literal, TokenStream}; -use ref_cast::RefCast; -use std::fmt::{self, Debug}; -use std::ops::Deref; -use syn::punctuated::Punctuated; - -#[derive(RefCast)] -#[repr(transparent)] -pub struct Lite<T: ?Sized> { - value: T, -} - -#[allow(non_snake_case)] -pub fn Lite<T: ?Sized>(value: &T) -> &Lite<T> { - Lite::ref_cast(value) -} - -impl<T: ?Sized> Deref for Lite<T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -impl Debug for Lite<bool> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", self.value) - } -} - -impl Debug for Lite<u32> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", self.value) - } -} - -impl Debug for Lite<usize> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", self.value) - } -} - -impl Debug for Lite<String> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value) - } -} - -impl Debug for Lite<Ident> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{:?}", self.value.to_string()) - } -} - -impl Debug for Lite<Literal> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "{}", self.value) - } -} - -impl Debug for Lite<TokenStream> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let string = self.value.to_string(); - if string.len() <= 80 { - write!(formatter, "TokenStream(`{}`)", self.value) - } else { - formatter - .debug_tuple("TokenStream") - .field(&format_args!("`{}`", string)) - .finish() - } - } -} - -impl<T> Debug for Lite<&T> -where - Lite<T>: Debug, -{ - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - Debug::fmt(Lite(self.value), formatter) - } -} - -impl<T> Debug for Lite<Box<T>> -where - Lite<T>: Debug, -{ - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - Debug::fmt(Lite(&*self.value), formatter) - } -} - -impl<T> Debug for Lite<Vec<T>> -where - Lite<T>: Debug, -{ - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter - .debug_list() - .entries(self.value.iter().map(Lite)) - .finish() - } -} - -impl<T, P> Debug for Lite<Punctuated<T, P>> -where - Lite<T>: Debug, - Lite<P>: Debug, -{ - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - let mut list = formatter.debug_list(); - for pair in self.pairs() { - let (node, punct) = pair.into_tuple(); - list.entry(Lite(node)); - list.entries(punct.map(Lite)); - } - list.finish() - } -} - -struct Present; - -impl Debug for Present { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("Some") - } -} - -struct Option { - present: bool, -} - -impl Debug for Option { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(if self.present { "Some" } else { "None" }) - } -} diff --git a/deps/crates/vendor/syn-v2/tests/macros/mod.rs b/deps/crates/vendor/syn-v2/tests/macros/mod.rs deleted file mode 100644 index 9c9a957f71c2..000000000000 --- a/deps/crates/vendor/syn-v2/tests/macros/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -macro_rules! errorf { - ($($tt:tt)*) => {{ - use ::std::io::Write; - let stderr = ::std::io::stderr(); - write!(stderr.lock(), $($tt)*).unwrap(); - }}; -} diff --git a/deps/crates/vendor/syn-v2/tests/regression.rs b/deps/crates/vendor/syn-v2/tests/regression.rs deleted file mode 100644 index 5c7fcddc8da9..000000000000 --- a/deps/crates/vendor/syn-v2/tests/regression.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(clippy::let_underscore_untyped, clippy::uninlined_format_args)] - -mod regression { - automod::dir!("tests/regression"); -} diff --git a/deps/crates/vendor/syn-v2/tests/regression/issue1108.rs b/deps/crates/vendor/syn-v2/tests/regression/issue1108.rs deleted file mode 100644 index 11a82adaadb0..000000000000 --- a/deps/crates/vendor/syn-v2/tests/regression/issue1108.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -fn issue1108() { - let data = "impl<x<>>::x for"; - let _ = syn::parse_file(data); -} diff --git a/deps/crates/vendor/syn-v2/tests/regression/issue1235.rs b/deps/crates/vendor/syn-v2/tests/regression/issue1235.rs deleted file mode 100644 index 8836030664b8..000000000000 --- a/deps/crates/vendor/syn-v2/tests/regression/issue1235.rs +++ /dev/null @@ -1,32 +0,0 @@ -use proc_macro2::{Delimiter, Group}; -use quote::quote; - -#[test] -fn main() { - // Okay. Rustc allows top-level `static` with no value syntactically, but - // not semantically. Syn parses as Item::Verbatim. - let tokens = quote! { - pub static FOO: usize; - pub static BAR: usize; - }; - let file = syn::parse2::<syn::File>(tokens).unwrap(); - println!("{:#?}", file); - - // Okay. - let inner = Group::new( - Delimiter::None, - quote!(static FOO: usize = 0; pub static BAR: usize = 0), - ); - let tokens = quote!(pub #inner;); - let file = syn::parse2::<syn::File>(tokens).unwrap(); - println!("{:#?}", file); - - // Formerly parser crash. - let inner = Group::new( - Delimiter::None, - quote!(static FOO: usize; pub static BAR: usize), - ); - let tokens = quote!(pub #inner;); - let file = syn::parse2::<syn::File>(tokens).unwrap(); - println!("{:#?}", file); -} diff --git a/deps/crates/vendor/syn-v2/tests/repo/mod.rs b/deps/crates/vendor/syn-v2/tests/repo/mod.rs deleted file mode 100644 index a9d4b3e37011..000000000000 --- a/deps/crates/vendor/syn-v2/tests/repo/mod.rs +++ /dev/null @@ -1,1017 +0,0 @@ -#![allow(clippy::manual_assert)] - -mod progress; - -use self::progress::Progress; -use anyhow::Result; -use flate2::read::GzDecoder; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; -use rayon::ThreadPoolBuilder; -use std::collections::BTreeSet; -use std::env; -use std::ffi::OsStr; -use std::fs; -use std::path::{Path, PathBuf}; -use tar::Archive; -use walkdir::{DirEntry, WalkDir}; - -// nightly-2026-07-13 -const REVISION: &str = "77cf889bc178ddb44d6a1c78e5a820b5abb31d8d"; - -#[rustfmt::skip] -static EXCLUDE_FILES: &[&str] = &[ - // TODO: const traits: `pub const trait Trait {}` - // https://github.com/dtolnay/syn/issues/1887 - "library/core/src/alloc/mod.rs", - "library/core/src/borrow.rs", - "library/core/src/clone.rs", - "library/core/src/cmp.rs", - "library/core/src/cmp/bytewise.rs", - "library/core/src/convert/mod.rs", - "library/core/src/default.rs", - "library/core/src/intrinsics/fallback.rs", - "library/core/src/iter/range.rs", - "library/core/src/iter/traits/accum.rs", - "library/core/src/iter/traits/collect.rs", - "library/core/src/iter/traits/double_ended.rs", - "library/core/src/iter/traits/iterator.rs", - "library/core/src/iter/traits/marker.rs", - "library/core/src/ops/arith.rs", - "library/core/src/ops/bit.rs", - "library/core/src/ops/deref.rs", - "library/core/src/ops/drop.rs", - "library/core/src/ops/function.rs", - "library/core/src/ops/index.rs", - "library/core/src/ops/range.rs", - "library/core/src/ops/try_trait.rs", - "library/core/src/pat.rs", - "library/core/src/slice/mod.rs", - "library/stdarch/crates/core_arch/src/loongarch64/simd.rs", - "src/tools/clippy/tests/ui/assign_ops.rs", - "src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs", - "src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs", - "src/tools/rust-analyzer/crates/test-utils/src/minicore.rs", - "src/tools/rustfmt/tests/target/const_trait.rs", - "tests/rustdoc-html/constant/const-effect-param.rs", - "tests/rustdoc-html/constant/const-trait-and-impl-methods.rs", - "tests/rustdoc-html/constant/rfc-2632-const-trait-impl.rs", - "tests/rustdoc-html/inline_cross/auxiliary/const-effect-param.rs", - "tests/rustdoc-json/attrs/stability/const_traits.rs", - "tests/ui/const-generics/const_trait_fn-issue-88433.rs", - "tests/ui/const-generics/issues/issue-88119.rs", - "tests/ui/consts/const-closure-in-trait-impl.rs", - "tests/ui/consts/trait_alias_method_call.rs", - "tests/ui/generic-const-items/const-trait-impl.rs", - "tests/ui/parser/impls-nested-within-fns-semantic-1.rs", - "tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs", - "tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs", - "tests/ui/traits/const-traits/auxiliary/associated-const-stability.rs", - "tests/ui/traits/const-traits/auxiliary/cross-crate.rs", - "tests/ui/traits/const-traits/auxiliary/minicore.rs", - "tests/ui/traits/const-traits/auxiliary/staged-api.rs", - "tests/ui/traits/const-traits/call-generic-in-impl.rs", - "tests/ui/traits/const-traits/conditionally-const-assoc-fn-in-trait-impl.rs", - "tests/ui/traits/const-traits/conditionally-const-inherent-assoc-const-fn.rs", - "tests/ui/traits/const-traits/conditionally-const-trait-bound-assoc-tys.rs", - "tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs", - "tests/ui/traits/const-traits/const-bound-in-host.rs", - "tests/ui/traits/const-traits/const-closure-inherited-const-condition.rs", - "tests/ui/traits/const-traits/const-closure-trait-method.rs", - "tests/ui/traits/const-traits/const-cond-for-rpitit.rs", - "tests/ui/traits/const-traits/const-impl-inherent-bounds.rs", - "tests/ui/traits/const-traits/const-impl-recovery.rs", - "tests/ui/traits/const-traits/const-impl-trait-not-impl-const-trait.rs", - "tests/ui/traits/const-traits/const-impl-trait.rs", - "tests/ui/traits/const-traits/const-in-closure.rs", - "tests/ui/traits/const-traits/const-via-item-bound.rs", - "tests/ui/traits/const-traits/default-method-body-is-const-with-staged-api.rs", - "tests/ui/traits/const-traits/do-not-const-check-override.rs", - "tests/ui/traits/const-traits/do-not-const-check.rs", - "tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs", - "tests/ui/traits/const-traits/dont-observe-host.rs", - "tests/ui/traits/const-traits/dont-prefer-param-env-for-infer-self-ty.rs", - "tests/ui/traits/const-traits/effect-param-infer.rs", - "tests/ui/traits/const-traits/function-pointer-does-not-require-const.rs", - "tests/ui/traits/const-traits/hir-const-check.rs", - "tests/ui/traits/const-traits/impl-with-default-fn-pass.rs", - "tests/ui/traits/const-traits/imply-always-const.rs", - "tests/ui/traits/const-traits/inherent-impl-const-bounds.rs", - "tests/ui/traits/const-traits/issue-100222.rs", - "tests/ui/traits/const-traits/issue-92230-wf-super-trait-env.rs", - "tests/ui/traits/const-traits/item-bound-entailment.rs", - "tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs", - "tests/ui/traits/const-traits/parse-const-unsafe-trait.rs", - "tests/ui/traits/const-traits/predicate-entailment-passes.rs", - "tests/ui/traits/const-traits/project.rs", - "tests/ui/traits/const-traits/specialization/const-default-const-specialized.rs", - "tests/ui/traits/const-traits/specialization/default-keyword.rs", - "tests/ui/traits/const-traits/specialization/issue-95187-same-trait-bound-different-constness.rs", - "tests/ui/traits/const-traits/specialization/non-const-default-const-specialized.rs", - "tests/ui/traits/const-traits/specialization/pass.rs", - "tests/ui/traits/const-traits/specialization/specialize-on-conditionally-const.rs", - "tests/ui/traits/const-traits/super-traits.rs", - "tests/ui/traits/const-traits/trait-where-clause-run.rs", - "tests/ui/traits/const-traits/trait-where-clause-self-referential.rs", - "tests/ui/traits/const-traits/unconstrained-var-specialization.rs", - "tests/ui/traits/next-solver/canonical/effect-var.rs", - - // TODO: const impls: `const impl Trait for T {}` - // https://github.com/dtolnay/syn/issues/1980 - "compiler/rustc_data_structures/src/unord.rs", - "compiler/rustc_middle/src/middle/codegen_fn_attrs.rs", - "library/alloc/src/alloc.rs", - "library/alloc/src/collections/btree/map.rs", - "library/alloc/src/collections/mod.rs", - "library/alloc/src/raw_vec/mod.rs", - "library/alloc/src/string.rs", - "library/alloc/src/vec/mod.rs", - "library/core/src/any.rs", - "library/core/src/array/drain.rs", - "library/core/src/array/equality.rs", - "library/core/src/array/mod.rs", - "library/core/src/bstr/mod.rs", - "library/core/src/cell.rs", - "library/core/src/cell/lazy.rs", - "library/core/src/cell/once.rs", - "library/core/src/char/convert.rs", - "library/core/src/ffi/c_str.rs", - "library/core/src/ffi/va_list.rs", - "library/core/src/hash/mod.rs", - "library/core/src/hash/sip.rs", - "library/core/src/iter/adapters/cycle.rs", - "library/core/src/iter/adapters/flatten.rs", - "library/core/src/iter/sources/empty.rs", - "library/core/src/marker.rs", - "library/core/src/mem/alignment.rs", - "library/core/src/mem/drop_guard.rs", - "library/core/src/mem/manually_drop.rs", - "library/core/src/net/ip_addr.rs", - "library/core/src/net/socket_addr.rs", - "library/core/src/num/error.rs", - "library/core/src/num/niche_types.rs", - "library/core/src/ops/control_flow.rs", - "library/core/src/option.rs", - "library/core/src/panic/unwind_safe.rs", - "library/core/src/pin.rs", - "library/core/src/pin/unsafe_pinned.rs", - "library/core/src/ptr/non_null.rs", - "library/core/src/ptr/unique.rs", - "library/core/src/range.rs", - "library/core/src/result.rs", - "library/core/src/slice/cmp.rs", - "library/core/src/slice/index.rs", - "library/core/src/str/mod.rs", - "library/core/src/str/traits.rs", - "library/core/src/sync/sync_view.rs", - "library/core/src/task/poll.rs", - "library/core/src/task/wake.rs", - "library/core/src/time.rs", - "library/coretests/tests/array.rs", - "library/coretests/tests/cmp.rs", - "library/coretests/tests/hint.rs", - "library/coretests/tests/manually_drop.rs", - "library/std/src/collections/hash/map.rs", - "library/std/src/collections/hash/set.rs", - "library/std/src/ffi/os_str.rs", - "library/std/src/hash/random.rs", - "library/std/src/path.rs", - "library/std/src/sync/lazy_lock.rs", - "library/std/src/sync/once_lock.rs", - "library/stdarch/crates/core_arch/src/simd.rs", - "src/tools/clippy/tests/ui/derivable_impls.rs", - "src/tools/clippy/tests/ui/derivable_impls_derive_const.rs", - "src/tools/clippy/tests/ui/equatable_if_let_const_cmp.rs", - "src/tools/rustfmt/tests/source/impls.rs", - "src/tools/rustfmt/tests/target/impls.rs", - "tests/ui/consts/const-try.rs", - "tests/ui/traits/const-traits/call-const-trait-method-pass.rs", - "tests/ui/traits/const-traits/call-generic-method-chain.rs", - "tests/ui/traits/const-traits/call-generic-method-dup-bound.rs", - "tests/ui/traits/const-traits/call-generic-method-pass.rs", - "tests/ui/traits/const-traits/const-drop.rs", - "tests/ui/traits/const-traits/const-impl-inherent.rs", - "tests/ui/traits/const-traits/const-unsafe-impl.rs", - "tests/ui/traits/const-traits/const_derives/derive-const-use.rs", - "tests/ui/traits/const-traits/drop-manually-drop.rs", - "tests/ui/traits/const-traits/enforce-deref-on-adjust.rs", - "tests/ui/traits/const-traits/generic-bound.rs", - "tests/ui/traits/const-traits/inherent-impl.rs", - "tests/ui/traits/const-traits/minicore-works.rs", - "tests/ui/traits/const-traits/rustc-impl-const-stability.rs", - "tests/ui/traits/const-traits/trait-default-body-stability.rs", - - // TODO: unsafe binders: `unsafe<'a> &'a T` - // https://github.com/dtolnay/syn/issues/1791 - "src/tools/rustfmt/tests/source/unsafe-binders.rs", - "src/tools/rustfmt/tests/target/unsafe-binders.rs", - "tests/debuginfo/unsafe-binders.rs", - "tests/mir-opt/gvn_on_unsafe_binder.rs", - "tests/rustdoc-html/auxiliary/unsafe-binder-dep.rs", - "tests/rustdoc-html/unsafe-binder.rs", - "tests/ui/unsafe-binders/binder-sized-crit.rs", - "tests/ui/unsafe-binders/cat-projection.rs", - "tests/ui/unsafe-binders/expr.rs", - "tests/ui/unsafe-binders/simple.rs", - "tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs", - - // TODO: unsafe fields: `struct S { unsafe field: T }` - // https://github.com/dtolnay/syn/issues/1792 - "src/tools/clippy/tests/ui/derive.rs", - "src/tools/clippy/tests/ui/doc_unsafe.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_list.rs", - "src/tools/rustfmt/tests/source/unsafe-field.rs", - "src/tools/rustfmt/tests/target/unsafe-field.rs", - "tests/ui/unsafe-fields/auxiliary/unsafe-fields-crate-dep.rs", - - // TODO: guard patterns: `match expr { (A if f()) | (B if g()) => {} }` - // https://github.com/dtolnay/syn/issues/1793 - "src/tools/rustfmt/tests/target/guard_patterns.rs", - "tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs", - "tests/ui/pattern/rfc-3637-guard-patterns/liveness-ice-issue-146445.rs", - "tests/ui/pattern/rfc-3637-guard-patterns/only-gather-locals-once.rs", - "tests/ui/reachable/guard_read_for_never.rs", - - // TODO: struct field default: `struct S { field: i32 = 1 }` - // https://github.com/dtolnay/syn/issues/1774 - "compiler/rustc_ast_lowering/src/delegation/generics.rs", - "compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs", - "compiler/rustc_errors/src/markdown/parse.rs", - "compiler/rustc_hir/src/attrs/diagnostic.rs", - "compiler/rustc_hir_analysis/src/hir_wf_check.rs", - "compiler/rustc_middle/src/hir/map.rs", - "compiler/rustc_middle/src/ty/mod.rs", - "compiler/rustc_parse/src/parser/mod.rs", - "compiler/rustc_parse/src/parser/stmt.rs", - "compiler/rustc_privacy/src/lib.rs", - "compiler/rustc_resolve/src/imports.rs", - "compiler/rustc_resolve/src/lib.rs", - "compiler/rustc_session/src/config.rs", - "compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs", - "src/tools/clippy/tests/ui/exhaustive_items.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs", - "src/tools/rustfmt/tests/source/default-field-values.rs", - "src/tools/rustfmt/tests/target/default-field-values.rs", - "tests/ui/structs/default-field-values/auxiliary/struct_field_default.rs", - "tests/ui/structs/default-field-values/const-trait-default-field-value.rs", - "tests/ui/structs/default-field-values/field-references-param.rs", - "tests/ui/structs/default-field-values/support.rs", - "tests/ui/structs/default-field-values/use-normalized-ty-for-default-struct-value.rs", - - // TODO: final associated functions: `final fn` - // https://github.com/dtolnay/syn/issues/1981 - "library/core/src/io/size_hint.rs", - "src/tools/rustfmt/tests/target/final-kw.rs", - "tests/rustdoc-html/final-trait-method.rs", - "tests/ui/traits/final/dyn-compat.rs", - "tests/ui/traits/final/works.rs", - - // TODO: impl restrictions: `pub impl(self) trait Trait` - // https://github.com/dtolnay/syn/issues/1982 - "library/core/src/convert/num.rs", - "library/core/src/num/nonzero.rs", - "library/core/src/num/traits.rs", - "library/core/src/sync/atomic.rs", - "library/std/src/io/stdio.rs", - "library/std/src/os/darwin/fs.rs", - "library/std/src/os/freebsd/net.rs", - "library/std/src/os/illumos/net.rs", - "library/std/src/os/linux/process.rs", - "library/std/src/os/motor/ffi.rs", - "library/std/src/os/motor/process.rs", - "library/std/src/os/net/linux_ext/addr.rs", - "library/std/src/os/net/linux_ext/socket.rs", - "library/std/src/os/net/linux_ext/tcp.rs", - "library/std/src/os/netbsd/net.rs", - "library/std/src/os/solaris/net.rs", - "library/std/src/os/unix/ffi/os_str.rs", - "library/std/src/os/unix/fs.rs", - "library/std/src/os/unix/io/mod.rs", - "library/std/src/os/unix/process.rs", - "library/std/src/os/windows/ffi.rs", - "library/std/src/os/windows/fs.rs", - "library/std/src/os/windows/process.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/impl_restrictions.rs", - "src/tools/rustfmt/tests/source/impl-restriction.rs", - "src/tools/rustfmt/tests/target/impl-restriction.rs", - "tests/pretty/hir-impl-restriction.rs", - "tests/rustdoc-html/impl/impl-restriction-document-private.rs", - "tests/rustdoc-html/impl/impl-restriction.rs", - "tests/ui/impl-restriction/auxiliary/external-impl-restriction.rs", - - // TODO: return type notation: `where T: Trait<method(): Send>` and `where T::method(..): Send` - // https://github.com/dtolnay/syn/issues/1434 - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs", - "src/tools/rustfmt/tests/target/return-type-notation.rs", - "tests/rustdoc-html/jump-to-def/assoc-items-extra.rs", - "tests/rustdoc-html/return-type-notation.rs", - "tests/rustdoc-json/return-type-notation.rs", - "tests/ui/associated-type-bounds/all-generics-lookup.rs", - "tests/ui/associated-type-bounds/implied-from-self-where-clause.rs", - "tests/ui/associated-type-bounds/return-type-notation/basic.rs", - "tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs", - "tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs", - "tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs", - "tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs", - "tests/ui/associated-type-bounds/return-type-notation/path-works.rs", - "tests/ui/associated-type-bounds/return-type-notation/trait-alias.rs", - "tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.rs", - "tests/ui/async-await/return-type-notation/issue-110963-late.rs", - "tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs", - "tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs", - "tests/ui/async-await/return-type-notation/super-method-bound.rs", - "tests/ui/async-await/return-type-notation/supertrait-bound.rs", - "tests/ui/borrowck/alias-liveness/rtn-static.rs", - "tests/ui/feature-gates/feature-gate-return_type_notation.rs", - - // TODO: lazy type alias syntax with where-clause in trailing position - // https://github.com/dtolnay/syn/issues/1525 - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_item_where_clause.rs", - "src/tools/rustfmt/tests/source/type-alias-where-clauses-with-comments.rs", - "src/tools/rustfmt/tests/source/type-alias-where-clauses.rs", - "src/tools/rustfmt/tests/target/type-alias-where-clauses-with-comments.rs", - "src/tools/rustfmt/tests/target/type-alias-where-clauses.rs", - "tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs", - "tests/ui/traits/next-solver/normalize/normalize-self-type-constrains-trait-args.rs", - - // TODO: gen blocks and functions - // https://github.com/dtolnay/syn/issues/1526 - "compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", - "compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs", - "compiler/rustc_metadata/src/rmeta/decoder.rs", - "compiler/rustc_middle/src/ty/closure.rs", - "compiler/rustc_middle/src/ty/context.rs", - "src/tools/clippy/tests/ui/infinite_loops.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/gen_blocks.rs", - "tests/ui/async-await/async-drop/assign-incompatible-types.rs", - "tests/ui/coroutine/async-gen-deduce-yield.rs", - "tests/ui/coroutine/async-gen-yield-ty-is-unit.rs", - "tests/ui/coroutine/async_gen_fn_iter.rs", - "tests/ui/coroutine/gen_block_is_fused_iter.rs", - "tests/ui/coroutine/gen_block_is_iter.rs", - "tests/ui/coroutine/gen_block_iterate.rs", - "tests/ui/coroutine/gen_fn_iter.rs", - "tests/ui/coroutine/gen_fn_lifetime_capture.rs", - "tests/ui/coroutine/other-attribute-on-gen.rs", - "tests/ui/coroutine/return-types-diverge.rs", - "tests/ui/higher-ranked/builtin-closure-like-bounds.rs", - "tests/ui/sanitizer/cfi/coroutine.rs", - - // TODO: postfix yield - // https://github.com/dtolnay/syn/issues/1890 - "tests/pretty/postfix-yield.rs", - "tests/ui/coroutine/postfix-yield.rs", - - // TODO: `!` as a pattern - // https://github.com/dtolnay/syn/issues/1546 - "tests/mir-opt/building/match/never_patterns.rs", - "tests/pretty/never-pattern.rs", - "tests/ui/reachable/never-pattern-closure-param-array.rs", - "tests/ui/rfcs/rfc-0000-never_patterns/always-read-in-closure-capture.rs", - "tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs", - "tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs", - - // TODO: async trait bounds: `impl async Fn()` - // https://github.com/dtolnay/syn/issues/1628 - "src/tools/miri/tests/pass/async-closure-captures.rs", - "src/tools/miri/tests/pass/async-closure-drop.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs", - "src/tools/rustfmt/tests/target/asyncness.rs", - "tests/coverage/async_closure.rs", - "tests/ui/async-await/async-closures/async-fn-mut-for-async-fn.rs", - "tests/ui/async-await/async-closures/async-fn-once-for-async-fn.rs", - "tests/ui/async-await/async-closures/auxiliary/foreign.rs", - "tests/ui/async-await/async-closures/body-check-on-non-fnmut.rs", - "tests/ui/async-await/async-closures/box-deref-in-debuginfo.rs", - "tests/ui/async-await/async-closures/brand.rs", - "tests/ui/async-await/async-closures/captures.rs", - "tests/ui/async-await/async-closures/clone-closure.rs", - "tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs", - "tests/ui/async-await/async-closures/debuginfo-by-move-body.rs", - "tests/ui/async-await/async-closures/drop.rs", - "tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs", - "tests/ui/async-await/async-closures/foreign.rs", - "tests/ui/async-await/async-closures/inline-body.rs", - "tests/ui/async-await/async-closures/mangle.rs", - "tests/ui/async-await/async-closures/moro-example.rs", - "tests/ui/async-await/async-closures/move-is-async-fn.rs", - "tests/ui/async-await/async-closures/mut-ref-reborrow.rs", - "tests/ui/async-await/async-closures/no-borrow-from-env.rs", - "tests/ui/async-await/async-closures/non-copy-arg-does-not-force-inner-move.rs", - "tests/ui/async-await/async-closures/overlapping-projs.rs", - "tests/ui/async-await/async-closures/precise-captures.rs", - "tests/ui/async-await/async-closures/refd.rs", - "tests/ui/async-await/async-closures/signature-deduction.rs", - "tests/ui/async-await/async-fn/edition-2015-not-async-bound.rs", - "tests/ui/async-await/async-fn/higher-ranked-async-fn.rs", - "tests/ui/async-await/async-fn/impl-trait.rs", - "tests/ui/async-await/async-fn/project.rs", - "tests/ui/async-await/async-fn/sugar.rs", - - // TODO: mutable by-reference bindings (mut ref) - // https://github.com/dtolnay/syn/issues/1629 - "src/tools/rustfmt/tests/source/mut_ref.rs", - "src/tools/rustfmt/tests/target/mut_ref.rs", - "tests/ui/mut/mut-ref.rs", - - // TODO: postfix match - // https://github.com/dtolnay/syn/issues/1630 - "src/tools/clippy/tests/ui/unnecessary_semicolon.rs", - "src/tools/rustfmt/tests/source/postfix-match/pf-match.rs", - "src/tools/rustfmt/tests/target/postfix-match/pf-match.rs", - "tests/pretty/postfix-match/simple-matches.rs", - "tests/ui/match/postfix-match/no-unused-parens.rs", - "tests/ui/match/postfix-match/pf-match-chain.rs", - "tests/ui/match/postfix-match/postfix-match.rs", - - // TODO: delegation: `reuse Trait::bar { Box::new(self.0) }` - // https://github.com/dtolnay/syn/issues/1580 - "src/tools/rustfmt/tests/target/issue_6513.rs", - "tests/incremental/delegation-ice-155729.rs", - "tests/pretty/delegation/delegation.rs", - "tests/pretty/delegation/generics.rs", - "tests/pretty/delegation/impl-reuse.rs", - "tests/pretty/delegation/inherit-attributes.rs", - "tests/pretty/delegation/inline-attribute.rs", - "tests/pretty/delegation/self-mapping-output.rs", - "tests/pretty/delegation/self-rename.rs", - "tests/pretty/hir-delegation.rs", - "tests/rustdoc-html/async/async-fn-delegation.rs", - "tests/ui/delegation/auxiliary/recursive-delegation-aux.rs", - "tests/ui/delegation/body-identity-glob.rs", - "tests/ui/delegation/body-identity-list.rs", - "tests/ui/delegation/explicit-paths-in-traits-pass.rs", - "tests/ui/delegation/explicit-paths-pass.rs", - "tests/ui/delegation/explicit-paths-signature-pass.rs", - "tests/ui/delegation/fn-header.rs", - "tests/ui/delegation/generics/const-type-ice-154334.rs", - "tests/ui/delegation/generics/free-fn-to-free-fn-pass.rs", - "tests/ui/delegation/generics/free-fn-to-trait-method-pass.rs", - "tests/ui/delegation/generics/generics-aux-pass.rs", - "tests/ui/delegation/generics/impl-to-free-fn-pass.rs", - "tests/ui/delegation/generics/impl-trait-to-trait-method-pass.rs", - "tests/ui/delegation/generics/inherent-impl-to-trait-method-pass.rs", - "tests/ui/delegation/generics/mapping/free-to-free-pass.rs", - "tests/ui/delegation/generics/mapping/free-to-trait-pass.rs", - "tests/ui/delegation/generics/mapping/impl-trait-to-free-pass.rs", - "tests/ui/delegation/generics/mapping/impl-trait-to-trait-pass.rs", - "tests/ui/delegation/generics/mapping/inherent-impl-to-free-pass.rs", - "tests/ui/delegation/generics/mapping/inherent-impl-to-trait-pass.rs", - "tests/ui/delegation/generics/mapping/trait-to-free-pass.rs", - "tests/ui/delegation/generics/mapping/trait-to-trait-pass.rs", - "tests/ui/delegation/generics/self-rename.rs", - "tests/ui/delegation/generics/stability-implications-non-local-defid.rs", - "tests/ui/delegation/generics/synth-params-ice-154780.rs", - "tests/ui/delegation/generics/trait-method-to-other-pass.rs", - "tests/ui/delegation/generics/unelided-lifetime-in-sig-ice-156848.rs", - "tests/ui/delegation/glob-glob.rs", - "tests/ui/delegation/glob-override.rs", - "tests/ui/delegation/glob.rs", - "tests/ui/delegation/impl-reuse-pass.rs", - "tests/ui/delegation/impl-trait.rs", - "tests/ui/delegation/list.rs", - "tests/ui/delegation/macro-inside-glob.rs", - "tests/ui/delegation/macro-inside-list.rs", - "tests/ui/delegation/method-call-priority.rs", - "tests/ui/delegation/parse.rs", - "tests/ui/delegation/recursive-delegation-pass.rs", - "tests/ui/delegation/rename.rs", - "tests/ui/delegation/self-coercion.rs", - "tests/ui/delegation/self-mapping-arguments.rs", - "tests/ui/delegation/target-expression-removal-pass.rs", - - // TODO: for await - // https://github.com/dtolnay/syn/issues/1631 - "tests/ui/async-await/for-await-2015.rs", - "tests/ui/async-await/for-await-passthrough.rs", - "tests/ui/async-await/for-await.rs", - - // TODO: unparenthesized half-open range pattern inside slice pattern: `[1..]` - // https://github.com/dtolnay/syn/issues/1769 - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/range_pat.rs", - "tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs", - - // TODO: pinned type sugar: `&pin const Self` - // https://github.com/dtolnay/syn/issues/1770 - "src/tools/rustfmt/tests/source/pin_sugar.rs", - "src/tools/rustfmt/tests/target/pin_sugar.rs", - "tests/pretty/pin-ergonomics-hir.rs", - "tests/pretty/pin-ergonomics.rs", - "tests/ui/pin-ergonomics/borrow.rs", - "tests/ui/pin-ergonomics/pin-coercion.rs", - "tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs", - "tests/ui/pin-ergonomics/pinned-drop-sugar.rs", - "tests/ui/pin-ergonomics/pinned-drop.rs", - "tests/ui/pin-ergonomics/sugar-self.rs", - "tests/ui/pin-ergonomics/sugar.rs", - "tests/ui/pin-ergonomics/user-type-projection.rs", - - // TODO: attributes on where-predicates - // https://github.com/dtolnay/syn/issues/1705 - "src/tools/rustfmt/tests/target/cfg_attribute_in_where.rs", - "tests/ui/where-clauses/cfg-attr-issue-138010-1.rs", - - // TODO: super let - // https://github.com/dtolnay/syn/issues/1889 - "library/std/src/macros/tests.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/let_stmt.rs", - "tests/ui/drop/if-let-super-let.rs", - "tests/ui/drop/super-let-tail-expr-drop-order.rs", - - // TODO: "ergonomic clones": `f(obj.use)`, `thread::spawn(use || f(obj))`, `async use` - // https://github.com/dtolnay/syn/issues/1802 - "src/tools/clippy/tests/ui/redundant_closure_call_early.rs", - "src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs", - "src/tools/rustfmt/tests/source/ergonomic_clones.rs", - "src/tools/rustfmt/tests/target/ergonomic_clones.rs", - "tests/codegen-llvm/ergonomic-clones/closure.rs", - "tests/mir-opt/ergonomic-clones/closure.rs", - "tests/ui/ergonomic-clones/async/basic.rs", - "tests/ui/ergonomic-clones/closure/basic.rs", - "tests/ui/ergonomic-clones/closure/const-closure.rs", - "tests/ui/ergonomic-clones/closure/mutation.rs", - "tests/ui/ergonomic-clones/closure/nested.rs", - "tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs", - "tests/ui/ergonomic-clones/closure/with-binders.rs", - "tests/ui/ergonomic-clones/dotuse/basic.rs", - "tests/ui/ergonomic-clones/dotuse/block.rs", - - // TODO: move expression - // https://github.com/dtolnay/syn/issues/1983 - "tests/ui/move-expr/borrow-only.rs", - "tests/ui/move-expr/copy-type.rs", - "tests/ui/move-expr/name-resolution.rs", - "tests/ui/move-expr/nested-closures.rs", - "tests/ui/move-expr/nested-move-expr.rs", - "tests/ui/move-expr/parse-ambiguity.rs", - "tests/ui/move-expr/plain-closure.rs", - - // TODO: contracts - // https://github.com/dtolnay/syn/issues/1892 - "tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs", - "tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs", - "tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs", - "tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs", - - // TODO: frontmatter - // https://github.com/dtolnay/syn/issues/1893 - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/frontmatter.rs", - "src/tools/rustfmt/tests/source/frontmatter_compact.rs", - "src/tools/rustfmt/tests/source/frontmatter_escaped.rs", - "src/tools/rustfmt/tests/source/frontmatter_spaced.rs", - "src/tools/rustfmt/tests/target/frontmatter_compact.rs", - "src/tools/rustfmt/tests/target/frontmatter_escaped.rs", - "src/tools/rustfmt/tests/target/frontmatter_spaced.rs", - "tests/rustdoc-html/source-code-pages/frontmatter.rs", - "tests/ui/frontmatter/auxiliary/expr.rs", - "tests/ui/frontmatter/auxiliary/lib.rs", - "tests/ui/frontmatter/content-contains-whitespace.rs", - "tests/ui/frontmatter/content-non-lexible-tokens.rs", - "tests/ui/frontmatter/escape-hyphens-leading.rs", - "tests/ui/frontmatter/escape-hyphens-nonleading-1.rs", - "tests/ui/frontmatter/escape-hyphens-nonleading-2.rs", - "tests/ui/frontmatter/escape-hyphens-nonleading-3.rs", - "tests/ui/frontmatter/fence-whitespace-trailing-1.rs", - "tests/ui/frontmatter/fence-whitespace-trailing-2.rs", - "tests/ui/frontmatter/frontmatter-crlf.rs", - "tests/ui/frontmatter/infostring-dot-nonleading.rs", - "tests/ui/frontmatter/infostring-hyphen-nonleading.rs", - "tests/ui/frontmatter/location-after-shebang.rs", - "tests/ui/include-macros/auxiliary/shebang-expr.rs", - "tests/ui/unpretty/frontmatter.rs", - - // TODO: `type const` associated items - // https://github.com/dtolnay/syn/issues/1984 - "src/tools/clippy/tests/ui/crashes/mgca-16691.rs", - "src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs", - "src/tools/rustfmt/tests/source/direct_const_arg.rs", - "src/tools/rustfmt/tests/target/direct_const_arg.rs", - "tests/debuginfo/associated-const-bindings.rs", - "tests/rustdoc-html/constant/ice-associated-const-equality-105952.rs", - "tests/rustdoc-html/inline_cross/auxiliary/assoc-const-equality.rs", - "tests/rustdoc-html/type-const-associated-const-no-body.rs", - "tests/rustdoc-html/type-const-free-in-array.rs", - "tests/rustdoc-html/type-const-inherent-with-body.rs", - "tests/ui/associated-consts/issue-110933.rs", - "tests/ui/associated-consts/type-const-in-array-len.rs", - "tests/ui/associated-type-bounds/duplicate-bound.rs", - "tests/ui/const-generics/associated-const-bindings/assoc-const.rs", - "tests/ui/const-generics/associated-const-bindings/bound-var-in-ty.rs", - "tests/ui/const-generics/associated-const-bindings/coexisting-with-type-binding.rs", - "tests/ui/const-generics/associated-const-bindings/const_evaluatable_unchecked.rs", - "tests/ui/const-generics/associated-const-bindings/dyn-compat-basic.rs", - "tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-methods.rs", - "tests/ui/const-generics/associated-const-bindings/dyn-const-projection-escaping-bound-vars.rs", - "tests/ui/const-generics/associated-const-bindings/equality-unused-issue-126729.rs", - "tests/ui/const-generics/associated-const-bindings/equality_bound_with_infer.rs", - "tests/ui/const-generics/associated-const-bindings/normalization-via-param-env.rs", - "tests/ui/const-generics/associated-const-bindings/supertraits.rs", - "tests/ui/const-generics/gca/basic-different-definitions.rs", - "tests/ui/const-generics/gca/basic.rs", - "tests/ui/const-generics/generic_const_exprs/auxiliary/non_local_type_const.rs", - "tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs", - "tests/ui/const-generics/mgca/array-expr-with-assoc-const.rs", - "tests/ui/const-generics/mgca/assoc-const-projection-in-bound.rs", - "tests/ui/const-generics/mgca/assoc-const.rs", - "tests/ui/const-generics/mgca/concrete-expr-with-generics-in-env.rs", - "tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs", - "tests/ui/const-generics/mgca/generic-args-on-enum-variant-segments.rs", - "tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs", - "tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs", - "tests/ui/const-generics/mgca/tuple_expr_arg_simple.rs", - "tests/ui/const-generics/mgca/type-const-ctor-148953.rs", - "tests/ui/const-generics/mgca/type-const-used-in-trait.rs", - "tests/ui/const-generics/mgca/type_const-array-return.rs", - "tests/ui/const-generics/mgca/type_const-incemental-compile.rs", - "tests/ui/const-generics/mgca/type_const-pub.rs", - "tests/ui/const-generics/mgca/type_const-use.rs", - "tests/ui/const-generics/mgca/type_const_in_pattern.rs", - "tests/ui/generic-const-items/assoc-const-bindings.rs", - "tests/ui/generic-const-items/type-const-nested-assoc-const.rs", - "tests/ui/sanitizer/cfi/assoc-const-projection-issue-151878.rs", - "tests/ui/supertrait-shadowing/assoc-const.rs", - "tests/ui/supertrait-shadowing/out-of-scope.rs", - "tests/ui/supertrait-shadowing/type-dependent.rs", - - // TODO: const block in path argument: `T: Trait<const { ... }>` - // https://github.com/dtolnay/syn/issues/1985 - "tests/ui/const-generics/mgca/higher-ranked-lts-good.rs", - "tests/ui/traits/associated_type_bound/generic-const-args-default.rs", - - // TODO: item-level const blocks - // https://github.com/dtolnay/syn/issues/1986 - "src/tools/rustfmt/tests/source/const-block-items.rs", - "src/tools/rustfmt/tests/target/const-block-items.rs", - "tests/ui/consts/const-block-items/assert-pass.rs", - "tests/ui/consts/const-block-items/hir.rs", - "tests/ui/parser/const-block-items/attrs.rs", - "tests/ui/parser/const-block-items/mod-in-fn.rs", - "tests/ui/parser/const-block-items/pub.rs", - - // TODO: mut-restricted fields - // https://github.com/dtolnay/syn/issues/1987 - "src/tools/rustfmt/tests/source/mut-restriction.rs", - "src/tools/rustfmt/tests/target/mut-restriction.rs", - "tests/pretty/hir-mut-restriction.rs", - "tests/ui/mut-restriction/auxiliary/external-mut-restriction.rs", - - // TODO: heterogeneous try-blocks: `try bikeshed Option<_>` - // https://github.com/dtolnay/syn/issues/1988 - "src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs", - "src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs", - "tests/pretty/try-blocks.rs", - "tests/ui/try-block/try-block-heterogeneous.rs", - - // TODO: `|| .. .method()` - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_range_method_call.rs", - "src/tools/rustfmt/tests/source/issue-4808.rs", - - // Negative inherent impl: `impl !Box<JoinHandle> {}` - "src/tools/rustfmt/tests/source/negative-impl.rs", - "src/tools/rustfmt/tests/target/negative-impl.rs", - - // Compile-fail expr parameter in const generic position: `f::<1 + 2>()` - "tests/ui/const-generics/early/closing-args-token.rs", - "tests/ui/const-generics/early/const-expression-parameter.rs", - - // Compile-fail variadics in not the last position of a function parameter list - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/fn_def_param.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_vararg.rs", - "tests/ui/parser/variadic-ffi-syntactic-pass.rs", - - // Need at least one trait in impl Trait, no such type as impl 'static - "tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs", - - // Negative polarity trait bound: `where T: !Copy` - "src/tools/rustfmt/tests/target/negative-bounds.rs", - "tests/ui/traits/negative-bounds/supertrait.rs", - - // Const impl that is not a trait impl: `impl ~const T {}` - "tests/ui/traits/const-traits/syntax.rs", - - // Lifetimes and types out of order in angle bracketed path arguments - "tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs", - - // Deprecated anonymous parameter syntax in traits - "src/tools/rustfmt/tests/source/trait.rs", - "src/tools/rustfmt/tests/target/trait.rs", - "tests/pretty/hir-fn-params.rs", - "tests/rustdoc-html/anon-fn-params.rs", - "tests/rustdoc-html/auxiliary/ext-anon-fn-params.rs", - "tests/ui/anon-params/anon-params-trait-method-multiple.rs", - "tests/ui/fn/anonymous-parameters-trait-13105.rs", - "tests/ui/proc-macro/trait-fn-args-2015.rs", - "tests/ui/trait-bounds/anonymous-parameters-13775.rs", - - // Deprecated where-clause location - "src/tools/rustfmt/tests/source/issue_4257.rs", - "src/tools/rustfmt/tests/source/issue_4911.rs", - "src/tools/rustfmt/tests/target/issue_4257.rs", - "src/tools/rustfmt/tests/target/issue_4911.rs", - "tests/pretty/gat-bounds.rs", - - // Deprecated trait object syntax with parenthesized generic arguments and no dyn keyword - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rs", - "src/tools/rustfmt/tests/source/attrib.rs", - "src/tools/rustfmt/tests/source/closure.rs", - "src/tools/rustfmt/tests/source/existential_type.rs", - "src/tools/rustfmt/tests/source/fn-simple.rs", - "src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs", - "src/tools/rustfmt/tests/source/issue-4689/one.rs", - "src/tools/rustfmt/tests/source/issue-4689/two.rs", - "src/tools/rustfmt/tests/source/paths.rs", - "src/tools/rustfmt/tests/source/structs.rs", - "src/tools/rustfmt/tests/target/attrib.rs", - "src/tools/rustfmt/tests/target/closure.rs", - "src/tools/rustfmt/tests/target/existential_type.rs", - "src/tools/rustfmt/tests/target/fn-simple.rs", - "src/tools/rustfmt/tests/target/fn.rs", - "src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs", - "src/tools/rustfmt/tests/target/issue-4689/one.rs", - "src/tools/rustfmt/tests/target/issue-4689/two.rs", - "src/tools/rustfmt/tests/target/paths.rs", - "src/tools/rustfmt/tests/target/structs.rs", - "tests/codegen-units/item-collection/non-generic-closures.rs", - "tests/debuginfo/recursive-enum.rs", - "tests/pretty/closure-reform-pretty.rs", - "tests/run-make/reproducible-build-2/reproducible-build.rs", - "tests/run-make/reproducible-build/reproducible-build.rs", - "tests/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs", - "tests/ui/lifetimes/auxiliary/lifetime_bound_will_change_warning_lib.rs", - "tests/ui/lifetimes/bare-trait-object-borrowck.rs", - "tests/ui/lifetimes/bare-trait-object.rs", - "tests/ui/parser/bounds-obj-parens.rs", - - // Various extensions to Rust syntax made up by rust-analyzer - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/const_param_default_path.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/deref_pat.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/global_asm.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/include_bytes.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/not_null_pat.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/pattern_type.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/question_for_type_trait_bound.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/try_block_expr.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_const.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/use_tree_abs_star.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0224_dangling_dyn.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0261_dangling_impl_undeclared_lifetime.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/dangling_impl_reference.rs", - "src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rs", - - // Placeholder syntax for "throw expressions" - "compiler/rustc_expand/src/module.rs", - "compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs", - "src/tools/clippy/tests/ui/needless_return.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/yeet_expr.rs", - "tests/pretty/yeet-expr.rs", - "tests/ui/contracts/contracts-ensures-early-fn-exit.rs", - "tests/ui/try-trait/yeet-for-option.rs", - "tests/ui/try-trait/yeet-for-result.rs", - - // Edition 2015 code using identifiers that are now keywords - // TODO: some of these we should probably parse - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rs", - "src/tools/rustfmt/tests/source/configs/indent_style/block_call.rs", - "src/tools/rustfmt/tests/source/configs/use_try_shorthand/false.rs", - "src/tools/rustfmt/tests/source/configs/use_try_shorthand/true.rs", - "src/tools/rustfmt/tests/source/issue_1306.rs", - "src/tools/rustfmt/tests/source/try-conversion.rs", - "src/tools/rustfmt/tests/target/configs/indent_style/block_call.rs", - "src/tools/rustfmt/tests/target/configs/use_try_shorthand/false.rs", - "src/tools/rustfmt/tests/target/issue-1681.rs", - "src/tools/rustfmt/tests/target/issue_1306.rs", - "tests/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs", - "tests/ui/editions/edition-keywords-2015-2015.rs", - "tests/ui/editions/edition-keywords-2015-2018.rs", - "tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs", - "tests/ui/lint/lint_pre_expansion_extern_module_aux.rs", - "tests/ui/macros/macro-comma-support-rpass.rs", - "tests/ui/macros/try-macro.rs", - "tests/ui/parser/extern-crate-async.rs", - "tests/ui/try-block/try-is-identifier-edition2015.rs", - - // Excessive nesting - "tests/ui/expr/if/expr-stack-overflow.rs", - - // Testing tools on invalid syntax - "src/tools/clippy/tests/ui/non_expressive_names_error_recovery.rs", - "src/tools/rustfmt/tests/coverage/target/comments.rs", - "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs", - "src/tools/rustfmt/tests/parser/issue_4418.rs", - "src/tools/rustfmt/tests/parser/stashed-diag.rs", - "src/tools/rustfmt/tests/parser/stashed-diag2.rs", - "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs", - "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs", - "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs", - "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs", - "src/tools/rustfmt/tests/source/type.rs", - "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs", - "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs", - "src/tools/rustfmt/tests/target/type.rs", - "src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs", - "tests/ui/generics/issue-94432-garbage-ice.rs", - - // Not actually test cases - "tests/ui/lint/expansion-time-include.rs", - "tests/ui/macros/auxiliary/macro-comma-support.rs", - "tests/ui/macros/auxiliary/macro-include-items-expr.rs", - "tests/ui/macros/include-single-expr-helper.rs", - "tests/ui/macros/include-single-expr-helper-1.rs", - "tests/ui/parser/issues/auxiliary/issue-21146-inc.rs", -]; - -#[rustfmt::skip] -static EXCLUDE_DIRS: &[&str] = &[ - // Inputs that intentionally do not parse - "src/tools/rust-analyzer/crates/parser/test_data/parser/err", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err", - - // Inputs that lex but do not necessarily parse - "src/tools/rust-analyzer/crates/parser/test_data/lexer", - - // Inputs that used to crash rust-analyzer, but aren't necessarily supposed to parse - "src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures", - "src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures", - - // Inputs that crash rustc, making no claim about whether they are valid Rust - "tests/crashes", -]; - -// Directories in which a .stderr implies the corresponding .rs is not expected -// to work. -static UI_TEST_DIRS: &[&str] = &["tests/ui", "tests/rustdoc-ui"]; - -pub fn for_each_rust_file(for_each: impl Fn(&Path) + Sync + Send) { - let mut rs_files = BTreeSet::new(); - - let repo_dir = Path::new("tests/rust"); - for entry in WalkDir::new(repo_dir).into_iter().filter_entry(base_dir_filter) { - let entry = entry.unwrap(); - if !entry.file_type().is_dir() { - rs_files.insert(entry.into_path()); - } - } - - for ui_test_dir in UI_TEST_DIRS { - for entry in WalkDir::new(repo_dir.join(ui_test_dir)) { - let mut path = entry.unwrap().into_path(); - if path.extension() == Some(OsStr::new("stderr")) { - loop { - rs_files.remove(&path.with_extension("rs")); - path = path.with_extension(""); - if path.extension().is_none() { - break; - } - } - } - } - } - - rs_files.par_iter().map(PathBuf::as_path).for_each(for_each); -} - -pub fn base_dir_filter(entry: &DirEntry) -> bool { - let path = entry.path(); - - let mut path_string = path.to_string_lossy(); - if cfg!(windows) { - path_string = path_string.replace('\\', "/").into(); - } - let path_string = if path_string == "tests/rust" { - return true; - } else if let Some(path) = path_string.strip_prefix("tests/rust/") { - path - } else { - panic!("unexpected path in Rust dist: {}", path_string); - }; - - if path.is_dir() { - return !EXCLUDE_DIRS.contains(&path_string); - } - - if path.extension() != Some(OsStr::new("rs")) { - return false; - } - - !EXCLUDE_FILES.contains(&path_string) -} - -#[allow(dead_code)] -pub fn edition(path: &Path) -> &'static str { - if path.ends_with("dyn-2015-no-warnings-without-lints.rs") { - "2015" - } else { - "2021" - } -} - -#[allow(dead_code)] -pub fn abort_after() -> usize { - match env::var("ABORT_AFTER_FAILURE") { - Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"), - Err(_) => usize::MAX, - } -} - -pub fn rayon_init() { - let stack_size = match env::var("RUST_MIN_STACK") { - Ok(s) => s.parse().expect("failed to parse RUST_MIN_STACK"), - Err(_) => 1024 * 1024 * if cfg!(debug_assertions) { 40 } else { 20 }, - }; - ThreadPoolBuilder::new().stack_size(stack_size).build_global().unwrap(); -} - -pub fn clone_rust() { - let needs_clone = match fs::read_to_string("tests/rust/COMMIT") { - Err(_) => true, - Ok(contents) => contents.trim() != REVISION, - }; - if needs_clone { - download_and_unpack().unwrap(); - } - - let mut missing = String::new(); - let test_src = Path::new("tests/rust"); - - let mut exclude_files_set = BTreeSet::new(); - for exclude in EXCLUDE_FILES { - if !exclude_files_set.insert(exclude) { - panic!("duplicate path in EXCLUDE_FILES: {}", exclude); - } - for dir in EXCLUDE_DIRS { - if Path::new(exclude).starts_with(dir) { - panic!("excluded file {} is inside an excluded dir", exclude); - } - } - if !test_src.join(exclude).is_file() { - missing += "\ntests/rust/"; - missing += exclude; - } - } - - let mut exclude_dirs_set = BTreeSet::new(); - for exclude in EXCLUDE_DIRS { - if !exclude_dirs_set.insert(exclude) { - panic!("duplicate path in EXCLUDE_DIRS: {}", exclude); - } - if !test_src.join(exclude).is_dir() { - missing += "\ntests/rust/"; - missing += exclude; - missing += "/"; - } - } - - if !missing.is_empty() { - panic!("excluded test file does not exist:{}\n", missing); - } -} - -fn download_and_unpack() -> Result<()> { - let url = format!("https://github.com/rust-lang/rust/archive/{REVISION}.tar.gz"); - errorf!("downloading {url}\n"); - - let response = reqwest::blocking::get(url)?.error_for_status()?; - let progress = Progress::new(response); - let decoder = GzDecoder::new(progress); - let mut archive = Archive::new(decoder); - let prefix = format!("rust-{}", REVISION); - - let tests_rust = Path::new("tests/rust"); - if tests_rust.exists() { - fs::remove_dir_all(tests_rust)?; - } - - for entry in archive.entries()? { - let mut entry = entry?; - let path = entry.path()?; - if path == Path::new("pax_global_header") { - continue; - } - let relative = path.strip_prefix(&prefix)?; - let out = tests_rust.join(relative); - entry.unpack(&out)?; - } - - fs::write("tests/rust/COMMIT", REVISION)?; - Ok(()) -} diff --git a/deps/crates/vendor/syn-v2/tests/repo/progress.rs b/deps/crates/vendor/syn-v2/tests/repo/progress.rs deleted file mode 100644 index 9e1e9a49b2b6..000000000000 --- a/deps/crates/vendor/syn-v2/tests/repo/progress.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::io::{Read, Result}; -use std::time::{Duration, Instant}; - -pub struct Progress<R> { - bytes: usize, - tick: Instant, - stream: R, -} - -impl<R> Progress<R> { - pub fn new(stream: R) -> Self { - Progress { bytes: 0, tick: Instant::now() + Duration::from_secs(2), stream } - } -} - -impl<R: Read> Read for Progress<R> { - fn read(&mut self, buf: &mut [u8]) -> Result<usize> { - let num = self.stream.read(buf)?; - self.bytes += num; - let now = Instant::now(); - if now > self.tick { - self.tick = now + Duration::from_millis(500); - errorf!("downloading... {} bytes\n", self.bytes); - } - Ok(num) - } -} - -impl<R> Drop for Progress<R> { - fn drop(&mut self) { - errorf!("done ({} bytes)\n", self.bytes); - } -} diff --git a/deps/crates/vendor/syn-v2/tests/snapshot/mod.rs b/deps/crates/vendor/syn-v2/tests/snapshot/mod.rs deleted file mode 100644 index 98d2aebc9d30..000000000000 --- a/deps/crates/vendor/syn-v2/tests/snapshot/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![allow(unused_macros, unused_macro_rules)] - -use std::str::FromStr; -use syn::parse::Result; - -macro_rules! snapshot { - ($($args:tt)*) => { - snapshot_impl!(() $($args)*) - }; -} - -macro_rules! snapshot_impl { - (($expr:ident) as $t:ty, @$snapshot:literal) => { - let tokens = crate::snapshot::TryIntoTokens::try_into_tokens($expr).unwrap(); - let $expr: $t = syn::parse_quote!(#tokens); - let debug = crate::debug::Lite(&$expr); - if !cfg!(miri) { - #[allow(clippy::needless_raw_string_hashes)] // https://github.com/mitsuhiko/insta/issues/389 - { - insta::assert_debug_snapshot!(debug, @$snapshot); - } - } - }; - (($($expr:tt)*) as $t:ty, @$snapshot:literal) => {{ - let tokens = crate::snapshot::TryIntoTokens::try_into_tokens($($expr)*).unwrap(); - let syntax_tree: $t = syn::parse_quote!(#tokens); - let debug = crate::debug::Lite(&syntax_tree); - if !cfg!(miri) { - #[allow(clippy::needless_raw_string_hashes)] - { - insta::assert_debug_snapshot!(debug, @$snapshot); - } - } - syntax_tree - }}; - (($($expr:tt)*) , @$snapshot:literal) => {{ - let syntax_tree = $($expr)*; - let debug = crate::debug::Lite(&syntax_tree); - if !cfg!(miri) { - #[allow(clippy::needless_raw_string_hashes)] - { - insta::assert_debug_snapshot!(debug, @$snapshot); - } - } - syntax_tree - }}; - (($($expr:tt)*) $next:tt $($rest:tt)*) => { - snapshot_impl!(($($expr)* $next) $($rest)*) - }; -} - -pub trait TryIntoTokens { - #[allow(dead_code)] - fn try_into_tokens(self) -> Result<proc_macro2::TokenStream>; -} - -impl TryIntoTokens for &str { - fn try_into_tokens(self) -> Result<proc_macro2::TokenStream> { - let tokens = proc_macro2::TokenStream::from_str(self)?; - Ok(tokens) - } -} - -impl TryIntoTokens for proc_macro2::TokenStream { - fn try_into_tokens(self) -> Result<proc_macro2::TokenStream> { - Ok(self) - } -} diff --git a/deps/crates/vendor/syn-v2/tests/test_asyncness.rs b/deps/crates/vendor/syn-v2/tests/test_asyncness.rs deleted file mode 100644 index c7aee3285bb2..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_asyncness.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use syn::{Expr, Item}; - -#[test] -fn test_async_fn() { - let input = "async fn process() {}"; - - snapshot!(input as Item, @r#" - Item::Fn { - vis: Visibility::Inherited, - sig: Signature { - asyncness: Some, - ident: "process", - generics: Generics, - output: ReturnType::Default, - }, - block: Block { - stmts: [], - }, - } - "#); -} - -#[test] -fn test_async_closure() { - let input = "async || {}"; - - snapshot!(input as Expr, @r#" - Expr::Closure { - asyncness: Some, - output: ReturnType::Default, - body: Expr::Block { - block: Block { - stmts: [], - }, - }, - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_attribute.rs b/deps/crates/vendor/syn-v2/tests/test_attribute.rs deleted file mode 100644 index 81c485e6b28f..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_attribute.rs +++ /dev/null @@ -1,231 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use syn::parse::Parser; -use syn::{Attribute, Meta}; - -#[test] -fn test_meta_item_word() { - let meta = test("#[foo]"); - - snapshot!(meta, @r#" - Meta::Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - } - "#); -} - -#[test] -fn test_meta_item_name_value() { - let meta = test("#[foo = 5]"); - - snapshot!(meta, @r#" - Meta::NameValue { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - value: Expr::Lit { - lit: 5, - }, - } - "#); -} - -#[test] -fn test_meta_item_bool_value() { - let meta = test("#[foo = true]"); - - snapshot!(meta, @r#" - Meta::NameValue { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - value: Expr::Lit { - lit: Lit::Bool { - value: true, - }, - }, - } - "#); - - let meta = test("#[foo = false]"); - - snapshot!(meta, @r#" - Meta::NameValue { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - value: Expr::Lit { - lit: Lit::Bool { - value: false, - }, - }, - } - "#); -} - -#[test] -fn test_meta_item_list_lit() { - let meta = test("#[foo(5)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`5`), - } - "#); -} - -#[test] -fn test_meta_item_list_word() { - let meta = test("#[foo(bar)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`bar`), - } - "#); -} - -#[test] -fn test_meta_item_list_name_value() { - let meta = test("#[foo(bar = 5)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`bar = 5`), - } - "#); -} - -#[test] -fn test_meta_item_list_bool_value() { - let meta = test("#[foo(bar = true)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`bar = true`), - } - "#); -} - -#[test] -fn test_meta_item_multiple() { - let meta = test("#[foo(word, name = 5, list(name2 = 6), word2)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`word , name = 5 , list (name2 = 6) , word2`), - } - "#); -} - -#[test] -fn test_bool_lit() { - let meta = test("#[foo(true)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`true`), - } - "#); -} - -#[test] -fn test_negative_lit() { - let meta = test("#[form(min = -1, max = 200)]"); - - snapshot!(meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "form", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`min = - 1 , max = 200`), - } - "#); -} - -fn test(input: &str) -> Meta { - let attrs = Attribute::parse_outer.parse_str(input).unwrap(); - - assert_eq!(attrs.len(), 1); - let attr = attrs.into_iter().next().unwrap(); - - attr.meta -} diff --git a/deps/crates/vendor/syn-v2/tests/test_derive_input.rs b/deps/crates/vendor/syn-v2/tests/test_derive_input.rs deleted file mode 100644 index 790e2792adb3..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_derive_input.rs +++ /dev/null @@ -1,785 +0,0 @@ -#![allow( - clippy::assertions_on_result_states, - clippy::elidable_lifetime_names, - clippy::manual_let_else, - clippy::needless_lifetimes, - clippy::too_many_lines, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use quote::quote; -use syn::{Data, DeriveInput}; - -#[test] -fn test_unit() { - let input = quote! { - struct Unit; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "Unit", - generics: Generics, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); -} - -#[test] -fn test_struct() { - let input = quote! { - #[derive(Debug, Clone)] - pub struct Item { - pub ident: Ident, - pub attrs: Vec<Attribute> - } - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "derive", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`Debug , Clone`), - }, - }, - ], - vis: Visibility::Public, - ident: "Item", - generics: Generics, - data: Data::Struct { - fields: Fields::Named { - named: [ - Field { - vis: Visibility::Public, - ident: Some("ident"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Ident", - }, - ], - }, - }, - }, - Token![,], - Field { - vis: Visibility::Public, - ident: Some("attrs"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Vec", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Attribute", - }, - ], - }, - }), - ], - }, - }, - ], - }, - }, - }, - ], - }, - }, - } - "#); - - snapshot!(&input.attrs[0].meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "derive", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`Debug , Clone`), - } - "#); -} - -#[test] -fn test_union() { - let input = quote! { - union MaybeUninit<T> { - uninit: (), - value: T - } - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "MaybeUninit", - generics: Generics { - lt_token: Some, - params: [ - GenericParam::Type(TypeParam { - ident: "T", - }), - ], - gt_token: Some, - }, - data: Data::Union { - fields: FieldsNamed { - named: [ - Field { - vis: Visibility::Inherited, - ident: Some("uninit"), - colon_token: Some, - ty: Type::Tuple, - }, - Token![,], - Field { - vis: Visibility::Inherited, - ident: Some("value"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }, - }, - ], - }, - }, - } - "#); -} - -#[test] -#[cfg(feature = "full")] -fn test_enum() { - let input = quote! { - /// See the std::result module documentation for details. - #[must_use] - pub enum Result<T, E> { - Ok(T), - Err(E), - Surprise = 0isize, - - // Smuggling data into a proc_macro_derive, - // in the style of https://github.com/dtolnay/proc-macro-hack - ProcMacroHack = (0, "data").0 - } - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::NameValue { - path: Path { - segments: [ - PathSegment { - ident: "doc", - }, - ], - }, - value: Expr::Lit { - lit: " See the std::result module documentation for details.", - }, - }, - }, - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "must_use", - }, - ], - }, - }, - ], - vis: Visibility::Public, - ident: "Result", - generics: Generics { - lt_token: Some, - params: [ - GenericParam::Type(TypeParam { - ident: "T", - }), - Token![,], - GenericParam::Type(TypeParam { - ident: "E", - }), - ], - gt_token: Some, - }, - data: Data::Enum { - variants: [ - Variant { - ident: "Ok", - fields: Fields::Unnamed { - unnamed: [ - Field { - vis: Visibility::Inherited, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }, - }, - ], - }, - }, - Token![,], - Variant { - ident: "Err", - fields: Fields::Unnamed { - unnamed: [ - Field { - vis: Visibility::Inherited, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "E", - }, - ], - }, - }, - }, - ], - }, - }, - Token![,], - Variant { - ident: "Surprise", - fields: Fields::Unit, - discriminant: Some(Expr::Lit { - lit: 0isize, - }), - }, - Token![,], - Variant { - ident: "ProcMacroHack", - fields: Fields::Unit, - discriminant: Some(Expr::Field { - base: Expr::Tuple { - elems: [ - Expr::Lit { - lit: 0, - }, - Token![,], - Expr::Lit { - lit: "data", - }, - ], - }, - member: Member::Unnamed(Index { - index: 0, - }), - }), - }, - ], - }, - } - "#); - - let meta_items: Vec<_> = input.attrs.into_iter().map(|attr| attr.meta).collect(); - - snapshot!(meta_items, @r#" - [ - Meta::NameValue { - path: Path { - segments: [ - PathSegment { - ident: "doc", - }, - ], - }, - value: Expr::Lit { - lit: " See the std::result module documentation for details.", - }, - }, - Meta::Path { - segments: [ - PathSegment { - ident: "must_use", - }, - ], - }, - ] - "#); -} - -#[test] -fn test_attr_with_non_mod_style_path() { - let input = quote! { - #[inert <T>] - struct S; - }; - - syn::parse2::<DeriveInput>(input).unwrap_err(); -} - -#[test] -fn test_attr_with_mod_style_path_with_self() { - let input = quote! { - #[foo::self] - struct S; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "foo", - }, - Token![::], - PathSegment { - ident: "self", - }, - ], - }, - }, - ], - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); - - snapshot!(&input.attrs[0].meta, @r#" - Meta::Path { - segments: [ - PathSegment { - ident: "foo", - }, - Token![::], - PathSegment { - ident: "self", - }, - ], - } - "#); -} - -#[test] -fn test_pub_restricted() { - // Taken from tests/rust/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs - let input = quote! { - pub(in m) struct Z(pub(in m::n) u8); - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Restricted { - in_token: Some, - path: Path { - segments: [ - PathSegment { - ident: "m", - }, - ], - }, - }, - ident: "Z", - generics: Generics, - data: Data::Struct { - fields: Fields::Unnamed { - unnamed: [ - Field { - vis: Visibility::Restricted { - in_token: Some, - path: Path { - segments: [ - PathSegment { - ident: "m", - }, - Token![::], - PathSegment { - ident: "n", - }, - ], - }, - }, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "u8", - }, - ], - }, - }, - }, - ], - }, - semi_token: Some, - }, - } - "#); -} - -#[test] -fn test_pub_restricted_crate() { - let input = quote! { - pub(crate) struct S; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Restricted { - path: Path { - segments: [ - PathSegment { - ident: "crate", - }, - ], - }, - }, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); -} - -#[test] -fn test_pub_restricted_super() { - let input = quote! { - pub(super) struct S; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Restricted { - path: Path { - segments: [ - PathSegment { - ident: "super", - }, - ], - }, - }, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); -} - -#[test] -fn test_pub_restricted_in_super() { - let input = quote! { - pub(in super) struct S; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Restricted { - in_token: Some, - path: Path { - segments: [ - PathSegment { - ident: "super", - }, - ], - }, - }, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); -} - -#[test] -fn test_fields_on_unit_struct() { - let input = quote! { - struct S; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); - - let data = match input.data { - Data::Struct(data) => data, - _ => panic!("expected a struct"), - }; - - assert_eq!(0, data.fields.iter().count()); -} - -#[test] -fn test_fields_on_named_struct() { - let input = quote! { - struct S { - foo: i32, - pub bar: String, - } - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Named { - named: [ - Field { - vis: Visibility::Inherited, - ident: Some("foo"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "i32", - }, - ], - }, - }, - }, - Token![,], - Field { - vis: Visibility::Public, - ident: Some("bar"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "String", - }, - ], - }, - }, - }, - Token![,], - ], - }, - }, - } - "#); - - let data = match input.data { - Data::Struct(data) => data, - _ => panic!("expected a struct"), - }; - - snapshot!(data.fields.into_iter().collect::<Vec<_>>(), @r#" - [ - Field { - vis: Visibility::Inherited, - ident: Some("foo"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "i32", - }, - ], - }, - }, - }, - Field { - vis: Visibility::Public, - ident: Some("bar"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "String", - }, - ], - }, - }, - }, - ] - "#); -} - -#[test] -fn test_fields_on_tuple_struct() { - let input = quote! { - struct S(i32, pub String); - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unnamed { - unnamed: [ - Field { - vis: Visibility::Inherited, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "i32", - }, - ], - }, - }, - }, - Token![,], - Field { - vis: Visibility::Public, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "String", - }, - ], - }, - }, - }, - ], - }, - semi_token: Some, - }, - } - "#); - - let data = match input.data { - Data::Struct(data) => data, - _ => panic!("expected a struct"), - }; - - snapshot!(data.fields.iter().collect::<Vec<_>>(), @r#" - [ - Field { - vis: Visibility::Inherited, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "i32", - }, - ], - }, - }, - }, - Field { - vis: Visibility::Public, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "String", - }, - ], - }, - }, - }, - ] - "#); -} - -#[test] -fn test_ambiguous_crate() { - let input = quote! { - // The field type is `(crate::X)` not `crate (::X)`. - struct S(crate::X); - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unnamed { - unnamed: [ - Field { - vis: Visibility::Inherited, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "crate", - }, - Token![::], - PathSegment { - ident: "X", - }, - ], - }, - }, - }, - ], - }, - semi_token: Some, - }, - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_expr.rs b/deps/crates/vendor/syn-v2/tests/test_expr.rs deleted file mode 100644 index e21373cf96d8..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_expr.rs +++ /dev/null @@ -1,1702 +0,0 @@ -#![cfg(not(miri))] -#![recursion_limit = "1024"] -#![feature(rustc_private)] -#![allow( - clippy::elidable_lifetime_names, - clippy::match_like_matches_macro, - clippy::needless_lifetimes, - clippy::single_element_loop, - clippy::too_many_lines, - clippy::uninlined_format_args, - clippy::unreadable_literal -)] - -#[macro_use] -mod macros; -#[macro_use] -mod snapshot; - -mod common; -mod debug; - -use crate::common::visit::{AsIfPrinted, FlattenParens}; -use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream}; -use quote::{quote, ToTokens as _}; -use std::process::ExitCode; -use syn::punctuated::Punctuated; -use syn::visit_mut::VisitMut as _; -use syn::{ - parse_quote, token, AngleBracketedGenericArguments, Arm, BinOp, Block, Expr, ExprArray, - ExprAssign, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBreak, ExprCall, ExprCast, - ExprClosure, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprIf, ExprIndex, ExprLet, - ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprPath, ExprRange, ExprRawAddr, - ExprReference, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnary, ExprUnsafe, - ExprWhile, ExprYield, GenericArgument, Label, Lifetime, Lit, LitInt, Macro, MacroDelimiter, - Member, Pat, PatWild, Path, PathArguments, PathSegment, PointerMutability, QSelf, RangeLimits, - ReturnType, Stmt, Token, Type, TypePath, UnOp, -}; - -#[test] -fn test_expr_parse() { - let tokens = quote!(..100u32); - snapshot!(tokens as Expr, @r#" - Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Lit { - lit: 100u32, - }), - } - "#); - - let tokens = quote!(..100u32); - snapshot!(tokens as ExprRange, @r#" - ExprRange { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Lit { - lit: 100u32, - }), - } - "#); -} - -#[test] -fn test_await() { - // Must not parse as Expr::Field. - let tokens = quote!(fut.await); - - snapshot!(tokens as Expr, @r#" - Expr::Await { - base: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "fut", - }, - ], - }, - }, - } - "#); -} - -#[rustfmt::skip] -#[test] -fn test_tuple_multi_index() { - let expected = snapshot!("tuple.0.0" as Expr, @r#" - Expr::Field { - base: Expr::Field { - base: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "tuple", - }, - ], - }, - }, - member: Member::Unnamed(Index { - index: 0, - }), - }, - member: Member::Unnamed(Index { - index: 0, - }), - } - "#); - - for &input in &[ - "tuple .0.0", - "tuple. 0.0", - "tuple.0 .0", - "tuple.0. 0", - "tuple . 0 . 0", - ] { - assert_eq!(expected, syn::parse_str(input).unwrap()); - } - - for tokens in [ - quote!(tuple.0.0), - quote!(tuple .0.0), - quote!(tuple. 0.0), - quote!(tuple.0 .0), - quote!(tuple.0. 0), - quote!(tuple . 0 . 0), - ] { - assert_eq!(expected, syn::parse2(tokens).unwrap()); - } -} - -#[test] -fn test_macro_variable_func() { - // mimics the token stream corresponding to `$fn()` - let path = Group::new(Delimiter::None, quote!(f)); - let tokens = quote!(#path()); - - snapshot!(tokens as Expr, @r#" - Expr::Call { - func: Expr::Group { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "f", - }, - ], - }, - }, - }, - } - "#); - - let path = Group::new(Delimiter::None, quote! { #[inside] f }); - let tokens = quote!(#[outside] #path()); - - snapshot!(tokens as Expr, @r#" - Expr::Call { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "outside", - }, - ], - }, - }, - ], - func: Expr::Group { - expr: Expr::Path { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "inside", - }, - ], - }, - }, - ], - path: Path { - segments: [ - PathSegment { - ident: "f", - }, - ], - }, - }, - }, - } - "#); -} - -#[test] -fn test_macro_variable_macro() { - // mimics the token stream corresponding to `$macro!()` - let mac = Group::new(Delimiter::None, quote!(m)); - let tokens = quote!(#mac!()); - - snapshot!(tokens as Expr, @r#" - Expr::Macro { - mac: Macro { - path: Path { - segments: [ - PathSegment { - ident: "m", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(``), - }, - } - "#); -} - -#[test] -fn test_macro_variable_struct() { - // mimics the token stream corresponding to `$struct {}` - let s = Group::new(Delimiter::None, quote! { S }); - let tokens = quote!(#s {}); - - snapshot!(tokens as Expr, @r#" - Expr::Struct { - path: Path { - segments: [ - PathSegment { - ident: "S", - }, - ], - }, - } - "#); -} - -#[test] -fn test_macro_variable_unary() { - // mimics the token stream corresponding to `$expr.method()` where expr is `&self` - let inner = Group::new(Delimiter::None, quote!(&self)); - let tokens = quote!(#inner.method()); - snapshot!(tokens as Expr, @r#" - Expr::MethodCall { - receiver: Expr::Group { - expr: Expr::Reference { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "self", - }, - ], - }, - }, - }, - }, - method: "method", - } - "#); -} - -#[test] -fn test_macro_variable_match_arm() { - // mimics the token stream corresponding to `match v { _ => $expr }` - let expr = Group::new(Delimiter::None, quote! { #[a] () }); - let tokens = quote!(match v { _ => #expr }); - snapshot!(tokens as Expr, @r#" - Expr::Match { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "v", - }, - ], - }, - }, - arms: [ - Arm { - pat: Pat::Wild, - body: Expr::Group { - expr: Expr::Tuple { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "a", - }, - ], - }, - }, - ], - }, - }, - }, - ], - } - "#); - - let expr = Group::new(Delimiter::None, quote!(loop {} + 1)); - let tokens = quote!(match v { _ => #expr }); - snapshot!(tokens as Expr, @r#" - Expr::Match { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "v", - }, - ], - }, - }, - arms: [ - Arm { - pat: Pat::Wild, - body: Expr::Group { - expr: Expr::Binary { - left: Expr::Loop { - body: Block { - stmts: [], - }, - }, - op: BinOp::Add, - right: Expr::Lit { - lit: 1, - }, - }, - }, - }, - ], - } - "#); -} - -// https://github.com/dtolnay/syn/issues/1019 -#[test] -fn test_closure_vs_rangefull() { - #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808 - let tokens = quote!(|| .. .method()); - snapshot!(tokens as Expr, @r#" - Expr::MethodCall { - receiver: Expr::Closure { - output: ReturnType::Default, - body: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - method: "method", - } - "#); -} - -#[test] -fn test_postfix_operator_after_cast() { - syn::parse_str::<Expr>("|| &x as T[0]").unwrap_err(); - syn::parse_str::<Expr>("|| () as ()()").unwrap_err(); -} - -#[test] -fn test_range_kinds() { - syn::parse_str::<Expr>("..").unwrap(); - syn::parse_str::<Expr>("..hi").unwrap(); - syn::parse_str::<Expr>("lo..").unwrap(); - syn::parse_str::<Expr>("lo..hi").unwrap(); - - syn::parse_str::<Expr>("..=").unwrap_err(); - syn::parse_str::<Expr>("..=hi").unwrap(); - syn::parse_str::<Expr>("lo..=").unwrap_err(); - syn::parse_str::<Expr>("lo..=hi").unwrap(); - - syn::parse_str::<Expr>("...").unwrap_err(); - syn::parse_str::<Expr>("...hi").unwrap_err(); - syn::parse_str::<Expr>("lo...").unwrap_err(); - syn::parse_str::<Expr>("lo...hi").unwrap_err(); -} - -#[test] -fn test_range_precedence() { - snapshot!(".. .." as Expr, @r#" - Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - } - "#); - - snapshot!(".. .. ()" as Expr, @r#" - Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Tuple), - }), - } - "#); - - snapshot!("() .. .." as Expr, @r#" - Expr::Range { - start: Some(Expr::Tuple), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - } - "#); - - snapshot!("() = .. + ()" as Expr, @r" - Expr::Binary { - left: Expr::Assign { - left: Expr::Tuple, - right: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - op: BinOp::Add, - right: Expr::Tuple, - } - "); - - // A range with a lower bound cannot be the upper bound of another range, - // and a range with an upper bound cannot be the lower bound of another - // range. - syn::parse_str::<Expr>(".. x ..").unwrap_err(); - syn::parse_str::<Expr>("x .. x ..").unwrap_err(); -} - -#[test] -fn test_range_attrs() { - // Attributes are not allowed on range expressions starting with `..` - syn::parse_str::<Expr>("#[allow()] ..").unwrap_err(); - syn::parse_str::<Expr>("#[allow()] .. hi").unwrap_err(); - - snapshot!("#[allow()] lo .. hi" as Expr, @r#" - Expr::Range { - start: Some(Expr::Path { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "allow", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(``), - }, - }, - ], - path: Path { - segments: [ - PathSegment { - ident: "lo", - }, - ], - }, - }), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "hi", - }, - ], - }, - }), - } - "#); -} - -#[test] -fn test_ranges_bailout() { - syn::parse_str::<Expr>(".. ?").unwrap_err(); - syn::parse_str::<Expr>(".. .field").unwrap_err(); - - snapshot!("return .. ?" as Expr, @r" - Expr::Try { - expr: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - } - "); - - snapshot!("break .. ?" as Expr, @r" - Expr::Try { - expr: Expr::Break { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - } - "); - - snapshot!("|| .. ?" as Expr, @r" - Expr::Try { - expr: Expr::Closure { - output: ReturnType::Default, - body: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - } - "); - - snapshot!("return .. .field" as Expr, @r#" - Expr::Field { - base: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - member: Member::Named("field"), - } - "#); - - snapshot!("break .. .field" as Expr, @r#" - Expr::Field { - base: Expr::Break { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - member: Member::Named("field"), - } - "#); - - snapshot!("|| .. .field" as Expr, @r#" - Expr::Field { - base: Expr::Closure { - output: ReturnType::Default, - body: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - member: Member::Named("field"), - } - "#); - - snapshot!("return .. = ()" as Expr, @r" - Expr::Assign { - left: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - right: Expr::Tuple, - } - "); - - snapshot!("return .. += ()" as Expr, @r" - Expr::Binary { - left: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - op: BinOp::AddAssign, - right: Expr::Tuple, - } - "); -} - -#[test] -fn test_ambiguous_label() { - for stmt in [ - quote! { - return 'label: loop { break 'label 42; }; - }, - quote! { - break ('label: loop { break 'label 42; }); - }, - quote! { - break 1 + 'label: loop { break 'label 42; }; - }, - quote! { - break 'outer 'inner: loop { break 'inner 42; }; - }, - ] { - syn::parse2::<Stmt>(stmt).unwrap(); - } - - for stmt in [ - // Parentheses required. See https://github.com/rust-lang/rust/pull/87026. - quote! { - break 'label: loop { break 'label 42; }; - }, - ] { - syn::parse2::<Stmt>(stmt).unwrap_err(); - } -} - -#[test] -fn test_extended_interpolated_path() { - let path = Group::new(Delimiter::None, quote!(a::b)); - - let tokens = quote!(if #path {}); - snapshot!(tokens as Expr, @r#" - Expr::If { - cond: Expr::Group { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - ], - }, - }, - }, - then_branch: Block { - stmts: [], - }, - } - "#); - - let tokens = quote!(#path {}); - snapshot!(tokens as Expr, @r#" - Expr::Struct { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - ], - }, - } - "#); - - let tokens = quote!(#path :: c); - snapshot!(tokens as Expr, @r#" - Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - Token![::], - PathSegment { - ident: "c", - }, - ], - }, - } - "#); - - let nested = Group::new(Delimiter::None, quote!(a::b || true)); - let tokens = quote!(if #nested && false {}); - snapshot!(tokens as Expr, @r#" - Expr::If { - cond: Expr::Binary { - left: Expr::Group { - expr: Expr::Binary { - left: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - ], - }, - }, - op: BinOp::Or, - right: Expr::Lit { - lit: Lit::Bool { - value: true, - }, - }, - }, - }, - op: BinOp::And, - right: Expr::Lit { - lit: Lit::Bool { - value: false, - }, - }, - }, - then_branch: Block { - stmts: [], - }, - } - "#); -} - -#[test] -fn test_tuple_comma() { - let mut expr = ExprTuple { - attrs: Vec::new(), - paren_token: token::Paren::default(), - elems: Punctuated::new(), - }; - snapshot!(expr.to_token_stream() as Expr, @"Expr::Tuple"); - - expr.elems.push_value(parse_quote!(continue)); - // Must not parse to Expr::Paren - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - ], - } - "#); - - expr.elems.push_value(parse_quote!(continue)); - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - Expr::Continue, - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - Expr::Continue, - Token![,], - ], - } - "#); -} - -#[test] -fn test_binop_associativity() { - // Left to right. - snapshot!("() + () + ()" as Expr, @r#" - Expr::Binary { - left: Expr::Binary { - left: Expr::Tuple, - op: BinOp::Add, - right: Expr::Tuple, - }, - op: BinOp::Add, - right: Expr::Tuple, - } - "#); - - // Right to left. - snapshot!("() += () += ()" as Expr, @r#" - Expr::Binary { - left: Expr::Tuple, - op: BinOp::AddAssign, - right: Expr::Binary { - left: Expr::Tuple, - op: BinOp::AddAssign, - right: Expr::Tuple, - }, - } - "#); - - // Parenthesization is required. - syn::parse_str::<Expr>("() == () == ()").unwrap_err(); -} - -#[test] -fn test_assign_range_precedence() { - // Range has higher precedence as the right-hand of an assignment, but - // ambiguous precedence as the left-hand of an assignment. - snapshot!("() = () .. ()" as Expr, @r#" - Expr::Assign { - left: Expr::Tuple, - right: Expr::Range { - start: Some(Expr::Tuple), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Tuple), - }, - } - "#); - - snapshot!("() += () .. ()" as Expr, @r#" - Expr::Binary { - left: Expr::Tuple, - op: BinOp::AddAssign, - right: Expr::Range { - start: Some(Expr::Tuple), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Tuple), - }, - } - "#); - - syn::parse_str::<Expr>("() .. () = ()").unwrap_err(); - syn::parse_str::<Expr>("() .. () += ()").unwrap_err(); -} - -#[test] -fn test_chained_comparison() { - // https://github.com/dtolnay/syn/issues/1738 - let _ = syn::parse_str::<Expr>("a = a < a <"); - let _ = syn::parse_str::<Expr>("a = a .. a .."); - let _ = syn::parse_str::<Expr>("a = a .. a +="); - - let err = syn::parse_str::<Expr>("a < a < a").unwrap_err(); - assert_eq!("comparison operators cannot be chained", err.to_string()); - - let err = syn::parse_str::<Expr>("a .. a .. a").unwrap_err(); - assert_eq!("unexpected token", err.to_string()); - - let err = syn::parse_str::<Expr>("a .. a += a").unwrap_err(); - assert_eq!("unexpected token", err.to_string()); -} - -#[test] -fn test_fixup() { - for tokens in [ - quote! { 2 * (1 + 1) }, - quote! { 0 + (0 + 0) }, - quote! { (a = b) = c }, - quote! { (x as i32) < 0 }, - quote! { 1 + (x as i32) < 0 }, - quote! { (1 + 1).abs() }, - quote! { (lo..hi)[..] }, - quote! { (a..b)..(c..d) }, - quote! { (x > ..) > x }, - quote! { (&mut fut).await }, - quote! { &mut (x as i32) }, - quote! { -(x as i32) }, - quote! { if (S {}) == 1 {} }, - quote! { { (m! {}) - 1 } }, - quote! { match m { _ => ({}) - 1 } }, - quote! { if let _ = (a && b) && c {} }, - quote! { if let _ = (S {}) {} }, - quote! { if (S {}) == 0 && let Some(_) = x {} }, - quote! { break ('a: loop { break 'a 1 } + 1) }, - quote! { a + (|| b) + c }, - quote! { if let _ = ((break) - 1 || true) {} }, - quote! { if let _ = (break + 1 || true) {} }, - quote! { if break (break) {} }, - quote! { if break break {} {} }, - quote! { if return (..) {} }, - quote! { if return .. {} {} }, - quote! { if || (Struct {}) {} }, - quote! { if || (Struct {}).await {} }, - quote! { if break || Struct {}.await {} }, - quote! { if break 'outer 'block: {} {} }, - quote! { if ..'block: {} {} }, - quote! { if break ({}).await {} }, - quote! { (break)() }, - quote! { (..) = () }, - quote! { (..) += () }, - quote! { (1 < 2) == (3 < 4) }, - quote! { { (let _ = ()) } }, - quote! { (#[attr] thing).field }, - quote! { #[attr] (1 + 1) }, - quote! { #[attr] (x = 1) }, - quote! { #[attr] (x += 1) }, - quote! { #[attr] (1 as T) }, - quote! { (return #[attr] (x + ..)).field }, - quote! { (self.f)() }, - quote! { (return)..=return }, - quote! { 1 + (return)..=1 + return }, - quote! { .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }, - ] { - let original: Expr = syn::parse2(tokens).unwrap(); - - let mut flat = original.clone(); - FlattenParens::combine_attrs().visit_expr_mut(&mut flat); - let reconstructed: Expr = match syn::parse2(flat.to_token_stream()) { - Ok(reconstructed) => reconstructed, - Err(err) => panic!("failed to parse `{}`: {}", flat.to_token_stream(), err), - }; - - assert!( - original == reconstructed, - "original: {}\n{:#?}\nreconstructed: {}\n{:#?}", - original.to_token_stream(), - crate::debug::Lite(&original), - reconstructed.to_token_stream(), - crate::debug::Lite(&reconstructed), - ); - } -} - -#[test] -fn test_permutations() -> ExitCode { - fn iter(depth: usize, f: &mut dyn FnMut(Expr)) { - let span = Span::call_site(); - - // Expr::Path - f(Expr::Path(ExprPath { - // `x` - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("x", span)), - })); - if false { - f(Expr::Path(ExprPath { - // `x::<T>` - attrs: Vec::new(), - qself: None, - path: Path { - leading_colon: None, - segments: Punctuated::from_iter([PathSegment { - ident: Ident::new("x", span), - arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { - colon2_token: Some(Token![::](span)), - lt_token: Token![<](span), - args: Punctuated::from_iter([GenericArgument::Type(Type::Path( - TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - }, - ))]), - gt_token: Token![>](span), - }), - }]), - }, - })); - f(Expr::Path(ExprPath { - // `<T as Trait>::CONST` - attrs: Vec::new(), - qself: Some(QSelf { - lt_token: Token![<](span), - ty: Box::new(Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - })), - position: 1, - as_token: Some(Token![as](span)), - gt_token: Token![>](span), - }), - path: Path { - leading_colon: None, - segments: Punctuated::from_iter([ - PathSegment::from(Ident::new("Trait", span)), - PathSegment::from(Ident::new("CONST", span)), - ]), - }, - })); - } - - let Some(depth) = depth.checked_sub(1) else { - return; - }; - - // Expr::Assign - iter(depth, &mut |expr| { - iter(0, &mut |simple| { - f(Expr::Assign(ExprAssign { - // `x = $expr` - attrs: Vec::new(), - left: Box::new(simple.clone()), - eq_token: Token![=](span), - right: Box::new(expr.clone()), - })); - f(Expr::Assign(ExprAssign { - // `$expr = x` - attrs: Vec::new(), - left: Box::new(expr.clone()), - eq_token: Token![=](span), - right: Box::new(simple), - })); - }); - }); - - // Expr::Binary - iter(depth, &mut |expr| { - iter(0, &mut |simple| { - for op in [ - BinOp::Add(Token![+](span)), - //BinOp::Sub(Token![-](span)), - //BinOp::Mul(Token![*](span)), - //BinOp::Div(Token![/](span)), - //BinOp::Rem(Token![%](span)), - //BinOp::And(Token![&&](span)), - //BinOp::Or(Token![||](span)), - //BinOp::BitXor(Token![^](span)), - //BinOp::BitAnd(Token![&](span)), - //BinOp::BitOr(Token![|](span)), - //BinOp::Shl(Token![<<](span)), - //BinOp::Shr(Token![>>](span)), - //BinOp::Eq(Token![==](span)), - BinOp::Lt(Token![<](span)), - //BinOp::Le(Token![<=](span)), - //BinOp::Ne(Token![!=](span)), - //BinOp::Ge(Token![>=](span)), - //BinOp::Gt(Token![>](span)), - BinOp::ShlAssign(Token![<<=](span)), - ] { - f(Expr::Binary(ExprBinary { - // `x + $expr` - attrs: Vec::new(), - left: Box::new(simple.clone()), - op, - right: Box::new(expr.clone()), - })); - f(Expr::Binary(ExprBinary { - // `$expr + x` - attrs: Vec::new(), - left: Box::new(expr.clone()), - op, - right: Box::new(simple.clone()), - })); - } - }); - }); - - // Expr::Block - f(Expr::Block(ExprBlock { - // `{}` - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Break - f(Expr::Break(ExprBreak { - // `break` - attrs: Vec::new(), - break_token: Token![break](span), - label: None, - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Break(ExprBreak { - // `break $expr` - attrs: Vec::new(), - break_token: Token![break](span), - label: None, - expr: Some(Box::new(expr)), - })); - }); - - // Expr::Call - iter(depth, &mut |expr| { - f(Expr::Call(ExprCall { - // `$expr()` - attrs: Vec::new(), - func: Box::new(expr), - paren_token: token::Paren(span), - args: Punctuated::new(), - })); - }); - - // Expr::Cast - iter(depth, &mut |expr| { - f(Expr::Cast(ExprCast { - // `$expr as T` - attrs: Vec::new(), - expr: Box::new(expr), - as_token: Token![as](span), - ty: Box::new(Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - })), - })); - }); - - // Expr::Closure - iter(depth, &mut |expr| { - f(Expr::Closure(ExprClosure { - // `|| $expr` - attrs: Vec::new(), - lifetimes: None, - constness: None, - movability: None, - asyncness: None, - capture: None, - or1_token: Token![|](span), - inputs: Punctuated::new(), - or2_token: Token![|](span), - output: ReturnType::Default, - body: Box::new(expr), - })); - }); - - // Expr::Field - iter(depth, &mut |expr| { - f(Expr::Field(ExprField { - // `$expr.field` - attrs: Vec::new(), - base: Box::new(expr), - dot_token: Token![.](span), - member: Member::Named(Ident::new("field", span)), - })); - }); - - // Expr::If - iter(depth, &mut |expr| { - f(Expr::If(ExprIf { - // `if $expr {}` - attrs: Vec::new(), - if_token: Token![if](span), - cond: Box::new(expr), - then_branch: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - else_branch: None, - })); - }); - - // Expr::Let - iter(depth, &mut |expr| { - f(Expr::Let(ExprLet { - attrs: Vec::new(), - let_token: Token![let](span), - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token![_](span), - })), - eq_token: Token![=](span), - expr: Box::new(expr), - })); - }); - - // Expr::Range - f(Expr::Range(ExprRange { - // `..` - attrs: Vec::new(), - start: None, - limits: RangeLimits::HalfOpen(Token![..](span)), - end: None, - })); - iter(depth, &mut |expr| { - f(Expr::Range(ExprRange { - // `..$expr` - attrs: Vec::new(), - start: None, - limits: RangeLimits::HalfOpen(Token![..](span)), - end: Some(Box::new(expr.clone())), - })); - f(Expr::Range(ExprRange { - // `$expr..` - attrs: Vec::new(), - start: Some(Box::new(expr)), - limits: RangeLimits::HalfOpen(Token![..](span)), - end: None, - })); - }); - - // Expr::Reference - iter(depth, &mut |expr| { - f(Expr::Reference(ExprReference { - // `&$expr` - attrs: Vec::new(), - and_token: Token![&](span), - mutability: None, - expr: Box::new(expr), - })); - }); - - // Expr::Return - f(Expr::Return(ExprReturn { - // `return` - attrs: Vec::new(), - return_token: Token![return](span), - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Return(ExprReturn { - // `return $expr` - attrs: Vec::new(), - return_token: Token![return](span), - expr: Some(Box::new(expr)), - })); - }); - - // Expr::Try - iter(depth, &mut |expr| { - f(Expr::Try(ExprTry { - // `$expr?` - attrs: Vec::new(), - expr: Box::new(expr), - question_token: Token![?](span), - })); - }); - - // Expr::Unary - iter(depth, &mut |expr| { - for op in [ - UnOp::Deref(Token![*](span)), - //UnOp::Not(Token![!](span)), - //UnOp::Neg(Token![-](span)), - ] { - f(Expr::Unary(ExprUnary { - // `*$expr` - attrs: Vec::new(), - op, - expr: Box::new(expr.clone()), - })); - } - }); - - if false { - // Expr::Array - f(Expr::Array(ExprArray { - // `[]` - attrs: Vec::new(), - bracket_token: token::Bracket(span), - elems: Punctuated::new(), - })); - - // Expr::Async - f(Expr::Async(ExprAsync { - // `async {}` - attrs: Vec::new(), - async_token: Token![async](span), - capture: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Await - iter(depth, &mut |expr| { - f(Expr::Await(ExprAwait { - // `$expr.await` - attrs: Vec::new(), - base: Box::new(expr), - dot_token: Token![.](span), - await_token: Token![await](span), - })); - }); - - // Expr::Block - f(Expr::Block(ExprBlock { - // `'a: {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token![:](span), - }), - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - iter(depth, &mut |expr| { - f(Expr::Block(ExprBlock { - // `{ $expr }` - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::from([Stmt::Expr(expr.clone(), None)]), - }, - })); - f(Expr::Block(ExprBlock { - // `{ $expr; }` - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::from([Stmt::Expr(expr, Some(Token![;](span)))]), - }, - })); - }); - - // Expr::Break - f(Expr::Break(ExprBreak { - // `break 'a` - attrs: Vec::new(), - break_token: Token![break](span), - label: Some(Lifetime::new("'a", span)), - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Break(ExprBreak { - // `break 'a $expr` - attrs: Vec::new(), - break_token: Token![break](span), - label: Some(Lifetime::new("'a", span)), - expr: Some(Box::new(expr)), - })); - }); - - // Expr::Closure - f(Expr::Closure(ExprClosure { - // `|| -> T {}` - attrs: Vec::new(), - lifetimes: None, - constness: None, - movability: None, - asyncness: None, - capture: None, - or1_token: Token![|](span), - inputs: Punctuated::new(), - or2_token: Token![|](span), - output: ReturnType::Type( - Token![->](span), - Box::new(Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - })), - ), - body: Box::new(Expr::Block(ExprBlock { - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })), - })); - - // Expr::Const - f(Expr::Const(ExprConst { - // `const {}` - attrs: Vec::new(), - const_token: Token![const](span), - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Continue - f(Expr::Continue(ExprContinue { - // `continue` - attrs: Vec::new(), - continue_token: Token![continue](span), - label: None, - })); - f(Expr::Continue(ExprContinue { - // `continue 'a` - attrs: Vec::new(), - continue_token: Token![continue](span), - label: Some(Lifetime::new("'a", span)), - })); - - // Expr::ForLoop - iter(depth, &mut |expr| { - f(Expr::ForLoop(ExprForLoop { - // `for _ in $expr {}` - attrs: Vec::new(), - label: None, - for_token: Token![for](span), - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token![_](span), - })), - in_token: Token![in](span), - expr: Box::new(expr.clone()), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - f(Expr::ForLoop(ExprForLoop { - // `'a: for _ in $expr {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token![:](span), - }), - for_token: Token![for](span), - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token![_](span), - })), - in_token: Token![in](span), - expr: Box::new(expr), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - }); - - // Expr::Index - iter(depth, &mut |expr| { - f(Expr::Index(ExprIndex { - // `$expr[0]` - attrs: Vec::new(), - expr: Box::new(expr), - bracket_token: token::Bracket(span), - index: Box::new(Expr::Lit(ExprLit { - attrs: Vec::new(), - lit: Lit::Int(LitInt::new("0", span)), - })), - })); - }); - - // Expr::Loop - f(Expr::Loop(ExprLoop { - // `loop {}` - attrs: Vec::new(), - label: None, - loop_token: Token![loop](span), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - f(Expr::Loop(ExprLoop { - // `'a: loop {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token![:](span), - }), - loop_token: Token![loop](span), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Macro - f(Expr::Macro(ExprMacro { - // `m!()` - attrs: Vec::new(), - mac: Macro { - path: Path::from(Ident::new("m", span)), - bang_token: Token![!](span), - delimiter: MacroDelimiter::Paren(token::Paren(span)), - tokens: TokenStream::new(), - }, - })); - f(Expr::Macro(ExprMacro { - // `m! {}` - attrs: Vec::new(), - mac: Macro { - path: Path::from(Ident::new("m", span)), - bang_token: Token![!](span), - delimiter: MacroDelimiter::Brace(token::Brace(span)), - tokens: TokenStream::new(), - }, - })); - - // Expr::Match - iter(depth, &mut |expr| { - f(Expr::Match(ExprMatch { - // `match $expr {}` - attrs: Vec::new(), - match_token: Token![match](span), - expr: Box::new(expr.clone()), - brace_token: token::Brace(span), - arms: Vec::new(), - })); - f(Expr::Match(ExprMatch { - // `match x { _ => $expr }` - attrs: Vec::new(), - match_token: Token![match](span), - expr: Box::new(Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("x", span)), - })), - brace_token: token::Brace(span), - arms: Vec::from([Arm { - attrs: Vec::new(), - pat: Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token![_](span), - }), - guard: None, - fat_arrow_token: Token![=>](span), - body: Box::new(expr.clone()), - comma: None, - }]), - })); - f(Expr::Match(ExprMatch { - // `match x { _ if $expr => {} }` - attrs: Vec::new(), - match_token: Token![match](span), - expr: Box::new(Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("x", span)), - })), - brace_token: token::Brace(span), - arms: Vec::from([Arm { - attrs: Vec::new(), - pat: Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token![_](span), - }), - guard: Some((Token![if](span), Box::new(expr))), - fat_arrow_token: Token![=>](span), - body: Box::new(Expr::Block(ExprBlock { - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })), - comma: None, - }]), - })); - }); - - // Expr::MethodCall - iter(depth, &mut |expr| { - f(Expr::MethodCall(ExprMethodCall { - // `$expr.method()` - attrs: Vec::new(), - receiver: Box::new(expr.clone()), - dot_token: Token![.](span), - method: Ident::new("method", span), - turbofish: None, - paren_token: token::Paren(span), - args: Punctuated::new(), - })); - f(Expr::MethodCall(ExprMethodCall { - // `$expr.method::<T>()` - attrs: Vec::new(), - receiver: Box::new(expr), - dot_token: Token![.](span), - method: Ident::new("method", span), - turbofish: Some(AngleBracketedGenericArguments { - colon2_token: Some(Token![::](span)), - lt_token: Token![<](span), - args: Punctuated::from_iter([GenericArgument::Type(Type::Path( - TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - }, - ))]), - gt_token: Token![>](span), - }), - paren_token: token::Paren(span), - args: Punctuated::new(), - })); - }); - - // Expr::RawAddr - iter(depth, &mut |expr| { - f(Expr::RawAddr(ExprRawAddr { - // `&raw const $expr` - attrs: Vec::new(), - and_token: Token![&](span), - raw: Token![raw](span), - mutability: PointerMutability::Const(Token![const](span)), - expr: Box::new(expr), - })); - }); - - // Expr::Struct - f(Expr::Struct(ExprStruct { - // `Struct {}` - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("Struct", span)), - brace_token: token::Brace(span), - fields: Punctuated::new(), - dot2_token: None, - rest: None, - })); - - // Expr::TryBlock - f(Expr::TryBlock(ExprTryBlock { - // `try {}` - attrs: Vec::new(), - try_token: Token![try](span), - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Unsafe - f(Expr::Unsafe(ExprUnsafe { - // `unsafe {}` - attrs: Vec::new(), - unsafe_token: Token![unsafe](span), - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::While - iter(depth, &mut |expr| { - f(Expr::While(ExprWhile { - // `while $expr {}` - attrs: Vec::new(), - label: None, - while_token: Token![while](span), - cond: Box::new(expr.clone()), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - f(Expr::While(ExprWhile { - // `'a: while $expr {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token![:](span), - }), - while_token: Token![while](span), - cond: Box::new(expr), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - }); - - // Expr::Yield - f(Expr::Yield(ExprYield { - // `yield` - attrs: Vec::new(), - yield_token: Token![yield](span), - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Yield(ExprYield { - // `yield $expr` - attrs: Vec::new(), - yield_token: Token![yield](span), - expr: Some(Box::new(expr)), - })); - }); - } - } - - let mut failures = 0; - macro_rules! fail { - ($($message:tt)*) => {{ - eprintln!($($message)*); - failures += 1; - return; - }}; - } - let mut assert = |mut original: Expr| { - let tokens = original.to_token_stream(); - let Ok(mut parsed) = syn::parse2::<Expr>(tokens.clone()) else { - fail!( - "failed to parse: {}\n{:#?}", - tokens, - crate::debug::Lite(&original), - ); - }; - AsIfPrinted.visit_expr_mut(&mut original); - FlattenParens::combine_attrs().visit_expr_mut(&mut parsed); - if original != parsed { - fail!( - "before: {}\n{:#?}\nafter: {}\n{:#?}", - tokens, - crate::debug::Lite(&original), - parsed.to_token_stream(), - crate::debug::Lite(&parsed), - ); - } - let mut tokens_no_paren = tokens.clone(); - FlattenParens::visit_token_stream_mut(&mut tokens_no_paren); - if tokens.to_string() != tokens_no_paren.to_string() { - if let Ok(mut parsed2) = syn::parse2::<Expr>(tokens_no_paren) { - FlattenParens::combine_attrs().visit_expr_mut(&mut parsed2); - if original == parsed2 { - fail!("redundant parens: {}", tokens); - } - } - } - }; - - iter(4, &mut assert); - if failures > 0 { - eprintln!("FAILURES: {failures}"); - ExitCode::FAILURE - } else { - ExitCode::SUCCESS - } -} diff --git a/deps/crates/vendor/syn-v2/tests/test_generics.rs b/deps/crates/vendor/syn-v2/tests/test_generics.rs deleted file mode 100644 index 61bc8dea1cec..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_generics.rs +++ /dev/null @@ -1,356 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::manual_let_else, - clippy::needless_lifetimes, - clippy::too_many_lines, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use quote::quote; -use syn::{ - parse_quote, DeriveInput, GenericParam, Generics, ItemFn, Lifetime, LifetimeParam, - TypeParamBound, WhereClause, WherePredicate, -}; - -#[test] -fn test_split_for_impl() { - let input = quote! { - struct S<'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug; - }; - - snapshot!(input as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics { - lt_token: Some, - params: [ - GenericParam::Lifetime(LifetimeParam { - lifetime: Lifetime { - ident: "a", - }, - }), - Token![,], - GenericParam::Lifetime(LifetimeParam { - lifetime: Lifetime { - ident: "b", - }, - colon_token: Some, - bounds: [ - Lifetime { - ident: "a", - }, - ], - }), - Token![,], - GenericParam::Type(TypeParam { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "may_dangle", - }, - ], - }, - }, - ], - ident: "T", - colon_token: Some, - bounds: [ - TypeParamBound::Lifetime { - ident: "a", - }, - ], - eq_token: Some, - default: Some(Type::Tuple), - }), - ], - gt_token: Some, - where_clause: Some(WhereClause { - predicates: [ - WherePredicate::Type(PredicateType { - bounded_ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }, - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Debug", - }, - ], - }, - }), - ], - }), - ], - }), - }, - data: Data::Struct { - fields: Fields::Unit, - semi_token: Some, - }, - } - "#); - - let generics = input.generics; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - let generated = quote! { - impl #impl_generics MyTrait for Test #ty_generics #where_clause {} - }; - let expected = quote! { - impl<'a, 'b: 'a, #[may_dangle] T: 'a> MyTrait - for Test<'a, 'b, T> - where - T: Debug - {} - }; - assert_eq!(generated.to_string(), expected.to_string()); - - let turbofish = ty_generics.as_turbofish(); - let generated = quote! { - Test #turbofish - }; - let expected = quote! { - Test::<'a, 'b, T> - }; - assert_eq!(generated.to_string(), expected.to_string()); -} - -#[test] -fn test_type_param_bound() { - let tokens = quote!('a); - snapshot!(tokens as TypeParamBound, @r#" - TypeParamBound::Lifetime { - ident: "a", - } - "#); - - let tokens = quote!('_); - snapshot!(tokens as TypeParamBound, @r#" - TypeParamBound::Lifetime { - ident: "_", - } - "#); - - let tokens = quote!(Debug); - snapshot!(tokens as TypeParamBound, @r#" - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Debug", - }, - ], - }, - }) - "#); - - let tokens = quote!(?Sized); - snapshot!(tokens as TypeParamBound, @r#" - TypeParamBound::Trait(TraitBound { - modifier: TraitBoundModifier::Maybe, - path: Path { - segments: [ - PathSegment { - ident: "Sized", - }, - ], - }, - }) - "#); - - let tokens = quote!(for<'a> Trait); - snapshot!(tokens as TypeParamBound, @r#" - TypeParamBound::Trait(TraitBound { - lifetimes: Some(BoundLifetimes { - lifetimes: [ - GenericParam::Lifetime(LifetimeParam { - lifetime: Lifetime { - ident: "a", - }, - }), - ], - }), - path: Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - }) - "#); - - let tokens = quote!(for<> ?Trait); - let err = syn::parse2::<TypeParamBound>(tokens).unwrap_err(); - assert_eq!( - "`for<...>` binder not allowed with `?` trait polarity modifier", - err.to_string(), - ); - - let tokens = quote!(?for<> Trait); - let err = syn::parse2::<TypeParamBound>(tokens).unwrap_err(); - assert_eq!( - "`for<...>` binder not allowed with `?` trait polarity modifier", - err.to_string(), - ); -} - -#[test] -fn test_fn_precedence_in_where_clause() { - // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not - // `FnOnce() -> (i32 + Send)`. - let input = quote! { - fn f<G>() - where - G: FnOnce() -> i32 + Send, - { - } - }; - - snapshot!(input as ItemFn, @r#" - ItemFn { - vis: Visibility::Inherited, - sig: Signature { - ident: "f", - generics: Generics { - lt_token: Some, - params: [ - GenericParam::Type(TypeParam { - ident: "G", - }), - ], - gt_token: Some, - where_clause: Some(WhereClause { - predicates: [ - WherePredicate::Type(PredicateType { - bounded_ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "G", - }, - ], - }, - }, - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "FnOnce", - arguments: PathArguments::Parenthesized { - output: ReturnType::Type( - Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "i32", - }, - ], - }, - }, - ), - }, - }, - ], - }, - }), - Token![+], - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Send", - }, - ], - }, - }), - ], - }), - Token![,], - ], - }), - }, - output: ReturnType::Default, - }, - block: Block { - stmts: [], - }, - } - "#); - - let where_clause = input.sig.generics.where_clause.as_ref().unwrap(); - assert_eq!(where_clause.predicates.len(), 1); - - let predicate = match &where_clause.predicates[0] { - WherePredicate::Type(pred) => pred, - _ => panic!("wrong predicate kind"), - }; - - assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds); - - let first_bound = &predicate.bounds[0]; - assert_eq!(quote!(#first_bound).to_string(), "FnOnce () -> i32"); - - let second_bound = &predicate.bounds[1]; - assert_eq!(quote!(#second_bound).to_string(), "Send"); -} - -#[test] -fn test_where_clause_at_end_of_input() { - let input = quote! { - where - }; - - snapshot!(input as WhereClause, @"WhereClause"); - - assert_eq!(input.predicates.len(), 0); -} - -// Regression test for https://github.com/dtolnay/syn/issues/1718 -#[test] -#[allow(clippy::map_unwrap_or)] -fn no_opaque_drop() { - let mut generics = Generics::default(); - - let _ = generics - .lifetimes() - .next() - .map(|param| param.lifetime.clone()) - .unwrap_or_else(|| { - let lifetime: Lifetime = parse_quote!('a); - generics.params.insert( - 0, - GenericParam::Lifetime(LifetimeParam::new(lifetime.clone())), - ); - lifetime - }); -} - -#[test] -fn type_param_with_colon_and_no_bounds() { - let tokens = quote!(T:); - snapshot!(tokens as GenericParam, @r#" - GenericParam::Type(TypeParam { - ident: "T", - colon_token: Some, - }) - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_grouping.rs b/deps/crates/vendor/syn-v2/tests/test_grouping.rs deleted file mode 100644 index b466c7e7217e..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_grouping.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, TokenStream, TokenTree}; -use syn::Expr; - -#[test] -fn test_grouping() { - let tokens: TokenStream = TokenStream::from_iter([ - TokenTree::Literal(Literal::i32_suffixed(1)), - TokenTree::Punct(Punct::new('+', Spacing::Alone)), - TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::from_iter([ - TokenTree::Literal(Literal::i32_suffixed(2)), - TokenTree::Punct(Punct::new('+', Spacing::Alone)), - TokenTree::Literal(Literal::i32_suffixed(3)), - ]), - )), - TokenTree::Punct(Punct::new('*', Spacing::Alone)), - TokenTree::Literal(Literal::i32_suffixed(4)), - ]); - - assert_eq!(tokens.to_string(), "1i32 + 2i32 + 3i32 * 4i32"); - - snapshot!(tokens as Expr, @r#" - Expr::Binary { - left: Expr::Lit { - lit: 1i32, - }, - op: BinOp::Add, - right: Expr::Binary { - left: Expr::Group { - expr: Expr::Binary { - left: Expr::Lit { - lit: 2i32, - }, - op: BinOp::Add, - right: Expr::Lit { - lit: 3i32, - }, - }, - }, - op: BinOp::Mul, - right: Expr::Lit { - lit: 4i32, - }, - }, - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_ident.rs b/deps/crates/vendor/syn-v2/tests/test_ident.rs deleted file mode 100644 index 10df0ad56c2a..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_ident.rs +++ /dev/null @@ -1,87 +0,0 @@ -use proc_macro2::{Ident, Span, TokenStream}; -use std::str::FromStr; -use syn::Result; - -#[track_caller] -fn parse(s: &str) -> Result<Ident> { - syn::parse2(TokenStream::from_str(s).unwrap()) -} - -#[track_caller] -fn new(s: &str) -> Ident { - Ident::new(s, Span::call_site()) -} - -#[test] -fn ident_parse() { - parse("String").unwrap(); -} - -#[test] -fn ident_parse_keyword() { - parse("abstract").unwrap_err(); -} - -#[test] -fn ident_parse_empty() { - parse("").unwrap_err(); -} - -#[test] -fn ident_parse_lifetime() { - parse("'static").unwrap_err(); -} - -#[test] -fn ident_parse_underscore() { - parse("_").unwrap_err(); -} - -#[test] -fn ident_parse_number() { - parse("255").unwrap_err(); -} - -#[test] -fn ident_parse_invalid() { - parse("a#").unwrap_err(); -} - -#[test] -fn ident_new() { - new("String"); -} - -#[test] -fn ident_new_keyword() { - new("abstract"); -} - -#[test] -#[should_panic(expected = "use Option<Ident>")] -fn ident_new_empty() { - new(""); -} - -#[test] -#[should_panic(expected = "not a valid Ident")] -fn ident_new_lifetime() { - new("'static"); -} - -#[test] -fn ident_new_underscore() { - new("_"); -} - -#[test] -#[should_panic(expected = "use Literal instead")] -fn ident_new_number() { - new("255"); -} - -#[test] -#[should_panic(expected = "\"a#\" is not a valid Ident")] -fn ident_new_invalid() { - new("a#"); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_item.rs b/deps/crates/vendor/syn-v2/tests/test_item.rs deleted file mode 100644 index cb63ad4c69fd..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_item.rs +++ /dev/null @@ -1,371 +0,0 @@ -#![recursion_limit = "256"] -#![feature(negative_impls)] -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; -use quote::quote; -use syn::{Item, ItemTrait}; - -#[test] -fn test_macro_variable_attr() { - // mimics the token stream corresponding to `$attr fn f() {}` - let tokens = TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, quote! { #[test] })), - TokenTree::Ident(Ident::new("fn", Span::call_site())), - TokenTree::Ident(Ident::new("f", Span::call_site())), - TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), - TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), - ]); - - snapshot!(tokens as Item, @r#" - Item::Fn { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "test", - }, - ], - }, - }, - ], - vis: Visibility::Inherited, - sig: Signature { - ident: "f", - generics: Generics, - output: ReturnType::Default, - }, - block: Block { - stmts: [], - }, - } - "#); -} - -#[test] -fn test_negative_impl() { - #[cfg(any())] - impl ! {} - let tokens = quote! { - impl ! {} - }; - snapshot!(tokens as Item, @r#" - Item::Impl { - generics: Generics, - self_ty: Type::Never, - } - "#); - - let tokens = quote! { - impl !Trait {} - }; - let err = syn::parse2::<Item>(tokens).unwrap_err(); - assert_eq!(err.to_string(), "inherent impls cannot be negative"); - - #[cfg(any())] - impl !Trait for T {} - let tokens = quote! { - impl !Trait for T {} - }; - snapshot!(tokens as Item, @r#" - Item::Impl { - generics: Generics, - trait_: Some(( - Some, - Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - )), - self_ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }, - } - "#); -} - -#[test] -fn test_macro_variable_impl() { - // mimics the token stream corresponding to `impl $trait for $ty {}` - let tokens = TokenStream::from_iter([ - TokenTree::Ident(Ident::new("impl", Span::call_site())), - TokenTree::Group(Group::new(Delimiter::None, quote!(Trait))), - TokenTree::Ident(Ident::new("for", Span::call_site())), - TokenTree::Group(Group::new(Delimiter::None, quote!(Type))), - TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), - ]); - - snapshot!(tokens as Item, @r#" - Item::Impl { - generics: Generics, - trait_: Some(( - None, - Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - )), - self_ty: Type::Group { - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Type", - }, - ], - }, - }, - }, - } - "#); -} - -#[test] -fn test_supertraits() { - // Rustc parses all of the following. - - #[rustfmt::skip] - let tokens = quote!(trait Trait where {}); - snapshot!(tokens as ItemTrait, @r#" - ItemTrait { - vis: Visibility::Inherited, - ident: "Trait", - generics: Generics { - where_clause: Some(WhereClause), - }, - } - "#); - - #[rustfmt::skip] - let tokens = quote!(trait Trait: where {}); - snapshot!(tokens as ItemTrait, @r#" - ItemTrait { - vis: Visibility::Inherited, - ident: "Trait", - generics: Generics { - where_clause: Some(WhereClause), - }, - colon_token: Some, - } - "#); - - #[rustfmt::skip] - let tokens = quote!(trait Trait: Sized where {}); - snapshot!(tokens as ItemTrait, @r#" - ItemTrait { - vis: Visibility::Inherited, - ident: "Trait", - generics: Generics { - where_clause: Some(WhereClause), - }, - colon_token: Some, - supertraits: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Sized", - }, - ], - }, - }), - ], - } - "#); - - #[rustfmt::skip] - let tokens = quote!(trait Trait: Sized + where {}); - snapshot!(tokens as ItemTrait, @r#" - ItemTrait { - vis: Visibility::Inherited, - ident: "Trait", - generics: Generics { - where_clause: Some(WhereClause), - }, - colon_token: Some, - supertraits: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Sized", - }, - ], - }, - }), - Token![+], - ], - } - "#); -} - -#[test] -fn test_type_empty_bounds() { - #[rustfmt::skip] - let tokens = quote! { - trait Foo { - type Bar: ; - } - }; - - snapshot!(tokens as ItemTrait, @r#" - ItemTrait { - vis: Visibility::Inherited, - ident: "Foo", - generics: Generics, - items: [ - TraitItem::Type { - ident: "Bar", - generics: Generics, - colon_token: Some, - }, - ], - } - "#); -} - -#[test] -fn test_impl_visibility() { - let tokens = quote! { - pub default unsafe impl union {} - }; - - snapshot!(tokens as Item, @"Item::Verbatim(`pub default unsafe impl union { }`)"); -} - -#[test] -fn test_impl_type_parameter_defaults() { - #[cfg(any())] - impl<T = ()> () {} - let tokens = quote! { - impl<T = ()> () {} - }; - snapshot!(tokens as Item, @r#" - Item::Impl { - generics: Generics { - lt_token: Some, - params: [ - GenericParam::Type(TypeParam { - ident: "T", - eq_token: Some, - default: Some(Type::Tuple), - }), - ], - gt_token: Some, - }, - self_ty: Type::Tuple, - } - "#); -} - -#[test] -fn test_impl_trait_trailing_plus() { - let tokens = quote! { - fn f() -> impl Sized + {} - }; - - snapshot!(tokens as Item, @r#" - Item::Fn { - vis: Visibility::Inherited, - sig: Signature { - ident: "f", - generics: Generics, - output: ReturnType::Type( - Type::ImplTrait { - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Sized", - }, - ], - }, - }), - Token![+], - ], - }, - ), - }, - block: Block { - stmts: [], - }, - } - "#); -} - -// Regression test for issue https://github.com/dtolnay/syn/issues/1967 -#[test] -fn test_nested_receiver_classification() { - let tokens = quote! { - fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - self: foo<{ fn foo( - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - )}> - ) {} - }; - - let _ = syn::parse2::<syn::File>(tokens); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_lit.rs b/deps/crates/vendor/syn-v2/tests/test_lit.rs deleted file mode 100644 index f2367b44165d..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_lit.rs +++ /dev/null @@ -1,335 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::float_cmp, - clippy::needless_lifetimes, - clippy::needless_raw_string_hashes, - clippy::non_ascii_literal, - clippy::single_match_else, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Literal, Span, TokenStream, TokenTree}; -use quote::ToTokens; -use std::ffi::CStr; -use std::str::FromStr; -use syn::{Lit, LitFloat, LitInt, LitStr}; - -#[track_caller] -fn lit(s: &str) -> Lit { - let mut tokens = TokenStream::from_str(s).unwrap().into_iter(); - match tokens.next().unwrap() { - TokenTree::Literal(lit) => { - assert!(tokens.next().is_none()); - Lit::new(lit) - } - wrong => panic!("{:?}", wrong), - } -} - -#[test] -fn strings() { - #[track_caller] - fn test_string(s: &str, value: &str) { - let s = s.trim(); - match lit(s) { - Lit::Str(lit) => { - assert_eq!(lit.value(), value); - let again = lit.into_token_stream().to_string(); - if again != s { - test_string(&again, value); - } - } - wrong => panic!("{:?}", wrong), - } - } - - test_string(r#" "" "#, ""); - test_string(r#" "a" "#, "a"); - test_string(r#" "\n" "#, "\n"); - test_string(r#" "\r" "#, "\r"); - test_string(r#" "\t" "#, "\t"); - test_string(r#" "🐕" "#, "🐕"); // NOTE: This is an emoji - test_string(r#" "\"" "#, "\""); - test_string(r#" "'" "#, "'"); - test_string(r#" "\u{1F415}" "#, "\u{1F415}"); - test_string(r#" "\u{1_2__3_}" "#, "\u{123}"); - test_string( - "\"contains\nnewlines\\\nescaped newlines\"", - "contains\nnewlinesescaped newlines", - ); - test_string( - "\"escaped newline\\\n \x0C unsupported whitespace\"", - "escaped newline\x0C unsupported whitespace", - ); - test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere"); - test_string("\"...\"q", "..."); - test_string("r\"...\"q", "..."); - test_string("r##\"...\"##q", "..."); -} - -#[test] -fn byte_strings() { - #[track_caller] - fn test_byte_string(s: &str, value: &[u8]) { - let s = s.trim(); - match lit(s) { - Lit::ByteStr(lit) => { - assert_eq!(lit.value(), value); - let again = lit.into_token_stream().to_string(); - if again != s { - test_byte_string(&again, value); - } - } - wrong => panic!("{:?}", wrong), - } - } - - test_byte_string(r#" b"" "#, b""); - test_byte_string(r#" b"a" "#, b"a"); - test_byte_string(r#" b"\n" "#, b"\n"); - test_byte_string(r#" b"\r" "#, b"\r"); - test_byte_string(r#" b"\t" "#, b"\t"); - test_byte_string(r#" b"\"" "#, b"\""); - test_byte_string(r#" b"'" "#, b"'"); - test_byte_string( - "b\"contains\nnewlines\\\nescaped newlines\"", - b"contains\nnewlinesescaped newlines", - ); - test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere"); - test_byte_string("b\"...\"q", b"..."); - test_byte_string("br\"...\"q", b"..."); - test_byte_string("br##\"...\"##q", b"..."); -} - -#[test] -fn c_strings() { - #[track_caller] - fn test_c_string(s: &str, value: &CStr) { - let s = s.trim(); - match lit(s) { - Lit::CStr(lit) => { - assert_eq!(*lit.value(), *value); - let again = lit.into_token_stream().to_string(); - if again != s { - test_c_string(&again, value); - } - } - wrong => panic!("{:?}", wrong), - } - } - - test_c_string(r#" c"" "#, c""); - test_c_string(r#" c"a" "#, c"a"); - test_c_string(r#" c"\n" "#, c"\n"); - test_c_string(r#" c"\r" "#, c"\r"); - test_c_string(r#" c"\t" "#, c"\t"); - test_c_string(r#" c"\\" "#, c"\\"); - test_c_string(r#" c"\'" "#, c"'"); - test_c_string(r#" c"\"" "#, c"\""); - test_c_string( - "c\"contains\nnewlines\\\nescaped newlines\"", - c"contains\nnewlinesescaped newlines", - ); - test_c_string("cr\"raw\nstring\\\nhere\"", c"raw\nstring\\\nhere"); - test_c_string("c\"...\"q", c"..."); - test_c_string("cr\"...\"", c"..."); - test_c_string("cr##\"...\"##", c"..."); - test_c_string( - r#" c"hello\x80我叫\u{1F980}" "#, // from the RFC - c"hello\x80我叫\u{1F980}", - ); -} - -#[test] -fn bytes() { - #[track_caller] - fn test_byte(s: &str, value: u8) { - let s = s.trim(); - match lit(s) { - Lit::Byte(lit) => { - assert_eq!(lit.value(), value); - let again = lit.into_token_stream().to_string(); - assert_eq!(again, s); - } - wrong => panic!("{:?}", wrong), - } - } - - test_byte(r#" b'a' "#, b'a'); - test_byte(r#" b'\n' "#, b'\n'); - test_byte(r#" b'\r' "#, b'\r'); - test_byte(r#" b'\t' "#, b'\t'); - test_byte(r#" b'\'' "#, b'\''); - test_byte(r#" b'"' "#, b'"'); - test_byte(r#" b'a'q "#, b'a'); -} - -#[test] -fn chars() { - #[track_caller] - fn test_char(s: &str, value: char) { - let s = s.trim(); - match lit(s) { - Lit::Char(lit) => { - assert_eq!(lit.value(), value); - let again = lit.into_token_stream().to_string(); - if again != s { - test_char(&again, value); - } - } - wrong => panic!("{:?}", wrong), - } - } - - test_char(r#" 'a' "#, 'a'); - test_char(r#" '\n' "#, '\n'); - test_char(r#" '\r' "#, '\r'); - test_char(r#" '\t' "#, '\t'); - test_char(r#" '🐕' "#, '🐕'); // NOTE: This is an emoji - test_char(r#" '\'' "#, '\''); - test_char(r#" '"' "#, '"'); - test_char(r#" '\u{1F415}' "#, '\u{1F415}'); - test_char(r#" 'a'q "#, 'a'); -} - -#[test] -fn ints() { - #[track_caller] - fn test_int(s: &str, value: u64, suffix: &str) { - match lit(s) { - Lit::Int(lit) => { - assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value); - assert_eq!(lit.suffix(), suffix); - let again = lit.into_token_stream().to_string(); - if again != s { - test_int(&again, value, suffix); - } - } - wrong => panic!("{:?}", wrong), - } - } - - test_int("5", 5, ""); - test_int("5u32", 5, "u32"); - test_int("0E", 0, "E"); - test_int("0ECMA", 0, "ECMA"); - test_int("0o0A", 0, "A"); - test_int("5_0", 50, ""); - test_int("5_____0_____", 50, ""); - test_int("0x7f", 127, ""); - test_int("0x7F", 127, ""); - test_int("0b1001", 9, ""); - test_int("0o73", 59, ""); - test_int("0x7Fu8", 127, "u8"); - test_int("0b1001i8", 9, "i8"); - test_int("0o73u32", 59, "u32"); - test_int("0x__7___f_", 127, ""); - test_int("0x__7___F_", 127, ""); - test_int("0b_1_0__01", 9, ""); - test_int("0o_7__3", 59, ""); - test_int("0x_7F__u8", 127, "u8"); - test_int("0b__10__0_1i8", 9, "i8"); - test_int("0o__7__________________3u32", 59, "u32"); - test_int("0e1\u{5c5}", 0, "e1\u{5c5}"); -} - -#[test] -fn floats() { - #[track_caller] - fn test_float(s: &str, value: f64, suffix: &str) { - match lit(s) { - Lit::Float(lit) => { - assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value); - assert_eq!(lit.suffix(), suffix); - let again = lit.into_token_stream().to_string(); - if again != s { - test_float(&again, value, suffix); - } - } - wrong => panic!("{:?}", wrong), - } - } - - test_float("5.5", 5.5, ""); - test_float("5.5E12", 5.5e12, ""); - test_float("5.5e12", 5.5e12, ""); - test_float("1.0__3e-12", 1.03e-12, ""); - test_float("1.03e+12", 1.03e12, ""); - test_float("9e99e99", 9e99, "e99"); - test_float("1e_0", 1.0, ""); - test_float("0.0ECMA", 0.0, "ECMA"); -} - -#[test] -fn negative() { - let span = Span::call_site(); - assert_eq!("-1", LitInt::new("-1", span).to_string()); - assert_eq!("-1i8", LitInt::new("-1i8", span).to_string()); - assert_eq!("-1i16", LitInt::new("-1i16", span).to_string()); - assert_eq!("-1i32", LitInt::new("-1i32", span).to_string()); - assert_eq!("-1i64", LitInt::new("-1i64", span).to_string()); - assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string()); - assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string()); - assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string()); -} - -#[test] -fn suffix() { - #[track_caller] - fn get_suffix(token: &str) -> String { - let lit = syn::parse_str::<Lit>(token).unwrap(); - match lit { - Lit::Str(lit) => lit.suffix().to_owned(), - Lit::ByteStr(lit) => lit.suffix().to_owned(), - Lit::CStr(lit) => lit.suffix().to_owned(), - Lit::Byte(lit) => lit.suffix().to_owned(), - Lit::Char(lit) => lit.suffix().to_owned(), - Lit::Int(lit) => lit.suffix().to_owned(), - Lit::Float(lit) => lit.suffix().to_owned(), - _ => unimplemented!(), - } - } - - assert_eq!(get_suffix("\"\"s"), "s"); - assert_eq!(get_suffix("r\"\"r"), "r"); - assert_eq!(get_suffix("r#\"\"#r"), "r"); - assert_eq!(get_suffix("b\"\"b"), "b"); - assert_eq!(get_suffix("br\"\"br"), "br"); - assert_eq!(get_suffix("br#\"\"#br"), "br"); - assert_eq!(get_suffix("c\"\"c"), "c"); - assert_eq!(get_suffix("cr\"\"cr"), "cr"); - assert_eq!(get_suffix("cr#\"\"#cr"), "cr"); - assert_eq!(get_suffix("'c'c"), "c"); - assert_eq!(get_suffix("b'b'b"), "b"); - assert_eq!(get_suffix("1i32"), "i32"); - assert_eq!(get_suffix("1_i32"), "i32"); - assert_eq!(get_suffix("1.0f32"), "f32"); - assert_eq!(get_suffix("1.0_f32"), "f32"); -} - -#[test] -fn test_deep_group_empty() { - let tokens = TokenStream::from_iter([TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::from_iter([TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::from_iter([TokenTree::Literal(Literal::string("hi"))]), - ))]), - ))]); - - snapshot!(tokens as Lit, @r#""hi""# ); -} - -#[test] -fn test_error() { - let err = syn::parse_str::<LitStr>("...").unwrap_err(); - assert_eq!("expected string literal", err.to_string()); - - let err = syn::parse_str::<LitStr>("5").unwrap_err(); - assert_eq!("expected string literal", err.to_string()); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_meta.rs b/deps/crates/vendor/syn-v2/tests/test_meta.rs deleted file mode 100644 index 4e1f9caf38e0..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_meta.rs +++ /dev/null @@ -1,180 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::shadow_unrelated, - clippy::too_many_lines, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use quote::quote; -use syn::parse::{ParseStream, Parser as _, Result}; -use syn::{Meta, MetaList, MetaNameValue, Token}; - -#[test] -fn test_parse_meta_item_word() { - let input = "hello"; - - snapshot!(input as Meta, @r#" - Meta::Path { - segments: [ - PathSegment { - ident: "hello", - }, - ], - } - "#); -} - -#[test] -fn test_parse_meta_name_value() { - let input = "foo = 5"; - let (inner, meta) = (input, input); - - snapshot!(inner as MetaNameValue, @r#" - MetaNameValue { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - value: Expr::Lit { - lit: 5, - }, - } - "#); - - snapshot!(meta as Meta, @r#" - Meta::NameValue { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - value: Expr::Lit { - lit: 5, - }, - } - "#); - - assert_eq!(meta, Meta::NameValue(inner)); -} - -#[test] -fn test_parse_meta_item_list_lit() { - let input = "foo(5)"; - let (inner, meta) = (input, input); - - snapshot!(inner as MetaList, @r#" - MetaList { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`5`), - } - "#); - - snapshot!(meta as Meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`5`), - } - "#); - - assert_eq!(meta, Meta::List(inner)); -} - -#[test] -fn test_parse_meta_item_multiple() { - let input = "foo(word, name = 5, list(name2 = 6), word2)"; - let (inner, meta) = (input, input); - - snapshot!(inner as MetaList, @r#" - MetaList { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`word , name = 5 , list (name2 = 6) , word2`), - } - "#); - - snapshot!(meta as Meta, @r#" - Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "foo", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`word , name = 5 , list (name2 = 6) , word2`), - } - "#); - - assert_eq!(meta, Meta::List(inner)); -} - -#[test] -fn test_parse_path() { - let input = "::serde::Serialize"; - snapshot!(input as Meta, @r#" - Meta::Path { - leading_colon: Some, - segments: [ - PathSegment { - ident: "serde", - }, - Token![::], - PathSegment { - ident: "Serialize", - }, - ], - } - "#); -} - -#[test] -fn test_fat_arrow_after_meta() { - fn parse(input: ParseStream) -> Result<()> { - while !input.is_empty() { - let _: Meta = input.parse()?; - let _: Token![=>] = input.parse()?; - let brace; - syn::braced!(brace in input); - } - Ok(()) - } - - let input = quote! { - target_os = "linux" => {} - windows => {} - }; - - parse.parse2(input).unwrap(); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_parse_buffer.rs b/deps/crates/vendor/syn-v2/tests/test_parse_buffer.rs deleted file mode 100644 index f756578b93a9..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_parse_buffer.rs +++ /dev/null @@ -1,104 +0,0 @@ -#![allow(clippy::non_ascii_literal)] - -use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, TokenStream, TokenTree}; -use std::panic; -use syn::parse::discouraged::Speculative as _; -use syn::parse::{Parse, ParseStream, Parser, Result}; -use syn::{parenthesized, Token}; - -#[test] -#[should_panic(expected = "fork was not derived from the advancing parse stream")] -fn smuggled_speculative_cursor_between_sources() { - struct BreakRules; - impl Parse for BreakRules { - fn parse(input1: ParseStream) -> Result<Self> { - let nested = |input2: ParseStream| { - input1.advance_to(input2); - Ok(Self) - }; - nested.parse_str("") - } - } - - syn::parse_str::<BreakRules>("").unwrap(); -} - -#[test] -#[should_panic(expected = "fork was not derived from the advancing parse stream")] -fn smuggled_speculative_cursor_between_brackets() { - struct BreakRules; - impl Parse for BreakRules { - fn parse(input: ParseStream) -> Result<Self> { - let a; - let b; - parenthesized!(a in input); - parenthesized!(b in input); - a.advance_to(&b); - Ok(Self) - } - } - - syn::parse_str::<BreakRules>("()()").unwrap(); -} - -#[test] -#[should_panic(expected = "fork was not derived from the advancing parse stream")] -fn smuggled_speculative_cursor_into_brackets() { - struct BreakRules; - impl Parse for BreakRules { - fn parse(input: ParseStream) -> Result<Self> { - let a; - parenthesized!(a in input); - input.advance_to(&a); - Ok(Self) - } - } - - syn::parse_str::<BreakRules>("()").unwrap(); -} - -#[test] -fn trailing_empty_none_group() { - fn parse(input: ParseStream) -> Result<()> { - input.parse::<Token![+]>()?; - - let content; - parenthesized!(content in input); - content.parse::<Token![+]>()?; - - Ok(()) - } - - // `+ ( + «∅ ∅» ) «∅ «∅ ∅» ∅»` - let tokens = TokenStream::from_iter([ - TokenTree::Punct(Punct::new('+', Spacing::Alone)), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter([ - TokenTree::Punct(Punct::new('+', Spacing::Alone)), - TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())), - ]), - )), - TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())), - TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::from_iter([TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::new(), - ))]), - )), - ]); - - parse.parse2(tokens).unwrap(); -} - -#[test] -#[cfg_attr(miri, ignore)] // https://github.com/rust-lang/miri/issues/4793 -fn test_unwind_safe() { - fn parse(input: ParseStream) -> Result<Ident> { - let thread_result = panic::catch_unwind(|| input.parse()); - thread_result.unwrap() - } - - parse.parse_str("throw").unwrap(); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_parse_quote.rs b/deps/crates/vendor/syn-v2/tests/test_parse_quote.rs deleted file mode 100644 index 600870bab58a..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_parse_quote.rs +++ /dev/null @@ -1,172 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use syn::punctuated::Punctuated; -use syn::{parse_quote, Attribute, Field, Lit, Pat, Stmt, Token}; - -#[test] -fn test_attribute() { - let attr: Attribute = parse_quote!(#[test]); - snapshot!(attr, @r#" - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "test", - }, - ], - }, - } - "#); - - let attr: Attribute = parse_quote!(#![no_std]); - snapshot!(attr, @r#" - Attribute { - style: AttrStyle::Inner, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "no_std", - }, - ], - }, - } - "#); -} - -#[test] -fn test_field() { - let field: Field = parse_quote!(pub enabled: bool); - snapshot!(field, @r#" - Field { - vis: Visibility::Public, - ident: Some("enabled"), - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "bool", - }, - ], - }, - }, - } - "#); - - let field: Field = parse_quote!(primitive::bool); - snapshot!(field, @r#" - Field { - vis: Visibility::Inherited, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "primitive", - }, - Token![::], - PathSegment { - ident: "bool", - }, - ], - }, - }, - } - "#); -} - -#[test] -fn test_pat() { - let pat: Pat = parse_quote!(Some(false) | None); - snapshot!(&pat, @r#" - Pat::Or { - cases: [ - Pat::TupleStruct { - path: Path { - segments: [ - PathSegment { - ident: "Some", - }, - ], - }, - elems: [ - Pat::Lit(ExprLit { - lit: Lit::Bool { - value: false, - }, - }), - ], - }, - Token![|], - Pat::Ident { - ident: "None", - }, - ], - } - "#); - - let boxed_pat: Box<Pat> = parse_quote!(Some(false) | None); - assert_eq!(*boxed_pat, pat); -} - -#[test] -fn test_punctuated() { - let punctuated: Punctuated<Lit, Token![|]> = parse_quote!(true | true); - snapshot!(punctuated, @r#" - [ - Lit::Bool { - value: true, - }, - Token![|], - Lit::Bool { - value: true, - }, - ] - "#); - - let punctuated: Punctuated<Lit, Token![|]> = parse_quote!(true | true |); - snapshot!(punctuated, @r#" - [ - Lit::Bool { - value: true, - }, - Token![|], - Lit::Bool { - value: true, - }, - Token![|], - ] - "#); -} - -#[test] -fn test_vec_stmt() { - let stmts: Vec<Stmt> = parse_quote! { - let _; - true - }; - snapshot!(stmts, @r#" - [ - Stmt::Local { - pat: Pat::Wild, - }, - Stmt::Expr( - Expr::Lit { - lit: Lit::Bool { - value: true, - }, - }, - None, - ), - ] - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_parse_stream.rs b/deps/crates/vendor/syn-v2/tests/test_parse_stream.rs deleted file mode 100644 index a650fc85346c..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_parse_stream.rs +++ /dev/null @@ -1,187 +0,0 @@ -#![allow(clippy::items_after_statements, clippy::let_underscore_untyped)] - -use proc_macro2::{Delimiter, Group, Punct, Spacing, Span, TokenStream, TokenTree}; -use quote::quote; -use syn::ext::IdentExt as _; -use syn::parse::discouraged::AnyDelimiter; -use syn::parse::{ParseStream, Parser as _, Result}; -use syn::{parenthesized, token, Ident, Lifetime, Token}; - -#[test] -fn test_peek_punct() { - let tokens = quote!(+= + =); - - fn assert(input: ParseStream) -> Result<()> { - assert!(input.peek(Token![+])); - assert!(input.peek(Token![+=])); - - let _: Token![+] = input.parse()?; - - assert!(input.peek(Token![=])); - assert!(!input.peek(Token![==])); - assert!(!input.peek(Token![+])); - - let _: Token![=] = input.parse()?; - - assert!(input.peek(Token![+])); - assert!(!input.peek(Token![+=])); - - let _: Token![+] = input.parse()?; - let _: Token![=] = input.parse()?; - Ok(()) - } - - assert.parse2(tokens).unwrap(); -} - -#[test] -fn test_peek_lifetime() { - // 'static ; - let tokens = TokenStream::from_iter([ - TokenTree::Punct(Punct::new('\'', Spacing::Joint)), - TokenTree::Ident(Ident::new("static", Span::call_site())), - TokenTree::Punct(Punct::new(';', Spacing::Alone)), - ]); - - fn assert(input: ParseStream) -> Result<()> { - assert!(input.peek(Lifetime)); - assert!(input.peek2(Token![;])); - assert!(!input.peek2(Token![static])); - - let _: Lifetime = input.parse()?; - - assert!(input.peek(Token![;])); - - let _: Token![;] = input.parse()?; - Ok(()) - } - - assert.parse2(tokens).unwrap(); -} - -#[test] -fn test_peek_not_lifetime() { - // ' static - let tokens = TokenStream::from_iter([ - TokenTree::Punct(Punct::new('\'', Spacing::Alone)), - TokenTree::Ident(Ident::new("static", Span::call_site())), - ]); - - fn assert(input: ParseStream) -> Result<()> { - assert!(!input.peek(Lifetime)); - assert!(input.parse::<Option<Punct>>()?.is_none()); - - let _: TokenTree = input.parse()?; - - assert!(input.peek(Token![static])); - - let _: Token![static] = input.parse()?; - Ok(()) - } - - assert.parse2(tokens).unwrap(); -} - -#[test] -fn test_peek_ident() { - let tokens = quote!(static var); - - fn assert(input: ParseStream) -> Result<()> { - assert!(!input.peek(Ident)); - assert!(input.peek(Ident::peek_any)); - assert!(input.peek(Token![static])); - - let _: Token![static] = input.parse()?; - - assert!(input.peek(Ident)); - assert!(input.peek(Ident::peek_any)); - - let _: Ident = input.parse()?; - Ok(()) - } - - assert.parse2(tokens).unwrap(); -} - -#[test] -fn test_peek_groups() { - // pub ( :: ) «∅ ! = ∅» static - let tokens = TokenStream::from_iter([ - TokenTree::Ident(Ident::new("pub", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter([ - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - ]), - )), - TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::from_iter([ - TokenTree::Punct(Punct::new('!', Spacing::Alone)), - TokenTree::Punct(Punct::new('=', Spacing::Alone)), - ]), - )), - TokenTree::Ident(Ident::new("static", Span::call_site())), - ]); - - fn assert(input: ParseStream) -> Result<()> { - assert!(input.peek2(token::Paren)); - assert!(input.peek3(token::Group)); - assert!(input.peek3(Token![!])); - - let _: Token![pub] = input.parse()?; - - assert!(input.peek(token::Paren)); - assert!(!input.peek(Token![::])); - assert!(!input.peek2(Token![::])); - assert!(input.peek2(Token![!])); - assert!(input.peek2(token::Group)); - assert!(input.peek3(Token![=])); - assert!(!input.peek3(Token![static])); - - let content; - parenthesized!(content in input); - - assert!(content.peek(Token![::])); - assert!(content.peek2(Token![:])); - assert!(!content.peek3(token::Group)); - assert!(!content.peek3(Token![!])); - - assert!(input.peek(token::Group)); - assert!(input.peek(Token![!])); - - let _: Token![::] = content.parse()?; - - assert!(input.peek(token::Group)); - assert!(input.peek(Token![!])); - assert!(input.peek2(Token![=])); - assert!(input.peek3(Token![static])); - assert!(!input.peek2(Token![static])); - - let implicit = input.fork(); - let explicit = input.fork(); - - let _: Token![!] = implicit.parse()?; - assert!(implicit.peek(Token![=])); - assert!(implicit.peek2(Token![static])); - let _: Token![=] = implicit.parse()?; - assert!(implicit.peek(Token![static])); - - let (delimiter, _span, grouped) = explicit.parse_any_delimiter()?; - assert_eq!(delimiter, Delimiter::None); - assert!(grouped.peek(Token![!])); - assert!(grouped.peek2(Token![=])); - assert!(!grouped.peek3(Token![static])); - let _: Token![!] = grouped.parse()?; - assert!(grouped.peek(Token![=])); - assert!(!grouped.peek2(Token![static])); - let _: Token![=] = grouped.parse()?; - assert!(!grouped.peek(Token![static])); - - let _: TokenStream = input.parse()?; - Ok(()) - } - - assert.parse2(tokens).unwrap(); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_pat.rs b/deps/crates/vendor/syn-v2/tests/test_pat.rs deleted file mode 100644 index f778928bc993..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_pat.rs +++ /dev/null @@ -1,158 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, TokenStream, TokenTree}; -use quote::{quote, ToTokens as _}; -use syn::parse::Parser; -use syn::punctuated::Punctuated; -use syn::{parse_quote, token, Item, Pat, PatTuple, Stmt, Token}; - -#[test] -fn test_pat_ident() { - match Pat::parse_single.parse2(quote!(self)).unwrap() { - Pat::Ident(_) => (), - value => panic!("expected PatIdent, got {:?}", value), - } -} - -#[test] -fn test_pat_path() { - match Pat::parse_single.parse2(quote!(self::CONST)).unwrap() { - Pat::Path(_) => (), - value => panic!("expected PatPath, got {:?}", value), - } -} - -#[test] -fn test_leading_vert() { - // https://github.com/rust-lang/rust/blob/1.43.0/src/test/ui/or-patterns/remove-leading-vert.rs - - syn::parse_str::<Item>("fn f() {}").unwrap(); - syn::parse_str::<Item>("fn fun1(| A: E) {}").unwrap_err(); - syn::parse_str::<Item>("fn fun2(|| A: E) {}").unwrap_err(); - - syn::parse_str::<Stmt>("let | () = ();").unwrap_err(); - syn::parse_str::<Stmt>("let (| A): E;").unwrap(); - syn::parse_str::<Stmt>("let (|| A): (E);").unwrap_err(); - syn::parse_str::<Stmt>("let (| A,): (E,);").unwrap(); - syn::parse_str::<Stmt>("let [| A]: [E; 1];").unwrap(); - syn::parse_str::<Stmt>("let [|| A]: [E; 1];").unwrap_err(); - syn::parse_str::<Stmt>("let TS(| A): TS;").unwrap(); - syn::parse_str::<Stmt>("let TS(|| A): TS;").unwrap_err(); - syn::parse_str::<Stmt>("let NS { f: | A }: NS;").unwrap(); - syn::parse_str::<Stmt>("let NS { f: || A }: NS;").unwrap_err(); -} - -#[test] -fn test_group() { - let group = Group::new(Delimiter::None, quote!(Some(_))); - let tokens = TokenStream::from_iter([TokenTree::Group(group)]); - let pat = Pat::parse_single.parse2(tokens).unwrap(); - - snapshot!(pat, @r#" - Pat::TupleStruct { - path: Path { - segments: [ - PathSegment { - ident: "Some", - }, - ], - }, - elems: [ - Pat::Wild, - ], - } - "#); -} - -#[test] -fn test_ranges() { - Pat::parse_single.parse_str("..").unwrap(); - Pat::parse_single.parse_str("..hi").unwrap(); - Pat::parse_single.parse_str("lo..").unwrap(); - Pat::parse_single.parse_str("lo..hi").unwrap(); - - Pat::parse_single.parse_str("..=").unwrap_err(); - Pat::parse_single.parse_str("..=hi").unwrap(); - Pat::parse_single.parse_str("lo..=").unwrap_err(); - Pat::parse_single.parse_str("lo..=hi").unwrap(); - - Pat::parse_single.parse_str("...").unwrap_err(); - Pat::parse_single.parse_str("...hi").unwrap_err(); - Pat::parse_single.parse_str("lo...").unwrap_err(); - Pat::parse_single.parse_str("lo...hi").unwrap(); - - Pat::parse_single.parse_str("[lo..]").unwrap_err(); - Pat::parse_single.parse_str("[..=hi]").unwrap_err(); - Pat::parse_single.parse_str("[(lo..)]").unwrap(); - Pat::parse_single.parse_str("[(..=hi)]").unwrap(); - Pat::parse_single.parse_str("[lo..=hi]").unwrap(); - - Pat::parse_single.parse_str("[_, lo.., _]").unwrap_err(); - Pat::parse_single.parse_str("[_, ..=hi, _]").unwrap_err(); - Pat::parse_single.parse_str("[_, (lo..), _]").unwrap(); - Pat::parse_single.parse_str("[_, (..=hi), _]").unwrap(); - Pat::parse_single.parse_str("[_, lo..=hi, _]").unwrap(); -} - -#[test] -fn test_tuple_comma() { - let mut expr = PatTuple { - attrs: Vec::new(), - paren_token: token::Paren::default(), - elems: Punctuated::new(), - }; - snapshot!(expr.to_token_stream() as Pat, @"Pat::Tuple"); - - expr.elems.push_value(parse_quote!(_)); - // Must not parse to Pat::Paren - snapshot!(expr.to_token_stream() as Pat, @r#" - Pat::Tuple { - elems: [ - Pat::Wild, - Token![,], - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Pat, @r#" - Pat::Tuple { - elems: [ - Pat::Wild, - Token![,], - ], - } - "#); - - expr.elems.push_value(parse_quote!(_)); - snapshot!(expr.to_token_stream() as Pat, @r#" - Pat::Tuple { - elems: [ - Pat::Wild, - Token![,], - Pat::Wild, - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Pat, @r#" - Pat::Tuple { - elems: [ - Pat::Wild, - Token![,], - Pat::Wild, - Token![,], - ], - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_path.rs b/deps/crates/vendor/syn-v2/tests/test_path.rs deleted file mode 100644 index 7f9e515d2696..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_path.rs +++ /dev/null @@ -1,116 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; -use quote::{quote, ToTokens}; -use syn::{parse_quote, Expr, Type, TypePath}; - -#[test] -fn parse_interpolated_leading_component() { - // mimics the token stream corresponding to `$mod::rest` - let tokens = TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, quote! { first })), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("rest", Span::call_site())), - ]); - - snapshot!(tokens.clone() as Expr, @r#" - Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "first", - }, - Token![::], - PathSegment { - ident: "rest", - }, - ], - }, - } - "#); - - snapshot!(tokens as Type, @r#" - Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "first", - }, - Token![::], - PathSegment { - ident: "rest", - }, - ], - }, - } - "#); -} - -#[test] -fn print_incomplete_qpath() { - // qpath with `as` token - let mut ty: TypePath = parse_quote!(<Self as A>::Q); - snapshot!(ty.to_token_stream(), @"TokenStream(`< Self as A > :: Q`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(`< Self as A > ::`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(`< Self >`)"); - assert!(ty.path.segments.pop().is_none()); - - // qpath without `as` token - let mut ty: TypePath = parse_quote!(<Self>::A::B); - snapshot!(ty.to_token_stream(), @"TokenStream(`< Self > :: A :: B`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(`< Self > :: A ::`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(`< Self > ::`)"); - assert!(ty.path.segments.pop().is_none()); - - // normal path - let mut ty: TypePath = parse_quote!(Self::A::B); - snapshot!(ty.to_token_stream(), @"TokenStream(`Self :: A :: B`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(`Self :: A ::`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(`Self ::`)"); - assert!(ty.path.segments.pop().is_some()); - snapshot!(ty.to_token_stream(), @"TokenStream(``)"); - assert!(ty.path.segments.pop().is_none()); -} - -#[test] -fn parse_parenthesized_path_arguments_with_disambiguator() { - #[rustfmt::skip] - let tokens = quote!(dyn FnOnce::() -> !); - snapshot!(tokens as Type, @r#" - Type::TraitObject { - dyn_token: Some, - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "FnOnce", - arguments: PathArguments::Parenthesized { - output: ReturnType::Type( - Type::Never, - ), - }, - }, - ], - }, - }), - ], - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_precedence.rs b/deps/crates/vendor/syn-v2/tests/test_precedence.rs deleted file mode 100644 index 4950eecb60aa..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_precedence.rs +++ /dev/null @@ -1,556 +0,0 @@ -// This test does the following for every file in the rust-lang/rust repo: -// -// 1. Parse the file using syn into a syn::File. -// 2. Extract every syn::Expr from the file. -// 3. Print each expr to a string of source code. -// 4. Parse the source code using librustc_parse into a rustc_ast::Expr. -// 5. For both the syn::Expr and rustc_ast::Expr, crawl the syntax tree to -// insert parentheses surrounding every subexpression. -// 6. Serialize the fully parenthesized syn::Expr to a string of source code. -// 7. Parse the fully parenthesized source code using librustc_parse. -// 8. Compare the rustc_ast::Expr resulting from parenthesizing using rustc data -// structures vs syn data structures, ignoring spans. If they agree, rustc's -// parser and syn's parser have identical handling of expression precedence. - -#![cfg(not(syn_disable_nightly_tests))] -#![cfg(not(miri))] -#![recursion_limit = "1024"] -#![feature(rustc_private)] -#![allow( - clippy::blocks_in_conditions, - clippy::doc_markdown, - clippy::elidable_lifetime_names, - clippy::explicit_deref_methods, - clippy::let_underscore_untyped, - clippy::manual_assert, - clippy::manual_let_else, - clippy::match_like_matches_macro, - clippy::match_wildcard_for_single_variants, - clippy::needless_lifetimes, - clippy::too_many_lines, - clippy::uninlined_format_args, - clippy::unnecessary_box_returns -)] - -extern crate rustc_ast; -extern crate rustc_ast_pretty; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_span; - -use crate::common::eq::SpanlessEq; -use crate::common::parse; -use quote::ToTokens; -use rustc_ast::ast; -use rustc_ast_pretty::pprust; -use rustc_span::edition::Edition; -use std::fs; -use std::mem; -use std::path::Path; -use std::process; -use std::sync::atomic::{AtomicUsize, Ordering}; -use syn::parse::Parser as _; - -#[macro_use] -mod macros; - -mod common; -mod repo; - -#[path = "../src/scan_expr.rs"] -mod scan_expr; - -#[test] -fn test_rustc_precedence() { - repo::rayon_init(); - repo::clone_rust(); - let abort_after = repo::abort_after(); - if abort_after == 0 { - panic!("skipping all precedence tests"); - } - - let passed = AtomicUsize::new(0); - let failed = AtomicUsize::new(0); - - repo::for_each_rust_file(|path| { - let content = fs::read_to_string(path).unwrap(); - - let (l_passed, l_failed) = match syn::parse_file(&content) { - Ok(file) => { - let edition = repo::edition(path).parse().unwrap(); - let exprs = collect_exprs(file); - let (l_passed, l_failed) = test_expressions(path, edition, exprs); - errorf!( - "=== {}: {} passed | {} failed\n", - path.display(), - l_passed, - l_failed, - ); - (l_passed, l_failed) - } - Err(msg) => { - errorf!("\nFAIL {} - syn failed to parse: {}\n", path.display(), msg); - (0, 1) - } - }; - - passed.fetch_add(l_passed, Ordering::Relaxed); - let prev_failed = failed.fetch_add(l_failed, Ordering::Relaxed); - - if prev_failed + l_failed >= abort_after { - process::exit(1); - } - }); - - let passed = passed.into_inner(); - let failed = failed.into_inner(); - - errorf!("\n===== Precedence Test Results =====\n"); - errorf!("{} passed | {} failed\n", passed, failed); - - if failed > 0 { - panic!("{} failures", failed); - } -} - -fn test_expressions(path: &Path, edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) { - let mut passed = 0; - let mut failed = 0; - - rustc_span::create_session_if_not_set_then(edition, |_| { - for expr in exprs { - let expr_tokens = expr.to_token_stream(); - let source_code = expr_tokens.to_string(); - let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&source_code) { - e - } else { - failed += 1; - errorf!( - "\nFAIL {} - librustc failed to parse original\n", - path.display(), - ); - continue; - }; - - let syn_parenthesized_code = - syn_parenthesize(expr.clone()).to_token_stream().to_string(); - let syn_ast = if let Some(e) = parse::librustc_expr(&syn_parenthesized_code) { - e - } else { - failed += 1; - errorf!( - "\nFAIL {} - librustc failed to parse parenthesized\n", - path.display(), - ); - continue; - }; - - if !SpanlessEq::eq(&syn_ast, &librustc_ast) { - failed += 1; - let syn_pretty = pprust::expr_to_string(&syn_ast); - let librustc_pretty = pprust::expr_to_string(&librustc_ast); - errorf!( - "\nFAIL {}\n{}\nsyn != rustc\n{}\n", - path.display(), - syn_pretty, - librustc_pretty, - ); - continue; - } - - let expr_invisible = make_parens_invisible(expr); - let Ok(reparsed_expr_invisible) = syn::parse2(expr_invisible.to_token_stream()) else { - failed += 1; - errorf!( - "\nFAIL {} - syn failed to parse invisible delimiters\n{}\n", - path.display(), - source_code, - ); - continue; - }; - if expr_invisible != reparsed_expr_invisible { - failed += 1; - errorf!( - "\nFAIL {} - mismatch after parsing invisible delimiters\n{}\n", - path.display(), - source_code, - ); - continue; - } - - if scan_expr::scan_expr.parse2(expr_tokens).is_err() { - failed += 1; - errorf!( - "\nFAIL {} - failed to scan expr\n{}\n", - path.display(), - source_code, - ); - continue; - } - - passed += 1; - } - }); - - (passed, failed) -} - -fn librustc_parse_and_rewrite(input: &str) -> Option<Box<ast::Expr>> { - parse::librustc_expr(input).map(librustc_parenthesize) -} - -fn librustc_parenthesize(mut librustc_expr: Box<ast::Expr>) -> Box<ast::Expr> { - use rustc_ast::ast::{ - AssocItem, AssocItemKind, Attribute, BinOpKind, Block, BoundConstness, Expr, ExprField, - ExprKind, GenericArg, GenericBound, Local, LocalKind, Pat, PolyTraitRef, Stmt, StmtKind, - StructExpr, StructRest, TraitBoundModifiers, Ty, - }; - use rustc_ast::mut_visit::{walk_flat_map_assoc_item, MutVisitor}; - use rustc_ast::visit::{AssocCtxt, BoundKind}; - use rustc_data_structures::flat_map_in_place::FlatMapInPlace; - use rustc_data_structures::smallvec::SmallVec; - use rustc_data_structures::thin_vec::ThinVec; - use rustc_span::DUMMY_SP; - use std::ops::DerefMut; - - struct FullyParenthesize; - - fn contains_let_chain(expr: &Expr) -> bool { - match &expr.kind { - ExprKind::Let(..) => true, - ExprKind::Binary(binop, left, right) => { - binop.node == BinOpKind::And - && (contains_let_chain(left) || contains_let_chain(right)) - } - _ => false, - } - } - - fn flat_map_field<T: MutVisitor>(mut f: ExprField, vis: &mut T) -> Vec<ExprField> { - if f.is_shorthand { - noop_visit_expr(&mut f.expr, vis); - } else { - vis.visit_expr(&mut f.expr); - } - vec![f] - } - - fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> { - let kind = match stmt.kind { - // Don't wrap toplevel expressions in statements. - StmtKind::Expr(mut e) => { - noop_visit_expr(&mut e, vis); - StmtKind::Expr(e) - } - StmtKind::Semi(mut e) => { - noop_visit_expr(&mut e, vis); - StmtKind::Semi(e) - } - s => s, - }; - - vec![Stmt { kind, ..stmt }] - } - - fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) { - match &mut e.kind { - ExprKind::Become(..) => {} - ExprKind::Struct(expr) => { - let StructExpr { - qself, - path, - fields, - rest, - } = expr.deref_mut(); - if let Some(qself) = qself { - vis.visit_qself(qself); - } - vis.visit_path(path); - fields.flat_map_in_place(|field| flat_map_field(field, vis)); - if let StructRest::Base(rest) = rest { - vis.visit_expr(rest); - } - } - _ => rustc_ast::mut_visit::walk_expr(vis, e), - } - } - - impl MutVisitor for FullyParenthesize { - fn visit_expr(&mut self, e: &mut Expr) { - noop_visit_expr(e, self); - match e.kind { - ExprKind::Block(..) | ExprKind::If(..) | ExprKind::Let(..) => {} - ExprKind::Binary(..) if contains_let_chain(e) => {} - _ => { - let inner = mem::replace(e, Expr::dummy()); - *e = Expr { - id: ast::DUMMY_NODE_ID, - kind: ExprKind::Paren(Box::new(inner)), - span: DUMMY_SP, - attrs: ThinVec::new(), - tokens: None, - }; - } - } - } - - fn visit_generic_arg(&mut self, arg: &mut GenericArg) { - match arg { - GenericArg::Lifetime(_lifetime) => {} - GenericArg::Type(arg) => self.visit_ty(arg), - // Don't wrap unbraced const generic arg as that's invalid syntax. - GenericArg::Const(anon_const) => { - if let ExprKind::Block(..) = &mut anon_const.value.kind { - noop_visit_expr(&mut anon_const.value, self); - } - } - } - } - - fn visit_param_bound(&mut self, bound: &mut GenericBound, _ctxt: BoundKind) { - match bound { - GenericBound::Trait(PolyTraitRef { - modifiers: - TraitBoundModifiers { - constness: BoundConstness::Maybe(_), - .. - }, - .. - }) - | GenericBound::Outlives(..) - | GenericBound::Use(..) => {} - GenericBound::Trait(ty) => self.visit_poly_trait_ref(ty), - } - } - - fn visit_block(&mut self, block: &mut Block) { - self.visit_id(&mut block.id); - block - .stmts - .flat_map_in_place(|stmt| flat_map_stmt(stmt, self)); - self.visit_span(&mut block.span); - } - - fn visit_local(&mut self, local: &mut Local) { - match &mut local.kind { - LocalKind::Decl => {} - LocalKind::Init(init) => { - self.visit_expr(init); - } - LocalKind::InitElse(init, els) => { - self.visit_expr(init); - self.visit_block(els); - } - } - } - - fn flat_map_assoc_item( - &mut self, - item: Box<AssocItem>, - ctxt: AssocCtxt, - ) -> SmallVec<[Box<AssocItem>; 1]> { - match &item.kind { - AssocItemKind::Const(const_item) - if !const_item.generics.params.is_empty() - || !const_item.generics.where_clause.predicates.is_empty() => - { - SmallVec::from([item]) - } - _ => walk_flat_map_assoc_item(self, item, ctxt), - } - } - - // We don't want to look at expressions that might appear in patterns or - // types yet. We'll look into comparing those in the future. For now - // focus on expressions appearing in other places. - fn visit_pat(&mut self, pat: &mut Pat) { - let _ = pat; - } - - fn visit_ty(&mut self, ty: &mut Ty) { - let _ = ty; - } - - fn visit_attribute(&mut self, attr: &mut Attribute) { - let _ = attr; - } - } - - let mut folder = FullyParenthesize; - folder.visit_expr(&mut librustc_expr); - librustc_expr -} - -fn syn_parenthesize(syn_expr: syn::Expr) -> syn::Expr { - use syn::fold::{fold_expr, fold_generic_argument, Fold}; - use syn::{ - token, BinOp, Expr, ExprParen, GenericArgument, Lit, MetaNameValue, Pat, Stmt, Type, - }; - - struct FullyParenthesize; - - fn parenthesize(expr: Expr) -> Expr { - Expr::Paren(ExprParen { - attrs: Vec::new(), - expr: Box::new(expr), - paren_token: token::Paren::default(), - }) - } - - fn needs_paren(expr: &Expr) -> bool { - match expr { - Expr::Group(_) => unreachable!(), - Expr::If(_) | Expr::Unsafe(_) | Expr::Block(_) | Expr::Let(_) => false, - Expr::Binary(_) => !contains_let_chain(expr), - _ => true, - } - } - - fn contains_let_chain(expr: &Expr) -> bool { - match expr { - Expr::Let(_) => true, - Expr::Binary(expr) => { - matches!(expr.op, BinOp::And(_)) - && (contains_let_chain(&expr.left) || contains_let_chain(&expr.right)) - } - _ => false, - } - } - - impl Fold for FullyParenthesize { - fn fold_expr(&mut self, expr: Expr) -> Expr { - let needs_paren = needs_paren(&expr); - let folded = fold_expr(self, expr); - if needs_paren { - parenthesize(folded) - } else { - folded - } - } - - fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument { - match arg { - GenericArgument::Const(arg) => GenericArgument::Const(match arg { - Expr::Block(_) => fold_expr(self, arg), - // Don't wrap unbraced const generic arg as that's invalid syntax. - _ => arg, - }), - _ => fold_generic_argument(self, arg), - } - } - - fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { - match stmt { - // Don't wrap toplevel expressions in statements. - Stmt::Expr(Expr::Verbatim(_), Some(_)) => stmt, - Stmt::Expr(e, semi) => Stmt::Expr(fold_expr(self, e), semi), - s => s, - } - } - - fn fold_meta_name_value(&mut self, meta: MetaNameValue) -> MetaNameValue { - // Don't turn #[p = "..."] into #[p = ("...")]. - meta - } - - // We don't want to look at expressions that might appear in patterns or - // types yet. We'll look into comparing those in the future. For now - // focus on expressions appearing in other places. - fn fold_pat(&mut self, pat: Pat) -> Pat { - pat - } - - fn fold_type(&mut self, ty: Type) -> Type { - ty - } - - fn fold_lit(&mut self, lit: Lit) -> Lit { - if let Lit::Verbatim(lit) = &lit { - panic!("unexpected verbatim literal: {lit}"); - } - lit - } - } - - let mut folder = FullyParenthesize; - folder.fold_expr(syn_expr) -} - -fn make_parens_invisible(expr: syn::Expr) -> syn::Expr { - use syn::fold::{fold_expr, fold_stmt, Fold}; - use syn::{token, Expr, ExprGroup, ExprParen, Stmt}; - - struct MakeParensInvisible; - - impl Fold for MakeParensInvisible { - fn fold_expr(&mut self, mut expr: Expr) -> Expr { - if let Expr::Paren(paren) = expr { - expr = Expr::Group(ExprGroup { - attrs: paren.attrs, - group_token: token::Group(paren.paren_token.span.join()), - expr: paren.expr, - }); - } - fold_expr(self, expr) - } - - fn fold_stmt(&mut self, stmt: Stmt) -> Stmt { - if let Stmt::Expr(expr @ (Expr::Binary(_) | Expr::Call(_) | Expr::Cast(_)), None) = stmt - { - Stmt::Expr( - Expr::Paren(ExprParen { - attrs: Vec::new(), - paren_token: token::Paren::default(), - expr: Box::new(fold_expr(self, expr)), - }), - None, - ) - } else { - fold_stmt(self, stmt) - } - } - } - - let mut folder = MakeParensInvisible; - folder.fold_expr(expr) -} - -/// Walk through a crate collecting all expressions we can find in it. -fn collect_exprs(file: syn::File) -> Vec<syn::Expr> { - use syn::fold::Fold; - use syn::punctuated::Punctuated; - use syn::{token, ConstParam, Expr, ExprTuple, Pat, Path}; - - struct CollectExprs(Vec<Expr>); - impl Fold for CollectExprs { - fn fold_expr(&mut self, expr: Expr) -> Expr { - match expr { - Expr::Verbatim(_) => {} - _ => self.0.push(expr), - } - - Expr::Tuple(ExprTuple { - attrs: vec![], - elems: Punctuated::new(), - paren_token: token::Paren::default(), - }) - } - - fn fold_pat(&mut self, pat: Pat) -> Pat { - pat - } - - fn fold_path(&mut self, path: Path) -> Path { - // Skip traversing into const generic path arguments - path - } - - fn fold_const_param(&mut self, const_param: ConstParam) -> ConstParam { - const_param - } - } - - let mut folder = CollectExprs(vec![]); - folder.fold_file(file); - folder.0 -} diff --git a/deps/crates/vendor/syn-v2/tests/test_punctuated.rs b/deps/crates/vendor/syn-v2/tests/test_punctuated.rs deleted file mode 100644 index 14ea96c77172..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_punctuated.rs +++ /dev/null @@ -1,92 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -use syn::punctuated::{Pair, Punctuated}; -use syn::Token; - -macro_rules! punctuated { - ($($e:expr,)+) => {{ - let mut seq = ::syn::punctuated::Punctuated::new(); - $( - seq.push($e); - )+ - seq - }}; - - ($($e:expr),+) => { - punctuated!($($e,)+) - }; -} - -macro_rules! check_exact_size_iterator { - ($iter:expr) => {{ - let iter = $iter; - let size_hint = iter.size_hint(); - let len = iter.len(); - let count = iter.count(); - assert_eq!(len, count); - assert_eq!(size_hint, (count, Some(count))); - }}; -} - -#[test] -fn pairs() { - let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); - - check_exact_size_iterator!(p.pairs()); - check_exact_size_iterator!(p.pairs_mut()); - check_exact_size_iterator!(p.into_pairs()); - - let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); - - assert_eq!(p.pairs().next_back().map(Pair::into_value), Some(&4)); - assert_eq!( - p.pairs_mut().next_back().map(Pair::into_value), - Some(&mut 4) - ); - assert_eq!(p.into_pairs().next_back().map(Pair::into_value), Some(4)); -} - -#[test] -fn iter() { - let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); - - check_exact_size_iterator!(p.iter()); - check_exact_size_iterator!(p.iter_mut()); - check_exact_size_iterator!(p.into_iter()); - - let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); - - assert_eq!(p.iter().next_back(), Some(&4)); - assert_eq!(p.iter_mut().next_back(), Some(&mut 4)); - assert_eq!(p.into_iter().next_back(), Some(4)); -} - -#[test] -fn may_dangle() { - let p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); - for element in &p { - if *element == 2 { - drop(p); - break; - } - } - - let mut p: Punctuated<_, Token![,]> = punctuated!(2, 3, 4); - for element in &mut p { - if *element == 2 { - drop(p); - break; - } - } -} - -#[test] -#[should_panic = "index out of bounds: the len is 0 but the index is 0"] -fn index_out_of_bounds() { - let p = Punctuated::<syn::Ident, Token![,]>::new(); - let _ = p[0].clone(); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_receiver.rs b/deps/crates/vendor/syn-v2/tests/test_receiver.rs deleted file mode 100644 index 98194101fdac..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_receiver.rs +++ /dev/null @@ -1,327 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use syn::{parse_quote, TraitItemFn}; - -#[test] -fn test_by_value() { - let TraitItemFn { sig, .. } = parse_quote! { - fn by_value(self: Self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_by_mut_value() { - let TraitItemFn { sig, .. } = parse_quote! { - fn by_mut(mut self: Self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - mutability: Some, - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_by_ref() { - let TraitItemFn { sig, .. } = parse_quote! { - fn by_ref(self: &Self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - colon_token: Some, - ty: Type::Reference { - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }, - }) - "#); -} - -#[test] -fn test_by_box() { - let TraitItemFn { sig, .. } = parse_quote! { - fn by_box(self: Box<Self>); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Box", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }), - ], - }, - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_by_pin() { - let TraitItemFn { sig, .. } = parse_quote! { - fn by_pin(self: Pin<Self>); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Pin", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }), - ], - }, - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_explicit_type() { - let TraitItemFn { sig, .. } = parse_quote! { - fn explicit_type(self: Pin<MyType>); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - colon_token: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Pin", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "MyType", - }, - ], - }, - }), - ], - }, - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_value_shorthand() { - let TraitItemFn { sig, .. } = parse_quote! { - fn value_shorthand(self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_mut_value_shorthand() { - let TraitItemFn { sig, .. } = parse_quote! { - fn mut_value_shorthand(mut self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - mutability: Some, - ty: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }) - "#); -} - -#[test] -fn test_ref_shorthand() { - let TraitItemFn { sig, .. } = parse_quote! { - fn ref_shorthand(&self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - reference: Some(None), - ty: Type::Reference { - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }, - }) - "#); -} - -#[test] -fn test_ref_shorthand_with_lifetime() { - let TraitItemFn { sig, .. } = parse_quote! { - fn ref_shorthand(&'a self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - reference: Some(Some(Lifetime { - ident: "a", - })), - ty: Type::Reference { - lifetime: Some(Lifetime { - ident: "a", - }), - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }, - }) - "#); -} - -#[test] -fn test_ref_mut_shorthand() { - let TraitItemFn { sig, .. } = parse_quote! { - fn ref_mut_shorthand(&mut self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - reference: Some(None), - mutability: Some, - ty: Type::Reference { - mutability: Some, - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }, - }) - "#); -} - -#[test] -fn test_ref_mut_shorthand_with_lifetime() { - let TraitItemFn { sig, .. } = parse_quote! { - fn ref_mut_shorthand(&'a mut self); - }; - snapshot!(&sig.inputs[0], @r#" - FnArg::Receiver(Receiver { - reference: Some(Some(Lifetime { - ident: "a", - })), - mutability: Some, - ty: Type::Reference { - lifetime: Some(Lifetime { - ident: "a", - }), - mutability: Some, - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Self", - }, - ], - }, - }, - }, - }) - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_round_trip.rs b/deps/crates/vendor/syn-v2/tests/test_round_trip.rs deleted file mode 100644 index c19adb843c86..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_round_trip.rs +++ /dev/null @@ -1,225 +0,0 @@ -#![cfg(not(syn_disable_nightly_tests))] -#![cfg(not(miri))] -#![recursion_limit = "1024"] -#![feature(rustc_private)] -#![allow( - clippy::blocks_in_conditions, - clippy::elidable_lifetime_names, - clippy::manual_assert, - clippy::manual_let_else, - clippy::match_like_matches_macro, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] -#![allow(mismatched_lifetime_syntaxes)] - -extern crate rustc_ast; -extern crate rustc_ast_pretty; -extern crate rustc_data_structures; -extern crate rustc_driver; -extern crate rustc_error_messages; -extern crate rustc_errors; -extern crate rustc_expand; -extern crate rustc_parse; -extern crate rustc_session; -extern crate rustc_span; - -use crate::common::eq::SpanlessEq; -use quote::quote; -use rustc_ast::ast::{ - AngleBracketedArg, Crate, GenericArg, GenericArgs, GenericParamKind, Generics, -}; -use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast_pretty::pprust; -use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_error_messages::DiagMessage; -use rustc_errors::{Diag, PResult}; -use rustc_parse::lexer::StripTokens; -use rustc_session::parse::ParseSess; -use rustc_span::FileName; -use std::borrow::Cow; -use std::fs; -use std::panic; -use std::path::Path; -use std::process; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::time::Instant; - -#[macro_use] -mod macros; - -mod common; -mod repo; - -#[test] -fn test_round_trip() { - repo::rayon_init(); - repo::clone_rust(); - let abort_after = repo::abort_after(); - if abort_after == 0 { - panic!("skipping all round_trip tests"); - } - - let failed = AtomicUsize::new(0); - - repo::for_each_rust_file(|path| test(path, &failed, abort_after)); - - let failed = failed.into_inner(); - if failed > 0 { - panic!("{} failures", failed); - } -} - -fn test(path: &Path, failed: &AtomicUsize, abort_after: usize) { - let failed = || { - let prev_failed = failed.fetch_add(1, Ordering::Relaxed); - if prev_failed + 1 >= abort_after { - process::exit(1); - } - }; - - let content = fs::read_to_string(path).unwrap(); - - let (back, elapsed) = match panic::catch_unwind(|| { - let start = Instant::now(); - let result = syn::parse_file(&content); - let elapsed = start.elapsed(); - result.map(|krate| (quote!(#krate).to_string(), elapsed)) - }) { - Err(_) => { - errorf!("=== {}: syn panic\n", path.display()); - failed(); - return; - } - Ok(Err(msg)) => { - errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg); - failed(); - return; - } - Ok(Ok(result)) => result, - }; - - let edition = repo::edition(path).parse().unwrap(); - - rustc_span::create_session_if_not_set_then(edition, |_| { - let equal = match panic::catch_unwind(|| { - let sess = ParseSess::new(); - let before = match librustc_parse(content, &sess) { - Ok(before) => before, - Err(diagnostic) => { - errorf!( - "=== {}: ignore - librustc failed to parse original content: {}\n", - path.display(), - translate_message(&diagnostic), - ); - diagnostic.cancel(); - return Err(true); - } - }; - let after = match librustc_parse(back, &sess) { - Ok(after) => after, - Err(diagnostic) => { - errorf!("=== {}: librustc failed to parse", path.display()); - diagnostic.emit(); - return Err(false); - } - }; - Ok((before, after)) - }) { - Err(_) => { - errorf!("=== {}: ignoring librustc panic\n", path.display()); - true - } - Ok(Err(equal)) => equal, - Ok(Ok((mut before, mut after))) => { - normalize(&mut before); - normalize(&mut after); - if SpanlessEq::eq(&before, &after) { - errorf!( - "=== {}: pass in {}ms\n", - path.display(), - elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos()) / 1_000_000 - ); - true - } else { - errorf!( - "=== {}: FAIL\n{}\n!=\n{}\n", - path.display(), - pprust::crate_to_string_for_macros(&before), - pprust::crate_to_string_for_macros(&after), - ); - false - } - } - }; - if !equal { - failed(); - } - }); -} - -fn librustc_parse(content: String, sess: &ParseSess) -> PResult<Crate> { - static COUNTER: AtomicUsize = AtomicUsize::new(0); - let counter = COUNTER.fetch_add(1, Ordering::Relaxed); - let name = FileName::Custom(format!("test_round_trip{}", counter)); - let mut parser = rustc_parse::new_parser_from_source_str( - sess, - name, - content, - StripTokens::ShebangAndFrontmatter, - ) - .unwrap(); - parser.parse_crate_mod() -} - -fn translate_message(diagnostic: &Diag) -> Cow<'static, str> { - match &diagnostic.messages[0].0 { - DiagMessage::Str(msg) | DiagMessage::Inline(msg) => msg.clone(), - } -} - -fn normalize(krate: &mut Crate) { - struct NormalizeVisitor; - - impl MutVisitor for NormalizeVisitor { - fn visit_generic_args(&mut self, e: &mut GenericArgs) { - if let GenericArgs::AngleBracketed(e) = e { - #[derive(Ord, PartialOrd, Eq, PartialEq)] - enum Group { - Lifetimes, - TypesAndConsts, - Constraints, - } - e.args.sort_by_key(|arg| match arg { - AngleBracketedArg::Arg(arg) => match arg { - GenericArg::Lifetime(_) => Group::Lifetimes, - GenericArg::Type(_) | GenericArg::Const(_) => Group::TypesAndConsts, - }, - AngleBracketedArg::Constraint(_) => Group::Constraints, - }); - } - mut_visit::walk_generic_args(self, e); - } - - fn visit_generics(&mut self, e: &mut Generics) { - #[derive(Ord, PartialOrd, Eq, PartialEq)] - enum Group { - Lifetimes, - TypesAndConsts, - } - e.params.sort_by_key(|param| match param.kind { - GenericParamKind::Lifetime => Group::Lifetimes, - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - Group::TypesAndConsts - } - }); - e.params - .flat_map_in_place(|param| self.flat_map_generic_param(param)); - if e.where_clause.predicates.is_empty() { - e.where_clause.has_where_token = false; - } - } - } - - NormalizeVisitor.visit_crate(krate); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_shebang.rs b/deps/crates/vendor/syn-v2/tests/test_shebang.rs deleted file mode 100644 index 3b55ddfdd59d..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_shebang.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -#[test] -fn test_basic() { - let content = "#!/usr/bin/env rustx\nfn main() {}"; - let file = syn::parse_file(content).unwrap(); - snapshot!(file, @r##" - File { - shebang: Some("#!/usr/bin/env rustx"), - items: [ - Item::Fn { - vis: Visibility::Inherited, - sig: Signature { - ident: "main", - generics: Generics, - output: ReturnType::Default, - }, - block: Block { - stmts: [], - }, - }, - ], - } - "##); -} - -#[test] -fn test_comment() { - let content = "#!//am/i/a/comment\n[allow(dead_code)] fn main() {}"; - let file = syn::parse_file(content).unwrap(); - snapshot!(file, @r#" - File { - attrs: [ - Attribute { - style: AttrStyle::Inner, - meta: Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "allow", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`dead_code`), - }, - }, - ], - items: [ - Item::Fn { - vis: Visibility::Inherited, - sig: Signature { - ident: "main", - generics: Generics, - output: ReturnType::Default, - }, - block: Block { - stmts: [], - }, - }, - ], - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_size.rs b/deps/crates/vendor/syn-v2/tests/test_size.rs deleted file mode 100644 index 29fd43589d42..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_size.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Assumes proc-macro2's "span-locations" feature is off. - -use std::mem; -use syn::{Expr, Item, Lit, Pat, Type}; - -#[rustversion::attr(before(2022-11-24), ignore = "requires nightly-2022-11-24 or newer")] -#[rustversion::attr( - since(2022-11-24), - cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") -)] -#[test] -fn test_expr_size() { - assert_eq!(mem::size_of::<Expr>(), 176); -} - -#[rustversion::attr(before(2022-09-09), ignore = "requires nightly-2022-09-09 or newer")] -#[rustversion::attr( - since(2022-09-09), - cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") -)] -#[test] -fn test_item_size() { - assert_eq!(mem::size_of::<Item>(), 352); -} - -#[rustversion::attr(before(2023-04-29), ignore = "requires nightly-2023-04-29 or newer")] -#[rustversion::attr( - since(2023-04-29), - cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") -)] -#[test] -fn test_type_size() { - assert_eq!(mem::size_of::<Type>(), 224); -} - -#[rustversion::attr(before(2023-04-29), ignore = "requires nightly-2023-04-29 or newer")] -#[rustversion::attr( - since(2023-04-29), - cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") -)] -#[test] -fn test_pat_size() { - assert_eq!(mem::size_of::<Pat>(), 184); -} - -#[rustversion::attr(before(2023-12-20), ignore = "requires nightly-2023-12-20 or newer")] -#[rustversion::attr( - since(2023-12-20), - cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") -)] -#[test] -fn test_lit_size() { - assert_eq!(mem::size_of::<Lit>(), 24); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_stmt.rs b/deps/crates/vendor/syn-v2/tests/test_stmt.rs deleted file mode 100644 index 101c1b1c906d..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_stmt.rs +++ /dev/null @@ -1,337 +0,0 @@ -#![allow( - clippy::assertions_on_result_states, - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::non_ascii_literal, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; -use quote::{quote, ToTokens as _}; -use syn::parse::Parser as _; -use syn::{Block, Stmt}; - -#[test] -fn test_raw_operator() { - let stmt = syn::parse_str::<Stmt>("let _ = &raw const x;").unwrap(); - - snapshot!(stmt, @r#" - Stmt::Local { - pat: Pat::Wild, - init: Some(LocalInit { - expr: Expr::RawAddr { - mutability: PointerMutability::Const, - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "x", - }, - ], - }, - }, - }, - }), - } - "#); -} - -#[test] -fn test_raw_variable() { - let stmt = syn::parse_str::<Stmt>("let _ = &raw;").unwrap(); - - snapshot!(stmt, @r#" - Stmt::Local { - pat: Pat::Wild, - init: Some(LocalInit { - expr: Expr::Reference { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "raw", - }, - ], - }, - }, - }, - }), - } - "#); -} - -#[test] -fn test_raw_invalid() { - assert!(syn::parse_str::<Stmt>("let _ = &raw x;").is_err()); -} - -#[test] -fn test_none_group() { - // «∅ async fn f() {} ∅» - let tokens = TokenStream::from_iter([TokenTree::Group(Group::new( - Delimiter::None, - TokenStream::from_iter([ - TokenTree::Ident(Ident::new("async", Span::call_site())), - TokenTree::Ident(Ident::new("fn", Span::call_site())), - TokenTree::Ident(Ident::new("f", Span::call_site())), - TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), - TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), - ]), - ))]); - snapshot!(tokens as Stmt, @r#" - Stmt::Item(Item::Fn { - vis: Visibility::Inherited, - sig: Signature { - asyncness: Some, - ident: "f", - generics: Generics, - output: ReturnType::Default, - }, - block: Block { - stmts: [], - }, - }) - "#); - - let tokens = Group::new(Delimiter::None, quote!(let None = None)).to_token_stream(); - let stmts = Block::parse_within.parse2(tokens).unwrap(); - snapshot!(stmts, @r#" - [ - Stmt::Expr( - Expr::Group { - expr: Expr::Let { - pat: Pat::Ident { - ident: "None", - }, - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "None", - }, - ], - }, - }, - }, - }, - None, - ), - ] - "#); -} - -#[test] -fn test_let_dot_dot() { - let tokens = quote! { - let .. = 10; - }; - - snapshot!(tokens as Stmt, @r#" - Stmt::Local { - pat: Pat::Rest, - init: Some(LocalInit { - expr: Expr::Lit { - lit: 10, - }, - }), - } - "#); -} - -#[test] -fn test_let_else() { - let tokens = quote! { - let Some(x) = None else { return 0; }; - }; - - snapshot!(tokens as Stmt, @r#" - Stmt::Local { - pat: Pat::TupleStruct { - path: Path { - segments: [ - PathSegment { - ident: "Some", - }, - ], - }, - elems: [ - Pat::Ident { - ident: "x", - }, - ], - }, - init: Some(LocalInit { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "None", - }, - ], - }, - }, - diverge: Some(Expr::Block { - block: Block { - stmts: [ - Stmt::Expr( - Expr::Return { - expr: Some(Expr::Lit { - lit: 0, - }), - }, - Some, - ), - ], - }, - }), - }), - } - "#); -} - -#[test] -fn test_macros() { - let tokens = quote! { - fn main() { - macro_rules! mac {} - thread_local! { static FOO } - println!(""); - vec![] - } - }; - - snapshot!(tokens as Stmt, @r#" - Stmt::Item(Item::Fn { - vis: Visibility::Inherited, - sig: Signature { - ident: "main", - generics: Generics, - output: ReturnType::Default, - }, - block: Block { - stmts: [ - Stmt::Item(Item::Macro { - ident: Some("mac"), - mac: Macro { - path: Path { - segments: [ - PathSegment { - ident: "macro_rules", - }, - ], - }, - delimiter: MacroDelimiter::Brace, - tokens: TokenStream(``), - }, - }), - Stmt::Macro { - mac: Macro { - path: Path { - segments: [ - PathSegment { - ident: "thread_local", - }, - ], - }, - delimiter: MacroDelimiter::Brace, - tokens: TokenStream(`static FOO`), - }, - }, - Stmt::Macro { - mac: Macro { - path: Path { - segments: [ - PathSegment { - ident: "println", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(`""`), - }, - semi_token: Some, - }, - Stmt::Expr( - Expr::Macro { - mac: Macro { - path: Path { - segments: [ - PathSegment { - ident: "vec", - }, - ], - }, - delimiter: MacroDelimiter::Bracket, - tokens: TokenStream(``), - }, - }, - None, - ), - ], - }, - }) - "#); -} - -#[test] -fn test_early_parse_loop() { - // The following is an Expr::Loop followed by Expr::Tuple. It is not an - // Expr::Call. - let tokens = quote! { - loop {} - () - }; - - let stmts = Block::parse_within.parse2(tokens).unwrap(); - - snapshot!(stmts, @r#" - [ - Stmt::Expr( - Expr::Loop { - body: Block { - stmts: [], - }, - }, - None, - ), - Stmt::Expr( - Expr::Tuple, - None, - ), - ] - "#); - - let tokens = quote! { - 'a: loop {} - () - }; - - let stmts = Block::parse_within.parse2(tokens).unwrap(); - - snapshot!(stmts, @r#" - [ - Stmt::Expr( - Expr::Loop { - label: Some(Label { - name: Lifetime { - ident: "a", - }, - }), - body: Block { - stmts: [], - }, - }, - None, - ), - Stmt::Expr( - Expr::Tuple, - None, - ), - ] - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_token_trees.rs b/deps/crates/vendor/syn-v2/tests/test_token_trees.rs deleted file mode 100644 index 1b473858cd1b..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_token_trees.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::TokenStream; -use quote::quote; -use syn::Lit; - -#[test] -fn test_struct() { - let input = " - #[derive(Debug, Clone)] - pub struct Item { - pub ident: Ident, - pub attrs: Vec<Attribute>, - } - "; - - snapshot!(input as TokenStream, @r##" - TokenStream( - `# [derive (Debug , Clone)] pub struct Item { pub ident : Ident , pub attrs : Vec < Attribute >, }`, - ) - "##); -} - -#[test] -fn test_literal_mangling() { - let code = "0_4"; - let parsed: Lit = syn::parse_str(code).unwrap(); - assert_eq!(code, quote!(#parsed).to_string()); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_ty.rs b/deps/crates/vendor/syn-v2/tests/test_ty.rs deleted file mode 100644 index 5f2922011478..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_ty.rs +++ /dev/null @@ -1,471 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; -use quote::{quote, ToTokens as _}; -use syn::punctuated::Punctuated; -use syn::{parse_quote, token, Token, Type, TypeTuple}; - -#[test] -fn test_mut_self() { - syn::parse_str::<Type>("fn(mut self)").unwrap(); - syn::parse_str::<Type>("fn(mut self,)").unwrap(); - syn::parse_str::<Type>("fn(mut self: ())").unwrap(); - syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err(); - syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err(); - syn::parse_str::<Type>("fn(mut self::T)").unwrap_err(); -} - -#[test] -fn test_macro_variable_type() { - // mimics the token stream corresponding to `$ty<T>` - let tokens = TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, quote! { ty })), - TokenTree::Punct(Punct::new('<', Spacing::Alone)), - TokenTree::Ident(Ident::new("T", Span::call_site())), - TokenTree::Punct(Punct::new('>', Spacing::Alone)), - ]); - - snapshot!(tokens as Type, @r#" - Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "ty", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }), - ], - }, - }, - ], - }, - } - "#); - - // mimics the token stream corresponding to `$ty::<T>` - let tokens = TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, quote! { ty })), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Punct(Punct::new('<', Spacing::Alone)), - TokenTree::Ident(Ident::new("T", Span::call_site())), - TokenTree::Punct(Punct::new('>', Spacing::Alone)), - ]); - - snapshot!(tokens as Type, @r#" - Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "ty", - arguments: PathArguments::AngleBracketed { - colon2_token: Some, - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }), - ], - }, - }, - ], - }, - } - "#); -} - -#[test] -fn test_group_angle_brackets() { - // mimics the token stream corresponding to `Option<$ty>` - let tokens = TokenStream::from_iter([ - TokenTree::Ident(Ident::new("Option", Span::call_site())), - TokenTree::Punct(Punct::new('<', Spacing::Alone)), - TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })), - TokenTree::Punct(Punct::new('>', Spacing::Alone)), - ]); - - snapshot!(tokens as Type, @r#" - Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Option", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Group { - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Vec", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "u8", - }, - ], - }, - }), - ], - }, - }, - ], - }, - }, - }), - ], - }, - }, - ], - }, - } - "#); -} - -#[test] -fn test_group_colons() { - // mimics the token stream corresponding to `$ty::Item` - let tokens = TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("Item", Span::call_site())), - ]); - - snapshot!(tokens as Type, @r#" - Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Vec", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "u8", - }, - ], - }, - }), - ], - }, - }, - Token![::], - PathSegment { - ident: "Item", - }, - ], - }, - } - "#); - - let tokens = TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, quote! { [T] })), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("Element", Span::call_site())), - ]); - - snapshot!(tokens as Type, @r#" - Type::Path { - qself: Some(QSelf { - ty: Type::Slice { - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "T", - }, - ], - }, - }, - }, - position: 0, - }), - path: Path { - leading_colon: Some, - segments: [ - PathSegment { - ident: "Element", - }, - ], - }, - } - "#); -} - -#[test] -fn test_trait_object() { - let tokens = quote!(dyn for<'a> Trait<'a> + 'static); - snapshot!(tokens as Type, @r#" - Type::TraitObject { - dyn_token: Some, - bounds: [ - TypeParamBound::Trait(TraitBound { - lifetimes: Some(BoundLifetimes { - lifetimes: [ - GenericParam::Lifetime(LifetimeParam { - lifetime: Lifetime { - ident: "a", - }, - }), - ], - }), - path: Path { - segments: [ - PathSegment { - ident: "Trait", - arguments: PathArguments::AngleBracketed { - args: [ - GenericArgument::Lifetime(Lifetime { - ident: "a", - }), - ], - }, - }, - ], - }, - }), - Token![+], - TypeParamBound::Lifetime { - ident: "static", - }, - ], - } - "#); - - let tokens = quote!(dyn 'a + Trait); - snapshot!(tokens as Type, @r#" - Type::TraitObject { - dyn_token: Some, - bounds: [ - TypeParamBound::Lifetime { - ident: "a", - }, - Token![+], - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - }), - ], - } - "#); - - // None of the following are valid Rust types. - syn::parse_str::<Type>("for<'a> dyn Trait<'a>").unwrap_err(); - syn::parse_str::<Type>("dyn for<'a> 'a + Trait").unwrap_err(); -} - -#[test] -fn test_trailing_plus() { - #[rustfmt::skip] - let tokens = quote!(impl Trait +); - snapshot!(tokens as Type, @r#" - Type::ImplTrait { - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - }), - Token![+], - ], - } - "#); - - #[rustfmt::skip] - let tokens = quote!(dyn Trait +); - snapshot!(tokens as Type, @r#" - Type::TraitObject { - dyn_token: Some, - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - }), - Token![+], - ], - } - "#); - - #[rustfmt::skip] - let tokens = quote!(Trait +); - snapshot!(tokens as Type, @r#" - Type::TraitObject { - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Trait", - }, - ], - }, - }), - Token![+], - ], - } - "#); -} - -#[test] -fn test_tuple_comma() { - let mut expr = TypeTuple { - paren_token: token::Paren::default(), - elems: Punctuated::new(), - }; - snapshot!(expr.to_token_stream() as Type, @"Type::Tuple"); - - expr.elems.push_value(parse_quote!(_)); - // Must not parse to Type::Paren - snapshot!(expr.to_token_stream() as Type, @r#" - Type::Tuple { - elems: [ - Type::Infer, - Token![,], - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Type, @r#" - Type::Tuple { - elems: [ - Type::Infer, - Token![,], - ], - } - "#); - - expr.elems.push_value(parse_quote!(_)); - snapshot!(expr.to_token_stream() as Type, @r#" - Type::Tuple { - elems: [ - Type::Infer, - Token![,], - Type::Infer, - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Type, @r#" - Type::Tuple { - elems: [ - Type::Infer, - Token![,], - Type::Infer, - Token![,], - ], - } - "#); -} - -#[test] -fn test_impl_trait_use() { - let tokens = quote! { - impl Sized + use<'_, 'a, A, Test> - }; - - snapshot!(tokens as Type, @r#" - Type::ImplTrait { - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Sized", - }, - ], - }, - }), - Token![+], - TypeParamBound::PreciseCapture(PreciseCapture { - params: [ - CapturedParam::Lifetime(Lifetime { - ident: "_", - }), - Token![,], - CapturedParam::Lifetime(Lifetime { - ident: "a", - }), - Token![,], - CapturedParam::Ident("A"), - Token![,], - CapturedParam::Ident("Test"), - ], - }), - ], - } - "#); - - let trailing = quote! { - impl Sized + use<'_,> - }; - - snapshot!(trailing as Type, @r#" - Type::ImplTrait { - bounds: [ - TypeParamBound::Trait(TraitBound { - path: Path { - segments: [ - PathSegment { - ident: "Sized", - }, - ], - }, - }), - Token![+], - TypeParamBound::PreciseCapture(PreciseCapture { - params: [ - CapturedParam::Lifetime(Lifetime { - ident: "_", - }), - Token![,], - ], - }), - ], - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/test_unparenthesize.rs b/deps/crates/vendor/syn-v2/tests/test_unparenthesize.rs deleted file mode 100644 index 5fa2e59e14be..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_unparenthesize.rs +++ /dev/null @@ -1,70 +0,0 @@ -#![cfg(not(miri))] -#![recursion_limit = "1024"] -#![feature(rustc_private)] -#![allow( - clippy::elidable_lifetime_names, - clippy::manual_assert, - clippy::match_like_matches_macro, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -use crate::common::visit::{AsIfPrinted, FlattenParens}; -use quote::ToTokens as _; -use std::fs; -use std::panic; -use std::path::Path; -use std::sync::atomic::{AtomicUsize, Ordering}; -use syn::visit_mut::VisitMut as _; - -#[macro_use] -mod macros; - -mod common; -mod repo; - -#[test] -fn test_unparenthesize() { - repo::rayon_init(); - repo::clone_rust(); - - let failed = AtomicUsize::new(0); - - repo::for_each_rust_file(|path| test(path, &failed)); - - let failed = failed.into_inner(); - if failed > 0 { - panic!("{} failures", failed); - } -} - -fn test(path: &Path, failed: &AtomicUsize) { - let content = fs::read_to_string(path).unwrap(); - - match panic::catch_unwind(|| -> syn::Result<()> { - let mut before = syn::parse_file(&content)?; - FlattenParens::discard_attrs().visit_file_mut(&mut before); - let printed = before.to_token_stream(); - let mut after = syn::parse2::<syn::File>(printed.clone())?; - FlattenParens::discard_attrs().visit_file_mut(&mut after); - // Normalize features that we expect Syn not to print. - AsIfPrinted.visit_file_mut(&mut before); - if before != after { - errorf!("=== {}\n", path.display()); - if failed.fetch_add(1, Ordering::Relaxed) == 0 { - errorf!("BEFORE:\n{:#?}\nAFTER:\n{:#?}\n", before, after); - } - } - Ok(()) - }) { - Err(_) => { - errorf!("=== {}: syn panic\n", path.display()); - failed.fetch_add(1, Ordering::Relaxed); - } - Ok(Err(msg)) => { - errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg); - failed.fetch_add(1, Ordering::Relaxed); - } - Ok(Ok(())) => {} - } -} diff --git a/deps/crates/vendor/syn-v2/tests/test_visibility.rs b/deps/crates/vendor/syn-v2/tests/test_visibility.rs deleted file mode 100644 index cf15574b5102..000000000000 --- a/deps/crates/vendor/syn-v2/tests/test_visibility.rs +++ /dev/null @@ -1,191 +0,0 @@ -#![allow( - clippy::elidable_lifetime_names, - clippy::needless_lifetimes, - clippy::uninlined_format_args -)] - -#[macro_use] -mod snapshot; - -mod debug; - -use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; -use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::{DeriveInput, Result, Visibility}; - -#[derive(Debug)] -struct VisRest { - vis: Visibility, - rest: TokenStream, -} - -impl Parse for VisRest { - fn parse(input: ParseStream) -> Result<Self> { - Ok(VisRest { - vis: input.parse()?, - rest: input.parse()?, - }) - } -} - -macro_rules! assert_vis_parse { - ($input:expr, Ok($p:pat)) => { - assert_vis_parse!($input, Ok($p) + ""); - }; - - ($input:expr, Ok($p:pat) + $rest:expr) => { - let expected = $rest.parse::<TokenStream>().unwrap(); - let parse: VisRest = syn::parse_str($input).unwrap(); - - match parse.vis { - $p => {} - _ => panic!("expected {}, got {:?}", stringify!($p), parse.vis), - } - - // NOTE: Round-trips through `to_string` to avoid potential whitespace - // diffs. - assert_eq!(parse.rest.to_string(), expected.to_string()); - }; - - ($input:expr, Err) => { - syn::parse2::<VisRest>($input.parse().unwrap()).unwrap_err(); - }; -} - -#[test] -fn test_pub() { - assert_vis_parse!("pub", Ok(Visibility::Public(_))); -} - -#[test] -fn test_inherited() { - assert_vis_parse!("", Ok(Visibility::Inherited)); -} - -#[test] -fn test_in() { - assert_vis_parse!("pub(in foo::bar)", Ok(Visibility::Restricted(_))); -} - -#[test] -fn test_pub_crate() { - assert_vis_parse!("pub(crate)", Ok(Visibility::Restricted(_))); -} - -#[test] -fn test_pub_self() { - assert_vis_parse!("pub(self)", Ok(Visibility::Restricted(_))); -} - -#[test] -fn test_pub_super() { - assert_vis_parse!("pub(super)", Ok(Visibility::Restricted(_))); -} - -#[test] -fn test_missing_in() { - assert_vis_parse!("pub(foo::bar)", Ok(Visibility::Public(_)) + "(foo::bar)"); -} - -#[test] -fn test_missing_in_path() { - assert_vis_parse!("pub(in)", Err); -} - -#[test] -fn test_crate_path() { - assert_vis_parse!( - "pub(crate::A, crate::B)", - Ok(Visibility::Public(_)) + "(crate::A, crate::B)" - ); -} - -#[test] -fn test_junk_after_in() { - assert_vis_parse!("pub(in some::path @@garbage)", Err); -} - -#[test] -fn test_inherited_vis_named_field() { - // mimics `struct S { $vis $field: () }` where $vis is empty - let tokens = TokenStream::from_iter([ - TokenTree::Ident(Ident::new("struct", Span::call_site())), - TokenTree::Ident(Ident::new("S", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Brace, - TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())), - TokenTree::Group(Group::new(Delimiter::None, quote!(f))), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())), - ]), - )), - ]); - - snapshot!(tokens as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Named { - named: [ - Field { - vis: Visibility::Inherited, - ident: Some("f"), - colon_token: Some, - ty: Type::Tuple, - }, - ], - }, - }, - } - "#); -} - -#[test] -fn test_inherited_vis_unnamed_field() { - // mimics `struct S($vis $ty);` where $vis is empty - let tokens = TokenStream::from_iter([ - TokenTree::Ident(Ident::new("struct", Span::call_site())), - TokenTree::Ident(Ident::new("S", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter([ - TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())), - TokenTree::Group(Group::new(Delimiter::None, quote!(str))), - ]), - )), - TokenTree::Punct(Punct::new(';', Spacing::Alone)), - ]); - - snapshot!(tokens as DeriveInput, @r#" - DeriveInput { - vis: Visibility::Inherited, - ident: "S", - generics: Generics, - data: Data::Struct { - fields: Fields::Unnamed { - unnamed: [ - Field { - vis: Visibility::Inherited, - ty: Type::Group { - elem: Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "str", - }, - ], - }, - }, - }, - }, - ], - }, - semi_token: Some, - }, - } - "#); -} diff --git a/deps/crates/vendor/syn-v2/tests/zzz_stable.rs b/deps/crates/vendor/syn-v2/tests/zzz_stable.rs deleted file mode 100644 index a1a670d9edee..000000000000 --- a/deps/crates/vendor/syn-v2/tests/zzz_stable.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![cfg(syn_disable_nightly_tests)] - -use std::io::{self, Write}; -use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; - -const MSG: &str = "\ -‖ -‖ WARNING: -‖ This is not a nightly compiler so not all tests were able to -‖ run. Syn includes tests that compare Syn's parser against the -‖ compiler's parser, which requires access to unstable librustc -‖ data structures and a nightly compiler. -‖ -"; - -#[test] -fn notice() -> io::Result<()> { - let header = "WARNING"; - let index_of_header = MSG.find(header).unwrap(); - let before = &MSG[..index_of_header]; - let after = &MSG[index_of_header + header.len()..]; - - let mut stderr = StandardStream::stderr(ColorChoice::Auto); - stderr.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; - write!(&mut stderr, "{}", before)?; - stderr.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?; - write!(&mut stderr, "{}", header)?; - stderr.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; - write!(&mut stderr, "{}", after)?; - stderr.reset()?; - - Ok(()) -} diff --git a/deps/crates/vendor/syn-v3/.cargo_vcs_info.json b/deps/crates/vendor/syn-v3/.cargo_vcs_info.json index f8dfb219e1e6..305c7a37416e 100644 --- a/deps/crates/vendor/syn-v3/.cargo_vcs_info.json +++ b/deps/crates/vendor/syn-v3/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "e0ad92d68b588c964e82bb74c3bd3e1e99f97ceb" + "sha1": "559cab55ef0c644f77660840edc3620d0d99d3d7" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/deps/crates/vendor/syn-v3/Cargo.lock b/deps/crates/vendor/syn-v3/Cargo.lock index f15946967cf0..d80901b46f07 100644 --- a/deps/crates/vendor/syn-v3/Cargo.lock +++ b/deps/crates/vendor/syn-v3/Cargo.lock @@ -60,11 +60,17 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "bitflags" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bumpalo" @@ -80,9 +86,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005ec2760ca554fae18df7a11195552ec576cd665632a881bc011d5bb2fd4d80" +checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4" dependencies = [ "find-msvc-tools", "jobserver", @@ -92,9 +98,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "cfg_aliases" @@ -134,9 +140,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.4" +version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" dependencies = [ "encode_unicode", "libc", @@ -169,6 +175,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + [[package]] name = "cpufeatures" version = "0.3.1" @@ -180,18 +192,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -199,18 +211,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "displaydoc" @@ -220,7 +232,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.4", + "syn 3.0.5", ] [[package]] @@ -243,11 +255,17 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "7b5ef0006ac9ab233c38522f5ae99cae3625151de8f706cacee1cba4b8e2832a" dependencies = [ "cfg-if", + "core_detect", + "multiversion", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", ] [[package]] @@ -502,7 +520,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", @@ -627,9 +645,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.1" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", "hashbrown", @@ -649,9 +667,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.1" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" [[package]] name = "itoa" @@ -720,9 +738,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.104" +version = "0.3.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" dependencies = [ "cfg-if", "futures-util", @@ -755,9 +773,9 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "lru-slab" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" [[package]] name = "memchr" @@ -792,6 +810,33 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "multiversion" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ca4bea16ffc3f443cf7d866912118196bfef4c6a1556ca00f9f9b00bb43f7c" +dependencies = [ + "multiversion-macros", +] + +[[package]] +name = "multiversion-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d416831a7317ef4b08bee00b69cbbb9c8763da7959a7026244d6266869f9c83" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn 3.0.5", +] + +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + [[package]] name = "once_cell" version = "1.21.4" @@ -842,9 +887,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" dependencies = [ "bytes", "cfg_aliases", @@ -862,9 +907,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.17" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04759210543be93709136e28212294a659ef5001836ff4eab4d663e4529bba83" +checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" dependencies = [ "aws-lc-rs", "bytes", @@ -975,16 +1020,16 @@ checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.4", + "syn 3.0.5", ] [[package]] name = "reqwest" -version = "0.13.4" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" dependencies = [ - "base64", + "base64 0.23.1", "bytes", "encoding_rs", "futures-channel", @@ -1062,9 +1107,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.43" +version = "0.23.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" dependencies = [ "aws-lc-rs", "once_cell", @@ -1159,6 +1204,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "security-framework" version = "3.7.0" @@ -1214,7 +1265,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.4", + "syn 3.0.5", ] [[package]] @@ -1259,9 +1310,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.16.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" [[package]] name = "socket2" @@ -1298,9 +1349,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" dependencies = [ "proc-macro2", "quote", @@ -1309,7 +1360,7 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.5" +version = "3.0.6" dependencies = [ "anyhow", "automod", @@ -1345,13 +1396,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.5", ] [[package]] @@ -1425,7 +1476,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.4", + "syn 3.0.5", ] [[package]] @@ -1440,18 +1491,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf0ded5c4e56918d8f8a339e1bb67d038d3bc6d144ac407904015ba2e4cde9b" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "tokio" @@ -1563,9 +1605,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "ab72a15cf68d77cb0987d3684aa8a45c5ef827e8cb49ee2f30bfd7ba2feb519f" [[package]] name = "untrusted" @@ -1618,9 +1660,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.127" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" dependencies = [ "cfg-if", "once_cell", @@ -1631,9 +1673,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.77" +version = "0.4.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" dependencies = [ "js-sys", "wasm-bindgen", @@ -1641,9 +1683,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.127" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1651,31 +1693,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.127" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.5", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.127" +version = "0.2.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.104" +version = "0.3.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" dependencies = [ "js-sys", "wasm-bindgen", @@ -1855,13 +1897,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.5", "synstructure", ] @@ -1876,13 +1918,13 @@ dependencies = [ [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.5", "synstructure", ] @@ -1922,11 +1964,11 @@ checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 3.0.4", + "syn 3.0.5", ] [[package]] name = "zlib-rs" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" diff --git a/deps/crates/vendor/syn-v3/Cargo.toml b/deps/crates/vendor/syn-v3/Cargo.toml index a18bffecfd39..7a29350790ca 100644 --- a/deps/crates/vendor/syn-v3/Cargo.toml +++ b/deps/crates/vendor/syn-v3/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.71" name = "syn" -version = "3.0.5" +version = "3.0.6" authors = ["David Tolnay <dtolnay@gmail.com>"] build = false include = [ diff --git a/deps/crates/vendor/syn-v3/Cargo.toml.orig b/deps/crates/vendor/syn-v3/Cargo.toml.orig index 7e6765a0f1a2..0e4139a18fd9 100644 --- a/deps/crates/vendor/syn-v3/Cargo.toml.orig +++ b/deps/crates/vendor/syn-v3/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "syn" -version = "3.0.5" +version = "3.0.6" authors = ["David Tolnay <dtolnay@gmail.com>"] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/deps/crates/vendor/syn-v3/src/expr.rs b/deps/crates/vendor/syn-v3/src/expr.rs index c9437d50cf32..5e4288344191 100644 --- a/deps/crates/vendor/syn-v3/src/expr.rs +++ b/deps/crates/vendor/syn-v3/src/expr.rs @@ -1293,13 +1293,12 @@ pub(crate) mod parsing { #[cfg(feature = "full")] use crate::generics::{self, BoundLifetimes}; use crate::ident::Ident; - #[cfg(feature = "full")] use crate::lifetime::Lifetime; use crate::lit::{Lit, LitFloat, LitInt}; use crate::mac::{self, Macro}; use crate::op::BinOp; use crate::parse::discouraged::Speculative as _; - use crate::parse::{Parse, ParseStream}; + use crate::parse::{End, Parse, ParseStream}; #[cfg(feature = "full")] use crate::pat::{Pat, PatType}; use crate::path::{self, AngleBracketedGenericArguments, Path, QSelf}; @@ -1342,7 +1341,10 @@ pub(crate) mod parsing { #[cfg(feature = "full")] pub(super) fn parse_with_earlier_boundary_rule(input: ParseStream) -> Result<Expr> { let mut attrs = input.call(expr_attrs)?; - let mut expr = if input.peek(token::Group) { + let mut expr = if input.peek(token::Group) && { + let group = crate::group::parse_group(&input.fork())?; + !(group.content.peek(Lifetime) && group.content.peek2(End)) + } { let allow_struct = AllowStruct(true); let atom = expr_group(input, allow_struct)?; if continue_parsing_early(&atom) { @@ -1894,7 +1896,10 @@ pub(crate) mod parsing { // interactions, as they are fully contained. #[cfg(feature = "full")] fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { - if input.peek(token::Group) { + if input.peek(token::Group) && { + let group = crate::group::parse_group(&input.fork())?; + !(group.content.peek(Lifetime) && group.content.peek2(End)) + } { expr_group(input, allow_struct) } else if input.peek(Lit) { input.parse().map(Expr::Lit) @@ -1994,7 +1999,10 @@ pub(crate) mod parsing { #[cfg(not(feature = "full"))] fn atom_expr(input: ParseStream) -> Result<Expr> { - if input.peek(token::Group) { + if input.peek(token::Group) && { + let group = crate::group::parse_group(&input.fork())?; + !(group.content.peek(Lifetime) && group.content.peek2(End)) + } { expr_group(input) } else if input.peek(Lit) { input.parse().map(Expr::Lit) diff --git a/deps/crates/vendor/syn-v3/src/lib.rs b/deps/crates/vendor/syn-v3/src/lib.rs index e09d386796c5..ffe527aad41d 100644 --- a/deps/crates/vendor/syn-v3/src/lib.rs +++ b/deps/crates/vendor/syn-v3/src/lib.rs @@ -364,7 +364,7 @@ //! compile and work for downstream users in the interim. #![no_std] -#![doc(html_root_url = "https://docs.rs/syn/3.0.5")] +#![doc(html_root_url = "https://docs.rs/syn/3.0.6")] #![cfg_attr(docsrs, feature(doc_cfg), doc(auto_cfg = false))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/deps/crates/vendor/syn-v3/tests/common/eq.rs b/deps/crates/vendor/syn-v3/tests/common/eq.rs index a55708e54f69..746b29e0c578 100644 --- a/deps/crates/vendor/syn-v3/tests/common/eq.rs +++ b/deps/crates/vendor/syn-v3/tests/common/eq.rs @@ -36,7 +36,6 @@ use rustc_ast::ast::ClosureBinder; use rustc_ast::ast::Const; use rustc_ast::ast::ConstBlockItem; use rustc_ast::ast::ConstItem; -use rustc_ast::ast::ConstItemKind; use rustc_ast::ast::CoroutineKind; use rustc_ast::ast::CoroutineMarker; use rustc_ast::ast::Crate; @@ -156,6 +155,7 @@ use rustc_ast::ast::StructRest; use rustc_ast::ast::SyntheticAttr; use rustc_ast::ast::Term; use rustc_ast::ast::TestBinderBody; +use rustc_ast::ast::TestBinderBoundTypeConstraint; use rustc_ast::ast::TestBinderConstraint; use rustc_ast::ast::TestBinderConstraints; use rustc_ast::ast::TestBinderExists; @@ -506,7 +506,7 @@ spanless_eq_struct!(BindingMode; 0 1); spanless_eq_struct!(Block; stmts id rules span); spanless_eq_struct!(Closure; binder capture_clause constness coroutine_marker movability fn_decl body !fn_decl_span !fn_arg_span); spanless_eq_struct!(ConstBlockItem; id span block); -spanless_eq_struct!(ConstItem; defaultness ident generics ty body kind define_opaque); +spanless_eq_struct!(ConstItem; defaultness ident generics ty body define_opaque); spanless_eq_struct!(CoroutineMarker; kind span closure_id return_impl_trait_id); spanless_eq_struct!(Crate; attrs items spans id is_placeholder); spanless_eq_struct!(Delegation; id qself path ident rename body source); @@ -566,7 +566,8 @@ spanless_eq_struct!(StaticItem; ident ty safety mutability expr define_opaque ei spanless_eq_struct!(Stmt; id kind span); spanless_eq_struct!(StrLit; symbol suffix symbol_unescaped style span); spanless_eq_struct!(StructExpr; qself path fields rest); -spanless_eq_struct!(TestBinderBody; foralls exists constraints); +spanless_eq_struct!(TestBinderBody; foralls exists constraints predicates); +spanless_eq_struct!(TestBinderBoundTypeConstraint; span node_id params lhs rhs); spanless_eq_struct!(TestBinderConstraints; generics body); spanless_eq_struct!(TestBinderExists; span node_id params body); spanless_eq_struct!(TestBinderForall; span node_id generics body assert_on_exit); @@ -605,7 +606,6 @@ spanless_eq_enum!(ByRef; Yes(0 1) No); spanless_eq_enum!(CaptureBy; Value(move_kw) Ref Use(use_kw)); spanless_eq_enum!(ClosureBinder; NotPresent For(span generic_params)); spanless_eq_enum!(Const; Yes(0) No); -spanless_eq_enum!(ConstItemKind; Body TypeConst); spanless_eq_enum!(CoroutineKind; Async Gen AsyncGen); spanless_eq_enum!(Defaultness; Implicit Default(0) Final(0)); spanless_eq_enum!(DelegationSource; Single List(0) Glob); @@ -657,7 +657,7 @@ spanless_eq_enum!(StrStyle; Cooked Raw(0)); spanless_eq_enum!(StructRest; Base(0) Rest(0) None NoneWithError(0)); spanless_eq_enum!(SyntheticAttr; CfgTrace(0) CfgAttrTrace(0)); spanless_eq_enum!(Term; Ty(0) Const(0)); -spanless_eq_enum!(TestBinderConstraint; And(items) Or(items) Lifetime(lhs rhs) Type(lhs rhs)); +spanless_eq_enum!(TestBinderConstraint; And(items) Or(items) Lifetime(lhs rhs) PlaceholderOutlives(lhs rhs) AliasOutlives(bound_type_constraint)); spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1 2 3)); spanless_eq_enum!(TraitObjectSyntax; Dyn None); spanless_eq_enum!(TyPatKind; Range(0 1 2) NotNull Or(0) Err(0)); diff --git a/deps/crates/vendor/syn-v3/tests/test_stmt.rs b/deps/crates/vendor/syn-v3/tests/test_stmt.rs index 9c2aa2a558b9..c66ff43ee937 100644 --- a/deps/crates/vendor/syn-v3/tests/test_stmt.rs +++ b/deps/crates/vendor/syn-v3/tests/test_stmt.rs @@ -11,7 +11,7 @@ mod snapshot; mod debug; -use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; use quote::{quote, ToTokens as _}; use syn::parse::Parser as _; use syn::{Block, Stmt}; @@ -343,3 +343,36 @@ fn test_early_parse_loop() { ] "#); } + +// Regression test for https://github.com/dtolnay/syn/issues/2081 +#[test] +fn test_interpolated_lifetime_at_statement_start() { + // «∅ 'a ∅» : loop {} + let tokens = TokenStream::from_iter([ + TokenTree::Group(Group::new( + Delimiter::None, + TokenStream::from_iter([ + TokenTree::Punct(Punct::new('\'', Spacing::Joint)), + TokenTree::Ident(Ident::new("a", Span::call_site())), + ]), + )), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Ident(Ident::new("loop", Span::call_site())), + TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), + ]); + snapshot!(tokens as Stmt, @r#" + Stmt::Expr( + Expr::Loop { + label: Some(Label { + name: Lifetime { + ident: "a", + }, + }), + body: Block { + stmts: [], + }, + }, + None, + ) + "#); +} diff --git a/deps/crates/vendor/synstructure-v0_13/.cargo-checksum.json b/deps/crates/vendor/synstructure-v0_13/.cargo-checksum.json deleted file mode 100644 index 697c9ce2fbb4..000000000000 --- a/deps/crates/vendor/synstructure-v0_13/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{}} diff --git a/deps/crates/vendor/synstructure-v0_13/.cargo_vcs_info.json b/deps/crates/vendor/synstructure-v0_13/.cargo_vcs_info.json deleted file mode 100644 index 54efc864c549..000000000000 --- a/deps/crates/vendor/synstructure-v0_13/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "91ead072fa43c55f35880bd7f75a2b0eab72a04e" - }, - "path_in_vcs": "" -} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale_data-v2/.cargo-checksum.json b/deps/crates/vendor/synstructure-v0_14/.cargo-checksum.json similarity index 100% rename from deps/crates/vendor/icu_locale_data-v2/.cargo-checksum.json rename to deps/crates/vendor/synstructure-v0_14/.cargo-checksum.json diff --git a/deps/crates/vendor/synstructure-v0_14/.cargo_vcs_info.json b/deps/crates/vendor/synstructure-v0_14/.cargo_vcs_info.json new file mode 100644 index 000000000000..ebbb9bb6587a --- /dev/null +++ b/deps/crates/vendor/synstructure-v0_14/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "30cfafe36e42405e717a8e55da042a2835a698d7" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/deps/crates/vendor/synstructure-v0_13/Cargo.lock b/deps/crates/vendor/synstructure-v0_14/Cargo.lock similarity index 69% rename from deps/crates/vendor/synstructure-v0_13/Cargo.lock rename to deps/crates/vendor/synstructure-v0_14/Cargo.lock index 5178efe403ed..adf7a9671e1f 100644 --- a/deps/crates/vendor/synstructure-v0_13/Cargo.lock +++ b/deps/crates/vendor/synstructure-v0_14/Cargo.lock @@ -1,30 +1,30 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "2.0.0" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cff13bb1732bccfe3b246f3fdb09edfd51c01d6f5299b7ccd9457c2e4e37774" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -33,7 +33,7 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" dependencies = [ "proc-macro2", "quote", @@ -49,6 +49,6 @@ checksum = "c6e0c1828b7994d45bbef3cbbe56a6157c42db92b82b1a5bf22fb09996d06eac" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/deps/crates/vendor/synstructure-v0_13/Cargo.toml b/deps/crates/vendor/synstructure-v0_14/Cargo.toml similarity index 96% rename from deps/crates/vendor/synstructure-v0_13/Cargo.toml rename to deps/crates/vendor/synstructure-v0_14/Cargo.toml index 095a18e0e750..4c3f07c7e021 100644 --- a/deps/crates/vendor/synstructure-v0_13/Cargo.toml +++ b/deps/crates/vendor/synstructure-v0_14/Cargo.toml @@ -11,8 +11,9 @@ [package] edition = "2018" +rust-version = "1.71" name = "synstructure" -version = "0.13.2" +version = "0.14.0" authors = ["Nika Layzell <nika@thelayzells.com>"] build = false include = [ @@ -39,6 +40,14 @@ keywords = [ license = "MIT" repository = "https://github.com/mystor/synstructure" +[features] +default = ["proc-macro"] +proc-macro = [ + "proc-macro2/proc-macro", + "syn/proc-macro", + "quote/proc-macro", +] + [lib] name = "synstructure" path = "src/lib.rs" @@ -52,7 +61,7 @@ version = "1" default-features = false [dependencies.syn] -version = "2" +version = "3" features = [ "derive", "parsing", @@ -65,11 +74,3 @@ default-features = false [dev-dependencies.synstructure_test_traits] version = "0.1" - -[features] -default = ["proc-macro"] -proc-macro = [ - "proc-macro2/proc-macro", - "syn/proc-macro", - "quote/proc-macro", -] diff --git a/deps/crates/vendor/synstructure-v0_13/Cargo.toml.orig b/deps/crates/vendor/synstructure-v0_14/Cargo.toml.orig similarity index 95% rename from deps/crates/vendor/synstructure-v0_13/Cargo.toml.orig rename to deps/crates/vendor/synstructure-v0_14/Cargo.toml.orig index 2edfa63d28e7..105fd2a4c229 100644 --- a/deps/crates/vendor/synstructure-v0_13/Cargo.toml.orig +++ b/deps/crates/vendor/synstructure-v0_14/Cargo.toml.orig @@ -1,9 +1,9 @@ [package] name = "synstructure" -version = "0.13.2" +version = "0.14.0" authors = ["Nika Layzell <nika@thelayzells.com>"] edition = "2018" - +rust-version = "1.71" description = "Helper methods and macros for custom derives" documentation = "https://docs.rs/synstructure" repository = "https://github.com/mystor/synstructure" @@ -22,7 +22,7 @@ proc-macro2 = { version = "1.0.60", default-features = false } quote = { version = "1", default-features = false } [dependencies.syn] -version = "2" +version = "3" default-features = false features = ["derive", "parsing", "printing", "clone-impls", "visit", "extra-traits"] diff --git a/deps/crates/vendor/synstructure-v0_13/LICENSE b/deps/crates/vendor/synstructure-v0_14/LICENSE similarity index 100% rename from deps/crates/vendor/synstructure-v0_13/LICENSE rename to deps/crates/vendor/synstructure-v0_14/LICENSE diff --git a/deps/crates/vendor/synstructure-v0_13/README.md b/deps/crates/vendor/synstructure-v0_14/README.md similarity index 96% rename from deps/crates/vendor/synstructure-v0_13/README.md rename to deps/crates/vendor/synstructure-v0_14/README.md index c7a6c5fd70ad..ba62fe9ae06f 100644 --- a/deps/crates/vendor/synstructure-v0_13/README.md +++ b/deps/crates/vendor/synstructure-v0_14/README.md @@ -3,7 +3,7 @@ [![Latest Version](https://img.shields.io/crates/v/synstructure.svg)](https://crates.io/crates/synstructure) [![Documentation](https://docs.rs/synstructure/badge.svg)](https://docs.rs/synstructure) [![Build Status](https://github.com/mystor/synstructure/actions/workflows/ci.yml/badge.svg)](https://github.com/mystor/synstructure/actions) -[![Rustc Version 1.31+](https://img.shields.io/badge/rustc-1.31+-lightgray.svg)](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html) +[![Rustc Version 1.71+](https://img.shields.io/badge/rustc-1.71+-lightgray.svg)](https://blog.rust-lang.org/2023/07/13/Rust-1.71.0/) > NOTE: What follows is an exerpt from the module level documentation. For full > details read the docs on [docs.rs](https://docs.rs/synstructure/) diff --git a/deps/crates/vendor/synstructure-v0_13/src/lib.rs b/deps/crates/vendor/synstructure-v0_14/src/lib.rs similarity index 98% rename from deps/crates/vendor/synstructure-v0_13/src/lib.rs rename to deps/crates/vendor/synstructure-v0_14/src/lib.rs index a1f1c2d3c9d2..f5e7ac4de1e9 100644 --- a/deps/crates/vendor/synstructure-v0_13/src/lib.rs +++ b/deps/crates/vendor/synstructure-v0_14/src/lib.rs @@ -257,31 +257,29 @@ fn merge_generics(into: &mut Generics, from: &Generics) -> Result<()> { for p in &from.params { for op in &into.params { match (op, p) { - (GenericParam::Type(otp), GenericParam::Type(tp)) => { - // NOTE: This is only OK because syn ignores the span for equality purposes. - if otp.ident == tp.ident { - return Err(Error::new_spanned( - p, - format!( - "Attempted to merge conflicting generic parameters: {} and {}", - quote!(#op), - quote!(#p) - ), - )); - } + // NOTE: This is only OK because syn ignores the span for equality purposes. + (GenericParam::Type(otp), GenericParam::Type(tp)) if otp.ident == tp.ident => { + return Err(Error::new_spanned( + p, + format!( + "Attempted to merge conflicting generic parameters: {} and {}", + quote!(#op), + quote!(#p) + ), + )); } - (GenericParam::Lifetime(olp), GenericParam::Lifetime(lp)) => { - // NOTE: This is only OK because syn ignores the span for equality purposes. - if olp.lifetime == lp.lifetime { - return Err(Error::new_spanned( - p, - format!( - "Attempted to merge conflicting generic parameters: {} and {}", - quote!(#op), - quote!(#p) - ), - )); - } + // NOTE: This is only OK because syn ignores the span for equality purposes. + (GenericParam::Lifetime(olp), GenericParam::Lifetime(lp)) + if olp.lifetime == lp.lifetime => + { + return Err(Error::new_spanned( + p, + format!( + "Attempted to merge conflicting generic parameters: {} and {}", + quote!(#op), + quote!(#p) + ), + )); } // We don't support merging Const parameters, because that wouldn't make much sense. _ => (), @@ -460,9 +458,7 @@ fn get_ty_params(field: &Field, generics: &Generics) -> Vec<bool> { fn visit_type_macro(&mut self, x: &'a TypeMacro) { // If we see a type_mac declaration, then we can't know what type parameters // it might be binding, so we presume it binds all of them. - for r in &mut self.result { - *r = true; - } + self.result.fill(true); visit::visit_type_macro(self, x); } } @@ -1751,6 +1747,7 @@ impl<'a> Structure<'a> { predicates: punctuated::Punctuated::new(), }); clause.predicates.push(WherePredicate::Type(PredicateType { + attrs: Vec::new(), lifetimes: None, bounded_ty: ty, colon_token: Default::default(), @@ -1779,6 +1776,7 @@ impl<'a> Structure<'a> { AddBounds::Both | AddBounds::Generics => { for param in binding.referenced_ty_params() { pred(Type::Path(TypePath { + attrs: Vec::new(), qself: None, path: (*param).clone().into(), })); diff --git a/deps/crates/vendor/synstructure-v0_13/src/macros.rs b/deps/crates/vendor/synstructure-v0_14/src/macros.rs similarity index 100% rename from deps/crates/vendor/synstructure-v0_13/src/macros.rs rename to deps/crates/vendor/synstructure-v0_14/src/macros.rs diff --git a/deps/crates/vendor/tinystr-v0_8/.cargo_vcs_info.json b/deps/crates/vendor/tinystr-v0_8/.cargo_vcs_info.json index b3092ebbf1c6..da90cd9baeb6 100644 --- a/deps/crates/vendor/tinystr-v0_8/.cargo_vcs_info.json +++ b/deps/crates/vendor/tinystr-v0_8/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "a14f2dad852be26bad277ae704abf27a15cbfed1" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "utils/tinystr" } \ No newline at end of file diff --git a/deps/crates/vendor/tinystr-v0_8/Cargo.lock b/deps/crates/vendor/tinystr-v0_8/Cargo.lock index f99cbcfc8819..23b87b71c4e0 100644 --- a/deps/crates/vendor/tinystr-v0_8/Cargo.lock +++ b/deps/crates/vendor/tinystr-v0_8/Cargo.lock @@ -52,9 +52,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "ciborium" @@ -85,18 +85,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cobs" @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -165,18 +165,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -202,14 +202,14 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "either" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "embedded-io" @@ -247,9 +247,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "is-terminal" @@ -289,9 +289,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "memchr" @@ -513,14 +513,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -542,9 +542,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -568,12 +568,12 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "tinystr" -version = "0.8.4" +version = "0.8.5" dependencies = [ "bincode", "criterion", @@ -598,9 +598,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "walkdir" @@ -708,18 +708,18 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.56" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.56" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", @@ -734,9 +734,9 @@ checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" [[package]] name = "zerovec" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "serde", "zerofrom", diff --git a/deps/crates/vendor/tinystr-v0_8/Cargo.toml b/deps/crates/vendor/tinystr-v0_8/Cargo.toml index 6b5000d9913d..0685945d3510 100644 --- a/deps/crates/vendor/tinystr-v0_8/Cargo.toml +++ b/deps/crates/vendor/tinystr-v0_8/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.82" name = "tinystr" -version = "0.8.4" +version = "0.8.5" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -110,7 +110,7 @@ optional = true default-features = false [dependencies.zerovec] -version = "0.11.7" +version = "0.11.9" optional = true default-features = false diff --git a/deps/crates/vendor/tinystr-v0_8/Cargo.toml.orig b/deps/crates/vendor/tinystr-v0_8/Cargo.toml.orig index b5a90127e79f..a162252f4fff 100644 --- a/deps/crates/vendor/tinystr-v0_8/Cargo.toml.orig +++ b/deps/crates/vendor/tinystr-v0_8/Cargo.toml.orig @@ -5,7 +5,7 @@ [package] name = "tinystr" description = "A small ASCII-only bounded length string representation." -version = "0.8.4" +version = "0.8.5" keywords = ["small-string", "ascii", "string", "str"] categories = ["data-structures"] diff --git a/deps/crates/vendor/tinystr-v0_8/src/ascii.rs b/deps/crates/vendor/tinystr-v0_8/src/ascii.rs index 8638672df26a..98fa64e8d9d6 100644 --- a/deps/crates/vendor/tinystr-v0_8/src/ascii.rs +++ b/deps/crates/vendor/tinystr-v0_8/src/ascii.rs @@ -24,6 +24,10 @@ impl<const N: usize> TinyAsciiStr<N> { bytes: [AsciiByte::B0; N], }; + pub const fn default() -> Self { + Self::EMPTY + } + #[inline] pub const fn try_from_str(s: &str) -> Result<Self, ParseError> { Self::try_from_utf8(s.as_bytes()) @@ -845,6 +849,12 @@ impl<const N: usize> Deref for TinyAsciiStr<N> { } } +impl<const N: usize> Default for TinyAsciiStr<N> { + fn default() -> Self { + Self::default() + } +} + impl<const N: usize> Borrow<str> for TinyAsciiStr<N> { #[inline] fn borrow(&self) -> &str { diff --git a/deps/crates/vendor/tinystr-v0_8/src/unvalidated.rs b/deps/crates/vendor/tinystr-v0_8/src/unvalidated.rs index 44e0f9f9c15e..7824c2c1a9f4 100644 --- a/deps/crates/vendor/tinystr-v0_8/src/unvalidated.rs +++ b/deps/crates/vendor/tinystr-v0_8/src/unvalidated.rs @@ -57,7 +57,7 @@ impl<const N: usize> UnvalidatedTinyAsciiStr<N> { #[inline] /// Returns the empty string. pub const fn default() -> Self { - TinyAsciiStr::EMPTY.to_unvalidated() + TinyAsciiStr::default().to_unvalidated() } } diff --git a/deps/crates/vendor/unicode-ident-v1/.cargo_vcs_info.json b/deps/crates/vendor/unicode-ident-v1/.cargo_vcs_info.json index bafcae375e74..60e919487279 100644 --- a/deps/crates/vendor/unicode-ident-v1/.cargo_vcs_info.json +++ b/deps/crates/vendor/unicode-ident-v1/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "5b54a632702b5744a1c40ea01c127c0ac0498172" + "sha1": "48771a67a73f7e14ce802aaeee16770ba661035b" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/deps/crates/vendor/unicode-ident-v1/.github/workflows/ci.yml b/deps/crates/vendor/unicode-ident-v1/.github/workflows/ci.yml index d8b3c84b96e7..6eb3300bee97 100644 --- a/deps/crates/vendor/unicode-ident-v1/.github/workflows/ci.yml +++ b/deps/crates/vendor/unicode-ident-v1/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable - id: ucd-generate run: echo "version=$(grep 'ucd-generate [0-9]\+\.[0-9]\+\.[0-9]\+' tests/tables/tables.rs --only-matching)" >> $GITHUB_OUTPUT @@ -44,10 +44,10 @@ jobs: strategy: fail-fast: false matrix: - rust: [nightly, beta, stable, 1.86.0] + rust: [nightly, beta, stable, 1.90.0] timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} @@ -56,7 +56,7 @@ jobs: if: matrix.rust == 'nightly' - run: cargo test - run: cargo check --benches - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 if: matrix.rust == 'nightly' && always() with: name: Cargo.lock @@ -70,7 +70,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@1.71.0 - run: cargo check --manifest-path tests/crate/Cargo.toml @@ -83,7 +83,7 @@ jobs: env: RUSTDOCFLAGS: -Dwarnings steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-docs-rs - run: cargo docs-rs @@ -94,7 +94,7 @@ jobs: if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --tests --benches --workspace -- -Dclippy::all -Dclippy::pedantic @@ -104,7 +104,7 @@ jobs: if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: dtolnay/rust-toolchain@stable - uses: dtolnay/install@cargo-outdated - run: cargo outdated --workspace --exit-code 1 diff --git a/deps/crates/vendor/unicode-ident-v1/Cargo.lock b/deps/crates/vendor/unicode-ident-v1/Cargo.lock index 8b38ee72426e..866e62118a8a 100644 --- a/deps/crates/vendor/unicode-ident-v1/Cargo.lock +++ b/deps/crates/vendor/unicode-ident-v1/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -28,33 +28,21 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anyhow" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -70,9 +58,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.56" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4" dependencies = [ "find-msvc-tools", "shlex", @@ -80,15 +68,15 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", "cpufeatures", @@ -124,18 +112,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.58" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.58" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -143,15 +131,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "cpufeatures" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] @@ -197,27 +185,15 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "either" -version = "1.15.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" [[package]] name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "foldhash" -version = "0.1.5" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" [[package]] name = "fst" @@ -227,16 +203,14 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi", "rand_core", - "wasip2", - "wasip3", ] [[package]] @@ -250,45 +224,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", -] - [[package]] name = "itertools" version = "0.13.0" @@ -300,33 +235,21 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "libc" -version = "0.2.182" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" - -[[package]] -name = "log" -version = "0.4.29" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "num-traits" @@ -353,45 +276,35 @@ dependencies = [ "winapi", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ - "unicode-ident 1.0.23", + "unicode-ident 1.0.25", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom", @@ -400,15 +313,15 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -418,9 +331,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -429,15 +342,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "roaring" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba9ce64a8f45d7fc86358410bb1a82e8c987504c0d4900e9141d69a9f26c885" +checksum = "18bd8a37d17a58532776dcdf6041ce64929adca78e8489d5cacbafe99229d3e1" dependencies = [ "bytemuck", "byteorder", @@ -452,17 +365,11 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -470,29 +377,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.6", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -503,19 +410,30 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "syn" -version = "2.0.116" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", - "unicode-ident 1.0.23", + "unicode-ident 1.0.25", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident 1.0.25", ] [[package]] @@ -536,13 +454,13 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "ab72a15cf68d77cb0987d3684aa8a45c5ef827e8cb49ee2f30bfd7ba2feb519f" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" dependencies = [ "criterion", "fst", @@ -568,58 +486,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - [[package]] name = "winapi" version = "0.3.9" @@ -666,116 +532,28 @@ dependencies = [ "windows-link", ] -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/deps/crates/vendor/unicode-ident-v1/Cargo.toml b/deps/crates/vendor/unicode-ident-v1/Cargo.toml index 720637c4d7f9..df3d4d437f9d 100644 --- a/deps/crates/vendor/unicode-ident-v1/Cargo.toml +++ b/deps/crates/vendor/unicode-ident-v1/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.71" name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" authors = ["David Tolnay <dtolnay@gmail.com>"] build = false autolib = false diff --git a/deps/crates/vendor/unicode-ident-v1/Cargo.toml.orig b/deps/crates/vendor/unicode-ident-v1/Cargo.toml.orig index f775754c8b86..bba531b8e942 100644 --- a/deps/crates/vendor/unicode-ident-v1/Cargo.toml.orig +++ b/deps/crates/vendor/unicode-ident-v1/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "unicode-ident" -version = "1.0.24" +version = "1.0.26" authors = ["David Tolnay <dtolnay@gmail.com>"] categories = ["development-tools::procedural-macro-helpers", "no-std", "no-std::no-alloc"] description = "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31" @@ -39,4 +39,4 @@ rustdoc-args = [ ] [patch.crates-io] -unicode-xid = { git = "https://github.com/dtolnay-contrib/unicode-xid", branch = "unicode17.0.0" } +unicode-xid = { git = "https://github.com/dtolnay-contrib/unicode-xid", branch = "unicode18.0.0" } diff --git a/deps/crates/vendor/unicode-ident-v1/README.md b/deps/crates/vendor/unicode-ident-v1/README.md index 2e4668ef6252..445e646c5bb3 100644 --- a/deps/crates/vendor/unicode-ident-v1/README.md +++ b/deps/crates/vendor/unicode-ident-v1/README.md @@ -41,11 +41,11 @@ different ratios of ASCII to non-ASCII codepoints in the input data. | | static storage | 0% nonascii | 1% | 10% | 100% nonascii | |---|---|---|---|---|---| -| **`unicode-ident`** | 10.3 K | 0.41 ns | 0.44 ns | 0.44 ns | 0.93 ns | -| **`unicode-xid`** | 12.0 K | 2.43 ns | 2.50 ns | 2.85 ns | 8.65 ns | -| **`ucd-trie`** | 10.4 K | 1.28 ns | 1.25 ns | 1.20 ns | 1.97 ns | -| **`fst`** | 144 K | 50.9 ns | 51.0 ns | 48.5 ns | 26.7 ns | -| **`roaring`** | 66.1 K | 4.28 ns | 4.22 ns | 4.25 ns | 4.61 ns | +| **`unicode-ident`** | 10.3 K | 0.36 ns | 0.37 ns | 0.37 ns | 0.43 ns | +| **`unicode-xid`** | 12.2 K | 1.63 ns | 1.70 ns | 1.82 ns | 4.56 ns | +| **`ucd-trie`** | 10.8 K | 1.01 ns | 0.73 ns | 0.97 ns | 1.09 ns | +| **`fst`** | 149 K | 22.0 ns | 21.9 ns | 20.9 ns | 10.5 ns | +| **`roaring`** | 66.1 K | 1.91 ns | 1.90 ns | 1.94 ns | 2.67 ns | Source code for the benchmark is provided in the *bench* directory of this repo and may be repeated by running `cargo criterion`. @@ -212,9 +212,8 @@ reasonable. However, as you can see there is a large degree of similarity between the two bitmaps and across the rows, which lends well to compression. This crate stores one 512-bit "row" of the above bitmaps in the leaf level of a -trie, and a single additional level to index into the leafs. It turns out there -are 124 unique 512-bit chunks across the two bitmaps so 7 bits are sufficient to -index them. +trie, and a single additional level to index into the leafs. There are 134 +unique 512-bit chunks across the two bitmaps. The chunk size of 512 bits is selected as the size that minimizes the total size of the data structure. A smaller chunk, like 256 or 128 bits, would achieve @@ -222,12 +221,13 @@ better deduplication but require a larger index. A larger chunk would increase redundancy in the leaf bitmaps. 512 bit chunks are the optimum for total size of the index plus leaf bitmaps. -In fact since there are only 124 unique chunks, we can use an 8-bit index with a -spare bit to index at the half-chunk level. This achieves an additional 8.5% -compression by eliminating redundancies between the second half of any chunk and -the first half of any other chunk. Note that this is not the same as using -chunks which are half the size, because it does not necessitate raising the size -of the trie's first level. +The chunk data is compressed using the Kuhn–Munkres algorithm for bipartite +matching to eliminate redundancies between the second half of any chunk and the +first half of any other chunk. This achieves an additional 9% compression of the +leaf level, leaving 122 chunks that can be indexed at the half-chunk level using +an 8-bit index. Note that this is not the same as using chunks which are half +the size, because it does not necessitate raising the size of the trie's first +level. In contrast to binary search or the `ucd-trie` crate, performing lookups in this data structure is straight-line code with no need for branching. @@ -235,9 +235,9 @@ data structure is straight-line code with no need for branching. ```asm is_xid_start: mov eax, edi - mov ecx, offset unicode_ident::ZERO shr eax, 9 - cmp edi, 210432 + cmp edi, 261632 + mov ecx, offset unicode_ident::tables::TRIE_START+17 lea rax, [rax + unicode_ident::tables::TRIE_START] cmovb rcx, rax movzx eax, byte ptr [rcx] diff --git a/deps/crates/vendor/unicode-ident-v1/src/lib.rs b/deps/crates/vendor/unicode-ident-v1/src/lib.rs index 7498812f0d3f..7e70a0938cd3 100644 --- a/deps/crates/vendor/unicode-ident-v1/src/lib.rs +++ b/deps/crates/vendor/unicode-ident-v1/src/lib.rs @@ -43,11 +43,11 @@ //! //! | | static storage | 0% nonascii | 1% | 10% | 100% nonascii | //! |---|---|---|---|---|---| -//! | **`unicode-ident`** | 10.3 K | 0.41 ns | 0.44 ns | 0.44 ns | 0.93 ns | -//! | **`unicode-xid`** | 12.0 K | 2.43 ns | 2.50 ns | 2.85 ns | 8.65 ns | -//! | **`ucd-trie`** | 10.4 K | 1.28 ns | 1.25 ns | 1.20 ns | 1.97 ns | -//! | **`fst`** | 144 K | 50.9 ns | 51.0 ns | 48.5 ns | 26.7 ns | -//! | **`roaring`** | 66.1 K | 4.28 ns | 4.22 ns | 4.25 ns | 4.61 ns | +//! | **`unicode-ident`** | 10.3 K | 0.36 ns | 0.37 ns | 0.37 ns | 0.43 ns | +//! | **`unicode-xid`** | 12.2 K | 1.63 ns | 1.70 ns | 1.82 ns | 4.56 ns | +//! | **`ucd-trie`** | 10.8 K | 1.01 ns | 0.73 ns | 0.97 ns | 1.09 ns | +//! | **`fst`** | 149 K | 22.0 ns | 21.9 ns | 20.9 ns | 10.5 ns | +//! | **`roaring`** | 66.1 K | 1.91 ns | 1.90 ns | 1.94 ns | 2.67 ns | //! //! Source code for the benchmark is provided in the *bench* directory of this //! repo and may be repeated by running `cargo criterion`. @@ -221,9 +221,8 @@ //! compression. //! //! This crate stores one 512-bit "row" of the above bitmaps in the leaf level -//! of a trie, and a single additional level to index into the leafs. It turns -//! out there are 124 unique 512-bit chunks across the two bitmaps so 7 bits are -//! sufficient to index them. +//! of a trie, and a single additional level to index into the leafs. There are +//! 134 unique 512-bit chunks across the two bitmaps. //! //! The chunk size of 512 bits is selected as the size that minimizes the total //! size of the data structure. A smaller chunk, like 256 or 128 bits, would @@ -231,18 +230,19 @@ //! would increase redundancy in the leaf bitmaps. 512 bit chunks are the //! optimum for total size of the index plus leaf bitmaps. //! -//! In fact since there are only 124 unique chunks, we can use an 8-bit index -//! with a spare bit to index at the half-chunk level. This achieves an -//! additional 8.5% compression by eliminating redundancies between the second -//! half of any chunk and the first half of any other chunk. Note that this is -//! not the same as using chunks which are half the size, because it does not -//! necessitate raising the size of the trie's first level. +//! The chunk data is compressed using the Kuhn–Munkres algorithm for bipartite +//! matching to eliminate redundancies between the second half of any chunk and +//! the first half of any other chunk. This achieves an additional 9% +//! compression of the leaf level, leaving 122 chunks that can be indexed at the +//! half-chunk level using an 8-bit index. Note that this is not the same as +//! using chunks which are half the size, because it does not necessitate +//! raising the size of the trie's first level. //! //! In contrast to binary search or the `ucd-trie` crate, performing lookups in //! this data structure is straight-line code with no need for branching. #![no_std] -#![doc(html_root_url = "https://docs.rs/unicode-ident/1.0.24")] +#![doc(html_root_url = "https://docs.rs/unicode-ident/1.0.26")] #![allow( clippy::doc_markdown, clippy::must_use_candidate, @@ -253,16 +253,19 @@ mod tables; pub use crate::tables::UNICODE_VERSION; -use crate::tables::{ASCII_CONTINUE, ASCII_START, CHUNK, LEAF, TRIE_CONTINUE, TRIE_START}; - -static ZERO: u8 = 0; +use crate::tables::{ + ASCII_CONTINUE, ASCII_START, CHUNK, LEAF, TRIE_CONTINUE, TRIE_START, ZERO_CONTINUE, ZERO_START, +}; /// Whether the character has the Unicode property XID\_Start. pub fn is_xid_start(ch: char) -> bool { if ch.is_ascii() { return ASCII_START & (1 << ch as u128) != 0; } - let chunk = *TRIE_START.0.get(ch as usize / 8 / CHUNK).unwrap_or(&ZERO); + let chunk = *TRIE_START + .0 + .get(ch as usize / 8 / CHUNK) + .unwrap_or(&TRIE_START.0[ZERO_START]); let offset = chunk as usize * CHUNK / 2 + ch as usize / 8 % CHUNK; unsafe { LEAF.0.get_unchecked(offset) }.wrapping_shr(ch as u32 % 8) & 1 != 0 } @@ -275,7 +278,7 @@ pub fn is_xid_continue(ch: char) -> bool { let chunk = *TRIE_CONTINUE .0 .get(ch as usize / 8 / CHUNK) - .unwrap_or(&ZERO); + .unwrap_or(&TRIE_CONTINUE.0[ZERO_CONTINUE]); let offset = chunk as usize * CHUNK / 2 + ch as usize / 8 % CHUNK; unsafe { LEAF.0.get_unchecked(offset) }.wrapping_shr(ch as u32 % 8) & 1 != 0 } diff --git a/deps/crates/vendor/unicode-ident-v1/src/tables.rs b/deps/crates/vendor/unicode-ident-v1/src/tables.rs index c8adab3eec7d..aa2a98ac4081 100644 --- a/deps/crates/vendor/unicode-ident-v1/src/tables.rs +++ b/deps/crates/vendor/unicode-ident-v1/src/tables.rs @@ -1,6 +1,6 @@ // @generated by ../generate. To regenerate, run the following in the repo root: // -// $ curl -LO https://www.unicode.org/Public/17.0.0/ucd/UCD.zip +// $ curl -LO https://www.unicode.org/Public/18.0.0/ucd/UCD.zip // $ unzip UCD.zip -d UCD // $ cargo run --manifest-path generate/Cargo.toml @@ -9,75 +9,85 @@ pub(crate) struct Align8<T>(pub(crate) T); #[repr(C, align(64))] pub(crate) struct Align64<T>(pub(crate) T); -pub const UNICODE_VERSION: (u8, u8, u8) = (17, 0, 0); +pub const UNICODE_VERSION: (u8, u8, u8) = (18, 0, 0); pub(crate) const ASCII_START: u128 = 0x7fffffe07fffffe0000000000000000; pub(crate) const ASCII_CONTINUE: u128 = 0x7fffffe87fffffe03ff000000000000; pub(crate) const CHUNK: usize = 64; -pub(crate) static TRIE_START: Align8<[u8; 411]> = Align8([ - 0x03, 0x09, 0x0D, 0x11, 0x15, 0x19, 0x1D, 0x21, 0x25, 0x2B, 0x2F, 0x32, 0x36, 0x3A, 0x3E, 0xA5, - 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x4B, 0x00, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x50, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0x4F, 0x52, 0x56, 0x5A, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x5E, 0x62, 0x64, - 0x68, 0x6C, 0x70, 0xF0, 0x74, 0x76, 0x7A, 0x7E, 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, - 0xEF, 0x41, 0xA2, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xEF, 0xEF, 0xA4, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0x29, 0xEF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xD5, 0x00, 0x00, 0x00, 0xEF, 0xAE, 0xCB, 0xB2, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x26, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xC6, 0x00, 0x00, 0x00, 0xB9, - 0xCD, 0xD1, 0xD8, 0xDC, 0xE0, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xE7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xE9, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEB, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x07, 0xEF, 0xED, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xD6, 0x00, 0x00, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x04, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xF2, +// Positions of entries for the all-zero chunk. +pub(crate) const ZERO_START: usize = 17; +pub(crate) const ZERO_CONTINUE: usize = 17; + +pub(crate) static TRIE_START: Align8<[u8; 511]> = Align8([ + 0x03, 0x09, 0x0D, 0x11, 0x15, 0x19, 0x1D, 0x21, 0x25, 0x2B, 0x2F, 0x32, 0x36, 0x3A, 0x3E, 0xAE, + 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x4B, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xEB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0x4F, 0x52, 0x56, 0x5A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x5E, 0x62, 0x64, + 0x68, 0x6C, 0x70, 0x30, 0x74, 0x76, 0x7A, 0x7E, 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, + 0xAA, 0xAB, 0xA2, 0xA4, 0x00, 0x00, 0x00, 0xDB, 0xAA, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0x41, 0xAA, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD7, 0x00, 0x00, 0x00, 0xAA, 0xB3, 0xC7, 0xB7, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xAA, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x26, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0xCB, 0x00, 0x00, 0x00, 0xB1, + 0xD2, 0xD6, 0xDD, 0xE1, 0xE5, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xED, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xEF, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xF1, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x07, 0xAA, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD8, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x04, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xF7, ]); pub(crate) static TRIE_CONTINUE: Align8<[u8; 1793]> = Align8([ - 0x06, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F, 0x23, 0x28, 0x2D, 0x2F, 0x34, 0x38, 0x3C, 0x40, 0xA5, - 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x4D, 0x00, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x50, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0x4F, 0x54, 0x58, 0x5C, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x60, 0x62, 0x66, - 0x6A, 0x6E, 0x72, 0xF0, 0x74, 0x78, 0x7C, 0x80, 0x84, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C, 0xA0, - 0xEF, 0x41, 0xA2, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xEF, 0xEF, 0xA7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0x29, 0xEF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xD2, 0x00, 0x00, 0x00, 0xEF, 0xB0, 0xC2, 0xB4, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x26, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xBF, 0xBC, 0xC1, 0xC4, 0xC8, 0x00, 0xCA, 0x00, 0xB9, - 0xCF, 0xD4, 0xDA, 0xDE, 0xE2, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xE7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xE9, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEB, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x07, 0xEF, 0xED, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xD6, 0x00, 0x00, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0x04, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, - 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F, 0x23, 0x28, 0x2D, 0x2F, 0x34, 0x38, 0x3C, 0x40, 0xAE, + 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x4D, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xEB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0x4F, 0x54, 0x58, 0x5C, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x60, 0x62, 0x66, + 0x6A, 0x6E, 0x72, 0x30, 0x74, 0x78, 0x7C, 0x80, 0x84, 0x88, 0x8C, 0x90, 0x94, 0x98, 0x9C, 0xA0, + 0xAA, 0xAB, 0xA2, 0xA4, 0x00, 0x00, 0x00, 0xDB, 0xAA, 0xAA, 0xAD, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0x41, 0xAA, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD0, 0x00, 0x00, 0x00, 0xAA, 0xB5, 0xA7, 0xB9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xAA, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x26, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xC1, 0xBE, 0xC6, 0xC9, 0xCD, 0x00, 0xCF, 0x00, 0xB1, + 0xD4, 0xDA, 0xDF, 0xE3, 0xE7, 0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xED, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xEF, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xF1, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x07, 0xAA, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD8, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x04, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -161,7 +171,7 @@ pub(crate) static TRIE_CONTINUE: Align8<[u8; 1793]> = Align8([ 0x01, ]); -pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ +pub(crate) static LEAF: Align64<[u8; 7968]> = Align64([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -190,12 +200,12 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xC0, 0xD7, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xB6, 0x00, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x19, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xB6, 0x03, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F, 0x00, 0x60, 0xC0, 0x00, 0x9C, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -218,7 +228,7 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xE8, 0xC7, 0x3D, 0xD6, 0x18, 0xC7, 0xFF, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x87, 0xF9, 0xFF, 0xFF, 0xFD, 0x6D, 0xD3, 0x87, 0x39, 0x02, 0x5E, 0xC0, 0xFF, 0x3F, 0x00, 0xEE, 0xBF, 0xFB, 0xFF, 0xFF, 0xFD, 0xED, 0xF3, 0xBF, 0x3B, 0x01, 0x00, 0xCF, 0xFF, 0x00, 0xFE, - 0xEE, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0xF3, 0x9F, 0x39, 0xE0, 0xB0, 0xCF, 0xFF, 0x02, 0x00, + 0xEE, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0xF3, 0x9F, 0x39, 0xF8, 0xB0, 0xCF, 0xFF, 0x02, 0x00, 0xEC, 0xC7, 0x3D, 0xD6, 0x18, 0xC7, 0xFF, 0xC3, 0xC7, 0x3D, 0x81, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF, 0x23, 0x00, 0x00, 0x00, 0x37, 0x03, 0x00, 0x00, 0x00, 0xE1, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xEF, 0x23, 0x00, 0x00, 0x00, 0x70, 0x03, 0x00, 0x06, 0x00, @@ -240,14 +250,14 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0x03, 0x40, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x27, 0x00, 0xF0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x04, 0x00, 0x00, 0x00, 0x27, 0x00, 0xF0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, + 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, @@ -260,8 +270,8 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0x01, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xDF, 0x01, 0x00, @@ -283,7 +293,7 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x01, 0xC0, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x9F, - 0xFF, 0x03, 0xFF, 0x03, 0x80, 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x0F, 0x00, 0x00, + 0xFF, 0x03, 0xFF, 0x03, 0x80, 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0x03, 0x00, 0xF8, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x3F, @@ -295,13 +305,13 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, - 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xFC, 0x2F, 0x3F, 0x50, 0xFD, 0xFF, 0xF3, 0xE0, 0x43, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x80, - 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0xE2, 0xFF, 0x01, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0xE2, 0xFF, 0x01, 0x00, 0x84, 0xFC, 0x2F, 0x3F, 0x50, 0xFD, 0xFF, 0xF3, 0xE0, 0x43, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -325,15 +335,15 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x1F, 0xFF, 0xFF, 0x00, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFE, 0xFF, + 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x04, 0x00, 0xFE, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0xFE, 0xFF, + 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x04, 0x00, 0xFE, 0xFF, 0xBB, 0xF7, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x68, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F, @@ -344,11 +354,11 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF7, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xC4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x3E, 0x05, 0x00, 0x00, 0x38, 0xFF, 0x07, 0x1C, 0x00, - 0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x03, 0xFF, 0xFF, + 0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0x3F, 0xFF, 0x03, 0xFF, 0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x38, 0xFF, 0xFF, 0x7C, 0x00, - 0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x03, 0xFF, 0xFF, + 0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x37, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, @@ -415,11 +425,11 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xBE, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x00, 0xFC, 0x00, 0x00, 0xFE, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F, 0x80, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0x03, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0x03, 0x00, 0xFC, 0xF8, 0x00, 0xFE, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, @@ -464,20 +474,20 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1B, 0x00, 0x00, 0x00, 0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x04, 0x00, 0x00, 0x01, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x20, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x23, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFF, 0x03, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0xBF, 0xFD, 0xFF, 0xFF, - 0xFF, 0x03, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x03, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x01, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xB4, 0xFF, 0x00, 0xFF, 0x03, 0xBF, 0xFD, 0xFF, 0xFF, - 0xFF, 0x7F, 0xFB, 0x01, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x03, 0x00, 0x00, + 0xFF, 0x7F, 0xFB, 0x01, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0xF4, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -486,30 +496,40 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x07, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xAA, 0xFF, 0xFF, 0xFF, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x5F, 0xDC, 0x1F, 0xCF, 0x0F, 0xFF, 0x1F, 0xDC, 0x1F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xAA, 0xFF, 0xFF, 0xFF, 0x3F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x5F, 0xDC, 0x1F, 0xCF, 0x0F, 0xFF, 0x1F, 0xDC, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x6F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x03, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xE0, @@ -527,50 +547,50 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x80, + 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x7F, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE3, 0x07, 0xF8, + 0xE7, 0x0F, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x1F, 0xFF, 0x01, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE3, 0x07, 0xF8, - 0xE7, 0x0F, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x1F, 0xFF, 0x01, 0xFF, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x6F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x07, 0x98, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x64, 0xDE, 0xFF, 0xEB, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xE7, 0xDF, 0xDF, 0xFF, 0xFF, 0xFF, 0x7B, 0x5F, 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7, + 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7, + 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x20, 0x00, 0x10, 0x00, 0x00, 0xF8, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -584,16 +604,16 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -622,13 +642,15 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0xFF, 0xFB, 0xFF, 0x0F, 0xEE, 0xFB, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -640,14 +662,12 @@ pub(crate) static LEAF: Align64<[u8; 7808]> = Align64([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0x00, 0x00, 0x00, - 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]); diff --git a/deps/crates/vendor/unicode-ident-v1/tests/fst/xid_continue.fst b/deps/crates/vendor/unicode-ident-v1/tests/fst/xid_continue.fst index cc15f2d5dc8d10036bcc13cc6785f161bef921d3..fd11825b69ec48b8d04996ade0d44a3db090c395 100644 GIT binary patch delta 3407 zcmc&$4OCRs7Cz@P!{{&!XGRbNfdPkLL}COa-^=7jEdM}}e=+`2L|}4|r!`{D42oJ> zaoOh0EQ40P_10>&0&hju5=AjJf53d{>uKs}FMaFv&~a5yu-@rhW<qR{E7ywUzIV?3 z&c6HXefFNS_rBLYmwj?Y)@o7nL=F~p=%^!y4;}2<-?<ms4##j?HbY95fh)*|6!Qac zEhid?Yzox*L~*%!(7P^n6s7ih$_P$=6QiZAv~3p^-=`mZ*e)?8_KYBZ37q=-7pJA? zAdxeG4VOiu=9~(YA=zAZ78HdvS(B1eQfEj)X*21gkIkArhtj$8(lh2S$Xu9}O>+j9 zyFqRq%`aF~xcG54FDfpfrDabnVQ^_VT}CUGGgMi{hHBH3Y+PZkSy}s+RjZ$R+OmdC zY2Dgqp0%>4jd`$ceZvMyH&WOY<qIF@Dz%cpP$B?f@{hzkoiUUr3TT|If}ae2&>E`| zcO|XC&?6h887j{(IRS0TFT{w{Dg{quY)PQzjh(N*w&T_9uL#>--U>~8<4e#!dmCiT z@s|1ejrE7lC}Ui}xWJ(C!6Bi#u<!|bNn-^2JrEgXm>4}N=D}FwWQjL~NF0v~#Bp<N zzOb`PgD(jhHO><Ii_>w$eo5@W5LpJh4t{#*@R84s9y@-byXWNR<P>x3GcmF3I|ZEI zt%8KgXE;+ev{fFI6)a+ZUt4^gKRtbh(tmvU&$H*gI)CA!!=;a0V$S_n?5nQQSWT81 zACqMyu6f!qesB2~23{Y(J=A2G6+WyD>xh^h*3__;nE%6Ho%-SVcjKl-?lx3R@{av> za!b5oiX_?bkm=6>kF+Q0Q_rL&KW4Io&e5eGm~XPYxo}<1D|uH6$^#akDMF=LPxLSS zprWEG=E?Ksv$gwHn=EFr&#EI*T7Q+N7Q-8pvHZoC8u=!{IU1*6={#>2Q=6u$coG54 zU4(BLEAKvW{Mb>j?WF32DTxnF9XvYVTsn3PbtPd=Zk{XUibye!>%q264#)Ru#f;{r zad2UGf|qh|83ku#0GJ!5kHVaXOzx=|1*Hx7&^9v+$S#?}Eyu7gM-q6vS#16!gOefT zye{_cX~o)oowrp<i0tQafMifSzW0=jCo17O!JEO6eo;Ok2%Q<Lz}V{}YzfEfd9p@& z-3li?HbK!L6*%(O3awh407<>iL+RP6LbDp5W*f3_WFwEu26MWnD_Oj7_<}Es9H!7& zUnrP0xC9zI{GjCOYOu-7EK&6yXURDh!k1y<#ad|bOl69S1&tQh`rNT+vXu#a3b<ne z^u!X8zoEzQp2M3dF3pY?CVFBoI2IMok%Q3T_>xr?Y0Hhuie=?Xm*gzWTo4ELw-??H zr~$%ou#Qy%N@MOYL#4_P=VpQZn?{Zt5S&{46ZBP2Zu;0uFlun~5EpoH&Xs?8K+J!1 z<D(*p4&5fZt$1-Evz#^~m3Xln|BjuFhs6!wzA1<9AURCBktsNJI8SKSVB-*l)0jso zHRGTqI*=j!RH%a9?CZZpew21`lj(>P=YQYp0Y<sNCh-b)0Tf$q$gtm?uGCA#c;hA( z&_q^>b&&jZop_|b%7^<QOh{DXaO*rRO7}(6{n4KSkv<st=uo5%E!UwR!jLK)8T3dW ziGsZGy9RW`AOY8%I|<nzygeP{-!riOqH%ELw8_XCkIJW@(}_r&>b9}+VRUtx8(XH| zgW;7acL=AXA<svV|18AKMYqz~t8%wPaSPDVOmr&~)n}s}xk#RmS{I=`i_x(nlvaXX zC_{luP)#}dr~=8W&;}Fw-wO0&4cb$S{<aE@ej4>!kl$LQdlqHcBztS?QFH@RZ$kFx zQTP_r_=51R7Y+jcMuhNhFB}Z^nHj9vy9k`kajGO29_ZIBw<4sYnYFyKs@g3?sc8_o z0Bgc4sJVtpU6|6<5_6yz4>V$%G_^~^FEsF7VO+<~prhSKjUAkDjbI1x9lnt4Gf^;m zV1H=7n#dAzE94|Nc|zF9TF{>4i??}NyMr;ilMr%&|6@0BP5-Fzvg|k1S_jPk9y6B| zzoFu;8ZImEzRD_je;;pm{O{Wiet-N&W{ZU*75x6bn*!G0?jfajefx8vSSIJWWT=U; z0pGXJN|F&q$lHML&utxIcs(BRebjmU%0%=%_zk-6W5BVf67m~1K~K~e&=l#Ll%u5& x3S$|oJx)-CDBB;8#MkhIuf4KEcC@KIIE-|1v@guU4fM^w#<O5Evgeh&^D{bcJfr{s delta 3021 zcmc&$2~3nn6rNdFV3%WmF1hzW5J8YdP!tbXKm-Iq5CN4-M3F-QEoJdou-MX4mE~Fg zYHP4<jEV8WzXlPj*wzvgqs3IkS`Y9*t!-^YIkZgYU%=7?txY8U|LmJLZ)V>2X7;^& ze`AOK9~blwsm)-$nG9;pe4%cEJ5B~|pCc5ci@{Y=X+-7|-2>W%?neD8A)re3vLO4( zfrI2w9XUK`W;5KdgAG4AcmBtgL94E3E<l~Qott8Q&4jJ>!D4WhhC`mTMngzokcwXt z96~~8hRq5mBqDNlRP>yf*tu~eUblIOn3q82CnhB?SV(P)Qc_7;dd6a^W-cLFWa%=h zWiO{9CpVAE{1qz;3X4{)ey8}|5;`R6(lu+>(SE(AjFfM9uY!<`M9EK(_jU4x_@MH` zkE%Z2w0TSQ3)6tYXh9)7%4NxwGLv5)+`rdx_s;EG?QJ*Vi?cHBTwp0SBc$>8Hz!Uu zo%;5>?@#{#3T!1{n(5gu!u3slP<@nvz$_(qB)H1}4n^3Te*W2x?VqySKG_O2+G@BO zvCWJa8i~ZlCZ=W*#@xaZ6j8p`R@S3zZ0+nF9G#>xIUk9F{$Q_-gMb;Y#mU_C*=1I6 zGEKs^xZ*g@IXxQlxL_Q2l}laRX$X=MF{I|K1BX^IbmTNb&HhMsmkpjMAwOLt<kIEV zD?eZT<=XWd>@yqu1dJd0aP#v6%rz=?p+uz~i8snZV!g{I(f*;MR;E%1IS-4W84>7V zp@v1G=O6xUa2ekID(f`2I`?!>q4#Z{?Y>=p{K^CVDFH^)w+9*oH-tLRQmJvIAbNL< zN?j3`l~9^^COKTbs3G-wx=&_n7G#Iz8m~B9aB$VuVwE~{E$RE~`Lo_0D7>Eyf$h_{ zma^3nE~Ywy{_RmS1<YoequaTXn#m?KDGX|A3AjXg8~II~<Ue@|6QITA5YuGCo!?bs zr^}4IWA1cc`ZhysMEfLAoKb*vs>H(GW1OegcyFc8g#P4be6_fW8-09^Ks+SzThcrs zrAo{lIZ=SY4Kr{m*`AAOYSo7=MP878Iv()U7-;gyfu=RC=KY?ANboU?XA9i07u*~- z3tIFlA?1t->m|a61Wc$FFQ!Fe0>5o?<tv9ff0kHb!nL*R!*DW82scwjKq4IUE-{zs zkpZsk@Exo$IOQ>el^J4lP)5bFN<$m~O&wtZrUsVZyP^wC`7~3sY-!e#gt)n}6QJBA zj2RLZua2fg<Ro`-9YcuQzo*91s~NO_O23*-6X0x63R%wh;WZ&V_){uoqzIwVkYGlS z)_$iBP#$l_#XtU12v55cIP(ipSU`(-uB|U7@Tk*K-1+1w>FVz3WuDO;PhnG$H^}3K zob>tcdIlcuW8KEM4xY(CPbOEu$~7*mQiQ)2Fs@phRo^VYxe`I0ob|K7&Kf6kB(+46 zQOL*+J$69XrRc5{xyVqR95u_)ZD(}D6*&p<g0ZN0EZXV8>u<7YbnfPOA+0wm@j>?{ zpwoT>7#04gck+N<74ScRE2jTzaeNT64Mtyupo*}6?2X}QUL>lBOhks!NFIYKW07w> z3Q9mRiKsaVF$>YoMW{0sP0c`+nMkx0m1ZMN4tkP{ZssFZ0UA?;qF1A&VpLVaJKbA~ zlGmYWW$54r6kCB#Y-EpFVh5OOrC@t4u@jVwqC|svK%gbv7L3&vpu|STGy2Vx+Jd14 z+p^Vq*fTCmM^ODU*)R6>E0ncz2xTpvvj{2VjXZM^N?nw;_~BY!3_d)K5#@TCDQ)$N zQMgUOXBexr!yKfA8-R`dB$`}oxhdWQOrAN&{Y}{|9yE?VC)}lFO!?LIN=MvaplP(m zv;`v6uk_&orGNOQ<SqS|xYg+3Uk9e$@Fgx@>7h;h>RlTC^lz~Z-2YpP;Pvl+WI|jx zQkUP`(+wF%1M6@2;96Y2(+%qjH5j2{86MHrjb9ES|1WH4+m{0s8!IVig$R@rX>~uU nryt8bc=SGzz2llaW_kjQ<U-VRCrm);1tI#iuIqO<p3MIn!byIS diff --git a/deps/crates/vendor/unicode-ident-v1/tests/fst/xid_start.fst b/deps/crates/vendor/unicode-ident-v1/tests/fst/xid_start.fst index 771dc459c6868e86a080eb6c08c4502a0df1dbf7..14ef0565ba185c00a673e03a349365bb6a88e8f1 100644 GIT binary patch delta 2503 zcmc&!2~d+q6wdxh2oNBP0Yrq7AXbGW5^+4M{E?P=0fO8`DX4%%fk3f}G9e;WE5-ag zDfK|37IDyy;E%OVDIy*fwct^Yj&=%ORc8=W9Xx7HH=+m@JGGVR?mut$fBWtG-h2CY zD++n#TX>ZdY@uz300M0LQw6Ia-qs66fimZ9sIpx_MMT2>tf7?21i35S0HeV$H(w02 zz_PE2w2hk#o6Tcq!&?CH*ReUGCrSqM95-z&-LQV$+Am5zFJ1#hjDEFNgT)MrX0NF< z_An#K9$f}q(sXw3^guMQ-fZPyr>UotLx+!if3)G)@e@BZHk~|m8lNHN_3XazS_{aE z&7$VdgIlqOdC@V%zxcB%Xx=6O1J4_l2<$+FL=<j>DyvrDH!0a!ai_7CR$GZ^b#L^m z_IVE9I9+k(_5aF^R(nZ$<k0pCb&pg%GLiUu?)l1|^?#?`>ft<a&md<nqima^Q9-No zm6pThBSwrmGy3}2#p4&!v^vs1D&WdQT3tUy5HvqHC?wE%`l#@>i2A6rF;`=yaS`#Q zv-F9OOsoCbW11%-2J`v*Yrm`cmOZMQg!qN4^-K|H>}U!DIrX)yG4Fzq!A_v5c48Y= z3lSI<PU7z6LjLeX24%8o%vMLRFZU2yzW{(zO2f4B1@N#;3bh&5FvH*oHk*UNw@wVX zTp?@Nz86s(BS^V2Hm_nbLirHp=m|eJh*|#50v>~HATDVYFip)|VihXG!hjwwfadpH zOC($bfce=3umRFzct8s=90*zg!K@9ac$IMH!lx|Cu|t6LizvLDK?!VHH6<o7BNIr^ zuVmBj$jKt|<X*&=NVvs>HWQd}6To4+JDen*x3p)9UIb%~bPd5B0ZrKesI11Iyqf`r z_T6^fFeWf2`@*gpa=3K^gZB7w1`CLfdh6t*#5uFWLqnzw1D!>v`F=~cneVq{KQC{Y z$t3S?MKRPzISfujc>=ya6Vi>26g~(oL;hg-O*gHf^`{8-)V?4DZ>cOHO3;Tyv{}}V zNS%#4-}K<&qu&9YDrE2&w(3$VB55iiF8B(by$PVYn*h1O3fm6KrFqNpKUuzlq+$ff z0wqv4L<|;<Dwf+^VWSNaU9>;vaG>u_m&2}g?o-<)dCc*c+Gg&*dAbein7zKdFr?Ib znY>xC-p9Omuy3NTdAvXTFP5}VsXEkmMm}HOG-mcYS>r!cMZepj(Ffdn-*uw*<fBvU z0waSRLX4p!!|sL0MvjYi_@Lhm*SP-i)U4v!0g2_w1u4bz45??*r?x%L*pZdJ@Jja5 zCAV{K-@Nhb^=nrzw>1B9{@mFgYj#&v?jlcT;b#Rf@~%77w7P*VCJ1z6B_v5MHhvv> zqg509O{CNY5~Z8n+!Xb^&Lf;pRDBhxY3Z70s*KE!vP=s;UbrZGv01aE6Zw21$zf4j zJr`ysl|HLx8g#<(a3I77u(1gI=DNT|Sv!L<Imu~kpZ0JIt(Cu=lnvsTWgRlhf78o& z|9sb%f-YF?E9lCsyMSJSc@qfjn=tYpY^3yJY+c=Y^zZ?+G^DX~y8@AyU>K<d(H<G% z@fnH+CLtF>4@t-?YtUkvgE*W;R_Oovv|Wgop<ef6G4~}3@7IXCh${!_(v*_X7HB>A tt+NKT)c`MY7kv^)3Qd-NF2SW-3UMSnPTgZQ#WA-&_9VHaeeIGO{3l!^Zu$TK delta 2177 zcmcIk3s6*L6yE=`yRf^gd#?+)4ui1R0=qm{lC%^SVtFVCD?yQ<_yAV71ma<nQwy3C z2^p8831Y@r48=eKS3w(xL|&1PV0h_FxlrK7Oe9QWP)*$K4P;;jsxkS`opbL!=R4;+ zXU>_w@;tZd1h+Ow3|g@x$oWbX52W~WD>{z;`v9_3Lbp5=h)VlatflPihv#Novl{;h z5bq3iR5Gn5&X%1iEjj(csgqDl78x^e35nvVUjj1-7^EaXCTyoVV<HhCWJ6qUX>Duo z_^R{k8#iy={-z7>X0jAfH)5OkP>_&WoY)3EzMe3ixP?JGVE9d_6O2(|yDSK!${>)a z49g+Igwf`rok_;AuW(QqoShcsFfI%AqEw4AG5s$t+3LmZ|70z5#uYWLxN6knoL7^V z%8;#|@^$cY+0e4F|2c!dUZXOEJ|7m+6Q(lMZ=H-xjPloQmc_Wmn&RqTYJ0gif!GzY z`<=aSq`awD89b@MjA;q)iz}BK8{mRM0bLRSWq-sDG3%qn@Dt2@ODW>*J0h!&_O{lR z>vgrD^HD))(OtliD?H<z1$ZY98iXsU9<tCDk}BnJ=O+{7+?HdwoJ5fzZk0l=g@}6a zX(Ix;g$LDJwFNQ35)3~^A{%(2P)fyB7jl_p%LTRQ9<g9g*&k?b%Ej;pB+^2jS3aao zSc2mv9@LaqGikUO9!#P=RQP2~ifAC*`yjnD0@Aew%nB+k`tbp#1z=cwp<JSYJdr=V zyIu{0av$i@c|&<quw(%tUJUoU?=r;{2~ty%_r-44MXv)QDFk1DqUp8lhRdE(xX`rg zLYJFT<qo&bhrxJ%G~}2A0p~SQ`F*28CMg&0IXl9s!F3SmUNKwf4vcA$$Xm@;|0Sz) ztsO1t$*JFd$NykzZ>Riz7(;xO(#_RH!Pd{8p@Xq}AE+(=j7!tFf<*pQqq)l3=(wU9 zuaFkm9bSFX{{1y2W})0g9=W!}{CG00XmPDl^4*&~*!XSUh2HGjLA_+QG{$ZB^donh z-|-E$&;Gh;=HD}b)LhZD2ki~6)Q*SNgdgA974hD-hf)2ynwa|7OD|rGFWZ3<>vu|b zPwhd;)~NyeOUyeB;)CC&Ycq$lqH}&8{n31XWcd4`LDN8gU+>lWy4njc@tqvrdguVn z;t0Xq7(h260}sPWW<9K|{b$Spn!q3$>eA%kbW8w3BwMjBIVE*2M9++KmDm0QhF4}y zuO3WGr!!v5%*xJTEr;fik3O7UXD+uPs$y~oV+LCb(IOwv={K>%R7a%&el`5G216o9 zGD+buJx$_b1{O^X{29wPt_jdj>L(G0)z=WKA4e*<|2^sx%XwJi5_BI6=Yf{MJPCyH zNhJ9nIZ~IgxA|o?;(Rp1HzE#4%|XlhOrfPIoc@g)0*@Sk&4&t@OHt$EvmS9e_&k{& aEHK1z;&QHyY{WS1v9)9xVUDo0!Soja=Nz*D diff --git a/deps/crates/vendor/unicode-ident-v1/tests/static_size.rs b/deps/crates/vendor/unicode-ident-v1/tests/static_size.rs index e2bcd736e38c..d36bb38db80b 100644 --- a/deps/crates/vendor/unicode-ident-v1/tests/static_size.rs +++ b/deps/crates/vendor/unicode-ident-v1/tests/static_size.rs @@ -13,7 +13,7 @@ fn test_size() { + size_of_val(&tables::TRIE_START) + size_of_val(&tables::TRIE_CONTINUE) + size_of_val(&tables::LEAF); - assert_eq!(10056, size); + assert_eq!(10344, size); } #[test] @@ -23,7 +23,7 @@ fn test_xid_size() { mod tables; let size = size_of_val(tables::XID_START) + size_of_val(tables::XID_CONTINUE); - assert_eq!(11976, size); + assert_eq!(12184, size); let _ = tables::BY_NAME; } @@ -70,7 +70,7 @@ fn test_trieset_size() { + size_of_val(tree3_level2) + size_of_val(tree3_level3); - assert_eq!(10392, start_size + continue_size); + assert_eq!(10752, start_size + continue_size); let _ = trie::BY_NAME; } @@ -80,7 +80,7 @@ fn test_fst_size() { let xid_start_fst = include_bytes!("fst/xid_start.fst"); let xid_continue_fst = include_bytes!("fst/xid_continue.fst"); let size = xid_start_fst.len() + xid_continue_fst.len(); - assert_eq!(143513, size); + assert_eq!(148706, size); } #[test] diff --git a/deps/crates/vendor/unicode-ident-v1/tests/tables/tables.rs b/deps/crates/vendor/unicode-ident-v1/tests/tables/tables.rs index 9db6fe958916..d4903351fb16 100644 --- a/deps/crates/vendor/unicode-ident-v1/tests/tables/tables.rs +++ b/deps/crates/vendor/unicode-ident-v1/tests/tables/tables.rs @@ -2,7 +2,7 @@ // // ucd-generate property-bool UCD --include XID_Start,XID_Continue // -// Unicode version: 17.0.0. +// Unicode version: 18.0.0. // // ucd-generate 0.3.1 is available on crates.io. @@ -15,55 +15,55 @@ pub const XID_CONTINUE: &'static [(u32, u32)] = &[ (186, 186), (192, 214), (216, 246), (248, 705), (710, 721), (736, 740), (748, 748), (750, 750), (768, 884), (886, 887), (891, 893), (895, 895), (902, 906), (908, 908), (910, 929), (931, 1013), (1015, 1153), (1155, 1159), - (1162, 1327), (1329, 1366), (1369, 1369), (1376, 1416), (1425, 1469), - (1471, 1471), (1473, 1474), (1476, 1477), (1479, 1479), (1488, 1514), - (1519, 1522), (1552, 1562), (1568, 1641), (1646, 1747), (1749, 1756), - (1759, 1768), (1770, 1788), (1791, 1791), (1808, 1866), (1869, 1969), - (1984, 2037), (2042, 2042), (2045, 2045), (2048, 2093), (2112, 2139), - (2144, 2154), (2160, 2183), (2185, 2191), (2199, 2273), (2275, 2403), - (2406, 2415), (2417, 2435), (2437, 2444), (2447, 2448), (2451, 2472), - (2474, 2480), (2482, 2482), (2486, 2489), (2492, 2500), (2503, 2504), - (2507, 2510), (2519, 2519), (2524, 2525), (2527, 2531), (2534, 2545), - (2556, 2556), (2558, 2558), (2561, 2563), (2565, 2570), (2575, 2576), - (2579, 2600), (2602, 2608), (2610, 2611), (2613, 2614), (2616, 2617), - (2620, 2620), (2622, 2626), (2631, 2632), (2635, 2637), (2641, 2641), - (2649, 2652), (2654, 2654), (2662, 2677), (2689, 2691), (2693, 2701), - (2703, 2705), (2707, 2728), (2730, 2736), (2738, 2739), (2741, 2745), - (2748, 2757), (2759, 2761), (2763, 2765), (2768, 2768), (2784, 2787), - (2790, 2799), (2809, 2815), (2817, 2819), (2821, 2828), (2831, 2832), - (2835, 2856), (2858, 2864), (2866, 2867), (2869, 2873), (2876, 2884), - (2887, 2888), (2891, 2893), (2901, 2903), (2908, 2909), (2911, 2915), - (2918, 2927), (2929, 2929), (2946, 2947), (2949, 2954), (2958, 2960), - (2962, 2965), (2969, 2970), (2972, 2972), (2974, 2975), (2979, 2980), - (2984, 2986), (2990, 3001), (3006, 3010), (3014, 3016), (3018, 3021), - (3024, 3024), (3031, 3031), (3046, 3055), (3072, 3084), (3086, 3088), - (3090, 3112), (3114, 3129), (3132, 3140), (3142, 3144), (3146, 3149), - (3157, 3158), (3160, 3162), (3164, 3165), (3168, 3171), (3174, 3183), - (3200, 3203), (3205, 3212), (3214, 3216), (3218, 3240), (3242, 3251), - (3253, 3257), (3260, 3268), (3270, 3272), (3274, 3277), (3285, 3286), - (3292, 3294), (3296, 3299), (3302, 3311), (3313, 3315), (3328, 3340), - (3342, 3344), (3346, 3396), (3398, 3400), (3402, 3406), (3412, 3415), - (3423, 3427), (3430, 3439), (3450, 3455), (3457, 3459), (3461, 3478), - (3482, 3505), (3507, 3515), (3517, 3517), (3520, 3526), (3530, 3530), - (3535, 3540), (3542, 3542), (3544, 3551), (3558, 3567), (3570, 3571), - (3585, 3642), (3648, 3662), (3664, 3673), (3713, 3714), (3716, 3716), - (3718, 3722), (3724, 3747), (3749, 3749), (3751, 3773), (3776, 3780), - (3782, 3782), (3784, 3790), (3792, 3801), (3804, 3807), (3840, 3840), - (3864, 3865), (3872, 3881), (3893, 3893), (3895, 3895), (3897, 3897), - (3902, 3911), (3913, 3948), (3953, 3972), (3974, 3991), (3993, 4028), - (4038, 4038), (4096, 4169), (4176, 4253), (4256, 4293), (4295, 4295), - (4301, 4301), (4304, 4346), (4348, 4680), (4682, 4685), (4688, 4694), - (4696, 4696), (4698, 4701), (4704, 4744), (4746, 4749), (4752, 4784), - (4786, 4789), (4792, 4798), (4800, 4800), (4802, 4805), (4808, 4822), - (4824, 4880), (4882, 4885), (4888, 4954), (4957, 4959), (4969, 4977), - (4992, 5007), (5024, 5109), (5112, 5117), (5121, 5740), (5743, 5759), - (5761, 5786), (5792, 5866), (5870, 5880), (5888, 5909), (5919, 5940), - (5952, 5971), (5984, 5996), (5998, 6000), (6002, 6003), (6016, 6099), - (6103, 6103), (6108, 6109), (6112, 6121), (6155, 6157), (6159, 6169), - (6176, 6264), (6272, 6314), (6320, 6389), (6400, 6430), (6432, 6443), - (6448, 6459), (6470, 6509), (6512, 6516), (6528, 6571), (6576, 6601), - (6608, 6618), (6656, 6683), (6688, 6750), (6752, 6780), (6783, 6793), - (6800, 6809), (6823, 6823), (6832, 6845), (6847, 6877), (6880, 6891), + (1162, 1327), (1329, 1366), (1368, 1369), (1376, 1416), (1419, 1420), + (1425, 1469), (1471, 1471), (1473, 1474), (1476, 1477), (1479, 1481), + (1488, 1514), (1519, 1522), (1552, 1562), (1568, 1641), (1646, 1747), + (1749, 1756), (1759, 1768), (1770, 1788), (1791, 1791), (1808, 1866), + (1869, 1969), (1984, 2037), (2042, 2042), (2045, 2045), (2048, 2093), + (2112, 2139), (2144, 2154), (2160, 2183), (2185, 2191), (2199, 2273), + (2275, 2403), (2406, 2415), (2417, 2435), (2437, 2444), (2447, 2448), + (2451, 2472), (2474, 2480), (2482, 2482), (2486, 2489), (2492, 2500), + (2503, 2504), (2507, 2510), (2519, 2519), (2524, 2525), (2527, 2531), + (2534, 2545), (2556, 2556), (2558, 2558), (2561, 2563), (2565, 2570), + (2575, 2576), (2579, 2600), (2602, 2608), (2610, 2611), (2613, 2614), + (2616, 2617), (2620, 2620), (2622, 2626), (2631, 2632), (2635, 2637), + (2641, 2641), (2649, 2652), (2654, 2654), (2662, 2677), (2689, 2691), + (2693, 2701), (2703, 2705), (2707, 2728), (2730, 2736), (2738, 2739), + (2741, 2745), (2748, 2757), (2759, 2761), (2763, 2765), (2768, 2768), + (2784, 2787), (2790, 2799), (2809, 2815), (2817, 2819), (2821, 2828), + (2831, 2832), (2835, 2856), (2858, 2864), (2866, 2867), (2869, 2873), + (2876, 2884), (2887, 2888), (2891, 2893), (2899, 2903), (2908, 2909), + (2911, 2915), (2918, 2927), (2929, 2929), (2946, 2947), (2949, 2954), + (2958, 2960), (2962, 2965), (2969, 2970), (2972, 2972), (2974, 2975), + (2979, 2980), (2984, 2986), (2990, 3001), (3006, 3010), (3014, 3016), + (3018, 3021), (3024, 3024), (3031, 3031), (3046, 3055), (3072, 3084), + (3086, 3088), (3090, 3112), (3114, 3129), (3132, 3140), (3142, 3144), + (3146, 3149), (3157, 3158), (3160, 3162), (3164, 3165), (3168, 3171), + (3174, 3183), (3200, 3203), (3205, 3212), (3214, 3216), (3218, 3240), + (3242, 3251), (3253, 3257), (3260, 3268), (3270, 3272), (3274, 3277), + (3285, 3286), (3292, 3294), (3296, 3299), (3302, 3311), (3313, 3315), + (3328, 3340), (3342, 3344), (3346, 3396), (3398, 3400), (3402, 3406), + (3412, 3415), (3423, 3427), (3430, 3439), (3450, 3455), (3457, 3459), + (3461, 3478), (3482, 3505), (3507, 3515), (3517, 3517), (3520, 3526), + (3530, 3530), (3535, 3540), (3542, 3542), (3544, 3551), (3558, 3567), + (3570, 3571), (3585, 3642), (3648, 3662), (3664, 3673), (3713, 3714), + (3716, 3716), (3718, 3722), (3724, 3747), (3749, 3749), (3751, 3773), + (3776, 3780), (3782, 3782), (3784, 3790), (3792, 3801), (3804, 3807), + (3840, 3840), (3864, 3865), (3872, 3881), (3893, 3893), (3895, 3895), + (3897, 3897), (3902, 3911), (3913, 3948), (3953, 3972), (3974, 3991), + (3993, 4028), (4038, 4038), (4096, 4169), (4176, 4253), (4256, 4293), + (4295, 4295), (4301, 4301), (4304, 4346), (4348, 4680), (4682, 4685), + (4688, 4694), (4696, 4696), (4698, 4701), (4704, 4744), (4746, 4749), + (4752, 4784), (4786, 4789), (4792, 4798), (4800, 4800), (4802, 4805), + (4808, 4822), (4824, 4880), (4882, 4885), (4888, 4954), (4957, 4959), + (4969, 4977), (4992, 5007), (5024, 5109), (5112, 5117), (5121, 5740), + (5743, 5759), (5761, 5786), (5792, 5866), (5870, 5880), (5888, 5909), + (5919, 5940), (5952, 5971), (5984, 5996), (5998, 6000), (6002, 6003), + (6016, 6099), (6103, 6103), (6108, 6109), (6112, 6121), (6155, 6157), + (6159, 6169), (6176, 6264), (6272, 6314), (6320, 6389), (6400, 6430), + (6432, 6443), (6448, 6459), (6470, 6509), (6512, 6516), (6528, 6571), + (6576, 6601), (6608, 6618), (6656, 6683), (6688, 6750), (6752, 6780), + (6783, 6793), (6800, 6809), (6823, 6823), (6832, 6845), (6847, 6896), (6912, 6988), (6992, 7001), (7019, 7027), (7040, 7155), (7168, 7223), (7232, 7241), (7245, 7293), (7296, 7306), (7312, 7354), (7357, 7359), (7376, 7378), (7380, 7418), (7424, 7957), (7960, 7965), (7968, 8005), @@ -71,7 +71,7 @@ pub const XID_CONTINUE: &'static [(u32, u32)] = &[ (8031, 8061), (8064, 8116), (8118, 8124), (8126, 8126), (8130, 8132), (8134, 8140), (8144, 8147), (8150, 8155), (8160, 8172), (8178, 8180), (8182, 8188), (8204, 8205), (8255, 8256), (8276, 8276), (8305, 8305), - (8319, 8319), (8336, 8348), (8400, 8412), (8417, 8417), (8421, 8432), + (8319, 8319), (8335, 8351), (8400, 8412), (8417, 8417), (8421, 8432), (8450, 8450), (8455, 8455), (8458, 8467), (8469, 8469), (8472, 8477), (8484, 8484), (8486, 8486), (8488, 8488), (8490, 8505), (8508, 8511), (8517, 8521), (8526, 8526), (8544, 8584), (11264, 11492), (11499, 11507), @@ -84,45 +84,46 @@ pub const XID_CONTINUE: &'static [(u32, u32)] = &[ (12593, 12686), (12704, 12735), (12784, 12799), (13312, 19903), (19968, 42124), (42192, 42237), (42240, 42508), (42512, 42539), (42560, 42607), (42612, 42621), (42623, 42737), (42775, 42783), - (42786, 42888), (42891, 42972), (42993, 43047), (43052, 43052), - (43072, 43123), (43136, 43205), (43216, 43225), (43232, 43255), - (43259, 43259), (43261, 43309), (43312, 43347), (43360, 43388), - (43392, 43456), (43471, 43481), (43488, 43518), (43520, 43574), - (43584, 43597), (43600, 43609), (43616, 43638), (43642, 43714), - (43739, 43741), (43744, 43759), (43762, 43766), (43777, 43782), - (43785, 43790), (43793, 43798), (43808, 43814), (43816, 43822), - (43824, 43866), (43868, 43881), (43888, 44010), (44012, 44013), - (44016, 44025), (44032, 55203), (55216, 55238), (55243, 55291), - (63744, 64109), (64112, 64217), (64256, 64262), (64275, 64279), - (64285, 64296), (64298, 64310), (64312, 64316), (64318, 64318), - (64320, 64321), (64323, 64324), (64326, 64433), (64467, 64605), - (64612, 64829), (64848, 64911), (64914, 64967), (65008, 65017), - (65024, 65039), (65056, 65071), (65075, 65076), (65101, 65103), - (65137, 65137), (65139, 65139), (65143, 65143), (65145, 65145), - (65147, 65147), (65149, 65149), (65151, 65276), (65296, 65305), - (65313, 65338), (65343, 65343), (65345, 65370), (65381, 65470), - (65474, 65479), (65482, 65487), (65490, 65495), (65498, 65500), - (65536, 65547), (65549, 65574), (65576, 65594), (65596, 65597), - (65599, 65613), (65616, 65629), (65664, 65786), (65856, 65908), - (66045, 66045), (66176, 66204), (66208, 66256), (66272, 66272), - (66304, 66335), (66349, 66378), (66384, 66426), (66432, 66461), - (66464, 66499), (66504, 66511), (66513, 66517), (66560, 66717), - (66720, 66729), (66736, 66771), (66776, 66811), (66816, 66855), - (66864, 66915), (66928, 66938), (66940, 66954), (66956, 66962), - (66964, 66965), (66967, 66977), (66979, 66993), (66995, 67001), - (67003, 67004), (67008, 67059), (67072, 67382), (67392, 67413), - (67424, 67431), (67456, 67461), (67463, 67504), (67506, 67514), - (67584, 67589), (67592, 67592), (67594, 67637), (67639, 67640), - (67644, 67644), (67647, 67669), (67680, 67702), (67712, 67742), - (67808, 67826), (67828, 67829), (67840, 67861), (67872, 67897), - (67904, 67929), (67968, 68023), (68030, 68031), (68096, 68099), - (68101, 68102), (68108, 68115), (68117, 68119), (68121, 68149), - (68152, 68154), (68159, 68159), (68192, 68220), (68224, 68252), - (68288, 68295), (68297, 68326), (68352, 68405), (68416, 68437), - (68448, 68466), (68480, 68497), (68608, 68680), (68736, 68786), - (68800, 68850), (68864, 68903), (68912, 68921), (68928, 68965), - (68969, 68973), (68975, 68997), (69248, 69289), (69291, 69292), - (69296, 69297), (69314, 69319), (69370, 69404), (69415, 69415), + (42786, 42888), (42891, 42973), (42978, 42978), (42993, 43047), + (43052, 43052), (43072, 43123), (43136, 43205), (43216, 43225), + (43232, 43255), (43259, 43259), (43261, 43309), (43312, 43347), + (43360, 43388), (43392, 43456), (43471, 43481), (43488, 43518), + (43520, 43574), (43584, 43597), (43600, 43609), (43616, 43638), + (43642, 43714), (43739, 43741), (43744, 43759), (43762, 43766), + (43777, 43782), (43785, 43790), (43793, 43798), (43808, 43814), + (43816, 43822), (43824, 43866), (43868, 43881), (43884, 43885), + (43888, 44010), (44012, 44013), (44016, 44025), (44032, 55203), + (55216, 55238), (55243, 55291), (63744, 64109), (64112, 64217), + (64256, 64262), (64275, 64279), (64285, 64296), (64298, 64310), + (64312, 64316), (64318, 64318), (64320, 64321), (64323, 64324), + (64326, 64433), (64467, 64605), (64612, 64829), (64848, 64911), + (64914, 64967), (65008, 65017), (65024, 65039), (65056, 65071), + (65075, 65076), (65101, 65103), (65137, 65137), (65139, 65139), + (65143, 65143), (65145, 65145), (65147, 65147), (65149, 65149), + (65151, 65276), (65296, 65305), (65313, 65338), (65343, 65343), + (65345, 65370), (65381, 65470), (65474, 65479), (65482, 65487), + (65490, 65495), (65498, 65500), (65536, 65547), (65549, 65574), + (65576, 65594), (65596, 65597), (65599, 65613), (65616, 65629), + (65664, 65786), (65856, 65908), (66045, 66045), (66176, 66204), + (66208, 66256), (66272, 66272), (66304, 66335), (66349, 66378), + (66384, 66426), (66432, 66461), (66464, 66499), (66504, 66511), + (66513, 66517), (66560, 66717), (66720, 66729), (66736, 66771), + (66776, 66811), (66816, 66855), (66864, 66915), (66928, 66938), + (66940, 66954), (66956, 66962), (66964, 66965), (66967, 66977), + (66979, 66993), (66995, 67001), (67003, 67004), (67008, 67059), + (67072, 67382), (67392, 67413), (67424, 67431), (67456, 67461), + (67463, 67504), (67506, 67519), (67584, 67589), (67592, 67592), + (67594, 67637), (67639, 67640), (67644, 67644), (67647, 67669), + (67680, 67702), (67712, 67742), (67808, 67826), (67828, 67829), + (67840, 67861), (67872, 67897), (67904, 67929), (67968, 68023), + (68030, 68031), (68096, 68099), (68101, 68102), (68108, 68115), + (68117, 68119), (68121, 68149), (68152, 68154), (68159, 68159), + (68192, 68220), (68224, 68252), (68288, 68295), (68297, 68326), + (68352, 68405), (68416, 68437), (68448, 68466), (68480, 68497), + (68608, 68680), (68736, 68786), (68800, 68850), (68864, 68903), + (68912, 68921), (68928, 68965), (68969, 68973), (68975, 68997), + (69248, 69289), (69291, 69292), (69296, 69297), (69314, 69319), + (69323, 69327), (69337, 69358), (69360, 69404), (69415, 69415), (69424, 69456), (69488, 69509), (69552, 69572), (69600, 69622), (69632, 69702), (69734, 69749), (69759, 69818), (69826, 69826), (69840, 69864), (69872, 69881), (69888, 69940), (69942, 69951), @@ -146,56 +147,58 @@ pub const XID_CONTINUE: &'static [(u32, u32)] = &[ (71991, 71992), (71995, 72003), (72016, 72025), (72096, 72103), (72106, 72151), (72154, 72161), (72163, 72164), (72192, 72254), (72263, 72263), (72272, 72345), (72349, 72349), (72368, 72440), - (72544, 72551), (72640, 72672), (72688, 72697), (72704, 72712), - (72714, 72758), (72760, 72768), (72784, 72793), (72818, 72847), - (72850, 72871), (72873, 72886), (72960, 72966), (72968, 72969), - (72971, 73014), (73018, 73018), (73020, 73021), (73023, 73031), - (73040, 73049), (73056, 73061), (73063, 73064), (73066, 73102), - (73104, 73105), (73107, 73112), (73120, 73129), (73136, 73179), - (73184, 73193), (73440, 73462), (73472, 73488), (73490, 73530), - (73534, 73538), (73552, 73562), (73648, 73648), (73728, 74649), - (74752, 74862), (74880, 75075), (77712, 77808), (77824, 78895), - (78912, 78933), (78944, 82938), (82944, 83526), (90368, 90425), - (92160, 92728), (92736, 92766), (92768, 92777), (92784, 92862), - (92864, 92873), (92880, 92909), (92912, 92916), (92928, 92982), - (92992, 92995), (93008, 93017), (93027, 93047), (93053, 93071), - (93504, 93548), (93552, 93561), (93760, 93823), (93856, 93880), - (93883, 93907), (93952, 94026), (94031, 94087), (94095, 94111), - (94176, 94177), (94179, 94180), (94192, 94198), (94208, 101589), - (101631, 101662), (101760, 101874), (110576, 110579), (110581, 110587), - (110589, 110590), (110592, 110882), (110898, 110898), (110928, 110930), - (110933, 110933), (110948, 110951), (110960, 111355), (113664, 113770), - (113776, 113788), (113792, 113800), (113808, 113817), (113821, 113822), - (118000, 118009), (118528, 118573), (118576, 118598), (119141, 119145), - (119149, 119154), (119163, 119170), (119173, 119179), (119210, 119213), - (119362, 119364), (119808, 119892), (119894, 119964), (119966, 119967), - (119970, 119970), (119973, 119974), (119977, 119980), (119982, 119993), - (119995, 119995), (119997, 120003), (120005, 120069), (120071, 120074), - (120077, 120084), (120086, 120092), (120094, 120121), (120123, 120126), - (120128, 120132), (120134, 120134), (120138, 120144), (120146, 120485), - (120488, 120512), (120514, 120538), (120540, 120570), (120572, 120596), - (120598, 120628), (120630, 120654), (120656, 120686), (120688, 120712), - (120714, 120744), (120746, 120770), (120772, 120779), (120782, 120831), - (121344, 121398), (121403, 121452), (121461, 121461), (121476, 121476), - (121499, 121503), (121505, 121519), (122624, 122654), (122661, 122666), - (122880, 122886), (122888, 122904), (122907, 122913), (122915, 122916), - (122918, 122922), (122928, 122989), (123023, 123023), (123136, 123180), - (123184, 123197), (123200, 123209), (123214, 123214), (123536, 123566), - (123584, 123641), (124112, 124153), (124368, 124410), (124608, 124638), - (124640, 124661), (124670, 124671), (124896, 124902), (124904, 124907), - (124909, 124910), (124912, 124926), (124928, 125124), (125136, 125142), - (125184, 125259), (125264, 125273), (126464, 126467), (126469, 126495), - (126497, 126498), (126500, 126500), (126503, 126503), (126505, 126514), - (126516, 126519), (126521, 126521), (126523, 126523), (126530, 126530), - (126535, 126535), (126537, 126537), (126539, 126539), (126541, 126543), - (126545, 126546), (126548, 126548), (126551, 126551), (126553, 126553), - (126555, 126555), (126557, 126557), (126559, 126559), (126561, 126562), - (126564, 126564), (126567, 126570), (126572, 126578), (126580, 126583), - (126585, 126588), (126590, 126590), (126592, 126601), (126603, 126619), - (126625, 126627), (126629, 126633), (126635, 126651), (130032, 130041), - (131072, 173791), (173824, 178205), (178208, 183981), (183984, 191456), - (191472, 192093), (194560, 195101), (196608, 201546), (201552, 210041), - (917760, 917999), + (72458, 72458), (72544, 72551), (72640, 72672), (72688, 72697), + (72704, 72712), (72714, 72758), (72760, 72768), (72784, 72793), + (72818, 72847), (72850, 72871), (72873, 72886), (72960, 72966), + (72968, 72969), (72971, 73014), (73018, 73018), (73020, 73021), + (73023, 73031), (73040, 73049), (73056, 73061), (73063, 73064), + (73066, 73102), (73104, 73105), (73107, 73112), (73120, 73129), + (73136, 73179), (73184, 73193), (73200, 73201), (73440, 73462), + (73472, 73488), (73490, 73530), (73534, 73538), (73552, 73562), + (73648, 73648), (73728, 74649), (74752, 74863), (74869, 75075), + (75088, 75398), (77712, 77808), (77824, 78895), (78912, 78933), + (78944, 82938), (82944, 83526), (90368, 90425), (92160, 92728), + (92736, 92766), (92768, 92777), (92784, 92862), (92864, 92873), + (92880, 92909), (92912, 92916), (92928, 92982), (92992, 92995), + (93008, 93017), (93027, 93047), (93053, 93071), (93504, 93548), + (93552, 93561), (93760, 93823), (93856, 93880), (93883, 93907), + (93952, 94026), (94031, 94087), (94095, 94111), (94176, 94177), + (94179, 94180), (94192, 94198), (94208, 101594), (101631, 101664), + (101760, 101874), (101888, 102801), (102816, 102866), (110576, 110579), + (110581, 110587), (110589, 110590), (110592, 110888), (110898, 110898), + (110928, 110930), (110933, 110933), (110948, 110952), (110960, 111355), + (113664, 113770), (113776, 113788), (113792, 113800), (113808, 113817), + (113821, 113822), (118000, 118009), (118528, 118573), (118576, 118598), + (119079, 119080), (119141, 119145), (119149, 119154), (119163, 119170), + (119173, 119179), (119210, 119213), (119362, 119364), (119376, 119378), + (119387, 119388), (119391, 119391), (119424, 119425), (119808, 119892), + (119894, 119964), (119966, 119967), (119970, 119970), (119973, 119974), + (119977, 119980), (119982, 119993), (119995, 119995), (119997, 120003), + (120005, 120069), (120071, 120074), (120077, 120084), (120086, 120092), + (120094, 120121), (120123, 120126), (120128, 120132), (120134, 120134), + (120138, 120144), (120146, 120486), (120488, 120512), (120514, 120538), + (120540, 120570), (120572, 120596), (120598, 120628), (120630, 120654), + (120656, 120686), (120688, 120712), (120714, 120744), (120746, 120770), + (120772, 120779), (120782, 120831), (121344, 121398), (121403, 121452), + (121461, 121461), (121476, 121476), (121499, 121503), (121505, 121519), + (122624, 122753), (122768, 122774), (122829, 122886), (122888, 122904), + (122907, 122913), (122915, 122916), (122918, 122922), (122928, 122989), + (123023, 123023), (123136, 123180), (123184, 123197), (123200, 123209), + (123214, 123214), (123536, 123566), (123584, 123641), (124112, 124153), + (124368, 124410), (124608, 124638), (124640, 124661), (124670, 124671), + (124896, 124902), (124904, 124907), (124909, 124910), (124912, 124926), + (124928, 125124), (125136, 125142), (125184, 125259), (125264, 125273), + (126464, 126467), (126469, 126495), (126497, 126498), (126500, 126500), + (126503, 126503), (126505, 126514), (126516, 126519), (126521, 126521), + (126523, 126523), (126530, 126530), (126535, 126535), (126537, 126537), + (126539, 126539), (126541, 126543), (126545, 126546), (126548, 126548), + (126551, 126551), (126553, 126553), (126555, 126555), (126557, 126557), + (126559, 126559), (126561, 126562), (126564, 126564), (126567, 126570), + (126572, 126578), (126580, 126583), (126585, 126588), (126590, 126590), + (126592, 126601), (126603, 126619), (126625, 126627), (126629, 126633), + (126635, 126651), (130032, 130041), (131072, 173791), (173824, 178206), + (178208, 183981), (183984, 191456), (191472, 192093), (194560, 195101), + (196608, 201546), (201552, 210041), (249856, 261183), (917760, 917999), ]; pub const XID_START: &'static [(u32, u32)] = &[ @@ -203,102 +206,103 @@ pub const XID_START: &'static [(u32, u32)] = &[ (216, 246), (248, 705), (710, 721), (736, 740), (748, 748), (750, 750), (880, 884), (886, 887), (891, 893), (895, 895), (902, 902), (904, 906), (908, 908), (910, 929), (931, 1013), (1015, 1153), (1162, 1327), - (1329, 1366), (1369, 1369), (1376, 1416), (1488, 1514), (1519, 1522), - (1568, 1610), (1646, 1647), (1649, 1747), (1749, 1749), (1765, 1766), - (1774, 1775), (1786, 1788), (1791, 1791), (1808, 1808), (1810, 1839), - (1869, 1957), (1969, 1969), (1994, 2026), (2036, 2037), (2042, 2042), - (2048, 2069), (2074, 2074), (2084, 2084), (2088, 2088), (2112, 2136), - (2144, 2154), (2160, 2183), (2185, 2191), (2208, 2249), (2308, 2361), - (2365, 2365), (2384, 2384), (2392, 2401), (2417, 2432), (2437, 2444), - (2447, 2448), (2451, 2472), (2474, 2480), (2482, 2482), (2486, 2489), - (2493, 2493), (2510, 2510), (2524, 2525), (2527, 2529), (2544, 2545), - (2556, 2556), (2565, 2570), (2575, 2576), (2579, 2600), (2602, 2608), - (2610, 2611), (2613, 2614), (2616, 2617), (2649, 2652), (2654, 2654), - (2674, 2676), (2693, 2701), (2703, 2705), (2707, 2728), (2730, 2736), - (2738, 2739), (2741, 2745), (2749, 2749), (2768, 2768), (2784, 2785), - (2809, 2809), (2821, 2828), (2831, 2832), (2835, 2856), (2858, 2864), - (2866, 2867), (2869, 2873), (2877, 2877), (2908, 2909), (2911, 2913), - (2929, 2929), (2947, 2947), (2949, 2954), (2958, 2960), (2962, 2965), - (2969, 2970), (2972, 2972), (2974, 2975), (2979, 2980), (2984, 2986), - (2990, 3001), (3024, 3024), (3077, 3084), (3086, 3088), (3090, 3112), - (3114, 3129), (3133, 3133), (3160, 3162), (3164, 3165), (3168, 3169), - (3200, 3200), (3205, 3212), (3214, 3216), (3218, 3240), (3242, 3251), - (3253, 3257), (3261, 3261), (3292, 3294), (3296, 3297), (3313, 3314), - (3332, 3340), (3342, 3344), (3346, 3386), (3389, 3389), (3406, 3406), - (3412, 3414), (3423, 3425), (3450, 3455), (3461, 3478), (3482, 3505), - (3507, 3515), (3517, 3517), (3520, 3526), (3585, 3632), (3634, 3634), - (3648, 3654), (3713, 3714), (3716, 3716), (3718, 3722), (3724, 3747), - (3749, 3749), (3751, 3760), (3762, 3762), (3773, 3773), (3776, 3780), - (3782, 3782), (3804, 3807), (3840, 3840), (3904, 3911), (3913, 3948), - (3976, 3980), (4096, 4138), (4159, 4159), (4176, 4181), (4186, 4189), - (4193, 4193), (4197, 4198), (4206, 4208), (4213, 4225), (4238, 4238), - (4256, 4293), (4295, 4295), (4301, 4301), (4304, 4346), (4348, 4680), - (4682, 4685), (4688, 4694), (4696, 4696), (4698, 4701), (4704, 4744), - (4746, 4749), (4752, 4784), (4786, 4789), (4792, 4798), (4800, 4800), - (4802, 4805), (4808, 4822), (4824, 4880), (4882, 4885), (4888, 4954), - (4992, 5007), (5024, 5109), (5112, 5117), (5121, 5740), (5743, 5759), - (5761, 5786), (5792, 5866), (5870, 5880), (5888, 5905), (5919, 5937), - (5952, 5969), (5984, 5996), (5998, 6000), (6016, 6067), (6103, 6103), - (6108, 6108), (6176, 6264), (6272, 6312), (6314, 6314), (6320, 6389), - (6400, 6430), (6480, 6509), (6512, 6516), (6528, 6571), (6576, 6601), - (6656, 6678), (6688, 6740), (6823, 6823), (6917, 6963), (6981, 6988), - (7043, 7072), (7086, 7087), (7098, 7141), (7168, 7203), (7245, 7247), - (7258, 7293), (7296, 7306), (7312, 7354), (7357, 7359), (7401, 7404), - (7406, 7411), (7413, 7414), (7418, 7418), (7424, 7615), (7680, 7957), - (7960, 7965), (7968, 8005), (8008, 8013), (8016, 8023), (8025, 8025), - (8027, 8027), (8029, 8029), (8031, 8061), (8064, 8116), (8118, 8124), - (8126, 8126), (8130, 8132), (8134, 8140), (8144, 8147), (8150, 8155), - (8160, 8172), (8178, 8180), (8182, 8188), (8305, 8305), (8319, 8319), - (8336, 8348), (8450, 8450), (8455, 8455), (8458, 8467), (8469, 8469), - (8472, 8477), (8484, 8484), (8486, 8486), (8488, 8488), (8490, 8505), - (8508, 8511), (8517, 8521), (8526, 8526), (8544, 8584), (11264, 11492), - (11499, 11502), (11506, 11507), (11520, 11557), (11559, 11559), - (11565, 11565), (11568, 11623), (11631, 11631), (11648, 11670), - (11680, 11686), (11688, 11694), (11696, 11702), (11704, 11710), - (11712, 11718), (11720, 11726), (11728, 11734), (11736, 11742), - (12293, 12295), (12321, 12329), (12337, 12341), (12344, 12348), - (12353, 12438), (12445, 12447), (12449, 12538), (12540, 12543), - (12549, 12591), (12593, 12686), (12704, 12735), (12784, 12799), - (13312, 19903), (19968, 42124), (42192, 42237), (42240, 42508), - (42512, 42527), (42538, 42539), (42560, 42606), (42623, 42653), - (42656, 42735), (42775, 42783), (42786, 42888), (42891, 42972), - (42993, 43009), (43011, 43013), (43015, 43018), (43020, 43042), - (43072, 43123), (43138, 43187), (43250, 43255), (43259, 43259), - (43261, 43262), (43274, 43301), (43312, 43334), (43360, 43388), - (43396, 43442), (43471, 43471), (43488, 43492), (43494, 43503), - (43514, 43518), (43520, 43560), (43584, 43586), (43588, 43595), - (43616, 43638), (43642, 43642), (43646, 43695), (43697, 43697), - (43701, 43702), (43705, 43709), (43712, 43712), (43714, 43714), - (43739, 43741), (43744, 43754), (43762, 43764), (43777, 43782), - (43785, 43790), (43793, 43798), (43808, 43814), (43816, 43822), - (43824, 43866), (43868, 43881), (43888, 44002), (44032, 55203), - (55216, 55238), (55243, 55291), (63744, 64109), (64112, 64217), - (64256, 64262), (64275, 64279), (64285, 64285), (64287, 64296), - (64298, 64310), (64312, 64316), (64318, 64318), (64320, 64321), - (64323, 64324), (64326, 64433), (64467, 64605), (64612, 64829), - (64848, 64911), (64914, 64967), (65008, 65017), (65137, 65137), - (65139, 65139), (65143, 65143), (65145, 65145), (65147, 65147), - (65149, 65149), (65151, 65276), (65313, 65338), (65345, 65370), - (65382, 65437), (65440, 65470), (65474, 65479), (65482, 65487), - (65490, 65495), (65498, 65500), (65536, 65547), (65549, 65574), - (65576, 65594), (65596, 65597), (65599, 65613), (65616, 65629), - (65664, 65786), (65856, 65908), (66176, 66204), (66208, 66256), - (66304, 66335), (66349, 66378), (66384, 66421), (66432, 66461), - (66464, 66499), (66504, 66511), (66513, 66517), (66560, 66717), - (66736, 66771), (66776, 66811), (66816, 66855), (66864, 66915), - (66928, 66938), (66940, 66954), (66956, 66962), (66964, 66965), - (66967, 66977), (66979, 66993), (66995, 67001), (67003, 67004), - (67008, 67059), (67072, 67382), (67392, 67413), (67424, 67431), - (67456, 67461), (67463, 67504), (67506, 67514), (67584, 67589), - (67592, 67592), (67594, 67637), (67639, 67640), (67644, 67644), - (67647, 67669), (67680, 67702), (67712, 67742), (67808, 67826), - (67828, 67829), (67840, 67861), (67872, 67897), (67904, 67929), - (67968, 68023), (68030, 68031), (68096, 68096), (68112, 68115), - (68117, 68119), (68121, 68149), (68192, 68220), (68224, 68252), - (68288, 68295), (68297, 68324), (68352, 68405), (68416, 68437), - (68448, 68466), (68480, 68497), (68608, 68680), (68736, 68786), - (68800, 68850), (68864, 68899), (68938, 68965), (68975, 68997), - (69248, 69289), (69296, 69297), (69314, 69319), (69376, 69404), + (1329, 1366), (1368, 1369), (1376, 1416), (1419, 1420), (1488, 1514), + (1519, 1522), (1568, 1610), (1646, 1647), (1649, 1747), (1749, 1749), + (1765, 1766), (1774, 1775), (1786, 1788), (1791, 1791), (1808, 1808), + (1810, 1839), (1869, 1957), (1969, 1969), (1994, 2026), (2036, 2037), + (2042, 2042), (2048, 2069), (2074, 2074), (2084, 2084), (2088, 2088), + (2112, 2136), (2144, 2154), (2160, 2183), (2185, 2191), (2208, 2249), + (2308, 2361), (2365, 2365), (2384, 2384), (2392, 2401), (2417, 2432), + (2437, 2444), (2447, 2448), (2451, 2472), (2474, 2480), (2482, 2482), + (2486, 2489), (2493, 2493), (2510, 2510), (2524, 2525), (2527, 2529), + (2544, 2545), (2556, 2556), (2565, 2570), (2575, 2576), (2579, 2600), + (2602, 2608), (2610, 2611), (2613, 2614), (2616, 2617), (2649, 2652), + (2654, 2654), (2674, 2676), (2693, 2701), (2703, 2705), (2707, 2728), + (2730, 2736), (2738, 2739), (2741, 2745), (2749, 2749), (2768, 2768), + (2784, 2785), (2809, 2809), (2821, 2828), (2831, 2832), (2835, 2856), + (2858, 2864), (2866, 2867), (2869, 2873), (2877, 2877), (2908, 2909), + (2911, 2913), (2929, 2929), (2947, 2947), (2949, 2954), (2958, 2960), + (2962, 2965), (2969, 2970), (2972, 2972), (2974, 2975), (2979, 2980), + (2984, 2986), (2990, 3001), (3024, 3024), (3077, 3084), (3086, 3088), + (3090, 3112), (3114, 3129), (3133, 3133), (3160, 3162), (3164, 3165), + (3168, 3169), (3200, 3200), (3205, 3212), (3214, 3216), (3218, 3240), + (3242, 3251), (3253, 3257), (3261, 3261), (3292, 3294), (3296, 3297), + (3313, 3314), (3332, 3340), (3342, 3344), (3346, 3386), (3389, 3389), + (3406, 3406), (3412, 3414), (3423, 3425), (3450, 3455), (3461, 3478), + (3482, 3505), (3507, 3515), (3517, 3517), (3520, 3526), (3585, 3632), + (3634, 3634), (3648, 3654), (3713, 3714), (3716, 3716), (3718, 3722), + (3724, 3747), (3749, 3749), (3751, 3760), (3762, 3762), (3773, 3773), + (3776, 3780), (3782, 3782), (3804, 3807), (3840, 3840), (3904, 3911), + (3913, 3948), (3976, 3980), (4096, 4138), (4159, 4159), (4176, 4181), + (4186, 4189), (4193, 4193), (4197, 4198), (4206, 4208), (4213, 4225), + (4238, 4238), (4256, 4293), (4295, 4295), (4301, 4301), (4304, 4346), + (4348, 4680), (4682, 4685), (4688, 4694), (4696, 4696), (4698, 4701), + (4704, 4744), (4746, 4749), (4752, 4784), (4786, 4789), (4792, 4798), + (4800, 4800), (4802, 4805), (4808, 4822), (4824, 4880), (4882, 4885), + (4888, 4954), (4992, 5007), (5024, 5109), (5112, 5117), (5121, 5740), + (5743, 5759), (5761, 5786), (5792, 5866), (5870, 5880), (5888, 5905), + (5919, 5937), (5952, 5969), (5984, 5996), (5998, 6000), (6016, 6067), + (6103, 6103), (6108, 6108), (6176, 6264), (6272, 6312), (6314, 6314), + (6320, 6389), (6400, 6430), (6480, 6509), (6512, 6516), (6528, 6571), + (6576, 6601), (6656, 6678), (6688, 6740), (6823, 6823), (6917, 6963), + (6981, 6988), (7043, 7072), (7086, 7087), (7098, 7141), (7168, 7203), + (7245, 7247), (7258, 7293), (7296, 7306), (7312, 7354), (7357, 7359), + (7401, 7404), (7406, 7411), (7413, 7414), (7418, 7418), (7424, 7615), + (7680, 7957), (7960, 7965), (7968, 8005), (8008, 8013), (8016, 8023), + (8025, 8025), (8027, 8027), (8029, 8029), (8031, 8061), (8064, 8116), + (8118, 8124), (8126, 8126), (8130, 8132), (8134, 8140), (8144, 8147), + (8150, 8155), (8160, 8172), (8178, 8180), (8182, 8188), (8305, 8305), + (8319, 8319), (8335, 8351), (8450, 8450), (8455, 8455), (8458, 8467), + (8469, 8469), (8472, 8477), (8484, 8484), (8486, 8486), (8488, 8488), + (8490, 8505), (8508, 8511), (8517, 8521), (8526, 8526), (8544, 8584), + (11264, 11492), (11499, 11502), (11506, 11507), (11520, 11557), + (11559, 11559), (11565, 11565), (11568, 11623), (11631, 11631), + (11648, 11670), (11680, 11686), (11688, 11694), (11696, 11702), + (11704, 11710), (11712, 11718), (11720, 11726), (11728, 11734), + (11736, 11742), (12293, 12295), (12321, 12329), (12337, 12341), + (12344, 12348), (12353, 12438), (12445, 12447), (12449, 12538), + (12540, 12543), (12549, 12591), (12593, 12686), (12704, 12735), + (12784, 12799), (13312, 19903), (19968, 42124), (42192, 42237), + (42240, 42508), (42512, 42527), (42538, 42539), (42560, 42606), + (42623, 42653), (42656, 42735), (42775, 42783), (42786, 42888), + (42891, 42973), (42978, 42978), (42993, 43009), (43011, 43013), + (43015, 43018), (43020, 43042), (43072, 43123), (43138, 43187), + (43250, 43255), (43259, 43259), (43261, 43262), (43274, 43301), + (43312, 43334), (43360, 43388), (43396, 43442), (43471, 43471), + (43488, 43492), (43494, 43503), (43514, 43518), (43520, 43560), + (43584, 43586), (43588, 43595), (43616, 43638), (43642, 43642), + (43646, 43695), (43697, 43697), (43701, 43702), (43705, 43709), + (43712, 43712), (43714, 43714), (43739, 43741), (43744, 43754), + (43762, 43764), (43777, 43782), (43785, 43790), (43793, 43798), + (43808, 43814), (43816, 43822), (43824, 43866), (43868, 43881), + (43884, 43885), (43888, 44002), (44032, 55203), (55216, 55238), + (55243, 55291), (63744, 64109), (64112, 64217), (64256, 64262), + (64275, 64279), (64285, 64285), (64287, 64296), (64298, 64310), + (64312, 64316), (64318, 64318), (64320, 64321), (64323, 64324), + (64326, 64433), (64467, 64605), (64612, 64829), (64848, 64911), + (64914, 64967), (65008, 65017), (65137, 65137), (65139, 65139), + (65143, 65143), (65145, 65145), (65147, 65147), (65149, 65149), + (65151, 65276), (65313, 65338), (65345, 65370), (65382, 65437), + (65440, 65470), (65474, 65479), (65482, 65487), (65490, 65495), + (65498, 65500), (65536, 65547), (65549, 65574), (65576, 65594), + (65596, 65597), (65599, 65613), (65616, 65629), (65664, 65786), + (65856, 65908), (66176, 66204), (66208, 66256), (66304, 66335), + (66349, 66378), (66384, 66421), (66432, 66461), (66464, 66499), + (66504, 66511), (66513, 66517), (66560, 66717), (66736, 66771), + (66776, 66811), (66816, 66855), (66864, 66915), (66928, 66938), + (66940, 66954), (66956, 66962), (66964, 66965), (66967, 66977), + (66979, 66993), (66995, 67001), (67003, 67004), (67008, 67059), + (67072, 67382), (67392, 67413), (67424, 67431), (67456, 67461), + (67463, 67504), (67506, 67519), (67584, 67589), (67592, 67592), + (67594, 67637), (67639, 67640), (67644, 67644), (67647, 67669), + (67680, 67702), (67712, 67742), (67808, 67826), (67828, 67829), + (67840, 67861), (67872, 67897), (67904, 67929), (67968, 68023), + (68030, 68031), (68096, 68096), (68112, 68115), (68117, 68119), + (68121, 68149), (68192, 68220), (68224, 68252), (68288, 68295), + (68297, 68324), (68352, 68405), (68416, 68437), (68448, 68466), + (68480, 68497), (68608, 68680), (68736, 68786), (68800, 68850), + (68864, 68899), (68938, 68965), (68975, 68997), (69248, 69289), + (69296, 69297), (69314, 69319), (69337, 69358), (69376, 69404), (69415, 69415), (69424, 69445), (69488, 69505), (69552, 69572), (69600, 69622), (69635, 69687), (69745, 69746), (69749, 69749), (69763, 69807), (69840, 69864), (69891, 69926), (69956, 69956), @@ -318,44 +322,46 @@ pub const XID_START: &'static [(u32, u32)] = &[ (71960, 71983), (71999, 71999), (72001, 72001), (72096, 72103), (72106, 72144), (72161, 72161), (72163, 72163), (72192, 72192), (72203, 72242), (72250, 72250), (72272, 72272), (72284, 72329), - (72349, 72349), (72368, 72440), (72640, 72672), (72704, 72712), - (72714, 72750), (72768, 72768), (72818, 72847), (72960, 72966), - (72968, 72969), (72971, 73008), (73030, 73030), (73056, 73061), - (73063, 73064), (73066, 73097), (73112, 73112), (73136, 73179), - (73440, 73458), (73474, 73474), (73476, 73488), (73490, 73523), - (73648, 73648), (73728, 74649), (74752, 74862), (74880, 75075), - (77712, 77808), (77824, 78895), (78913, 78918), (78944, 82938), - (82944, 83526), (90368, 90397), (92160, 92728), (92736, 92766), - (92784, 92862), (92880, 92909), (92928, 92975), (92992, 92995), - (93027, 93047), (93053, 93071), (93504, 93548), (93760, 93823), - (93856, 93880), (93883, 93907), (93952, 94026), (94032, 94032), - (94099, 94111), (94176, 94177), (94179, 94179), (94194, 94198), - (94208, 101589), (101631, 101662), (101760, 101874), (110576, 110579), - (110581, 110587), (110589, 110590), (110592, 110882), (110898, 110898), - (110928, 110930), (110933, 110933), (110948, 110951), (110960, 111355), - (113664, 113770), (113776, 113788), (113792, 113800), (113808, 113817), - (119808, 119892), (119894, 119964), (119966, 119967), (119970, 119970), - (119973, 119974), (119977, 119980), (119982, 119993), (119995, 119995), - (119997, 120003), (120005, 120069), (120071, 120074), (120077, 120084), - (120086, 120092), (120094, 120121), (120123, 120126), (120128, 120132), - (120134, 120134), (120138, 120144), (120146, 120485), (120488, 120512), - (120514, 120538), (120540, 120570), (120572, 120596), (120598, 120628), - (120630, 120654), (120656, 120686), (120688, 120712), (120714, 120744), - (120746, 120770), (120772, 120779), (122624, 122654), (122661, 122666), - (122928, 122989), (123136, 123180), (123191, 123197), (123214, 123214), - (123536, 123565), (123584, 123627), (124112, 124139), (124368, 124397), - (124400, 124400), (124608, 124638), (124640, 124642), (124644, 124645), - (124647, 124653), (124656, 124660), (124670, 124671), (124896, 124902), - (124904, 124907), (124909, 124910), (124912, 124926), (124928, 125124), - (125184, 125251), (125259, 125259), (126464, 126467), (126469, 126495), - (126497, 126498), (126500, 126500), (126503, 126503), (126505, 126514), - (126516, 126519), (126521, 126521), (126523, 126523), (126530, 126530), - (126535, 126535), (126537, 126537), (126539, 126539), (126541, 126543), - (126545, 126546), (126548, 126548), (126551, 126551), (126553, 126553), - (126555, 126555), (126557, 126557), (126559, 126559), (126561, 126562), - (126564, 126564), (126567, 126570), (126572, 126578), (126580, 126583), - (126585, 126588), (126590, 126590), (126592, 126601), (126603, 126619), - (126625, 126627), (126629, 126633), (126635, 126651), (131072, 173791), - (173824, 178205), (178208, 183981), (183984, 191456), (191472, 192093), - (194560, 195101), (196608, 201546), (201552, 210041), + (72349, 72349), (72368, 72440), (72458, 72458), (72640, 72672), + (72704, 72712), (72714, 72750), (72768, 72768), (72818, 72847), + (72960, 72966), (72968, 72969), (72971, 73008), (73030, 73030), + (73056, 73061), (73063, 73064), (73066, 73097), (73112, 73112), + (73136, 73179), (73201, 73201), (73440, 73458), (73474, 73474), + (73476, 73488), (73490, 73523), (73648, 73648), (73728, 74649), + (74752, 74863), (74869, 75075), (75088, 75398), (77712, 77808), + (77824, 78895), (78913, 78918), (78944, 82938), (82944, 83526), + (90368, 90397), (92160, 92728), (92736, 92766), (92784, 92862), + (92880, 92909), (92928, 92975), (92992, 92995), (93027, 93047), + (93053, 93071), (93504, 93548), (93760, 93823), (93856, 93880), + (93883, 93907), (93952, 94026), (94032, 94032), (94099, 94111), + (94176, 94177), (94179, 94179), (94194, 94198), (94208, 101594), + (101631, 101664), (101760, 101874), (101888, 102801), (102816, 102866), + (110576, 110579), (110581, 110587), (110589, 110590), (110592, 110888), + (110898, 110898), (110928, 110930), (110933, 110933), (110948, 110952), + (110960, 111355), (113664, 113770), (113776, 113788), (113792, 113800), + (113808, 113817), (119808, 119892), (119894, 119964), (119966, 119967), + (119970, 119970), (119973, 119974), (119977, 119980), (119982, 119993), + (119995, 119995), (119997, 120003), (120005, 120069), (120071, 120074), + (120077, 120084), (120086, 120092), (120094, 120121), (120123, 120126), + (120128, 120132), (120134, 120134), (120138, 120144), (120146, 120486), + (120488, 120512), (120514, 120538), (120540, 120570), (120572, 120596), + (120598, 120628), (120630, 120654), (120656, 120686), (120688, 120712), + (120714, 120744), (120746, 120770), (120772, 120779), (122624, 122753), + (122768, 122774), (122829, 122879), (122928, 122989), (123136, 123180), + (123191, 123197), (123214, 123214), (123536, 123565), (123584, 123627), + (124112, 124139), (124368, 124397), (124400, 124400), (124608, 124638), + (124640, 124642), (124644, 124645), (124647, 124653), (124656, 124660), + (124670, 124671), (124896, 124902), (124904, 124907), (124909, 124910), + (124912, 124926), (124928, 125124), (125184, 125251), (125259, 125259), + (126464, 126467), (126469, 126495), (126497, 126498), (126500, 126500), + (126503, 126503), (126505, 126514), (126516, 126519), (126521, 126521), + (126523, 126523), (126530, 126530), (126535, 126535), (126537, 126537), + (126539, 126539), (126541, 126543), (126545, 126546), (126548, 126548), + (126551, 126551), (126553, 126553), (126555, 126555), (126557, 126557), + (126559, 126559), (126561, 126562), (126564, 126564), (126567, 126570), + (126572, 126578), (126580, 126583), (126585, 126588), (126590, 126590), + (126592, 126601), (126603, 126619), (126625, 126627), (126629, 126633), + (126635, 126651), (131072, 173791), (173824, 178206), (178208, 183981), + (183984, 191456), (191472, 192093), (194560, 195101), (196608, 201546), + (201552, 210041), (249856, 261183), ]; diff --git a/deps/crates/vendor/unicode-ident-v1/tests/trie/trie.rs b/deps/crates/vendor/unicode-ident-v1/tests/trie/trie.rs index 0cca9ecce648..c385bc855491 100644 --- a/deps/crates/vendor/unicode-ident-v1/tests/trie/trie.rs +++ b/deps/crates/vendor/unicode-ident-v1/tests/trie/trie.rs @@ -2,7 +2,7 @@ // // ucd-generate property-bool UCD --include XID_Start,XID_Continue --trie-set // -// Unicode version: 17.0.0. +// Unicode version: 18.0.0. // // ucd-generate 0.3.1 is available on crates.io. @@ -19,7 +19,7 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFFFFFFFFFFFFFFFF, 0xB8DFFFFFFFFFFFFF, 0xFFFFFFFBFFFFD7C0, 0xFFBFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFCFB, 0xFFFFFFFFFFFFFFFF, 0xFFFEFFFFFFFFFFFF, - 0xFFFFFFFF027FFFFF, 0xBFFFFFFFFFFE01FF, 0x787FFFFFF00B6, + 0xFFFFFFFF037FFFFF, 0xBFFFFFFFFFFE19FF, 0x787FFFFFF03B6, 0xFFFFFFFF07FF0000, 0xFFFFC3FFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x9FFFFDFF9FEFFFFF, 0xFFFFFFFFFFFF0000, 0xFFFFFFFFFFFFE7FF, 0x3FFFFFFFFFFFF, 0x243FFFFFFFFFFFFF, @@ -76,7 +76,7 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFFFFFFFBFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFEFFCFFFFFFFFF, 0xF3C5FDFFFFF99FEF, 0x5003FFCFB080799F, 0xD36DFDFFFFF987EE, 0x3FFFC05E023987, 0xF3EDFDFFFFFBBFEE, 0xFE00FFCF00013BBF, - 0xF3EDFDFFFFF99FEE, 0x2FFCFB0E0399F, 0xC3FFC718D63DC7EC, 0xFFC000813DC7, + 0xF3EDFDFFFFF99FEE, 0x2FFCFB0F8399F, 0xC3FFC718D63DC7EC, 0xFFC000813DC7, 0xF3FFFDFFFFFDDFFF, 0xFFCF37603DDF, 0xF3EFFDFFFFFDDFEF, 0xEFFCF70603DDF, 0xFFFFFFFFFFFDDFFF, 0xFC00FFCF80F07DDF, 0x2FFBFFFFFC7FFFEE, 0xCFFC0FF5F847F, 0x7FFFFFFFFFFFFFE, 0x3FF7FFF, 0x3FFFFFAFFFFFF7D6, @@ -89,20 +89,20 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0x3FF308FFFFF, 0xFFFFFFFF03FFB800, 0x1FFFFFFFFFFFFFF, 0xFFFF07FFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0xFFF0FFF7FFFFFFF, 0x1F3FFFFFFFFFC0, 0xFFFF0FFFFFFFFFFF, 0x7FF03FF, 0xFFFFFFFF0FFFFFFF, 0x9FFFFFFF7FFFFFFF, 0xBFFF008003FF03FF, - 0xFFF3FFFFFFF, 0xFF80003FF1FFF, 0xFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF, + 0x1FFFFFFFFFFFF, 0xFF80003FF1FFF, 0xFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFE3FF, 0xE7FFFFFFFFFF07FF, 0x7FFFFFFFFF70000, 0xFFFFFFFF3F3FFFFF, 0x3FFFFFFFAAFF3F3F, 0x5FDFFFFFFFFFFFFF, - 0x1FDC1FFF0FCF1FDC, 0x8000000000003000, 0x8002000000100001, 0x1FFF0000, + 0x1FDC1FFF0FCF1FDC, 0x8000000000003000, 0x8002000000100001, 0xFFFF8000, 0x1FFE21FFF0000, 0xF3FFFD503F2FFC84, 0xFFFFFFFF000043E0, 0x1FF, 0, 0xFF81FFFFFFFFF, 0xFFFF20BFFFFFFFFF, 0x800080FFFFFFFFFF, 0x7F7F7F7F007FFFFF, 0xFFFFFFFF7F7F7F7F, 0x1F3EFFFE000000E0, 0xFFFFFFFEE67FFFFF, 0xFFFEFFFFFFFFFFE0, 0xFFFFFFFF00007FFF, 0xFFFF000000000000, 0x1FFF, 0x3FFFFFFFFFFF0000, 0xFFFFFFF1FFF, 0xBFF0FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0xFFFFFFFCFF800000, - 0xFFFFFFFFFFFFF9FF, 0xFFFE00001FFFFFFF, 0x10FFFFFFFFFF, + 0xFFFFFFFFFFFFF9FF, 0xFFFE00043FFFFFFF, 0x10FFFFFFFFFF, 0xE8FFFFFF03FF003F, 0xFFFF3FFFFFFFFFFF, 0x1FFFFFFF000FFFFF, 0x7FFFFFFF03FF8001, 0x7FFFFFFFFFFFFF, 0xFC7FFFFF03FF3FFF, - 0x7CFFFF38000007, 0xFFFF7F7F007E7E7E, 0xFFFF03FFF7FFFFFF, + 0x7CFFFF38000007, 0xFFFF7F7F007E7E7E, 0xFFFF33FFF7FFFFFF, 0x3FF37FFFFFFFFFF, 0xFFFF000FFFFFFFFF, 0xFFFFFFFFFFFF87F, 0x3FFFFFF, 0x5F7FFDFFE0F8007F, 0xFFFFFFFFFFFFFFDB, 0xFFFFFFFFFFF80000, 0xFFFFFFF03FFFFFFF, 0x3FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFF0000, @@ -111,17 +111,17 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFFFFFFE007FFFFFE, 0x7FFFFFFFFFFFFFFF, 0x1CFCFCFC, ], tree3_level1: &[ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 9, 10, 11, 12, 13, 14, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 15, 16, 17, 7, 18, 19, 7, 20, 7, 21, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 16, 17, 18, 7, 19, 20, 7, 21, 7, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 7, 7, 23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, ], tree3_level2: &[ 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, @@ -129,11 +129,11 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 31, 32, 33, 34, 35, 4, 2, 36, 37, 37, 38, 39, 40, 4, 4, 4, 41, 42, 43, 44, 45, 46, 2, 47, 3, 48, 49, 50, 2, 51, 52, 53, 54, 55, 56, 57, 58, 59, 2, 60, 2, 61, 4, 4, 62, 63, 2, 64, 65, 66, 67, 68, 4, 4, 3, 4, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 65, 4, 78, 4, 79, 80, 81, 82, 4, 83, 84, 85, 86, - 4, 4, 4, 87, 88, 89, 90, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 27, - 4, 2, 91, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 93, - 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 96, 2, 2, 2, 2, 2, + 72, 73, 74, 75, 76, 77, 65, 78, 79, 4, 80, 81, 82, 83, 4, 84, 85, 86, 87, + 4, 4, 4, 88, 89, 90, 91, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 27, + 4, 2, 92, 2, 2, 2, 93, 2, 2, 2, 2, 68, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 94, + 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 4, 4, 4, 4, 4, 4, @@ -141,52 +141,57 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 97, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 65, 98, 75, 99, 19, 100, 101, 4, 4, 4, - 4, 4, 4, 102, 4, 4, 4, 2, 103, 104, 2, 105, 106, 107, 2, 2, 2, 2, 2, 2, 2, + 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 65, 99, 75, 100, 19, 101, 102, 4, 4, + 4, 4, 4, 4, 103, 4, 4, 4, 2, 104, 105, 2, 106, 107, 108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 108, 24, 4, 2, 37, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 109, 110, 4, 2, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 111, 112, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 109, 2, 2, 2, 2, 110, 111, 2, 2, 2, 2, 2, - 112, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 113, 114, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 115, 4, 4, 4, 4, 4, 4, 4, 4, 116, 68, 4, 4, 4, 4, 4, - 4, 4, 117, 118, 4, 4, 119, 4, 4, 4, 4, 4, 4, 2, 120, 121, 122, 123, 124, - 2, 2, 2, 2, 125, 126, 127, 128, 129, 130, 4, 4, 4, 4, 4, 4, 4, 4, 131, - 132, 133, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 134, 4, 4, 4, - 135, 136, 137, 4, 138, 139, 4, 4, 4, 4, 140, 97, 4, 4, 4, 4, 4, 4, 4, 141, - 4, 4, 4, 142, 4, 4, 4, 143, 4, 4, 4, 144, 2, 2, 2, 145, 2, 146, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 147, 148, 149, 4, 4, 4, 4, 4, + 4, 4, 4, 113, 2, 2, 2, 2, 114, 115, 2, 2, 2, 2, 2, 116, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 115, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 150, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 2, 117, 118, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 119, 4, 4, 4, 4, 4, 4, 4, 4, 120, 68, 4, 4, 4, 4, 4, 4, 121, 122, 123, 4, + 4, 124, 53, 4, 4, 4, 4, 4, 2, 125, 126, 127, 128, 129, 2, 2, 2, 2, 130, + 131, 132, 133, 134, 135, 4, 4, 4, 4, 4, 4, 4, 4, 136, 137, 138, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 139, 140, 141, 142, 143, + 4, 144, 145, 4, 4, 4, 4, 146, 98, 4, 4, 4, 4, 4, 4, 4, 147, 4, 4, 4, 148, + 4, 4, 4, 149, 4, 4, 4, 150, 2, 2, 2, 151, 2, 152, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 153, 154, 155, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 119, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 156, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 157, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 120, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 116, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 151, 2, 2, 2, 2, 2, 2, 2, 2, 2, 152, 4, 4, 4, 4, 4, + 2, 2, 158, 2, 2, 2, 2, 2, 2, 2, 2, 2, 159, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 152, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 153, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 159, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 160, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 2, 2, 2, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ], tree3_level3: &[ 0xB7FFFF7FFFFFEFFF, 0x3FFF3FFF, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0, @@ -194,12 +199,12 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFFFFE000FFFFFFFF, 0x7FFFFFFFFFF07FF, 0xFFFFFFFF3FFFFFFF, 0x3EFF0F, 0xFFFF03FF3FFFFFFF, 0xFFFFFFFFF0FFFFF, 0xFFFF00FFFFFFFFFF, 0xF7FF000FFFFFFFFF, 0x1BFBFFFBFFB7F7FF, 0xFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, - 0xFF003FFFFF, 0x7FDFFFFFFFFFFBF, 0x91BFFFFFFFFFFD3F, 0x7FFFFF003FFFFF, + 0xFF003FFFFF, 0xFFFDFFFFFFFFFFBF, 0x91BFFFFFFFFFFD3F, 0x7FFFFF003FFFFF, 0x7FFFFFFF, 0x37FFFF00000000, 0x3FFFFFF003FFFFF, 0x3FFFFFF, 0xC0FFFFFFFFFFFFFF, 0x873FFFFFFEEFF06F, 0x1FFFFFFF00000000, 0x1FFFFFFF, 0x7FFFFFFEFF, 0x3FFFFFFFFFFFFF, 0x7FFFF003FFFFF, 0x3FFFF, 0x1FF, 0x7FFFFFFFFFFFF, 0x3FF00FFFFFFFFFF, 0xFFFFBE3FFFFFFFFF, 0x3F, - 0x31BFFFFFFFFFF, 0xFC000000000000FC, 0xFFFF00801FFFFFFF, + 0x31BFFFFFFFFFF, 0xFFFF7FFFFE00F8FC, 0xFFFF00801FFFFFFF, 0xFFFF00000001FFFF, 0xFFFF00000000003F, 0x7FFFFF0000001F, 0x803FFFC00000007F, 0x3FF01FFFFFF0004, 0xFFDFFFFFFFFFFFFF, 0x4FFFFFFFFF00F0, 0x17FFDE1F, 0xC0FFFFFFFFFBFFFF, 0x3, 0xFFFF01FFBFFFBD7F, @@ -208,27 +213,29 @@ pub const XID_CONTINUE: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFF3FFFFFFFFFFFFF, 0x3F000001, 0x3FF0011, 0x1FFFFFFFFFFFFFF, 0xFFFFF03FF, 0x3FF0FFFE7FFFFFF, 0x7F, 0xFFFFFFFF00000000, 0x800003FFFFFFFFFF, 0xF9BFFFFFFF6FF27F, 0x3FF000F, 0xFFFFFCFF00000000, 0x1BFCFFFFFF, - 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFF0080, 0xFFFF000023FFFFFF, 0xFF00000000, - 0x3FF0001FFFFFFFF, 0xFF7FFFFFFFFFFDFF, 0xFFFC000003FF0001, + 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFF0080, 0xFFFF000023FFFFFF, 0x400, + 0xFF00000000, 0x3FF0001FFFFFFFF, 0xFF7FFFFFFFFFFDFF, 0xFFFC000003FF0001, 0x7FFEFFFFFCFFFF, 0xB47FFFFFFFFFFB7F, 0xFFFFFDBF03FF00FF, - 0xFFFF03FF01FB7FFF, 0x3FF0FFFFFFF, 0x7FFFFF00000000, 0xC7FFFFFFFFFDFFFF, - 0x7FF0007, 0x1000000000000, 0x7FFFFFFFFFFF, 0xF, 0xFFFFFFFFFFFF0000, - 0x1FFFFFFFFFFFF, 0xFFFFFFFFFFFF, 0xFFFFFFFF003FFFFF, 0x3FFFFFFFFFFFFFF, - 0xFFFF03FF7FFFFFFF, 0x1F3FFFFFFF03FF, 0xE0FFFFF803FF000F, 0xFFFF, - 0x3FF1FFFFFFFFFFF, 0xF9FFFFFF00000000, 0xFFFFF, 0xFFFFFFFFFFFF87FF, - 0xFFFF80FF, 0x7F001B00000000, 0x80000000003FFFFF, 0x6FEF000000000000, - 0x40007FFFFFFFF, 0xFFFF00F000270000, 0xFFFFFFFFFFFFFFF, - 0x1FFF07FFFFFFFFFF, 0x63FF01FF, 0x3FF000000000000, 0xFFFF3FFFFFFFFFFF, - 0xF807E3E000000000, 0x3C0000000FE7, 0x1C, 0xFFFFFFFFFFDFFFFF, - 0xEBFFDE64DFFFFFFF, 0xFFFFFFFFFFFFFFEF, 0x7BFFFFFFDFDFE7BF, - 0xFFFFFFFFFFFDFC5F, 0xFFFFFF3FFFFFFFFF, 0xF7FFFFFFF7FFFFFD, - 0xFFDFFFFFFFDFFFFF, 0xFFFF7FFFFFFF7FFF, 0xFFFFFDFFFFFFFDFF, - 0xFFFFFFFFFFFFCFF7, 0xF87FFFFFFFFFFFFF, 0x201FFFFFFFFFFF, 0xFFFEF8000010, - 0x7E07FFFFFFF, 0xFFFF07DBF9FFFF7F, 0x3FFFFFFFFFFF, 0x8000, - 0x3FFF1FFFFFFFFFFF, 0x43FF, 0x7FFFFFFF0000, 0x3FFFFFFFFFF0000, - 0x7FFFFFFFFFF0000, 0xC03FFFFF7FFFFFFF, 0x7FFF6F7F00000000, 0x7F001F, - 0x3FF0FFF, 0xAF7FE96FFFFFFEF, 0x5EF7F796AA96EA84, 0xFFFFBEE0FFFFBFF, - 0xFFFFFFFF, 0xFFFF0001FFFFFFFF, 0x3FFFFFFF, 0xFFFFFFFFFFFF07FF, + 0xFFFF03FF01FB7FFF, 0x303FF0FFFFFFF, 0x7FFFFF00000000, 0xC7FFFFFFFFFDFFFF, + 0x7FF0007, 0x1000000000000, 0xFFE0FFFFFFFFFFFF, 0xFFFFFFFFFFFF000F, + 0xFFFFFFFFFFFF0000, 0x1FFFFFFFFFFFF, 0xFFFFFFFFFFFF, 0xFFFFFFFF003FFFFF, + 0x3FFFFFFFFFFFFFF, 0xFFFF03FF7FFFFFFF, 0x1F3FFFFFFF03FF, + 0xE0FFFFF803FF000F, 0xFFFF, 0x3FF1FFFFFFFFFFF, 0xF9FFFFFF00000000, + 0xFFFFF, 0xFFFFFFFFFFFF87FF, 0xFFFF80FF, 0x7F001B00000000, + 0x8000000007FFFFFF, 0x1FFFFFFFF, 0xFFFFFFFF0003FFFF, 0x7FFFF, + 0x6FEF000000000000, 0x401FFFFFFFFFF, 0xFFFF01F000270000, + 0xFFFFFFFFFFFFFFF, 0x1FFF07FFFFFFFFFF, 0x63FF01FF, 0x3FF000000000000, + 0xFFFF3FFFFFFFFFFF, 0x18000000000, 0xF807E3E000000000, 0x3C0000000FE7, + 0x9807001C, 0xFFFFFFFFFFDFFFFF, 0xEBFFDE64DFFFFFFF, 0xFFFFFFFFFFFFFFEF, + 0x7BFFFFFFDFDFE7BF, 0xFFFFFFFFFFFDFC5F, 0xFFFFFF7FFFFFFFFF, + 0xF7FFFFFFF7FFFFFD, 0xFFDFFFFFFFDFFFFF, 0xFFFF7FFFFFFF7FFF, + 0xFFFFFDFFFFFFFDFF, 0xFFFFFFFFFFFFCFF7, 0xF87FFFFFFFFFFFFF, + 0x201FFFFFFFFFFF, 0xFFFEF8000010, 0x7F0003, 0xFFFFFFFFFFFFE000, + 0xFFFF07DBF9FFFF7F, 0x3FFFFFFFFFFF, 0x8000, 0x3FFF1FFFFFFFFFFF, 0x43FF, + 0x7FFFFFFF0000, 0x3FFFFFFFFFF0000, 0x7FFFFFFFFFF0000, 0xC03FFFFF7FFFFFFF, + 0x7FFF6F7F00000000, 0x7F001F, 0x3FF0FFF, 0xAF7FE96FFFFFFEF, + 0x5EF7F796AA96EA84, 0xFFFFBEE0FFFFBFF, 0xFFFFFFFF, 0xFFFFFFFF7FFFFFFF, + 0xFFFF0001FFFFFFFF, 0x3FFFFFFF, 0xFFFFFFFFFFFF07FF, ], }; @@ -240,7 +247,7 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFFFFFFFFFFFFFFFF, 0x501F0003FFC3, 0, 0xB8DF000000000000, 0xFFFFFFFBFFFFD740, 0xFFBFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFC03, 0xFFFFFFFFFFFFFFFF, - 0xFFFEFFFFFFFFFFFF, 0xFFFFFFFF027FFFFF, 0x1FF, 0x787FFFFFF0000, + 0xFFFEFFFFFFFFFFFF, 0xFFFFFFFF037FFFFF, 0x19FF, 0x787FFFFFF0000, 0xFFFFFFFF00000000, 0xFFFEC000000007FF, 0xFFFFFFFFFFFFFFFF, 0x9C00C060002FFFFF, 0xFFFFFFFD0000, 0xFFFFFFFFFFFFE000, 0x2003FFFFFFFFF, 0x43007FFFFFFFC00, @@ -324,17 +331,17 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0xFC00C001FFFFFFF8, 0x3FFFFFFFFF, 0xFFFFFFFFF, 0x3FFFFFFFFC00E000, 0xE7FFFFFFFFFF07FF, 0x46FDE0000000000, 0xFFFFFFFF3F3FFFFF, 0x3FFFFFFFAAFF3F3F, 0x5FDFFFFFFFFFFFFF, 0x1FDC1FFF0FCF1FDC, - 0x8002000000000000, 0x1FFF0000, 0xF3FFFD503F2FFC84, 0xFFFFFFFF000043E0, + 0x8002000000000000, 0xFFFF8000, 0xF3FFFD503F2FFC84, 0xFFFFFFFF000043E0, 0x1FF, 0xC781FFFFFFFFF, 0xFFFF20BFFFFFFFFF, 0x80FFFFFFFFFF, 0x7F7F7F7F007FFFFF, 0x7F7F7F7F, 0x1F3E03FE000000E0, 0xFFFFFFFEE07FFFFF, 0xF7FFFFFFFFFFFFFF, 0xFFFEFFFFFFFFFFE0, 0xFFFFFFFF00007FFF, 0xFFFF000000000000, 0x1FFF, 0x3FFFFFFFFFFF0000, 0xC00FFFF1FFF, 0x80007FFFFFFFFFFF, 0xFFFFFFFF3FFFFFFF, 0xFFFFFFFFFFFF, - 0xFFFFFFFCFF800000, 0xFFFFFFFFFFFFF9FF, 0xFFFE00001FFFFFFF, 0x7FFFFF7BB, + 0xFFFFFFFCFF800000, 0xFFFFFFFFFFFFF9FF, 0xFFFE00043FFFFFFF, 0x7FFFFF7BB, 0xFFFFFFFFFFFFC, 0x68FC000000000000, 0xFFFF003FFFFFFC00, 0x1FFFFFFF0000007F, 0x7FFFFFFFFFFF0, 0x7C00FFDF00008000, 0x1FFFFFFFFFF, 0xC47FFFFF00000FF7, 0x3E62FFFFFFFFFFFF, 0x1C07FF38000005, - 0xFFFF7F7F007E7E7E, 0xFFFF03FFF7FFFFFF, 0x7FFFFFFFF, 0xFFFF000FFFFFFFFF, + 0xFFFF7F7F007E7E7E, 0xFFFF33FFF7FFFFFF, 0x7FFFFFFFF, 0xFFFF000FFFFFFFFF, 0xFFFFFFFFFFFF87F, 0xFFFF3FFFFFFFFFFF, 0x3FFFFFF, 0x5F7FFDFFA0F8007F, 0xFFFFFFFFFFFFFFDB, 0x3FFFFFFFFFFFF, 0xFFFFFFFFFFF80000, 0xFFFFFFF03FFFFFFF, 0x3FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFF0000, @@ -343,9 +350,9 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0x7FFFFFFF3FFFFFFF, 0x1CFCFCFC, ], tree3_level1: &[ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 9, 10, 5, 11, 12, 5, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 13, 14, 15, 7, 16, 17, 7, 18, 7, 19, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 5, 12, 13, 5, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 14, 15, 16, 7, 17, 18, 7, 19, 7, 20, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 7, 7, 21, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, @@ -353,7 +360,7 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, ], tree3_level2: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, @@ -361,56 +368,61 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 30, 31, 32, 33, 34, 4, 2, 35, 36, 36, 37, 38, 39, 4, 4, 4, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 23, 57, 58, 59, 60, 5, 61, 62, 63, 4, 4, 64, 65, 62, 66, 67, 4, 68, 69, 4, 4, 70, 4, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 4, 4, 4, 81, 82, 83, 84, 4, 85, 86, 87, 88, 4, - 4, 4, 89, 90, 4, 91, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 4, - 2, 64, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 95, 2, 2, 2, 2, 2, 2, + 74, 75, 76, 77, 78, 79, 80, 81, 4, 4, 82, 83, 84, 85, 4, 86, 87, 88, 89, + 4, 4, 4, 90, 91, 4, 92, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, + 4, 2, 93, 2, 2, 2, 94, 2, 2, 2, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 95, + 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 80, 97, 98, 99, 62, 100, 84, 4, 4, 4, 4, 4, - 4, 101, 4, 4, 4, 2, 102, 103, 2, 104, 105, 106, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 80, 99, 100, 101, 62, 102, 85, 4, 4, + 4, 4, 4, 4, 103, 4, 4, 4, 2, 104, 105, 2, 106, 107, 108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 107, 23, 4, 2, 36, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 109, 82, 4, 2, 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 110, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 108, 2, 2, 2, 2, 109, 110, 2, 2, 2, 2, 2, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 112, 113, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 114, 115, - 116, 117, 118, 2, 2, 2, 2, 119, 120, 121, 122, 123, 124, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 125, 4, - 4, 4, 126, 127, 4, 4, 128, 129, 4, 4, 4, 4, 99, 70, 4, 4, 4, 4, 4, 4, 4, - 130, 4, 4, 4, 131, 4, 4, 4, 132, 4, 4, 4, 133, 2, 2, 2, 134, 2, 135, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 136, 137, 138, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 139, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 112, 2, 2, 2, 2, 113, 114, 2, 2, 2, 2, 2, 115, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 116, 117, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 118, 119, 120, 121, 122, 2, + 2, 2, 2, 123, 124, 125, 126, 127, 128, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 129, 130, 131, 132, + 4, 4, 133, 134, 4, 4, 4, 4, 101, 70, 4, 4, 4, 4, 4, 4, 4, 135, 4, 4, 4, + 136, 4, 4, 4, 137, 4, 4, 4, 138, 2, 2, 2, 139, 2, 140, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 141, 142, 143, 4, 4, 4, 4, 4, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 144, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 145, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 140, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 146, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 141, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, - 2, 2, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 142, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 147, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, + 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 148, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 143, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 149, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ], tree3_level3: &[ 0xB7FFFF7FFFFFEFFF, 0x3FFF3FFF, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFF, 0, @@ -418,11 +430,11 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0x3FFFFFFFFF07FF, 0xFFFFFFFF3FFFFFFF, 0x3EFF0F, 0xFFFF00003FFFFFFF, 0xFFFFFFFFF0FFFFF, 0xFFFF00FFFFFFFFFF, 0xF7FF000FFFFFFFFF, 0x1BFBFFFBFFB7F7FF, 0xFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFF003FFFFF, - 0x7FDFFFFFFFFFFBF, 0x91BFFFFFFFFFFD3F, 0x7FFFFF003FFFFF, 0x7FFFFFFF, + 0xFFFDFFFFFFFFFFBF, 0x91BFFFFFFFFFFD3F, 0x7FFFFF003FFFFF, 0x7FFFFFFF, 0x37FFFF00000000, 0x3FFFFFF003FFFFF, 0x3FFFFFF, 0xC0FFFFFFFFFFFFFF, 0x3FFFFFFEEF0001, 0x1FFFFFFF00000000, 0x1FFFFFFF, 0x1FFFFFFEFF, 0x3FFFFFFFFFFFFF, 0x7FFFF003FFFFF, 0x3FFFF, 0x1FF, 0x7FFFFFFFFFFFF, - 0xFFFFFFFFF, 0xFFFF803FFFFFFC00, 0x3F, 0x303FFFFFFFFFF, 0xFC, + 0xFFFFFFFFF, 0xFFFF803FFFFFFC00, 0x3F, 0x303FFFFFFFFFF, 0x7FFFFE0000FC, 0xFFFF00801FFFFFFF, 0xFFFF00000000003F, 0xFFFF000000000003, 0x7FFFFF0000001F, 0xFFFFFFFFFFFFF8, 0x26000000000000, 0xFFFFFFFFFFF8, 0x1FFFFFF0000, 0x7FFFFFFFF8, 0x47FFFFFFFF0090, 0x7FFFFFFFFFFF8, @@ -432,22 +444,24 @@ pub const XID_START: &'static ::ucd_trie::TrieSet = &::ucd_trie::TrieSet { 0x7FFFFFF, 0x7F, 0xFFFFFFFFFFF, 0xFFFFFFFF00000000, 0x80000000FFFFFFFF, 0x8000FFFFFF6FF27F, 0x2, 0xFFFFFCFF00000000, 0xA0001FFFF, 0x407FFFFFFFFF801, 0xFFFFFFFFF0010000, 0xFFFF0000200003FF, - 0x1FFFFFFFFFFFFFF, 0x1FFFFFFFF, 0x7FFFFFFFFDFF, 0xFFFC000000000001, + 0x1FFFFFFFFFFFFFF, 0x400, 0x1FFFFFFFF, 0x7FFFFFFFFDFF, 0xFFFC000000000001, 0xFFFF, 0x1FFFFFFFFFB7F, 0xFFFFFDBF00000040, 0xFFFF0000010003FF, - 0xFFFFFFF, 0x7FFFF00000000, 0xFFFFFFFFDFFF4, 0x1000000000000, 0xF, - 0xFFFFFFFFFFFF0000, 0x1FFFFFFFFFFFF, 0xFFFFFFFF0000007E, 0x3FFFFFFF, - 0xFFFF00007FFFFFFF, 0x7FFFFFFFFFFFFFFF, 0x3FFFFFFF0000, - 0xE0FFFFF80000000F, 0x1FFFFFFFFFFF, 0xF9FFFFFF00000000, 0xFFFFF, 0x107FF, - 0xFFF80000, 0x7C000B00000000, 0x80000000003FFFFF, 0x6FEF000000000000, - 0x40007FFFFFFFF, 0xFFFF00F000270000, 0xFFFFFFFFFFFFFFF, + 0x200000FFFFFFF, 0x7FFFF00000000, 0xFFFFFFFFDFFF4, 0x1000000000000, + 0xFFE0FFFFFFFFFFFF, 0xFFFFFFFFFFFF000F, 0xFFFFFFFFFFFF0000, + 0x1FFFFFFFFFFFF, 0xFFFFFFFF0000007E, 0x3FFFFFFF, 0xFFFF00007FFFFFFF, + 0x7FFFFFFFFFFFFFFF, 0x3FFFFFFF0000, 0xE0FFFFF80000000F, 0x1FFFFFFFFFFF, + 0xF9FFFFFF00000000, 0xFFFFF, 0x107FF, 0xFFF80000, 0x7C000B00000000, + 0x8000000007FFFFFF, 0xFFFFFFFF0003FFFF, 0x7FFFF, 0x6FEF000000000000, + 0x401FFFFFFFFFF, 0xFFFF01F000270000, 0xFFFFFFFFFFFFFFF, 0x1FFF07FFFFFFFFFF, 0x3FF01FF, 0xFFFFFFFFFFDFFFFF, 0xEBFFDE64DFFFFFFF, 0xFFFFFFFFFFFFFFEF, 0x7BFFFFFFDFDFE7BF, 0xFFFFFFFFFFFDFC5F, - 0xFFFFFF3FFFFFFFFF, 0xF7FFFFFFF7FFFFFD, 0xFFDFFFFFFFDFFFFF, - 0xFFFF7FFFFFFF7FFF, 0xFFFFFDFFFFFFFDFF, 0xFF7, 0x7E07FFFFFFF, - 0xFFFF000000000000, 0x3FFFFFFFFFFF, 0x3F801FFFFFFFFFFF, 0x4000, - 0xFFFFFFF0000, 0x13FFFFFFF0000, 0xC01F3FB77FFFFFFF, 0x7FFF6F7F00000000, - 0x1F, 0x80F, 0xAF7FE96FFFFFFEF, 0x5EF7F796AA96EA84, 0xFFFFBEE0FFFFBFF, - 0xFFFFFFFF, 0xFFFF3FFFFFFFFFFF, 0xFFFF0001FFFFFFFF, 0xFFFFFFFFFFFF07FF, + 0xFFFFFF7FFFFFFFFF, 0xF7FFFFFFF7FFFFFD, 0xFFDFFFFFFFDFFFFF, + 0xFFFF7FFFFFFF7FFF, 0xFFFFFDFFFFFFFDFF, 0xFF7, 0x7F0003, + 0xFFFFFFFFFFFFE000, 0xFFFF000000000000, 0x3FFFFFFFFFFF, + 0x3F801FFFFFFFFFFF, 0x4000, 0xFFFFFFF0000, 0x13FFFFFFF0000, + 0xC01F3FB77FFFFFFF, 0x7FFF6F7F00000000, 0x1F, 0x80F, 0xAF7FE96FFFFFFEF, + 0x5EF7F796AA96EA84, 0xFFFFBEE0FFFFBFF, 0xFFFFFFFF, 0xFFFFFFFF7FFFFFFF, + 0xFFFF3FFFFFFFFFFF, 0xFFFF0001FFFFFFFF, 0xFFFFFFFFFFFF07FF, 0x3FFFFFFFFFFFFFF, ], }; diff --git a/deps/crates/vendor/utf8_iter-v1/.cargo-checksum.json b/deps/crates/vendor/utf8_iter-v1/.cargo-checksum.json deleted file mode 100644 index 697c9ce2fbb4..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{}} diff --git a/deps/crates/vendor/utf8_iter-v1/.cargo_vcs_info.json b/deps/crates/vendor/utf8_iter-v1/.cargo_vcs_info.json deleted file mode 100644 index 2d3b66974951..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/.cargo_vcs_info.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "git": { - "sha1": "6b604ea2365bd535fb66eb4bfe92a9e00e333090" - }, - "path_in_vcs": "" -} \ No newline at end of file diff --git a/deps/crates/vendor/utf8_iter-v1/.gitignore b/deps/crates/vendor/utf8_iter-v1/.gitignore deleted file mode 100644 index 4fffb2f89cbd..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/deps/crates/vendor/utf8_iter-v1/COPYRIGHT b/deps/crates/vendor/utf8_iter-v1/COPYRIGHT deleted file mode 100644 index b5e94574045c..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/COPYRIGHT +++ /dev/null @@ -1,42 +0,0 @@ -Copyright Mozilla Foundation - -Licensed under the Apache License (Version 2.0), or the MIT license, -(the "Licenses") at your option. You may not use this file except in -compliance with one of the Licenses. You may obtain copies of the -Licenses at: - - https://www.apache.org/licenses/LICENSE-2.0 - https://opensource.org/licenses/MIT - -Unless required by applicable law or agreed to in writing, software -distributed under the Licenses is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the Licenses for the specific language governing permissions and -limitations under the Licenses. - --- - -Test code is dedicated to the Public Domain when so designated (see -the individual files for PD/CC0-dedicated sections). - --- - -The implementation for Utf8CharIndices was adapted from the -CharIndices implementation of the Rust standard library at revision -ab32548539ec38a939c1b58599249f3b54130026 -(https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/library/core/src/str/iter.rs). - -Excerpt from https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/COPYRIGHT , -which refers to -https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/LICENSE-APACHE -and -https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/LICENSE-MIT -: - -For full authorship information, see the version control history or -https://thanks.rust-lang.org - -Except as otherwise noted (below and/or in individual files), Rust is -licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or -<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. diff --git a/deps/crates/vendor/utf8_iter-v1/Cargo.toml b/deps/crates/vendor/utf8_iter-v1/Cargo.toml deleted file mode 100644 index d1008fdb4441..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "utf8_iter" -version = "1.0.4" -authors = ["Henri Sivonen <hsivonen@hsivonen.fi>"] -description = "Iterator by char over potentially-invalid UTF-8 in &[u8]" -homepage = "https://docs.rs/utf8_iter/" -documentation = "https://docs.rs/utf8_iter/" -readme = "README.md" -keywords = [ - "encoding", - "UTF-8", - "unicode", - "iterator", -] -categories = [ - "text-processing", - "encoding", - "internationalization", -] -license = "Apache-2.0 OR MIT" -repository = "https://github.com/hsivonen/utf8_iter" diff --git a/deps/crates/vendor/utf8_iter-v1/Cargo.toml.orig b/deps/crates/vendor/utf8_iter-v1/Cargo.toml.orig deleted file mode 100644 index 263d2d87db4c..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/Cargo.toml.orig +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "utf8_iter" -version = "1.0.4" -edition = "2021" -description = "Iterator by char over potentially-invalid UTF-8 in &[u8]" -authors = ["Henri Sivonen <hsivonen@hsivonen.fi>"] -license = "Apache-2.0 OR MIT" -readme = "README.md" -documentation = "https://docs.rs/utf8_iter/" -homepage = "https://docs.rs/utf8_iter/" -repository = "https://github.com/hsivonen/utf8_iter" -keywords = ["encoding", "UTF-8", "unicode", "iterator"] -categories = ["text-processing", "encoding", "internationalization"] diff --git a/deps/crates/vendor/utf8_iter-v1/LICENSE-APACHE b/deps/crates/vendor/utf8_iter-v1/LICENSE-APACHE deleted file mode 100644 index d64569567334..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/deps/crates/vendor/utf8_iter-v1/LICENSE-MIT b/deps/crates/vendor/utf8_iter-v1/LICENSE-MIT deleted file mode 100644 index 3317c82e2f67..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright Mozilla Foundation - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/deps/crates/vendor/utf8_iter-v1/README.md b/deps/crates/vendor/utf8_iter-v1/README.md deleted file mode 100644 index 08334d4db823..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# utf8_iter - -[![crates.io](https://img.shields.io/crates/v/utf8_iter.svg)](https://crates.io/crates/utf8_iter) -[![docs.rs](https://docs.rs/utf8_iter/badge.svg)](https://docs.rs/utf8_iter/) - -utf8_iter provides iteration by `char` over potentially-invalid UTF-8 `&[u8]` -such that UTF-8 errors are handled according to the WHATWG Encoding Standard. - -Iteration by `Result<char,Utf8CharsError>` is provided as an alternative that -distinguishes UTF-8 errors from U+FFFD appearing in the input. - -An implementation of `char_indices()` analogous to the same-name method on -`str` is also provided. - -Key parts of the code are copypaste from the UTF-8 to UTF-16 conversion code -in `encoding_rs`, which was optimized for speed in the case of valid input. -The implementation here uses the structure that was found to be fast in the -`encoding_rs` context but the structure hasn't been benchmarked in this -context. - -This is a `no_std` crate. - -## Licensing - -TL;DR: `Apache-2.0 OR MIT` - -Please see the file named -[COPYRIGHT](https://github.com/hsivonen/utf8_iter/blob/master/COPYRIGHT). - -## Documentation - -Generated [API documentation](https://docs.rs/utf8_iter/) is available -online. - -## Release Notes - -### 1.0.4 - -* Add iteration by `Result<char,Utf8CharsError>`. - -### 1.0.3 - -* Fix an error in documentation. - -### 1.0.2 - -* `char_indices()` implementation. - -### 1.0.1 - -* `as_slice()` method. -* Implement `DoubleEndedIterator` - -### 1.0.0 - -The initial release. diff --git a/deps/crates/vendor/utf8_iter-v1/src/indices.rs b/deps/crates/vendor/utf8_iter-v1/src/indices.rs deleted file mode 100644 index 1646f8b8dc0b..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/src/indices.rs +++ /dev/null @@ -1,120 +0,0 @@ -// The code in this file was adapted from the CharIndices implementation of -// the Rust standard library at revision ab32548539ec38a939c1b58599249f3b54130026 -// (https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/library/core/src/str/iter.rs). -// -// Excerpt from https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/COPYRIGHT , -// which refers to -// https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/LICENSE-APACHE -// and -// https://github.com/rust-lang/rust/blob/ab32548539ec38a939c1b58599249f3b54130026/LICENSE-MIT -// : -// -// For full authorship information, see the version control history or -// https://thanks.rust-lang.org -// -// Except as otherwise noted (below and/or in individual files), Rust is -// licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or -// <http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. - -use super::Utf8Chars; -use core::iter::FusedIterator; - -/// An iterator over the [`char`]s and their positions. -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Utf8CharIndices<'a> { - front_offset: usize, - iter: Utf8Chars<'a>, -} - -impl<'a> Iterator for Utf8CharIndices<'a> { - type Item = (usize, char); - - #[inline] - fn next(&mut self) -> Option<(usize, char)> { - let pre_len = self.as_slice().len(); - match self.iter.next() { - None => None, - Some(ch) => { - let index = self.front_offset; - let len = self.as_slice().len(); - self.front_offset += pre_len - len; - Some((index, ch)) - } - } - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } - - #[inline] - fn last(mut self) -> Option<(usize, char)> { - // No need to go through the entire string. - self.next_back() - } -} - -impl<'a> DoubleEndedIterator for Utf8CharIndices<'a> { - #[inline] - fn next_back(&mut self) -> Option<(usize, char)> { - self.iter.next_back().map(|ch| { - let index = self.front_offset + self.as_slice().len(); - (index, ch) - }) - } -} - -impl FusedIterator for Utf8CharIndices<'_> {} - -impl<'a> Utf8CharIndices<'a> { - #[inline(always)] - /// Creates the iterator from a byte slice. - pub fn new(bytes: &'a [u8]) -> Self { - Utf8CharIndices::<'a> { - front_offset: 0, - iter: Utf8Chars::new(bytes), - } - } - - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - #[must_use] - #[inline] - pub fn as_slice(&self) -> &'a [u8] { - self.iter.as_slice() - } - - /// Returns the byte position of the next character, or the length - /// of the underlying string if there are no more characters. - /// - /// # Examples - /// - /// ``` - /// use utf8_iter::Utf8CharsEx; - /// let mut chars = "a楽".as_bytes().char_indices(); - /// - /// assert_eq!(chars.offset(), 0); - /// assert_eq!(chars.next(), Some((0, 'a'))); - /// - /// assert_eq!(chars.offset(), 1); - /// assert_eq!(chars.next(), Some((1, '楽'))); - /// - /// assert_eq!(chars.offset(), 4); - /// assert_eq!(chars.next(), None); - /// ``` - #[inline] - #[must_use] - pub fn offset(&self) -> usize { - self.front_offset - } -} diff --git a/deps/crates/vendor/utf8_iter-v1/src/lib.rs b/deps/crates/vendor/utf8_iter-v1/src/lib.rs deleted file mode 100644 index 8edb094b3223..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/src/lib.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright Mozilla Foundation -// -// Licensed under the Apache License (Version 2.0), or the MIT license, -// (the "Licenses") at your option. You may not use this file except in -// compliance with one of the Licenses. You may obtain copies of the -// Licenses at: -// -// https://www.apache.org/licenses/LICENSE-2.0 -// https://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Licenses is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the Licenses for the specific language governing permissions and -// limitations under the Licenses. - -#![no_std] - -//! Provides iteration by `char` over `&[u8]` containing potentially-invalid -//! UTF-8 such that errors are handled according to the [WHATWG Encoding -//! Standard](https://encoding.spec.whatwg.org/#utf-8-decoder) (i.e. the same -//! way as in `String::from_utf8_lossy`). -//! -//! The trait `Utf8CharsEx` provides the convenience method `chars()` on -//! byte slices themselves instead of having to use the more verbose -//! `Utf8Chars::new(slice)`. -//! -//! ```rust -//! use utf8_iter::Utf8CharsEx; -//! let data = b"\xFF\xC2\xE2\xE2\x98\xF0\xF0\x9F\xF0\x9F\x92\xE2\x98\x83"; -//! let from_iter: String = data.chars().collect(); -//! let from_std = String::from_utf8_lossy(data); -//! assert_eq!(from_iter, from_std); -//! ``` - -mod indices; -mod report; - -pub use crate::indices::Utf8CharIndices; -pub use crate::report::ErrorReportingUtf8Chars; -pub use crate::report::Utf8CharsError; -use core::iter::FusedIterator; - -#[repr(align(64))] // Align to cache lines -struct Utf8Data { - pub table: [u8; 384], -} - -// This is generated code copied and pasted from utf_8.rs of encoding_rs. -// Please don't edit by hand but instead regenerate as instructed in that -// file. - -static UTF8_DATA: Utf8Data = Utf8Data { - table: [ - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 148, 148, 148, - 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 164, 164, 164, 164, 164, - 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, - 164, 164, 164, 164, 164, 164, 164, 164, 164, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, - 252, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 32, 8, 8, 64, 8, 8, 8, 128, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - ], -}; - -// End manually copypasted generated code. - -#[inline(always)] -fn in_inclusive_range8(i: u8, start: u8, end: u8) -> bool { - i.wrapping_sub(start) <= (end - start) -} - -/// Iterator by `char` over `&[u8]` that contains -/// potentially-invalid UTF-8. See the crate documentation. -#[derive(Debug, Clone)] -pub struct Utf8Chars<'a> { - remaining: &'a [u8], -} - -impl<'a> Utf8Chars<'a> { - #[inline(always)] - /// Creates the iterator from a byte slice. - pub fn new(bytes: &'a [u8]) -> Self { - Utf8Chars::<'a> { remaining: bytes } - } - - /// Views the current remaining data in the iterator as a subslice - /// of the original slice. - #[inline(always)] - pub fn as_slice(&self) -> &'a [u8] { - self.remaining - } - - #[inline(never)] - fn next_fallback(&mut self) -> Option<char> { - if self.remaining.is_empty() { - return None; - } - let first = self.remaining[0]; - if first < 0x80 { - self.remaining = &self.remaining[1..]; - return Some(char::from(first)); - } - if !in_inclusive_range8(first, 0xC2, 0xF4) || self.remaining.len() == 1 { - self.remaining = &self.remaining[1..]; - return Some('\u{FFFD}'); - } - let second = self.remaining[1]; - let (lower_bound, upper_bound) = match first { - 0xE0 => (0xA0, 0xBF), - 0xED => (0x80, 0x9F), - 0xF0 => (0x90, 0xBF), - 0xF4 => (0x80, 0x8F), - _ => (0x80, 0xBF), - }; - if !in_inclusive_range8(second, lower_bound, upper_bound) { - self.remaining = &self.remaining[1..]; - return Some('\u{FFFD}'); - } - if first < 0xE0 { - self.remaining = &self.remaining[2..]; - let point = ((u32::from(first) & 0x1F) << 6) | (u32::from(second) & 0x3F); - return Some(unsafe { char::from_u32_unchecked(point) }); - } - if self.remaining.len() == 2 { - self.remaining = &self.remaining[2..]; - return Some('\u{FFFD}'); - } - let third = self.remaining[2]; - if !in_inclusive_range8(third, 0x80, 0xBF) { - self.remaining = &self.remaining[2..]; - return Some('\u{FFFD}'); - } - if first < 0xF0 { - self.remaining = &self.remaining[3..]; - let point = ((u32::from(first) & 0xF) << 12) - | ((u32::from(second) & 0x3F) << 6) - | (u32::from(third) & 0x3F); - return Some(unsafe { char::from_u32_unchecked(point) }); - } - // At this point, we have a valid 3-byte prefix of a - // four-byte sequence that has to be incomplete, because - // otherwise `next()` would have succeeded. - self.remaining = &self.remaining[3..]; - Some('\u{FFFD}') - } -} - -impl<'a> Iterator for Utf8Chars<'a> { - type Item = char; - - #[inline] - fn next(&mut self) -> Option<char> { - // Not delegating directly to `ErrorReportingUtf8Chars` to avoid - // an extra branch in the common case based on a cursory inspection - // of generated code in a similar case. Be sure to inspect the - // generated code as inlined into an actual usage site carefully - // if attempting to consolidate the source code here. - - // This loop is only broken out of as goto forward - #[allow(clippy::never_loop)] - loop { - if self.remaining.len() < 4 { - break; - } - let first = self.remaining[0]; - if first < 0x80 { - self.remaining = &self.remaining[1..]; - return Some(char::from(first)); - } - let second = self.remaining[1]; - if in_inclusive_range8(first, 0xC2, 0xDF) { - if !in_inclusive_range8(second, 0x80, 0xBF) { - break; - } - let point = ((u32::from(first) & 0x1F) << 6) | (u32::from(second) & 0x3F); - self.remaining = &self.remaining[2..]; - return Some(unsafe { char::from_u32_unchecked(point) }); - } - // This table-based formulation was benchmark-based in encoding_rs, - // but it hasn't been re-benchmarked in this iterator context. - let third = self.remaining[2]; - if first < 0xF0 { - if ((UTF8_DATA.table[usize::from(second)] - & UTF8_DATA.table[usize::from(first) + 0x80]) - | (third >> 6)) - != 2 - { - break; - } - let point = ((u32::from(first) & 0xF) << 12) - | ((u32::from(second) & 0x3F) << 6) - | (u32::from(third) & 0x3F); - self.remaining = &self.remaining[3..]; - return Some(unsafe { char::from_u32_unchecked(point) }); - } - let fourth = self.remaining[3]; - if (u16::from( - UTF8_DATA.table[usize::from(second)] & UTF8_DATA.table[usize::from(first) + 0x80], - ) | u16::from(third >> 6) - | (u16::from(fourth & 0xC0) << 2)) - != 0x202 - { - break; - } - let point = ((u32::from(first) & 0x7) << 18) - | ((u32::from(second) & 0x3F) << 12) - | ((u32::from(third) & 0x3F) << 6) - | (u32::from(fourth) & 0x3F); - self.remaining = &self.remaining[4..]; - return Some(unsafe { char::from_u32_unchecked(point) }); - } - self.next_fallback() - } -} - -impl<'a> DoubleEndedIterator for Utf8Chars<'a> { - #[inline] - fn next_back(&mut self) -> Option<char> { - if self.remaining.is_empty() { - return None; - } - let mut attempt = 1; - for b in self.remaining.iter().rev() { - if b & 0xC0 != 0x80 { - let (head, tail) = self.remaining.split_at(self.remaining.len() - attempt); - let mut inner = Utf8Chars::new(tail); - let candidate = inner.next(); - if inner.as_slice().is_empty() { - self.remaining = head; - return candidate; - } - break; - } - if attempt == 4 { - break; - } - attempt += 1; - } - - self.remaining = &self.remaining[..self.remaining.len() - 1]; - Some('\u{FFFD}') - } -} - -impl FusedIterator for Utf8Chars<'_> {} - -/// Convenience trait that adds `chars()` and `char_indices()` methods -/// similar to the ones on string slices to byte slices. -pub trait Utf8CharsEx { - fn chars(&self) -> Utf8Chars<'_>; - fn char_indices(&self) -> Utf8CharIndices<'_>; -} - -impl Utf8CharsEx for [u8] { - /// Convenience method for creating an UTF-8 iterator - /// for the slice. - #[inline] - fn chars(&self) -> Utf8Chars<'_> { - Utf8Chars::new(self) - } - /// Convenience method for creating a byte index and - /// UTF-8 iterator for the slice. - #[inline] - fn char_indices(&self) -> Utf8CharIndices<'_> { - Utf8CharIndices::new(self) - } -} - -// No manually-written tests for forward-iteration, because the code passed multiple -// days of fuzzing comparing with known-good behavior. diff --git a/deps/crates/vendor/utf8_iter-v1/src/report.rs b/deps/crates/vendor/utf8_iter-v1/src/report.rs deleted file mode 100644 index 6f0c44cb57c3..000000000000 --- a/deps/crates/vendor/utf8_iter-v1/src/report.rs +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright Mozilla Foundation -// -// Licensed under the Apache License (Version 2.0), or the MIT license, -// (the "Licenses") at your option. You may not use this file except in -// compliance with one of the Licenses. You may obtain copies of the -// Licenses at: -// -// https://www.apache.org/licenses/LICENSE-2.0 -// https://opensource.org/licenses/MIT -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Licenses is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the Licenses for the specific language governing permissions and -// limitations under the Licenses. - -use crate::in_inclusive_range8; -use crate::UTF8_DATA; -use core::fmt::Formatter; -use core::iter::FusedIterator; - -/// A type for signaling UTF-8 errors. -/// -/// Note: `core::error::Error` is not implemented due to implementing it -/// being an [unstable feature][1] at the time of writing. -/// -/// [1]: https://github.com/rust-lang/rust/issues/103765 -#[derive(Debug, PartialEq)] -#[non_exhaustive] -pub struct Utf8CharsError; - -impl core::fmt::Display for Utf8CharsError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "byte sequence not well-formed UTF-8") - } -} - -/// Iterator by `Result<char,Utf8CharsError>` over `&[u8]` that contains -/// potentially-invalid UTF-8. There is exactly one `Utf8CharsError` per -/// each error as defined by the WHATWG Encoding Standard. -/// -/// ``` -/// let s = b"a\xFFb\xFF\x80c\xF0\x9F\xA4\xA6\xF0\x9F\xA4\xF0\x9F\xF0d"; -/// let plain = utf8_iter::Utf8Chars::new(s); -/// let reporting = utf8_iter::ErrorReportingUtf8Chars::new(s); -/// assert!(plain.eq(reporting.map(|r| r.unwrap_or('\u{FFFD}')))); -/// ``` -#[derive(Debug, Clone)] -pub struct ErrorReportingUtf8Chars<'a> { - remaining: &'a [u8], -} - -impl<'a> ErrorReportingUtf8Chars<'a> { - #[inline(always)] - /// Creates the iterator from a byte slice. - pub fn new(bytes: &'a [u8]) -> Self { - ErrorReportingUtf8Chars::<'a> { remaining: bytes } - } - - /// Views the current remaining data in the iterator as a subslice - /// of the original slice. - #[inline(always)] - pub fn as_slice(&self) -> &'a [u8] { - self.remaining - } - - #[inline(never)] - fn next_fallback(&mut self) -> Option<Result<char, Utf8CharsError>> { - if self.remaining.is_empty() { - return None; - } - let first = self.remaining[0]; - if first < 0x80 { - self.remaining = &self.remaining[1..]; - return Some(Ok(char::from(first))); - } - if !in_inclusive_range8(first, 0xC2, 0xF4) || self.remaining.len() == 1 { - self.remaining = &self.remaining[1..]; - return Some(Err(Utf8CharsError)); - } - let second = self.remaining[1]; - let (lower_bound, upper_bound) = match first { - 0xE0 => (0xA0, 0xBF), - 0xED => (0x80, 0x9F), - 0xF0 => (0x90, 0xBF), - 0xF4 => (0x80, 0x8F), - _ => (0x80, 0xBF), - }; - if !in_inclusive_range8(second, lower_bound, upper_bound) { - self.remaining = &self.remaining[1..]; - return Some(Err(Utf8CharsError)); - } - if first < 0xE0 { - self.remaining = &self.remaining[2..]; - let point = ((u32::from(first) & 0x1F) << 6) | (u32::from(second) & 0x3F); - return Some(Ok(unsafe { char::from_u32_unchecked(point) })); - } - if self.remaining.len() == 2 { - self.remaining = &self.remaining[2..]; - return Some(Err(Utf8CharsError)); - } - let third = self.remaining[2]; - if !in_inclusive_range8(third, 0x80, 0xBF) { - self.remaining = &self.remaining[2..]; - return Some(Err(Utf8CharsError)); - } - if first < 0xF0 { - self.remaining = &self.remaining[3..]; - let point = ((u32::from(first) & 0xF) << 12) - | ((u32::from(second) & 0x3F) << 6) - | (u32::from(third) & 0x3F); - return Some(Ok(unsafe { char::from_u32_unchecked(point) })); - } - // At this point, we have a valid 3-byte prefix of a - // four-byte sequence that has to be incomplete, because - // otherwise `next()` would have succeeded. - self.remaining = &self.remaining[3..]; - Some(Err(Utf8CharsError)) - } -} - -impl<'a> Iterator for ErrorReportingUtf8Chars<'a> { - type Item = Result<char, Utf8CharsError>; - - #[inline] - fn next(&mut self) -> Option<Result<char, Utf8CharsError>> { - // This loop is only broken out of as goto forward - #[allow(clippy::never_loop)] - loop { - if self.remaining.len() < 4 { - break; - } - let first = self.remaining[0]; - if first < 0x80 { - self.remaining = &self.remaining[1..]; - return Some(Ok(char::from(first))); - } - let second = self.remaining[1]; - if in_inclusive_range8(first, 0xC2, 0xDF) { - if !in_inclusive_range8(second, 0x80, 0xBF) { - break; - } - let point = ((u32::from(first) & 0x1F) << 6) | (u32::from(second) & 0x3F); - self.remaining = &self.remaining[2..]; - return Some(Ok(unsafe { char::from_u32_unchecked(point) })); - } - // This table-based formulation was benchmark-based in encoding_rs, - // but it hasn't been re-benchmarked in this iterator context. - let third = self.remaining[2]; - if first < 0xF0 { - if ((UTF8_DATA.table[usize::from(second)] - & UTF8_DATA.table[usize::from(first) + 0x80]) - | (third >> 6)) - != 2 - { - break; - } - let point = ((u32::from(first) & 0xF) << 12) - | ((u32::from(second) & 0x3F) << 6) - | (u32::from(third) & 0x3F); - self.remaining = &self.remaining[3..]; - return Some(Ok(unsafe { char::from_u32_unchecked(point) })); - } - let fourth = self.remaining[3]; - if (u16::from( - UTF8_DATA.table[usize::from(second)] & UTF8_DATA.table[usize::from(first) + 0x80], - ) | u16::from(third >> 6) - | (u16::from(fourth & 0xC0) << 2)) - != 0x202 - { - break; - } - let point = ((u32::from(first) & 0x7) << 18) - | ((u32::from(second) & 0x3F) << 12) - | ((u32::from(third) & 0x3F) << 6) - | (u32::from(fourth) & 0x3F); - self.remaining = &self.remaining[4..]; - return Some(Ok(unsafe { char::from_u32_unchecked(point) })); - } - self.next_fallback() - } -} - -impl<'a> DoubleEndedIterator for ErrorReportingUtf8Chars<'a> { - #[inline] - fn next_back(&mut self) -> Option<Result<char, Utf8CharsError>> { - if self.remaining.is_empty() { - return None; - } - let mut attempt = 1; - for b in self.remaining.iter().rev() { - if b & 0xC0 != 0x80 { - let (head, tail) = self.remaining.split_at(self.remaining.len() - attempt); - let mut inner = ErrorReportingUtf8Chars::new(tail); - let candidate = inner.next(); - if inner.as_slice().is_empty() { - self.remaining = head; - return candidate; - } - break; - } - if attempt == 4 { - break; - } - attempt += 1; - } - - self.remaining = &self.remaining[..self.remaining.len() - 1]; - Some(Err(Utf8CharsError)) - } -} - -impl FusedIterator for ErrorReportingUtf8Chars<'_> {} - -#[cfg(test)] -mod tests { - use crate::ErrorReportingUtf8Chars; - - // Should be a static assert, but not taking a dependency for this. - #[test] - fn test_size() { - assert_eq!( - core::mem::size_of::<Option<<ErrorReportingUtf8Chars<'_> as Iterator>::Item>>(), - core::mem::size_of::<Option<char>>() - ); - } - - #[test] - fn test_eq() { - let a: <ErrorReportingUtf8Chars<'_> as Iterator>::Item = Ok('a'); - let a_again: <ErrorReportingUtf8Chars<'_> as Iterator>::Item = Ok('a'); - assert_eq!(a, a_again); - } -} diff --git a/deps/crates/vendor/yoke-derive-v0_8/.cargo_vcs_info.json b/deps/crates/vendor/yoke-derive-v0_8/.cargo_vcs_info.json index 9d2ce6c66fd0..d0c23e30ba5b 100644 --- a/deps/crates/vendor/yoke-derive-v0_8/.cargo_vcs_info.json +++ b/deps/crates/vendor/yoke-derive-v0_8/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "c9fac4e625ccb2c6a7aa35079fff9709db4385ac" + "sha1": "a59ab860d4bda548e94dfbf992d87fe1f761bc55" }, "path_in_vcs": "utils/yoke/derive" } \ No newline at end of file diff --git a/deps/crates/vendor/yoke-derive-v0_8/Cargo.lock b/deps/crates/vendor/yoke-derive-v0_8/Cargo.lock index d5dcd9c69d61..b175e811ba6f 100644 --- a/deps/crates/vendor/yoke-derive-v0_8/Cargo.lock +++ b/deps/crates/vendor/yoke-derive-v0_8/Cargo.lock @@ -4,27 +4,27 @@ version = 3 [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "2.0.117" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", @@ -50,7 +50,7 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" dependencies = [ "proc-macro2", "quote", diff --git a/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml b/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml index ede0525132e0..03a8f09243f6 100644 --- a/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml +++ b/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml @@ -11,8 +11,9 @@ [package] edition = "2021" +rust-version = "1.82" name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] build = false autolib = false @@ -57,17 +58,21 @@ version = "1.0.61" version = "1.0.44" [dependencies.syn] -version = "2.0.21" -features = ["fold"] +version = "3.0" +features = [ + "fold", + "visit", +] [dependencies.synstructure] -version = "0.13.0" +version = "0.14.0" [dev-dependencies] [lints.clippy] -alloc-instead-of-core = "warn" -branches-sharing-code = "warn" +alloc_instead_of_core = "warn" +bool_assert_comparison = "allow" +branches_sharing_code = "warn" collection_is_never_read = "warn" crosspointer_transmute = "warn" dbg_macro = "warn" @@ -82,7 +87,7 @@ mismatching_type_param_order = "warn" missing_fields_in_debug = "warn" missing_transmute_annotations = "warn" negative_feature_names = "warn" -or-fun-call = "warn" +or_fun_call = "warn" same_functions_in_if_condition = "warn" todo = "warn" transmute_bytes_to_str = "warn" @@ -93,7 +98,7 @@ transmute_ptr_to_ref = "warn" transmute_undefined_repr = "warn" transmutes_expressible_as_ptr_casts = "warn" trivially_copy_pass_by_ref = "deny" -unnecessary-wraps = "warn" +unnecessary_wraps = "warn" useless_transmute = "warn" wildcard_dependencies = "warn" @@ -110,6 +115,7 @@ priority = 0 check-cfg = [ "cfg(icu4c_enable_renaming)", "cfg(needs_alloc_error_handler)", + "cfg(icu4x_nightly_tests)", "cfg(icu4x_run_size_tests)", "cfg(icu4x_unstable_fast_trie_only)", ] diff --git a/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml.orig b/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml.orig index 159715434496..a1dffb4be427 100644 --- a/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml.orig +++ b/deps/crates/vendor/yoke-derive-v0_8/Cargo.toml.orig @@ -5,14 +5,15 @@ [package] name = "yoke-derive" description = "Custom derive for the yoke crate" -version = "0.8.2" +version = "0.8.4" categories = ["data-structures", "memory-management", "caching", "no-std"] keywords = ["macros", "derive", "zero-copy", "serialization", "self-referential"] authors = ["Manish Goregaokar <manishsmail@gmail.com>"] -edition.workspace = true +edition = "2021" license.workspace = true repository.workspace = true +rust-version = "1.82" [package.metadata.workspaces] independent = true @@ -24,12 +25,12 @@ path = "src/lib.rs" [dependencies] proc-macro2 = { workspace = true } quote = { workspace = true } -syn = { workspace = true, features = ["fold"] } +syn = { workspace = true, features = ["fold", "visit"] } synstructure = { workspace = true } [dev-dependencies] yoke = { path = "..", features = ["derive"] } -zerovec = { path = "../../../utils/zerovec", features = ["yoke", "alloc"] } +zerovec = { path = "../../../utils/zerovec", features = ["alloc", "yoke"] } [lints] workspace = true diff --git a/deps/crates/vendor/yoke-derive-v0_8/src/lib.rs b/deps/crates/vendor/yoke-derive-v0_8/src/lib.rs index feb8db6ef842..476074767a55 100644 --- a/deps/crates/vendor/yoke-derive-v0_8/src/lib.rs +++ b/deps/crates/vendor/yoke-derive-v0_8/src/lib.rs @@ -81,7 +81,6 @@ fn yokeable_derive_impl(input: &DeriveInput) -> TokenStream2 { GenericParam::Type(ty) => { // Strip out param defaults, we don't need them in the impl let mut ty = ty.clone(); - ty.eq_token = None; ty.default = None; Some(GenericParam::Type(ty)) } @@ -198,9 +197,7 @@ fn yokeable_derive_impl(input: &DeriveInput) -> TokenStream2 { // All usages of the `check_*` functions are above this point, // in order to ensure that `yoke_lt` is correct. let (yoke_lt, bound_lt) = { - let underscores = vec![b'_'; underscores_for_lt]; - #[expect(clippy::expect_used, reason = "invariant is ensured immediately above")] - let underscores = core::str::from_utf8(&underscores).expect("_ is ASCII and thus UTF-8"); + let underscores = "_".repeat(underscores_for_lt); ( format!("'{underscores}yoke"), format!("'_{underscores}yoke"), diff --git a/deps/crates/vendor/yoke-v0_8/.cargo_vcs_info.json b/deps/crates/vendor/yoke-v0_8/.cargo_vcs_info.json index 337747e19e55..d46de6c83a41 100644 --- a/deps/crates/vendor/yoke-v0_8/.cargo_vcs_info.json +++ b/deps/crates/vendor/yoke-v0_8/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "a954ec29392c0225453404cb1f6a77f0ded27089" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "utils/yoke" } \ No newline at end of file diff --git a/deps/crates/vendor/yoke-v0_8/Cargo.lock b/deps/crates/vendor/yoke-v0_8/Cargo.lock index f68d17e841a7..6da58762e86f 100644 --- a/deps/crates/vendor/yoke-v0_8/Cargo.lock +++ b/deps/crates/vendor/yoke-v0_8/Cargo.lock @@ -32,27 +32,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -60,18 +60,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", @@ -86,9 +86,9 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.117" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", @@ -108,18 +108,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", @@ -128,13 +128,13 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" dependencies = [ "bincode", "postcard", @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", diff --git a/deps/crates/vendor/yoke-v0_8/Cargo.toml b/deps/crates/vendor/yoke-v0_8/Cargo.toml index eeafbf1378e0..0a6163ca404d 100644 --- a/deps/crates/vendor/yoke-v0_8/Cargo.toml +++ b/deps/crates/vendor/yoke-v0_8/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.82" name = "yoke" -version = "0.8.3" +version = "0.8.4" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] build = false include = [ @@ -91,7 +91,7 @@ version = "1.2.0" default-features = false [dependencies.yoke-derive] -version = "0.8.2" +version = "0.8.4" optional = true default-features = false @@ -112,9 +112,9 @@ version = "1.0.220" default-features = false [lints.clippy] -alloc-instead-of-core = "warn" -bool-assert-comparison = "allow" -branches-sharing-code = "warn" +alloc_instead_of_core = "warn" +bool_assert_comparison = "allow" +branches_sharing_code = "warn" collection_is_never_read = "warn" crosspointer_transmute = "warn" dbg_macro = "warn" @@ -129,7 +129,7 @@ mismatching_type_param_order = "warn" missing_fields_in_debug = "warn" missing_transmute_annotations = "warn" negative_feature_names = "warn" -or-fun-call = "warn" +or_fun_call = "warn" same_functions_in_if_condition = "warn" todo = "warn" transmute_bytes_to_str = "warn" @@ -140,7 +140,7 @@ transmute_ptr_to_ref = "warn" transmute_undefined_repr = "warn" transmutes_expressible_as_ptr_casts = "warn" trivially_copy_pass_by_ref = "deny" -unnecessary-wraps = "warn" +unnecessary_wraps = "warn" useless_transmute = "warn" wildcard_dependencies = "warn" @@ -157,6 +157,7 @@ priority = 0 check-cfg = [ "cfg(icu4c_enable_renaming)", "cfg(needs_alloc_error_handler)", + "cfg(icu4x_nightly_tests)", "cfg(icu4x_run_size_tests)", "cfg(icu4x_unstable_fast_trie_only)", ] diff --git a/deps/crates/vendor/yoke-v0_8/Cargo.toml.orig b/deps/crates/vendor/yoke-v0_8/Cargo.toml.orig index bc644c8c39a1..8edbcebb030f 100644 --- a/deps/crates/vendor/yoke-v0_8/Cargo.toml.orig +++ b/deps/crates/vendor/yoke-v0_8/Cargo.toml.orig @@ -5,7 +5,7 @@ [package] name = "yoke" description = "Abstraction allowing borrowed data to be carried along with the backing data it borrows from" -version = "0.8.3" +version = "0.8.4" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] categories = ["data-structures", "memory-management", "caching", "no-std"] keywords = ["zero-copy", "serialization", "memory-efficiency", "self-referential"] diff --git a/deps/crates/vendor/yoke-v0_8/src/cartable_ptr.rs b/deps/crates/vendor/yoke-v0_8/src/cartable_ptr.rs index f220329ed422..de0e9493e9a5 100644 --- a/deps/crates/vendor/yoke-v0_8/src/cartable_ptr.rs +++ b/deps/crates/vendor/yoke-v0_8/src/cartable_ptr.rs @@ -156,13 +156,12 @@ unsafe impl<T> CartablePointerLike for Box<T> { #[inline] fn into_raw(self) -> NonNull<T> { - // Safety: `Box::into_raw` says: "The pointer will be properly aligned and non-null." - unsafe { NonNull::new_unchecked(Box::into_raw(self)) } + NonNull::from(Box::leak(self)) } #[inline] unsafe fn drop_raw(pointer: NonNull<T>) { // Safety: per the method's precondition, `pointer` is dereferenceable and was returned by - // `Self::into_raw`, i.e. by `Box::into_raw`. In this circumstances, calling + // `Self::into_raw`, i.e. by `Box::leak`. In this circumstances, calling // `Box::from_raw` is safe. let _box = unsafe { Box::from_raw(pointer.as_ptr()) }; diff --git a/deps/crates/vendor/yoke-v0_8/src/yoke.rs b/deps/crates/vendor/yoke-v0_8/src/yoke.rs index 96e079d9b345..6d21abece74a 100644 --- a/deps/crates/vendor/yoke-v0_8/src/yoke.rs +++ b/deps/crates/vendor/yoke-v0_8/src/yoke.rs @@ -154,6 +154,16 @@ where } } +impl<T: ?Sized, Y, C> AsRef<T> for Yoke<Y, C> +where + Y: for<'a> Yokeable<'a>, + for<'a> <Y as Yokeable<'a>>::Output: AsRef<T>, +{ + fn as_ref(&self) -> &T { + self.get().as_ref() + } +} + #[test] fn test_debug() { let local_data = "foo".to_owned(); @@ -212,6 +222,19 @@ fn test_partialord_ord() { assert_eq!(y1.partial_cmp(&y2), Some(core::cmp::Ordering::Less)); } +#[test] +fn test_as_ref() { + let a = Rc::new("hello".to_string()); + + let y1 = Yoke::<&str, Rc<String>>::attach_to_zero_copy_cart(Rc::clone(&a)); + let y2 = Yoke::<alloc::borrow::Cow<'_, str>, Rc<String>>::attach_to_zero_copy_cart(a); + let y3 = Yoke::<Vec<u8>, ()>::new_always_owned(vec![1, 2, 3]); + + assert_eq!(AsRef::<str>::as_ref(&y1), "hello"); + assert_eq!(AsRef::<str>::as_ref(&y2), "hello"); + assert_eq!(AsRef::<[u8]>::as_ref(&y3), [1, 2, 3]); +} + impl<Y: for<'a> Yokeable<'a>, C: StableDeref> Yoke<Y, C> where <C as Deref>::Target: 'static, @@ -902,14 +925,14 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> { /// # } /// # /// # unsafe fn make(from: Bar<'a>) -> Self { - /// # unsafe { mem::transmute(from) } + /// # unsafe { mem::transmute::<Self::Output, Self>(from) } /// # } /// # /// # fn transform_mut<F>(&'a mut self, f: F) /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { - /// # unsafe { f(mem::transmute(self)) } + /// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// ``` @@ -1009,14 +1032,14 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> { /// # } /// # /// # unsafe fn make(from: Bar<'a>) -> Self { - /// # unsafe { mem::transmute(from) } + /// # unsafe { mem::transmute::<Self::Output, Self>(from) } /// # } /// # /// # fn transform_mut<F>(&'a mut self, f: F) /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { - /// # unsafe { f(mem::transmute(self)) } + /// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// ``` @@ -1258,14 +1281,14 @@ where /// # } /// # /// # unsafe fn make(from: Foo<'a>) -> Self { - /// # unsafe { mem::transmute(from) } + /// # unsafe { mem::transmute::<Self::Output, Self>(from) } /// # } /// # /// # fn transform_mut<F>(&'a mut self, f: F) /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { - /// # unsafe { f(mem::transmute(self)) } + /// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// # @@ -1281,14 +1304,14 @@ where /// # } /// # /// # unsafe fn make(from: Bar<'a>) -> Self { - /// # unsafe { mem::transmute(from) } + /// # unsafe { mem::transmute::<Self::Output, Self>(from) } /// # } /// # /// # fn transform_mut<F>(&'a mut self, f: F) /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { - /// # unsafe { f(mem::transmute(self)) } + /// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// ``` @@ -1703,7 +1726,7 @@ impl<Y: for<'a> Yokeable<'a>, C> Yoke<Y, C> { /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { -/// # unsafe { f(mem::transmute(self)) } +/// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// ``` @@ -1986,7 +2009,7 @@ const _: () = (); /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { -/// # unsafe { f(mem::transmute(self)) } +/// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// ``` @@ -2081,6 +2104,7 @@ const _: () = (); /// /// type Contra<'a> = fn(&'a ()); /// +/// #[allow(clippy::extra_unused_lifetimes)] /// fn scope<'b>() { /// let local = String::from("Hello World!"); /// let yoke: Yoke<&'static str, Option<Rc<Contra<'b>>>> = Yoke::new_owned("hi"); @@ -2097,6 +2121,7 @@ const _: () = (); /// /// type Contra<'a> = fn(&'a ()); /// +/// #[allow(clippy::extra_unused_lifetimes)] /// fn scope<'b>() { /// let local = String::from("Hello World!"); /// let yoke: Yoke<&'static str, Option<Rc<Contra<'b>>>> = diff --git a/deps/crates/vendor/yoke-v0_8/src/yokeable.rs b/deps/crates/vendor/yoke-v0_8/src/yokeable.rs index 49d5fd15d6cc..fd27cf95194f 100644 --- a/deps/crates/vendor/yoke-v0_8/src/yokeable.rs +++ b/deps/crates/vendor/yoke-v0_8/src/yokeable.rs @@ -194,7 +194,7 @@ pub unsafe trait Yokeable<'a>: 'static { /// # where /// # F: 'static + FnOnce(&'a mut Self::Output), /// # { - /// # unsafe { f(mem::transmute(self)) } + /// # unsafe { f(mem::transmute::<&mut Self, &mut Self::Output>(self)) } /// # } /// # } /// ``` diff --git a/deps/crates/vendor/zerofrom-derive-v0_1/.cargo_vcs_info.json b/deps/crates/vendor/zerofrom-derive-v0_1/.cargo_vcs_info.json index 58f5a56738dd..87493b0d045d 100644 --- a/deps/crates/vendor/zerofrom-derive-v0_1/.cargo_vcs_info.json +++ b/deps/crates/vendor/zerofrom-derive-v0_1/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "c9fac4e625ccb2c6a7aa35079fff9709db4385ac" + "sha1": "ce235d80cf7cbd028e8bd59920420e1203b205b3" }, "path_in_vcs": "utils/zerofrom/derive" } \ No newline at end of file diff --git a/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.lock b/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.lock index c784667bac7e..3a58b330dba5 100644 --- a/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.lock +++ b/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.lock @@ -4,27 +4,27 @@ version = 3 [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "syn" -version = "2.0.117" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", @@ -50,7 +50,7 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" dependencies = [ "proc-macro2", "quote", diff --git a/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml b/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml index d550ded8c1cd..cc9465f2e713 100644 --- a/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml +++ b/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.71.1" name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] build = false autolib = false @@ -57,17 +57,21 @@ version = "1.0.61" version = "1.0.44" [dependencies.syn] -version = "2.0.21" -features = ["fold"] +version = "3.0" +features = [ + "fold", + "visit", +] [dependencies.synstructure] -version = "0.13.0" +version = "0.14.0" [dev-dependencies] [lints.clippy] -alloc-instead-of-core = "warn" -branches-sharing-code = "warn" +alloc_instead_of_core = "warn" +bool_assert_comparison = "allow" +branches_sharing_code = "warn" collection_is_never_read = "warn" crosspointer_transmute = "warn" dbg_macro = "warn" @@ -82,7 +86,7 @@ mismatching_type_param_order = "warn" missing_fields_in_debug = "warn" missing_transmute_annotations = "warn" negative_feature_names = "warn" -or-fun-call = "warn" +or_fun_call = "warn" same_functions_in_if_condition = "warn" todo = "warn" transmute_bytes_to_str = "warn" @@ -93,7 +97,7 @@ transmute_ptr_to_ref = "warn" transmute_undefined_repr = "warn" transmutes_expressible_as_ptr_casts = "warn" trivially_copy_pass_by_ref = "deny" -unnecessary-wraps = "warn" +unnecessary_wraps = "warn" useless_transmute = "warn" wildcard_dependencies = "warn" @@ -110,6 +114,7 @@ priority = 0 check-cfg = [ "cfg(icu4c_enable_renaming)", "cfg(needs_alloc_error_handler)", + "cfg(icu4x_nightly_tests)", "cfg(icu4x_run_size_tests)", "cfg(icu4x_unstable_fast_trie_only)", ] diff --git a/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml.orig b/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml.orig index fa89857ff060..36be4881b8c2 100644 --- a/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml.orig +++ b/deps/crates/vendor/zerofrom-derive-v0_1/Cargo.toml.orig @@ -5,12 +5,12 @@ [package] name = "zerofrom-derive" description = "Custom derive for the zerofrom crate" -version = "0.1.7" +version = "0.1.8" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] categories = ["data-structures", "memory-management", "caching", "no-std"] keywords = ["macros", "derive", "zero-copy", "serialization"] -edition.workspace = true +edition = "2021" license.workspace = true repository.workspace = true rust-version = "1.71.1" @@ -25,12 +25,12 @@ path = "src/lib.rs" [dependencies] proc-macro2 = { workspace = true } quote = { workspace = true } -syn = { workspace = true, features = ["fold"] } +syn = { workspace = true, features = ["fold", "visit"] } synstructure = { workspace = true } [dev-dependencies] zerofrom = { path = "..", features = ["derive"]} -zerovec = { path = "../../../utils/zerovec", features = ["yoke"] } +zerovec = { path = "../../../utils/zerovec", features = ["alloc", "yoke"] } [lints] workspace = true diff --git a/deps/crates/vendor/zerofrom-derive-v0_1/src/lib.rs b/deps/crates/vendor/zerofrom-derive-v0_1/src/lib.rs index 060b961c8ca5..c33d3a5d3ec8 100644 --- a/deps/crates/vendor/zerofrom-derive-v0_1/src/lib.rs +++ b/deps/crates/vendor/zerofrom-derive-v0_1/src/lib.rs @@ -25,8 +25,8 @@ use syn::fold::{self, Fold}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - parse_macro_input, parse_quote, DeriveInput, Ident, Lifetime, MetaList, Token, - TraitBoundModifier, Type, TypeParamBound, TypePath, WherePredicate, + parse_macro_input, parse_quote, DeriveInput, Ident, Lifetime, MetaList, Token, Type, + TypeParamBound, TypePath, WherePredicate, }; use synstructure::Structure; mod visitor; @@ -91,7 +91,6 @@ fn zf_derive_impl(input: &DeriveInput) -> TokenStream2 { .map(|ty| { // Strip out param defaults, we don't need them in the impl let mut ty = ty.clone(); - ty.eq_token = None; ty.default = None; ty }) @@ -128,11 +127,10 @@ fn zf_derive_impl(input: &DeriveInput) -> TokenStream2 { // Remove `?Sized`` bound because we need a param to be Sized in order to take a ZeroFrom of it. // This only applies to fields marked as `may_borrow`. let mut bounds = core::mem::take(&mut param.bounds); - while let Some(bound_pair) = bounds.pop() { - let bound = bound_pair.into_value(); + while let Some(bound) = bounds.pop() { if let TypeParamBound::Trait(ref trait_bound) = bound { if trait_bound.path.get_ident().map(|ident| ident == "Sized") == Some(true) - && matches!(trait_bound.modifier, TraitBoundModifier::Maybe(_)) + && trait_bound.maybe.is_some() { continue; } diff --git a/deps/crates/vendor/zerovec-derive-v0_11/.cargo_vcs_info.json b/deps/crates/vendor/zerovec-derive-v0_11/.cargo_vcs_info.json index c3c6c52ad842..8d63e9ff1b29 100644 --- a/deps/crates/vendor/zerovec-derive-v0_11/.cargo_vcs_info.json +++ b/deps/crates/vendor/zerovec-derive-v0_11/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "898d79c69f37da7b45a15a5714663c9b59b3d928" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "utils/zerovec/derive" } \ No newline at end of file diff --git a/deps/crates/vendor/zerovec-derive-v0_11/Cargo.lock b/deps/crates/vendor/zerovec-derive-v0_11/Cargo.lock index 76debd400d9d..457889d60d4a 100644 --- a/deps/crates/vendor/zerovec-derive-v0_11/Cargo.lock +++ b/deps/crates/vendor/zerovec-derive-v0_11/Cargo.lock @@ -73,9 +73,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -86,9 +86,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -97,13 +97,13 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "zerovec-derive" -version = "0.11.6" +version = "0.11.7" dependencies = [ "bincode", "proc-macro2", diff --git a/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml b/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml index e07f10fe2623..ac416f717a64 100644 --- a/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml +++ b/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml @@ -11,8 +11,9 @@ [package] edition = "2021" +rust-version = "1.83" name = "zerovec-derive" -version = "0.11.6" +version = "0.11.7" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] build = false autolib = false diff --git a/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml.orig b/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml.orig index d4a37fbc140c..5018839ebcb5 100644 --- a/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml.orig +++ b/deps/crates/vendor/zerovec-derive-v0_11/Cargo.toml.orig @@ -5,7 +5,7 @@ [package] name = "zerovec-derive" description = "Custom derive for the zerovec crate" -version = "0.11.6" +version = "0.11.7" authors = ["Manish Goregaokar <manishsmail@gmail.com>"] categories = ["rust-patterns", "memory-management", "caching", "no-std", "data-structures"] keywords = ["macros", "derive", "serialization", "zero-copy"] @@ -13,6 +13,7 @@ keywords = ["macros", "derive", "serialization", "zero-copy"] edition = "2021" license.workspace = true repository.workspace = true +rust-version = "1.83" [package.metadata.workspaces] independent = true diff --git a/deps/crates/vendor/zerovec-derive-v0_11/src/varule.rs b/deps/crates/vendor/zerovec-derive-v0_11/src/varule.rs index 58ccf58fd0e9..b4da7e4a4649 100644 --- a/deps/crates/vendor/zerovec-derive-v0_11/src/varule.rs +++ b/deps/crates/vendor/zerovec-derive-v0_11/src/varule.rs @@ -112,7 +112,18 @@ pub fn derive_impl( Ok(()) } #[inline] + #[allow(clippy::transmute_undefined_repr, reason = "This is the only way to do this until ptr metadata stabilizes")] unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { + #[repr(C)] + struct FatPtr{ + ptr: usize, + metadata: usize + } + const { + assert!(::core::mem::size_of::<FatPtr>() == ::core::mem::size_of::<&#unsized_field>()); + assert!(::core::mem::align_of::<FatPtr>() == ::core::mem::align_of::<&#unsized_field>()); + } + // just the unsized part // Safety: The invariants of this function allow us to assume bytes is valid, and // having at least #ule_size bytes is a validity constraint for the ULE type. @@ -120,7 +131,7 @@ pub fn derive_impl( let unsized_ref = <#unsized_field as zerovec::ule::VarULE>::from_bytes_unchecked(unsized_bytes); // We should use the pointer metadata APIs here when they are stable: https://github.com/rust-lang/rust/issues/81513 // For now we rely on all DST metadata being a usize to extract it via a fake slice pointer - let (_ptr, metadata) = ::core::mem::transmute::<&#unsized_field, (usize, usize)>(unsized_ref); + let FatPtr{metadata, ..} = ::core::mem::transmute::<&#unsized_field, FatPtr>(unsized_ref); let entire_struct_as_slice: *const [u8] = ::core::ptr::slice_from_raw_parts(bytes.as_ptr(), metadata); &*(entire_struct_as_slice as *const Self) } diff --git a/deps/crates/vendor/zerovec-v0_11/.cargo_vcs_info.json b/deps/crates/vendor/zerovec-v0_11/.cargo_vcs_info.json index b1271c28daa6..4784f75481c4 100644 --- a/deps/crates/vendor/zerovec-v0_11/.cargo_vcs_info.json +++ b/deps/crates/vendor/zerovec-v0_11/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "c56bbb5a7b47409759113903764c456f13b418e5" + "sha1": "031d9e89f6a3fd26a14491e090729d46094328fd" }, "path_in_vcs": "utils/zerovec" } \ No newline at end of file diff --git a/deps/crates/vendor/zerovec-v0_11/Cargo.lock b/deps/crates/vendor/zerovec-v0_11/Cargo.lock index a3c761fbd560..974092e476dc 100644 --- a/deps/crates/vendor/zerovec-v0_11/Cargo.lock +++ b/deps/crates/vendor/zerovec-v0_11/Cargo.lock @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.13.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "bumpalo" @@ -64,9 +64,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "ciborium" @@ -97,18 +97,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstyle", "clap_lex", @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "0e78417baa3b3114dc0e95e7357389a249c4da97c3c2b540700079db6171bfd7" [[package]] name = "cobs" @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.4" +version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" dependencies = [ "encode_unicode", "libc", @@ -178,9 +178,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -188,18 +188,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.20" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -220,13 +220,13 @@ dependencies = [ [[package]] name = "databake-derive" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b537745234cbf0e296a3bd836d70a614dff4cb522b14e2680ef006bb1ed5ff" +checksum = "495503291b258422ea2bb9863d9f4e31eadbc5bcbdbe8b721769fa2c98dc4d41" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -238,9 +238,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "embedded-io" @@ -302,9 +302,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "iai" @@ -314,9 +314,9 @@ checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678" [[package]] name = "insta" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" +checksum = "b67d3d2e287e4b86c10b3f3b641033d1f89b74bdb39d05f34952e2b9a6fe21cd" dependencies = [ "console", "once_cell", @@ -363,9 +363,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.189" +version = "0.2.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" [[package]] name = "libm" @@ -556,22 +556,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] @@ -627,9 +627,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ "bitflags", "errno", @@ -655,9 +655,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +checksum = "ab508826f74a77ca9d5aba6ff19b522583ee3eaf28a19384ff3d0e5835fadf6e" dependencies = [ "dyn-clone", "ref-cast", @@ -692,14 +692,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -733,9 +733,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.3" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -744,13 +744,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] [[package]] @@ -783,7 +783,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] @@ -798,15 +798,15 @@ dependencies = [ [[package]] name = "twox-hash" -version = "2.1.3" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8464ec13c3691491391d9fce00f6416c9a48e46972f72d7865688be2080192c9" +checksum = "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "walkdir" @@ -914,9 +914,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -925,30 +925,30 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.56" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.56" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", @@ -966,19 +966,19 @@ dependencies = [ [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerovec" -version = "0.11.8" +version = "0.11.9" dependencies = [ "bincode", "criterion", @@ -1002,13 +1002,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.5" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f212a141d820099d57ffafb9569be9617a6f27d3dc881fbee8fb56642f917a9" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.3", + "syn 3.0.9", ] [[package]] diff --git a/deps/crates/vendor/zerovec-v0_11/Cargo.toml b/deps/crates/vendor/zerovec-v0_11/Cargo.toml index a99a3e4e6f62..1746eb613133 100644 --- a/deps/crates/vendor/zerovec-v0_11/Cargo.toml +++ b/deps/crates/vendor/zerovec-v0_11/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.83" name = "zerovec" -version = "0.11.8" +version = "0.11.9" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -140,7 +140,7 @@ optional = true default-features = false [dependencies.yoke] -version = "0.8.3" +version = "0.8.4" optional = true default-features = false @@ -149,7 +149,7 @@ version = "0.1.6" default-features = false [dependencies.zerovec-derive] -version = "0.11.5" +version = "0.11.7" optional = true default-features = false @@ -193,7 +193,7 @@ default-features = false version = "1.0.45" [dev-dependencies.yoke] -version = "0.8.3" +version = "0.8.4" features = ["derive"] default-features = false diff --git a/deps/crates/vendor/zerovec-v0_11/Cargo.toml.orig b/deps/crates/vendor/zerovec-v0_11/Cargo.toml.orig index 9f0fb7ebc3a5..8d1cc0fa39d2 100644 --- a/deps/crates/vendor/zerovec-v0_11/Cargo.toml.orig +++ b/deps/crates/vendor/zerovec-v0_11/Cargo.toml.orig @@ -5,7 +5,7 @@ [package] name = "zerovec" description = "Zero-copy vector backed by a byte array" -version = "0.11.8" +version = "0.11.9" categories = ["rust-patterns", "memory-management", "caching", "no-std", "data-structures"] keywords = ["zero-copy", "serialization", "memory-efficiency", "serde"] diff --git a/deps/crates/vendor/zerovec-v0_11/src/lib.rs b/deps/crates/vendor/zerovec-v0_11/src/lib.rs index 5e9865bf400d..d710e8c0b7bd 100644 --- a/deps/crates/vendor/zerovec-v0_11/src/lib.rs +++ b/deps/crates/vendor/zerovec-v0_11/src/lib.rs @@ -576,7 +576,7 @@ mod tests { #[test] fn test_miri_repro_eyepatch_hack_truncate() { let slice: &[u16] = &[1, 2, 3, 4]; - let zv: ZeroVec<u16> = ZeroVec::try_from_slice(slice).unwrap(); + let zv: ZeroVec<u16> = ZeroVec::from_slice_or_alloc(slice); let _truncated = zv.truncated(2); } diff --git a/deps/crates/vendor/zerovec-v0_11/src/map2d/map.rs b/deps/crates/vendor/zerovec-v0_11/src/map2d/map.rs index cf5f253a130b..60c8398982b9 100644 --- a/deps/crates/vendor/zerovec-v0_11/src/map2d/map.rs +++ b/deps/crates/vendor/zerovec-v0_11/src/map2d/map.rs @@ -20,9 +20,9 @@ use crate::map::{MutableZeroVecLike, ZeroVecLike}; /// This is an extension of [`ZeroMap`] that supports two layers of keys. For example, /// to map a pair of an integer and a string to a buffer, you can write: /// -/// ```no_run +/// ``` /// # use zerovec::ZeroMap2d; -/// let _: ZeroMap2d<u32, str, [u8]> = unimplemented!(); +/// ZeroMap2d::<u32, str, [u8]>::new(); /// ``` /// /// Internally, `ZeroMap2d` stores four zero-copy vectors, one for each type argument plus diff --git a/deps/crates/vendor/zerovec-v0_11/src/ule/custom.rs b/deps/crates/vendor/zerovec-v0_11/src/ule/custom.rs index 2862d9e05281..c8118ca78ecb 100644 --- a/deps/crates/vendor/zerovec-v0_11/src/ule/custom.rs +++ b/deps/crates/vendor/zerovec-v0_11/src/ule/custom.rs @@ -123,8 +123,8 @@ //! where //! D: serde::Deserializer<'de>, //! { -//! let mut foo = Foo::deserialize(deserializer)?; -//! Ok(encode_varule_to_box(&foo)) +//! let deserialized = Foo::deserialize(deserializer)?; +//! Ok(encode_varule_to_box(&deserialized)) //! } //! } //! diff --git a/deps/crates/vendor/zerovec-v0_11/src/ule/mod.rs b/deps/crates/vendor/zerovec-v0_11/src/ule/mod.rs index b4c86d777d52..49978f2a6653 100644 --- a/deps/crates/vendor/zerovec-v0_11/src/ule/mod.rs +++ b/deps/crates/vendor/zerovec-v0_11/src/ule/mod.rs @@ -246,8 +246,8 @@ where /// If you need to implement this trait, consider using [`#[make_varule]`](crate::make_varule) or /// [`#[derive(VarULE)]`](macro@VarULE) instead. /// -/// This trait is mostly for unsized types like `str` and `[T]`. It can be implemented on sized types; -/// however, it is much more preferable to use [`ULE`] for that purpose. The [`custom`] module contains +/// This trait is for unsized types like `str` and `[T]`. For sized types use [`ULE`] instead. +/// The [`custom`] module contains /// additional documentation on how this type can be implemented on custom types. /// /// If deserialization with `VarZeroVec` is desired is recommended to implement `Deserialize` for @@ -271,6 +271,8 @@ where /// 6. All other methods *must* be left with their default impl, or else implemented according to /// their respective safety guidelines. /// 7. Acknowledge the following note about the equality invariant. +/// 8. The type **must** be a unsized, slice like type. Specifically this trait requires that a fat +/// pointer to this type is represented by the pointer to the first element and the number of elements. /// /// If the ULE type is a struct only containing other ULE/VarULE types (or other types which satisfy invariants 1 and 2, /// like `[u8; N]`), invariants 1 and 2 can be achieved via `#[repr(C, packed)]` or `#[repr(transparent)]`. @@ -445,6 +447,13 @@ impl UleError { impl core::error::Error for UleError {} +#[cfg(feature = "alloc")] +#[repr(C)] +struct DstMetadata<Ptr> { + ptr: Ptr, + metadata: usize, +} + #[cfg(feature = "alloc")] /// Reconstructs a `Box<T>` from a `Box<[u8]>` while preserving unique pointer provenance /// and correctly resolving DST metadata. @@ -469,20 +478,30 @@ impl core::error::Error for UleError {} /// - `T::from_bytes_unchecked` must be safe to call on the slice behind bytes pub(crate) unsafe fn cast_box<T: VarULE + ?Sized>(bytes: Box<[u8]>) -> Box<T> { use core::alloc::Layout; + + const { + assert!(size_of::<&T>() == size_of::<DstMetadata<*const u8>>()); + assert!(size_of::<&T>() == size_of::<DstMetadata<*mut u8>>()); + let expected_layout = Layout::new::<&[u8]>(); + let actual_layout = Layout::new::<&T>(); + assert!(expected_layout.size() == actual_layout.size()); + assert!(expected_layout.align() == actual_layout.align()); + } let raw = Box::into_raw(bytes); // SAFETY: we just produced `raw`; it is valid let slice: &[u8] = unsafe { &*raw }; // SAFETY: caller guarantees `from_bytes_unchecked` is safe. let ref_t: &T = unsafe { T::from_bytes_unchecked(slice) }; - // Extract metadata from ref_t. - debug_assert_eq!(size_of::<&T>(), size_of::<(*const u8, usize)>()); - let (_, metadata) = unsafe { core::mem::transmute_copy::<&T, (*const u8, usize)>(&ref_t) }; + let DstMetadata { metadata, .. } = + unsafe { core::mem::transmute_copy::<&T, DstMetadata<*const u8>>(&ref_t) }; // Construct *mut T from (raw_data_ptr, metadata). - debug_assert_eq!(size_of::<*mut T>(), size_of::<(*mut u8, usize)>()); let ptr: *mut T = unsafe { - core::mem::transmute_copy::<(*mut u8, usize), *mut T>(&(raw.cast::<u8>(), metadata)) + core::mem::transmute_copy::<DstMetadata<*mut u8>, *mut T>(&DstMetadata { + ptr: raw.cast::<u8>(), + metadata, + }) }; let expected_layout = Layout::for_value(slice); diff --git a/deps/crates/vendor/zerovec-v0_11/src/ule/slices.rs b/deps/crates/vendor/zerovec-v0_11/src/ule/slices.rs index 51ea1a542b7e..16164d3716f2 100644 --- a/deps/crates/vendor/zerovec-v0_11/src/ule/slices.rs +++ b/deps/crates/vendor/zerovec-v0_11/src/ule/slices.rs @@ -70,18 +70,18 @@ unsafe impl VarULE for str { /// Note: [`VarULE`] is well-defined for all `[T] where T: ULE`, but [`ZeroSlice`] is more ergonomic /// when `T` is a low-level ULE type. For example: /// -/// ```no_run +/// ``` /// # use zerovec::ZeroSlice; /// # use zerovec::VarZeroVec; /// # use zerovec::ule::AsULE; /// // OK: [u8] is a useful type -/// let _: VarZeroVec<[u8]> = unimplemented!(); +/// VarZeroVec::<[u8]>::new(); /// /// // Technically works, but [u32::ULE] is not very useful -/// let _: VarZeroVec<[<u32 as AsULE>::ULE]> = unimplemented!(); +/// VarZeroVec::<[<u32 as AsULE>::ULE]>::new(); /// /// // Better: ZeroSlice<u32> -/// let _: VarZeroVec<ZeroSlice<u32>> = unimplemented!(); +/// VarZeroVec::<ZeroSlice<u32>>::new(); /// ``` /// /// [`ZeroSlice`]: crate::ZeroSlice diff --git a/deps/crates/vendor/zerovec-v0_11/src/varzerovec/owned.rs b/deps/crates/vendor/zerovec-v0_11/src/varzerovec/owned.rs index 1a2a15bdb886..44be5d865c6f 100644 --- a/deps/crates/vendor/zerovec-v0_11/src/varzerovec/owned.rs +++ b/deps/crates/vendor/zerovec-v0_11/src/varzerovec/owned.rs @@ -494,21 +494,36 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> { } let value_len = element.encode_var_ule_len(); + assert!(value_len < F::Index::MAX_VALUE as usize); if len == 0 { let header_len = F::Len::SIZE; // Index array is size 0 for len = 1 let cap = header_len + value_len; - self.entire_slice.resize(cap, 0); - self.entire_slice[0] = 1; // set length - element.encode_var_ule_write(&mut self.entire_slice[header_len..]); + let guard = ClearOnPanic(self); + guard.0.entire_slice.resize(cap, 0); + guard.0.entire_slice[0] = 1; // set length + element.encode_var_ule_write(&mut guard.0.entire_slice[header_len..]); + debug_assert_eq!( + T::validate_bytes(&guard.0.entire_slice[header_len..]), + Ok(()) + ); + core::mem::forget(guard); return; } - assert!(value_len < F::Index::MAX_VALUE as usize); + let guard = ClearOnPanic(self); + // SAFETY: + // - `index <= self.len()` is checked above (`ShiftType::Insert` allows `index == self.len()`). + // - `value_len < F::Index::MAX_VALUE` is asserted above, and `shift` checks that the + // total grown slice length fits within `F::Index::MAX_VALUE`. + // - `guard` clears `entire_slice` if `shift` or `encode_var_ule_write` panics, + // preventing partially-mutated state from being observed after unwinding. unsafe { - let place = self.shift(index, value_len, ShiftType::Insert); + let place = guard.0.shift(index, value_len, ShiftType::Insert); element.encode_var_ule_write(place); + debug_assert_eq!(T::validate_bytes(place), Ok(())); } + core::mem::forget(guard); } /// Remove the element at index `idx` @@ -522,9 +537,15 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> { self.entire_slice.clear(); return; } + let guard = ClearOnPanic(self); + // SAFETY: + // - `index < self.len()` is checked above. + // - `new_size` is 0, so the data segment does not grow. + // - `guard` clears `entire_slice` if `shift` panics. unsafe { - self.shift(index, 0, ShiftType::Remove); + guard.0.shift(index, 0, ShiftType::Remove); } + core::mem::forget(guard); } /// Replace the element at index `idx` with another @@ -537,10 +558,30 @@ impl<T: VarULE + ?Sized, F: VarZeroVecFormat> VarZeroVecOwned<T, F> { let value_len = element.encode_var_ule_len(); assert!(value_len < F::Index::MAX_VALUE as usize); + let guard = ClearOnPanic(self); + // SAFETY: + // - `index < self.len()` is checked above. + // - `value_len < F::Index::MAX_VALUE` is asserted above, and `shift` checks that the + // total grown slice length fits within `F::Index::MAX_VALUE`. + // - `guard` clears `entire_slice` if `shift` or `encode_var_ule_write` panics, + // preventing partially-mutated state from being observed after unwinding. unsafe { - let place = self.shift(index, value_len, ShiftType::Replace); + let place = guard.0.shift(index, value_len, ShiftType::Replace); element.encode_var_ule_write(place); + debug_assert_eq!(T::validate_bytes(place), Ok(())); } + core::mem::forget(guard); + } +} + +/// Drop guard that clears `entire_slice` if a panic occurs during an in-place +/// mutation (e.g. inside `shift` or a user-provided `EncodeAsVarULE::encode_var_ule_write`), +/// restoring the safety invariant that `entire_slice` is a valid (empty) `VarZeroVecComponents`. +struct ClearOnPanic<'a, T: ?Sized, F>(&'a mut VarZeroVecOwned<T, F>); + +impl<T: ?Sized, F> Drop for ClearOnPanic<'_, T, F> { + fn drop(&mut self) { + self.0.entire_slice.clear(); } } @@ -720,4 +761,66 @@ mod test { fn test_replace_past_end() { VarZeroVecOwned::<str>::new().replace(0, ""); } + + #[test] + #[cfg(feature = "std")] + fn test_panic_safety() { + use crate::ule::EncodeAsVarULE; + use std::panic::{catch_unwind, AssertUnwindSafe}; + + struct PanicAfterWrite { + invalid: &'static [u8], + } + + // SAFETY: `encode_var_ule_write` always panics and never returns normally, + // so callers must not observe the invalid bytes written before unwinding. + unsafe impl EncodeAsVarULE<str> for PanicAfterWrite { + fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { + cb(&[self.invalid]) + } + + fn encode_var_ule_len(&self) -> usize { + self.invalid.len() + } + + fn encode_var_ule_write(&self, dst: &mut [u8]) { + dst.copy_from_slice(self.invalid); + panic!("encode_var_ule_write panicked after writing invalid bytes"); + } + } + + let panicker = PanicAfterWrite { + invalid: &[0x80, 0xC0, 0xFF], + }; + + // 1. `replace` on non-empty vector + let mut v = VarZeroVecOwned::<str>::try_from_elements(&["hello"]).unwrap(); + let res = catch_unwind(AssertUnwindSafe(|| { + v.replace(0, &panicker); + })); + assert!(res.is_err()); + assert!(v.is_empty()); + assert_eq!(v.get(0), None); + assert!(v.verify_integrity()); + + // 2. `insert` into empty vector (`len == 0` fast-path) + let mut v = VarZeroVecOwned::<str>::new(); + let res = catch_unwind(AssertUnwindSafe(|| { + v.insert(0, &panicker); + })); + assert!(res.is_err()); + assert!(v.is_empty()); + assert_eq!(v.get(0), None); + assert!(v.verify_integrity()); + + // 3. `insert` into non-empty vector (`len > 0` shift path) + let mut v = VarZeroVecOwned::<str>::try_from_elements(&["hello", "world"]).unwrap(); + let res = catch_unwind(AssertUnwindSafe(|| { + v.insert(1, &panicker); + })); + assert!(res.is_err()); + assert!(v.is_empty()); + assert_eq!(v.get(0), None); + assert!(v.verify_integrity()); + } } From 9a23b8498ee50c4a4e4b1cfeee8b1355d25c6c6e Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Tue, 27 Oct 2026 16:53:08 -0400 Subject: [PATCH 3/9] build: reset embedder string to "-node.0" --- common.gypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.gypi b/common.gypi index a8dbd9ba13e4..108e1a6ee6c1 100644 --- a/common.gypi +++ b/common.gypi @@ -50,7 +50,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.10', + 'v8_embedder_string': '-node.0', ##### V8 defaults for Node.js ##### From a9bef34360112fb246739635a14a31094ada333c Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Tue, 27 Oct 2026 16:53:08 -0400 Subject: [PATCH 4/9] src: update NODE_MODULE_VERSION to 155 Major V8 updates are usually API/ABI incompatible with previous versions. This commit adapts NODE_MODULE_VERSION for V8 15.8. Refs: https://github.com/nodejs/CTC/blob/master/meetings/2016-09-28.md --- doc/abi_version_registry.json | 1 + src/node_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/abi_version_registry.json b/doc/abi_version_registry.json index 661dd04c7e69..3716d82440de 100644 --- a/doc/abi_version_registry.json +++ b/doc/abi_version_registry.json @@ -1,5 +1,6 @@ { "NODE_MODULE_VERSION": [ + { "modules": 155, "runtime": "node", "variant": "v8_15.8", "versions": "27.0.0-pre" }, { "modules": 154,"runtime": "electron", "variant": "electron", "versions": "46" }, { "modules": 153, "runtime": "node", "variant": "v8_15.6", "versions": "27.0.0-pre" }, { "modules": 152, "runtime": "node", "variant": "v8_15.5", "versions": "27.0.0-pre" }, diff --git a/src/node_version.h b/src/node_version.h index be30a782e67b..35d0196d9b51 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -105,7 +105,7 @@ #if defined(NODE_EMBEDDER_MODULE_VERSION) #define NODE_MODULE_VERSION NODE_EMBEDDER_MODULE_VERSION #else -#define NODE_MODULE_VERSION 153 +#define NODE_MODULE_VERSION 155 #endif // The NAPI_VERSION supported by the runtime. This is the inclusive range of From ff2f23fe399da8d1287f40d6541a291f942628e1 Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyee@igalia.com> Date: Tue, 13 Oct 2026 13:32:15 +0200 Subject: [PATCH 5/9] deps: V8: cherry-pick 011b2de3051a Original commit message: [sandbox] fix dispatch table access on illumos illumos pointers are VA48, can allocate from the top of the 64-bit range as well. Co-Authored-By: Dan McDonald <danmcd@mnx.io> Refs: https://github.com/nodejs/node/pull/65161 Change-Id: I7d803ca0da2ab6c7cc206cb964d63683523a13da Refs: https://github.com/v8/v8/commit/011b2de3051afad5f0adb7b9dfedffa888c0a07b --- common.gypi | 2 +- deps/v8/src/codegen/code-stub-assembler.cc | 15 +++++++++++++-- deps/v8/src/sandbox/js-dispatch-table-inl.h | 16 ++++++++++++++++ deps/v8/src/sandbox/js-dispatch-table.h | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/common.gypi b/common.gypi index 108e1a6ee6c1..e75f33da9b88 100644 --- a/common.gypi +++ b/common.gypi @@ -50,7 +50,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.0', + 'v8_embedder_string': '-node.1', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/codegen/code-stub-assembler.cc b/deps/v8/src/codegen/code-stub-assembler.cc index b535dd1c9e43..21ab3788791c 100644 --- a/deps/v8/src/codegen/code-stub-assembler.cc +++ b/deps/v8/src/codegen/code-stub-assembler.cc @@ -2216,8 +2216,19 @@ TNode<Code> CodeStubAssembler::LoadCodeObjectFromJSDispatchTable( TNode<UintPtrT> shifted_value; if (JSDispatchEntry::kObjectPointerOffset == 0) { - shifted_value = WordShr( - value, UniqueUintPtrConstant(JSDispatchEntry::kObjectPointerShift)); + shifted_value = +#if defined(__illumos__) && defined(V8_HOST_ARCH_64_BIT) + // Pointers in illumos span both the low 2^47 range and the high 2^47 + // range as well. Checking the high bit being set in illumos means all + // higher bits need to be set to 1 after shifting right. Use WordSar() + // so any high-bit check wouldn't be necessary. + UncheckedCast<UintPtrT>(WordSar( + UncheckedCast<IntPtrT>(value), + UniqueIntPtrConstant(JSDispatchEntry::kObjectPointerShift))); +#else + WordShr(value, + UniqueUintPtrConstant(JSDispatchEntry::kObjectPointerShift)); +#endif /* __illumos__ and 64-bit */ } else { shifted_value = UintPtrAdd( WordShr(value, diff --git a/deps/v8/src/sandbox/js-dispatch-table-inl.h b/deps/v8/src/sandbox/js-dispatch-table-inl.h index c43dd402967f..00295fa38cb6 100644 --- a/deps/v8/src/sandbox/js-dispatch-table-inl.h +++ b/deps/v8/src/sandbox/js-dispatch-table-inl.h @@ -33,6 +33,7 @@ void JSDispatchEntry::MakeJSDispatchEntry(Address object, Address entrypoint, DCHECK_EQ(parameter_count & ~kParameterCountMask, 0); Address payload = parameter_count; #else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) +#if !defined(__illumos__) || !defined(V8_TARGET_ARCH_64_BIT) DCHECK_EQ((((object - kObjectPointerOffset) << kObjectPointerShift) >> kObjectPointerShift) + kObjectPointerOffset, @@ -40,6 +41,7 @@ void JSDispatchEntry::MakeJSDispatchEntry(Address object, Address entrypoint, DCHECK_EQ((object - kObjectPointerOffset) + kObjectPointerOffset, object); DCHECK_LT((object - kObjectPointerOffset), 1ULL << ((sizeof(encoded_word_) * 8) - kObjectPointerShift)); +#endif /* __illumos__ & 64-bit */ Address payload = ((object - kObjectPointerOffset) << kObjectPointerShift) | (parameter_count & kParameterCountMask); @@ -74,8 +76,17 @@ Address JSDispatchEntry::GetCodePointer() const { // and so may be 0 or 1 here. As the return value is a tagged pointer, the // bit must be 1 when returned, so we need to set it here. Address payload = encoded_word_.load(std::memory_order_acquire); +#if defined(__illumos__) && defined(V8_TARGET_ARCH_64_BIT) + // Unsigned types won't sign-extend on shift-right, but we need to do + // this with illumos VA48 addressing. + DCHECK_EQ(kObjectPointerOffset, 0); + return (Address)(static_cast<intptr_t>(payload) >> + static_cast<int>(kObjectPointerShift)) | + kHeapObjectTag; +#else return ((payload >> kObjectPointerShift) + kObjectPointerOffset) | kHeapObjectTag; +#endif /* __illumos__ & 64-bit */ #endif // V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57 } @@ -292,7 +303,12 @@ void JSDispatchEntry::MakeFreelistEntry(uint32_t next_entry_index) { #ifdef V8_TARGET_ARCH_64_BIT bool JSDispatchEntry::IsFreelistEntry(Address entrypoint) const { +#ifdef __illumos__ + // See the illumos definition of kFreeEntryTag for why we have to do this. + return (entrypoint & 0xffff000000000000ull) == kFreeEntryTag; +#else return (entrypoint & kFreeEntryTag) == kFreeEntryTag; +#endif /* __illumos__ */ } #endif diff --git a/deps/v8/src/sandbox/js-dispatch-table.h b/deps/v8/src/sandbox/js-dispatch-table.h index ee58c6b4367a..270c2efa13e5 100644 --- a/deps/v8/src/sandbox/js-dispatch-table.h +++ b/deps/v8/src/sandbox/js-dispatch-table.h @@ -106,7 +106,22 @@ struct JSDispatchEntry { static constexpr uintptr_t kParameterCountOffset = 2 * kSystemPointerSize; static constexpr uint32_t kObjectPointerShift = 0; #else // !(V8_TARGET_ARCH_X64 && V8_SUPPORT_LA57) +#ifdef __illumos__ + // In illumos 64-bit apps, pointers are allocated both the bottom 2^47 range + // AND the top 2^47 range in the 64-bit space. Instead of 47 bits of VA space + // we have 48 bits. This means, however, the top 16-bits may be 0xffff. We + // therefore pick a different value for the kFreeEntryTag. If/when we go to + // VA57, aka 5-level paging, we'll need to revisit this again, as will node + // by default, since the fixed-bits on the high end will shrink from top + // 16-bits to top 8-bits. + // + // Unless illumos ships an Oracle-Solaris-like VA47 link-time options to + // restrict pointers from allocating from above the Virtual Address hole, + // we need to be mindful of this. + static constexpr Address kFreeEntryTag = 0xfeed000000000000ull; +#else static constexpr Address kFreeEntryTag = 0xffff000000000000ull; +#endif /* __illumos__ */ #ifdef V8_TARGET_BIG_ENDIAN // 2-byte parameter count is on the least significant side of encoded_word_. static constexpr int kBigEndianParamCountOffset = From 6f206ccede2a1bff6960936323c4255cf1c71336 Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyee@igalia.com> Date: Wed, 7 Oct 2026 23:48:51 +0200 Subject: [PATCH 6/9] deps: V8: cherry-pick 7d7e8c237c53 Original commit message: Do not use preserve_most when targeting the MSVC ABI In the Microsoft C++ ABI, because preserve_most changes the calling convention, clang mangles it with U while cdecl gets an A, which means components compiled with different toolchains can fail to link. Make it a no-op when targeting MSVC and its ABI. Co-Authored-By: Stefan Stojanovic <stefan.stojanovic@janeasystems.com> Refs: https://github.com/nodejs/node/pull/55784 Change-Id: I67b49e739942d4026ac060be35bb39ec22256cbd Refs: https://github.com/v8/v8/commit/7d7e8c237c53352388a3ce3587d6e69fc3bc1c11 --- common.gypi | 2 +- deps/v8/include/v8config.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common.gypi b/common.gypi index e75f33da9b88..f7cdf6059387 100644 --- a/common.gypi +++ b/common.gypi @@ -50,7 +50,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.1', + 'v8_embedder_string': '-node.2', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/include/v8config.h b/deps/v8/include/v8config.h index b7aeeade6b81..79bb264d2c9f 100644 --- a/deps/v8/include/v8config.h +++ b/deps/v8/include/v8config.h @@ -609,11 +609,15 @@ path. Add it with -I<path> to the command line // functions. // Use like: // V8_NOINLINE V8_PRESERVE_MOST void UnlikelyMethod(); +#if V8_CC_MSVC +# define V8_PRESERVE_MOST +#else #if V8_HAS_ATTRIBUTE_PRESERVE_MOST # define V8_PRESERVE_MOST __attribute__((preserve_most)) #else # define V8_PRESERVE_MOST /* NOT SUPPORTED */ #endif +#endif // A macro (V8_DEPRECATED) to mark classes or functions as deprecated. From 61409d4259e0f13e5891033607468a70fdccf4a3 Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyeec9h3@gmail.com> Date: Mon, 5 Oct 2026 20:43:00 +0200 Subject: [PATCH 7/9] build: add simdutf dependency to torque_base Refs: https://chromium-review.googlesource.com/c/v8/v8/+/8459484 Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> --- tools/v8_gypfiles/v8.gyp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index 71b6772bc345..a862f5236bb7 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -1454,6 +1454,9 @@ ['node_shared_abseil=="false"', { 'dependencies': ['abseil.gyp:abseil'], }], + ['node_shared_simdutf=="false"', { + 'dependencies': ['simdutf.gyp:simdutf'], + }], ], }, # torque_base { From 4ef7e31f0775e126309b4026efb4e090c3f969cb Mon Sep 17 00:00:00 2001 From: Joyee Cheung <joyeec9h3@gmail.com> Date: Thu, 8 Oct 2026 00:25:11 +0200 Subject: [PATCH 8/9] build: use v8_use_metagen in build flags Refs: https://chromium-review.googlesource.com/c/v8/v8/+/8524366 Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com> --- tools/v8_gypfiles/features.gypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/v8_gypfiles/features.gypi b/tools/v8_gypfiles/features.gypi index 305c81eab34d..309b295e2c63 100644 --- a/tools/v8_gypfiles/features.gypi +++ b/tools/v8_gypfiles/features.gypi @@ -581,7 +581,7 @@ 'V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=<(v8_typed_array_max_size_in_heap)', # See deps/v8/src/objects/instance-types-gen.h and # https://github.com/nodejs/build/issues/4350 - 'V8_USE_METAGEN_INSTANCE_TYPES=0', + 'V8_USE_METAGEN=0', ], # defines }, # target_defaults } From 834065889725f29243d645f741629963dec33fc7 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu <cwu631@bloomberg.net> Date: Tue, 27 Oct 2026 17:47:05 -0400 Subject: [PATCH 9/9] test: remove test on --harmony-struct V8 deprecated --harmony-struct. Refs: https://chromium-review.googlesource.com/c/v8/v8/+/8610686 Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net> --- ...test-experimental-shared-value-conveyor.js | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 test/parallel/test-experimental-shared-value-conveyor.js diff --git a/test/parallel/test-experimental-shared-value-conveyor.js b/test/parallel/test-experimental-shared-value-conveyor.js deleted file mode 100644 index b4e3cb2f1db8..000000000000 --- a/test/parallel/test-experimental-shared-value-conveyor.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; -const common = require('../common'); -const assert = require('assert'); -const { MessageChannel } = require('worker_threads'); -const { spawnSyncAndAssert } = require('../common/child_process'); - -if (process.env.TEST_CHILD_PROCESS === '1') { - // --harmony-struct implies --shared-string-table. V8 currently does not - // support JSON.parse in worker isolates with that flag, and Node workers - // parse process.config during bootstrap. - const m = new globalThis.SharedArray(16); - const { port1, port2 } = new MessageChannel(); - - port1.once('message', common.mustCall((message) => { - assert.strictEqual(message, m); - port1.close(); - port2.close(); - })); - - port2.postMessage(m); -} else { - if (process.config.variables.v8_enable_pointer_compression === 1) { - common.skip('--harmony-struct cannot be used with pointer compression'); - } - - const args = ['--harmony-struct', __filename]; - const options = { env: { TEST_CHILD_PROCESS: '1', ...process.env } }; - - spawnSyncAndAssert(process.execPath, args, options, { - stdout: '', - stderr: '', - trim: true - }); -}